Skip to contentSkip to conversation

Open-FCoE Submission

PATCH In review Robert Love 2 participants 7 messages Nov 18, 2008 – Dec 2, 2008

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover Open-FCoE Submission

The following series adds the following code to the SCSI subsystem.

1) FC and FCoE protocol definitions in header files
- Files are added in include/scsi/fc/
- New files are: fc_els.h, fc_encaps.h, fc_fc2.h, fc_fcp.h, fc_fs.h, fc_gs.h and fc_ns.h

2) libfc - a FC assist library
- Composed of 5 sub-components: Exchange Manager, Local Port Remote Port, Discovery and SCSI-FCP
- Uses libfc_function_template for cross-layer calls
- Uses struct fc_lport as primary object shared by all sub-modules
- Common code defined in include/scsi/libfc.h

3) fcoe - a FCoE initiator implementation
- Simple encapsulation and unpacking layer
- Interacts with netdev
- Initial support for FCoE offload
- Uses /sys/module/fcoe/parameters/create and destroy for enabling/disabling FCoE connection over a particular Ethernet adapter
- Works on any Ethernet adapter

These patches apply to both the scsi-misc and scsi-rc-fixes trees.

We've spent a lot of time recently improving stability and creating different interfaces for potential users. We'd like to be queued for the 2.6.29 merge window. We're actively developing this stack and we will continue to have a lot of changes, but I think that the code is at a good place right now and it's ready for inclusion. Please let me know what you think.

---

Robert Love (3):
fcoe: Fibre Channel over Ethernet
libfc: A modular Fibre Channel library
FC protocol definition header files

 drivers/scsi/Kconfig                  |   13 
 drivers/scsi/Makefile                 |    2 
 drivers/scsi/fcoe/Makefile            |    8 
 drivers/scsi/fcoe/fc_transport_fcoe.c |  446 +++++++
 drivers/scsi/fcoe/fcoe_sw.c           |  488 ++++++++
 drivers/scsi/fcoe/libfcoe.c           | 1506 +++++++++++++++++++++++
 drivers/scsi/libfc/Makefile           |   12 
 drivers/scsi/libfc/fc_disc.c          |  932 ++++++++++++++
 drivers/scsi/libfc/fc_elsct.c         |   71 +
 drivers/scsi/libfc/fc_exch.c          | 1971 +++++++++++++++++++++++++++++++
 drivers/scsi/libfc/fc_fcp.c           | 2130 +++++++++++++++++++++++++++++++++
 drivers/scsi/libfc/fc_frame.c         |   89 +
 drivers/scsi/libfc/fc_lport.c         | 1525 ++++++++++++++++++++++++
 drivers/scsi/libfc/fc_rport.c         | 1277 ++++++++++++++++++++
 include/scsi/fc/fc_els.h              |  802 ++++++++++++
 include/scsi/fc/fc_encaps.h           |  138 ++
 include/scsi/fc/fc_fc2.h              |  124 ++
 include/scsi/fc/fc_fcoe.h             |  102 ++
 include/scsi/fc/fc_fcp.h              |  199 +++
 include/scsi/fc/fc_fs.h               |  340 +++++
 include/scsi/fc/fc_gs.h               |   93 +
 include/scsi/fc/fc_ns.h               |  159 ++
 include/scsi/fc_encode.h              |  309 +++++
 include/scsi/fc_frame.h               |  239 ++++
 include/scsi/fc_transport_fcoe.h      |   54 +
 include/scsi/libfc.h                  |  917 ++++++++++++++
 include/scsi/libfcoe.h                |  177 +++
 27 files changed, 14123 insertions(+), 0 deletions(-)
 create mode 100644 drivers/scsi/fcoe/Makefile
 create mode 100644 drivers/scsi/fcoe/fc_transport_fcoe.c
 create mode 100644 drivers/scsi/fcoe/fcoe_sw.c
 create mode 100644 drivers/scsi/fcoe/libfcoe.c
 create mode 100644 drivers/scsi/libfc/Makefile
 create mode 100644 drivers/scsi/libfc/fc_disc.c
 create mode 100644 drivers/scsi/libfc/fc_elsct.c
 create mode 100644 drivers/scsi/libfc/fc_exch.c
 create mode 100644 drivers/scsi/libfc/fc_fcp.c
 create mode 100644 drivers/scsi/libfc/fc_frame.c
 create mode 100644 drivers/scsi/libfc/fc_lport.c
 create mode 100644 drivers/scsi/libfc/fc_rport.c
 create mode 100644 include/scsi/fc/fc_els.h
 create mode 100644 include/scsi/fc/fc_encaps.h
 create mode 100644 include/scsi/fc/fc_fc2.h
 create mode 100644 include/scsi/fc/fc_fcoe.h
 create mode 100644 include/scsi/fc/fc_fcp.h
 create mode 100644 include/scsi/fc/fc_fs.h
 create mode 100644 include/scsi/fc/fc_gs.h
 create mode 100644 include/scsi/fc/fc_ns.h
 create mode 100644 include/scsi/fc_encode.h
 create mode 100644 include/scsi/fc_frame.h
 create mode 100644 include/scsi/fc_transport_fcoe.h
 create mode 100644 include/scsi/libfc.h
 create mode 100644 include/scsi/libfcoe.h
Signature · 1 line
//Rob
#1 lore raw

PATCH 1/3 FC protocol definition header files

---

 include/scsi/fc/fc_els.h    |  802 +++++++++++++++++++++++++++++++++++++++++++
 include/scsi/fc/fc_encaps.h |  138 +++++++
 include/scsi/fc/fc_fc2.h    |  124 +++++++
 include/scsi/fc/fc_fcoe.h   |  102 +++++
 include/scsi/fc/fc_fcp.h    |  199 +++++++++++
 include/scsi/fc/fc_fs.h     |  340 ++++++++++++++++++
 include/scsi/fc/fc_gs.h     |   93 +++++
 include/scsi/fc/fc_ns.h     |  159 +++++++++
 8 files changed, 1957 insertions(+), 0 deletions(-)
 create mode 100644 include/scsi/fc/fc_els.h
 create mode 100644 include/scsi/fc/fc_encaps.h
 create mode 100644 include/scsi/fc/fc_fc2.h
 create mode 100644 include/scsi/fc/fc_fcoe.h
 create mode 100644 include/scsi/fc/fc_fcp.h
 create mode 100644 include/scsi/fc/fc_fs.h
 create mode 100644 include/scsi/fc/fc_gs.h
 create mode 100644 include/scsi/fc/fc_ns.h
include/scsi/fc/fc_els.h new file +802 -0
new file mode 100644
index 0000000..af4bf0c
@@ -0,0 +1,802 @@
+/*
+ * Copyright(c) 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Maintained at www.Open-FCoE.org
+ */
+
+#ifndef _FC_ELS_H_
+#define	_FC_ELS_H_
+
+/*
+ * Fibre Channel Switch - Enhanced Link Services definitions.
+ * From T11 FC-LS Rev 1.2 June 7, 2005.
+ */
+
+/*
+ * ELS Command codes - byte 0 of the frame payload
+ */
+enum fc_els_cmd {
+	ELS_LS_RJT =	0x01,	/* ESL reject */
+	ELS_LS_ACC =	0x02,	/* ESL Accept */
+	ELS_PLOGI =	0x03,	/* N_Port login */
+	ELS_FLOGI =	0x04,	/* F_Port login */
+	ELS_LOGO =	0x05,	/* Logout */
+	ELS_ABTX =	0x06,	/* Abort exchange - obsolete */
+	ELS_RCS =	0x07,	/* read connection status */
+	ELS_RES =	0x08,	/* read exchange status block */
+	ELS_RSS =	0x09,	/* read sequence status block */
+	ELS_RSI =	0x0a,	/* read sequence initiative */
+	ELS_ESTS =	0x0b,	/* establish streaming */
+	ELS_ESTC =	0x0c,	/* estimate credit */
+	ELS_ADVC =	0x0d,	/* advise credit */
+	ELS_RTV =	0x0e,	/* read timeout value */
+	ELS_RLS =	0x0f,	/* read link error status block */
+	ELS_ECHO =	0x10,	/* echo */
+	ELS_TEST =	0x11,	/* test */
+	ELS_RRQ =	0x12,	/* reinstate recovery qualifier */
+	ELS_REC =	0x13,	/* read exchange concise */
+	ELS_SRR =	0x14,	/* sequence retransmission request */
+	ELS_PRLI =	0x20,	/* process login */
+	ELS_PRLO =	0x21,	/* process logout */
+	ELS_SCN =	0x22,	/* state change notification */
+	ELS_TPLS =	0x23,	/* test process login state */
+	ELS_TPRLO =	0x24,	/* third party process logout */
+	ELS_LCLM =	0x25,	/* login control list mgmt (obs) */
+	ELS_GAID =	0x30,	/* get alias_ID */
+	ELS_FACT =	0x31,	/* fabric activate alias_id */
+	ELS_FDACDT =	0x32,	/* fabric deactivate alias_id */
+	ELS_NACT =	0x33,	/* N-port activate alias_id */
+	ELS_NDACT =	0x34,	/* N-port deactivate alias_id */
+	ELS_QOSR =	0x40,	/* quality of service request */
+	ELS_RVCS =	0x41,	/* read virtual circuit status */
+	ELS_PDISC =	0x50,	/* discover N_port service params */
+	ELS_FDISC =	0x51,	/* discover F_port service params */
+	ELS_ADISC =	0x52,	/* discover address */
+	ELS_RNC =	0x53,	/* report node cap (obs) */
+	ELS_FARP_REQ =	0x54,	/* FC ARP request */
+	ELS_FARP_REPL =	0x55,	/* FC ARP reply */
+	ELS_RPS =	0x56,	/* read port status block */
+	ELS_RPL =	0x57,	/* read port list */
+	ELS_RPBC =	0x58,	/* read port buffer condition */
+	ELS_FAN =	0x60,	/* fabric address notification */
+	ELS_RSCN =	0x61,	/* registered state change notification */
+	ELS_SCR =	0x62,	/* state change registration */
+	ELS_RNFT =	0x63,	/* report node FC-4 types */
+	ELS_CSR =	0x68,	/* clock synch. request */
+	ELS_CSU =	0x69,	/* clock synch. update */
+	ELS_LINIT =	0x70,	/* loop initialize */
+	ELS_LSTS =	0x72,	/* loop status */
+	ELS_RNID =	0x78,	/* request node ID data */
+	ELS_RLIR =	0x79,	/* registered link incident report */
+	ELS_LIRR =	0x7a,	/* link incident record registration */
+	ELS_SRL =	0x7b,	/* scan remote loop */
+	ELS_SBRP =	0x7c,	/* set bit-error reporting params */
+	ELS_RPSC =	0x7d,	/* report speed capabilities */
+	ELS_QSA =	0x7e,	/* query security attributes */
+	ELS_EVFP =	0x7f,	/* exchange virt. fabrics params */
+	ELS_LKA =	0x80,	/* link keep-alive */
+	ELS_AUTH_ELS =	0x90,	/* authentication ELS */
+};
+
+/*
+ * Initializer useful for decoding table.
+ * Please keep this in sync with the above definitions.
+ */
+#define	FC_ELS_CMDS_INIT {			\
+	[ELS_LS_RJT] =	"LS_RJT",		\
+	[ELS_LS_ACC] =	"LS_ACC",		\
+	[ELS_PLOGI] =	"PLOGI",		\
+	[ELS_FLOGI] =	"FLOGI",		\
+	[ELS_LOGO] =	"LOGO",			\
+	[ELS_ABTX] =	"ABTX",			\
+	[ELS_RCS] =	"RCS",			\
+	[ELS_RES] =	"RES",			\
+	[ELS_RSS] =	"RSS",			\
+	[ELS_RSI] =	"RSI",			\
+	[ELS_ESTS] =	"ESTS",			\
+	[ELS_ESTC] =	"ESTC",			\
+	[ELS_ADVC] =	"ADVC",			\
+	[ELS_RTV] =	"RTV",			\
+	[ELS_RLS] =	"RLS",			\
+	[ELS_ECHO] =	"ECHO",			\
+	[ELS_TEST] =	"TEST",			\
+	[ELS_RRQ] =	"RRQ",			\
+	[ELS_REC] =	"REC",			\
+	[ELS_SRR] =	"SRR",			\
+	[ELS_PRLI] =	"PRLI",			\
+	[ELS_PRLO] =	"PRLO",			\
+	[ELS_SCN] =	"SCN",			\
+	[ELS_TPLS] =	"TPLS",			\
+	[ELS_TPRLO] =	"TPRLO",		\
+	[ELS_LCLM] =	"LCLM",			\
+	[ELS_GAID] =	"GAID",			\
+	[ELS_FACT] =	"FACT",			\
+	[ELS_FDACDT] =	"FDACDT",		\
+	[ELS_NACT] =	"NACT",			\
+	[ELS_NDACT] =	"NDACT",		\
+	[ELS_QOSR] =	"QOSR",			\
+	[ELS_RVCS] =	"RVCS",			\
+	[ELS_PDISC] =	"PDISC",		\
+	[ELS_FDISC] =	"FDISC",		\
+	[ELS_ADISC] =	"ADISC",		\
+	[ELS_RNC] =	"RNC",			\
+	[ELS_FARP_REQ] = "FARP_REQ",		\
+	[ELS_FARP_REPL] =  "FARP_REPL",		\
+	[ELS_RPS] =	"RPS",			\
+	[ELS_RPL] =	"RPL",			\
+	[ELS_RPBC] =	"RPBC",			\
+	[ELS_FAN] =	"FAN",			\
+	[ELS_RSCN] =	"RSCN",			\
+	[ELS_SCR] =	"SCR",			\
+	[ELS_RNFT] =	"RNFT",			\
+	[ELS_CSR] =	"CSR",			\
+	[ELS_CSU] =	"CSU",			\
+	[ELS_LINIT] =	"LINIT",		\
+	[ELS_LSTS] =	"LSTS",			\
+	[ELS_RNID] =	"RNID",			\
+	[ELS_RLIR] =	"RLIR",			\
+	[ELS_LIRR] =	"LIRR",			\
+	[ELS_SRL] =	"SRL",			\
+	[ELS_SBRP] =	"SBRP",			\
+	[ELS_RPSC] =	"RPSC",			\
+	[ELS_QSA] =	"QSA",			\
+	[ELS_EVFP] =	"EVFP",			\
+	[ELS_LKA] =	"LKA",			\
+	[ELS_AUTH_ELS] = "AUTH_ELS",		\
+}
+
+/*
+ * LS_ACC payload.
+ */
+struct fc_els_ls_acc {
+	__u8          la_cmd;		/* command code ELS_LS_ACC */
+	__u8          la_resv[3];	/* reserved */
+};
+
+/*
+ * ELS reject payload.
+ */
+struct fc_els_ls_rjt {
+	__u8	er_cmd;		/* command code ELS_LS_RJT */
+	__u8	er_resv[4];	/* reserved must be zero */
+	__u8	er_reason;	/* reason (enum fc_els_rjt_reason below) */
+	__u8	er_explan;	/* explanation (enum fc_els_rjt_explan below) */
+	__u8	er_vendor;	/* vendor specific code */
+};
+
+/*
+ * ELS reject reason codes (er_reason).
+ */
+enum fc_els_rjt_reason {
+	ELS_RJT_NONE =		0,	/* no reject - not to be sent */
+	ELS_RJT_INVAL =		0x01,	/* invalid ELS command code */
+	ELS_RJT_LOGIC =		0x03,	/* logical error */
+	ELS_RJT_BUSY =		0x05,	/* logical busy */
+	ELS_RJT_PROT =		0x07,	/* protocol error */
+	ELS_RJT_UNAB =		0x09,	/* unable to perform command request */
+	ELS_RJT_UNSUP =		0x0b,	/* command not supported */
+	ELS_RJT_INPROG =	0x0e,	/* command already in progress */
+	ELS_RJT_VENDOR =	0xff,	/* vendor specific error */
+};
+
+
+/*
+ * reason code explanation (er_explan).
+ */
+enum fc_els_rjt_explan {
+	ELS_EXPL_NONE =		0x00,	/* No additional explanation */
+	ELS_EXPL_SPP_OPT_ERR =	0x01,	/* service parameter error - options */
+	ELS_EXPL_SPP_ICTL_ERR =	0x03,	/* service parm error - initiator ctl */
+	ELS_EXPL_AH =		0x11,	/* invalid association header */
+	ELS_EXPL_AH_REQ =	0x13,	/* association_header required */
+	ELS_EXPL_SID =		0x15,	/* invalid originator S_ID */
+	ELS_EXPL_OXID_RXID =	0x17,	/* invalid OX_ID-RX_ID combination */
+	ELS_EXPL_INPROG =	0x19,	/* Request already in progress */
+	ELS_EXPL_PLOGI_REQD =	0x1e,	/* N_Port login required */
+	ELS_EXPL_INSUF_RES =	0x29,	/* insufficient resources */
+	ELS_EXPL_UNAB_DATA =	0x2a,	/* unable to supply requested data */
+	ELS_EXPL_UNSUPR =	0x2c,	/* Request not supported */
+	ELS_EXPL_INV_LEN =	0x2d,	/* Invalid payload length */
+	/* TBD - above definitions incomplete */
+};
+
+/*
+ * Common service parameters (N ports).
+ */
+struct fc_els_csp {
+	__u8		sp_hi_ver;	/* highest version supported (obs.) */
+	__u8		sp_lo_ver;	/* highest version supported (obs.) */
+	__be16		sp_bb_cred;	/* buffer-to-buffer credits */
+	__be16		sp_features;	/* common feature flags */
+	__be16		sp_bb_data;	/* b-b state number and data field sz */
+	union {
+		struct {
+			__be16	_sp_tot_seq; /* total concurrent sequences */
+			__be16	_sp_rel_off; /* rel. offset by info cat */
+		} sp_plogi;
+		struct {
+			__be32	_sp_r_a_tov; /* resource alloc. timeout msec */
+		} sp_flogi_acc;
+	} sp_u;
+	__be32		sp_e_d_tov;	/* error detect timeout value */
+};
+#define	sp_tot_seq	sp_u.sp_plogi._sp_tot_seq
+#define	sp_rel_off	sp_u.sp_plogi._sp_rel_off
+#define	sp_r_a_tov	sp_u.sp_flogi_acc._sp_r_a_tov
+
+#define	FC_SP_BB_DATA_MASK 0xfff /* mask for data field size in sp_bb_data */
+
+/*
+ * Minimum and maximum values for max data field size in service parameters.
+ */
+#define	FC_SP_MIN_MAX_PAYLOAD	FC_MIN_MAX_PAYLOAD
+#define	FC_SP_MAX_MAX_PAYLOAD	FC_MAX_PAYLOAD
+
+/*
+ * sp_features
+ */
+#define	FC_SP_FT_CIRO	0x8000	/* continuously increasing rel. off. */
+#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_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 */
+#define	FC_SP_FT_MCAST	0x0200	/* multicast */
+#define	FC_SP_FT_BCAST	0x0100	/* broadcast */
+#define	FC_SP_FT_HUNT	0x0080	/* hunt group */
+#define	FC_SP_FT_SIMP	0x0040	/* dedicated simplex */
+#define	FC_SP_FT_SEC	0x0020	/* reserved for security */
+#define	FC_SP_FT_CSYN	0x0010	/* clock synch. supported */
+#define	FC_SP_FT_RTTOV	0x0008	/* R_T_TOV value 100 uS, else 100 mS */
+#define	FC_SP_FT_HALF	0x0004	/* dynamic half duplex */
+#define	FC_SP_FT_SEQC	0x0002	/* SEQ_CNT */
+#define	FC_SP_FT_PAYL	0x0001	/* FLOGI payload length 256, else 116 */
+
+/*
+ * Class-specific service parameters.
+ */
+struct fc_els_cssp {
+	__be16		cp_class;	/* class flags */
+	__be16		cp_init;	/* initiator flags */
+	__be16		cp_recip;	/* recipient flags */
+	__be16		cp_rdfs;	/* receive data field size */
+	__be16		cp_con_seq;	/* concurrent sequences */
+	__be16		cp_ee_cred;	/* N-port end-to-end credit */
+	__u8		cp_resv1;	/* reserved */
+	__u8		cp_open_seq;	/* open sequences per exchange */
+	__u8		_cp_resv2[2];	/* reserved */
+};
+
+/*
+ * cp_class flags.
+ */
+#define	FC_CPC_VALID	0x8000		/* class valid */
+#define	FC_CPC_IMIX	0x4000		/* intermix mode */
+#define	FC_CPC_SEQ	0x0800		/* sequential delivery */
+#define	FC_CPC_CAMP	0x0200		/* camp-on */
+#define	FC_CPC_PRI	0x0080		/* priority */
+
+/*
+ * cp_init flags.
+ * (TBD: not all flags defined here).
+ */
+#define	FC_CPI_CSYN	0x0010		/* clock synch. capable */
+
+/*
+ * cp_recip flags.
+ */
+#define	FC_CPR_CSYN	0x0008		/* clock synch. capable */
+
+/*
+ * NFC_ELS_FLOGI: Fabric login request.
+ * NFC_ELS_PLOGI: Port login request (same format).
+ */
+struct fc_els_flogi {
+	__u8		fl_cmd;		/* command */
+	__u8		_fl_resvd[3];	/* must be zero */
+	struct fc_els_csp fl_csp;	/* common service parameters */
+	__be64		fl_wwpn;	/* port name */
+	__be64		fl_wwnn;	/* node name */
+	struct fc_els_cssp fl_cssp[4];	/* class 1-4 service parameters */
+	__u8		fl_vend[16];	/* vendor version level */
+} __attribute__((__packed__));
+
+/*
+ * Process login service parameter page.
+ */
+struct fc_els_spp {
+	__u8		spp_type;	/* type code or common service params */
+	__u8		spp_type_ext;	/* type code extension */
+	__u8		spp_flags;
+	__u8		_spp_resvd;
+	__be32		spp_orig_pa;	/* originator process associator */
+	__be32		spp_resp_pa;	/* responder process associator */
+	__be32		spp_params;	/* service parameters */
+};
+
+/*
+ * spp_flags.
+ */
+#define	FC_SPP_OPA_VAL	    0x80	/* originator proc. assoc. valid */
+#define	FC_SPP_RPA_VAL	    0x40	/* responder proc. assoc. valid */
+#define	FC_SPP_EST_IMG_PAIR 0x20	/* establish image pair */
+#define	FC_SPP_RESP_MASK    0x0f	/* mask for response code (below) */
+
+/*
+ * SPP response code in spp_flags - lower 4 bits.
+ */
+enum fc_els_spp_resp {
+	FC_SPP_RESP_ACK	=	1,	/* request executed */
+	FC_SPP_RESP_RES =	2,	/* unable due to lack of resources */
+	FC_SPP_RESP_INIT =	3,	/* initialization not complete */
+	FC_SPP_RESP_NO_PA = 	4,	/* unknown process associator */
+	FC_SPP_RESP_CONF = 	5,	/* configuration precludes image pair */
+	FC_SPP_RESP_COND = 	6,	/* request completed conditionally */
+	FC_SPP_RESP_MULT = 	7,	/* unable to handle multiple SPPs */
+	FC_SPP_RESP_INVL = 	8,	/* SPP is invalid */
+};
+
+/*
+ * ELS_RRQ - Reinstate Recovery Qualifier
+ */
+struct fc_els_rrq {
+	__u8		rrq_cmd;	/* command (0x12) */
+	__u8		rrq_zero[3];	/* specified as zero - part of cmd */
+	__u8		rrq_resvd;	/* reserved */
+	__u8		rrq_s_id[3];	/* originator FID */
+	__be16		rrq_ox_id;	/* originator exchange ID */
+	__be16		rrq_rx_id;	/* responders exchange ID */
+};
+
+/*
+ * ELS_REC - Read exchange concise.
+ */
+struct fc_els_rec {
+	__u8		rec_cmd;	/* command (0x13) */
+	__u8		rec_zero[3];	/* specified as zero - part of cmd */
+	__u8		rec_resvd;	/* reserved */
+	__u8		rec_s_id[3];	/* originator FID */
+	__be16		rec_ox_id;	/* originator exchange ID */
+	__be16		rec_rx_id;	/* responders exchange ID */
+};
+
+/*
+ * ELS_REC LS_ACC payload.
+ */
+struct fc_els_rec_acc {
+	__u8		reca_cmd;	/* accept (0x02) */
+	__u8		reca_zero[3];	/* specified as zero - part of cmd */
+	__be16		reca_ox_id;	/* originator exchange ID */
+	__be16		reca_rx_id;	/* responders exchange ID */
+	__u8		reca_resvd1;	/* reserved */
+	__u8		reca_ofid[3];	/* originator FID */
+	__u8		reca_resvd2;	/* reserved */
+	__u8		reca_rfid[3];	/* responder FID */
+	__be32		reca_fc4value;	/* FC4 value */
+	__be32		reca_e_stat;	/* ESB (exchange status block) status */
+};
+
+/*
+ * ELS_PRLI - Process login request and response.
+ */
+struct fc_els_prli {
+	__u8		prli_cmd;	/* command */
+	__u8		prli_spp_len;	/* length of each serv. parm. page */
+	__be16		prli_len;	/* length of entire payload */
+	/* service parameter pages follow */
+};
+
+/*
+ * ELS_LOGO - process or fabric logout.
+ */
+struct fc_els_logo {
+	__u8		fl_cmd;		/* command code */
+	__u8		fl_zero[3];	/* specified as zero - part of cmd */
+	__u8		fl_resvd;	/* reserved */
+	__u8		fl_n_port_id[3];/* N port ID */
+	__be64		fl_n_port_wwn;	/* port name */
+};
+
+/*
+ * ELS_RTV - read timeout value.
+ */
+struct fc_els_rtv {
+	__u8		rtv_cmd;	/* command code 0x0e */
+	__u8		rtv_zero[3];	/* specified as zero - part of cmd */
+};
+
+/*
+ * LS_ACC for ELS_RTV - read timeout value.
+ */
+struct fc_els_rtv_acc {
+	__u8		rtv_cmd;	/* command code 0x02 */
+	__u8		rtv_zero[3];	/* specified as zero - part of cmd */
+	__be32		rtv_r_a_tov;	/* resource allocation timeout value */
+	__be32		rtv_e_d_tov;	/* error detection timeout value */
+	__be32		rtv_toq;	/* timeout qualifier (see below) */
+};
+
+/*
+ * rtv_toq bits.
+ */
+#define	FC_ELS_RTV_EDRES (1 << 26)	/* E_D_TOV resolution is nS else mS */
+#define	FC_ELS_RTV_RTTOV (1 << 19)	/* R_T_TOV is 100 uS else 100 mS */
+
+/*
+ * ELS_SCR - state change registration payload.
+ */
+struct fc_els_scr {
+	__u8		scr_cmd;	/* command code */
+	__u8		scr_resv[6];	/* reserved */
+	__u8		scr_reg_func;	/* registration function (see below) */
+};
+
+enum fc_els_scr_func {
+	ELS_SCRF_FAB =	1,	/* fabric-detected registration */
+	ELS_SCRF_NPORT = 2,	/* Nx_Port-detected registration */
+	ELS_SCRF_FULL =	3,	/* full registration */
+	ELS_SCRF_CLEAR = 255,	/* remove any current registrations */
+};
+
+/*
+ * ELS_RSCN - registered state change notification payload.
+ */
+struct fc_els_rscn {
+	__u8		rscn_cmd;	/* RSCN opcode (0x61) */
+	__u8		rscn_page_len;	/* page length (4) */
+	__be16		rscn_plen;	/* payload length including this word */
+
+	/* followed by 4-byte generic affected Port_ID pages */
+};
+
+struct fc_els_rscn_page {
+	__u8		rscn_page_flags; /* event and address format */
+	__u8		rscn_fid[3];	/* fabric ID */
+};
+
+#define	ELS_RSCN_EV_QUAL_BIT	2	/* shift count for event qualifier */
+#define	ELS_RSCN_EV_QUAL_MASK	0xf	/* mask for event qualifier */
+#define	ELS_RSCN_ADDR_FMT_BIT	0	/* shift count for address format */
+#define	ELS_RSCN_ADDR_FMT_MASK	0x3	/* mask for address format */
+
+enum fc_els_rscn_ev_qual {
+	ELS_EV_QUAL_NONE = 0,		/* unspecified */
+	ELS_EV_QUAL_NS_OBJ = 1,		/* changed name server object */
+	ELS_EV_QUAL_PORT_ATTR = 2,	/* changed port attribute */
+	ELS_EV_QUAL_SERV_OBJ = 3,	/* changed service object */
+	ELS_EV_QUAL_SW_CONFIG = 4,	/* changed switch configuration */
+	ELS_EV_QUAL_REM_OBJ = 5,	/* removed object */
+};
+
+enum fc_els_rscn_addr_fmt {
+	ELS_ADDR_FMT_PORT = 0,	/* rscn_fid is a port address */
+	ELS_ADDR_FMT_AREA = 1,	/* rscn_fid is a area address */
+	ELS_ADDR_FMT_DOM = 2,	/* rscn_fid is a domain address */
+	ELS_ADDR_FMT_FAB = 3,	/* anything on fabric may have changed */
+};
+
+/*
+ * ELS_RNID - request Node ID.
+ */
+struct fc_els_rnid {
+	__u8		rnid_cmd;	/* RNID opcode (0x78) */
+	__u8		rnid_resv[3];	/* reserved */
+	__u8		rnid_fmt;	/* data format */
+	__u8		rnid_resv2[3];	/* reserved */
+};
+
+/*
+ * Node Identification Data formats (rnid_fmt)
+ */
+enum fc_els_rnid_fmt {
+	ELS_RNIDF_NONE = 0,		/* no specific identification data */
+	ELS_RNIDF_GEN = 0xdf,		/* general topology discovery format */
+};
+
+/*
+ * ELS_RNID response.
+ */
+struct fc_els_rnid_resp {
+	__u8		rnid_cmd;	/* response code (LS_ACC) */
+	__u8		rnid_resv[3];	/* reserved */
+	__u8		rnid_fmt;	/* data format */
+	__u8		rnid_cid_len;	/* common ID data length */
+	__u8		rnid_resv2;	/* reserved */
+	__u8		rnid_sid_len;	/* specific ID data length */
+};
+
+struct fc_els_rnid_cid {
+	__be64		rnid_wwpn;	/* N port name */
+	__be64		rnid_wwnn;	/* node name */
+};
+
+struct fc_els_rnid_gen {
+	__u8		rnid_vend_id[16]; /* vendor-unique ID */
+	__be32		rnid_atype;	/* associated type (see below) */
+	__be32		rnid_phys_port;	/* physical port number */
+	__be32		rnid_att_nodes;	/* number of attached nodes */
+	__u8		rnid_node_mgmt;	/* node management (see below) */
+	__u8		rnid_ip_ver;	/* IP version (see below) */
+	__be16		rnid_prot_port;	/* UDP / TCP port number */
+	__be32		rnid_ip_addr[4]; /* IP address */
+	__u8		rnid_resvd[2];	/* reserved */
+	__be16		rnid_vend_spec;	/* vendor-specific field */
+};
+
+enum fc_els_rnid_atype {
+	ELS_RNIDA_UNK =		0x01,	/* unknown */
+	ELS_RNIDA_OTHER =	0x02,	/* none of the following */
+	ELS_RNIDA_HUB =		0x03,
+	ELS_RNIDA_SWITCH =	0x04,
+	ELS_RNIDA_GATEWAY =	0x05,
+	ELS_RNIDA_CONV =	0x06,   /* Obsolete, do not use this value */
+	ELS_RNIDA_HBA =	        0x07,   /* Obsolete, do not use this value */
+	ELS_RNIDA_PROXY =       0x08,   /* Obsolete, do not use this value */
+	ELS_RNIDA_STORAGE =	0x09,
+	ELS_RNIDA_HOST =	0x0a,
+	ELS_RNIDA_SUBSYS =	0x0b,	/* storage subsystem (e.g., RAID) */
+	ELS_RNIDA_ACCESS =	0x0e,	/* access device (e.g. media changer) */
+	ELS_RNIDA_NAS =		0x11,	/* NAS server */
+	ELS_RNIDA_BRIDGE =	0x12,	/* bridge */
+	ELS_RNIDA_VIRT =	0x13,	/* virtualization device */
+	ELS_RNIDA_MF =		0xff,	/* multifunction device (bits below) */
+	ELS_RNIDA_MF_HUB =	1UL << 31, 	/* hub */
+	ELS_RNIDA_MF_SW =	1UL << 30, 	/* switch */
+	ELS_RNIDA_MF_GW =	1UL << 29,	/* gateway */
+	ELS_RNIDA_MF_ST =	1UL << 28,	/* storage */
+	ELS_RNIDA_MF_HOST =	1UL << 27,	/* host */
+	ELS_RNIDA_MF_SUB =	1UL << 26,	/* storage subsystem */
+	ELS_RNIDA_MF_ACC =	1UL << 25,	/* storage access dev */
+	ELS_RNIDA_MF_WDM =	1UL << 24,	/* wavelength division mux */
+	ELS_RNIDA_MF_NAS =	1UL << 23,	/* NAS server */
+	ELS_RNIDA_MF_BR =	1UL << 22,	/* bridge */
+	ELS_RNIDA_MF_VIRT =	1UL << 21,	/* virtualization device */
+};
+
+enum fc_els_rnid_mgmt {
+	ELS_RNIDM_SNMP =	0,
+	ELS_RNIDM_TELNET =	1,
+	ELS_RNIDM_HTTP =	2,
+	ELS_RNIDM_HTTPS =	3,
+	ELS_RNIDM_XML =		4,	/* HTTP + XML */
+};
+
+enum fc_els_rnid_ipver {
+	ELS_RNIDIP_NONE =	0,	/* no IP support or node mgmt. */
+	ELS_RNIDIP_V4 =		1,	/* IPv4 */
+	ELS_RNIDIP_V6 =		2,	/* IPv6 */
+};
+
+/*
+ * ELS RPL - Read Port List.
+ */
+struct fc_els_rpl {
+	__u8		rpl_cmd;	/* command */
+	__u8		rpl_resv[5];	/* reserved - must be zero */
+	__be16		rpl_max_size;	/* maximum response size or zero */
+	__u8		rpl_resv1;	/* reserved - must be zero */
+	__u8		rpl_index[3];	/* starting index */
+};
+
+/*
+ * Port number block in RPL response.
+ */
+struct fc_els_pnb {
+	__be32		pnb_phys_pn;	/* physical port number */
+	__u8		pnb_resv;	/* reserved */
+	__u8		pnb_port_id[3];	/* port ID */
+	__be64		pnb_wwpn;	/* port name */
+};
+
+/*
+ * RPL LS_ACC response.
+ */
+struct fc_els_rpl_resp {
+	__u8		rpl_cmd;	/* ELS_LS_ACC */
+	__u8		rpl_resv1;	/* reserved - must be zero */
+	__be16		rpl_plen;	/* payload length */
+	__u8		rpl_resv2;	/* reserved - must be zero */
+	__u8		rpl_llen[3];	/* list length */
+	__u8		rpl_resv3;	/* reserved - must be zero */
+	__u8		rpl_index[3];	/* starting index */
+	struct fc_els_pnb rpl_pnb[1];	/* variable number of PNBs */
+};
+
+/*
+ * Link Error Status Block.
+ */
+struct fc_els_lesb {
+	__be32		lesb_link_fail;	/* link failure count */
+	__be32		lesb_sync_loss;	/* loss of synchronization count */
+	__be32		lesb_sig_loss;	/* loss of signal count */
+	__be32		lesb_prim_err;	/* primitive sequence error count */
+	__be32		lesb_inv_word;	/* invalid transmission word count */
+	__be32		lesb_inv_crc;	/* invalid CRC count */
+};
+
+/*
+ * ELS RPS - Read Port Status Block request.
+ */
+struct fc_els_rps {
+	__u8		rps_cmd;	/* command */
+	__u8		rps_resv[2];	/* reserved - must be zero */
+	__u8		rps_flag;	/* flag - see below */
+	__be64		rps_port_spec;	/* port selection */
+};
+
+enum fc_els_rps_flag {
+	FC_ELS_RPS_DID =	0x00,	/* port identified by D_ID of req. */
+	FC_ELS_RPS_PPN =	0x01,	/* port_spec is physical port number */
+	FC_ELS_RPS_WWPN =	0x02,	/* port_spec is port WWN */
+};
+
+/*
+ * ELS RPS LS_ACC response.
+ */
+struct fc_els_rps_resp {
+	__u8		rps_cmd;	/* command - LS_ACC */
+	__u8		rps_resv[2];	/* reserved - must be zero */
+	__u8		rps_flag;	/* flag - see below */
+	__u8		rps_resv2[2];	/* reserved */
+	__be16		rps_status;	/* port status - see below */
+	struct fc_els_lesb rps_lesb;	/* link error status block */
+};
+
+enum fc_els_rps_resp_flag {
+	FC_ELS_RPS_LPEV =	0x01,	/* L_port extension valid */
+};
+
+enum fc_els_rps_resp_status {
+	FC_ELS_RPS_PTP =	1 << 5,	/* point-to-point connection */
+	FC_ELS_RPS_LOOP =	1 << 4,	/* loop mode */
+	FC_ELS_RPS_FAB =	1 << 3,	/* fabric present */
+	FC_ELS_RPS_NO_SIG =	1 << 2,	/* loss of signal */
+	FC_ELS_RPS_NO_SYNC =	1 << 1,	/* loss of synchronization */
+	FC_ELS_RPS_RESET =	1 << 0,	/* in link reset protocol */
+};
+
+/*
+ * ELS LIRR - Link Incident Record Registration request.
+ */
+struct fc_els_lirr {
+	__u8		lirr_cmd;	/* command */
+	__u8		lirr_resv[3];	/* reserved - must be zero */
+	__u8		lirr_func;	/* registration function */
+	__u8		lirr_fmt;	/* FC-4 type of RLIR requested */
+	__u8		lirr_resv2[2];	/* reserved - must be zero */
+};
+
+enum fc_els_lirr_func {
+	ELS_LIRR_SET_COND = 	0x01,	/* set - conditionally receive */
+	ELS_LIRR_SET_UNCOND = 	0x02,	/* set - unconditionally receive */
+	ELS_LIRR_CLEAR = 	0xff	/* clear registration */
+};
+
+/*
+ * ELS SRL - Scan Remote Loop request.
+ */
+struct fc_els_srl {
+	__u8		srl_cmd;	/* command */
+	__u8		srl_resv[3];	/* reserved - must be zero */
+	__u8		srl_flag;	/* flag - see below */
+	__u8		srl_flag_param[3];	/* flag parameter */
+};
+
+enum fc_els_srl_flag {
+	FC_ELS_SRL_ALL =	0x00,	/* scan all FL ports */
+	FC_ELS_SRL_ONE =	0x01,	/* scan specified loop */
+	FC_ELS_SRL_EN_PER =	0x02,	/* enable periodic scanning (param) */
+	FC_ELS_SRL_DIS_PER =	0x03,	/* disable periodic scanning */
+};
+
+/*
+ * ELS RLS - Read Link Error Status Block request.
+ */
+struct fc_els_rls {
+	__u8		rls_cmd;	/* command */
+	__u8		rls_resv[4];	/* reserved - must be zero */
+	__u8		rls_port_id[3];	/* port ID */
+};
+
+/*
+ * ELS RLS LS_ACC Response.
+ */
+struct fc_els_rls_resp {
+	__u8		rls_cmd;	/* ELS_LS_ACC */
+	__u8		rls_resv[3];	/* reserved - must be zero */
+	struct fc_els_lesb rls_lesb;	/* link error status block */
+};
+
+/*
+ * ELS RLIR - Registered Link Incident Report.
+ * This is followed by the CLIR and the CLID, described below.
+ */
+struct fc_els_rlir {
+	__u8		rlir_cmd;	/* command */
+	__u8		rlir_resv[3];	/* reserved - must be zero */
+	__u8		rlir_fmt;	/* format (FC4-type if type specific) */
+	__u8		rlir_clr_len;	/* common link incident record length */
+	__u8		rlir_cld_len;	/* common link incident desc. length */
+	__u8		rlir_slr_len;	/* spec. link incident record length */
+};
+
+/*
+ * CLIR - Common Link Incident Record Data. - Sent via RLIR.
+ */
+struct fc_els_clir {
+	__be64		clir_wwpn;	/* incident port name */
+	__be64		clir_wwnn;	/* incident port node name */
+	__u8		clir_port_type;	/* incident port type */
+	__u8		clir_port_id[3];	/* incident port ID */
+
+	__be64		clir_conn_wwpn;	/* connected port name */
+	__be64		clir_conn_wwnn;	/* connected node name */
+	__be64		clir_fab_name;	/* fabric name */
+	__be32		clir_phys_port;	/* physical port number */
+	__be32		clir_trans_id;	/* transaction ID */
+	__u8		clir_resv[3];	/* reserved */
+	__u8		clir_ts_fmt;	/* time stamp format */
+	__be64		clir_timestamp;	/* time stamp */
+};
+
+/*
+ * CLIR clir_ts_fmt - time stamp format values.
+ */
+enum fc_els_clir_ts_fmt {
+	ELS_CLIR_TS_UNKNOWN = 	0,	/* time stamp field unknown */
+	ELS_CLIR_TS_SEC_FRAC = 	1,	/* time in seconds and fractions */
+	ELS_CLIR_TS_CSU =	2,	/* time in clock synch update format */
+};
+
+/*
+ * Common Link Incident Descriptor - sent via RLIR.
+ */
+struct fc_els_clid {
+	__u8		clid_iq;	/* incident qualifier flags */
+	__u8		clid_ic;	/* incident code */
+	__be16		clid_epai;	/* domain/area of ISL */
+};
+
+/*
+ * CLID incident qualifier flags.
+ */
+enum fc_els_clid_iq {
+	ELS_CLID_SWITCH =	0x20,	/* incident port is a switch node */
+	ELS_CLID_E_PORT =	0x10,	/* incident is an ISL (E) port */
+	ELS_CLID_SEV_MASK =	0x0c,	/* severity 2-bit field mask */
+	ELS_CLID_SEV_INFO =	0x00,	/* report is informational */
+	ELS_CLID_SEV_INOP =	0x08,	/* link not operational */
+	ELS_CLID_SEV_DEG =	0x04,	/* link degraded but operational */
+	ELS_CLID_LASER =	0x02,	/* subassembly is a laser */
+	ELS_CLID_FRU =		0x01,	/* format can identify a FRU */
+};
+
+/*
+ * CLID incident code.
+ */
+enum fc_els_clid_ic {
+	ELS_CLID_IC_IMPL =	1,	/* implicit incident */
+	ELS_CLID_IC_BER =	2,	/* bit-error-rate threshold exceeded */
+	ELS_CLID_IC_LOS =	3,	/* loss of synch or signal */
+	ELS_CLID_IC_NOS =	4,	/* non-operational primitive sequence */
+	ELS_CLID_IC_PST =	5,	/* primitive sequence timeout */
+	ELS_CLID_IC_INVAL =	6,	/* invalid primitive sequence */
+	ELS_CLID_IC_LOOP_TO =	7,	/* loop initialization time out */
+	ELS_CLID_IC_LIP =	8,	/* receiving LIP */
+};
+
+#endif /* _FC_ELS_H_ */
include/scsi/fc/fc_encaps.h new file +138 -0

138 lines not on this page · raw message

include/scsi/fc/fc_fc2.h new file +124 -0

124 lines not on this page · raw message

include/scsi/fc/fc_fcoe.h new file +102 -0

102 lines not on this page · raw message

include/scsi/fc/fc_fcp.h new file +199 -0

199 lines not on this page · raw message

include/scsi/fc/fc_fs.h new file +340 -0

340 lines not on this page · raw message

include/scsi/fc/fc_gs.h new file +93 -0

93 lines not on this page · raw message

include/scsi/fc/fc_ns.h new file +159 -0

159 lines not on this page · raw message

#2 lore raw

PATCH 2/3 libfc: A modular Fibre Channel library

In reply to Robert Love

---

 drivers/scsi/Kconfig          |    6 
 drivers/scsi/Makefile         |    1 
 drivers/scsi/libfc/Makefile   |   12 
 drivers/scsi/libfc/fc_disc.c  |  932 ++++++++++++++++++
 drivers/scsi/libfc/fc_elsct.c |   71 +
 drivers/scsi/libfc/fc_exch.c  | 1971 ++++++++++++++++++++++++++++++++++++++
 drivers/scsi/libfc/fc_fcp.c   | 2130 +++++++++++++++++++++++++++++++++++++++++
 drivers/scsi/libfc/fc_frame.c |   89 ++
 drivers/scsi/libfc/fc_lport.c | 1525 +++++++++++++++++++++++++++++
 drivers/scsi/libfc/fc_rport.c | 1277 +++++++++++++++++++++++++
 include/scsi/fc_encode.h      |  309 ++++++
 include/scsi/fc_frame.h       |  239 +++++
 include/scsi/libfc.h          |  917 ++++++++++++++++++
 13 files changed, 9479 insertions(+), 0 deletions(-)
 create mode 100644 drivers/scsi/libfc/Makefile
 create mode 100644 drivers/scsi/libfc/fc_disc.c
 create mode 100644 drivers/scsi/libfc/fc_elsct.c
 create mode 100644 drivers/scsi/libfc/fc_exch.c
 create mode 100644 drivers/scsi/libfc/fc_fcp.c
 create mode 100644 drivers/scsi/libfc/fc_frame.c
 create mode 100644 drivers/scsi/libfc/fc_lport.c
 create mode 100644 drivers/scsi/libfc/fc_rport.c
 create mode 100644 include/scsi/fc_encode.h
 create mode 100644 include/scsi/fc_frame.h
 create mode 100644 include/scsi/libfc.h
drivers/scsi/Kconfig +6 -0
index 403ecad..860c935 100644
@@ -603,6 +603,12 @@ config SCSI_FLASHPOINT
 	  substantial, so users of MultiMaster Host Adapters may not
 	  wish to include it.
 
+config LIBFC
+	tristate "LibFC module"
+	depends on SCSI && SCSI_FC_ATTRS
+	---help---
+	  Fibre Channel library module
+
 config SCSI_DMX3191D
 	tristate "DMX3191D SCSI support"
 	depends on PCI && SCSI
drivers/scsi/Makefile +1 -0
index 72fd504..9158dc6 100644
@@ -36,6 +36,7 @@ obj-$(CONFIG_SCSI_SAS_LIBSAS)	+= libsas/
 obj-$(CONFIG_SCSI_SRP_ATTRS)	+= scsi_transport_srp.o
 obj-$(CONFIG_SCSI_DH)		+= device_handler/
 
+obj-$(CONFIG_LIBFC)		+= libfc/
 obj-$(CONFIG_ISCSI_TCP) 	+= libiscsi.o	iscsi_tcp.o
 obj-$(CONFIG_INFINIBAND_ISER) 	+= libiscsi.o
 obj-$(CONFIG_SCSI_A4000T)	+= 53c700.o	a4000t.o
drivers/scsi/libfc/Makefile new file +12 -0
new file mode 100644
index 0000000..55f982d
@@ -0,0 +1,12 @@
+# $Id: Makefile
+
+obj-$(CONFIG_LIBFC) += libfc.o
+
+libfc-objs := \
+	fc_disc.o \
+	fc_exch.o \
+	fc_elsct.o \
+	fc_frame.o \
+	fc_lport.o \
+	fc_rport.o \
+	fc_fcp.o
drivers/scsi/libfc/fc_disc.c new file +932 -0

932 lines not on this page · raw message

drivers/scsi/libfc/fc_elsct.c new file +71 -0

71 lines not on this page · raw message

drivers/scsi/libfc/fc_exch.c new file +1971 -0

1,966 lines not on this page · raw message

drivers/scsi/libfc/fc_fcp.c new file +2130 -0

2,130 lines not on this page · raw message

drivers/scsi/libfc/fc_frame.c new file +89 -0

89 lines not on this page · raw message

drivers/scsi/libfc/fc_lport.c new file +1525 -0

1,525 lines not on this page · raw message

drivers/scsi/libfc/fc_rport.c new file +1277 -0

1,277 lines not on this page · raw message

include/scsi/fc_encode.h new file +309 -0

309 lines not on this page · raw message

include/scsi/fc_frame.h new file +239 -0

239 lines not on this page · raw message

include/scsi/libfc.h new file +917 -0

917 lines not on this page · raw message

The rest of this diff is not shown. View the raw message.

Part of the diff is not shown here. View the raw message.

#3 lore raw

Re: [PATCH 2/3] libfc: A modular Fibre Channel library

Robert Love <[email protected]> writes:

A quick review. I'm not a SCSI layer expert, so it's more general code comments.

Could you perhaps give a brief design overview of the library in the description?

What it does, where it sits on the stack etc.? Doesn't need to be very extensive, but should be understandable even for people not intimate with the FCoE spec.

drivers/scsi/libfc/fc_disc.c line 36

Quoted 2 lines
drivers/scsi/libfc/fc_disc.c new file +2 -0
+#define FC_DISC_RETRY_LIMIT	3	/* max retries */
+#define FC_DISC_RETRY_DELAY	500UL	/* (msecs) delay */

Define is not used?

drivers/scsi/libfc/fc_disc.c line 46

Quoted 10 lines
drivers/scsi/libfc/fc_disc.c new file +10 -0
+
+#define	FC_DISC_DELAY		3
+
+static int fc_disc_debug;
+
+#define FC_DEBUG_DISC(fmt...)			\
+	do {					\
+		if (fc_disc_debug)		\
+			FC_DBG(fmt);		\
+	} while (0)

In 2.6.28 there is dynamic_printk.h now to handle this.

Quoted 5 lines
drivers/scsi/libfc/fc_disc.c new file +5 -0
+
+static struct mutex		disc_list_lock;
+static struct list_head		disc_list;
+
+struct fc_disc {

drivers/scsi/libfc/fc_disc.c line 61

Quoted 10 lines
drivers/scsi/libfc/fc_disc.c new file +10 -0
+	unsigned char		retry_count;
+	unsigned char		delay;
+	unsigned char		pending;
+	unsigned char		requested;
+	unsigned short		seq_count;
+	unsigned char		buf_len;
+	enum fc_disc_event	event;
+
+	void (*disc_callback)(struct fc_lport *,
+			      enum fc_disc_event);

While it may seem excessive for a single callback the tend is towards separate ->ops structures. They have the advantage that they can be made const which has at least some theoretical security advantages. Also callback numbers tend to grow over time.

Quoted 7 lines
drivers/scsi/libfc/fc_disc.c new file +7 -0
+/**
+ * fc_disc_lookup_rport - lookup a remote port by port_id
+ * @lport: Fibre Channel host port instance
+ * @port_id: remote port port_id to match
+ */
+struct fc_rport *fc_disc_lookup_rport(const struct fc_lport *lport,
+				      u32 port_id)

drivers/scsi/libfc/fc_disc.c line 98

Quoted 10 lines
drivers/scsi/libfc/fc_disc.c new file +10 -0
+{
+	struct fc_disc *disc;
+	struct fc_rport *rport, *found = NULL;
+	struct fc_rport_libfc_priv *rdata;
+	int disc_found = 0;
+
+	mutex_lock(&disc_list_lock);
+	list_for_each_entry(disc, &disc_list, list) {
+		if (disc->lport == lport) {
+			list_for_each_entry(rdata, &disc->rports, peers) {

Hopefully the max numbers of either of those are strictly bounded.

drivers/scsi/libfc/fc_disc.c line 129

Quoted 10 lines
drivers/scsi/libfc/fc_disc.c new file +10 -0
+
+/**
+ * fc_disc_alloc - Allocate a discovery work object
+ * @lport: The FC lport associated with the discovery job
+ */
+static inline struct fc_disc *fc_disc_alloc(struct fc_lport *lport)
+{
+	struct fc_disc *disc;
+
+	disc = kzalloc(sizeof(struct fc_disc), GFP_KERNEL);

This misses a NULL check

drivers/scsi/libfc/fc_disc.c line 137

Quoted 8 lines
drivers/scsi/libfc/fc_disc.c new file +8 -0
+	INIT_LIST_HEAD(&disc->list);
+	INIT_DELAYED_WORK(&disc->disc_work, fc_disc_timeout);
+	mutex_init(&disc->disc_mutex);
+	INIT_LIST_HEAD(&disc->rports);
+
+	disc->lport = lport;
+	disc->delay = FC_DISC_DELAY;
+	disc->event = DISC_EV_NONE;

Is it ok that the callback (and probably some other fields) is not initialized here yet?

drivers/scsi/libfc/fc_disc.c line 141

Quoted 4 lines
drivers/scsi/libfc/fc_disc.c new file +4 -0
+
+	mutex_lock(&disc_list_lock);
+	list_add_tail(&disc->list, &disc_list);
+	mutex_unlock(&disc_list_lock);

... when you make this globally visible?

drivers/scsi/libfc/fc_disc.c line 201

Quoted 11 lines
drivers/scsi/libfc/fc_disc.c new file +11 -0
+	if (event == RPORT_EV_CREATED) {
+		mutex_lock(&disc_list_lock);
+		list_for_each_entry(disc, &disc_list, list) {
+			if (disc->lport == lport) {
+				found = 1;
+				mutex_lock(&disc->disc_mutex);
+				list_add_tail(&rdata->peers, &disc->rports);
+				mutex_unlock(&disc->disc_mutex);
+			}
+		}
+		mutex_unlock(&disc_list_lock);

That's a lot of locks. Did you have a locking order comment somewhere?

drivers/scsi/libfc/fc_disc.c line 247

Quoted 7 lines
drivers/scsi/libfc/fc_disc.c new file +7 -0
+	if (!rp || rp->rscn_page_len != sizeof(*pp))
+		goto reject;
+
+	len = ntohs(rp->rscn_plen);
+	if (len < sizeof(*rp))
+		goto reject;
+	len -= sizeof(*rp);

Don't you need to check here than len is a multiple of sizeof(*pp) ? Otherwise bad input could make it loop a very long time.

Review

Quoted 2 lines
(quoted diff) +2 -0
+
+	for (pp = (void *)(rp + 1); len; len -= sizeof(*pp), pp++) {

Also len >= 0 is always safer.

drivers/scsi/libfc/fc_disc.c line 296

Quoted 7 lines
drivers/scsi/libfc/fc_disc.c new file +7 -0
+			      redisc, lport->state, disc->pending);
+		list_for_each_entry_safe(dp, next, &disc_ports, peers) {
+			list_del(&dp->peers);
+			rport = lport->tt.rport_lookup(lport, dp->ids.port_id);
+			if (rport) {
+				rdata = RPORT_TO_PRIV(rport);
+				list_del(&rdata->peers);

Hopefully there's a mutex here hold for that list.

drivers/scsi/libfc/fc_disc.c line 309

Quoted 13 lines
drivers/scsi/libfc/fc_disc.c new file +13 -0
+				lport->tt.rport_logoff(rport);
+			}
+			fc_disc_single(disc, dp);
+		}
+	}
+	fc_frame_free(fp);
+	return;
+reject:
+	rjt_data.fp = NULL;
+	rjt_data.reason = ELS_RJT_LOGIC;
+	rjt_data.explan = ELS_EXPL_NONE;
+	lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
+	fc_frame_free(fp);

Some statistics counter for that case would be probably useful.

drivers/scsi/libfc/fc_disc.c line 349

Quoted 7 lines
drivers/scsi/libfc/fc_disc.c new file +7 -0
+
+	op = fc_frame_payload_op(fp);
+	switch (op) {
+	case ELS_RSCN:
+		mutex_lock(&disc->disc_mutex);
+		fc_disc_recv_rscn_req(sp, fp, disc);
+		mutex_unlock(&disc->disc_mutex);

Ok yes seems the lock is hold.

drivers/scsi/libfc/fc_disc.c line 377

Quoted 6 lines
drivers/scsi/libfc/fc_disc.c new file +6 -0
+
+	list_for_each_entry_safe(rdata, next, &disc->rports, peers) {
+		rport = PRIV_TO_RPORT(rdata);
+		FC_DEBUG_DISC("list_del(%6x)\n", rport->port_id);
+		list_del(&rdata->peers);
+		lport->tt.rport_logoff(rport);

Hopefully that callback knows for which peer that is.

Quoted 7 lines
drivers/scsi/libfc/fc_disc.c new file +7 -0
+static void fc_disc_start(void (*disc_callback)(struct fc_lport *,
+						enum fc_disc_event),
+			  struct fc_lport *lport)
+{
+	struct fc_rport *rport;
+	struct fc_rport_identifiers ids;
+	struct fc_disc *disc;

drivers/scsi/libfc/fc_disc.c line 407

Quoted 10 lines
drivers/scsi/libfc/fc_disc.c new file +10 -0
+	int found = 0;
+
+	mutex_lock(&disc_list_lock);
+	list_for_each_entry(disc, &disc_list, list) {
+		if (disc->lport == lport) {
+			found = 1;
+			break;
+		}
+	}
+	mutex_unlock(&disc_list_lock);

This seems to be opencoded a lot. Put it into some helper.

Quoted 8 lines
drivers/scsi/libfc/fc_disc.c new file +8 -0
+
+	/*
+	 * Handle point-to-point mode as a simple discovery
+	 * of the remote port. Yucky, yucky, yuck, yuck!
+	 */
+	rport = disc->lport->ptp_rp;
+	if (rport) {
+		ids.port_id = rport->port_id;

drivers/scsi/libfc/fc_disc.c line 454

Quoted 10 lines
drivers/scsi/libfc/fc_disc.c new file +10 -0
+		ids.port_name = rport->port_name;
+		ids.node_name = rport->node_name;
+		ids.roles = FC_RPORT_ROLE_UNKNOWN;
+		get_device(&rport->dev);
+
+		if (!fc_disc_new_target(disc, rport, &ids)) {
+			disc->event = DISC_EV_SUCCESS;
+			fc_disc_done(disc);
+		}
+		put_device(&rport->dev);

The ref counting here seems a little dubious. If it's because disc_new_target can sleep then preemptible kernels can do that anyways. Or it's not needed.

Quoted 16 lines
drivers/scsi/libfc/fc_disc.c new file +16 -0
+	}
+	if (((ids->port_name != -1) || (ids->port_id != -1)) &&
+	    ids->port_id != fc_host_port_id(lport->host) &&
+	    ids->port_name != lport->wwpn) {
+		if (!rport) {
+			rport = lport->tt.rport_lookup(lport, ids->port_id);
+			if (!rport) {
+				struct fc_disc_port dp;
+				dp.lp = lport;
+				dp.ids.port_id = ids->port_id;
+				dp.ids.port_name = ids->port_name;
+				dp.ids.node_name = ids->node_name;
+				dp.ids.roles = ids->roles;
+				rport = fc_rport_rogue_create(&dp);
+			}
+			if (!rport)

drivers/scsi/libfc/fc_disc.c line 522

Quoted 10 lines
drivers/scsi/libfc/fc_disc.c new file +10 -0
+				error = ENOMEM;
+		}
+		if (rport) {
+			rp = rport->dd_data;
+			rp->event_callback = fc_disc_rport_event;
+			rp->rp_state = RPORT_ST_INIT;
+			lport->tt.rport_login(rport);
+		}
+	}
+	return error;

Unusual positive error return convention. Ok?

drivers/scsi/libfc/fc_disc.c line 572

Quoted 5 lines
drivers/scsi/libfc/fc_disc.c new file +5 -0
+		FC_DBG("Error %ld, retries %d/%d\n",
+		       PTR_ERR(fp), disc->retry_count,
+		       FC_DISC_RETRY_LIMIT);
+
+	if (!fp || PTR_ERR(fp) == -FC_EX_TIMEOUT) {

The mixing of non errnos into PTR_ERR is also unusual, but ok, but make sure you never leak them.

drivers/scsi/libfc/fc_disc.c line 580

Quoted 8 lines
drivers/scsi/libfc/fc_disc.c new file +8 -0
+		/*
+		 * Memory allocation failure, or the exchange timed out,
+		 * retry after delay.
+		 */
+		if (disc->retry_count < FC_DISC_RETRY_LIMIT) {
+			/* go ahead and retry */
+			if (!fp)
+				delay = msecs_to_jiffies(500);

Ah that was the missing define above?

drivers/scsi/libfc/fc_disc.c line 587

Quoted 7 lines
drivers/scsi/libfc/fc_disc.c new file +7 -0
+			else {
+				delay = jiffies +
+					msecs_to_jiffies(lport->e_d_tov);
+
+				/* timeout faster first time */
+				if (!disc->retry_count)
+					delay /= 4;

You have to divide by four before you add to jiffies, dividing absolute jiffies doesn't make sense.

drivers/scsi/libfc/fc_disc.c line 665

Quoted 12 lines
drivers/scsi/libfc/fc_disc.c new file +12 -0
+	/*
+	 * Handle partial name record left over from previous call.
+	 */
+	bp = buf;
+	plen = len;
+	np = (struct fc_gpn_ft_resp *)bp;
+	tlen = disc->buf_len;
+	if (tlen) {
+		WARN_ON(tlen >= sizeof(*np));
+		plen = sizeof(*np) - tlen;
+		WARN_ON(plen <= 0);
+		WARN_ON(plen >= sizeof(*np));

I hope none of these WARN_ONs in network controllable. They nearly look like some of them are.

Ok stopping here for now. That's a lot of code. Perhaps split it up into a little smaller patches?

General impressions:
- Your locking is to complicated I think. Less locks is often more. For short locks we also recommend spinlocks which perform better (although you have to make sure you don't sleep then of course)
- I would double check everything that handles network data to make sure it's not exploitable.

-Andi

Signature · 1 line
[email protected]
#4 lore raw

RE: [PATCH 2/3] libfc: A modular Fibre Channel library

Quoted 5 lines · Andi Kleen

Robert Love <[email protected]> writes:

A quick review. I'm not a SCSI layer expert, so it's more general code comments.

Thanks. I appreciate all reviews.

Quoted 3 lines

Could you perhaps give a brief design overview of the library in the description?

Sure. I'll put it in the description when I re-submit.

It's fairly complicated, so even though I'm trying to be breif, this overview got a bit long. The library has 5 major layers/blocks- the EM, FCP, LP, RP, and disc. The EM is the Exchange Manager and it is used by each of the other four blocks. FCP is the mapping of SCSI commands to FC frames, it's the I/O path. The RP layer handles individual targets (i.e. remote ports). The LP block handles the host (or local port) for example, fabric login, registration with the directoy server, etc... The disc layer handles discovery, it queries the directoy server to find the targets/RPs that are in its zone.

The FC transport class already provides us some remote port functionality. It doesn't manage our RP state machine, but we interact with it to add/delete RPs from both sysfs, it's also what makes the SCSI-ml aware that there is storage available.

We have some diagrams that might be helpful, but they haven't been refreshed in a few months. They're at:
http://www.open-fcoe.org/openfc/wiki/index.php/Architecture

My incomplete ASCII representation looks like this.

---------------------------
| FC Transport Class
---------------------------
^
| (add/delete)
v
---------------------------
| RP
---------------------------

   ^                       ^
   |    (targets)          | (directory server)
   v                       |
--------------     |
| Disc             |
--------------     |
   ^                       |
   |                       |
   v                       v

---------------------------
| LP
---------------------------

The EM is in-use by each of the blocks drawn above.

The I/O path is pretty straight-forward, kind of silly to draw.

-------------------------
| SCSI-ml
-------------------------
^
|
v
-------------------------
| FCP
-------------------------
^
|
v
-------------------------
| EM
-------------------------

Quoted 4 lines

What it does, where it sits on the stack etc.? Doesn't need to be very extensive, but should be understandable even for people not intimate with the FCoE spec.

So, libfc is an assist library, fcoe is the LLD. The stack looks roughly like this.

-----------  --------------------
| SCSI-ml |  | FC transport class
-----------  --------------------
   ^                    ^
   |                    |
   v                    v
---------------------------             -------------
| FCoE                    | <- - -> | libfc     |
---------------------------             -------------

^
|
v
--------------------------
| netdev
--------------------------

fcoe is the LLD to the SCSI-ml and it allocates the scsi_host. When allocating the scsi_host it requests some memory for the fc_lport (as well as a fcoe structure) and then uses the libfc state machine to login to the fabric and register with the necessary entities. This process requires the lport to start a fc_rport for the directory server (we must be logged in to do discovery). Once that has occurred we start discovery which queries the directory server and returns us a list of targets. We create a fc_rport for each of those targets and have the RP layer log us into each of those targets. Once we're logged into a target we "add" it to the transport layer. It show up in sysfs and the SCSI-ml begins querying it (I/O).

We've been trying to make libfc as flexible as possible as we expect a variety of LLDs to use it eventually. Users could be traditional FC HBAs, SW only FCoE HBAs or offloaded FC/FCoE HBAs. Therefore each block (EM, FCP, RP, LP, disc) can be implemented by libfc or by a LLD. Our transport template in libfc.h defines all of the transition points between each of these blocks so that a LLD that doesn't want to use the library provided block can just assign its own functions in the template before starting the library.

For libfc we've also added an interface at the FCP layer to allow LLDs to partially use that layer. This interface allows the library to do the SCSI->FC mapping and then pass the FCP command down to the LLD. A mini FC framing mini-library, in fc_encode.h and an ELS/CT interface is also available.

For FCoE there has been recent work to support FCoE HBAs that offload various functionality.

Quoted 5 lines

drivers/scsi/libfc/fc_disc.c line 36

Quoted 2 lines
drivers/scsi/libfc/fc_disc.c new file +2 -0
+#define FC_DISC_RETRY_LIMIT 3       /* max retries */
+#define FC_DISC_RETRY_DELAY 500UL   /* (msecs) delay */

Define is not used?

Yeah, I think you caught this below. I will fix it.

Quoted 4 lines
Quoted 4 lines
drivers/scsi/libfc/fc_disc.c new file +4 -0
+
+#define     FC_DISC_DELAY           3
+
+static int fc_disc_debug;
Quoted 9 lines

drivers/scsi/libfc/fc_disc.c line 46

Quoted 6 lines
drivers/scsi/libfc/fc_disc.c new file +6 -0
+
+#define FC_DEBUG_DISC(fmt...)                       \
+    do {                                    \
+            if (fc_disc_debug)              \
+                    FC_DBG(fmt);            \
+    } while (0)

In 2.6.28 there is dynamic_printk.h now to handle this.

Excellent, we have this block in a few places. I'll change this.

Quoted 33 lines
Quoted 6 lines
drivers/scsi/libfc/fc_disc.c new file +5 -0
+
+static struct mutex         disc_list_lock;
+static struct list_head             disc_list;
+
+struct fc_disc {

drivers/scsi/libfc/fc_disc.c line 61

Quoted 10 lines
drivers/scsi/libfc/fc_disc.c new file +10 -0
+    unsigned char           retry_count;
+    unsigned char           delay;
+    unsigned char           pending;
+    unsigned char           requested;
+    unsigned short          seq_count;
+    unsigned char           buf_len;
+    enum fc_disc_event      event;
+
+    void (*disc_callback)(struct fc_lport *,
+                          enum fc_disc_event);

While it may seem excessive for a single callback the tend is towards separate ->ops structures. They have the advantage that they can be made const which has at least some theoretical security advantages. Also callback numbers tend to grow over time.

Quoted 10 lines
drivers/scsi/libfc/fc_disc.c new file +10 -0
+/**
+ * fc_disc_lookup_rport - lookup a remote port by port_id
+ * @lport: Fibre Channel host port instance
+ * @port_id: remote port port_id to match
+ */
+struct fc_rport *fc_disc_lookup_rport(const struct fc_lport *lport,
+                                  u32 port_id) +{
+    struct fc_disc *disc;
+    struct fc_rport *rport, *found = NULL;
+    struct fc_rport_libfc_priv *rdata;
Quoted 9 lines

drivers/scsi/libfc/fc_disc.c line 98

Quoted 6 lines
drivers/scsi/libfc/fc_disc.c new file +6 -0
+    int disc_found = 0;
+
+    mutex_lock(&disc_list_lock);
+    list_for_each_entry(disc, &disc_list, list) {
+            if (disc->lport == lport) {
+                    list_for_each_entry(rdata, &disc->rports, peers) {

Hopefully the max numbers of either of those are strictly bounded.

The max number of discovery objects? It isn't bound now. I don't think that this discovery list is working out as well as I had hoped that it would. There is a patch on our mailing list now that removes this list and just attaches the disc object to the lport. This means that there is no lookup anymore. Since all incoming FC requests go though the lport first it can just follow its pointer, get the disc object and use it.

Quoted 11 lines

drivers/scsi/libfc/fc_disc.c line 129

Quoted 8 lines
drivers/scsi/libfc/fc_disc.c new file +8 -0
+
+/**
+ * fc_disc_alloc - Allocate a discovery work object
+ * @lport: The FC lport associated with the discovery job + */
+static inline struct fc_disc *fc_disc_alloc(struct fc_lport *lport)
+{ + struct fc_disc *disc;
+
+    disc = kzalloc(sizeof(struct fc_disc), GFP_KERNEL);

This misses a NULL check

OK, will fix.

Quoted 31 lines

drivers/scsi/libfc/fc_disc.c line 137

Quoted 8 lines
drivers/scsi/libfc/fc_disc.c new file +8 -0
+    INIT_LIST_HEAD(&disc->list);
+    INIT_DELAYED_WORK(&disc->disc_work, fc_disc_timeout);
+    mutex_init(&disc->disc_mutex);
+    INIT_LIST_HEAD(&disc->rports);
+
+    disc->lport = lport;
+    disc->delay = FC_DISC_DELAY;
+    disc->event = DISC_EV_NONE;

Is it ok that the callback (and probably some other fields) is not initialized here yet?

drivers/scsi/libfc/fc_disc.c line 141

Quoted 4 lines
drivers/scsi/libfc/fc_disc.c new file +4 -0
+
+    mutex_lock(&disc_list_lock);
+    list_add_tail(&disc->list, &disc_list);
+    mutex_unlock(&disc_list_lock);

... when you make this globally visible?

drivers/scsi/libfc/fc_disc.c line 201

Quoted 11 lines
drivers/scsi/libfc/fc_disc.c new file +11 -0
+    if (event == RPORT_EV_CREATED) {
+            mutex_lock(&disc_list_lock);
+            list_for_each_entry(disc, &disc_list, list) {
+                    if (disc->lport == lport) {
+                            found = 1;
+                            mutex_lock(&disc->disc_mutex);
+                            list_add_tail(&rdata->peers, &disc->rports);
+                            mutex_unlock(&disc->disc_mutex);
+                    }
+            }
+            mutex_unlock(&disc_list_lock);
Quoted 2 lines

That's a lot of locks. Did you have a locking order comment somewhere?

I have a locking comment at the top of fc_lport.c as well as fc_rport.c, but they don't mention the discovery code. After we change the disc object management I'll make sure they're up-to-date. The locking has been particularly troublesome for me, so I'm sure it can be improved.

Quoted 11 lines

drivers/scsi/libfc/fc_disc.c line 247

Quoted 7 lines
drivers/scsi/libfc/fc_disc.c new file +7 -0
+    if (!rp || rp->rscn_page_len != sizeof(*pp))
+            goto reject;
+
+    len = ntohs(rp->rscn_plen);
+    if (len < sizeof(*rp))
+            goto reject;
+    len -= sizeof(*rp);

Don't you need to check here than len is a multiple of sizeof(*pp) ? Otherwise bad input could make it loop a very long time.

I'll have to look into this. You're comment seems reasonable though.

Quoted 5 lines

Review

Quoted 2 lines
(quoted diff) +2 -0
+
+    for (pp = (void *)(rp + 1); len; len -= sizeof(*pp), pp++) {

Also len >= 0 is always safer.

Noted.

Quoted 31 lines
Quoted 5 lines
drivers/scsi/libfc/fc_disc.c new file +3 -0
+                          redisc, lport->state, disc->pending);
+            list_for_each_entry_safe(dp, next, &disc_ports, peers) {
+                    list_del(&dp->peers); +                 rport = lport->tt.rport_lookup(lport,

dp->ids.port_id); + if (rport) { + rdata = RPORT_TO_PRIV(rport);
+ list_del(&rdata->peers);

Hopefully there's a mutex here hold for that list.

drivers/scsi/libfc/fc_disc.c line 309

Quoted 13 lines
drivers/scsi/libfc/fc_disc.c new file +13 -0
+                            lport->tt.rport_logoff(rport);
+                    }
+                    fc_disc_single(disc, dp);
+            }
+    }
+    fc_frame_free(fp);
+    return;
+reject:
+    rjt_data.fp = NULL;
+    rjt_data.reason = ELS_RJT_LOGIC;
+    rjt_data.explan = ELS_EXPL_NONE;
+    lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
+    fc_frame_free(fp);

Some statistics counter for that case would be probably useful.

drivers/scsi/libfc/fc_disc.c line 349

Quoted 7 lines
drivers/scsi/libfc/fc_disc.c new file +7 -0
+
+    op = fc_frame_payload_op(fp);
+    switch (op) {
+    case ELS_RSCN:
+            mutex_lock(&disc->disc_mutex);
+            fc_disc_recv_rscn_req(sp, fp, disc);
+            mutex_unlock(&disc->disc_mutex);
Quoted 9 lines

Ok yes seems the lock is hold.

drivers/scsi/libfc/fc_disc.c

Quoted 5 lines
drivers/scsi/libfc/fc_disc.c new file +5 -0
+
+    list_for_each_entry_safe(rdata, next, &disc->rports, peers) {
+            rport = PRIV_TO_RPORT(rdata);
+            FC_DEBUG_DISC("list_del(%6x)\n", rport->port_id);
+            list_del(&rdata->peers); +              lport->tt.rport_logoff(rport);

Hopefully that callback knows for which peer that is.

I'm a little confused what you're referring to here. rport_logoff() is one of our transport template function pointers, so for the purely SW case the rport layer will handle the logoff(). I'm not sure if this is what you were getting at though.

Quoted 10 lines
Quoted 10 lines
drivers/scsi/libfc/fc_disc.c new file +10 -0
+static void fc_disc_start(void (*disc_callback)(struct fc_lport *,
+                                            enum fc_disc_event), +                    struct fc_lport *lport)
+{
+    struct fc_rport *rport;
+    struct fc_rport_identifiers ids;
+    struct fc_disc *disc;
+    int found = 0;
+
+    mutex_lock(&disc_list_lock);
+    list_for_each_entry(disc, &disc_list, list) {
Quoted 8 lines

drivers/scsi/libfc/fc_disc.c line 336

Quoted 6 lines
drivers/scsi/libfc/fc_disc.c new file +6 -0
+            if (disc->lport == lport) {
+                    found = 1;
+                    break;
+            }
+    }
+    mutex_unlock(&disc_list_lock);

This seems to be opencoded a lot. Put it into some helper.

Yes, we probably do this too much. If we end up not using the discovery list we can dump a lot of this code.

Quoted 14 lines
Quoted 14 lines
drivers/scsi/libfc/fc_disc.c new file +14 -0
+
+    /*
+     * Handle point-to-point mode as a simple discovery
+     * of the remote port. Yucky, yucky, yuck, yuck!
+     */
+    rport = disc->lport->ptp_rp;
+    if (rport) {
+            ids.port_id = rport->port_id;
+            ids.port_name = rport->port_name;
+            ids.node_name = rport->node_name;
+            ids.roles = FC_RPORT_ROLE_UNKNOWN;
+            get_device(&rport->dev);
+
+            if (!fc_disc_new_target(disc, rport, &ids)) {
Quoted 9 lines

drivers/scsi/libfc/fc_disc.c line 454

Quoted 4 lines
drivers/scsi/libfc/fc_disc.c new file +4 -0
+                    disc->event = DISC_EV_SUCCESS;
+                    fc_disc_done(disc);
+            }
+            put_device(&rport->dev);

The ref counting here seems a little dubious. If it's because disc_new_target can sleep then preemptible kernels can do that anyways. Or it's not needed.

OK, I'll have to look into this.

Quoted 26 lines
Quoted 15 lines
drivers/scsi/libfc/fc_disc.c new file +6 -0
+    }
+    if (((ids->port_name != -1) || (ids->port_id != -1)) &&
+        ids->port_id != fc_host_port_id(lport->host) &&
+        ids->port_name != lport->wwpn) {
+            if (!rport) {
+                    rport = lport->tt.rport_lookup(lport, ids->port_id); +                  if

(!rport) { + struct fc_disc_port dp;

drivers/scsi/libfc/fc_disc.c new file +8 -0
+                            dp.lp = lport;
+                            dp.ids.port_id = ids->port_id;
+                            dp.ids.port_name = ids->port_name;
+                            dp.ids.node_name = ids->node_name;
+                            dp.ids.roles = ids->roles;
+                            rport = fc_rport_rogue_create(&dp);
+                    }
+                    if (!rport)

drivers/scsi/libfc/fc_disc.c line 522

Quoted 10 lines
drivers/scsi/libfc/fc_disc.c new file +10 -0
+                            error = ENOMEM;
+            }
+            if (rport) {
+                    rp = rport->dd_data;
+                    rp->event_callback = fc_disc_rport_event;
+                    rp->rp_state = RPORT_ST_INIT;
+                    lport->tt.rport_login(rport);
+            }
+    }
+    return error;
Quoted 2 lines

Unusual positive error return convention. Ok?

Just an oversight, I'll correct this.

Quoted 17 lines

drivers/scsi/libfc/fc_disc.c line 572

Quoted 5 lines
drivers/scsi/libfc/fc_disc.c new file +5 -0
+            FC_DBG("Error %ld, retries %d/%d\n",
+                   PTR_ERR(fp), disc->retry_count,
+                   FC_DISC_RETRY_LIMIT);
+
+    if (!fp || PTR_ERR(fp) == -FC_EX_TIMEOUT) {

The mixing of non errnos into PTR_ERR is also unusual, but ok, but make sure you never leak them.

drivers/scsi/libfc/fc_disc.c line 580

Quoted 7 lines
(quoted diff) +2 -0
+            /*
+             * Memory allocation failure, or the exchange timed out, +               *

retry after delay. + */

drivers/scsi/libfc/fc_disc.c new file +4 -0
+            if (disc->retry_count < FC_DISC_RETRY_LIMIT) {
+                    /* go ahead and retry */
+                    if (!fp)
+                            delay = msecs_to_jiffies(500);
Quoted 2 lines

Ah that was the missing define above?

Yeah, we'll take care of this.

Quoted 11 lines

drivers/scsi/libfc/fc_disc.c line 587

Quoted 7 lines
drivers/scsi/libfc/fc_disc.c new file +7 -0
+                    else {
+                            delay = jiffies +
+                                    msecs_to_jiffies(lport->e_d_tov);
+
+                            /* timeout faster first time */
+                            if (!disc->retry_count)
+                                    delay /= 4;

You have to divide by four before you add to jiffies, dividing absolute jiffies doesn't make sense.

Will do.

Quoted 12 lines

drivers/scsi/libfc/fc_disc.c line 665

Quoted 11 lines
drivers/scsi/libfc/fc_disc.c new file +11 -0
+    /*
+     * Handle partial name record left over from previous call. +    */
+    bp = buf;
+    plen = len;
+    np = (struct fc_gpn_ft_resp *)bp;
+    tlen = disc->buf_len;
+    if (tlen) {
+            WARN_ON(tlen >= sizeof(*np));
+            plen = sizeof(*np) - tlen;
+            WARN_ON(plen <= 0);
+            WARN_ON(plen >= sizeof(*np));
Quoted 6 lines

I hope none of these WARN_ONs in network controllable. They nearly look like some of them are.

Ok stopping here for now. That's a lot of code. Perhaps split it up into a little smaller patches?

OK, I can do that. Honestly, preparing these patches is a pain. We have a full git tree that isn't reviewable. So, I diff, splitdiff and then start putting things back together manually. Maybe, patches by the different blocks would be more easily reviewable...?

Most people are on vacation this week, including myself. We'll correct the called-out problems and re-send a patch next week.

Quoted 2 lines

General impressions:
- Your locking is to complicated I think. Less locks is often more.

So, the question for me is really if the discovery object should have its own lock or if it should share the lport's lock. I liked it having its own lock because it seemed to make it more modular, but the discovery code (as well as the EM) still relies on the lport and so it is in limbo a bit. It has its own members and lock, but still relies on the lport. If the pointer to the discovery object moves into the lport and the disc list goes away then maybe it makes sense to just use the lport lock. I guess I envisioned some meta-data eventually being passed between the lport and the discovery layer so they were more independent.

Quoted 6 lines

For short locks we also recommend spinlocks which perform better (although you have to make sure you don't sleep then of course)
- I would double check everything that handles network data to make sure it's not exploitable.

-Andi

Thanks,

//Rob

#5 lore raw

RE: [PATCH 2/3] libfc: A modular Fibre Channel library

In reply to Andi Kleen
Quoted 2 lines · Andi Kleen

Robert Love <[email protected]> writes:

<snip>

Quoted 10 lines

drivers/scsi/libfc/fc_disc.c line 46

Quoted 7 lines
drivers/scsi/libfc/fc_disc.c new file +7 -0
+static int fc_disc_debug;
+
+#define FC_DEBUG_DISC(fmt...)			\
+	do {					\
+		if (fc_disc_debug)		\
+			FC_DBG(fmt);		\
+	} while (0)

In 2.6.28 there is dynamic_printk.h now to handle this.

I was looking into making this change, but the dynamic_printk doesn't do what we want. We have this code in each of our layers to allow us to turn on debugging at a sub-module level, as far as I can tell this isn't supported by the dynamic_printk.

I then thought that we could convert our debug statements to pr_debug() calls (I'm not sure what 'pr' stands for, but I think that's what I should use). However, that would cause us to do excessive printing if the kernel was configured with DEBUG (how do you set this?). This is especially true in the EM where code is executed frequently and some of our debug statements happen often when the EM debug define has a value. Also, it would mean that when debugging Open-FCoE, we'd have all kernel debug statements, not just our own.

What I really want is the ability to dynamically turn on or off our port code debug statements (LP, RP and disc) and then have a compile option for our I/O path and EM. We think that adding module parameter to toggle some of these prints would probably work best for our needs, but it's low on our priority list right now.

Open-iSCSI uses a method similar to what we're doing, just not to the degree that we're doing it and I didn't find much use of pr_debug in drivers/scsi/* or include/scsi/*.

#6 lore raw

PATCH 3/3 fcoe: Fibre Channel over Ethernet

In reply to Robert Love

Encapsulation protocol for running Fibre Channel over Ethernet interfaces. Creates virtual Fibre Channel host adapters using libfc.

This patch leaves two WARNINGs from checkpatch.pl regarding the use of NR_CPUS. We're using them to create per-cpu receive threads. Since these are WARNINGS and not ERRORS we'd like to fix this issue later.

---

 drivers/scsi/Kconfig                  |    7 
 drivers/scsi/Makefile                 |    1 
 drivers/scsi/fcoe/Makefile            |    8 
 drivers/scsi/fcoe/fc_transport_fcoe.c |  446 ++++++++++
 drivers/scsi/fcoe/fcoe_sw.c           |  488 +++++++++++
 drivers/scsi/fcoe/libfcoe.c           | 1506 +++++++++++++++++++++++++++++++++
 include/scsi/fc_transport_fcoe.h      |   54 +
 include/scsi/libfcoe.h                |  177 ++++
 8 files changed, 2687 insertions(+), 0 deletions(-)
 create mode 100644 drivers/scsi/fcoe/Makefile
 create mode 100644 drivers/scsi/fcoe/fc_transport_fcoe.c
 create mode 100644 drivers/scsi/fcoe/fcoe_sw.c
 create mode 100644 drivers/scsi/fcoe/libfcoe.c
 create mode 100644 include/scsi/fc_transport_fcoe.h
 create mode 100644 include/scsi/libfcoe.h
drivers/scsi/Kconfig +7 -0
index 860c935..a3a73ea 100644
@@ -609,6 +609,13 @@ config LIBFC
 	---help---
 	  Fibre Channel library module
 
+config FCOE
+	tristate "FCoE module"
+	depends on SCSI
+	select LIBFC
+	---help---
+	  Fibre Channel over Ethernet module
+
 config SCSI_DMX3191D
 	tristate "DMX3191D SCSI support"
 	depends on PCI && SCSI
drivers/scsi/Makefile +1 -0
index 9158dc6..b0aa59e 100644
@@ -37,6 +37,7 @@ obj-$(CONFIG_SCSI_SRP_ATTRS)	+= scsi_transport_srp.o
 obj-$(CONFIG_SCSI_DH)		+= device_handler/
 
 obj-$(CONFIG_LIBFC)		+= libfc/
+obj-$(CONFIG_FCOE)		+= fcoe/
 obj-$(CONFIG_ISCSI_TCP) 	+= libiscsi.o	iscsi_tcp.o
 obj-$(CONFIG_INFINIBAND_ISER) 	+= libiscsi.o
 obj-$(CONFIG_SCSI_A4000T)	+= 53c700.o	a4000t.o
drivers/scsi/fcoe/Makefile new file +8 -0
new file mode 100644
index 0000000..b78da06
@@ -0,0 +1,8 @@
+# $Id: Makefile
+
+obj-$(CONFIG_FCOE) += fcoe.o
+
+fcoe-y := \
+	libfcoe.o \
+	fcoe_sw.o \
+	fc_transport_fcoe.o
drivers/scsi/fcoe/fc_transport_fcoe.c new file +446 -0

446 lines not on this page · raw message

drivers/scsi/fcoe/fcoe_sw.c new file +488 -0

488 lines not on this page · raw message

drivers/scsi/fcoe/libfcoe.c new file +1506 -0

1,506 lines not on this page · raw message

include/scsi/fc_transport_fcoe.h new file +54 -0

54 lines not on this page · raw message

include/scsi/libfcoe.h new file +177 -0

177 lines not on this page · raw message