diff options
Diffstat (limited to 'kernel/include/scsi')
47 files changed, 15276 insertions, 0 deletions
diff --git a/kernel/include/scsi/fc/Kbuild b/kernel/include/scsi/fc/Kbuild new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/kernel/include/scsi/fc/Kbuild diff --git a/kernel/include/scsi/fc/fc_encaps.h b/kernel/include/scsi/fc/fc_encaps.h new file mode 100644 index 000000000..f180c3e16 --- /dev/null +++ b/kernel/include/scsi/fc/fc_encaps.h @@ -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_ */ diff --git a/kernel/include/scsi/fc/fc_fc2.h b/kernel/include/scsi/fc/fc_fc2.h new file mode 100644 index 000000000..0b2671431 --- /dev/null +++ b/kernel/include/scsi/fc/fc_fc2.h @@ -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 initiative */ +#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_ */ diff --git a/kernel/include/scsi/fc/fc_fcoe.h b/kernel/include/scsi/fc/fc_fcoe.h new file mode 100644 index 000000000..d5dcd6062 --- /dev/null +++ b/kernel/include/scsi/fc/fc_fcoe.h @@ -0,0 +1,108 @@ +/* + * 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. + * See T11 FC-BB-5 Rev 2.00 (09-056v5.pdf) + */ + +/* + * Default FC_FCOE_OUI / FC-MAP value. + */ +#define FC_FCOE_OUI 0x0efc00 /* upper 24 bits of FCOE MAC */ + +/* + * Fabric Login (FLOGI) MAC for non-FIP use. Non-FIP use is deprecated. + */ +#define FC_FCOE_FLOGI_MAC { 0x0e, 0xfc, 0x00, 0xff, 0xff, 0xfe } + +#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 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 + +/* + * FCoE Link Error Status Block: T11 FC-BB-5 Rev2.0, Clause 7.10. + */ +struct fcoe_fc_els_lesb { + __be32 lesb_link_fail; /* link failure count */ + __be32 lesb_vlink_fail; /* virtual link failure count */ + __be32 lesb_miss_fka; /* missing FIP keep-alive count */ + __be32 lesb_symb_err; /* symbol error during carrier count */ + __be32 lesb_err_block; /* errored block count */ + __be32 lesb_fcs_error; /* frame check sequence error count */ +}; + +/* + * 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_ */ diff --git a/kernel/include/scsi/fc/fc_fcp.h b/kernel/include/scsi/fc/fc_fcp.h new file mode 100644 index 000000000..9c8702942 --- /dev/null +++ b/kernel/include/scsi/fc/fc_fcp.h @@ -0,0 +1,216 @@ +/* + * 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_ + +#include <scsi/scsi.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 { + struct scsi_lun fc_lun; /* logical unit number */ + __u8 fc_cmdref; /* command 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 { + struct scsi_lun fc_lun; /* logical unit number */ + __u8 fc_cmdref; /* command 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. contingent allegiance */ +#define FCP_PTA_MASK 7 /* mask for task attribute field */ +#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_TGT_RESET 0x20 /* target reset task management, + deprecated as of FCP-3 */ +#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. + * + * From Table 23, the FCP_RSP_INFO can either be 4 bytes or 8 bytes, both + * are valid length. + */ +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 */ +}; + +#define FCP_RESP_RSP_INFO_LEN4 4 /* without reserved field */ +#define FCP_RESP_RSP_INFO_LEN8 8 /* with reserved field */ + +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 */ +}; + +/* + * Feature bits in name server FC-4 Features object. + */ +#define FCP_FEAT_TARG (1 << 0) /* target function supported */ +#define FCP_FEAT_INIT (1 << 1) /* initiator function supported */ + +#endif /* _FC_FCP_H_ */ diff --git a/kernel/include/scsi/fc/fc_fip.h b/kernel/include/scsi/fc/fc_fip.h new file mode 100644 index 000000000..ae25d4ab2 --- /dev/null +++ b/kernel/include/scsi/fc/fc_fip.h @@ -0,0 +1,280 @@ +/* + * 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_ + +#include <scsi/fc/fc_ns.h> + +/* + * This version is based on: + * http://www.t11.org/ftp/t11/pub/fc/bb-5/08-543v1.pdf + * and T11 FC-BB-6 10-019v4.pdf (June 2010 VN2VN proposal) + */ + +#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) */ + +/* + * VN2VN proposed-standard values. + */ +#define FIP_VN_FC_MAP 0x0efd00 /* MAC OUI for VN2VN use */ +#define FIP_VN_PROBE_WAIT 100 /* interval between VN2VN probes (ms) */ +#define FIP_VN_ANN_WAIT 400 /* interval between VN2VN announcements (ms) */ +#define FIP_VN_RLIM_INT 10000 /* interval between probes when rate limited */ +#define FIP_VN_RLIM_COUNT 10 /* number of probes before rate limiting */ +#define FIP_VN_BEACON_INT 8000 /* interval between VN2VN beacons */ +#define FIP_VN_BEACON_FUZZ 100 /* random time to add to beacon period (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_ALL_VN2VN_MACS ((__u8[6]) { 1, 0x10, 0x18, 1, 0, 4 }) +#define FIP_ALL_P2P_MACS ((__u8[6]) { 1, 0x10, 0x18, 1, 0, 5 }) + +#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_VN2VN = 5, /* VN2VN operation */ + 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 */ +}; + +/* + * Subcodes for FIP_OP_VN2VN. + */ +enum fip_vn2vn_subcode { + FIP_SC_VN_PROBE_REQ = 1, /* probe request */ + FIP_SC_VN_PROBE_REP = 2, /* probe reply */ + FIP_SC_VN_CLAIM_NOTIFY = 3, /* claim notification */ + FIP_SC_VN_CLAIM_REP = 4, /* claim response */ + FIP_SC_VN_BEACON = 5, /* beacon */ +}; + +/* + * 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_REC_OR_P2P = 0x0008, /* configured addr or point-to-point */ + 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_FC4F = 15, /* FC-4 features */ + 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; + __u8 fd_flags; /* bit0 is fka disable flag */ + __be32 fd_fka_period; /* adv./keep-alive period in mS */ +} __attribute__((packed)); + +/* + * flags for fip_fka_desc.fd_flags + */ +enum fip_fka_flags { + FIP_FKA_ADV_D = 0x01, /* no need for FKA from ENode */ +}; + +/* FIP_DT_FKA flags */ + +/* + * FIP_DT_FC4F - FC-4 features. + */ +struct fip_fc4_feat { + struct fip_desc fd_desc; + __u8 fd_resvd[2]; + struct fc_ns_fts fd_fts; + struct fc_ns_ff fd_ff; +} __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_ */ diff --git a/kernel/include/scsi/fc/fc_ms.h b/kernel/include/scsi/fc/fc_ms.h new file mode 100644 index 000000000..f52b921b5 --- /dev/null +++ b/kernel/include/scsi/fc/fc_ms.h @@ -0,0 +1,213 @@ +/* * Copyright(c) 2011 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_MS_H_ +#define _FC_MS_H_ + +#include <linux/types.h> + +/* + * Fibre Channel Services - Management Service (MS) + * From T11.org FC-GS-4 Rev 7.91 February 4, 2004 + */ + +/* + * Fabric Device Management Interface + */ + +/* + * Common-transport sub-type for FDMI + */ +#define FC_FDMI_SUBTYPE 0x10 /* fs_ct_hdr.ct_fs_subtype */ + +/* + * Management server FDMI Requests. + */ +enum fc_fdmi_req { + FC_FDMI_GRHL = 0x0100, /* Get Registered HBA List */ + FC_FDMI_GHAT = 0x0101, /* Get HBA Attributes */ + FC_FDMI_GRPL = 0x0102, /* Get Registered Port List */ + FC_FDMI_GPAT = 0x0110, /* Get Port Attributes */ + FC_FDMI_RHBA = 0x0200, /* Register HBA */ + FC_FDMI_RHAT = 0x0201, /* Register HBA Attributes */ + FC_FDMI_RPRT = 0x0210, /* Register Port */ + FC_FDMI_RPA = 0x0211, /* Register Port Attributes */ + FC_FDMI_DHBA = 0x0300, /* Deregister HBA */ + FC_FDMI_DHAT = 0x0301, /* Deregister HBA Attributes */ + FC_FDMI_DPRT = 0x0310, /* Deregister Port */ + FC_FDMI_DPA = 0x0311, /* Deregister Port Attributes */ +}; + +/* + * HBA Attribute Entry Type + */ +enum fc_fdmi_hba_attr_type { + FC_FDMI_HBA_ATTR_NODENAME = 0x0001, + FC_FDMI_HBA_ATTR_MANUFACTURER = 0x0002, + FC_FDMI_HBA_ATTR_SERIALNUMBER = 0x0003, + FC_FDMI_HBA_ATTR_MODEL = 0x0004, + FC_FDMI_HBA_ATTR_MODELDESCRIPTION = 0x0005, + FC_FDMI_HBA_ATTR_HARDWAREVERSION = 0x0006, + FC_FDMI_HBA_ATTR_DRIVERVERSION = 0x0007, + FC_FDMI_HBA_ATTR_OPTIONROMVERSION = 0x0008, + FC_FDMI_HBA_ATTR_FIRMWAREVERSION = 0x0009, + FC_FDMI_HBA_ATTR_OSNAMEVERSION = 0x000A, + FC_FDMI_HBA_ATTR_MAXCTPAYLOAD = 0x000B, +}; + +/* + * HBA Attribute Length + */ +#define FC_FDMI_HBA_ATTR_NODENAME_LEN 8 +#define FC_FDMI_HBA_ATTR_MANUFACTURER_LEN 64 +#define FC_FDMI_HBA_ATTR_SERIALNUMBER_LEN 64 +#define FC_FDMI_HBA_ATTR_MODEL_LEN 256 +#define FC_FDMI_HBA_ATTR_MODELDESCR_LEN 256 +#define FC_FDMI_HBA_ATTR_HARDWAREVERSION_LEN 256 +#define FC_FDMI_HBA_ATTR_DRIVERVERSION_LEN 256 +#define FC_FDMI_HBA_ATTR_OPTIONROMVERSION_LEN 256 +#define FC_FDMI_HBA_ATTR_FIRMWAREVERSION_LEN 256 +#define FC_FDMI_HBA_ATTR_OSNAMEVERSION_LEN 256 +#define FC_FDMI_HBA_ATTR_MAXCTPAYLOAD_LEN 4 + +/* + * Port Attribute Type + */ +enum fc_fdmi_port_attr_type { + FC_FDMI_PORT_ATTR_FC4TYPES = 0x0001, + FC_FDMI_PORT_ATTR_SUPPORTEDSPEED = 0x0002, + FC_FDMI_PORT_ATTR_CURRENTPORTSPEED = 0x0003, + FC_FDMI_PORT_ATTR_MAXFRAMESIZE = 0x0004, + FC_FDMI_PORT_ATTR_OSDEVICENAME = 0x0005, + FC_FDMI_PORT_ATTR_HOSTNAME = 0x0006, +}; + +/* + * Port Attribute Length + */ +#define FC_FDMI_PORT_ATTR_FC4TYPES_LEN 32 +#define FC_FDMI_PORT_ATTR_SUPPORTEDSPEED_LEN 4 +#define FC_FDMI_PORT_ATTR_CURRENTPORTSPEED_LEN 4 +#define FC_FDMI_PORT_ATTR_MAXFRAMESIZE_LEN 4 +#define FC_FDMI_PORT_ATTR_OSDEVICENAME_LEN 256 +#define FC_FDMI_PORT_ATTR_HOSTNAME_LEN 256 + +/* + * HBA Attribute ID + */ +struct fc_fdmi_hba_identifier { + __be64 id; +}; + +/* + * Port Name + */ +struct fc_fdmi_port_name { + __be64 portname; +}; + +/* + * Attribute Entry Block for HBA/Port Attributes + */ +#define FC_FDMI_ATTR_ENTRY_HEADER_LEN 4 +struct fc_fdmi_attr_entry { + __be16 type; + __be16 len; + __u8 value[1]; +} __attribute__((__packed__)); + +/* + * Common for HBA/Port Attributes + */ +struct fs_fdmi_attrs { + __be32 numattrs; + struct fc_fdmi_attr_entry attr[1]; +} __attribute__((__packed__)); + +/* + * Registered Port List + */ +struct fc_fdmi_rpl { + __be32 numport; + struct fc_fdmi_port_name port[1]; +} __attribute__((__packed__)); + +/* + * Register HBA (RHBA) + */ +struct fc_fdmi_rhba { + struct fc_fdmi_hba_identifier hbaid; + struct fc_fdmi_rpl port; + struct fs_fdmi_attrs hba_attrs; +} __attribute__((__packed__)); + +/* + * Register HBA Attributes (RHAT) + */ +struct fc_fdmi_rhat { + struct fc_fdmi_hba_identifier hbaid; + struct fs_fdmi_attrs hba_attrs; +} __attribute__((__packed__)); + +/* + * Register Port (RPRT) + */ +struct fc_fdmi_rprt { + struct fc_fdmi_hba_identifier hbaid; + struct fc_fdmi_port_name port; + struct fs_fdmi_attrs hba_attrs; +} __attribute__((__packed__)); + +/* + * Register Port Attributes (RPA) + */ +struct fc_fdmi_rpa { + struct fc_fdmi_port_name port; + struct fs_fdmi_attrs hba_attrs; +} __attribute__((__packed__)); + +/* + * Deregister Port (DPRT) + */ +struct fc_fdmi_dprt { + struct fc_fdmi_port_name port; +} __attribute__((__packed__)); + +/* + * Deregister Port Attributes (DPA) + */ +struct fc_fdmi_dpa { + struct fc_fdmi_port_name port; + struct fs_fdmi_attrs hba_attrs; +} __attribute__((__packed__)); + +/* + * Deregister HBA Attributes (DHAT) + */ +struct fc_fdmi_dhat { + struct fc_fdmi_hba_identifier hbaid; +} __attribute__((__packed__)); + +/* + * Deregister HBA (DHBA) + */ +struct fc_fdmi_dhba { + struct fc_fdmi_hba_identifier hbaid; +} __attribute__((__packed__)); + +#endif /* _FC_MS_H_ */ diff --git a/kernel/include/scsi/fc_encode.h b/kernel/include/scsi/fc_encode.h new file mode 100644 index 000000000..35fd4744f --- /dev/null +++ b/kernel/include/scsi/fc_encode.h @@ -0,0 +1,739 @@ +/* + * 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> +#include <linux/utsname.h> + +/* + * F_CTL values for simple requests and responses. + */ +#define FC_FCTL_REQ (FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT) +#define FC_FCTL_RESP (FC_FC_EX_CTX | FC_FC_LAST_SEQ | \ + FC_FC_END_SEQ | FC_FC_SEQ_INIT) + +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_rff_id rff; + struct fc_ns_fid fid; + struct fc_ns_rsnn snn; + struct fc_ns_rspn spn; + struct fc_fdmi_rhba rhba; + struct fc_fdmi_rpa rpa; + struct fc_fdmi_dprt dprt; + struct fc_fdmi_dhba dhba; + } payload; +}; + +static inline void __fc_fill_fc_hdr(struct fc_frame_header *fh, + enum fc_rctl r_ctl, + u32 did, u32 sid, enum fc_fh_type type, + u32 f_ctl, u32 parm_offset) +{ + 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); +} + +/** + * 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); + __fc_fill_fc_hdr(fh, r_ctl, did, sid, type, f_ctl, 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, lport->port_id); +} + +/** + * 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, + enum fc_ct_fs_type fs_type, + u8 subtype) +{ + 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 = fs_type; + ct->hdr.ct_fs_subtype = subtype; + ct->hdr.ct_cmd = htons((u16) op); + return ct; +} + +/** + * fc_ct_ns_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_ns_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; + size_t len; + + switch (op) { + case FC_NS_GPN_FT: + ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_gid_ft), + FC_FST_DIR, FC_NS_SUBTYPE); + 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), + FC_FST_DIR, FC_NS_SUBTYPE); + ct->payload.gid.fn_fc4_type = FC_TYPE_FCP; + 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), + FC_FST_DIR, FC_NS_SUBTYPE); + hton24(ct->payload.rft.fid.fp_fid, lport->port_id); + ct->payload.rft.fts = lport->fcts; + break; + + case FC_NS_RFF_ID: + ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rff_id), + FC_FST_DIR, FC_NS_SUBTYPE); + hton24(ct->payload.rff.fr_fid.fp_fid, lport->port_id); + ct->payload.rff.fr_type = FC_TYPE_FCP; + if (lport->service_params & FCP_SPPF_INIT_FCN) + ct->payload.rff.fr_feat = FCP_FEAT_INIT; + if (lport->service_params & FCP_SPPF_TARG_FCN) + ct->payload.rff.fr_feat |= FCP_FEAT_TARG; + break; + + case FC_NS_RNN_ID: + ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rn_id), + FC_FST_DIR, FC_NS_SUBTYPE); + hton24(ct->payload.rn.fr_fid.fp_fid, lport->port_id); + put_unaligned_be64(lport->wwnn, &ct->payload.rn.fr_wwn); + break; + + case FC_NS_RSPN_ID: + len = strnlen(fc_host_symbolic_name(lport->host), 255); + ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rspn) + len, + FC_FST_DIR, FC_NS_SUBTYPE); + hton24(ct->payload.spn.fr_fid.fp_fid, lport->port_id); + strncpy(ct->payload.spn.fr_name, + fc_host_symbolic_name(lport->host), len); + ct->payload.spn.fr_name_len = len; + break; + + case FC_NS_RSNN_NN: + len = strnlen(fc_host_symbolic_name(lport->host), 255); + ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rsnn) + len, + FC_FST_DIR, FC_NS_SUBTYPE); + put_unaligned_be64(lport->wwnn, &ct->payload.snn.fr_wwn); + strncpy(ct->payload.snn.fr_name, + fc_host_symbolic_name(lport->host), len); + ct->payload.snn.fr_name_len = len; + break; + + default: + return -EINVAL; + } + *r_ctl = FC_RCTL_DD_UNSOL_CTL; + *fh_type = FC_TYPE_CT; + return 0; +} + +/** + * fc_ct_ms_fill() - Fill in a mgmt 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_ms_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; + size_t len; + struct fc_fdmi_attr_entry *entry; + struct fs_fdmi_attrs *hba_attrs; + int numattrs = 0; + + switch (op) { + case FC_FDMI_RHBA: + numattrs = 10; + len = sizeof(struct fc_fdmi_rhba); + len -= sizeof(struct fc_fdmi_attr_entry); + len += (numattrs * FC_FDMI_ATTR_ENTRY_HEADER_LEN); + len += FC_FDMI_HBA_ATTR_NODENAME_LEN; + len += FC_FDMI_HBA_ATTR_MANUFACTURER_LEN; + len += FC_FDMI_HBA_ATTR_SERIALNUMBER_LEN; + len += FC_FDMI_HBA_ATTR_MODEL_LEN; + len += FC_FDMI_HBA_ATTR_MODELDESCR_LEN; + len += FC_FDMI_HBA_ATTR_HARDWAREVERSION_LEN; + len += FC_FDMI_HBA_ATTR_DRIVERVERSION_LEN; + len += FC_FDMI_HBA_ATTR_OPTIONROMVERSION_LEN; + len += FC_FDMI_HBA_ATTR_FIRMWAREVERSION_LEN; + len += FC_FDMI_HBA_ATTR_OSNAMEVERSION_LEN; + ct = fc_ct_hdr_fill(fp, op, len, FC_FST_MGMT, + FC_FDMI_SUBTYPE); + + /* HBA Identifier */ + put_unaligned_be64(lport->wwpn, &ct->payload.rhba.hbaid.id); + /* Number of Ports - always 1 */ + put_unaligned_be32(1, &ct->payload.rhba.port.numport); + /* Port Name */ + put_unaligned_be64(lport->wwpn, + &ct->payload.rhba.port.port[0].portname); + + /* HBA Attributes */ + put_unaligned_be32(numattrs, + &ct->payload.rhba.hba_attrs.numattrs); + hba_attrs = &ct->payload.rhba.hba_attrs; + entry = (struct fc_fdmi_attr_entry *)hba_attrs->attr; + /* NodeName*/ + len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; + len += FC_FDMI_HBA_ATTR_NODENAME_LEN; + put_unaligned_be16(FC_FDMI_HBA_ATTR_NODENAME, + &entry->type); + put_unaligned_be16(len, &entry->len); + put_unaligned_be64(lport->wwnn, + (__be64 *)&entry->value[0]); + + /* Manufacturer */ + entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + + FC_FDMI_HBA_ATTR_NODENAME_LEN); + len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; + len += FC_FDMI_HBA_ATTR_MANUFACTURER_LEN; + put_unaligned_be16(FC_FDMI_HBA_ATTR_MANUFACTURER, + &entry->type); + put_unaligned_be16(len, &entry->len); + strncpy((char *)&entry->value, + fc_host_manufacturer(lport->host), + FC_FDMI_HBA_ATTR_MANUFACTURER_LEN); + + /* SerialNumber */ + entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + + FC_FDMI_HBA_ATTR_MANUFACTURER_LEN); + len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; + len += FC_FDMI_HBA_ATTR_SERIALNUMBER_LEN; + put_unaligned_be16(FC_FDMI_HBA_ATTR_SERIALNUMBER, + &entry->type); + put_unaligned_be16(len, &entry->len); + strncpy((char *)&entry->value, + fc_host_serial_number(lport->host), + FC_FDMI_HBA_ATTR_SERIALNUMBER_LEN); + + /* Model */ + entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + + FC_FDMI_HBA_ATTR_SERIALNUMBER_LEN); + len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; + len += FC_FDMI_HBA_ATTR_MODEL_LEN; + put_unaligned_be16(FC_FDMI_HBA_ATTR_MODEL, + &entry->type); + put_unaligned_be16(len, &entry->len); + strncpy((char *)&entry->value, + fc_host_model(lport->host), + FC_FDMI_HBA_ATTR_MODEL_LEN); + + /* Model Description */ + entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + + FC_FDMI_HBA_ATTR_MODEL_LEN); + len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; + len += FC_FDMI_HBA_ATTR_MODELDESCR_LEN; + put_unaligned_be16(FC_FDMI_HBA_ATTR_MODELDESCRIPTION, + &entry->type); + put_unaligned_be16(len, &entry->len); + strncpy((char *)&entry->value, + fc_host_model_description(lport->host), + FC_FDMI_HBA_ATTR_MODELDESCR_LEN); + + /* Hardware Version */ + entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + + FC_FDMI_HBA_ATTR_MODELDESCR_LEN); + len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; + len += FC_FDMI_HBA_ATTR_HARDWAREVERSION_LEN; + put_unaligned_be16(FC_FDMI_HBA_ATTR_HARDWAREVERSION, + &entry->type); + put_unaligned_be16(len, &entry->len); + strncpy((char *)&entry->value, + fc_host_hardware_version(lport->host), + FC_FDMI_HBA_ATTR_HARDWAREVERSION_LEN); + + /* Driver Version */ + entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + + FC_FDMI_HBA_ATTR_HARDWAREVERSION_LEN); + len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; + len += FC_FDMI_HBA_ATTR_DRIVERVERSION_LEN; + put_unaligned_be16(FC_FDMI_HBA_ATTR_DRIVERVERSION, + &entry->type); + put_unaligned_be16(len, &entry->len); + strncpy((char *)&entry->value, + fc_host_driver_version(lport->host), + FC_FDMI_HBA_ATTR_DRIVERVERSION_LEN); + + /* OptionROM Version */ + entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + + FC_FDMI_HBA_ATTR_DRIVERVERSION_LEN); + len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; + len += FC_FDMI_HBA_ATTR_OPTIONROMVERSION_LEN; + put_unaligned_be16(FC_FDMI_HBA_ATTR_OPTIONROMVERSION, + &entry->type); + put_unaligned_be16(len, &entry->len); + strncpy((char *)&entry->value, + fc_host_optionrom_version(lport->host), + FC_FDMI_HBA_ATTR_OPTIONROMVERSION_LEN); + + /* Firmware Version */ + entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + + FC_FDMI_HBA_ATTR_OPTIONROMVERSION_LEN); + len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; + len += FC_FDMI_HBA_ATTR_FIRMWAREVERSION_LEN; + put_unaligned_be16(FC_FDMI_HBA_ATTR_FIRMWAREVERSION, + &entry->type); + put_unaligned_be16(len, &entry->len); + strncpy((char *)&entry->value, + fc_host_firmware_version(lport->host), + FC_FDMI_HBA_ATTR_FIRMWAREVERSION_LEN); + + /* OS Name and Version */ + entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + + FC_FDMI_HBA_ATTR_FIRMWAREVERSION_LEN); + len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; + len += FC_FDMI_HBA_ATTR_OSNAMEVERSION_LEN; + put_unaligned_be16(FC_FDMI_HBA_ATTR_OSNAMEVERSION, + &entry->type); + put_unaligned_be16(len, &entry->len); + snprintf((char *)&entry->value, + FC_FDMI_HBA_ATTR_OSNAMEVERSION_LEN, + "%s v%s", + init_utsname()->sysname, + init_utsname()->release); + break; + case FC_FDMI_RPA: + numattrs = 6; + len = sizeof(struct fc_fdmi_rpa); + len -= sizeof(struct fc_fdmi_attr_entry); + len += (numattrs * FC_FDMI_ATTR_ENTRY_HEADER_LEN); + len += FC_FDMI_PORT_ATTR_FC4TYPES_LEN; + len += FC_FDMI_PORT_ATTR_SUPPORTEDSPEED_LEN; + len += FC_FDMI_PORT_ATTR_CURRENTPORTSPEED_LEN; + len += FC_FDMI_PORT_ATTR_MAXFRAMESIZE_LEN; + len += FC_FDMI_PORT_ATTR_OSDEVICENAME_LEN; + len += FC_FDMI_PORT_ATTR_HOSTNAME_LEN; + ct = fc_ct_hdr_fill(fp, op, len, FC_FST_MGMT, + FC_FDMI_SUBTYPE); + + /* Port Name */ + put_unaligned_be64(lport->wwpn, + &ct->payload.rpa.port.portname); + + /* Port Attributes */ + put_unaligned_be32(numattrs, + &ct->payload.rpa.hba_attrs.numattrs); + + hba_attrs = &ct->payload.rpa.hba_attrs; + entry = (struct fc_fdmi_attr_entry *)hba_attrs->attr; + + /* FC4 types */ + len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; + len += FC_FDMI_PORT_ATTR_FC4TYPES_LEN; + put_unaligned_be16(FC_FDMI_PORT_ATTR_FC4TYPES, + &entry->type); + put_unaligned_be16(len, &entry->len); + memcpy(&entry->value, fc_host_supported_fc4s(lport->host), + FC_FDMI_PORT_ATTR_FC4TYPES_LEN); + + /* Supported Speed */ + entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + + FC_FDMI_PORT_ATTR_FC4TYPES_LEN); + len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; + len += FC_FDMI_PORT_ATTR_SUPPORTEDSPEED_LEN; + put_unaligned_be16(FC_FDMI_PORT_ATTR_SUPPORTEDSPEED, + &entry->type); + put_unaligned_be16(len, &entry->len); + + put_unaligned_be32(fc_host_supported_speeds(lport->host), + &entry->value); + + /* Current Port Speed */ + entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + + FC_FDMI_PORT_ATTR_SUPPORTEDSPEED_LEN); + len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; + len += FC_FDMI_PORT_ATTR_CURRENTPORTSPEED_LEN; + put_unaligned_be16(FC_FDMI_PORT_ATTR_CURRENTPORTSPEED, + &entry->type); + put_unaligned_be16(len, &entry->len); + put_unaligned_be32(lport->link_speed, + &entry->value); + + /* Max Frame Size */ + entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + + FC_FDMI_PORT_ATTR_CURRENTPORTSPEED_LEN); + len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; + len += FC_FDMI_PORT_ATTR_MAXFRAMESIZE_LEN; + put_unaligned_be16(FC_FDMI_PORT_ATTR_MAXFRAMESIZE, + &entry->type); + put_unaligned_be16(len, &entry->len); + put_unaligned_be32(fc_host_maxframe_size(lport->host), + &entry->value); + + /* OS Device Name */ + entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + + FC_FDMI_PORT_ATTR_MAXFRAMESIZE_LEN); + len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; + len += FC_FDMI_PORT_ATTR_OSDEVICENAME_LEN; + put_unaligned_be16(FC_FDMI_PORT_ATTR_OSDEVICENAME, + &entry->type); + put_unaligned_be16(len, &entry->len); + /* Use the sysfs device name */ + strncpy((char *)&entry->value, + dev_name(&lport->host->shost_gendev), + strnlen(dev_name(&lport->host->shost_gendev), + FC_FDMI_PORT_ATTR_HOSTNAME_LEN)); + + /* Host Name */ + entry = (struct fc_fdmi_attr_entry *)((char *)entry->value + + FC_FDMI_PORT_ATTR_OSDEVICENAME_LEN); + len = FC_FDMI_ATTR_ENTRY_HEADER_LEN; + len += FC_FDMI_PORT_ATTR_HOSTNAME_LEN; + put_unaligned_be16(FC_FDMI_PORT_ATTR_HOSTNAME, + &entry->type); + put_unaligned_be16(len, &entry->len); + if (strlen(fc_host_system_hostname(lport->host))) + strncpy((char *)&entry->value, + fc_host_system_hostname(lport->host), + strnlen(fc_host_system_hostname(lport->host), + FC_FDMI_PORT_ATTR_HOSTNAME_LEN)); + else + strncpy((char *)&entry->value, + init_utsname()->nodename, + FC_FDMI_PORT_ATTR_HOSTNAME_LEN); + break; + case FC_FDMI_DPRT: + len = sizeof(struct fc_fdmi_dprt); + ct = fc_ct_hdr_fill(fp, op, len, FC_FST_MGMT, + FC_FDMI_SUBTYPE); + /* Port Name */ + put_unaligned_be64(lport->wwpn, + &ct->payload.dprt.port.portname); + break; + case FC_FDMI_DHBA: + len = sizeof(struct fc_fdmi_dhba); + ct = fc_ct_hdr_fill(fp, op, len, FC_FST_MGMT, + FC_FDMI_SUBTYPE); + /* HBA Identifier */ + put_unaligned_be64(lport->wwpn, &ct->payload.dhba.hbaid.id); + break; + default: + return -EINVAL; + } + *r_ctl = FC_RCTL_DD_UNSOL_CTL; + *fh_type = FC_TYPE_CT; + return 0; +} + +/** + * fc_ct_fill() - Fill in a common transport 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, u32 *did) +{ + int rc = -EINVAL; + + switch (fc_id) { + case FC_FID_MGMT_SERV: + rc = fc_ct_ms_fill(lport, fc_id, fp, op, r_ctl, fh_type); + *did = FC_FID_MGMT_SERV; + break; + case FC_FID_DIR_SERV: + default: + rc = fc_ct_ns_fill(lport, fc_id, fp, op, r_ctl, fh_type); + *did = FC_FID_DIR_SERV; + break; + } + + return rc; +} +/** + * 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); + if (lport->does_npiv) + sp->sp_features = htons(FC_SP_FT_NPIV); +} + +/** + * fc_fdisc_fill - Fill in a fdisc request frame. + */ +static inline void fc_fdisc_fill(struct fc_lport *lport, struct fc_frame *fp) +{ + struct fc_els_csp *sp; + struct fc_els_cssp *cp; + struct fc_els_flogi *fdisc; + + fdisc = fc_frame_payload_get(fp, sizeof(*fdisc)); + memset(fdisc, 0, sizeof(*fdisc)); + fdisc->fl_cmd = (u8) ELS_FDISC; + put_unaligned_be64(lport->wwpn, &fdisc->fl_wwpn); + put_unaligned_be64(lport->wwnn, &fdisc->fl_wwnn); + sp = &fdisc->fl_csp; + sp->sp_hi_ver = 0x20; + sp->sp_lo_ver = 0x20; + sp->sp_bb_cred = htons(10); /* this gets set by gateway */ + sp->sp_bb_data = htons((u16) lport->mfs); + cp = &fdisc->fl_cssp[3 - 1]; /* class 3 parameters */ + cp->cp_class = htons(FC_CPC_VALID | FC_CPC_SEQ); +} + +/** + * 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, lport->port_id); + 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, lport->port_id); + 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_FDISC: + fc_fdisc_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_ */ diff --git a/kernel/include/scsi/fc_frame.h b/kernel/include/scsi/fc_frame.h new file mode 100644 index 000000000..8225d8063 --- /dev/null +++ b/kernel/include/scsi/fc_frame.h @@ -0,0 +1,261 @@ +/* + * 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> + +#include <linux/if_ether.h> + +/* some helpful macros */ + +#define ntohll(x) be64_to_cpu(x) +#define htonll(x) cpu_to_be64(x) + +static inline u32 ntoh24(const u8 *p) +{ + return (p[0] << 16) | (p[1] << 8) | p[2]; +} + +static inline void hton24(u8 *p, u32 v) +{ + p[0] = (v >> 16) & 0xff; + p[1] = (v >> 8) & 0xff; + p[2] = v & 0xff; +} + +/* + * 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_encaps(fp) (fr_cb(fp)->fr_encaps) +#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 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 */ + u8 fr_sof; /* start of frame delimiter */ + u8 fr_eof; /* end of frame delimiter */ + u8 fr_flags; /* flags - see below */ + u8 fr_encaps; /* LLD encapsulation info (e.g. FIP) */ + u8 granted_mac[ETH_ALEN]; /* FCoE MAC address */ +}; + + +/* + * 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; + fr_encaps(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); + +/* + * 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 && len % 4) + fp = fc_frame_alloc_fill(dev, len); + else + fp = _fc_frame_alloc(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 version doesn't do a length check. + */ +static inline +struct fc_frame_header *__fc_frame_header_get(const struct fc_frame *fp) +{ + return (struct fc_frame_header *)fr_hdr(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 __fc_frame_header_get(fp); +} + +/* + * Get source FC_ID (S_ID) from frame header in message. + */ +static inline u32 fc_frame_sid(const struct fc_frame *fp) +{ + return ntoh24(__fc_frame_header_get(fp)->fh_s_id); +} + +/* + * Get destination FC_ID (D_ID) from frame header in message. + */ +static inline u32 fc_frame_did(const struct fc_frame *fp) +{ + return ntoh24(__fc_frame_header_get(fp)->fh_d_id); +} + +/* + * 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_ */ diff --git a/kernel/include/scsi/fcoe_sysfs.h b/kernel/include/scsi/fcoe_sysfs.h new file mode 100644 index 000000000..7e2314870 --- /dev/null +++ b/kernel/include/scsi/fcoe_sysfs.h @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2011-2012 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 FCOE_SYSFS +#define FCOE_SYSFS + +#include <linux/if_ether.h> +#include <linux/device.h> +#include <scsi/fc/fc_fcoe.h> + +struct fcoe_ctlr_device; +struct fcoe_fcf_device; + +struct fcoe_sysfs_function_template { + void (*get_fcoe_ctlr_link_fail)(struct fcoe_ctlr_device *); + void (*get_fcoe_ctlr_vlink_fail)(struct fcoe_ctlr_device *); + void (*get_fcoe_ctlr_miss_fka)(struct fcoe_ctlr_device *); + void (*get_fcoe_ctlr_symb_err)(struct fcoe_ctlr_device *); + void (*get_fcoe_ctlr_err_block)(struct fcoe_ctlr_device *); + void (*get_fcoe_ctlr_fcs_error)(struct fcoe_ctlr_device *); + void (*set_fcoe_ctlr_mode)(struct fcoe_ctlr_device *); + int (*set_fcoe_ctlr_enabled)(struct fcoe_ctlr_device *); + void (*get_fcoe_fcf_selected)(struct fcoe_fcf_device *); + void (*get_fcoe_fcf_vlan_id)(struct fcoe_fcf_device *); +}; + +#define dev_to_ctlr(d) \ + container_of((d), struct fcoe_ctlr_device, dev) + +enum fip_conn_type { + FIP_CONN_TYPE_UNKNOWN, + FIP_CONN_TYPE_FABRIC, + FIP_CONN_TYPE_VN2VN, +}; + +enum ctlr_enabled_state { + FCOE_CTLR_ENABLED, + FCOE_CTLR_DISABLED, + FCOE_CTLR_UNUSED, +}; + +struct fcoe_ctlr_device { + u32 id; + + struct device dev; + struct fcoe_sysfs_function_template *f; + + struct list_head fcfs; + char work_q_name[20]; + struct workqueue_struct *work_q; + char devloss_work_q_name[20]; + struct workqueue_struct *devloss_work_q; + struct mutex lock; + + int fcf_dev_loss_tmo; + enum fip_conn_type mode; + + enum ctlr_enabled_state enabled; + + /* expected in host order for displaying */ + struct fcoe_fc_els_lesb lesb; +}; + +static inline void *fcoe_ctlr_device_priv(const struct fcoe_ctlr_device *ctlr) +{ + return (void *)(ctlr + 1); +} + +/* fcf states */ +enum fcf_state { + FCOE_FCF_STATE_UNKNOWN, + FCOE_FCF_STATE_DISCONNECTED, + FCOE_FCF_STATE_CONNECTED, + FCOE_FCF_STATE_DELETED, +}; + +struct fcoe_fcf_device { + u32 id; + struct device dev; + struct list_head peers; + struct work_struct delete_work; + struct delayed_work dev_loss_work; + u32 dev_loss_tmo; + void *priv; + enum fcf_state state; + + u64 fabric_name; + u64 switch_name; + u32 fc_map; + u16 vfid; + u8 mac[ETH_ALEN]; + u8 priority; + u32 fka_period; + u8 selected; + u16 vlan_id; +}; + +#define dev_to_fcf(d) \ + container_of((d), struct fcoe_fcf_device, dev) +/* parentage should never be missing */ +#define fcoe_fcf_dev_to_ctlr_dev(x) \ + dev_to_ctlr((x)->dev.parent) +#define fcoe_fcf_device_priv(x) \ + ((x)->priv) + +struct fcoe_ctlr_device *fcoe_ctlr_device_add(struct device *parent, + struct fcoe_sysfs_function_template *f, + int priv_size); +void fcoe_ctlr_device_delete(struct fcoe_ctlr_device *); +struct fcoe_fcf_device *fcoe_fcf_device_add(struct fcoe_ctlr_device *, + struct fcoe_fcf_device *); +void fcoe_fcf_device_delete(struct fcoe_fcf_device *); + +int __init fcoe_sysfs_setup(void); +void __exit fcoe_sysfs_teardown(void); + +#endif /* FCOE_SYSFS */ diff --git a/kernel/include/scsi/iscsi_if.h b/kernel/include/scsi/iscsi_if.h new file mode 100644 index 000000000..95ed9424a --- /dev/null +++ b/kernel/include/scsi/iscsi_if.h @@ -0,0 +1,962 @@ +/* + * 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, + ISCSI_UEVENT_SET_IFACE_PARAMS = UEVENT_BASE + 21, + ISCSI_UEVENT_PING = UEVENT_BASE + 22, + ISCSI_UEVENT_GET_CHAP = UEVENT_BASE + 23, + ISCSI_UEVENT_DELETE_CHAP = UEVENT_BASE + 24, + ISCSI_UEVENT_SET_FLASHNODE_PARAMS = UEVENT_BASE + 25, + ISCSI_UEVENT_NEW_FLASHNODE = UEVENT_BASE + 26, + ISCSI_UEVENT_DEL_FLASHNODE = UEVENT_BASE + 27, + ISCSI_UEVENT_LOGIN_FLASHNODE = UEVENT_BASE + 28, + ISCSI_UEVENT_LOGOUT_FLASHNODE = UEVENT_BASE + 29, + ISCSI_UEVENT_LOGOUT_FLASHNODE_SID = UEVENT_BASE + 30, + ISCSI_UEVENT_SET_CHAP = UEVENT_BASE + 31, + ISCSI_UEVENT_GET_HOST_STATS = UEVENT_BASE + 32, + + /* 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, + ISCSI_KEVENT_CONN_LOGIN_STATE = KEVENT_BASE + 9, + ISCSI_KEVENT_HOST_EVENT = KEVENT_BASE + 10, + ISCSI_KEVENT_PING_COMP = KEVENT_BASE + 11, +}; + +enum iscsi_tgt_dscvr { + ISCSI_TGT_DSCVR_SEND_TARGETS = 1, + ISCSI_TGT_DSCVR_ISNS = 2, + ISCSI_TGT_DSCVR_SLP = 3, +}; + +enum iscsi_host_event_code { + ISCSI_EVENT_LINKUP = 1, + ISCSI_EVENT_LINKDOWN, + /* must always be last */ + ISCSI_EVENT_MAX, +}; + +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; + struct msg_set_iface_params { + uint32_t host_no; + uint32_t count; + } set_iface_params; + struct msg_iscsi_ping { + uint32_t host_no; + uint32_t iface_num; + uint32_t iface_type; + uint32_t payload_size; + uint32_t pid; /* unique ping id associated + with each ping request */ + } iscsi_ping; + struct msg_get_chap { + uint32_t host_no; + uint32_t num_entries; /* number of CHAP entries + * on request, number of + * valid CHAP entries on + * response */ + uint16_t chap_tbl_idx; + } get_chap; + struct msg_delete_chap { + uint32_t host_no; + uint16_t chap_tbl_idx; + } delete_chap; + struct msg_set_flashnode_param { + uint32_t host_no; + uint32_t flashnode_idx; + uint32_t count; + } set_flashnode; + struct msg_new_flashnode { + uint32_t host_no; + uint32_t len; + } new_flashnode; + struct msg_del_flashnode { + uint32_t host_no; + uint32_t flashnode_idx; + } del_flashnode; + struct msg_login_flashnode { + uint32_t host_no; + uint32_t flashnode_idx; + } login_flashnode; + struct msg_logout_flashnode { + uint32_t host_no; + uint32_t flashnode_idx; + } logout_flashnode; + struct msg_logout_flashnode_sid { + uint32_t host_no; + uint32_t sid; + } logout_flashnode_sid; + struct msg_get_host_stats { + uint32_t host_no; + } get_host_stats; + } 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_login { + uint32_t sid; + uint32_t cid; + uint32_t state; /* enum iscsi_conn_state */ + } conn_login; + 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; + struct msg_host_event { + uint32_t host_no; + uint32_t data_size; + enum iscsi_host_event_code code; + } host_event; + struct msg_ping_comp { + uint32_t host_no; + uint32_t status; /* enum + * iscsi_ping_status_code */ + uint32_t pid; /* unique ping id associated + with each ping request */ + uint32_t data_size; + } ping_comp; + struct msg_new_flashnode_ret { + uint32_t flashnode_idx; + } new_flashnode_ret; + } r; +} __attribute__ ((aligned (sizeof(uint64_t)))); + +enum iscsi_param_type { + ISCSI_PARAM, /* iscsi_param (session, conn, target, LU) */ + ISCSI_HOST_PARAM, /* iscsi_host_param */ + ISCSI_NET_PARAM, /* iscsi_net_param */ + ISCSI_FLASHNODE_PARAM, /* iscsi_flashnode_param */ + ISCSI_CHAP_PARAM, /* iscsi_chap_param */ + ISCSI_IFACE_PARAM, /* iscsi_iface_param */ +}; + +/* structure for minimalist usecase */ +struct iscsi_param_info { + uint32_t len; /* Actual length of the param value */ + uint16_t param; /* iscsi param */ + uint8_t value[0]; /* length sized value follows */ +} __packed; + +struct iscsi_iface_param_info { + uint32_t iface_num; /* iface number, 0 - n */ + uint32_t len; /* Actual length of the param */ + uint16_t param; /* iscsi param value */ + uint8_t iface_type; /* IPv4 or IPv6 */ + uint8_t param_type; /* iscsi_param_type */ + uint8_t value[0]; /* length sized value follows */ +} __packed; + +/* + * 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)))); + +/* iscsi iface enabled/disabled setting */ +#define ISCSI_IFACE_DISABLE 0x01 +#define ISCSI_IFACE_ENABLE 0x02 + +/* ipv4 bootproto */ +#define ISCSI_BOOTPROTO_STATIC 0x01 +#define ISCSI_BOOTPROTO_DHCP 0x02 + +/* ipv6 addr autoconfig type */ +#define ISCSI_IPV6_AUTOCFG_DISABLE 0x01 +#define ISCSI_IPV6_AUTOCFG_ND_ENABLE 0x02 +#define ISCSI_IPV6_AUTOCFG_DHCPV6_ENABLE 0x03 + +/* ipv6 link local addr type */ +#define ISCSI_IPV6_LINKLOCAL_AUTOCFG_ENABLE 0x01 +#define ISCSI_IPV6_LINKLOCAL_AUTOCFG_DISABLE 0x02 + +/* ipv6 router addr type */ +#define ISCSI_IPV6_ROUTER_AUTOCFG_ENABLE 0x01 +#define ISCSI_IPV6_ROUTER_AUTOCFG_DISABLE 0x02 + +#define ISCSI_IFACE_TYPE_IPV4 0x01 +#define ISCSI_IFACE_TYPE_IPV6 0x02 + +#define ISCSI_MAX_VLAN_ID 4095 +#define ISCSI_MAX_VLAN_PRIORITY 7 + +/* iscsi vlan enable/disabled setting */ +#define ISCSI_VLAN_DISABLE 0x01 +#define ISCSI_VLAN_ENABLE 0x02 + +/* iscsi generic enable/disabled setting for various features */ +#define ISCSI_NET_PARAM_DISABLE 0x01 +#define ISCSI_NET_PARAM_ENABLE 0x02 + +/* iSCSI network params */ +enum iscsi_net_param { + ISCSI_NET_PARAM_IPV4_ADDR = 1, + ISCSI_NET_PARAM_IPV4_SUBNET, + ISCSI_NET_PARAM_IPV4_GW, + ISCSI_NET_PARAM_IPV4_BOOTPROTO, + ISCSI_NET_PARAM_MAC, + ISCSI_NET_PARAM_IPV6_LINKLOCAL, + ISCSI_NET_PARAM_IPV6_ADDR, + ISCSI_NET_PARAM_IPV6_ROUTER, + ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG, + ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG, + ISCSI_NET_PARAM_IPV6_ROUTER_AUTOCFG, + ISCSI_NET_PARAM_IFACE_ENABLE, + ISCSI_NET_PARAM_VLAN_ID, + ISCSI_NET_PARAM_VLAN_PRIORITY, + ISCSI_NET_PARAM_VLAN_ENABLED, + ISCSI_NET_PARAM_VLAN_TAG, + ISCSI_NET_PARAM_IFACE_TYPE, + ISCSI_NET_PARAM_IFACE_NAME, + ISCSI_NET_PARAM_MTU, + ISCSI_NET_PARAM_PORT, + ISCSI_NET_PARAM_IPADDR_STATE, + ISCSI_NET_PARAM_IPV6_LINKLOCAL_STATE, + ISCSI_NET_PARAM_IPV6_ROUTER_STATE, + ISCSI_NET_PARAM_DELAYED_ACK_EN, + ISCSI_NET_PARAM_TCP_NAGLE_DISABLE, + ISCSI_NET_PARAM_TCP_WSF_DISABLE, + ISCSI_NET_PARAM_TCP_WSF, + ISCSI_NET_PARAM_TCP_TIMER_SCALE, + ISCSI_NET_PARAM_TCP_TIMESTAMP_EN, + ISCSI_NET_PARAM_CACHE_ID, + ISCSI_NET_PARAM_IPV4_DHCP_DNS_ADDR_EN, + ISCSI_NET_PARAM_IPV4_DHCP_SLP_DA_EN, + ISCSI_NET_PARAM_IPV4_TOS_EN, + ISCSI_NET_PARAM_IPV4_TOS, + ISCSI_NET_PARAM_IPV4_GRAT_ARP_EN, + ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID_EN, + ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID, + ISCSI_NET_PARAM_IPV4_DHCP_REQ_VENDOR_ID_EN, + ISCSI_NET_PARAM_IPV4_DHCP_USE_VENDOR_ID_EN, + ISCSI_NET_PARAM_IPV4_DHCP_VENDOR_ID, + ISCSI_NET_PARAM_IPV4_DHCP_LEARN_IQN_EN, + ISCSI_NET_PARAM_IPV4_FRAGMENT_DISABLE, + ISCSI_NET_PARAM_IPV4_IN_FORWARD_EN, + ISCSI_NET_PARAM_IPV4_TTL, + ISCSI_NET_PARAM_IPV6_GRAT_NEIGHBOR_ADV_EN, + ISCSI_NET_PARAM_IPV6_MLD_EN, + ISCSI_NET_PARAM_IPV6_FLOW_LABEL, + ISCSI_NET_PARAM_IPV6_TRAFFIC_CLASS, + ISCSI_NET_PARAM_IPV6_HOP_LIMIT, + ISCSI_NET_PARAM_IPV6_ND_REACHABLE_TMO, + ISCSI_NET_PARAM_IPV6_ND_REXMIT_TIME, + ISCSI_NET_PARAM_IPV6_ND_STALE_TMO, + ISCSI_NET_PARAM_IPV6_DUP_ADDR_DETECT_CNT, + ISCSI_NET_PARAM_IPV6_RTR_ADV_LINK_MTU, + ISCSI_NET_PARAM_REDIRECT_EN, +}; + +enum iscsi_ipaddress_state { + ISCSI_IPDDRESS_STATE_UNCONFIGURED, + ISCSI_IPDDRESS_STATE_ACQUIRING, + ISCSI_IPDDRESS_STATE_TENTATIVE, + ISCSI_IPDDRESS_STATE_VALID, + ISCSI_IPDDRESS_STATE_DISABLING, + ISCSI_IPDDRESS_STATE_INVALID, + ISCSI_IPDDRESS_STATE_DEPRECATED, +}; + +enum iscsi_router_state { + ISCSI_ROUTER_STATE_UNKNOWN, + ISCSI_ROUTER_STATE_ADVERTISED, + ISCSI_ROUTER_STATE_MANUAL, + ISCSI_ROUTER_STATE_STALE, +}; + +/* iSCSI specific settings params for iface */ +enum iscsi_iface_param { + ISCSI_IFACE_PARAM_DEF_TASKMGMT_TMO, + ISCSI_IFACE_PARAM_HDRDGST_EN, + ISCSI_IFACE_PARAM_DATADGST_EN, + ISCSI_IFACE_PARAM_IMM_DATA_EN, + ISCSI_IFACE_PARAM_INITIAL_R2T_EN, + ISCSI_IFACE_PARAM_DATASEQ_INORDER_EN, + ISCSI_IFACE_PARAM_PDU_INORDER_EN, + ISCSI_IFACE_PARAM_ERL, + ISCSI_IFACE_PARAM_MAX_RECV_DLENGTH, + ISCSI_IFACE_PARAM_FIRST_BURST, + ISCSI_IFACE_PARAM_MAX_R2T, + ISCSI_IFACE_PARAM_MAX_BURST, + ISCSI_IFACE_PARAM_CHAP_AUTH_EN, + ISCSI_IFACE_PARAM_BIDI_CHAP_EN, + ISCSI_IFACE_PARAM_DISCOVERY_AUTH_OPTIONAL, + ISCSI_IFACE_PARAM_DISCOVERY_LOGOUT_EN, + ISCSI_IFACE_PARAM_STRICT_LOGIN_COMP_EN, + ISCSI_IFACE_PARAM_INITIATOR_NAME, +}; + +enum iscsi_conn_state { + ISCSI_CONN_STATE_FREE, + ISCSI_CONN_STATE_XPT_WAIT, + ISCSI_CONN_STATE_IN_LOGIN, + ISCSI_CONN_STATE_LOGGED_IN, + ISCSI_CONN_STATE_IN_LOGOUT, + ISCSI_CONN_STATE_LOGOUT_REQUESTED, + ISCSI_CONN_STATE_CLEANUP_WAIT, +}; + +/* + * 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_ERR_SCSI_EH_SESSION_RST = ISCSI_ERR_BASE + 21, + ISCSI_ERR_NOP_TIMEDOUT = ISCSI_ERR_BASE + 22, +}; + +/* + * 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, + + /* passed 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, + + ISCSI_PARAM_TGT_RESET_TMO, + ISCSI_PARAM_TARGET_ALIAS, + + ISCSI_PARAM_CHAP_IN_IDX, + ISCSI_PARAM_CHAP_OUT_IDX, + + ISCSI_PARAM_BOOT_ROOT, + ISCSI_PARAM_BOOT_NIC, + ISCSI_PARAM_BOOT_TARGET, + + ISCSI_PARAM_AUTO_SND_TGT_DISABLE, + ISCSI_PARAM_DISCOVERY_SESS, + ISCSI_PARAM_PORTAL_TYPE, + ISCSI_PARAM_CHAP_AUTH_EN, + ISCSI_PARAM_DISCOVERY_LOGOUT_EN, + ISCSI_PARAM_BIDI_CHAP_EN, + ISCSI_PARAM_DISCOVERY_AUTH_OPTIONAL, + + ISCSI_PARAM_DEF_TIME2WAIT, + ISCSI_PARAM_DEF_TIME2RETAIN, + ISCSI_PARAM_MAX_SEGMENT_SIZE, + ISCSI_PARAM_STATSN, + ISCSI_PARAM_KEEPALIVE_TMO, + ISCSI_PARAM_LOCAL_PORT, + ISCSI_PARAM_TSID, + ISCSI_PARAM_DEF_TASKMGMT_TMO, + + ISCSI_PARAM_TCP_TIMESTAMP_STAT, + ISCSI_PARAM_TCP_WSF_DISABLE, + ISCSI_PARAM_TCP_NAGLE_DISABLE, + ISCSI_PARAM_TCP_TIMER_SCALE, + ISCSI_PARAM_TCP_TIMESTAMP_EN, + ISCSI_PARAM_TCP_XMIT_WSF, + ISCSI_PARAM_TCP_RECV_WSF, + ISCSI_PARAM_IP_FRAGMENT_DISABLE, + ISCSI_PARAM_IPV4_TOS, + ISCSI_PARAM_IPV6_TC, + ISCSI_PARAM_IPV6_FLOW_LABEL, + ISCSI_PARAM_IS_FW_ASSIGNED_IPV6, + + ISCSI_PARAM_DISCOVERY_PARENT_IDX, + ISCSI_PARAM_DISCOVERY_PARENT_TYPE, + ISCSI_PARAM_LOCAL_IPADDR, + /* must always be last */ + ISCSI_PARAM_MAX, +}; + +/* 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_PORT_STATE, + ISCSI_HOST_PARAM_PORT_SPEED, + ISCSI_HOST_PARAM_MAX, +}; + +/* portal type */ +#define PORTAL_TYPE_IPV4 "ipv4" +#define PORTAL_TYPE_IPV6 "ipv6" + +/* iSCSI Flash Target params */ +enum iscsi_flashnode_param { + ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6, + ISCSI_FLASHNODE_PORTAL_TYPE, + ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE, + ISCSI_FLASHNODE_DISCOVERY_SESS, + ISCSI_FLASHNODE_ENTRY_EN, + ISCSI_FLASHNODE_HDR_DGST_EN, + ISCSI_FLASHNODE_DATA_DGST_EN, + ISCSI_FLASHNODE_IMM_DATA_EN, + ISCSI_FLASHNODE_INITIAL_R2T_EN, + ISCSI_FLASHNODE_DATASEQ_INORDER, + ISCSI_FLASHNODE_PDU_INORDER, + ISCSI_FLASHNODE_CHAP_AUTH_EN, + ISCSI_FLASHNODE_SNACK_REQ_EN, + ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN, + ISCSI_FLASHNODE_BIDI_CHAP_EN, + /* make authentication for discovery sessions optional */ + ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL, + ISCSI_FLASHNODE_ERL, + ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT, + ISCSI_FLASHNODE_TCP_NAGLE_DISABLE, + ISCSI_FLASHNODE_TCP_WSF_DISABLE, + ISCSI_FLASHNODE_TCP_TIMER_SCALE, + ISCSI_FLASHNODE_TCP_TIMESTAMP_EN, + ISCSI_FLASHNODE_IP_FRAG_DISABLE, + ISCSI_FLASHNODE_MAX_RECV_DLENGTH, + ISCSI_FLASHNODE_MAX_XMIT_DLENGTH, + ISCSI_FLASHNODE_FIRST_BURST, + ISCSI_FLASHNODE_DEF_TIME2WAIT, + ISCSI_FLASHNODE_DEF_TIME2RETAIN, + ISCSI_FLASHNODE_MAX_R2T, + ISCSI_FLASHNODE_KEEPALIVE_TMO, + ISCSI_FLASHNODE_ISID, + ISCSI_FLASHNODE_TSID, + ISCSI_FLASHNODE_PORT, + ISCSI_FLASHNODE_MAX_BURST, + ISCSI_FLASHNODE_DEF_TASKMGMT_TMO, + ISCSI_FLASHNODE_IPADDR, + ISCSI_FLASHNODE_ALIAS, + ISCSI_FLASHNODE_REDIRECT_IPADDR, + ISCSI_FLASHNODE_MAX_SEGMENT_SIZE, + ISCSI_FLASHNODE_LOCAL_PORT, + ISCSI_FLASHNODE_IPV4_TOS, + ISCSI_FLASHNODE_IPV6_TC, + ISCSI_FLASHNODE_IPV6_FLOW_LABEL, + ISCSI_FLASHNODE_NAME, + ISCSI_FLASHNODE_TPGT, + ISCSI_FLASHNODE_LINK_LOCAL_IPV6, + ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX, + ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE, + ISCSI_FLASHNODE_TCP_XMIT_WSF, + ISCSI_FLASHNODE_TCP_RECV_WSF, + ISCSI_FLASHNODE_CHAP_IN_IDX, + ISCSI_FLASHNODE_CHAP_OUT_IDX, + ISCSI_FLASHNODE_USERNAME, + ISCSI_FLASHNODE_USERNAME_IN, + ISCSI_FLASHNODE_PASSWORD, + ISCSI_FLASHNODE_PASSWORD_IN, + ISCSI_FLASHNODE_STATSN, + ISCSI_FLASHNODE_EXP_STATSN, + ISCSI_FLASHNODE_IS_BOOT_TGT, + + ISCSI_FLASHNODE_MAX, +}; + +struct iscsi_flashnode_param_info { + uint32_t len; /* Actual length of the param */ + uint16_t param; /* iscsi param value */ + uint8_t value[0]; /* length sized value follows */ +} __packed; + +enum iscsi_discovery_parent_type { + ISCSI_DISC_PARENT_UNKNOWN = 0x1, + ISCSI_DISC_PARENT_SENDTGT = 0x2, + ISCSI_DISC_PARENT_ISNS = 0x3, +}; + +/* iSCSI port Speed */ +enum iscsi_port_speed { + ISCSI_PORT_SPEED_UNKNOWN = 0x1, + ISCSI_PORT_SPEED_10MBPS = 0x2, + ISCSI_PORT_SPEED_100MBPS = 0x4, + ISCSI_PORT_SPEED_1GBPS = 0x8, + ISCSI_PORT_SPEED_10GBPS = 0x10, +}; + +/* iSCSI port state */ +enum iscsi_port_state { + ISCSI_PORT_STATE_DOWN = 0x1, + ISCSI_PORT_STATE_UP = 0x2, +}; + +/* iSCSI PING status/error code */ +enum iscsi_ping_status_code { + ISCSI_PING_SUCCESS = 0, + ISCSI_PING_FW_DISABLED = 0x1, + ISCSI_PING_IPADDR_INVALID = 0x2, + ISCSI_PING_LINKLOCAL_IPV6_ADDR_INVALID = 0x3, + ISCSI_PING_TIMEOUT = 0x4, + ISCSI_PING_INVALID_DEST_ADDR = 0x5, + ISCSI_PING_OVERSIZE_PACKET = 0x6, + ISCSI_PING_ICMP_ERROR = 0x7, + ISCSI_PING_MAX_REQ_EXCEEDED = 0x8, + ISCSI_PING_NO_ARP_RECEIVED = 0x9, +}; + +#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 */ +#define CAP_LOGIN_OFFLOAD 0x4000 /* offload session login */ + +/* + * 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)))); +}; + +enum chap_type_e { + CHAP_TYPE_OUT, + CHAP_TYPE_IN, +}; + +enum iscsi_chap_param { + ISCSI_CHAP_PARAM_INDEX, + ISCSI_CHAP_PARAM_CHAP_TYPE, + ISCSI_CHAP_PARAM_USERNAME, + ISCSI_CHAP_PARAM_PASSWORD, + ISCSI_CHAP_PARAM_PASSWORD_LEN +}; + +#define ISCSI_CHAP_AUTH_NAME_MAX_LEN 256 +#define ISCSI_CHAP_AUTH_SECRET_MAX_LEN 256 +struct iscsi_chap_rec { + uint16_t chap_tbl_idx; + enum chap_type_e chap_type; + char username[ISCSI_CHAP_AUTH_NAME_MAX_LEN]; + uint8_t password[ISCSI_CHAP_AUTH_SECRET_MAX_LEN]; + uint8_t password_length; +}; + +#define ISCSI_HOST_STATS_CUSTOM_MAX 32 +#define ISCSI_HOST_STATS_CUSTOM_DESC_MAX 64 +struct iscsi_host_stats_custom { + char desc[ISCSI_HOST_STATS_CUSTOM_DESC_MAX]; + uint64_t value; +}; + +/* struct iscsi_offload_host_stats: Host statistics, + * Include statistics for MAC, IP, TCP & iSCSI. + */ +struct iscsi_offload_host_stats { + /* MAC */ + uint64_t mactx_frames; + uint64_t mactx_bytes; + uint64_t mactx_multicast_frames; + uint64_t mactx_broadcast_frames; + uint64_t mactx_pause_frames; + uint64_t mactx_control_frames; + uint64_t mactx_deferral; + uint64_t mactx_excess_deferral; + uint64_t mactx_late_collision; + uint64_t mactx_abort; + uint64_t mactx_single_collision; + uint64_t mactx_multiple_collision; + uint64_t mactx_collision; + uint64_t mactx_frames_dropped; + uint64_t mactx_jumbo_frames; + uint64_t macrx_frames; + uint64_t macrx_bytes; + uint64_t macrx_unknown_control_frames; + uint64_t macrx_pause_frames; + uint64_t macrx_control_frames; + uint64_t macrx_dribble; + uint64_t macrx_frame_length_error; + uint64_t macrx_jabber; + uint64_t macrx_carrier_sense_error; + uint64_t macrx_frame_discarded; + uint64_t macrx_frames_dropped; + uint64_t mac_crc_error; + uint64_t mac_encoding_error; + uint64_t macrx_length_error_large; + uint64_t macrx_length_error_small; + uint64_t macrx_multicast_frames; + uint64_t macrx_broadcast_frames; + /* IP */ + uint64_t iptx_packets; + uint64_t iptx_bytes; + uint64_t iptx_fragments; + uint64_t iprx_packets; + uint64_t iprx_bytes; + uint64_t iprx_fragments; + uint64_t ip_datagram_reassembly; + uint64_t ip_invalid_address_error; + uint64_t ip_error_packets; + uint64_t ip_fragrx_overlap; + uint64_t ip_fragrx_outoforder; + uint64_t ip_datagram_reassembly_timeout; + uint64_t ipv6tx_packets; + uint64_t ipv6tx_bytes; + uint64_t ipv6tx_fragments; + uint64_t ipv6rx_packets; + uint64_t ipv6rx_bytes; + uint64_t ipv6rx_fragments; + uint64_t ipv6_datagram_reassembly; + uint64_t ipv6_invalid_address_error; + uint64_t ipv6_error_packets; + uint64_t ipv6_fragrx_overlap; + uint64_t ipv6_fragrx_outoforder; + uint64_t ipv6_datagram_reassembly_timeout; + /* TCP */ + uint64_t tcptx_segments; + uint64_t tcptx_bytes; + uint64_t tcprx_segments; + uint64_t tcprx_byte; + uint64_t tcp_duplicate_ack_retx; + uint64_t tcp_retx_timer_expired; + uint64_t tcprx_duplicate_ack; + uint64_t tcprx_pure_ackr; + uint64_t tcptx_delayed_ack; + uint64_t tcptx_pure_ack; + uint64_t tcprx_segment_error; + uint64_t tcprx_segment_outoforder; + uint64_t tcprx_window_probe; + uint64_t tcprx_window_update; + uint64_t tcptx_window_probe_persist; + /* ECC */ + uint64_t ecc_error_correction; + /* iSCSI */ + uint64_t iscsi_pdu_tx; + uint64_t iscsi_data_bytes_tx; + uint64_t iscsi_pdu_rx; + uint64_t iscsi_data_bytes_rx; + uint64_t iscsi_io_completed; + uint64_t iscsi_unexpected_io_rx; + uint64_t iscsi_format_error; + uint64_t iscsi_hdr_digest_error; + uint64_t iscsi_data_digest_error; + uint64_t iscsi_sequence_error; + /* + * iSCSI Custom Host Statistics support, i.e. Transport could + * extend existing host statistics with its own specific statistics + * up to ISCSI_HOST_STATS_CUSTOM_MAX + */ + uint32_t custom_length; + struct iscsi_host_stats_custom custom[0] + __aligned(sizeof(uint64_t)); +}; + +#endif diff --git a/kernel/include/scsi/iscsi_proto.h b/kernel/include/scsi/iscsi_proto.h new file mode 100644 index 000000000..c1260d80e --- /dev/null +++ b/kernel/include/scsi/iscsi_proto.h @@ -0,0 +1,668 @@ +/* + * 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 + +/* iSCSI header length */ +#define ISCSI_HDR_LEN 48 + +/* iSCSI CRC32C length */ +#define ISCSI_CRC_LEN 4 + +/* Padding word length */ +#define ISCSI_PAD_LEN 4 + +/* + * Serial Number Arithmetic, 32 bits, RFC1982 + */ + +static inline int iscsi_sna_lt(u32 n1, u32 n2) +{ + return (s32)(n1 - n2) < 0; +} + +static inline int iscsi_sna_lte(u32 n1, u32 n2) +{ + return (s32)(n1 - n2) <= 0; +} + +static inline int iscsi_sna_gt(u32 n1, u32 n2) +{ + return (s32)(n1 - n2) > 0; +} + +static inline int iscsi_sna_gte(u32 n1, u32 n2) +{ + return (s32)(n1 - n2) >= 0; +} + +/* + * 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 */ + struct scsi_lun lun; + 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_scsi_req { + uint8_t opcode; + uint8_t flags; + __be16 rsvd2; + uint8_t hlength; + uint8_t dlength[3]; + struct scsi_lun lun; + 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_scsi_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]; + struct scsi_lun lun; + 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]; + struct scsi_lun lun; + 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]; + struct scsi_lun lun; + 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]; + struct scsi_lun lun; + 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 + +#define ISCSI_TM_FUNC_VALUE(hdr) ((hdr)->flags & ISCSI_FLAG_TM_FUNC_MASK) + +/* 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]; + struct scsi_lun lun; + 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]; + struct scsi_lun lun; + 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]; + struct scsi_lun lun; + 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_req { + 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_CURRENT_STAGE1 0x04 +#define ISCSI_FLAG_LOGIN_CURRENT_STAGE2 0x08 +#define ISCSI_FLAG_LOGIN_CURRENT_STAGE3 0x0C +#define ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK 0x03 /* 2 bits */ +#define ISCSI_FLAG_LOGIN_NEXT_STAGE1 0x01 +#define ISCSI_FLAG_LOGIN_NEXT_STAGE2 0x02 +#define ISCSI_FLAG_LOGIN_NEXT_STAGE3 0x03 + +#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[2]; + uint8_t hlength; + uint8_t dlength[3]; + uint8_t lun[8]; + itt_t itt; + __be32 ttt; + uint8_t rsvd3[4]; + __be32 exp_statsn; + uint8_t rsvd4[8]; + __be32 begrun; + __be32 runlength; +}; + +/* SNACK PDU flags */ +#define ISCSI_FLAG_SNACK_TYPE_DATA 0 +#define ISCSI_FLAG_SNACK_TYPE_R2T 0 +#define ISCSI_FLAG_SNACK_TYPE_STATUS 1 +#define ISCSI_FLAG_SNACK_TYPE_DATA_ACK 2 +#define ISCSI_FLAG_SNACK_TYPE_RDATA 3 +#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 + +#define ISCSI_NAME_LEN 224 + +/************************* RFC 3720 End *****************************/ + +#endif /* ISCSI_PROTO_H */ diff --git a/kernel/include/scsi/libfc.h b/kernel/include/scsi/libfc.h new file mode 100644 index 000000000..93d14daf0 --- /dev/null +++ b/kernel/include/scsi/libfc.h @@ -0,0 +1,1153 @@ +/* + * 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 _LIBFC_H_ +#define _LIBFC_H_ + +#include <linux/timer.h> +#include <linux/if.h> +#include <linux/percpu.h> + +#include <scsi/scsi_transport.h> +#include <scsi/scsi_transport_fc.h> +#include <scsi/scsi_bsg_fc.h> + +#include <scsi/fc/fc_fcp.h> +#include <scsi/fc/fc_ns.h> +#include <scsi/fc/fc_ms.h> +#include <scsi/fc/fc_els.h> +#include <scsi/fc/fc_gs.h> + +#include <scsi/fc_frame.h> + +#define FC_FC4_PROV_SIZE (FC_TYPE_FCP + 1) /* size of tables */ + +/* + * libfc error codes + */ +#define FC_NO_ERR 0 /* no error */ +#define FC_EX_TIMEOUT 1 /* Exchange timeout */ +#define FC_EX_CLOSED 2 /* Exchange closed */ + +/** + * enum fc_lport_state - Local port states + * @LPORT_ST_DISABLED: Disabled + * @LPORT_ST_FLOGI: Fabric login (FLOGI) sent + * @LPORT_ST_DNS: Waiting for name server remote port to become ready + * @LPORT_ST_RPN_ID: Register port name by ID (RPN_ID) sent + * @LPORT_ST_RFT_ID: Register Fibre Channel types by ID (RFT_ID) sent + * @LPORT_ST_RFF_ID: Register FC-4 Features by ID (RFF_ID) sent + * @LPORT_ST_FDMI: Waiting for mgmt server rport to become ready + * @LPORT_ST_RHBA: + * @LPORT_ST_SCR: State Change Register (SCR) sent + * @LPORT_ST_READY: Ready for use + * @LPORT_ST_LOGO: Local port logout (LOGO) sent + * @LPORT_ST_RESET: Local port reset + */ +enum fc_lport_state { + LPORT_ST_DISABLED = 0, + LPORT_ST_FLOGI, + LPORT_ST_DNS, + LPORT_ST_RNN_ID, + LPORT_ST_RSNN_NN, + LPORT_ST_RSPN_ID, + LPORT_ST_RFT_ID, + LPORT_ST_RFF_ID, + LPORT_ST_FDMI, + LPORT_ST_RHBA, + LPORT_ST_RPA, + LPORT_ST_DHBA, + LPORT_ST_DPRT, + LPORT_ST_SCR, + LPORT_ST_READY, + LPORT_ST_LOGO, + LPORT_ST_RESET +}; + +enum fc_disc_event { + DISC_EV_NONE = 0, + DISC_EV_SUCCESS, + DISC_EV_FAILED +}; + +/** + * enum fc_rport_state - Remote port states + * @RPORT_ST_INIT: Initialized + * @RPORT_ST_FLOGI: Waiting for FLOGI completion for point-to-multipoint + * @RPORT_ST_PLOGI_WAIT: Waiting for peer to login for point-to-multipoint + * @RPORT_ST_PLOGI: Waiting for PLOGI completion + * @RPORT_ST_PRLI: Waiting for PRLI completion + * @RPORT_ST_RTV: Waiting for RTV completion + * @RPORT_ST_READY: Ready for use + * @RPORT_ST_ADISC: Discover Address sent + * @RPORT_ST_DELETE: Remote port being deleted +*/ +enum fc_rport_state { + RPORT_ST_INIT, + RPORT_ST_FLOGI, + RPORT_ST_PLOGI_WAIT, + RPORT_ST_PLOGI, + RPORT_ST_PRLI, + RPORT_ST_RTV, + RPORT_ST_READY, + RPORT_ST_ADISC, + RPORT_ST_DELETE, +}; + +/** + * struct fc_disc_port - temporary discovery port to hold rport identifiers + * @lp: Fibre Channel host port instance + * @peers: Node for list management during discovery and RSCN processing + * @rport_work: Work struct for starting the rport state machine + * @port_id: Port ID of the discovered port + */ +struct fc_disc_port { + struct fc_lport *lp; + struct list_head peers; + struct work_struct rport_work; + u32 port_id; +}; + +/** + * enum fc_rport_event - Remote port events + * @RPORT_EV_NONE: No event + * @RPORT_EV_READY: Remote port is ready for use + * @RPORT_EV_FAILED: State machine failed, remote port is not ready + * @RPORT_EV_STOP: Remote port has been stopped + * @RPORT_EV_LOGO: Remote port logout (LOGO) sent + */ +enum fc_rport_event { + RPORT_EV_NONE = 0, + RPORT_EV_READY, + RPORT_EV_FAILED, + RPORT_EV_STOP, + RPORT_EV_LOGO +}; + +struct fc_rport_priv; + +/** + * struct fc_rport_operations - Operations for a remote port + * @event_callback: Function to be called for remote port events + */ +struct fc_rport_operations { + void (*event_callback)(struct fc_lport *, struct fc_rport_priv *, + enum fc_rport_event); +}; + +/** + * struct fc_rport_libfc_priv - libfc internal information about a remote port + * @local_port: The associated local port + * @rp_state: Indicates READY for I/O or DELETE when blocked + * @flags: REC and RETRY supported flags + * @e_d_tov: Error detect timeout value (in msec) + * @r_a_tov: Resource allocation timeout value (in msec) + */ +struct fc_rport_libfc_priv { + struct fc_lport *local_port; + enum fc_rport_state rp_state; + u16 flags; + #define FC_RP_FLAGS_REC_SUPPORTED (1 << 0) + #define FC_RP_FLAGS_RETRY (1 << 1) + #define FC_RP_STARTED (1 << 2) + #define FC_RP_FLAGS_CONF_REQ (1 << 3) + unsigned int e_d_tov; + unsigned int r_a_tov; +}; + +/** + * struct fc_rport_priv - libfc remote port and discovery info + * @local_port: The associated local port + * @rport: The FC transport remote port + * @kref: Reference counter + * @rp_state: Enumeration that tracks progress of PLOGI, PRLI, + * and RTV exchanges + * @ids: The remote port identifiers and roles + * @flags: STARTED, REC and RETRY_SUPPORTED flags + * @max_seq: Maximum number of concurrent sequences + * @disc_id: The discovery identifier + * @maxframe_size: The maximum frame size + * @retries: The retry count for the current state + * @major_retries: The retry count for the entire PLOGI/PRLI state machine + * @e_d_tov: Error detect timeout value (in msec) + * @r_a_tov: Resource allocation timeout value (in msec) + * @rp_mutex: The mutex that protects the remote port + * @retry_work: Handle for retries + * @event_callback: Callback when READY, FAILED or LOGO states complete + * @prli_count: Count of open PRLI sessions in providers + * @rcu: Structure used for freeing in an RCU-safe manner + */ +struct fc_rport_priv { + struct fc_lport *local_port; + struct fc_rport *rport; + struct kref kref; + enum fc_rport_state rp_state; + struct fc_rport_identifiers ids; + u16 flags; + u16 max_seq; + u16 disc_id; + u16 maxframe_size; + unsigned int retries; + unsigned int major_retries; + unsigned int e_d_tov; + unsigned int r_a_tov; + struct mutex rp_mutex; + struct delayed_work retry_work; + enum fc_rport_event event; + struct fc_rport_operations *ops; + struct list_head peers; + struct work_struct event_work; + u32 supported_classes; + u16 prli_count; + struct rcu_head rcu; + u16 sp_features; + u8 spp_type; + void (*lld_event_callback)(struct fc_lport *, + struct fc_rport_priv *, + enum fc_rport_event); +}; + +/** + * struct fc_stats - fc stats structure + * @SecondsSinceLastReset: Seconds since the last reset + * @TxFrames: Number of transmitted frames + * @TxWords: Number of transmitted words + * @RxFrames: Number of received frames + * @RxWords: Number of received words + * @ErrorFrames: Number of received error frames + * @DumpedFrames: Number of dumped frames + * @FcpPktAllocFails: Number of fcp packet allocation failures + * @FcpPktAborts: Number of fcp packet aborts + * @FcpFrameAllocFails: Number of fcp frame allocation failures + * @LinkFailureCount: Number of link failures + * @LossOfSignalCount: Number for signal losses + * @InvalidTxWordCount: Number of invalid transmitted words + * @InvalidCRCCount: Number of invalid CRCs + * @InputRequests: Number of input requests + * @OutputRequests: Number of output requests + * @ControlRequests: Number of control requests + * @InputBytes: Number of received bytes + * @OutputBytes: Number of transmitted bytes + * @VLinkFailureCount: Number of virtual link failures + * @MissDiscAdvCount: Number of missing FIP discovery advertisement + */ +struct fc_stats { + u64 SecondsSinceLastReset; + u64 TxFrames; + u64 TxWords; + u64 RxFrames; + u64 RxWords; + u64 ErrorFrames; + u64 DumpedFrames; + u64 FcpPktAllocFails; + u64 FcpPktAborts; + u64 FcpFrameAllocFails; + u64 LinkFailureCount; + u64 LossOfSignalCount; + u64 InvalidTxWordCount; + u64 InvalidCRCCount; + u64 InputRequests; + u64 OutputRequests; + u64 ControlRequests; + u64 InputBytes; + u64 OutputBytes; + u64 VLinkFailureCount; + u64 MissDiscAdvCount; +}; + +/** + * struct fc_seq_els_data - ELS data used for passing ELS specific responses + * @reason: The reason for rejection + * @explan: The explanation of the rejection + * + * Mainly used by the exchange manager layer. + */ +struct fc_seq_els_data { + enum fc_els_rjt_reason reason; + enum fc_els_rjt_explan explan; +}; + +/** + * struct fc_fcp_pkt - FCP request structure (one for each scsi_cmnd request) + * @lp: The associated local port + * @state: The state of the I/O + * @ref_cnt: Reference count + * @scsi_pkt_lock: Lock to protect the SCSI packet (must be taken before the + * host_lock if both are to be held at the same time) + * @cmd: The SCSI command (set and clear with the host_lock held) + * @list: Tracks queued commands (accessed with the host_lock held) + * @timer: The command timer + * @tm_done: Completion indicator + * @wait_for_comp: Indicator to wait for completion of the I/O (in jiffies) + * @data_len: The length of the data + * @cdb_cmd: The CDB command + * @xfer_len: The transfer length + * @xfer_ddp: Indicates if this transfer used DDP (XID of the exchange + * will be set here if DDP was setup) + * @xfer_contig_end: The offset into the buffer if the buffer is contiguous + * (Tx and Rx) + * @max_payload: The maximum payload size (in bytes) + * @io_status: SCSI result (upper 24 bits) + * @cdb_status: CDB status + * @status_code: FCP I/O status + * @scsi_comp_flags: Completion flags (bit 3 Underrun bit 2: overrun) + * @req_flags: Request flags (bit 0: read bit:1 write) + * @scsi_resid: SCSI residule length + * @rport: The remote port that the SCSI command is targeted at + * @seq_ptr: The sequence that will carry the SCSI command + * @recov_retry: Number of recovery retries + * @recov_seq: The sequence for REC or SRR + */ +struct fc_fcp_pkt { + spinlock_t scsi_pkt_lock; + atomic_t ref_cnt; + + /* SCSI command and data transfer information */ + u32 data_len; + + /* SCSI I/O related information */ + struct scsi_cmnd *cmd; + struct list_head list; + + /* Housekeeping information */ + struct fc_lport *lp; + u8 state; + + /* SCSI/FCP return status */ + u8 cdb_status; + u8 status_code; + u8 scsi_comp_flags; + u32 io_status; + u32 req_flags; + u32 scsi_resid; + + /* Transport related veriables */ + size_t xfer_len; + struct fcp_cmnd cdb_cmd; + u32 xfer_contig_end; + u16 max_payload; + u16 xfer_ddp; + + /* Associated structures */ + struct fc_rport *rport; + struct fc_seq *seq_ptr; + + /* Timeout/error related information */ + struct timer_list timer; + int wait_for_comp; + u32 recov_retry; + struct fc_seq *recov_seq; + struct completion tm_done; +} ____cacheline_aligned_in_smp; + +/* + * Structure and function definitions for managing Fibre Channel Exchanges + * and Sequences + * + * fc_exch holds state for one exchange and links to its active sequence. + * + * fc_seq holds the state for an individual sequence. + */ + +struct fc_exch_mgr; +struct fc_exch_mgr_anchor; +extern u16 fc_cpu_mask; /* cpu mask for possible cpus */ + +/** + * struct fc_seq - FC sequence + * @id: The sequence ID + * @ssb_stat: Status flags for the sequence status block (SSB) + * @cnt: Number of frames sent so far + * @rec_data: FC-4 value for REC + */ +struct fc_seq { + u8 id; + u16 ssb_stat; + u16 cnt; + u32 rec_data; +}; + +#define FC_EX_DONE (1 << 0) /* ep is completed */ +#define FC_EX_RST_CLEANUP (1 << 1) /* reset is forcing completion */ + +/** + * struct fc_exch - Fibre Channel Exchange + * @em: Exchange manager + * @pool: Exchange pool + * @state: The exchange's state + * @xid: The exchange ID + * @ex_list: Handle used by the EM to track free exchanges + * @ex_lock: Lock that protects the exchange + * @ex_refcnt: Reference count + * @timeout_work: Handle for timeout handler + * @lp: The local port that this exchange is on + * @oxid: Originator's exchange ID + * @rxid: Responder's exchange ID + * @oid: Originator's FCID + * @sid: Source FCID + * @did: Destination FCID + * @esb_stat: ESB exchange status + * @r_a_tov: Resouce allocation time out value (in msecs) + * @seq_id: The next sequence ID to use + * @encaps: encapsulation information for lower-level driver + * @f_ctl: F_CTL flags for the sequence + * @fh_type: The frame type + * @class: The class of service + * @seq: The sequence in use on this exchange + * @resp_active: Number of tasks that are concurrently executing @resp(). + * @resp_task: If @resp_active > 0, either the task executing @resp(), the + * task that has been interrupted to execute the soft-IRQ + * executing @resp() or NULL if more than one task is executing + * @resp concurrently. + * @resp_wq: Waitqueue for the tasks waiting on @resp_active. + * @resp: Callback for responses on this exchange + * @destructor: Called when destroying the exchange + * @arg: Passed as a void pointer to the resp() callback + * + * Locking notes: The ex_lock protects following items: + * state, esb_stat, f_ctl, seq.ssb_stat + * seq_id + * sequence allocation + */ +struct fc_exch { + spinlock_t ex_lock; + atomic_t ex_refcnt; + enum fc_class class; + struct fc_exch_mgr *em; + struct fc_exch_pool *pool; + struct list_head ex_list; + struct fc_lport *lp; + u32 esb_stat; + u8 state; + u8 fh_type; + u8 seq_id; + u8 encaps; + u16 xid; + u16 oxid; + u16 rxid; + u32 oid; + u32 sid; + u32 did; + u32 r_a_tov; + u32 f_ctl; + struct fc_seq seq; + int resp_active; + struct task_struct *resp_task; + wait_queue_head_t resp_wq; + void (*resp)(struct fc_seq *, struct fc_frame *, void *); + void *arg; + void (*destructor)(struct fc_seq *, void *); + struct delayed_work timeout_work; +} ____cacheline_aligned_in_smp; +#define fc_seq_exch(sp) container_of(sp, struct fc_exch, seq) + + +struct libfc_function_template { + /* + * Interface to send a FC frame + * + * STATUS: REQUIRED + */ + int (*frame_send)(struct fc_lport *, struct fc_frame *); + + /* + * Interface to send ELS/CT frames + * + * STATUS: OPTIONAL + */ + struct fc_seq *(*elsct_send)(struct fc_lport *, u32 did, + struct fc_frame *, unsigned int op, + void (*resp)(struct fc_seq *, + struct fc_frame *, void *arg), + void *arg, u32 timer_msec); + + /* + * Send the FC frame payload using a new exchange and sequence. + * + * The exchange response handler is set in this routine to resp() + * function pointer. It can be called in two scenarios: if a timeout + * occurs or if a response frame is received for the exchange. The + * fc_frame pointer in response handler will also indicate timeout + * as error using IS_ERR related macros. + * + * The exchange destructor handler is also set in this routine. + * The destructor handler is invoked by EM layer when exchange + * is about to free, this can be used by caller to free its + * resources along with exchange free. + * + * The arg is passed back to resp and destructor handler. + * + * The timeout value (in msec) for an exchange is set if non zero + * timer_msec argument is specified. The timer is canceled when + * it fires or when the exchange is done. The exchange timeout handler + * is registered by EM layer. + * + * STATUS: OPTIONAL + */ + struct fc_seq *(*exch_seq_send)(struct fc_lport *, struct fc_frame *, + void (*resp)(struct fc_seq *, + struct fc_frame *, + void *), + void (*destructor)(struct fc_seq *, + void *), + void *, unsigned int timer_msec); + + /* + * Sets up the DDP context for a given exchange id on the given + * scatterlist if LLD supports DDP for large receive. + * + * STATUS: OPTIONAL + */ + int (*ddp_setup)(struct fc_lport *, u16, struct scatterlist *, + unsigned int); + /* + * Completes the DDP transfer and returns the length of data DDPed + * for the given exchange id. + * + * STATUS: OPTIONAL + */ + int (*ddp_done)(struct fc_lport *, u16); + /* + * Sets up the DDP context for a given exchange id on the given + * scatterlist if LLD supports DDP for target. + * + * STATUS: OPTIONAL + */ + int (*ddp_target)(struct fc_lport *, u16, struct scatterlist *, + unsigned int); + /* + * Allow LLD to fill its own Link Error Status Block + * + * STATUS: OPTIONAL + */ + void (*get_lesb)(struct fc_lport *, struct fc_els_lesb *lesb); + /* + * Send a frame using an existing sequence and exchange. + * + * STATUS: OPTIONAL + */ + int (*seq_send)(struct fc_lport *, struct fc_seq *, + struct fc_frame *); + + /* + * Send an ELS response using information from the received frame. + * + * STATUS: OPTIONAL + */ + void (*seq_els_rsp_send)(struct fc_frame *, enum fc_els_cmd, + struct fc_seq_els_data *); + + /* + * Abort an exchange and sequence. Generally called because of a + * exchange timeout or an abort from the upper layer. + * + * A timer_msec can be specified for abort timeout, if non-zero + * timer_msec value is specified then exchange resp handler + * will be called with timeout error if no response to abort. + * + * STATUS: OPTIONAL + */ + int (*seq_exch_abort)(const struct fc_seq *, + unsigned int timer_msec); + + /* + * Indicate that an exchange/sequence tuple is complete and the memory + * allocated for the related objects may be freed. + * + * STATUS: OPTIONAL + */ + void (*exch_done)(struct fc_seq *); + + /* + * Start a new sequence on the same exchange/sequence tuple. + * + * STATUS: OPTIONAL + */ + struct fc_seq *(*seq_start_next)(struct fc_seq *); + + /* + * Set a response handler for the exchange of the sequence. + * + * STATUS: OPTIONAL + */ + void (*seq_set_resp)(struct fc_seq *sp, + void (*resp)(struct fc_seq *, struct fc_frame *, + void *), + void *arg); + + /* + * Assign a sequence for an incoming request frame. + * + * STATUS: OPTIONAL + */ + struct fc_seq *(*seq_assign)(struct fc_lport *, struct fc_frame *); + + /* + * Release the reference on the sequence returned by seq_assign(). + * + * STATUS: OPTIONAL + */ + void (*seq_release)(struct fc_seq *); + + /* + * Reset an exchange manager, completing all sequences and exchanges. + * If s_id is non-zero, reset only exchanges originating from that FID. + * If d_id is non-zero, reset only exchanges sending to that FID. + * + * STATUS: OPTIONAL + */ + void (*exch_mgr_reset)(struct fc_lport *, u32 s_id, u32 d_id); + + /* + * Flush the rport work queue. Generally used before shutdown. + * + * STATUS: OPTIONAL + */ + void (*rport_flush_queue)(void); + + /* + * Receive a frame for a local port. + * + * STATUS: OPTIONAL + */ + void (*lport_recv)(struct fc_lport *, struct fc_frame *); + + /* + * Reset the local port. + * + * STATUS: OPTIONAL + */ + int (*lport_reset)(struct fc_lport *); + + /* + * Set the local port FC_ID. + * + * This may be provided by the LLD to allow it to be + * notified when the local port is assigned a FC-ID. + * + * The frame, if non-NULL, is the incoming frame with the + * FLOGI LS_ACC or FLOGI, and may contain the granted MAC + * address for the LLD. The frame pointer may be NULL if + * no MAC is associated with this assignment (LOGO or PLOGI). + * + * If FC_ID is non-zero, r_a_tov and e_d_tov must be valid. + * + * Note: this is called with the local port mutex held. + * + * STATUS: OPTIONAL + */ + void (*lport_set_port_id)(struct fc_lport *, u32 port_id, + struct fc_frame *); + + /* + * Create a remote port with a given port ID + * + * STATUS: OPTIONAL + */ + struct fc_rport_priv *(*rport_create)(struct fc_lport *, u32); + + /* + * Initiates the RP state machine. It is called from the LP module. + * This function will issue the following commands to the N_Port + * identified by the FC ID provided. + * + * - PLOGI + * - PRLI + * - RTV + * + * STATUS: OPTIONAL + */ + int (*rport_login)(struct fc_rport_priv *); + + /* + * Logoff, and remove the rport from the transport if + * it had been added. This will send a LOGO to the target. + * + * STATUS: OPTIONAL + */ + int (*rport_logoff)(struct fc_rport_priv *); + + /* + * Receive a request from a remote port. + * + * STATUS: OPTIONAL + */ + void (*rport_recv_req)(struct fc_lport *, struct fc_frame *); + + /* + * lookup an rport by it's port ID. + * + * STATUS: OPTIONAL + */ + struct fc_rport_priv *(*rport_lookup)(const struct fc_lport *, u32); + + /* + * Destroy an rport after final kref_put(). + * The argument is a pointer to the kref inside the fc_rport_priv. + */ + void (*rport_destroy)(struct kref *); + + /* + * Callback routine after the remote port is logged in + * + * STATUS: OPTIONAL + */ + void (*rport_event_callback)(struct fc_lport *, + struct fc_rport_priv *, + enum fc_rport_event); + + /* + * Send a fcp cmd from fsp pkt. + * Called with the SCSI host lock unlocked and irqs disabled. + * + * The resp handler is called when FCP_RSP received. + * + * STATUS: OPTIONAL + */ + int (*fcp_cmd_send)(struct fc_lport *, struct fc_fcp_pkt *, + void (*resp)(struct fc_seq *, struct fc_frame *, + void *)); + + /* + * Cleanup the FCP layer, used during link down and reset + * + * STATUS: OPTIONAL + */ + void (*fcp_cleanup)(struct fc_lport *); + + /* + * Abort all I/O on a local port + * + * STATUS: OPTIONAL + */ + void (*fcp_abort_io)(struct fc_lport *); + + /* + * Receive a request for the discovery layer. + * + * STATUS: OPTIONAL + */ + void (*disc_recv_req)(struct fc_lport *, struct fc_frame *); + + /* + * Start discovery for a local port. + * + * STATUS: OPTIONAL + */ + void (*disc_start)(void (*disc_callback)(struct fc_lport *, + enum fc_disc_event), + struct fc_lport *); + + /* + * Stop discovery for a given lport. This will remove + * all discovered rports + * + * STATUS: OPTIONAL + */ + void (*disc_stop) (struct fc_lport *); + + /* + * Stop discovery for a given lport. This will block + * until all discovered rports are deleted from the + * FC transport class + * + * STATUS: OPTIONAL + */ + void (*disc_stop_final) (struct fc_lport *); +}; + +/** + * struct fc_disc - Discovery context + * @retry_count: Number of retries + * @pending: 1 if discovery is pending, 0 if not + * @requested: 1 if discovery has been requested, 0 if not + * @seq_count: Number of sequences used for discovery + * @buf_len: Length of the discovery buffer + * @disc_id: Discovery ID + * @rports: List of discovered remote ports + * @priv: Private pointer for use by discovery code + * @disc_mutex: Mutex that protects the discovery context + * @partial_buf: Partial name buffer (if names are returned + * in multiple frames) + * @disc_work: handle for delayed work context + * @disc_callback: Callback routine called when discovery completes + */ +struct fc_disc { + unsigned char retry_count; + unsigned char pending; + unsigned char requested; + unsigned short seq_count; + unsigned char buf_len; + u16 disc_id; + + struct list_head rports; + void *priv; + struct mutex disc_mutex; + struct fc_gpn_ft_resp partial_buf; + struct delayed_work disc_work; + + void (*disc_callback)(struct fc_lport *, + enum fc_disc_event); +}; + +/* + * Local port notifier and events. + */ +extern struct blocking_notifier_head fc_lport_notifier_head; +enum fc_lport_event { + FC_LPORT_EV_ADD, + FC_LPORT_EV_DEL, +}; + +/** + * struct fc_lport - Local port + * @host: The SCSI host associated with a local port + * @ema_list: Exchange manager anchor list + * @dns_rdata: The directory server remote port + * @ms_rdata: The management server remote port + * @ptp_rdata: Point to point remote port + * @scsi_priv: FCP layer internal data + * @disc: Discovery context + * @vports: Child vports if N_Port + * @vport: Parent vport if VN_Port + * @tt: Libfc function template + * @link_up: Link state (1 = link up, 0 = link down) + * @qfull: Queue state (1 queue is full, 0 queue is not full) + * @state: Identifies the state + * @boot_time: Timestamp indicating when the local port came online + * @host_stats: SCSI host statistics + * @stats: FC local port stats (TODO separate libfc LLD stats) + * @retry_count: Number of retries in the current state + * @port_id: FC Port ID + * @wwpn: World Wide Port Name + * @wwnn: World Wide Node Name + * @service_params: Common service parameters + * @e_d_tov: Error detection timeout value + * @r_a_tov: Resouce allocation timeout value + * @rnid_gen: RNID information + * @sg_supp: Indicates if scatter gather is supported + * @seq_offload: Indicates if sequence offload is supported + * @crc_offload: Indicates if CRC offload is supported + * @lro_enabled: Indicates if large receive offload is supported + * @does_npiv: Supports multiple vports + * @npiv_enabled: Switch/fabric allows NPIV + * @mfs: The maximum Fibre Channel payload size + * @max_retry_count: The maximum retry attempts + * @max_rport_retry_count: The maximum remote port retry attempts + * @rport_priv_size: Size needed by driver after struct fc_rport_priv + * @lro_xid: The maximum XID for LRO + * @lso_max: The maximum large offload send size + * @fcts: FC-4 type mask + * @lp_mutex: Mutex to protect the local port + * @list: Linkage on list of vport peers + * @retry_work: Handle to local port for delayed retry context + * @prov: Pointers available for use by passive FC-4 providers + * @lport_list: Linkage on module-wide list of local ports + */ +struct fc_lport { + /* Associations */ + struct Scsi_Host *host; + struct list_head ema_list; + struct fc_rport_priv *dns_rdata; + struct fc_rport_priv *ms_rdata; + struct fc_rport_priv *ptp_rdata; + void *scsi_priv; + struct fc_disc disc; + + /* Virtual port information */ + struct list_head vports; + struct fc_vport *vport; + + /* Operational Information */ + struct libfc_function_template tt; + u8 link_up; + u8 qfull; + enum fc_lport_state state; + unsigned long boot_time; + struct fc_host_statistics host_stats; + struct fc_stats __percpu *stats; + u8 retry_count; + + /* Fabric information */ + u32 port_id; + u64 wwpn; + u64 wwnn; + unsigned int service_params; + unsigned int e_d_tov; + unsigned int r_a_tov; + struct fc_els_rnid_gen rnid_gen; + + /* Capabilities */ + u32 sg_supp:1; + u32 seq_offload:1; + u32 crc_offload:1; + u32 lro_enabled:1; + u32 does_npiv:1; + u32 npiv_enabled:1; + u32 point_to_multipoint:1; + u32 fdmi_enabled:1; + u32 mfs; + u8 max_retry_count; + u8 max_rport_retry_count; + u16 rport_priv_size; + u16 link_speed; + u16 link_supported_speeds; + u16 lro_xid; + unsigned int lso_max; + struct fc_ns_fts fcts; + + /* Miscellaneous */ + struct mutex lp_mutex; + struct list_head list; + struct delayed_work retry_work; + void *prov[FC_FC4_PROV_SIZE]; + struct list_head lport_list; +}; + +/** + * struct fc4_prov - FC-4 provider registration + * @prli: Handler for incoming PRLI + * @prlo: Handler for session reset + * @recv: Handler for incoming request + * @module: Pointer to module. May be NULL. + */ +struct fc4_prov { + int (*prli)(struct fc_rport_priv *, u32 spp_len, + const struct fc_els_spp *spp_in, + struct fc_els_spp *spp_out); + void (*prlo)(struct fc_rport_priv *); + void (*recv)(struct fc_lport *, struct fc_frame *); + struct module *module; +}; + +/* + * Register FC-4 provider with libfc. + */ +int fc_fc4_register_provider(enum fc_fh_type type, struct fc4_prov *); +void fc_fc4_deregister_provider(enum fc_fh_type type, struct fc4_prov *); + +/* + * FC_LPORT HELPER FUNCTIONS + *****************************/ + +/** + * fc_lport_test_ready() - Determine if a local port is in the READY state + * @lport: The local port to test + */ +static inline int fc_lport_test_ready(struct fc_lport *lport) +{ + return lport->state == LPORT_ST_READY; +} + +/** + * fc_set_wwnn() - Set the World Wide Node Name of a local port + * @lport: The local port whose WWNN is to be set + * @wwnn: The new WWNN + */ +static inline void fc_set_wwnn(struct fc_lport *lport, u64 wwnn) +{ + lport->wwnn = wwnn; +} + +/** + * fc_set_wwpn() - Set the World Wide Port Name of a local port + * @lport: The local port whose WWPN is to be set + * @wwnn: The new WWPN + */ +static inline void fc_set_wwpn(struct fc_lport *lport, u64 wwnn) +{ + lport->wwpn = wwnn; +} + +/** + * fc_lport_state_enter() - Change a local port's state + * @lport: The local port whose state is to change + * @state: The new state + */ +static inline void fc_lport_state_enter(struct fc_lport *lport, + enum fc_lport_state state) +{ + if (state != lport->state) + lport->retry_count = 0; + lport->state = state; +} + +/** + * fc_lport_init_stats() - Allocate per-CPU statistics for a local port + * @lport: The local port whose statistics are to be initialized + */ +static inline int fc_lport_init_stats(struct fc_lport *lport) +{ + lport->stats = alloc_percpu(struct fc_stats); + if (!lport->stats) + return -ENOMEM; + return 0; +} + +/** + * fc_lport_free_stats() - Free memory for a local port's statistics + * @lport: The local port whose statistics are to be freed + */ +static inline void fc_lport_free_stats(struct fc_lport *lport) +{ + free_percpu(lport->stats); +} + +/** + * lport_priv() - Return the private data from a local port + * @lport: The local port whose private data is to be retreived + */ +static inline void *lport_priv(const struct fc_lport *lport) +{ + return (void *)(lport + 1); +} + +/** + * libfc_host_alloc() - Allocate a Scsi_Host with room for a local port and + * LLD private data + * @sht: The SCSI host template + * @priv_size: Size of private data + * + * Returns: libfc lport + */ +static inline struct fc_lport * +libfc_host_alloc(struct scsi_host_template *sht, int priv_size) +{ + struct fc_lport *lport; + struct Scsi_Host *shost; + + shost = scsi_host_alloc(sht, sizeof(*lport) + priv_size); + if (!shost) + return NULL; + lport = shost_priv(shost); + lport->host = shost; + INIT_LIST_HEAD(&lport->ema_list); + INIT_LIST_HEAD(&lport->vports); + return lport; +} + +/* + * FC_FCP HELPER FUNCTIONS + *****************************/ +static inline bool fc_fcp_is_read(const struct fc_fcp_pkt *fsp) +{ + if (fsp && fsp->cmd) + return fsp->cmd->sc_data_direction == DMA_FROM_DEVICE; + return false; +} + +/* + * LOCAL PORT LAYER + *****************************/ +int fc_lport_init(struct fc_lport *); +int fc_lport_destroy(struct fc_lport *); +int fc_fabric_logoff(struct fc_lport *); +int fc_fabric_login(struct fc_lport *); +void __fc_linkup(struct fc_lport *); +void fc_linkup(struct fc_lport *); +void __fc_linkdown(struct fc_lport *); +void fc_linkdown(struct fc_lport *); +void fc_vport_setlink(struct fc_lport *); +void fc_vports_linkchange(struct fc_lport *); +int fc_lport_config(struct fc_lport *); +int fc_lport_reset(struct fc_lport *); +int fc_set_mfs(struct fc_lport *, u32 mfs); +struct fc_lport *libfc_vport_create(struct fc_vport *, int privsize); +struct fc_lport *fc_vport_id_lookup(struct fc_lport *, u32 port_id); +int fc_lport_bsg_request(struct fc_bsg_job *); +void fc_lport_set_local_id(struct fc_lport *, u32 port_id); +void fc_lport_iterate(void (*func)(struct fc_lport *, void *), void *); + +/* + * REMOTE PORT LAYER + *****************************/ +int fc_rport_init(struct fc_lport *); +void fc_rport_terminate_io(struct fc_rport *); + +/* + * DISCOVERY LAYER + *****************************/ +void fc_disc_init(struct fc_lport *); +void fc_disc_config(struct fc_lport *, void *); + +static inline struct fc_lport *fc_disc_lport(struct fc_disc *disc) +{ + return container_of(disc, struct fc_lport, disc); +} + +/* + * FCP LAYER + *****************************/ +int fc_fcp_init(struct fc_lport *); +void fc_fcp_destroy(struct fc_lport *); + +/* + * SCSI INTERACTION LAYER + *****************************/ +int fc_queuecommand(struct Scsi_Host *, struct scsi_cmnd *); +int fc_eh_abort(struct scsi_cmnd *); +int fc_eh_device_reset(struct scsi_cmnd *); +int fc_eh_host_reset(struct scsi_cmnd *); +int fc_slave_alloc(struct scsi_device *); + +/* + * ELS/CT interface + *****************************/ +int fc_elsct_init(struct fc_lport *); +struct fc_seq *fc_elsct_send(struct fc_lport *, u32 did, + struct fc_frame *, + unsigned int op, + void (*resp)(struct fc_seq *, + struct fc_frame *, + void *arg), + void *arg, u32 timer_msec); +void fc_lport_flogi_resp(struct fc_seq *, struct fc_frame *, void *); +void fc_lport_logo_resp(struct fc_seq *, struct fc_frame *, void *); +void fc_fill_reply_hdr(struct fc_frame *, const struct fc_frame *, + enum fc_rctl, u32 parm_offset); +void fc_fill_hdr(struct fc_frame *, const struct fc_frame *, + enum fc_rctl, u32 f_ctl, u16 seq_cnt, u32 parm_offset); + + +/* + * EXCHANGE MANAGER LAYER + *****************************/ +int fc_exch_init(struct fc_lport *); +void fc_exch_update_stats(struct fc_lport *lport); +struct fc_exch_mgr_anchor *fc_exch_mgr_add(struct fc_lport *, + struct fc_exch_mgr *, + bool (*match)(struct fc_frame *)); +void fc_exch_mgr_del(struct fc_exch_mgr_anchor *); +int fc_exch_mgr_list_clone(struct fc_lport *src, struct fc_lport *dst); +struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *, enum fc_class class, + u16 min_xid, u16 max_xid, + bool (*match)(struct fc_frame *)); +void fc_exch_mgr_free(struct fc_lport *); +void fc_exch_recv(struct fc_lport *, struct fc_frame *); +void fc_exch_mgr_reset(struct fc_lport *, u32 s_id, u32 d_id); + +/* + * Functions for fc_functions_template + */ +void fc_get_host_speed(struct Scsi_Host *); +void fc_get_host_port_state(struct Scsi_Host *); +void fc_set_rport_loss_tmo(struct fc_rport *, u32 timeout); +struct fc_host_statistics *fc_get_host_stats(struct Scsi_Host *); + +#endif /* _LIBFC_H_ */ diff --git a/kernel/include/scsi/libfcoe.h b/kernel/include/scsi/libfcoe.h new file mode 100644 index 000000000..de7e3ee60 --- /dev/null +++ b/kernel/include/scsi/libfcoe.h @@ -0,0 +1,408 @@ +/* + * 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 <linux/random.h> +#include <scsi/fc/fc_fcoe.h> +#include <scsi/libfc.h> +#include <scsi/fcoe_sysfs.h> + +#define FCOE_MAX_CMD_LEN 16 /* Supported CDB length */ + +/* + * Max MTU for FCoE: 14 (FCoE header) + 24 (FC header) + 2112 (max FC payload) + * + 4 (FC CRC) + 4 (FCoE trailer) = 2158 bytes + */ +#define FCOE_MTU 2158 + +/* + * 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 */ +#define FCOE_CTLR_VN2VN_LOGIN_LIMIT 3 /* max. VN2VN rport login retries */ + +/** + * 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. + * @FIP_ST_VNMP_START: VN2VN multipath mode start, wait + * @FIP_ST_VNMP_PROBE1: VN2VN sent first probe, listening + * @FIP_ST_VNMP_PROBE2: VN2VN sent second probe, listening + * @FIP_ST_VNMP_CLAIM: VN2VN sent claim, waiting for responses + * @FIP_ST_VNMP_UP: VN2VN multipath mode operation + */ +enum fip_state { + FIP_ST_DISABLED, + FIP_ST_LINK_WAIT, + FIP_ST_AUTO, + FIP_ST_NON_FIP, + FIP_ST_ENABLED, + FIP_ST_VNMP_START, + FIP_ST_VNMP_PROBE1, + FIP_ST_VNMP_PROBE2, + FIP_ST_VNMP_CLAIM, + FIP_ST_VNMP_UP, +}; + +/* + * Modes: + * The mode is the state that is to be entered after link up. + * It must not change after fcoe_ctlr_init() sets it. + */ +#define FIP_MODE_AUTO FIP_ST_AUTO +#define FIP_MODE_NON_FIP FIP_ST_NON_FIP +#define FIP_MODE_FABRIC FIP_ST_ENABLED +#define FIP_MODE_VN2VN FIP_ST_VNMP_START + +/** + * struct fcoe_ctlr - FCoE Controller and FIP state + * @state: internal FIP state for network link and FIP or non-FIP mode. + * @mode: LLD-selected mode. + * @lp: &fc_lport: libfc local port. + * @sel_fcf: currently selected FCF, or NULL. + * @fcfs: list of discovered FCFs. + * @cdev: (Optional) pointer to sysfs fcoe_ctlr_device. + * @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. + * @timer_work: &work_struct for doing keep-alives and resets. + * @recv_work: &work_struct for receiving FIP frames. + * @fip_recv_list: list of received FIP frames. + * @flogi_req: clone of FLOGI request sent + * @rnd_state: state for pseudo-random number generator. + * @port_id: proposed or selected local-port ID. + * @user_mfs: configured maximum FC frame size, including FC header. + * @flogi_oxid: exchange ID of most recent fabric login. + * @flogi_req_send: send of FLOGI requested + * @flogi_count: number of FLOGI attempts in AUTO mode. + * @map_dest: use the FC_MAP mode for destination MAC addresses. + * @spma: supports SPMA server-provided MACs mode + * @probe_tries: number of FC_IDs probed + * @dest_addr: MAC address of the selected FC forwarder. + * @ctl_src_addr: the native MAC address of our local port. + * @send: LLD-supplied function to handle sending FIP Ethernet frames + * @update_mac: LLD-supplied function to handle changes to MAC addresses. + * @get_src_addr: LLD-supplied function to supply a source MAC address. + * @ctlr_mutex: lock protecting this structure. + * @ctlr_lock: spinlock covering flogi_req + * + * 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; + enum fip_state mode; + struct fc_lport *lp; + struct fcoe_fcf *sel_fcf; + struct list_head fcfs; + struct fcoe_ctlr_device *cdev; + 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 timer_work; + struct work_struct recv_work; + struct sk_buff_head fip_recv_list; + struct sk_buff *flogi_req; + + struct rnd_state rnd_state; + u32 port_id; + + u16 user_mfs; + u16 flogi_oxid; + u8 flogi_req_send; + u8 flogi_count; + u8 map_dest; + u8 spma; + u8 probe_tries; + u8 priority; + u8 dest_addr[ETH_ALEN]; + u8 ctl_src_addr[ETH_ALEN]; + + void (*send)(struct fcoe_ctlr *, struct sk_buff *); + void (*update_mac)(struct fc_lport *, u8 *addr); + u8 * (*get_src_addr)(struct fc_lport *); + struct mutex ctlr_mutex; + spinlock_t ctlr_lock; +}; + +/** + * fcoe_ctlr_priv() - Return the private data from a fcoe_ctlr + * @cltr: The fcoe_ctlr whose private data will be returned + */ +static inline void *fcoe_ctlr_priv(const struct fcoe_ctlr *ctlr) +{ + return (void *)(ctlr + 1); +} + +/* + * This assumes that the fcoe_ctlr (x) is allocated with the fcoe_ctlr_device. + */ +#define fcoe_ctlr_to_ctlr_dev(x) \ + (x)->cdev + +/** + * struct fcoe_fcf - Fibre-Channel Forwarder + * @list: list linkage + * @event_work: Work for FC Transport actions queue + * @event: The event to be processed + * @fip: The controller that the FCF was discovered on + * @fcf_dev: The associated fcoe_fcf_device instance + * @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 for FIP traffic + * @fcoe_mac: Ethernet address of the FCF for FCoE traffic + * @vfid: virtual fabric ID + * @pri: selection priority, smaller values are better + * @flogi_sent: current FLOGI sent to this FCF + * @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; + struct work_struct event_work; + struct fcoe_ctlr *fip; + struct fcoe_fcf_device *fcf_dev; + unsigned long time; + + u64 switch_name; + u64 fabric_name; + u32 fc_map; + u16 vfid; + u8 fcf_mac[ETH_ALEN]; + u8 fcoe_mac[ETH_ALEN]; + + u8 pri; + u8 flogi_sent; + u16 flags; + u32 fka_period; + u8 fd_flags:1; +}; + +#define fcoe_fcf_to_fcf_dev(x) \ + ((x)->fcf_dev) + +/** + * struct fcoe_rport - VN2VN remote port + * @time: time of create or last beacon packet received from node + * @fcoe_len: max FCoE frame size, not including VLAN or Ethernet headers + * @flags: flags from probe or claim + * @login_count: number of unsuccessful rport logins to this port + * @enode_mac: E_Node control MAC address + * @vn_mac: VN_Node assigned MAC address for data + */ +struct fcoe_rport { + unsigned long time; + u16 fcoe_len; + u16 flags; + u8 login_count; + u8 enode_mac[ETH_ALEN]; + u8 vn_mac[ETH_ALEN]; +}; + +/* FIP API functions */ +void fcoe_ctlr_init(struct fcoe_ctlr *, enum fip_state); +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 fc_lport *, struct sk_buff *); +void fcoe_ctlr_recv(struct fcoe_ctlr *, struct sk_buff *); +int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *, struct fc_lport *, + struct fc_frame *); + +/* libfcoe funcs */ +u64 fcoe_wwn_from_mac(unsigned char mac[], unsigned int, unsigned int); +int fcoe_libfc_config(struct fc_lport *, struct fcoe_ctlr *, + const struct libfc_function_template *, int init_fcp); +u32 fcoe_fc_crc(struct fc_frame *fp); +int fcoe_start_io(struct sk_buff *skb); +int fcoe_get_wwn(struct net_device *netdev, u64 *wwn, int type); +void __fcoe_get_lesb(struct fc_lport *lport, struct fc_els_lesb *fc_lesb, + struct net_device *netdev); +void fcoe_wwn_to_str(u64 wwn, char *buf, int len); +int fcoe_validate_vport_create(struct fc_vport *vport); +int fcoe_link_speed_update(struct fc_lport *); +void fcoe_get_lesb(struct fc_lport *, struct fc_els_lesb *); +void fcoe_ctlr_get_lesb(struct fcoe_ctlr_device *ctlr_dev); + +/** + * is_fip_mode() - returns true if FIP mode selected. + * @fip: FCoE controller. + */ +static inline bool is_fip_mode(struct fcoe_ctlr *fip) +{ + return fip->state == FIP_ST_ENABLED; +} + +/* helper for FCoE SW HBA drivers, can include subven and subdev if needed. The + * modpost would use pci_device_id table to auto-generate formatted module alias + * into the corresponding .mod.c file, but there may or may not be a pci device + * id table for FCoE drivers so we use the following helper for build the fcoe + * driver module alias. + */ +#define MODULE_ALIAS_FCOE_PCI(ven, dev) \ + MODULE_ALIAS("fcoe-pci:" \ + "v" __stringify(ven) \ + "d" __stringify(dev) "sv*sd*bc*sc*i*") + +/* the name of the default FCoE transport driver fcoe.ko */ +#define FCOE_TRANSPORT_DEFAULT "fcoe" + +/* struct fcoe_transport - The FCoE transport interface + * @name: a vendor specific name for their FCoE transport driver + * @attached: whether this transport is already attached + * @list: list linkage to all attached transports + * @match: handler to allow the transport driver to match up a given netdev + * @alloc: handler to allocate per-instance FCoE structures + * (no discovery or login) + * @create: handler to sysfs entry of create for FCoE instances + * @destroy: handler to delete per-instance FCoE structures + * (frees all memory) + * @enable: handler to sysfs entry of enable for FCoE instances + * @disable: handler to sysfs entry of disable for FCoE instances + */ +struct fcoe_transport { + char name[IFNAMSIZ]; + bool attached; + struct list_head list; + bool (*match) (struct net_device *device); + int (*alloc) (struct net_device *device); + int (*create) (struct net_device *device, enum fip_state fip_mode); + int (*destroy) (struct net_device *device); + int (*enable) (struct net_device *device); + int (*disable) (struct net_device *device); +}; + +/** + * struct fcoe_percpu_s - The context for FCoE receive thread(s) + * @thread: The thread context + * @fcoe_rx_list: The queue of pending packets to process + * @page: The memory page for calculating frame trailer CRCs + * @crc_eof_offset: The offset into the CRC page pointing to available + * memory for a new trailer + */ +struct fcoe_percpu_s { + struct task_struct *thread; + struct sk_buff_head fcoe_rx_list; + struct page *crc_eof_page; + int crc_eof_offset; +}; + +/** + * struct fcoe_port - The FCoE private structure + * @priv: The associated fcoe interface. The structure is + * defined by the low level driver + * @lport: The associated local port + * @fcoe_pending_queue: The pending Rx queue of skbs + * @fcoe_pending_queue_active: Indicates if the pending queue is active + * @max_queue_depth: Max queue depth of pending queue + * @min_queue_depth: Min queue depth of pending queue + * @timer: The queue timer + * @destroy_work: Handle for work context + * (to prevent RTNL deadlocks) + * @data_srt_addr: Source address for data + * + * An instance of this structure is to be allocated along with the + * Scsi_Host and libfc fc_lport structures. + */ +struct fcoe_port { + void *priv; + struct fc_lport *lport; + struct sk_buff_head fcoe_pending_queue; + u8 fcoe_pending_queue_active; + u32 max_queue_depth; + u32 min_queue_depth; + struct timer_list timer; + struct work_struct destroy_work; + u8 data_src_addr[ETH_ALEN]; + struct net_device * (*get_netdev)(const struct fc_lport *lport); +}; + +/** + * fcoe_get_netdev() - Return the net device associated with a local port + * @lport: The local port to get the net device from + */ +static inline struct net_device *fcoe_get_netdev(const struct fc_lport *lport) +{ + struct fcoe_port *port = ((struct fcoe_port *)lport_priv(lport)); + + return (port->get_netdev) ? port->get_netdev(lport) : NULL; +} + +void fcoe_clean_pending_queue(struct fc_lport *); +void fcoe_check_wait_queue(struct fc_lport *lport, struct sk_buff *skb); +void fcoe_queue_timer(ulong lport); +int fcoe_get_paged_crc_eof(struct sk_buff *skb, int tlen, + struct fcoe_percpu_s *fps); + +/* FCoE Sysfs helpers */ +void fcoe_fcf_get_selected(struct fcoe_fcf_device *); +void fcoe_ctlr_set_fip_mode(struct fcoe_ctlr_device *); + +/** + * struct netdev_list + * A mapping from netdevice to fcoe_transport + */ +struct fcoe_netdev_mapping { + struct list_head list; + struct net_device *netdev; + struct fcoe_transport *ft; +}; + +/* fcoe transports registration and deregistration */ +int fcoe_transport_attach(struct fcoe_transport *ft); +int fcoe_transport_detach(struct fcoe_transport *ft); + +/* sysfs store handler for ctrl_control interface */ +ssize_t fcoe_ctlr_create_store(struct bus_type *bus, + const char *buf, size_t count); +ssize_t fcoe_ctlr_destroy_store(struct bus_type *bus, + const char *buf, size_t count); + +#endif /* _LIBFCOE_H */ + + diff --git a/kernel/include/scsi/libiscsi.h b/kernel/include/scsi/libiscsi.h new file mode 100644 index 000000000..4d1c46aac --- /dev/null +++ b/kernel/include/scsi/libiscsi.h @@ -0,0 +1,495 @@ +/* + * 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 <linux/kfifo.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, +}; + +#define ISID_SIZE 6 + +/* 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 */ + ISCSI_TASK_REQUEUE_SCSIQ, /* qcmd requeueing to scsi-ml */ +}; + +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; + struct scsi_lun lun; + + 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; + + /* T10 protection information */ + bool protected; + + /* 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; + uint32_t 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; + + unsigned max_segment_size; + unsigned tcp_xmit_wsf; + unsigned tcp_recv_wsf; + uint16_t keepalive_tmo; + uint16_t local_port; + uint8_t tcp_timestamp_stat; + uint8_t tcp_nagle_disable; + uint8_t tcp_wsf_disable; + uint8_t tcp_timer_scale; + uint8_t tcp_timestamp_en; + uint8_t fragment_disable; + uint8_t ipv4_tos; + uint8_t ipv6_traffic_class; + uint8_t ipv6_flow_label; + uint8_t is_fw_assigned_ipv6; + char *local_ipaddr; + + /* 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 tgt_reset_timeout; + int initial_r2t_en; + unsigned short 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 *targetalias; + char *ifacename; + char *initiatorname; + char *boot_root; + char *boot_nic; + char *boot_target; + char *portal_type; + char *discovery_parent_type; + uint16_t discovery_parent_idx; + uint16_t def_taskmgmt_tmo; + uint16_t tsid; + uint8_t auto_snd_tgt_disable; + uint8_t discovery_sess; + uint8_t chap_auth_en; + uint8_t discovery_logout_en; + uint8_t bidi_chap_en; + uint8_t discovery_auth_optional; + uint8_t isid[ISID_SIZE]; + + /* control data */ + struct iscsi_transport *tt; + struct Scsi_Host *host; + struct iscsi_conn *leadconn; /* leading connection */ + /* Between the forward and the backward locks exists a strict locking + * hierarchy. The mutual exclusion zone protected by the forward lock + * can enclose the mutual exclusion zone protected by the backward lock + * but not vice versa. + */ + spinlock_t frwd_lock; /* protects session state, * + * cmdsn, queued_cmdsn * + * session resources: * + * - cmdpool kfifo_out , * + * - mgmtpool, */ + spinlock_t back_lock; /* protects cmdsn_exp * + * cmdsn_max, * + * cmdpool kfifo_in */ + 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; + + 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_eh_abort(struct scsi_cmnd *sc); +extern int iscsi_eh_recover_target(struct scsi_cmnd *sc); +extern int iscsi_eh_session_reset(struct scsi_cmnd *sc); +extern int iscsi_eh_device_reset(struct scsi_cmnd *sc); +extern int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc); + +/* + * 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 int iscsi_conn_get_addr_param(struct sockaddr_storage *addr, + 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_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); +extern int iscsi_switch_str_param(char **, char *); + +/* + * 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 diff --git a/kernel/include/scsi/libiscsi_tcp.h b/kernel/include/scsi/libiscsi_tcp.h new file mode 100644 index 000000000..2a7aa75dd --- /dev/null +++ b/kernel/include/scsi/libiscsi_tcp.h @@ -0,0 +1,136 @@ +/* + * 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; + bool atomic_mapped; + + iscsi_segment_done_fn_t *done; +}; + +/* Socket connection receive 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; + spinlock_t pool2queue; + spinlock_t queue2pool; +}; + +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 int iscsi_tcp_set_max_r2t(struct iscsi_conn *conn, char *buf); +extern void iscsi_tcp_conn_get_stats(struct iscsi_cls_conn *cls_conn, + struct iscsi_stats *stats); +#endif /* LIBISCSI_TCP_H */ diff --git a/kernel/include/scsi/libsas.h b/kernel/include/scsi/libsas.h new file mode 100644 index 000000000..dae99d7d2 --- /dev/null +++ b/kernel/include/scsi/libsas.h @@ -0,0 +1,734 @@ +/* + * 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> +#include <linux/slab.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 */ + PHYE_RESUME_TIMEOUT = 4, + PHY_NUM_EVENTS = 5, +}; + +enum discover_event { + DISCE_DISCOVER_DOMAIN = 0U, + DISCE_REVALIDATE_DOMAIN = 1, + DISCE_PORT_GONE = 2, + DISCE_PROBE = 3, + DISCE_SUSPEND = 4, + DISCE_RESUME = 5, + DISCE_DESTRUCT = 6, + DISC_NUM_EVENTS = 7, +}; + +/* ---------- 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_device_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; + + int 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; + + int ex_change_count; + u16 max_route_indexes; + u8 num_phys; + + u8 t2t_supp:1; + u8 configuring:1; + u8 conf_route_table:1; + + u8 enclosure_logical_id[8]; + + struct ex_phy *ex_phy; + struct sas_port *parent_port; + + struct mutex cmd_mutex; +}; + +/* ---------- SATA device ---------- */ +#define ATA_RESP_FIS_SIZE 24 + +struct sata_device { + unsigned int class; + struct smp_resp rps_resp; /* report_phy_sata_resp */ + u8 port_no; /* port number, if this is a PM (Port) */ + + struct ata_port *ap; + struct ata_host ata_host; + u8 fis[ATA_RESP_FIS_SIZE]; +}; + +struct ssp_device { + struct list_head eh_list_node; /* pending a user requested eh action */ + struct scsi_lun reset_lun; +}; + +enum { + SAS_DEV_GONE, + SAS_DEV_FOUND, /* device notified to lldd */ + SAS_DEV_DESTROY, + SAS_DEV_EH_PENDING, + SAS_DEV_LU_RESET, + SAS_DEV_RESET, +}; + +struct domain_device { + spinlock_t done_lock; + enum sas_device_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 sas_phy *phy; + + struct list_head dev_list_node; + struct list_head disco_list_node; /* awaiting probe or destruct */ + + 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 */ + struct ssp_device ssp_dev; + }; + + void *lldd_dev; + unsigned long state; + struct kref kref; +}; + +struct sas_work { + struct list_head drain_node; + struct work_struct work; +}; + +static inline void INIT_SAS_WORK(struct sas_work *sw, void (*fn)(struct work_struct *)) +{ + INIT_WORK(&sw->work, fn); + INIT_LIST_HEAD(&sw->drain_node); +} + +struct sas_discovery_event { + struct sas_work work; + struct asd_sas_port *port; +}; + +static inline struct sas_discovery_event *to_sas_discovery_event(struct work_struct *work) +{ + struct sas_discovery_event *ev = container_of(work, typeof(*ev), work.work); + + return ev; +} + +struct sas_discovery { + 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; + struct list_head disco_list; + struct list_head destroy_list; + enum sas_linkrate linkrate; + + struct sas_work work; + int suspended; + +/* 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 sas_work work; + struct asd_sas_phy *phy; +}; + +static inline struct asd_sas_event *to_asd_sas_event(struct work_struct *work) +{ + struct asd_sas_event *ev = container_of(work, typeof(*ev), work.work); + + return ev; +} + +/* The phy pretty much is controlled by the LLDD. + * The class only reads those fields. + */ +struct asd_sas_phy { +/* private: */ + 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; + int suspended; + + 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; + +}; + +struct sas_ha_event { + struct sas_work work; + struct sas_ha_struct *ha; +}; + +static inline struct sas_ha_event *to_sas_ha_event(struct work_struct *work) +{ + struct sas_ha_event *ev = container_of(work, typeof(*ev), work.work); + + return ev; +} + +enum sas_ha_state { + SAS_HA_REGISTERED, + SAS_HA_DRAINING, + SAS_HA_ATA_EH_ACTIVE, + SAS_HA_FROZEN, +}; + +struct sas_ha_struct { +/* private: */ + struct sas_ha_event ha_events[HA_NUM_EVENTS]; + unsigned long pending; + + struct list_head defer_q; /* work queued while draining */ + struct mutex drain_mutex; + unsigned long state; + spinlock_t lock; + int eh_active; + wait_queue_head_t eh_wait_q; + struct list_head eh_dev_q; + + struct mutex disco_mutex; + + 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 */ + + int strict_wide_ports; /* both sas_addr and attached_sas_addr must match + * their siblings when forming wide ports */ + + /* 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; /* complete via scsi_eh_flush_done_q */ + struct list_head eh_ata_q; /* scmds to promote from sas to ata eh */ +}; + +#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 ata_device *sas_to_ata_dev(struct domain_device *dev) +{ + return &dev->sata_dev.ap->link.device[0]; +} + +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; +} + +static inline unsigned int to_sas_gpio_od(int device, int bit) +{ + return 3 * device + bit; +} + +static inline void sas_put_local_phy(struct sas_phy *phy) +{ + put_device(&phy->dev); +} + +#ifdef CONFIG_SCSI_SAS_HOST_SMP +int try_test_sas_gpio_gp_bit(unsigned int od, u8 *data, u8 index, u8 count); +#else +static inline int try_test_sas_gpio_gp_bit(unsigned int od, u8 *data, u8 index, u8 count) +{ + return -1; +} +#endif + +/* ---------- 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 { + /* The SAM_STAT_.. codes fit in the lower 6 bits, alias some of + * them here to silence 'case value not in enumerated type' warnings + */ + __SAM_STAT_CHECK_CONDITION = SAM_STAT_CHECK_CONDITION, + + 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[ATA_RESP_FIS_SIZE]; /* dev to host or data-in */ +}; + +#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; + struct scsi_cmnd *cmd; +}; + +struct sas_task { + struct domain_device *dev; + + spinlock_t task_state_lock; + unsigned task_state_flags; + + enum sas_protocol task_proto; + + 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 sas_task_slow *slow_task; +}; + +struct sas_task_slow { + /* standard/extra infrastructure for slow path commands (SMP and + * internal lldd commands + */ + struct timer_list timer; + struct completion completion; +}; + +#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 + +extern struct sas_task *sas_alloc_task(gfp_t flags); +extern struct sas_task *sas_alloc_slow_task(gfp_t flags); +extern void sas_free_task(struct sas_task *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 *, 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_ata_check_ready)(struct domain_device *); + void (*lldd_ata_set_dmamode)(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 *); + + /* GPIO support */ + int (*lldd_write_gpio)(struct sas_ha_struct *, u8 reg_type, + u8 reg_index, u8 reg_count, u8 *write_data); +}; + +extern int sas_register_ha(struct sas_ha_struct *); +extern int sas_unregister_ha(struct sas_ha_struct *); +extern void sas_prep_resume_ha(struct sas_ha_struct *sas_ha); +extern void sas_resume_ha(struct sas_ha_struct *sas_ha); +extern void sas_suspend_ha(struct sas_ha_struct *sas_ha); + +int sas_set_phy_speed(struct sas_phy *phy, + struct sas_phy_linkrates *rates); +int sas_phy_reset(struct sas_phy *phy, int hard_reset); +extern int sas_queuecommand(struct Scsi_Host * ,struct scsi_cmnd *); +extern int sas_target_alloc(struct scsi_target *); +extern int sas_slave_configure(struct scsi_device *); +extern int sas_change_queue_depth(struct scsi_device *, int new_depth); +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, int gone); +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 asd_sas_port *port, struct domain_device *); + +void sas_init_dev(struct domain_device *); + +void sas_task_abort(struct sas_task *); +int sas_eh_abort_handler(struct scsi_cmnd *cmd); +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_drain_work(struct sas_ha_struct *ha); + +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_get_local_phy(struct domain_device *dev); + +int sas_request_addr(struct Scsi_Host *shost, u8 *addr); + +#endif /* _SASLIB_H_ */ diff --git a/kernel/include/scsi/osd_attributes.h b/kernel/include/scsi/osd_attributes.h new file mode 100644 index 000000000..303ba1118 --- /dev/null +++ b/kernel/include/scsi/osd_attributes.h @@ -0,0 +1,397 @@ +#ifndef __OSD_ATTRIBUTES_H__ +#define __OSD_ATTRIBUTES_H__ + +#include <scsi/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__*/ diff --git a/kernel/include/scsi/osd_initiator.h b/kernel/include/scsi/osd_initiator.h new file mode 100644 index 000000000..a09cca829 --- /dev/null +++ b/kernel/include/scsi/osd_initiator.h @@ -0,0 +1,515 @@ +/* + * osd_initiator.h - OSD initiator API definition + * + * Copyright (C) 2008 Panasas Inc. All rights reserved. + * + * Authors: + * Boaz Harrosh <ooo@electrozaur.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 <scsi/osd_protocol.h> +#include <scsi/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; + unsigned def_timeout; + +#ifdef OSD_VER1_SUPPORT + enum osd_std_version version; +#endif +}; + +/* Unique Identification of an OSD device */ +struct osd_dev_info { + unsigned systemid_len; + u8 systemid[OSD_SYSTEMID_LEN]; + unsigned osdname_len; + u8 *osdname; +}; + +/* Retrieve/return osd_dev(s) for use by Kernel clients + * Use IS_ERR/ERR_PTR on returned "osd_dev *". + */ +struct osd_dev *osduld_path_lookup(const char *dev_name); +struct osd_dev *osduld_info_lookup(const struct osd_dev_info *odi); +void osduld_put_device(struct osd_dev *od); + +const struct osd_dev_info *osduld_device_info(struct osd_dev *od); +bool osduld_device_same(struct osd_dev *od, const struct osd_dev_info *odi); + +/* 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); + +/** + * osd_auto_detect_ver - Detect the OSD version, return Unique Identification + * + * @od: OSD target lun handle + * @caps: Capabilities authorizing OSD root read attributes access + * @odi: Retrieved information uniquely identifying the osd target lun + * Note: odi->osdname must be kfreed by caller. + * + * Auto detects the OSD version of the OSD target and sets the @od + * accordingly. Meanwhile also returns the "system id" and "osd name" root + * attributes which uniquely identify the OSD target. This member is usually + * called by the ULD. ULD users should call osduld_device_info(). + * This rutine allocates osd requests and memory at GFP_KERNEL level and might + * sleep. + */ +int osd_auto_detect_ver(struct osd_dev *od, + void *caps, struct osd_dev_info *odi); + +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 +} + +static inline bool osd_dev_is_ver1(struct osd_dev *od) +{ +#ifdef OSD_VER1_SUPPORT + return od->version == OSD_VER1; +#else + return false; +#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; + } cdb_cont, set_attr, enc_get_attr, get_attr; + + struct _osd_io_info { + struct bio *bio; + u64 total_bytes; + u64 residual; + struct request *req; + struct _osd_req_data_segment *last_seg; + u8 *pad_buff; + } out, in; + + gfp_t alloc_flags; + unsigned timeout; + unsigned retries; + unsigned sense_len; + u8 sense[OSD_MAX_SENSE_LEN]; + enum osd_attributes_mode attributes_mode; + + osd_req_done_fn *async_done; + void *async_private; + int async_error; + int req_errors; +}; + +static inline bool osd_req_is_ver1(struct osd_request *or) +{ + return osd_dev_is_ver1(or->osd_dev); +} + +/* + * 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 - Receives 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 received 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, osd_request results are 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. + */ + +/** + * osd_err_priority - osd categorized return codes in ascending severity. + * + * The categories are borrowed from the pnfs_osd_errno enum. + * See comments for translated Linux codes returned by osd_req_decode_sense. + */ +enum osd_err_priority { + OSD_ERR_PRI_NO_ERROR = 0, + /* Recoverable, caller should clear_highpage() all pages */ + OSD_ERR_PRI_CLEAR_PAGES = 1, /* -EFAULT */ + OSD_ERR_PRI_RESOURCE = 2, /* -ENOMEM */ + OSD_ERR_PRI_BAD_CRED = 3, /* -EINVAL */ + OSD_ERR_PRI_NO_ACCESS = 4, /* -EACCES */ + OSD_ERR_PRI_UNREACHABLE = 5, /* any other */ + OSD_ERR_PRI_NOT_FOUND = 6, /* -ENOENT */ + OSD_ERR_PRI_NO_SPACE = 7, /* -ENOSPC */ + OSD_ERR_PRI_EIO = 8, /* -EIO */ +}; + +struct osd_sense_info { + enum osd_err_priority osd_err_pri; + + 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); + +/* Scatter/Gather write/read commands */ +int osd_req_write_sg(struct osd_request *or, + const struct osd_obj_id *obj, struct bio *bio, + const struct osd_sg_entry *sglist, unsigned numentries); +int osd_req_read_sg(struct osd_request *or, + const struct osd_obj_id *obj, struct bio *bio, + const struct osd_sg_entry *sglist, unsigned numentries); +int osd_req_write_sg_kern(struct osd_request *or, + const struct osd_obj_id *obj, void **buff, + const struct osd_sg_entry *sglist, unsigned numentries); +int osd_req_read_sg_kern(struct osd_request *or, + const struct osd_obj_id *obj, void **buff, + const struct osd_sg_entry *sglist, unsigned numentries); + +/* + * 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__ */ diff --git a/kernel/include/scsi/osd_ore.h b/kernel/include/scsi/osd_ore.h new file mode 100644 index 000000000..7a8d2cd30 --- /dev/null +++ b/kernel/include/scsi/osd_ore.h @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2011 + * Boaz Harrosh <ooo@electrozaur.com> + * + * Public Declarations of the ORE API + * + * This file is part of the ORE (Object Raid Engine) library. + * + * ORE is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. (GPL v2) + * + * ORE 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 the ORE; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef __ORE_H__ +#define __ORE_H__ + +#include <scsi/osd_initiator.h> +#include <scsi/osd_attributes.h> +#include <scsi/osd_sec.h> +#include <linux/pnfs_osd_xdr.h> +#include <linux/bug.h> + +struct ore_comp { + struct osd_obj_id obj; + u8 cred[OSD_CAP_LEN]; +}; + +struct ore_layout { + /* Our way of looking at the data_map */ + enum pnfs_osd_raid_algorithm4 + raid_algorithm; + unsigned stripe_unit; + unsigned mirrors_p1; + + unsigned group_width; + unsigned parity; + u64 group_depth; + unsigned group_count; + + /* Cached often needed calculations filled in by + * ore_verify_layout + */ + unsigned long max_io_length; /* Max length that should be passed to + * ore_get_rw_state + */ +}; + +struct ore_dev { + struct osd_dev *od; +}; + +struct ore_components { + unsigned first_dev; /* First logical device no */ + unsigned numdevs; /* Num of devices in array */ + /* If @single_comp == EC_SINGLE_COMP, @comps points to a single + * component. else there are @numdevs components + */ + enum EC_COMP_USAGE { + EC_SINGLE_COMP = 0, EC_MULTPLE_COMPS = 0xffffffff + } single_comp; + struct ore_comp *comps; + + /* Array of pointers to ore_dev-* . User will usually have these pointed + * too a bigger struct which contain an "ore_dev ored" member and use + * container_of(oc->ods[i], struct foo_dev, ored) to access the bigger + * structure. + */ + struct ore_dev **ods; +}; + +/* ore_comp_dev Recievies a logical device index */ +static inline struct osd_dev *ore_comp_dev( + const struct ore_components *oc, unsigned i) +{ + BUG_ON((i < oc->first_dev) || (oc->first_dev + oc->numdevs <= i)); + return oc->ods[i - oc->first_dev]->od; +} + +static inline void ore_comp_set_dev( + struct ore_components *oc, unsigned i, struct osd_dev *od) +{ + oc->ods[i - oc->first_dev]->od = od; +} + +struct ore_striping_info { + u64 offset; + u64 obj_offset; + u64 length; + u64 first_stripe_start; /* only used in raid writes */ + u64 M; /* for truncate */ + unsigned bytes_in_stripe; + unsigned dev; + unsigned par_dev; + unsigned unit_off; + unsigned cur_pg; + unsigned cur_comp; + unsigned maxdevUnits; +}; + +struct ore_io_state; +typedef void (*ore_io_done_fn)(struct ore_io_state *ios, void *private); +struct _ore_r4w_op { + /* @Priv given here is passed ios->private */ + struct page * (*get_page)(void *priv, u64 page_index, bool *uptodate); + void (*put_page)(void *priv, struct page *page); +}; + +struct ore_io_state { + struct kref kref; + struct ore_striping_info si; + + void *private; + ore_io_done_fn done; + + struct ore_layout *layout; + struct ore_components *oc; + + /* Global read/write IO*/ + loff_t offset; + unsigned long length; + void *kern_buff; + + struct page **pages; + unsigned nr_pages; + unsigned pgbase; + unsigned pages_consumed; + + /* Attributes */ + unsigned in_attr_len; + struct osd_attr *in_attr; + unsigned out_attr_len; + struct osd_attr *out_attr; + + bool reading; + + /* House keeping of Parity pages */ + bool extra_part_alloc; + struct page **parity_pages; + unsigned max_par_pages; + unsigned cur_par_page; + unsigned sgs_per_dev; + struct __stripe_pages_2d *sp2d; + struct ore_io_state *ios_read_4_write; + const struct _ore_r4w_op *r4w; + + /* Variable array of size numdevs */ + unsigned numdevs; + struct ore_per_dev_state { + struct osd_request *or; + struct bio *bio; + loff_t offset; + unsigned length; + unsigned last_sgs_total; + unsigned dev; + struct osd_sg_entry *sglist; + unsigned cur_sg; + } per_dev[]; +}; + +static inline unsigned ore_io_state_size(unsigned numdevs) +{ + return sizeof(struct ore_io_state) + + sizeof(struct ore_per_dev_state) * numdevs; +} + +/* ore.c */ +int ore_verify_layout(unsigned total_comps, struct ore_layout *layout); +void ore_calc_stripe_info(struct ore_layout *layout, u64 file_offset, + u64 length, struct ore_striping_info *si); +int ore_get_rw_state(struct ore_layout *layout, struct ore_components *comps, + bool is_reading, u64 offset, u64 length, + struct ore_io_state **ios); +int ore_get_io_state(struct ore_layout *layout, struct ore_components *comps, + struct ore_io_state **ios); +void ore_put_io_state(struct ore_io_state *ios); + +typedef void (*ore_on_dev_error)(struct ore_io_state *ios, struct ore_dev *od, + unsigned dev_index, enum osd_err_priority oep, + u64 dev_offset, u64 dev_len); +int ore_check_io(struct ore_io_state *ios, ore_on_dev_error rep); + +int ore_create(struct ore_io_state *ios); +int ore_remove(struct ore_io_state *ios); +int ore_write(struct ore_io_state *ios); +int ore_read(struct ore_io_state *ios); +int ore_truncate(struct ore_layout *layout, struct ore_components *comps, + u64 size); + +int extract_attr_from_ios(struct ore_io_state *ios, struct osd_attr *attr); + +extern const struct osd_attr g_attr_logical_length; + +#endif diff --git a/kernel/include/scsi/osd_protocol.h b/kernel/include/scsi/osd_protocol.h new file mode 100644 index 000000000..e0ca835e7 --- /dev/null +++ b/kernel/include/scsi/osd_protocol.h @@ -0,0 +1,676 @@ +/* + * osd_protocol.h - OSD T10 standard C definitions. + * + * Copyright (C) 2008 Panasas Inc. All rights reserved. + * + * Authors: + * Boaz Harrosh <ooo@electrozaur.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 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 = cpu_to_be16(0x8880 + Num), \ + OSDv1_ACT_##Name = cpu_to_be16(0x8800 + Num), + +/* V2 only actions */ +#define OSD_ACT_V2(Name, Num) \ + OSD_ACT_##Name = cpu_to_be16(0x8880 + Num), + +#define OSD_ACT_V1_V2(Name, Num1, Num2) \ + OSD_ACT_##Name = cpu_to_be16(Num2), \ + OSDv1_ACT_##Name = 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 ooo@electrozaur.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); +} + +/* osd2r05a sec 5.3: CDB continuation segment formats */ +enum osd_continuation_segment_format { + CDB_CONTINUATION_FORMAT_V2 = 0x01, +}; + +struct osd_continuation_segment_header { + u8 format; + u8 reserved1; + __be16 service_action; + __be32 reserved2; + u8 integrity_check[OSDv2_CRYPTO_KEYID_SIZE]; +} __packed; + +/* osd2r05a sec 5.4.1: CDB continuation descriptors */ +enum osd_continuation_descriptor_type { + NO_MORE_DESCRIPTORS = 0x0000, + SCATTER_GATHER_LIST = 0x0001, + QUERY_LIST = 0x0002, + USER_OBJECT = 0x0003, + COPY_USER_OBJECT_SOURCE = 0x0101, + EXTENSION_CAPABILITIES = 0xFFEE +}; + +struct osd_continuation_descriptor_header { + __be16 type; + u8 reserved; + u8 pad_length; + __be32 length; +} __packed; + + +/* osd2r05a sec 5.4.2: Scatter/gather list */ +struct osd_sg_list_entry { + __be64 offset; + __be64 len; +}; + +struct osd_sg_continuation_descriptor { + struct osd_continuation_descriptor_header hdr; + struct osd_sg_list_entry entries[]; +}; + +#endif /* ndef __OSD_PROTOCOL_H__ */ diff --git a/kernel/include/scsi/osd_sec.h b/kernel/include/scsi/osd_sec.h new file mode 100644 index 000000000..7abeb0f0d --- /dev/null +++ b/kernel/include/scsi/osd_sec.h @@ -0,0 +1,45 @@ +/* + * osd_sec.h - OSD security manager API + * + * Copyright (C) 2008 Panasas Inc. All rights reserved. + * + * Authors: + * Boaz Harrosh <ooo@electrozaur.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 <scsi/osd_protocol.h> +#include <scsi/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__ */ diff --git a/kernel/include/scsi/osd_sense.h b/kernel/include/scsi/osd_sense.h new file mode 100644 index 000000000..d52aa93a0 --- /dev/null +++ b/kernel/include/scsi/osd_sense.h @@ -0,0 +1,263 @@ +/* + * osd_sense.h - OSD Related sense handling definitions. + * + * Copyright (C) 2008 Panasas Inc. All rights reserved. + * + * Authors: + * Boaz Harrosh <ooo@electrozaur.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), + OSD_CFO_PERMISSIONS = sizeof(struct osd_cdb_head) + + offsetof(struct osd_capability_head, + permissions_bit_mask), +}; + +#endif /* ndef __OSD_SENSE_H__ */ diff --git a/kernel/include/scsi/osd_types.h b/kernel/include/scsi/osd_types.h new file mode 100644 index 000000000..48e8a165e --- /dev/null +++ b/kernel/include/scsi/osd_types.h @@ -0,0 +1,45 @@ +/* + * osd_types.h - Types and constants which are not part of the protocol. + * + * Copyright (C) 2008 Panasas Inc. All rights reserved. + * + * Authors: + * Boaz Harrosh <ooo@electrozaur.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 */ +}; + +struct osd_sg_entry { + u64 offset; + u64 len; +}; + +#endif /* ndef __OSD_TYPES_H__ */ diff --git a/kernel/include/scsi/sas.h b/kernel/include/scsi/sas.h new file mode 100644 index 000000000..0d2607d12 --- /dev/null +++ b/kernel/include/scsi/sas.h @@ -0,0 +1,653 @@ +/* + * 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_device_type { + /* these are SAS protocol defined (attached device type field) */ + SAS_PHY_UNUSED = 0, + SAS_END_DEVICE = 1, + SAS_EDGE_EXPANDER_DEVICE = 2, + SAS_FANOUT_EXPANDER_DEVICE = 3, + /* these are internal to libsas */ + SAS_HA = 4, + SAS_SATA_DEV = 5, + SAS_SATA_PM = 7, + SAS_SATA_PM_PORT = 8, + SAS_SATA_PENDING = 9, +}; + +enum sas_protocol { + SAS_PROTOCOL_NONE = 0, + SAS_PROTOCOL_SATA = 0x01, + SAS_PROTOCOL_SMP = 0x02, + SAS_PROTOCOL_STP = 0x04, + SAS_PROTOCOL_SSP = 0x08, + SAS_PROTOCOL_ALL = 0x0E, + SAS_PROTOCOL_STP_ALL = SAS_PROTOCOL_STP|SAS_PROTOCOL_SATA, +}; + +/* 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, + PHY_FUNC_GET_EVENTS, +}; + +/* 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, +}; + +enum sas_gpio_reg_type { + SAS_GPIO_REG_CFG = 0, + SAS_GPIO_REG_RX = 1, + SAS_GPIO_REG_RX_GP = 2, + SAS_GPIO_REG_TX = 3, + SAS_GPIO_REG_TX_GP = 4, +}; + +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 config_others:1; + u8 orej_retry_supp:1; + u8 stp_cont_awt:1; + u8 self_config:1; + u8 zone_config:1; + u8 t2t_supp: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_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 t2t_supp:1; + u8 zone_config:1; + u8 self_config:1; + u8 stp_cont_awt:1; + u8 orej_retry_supp:1; + u8 config_others:1; + 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_ */ diff --git a/kernel/include/scsi/sas_ata.h b/kernel/include/scsi/sas_ata.h new file mode 100644 index 000000000..00f41aeee --- /dev/null +++ b/kernel/include/scsi/sas_ata.h @@ -0,0 +1,105 @@ +/* + * 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->dev_type == SAS_SATA_DEV || dev->dev_type == SAS_SATA_PM || + dev->dev_type == SAS_SATA_PM_PORT || dev->dev_type == SAS_SATA_PENDING; +} + +int sas_get_ata_info(struct domain_device *dev, struct ex_phy *phy); +int sas_ata_init(struct domain_device *dev); +void sas_ata_task_abort(struct sas_task *task); +void sas_ata_strategy_handler(struct Scsi_Host *shost); +void sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q, + struct list_head *done_q); +void sas_ata_schedule_reset(struct domain_device *dev); +void sas_ata_wait_eh(struct domain_device *dev); +void sas_probe_sata(struct asd_sas_port *port); +void sas_suspend_sata(struct asd_sas_port *port); +void sas_resume_sata(struct asd_sas_port *port); +void sas_ata_end_eh(struct ata_port *ap); +#else + + +static inline int dev_is_sata(struct domain_device *dev) +{ + return 0; +} +static inline int sas_ata_init(struct domain_device *dev) +{ + return 0; +} +static inline void sas_ata_task_abort(struct sas_task *task) +{ +} + +static inline void sas_ata_strategy_handler(struct Scsi_Host *shost) +{ +} + +static inline void sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q, + struct list_head *done_q) +{ +} + +static inline void sas_ata_schedule_reset(struct domain_device *dev) +{ +} + +static inline void sas_ata_wait_eh(struct domain_device *dev) +{ +} + +static inline void sas_probe_sata(struct asd_sas_port *port) +{ +} + +static inline void sas_suspend_sata(struct asd_sas_port *port) +{ +} + +static inline void sas_resume_sata(struct asd_sas_port *port) +{ +} + +static inline int sas_get_ata_info(struct domain_device *dev, struct ex_phy *phy) +{ + return 0; +} + +static inline void sas_ata_end_eh(struct ata_port *ap) +{ +} +#endif + +#endif /* _SAS_ATA_H_ */ diff --git a/kernel/include/scsi/scsi.h b/kernel/include/scsi/scsi.h new file mode 100644 index 000000000..d0a66aa18 --- /dev/null +++ b/kernel/include/scsi/scsi.h @@ -0,0 +1,594 @@ +/* + * 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> +#include <linux/scatterlist.h> +#include <linux/kernel.h> + +struct scsi_cmnd; + +enum scsi_timeouts { + SCSI_DEFAULT_EH_TIMEOUT = 10 * HZ, +}; + +/* + * 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 CONFIG_ARCH_HAS_SG_CHAIN +#define SCSI_MAX_SG_CHAIN_SEGMENTS 2048 +#else +#define SCSI_MAX_SG_CHAIN_SEGMENTS SCSI_MAX_SG_SEGMENTS +#endif + +/* + * DIX-capable adapters effectively support infinite chaining for the + * protection information scatterlist + */ +#define SCSI_MAX_PROT_SG_SEGMENTS 0xFFFF + +/* + * 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 READ_FORMAT_CAPACITIES 0x23 +#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 UNMAP 0x42 +#define READ_TOC 0x43 +#define READ_HEADER 0x44 +#define GET_EVENT_STATUS_NOTIFICATION 0x4a +#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 SECURITY_PROTOCOL_IN 0xa2 +#define MAINTENANCE_IN 0xa3 +#define MAINTENANCE_OUT 0xa4 +#define MOVE_MEDIUM 0xa5 +#define EXCHANGE_MEDIUM 0xa6 +#define READ_12 0xa8 +#define SERVICE_ACTION_OUT_12 0xa9 +#define WRITE_12 0xaa +#define READ_MEDIA_SERIAL_NUMBER 0xab /* Obsolete with SPC-2 */ +#define SERVICE_ACTION_IN_12 0xab +#define WRITE_VERIFY_12 0xae +#define VERIFY_12 0xaf +#define SEARCH_HIGH_12 0xb0 +#define SEARCH_EQUAL_12 0xb1 +#define SEARCH_LOW_12 0xb2 +#define SECURITY_PROTOCOL_OUT 0xb5 +#define READ_ELEMENT_STATUS 0xb8 +#define SEND_VOLUME_TAG 0xb6 +#define WRITE_LONG_2 0xea +#define EXTENDED_COPY 0x83 +#define RECEIVE_COPY_RESULTS 0x84 +#define ACCESS_CONTROL_IN 0x86 +#define ACCESS_CONTROL_OUT 0x87 +#define READ_16 0x88 +#define COMPARE_AND_WRITE 0x89 +#define WRITE_16 0x8a +#define READ_ATTRIBUTE 0x8c +#define WRITE_ATTRIBUTE 0x8d +#define VERIFY_16 0x8f +#define SYNCHRONIZE_CACHE_16 0x91 +#define WRITE_SAME_16 0x93 +#define SERVICE_ACTION_BIDIRECTIONAL 0x9d +#define SERVICE_ACTION_IN_16 0x9e +#define SERVICE_ACTION_OUT_16 0x9f +/* values for service action in */ +#define SAI_READ_CAPACITY_16 0x10 +#define SAI_GET_LBA_STATUS 0x12 +#define SAI_REPORT_REFERRALS 0x13 +/* values for VARIABLE_LENGTH_CMD service action codes + * see spc4r17 Section D.3.5, table D.7 and D.8 */ +#define VLC_SA_RECEIVE_CREDENTIAL 0x1800 +/* values for maintenance in */ +#define MI_REPORT_IDENTIFYING_INFORMATION 0x05 +#define MI_REPORT_TARGET_PGS 0x0a +#define MI_REPORT_ALIASES 0x0b +#define MI_REPORT_SUPPORTED_OPERATION_CODES 0x0c +#define MI_REPORT_SUPPORTED_TASK_MANAGEMENT_FUNCTIONS 0x0d +#define MI_REPORT_PRIORITY 0x0e +#define MI_REPORT_TIMESTAMP 0x0f +#define MI_MANAGEMENT_PROTOCOL_IN 0x10 +/* value for MI_REPORT_TARGET_PGS ext header */ +#define MI_EXT_HDR_PARAM_FMT 0x20 +/* values for maintenance out */ +#define MO_SET_IDENTIFYING_INFORMATION 0x06 +#define MO_SET_TARGET_PGS 0x0a +#define MO_CHANGE_ALIASES 0x0b +#define MO_SET_PRIORITY 0x0e +#define MO_SET_TIMESTAMP 0x0f +#define MO_MANAGEMENT_PROTOCOL_OUT 0x10 +/* values for variable length command */ +#define XDREAD_32 0x03 +#define XDWRITE_32 0x04 +#define XPWRITE_32 0x06 +#define XDWRITEREAD_32 0x07 +#define READ_32 0x09 +#define VERIFY_32 0x0a +#define WRITE_32 0x0b +#define WRITE_SAME_32 0x0d + +/* Values for T10/04-262r7 */ +#define ATA_16 0x85 /* 16-byte pass-thru */ +#define ATA_12 0xa1 /* 12-byte pass-thru */ + +/* Vendor specific CDBs start here */ +#define VENDOR_SPECIFIC_CDB 0xc0 + +/* + * 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]); +} + +#ifdef CONFIG_ACPI +struct acpi_bus_type; + +extern int +scsi_register_acpi_bus_type(struct acpi_bus_type *bus); + +extern void +scsi_unregister_acpi_bus_type(struct acpi_bus_type *bus); +#endif + +/* + * 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_ZBC 0x14 +#define TYPE_WLUN 0x1e /* well-known logical unit */ +#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(u64 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 DID_TARGET_FAILURE 0x10 /* Permanent target failure, do not retry on + * other paths */ +#define DID_NEXUS_FAILURE 0x11 /* Permanent nexus failure, retry on other + * paths might yield different results */ +#define DID_ALLOC_FAILURE 0x12 /* Space allocation on the device failed */ +#define DID_MEDIUM_ERROR 0x13 /* Medium error */ +#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 +#define FAST_IO_FAIL 0x2009 + +/* + * 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 */ diff --git a/kernel/include/scsi/scsi_bsg_iscsi.h b/kernel/include/scsi/scsi_bsg_iscsi.h new file mode 100644 index 000000000..fd5689d4c --- /dev/null +++ b/kernel/include/scsi/scsi_bsg_iscsi.h @@ -0,0 +1,110 @@ +/* + * iSCSI Transport BSG Interface + * + * Copyright (C) 2009 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_ISCSI_H +#define SCSI_BSG_ISCSI_H + +/* + * This file intended to be included by both kernel and user space + */ + +#include <scsi/scsi.h> + +/* + * iSCSI Transport SGIO v4 BSG Message Support + */ + +/* Default BSG request timeout (in seconds) */ +#define ISCSI_DEFAULT_BSG_TIMEOUT (10 * HZ) + + +/* + * Request Message Codes supported by the iSCSI Transport + */ + +/* define the class masks for the message codes */ +#define ISCSI_BSG_CLS_MASK 0xF0000000 /* find object class */ +#define ISCSI_BSG_HST_MASK 0x80000000 /* iscsi host class */ + +/* iscsi host Message Codes */ +#define ISCSI_BSG_HST_VENDOR (ISCSI_BSG_HST_MASK | 0x000000FF) + + +/* + * iSCSI Host Messages + */ + +/* ISCSI_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 iscsi_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 iscsi_bsg_host_vendor_reply { + /* start of vendor response area */ + uint32_t vendor_rsp[0]; +}; + + +/* request (CDB) structure of the sg_io_v4 */ +struct iscsi_bsg_request { + uint32_t msgcode; + union { + struct iscsi_bsg_host_vendor h_vendor; + } rqst_data; +} __attribute__((packed)); + + +/* response (request sense data) structure of the sg_io_v4 */ +struct iscsi_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 iscsi_bsg_host_vendor_reply vendor_reply; + } reply_data; +}; + + +#endif /* SCSI_BSG_ISCSI_H */ diff --git a/kernel/include/scsi/scsi_cmnd.h b/kernel/include/scsi/scsi_cmnd.h new file mode 100644 index 000000000..9fc1aecfc --- /dev/null +++ b/kernel/include/scsi/scsi_cmnd.h @@ -0,0 +1,352 @@ +#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> +#include <scsi/scsi_device.h> + +struct Scsi_Host; +struct scsi_driver; + +#include <scsi/scsi_device.h> + +/* + * 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; +}; + +/* for scmd->flags */ +#define SCMD_TAGGED (1 << 0) + +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 */ + struct delayed_work abort_work; + 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 char prot_flags; + + 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 */ + int flags; /* Command flags */ + + unsigned char tag; /* SCSI-II queued command tag */ +}; + +/* + * Return the driver private allocation behind the command. + * Only works if cmd_size is set in the host template. + */ +static inline void *scsi_cmd_priv(struct scsi_cmnd *cmd) +{ + return cmd + 1; +} + +/* make sure not to use it with REQ_TYPE_BLOCK_PC commands */ +static inline struct scsi_driver *scsi_cmd_to_driver(struct scsi_cmnd *cmd) +{ + return *(struct scsi_driver **)cmd->request->rq_disk->private_data; +} + +extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, gfp_t); +extern void scsi_put_command(struct scsi_cmnd *); +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); + +extern int scsi_dma_map(struct scsi_cmnd *cmd); +extern void scsi_dma_unmap(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; +} + +enum scsi_prot_flags { + SCSI_PROT_TRANSFER_PI = 1 << 0, + SCSI_PROT_GUARD_CHECK = 1 << 1, + SCSI_PROT_REF_CHECK = 1 << 2, + SCSI_PROT_REF_INCREMENT = 1 << 3, + SCSI_PROT_IP_CHECKSUM = 1 << 4, +}; + +/* + * 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 int scsi_prot_interval(struct scsi_cmnd *scmd) +{ + return scmd->device->sector_size; +} + +static inline u32 scsi_prot_ref_tag(struct scsi_cmnd *scmd) +{ + return blk_rq_pos(scmd->request) >> + (ilog2(scsi_prot_interval(scmd)) - 9) & 0xffffffff; +} + +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 = (cmd->result & 0xffff00ff) | (status << 8); +} + +static inline void set_host_byte(struct scsi_cmnd *cmd, char status) +{ + cmd->result = (cmd->result & 0xff00ffff) | (status << 16); +} + +static inline void set_driver_byte(struct scsi_cmnd *cmd, char status) +{ + cmd->result = (cmd->result & 0x00ffffff) | (status << 24); +} + +static inline unsigned scsi_transfer_length(struct scsi_cmnd *scmd) +{ + unsigned int xfer_len = scsi_out(scmd)->length; + unsigned int prot_interval = scsi_prot_interval(scmd); + + if (scmd->prot_flags & SCSI_PROT_TRANSFER_PI) + xfer_len += (xfer_len >> ilog2(prot_interval)) * 8; + + return xfer_len; +} + +#endif /* _SCSI_SCSI_CMND_H */ diff --git a/kernel/include/scsi/scsi_dbg.h b/kernel/include/scsi/scsi_dbg.h new file mode 100644 index 000000000..f8170e90b --- /dev/null +++ b/kernel/include/scsi/scsi_dbg.h @@ -0,0 +1,92 @@ +#ifndef _SCSI_SCSI_DBG_H +#define _SCSI_SCSI_DBG_H + +struct scsi_cmnd; +struct scsi_device; +struct scsi_sense_hdr; + +#define SCSI_LOG_BUFSIZE 128 + +extern void scsi_print_command(struct scsi_cmnd *); +extern size_t __scsi_format_command(char *, size_t, + const unsigned char *, size_t); +extern void scsi_show_extd_sense(const struct scsi_device *, const char *, + unsigned char, unsigned char); +extern void scsi_show_sense_hdr(const struct scsi_device *, const char *, + const struct scsi_sense_hdr *); +extern void scsi_print_sense_hdr(const struct scsi_device *, const char *, + const struct scsi_sense_hdr *); +extern void scsi_print_sense(const struct scsi_cmnd *); +extern void __scsi_print_sense(const struct scsi_device *, const char *name, + const unsigned char *sense_buffer, + int sense_len); +extern void scsi_print_result(const struct scsi_cmnd *, const char *, int); + +#ifdef CONFIG_SCSI_CONSTANTS +extern bool scsi_opcode_sa_name(int, int, const char **, const char **); +extern const char *scsi_sense_key_string(unsigned char); +extern const char *scsi_extd_sense_format(unsigned char, unsigned char, + const char **); +extern const char *scsi_mlreturn_string(int); +extern const char *scsi_hostbyte_string(int); +extern const char *scsi_driverbyte_string(int); +#else +static inline bool +scsi_opcode_sa_name(int cmd, int sa, + const char **cdb_name, const char **sa_name) +{ + *cdb_name = NULL; + switch (cmd) { + case VARIABLE_LENGTH_CMD: + case MAINTENANCE_IN: + case MAINTENANCE_OUT: + case PERSISTENT_RESERVE_IN: + case PERSISTENT_RESERVE_OUT: + case SERVICE_ACTION_IN_12: + case SERVICE_ACTION_OUT_12: + case SERVICE_ACTION_BIDIRECTIONAL: + case SERVICE_ACTION_IN_16: + case SERVICE_ACTION_OUT_16: + case EXTENDED_COPY: + case RECEIVE_COPY_RESULTS: + *sa_name = NULL; + return true; + default: + return false; + } +} + +static inline const char * +scsi_sense_key_string(unsigned char key) +{ + return NULL; +} + +static inline const char * +scsi_extd_sense_format(unsigned char asc, unsigned char ascq, const char **fmt) +{ + *fmt = NULL; + return NULL; +} + +static inline const char * +scsi_mlreturn_string(int result) +{ + return NULL; +} + +static inline const char * +scsi_hostbyte_string(int result) +{ + return NULL; +} + +static inline const char * +scsi_driverbyte_string(int result) +{ + return NULL; +} + +#endif + +#endif /* _SCSI_SCSI_DBG_H */ diff --git a/kernel/include/scsi/scsi_device.h b/kernel/include/scsi/scsi_device.h new file mode 100644 index 000000000..a4c933681 --- /dev/null +++ b/kernel/include/scsi/scsi_device.h @@ -0,0 +1,539 @@ +#ifndef _SCSI_SCSI_DEVICE_H +#define _SCSI_SCSI_DEVICE_H + +#include <linux/list.h> +#include <linux/spinlock.h> +#include <linux/workqueue.h> +#include <linux/blkdev.h> +#include <scsi/scsi.h> +#include <linux/atomic.h> + +struct device; +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_TRANSPORT_OFFLINE, /* Offlined by transport class error handler */ + 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_INQUIRY_CHANGE_REPORTED, /* 3F 03 UA reported */ + SDEV_EVT_CAPACITY_CHANGE_REPORTED, /* 2A 09 UA reported */ + SDEV_EVT_SOFT_THRESHOLD_REACHED_REPORTED, /* 38 07 UA reported */ + SDEV_EVT_MODE_PARAMETER_CHANGE_REPORTED, /* 2A 01 UA reported */ + SDEV_EVT_LUN_CHANGE_REPORTED, /* 3F 0E UA reported */ + + SDEV_EVT_FIRST = SDEV_EVT_MEDIA_CHANGE, + SDEV_EVT_LAST = SDEV_EVT_LUN_CHANGE_REPORTED, + + 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 */ + + atomic_t device_busy; /* commands actually active on LLDD */ + atomic_t device_blocked; /* Device returned QUEUE_FULL. */ + + 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 max_queue_depth; /* max queue depth */ + 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; /* last queue full time */ + unsigned long queue_ramp_up_period; /* ramp up period in jiffies */ +#define SCSI_DEFAULT_RAMP_UP_PERIOD (120 * HZ) + + unsigned long last_queue_ramp_up; /* last queue ramp up time */ + + unsigned int id, channel; + u64 lun; + 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 */ + +#define SCSI_VPD_PG_LEN 255 + int vpd_pg83_len; + unsigned char *vpd_pg83; + int vpd_pg80_len; + unsigned char *vpd_pg80; + 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 int eh_timeout; /* Error handling timeout */ + 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 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 no_report_opcodes:1; /* no REPORT SUPPORTED OPERATION CODES */ + unsigned no_write_same:1; /* no WRITE SAME command */ + unsigned use_16_for_rw:1; /* Use read/write(16) over read/write(10) */ + 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 skip_vpd_pages:1; /* do not read VPD pages */ + unsigned try_vpd_pages:1; /* attempt to read VPD pages */ + 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 no_read_disc_info:1; /* Avoid READ_DISC_INFO cmds */ + unsigned no_read_capacity_16:1; /* Avoid READ_CAPACITY_16 cmds */ + unsigned try_rc_10_first:1; /* Try READ_CAPACACITY_10 first */ + unsigned is_visible:1; /* is the device visible in sysfs */ + unsigned wce_default_on:1; /* Cache is ON by default */ + unsigned no_dif:1; /* T10 PI (DIF) should be disabled */ + unsigned broken_fua:1; /* Don't set FUA bit */ + unsigned lun_in_cdb:1; /* Store LUN bits in CDB[1] */ + + atomic_t disk_events_disable_depth; /* disable depth for disk events */ + + DECLARE_BITMAP(supported_events, SDEV_EVT_MAXBITS); /* supported events */ + DECLARE_BITMAP(pending_events, SDEV_EVT_MAXBITS); /* pending events */ + struct list_head event_list; /* asserted events */ + struct work_struct event_work; + + 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 work_struct requeue_work; + + struct scsi_dh_data *scsi_dh_data; + enum scsi_device_state sdev_state; + unsigned long sdev_data[0]; +} __attribute__((aligned(sizeof(unsigned long)))); + +typedef void (*activate_complete)(void *, int); +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; + int (*check_sense)(struct scsi_device *, struct scsi_sense_hdr *); + struct scsi_dh_data *(*attach)(struct scsi_device *); + void (*detach)(struct scsi_device *); + int (*activate)(struct scsi_device *, activate_complete, void *); + int (*prep_fn)(struct scsi_device *, struct request *); + int (*set_params)(struct scsi_device *, const char *); + bool (*match)(struct scsi_device *); +}; + +struct scsi_dh_data { + struct scsi_device_handler *scsi_dh; + struct scsi_device *sdev; + struct kref kref; +}; + +#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_dbg(sdev, fmt, a...) \ + dev_dbg(&(sdev)->sdev_gendev, fmt, ##a) + +/* + * like scmd_printk, but the device name is passed in + * as a string pointer + */ +__printf(4, 5) void +sdev_prefix_printk(const char *, const struct scsi_device *, const char *, + const char *, ...); + +#define sdev_printk(l, sdev, fmt, a...) \ + sdev_prefix_printk(l, sdev, NULL, fmt, ##a) + +__printf(3, 4) void +scmd_printk(const char *, const struct scsi_cmnd *, const char *, ...); + +#define scmd_dbg(scmd, fmt, a...) \ + do { \ + if ((scmd)->request->rq_disk) \ + sdev_dbg((scmd)->device, "[%s] " fmt, \ + (scmd)->request->rq_disk->disk_name, ##a);\ + else \ + sdev_dbg((scmd)->device, fmt, ##a); \ + } while (0) + +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; + struct kref reap_ref; /* last put renders target invisible */ + 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:1; /* PDT = 0x1f + * means no lun present. */ + unsigned int no_report_luns:1; /* Don't use + * REPORT LUNS for scanning. */ + unsigned int expecting_lun_change:1; /* A device has reported + * a 3F/0E UA, other devices on + * the same target will also. */ + /* commands actually active on LLD. */ + atomic_t target_busy; + atomic_t target_blocked; + + /* + * 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 max_target_blocked; +#define SCSI_DEFAULT_TARGET_BLOCKED 3 + + char scsi_level; + 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, u64, void *hostdata); +extern int scsi_add_device(struct Scsi_Host *host, uint channel, + uint target, u64 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); +void scsi_attach_vpd(struct scsi_device *sdev); + +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, u64); +extern struct scsi_device *__scsi_device_lookup(struct Scsi_Host *, + uint, uint, u64); +extern struct scsi_device *scsi_device_lookup_by_target(struct scsi_target *, + u64); +extern struct scsi_device *__scsi_device_lookup_by_target(struct scsi_target *, + u64); +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 int scsi_change_queue_depth(struct scsi_device *, 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 int scsi_get_vpd_page(struct scsi_device *, u8 page, unsigned char *buf, + int buf_len); +extern int scsi_report_opcode(struct scsi_device *sdev, unsigned char *buffer, + unsigned int len, unsigned char opcode); +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, u64 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 *, enum scsi_device_state); +extern void scsi_remove_target(struct device *); +extern void int_to_scsilun(u64, struct scsi_lun *); +extern u64 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, + u64 flags, int *resid); +extern int scsi_execute_req_flags(struct scsi_device *sdev, + const unsigned char *cmd, int data_direction, void *buffer, + unsigned bufflen, struct scsi_sense_hdr *sshdr, int timeout, + int retries, int *resid, u64 flags); +static inline int scsi_execute_req(struct scsi_device *sdev, + const unsigned char *cmd, int data_direction, void *buffer, + unsigned bufflen, struct scsi_sense_hdr *sshdr, int timeout, + int retries, int *resid) +{ + return scsi_execute_req_flags(sdev, cmd, data_direction, buffer, + bufflen, sshdr, timeout, retries, resid, 0); +} +extern void sdev_disable_disk_events(struct scsi_device *sdev); +extern void sdev_enable_disk_events(struct scsi_device *sdev); + +#ifdef CONFIG_PM +extern int scsi_autopm_get_device(struct scsi_device *); +extern void scsi_autopm_put_device(struct scsi_device *); +#else +static inline int scsi_autopm_get_device(struct scsi_device *d) { return 0; } +static inline void scsi_autopm_put_device(struct scsi_device *d) {} +#endif /* CONFIG_PM */ + +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_TRANSPORT_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) +{ + if (sdev->no_dif) + return 0; + + return sdev->scsi_level > SCSI_2 && sdev->inquiry[5] & (1<<0); +} + +static inline int scsi_device_tpgs(struct scsi_device *sdev) +{ + return sdev->inquiry ? (sdev->inquiry[5] >> 4) & 0x3 : 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 */ diff --git a/kernel/include/scsi/scsi_devinfo.h b/kernel/include/scsi/scsi_devinfo.h new file mode 100644 index 000000000..96e3f5651 --- /dev/null +++ b/kernel/include/scsi/scsi_devinfo.h @@ -0,0 +1,41 @@ +#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 */ +#define BLIST_NO_DIF 0x2000000 /* Disable T10 PI (DIF) */ +#define BLIST_SKIP_VPD_PAGES 0x4000000 /* Ignore SBC-3 VPD pages */ +#define BLIST_SCSI3LUN 0x8000000 /* Scan more than 256 LUNs + for sequential scan */ +#define BLIST_TRY_VPD_PAGES 0x10000000 /* Attempt to read VPD pages */ +#define BLIST_NO_RSOC 0x20000000 /* don't try to issue RSOC */ +#define BLIST_MAX_1024 0x40000000 /* maximum 1024 sector cdb length */ + +#endif diff --git a/kernel/include/scsi/scsi_dh.h b/kernel/include/scsi/scsi_dh.h new file mode 100644 index 000000000..620c723ee --- /dev/null +++ b/kernel/include/scsi/scsi_dh.h @@ -0,0 +1,93 @@ +/* + * 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 *, activate_complete, void *); +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 const char *scsi_dh_attached_handler_name(struct request_queue *, gfp_t); +extern int scsi_dh_set_params(struct request_queue *, const char *); +#else +static inline int scsi_dh_activate(struct request_queue *req, + activate_complete fn, void *data) +{ + fn(data, 0); + 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 const char *scsi_dh_attached_handler_name(struct request_queue *q, + gfp_t gfp) +{ + return NULL; +} +static inline int scsi_dh_set_params(struct request_queue *req, const char *params) +{ + return -SCSI_DH_NOSYS; +} +#endif diff --git a/kernel/include/scsi/scsi_driver.h b/kernel/include/scsi/scsi_driver.h new file mode 100644 index 000000000..891a658aa --- /dev/null +++ b/kernel/include/scsi/scsi_driver.h @@ -0,0 +1,31 @@ +#ifndef _SCSI_SCSI_DRIVER_H +#define _SCSI_SCSI_DRIVER_H + +#include <linux/device.h> + +struct module; +struct request; +struct scsi_cmnd; +struct scsi_device; + +struct scsi_driver { + struct device_driver gendrv; + + void (*rescan)(struct device *); + int (*init_command)(struct scsi_cmnd *); + void (*uninit_command)(struct scsi_cmnd *); + int (*done)(struct scsi_cmnd *); + int (*eh_action)(struct scsi_cmnd *, int); +}; +#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) + +#endif /* _SCSI_SCSI_DRIVER_H */ diff --git a/kernel/include/scsi/scsi_eh.h b/kernel/include/scsi/scsi_eh.h new file mode 100644 index 000000000..5a4bb5bb6 --- /dev/null +++ b/kernel/include/scsi/scsi_eh.h @@ -0,0 +1,88 @@ +#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 bool scsi_sense_valid(const struct scsi_sense_hdr *sshdr) +{ + if (!sshdr) + return false; + + 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 bool scsi_normalize_sense(const u8 *sense_buffer, int sb_len, + struct scsi_sense_hdr *sshdr); +extern bool scsi_command_normalize_sense(const struct scsi_cmnd *cmd, + struct scsi_sense_hdr *sshdr); + +static inline bool scsi_sense_is_deferred(const 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); +extern void scsi_set_sense_information(u8 *buf, u64 info); + +extern int scsi_ioctl_reset(struct scsi_device *, int __user *); + +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 */ diff --git a/kernel/include/scsi/scsi_host.h b/kernel/include/scsi/scsi_host.h new file mode 100644 index 000000000..e113c757d --- /dev/null +++ b/kernel/include/scsi/scsi_host.h @@ -0,0 +1,936 @@ +#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 <linux/seq_file.h> +#include <linux/blk-mq.h> +#include <scsi/scsi.h> + +struct request_queue; +struct block_device; +struct completion; +struct module; +struct scsi_cmnd; +struct scsi_device; +struct scsi_host_cmd_pool; +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_Host *, 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_change_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); + + /* + * 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 []); + + /* + * This function is called when one or more partitions on the + * device reach beyond the end of the device. + * + * Status: OPTIONAL + */ + void (*unlock_native_capacity)(struct scsi_device *); + + /* + * 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 (*show_info)(struct seq_file *, struct Scsi_Host *); + int (*write_info)(struct Scsi_Host *, char *, 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 *); + + /* This is an optional routine that allows transport to initiate + * LLD adapter or firmware reset using sysfs attribute. + * + * Return values: 0 on success, -ve value on failure. + * + * Status: OPTIONAL + */ + + int (*host_reset)(struct Scsi_Host *shost, int reset_type); +#define SCSI_ADAPTER_RESET 1 +#define SCSI_FIRMWARE_RESET 2 + + + /* + * Name of proc directory + */ + const char *proc_name; + + /* + * Used to store the procfs directory if a driver implements the + * show_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; + unsigned short sg_prot_tablesize; + + /* + * Set this if the host adapter has limitations beside segment count. + */ + unsigned int 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; + + /* If use block layer to manage tags, this is tag allocation policy */ + int tag_alloc_policy; + + /* + * Let the block layer assigns tags to all commands. + */ + unsigned use_blk_tags:1; + + /* + * Track QUEUE_FULL events and reduce queue depth on demand. + */ + unsigned track_queue_depth:1; + + /* + * 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 the controller does not support WRITE SAME */ + unsigned no_write_same:1; + + /* + * True if asynchronous aborts are not supported + */ + unsigned no_async_abort: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; + + /* + * Additional per-command data allocated for the driver. + */ + unsigned int cmd_size; + struct scsi_host_cmd_pool *cmd_pool; + + /* temporary flag to disable blk-mq I/O path */ + bool disable_blk_mq; +}; + +/* + * Temporary #define for host lock push down. Can be removed when all + * drivers have been updated to take advantage of unlocked + * queuecommand. + * + */ +#define DEF_SCSI_QCMD(func_name) \ + int func_name(struct Scsi_Host *shost, struct scsi_cmnd *cmd) \ + { \ + unsigned long irq_flags; \ + int rc; \ + spin_lock_irqsave(shost->host_lock, irq_flags); \ + scsi_cmd_get_serial(shost, cmd); \ + rc = func_name##_lck (cmd, cmd->scsi_done); \ + spin_unlock_irqrestore(shost->host_lock, irq_flags); \ + return rc; \ + } + + +/* + * 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 being 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). + */ + union { + struct blk_queue_tag *bqt; + struct blk_mq_tag_set tag_set; + }; + + atomic_t host_busy; /* commands actually active on low-level */ + atomic_t host_blocked; + + unsigned int host_failed; /* commands that failed. + protected by host_lock */ + unsigned int host_eh_scheduled; /* EH scheduled without command */ + + unsigned int host_no; /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */ + + /* next two fields are used to bound the time spent in error handling */ + int eh_deadline; + unsigned long last_reset; + + + /* + * These three parameters can be used to allow for wide scsi, + * and for host adapters that support multiple busses + * The last two should be set to 1 more than the actual max id + * or lun (e.g. 8 for SCSI parallel systems). + */ + unsigned int max_channel; + unsigned int max_id; + u64 max_lun; + + /* + * 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 sg_prot_tablesize; + unsigned int max_sectors; + unsigned long dma_boundary; + /* + * In scsi-mq mode, the number of hardware queues supported by the LLD. + * + * Note: it is assumed that each hardware queue has a queue depth of + * can_queue. In other words, the total queue depth per host + * is nr_hw_queues * can_queue. + */ + unsigned nr_hw_queues; + /* + * 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; + + /* + * 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; + + /* Task mgmt function in progress */ + unsigned tmf_in_progress:1; + + /* Asynchronous scan in progress */ + unsigned async_scan:1; + + /* Don't resume host in EH */ + unsigned eh_noresume:1; + + /* The controller does not support WRITE SAME */ + unsigned no_write_same:1; + + unsigned use_blk_mq:1; + unsigned use_cmd_list:1; + + /* + * Optional work queue to be utilized by the transport + */ + char work_q_name[20]; + struct workqueue_struct *work_q; + + /* + * Task management function work queue + */ + struct workqueue_struct *tmf_work_q; + + /* The transport requires the LUN bits NOT to be stored in CDB[1] */ + unsigned no_scsi2_lun_in_cdb:1; + + /* + * 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 bool scsi_use_blk_mq; + +static inline bool shost_use_blk_mq(struct Scsi_Host *shost) +{ + return shost->use_blk_mq; +} + +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 void scsi_cmd_get_serial(struct Scsi_Host *, struct scsi_cmnd *); + +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 || + shost->shost_state == SHOST_RECOVERY; +} + +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 int scsi_host_prot_dma(struct Scsi_Host *shost) +{ + return shost->prot_capabilities >= SHOST_DIX_TYPE0_PROTECTION; +} + +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 }; + + if (target_type >= ARRAY_SIZE(cap)) + return 0; + + 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 }; + + if (target_type >= ARRAY_SIZE(cap)) + return 0; + + 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 */ diff --git a/kernel/include/scsi/scsi_ioctl.h b/kernel/include/scsi/scsi_ioctl.h new file mode 100644 index 000000000..8d19d1d23 --- /dev/null +++ b/kernel/include/scsi/scsi_ioctl.h @@ -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; + +int scsi_ioctl_block_when_processing_errors(struct scsi_device *sdev, + int cmd, bool ndelay); +extern int scsi_ioctl(struct scsi_device *, int, void __user *); + +#endif /* __KERNEL__ */ +#endif /* _SCSI_IOCTL_H */ diff --git a/kernel/include/scsi/scsi_tcq.h b/kernel/include/scsi/scsi_tcq.h new file mode 100644 index 000000000..b27977e8a --- /dev/null +++ b/kernel/include/scsi/scsi_tcq.h @@ -0,0 +1,101 @@ +#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 SCSI_NO_TAG (-1) /* identify no tag in use */ + + +#ifdef CONFIG_BLOCK +static inline struct scsi_cmnd *scsi_mq_find_tag(struct Scsi_Host *shost, + int unique_tag) +{ + u16 hwq = blk_mq_unique_tag_to_hwq(unique_tag); + struct request *req = NULL; + + if (hwq < shost->tag_set.nr_hw_queues) + req = blk_mq_tag_to_rq(shost->tag_set.tags[hwq], + blk_mq_unique_tag_to_tag(unique_tag)); + return req ? (struct scsi_cmnd *)req->special : NULL; +} + +/** + * scsi_find_tag - find a tagged command by device + * @SDpnt: pointer to the ScSI device + * @tag: tag generated by blk_mq_unique_tag() + * + * 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) { + if (shost_use_blk_mq(sdev->host)) + return scsi_mq_find_tag(sdev->host, 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) +{ + /* + * We always have a shared tag map around when using blk-mq. + */ + if (shost_use_blk_mq(shost)) + return 0; + + /* + * 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, + shost->hostt->tag_alloc_policy); + if (!shost->bqt) + return -ENOMEM; + } + + return 0; +} + +/** + * scsi_host_find_tag - find the tagged command by host + * @shost: pointer to scsi_host + * @tag: tag generated by blk_mq_unique_tag() + * + * 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) { + if (shost_use_blk_mq(shost)) + return scsi_mq_find_tag(shost, 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 */ diff --git a/kernel/include/scsi/scsi_transport.h b/kernel/include/scsi/scsi_transport.h new file mode 100644 index 000000000..81292392a --- /dev/null +++ b/kernel/include/scsi/scsi_transport.h @@ -0,0 +1,122 @@ +/* + * 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 <linux/bug.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, u64); + + /* 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 */ diff --git a/kernel/include/scsi/scsi_transport_fc.h b/kernel/include/scsi/scsi_transport_fc.h new file mode 100644 index 000000000..784bc2c09 --- /dev/null +++ b/kernel/include/scsi/scsi_transport_fc.h @@ -0,0 +1,861 @@ +/* + * 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_10GBIT 4 +#define FC_PORTSPEED_4GBIT 8 +#define FC_PORTSPEED_8GBIT 0x10 +#define FC_PORTSPEED_16GBIT 0x20 +#define FC_PORTSPEED_32GBIT 0x40 +#define FC_PORTSPEED_20GBIT 0x80 +#define FC_PORTSPEED_40GBIT 0x100 +#define FC_PORTSPEED_50GBIT 0x200 +#define FC_PORTSPEED_100GBIT 0x400 +#define FC_PORTSPEED_25GBIT 0x800 +#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 presence on the SAN, and may be instantiated via + * NPIV, Virtual Fabrics, or via additional ALPAs. As the vport is a + * unique presence, 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 extension 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; + u64 fcp_packet_alloc_failures; /* fcp packet allocation failures */ + u64 fcp_packet_aborts; /* fcp packet aborted */ + u64 fcp_frame_alloc_failures; /* fcp frame allocation failures */ + + /* fc exches statistics */ + u64 fc_no_free_exch; /* no free exch memory */ + u64 fc_no_free_exch_xid; /* no free exch id */ + u64 fc_xid_not_found; /* exch not found for a response */ + u64 fc_xid_busy; /* exch exist for new a request */ + u64 fc_seq_not_found; /* seq is not found for exchange */ + u64 fc_non_bls_resp; /* a non BLS response frame with + a sequence responder in new exch */ +}; + + +/* + * 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]; + char manufacturer[FC_SERIAL_NUMBER_SIZE]; + char model[FC_SYMBOLIC_NAME_SIZE]; + char model_description[FC_SYMBOLIC_NAME_SIZE]; + char hardware_version[FC_VERSION_STRING_SIZE]; + char driver_version[FC_VERSION_STRING_SIZE]; + char firmware_version[FC_VERSION_STRING_SIZE]; + char optionrom_version[FC_VERSION_STRING_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]; + u32 dev_loss_tmo; + + /* 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_manufacturer(x) \ + (((struct fc_host_attrs *)(x)->shost_data)->manufacturer) +#define fc_host_model(x) \ + (((struct fc_host_attrs *)(x)->shost_data)->model) +#define fc_host_model_description(x) \ + (((struct fc_host_attrs *)(x)->shost_data)->model_description) +#define fc_host_hardware_version(x) \ + (((struct fc_host_attrs *)(x)->shost_data)->hardware_version) +#define fc_host_driver_version(x) \ + (((struct fc_host_attrs *)(x)->shost_data)->driver_version) +#define fc_host_firmware_version(x) \ + (((struct fc_host_attrs *)(x)->shost_data)->firmware_version) +#define fc_host_optionrom_version(x) \ + (((struct fc_host_attrs *)(x)->shost_data)->optionrom_version) +#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) +#define fc_host_dev_loss_tmo(x) \ + (((struct fc_host_attrs *)(x)->shost_data)->dev_loss_tmo) + + +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; + unsigned long show_host_manufacturer:1; + unsigned long show_host_model:1; + unsigned long show_host_model_description:1; + unsigned long show_host_hardware_version:1; + unsigned long show_host_driver_version:1; + unsigned long show_host_firmware_version:1; + unsigned long show_host_optionrom_version: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); +int fc_block_scsi_eh(struct scsi_cmnd *cmnd); + +#endif /* SCSI_TRANSPORT_FC_H */ diff --git a/kernel/include/scsi/scsi_transport_iscsi.h b/kernel/include/scsi/scsi_transport_iscsi.h new file mode 100644 index 000000000..2555ee534 --- /dev/null +++ b/kernel/include/scsi/scsi_transport_iscsi.h @@ -0,0 +1,486 @@ +/* + * 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 scsi_cmnd; +struct iscsi_cls_conn; +struct iscsi_conn; +struct iscsi_task; +struct sockaddr; +struct iscsi_iface; +struct bsg_job; +struct iscsi_bus_flash_session; +struct iscsi_bus_flash_conn; + +/** + * 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; + + 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_ep_param) (struct iscsi_endpoint *ep, enum iscsi_param param, + char *buf); + 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); + int (*set_iface_param) (struct Scsi_Host *shost, void *data, + uint32_t len); + int (*get_iface_param) (struct iscsi_iface *iface, + enum iscsi_param_type param_type, + int param, char *buf); + umode_t (*attr_is_visible)(int param_type, int param); + int (*bsg_request)(struct bsg_job *job); + int (*send_ping) (struct Scsi_Host *shost, uint32_t iface_num, + uint32_t iface_type, uint32_t payload_size, + uint32_t pid, struct sockaddr *dst_addr); + int (*get_chap) (struct Scsi_Host *shost, uint16_t chap_tbl_idx, + uint32_t *num_entries, char *buf); + int (*delete_chap) (struct Scsi_Host *shost, uint16_t chap_tbl_idx); + int (*set_chap) (struct Scsi_Host *shost, void *data, int len); + int (*get_flashnode_param) (struct iscsi_bus_flash_session *fnode_sess, + int param, char *buf); + int (*set_flashnode_param) (struct iscsi_bus_flash_session *fnode_sess, + struct iscsi_bus_flash_conn *fnode_conn, + void *data, int len); + int (*new_flashnode) (struct Scsi_Host *shost, const char *buf, + int len); + int (*del_flashnode) (struct iscsi_bus_flash_session *fnode_sess); + int (*login_flashnode) (struct iscsi_bus_flash_session *fnode_sess, + struct iscsi_bus_flash_conn *fnode_conn); + int (*logout_flashnode) (struct iscsi_bus_flash_session *fnode_sess, + struct iscsi_bus_flash_conn *fnode_conn); + int (*logout_flashnode_sid) (struct iscsi_cls_session *cls_sess); + int (*get_host_stats) (struct Scsi_Host *shost, char *buf, int len); + u8 (*check_protection)(struct iscsi_task *task, sector_t *sector); +}; + +/* + * 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 void iscsi_conn_login_event(struct iscsi_cls_conn *conn, + enum iscsi_conn_state state); +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); + +extern void iscsi_post_host_event(uint32_t host_no, + struct iscsi_transport *transport, + enum iscsi_host_event_code code, + uint32_t data_size, + uint8_t *data); + +extern void iscsi_ping_comp_event(uint32_t host_no, + struct iscsi_transport *transport, + uint32_t status, uint32_t pid, + uint32_t data_size, uint8_t *data); + +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 */ + struct mutex ep_mutex; + struct iscsi_endpoint *ep; + + struct device dev; /* sysfs transport/container device */ +}; + +#define iscsi_dev_to_conn(_dev) \ + container_of(_dev, struct iscsi_cls_conn, dev) + +#define transport_class_to_conn(_cdev) \ + iscsi_dev_to_conn(_cdev->parent) + +#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; + bool ida_used; + + /* + * pid of userspace process that created session or -1 if + * created by the kernel. + */ + pid_t creator; + 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 transport_class_to_session(_cdev) \ + iscsi_dev_to_session(_cdev->parent) + +#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; + struct request_queue *bsg_q; + uint32_t port_speed; + uint32_t port_state; +}; + +#define iscsi_job_to_shost(_job) \ + dev_to_shost(_job->dev) + +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; + struct iscsi_cls_conn *conn; +}; + +struct iscsi_iface { + struct device dev; + struct iscsi_transport *transport; + uint32_t iface_type; /* IPv4 or IPv6 */ + uint32_t iface_num; /* iface number, 0 - n */ + void *dd_data; /* LLD private data */ +}; + +#define iscsi_dev_to_iface(_dev) \ + container_of(_dev, struct iscsi_iface, dev) + +#define iscsi_iface_to_shost(_iface) \ + dev_to_shost(_iface->dev.parent) + + +struct iscsi_bus_flash_conn { + struct list_head conn_list; /* item in connlist */ + void *dd_data; /* LLD private data */ + struct iscsi_transport *transport; + struct device dev; /* sysfs transport/container device */ + /* iscsi connection parameters */ + uint32_t exp_statsn; + uint32_t statsn; + unsigned max_recv_dlength; /* initiator_max_recv_dsl*/ + unsigned max_xmit_dlength; /* target_max_recv_dsl */ + unsigned max_segment_size; + unsigned tcp_xmit_wsf; + unsigned tcp_recv_wsf; + int hdrdgst_en; + int datadgst_en; + int port; + char *ipaddress; + char *link_local_ipv6_addr; + char *redirect_ipaddr; + uint16_t keepalive_timeout; + uint16_t local_port; + uint8_t snack_req_en; + /* tcp timestamp negotiation status */ + uint8_t tcp_timestamp_stat; + uint8_t tcp_nagle_disable; + /* tcp window scale factor */ + uint8_t tcp_wsf_disable; + uint8_t tcp_timer_scale; + uint8_t tcp_timestamp_en; + uint8_t ipv4_tos; + uint8_t ipv6_traffic_class; + uint8_t ipv6_flow_label; + uint8_t fragment_disable; + /* Link local IPv6 address is assigned by firmware or driver */ + uint8_t is_fw_assigned_ipv6; +}; + +#define iscsi_dev_to_flash_conn(_dev) \ + container_of(_dev, struct iscsi_bus_flash_conn, dev) + +#define iscsi_flash_conn_to_flash_session(_conn) \ + iscsi_dev_to_flash_session(_conn->dev.parent) + +#define ISID_SIZE 6 + +struct iscsi_bus_flash_session { + struct list_head sess_list; /* item in session_list */ + struct iscsi_transport *transport; + unsigned int target_id; + int flash_state; /* persistent or non-persistent */ + void *dd_data; /* LLD private data */ + struct device dev; /* sysfs transport/container device */ + /* iscsi session parameters */ + unsigned first_burst; + unsigned max_burst; + unsigned short max_r2t; + int default_taskmgmt_timeout; + int initial_r2t_en; + int imm_data_en; + int time2wait; + int time2retain; + int pdu_inorder_en; + int dataseq_inorder_en; + int erl; + int tpgt; + char *username; + char *username_in; + char *password; + char *password_in; + char *targetname; + char *targetalias; + char *portal_type; + uint16_t tsid; + uint16_t chap_in_idx; + uint16_t chap_out_idx; + /* index of iSCSI discovery session if the entry is + * discovered by iSCSI discovery session + */ + uint16_t discovery_parent_idx; + /* indicates if discovery was done through iSNS discovery service + * or through sendTarget */ + uint16_t discovery_parent_type; + /* Firmware auto sendtarget discovery disable */ + uint8_t auto_snd_tgt_disable; + uint8_t discovery_sess; + /* indicates if this flashnode entry is enabled or disabled */ + uint8_t entry_state; + uint8_t chap_auth_en; + /* enables firmware to auto logout the discovery session on discovery + * completion + */ + uint8_t discovery_logout_en; + uint8_t bidi_chap_en; + /* makes authentication for discovery session optional */ + uint8_t discovery_auth_optional; + uint8_t isid[ISID_SIZE]; + uint8_t is_boot_target; +}; + +#define iscsi_dev_to_flash_session(_dev) \ + container_of(_dev, struct iscsi_bus_flash_session, dev) + +#define iscsi_flash_session_to_shost(_session) \ + dev_to_shost(_session->dev.parent) + +/* + * 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 int iscsi_is_session_online(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); +extern int iscsi_block_scsi_eh(struct scsi_cmnd *cmd); +extern struct iscsi_iface *iscsi_create_iface(struct Scsi_Host *shost, + struct iscsi_transport *t, + uint32_t iface_type, + uint32_t iface_num, int dd_size); +extern void iscsi_destroy_iface(struct iscsi_iface *iface); +extern struct iscsi_iface *iscsi_lookup_iface(int handle); +extern char *iscsi_get_port_speed_name(struct Scsi_Host *shost); +extern char *iscsi_get_port_state_name(struct Scsi_Host *shost); +extern int iscsi_is_session_dev(const struct device *dev); + +extern char *iscsi_get_discovery_parent_name(int parent_type); +extern struct device * +iscsi_find_flashnode(struct Scsi_Host *shost, void *data, + int (*fn)(struct device *dev, void *data)); + +extern struct iscsi_bus_flash_session * +iscsi_create_flashnode_sess(struct Scsi_Host *shost, int index, + struct iscsi_transport *transport, int dd_size); + +extern struct iscsi_bus_flash_conn * +iscsi_create_flashnode_conn(struct Scsi_Host *shost, + struct iscsi_bus_flash_session *fnode_sess, + struct iscsi_transport *transport, int dd_size); + +extern void +iscsi_destroy_flashnode_sess(struct iscsi_bus_flash_session *fnode_sess); + +extern void iscsi_destroy_all_flashnode(struct Scsi_Host *shost); +extern int iscsi_flashnode_bus_match(struct device *dev, + struct device_driver *drv); +extern struct device * +iscsi_find_flashnode_sess(struct Scsi_Host *shost, void *data, + int (*fn)(struct device *dev, void *data)); +extern struct device * +iscsi_find_flashnode_conn(struct iscsi_bus_flash_session *fnode_sess); + +extern char * +iscsi_get_ipaddress_state_name(enum iscsi_ipaddress_state port_state); +extern char *iscsi_get_router_state_name(enum iscsi_router_state router_state); +#endif diff --git a/kernel/include/scsi/scsi_transport_sas.h b/kernel/include/scsi/scsi_transport_sas.h new file mode 100644 index 000000000..0bd71e270 --- /dev/null +++ b/kernel/include/scsi/scsi_transport_sas.h @@ -0,0 +1,231 @@ +#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; + +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, + SAS_LINK_RATE_12_0_GBPS = 11, + /* 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; + + /* available to the lldd */ + void *hostdata; +}; + +#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; + unsigned tlr_supported:1; + unsigned tlr_enabled: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 (*phy_setup)(struct sas_phy *); + void (*phy_release)(struct sas_phy *); + 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 *); + +unsigned int sas_tlr_supported(struct scsi_device *); +unsigned int sas_is_tlr_enabled(struct scsi_device *); +void sas_disable_tlr(struct scsi_device *); +void sas_enable_tlr(struct scsi_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 void sas_rphy_unlink(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 *); +struct sas_phy *sas_port_get_phy(struct sas_port *port); +static inline void sas_port_put_phy(struct sas_phy *phy) +{ + if (phy) + put_device(&phy->dev); +} + +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 */ diff --git a/kernel/include/scsi/scsi_transport_spi.h b/kernel/include/scsi/scsi_transport_spi.h new file mode 100644 index 000000000..a4fa52b4d --- /dev/null +++ b/kernel/include/scsi/scsi_transport_spi.h @@ -0,0 +1,162 @@ +/* + * 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); +int spi_populate_tag_msg(unsigned char *msg, struct scsi_cmnd *cmd); + +#endif /* SCSI_TRANSPORT_SPI_H */ diff --git a/kernel/include/scsi/scsi_transport_srp.h b/kernel/include/scsi/scsi_transport_srp.h new file mode 100644 index 000000000..cdb05dd1d --- /dev/null +++ b/kernel/include/scsi/scsi_transport_srp.h @@ -0,0 +1,149 @@ +#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; +}; + +/** + * enum srp_rport_state - SRP transport layer state + * @SRP_RPORT_RUNNING: Transport layer operational. + * @SRP_RPORT_BLOCKED: Transport layer not operational; fast I/O fail timer + * is running and I/O has been blocked. + * @SRP_RPORT_FAIL_FAST: Fast I/O fail timer has expired; fail I/O fast. + * @SRP_RPORT_LOST: Port is being removed. + */ +enum srp_rport_state { + SRP_RPORT_RUNNING, + SRP_RPORT_BLOCKED, + SRP_RPORT_FAIL_FAST, + SRP_RPORT_LOST, +}; + +/** + * struct srp_rport - SRP initiator or target port + * + * Fields that are relevant for SRP initiator and SRP target drivers: + * @dev: Device associated with this rport. + * @port_id: 16-byte port identifier. + * @roles: Role of this port - initiator or target. + * + * Fields that are only relevant for SRP initiator drivers: + * @lld_data: LLD private data. + * @mutex: Protects against concurrent rport reconnect / + * fast_io_fail / dev_loss_tmo activity. + * @state: rport state. + * @reconnect_delay: Reconnect delay in seconds. + * @failed_reconnects: Number of failed reconnect attempts. + * @reconnect_work: Work structure used for scheduling reconnect attempts. + * @fast_io_fail_tmo: Fast I/O fail timeout in seconds. + * @dev_loss_tmo: Device loss timeout in seconds. + * @fast_io_fail_work: Work structure used for scheduling fast I/O fail work. + * @dev_loss_work: Work structure used for scheduling device loss work. + */ +struct srp_rport { + /* for initiator and target drivers */ + + struct device dev; + + u8 port_id[16]; + u8 roles; + + /* for initiator drivers */ + + void *lld_data; + + struct mutex mutex; + enum srp_rport_state state; + int reconnect_delay; + int failed_reconnects; + struct delayed_work reconnect_work; + int fast_io_fail_tmo; + int dev_loss_tmo; + struct delayed_work fast_io_fail_work; + struct delayed_work dev_loss_work; +}; + +/** + * struct srp_function_template + * + * Fields that are only relevant for SRP initiator drivers: + * @has_rport_state: Whether or not to create the state, fast_io_fail_tmo and + * dev_loss_tmo sysfs attribute for an rport. + * @reset_timer_if_blocked: Whether or srp_timed_out() should reset the command + * timer if the device on which it has been queued is blocked. + * @reconnect_delay: If not NULL, points to the default reconnect_delay value. + * @fast_io_fail_tmo: If not NULL, points to the default fast_io_fail_tmo value. + * @dev_loss_tmo: If not NULL, points to the default dev_loss_tmo value. + * @reconnect: Callback function for reconnecting to the target. See also + * srp_reconnect_rport(). + * @terminate_rport_io: Callback function for terminating all outstanding I/O + * requests for an rport. + * @rport_delete: Callback function that deletes an rport. + * + * Fields that are only relevant for SRP target drivers: + * @tsk_mgmt_response: Callback function for sending a task management response. + * @it_nexus_response: Callback function for processing an IT nexus response. + */ +struct srp_function_template { + /* for initiator drivers */ + bool has_rport_state; + bool reset_timer_if_blocked; + int *reconnect_delay; + int *fast_io_fail_tmo; + int *dev_loss_tmo; + int (*reconnect)(struct srp_rport *rport); + void (*terminate_rport_io)(struct srp_rport *rport); + void (*rport_delete)(struct srp_rport *rport); + /* 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 void srp_rport_get(struct srp_rport *rport); +extern void srp_rport_put(struct srp_rport *rport); +extern struct srp_rport *srp_rport_add(struct Scsi_Host *, + struct srp_rport_identifiers *); +extern void srp_rport_del(struct srp_rport *); +extern int srp_tmo_valid(int reconnect_delay, int fast_io_fail_tmo, + int dev_loss_tmo); +extern int srp_reconnect_rport(struct srp_rport *rport); +extern void srp_start_tl_fail_timers(struct srp_rport *rport); +extern void srp_remove_host(struct Scsi_Host *); +extern void srp_stop_rport_timers(struct srp_rport *rport); + +/** + * srp_chkready() - evaluate the transport layer state before I/O + * @rport: SRP target port pointer. + * + * Returns a SCSI result code that can be returned by the LLD queuecommand() + * implementation. The role of this function is similar to that of + * fc_remote_port_chkready(). + */ +static inline int srp_chkready(struct srp_rport *rport) +{ + switch (rport->state) { + case SRP_RPORT_RUNNING: + case SRP_RPORT_BLOCKED: + default: + return 0; + case SRP_RPORT_FAIL_FAST: + return DID_TRANSPORT_FAILFAST << 16; + case SRP_RPORT_LOST: + return DID_NO_CONNECT << 16; + } +} + +#endif diff --git a/kernel/include/scsi/scsicam.h b/kernel/include/scsi/scsicam.h new file mode 100644 index 000000000..24ede4747 --- /dev/null +++ b/kernel/include/scsi/scsicam.h @@ -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 */ diff --git a/kernel/include/scsi/sg.h b/kernel/include/scsi/sg.h new file mode 100644 index 000000000..3afec7032 --- /dev/null +++ b/kernel/include/scsi/sg.h @@ -0,0 +1,274 @@ +#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 - 2014 Douglas Gilbert + * + * Version: 3.5.36 (20140603) + * This version is for 2.6 and 3 series kernels. + * + * Documentation + * ============= + * A web site for the SG device driver can be found at: + * http://sg.danny.cz/sg [alternatively check the MAINTAINERS file] + * The documentation for the sg version 3 driver can be found at: + * http://sg.danny.cz/sg/p/sg_v3_ho.html + * Also see: <kernel_source>/Documentation/scsi/scsi-generic.txt + * + * For utility and test programs see: http://sg.danny.cz/sg/sg3_utils.html + */ + +#ifdef __KERNEL__ +extern int sg_big_buff; /* for sysctl */ +#endif + + +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 */ + 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) */ +/* defaults:: for sg driver: Q_AT_HEAD; for block layer: Q_AT_TAIL */ +#define SG_FLAG_Q_AT_TAIL 0x10 +#define SG_FLAG_Q_AT_HEAD 0x20 + +/* 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. + * SG_SCSI_RESET_NO_ESCALATE may be OR-ed to the _DEVICE, _TARGET, _BUS + * or _HOST reset value so only that action is attempted. */ +#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 +#define SG_SCSI_RESET_NO_ESCALATE 0x100 + +/* 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 diff --git a/kernel/include/scsi/srp.h b/kernel/include/scsi/srp.h new file mode 100644 index 000000000..1ae84db4c --- /dev/null +++ b/kernel/include/scsi/srp.h @@ -0,0 +1,280 @@ +/* + * 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)); + +struct srp_cred_req { + u8 opcode; + u8 sol_not; + u8 reserved[2]; + __be32 req_lim_delta; + u64 tag; +}; + +struct srp_cred_rsp { + u8 opcode; + u8 reserved[7]; + u64 tag; +}; + +/* + * The SRP spec defines the fixed portion of the AER_REQ 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_aer_req { + u8 opcode; + u8 sol_not; + u8 reserved[2]; + __be32 req_lim_delta; + u64 tag; + u32 reserved2; + __be64 lun; + __be32 sense_data_len; + u32 reserved3; + u8 sense_data[0]; +} __attribute__((packed)); + +struct srp_aer_rsp { + u8 opcode; + u8 reserved[7]; + u64 tag; +}; + +#endif /* SCSI_SRP_H */ |