2 * Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved.
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.
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
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.
17 * Maintained at www.Open-FCoE.org
23 * This block discovers all FC-4 remote ports, including FCP initiators. It
24 * also handles RSCN events and re-discovery if necessary.
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
35 #include <linux/timer.h>
36 #include <linux/err.h>
37 #include <asm/unaligned.h>
39 #include <scsi/fc/fc_gs.h>
41 #include <scsi/libfc.h>
43 #define FC_DISC_RETRY_LIMIT 3 /* max retries */
44 #define FC_DISC_RETRY_DELAY 500UL /* (msecs) delay */
46 #define FC_DISC_DELAY 3
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
*);
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
62 struct fc_rport_priv
*fc_disc_lookup_rport(const struct fc_lport
*lport
,
65 const struct fc_disc
*disc
= &lport
->disc
;
66 struct fc_rport_priv
*rdata
;
68 list_for_each_entry(rdata
, &disc
->rports
, peers
) {
69 if (rdata
->ids
.port_id
== port_id
)
76 * fc_disc_stop_rports() - delete all the remote ports associated with the lport
77 * @disc: The discovery job to stop rports on
79 * Locking Note: This function expects that the lport mutex is locked before
82 void fc_disc_stop_rports(struct fc_disc
*disc
)
84 struct fc_lport
*lport
;
85 struct fc_rport_priv
*rdata
, *next
;
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
);
95 list_for_each_entry_safe(rdata
, next
, &disc
->rogue_rports
, peers
) {
96 lport
->tt
.rport_logoff(rdata
);
99 mutex_unlock(&disc
->disc_mutex
);
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
108 * Locking Note: The rport lock should not be held when calling
111 static void fc_disc_rport_callback(struct fc_lport
*lport
,
112 struct fc_rport_priv
*rdata
,
113 enum fc_rport_event event
)
115 struct fc_disc
*disc
= &lport
->disc
;
117 FC_DISC_DBG(disc
, "Received a %d event for port (%6x)\n", event
,
123 mutex_lock(&disc
->disc_mutex
);
124 list_add_tail(&rdata
->peers
, &disc
->rports
);
125 mutex_unlock(&disc
->disc_mutex
);
129 case RPORT_EV_FAILED
:
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
);
145 * fc_disc_recv_rscn_req() - Handle Registered State Change Notification (RSCN)
146 * @sp: Current sequence of the RSCN exchange
148 * @lport: Fibre Channel host port instance
150 * Locking Note: This function expects that the disc_mutex is locked
151 * before it is called.
153 static void fc_disc_recv_rscn_req(struct fc_seq
*sp
, struct fc_frame
*fp
,
154 struct fc_disc
*disc
)
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
;
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
;
170 FC_DISC_DBG(disc
, "Received an RSCN event\n");
172 /* make sure the frame contains an RSCN message */
173 rp
= fc_frame_payload_get(fp
, sizeof(*rp
));
176 /* make sure the page length is as expected (4 bytes) */
177 if (rp
->rscn_page_len
!= sizeof(*pp
))
179 /* get the RSCN payload length */
180 len
= ntohs(rp
->rscn_plen
);
181 if (len
< sizeof(*rp
))
183 /* make sure the frame contains the expected payload */
184 rp
= fc_frame_payload_get(fp
, len
);
187 /* payload must be a multiple of the RSCN page size */
189 if (len
% sizeof(*pp
))
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
;
198 * if we get an address format other than port
199 * (area, domain, fabric), then do a full discovery
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
);
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
);
217 case ELS_ADDR_FMT_AREA
:
218 case ELS_ADDR_FMT_DOM
:
219 case ELS_ADDR_FMT_FAB
:
221 FC_DISC_DBG(disc
, "Address format is (%d)\n", fmt
);
226 lport
->tt
.seq_els_rsp_send(sp
, ELS_LS_ACC
, NULL
);
228 FC_DISC_DBG(disc
, "RSCN received: rediscovering\n");
229 fc_disc_restart(disc
);
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
);
238 list_del(&rdata
->peers
);
239 lport
->tt
.rport_logoff(rdata
);
241 fc_disc_single(disc
, dp
);
247 FC_DISC_DBG(disc
, "Received a bad RSCN frame\n");
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
);
256 * fc_disc_recv_req() - Handle incoming requests
257 * @sp: Current sequence of the request exchange
259 * @lport: The FC local port
261 * Locking Note: This function is called from the EM and will lock
262 * the disc_mutex before calling the handler for the
265 static void fc_disc_recv_req(struct fc_seq
*sp
, struct fc_frame
*fp
,
266 struct fc_lport
*lport
)
269 struct fc_disc
*disc
= &lport
->disc
;
271 op
= fc_frame_payload_op(fp
);
274 mutex_lock(&disc
->disc_mutex
);
275 fc_disc_recv_rscn_req(sp
, fp
, disc
);
276 mutex_unlock(&disc
->disc_mutex
);
279 FC_DISC_DBG(disc
, "Received an unsupported request, "
280 "the opcode is (%x)\n", op
);
286 * fc_disc_restart() - Restart discovery
287 * @lport: FC discovery context
289 * Locking Note: This function expects that the disc mutex
292 static void fc_disc_restart(struct fc_disc
*disc
)
294 struct fc_rport_priv
*rdata
, *next
;
295 struct fc_lport
*lport
= disc
->lport
;
297 FC_DISC_DBG(disc
, "Restarting discovery\n");
299 list_for_each_entry_safe(rdata
, next
, &disc
->rports
, peers
) {
300 list_del(&rdata
->peers
);
301 lport
->tt
.rport_logoff(rdata
);
306 fc_disc_gpn_ft_req(disc
);
310 * fc_disc_start() - Fibre Channel Target discovery
311 * @lport: FC local port
313 * Returns non-zero if discovery cannot be started.
315 static void fc_disc_start(void (*disc_callback
)(struct fc_lport
*,
317 struct fc_lport
*lport
)
319 struct fc_rport_priv
*rdata
;
320 struct fc_disc
*disc
= &lport
->disc
;
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.
327 mutex_lock(&disc
->disc_mutex
);
329 disc
->disc_callback
= disc_callback
;
332 * If not ready, or already running discovery, just set request flag.
337 mutex_unlock(&disc
->disc_mutex
);
342 * Handle point-to-point mode as a simple discovery
343 * of the remote port. Yucky, yucky, yuck, yuck!
345 rdata
= disc
->lport
->ptp_rp
;
347 kref_get(&rdata
->kref
);
348 if (!fc_disc_new_target(disc
, rdata
, &rdata
->ids
)) {
349 disc
->event
= DISC_EV_SUCCESS
;
352 kref_put(&rdata
->kref
, rdata
->local_port
->tt
.rport_destroy
);
354 fc_disc_gpn_ft_req(disc
); /* get ports by FC-4 type */
357 mutex_unlock(&disc
->disc_mutex
);
360 static struct fc_rport_operations fc_disc_rport_ops
= {
361 .event_callback
= fc_disc_rport_callback
,
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
370 * Locking Note: This function expects that the disc_mutex is locked
371 * before it is called.
373 static int fc_disc_new_target(struct fc_disc
*disc
,
374 struct fc_rport_priv
*rdata
,
375 struct fc_rport_identifiers
*ids
)
377 struct fc_lport
*lport
= disc
->lport
;
380 if (rdata
&& ids
->port_name
) {
381 if (rdata
->ids
.port_name
== -1) {
383 * Set WWN and fall through to notify of create.
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
) {
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.
395 list_del(&rdata
->peers
);
396 lport
->tt
.rport_logoff(rdata
);
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
) {
404 rdata
= lport
->tt
.rport_lookup(lport
, ids
->port_id
);
406 rdata
= lport
->tt
.rport_create(lport
, ids
);
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
);
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
428 static void fc_disc_done(struct fc_disc
*disc
)
430 struct fc_lport
*lport
= disc
->lport
;
431 enum fc_disc_event event
;
433 FC_DISC_DBG(disc
, "Discovery complete\n");
436 disc
->event
= DISC_EV_NONE
;
439 fc_disc_gpn_ft_req(disc
);
443 mutex_unlock(&disc
->disc_mutex
);
444 disc
->disc_callback(lport
, event
);
445 mutex_lock(&disc
->disc_mutex
);
449 * fc_disc_error() - Handle error on dNS request
450 * @disc: FC discovery context
451 * @fp: The frame pointer
453 static void fc_disc_error(struct fc_disc
*disc
, struct fc_frame
*fp
)
455 struct fc_lport
*lport
= disc
->lport
;
456 unsigned long delay
= 0;
458 FC_DISC_DBG(disc
, "Error %ld, retries %d/%d\n",
459 PTR_ERR(fp
), disc
->retry_count
,
460 FC_DISC_RETRY_LIMIT
);
462 if (!fp
|| PTR_ERR(fp
) == -FC_EX_TIMEOUT
) {
464 * Memory allocation failure, or the exchange timed out,
467 if (disc
->retry_count
< FC_DISC_RETRY_LIMIT
) {
468 /* go ahead and retry */
470 delay
= msecs_to_jiffies(FC_DISC_RETRY_DELAY
);
472 delay
= msecs_to_jiffies(lport
->e_d_tov
);
474 /* timeout faster first time */
475 if (!disc
->retry_count
)
479 schedule_delayed_work(&disc
->disc_work
, delay
);
481 /* exceeded retries */
482 disc
->event
= DISC_EV_FAILED
;
489 * fc_disc_gpn_ft_req() - Send Get Port Names by FC-4 type (GPN_FT) request
490 * @lport: FC discovery context
492 * Locking Note: This function expects that the disc_mutex is locked
493 * before it is called.
495 static void fc_disc_gpn_ft_req(struct fc_disc
*disc
)
498 struct fc_lport
*lport
= disc
->lport
;
500 WARN_ON(!fc_lport_test_ready(lport
));
507 fp
= fc_frame_alloc(lport
,
508 sizeof(struct fc_ct_hdr
) +
509 sizeof(struct fc_ns_gid_ft
));
513 if (lport
->tt
.elsct_send(lport
, 0, fp
,
516 disc
, lport
->e_d_tov
))
519 fc_disc_error(disc
, fp
);
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
528 static int fc_disc_gpn_ft_parse(struct fc_disc
*disc
, void *buf
, size_t len
)
530 struct fc_lport
*lport
;
531 struct fc_gpn_ft_resp
*np
;
536 struct fc_rport_identifiers ids
;
537 struct fc_rport_priv
*rdata
;
542 * Handle partial name record left over from previous call.
546 np
= (struct fc_gpn_ft_resp
*)bp
;
547 tlen
= disc
->buf_len
;
549 WARN_ON(tlen
>= sizeof(*np
));
550 plen
= sizeof(*np
) - tlen
;
552 WARN_ON(plen
>= sizeof(*np
));
555 np
= &disc
->partial_buf
;
556 memcpy((char *)np
+ tlen
, bp
, plen
);
559 * Set bp so that the loop below will advance it to the
560 * first valid full name element.
565 disc
->buf_len
= (unsigned char) plen
;
566 if (plen
== sizeof(*np
))
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".
577 while (plen
>= sizeof(*np
)) {
578 ids
.port_id
= ntoh24(np
->fp_fid
);
579 ids
.port_name
= ntohll(np
->fp_wwpn
);
581 ids
.roles
= FC_RPORT_ROLE_UNKNOWN
;
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
);
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
);
593 printk(KERN_WARNING
"libfc: Failed to allocate "
594 "memory for the newly discovered port "
595 "(%6x)\n", ids
.port_id
);
598 if (np
->fp_flags
& FC_NS_FID_LAST
) {
599 disc
->event
= DISC_EV_SUCCESS
;
606 np
= (struct fc_gpn_ft_resp
*)bp
;
611 * Save any partial record at the end of the buffer for next time.
613 if (error
== 0 && len
> 0 && len
< sizeof(*np
)) {
614 if (np
!= &disc
->partial_buf
) {
615 FC_DISC_DBG(disc
, "Partial buffer remains "
617 memcpy(&disc
->partial_buf
, np
, len
);
619 disc
->buf_len
= (unsigned char) len
;
627 * fc_disc_timeout() - Retry handler for the disc component
628 * @work: Structure holding disc obj that needs retry discovery
630 * Handle retry of memory allocation for remote ports.
632 static void fc_disc_timeout(struct work_struct
*work
)
634 struct fc_disc
*disc
= container_of(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
);
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
649 * Locking Note: This function is called without disc mutex held, and
650 * should do all its processing with the mutex held
652 static void fc_disc_gpn_ft_resp(struct fc_seq
*sp
, struct fc_frame
*fp
,
655 struct fc_disc
*disc
= disc_arg
;
656 struct fc_ct_hdr
*cp
;
657 struct fc_frame_header
*fh
;
658 unsigned int seq_cnt
;
663 mutex_lock(&disc
->disc_mutex
);
664 FC_DISC_DBG(disc
, "Received a GPN_FT response\n");
667 fc_disc_error(disc
, fp
);
668 mutex_unlock(&disc
->disc_mutex
);
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
));
680 FC_DISC_DBG(disc
, "GPN_FT response too short, len %d\n",
682 } else if (ntohs(cp
->ct_cmd
) == FC_FS_ACC
) {
684 /* Accepted, parse the response. */
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
,
691 disc
->event
= DISC_EV_FAILED
;
694 FC_DISC_DBG(disc
, "GPN_FT unexpected response code "
695 "%x\n", ntohs(cp
->ct_cmd
));
697 } else if (fr_sof(fp
) == FC_SOF_N3
&&
698 seq_cnt
== disc
->seq_count
) {
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
));
706 error
= fc_disc_gpn_ft_parse(disc
, buf
, len
);
708 fc_disc_error(disc
, fp
);
714 mutex_unlock(&disc
->disc_mutex
);
718 * fc_disc_single() - Discover the directory information for a single target
719 * @lport: FC local port
720 * @dp: The port to rediscover
722 * Locking Note: This function expects that the disc_mutex is locked
723 * before it is called.
725 static void fc_disc_single(struct fc_disc
*disc
, struct fc_disc_port
*dp
)
727 struct fc_lport
*lport
;
728 struct fc_rport_priv
*rdata
;
732 if (dp
->ids
.port_id
== fc_host_port_id(lport
->host
))
735 rdata
= lport
->tt
.rport_create(lport
, &dp
->ids
);
737 rdata
->ops
= &fc_disc_rport_ops
;
739 list_add_tail(&rdata
->peers
, &disc
->rogue_rports
);
740 lport
->tt
.rport_login(rdata
);
748 * fc_disc_stop() - Stop discovery for a given lport
749 * @lport: The lport that discovery should stop for
751 void fc_disc_stop(struct fc_lport
*lport
)
753 struct fc_disc
*disc
= &lport
->disc
;
756 cancel_delayed_work_sync(&disc
->disc_work
);
757 fc_disc_stop_rports(disc
);
762 * fc_disc_stop_final() - Stop discovery for a given lport
763 * @lport: The lport that discovery should stop for
765 * This function will block until discovery has been
766 * completely stopped and all rports have been deleted.
768 void fc_disc_stop_final(struct fc_lport
*lport
)
771 lport
->tt
.rport_flush_queue();
775 * fc_disc_init() - Initialize the discovery block
776 * @lport: FC local port
778 int fc_disc_init(struct fc_lport
*lport
)
780 struct fc_disc
*disc
;
782 if (!lport
->tt
.disc_start
)
783 lport
->tt
.disc_start
= fc_disc_start
;
785 if (!lport
->tt
.disc_stop
)
786 lport
->tt
.disc_stop
= fc_disc_stop
;
788 if (!lport
->tt
.disc_stop_final
)
789 lport
->tt
.disc_stop_final
= fc_disc_stop_final
;
791 if (!lport
->tt
.disc_recv_req
)
792 lport
->tt
.disc_recv_req
= fc_disc_recv_req
;
794 if (!lport
->tt
.rport_lookup
)
795 lport
->tt
.rport_lookup
= fc_disc_lookup_rport
;
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
);
804 disc
->delay
= FC_DISC_DELAY
;
805 disc
->event
= DISC_EV_NONE
;
809 EXPORT_SYMBOL(fc_disc_init
);