aboutsummaryrefslogtreecommitdiff
path: root/include/scsi
diff options
context:
space:
mode:
Diffstat (limited to 'include/scsi')
-rw-r--r--include/scsi/fc/Kbuild0
-rw-r--r--include/scsi/fc/fc_encaps.h138
-rw-r--r--include/scsi/fc/fc_fc2.h123
-rw-r--r--include/scsi/fc/fc_fcoe.h108
-rw-r--r--include/scsi/fc/fc_fcp.h216
-rw-r--r--include/scsi/fc/fc_fip.h280
-rw-r--r--include/scsi/fc/fc_ms.h213
-rw-r--r--include/scsi/fc_encode.h739
-rw-r--r--include/scsi/fc_frame.h261
-rw-r--r--include/scsi/fcoe_sysfs.h133
-rw-r--r--include/scsi/iscsi_if.h793
-rw-r--r--include/scsi/iscsi_proto.h161
-rw-r--r--include/scsi/libfc.h1155
-rw-r--r--include/scsi/libfcoe.h408
-rw-r--r--include/scsi/libiscsi.h497
-rw-r--r--include/scsi/libiscsi_tcp.h136
-rw-r--r--include/scsi/libsas.h753
-rw-r--r--include/scsi/libsrp.h78
-rw-r--r--include/scsi/osd_attributes.h397
-rw-r--r--include/scsi/osd_initiator.h515
-rw-r--r--include/scsi/osd_ore.h201
-rw-r--r--include/scsi/osd_protocol.h676
-rw-r--r--include/scsi/osd_sec.h45
-rw-r--r--include/scsi/osd_sense.h263
-rw-r--r--include/scsi/osd_types.h45
-rw-r--r--include/scsi/sas.h653
-rw-r--r--include/scsi/sas_ata.h105
-rw-r--r--include/scsi/scsi.h197
-rw-r--r--include/scsi/scsi_bsg_iscsi.h110
-rw-r--r--include/scsi/scsi_cmnd.h298
-rw-r--r--include/scsi/scsi_dbg.h14
-rw-r--r--include/scsi/scsi_device.h311
-rw-r--r--include/scsi/scsi_devinfo.h4
-rw-r--r--include/scsi/scsi_dh.h93
-rw-r--r--include/scsi/scsi_driver.h13
-rw-r--r--include/scsi/scsi_eh.h37
-rw-r--r--include/scsi/scsi_host.h393
-rw-r--r--include/scsi/scsi_ioctl.h4
-rw-r--r--include/scsi/scsi_request.h54
-rw-r--r--include/scsi/scsi_tcq.h55
-rw-r--r--include/scsi/scsi_tgt.h21
-rw-r--r--include/scsi/scsi_tgt_if.h108
-rw-r--r--include/scsi/scsi_transport.h33
-rw-r--r--include/scsi/scsi_transport_fc.h449
-rw-r--r--include/scsi/scsi_transport_iscsi.h407
-rw-r--r--include/scsi/scsi_transport_sas.h178
-rw-r--r--include/scsi/scsi_transport_spi.h13
-rw-r--r--include/scsi/scsi_transport_srp.h149
-rw-r--r--include/scsi/sg.h65
-rw-r--r--include/scsi/sg_request.h26
-rw-r--r--include/scsi/srp.h64
51 files changed, 11643 insertions, 545 deletions
diff --git a/include/scsi/fc/Kbuild b/include/scsi/fc/Kbuild
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/include/scsi/fc/Kbuild
diff --git a/include/scsi/fc/fc_encaps.h b/include/scsi/fc/fc_encaps.h
new file mode 100644
index 00000000000..f180c3e1622
--- /dev/null
+++ b/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/include/scsi/fc/fc_fc2.h b/include/scsi/fc/fc_fc2.h
new file mode 100644
index 00000000000..0b267143130
--- /dev/null
+++ b/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/include/scsi/fc/fc_fcoe.h b/include/scsi/fc/fc_fcoe.h
new file mode 100644
index 00000000000..d5dcd606281
--- /dev/null
+++ b/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/include/scsi/fc/fc_fcp.h b/include/scsi/fc/fc_fcp.h
new file mode 100644
index 00000000000..9c8702942b6
--- /dev/null
+++ b/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/include/scsi/fc/fc_fip.h b/include/scsi/fc/fc_fip.h
new file mode 100644
index 00000000000..ae25d4ab254
--- /dev/null
+++ b/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/include/scsi/fc/fc_ms.h b/include/scsi/fc/fc_ms.h
new file mode 100644
index 00000000000..f52b921b5c7
--- /dev/null
+++ b/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/include/scsi/fc_encode.h b/include/scsi/fc_encode.h
new file mode 100644
index 00000000000..35fd4744f3e
--- /dev/null
+++ b/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/include/scsi/fc_frame.h b/include/scsi/fc_frame.h
new file mode 100644
index 00000000000..8225d8063ec
--- /dev/null
+++ b/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/include/scsi/fcoe_sysfs.h b/include/scsi/fcoe_sysfs.h
new file mode 100644
index 00000000000..7e231487034
--- /dev/null
+++ b/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/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h
index e5618b90996..fd0421c6d40 100644
--- a/include/scsi/iscsi_if.h
+++ b/include/scsi/iscsi_if.h
@@ -22,6 +22,11 @@
#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
@@ -43,10 +48,56 @@ enum iscsi_uevent_e {
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 {
@@ -58,66 +109,397 @@ struct iscsi_uevent {
/* 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 {
- uint64_t session_handle;
uint32_t sid;
} d_session;
struct msg_create_conn {
- uint64_t session_handle;
- uint32_t cid;
uint32_t sid;
+ uint32_t cid;
} c_conn;
struct msg_bind_conn {
- uint64_t session_handle;
- uint64_t conn_handle;
- uint32_t transport_fd;
+ uint32_t sid;
+ uint32_t cid;
+ uint64_t transport_eph;
uint32_t is_leading;
} b_conn;
struct msg_destroy_conn {
- uint64_t conn_handle;
+ 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;
- uint64_t conn_handle;
} send_pdu;
struct msg_set_param {
- uint64_t conn_handle;
+ uint32_t sid;
+ uint32_t cid;
uint32_t param; /* enum iscsi_param */
- uint32_t value;
+ uint32_t len;
} set_param;
struct msg_start_conn {
- uint64_t conn_handle;
+ 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 {
- uint64_t conn_handle;
+ 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 */
- uint64_t handle;
int retcode;
struct msg_create_session_ret {
- uint64_t session_handle;
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;
- uint64_t conn_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 {
- uint64_t conn_handle;
+ 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
*/
@@ -139,39 +521,232 @@ enum iscsi_err {
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_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 Parameters (RFC3720)
*/
enum iscsi_param {
- ISCSI_PARAM_MAX_RECV_DLENGTH = 0,
- ISCSI_PARAM_MAX_XMIT_DLENGTH = 1,
- ISCSI_PARAM_HDRDGST_EN = 2,
- ISCSI_PARAM_DATADGST_EN = 3,
- ISCSI_PARAM_INITIAL_R2T_EN = 4,
- ISCSI_PARAM_MAX_R2T = 5,
- ISCSI_PARAM_IMM_DATA_EN = 6,
- ISCSI_PARAM_FIRST_BURST = 7,
- ISCSI_PARAM_MAX_BURST = 8,
- ISCSI_PARAM_PDU_INORDER_EN = 9,
- ISCSI_PARAM_DATASEQ_INORDER_EN = 10,
- ISCSI_PARAM_ERL = 11,
- ISCSI_PARAM_IFMARKER_EN = 12,
- ISCSI_PARAM_OFMARKER_EN = 13,
-};
-#define ISCSI_PARAM_MAX 14
+ /* 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)
-#define hostdata_session(_hostdata) (iscsi_ptr(*(unsigned long *)_hostdata))
-
-/**
- * iscsi_hostdata - get LLD hostdata from scsi_host
- * @_hostdata: pointer to scsi host's hostdata
- **/
-#define iscsi_hostdata(_hostdata) ((void*)_hostdata + sizeof(unsigned long))
/*
* These flags presents iSCSI Data-Path capabilities.
@@ -185,6 +760,13 @@ enum iscsi_param {
#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
@@ -245,4 +827,135 @@ struct iscsi_stats {
__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/include/scsi/iscsi_proto.h b/include/scsi/iscsi_proto.h
index 4feda05fdf2..c1260d80ef3 100644
--- a/include/scsi/iscsi_proto.h
+++ b/include/scsi/iscsi_proto.h
@@ -21,15 +21,46 @@
#ifndef ISCSI_PROTO_H
#define ISCSI_PROTO_H
-#define ISCSI_VERSION_STR "0.3"
-#define ISCSI_DATE_STR "22-Apr-2005"
+#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 PAD_WORD_LEN 4
+#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
@@ -42,6 +73,14 @@
}
#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
*/
@@ -51,8 +90,8 @@ struct iscsi_hdr {
uint8_t rsvd2[2];
uint8_t hlength; /* AHSs total length */
uint8_t dlength[3]; /* Data length */
- uint8_t lun[8];
- __be32 itt; /* Initiator Task Tag */
+ struct scsi_lun lun;
+ itt_t itt; /* Initiator Task Tag, opaque for target */
__be32 ttt; /* Target Task Tag */
__be32 statsn;
__be32 exp_statsn;
@@ -104,20 +143,21 @@ struct iscsi_ahs_hdr {
#define ISCSI_AHSTYPE_CDB 1
#define ISCSI_AHSTYPE_RLENGTH 2
+#define ISCSI_CDB_SIZE 16
/* iSCSI PDU Header */
-struct iscsi_cmd {
+struct iscsi_scsi_req {
uint8_t opcode;
uint8_t flags;
__be16 rsvd2;
uint8_t hlength;
uint8_t dlength[3];
- uint8_t lun[8];
- __be32 itt; /* Initiator Task Tag */
+ struct scsi_lun lun;
+ itt_t itt; /* Initiator Task Tag */
__be32 data_length;
__be32 cmdsn;
__be32 exp_statsn;
- uint8_t cdb[16]; /* SCSI Command Block */
+ uint8_t cdb[ISCSI_CDB_SIZE]; /* SCSI Command Block */
/* Additional Data (Command Dependent) */
};
@@ -141,8 +181,17 @@ struct iscsi_rlength_ahdr {
__be32 read_length;
};
+/* Extended CDB AHS */
+struct iscsi_ecdb_ahdr {
+ __be16 ahslength; /* CDB length - 15, including reserved byte */
+ uint8_t ahstype;
+ uint8_t reserved;
+ /* 4-byte aligned extended CDB spillover */
+ uint8_t ecdb[SCSI_MAX_VARLEN_CDB_SIZE - ISCSI_CDB_SIZE];
+};
+
/* SCSI Response Header */
-struct iscsi_cmd_rsp {
+struct iscsi_scsi_rsp {
uint8_t opcode;
uint8_t flags;
uint8_t response;
@@ -150,7 +199,7 @@ struct iscsi_cmd_rsp {
uint8_t hlength;
uint8_t dlength[3];
uint8_t rsvd[8];
- __be32 itt; /* Initiator Task Tag */
+ itt_t itt; /* Initiator Task Tag */
__be32 rsvd1;
__be32 statsn;
__be32 exp_cmdsn;
@@ -179,7 +228,7 @@ struct iscsi_async {
uint8_t rsvd2[2];
uint8_t rsvd3;
uint8_t dlength[3];
- uint8_t lun[8];
+ struct scsi_lun lun;
uint8_t rsvd4[8];
__be32 statsn;
__be32 exp_cmdsn;
@@ -207,8 +256,8 @@ struct iscsi_nopout {
__be16 rsvd2;
uint8_t rsvd3;
uint8_t dlength[3];
- uint8_t lun[8];
- __be32 itt; /* Initiator Task Tag */
+ struct scsi_lun lun;
+ itt_t itt; /* Initiator Task Tag */
__be32 ttt; /* Target Transfer Tag */
__be32 cmdsn;
__be32 exp_statsn;
@@ -222,8 +271,8 @@ struct iscsi_nopin {
__be16 rsvd2;
uint8_t rsvd3;
uint8_t dlength[3];
- uint8_t lun[8];
- __be32 itt; /* Initiator Task Tag */
+ struct scsi_lun lun;
+ itt_t itt; /* Initiator Task Tag */
__be32 ttt; /* Target Transfer Tag */
__be32 statsn;
__be32 exp_cmdsn;
@@ -238,9 +287,9 @@ struct iscsi_tm {
uint8_t rsvd1[2];
uint8_t hlength;
uint8_t dlength[3];
- uint8_t lun[8];
- __be32 itt; /* Initiator Task Tag */
- __be32 rtt; /* Reference Task Tag */
+ struct scsi_lun lun;
+ itt_t itt; /* Initiator Task Tag */
+ itt_t rtt; /* Reference Task Tag */
__be32 cmdsn;
__be32 exp_statsn;
__be32 refcmdsn;
@@ -260,6 +309,8 @@ struct iscsi_tm {
#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;
@@ -269,8 +320,8 @@ struct iscsi_tm_rsp {
uint8_t hlength;
uint8_t dlength[3];
uint8_t rsvd2[8];
- __be32 itt; /* Initiator Task Tag */
- __be32 rtt; /* Reference Task Tag */
+ itt_t itt; /* Initiator Task Tag */
+ itt_t rtt; /* Reference Task Tag */
__be32 statsn;
__be32 exp_cmdsn;
__be32 max_cmdsn;
@@ -294,8 +345,8 @@ struct iscsi_r2t_rsp {
uint8_t rsvd2[2];
uint8_t hlength;
uint8_t dlength[3];
- uint8_t lun[8];
- __be32 itt; /* Initiator Task Tag */
+ struct scsi_lun lun;
+ itt_t itt; /* Initiator Task Tag */
__be32 ttt; /* Target Transfer Tag */
__be32 statsn;
__be32 exp_cmdsn;
@@ -312,8 +363,8 @@ struct iscsi_data {
uint8_t rsvd2[2];
uint8_t rsvd3;
uint8_t dlength[3];
- uint8_t lun[8];
- __be32 itt;
+ struct scsi_lun lun;
+ itt_t itt;
__be32 ttt;
__be32 rsvd4;
__be32 exp_statsn;
@@ -332,8 +383,8 @@ struct iscsi_data_rsp {
uint8_t cmd_status;
uint8_t hlength;
uint8_t dlength[3];
- uint8_t lun[8];
- __be32 itt;
+ struct scsi_lun lun;
+ itt_t itt;
__be32 ttt;
__be32 statsn;
__be32 exp_cmdsn;
@@ -357,7 +408,7 @@ struct iscsi_text {
uint8_t hlength;
uint8_t dlength[3];
uint8_t rsvd4[8];
- __be32 itt;
+ itt_t itt;
__be32 ttt;
__be32 cmdsn;
__be32 exp_statsn;
@@ -375,7 +426,7 @@ struct iscsi_text_rsp {
uint8_t hlength;
uint8_t dlength[3];
uint8_t rsvd4[8];
- __be32 itt;
+ itt_t itt;
__be32 ttt;
__be32 statsn;
__be32 exp_cmdsn;
@@ -385,7 +436,7 @@ struct iscsi_text_rsp {
};
/* Login Header */
-struct iscsi_login {
+struct iscsi_login_req {
uint8_t opcode;
uint8_t flags;
uint8_t max_version; /* Max. version supported */
@@ -394,7 +445,7 @@ struct iscsi_login {
uint8_t dlength[3];
uint8_t isid[6]; /* Initiator Session ID */
__be16 tsih; /* Target Session Handle */
- __be32 itt; /* Initiator Task Tag */
+ itt_t itt; /* Initiator Task Tag */
__be16 cid;
__be16 rsvd3;
__be32 cmdsn;
@@ -406,7 +457,13 @@ struct iscsi_login {
#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)
@@ -423,7 +480,7 @@ struct iscsi_login_rsp {
uint8_t dlength[3];
uint8_t isid[6]; /* Initiator Session ID */
__be16 tsih; /* Target Session Handle */
- __be32 itt; /* Initiator Task Tag */
+ itt_t itt; /* Initiator Task Tag */
__be32 rsvd3;
__be32 statsn;
__be32 exp_cmdsn;
@@ -480,7 +537,7 @@ struct iscsi_logout {
uint8_t hlength;
uint8_t dlength[3];
uint8_t rsvd2[8];
- __be32 itt; /* Initiator Task Tag */
+ itt_t itt; /* Initiator Task Tag */
__be16 cid;
uint8_t rsvd3[2];
__be32 cmdsn;
@@ -507,7 +564,7 @@ struct iscsi_logout_rsp {
uint8_t hlength;
uint8_t dlength[3];
uint8_t rsvd3[8];
- __be32 itt; /* Initiator Task Tag */
+ itt_t itt; /* Initiator Task Tag */
__be32 rsvd4;
__be32 statsn;
__be32 exp_cmdsn;
@@ -529,17 +586,25 @@ struct iscsi_logout_rsp {
struct iscsi_snack {
uint8_t opcode;
uint8_t flags;
- uint8_t rsvd2[14];
- __be32 itt;
+ 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;
- __be32 exp_statsn;
- __be32 rsvd3;
- __be32 exp_datasn;
- uint8_t rsvd6[8];
};
/* 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 */
@@ -582,7 +647,21 @@ struct iscsi_reject {
#define VALUE_MAXLEN 255
#define TARGET_NAME_MAXLEN VALUE_MAXLEN
-#define DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH 8192
+#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 *****************************/
diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h
new file mode 100644
index 00000000000..52beadf9a29
--- /dev/null
+++ b/include/scsi/libfc.h
@@ -0,0 +1,1155 @@
+/*
+ * 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 *);
+int fc_change_queue_depth(struct scsi_device *, int qdepth, int reason);
+int fc_change_queue_type(struct scsi_device *, int tag_type);
+
+/*
+ * 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/include/scsi/libfcoe.h b/include/scsi/libfcoe.h
new file mode 100644
index 00000000000..de7e3ee60f0
--- /dev/null
+++ b/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/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
new file mode 100644
index 00000000000..728c9ad9feb
--- /dev/null
+++ b/include/scsi/libiscsi.h
@@ -0,0 +1,497 @@
+/*
+ * 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_change_queue_depth(struct scsi_device *sdev, int depth,
+ int reason);
+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/include/scsi/libiscsi_tcp.h b/include/scsi/libiscsi_tcp.h
new file mode 100644
index 00000000000..2a7aa75dd00
--- /dev/null
+++ b/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/include/scsi/libsas.h b/include/scsi/libsas.h
new file mode 100644
index 00000000000..ef7872c20da
--- /dev/null
+++ b/include/scsi/libsas.h
@@ -0,0 +1,753 @@
+/*
+ * 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 ---------- */
+enum ata_command_set {
+ ATA_COMMAND_SET = 0,
+ ATAPI_COMMAND_SET = 1,
+};
+
+#define ATA_RESP_FIS_SIZE 24
+
+struct sata_device {
+ enum ata_command_set command_set;
+ 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 mutex task_queue_flush;
+ spinlock_t task_queue_lock;
+ struct list_head task_queue;
+ int task_queue_size;
+
+ struct task_struct *queue_thread;
+};
+
+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 */
+
+ /* The class calls this to send a task for execution. */
+ int lldd_max_execute_num;
+ int lldd_queue_size;
+ 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;
+ struct list_head list;
+
+ 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 *, int num,
+ gfp_t gfp_flags);
+
+ /* Task Management Functions. Must be called from process context. */
+ int (*lldd_abort_task)(struct sas_task *);
+ int (*lldd_abort_task_set)(struct domain_device *, u8 *lun);
+ int (*lldd_clear_aca)(struct domain_device *, u8 *lun);
+ int (*lldd_clear_task_set)(struct domain_device *, u8 *lun);
+ int (*lldd_I_T_nexus_reset)(struct domain_device *);
+ int (*lldd_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);
+int sas_queue_up(struct sas_task *task);
+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,
+ int reason);
+extern int sas_change_queue_type(struct scsi_device *, int qt);
+extern int sas_bios_param(struct scsi_device *,
+ struct block_device *,
+ sector_t capacity, int *hsc);
+extern struct scsi_transport_template *
+sas_domain_attach_transport(struct sas_domain_function_template *);
+extern void sas_domain_release_transport(struct scsi_transport_template *);
+
+int sas_discover_root_expander(struct domain_device *);
+
+void sas_init_ex_attr(void);
+
+int sas_ex_revalidate_domain(struct domain_device *);
+
+void sas_unregister_domain_devices(struct asd_sas_port *port, 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/include/scsi/libsrp.h b/include/scsi/libsrp.h
new file mode 100644
index 00000000000..f4105c91af5
--- /dev/null
+++ b/include/scsi/libsrp.h
@@ -0,0 +1,78 @@
+#ifndef __LIBSRP_H__
+#define __LIBSRP_H__
+
+#include <linux/list.h>
+#include <linux/kfifo.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_host.h>
+#include <scsi/srp.h>
+
+enum iue_flags {
+ V_DIOVER,
+ V_WRITE,
+ V_LINKED,
+ V_FLYING,
+};
+
+struct srp_buf {
+ dma_addr_t dma;
+ void *buf;
+};
+
+struct srp_queue {
+ void *pool;
+ void *items;
+ struct kfifo queue;
+ spinlock_t lock;
+};
+
+struct srp_target {
+ struct Scsi_Host *shost;
+ struct device *dev;
+
+ spinlock_t lock;
+ struct list_head cmd_queue;
+
+ size_t srp_iu_size;
+ struct srp_queue iu_queue;
+ size_t rx_ring_size;
+ struct srp_buf **rx_ring;
+
+ void *ldata;
+};
+
+struct iu_entry {
+ struct srp_target *target;
+
+ struct list_head ilist;
+ dma_addr_t remote_token;
+ unsigned long flags;
+
+ struct srp_buf *sbuf;
+};
+
+typedef int (srp_rdma_t)(struct scsi_cmnd *, struct scatterlist *, int,
+ struct srp_direct_buf *, int,
+ enum dma_data_direction, unsigned int);
+extern int srp_target_alloc(struct srp_target *, struct device *, size_t, size_t);
+extern void srp_target_free(struct srp_target *);
+
+extern struct iu_entry *srp_iu_get(struct srp_target *);
+extern void srp_iu_put(struct iu_entry *);
+
+extern int srp_cmd_queue(struct Scsi_Host *, struct srp_cmd *, void *, u64, u64);
+extern int srp_transfer_data(struct scsi_cmnd *, struct srp_cmd *,
+ srp_rdma_t, int, int);
+
+
+static inline struct srp_target *host_to_srp_target(struct Scsi_Host *host)
+{
+ return (struct srp_target *) host->hostdata;
+}
+
+static inline int srp_cmd_direction(struct srp_cmd *cmd)
+{
+ return (cmd->buf_fmt >> 4) ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
+}
+
+#endif
diff --git a/include/scsi/osd_attributes.h b/include/scsi/osd_attributes.h
new file mode 100644
index 00000000000..303ba1118a4
--- /dev/null
+++ b/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/include/scsi/osd_initiator.h b/include/scsi/osd_initiator.h
new file mode 100644
index 00000000000..b2e85fdd2ae
--- /dev/null
+++ b/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 <bharrosh@panasas.com>
+ * Benny Halevy <bhalevy@panasas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ *
+ */
+#ifndef __OSD_INITIATOR_H__
+#define __OSD_INITIATOR_H__
+
+#include <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/include/scsi/osd_ore.h b/include/scsi/osd_ore.h
new file mode 100644
index 00000000000..6ca3265a4dc
--- /dev/null
+++ b/include/scsi/osd_ore.h
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2011
+ * Boaz Harrosh <bharrosh@panasas.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/include/scsi/osd_protocol.h b/include/scsi/osd_protocol.h
new file mode 100644
index 00000000000..a2594afe05c
--- /dev/null
+++ b/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 <bharrosh@panasas.com>
+ * Benny Halevy <bhalevy@panasas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ *
+ * This file contains types and constants that are defined by the protocol
+ * Note: All names and symbols are taken from the OSD standard's text.
+ */
+#ifndef __OSD_PROTOCOL_H__
+#define __OSD_PROTOCOL_H__
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/unaligned.h>
+#include <scsi/scsi.h>
+
+enum {
+ OSDv1_ADDITIONAL_CDB_LENGTH = 192,
+ OSDv1_TOTAL_CDB_LEN = OSDv1_ADDITIONAL_CDB_LENGTH + 8,
+ OSDv1_CAP_LEN = 80,
+
+ /* Latest supported version */
+ OSDv2_ADDITIONAL_CDB_LENGTH = 228,
+ OSD_ADDITIONAL_CDB_LENGTH =
+ OSDv2_ADDITIONAL_CDB_LENGTH,
+ OSD_TOTAL_CDB_LEN = OSD_ADDITIONAL_CDB_LENGTH + 8,
+ OSD_CAP_LEN = 104,
+
+ OSD_SYSTEMID_LEN = 20,
+ OSDv1_CRYPTO_KEYID_SIZE = 20,
+ OSDv2_CRYPTO_KEYID_SIZE = 32,
+ OSD_CRYPTO_KEYID_SIZE = OSDv2_CRYPTO_KEYID_SIZE,
+ OSD_CRYPTO_SEED_SIZE = 4,
+ OSD_CRYPTO_NONCE_SIZE = 12,
+ OSD_MAX_SENSE_LEN = 252, /* from SPC-3 */
+
+ OSD_PARTITION_FIRST_ID = 0x10000,
+ OSD_OBJECT_FIRST_ID = 0x10000,
+};
+
+/* (osd-r10 5.2.4)
+ * osd2r03: 5.2.3 Caching control bits
+ */
+enum osd_options_byte {
+ OSD_CDB_FUA = 0x08, /* Force Unit Access */
+ OSD_CDB_DPO = 0x10, /* Disable Page Out */
+};
+
+/*
+ * osd2r03: 5.2.5 Isolation.
+ * First 3 bits, V2-only.
+ * Also for attr 110h "default isolation method" at Root Information page
+ */
+enum osd_options_byte_isolation {
+ OSD_ISOLATION_DEFAULT = 0,
+ OSD_ISOLATION_NONE = 1,
+ OSD_ISOLATION_STRICT = 2,
+ OSD_ISOLATION_RANGE = 4,
+ OSD_ISOLATION_FUNCTIONAL = 5,
+ OSD_ISOLATION_VENDOR = 7,
+};
+
+/* (osd-r10: 6.7)
+ * osd2r03: 6.8 FLUSH, FLUSH COLLECTION, FLUSH OSD, FLUSH PARTITION
+ */
+enum osd_options_flush_scope_values {
+ OSD_CDB_FLUSH_ALL = 0,
+ OSD_CDB_FLUSH_ATTR_ONLY = 1,
+
+ OSD_CDB_FLUSH_ALL_RECURSIVE = 2,
+ /* V2-only */
+ OSD_CDB_FLUSH_ALL_RANGE = 2,
+};
+
+/* osd2r03: 5.2.10 Timestamps control */
+enum {
+ OSD_CDB_NORMAL_TIMESTAMPS = 0,
+ OSD_CDB_BYPASS_TIMESTAMPS = 0x7f,
+};
+
+/* (osd-r10: 5.2.2.1)
+ * osd2r03: 5.2.4.1 Get and set attributes CDB format selection
+ * 2 bits at second nibble of command_specific_options byte
+ */
+enum osd_attributes_mode {
+ /* V2-only */
+ OSD_CDB_SET_ONE_ATTR = 0x10,
+
+ OSD_CDB_GET_ATTR_PAGE_SET_ONE = 0x20,
+ OSD_CDB_GET_SET_ATTR_LISTS = 0x30,
+
+ OSD_CDB_GET_SET_ATTR_MASK = 0x30,
+};
+
+/* (osd-r10: 4.12.5)
+ * osd2r03: 4.14.5 Data-In and Data-Out buffer offsets
+ * byte offset = mantissa * (2^(exponent+8))
+ * struct {
+ * unsigned mantissa: 28;
+ * int exponent: 04;
+ * }
+ */
+typedef __be32 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 bharrosh@panasas.com */
+} __packed;
+
+/* for osd_capability.format */
+enum {
+ OSD_SEC_CAP_FORMAT_NO_CAPS = 0,
+ OSD_SEC_CAP_FORMAT_VER1 = 1,
+ OSD_SEC_CAP_FORMAT_VER2 = 2,
+};
+
+/* security_method */
+enum {
+ OSD_SEC_NOSEC = 0,
+ OSD_SEC_CAPKEY = 1,
+ OSD_SEC_CMDRSP = 2,
+ OSD_SEC_ALLDATA = 3,
+};
+
+enum object_type {
+ OSD_SEC_OBJ_ROOT = 0x1,
+ OSD_SEC_OBJ_PARTITION = 0x2,
+ OSD_SEC_OBJ_COLLECTION = 0x40,
+ OSD_SEC_OBJ_USER = 0x80,
+};
+
+enum osd_capability_bit_masks {
+ OSD_SEC_CAP_APPEND = BIT(0),
+ OSD_SEC_CAP_OBJ_MGMT = BIT(1),
+ OSD_SEC_CAP_REMOVE = BIT(2),
+ OSD_SEC_CAP_CREATE = BIT(3),
+ OSD_SEC_CAP_SET_ATTR = BIT(4),
+ OSD_SEC_CAP_GET_ATTR = BIT(5),
+ OSD_SEC_CAP_WRITE = BIT(6),
+ OSD_SEC_CAP_READ = BIT(7),
+
+ OSD_SEC_CAP_NONE1 = BIT(8),
+ OSD_SEC_CAP_NONE2 = BIT(9),
+ OSD_SEC_GBL_REM = BIT(10), /*v2 only*/
+ OSD_SEC_CAP_QUERY = BIT(11), /*v2 only*/
+ OSD_SEC_CAP_M_OBJECT = BIT(12), /*v2 only*/
+ OSD_SEC_CAP_POL_SEC = BIT(13),
+ OSD_SEC_CAP_GLOBAL = BIT(14),
+ OSD_SEC_CAP_DEV_MGMT = BIT(15),
+};
+
+/* for object_descriptor_type (hi nibble used) */
+enum {
+ OSD_SEC_OBJ_DESC_NONE = 0, /* Not allowed */
+ OSD_SEC_OBJ_DESC_OBJ = 1 << 4, /* v1: also collection */
+ OSD_SEC_OBJ_DESC_PAR = 2 << 4, /* also root */
+ OSD_SEC_OBJ_DESC_COL = 3 << 4, /* v2 only */
+};
+
+/* (osd-r10:4.9.2.2)
+ * osd2r03:4.11.2.2 Capability format
+ */
+struct osd_capability_head {
+ u8 format; /* low nibble */
+ u8 integrity_algorithm__key_version; /* MAKE_BYTE(integ_alg, key_ver) */
+ u8 security_method;
+ u8 reserved1;
+/*04*/ struct osd_timestamp expiration_time;
+/*10*/ u8 audit[20];
+/*30*/ u8 discriminator[12];
+/*42*/ struct osd_timestamp object_created_time;
+/*48*/ u8 object_type;
+/*49*/ u8 permissions_bit_mask[5];
+/*54*/ u8 reserved2;
+/*55*/ u8 object_descriptor_type; /* high nibble */
+} __packed;
+
+/*56 v1*/
+struct osdv1_cap_object_descriptor {
+ union {
+ struct {
+/*56*/ __be32 policy_access_tag;
+/*60*/ __be64 allowed_partition_id;
+/*68*/ __be64 allowed_object_id;
+/*76*/ __be32 reserved;
+ } __packed obj_desc;
+
+/*56*/ u8 object_descriptor[24];
+ };
+} __packed;
+/*80 v1*/
+
+/*56 v2*/
+struct osd_cap_object_descriptor {
+ union {
+ struct {
+/*56*/ __be32 allowed_attributes_access;
+/*60*/ __be32 policy_access_tag;
+/*64*/ __be16 boot_epoch;
+/*66*/ u8 reserved[6];
+/*72*/ __be64 allowed_partition_id;
+/*80*/ __be64 allowed_object_id;
+/*88*/ __be64 allowed_range_length;
+/*96*/ __be64 allowed_range_start;
+ } __packed obj_desc;
+
+/*56*/ u8 object_descriptor[48];
+ };
+} __packed;
+/*104 v2*/
+
+struct osdv1_capability {
+ struct osd_capability_head h;
+ struct osdv1_cap_object_descriptor od;
+} __packed;
+
+struct osd_capability {
+ struct osd_capability_head h;
+ struct osd_cap_object_descriptor od;
+} __packed;
+
+/**
+ * osd_sec_set_caps - set cap-bits into the capabilities header
+ *
+ * @cap: The osd_capability_head to set cap bits to.
+ * @bit_mask: Use an ORed list of enum osd_capability_bit_masks values
+ *
+ * permissions_bit_mask is unaligned use below to set into caps
+ * in a version independent way
+ */
+static inline void osd_sec_set_caps(struct osd_capability_head *cap,
+ u16 bit_mask)
+{
+ /*
+ *Note: The bits above are defined LE order this is because this way
+ * they can grow in the future to more then 16, and still retain
+ * there constant values.
+ */
+ put_unaligned_le16(bit_mask, &cap->permissions_bit_mask);
+}
+
+/* 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/include/scsi/osd_sec.h b/include/scsi/osd_sec.h
new file mode 100644
index 00000000000..f96151c9c9e
--- /dev/null
+++ b/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 <bharrosh@panasas.com>
+ * Benny Halevy <bhalevy@panasas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ *
+ */
+#ifndef __OSD_SEC_H__
+#define __OSD_SEC_H__
+
+#include <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/include/scsi/osd_sense.h b/include/scsi/osd_sense.h
new file mode 100644
index 00000000000..91db543a550
--- /dev/null
+++ b/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 <bharrosh@panasas.com>
+ * Benny Halevy <bhalevy@panasas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ *
+ * This file contains types and constants that are defined by the protocol
+ * Note: All names and symbols are taken from the OSD standard's text.
+ */
+#ifndef __OSD_SENSE_H__
+#define __OSD_SENSE_H__
+
+#include <scsi/osd_protocol.h>
+
+/* SPC3r23 4.5.6 Sense key and sense code definitions table 27 */
+enum scsi_sense_keys {
+ scsi_sk_no_sense = 0x0,
+ scsi_sk_recovered_error = 0x1,
+ scsi_sk_not_ready = 0x2,
+ scsi_sk_medium_error = 0x3,
+ scsi_sk_hardware_error = 0x4,
+ scsi_sk_illegal_request = 0x5,
+ scsi_sk_unit_attention = 0x6,
+ scsi_sk_data_protect = 0x7,
+ scsi_sk_blank_check = 0x8,
+ scsi_sk_vendor_specific = 0x9,
+ scsi_sk_copy_aborted = 0xa,
+ scsi_sk_aborted_command = 0xb,
+ scsi_sk_volume_overflow = 0xd,
+ scsi_sk_miscompare = 0xe,
+ scsi_sk_reserved = 0xf,
+};
+
+/* SPC3r23 4.5.6 Sense key and sense code definitions table 28 */
+/* Note: only those which can be returned by an OSD target. Most of
+ * these errors are taken care of by the generic scsi layer.
+ */
+enum osd_additional_sense_codes {
+ scsi_no_additional_sense_information = 0x0000,
+ scsi_operation_in_progress = 0x0016,
+ scsi_cleaning_requested = 0x0017,
+ scsi_lunr_cause_not_reportable = 0x0400,
+ scsi_logical_unit_is_in_process_of_becoming_ready = 0x0401,
+ scsi_lunr_initializing_command_required = 0x0402,
+ scsi_lunr_manual_intervention_required = 0x0403,
+ scsi_lunr_operation_in_progress = 0x0407,
+ scsi_lunr_selftest_in_progress = 0x0409,
+ scsi_luna_asymmetric_access_state_transition = 0x040a,
+ scsi_luna_target_port_in_standby_state = 0x040b,
+ scsi_luna_target_port_in_unavailable_state = 0x040c,
+ scsi_lunr_notify_enable_spinup_required = 0x0411,
+ scsi_logical_unit_does_not_respond_to_selection = 0x0500,
+ scsi_logical_unit_communication_failure = 0x0800,
+ scsi_logical_unit_communication_timeout = 0x0801,
+ scsi_logical_unit_communication_parity_error = 0x0802,
+ scsi_error_log_overflow = 0x0a00,
+ scsi_warning = 0x0b00,
+ scsi_warning_specified_temperature_exceeded = 0x0b01,
+ scsi_warning_enclosure_degraded = 0x0b02,
+ scsi_write_error_unexpected_unsolicited_data = 0x0c0c,
+ scsi_write_error_not_enough_unsolicited_data = 0x0c0d,
+ scsi_invalid_information_unit = 0x0e00,
+ scsi_invalid_field_in_command_information_unit = 0x0e03,
+ scsi_read_error_failed_retransmission_request = 0x1113,
+ scsi_parameter_list_length_error = 0x1a00,
+ scsi_invalid_command_operation_code = 0x2000,
+ scsi_invalid_field_in_cdb = 0x2400,
+ osd_security_audit_value_frozen = 0x2404,
+ osd_security_working_key_frozen = 0x2405,
+ osd_nonce_not_unique = 0x2406,
+ osd_nonce_timestamp_out_of_range = 0x2407,
+ scsi_logical_unit_not_supported = 0x2500,
+ scsi_invalid_field_in_parameter_list = 0x2600,
+ scsi_parameter_not_supported = 0x2601,
+ scsi_parameter_value_invalid = 0x2602,
+ scsi_invalid_release_of_persistent_reservation = 0x2604,
+ osd_invalid_dataout_buffer_integrity_check_value = 0x260f,
+ scsi_not_ready_to_ready_change_medium_may_have_changed = 0x2800,
+ scsi_power_on_reset_or_bus_device_reset_occurred = 0x2900,
+ scsi_power_on_occurred = 0x2901,
+ scsi_scsi_bus_reset_occurred = 0x2902,
+ scsi_bus_device_reset_function_occurred = 0x2903,
+ scsi_device_internal_reset = 0x2904,
+ scsi_transceiver_mode_changed_to_single_ended = 0x2905,
+ scsi_transceiver_mode_changed_to_lvd = 0x2906,
+ scsi_i_t_nexus_loss_occurred = 0x2907,
+ scsi_parameters_changed = 0x2a00,
+ scsi_mode_parameters_changed = 0x2a01,
+ scsi_asymmetric_access_state_changed = 0x2a06,
+ scsi_priority_changed = 0x2a08,
+ scsi_command_sequence_error = 0x2c00,
+ scsi_previous_busy_status = 0x2c07,
+ scsi_previous_task_set_full_status = 0x2c08,
+ scsi_previous_reservation_conflict_status = 0x2c09,
+ osd_partition_or_collection_contains_user_objects = 0x2c0a,
+ scsi_commands_cleared_by_another_initiator = 0x2f00,
+ scsi_cleaning_failure = 0x3007,
+ scsi_enclosure_failure = 0x3400,
+ scsi_enclosure_services_failure = 0x3500,
+ scsi_unsupported_enclosure_function = 0x3501,
+ scsi_enclosure_services_unavailable = 0x3502,
+ scsi_enclosure_services_transfer_failure = 0x3503,
+ scsi_enclosure_services_transfer_refused = 0x3504,
+ scsi_enclosure_services_checksum_error = 0x3505,
+ scsi_rounded_parameter = 0x3700,
+ osd_read_past_end_of_user_object = 0x3b17,
+ scsi_logical_unit_has_not_self_configured_yet = 0x3e00,
+ scsi_logical_unit_failure = 0x3e01,
+ scsi_timeout_on_logical_unit = 0x3e02,
+ scsi_logical_unit_failed_selftest = 0x3e03,
+ scsi_logical_unit_unable_to_update_selftest_log = 0x3e04,
+ scsi_target_operating_conditions_have_changed = 0x3f00,
+ scsi_microcode_has_been_changed = 0x3f01,
+ scsi_inquiry_data_has_changed = 0x3f03,
+ scsi_echo_buffer_overwritten = 0x3f0f,
+ scsi_diagnostic_failure_on_component_nn_first = 0x4080,
+ scsi_diagnostic_failure_on_component_nn_last = 0x40ff,
+ scsi_message_error = 0x4300,
+ scsi_internal_target_failure = 0x4400,
+ scsi_select_or_reselect_failure = 0x4500,
+ scsi_scsi_parity_error = 0x4700,
+ scsi_data_phase_crc_error_detected = 0x4701,
+ scsi_scsi_parity_error_detected_during_st_data_phase = 0x4702,
+ scsi_asynchronous_information_protection_error_detected = 0x4704,
+ scsi_protocol_service_crc_error = 0x4705,
+ scsi_phy_test_function_in_progress = 0x4706,
+ scsi_invalid_message_error = 0x4900,
+ scsi_command_phase_error = 0x4a00,
+ scsi_data_phase_error = 0x4b00,
+ scsi_logical_unit_failed_self_configuration = 0x4c00,
+ scsi_overlapped_commands_attempted = 0x4e00,
+ osd_quota_error = 0x5507,
+ scsi_failure_prediction_threshold_exceeded = 0x5d00,
+ scsi_failure_prediction_threshold_exceeded_false = 0x5dff,
+ scsi_voltage_fault = 0x6500,
+};
+
+enum scsi_descriptor_types {
+ scsi_sense_information = 0x0,
+ scsi_sense_command_specific_information = 0x1,
+ scsi_sense_key_specific = 0x2,
+ scsi_sense_field_replaceable_unit = 0x3,
+ scsi_sense_stream_commands = 0x4,
+ scsi_sense_block_commands = 0x5,
+ osd_sense_object_identification = 0x6,
+ osd_sense_response_integrity_check = 0x7,
+ osd_sense_attribute_identification = 0x8,
+ scsi_sense_ata_return = 0x9,
+
+ scsi_sense_Reserved_first = 0x0A,
+ scsi_sense_Reserved_last = 0x7F,
+ scsi_sense_Vendor_specific_first = 0x80,
+ scsi_sense_Vendor_specific_last = 0xFF,
+};
+
+struct scsi_sense_descriptor { /* for picking into desc type */
+ u8 descriptor_type; /* one of enum scsi_descriptor_types */
+ u8 additional_length; /* n - 1 */
+ u8 data[];
+} __packed;
+
+/* OSD deploys only scsi descriptor_based sense buffers */
+struct scsi_sense_descriptor_based {
+/*0*/ u8 response_code; /* 0x72 or 0x73 */
+/*1*/ u8 sense_key; /* one of enum scsi_sense_keys (4 lower bits) */
+/*2*/ __be16 additional_sense_code; /* enum osd_additional_sense_codes */
+/*4*/ u8 Reserved[3];
+/*7*/ u8 additional_sense_length; /* n - 7 */
+/*8*/ struct scsi_sense_descriptor ssd[0]; /* variable length, 1 or more */
+} __packed;
+
+/* some descriptors deployed by OSD */
+
+/* SPC3r23 4.5.2.3 Command-specific information sense data descriptor */
+/* Note: this is the same for descriptor_type=00 but with type=00 the
+ * Reserved[0] == 0x80 (ie. bit-7 set)
+ */
+struct scsi_sense_command_specific_data_descriptor {
+/*0*/ u8 descriptor_type; /* (00h/01h) */
+/*1*/ u8 additional_length; /* (0Ah) */
+/*2*/ u8 Reserved[2];
+/*4*/ __be64 information;
+} __packed;
+/*12*/
+
+struct scsi_sense_key_specific_data_descriptor {
+/*0*/ u8 descriptor_type; /* (02h) */
+/*1*/ u8 additional_length; /* (06h) */
+/*2*/ u8 Reserved[2];
+/* SKSV, C/D, Reserved (2), BPV, BIT POINTER (3) */
+/*4*/ u8 sksv_cd_bpv_bp;
+/*5*/ __be16 value; /* field-pointer/progress-value/retry-count/... */
+/*7*/ u8 Reserved2;
+} __packed;
+/*8*/
+
+/* 4.16.2.1 OSD error identification sense data descriptor - table 52 */
+/* Note: these bits are defined LE order for easy definition, this way the BIT()
+ * number is the same as in the documentation. Below members at
+ * osd_sense_identification_data_descriptor are therefore defined __le32.
+ */
+enum osd_command_functions_bits {
+ OSD_CFB_COMMAND = BIT(4),
+ OSD_CFB_CMD_CAP_VERIFIED = BIT(5),
+ OSD_CFB_VALIDATION = BIT(7),
+ OSD_CFB_IMP_ST_ATT = BIT(12),
+ OSD_CFB_SET_ATT = BIT(20),
+ OSD_CFB_SA_CAP_VERIFIED = BIT(21),
+ OSD_CFB_GET_ATT = BIT(28),
+ OSD_CFB_GA_CAP_VERIFIED = BIT(29),
+};
+
+struct osd_sense_identification_data_descriptor {
+/*0*/ u8 descriptor_type; /* (06h) */
+/*1*/ u8 additional_length; /* (1Eh) */
+/*2*/ u8 Reserved[6];
+/*8*/ __le32 not_initiated_functions; /*osd_command_functions_bits*/
+/*12*/ __le32 completed_functions; /*osd_command_functions_bits*/
+/*16*/ __be64 partition_id;
+/*24*/ __be64 object_id;
+} __packed;
+/*32*/
+
+struct osd_sense_response_integrity_check_descriptor {
+/*0*/ u8 descriptor_type; /* (07h) */
+/*1*/ u8 additional_length; /* (20h) */
+/*2*/ u8 integrity_check_value[32]; /*FIXME: OSDv2_CRYPTO_KEYID_SIZE*/
+} __packed;
+/*34*/
+
+struct osd_sense_attributes_data_descriptor {
+/*0*/ u8 descriptor_type; /* (08h) */
+/*1*/ u8 additional_length; /* (n-2) */
+/*2*/ u8 Reserved[6];
+ struct osd_sense_attr {
+/*8*/ __be32 attr_page;
+/*12*/ __be32 attr_id;
+/*16*/ } sense_attrs[0]; /* 1 or more */
+} __packed;
+/*variable*/
+
+/* Dig into scsi_sk_illegal_request/scsi_invalid_field_in_cdb errors */
+
+/*FIXME: Support also field in CAPS*/
+#define OSD_CDB_OFFSET(F) offsetof(struct osd_cdb_head, F)
+
+enum osdv2_cdb_field_offset {
+ OSDv1_CFO_STARTING_BYTE = OSD_CDB_OFFSET(v1.start_address),
+ OSD_CFO_STARTING_BYTE = OSD_CDB_OFFSET(v2.start_address),
+ OSD_CFO_PARTITION_ID = OSD_CDB_OFFSET(partition),
+ OSD_CFO_OBJECT_ID = OSD_CDB_OFFSET(object),
+ OSD_CFO_PERMISSIONS = sizeof(struct osd_cdb_head) +
+ offsetof(struct osd_capability_head,
+ permissions_bit_mask),
+};
+
+#endif /* ndef __OSD_SENSE_H__ */
diff --git a/include/scsi/osd_types.h b/include/scsi/osd_types.h
new file mode 100644
index 00000000000..bd0be7ed4bc
--- /dev/null
+++ b/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 <bharrosh@panasas.com>
+ * Benny Halevy <bhalevy@panasas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ *
+ * Contains types and constants that are implementation specific and are
+ * used by more than one part of the osd library.
+ * (Eg initiator/target/security_manager/...)
+ */
+#ifndef __OSD_TYPES_H__
+#define __OSD_TYPES_H__
+
+struct osd_systemid {
+ u8 data[OSD_SYSTEMID_LEN];
+};
+
+typedef u64 __bitwise osd_id;
+
+struct osd_obj_id {
+ osd_id partition;
+ osd_id id;
+};
+
+static const struct __weak osd_obj_id osd_root_object = {0, 0};
+
+struct osd_attr {
+ u32 attr_page;
+ u32 attr_id;
+ u16 len; /* byte count of operand */
+ void *val_ptr; /* in network order */
+};
+
+struct osd_sg_entry {
+ u64 offset;
+ u64 len;
+};
+
+#endif /* ndef __OSD_TYPES_H__ */
diff --git a/include/scsi/sas.h b/include/scsi/sas.h
new file mode 100644
index 00000000000..0d2607d1238
--- /dev/null
+++ b/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/include/scsi/sas_ata.h b/include/scsi/sas_ata.h
new file mode 100644
index 00000000000..00f41aeeecf
--- /dev/null
+++ b/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/include/scsi/scsi.h b/include/scsi/scsi.h
index 9c331258bc2..0a4edfe8af5 100644
--- a/include/scsi/scsi.h
+++ b/include/scsi/scsi.h
@@ -9,27 +9,39 @@
#define _SCSI_SCSI_H
#include <linux/types.h>
+#include <linux/scatterlist.h>
+#include <linux/kernel.h>
-/*
- * The maximum sg list length SCSI can cope with
- * (currently must be a power of 2 between 32 and 256)
- */
-#define SCSI_MAX_PHYS_SEGMENTS MAX_PHYS_SEGMENTS
+struct scsi_cmnd;
+enum scsi_timeouts {
+ SCSI_DEFAULT_EH_TIMEOUT = 10 * HZ,
+};
/*
- * SCSI command lengths
+ * 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
*/
-
-extern const unsigned char scsi_command_size[8];
-#define COMMAND_SIZE(opcode) scsi_command_size[((opcode) >> 5) & 7]
+#define SCSI_MAX_SG_SEGMENTS 128
/*
- * SCSI device types
+ * Like SCSI_MAX_SG_SEGMENTS, but for archs that have sg chaining. This limit
+ * is totally arbitrary, a setting of 2048 will get you at least 8mb ios.
*/
+#ifdef ARCH_HAS_SG_CHAIN
+#define SCSI_MAX_SG_CHAIN_SEGMENTS 2048
+#else
+#define SCSI_MAX_SG_CHAIN_SEGMENTS SCSI_MAX_SG_SEGMENTS
+#endif
-#define MAX_SCSI_DEVICE_CODE 15
-extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
+/*
+ * 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
@@ -67,6 +79,7 @@ extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
#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
@@ -94,39 +107,133 @@ extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
#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 WRITE_12 0xaa
+#define READ_MEDIA_SERIAL_NUMBER 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_IN 0x9e
/* 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 */
/*
+ * 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.
*/
@@ -207,6 +314,7 @@ static inline int scsi_status_is_good(int status)
/*
* DEVICE TYPES
+ * Please keep them in 0x%02x format for $MODALIAS to work
*/
#define TYPE_DISK 0x00
@@ -223,8 +331,26 @@ static inline int scsi_status_is_good(int status)
#define TYPE_RAID 0x0c
#define TYPE_ENCLOSURE 0x0d /* Enclosure Services Device */
#define TYPE_RBC 0x0e
+#define TYPE_OSD 0x11
#define TYPE_NO_LUN 0x7f
+/* SCSI protocols; these are taken from SPC-3 section 7.5 */
+enum scsi_protocol {
+ SCSI_PROTOCOL_FCP = 0, /* Fibre Channel */
+ SCSI_PROTOCOL_SPI = 1, /* parallel SCSI */
+ SCSI_PROTOCOL_SSA = 2, /* Serial Storage Architecture - Obsolete */
+ SCSI_PROTOCOL_SBP = 3, /* firewire */
+ SCSI_PROTOCOL_SRP = 4, /* Infiniband RDMA */
+ SCSI_PROTOCOL_ISCSI = 5,
+ SCSI_PROTOCOL_SAS = 6,
+ SCSI_PROTOCOL_ADT = 7, /* Media Changers */
+ SCSI_PROTOCOL_ATA = 8,
+ SCSI_PROTOCOL_UNSPEC = 0xf, /* No specific protocol */
+};
+
+/* Returns a human-readable name for the device */
+extern const char * scsi_device_type(unsigned type);
+
/*
* standard mode-select header prepended to all mode-select commands
*/
@@ -252,6 +378,20 @@ struct scsi_lun {
};
/*
+ * The Well Known LUNS (SAM-3) in our int representation of a LUN
+ */
+#define SCSI_W_LUN_BASE 0xc100
+#define SCSI_W_LUN_REPORT_LUNS (SCSI_W_LUN_BASE + 1)
+#define SCSI_W_LUN_ACCESS_CONTROL (SCSI_W_LUN_BASE + 2)
+#define SCSI_W_LUN_TARGET_LOG_PAGE (SCSI_W_LUN_BASE + 3)
+
+static inline int scsi_is_wlun(unsigned int lun)
+{
+ return (lun & 0xff00) == SCSI_W_LUN_BASE;
+}
+
+
+/*
* MESSAGE CODES
*/
@@ -310,6 +450,17 @@ struct scsi_lun {
#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 */
/*
@@ -326,16 +477,6 @@ struct scsi_lun {
#define DRIVER_HARD 0x07
#define DRIVER_SENSE 0x08
-#define SUGGEST_RETRY 0x10
-#define SUGGEST_ABORT 0x20
-#define SUGGEST_REMAP 0x30
-#define SUGGEST_DIE 0x40
-#define SUGGEST_SENSE 0x80
-#define SUGGEST_IS_OK 0xff
-
-#define DRIVER_MASK 0x0f
-#define SUGGEST_MASK 0xf0
-
/*
* Internal return values.
*/
@@ -347,6 +488,8 @@ struct scsi_lun {
#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.
@@ -354,6 +497,7 @@ struct scsi_lun {
#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
@@ -369,11 +513,10 @@ struct scsi_lun {
#define msg_byte(result) (((result) >> 8) & 0xff)
#define host_byte(result) (((result) >> 16) & 0xff)
#define driver_byte(result) (((result) >> 24) & 0xff)
-#define suggestion(result) (driver_byte(result) & SUGGEST_MASK)
#define sense_class(sense) (((sense) >> 4) & 0x7)
#define sense_error(sense) ((sense) & 0xf)
-#define sense_valid(sense) ((sense) & 0x80);
+#define sense_valid(sense) ((sense) & 0x80)
/*
* default timeouts
@@ -433,6 +576,10 @@ struct scsi_lun {
/* Used to obtain the PCI location of a device */
#define SCSI_IOCTL_GET_PCI 0x5387
-int scsi_execute_in_process_context(void (*fn)(void *data), void *data);
+/* 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/include/scsi/scsi_bsg_iscsi.h b/include/scsi/scsi_bsg_iscsi.h
new file mode 100644
index 00000000000..fd5689d4c05
--- /dev/null
+++ b/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/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
index 7529f4388bb..e0ae7109814 100644
--- a/include/scsi/scsi_cmnd.h
+++ b/include/scsi/scsi_cmnd.h
@@ -2,15 +2,39 @@
#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 request;
-struct scatterlist;
+struct Scsi_Host;
struct scsi_device;
-struct scsi_request;
+struct scsi_driver;
+/*
+ * 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 {
@@ -29,29 +53,22 @@ struct scsi_pointer {
};
struct scsi_cmnd {
- int sc_magic;
-
struct scsi_device *device;
- struct scsi_request *sc_request;
-
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 */
- void (*done) (struct scsi_cmnd *); /* Mid-level done function */
/*
* 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 currently doesn't have much use other
- * than printk's. Some lldd's use this number for other purposes.
- * It's almost certain that such usages are either incorrect or
- * meaningless. Please kill all usages other than printk's. Also,
- * as this number is always identical to ->pid, please convert
- * printk's to use ->pid, so that we can kill this field.
+ * 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
@@ -61,34 +78,23 @@ struct scsi_cmnd {
int retries;
int allowed;
- int timeout_per_command;
- unsigned char cmd_len;
- unsigned char old_cmd_len;
+ unsigned char prot_op;
+ unsigned char prot_type;
+
+ unsigned short cmd_len;
enum dma_data_direction sc_data_direction;
- enum dma_data_direction sc_old_data_direction;
/* These elements define the operation we are about to perform */
-#define MAX_COMMAND_SIZE 16
- unsigned char cmnd[MAX_COMMAND_SIZE];
- unsigned request_bufflen; /* Actual request size */
+ unsigned char *cmnd;
- struct timer_list eh_timeout; /* Used to time out the command. */
- void *request_buffer; /* Actual requested buffer */
/* These elements define the operation we ultimately want to perform */
- unsigned char data_cmnd[MAX_COMMAND_SIZE];
- unsigned short old_use_sg; /* We save use_sg here when requesting
- * sense info */
- unsigned short use_sg; /* Number of pieces of scatter-gather */
- unsigned short sglist_len; /* size of malloc'd scatter-gather list */
- unsigned bufflen; /* Size of data buffer */
- void *buffer; /* Data buffer */
+ struct scsi_data_buffer sdb;
+ struct scsi_data_buffer *prot_sdb;
unsigned underflow; /* Return error if less than
this amount is transferred */
- unsigned old_underflow; /* save underflow here when reusing the
- * command for error handling */
unsigned transfersize; /* How much we are guaranteed to
transfer with each SCSI transfer
@@ -96,18 +102,14 @@ struct scsi_cmnd {
reconnects. Probably == sector
size */
- int resid; /* Number of bytes requested to be
- transferred less actual number
- transferred (0 if not supported) */
-
struct request *request; /* The command we are
working on */
#define SCSI_SENSE_BUFFERSIZE 96
- unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE]; /* obtained by REQUEST SENSE
- * when CHECK CONDITION is
- * received on original command
- * (auto-sense) */
+ 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. */
@@ -120,36 +122,214 @@ struct scsi_cmnd {
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). */
+ * call scsi_malloc and get some memory
+ * and hang it here. The host adapter
+ * is also expected to call scsi_free
+ * to release this memory. (The memory
+ * obtained by scsi_malloc is guaranteed
+ * to be at an address < 16Mb). */
int result; /* Status code from lower level driver */
unsigned char tag; /* SCSI-II queued command tag */
- unsigned long pid; /* Process ID, starts at 0. Unique per host. */
};
/*
- * These are the values that scsi_cmd->state can take.
+ * Return the driver private allocation behind the command.
+ * Only works if cmd_size is set in the host template.
*/
-#define SCSI_STATE_TIMEOUT 0x1000
-#define SCSI_STATE_FINISHED 0x1001
-#define SCSI_STATE_FAILED 0x1002
-#define SCSI_STATE_QUEUED 0x1003
-#define SCSI_STATE_UNUSED 0x1006
-#define SCSI_STATE_DISCONNECTING 0x1008
-#define SCSI_STATE_INITIALIZING 0x1009
-#define SCSI_STATE_BHQUEUE 0x100a
-#define SCSI_STATE_MLQUEUE 0x100b
+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 struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *, gfp_t);
extern void scsi_put_command(struct scsi_cmnd *);
-extern void scsi_io_completion(struct scsi_cmnd *, unsigned int, unsigned int);
+extern void __scsi_put_command(struct Scsi_Host *, 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, gfp_t gfp_mask);
+extern void scsi_release_buffers(struct scsi_cmnd *cmd);
+
+extern int scsi_dma_map(struct scsi_cmnd *cmd);
+extern void scsi_dma_unmap(struct scsi_cmnd *cmd);
+
+static inline unsigned scsi_sg_count(struct scsi_cmnd *cmd)
+{
+ return cmd->sdb.table.nents;
+}
+
+static inline struct scatterlist *scsi_sglist(struct scsi_cmnd *cmd)
+{
+ return cmd->sdb.table.sgl;
+}
+
+static inline unsigned scsi_bufflen(struct scsi_cmnd *cmd)
+{
+ return cmd->sdb.length;
+}
+
+static inline void scsi_set_resid(struct scsi_cmnd *cmd, int resid)
+{
+ cmd->sdb.resid = resid;
+}
+
+static inline int scsi_get_resid(struct scsi_cmnd *cmd)
+{
+ return cmd->sdb.resid;
+}
+
+#define scsi_for_each_sg(cmd, sg, nseg, __i) \
+ for_each_sg(scsi_sglist(cmd), sg, nseg, __i)
+
+static inline int scsi_bidi_cmnd(struct scsi_cmnd *cmd)
+{
+ return blk_bidi_rq(cmd->request) &&
+ (cmd->request->next_rq->special != NULL);
+}
+
+static inline struct scsi_data_buffer *scsi_in(struct scsi_cmnd *cmd)
+{
+ return scsi_bidi_cmnd(cmd) ?
+ cmd->request->next_rq->special : &cmd->sdb;
+}
+
+static inline struct scsi_data_buffer *scsi_out(struct scsi_cmnd *cmd)
+{
+ return &cmd->sdb;
+}
+
+static inline int scsi_sg_copy_from_buffer(struct scsi_cmnd *cmd,
+ void *buf, int buflen)
+{
+ return sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd),
+ buf, buflen);
+}
+
+static inline int scsi_sg_copy_to_buffer(struct scsi_cmnd *cmd,
+ void *buf, int buflen)
+{
+ return sg_copy_to_buffer(scsi_sglist(cmd), scsi_sg_count(cmd),
+ buf, buflen);
+}
+
+/*
+ * The operations below are hints that tell the controller driver how
+ * to handle I/Os with DIF or similar types of protection information.
+ */
+enum scsi_prot_operations {
+ /* Normal I/O */
+ SCSI_PROT_NORMAL = 0,
+
+ /* OS-HBA: Protected, HBA-Target: Unprotected */
+ SCSI_PROT_READ_INSERT,
+ SCSI_PROT_WRITE_STRIP,
+
+ /* OS-HBA: Unprotected, HBA-Target: Protected */
+ SCSI_PROT_READ_STRIP,
+ SCSI_PROT_WRITE_INSERT,
+
+ /* OS-HBA: Protected, HBA-Target: Protected */
+ SCSI_PROT_READ_PASS,
+ SCSI_PROT_WRITE_PASS,
+};
+
+static inline void scsi_set_prot_op(struct scsi_cmnd *scmd, unsigned char op)
+{
+ scmd->prot_op = op;
+}
+
+static inline unsigned char scsi_get_prot_op(struct scsi_cmnd *scmd)
+{
+ return scmd->prot_op;
+}
+
+/*
+ * The controller usually does not know anything about the target it
+ * is communicating with. However, when DIX is enabled the controller
+ * must be know target type so it can verify the protection
+ * information passed along with the I/O.
+ */
+enum scsi_prot_target_type {
+ SCSI_PROT_DIF_TYPE0 = 0,
+ SCSI_PROT_DIF_TYPE1,
+ SCSI_PROT_DIF_TYPE2,
+ SCSI_PROT_DIF_TYPE3,
+};
+
+static inline void scsi_set_prot_type(struct scsi_cmnd *scmd, unsigned char type)
+{
+ scmd->prot_type = type;
+}
+
+static inline unsigned char scsi_get_prot_type(struct scsi_cmnd *scmd)
+{
+ return scmd->prot_type;
+}
+
+static inline sector_t scsi_get_lba(struct scsi_cmnd *scmd)
+{
+ return blk_rq_pos(scmd->request);
+}
+
+static inline unsigned scsi_prot_sg_count(struct scsi_cmnd *cmd)
+{
+ return cmd->prot_sdb ? cmd->prot_sdb->table.nents : 0;
+}
+
+static inline struct scatterlist *scsi_prot_sglist(struct scsi_cmnd *cmd)
+{
+ return cmd->prot_sdb ? cmd->prot_sdb->table.sgl : NULL;
+}
+
+static inline struct scsi_data_buffer *scsi_prot(struct scsi_cmnd *cmd)
+{
+ return cmd->prot_sdb;
+}
+
+#define scsi_for_each_prot_sg(cmd, sg, nseg, __i) \
+ for_each_sg(scsi_prot_sglist(cmd), sg, nseg, __i)
+
+static inline void set_msg_byte(struct scsi_cmnd *cmd, char status)
+{
+ cmd->result = (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_op = scsi_get_prot_op(scmd);
+ unsigned int sector_size = scmd->device->sector_size;
+
+ switch (prot_op) {
+ case SCSI_PROT_NORMAL:
+ case SCSI_PROT_WRITE_STRIP:
+ case SCSI_PROT_READ_INSERT:
+ return xfer_len;
+ }
+
+ return xfer_len + (xfer_len >> ilog2(sector_size)) * 8;
+}
+
#endif /* _SCSI_SCSI_CMND_H */
diff --git a/include/scsi/scsi_dbg.h b/include/scsi/scsi_dbg.h
index 4d69dee66d4..e89844cc2cd 100644
--- a/include/scsi/scsi_dbg.h
+++ b/include/scsi/scsi_dbg.h
@@ -2,19 +2,21 @@
#define _SCSI_SCSI_DBG_H
struct scsi_cmnd;
-struct scsi_request;
struct scsi_sense_hdr;
extern void scsi_print_command(struct scsi_cmnd *);
-extern void scsi_print_sense_hdr(const char *, struct scsi_sense_hdr *);
extern void __scsi_print_command(unsigned char *);
-extern void scsi_print_sense(const char *, struct scsi_cmnd *);
-extern void scsi_print_req_sense(const char *, struct scsi_request *);
+extern void scsi_show_extd_sense(unsigned char, unsigned char);
+extern void scsi_show_sense_hdr(struct scsi_sense_hdr *);
+extern void scsi_print_sense_hdr(const char *, struct scsi_sense_hdr *);
+extern void scsi_cmd_print_sense_hdr(struct scsi_cmnd *, const char *,
+ struct scsi_sense_hdr *);
+extern void scsi_print_sense(char *, struct scsi_cmnd *);
extern void __scsi_print_sense(const char *name,
const unsigned char *sense_buffer,
int sense_len);
-extern void scsi_print_driverbyte(int);
-extern void scsi_print_hostbyte(int);
+extern void scsi_show_result(int);
+extern void scsi_print_result(struct scsi_cmnd *);
extern void scsi_print_status(unsigned char);
extern const char *scsi_sense_key_string(unsigned char);
extern const char *scsi_extd_sense_format(unsigned char, unsigned char);
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index 290e3b4d2ae..27ab31017f0 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -1,11 +1,14 @@
#ifndef _SCSI_SCSI_DEVICE_H
#define _SCSI_SCSI_DEVICE_H
-#include <linux/device.h>
#include <linux/list.h>
#include <linux/spinlock.h>
-#include <asm/atomic.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;
@@ -39,9 +42,35 @@ enum scsi_device_state {
* originate in the mid-layer) */
SDEV_OFFLINE, /* Device offlined (by error handling or
* user request */
- SDEV_BLOCK, /* Device blocked by scsi lld. No scsi
- * commands from user or midlayer should be issued
- * to the scsi lld. */
+ SDEV_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 {
@@ -60,11 +89,14 @@ struct scsi_device {
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;/* don't let QUEUE_FULLs on the same
- jiffie count on our counter, they
- could all be from the same event. */
+ 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, lun, channel;
@@ -73,7 +105,6 @@ struct scsi_device {
unsigned sector_size; /* size in bytes */
void *hostdata; /* available to low-level driver */
- char devfs_name[256]; /* devfs junk */
char type;
char scsi_level;
char inq_periph_qual; /* PQ from INQUIRY data */
@@ -82,6 +113,12 @@ struct scsi_device {
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 */
@@ -89,6 +126,7 @@ struct scsi_device {
* scsi_devinfo.[hc]. For now used only to
* pass settings from slave_alloc to scsi
* core. */
+ unsigned int eh_timeout; /* Error handling timeout */
unsigned writeable:1;
unsigned removable:1;
unsigned changed:1; /* Data invalid due to media change */
@@ -105,24 +143,44 @@ struct scsi_device {
unsigned tagged_supported:1; /* Supports SCSI-II tagged queuing */
unsigned simple_tags:1; /* simple queue tag messages are enabled */
unsigned ordered_tags:1;/* ordered queue tag messages are enabled */
- unsigned single_lun:1; /* Indicates we should only allow I/O to
- * one of the luns for the device at a
- * time. */
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 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 */
+
+ 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 device_blocked; /* Device returned QUEUE_FULL. */
@@ -133,26 +191,80 @@ struct scsi_device {
atomic_t iodone_cnt;
atomic_t ioerr_cnt;
- int timeout;
+ struct device sdev_gendev,
+ sdev_dev;
- struct device sdev_gendev;
- struct class_device sdev_classdev;
+ 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))));
+
+struct scsi_dh_devlist {
+ char *vendor;
+ char *model;
+};
+
+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;
+ const struct scsi_dh_devlist *devlist;
+ int (*check_sense)(struct scsi_device *, struct scsi_sense_hdr *);
+ int (*attach)(struct scsi_device *);
+ void (*detach)(struct scsi_device *);
+ int (*activate)(struct scsi_device *, 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;
+ char buf[0];
+};
+
#define to_scsi_device(d) \
container_of(d, struct scsi_device, sdev_gendev)
#define class_to_sdev(d) \
- container_of(d, struct scsi_device, sdev_classdev)
+ container_of(d, struct scsi_device, sdev_dev)
#define transport_class_to_sdev(class_dev) \
- to_scsi_device(class_dev->dev)
+ to_scsi_device(class_dev->parent)
#define sdev_printk(prefix, sdev, fmt, a...) \
dev_printk(prefix, &(sdev)->sdev_gendev, fmt, ##a)
-#define scmd_printk(prefix, scmd, fmt, a...) \
- dev_printk(prefix, &(scmd)->device->sdev_gendev, fmt, ##a)
+#define sdev_dbg(sdev, fmt, a...) \
+ dev_dbg(&(sdev)->sdev_gendev, fmt, ##a)
+
+#define scmd_printk(prefix, scmd, fmt, a...) \
+ (scmd)->request->rq_disk ? \
+ sdev_printk(prefix, (scmd)->device, "[%s] " fmt, \
+ (scmd)->request->rq_disk->disk_name, ##a) : \
+ sdev_printk(prefix, (scmd)->device, fmt, ##a)
+
+#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
@@ -164,12 +276,34 @@ struct scsi_target {
struct list_head siblings;
struct list_head devices;
struct device dev;
- unsigned int reap_ref; /* protected by the host lock */
+ struct kref reap_ref; /* last put renders target invisible */
unsigned int channel;
unsigned int id; /* target id ... replace
* scsi_device.id eventually */
- unsigned long create:1; /* signal that it needs to be added */
+ 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. protected by host lock. */
+ unsigned int target_busy;
+ /*
+ * LLDs should set this in the slave_alloc host template callout.
+ * If set to zero then there is not limit.
+ */
+ unsigned int can_queue;
+ unsigned int target_blocked;
+ unsigned int max_target_blocked;
+#define SCSI_DEFAULT_TARGET_BLOCKED 3
+
char scsi_level;
+ 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!!!! */
@@ -181,7 +315,7 @@ 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->dev)
+ to_scsi_target(class_dev->parent)
#define starget_printk(prefix, starget, fmt, a...) \
dev_printk(prefix, &(starget)->dev, fmt, ##a)
@@ -190,8 +324,10 @@ extern struct scsi_device *__scsi_add_device(struct Scsi_Host *,
uint, uint, uint, void *hostdata);
extern int scsi_add_device(struct Scsi_Host *host, uint channel,
uint target, uint lun);
+extern int scsi_register_device_handler(struct scsi_device_handler *scsi_dh);
extern void scsi_remove_device(struct scsi_device *);
-extern int scsi_device_cancel(struct scsi_device *, int);
+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 *);
@@ -205,19 +341,22 @@ extern struct scsi_device *__scsi_device_lookup_by_target(struct scsi_target *,
uint);
extern void starget_for_each_device(struct scsi_target *, void *,
void (*fn)(struct scsi_device *, void *));
+extern void __starget_for_each_device(struct scsi_target *, void *,
+ void (*fn)(struct scsi_device *,
+ void *));
/* only exposed to implement shost_for_each_device */
extern struct scsi_device *__scsi_iterate_devices(struct Scsi_Host *,
struct scsi_device *);
/**
- * shost_for_each_device - iterate over all devices of a host
- * @sdev: iterator
- * @host: host whiches devices we want to iterate over
+ * 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
*
- * This traverses over each devices of @shost. The devices have
- * a reference that must be released by scsi_host_put when breaking
- * out of the loop.
+ * 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); \
@@ -225,17 +364,17 @@ extern struct scsi_device *__scsi_iterate_devices(struct Scsi_Host *,
(sdev) = __scsi_iterate_devices((shost), (sdev)))
/**
- * __shost_for_each_device - iterate over all devices of a host (UNLOCKED)
- * @sdev: iterator
- * @host: host whiches devices we want to iterate over
+ * __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
*
- * This traverses over each devices of @shost. It does _not_ take a
- * reference on the scsi_device, thus it the whole loop must be protected
- * by shost->host_lock.
+ * 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 why drivers would want to use this is because
- * they're need to access the device list in irq context. Otherwise you
- * really want to use shost_for_each_device instead.
+ * 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)
@@ -249,10 +388,24 @@ 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);
+ 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 *);
@@ -261,25 +414,44 @@ extern void scsi_scan_target(struct device *parent, unsigned int channel,
unsigned int id, unsigned int lun, int rescan);
extern void scsi_target_reap(struct scsi_target *);
extern void scsi_target_block(struct device *);
-extern void scsi_target_unblock(struct device *);
+extern void scsi_target_unblock(struct device *, enum scsi_device_state);
extern void scsi_remove_target(struct device *);
extern void int_to_scsilun(unsigned int, struct scsi_lun *);
+extern int scsilun_to_int(struct scsi_lun *);
extern const char *scsi_device_state_name(enum scsi_device_state);
extern int scsi_is_sdev_device(const struct device *);
extern int scsi_is_target_device(const struct device *);
extern int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
int data_direction, void *buffer, unsigned bufflen,
unsigned char *sense, int timeout, int retries,
- int flag);
-extern int scsi_execute_req(struct scsi_device *sdev, const unsigned char *cmd,
- int data_direction, void *buffer, unsigned bufflen,
- struct scsi_sense_hdr *, int timeout, int retries);
-extern int scsi_execute_async(struct scsi_device *sdev,
- const unsigned char *cmd, int cmd_len, int data_direction,
- void *buffer, unsigned bufflen, int use_sg,
- int timeout, int retries, void *privdata,
- void (*done)(void *, char *, int, int),
- gfp_t gfp);
+ 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_RUNTIME
+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_RUNTIME */
+
+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)
{
@@ -294,9 +466,24 @@ static inline unsigned int sdev_id(struct scsi_device *sdev)
#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;
+ 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 */
@@ -330,4 +517,26 @@ static inline int scsi_device_qas(struct scsi_device *sdev)
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/include/scsi/scsi_devinfo.h b/include/scsi/scsi_devinfo.h
index 174101b2069..447d2d7466f 100644
--- a/include/scsi/scsi_devinfo.h
+++ b/include/scsi/scsi_devinfo.h
@@ -28,4 +28,8 @@
#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 */
#endif
diff --git a/include/scsi/scsi_dh.h b/include/scsi/scsi_dh.h
new file mode 100644
index 00000000000..620c723ee8e
--- /dev/null
+++ b/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/include/scsi/scsi_driver.h b/include/scsi/scsi_driver.h
index 02e26c1672b..36c4114ed9b 100644
--- a/include/scsi/scsi_driver.h
+++ b/include/scsi/scsi_driver.h
@@ -4,17 +4,19 @@
#include <linux/device.h>
struct module;
+struct request;
struct scsi_cmnd;
-
+struct scsi_device;
struct scsi_driver {
struct module *owner;
struct device_driver gendrv;
- int (*init_command)(struct scsi_cmnd *);
void (*rescan)(struct device *);
- int (*issue_flush)(struct device *, sector_t *);
- int (*prepare_flush)(struct request_queue *, struct request *);
+ 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)
@@ -27,4 +29,7 @@ extern int scsi_register_interface(struct class_interface *);
#define scsi_unregister_interface(intf) \
class_interface_unregister(intf)
+int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req);
+int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req);
+
#endif /* _SCSI_SCSI_DRIVER_H */
diff --git a/include/scsi/scsi_eh.h b/include/scsi/scsi_eh.h
index fabd879c2f2..06a8790893e 100644
--- a/include/scsi/scsi_eh.h
+++ b/include/scsi/scsi_eh.h
@@ -1,9 +1,10 @@
#ifndef _SCSI_SCSI_EH_H
#define _SCSI_SCSI_EH_H
-struct scsi_cmnd;
+#include <linux/scatterlist.h>
+
+#include <scsi/scsi_cmnd.h>
struct scsi_device;
-struct scsi_request;
struct Scsi_Host;
/*
@@ -35,13 +36,14 @@ static inline int scsi_sense_valid(struct scsi_sense_hdr *sshdr)
}
+extern void scsi_eh_finish_cmd(struct scsi_cmnd *scmd,
+ struct list_head *done_q);
+extern void scsi_eh_flush_done_q(struct list_head *done_q);
extern void scsi_report_bus_reset(struct Scsi_Host *, int);
extern void scsi_report_device_reset(struct Scsi_Host *, int, int);
extern int scsi_block_when_processing_errors(struct scsi_device *);
extern int scsi_normalize_sense(const u8 *sense_buffer, int sb_len,
struct scsi_sense_hdr *sshdr);
-extern int scsi_request_normalize_sense(struct scsi_request *sreq,
- struct scsi_sense_hdr *sshdr);
extern int scsi_command_normalize_sense(struct scsi_cmnd *cmd,
struct scsi_sense_hdr *sshdr);
@@ -55,14 +57,39 @@ extern const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len,
extern int scsi_get_sense_info_fld(const u8 * sense_buffer, int sb_len,
u64 * info_out);
-
+
+extern void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq);
+
/*
* Reset request from external source
*/
#define SCSI_TRY_RESET_DEVICE 1
#define SCSI_TRY_RESET_BUS 2
#define SCSI_TRY_RESET_HOST 3
+#define SCSI_TRY_RESET_TARGET 4
extern int scsi_reset_provider(struct scsi_device *, int);
+struct scsi_eh_save {
+ /* saved state */
+ int result;
+ enum dma_data_direction data_direction;
+ unsigned underflow;
+ unsigned char cmd_len;
+ unsigned char prot_op;
+ unsigned char *cmnd;
+ struct scsi_data_buffer sdb;
+ struct request *next_rq;
+ /* new command support */
+ unsigned char eh_cmnd[BLK_MAX_CDB];
+ struct scatterlist sense_sgl;
+};
+
+extern void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd,
+ struct scsi_eh_save *ses, unsigned char *cmnd,
+ int cmnd_size, unsigned sense_bytes);
+
+extern void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd,
+ struct scsi_eh_save *ses);
+
#endif /* _SCSI_SCSI_EH_H */
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index 827992949c4..94844fc77b9 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -6,16 +6,21 @@
#include <linux/types.h>
#include <linux/workqueue.h>
#include <linux/mutex.h>
+#include <linux/seq_file.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;
/*
@@ -23,24 +28,29 @@ struct scsi_transport_template;
* 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.
+ * 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 0xff
+#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
-enum scsi_eh_timer_return {
- EH_NOT_HANDLED,
- EH_HANDLED,
- EH_RESET_TIMER,
+enum {
+ SCSI_QDEPTH_DEFAULT, /* default requested change, e.g. from sysfs */
+ SCSI_QDEPTH_QFULL, /* scsi-ml requested due to queue full */
+ SCSI_QDEPTH_RAMP_UP, /* scsi-ml requested due to threshold event */
};
-
struct scsi_host_template {
struct module *module;
const char *name;
@@ -119,8 +129,28 @@ struct scsi_host_template {
*
* STATUS: REQUIRED
*/
- int (* queuecommand)(struct scsi_cmnd *,
- void (*done)(struct scsi_cmnd *));
+ int (* queuecommand)(struct Scsi_Host *, struct scsi_cmnd *);
+
+ /*
+ * The transfer functions are used to queue a scsi command to
+ * the LLD. When the driver is finished processing the command
+ * the done callback is invoked.
+ *
+ * This is called to inform the LLD to transfer
+ * scsi_bufflen(cmd) bytes. scsi_sg_count(cmd) speciefies the
+ * number of scatterlist entried in the command and
+ * scsi_sglist(cmd) returns the scatterlist.
+ *
+ * return values: see queuecommand
+ *
+ * If the LLD accepts the cmd, it should set the result to an
+ * appropriate value when completed before calling the done function.
+ *
+ * STATUS: REQUIRED FOR TARGET DRIVERS
+ */
+ /* TODO: rename */
+ int (* transfer_response)(struct scsi_cmnd *,
+ void (*done)(struct scsi_cmnd *));
/*
* This is an error handling strategy routine. You don't need to
@@ -140,27 +170,13 @@ struct scsi_host_template {
*
* Status: REQUIRED (at least one of them)
*/
- int (* eh_strategy_handler)(struct Scsi_Host *);
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 *);
/*
- * This is an optional routine to notify the host that the scsi
- * timer just fired. The returns tell the timer routine what to
- * do about this:
- *
- * 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 scsi_eh_timer_return (* eh_timed_out)(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
@@ -255,67 +271,120 @@ struct scsi_host_template {
void (* target_destroy)(struct scsi_target *);
/*
- * fill in this function to allow the queue depth of this host
- * to be changeable (on a per device basis). returns either
+ * 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);
+ int (* change_queue_depth)(struct scsi_device *, int, int);
/*
- * fill in this function to allow the changing of tag types
+ * Fill in this function to allow the changing of tag types
* (this also allows the enabling/disabling of tag command
* queueing). An error should only be returned if something
* went wrong in the driver while trying to set the tag type.
* If the driver doesn't support the requested tag type, then
* it should set the closest type it does support without
* returning an error. Returns the actual tag type set.
+ *
+ * Status: OPTIONAL
*/
int (* change_queue_type)(struct scsi_device *, int);
/*
- * This function determines the bios parameters for a given
+ * 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 */
+ * 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 (*proc_info)(struct Scsi_Host *, char *, char **, off_t, int, int);
+ int (*show_info)(struct seq_file *, struct Scsi_Host *);
+ int (*write_info)(struct Scsi_Host *, char *, int);
/*
- * suspend support
+ * 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 (*resume)(struct scsi_device *);
- int (*suspend)(struct scsi_device *);
+
+ int (*host_reset)(struct Scsi_Host *shost, int reset_type);
+#define SCSI_ADAPTER_RESET 1
+#define SCSI_FIRMWARE_RESET 2
+
/*
* Name of proc directory
*/
- char *proc_name;
+ const char *proc_name;
/*
* Used to store the procfs directory if a driver implements the
- * proc_info method.
+ * 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
+ * or an interrupt driven scheme. It is set to the maximum number
* of simultaneous commands a given host adapter will accept.
*/
int can_queue;
@@ -334,14 +403,15 @@ struct scsi_host_template {
* of scatter-gather.
*/
unsigned short sg_tablesize;
+ unsigned short sg_prot_tablesize;
/*
- * If the host adapter has limitations beside segment count
+ * Set this if the host adapter has limitations beside segment count.
*/
unsigned short max_sectors;
/*
- * dma scatter gather segment boundary limit. a segment crossing this
+ * DMA scatter gather segment boundary limit. A segment crossing this
* boundary will be split in two.
*/
unsigned long dma_boundary;
@@ -350,7 +420,7 @@ struct scsi_host_template {
* 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)
+ * individual devices (e.g. 256 for SCSI-1).
*/
#define SCSI_DEFAULT_MAX_SECTORS 1024
@@ -372,12 +442,17 @@ struct scsi_host_template {
unsigned char present;
/*
- * true if this host adapter uses unchecked DMA onto an ISA bus.
+ * 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.
+ * 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
@@ -387,7 +462,7 @@ struct scsi_host_template {
unsigned use_clustering:1;
/*
- * True for emulated SCSI host adapters (e.g. ATAPI)
+ * True for emulated SCSI host adapters (e.g. ATAPI).
*/
unsigned emulated:1;
@@ -397,12 +472,20 @@ struct scsi_host_template {
unsigned skip_settle_delay:1;
/*
- * ordered write support
+ * True if we are using ordered write support.
*/
unsigned ordered_tag: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
+ * Countdown for host blocking with no commands outstanding.
*/
unsigned int max_host_blocked;
@@ -418,7 +501,7 @@ struct scsi_host_template {
/*
* Pointer to the sysfs class properties for this host, NULL terminated.
*/
- struct class_device_attribute **shost_attrs;
+ struct device_attribute **shost_attrs;
/*
* Pointer to the SCSI device properties for this host, NULL terminated.
@@ -433,9 +516,43 @@ struct scsi_host_template {
* 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 #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()
@@ -481,17 +598,27 @@ struct Scsi_Host {
struct scsi_transport_template *transportt;
/*
+ * Area to keep a shared tag map (if needed, will be
+ * NULL if not).
+ */
+ struct blk_queue_tag *bqt;
+
+ /*
* The following two fields are protected with host_lock;
* however, eh routines can safely access during eh processing
* without acquiring the lock.
*/
unsigned int host_busy; /* commands actually active on low-level */
unsigned int host_failed; /* commands that failed. */
+ unsigned int host_eh_scheduled; /* EH scheduled without command */
- unsigned short host_no; /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */
- int resetting; /* if set, it means that last_reset is a valid value */
+ unsigned 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
@@ -514,26 +641,26 @@ struct Scsi_Host {
/*
* 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. I am leaving this as a number rather than a bit
- * because you never know what subsequent SCSI standards might do
- * (i.e. could there be a 20 byte or a 24-byte command a few years
- * down the road?).
+ * assumed.
*/
- unsigned char max_cmd_len;
+ 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;
short unsigned int max_sectors;
unsigned long dma_boundary;
/*
* Used to assign serial numbers to the cmds.
* Protected by the host lock.
*/
- unsigned long cmd_serial_number, cmd_pid;
+ unsigned long cmd_serial_number;
+ unsigned active_mode:2;
unsigned unchecked_isa_dma:1;
unsigned use_clustering:1;
unsigned use_blk_tcq:1;
@@ -547,22 +674,39 @@ struct Scsi_Host {
/*
* Host uses correct SCSI ordering not PC ordering. The bit is
* set for the minority of drivers whose authors actually read
- * the spec ;)
+ * the spec ;).
*/
unsigned reverse_ordering:1;
/*
- * ordered write support
+ * Ordered write support
*/
unsigned ordered_tag:1;
+ /* Task mgmt function in progress */
+ unsigned tmf_in_progress:1;
+
+ /* Asynchronous scan in progress */
+ unsigned async_scan:1;
+
+ /* Don't resume host in EH */
+ unsigned eh_noresume:1;
+
+ /* The controller does not support WRITE SAME */
+ unsigned no_write_same:1;
+
/*
* Optional work queue to be utilized by the transport
*/
- char work_q_name[KOBJ_NAME_LEN];
+ char work_q_name[20];
struct workqueue_struct *work_q;
/*
+ * Task management function work queue
+ */
+ struct workqueue_struct *tmf_work_q;
+
+ /*
* Host has rejected a command because it was busy.
*/
unsigned int host_blocked;
@@ -572,6 +716,16 @@ struct Scsi_Host {
*/
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;
@@ -583,8 +737,7 @@ struct Scsi_Host {
enum scsi_host_state shost_state;
/* ldm bits */
- struct device shost_gendev;
- struct class_device shost_classdev;
+ struct device shost_gendev, shost_dev;
/*
* List of hosts per template.
@@ -602,6 +755,12 @@ struct Scsi_Host {
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.
@@ -611,11 +770,15 @@ struct Scsi_Host {
};
#define class_to_shost(d) \
- container_of(d, struct Scsi_Host, shost_classdev)
+ 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 *);
@@ -633,14 +796,17 @@ 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->shost_state == SHOST_DEL_RECOVERY ||
+ shost->tmf_in_progress;
}
extern int scsi_queue_work(struct Scsi_Host *, struct work_struct *);
extern void scsi_flush_work(struct Scsi_Host *);
extern struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *, int);
-extern int __must_check scsi_add_host(struct Scsi_Host *, struct device *);
+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 *);
@@ -648,12 +814,14 @@ 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 *);
extern u64 scsi_calculate_bounce_limit(struct Scsi_Host *);
-static inline void scsi_assign_lock(struct Scsi_Host *shost, spinlock_t *lock)
+static inline int __must_check scsi_add_host(struct Scsi_Host *host,
+ struct device *dev)
{
- shost->host_lock = lock;
+ return scsi_add_host_with_dma(host, dev, dev);
}
static inline struct device *scsi_get_device(struct Scsi_Host *shost)
@@ -667,13 +835,17 @@ static inline struct device *scsi_get_device(struct Scsi_Host *shost)
**/
static inline int scsi_host_scan_allowed(struct Scsi_Host *shost)
{
- return shost->shost_state == SHOST_RUNNING;
+ 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
@@ -684,6 +856,97 @@ struct class_container;
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 *);
diff --git a/include/scsi/scsi_ioctl.h b/include/scsi/scsi_ioctl.h
index d4be4d92d58..b9006848b81 100644
--- a/include/scsi/scsi_ioctl.h
+++ b/include/scsi/scsi_ioctl.h
@@ -41,10 +41,8 @@ typedef struct scsi_fctargaddress {
} Scsi_FCTargAddress;
extern int scsi_ioctl(struct scsi_device *, int, void __user *);
-extern int scsi_ioctl_send_command(struct scsi_device *,
- struct scsi_ioctl_command __user *);
extern int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd,
- void __user *arg, struct file *filp);
+ void __user *arg, int ndelay);
#endif /* __KERNEL__ */
#endif /* _SCSI_IOCTL_H */
diff --git a/include/scsi/scsi_request.h b/include/scsi/scsi_request.h
deleted file mode 100644
index 98d69fdb851..00000000000
--- a/include/scsi/scsi_request.h
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifndef _SCSI_SCSI_REQUEST_H
-#define _SCSI_SCSI_REQUEST_H
-
-#include <scsi/scsi_cmnd.h>
-
-struct request;
-struct scsi_cmnd;
-struct scsi_device;
-struct Scsi_Host;
-
-
-/*
- * This is essentially a slimmed down version of Scsi_Cmnd. The point of
- * having this is that requests that are injected into the queue as result
- * of things like ioctls and character devices shouldn't be using a
- * Scsi_Cmnd until such a time that the command is actually at the head
- * of the queue and being sent to the driver.
- */
-struct scsi_request {
- int sr_magic;
- int sr_result; /* Status code from lower level driver */
- unsigned char sr_sense_buffer[SCSI_SENSE_BUFFERSIZE]; /* obtained by REQUEST SENSE
- * when CHECK CONDITION is
- * received on original command
- * (auto-sense) */
-
- struct Scsi_Host *sr_host;
- struct scsi_device *sr_device;
- struct scsi_cmnd *sr_command;
- struct request *sr_request; /* A copy of the command we are
- working on */
- unsigned sr_bufflen; /* Size of data buffer */
- void *sr_buffer; /* Data buffer */
- int sr_allowed;
- enum dma_data_direction sr_data_direction;
- unsigned char sr_cmd_len;
- unsigned char sr_cmnd[MAX_COMMAND_SIZE];
- void (*sr_done) (struct scsi_cmnd *); /* Mid-level done function */
- int sr_timeout_per_command;
- unsigned short sr_use_sg; /* Number of pieces of scatter-gather */
- unsigned short sr_sglist_len; /* size of malloc'd scatter-gather list */
- unsigned sr_underflow; /* Return error if less than
- this amount is transferred */
- void *upper_private_data; /* reserved for owner (usually upper
- level driver) of this request */
-};
-
-extern struct scsi_request *scsi_allocate_request(struct scsi_device *, gfp_t);
-extern void scsi_release_request(struct scsi_request *);
-extern void scsi_do_req(struct scsi_request *, const void *cmnd,
- void *buffer, unsigned bufflen,
- void (*done) (struct scsi_cmnd *),
- int timeout, int retries);
-#endif /* _SCSI_SCSI_REQUEST_H */
diff --git a/include/scsi/scsi_tcq.h b/include/scsi/scsi_tcq.h
index e47e36a4ef4..81dd12edc38 100644
--- a/include/scsi/scsi_tcq.h
+++ b/include/scsi/scsi_tcq.h
@@ -4,15 +4,17 @@
#include <linux/blkdev.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
-
+#include <scsi/scsi_host.h>
#define MSG_SIMPLE_TAG 0x20
#define MSG_HEAD_TAG 0x21
#define MSG_ORDERED_TAG 0x22
+#define MSG_ACA_TAG 0x24 /* unsupported */
#define SCSI_NO_TAG (-1) /* identify no tag in use */
+#ifdef CONFIG_BLOCK
/**
* scsi_get_tag_type - get the type of tag the device supports
@@ -66,7 +68,8 @@ static inline void scsi_activate_tcq(struct scsi_device *sdev, int depth)
return;
if (!blk_queue_tagged(sdev->request_queue))
- blk_queue_init_tags(sdev->request_queue, depth, NULL);
+ blk_queue_init_tags(sdev->request_queue, depth,
+ sdev->host->bqt);
scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
}
@@ -95,13 +98,9 @@ static inline void scsi_deactivate_tcq(struct scsi_device *sdev, int depth)
static inline int scsi_populate_tag_msg(struct scsi_cmnd *cmd, char *msg)
{
struct request *req = cmd->request;
- struct scsi_device *sdev = cmd->device;
if (blk_rq_tagged(req)) {
- if (sdev->ordered_tags && req->flags & REQ_HARDBARRIER)
- *msg++ = MSG_ORDERED_TAG;
- else
- *msg++ = MSG_SIMPLE_TAG;
+ *msg++ = MSG_SIMPLE_TAG;
*msg++ = req->tag;
return 2;
}
@@ -131,4 +130,46 @@ static inline struct scsi_cmnd *scsi_find_tag(struct scsi_device *sdev, int tag)
return sdev->current_cmnd;
}
+/**
+ * scsi_init_shared_tag_map - create a shared tag map
+ * @shost: the host to share the tag map among all devices
+ * @depth: the total depth of the map
+ */
+static inline int scsi_init_shared_tag_map(struct Scsi_Host *shost, int depth)
+{
+ /*
+ * If the shared tag map isn't already initialized, do it now.
+ * This saves callers from having to check ->bqt when setting up
+ * devices on the shared host (for libata)
+ */
+ if (!shost->bqt) {
+ shost->bqt = blk_init_tags(depth);
+ if (!shost->bqt)
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/**
+ * scsi_host_find_tag - find the tagged command by host
+ * @shost: pointer to scsi_host
+ * @tag: tag of the scsi_cmnd
+ *
+ * Notes:
+ * Only works with tags allocated by the generic blk layer.
+ **/
+static inline struct scsi_cmnd *scsi_host_find_tag(struct Scsi_Host *shost,
+ int tag)
+{
+ struct request *req;
+
+ if (tag != SCSI_NO_TAG) {
+ req = blk_map_queue_find_tag(shost->bqt, tag);
+ return req ? (struct scsi_cmnd *)req->special : NULL;
+ }
+ return NULL;
+}
+
+#endif /* CONFIG_BLOCK */
#endif /* _SCSI_SCSI_TCQ_H */
diff --git a/include/scsi/scsi_tgt.h b/include/scsi/scsi_tgt.h
new file mode 100644
index 00000000000..d0fefb96158
--- /dev/null
+++ b/include/scsi/scsi_tgt.h
@@ -0,0 +1,21 @@
+/*
+ * SCSI target definitions
+ */
+
+#include <linux/dma-mapping.h>
+
+struct Scsi_Host;
+struct scsi_cmnd;
+struct scsi_lun;
+
+extern struct Scsi_Host *scsi_tgt_cmd_to_host(struct scsi_cmnd *);
+extern int scsi_tgt_alloc_queue(struct Scsi_Host *);
+extern void scsi_tgt_free_queue(struct Scsi_Host *);
+extern int scsi_tgt_queue_command(struct scsi_cmnd *, u64, struct scsi_lun *, u64);
+extern int scsi_tgt_tsk_mgmt_request(struct Scsi_Host *, u64, int, u64,
+ struct scsi_lun *, void *);
+extern struct scsi_cmnd *scsi_host_get_command(struct Scsi_Host *,
+ enum dma_data_direction, gfp_t);
+extern void scsi_host_put_command(struct Scsi_Host *, struct scsi_cmnd *);
+extern int scsi_tgt_it_nexus_create(struct Scsi_Host *, u64, char *);
+extern int scsi_tgt_it_nexus_destroy(struct Scsi_Host *, u64);
diff --git a/include/scsi/scsi_tgt_if.h b/include/scsi/scsi_tgt_if.h
new file mode 100644
index 00000000000..f2ee7c238a4
--- /dev/null
+++ b/include/scsi/scsi_tgt_if.h
@@ -0,0 +1,108 @@
+/*
+ * SCSI target kernel/user interface
+ *
+ * Copyright (C) 2005 FUJITA Tomonori <tomof@acm.org>
+ * Copyright (C) 2005 Mike Christie <michaelc@cs.wisc.edu>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#ifndef __SCSI_TARGET_IF_H
+#define __SCSI_TARGET_IF_H
+
+/* user -> kernel */
+#define TGT_UEVENT_CMD_RSP 0x0001
+#define TGT_UEVENT_IT_NEXUS_RSP 0x0002
+#define TGT_UEVENT_TSK_MGMT_RSP 0x0003
+
+/* kernel -> user */
+#define TGT_KEVENT_CMD_REQ 0x1001
+#define TGT_KEVENT_CMD_DONE 0x1002
+#define TGT_KEVENT_IT_NEXUS_REQ 0x1003
+#define TGT_KEVENT_TSK_MGMT_REQ 0x1004
+
+struct tgt_event_hdr {
+ uint16_t version;
+ uint16_t status;
+ uint16_t type;
+ uint16_t len;
+} __attribute__ ((aligned (sizeof(uint64_t))));
+
+struct tgt_event {
+ struct tgt_event_hdr hdr;
+
+ union {
+ /* user-> kernel */
+ struct {
+ int host_no;
+ int result;
+ aligned_u64 itn_id;
+ aligned_u64 tag;
+ aligned_u64 uaddr;
+ aligned_u64 sense_uaddr;
+ uint32_t len;
+ uint32_t sense_len;
+ uint8_t rw;
+ } cmd_rsp;
+ struct {
+ int host_no;
+ int result;
+ aligned_u64 itn_id;
+ aligned_u64 mid;
+ } tsk_mgmt_rsp;
+ struct {
+ __s32 host_no;
+ __s32 result;
+ aligned_u64 itn_id;
+ __u32 function;
+ } it_nexus_rsp;
+
+ /* kernel -> user */
+ struct {
+ int host_no;
+ uint32_t data_len;
+ aligned_u64 itn_id;
+ uint8_t scb[16];
+ uint8_t lun[8];
+ int attribute;
+ aligned_u64 tag;
+ } cmd_req;
+ struct {
+ int host_no;
+ int result;
+ aligned_u64 itn_id;
+ aligned_u64 tag;
+ } cmd_done;
+ struct {
+ int host_no;
+ int function;
+ aligned_u64 itn_id;
+ aligned_u64 tag;
+ uint8_t lun[8];
+ aligned_u64 mid;
+ } tsk_mgmt_req;
+ struct {
+ __s32 host_no;
+ __u32 function;
+ aligned_u64 itn_id;
+ __u32 max_cmds;
+ __u8 initiator_id[16];
+ } it_nexus_req;
+ } p;
+} __attribute__ ((aligned (sizeof(uint64_t))));
+
+#define TGT_RING_SIZE (1UL << 16)
+
+#endif
diff --git a/include/scsi/scsi_transport.h b/include/scsi/scsi_transport.h
index e7b1054adf8..af244f4bba5 100644
--- a/include/scsi/scsi_transport.h
+++ b/include/scsi/scsi_transport.h
@@ -21,7 +21,10 @@
#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 */
@@ -48,10 +51,38 @@ struct scsi_transport_template {
* 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)->dev)
+ dev_to_shost((tc)->parent)
/* Private area maintenance. The driver requested allocations come
diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h
index cf3fec8be1e..8c79980dc8f 100644
--- a/include/scsi/scsi_transport_fc.h
+++ b/include/scsi/scsi_transport_fc.h
@@ -1,4 +1,4 @@
-/*
+/*
* FiberChannel transport specific attributes exported to sysfs.
*
* Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved.
@@ -19,7 +19,7 @@
*
* ========
*
- * Copyright (C) 2004-2005 James Smart, Emulex Corporation
+ * Copyright (C) 2004-2007 James Smart, Emulex Corporation
* Rewrite for host, target, device, and remote port attributes,
* statistics, and service functions...
*
@@ -27,13 +27,12 @@
#ifndef SCSI_TRANSPORT_FC_H
#define SCSI_TRANSPORT_FC_H
-#include <linux/config.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
*
@@ -62,8 +61,10 @@ enum fc_port_type {
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).
@@ -83,7 +84,26 @@ enum fc_port_state {
};
-/*
+/*
+ * 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,
@@ -96,7 +116,7 @@ enum fc_port_state {
#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,
@@ -106,8 +126,11 @@ enum fc_port_state {
incapable of reporting */
#define FC_PORTSPEED_1GBIT 1
#define FC_PORTSPEED_2GBIT 2
-#define FC_PORTSPEED_4GBIT 4
-#define FC_PORTSPEED_10GBIT 8
+#define FC_PORTSPEED_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_NOT_NEGOTIATED (1 << 15) /* Speed not established */
/*
@@ -122,16 +145,133 @@ enum fc_tgtid_binding_type {
};
/*
- * FC Remote Port Roles
+ * 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_RPORT_ROLE_UNKNOWN 0x00
-#define FC_RPORT_ROLE_FCP_TARGET 0x01
-#define FC_RPORT_ROLE_FCP_INITIATOR 0x02
-#define FC_RPORT_ROLE_IP_PORT 0x04
+#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
@@ -147,9 +287,10 @@ struct fc_rport_identifiers {
u32 roles;
};
+
/* Macro for use in defining Remote Port attributes */
#define FC_RPORT_ATTR(_name,_mode,_show,_store) \
-struct class_device_attribute class_device_attr_rport_##_name = \
+struct device_attribute dev_attr_rport_##_name = \
__ATTR(_name,_mode,_show,_store)
@@ -195,6 +336,7 @@ struct fc_rport { /* aka fc_starget_attrs */
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 */
@@ -202,23 +344,34 @@ struct fc_rport { /* aka fc_starget_attrs */
/* internal data */
unsigned int channel;
u32 number;
+ u8 flags;
struct list_head peers;
struct device dev;
- struct work_struct dev_loss_work;
+ 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(classdev) \
- dev_to_rport(classdev->dev)
+#define transport_class_to_rport(dev) \
+ dev_to_rport(dev->parent)
#define rport_to_shost(r) \
dev_to_shost(r->dev.parent)
/*
* FC SCSI Target Attributes
*
- * The SCSI Target is considered an extention of a remote port (as
+ * 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,
@@ -267,13 +420,49 @@ struct fc_host_statistics {
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,
};
@@ -306,10 +495,17 @@ struct fc_host_attrs {
u64 permanent_port_name;
u32 supported_classes;
u8 supported_fc4s[FC_FC4_LIST_SIZE];
- char symbolic_name[FC_SYMBOLIC_NAME_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;
@@ -318,6 +514,9 @@ struct fc_host_attrs {
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;
@@ -325,15 +524,24 @@ struct fc_host_attrs {
/* internal data */
struct list_head rports;
struct list_head rport_bindings;
+ struct list_head vports;
u32 next_rport_number;
u32 next_target_id;
- u8 flags;
- struct work_struct rport_del_work;
-};
+ u32 next_vport_number;
+ u16 npiv_vports_inuse;
-/* values for struct fc_host_attrs "flags" field: */
-#define FC_SHOST_RPORT_DEL_SCHEDULED 0x01
+ /* 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)
@@ -345,14 +553,28 @@ struct fc_host_attrs {
(((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_symbolic_name(x) \
- (((struct fc_host_attrs *)(x)->shost_data)->symbolic_name)
#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) \
@@ -365,20 +587,77 @@ struct fc_host_attrs {
(((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_flags(x) \
- (((struct fc_host_attrs *)(x)->shost_data)->flags)
-#define fc_host_rport_del_work(x) \
- (((struct fc_host_attrs *)(x)->shost_data)->rport_del_work)
+#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 */
@@ -396,20 +675,40 @@ struct fc_function_template {
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
+ * class
*/
/* remote port fixed attributes */
@@ -432,10 +731,16 @@ struct fc_function_template {
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_symbolic_name: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;
@@ -443,6 +748,10 @@ struct fc_function_template {
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;
};
@@ -461,10 +770,18 @@ fc_remote_port_chkready(struct fc_rport *rport)
switch (rport->port_state) {
case FC_PORTSTATE_ONLINE:
- result = 0;
+ 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:
- result = DID_BUS_BUSY << 16;
+ 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;
@@ -473,6 +790,45 @@ fc_remote_port_chkready(struct fc_rport *rport)
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 *);
@@ -483,13 +839,18 @@ struct fc_rport *fc_remote_port_add(struct Scsi_Host *shost,
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 *);
-
-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];
-}
+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/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h
index b41cf077e54..2555ee5343f 100644
--- a/include/scsi/scsi_transport_iscsi.h
+++ b/include/scsi/scsi_transport_iscsi.h
@@ -2,7 +2,7 @@
* iSCSI transport class definitions
*
* Copyright (C) IBM Corporation, 2004
- * Copyright (C) Mike Christie, 2004 - 2005
+ * Copyright (C) Mike Christie, 2004 - 2006
* Copyright (C) Dmitry Yusupov, 2004 - 2005
* Copyright (C) Alex Aizman, 2004 - 2005
*
@@ -24,12 +24,23 @@
#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 mempool_zone;
+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
@@ -42,10 +53,34 @@ struct iscsi_cls_conn;
* @bind_conn: associate this connection with existing iSCSI session
* and specified transport descriptor
* @destroy_conn: destroy inactive iSCSI connection
- * @set_param: set iSCSI Data-Path operational parameter
+ * @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
*/
@@ -53,38 +88,86 @@ struct iscsi_transport {
struct module *owner;
char *name;
unsigned int caps;
- struct scsi_host_template *host_template;
- /* LLD session/scsi_host data size */
- int hostdata_size;
- /* LLD iscsi_host data size */
- int ihostdata_size;
- /* LLD connection data size */
- int conndata_size;
- int max_lun;
- unsigned int max_conn;
- unsigned int max_cmd_len;
- struct iscsi_cls_session *(*create_session)
- (struct scsi_transport_template *t, uint32_t sn, uint32_t *sid);
+
+ 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,
- uint32_t transport_fd, int is_leading);
+ 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,
- uint32_t value);
+ 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,
- uint32_t *value);
+ enum iscsi_param param, char *buf);
int (*get_session_param) (struct iscsi_cls_session *session,
- enum iscsi_param param, uint32_t *value);
+ 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);
};
/*
@@ -96,52 +179,308 @@ extern int iscsi_unregister_transport(struct iscsi_transport *tt);
/*
* control plane upcalls
*/
-extern void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error);
+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;
- int active; /* must be accessed with the connlock */
+ uint32_t cid; /* connection id */
+ struct mutex ep_mutex;
+ struct iscsi_endpoint *ep;
+
struct device dev; /* sysfs transport/container device */
- struct mempool_zone *z_error;
- struct mempool_zone *z_pdu;
- struct list_head freequeue;
};
#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);
+ 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,
- uint32_t cid);
+ 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);
-/*
- * session functions used by software iscsi
- */
-extern struct Scsi_Host *
-iscsi_transport_create_session(struct scsi_transport_template *scsit,
- struct iscsi_transport *transport);
-extern int iscsi_transport_destroy_session(struct Scsi_Host *shost);
+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/include/scsi/scsi_transport_sas.h b/include/scsi/scsi_transport_sas.h
index b91400bfb02..0bd71e2702e 100644
--- a/include/scsi/scsi_transport_sas.h
+++ b/include/scsi/scsi_transport_sas.h
@@ -3,34 +3,38 @@
#include <linux/transport_class.h>
#include <linux/types.h>
+#include <linux/mutex.h>
+#include <scsi/sas.h>
struct scsi_transport_template;
struct sas_rphy;
+struct request;
-
-enum sas_device_type {
- SAS_PHY_UNUSED,
- SAS_END_DEVICE,
- SAS_EDGE_EXPANDER_DEVICE,
- SAS_FANOUT_EXPANDER_DEVICE,
-};
-
-enum sas_protocol {
- SAS_PROTOCOL_SATA = 0x01,
- SAS_PROTOCOL_SMP = 0x02,
- SAS_PROTOCOL_STP = 0x04,
- SAS_PROTOCOL_SSP = 0x08,
-};
+static inline int sas_protocol_ata(enum sas_protocol proto)
+{
+ return ((proto & SAS_PROTOCOL_SATA) ||
+ (proto & SAS_PROTOCOL_STP))? 1 : 0;
+}
enum sas_linkrate {
- SAS_LINK_RATE_UNKNOWN,
- SAS_PHY_DISABLED,
- SAS_LINK_RATE_FAILED,
- SAS_SATA_SPINUP_HOLD,
- SAS_SATA_PORT_SELECTOR,
- SAS_LINK_RATE_1_5_GBPS,
- SAS_LINK_RATE_3_0_GBPS,
- SAS_LINK_VIRTUAL,
+ /* 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 {
@@ -44,6 +48,7 @@ struct sas_identify {
struct sas_phy {
struct device dev;
int number;
+ int enabled;
/* phy identification */
struct sas_identify identify;
@@ -54,10 +59,6 @@ struct sas_phy {
enum sas_linkrate minimum_linkrate;
enum sas_linkrate maximum_linkrate_hw;
enum sas_linkrate maximum_linkrate;
- u8 port_identifier;
-
- /* internal state */
- unsigned int local_attached : 1;
/* link error statistics */
u32 invalid_dword_count;
@@ -65,39 +66,112 @@ struct sas_phy {
u32 loss_of_dword_sync_count;
u32 phy_reset_problem_count;
- /* the other end of the link */
- struct sas_rphy *rphy;
+ /* 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(cdev) \
- dev_to_phy((cdev)->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(cdev) \
- dev_to_rphy((cdev)->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);
@@ -106,14 +180,52 @@ extern int sas_phy_add(struct sas_phy *);
extern void sas_phy_delete(struct sas_phy *);
extern int scsi_is_sas_phy(const struct device *);
-extern struct sas_rphy *sas_rphy_alloc(struct sas_phy *);
+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/include/scsi/scsi_transport_spi.h b/include/scsi/scsi_transport_spi.h
index fb5a2ffae93..7497a383b1a 100644
--- a/include/scsi/scsi_transport_spi.h
+++ b/include/scsi/scsi_transport_spi.h
@@ -20,7 +20,6 @@
#ifndef SCSI_TRANSPORT_SPI_H
#define SCSI_TRANSPORT_SPI_H
-#include <linux/config.h>
#include <linux/transport_class.h>
#include <linux/mutex.h>
@@ -37,8 +36,10 @@ struct spi_transport_attrs {
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 */
@@ -54,7 +55,8 @@ struct spi_transport_attrs {
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 */
+ 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 */
};
@@ -77,14 +79,17 @@ struct spi_host_attrs {
#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)
@@ -148,5 +153,9 @@ void spi_schedule_dv_device(struct scsi_device *);
void spi_dv_device(struct scsi_device *);
void spi_display_xfer_agreement(struct scsi_target *);
int spi_print_msg(const unsigned char *);
+int spi_populate_width_msg(unsigned char *msg, int width);
+int spi_populate_sync_msg(unsigned char *msg, int period, int offset);
+int spi_populate_ppr_msg(unsigned char *msg, int period, int offset, int width,
+ int options);
#endif /* SCSI_TRANSPORT_SPI_H */
diff --git a/include/scsi/scsi_transport_srp.h b/include/scsi/scsi_transport_srp.h
new file mode 100644
index 00000000000..cdb05dd1d44
--- /dev/null
+++ b/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/include/scsi/sg.h b/include/scsi/sg.h
index 0a487fe26d4..a9f3c6fc3f5 100644
--- a/include/scsi/sg.h
+++ b/include/scsi/sg.h
@@ -11,26 +11,10 @@
Original driver (sg.h):
* Copyright (C) 1992 Lawrence Foard
Version 2 and 3 extensions to driver:
-* Copyright (C) 1998 - 2003 Douglas Gilbert
-
- Version: 3.5.29 (20030529)
- This version is for 2.5 series kernels.
-
- Changes since 3.5.28 (20030308)
- - fix bug introduced in version 3.1.24 (last segment of sgat list)
- Changes since 3.5.27 (20020812)
- - remove procfs entries: hosts, host_hdr + host_strs (now in sysfs)
- - add sysfs sg driver params: def_reserved_size, allow_dio, version
- - new boot option: "sg_allow_dio" and module parameter: "allow_dio"
- - multiple internal changes due to scsi subsystem rework
- Changes since 3.5.26 (20020708)
- - re-add direct IO using Kai Makisara's work
- - re-tab to 8, start using C99-isms
- - simplify memory management
- Changes since 3.5.25 (20020504)
- - driverfs additions
- - copy_to/from_user() fixes [William Stinson]
- - disable kiobufs support
+* Copyright (C) 1998 - 2006 Douglas Gilbert
+
+ Version: 3.5.34 (20060920)
+ This version is for 2.6 series kernels.
For a full changelog see http://www.torque.net/sg
@@ -40,7 +24,7 @@ Map of SG verions to the Linux kernels in which they appear:
2.1.40 2.2.20
3.0.x optional version 3 sg driver for 2.2 series
3.1.17++ 2.4.0++
- 3.5.23++ 2.5.0++
+ 3.5.30++ 2.6.0++
Major new features in SG 3.x driver (cf SG 2.x drivers)
- SG_IO ioctl() combines function if write() and read()
@@ -51,14 +35,15 @@ Major new features in SG 3.x driver (cf SG 2.x drivers)
data into kernel buffers and then use the CPU to copy the data into the
user space (vice versa for writes). That is called "indirect" IO due to
the double handling of data. There are two methods offered to remove the
- redundant copy: 1) direct IO which uses the kernel kiobuf mechanism and
- 2) using the mmap() system call to map the reserve buffer (this driver has
- one reserve buffer per fd) into the user space. Both have their advantages.
+ redundant copy: 1) direct IO and 2) using the mmap() system call to map
+ the reserve buffer (this driver has one reserve buffer per fd) into the
+ user space. Both have their advantages.
In terms of absolute speed mmap() is faster. If speed is not a concern,
indirect IO should be fine. Read the documentation for more information.
- ** N.B. To use direct IO 'echo 1 > /proc/scsi/sg/allow_dio' may be
- needed. That pseudo file's content is defaulted to 0. **
+ ** N.B. To use direct IO 'echo 1 > /proc/scsi/sg/allow_dio' or
+ 'echo 1 > /sys/module/sg/parameters/allow_dio' is needed.
+ That attribute is 0 by default. **
Historical note: this SCSI pass-through driver has been known as "sg" for
a decade. In broader kernel discussions "sg" is used to refer to scatter
@@ -72,22 +57,22 @@ Major new features in SG 3.x driver (cf SG 2.x drivers)
http://www.torque.net/sg/p/sg_v3_ho.html
This is a rendering from DocBook source [change the extension to "sgml"
or "xml"]. There are renderings in "ps", "pdf", "rtf" and "txt" (soon).
+ The SG_IO ioctl is now found in other parts kernel (e.g. the block layer).
+ For more information see http://www.torque.net/sg/sg_io.html
The older, version 2 documents discuss the original sg interface in detail:
http://www.torque.net/sg/p/scsi-generic.txt
http://www.torque.net/sg/p/scsi-generic_long.txt
- A version of this document (potentially out of date) may also be found in
- the kernel source tree, probably at:
- Documentation/scsi/scsi-generic.txt .
+ Also available: <kernel_source>/Documentation/scsi/scsi-generic.txt
Utility and test programs are available at the sg web site. They are
- bundled as sg_utils (for the lk 2.2 series) and sg3_utils (for the
- lk 2.4 series).
-
- There is a HOWTO on the Linux SCSI subsystem in the lk 2.4 series at:
- http://www.linuxdoc.org/HOWTO/SCSI-2.4-HOWTO
+ packaged as sg3_utils (for the lk 2.4 and 2.6 series) and sg_utils
+ (for the lk 2.2 series).
*/
+#ifdef __KERNEL__
+extern int sg_big_buff; /* for sysctl */
+#endif
/* New interface introduced in the 3.x SG drivers follows */
@@ -224,6 +209,7 @@ typedef struct sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */
#define SG_SCSI_RESET_DEVICE 1
#define SG_SCSI_RESET_BUS 2
#define SG_SCSI_RESET_HOST 3
+#define SG_SCSI_RESET_TARGET 4
/* synchronous SCSI command ioctl, (only in version 3 interface) */
#define SG_IO 0x2285 /* similar effect as write() followed by read() */
@@ -238,13 +224,12 @@ typedef struct sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */
#define SG_GET_ACCESS_COUNT 0x2289
-#define SG_SCATTER_SZ (8 * 4096) /* PAGE_SIZE not available to user */
+#define SG_SCATTER_SZ (8 * 4096)
/* Largest size (in bytes) a single scatter-gather list element can have.
- The value must be a power of 2 and <= (PAGE_SIZE * 32) [131072 bytes on
- i386]. The minimum value is PAGE_SIZE. If scatter-gather not supported
- by adapter then this value is the largest data block that can be
- read/written by a single scsi command. The user can find the value of
- PAGE_SIZE by calling getpagesize() defined in unistd.h . */
+ 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
diff --git a/include/scsi/sg_request.h b/include/scsi/sg_request.h
deleted file mode 100644
index 57ff525bdd3..00000000000
--- a/include/scsi/sg_request.h
+++ /dev/null
@@ -1,26 +0,0 @@
-typedef struct scsi_request Scsi_Request;
-
-static Scsi_Request *dummy_cmdp; /* only used for sizeof */
-
-typedef struct sg_scatter_hold { /* holding area for scsi scatter gather info */
- unsigned short k_use_sg; /* Count of kernel scatter-gather pieces */
- unsigned short sglist_len; /* size of malloc'd scatter-gather list ++ */
- unsigned bufflen; /* Size of (aggregate) data buffer */
- unsigned b_malloc_len; /* actual len malloc'ed in buffer */
- void *buffer; /* Data buffer or scatter list (k_use_sg>0) */
- char dio_in_use; /* 0->indirect IO (or mmap), 1->dio */
- unsigned char cmd_opcode; /* first byte of command */
-} Sg_scatter_hold;
-
-typedef struct sg_request { /* SG_MAX_QUEUE requests outstanding per file */
- Scsi_Request *my_cmdp; /* != 0 when request with lower levels */
- struct sg_request *nextrp; /* NULL -> tail request (slist) */
- struct sg_fd *parentfp; /* NULL -> not in use */
- Sg_scatter_hold data; /* hold buffer, perhaps scatter list */
- sg_io_hdr_t header; /* scsi command+info, see <scsi/sg.h> */
- unsigned char sense_b[sizeof (dummy_cmdp->sr_sense_buffer)];
- char res_used; /* 1 -> using reserve buffer, 0 -> not ... */
- char orphan; /* 1 -> drop on sight, 0 -> normal */
- char sg_io_owned; /* 1 -> packet belongs to SG_IO */
- volatile char done; /* 0->before bh, 1->before read, 2->read */
-} Sg_request;
diff --git a/include/scsi/srp.h b/include/scsi/srp.h
index 6c2681dc5b4..1ae84db4c9f 100644
--- a/include/scsi/srp.h
+++ b/include/scsi/srp.h
@@ -87,6 +87,11 @@ enum srp_login_rej_reason {
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;
@@ -95,14 +100,15 @@ struct srp_direct_buf {
/*
* 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.
+ * 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));
-};
+ struct srp_direct_buf desc_list[0];
+} __attribute__((packed));
enum {
SRP_MULTICHAN_SINGLE = 0,
@@ -122,6 +128,11 @@ struct srp_login_req {
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];
@@ -132,7 +143,7 @@ struct srp_login_rsp {
__be16 buf_fmt;
u8 rsp_flags;
u8 reserved2[25];
-};
+} __attribute__((packed));
struct srp_login_rej {
u8 opcode;
@@ -207,6 +218,11 @@ enum {
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;
@@ -221,6 +237,44 @@ struct srp_rsp {
__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 */