36 #include <linux/slab.h>
38 #include <linux/export.h>
39 #include <asm/unaligned.h>
47 #define FC_DISC_RETRY_LIMIT 3
48 #define FC_DISC_RETRY_DELAY 500UL
50 static void fc_disc_gpn_ft_req(
struct fc_disc *);
51 static void fc_disc_gpn_ft_resp(
struct fc_seq *,
struct fc_frame *,
void *);
55 static void fc_disc_restart(
struct fc_disc *);
64 static void fc_disc_stop_rports(
struct fc_disc *disc)
69 lport = fc_disc_lport(disc);
72 list_for_each_entry_rcu(rdata, &disc->
rports,
peers)
73 lport->
tt.rport_logoff(rdata);
98 lport = fc_disc_lport(disc);
103 rp = fc_frame_payload_get(fp,
sizeof(*rp));
111 if (len <
sizeof(*rp))
114 rp = fc_frame_payload_get(fp, len);
119 if (len %
sizeof(*pp))
122 for (pp = (
void *)(rp + 1); len > 0; len -=
sizeof(*pp), pp++) {
148 FC_DISC_DBG(disc,
"Address format is (%d)\n", fmt);
164 redisc = fc_disc_single(lport, dp);
168 FC_DISC_DBG(disc,
"RSCN received: rediscovering\n");
169 fc_disc_restart(disc);
171 FC_DISC_DBG(disc,
"RSCN received: not rediscovering. "
172 "redisc %d state %d in_prog %d\n",
173 redisc, lport->
state, disc->pending);
199 op = fc_frame_payload_op(fp);
203 fc_disc_recv_rscn_req(disc, fp);
207 FC_DISC_DBG(disc,
"Received an unsupported request, "
208 "the opcode is (%x)\n", op);
221 static void fc_disc_restart(
struct fc_disc *disc)
239 fc_disc_gpn_ft_req(disc);
260 fc_disc_restart(disc);
275 struct fc_lport *lport = fc_disc_lport(disc);
282 fc_disc_restart(disc);
292 list_for_each_entry_rcu(rdata, &disc->
rports,
peers) {
296 lport->
tt.rport_login(rdata);
298 lport->
tt.rport_logoff(rdata);
313 struct fc_lport *lport = fc_disc_lport(disc);
314 unsigned long delay = 0;
357 static void fc_disc_gpn_ft_req(
struct fc_disc *disc)
360 struct fc_lport *lport = fc_disc_lport(disc);
362 WARN_ON(!fc_lport_test_ready(lport));
369 fp = fc_frame_alloc(lport,
375 if (lport->
tt.elsct_send(lport, 0, fp,
381 fc_disc_error(disc,
NULL);
392 static int fc_disc_gpn_ft_parse(
struct fc_disc *disc,
void *
buf,
size_t len)
403 lport = fc_disc_lport(disc);
416 plen =
sizeof(*np) - tlen;
422 memcpy((
char *)np + tlen, bp, plen);
432 if (plen ==
sizeof(*np))
443 while (plen >=
sizeof(*np)) {
447 if (ids.port_id != lport->
port_id &&
448 ids.port_name != lport->
wwpn) {
449 rdata = lport->
tt.rport_create(lport, ids.
port_id);
451 rdata->
ids.port_name = ids.port_name;
455 "memory for the newly discovered port "
456 "(%6.6x)\n", ids.port_id);
475 if (error == 0 && len > 0 && len <
sizeof(*np)) {
496 fc_disc_gpn_ft_req(disc);
512 struct fc_disc *disc = disc_arg;
516 unsigned int seq_cnt;
524 fc_disc_error(disc, fp);
529 WARN_ON(!fc_frame_is_linear(fp));
530 fh = fc_frame_header_get(fp);
531 len =
fr_len(fp) -
sizeof(*fh);
534 cp = fc_frame_payload_get(fp,
sizeof(*cp));
536 FC_DISC_DBG(disc,
"GPN_FT response too short, len %d\n",
543 error = fc_disc_gpn_ft_parse(disc, cp + 1, len);
545 FC_DISC_DBG(disc,
"GPN_FT rejected reason %x exp %x "
553 FC_DISC_DBG(disc,
"GPN_FT unexpected response code "
558 error = fc_disc_gpn_ft_parse(disc, fh + 1, len);
560 FC_DISC_DBG(disc,
"GPN_FT unexpected frame - out of sequence? "
561 "seq_cnt %x expected %x sof %x eof %x\n",
566 fc_disc_error(disc, fp);
568 fc_disc_done(disc, event);
581 static void fc_disc_gpn_id_resp(
struct fc_seq *sp,
struct fc_frame *fp,
601 cp = fc_frame_payload_get(fp,
sizeof(*cp));
606 sizeof(*cp) +
sizeof(*pn))
610 if (rdata->
ids.port_name == -1)
612 else if (rdata->
ids.port_name != port_name) {
613 FC_DISC_DBG(disc,
"GPN_ID accepted. WWPN changed. "
614 "Port-id %6.6x wwpn %16.16llx\n",
615 rdata->
ids.port_id, port_name);
616 lport->
tt.rport_logoff(rdata);
618 new_rdata = lport->
tt.rport_create(lport,
622 lport->
tt.rport_login(new_rdata);
627 lport->
tt.rport_login(rdata);
629 FC_DISC_DBG(disc,
"GPN_ID rejected reason %x exp %x\n",
631 lport->
tt.rport_logoff(rdata);
633 FC_DISC_DBG(disc,
"GPN_ID unexpected response code %x\n",
636 fc_disc_restart(disc);
640 kref_put(&rdata->
kref, lport->
tt.rport_destroy);
652 static int fc_disc_gpn_id_req(
struct fc_lport *lport,
657 fp = fc_frame_alloc(lport,
sizeof(
struct fc_ct_hdr) +
662 fc_disc_gpn_id_resp, rdata,
665 kref_get(&rdata->
kref);
681 rdata = lport->
tt.rport_create(lport, dp->
port_id);
685 return fc_disc_gpn_id_req(lport, rdata);
692 static void fc_disc_stop(
struct fc_lport *lport)
698 fc_disc_stop_rports(disc);
708 static void fc_disc_stop_final(
struct fc_lport *lport)
711 lport->
tt.rport_flush_queue();
722 if (!lport->
tt.disc_start)
723 lport->
tt.disc_start = fc_disc_start;
725 if (!lport->
tt.disc_stop)
726 lport->
tt.disc_stop = fc_disc_stop;
728 if (!lport->
tt.disc_stop_final)
729 lport->
tt.disc_stop_final = fc_disc_stop_final;
731 if (!lport->
tt.disc_recv_req)
732 lport->
tt.disc_recv_req = fc_disc_recv_req;
737 INIT_LIST_HEAD(&disc->
rports);