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