xref: /openbmc/linux/drivers/scsi/libfc/fc_disc.c (revision 05d7d3b0)
1 /*
2  * Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms and conditions of the GNU General Public License,
6  * version 2, as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope it will be useful, but WITHOUT
9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
11  * more details.
12  *
13  * You should have received a copy of the GNU General Public License along with
14  * this program; if not, write to the Free Software Foundation, Inc.,
15  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
16  *
17  * Maintained at www.Open-FCoE.org
18  */
19 
20 /*
21  * Target Discovery
22  *
23  * This block discovers all FC-4 remote ports, including FCP initiators. It
24  * also handles RSCN events and re-discovery if necessary.
25  */
26 
27 /*
28  * DISC LOCKING
29  *
30  * The disc mutex is can be locked when acquiring rport locks, but may not
31  * be held when acquiring the lport lock. Refer to fc_lport.c for more
32  * details.
33  */
34 
35 #include <linux/timer.h>
36 #include <linux/slab.h>
37 #include <linux/err.h>
38 #include <linux/export.h>
39 #include <asm/unaligned.h>
40 
41 #include <scsi/fc/fc_gs.h>
42 
43 #include <scsi/libfc.h>
44 
45 #include "fc_libfc.h"
46 
47 #define FC_DISC_RETRY_LIMIT	3	/* max retries */
48 #define FC_DISC_RETRY_DELAY	500UL	/* (msecs) delay */
49 
50 static void fc_disc_gpn_ft_req(struct fc_disc *);
51 static void fc_disc_gpn_ft_resp(struct fc_seq *, struct fc_frame *, void *);
52 static void fc_disc_done(struct fc_disc *, enum fc_disc_event);
53 static void fc_disc_timeout(struct work_struct *);
54 static int fc_disc_single(struct fc_lport *, struct fc_disc_port *);
55 static void fc_disc_restart(struct fc_disc *);
56 
57 /**
58  * fc_disc_stop_rports() - Delete all the remote ports associated with the lport
59  * @disc: The discovery job to stop remote ports on
60  *
61  * Locking Note: This function expects that the lport mutex is locked before
62  * calling it.
63  */
64 static void fc_disc_stop_rports(struct fc_disc *disc)
65 {
66 	struct fc_lport *lport;
67 	struct fc_rport_priv *rdata;
68 
69 	lport = fc_disc_lport(disc);
70 
71 	rcu_read_lock();
72 	list_for_each_entry_rcu(rdata, &disc->rports, peers) {
73 		if (kref_get_unless_zero(&rdata->kref)) {
74 			lport->tt.rport_logoff(rdata);
75 			kref_put(&rdata->kref, fc_rport_destroy);
76 		}
77 	}
78 	rcu_read_unlock();
79 }
80 
81 /**
82  * fc_disc_recv_rscn_req() - Handle Registered State Change Notification (RSCN)
83  * @disc:  The discovery object to which the RSCN applies
84  * @fp:	   The RSCN frame
85  *
86  * Locking Note: This function expects that the disc_mutex is locked
87  *		 before it is called.
88  */
89 static void fc_disc_recv_rscn_req(struct fc_disc *disc, struct fc_frame *fp)
90 {
91 	struct fc_lport *lport;
92 	struct fc_els_rscn *rp;
93 	struct fc_els_rscn_page *pp;
94 	struct fc_seq_els_data rjt_data;
95 	unsigned int len;
96 	int redisc = 0;
97 	enum fc_els_rscn_ev_qual ev_qual;
98 	enum fc_els_rscn_addr_fmt fmt;
99 	LIST_HEAD(disc_ports);
100 	struct fc_disc_port *dp, *next;
101 
102 	lport = fc_disc_lport(disc);
103 
104 	FC_DISC_DBG(disc, "Received an RSCN event\n");
105 
106 	/* make sure the frame contains an RSCN message */
107 	rp = fc_frame_payload_get(fp, sizeof(*rp));
108 	if (!rp)
109 		goto reject;
110 	/* make sure the page length is as expected (4 bytes) */
111 	if (rp->rscn_page_len != sizeof(*pp))
112 		goto reject;
113 	/* get the RSCN payload length */
114 	len = ntohs(rp->rscn_plen);
115 	if (len < sizeof(*rp))
116 		goto reject;
117 	/* make sure the frame contains the expected payload */
118 	rp = fc_frame_payload_get(fp, len);
119 	if (!rp)
120 		goto reject;
121 	/* payload must be a multiple of the RSCN page size */
122 	len -= sizeof(*rp);
123 	if (len % sizeof(*pp))
124 		goto reject;
125 
126 	for (pp = (void *)(rp + 1); len > 0; len -= sizeof(*pp), pp++) {
127 		ev_qual = pp->rscn_page_flags >> ELS_RSCN_EV_QUAL_BIT;
128 		ev_qual &= ELS_RSCN_EV_QUAL_MASK;
129 		fmt = pp->rscn_page_flags >> ELS_RSCN_ADDR_FMT_BIT;
130 		fmt &= ELS_RSCN_ADDR_FMT_MASK;
131 		/*
132 		 * if we get an address format other than port
133 		 * (area, domain, fabric), then do a full discovery
134 		 */
135 		switch (fmt) {
136 		case ELS_ADDR_FMT_PORT:
137 			FC_DISC_DBG(disc, "Port address format for port "
138 				    "(%6.6x)\n", ntoh24(pp->rscn_fid));
139 			dp = kzalloc(sizeof(*dp), GFP_KERNEL);
140 			if (!dp) {
141 				redisc = 1;
142 				break;
143 			}
144 			dp->lp = lport;
145 			dp->port_id = ntoh24(pp->rscn_fid);
146 			list_add_tail(&dp->peers, &disc_ports);
147 			break;
148 		case ELS_ADDR_FMT_AREA:
149 		case ELS_ADDR_FMT_DOM:
150 		case ELS_ADDR_FMT_FAB:
151 		default:
152 			FC_DISC_DBG(disc, "Address format is (%d)\n", fmt);
153 			redisc = 1;
154 			break;
155 		}
156 	}
157 	fc_seq_els_rsp_send(fp, ELS_LS_ACC, NULL);
158 
159 	/*
160 	 * If not doing a complete rediscovery, do GPN_ID on
161 	 * the individual ports mentioned in the list.
162 	 * If any of these get an error, do a full rediscovery.
163 	 * In any case, go through the list and free the entries.
164 	 */
165 	list_for_each_entry_safe(dp, next, &disc_ports, peers) {
166 		list_del(&dp->peers);
167 		if (!redisc)
168 			redisc = fc_disc_single(lport, dp);
169 		kfree(dp);
170 	}
171 	if (redisc) {
172 		FC_DISC_DBG(disc, "RSCN received: rediscovering\n");
173 		fc_disc_restart(disc);
174 	} else {
175 		FC_DISC_DBG(disc, "RSCN received: not rediscovering. "
176 			    "redisc %d state %d in_prog %d\n",
177 			    redisc, lport->state, disc->pending);
178 	}
179 	fc_frame_free(fp);
180 	return;
181 reject:
182 	FC_DISC_DBG(disc, "Received a bad RSCN frame\n");
183 	rjt_data.reason = ELS_RJT_LOGIC;
184 	rjt_data.explan = ELS_EXPL_NONE;
185 	fc_seq_els_rsp_send(fp, ELS_LS_RJT, &rjt_data);
186 	fc_frame_free(fp);
187 }
188 
189 /**
190  * fc_disc_recv_req() - Handle incoming requests
191  * @lport: The local port receiving the request
192  * @fp:	   The request frame
193  *
194  * Locking Note: This function is called from the EM and will lock
195  *		 the disc_mutex before calling the handler for the
196  *		 request.
197  */
198 static void fc_disc_recv_req(struct fc_lport *lport, struct fc_frame *fp)
199 {
200 	u8 op;
201 	struct fc_disc *disc = &lport->disc;
202 
203 	op = fc_frame_payload_op(fp);
204 	switch (op) {
205 	case ELS_RSCN:
206 		mutex_lock(&disc->disc_mutex);
207 		fc_disc_recv_rscn_req(disc, fp);
208 		mutex_unlock(&disc->disc_mutex);
209 		break;
210 	default:
211 		FC_DISC_DBG(disc, "Received an unsupported request, "
212 			    "the opcode is (%x)\n", op);
213 		fc_frame_free(fp);
214 		break;
215 	}
216 }
217 
218 /**
219  * fc_disc_restart() - Restart discovery
220  * @disc: The discovery object to be restarted
221  *
222  * Locking Note: This function expects that the disc mutex
223  *		 is already locked.
224  */
225 static void fc_disc_restart(struct fc_disc *disc)
226 {
227 	if (!disc->disc_callback)
228 		return;
229 
230 	FC_DISC_DBG(disc, "Restarting discovery\n");
231 
232 	disc->requested = 1;
233 	if (disc->pending)
234 		return;
235 
236 	/*
237 	 * Advance disc_id.  This is an arbitrary non-zero number that will
238 	 * match the value in the fc_rport_priv after discovery for all
239 	 * freshly-discovered remote ports.  Avoid wrapping to zero.
240 	 */
241 	disc->disc_id = (disc->disc_id + 2) | 1;
242 	disc->retry_count = 0;
243 	fc_disc_gpn_ft_req(disc);
244 }
245 
246 /**
247  * fc_disc_start() - Start discovery on a local port
248  * @lport:	   The local port to have discovery started on
249  * @disc_callback: Callback function to be called when discovery is complete
250  */
251 static void fc_disc_start(void (*disc_callback)(struct fc_lport *,
252 						enum fc_disc_event),
253 			  struct fc_lport *lport)
254 {
255 	struct fc_disc *disc = &lport->disc;
256 
257 	/*
258 	 * At this point we may have a new disc job or an existing
259 	 * one. Either way, let's lock when we make changes to it
260 	 * and send the GPN_FT request.
261 	 */
262 	mutex_lock(&disc->disc_mutex);
263 	disc->disc_callback = disc_callback;
264 	fc_disc_restart(disc);
265 	mutex_unlock(&disc->disc_mutex);
266 }
267 
268 /**
269  * fc_disc_done() - Discovery has been completed
270  * @disc:  The discovery context
271  * @event: The discovery completion status
272  *
273  * Locking Note: This function expects that the disc mutex is locked before
274  * it is called. The discovery callback is then made with the lock released,
275  * and the lock is re-taken before returning from this function
276  */
277 static void fc_disc_done(struct fc_disc *disc, enum fc_disc_event event)
278 {
279 	struct fc_lport *lport = fc_disc_lport(disc);
280 	struct fc_rport_priv *rdata;
281 
282 	FC_DISC_DBG(disc, "Discovery complete\n");
283 
284 	disc->pending = 0;
285 	if (disc->requested) {
286 		fc_disc_restart(disc);
287 		return;
288 	}
289 
290 	/*
291 	 * Go through all remote ports.	 If they were found in the latest
292 	 * discovery, reverify or log them in.	Otherwise, log them out.
293 	 * Skip ports which were never discovered.  These are the dNS port
294 	 * and ports which were created by PLOGI.
295 	 */
296 	rcu_read_lock();
297 	list_for_each_entry_rcu(rdata, &disc->rports, peers) {
298 		if (!kref_get_unless_zero(&rdata->kref))
299 			continue;
300 		if (rdata->disc_id) {
301 			if (rdata->disc_id == disc->disc_id)
302 				fc_rport_login(rdata);
303 			else
304 				lport->tt.rport_logoff(rdata);
305 		}
306 		kref_put(&rdata->kref, fc_rport_destroy);
307 	}
308 	rcu_read_unlock();
309 	mutex_unlock(&disc->disc_mutex);
310 	disc->disc_callback(lport, event);
311 	mutex_lock(&disc->disc_mutex);
312 }
313 
314 /**
315  * fc_disc_error() - Handle error on dNS request
316  * @disc: The discovery context
317  * @fp:	  The error code encoded as a frame pointer
318  */
319 static void fc_disc_error(struct fc_disc *disc, struct fc_frame *fp)
320 {
321 	struct fc_lport *lport = fc_disc_lport(disc);
322 	unsigned long delay = 0;
323 
324 	FC_DISC_DBG(disc, "Error %ld, retries %d/%d\n",
325 		    PTR_ERR(fp), disc->retry_count,
326 		    FC_DISC_RETRY_LIMIT);
327 
328 	if (!fp || PTR_ERR(fp) == -FC_EX_TIMEOUT) {
329 		/*
330 		 * Memory allocation failure, or the exchange timed out,
331 		 * retry after delay.
332 		 */
333 		if (disc->retry_count < FC_DISC_RETRY_LIMIT) {
334 			/* go ahead and retry */
335 			if (!fp)
336 				delay = msecs_to_jiffies(FC_DISC_RETRY_DELAY);
337 			else {
338 				delay = msecs_to_jiffies(lport->e_d_tov);
339 
340 				/* timeout faster first time */
341 				if (!disc->retry_count)
342 					delay /= 4;
343 			}
344 			disc->retry_count++;
345 			schedule_delayed_work(&disc->disc_work, delay);
346 		} else
347 			fc_disc_done(disc, DISC_EV_FAILED);
348 	} else if (PTR_ERR(fp) == -FC_EX_CLOSED) {
349 		/*
350 		 * if discovery fails due to lport reset, clear
351 		 * pending flag so that subsequent discovery can
352 		 * continue
353 		 */
354 		disc->pending = 0;
355 	}
356 }
357 
358 /**
359  * fc_disc_gpn_ft_req() - Send Get Port Names by FC-4 type (GPN_FT) request
360  * @lport: The discovery context
361  *
362  * Locking Note: This function expects that the disc_mutex is locked
363  *		 before it is called.
364  */
365 static void fc_disc_gpn_ft_req(struct fc_disc *disc)
366 {
367 	struct fc_frame *fp;
368 	struct fc_lport *lport = fc_disc_lport(disc);
369 
370 	WARN_ON(!fc_lport_test_ready(lport));
371 
372 	disc->pending = 1;
373 	disc->requested = 0;
374 
375 	disc->buf_len = 0;
376 	disc->seq_count = 0;
377 	fp = fc_frame_alloc(lport,
378 			    sizeof(struct fc_ct_hdr) +
379 			    sizeof(struct fc_ns_gid_ft));
380 	if (!fp)
381 		goto err;
382 
383 	if (lport->tt.elsct_send(lport, 0, fp,
384 				 FC_NS_GPN_FT,
385 				 fc_disc_gpn_ft_resp,
386 				 disc, 3 * lport->r_a_tov))
387 		return;
388 err:
389 	fc_disc_error(disc, NULL);
390 }
391 
392 /**
393  * fc_disc_gpn_ft_parse() - Parse the body of the dNS GPN_FT response.
394  * @lport: The local port the GPN_FT was received on
395  * @buf:   The GPN_FT response buffer
396  * @len:   The size of response buffer
397  *
398  * Goes through the list of IDs and names resulting from a request.
399  */
400 static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len)
401 {
402 	struct fc_lport *lport;
403 	struct fc_gpn_ft_resp *np;
404 	char *bp;
405 	size_t plen;
406 	size_t tlen;
407 	int error = 0;
408 	struct fc_rport_identifiers ids;
409 	struct fc_rport_priv *rdata;
410 
411 	lport = fc_disc_lport(disc);
412 	disc->seq_count++;
413 
414 	/*
415 	 * Handle partial name record left over from previous call.
416 	 */
417 	bp = buf;
418 	plen = len;
419 	np = (struct fc_gpn_ft_resp *)bp;
420 	tlen = disc->buf_len;
421 	disc->buf_len = 0;
422 	if (tlen) {
423 		WARN_ON(tlen >= sizeof(*np));
424 		plen = sizeof(*np) - tlen;
425 		WARN_ON(plen <= 0);
426 		WARN_ON(plen >= sizeof(*np));
427 		if (plen > len)
428 			plen = len;
429 		np = &disc->partial_buf;
430 		memcpy((char *)np + tlen, bp, plen);
431 
432 		/*
433 		 * Set bp so that the loop below will advance it to the
434 		 * first valid full name element.
435 		 */
436 		bp -= tlen;
437 		len += tlen;
438 		plen += tlen;
439 		disc->buf_len = (unsigned char) plen;
440 		if (plen == sizeof(*np))
441 			disc->buf_len = 0;
442 	}
443 
444 	/*
445 	 * Handle full name records, including the one filled from above.
446 	 * Normally, np == bp and plen == len, but from the partial case above,
447 	 * bp, len describe the overall buffer, and np, plen describe the
448 	 * partial buffer, which if would usually be full now.
449 	 * After the first time through the loop, things return to "normal".
450 	 */
451 	while (plen >= sizeof(*np)) {
452 		ids.port_id = ntoh24(np->fp_fid);
453 		ids.port_name = ntohll(np->fp_wwpn);
454 
455 		if (ids.port_id != lport->port_id &&
456 		    ids.port_name != lport->wwpn) {
457 			rdata = fc_rport_create(lport, ids.port_id);
458 			if (rdata) {
459 				rdata->ids.port_name = ids.port_name;
460 				rdata->disc_id = disc->disc_id;
461 			} else {
462 				printk(KERN_WARNING "libfc: Failed to allocate "
463 				       "memory for the newly discovered port "
464 				       "(%6.6x)\n", ids.port_id);
465 				error = -ENOMEM;
466 			}
467 		}
468 
469 		if (np->fp_flags & FC_NS_FID_LAST) {
470 			fc_disc_done(disc, DISC_EV_SUCCESS);
471 			len = 0;
472 			break;
473 		}
474 		len -= sizeof(*np);
475 		bp += sizeof(*np);
476 		np = (struct fc_gpn_ft_resp *)bp;
477 		plen = len;
478 	}
479 
480 	/*
481 	 * Save any partial record at the end of the buffer for next time.
482 	 */
483 	if (error == 0 && len > 0 && len < sizeof(*np)) {
484 		if (np != &disc->partial_buf) {
485 			FC_DISC_DBG(disc, "Partial buffer remains "
486 				    "for discovery\n");
487 			memcpy(&disc->partial_buf, np, len);
488 		}
489 		disc->buf_len = (unsigned char) len;
490 	}
491 	return error;
492 }
493 
494 /**
495  * fc_disc_timeout() - Handler for discovery timeouts
496  * @work: Structure holding discovery context that needs to retry discovery
497  */
498 static void fc_disc_timeout(struct work_struct *work)
499 {
500 	struct fc_disc *disc = container_of(work,
501 					    struct fc_disc,
502 					    disc_work.work);
503 	mutex_lock(&disc->disc_mutex);
504 	fc_disc_gpn_ft_req(disc);
505 	mutex_unlock(&disc->disc_mutex);
506 }
507 
508 /**
509  * fc_disc_gpn_ft_resp() - Handle a response frame from Get Port Names (GPN_FT)
510  * @sp:	    The sequence that the GPN_FT response was received on
511  * @fp:	    The GPN_FT response frame
512  * @lp_arg: The discovery context
513  *
514  * Locking Note: This function is called without disc mutex held, and
515  *		 should do all its processing with the mutex held
516  */
517 static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp,
518 				void *disc_arg)
519 {
520 	struct fc_disc *disc = disc_arg;
521 	struct fc_ct_hdr *cp;
522 	struct fc_frame_header *fh;
523 	enum fc_disc_event event = DISC_EV_NONE;
524 	unsigned int seq_cnt;
525 	unsigned int len;
526 	int error = 0;
527 
528 	mutex_lock(&disc->disc_mutex);
529 	FC_DISC_DBG(disc, "Received a GPN_FT response\n");
530 
531 	if (IS_ERR(fp)) {
532 		fc_disc_error(disc, fp);
533 		mutex_unlock(&disc->disc_mutex);
534 		return;
535 	}
536 
537 	WARN_ON(!fc_frame_is_linear(fp));	/* buffer must be contiguous */
538 	fh = fc_frame_header_get(fp);
539 	len = fr_len(fp) - sizeof(*fh);
540 	seq_cnt = ntohs(fh->fh_seq_cnt);
541 	if (fr_sof(fp) == FC_SOF_I3 && seq_cnt == 0 && disc->seq_count == 0) {
542 		cp = fc_frame_payload_get(fp, sizeof(*cp));
543 		if (!cp) {
544 			FC_DISC_DBG(disc, "GPN_FT response too short, len %d\n",
545 				    fr_len(fp));
546 			event = DISC_EV_FAILED;
547 		} else if (ntohs(cp->ct_cmd) == FC_FS_ACC) {
548 
549 			/* Accepted, parse the response. */
550 			len -= sizeof(*cp);
551 			error = fc_disc_gpn_ft_parse(disc, cp + 1, len);
552 		} else if (ntohs(cp->ct_cmd) == FC_FS_RJT) {
553 			FC_DISC_DBG(disc, "GPN_FT rejected reason %x exp %x "
554 				    "(check zoning)\n", cp->ct_reason,
555 				    cp->ct_explan);
556 			event = DISC_EV_FAILED;
557 			if (cp->ct_reason == FC_FS_RJT_UNABL &&
558 			    cp->ct_explan == FC_FS_EXP_FTNR)
559 				event = DISC_EV_SUCCESS;
560 		} else {
561 			FC_DISC_DBG(disc, "GPN_FT unexpected response code "
562 				    "%x\n", ntohs(cp->ct_cmd));
563 			event = DISC_EV_FAILED;
564 		}
565 	} else if (fr_sof(fp) == FC_SOF_N3 && seq_cnt == disc->seq_count) {
566 		error = fc_disc_gpn_ft_parse(disc, fh + 1, len);
567 	} else {
568 		FC_DISC_DBG(disc, "GPN_FT unexpected frame - out of sequence? "
569 			    "seq_cnt %x expected %x sof %x eof %x\n",
570 			    seq_cnt, disc->seq_count, fr_sof(fp), fr_eof(fp));
571 		event = DISC_EV_FAILED;
572 	}
573 	if (error)
574 		fc_disc_error(disc, fp);
575 	else if (event != DISC_EV_NONE)
576 		fc_disc_done(disc, event);
577 	fc_frame_free(fp);
578 	mutex_unlock(&disc->disc_mutex);
579 }
580 
581 /**
582  * fc_disc_gpn_id_resp() - Handle a response frame from Get Port Names (GPN_ID)
583  * @sp:	       The sequence the GPN_ID is on
584  * @fp:	       The response frame
585  * @rdata_arg: The remote port that sent the GPN_ID response
586  *
587  * Locking Note: This function is called without disc mutex held.
588  */
589 static void fc_disc_gpn_id_resp(struct fc_seq *sp, struct fc_frame *fp,
590 				void *rdata_arg)
591 {
592 	struct fc_rport_priv *rdata = rdata_arg;
593 	struct fc_rport_priv *new_rdata;
594 	struct fc_lport *lport;
595 	struct fc_disc *disc;
596 	struct fc_ct_hdr *cp;
597 	struct fc_ns_gid_pn *pn;
598 	u64 port_name;
599 
600 	lport = rdata->local_port;
601 	disc = &lport->disc;
602 
603 	if (PTR_ERR(fp) == -FC_EX_CLOSED)
604 		goto out;
605 	if (IS_ERR(fp))
606 		goto redisc;
607 
608 	cp = fc_frame_payload_get(fp, sizeof(*cp));
609 	if (!cp)
610 		goto redisc;
611 	if (ntohs(cp->ct_cmd) == FC_FS_ACC) {
612 		if (fr_len(fp) < sizeof(struct fc_frame_header) +
613 		    sizeof(*cp) + sizeof(*pn))
614 			goto redisc;
615 		pn = (struct fc_ns_gid_pn *)(cp + 1);
616 		port_name = get_unaligned_be64(&pn->fn_wwpn);
617 		mutex_lock(&rdata->rp_mutex);
618 		if (rdata->ids.port_name == -1)
619 			rdata->ids.port_name = port_name;
620 		else if (rdata->ids.port_name != port_name) {
621 			FC_DISC_DBG(disc, "GPN_ID accepted.  WWPN changed. "
622 				    "Port-id %6.6x wwpn %16.16llx\n",
623 				    rdata->ids.port_id, port_name);
624 			mutex_unlock(&rdata->rp_mutex);
625 			lport->tt.rport_logoff(rdata);
626 			mutex_lock(&lport->disc.disc_mutex);
627 			new_rdata = fc_rport_create(lport, rdata->ids.port_id);
628 			mutex_unlock(&lport->disc.disc_mutex);
629 			if (new_rdata) {
630 				new_rdata->disc_id = disc->disc_id;
631 				fc_rport_login(new_rdata);
632 			}
633 			goto out;
634 		}
635 		rdata->disc_id = disc->disc_id;
636 		mutex_unlock(&rdata->rp_mutex);
637 		fc_rport_login(rdata);
638 	} else if (ntohs(cp->ct_cmd) == FC_FS_RJT) {
639 		FC_DISC_DBG(disc, "GPN_ID rejected reason %x exp %x\n",
640 			    cp->ct_reason, cp->ct_explan);
641 		lport->tt.rport_logoff(rdata);
642 	} else {
643 		FC_DISC_DBG(disc, "GPN_ID unexpected response code %x\n",
644 			    ntohs(cp->ct_cmd));
645 redisc:
646 		mutex_lock(&disc->disc_mutex);
647 		fc_disc_restart(disc);
648 		mutex_unlock(&disc->disc_mutex);
649 	}
650 out:
651 	kref_put(&rdata->kref, fc_rport_destroy);
652 }
653 
654 /**
655  * fc_disc_gpn_id_req() - Send Get Port Names by ID (GPN_ID) request
656  * @lport: The local port to initiate discovery on
657  * @rdata: remote port private data
658  *
659  * Locking Note: This function expects that the disc_mutex is locked
660  *		 before it is called.
661  * On failure, an error code is returned.
662  */
663 static int fc_disc_gpn_id_req(struct fc_lport *lport,
664 			      struct fc_rport_priv *rdata)
665 {
666 	struct fc_frame *fp;
667 
668 	fp = fc_frame_alloc(lport, sizeof(struct fc_ct_hdr) +
669 			    sizeof(struct fc_ns_fid));
670 	if (!fp)
671 		return -ENOMEM;
672 	if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, FC_NS_GPN_ID,
673 				  fc_disc_gpn_id_resp, rdata,
674 				  3 * lport->r_a_tov))
675 		return -ENOMEM;
676 	kref_get(&rdata->kref);
677 	return 0;
678 }
679 
680 /**
681  * fc_disc_single() - Discover the directory information for a single target
682  * @lport: The local port the remote port is associated with
683  * @dp:	   The port to rediscover
684  *
685  * Locking Note: This function expects that the disc_mutex is locked
686  *		 before it is called.
687  */
688 static int fc_disc_single(struct fc_lport *lport, struct fc_disc_port *dp)
689 {
690 	struct fc_rport_priv *rdata;
691 
692 	rdata = fc_rport_create(lport, dp->port_id);
693 	if (!rdata)
694 		return -ENOMEM;
695 	rdata->disc_id = 0;
696 	return fc_disc_gpn_id_req(lport, rdata);
697 }
698 
699 /**
700  * fc_disc_stop() - Stop discovery for a given lport
701  * @lport: The local port that discovery should stop on
702  */
703 static void fc_disc_stop(struct fc_lport *lport)
704 {
705 	struct fc_disc *disc = &lport->disc;
706 
707 	if (disc->pending)
708 		cancel_delayed_work_sync(&disc->disc_work);
709 	fc_disc_stop_rports(disc);
710 }
711 
712 /**
713  * fc_disc_stop_final() - Stop discovery for a given lport
714  * @lport: The lport that discovery should stop on
715  *
716  * This function will block until discovery has been
717  * completely stopped and all rports have been deleted.
718  */
719 static void fc_disc_stop_final(struct fc_lport *lport)
720 {
721 	fc_disc_stop(lport);
722 	lport->tt.rport_flush_queue();
723 }
724 
725 /**
726  * fc_disc_config() - Configure the discovery layer for a local port
727  * @lport: The local port that needs the discovery layer to be configured
728  * @priv: Private data structre for users of the discovery layer
729  */
730 void fc_disc_config(struct fc_lport *lport, void *priv)
731 {
732 	struct fc_disc *disc = &lport->disc;
733 
734 	if (!lport->tt.disc_start)
735 		lport->tt.disc_start = fc_disc_start;
736 
737 	if (!lport->tt.disc_stop)
738 		lport->tt.disc_stop = fc_disc_stop;
739 
740 	if (!lport->tt.disc_stop_final)
741 		lport->tt.disc_stop_final = fc_disc_stop_final;
742 
743 	if (!lport->tt.disc_recv_req)
744 		lport->tt.disc_recv_req = fc_disc_recv_req;
745 
746 	disc = &lport->disc;
747 
748 	disc->priv = priv;
749 }
750 EXPORT_SYMBOL(fc_disc_config);
751 
752 /**
753  * fc_disc_init() - Initialize the discovery layer for a local port
754  * @lport: The local port that needs the discovery layer to be initialized
755  */
756 void fc_disc_init(struct fc_lport *lport)
757 {
758 	struct fc_disc *disc = &lport->disc;
759 
760 	INIT_DELAYED_WORK(&disc->disc_work, fc_disc_timeout);
761 	mutex_init(&disc->disc_mutex);
762 	INIT_LIST_HEAD(&disc->rports);
763 }
764 EXPORT_SYMBOL(fc_disc_init);
765