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