[SCSI] libfc, libfcoe: FDISC ELS for NPIV
Chris Leech [Tue, 3 Nov 2009 19:46:24 +0000 (11:46 -0800)]
Add FDISC ELS handling to libfc and libfcoe, treat it the same as FLOGI where
appropriate.

Add checking for NPIV support in the FLOGI LS_ACC service parameters.

Signed-off-by: Chris Leech <christopher.leech@intel.com>
Signed-off-by: Robert Love <robert.w.love@intel.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>

drivers/scsi/fcoe/libfcoe.c
drivers/scsi/libfc/fc_lport.c
include/scsi/fc/fc_els.h
include/scsi/fc_encode.h

index 11ae5c9..d8ea04a 100644 (file)
@@ -449,7 +449,7 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip,
        memset(mac, 0, sizeof(mac));
        mac->fd_desc.fip_dtype = FIP_DT_MAC;
        mac->fd_desc.fip_dlen = sizeof(*mac) / FIP_BPW;
-       if (dtype != FIP_DT_FLOGI)
+       if (dtype != FIP_DT_FLOGI && dtype != FIP_DT_FDISC)
                memcpy(mac->fd_mac, fip->data_src_addr, ETH_ALEN);
        else if (fip->spma)
                memcpy(mac->fd_mac, fip->ctl_src_addr, ETH_ALEN);
@@ -865,8 +865,8 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
                goto drop;
        els_op = *(u8 *)(fh + 1);
 
-       if (els_dtype == FIP_DT_FLOGI && sub == FIP_SC_REP &&
-           fip->flogi_oxid == ntohs(fh->fh_ox_id) &&
+       if ((els_dtype == FIP_DT_FLOGI || els_dtype == FIP_DT_FDISC) &&
+           sub == FIP_SC_REP && fip->flogi_oxid == ntohs(fh->fh_ox_id) &&
            els_op == ELS_LS_ACC && is_valid_ether_addr(granted_mac)) {
                fip->flogi_oxid = FC_XID_UNKNOWN;
                fip->update_mac(fip, fip->data_src_addr, granted_mac);
index 46897cf..ccba67c 100644 (file)
@@ -1449,6 +1449,9 @@ static void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
                        e_d_tov = ntohl(flp->fl_csp.sp_e_d_tov);
                        if (csp_flags & FC_SP_FT_EDTR)
                                e_d_tov /= 1000000;
+
+                       lport->npiv_enabled = !!(csp_flags & FC_SP_FT_NPIV_ACC);
+
                        if ((csp_flags & FC_SP_FT_FPORT) == 0) {
                                if (e_d_tov > lport->e_d_tov)
                                        lport->e_d_tov = e_d_tov;
@@ -1498,7 +1501,8 @@ void fc_lport_enter_flogi(struct fc_lport *lport)
        if (!fp)
                return fc_lport_error(lport, fp);
 
-       if (!lport->tt.elsct_send(lport, FC_FID_FLOGI, fp, ELS_FLOGI,
+       if (!lport->tt.elsct_send(lport, FC_FID_FLOGI, fp,
+                                 lport->vport ? ELS_FDISC : ELS_FLOGI,
                                  fc_lport_flogi_resp, lport, lport->e_d_tov))
                fc_lport_error(lport, NULL);
 }
index 195ca01..b0872af 100644 (file)
@@ -248,10 +248,12 @@ struct fc_els_csp {
 /*
  * sp_features
  */
-#define        FC_SP_FT_CIRO   0x8000  /* continuously increasing rel. off. */
+#define        FC_SP_FT_NPIV   0x8000  /* multiple N_Port_ID support (FLOGI) */
+#define        FC_SP_FT_CIRO   0x8000  /* continuously increasing rel off (PLOGI) */
 #define        FC_SP_FT_CLAD   0x8000  /* clean address (in FLOGI LS_ACC) */
 #define        FC_SP_FT_RAND   0x4000  /* random relative offset */
 #define        FC_SP_FT_VAL    0x2000  /* valid vendor version level */
+#define        FC_SP_FT_NPIV_ACC       0x2000  /* NPIV assignment (FLOGI LS_ACC) */
 #define        FC_SP_FT_FPORT  0x1000  /* F port (1) vs. N port (0) */
 #define        FC_SP_FT_ABB    0x0800  /* alternate BB_credit management */
 #define        FC_SP_FT_EDTR   0x0400  /* E_D_TOV Resolution is nanoseconds */
index 27dad70..c93ca3e 100644 (file)
@@ -198,6 +198,31 @@ static inline void fc_flogi_fill(struct fc_lport *lport, struct fc_frame *fp)
        sp->sp_bb_data = htons((u16) lport->mfs);
        cp = &flogi->fl_cssp[3 - 1];    /* class 3 parameters */
        cp->cp_class = htons(FC_CPC_VALID | FC_CPC_SEQ);
+       if (lport->does_npiv)
+               sp->sp_features = htons(FC_SP_FT_NPIV);
+}
+
+/**
+ * fc_fdisc_fill - Fill in a fdisc request frame.
+ */
+static inline void fc_fdisc_fill(struct fc_lport *lport, struct fc_frame *fp)
+{
+       struct fc_els_csp *sp;
+       struct fc_els_cssp *cp;
+       struct fc_els_flogi *fdisc;
+
+       fdisc = fc_frame_payload_get(fp, sizeof(*fdisc));
+       memset(fdisc, 0, sizeof(*fdisc));
+       fdisc->fl_cmd = (u8) ELS_FDISC;
+       put_unaligned_be64(lport->wwpn, &fdisc->fl_wwpn);
+       put_unaligned_be64(lport->wwnn, &fdisc->fl_wwnn);
+       sp = &fdisc->fl_csp;
+       sp->sp_hi_ver = 0x20;
+       sp->sp_lo_ver = 0x20;
+       sp->sp_bb_cred = htons(10);     /* this gets set by gateway */
+       sp->sp_bb_data = htons((u16) lport->mfs);
+       cp = &fdisc->fl_cssp[3 - 1];    /* class 3 parameters */
+       cp->cp_class = htons(FC_CPC_VALID | FC_CPC_SEQ);
 }
 
 /**
@@ -296,6 +321,10 @@ static inline int fc_els_fill(struct fc_lport *lport,
                fc_flogi_fill(lport, fp);
                break;
 
+       case ELS_FDISC:
+               fc_fdisc_fill(lport, fp);
+               break;
+
        case ELS_LOGO:
                fc_logo_fill(lport, fp);
                break;