aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/libfc/fc_disc.c137
-rw-r--r--drivers/scsi/libfc/fc_elsct.c2
-rw-r--r--include/scsi/fc_encode.h16
3 files changed, 128 insertions, 27 deletions
diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c
index 4242894cce7c..c48799e9dd8e 100644
--- a/drivers/scsi/libfc/fc_disc.c
+++ b/drivers/scsi/libfc/fc_disc.c
@@ -47,7 +47,7 @@ static void fc_disc_gpn_ft_req(struct fc_disc *);
47static void fc_disc_gpn_ft_resp(struct fc_seq *, struct fc_frame *, void *); 47static void fc_disc_gpn_ft_resp(struct fc_seq *, struct fc_frame *, void *);
48static void fc_disc_done(struct fc_disc *, enum fc_disc_event); 48static void fc_disc_done(struct fc_disc *, enum fc_disc_event);
49static void fc_disc_timeout(struct work_struct *); 49static void fc_disc_timeout(struct work_struct *);
50static void fc_disc_single(struct fc_disc *, struct fc_disc_port *); 50static int fc_disc_single(struct fc_lport *, struct fc_disc_port *);
51static void fc_disc_restart(struct fc_disc *); 51static void fc_disc_restart(struct fc_disc *);
52 52
53/** 53/**
@@ -83,7 +83,6 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp,
83 struct fc_disc *disc) 83 struct fc_disc *disc)
84{ 84{
85 struct fc_lport *lport; 85 struct fc_lport *lport;
86 struct fc_rport_priv *rdata;
87 struct fc_els_rscn *rp; 86 struct fc_els_rscn *rp;
88 struct fc_els_rscn_page *pp; 87 struct fc_els_rscn_page *pp;
89 struct fc_seq_els_data rjt_data; 88 struct fc_seq_els_data rjt_data;
@@ -150,6 +149,19 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp,
150 } 149 }
151 } 150 }
152 lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); 151 lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL);
152
153 /*
154 * If not doing a complete rediscovery, do GPN_ID on
155 * the individual ports mentioned in the list.
156 * If any of these get an error, do a full rediscovery.
157 * In any case, go through the list and free the entries.
158 */
159 list_for_each_entry_safe(dp, next, &disc_ports, peers) {
160 list_del(&dp->peers);
161 if (!redisc)
162 redisc = fc_disc_single(lport, dp);
163 kfree(dp);
164 }
153 if (redisc) { 165 if (redisc) {
154 FC_DISC_DBG(disc, "RSCN received: rediscovering\n"); 166 FC_DISC_DBG(disc, "RSCN received: rediscovering\n");
155 fc_disc_restart(disc); 167 fc_disc_restart(disc);
@@ -157,14 +169,6 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp,
157 FC_DISC_DBG(disc, "RSCN received: not rediscovering. " 169 FC_DISC_DBG(disc, "RSCN received: not rediscovering. "
158 "redisc %d state %d in_prog %d\n", 170 "redisc %d state %d in_prog %d\n",
159 redisc, lport->state, disc->pending); 171 redisc, lport->state, disc->pending);
160 list_for_each_entry_safe(dp, next, &disc_ports, peers) {
161 list_del(&dp->peers);
162 rdata = lport->tt.rport_lookup(lport, dp->port_id);
163 if (rdata) {
164 lport->tt.rport_logoff(rdata);
165 }
166 fc_disc_single(disc, dp);
167 }
168 } 172 }
169 fc_frame_free(fp); 173 fc_frame_free(fp);
170 return; 174 return;
@@ -562,32 +566,117 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp,
562} 566}
563 567
564/** 568/**
565 * fc_disc_single() - Discover the directory information for a single target 569 * fc_disc_gpn_id_resp() - Handle a response frame from Get Port Names (GPN_ID)
566 * @lport: FC local port 570 * @sp: exchange sequence
567 * @dp: The port to rediscover 571 * @fp: response frame
572 * @rdata_arg: remote port private data
568 * 573 *
569 * Locking Note: This function expects that the disc_mutex is locked 574 * Locking Note: This function is called without disc mutex held.
570 * before it is called.
571 */ 575 */
572static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp) 576static void fc_disc_gpn_id_resp(struct fc_seq *sp, struct fc_frame *fp,
577 void *rdata_arg)
573{ 578{
579 struct fc_rport_priv *rdata = rdata_arg;
580 struct fc_rport_priv *new_rdata;
574 struct fc_lport *lport; 581 struct fc_lport *lport;
575 struct fc_rport_priv *rdata; 582 struct fc_disc *disc;
583 struct fc_ct_hdr *cp;
584 struct fc_ns_gid_pn *pn;
585 u64 port_name;
576 586
577 lport = disc->lport; 587 lport = rdata->local_port;
588 disc = &lport->disc;
578 589
579 if (dp->port_id == fc_host_port_id(lport->host)) 590 mutex_lock(&disc->disc_mutex);
591 if (PTR_ERR(fp) == -FC_EX_CLOSED)
580 goto out; 592 goto out;
593 if (IS_ERR(fp))
594 goto redisc;
595
596 cp = fc_frame_payload_get(fp, sizeof(*cp));
597 if (!cp)
598 goto redisc;
599 if (ntohs(cp->ct_cmd) == FC_FS_ACC) {
600 if (fr_len(fp) < sizeof(struct fc_frame_header) +
601 sizeof(*cp) + sizeof(*pn))
602 goto redisc;
603 pn = (struct fc_ns_gid_pn *)(cp + 1);
604 port_name = get_unaligned_be64(&pn->fn_wwpn);
605 if (rdata->ids.port_name == -1)
606 rdata->ids.port_name = port_name;
607 else if (rdata->ids.port_name != port_name) {
608 FC_DISC_DBG(disc, "GPN_ID accepted. WWPN changed. "
609 "Port-id %x wwpn %llx\n",
610 rdata->ids.port_id, port_name);
611 lport->tt.rport_logoff(rdata);
581 612
582 rdata = lport->tt.rport_create(lport, dp->port_id); 613 new_rdata = lport->tt.rport_create(lport,
583 if (rdata) { 614 rdata->ids.port_id);
615 if (new_rdata) {
616 new_rdata->disc_id = disc->disc_id;
617 lport->tt.rport_login(new_rdata);
618 }
619 goto out;
620 }
584 rdata->disc_id = disc->disc_id; 621 rdata->disc_id = disc->disc_id;
585 kfree(dp);
586 lport->tt.rport_login(rdata); 622 lport->tt.rport_login(rdata);
623 } else if (ntohs(cp->ct_cmd) == FC_FS_RJT) {
624 FC_DISC_DBG(disc, "GPN_ID rejected reason %x exp %x\n",
625 cp->ct_reason, cp->ct_explan);
626 lport->tt.rport_logoff(rdata);
627 } else {
628 FC_DISC_DBG(disc, "GPN_ID unexpected response code %x\n",
629 ntohs(cp->ct_cmd));
630redisc:
631 fc_disc_restart(disc);
587 } 632 }
588 return;
589out: 633out:
590 kfree(dp); 634 mutex_unlock(&disc->disc_mutex);
635 kref_put(&rdata->kref, lport->tt.rport_destroy);
636}
637
638/**
639 * fc_disc_gpn_id_req() - Send Get Port Names by ID (GPN_ID) request
640 * @lport: local port
641 * @rdata: remote port private data
642 *
643 * Locking Note: This function expects that the disc_mutex is locked
644 * before it is called.
645 * On failure, an error code is returned.
646 */
647static int fc_disc_gpn_id_req(struct fc_lport *lport,
648 struct fc_rport_priv *rdata)
649{
650 struct fc_frame *fp;
651
652 fp = fc_frame_alloc(lport, sizeof(struct fc_ct_hdr) +
653 sizeof(struct fc_ns_fid));
654 if (!fp)
655 return -ENOMEM;
656 if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, FC_NS_GPN_ID,
657 fc_disc_gpn_id_resp, rdata, lport->e_d_tov))
658 return -ENOMEM;
659 kref_get(&rdata->kref);
660 return 0;
661}
662
663/**
664 * fc_disc_single() - Discover the directory information for a single target
665 * @lport: local port
666 * @dp: The port to rediscover
667 *
668 * Locking Note: This function expects that the disc_mutex is locked
669 * before it is called.
670 */
671static int fc_disc_single(struct fc_lport *lport, struct fc_disc_port *dp)
672{
673 struct fc_rport_priv *rdata;
674
675 rdata = lport->tt.rport_create(lport, dp->port_id);
676 if (!rdata)
677 return -ENOMEM;
678 rdata->disc_id = 0;
679 return fc_disc_gpn_id_req(lport, rdata);
591} 680}
592 681
593/** 682/**
diff --git a/drivers/scsi/libfc/fc_elsct.c b/drivers/scsi/libfc/fc_elsct.c
index d655924d46b6..5cfa68732e9d 100644
--- a/drivers/scsi/libfc/fc_elsct.c
+++ b/drivers/scsi/libfc/fc_elsct.c
@@ -49,7 +49,7 @@ static struct fc_seq *fc_elsct_send(struct fc_lport *lport,
49 rc = fc_els_fill(lport, did, fp, op, &r_ctl, &fh_type); 49 rc = fc_els_fill(lport, did, fp, op, &r_ctl, &fh_type);
50 else { 50 else {
51 /* CT requests */ 51 /* CT requests */
52 rc = fc_ct_fill(lport, fp, op, &r_ctl, &fh_type); 52 rc = fc_ct_fill(lport, did, fp, op, &r_ctl, &fh_type);
53 did = FC_FID_DIR_SERV; 53 did = FC_FID_DIR_SERV;
54 } 54 }
55 55
diff --git a/include/scsi/fc_encode.h b/include/scsi/fc_encode.h
index c5ee6bb79e05..27dad703824f 100644
--- a/include/scsi/fc_encode.h
+++ b/include/scsi/fc_encode.h
@@ -32,6 +32,7 @@ struct fc_ct_req {
32 struct fc_ns_gid_ft gid; 32 struct fc_ns_gid_ft gid;
33 struct fc_ns_rn_id rn; 33 struct fc_ns_rn_id rn;
34 struct fc_ns_rft rft; 34 struct fc_ns_rft rft;
35 struct fc_ns_fid fid;
35 } payload; 36 } payload;
36}; 37};
37 38
@@ -94,10 +95,16 @@ static inline struct fc_ct_req *fc_ct_hdr_fill(const struct fc_frame *fp,
94} 95}
95 96
96/** 97/**
97 * fc_ct_fill - Fill in a name service request frame 98 * fc_ct_fill() - Fill in a name service request frame
99 * @lport: local port.
100 * @fc_id: FC_ID of non-destination rport for GPN_ID and similar inquiries.
101 * @fp: frame to contain payload.
102 * @op: CT opcode.
103 * @r_ctl: pointer to FC header R_CTL.
104 * @fh_type: pointer to FC-4 type.
98 */ 105 */
99static inline int fc_ct_fill(struct fc_lport *lport, 106static inline int fc_ct_fill(struct fc_lport *lport,
100 struct fc_frame *fp, 107 u32 fc_id, struct fc_frame *fp,
101 unsigned int op, enum fc_rctl *r_ctl, 108 unsigned int op, enum fc_rctl *r_ctl,
102 enum fc_fh_type *fh_type) 109 enum fc_fh_type *fh_type)
103{ 110{
@@ -109,6 +116,11 @@ static inline int fc_ct_fill(struct fc_lport *lport,
109 ct->payload.gid.fn_fc4_type = FC_TYPE_FCP; 116 ct->payload.gid.fn_fc4_type = FC_TYPE_FCP;
110 break; 117 break;
111 118
119 case FC_NS_GPN_ID:
120 ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_fid));
121 hton24(ct->payload.fid.fp_fid, fc_id);
122 break;
123
112 case FC_NS_RFT_ID: 124 case FC_NS_RFT_ID:
113 ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rft)); 125 ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rft));
114 hton24(ct->payload.rft.fid.fp_fid, 126 hton24(ct->payload.rft.fid.fp_fid,