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