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