add idl4k kernel firmware version 1.13.0.105

This commit is contained in:
Jaroslav Kysela
2015-03-26 17:22:37 +01:00
parent 5194d2792e
commit e9070cdc77
31064 changed files with 12769984 additions and 0 deletions

View File

@@ -0,0 +1,4 @@
header-y += scsi.h
header-y += scsi_netlink.h
header-y += scsi_netlink_fc.h
header-y += scsi_bsg_fc.h

View File

@@ -0,0 +1,816 @@
/*
* 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_ADISC payload
*/
struct fc_els_adisc {
__u8 adisc_cmd;
__u8 adisc_resv[3];
__u8 adisc_resv1;
__u8 adisc_hard_addr[3];
__be64 adisc_wwpn;
__be64 adisc_wwnn;
__u8 adisc_resv2;
__u8 adisc_port_id[3];
} __attribute__((__packed__));
/*
* 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_ */

View File

@@ -0,0 +1,138 @@
/*
* 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_ENCAPS_H_
#define _FC_ENCAPS_H_
/*
* Protocol definitions from RFC 3643 - Fibre Channel Frame Encapsulation.
*
* Note: The frame length field is the number of 32-bit words in
* the encapsulation including the fcip_encaps_header, CRC and EOF words.
* The minimum frame length value in bytes is (32 + 24 + 4 + 4) * 4 = 64.
* The maximum frame length value in bytes is (32 + 24 + 2112 + 4 + 4) = 2172.
*/
#define FC_ENCAPS_MIN_FRAME_LEN 64 /* min frame len (bytes) (see above) */
#define FC_ENCAPS_MAX_FRAME_LEN (FC_ENCAPS_MIN_FRAME_LEN + FC_MAX_PAYLOAD)
#define FC_ENCAPS_VER 1 /* current version number */
struct fc_encaps_hdr {
__u8 fc_proto; /* protocol number */
__u8 fc_ver; /* version of encapsulation */
__u8 fc_proto_n; /* ones complement of protocol */
__u8 fc_ver_n; /* ones complement of version */
unsigned char fc_proto_data[8]; /* protocol specific data */
__be16 fc_len_flags; /* 10-bit length/4 w/ 6 flag bits */
__be16 fc_len_flags_n; /* ones complement of length / flags */
/*
* Offset 0x10
*/
__be32 fc_time[2]; /* time stamp: seconds and fraction */
__be32 fc_crc; /* CRC */
__be32 fc_sof; /* start of frame (see FC_SOF below) */
/* 0x20 - FC frame content followed by EOF word */
};
#define FCIP_ENCAPS_HDR_LEN 0x20 /* expected length for asserts */
/*
* Macro's for making redundant copies of EOF and SOF.
*/
#define FC_XY(x, y) ((((x) & 0xff) << 8) | ((y) & 0xff))
#define FC_XYXY(x, y) ((FCIP_XY(x, y) << 16) | FCIP_XY(x, y))
#define FC_XYNN(x, y) (FCIP_XYXY(x, y) ^ 0xffff)
#define FC_SOF_ENCODE(n) FC_XYNN(n, n)
#define FC_EOF_ENCODE(n) FC_XYNN(n, n)
/*
* SOF / EOF bytes.
*/
enum fc_sof {
FC_SOF_F = 0x28, /* fabric */
FC_SOF_I4 = 0x29, /* initiate class 4 */
FC_SOF_I2 = 0x2d, /* initiate class 2 */
FC_SOF_I3 = 0x2e, /* initiate class 3 */
FC_SOF_N4 = 0x31, /* normal class 4 */
FC_SOF_N2 = 0x35, /* normal class 2 */
FC_SOF_N3 = 0x36, /* normal class 3 */
FC_SOF_C4 = 0x39, /* activate class 4 */
} __attribute__((packed));
enum fc_eof {
FC_EOF_N = 0x41, /* normal (not last frame of seq) */
FC_EOF_T = 0x42, /* terminate (last frame of sequence) */
FC_EOF_RT = 0x44,
FC_EOF_DT = 0x46, /* disconnect-terminate class-1 */
FC_EOF_NI = 0x49, /* normal-invalid */
FC_EOF_DTI = 0x4e, /* disconnect-terminate-invalid */
FC_EOF_RTI = 0x4f,
FC_EOF_A = 0x50, /* abort */
} __attribute__((packed));
#define FC_SOF_CLASS_MASK 0x06 /* mask for class of service in SOF */
/*
* Define classes in terms of the SOF code (initial).
*/
enum fc_class {
FC_CLASS_NONE = 0, /* software value indicating no class */
FC_CLASS_2 = FC_SOF_I2,
FC_CLASS_3 = FC_SOF_I3,
FC_CLASS_4 = FC_SOF_I4,
FC_CLASS_F = FC_SOF_F,
};
/*
* Determine whether SOF code indicates the need for a BLS ACK.
*/
static inline int fc_sof_needs_ack(enum fc_sof sof)
{
return (~sof) & 0x02; /* true for class 1, 2, 4, 6, or F */
}
/*
* Given an fc_class, return the normal (non-initial) SOF value.
*/
static inline enum fc_sof fc_sof_normal(enum fc_class class)
{
return class + FC_SOF_N3 - FC_SOF_I3; /* diff is always 8 */
}
/*
* Compute class from SOF value.
*/
static inline enum fc_class fc_sof_class(enum fc_sof sof)
{
return (sof & 0x7) | FC_SOF_F;
}
/*
* Determine whether SOF is for the initial frame of a sequence.
*/
static inline int fc_sof_is_init(enum fc_sof sof)
{
return sof < 0x30;
}
#endif /* _FC_ENCAPS_H_ */

View File

@@ -0,0 +1,123 @@
/*
* 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_FC2_H_
#define _FC_FC2_H_
/*
* Fibre Channel Exchanges and Sequences.
*/
#ifndef PACKED
#define PACKED __attribute__ ((__packed__))
#endif /* PACKED */
/*
* Sequence Status Block.
* This format is set by the FC-FS standard and is sent over the wire.
* Note that the fields aren't all naturally aligned.
*/
struct fc_ssb {
__u8 ssb_seq_id; /* sequence ID */
__u8 _ssb_resvd;
__be16 ssb_low_seq_cnt; /* lowest SEQ_CNT */
__be16 ssb_high_seq_cnt; /* highest SEQ_CNT */
__be16 ssb_s_stat; /* sequence status flags */
__be16 ssb_err_seq_cnt; /* error SEQ_CNT */
__u8 ssb_fh_cs_ctl; /* frame header CS_CTL */
__be16 ssb_fh_ox_id; /* frame header OX_ID */
__be16 ssb_rx_id; /* responder's exchange ID */
__u8 _ssb_resvd2[2];
} PACKED;
/*
* The SSB should be 17 bytes. Since it's layout is somewhat strange,
* we define the size here so that code can ASSERT that the size comes out
* correct.
*/
#define FC_SSB_SIZE 17 /* length of fc_ssb for assert */
/*
* ssb_s_stat - flags from FC-FS-2 T11/1619-D Rev 0.90.
*/
#define SSB_ST_RESP (1 << 15) /* sequence responder */
#define SSB_ST_ACTIVE (1 << 14) /* sequence is active */
#define SSB_ST_ABNORMAL (1 << 12) /* abnormal ending condition */
#define SSB_ST_REQ_MASK (3 << 10) /* ACK, abort sequence condition */
#define SSB_ST_REQ_CONT (0 << 10)
#define SSB_ST_REQ_ABORT (1 << 10)
#define SSB_ST_REQ_STOP (2 << 10)
#define SSB_ST_REQ_RETRANS (3 << 10)
#define SSB_ST_ABTS (1 << 9) /* ABTS protocol completed */
#define SSB_ST_RETRANS (1 << 8) /* retransmission completed */
#define SSB_ST_TIMEOUT (1 << 7) /* sequence timed out by recipient */
#define SSB_ST_P_RJT (1 << 6) /* P_RJT transmitted */
#define SSB_ST_CLASS_BIT 4 /* class of service field LSB */
#define SSB_ST_CLASS_MASK 3 /* class of service mask */
#define SSB_ST_ACK (1 << 3) /* ACK (EOFt or EOFdt) transmitted */
/*
* Exchange Status Block.
* This format is set by the FC-FS standard and is sent over the wire.
* Note that the fields aren't all naturally aligned.
*/
struct fc_esb {
__u8 esb_cs_ctl; /* CS_CTL for frame header */
__be16 esb_ox_id; /* originator exchange ID */
__be16 esb_rx_id; /* responder exchange ID */
__be32 esb_orig_fid; /* fabric ID of originator */
__be32 esb_resp_fid; /* fabric ID of responder */
__be32 esb_e_stat; /* status */
__u8 _esb_resvd[4];
__u8 esb_service_params[112]; /* TBD */
__u8 esb_seq_status[8]; /* sequence statuses, 8 bytes each */
} __attribute__((packed));
/*
* Define expected size for ASSERTs.
* See comments on FC_SSB_SIZE.
*/
#define FC_ESB_SIZE (1 + 5*4 + 112 + 8) /* expected size */
/*
* esb_e_stat - flags from FC-FS-2 T11/1619-D Rev 0.90.
*/
#define ESB_ST_RESP (1 << 31) /* responder to exchange */
#define ESB_ST_SEQ_INIT (1 << 30) /* port holds sequence initiaive */
#define ESB_ST_COMPLETE (1 << 29) /* exchange is complete */
#define ESB_ST_ABNORMAL (1 << 28) /* abnormal ending condition */
#define ESB_ST_REC_QUAL (1 << 26) /* recovery qualifier active */
#define ESB_ST_ERRP_BIT 24 /* LSB for error policy */
#define ESB_ST_ERRP_MASK (3 << 24) /* mask for error policy */
#define ESB_ST_ERRP_MULT (0 << 24) /* abort, discard multiple sequences */
#define ESB_ST_ERRP_SING (1 << 24) /* abort, discard single sequence */
#define ESB_ST_ERRP_INF (2 << 24) /* process with infinite buffers */
#define ESB_ST_ERRP_IMM (3 << 24) /* discard mult. with immed. retran. */
#define ESB_ST_OX_ID_INVL (1 << 23) /* originator XID invalid */
#define ESB_ST_RX_ID_INVL (1 << 22) /* responder XID invalid */
#define ESB_ST_PRI_INUSE (1 << 21) /* priority / preemption in use */
#endif /* _FC_FC2_H_ */

View File

@@ -0,0 +1,103 @@
/*
* 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_FCOE_H_
#define _FC_FCOE_H_
/*
* FCoE - Fibre Channel over Ethernet.
*/
/*
* FC_FCOE_OUI hasn't been standardized yet. XXX TBD.
*/
#ifndef FC_FCOE_OUI
#define FC_FCOE_OUI 0x0efc00 /* upper 24 bits of FCOE dest MAC TBD */
#endif
/*
* The destination MAC address for the fabric login may get a different OUI.
* This isn't standardized yet.
*/
#ifndef FC_FCOE_FLOGI_MAC
/* gateway MAC - TBD */
#define FC_FCOE_FLOGI_MAC { 0x0e, 0xfc, 0x00, 0xff, 0xff, 0xfe }
#endif
#define FC_FCOE_VER 0 /* version */
/*
* Ethernet Addresses based on FC S_ID and D_ID.
* Generated by FC_FCOE_OUI | S_ID/D_ID
*/
#define FC_FCOE_ENCAPS_ID(n) (((u64) FC_FCOE_OUI << 24) | (n))
#define FC_FCOE_DECAPS_ID(n) ((n) >> 24)
/*
* FCoE frame header - 14 bytes
*
* This is the August 2007 version of the FCoE header as defined by T11.
* This follows the VLAN header, which includes the ethertype.
*/
struct fcoe_hdr {
__u8 fcoe_ver; /* version field - upper 4 bits */
__u8 fcoe_resvd[12]; /* reserved - send zero and ignore */
__u8 fcoe_sof; /* start of frame per RFC 3643 */
};
#define FC_FCOE_DECAPS_VER(hp) ((hp)->fcoe_ver >> 4)
#define FC_FCOE_ENCAPS_VER(hp, ver) ((hp)->fcoe_ver = (ver) << 4)
/*
* FCoE CRC & EOF - 8 bytes.
*/
struct fcoe_crc_eof {
__le32 fcoe_crc32; /* CRC for FC packet */
__u8 fcoe_eof; /* EOF from RFC 3643 */
__u8 fcoe_resvd[3]; /* reserved - send zero and ignore */
} __attribute__((packed));
/*
* Minimum FCoE + FC header length
* 14 bytes FCoE header + 24 byte FC header = 38 bytes
*/
#define FCOE_HEADER_LEN 38
/*
* Minimum FCoE frame size
* 14 bytes FCoE header + 24 byte FC header + 8 byte FCoE trailer = 46 bytes
*/
#define FCOE_MIN_FRAME 46
/*
* fc_fcoe_set_mac - Store OUI + DID into MAC address field.
* @mac: mac address to be set
* @did: fc dest id to use
*/
static inline void fc_fcoe_set_mac(u8 *mac, u8 *did)
{
mac[0] = (u8) (FC_FCOE_OUI >> 16);
mac[1] = (u8) (FC_FCOE_OUI >> 8);
mac[2] = (u8) FC_FCOE_OUI;
mac[3] = did[0];
mac[4] = did[1];
mac[5] = did[2];
}
#endif /* _FC_FCOE_H_ */

View File

@@ -0,0 +1,199 @@
/*
* 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_FCP_H_
#define _FC_FCP_H_
/*
* Fibre Channel Protocol for SCSI.
* From T10 FCP-3, T10 project 1560-D Rev 4, Sept. 13, 2005.
*/
/*
* fc/fs.h defines FC_TYPE_FCP.
*/
/*
* Service parameter page parameters (word 3 bits) for Process Login.
*/
#define FCP_SPPF_TASK_RETRY_ID 0x0200 /* task retry ID requested */
#define FCP_SPPF_RETRY 0x0100 /* retry supported */
#define FCP_SPPF_CONF_COMPL 0x0080 /* confirmed completion allowed */
#define FCP_SPPF_OVLY_ALLOW 0x0040 /* data overlay allowed */
#define FCP_SPPF_INIT_FCN 0x0020 /* initiator function */
#define FCP_SPPF_TARG_FCN 0x0010 /* target function */
#define FCP_SPPF_RD_XRDY_DIS 0x0002 /* disable XFER_RDY for reads */
#define FCP_SPPF_WR_XRDY_DIS 0x0001 /* disable XFER_RDY for writes */
/*
* FCP_CMND IU Payload.
*/
struct fcp_cmnd {
__u8 fc_lun[8]; /* logical unit number */
__u8 fc_cmdref; /* commmand reference number */
__u8 fc_pri_ta; /* priority and task attribute */
__u8 fc_tm_flags; /* task management flags */
__u8 fc_flags; /* additional len & flags */
__u8 fc_cdb[16]; /* base CDB */
__be32 fc_dl; /* data length (must follow fc_cdb) */
};
#define FCP_CMND_LEN 32 /* expected length of structure */
struct fcp_cmnd32 {
__u8 fc_lun[8]; /* logical unit number */
__u8 fc_cmdref; /* commmand reference number */
__u8 fc_pri_ta; /* priority and task attribute */
__u8 fc_tm_flags; /* task management flags */
__u8 fc_flags; /* additional len & flags */
__u8 fc_cdb[32]; /* base CDB */
__be32 fc_dl; /* data length (must follow fc_cdb) */
};
#define FCP_CMND32_LEN 48 /* expected length of structure */
#define FCP_CMND32_ADD_LEN (16 / 4) /* Additional cdb length */
/*
* fc_pri_ta.
*/
#define FCP_PTA_SIMPLE 0 /* simple task attribute */
#define FCP_PTA_HEADQ 1 /* head of queue task attribute */
#define FCP_PTA_ORDERED 2 /* ordered task attribute */
#define FCP_PTA_ACA 4 /* auto. contigent allegiance */
#define FCP_PRI_SHIFT 3 /* priority field starts in bit 3 */
#define FCP_PRI_RESVD_MASK 0x80 /* reserved bits in priority field */
/*
* fc_tm_flags - task management flags field.
*/
#define FCP_TMF_CLR_ACA 0x40 /* clear ACA condition */
#define FCP_TMF_LUN_RESET 0x10 /* logical unit reset task management */
#define FCP_TMF_CLR_TASK_SET 0x04 /* clear task set */
#define FCP_TMF_ABT_TASK_SET 0x02 /* abort task set */
/*
* fc_flags.
* Bits 7:2 are the additional FCP_CDB length / 4.
*/
#define FCP_CFL_LEN_MASK 0xfc /* mask for additional length */
#define FCP_CFL_LEN_SHIFT 2 /* shift bits for additional length */
#define FCP_CFL_RDDATA 0x02 /* read data */
#define FCP_CFL_WRDATA 0x01 /* write data */
/*
* FCP_TXRDY IU - transfer ready payload.
*/
struct fcp_txrdy {
__be32 ft_data_ro; /* data relative offset */
__be32 ft_burst_len; /* burst length */
__u8 _ft_resvd[4]; /* reserved */
};
#define FCP_TXRDY_LEN 12 /* expected length of structure */
/*
* FCP_RESP IU - response payload.
*
* The response payload comes in three parts: the flags/status, the
* sense/response lengths and the sense data/response info section.
*
* From FCP3r04, note 6 of section 9.5.13:
*
* Some early implementations presented the FCP_RSP IU without the FCP_RESID,
* FCP_SNS_LEN, and FCP_RSP_LEN fields if the FCP_RESID_UNDER, FCP_RESID_OVER,
* FCP_SNS_LEN_VALID, and FCP_RSP_LEN_VALID bits were all set to zero. This
* non-standard behavior should be tolerated.
*
* All response frames will always contain the fcp_resp template. Some
* will also include the fcp_resp_len template.
*/
struct fcp_resp {
__u8 _fr_resvd[8]; /* reserved */
__be16 fr_retry_delay; /* retry delay timer */
__u8 fr_flags; /* flags */
__u8 fr_status; /* SCSI status code */
};
#define FCP_RESP_LEN 12 /* expected length of structure */
struct fcp_resp_ext {
__be32 fr_resid; /* Residual value */
__be32 fr_sns_len; /* SCSI Sense length */
__be32 fr_rsp_len; /* Response Info length */
/*
* Optionally followed by RSP info and/or SNS info and/or
* bidirectional read residual length, if any.
*/
};
#define FCP_RESP_EXT_LEN 12 /* expected length of the structure */
struct fcp_resp_rsp_info {
__u8 _fr_resvd[3]; /* reserved */
__u8 rsp_code; /* Response Info Code */
__u8 _fr_resvd2[4]; /* reserved */
};
struct fcp_resp_with_ext {
struct fcp_resp resp;
struct fcp_resp_ext ext;
};
#define FCP_RESP_WITH_EXT (FCP_RESP_LEN + FCP_RESP_EXT_LEN)
/*
* fr_flags.
*/
#define FCP_BIDI_RSP 0x80 /* bidirectional read response */
#define FCP_BIDI_READ_UNDER 0x40 /* bidir. read less than requested */
#define FCP_BIDI_READ_OVER 0x20 /* DL insufficient for full transfer */
#define FCP_CONF_REQ 0x10 /* confirmation requested */
#define FCP_RESID_UNDER 0x08 /* transfer shorter than expected */
#define FCP_RESID_OVER 0x04 /* DL insufficient for full transfer */
#define FCP_SNS_LEN_VAL 0x02 /* SNS_LEN field is valid */
#define FCP_RSP_LEN_VAL 0x01 /* RSP_LEN field is valid */
/*
* rsp_codes
*/
enum fcp_resp_rsp_codes {
FCP_TMF_CMPL = 0,
FCP_DATA_LEN_INVALID = 1,
FCP_CMND_FIELDS_INVALID = 2,
FCP_DATA_PARAM_MISMATCH = 3,
FCP_TMF_REJECTED = 4,
FCP_TMF_FAILED = 5,
FCP_TMF_INVALID_LUN = 9,
};
/*
* FCP SRR Link Service request - Sequence Retransmission Request.
*/
struct fcp_srr {
__u8 srr_op; /* opcode ELS_SRR */
__u8 srr_resvd[3]; /* opcode / reserved - must be zero */
__be16 srr_ox_id; /* OX_ID of failed command */
__be16 srr_rx_id; /* RX_ID of failed command */
__be32 srr_rel_off; /* relative offset */
__u8 srr_r_ctl; /* r_ctl for the information unit */
__u8 srr_resvd2[3]; /* reserved */
};
#endif /* _FC_FCP_H_ */

View File

@@ -0,0 +1,230 @@
/*
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _FC_FIP_H_
#define _FC_FIP_H_
/*
* This version is based on:
* http://www.t11.org/ftp/t11/pub/fc/bb-5/08-543v1.pdf
*/
#define FIP_DEF_PRI 128 /* default selection priority */
#define FIP_DEF_FC_MAP 0x0efc00 /* default FCoE MAP (MAC OUI) value */
#define FIP_DEF_FKA 8000 /* default FCF keep-alive/advert period (mS) */
#define FIP_VN_KA_PERIOD 90000 /* required VN_port keep-alive period (mS) */
#define FIP_FCF_FUZZ 100 /* random time added by FCF (mS) */
/*
* Multicast MAC addresses. T11-adopted.
*/
#define FIP_ALL_FCOE_MACS ((u8[6]) { 1, 0x10, 0x18, 1, 0, 0 })
#define FIP_ALL_ENODE_MACS ((u8[6]) { 1, 0x10, 0x18, 1, 0, 1 })
#define FIP_ALL_FCF_MACS ((u8[6]) { 1, 0x10, 0x18, 1, 0, 2 })
#define FIP_VER 1 /* version for fip_header */
struct fip_header {
__u8 fip_ver; /* upper 4 bits are the version */
__u8 fip_resv1; /* reserved */
__be16 fip_op; /* operation code */
__u8 fip_resv2; /* reserved */
__u8 fip_subcode; /* lower 4 bits are sub-code */
__be16 fip_dl_len; /* length of descriptors in words */
__be16 fip_flags; /* header flags */
} __attribute__((packed));
#define FIP_VER_SHIFT 4
#define FIP_VER_ENCAPS(v) ((v) << FIP_VER_SHIFT)
#define FIP_VER_DECAPS(v) ((v) >> FIP_VER_SHIFT)
#define FIP_BPW 4 /* bytes per word for lengths */
/*
* fip_op.
*/
enum fip_opcode {
FIP_OP_DISC = 1, /* discovery, advertisement, etc. */
FIP_OP_LS = 2, /* Link Service request or reply */
FIP_OP_CTRL = 3, /* Keep Alive / Link Reset */
FIP_OP_VLAN = 4, /* VLAN discovery */
FIP_OP_VENDOR_MIN = 0xfff8, /* min vendor-specific opcode */
FIP_OP_VENDOR_MAX = 0xfffe, /* max vendor-specific opcode */
};
/*
* Subcodes for FIP_OP_DISC.
*/
enum fip_disc_subcode {
FIP_SC_SOL = 1, /* solicitation */
FIP_SC_ADV = 2, /* advertisement */
};
/*
* Subcodes for FIP_OP_LS.
*/
enum fip_trans_subcode {
FIP_SC_REQ = 1, /* request */
FIP_SC_REP = 2, /* reply */
};
/*
* Subcodes for FIP_OP_RESET.
*/
enum fip_reset_subcode {
FIP_SC_KEEP_ALIVE = 1, /* keep-alive from VN_Port */
FIP_SC_CLR_VLINK = 2, /* clear virtual link from VF_Port */
};
/*
* Subcodes for FIP_OP_VLAN.
*/
enum fip_vlan_subcode {
FIP_SC_VL_REQ = 1, /* request */
FIP_SC_VL_REP = 2, /* reply */
};
/*
* flags in header fip_flags.
*/
enum fip_flag {
FIP_FL_FPMA = 0x8000, /* supports FPMA fabric-provided MACs */
FIP_FL_SPMA = 0x4000, /* supports SPMA server-provided MACs */
FIP_FL_AVAIL = 0x0004, /* available for FLOGI/ELP */
FIP_FL_SOL = 0x0002, /* this is a solicited message */
FIP_FL_FPORT = 0x0001, /* sent from an F port */
};
/*
* Common descriptor header format.
*/
struct fip_desc {
__u8 fip_dtype; /* type - see below */
__u8 fip_dlen; /* length - in 32-bit words */
};
enum fip_desc_type {
FIP_DT_PRI = 1, /* priority for forwarder selection */
FIP_DT_MAC = 2, /* MAC address */
FIP_DT_MAP_OUI = 3, /* FC-MAP OUI */
FIP_DT_NAME = 4, /* switch name or node name */
FIP_DT_FAB = 5, /* fabric descriptor */
FIP_DT_FCOE_SIZE = 6, /* max FCoE frame size */
FIP_DT_FLOGI = 7, /* FLOGI request or response */
FIP_DT_FDISC = 8, /* FDISC request or response */
FIP_DT_LOGO = 9, /* LOGO request or response */
FIP_DT_ELP = 10, /* ELP request or response */
FIP_DT_VN_ID = 11, /* VN_Node Identifier */
FIP_DT_FKA = 12, /* advertisement keep-alive period */
FIP_DT_VENDOR = 13, /* vendor ID */
FIP_DT_VLAN = 14, /* vlan number */
FIP_DT_LIMIT, /* max defined desc_type + 1 */
FIP_DT_VENDOR_BASE = 128, /* first vendor-specific desc_type */
};
/*
* FIP_DT_PRI - priority descriptor.
*/
struct fip_pri_desc {
struct fip_desc fd_desc;
__u8 fd_resvd;
__u8 fd_pri; /* FCF priority: higher is better */
} __attribute__((packed));
/*
* FIP_DT_MAC - MAC address descriptor.
*/
struct fip_mac_desc {
struct fip_desc fd_desc;
__u8 fd_mac[ETH_ALEN];
} __attribute__((packed));
/*
* FIP_DT_MAP - descriptor.
*/
struct fip_map_desc {
struct fip_desc fd_desc;
__u8 fd_resvd[3];
__u8 fd_map[3];
} __attribute__((packed));
/*
* FIP_DT_NAME descriptor.
*/
struct fip_wwn_desc {
struct fip_desc fd_desc;
__u8 fd_resvd[2];
__be64 fd_wwn; /* 64-bit WWN, unaligned */
} __attribute__((packed));
/*
* FIP_DT_FAB descriptor.
*/
struct fip_fab_desc {
struct fip_desc fd_desc;
__be16 fd_vfid; /* virtual fabric ID */
__u8 fd_resvd;
__u8 fd_map[3]; /* FC-MAP value */
__be64 fd_wwn; /* fabric name, unaligned */
} __attribute__((packed));
/*
* FIP_DT_FCOE_SIZE descriptor.
*/
struct fip_size_desc {
struct fip_desc fd_desc;
__be16 fd_size;
} __attribute__((packed));
/*
* Descriptor that encapsulates an ELS or ILS frame.
* The encapsulated frame immediately follows this header, without
* SOF, EOF, or CRC.
*/
struct fip_encaps {
struct fip_desc fd_desc;
__u8 fd_resvd[2];
} __attribute__((packed));
/*
* FIP_DT_VN_ID - VN_Node Identifier descriptor.
*/
struct fip_vn_desc {
struct fip_desc fd_desc;
__u8 fd_mac[ETH_ALEN];
__u8 fd_resvd;
__u8 fd_fc_id[3];
__be64 fd_wwpn; /* port name, unaligned */
} __attribute__((packed));
/*
* FIP_DT_FKA - Advertisement keep-alive period.
*/
struct fip_fka_desc {
struct fip_desc fd_desc;
__u8 fd_resvd[2];
__be32 fd_fka_period; /* adv./keep-alive period in mS */
} __attribute__((packed));
/*
* FIP_DT_VENDOR descriptor.
*/
struct fip_vendor_desc {
struct fip_desc fd_desc;
__u8 fd_resvd[2];
__u8 fd_vendor_id[8];
} __attribute__((packed));
#endif /* _FC_FIP_H_ */

View File

@@ -0,0 +1,346 @@
/*
* 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_FS_H_
#define _FC_FS_H_
/*
* Fibre Channel Framing and Signalling definitions.
* From T11 FC-FS-2 Rev 0.90 - 9 August 2005.
*/
/*
* Frame header
*/
struct fc_frame_header {
__u8 fh_r_ctl; /* routing control */
__u8 fh_d_id[3]; /* Destination ID */
__u8 fh_cs_ctl; /* class of service control / pri */
__u8 fh_s_id[3]; /* Source ID */
__u8 fh_type; /* see enum fc_fh_type below */
__u8 fh_f_ctl[3]; /* frame control */
__u8 fh_seq_id; /* sequence ID */
__u8 fh_df_ctl; /* data field control */
__be16 fh_seq_cnt; /* sequence count */
__be16 fh_ox_id; /* originator exchange ID */
__be16 fh_rx_id; /* responder exchange ID */
__be32 fh_parm_offset; /* parameter or relative offset */
};
#define FC_FRAME_HEADER_LEN 24 /* expected length of structure */
#define FC_MAX_PAYLOAD 2112U /* max payload length in bytes */
#define FC_MIN_MAX_PAYLOAD 256U /* lower limit on max payload */
#define FC_MAX_FRAME (FC_MAX_PAYLOAD + FC_FRAME_HEADER_LEN)
#define FC_MIN_MAX_FRAME (FC_MIN_MAX_PAYLOAD + FC_FRAME_HEADER_LEN)
/*
* fh_r_ctl - Routing control definitions.
*/
/*
* FC-4 device_data.
*/
enum fc_rctl {
FC_RCTL_DD_UNCAT = 0x00, /* uncategorized information */
FC_RCTL_DD_SOL_DATA = 0x01, /* solicited data */
FC_RCTL_DD_UNSOL_CTL = 0x02, /* unsolicited control */
FC_RCTL_DD_SOL_CTL = 0x03, /* solicited control or reply */
FC_RCTL_DD_UNSOL_DATA = 0x04, /* unsolicited data */
FC_RCTL_DD_DATA_DESC = 0x05, /* data descriptor */
FC_RCTL_DD_UNSOL_CMD = 0x06, /* unsolicited command */
FC_RCTL_DD_CMD_STATUS = 0x07, /* command status */
#define FC_RCTL_ILS_REQ FC_RCTL_DD_UNSOL_CTL /* ILS request */
#define FC_RCTL_ILS_REP FC_RCTL_DD_SOL_CTL /* ILS reply */
/*
* Extended Link_Data
*/
FC_RCTL_ELS_REQ = 0x22, /* extended link services request */
FC_RCTL_ELS_REP = 0x23, /* extended link services reply */
FC_RCTL_ELS4_REQ = 0x32, /* FC-4 ELS request */
FC_RCTL_ELS4_REP = 0x33, /* FC-4 ELS reply */
/*
* Optional Extended Headers
*/
FC_RCTL_VFTH = 0x50, /* virtual fabric tagging header */
FC_RCTL_IFRH = 0x51, /* inter-fabric routing header */
FC_RCTL_ENCH = 0x52, /* encapsulation header */
/*
* Basic Link Services fh_r_ctl values.
*/
FC_RCTL_BA_NOP = 0x80, /* basic link service NOP */
FC_RCTL_BA_ABTS = 0x81, /* basic link service abort */
FC_RCTL_BA_RMC = 0x82, /* remove connection */
FC_RCTL_BA_ACC = 0x84, /* basic accept */
FC_RCTL_BA_RJT = 0x85, /* basic reject */
FC_RCTL_BA_PRMT = 0x86, /* dedicated connection preempted */
/*
* Link Control Information.
*/
FC_RCTL_ACK_1 = 0xc0, /* acknowledge_1 */
FC_RCTL_ACK_0 = 0xc1, /* acknowledge_0 */
FC_RCTL_P_RJT = 0xc2, /* port reject */
FC_RCTL_F_RJT = 0xc3, /* fabric reject */
FC_RCTL_P_BSY = 0xc4, /* port busy */
FC_RCTL_F_BSY = 0xc5, /* fabric busy to data frame */
FC_RCTL_F_BSYL = 0xc6, /* fabric busy to link control frame */
FC_RCTL_LCR = 0xc7, /* link credit reset */
FC_RCTL_END = 0xc9, /* end */
};
/* incomplete list of definitions */
/*
* R_CTL names initializer.
* Please keep this matching the above definitions.
*/
#define FC_RCTL_NAMES_INIT { \
[FC_RCTL_DD_UNCAT] = "uncat", \
[FC_RCTL_DD_SOL_DATA] = "sol data", \
[FC_RCTL_DD_UNSOL_CTL] = "unsol ctl", \
[FC_RCTL_DD_SOL_CTL] = "sol ctl/reply", \
[FC_RCTL_DD_UNSOL_DATA] = "unsol data", \
[FC_RCTL_DD_DATA_DESC] = "data desc", \
[FC_RCTL_DD_UNSOL_CMD] = "unsol cmd", \
[FC_RCTL_DD_CMD_STATUS] = "cmd status", \
[FC_RCTL_ELS_REQ] = "ELS req", \
[FC_RCTL_ELS_REP] = "ELS rep", \
[FC_RCTL_ELS4_REQ] = "FC-4 ELS req", \
[FC_RCTL_ELS4_REP] = "FC-4 ELS rep", \
[FC_RCTL_BA_NOP] = "BLS NOP", \
[FC_RCTL_BA_ABTS] = "BLS abort", \
[FC_RCTL_BA_RMC] = "BLS remove connection", \
[FC_RCTL_BA_ACC] = "BLS accept", \
[FC_RCTL_BA_RJT] = "BLS reject", \
[FC_RCTL_BA_PRMT] = "BLS dedicated connection preempted", \
[FC_RCTL_ACK_1] = "LC ACK_1", \
[FC_RCTL_ACK_0] = "LC ACK_0", \
[FC_RCTL_P_RJT] = "LC port reject", \
[FC_RCTL_F_RJT] = "LC fabric reject", \
[FC_RCTL_P_BSY] = "LC port busy", \
[FC_RCTL_F_BSY] = "LC fabric busy to data frame", \
[FC_RCTL_F_BSYL] = "LC fabric busy to link control frame",\
[FC_RCTL_LCR] = "LC link credit reset", \
[FC_RCTL_END] = "LC end", \
}
/*
* Well-known fabric addresses.
*/
enum fc_well_known_fid {
FC_FID_NONE = 0x000000, /* No destination */
FC_FID_BCAST = 0xffffff, /* broadcast */
FC_FID_FLOGI = 0xfffffe, /* fabric login */
FC_FID_FCTRL = 0xfffffd, /* fabric controller */
FC_FID_DIR_SERV = 0xfffffc, /* directory server */
FC_FID_TIME_SERV = 0xfffffb, /* time server */
FC_FID_MGMT_SERV = 0xfffffa, /* management server */
FC_FID_QOS = 0xfffff9, /* QoS Facilitator */
FC_FID_ALIASES = 0xfffff8, /* alias server (FC-PH2) */
FC_FID_SEC_KEY = 0xfffff7, /* Security key dist. server */
FC_FID_CLOCK = 0xfffff6, /* clock synch server */
FC_FID_MCAST_SERV = 0xfffff5, /* multicast server */
};
#define FC_FID_WELL_KNOWN_MAX 0xffffff /* highest well-known fabric ID */
#define FC_FID_WELL_KNOWN_BASE 0xfffff5 /* start of well-known fabric ID */
/*
* Other well-known addresses, outside the above contiguous range.
*/
#define FC_FID_DOM_MGR 0xfffc00 /* domain manager base */
/*
* Fabric ID bytes.
*/
#define FC_FID_DOMAIN 0
#define FC_FID_PORT 1
#define FC_FID_LINK 2
/*
* fh_type codes
*/
enum fc_fh_type {
FC_TYPE_BLS = 0x00, /* basic link service */
FC_TYPE_ELS = 0x01, /* extended link service */
FC_TYPE_IP = 0x05, /* IP over FC, RFC 4338 */
FC_TYPE_FCP = 0x08, /* SCSI FCP */
FC_TYPE_CT = 0x20, /* Fibre Channel Services (FC-CT) */
FC_TYPE_ILS = 0x22, /* internal link service */
};
/*
* FC_TYPE names initializer.
* Please keep this matching the above definitions.
*/
#define FC_TYPE_NAMES_INIT { \
[FC_TYPE_BLS] = "BLS", \
[FC_TYPE_ELS] = "ELS", \
[FC_TYPE_IP] = "IP", \
[FC_TYPE_FCP] = "FCP", \
[FC_TYPE_CT] = "CT", \
[FC_TYPE_ILS] = "ILS", \
}
/*
* Exchange IDs.
*/
#define FC_XID_UNKNOWN 0xffff /* unknown exchange ID */
#define FC_XID_MIN 0x0 /* supported min exchange ID */
#define FC_XID_MAX 0xfffe /* supported max exchange ID */
/*
* fh_f_ctl - Frame control flags.
*/
#define FC_FC_EX_CTX (1 << 23) /* sent by responder to exchange */
#define FC_FC_SEQ_CTX (1 << 22) /* sent by responder to sequence */
#define FC_FC_FIRST_SEQ (1 << 21) /* first sequence of this exchange */
#define FC_FC_LAST_SEQ (1 << 20) /* last sequence of this exchange */
#define FC_FC_END_SEQ (1 << 19) /* last frame of sequence */
#define FC_FC_END_CONN (1 << 18) /* end of class 1 connection pending */
#define FC_FC_RES_B17 (1 << 17) /* reserved */
#define FC_FC_SEQ_INIT (1 << 16) /* transfer of sequence initiative */
#define FC_FC_X_ID_REASS (1 << 15) /* exchange ID has been changed */
#define FC_FC_X_ID_INVAL (1 << 14) /* exchange ID invalidated */
#define FC_FC_ACK_1 (1 << 12) /* 13:12 = 1: ACK_1 expected */
#define FC_FC_ACK_N (2 << 12) /* 13:12 = 2: ACK_N expected */
#define FC_FC_ACK_0 (3 << 12) /* 13:12 = 3: ACK_0 expected */
#define FC_FC_RES_B11 (1 << 11) /* reserved */
#define FC_FC_RES_B10 (1 << 10) /* reserved */
#define FC_FC_RETX_SEQ (1 << 9) /* retransmitted sequence */
#define FC_FC_UNI_TX (1 << 8) /* unidirectional transmit (class 1) */
#define FC_FC_CONT_SEQ(i) ((i) << 6)
#define FC_FC_ABT_SEQ(i) ((i) << 4)
#define FC_FC_REL_OFF (1 << 3) /* parameter is relative offset */
#define FC_FC_RES2 (1 << 2) /* reserved */
#define FC_FC_FILL(i) ((i) & 3) /* 1:0: bytes of trailing fill */
/*
* BA_ACC payload.
*/
struct fc_ba_acc {
__u8 ba_seq_id_val; /* SEQ_ID validity */
#define FC_BA_SEQ_ID_VAL 0x80
__u8 ba_seq_id; /* SEQ_ID of seq last deliverable */
__u8 ba_resvd[2]; /* reserved */
__be16 ba_ox_id; /* OX_ID for aborted seq or exch */
__be16 ba_rx_id; /* RX_ID for aborted seq or exch */
__be16 ba_low_seq_cnt; /* low SEQ_CNT of aborted seq */
__be16 ba_high_seq_cnt; /* high SEQ_CNT of aborted seq */
};
/*
* BA_RJT: Basic Reject payload.
*/
struct fc_ba_rjt {
__u8 br_resvd; /* reserved */
__u8 br_reason; /* reason code */
__u8 br_explan; /* reason explanation */
__u8 br_vendor; /* vendor unique code */
};
/*
* BA_RJT reason codes.
* From FS-2.
*/
enum fc_ba_rjt_reason {
FC_BA_RJT_NONE = 0, /* in software this means no reject */
FC_BA_RJT_INVL_CMD = 0x01, /* invalid command code */
FC_BA_RJT_LOG_ERR = 0x03, /* logical error */
FC_BA_RJT_LOG_BUSY = 0x05, /* logical busy */
FC_BA_RJT_PROTO_ERR = 0x07, /* protocol error */
FC_BA_RJT_UNABLE = 0x09, /* unable to perform request */
FC_BA_RJT_VENDOR = 0xff, /* vendor-specific (see br_vendor) */
};
/*
* BA_RJT reason code explanations.
*/
enum fc_ba_rjt_explan {
FC_BA_RJT_EXP_NONE = 0x00, /* no additional expanation */
FC_BA_RJT_INV_XID = 0x03, /* invalid OX_ID-RX_ID combination */
FC_BA_RJT_ABT = 0x05, /* sequence aborted, no seq info */
};
/*
* P_RJT or F_RJT: Port Reject or Fabric Reject parameter field.
*/
struct fc_pf_rjt {
__u8 rj_action; /* reserved */
__u8 rj_reason; /* reason code */
__u8 rj_resvd; /* reserved */
__u8 rj_vendor; /* vendor unique code */
};
/*
* P_RJT and F_RJT reject reason codes.
*/
enum fc_pf_rjt_reason {
FC_RJT_NONE = 0, /* non-reject (reserved by standard) */
FC_RJT_INVL_DID = 0x01, /* invalid destination ID */
FC_RJT_INVL_SID = 0x02, /* invalid source ID */
FC_RJT_P_UNAV_T = 0x03, /* port unavailable, temporary */
FC_RJT_P_UNAV = 0x04, /* port unavailable, permanent */
FC_RJT_CLS_UNSUP = 0x05, /* class not supported */
FC_RJT_DEL_USAGE = 0x06, /* delimiter usage error */
FC_RJT_TYPE_UNSUP = 0x07, /* type not supported */
FC_RJT_LINK_CTL = 0x08, /* invalid link control */
FC_RJT_R_CTL = 0x09, /* invalid R_CTL field */
FC_RJT_F_CTL = 0x0a, /* invalid F_CTL field */
FC_RJT_OX_ID = 0x0b, /* invalid originator exchange ID */
FC_RJT_RX_ID = 0x0c, /* invalid responder exchange ID */
FC_RJT_SEQ_ID = 0x0d, /* invalid sequence ID */
FC_RJT_DF_CTL = 0x0e, /* invalid DF_CTL field */
FC_RJT_SEQ_CNT = 0x0f, /* invalid SEQ_CNT field */
FC_RJT_PARAM = 0x10, /* invalid parameter field */
FC_RJT_EXCH_ERR = 0x11, /* exchange error */
FC_RJT_PROTO = 0x12, /* protocol error */
FC_RJT_LEN = 0x13, /* incorrect length */
FC_RJT_UNEXP_ACK = 0x14, /* unexpected ACK */
FC_RJT_FAB_CLASS = 0x15, /* class unsupported by fabric entity */
FC_RJT_LOGI_REQ = 0x16, /* login required */
FC_RJT_SEQ_XS = 0x17, /* excessive sequences attempted */
FC_RJT_EXCH_EST = 0x18, /* unable to establish exchange */
FC_RJT_FAB_UNAV = 0x1a, /* fabric unavailable */
FC_RJT_VC_ID = 0x1b, /* invalid VC_ID (class 4) */
FC_RJT_CS_CTL = 0x1c, /* invalid CS_CTL field */
FC_RJT_INSUF_RES = 0x1d, /* insuff. resources for VC (Class 4) */
FC_RJT_INVL_CLS = 0x1f, /* invalid class of service */
FC_RJT_PREEMT_RJT = 0x20, /* preemption request rejected */
FC_RJT_PREEMT_DIS = 0x21, /* preemption not enabled */
FC_RJT_MCAST_ERR = 0x22, /* multicast error */
FC_RJT_MCAST_ET = 0x23, /* multicast error terminate */
FC_RJT_PRLI_REQ = 0x24, /* process login required */
FC_RJT_INVL_ATT = 0x25, /* invalid attachment */
FC_RJT_VENDOR = 0xff, /* vendor specific reject */
};
/* default timeout values */
#define FC_DEF_E_D_TOV 2000UL
#define FC_DEF_R_A_TOV 10000UL
#endif /* _FC_FS_H_ */

View File

@@ -0,0 +1,94 @@
/*
* 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_GS_H_
#define _FC_GS_H_
/*
* Fibre Channel Services - Common Transport.
* From T11.org FC-GS-2 Rev 5.3 November 1998.
*/
struct fc_ct_hdr {
__u8 ct_rev; /* revision */
__u8 ct_in_id[3]; /* N_Port ID of original requestor */
__u8 ct_fs_type; /* type of fibre channel service */
__u8 ct_fs_subtype; /* subtype */
__u8 ct_options;
__u8 _ct_resvd1;
__be16 ct_cmd; /* command / response code */
__be16 ct_mr_size; /* maximum / residual size */
__u8 _ct_resvd2;
__u8 ct_reason; /* reject reason */
__u8 ct_explan; /* reason code explanation */
__u8 ct_vendor; /* vendor unique data */
};
#define FC_CT_HDR_LEN 16 /* expected sizeof (struct fc_ct_hdr) */
enum fc_ct_rev {
FC_CT_REV = 1 /* common transport revision */
};
/*
* ct_fs_type values.
*/
enum fc_ct_fs_type {
FC_FST_ALIAS = 0xf8, /* alias service */
FC_FST_MGMT = 0xfa, /* management service */
FC_FST_TIME = 0xfb, /* time service */
FC_FST_DIR = 0xfc, /* directory service */
};
/*
* ct_cmd: Command / response codes
*/
enum fc_ct_cmd {
FC_FS_RJT = 0x8001, /* reject */
FC_FS_ACC = 0x8002, /* accept */
};
/*
* FS_RJT reason codes.
*/
enum fc_ct_reason {
FC_FS_RJT_CMD = 0x01, /* invalid command code */
FC_FS_RJT_VER = 0x02, /* invalid version level */
FC_FS_RJT_LOG = 0x03, /* logical error */
FC_FS_RJT_IUSIZ = 0x04, /* invalid IU size */
FC_FS_RJT_BSY = 0x05, /* logical busy */
FC_FS_RJT_PROTO = 0x07, /* protocol error */
FC_FS_RJT_UNABL = 0x09, /* unable to perform command request */
FC_FS_RJT_UNSUP = 0x0b, /* command not supported */
};
/*
* FS_RJT reason code explanations.
*/
enum fc_ct_explan {
FC_FS_EXP_NONE = 0x00, /* no additional explanation */
FC_FS_EXP_PID = 0x01, /* port ID not registered */
FC_FS_EXP_PNAM = 0x02, /* port name not registered */
FC_FS_EXP_NNAM = 0x03, /* node name not registered */
FC_FS_EXP_COS = 0x04, /* class of service not registered */
FC_FS_EXP_FTNR = 0x07, /* FC-4 types not registered */
/* definitions not complete */
};
#endif /* _FC_GS_H_ */

View File

@@ -0,0 +1,159 @@
/*
* 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_NS_H_
#define _FC_NS_H_
/*
* Fibre Channel Services - Name Service (dNS)
* From T11.org FC-GS-2 Rev 5.3 November 1998.
*/
/*
* Common-transport sub-type for Name Server.
*/
#define FC_NS_SUBTYPE 2 /* fs_ct_hdr.ct_fs_subtype */
/*
* Name server Requests.
* Note: this is an incomplete list, some unused requests are omitted.
*/
enum fc_ns_req {
FC_NS_GA_NXT = 0x0100, /* get all next */
FC_NS_GI_A = 0x0101, /* get identifiers - scope */
FC_NS_GPN_ID = 0x0112, /* get port name by ID */
FC_NS_GNN_ID = 0x0113, /* get node name by ID */
FC_NS_GID_PN = 0x0121, /* get ID for port name */
FC_NS_GID_NN = 0x0131, /* get IDs for node name */
FC_NS_GID_FT = 0x0171, /* get IDs by FC4 type */
FC_NS_GPN_FT = 0x0172, /* get port names by FC4 type */
FC_NS_GID_PT = 0x01a1, /* get IDs by port type */
FC_NS_RFT_ID = 0x0217, /* reg FC4 type for ID */
FC_NS_RPN_ID = 0x0212, /* reg port name for ID */
FC_NS_RNN_ID = 0x0213, /* reg node name for ID */
};
/*
* Port type values.
*/
enum fc_ns_pt {
FC_NS_UNID_PORT = 0x00, /* unidentified */
FC_NS_N_PORT = 0x01, /* N port */
FC_NS_NL_PORT = 0x02, /* NL port */
FC_NS_FNL_PORT = 0x03, /* F/NL port */
FC_NS_NX_PORT = 0x7f, /* Nx port */
FC_NS_F_PORT = 0x81, /* F port */
FC_NS_FL_PORT = 0x82, /* FL port */
FC_NS_E_PORT = 0x84, /* E port */
FC_NS_B_PORT = 0x85, /* B port */
};
/*
* Port type object.
*/
struct fc_ns_pt_obj {
__u8 pt_type;
};
/*
* Port ID object
*/
struct fc_ns_fid {
__u8 fp_flags; /* flags for responses only */
__u8 fp_fid[3];
};
/*
* fp_flags in port ID object, for responses only.
*/
#define FC_NS_FID_LAST 0x80 /* last object */
/*
* FC4-types object.
*/
#define FC_NS_TYPES 256 /* number of possible FC-4 types */
#define FC_NS_BPW 32 /* bits per word in bitmap */
struct fc_ns_fts {
__be32 ff_type_map[FC_NS_TYPES / FC_NS_BPW]; /* bitmap of FC-4 types */
};
/*
* GID_PT request.
*/
struct fc_ns_gid_pt {
__u8 fn_pt_type;
__u8 fn_domain_id_scope;
__u8 fn_area_id_scope;
__u8 fn_resvd;
};
/*
* GID_FT or GPN_FT request.
*/
struct fc_ns_gid_ft {
__u8 fn_resvd;
__u8 fn_domain_id_scope;
__u8 fn_area_id_scope;
__u8 fn_fc4_type;
};
/*
* GPN_FT response.
*/
struct fc_gpn_ft_resp {
__u8 fp_flags; /* see fp_flags definitions above */
__u8 fp_fid[3]; /* port ID */
__be32 fp_resvd;
__be64 fp_wwpn; /* port name */
};
/*
* GID_PN request
*/
struct fc_ns_gid_pn {
__be64 fn_wwpn; /* port name */
};
/*
* GID_PN response
*/
struct fc_gid_pn_resp {
__u8 fp_resvd;
__u8 fp_fid[3]; /* port ID */
};
/*
* RFT_ID request - register FC-4 types for ID.
*/
struct fc_ns_rft_id {
struct fc_ns_fid fr_fid; /* port ID object */
struct fc_ns_fts fr_fts; /* FC-4 types object */
};
/*
* RPN_ID request - register port name for ID.
* RNN_ID request - register node name for ID.
*/
struct fc_ns_rn_id {
struct fc_ns_fid fr_fid; /* port ID object */
__be64 fr_wwn; /* node name or port name */
} __attribute__((__packed__));
#endif /* _FC_NS_H_ */

View File

@@ -0,0 +1,327 @@
/*
* Copyright(c) 2008 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_ENCODE_H_
#define _FC_ENCODE_H_
#include <asm/unaligned.h>
struct fc_ns_rft {
struct fc_ns_fid fid; /* port ID object */
struct fc_ns_fts fts; /* FC4-types object */
};
struct fc_ct_req {
struct fc_ct_hdr hdr;
union {
struct fc_ns_gid_ft gid;
struct fc_ns_rn_id rn;
struct fc_ns_rft rft;
struct fc_ns_fid fid;
} payload;
};
/**
* fill FC header fields in specified fc_frame
*/
static inline void fc_fill_fc_hdr(struct fc_frame *fp, enum fc_rctl r_ctl,
u32 did, u32 sid, enum fc_fh_type type,
u32 f_ctl, u32 parm_offset)
{
struct fc_frame_header *fh;
fh = fc_frame_header_get(fp);
WARN_ON(r_ctl == 0);
fh->fh_r_ctl = r_ctl;
hton24(fh->fh_d_id, did);
hton24(fh->fh_s_id, sid);
fh->fh_type = type;
hton24(fh->fh_f_ctl, f_ctl);
fh->fh_cs_ctl = 0;
fh->fh_df_ctl = 0;
fh->fh_parm_offset = htonl(parm_offset);
}
/**
* fc_adisc_fill() - Fill in adisc request frame
* @lport: local port.
* @fp: fc frame where payload will be placed.
*/
static inline void fc_adisc_fill(struct fc_lport *lport, struct fc_frame *fp)
{
struct fc_els_adisc *adisc;
adisc = fc_frame_payload_get(fp, sizeof(*adisc));
memset(adisc, 0, sizeof(*adisc));
adisc->adisc_cmd = ELS_ADISC;
put_unaligned_be64(lport->wwpn, &adisc->adisc_wwpn);
put_unaligned_be64(lport->wwnn, &adisc->adisc_wwnn);
hton24(adisc->adisc_port_id, fc_host_port_id(lport->host));
}
/**
* fc_ct_hdr_fill- fills ct header and reset ct payload
* returns pointer to ct request.
*/
static inline struct fc_ct_req *fc_ct_hdr_fill(const struct fc_frame *fp,
unsigned int op, size_t req_size)
{
struct fc_ct_req *ct;
size_t ct_plen;
ct_plen = sizeof(struct fc_ct_hdr) + req_size;
ct = fc_frame_payload_get(fp, ct_plen);
memset(ct, 0, ct_plen);
ct->hdr.ct_rev = FC_CT_REV;
ct->hdr.ct_fs_type = FC_FST_DIR;
ct->hdr.ct_fs_subtype = FC_NS_SUBTYPE;
ct->hdr.ct_cmd = htons((u16) op);
return ct;
}
/**
* fc_ct_fill() - Fill in a name service request frame
* @lport: local port.
* @fc_id: FC_ID of non-destination rport for GPN_ID and similar inquiries.
* @fp: frame to contain payload.
* @op: CT opcode.
* @r_ctl: pointer to FC header R_CTL.
* @fh_type: pointer to FC-4 type.
*/
static inline int fc_ct_fill(struct fc_lport *lport,
u32 fc_id, struct fc_frame *fp,
unsigned int op, enum fc_rctl *r_ctl,
enum fc_fh_type *fh_type)
{
struct fc_ct_req *ct;
switch (op) {
case FC_NS_GPN_FT:
ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_gid_ft));
ct->payload.gid.fn_fc4_type = FC_TYPE_FCP;
break;
case FC_NS_GPN_ID:
ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_fid));
hton24(ct->payload.fid.fp_fid, fc_id);
break;
case FC_NS_RFT_ID:
ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rft));
hton24(ct->payload.rft.fid.fp_fid,
fc_host_port_id(lport->host));
ct->payload.rft.fts = lport->fcts;
break;
case FC_NS_RPN_ID:
ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rn_id));
hton24(ct->payload.rn.fr_fid.fp_fid,
fc_host_port_id(lport->host));
ct->payload.rft.fts = lport->fcts;
put_unaligned_be64(lport->wwpn, &ct->payload.rn.fr_wwn);
break;
default:
return -EINVAL;
}
*r_ctl = FC_RCTL_DD_UNSOL_CTL;
*fh_type = FC_TYPE_CT;
return 0;
}
/**
* fc_plogi_fill - Fill in plogi request frame
*/
static inline void fc_plogi_fill(struct fc_lport *lport, struct fc_frame *fp,
unsigned int op)
{
struct fc_els_flogi *plogi;
struct fc_els_csp *csp;
struct fc_els_cssp *cp;
plogi = fc_frame_payload_get(fp, sizeof(*plogi));
memset(plogi, 0, sizeof(*plogi));
plogi->fl_cmd = (u8) op;
put_unaligned_be64(lport->wwpn, &plogi->fl_wwpn);
put_unaligned_be64(lport->wwnn, &plogi->fl_wwnn);
csp = &plogi->fl_csp;
csp->sp_hi_ver = 0x20;
csp->sp_lo_ver = 0x20;
csp->sp_bb_cred = htons(10); /* this gets set by gateway */
csp->sp_bb_data = htons((u16) lport->mfs);
cp = &plogi->fl_cssp[3 - 1]; /* class 3 parameters */
cp->cp_class = htons(FC_CPC_VALID | FC_CPC_SEQ);
csp->sp_features = htons(FC_SP_FT_CIRO);
csp->sp_tot_seq = htons(255); /* seq. we accept */
csp->sp_rel_off = htons(0x1f);
csp->sp_e_d_tov = htonl(lport->e_d_tov);
cp->cp_rdfs = htons((u16) lport->mfs);
cp->cp_con_seq = htons(255);
cp->cp_open_seq = 1;
}
/**
* fc_flogi_fill - Fill in a flogi request frame.
*/
static inline void fc_flogi_fill(struct fc_lport *lport, struct fc_frame *fp)
{
struct fc_els_csp *sp;
struct fc_els_cssp *cp;
struct fc_els_flogi *flogi;
flogi = fc_frame_payload_get(fp, sizeof(*flogi));
memset(flogi, 0, sizeof(*flogi));
flogi->fl_cmd = (u8) ELS_FLOGI;
put_unaligned_be64(lport->wwpn, &flogi->fl_wwpn);
put_unaligned_be64(lport->wwnn, &flogi->fl_wwnn);
sp = &flogi->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 = &flogi->fl_cssp[3 - 1]; /* class 3 parameters */
cp->cp_class = htons(FC_CPC_VALID | FC_CPC_SEQ);
}
/**
* fc_logo_fill - Fill in a logo request frame.
*/
static inline void fc_logo_fill(struct fc_lport *lport, struct fc_frame *fp)
{
struct fc_els_logo *logo;
logo = fc_frame_payload_get(fp, sizeof(*logo));
memset(logo, 0, sizeof(*logo));
logo->fl_cmd = ELS_LOGO;
hton24(logo->fl_n_port_id, fc_host_port_id(lport->host));
logo->fl_n_port_wwn = htonll(lport->wwpn);
}
/**
* fc_rtv_fill - Fill in RTV (read timeout value) request frame.
*/
static inline void fc_rtv_fill(struct fc_lport *lport, struct fc_frame *fp)
{
struct fc_els_rtv *rtv;
rtv = fc_frame_payload_get(fp, sizeof(*rtv));
memset(rtv, 0, sizeof(*rtv));
rtv->rtv_cmd = ELS_RTV;
}
/**
* fc_rec_fill - Fill in rec request frame
*/
static inline void fc_rec_fill(struct fc_lport *lport, struct fc_frame *fp)
{
struct fc_els_rec *rec;
struct fc_exch *ep = fc_seq_exch(fr_seq(fp));
rec = fc_frame_payload_get(fp, sizeof(*rec));
memset(rec, 0, sizeof(*rec));
rec->rec_cmd = ELS_REC;
hton24(rec->rec_s_id, fc_host_port_id(lport->host));
rec->rec_ox_id = htons(ep->oxid);
rec->rec_rx_id = htons(ep->rxid);
}
/**
* fc_prli_fill - Fill in prli request frame
*/
static inline void fc_prli_fill(struct fc_lport *lport, struct fc_frame *fp)
{
struct {
struct fc_els_prli prli;
struct fc_els_spp spp;
} *pp;
pp = fc_frame_payload_get(fp, sizeof(*pp));
memset(pp, 0, sizeof(*pp));
pp->prli.prli_cmd = ELS_PRLI;
pp->prli.prli_spp_len = sizeof(struct fc_els_spp);
pp->prli.prli_len = htons(sizeof(*pp));
pp->spp.spp_type = FC_TYPE_FCP;
pp->spp.spp_flags = FC_SPP_EST_IMG_PAIR;
pp->spp.spp_params = htonl(lport->service_params);
}
/**
* fc_scr_fill - Fill in a scr request frame.
*/
static inline void fc_scr_fill(struct fc_lport *lport, struct fc_frame *fp)
{
struct fc_els_scr *scr;
scr = fc_frame_payload_get(fp, sizeof(*scr));
memset(scr, 0, sizeof(*scr));
scr->scr_cmd = ELS_SCR;
scr->scr_reg_func = ELS_SCRF_FULL;
}
/**
* fc_els_fill - Fill in an ELS request frame
*/
static inline int fc_els_fill(struct fc_lport *lport,
u32 did,
struct fc_frame *fp, unsigned int op,
enum fc_rctl *r_ctl, enum fc_fh_type *fh_type)
{
switch (op) {
case ELS_ADISC:
fc_adisc_fill(lport, fp);
break;
case ELS_PLOGI:
fc_plogi_fill(lport, fp, ELS_PLOGI);
break;
case ELS_FLOGI:
fc_flogi_fill(lport, fp);
break;
case ELS_LOGO:
fc_logo_fill(lport, fp);
break;
case ELS_RTV:
fc_rtv_fill(lport, fp);
break;
case ELS_REC:
fc_rec_fill(lport, fp);
break;
case ELS_PRLI:
fc_prli_fill(lport, fp);
break;
case ELS_SCR:
fc_scr_fill(lport, fp);
break;
default:
return -EINVAL;
}
*r_ctl = FC_RCTL_ELS_REQ;
*fh_type = FC_TYPE_ELS;
return 0;
}
#endif /* _FC_ENCODE_H_ */

View File

@@ -0,0 +1,223 @@
/*
* 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_FRAME_H_
#define _FC_FRAME_H_
#include <linux/scatterlist.h>
#include <linux/skbuff.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/fc/fc_fs.h>
#include <scsi/fc/fc_fcp.h>
#include <scsi/fc/fc_encaps.h>
/*
* The fc_frame interface is used to pass frame data between functions.
* The frame includes the data buffer, length, and SOF / EOF delimiter types.
* A pointer to the port structure of the receiving port is also includeded.
*/
#define FC_FRAME_HEADROOM 32 /* headroom for VLAN + FCoE headers */
#define FC_FRAME_TAILROOM 8 /* trailer space for FCoE */
/* Max number of skb frags allowed, reserving one for fcoe_crc_eof page */
#define FC_FRAME_SG_LEN (MAX_SKB_FRAGS - 1)
#define fp_skb(fp) (&((fp)->skb))
#define fr_hdr(fp) ((fp)->skb.data)
#define fr_len(fp) ((fp)->skb.len)
#define fr_cb(fp) ((struct fcoe_rcv_info *)&((fp)->skb.cb[0]))
#define fr_dev(fp) (fr_cb(fp)->fr_dev)
#define fr_seq(fp) (fr_cb(fp)->fr_seq)
#define fr_sof(fp) (fr_cb(fp)->fr_sof)
#define fr_eof(fp) (fr_cb(fp)->fr_eof)
#define fr_flags(fp) (fr_cb(fp)->fr_flags)
#define fr_max_payload(fp) (fr_cb(fp)->fr_max_payload)
#define fr_fsp(fp) (fr_cb(fp)->fr_fsp)
#define fr_crc(fp) (fr_cb(fp)->fr_crc)
struct fc_frame {
struct sk_buff skb;
};
struct fcoe_rcv_info {
struct packet_type *ptype;
struct fc_lport *fr_dev; /* transport layer private pointer */
struct fc_seq *fr_seq; /* for use with exchange manager */
struct fc_fcp_pkt *fr_fsp; /* for the corresponding fcp I/O */
u32 fr_crc;
u16 fr_max_payload; /* max FC payload */
enum fc_sof fr_sof; /* start of frame delimiter */
enum fc_eof fr_eof; /* end of frame delimiter */
u8 fr_flags; /* flags - see below */
};
/*
* Get fc_frame pointer for an skb that's already been imported.
*/
static inline struct fcoe_rcv_info *fcoe_dev_from_skb(const struct sk_buff *skb)
{
BUILD_BUG_ON(sizeof(struct fcoe_rcv_info) > sizeof(skb->cb));
return (struct fcoe_rcv_info *) skb->cb;
}
/*
* fr_flags.
*/
#define FCPHF_CRC_UNCHECKED 0x01 /* CRC not computed, still appended */
/*
* Initialize a frame.
* We don't do a complete memset here for performance reasons.
* The caller must set fr_free, fr_hdr, fr_len, fr_sof, and fr_eof eventually.
*/
static inline void fc_frame_init(struct fc_frame *fp)
{
fr_dev(fp) = NULL;
fr_seq(fp) = NULL;
fr_flags(fp) = 0;
}
struct fc_frame *fc_frame_alloc_fill(struct fc_lport *, size_t payload_len);
struct fc_frame *__fc_frame_alloc(size_t payload_len);
/*
* Get frame for sending via port.
*/
static inline struct fc_frame *_fc_frame_alloc(struct fc_lport *dev,
size_t payload_len)
{
return __fc_frame_alloc(payload_len);
}
/*
* Allocate fc_frame structure and buffer. Set the initial length to
* payload_size + sizeof (struct fc_frame_header).
*/
static inline struct fc_frame *fc_frame_alloc(struct fc_lport *dev, size_t len)
{
struct fc_frame *fp;
/*
* Note: Since len will often be a constant multiple of 4,
* this check will usually be evaluated and eliminated at compile time.
*/
if ((len % 4) != 0)
fp = fc_frame_alloc_fill(dev, len);
else
fp = _fc_frame_alloc(dev, len);
return fp;
}
/*
* Free the fc_frame structure and buffer.
*/
static inline void fc_frame_free(struct fc_frame *fp)
{
kfree_skb(fp_skb(fp));
}
static inline int fc_frame_is_linear(struct fc_frame *fp)
{
return !skb_is_nonlinear(fp_skb(fp));
}
/*
* Get frame header from message in fc_frame structure.
* This hides a cast and provides a place to add some checking.
*/
static inline
struct fc_frame_header *fc_frame_header_get(const struct fc_frame *fp)
{
WARN_ON(fr_len(fp) < sizeof(struct fc_frame_header));
return (struct fc_frame_header *) fr_hdr(fp);
}
/*
* Get frame payload from message in fc_frame structure.
* This hides a cast and provides a place to add some checking.
* The len parameter is the minimum length for the payload portion.
* Returns NULL if the frame is too short.
*
* This assumes the interesting part of the payload is in the first part
* of the buffer for received data. This may not be appropriate to use for
* buffers being transmitted.
*/
static inline void *fc_frame_payload_get(const struct fc_frame *fp,
size_t len)
{
void *pp = NULL;
if (fr_len(fp) >= sizeof(struct fc_frame_header) + len)
pp = fc_frame_header_get(fp) + 1;
return pp;
}
/*
* Get frame payload opcode (first byte) from message in fc_frame structure.
* This hides a cast and provides a place to add some checking. Return 0
* if the frame has no payload.
*/
static inline u8 fc_frame_payload_op(const struct fc_frame *fp)
{
u8 *cp;
cp = fc_frame_payload_get(fp, sizeof(u8));
if (!cp)
return 0;
return *cp;
}
/*
* Get FC class from frame.
*/
static inline enum fc_class fc_frame_class(const struct fc_frame *fp)
{
return fc_sof_class(fr_sof(fp));
}
/*
* Check the CRC in a frame.
* The CRC immediately follows the last data item *AFTER* the length.
* The return value is zero if the CRC matches.
*/
u32 fc_frame_crc_check(struct fc_frame *);
static inline u8 fc_frame_rctl(const struct fc_frame *fp)
{
return fc_frame_header_get(fp)->fh_r_ctl;
}
static inline bool fc_frame_is_cmd(const struct fc_frame *fp)
{
return fc_frame_rctl(fp) == FC_RCTL_DD_UNSOL_CMD;
}
/*
* Check for leaks.
* Print the frame header of any currently allocated frame, assuming there
* should be none at this point.
*/
void fc_frame_leak_check(void);
#endif /* _FC_FRAME_H_ */

View File

@@ -0,0 +1,449 @@
/*
* iSCSI User/Kernel Shares (Defines, Constants, Protocol definitions, etc)
*
* Copyright (C) 2005 Dmitry Yusupov
* Copyright (C) 2005 Alex Aizman
* maintained by open-iscsi@googlegroups.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that 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.
*
* See the file COPYING included with this distribution for more details.
*/
#ifndef ISCSI_IF_H
#define ISCSI_IF_H
#include <scsi/iscsi_proto.h>
#include <linux/in.h>
#include <linux/in6.h>
#define ISCSI_NL_GRP_ISCSID 1
#define ISCSI_NL_GRP_UIP 2
#define UEVENT_BASE 10
#define KEVENT_BASE 100
#define ISCSI_ERR_BASE 1000
enum iscsi_uevent_e {
ISCSI_UEVENT_UNKNOWN = 0,
/* down events */
ISCSI_UEVENT_CREATE_SESSION = UEVENT_BASE + 1,
ISCSI_UEVENT_DESTROY_SESSION = UEVENT_BASE + 2,
ISCSI_UEVENT_CREATE_CONN = UEVENT_BASE + 3,
ISCSI_UEVENT_DESTROY_CONN = UEVENT_BASE + 4,
ISCSI_UEVENT_BIND_CONN = UEVENT_BASE + 5,
ISCSI_UEVENT_SET_PARAM = UEVENT_BASE + 6,
ISCSI_UEVENT_START_CONN = UEVENT_BASE + 7,
ISCSI_UEVENT_STOP_CONN = UEVENT_BASE + 8,
ISCSI_UEVENT_SEND_PDU = UEVENT_BASE + 9,
ISCSI_UEVENT_GET_STATS = UEVENT_BASE + 10,
ISCSI_UEVENT_GET_PARAM = UEVENT_BASE + 11,
ISCSI_UEVENT_TRANSPORT_EP_CONNECT = UEVENT_BASE + 12,
ISCSI_UEVENT_TRANSPORT_EP_POLL = UEVENT_BASE + 13,
ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT = UEVENT_BASE + 14,
ISCSI_UEVENT_TGT_DSCVR = UEVENT_BASE + 15,
ISCSI_UEVENT_SET_HOST_PARAM = UEVENT_BASE + 16,
ISCSI_UEVENT_UNBIND_SESSION = UEVENT_BASE + 17,
ISCSI_UEVENT_CREATE_BOUND_SESSION = UEVENT_BASE + 18,
ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST = UEVENT_BASE + 19,
ISCSI_UEVENT_PATH_UPDATE = UEVENT_BASE + 20,
/* up events */
ISCSI_KEVENT_RECV_PDU = KEVENT_BASE + 1,
ISCSI_KEVENT_CONN_ERROR = KEVENT_BASE + 2,
ISCSI_KEVENT_IF_ERROR = KEVENT_BASE + 3,
ISCSI_KEVENT_DESTROY_SESSION = KEVENT_BASE + 4,
ISCSI_KEVENT_UNBIND_SESSION = KEVENT_BASE + 5,
ISCSI_KEVENT_CREATE_SESSION = KEVENT_BASE + 6,
ISCSI_KEVENT_PATH_REQ = KEVENT_BASE + 7,
ISCSI_KEVENT_IF_DOWN = KEVENT_BASE + 8,
};
enum iscsi_tgt_dscvr {
ISCSI_TGT_DSCVR_SEND_TARGETS = 1,
ISCSI_TGT_DSCVR_ISNS = 2,
ISCSI_TGT_DSCVR_SLP = 3,
};
struct iscsi_uevent {
uint32_t type; /* k/u events type */
uint32_t iferror; /* carries interface or resource errors */
uint64_t transport_handle;
union {
/* messages u -> k */
struct msg_create_session {
uint32_t initial_cmdsn;
uint16_t cmds_max;
uint16_t queue_depth;
} c_session;
struct msg_create_bound_session {
uint64_t ep_handle;
uint32_t initial_cmdsn;
uint16_t cmds_max;
uint16_t queue_depth;
} c_bound_session;
struct msg_destroy_session {
uint32_t sid;
} d_session;
struct msg_create_conn {
uint32_t sid;
uint32_t cid;
} c_conn;
struct msg_bind_conn {
uint32_t sid;
uint32_t cid;
uint64_t transport_eph;
uint32_t is_leading;
} b_conn;
struct msg_destroy_conn {
uint32_t sid;
uint32_t cid;
} d_conn;
struct msg_send_pdu {
uint32_t sid;
uint32_t cid;
uint32_t hdr_size;
uint32_t data_size;
} send_pdu;
struct msg_set_param {
uint32_t sid;
uint32_t cid;
uint32_t param; /* enum iscsi_param */
uint32_t len;
} set_param;
struct msg_start_conn {
uint32_t sid;
uint32_t cid;
} start_conn;
struct msg_stop_conn {
uint32_t sid;
uint32_t cid;
uint64_t conn_handle;
uint32_t flag;
} stop_conn;
struct msg_get_stats {
uint32_t sid;
uint32_t cid;
} get_stats;
struct msg_transport_connect {
uint32_t non_blocking;
} ep_connect;
struct msg_transport_connect_through_host {
uint32_t host_no;
uint32_t non_blocking;
} ep_connect_through_host;
struct msg_transport_poll {
uint64_t ep_handle;
uint32_t timeout_ms;
} ep_poll;
struct msg_transport_disconnect {
uint64_t ep_handle;
} ep_disconnect;
struct msg_tgt_dscvr {
enum iscsi_tgt_dscvr type;
uint32_t host_no;
/*
* enable = 1 to establish a new connection
* with the server. enable = 0 to disconnect
* from the server. Used primarily to switch
* from one iSNS server to another.
*/
uint32_t enable;
} tgt_dscvr;
struct msg_set_host_param {
uint32_t host_no;
uint32_t param; /* enum iscsi_host_param */
uint32_t len;
} set_host_param;
struct msg_set_path {
uint32_t host_no;
} set_path;
} u;
union {
/* messages k -> u */
int retcode;
struct msg_create_session_ret {
uint32_t sid;
uint32_t host_no;
} c_session_ret;
struct msg_create_conn_ret {
uint32_t sid;
uint32_t cid;
} c_conn_ret;
struct msg_unbind_session {
uint32_t sid;
uint32_t host_no;
} unbind_session;
struct msg_recv_req {
uint32_t sid;
uint32_t cid;
uint64_t recv_handle;
} recv_req;
struct msg_conn_error {
uint32_t sid;
uint32_t cid;
uint32_t error; /* enum iscsi_err */
} connerror;
struct msg_session_destroyed {
uint32_t host_no;
uint32_t sid;
} d_session;
struct msg_transport_connect_ret {
uint64_t handle;
} ep_connect_ret;
struct msg_req_path {
uint32_t host_no;
} req_path;
struct msg_notify_if_down {
uint32_t host_no;
} notify_if_down;
} r;
} __attribute__ ((aligned (sizeof(uint64_t))));
/*
* To keep the struct iscsi_uevent size the same for userspace code
* compatibility, the main structure for ISCSI_UEVENT_PATH_UPDATE and
* ISCSI_KEVENT_PATH_REQ is defined separately and comes after the
* struct iscsi_uevent in the NETLINK_ISCSI message.
*/
struct iscsi_path {
uint64_t handle;
uint8_t mac_addr[6];
uint8_t mac_addr_old[6];
uint32_t ip_addr_len; /* 4 or 16 */
union {
struct in_addr v4_addr;
struct in6_addr v6_addr;
} src;
union {
struct in_addr v4_addr;
struct in6_addr v6_addr;
} dst;
uint16_t vlan_id;
uint16_t pmtu;
} __attribute__ ((aligned (sizeof(uint64_t))));
/*
* Common error codes
*/
enum iscsi_err {
ISCSI_OK = 0,
ISCSI_ERR_DATASN = ISCSI_ERR_BASE + 1,
ISCSI_ERR_DATA_OFFSET = ISCSI_ERR_BASE + 2,
ISCSI_ERR_MAX_CMDSN = ISCSI_ERR_BASE + 3,
ISCSI_ERR_EXP_CMDSN = ISCSI_ERR_BASE + 4,
ISCSI_ERR_BAD_OPCODE = ISCSI_ERR_BASE + 5,
ISCSI_ERR_DATALEN = ISCSI_ERR_BASE + 6,
ISCSI_ERR_AHSLEN = ISCSI_ERR_BASE + 7,
ISCSI_ERR_PROTO = ISCSI_ERR_BASE + 8,
ISCSI_ERR_LUN = ISCSI_ERR_BASE + 9,
ISCSI_ERR_BAD_ITT = ISCSI_ERR_BASE + 10,
ISCSI_ERR_CONN_FAILED = ISCSI_ERR_BASE + 11,
ISCSI_ERR_R2TSN = ISCSI_ERR_BASE + 12,
ISCSI_ERR_SESSION_FAILED = ISCSI_ERR_BASE + 13,
ISCSI_ERR_HDR_DGST = ISCSI_ERR_BASE + 14,
ISCSI_ERR_DATA_DGST = ISCSI_ERR_BASE + 15,
ISCSI_ERR_PARAM_NOT_FOUND = ISCSI_ERR_BASE + 16,
ISCSI_ERR_NO_SCSI_CMD = ISCSI_ERR_BASE + 17,
ISCSI_ERR_INVALID_HOST = ISCSI_ERR_BASE + 18,
ISCSI_ERR_XMIT_FAILED = ISCSI_ERR_BASE + 19,
ISCSI_ERR_TCP_CONN_CLOSE = ISCSI_ERR_BASE + 20,
};
/*
* iSCSI Parameters (RFC3720)
*/
enum iscsi_param {
/* passed in using netlink set param */
ISCSI_PARAM_MAX_RECV_DLENGTH,
ISCSI_PARAM_MAX_XMIT_DLENGTH,
ISCSI_PARAM_HDRDGST_EN,
ISCSI_PARAM_DATADGST_EN,
ISCSI_PARAM_INITIAL_R2T_EN,
ISCSI_PARAM_MAX_R2T,
ISCSI_PARAM_IMM_DATA_EN,
ISCSI_PARAM_FIRST_BURST,
ISCSI_PARAM_MAX_BURST,
ISCSI_PARAM_PDU_INORDER_EN,
ISCSI_PARAM_DATASEQ_INORDER_EN,
ISCSI_PARAM_ERL,
ISCSI_PARAM_IFMARKER_EN,
ISCSI_PARAM_OFMARKER_EN,
ISCSI_PARAM_EXP_STATSN,
ISCSI_PARAM_TARGET_NAME,
ISCSI_PARAM_TPGT,
ISCSI_PARAM_PERSISTENT_ADDRESS,
ISCSI_PARAM_PERSISTENT_PORT,
ISCSI_PARAM_SESS_RECOVERY_TMO,
/* pased in through bind conn using transport_fd */
ISCSI_PARAM_CONN_PORT,
ISCSI_PARAM_CONN_ADDRESS,
ISCSI_PARAM_USERNAME,
ISCSI_PARAM_USERNAME_IN,
ISCSI_PARAM_PASSWORD,
ISCSI_PARAM_PASSWORD_IN,
ISCSI_PARAM_FAST_ABORT,
ISCSI_PARAM_ABORT_TMO,
ISCSI_PARAM_LU_RESET_TMO,
ISCSI_PARAM_HOST_RESET_TMO,
ISCSI_PARAM_PING_TMO,
ISCSI_PARAM_RECV_TMO,
ISCSI_PARAM_IFACE_NAME,
ISCSI_PARAM_ISID,
ISCSI_PARAM_INITIATOR_NAME,
/* must always be last */
ISCSI_PARAM_MAX,
};
#define ISCSI_MAX_RECV_DLENGTH (1ULL << ISCSI_PARAM_MAX_RECV_DLENGTH)
#define ISCSI_MAX_XMIT_DLENGTH (1ULL << ISCSI_PARAM_MAX_XMIT_DLENGTH)
#define ISCSI_HDRDGST_EN (1ULL << ISCSI_PARAM_HDRDGST_EN)
#define ISCSI_DATADGST_EN (1ULL << ISCSI_PARAM_DATADGST_EN)
#define ISCSI_INITIAL_R2T_EN (1ULL << ISCSI_PARAM_INITIAL_R2T_EN)
#define ISCSI_MAX_R2T (1ULL << ISCSI_PARAM_MAX_R2T)
#define ISCSI_IMM_DATA_EN (1ULL << ISCSI_PARAM_IMM_DATA_EN)
#define ISCSI_FIRST_BURST (1ULL << ISCSI_PARAM_FIRST_BURST)
#define ISCSI_MAX_BURST (1ULL << ISCSI_PARAM_MAX_BURST)
#define ISCSI_PDU_INORDER_EN (1ULL << ISCSI_PARAM_PDU_INORDER_EN)
#define ISCSI_DATASEQ_INORDER_EN (1ULL << ISCSI_PARAM_DATASEQ_INORDER_EN)
#define ISCSI_ERL (1ULL << ISCSI_PARAM_ERL)
#define ISCSI_IFMARKER_EN (1ULL << ISCSI_PARAM_IFMARKER_EN)
#define ISCSI_OFMARKER_EN (1ULL << ISCSI_PARAM_OFMARKER_EN)
#define ISCSI_EXP_STATSN (1ULL << ISCSI_PARAM_EXP_STATSN)
#define ISCSI_TARGET_NAME (1ULL << ISCSI_PARAM_TARGET_NAME)
#define ISCSI_TPGT (1ULL << ISCSI_PARAM_TPGT)
#define ISCSI_PERSISTENT_ADDRESS (1ULL << ISCSI_PARAM_PERSISTENT_ADDRESS)
#define ISCSI_PERSISTENT_PORT (1ULL << ISCSI_PARAM_PERSISTENT_PORT)
#define ISCSI_SESS_RECOVERY_TMO (1ULL << ISCSI_PARAM_SESS_RECOVERY_TMO)
#define ISCSI_CONN_PORT (1ULL << ISCSI_PARAM_CONN_PORT)
#define ISCSI_CONN_ADDRESS (1ULL << ISCSI_PARAM_CONN_ADDRESS)
#define ISCSI_USERNAME (1ULL << ISCSI_PARAM_USERNAME)
#define ISCSI_USERNAME_IN (1ULL << ISCSI_PARAM_USERNAME_IN)
#define ISCSI_PASSWORD (1ULL << ISCSI_PARAM_PASSWORD)
#define ISCSI_PASSWORD_IN (1ULL << ISCSI_PARAM_PASSWORD_IN)
#define ISCSI_FAST_ABORT (1ULL << ISCSI_PARAM_FAST_ABORT)
#define ISCSI_ABORT_TMO (1ULL << ISCSI_PARAM_ABORT_TMO)
#define ISCSI_LU_RESET_TMO (1ULL << ISCSI_PARAM_LU_RESET_TMO)
#define ISCSI_HOST_RESET_TMO (1ULL << ISCSI_PARAM_HOST_RESET_TMO)
#define ISCSI_PING_TMO (1ULL << ISCSI_PARAM_PING_TMO)
#define ISCSI_RECV_TMO (1ULL << ISCSI_PARAM_RECV_TMO)
#define ISCSI_IFACE_NAME (1ULL << ISCSI_PARAM_IFACE_NAME)
#define ISCSI_ISID (1ULL << ISCSI_PARAM_ISID)
#define ISCSI_INITIATOR_NAME (1ULL << ISCSI_PARAM_INITIATOR_NAME)
/* iSCSI HBA params */
enum iscsi_host_param {
ISCSI_HOST_PARAM_HWADDRESS,
ISCSI_HOST_PARAM_INITIATOR_NAME,
ISCSI_HOST_PARAM_NETDEV_NAME,
ISCSI_HOST_PARAM_IPADDRESS,
ISCSI_HOST_PARAM_MAX,
};
#define ISCSI_HOST_HWADDRESS (1ULL << ISCSI_HOST_PARAM_HWADDRESS)
#define ISCSI_HOST_INITIATOR_NAME (1ULL << ISCSI_HOST_PARAM_INITIATOR_NAME)
#define ISCSI_HOST_NETDEV_NAME (1ULL << ISCSI_HOST_PARAM_NETDEV_NAME)
#define ISCSI_HOST_IPADDRESS (1ULL << ISCSI_HOST_PARAM_IPADDRESS)
#define iscsi_ptr(_handle) ((void*)(unsigned long)_handle)
#define iscsi_handle(_ptr) ((uint64_t)(unsigned long)_ptr)
/*
* These flags presents iSCSI Data-Path capabilities.
*/
#define CAP_RECOVERY_L0 0x1
#define CAP_RECOVERY_L1 0x2
#define CAP_RECOVERY_L2 0x4
#define CAP_MULTI_R2T 0x8
#define CAP_HDRDGST 0x10
#define CAP_DATADGST 0x20
#define CAP_MULTI_CONN 0x40
#define CAP_TEXT_NEGO 0x80
#define CAP_MARKERS 0x100
#define CAP_FW_DB 0x200
#define CAP_SENDTARGETS_OFFLOAD 0x400 /* offload discovery process */
#define CAP_DATA_PATH_OFFLOAD 0x800 /* offload entire IO path */
#define CAP_DIGEST_OFFLOAD 0x1000 /* offload hdr and data digests */
#define CAP_PADDING_OFFLOAD 0x2000 /* offload padding insertion, removal,
and verification */
/*
* These flags describes reason of stop_conn() call
*/
#define STOP_CONN_TERM 0x1
#define STOP_CONN_SUSPEND 0x2
#define STOP_CONN_RECOVER 0x3
#define ISCSI_STATS_CUSTOM_MAX 32
#define ISCSI_STATS_CUSTOM_DESC_MAX 64
struct iscsi_stats_custom {
char desc[ISCSI_STATS_CUSTOM_DESC_MAX];
uint64_t value;
};
/*
* struct iscsi_stats - iSCSI Statistics (iSCSI MIB)
*
* Note: this structure contains counters collected on per-connection basis.
*/
struct iscsi_stats {
/* octets */
uint64_t txdata_octets;
uint64_t rxdata_octets;
/* xmit pdus */
uint32_t noptx_pdus;
uint32_t scsicmd_pdus;
uint32_t tmfcmd_pdus;
uint32_t login_pdus;
uint32_t text_pdus;
uint32_t dataout_pdus;
uint32_t logout_pdus;
uint32_t snack_pdus;
/* recv pdus */
uint32_t noprx_pdus;
uint32_t scsirsp_pdus;
uint32_t tmfrsp_pdus;
uint32_t textrsp_pdus;
uint32_t datain_pdus;
uint32_t logoutrsp_pdus;
uint32_t r2t_pdus;
uint32_t async_pdus;
uint32_t rjt_pdus;
/* errors */
uint32_t digest_err;
uint32_t timeout_err;
/*
* iSCSI Custom Statistics support, i.e. Transport could
* extend existing MIB statistics with its own specific statistics
* up to ISCSI_STATS_CUSTOM_MAX
*/
uint32_t custom_length;
struct iscsi_stats_custom custom[0]
__attribute__ ((aligned (sizeof(uint64_t))));
};
#endif

View File

@@ -0,0 +1,620 @@
/*
* RFC 3720 (iSCSI) protocol data types
*
* Copyright (C) 2005 Dmitry Yusupov
* Copyright (C) 2005 Alex Aizman
* maintained by open-iscsi@googlegroups.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that 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.
*
* See the file COPYING included with this distribution for more details.
*/
#ifndef ISCSI_PROTO_H
#define ISCSI_PROTO_H
#include <linux/types.h>
#include <scsi/scsi.h>
#define ISCSI_DRAFT20_VERSION 0x00
/* default iSCSI listen port for incoming connections */
#define ISCSI_LISTEN_PORT 3260
/* Padding word length */
#define ISCSI_PAD_LEN 4
/*
* useful common(control and data pathes) macro
*/
#define ntoh24(p) (((p)[0] << 16) | ((p)[1] << 8) | ((p)[2]))
#define hton24(p, v) { \
p[0] = (((v) >> 16) & 0xFF); \
p[1] = (((v) >> 8) & 0xFF); \
p[2] = ((v) & 0xFF); \
}
#define zero_data(p) {p[0]=0;p[1]=0;p[2]=0;}
/* initiator tags; opaque for target */
typedef uint32_t __bitwise__ itt_t;
/* below makes sense only for initiator that created this tag */
#define build_itt(itt, age) ((__force itt_t)\
((itt) | ((age) << ISCSI_AGE_SHIFT)))
#define get_itt(itt) ((__force uint32_t)(itt_t)(itt) & ISCSI_ITT_MASK)
#define RESERVED_ITT ((__force itt_t)0xffffffff)
/*
* iSCSI Template Message Header
*/
struct iscsi_hdr {
uint8_t opcode;
uint8_t flags; /* Final bit */
uint8_t rsvd2[2];
uint8_t hlength; /* AHSs total length */
uint8_t dlength[3]; /* Data length */
uint8_t lun[8];
itt_t itt; /* Initiator Task Tag, opaque for target */
__be32 ttt; /* Target Task Tag */
__be32 statsn;
__be32 exp_statsn;
__be32 max_statsn;
uint8_t other[12];
};
/************************* RFC 3720 Begin *****************************/
#define ISCSI_RESERVED_TAG 0xffffffff
/* Opcode encoding bits */
#define ISCSI_OP_RETRY 0x80
#define ISCSI_OP_IMMEDIATE 0x40
#define ISCSI_OPCODE_MASK 0x3F
/* Initiator Opcode values */
#define ISCSI_OP_NOOP_OUT 0x00
#define ISCSI_OP_SCSI_CMD 0x01
#define ISCSI_OP_SCSI_TMFUNC 0x02
#define ISCSI_OP_LOGIN 0x03
#define ISCSI_OP_TEXT 0x04
#define ISCSI_OP_SCSI_DATA_OUT 0x05
#define ISCSI_OP_LOGOUT 0x06
#define ISCSI_OP_SNACK 0x10
#define ISCSI_OP_VENDOR1_CMD 0x1c
#define ISCSI_OP_VENDOR2_CMD 0x1d
#define ISCSI_OP_VENDOR3_CMD 0x1e
#define ISCSI_OP_VENDOR4_CMD 0x1f
/* Target Opcode values */
#define ISCSI_OP_NOOP_IN 0x20
#define ISCSI_OP_SCSI_CMD_RSP 0x21
#define ISCSI_OP_SCSI_TMFUNC_RSP 0x22
#define ISCSI_OP_LOGIN_RSP 0x23
#define ISCSI_OP_TEXT_RSP 0x24
#define ISCSI_OP_SCSI_DATA_IN 0x25
#define ISCSI_OP_LOGOUT_RSP 0x26
#define ISCSI_OP_R2T 0x31
#define ISCSI_OP_ASYNC_EVENT 0x32
#define ISCSI_OP_REJECT 0x3f
struct iscsi_ahs_hdr {
__be16 ahslength;
uint8_t ahstype;
uint8_t ahspec[5];
};
#define ISCSI_AHSTYPE_CDB 1
#define ISCSI_AHSTYPE_RLENGTH 2
#define ISCSI_CDB_SIZE 16
/* iSCSI PDU Header */
struct iscsi_cmd {
uint8_t opcode;
uint8_t flags;
__be16 rsvd2;
uint8_t hlength;
uint8_t dlength[3];
uint8_t lun[8];
itt_t itt; /* Initiator Task Tag */
__be32 data_length;
__be32 cmdsn;
__be32 exp_statsn;
uint8_t cdb[ISCSI_CDB_SIZE]; /* SCSI Command Block */
/* Additional Data (Command Dependent) */
};
/* Command PDU flags */
#define ISCSI_FLAG_CMD_FINAL 0x80
#define ISCSI_FLAG_CMD_READ 0x40
#define ISCSI_FLAG_CMD_WRITE 0x20
#define ISCSI_FLAG_CMD_ATTR_MASK 0x07 /* 3 bits */
/* SCSI Command Attribute values */
#define ISCSI_ATTR_UNTAGGED 0
#define ISCSI_ATTR_SIMPLE 1
#define ISCSI_ATTR_ORDERED 2
#define ISCSI_ATTR_HEAD_OF_QUEUE 3
#define ISCSI_ATTR_ACA 4
struct iscsi_rlength_ahdr {
__be16 ahslength;
uint8_t ahstype;
uint8_t reserved;
__be32 read_length;
};
/* Extended CDB AHS */
struct iscsi_ecdb_ahdr {
__be16 ahslength; /* CDB length - 15, including reserved byte */
uint8_t ahstype;
uint8_t reserved;
/* 4-byte aligned extended CDB spillover */
uint8_t ecdb[SCSI_MAX_VARLEN_CDB_SIZE - ISCSI_CDB_SIZE];
};
/* SCSI Response Header */
struct iscsi_cmd_rsp {
uint8_t opcode;
uint8_t flags;
uint8_t response;
uint8_t cmd_status;
uint8_t hlength;
uint8_t dlength[3];
uint8_t rsvd[8];
itt_t itt; /* Initiator Task Tag */
__be32 rsvd1;
__be32 statsn;
__be32 exp_cmdsn;
__be32 max_cmdsn;
__be32 exp_datasn;
__be32 bi_residual_count;
__be32 residual_count;
/* Response or Sense Data (optional) */
};
/* Command Response PDU flags */
#define ISCSI_FLAG_CMD_BIDI_OVERFLOW 0x10
#define ISCSI_FLAG_CMD_BIDI_UNDERFLOW 0x08
#define ISCSI_FLAG_CMD_OVERFLOW 0x04
#define ISCSI_FLAG_CMD_UNDERFLOW 0x02
/* iSCSI Status values. Valid if Rsp Selector bit is not set */
#define ISCSI_STATUS_CMD_COMPLETED 0
#define ISCSI_STATUS_TARGET_FAILURE 1
#define ISCSI_STATUS_SUBSYS_FAILURE 2
/* Asynchronous Event Header */
struct iscsi_async {
uint8_t opcode;
uint8_t flags;
uint8_t rsvd2[2];
uint8_t rsvd3;
uint8_t dlength[3];
uint8_t lun[8];
uint8_t rsvd4[8];
__be32 statsn;
__be32 exp_cmdsn;
__be32 max_cmdsn;
uint8_t async_event;
uint8_t async_vcode;
__be16 param1;
__be16 param2;
__be16 param3;
uint8_t rsvd5[4];
};
/* iSCSI Event Codes */
#define ISCSI_ASYNC_MSG_SCSI_EVENT 0
#define ISCSI_ASYNC_MSG_REQUEST_LOGOUT 1
#define ISCSI_ASYNC_MSG_DROPPING_CONNECTION 2
#define ISCSI_ASYNC_MSG_DROPPING_ALL_CONNECTIONS 3
#define ISCSI_ASYNC_MSG_PARAM_NEGOTIATION 4
#define ISCSI_ASYNC_MSG_VENDOR_SPECIFIC 255
/* NOP-Out Message */
struct iscsi_nopout {
uint8_t opcode;
uint8_t flags;
__be16 rsvd2;
uint8_t rsvd3;
uint8_t dlength[3];
uint8_t lun[8];
itt_t itt; /* Initiator Task Tag */
__be32 ttt; /* Target Transfer Tag */
__be32 cmdsn;
__be32 exp_statsn;
uint8_t rsvd4[16];
};
/* NOP-In Message */
struct iscsi_nopin {
uint8_t opcode;
uint8_t flags;
__be16 rsvd2;
uint8_t rsvd3;
uint8_t dlength[3];
uint8_t lun[8];
itt_t itt; /* Initiator Task Tag */
__be32 ttt; /* Target Transfer Tag */
__be32 statsn;
__be32 exp_cmdsn;
__be32 max_cmdsn;
uint8_t rsvd4[12];
};
/* SCSI Task Management Message Header */
struct iscsi_tm {
uint8_t opcode;
uint8_t flags;
uint8_t rsvd1[2];
uint8_t hlength;
uint8_t dlength[3];
uint8_t lun[8];
itt_t itt; /* Initiator Task Tag */
itt_t rtt; /* Reference Task Tag */
__be32 cmdsn;
__be32 exp_statsn;
__be32 refcmdsn;
__be32 exp_datasn;
uint8_t rsvd2[8];
};
#define ISCSI_FLAG_TM_FUNC_MASK 0x7F
/* Function values */
#define ISCSI_TM_FUNC_ABORT_TASK 1
#define ISCSI_TM_FUNC_ABORT_TASK_SET 2
#define ISCSI_TM_FUNC_CLEAR_ACA 3
#define ISCSI_TM_FUNC_CLEAR_TASK_SET 4
#define ISCSI_TM_FUNC_LOGICAL_UNIT_RESET 5
#define ISCSI_TM_FUNC_TARGET_WARM_RESET 6
#define ISCSI_TM_FUNC_TARGET_COLD_RESET 7
#define ISCSI_TM_FUNC_TASK_REASSIGN 8
/* SCSI Task Management Response Header */
struct iscsi_tm_rsp {
uint8_t opcode;
uint8_t flags;
uint8_t response; /* see Response values below */
uint8_t qualifier;
uint8_t hlength;
uint8_t dlength[3];
uint8_t rsvd2[8];
itt_t itt; /* Initiator Task Tag */
itt_t rtt; /* Reference Task Tag */
__be32 statsn;
__be32 exp_cmdsn;
__be32 max_cmdsn;
uint8_t rsvd3[12];
};
/* Response values */
#define ISCSI_TMF_RSP_COMPLETE 0x00
#define ISCSI_TMF_RSP_NO_TASK 0x01
#define ISCSI_TMF_RSP_NO_LUN 0x02
#define ISCSI_TMF_RSP_TASK_ALLEGIANT 0x03
#define ISCSI_TMF_RSP_NO_FAILOVER 0x04
#define ISCSI_TMF_RSP_NOT_SUPPORTED 0x05
#define ISCSI_TMF_RSP_AUTH_FAILED 0x06
#define ISCSI_TMF_RSP_REJECTED 0xff
/* Ready To Transfer Header */
struct iscsi_r2t_rsp {
uint8_t opcode;
uint8_t flags;
uint8_t rsvd2[2];
uint8_t hlength;
uint8_t dlength[3];
uint8_t lun[8];
itt_t itt; /* Initiator Task Tag */
__be32 ttt; /* Target Transfer Tag */
__be32 statsn;
__be32 exp_cmdsn;
__be32 max_cmdsn;
__be32 r2tsn;
__be32 data_offset;
__be32 data_length;
};
/* SCSI Data Hdr */
struct iscsi_data {
uint8_t opcode;
uint8_t flags;
uint8_t rsvd2[2];
uint8_t rsvd3;
uint8_t dlength[3];
uint8_t lun[8];
itt_t itt;
__be32 ttt;
__be32 rsvd4;
__be32 exp_statsn;
__be32 rsvd5;
__be32 datasn;
__be32 offset;
__be32 rsvd6;
/* Payload */
};
/* SCSI Data Response Hdr */
struct iscsi_data_rsp {
uint8_t opcode;
uint8_t flags;
uint8_t rsvd2;
uint8_t cmd_status;
uint8_t hlength;
uint8_t dlength[3];
uint8_t lun[8];
itt_t itt;
__be32 ttt;
__be32 statsn;
__be32 exp_cmdsn;
__be32 max_cmdsn;
__be32 datasn;
__be32 offset;
__be32 residual_count;
};
/* Data Response PDU flags */
#define ISCSI_FLAG_DATA_ACK 0x40
#define ISCSI_FLAG_DATA_OVERFLOW 0x04
#define ISCSI_FLAG_DATA_UNDERFLOW 0x02
#define ISCSI_FLAG_DATA_STATUS 0x01
/* Text Header */
struct iscsi_text {
uint8_t opcode;
uint8_t flags;
uint8_t rsvd2[2];
uint8_t hlength;
uint8_t dlength[3];
uint8_t rsvd4[8];
itt_t itt;
__be32 ttt;
__be32 cmdsn;
__be32 exp_statsn;
uint8_t rsvd5[16];
/* Text - key=value pairs */
};
#define ISCSI_FLAG_TEXT_CONTINUE 0x40
/* Text Response Header */
struct iscsi_text_rsp {
uint8_t opcode;
uint8_t flags;
uint8_t rsvd2[2];
uint8_t hlength;
uint8_t dlength[3];
uint8_t rsvd4[8];
itt_t itt;
__be32 ttt;
__be32 statsn;
__be32 exp_cmdsn;
__be32 max_cmdsn;
uint8_t rsvd5[12];
/* Text Response - key:value pairs */
};
/* Login Header */
struct iscsi_login {
uint8_t opcode;
uint8_t flags;
uint8_t max_version; /* Max. version supported */
uint8_t min_version; /* Min. version supported */
uint8_t hlength;
uint8_t dlength[3];
uint8_t isid[6]; /* Initiator Session ID */
__be16 tsih; /* Target Session Handle */
itt_t itt; /* Initiator Task Tag */
__be16 cid;
__be16 rsvd3;
__be32 cmdsn;
__be32 exp_statsn;
uint8_t rsvd5[16];
};
/* Login PDU flags */
#define ISCSI_FLAG_LOGIN_TRANSIT 0x80
#define ISCSI_FLAG_LOGIN_CONTINUE 0x40
#define ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK 0x0C /* 2 bits */
#define ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK 0x03 /* 2 bits */
#define ISCSI_LOGIN_CURRENT_STAGE(flags) \
((flags & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2)
#define ISCSI_LOGIN_NEXT_STAGE(flags) \
(flags & ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK)
/* Login Response Header */
struct iscsi_login_rsp {
uint8_t opcode;
uint8_t flags;
uint8_t max_version; /* Max. version supported */
uint8_t active_version; /* Active version */
uint8_t hlength;
uint8_t dlength[3];
uint8_t isid[6]; /* Initiator Session ID */
__be16 tsih; /* Target Session Handle */
itt_t itt; /* Initiator Task Tag */
__be32 rsvd3;
__be32 statsn;
__be32 exp_cmdsn;
__be32 max_cmdsn;
uint8_t status_class; /* see Login RSP ststus classes below */
uint8_t status_detail; /* see Login RSP Status details below */
uint8_t rsvd4[10];
};
/* Login stage (phase) codes for CSG, NSG */
#define ISCSI_INITIAL_LOGIN_STAGE -1
#define ISCSI_SECURITY_NEGOTIATION_STAGE 0
#define ISCSI_OP_PARMS_NEGOTIATION_STAGE 1
#define ISCSI_FULL_FEATURE_PHASE 3
/* Login Status response classes */
#define ISCSI_STATUS_CLS_SUCCESS 0x00
#define ISCSI_STATUS_CLS_REDIRECT 0x01
#define ISCSI_STATUS_CLS_INITIATOR_ERR 0x02
#define ISCSI_STATUS_CLS_TARGET_ERR 0x03
/* Login Status response detail codes */
/* Class-0 (Success) */
#define ISCSI_LOGIN_STATUS_ACCEPT 0x00
/* Class-1 (Redirection) */
#define ISCSI_LOGIN_STATUS_TGT_MOVED_TEMP 0x01
#define ISCSI_LOGIN_STATUS_TGT_MOVED_PERM 0x02
/* Class-2 (Initiator Error) */
#define ISCSI_LOGIN_STATUS_INIT_ERR 0x00
#define ISCSI_LOGIN_STATUS_AUTH_FAILED 0x01
#define ISCSI_LOGIN_STATUS_TGT_FORBIDDEN 0x02
#define ISCSI_LOGIN_STATUS_TGT_NOT_FOUND 0x03
#define ISCSI_LOGIN_STATUS_TGT_REMOVED 0x04
#define ISCSI_LOGIN_STATUS_NO_VERSION 0x05
#define ISCSI_LOGIN_STATUS_ISID_ERROR 0x06
#define ISCSI_LOGIN_STATUS_MISSING_FIELDS 0x07
#define ISCSI_LOGIN_STATUS_CONN_ADD_FAILED 0x08
#define ISCSI_LOGIN_STATUS_NO_SESSION_TYPE 0x09
#define ISCSI_LOGIN_STATUS_NO_SESSION 0x0a
#define ISCSI_LOGIN_STATUS_INVALID_REQUEST 0x0b
/* Class-3 (Target Error) */
#define ISCSI_LOGIN_STATUS_TARGET_ERROR 0x00
#define ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE 0x01
#define ISCSI_LOGIN_STATUS_NO_RESOURCES 0x02
/* Logout Header */
struct iscsi_logout {
uint8_t opcode;
uint8_t flags;
uint8_t rsvd1[2];
uint8_t hlength;
uint8_t dlength[3];
uint8_t rsvd2[8];
itt_t itt; /* Initiator Task Tag */
__be16 cid;
uint8_t rsvd3[2];
__be32 cmdsn;
__be32 exp_statsn;
uint8_t rsvd4[16];
};
/* Logout PDU flags */
#define ISCSI_FLAG_LOGOUT_REASON_MASK 0x7F
/* logout reason_code values */
#define ISCSI_LOGOUT_REASON_CLOSE_SESSION 0
#define ISCSI_LOGOUT_REASON_CLOSE_CONNECTION 1
#define ISCSI_LOGOUT_REASON_RECOVERY 2
#define ISCSI_LOGOUT_REASON_AEN_REQUEST 3
/* Logout Response Header */
struct iscsi_logout_rsp {
uint8_t opcode;
uint8_t flags;
uint8_t response; /* see Logout response values below */
uint8_t rsvd2;
uint8_t hlength;
uint8_t dlength[3];
uint8_t rsvd3[8];
itt_t itt; /* Initiator Task Tag */
__be32 rsvd4;
__be32 statsn;
__be32 exp_cmdsn;
__be32 max_cmdsn;
__be32 rsvd5;
__be16 t2wait;
__be16 t2retain;
__be32 rsvd6;
};
/* logout response status values */
#define ISCSI_LOGOUT_SUCCESS 0
#define ISCSI_LOGOUT_CID_NOT_FOUND 1
#define ISCSI_LOGOUT_RECOVERY_UNSUPPORTED 2
#define ISCSI_LOGOUT_CLEANUP_FAILED 3
/* SNACK Header */
struct iscsi_snack {
uint8_t opcode;
uint8_t flags;
uint8_t rsvd2[14];
itt_t itt;
__be32 begrun;
__be32 runlength;
__be32 exp_statsn;
__be32 rsvd3;
__be32 exp_datasn;
uint8_t rsvd6[8];
};
/* SNACK PDU flags */
#define ISCSI_FLAG_SNACK_TYPE_MASK 0x0F /* 4 bits */
/* Reject Message Header */
struct iscsi_reject {
uint8_t opcode;
uint8_t flags;
uint8_t reason;
uint8_t rsvd2;
uint8_t hlength;
uint8_t dlength[3];
uint8_t rsvd3[8];
__be32 ffffffff;
uint8_t rsvd4[4];
__be32 statsn;
__be32 exp_cmdsn;
__be32 max_cmdsn;
__be32 datasn;
uint8_t rsvd5[8];
/* Text - Rejected hdr */
};
/* Reason for Reject */
#define ISCSI_REASON_CMD_BEFORE_LOGIN 1
#define ISCSI_REASON_DATA_DIGEST_ERROR 2
#define ISCSI_REASON_DATA_SNACK_REJECT 3
#define ISCSI_REASON_PROTOCOL_ERROR 4
#define ISCSI_REASON_CMD_NOT_SUPPORTED 5
#define ISCSI_REASON_IMM_CMD_REJECT 6
#define ISCSI_REASON_TASK_IN_PROGRESS 7
#define ISCSI_REASON_INVALID_SNACK 8
#define ISCSI_REASON_BOOKMARK_INVALID 9
#define ISCSI_REASON_BOOKMARK_NO_RESOURCES 10
#define ISCSI_REASON_NEGOTIATION_RESET 11
/* Max. number of Key=Value pairs in a text message */
#define MAX_KEY_VALUE_PAIRS 8192
/* maximum length for text keys/values */
#define KEY_MAXLEN 64
#define VALUE_MAXLEN 255
#define TARGET_NAME_MAXLEN VALUE_MAXLEN
#define ISCSI_DEF_MAX_RECV_SEG_LEN 8192
#define ISCSI_MIN_MAX_RECV_SEG_LEN 512
#define ISCSI_MAX_MAX_RECV_SEG_LEN 16777215
#define ISCSI_DEF_FIRST_BURST_LEN 65536
#define ISCSI_MIN_FIRST_BURST_LEN 512
#define ISCSI_MAX_FIRST_BURST_LEN 16777215
#define ISCSI_DEF_MAX_BURST_LEN 262144
#define ISCSI_MIN_MAX_BURST_LEN 512
#define ISCSI_MAX_MAX_BURST_LEN 16777215
#define ISCSI_DEF_TIME2WAIT 2
/************************* RFC 3720 End *****************************/
#endif /* ISCSI_PROTO_H */

1094
kernel/include/scsi/libfc.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,166 @@
/*
* Copyright (c) 2008-2009 Cisco Systems, Inc. All rights reserved.
* Copyright (c) 2007-2008 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 _LIBFCOE_H
#define _LIBFCOE_H
#include <linux/etherdevice.h>
#include <linux/if_ether.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/workqueue.h>
#include <scsi/fc/fc_fcoe.h>
#include <scsi/libfc.h>
/*
* FIP tunable parameters.
*/
#define FCOE_CTLR_START_DELAY 2000 /* mS after first adv. to choose FCF */
#define FCOE_CTRL_SOL_TOV 2000 /* min. solicitation interval (mS) */
#define FCOE_CTLR_FCF_LIMIT 20 /* max. number of FCF entries */
/**
* enum fip_state - internal state of FCoE controller.
* @FIP_ST_DISABLED: controller has been disabled or not yet enabled.
* @FIP_ST_LINK_WAIT: the physical link is down or unusable.
* @FIP_ST_AUTO: determining whether to use FIP or non-FIP mode.
* @FIP_ST_NON_FIP: non-FIP mode selected.
* @FIP_ST_ENABLED: FIP mode selected.
*/
enum fip_state {
FIP_ST_DISABLED,
FIP_ST_LINK_WAIT,
FIP_ST_AUTO,
FIP_ST_NON_FIP,
FIP_ST_ENABLED,
};
/**
* struct fcoe_ctlr - FCoE Controller and FIP state.
* @state: internal FIP state for network link and FIP or non-FIP mode.
* @lp: &fc_lport: libfc local port.
* @sel_fcf: currently selected FCF, or NULL.
* @fcfs: list of discovered FCFs.
* @fcf_count: number of discovered FCF entries.
* @sol_time: time when a multicast solicitation was last sent.
* @sel_time: time after which to select an FCF.
* @port_ka_time: time of next port keep-alive.
* @ctlr_ka_time: time of next controller keep-alive.
* @timer: timer struct used for all delayed events.
* @link_work: &work_struct for doing FCF selection.
* @recv_work: &work_struct for receiving FIP frames.
* @fip_recv_list: list of received FIP frames.
* @user_mfs: configured maximum FC frame size, including FC header.
* @flogi_oxid: exchange ID of most recent fabric login.
* @flogi_count: number of FLOGI attempts in AUTO mode.
* @link: current link status for libfc.
* @last_link: last link state reported to libfc.
* @map_dest: use the FC_MAP mode for destination MAC addresses.
* @spma: supports SPMA server-provided MACs mode
* @dest_addr: MAC address of the selected FC forwarder.
* @ctl_src_addr: the native MAC address of our local port.
* @data_src_addr: the assigned MAC address for the local port after FLOGI.
* @send: LLD-supplied function to handle sending of FIP Ethernet frames.
* @update_mac: LLD-supplied function to handle changes to MAC addresses.
* @lock: lock protecting this structure.
*
* This structure is used by all FCoE drivers. It contains information
* needed by all FCoE low-level drivers (LLDs) as well as internal state
* for FIP, and fields shared with the LLDS.
*/
struct fcoe_ctlr {
enum fip_state state;
struct fc_lport *lp;
struct fcoe_fcf *sel_fcf;
struct list_head fcfs;
u16 fcf_count;
unsigned long sol_time;
unsigned long sel_time;
unsigned long port_ka_time;
unsigned long ctlr_ka_time;
struct timer_list timer;
struct work_struct link_work;
struct work_struct recv_work;
struct sk_buff_head fip_recv_list;
u16 user_mfs;
u16 flogi_oxid;
u8 flogi_count;
u8 link;
u8 last_link;
u8 map_dest;
u8 spma;
u8 dest_addr[ETH_ALEN];
u8 ctl_src_addr[ETH_ALEN];
u8 data_src_addr[ETH_ALEN];
void (*send)(struct fcoe_ctlr *, struct sk_buff *);
void (*update_mac)(struct fcoe_ctlr *, u8 *old, u8 *new);
spinlock_t lock;
};
/*
* struct fcoe_fcf - Fibre-Channel Forwarder.
* @list: list linkage.
* @time: system time (jiffies) when an advertisement was last received.
* @switch_name: WWN of switch from advertisement.
* @fabric_name: WWN of fabric from advertisement.
* @fc_map: FC_MAP value from advertisement.
* @fcf_mac: Ethernet address of the FCF.
* @vfid: virtual fabric ID.
* @pri: seletion priority, smaller values are better.
* @flags: flags received from advertisement.
* @fka_period: keep-alive period, in jiffies.
*
* A Fibre-Channel Forwarder (FCF) is the entity on the Ethernet that
* passes FCoE frames on to an FC fabric. This structure represents
* one FCF from which advertisements have been received.
*
* When looking up an FCF, @switch_name, @fabric_name, @fc_map, @vfid, and
* @fcf_mac together form the lookup key.
*/
struct fcoe_fcf {
struct list_head list;
unsigned long time;
u64 switch_name;
u64 fabric_name;
u32 fc_map;
u16 vfid;
u8 fcf_mac[ETH_ALEN];
u8 pri;
u16 flags;
u32 fka_period;
};
/* FIP API functions */
void fcoe_ctlr_init(struct fcoe_ctlr *);
void fcoe_ctlr_destroy(struct fcoe_ctlr *);
void fcoe_ctlr_link_up(struct fcoe_ctlr *);
int fcoe_ctlr_link_down(struct fcoe_ctlr *);
int fcoe_ctlr_els_send(struct fcoe_ctlr *, struct sk_buff *);
void fcoe_ctlr_recv(struct fcoe_ctlr *, struct sk_buff *);
int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *, struct fc_frame *fp, u8 *sa);
/* libfcoe funcs */
u64 fcoe_wwn_from_mac(unsigned char mac[], unsigned int, unsigned int);
int fcoe_libfc_config(struct fc_lport *, struct libfc_function_template *);
#endif /* _LIBFCOE_H */

View File

@@ -0,0 +1,447 @@
/*
* iSCSI lib definitions
*
* Copyright (C) 2006 Red Hat, Inc. All rights reserved.
* Copyright (C) 2004 - 2006 Mike Christie
* Copyright (C) 2004 - 2005 Dmitry Yusupov
* Copyright (C) 2004 - 2005 Alex Aizman
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef LIBISCSI_H
#define LIBISCSI_H
#include <linux/types.h>
#include <linux/wait.h>
#include <linux/mutex.h>
#include <linux/timer.h>
#include <linux/workqueue.h>
#include <scsi/iscsi_proto.h>
#include <scsi/iscsi_if.h>
#include <scsi/scsi_transport_iscsi.h>
struct scsi_transport_template;
struct scsi_host_template;
struct scsi_device;
struct Scsi_Host;
struct scsi_target;
struct scsi_cmnd;
struct socket;
struct iscsi_transport;
struct iscsi_cls_session;
struct iscsi_cls_conn;
struct iscsi_session;
struct iscsi_nopin;
struct device;
#define ISCSI_DEF_XMIT_CMDS_MAX 128 /* must be power of 2 */
#define ISCSI_MGMT_CMDS_MAX 15
#define ISCSI_DEF_CMD_PER_LUN 32
/* Task Mgmt states */
enum {
TMF_INITIAL,
TMF_QUEUED,
TMF_SUCCESS,
TMF_FAILED,
TMF_TIMEDOUT,
TMF_NOT_FOUND,
};
/* Connection suspend "bit" */
#define ISCSI_SUSPEND_BIT 1
#define ISCSI_ITT_MASK 0x1fff
#define ISCSI_TOTAL_CMDS_MAX 4096
/* this must be a power of two greater than ISCSI_MGMT_CMDS_MAX */
#define ISCSI_TOTAL_CMDS_MIN 16
#define ISCSI_AGE_SHIFT 28
#define ISCSI_AGE_MASK 0xf
#define ISCSI_ADDRESS_BUF_LEN 64
enum {
/* this is the maximum possible storage for AHSs */
ISCSI_MAX_AHS_SIZE = sizeof(struct iscsi_ecdb_ahdr) +
sizeof(struct iscsi_rlength_ahdr),
ISCSI_DIGEST_SIZE = sizeof(__u32),
};
enum {
ISCSI_TASK_FREE,
ISCSI_TASK_COMPLETED,
ISCSI_TASK_PENDING,
ISCSI_TASK_RUNNING,
ISCSI_TASK_ABRT_TMF, /* aborted due to TMF */
ISCSI_TASK_ABRT_SESS_RECOV, /* aborted due to session recovery */
};
struct iscsi_r2t_info {
__be32 ttt; /* copied from R2T */
__be32 exp_statsn; /* copied from R2T */
uint32_t data_length; /* copied from R2T */
uint32_t data_offset; /* copied from R2T */
int data_count; /* DATA-Out payload progress */
int datasn;
/* LLDs should set/update these values */
int sent; /* R2T sequence progress */
};
struct iscsi_task {
/*
* Because LLDs allocate their hdr differently, this is a pointer
* and length to that storage. It must be setup at session
* creation time.
*/
struct iscsi_hdr *hdr;
unsigned short hdr_max;
unsigned short hdr_len; /* accumulated size of hdr used */
/* copied values in case we need to send tmfs */
itt_t hdr_itt;
__be32 cmdsn;
uint8_t lun[8];
int itt; /* this ITT */
unsigned imm_count; /* imm-data (bytes) */
/* offset in unsolicited stream (bytes); */
struct iscsi_r2t_info unsol_r2t;
char *data; /* mgmt payload */
unsigned data_count;
struct scsi_cmnd *sc; /* associated SCSI cmd*/
struct iscsi_conn *conn; /* used connection */
/* data processing tracking */
unsigned long last_xfer;
unsigned long last_timeout;
bool have_checked_conn;
/* state set/tested under session->lock */
int state;
atomic_t refcount;
struct list_head running; /* running cmd list */
void *dd_data; /* driver/transport data */
};
static inline int iscsi_task_has_unsol_data(struct iscsi_task *task)
{
return task->unsol_r2t.data_length > task->unsol_r2t.sent;
}
static inline void* iscsi_next_hdr(struct iscsi_task *task)
{
return (void*)task->hdr + task->hdr_len;
}
/* Connection's states */
enum {
ISCSI_CONN_INITIAL_STAGE,
ISCSI_CONN_STARTED,
ISCSI_CONN_STOPPED,
ISCSI_CONN_CLEANUP_WAIT,
};
struct iscsi_conn {
struct iscsi_cls_conn *cls_conn; /* ptr to class connection */
void *dd_data; /* iscsi_transport data */
struct iscsi_session *session; /* parent session */
/*
* conn_stop() flag: stop to recover, stop to terminate
*/
int stop_stage;
struct timer_list transport_timer;
unsigned long last_recv;
unsigned long last_ping;
int ping_timeout;
int recv_timeout;
struct iscsi_task *ping_task;
/* iSCSI connection-wide sequencing */
uint32_t exp_statsn;
/* control data */
int id; /* CID */
int c_stage; /* connection state */
/*
* Preallocated buffer for pdus that have data but do not
* originate from scsi-ml. We never have two pdus using the
* buffer at the same time. It is only allocated to
* the default max recv size because the pdus we support
* should always fit in this buffer
*/
char *data;
struct iscsi_task *login_task; /* mtask used for login/text */
struct iscsi_task *task; /* xmit task in progress */
/* xmit */
struct list_head mgmtqueue; /* mgmt (control) xmit queue */
struct list_head cmdqueue; /* data-path cmd queue */
struct list_head requeue; /* tasks needing another run */
struct work_struct xmitwork; /* per-conn. xmit workqueue */
unsigned long suspend_tx; /* suspend Tx */
unsigned long suspend_rx; /* suspend Rx */
/* abort */
wait_queue_head_t ehwait; /* used in eh_abort() */
struct iscsi_tm tmhdr;
struct timer_list tmf_timer;
int tmf_state; /* see TMF_INITIAL, etc.*/
/* negotiated params */
unsigned max_recv_dlength; /* initiator_max_recv_dsl*/
unsigned max_xmit_dlength; /* target_max_recv_dsl */
int hdrdgst_en;
int datadgst_en;
int ifmarker_en;
int ofmarker_en;
/* values userspace uses to id a conn */
int persistent_port;
char *persistent_address;
/* remote portal currently connected to */
int portal_port;
char portal_address[ISCSI_ADDRESS_BUF_LEN];
/* MIB-statistics */
uint64_t txdata_octets;
uint64_t rxdata_octets;
uint32_t scsicmd_pdus_cnt;
uint32_t dataout_pdus_cnt;
uint32_t scsirsp_pdus_cnt;
uint32_t datain_pdus_cnt;
uint32_t r2t_pdus_cnt;
uint32_t tmfcmd_pdus_cnt;
int32_t tmfrsp_pdus_cnt;
/* custom statistics */
uint32_t eh_abort_cnt;
uint32_t fmr_unalign_cnt;
};
struct iscsi_pool {
struct kfifo *queue; /* FIFO Queue */
void **pool; /* Pool of elements */
int max; /* Max number of elements */
};
/* Session's states */
enum {
ISCSI_STATE_FREE = 1,
ISCSI_STATE_LOGGED_IN,
ISCSI_STATE_FAILED,
ISCSI_STATE_TERMINATE,
ISCSI_STATE_IN_RECOVERY,
ISCSI_STATE_RECOVERY_FAILED,
ISCSI_STATE_LOGGING_OUT,
};
struct iscsi_session {
struct iscsi_cls_session *cls_session;
/*
* Syncs up the scsi eh thread with the iscsi eh thread when sending
* task management functions. This must be taken before the session
* and recv lock.
*/
struct mutex eh_mutex;
/* iSCSI session-wide sequencing */
uint32_t cmdsn;
uint32_t exp_cmdsn;
uint32_t max_cmdsn;
/* This tracks the reqs queued into the initiator */
uint32_t queued_cmdsn;
/* configuration */
int abort_timeout;
int lu_reset_timeout;
int initial_r2t_en;
unsigned max_r2t;
int imm_data_en;
unsigned first_burst;
unsigned max_burst;
int time2wait;
int time2retain;
int pdu_inorder_en;
int dataseq_inorder_en;
int erl;
int fast_abort;
int tpgt;
char *username;
char *username_in;
char *password;
char *password_in;
char *targetname;
char *ifacename;
char *initiatorname;
/* control data */
struct iscsi_transport *tt;
struct Scsi_Host *host;
struct iscsi_conn *leadconn; /* leading connection */
spinlock_t lock; /* protects session state, *
* sequence numbers, *
* session resources: *
* - cmdpool, *
* - mgmtpool, *
* - r2tpool */
int state; /* session state */
int age; /* counts session re-opens */
int scsi_cmds_max; /* max scsi commands */
int cmds_max; /* size of cmds array */
struct iscsi_task **cmds; /* Original Cmds arr */
struct iscsi_pool cmdpool; /* PDU's pool */
void *dd_data; /* LLD private data */
};
enum {
ISCSI_HOST_SETUP,
ISCSI_HOST_REMOVED,
};
struct iscsi_host {
char *initiatorname;
/* hw address or netdev iscsi connection is bound to */
char *hwaddress;
char *netdev;
/* local address */
int local_port;
char local_address[ISCSI_ADDRESS_BUF_LEN];
wait_queue_head_t session_removal_wq;
/* protects sessions and state */
spinlock_t lock;
int num_sessions;
int state;
struct workqueue_struct *workq;
char workq_name[20];
};
/*
* scsi host template
*/
extern int iscsi_change_queue_depth(struct scsi_device *sdev, int depth);
extern int iscsi_eh_abort(struct scsi_cmnd *sc);
extern int iscsi_eh_target_reset(struct scsi_cmnd *sc);
extern int iscsi_eh_device_reset(struct scsi_cmnd *sc);
extern int iscsi_queuecommand(struct scsi_cmnd *sc,
void (*done)(struct scsi_cmnd *));
/*
* iSCSI host helpers.
*/
#define iscsi_host_priv(_shost) \
(shost_priv(_shost) + sizeof(struct iscsi_host))
extern int iscsi_host_set_param(struct Scsi_Host *shost,
enum iscsi_host_param param, char *buf,
int buflen);
extern int iscsi_host_get_param(struct Scsi_Host *shost,
enum iscsi_host_param param, char *buf);
extern int iscsi_host_add(struct Scsi_Host *shost, struct device *pdev);
extern struct Scsi_Host *iscsi_host_alloc(struct scsi_host_template *sht,
int dd_data_size,
bool xmit_can_sleep);
extern void iscsi_host_remove(struct Scsi_Host *shost);
extern void iscsi_host_free(struct Scsi_Host *shost);
extern int iscsi_target_alloc(struct scsi_target *starget);
/*
* session management
*/
extern struct iscsi_cls_session *
iscsi_session_setup(struct iscsi_transport *, struct Scsi_Host *shost,
uint16_t, int, int, uint32_t, unsigned int);
extern void iscsi_session_teardown(struct iscsi_cls_session *);
extern void iscsi_session_recovery_timedout(struct iscsi_cls_session *);
extern int iscsi_set_param(struct iscsi_cls_conn *cls_conn,
enum iscsi_param param, char *buf, int buflen);
extern int iscsi_session_get_param(struct iscsi_cls_session *cls_session,
enum iscsi_param param, char *buf);
#define iscsi_session_printk(prefix, _sess, fmt, a...) \
iscsi_cls_session_printk(prefix, _sess->cls_session, fmt, ##a)
/*
* connection management
*/
extern struct iscsi_cls_conn *iscsi_conn_setup(struct iscsi_cls_session *,
int, uint32_t);
extern void iscsi_conn_teardown(struct iscsi_cls_conn *);
extern int iscsi_conn_start(struct iscsi_cls_conn *);
extern void iscsi_conn_stop(struct iscsi_cls_conn *, int);
extern int iscsi_conn_bind(struct iscsi_cls_session *, struct iscsi_cls_conn *,
int);
extern void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err);
extern void iscsi_session_failure(struct iscsi_session *session,
enum iscsi_err err);
extern int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
enum iscsi_param param, char *buf);
extern void iscsi_suspend_tx(struct iscsi_conn *conn);
extern void iscsi_suspend_queue(struct iscsi_conn *conn);
extern void iscsi_conn_queue_work(struct iscsi_conn *conn);
#define iscsi_conn_printk(prefix, _c, fmt, a...) \
iscsi_cls_conn_printk(prefix, ((struct iscsi_conn *)_c)->cls_conn, \
fmt, ##a)
/*
* pdu and task processing
*/
extern void iscsi_update_cmdsn(struct iscsi_session *, struct iscsi_nopin *);
extern void iscsi_prep_data_out_pdu(struct iscsi_task *task,
struct iscsi_r2t_info *r2t,
struct iscsi_data *hdr);
extern int iscsi_conn_send_pdu(struct iscsi_cls_conn *, struct iscsi_hdr *,
char *, uint32_t);
extern int iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *,
char *, int);
extern int __iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *,
char *, int);
extern int iscsi_verify_itt(struct iscsi_conn *, itt_t);
extern struct iscsi_task *iscsi_itt_to_ctask(struct iscsi_conn *, itt_t);
extern struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *, itt_t);
extern void iscsi_requeue_task(struct iscsi_task *task);
extern void iscsi_put_task(struct iscsi_task *task);
extern void __iscsi_get_task(struct iscsi_task *task);
extern void iscsi_complete_scsi_task(struct iscsi_task *task,
uint32_t exp_cmdsn, uint32_t max_cmdsn);
/*
* generic helpers
*/
extern void iscsi_pool_free(struct iscsi_pool *);
extern int iscsi_pool_init(struct iscsi_pool *, int, void ***, int);
/*
* inline functions to deal with padding.
*/
static inline unsigned int
iscsi_padded(unsigned int len)
{
return (len + ISCSI_PAD_LEN - 1) & ~(ISCSI_PAD_LEN - 1);
}
static inline unsigned int
iscsi_padding(unsigned int len)
{
len &= (ISCSI_PAD_LEN - 1);
if (len)
len = ISCSI_PAD_LEN - len;
return len;
}
#endif

View File

@@ -0,0 +1,133 @@
/*
* iSCSI over TCP/IP Data-Path lib
*
* Copyright (C) 2008 Mike Christie
* Copyright (C) 2008 Red Hat, Inc. All rights reserved.
* maintained by open-iscsi@googlegroups.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that 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.
*
* See the file COPYING included with this distribution for more details.
*/
#ifndef LIBISCSI_TCP_H
#define LIBISCSI_TCP_H
#include <scsi/libiscsi.h>
struct iscsi_tcp_conn;
struct iscsi_segment;
struct sk_buff;
struct hash_desc;
typedef int iscsi_segment_done_fn_t(struct iscsi_tcp_conn *,
struct iscsi_segment *);
struct iscsi_segment {
unsigned char *data;
unsigned int size;
unsigned int copied;
unsigned int total_size;
unsigned int total_copied;
struct hash_desc *hash;
unsigned char padbuf[ISCSI_PAD_LEN];
unsigned char recv_digest[ISCSI_DIGEST_SIZE];
unsigned char digest[ISCSI_DIGEST_SIZE];
unsigned int digest_len;
struct scatterlist *sg;
void *sg_mapped;
unsigned int sg_offset;
iscsi_segment_done_fn_t *done;
};
/* Socket connection recieve helper */
struct iscsi_tcp_recv {
struct iscsi_hdr *hdr;
struct iscsi_segment segment;
/* Allocate buffer for BHS + AHS */
uint32_t hdr_buf[64];
/* copied and flipped values */
int datalen;
};
struct iscsi_tcp_conn {
struct iscsi_conn *iscsi_conn;
void *dd_data;
int stop_stage; /* conn_stop() flag: *
* stop to recover, *
* stop to terminate */
/* control data */
struct iscsi_tcp_recv in; /* TCP receive context */
/* CRC32C (Rx) LLD should set this is they do not offload */
struct hash_desc *rx_hash;
};
struct iscsi_tcp_task {
uint32_t exp_datasn; /* expected target's R2TSN/DataSN */
int data_offset;
struct iscsi_r2t_info *r2t; /* in progress solict R2T */
struct iscsi_pool r2tpool;
struct kfifo *r2tqueue;
void *dd_data;
};
enum {
ISCSI_TCP_SEGMENT_DONE, /* curr seg has been processed */
ISCSI_TCP_SKB_DONE, /* skb is out of data */
ISCSI_TCP_CONN_ERR, /* iscsi layer has fired a conn err */
ISCSI_TCP_SUSPENDED, /* conn is suspended */
};
extern void iscsi_tcp_hdr_recv_prep(struct iscsi_tcp_conn *tcp_conn);
extern int iscsi_tcp_recv_skb(struct iscsi_conn *conn, struct sk_buff *skb,
unsigned int offset, bool offloaded, int *status);
extern void iscsi_tcp_cleanup_task(struct iscsi_task *task);
extern int iscsi_tcp_task_init(struct iscsi_task *task);
extern int iscsi_tcp_task_xmit(struct iscsi_task *task);
/* segment helpers */
extern int iscsi_tcp_recv_segment_is_hdr(struct iscsi_tcp_conn *tcp_conn);
extern int iscsi_tcp_segment_done(struct iscsi_tcp_conn *tcp_conn,
struct iscsi_segment *segment, int recv,
unsigned copied);
extern void iscsi_tcp_segment_unmap(struct iscsi_segment *segment);
extern void iscsi_segment_init_linear(struct iscsi_segment *segment,
void *data, size_t size,
iscsi_segment_done_fn_t *done,
struct hash_desc *hash);
extern int
iscsi_segment_seek_sg(struct iscsi_segment *segment,
struct scatterlist *sg_list, unsigned int sg_count,
unsigned int offset, size_t size,
iscsi_segment_done_fn_t *done, struct hash_desc *hash);
/* digest helpers */
extern void iscsi_tcp_dgst_header(struct hash_desc *hash, const void *hdr,
size_t hdrlen,
unsigned char digest[ISCSI_DIGEST_SIZE]);
extern struct iscsi_cls_conn *
iscsi_tcp_conn_setup(struct iscsi_cls_session *cls_session, int dd_data_size,
uint32_t conn_idx);
extern void iscsi_tcp_conn_teardown(struct iscsi_cls_conn *cls_conn);
/* misc helpers */
extern int iscsi_tcp_r2tpool_alloc(struct iscsi_session *session);
extern void iscsi_tcp_r2tpool_free(struct iscsi_session *session);
extern void iscsi_tcp_conn_get_stats(struct iscsi_cls_conn *cls_conn,
struct iscsi_stats *stats);
#endif /* LIBISCSI_TCP_H */

View File

@@ -0,0 +1,681 @@
/*
* SAS host prototypes and structures header file
*
* Copyright (C) 2005 Adaptec, Inc. All rights reserved.
* Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
*
* This file is licensed under GPLv2.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
*/
#ifndef _LIBSAS_H_
#define _LIBSAS_H_
#include <linux/timer.h>
#include <linux/pci.h>
#include <scsi/sas.h>
#include <linux/libata.h>
#include <linux/list.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_transport_sas.h>
#include <linux/scatterlist.h>
struct block_device;
enum sas_class {
SAS,
EXPANDER
};
enum sas_phy_role {
PHY_ROLE_NONE = 0,
PHY_ROLE_TARGET = 0x40,
PHY_ROLE_INITIATOR = 0x80,
};
enum sas_phy_type {
PHY_TYPE_PHYSICAL,
PHY_TYPE_VIRTUAL
};
/* The events are mnemonically described in sas_dump.c
* so when updating/adding events here, please also
* update the other file too.
*/
enum ha_event {
HAE_RESET = 0U,
HA_NUM_EVENTS = 1,
};
enum port_event {
PORTE_BYTES_DMAED = 0U,
PORTE_BROADCAST_RCVD = 1,
PORTE_LINK_RESET_ERR = 2,
PORTE_TIMER_EVENT = 3,
PORTE_HARD_RESET = 4,
PORT_NUM_EVENTS = 5,
};
enum phy_event {
PHYE_LOSS_OF_SIGNAL = 0U,
PHYE_OOB_DONE = 1,
PHYE_OOB_ERROR = 2,
PHYE_SPINUP_HOLD = 3, /* hot plug SATA, no COMWAKE sent */
PHY_NUM_EVENTS = 4,
};
enum discover_event {
DISCE_DISCOVER_DOMAIN = 0U,
DISCE_REVALIDATE_DOMAIN = 1,
DISCE_PORT_GONE = 2,
DISC_NUM_EVENTS = 3,
};
/* ---------- Expander Devices ---------- */
#define to_dom_device(_obj) container_of(_obj, struct domain_device, dev_obj)
#define to_dev_attr(_attr) container_of(_attr, struct domain_dev_attribute,\
attr)
enum routing_attribute {
DIRECT_ROUTING,
SUBTRACTIVE_ROUTING,
TABLE_ROUTING,
};
enum ex_phy_state {
PHY_EMPTY,
PHY_VACANT,
PHY_NOT_PRESENT,
PHY_DEVICE_DISCOVERED
};
struct ex_phy {
int phy_id;
enum ex_phy_state phy_state;
enum sas_dev_type attached_dev_type;
enum sas_linkrate linkrate;
u8 attached_sata_host:1;
u8 attached_sata_dev:1;
u8 attached_sata_ps:1;
enum sas_protocol attached_tproto;
enum sas_protocol attached_iproto;
u8 attached_sas_addr[SAS_ADDR_SIZE];
u8 attached_phy_id;
u8 phy_change_count;
enum routing_attribute routing_attr;
u8 virtual:1;
int last_da_index;
struct sas_phy *phy;
struct sas_port *port;
};
struct expander_device {
struct list_head children;
u16 ex_change_count;
u16 max_route_indexes;
u8 num_phys;
u8 configuring:1;
u8 conf_route_table:1;
u8 enclosure_logical_id[8];
struct ex_phy *ex_phy;
struct sas_port *parent_port;
};
/* ---------- SATA device ---------- */
enum ata_command_set {
ATA_COMMAND_SET = 0,
ATAPI_COMMAND_SET = 1,
};
struct sata_device {
enum ata_command_set command_set;
struct smp_resp rps_resp; /* report_phy_sata_resp */
__le16 *identify_device;
__le16 *identify_packet_device;
u8 port_no; /* port number, if this is a PM (Port) */
struct list_head children; /* PM Ports if this is a PM */
struct ata_port *ap;
struct ata_host ata_host;
struct ata_taskfile tf;
u32 sstatus;
u32 serror;
u32 scontrol;
};
/* ---------- Domain device ---------- */
struct domain_device {
enum sas_dev_type dev_type;
enum sas_linkrate linkrate;
enum sas_linkrate min_linkrate;
enum sas_linkrate max_linkrate;
int pathways;
struct domain_device *parent;
struct list_head siblings; /* devices on the same level */
struct asd_sas_port *port; /* shortcut to root of the tree */
struct list_head dev_list_node;
enum sas_protocol iproto;
enum sas_protocol tproto;
struct sas_rphy *rphy;
u8 sas_addr[SAS_ADDR_SIZE];
u8 hashed_sas_addr[HASHED_SAS_ADDR_SIZE];
u8 frame_rcvd[32];
union {
struct expander_device ex_dev;
struct sata_device sata_dev; /* STP & directly attached */
};
void *lldd_dev;
};
struct sas_discovery_event {
struct work_struct work;
struct asd_sas_port *port;
};
struct sas_discovery {
spinlock_t disc_event_lock;
struct sas_discovery_event disc_work[DISC_NUM_EVENTS];
unsigned long pending;
u8 fanout_sas_addr[8];
u8 eeds_a[8];
u8 eeds_b[8];
int max_level;
};
/* The port struct is Class:RW, driver:RO */
struct asd_sas_port {
/* private: */
struct completion port_gone_completion;
struct sas_discovery disc;
struct domain_device *port_dev;
spinlock_t dev_list_lock;
struct list_head dev_list;
enum sas_linkrate linkrate;
struct sas_phy *phy;
struct work_struct work;
/* public: */
int id;
enum sas_class class;
u8 sas_addr[SAS_ADDR_SIZE];
u8 attached_sas_addr[SAS_ADDR_SIZE];
enum sas_protocol iproto;
enum sas_protocol tproto;
enum sas_oob_mode oob_mode;
spinlock_t phy_list_lock;
struct list_head phy_list;
int num_phys;
u32 phy_mask;
struct sas_ha_struct *ha;
struct sas_port *port;
void *lldd_port; /* not touched by the sas class code */
};
struct asd_sas_event {
struct work_struct work;
struct asd_sas_phy *phy;
};
/* The phy pretty much is controlled by the LLDD.
* The class only reads those fields.
*/
struct asd_sas_phy {
/* private: */
/* protected by ha->event_lock */
struct asd_sas_event port_events[PORT_NUM_EVENTS];
struct asd_sas_event phy_events[PHY_NUM_EVENTS];
unsigned long port_events_pending;
unsigned long phy_events_pending;
int error;
struct sas_phy *phy;
/* public: */
/* The following are class:RO, driver:R/W */
int enabled; /* must be set */
int id; /* must be set */
enum sas_class class;
enum sas_protocol iproto;
enum sas_protocol tproto;
enum sas_phy_type type;
enum sas_phy_role role;
enum sas_oob_mode oob_mode;
enum sas_linkrate linkrate;
u8 *sas_addr; /* must be set */
u8 attached_sas_addr[SAS_ADDR_SIZE]; /* class:RO, driver: R/W */
spinlock_t frame_rcvd_lock;
u8 *frame_rcvd; /* must be set */
int frame_rcvd_size;
spinlock_t sas_prim_lock;
u32 sas_prim;
struct list_head port_phy_el; /* driver:RO */
struct asd_sas_port *port; /* Class:RW, driver: RO */
struct sas_ha_struct *ha; /* may be set; the class sets it anyway */
void *lldd_phy; /* not touched by the sas_class_code */
};
struct scsi_core {
struct Scsi_Host *shost;
spinlock_t task_queue_lock;
struct list_head task_queue;
int task_queue_size;
struct task_struct *queue_thread;
};
struct sas_ha_event {
struct work_struct work;
struct sas_ha_struct *ha;
};
enum sas_ha_state {
SAS_HA_REGISTERED,
SAS_HA_UNREGISTERED
};
struct sas_ha_struct {
/* private: */
spinlock_t event_lock;
struct sas_ha_event ha_events[HA_NUM_EVENTS];
unsigned long pending;
enum sas_ha_state state;
spinlock_t state_lock;
struct scsi_core core;
/* public: */
char *sas_ha_name;
struct device *dev; /* should be set */
struct module *lldd_module; /* should be set */
u8 *sas_addr; /* must be set */
u8 hashed_sas_addr[HASHED_SAS_ADDR_SIZE];
spinlock_t phy_port_lock;
struct asd_sas_phy **sas_phy; /* array of valid pointers, must be set */
struct asd_sas_port **sas_port; /* array of valid pointers, must be set */
int num_phys; /* must be set, gt 0, static */
/* The class calls this to send a task for execution. */
int lldd_max_execute_num;
int lldd_queue_size;
/* LLDD calls these to notify the class of an event. */
void (*notify_ha_event)(struct sas_ha_struct *, enum ha_event);
void (*notify_port_event)(struct asd_sas_phy *, enum port_event);
void (*notify_phy_event)(struct asd_sas_phy *, enum phy_event);
void *lldd_ha; /* not touched by sas class code */
struct list_head eh_done_q;
};
#define SHOST_TO_SAS_HA(_shost) (*(struct sas_ha_struct **)(_shost)->hostdata)
static inline struct domain_device *
starget_to_domain_dev(struct scsi_target *starget) {
return starget->hostdata;
}
static inline struct domain_device *
sdev_to_domain_dev(struct scsi_device *sdev) {
return starget_to_domain_dev(sdev->sdev_target);
}
static inline struct domain_device *
cmd_to_domain_dev(struct scsi_cmnd *cmd)
{
return sdev_to_domain_dev(cmd->device);
}
void sas_hash_addr(u8 *hashed, const u8 *sas_addr);
/* Before calling a notify event, LLDD should use this function
* when the link is severed (possibly from its tasklet).
* The idea is that the Class only reads those, while the LLDD,
* can R/W these (thus avoiding a race).
*/
static inline void sas_phy_disconnected(struct asd_sas_phy *phy)
{
phy->oob_mode = OOB_NOT_CONNECTED;
phy->linkrate = SAS_LINK_RATE_UNKNOWN;
}
/* ---------- Tasks ---------- */
/*
service_response | SAS_TASK_COMPLETE | SAS_TASK_UNDELIVERED |
exec_status | | |
---------------------+---------------------+-----------------------+
SAM_... | X | |
DEV_NO_RESPONSE | X | X |
INTERRUPTED | X | |
QUEUE_FULL | | X |
DEVICE_UNKNOWN | | X |
SG_ERR | | X |
---------------------+---------------------+-----------------------+
*/
enum service_response {
SAS_TASK_COMPLETE,
SAS_TASK_UNDELIVERED = -1,
};
enum exec_status {
SAM_GOOD = 0,
SAM_CHECK_COND = 2,
SAM_COND_MET = 4,
SAM_BUSY = 8,
SAM_INTERMEDIATE = 0x10,
SAM_IM_COND_MET = 0x12,
SAM_RESV_CONFLICT= 0x14,
SAM_TASK_SET_FULL= 0x28,
SAM_ACA_ACTIVE = 0x30,
SAM_TASK_ABORTED = 0x40,
SAS_DEV_NO_RESPONSE = 0x80,
SAS_DATA_UNDERRUN,
SAS_DATA_OVERRUN,
SAS_INTERRUPTED,
SAS_QUEUE_FULL,
SAS_DEVICE_UNKNOWN,
SAS_SG_ERR,
SAS_OPEN_REJECT,
SAS_OPEN_TO,
SAS_PROTO_RESPONSE,
SAS_PHY_DOWN,
SAS_NAK_R_ERR,
SAS_PENDING,
SAS_ABORTED_TASK,
};
/* When a task finishes with a response, the LLDD examines the
* response:
* - For an ATA task task_status_struct::stat is set to
* SAS_PROTO_RESPONSE, and the task_status_struct::buf is set to the
* contents of struct ata_task_resp.
* - For SSP tasks, if no data is present or status/TMF response
* is valid, task_status_struct::stat is set. If data is present
* (SENSE data), the LLDD copies up to SAS_STATUS_BUF_SIZE, sets
* task_status_struct::buf_valid_size, and task_status_struct::stat is
* set to SAM_CHECK_COND.
*
* "buf" has format SCSI Sense for SSP task, or struct ata_task_resp
* for ATA task.
*
* "frame_len" is the total frame length, which could be more or less
* than actually copied.
*
* Tasks ending with response, always set the residual field.
*/
struct ata_task_resp {
u16 frame_len;
u8 ending_fis[24]; /* dev to host or data-in */
u32 sstatus;
u32 serror;
u32 scontrol;
u32 sactive;
};
#define SAS_STATUS_BUF_SIZE 96
struct task_status_struct {
enum service_response resp;
enum exec_status stat;
int buf_valid_size;
u8 buf[SAS_STATUS_BUF_SIZE];
u32 residual;
enum sas_open_rej_reason open_rej_reason;
};
/* ATA and ATAPI task queuable to a SAS LLDD.
*/
struct sas_ata_task {
struct host_to_dev_fis fis;
u8 atapi_packet[16]; /* 0 if not ATAPI task */
u8 retry_count; /* hardware retry, should be > 0 */
u8 dma_xfer:1; /* PIO:0 or DMA:1 */
u8 use_ncq:1;
u8 set_affil_pol:1;
u8 stp_affil_pol:1;
u8 device_control_reg_update:1;
};
struct sas_smp_task {
struct scatterlist smp_req;
struct scatterlist smp_resp;
};
enum task_attribute {
TASK_ATTR_SIMPLE = 0,
TASK_ATTR_HOQ = 1,
TASK_ATTR_ORDERED= 2,
TASK_ATTR_ACA = 4,
};
struct sas_ssp_task {
u8 retry_count; /* hardware retry, should be > 0 */
u8 LUN[8];
u8 enable_first_burst:1;
enum task_attribute task_attr;
u8 task_prio;
u8 cdb[16];
};
struct sas_task {
struct domain_device *dev;
struct list_head list;
spinlock_t task_state_lock;
unsigned task_state_flags;
enum sas_protocol task_proto;
/* Used by the discovery code. */
struct timer_list timer;
struct completion completion;
union {
struct sas_ata_task ata_task;
struct sas_smp_task smp_task;
struct sas_ssp_task ssp_task;
};
struct scatterlist *scatter;
int num_scatter;
u32 total_xfer_len;
u8 data_dir:2; /* Use PCI_DMA_... */
struct task_status_struct task_status;
void (*task_done)(struct sas_task *);
void *lldd_task; /* for use by LLDDs */
void *uldd_task;
struct work_struct abort_work;
};
extern struct kmem_cache *sas_task_cache;
#define SAS_TASK_STATE_PENDING 1
#define SAS_TASK_STATE_DONE 2
#define SAS_TASK_STATE_ABORTED 4
#define SAS_TASK_NEED_DEV_RESET 8
#define SAS_TASK_AT_INITIATOR 16
static inline struct sas_task *sas_alloc_task(gfp_t flags)
{
struct sas_task *task = kmem_cache_zalloc(sas_task_cache, flags);
if (task) {
INIT_LIST_HEAD(&task->list);
spin_lock_init(&task->task_state_lock);
task->task_state_flags = SAS_TASK_STATE_PENDING;
init_timer(&task->timer);
init_completion(&task->completion);
}
return task;
}
static inline void sas_free_task(struct sas_task *task)
{
if (task) {
BUG_ON(!list_empty(&task->list));
kmem_cache_free(sas_task_cache, task);
}
}
struct sas_domain_function_template {
/* The class calls these to notify the LLDD of an event. */
void (*lldd_port_formed)(struct asd_sas_phy *);
void (*lldd_port_deformed)(struct asd_sas_phy *);
/* The class calls these when a device is found or gone. */
int (*lldd_dev_found)(struct domain_device *);
void (*lldd_dev_gone)(struct domain_device *);
int (*lldd_execute_task)(struct sas_task *, int num,
gfp_t gfp_flags);
/* Task Management Functions. Must be called from process context. */
int (*lldd_abort_task)(struct sas_task *);
int (*lldd_abort_task_set)(struct domain_device *, u8 *lun);
int (*lldd_clear_aca)(struct domain_device *, u8 *lun);
int (*lldd_clear_task_set)(struct domain_device *, u8 *lun);
int (*lldd_I_T_nexus_reset)(struct domain_device *);
int (*lldd_lu_reset)(struct domain_device *, u8 *lun);
int (*lldd_query_task)(struct sas_task *);
/* Port and Adapter management */
int (*lldd_clear_nexus_port)(struct asd_sas_port *);
int (*lldd_clear_nexus_ha)(struct sas_ha_struct *);
/* Phy management */
int (*lldd_control_phy)(struct asd_sas_phy *, enum phy_func, void *);
};
extern int sas_register_ha(struct sas_ha_struct *);
extern int sas_unregister_ha(struct sas_ha_struct *);
int sas_set_phy_speed(struct sas_phy *phy,
struct sas_phy_linkrates *rates);
int sas_phy_enable(struct sas_phy *phy, int enabled);
int sas_phy_reset(struct sas_phy *phy, int hard_reset);
int sas_queue_up(struct sas_task *task);
extern int sas_queuecommand(struct scsi_cmnd *,
void (*scsi_done)(struct scsi_cmnd *));
extern int sas_target_alloc(struct scsi_target *);
extern int sas_slave_alloc(struct scsi_device *);
extern int sas_slave_configure(struct scsi_device *);
extern void sas_slave_destroy(struct scsi_device *);
extern int sas_change_queue_depth(struct scsi_device *, int new_depth);
extern int sas_change_queue_type(struct scsi_device *, int qt);
extern int sas_bios_param(struct scsi_device *,
struct block_device *,
sector_t capacity, int *hsc);
extern struct scsi_transport_template *
sas_domain_attach_transport(struct sas_domain_function_template *);
extern void sas_domain_release_transport(struct scsi_transport_template *);
int sas_discover_root_expander(struct domain_device *);
void sas_init_ex_attr(void);
int sas_ex_revalidate_domain(struct domain_device *);
void sas_unregister_domain_devices(struct asd_sas_port *port);
void sas_init_disc(struct sas_discovery *disc, struct asd_sas_port *);
int sas_discover_event(struct asd_sas_port *, enum discover_event ev);
int sas_discover_sata(struct domain_device *);
int sas_discover_end_dev(struct domain_device *);
void sas_unregister_dev(struct domain_device *);
void sas_init_dev(struct domain_device *);
void sas_task_abort(struct sas_task *);
int __sas_task_abort(struct sas_task *);
int sas_eh_device_reset_handler(struct scsi_cmnd *cmd);
int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd);
extern void sas_target_destroy(struct scsi_target *);
extern int sas_slave_alloc(struct scsi_device *);
extern int sas_ioctl(struct scsi_device *sdev, int cmd, void __user *arg);
extern int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
struct request *req);
extern void sas_ssp_task_response(struct device *dev, struct sas_task *task,
struct ssp_response_iu *iu);
struct sas_phy *sas_find_local_phy(struct domain_device *dev);
int sas_request_addr(struct Scsi_Host *shost, u8 *addr);
#endif /* _SASLIB_H_ */

View File

@@ -0,0 +1,77 @@
#ifndef __LIBSRP_H__
#define __LIBSRP_H__
#include <linux/list.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_host.h>
#include <scsi/srp.h>
enum iue_flags {
V_DIOVER,
V_WRITE,
V_LINKED,
V_FLYING,
};
struct srp_buf {
dma_addr_t dma;
void *buf;
};
struct srp_queue {
void *pool;
void *items;
struct kfifo *queue;
spinlock_t lock;
};
struct srp_target {
struct Scsi_Host *shost;
struct device *dev;
spinlock_t lock;
struct list_head cmd_queue;
size_t srp_iu_size;
struct srp_queue iu_queue;
size_t rx_ring_size;
struct srp_buf **rx_ring;
void *ldata;
};
struct iu_entry {
struct srp_target *target;
struct list_head ilist;
dma_addr_t remote_token;
unsigned long flags;
struct srp_buf *sbuf;
};
typedef int (srp_rdma_t)(struct scsi_cmnd *, struct scatterlist *, int,
struct srp_direct_buf *, int,
enum dma_data_direction, unsigned int);
extern int srp_target_alloc(struct srp_target *, struct device *, size_t, size_t);
extern void srp_target_free(struct srp_target *);
extern struct iu_entry *srp_iu_get(struct srp_target *);
extern void srp_iu_put(struct iu_entry *);
extern int srp_cmd_queue(struct Scsi_Host *, struct srp_cmd *, void *, u64, u64);
extern int srp_transfer_data(struct scsi_cmnd *, struct srp_cmd *,
srp_rdma_t, int, int);
static inline struct srp_target *host_to_srp_target(struct Scsi_Host *host)
{
return (struct srp_target *) host->hostdata;
}
static inline int srp_cmd_direction(struct srp_cmd *cmd)
{
return (cmd->buf_fmt >> 4) ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
}
#endif

View File

@@ -0,0 +1,397 @@
#ifndef __OSD_ATTRIBUTES_H__
#define __OSD_ATTRIBUTES_H__
#include "osd_protocol.h"
/*
* Contains types and constants that define attribute pages and attribute
* numbers and their data types.
*/
#define ATTR_SET(pg, id, l, ptr) \
{ .attr_page = pg, .attr_id = id, .len = l, .val_ptr = ptr }
#define ATTR_DEF(pg, id, l) ATTR_SET(pg, id, l, NULL)
/* osd-r10 4.7.3 Attributes pages */
enum {
OSD_APAGE_OBJECT_FIRST = 0x0,
OSD_APAGE_OBJECT_DIRECTORY = 0,
OSD_APAGE_OBJECT_INFORMATION = 1,
OSD_APAGE_OBJECT_QUOTAS = 2,
OSD_APAGE_OBJECT_TIMESTAMP = 3,
OSD_APAGE_OBJECT_COLLECTIONS = 4,
OSD_APAGE_OBJECT_SECURITY = 5,
OSD_APAGE_OBJECT_LAST = 0x2fffffff,
OSD_APAGE_PARTITION_FIRST = 0x30000000,
OSD_APAGE_PARTITION_DIRECTORY = OSD_APAGE_PARTITION_FIRST + 0,
OSD_APAGE_PARTITION_INFORMATION = OSD_APAGE_PARTITION_FIRST + 1,
OSD_APAGE_PARTITION_QUOTAS = OSD_APAGE_PARTITION_FIRST + 2,
OSD_APAGE_PARTITION_TIMESTAMP = OSD_APAGE_PARTITION_FIRST + 3,
OSD_APAGE_PARTITION_ATTR_ACCESS = OSD_APAGE_PARTITION_FIRST + 4,
OSD_APAGE_PARTITION_SECURITY = OSD_APAGE_PARTITION_FIRST + 5,
OSD_APAGE_PARTITION_LAST = 0x5FFFFFFF,
OSD_APAGE_COLLECTION_FIRST = 0x60000000,
OSD_APAGE_COLLECTION_DIRECTORY = OSD_APAGE_COLLECTION_FIRST + 0,
OSD_APAGE_COLLECTION_INFORMATION = OSD_APAGE_COLLECTION_FIRST + 1,
OSD_APAGE_COLLECTION_TIMESTAMP = OSD_APAGE_COLLECTION_FIRST + 3,
OSD_APAGE_COLLECTION_SECURITY = OSD_APAGE_COLLECTION_FIRST + 5,
OSD_APAGE_COLLECTION_LAST = 0x8FFFFFFF,
OSD_APAGE_ROOT_FIRST = 0x90000000,
OSD_APAGE_ROOT_DIRECTORY = OSD_APAGE_ROOT_FIRST + 0,
OSD_APAGE_ROOT_INFORMATION = OSD_APAGE_ROOT_FIRST + 1,
OSD_APAGE_ROOT_QUOTAS = OSD_APAGE_ROOT_FIRST + 2,
OSD_APAGE_ROOT_TIMESTAMP = OSD_APAGE_ROOT_FIRST + 3,
OSD_APAGE_ROOT_SECURITY = OSD_APAGE_ROOT_FIRST + 5,
OSD_APAGE_ROOT_LAST = 0xBFFFFFFF,
OSD_APAGE_RESERVED_TYPE_FIRST = 0xC0000000,
OSD_APAGE_RESERVED_TYPE_LAST = 0xEFFFFFFF,
OSD_APAGE_COMMON_FIRST = 0xF0000000,
OSD_APAGE_COMMON_LAST = 0xFFFFFFFD,
OSD_APAGE_CURRENT_COMMAND = 0xFFFFFFFE,
OSD_APAGE_REQUEST_ALL = 0xFFFFFFFF,
};
/* subcategories of attr pages within each range above */
enum {
OSD_APAGE_STD_FIRST = 0x0,
OSD_APAGE_STD_DIRECTORY = 0,
OSD_APAGE_STD_INFORMATION = 1,
OSD_APAGE_STD_QUOTAS = 2,
OSD_APAGE_STD_TIMESTAMP = 3,
OSD_APAGE_STD_COLLECTIONS = 4,
OSD_APAGE_STD_POLICY_SECURITY = 5,
OSD_APAGE_STD_LAST = 0x0000007F,
OSD_APAGE_RESERVED_FIRST = 0x00000080,
OSD_APAGE_RESERVED_LAST = 0x00007FFF,
OSD_APAGE_OTHER_STD_FIRST = 0x00008000,
OSD_APAGE_OTHER_STD_LAST = 0x0000EFFF,
OSD_APAGE_PUBLIC_FIRST = 0x0000F000,
OSD_APAGE_PUBLIC_LAST = 0x0000FFFF,
OSD_APAGE_APP_DEFINED_FIRST = 0x00010000,
OSD_APAGE_APP_DEFINED_LAST = 0x1FFFFFFF,
OSD_APAGE_VENDOR_SPECIFIC_FIRST = 0x20000000,
OSD_APAGE_VENDOR_SPECIFIC_LAST = 0x2FFFFFFF,
};
enum {
OSD_ATTR_PAGE_IDENTIFICATION = 0, /* in all pages 40 bytes */
};
struct page_identification {
u8 vendor_identification[8];
u8 page_identification[32];
} __packed;
struct osd_attr_page_header {
__be32 page_number;
__be32 page_length;
} __packed;
/* 7.1.2.8 Root Information attributes page (OSD_APAGE_ROOT_INFORMATION) */
enum {
OSD_ATTR_RI_OSD_SYSTEM_ID = 0x3, /* 20 */
OSD_ATTR_RI_VENDOR_IDENTIFICATION = 0x4, /* 8 */
OSD_ATTR_RI_PRODUCT_IDENTIFICATION = 0x5, /* 16 */
OSD_ATTR_RI_PRODUCT_MODEL = 0x6, /* 32 */
OSD_ATTR_RI_PRODUCT_REVISION_LEVEL = 0x7, /* 4 */
OSD_ATTR_RI_PRODUCT_SERIAL_NUMBER = 0x8, /* variable */
OSD_ATTR_RI_OSD_NAME = 0x9, /* variable */
OSD_ATTR_RI_MAX_CDB_CONTINUATION_LEN = 0xA, /* 4 */
OSD_ATTR_RI_TOTAL_CAPACITY = 0x80, /* 8 */
OSD_ATTR_RI_USED_CAPACITY = 0x81, /* 8 */
OSD_ATTR_RI_NUMBER_OF_PARTITIONS = 0xC0, /* 8 */
OSD_ATTR_RI_CLOCK = 0x100, /* 6 */
OARI_DEFAULT_ISOLATION_METHOD = 0X110, /* 1 */
OARI_SUPPORTED_ISOLATION_METHODS = 0X111, /* 32 */
OARI_DATA_ATOMICITY_GUARANTEE = 0X120, /* 8 */
OARI_DATA_ATOMICITY_ALIGNMENT = 0X121, /* 8 */
OARI_ATTRIBUTES_ATOMICITY_GUARANTEE = 0X122, /* 8 */
OARI_DATA_ATTRIBUTES_ATOMICITY_MULTIPLIER = 0X123, /* 1 */
OARI_MAXIMUM_SNAPSHOTS_COUNT = 0X1C1, /* 0 or 4 */
OARI_MAXIMUM_CLONES_COUNT = 0X1C2, /* 0 or 4 */
OARI_MAXIMUM_BRANCH_DEPTH = 0X1CC, /* 0 or 4 */
OARI_SUPPORTED_OBJECT_DUPLICATION_METHOD_FIRST = 0X200, /* 0 or 4 */
OARI_SUPPORTED_OBJECT_DUPLICATION_METHOD_LAST = 0X2ff, /* 0 or 4 */
OARI_SUPPORTED_TIME_OF_DUPLICATION_METHOD_FIRST = 0X300, /* 0 or 4 */
OARI_SUPPORTED_TIME_OF_DUPLICATION_METHOD_LAST = 0X30F, /* 0 or 4 */
OARI_SUPPORT_FOR_DUPLICATED_OBJECT_FREEZING = 0X310, /* 0 or 4 */
OARI_SUPPORT_FOR_SNAPSHOT_REFRESHING = 0X311, /* 0 or 1 */
OARI_SUPPORTED_CDB_CONTINUATION_DESC_TYPE_FIRST = 0X7000001,/* 0 or 4 */
OARI_SUPPORTED_CDB_CONTINUATION_DESC_TYPE_LAST = 0X700FFFF,/* 0 or 4 */
};
/* Root_Information_attributes_page does not have a get_page structure */
/* 7.1.2.9 Partition Information attributes page
* (OSD_APAGE_PARTITION_INFORMATION)
*/
enum {
OSD_ATTR_PI_PARTITION_ID = 0x1, /* 8 */
OSD_ATTR_PI_USERNAME = 0x9, /* variable */
OSD_ATTR_PI_USED_CAPACITY = 0x81, /* 8 */
OSD_ATTR_PI_USED_CAPACITY_INCREMENT = 0x84, /* 0 or 8 */
OSD_ATTR_PI_NUMBER_OF_OBJECTS = 0xC1, /* 8 */
OSD_ATTR_PI_ACTUAL_DATA_SPACE = 0xD1, /* 0 or 8 */
OSD_ATTR_PI_RESERVED_DATA_SPACE = 0xD2, /* 0 or 8 */
OSD_ATTR_PI_DEFAULT_SNAPSHOT_DUPLICATION_METHOD = 0x200,/* 0 or 4 */
OSD_ATTR_PI_DEFAULT_CLONE_DUPLICATION_METHOD = 0x201,/* 0 or 4 */
OSD_ATTR_PI_DEFAULT_SP_TIME_OF_DUPLICATION = 0x300,/* 0 or 4 */
OSD_ATTR_PI_DEFAULT_CLONE_TIME_OF_DUPLICATION = 0x301,/* 0 or 4 */
};
/* Partition Information attributes page does not have a get_page structure */
/* 7.1.2.10 Collection Information attributes page
* (OSD_APAGE_COLLECTION_INFORMATION)
*/
enum {
OSD_ATTR_CI_PARTITION_ID = 0x1, /* 8 */
OSD_ATTR_CI_COLLECTION_OBJECT_ID = 0x2, /* 8 */
OSD_ATTR_CI_USERNAME = 0x9, /* variable */
OSD_ATTR_CI_COLLECTION_TYPE = 0xA, /* 1 */
OSD_ATTR_CI_USED_CAPACITY = 0x81, /* 8 */
};
/* Collection Information attributes page does not have a get_page structure */
/* 7.1.2.11 User Object Information attributes page
* (OSD_APAGE_OBJECT_INFORMATION)
*/
enum {
OSD_ATTR_OI_PARTITION_ID = 0x1, /* 8 */
OSD_ATTR_OI_OBJECT_ID = 0x2, /* 8 */
OSD_ATTR_OI_USERNAME = 0x9, /* variable */
OSD_ATTR_OI_USED_CAPACITY = 0x81, /* 8 */
OSD_ATTR_OI_LOGICAL_LENGTH = 0x82, /* 8 */
SD_ATTR_OI_ACTUAL_DATA_SPACE = 0XD1, /* 0 OR 8 */
SD_ATTR_OI_RESERVED_DATA_SPACE = 0XD2, /* 0 OR 8 */
};
/* Object Information attributes page does not have a get_page structure */
/* 7.1.2.12 Root Quotas attributes page (OSD_APAGE_ROOT_QUOTAS) */
enum {
OSD_ATTR_RQ_DEFAULT_MAXIMUM_USER_OBJECT_LENGTH = 0x1, /* 8 */
OSD_ATTR_RQ_PARTITION_CAPACITY_QUOTA = 0x10001, /* 8 */
OSD_ATTR_RQ_PARTITION_OBJECT_COUNT = 0x10002, /* 8 */
OSD_ATTR_RQ_PARTITION_COLLECTIONS_PER_USER_OBJECT = 0x10081, /* 4 */
OSD_ATTR_RQ_PARTITION_COUNT = 0x20002, /* 8 */
};
struct Root_Quotas_attributes_page {
struct osd_attr_page_header hdr; /* id=R+2, size=0x24 */
__be64 default_maximum_user_object_length;
__be64 partition_capacity_quota;
__be64 partition_object_count;
__be64 partition_collections_per_user_object;
__be64 partition_count;
} __packed;
/* 7.1.2.13 Partition Quotas attributes page (OSD_APAGE_PARTITION_QUOTAS)*/
enum {
OSD_ATTR_PQ_DEFAULT_MAXIMUM_USER_OBJECT_LENGTH = 0x1, /* 8 */
OSD_ATTR_PQ_CAPACITY_QUOTA = 0x10001, /* 8 */
OSD_ATTR_PQ_OBJECT_COUNT = 0x10002, /* 8 */
OSD_ATTR_PQ_COLLECTIONS_PER_USER_OBJECT = 0x10081, /* 4 */
};
struct Partition_Quotas_attributes_page {
struct osd_attr_page_header hdr; /* id=P+2, size=0x1C */
__be64 default_maximum_user_object_length;
__be64 capacity_quota;
__be64 object_count;
__be64 collections_per_user_object;
} __packed;
/* 7.1.2.14 User Object Quotas attributes page (OSD_APAGE_OBJECT_QUOTAS) */
enum {
OSD_ATTR_OQ_MAXIMUM_LENGTH = 0x1, /* 8 */
};
struct Object_Quotas_attributes_page {
struct osd_attr_page_header hdr; /* id=U+2, size=0x8 */
__be64 maximum_length;
} __packed;
/* 7.1.2.15 Root Timestamps attributes page (OSD_APAGE_ROOT_TIMESTAMP) */
enum {
OSD_ATTR_RT_ATTRIBUTES_ACCESSED_TIME = 0x2, /* 6 */
OSD_ATTR_RT_ATTRIBUTES_MODIFIED_TIME = 0x3, /* 6 */
OSD_ATTR_RT_TIMESTAMP_BYPASS = 0xFFFFFFFE, /* 1 */
};
struct root_timestamps_attributes_page {
struct osd_attr_page_header hdr; /* id=R+3, size=0xD */
struct osd_timestamp attributes_accessed_time;
struct osd_timestamp attributes_modified_time;
u8 timestamp_bypass;
} __packed;
/* 7.1.2.16 Partition Timestamps attributes page
* (OSD_APAGE_PARTITION_TIMESTAMP)
*/
enum {
OSD_ATTR_PT_CREATED_TIME = 0x1, /* 6 */
OSD_ATTR_PT_ATTRIBUTES_ACCESSED_TIME = 0x2, /* 6 */
OSD_ATTR_PT_ATTRIBUTES_MODIFIED_TIME = 0x3, /* 6 */
OSD_ATTR_PT_DATA_ACCESSED_TIME = 0x4, /* 6 */
OSD_ATTR_PT_DATA_MODIFIED_TIME = 0x5, /* 6 */
OSD_ATTR_PT_TIMESTAMP_BYPASS = 0xFFFFFFFE, /* 1 */
};
struct partition_timestamps_attributes_page {
struct osd_attr_page_header hdr; /* id=P+3, size=0x1F */
struct osd_timestamp created_time;
struct osd_timestamp attributes_accessed_time;
struct osd_timestamp attributes_modified_time;
struct osd_timestamp data_accessed_time;
struct osd_timestamp data_modified_time;
u8 timestamp_bypass;
} __packed;
/* 7.1.2.17/18 Collection/Object Timestamps attributes page
* (OSD_APAGE_COLLECTION_TIMESTAMP/OSD_APAGE_OBJECT_TIMESTAMP)
*/
enum {
OSD_ATTR_OT_CREATED_TIME = 0x1, /* 6 */
OSD_ATTR_OT_ATTRIBUTES_ACCESSED_TIME = 0x2, /* 6 */
OSD_ATTR_OT_ATTRIBUTES_MODIFIED_TIME = 0x3, /* 6 */
OSD_ATTR_OT_DATA_ACCESSED_TIME = 0x4, /* 6 */
OSD_ATTR_OT_DATA_MODIFIED_TIME = 0x5, /* 6 */
};
/* same for collection */
struct object_timestamps_attributes_page {
struct osd_attr_page_header hdr; /* id=C+3/3, size=0x1E */
struct osd_timestamp created_time;
struct osd_timestamp attributes_accessed_time;
struct osd_timestamp attributes_modified_time;
struct osd_timestamp data_accessed_time;
struct osd_timestamp data_modified_time;
} __packed;
/* OSD2r05: 7.1.3.19 Attributes Access attributes page
* (OSD_APAGE_PARTITION_ATTR_ACCESS)
*
* each attribute is of the form below. Total array length is deduced
* from the attribute's length
* (See allowed_attributes_access of the struct osd_cap_object_descriptor)
*/
struct attributes_access_attr {
struct osd_attributes_list_attrid attr_list[0];
} __packed;
/* OSD2r05: 7.1.2.21 Collections attributes page */
/* TBD */
/* 7.1.2.20 Root Policy/Security attributes page (OSD_APAGE_ROOT_SECURITY) */
enum {
OSD_ATTR_RS_DEFAULT_SECURITY_METHOD = 0x1, /* 1 */
OSD_ATTR_RS_OLDEST_VALID_NONCE_LIMIT = 0x2, /* 6 */
OSD_ATTR_RS_NEWEST_VALID_NONCE_LIMIT = 0x3, /* 6 */
OSD_ATTR_RS_PARTITION_DEFAULT_SECURITY_METHOD = 0x6, /* 1 */
OSD_ATTR_RS_SUPPORTED_SECURITY_METHODS = 0x7, /* 2 */
OSD_ATTR_RS_ADJUSTABLE_CLOCK = 0x9, /* 6 */
OSD_ATTR_RS_MASTER_KEY_IDENTIFIER = 0x7FFD, /* 0 or 7 */
OSD_ATTR_RS_ROOT_KEY_IDENTIFIER = 0x7FFE, /* 0 or 7 */
OSD_ATTR_RS_SUPPORTED_INTEGRITY_ALGORITHM_0 = 0x80000000,/* 1,(x16)*/
OSD_ATTR_RS_SUPPORTED_DH_GROUP_0 = 0x80000010,/* 1,(x16)*/
};
struct root_security_attributes_page {
struct osd_attr_page_header hdr; /* id=R+5, size=0x3F */
u8 default_security_method;
u8 partition_default_security_method;
__be16 supported_security_methods;
u8 mki_valid_rki_valid;
struct osd_timestamp oldest_valid_nonce_limit;
struct osd_timestamp newest_valid_nonce_limit;
struct osd_timestamp adjustable_clock;
u8 master_key_identifier[32-25];
u8 root_key_identifier[39-32];
u8 supported_integrity_algorithm[16];
u8 supported_dh_group[16];
} __packed;
/* 7.1.2.21 Partition Policy/Security attributes page
* (OSD_APAGE_PARTITION_SECURITY)
*/
enum {
OSD_ATTR_PS_DEFAULT_SECURITY_METHOD = 0x1, /* 1 */
OSD_ATTR_PS_OLDEST_VALID_NONCE = 0x2, /* 6 */
OSD_ATTR_PS_NEWEST_VALID_NONCE = 0x3, /* 6 */
OSD_ATTR_PS_REQUEST_NONCE_LIST_DEPTH = 0x4, /* 2 */
OSD_ATTR_PS_FROZEN_WORKING_KEY_BIT_MASK = 0x5, /* 2 */
OSD_ATTR_PS_PARTITION_KEY_IDENTIFIER = 0x7FFF, /* 0 or 7 */
OSD_ATTR_PS_WORKING_KEY_IDENTIFIER_FIRST = 0x8000, /* 0 or 7 */
OSD_ATTR_PS_WORKING_KEY_IDENTIFIER_LAST = 0x800F, /* 0 or 7 */
OSD_ATTR_PS_POLICY_ACCESS_TAG = 0x40000001, /* 4 */
OSD_ATTR_PS_USER_OBJECT_POLICY_ACCESS_TAG = 0x40000002, /* 4 */
};
struct partition_security_attributes_page {
struct osd_attr_page_header hdr; /* id=p+5, size=0x8f */
u8 reserved[3];
u8 default_security_method;
struct osd_timestamp oldest_valid_nonce;
struct osd_timestamp newest_valid_nonce;
__be16 request_nonce_list_depth;
__be16 frozen_working_key_bit_mask;
__be32 policy_access_tag;
__be32 user_object_policy_access_tag;
u8 pki_valid;
__be16 wki_00_0f_vld;
struct osd_key_identifier partition_key_identifier;
struct osd_key_identifier working_key_identifiers[16];
} __packed;
/* 7.1.2.22/23 Collection/Object Policy-Security attributes page
* (OSD_APAGE_COLLECTION_SECURITY/OSD_APAGE_OBJECT_SECURITY)
*/
enum {
OSD_ATTR_OS_POLICY_ACCESS_TAG = 0x40000001, /* 4 */
};
struct object_security_attributes_page {
struct osd_attr_page_header hdr; /* id=C+5/5, size=4 */
__be32 policy_access_tag;
} __packed;
/* OSD2r05: 7.1.3.31 Current Command attributes page
* (OSD_APAGE_CURRENT_COMMAND)
*/
enum {
OSD_ATTR_CC_RESPONSE_INTEGRITY_CHECK_VALUE = 0x1, /* 32 */
OSD_ATTR_CC_OBJECT_TYPE = 0x2, /* 1 */
OSD_ATTR_CC_PARTITION_ID = 0x3, /* 8 */
OSD_ATTR_CC_OBJECT_ID = 0x4, /* 8 */
OSD_ATTR_CC_STARTING_BYTE_ADDRESS_OF_APPEND = 0x5, /* 8 */
OSD_ATTR_CC_CHANGE_IN_USED_CAPACITY = 0x6, /* 8 */
};
/*TBD: osdv1_current_command_attributes_page */
struct osdv2_current_command_attributes_page {
struct osd_attr_page_header hdr; /* id=0xFFFFFFFE, size=0x44 */
u8 response_integrity_check_value[OSD_CRYPTO_KEYID_SIZE];
u8 object_type;
u8 reserved[3];
__be64 partition_id;
__be64 object_id;
__be64 starting_byte_address_of_append;
__be64 change_in_used_capacity;
};
#endif /*ndef __OSD_ATTRIBUTES_H__*/

View File

@@ -0,0 +1,443 @@
/*
* osd_initiator.h - OSD initiator API definition
*
* Copyright (C) 2008 Panasas Inc. All rights reserved.
*
* Authors:
* Boaz Harrosh <bharrosh@panasas.com>
* Benny Halevy <bhalevy@panasas.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
*
*/
#ifndef __OSD_INITIATOR_H__
#define __OSD_INITIATOR_H__
#include "osd_protocol.h"
#include "osd_types.h"
#include <linux/blkdev.h>
#include <scsi/scsi_device.h>
/* Note: "NI" in comments below means "Not Implemented yet" */
/* Configure of code:
* #undef if you *don't* want OSD v1 support in runtime.
* If #defined the initiator will dynamically configure to encode OSD v1
* CDB's if the target is detected to be OSD v1 only.
* OSD v2 only commands, options, and attributes will be ignored if target
* is v1 only.
* If #defined will result in bigger/slower code (OK Slower maybe not)
* Q: Should this be CONFIG_SCSI_OSD_VER1_SUPPORT and set from Kconfig?
*/
#define OSD_VER1_SUPPORT y
enum osd_std_version {
OSD_VER_NONE = 0,
OSD_VER1 = 1,
OSD_VER2 = 2,
};
/*
* Object-based Storage Device.
* This object represents an OSD device.
* It is not a full linux device in any way. It is only
* a place to hang resources associated with a Linux
* request Q and some default properties.
*/
struct osd_dev {
struct scsi_device *scsi_device;
struct file *file;
unsigned def_timeout;
#ifdef OSD_VER1_SUPPORT
enum osd_std_version version;
#endif
};
/* Retrieve/return osd_dev(s) for use by Kernel clients */
struct osd_dev *osduld_path_lookup(const char *dev_name); /*Use IS_ERR/ERR_PTR*/
void osduld_put_device(struct osd_dev *od);
/* Add/remove test ioctls from external modules */
typedef int (do_test_fn)(struct osd_dev *od, unsigned cmd, unsigned long arg);
int osduld_register_test(unsigned ioctl, do_test_fn *do_test);
void osduld_unregister_test(unsigned ioctl);
/* These are called by uld at probe time */
void osd_dev_init(struct osd_dev *od, struct scsi_device *scsi_device);
void osd_dev_fini(struct osd_dev *od);
/* some hi level device operations */
int osd_auto_detect_ver(struct osd_dev *od, void *caps); /* GFP_KERNEL */
static inline struct request_queue *osd_request_queue(struct osd_dev *od)
{
return od->scsi_device->request_queue;
}
/* we might want to use function vector in the future */
static inline void osd_dev_set_ver(struct osd_dev *od, enum osd_std_version v)
{
#ifdef OSD_VER1_SUPPORT
od->version = v;
#endif
}
struct osd_request;
typedef void (osd_req_done_fn)(struct osd_request *or, void *private);
struct osd_request {
struct osd_cdb cdb;
struct osd_data_out_integrity_info out_data_integ;
struct osd_data_in_integrity_info in_data_integ;
struct osd_dev *osd_dev;
struct request *request;
struct _osd_req_data_segment {
void *buff;
unsigned alloc_size; /* 0 here means: don't call kfree */
unsigned total_bytes;
} set_attr, enc_get_attr, get_attr;
struct _osd_io_info {
struct bio *bio;
u64 total_bytes;
struct request *req;
struct _osd_req_data_segment *last_seg;
u8 *pad_buff;
} out, in;
gfp_t alloc_flags;
unsigned timeout;
unsigned retries;
u8 sense[OSD_MAX_SENSE_LEN];
enum osd_attributes_mode attributes_mode;
osd_req_done_fn *async_done;
void *async_private;
int async_error;
};
/* OSD Version control */
static inline bool osd_req_is_ver1(struct osd_request *or)
{
#ifdef OSD_VER1_SUPPORT
return or->osd_dev->version == OSD_VER1;
#else
return false;
#endif
}
/*
* How to use the osd library:
*
* osd_start_request
* Allocates a request.
*
* osd_req_*
* Call one of, to encode the desired operation.
*
* osd_add_{get,set}_attr
* Optionally add attributes to the CDB, list or page mode.
*
* osd_finalize_request
* Computes final data out/in offsets and signs the request,
* making it ready for execution.
*
* osd_execute_request
* May be called to execute it through the block layer. Other wise submit
* the associated block request in some other way.
*
* After execution:
* osd_req_decode_sense
* Decodes sense information to verify execution results.
*
* osd_req_decode_get_attr
* Retrieve osd_add_get_attr_list() values if used.
*
* osd_end_request
* Must be called to deallocate the request.
*/
/**
* osd_start_request - Allocate and initialize an osd_request
*
* @osd_dev: OSD device that holds the scsi-device and default values
* that the request is associated with.
* @gfp: The allocation flags to use for request allocation, and all
* subsequent allocations. This will be stored at
* osd_request->alloc_flags, can be changed by user later
*
* Allocate osd_request and initialize all members to the
* default/initial state.
*/
struct osd_request *osd_start_request(struct osd_dev *od, gfp_t gfp);
enum osd_req_options {
OSD_REQ_FUA = 0x08, /* Force Unit Access */
OSD_REQ_DPO = 0x10, /* Disable Page Out */
OSD_REQ_BYPASS_TIMESTAMPS = 0x80,
};
/**
* osd_finalize_request - Sign request and prepare request for execution
*
* @or: osd_request to prepare
* @options: combination of osd_req_options bit flags or 0.
* @cap: A Pointer to an OSD_CAP_LEN bytes buffer that is received from
* The security manager as capabilities for this cdb.
* @cap_key: The cryptographic key used to sign the cdb/data. Can be null
* if NOSEC is used.
*
* The actual request and bios are only allocated here, so are the get_attr
* buffers that will receive the returned attributes. Copy's @cap to cdb.
* Sign the cdb/data with @cap_key.
*/
int osd_finalize_request(struct osd_request *or,
u8 options, const void *cap, const u8 *cap_key);
/**
* osd_execute_request - Execute the request synchronously through block-layer
*
* @or: osd_request to Executed
*
* Calls blk_execute_rq to q the command and waits for completion.
*/
int osd_execute_request(struct osd_request *or);
/**
* osd_execute_request_async - Execute the request without waitting.
*
* @or: - osd_request to Executed
* @done: (Optional) - Called at end of execution
* @private: - Will be passed to @done function
*
* Calls blk_execute_rq_nowait to queue the command. When execution is done
* optionally calls @done with @private as parameter. @or->async_error will
* have the return code
*/
int osd_execute_request_async(struct osd_request *or,
osd_req_done_fn *done, void *private);
/**
* osd_req_decode_sense_full - Decode sense information after execution.
*
* @or: - osd_request to examine
* @osi - Recievs a more detailed error report information (optional).
* @silent - Do not print to dmsg (Even if enabled)
* @bad_obj_list - Some commands act on multiple objects. Failed objects will
* be recieved here (optional)
* @max_obj - Size of @bad_obj_list.
* @bad_attr_list - List of failing attributes (optional)
* @max_attr - Size of @bad_attr_list.
*
* After execution, sense + return code can be analyzed using this function. The
* return code is the final disposition on the error. So it is possible that a
* CHECK_CONDITION was returned from target but this will return NO_ERROR, for
* example on recovered errors. All parameters are optional if caller does
* not need any returned information.
* Note: This function will also dump the error to dmsg according to settings
* of the SCSI_OSD_DPRINT_SENSE Kconfig value. Set @silent if you know the
* command would routinely fail, to not spam the dmsg file.
*/
struct osd_sense_info {
int key; /* one of enum scsi_sense_keys */
int additional_code ; /* enum osd_additional_sense_codes */
union { /* Sense specific information */
u16 sense_info;
u16 cdb_field_offset; /* scsi_invalid_field_in_cdb */
};
union { /* Command specific information */
u64 command_info;
};
u32 not_initiated_command_functions; /* osd_command_functions_bits */
u32 completed_command_functions; /* osd_command_functions_bits */
struct osd_obj_id obj;
struct osd_attr attr;
};
int osd_req_decode_sense_full(struct osd_request *or,
struct osd_sense_info *osi, bool silent,
struct osd_obj_id *bad_obj_list, int max_obj,
struct osd_attr *bad_attr_list, int max_attr);
static inline int osd_req_decode_sense(struct osd_request *or,
struct osd_sense_info *osi)
{
return osd_req_decode_sense_full(or, osi, false, NULL, 0, NULL, 0);
}
/**
* osd_end_request - return osd_request to free store
*
* @or: osd_request to free
*
* Deallocate all osd_request resources (struct req's, BIOs, buffers, etc.)
*/
void osd_end_request(struct osd_request *or);
/*
* CDB Encoding
*
* Note: call only one of the following methods.
*/
/*
* Device commands
*/
void osd_req_set_master_seed_xchg(struct osd_request *or, ...);/* NI */
void osd_req_set_master_key(struct osd_request *or, ...);/* NI */
void osd_req_format(struct osd_request *or, u64 tot_capacity);
/* list all partitions
* @list header must be initialized to zero on first run.
*
* Call osd_is_obj_list_done() to find if we got the complete list.
*/
int osd_req_list_dev_partitions(struct osd_request *or,
osd_id initial_id, struct osd_obj_id_list *list, unsigned nelem);
void osd_req_flush_obsd(struct osd_request *or,
enum osd_options_flush_scope_values);
void osd_req_perform_scsi_command(struct osd_request *or,
const u8 *cdb, ...);/* NI */
void osd_req_task_management(struct osd_request *or, ...);/* NI */
/*
* Partition commands
*/
void osd_req_create_partition(struct osd_request *or, osd_id partition);
void osd_req_remove_partition(struct osd_request *or, osd_id partition);
void osd_req_set_partition_key(struct osd_request *or,
osd_id partition, u8 new_key_id[OSD_CRYPTO_KEYID_SIZE],
u8 seed[OSD_CRYPTO_SEED_SIZE]);/* NI */
/* list all collections in the partition
* @list header must be init to zero on first run.
*
* Call osd_is_obj_list_done() to find if we got the complete list.
*/
int osd_req_list_partition_collections(struct osd_request *or,
osd_id partition, osd_id initial_id, struct osd_obj_id_list *list,
unsigned nelem);
/* list all objects in the partition
* @list header must be init to zero on first run.
*
* Call osd_is_obj_list_done() to find if we got the complete list.
*/
int osd_req_list_partition_objects(struct osd_request *or,
osd_id partition, osd_id initial_id, struct osd_obj_id_list *list,
unsigned nelem);
void osd_req_flush_partition(struct osd_request *or,
osd_id partition, enum osd_options_flush_scope_values);
/*
* Collection commands
*/
void osd_req_create_collection(struct osd_request *or,
const struct osd_obj_id *);/* NI */
void osd_req_remove_collection(struct osd_request *or,
const struct osd_obj_id *);/* NI */
/* list all objects in the collection */
int osd_req_list_collection_objects(struct osd_request *or,
const struct osd_obj_id *, osd_id initial_id,
struct osd_obj_id_list *list, unsigned nelem);
/* V2 only filtered list of objects in the collection */
void osd_req_query(struct osd_request *or, ...);/* NI */
void osd_req_flush_collection(struct osd_request *or,
const struct osd_obj_id *, enum osd_options_flush_scope_values);
void osd_req_get_member_attrs(struct osd_request *or, ...);/* V2-only NI */
void osd_req_set_member_attrs(struct osd_request *or, ...);/* V2-only NI */
/*
* Object commands
*/
void osd_req_create_object(struct osd_request *or, struct osd_obj_id *);
void osd_req_remove_object(struct osd_request *or, struct osd_obj_id *);
void osd_req_write(struct osd_request *or,
const struct osd_obj_id *obj, u64 offset, struct bio *bio, u64 len);
int osd_req_write_kern(struct osd_request *or,
const struct osd_obj_id *obj, u64 offset, void *buff, u64 len);
void osd_req_append(struct osd_request *or,
const struct osd_obj_id *, struct bio *data_out);/* NI */
void osd_req_create_write(struct osd_request *or,
const struct osd_obj_id *, struct bio *data_out, u64 offset);/* NI */
void osd_req_clear(struct osd_request *or,
const struct osd_obj_id *, u64 offset, u64 len);/* NI */
void osd_req_punch(struct osd_request *or,
const struct osd_obj_id *, u64 offset, u64 len);/* V2-only NI */
void osd_req_flush_object(struct osd_request *or,
const struct osd_obj_id *, enum osd_options_flush_scope_values,
/*V2*/ u64 offset, /*V2*/ u64 len);
void osd_req_read(struct osd_request *or,
const struct osd_obj_id *obj, u64 offset, struct bio *bio, u64 len);
int osd_req_read_kern(struct osd_request *or,
const struct osd_obj_id *obj, u64 offset, void *buff, u64 len);
/*
* Root/Partition/Collection/Object Attributes commands
*/
/* get before set */
void osd_req_get_attributes(struct osd_request *or, const struct osd_obj_id *);
/* set before get */
void osd_req_set_attributes(struct osd_request *or, const struct osd_obj_id *);
/*
* Attributes appended to most commands
*/
/* Attributes List mode (or V2 CDB) */
/*
* TODO: In ver2 if at finalize time only one attr was set and no gets,
* then the Attributes CDB mode is used automatically to save IO.
*/
/* set a list of attributes. */
int osd_req_add_set_attr_list(struct osd_request *or,
const struct osd_attr *, unsigned nelem);
/* get a list of attributes */
int osd_req_add_get_attr_list(struct osd_request *or,
const struct osd_attr *, unsigned nelem);
/*
* Attributes list decoding
* Must be called after osd_request.request was executed
* It is called in a loop to decode the returned get_attr
* (see osd_add_get_attr)
*/
int osd_req_decode_get_attr_list(struct osd_request *or,
struct osd_attr *, int *nelem, void **iterator);
/* Attributes Page mode */
/*
* Read an attribute page and optionally set one attribute
*
* Retrieves the attribute page directly to a user buffer.
* @attr_page_data shall stay valid until end of execution.
* See osd_attributes.h for common page structures
*/
int osd_req_add_get_attr_page(struct osd_request *or,
u32 page_id, void *attr_page_data, unsigned max_page_len,
const struct osd_attr *set_one);
#endif /* __OSD_LIB_H__ */

View File

@@ -0,0 +1,634 @@
/*
* osd_protocol.h - OSD T10 standard C definitions.
*
* Copyright (C) 2008 Panasas Inc. All rights reserved.
*
* Authors:
* Boaz Harrosh <bharrosh@panasas.com>
* Benny Halevy <bhalevy@panasas.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
*
* This file contains types and constants that are defined by the protocol
* Note: All names and symbols are taken from the OSD standard's text.
*/
#ifndef __OSD_PROTOCOL_H__
#define __OSD_PROTOCOL_H__
#include <linux/types.h>
#include <linux/kernel.h>
#include <asm/unaligned.h>
#include <scsi/scsi.h>
enum {
OSDv1_ADDITIONAL_CDB_LENGTH = 192,
OSDv1_TOTAL_CDB_LEN = OSDv1_ADDITIONAL_CDB_LENGTH + 8,
OSDv1_CAP_LEN = 80,
/* Latest supported version */
OSDv2_ADDITIONAL_CDB_LENGTH = 228,
OSD_ADDITIONAL_CDB_LENGTH =
OSDv2_ADDITIONAL_CDB_LENGTH,
OSD_TOTAL_CDB_LEN = OSD_ADDITIONAL_CDB_LENGTH + 8,
OSD_CAP_LEN = 104,
OSD_SYSTEMID_LEN = 20,
OSDv1_CRYPTO_KEYID_SIZE = 20,
OSDv2_CRYPTO_KEYID_SIZE = 32,
OSD_CRYPTO_KEYID_SIZE = OSDv2_CRYPTO_KEYID_SIZE,
OSD_CRYPTO_SEED_SIZE = 4,
OSD_CRYPTO_NONCE_SIZE = 12,
OSD_MAX_SENSE_LEN = 252, /* from SPC-3 */
OSD_PARTITION_FIRST_ID = 0x10000,
OSD_OBJECT_FIRST_ID = 0x10000,
};
/* (osd-r10 5.2.4)
* osd2r03: 5.2.3 Caching control bits
*/
enum osd_options_byte {
OSD_CDB_FUA = 0x08, /* Force Unit Access */
OSD_CDB_DPO = 0x10, /* Disable Page Out */
};
/*
* osd2r03: 5.2.5 Isolation.
* First 3 bits, V2-only.
* Also for attr 110h "default isolation method" at Root Information page
*/
enum osd_options_byte_isolation {
OSD_ISOLATION_DEFAULT = 0,
OSD_ISOLATION_NONE = 1,
OSD_ISOLATION_STRICT = 2,
OSD_ISOLATION_RANGE = 4,
OSD_ISOLATION_FUNCTIONAL = 5,
OSD_ISOLATION_VENDOR = 7,
};
/* (osd-r10: 6.7)
* osd2r03: 6.8 FLUSH, FLUSH COLLECTION, FLUSH OSD, FLUSH PARTITION
*/
enum osd_options_flush_scope_values {
OSD_CDB_FLUSH_ALL = 0,
OSD_CDB_FLUSH_ATTR_ONLY = 1,
OSD_CDB_FLUSH_ALL_RECURSIVE = 2,
/* V2-only */
OSD_CDB_FLUSH_ALL_RANGE = 2,
};
/* osd2r03: 5.2.10 Timestamps control */
enum {
OSD_CDB_NORMAL_TIMESTAMPS = 0,
OSD_CDB_BYPASS_TIMESTAMPS = 0x7f,
};
/* (osd-r10: 5.2.2.1)
* osd2r03: 5.2.4.1 Get and set attributes CDB format selection
* 2 bits at second nibble of command_specific_options byte
*/
enum osd_attributes_mode {
/* V2-only */
OSD_CDB_SET_ONE_ATTR = 0x10,
OSD_CDB_GET_ATTR_PAGE_SET_ONE = 0x20,
OSD_CDB_GET_SET_ATTR_LISTS = 0x30,
OSD_CDB_GET_SET_ATTR_MASK = 0x30,
};
/* (osd-r10: 4.12.5)
* osd2r03: 4.14.5 Data-In and Data-Out buffer offsets
* byte offset = mantissa * (2^(exponent+8))
* struct {
* unsigned mantissa: 28;
* int exponent: 04;
* }
*/
typedef __be32 __bitwise osd_cdb_offset;
enum {
OSD_OFFSET_UNUSED = 0xFFFFFFFF,
OSD_OFFSET_MAX_BITS = 28,
OSDv1_OFFSET_MIN_SHIFT = 8,
OSD_OFFSET_MIN_SHIFT = 3,
OSD_OFFSET_MAX_SHIFT = 16,
};
/* Return the smallest allowed encoded offset that contains @offset.
*
* The actual encoded offset returned is @offset + *padding.
* (up to max_shift, non-inclusive)
*/
osd_cdb_offset __osd_encode_offset(u64 offset, unsigned *padding,
int min_shift, int max_shift);
/* Minimum alignment is 256 bytes
* Note: Seems from std v1 that exponent can be from 0+8 to 0xE+8 (inclusive)
* which is 8 to 23 but IBM code restricts it to 16, so be it.
*/
static inline osd_cdb_offset osd_encode_offset_v1(u64 offset, unsigned *padding)
{
return __osd_encode_offset(offset, padding,
OSDv1_OFFSET_MIN_SHIFT, OSD_OFFSET_MAX_SHIFT);
}
/* Minimum 8 bytes alignment
* Same as v1 but since exponent can be signed than a less than
* 256 alignment can be reached with small offsets (<2GB)
*/
static inline osd_cdb_offset osd_encode_offset_v2(u64 offset, unsigned *padding)
{
return __osd_encode_offset(offset, padding,
OSD_OFFSET_MIN_SHIFT, OSD_OFFSET_MAX_SHIFT);
}
/* osd2r03: 5.2.1 Overview */
struct osd_cdb_head {
struct scsi_varlen_cdb_hdr varlen_cdb;
/*10*/ u8 options;
u8 command_specific_options;
u8 timestamp_control;
/*13*/ u8 reserved1[3];
/*16*/ __be64 partition;
/*24*/ __be64 object;
/*32*/ union { /* V1 vs V2 alignment differences */
struct __osdv1_cdb_addr_len {
/*32*/ __be32 list_identifier;/* Rarely used */
/*36*/ __be64 length;
/*44*/ __be64 start_address;
} __packed v1;
struct __osdv2_cdb_addr_len {
/* called allocation_length in some commands */
/*32*/ __be64 length;
/*40*/ __be64 start_address;
union {
/*48*/ __be32 list_identifier;/* Rarely used */
/* OSD2r05 5.2.5 CDB continuation length */
/*48*/ __be32 cdb_continuation_length;
};
} __packed v2;
};
/*52*/ union { /* selected attributes mode Page/List/Single */
struct osd_attributes_page_mode {
/*52*/ __be32 get_attr_page;
/*56*/ __be32 get_attr_alloc_length;
/*60*/ osd_cdb_offset get_attr_offset;
/*64*/ __be32 set_attr_page;
/*68*/ __be32 set_attr_id;
/*72*/ __be32 set_attr_length;
/*76*/ osd_cdb_offset set_attr_offset;
/*80*/ } __packed attrs_page;
struct osd_attributes_list_mode {
/*52*/ __be32 get_attr_desc_bytes;
/*56*/ osd_cdb_offset get_attr_desc_offset;
/*60*/ __be32 get_attr_alloc_length;
/*64*/ osd_cdb_offset get_attr_offset;
/*68*/ __be32 set_attr_bytes;
/*72*/ osd_cdb_offset set_attr_offset;
__be32 not_used;
/*80*/ } __packed attrs_list;
/* osd2r03:5.2.4.2 Set one attribute value using CDB fields */
struct osd_attributes_cdb_mode {
/*52*/ __be32 set_attr_page;
/*56*/ __be32 set_attr_id;
/*60*/ __be16 set_attr_len;
/*62*/ u8 set_attr_val[18];
/*80*/ } __packed attrs_cdb;
/*52*/ u8 get_set_attributes_parameters[28];
};
} __packed;
/*80*/
/*160 v1*/
struct osdv1_security_parameters {
/*160*/u8 integrity_check_value[OSDv1_CRYPTO_KEYID_SIZE];
/*180*/u8 request_nonce[OSD_CRYPTO_NONCE_SIZE];
/*192*/osd_cdb_offset data_in_integrity_check_offset;
/*196*/osd_cdb_offset data_out_integrity_check_offset;
} __packed;
/*200 v1*/
/*184 v2*/
struct osdv2_security_parameters {
/*184*/u8 integrity_check_value[OSDv2_CRYPTO_KEYID_SIZE];
/*216*/u8 request_nonce[OSD_CRYPTO_NONCE_SIZE];
/*228*/osd_cdb_offset data_in_integrity_check_offset;
/*232*/osd_cdb_offset data_out_integrity_check_offset;
} __packed;
/*236 v2*/
struct osd_security_parameters {
union {
struct osdv1_security_parameters v1;
struct osdv2_security_parameters v2;
};
};
struct osdv1_cdb {
struct osd_cdb_head h;
u8 caps[OSDv1_CAP_LEN];
struct osdv1_security_parameters sec_params;
} __packed;
struct osdv2_cdb {
struct osd_cdb_head h;
u8 caps[OSD_CAP_LEN];
struct osdv2_security_parameters sec_params;
} __packed;
struct osd_cdb {
union {
struct osdv1_cdb v1;
struct osdv2_cdb v2;
u8 buff[OSD_TOTAL_CDB_LEN];
};
} __packed;
static inline struct osd_cdb_head *osd_cdb_head(struct osd_cdb *ocdb)
{
return (struct osd_cdb_head *)ocdb->buff;
}
/* define both version actions
* Ex name = FORMAT_OSD we have OSD_ACT_FORMAT_OSD && OSDv1_ACT_FORMAT_OSD
*/
#define OSD_ACT___(Name, Num) \
OSD_ACT_##Name = __constant_cpu_to_be16(0x8880 + Num), \
OSDv1_ACT_##Name = __constant_cpu_to_be16(0x8800 + Num),
/* V2 only actions */
#define OSD_ACT_V2(Name, Num) \
OSD_ACT_##Name = __constant_cpu_to_be16(0x8880 + Num),
#define OSD_ACT_V1_V2(Name, Num1, Num2) \
OSD_ACT_##Name = __constant_cpu_to_be16(Num2), \
OSDv1_ACT_##Name = __constant_cpu_to_be16(Num1),
enum osd_service_actions {
OSD_ACT_V2(OBJECT_STRUCTURE_CHECK, 0x00)
OSD_ACT___(FORMAT_OSD, 0x01)
OSD_ACT___(CREATE, 0x02)
OSD_ACT___(LIST, 0x03)
OSD_ACT_V2(PUNCH, 0x04)
OSD_ACT___(READ, 0x05)
OSD_ACT___(WRITE, 0x06)
OSD_ACT___(APPEND, 0x07)
OSD_ACT___(FLUSH, 0x08)
OSD_ACT_V2(CLEAR, 0x09)
OSD_ACT___(REMOVE, 0x0A)
OSD_ACT___(CREATE_PARTITION, 0x0B)
OSD_ACT___(REMOVE_PARTITION, 0x0C)
OSD_ACT___(GET_ATTRIBUTES, 0x0E)
OSD_ACT___(SET_ATTRIBUTES, 0x0F)
OSD_ACT___(CREATE_AND_WRITE, 0x12)
OSD_ACT___(CREATE_COLLECTION, 0x15)
OSD_ACT___(REMOVE_COLLECTION, 0x16)
OSD_ACT___(LIST_COLLECTION, 0x17)
OSD_ACT___(SET_KEY, 0x18)
OSD_ACT___(SET_MASTER_KEY, 0x19)
OSD_ACT___(FLUSH_COLLECTION, 0x1A)
OSD_ACT___(FLUSH_PARTITION, 0x1B)
OSD_ACT___(FLUSH_OSD, 0x1C)
OSD_ACT_V2(QUERY, 0x20)
OSD_ACT_V2(REMOVE_MEMBER_OBJECTS, 0x21)
OSD_ACT_V2(GET_MEMBER_ATTRIBUTES, 0x22)
OSD_ACT_V2(SET_MEMBER_ATTRIBUTES, 0x23)
OSD_ACT_V2(CREATE_CLONE, 0x28)
OSD_ACT_V2(CREATE_SNAPSHOT, 0x29)
OSD_ACT_V2(DETACH_CLONE, 0x2A)
OSD_ACT_V2(REFRESH_SNAPSHOT_CLONE, 0x2B)
OSD_ACT_V2(RESTORE_PARTITION_FROM_SNAPSHOT, 0x2C)
OSD_ACT_V2(READ_MAP, 0x31)
OSD_ACT_V2(READ_MAPS_COMPARE, 0x32)
OSD_ACT_V1_V2(PERFORM_SCSI_COMMAND, 0x8F7E, 0x8F7C)
OSD_ACT_V1_V2(SCSI_TASK_MANAGEMENT, 0x8F7F, 0x8F7D)
/* 0x8F80 to 0x8FFF are Vendor specific */
};
/* osd2r03: 7.1.3.2 List entry format for retrieving attributes */
struct osd_attributes_list_attrid {
__be32 attr_page;
__be32 attr_id;
} __packed;
/*
* NOTE: v1: is not aligned.
*/
struct osdv1_attributes_list_element {
__be32 attr_page;
__be32 attr_id;
__be16 attr_bytes; /* valid bytes at attr_val without padding */
u8 attr_val[0];
} __packed;
/*
* osd2r03: 7.1.3.3 List entry format for retrieved attributes and
* for setting attributes
* NOTE: v2 is 8-bytes aligned
*/
struct osdv2_attributes_list_element {
__be32 attr_page;
__be32 attr_id;
u8 reserved[6];
__be16 attr_bytes; /* valid bytes at attr_val without padding */
u8 attr_val[0];
} __packed;
enum {
OSDv1_ATTRIBUTES_ELEM_ALIGN = 1,
OSD_ATTRIBUTES_ELEM_ALIGN = 8,
};
enum {
OSD_ATTR_LIST_ALL_PAGES = 0xFFFFFFFF,
OSD_ATTR_LIST_ALL_IN_PAGE = 0xFFFFFFFF,
};
static inline unsigned osdv1_attr_list_elem_size(unsigned len)
{
return ALIGN(len + sizeof(struct osdv1_attributes_list_element),
OSDv1_ATTRIBUTES_ELEM_ALIGN);
}
static inline unsigned osdv2_attr_list_elem_size(unsigned len)
{
return ALIGN(len + sizeof(struct osdv2_attributes_list_element),
OSD_ATTRIBUTES_ELEM_ALIGN);
}
/*
* osd2r03: 7.1.3 OSD attributes lists (Table 184) — List type values
*/
enum osd_attr_list_types {
OSD_ATTR_LIST_GET = 0x1, /* descriptors only */
OSD_ATTR_LIST_SET_RETRIEVE = 0x9, /*descriptors/values variable-length*/
OSD_V2_ATTR_LIST_MULTIPLE = 0xE, /* ver2, Multiple Objects lists*/
OSD_V1_ATTR_LIST_CREATE_MULTIPLE = 0xF,/*ver1, used by create_multple*/
};
/* osd2r03: 7.1.3.4 Multi-object retrieved attributes format */
struct osd_attributes_list_multi_header {
__be64 object_id;
u8 object_type; /* object_type enum below */
u8 reserved[5];
__be16 list_bytes;
/* followed by struct osd_attributes_list_element's */
};
struct osdv1_attributes_list_header {
u8 type; /* low 4-bit only */
u8 pad;
__be16 list_bytes; /* Initiator shall set to Zero. Only set by target */
/*
* type=9 followed by struct osd_attributes_list_element's
* type=E followed by struct osd_attributes_list_multi_header's
*/
} __packed;
static inline unsigned osdv1_list_size(struct osdv1_attributes_list_header *h)
{
return be16_to_cpu(h->list_bytes);
}
struct osdv2_attributes_list_header {
u8 type; /* lower 4-bits only */
u8 pad[3];
/*4*/ __be32 list_bytes; /* Initiator shall set to zero. Only set by target */
/*
* type=9 followed by struct osd_attributes_list_element's
* type=E followed by struct osd_attributes_list_multi_header's
*/
} __packed;
static inline unsigned osdv2_list_size(struct osdv2_attributes_list_header *h)
{
return be32_to_cpu(h->list_bytes);
}
/* (osd-r10 6.13)
* osd2r03: 6.15 LIST (Table 79) LIST command parameter data.
* for root_lstchg below
*/
enum {
OSD_OBJ_ID_LIST_PAR = 0x1, /* V1-only. Not used in V2 */
OSD_OBJ_ID_LIST_LSTCHG = 0x2,
};
/*
* osd2r03: 6.15.2 LIST command parameter data
* (Also for LIST COLLECTION)
*/
struct osd_obj_id_list {
__be64 list_bytes; /* bytes in list excluding list_bytes (-8) */
__be64 continuation_id;
__be32 list_identifier;
u8 pad[3];
u8 root_lstchg;
__be64 object_ids[0];
} __packed;
static inline bool osd_is_obj_list_done(struct osd_obj_id_list *list,
bool *is_changed)
{
*is_changed = (0 != (list->root_lstchg & OSD_OBJ_ID_LIST_LSTCHG));
return 0 != list->continuation_id;
}
/*
* osd2r03: 4.12.4.5 The ALLDATA security method
*/
struct osd_data_out_integrity_info {
__be64 data_bytes;
__be64 set_attributes_bytes;
__be64 get_attributes_bytes;
__u8 integrity_check_value[OSD_CRYPTO_KEYID_SIZE];
} __packed;
/* Same osd_data_out_integrity_info is used for OSD2/OSD1. The only difference
* Is the sizeof the structure since in OSD1 the last array is smaller. Use
* below for version independent handling of this structure
*/
static inline int osd_data_out_integrity_info_sizeof(bool is_ver1)
{
return sizeof(struct osd_data_out_integrity_info) -
(is_ver1 * (OSDv2_CRYPTO_KEYID_SIZE - OSDv1_CRYPTO_KEYID_SIZE));
}
struct osd_data_in_integrity_info {
__be64 data_bytes;
__be64 retrieved_attributes_bytes;
__u8 integrity_check_value[OSD_CRYPTO_KEYID_SIZE];
} __packed;
/* Same osd_data_in_integrity_info is used for OSD2/OSD1. The only difference
* Is the sizeof the structure since in OSD1 the last array is smaller. Use
* below for version independent handling of this structure
*/
static inline int osd_data_in_integrity_info_sizeof(bool is_ver1)
{
return sizeof(struct osd_data_in_integrity_info) -
(is_ver1 * (OSDv2_CRYPTO_KEYID_SIZE - OSDv1_CRYPTO_KEYID_SIZE));
}
struct osd_timestamp {
u8 time[6]; /* number of milliseconds since 1/1/1970 UT (big endian) */
} __packed;
/* FIXME: define helper functions to convert to/from osd time format */
/*
* Capability & Security definitions
* osd2r03: 4.11.2.2 Capability format
* osd2r03: 5.2.8 Security parameters
*/
struct osd_key_identifier {
u8 id[7]; /* if you know why 7 please email bharrosh@panasas.com */
} __packed;
/* for osd_capability.format */
enum {
OSD_SEC_CAP_FORMAT_NO_CAPS = 0,
OSD_SEC_CAP_FORMAT_VER1 = 1,
OSD_SEC_CAP_FORMAT_VER2 = 2,
};
/* security_method */
enum {
OSD_SEC_NOSEC = 0,
OSD_SEC_CAPKEY = 1,
OSD_SEC_CMDRSP = 2,
OSD_SEC_ALLDATA = 3,
};
enum object_type {
OSD_SEC_OBJ_ROOT = 0x1,
OSD_SEC_OBJ_PARTITION = 0x2,
OSD_SEC_OBJ_COLLECTION = 0x40,
OSD_SEC_OBJ_USER = 0x80,
};
enum osd_capability_bit_masks {
OSD_SEC_CAP_APPEND = BIT(0),
OSD_SEC_CAP_OBJ_MGMT = BIT(1),
OSD_SEC_CAP_REMOVE = BIT(2),
OSD_SEC_CAP_CREATE = BIT(3),
OSD_SEC_CAP_SET_ATTR = BIT(4),
OSD_SEC_CAP_GET_ATTR = BIT(5),
OSD_SEC_CAP_WRITE = BIT(6),
OSD_SEC_CAP_READ = BIT(7),
OSD_SEC_CAP_NONE1 = BIT(8),
OSD_SEC_CAP_NONE2 = BIT(9),
OSD_SEC_GBL_REM = BIT(10), /*v2 only*/
OSD_SEC_CAP_QUERY = BIT(11), /*v2 only*/
OSD_SEC_CAP_M_OBJECT = BIT(12), /*v2 only*/
OSD_SEC_CAP_POL_SEC = BIT(13),
OSD_SEC_CAP_GLOBAL = BIT(14),
OSD_SEC_CAP_DEV_MGMT = BIT(15),
};
/* for object_descriptor_type (hi nibble used) */
enum {
OSD_SEC_OBJ_DESC_NONE = 0, /* Not allowed */
OSD_SEC_OBJ_DESC_OBJ = 1 << 4, /* v1: also collection */
OSD_SEC_OBJ_DESC_PAR = 2 << 4, /* also root */
OSD_SEC_OBJ_DESC_COL = 3 << 4, /* v2 only */
};
/* (osd-r10:4.9.2.2)
* osd2r03:4.11.2.2 Capability format
*/
struct osd_capability_head {
u8 format; /* low nibble */
u8 integrity_algorithm__key_version; /* MAKE_BYTE(integ_alg, key_ver) */
u8 security_method;
u8 reserved1;
/*04*/ struct osd_timestamp expiration_time;
/*10*/ u8 audit[20];
/*30*/ u8 discriminator[12];
/*42*/ struct osd_timestamp object_created_time;
/*48*/ u8 object_type;
/*49*/ u8 permissions_bit_mask[5];
/*54*/ u8 reserved2;
/*55*/ u8 object_descriptor_type; /* high nibble */
} __packed;
/*56 v1*/
struct osdv1_cap_object_descriptor {
union {
struct {
/*56*/ __be32 policy_access_tag;
/*60*/ __be64 allowed_partition_id;
/*68*/ __be64 allowed_object_id;
/*76*/ __be32 reserved;
} __packed obj_desc;
/*56*/ u8 object_descriptor[24];
};
} __packed;
/*80 v1*/
/*56 v2*/
struct osd_cap_object_descriptor {
union {
struct {
/*56*/ __be32 allowed_attributes_access;
/*60*/ __be32 policy_access_tag;
/*64*/ __be16 boot_epoch;
/*66*/ u8 reserved[6];
/*72*/ __be64 allowed_partition_id;
/*80*/ __be64 allowed_object_id;
/*88*/ __be64 allowed_range_length;
/*96*/ __be64 allowed_range_start;
} __packed obj_desc;
/*56*/ u8 object_descriptor[48];
};
} __packed;
/*104 v2*/
struct osdv1_capability {
struct osd_capability_head h;
struct osdv1_cap_object_descriptor od;
} __packed;
struct osd_capability {
struct osd_capability_head h;
struct osd_cap_object_descriptor od;
} __packed;
/**
* osd_sec_set_caps - set cap-bits into the capabilities header
*
* @cap: The osd_capability_head to set cap bits to.
* @bit_mask: Use an ORed list of enum osd_capability_bit_masks values
*
* permissions_bit_mask is unaligned use below to set into caps
* in a version independent way
*/
static inline void osd_sec_set_caps(struct osd_capability_head *cap,
u16 bit_mask)
{
/*
*Note: The bits above are defined LE order this is because this way
* they can grow in the future to more then 16, and still retain
* there constant values.
*/
put_unaligned_le16(bit_mask, &cap->permissions_bit_mask);
}
#endif /* ndef __OSD_PROTOCOL_H__ */

View File

@@ -0,0 +1,45 @@
/*
* osd_sec.h - OSD security manager API
*
* Copyright (C) 2008 Panasas Inc. All rights reserved.
*
* Authors:
* Boaz Harrosh <bharrosh@panasas.com>
* Benny Halevy <bhalevy@panasas.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
*
*/
#ifndef __OSD_SEC_H__
#define __OSD_SEC_H__
#include "osd_protocol.h"
#include "osd_types.h"
/*
* Contains types and constants of osd capabilities and security
* encoding/decoding.
* API is trying to keep security abstract so initiator of an object
* based pNFS client knows as little as possible about security and
* capabilities. It is the Server's osd-initiator place to know more.
* Also can be used by osd-target.
*/
void osd_sec_encode_caps(void *caps, ...);/* NI */
void osd_sec_init_nosec_doall_caps(void *caps,
const struct osd_obj_id *obj, bool is_collection, const bool is_v1);
bool osd_is_sec_alldata(struct osd_security_parameters *sec_params);
/* Conditionally sign the CDB according to security setting in ocdb
* with cap_key */
void osd_sec_sign_cdb(struct osd_cdb *ocdb, const u8 *cap_key);
/* Unconditionally sign the BIO data with cap_key.
* Check for osd_is_sec_alldata() was done prior to calling this. */
void osd_sec_sign_data(void *data_integ, struct bio *bio, const u8 *cap_key);
/* Version independent copy of caps into the cdb */
void osd_set_caps(struct osd_cdb *cdb, const void *caps);
#endif /* ndef __OSD_SEC_H__ */

View File

@@ -0,0 +1,260 @@
/*
* osd_sense.h - OSD Related sense handling definitions.
*
* Copyright (C) 2008 Panasas Inc. All rights reserved.
*
* Authors:
* Boaz Harrosh <bharrosh@panasas.com>
* Benny Halevy <bhalevy@panasas.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
*
* This file contains types and constants that are defined by the protocol
* Note: All names and symbols are taken from the OSD standard's text.
*/
#ifndef __OSD_SENSE_H__
#define __OSD_SENSE_H__
#include <scsi/osd_protocol.h>
/* SPC3r23 4.5.6 Sense key and sense code definitions table 27 */
enum scsi_sense_keys {
scsi_sk_no_sense = 0x0,
scsi_sk_recovered_error = 0x1,
scsi_sk_not_ready = 0x2,
scsi_sk_medium_error = 0x3,
scsi_sk_hardware_error = 0x4,
scsi_sk_illegal_request = 0x5,
scsi_sk_unit_attention = 0x6,
scsi_sk_data_protect = 0x7,
scsi_sk_blank_check = 0x8,
scsi_sk_vendor_specific = 0x9,
scsi_sk_copy_aborted = 0xa,
scsi_sk_aborted_command = 0xb,
scsi_sk_volume_overflow = 0xd,
scsi_sk_miscompare = 0xe,
scsi_sk_reserved = 0xf,
};
/* SPC3r23 4.5.6 Sense key and sense code definitions table 28 */
/* Note: only those which can be returned by an OSD target. Most of
* these errors are taken care of by the generic scsi layer.
*/
enum osd_additional_sense_codes {
scsi_no_additional_sense_information = 0x0000,
scsi_operation_in_progress = 0x0016,
scsi_cleaning_requested = 0x0017,
scsi_lunr_cause_not_reportable = 0x0400,
scsi_logical_unit_is_in_process_of_becoming_ready = 0x0401,
scsi_lunr_initializing_command_required = 0x0402,
scsi_lunr_manual_intervention_required = 0x0403,
scsi_lunr_operation_in_progress = 0x0407,
scsi_lunr_selftest_in_progress = 0x0409,
scsi_luna_asymmetric_access_state_transition = 0x040a,
scsi_luna_target_port_in_standby_state = 0x040b,
scsi_luna_target_port_in_unavailable_state = 0x040c,
scsi_lunr_notify_enable_spinup_required = 0x0411,
scsi_logical_unit_does_not_respond_to_selection = 0x0500,
scsi_logical_unit_communication_failure = 0x0800,
scsi_logical_unit_communication_timeout = 0x0801,
scsi_logical_unit_communication_parity_error = 0x0802,
scsi_error_log_overflow = 0x0a00,
scsi_warning = 0x0b00,
scsi_warning_specified_temperature_exceeded = 0x0b01,
scsi_warning_enclosure_degraded = 0x0b02,
scsi_write_error_unexpected_unsolicited_data = 0x0c0c,
scsi_write_error_not_enough_unsolicited_data = 0x0c0d,
scsi_invalid_information_unit = 0x0e00,
scsi_invalid_field_in_command_information_unit = 0x0e03,
scsi_read_error_failed_retransmission_request = 0x1113,
scsi_parameter_list_length_error = 0x1a00,
scsi_invalid_command_operation_code = 0x2000,
scsi_invalid_field_in_cdb = 0x2400,
osd_security_audit_value_frozen = 0x2404,
osd_security_working_key_frozen = 0x2405,
osd_nonce_not_unique = 0x2406,
osd_nonce_timestamp_out_of_range = 0x2407,
scsi_logical_unit_not_supported = 0x2500,
scsi_invalid_field_in_parameter_list = 0x2600,
scsi_parameter_not_supported = 0x2601,
scsi_parameter_value_invalid = 0x2602,
scsi_invalid_release_of_persistent_reservation = 0x2604,
osd_invalid_dataout_buffer_integrity_check_value = 0x260f,
scsi_not_ready_to_ready_change_medium_may_have_changed = 0x2800,
scsi_power_on_reset_or_bus_device_reset_occurred = 0x2900,
scsi_power_on_occurred = 0x2901,
scsi_scsi_bus_reset_occurred = 0x2902,
scsi_bus_device_reset_function_occurred = 0x2903,
scsi_device_internal_reset = 0x2904,
scsi_transceiver_mode_changed_to_single_ended = 0x2905,
scsi_transceiver_mode_changed_to_lvd = 0x2906,
scsi_i_t_nexus_loss_occurred = 0x2907,
scsi_parameters_changed = 0x2a00,
scsi_mode_parameters_changed = 0x2a01,
scsi_asymmetric_access_state_changed = 0x2a06,
scsi_priority_changed = 0x2a08,
scsi_command_sequence_error = 0x2c00,
scsi_previous_busy_status = 0x2c07,
scsi_previous_task_set_full_status = 0x2c08,
scsi_previous_reservation_conflict_status = 0x2c09,
osd_partition_or_collection_contains_user_objects = 0x2c0a,
scsi_commands_cleared_by_another_initiator = 0x2f00,
scsi_cleaning_failure = 0x3007,
scsi_enclosure_failure = 0x3400,
scsi_enclosure_services_failure = 0x3500,
scsi_unsupported_enclosure_function = 0x3501,
scsi_enclosure_services_unavailable = 0x3502,
scsi_enclosure_services_transfer_failure = 0x3503,
scsi_enclosure_services_transfer_refused = 0x3504,
scsi_enclosure_services_checksum_error = 0x3505,
scsi_rounded_parameter = 0x3700,
osd_read_past_end_of_user_object = 0x3b17,
scsi_logical_unit_has_not_self_configured_yet = 0x3e00,
scsi_logical_unit_failure = 0x3e01,
scsi_timeout_on_logical_unit = 0x3e02,
scsi_logical_unit_failed_selftest = 0x3e03,
scsi_logical_unit_unable_to_update_selftest_log = 0x3e04,
scsi_target_operating_conditions_have_changed = 0x3f00,
scsi_microcode_has_been_changed = 0x3f01,
scsi_inquiry_data_has_changed = 0x3f03,
scsi_echo_buffer_overwritten = 0x3f0f,
scsi_diagnostic_failure_on_component_nn_first = 0x4080,
scsi_diagnostic_failure_on_component_nn_last = 0x40ff,
scsi_message_error = 0x4300,
scsi_internal_target_failure = 0x4400,
scsi_select_or_reselect_failure = 0x4500,
scsi_scsi_parity_error = 0x4700,
scsi_data_phase_crc_error_detected = 0x4701,
scsi_scsi_parity_error_detected_during_st_data_phase = 0x4702,
scsi_asynchronous_information_protection_error_detected = 0x4704,
scsi_protocol_service_crc_error = 0x4705,
scsi_phy_test_function_in_progress = 0x4706,
scsi_invalid_message_error = 0x4900,
scsi_command_phase_error = 0x4a00,
scsi_data_phase_error = 0x4b00,
scsi_logical_unit_failed_self_configuration = 0x4c00,
scsi_overlapped_commands_attempted = 0x4e00,
osd_quota_error = 0x5507,
scsi_failure_prediction_threshold_exceeded = 0x5d00,
scsi_failure_prediction_threshold_exceeded_false = 0x5dff,
scsi_voltage_fault = 0x6500,
};
enum scsi_descriptor_types {
scsi_sense_information = 0x0,
scsi_sense_command_specific_information = 0x1,
scsi_sense_key_specific = 0x2,
scsi_sense_field_replaceable_unit = 0x3,
scsi_sense_stream_commands = 0x4,
scsi_sense_block_commands = 0x5,
osd_sense_object_identification = 0x6,
osd_sense_response_integrity_check = 0x7,
osd_sense_attribute_identification = 0x8,
scsi_sense_ata_return = 0x9,
scsi_sense_Reserved_first = 0x0A,
scsi_sense_Reserved_last = 0x7F,
scsi_sense_Vendor_specific_first = 0x80,
scsi_sense_Vendor_specific_last = 0xFF,
};
struct scsi_sense_descriptor { /* for picking into desc type */
u8 descriptor_type; /* one of enum scsi_descriptor_types */
u8 additional_length; /* n - 1 */
u8 data[];
} __packed;
/* OSD deploys only scsi descriptor_based sense buffers */
struct scsi_sense_descriptor_based {
/*0*/ u8 response_code; /* 0x72 or 0x73 */
/*1*/ u8 sense_key; /* one of enum scsi_sense_keys (4 lower bits) */
/*2*/ __be16 additional_sense_code; /* enum osd_additional_sense_codes */
/*4*/ u8 Reserved[3];
/*7*/ u8 additional_sense_length; /* n - 7 */
/*8*/ struct scsi_sense_descriptor ssd[0]; /* variable length, 1 or more */
} __packed;
/* some descriptors deployed by OSD */
/* SPC3r23 4.5.2.3 Command-specific information sense data descriptor */
/* Note: this is the same for descriptor_type=00 but with type=00 the
* Reserved[0] == 0x80 (ie. bit-7 set)
*/
struct scsi_sense_command_specific_data_descriptor {
/*0*/ u8 descriptor_type; /* (00h/01h) */
/*1*/ u8 additional_length; /* (0Ah) */
/*2*/ u8 Reserved[2];
/*4*/ __be64 information;
} __packed;
/*12*/
struct scsi_sense_key_specific_data_descriptor {
/*0*/ u8 descriptor_type; /* (02h) */
/*1*/ u8 additional_length; /* (06h) */
/*2*/ u8 Reserved[2];
/* SKSV, C/D, Reserved (2), BPV, BIT POINTER (3) */
/*4*/ u8 sksv_cd_bpv_bp;
/*5*/ __be16 value; /* field-pointer/progress-value/retry-count/... */
/*7*/ u8 Reserved2;
} __packed;
/*8*/
/* 4.16.2.1 OSD error identification sense data descriptor - table 52 */
/* Note: these bits are defined LE order for easy definition, this way the BIT()
* number is the same as in the documentation. Below members at
* osd_sense_identification_data_descriptor are therefore defined __le32.
*/
enum osd_command_functions_bits {
OSD_CFB_COMMAND = BIT(4),
OSD_CFB_CMD_CAP_VERIFIED = BIT(5),
OSD_CFB_VALIDATION = BIT(7),
OSD_CFB_IMP_ST_ATT = BIT(12),
OSD_CFB_SET_ATT = BIT(20),
OSD_CFB_SA_CAP_VERIFIED = BIT(21),
OSD_CFB_GET_ATT = BIT(28),
OSD_CFB_GA_CAP_VERIFIED = BIT(29),
};
struct osd_sense_identification_data_descriptor {
/*0*/ u8 descriptor_type; /* (06h) */
/*1*/ u8 additional_length; /* (1Eh) */
/*2*/ u8 Reserved[6];
/*8*/ __le32 not_initiated_functions; /*osd_command_functions_bits*/
/*12*/ __le32 completed_functions; /*osd_command_functions_bits*/
/*16*/ __be64 partition_id;
/*24*/ __be64 object_id;
} __packed;
/*32*/
struct osd_sense_response_integrity_check_descriptor {
/*0*/ u8 descriptor_type; /* (07h) */
/*1*/ u8 additional_length; /* (20h) */
/*2*/ u8 integrity_check_value[32]; /*FIXME: OSDv2_CRYPTO_KEYID_SIZE*/
} __packed;
/*34*/
struct osd_sense_attributes_data_descriptor {
/*0*/ u8 descriptor_type; /* (08h) */
/*1*/ u8 additional_length; /* (n-2) */
/*2*/ u8 Reserved[6];
struct osd_sense_attr {
/*8*/ __be32 attr_page;
/*12*/ __be32 attr_id;
/*16*/ } sense_attrs[0]; /* 1 or more */
} __packed;
/*variable*/
/* Dig into scsi_sk_illegal_request/scsi_invalid_field_in_cdb errors */
/*FIXME: Support also field in CAPS*/
#define OSD_CDB_OFFSET(F) offsetof(struct osd_cdb_head, F)
enum osdv2_cdb_field_offset {
OSDv1_CFO_STARTING_BYTE = OSD_CDB_OFFSET(v1.start_address),
OSD_CFO_STARTING_BYTE = OSD_CDB_OFFSET(v2.start_address),
OSD_CFO_PARTITION_ID = OSD_CDB_OFFSET(partition),
OSD_CFO_OBJECT_ID = OSD_CDB_OFFSET(object),
};
#endif /* ndef __OSD_SENSE_H__ */

View File

@@ -0,0 +1,40 @@
/*
* osd_types.h - Types and constants which are not part of the protocol.
*
* Copyright (C) 2008 Panasas Inc. All rights reserved.
*
* Authors:
* Boaz Harrosh <bharrosh@panasas.com>
* Benny Halevy <bhalevy@panasas.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
*
* Contains types and constants that are implementation specific and are
* used by more than one part of the osd library.
* (Eg initiator/target/security_manager/...)
*/
#ifndef __OSD_TYPES_H__
#define __OSD_TYPES_H__
struct osd_systemid {
u8 data[OSD_SYSTEMID_LEN];
};
typedef u64 __bitwise osd_id;
struct osd_obj_id {
osd_id partition;
osd_id id;
};
static const struct __weak osd_obj_id osd_root_object = {0, 0};
struct osd_attr {
u32 attr_page;
u32 attr_id;
u16 len; /* byte count of operand */
void *val_ptr; /* in network order */
};
#endif /* ndef __OSD_TYPES_H__ */

630
kernel/include/scsi/sas.h Normal file
View File

@@ -0,0 +1,630 @@
/*
* SAS structures and definitions header file
*
* Copyright (C) 2005 Adaptec, Inc. All rights reserved.
* Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
*
* This file is licensed under GPLv2.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
*/
#ifndef _SAS_H_
#define _SAS_H_
#include <linux/types.h>
#include <asm/byteorder.h>
#define SAS_ADDR_SIZE 8
#define HASHED_SAS_ADDR_SIZE 3
#define SAS_ADDR(_sa) ((unsigned long long) be64_to_cpu(*(__be64 *)(_sa)))
#define SMP_REQUEST 0x40
#define SMP_RESPONSE 0x41
#define SSP_DATA 0x01
#define SSP_XFER_RDY 0x05
#define SSP_COMMAND 0x06
#define SSP_RESPONSE 0x07
#define SSP_TASK 0x16
#define SMP_REPORT_GENERAL 0x00
#define SMP_REPORT_MANUF_INFO 0x01
#define SMP_READ_GPIO_REG 0x02
#define SMP_DISCOVER 0x10
#define SMP_REPORT_PHY_ERR_LOG 0x11
#define SMP_REPORT_PHY_SATA 0x12
#define SMP_REPORT_ROUTE_INFO 0x13
#define SMP_WRITE_GPIO_REG 0x82
#define SMP_CONF_ROUTE_INFO 0x90
#define SMP_PHY_CONTROL 0x91
#define SMP_PHY_TEST_FUNCTION 0x92
#define SMP_RESP_FUNC_ACC 0x00
#define SMP_RESP_FUNC_UNK 0x01
#define SMP_RESP_FUNC_FAILED 0x02
#define SMP_RESP_INV_FRM_LEN 0x03
#define SMP_RESP_NO_PHY 0x10
#define SMP_RESP_NO_INDEX 0x11
#define SMP_RESP_PHY_NO_SATA 0x12
#define SMP_RESP_PHY_UNK_OP 0x13
#define SMP_RESP_PHY_UNK_TESTF 0x14
#define SMP_RESP_PHY_TEST_INPROG 0x15
#define SMP_RESP_PHY_VACANT 0x16
/* SAM TMFs */
#define TMF_ABORT_TASK 0x01
#define TMF_ABORT_TASK_SET 0x02
#define TMF_CLEAR_TASK_SET 0x04
#define TMF_LU_RESET 0x08
#define TMF_CLEAR_ACA 0x40
#define TMF_QUERY_TASK 0x80
/* SAS TMF responses */
#define TMF_RESP_FUNC_COMPLETE 0x00
#define TMF_RESP_INVALID_FRAME 0x02
#define TMF_RESP_FUNC_ESUPP 0x04
#define TMF_RESP_FUNC_FAILED 0x05
#define TMF_RESP_FUNC_SUCC 0x08
#define TMF_RESP_NO_LUN 0x09
#define TMF_RESP_OVERLAPPED_TAG 0x0A
enum sas_oob_mode {
OOB_NOT_CONNECTED,
SATA_OOB_MODE,
SAS_OOB_MODE
};
/* See sas_discover.c if you plan on changing these.
*/
enum sas_dev_type {
NO_DEVICE = 0, /* protocol */
SAS_END_DEV = 1, /* protocol */
EDGE_DEV = 2, /* protocol */
FANOUT_DEV = 3, /* protocol */
SAS_HA = 4,
SATA_DEV = 5,
SATA_PM = 7,
SATA_PM_PORT= 8,
};
enum sas_protocol {
SAS_PROTOCOL_SATA = 0x01,
SAS_PROTOCOL_SMP = 0x02,
SAS_PROTOCOL_STP = 0x04,
SAS_PROTOCOL_SSP = 0x08,
SAS_PROTOCOL_ALL = 0x0E,
};
/* From the spec; local phys only */
enum phy_func {
PHY_FUNC_NOP,
PHY_FUNC_LINK_RESET, /* Enables the phy */
PHY_FUNC_HARD_RESET,
PHY_FUNC_DISABLE,
PHY_FUNC_CLEAR_ERROR_LOG = 5,
PHY_FUNC_CLEAR_AFFIL,
PHY_FUNC_TX_SATA_PS_SIGNAL,
PHY_FUNC_RELEASE_SPINUP_HOLD = 0x10, /* LOCAL PORT ONLY! */
PHY_FUNC_SET_LINK_RATE,
};
/* SAS LLDD would need to report only _very_few_ of those, like BROADCAST.
* Most of those are here for completeness.
*/
enum sas_prim {
SAS_PRIM_AIP_NORMAL = 1,
SAS_PRIM_AIP_R0 = 2,
SAS_PRIM_AIP_R1 = 3,
SAS_PRIM_AIP_R2 = 4,
SAS_PRIM_AIP_WC = 5,
SAS_PRIM_AIP_WD = 6,
SAS_PRIM_AIP_WP = 7,
SAS_PRIM_AIP_RWP = 8,
SAS_PRIM_BC_CH = 9,
SAS_PRIM_BC_RCH0 = 10,
SAS_PRIM_BC_RCH1 = 11,
SAS_PRIM_BC_R0 = 12,
SAS_PRIM_BC_R1 = 13,
SAS_PRIM_BC_R2 = 14,
SAS_PRIM_BC_R3 = 15,
SAS_PRIM_BC_R4 = 16,
SAS_PRIM_NOTIFY_ENSP= 17,
SAS_PRIM_NOTIFY_R0 = 18,
SAS_PRIM_NOTIFY_R1 = 19,
SAS_PRIM_NOTIFY_R2 = 20,
SAS_PRIM_CLOSE_CLAF = 21,
SAS_PRIM_CLOSE_NORM = 22,
SAS_PRIM_CLOSE_R0 = 23,
SAS_PRIM_CLOSE_R1 = 24,
SAS_PRIM_OPEN_RTRY = 25,
SAS_PRIM_OPEN_RJCT = 26,
SAS_PRIM_OPEN_ACPT = 27,
SAS_PRIM_DONE = 28,
SAS_PRIM_BREAK = 29,
SATA_PRIM_DMAT = 33,
SATA_PRIM_PMNAK = 34,
SATA_PRIM_PMACK = 35,
SATA_PRIM_PMREQ_S = 36,
SATA_PRIM_PMREQ_P = 37,
SATA_SATA_R_ERR = 38,
};
enum sas_open_rej_reason {
/* Abandon open */
SAS_OREJ_UNKNOWN = 0,
SAS_OREJ_BAD_DEST = 1,
SAS_OREJ_CONN_RATE = 2,
SAS_OREJ_EPROTO = 3,
SAS_OREJ_RESV_AB0 = 4,
SAS_OREJ_RESV_AB1 = 5,
SAS_OREJ_RESV_AB2 = 6,
SAS_OREJ_RESV_AB3 = 7,
SAS_OREJ_WRONG_DEST= 8,
SAS_OREJ_STP_NORES = 9,
/* Retry open */
SAS_OREJ_NO_DEST = 10,
SAS_OREJ_PATH_BLOCKED = 11,
SAS_OREJ_RSVD_CONT0 = 12,
SAS_OREJ_RSVD_CONT1 = 13,
SAS_OREJ_RSVD_INIT0 = 14,
SAS_OREJ_RSVD_INIT1 = 15,
SAS_OREJ_RSVD_STOP0 = 16,
SAS_OREJ_RSVD_STOP1 = 17,
SAS_OREJ_RSVD_RETRY = 18,
};
struct dev_to_host_fis {
u8 fis_type; /* 0x34 */
u8 flags;
u8 status;
u8 error;
u8 lbal;
union { u8 lbam; u8 byte_count_low; };
union { u8 lbah; u8 byte_count_high; };
u8 device;
u8 lbal_exp;
u8 lbam_exp;
u8 lbah_exp;
u8 _r_a;
union { u8 sector_count; u8 interrupt_reason; };
u8 sector_count_exp;
u8 _r_b;
u8 _r_c;
u32 _r_d;
} __attribute__ ((packed));
struct host_to_dev_fis {
u8 fis_type; /* 0x27 */
u8 flags;
u8 command;
u8 features;
u8 lbal;
union { u8 lbam; u8 byte_count_low; };
union { u8 lbah; u8 byte_count_high; };
u8 device;
u8 lbal_exp;
u8 lbam_exp;
u8 lbah_exp;
u8 features_exp;
union { u8 sector_count; u8 interrupt_reason; };
u8 sector_count_exp;
u8 _r_a;
u8 control;
u32 _r_b;
} __attribute__ ((packed));
/* Prefer to have code clarity over header file clarity.
*/
#ifdef __LITTLE_ENDIAN_BITFIELD
struct sas_identify_frame {
/* Byte 0 */
u8 frame_type:4;
u8 dev_type:3;
u8 _un0:1;
/* Byte 1 */
u8 _un1;
/* Byte 2 */
union {
struct {
u8 _un20:1;
u8 smp_iport:1;
u8 stp_iport:1;
u8 ssp_iport:1;
u8 _un247:4;
};
u8 initiator_bits;
};
/* Byte 3 */
union {
struct {
u8 _un30:1;
u8 smp_tport:1;
u8 stp_tport:1;
u8 ssp_tport:1;
u8 _un347:4;
};
u8 target_bits;
};
/* Byte 4 - 11 */
u8 _un4_11[8];
/* Byte 12 - 19 */
u8 sas_addr[SAS_ADDR_SIZE];
/* Byte 20 */
u8 phy_id;
u8 _un21_27[7];
__be32 crc;
} __attribute__ ((packed));
struct ssp_frame_hdr {
u8 frame_type;
u8 hashed_dest_addr[HASHED_SAS_ADDR_SIZE];
u8 _r_a;
u8 hashed_src_addr[HASHED_SAS_ADDR_SIZE];
__be16 _r_b;
u8 changing_data_ptr:1;
u8 retransmit:1;
u8 retry_data_frames:1;
u8 _r_c:5;
u8 num_fill_bytes:2;
u8 _r_d:6;
u32 _r_e;
__be16 tag;
__be16 tptt;
__be32 data_offs;
} __attribute__ ((packed));
struct ssp_response_iu {
u8 _r_a[10];
u8 datapres:2;
u8 _r_b:6;
u8 status;
u32 _r_c;
__be32 sense_data_len;
__be32 response_data_len;
u8 resp_data[0];
u8 sense_data[0];
} __attribute__ ((packed));
/* ---------- SMP ---------- */
struct report_general_resp {
__be16 change_count;
__be16 route_indexes;
u8 _r_a;
u8 num_phys;
u8 conf_route_table:1;
u8 configuring:1;
u8 _r_b:6;
u8 _r_c;
u8 enclosure_logical_id[8];
u8 _r_d[12];
} __attribute__ ((packed));
struct discover_resp {
u8 _r_a[5];
u8 phy_id;
__be16 _r_b;
u8 _r_c:4;
u8 attached_dev_type:3;
u8 _r_d:1;
u8 linkrate:4;
u8 _r_e:4;
u8 attached_sata_host:1;
u8 iproto:3;
u8 _r_f:4;
u8 attached_sata_dev:1;
u8 tproto:3;
u8 _r_g:3;
u8 attached_sata_ps:1;
u8 sas_addr[8];
u8 attached_sas_addr[8];
u8 attached_phy_id;
u8 _r_h[7];
u8 hmin_linkrate:4;
u8 pmin_linkrate:4;
u8 hmax_linkrate:4;
u8 pmax_linkrate:4;
u8 change_count;
u8 pptv:4;
u8 _r_i:3;
u8 virtual:1;
u8 routing_attr:4;
u8 _r_j:4;
u8 conn_type;
u8 conn_el_index;
u8 conn_phy_link;
u8 _r_k[8];
} __attribute__ ((packed));
struct report_phy_sata_resp {
u8 _r_a[5];
u8 phy_id;
u8 _r_b;
u8 affil_valid:1;
u8 affil_supp:1;
u8 _r_c:6;
u32 _r_d;
u8 stp_sas_addr[8];
struct dev_to_host_fis fis;
u32 _r_e;
u8 affil_stp_ini_addr[8];
__be32 crc;
} __attribute__ ((packed));
struct smp_resp {
u8 frame_type;
u8 function;
u8 result;
u8 reserved;
union {
struct report_general_resp rg;
struct discover_resp disc;
struct report_phy_sata_resp rps;
};
} __attribute__ ((packed));
#elif defined(__BIG_ENDIAN_BITFIELD)
struct sas_identify_frame {
/* Byte 0 */
u8 _un0:1;
u8 dev_type:3;
u8 frame_type:4;
/* Byte 1 */
u8 _un1;
/* Byte 2 */
union {
struct {
u8 _un247:4;
u8 ssp_iport:1;
u8 stp_iport:1;
u8 smp_iport:1;
u8 _un20:1;
};
u8 initiator_bits;
};
/* Byte 3 */
union {
struct {
u8 _un347:4;
u8 ssp_tport:1;
u8 stp_tport:1;
u8 smp_tport:1;
u8 _un30:1;
};
u8 target_bits;
};
/* Byte 4 - 11 */
u8 _un4_11[8];
/* Byte 12 - 19 */
u8 sas_addr[SAS_ADDR_SIZE];
/* Byte 20 */
u8 phy_id;
u8 _un21_27[7];
__be32 crc;
} __attribute__ ((packed));
struct ssp_frame_hdr {
u8 frame_type;
u8 hashed_dest_addr[HASHED_SAS_ADDR_SIZE];
u8 _r_a;
u8 hashed_src_addr[HASHED_SAS_ADDR_SIZE];
__be16 _r_b;
u8 _r_c:5;
u8 retry_data_frames:1;
u8 retransmit:1;
u8 changing_data_ptr:1;
u8 _r_d:6;
u8 num_fill_bytes:2;
u32 _r_e;
__be16 tag;
__be16 tptt;
__be32 data_offs;
} __attribute__ ((packed));
struct ssp_response_iu {
u8 _r_a[10];
u8 _r_b:6;
u8 datapres:2;
u8 status;
u32 _r_c;
__be32 sense_data_len;
__be32 response_data_len;
u8 resp_data[0];
u8 sense_data[0];
} __attribute__ ((packed));
/* ---------- SMP ---------- */
struct report_general_resp {
__be16 change_count;
__be16 route_indexes;
u8 _r_a;
u8 num_phys;
u8 _r_b:6;
u8 configuring:1;
u8 conf_route_table:1;
u8 _r_c;
u8 enclosure_logical_id[8];
u8 _r_d[12];
} __attribute__ ((packed));
struct discover_resp {
u8 _r_a[5];
u8 phy_id;
__be16 _r_b;
u8 _r_d:1;
u8 attached_dev_type:3;
u8 _r_c:4;
u8 _r_e:4;
u8 linkrate:4;
u8 _r_f:4;
u8 iproto:3;
u8 attached_sata_host:1;
u8 attached_sata_ps:1;
u8 _r_g:3;
u8 tproto:3;
u8 attached_sata_dev:1;
u8 sas_addr[8];
u8 attached_sas_addr[8];
u8 attached_phy_id;
u8 _r_h[7];
u8 pmin_linkrate:4;
u8 hmin_linkrate:4;
u8 pmax_linkrate:4;
u8 hmax_linkrate:4;
u8 change_count;
u8 virtual:1;
u8 _r_i:3;
u8 pptv:4;
u8 _r_j:4;
u8 routing_attr:4;
u8 conn_type;
u8 conn_el_index;
u8 conn_phy_link;
u8 _r_k[8];
} __attribute__ ((packed));
struct report_phy_sata_resp {
u8 _r_a[5];
u8 phy_id;
u8 _r_b;
u8 _r_c:6;
u8 affil_supp:1;
u8 affil_valid:1;
u32 _r_d;
u8 stp_sas_addr[8];
struct dev_to_host_fis fis;
u32 _r_e;
u8 affil_stp_ini_addr[8];
__be32 crc;
} __attribute__ ((packed));
struct smp_resp {
u8 frame_type;
u8 function;
u8 result;
u8 reserved;
union {
struct report_general_resp rg;
struct discover_resp disc;
struct report_phy_sata_resp rps;
};
} __attribute__ ((packed));
#else
#error "Bitfield order not defined!"
#endif
#endif /* _SAS_H_ */

View File

@@ -0,0 +1,60 @@
/*
* Support for SATA devices on Serial Attached SCSI (SAS) controllers
*
* Copyright (C) 2006 IBM Corporation
*
* Written by: Darrick J. Wong <djwong@us.ibm.com>, IBM Corporation
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
*/
#ifndef _SAS_ATA_H_
#define _SAS_ATA_H_
#include <linux/libata.h>
#include <scsi/libsas.h>
#ifdef CONFIG_SCSI_SAS_ATA
static inline int dev_is_sata(struct domain_device *dev)
{
return (dev->rphy->identify.target_port_protocols & SAS_PROTOCOL_SATA);
}
int sas_ata_init_host_and_port(struct domain_device *found_dev,
struct scsi_target *starget);
void sas_ata_task_abort(struct sas_task *task);
#else
static inline int dev_is_sata(struct domain_device *dev)
{
return 0;
}
static inline int sas_ata_init_host_and_port(struct domain_device *found_dev,
struct scsi_target *starget)
{
return 0;
}
static inline void sas_ata_task_abort(struct sas_task *task)
{
}
#endif
#endif /* _SAS_ATA_H_ */

514
kernel/include/scsi/scsi.h Normal file
View File

@@ -0,0 +1,514 @@
/*
* This header file contains public constants and structures used by
* the scsi code for linux.
*
* For documentation on the OPCODES, MESSAGES, and SENSE values,
* please consult the SCSI standard.
*/
#ifndef _SCSI_SCSI_H
#define _SCSI_SCSI_H
#include <linux/types.h>
struct scsi_cmnd;
/*
* The maximum number of SG segments that we will put inside a
* scatterlist (unless chaining is used). Should ideally fit inside a
* single page, to avoid a higher order allocation. We could define this
* to SG_MAX_SINGLE_ALLOC to pack correctly at the highest order. The
* minimum value is 32
*/
#define SCSI_MAX_SG_SEGMENTS 128
/*
* Like SCSI_MAX_SG_SEGMENTS, but for archs that have sg chaining. This limit
* is totally arbitrary, a setting of 2048 will get you at least 8mb ios.
*/
#ifdef ARCH_HAS_SG_CHAIN
#define SCSI_MAX_SG_CHAIN_SEGMENTS 2048
#else
#define SCSI_MAX_SG_CHAIN_SEGMENTS SCSI_MAX_SG_SEGMENTS
#endif
/*
* Special value for scanning to specify scanning or rescanning of all
* possible channels, (target) ids, or luns on a given shost.
*/
#define SCAN_WILD_CARD ~0
/*
* SCSI opcodes
*/
#define TEST_UNIT_READY 0x00
#define REZERO_UNIT 0x01
#define REQUEST_SENSE 0x03
#define FORMAT_UNIT 0x04
#define READ_BLOCK_LIMITS 0x05
#define REASSIGN_BLOCKS 0x07
#define INITIALIZE_ELEMENT_STATUS 0x07
#define READ_6 0x08
#define WRITE_6 0x0a
#define SEEK_6 0x0b
#define READ_REVERSE 0x0f
#define WRITE_FILEMARKS 0x10
#define SPACE 0x11
#define INQUIRY 0x12
#define RECOVER_BUFFERED_DATA 0x14
#define MODE_SELECT 0x15
#define RESERVE 0x16
#define RELEASE 0x17
#define COPY 0x18
#define ERASE 0x19
#define MODE_SENSE 0x1a
#define START_STOP 0x1b
#define RECEIVE_DIAGNOSTIC 0x1c
#define SEND_DIAGNOSTIC 0x1d
#define ALLOW_MEDIUM_REMOVAL 0x1e
#define SET_WINDOW 0x24
#define READ_CAPACITY 0x25
#define READ_10 0x28
#define WRITE_10 0x2a
#define SEEK_10 0x2b
#define POSITION_TO_ELEMENT 0x2b
#define WRITE_VERIFY 0x2e
#define VERIFY 0x2f
#define SEARCH_HIGH 0x30
#define SEARCH_EQUAL 0x31
#define SEARCH_LOW 0x32
#define SET_LIMITS 0x33
#define PRE_FETCH 0x34
#define READ_POSITION 0x34
#define SYNCHRONIZE_CACHE 0x35
#define LOCK_UNLOCK_CACHE 0x36
#define READ_DEFECT_DATA 0x37
#define MEDIUM_SCAN 0x38
#define COMPARE 0x39
#define COPY_VERIFY 0x3a
#define WRITE_BUFFER 0x3b
#define READ_BUFFER 0x3c
#define UPDATE_BLOCK 0x3d
#define READ_LONG 0x3e
#define WRITE_LONG 0x3f
#define CHANGE_DEFINITION 0x40
#define WRITE_SAME 0x41
#define READ_TOC 0x43
#define LOG_SELECT 0x4c
#define LOG_SENSE 0x4d
#define XDWRITEREAD_10 0x53
#define MODE_SELECT_10 0x55
#define RESERVE_10 0x56
#define RELEASE_10 0x57
#define MODE_SENSE_10 0x5a
#define PERSISTENT_RESERVE_IN 0x5e
#define PERSISTENT_RESERVE_OUT 0x5f
#define VARIABLE_LENGTH_CMD 0x7f
#define REPORT_LUNS 0xa0
#define MAINTENANCE_IN 0xa3
#define MAINTENANCE_OUT 0xa4
#define MOVE_MEDIUM 0xa5
#define EXCHANGE_MEDIUM 0xa6
#define READ_12 0xa8
#define WRITE_12 0xaa
#define WRITE_VERIFY_12 0xae
#define SEARCH_HIGH_12 0xb0
#define SEARCH_EQUAL_12 0xb1
#define SEARCH_LOW_12 0xb2
#define READ_ELEMENT_STATUS 0xb8
#define SEND_VOLUME_TAG 0xb6
#define WRITE_LONG_2 0xea
#define READ_16 0x88
#define WRITE_16 0x8a
#define VERIFY_16 0x8f
#define SERVICE_ACTION_IN 0x9e
/* values for service action in */
#define SAI_READ_CAPACITY_16 0x10
/* values for maintenance in */
#define MI_REPORT_TARGET_PGS 0x0a
/* values for maintenance out */
#define MO_SET_TARGET_PGS 0x0a
/* values for variable length command */
#define READ_32 0x09
#define WRITE_32 0x0b
/* Values for T10/04-262r7 */
#define ATA_16 0x85 /* 16-byte pass-thru */
#define ATA_12 0xa1 /* 12-byte pass-thru */
/*
* SCSI command lengths
*/
#define SCSI_MAX_VARLEN_CDB_SIZE 260
/* defined in T10 SCSI Primary Commands-2 (SPC2) */
struct scsi_varlen_cdb_hdr {
u8 opcode; /* opcode always == VARIABLE_LENGTH_CMD */
u8 control;
u8 misc[5];
u8 additional_cdb_length; /* total cdb length - 8 */
__be16 service_action;
/* service specific data follows */
};
static inline unsigned
scsi_varlen_cdb_length(const void *hdr)
{
return ((struct scsi_varlen_cdb_hdr *)hdr)->additional_cdb_length + 8;
}
extern const unsigned char scsi_command_size_tbl[8];
#define COMMAND_SIZE(opcode) scsi_command_size_tbl[((opcode) >> 5) & 7]
static inline unsigned
scsi_command_size(const unsigned char *cmnd)
{
return (cmnd[0] == VARIABLE_LENGTH_CMD) ?
scsi_varlen_cdb_length(cmnd) : COMMAND_SIZE(cmnd[0]);
}
/*
* SCSI Architecture Model (SAM) Status codes. Taken from SAM-3 draft
* T10/1561-D Revision 4 Draft dated 7th November 2002.
*/
#define SAM_STAT_GOOD 0x00
#define SAM_STAT_CHECK_CONDITION 0x02
#define SAM_STAT_CONDITION_MET 0x04
#define SAM_STAT_BUSY 0x08
#define SAM_STAT_INTERMEDIATE 0x10
#define SAM_STAT_INTERMEDIATE_CONDITION_MET 0x14
#define SAM_STAT_RESERVATION_CONFLICT 0x18
#define SAM_STAT_COMMAND_TERMINATED 0x22 /* obsolete in SAM-3 */
#define SAM_STAT_TASK_SET_FULL 0x28
#define SAM_STAT_ACA_ACTIVE 0x30
#define SAM_STAT_TASK_ABORTED 0x40
/** scsi_status_is_good - check the status return.
*
* @status: the status passed up from the driver (including host and
* driver components)
*
* This returns true for known good conditions that may be treated as
* command completed normally
*/
static inline int scsi_status_is_good(int status)
{
/*
* FIXME: bit0 is listed as reserved in SCSI-2, but is
* significant in SCSI-3. For now, we follow the SCSI-2
* behaviour and ignore reserved bits.
*/
status &= 0xfe;
return ((status == SAM_STAT_GOOD) ||
(status == SAM_STAT_INTERMEDIATE) ||
(status == SAM_STAT_INTERMEDIATE_CONDITION_MET) ||
/* FIXME: this is obsolete in SAM-3 */
(status == SAM_STAT_COMMAND_TERMINATED));
}
/*
* Status codes. These are deprecated as they are shifted 1 bit right
* from those found in the SCSI standards. This causes confusion for
* applications that are ported to several OSes. Prefer SAM Status codes
* above.
*/
#define GOOD 0x00
#define CHECK_CONDITION 0x01
#define CONDITION_GOOD 0x02
#define BUSY 0x04
#define INTERMEDIATE_GOOD 0x08
#define INTERMEDIATE_C_GOOD 0x0a
#define RESERVATION_CONFLICT 0x0c
#define COMMAND_TERMINATED 0x11
#define QUEUE_FULL 0x14
#define ACA_ACTIVE 0x18
#define TASK_ABORTED 0x20
#define STATUS_MASK 0xfe
/*
* SENSE KEYS
*/
#define NO_SENSE 0x00
#define RECOVERED_ERROR 0x01
#define NOT_READY 0x02
#define MEDIUM_ERROR 0x03
#define HARDWARE_ERROR 0x04
#define ILLEGAL_REQUEST 0x05
#define UNIT_ATTENTION 0x06
#define DATA_PROTECT 0x07
#define BLANK_CHECK 0x08
#define COPY_ABORTED 0x0a
#define ABORTED_COMMAND 0x0b
#define VOLUME_OVERFLOW 0x0d
#define MISCOMPARE 0x0e
/*
* DEVICE TYPES
* Please keep them in 0x%02x format for $MODALIAS to work
*/
#define TYPE_DISK 0x00
#define TYPE_TAPE 0x01
#define TYPE_PRINTER 0x02
#define TYPE_PROCESSOR 0x03 /* HP scanners use this */
#define TYPE_WORM 0x04 /* Treated as ROM by our system */
#define TYPE_ROM 0x05
#define TYPE_SCANNER 0x06
#define TYPE_MOD 0x07 /* Magneto-optical disk -
* - treated as TYPE_DISK */
#define TYPE_MEDIUM_CHANGER 0x08
#define TYPE_COMM 0x09 /* Communications device */
#define TYPE_RAID 0x0c
#define TYPE_ENCLOSURE 0x0d /* Enclosure Services Device */
#define TYPE_RBC 0x0e
#define TYPE_OSD 0x11
#define TYPE_NO_LUN 0x7f
/* SCSI protocols; these are taken from SPC-3 section 7.5 */
enum scsi_protocol {
SCSI_PROTOCOL_FCP = 0, /* Fibre Channel */
SCSI_PROTOCOL_SPI = 1, /* parallel SCSI */
SCSI_PROTOCOL_SSA = 2, /* Serial Storage Architecture - Obsolete */
SCSI_PROTOCOL_SBP = 3, /* firewire */
SCSI_PROTOCOL_SRP = 4, /* Infiniband RDMA */
SCSI_PROTOCOL_ISCSI = 5,
SCSI_PROTOCOL_SAS = 6,
SCSI_PROTOCOL_ADT = 7, /* Media Changers */
SCSI_PROTOCOL_ATA = 8,
SCSI_PROTOCOL_UNSPEC = 0xf, /* No specific protocol */
};
/* Returns a human-readable name for the device */
extern const char * scsi_device_type(unsigned type);
/*
* standard mode-select header prepended to all mode-select commands
*/
struct ccs_modesel_head {
__u8 _r1; /* reserved */
__u8 medium; /* device-specific medium type */
__u8 _r2; /* reserved */
__u8 block_desc_length; /* block descriptor length */
__u8 density; /* device-specific density code */
__u8 number_blocks_hi; /* number of blocks in this block desc */
__u8 number_blocks_med;
__u8 number_blocks_lo;
__u8 _r3;
__u8 block_length_hi; /* block length for blocks in this desc */
__u8 block_length_med;
__u8 block_length_lo;
};
/*
* ScsiLun: 8 byte LUN.
*/
struct scsi_lun {
__u8 scsi_lun[8];
};
/*
* The Well Known LUNS (SAM-3) in our int representation of a LUN
*/
#define SCSI_W_LUN_BASE 0xc100
#define SCSI_W_LUN_REPORT_LUNS (SCSI_W_LUN_BASE + 1)
#define SCSI_W_LUN_ACCESS_CONTROL (SCSI_W_LUN_BASE + 2)
#define SCSI_W_LUN_TARGET_LOG_PAGE (SCSI_W_LUN_BASE + 3)
static inline int scsi_is_wlun(unsigned int lun)
{
return (lun & 0xff00) == SCSI_W_LUN_BASE;
}
/*
* MESSAGE CODES
*/
#define COMMAND_COMPLETE 0x00
#define EXTENDED_MESSAGE 0x01
#define EXTENDED_MODIFY_DATA_POINTER 0x00
#define EXTENDED_SDTR 0x01
#define EXTENDED_EXTENDED_IDENTIFY 0x02 /* SCSI-I only */
#define EXTENDED_WDTR 0x03
#define EXTENDED_PPR 0x04
#define EXTENDED_MODIFY_BIDI_DATA_PTR 0x05
#define SAVE_POINTERS 0x02
#define RESTORE_POINTERS 0x03
#define DISCONNECT 0x04
#define INITIATOR_ERROR 0x05
#define ABORT_TASK_SET 0x06
#define MESSAGE_REJECT 0x07
#define NOP 0x08
#define MSG_PARITY_ERROR 0x09
#define LINKED_CMD_COMPLETE 0x0a
#define LINKED_FLG_CMD_COMPLETE 0x0b
#define TARGET_RESET 0x0c
#define ABORT_TASK 0x0d
#define CLEAR_TASK_SET 0x0e
#define INITIATE_RECOVERY 0x0f /* SCSI-II only */
#define RELEASE_RECOVERY 0x10 /* SCSI-II only */
#define CLEAR_ACA 0x16
#define LOGICAL_UNIT_RESET 0x17
#define SIMPLE_QUEUE_TAG 0x20
#define HEAD_OF_QUEUE_TAG 0x21
#define ORDERED_QUEUE_TAG 0x22
#define IGNORE_WIDE_RESIDUE 0x23
#define ACA 0x24
#define QAS_REQUEST 0x55
/* Old SCSI2 names, don't use in new code */
#define BUS_DEVICE_RESET TARGET_RESET
#define ABORT ABORT_TASK_SET
/*
* Host byte codes
*/
#define DID_OK 0x00 /* NO error */
#define DID_NO_CONNECT 0x01 /* Couldn't connect before timeout period */
#define DID_BUS_BUSY 0x02 /* BUS stayed busy through time out period */
#define DID_TIME_OUT 0x03 /* TIMED OUT for other reason */
#define DID_BAD_TARGET 0x04 /* BAD target. */
#define DID_ABORT 0x05 /* Told to abort for some other reason */
#define DID_PARITY 0x06 /* Parity error */
#define DID_ERROR 0x07 /* Internal error */
#define DID_RESET 0x08 /* Reset by somebody. */
#define DID_BAD_INTR 0x09 /* Got an interrupt we weren't expecting. */
#define DID_PASSTHROUGH 0x0a /* Force command past mid-layer */
#define DID_SOFT_ERROR 0x0b /* The low level driver just wish a retry */
#define DID_IMM_RETRY 0x0c /* Retry without decrementing retry count */
#define DID_REQUEUE 0x0d /* Requeue command (no immediate retry) also
* without decrementing the retry count */
#define DID_TRANSPORT_DISRUPTED 0x0e /* Transport error disrupted execution
* and the driver blocked the port to
* recover the link. Transport class will
* retry or fail IO */
#define DID_TRANSPORT_FAILFAST 0x0f /* Transport class fastfailed the io */
#define DRIVER_OK 0x00 /* Driver status */
/*
* These indicate the error that occurred, and what is available.
*/
#define DRIVER_BUSY 0x01
#define DRIVER_SOFT 0x02
#define DRIVER_MEDIA 0x03
#define DRIVER_ERROR 0x04
#define DRIVER_INVALID 0x05
#define DRIVER_TIMEOUT 0x06
#define DRIVER_HARD 0x07
#define DRIVER_SENSE 0x08
/*
* Internal return values.
*/
#define NEEDS_RETRY 0x2001
#define SUCCESS 0x2002
#define FAILED 0x2003
#define QUEUED 0x2004
#define SOFT_ERROR 0x2005
#define ADD_TO_MLQUEUE 0x2006
#define TIMEOUT_ERROR 0x2007
#define SCSI_RETURN_NOT_HANDLED 0x2008
/*
* Midlevel queue return values.
*/
#define SCSI_MLQUEUE_HOST_BUSY 0x1055
#define SCSI_MLQUEUE_DEVICE_BUSY 0x1056
#define SCSI_MLQUEUE_EH_RETRY 0x1057
#define SCSI_MLQUEUE_TARGET_BUSY 0x1058
/*
* Use these to separate status msg and our bytes
*
* These are set by:
*
* status byte = set from target device
* msg_byte = return status from host adapter itself.
* host_byte = set by low-level driver to indicate status.
* driver_byte = set by mid-level.
*/
#define status_byte(result) (((result) >> 1) & 0x7f)
#define msg_byte(result) (((result) >> 8) & 0xff)
#define host_byte(result) (((result) >> 16) & 0xff)
#define driver_byte(result) (((result) >> 24) & 0xff)
#define sense_class(sense) (((sense) >> 4) & 0x7)
#define sense_error(sense) ((sense) & 0xf)
#define sense_valid(sense) ((sense) & 0x80);
/*
* default timeouts
*/
#define FORMAT_UNIT_TIMEOUT (2 * 60 * 60 * HZ)
#define START_STOP_TIMEOUT (60 * HZ)
#define MOVE_MEDIUM_TIMEOUT (5 * 60 * HZ)
#define READ_ELEMENT_STATUS_TIMEOUT (5 * 60 * HZ)
#define READ_DEFECT_DATA_TIMEOUT (60 * HZ )
#define IDENTIFY_BASE 0x80
#define IDENTIFY(can_disconnect, lun) (IDENTIFY_BASE |\
((can_disconnect) ? 0x40 : 0) |\
((lun) & 0x07))
/*
* struct scsi_device::scsi_level values. For SCSI devices other than those
* prior to SCSI-2 (i.e. over 12 years old) this value is (resp[2] + 1)
* where "resp" is a byte array of the response to an INQUIRY. The scsi_level
* variable is visible to the user via sysfs.
*/
#define SCSI_UNKNOWN 0
#define SCSI_1 1
#define SCSI_1_CCS 2
#define SCSI_2 3
#define SCSI_3 4 /* SPC */
#define SCSI_SPC_2 5
#define SCSI_SPC_3 6
/*
* INQ PERIPHERAL QUALIFIERS
*/
#define SCSI_INQ_PQ_CON 0x00
#define SCSI_INQ_PQ_NOT_CON 0x01
#define SCSI_INQ_PQ_NOT_CAP 0x03
/*
* Here are some scsi specific ioctl commands which are sometimes useful.
*
* Note that include/linux/cdrom.h also defines IOCTL 0x5300 - 0x5395
*/
/* Used to obtain PUN and LUN info. Conflicts with CDROMAUDIOBUFSIZ */
#define SCSI_IOCTL_GET_IDLUN 0x5382
/* 0x5383 and 0x5384 were used for SCSI_IOCTL_TAGGED_{ENABLE,DISABLE} */
/* Used to obtain the host number of a device. */
#define SCSI_IOCTL_PROBE_HOST 0x5385
/* Used to obtain the bus number for a device */
#define SCSI_IOCTL_GET_BUS_NUMBER 0x5386
/* Used to obtain the PCI location of a device */
#define SCSI_IOCTL_GET_PCI 0x5387
/* Pull a u32 out of a SCSI message (using BE SCSI conventions) */
static inline __u32 scsi_to_u32(__u8 *ptr)
{
return (ptr[0]<<24) + (ptr[1]<<16) + (ptr[2]<<8) + ptr[3];
}
#endif /* _SCSI_SCSI_H */

View File

@@ -0,0 +1,322 @@
/*
* FC Transport BSG Interface
*
* Copyright (C) 2008 James Smart, Emulex Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef SCSI_BSG_FC_H
#define SCSI_BSG_FC_H
/*
* This file intended to be included by both kernel and user space
*/
#include <scsi/scsi.h>
/*
* FC Transport SGIO v4 BSG Message Support
*/
/* Default BSG request timeout (in seconds) */
#define FC_DEFAULT_BSG_TIMEOUT (10 * HZ)
/*
* Request Message Codes supported by the FC Transport
*/
/* define the class masks for the message codes */
#define FC_BSG_CLS_MASK 0xF0000000 /* find object class */
#define FC_BSG_HST_MASK 0x80000000 /* fc host class */
#define FC_BSG_RPT_MASK 0x40000000 /* fc rport class */
/* fc_host Message Codes */
#define FC_BSG_HST_ADD_RPORT (FC_BSG_HST_MASK | 0x00000001)
#define FC_BSG_HST_DEL_RPORT (FC_BSG_HST_MASK | 0x00000002)
#define FC_BSG_HST_ELS_NOLOGIN (FC_BSG_HST_MASK | 0x00000003)
#define FC_BSG_HST_CT (FC_BSG_HST_MASK | 0x00000004)
#define FC_BSG_HST_VENDOR (FC_BSG_HST_MASK | 0x000000FF)
/* fc_rport Message Codes */
#define FC_BSG_RPT_ELS (FC_BSG_RPT_MASK | 0x00000001)
#define FC_BSG_RPT_CT (FC_BSG_RPT_MASK | 0x00000002)
/*
* FC Address Identifiers in Message Structures :
*
* Whenever a command payload contains a FC Address Identifier
* (aka port_id), the value is effectively in big-endian
* order, thus the array elements are decoded as follows:
* element [0] is bits 23:16 of the FC Address Identifier
* element [1] is bits 15:8 of the FC Address Identifier
* element [2] is bits 7:0 of the FC Address Identifier
*/
/*
* FC Host Messages
*/
/* FC_BSG_HST_ADDR_PORT : */
/* Request:
* This message requests the FC host to login to the remote port
* at the specified N_Port_Id. The remote port is to be enumerated
* with the transport upon completion of the login.
*/
struct fc_bsg_host_add_rport {
uint8_t reserved;
/* FC Address Identier of the remote port to login to */
uint8_t port_id[3];
};
/* Response:
* There is no additional response data - fc_bsg_reply->result is sufficient
*/
/* FC_BSG_HST_DEL_RPORT : */
/* Request:
* This message requests the FC host to remove an enumerated
* remote port and to terminate the login to it.
*
* Note: The driver is free to reject this request if it desires to
* remain logged in with the remote port.
*/
struct fc_bsg_host_del_rport {
uint8_t reserved;
/* FC Address Identier of the remote port to logout of */
uint8_t port_id[3];
};
/* Response:
* There is no additional response data - fc_bsg_reply->result is sufficient
*/
/* FC_BSG_HST_ELS_NOLOGIN : */
/* Request:
* This message requests the FC_Host to send an ELS to a specific
* N_Port_ID. The host does not need to log into the remote port,
* nor does it need to enumerate the rport for further traffic
* (although, the FC host is free to do so if it desires).
*/
struct fc_bsg_host_els {
/*
* ELS Command Code being sent (must be the same as byte 0
* of the payload)
*/
uint8_t command_code;
/* FC Address Identier of the remote port to send the ELS to */
uint8_t port_id[3];
};
/* Response:
*/
/* fc_bsg_ctels_reply->status values */
#define FC_CTELS_STATUS_OK 0x00000000
#define FC_CTELS_STATUS_REJECT 0x00000001
#define FC_CTELS_STATUS_P_RJT 0x00000002
#define FC_CTELS_STATUS_F_RJT 0x00000003
#define FC_CTELS_STATUS_P_BSY 0x00000004
#define FC_CTELS_STATUS_F_BSY 0x00000006
struct fc_bsg_ctels_reply {
/*
* Note: An ELS LS_RJT may be reported in 2 ways:
* a) A status of FC_CTELS_STATUS_OK is returned. The caller
* is to look into the ELS receive payload to determine
* LS_ACC or LS_RJT (by contents of word 0). The reject
* data will be in word 1.
* b) A status of FC_CTELS_STATUS_REJECT is returned, The
* rjt_data field will contain valid data.
*
* Note: ELS LS_ACC is determined by an FC_CTELS_STATUS_OK, and
* the receive payload word 0 indicates LS_ACC
* (e.g. value is 0x02xxxxxx).
*
* Note: Similarly, a CT Reject may be reported in 2 ways:
* a) A status of FC_CTELS_STATUS_OK is returned. The caller
* is to look into the CT receive payload to determine
* Accept or Reject (by contents of word 2). The reject
* data will be in word 3.
* b) A status of FC_CTELS_STATUS_REJECT is returned, The
* rjt_data field will contain valid data.
*
* Note: x_RJT/BSY status will indicae that the rjt_data field
* is valid and contains the reason/explanation values.
*/
uint32_t status; /* See FC_CTELS_STATUS_xxx */
/* valid if status is not FC_CTELS_STATUS_OK */
struct {
uint8_t action; /* fragment_id for CT REJECT */
uint8_t reason_code;
uint8_t reason_explanation;
uint8_t vendor_unique;
} rjt_data;
};
/* FC_BSG_HST_CT : */
/* Request:
* This message requests that a CT Request be performed with the
* indicated N_Port_ID. The driver is responsible for logging in with
* the fabric and/or N_Port_ID, etc as per FC rules. This request does
* not mandate that the driver must enumerate the destination in the
* transport. The driver is allowed to decide whether to enumerate it,
* and whether to tear it down after the request.
*/
struct fc_bsg_host_ct {
uint8_t reserved;
/* FC Address Identier of the remote port to send the ELS to */
uint8_t port_id[3];
/*
* We need words 0-2 of the generic preamble for the LLD's
*/
uint32_t preamble_word0; /* revision & IN_ID */
uint32_t preamble_word1; /* GS_Type, GS_SubType, Options, Rsvd */
uint32_t preamble_word2; /* Cmd Code, Max Size */
};
/* Response:
*
* The reply structure is an fc_bsg_ctels_reply structure
*/
/* FC_BSG_HST_VENDOR : */
/* Request:
* Note: When specifying vendor_id, be sure to read the Vendor Type and ID
* formatting requirements specified in scsi_netlink.h
*/
struct fc_bsg_host_vendor {
/*
* Identifies the vendor that the message is formatted for. This
* should be the recipient of the message.
*/
uint64_t vendor_id;
/* start of vendor command area */
uint32_t vendor_cmd[0];
};
/* Response:
*/
struct fc_bsg_host_vendor_reply {
/* start of vendor response area */
uint32_t vendor_rsp[0];
};
/*
* FC Remote Port Messages
*/
/* FC_BSG_RPT_ELS : */
/* Request:
* This message requests that an ELS be performed with the rport.
*/
struct fc_bsg_rport_els {
/*
* ELS Command Code being sent (must be the same as
* byte 0 of the payload)
*/
uint8_t els_code;
};
/* Response:
*
* The reply structure is an fc_bsg_ctels_reply structure
*/
/* FC_BSG_RPT_CT : */
/* Request:
* This message requests that a CT Request be performed with the rport.
*/
struct fc_bsg_rport_ct {
/*
* We need words 0-2 of the generic preamble for the LLD's
*/
uint32_t preamble_word0; /* revision & IN_ID */
uint32_t preamble_word1; /* GS_Type, GS_SubType, Options, Rsvd */
uint32_t preamble_word2; /* Cmd Code, Max Size */
};
/* Response:
*
* The reply structure is an fc_bsg_ctels_reply structure
*/
/* request (CDB) structure of the sg_io_v4 */
struct fc_bsg_request {
uint32_t msgcode;
union {
struct fc_bsg_host_add_rport h_addrport;
struct fc_bsg_host_del_rport h_delrport;
struct fc_bsg_host_els h_els;
struct fc_bsg_host_ct h_ct;
struct fc_bsg_host_vendor h_vendor;
struct fc_bsg_rport_els r_els;
struct fc_bsg_rport_ct r_ct;
} rqst_data;
} __attribute__((packed));
/* response (request sense data) structure of the sg_io_v4 */
struct fc_bsg_reply {
/*
* The completion result. Result exists in two forms:
* if negative, it is an -Exxx system errno value. There will
* be no further reply information supplied.
* else, it's the 4-byte scsi error result, with driver, host,
* msg and status fields. The per-msgcode reply structure
* will contain valid data.
*/
uint32_t result;
/* If there was reply_payload, how much was recevied ? */
uint32_t reply_payload_rcv_len;
union {
struct fc_bsg_host_vendor_reply vendor_reply;
struct fc_bsg_ctels_reply ctels_reply;
} reply_data;
};
#endif /* SCSI_BSG_FC_H */

View File

@@ -0,0 +1,305 @@
#ifndef _SCSI_SCSI_CMND_H
#define _SCSI_SCSI_CMND_H
#include <linux/dma-mapping.h>
#include <linux/blkdev.h>
#include <linux/list.h>
#include <linux/types.h>
#include <linux/timer.h>
#include <linux/scatterlist.h>
struct Scsi_Host;
struct scsi_device;
/*
* MAX_COMMAND_SIZE is:
* The longest fixed-length SCSI CDB as per the SCSI standard.
* fixed-length means: commands that their size can be determined
* by their opcode and the CDB does not carry a length specifier, (unlike
* the VARIABLE_LENGTH_CMD(0x7f) command). This is actually not exactly
* true and the SCSI standard also defines extended commands and
* vendor specific commands that can be bigger than 16 bytes. The kernel
* will support these using the same infrastructure used for VARLEN CDB's.
* So in effect MAX_COMMAND_SIZE means the maximum size command scsi-ml
* supports without specifying a cmd_len by ULD's
*/
#define MAX_COMMAND_SIZE 16
#if (MAX_COMMAND_SIZE > BLK_MAX_CDB)
# error MAX_COMMAND_SIZE can not be bigger than BLK_MAX_CDB
#endif
struct scsi_data_buffer {
struct sg_table table;
unsigned length;
int resid;
};
/* embedded in scsi_cmnd */
struct scsi_pointer {
char *ptr; /* data pointer */
int this_residual; /* left in this buffer */
struct scatterlist *buffer; /* which buffer */
int buffers_residual; /* how many buffers left */
dma_addr_t dma_handle;
volatile int Status;
volatile int Message;
volatile int have_data_in;
volatile int sent_command;
volatile int phase;
};
struct scsi_cmnd {
struct scsi_device *device;
struct list_head list; /* scsi_cmnd participates in queue lists */
struct list_head eh_entry; /* entry for the host eh_cmd_q */
int eh_eflags; /* Used by error handlr */
/*
* A SCSI Command is assigned a nonzero serial_number before passed
* to the driver's queue command function. The serial_number is
* cleared when scsi_done is entered indicating that the command
* has been completed. It is a bug for LLDDs to use this number
* for purposes other than printk (and even that is only useful
* for debugging).
*/
unsigned long serial_number;
/*
* This is set to jiffies as it was when the command was first
* allocated. It is used to time how long the command has
* been outstanding
*/
unsigned long jiffies_at_alloc;
int retries;
int allowed;
unsigned char prot_op;
unsigned char prot_type;
unsigned short cmd_len;
enum dma_data_direction sc_data_direction;
/* These elements define the operation we are about to perform */
unsigned char *cmnd;
/* These elements define the operation we ultimately want to perform */
struct scsi_data_buffer sdb;
struct scsi_data_buffer *prot_sdb;
unsigned underflow; /* Return error if less than
this amount is transferred */
unsigned transfersize; /* How much we are guaranteed to
transfer with each SCSI transfer
(ie, between disconnect /
reconnects. Probably == sector
size */
struct request *request; /* The command we are
working on */
#define SCSI_SENSE_BUFFERSIZE 96
unsigned char *sense_buffer;
/* obtained by REQUEST SENSE when
* CHECK CONDITION is received on original
* command (auto-sense) */
/* Low-level done function - can be used by low-level driver to point
* to completion function. Not used by mid/upper level code. */
void (*scsi_done) (struct scsi_cmnd *);
/*
* The following fields can be written to by the host specific code.
* Everything else should be left alone.
*/
struct scsi_pointer SCp; /* Scratchpad used by some host adapters */
unsigned char *host_scribble; /* The host adapter is allowed to
* call scsi_malloc and get some memory
* and hang it here. The host adapter
* is also expected to call scsi_free
* to release this memory. (The memory
* obtained by scsi_malloc is guaranteed
* to be at an address < 16Mb). */
int result; /* Status code from lower level driver */
unsigned char tag; /* SCSI-II queued command tag */
};
extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, gfp_t);
extern struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *, gfp_t);
extern void scsi_put_command(struct scsi_cmnd *);
extern void __scsi_put_command(struct Scsi_Host *, struct scsi_cmnd *,
struct device *);
extern void scsi_finish_command(struct scsi_cmnd *cmd);
extern void *scsi_kmap_atomic_sg(struct scatterlist *sg, int sg_count,
size_t *offset, size_t *len);
extern void scsi_kunmap_atomic_sg(void *virt);
extern int scsi_init_io(struct scsi_cmnd *cmd, gfp_t gfp_mask);
extern void scsi_release_buffers(struct scsi_cmnd *cmd);
extern int scsi_dma_map(struct scsi_cmnd *cmd);
extern void scsi_dma_unmap(struct scsi_cmnd *cmd);
struct scsi_cmnd *scsi_allocate_command(gfp_t gfp_mask);
void scsi_free_command(gfp_t gfp_mask, struct scsi_cmnd *cmd);
static inline unsigned scsi_sg_count(struct scsi_cmnd *cmd)
{
return cmd->sdb.table.nents;
}
static inline struct scatterlist *scsi_sglist(struct scsi_cmnd *cmd)
{
return cmd->sdb.table.sgl;
}
static inline unsigned scsi_bufflen(struct scsi_cmnd *cmd)
{
return cmd->sdb.length;
}
static inline void scsi_set_resid(struct scsi_cmnd *cmd, int resid)
{
cmd->sdb.resid = resid;
}
static inline int scsi_get_resid(struct scsi_cmnd *cmd)
{
return cmd->sdb.resid;
}
#define scsi_for_each_sg(cmd, sg, nseg, __i) \
for_each_sg(scsi_sglist(cmd), sg, nseg, __i)
static inline int scsi_bidi_cmnd(struct scsi_cmnd *cmd)
{
return blk_bidi_rq(cmd->request) &&
(cmd->request->next_rq->special != NULL);
}
static inline struct scsi_data_buffer *scsi_in(struct scsi_cmnd *cmd)
{
return scsi_bidi_cmnd(cmd) ?
cmd->request->next_rq->special : &cmd->sdb;
}
static inline struct scsi_data_buffer *scsi_out(struct scsi_cmnd *cmd)
{
return &cmd->sdb;
}
static inline int scsi_sg_copy_from_buffer(struct scsi_cmnd *cmd,
void *buf, int buflen)
{
return sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd),
buf, buflen);
}
static inline int scsi_sg_copy_to_buffer(struct scsi_cmnd *cmd,
void *buf, int buflen)
{
return sg_copy_to_buffer(scsi_sglist(cmd), scsi_sg_count(cmd),
buf, buflen);
}
/*
* The operations below are hints that tell the controller driver how
* to handle I/Os with DIF or similar types of protection information.
*/
enum scsi_prot_operations {
/* Normal I/O */
SCSI_PROT_NORMAL = 0,
/* OS-HBA: Protected, HBA-Target: Unprotected */
SCSI_PROT_READ_INSERT,
SCSI_PROT_WRITE_STRIP,
/* OS-HBA: Unprotected, HBA-Target: Protected */
SCSI_PROT_READ_STRIP,
SCSI_PROT_WRITE_INSERT,
/* OS-HBA: Protected, HBA-Target: Protected */
SCSI_PROT_READ_PASS,
SCSI_PROT_WRITE_PASS,
};
static inline void scsi_set_prot_op(struct scsi_cmnd *scmd, unsigned char op)
{
scmd->prot_op = op;
}
static inline unsigned char scsi_get_prot_op(struct scsi_cmnd *scmd)
{
return scmd->prot_op;
}
/*
* The controller usually does not know anything about the target it
* is communicating with. However, when DIX is enabled the controller
* must be know target type so it can verify the protection
* information passed along with the I/O.
*/
enum scsi_prot_target_type {
SCSI_PROT_DIF_TYPE0 = 0,
SCSI_PROT_DIF_TYPE1,
SCSI_PROT_DIF_TYPE2,
SCSI_PROT_DIF_TYPE3,
};
static inline void scsi_set_prot_type(struct scsi_cmnd *scmd, unsigned char type)
{
scmd->prot_type = type;
}
static inline unsigned char scsi_get_prot_type(struct scsi_cmnd *scmd)
{
return scmd->prot_type;
}
static inline sector_t scsi_get_lba(struct scsi_cmnd *scmd)
{
return blk_rq_pos(scmd->request);
}
static inline unsigned scsi_prot_sg_count(struct scsi_cmnd *cmd)
{
return cmd->prot_sdb ? cmd->prot_sdb->table.nents : 0;
}
static inline struct scatterlist *scsi_prot_sglist(struct scsi_cmnd *cmd)
{
return cmd->prot_sdb ? cmd->prot_sdb->table.sgl : NULL;
}
static inline struct scsi_data_buffer *scsi_prot(struct scsi_cmnd *cmd)
{
return cmd->prot_sdb;
}
#define scsi_for_each_prot_sg(cmd, sg, nseg, __i) \
for_each_sg(scsi_prot_sglist(cmd), sg, nseg, __i)
static inline void set_msg_byte(struct scsi_cmnd *cmd, char status)
{
cmd->result |= status << 8;
}
static inline void set_host_byte(struct scsi_cmnd *cmd, char status)
{
cmd->result |= status << 16;
}
static inline void set_driver_byte(struct scsi_cmnd *cmd, char status)
{
cmd->result |= status << 24;
}
#endif /* _SCSI_SCSI_CMND_H */

View File

@@ -0,0 +1,24 @@
#ifndef _SCSI_SCSI_DBG_H
#define _SCSI_SCSI_DBG_H
struct scsi_cmnd;
struct scsi_sense_hdr;
extern void scsi_print_command(struct scsi_cmnd *);
extern void __scsi_print_command(unsigned char *);
extern void scsi_show_extd_sense(unsigned char, unsigned char);
extern void scsi_show_sense_hdr(struct scsi_sense_hdr *);
extern void scsi_print_sense_hdr(const char *, struct scsi_sense_hdr *);
extern void scsi_cmd_print_sense_hdr(struct scsi_cmnd *, const char *,
struct scsi_sense_hdr *);
extern void scsi_print_sense(char *, struct scsi_cmnd *);
extern void __scsi_print_sense(const char *name,
const unsigned char *sense_buffer,
int sense_len);
extern void scsi_show_result(int);
extern void scsi_print_result(struct scsi_cmnd *);
extern void scsi_print_status(unsigned char);
extern const char *scsi_sense_key_string(unsigned char);
extern const char *scsi_extd_sense_format(unsigned char, unsigned char);
#endif /* _SCSI_SCSI_DBG_H */

View File

@@ -0,0 +1,461 @@
#ifndef _SCSI_SCSI_DEVICE_H
#define _SCSI_SCSI_DEVICE_H
#include <linux/device.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/blkdev.h>
#include <scsi/scsi.h>
#include <asm/atomic.h>
struct request_queue;
struct scsi_cmnd;
struct scsi_lun;
struct scsi_sense_hdr;
struct scsi_mode_data {
__u32 length;
__u16 block_descriptor_length;
__u8 medium_type;
__u8 device_specific;
__u8 header_length;
__u8 longlba:1;
};
/*
* sdev state: If you alter this, you also need to alter scsi_sysfs.c
* (for the ascii descriptions) and the state model enforcer:
* scsi_lib:scsi_device_set_state().
*/
enum scsi_device_state {
SDEV_CREATED = 1, /* device created but not added to sysfs
* Only internal commands allowed (for inq) */
SDEV_RUNNING, /* device properly configured
* All commands allowed */
SDEV_CANCEL, /* beginning to delete device
* Only error handler commands allowed */
SDEV_DEL, /* device deleted
* no commands allowed */
SDEV_QUIESCE, /* Device quiescent. No block commands
* will be accepted, only specials (which
* originate in the mid-layer) */
SDEV_OFFLINE, /* Device offlined (by error handling or
* user request */
SDEV_BLOCK, /* Device blocked by scsi lld. No
* scsi commands from user or midlayer
* should be issued to the scsi
* lld. */
SDEV_CREATED_BLOCK, /* same as above but for created devices */
};
enum scsi_device_event {
SDEV_EVT_MEDIA_CHANGE = 1, /* media has changed */
SDEV_EVT_LAST = SDEV_EVT_MEDIA_CHANGE,
SDEV_EVT_MAXBITS = SDEV_EVT_LAST + 1
};
struct scsi_event {
enum scsi_device_event evt_type;
struct list_head node;
/* put union of data structures, for non-simple event types,
* here
*/
};
struct scsi_device {
struct Scsi_Host *host;
struct request_queue *request_queue;
/* the next two are protected by the host->host_lock */
struct list_head siblings; /* list of all devices on this host */
struct list_head same_target_siblings; /* just the devices sharing same target id */
/* this is now protected by the request_queue->queue_lock */
unsigned int device_busy; /* commands actually active on
* low-level. protected by queue_lock. */
spinlock_t list_lock;
struct list_head cmd_list; /* queue of in use SCSI Command structures */
struct list_head starved_entry;
struct scsi_cmnd *current_cmnd; /* currently active command */
unsigned short queue_depth; /* How deep of a queue we want */
unsigned short last_queue_full_depth; /* These two are used by */
unsigned short last_queue_full_count; /* scsi_track_queue_full() */
unsigned long last_queue_full_time;/* don't let QUEUE_FULLs on the same
jiffie count on our counter, they
could all be from the same event. */
unsigned int id, lun, channel;
unsigned int manufacturer; /* Manufacturer of device, for using
* vendor-specific cmd's */
unsigned sector_size; /* size in bytes */
void *hostdata; /* available to low-level driver */
char type;
char scsi_level;
char inq_periph_qual; /* PQ from INQUIRY data */
unsigned char inquiry_len; /* valid bytes in 'inquiry' */
unsigned char * inquiry; /* INQUIRY response data */
const char * vendor; /* [back_compat] point into 'inquiry' ... */
const char * model; /* ... after scan; point to static string */
const char * rev; /* ... "nullnullnullnull" before scan */
unsigned char current_tag; /* current tag */
struct scsi_target *sdev_target; /* used only for single_lun */
unsigned int sdev_bflags; /* black/white flags as also found in
* scsi_devinfo.[hc]. For now used only to
* pass settings from slave_alloc to scsi
* core. */
unsigned writeable:1;
unsigned removable:1;
unsigned changed:1; /* Data invalid due to media change */
unsigned busy:1; /* Used to prevent races */
unsigned lockable:1; /* Able to prevent media removal */
unsigned locked:1; /* Media removal disabled */
unsigned borken:1; /* Tell the Seagate driver to be
* painfully slow on this device */
unsigned disconnect:1; /* can disconnect */
unsigned soft_reset:1; /* Uses soft reset option */
unsigned sdtr:1; /* Device supports SDTR messages */
unsigned wdtr:1; /* Device supports WDTR messages */
unsigned ppr:1; /* Device supports PPR messages */
unsigned tagged_supported:1; /* Supports SCSI-II tagged queuing */
unsigned simple_tags:1; /* simple queue tag messages are enabled */
unsigned ordered_tags:1;/* ordered queue tag messages are enabled */
unsigned was_reset:1; /* There was a bus reset on the bus for
* this device */
unsigned expecting_cc_ua:1; /* Expecting a CHECK_CONDITION/UNIT_ATTN
* because we did a bus reset. */
unsigned use_10_for_rw:1; /* first try 10-byte read / write */
unsigned use_10_for_ms:1; /* first try 10-byte mode sense/select */
unsigned skip_ms_page_8:1; /* do not use MODE SENSE page 0x08 */
unsigned skip_ms_page_3f:1; /* do not use MODE SENSE page 0x3f */
unsigned use_192_bytes_for_3f:1; /* ask for 192 bytes from page 0x3f */
unsigned no_start_on_add:1; /* do not issue start on add */
unsigned allow_restart:1; /* issue START_UNIT in error handler */
unsigned manage_start_stop:1; /* Let HLD (sd) manage start/stop */
unsigned start_stop_pwr_cond:1; /* Set power cond. in START_STOP_UNIT */
unsigned no_uld_attach:1; /* disable connecting to upper level drivers */
unsigned select_no_atn:1;
unsigned fix_capacity:1; /* READ_CAPACITY is too high by 1 */
unsigned guess_capacity:1; /* READ_CAPACITY might be too high by 1 */
unsigned retry_hwerror:1; /* Retry HARDWARE_ERROR */
unsigned last_sector_bug:1; /* do not use multisector accesses on
SD_LAST_BUGGY_SECTORS */
unsigned is_visible:1; /* is the device visible in sysfs */
DECLARE_BITMAP(supported_events, SDEV_EVT_MAXBITS); /* supported events */
struct list_head event_list; /* asserted events */
struct work_struct event_work;
unsigned int device_blocked; /* Device returned QUEUE_FULL. */
unsigned int max_device_blocked; /* what device_blocked counts down from */
#define SCSI_DEFAULT_DEVICE_BLOCKED 3
atomic_t iorequest_cnt;
atomic_t iodone_cnt;
atomic_t ioerr_cnt;
struct device sdev_gendev,
sdev_dev;
struct execute_work ew; /* used to get process context on put */
struct scsi_dh_data *scsi_dh_data;
enum scsi_device_state sdev_state;
unsigned long sdev_data[0];
} __attribute__((aligned(sizeof(unsigned long))));
struct scsi_dh_devlist {
char *vendor;
char *model;
};
struct scsi_device_handler {
/* Used by the infrastructure */
struct list_head list; /* list of scsi_device_handlers */
/* Filled by the hardware handler */
struct module *module;
const char *name;
const struct scsi_dh_devlist *devlist;
int (*check_sense)(struct scsi_device *, struct scsi_sense_hdr *);
int (*attach)(struct scsi_device *);
void (*detach)(struct scsi_device *);
int (*activate)(struct scsi_device *);
int (*prep_fn)(struct scsi_device *, struct request *);
int (*set_params)(struct scsi_device *, const char *);
};
struct scsi_dh_data {
struct scsi_device_handler *scsi_dh;
struct scsi_device *sdev;
struct kref kref;
char buf[0];
};
#define to_scsi_device(d) \
container_of(d, struct scsi_device, sdev_gendev)
#define class_to_sdev(d) \
container_of(d, struct scsi_device, sdev_dev)
#define transport_class_to_sdev(class_dev) \
to_scsi_device(class_dev->parent)
#define sdev_printk(prefix, sdev, fmt, a...) \
dev_printk(prefix, &(sdev)->sdev_gendev, fmt, ##a)
#define scmd_printk(prefix, scmd, fmt, a...) \
(scmd)->request->rq_disk ? \
sdev_printk(prefix, (scmd)->device, "[%s] " fmt, \
(scmd)->request->rq_disk->disk_name, ##a) : \
sdev_printk(prefix, (scmd)->device, fmt, ##a)
enum scsi_target_state {
STARGET_CREATED = 1,
STARGET_RUNNING,
STARGET_DEL,
};
/*
* scsi_target: representation of a scsi target, for now, this is only
* used for single_lun devices. If no one has active IO to the target,
* starget_sdev_user is NULL, else it points to the active sdev.
*/
struct scsi_target {
struct scsi_device *starget_sdev_user;
struct list_head siblings;
struct list_head devices;
struct device dev;
unsigned int reap_ref; /* protected by the host lock */
unsigned int channel;
unsigned int id; /* target id ... replace
* scsi_device.id eventually */
unsigned int create:1; /* signal that it needs to be added */
unsigned int single_lun:1; /* Indicates we should only
* allow I/O to one of the luns
* for the device at a time. */
unsigned int pdt_1f_for_no_lun; /* PDT = 0x1f */
/* means no lun present */
/* commands actually active on LLD. protected by host lock. */
unsigned int target_busy;
/*
* LLDs should set this in the slave_alloc host template callout.
* If set to zero then there is not limit.
*/
unsigned int can_queue;
unsigned int target_blocked;
unsigned int max_target_blocked;
#define SCSI_DEFAULT_TARGET_BLOCKED 3
char scsi_level;
struct execute_work ew;
enum scsi_target_state state;
void *hostdata; /* available to low-level driver */
unsigned long starget_data[0]; /* for the transport */
/* starget_data must be the last element!!!! */
} __attribute__((aligned(sizeof(unsigned long))));
#define to_scsi_target(d) container_of(d, struct scsi_target, dev)
static inline struct scsi_target *scsi_target(struct scsi_device *sdev)
{
return to_scsi_target(sdev->sdev_gendev.parent);
}
#define transport_class_to_starget(class_dev) \
to_scsi_target(class_dev->parent)
#define starget_printk(prefix, starget, fmt, a...) \
dev_printk(prefix, &(starget)->dev, fmt, ##a)
extern struct scsi_device *__scsi_add_device(struct Scsi_Host *,
uint, uint, uint, void *hostdata);
extern int scsi_add_device(struct Scsi_Host *host, uint channel,
uint target, uint lun);
extern int scsi_register_device_handler(struct scsi_device_handler *scsi_dh);
extern void scsi_remove_device(struct scsi_device *);
extern int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh);
extern int scsi_device_get(struct scsi_device *);
extern void scsi_device_put(struct scsi_device *);
extern struct scsi_device *scsi_device_lookup(struct Scsi_Host *,
uint, uint, uint);
extern struct scsi_device *__scsi_device_lookup(struct Scsi_Host *,
uint, uint, uint);
extern struct scsi_device *scsi_device_lookup_by_target(struct scsi_target *,
uint);
extern struct scsi_device *__scsi_device_lookup_by_target(struct scsi_target *,
uint);
extern void starget_for_each_device(struct scsi_target *, void *,
void (*fn)(struct scsi_device *, void *));
extern void __starget_for_each_device(struct scsi_target *, void *,
void (*fn)(struct scsi_device *,
void *));
/* only exposed to implement shost_for_each_device */
extern struct scsi_device *__scsi_iterate_devices(struct Scsi_Host *,
struct scsi_device *);
/**
* shost_for_each_device - iterate over all devices of a host
* @sdev: the &struct scsi_device to use as a cursor
* @shost: the &struct scsi_host to iterate over
*
* Iterator that returns each device attached to @shost. This loop
* takes a reference on each device and releases it at the end. If
* you break out of the loop, you must call scsi_device_put(sdev).
*/
#define shost_for_each_device(sdev, shost) \
for ((sdev) = __scsi_iterate_devices((shost), NULL); \
(sdev); \
(sdev) = __scsi_iterate_devices((shost), (sdev)))
/**
* __shost_for_each_device - iterate over all devices of a host (UNLOCKED)
* @sdev: the &struct scsi_device to use as a cursor
* @shost: the &struct scsi_host to iterate over
*
* Iterator that returns each device attached to @shost. It does _not_
* take a reference on the scsi_device, so the whole loop must be
* protected by shost->host_lock.
*
* Note: The only reason to use this is because you need to access the
* device list in interrupt context. Otherwise you really want to use
* shost_for_each_device instead.
*/
#define __shost_for_each_device(sdev, shost) \
list_for_each_entry((sdev), &((shost)->__devices), siblings)
extern void scsi_adjust_queue_depth(struct scsi_device *, int, int);
extern int scsi_track_queue_full(struct scsi_device *, int);
extern int scsi_set_medium_removal(struct scsi_device *, char);
extern int scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
unsigned char *buffer, int len, int timeout,
int retries, struct scsi_mode_data *data,
struct scsi_sense_hdr *);
extern int scsi_mode_select(struct scsi_device *sdev, int pf, int sp,
int modepage, unsigned char *buffer, int len,
int timeout, int retries,
struct scsi_mode_data *data,
struct scsi_sense_hdr *);
extern int scsi_test_unit_ready(struct scsi_device *sdev, int timeout,
int retries, struct scsi_sense_hdr *sshdr);
extern unsigned char *scsi_get_vpd_page(struct scsi_device *, u8 page);
extern int scsi_device_set_state(struct scsi_device *sdev,
enum scsi_device_state state);
extern struct scsi_event *sdev_evt_alloc(enum scsi_device_event evt_type,
gfp_t gfpflags);
extern void sdev_evt_send(struct scsi_device *sdev, struct scsi_event *evt);
extern void sdev_evt_send_simple(struct scsi_device *sdev,
enum scsi_device_event evt_type, gfp_t gfpflags);
extern int scsi_device_quiesce(struct scsi_device *sdev);
extern void scsi_device_resume(struct scsi_device *sdev);
extern void scsi_target_quiesce(struct scsi_target *);
extern void scsi_target_resume(struct scsi_target *);
extern void scsi_scan_target(struct device *parent, unsigned int channel,
unsigned int id, unsigned int lun, int rescan);
extern void scsi_target_reap(struct scsi_target *);
extern void scsi_target_block(struct device *);
extern void scsi_target_unblock(struct device *);
extern void scsi_remove_target(struct device *);
extern void int_to_scsilun(unsigned int, struct scsi_lun *);
extern int scsilun_to_int(struct scsi_lun *);
extern const char *scsi_device_state_name(enum scsi_device_state);
extern int scsi_is_sdev_device(const struct device *);
extern int scsi_is_target_device(const struct device *);
extern int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
int data_direction, void *buffer, unsigned bufflen,
unsigned char *sense, int timeout, int retries,
int flag, int *resid);
extern int scsi_execute_req(struct scsi_device *sdev, const unsigned char *cmd,
int data_direction, void *buffer, unsigned bufflen,
struct scsi_sense_hdr *, int timeout, int retries,
int *resid);
static inline int __must_check scsi_device_reprobe(struct scsi_device *sdev)
{
return device_reprobe(&sdev->sdev_gendev);
}
static inline unsigned int sdev_channel(struct scsi_device *sdev)
{
return sdev->channel;
}
static inline unsigned int sdev_id(struct scsi_device *sdev)
{
return sdev->id;
}
#define scmd_id(scmd) sdev_id((scmd)->device)
#define scmd_channel(scmd) sdev_channel((scmd)->device)
/*
* checks for positions of the SCSI state machine
*/
static inline int scsi_device_online(struct scsi_device *sdev)
{
return (sdev->sdev_state != SDEV_OFFLINE &&
sdev->sdev_state != SDEV_DEL);
}
static inline int scsi_device_blocked(struct scsi_device *sdev)
{
return sdev->sdev_state == SDEV_BLOCK ||
sdev->sdev_state == SDEV_CREATED_BLOCK;
}
static inline int scsi_device_created(struct scsi_device *sdev)
{
return sdev->sdev_state == SDEV_CREATED ||
sdev->sdev_state == SDEV_CREATED_BLOCK;
}
/* accessor functions for the SCSI parameters */
static inline int scsi_device_sync(struct scsi_device *sdev)
{
return sdev->sdtr;
}
static inline int scsi_device_wide(struct scsi_device *sdev)
{
return sdev->wdtr;
}
static inline int scsi_device_dt(struct scsi_device *sdev)
{
return sdev->ppr;
}
static inline int scsi_device_dt_only(struct scsi_device *sdev)
{
if (sdev->inquiry_len < 57)
return 0;
return (sdev->inquiry[56] & 0x0c) == 0x04;
}
static inline int scsi_device_ius(struct scsi_device *sdev)
{
if (sdev->inquiry_len < 57)
return 0;
return sdev->inquiry[56] & 0x01;
}
static inline int scsi_device_qas(struct scsi_device *sdev)
{
if (sdev->inquiry_len < 57)
return 0;
return sdev->inquiry[56] & 0x02;
}
static inline int scsi_device_enclosure(struct scsi_device *sdev)
{
return sdev->inquiry ? (sdev->inquiry[6] & (1<<6)) : 1;
}
static inline int scsi_device_protection(struct scsi_device *sdev)
{
return sdev->scsi_level > SCSI_2 && sdev->inquiry[5] & (1<<0);
}
#define MODULE_ALIAS_SCSI_DEVICE(type) \
MODULE_ALIAS("scsi:t-" __stringify(type) "*")
#define SCSI_DEVICE_MODALIAS_FMT "scsi:t-0x%02x"
#endif /* _SCSI_SCSI_DEVICE_H */

View File

@@ -0,0 +1,33 @@
#ifndef _SCSI_SCSI_DEVINFO_H
#define _SCSI_SCSI_DEVINFO_H
/*
* Flags for SCSI devices that need special treatment
*/
#define BLIST_NOLUN 0x001 /* Only scan LUN 0 */
#define BLIST_FORCELUN 0x002 /* Known to have LUNs, force scanning,
deprecated: Use max_luns=N */
#define BLIST_BORKEN 0x004 /* Flag for broken handshaking */
#define BLIST_KEY 0x008 /* unlock by special command */
#define BLIST_SINGLELUN 0x010 /* Do not use LUNs in parallel */
#define BLIST_NOTQ 0x020 /* Buggy Tagged Command Queuing */
#define BLIST_SPARSELUN 0x040 /* Non consecutive LUN numbering */
#define BLIST_MAX5LUN 0x080 /* Avoid LUNS >= 5 */
#define BLIST_ISROM 0x100 /* Treat as (removable) CD-ROM */
#define BLIST_LARGELUN 0x200 /* LUNs past 7 on a SCSI-2 device */
#define BLIST_INQUIRY_36 0x400 /* override additional length field */
#define BLIST_INQUIRY_58 0x800 /* ... for broken inquiry responses */
#define BLIST_NOSTARTONADD 0x1000 /* do not do automatic start on add */
#define BLIST_MS_SKIP_PAGE_08 0x2000 /* do not send ms page 0x08 */
#define BLIST_MS_SKIP_PAGE_3F 0x4000 /* do not send ms page 0x3f */
#define BLIST_USE_10_BYTE_MS 0x8000 /* use 10 byte ms before 6 byte ms */
#define BLIST_MS_192_BYTES_FOR_3F 0x10000 /* 192 byte ms page 0x3f request */
#define BLIST_REPORTLUN2 0x20000 /* try REPORT_LUNS even for SCSI-2 devs
(if HBA supports more than 8 LUNs) */
#define BLIST_NOREPORTLUN 0x40000 /* don't try REPORT_LUNS scan (SCSI-3 devs) */
#define BLIST_NOT_LOCKABLE 0x80000 /* don't use PREVENT-ALLOW commands */
#define BLIST_NO_ULD_ATTACH 0x100000 /* device is actually for RAID config */
#define BLIST_SELECT_NO_ATN 0x200000 /* select without ATN */
#define BLIST_RETRY_HWERROR 0x400000 /* retry HARDWARE_ERROR */
#define BLIST_MAX_512 0x800000 /* maximum 512 sector cdb length */
#define BLIST_ATTACH_PQ3 0x1000000 /* Scan: Attach to PQ3 devices */
#endif

View File

@@ -0,0 +1,85 @@
/*
* Header file for SCSI device handler infrastruture.
*
* Modified version of patches posted by Mike Christie <michaelc@cs.wisc.edu>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that 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.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Copyright IBM Corporation, 2007
* Authors:
* Chandra Seetharaman <sekharan@us.ibm.com>
* Mike Anderson <andmike@linux.vnet.ibm.com>
*/
#include <scsi/scsi_device.h>
enum {
SCSI_DH_OK = 0,
/*
* device errors
*/
SCSI_DH_DEV_FAILED, /* generic device error */
SCSI_DH_DEV_TEMP_BUSY,
SCSI_DH_DEV_UNSUPP, /* device handler not supported */
SCSI_DH_DEVICE_MAX, /* max device blkerr definition */
/*
* transport errors
*/
SCSI_DH_NOTCONN = SCSI_DH_DEVICE_MAX + 1,
SCSI_DH_CONN_FAILURE,
SCSI_DH_TRANSPORT_MAX, /* max transport blkerr definition */
/*
* driver and generic errors
*/
SCSI_DH_IO = SCSI_DH_TRANSPORT_MAX + 1, /* generic error */
SCSI_DH_INVALID_IO,
SCSI_DH_RETRY, /* retry the req, but not immediately */
SCSI_DH_IMM_RETRY, /* immediately retry the req */
SCSI_DH_TIMED_OUT,
SCSI_DH_RES_TEMP_UNAVAIL,
SCSI_DH_DEV_OFFLINED,
SCSI_DH_NOSYS,
SCSI_DH_DRIVER_MAX,
};
#if defined(CONFIG_SCSI_DH) || defined(CONFIG_SCSI_DH_MODULE)
extern int scsi_dh_activate(struct request_queue *);
extern int scsi_dh_handler_exist(const char *);
extern int scsi_dh_attach(struct request_queue *, const char *);
extern void scsi_dh_detach(struct request_queue *);
extern int scsi_dh_set_params(struct request_queue *, const char *);
#else
static inline int scsi_dh_activate(struct request_queue *req)
{
return 0;
}
static inline int scsi_dh_handler_exist(const char *name)
{
return 0;
}
static inline int scsi_dh_attach(struct request_queue *req, const char *name)
{
return SCSI_DH_NOSYS;
}
static inline void scsi_dh_detach(struct request_queue *q)
{
return;
}
static inline int scsi_dh_set_params(struct request_queue *req, const char *params)
{
return -SCSI_DH_NOSYS;
}
#endif

View File

@@ -0,0 +1,37 @@
#ifndef _SCSI_SCSI_DRIVER_H
#define _SCSI_SCSI_DRIVER_H
#include <linux/device.h>
struct module;
struct scsi_cmnd;
struct scsi_device;
struct request;
struct request_queue;
struct scsi_driver {
struct module *owner;
struct device_driver gendrv;
void (*rescan)(struct device *);
int (*done)(struct scsi_cmnd *);
};
#define to_scsi_driver(drv) \
container_of((drv), struct scsi_driver, gendrv)
extern int scsi_register_driver(struct device_driver *);
#define scsi_unregister_driver(drv) \
driver_unregister(drv);
extern int scsi_register_interface(struct class_interface *);
#define scsi_unregister_interface(intf) \
class_interface_unregister(intf)
int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req);
int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req);
int scsi_prep_state_check(struct scsi_device *sdev, struct request *req);
int scsi_prep_return(struct request_queue *q, struct request *req, int ret);
int scsi_prep_fn(struct request_queue *, struct request *);
#endif /* _SCSI_SCSI_DRIVER_H */

View File

@@ -0,0 +1,95 @@
#ifndef _SCSI_SCSI_EH_H
#define _SCSI_SCSI_EH_H
#include <linux/scatterlist.h>
#include <scsi/scsi_cmnd.h>
struct scsi_device;
struct Scsi_Host;
/*
* This is a slightly modified SCSI sense "descriptor" format header.
* The addition is to allow the 0x70 and 0x71 response codes. The idea
* is to place the salient data from either "fixed" or "descriptor" sense
* format into one structure to ease application processing.
*
* The original sense buffer should be kept around for those cases
* in which more information is required (e.g. the LBA of a MEDIUM ERROR).
*/
struct scsi_sense_hdr { /* See SPC-3 section 4.5 */
u8 response_code; /* permit: 0x0, 0x70, 0x71, 0x72, 0x73 */
u8 sense_key;
u8 asc;
u8 ascq;
u8 byte4;
u8 byte5;
u8 byte6;
u8 additional_length; /* always 0 for fixed sense format */
};
static inline int scsi_sense_valid(struct scsi_sense_hdr *sshdr)
{
if (!sshdr)
return 0;
return (sshdr->response_code & 0x70) == 0x70;
}
extern void scsi_eh_finish_cmd(struct scsi_cmnd *scmd,
struct list_head *done_q);
extern void scsi_eh_flush_done_q(struct list_head *done_q);
extern void scsi_report_bus_reset(struct Scsi_Host *, int);
extern void scsi_report_device_reset(struct Scsi_Host *, int, int);
extern int scsi_block_when_processing_errors(struct scsi_device *);
extern int scsi_normalize_sense(const u8 *sense_buffer, int sb_len,
struct scsi_sense_hdr *sshdr);
extern int scsi_command_normalize_sense(struct scsi_cmnd *cmd,
struct scsi_sense_hdr *sshdr);
static inline int scsi_sense_is_deferred(struct scsi_sense_hdr *sshdr)
{
return ((sshdr->response_code >= 0x70) && (sshdr->response_code & 1));
}
extern const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len,
int desc_type);
extern int scsi_get_sense_info_fld(const u8 * sense_buffer, int sb_len,
u64 * info_out);
extern void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq);
/*
* Reset request from external source
*/
#define SCSI_TRY_RESET_DEVICE 1
#define SCSI_TRY_RESET_BUS 2
#define SCSI_TRY_RESET_HOST 3
#define SCSI_TRY_RESET_TARGET 4
extern int scsi_reset_provider(struct scsi_device *, int);
struct scsi_eh_save {
/* saved state */
int result;
enum dma_data_direction data_direction;
unsigned underflow;
unsigned char cmd_len;
unsigned char prot_op;
unsigned char *cmnd;
struct scsi_data_buffer sdb;
struct request *next_rq;
/* new command support */
unsigned char eh_cmnd[BLK_MAX_CDB];
struct scatterlist sense_sgl;
};
extern void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd,
struct scsi_eh_save *ses, unsigned char *cmnd,
int cmnd_size, unsigned sense_bytes);
extern void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd,
struct scsi_eh_save *ses);
#endif /* _SCSI_SCSI_EH_H */

View File

@@ -0,0 +1,864 @@
#ifndef _SCSI_SCSI_HOST_H
#define _SCSI_SCSI_HOST_H
#include <linux/device.h>
#include <linux/list.h>
#include <linux/types.h>
#include <linux/workqueue.h>
#include <linux/mutex.h>
#include <scsi/scsi.h>
struct request_queue;
struct block_device;
struct completion;
struct module;
struct scsi_cmnd;
struct scsi_device;
struct scsi_target;
struct Scsi_Host;
struct scsi_host_cmd_pool;
struct scsi_transport_template;
struct blk_queue_tags;
/*
* The various choices mean:
* NONE: Self evident. Host adapter is not capable of scatter-gather.
* ALL: Means that the host adapter module can do scatter-gather,
* and that there is no limit to the size of the table to which
* we scatter/gather data. The value we set here is the maximum
* single element sglist. To use chained sglists, the adapter
* has to set a value beyond ALL (and correctly use the chain
* handling API.
* Anything else: Indicates the maximum number of chains that can be
* used in one scatter-gather request.
*/
#define SG_NONE 0
#define SG_ALL SCSI_MAX_SG_SEGMENTS
#define MODE_UNKNOWN 0x00
#define MODE_INITIATOR 0x01
#define MODE_TARGET 0x02
#define DISABLE_CLUSTERING 0
#define ENABLE_CLUSTERING 1
struct scsi_host_template {
struct module *module;
const char *name;
/*
* Used to initialize old-style drivers. For new-style drivers
* just perform all work in your module initialization function.
*
* Status: OBSOLETE
*/
int (* detect)(struct scsi_host_template *);
/*
* Used as unload callback for hosts with old-style drivers.
*
* Status: OBSOLETE
*/
int (* release)(struct Scsi_Host *);
/*
* The info function will return whatever useful information the
* developer sees fit. If not provided, then the name field will
* be used instead.
*
* Status: OPTIONAL
*/
const char *(* info)(struct Scsi_Host *);
/*
* Ioctl interface
*
* Status: OPTIONAL
*/
int (* ioctl)(struct scsi_device *dev, int cmd, void __user *arg);
#ifdef CONFIG_COMPAT
/*
* Compat handler. Handle 32bit ABI.
* When unknown ioctl is passed return -ENOIOCTLCMD.
*
* Status: OPTIONAL
*/
int (* compat_ioctl)(struct scsi_device *dev, int cmd, void __user *arg);
#endif
/*
* The queuecommand function is used to queue up a scsi
* command block to the LLDD. When the driver finished
* processing the command the done callback is invoked.
*
* If queuecommand returns 0, then the HBA has accepted the
* command. The done() function must be called on the command
* when the driver has finished with it. (you may call done on the
* command before queuecommand returns, but in this case you
* *must* return 0 from queuecommand).
*
* Queuecommand may also reject the command, in which case it may
* not touch the command and must not call done() for it.
*
* There are two possible rejection returns:
*
* SCSI_MLQUEUE_DEVICE_BUSY: Block this device temporarily, but
* allow commands to other devices serviced by this host.
*
* SCSI_MLQUEUE_HOST_BUSY: Block all devices served by this
* host temporarily.
*
* For compatibility, any other non-zero return is treated the
* same as SCSI_MLQUEUE_HOST_BUSY.
*
* NOTE: "temporarily" means either until the next command for#
* this device/host completes, or a period of time determined by
* I/O pressure in the system if there are no other outstanding
* commands.
*
* STATUS: REQUIRED
*/
int (* queuecommand)(struct scsi_cmnd *,
void (*done)(struct scsi_cmnd *));
/*
* The transfer functions are used to queue a scsi command to
* the LLD. When the driver is finished processing the command
* the done callback is invoked.
*
* This is called to inform the LLD to transfer
* scsi_bufflen(cmd) bytes. scsi_sg_count(cmd) speciefies the
* number of scatterlist entried in the command and
* scsi_sglist(cmd) returns the scatterlist.
*
* return values: see queuecommand
*
* If the LLD accepts the cmd, it should set the result to an
* appropriate value when completed before calling the done function.
*
* STATUS: REQUIRED FOR TARGET DRIVERS
*/
/* TODO: rename */
int (* transfer_response)(struct scsi_cmnd *,
void (*done)(struct scsi_cmnd *));
/*
* This is an error handling strategy routine. You don't need to
* define one of these if you don't want to - there is a default
* routine that is present that should work in most cases. For those
* driver authors that have the inclination and ability to write their
* own strategy routine, this is where it is specified. Note - the
* strategy routine is *ALWAYS* run in the context of the kernel eh
* thread. Thus you are guaranteed to *NOT* be in an interrupt
* handler when you execute this, and you are also guaranteed to
* *NOT* have any other commands being queued while you are in the
* strategy routine. When you return from this function, operations
* return to normal.
*
* See scsi_error.c scsi_unjam_host for additional comments about
* what this function should and should not be attempting to do.
*
* Status: REQUIRED (at least one of them)
*/
int (* eh_abort_handler)(struct scsi_cmnd *);
int (* eh_device_reset_handler)(struct scsi_cmnd *);
int (* eh_target_reset_handler)(struct scsi_cmnd *);
int (* eh_bus_reset_handler)(struct scsi_cmnd *);
int (* eh_host_reset_handler)(struct scsi_cmnd *);
/*
* Before the mid layer attempts to scan for a new device where none
* currently exists, it will call this entry in your driver. Should
* your driver need to allocate any structs or perform any other init
* items in order to send commands to a currently unused target/lun
* combo, then this is where you can perform those allocations. This
* is specifically so that drivers won't have to perform any kind of
* "is this a new device" checks in their queuecommand routine,
* thereby making the hot path a bit quicker.
*
* Return values: 0 on success, non-0 on failure
*
* Deallocation: If we didn't find any devices at this ID, you will
* get an immediate call to slave_destroy(). If we find something
* here then you will get a call to slave_configure(), then the
* device will be used for however long it is kept around, then when
* the device is removed from the system (or * possibly at reboot
* time), you will then get a call to slave_destroy(). This is
* assuming you implement slave_configure and slave_destroy.
* However, if you allocate memory and hang it off the device struct,
* then you must implement the slave_destroy() routine at a minimum
* in order to avoid leaking memory
* each time a device is tore down.
*
* Status: OPTIONAL
*/
int (* slave_alloc)(struct scsi_device *);
/*
* Once the device has responded to an INQUIRY and we know the
* device is online, we call into the low level driver with the
* struct scsi_device *. If the low level device driver implements
* this function, it *must* perform the task of setting the queue
* depth on the device. All other tasks are optional and depend
* on what the driver supports and various implementation details.
*
* Things currently recommended to be handled at this time include:
*
* 1. Setting the device queue depth. Proper setting of this is
* described in the comments for scsi_adjust_queue_depth.
* 2. Determining if the device supports the various synchronous
* negotiation protocols. The device struct will already have
* responded to INQUIRY and the results of the standard items
* will have been shoved into the various device flag bits, eg.
* device->sdtr will be true if the device supports SDTR messages.
* 3. Allocating command structs that the device will need.
* 4. Setting the default timeout on this device (if needed).
* 5. Anything else the low level driver might want to do on a device
* specific setup basis...
* 6. Return 0 on success, non-0 on error. The device will be marked
* as offline on error so that no access will occur. If you return
* non-0, your slave_destroy routine will never get called for this
* device, so don't leave any loose memory hanging around, clean
* up after yourself before returning non-0
*
* Status: OPTIONAL
*/
int (* slave_configure)(struct scsi_device *);
/*
* Immediately prior to deallocating the device and after all activity
* has ceased the mid layer calls this point so that the low level
* driver may completely detach itself from the scsi device and vice
* versa. The low level driver is responsible for freeing any memory
* it allocated in the slave_alloc or slave_configure calls.
*
* Status: OPTIONAL
*/
void (* slave_destroy)(struct scsi_device *);
/*
* Before the mid layer attempts to scan for a new device attached
* to a target where no target currently exists, it will call this
* entry in your driver. Should your driver need to allocate any
* structs or perform any other init items in order to send commands
* to a currently unused target, then this is where you can perform
* those allocations.
*
* Return values: 0 on success, non-0 on failure
*
* Status: OPTIONAL
*/
int (* target_alloc)(struct scsi_target *);
/*
* Immediately prior to deallocating the target structure, and
* after all activity to attached scsi devices has ceased, the
* midlayer calls this point so that the driver may deallocate
* and terminate any references to the target.
*
* Status: OPTIONAL
*/
void (* target_destroy)(struct scsi_target *);
/*
* If a host has the ability to discover targets on its own instead
* of scanning the entire bus, it can fill in this function and
* call scsi_scan_host(). This function will be called periodically
* until it returns 1 with the scsi_host and the elapsed time of
* the scan in jiffies.
*
* Status: OPTIONAL
*/
int (* scan_finished)(struct Scsi_Host *, unsigned long);
/*
* If the host wants to be called before the scan starts, but
* after the midlayer has set up ready for the scan, it can fill
* in this function.
*
* Status: OPTIONAL
*/
void (* scan_start)(struct Scsi_Host *);
/*
* Fill in this function to allow the queue depth of this host
* to be changeable (on a per device basis). Returns either
* the current queue depth setting (may be different from what
* was passed in) or an error. An error should only be
* returned if the requested depth is legal but the driver was
* unable to set it. If the requested depth is illegal, the
* driver should set and return the closest legal queue depth.
*
* Status: OPTIONAL
*/
int (* change_queue_depth)(struct scsi_device *, int);
/*
* Fill in this function to allow the changing of tag types
* (this also allows the enabling/disabling of tag command
* queueing). An error should only be returned if something
* went wrong in the driver while trying to set the tag type.
* If the driver doesn't support the requested tag type, then
* it should set the closest type it does support without
* returning an error. Returns the actual tag type set.
*
* Status: OPTIONAL
*/
int (* change_queue_type)(struct scsi_device *, int);
/*
* This function determines the BIOS parameters for a given
* harddisk. These tend to be numbers that are made up by
* the host adapter. Parameters:
* size, device, list (heads, sectors, cylinders)
*
* Status: OPTIONAL
*/
int (* bios_param)(struct scsi_device *, struct block_device *,
sector_t, int []);
/*
* Can be used to export driver statistics and other infos to the
* world outside the kernel ie. userspace and it also provides an
* interface to feed the driver with information.
*
* Status: OBSOLETE
*/
int (*proc_info)(struct Scsi_Host *, char *, char **, off_t, int, int);
/*
* This is an optional routine that allows the transport to become
* involved when a scsi io timer fires. The return value tells the
* timer routine how to finish the io timeout handling:
* EH_HANDLED: I fixed the error, please complete the command
* EH_RESET_TIMER: I need more time, reset the timer and
* begin counting again
* EH_NOT_HANDLED Begin normal error recovery
*
* Status: OPTIONAL
*/
enum blk_eh_timer_return (*eh_timed_out)(struct scsi_cmnd *);
/*
* Name of proc directory
*/
const char *proc_name;
/*
* Used to store the procfs directory if a driver implements the
* proc_info method.
*/
struct proc_dir_entry *proc_dir;
/*
* This determines if we will use a non-interrupt driven
* or an interrupt driven scheme. It is set to the maximum number
* of simultaneous commands a given host adapter will accept.
*/
int can_queue;
/*
* In many instances, especially where disconnect / reconnect are
* supported, our host also has an ID on the SCSI bus. If this is
* the case, then it must be reserved. Please set this_id to -1 if
* your setup is in single initiator mode, and the host lacks an
* ID.
*/
int this_id;
/*
* This determines the degree to which the host adapter is capable
* of scatter-gather.
*/
unsigned short sg_tablesize;
/*
* Set this if the host adapter has limitations beside segment count.
*/
unsigned short max_sectors;
/*
* DMA scatter gather segment boundary limit. A segment crossing this
* boundary will be split in two.
*/
unsigned long dma_boundary;
/*
* This specifies "machine infinity" for host templates which don't
* limit the transfer size. Note this limit represents an absolute
* maximum, and may be over the transfer limits allowed for
* individual devices (e.g. 256 for SCSI-1).
*/
#define SCSI_DEFAULT_MAX_SECTORS 1024
/*
* True if this host adapter can make good use of linked commands.
* This will allow more than one command to be queued to a given
* unit on a given host. Set this to the maximum number of command
* blocks to be provided for each device. Set this to 1 for one
* command block per lun, 2 for two, etc. Do not set this to 0.
* You should make sure that the host adapter will do the right thing
* before you try setting this above 1.
*/
short cmd_per_lun;
/*
* present contains counter indicating how many boards of this
* type were found when we did the scan.
*/
unsigned char present;
/*
* This specifies the mode that a LLD supports.
*/
unsigned supported_mode:2;
/*
* True if this host adapter uses unchecked DMA onto an ISA bus.
*/
unsigned unchecked_isa_dma:1;
/*
* True if this host adapter can make good use of clustering.
* I originally thought that if the tablesize was large that it
* was a waste of CPU cycles to prepare a cluster list, but
* it works out that the Buslogic is faster if you use a smaller
* number of segments (i.e. use clustering). I guess it is
* inefficient.
*/
unsigned use_clustering:1;
/*
* True for emulated SCSI host adapters (e.g. ATAPI).
*/
unsigned emulated:1;
/*
* True if the low-level driver performs its own reset-settle delays.
*/
unsigned skip_settle_delay:1;
/*
* True if we are using ordered write support.
*/
unsigned ordered_tag:1;
/*
* Countdown for host blocking with no commands outstanding.
*/
unsigned int max_host_blocked;
/*
* Default value for the blocking. If the queue is empty,
* host_blocked counts down in the request_fn until it restarts
* host operations as zero is reached.
*
* FIXME: This should probably be a value in the template
*/
#define SCSI_DEFAULT_HOST_BLOCKED 7
/*
* Pointer to the sysfs class properties for this host, NULL terminated.
*/
struct device_attribute **shost_attrs;
/*
* Pointer to the SCSI device properties for this host, NULL terminated.
*/
struct device_attribute **sdev_attrs;
/*
* List of hosts per template.
*
* This is only for use by scsi_module.c for legacy templates.
* For these access to it is synchronized implicitly by
* module_init/module_exit.
*/
struct list_head legacy_hosts;
/*
* Vendor Identifier associated with the host
*
* Note: When specifying vendor_id, be sure to read the
* Vendor Type and ID formatting requirements specified in
* scsi_netlink.h
*/
u64 vendor_id;
};
/*
* shost state: If you alter this, you also need to alter scsi_sysfs.c
* (for the ascii descriptions) and the state model enforcer:
* scsi_host_set_state()
*/
enum scsi_host_state {
SHOST_CREATED = 1,
SHOST_RUNNING,
SHOST_CANCEL,
SHOST_DEL,
SHOST_RECOVERY,
SHOST_CANCEL_RECOVERY,
SHOST_DEL_RECOVERY,
};
struct Scsi_Host {
/*
* __devices is protected by the host_lock, but you should
* usually use scsi_device_lookup / shost_for_each_device
* to access it and don't care about locking yourself.
* In the rare case of beeing in irq context you can use
* their __ prefixed variants with the lock held. NEVER
* access this list directly from a driver.
*/
struct list_head __devices;
struct list_head __targets;
struct scsi_host_cmd_pool *cmd_pool;
spinlock_t free_list_lock;
struct list_head free_list; /* backup store of cmd structs */
struct list_head starved_list;
spinlock_t default_lock;
spinlock_t *host_lock;
struct mutex scan_mutex;/* serialize scanning activity */
struct list_head eh_cmd_q;
struct task_struct * ehandler; /* Error recovery thread. */
struct completion * eh_action; /* Wait for specific actions on the
host. */
wait_queue_head_t host_wait;
struct scsi_host_template *hostt;
struct scsi_transport_template *transportt;
/*
* Area to keep a shared tag map (if needed, will be
* NULL if not).
*/
struct blk_queue_tag *bqt;
/*
* The following two fields are protected with host_lock;
* however, eh routines can safely access during eh processing
* without acquiring the lock.
*/
unsigned int host_busy; /* commands actually active on low-level */
unsigned int host_failed; /* commands that failed. */
unsigned int host_eh_scheduled; /* EH scheduled without command */
unsigned int host_no; /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */
int resetting; /* if set, it means that last_reset is a valid value */
unsigned long last_reset;
/*
* These three parameters can be used to allow for wide scsi,
* and for host adapters that support multiple busses
* The first two should be set to 1 more than the actual max id
* or lun (i.e. 8 for normal systems).
*/
unsigned int max_id;
unsigned int max_lun;
unsigned int max_channel;
/*
* This is a unique identifier that must be assigned so that we
* have some way of identifying each detected host adapter properly
* and uniquely. For hosts that do not support more than one card
* in the system at one time, this does not need to be set. It is
* initialized to 0 in scsi_register.
*/
unsigned int unique_id;
/*
* The maximum length of SCSI commands that this host can accept.
* Probably 12 for most host adapters, but could be 16 for others.
* or 260 if the driver supports variable length cdbs.
* For drivers that don't set this field, a value of 12 is
* assumed.
*/
unsigned short max_cmd_len;
int this_id;
int can_queue;
short cmd_per_lun;
short unsigned int sg_tablesize;
short unsigned int max_sectors;
unsigned long dma_boundary;
/*
* Used to assign serial numbers to the cmds.
* Protected by the host lock.
*/
unsigned long cmd_serial_number;
unsigned active_mode:2;
unsigned unchecked_isa_dma:1;
unsigned use_clustering:1;
unsigned use_blk_tcq:1;
/*
* Host has requested that no further requests come through for the
* time being.
*/
unsigned host_self_blocked:1;
/*
* Host uses correct SCSI ordering not PC ordering. The bit is
* set for the minority of drivers whose authors actually read
* the spec ;).
*/
unsigned reverse_ordering:1;
/*
* Ordered write support
*/
unsigned ordered_tag:1;
/* Task mgmt function in progress */
unsigned tmf_in_progress:1;
/* Asynchronous scan in progress */
unsigned async_scan:1;
/*
* Optional work queue to be utilized by the transport
*/
char work_q_name[20];
struct workqueue_struct *work_q;
/*
* Host has rejected a command because it was busy.
*/
unsigned int host_blocked;
/*
* Value host_blocked counts down from
*/
unsigned int max_host_blocked;
/* Protection Information */
unsigned int prot_capabilities;
unsigned char prot_guard_type;
/*
* q used for scsi_tgt msgs, async events or any other requests that
* need to be processed in userspace
*/
struct request_queue *uspace_req_q;
/* legacy crap */
unsigned long base;
unsigned long io_port;
unsigned char n_io_port;
unsigned char dma_channel;
unsigned int irq;
enum scsi_host_state shost_state;
/* ldm bits */
struct device shost_gendev, shost_dev;
/*
* List of hosts per template.
*
* This is only for use by scsi_module.c for legacy templates.
* For these access to it is synchronized implicitly by
* module_init/module_exit.
*/
struct list_head sht_legacy_list;
/*
* Points to the transport data (if any) which is allocated
* separately
*/
void *shost_data;
/*
* Points to the physical bus device we'd use to do DMA
* Needed just in case we have virtual hosts.
*/
struct device *dma_dev;
/*
* We should ensure that this is aligned, both for better performance
* and also because some compilers (m68k) don't automatically force
* alignment to a long boundary.
*/
unsigned long hostdata[0] /* Used for storage of host specific stuff */
__attribute__ ((aligned (sizeof(unsigned long))));
};
#define class_to_shost(d) \
container_of(d, struct Scsi_Host, shost_dev)
#define shost_printk(prefix, shost, fmt, a...) \
dev_printk(prefix, &(shost)->shost_gendev, fmt, ##a)
static inline void *shost_priv(struct Scsi_Host *shost)
{
return (void *)shost->hostdata;
}
int scsi_is_host_device(const struct device *);
static inline struct Scsi_Host *dev_to_shost(struct device *dev)
{
while (!scsi_is_host_device(dev)) {
if (!dev->parent)
return NULL;
dev = dev->parent;
}
return container_of(dev, struct Scsi_Host, shost_gendev);
}
static inline int scsi_host_in_recovery(struct Scsi_Host *shost)
{
return shost->shost_state == SHOST_RECOVERY ||
shost->shost_state == SHOST_CANCEL_RECOVERY ||
shost->shost_state == SHOST_DEL_RECOVERY ||
shost->tmf_in_progress;
}
extern int scsi_queue_work(struct Scsi_Host *, struct work_struct *);
extern void scsi_flush_work(struct Scsi_Host *);
extern struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *, int);
extern int __must_check scsi_add_host_with_dma(struct Scsi_Host *,
struct device *,
struct device *);
extern void scsi_scan_host(struct Scsi_Host *);
extern void scsi_rescan_device(struct device *);
extern void scsi_remove_host(struct Scsi_Host *);
extern struct Scsi_Host *scsi_host_get(struct Scsi_Host *);
extern void scsi_host_put(struct Scsi_Host *t);
extern struct Scsi_Host *scsi_host_lookup(unsigned short);
extern const char *scsi_host_state_name(enum scsi_host_state);
extern u64 scsi_calculate_bounce_limit(struct Scsi_Host *);
static inline int __must_check scsi_add_host(struct Scsi_Host *host,
struct device *dev)
{
return scsi_add_host_with_dma(host, dev, dev);
}
static inline struct device *scsi_get_device(struct Scsi_Host *shost)
{
return shost->shost_gendev.parent;
}
/**
* scsi_host_scan_allowed - Is scanning of this host allowed
* @shost: Pointer to Scsi_Host.
**/
static inline int scsi_host_scan_allowed(struct Scsi_Host *shost)
{
return shost->shost_state == SHOST_RUNNING;
}
extern void scsi_unblock_requests(struct Scsi_Host *);
extern void scsi_block_requests(struct Scsi_Host *);
struct class_container;
extern struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost,
void (*) (struct request_queue *));
/*
* These two functions are used to allocate and free a pseudo device
* which will connect to the host adapter itself rather than any
* physical device. You must deallocate when you are done with the
* thing. This physical pseudo-device isn't real and won't be available
* from any high-level drivers.
*/
extern void scsi_free_host_dev(struct scsi_device *);
extern struct scsi_device *scsi_get_host_dev(struct Scsi_Host *);
/*
* DIF defines the exchange of protection information between
* initiator and SBC block device.
*
* DIX defines the exchange of protection information between OS and
* initiator.
*/
enum scsi_host_prot_capabilities {
SHOST_DIF_TYPE1_PROTECTION = 1 << 0, /* T10 DIF Type 1 */
SHOST_DIF_TYPE2_PROTECTION = 1 << 1, /* T10 DIF Type 2 */
SHOST_DIF_TYPE3_PROTECTION = 1 << 2, /* T10 DIF Type 3 */
SHOST_DIX_TYPE0_PROTECTION = 1 << 3, /* DIX between OS and HBA only */
SHOST_DIX_TYPE1_PROTECTION = 1 << 4, /* DIX with DIF Type 1 */
SHOST_DIX_TYPE2_PROTECTION = 1 << 5, /* DIX with DIF Type 2 */
SHOST_DIX_TYPE3_PROTECTION = 1 << 6, /* DIX with DIF Type 3 */
};
/*
* SCSI hosts which support the Data Integrity Extensions must
* indicate their capabilities by setting the prot_capabilities using
* this call.
*/
static inline void scsi_host_set_prot(struct Scsi_Host *shost, unsigned int mask)
{
shost->prot_capabilities = mask;
}
static inline unsigned int scsi_host_get_prot(struct Scsi_Host *shost)
{
return shost->prot_capabilities;
}
static inline unsigned int scsi_host_dif_capable(struct Scsi_Host *shost, unsigned int target_type)
{
static unsigned char cap[] = { 0,
SHOST_DIF_TYPE1_PROTECTION,
SHOST_DIF_TYPE2_PROTECTION,
SHOST_DIF_TYPE3_PROTECTION };
return shost->prot_capabilities & cap[target_type] ? target_type : 0;
}
static inline unsigned int scsi_host_dix_capable(struct Scsi_Host *shost, unsigned int target_type)
{
#if defined(CONFIG_BLK_DEV_INTEGRITY)
static unsigned char cap[] = { SHOST_DIX_TYPE0_PROTECTION,
SHOST_DIX_TYPE1_PROTECTION,
SHOST_DIX_TYPE2_PROTECTION,
SHOST_DIX_TYPE3_PROTECTION };
return shost->prot_capabilities & cap[target_type];
#endif
return 0;
}
/*
* All DIX-capable initiators must support the T10-mandated CRC
* checksum. Controllers can optionally implement the IP checksum
* scheme which has much lower impact on system performance. Note
* that the main rationale for the checksum is to match integrity
* metadata with data. Detecting bit errors are a job for ECC memory
* and buses.
*/
enum scsi_host_guard_type {
SHOST_DIX_GUARD_CRC = 1 << 0,
SHOST_DIX_GUARD_IP = 1 << 1,
};
static inline void scsi_host_set_guard(struct Scsi_Host *shost, unsigned char type)
{
shost->prot_guard_type = type;
}
static inline unsigned char scsi_host_get_guard(struct Scsi_Host *shost)
{
return shost->prot_guard_type;
}
/* legacy interfaces */
extern struct Scsi_Host *scsi_register(struct scsi_host_template *, int);
extern void scsi_unregister(struct Scsi_Host *);
extern int scsi_host_set_state(struct Scsi_Host *, enum scsi_host_state);
#endif /* _SCSI_SCSI_HOST_H */

View File

@@ -0,0 +1,48 @@
#ifndef _SCSI_IOCTL_H
#define _SCSI_IOCTL_H
#define SCSI_IOCTL_SEND_COMMAND 1
#define SCSI_IOCTL_TEST_UNIT_READY 2
#define SCSI_IOCTL_BENCHMARK_COMMAND 3
#define SCSI_IOCTL_SYNC 4 /* Request synchronous parameters */
#define SCSI_IOCTL_START_UNIT 5
#define SCSI_IOCTL_STOP_UNIT 6
/* The door lock/unlock constants are compatible with Sun constants for
the cdrom */
#define SCSI_IOCTL_DOORLOCK 0x5380 /* lock the eject mechanism */
#define SCSI_IOCTL_DOORUNLOCK 0x5381 /* unlock the mechanism */
#define SCSI_REMOVAL_PREVENT 1
#define SCSI_REMOVAL_ALLOW 0
#ifdef __KERNEL__
struct scsi_device;
/*
* Structures used for scsi_ioctl et al.
*/
typedef struct scsi_ioctl_command {
unsigned int inlen;
unsigned int outlen;
unsigned char data[0];
} Scsi_Ioctl_Command;
typedef struct scsi_idlun {
__u32 dev_id;
__u32 host_unique_id;
} Scsi_Idlun;
/* Fibre Channel WWN, port_id struct */
typedef struct scsi_fctargaddress {
__u32 host_port_id;
unsigned char host_wwn[8]; // include NULL term.
} Scsi_FCTargAddress;
extern int scsi_ioctl(struct scsi_device *, int, void __user *);
extern int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd,
void __user *arg, int ndelay);
#endif /* __KERNEL__ */
#endif /* _SCSI_IOCTL_H */

View File

@@ -0,0 +1,147 @@
/*
* SCSI Transport Netlink Interface
* Used for the posting of outbound SCSI transport events
*
* Copyright (C) 2006 James Smart, Emulex Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef SCSI_NETLINK_H
#define SCSI_NETLINK_H
#include <linux/netlink.h>
/*
* This file intended to be included by both kernel and user space
*/
/* Single Netlink Message type to send all SCSI Transport messages */
#define SCSI_TRANSPORT_MSG NLMSG_MIN_TYPE + 1
/* SCSI Transport Broadcast Groups */
/* leaving groups 0 and 1 unassigned */
#define SCSI_NL_GRP_FC_EVENTS (1<<2) /* Group 2 */
#define SCSI_NL_GRP_CNT 3
/* SCSI_TRANSPORT_MSG event message header */
struct scsi_nl_hdr {
uint8_t version;
uint8_t transport;
uint16_t magic;
uint16_t msgtype;
uint16_t msglen;
} __attribute__((aligned(sizeof(uint64_t))));
/* scsi_nl_hdr->version value */
#define SCSI_NL_VERSION 1
/* scsi_nl_hdr->magic value */
#define SCSI_NL_MAGIC 0xA1B2
/* scsi_nl_hdr->transport value */
#define SCSI_NL_TRANSPORT 0
#define SCSI_NL_TRANSPORT_FC 1
#define SCSI_NL_MAX_TRANSPORTS 2
/* Transport-based scsi_nl_hdr->msgtype values are defined in each transport */
/*
* GENERIC SCSI scsi_nl_hdr->msgtype Values
*/
/* kernel -> user */
#define SCSI_NL_SHOST_VENDOR 0x0001
/* user -> kernel */
/* SCSI_NL_SHOST_VENDOR msgtype is kernel->user and user->kernel */
/*
* Message Structures :
*/
/* macro to round up message lengths to 8byte boundary */
#define SCSI_NL_MSGALIGN(len) (((len) + 7) & ~7)
/*
* SCSI HOST Vendor Unique messages :
* SCSI_NL_SHOST_VENDOR
*
* Note: The Vendor Unique message payload will begin directly after
* this structure, with the length of the payload per vmsg_datalen.
*
* Note: When specifying vendor_id, be sure to read the Vendor Type and ID
* formatting requirements specified below
*/
struct scsi_nl_host_vendor_msg {
struct scsi_nl_hdr snlh; /* must be 1st element ! */
uint64_t vendor_id;
uint16_t host_no;
uint16_t vmsg_datalen;
} __attribute__((aligned(sizeof(uint64_t))));
/*
* Vendor ID:
* If transports post vendor-unique events, they must pass a well-known
* 32-bit vendor identifier. This identifier consists of 8 bits indicating
* the "type" of identifier contained, and 24 bits of id data.
*
* Identifiers for each type:
* PCI : ID data is the 16 bit PCI Registered Vendor ID
*/
#define SCSI_NL_VID_TYPE_SHIFT 56
#define SCSI_NL_VID_TYPE_MASK ((u64)0xFF << SCSI_NL_VID_TYPE_SHIFT)
#define SCSI_NL_VID_TYPE_PCI ((u64)0x01 << SCSI_NL_VID_TYPE_SHIFT)
#define SCSI_NL_VID_ID_MASK (~ SCSI_NL_VID_TYPE_MASK)
#define INIT_SCSI_NL_HDR(hdr, t, mtype, mlen) \
{ \
(hdr)->version = SCSI_NL_VERSION; \
(hdr)->transport = t; \
(hdr)->magic = SCSI_NL_MAGIC; \
(hdr)->msgtype = mtype; \
(hdr)->msglen = mlen; \
}
#ifdef __KERNEL__
#include <scsi/scsi_host.h>
/* Exported Kernel Interfaces */
int scsi_nl_add_transport(u8 tport,
int (*msg_handler)(struct sk_buff *),
void (*event_handler)(struct notifier_block *, unsigned long, void *));
void scsi_nl_remove_transport(u8 tport);
int scsi_nl_add_driver(u64 vendor_id, struct scsi_host_template *hostt,
int (*nlmsg_handler)(struct Scsi_Host *shost, void *payload,
u32 len, u32 pid),
void (*nlevt_handler)(struct notifier_block *nb,
unsigned long event, void *notify_ptr));
void scsi_nl_remove_driver(u64 vendor_id);
void scsi_nl_send_transport_msg(u32 pid, struct scsi_nl_hdr *hdr);
int scsi_nl_send_vendor_msg(u32 pid, unsigned short host_no, u64 vendor_id,
char *data_buf, u32 data_len);
#endif /* __KERNEL__ */
#endif /* SCSI_NETLINK_H */

View File

@@ -0,0 +1,71 @@
/*
* FC Transport Netlink Interface
*
* Copyright (C) 2006 James Smart, Emulex Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef SCSI_NETLINK_FC_H
#define SCSI_NETLINK_FC_H
#include <scsi/scsi_netlink.h>
/*
* This file intended to be included by both kernel and user space
*/
/*
* FC Transport Message Types
*/
/* kernel -> user */
#define FC_NL_ASYNC_EVENT 0x0100
/* user -> kernel */
/* none */
/*
* Message Structures :
*/
/* macro to round up message lengths to 8byte boundary */
#define FC_NL_MSGALIGN(len) (((len) + 7) & ~7)
/*
* FC Transport Broadcast Event Message :
* FC_NL_ASYNC_EVENT
*
* Note: if Vendor Unique message, &event_data will be start of
* vendor unique payload, and the length of the payload is
* per event_datalen
*
* Note: When specifying vendor_id, be sure to read the Vendor Type and ID
* formatting requirements specified in scsi_netlink.h
*/
struct fc_nl_event {
struct scsi_nl_hdr snlh; /* must be 1st element ! */
uint64_t seconds;
uint64_t vendor_id;
uint16_t host_no;
uint16_t event_datalen;
uint32_t event_num;
uint32_t event_code;
uint32_t event_data;
} __attribute__((aligned(sizeof(uint64_t))));
#endif /* SCSI_NETLINK_FC_H */

View File

@@ -0,0 +1,11 @@
#ifndef _SCSI_SCSI_SCAN_H
#define _SCSI_SCSI_SCAN_H
#ifdef CONFIG_SCSI
/* drivers/scsi/scsi_scan.c */
extern int scsi_complete_async_scans(void);
#else
static inline int scsi_complete_async_scans(void) { return 0; }
#endif
#endif /* _SCSI_SCSI_SCAN_H */

View File

@@ -0,0 +1,178 @@
#ifndef _SCSI_SCSI_TCQ_H
#define _SCSI_SCSI_TCQ_H
#include <linux/blkdev.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#define MSG_SIMPLE_TAG 0x20
#define MSG_HEAD_TAG 0x21
#define MSG_ORDERED_TAG 0x22
#define SCSI_NO_TAG (-1) /* identify no tag in use */
#ifdef CONFIG_BLOCK
/**
* scsi_get_tag_type - get the type of tag the device supports
* @sdev: the scsi device
*
* Notes:
* If the drive only supports simple tags, returns MSG_SIMPLE_TAG
* if it supports all tag types, returns MSG_ORDERED_TAG.
*/
static inline int scsi_get_tag_type(struct scsi_device *sdev)
{
if (!sdev->tagged_supported)
return 0;
if (sdev->ordered_tags)
return MSG_ORDERED_TAG;
if (sdev->simple_tags)
return MSG_SIMPLE_TAG;
return 0;
}
static inline void scsi_set_tag_type(struct scsi_device *sdev, int tag)
{
switch (tag) {
case MSG_ORDERED_TAG:
sdev->ordered_tags = 1;
/* fall through */
case MSG_SIMPLE_TAG:
sdev->simple_tags = 1;
break;
case 0:
/* fall through */
default:
sdev->ordered_tags = 0;
sdev->simple_tags = 0;
break;
}
}
/**
* scsi_activate_tcq - turn on tag command queueing
* @SDpnt: device to turn on TCQ for
* @depth: queue depth
*
* Notes:
* Eventually, I hope depth would be the maximum depth
* the device could cope with and the real queue depth
* would be adjustable from 0 to depth.
**/
static inline void scsi_activate_tcq(struct scsi_device *sdev, int depth)
{
if (!sdev->tagged_supported)
return;
if (!blk_queue_tagged(sdev->request_queue))
blk_queue_init_tags(sdev->request_queue, depth,
sdev->host->bqt);
scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
}
/**
* scsi_deactivate_tcq - turn off tag command queueing
* @SDpnt: device to turn off TCQ for
**/
static inline void scsi_deactivate_tcq(struct scsi_device *sdev, int depth)
{
if (blk_queue_tagged(sdev->request_queue))
blk_queue_free_tags(sdev->request_queue);
scsi_adjust_queue_depth(sdev, 0, depth);
}
/**
* scsi_populate_tag_msg - place a tag message in a buffer
* @SCpnt: pointer to the Scsi_Cmnd for the tag
* @msg: pointer to the area to place the tag
*
* Notes:
* designed to create the correct type of tag message for the
* particular request. Returns the size of the tag message.
* May return 0 if TCQ is disabled for this device.
**/
static inline int scsi_populate_tag_msg(struct scsi_cmnd *cmd, char *msg)
{
struct request *req = cmd->request;
struct scsi_device *sdev = cmd->device;
if (blk_rq_tagged(req)) {
if (sdev->ordered_tags && req->cmd_flags & REQ_HARDBARRIER)
*msg++ = MSG_ORDERED_TAG;
else
*msg++ = MSG_SIMPLE_TAG;
*msg++ = req->tag;
return 2;
}
return 0;
}
/**
* scsi_find_tag - find a tagged command by device
* @SDpnt: pointer to the ScSI device
* @tag: the tag number
*
* Notes:
* Only works with tags allocated by the generic blk layer.
**/
static inline struct scsi_cmnd *scsi_find_tag(struct scsi_device *sdev, int tag)
{
struct request *req;
if (tag != SCSI_NO_TAG) {
req = blk_queue_find_tag(sdev->request_queue, tag);
return req ? (struct scsi_cmnd *)req->special : NULL;
}
/* single command, look in space */
return sdev->current_cmnd;
}
/**
* scsi_init_shared_tag_map - create a shared tag map
* @shost: the host to share the tag map among all devices
* @depth: the total depth of the map
*/
static inline int scsi_init_shared_tag_map(struct Scsi_Host *shost, int depth)
{
/*
* If the shared tag map isn't already initialized, do it now.
* This saves callers from having to check ->bqt when setting up
* devices on the shared host (for libata)
*/
if (!shost->bqt) {
shost->bqt = blk_init_tags(depth);
if (!shost->bqt)
return -ENOMEM;
}
return 0;
}
/**
* scsi_host_find_tag - find the tagged command by host
* @shost: pointer to scsi_host
* @tag: tag of the scsi_cmnd
*
* Notes:
* Only works with tags allocated by the generic blk layer.
**/
static inline struct scsi_cmnd *scsi_host_find_tag(struct Scsi_Host *shost,
int tag)
{
struct request *req;
if (tag != SCSI_NO_TAG) {
req = blk_map_queue_find_tag(shost->bqt, tag);
return req ? (struct scsi_cmnd *)req->special : NULL;
}
return NULL;
}
#endif /* CONFIG_BLOCK */
#endif /* _SCSI_SCSI_TCQ_H */

View File

@@ -0,0 +1,21 @@
/*
* SCSI target definitions
*/
#include <linux/dma-mapping.h>
struct Scsi_Host;
struct scsi_cmnd;
struct scsi_lun;
extern struct Scsi_Host *scsi_tgt_cmd_to_host(struct scsi_cmnd *);
extern int scsi_tgt_alloc_queue(struct Scsi_Host *);
extern void scsi_tgt_free_queue(struct Scsi_Host *);
extern int scsi_tgt_queue_command(struct scsi_cmnd *, u64, struct scsi_lun *, u64);
extern int scsi_tgt_tsk_mgmt_request(struct Scsi_Host *, u64, int, u64,
struct scsi_lun *, void *);
extern struct scsi_cmnd *scsi_host_get_command(struct Scsi_Host *,
enum dma_data_direction, gfp_t);
extern void scsi_host_put_command(struct Scsi_Host *, struct scsi_cmnd *);
extern int scsi_tgt_it_nexus_create(struct Scsi_Host *, u64, char *);
extern int scsi_tgt_it_nexus_destroy(struct Scsi_Host *, u64);

View File

@@ -0,0 +1,108 @@
/*
* SCSI target kernel/user interface
*
* Copyright (C) 2005 FUJITA Tomonori <tomof@acm.org>
* Copyright (C) 2005 Mike Christie <michaelc@cs.wisc.edu>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that 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
*/
#ifndef __SCSI_TARGET_IF_H
#define __SCSI_TARGET_IF_H
/* user -> kernel */
#define TGT_UEVENT_CMD_RSP 0x0001
#define TGT_UEVENT_IT_NEXUS_RSP 0x0002
#define TGT_UEVENT_TSK_MGMT_RSP 0x0003
/* kernel -> user */
#define TGT_KEVENT_CMD_REQ 0x1001
#define TGT_KEVENT_CMD_DONE 0x1002
#define TGT_KEVENT_IT_NEXUS_REQ 0x1003
#define TGT_KEVENT_TSK_MGMT_REQ 0x1004
struct tgt_event_hdr {
uint16_t version;
uint16_t status;
uint16_t type;
uint16_t len;
} __attribute__ ((aligned (sizeof(uint64_t))));
struct tgt_event {
struct tgt_event_hdr hdr;
union {
/* user-> kernel */
struct {
int host_no;
int result;
aligned_u64 itn_id;
aligned_u64 tag;
aligned_u64 uaddr;
aligned_u64 sense_uaddr;
uint32_t len;
uint32_t sense_len;
uint8_t rw;
} cmd_rsp;
struct {
int host_no;
int result;
aligned_u64 itn_id;
aligned_u64 mid;
} tsk_mgmt_rsp;
struct {
__s32 host_no;
__s32 result;
aligned_u64 itn_id;
__u32 function;
} it_nexus_rsp;
/* kernel -> user */
struct {
int host_no;
uint32_t data_len;
aligned_u64 itn_id;
uint8_t scb[16];
uint8_t lun[8];
int attribute;
aligned_u64 tag;
} cmd_req;
struct {
int host_no;
int result;
aligned_u64 itn_id;
aligned_u64 tag;
} cmd_done;
struct {
int host_no;
int function;
aligned_u64 itn_id;
aligned_u64 tag;
uint8_t lun[8];
aligned_u64 mid;
} tsk_mgmt_req;
struct {
__s32 host_no;
__u32 function;
aligned_u64 itn_id;
__u32 max_cmds;
__u8 initiator_id[16];
} it_nexus_req;
} p;
} __attribute__ ((aligned (sizeof(uint64_t))));
#define TGT_RING_SIZE (1UL << 16)
#endif

View File

@@ -0,0 +1,121 @@
/*
* Transport specific attributes.
*
* Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef SCSI_TRANSPORT_H
#define SCSI_TRANSPORT_H
#include <linux/transport_class.h>
#include <linux/blkdev.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_device.h>
struct scsi_transport_template {
/* the attribute containers */
struct transport_container host_attrs;
struct transport_container target_attrs;
struct transport_container device_attrs;
/*
* If set, called from sysfs and legacy procfs rescanning code.
*/
int (*user_scan)(struct Scsi_Host *, uint, uint, uint);
/* The size of the specific transport attribute structure (a
* space of this size will be left at the end of the
* scsi_* structure */
int device_size;
int device_private_offset;
int target_size;
int target_private_offset;
int host_size;
/* no private offset for the host; there's an alternative mechanism */
/*
* True if the transport wants to use a host-based work-queue
*/
unsigned int create_work_queue : 1;
/*
* Allows a transport to override the default error handler.
*/
void (* eh_strategy_handler)(struct Scsi_Host *);
/*
* This is an optional routine that allows the transport to become
* involved when a scsi io timer fires. The return value tells the
* timer routine how to finish the io timeout handling:
* EH_HANDLED: I fixed the error, please complete the command
* EH_RESET_TIMER: I need more time, reset the timer and
* begin counting again
* EH_NOT_HANDLED Begin normal error recovery
*/
enum blk_eh_timer_return (*eh_timed_out)(struct scsi_cmnd *);
/*
* Used as callback for the completion of i_t_nexus request
* for target drivers.
*/
int (* it_nexus_response)(struct Scsi_Host *, u64, int);
/*
* Used as callback for the completion of task management
* request for target drivers.
*/
int (* tsk_mgmt_response)(struct Scsi_Host *, u64, u64, int);
};
#define transport_class_to_shost(tc) \
dev_to_shost((tc)->parent)
/* Private area maintenance. The driver requested allocations come
* directly after the transport class allocations (if any). The idea
* is that you *must* call these only once. The code assumes that the
* initial values are the ones the transport specific code requires */
static inline void
scsi_transport_reserve_target(struct scsi_transport_template * t, int space)
{
BUG_ON(t->target_private_offset != 0);
t->target_private_offset = ALIGN(t->target_size, sizeof(void *));
t->target_size = t->target_private_offset + space;
}
static inline void
scsi_transport_reserve_device(struct scsi_transport_template * t, int space)
{
BUG_ON(t->device_private_offset != 0);
t->device_private_offset = ALIGN(t->device_size, sizeof(void *));
t->device_size = t->device_private_offset + space;
}
static inline void *
scsi_transport_target_data(struct scsi_target *starget)
{
struct Scsi_Host *shost = dev_to_shost(&starget->dev);
return (u8 *)starget->starget_data
+ shost->transportt->target_private_offset;
}
static inline void *
scsi_transport_device_data(struct scsi_device *sdev)
{
struct Scsi_Host *shost = sdev->host;
return (u8 *)sdev->sdev_data
+ shost->transportt->device_private_offset;
}
#endif /* SCSI_TRANSPORT_H */

View File

@@ -0,0 +1,811 @@
/*
* FiberChannel transport specific attributes exported to sysfs.
*
* Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* ========
*
* Copyright (C) 2004-2007 James Smart, Emulex Corporation
* Rewrite for host, target, device, and remote port attributes,
* statistics, and service functions...
*
*/
#ifndef SCSI_TRANSPORT_FC_H
#define SCSI_TRANSPORT_FC_H
#include <linux/sched.h>
#include <scsi/scsi.h>
#include <scsi/scsi_netlink.h>
struct scsi_transport_template;
/*
* FC Port definitions - Following FC HBAAPI guidelines
*
* Note: Not all binary values for the different fields match HBAAPI.
* Instead, we use densely packed ordinal values or enums.
* We get away with this as we never present the actual binary values
* externally. For sysfs, we always present the string that describes
* the value. Thus, an admin doesn't need a magic HBAAPI decoder ring
* to understand the values. The HBAAPI user-space library is free to
* convert the strings into the HBAAPI-specified binary values.
*
* Note: Not all HBAAPI-defined values are contained in the definitions
* below. Those not appropriate to an fc_host (e.g. FCP initiator) have
* been removed.
*/
/*
* fc_port_type: If you alter this, you also need to alter scsi_transport_fc.c
* (for the ascii descriptions).
*/
enum fc_port_type {
FC_PORTTYPE_UNKNOWN,
FC_PORTTYPE_OTHER,
FC_PORTTYPE_NOTPRESENT,
FC_PORTTYPE_NPORT, /* Attached to FPort */
FC_PORTTYPE_NLPORT, /* (Public) Loop w/ FLPort */
FC_PORTTYPE_LPORT, /* (Private) Loop w/o FLPort */
FC_PORTTYPE_PTP, /* Point to Point w/ another NPort */
FC_PORTTYPE_NPIV, /* VPORT based on NPIV */
};
/*
* fc_port_state: If you alter this, you also need to alter scsi_transport_fc.c
* (for the ascii descriptions).
*/
enum fc_port_state {
FC_PORTSTATE_UNKNOWN,
FC_PORTSTATE_NOTPRESENT,
FC_PORTSTATE_ONLINE,
FC_PORTSTATE_OFFLINE, /* User has taken Port Offline */
FC_PORTSTATE_BLOCKED,
FC_PORTSTATE_BYPASSED,
FC_PORTSTATE_DIAGNOSTICS,
FC_PORTSTATE_LINKDOWN,
FC_PORTSTATE_ERROR,
FC_PORTSTATE_LOOPBACK,
FC_PORTSTATE_DELETED,
};
/*
* fc_vport_state: If you alter this, you also need to alter
* scsi_transport_fc.c (for the ascii descriptions).
*/
enum fc_vport_state {
FC_VPORT_UNKNOWN,
FC_VPORT_ACTIVE,
FC_VPORT_DISABLED,
FC_VPORT_LINKDOWN,
FC_VPORT_INITIALIZING,
FC_VPORT_NO_FABRIC_SUPP,
FC_VPORT_NO_FABRIC_RSCS,
FC_VPORT_FABRIC_LOGOUT,
FC_VPORT_FABRIC_REJ_WWN,
FC_VPORT_FAILED,
};
/*
* FC Classes of Service
* Note: values are not enumerated, as they can be "or'd" together
* for reporting (e.g. report supported_classes). If you alter this list,
* you also need to alter scsi_transport_fc.c (for the ascii descriptions).
*/
#define FC_COS_UNSPECIFIED 0
#define FC_COS_CLASS1 2
#define FC_COS_CLASS2 4
#define FC_COS_CLASS3 8
#define FC_COS_CLASS4 0x10
#define FC_COS_CLASS6 0x40
/*
* FC Port Speeds
* Note: values are not enumerated, as they can be "or'd" together
* for reporting (e.g. report supported_speeds). If you alter this list,
* you also need to alter scsi_transport_fc.c (for the ascii descriptions).
*/
#define FC_PORTSPEED_UNKNOWN 0 /* Unknown - transceiver
incapable of reporting */
#define FC_PORTSPEED_1GBIT 1
#define FC_PORTSPEED_2GBIT 2
#define FC_PORTSPEED_4GBIT 4
#define FC_PORTSPEED_10GBIT 8
#define FC_PORTSPEED_8GBIT 0x10
#define FC_PORTSPEED_16GBIT 0x20
#define FC_PORTSPEED_NOT_NEGOTIATED (1 << 15) /* Speed not established */
/*
* fc_tgtid_binding_type: If you alter this, you also need to alter
* scsi_transport_fc.c (for the ascii descriptions).
*/
enum fc_tgtid_binding_type {
FC_TGTID_BIND_NONE,
FC_TGTID_BIND_BY_WWPN,
FC_TGTID_BIND_BY_WWNN,
FC_TGTID_BIND_BY_ID,
};
/*
* FC Port Roles
* Note: values are not enumerated, as they can be "or'd" together
* for reporting (e.g. report roles). If you alter this list,
* you also need to alter scsi_transport_fc.c (for the ascii descriptions).
*/
#define FC_PORT_ROLE_UNKNOWN 0x00
#define FC_PORT_ROLE_FCP_TARGET 0x01
#define FC_PORT_ROLE_FCP_INITIATOR 0x02
#define FC_PORT_ROLE_IP_PORT 0x04
/* The following are for compatibility */
#define FC_RPORT_ROLE_UNKNOWN FC_PORT_ROLE_UNKNOWN
#define FC_RPORT_ROLE_FCP_TARGET FC_PORT_ROLE_FCP_TARGET
#define FC_RPORT_ROLE_FCP_INITIATOR FC_PORT_ROLE_FCP_INITIATOR
#define FC_RPORT_ROLE_IP_PORT FC_PORT_ROLE_IP_PORT
/* Macro for use in defining Virtual Port attributes */
#define FC_VPORT_ATTR(_name,_mode,_show,_store) \
struct device_attribute dev_attr_vport_##_name = \
__ATTR(_name,_mode,_show,_store)
/*
* fc_vport_identifiers: This set of data contains all elements
* to uniquely identify and instantiate a FC virtual port.
*
* Notes:
* symbolic_name: The driver is to append the symbolic_name string data
* to the symbolic_node_name data that it generates by default.
* the resulting combination should then be registered with the switch.
* It is expected that things like Xen may stuff a VM title into
* this field.
*/
#define FC_VPORT_SYMBOLIC_NAMELEN 64
struct fc_vport_identifiers {
u64 node_name;
u64 port_name;
u32 roles;
bool disable;
enum fc_port_type vport_type; /* only FC_PORTTYPE_NPIV allowed */
char symbolic_name[FC_VPORT_SYMBOLIC_NAMELEN];
};
/*
* FC Virtual Port Attributes
*
* This structure exists for each FC port is a virtual FC port. Virtual
* ports share the physical link with the Physical port. Each virtual
* ports has a unique presense on the SAN, and may be instantiated via
* NPIV, Virtual Fabrics, or via additional ALPAs. As the vport is a
* unique presense, each vport has it's own view of the fabric,
* authentication privilege, and priorities.
*
* A virtual port may support 1 or more FC4 roles. Typically it is a
* FCP Initiator. It could be a FCP Target, or exist sole for an IP over FC
* roles. FC port attributes for the vport will be reported on any
* fc_host class object allocated for an FCP Initiator.
*
* --
*
* Fixed attributes are not expected to change. The driver is
* expected to set these values after receiving the fc_vport structure
* via the vport_create() call from the transport.
* The transport fully manages all get functions w/o driver interaction.
*
* Dynamic attributes are expected to change. The driver participates
* in all get/set operations via functions provided by the driver.
*
* Private attributes are transport-managed values. They are fully
* managed by the transport w/o driver interaction.
*/
struct fc_vport {
/* Fixed Attributes */
/* Dynamic Attributes */
/* Private (Transport-managed) Attributes */
enum fc_vport_state vport_state;
enum fc_vport_state vport_last_state;
u64 node_name;
u64 port_name;
u32 roles;
u32 vport_id; /* Admin Identifier for the vport */
enum fc_port_type vport_type;
char symbolic_name[FC_VPORT_SYMBOLIC_NAMELEN];
/* exported data */
void *dd_data; /* Used for driver-specific storage */
/* internal data */
struct Scsi_Host *shost; /* Physical Port Parent */
unsigned int channel;
u32 number;
u8 flags;
struct list_head peers;
struct device dev;
struct work_struct vport_delete_work;
} __attribute__((aligned(sizeof(unsigned long))));
/* bit field values for struct fc_vport "flags" field: */
#define FC_VPORT_CREATING 0x01
#define FC_VPORT_DELETING 0x02
#define FC_VPORT_DELETED 0x04
#define FC_VPORT_DEL 0x06 /* Any DELETE state */
#define dev_to_vport(d) \
container_of(d, struct fc_vport, dev)
#define transport_class_to_vport(dev) \
dev_to_vport(dev->parent)
#define vport_to_shost(v) \
(v->shost)
#define vport_to_shost_channel(v) \
(v->channel)
#define vport_to_parent(v) \
(v->dev.parent)
/* Error return codes for vport_create() callback */
#define VPCERR_UNSUPPORTED -ENOSYS /* no driver/adapter
support */
#define VPCERR_BAD_WWN -ENOTUNIQ /* driver validation
of WWNs failed */
#define VPCERR_NO_FABRIC_SUPP -EOPNOTSUPP /* Fabric connection
is loop or the
Fabric Port does
not support NPIV */
/*
* fc_rport_identifiers: This set of data contains all elements
* to uniquely identify a remote FC port. The driver uses this data
* to report the existence of a remote FC port in the topology. Internally,
* the transport uses this data for attributes and to manage consistent
* target id bindings.
*/
struct fc_rport_identifiers {
u64 node_name;
u64 port_name;
u32 port_id;
u32 roles;
};
/* Macro for use in defining Remote Port attributes */
#define FC_RPORT_ATTR(_name,_mode,_show,_store) \
struct device_attribute dev_attr_rport_##_name = \
__ATTR(_name,_mode,_show,_store)
/*
* FC Remote Port Attributes
*
* This structure exists for each remote FC port that a LLDD notifies
* the subsystem of. A remote FC port may or may not be a SCSI Target,
* also be a SCSI initiator, IP endpoint, etc. As such, the remote
* port is considered a separate entity, independent of "role" (such
* as scsi target).
*
* --
*
* Attributes are based on HBAAPI V2.0 definitions. Only those
* attributes that are determinable by the local port (aka Host)
* are contained.
*
* Fixed attributes are not expected to change. The driver is
* expected to set these values after successfully calling
* fc_remote_port_add(). The transport fully manages all get functions
* w/o driver interaction.
*
* Dynamic attributes are expected to change. The driver participates
* in all get/set operations via functions provided by the driver.
*
* Private attributes are transport-managed values. They are fully
* managed by the transport w/o driver interaction.
*/
struct fc_rport { /* aka fc_starget_attrs */
/* Fixed Attributes */
u32 maxframe_size;
u32 supported_classes;
/* Dynamic Attributes */
u32 dev_loss_tmo; /* Remote Port loss timeout in seconds. */
/* Private (Transport-managed) Attributes */
u64 node_name;
u64 port_name;
u32 port_id;
u32 roles;
enum fc_port_state port_state; /* Will only be ONLINE or UNKNOWN */
u32 scsi_target_id;
u32 fast_io_fail_tmo;
/* exported data */
void *dd_data; /* Used for driver-specific storage */
/* internal data */
unsigned int channel;
u32 number;
u8 flags;
struct list_head peers;
struct device dev;
struct delayed_work dev_loss_work;
struct work_struct scan_work;
struct delayed_work fail_io_work;
struct work_struct stgt_delete_work;
struct work_struct rport_delete_work;
struct request_queue *rqst_q; /* bsg support */
} __attribute__((aligned(sizeof(unsigned long))));
/* bit field values for struct fc_rport "flags" field: */
#define FC_RPORT_DEVLOSS_PENDING 0x01
#define FC_RPORT_SCAN_PENDING 0x02
#define FC_RPORT_FAST_FAIL_TIMEDOUT 0x04
#define FC_RPORT_DEVLOSS_CALLBK_DONE 0x08
#define dev_to_rport(d) \
container_of(d, struct fc_rport, dev)
#define transport_class_to_rport(dev) \
dev_to_rport(dev->parent)
#define rport_to_shost(r) \
dev_to_shost(r->dev.parent)
/*
* FC SCSI Target Attributes
*
* The SCSI Target is considered an extention of a remote port (as
* a remote port can be more than a SCSI Target). Within the scsi
* subsystem, we leave the Target as a separate entity. Doing so
* provides backward compatibility with prior FC transport api's,
* and lets remote ports be handled entirely within the FC transport
* and independently from the scsi subsystem. The drawback is that
* some data will be duplicated.
*/
struct fc_starget_attrs { /* aka fc_target_attrs */
/* Dynamic Attributes */
u64 node_name;
u64 port_name;
u32 port_id;
};
#define fc_starget_node_name(x) \
(((struct fc_starget_attrs *)&(x)->starget_data)->node_name)
#define fc_starget_port_name(x) \
(((struct fc_starget_attrs *)&(x)->starget_data)->port_name)
#define fc_starget_port_id(x) \
(((struct fc_starget_attrs *)&(x)->starget_data)->port_id)
#define starget_to_rport(s) \
scsi_is_fc_rport(s->dev.parent) ? dev_to_rport(s->dev.parent) : NULL
/*
* FC Local Port (Host) Statistics
*/
/* FC Statistics - Following FC HBAAPI v2.0 guidelines */
struct fc_host_statistics {
/* port statistics */
u64 seconds_since_last_reset;
u64 tx_frames;
u64 tx_words;
u64 rx_frames;
u64 rx_words;
u64 lip_count;
u64 nos_count;
u64 error_frames;
u64 dumped_frames;
u64 link_failure_count;
u64 loss_of_sync_count;
u64 loss_of_signal_count;
u64 prim_seq_protocol_err_count;
u64 invalid_tx_word_count;
u64 invalid_crc_count;
/* fc4 statistics (only FCP supported currently) */
u64 fcp_input_requests;
u64 fcp_output_requests;
u64 fcp_control_requests;
u64 fcp_input_megabytes;
u64 fcp_output_megabytes;
};
/*
* FC Event Codes - Polled and Async, following FC HBAAPI v2.0 guidelines
*/
/*
* fc_host_event_code: If you alter this, you also need to alter
* scsi_transport_fc.c (for the ascii descriptions).
*/
enum fc_host_event_code {
FCH_EVT_LIP = 0x1,
FCH_EVT_LINKUP = 0x2,
FCH_EVT_LINKDOWN = 0x3,
FCH_EVT_LIPRESET = 0x4,
FCH_EVT_RSCN = 0x5,
FCH_EVT_ADAPTER_CHANGE = 0x103,
FCH_EVT_PORT_UNKNOWN = 0x200,
FCH_EVT_PORT_OFFLINE = 0x201,
FCH_EVT_PORT_ONLINE = 0x202,
FCH_EVT_PORT_FABRIC = 0x204,
FCH_EVT_LINK_UNKNOWN = 0x500,
FCH_EVT_VENDOR_UNIQUE = 0xffff,
};
/*
* FC Local Port (Host) Attributes
*
* Attributes are based on HBAAPI V2.0 definitions.
* Note: OSDeviceName is determined by user-space library
*
* Fixed attributes are not expected to change. The driver is
* expected to set these values after successfully calling scsi_add_host().
* The transport fully manages all get functions w/o driver interaction.
*
* Dynamic attributes are expected to change. The driver participates
* in all get/set operations via functions provided by the driver.
*
* Private attributes are transport-managed values. They are fully
* managed by the transport w/o driver interaction.
*/
#define FC_FC4_LIST_SIZE 32
#define FC_SYMBOLIC_NAME_SIZE 256
#define FC_VERSION_STRING_SIZE 64
#define FC_SERIAL_NUMBER_SIZE 80
struct fc_host_attrs {
/* Fixed Attributes */
u64 node_name;
u64 port_name;
u64 permanent_port_name;
u32 supported_classes;
u8 supported_fc4s[FC_FC4_LIST_SIZE];
u32 supported_speeds;
u32 maxframe_size;
u16 max_npiv_vports;
char serial_number[FC_SERIAL_NUMBER_SIZE];
/* Dynamic Attributes */
u32 port_id;
enum fc_port_type port_type;
enum fc_port_state port_state;
u8 active_fc4s[FC_FC4_LIST_SIZE];
u32 speed;
u64 fabric_name;
char symbolic_name[FC_SYMBOLIC_NAME_SIZE];
char system_hostname[FC_SYMBOLIC_NAME_SIZE];
/* Private (Transport-managed) Attributes */
enum fc_tgtid_binding_type tgtid_bind_type;
/* internal data */
struct list_head rports;
struct list_head rport_bindings;
struct list_head vports;
u32 next_rport_number;
u32 next_target_id;
u32 next_vport_number;
u16 npiv_vports_inuse;
/* work queues for rport state manipulation */
char work_q_name[20];
struct workqueue_struct *work_q;
char devloss_work_q_name[20];
struct workqueue_struct *devloss_work_q;
/* bsg support */
struct request_queue *rqst_q;
};
#define shost_to_fc_host(x) \
((struct fc_host_attrs *)(x)->shost_data)
#define fc_host_node_name(x) \
(((struct fc_host_attrs *)(x)->shost_data)->node_name)
#define fc_host_port_name(x) \
(((struct fc_host_attrs *)(x)->shost_data)->port_name)
#define fc_host_permanent_port_name(x) \
(((struct fc_host_attrs *)(x)->shost_data)->permanent_port_name)
#define fc_host_supported_classes(x) \
(((struct fc_host_attrs *)(x)->shost_data)->supported_classes)
#define fc_host_supported_fc4s(x) \
(((struct fc_host_attrs *)(x)->shost_data)->supported_fc4s)
#define fc_host_supported_speeds(x) \
(((struct fc_host_attrs *)(x)->shost_data)->supported_speeds)
#define fc_host_maxframe_size(x) \
(((struct fc_host_attrs *)(x)->shost_data)->maxframe_size)
#define fc_host_max_npiv_vports(x) \
(((struct fc_host_attrs *)(x)->shost_data)->max_npiv_vports)
#define fc_host_serial_number(x) \
(((struct fc_host_attrs *)(x)->shost_data)->serial_number)
#define fc_host_port_id(x) \
(((struct fc_host_attrs *)(x)->shost_data)->port_id)
#define fc_host_port_type(x) \
(((struct fc_host_attrs *)(x)->shost_data)->port_type)
#define fc_host_port_state(x) \
(((struct fc_host_attrs *)(x)->shost_data)->port_state)
#define fc_host_active_fc4s(x) \
(((struct fc_host_attrs *)(x)->shost_data)->active_fc4s)
#define fc_host_speed(x) \
(((struct fc_host_attrs *)(x)->shost_data)->speed)
#define fc_host_fabric_name(x) \
(((struct fc_host_attrs *)(x)->shost_data)->fabric_name)
#define fc_host_symbolic_name(x) \
(((struct fc_host_attrs *)(x)->shost_data)->symbolic_name)
#define fc_host_system_hostname(x) \
(((struct fc_host_attrs *)(x)->shost_data)->system_hostname)
#define fc_host_tgtid_bind_type(x) \
(((struct fc_host_attrs *)(x)->shost_data)->tgtid_bind_type)
#define fc_host_rports(x) \
(((struct fc_host_attrs *)(x)->shost_data)->rports)
#define fc_host_rport_bindings(x) \
(((struct fc_host_attrs *)(x)->shost_data)->rport_bindings)
#define fc_host_vports(x) \
(((struct fc_host_attrs *)(x)->shost_data)->vports)
#define fc_host_next_rport_number(x) \
(((struct fc_host_attrs *)(x)->shost_data)->next_rport_number)
#define fc_host_next_target_id(x) \
(((struct fc_host_attrs *)(x)->shost_data)->next_target_id)
#define fc_host_next_vport_number(x) \
(((struct fc_host_attrs *)(x)->shost_data)->next_vport_number)
#define fc_host_npiv_vports_inuse(x) \
(((struct fc_host_attrs *)(x)->shost_data)->npiv_vports_inuse)
#define fc_host_work_q_name(x) \
(((struct fc_host_attrs *)(x)->shost_data)->work_q_name)
#define fc_host_work_q(x) \
(((struct fc_host_attrs *)(x)->shost_data)->work_q)
#define fc_host_devloss_work_q_name(x) \
(((struct fc_host_attrs *)(x)->shost_data)->devloss_work_q_name)
#define fc_host_devloss_work_q(x) \
(((struct fc_host_attrs *)(x)->shost_data)->devloss_work_q)
struct fc_bsg_buffer {
unsigned int payload_len;
int sg_cnt;
struct scatterlist *sg_list;
};
/* Values for fc_bsg_job->state_flags (bitflags) */
#define FC_RQST_STATE_INPROGRESS 0
#define FC_RQST_STATE_DONE 1
struct fc_bsg_job {
struct Scsi_Host *shost;
struct fc_rport *rport;
struct device *dev;
struct request *req;
spinlock_t job_lock;
unsigned int state_flags;
unsigned int ref_cnt;
void (*job_done)(struct fc_bsg_job *);
struct fc_bsg_request *request;
struct fc_bsg_reply *reply;
unsigned int request_len;
unsigned int reply_len;
/*
* On entry : reply_len indicates the buffer size allocated for
* the reply.
*
* Upon completion : the message handler must set reply_len
* to indicates the size of the reply to be returned to the
* caller.
*/
/* DMA payloads for the request/response */
struct fc_bsg_buffer request_payload;
struct fc_bsg_buffer reply_payload;
void *dd_data; /* Used for driver-specific storage */
};
/* The functions by which the transport class and the driver communicate */
struct fc_function_template {
void (*get_rport_dev_loss_tmo)(struct fc_rport *);
void (*set_rport_dev_loss_tmo)(struct fc_rport *, u32);
void (*get_starget_node_name)(struct scsi_target *);
void (*get_starget_port_name)(struct scsi_target *);
void (*get_starget_port_id)(struct scsi_target *);
void (*get_host_port_id)(struct Scsi_Host *);
void (*get_host_port_type)(struct Scsi_Host *);
void (*get_host_port_state)(struct Scsi_Host *);
void (*get_host_active_fc4s)(struct Scsi_Host *);
void (*get_host_speed)(struct Scsi_Host *);
void (*get_host_fabric_name)(struct Scsi_Host *);
void (*get_host_symbolic_name)(struct Scsi_Host *);
void (*set_host_system_hostname)(struct Scsi_Host *);
struct fc_host_statistics * (*get_fc_host_stats)(struct Scsi_Host *);
void (*reset_fc_host_stats)(struct Scsi_Host *);
int (*issue_fc_host_lip)(struct Scsi_Host *);
void (*dev_loss_tmo_callbk)(struct fc_rport *);
void (*terminate_rport_io)(struct fc_rport *);
void (*set_vport_symbolic_name)(struct fc_vport *);
int (*vport_create)(struct fc_vport *, bool);
int (*vport_disable)(struct fc_vport *, bool);
int (*vport_delete)(struct fc_vport *);
/* target-mode drivers' functions */
int (* tsk_mgmt_response)(struct Scsi_Host *, u64, u64, int);
int (* it_nexus_response)(struct Scsi_Host *, u64, int);
/* bsg support */
int (*bsg_request)(struct fc_bsg_job *);
int (*bsg_timeout)(struct fc_bsg_job *);
/* allocation lengths for host-specific data */
u32 dd_fcrport_size;
u32 dd_fcvport_size;
u32 dd_bsg_size;
/*
* The driver sets these to tell the transport class it
* wants the attributes displayed in sysfs. If the show_ flag
* is not set, the attribute will be private to the transport
* class
*/
/* remote port fixed attributes */
unsigned long show_rport_maxframe_size:1;
unsigned long show_rport_supported_classes:1;
unsigned long show_rport_dev_loss_tmo:1;
/*
* target dynamic attributes
* These should all be "1" if the driver uses the remote port
* add/delete functions (so attributes reflect rport values).
*/
unsigned long show_starget_node_name:1;
unsigned long show_starget_port_name:1;
unsigned long show_starget_port_id:1;
/* host fixed attributes */
unsigned long show_host_node_name:1;
unsigned long show_host_port_name:1;
unsigned long show_host_permanent_port_name:1;
unsigned long show_host_supported_classes:1;
unsigned long show_host_supported_fc4s:1;
unsigned long show_host_supported_speeds:1;
unsigned long show_host_maxframe_size:1;
unsigned long show_host_serial_number:1;
/* host dynamic attributes */
unsigned long show_host_port_id:1;
unsigned long show_host_port_type:1;
unsigned long show_host_port_state:1;
unsigned long show_host_active_fc4s:1;
unsigned long show_host_speed:1;
unsigned long show_host_fabric_name:1;
unsigned long show_host_symbolic_name:1;
unsigned long show_host_system_hostname:1;
unsigned long disable_target_scan:1;
};
/**
* fc_remote_port_chkready - called to validate the remote port state
* prior to initiating io to the port.
*
* Returns a scsi result code that can be returned by the LLDD.
*
* @rport: remote port to be checked
**/
static inline int
fc_remote_port_chkready(struct fc_rport *rport)
{
int result;
switch (rport->port_state) {
case FC_PORTSTATE_ONLINE:
if (rport->roles & FC_PORT_ROLE_FCP_TARGET)
result = 0;
else if (rport->flags & FC_RPORT_DEVLOSS_PENDING)
result = DID_IMM_RETRY << 16;
else
result = DID_NO_CONNECT << 16;
break;
case FC_PORTSTATE_BLOCKED:
if (rport->flags & FC_RPORT_FAST_FAIL_TIMEDOUT)
result = DID_TRANSPORT_FAILFAST << 16;
else
result = DID_IMM_RETRY << 16;
break;
default:
result = DID_NO_CONNECT << 16;
break;
}
return result;
}
static inline u64 wwn_to_u64(u8 *wwn)
{
return (u64)wwn[0] << 56 | (u64)wwn[1] << 48 |
(u64)wwn[2] << 40 | (u64)wwn[3] << 32 |
(u64)wwn[4] << 24 | (u64)wwn[5] << 16 |
(u64)wwn[6] << 8 | (u64)wwn[7];
}
static inline void u64_to_wwn(u64 inm, u8 *wwn)
{
wwn[0] = (inm >> 56) & 0xff;
wwn[1] = (inm >> 48) & 0xff;
wwn[2] = (inm >> 40) & 0xff;
wwn[3] = (inm >> 32) & 0xff;
wwn[4] = (inm >> 24) & 0xff;
wwn[5] = (inm >> 16) & 0xff;
wwn[6] = (inm >> 8) & 0xff;
wwn[7] = inm & 0xff;
}
/**
* fc_vport_set_state() - called to set a vport's state. Saves the old state,
* excepting the transitory states of initializing and sending the ELS
* traffic to instantiate the vport on the link.
*
* Assumes the driver has surrounded this with the proper locking to ensure
* a coherent state change.
*
* @vport: virtual port whose state is changing
* @new_state: new state
**/
static inline void
fc_vport_set_state(struct fc_vport *vport, enum fc_vport_state new_state)
{
if ((new_state != FC_VPORT_UNKNOWN) &&
(new_state != FC_VPORT_INITIALIZING))
vport->vport_last_state = vport->vport_state;
vport->vport_state = new_state;
}
struct scsi_transport_template *fc_attach_transport(
struct fc_function_template *);
void fc_release_transport(struct scsi_transport_template *);
void fc_remove_host(struct Scsi_Host *);
struct fc_rport *fc_remote_port_add(struct Scsi_Host *shost,
int channel, struct fc_rport_identifiers *ids);
void fc_remote_port_delete(struct fc_rport *rport);
void fc_remote_port_rolechg(struct fc_rport *rport, u32 roles);
int scsi_is_fc_rport(const struct device *);
u32 fc_get_event_number(void);
void fc_host_post_event(struct Scsi_Host *shost, u32 event_number,
enum fc_host_event_code event_code, u32 event_data);
void fc_host_post_vendor_event(struct Scsi_Host *shost, u32 event_number,
u32 data_len, char * data_buf, u64 vendor_id);
/* Note: when specifying vendor_id to fc_host_post_vendor_event()
* be sure to read the Vendor Type and ID formatting requirements
* specified in scsi_netlink.h
*/
struct fc_vport *fc_vport_create(struct Scsi_Host *shost, int channel,
struct fc_vport_identifiers *);
int fc_vport_terminate(struct fc_vport *vport);
#endif /* SCSI_TRANSPORT_FC_H */

View File

@@ -0,0 +1,259 @@
/*
* iSCSI transport class definitions
*
* Copyright (C) IBM Corporation, 2004
* Copyright (C) Mike Christie, 2004 - 2006
* Copyright (C) Dmitry Yusupov, 2004 - 2005
* Copyright (C) Alex Aizman, 2004 - 2005
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef SCSI_TRANSPORT_ISCSI_H
#define SCSI_TRANSPORT_ISCSI_H
#include <linux/device.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <scsi/iscsi_if.h>
struct scsi_transport_template;
struct iscsi_transport;
struct iscsi_endpoint;
struct Scsi_Host;
struct iscsi_cls_conn;
struct iscsi_conn;
struct iscsi_task;
struct sockaddr;
/**
* struct iscsi_transport - iSCSI Transport template
*
* @name: transport name
* @caps: iSCSI Data-Path capabilities
* @create_session: create new iSCSI session object
* @destroy_session: destroy existing iSCSI session object
* @create_conn: create new iSCSI connection
* @bind_conn: associate this connection with existing iSCSI session
* and specified transport descriptor
* @destroy_conn: destroy inactive iSCSI connection
* @set_param: set iSCSI parameter. Return 0 on success, -ENODATA
* when param is not supported, and a -Exx value on other
* error.
* @get_param get iSCSI parameter. Must return number of bytes
* copied to buffer on success, -ENODATA when param
* is not supported, and a -Exx value on other error
* @start_conn: set connection to be operational
* @stop_conn: suspend/recover/terminate connection
* @send_pdu: send iSCSI PDU, Login, Logout, NOP-Out, Reject, Text.
* @session_recovery_timedout: notify LLD a block during recovery timed out
* @init_task: Initialize a iscsi_task and any internal structs.
* When offloading the data path, this is called from
* queuecommand with the session lock, or from the
* iscsi_conn_send_pdu context with the session lock.
* When not offloading the data path, this is called
* from the scsi work queue without the session lock.
* @xmit_task Requests LLD to transfer cmd task. Returns 0 or the
* the number of bytes transferred on success, and -Exyz
* value on error. When offloading the data path, this
* is called from queuecommand with the session lock, or
* from the iscsi_conn_send_pdu context with the session
* lock. When not offloading the data path, this is called
* from the scsi work queue without the session lock.
* @cleanup_task: requests LLD to fail task. Called with session lock
* and after the connection has been suspended and
* terminated during recovery. If called
* from abort task then connection is not suspended
* or terminated but sk_callback_lock is held
*
* Template API provided by iSCSI Transport
*/
struct iscsi_transport {
struct module *owner;
char *name;
unsigned int caps;
/* LLD sets this to indicate what values it can export to sysfs */
uint64_t param_mask;
uint64_t host_param_mask;
struct iscsi_cls_session *(*create_session) (struct iscsi_endpoint *ep,
uint16_t cmds_max, uint16_t qdepth,
uint32_t sn);
void (*destroy_session) (struct iscsi_cls_session *session);
struct iscsi_cls_conn *(*create_conn) (struct iscsi_cls_session *sess,
uint32_t cid);
int (*bind_conn) (struct iscsi_cls_session *session,
struct iscsi_cls_conn *cls_conn,
uint64_t transport_eph, int is_leading);
int (*start_conn) (struct iscsi_cls_conn *conn);
void (*stop_conn) (struct iscsi_cls_conn *conn, int flag);
void (*destroy_conn) (struct iscsi_cls_conn *conn);
int (*set_param) (struct iscsi_cls_conn *conn, enum iscsi_param param,
char *buf, int buflen);
int (*get_conn_param) (struct iscsi_cls_conn *conn,
enum iscsi_param param, char *buf);
int (*get_session_param) (struct iscsi_cls_session *session,
enum iscsi_param param, char *buf);
int (*get_host_param) (struct Scsi_Host *shost,
enum iscsi_host_param param, char *buf);
int (*set_host_param) (struct Scsi_Host *shost,
enum iscsi_host_param param, char *buf,
int buflen);
int (*send_pdu) (struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
char *data, uint32_t data_size);
void (*get_stats) (struct iscsi_cls_conn *conn,
struct iscsi_stats *stats);
int (*init_task) (struct iscsi_task *task);
int (*xmit_task) (struct iscsi_task *task);
void (*cleanup_task) (struct iscsi_task *task);
int (*alloc_pdu) (struct iscsi_task *task, uint8_t opcode);
int (*xmit_pdu) (struct iscsi_task *task);
int (*init_pdu) (struct iscsi_task *task, unsigned int offset,
unsigned int count);
void (*parse_pdu_itt) (struct iscsi_conn *conn, itt_t itt,
int *index, int *age);
void (*session_recovery_timedout) (struct iscsi_cls_session *session);
struct iscsi_endpoint *(*ep_connect) (struct Scsi_Host *shost,
struct sockaddr *dst_addr,
int non_blocking);
int (*ep_poll) (struct iscsi_endpoint *ep, int timeout_ms);
void (*ep_disconnect) (struct iscsi_endpoint *ep);
int (*tgt_dscvr) (struct Scsi_Host *shost, enum iscsi_tgt_dscvr type,
uint32_t enable, struct sockaddr *dst_addr);
int (*set_path) (struct Scsi_Host *shost, struct iscsi_path *params);
};
/*
* transport registration upcalls
*/
extern struct scsi_transport_template *iscsi_register_transport(struct iscsi_transport *tt);
extern int iscsi_unregister_transport(struct iscsi_transport *tt);
/*
* control plane upcalls
*/
extern void iscsi_conn_error_event(struct iscsi_cls_conn *conn,
enum iscsi_err error);
extern int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
char *data, uint32_t data_size);
extern int iscsi_offload_mesg(struct Scsi_Host *shost,
struct iscsi_transport *transport, uint32_t type,
char *data, uint16_t data_size);
struct iscsi_cls_conn {
struct list_head conn_list; /* item in connlist */
void *dd_data; /* LLD private data */
struct iscsi_transport *transport;
uint32_t cid; /* connection id */
int active; /* must be accessed with the connlock */
struct device dev; /* sysfs transport/container device */
};
#define iscsi_dev_to_conn(_dev) \
container_of(_dev, struct iscsi_cls_conn, dev)
#define iscsi_conn_to_session(_conn) \
iscsi_dev_to_session(_conn->dev.parent)
/* iscsi class session state */
enum {
ISCSI_SESSION_LOGGED_IN,
ISCSI_SESSION_FAILED,
ISCSI_SESSION_FREE,
};
#define ISCSI_MAX_TARGET -1
struct iscsi_cls_session {
struct list_head sess_list; /* item in session_list */
struct iscsi_transport *transport;
spinlock_t lock;
struct work_struct block_work;
struct work_struct unblock_work;
struct work_struct scan_work;
struct work_struct unbind_work;
/* recovery fields */
int recovery_tmo;
struct delayed_work recovery_work;
unsigned int target_id;
int state;
int sid; /* session id */
void *dd_data; /* LLD private data */
struct device dev; /* sysfs transport/container device */
};
#define iscsi_dev_to_session(_dev) \
container_of(_dev, struct iscsi_cls_session, dev)
#define iscsi_session_to_shost(_session) \
dev_to_shost(_session->dev.parent)
#define starget_to_session(_stgt) \
iscsi_dev_to_session(_stgt->dev.parent)
struct iscsi_cls_host {
atomic_t nr_scans;
struct mutex mutex;
};
extern void iscsi_host_for_each_session(struct Scsi_Host *shost,
void (*fn)(struct iscsi_cls_session *));
struct iscsi_endpoint {
void *dd_data; /* LLD private data */
struct device dev;
uint64_t id;
};
/*
* session and connection functions that can be used by HW iSCSI LLDs
*/
#define iscsi_cls_session_printk(prefix, _cls_session, fmt, a...) \
dev_printk(prefix, &(_cls_session)->dev, fmt, ##a)
#define iscsi_cls_conn_printk(prefix, _cls_conn, fmt, a...) \
dev_printk(prefix, &(_cls_conn)->dev, fmt, ##a)
extern int iscsi_session_chkready(struct iscsi_cls_session *session);
extern struct iscsi_cls_session *iscsi_alloc_session(struct Scsi_Host *shost,
struct iscsi_transport *transport, int dd_size);
extern int iscsi_add_session(struct iscsi_cls_session *session,
unsigned int target_id);
extern int iscsi_session_event(struct iscsi_cls_session *session,
enum iscsi_uevent_e event);
extern struct iscsi_cls_session *iscsi_create_session(struct Scsi_Host *shost,
struct iscsi_transport *t,
int dd_size,
unsigned int target_id);
extern void iscsi_remove_session(struct iscsi_cls_session *session);
extern void iscsi_free_session(struct iscsi_cls_session *session);
extern int iscsi_destroy_session(struct iscsi_cls_session *session);
extern struct iscsi_cls_conn *iscsi_create_conn(struct iscsi_cls_session *sess,
int dd_size, uint32_t cid);
extern int iscsi_destroy_conn(struct iscsi_cls_conn *conn);
extern void iscsi_unblock_session(struct iscsi_cls_session *session);
extern void iscsi_block_session(struct iscsi_cls_session *session);
extern int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time);
extern struct iscsi_endpoint *iscsi_create_endpoint(int dd_size);
extern void iscsi_destroy_endpoint(struct iscsi_endpoint *ep);
extern struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle);
#endif

View File

@@ -0,0 +1,220 @@
#ifndef SCSI_TRANSPORT_SAS_H
#define SCSI_TRANSPORT_SAS_H
#include <linux/transport_class.h>
#include <linux/types.h>
#include <linux/mutex.h>
#include <scsi/sas.h>
struct scsi_transport_template;
struct sas_rphy;
struct request;
enum sas_device_type {
SAS_PHY_UNUSED = 0,
SAS_END_DEVICE = 1,
SAS_EDGE_EXPANDER_DEVICE = 2,
SAS_FANOUT_EXPANDER_DEVICE = 3,
};
static inline int sas_protocol_ata(enum sas_protocol proto)
{
return ((proto & SAS_PROTOCOL_SATA) ||
(proto & SAS_PROTOCOL_STP))? 1 : 0;
}
enum sas_linkrate {
/* These Values are defined in the SAS standard */
SAS_LINK_RATE_UNKNOWN = 0,
SAS_PHY_DISABLED = 1,
SAS_PHY_RESET_PROBLEM = 2,
SAS_SATA_SPINUP_HOLD = 3,
SAS_SATA_PORT_SELECTOR = 4,
SAS_PHY_RESET_IN_PROGRESS = 5,
SAS_LINK_RATE_1_5_GBPS = 8,
SAS_LINK_RATE_G1 = SAS_LINK_RATE_1_5_GBPS,
SAS_LINK_RATE_3_0_GBPS = 9,
SAS_LINK_RATE_G2 = SAS_LINK_RATE_3_0_GBPS,
SAS_LINK_RATE_6_0_GBPS = 10,
/* These are virtual to the transport class and may never
* be signalled normally since the standard defined field
* is only 4 bits */
SAS_LINK_RATE_FAILED = 0x10,
SAS_PHY_VIRTUAL = 0x11,
};
struct sas_identify {
enum sas_device_type device_type;
enum sas_protocol initiator_port_protocols;
enum sas_protocol target_port_protocols;
u64 sas_address;
u8 phy_identifier;
};
struct sas_phy {
struct device dev;
int number;
int enabled;
/* phy identification */
struct sas_identify identify;
/* phy attributes */
enum sas_linkrate negotiated_linkrate;
enum sas_linkrate minimum_linkrate_hw;
enum sas_linkrate minimum_linkrate;
enum sas_linkrate maximum_linkrate_hw;
enum sas_linkrate maximum_linkrate;
/* link error statistics */
u32 invalid_dword_count;
u32 running_disparity_error_count;
u32 loss_of_dword_sync_count;
u32 phy_reset_problem_count;
/* for the list of phys belonging to a port */
struct list_head port_siblings;
struct work_struct reset_work;
};
#define dev_to_phy(d) \
container_of((d), struct sas_phy, dev)
#define transport_class_to_phy(dev) \
dev_to_phy((dev)->parent)
#define phy_to_shost(phy) \
dev_to_shost((phy)->dev.parent)
struct request_queue;
struct sas_rphy {
struct device dev;
struct sas_identify identify;
struct list_head list;
struct request_queue *q;
u32 scsi_target_id;
};
#define dev_to_rphy(d) \
container_of((d), struct sas_rphy, dev)
#define transport_class_to_rphy(dev) \
dev_to_rphy((dev)->parent)
#define rphy_to_shost(rphy) \
dev_to_shost((rphy)->dev.parent)
#define target_to_rphy(targ) \
dev_to_rphy((targ)->dev.parent)
struct sas_end_device {
struct sas_rphy rphy;
/* flags */
unsigned ready_led_meaning:1;
/* parameters */
u16 I_T_nexus_loss_timeout;
u16 initiator_response_timeout;
};
#define rphy_to_end_device(r) \
container_of((r), struct sas_end_device, rphy)
struct sas_expander_device {
int level;
int next_port_id;
#define SAS_EXPANDER_VENDOR_ID_LEN 8
char vendor_id[SAS_EXPANDER_VENDOR_ID_LEN+1];
#define SAS_EXPANDER_PRODUCT_ID_LEN 16
char product_id[SAS_EXPANDER_PRODUCT_ID_LEN+1];
#define SAS_EXPANDER_PRODUCT_REV_LEN 4
char product_rev[SAS_EXPANDER_PRODUCT_REV_LEN+1];
#define SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN 8
char component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN+1];
u16 component_id;
u8 component_revision_id;
struct sas_rphy rphy;
};
#define rphy_to_expander_device(r) \
container_of((r), struct sas_expander_device, rphy)
struct sas_port {
struct device dev;
int port_identifier;
int num_phys;
/* port flags */
unsigned int is_backlink:1;
/* the other end of the link */
struct sas_rphy *rphy;
struct mutex phy_list_mutex;
struct list_head phy_list;
};
#define dev_to_sas_port(d) \
container_of((d), struct sas_port, dev)
#define transport_class_to_sas_port(dev) \
dev_to_sas_port((dev)->parent)
struct sas_phy_linkrates {
enum sas_linkrate maximum_linkrate;
enum sas_linkrate minimum_linkrate;
};
/* The functions by which the transport class and the driver communicate */
struct sas_function_template {
int (*get_linkerrors)(struct sas_phy *);
int (*get_enclosure_identifier)(struct sas_rphy *, u64 *);
int (*get_bay_identifier)(struct sas_rphy *);
int (*phy_reset)(struct sas_phy *, int);
int (*phy_enable)(struct sas_phy *, int);
int (*set_phy_speed)(struct sas_phy *, struct sas_phy_linkrates *);
int (*smp_handler)(struct Scsi_Host *, struct sas_rphy *, struct request *);
};
void sas_remove_children(struct device *);
extern void sas_remove_host(struct Scsi_Host *);
extern struct sas_phy *sas_phy_alloc(struct device *, int);
extern void sas_phy_free(struct sas_phy *);
extern int sas_phy_add(struct sas_phy *);
extern void sas_phy_delete(struct sas_phy *);
extern int scsi_is_sas_phy(const struct device *);
extern struct sas_rphy *sas_end_device_alloc(struct sas_port *);
extern struct sas_rphy *sas_expander_alloc(struct sas_port *, enum sas_device_type);
void sas_rphy_free(struct sas_rphy *);
extern int sas_rphy_add(struct sas_rphy *);
extern void sas_rphy_remove(struct sas_rphy *);
extern void sas_rphy_delete(struct sas_rphy *);
extern int scsi_is_sas_rphy(const struct device *);
struct sas_port *sas_port_alloc(struct device *, int);
struct sas_port *sas_port_alloc_num(struct device *);
int sas_port_add(struct sas_port *);
void sas_port_free(struct sas_port *);
void sas_port_delete(struct sas_port *);
void sas_port_add_phy(struct sas_port *, struct sas_phy *);
void sas_port_delete_phy(struct sas_port *, struct sas_phy *);
void sas_port_mark_backlink(struct sas_port *);
int scsi_is_sas_port(const struct device *);
extern struct scsi_transport_template *
sas_attach_transport(struct sas_function_template *);
extern void sas_release_transport(struct scsi_transport_template *);
int sas_read_port_mode_page(struct scsi_device *);
static inline int
scsi_is_sas_expander_device(struct device *dev)
{
struct sas_rphy *rphy;
if (!scsi_is_sas_rphy(dev))
return 0;
rphy = dev_to_rphy(dev);
return rphy->identify.device_type == SAS_FANOUT_EXPANDER_DEVICE ||
rphy->identify.device_type == SAS_EDGE_EXPANDER_DEVICE;
}
#define scsi_is_sas_phy_local(phy) scsi_is_host_device((phy)->dev.parent)
#endif /* SCSI_TRANSPORT_SAS_H */

View File

@@ -0,0 +1,161 @@
/*
* Parallel SCSI (SPI) transport specific attributes exported to sysfs.
*
* Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef SCSI_TRANSPORT_SPI_H
#define SCSI_TRANSPORT_SPI_H
#include <linux/transport_class.h>
#include <linux/mutex.h>
struct scsi_transport_template;
struct scsi_target;
struct scsi_device;
struct Scsi_Host;
struct spi_transport_attrs {
int period; /* value in the PPR/SDTR command */
int min_period;
int offset;
int max_offset;
unsigned int width:1; /* 0 - narrow, 1 - wide */
unsigned int max_width:1;
unsigned int iu:1; /* Information Units enabled */
unsigned int max_iu:1;
unsigned int dt:1; /* DT clocking enabled */
unsigned int qas:1; /* Quick Arbitration and Selection enabled */
unsigned int max_qas:1;
unsigned int wr_flow:1; /* Write Flow control enabled */
unsigned int rd_strm:1; /* Read streaming enabled */
unsigned int rti:1; /* Retain Training Information */
unsigned int pcomp_en:1;/* Precompensation enabled */
unsigned int hold_mcs:1;/* Hold Margin Control Settings */
unsigned int initial_dv:1; /* DV done to this target yet */
unsigned long flags; /* flags field for drivers to use */
/* Device Properties fields */
unsigned int support_sync:1; /* synchronous support */
unsigned int support_wide:1; /* wide support */
unsigned int support_dt:1; /* allows DT phases */
unsigned int support_dt_only; /* disallows ST phases */
unsigned int support_ius; /* support Information Units */
unsigned int support_qas; /* supports quick arbitration and selection */
/* Private Fields */
unsigned int dv_pending:1; /* Internal flag: DV Requested */
unsigned int dv_in_progress:1; /* Internal: DV started */
struct mutex dv_mutex; /* semaphore to serialise dv */
};
enum spi_signal_type {
SPI_SIGNAL_UNKNOWN = 1,
SPI_SIGNAL_SE,
SPI_SIGNAL_LVD,
SPI_SIGNAL_HVD,
};
struct spi_host_attrs {
enum spi_signal_type signalling;
};
/* accessor functions */
#define spi_period(x) (((struct spi_transport_attrs *)&(x)->starget_data)->period)
#define spi_min_period(x) (((struct spi_transport_attrs *)&(x)->starget_data)->min_period)
#define spi_offset(x) (((struct spi_transport_attrs *)&(x)->starget_data)->offset)
#define spi_max_offset(x) (((struct spi_transport_attrs *)&(x)->starget_data)->max_offset)
#define spi_width(x) (((struct spi_transport_attrs *)&(x)->starget_data)->width)
#define spi_max_width(x) (((struct spi_transport_attrs *)&(x)->starget_data)->max_width)
#define spi_iu(x) (((struct spi_transport_attrs *)&(x)->starget_data)->iu)
#define spi_max_iu(x) (((struct spi_transport_attrs *)&(x)->starget_data)->max_iu)
#define spi_dt(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dt)
#define spi_qas(x) (((struct spi_transport_attrs *)&(x)->starget_data)->qas)
#define spi_max_qas(x) (((struct spi_transport_attrs *)&(x)->starget_data)->max_qas)
#define spi_wr_flow(x) (((struct spi_transport_attrs *)&(x)->starget_data)->wr_flow)
#define spi_rd_strm(x) (((struct spi_transport_attrs *)&(x)->starget_data)->rd_strm)
#define spi_rti(x) (((struct spi_transport_attrs *)&(x)->starget_data)->rti)
#define spi_pcomp_en(x) (((struct spi_transport_attrs *)&(x)->starget_data)->pcomp_en)
#define spi_hold_mcs(x) (((struct spi_transport_attrs *)&(x)->starget_data)->hold_mcs)
#define spi_initial_dv(x) (((struct spi_transport_attrs *)&(x)->starget_data)->initial_dv)
#define spi_dv_pending(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_pending)
#define spi_support_sync(x) (((struct spi_transport_attrs *)&(x)->starget_data)->support_sync)
#define spi_support_wide(x) (((struct spi_transport_attrs *)&(x)->starget_data)->support_wide)
#define spi_support_dt(x) (((struct spi_transport_attrs *)&(x)->starget_data)->support_dt)
#define spi_support_dt_only(x) (((struct spi_transport_attrs *)&(x)->starget_data)->support_dt_only)
#define spi_support_ius(x) (((struct spi_transport_attrs *)&(x)->starget_data)->support_ius)
#define spi_support_qas(x) (((struct spi_transport_attrs *)&(x)->starget_data)->support_qas)
#define spi_flags(x) (((struct spi_transport_attrs *)&(x)->starget_data)->flags)
#define spi_signalling(h) (((struct spi_host_attrs *)(h)->shost_data)->signalling)
/* The functions by which the transport class and the driver communicate */
struct spi_function_template {
void (*get_period)(struct scsi_target *);
void (*set_period)(struct scsi_target *, int);
void (*get_offset)(struct scsi_target *);
void (*set_offset)(struct scsi_target *, int);
void (*get_width)(struct scsi_target *);
void (*set_width)(struct scsi_target *, int);
void (*get_iu)(struct scsi_target *);
void (*set_iu)(struct scsi_target *, int);
void (*get_dt)(struct scsi_target *);
void (*set_dt)(struct scsi_target *, int);
void (*get_qas)(struct scsi_target *);
void (*set_qas)(struct scsi_target *, int);
void (*get_wr_flow)(struct scsi_target *);
void (*set_wr_flow)(struct scsi_target *, int);
void (*get_rd_strm)(struct scsi_target *);
void (*set_rd_strm)(struct scsi_target *, int);
void (*get_rti)(struct scsi_target *);
void (*set_rti)(struct scsi_target *, int);
void (*get_pcomp_en)(struct scsi_target *);
void (*set_pcomp_en)(struct scsi_target *, int);
void (*get_hold_mcs)(struct scsi_target *);
void (*set_hold_mcs)(struct scsi_target *, int);
void (*get_signalling)(struct Scsi_Host *);
void (*set_signalling)(struct Scsi_Host *, enum spi_signal_type);
int (*deny_binding)(struct scsi_target *);
/* The driver sets these to tell the transport class it
* wants the attributes displayed in sysfs. If the show_ flag
* is not set, the attribute will be private to the transport
* class */
unsigned long show_period:1;
unsigned long show_offset:1;
unsigned long show_width:1;
unsigned long show_iu:1;
unsigned long show_dt:1;
unsigned long show_qas:1;
unsigned long show_wr_flow:1;
unsigned long show_rd_strm:1;
unsigned long show_rti:1;
unsigned long show_pcomp_en:1;
unsigned long show_hold_mcs:1;
};
struct scsi_transport_template *spi_attach_transport(struct spi_function_template *);
void spi_release_transport(struct scsi_transport_template *);
void spi_schedule_dv_device(struct scsi_device *);
void spi_dv_device(struct scsi_device *);
void spi_display_xfer_agreement(struct scsi_target *);
int spi_print_msg(const unsigned char *);
int spi_populate_width_msg(unsigned char *msg, int width);
int spi_populate_sync_msg(unsigned char *msg, int period, int offset);
int spi_populate_ppr_msg(unsigned char *msg, int period, int offset, int width,
int options);
#endif /* SCSI_TRANSPORT_SPI_H */

View File

@@ -0,0 +1,39 @@
#ifndef SCSI_TRANSPORT_SRP_H
#define SCSI_TRANSPORT_SRP_H
#include <linux/transport_class.h>
#include <linux/types.h>
#include <linux/mutex.h>
#define SRP_RPORT_ROLE_INITIATOR 0
#define SRP_RPORT_ROLE_TARGET 1
struct srp_rport_identifiers {
u8 port_id[16];
u8 roles;
};
struct srp_rport {
struct device dev;
u8 port_id[16];
u8 roles;
};
struct srp_function_template {
/* for target drivers */
int (* tsk_mgmt_response)(struct Scsi_Host *, u64, u64, int);
int (* it_nexus_response)(struct Scsi_Host *, u64, int);
};
extern struct scsi_transport_template *
srp_attach_transport(struct srp_function_template *);
extern void srp_release_transport(struct scsi_transport_template *);
extern struct srp_rport *srp_rport_add(struct Scsi_Host *,
struct srp_rport_identifiers *);
extern void srp_rport_del(struct srp_rport *);
extern void srp_remove_host(struct Scsi_Host *);
#endif

View File

@@ -0,0 +1,19 @@
/*
* scsicam.h - SCSI CAM support functions, use for HDIO_GETGEO, etc.
*
* Copyright 1993, 1994 Drew Eckhardt
* Visionary Computing
* (Unix and Linux consulting and custom programming)
* drew@Colorado.EDU
* +1 (303) 786-7975
*
* For more information, please consult the SCSI-CAM draft.
*/
#ifndef SCSICAM_H
#define SCSICAM_H
extern int scsicam_bios_param (struct block_device *bdev, sector_t capacity, int *ip);
extern int scsi_partsize(unsigned char *buf, unsigned long capacity,
unsigned int *cyls, unsigned int *hds, unsigned int *secs);
extern unsigned char *scsi_bios_ptable(struct block_device *bdev);
#endif /* def SCSICAM_H */

308
kernel/include/scsi/sg.h Normal file
View File

@@ -0,0 +1,308 @@
#ifndef _SCSI_GENERIC_H
#define _SCSI_GENERIC_H
#include <linux/compiler.h>
/*
History:
Started: Aug 9 by Lawrence Foard (entropy@world.std.com), to allow user
process control of SCSI devices.
Development Sponsored by Killy Corp. NY NY
Original driver (sg.h):
* Copyright (C) 1992 Lawrence Foard
Version 2 and 3 extensions to driver:
* Copyright (C) 1998 - 2006 Douglas Gilbert
Version: 3.5.34 (20060920)
This version is for 2.6 series kernels.
For a full changelog see http://www.torque.net/sg
Map of SG verions to the Linux kernels in which they appear:
---------- ----------------------------------
original all kernels < 2.2.6
2.1.40 2.2.20
3.0.x optional version 3 sg driver for 2.2 series
3.1.17++ 2.4.0++
3.5.30++ 2.6.0++
Major new features in SG 3.x driver (cf SG 2.x drivers)
- SG_IO ioctl() combines function if write() and read()
- new interface (sg_io_hdr_t) but still supports old interface
- scatter/gather in user space, direct IO, and mmap supported
The normal action of this driver is to use the adapter (HBA) driver to DMA
data into kernel buffers and then use the CPU to copy the data into the
user space (vice versa for writes). That is called "indirect" IO due to
the double handling of data. There are two methods offered to remove the
redundant copy: 1) direct IO and 2) using the mmap() system call to map
the reserve buffer (this driver has one reserve buffer per fd) into the
user space. Both have their advantages.
In terms of absolute speed mmap() is faster. If speed is not a concern,
indirect IO should be fine. Read the documentation for more information.
** N.B. To use direct IO 'echo 1 > /proc/scsi/sg/allow_dio' or
'echo 1 > /sys/module/sg/parameters/allow_dio' is needed.
That attribute is 0 by default. **
Historical note: this SCSI pass-through driver has been known as "sg" for
a decade. In broader kernel discussions "sg" is used to refer to scatter
gather techniques. The context should clarify which "sg" is referred to.
Documentation
=============
A web site for the SG device driver can be found at:
http://www.torque.net/sg [alternatively check the MAINTAINERS file]
The documentation for the sg version 3 driver can be found at:
http://www.torque.net/sg/p/sg_v3_ho.html
This is a rendering from DocBook source [change the extension to "sgml"
or "xml"]. There are renderings in "ps", "pdf", "rtf" and "txt" (soon).
The SG_IO ioctl is now found in other parts kernel (e.g. the block layer).
For more information see http://www.torque.net/sg/sg_io.html
The older, version 2 documents discuss the original sg interface in detail:
http://www.torque.net/sg/p/scsi-generic.txt
http://www.torque.net/sg/p/scsi-generic_long.txt
Also available: <kernel_source>/Documentation/scsi/scsi-generic.txt
Utility and test programs are available at the sg web site. They are
packaged as sg3_utils (for the lk 2.4 and 2.6 series) and sg_utils
(for the lk 2.2 series).
*/
/* New interface introduced in the 3.x SG drivers follows */
typedef struct sg_iovec /* same structure as used by readv() Linux system */
{ /* call. It defines one scatter-gather element. */
void __user *iov_base; /* Starting address */
size_t iov_len; /* Length in bytes */
} sg_iovec_t;
typedef struct sg_io_hdr
{
int interface_id; /* [i] 'S' for SCSI generic (required) */
int dxfer_direction; /* [i] data transfer direction */
unsigned char cmd_len; /* [i] SCSI command length ( <= 16 bytes) */
unsigned char mx_sb_len; /* [i] max length to write to sbp */
unsigned short iovec_count; /* [i] 0 implies no scatter gather */
unsigned int dxfer_len; /* [i] byte count of data transfer */
void __user *dxferp; /* [i], [*io] points to data transfer memory
or scatter gather list */
unsigned char __user *cmdp; /* [i], [*i] points to command to perform */
void __user *sbp; /* [i], [*o] points to sense_buffer memory */
unsigned int timeout; /* [i] MAX_UINT->no timeout (unit: millisec) */
unsigned int flags; /* [i] 0 -> default, see SG_FLAG... */
int pack_id; /* [i->o] unused internally (normally) */
void __user * usr_ptr; /* [i->o] unused internally */
unsigned char status; /* [o] scsi status */
unsigned char masked_status;/* [o] shifted, masked scsi status */
unsigned char msg_status; /* [o] messaging level data (optional) */
unsigned char sb_len_wr; /* [o] byte count actually written to sbp */
unsigned short host_status; /* [o] errors from host adapter */
unsigned short driver_status;/* [o] errors from software driver */
int resid; /* [o] dxfer_len - actual_transferred */
unsigned int duration; /* [o] time taken by cmd (unit: millisec) */
unsigned int info; /* [o] auxiliary information */
} sg_io_hdr_t; /* 64 bytes long (on i386) */
#define SG_INTERFACE_ID_ORIG 'S'
/* Use negative values to flag difference from original sg_header structure */
#define SG_DXFER_NONE (-1) /* e.g. a SCSI Test Unit Ready command */
#define SG_DXFER_TO_DEV (-2) /* e.g. a SCSI WRITE command */
#define SG_DXFER_FROM_DEV (-3) /* e.g. a SCSI READ command */
#define SG_DXFER_TO_FROM_DEV (-4) /* treated like SG_DXFER_FROM_DEV with the
additional property than during indirect
IO the user buffer is copied into the
kernel buffers before the transfer */
#define SG_DXFER_UNKNOWN (-5) /* Unknown data direction */
/* following flag values can be "or"-ed together */
#define SG_FLAG_DIRECT_IO 1 /* default is indirect IO */
#define SG_FLAG_UNUSED_LUN_INHIBIT 2 /* default is overwrite lun in SCSI */
/* command block (when <= SCSI_2) */
#define SG_FLAG_MMAP_IO 4 /* request memory mapped IO */
#define SG_FLAG_NO_DXFER 0x10000 /* no transfer of kernel buffers to/from */
/* user space (debug indirect IO) */
/* following 'info' values are "or"-ed together */
#define SG_INFO_OK_MASK 0x1
#define SG_INFO_OK 0x0 /* no sense, host nor driver "noise" */
#define SG_INFO_CHECK 0x1 /* something abnormal happened */
#define SG_INFO_DIRECT_IO_MASK 0x6
#define SG_INFO_INDIRECT_IO 0x0 /* data xfer via kernel buffers (or no xfer) */
#define SG_INFO_DIRECT_IO 0x2 /* direct IO requested and performed */
#define SG_INFO_MIXED_IO 0x4 /* part direct, part indirect IO */
typedef struct sg_scsi_id { /* used by SG_GET_SCSI_ID ioctl() */
int host_no; /* as in "scsi<n>" where 'n' is one of 0, 1, 2 etc */
int channel;
int scsi_id; /* scsi id of target device */
int lun;
int scsi_type; /* TYPE_... defined in scsi/scsi.h */
short h_cmd_per_lun;/* host (adapter) maximum commands per lun */
short d_queue_depth;/* device (or adapter) maximum queue length */
int unused[2]; /* probably find a good use, set 0 for now */
} sg_scsi_id_t; /* 32 bytes long on i386 */
typedef struct sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */
char req_state; /* 0 -> not used, 1 -> written, 2 -> ready to read */
char orphan; /* 0 -> normal request, 1 -> from interruped SG_IO */
char sg_io_owned; /* 0 -> complete with read(), 1 -> owned by SG_IO */
char problem; /* 0 -> no problem detected, 1 -> error to report */
int pack_id; /* pack_id associated with request */
void __user *usr_ptr; /* user provided pointer (in new interface) */
unsigned int duration; /* millisecs elapsed since written (req_state==1)
or request duration (req_state==2) */
int unused;
} sg_req_info_t; /* 20 bytes long on i386 */
/* IOCTLs: Those ioctls that are relevant to the SG 3.x drivers follow.
[Those that only apply to the SG 2.x drivers are at the end of the file.]
(_GET_s yield result via 'int *' 3rd argument unless otherwise indicated) */
#define SG_EMULATED_HOST 0x2203 /* true for emulated host adapter (ATAPI) */
/* Used to configure SCSI command transformation layer for ATAPI devices */
/* Only supported by the ide-scsi driver */
#define SG_SET_TRANSFORM 0x2204 /* N.B. 3rd arg is not pointer but value: */
/* 3rd arg = 0 to disable transform, 1 to enable it */
#define SG_GET_TRANSFORM 0x2205
#define SG_SET_RESERVED_SIZE 0x2275 /* request a new reserved buffer size */
#define SG_GET_RESERVED_SIZE 0x2272 /* actual size of reserved buffer */
/* The following ioctl has a 'sg_scsi_id_t *' object as its 3rd argument. */
#define SG_GET_SCSI_ID 0x2276 /* Yields fd's bus, chan, dev, lun + type */
/* SCSI id information can also be obtained from SCSI_IOCTL_GET_IDLUN */
/* Override host setting and always DMA using low memory ( <16MB on i386) */
#define SG_SET_FORCE_LOW_DMA 0x2279 /* 0-> use adapter setting, 1-> force */
#define SG_GET_LOW_DMA 0x227a /* 0-> use all ram for dma; 1-> low dma ram */
/* When SG_SET_FORCE_PACK_ID set to 1, pack_id is input to read() which
tries to fetch a packet with a matching pack_id, waits, or returns EAGAIN.
If pack_id is -1 then read oldest waiting. When ...FORCE_PACK_ID set to 0
then pack_id ignored by read() and oldest readable fetched. */
#define SG_SET_FORCE_PACK_ID 0x227b
#define SG_GET_PACK_ID 0x227c /* Yields oldest readable pack_id (or -1) */
#define SG_GET_NUM_WAITING 0x227d /* Number of commands awaiting read() */
/* Yields max scatter gather tablesize allowed by current host adapter */
#define SG_GET_SG_TABLESIZE 0x227F /* 0 implies can't do scatter gather */
#define SG_GET_VERSION_NUM 0x2282 /* Example: version 2.1.34 yields 20134 */
/* Returns -EBUSY if occupied. 3rd argument pointer to int (see next) */
#define SG_SCSI_RESET 0x2284
/* Associated values that can be given to SG_SCSI_RESET follow */
#define SG_SCSI_RESET_NOTHING 0
#define SG_SCSI_RESET_DEVICE 1
#define SG_SCSI_RESET_BUS 2
#define SG_SCSI_RESET_HOST 3
#define SG_SCSI_RESET_TARGET 4
/* synchronous SCSI command ioctl, (only in version 3 interface) */
#define SG_IO 0x2285 /* similar effect as write() followed by read() */
#define SG_GET_REQUEST_TABLE 0x2286 /* yields table of active requests */
/* How to treat EINTR during SG_IO ioctl(), only in SG 3.x series */
#define SG_SET_KEEP_ORPHAN 0x2287 /* 1 -> hold for read(), 0 -> drop (def) */
#define SG_GET_KEEP_ORPHAN 0x2288
/* yields scsi midlevel's access_count for this SCSI device */
#define SG_GET_ACCESS_COUNT 0x2289
#define SG_SCATTER_SZ (8 * 4096)
/* Largest size (in bytes) a single scatter-gather list element can have.
The value used by the driver is 'max(SG_SCATTER_SZ, PAGE_SIZE)'.
This value should be a power of 2 (and may be rounded up internally).
If scatter-gather is not supported by adapter then this value is the
largest data block that can be read/written by a single scsi command. */
#define SG_DEFAULT_RETRIES 0
/* Defaults, commented if they differ from original sg driver */
#define SG_DEF_FORCE_LOW_DMA 0 /* was 1 -> memory below 16MB on i386 */
#define SG_DEF_FORCE_PACK_ID 0
#define SG_DEF_KEEP_ORPHAN 0
#define SG_DEF_RESERVED_SIZE SG_SCATTER_SZ /* load time option */
/* maximum outstanding requests, write() yields EDOM if exceeded */
#define SG_MAX_QUEUE 16
#define SG_BIG_BUFF SG_DEF_RESERVED_SIZE /* for backward compatibility */
/* Alternate style type names, "..._t" variants preferred */
typedef struct sg_io_hdr Sg_io_hdr;
typedef struct sg_io_vec Sg_io_vec;
typedef struct sg_scsi_id Sg_scsi_id;
typedef struct sg_req_info Sg_req_info;
/* vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */
/* The older SG interface based on the 'sg_header' structure follows. */
/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
#define SG_MAX_SENSE 16 /* this only applies to the sg_header interface */
struct sg_header
{
int pack_len; /* [o] reply_len (ie useless), ignored as input */
int reply_len; /* [i] max length of expected reply (inc. sg_header) */
int pack_id; /* [io] id number of packet (use ints >= 0) */
int result; /* [o] 0==ok, else (+ve) Unix errno (best ignored) */
unsigned int twelve_byte:1;
/* [i] Force 12 byte command length for group 6 & 7 commands */
unsigned int target_status:5; /* [o] scsi status from target */
unsigned int host_status:8; /* [o] host status (see "DID" codes) */
unsigned int driver_status:8; /* [o] driver status+suggestion */
unsigned int other_flags:10; /* unused */
unsigned char sense_buffer[SG_MAX_SENSE]; /* [o] Output in 3 cases:
when target_status is CHECK_CONDITION or
when target_status is COMMAND_TERMINATED or
when (driver_status & DRIVER_SENSE) is true. */
}; /* This structure is 36 bytes long on i386 */
/* IOCTLs: The following are not required (or ignored) when the sg_io_hdr_t
interface is used. They are kept for backward compatibility with
the original and version 2 drivers. */
#define SG_SET_TIMEOUT 0x2201 /* unit: jiffies (10ms on i386) */
#define SG_GET_TIMEOUT 0x2202 /* yield timeout as _return_ value */
/* Get/set command queuing state per fd (default is SG_DEF_COMMAND_Q.
Each time a sg_io_hdr_t object is seen on this file descriptor, this
command queuing flag is set on (overriding the previous setting). */
#define SG_GET_COMMAND_Q 0x2270 /* Yields 0 (queuing off) or 1 (on) */
#define SG_SET_COMMAND_Q 0x2271 /* Change queuing state with 0 or 1 */
/* Turn on/off error sense trace (1 and 0 respectively, default is off).
Try using: "# cat /proc/scsi/sg/debug" instead in the v3 driver */
#define SG_SET_DEBUG 0x227e /* 0 -> turn off debug */
#define SG_NEXT_CMD_LEN 0x2283 /* override SCSI command length with given
number on the next write() on this file descriptor */
/* Defaults, commented if they differ from original sg driver */
#ifdef __KERNEL__
#define SG_DEFAULT_TIMEOUT_USER (60*USER_HZ) /* HZ == 'jiffies in 1 second' */
#else
#define SG_DEFAULT_TIMEOUT (60*HZ) /* HZ == 'jiffies in 1 second' */
#endif
#define SG_DEF_COMMAND_Q 0 /* command queuing is always on when
the new interface is used */
#define SG_DEF_UNDERRUN_FLAG 0
#endif

242
kernel/include/scsi/srp.h Normal file
View File

@@ -0,0 +1,242 @@
/*
* Copyright (c) 2005 Cisco Systems. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* $Id$
*/
#ifndef SCSI_SRP_H
#define SCSI_SRP_H
/*
* Structures and constants for the SCSI RDMA Protocol (SRP) as
* defined by the INCITS T10 committee. This file was written using
* draft Revision 16a of the SRP standard.
*/
#include <linux/types.h>
enum {
SRP_LOGIN_REQ = 0x00,
SRP_TSK_MGMT = 0x01,
SRP_CMD = 0x02,
SRP_I_LOGOUT = 0x03,
SRP_LOGIN_RSP = 0xc0,
SRP_RSP = 0xc1,
SRP_LOGIN_REJ = 0xc2,
SRP_T_LOGOUT = 0x80,
SRP_CRED_REQ = 0x81,
SRP_AER_REQ = 0x82,
SRP_CRED_RSP = 0x41,
SRP_AER_RSP = 0x42
};
enum {
SRP_BUF_FORMAT_DIRECT = 1 << 1,
SRP_BUF_FORMAT_INDIRECT = 1 << 2
};
enum {
SRP_NO_DATA_DESC = 0,
SRP_DATA_DESC_DIRECT = 1,
SRP_DATA_DESC_INDIRECT = 2
};
enum {
SRP_TSK_ABORT_TASK = 0x01,
SRP_TSK_ABORT_TASK_SET = 0x02,
SRP_TSK_CLEAR_TASK_SET = 0x04,
SRP_TSK_LUN_RESET = 0x08,
SRP_TSK_CLEAR_ACA = 0x40
};
enum srp_login_rej_reason {
SRP_LOGIN_REJ_UNABLE_ESTABLISH_CHANNEL = 0x00010000,
SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES = 0x00010001,
SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE = 0x00010002,
SRP_LOGIN_REJ_UNABLE_ASSOCIATE_CHANNEL = 0x00010003,
SRP_LOGIN_REJ_UNSUPPORTED_DESCRIPTOR_FMT = 0x00010004,
SRP_LOGIN_REJ_MULTI_CHANNEL_UNSUPPORTED = 0x00010005,
SRP_LOGIN_REJ_CHANNEL_LIMIT_REACHED = 0x00010006
};
enum {
SRP_REV10_IB_IO_CLASS = 0xff00,
SRP_REV16A_IB_IO_CLASS = 0x0100
};
struct srp_direct_buf {
__be64 va;
__be32 key;
__be32 len;
};
/*
* We need the packed attribute because the SRP spec puts the list of
* descriptors at an offset of 20, which is not aligned to the size of
* struct srp_direct_buf. The whole structure must be packed to avoid
* having the 20-byte structure padded to 24 bytes on 64-bit architectures.
*/
struct srp_indirect_buf {
struct srp_direct_buf table_desc;
__be32 len;
struct srp_direct_buf desc_list[0];
} __attribute__((packed));
enum {
SRP_MULTICHAN_SINGLE = 0,
SRP_MULTICHAN_MULTI = 1
};
struct srp_login_req {
u8 opcode;
u8 reserved1[7];
u64 tag;
__be32 req_it_iu_len;
u8 reserved2[4];
__be16 req_buf_fmt;
u8 req_flags;
u8 reserved3[5];
u8 initiator_port_id[16];
u8 target_port_id[16];
};
/*
* The SRP spec defines the size of the LOGIN_RSP structure to be 52
* bytes, so it needs to be packed to avoid having it padded to 56
* bytes on 64-bit architectures.
*/
struct srp_login_rsp {
u8 opcode;
u8 reserved1[3];
__be32 req_lim_delta;
u64 tag;
__be32 max_it_iu_len;
__be32 max_ti_iu_len;
__be16 buf_fmt;
u8 rsp_flags;
u8 reserved2[25];
} __attribute__((packed));
struct srp_login_rej {
u8 opcode;
u8 reserved1[3];
__be32 reason;
u64 tag;
u8 reserved2[8];
__be16 buf_fmt;
u8 reserved3[6];
};
struct srp_i_logout {
u8 opcode;
u8 reserved[7];
u64 tag;
};
struct srp_t_logout {
u8 opcode;
u8 sol_not;
u8 reserved[2];
__be32 reason;
u64 tag;
};
/*
* We need the packed attribute because the SRP spec only aligns the
* 8-byte LUN field to 4 bytes.
*/
struct srp_tsk_mgmt {
u8 opcode;
u8 sol_not;
u8 reserved1[6];
u64 tag;
u8 reserved2[4];
__be64 lun __attribute__((packed));
u8 reserved3[2];
u8 tsk_mgmt_func;
u8 reserved4;
u64 task_tag;
u8 reserved5[8];
};
/*
* We need the packed attribute because the SRP spec only aligns the
* 8-byte LUN field to 4 bytes.
*/
struct srp_cmd {
u8 opcode;
u8 sol_not;
u8 reserved1[3];
u8 buf_fmt;
u8 data_out_desc_cnt;
u8 data_in_desc_cnt;
u64 tag;
u8 reserved2[4];
__be64 lun __attribute__((packed));
u8 reserved3;
u8 task_attr;
u8 reserved4;
u8 add_cdb_len;
u8 cdb[16];
u8 add_data[0];
};
enum {
SRP_RSP_FLAG_RSPVALID = 1 << 0,
SRP_RSP_FLAG_SNSVALID = 1 << 1,
SRP_RSP_FLAG_DOOVER = 1 << 2,
SRP_RSP_FLAG_DOUNDER = 1 << 3,
SRP_RSP_FLAG_DIOVER = 1 << 4,
SRP_RSP_FLAG_DIUNDER = 1 << 5
};
/*
* The SRP spec defines the size of the RSP structure to be 36 bytes,
* so it needs to be packed to avoid having it padded to 40 bytes on
* 64-bit architectures.
*/
struct srp_rsp {
u8 opcode;
u8 sol_not;
u8 reserved1[2];
__be32 req_lim_delta;
u64 tag;
u8 reserved2[2];
u8 flags;
u8 status;
__be32 data_out_res_cnt;
__be32 data_in_res_cnt;
__be32 sense_data_len;
__be32 resp_data_len;
u8 data[0];
} __attribute__((packed));
#endif /* SCSI_SRP_H */