[SCSI] libfc, libfcoe: FDISC ELS for NPIV

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>
diff --git a/include/scsi/fc/fc_els.h b/include/scsi/fc/fc_els.h
index 195ca01..b0872af 100644
--- a/include/scsi/fc/fc_els.h
+++ b/include/scsi/fc/fc_els.h
@@ -248,10 +248,12 @@
 /*
  * 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 */
diff --git a/include/scsi/fc_encode.h b/include/scsi/fc_encode.h
index 27dad70..c93ca3e 100644
--- a/include/scsi/fc_encode.h
+++ b/include/scsi/fc_encode.h
@@ -198,6 +198,31 @@
 	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 @@
 		fc_flogi_fill(lport, fp);
 		break;
 
+	case ELS_FDISC:
+		fc_fdisc_fill(lport, fp);
+		break;
+
 	case ELS_LOGO:
 		fc_logo_fill(lport, fp);
 		break;