summaryrefslogtreecommitdiffstats
path: root/include/scsi
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 18:49:45 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 18:49:45 +0000
commit2c3c1048746a4622d8c89a29670120dc8fab93c4 (patch)
tree848558de17fb3008cdf4d861b01ac7781903ce39 /include/scsi
parentInitial commit. (diff)
downloadlinux-upstream.tar.xz
linux-upstream.zip
Adding upstream version 6.1.76.upstream/6.1.76upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'include/scsi')
-rw-r--r--include/scsi/fc/fc_encaps.h126
-rw-r--r--include/scsi/fc/fc_fc2.h111
-rw-r--r--include/scsi/fc/fc_fcoe.h96
-rw-r--r--include/scsi/fc/fc_fcp.h204
-rw-r--r--include/scsi/fc/fc_fip.h281
-rw-r--r--include/scsi/fc/fc_ms.h243
-rw-r--r--include/scsi/fc_frame.h279
-rw-r--r--include/scsi/fcoe_sysfs.h121
-rw-r--r--include/scsi/iscsi_if.h954
-rw-r--r--include/scsi/iscsi_proto.h657
-rw-r--r--include/scsi/iser.h78
-rw-r--r--include/scsi/libfc.h1018
-rw-r--r--include/scsi/libfcoe.h407
-rw-r--r--include/scsi/libiscsi.h513
-rw-r--r--include/scsi/libiscsi_tcp.h126
-rw-r--r--include/scsi/libsas.h759
-rw-r--r--include/scsi/sas.h723
-rw-r--r--include/scsi/sas_ata.h115
-rw-r--r--include/scsi/scsi.h219
-rw-r--r--include/scsi/scsi_bsg_iscsi.h96
-rw-r--r--include/scsi/scsi_cmnd.h392
-rw-r--r--include/scsi/scsi_common.h78
-rw-r--r--include/scsi/scsi_dbg.h87
-rw-r--r--include/scsi/scsi_device.h647
-rw-r--r--include/scsi/scsi_devinfo.h85
-rw-r--r--include/scsi/scsi_dh.h90
-rw-r--r--include/scsi/scsi_driver.h39
-rw-r--r--include/scsi/scsi_eh.h53
-rw-r--r--include/scsi/scsi_host.h889
-rw-r--r--include/scsi/scsi_ioctl.h55
-rw-r--r--include/scsi/scsi_proto.h345
-rw-r--r--include/scsi/scsi_status.h74
-rw-r--r--include/scsi/scsi_tcq.h43
-rw-r--r--include/scsi/scsi_transport.h88
-rw-r--r--include/scsi/scsi_transport_fc.h882
-rw-r--r--include/scsi/scsi_transport_iscsi.h509
-rw-r--r--include/scsi/scsi_transport_sas.h245
-rw-r--r--include/scsi/scsi_transport_spi.h149
-rw-r--r--include/scsi/scsi_transport_srp.h145
-rw-r--r--include/scsi/scsicam.h19
-rw-r--r--include/scsi/sg.h333
-rw-r--r--include/scsi/srp.h310
-rw-r--r--include/scsi/viosrp.h217
43 files changed, 12900 insertions, 0 deletions
diff --git a/include/scsi/fc/fc_encaps.h b/include/scsi/fc/fc_encaps.h
new file mode 100644
index 000000000..4261e609c
--- /dev/null
+++ b/include/scsi/fc/fc_encaps.h
@@ -0,0 +1,126 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright(c) 2007 Intel Corporation. All rights reserved.
+ *
+ * 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 000000000..0ffd314eb
--- /dev/null
+++ b/include/scsi/fc/fc_fc2.h
@@ -0,0 +1,111 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright(c) 2007 Intel Corporation. All rights reserved.
+ *
+ * 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 000000000..d8c921c85
--- /dev/null
+++ b/include/scsi/fc/fc_fcoe.h
@@ -0,0 +1,96 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright(c) 2007 Intel Corporation. All rights reserved.
+ *
+ * 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 000000000..4b968448f
--- /dev/null
+++ b/include/scsi/fc/fc_fcp.h
@@ -0,0 +1,204 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright(c) 2007 Intel Corporation. All rights reserved.
+ *
+ * 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 000000000..e0a3423ba
--- /dev/null
+++ b/include/scsi/fc/fc_fip.h
@@ -0,0 +1,281 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2008 Cisco Systems, Inc. All rights reserved.
+ */
+#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 13-091v5.pdf (December 2013 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, /* vlan request */
+ FIP_SC_VL_NOTE = 2, /* vlan notification */
+ FIP_SC_VL_VN2VN_NOTE = 3, /* VN2VN vlan notification */
+};
+
+/*
+ * 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_FCF = 0x0020, /* originated from a controlling FCF */
+ FIP_FL_FDF = 0x0010, /* originated from an FDF */
+ 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_NON_CRITICAL = 128, /* First non-critical descriptor */
+ FIP_DT_CLR_VLINKS = 128, /* Clear virtual links reason code */
+ FIP_DT_VENDOR_BASE = 241, /* 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_VLAN descriptor
+ */
+struct fip_vlan_desc {
+ struct fip_desc fd_desc;
+ __be16 fd_vlan; /* Note: highest 4 bytes are unused */
+} __attribute__((packed));
+
+/*
+ * 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 000000000..56a5d2b5a
--- /dev/null
+++ b/include/scsi/fc/fc_ms.h
@@ -0,0 +1,243 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright(c) 2011 Intel Corporation. All rights reserved.
+ *
+ * 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 specifications.
+ */
+#define FDMI_V1 1 /* FDMI version 1 specifications */
+#define FDMI_V2 2 /* FDMI version 2 specifications */
+
+/*
+ * 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,
+ FC_FDMI_HBA_ATTR_NODESYMBLNAME = 0x000C,
+ FC_FDMI_HBA_ATTR_VENDORSPECIFICINFO = 0x000D,
+ FC_FDMI_HBA_ATTR_NUMBEROFPORTS = 0x000E,
+ FC_FDMI_HBA_ATTR_FABRICNAME = 0x000F,
+ FC_FDMI_HBA_ATTR_BIOSVERSION = 0x0010,
+ FC_FDMI_HBA_ATTR_BIOSSTATE = 0x0011,
+ FC_FDMI_HBA_ATTR_VENDORIDENTIFIER = 0x00E0,
+};
+
+/*
+ * 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 64
+#define FC_FDMI_HBA_ATTR_MODELDESCR_LEN 64
+#define FC_FDMI_HBA_ATTR_HARDWAREVERSION_LEN 64
+#define FC_FDMI_HBA_ATTR_DRIVERVERSION_LEN 64
+#define FC_FDMI_HBA_ATTR_OPTIONROMVERSION_LEN 64
+#define FC_FDMI_HBA_ATTR_FIRMWAREVERSION_LEN 64
+#define FC_FDMI_HBA_ATTR_OSNAMEVERSION_LEN 128
+#define FC_FDMI_HBA_ATTR_MAXCTPAYLOAD_LEN 4
+#define FC_FDMI_HBA_ATTR_NODESYMBLNAME_LEN 64
+#define FC_FDMI_HBA_ATTR_VENDORSPECIFICINFO_LEN 4
+#define FC_FDMI_HBA_ATTR_NUMBEROFPORTS_LEN 4
+#define FC_FDMI_HBA_ATTR_FABRICNAME_LEN 8
+#define FC_FDMI_HBA_ATTR_BIOSVERSION_LEN 64
+#define FC_FDMI_HBA_ATTR_BIOSSTATE_LEN 4
+#define FC_FDMI_HBA_ATTR_VENDORIDENTIFIER_LEN 8
+
+/*
+ * 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,
+ FC_FDMI_PORT_ATTR_NODENAME = 0x0007,
+ FC_FDMI_PORT_ATTR_PORTNAME = 0x0008,
+ FC_FDMI_PORT_ATTR_SYMBOLICNAME = 0x0009,
+ FC_FDMI_PORT_ATTR_PORTTYPE = 0x000A,
+ FC_FDMI_PORT_ATTR_SUPPORTEDCLASSSRVC = 0x000B,
+ FC_FDMI_PORT_ATTR_FABRICNAME = 0x000C,
+ FC_FDMI_PORT_ATTR_CURRENTFC4TYPE = 0x000D,
+ FC_FDMI_PORT_ATTR_PORTSTATE = 0x101,
+ FC_FDMI_PORT_ATTR_DISCOVEREDPORTS = 0x102,
+ FC_FDMI_PORT_ATTR_PORTID = 0x103,
+};
+
+/*
+ * 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
+#define FC_FDMI_PORT_ATTR_NODENAME_LEN 8
+#define FC_FDMI_PORT_ATTR_PORTNAME_LEN 8
+#define FC_FDMI_PORT_ATTR_SYMBOLICNAME_LEN 256
+#define FC_FDMI_PORT_ATTR_PORTTYPE_LEN 4
+#define FC_FDMI_PORT_ATTR_SUPPORTEDCLASSSRVC_LEN 4
+#define FC_FDMI_PORT_ATTR_FABRICNAME_LEN 8
+#define FC_FDMI_PORT_ATTR_CURRENTFC4TYPE_LEN 32
+#define FC_FDMI_PORT_ATTR_PORTSTATE_LEN 4
+#define FC_FDMI_PORT_ATTR_DISCOVEREDPORTS_LEN 4
+#define FC_FDMI_PORT_ATTR_PORTID_LEN 4
+
+
+/*
+ * 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[];
+} __attribute__((__packed__));
+
+/*
+ * Common for HBA/Port Attributes
+ */
+struct fs_fdmi_attrs {
+ __be32 numattrs;
+ struct fc_fdmi_attr_entry attr[];
+} __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_frame.h b/include/scsi/fc_frame.h
new file mode 100644
index 000000000..d544dc505
--- /dev/null
+++ b/include/scsi/fc_frame.h
@@ -0,0 +1,279 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright(c) 2007 Intel Corporation. All rights reserved.
+ *
+ * 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);
+
+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);
+}
+
+
+#endif /* _FC_FRAME_H_ */
diff --git a/include/scsi/fcoe_sysfs.h b/include/scsi/fcoe_sysfs.h
new file mode 100644
index 000000000..4b1216de3
--- /dev/null
+++ b/include/scsi/fcoe_sysfs.h
@@ -0,0 +1,121 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2011-2012 Intel Corporation. All rights reserved.
+ *
+ * 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
new file mode 100644
index 000000000..5225a23f2
--- /dev/null
+++ b/include/scsi/iscsi_if.h
@@ -0,0 +1,954 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * iSCSI User/Kernel Shares (Defines, Constants, Protocol definitions, etc)
+ *
+ * Copyright (C) 2005 Dmitry Yusupov
+ * Copyright (C) 2005 Alex Aizman
+ * maintained by open-iscsi@googlegroups.com
+ */
+
+#ifndef ISCSI_IF_H
+#define ISCSI_IF_H
+
+#include <scsi/iscsi_proto.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+
+#define ISCSI_NL_GRP_ISCSID 1
+#define ISCSI_NL_GRP_UIP 2
+
+#define UEVENT_BASE 10
+#define KEVENT_BASE 100
+#define ISCSI_ERR_BASE 1000
+
+enum iscsi_uevent_e {
+ ISCSI_UEVENT_UNKNOWN = 0,
+
+ /* down events */
+ ISCSI_UEVENT_CREATE_SESSION = UEVENT_BASE + 1,
+ ISCSI_UEVENT_DESTROY_SESSION = UEVENT_BASE + 2,
+ ISCSI_UEVENT_CREATE_CONN = UEVENT_BASE + 3,
+ ISCSI_UEVENT_DESTROY_CONN = UEVENT_BASE + 4,
+ ISCSI_UEVENT_BIND_CONN = UEVENT_BASE + 5,
+ ISCSI_UEVENT_SET_PARAM = UEVENT_BASE + 6,
+ ISCSI_UEVENT_START_CONN = UEVENT_BASE + 7,
+ ISCSI_UEVENT_STOP_CONN = UEVENT_BASE + 8,
+ ISCSI_UEVENT_SEND_PDU = UEVENT_BASE + 9,
+ ISCSI_UEVENT_GET_STATS = UEVENT_BASE + 10,
+ ISCSI_UEVENT_GET_PARAM = UEVENT_BASE + 11,
+
+ ISCSI_UEVENT_TRANSPORT_EP_CONNECT = UEVENT_BASE + 12,
+ ISCSI_UEVENT_TRANSPORT_EP_POLL = UEVENT_BASE + 13,
+ ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT = UEVENT_BASE + 14,
+
+ ISCSI_UEVENT_TGT_DSCVR = UEVENT_BASE + 15,
+ ISCSI_UEVENT_SET_HOST_PARAM = UEVENT_BASE + 16,
+ ISCSI_UEVENT_UNBIND_SESSION = UEVENT_BASE + 17,
+ ISCSI_UEVENT_CREATE_BOUND_SESSION = UEVENT_BASE + 18,
+ ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST = UEVENT_BASE + 19,
+
+ ISCSI_UEVENT_PATH_UPDATE = UEVENT_BASE + 20,
+ ISCSI_UEVENT_SET_IFACE_PARAMS = UEVENT_BASE + 21,
+ ISCSI_UEVENT_PING = UEVENT_BASE + 22,
+ ISCSI_UEVENT_GET_CHAP = UEVENT_BASE + 23,
+ ISCSI_UEVENT_DELETE_CHAP = UEVENT_BASE + 24,
+ ISCSI_UEVENT_SET_FLASHNODE_PARAMS = UEVENT_BASE + 25,
+ ISCSI_UEVENT_NEW_FLASHNODE = UEVENT_BASE + 26,
+ ISCSI_UEVENT_DEL_FLASHNODE = UEVENT_BASE + 27,
+ ISCSI_UEVENT_LOGIN_FLASHNODE = UEVENT_BASE + 28,
+ ISCSI_UEVENT_LOGOUT_FLASHNODE = UEVENT_BASE + 29,
+ ISCSI_UEVENT_LOGOUT_FLASHNODE_SID = UEVENT_BASE + 30,
+ ISCSI_UEVENT_SET_CHAP = UEVENT_BASE + 31,
+ ISCSI_UEVENT_GET_HOST_STATS = UEVENT_BASE + 32,
+ ISCSI_UEVENT_DESTROY_SESSION_ASYNC = UEVENT_BASE + 33,
+
+ /* up events */
+ ISCSI_KEVENT_RECV_PDU = KEVENT_BASE + 1,
+ ISCSI_KEVENT_CONN_ERROR = KEVENT_BASE + 2,
+ ISCSI_KEVENT_IF_ERROR = KEVENT_BASE + 3,
+ ISCSI_KEVENT_DESTROY_SESSION = KEVENT_BASE + 4,
+ ISCSI_KEVENT_UNBIND_SESSION = KEVENT_BASE + 5,
+ ISCSI_KEVENT_CREATE_SESSION = KEVENT_BASE + 6,
+
+ ISCSI_KEVENT_PATH_REQ = KEVENT_BASE + 7,
+ ISCSI_KEVENT_IF_DOWN = KEVENT_BASE + 8,
+ ISCSI_KEVENT_CONN_LOGIN_STATE = KEVENT_BASE + 9,
+ ISCSI_KEVENT_HOST_EVENT = KEVENT_BASE + 10,
+ ISCSI_KEVENT_PING_COMP = KEVENT_BASE + 11,
+};
+
+enum iscsi_tgt_dscvr {
+ ISCSI_TGT_DSCVR_SEND_TARGETS = 1,
+ ISCSI_TGT_DSCVR_ISNS = 2,
+ ISCSI_TGT_DSCVR_SLP = 3,
+};
+
+enum iscsi_host_event_code {
+ ISCSI_EVENT_LINKUP = 1,
+ ISCSI_EVENT_LINKDOWN,
+ /* must always be last */
+ ISCSI_EVENT_MAX,
+};
+
+struct iscsi_uevent {
+ uint32_t type; /* k/u events type */
+ uint32_t iferror; /* carries interface or resource errors */
+ uint64_t transport_handle;
+
+ union {
+ /* messages u -> k */
+ struct msg_create_session {
+ uint32_t initial_cmdsn;
+ uint16_t cmds_max;
+ uint16_t queue_depth;
+ } c_session;
+ struct msg_create_bound_session {
+ uint64_t ep_handle;
+ uint32_t initial_cmdsn;
+ uint16_t cmds_max;
+ uint16_t queue_depth;
+ } c_bound_session;
+ struct msg_destroy_session {
+ uint32_t sid;
+ } d_session;
+ struct msg_create_conn {
+ uint32_t sid;
+ uint32_t cid;
+ } c_conn;
+ struct msg_bind_conn {
+ uint32_t sid;
+ uint32_t cid;
+ uint64_t transport_eph;
+ uint32_t is_leading;
+ } b_conn;
+ struct msg_destroy_conn {
+ uint32_t sid;
+ uint32_t cid;
+ } d_conn;
+ struct msg_send_pdu {
+ uint32_t sid;
+ uint32_t cid;
+ uint32_t hdr_size;
+ uint32_t data_size;
+ } send_pdu;
+ struct msg_set_param {
+ uint32_t sid;
+ uint32_t cid;
+ uint32_t param; /* enum iscsi_param */
+ uint32_t len;
+ } set_param;
+ struct msg_start_conn {
+ uint32_t sid;
+ uint32_t cid;
+ } start_conn;
+ struct msg_stop_conn {
+ uint32_t sid;
+ uint32_t cid;
+ uint64_t conn_handle;
+ uint32_t flag;
+ } stop_conn;
+ struct msg_get_stats {
+ uint32_t sid;
+ uint32_t cid;
+ } get_stats;
+ struct msg_transport_connect {
+ uint32_t non_blocking;
+ } ep_connect;
+ struct msg_transport_connect_through_host {
+ uint32_t host_no;
+ uint32_t non_blocking;
+ } ep_connect_through_host;
+ struct msg_transport_poll {
+ uint64_t ep_handle;
+ uint32_t timeout_ms;
+ } ep_poll;
+ struct msg_transport_disconnect {
+ uint64_t ep_handle;
+ } ep_disconnect;
+ struct msg_tgt_dscvr {
+ enum iscsi_tgt_dscvr type;
+ uint32_t host_no;
+ /*
+ * enable = 1 to establish a new connection
+ * with the server. enable = 0 to disconnect
+ * from the server. Used primarily to switch
+ * from one iSNS server to another.
+ */
+ uint32_t enable;
+ } tgt_dscvr;
+ struct msg_set_host_param {
+ uint32_t host_no;
+ uint32_t param; /* enum iscsi_host_param */
+ uint32_t len;
+ } set_host_param;
+ struct msg_set_path {
+ uint32_t host_no;
+ } set_path;
+ struct msg_set_iface_params {
+ uint32_t host_no;
+ uint32_t count;
+ } set_iface_params;
+ struct msg_iscsi_ping {
+ uint32_t host_no;
+ uint32_t iface_num;
+ uint32_t iface_type;
+ uint32_t payload_size;
+ uint32_t pid; /* unique ping id associated
+ with each ping request */
+ } iscsi_ping;
+ struct msg_get_chap {
+ uint32_t host_no;
+ uint32_t num_entries; /* number of CHAP entries
+ * on request, number of
+ * valid CHAP entries on
+ * response */
+ uint16_t chap_tbl_idx;
+ } get_chap;
+ struct msg_delete_chap {
+ uint32_t host_no;
+ uint16_t chap_tbl_idx;
+ } delete_chap;
+ struct msg_set_flashnode_param {
+ uint32_t host_no;
+ uint32_t flashnode_idx;
+ uint32_t count;
+ } set_flashnode;
+ struct msg_new_flashnode {
+ uint32_t host_no;
+ uint32_t len;
+ } new_flashnode;
+ struct msg_del_flashnode {
+ uint32_t host_no;
+ uint32_t flashnode_idx;
+ } del_flashnode;
+ struct msg_login_flashnode {
+ uint32_t host_no;
+ uint32_t flashnode_idx;
+ } login_flashnode;
+ struct msg_logout_flashnode {
+ uint32_t host_no;
+ uint32_t flashnode_idx;
+ } logout_flashnode;
+ struct msg_logout_flashnode_sid {
+ uint32_t host_no;
+ uint32_t sid;
+ } logout_flashnode_sid;
+ struct msg_get_host_stats {
+ uint32_t host_no;
+ } get_host_stats;
+ } u;
+ union {
+ /* messages k -> u */
+ int retcode;
+ struct msg_create_session_ret {
+ uint32_t sid;
+ uint32_t host_no;
+ } c_session_ret;
+ struct msg_create_conn_ret {
+ uint32_t sid;
+ uint32_t cid;
+ } c_conn_ret;
+ struct msg_unbind_session {
+ uint32_t sid;
+ uint32_t host_no;
+ } unbind_session;
+ struct msg_recv_req {
+ uint32_t sid;
+ uint32_t cid;
+ uint64_t recv_handle;
+ } recv_req;
+ struct msg_conn_login {
+ uint32_t sid;
+ uint32_t cid;
+ uint32_t state; /* enum iscsi_conn_state */
+ } conn_login;
+ struct msg_conn_error {
+ uint32_t sid;
+ uint32_t cid;
+ uint32_t error; /* enum iscsi_err */
+ } connerror;
+ struct msg_session_destroyed {
+ uint32_t host_no;
+ uint32_t sid;
+ } d_session;
+ struct msg_transport_connect_ret {
+ uint64_t handle;
+ } ep_connect_ret;
+ struct msg_req_path {
+ uint32_t host_no;
+ } req_path;
+ struct msg_notify_if_down {
+ uint32_t host_no;
+ } notify_if_down;
+ struct msg_host_event {
+ uint32_t host_no;
+ uint32_t data_size;
+ enum iscsi_host_event_code code;
+ } host_event;
+ struct msg_ping_comp {
+ uint32_t host_no;
+ uint32_t status; /* enum
+ * iscsi_ping_status_code */
+ uint32_t pid; /* unique ping id associated
+ with each ping request */
+ uint32_t data_size;
+ } ping_comp;
+ struct msg_new_flashnode_ret {
+ uint32_t flashnode_idx;
+ } new_flashnode_ret;
+ } r;
+} __attribute__ ((aligned (sizeof(uint64_t))));
+
+enum iscsi_param_type {
+ ISCSI_PARAM, /* iscsi_param (session, conn, target, LU) */
+ ISCSI_HOST_PARAM, /* iscsi_host_param */
+ ISCSI_NET_PARAM, /* iscsi_net_param */
+ ISCSI_FLASHNODE_PARAM, /* iscsi_flashnode_param */
+ ISCSI_CHAP_PARAM, /* iscsi_chap_param */
+ ISCSI_IFACE_PARAM, /* iscsi_iface_param */
+};
+
+/* structure for minimalist usecase */
+struct iscsi_param_info {
+ uint32_t len; /* Actual length of the param value */
+ uint16_t param; /* iscsi param */
+ uint8_t value[]; /* 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[]; /* length sized value follows */
+} __packed;
+
+/*
+ * To keep the struct iscsi_uevent size the same for userspace code
+ * compatibility, the main structure for ISCSI_UEVENT_PATH_UPDATE and
+ * ISCSI_KEVENT_PATH_REQ is defined separately and comes after the
+ * struct iscsi_uevent in the NETLINK_ISCSI message.
+ */
+struct iscsi_path {
+ uint64_t handle;
+ uint8_t mac_addr[6];
+ uint8_t mac_addr_old[6];
+ uint32_t ip_addr_len; /* 4 or 16 */
+ union {
+ struct in_addr v4_addr;
+ struct in6_addr v6_addr;
+ } src;
+ union {
+ struct in_addr v4_addr;
+ struct in6_addr v6_addr;
+ } dst;
+ uint16_t vlan_id;
+ uint16_t pmtu;
+} __attribute__ ((aligned (sizeof(uint64_t))));
+
+/* iscsi iface enabled/disabled setting */
+#define ISCSI_IFACE_DISABLE 0x01
+#define ISCSI_IFACE_ENABLE 0x02
+
+/* ipv4 bootproto */
+#define ISCSI_BOOTPROTO_STATIC 0x01
+#define ISCSI_BOOTPROTO_DHCP 0x02
+
+/* ipv6 addr autoconfig type */
+#define ISCSI_IPV6_AUTOCFG_DISABLE 0x01
+#define ISCSI_IPV6_AUTOCFG_ND_ENABLE 0x02
+#define ISCSI_IPV6_AUTOCFG_DHCPV6_ENABLE 0x03
+
+/* ipv6 link local addr type */
+#define ISCSI_IPV6_LINKLOCAL_AUTOCFG_ENABLE 0x01
+#define ISCSI_IPV6_LINKLOCAL_AUTOCFG_DISABLE 0x02
+
+/* ipv6 router addr type */
+#define ISCSI_IPV6_ROUTER_AUTOCFG_ENABLE 0x01
+#define ISCSI_IPV6_ROUTER_AUTOCFG_DISABLE 0x02
+
+#define ISCSI_IFACE_TYPE_IPV4 0x01
+#define ISCSI_IFACE_TYPE_IPV6 0x02
+
+#define ISCSI_MAX_VLAN_ID 4095
+#define ISCSI_MAX_VLAN_PRIORITY 7
+
+/* iscsi vlan enable/disabled setting */
+#define ISCSI_VLAN_DISABLE 0x01
+#define ISCSI_VLAN_ENABLE 0x02
+
+/* iscsi generic enable/disabled setting for various features */
+#define ISCSI_NET_PARAM_DISABLE 0x01
+#define ISCSI_NET_PARAM_ENABLE 0x02
+
+/* iSCSI network params */
+enum iscsi_net_param {
+ ISCSI_NET_PARAM_IPV4_ADDR = 1,
+ ISCSI_NET_PARAM_IPV4_SUBNET,
+ ISCSI_NET_PARAM_IPV4_GW,
+ ISCSI_NET_PARAM_IPV4_BOOTPROTO,
+ ISCSI_NET_PARAM_MAC,
+ ISCSI_NET_PARAM_IPV6_LINKLOCAL,
+ ISCSI_NET_PARAM_IPV6_ADDR,
+ ISCSI_NET_PARAM_IPV6_ROUTER,
+ ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG,
+ ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG,
+ ISCSI_NET_PARAM_IPV6_ROUTER_AUTOCFG,
+ ISCSI_NET_PARAM_IFACE_ENABLE,
+ ISCSI_NET_PARAM_VLAN_ID,
+ ISCSI_NET_PARAM_VLAN_PRIORITY,
+ ISCSI_NET_PARAM_VLAN_ENABLED,
+ ISCSI_NET_PARAM_VLAN_TAG,
+ ISCSI_NET_PARAM_IFACE_TYPE,
+ ISCSI_NET_PARAM_IFACE_NAME,
+ ISCSI_NET_PARAM_MTU,
+ ISCSI_NET_PARAM_PORT,
+ ISCSI_NET_PARAM_IPADDR_STATE,
+ ISCSI_NET_PARAM_IPV6_LINKLOCAL_STATE,
+ ISCSI_NET_PARAM_IPV6_ROUTER_STATE,
+ ISCSI_NET_PARAM_DELAYED_ACK_EN,
+ ISCSI_NET_PARAM_TCP_NAGLE_DISABLE,
+ ISCSI_NET_PARAM_TCP_WSF_DISABLE,
+ ISCSI_NET_PARAM_TCP_WSF,
+ ISCSI_NET_PARAM_TCP_TIMER_SCALE,
+ ISCSI_NET_PARAM_TCP_TIMESTAMP_EN,
+ ISCSI_NET_PARAM_CACHE_ID,
+ ISCSI_NET_PARAM_IPV4_DHCP_DNS_ADDR_EN,
+ ISCSI_NET_PARAM_IPV4_DHCP_SLP_DA_EN,
+ ISCSI_NET_PARAM_IPV4_TOS_EN,
+ ISCSI_NET_PARAM_IPV4_TOS,
+ ISCSI_NET_PARAM_IPV4_GRAT_ARP_EN,
+ ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID_EN,
+ ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID,
+ ISCSI_NET_PARAM_IPV4_DHCP_REQ_VENDOR_ID_EN,
+ ISCSI_NET_PARAM_IPV4_DHCP_USE_VENDOR_ID_EN,
+ ISCSI_NET_PARAM_IPV4_DHCP_VENDOR_ID,
+ ISCSI_NET_PARAM_IPV4_DHCP_LEARN_IQN_EN,
+ ISCSI_NET_PARAM_IPV4_FRAGMENT_DISABLE,
+ ISCSI_NET_PARAM_IPV4_IN_FORWARD_EN,
+ ISCSI_NET_PARAM_IPV4_TTL,
+ ISCSI_NET_PARAM_IPV6_GRAT_NEIGHBOR_ADV_EN,
+ ISCSI_NET_PARAM_IPV6_MLD_EN,
+ ISCSI_NET_PARAM_IPV6_FLOW_LABEL,
+ ISCSI_NET_PARAM_IPV6_TRAFFIC_CLASS,
+ ISCSI_NET_PARAM_IPV6_HOP_LIMIT,
+ ISCSI_NET_PARAM_IPV6_ND_REACHABLE_TMO,
+ ISCSI_NET_PARAM_IPV6_ND_REXMIT_TIME,
+ ISCSI_NET_PARAM_IPV6_ND_STALE_TMO,
+ ISCSI_NET_PARAM_IPV6_DUP_ADDR_DETECT_CNT,
+ ISCSI_NET_PARAM_IPV6_RTR_ADV_LINK_MTU,
+ ISCSI_NET_PARAM_REDIRECT_EN,
+};
+
+enum iscsi_ipaddress_state {
+ ISCSI_IPDDRESS_STATE_UNCONFIGURED,
+ ISCSI_IPDDRESS_STATE_ACQUIRING,
+ ISCSI_IPDDRESS_STATE_TENTATIVE,
+ ISCSI_IPDDRESS_STATE_VALID,
+ ISCSI_IPDDRESS_STATE_DISABLING,
+ ISCSI_IPDDRESS_STATE_INVALID,
+ ISCSI_IPDDRESS_STATE_DEPRECATED,
+};
+
+enum iscsi_router_state {
+ ISCSI_ROUTER_STATE_UNKNOWN,
+ ISCSI_ROUTER_STATE_ADVERTISED,
+ ISCSI_ROUTER_STATE_MANUAL,
+ ISCSI_ROUTER_STATE_STALE,
+};
+
+/* iSCSI specific settings params for iface */
+enum iscsi_iface_param {
+ ISCSI_IFACE_PARAM_DEF_TASKMGMT_TMO,
+ ISCSI_IFACE_PARAM_HDRDGST_EN,
+ ISCSI_IFACE_PARAM_DATADGST_EN,
+ ISCSI_IFACE_PARAM_IMM_DATA_EN,
+ ISCSI_IFACE_PARAM_INITIAL_R2T_EN,
+ ISCSI_IFACE_PARAM_DATASEQ_INORDER_EN,
+ ISCSI_IFACE_PARAM_PDU_INORDER_EN,
+ ISCSI_IFACE_PARAM_ERL,
+ ISCSI_IFACE_PARAM_MAX_RECV_DLENGTH,
+ ISCSI_IFACE_PARAM_FIRST_BURST,
+ ISCSI_IFACE_PARAM_MAX_R2T,
+ ISCSI_IFACE_PARAM_MAX_BURST,
+ ISCSI_IFACE_PARAM_CHAP_AUTH_EN,
+ ISCSI_IFACE_PARAM_BIDI_CHAP_EN,
+ ISCSI_IFACE_PARAM_DISCOVERY_AUTH_OPTIONAL,
+ ISCSI_IFACE_PARAM_DISCOVERY_LOGOUT_EN,
+ ISCSI_IFACE_PARAM_STRICT_LOGIN_COMP_EN,
+ ISCSI_IFACE_PARAM_INITIATOR_NAME,
+};
+
+enum iscsi_conn_state {
+ ISCSI_CONN_STATE_FREE,
+ ISCSI_CONN_STATE_XPT_WAIT,
+ ISCSI_CONN_STATE_IN_LOGIN,
+ ISCSI_CONN_STATE_LOGGED_IN,
+ ISCSI_CONN_STATE_IN_LOGOUT,
+ ISCSI_CONN_STATE_LOGOUT_REQUESTED,
+ ISCSI_CONN_STATE_CLEANUP_WAIT,
+};
+
+/*
+ * Common error codes
+ */
+enum iscsi_err {
+ ISCSI_OK = 0,
+
+ ISCSI_ERR_DATASN = ISCSI_ERR_BASE + 1,
+ ISCSI_ERR_DATA_OFFSET = ISCSI_ERR_BASE + 2,
+ ISCSI_ERR_MAX_CMDSN = ISCSI_ERR_BASE + 3,
+ ISCSI_ERR_EXP_CMDSN = ISCSI_ERR_BASE + 4,
+ ISCSI_ERR_BAD_OPCODE = ISCSI_ERR_BASE + 5,
+ ISCSI_ERR_DATALEN = ISCSI_ERR_BASE + 6,
+ ISCSI_ERR_AHSLEN = ISCSI_ERR_BASE + 7,
+ ISCSI_ERR_PROTO = ISCSI_ERR_BASE + 8,
+ ISCSI_ERR_LUN = ISCSI_ERR_BASE + 9,
+ ISCSI_ERR_BAD_ITT = ISCSI_ERR_BASE + 10,
+ ISCSI_ERR_CONN_FAILED = ISCSI_ERR_BASE + 11,
+ ISCSI_ERR_R2TSN = ISCSI_ERR_BASE + 12,
+ ISCSI_ERR_SESSION_FAILED = ISCSI_ERR_BASE + 13,
+ ISCSI_ERR_HDR_DGST = ISCSI_ERR_BASE + 14,
+ ISCSI_ERR_DATA_DGST = ISCSI_ERR_BASE + 15,
+ ISCSI_ERR_PARAM_NOT_FOUND = ISCSI_ERR_BASE + 16,
+ ISCSI_ERR_NO_SCSI_CMD = ISCSI_ERR_BASE + 17,
+ ISCSI_ERR_INVALID_HOST = ISCSI_ERR_BASE + 18,
+ ISCSI_ERR_XMIT_FAILED = ISCSI_ERR_BASE + 19,
+ ISCSI_ERR_TCP_CONN_CLOSE = ISCSI_ERR_BASE + 20,
+ ISCSI_ERR_SCSI_EH_SESSION_RST = ISCSI_ERR_BASE + 21,
+ ISCSI_ERR_NOP_TIMEDOUT = ISCSI_ERR_BASE + 22,
+};
+
+/*
+ * iSCSI Parameters (RFC3720)
+ */
+enum iscsi_param {
+ /* passed in using netlink set param */
+ ISCSI_PARAM_MAX_RECV_DLENGTH,
+ ISCSI_PARAM_MAX_XMIT_DLENGTH,
+ ISCSI_PARAM_HDRDGST_EN,
+ ISCSI_PARAM_DATADGST_EN,
+ ISCSI_PARAM_INITIAL_R2T_EN,
+ ISCSI_PARAM_MAX_R2T,
+ ISCSI_PARAM_IMM_DATA_EN,
+ ISCSI_PARAM_FIRST_BURST,
+ ISCSI_PARAM_MAX_BURST,
+ ISCSI_PARAM_PDU_INORDER_EN,
+ ISCSI_PARAM_DATASEQ_INORDER_EN,
+ ISCSI_PARAM_ERL,
+ ISCSI_PARAM_IFMARKER_EN,
+ ISCSI_PARAM_OFMARKER_EN,
+ ISCSI_PARAM_EXP_STATSN,
+ ISCSI_PARAM_TARGET_NAME,
+ ISCSI_PARAM_TPGT,
+ ISCSI_PARAM_PERSISTENT_ADDRESS,
+ ISCSI_PARAM_PERSISTENT_PORT,
+ ISCSI_PARAM_SESS_RECOVERY_TMO,
+
+ /* passed in through bind conn using transport_fd */
+ ISCSI_PARAM_CONN_PORT,
+ ISCSI_PARAM_CONN_ADDRESS,
+
+ ISCSI_PARAM_USERNAME,
+ ISCSI_PARAM_USERNAME_IN,
+ ISCSI_PARAM_PASSWORD,
+ ISCSI_PARAM_PASSWORD_IN,
+
+ ISCSI_PARAM_FAST_ABORT,
+ ISCSI_PARAM_ABORT_TMO,
+ ISCSI_PARAM_LU_RESET_TMO,
+ ISCSI_PARAM_HOST_RESET_TMO,
+
+ ISCSI_PARAM_PING_TMO,
+ ISCSI_PARAM_RECV_TMO,
+
+ ISCSI_PARAM_IFACE_NAME,
+ ISCSI_PARAM_ISID,
+ ISCSI_PARAM_INITIATOR_NAME,
+
+ ISCSI_PARAM_TGT_RESET_TMO,
+ ISCSI_PARAM_TARGET_ALIAS,
+
+ ISCSI_PARAM_CHAP_IN_IDX,
+ ISCSI_PARAM_CHAP_OUT_IDX,
+
+ ISCSI_PARAM_BOOT_ROOT,
+ ISCSI_PARAM_BOOT_NIC,
+ ISCSI_PARAM_BOOT_TARGET,
+
+ ISCSI_PARAM_AUTO_SND_TGT_DISABLE,
+ ISCSI_PARAM_DISCOVERY_SESS,
+ ISCSI_PARAM_PORTAL_TYPE,
+ ISCSI_PARAM_CHAP_AUTH_EN,
+ ISCSI_PARAM_DISCOVERY_LOGOUT_EN,
+ ISCSI_PARAM_BIDI_CHAP_EN,
+ ISCSI_PARAM_DISCOVERY_AUTH_OPTIONAL,
+
+ ISCSI_PARAM_DEF_TIME2WAIT,
+ ISCSI_PARAM_DEF_TIME2RETAIN,
+ ISCSI_PARAM_MAX_SEGMENT_SIZE,
+ ISCSI_PARAM_STATSN,
+ ISCSI_PARAM_KEEPALIVE_TMO,
+ ISCSI_PARAM_LOCAL_PORT,
+ ISCSI_PARAM_TSID,
+ ISCSI_PARAM_DEF_TASKMGMT_TMO,
+
+ ISCSI_PARAM_TCP_TIMESTAMP_STAT,
+ ISCSI_PARAM_TCP_WSF_DISABLE,
+ ISCSI_PARAM_TCP_NAGLE_DISABLE,
+ ISCSI_PARAM_TCP_TIMER_SCALE,
+ ISCSI_PARAM_TCP_TIMESTAMP_EN,
+ ISCSI_PARAM_TCP_XMIT_WSF,
+ ISCSI_PARAM_TCP_RECV_WSF,
+ ISCSI_PARAM_IP_FRAGMENT_DISABLE,
+ ISCSI_PARAM_IPV4_TOS,
+ ISCSI_PARAM_IPV6_TC,
+ ISCSI_PARAM_IPV6_FLOW_LABEL,
+ ISCSI_PARAM_IS_FW_ASSIGNED_IPV6,
+
+ ISCSI_PARAM_DISCOVERY_PARENT_IDX,
+ ISCSI_PARAM_DISCOVERY_PARENT_TYPE,
+ ISCSI_PARAM_LOCAL_IPADDR,
+ /* must always be last */
+ ISCSI_PARAM_MAX,
+};
+
+/* iSCSI HBA params */
+enum iscsi_host_param {
+ ISCSI_HOST_PARAM_HWADDRESS,
+ ISCSI_HOST_PARAM_INITIATOR_NAME,
+ ISCSI_HOST_PARAM_NETDEV_NAME,
+ ISCSI_HOST_PARAM_IPADDRESS,
+ ISCSI_HOST_PARAM_PORT_STATE,
+ ISCSI_HOST_PARAM_PORT_SPEED,
+ ISCSI_HOST_PARAM_MAX,
+};
+
+/* portal type */
+#define PORTAL_TYPE_IPV4 "ipv4"
+#define PORTAL_TYPE_IPV6 "ipv6"
+
+/* iSCSI Flash Target params */
+enum iscsi_flashnode_param {
+ ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6,
+ ISCSI_FLASHNODE_PORTAL_TYPE,
+ ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE,
+ ISCSI_FLASHNODE_DISCOVERY_SESS,
+ ISCSI_FLASHNODE_ENTRY_EN,
+ ISCSI_FLASHNODE_HDR_DGST_EN,
+ ISCSI_FLASHNODE_DATA_DGST_EN,
+ ISCSI_FLASHNODE_IMM_DATA_EN,
+ ISCSI_FLASHNODE_INITIAL_R2T_EN,
+ ISCSI_FLASHNODE_DATASEQ_INORDER,
+ ISCSI_FLASHNODE_PDU_INORDER,
+ ISCSI_FLASHNODE_CHAP_AUTH_EN,
+ ISCSI_FLASHNODE_SNACK_REQ_EN,
+ ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN,
+ ISCSI_FLASHNODE_BIDI_CHAP_EN,
+ /* make authentication for discovery sessions optional */
+ ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL,
+ ISCSI_FLASHNODE_ERL,
+ ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT,
+ ISCSI_FLASHNODE_TCP_NAGLE_DISABLE,
+ ISCSI_FLASHNODE_TCP_WSF_DISABLE,
+ ISCSI_FLASHNODE_TCP_TIMER_SCALE,
+ ISCSI_FLASHNODE_TCP_TIMESTAMP_EN,
+ ISCSI_FLASHNODE_IP_FRAG_DISABLE,
+ ISCSI_FLASHNODE_MAX_RECV_DLENGTH,
+ ISCSI_FLASHNODE_MAX_XMIT_DLENGTH,
+ ISCSI_FLASHNODE_FIRST_BURST,
+ ISCSI_FLASHNODE_DEF_TIME2WAIT,
+ ISCSI_FLASHNODE_DEF_TIME2RETAIN,
+ ISCSI_FLASHNODE_MAX_R2T,
+ ISCSI_FLASHNODE_KEEPALIVE_TMO,
+ ISCSI_FLASHNODE_ISID,
+ ISCSI_FLASHNODE_TSID,
+ ISCSI_FLASHNODE_PORT,
+ ISCSI_FLASHNODE_MAX_BURST,
+ ISCSI_FLASHNODE_DEF_TASKMGMT_TMO,
+ ISCSI_FLASHNODE_IPADDR,
+ ISCSI_FLASHNODE_ALIAS,
+ ISCSI_FLASHNODE_REDIRECT_IPADDR,
+ ISCSI_FLASHNODE_MAX_SEGMENT_SIZE,
+ ISCSI_FLASHNODE_LOCAL_PORT,
+ ISCSI_FLASHNODE_IPV4_TOS,
+ ISCSI_FLASHNODE_IPV6_TC,
+ ISCSI_FLASHNODE_IPV6_FLOW_LABEL,
+ ISCSI_FLASHNODE_NAME,
+ ISCSI_FLASHNODE_TPGT,
+ ISCSI_FLASHNODE_LINK_LOCAL_IPV6,
+ ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX,
+ ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE,
+ ISCSI_FLASHNODE_TCP_XMIT_WSF,
+ ISCSI_FLASHNODE_TCP_RECV_WSF,
+ ISCSI_FLASHNODE_CHAP_IN_IDX,
+ ISCSI_FLASHNODE_CHAP_OUT_IDX,
+ ISCSI_FLASHNODE_USERNAME,
+ ISCSI_FLASHNODE_USERNAME_IN,
+ ISCSI_FLASHNODE_PASSWORD,
+ ISCSI_FLASHNODE_PASSWORD_IN,
+ ISCSI_FLASHNODE_STATSN,
+ ISCSI_FLASHNODE_EXP_STATSN,
+ ISCSI_FLASHNODE_IS_BOOT_TGT,
+
+ ISCSI_FLASHNODE_MAX,
+};
+
+struct iscsi_flashnode_param_info {
+ uint32_t len; /* Actual length of the param */
+ uint16_t param; /* iscsi param value */
+ uint8_t value[]; /* 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_SPEED_25GBPS = 0x20,
+ ISCSI_PORT_SPEED_40GBPS = 0x40,
+};
+
+/* iSCSI port state */
+enum iscsi_port_state {
+ ISCSI_PORT_STATE_DOWN = 0x1,
+ ISCSI_PORT_STATE_UP = 0x2,
+};
+
+/* iSCSI PING status/error code */
+enum iscsi_ping_status_code {
+ ISCSI_PING_SUCCESS = 0,
+ ISCSI_PING_FW_DISABLED = 0x1,
+ ISCSI_PING_IPADDR_INVALID = 0x2,
+ ISCSI_PING_LINKLOCAL_IPV6_ADDR_INVALID = 0x3,
+ ISCSI_PING_TIMEOUT = 0x4,
+ ISCSI_PING_INVALID_DEST_ADDR = 0x5,
+ ISCSI_PING_OVERSIZE_PACKET = 0x6,
+ ISCSI_PING_ICMP_ERROR = 0x7,
+ ISCSI_PING_MAX_REQ_EXCEEDED = 0x8,
+ ISCSI_PING_NO_ARP_RECEIVED = 0x9,
+};
+
+#define iscsi_ptr(_handle) ((void*)(unsigned long)_handle)
+#define iscsi_handle(_ptr) ((uint64_t)(unsigned long)_ptr)
+
+/*
+ * These flags presents iSCSI Data-Path capabilities.
+ */
+#define CAP_RECOVERY_L0 0x1
+#define CAP_RECOVERY_L1 0x2
+#define CAP_RECOVERY_L2 0x4
+#define CAP_MULTI_R2T 0x8
+#define CAP_HDRDGST 0x10
+#define CAP_DATADGST 0x20
+#define CAP_MULTI_CONN 0x40
+#define CAP_TEXT_NEGO 0x80
+#define CAP_MARKERS 0x100
+#define CAP_FW_DB 0x200
+#define CAP_SENDTARGETS_OFFLOAD 0x400 /* offload discovery process */
+#define CAP_DATA_PATH_OFFLOAD 0x800 /* offload entire IO path */
+#define CAP_DIGEST_OFFLOAD 0x1000 /* offload hdr and data digests */
+#define CAP_PADDING_OFFLOAD 0x2000 /* offload padding insertion, removal,
+ and verification */
+#define CAP_LOGIN_OFFLOAD 0x4000 /* offload session login */
+
+/*
+ * These flags describes reason of stop_conn() call
+ */
+#define STOP_CONN_TERM 0x1
+#define STOP_CONN_SUSPEND 0x2
+#define STOP_CONN_RECOVER 0x3
+
+#define ISCSI_STATS_CUSTOM_MAX 32
+#define ISCSI_STATS_CUSTOM_DESC_MAX 64
+struct iscsi_stats_custom {
+ char desc[ISCSI_STATS_CUSTOM_DESC_MAX];
+ uint64_t value;
+};
+
+/*
+ * struct iscsi_stats - iSCSI Statistics (iSCSI MIB)
+ *
+ * Note: this structure contains counters collected on per-connection basis.
+ */
+struct iscsi_stats {
+ /* octets */
+ uint64_t txdata_octets;
+ uint64_t rxdata_octets;
+
+ /* xmit pdus */
+ uint32_t noptx_pdus;
+ uint32_t scsicmd_pdus;
+ uint32_t tmfcmd_pdus;
+ uint32_t login_pdus;
+ uint32_t text_pdus;
+ uint32_t dataout_pdus;
+ uint32_t logout_pdus;
+ uint32_t snack_pdus;
+
+ /* recv pdus */
+ uint32_t noprx_pdus;
+ uint32_t scsirsp_pdus;
+ uint32_t tmfrsp_pdus;
+ uint32_t textrsp_pdus;
+ uint32_t datain_pdus;
+ uint32_t logoutrsp_pdus;
+ uint32_t r2t_pdus;
+ uint32_t async_pdus;
+ uint32_t rjt_pdus;
+
+ /* errors */
+ uint32_t digest_err;
+ uint32_t timeout_err;
+
+ /*
+ * iSCSI Custom Statistics support, i.e. Transport could
+ * extend existing MIB statistics with its own specific statistics
+ * up to ISCSI_STATS_CUSTOM_MAX
+ */
+ uint32_t custom_length;
+ struct iscsi_stats_custom custom[]
+ __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[]
+ __aligned(sizeof(uint64_t));
+};
+
+#endif
diff --git a/include/scsi/iscsi_proto.h b/include/scsi/iscsi_proto.h
new file mode 100644
index 000000000..7b192d88f
--- /dev/null
+++ b/include/scsi/iscsi_proto.h
@@ -0,0 +1,657 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * RFC 3720 (iSCSI) protocol data types
+ *
+ * Copyright (C) 2005 Dmitry Yusupov
+ * Copyright (C) 2005 Alex Aizman
+ * maintained by open-iscsi@googlegroups.com
+ */
+
+#ifndef ISCSI_PROTO_H
+#define ISCSI_PROTO_H
+
+#include <linux/types.h>
+#include <scsi/scsi.h>
+
+#define ISCSI_DRAFT20_VERSION 0x00
+
+/* default iSCSI listen port for incoming connections */
+#define ISCSI_LISTEN_PORT 3260
+
+/* iSCSI header length */
+#define ISCSI_HDR_LEN 48
+
+/* iSCSI CRC32C length */
+#define ISCSI_CRC_LEN 4
+
+/* Padding word length */
+#define ISCSI_PAD_LEN 4
+
+/*
+ * Serial Number Arithmetic, 32 bits, RFC1982
+ */
+
+static inline int iscsi_sna_lt(u32 n1, u32 n2)
+{
+ return (s32)(n1 - n2) < 0;
+}
+
+static inline int iscsi_sna_lte(u32 n1, u32 n2)
+{
+ return (s32)(n1 - n2) <= 0;
+}
+
+static inline int iscsi_sna_gt(u32 n1, u32 n2)
+{
+ return (s32)(n1 - n2) > 0;
+}
+
+static inline int iscsi_sna_gte(u32 n1, u32 n2)
+{
+ return (s32)(n1 - n2) >= 0;
+}
+
+/*
+ * useful common(control and data paths) macro
+ */
+#define ntoh24(p) (((p)[0] << 16) | ((p)[1] << 8) | ((p)[2]))
+#define hton24(p, v) { \
+ p[0] = (((v) >> 16) & 0xFF); \
+ p[1] = (((v) >> 8) & 0xFF); \
+ p[2] = ((v) & 0xFF); \
+}
+#define zero_data(p) {p[0]=0;p[1]=0;p[2]=0;}
+
+/* initiator tags; opaque for target */
+typedef uint32_t __bitwise itt_t;
+/* below makes sense only for initiator that created this tag */
+#define build_itt(itt, age) ((__force itt_t)\
+ ((itt) | ((age) << ISCSI_AGE_SHIFT)))
+#define get_itt(itt) ((__force uint32_t)(itt_t)(itt) & ISCSI_ITT_MASK)
+#define RESERVED_ITT ((__force itt_t)0xffffffff)
+
+/*
+ * iSCSI Template Message Header
+ */
+struct iscsi_hdr {
+ uint8_t opcode;
+ uint8_t flags; /* Final bit */
+ uint8_t rsvd2[2];
+ uint8_t hlength; /* AHSs total length */
+ uint8_t dlength[3]; /* Data length */
+ struct scsi_lun lun;
+ itt_t itt; /* Initiator Task Tag, opaque for target */
+ __be32 ttt; /* Target Task Tag */
+ __be32 statsn;
+ __be32 exp_statsn;
+ __be32 max_statsn;
+ uint8_t other[12];
+};
+
+/************************* RFC 3720 Begin *****************************/
+
+#define ISCSI_RESERVED_TAG 0xffffffff
+
+/* Opcode encoding bits */
+#define ISCSI_OP_RETRY 0x80
+#define ISCSI_OP_IMMEDIATE 0x40
+#define ISCSI_OPCODE_MASK 0x3F
+
+/* Initiator Opcode values */
+#define ISCSI_OP_NOOP_OUT 0x00
+#define ISCSI_OP_SCSI_CMD 0x01
+#define ISCSI_OP_SCSI_TMFUNC 0x02
+#define ISCSI_OP_LOGIN 0x03
+#define ISCSI_OP_TEXT 0x04
+#define ISCSI_OP_SCSI_DATA_OUT 0x05
+#define ISCSI_OP_LOGOUT 0x06
+#define ISCSI_OP_SNACK 0x10
+
+#define ISCSI_OP_VENDOR1_CMD 0x1c
+#define ISCSI_OP_VENDOR2_CMD 0x1d
+#define ISCSI_OP_VENDOR3_CMD 0x1e
+#define ISCSI_OP_VENDOR4_CMD 0x1f
+
+/* Target Opcode values */
+#define ISCSI_OP_NOOP_IN 0x20
+#define ISCSI_OP_SCSI_CMD_RSP 0x21
+#define ISCSI_OP_SCSI_TMFUNC_RSP 0x22
+#define ISCSI_OP_LOGIN_RSP 0x23
+#define ISCSI_OP_TEXT_RSP 0x24
+#define ISCSI_OP_SCSI_DATA_IN 0x25
+#define ISCSI_OP_LOGOUT_RSP 0x26
+#define ISCSI_OP_R2T 0x31
+#define ISCSI_OP_ASYNC_EVENT 0x32
+#define ISCSI_OP_REJECT 0x3f
+
+struct iscsi_ahs_hdr {
+ __be16 ahslength;
+ uint8_t ahstype;
+ uint8_t ahspec[5];
+};
+
+#define ISCSI_AHSTYPE_CDB 1
+#define ISCSI_AHSTYPE_RLENGTH 2
+#define ISCSI_CDB_SIZE 16
+
+/* iSCSI PDU Header */
+struct iscsi_scsi_req {
+ uint8_t opcode;
+ uint8_t flags;
+ __be16 rsvd2;
+ uint8_t hlength;
+ uint8_t dlength[3];
+ struct scsi_lun lun;
+ itt_t itt; /* Initiator Task Tag */
+ __be32 data_length;
+ __be32 cmdsn;
+ __be32 exp_statsn;
+ uint8_t cdb[ISCSI_CDB_SIZE]; /* SCSI Command Block */
+ /* Additional Data (Command Dependent) */
+};
+
+/* Command PDU flags */
+#define ISCSI_FLAG_CMD_FINAL 0x80
+#define ISCSI_FLAG_CMD_READ 0x40
+#define ISCSI_FLAG_CMD_WRITE 0x20
+#define ISCSI_FLAG_CMD_ATTR_MASK 0x07 /* 3 bits */
+
+/* SCSI Command Attribute values */
+#define ISCSI_ATTR_UNTAGGED 0
+#define ISCSI_ATTR_SIMPLE 1
+#define ISCSI_ATTR_ORDERED 2
+#define ISCSI_ATTR_HEAD_OF_QUEUE 3
+#define ISCSI_ATTR_ACA 4
+
+struct iscsi_rlength_ahdr {
+ __be16 ahslength;
+ uint8_t ahstype;
+ uint8_t reserved;
+ __be32 read_length;
+};
+
+/* Extended CDB AHS */
+struct iscsi_ecdb_ahdr {
+ __be16 ahslength; /* CDB length - 15, including reserved byte */
+ uint8_t ahstype;
+ uint8_t reserved;
+ /* 4-byte aligned extended CDB spillover */
+ uint8_t ecdb[SCSI_MAX_VARLEN_CDB_SIZE - ISCSI_CDB_SIZE];
+};
+
+/* SCSI Response Header */
+struct iscsi_scsi_rsp {
+ uint8_t opcode;
+ uint8_t flags;
+ uint8_t response;
+ uint8_t cmd_status;
+ uint8_t hlength;
+ uint8_t dlength[3];
+ uint8_t rsvd[8];
+ itt_t itt; /* Initiator Task Tag */
+ __be32 rsvd1;
+ __be32 statsn;
+ __be32 exp_cmdsn;
+ __be32 max_cmdsn;
+ __be32 exp_datasn;
+ __be32 bi_residual_count;
+ __be32 residual_count;
+ /* Response or Sense Data (optional) */
+};
+
+/* Command Response PDU flags */
+#define ISCSI_FLAG_CMD_BIDI_OVERFLOW 0x10
+#define ISCSI_FLAG_CMD_BIDI_UNDERFLOW 0x08
+#define ISCSI_FLAG_CMD_OVERFLOW 0x04
+#define ISCSI_FLAG_CMD_UNDERFLOW 0x02
+
+/* iSCSI Status values. Valid if Rsp Selector bit is not set */
+#define ISCSI_STATUS_CMD_COMPLETED 0
+#define ISCSI_STATUS_TARGET_FAILURE 1
+#define ISCSI_STATUS_SUBSYS_FAILURE 2
+
+/* Asynchronous Event Header */
+struct iscsi_async {
+ uint8_t opcode;
+ uint8_t flags;
+ uint8_t rsvd2[2];
+ uint8_t rsvd3;
+ uint8_t dlength[3];
+ struct scsi_lun lun;
+ uint8_t rsvd4[8];
+ __be32 statsn;
+ __be32 exp_cmdsn;
+ __be32 max_cmdsn;
+ uint8_t async_event;
+ uint8_t async_vcode;
+ __be16 param1;
+ __be16 param2;
+ __be16 param3;
+ uint8_t rsvd5[4];
+};
+
+/* iSCSI Event Codes */
+#define ISCSI_ASYNC_MSG_SCSI_EVENT 0
+#define ISCSI_ASYNC_MSG_REQUEST_LOGOUT 1
+#define ISCSI_ASYNC_MSG_DROPPING_CONNECTION 2
+#define ISCSI_ASYNC_MSG_DROPPING_ALL_CONNECTIONS 3
+#define ISCSI_ASYNC_MSG_PARAM_NEGOTIATION 4
+#define ISCSI_ASYNC_MSG_VENDOR_SPECIFIC 255
+
+/* NOP-Out Message */
+struct iscsi_nopout {
+ uint8_t opcode;
+ uint8_t flags;
+ __be16 rsvd2;
+ uint8_t rsvd3;
+ uint8_t dlength[3];
+ struct scsi_lun lun;
+ itt_t itt; /* Initiator Task Tag */
+ __be32 ttt; /* Target Transfer Tag */
+ __be32 cmdsn;
+ __be32 exp_statsn;
+ uint8_t rsvd4[16];
+};
+
+/* NOP-In Message */
+struct iscsi_nopin {
+ uint8_t opcode;
+ uint8_t flags;
+ __be16 rsvd2;
+ uint8_t rsvd3;
+ uint8_t dlength[3];
+ struct scsi_lun lun;
+ itt_t itt; /* Initiator Task Tag */
+ __be32 ttt; /* Target Transfer Tag */
+ __be32 statsn;
+ __be32 exp_cmdsn;
+ __be32 max_cmdsn;
+ uint8_t rsvd4[12];
+};
+
+/* SCSI Task Management Message Header */
+struct iscsi_tm {
+ uint8_t opcode;
+ uint8_t flags;
+ uint8_t rsvd1[2];
+ uint8_t hlength;
+ uint8_t dlength[3];
+ struct scsi_lun lun;
+ itt_t itt; /* Initiator Task Tag */
+ itt_t rtt; /* Reference Task Tag */
+ __be32 cmdsn;
+ __be32 exp_statsn;
+ __be32 refcmdsn;
+ __be32 exp_datasn;
+ uint8_t rsvd2[8];
+};
+
+#define ISCSI_FLAG_TM_FUNC_MASK 0x7F
+
+/* Function values */
+#define ISCSI_TM_FUNC_ABORT_TASK 1
+#define ISCSI_TM_FUNC_ABORT_TASK_SET 2
+#define ISCSI_TM_FUNC_CLEAR_ACA 3
+#define ISCSI_TM_FUNC_CLEAR_TASK_SET 4
+#define ISCSI_TM_FUNC_LOGICAL_UNIT_RESET 5
+#define ISCSI_TM_FUNC_TARGET_WARM_RESET 6
+#define ISCSI_TM_FUNC_TARGET_COLD_RESET 7
+#define ISCSI_TM_FUNC_TASK_REASSIGN 8
+
+#define ISCSI_TM_FUNC_VALUE(hdr) ((hdr)->flags & ISCSI_FLAG_TM_FUNC_MASK)
+
+/* SCSI Task Management Response Header */
+struct iscsi_tm_rsp {
+ uint8_t opcode;
+ uint8_t flags;
+ uint8_t response; /* see Response values below */
+ uint8_t qualifier;
+ uint8_t hlength;
+ uint8_t dlength[3];
+ uint8_t rsvd2[8];
+ itt_t itt; /* Initiator Task Tag */
+ itt_t rtt; /* Reference Task Tag */
+ __be32 statsn;
+ __be32 exp_cmdsn;
+ __be32 max_cmdsn;
+ uint8_t rsvd3[12];
+};
+
+/* Response values */
+#define ISCSI_TMF_RSP_COMPLETE 0x00
+#define ISCSI_TMF_RSP_NO_TASK 0x01
+#define ISCSI_TMF_RSP_NO_LUN 0x02
+#define ISCSI_TMF_RSP_TASK_ALLEGIANT 0x03
+#define ISCSI_TMF_RSP_NO_FAILOVER 0x04
+#define ISCSI_TMF_RSP_NOT_SUPPORTED 0x05
+#define ISCSI_TMF_RSP_AUTH_FAILED 0x06
+#define ISCSI_TMF_RSP_REJECTED 0xff
+
+/* Ready To Transfer Header */
+struct iscsi_r2t_rsp {
+ uint8_t opcode;
+ uint8_t flags;
+ uint8_t rsvd2[2];
+ uint8_t hlength;
+ uint8_t dlength[3];
+ struct scsi_lun lun;
+ itt_t itt; /* Initiator Task Tag */
+ __be32 ttt; /* Target Transfer Tag */
+ __be32 statsn;
+ __be32 exp_cmdsn;
+ __be32 max_cmdsn;
+ __be32 r2tsn;
+ __be32 data_offset;
+ __be32 data_length;
+};
+
+/* SCSI Data Hdr */
+struct iscsi_data {
+ uint8_t opcode;
+ uint8_t flags;
+ uint8_t rsvd2[2];
+ uint8_t rsvd3;
+ uint8_t dlength[3];
+ struct scsi_lun lun;
+ itt_t itt;
+ __be32 ttt;
+ __be32 rsvd4;
+ __be32 exp_statsn;
+ __be32 rsvd5;
+ __be32 datasn;
+ __be32 offset;
+ __be32 rsvd6;
+ /* Payload */
+};
+
+/* SCSI Data Response Hdr */
+struct iscsi_data_rsp {
+ uint8_t opcode;
+ uint8_t flags;
+ uint8_t rsvd2;
+ uint8_t cmd_status;
+ uint8_t hlength;
+ uint8_t dlength[3];
+ struct scsi_lun lun;
+ itt_t itt;
+ __be32 ttt;
+ __be32 statsn;
+ __be32 exp_cmdsn;
+ __be32 max_cmdsn;
+ __be32 datasn;
+ __be32 offset;
+ __be32 residual_count;
+};
+
+/* Data Response PDU flags */
+#define ISCSI_FLAG_DATA_ACK 0x40
+#define ISCSI_FLAG_DATA_OVERFLOW 0x04
+#define ISCSI_FLAG_DATA_UNDERFLOW 0x02
+#define ISCSI_FLAG_DATA_STATUS 0x01
+
+/* Text Header */
+struct iscsi_text {
+ uint8_t opcode;
+ uint8_t flags;
+ uint8_t rsvd2[2];
+ uint8_t hlength;
+ uint8_t dlength[3];
+ uint8_t rsvd4[8];
+ itt_t itt;
+ __be32 ttt;
+ __be32 cmdsn;
+ __be32 exp_statsn;
+ uint8_t rsvd5[16];
+ /* Text - key=value pairs */
+};
+
+#define ISCSI_FLAG_TEXT_CONTINUE 0x40
+
+/* Text Response Header */
+struct iscsi_text_rsp {
+ uint8_t opcode;
+ uint8_t flags;
+ uint8_t rsvd2[2];
+ uint8_t hlength;
+ uint8_t dlength[3];
+ uint8_t rsvd4[8];
+ itt_t itt;
+ __be32 ttt;
+ __be32 statsn;
+ __be32 exp_cmdsn;
+ __be32 max_cmdsn;
+ uint8_t rsvd5[12];
+ /* Text Response - key:value pairs */
+};
+
+/* Login Header */
+struct iscsi_login_req {
+ uint8_t opcode;
+ uint8_t flags;
+ uint8_t max_version; /* Max. version supported */
+ uint8_t min_version; /* Min. version supported */
+ uint8_t hlength;
+ uint8_t dlength[3];
+ uint8_t isid[6]; /* Initiator Session ID */
+ __be16 tsih; /* Target Session Handle */
+ itt_t itt; /* Initiator Task Tag */
+ __be16 cid;
+ __be16 rsvd3;
+ __be32 cmdsn;
+ __be32 exp_statsn;
+ uint8_t rsvd5[16];
+};
+
+/* Login PDU flags */
+#define ISCSI_FLAG_LOGIN_TRANSIT 0x80
+#define ISCSI_FLAG_LOGIN_CONTINUE 0x40
+#define ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK 0x0C /* 2 bits */
+#define ISCSI_FLAG_LOGIN_CURRENT_STAGE1 0x04
+#define ISCSI_FLAG_LOGIN_CURRENT_STAGE2 0x08
+#define ISCSI_FLAG_LOGIN_CURRENT_STAGE3 0x0C
+#define ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK 0x03 /* 2 bits */
+#define ISCSI_FLAG_LOGIN_NEXT_STAGE1 0x01
+#define ISCSI_FLAG_LOGIN_NEXT_STAGE2 0x02
+#define ISCSI_FLAG_LOGIN_NEXT_STAGE3 0x03
+
+#define ISCSI_LOGIN_CURRENT_STAGE(flags) \
+ ((flags & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2)
+#define ISCSI_LOGIN_NEXT_STAGE(flags) \
+ (flags & ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK)
+
+/* Login Response Header */
+struct iscsi_login_rsp {
+ uint8_t opcode;
+ uint8_t flags;
+ uint8_t max_version; /* Max. version supported */
+ uint8_t active_version; /* Active version */
+ uint8_t hlength;
+ uint8_t dlength[3];
+ uint8_t isid[6]; /* Initiator Session ID */
+ __be16 tsih; /* Target Session Handle */
+ itt_t itt; /* Initiator Task Tag */
+ __be32 rsvd3;
+ __be32 statsn;
+ __be32 exp_cmdsn;
+ __be32 max_cmdsn;
+ uint8_t status_class; /* see Login RSP ststus classes below */
+ uint8_t status_detail; /* see Login RSP Status details below */
+ uint8_t rsvd4[10];
+};
+
+/* Login stage (phase) codes for CSG, NSG */
+#define ISCSI_INITIAL_LOGIN_STAGE -1
+#define ISCSI_SECURITY_NEGOTIATION_STAGE 0
+#define ISCSI_OP_PARMS_NEGOTIATION_STAGE 1
+#define ISCSI_FULL_FEATURE_PHASE 3
+
+/* Login Status response classes */
+#define ISCSI_STATUS_CLS_SUCCESS 0x00
+#define ISCSI_STATUS_CLS_REDIRECT 0x01
+#define ISCSI_STATUS_CLS_INITIATOR_ERR 0x02
+#define ISCSI_STATUS_CLS_TARGET_ERR 0x03
+
+/* Login Status response detail codes */
+/* Class-0 (Success) */
+#define ISCSI_LOGIN_STATUS_ACCEPT 0x00
+
+/* Class-1 (Redirection) */
+#define ISCSI_LOGIN_STATUS_TGT_MOVED_TEMP 0x01
+#define ISCSI_LOGIN_STATUS_TGT_MOVED_PERM 0x02
+
+/* Class-2 (Initiator Error) */
+#define ISCSI_LOGIN_STATUS_INIT_ERR 0x00
+#define ISCSI_LOGIN_STATUS_AUTH_FAILED 0x01
+#define ISCSI_LOGIN_STATUS_TGT_FORBIDDEN 0x02
+#define ISCSI_LOGIN_STATUS_TGT_NOT_FOUND 0x03
+#define ISCSI_LOGIN_STATUS_TGT_REMOVED 0x04
+#define ISCSI_LOGIN_STATUS_NO_VERSION 0x05
+#define ISCSI_LOGIN_STATUS_ISID_ERROR 0x06
+#define ISCSI_LOGIN_STATUS_MISSING_FIELDS 0x07
+#define ISCSI_LOGIN_STATUS_CONN_ADD_FAILED 0x08
+#define ISCSI_LOGIN_STATUS_NO_SESSION_TYPE 0x09
+#define ISCSI_LOGIN_STATUS_NO_SESSION 0x0a
+#define ISCSI_LOGIN_STATUS_INVALID_REQUEST 0x0b
+
+/* Class-3 (Target Error) */
+#define ISCSI_LOGIN_STATUS_TARGET_ERROR 0x00
+#define ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE 0x01
+#define ISCSI_LOGIN_STATUS_NO_RESOURCES 0x02
+
+/* Logout Header */
+struct iscsi_logout {
+ uint8_t opcode;
+ uint8_t flags;
+ uint8_t rsvd1[2];
+ uint8_t hlength;
+ uint8_t dlength[3];
+ uint8_t rsvd2[8];
+ itt_t itt; /* Initiator Task Tag */
+ __be16 cid;
+ uint8_t rsvd3[2];
+ __be32 cmdsn;
+ __be32 exp_statsn;
+ uint8_t rsvd4[16];
+};
+
+/* Logout PDU flags */
+#define ISCSI_FLAG_LOGOUT_REASON_MASK 0x7F
+
+/* logout reason_code values */
+
+#define ISCSI_LOGOUT_REASON_CLOSE_SESSION 0
+#define ISCSI_LOGOUT_REASON_CLOSE_CONNECTION 1
+#define ISCSI_LOGOUT_REASON_RECOVERY 2
+#define ISCSI_LOGOUT_REASON_AEN_REQUEST 3
+
+/* Logout Response Header */
+struct iscsi_logout_rsp {
+ uint8_t opcode;
+ uint8_t flags;
+ uint8_t response; /* see Logout response values below */
+ uint8_t rsvd2;
+ uint8_t hlength;
+ uint8_t dlength[3];
+ uint8_t rsvd3[8];
+ itt_t itt; /* Initiator Task Tag */
+ __be32 rsvd4;
+ __be32 statsn;
+ __be32 exp_cmdsn;
+ __be32 max_cmdsn;
+ __be32 rsvd5;
+ __be16 t2wait;
+ __be16 t2retain;
+ __be32 rsvd6;
+};
+
+/* logout response status values */
+
+#define ISCSI_LOGOUT_SUCCESS 0
+#define ISCSI_LOGOUT_CID_NOT_FOUND 1
+#define ISCSI_LOGOUT_RECOVERY_UNSUPPORTED 2
+#define ISCSI_LOGOUT_CLEANUP_FAILED 3
+
+/* SNACK Header */
+struct iscsi_snack {
+ uint8_t opcode;
+ uint8_t flags;
+ uint8_t rsvd2[2];
+ uint8_t hlength;
+ uint8_t dlength[3];
+ uint8_t lun[8];
+ itt_t itt;
+ __be32 ttt;
+ uint8_t rsvd3[4];
+ __be32 exp_statsn;
+ uint8_t rsvd4[8];
+ __be32 begrun;
+ __be32 runlength;
+};
+
+/* SNACK PDU flags */
+#define ISCSI_FLAG_SNACK_TYPE_DATA 0
+#define ISCSI_FLAG_SNACK_TYPE_R2T 0
+#define ISCSI_FLAG_SNACK_TYPE_STATUS 1
+#define ISCSI_FLAG_SNACK_TYPE_DATA_ACK 2
+#define ISCSI_FLAG_SNACK_TYPE_RDATA 3
+#define ISCSI_FLAG_SNACK_TYPE_MASK 0x0F /* 4 bits */
+
+/* Reject Message Header */
+struct iscsi_reject {
+ uint8_t opcode;
+ uint8_t flags;
+ uint8_t reason;
+ uint8_t rsvd2;
+ uint8_t hlength;
+ uint8_t dlength[3];
+ uint8_t rsvd3[8];
+ __be32 ffffffff;
+ uint8_t rsvd4[4];
+ __be32 statsn;
+ __be32 exp_cmdsn;
+ __be32 max_cmdsn;
+ __be32 datasn;
+ uint8_t rsvd5[8];
+ /* Text - Rejected hdr */
+};
+
+/* Reason for Reject */
+#define ISCSI_REASON_CMD_BEFORE_LOGIN 1
+#define ISCSI_REASON_DATA_DIGEST_ERROR 2
+#define ISCSI_REASON_DATA_SNACK_REJECT 3
+#define ISCSI_REASON_PROTOCOL_ERROR 4
+#define ISCSI_REASON_CMD_NOT_SUPPORTED 5
+#define ISCSI_REASON_IMM_CMD_REJECT 6
+#define ISCSI_REASON_TASK_IN_PROGRESS 7
+#define ISCSI_REASON_INVALID_SNACK 8
+#define ISCSI_REASON_BOOKMARK_INVALID 9
+#define ISCSI_REASON_BOOKMARK_NO_RESOURCES 10
+#define ISCSI_REASON_NEGOTIATION_RESET 11
+
+/* Max. number of Key=Value pairs in a text message */
+#define MAX_KEY_VALUE_PAIRS 8192
+
+/* maximum length for text keys/values */
+#define KEY_MAXLEN 64
+#define VALUE_MAXLEN 255
+#define TARGET_NAME_MAXLEN VALUE_MAXLEN
+
+#define ISCSI_DEF_MAX_RECV_SEG_LEN 8192
+#define ISCSI_MIN_MAX_RECV_SEG_LEN 512
+#define ISCSI_MAX_MAX_RECV_SEG_LEN 16777215
+
+#define ISCSI_DEF_FIRST_BURST_LEN 65536
+#define ISCSI_MIN_FIRST_BURST_LEN 512
+#define ISCSI_MAX_FIRST_BURST_LEN 16777215
+
+#define ISCSI_DEF_MAX_BURST_LEN 262144
+#define ISCSI_MIN_MAX_BURST_LEN 512
+#define ISCSI_MAX_MAX_BURST_LEN 16777215
+
+#define ISCSI_DEF_TIME2WAIT 2
+
+#define ISCSI_NAME_LEN 224
+
+/************************* RFC 3720 End *****************************/
+
+#endif /* ISCSI_PROTO_H */
diff --git a/include/scsi/iser.h b/include/scsi/iser.h
new file mode 100644
index 000000000..2e678fa74
--- /dev/null
+++ b/include/scsi/iser.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2015 Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef ISCSI_ISER_H
+#define ISCSI_ISER_H
+
+#define ISER_ZBVA_NOT_SUP 0x80
+#define ISER_SEND_W_INV_NOT_SUP 0x40
+#define ISERT_ZBVA_NOT_USED 0x80
+#define ISERT_SEND_W_INV_NOT_USED 0x40
+
+#define ISCSI_CTRL 0x10
+#define ISER_HELLO 0x20
+#define ISER_HELLORPLY 0x30
+
+#define ISER_VER 0x10
+#define ISER_WSV 0x08
+#define ISER_RSV 0x04
+
+/**
+ * struct iser_cm_hdr - iSER CM header (from iSER Annex A12)
+ *
+ * @flags: flags support (zbva, send_w_inv)
+ * @rsvd: reserved
+ */
+struct iser_cm_hdr {
+ u8 flags;
+ u8 rsvd[3];
+} __packed;
+
+/**
+ * struct iser_ctrl - iSER header of iSCSI control PDU
+ *
+ * @flags: opcode and read/write valid bits
+ * @rsvd: reserved
+ * @write_stag: write rkey
+ * @write_va: write virtual address
+ * @reaf_stag: read rkey
+ * @read_va: read virtual address
+ */
+struct iser_ctrl {
+ u8 flags;
+ u8 rsvd[3];
+ __be32 write_stag;
+ __be64 write_va;
+ __be32 read_stag;
+ __be64 read_va;
+} __packed;
+
+#endif /* ISCSI_ISER_H */
diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h
new file mode 100644
index 000000000..6e29e1719
--- /dev/null
+++ b/include/scsi/libfc.h
@@ -0,0 +1,1018 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright(c) 2007 Intel Corporation. All rights reserved.
+ *
+ * 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 <linux/refcount.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 */
+#define FC_EX_ALLOC_ERR 3 /* Exchange allocation failed */
+#define FC_EX_XMIT_ERR 4 /* Exchange transmit failed */
+#define FC_EX_ELS_RJT 5 /* ELS rejected */
+#define FC_EX_INV_LOGIN 6 /* Login not completed */
+#define FC_EX_SEQ_ERR 6 /* Exchange sequence error */
+
+/**
+ * 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;
+ refcount_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;
+ int timer_delay;
+ u32 recov_retry;
+ struct fc_seq *recov_seq;
+ struct completion tm_done;
+} ____cacheline_aligned_in_smp;
+
+/*
+ * @fsp should be tested and set under the scsi_pkt_queue lock
+ */
+struct libfc_cmd_priv {
+ struct fc_fcp_pkt *fsp;
+ u32 resid_len;
+ u8 status;
+};
+
+/*
+ * 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 */
+#define FC_EX_QUARANTINE (1 << 2) /* exch is quarantined */
+
+/**
+ * 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: Resource 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);
+
+ /*
+ * 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);
+
+ /*
+ * 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);
+
+ /*
+ * 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 *);
+
+ /*
+ * 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: Resource 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;
+ u16 vlan;
+ 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
+ * @wwpn: The new WWPN
+ */
+static inline void fc_set_wwpn(struct fc_lport *lport, u64 wwpn)
+{
+ lport->wwpn = wwpn;
+}
+
+/**
+ * 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 retrieved
+ */
+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 *);
+void fc_lport_recv(struct fc_lport *lport, struct fc_frame *fp);
+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 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
+ *****************************/
+void fc_rport_terminate_io(struct fc_rport *);
+struct fc_rport_priv *fc_rport_lookup(const struct fc_lport *lport,
+ u32 port_id);
+struct fc_rport_priv *fc_rport_create(struct fc_lport *, u32);
+void fc_rport_destroy(struct kref *kref);
+int fc_rport_login(struct fc_rport_priv *rdata);
+int fc_rport_logoff(struct fc_rport_priv *rdata);
+void fc_rport_recv_req(struct fc_lport *lport, struct fc_frame *fp);
+void fc_rport_flush_queue(void);
+
+/*
+ * DISCOVERY LAYER
+ *****************************/
+void fc_disc_init(struct fc_lport *);
+void fc_disc_config(struct fc_lport *, void *);
+
+static inline struct fc_lport *fc_disc_lport(struct fc_disc *disc)
+{
+ return container_of(disc, struct fc_lport, disc);
+}
+
+/*
+ * FCP LAYER
+ *****************************/
+int fc_fcp_init(struct fc_lport *);
+void fc_fcp_destroy(struct fc_lport *);
+
+/*
+ * SCSI INTERACTION LAYER
+ *****************************/
+int fc_queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
+int fc_eh_abort(struct scsi_cmnd *);
+int fc_eh_device_reset(struct scsi_cmnd *);
+int fc_eh_host_reset(struct scsi_cmnd *);
+int fc_slave_alloc(struct scsi_device *);
+
+/*
+ * ELS/CT interface
+ *****************************/
+int fc_elsct_init(struct fc_lport *);
+struct fc_seq *fc_elsct_send(struct fc_lport *, u32 did,
+ struct fc_frame *,
+ unsigned int op,
+ void (*resp)(struct fc_seq *,
+ struct fc_frame *,
+ void *arg),
+ void *arg, u32 timer_msec);
+void fc_lport_flogi_resp(struct fc_seq *, struct fc_frame *, void *);
+void fc_lport_logo_resp(struct fc_seq *, struct fc_frame *, void *);
+void fc_fill_reply_hdr(struct fc_frame *, const struct fc_frame *,
+ enum fc_rctl, u32 parm_offset);
+void fc_fill_hdr(struct fc_frame *, const struct fc_frame *,
+ enum fc_rctl, u32 f_ctl, u16 seq_cnt, u32 parm_offset);
+
+
+/*
+ * EXCHANGE MANAGER LAYER
+ *****************************/
+int fc_exch_init(struct fc_lport *);
+void fc_exch_update_stats(struct fc_lport *lport);
+struct fc_seq *fc_exch_seq_send(struct fc_lport *lport,
+ struct fc_frame *fp,
+ void (*resp)(struct fc_seq *,
+ struct fc_frame *fp,
+ void *arg),
+ void (*destructor)(struct fc_seq *, void *),
+ void *arg, u32 timer_msec);
+void fc_seq_els_rsp_send(struct fc_frame *, enum fc_els_cmd,
+ struct fc_seq_els_data *);
+struct fc_seq *fc_seq_start_next(struct fc_seq *sp);
+void fc_seq_set_resp(struct fc_seq *sp,
+ void (*resp)(struct fc_seq *, struct fc_frame *, void *),
+ void *arg);
+struct fc_seq *fc_seq_assign(struct fc_lport *lport, struct fc_frame *fp);
+void fc_seq_release(struct fc_seq *sp);
+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);
+int fc_seq_send(struct fc_lport *lport, struct fc_seq *sp, struct fc_frame *fp);
+int fc_seq_exch_abort(const struct fc_seq *, unsigned int timer_msec);
+void fc_exch_done(struct fc_seq *sp);
+
+/*
+ * 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 000000000..279782156
--- /dev/null
+++ b/include/scsi/libfcoe.h
@@ -0,0 +1,407 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2008-2009 Cisco Systems, Inc. All rights reserved.
+ * Copyright (c) 2007-2008 Intel Corporation. All rights reserved.
+ *
+ * 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/local_lock.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_CTLR_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.
+ */
+enum fip_mode {
+ FIP_MODE_AUTO,
+ FIP_MODE_NON_FIP,
+ FIP_MODE_FABRIC,
+ FIP_MODE_VN2VN,
+};
+
+/**
+ * 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.
+ * @fip_resp: start FIP VLAN discovery responder
+ * @spma: supports SPMA server-provided MACs mode
+ * @probe_tries: number of FC_IDs probed
+ * @priority: DCBx FCoE APP priority
+ * @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_mode 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;
+ bool map_dest;
+ bool fip_resp;
+ 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 {
+ struct fc_rport_priv rdata;
+ 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_mode);
+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[ETH_ALEN], unsigned int scheme,
+ unsigned int port);
+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_mode 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)
+ * @kthread: The thread context (used by bnx2fc)
+ * @work: The work item (used by fcoe)
+ * @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 *kthread;
+ struct work_struct work;
+ struct sk_buff_head fcoe_rx_list;
+ struct page *crc_eof_page;
+ int crc_eof_offset;
+ local_lock_t lock;
+};
+
+/**
+ * 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(struct timer_list *t);
+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 000000000..7fb3cb787
--- /dev/null
+++ b/include/scsi/libiscsi.h
@@ -0,0 +1,513 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * 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
+ */
+#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 <linux/refcount.h>
+#include <scsi/iscsi_proto.h>
+#include <scsi/iscsi_if.h>
+#include <scsi/scsi_cmnd.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 flags */
+#define ISCSI_CONN_FLAG_SUSPEND_TX 0
+#define ISCSI_CONN_FLAG_SUSPEND_RX 1
+#define ISCSI_CONN_FLAG_BOUND 2
+
+#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;
+ refcount_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;
+}
+
+static inline bool iscsi_task_is_completed(struct iscsi_task *task)
+{
+ return task->state == ISCSI_TASK_COMPLETED ||
+ task->state == ISCSI_TASK_ABRT_TMF ||
+ task->state == ISCSI_TASK_ABRT_SESS_RECOV;
+}
+
+/* Private data associated with struct scsi_cmnd. */
+struct iscsi_cmd {
+ struct iscsi_task *task;
+ int age;
+};
+
+static inline struct iscsi_cmd *iscsi_cmd(struct scsi_cmnd *cmd)
+{
+ return scsi_cmd_priv(cmd);
+}
+
+/* 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 */
+ /* items must be added/deleted under frwd lock */
+ 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 */
+ /* recv */
+ struct work_struct recvwork;
+ unsigned long flags; /* ISCSI_CONN_FLAGs */
+
+ /* 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;
+ /* 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.*/
+ struct iscsi_task *running_aborted_task;
+
+ /* 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, queues */
+ 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;
+};
+
+/*
+ * scsi host template
+ */
+extern int iscsi_eh_abort(struct scsi_cmnd *sc);
+extern int iscsi_eh_recover_target(struct scsi_cmnd *sc);
+extern int iscsi_eh_session_reset(struct scsi_cmnd *sc);
+extern int iscsi_eh_device_reset(struct scsi_cmnd *sc);
+extern int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc);
+extern enum blk_eh_timer_return iscsi_eh_cmd_timed_out(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, bool is_shutdown);
+extern void iscsi_host_free(struct Scsi_Host *shost);
+extern int iscsi_target_alloc(struct scsi_target *starget);
+extern int iscsi_host_get_max_scsi_cmds(struct Scsi_Host *shost,
+ uint16_t requested_cmds_max);
+
+/*
+ * 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);
+void iscsi_session_remove(struct iscsi_cls_session *cls_session);
+void iscsi_session_free(struct iscsi_cls_session *cls_session);
+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_unbind(struct iscsi_cls_conn *cls_conn, bool is_active);
+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_rx(struct iscsi_conn *conn);
+extern void iscsi_suspend_queue(struct iscsi_conn *conn);
+extern void iscsi_conn_queue_xmit(struct iscsi_conn *conn);
+extern void iscsi_conn_queue_recv(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 bool 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 000000000..7c8ba9d73
--- /dev/null
+++ b/include/scsi/libiscsi_tcp.h
@@ -0,0 +1,126 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * 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
+ */
+
+#ifndef LIBISCSI_TCP_H
+#define LIBISCSI_TCP_H
+
+#include <scsi/libiscsi.h>
+
+struct iscsi_tcp_conn;
+struct iscsi_segment;
+struct sk_buff;
+struct ahash_request;
+
+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 ahash_request *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 ahash_request *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 ahash_request *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 ahash_request *hash);
+
+/* digest helpers */
+extern void iscsi_tcp_dgst_header(struct ahash_request *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 000000000..2dbead74a
--- /dev/null
+++ b/include/scsi/libsas.h
@@ -0,0 +1,759 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * SAS host prototypes and structures header file
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ */
+
+#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 port_event {
+ PORTE_BYTES_DMAED = 0U,
+ PORTE_BROADCAST_RCVD,
+ PORTE_LINK_RESET_ERR,
+ PORTE_TIMER_EVENT,
+ PORTE_HARD_RESET,
+ PORT_NUM_EVENTS,
+};
+
+enum phy_event {
+ PHYE_LOSS_OF_SIGNAL = 0U,
+ PHYE_OOB_DONE,
+ PHYE_OOB_ERROR,
+ PHYE_SPINUP_HOLD, /* hot plug SATA, no COMWAKE sent */
+ PHYE_RESUME_TIMEOUT,
+ PHYE_SHUTDOWN,
+ PHY_NUM_EVENTS,
+};
+
+enum discover_event {
+ DISCE_DISCOVER_DOMAIN = 0U,
+ DISCE_REVALIDATE_DOMAIN,
+ DISCE_SUSPEND,
+ DISCE_RESUME,
+ DISC_NUM_EVENTS,
+};
+
+/* ---------- Expander Devices ---------- */
+
+#define to_dom_device(_obj) container_of(_obj, struct domain_device, dev_obj)
+#define to_dev_attr(_attr) container_of(_attr, struct domain_dev_attribute,\
+ attr)
+
+enum routing_attribute {
+ DIRECT_ROUTING,
+ SUBTRACTIVE_ROUTING,
+ TABLE_ROUTING,
+};
+
+enum ex_phy_state {
+ PHY_EMPTY,
+ PHY_VACANT,
+ PHY_NOT_PRESENT,
+ PHY_DEVICE_DISCOVERED
+};
+
+struct ex_phy {
+ int phy_id;
+
+ enum ex_phy_state phy_state;
+
+ enum sas_device_type attached_dev_type;
+ enum sas_linkrate linkrate;
+
+ u8 attached_sata_host:1;
+ u8 attached_sata_dev:1;
+ u8 attached_sata_ps:1;
+
+ enum sas_protocol attached_tproto;
+ enum sas_protocol attached_iproto;
+
+ u8 attached_sas_addr[SAS_ADDR_SIZE];
+ u8 attached_phy_id;
+
+ int phy_change_count;
+ enum routing_attribute routing_attr;
+ u8 virtual:1;
+
+ int last_da_index;
+
+ struct sas_phy *phy;
+ struct sas_port *port;
+};
+
+struct expander_device {
+ struct list_head children;
+
+ int ex_change_count;
+ u16 max_route_indexes;
+ u8 num_phys;
+
+ u8 t2t_supp:1;
+ u8 configuring:1;
+ u8 conf_route_table:1;
+
+ u8 enclosure_logical_id[8];
+
+ struct ex_phy *ex_phy;
+ struct sas_port *parent_port;
+
+ struct mutex cmd_mutex;
+};
+
+/* ---------- SATA device ---------- */
+#define ATA_RESP_FIS_SIZE 24
+
+struct sata_device {
+ unsigned int class;
+ u8 port_no; /* port number, if this is a PM (Port) */
+
+ struct ata_port *ap;
+ struct ata_host *ata_host;
+ struct smp_rps_resp rps_resp ____cacheline_aligned; /* report_phy_sata_resp */
+ 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 bool dev_is_expander(enum sas_device_type type)
+{
+ return type == SAS_EDGE_EXPANDER_DEVICE ||
+ type == SAS_FANOUT_EXPANDER_DEVICE;
+}
+
+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[SAS_ADDR_SIZE];
+ u8 eeds_a[SAS_ADDR_SIZE];
+ u8 eeds_b[SAS_ADDR_SIZE];
+ int max_level;
+};
+
+/* The port struct is Class:RW, driver:RO */
+struct asd_sas_port {
+/* private: */
+ 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;
+ struct list_head sas_port_del_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;
+ int event;
+};
+
+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;
+}
+
+static inline void INIT_SAS_EVENT(struct asd_sas_event *ev,
+ void (*fn)(struct work_struct *),
+ struct asd_sas_phy *phy, int event)
+{
+ INIT_SAS_WORK(&ev->work, fn);
+ ev->phy = phy;
+ ev->event = event;
+}
+
+#define SAS_PHY_SHUTDOWN_THRES 1024
+
+/* The phy pretty much is controlled by the LLDD.
+ * The class only reads those fields.
+ */
+struct asd_sas_phy {
+/* private: */
+ atomic_t event_nr;
+ int in_shutdown;
+ 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;
+
+};
+
+enum sas_ha_state {
+ SAS_HA_REGISTERED,
+ SAS_HA_DRAINING,
+ SAS_HA_ATA_EH_ACTIVE,
+ SAS_HA_FROZEN,
+ SAS_HA_RESUMING,
+};
+
+struct sas_ha_struct {
+/* private: */
+ 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 */
+
+ struct workqueue_struct *event_q;
+ struct workqueue_struct *disco_q;
+
+ u8 *sas_addr; /* must be set */
+ u8 hashed_sas_addr[HASHED_SAS_ADDR_SIZE];
+
+ spinlock_t phy_port_lock;
+ struct asd_sas_phy **sas_phy; /* array of valid pointers, must be set */
+ struct asd_sas_port **sas_port; /* array of valid pointers, must be set */
+ int num_phys; /* must be set, gt 0, static */
+
+ int strict_wide_ports; /* both sas_addr and attached_sas_addr must match
+ * their siblings when forming wide ports */
+
+ 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 */
+
+ int event_thres;
+};
+
+#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 {
+ /*
+ * Values 0..0x7f are used to return the SAM_STAT_* codes. To avoid
+ * 'case value not in enumerated type' compiler warnings every value
+ * returned through the exec_status enum needs an alias with the SAS_
+ * prefix here.
+ */
+ SAS_SAM_STAT_GOOD = SAM_STAT_GOOD,
+ SAS_SAM_STAT_BUSY = SAM_STAT_BUSY,
+ SAS_SAM_STAT_TASK_ABORTED = SAM_STAT_TASK_ABORTED,
+ SAS_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_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;
+
+ bool force_phy;
+ int force_phy_id;
+};
+
+/* LLDDs rely on these values */
+enum sas_internal_abort {
+ SAS_INTERNAL_ABORT_SINGLE = 0,
+ SAS_INTERNAL_ABORT_DEV = 1,
+};
+
+struct sas_internal_abort_task {
+ enum sas_internal_abort type;
+ unsigned int qid;
+ u16 tag;
+};
+
+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_tmf_task {
+ u8 tmf;
+ u16 tag_of_task_to_be_managed;
+};
+
+struct sas_task {
+ struct domain_device *dev;
+
+ spinlock_t task_state_lock;
+ unsigned task_state_flags;
+
+ enum sas_protocol task_proto;
+
+ union {
+ struct sas_ata_task ata_task;
+ struct sas_smp_task smp_task;
+ struct sas_ssp_task ssp_task;
+ struct sas_internal_abort_task abort_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_tmf_task *tmf;
+};
+
+struct sas_task_slow {
+ /* standard/extra infrastructure for slow path commands (SMP and
+ * internal lldd commands
+ */
+ struct timer_list timer;
+ struct completion completion;
+ struct sas_task *task;
+};
+
+#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
+
+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);
+
+static inline bool sas_is_internal_abort(struct sas_task *task)
+{
+ return task->task_proto == SAS_PROTOCOL_INTERNAL_ABORT;
+}
+
+struct sas_domain_function_template {
+ /* The class calls these to notify the LLDD of an event. */
+ void (*lldd_port_formed)(struct asd_sas_phy *);
+ void (*lldd_port_deformed)(struct asd_sas_phy *);
+
+ /* The class calls these when a device is found or gone. */
+ int (*lldd_dev_found)(struct domain_device *);
+ void (*lldd_dev_gone)(struct domain_device *);
+
+ int (*lldd_execute_task)(struct sas_task *, gfp_t gfp_flags);
+
+ /* Task Management Functions. Must be called from process context. */
+ int (*lldd_abort_task)(struct sas_task *);
+ int (*lldd_abort_task_set)(struct domain_device *, u8 *lun);
+ int (*lldd_clear_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 *);
+
+ /* Special TMF callbacks */
+ void (*lldd_tmf_exec_complete)(struct domain_device *dev);
+ void (*lldd_tmf_aborted)(struct sas_task *task);
+ bool (*lldd_abort_timeout)(struct sas_task *task, void *data);
+
+ /* 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_resume_ha_no_sync(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_phy_enable(struct sas_phy *phy, int enable);
+extern int sas_queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
+extern int sas_target_alloc(struct scsi_target *);
+extern int sas_slave_configure(struct scsi_device *);
+extern int sas_change_queue_depth(struct scsi_device *, int new_depth);
+extern int sas_bios_param(struct scsi_device *, struct block_device *,
+ sector_t capacity, int *hsc);
+int sas_execute_internal_abort_single(struct domain_device *device,
+ u16 tag, unsigned int qid,
+ void *data);
+int sas_execute_internal_abort_dev(struct domain_device *device,
+ unsigned int qid, void *data);
+extern struct scsi_transport_template *
+sas_domain_attach_transport(struct sas_domain_function_template *);
+extern struct device_attribute dev_attr_phy_event_threshold;
+
+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 *);
+void 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_target_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, unsigned int cmd,
+ void __user *arg);
+extern int sas_drain_work(struct sas_ha_struct *ha);
+
+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);
+
+int sas_abort_task_set(struct domain_device *dev, u8 *lun);
+int sas_clear_task_set(struct domain_device *dev, u8 *lun);
+int sas_lu_reset(struct domain_device *dev, u8 *lun);
+int sas_query_task(struct sas_task *task, u16 tag);
+int sas_abort_task(struct sas_task *task, u16 tag);
+
+void sas_notify_port_event(struct asd_sas_phy *phy, enum port_event event,
+ gfp_t gfp_flags);
+void sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event,
+ gfp_t gfp_flags);
+
+#endif /* _SASLIB_H_ */
diff --git a/include/scsi/sas.h b/include/scsi/sas.h
new file mode 100644
index 000000000..71b749bed
--- /dev/null
+++ b/include/scsi/sas.h
@@ -0,0 +1,723 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * SAS structures and definitions header file
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ */
+
+#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,
+ /* these are internal to libsas */
+ SAS_PROTOCOL_INTERNAL_ABORT = 0x10,
+};
+
+/* 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,
+};
+
+/* Response frame DATAPRES field */
+enum {
+ SAS_DATAPRES_NO_DATA = 0,
+ SAS_DATAPRES_RESPONSE_DATA = 1,
+ SAS_DATAPRES_SENSE_DATA = 2,
+};
+
+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;
+
+ union {
+ DECLARE_FLEX_ARRAY(u8, resp_data);
+ DECLARE_FLEX_ARRAY(u8, sense_data);
+ };
+} __attribute__ ((packed));
+
+struct ssp_command_iu {
+ u8 lun[8];
+ u8 _r_a;
+
+ union {
+ struct {
+ u8 attr:3;
+ u8 prio:4;
+ u8 efb:1;
+ };
+ u8 efb_prio_attr;
+ };
+
+ u8 _r_b;
+
+ u8 _r_c:2;
+ u8 add_cdb_len:6;
+
+ u8 cdb[16];
+ u8 add_cdb[];
+} __attribute__ ((packed));
+
+struct xfer_rdy_iu {
+ __be32 requested_offset;
+ __be32 write_data_len;
+ __be32 _r_a;
+} __attribute__ ((packed));
+
+struct ssp_tmf_iu {
+ u8 lun[8];
+ u16 _r_a;
+ u8 tmf;
+ u8 _r_b;
+ __be16 tag;
+ u8 _r_c[14];
+} __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));
+
+#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;
+
+ union {
+ DECLARE_FLEX_ARRAY(u8, resp_data);
+ DECLARE_FLEX_ARRAY(u8, sense_data);
+ };
+} __attribute__ ((packed));
+
+struct ssp_command_iu {
+ u8 lun[8];
+ u8 _r_a;
+
+ union {
+ struct {
+ u8 efb:1;
+ u8 prio:4;
+ u8 attr:3;
+ };
+ u8 efb_prio_attr;
+ };
+
+ u8 _r_b;
+
+ u8 add_cdb_len:6;
+ u8 _r_c:2;
+
+ u8 cdb[16];
+ u8 add_cdb[];
+} __attribute__ ((packed));
+
+struct xfer_rdy_iu {
+ __be32 requested_offset;
+ __be32 write_data_len;
+ __be32 _r_a;
+} __attribute__ ((packed));
+
+struct ssp_tmf_iu {
+ u8 lun[8];
+ u16 _r_a;
+ u8 tmf;
+ u8 _r_b;
+ __be16 tag;
+ u8 _r_c[14];
+} __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));
+
+#else
+#error "Bitfield order not defined!"
+#endif
+
+struct smp_rg_resp {
+ u8 frame_type;
+ u8 function;
+ u8 result;
+ u8 reserved;
+ struct report_general_resp rg;
+} __attribute__ ((packed));
+
+struct smp_disc_resp {
+ u8 frame_type;
+ u8 function;
+ u8 result;
+ u8 reserved;
+ struct discover_resp disc;
+} __attribute__ ((packed));
+
+struct smp_rps_resp {
+ u8 frame_type;
+ u8 function;
+ u8 result;
+ u8 reserved;
+ struct report_phy_sata_resp rps;
+} __attribute__ ((packed));
+
+#endif /* _SAS_H_ */
diff --git a/include/scsi/sas_ata.h b/include/scsi/sas_ata.h
new file mode 100644
index 000000000..e7d466df8
--- /dev/null
+++ b/include/scsi/sas_ata.h
@@ -0,0 +1,115 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * 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
+ */
+
+#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);
+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);
+void sas_ata_device_link_abort(struct domain_device *dev, bool force_reset);
+int sas_execute_ata_cmd(struct domain_device *device, u8 *fis,
+ int force_phy_id);
+int sas_ata_wait_after_reset(struct domain_device *dev, unsigned long deadline);
+int smp_ata_check_ready_type(struct ata_link *link);
+#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)
+{
+}
+
+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)
+{
+}
+
+static inline void sas_ata_device_link_abort(struct domain_device *dev,
+ bool force_reset)
+{
+}
+
+static inline int sas_execute_ata_cmd(struct domain_device *device, u8 *fis,
+ int force_phy_id)
+{
+ return 0;
+}
+
+static inline int sas_ata_wait_after_reset(struct domain_device *dev,
+ unsigned long deadline)
+{
+ return -ETIMEDOUT;
+}
+
+static inline int smp_ata_check_ready_type(struct ata_link *link)
+{
+ return 0;
+}
+#endif
+
+#endif /* _SAS_ATA_H_ */
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
new file mode 100644
index 000000000..3e4685977
--- /dev/null
+++ b/include/scsi/scsi.h
@@ -0,0 +1,219 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * This header file contains public constants and structures used by
+ * the SCSI initiator code.
+ */
+#ifndef _SCSI_SCSI_H
+#define _SCSI_SCSI_H
+
+#include <linux/types.h>
+#include <linux/scatterlist.h>
+#include <linux/kernel.h>
+#include <scsi/scsi_common.h>
+#include <scsi/scsi_proto.h>
+#include <scsi/scsi_status.h>
+
+struct scsi_cmnd;
+
+enum scsi_timeouts {
+ SCSI_DEFAULT_EH_TIMEOUT = 10 * HZ,
+};
+
+/*
+ * DIX-capable adapters effectively support infinite chaining for the
+ * protection information scatterlist
+ */
+#define SCSI_MAX_PROT_SG_SEGMENTS 0xFFFF
+
+/*
+ * Special value for scanning to specify scanning or rescanning of all
+ * possible channels, (target) ids, or luns on a given shost.
+ */
+#define SCAN_WILD_CARD ~0
+
+/*
+ * standard mode-select header prepended to all mode-select commands
+ */
+
+struct ccs_modesel_head {
+ __u8 _r1; /* reserved */
+ __u8 medium; /* device-specific medium type */
+ __u8 _r2; /* reserved */
+ __u8 block_desc_length; /* block descriptor length */
+ __u8 density; /* device-specific density code */
+ __u8 number_blocks_hi; /* number of blocks in this block desc */
+ __u8 number_blocks_med;
+ __u8 number_blocks_lo;
+ __u8 _r3;
+ __u8 block_length_hi; /* block length for blocks in this desc */
+ __u8 block_length_med;
+ __u8 block_length_lo;
+};
+
+/*
+ * The Well Known LUNS (SAM-3) in our int representation of a LUN
+ */
+#define SCSI_W_LUN_BASE 0xc100
+#define SCSI_W_LUN_REPORT_LUNS (SCSI_W_LUN_BASE + 1)
+#define SCSI_W_LUN_ACCESS_CONTROL (SCSI_W_LUN_BASE + 2)
+#define SCSI_W_LUN_TARGET_LOG_PAGE (SCSI_W_LUN_BASE + 3)
+
+static inline int scsi_is_wlun(u64 lun)
+{
+ return (lun & 0xff00) == SCSI_W_LUN_BASE;
+}
+
+/**
+ * scsi_status_is_check_condition - check the status return.
+ *
+ * @status: the status passed up from the driver (including host and
+ * driver components)
+ *
+ * This returns true if the status code is SAM_STAT_CHECK_CONDITION.
+ */
+static inline int scsi_status_is_check_condition(int status)
+{
+ if (status < 0)
+ return false;
+ status &= 0xfe;
+ return status == SAM_STAT_CHECK_CONDITION;
+}
+
+/*
+ * Extended message codes.
+ */
+#define EXTENDED_MODIFY_DATA_POINTER 0x00
+#define EXTENDED_SDTR 0x01
+#define EXTENDED_EXTENDED_IDENTIFY 0x02 /* SCSI-I only */
+#define EXTENDED_WDTR 0x03
+#define EXTENDED_PPR 0x04
+#define EXTENDED_MODIFY_BIDI_DATA_PTR 0x05
+
+/*
+ * Internal return values.
+ */
+enum scsi_disposition {
+ NEEDS_RETRY = 0x2001,
+ SUCCESS = 0x2002,
+ FAILED = 0x2003,
+ QUEUED = 0x2004,
+ SOFT_ERROR = 0x2005,
+ ADD_TO_MLQUEUE = 0x2006,
+ TIMEOUT_ERROR = 0x2007,
+ SCSI_RETURN_NOT_HANDLED = 0x2008,
+ FAST_IO_FAIL = 0x2009,
+};
+
+/*
+ * Midlevel queue return values.
+ */
+#define SCSI_MLQUEUE_HOST_BUSY 0x1055
+#define SCSI_MLQUEUE_DEVICE_BUSY 0x1056
+#define SCSI_MLQUEUE_EH_RETRY 0x1057
+#define SCSI_MLQUEUE_TARGET_BUSY 0x1058
+
+/*
+ * Use these to separate status msg and our bytes
+ *
+ * These are set by:
+ *
+ * status byte = set from target device
+ * msg_byte (unused)
+ * host_byte = set by low-level driver to indicate status.
+ */
+#define host_byte(result) (((result) >> 16) & 0xff)
+
+#define sense_class(sense) (((sense) >> 4) & 0x7)
+#define sense_error(sense) ((sense) & 0xf)
+#define sense_valid(sense) ((sense) & 0x80)
+
+/*
+ * default timeouts
+*/
+#define FORMAT_UNIT_TIMEOUT (2 * 60 * 60 * HZ)
+#define START_STOP_TIMEOUT (60 * HZ)
+#define MOVE_MEDIUM_TIMEOUT (5 * 60 * HZ)
+#define READ_ELEMENT_STATUS_TIMEOUT (5 * 60 * HZ)
+#define READ_DEFECT_DATA_TIMEOUT (60 * HZ )
+
+
+#define IDENTIFY_BASE 0x80
+#define IDENTIFY(can_disconnect, lun) (IDENTIFY_BASE |\
+ ((can_disconnect) ? 0x40 : 0) |\
+ ((lun) & 0x07))
+
+/*
+ * struct scsi_device::scsi_level values. For SCSI devices other than those
+ * prior to SCSI-2 (i.e. over 12 years old) this value is (resp[2] + 1)
+ * where "resp" is a byte array of the response to an INQUIRY. The scsi_level
+ * variable is visible to the user via sysfs.
+ */
+
+#define SCSI_UNKNOWN 0
+#define SCSI_1 1
+#define SCSI_1_CCS 2
+#define SCSI_2 3
+#define SCSI_3 4 /* SPC */
+#define SCSI_SPC_2 5
+#define SCSI_SPC_3 6
+
+/*
+ * INQ PERIPHERAL QUALIFIERS
+ */
+#define SCSI_INQ_PQ_CON 0x00
+#define SCSI_INQ_PQ_NOT_CON 0x01
+#define SCSI_INQ_PQ_NOT_CAP 0x03
+
+
+/*
+ * Here are some scsi specific ioctl commands which are sometimes useful.
+ *
+ * Note that include/linux/cdrom.h also defines IOCTL 0x5300 - 0x5395
+ */
+
+/* Used to obtain PUN and LUN info. Conflicts with CDROMAUDIOBUFSIZ */
+#define SCSI_IOCTL_GET_IDLUN 0x5382
+
+/* 0x5383 and 0x5384 were used for SCSI_IOCTL_TAGGED_{ENABLE,DISABLE} */
+
+/* Used to obtain the host number of a device. */
+#define SCSI_IOCTL_PROBE_HOST 0x5385
+
+/* Used to obtain the bus number for a device */
+#define SCSI_IOCTL_GET_BUS_NUMBER 0x5386
+
+/* Used to obtain the PCI location of a device */
+#define SCSI_IOCTL_GET_PCI 0x5387
+
+/** scsi_status_is_good - check the status return.
+ *
+ * @status: the status passed up from the driver (including host and
+ * driver components)
+ *
+ * This returns true for known good conditions that may be treated as
+ * command completed normally
+ */
+static inline bool scsi_status_is_good(int status)
+{
+ if (status < 0)
+ return false;
+
+ if (host_byte(status) == DID_NO_CONNECT)
+ return false;
+
+ /*
+ * FIXME: bit0 is listed as reserved in SCSI-2, but is
+ * significant in SCSI-3. For now, we follow the SCSI-2
+ * behaviour and ignore reserved bits.
+ */
+ status &= 0xfe;
+ return ((status == SAM_STAT_GOOD) ||
+ (status == SAM_STAT_CONDITION_MET) ||
+ /* Next two "intermediate" statuses are obsolete in SAM-4 */
+ (status == SAM_STAT_INTERMEDIATE) ||
+ (status == SAM_STAT_INTERMEDIATE_CONDITION_MET) ||
+ /* FIXME: this is obsolete in SAM-3 */
+ (status == SAM_STAT_COMMAND_TERMINATED));
+}
+
+#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 000000000..9b1f0f424
--- /dev/null
+++ b/include/scsi/scsi_bsg_iscsi.h
@@ -0,0 +1,96 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * iSCSI Transport BSG Interface
+ *
+ * Copyright (C) 2009 James Smart, Emulex Corporation
+ */
+
+#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[];
+};
+
+/* 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 received ? */
+ 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
new file mode 100644
index 000000000..7d3622db3
--- /dev/null
+++ b/include/scsi/scsi_cmnd.h
@@ -0,0 +1,392 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _SCSI_SCSI_CMND_H
+#define _SCSI_SCSI_CMND_H
+
+#include <linux/dma-mapping.h>
+#include <linux/blkdev.h>
+#include <linux/t10-pi.h>
+#include <linux/list.h>
+#include <linux/types.h>
+#include <linux/timer.h>
+#include <linux/scatterlist.h>
+#include <scsi/scsi_device.h>
+
+struct Scsi_Host;
+
+/*
+ * 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
+
+struct scsi_data_buffer {
+ struct sg_table table;
+ unsigned length;
+};
+
+/* embedded in scsi_cmnd */
+struct scsi_pointer {
+ char *ptr; /* data pointer */
+ int this_residual; /* left in this buffer */
+ struct scatterlist *buffer; /* which buffer */
+ int buffers_residual; /* how many buffers left */
+
+ dma_addr_t dma_handle;
+
+ volatile int Status;
+ volatile int Message;
+ volatile int have_data_in;
+ volatile int sent_command;
+ volatile int phase;
+};
+
+/* for scmd->flags */
+#define SCMD_TAGGED (1 << 0)
+#define SCMD_INITIALIZED (1 << 1)
+#define SCMD_LAST (1 << 2)
+/* flags preserved across unprep / reprep */
+#define SCMD_PRESERVED_FLAGS (SCMD_INITIALIZED)
+
+/* for scmd->state */
+#define SCMD_STATE_COMPLETE 0
+#define SCMD_STATE_INFLIGHT 1
+
+enum scsi_cmnd_submitter {
+ SUBMITTED_BY_BLOCK_LAYER = 0,
+ SUBMITTED_BY_SCSI_ERROR_HANDLER = 1,
+ SUBMITTED_BY_SCSI_RESET_IOCTL = 2,
+} __packed;
+
+struct scsi_cmnd {
+ struct scsi_device *device;
+ struct list_head eh_entry; /* entry for the host eh_abort_list/eh_cmd_q */
+ struct delayed_work abort_work;
+
+ struct rcu_head rcu;
+
+ int eh_eflags; /* Used by error handlr */
+
+ int budget_token;
+
+ /*
+ * This is set to jiffies as it was when the command was first
+ * allocated. It is used to time how long the command has
+ * been outstanding
+ */
+ unsigned long jiffies_at_alloc;
+
+ int retries;
+ int allowed;
+
+ unsigned char prot_op;
+ unsigned char prot_type;
+ unsigned char prot_flags;
+ enum scsi_cmnd_submitter submitter;
+
+ unsigned short cmd_len;
+ enum dma_data_direction sc_data_direction;
+
+ unsigned char cmnd[32]; /* SCSI CDB */
+
+ /* These elements define the operation we ultimately want to perform */
+ struct scsi_data_buffer sdb;
+ struct scsi_data_buffer *prot_sdb;
+
+ unsigned underflow; /* Return error if less than
+ this amount is transferred */
+
+ unsigned transfersize; /* How much we are guaranteed to
+ transfer with each SCSI transfer
+ (ie, between disconnect /
+ reconnects. Probably == sector
+ size */
+ unsigned resid_len; /* residual count */
+ unsigned sense_len;
+ unsigned char *sense_buffer;
+ /* obtained by REQUEST SENSE when
+ * CHECK CONDITION is received on original
+ * command (auto-sense). Length must be
+ * SCSI_SENSE_BUFFERSIZE bytes. */
+
+ int flags; /* Command flags */
+ unsigned long state; /* Command completion state */
+
+ unsigned int extra_len; /* length of alignment and padding */
+
+ /*
+ * The fields below can be modified by the LLD but the fields above
+ * must not be modified.
+ */
+
+ unsigned char *host_scribble; /* The host adapter is allowed to
+ * call scsi_malloc and get some memory
+ * and hang it here. The host adapter
+ * is also expected to call scsi_free
+ * to release this memory. (The memory
+ * obtained by scsi_malloc is guaranteed
+ * to be at an address < 16Mb). */
+
+ int result; /* Status code from lower level driver */
+};
+
+/* Variant of blk_mq_rq_from_pdu() that verifies the type of its argument. */
+static inline struct request *scsi_cmd_to_rq(struct scsi_cmnd *scmd)
+{
+ return blk_mq_rq_from_pdu(scmd);
+}
+
+/*
+ * Return the driver private allocation behind the command.
+ * Only works if cmd_size is set in the host template.
+ */
+static inline void *scsi_cmd_priv(struct scsi_cmnd *cmd)
+{
+ return cmd + 1;
+}
+
+void scsi_done(struct scsi_cmnd *cmd);
+void scsi_done_direct(struct scsi_cmnd *cmd);
+
+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);
+
+blk_status_t scsi_alloc_sgtables(struct scsi_cmnd *cmd);
+void scsi_free_sgtables(struct scsi_cmnd *cmd);
+
+#ifdef CONFIG_SCSI_DMA
+extern int scsi_dma_map(struct scsi_cmnd *cmd);
+extern void scsi_dma_unmap(struct scsi_cmnd *cmd);
+#else /* !CONFIG_SCSI_DMA */
+static inline int scsi_dma_map(struct scsi_cmnd *cmd) { return -ENOSYS; }
+static inline void scsi_dma_unmap(struct scsi_cmnd *cmd) { }
+#endif /* !CONFIG_SCSI_DMA */
+
+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, unsigned int resid)
+{
+ cmd->resid_len = resid;
+}
+
+static inline unsigned int scsi_get_resid(struct scsi_cmnd *cmd)
+{
+ return cmd->resid_len;
+}
+
+#define scsi_for_each_sg(cmd, sg, nseg, __i) \
+ for_each_sg(scsi_sglist(cmd), sg, nseg, __i)
+
+static inline int scsi_sg_copy_from_buffer(struct scsi_cmnd *cmd,
+ const 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);
+}
+
+static inline sector_t scsi_get_sector(struct scsi_cmnd *scmd)
+{
+ return blk_rq_pos(scsi_cmd_to_rq(scmd));
+}
+
+static inline sector_t scsi_get_lba(struct scsi_cmnd *scmd)
+{
+ unsigned int shift = ilog2(scmd->device->sector_size) - SECTOR_SHIFT;
+
+ return blk_rq_pos(scsi_cmd_to_rq(scmd)) >> shift;
+}
+
+static inline unsigned int scsi_logical_block_count(struct scsi_cmnd *scmd)
+{
+ unsigned int shift = ilog2(scmd->device->sector_size) - SECTOR_SHIFT;
+
+ return blk_rq_bytes(scsi_cmd_to_rq(scmd)) >> shift;
+}
+
+/*
+ * The operations below are hints that tell the controller driver how
+ * to handle I/Os with DIF or similar types of protection information.
+ */
+enum scsi_prot_operations {
+ /* Normal I/O */
+ SCSI_PROT_NORMAL = 0,
+
+ /* OS-HBA: Protected, HBA-Target: Unprotected */
+ SCSI_PROT_READ_INSERT,
+ SCSI_PROT_WRITE_STRIP,
+
+ /* OS-HBA: Unprotected, HBA-Target: Protected */
+ SCSI_PROT_READ_STRIP,
+ SCSI_PROT_WRITE_INSERT,
+
+ /* OS-HBA: Protected, HBA-Target: Protected */
+ SCSI_PROT_READ_PASS,
+ SCSI_PROT_WRITE_PASS,
+};
+
+static inline void scsi_set_prot_op(struct scsi_cmnd *scmd, unsigned char op)
+{
+ scmd->prot_op = op;
+}
+
+static inline unsigned char scsi_get_prot_op(struct scsi_cmnd *scmd)
+{
+ return scmd->prot_op;
+}
+
+enum scsi_prot_flags {
+ SCSI_PROT_TRANSFER_PI = 1 << 0,
+ SCSI_PROT_GUARD_CHECK = 1 << 1,
+ SCSI_PROT_REF_CHECK = 1 << 2,
+ SCSI_PROT_REF_INCREMENT = 1 << 3,
+ SCSI_PROT_IP_CHECKSUM = 1 << 4,
+};
+
+/*
+ * The controller usually does not know anything about the target it
+ * is communicating with. However, when DIX is enabled the controller
+ * must be know target type so it can verify the protection
+ * information passed along with the I/O.
+ */
+enum scsi_prot_target_type {
+ SCSI_PROT_DIF_TYPE0 = 0,
+ SCSI_PROT_DIF_TYPE1,
+ SCSI_PROT_DIF_TYPE2,
+ SCSI_PROT_DIF_TYPE3,
+};
+
+static inline void scsi_set_prot_type(struct scsi_cmnd *scmd, unsigned char type)
+{
+ scmd->prot_type = type;
+}
+
+static inline unsigned char scsi_get_prot_type(struct scsi_cmnd *scmd)
+{
+ return scmd->prot_type;
+}
+
+static inline u32 scsi_prot_ref_tag(struct scsi_cmnd *scmd)
+{
+ struct request *rq = blk_mq_rq_from_pdu(scmd);
+
+ return t10_pi_ref_tag(rq);
+}
+
+static inline unsigned int scsi_prot_interval(struct scsi_cmnd *scmd)
+{
+ return scmd->device->sector_size;
+}
+
+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_status_byte(struct scsi_cmnd *cmd, char status)
+{
+ cmd->result = (cmd->result & 0xffffff00) | status;
+}
+
+static inline u8 get_status_byte(struct scsi_cmnd *cmd)
+{
+ return cmd->result & 0xff;
+}
+
+static inline void set_host_byte(struct scsi_cmnd *cmd, char status)
+{
+ cmd->result = (cmd->result & 0xff00ffff) | (status << 16);
+}
+
+static inline u8 get_host_byte(struct scsi_cmnd *cmd)
+{
+ return (cmd->result >> 16) & 0xff;
+}
+
+/**
+ * scsi_msg_to_host_byte() - translate message byte
+ *
+ * Translate the SCSI parallel message byte to a matching
+ * host byte setting. A message of COMMAND_COMPLETE indicates
+ * a successful command execution, any other message indicate
+ * an error. As the messages themselves only have a meaning
+ * for the SCSI parallel protocol this function translates
+ * them into a matching host byte value for SCSI EH.
+ */
+static inline void scsi_msg_to_host_byte(struct scsi_cmnd *cmd, u8 msg)
+{
+ switch (msg) {
+ case COMMAND_COMPLETE:
+ break;
+ case ABORT_TASK_SET:
+ set_host_byte(cmd, DID_ABORT);
+ break;
+ case TARGET_RESET:
+ set_host_byte(cmd, DID_RESET);
+ break;
+ default:
+ set_host_byte(cmd, DID_ERROR);
+ break;
+ }
+}
+
+static inline unsigned scsi_transfer_length(struct scsi_cmnd *scmd)
+{
+ unsigned int xfer_len = scmd->sdb.length;
+ unsigned int prot_interval = scsi_prot_interval(scmd);
+
+ if (scmd->prot_flags & SCSI_PROT_TRANSFER_PI)
+ xfer_len += (xfer_len >> ilog2(prot_interval)) * 8;
+
+ return xfer_len;
+}
+
+extern void scsi_build_sense(struct scsi_cmnd *scmd, int desc,
+ u8 key, u8 asc, u8 ascq);
+
+struct request *scsi_alloc_request(struct request_queue *q, blk_opf_t opf,
+ blk_mq_req_flags_t flags);
+
+#endif /* _SCSI_SCSI_CMND_H */
diff --git a/include/scsi/scsi_common.h b/include/scsi/scsi_common.h
new file mode 100644
index 000000000..5b567b43e
--- /dev/null
+++ b/include/scsi/scsi_common.h
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Functions used by both the SCSI initiator code and the SCSI target code.
+ */
+
+#ifndef _SCSI_COMMON_H_
+#define _SCSI_COMMON_H_
+
+#include <linux/types.h>
+#include <scsi/scsi_proto.h>
+
+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]);
+}
+
+static inline unsigned char
+scsi_command_control(const unsigned char *cmnd)
+{
+ return (cmnd[0] == VARIABLE_LENGTH_CMD) ?
+ cmnd[1] : cmnd[COMMAND_SIZE(cmnd[0]) - 1];
+}
+
+/* Returns a human-readable name for the device */
+extern const char *scsi_device_type(unsigned type);
+
+extern void int_to_scsilun(u64, struct scsi_lun *);
+extern u64 scsilun_to_int(struct scsi_lun *);
+
+/*
+ * This is a slightly modified SCSI sense "descriptor" format header.
+ * The addition is to allow the 0x70 and 0x71 response codes. The idea
+ * is to place the salient data from either "fixed" or "descriptor" sense
+ * format into one structure to ease application processing.
+ *
+ * The original sense buffer should be kept around for those cases
+ * in which more information is required (e.g. the LBA of a MEDIUM ERROR).
+ */
+struct scsi_sense_hdr { /* See SPC-3 section 4.5 */
+ u8 response_code; /* permit: 0x0, 0x70, 0x71, 0x72, 0x73 */
+ u8 sense_key;
+ u8 asc;
+ u8 ascq;
+ u8 byte4;
+ u8 byte5;
+ u8 byte6;
+ u8 additional_length; /* always 0 for fixed sense format */
+};
+
+static inline bool scsi_sense_valid(const struct scsi_sense_hdr *sshdr)
+{
+ if (!sshdr)
+ return false;
+
+ return (sshdr->response_code & 0x70) == 0x70;
+}
+
+extern bool scsi_normalize_sense(const u8 *sense_buffer, int sb_len,
+ struct scsi_sense_hdr *sshdr);
+
+extern void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq);
+int scsi_set_sense_information(u8 *buf, int buf_len, u64 info);
+int scsi_set_sense_field_pointer(u8 *buf, int buf_len, u16 fp, u8 bp, bool cd);
+extern const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len,
+ int desc_type);
+
+#endif /* _SCSI_COMMON_H_ */
diff --git a/include/scsi/scsi_dbg.h b/include/scsi/scsi_dbg.h
new file mode 100644
index 000000000..7b196d234
--- /dev/null
+++ b/include/scsi/scsi_dbg.h
@@ -0,0 +1,87 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _SCSI_SCSI_DBG_H
+#define _SCSI_SCSI_DBG_H
+
+struct scsi_cmnd;
+struct scsi_device;
+struct scsi_sense_hdr;
+
+extern void scsi_print_command(struct scsi_cmnd *);
+extern size_t __scsi_format_command(char *, size_t,
+ const unsigned char *, size_t);
+extern void scsi_print_sense_hdr(const struct scsi_device *, const char *,
+ const struct scsi_sense_hdr *);
+extern void scsi_print_sense(const struct scsi_cmnd *);
+extern void __scsi_print_sense(const struct scsi_device *, const char *name,
+ const unsigned char *sense_buffer,
+ int sense_len);
+extern void scsi_print_result(const struct scsi_cmnd *, const char *, int);
+
+#ifdef CONFIG_SCSI_CONSTANTS
+extern bool scsi_opcode_sa_name(int, int, const char **, const char **);
+extern const char *scsi_sense_key_string(unsigned char);
+extern const char *scsi_extd_sense_format(unsigned char, unsigned char,
+ const char **);
+extern const char *scsi_mlreturn_string(int);
+extern const char *scsi_hostbyte_string(int);
+extern const char *scsi_driverbyte_string(int);
+#else
+static inline bool
+scsi_opcode_sa_name(int cmd, int sa,
+ const char **cdb_name, const char **sa_name)
+{
+ *cdb_name = NULL;
+ switch (cmd) {
+ case VARIABLE_LENGTH_CMD:
+ case MAINTENANCE_IN:
+ case MAINTENANCE_OUT:
+ case PERSISTENT_RESERVE_IN:
+ case PERSISTENT_RESERVE_OUT:
+ case SERVICE_ACTION_IN_12:
+ case SERVICE_ACTION_OUT_12:
+ case SERVICE_ACTION_BIDIRECTIONAL:
+ case SERVICE_ACTION_IN_16:
+ case SERVICE_ACTION_OUT_16:
+ case EXTENDED_COPY:
+ case RECEIVE_COPY_RESULTS:
+ *sa_name = NULL;
+ return true;
+ default:
+ return false;
+ }
+}
+
+static inline const char *
+scsi_sense_key_string(unsigned char key)
+{
+ return NULL;
+}
+
+static inline const char *
+scsi_extd_sense_format(unsigned char asc, unsigned char ascq, const char **fmt)
+{
+ *fmt = NULL;
+ return NULL;
+}
+
+static inline const char *
+scsi_mlreturn_string(int result)
+{
+ return NULL;
+}
+
+static inline const char *
+scsi_hostbyte_string(int result)
+{
+ return NULL;
+}
+
+static inline const char *
+scsi_driverbyte_string(int result)
+{
+ return NULL;
+}
+
+#endif
+
+#endif /* _SCSI_SCSI_DBG_H */
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
new file mode 100644
index 000000000..fdc31fdb6
--- /dev/null
+++ b/include/scsi/scsi_device.h
@@ -0,0 +1,647 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _SCSI_SCSI_DEVICE_H
+#define _SCSI_SCSI_DEVICE_H
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/blk-mq.h>
+#include <scsi/scsi.h>
+#include <linux/atomic.h>
+#include <linux/sbitmap.h>
+
+struct bsg_device;
+struct device;
+struct request_queue;
+struct scsi_cmnd;
+struct scsi_lun;
+struct scsi_sense_hdr;
+
+typedef __u64 __bitwise blist_flags_t;
+
+#define SCSI_SENSE_BUFFERSIZE 96
+
+struct scsi_mode_data {
+ __u32 length;
+ __u16 block_descriptor_length;
+ __u8 medium_type;
+ __u8 device_specific;
+ __u8 header_length;
+ __u8 longlba:1;
+};
+
+/*
+ * sdev state: If you alter this, you also need to alter scsi_sysfs.c
+ * (for the ascii descriptions) and the state model enforcer:
+ * scsi_lib:scsi_device_set_state().
+ */
+enum scsi_device_state {
+ SDEV_CREATED = 1, /* device created but not added to sysfs
+ * Only internal commands allowed (for inq) */
+ SDEV_RUNNING, /* device properly configured
+ * All commands allowed */
+ SDEV_CANCEL, /* beginning to delete device
+ * Only error handler commands allowed */
+ SDEV_DEL, /* device deleted
+ * no commands allowed */
+ SDEV_QUIESCE, /* Device quiescent. No block commands
+ * will be accepted, only specials (which
+ * originate in the mid-layer) */
+ SDEV_OFFLINE, /* Device offlined (by error handling or
+ * user request */
+ SDEV_TRANSPORT_OFFLINE, /* Offlined by transport class error handler */
+ SDEV_BLOCK, /* Device blocked by scsi lld. No
+ * scsi commands from user or midlayer
+ * should be issued to the scsi
+ * lld. */
+ SDEV_CREATED_BLOCK, /* same as above but for created devices */
+};
+
+enum scsi_scan_mode {
+ SCSI_SCAN_INITIAL = 0,
+ SCSI_SCAN_RESCAN,
+ SCSI_SCAN_MANUAL,
+};
+
+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_ALUA_STATE_CHANGE_REPORTED, /* 2A 06 UA reported */
+ SDEV_EVT_POWER_ON_RESET_OCCURRED, /* 29 00 UA reported */
+
+ SDEV_EVT_FIRST = SDEV_EVT_MEDIA_CHANGE,
+ SDEV_EVT_LAST = SDEV_EVT_POWER_ON_RESET_OCCURRED,
+
+ 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_vpd - SCSI Vital Product Data
+ * @rcu: For kfree_rcu().
+ * @len: Length in bytes of @data.
+ * @data: VPD data as defined in various T10 SCSI standard documents.
+ */
+struct scsi_vpd {
+ struct rcu_head rcu;
+ int len;
+ unsigned char data[];
+};
+
+enum scsi_vpd_parameters {
+ SCSI_VPD_HEADER_SIZE = 4,
+};
+
+struct scsi_device {
+ struct Scsi_Host *host;
+ struct request_queue *request_queue;
+
+ /* the next two are protected by the host->host_lock */
+ struct list_head siblings; /* list of all devices on this host */
+ struct list_head same_target_siblings; /* just the devices sharing same target id */
+
+ struct sbitmap budget_map;
+ atomic_t device_blocked; /* Device returned QUEUE_FULL. */
+
+ atomic_t restarts;
+ spinlock_t list_lock;
+ struct list_head starved_entry;
+ unsigned short queue_depth; /* How deep of a queue we want */
+ unsigned short max_queue_depth; /* max queue depth */
+ unsigned short last_queue_full_depth; /* These two are used by */
+ unsigned short last_queue_full_count; /* scsi_track_queue_full() */
+ unsigned long last_queue_full_time; /* last queue full time */
+ unsigned long queue_ramp_up_period; /* ramp up period in jiffies */
+#define SCSI_DEFAULT_RAMP_UP_PERIOD (120 * HZ)
+
+ unsigned long last_queue_ramp_up; /* last queue ramp up time */
+
+ unsigned int id, channel;
+ u64 lun;
+ unsigned int manufacturer; /* Manufacturer of device, for using
+ * vendor-specific cmd's */
+ unsigned sector_size; /* size in bytes */
+
+ void *hostdata; /* available to low-level driver */
+ unsigned char type;
+ char scsi_level;
+ char inq_periph_qual; /* PQ from INQUIRY data */
+ struct mutex inquiry_mutex;
+ unsigned char inquiry_len; /* valid bytes in 'inquiry' */
+ unsigned char * inquiry; /* INQUIRY response data */
+ const char * vendor; /* [back_compat] point into 'inquiry' ... */
+ const char * model; /* ... after scan; point to static string */
+ const char * rev; /* ... "nullnullnullnull" before scan */
+
+#define SCSI_DEFAULT_VPD_LEN 255 /* default SCSI VPD page size (max) */
+ struct scsi_vpd __rcu *vpd_pg0;
+ struct scsi_vpd __rcu *vpd_pg83;
+ struct scsi_vpd __rcu *vpd_pg80;
+ struct scsi_vpd __rcu *vpd_pg89;
+ struct scsi_vpd __rcu *vpd_pgb0;
+ struct scsi_vpd __rcu *vpd_pgb1;
+ struct scsi_vpd __rcu *vpd_pgb2;
+
+ struct scsi_target *sdev_target;
+
+ blist_flags_t sdev_bflags; /* black/white flags as also found in
+ * scsi_devinfo.[hc]. For now used only to
+ * pass settings from slave_alloc to scsi
+ * core. */
+ unsigned int eh_timeout; /* Error handling timeout */
+
+ /*
+ * If true, let the high-level device driver (sd) manage the device
+ * power state for system suspend/resume (suspend to RAM and
+ * hibernation) operations.
+ */
+ unsigned manage_system_start_stop:1;
+
+ /*
+ * If true, let the high-level device driver (sd) manage the device
+ * power state for runtime device suspand and resume operations.
+ */
+ unsigned manage_runtime_start_stop:1;
+
+ /*
+ * If true, let the high-level device driver (sd) manage the device
+ * power state for system shutdown (power off) operations.
+ */
+ unsigned manage_shutdown:1;
+
+ /*
+ * If set and if the device is runtime suspended, ask the high-level
+ * device driver (sd) to force a runtime resume of the device.
+ */
+ unsigned force_runtime_start_on_system_start:1;
+
+ unsigned removable:1;
+ unsigned changed:1; /* Data invalid due to media change */
+ unsigned busy:1; /* Used to prevent races */
+ unsigned lockable:1; /* Able to prevent media removal */
+ unsigned locked:1; /* Media removal disabled */
+ unsigned borken:1; /* Tell the Seagate driver to be
+ * painfully slow on this device */
+ unsigned disconnect:1; /* can disconnect */
+ unsigned soft_reset:1; /* Uses soft reset option */
+ unsigned sdtr:1; /* Device supports SDTR messages */
+ unsigned wdtr:1; /* Device supports WDTR messages */
+ unsigned ppr:1; /* Device supports PPR messages */
+ unsigned tagged_supported:1; /* Supports SCSI-II tagged queuing */
+ unsigned simple_tags:1; /* simple queue tag messages are enabled */
+ unsigned 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 set_dbd_for_ms:1; /* Set "DBD" field in mode sense */
+ unsigned no_report_opcodes:1; /* no REPORT SUPPORTED OPERATION CODES */
+ unsigned no_write_same:1; /* no WRITE SAME command */
+ unsigned use_16_for_rw:1; /* Use read/write(16) over read/write(10) */
+ unsigned skip_ms_page_8:1; /* do not use MODE SENSE page 0x08 */
+ unsigned skip_ms_page_3f:1; /* do not use MODE SENSE page 0x3f */
+ unsigned skip_vpd_pages:1; /* do not read VPD pages */
+ unsigned try_vpd_pages:1; /* attempt to read VPD pages */
+ unsigned use_192_bytes_for_3f:1; /* ask for 192 bytes from page 0x3f */
+ unsigned no_start_on_add:1; /* do not issue start on add */
+ unsigned allow_restart:1; /* issue START_UNIT in error handler */
+ unsigned no_start_on_resume:1; /* Do not issue START_STOP_UNIT on resume */
+ 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 security_supported:1; /* Supports Security Protocols */
+ unsigned is_visible:1; /* is the device visible in sysfs */
+ unsigned wce_default_on:1; /* Cache is ON by default */
+ unsigned no_dif:1; /* T10 PI (DIF) should be disabled */
+ unsigned broken_fua:1; /* Don't set FUA bit */
+ unsigned lun_in_cdb:1; /* Store LUN bits in CDB[1] */
+ unsigned unmap_limit_for_ws:1; /* Use the UNMAP limit for WRITE SAME */
+ unsigned rpm_autosuspend:1; /* Enable runtime autosuspend at device
+ * creation time */
+ unsigned ignore_media_change:1; /* Ignore MEDIA CHANGE on resume */
+ unsigned silence_suspend:1; /* Do not print runtime PM related messages */
+ unsigned no_vpd_size:1; /* No VPD size reported in header */
+
+ unsigned int queue_stopped; /* request queue is quiesced */
+ bool offline_already; /* Device offline message logged */
+
+ atomic_t disk_events_disable_depth; /* disable depth for disk events */
+
+ DECLARE_BITMAP(supported_events, SDEV_EVT_MAXBITS); /* supported events */
+ DECLARE_BITMAP(pending_events, SDEV_EVT_MAXBITS); /* pending events */
+ struct list_head event_list; /* asserted events */
+ struct work_struct event_work;
+
+ unsigned int max_device_blocked; /* what device_blocked counts down from */
+#define SCSI_DEFAULT_DEVICE_BLOCKED 3
+
+ atomic_t iorequest_cnt;
+ atomic_t iodone_cnt;
+ atomic_t ioerr_cnt;
+ atomic_t iotmo_cnt;
+
+ struct device sdev_gendev,
+ sdev_dev;
+
+ struct execute_work ew; /* used to get process context on put */
+ struct work_struct requeue_work;
+
+ struct scsi_device_handler *handler;
+ void *handler_data;
+
+ size_t dma_drain_len;
+ void *dma_drain_buf;
+
+ unsigned int sg_timeout;
+ unsigned int sg_reserved_size;
+
+ struct bsg_device *bsg_dev;
+ unsigned char access_state;
+ struct mutex state_mutex;
+ enum scsi_device_state sdev_state;
+ struct task_struct *quiesced_by;
+ unsigned long sdev_data[];
+} __attribute__((aligned(sizeof(unsigned long))));
+
+#define to_scsi_device(d) \
+ container_of(d, struct scsi_device, sdev_gendev)
+#define class_to_sdev(d) \
+ container_of(d, struct scsi_device, sdev_dev)
+#define transport_class_to_sdev(class_dev) \
+ to_scsi_device(class_dev->parent)
+
+#define sdev_dbg(sdev, fmt, a...) \
+ dev_dbg(&(sdev)->sdev_gendev, fmt, ##a)
+
+/*
+ * like scmd_printk, but the device name is passed in
+ * as a string pointer
+ */
+__printf(4, 5) void
+sdev_prefix_printk(const char *, const struct scsi_device *, const char *,
+ const char *, ...);
+
+#define sdev_printk(l, sdev, fmt, a...) \
+ sdev_prefix_printk(l, sdev, NULL, fmt, ##a)
+
+__printf(3, 4) void
+scmd_printk(const char *, const struct scsi_cmnd *, const char *, ...);
+
+#define scmd_dbg(scmd, fmt, a...) \
+ do { \
+ struct request *__rq = scsi_cmd_to_rq((scmd)); \
+ \
+ if (__rq->q->disk) \
+ sdev_dbg((scmd)->device, "[%s] " fmt, \
+ __rq->q->disk->disk_name, ##a); \
+ else \
+ sdev_dbg((scmd)->device, fmt, ##a); \
+ } while (0)
+
+enum scsi_target_state {
+ STARGET_CREATED = 1,
+ STARGET_RUNNING,
+ STARGET_REMOVE,
+ STARGET_CREATED_REMOVE,
+ STARGET_DEL,
+};
+
+/*
+ * scsi_target: representation of a scsi target, for now, this is only
+ * used for single_lun devices. If no one has active IO to the target,
+ * starget_sdev_user is NULL, else it points to the active sdev.
+ */
+struct scsi_target {
+ struct scsi_device *starget_sdev_user;
+ struct list_head siblings;
+ struct list_head devices;
+ struct device dev;
+ struct kref reap_ref; /* last put renders target invisible */
+ unsigned int channel;
+ unsigned int id; /* target id ... replace
+ * scsi_device.id eventually */
+ unsigned int create:1; /* signal that it needs to be added */
+ unsigned int single_lun:1; /* Indicates we should only
+ * allow I/O to one of the luns
+ * for the device at a time. */
+ unsigned int pdt_1f_for_no_lun:1; /* PDT = 0x1f
+ * means no lun present. */
+ unsigned int no_report_luns:1; /* Don't use
+ * REPORT LUNS for scanning. */
+ unsigned int expecting_lun_change:1; /* A device has reported
+ * a 3F/0E UA, other devices on
+ * the same target will also. */
+ /* commands actually active on LLD. */
+ atomic_t target_busy;
+ atomic_t target_blocked;
+
+ /*
+ * LLDs should set this in the slave_alloc host template callout.
+ * If set to zero then there is not limit.
+ */
+ unsigned int can_queue;
+ unsigned int max_target_blocked;
+#define SCSI_DEFAULT_TARGET_BLOCKED 3
+
+ char scsi_level;
+ enum scsi_target_state state;
+ void *hostdata; /* available to low-level driver */
+ unsigned long starget_data[]; /* for the transport */
+ /* starget_data must be the last element!!!! */
+} __attribute__((aligned(sizeof(unsigned long))));
+
+#define to_scsi_target(d) container_of(d, struct scsi_target, dev)
+static inline struct scsi_target *scsi_target(struct scsi_device *sdev)
+{
+ return to_scsi_target(sdev->sdev_gendev.parent);
+}
+#define transport_class_to_starget(class_dev) \
+ to_scsi_target(class_dev->parent)
+
+#define starget_printk(prefix, starget, fmt, a...) \
+ dev_printk(prefix, &(starget)->dev, fmt, ##a)
+
+extern struct scsi_device *__scsi_add_device(struct Scsi_Host *,
+ uint, uint, u64, void *hostdata);
+extern int scsi_add_device(struct Scsi_Host *host, uint channel,
+ uint target, u64 lun);
+extern int scsi_register_device_handler(struct scsi_device_handler *scsi_dh);
+extern void scsi_remove_device(struct scsi_device *);
+extern int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh);
+void scsi_attach_vpd(struct scsi_device *sdev);
+
+extern struct scsi_device *scsi_device_from_queue(struct request_queue *q);
+extern int __must_check scsi_device_get(struct scsi_device *);
+extern void scsi_device_put(struct scsi_device *);
+extern struct scsi_device *scsi_device_lookup(struct Scsi_Host *,
+ uint, uint, u64);
+extern struct scsi_device *__scsi_device_lookup(struct Scsi_Host *,
+ uint, uint, u64);
+extern struct scsi_device *scsi_device_lookup_by_target(struct scsi_target *,
+ u64);
+extern struct scsi_device *__scsi_device_lookup_by_target(struct scsi_target *,
+ u64);
+extern void starget_for_each_device(struct scsi_target *, void *,
+ void (*fn)(struct scsi_device *, void *));
+extern void __starget_for_each_device(struct scsi_target *, void *,
+ void (*fn)(struct scsi_device *,
+ void *));
+
+/* only exposed to implement shost_for_each_device */
+extern struct scsi_device *__scsi_iterate_devices(struct Scsi_Host *,
+ struct scsi_device *);
+
+/**
+ * shost_for_each_device - iterate over all devices of a host
+ * @sdev: the &struct scsi_device to use as a cursor
+ * @shost: the &struct scsi_host to iterate over
+ *
+ * Iterator that returns each device attached to @shost. This loop
+ * takes a reference on each device and releases it at the end. If
+ * you break out of the loop, you must call scsi_device_put(sdev).
+ */
+#define shost_for_each_device(sdev, shost) \
+ for ((sdev) = __scsi_iterate_devices((shost), NULL); \
+ (sdev); \
+ (sdev) = __scsi_iterate_devices((shost), (sdev)))
+
+/**
+ * __shost_for_each_device - iterate over all devices of a host (UNLOCKED)
+ * @sdev: the &struct scsi_device to use as a cursor
+ * @shost: the &struct scsi_host to iterate over
+ *
+ * Iterator that returns each device attached to @shost. It does _not_
+ * take a reference on the scsi_device, so the whole loop must be
+ * protected by shost->host_lock.
+ *
+ * Note: The only reason to use this is because you need to access the
+ * device list in interrupt context. Otherwise you really want to use
+ * shost_for_each_device instead.
+ */
+#define __shost_for_each_device(sdev, shost) \
+ list_for_each_entry((sdev), &((shost)->__devices), siblings)
+
+extern int scsi_change_queue_depth(struct scsi_device *, int);
+extern int scsi_track_queue_full(struct scsi_device *, int);
+
+extern int scsi_set_medium_removal(struct scsi_device *, char);
+
+extern int scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
+ unsigned char *buffer, int len, int timeout,
+ int retries, struct scsi_mode_data *data,
+ struct scsi_sense_hdr *);
+extern int scsi_mode_select(struct scsi_device *sdev, int pf, int sp,
+ unsigned char *buffer, int len, int timeout,
+ int retries, struct scsi_mode_data *data,
+ struct scsi_sense_hdr *);
+extern int scsi_test_unit_ready(struct scsi_device *sdev, int timeout,
+ int retries, struct scsi_sense_hdr *sshdr);
+extern int scsi_get_vpd_page(struct scsi_device *, u8 page, unsigned char *buf,
+ int buf_len);
+extern int scsi_report_opcode(struct scsi_device *sdev, unsigned char *buffer,
+ unsigned int len, unsigned char opcode);
+extern int scsi_device_set_state(struct scsi_device *sdev,
+ enum scsi_device_state state);
+extern struct scsi_event *sdev_evt_alloc(enum scsi_device_event evt_type,
+ gfp_t gfpflags);
+extern void sdev_evt_send(struct scsi_device *sdev, struct scsi_event *evt);
+extern void sdev_evt_send_simple(struct scsi_device *sdev,
+ enum scsi_device_event evt_type, gfp_t gfpflags);
+extern int scsi_device_quiesce(struct scsi_device *sdev);
+extern void scsi_device_resume(struct scsi_device *sdev);
+extern void scsi_target_quiesce(struct scsi_target *);
+extern void scsi_target_resume(struct scsi_target *);
+extern void scsi_scan_target(struct device *parent, unsigned int channel,
+ unsigned int id, u64 lun,
+ enum scsi_scan_mode rescan);
+extern void scsi_target_reap(struct scsi_target *);
+extern void scsi_target_block(struct device *);
+extern void scsi_target_unblock(struct device *, enum scsi_device_state);
+extern void scsi_remove_target(struct device *);
+extern 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 void scsi_sanitize_inquiry_string(unsigned char *s, int len);
+extern int __scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
+ int data_direction, void *buffer, unsigned bufflen,
+ unsigned char *sense, struct scsi_sense_hdr *sshdr,
+ int timeout, int retries, blk_opf_t flags,
+ req_flags_t rq_flags, int *resid);
+/* Make sure any sense buffer is the correct size. */
+#define scsi_execute(sdev, cmd, data_direction, buffer, bufflen, sense, \
+ sshdr, timeout, retries, flags, rq_flags, resid) \
+({ \
+ BUILD_BUG_ON((sense) != NULL && \
+ sizeof(sense) != SCSI_SENSE_BUFFERSIZE); \
+ __scsi_execute(sdev, cmd, data_direction, buffer, bufflen, \
+ sense, sshdr, timeout, retries, flags, rq_flags, \
+ resid); \
+})
+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(sdev, cmd, data_direction, buffer,
+ bufflen, NULL, sshdr, timeout, retries, 0, 0, resid);
+}
+extern void sdev_disable_disk_events(struct scsi_device *sdev);
+extern void sdev_enable_disk_events(struct scsi_device *sdev);
+extern int scsi_vpd_lun_id(struct scsi_device *, char *, size_t);
+extern int scsi_vpd_tpg_id(struct scsi_device *, int *);
+
+#ifdef CONFIG_PM
+extern int scsi_autopm_get_device(struct scsi_device *);
+extern void scsi_autopm_put_device(struct scsi_device *);
+#else
+static inline int scsi_autopm_get_device(struct scsi_device *d) { return 0; }
+static inline void scsi_autopm_put_device(struct scsi_device *d) {}
+#endif /* CONFIG_PM */
+
+static inline int __must_check scsi_device_reprobe(struct scsi_device *sdev)
+{
+ return device_reprobe(&sdev->sdev_gendev);
+}
+
+static inline unsigned int sdev_channel(struct scsi_device *sdev)
+{
+ return sdev->channel;
+}
+
+static inline unsigned int sdev_id(struct scsi_device *sdev)
+{
+ return sdev->id;
+}
+
+#define scmd_id(scmd) sdev_id((scmd)->device)
+#define scmd_channel(scmd) sdev_channel((scmd)->device)
+
+/*
+ * checks for positions of the SCSI state machine
+ */
+static inline int scsi_device_online(struct scsi_device *sdev)
+{
+ return (sdev->sdev_state != SDEV_OFFLINE &&
+ sdev->sdev_state != SDEV_TRANSPORT_OFFLINE &&
+ sdev->sdev_state != SDEV_DEL);
+}
+static inline int scsi_device_blocked(struct scsi_device *sdev)
+{
+ return sdev->sdev_state == SDEV_BLOCK ||
+ sdev->sdev_state == SDEV_CREATED_BLOCK;
+}
+static inline int scsi_device_created(struct scsi_device *sdev)
+{
+ return sdev->sdev_state == SDEV_CREATED ||
+ sdev->sdev_state == SDEV_CREATED_BLOCK;
+}
+
+int scsi_internal_device_block_nowait(struct scsi_device *sdev);
+int scsi_internal_device_unblock_nowait(struct scsi_device *sdev,
+ enum scsi_device_state new_state);
+
+/* accessor functions for the SCSI parameters */
+static inline int scsi_device_sync(struct scsi_device *sdev)
+{
+ return sdev->sdtr;
+}
+static inline int scsi_device_wide(struct scsi_device *sdev)
+{
+ return sdev->wdtr;
+}
+static inline int scsi_device_dt(struct scsi_device *sdev)
+{
+ return sdev->ppr;
+}
+static inline int scsi_device_dt_only(struct scsi_device *sdev)
+{
+ if (sdev->inquiry_len < 57)
+ return 0;
+ return (sdev->inquiry[56] & 0x0c) == 0x04;
+}
+static inline int scsi_device_ius(struct scsi_device *sdev)
+{
+ if (sdev->inquiry_len < 57)
+ return 0;
+ return sdev->inquiry[56] & 0x01;
+}
+static inline int scsi_device_qas(struct scsi_device *sdev)
+{
+ if (sdev->inquiry_len < 57)
+ return 0;
+ return sdev->inquiry[56] & 0x02;
+}
+static inline int scsi_device_enclosure(struct scsi_device *sdev)
+{
+ return sdev->inquiry ? (sdev->inquiry[6] & (1<<6)) : 1;
+}
+
+static inline int scsi_device_protection(struct scsi_device *sdev)
+{
+ if (sdev->no_dif)
+ return 0;
+
+ return sdev->scsi_level > SCSI_2 && sdev->inquiry[5] & (1<<0);
+}
+
+static inline int scsi_device_tpgs(struct scsi_device *sdev)
+{
+ return sdev->inquiry ? (sdev->inquiry[5] >> 4) & 0x3 : 0;
+}
+
+/**
+ * scsi_device_supports_vpd - test if a device supports VPD pages
+ * @sdev: the &struct scsi_device to test
+ *
+ * If the 'try_vpd_pages' flag is set it takes precedence.
+ * Otherwise we will assume VPD pages are supported if the
+ * SCSI level is at least SPC-3 and 'skip_vpd_pages' is not set.
+ */
+static inline int scsi_device_supports_vpd(struct scsi_device *sdev)
+{
+ /* Attempt VPD inquiry if the device blacklist explicitly calls
+ * for it.
+ */
+ if (sdev->try_vpd_pages)
+ return 1;
+ /*
+ * Although VPD inquiries can go to SCSI-2 type devices,
+ * some USB ones crash on receiving them, and the pages
+ * we currently ask for are mandatory for SPC-2 and beyond
+ */
+ if (sdev->scsi_level >= SCSI_SPC_2 && !sdev->skip_vpd_pages)
+ return 1;
+ return 0;
+}
+
+static inline int scsi_device_busy(struct scsi_device *sdev)
+{
+ return sbitmap_weight(&sdev->budget_map);
+}
+
+#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
new file mode 100644
index 000000000..6b548dc2c
--- /dev/null
+++ b/include/scsi/scsi_devinfo.h
@@ -0,0 +1,85 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _SCSI_SCSI_DEVINFO_H
+#define _SCSI_SCSI_DEVINFO_H
+/*
+ * Flags for SCSI devices that need special treatment
+ */
+
+/* Only scan LUN 0 */
+#define BLIST_NOLUN ((__force blist_flags_t)(1ULL << 0))
+/* Known to have LUNs, force scanning.
+ * DEPRECATED: Use max_luns=N */
+#define BLIST_FORCELUN ((__force blist_flags_t)(1ULL << 1))
+/* Flag for broken handshaking */
+#define BLIST_BORKEN ((__force blist_flags_t)(1ULL << 2))
+/* unlock by special command */
+#define BLIST_KEY ((__force blist_flags_t)(1ULL << 3))
+/* Do not use LUNs in parallel */
+#define BLIST_SINGLELUN ((__force blist_flags_t)(1ULL << 4))
+/* Buggy Tagged Command Queuing */
+#define BLIST_NOTQ ((__force blist_flags_t)(1ULL << 5))
+/* Non consecutive LUN numbering */
+#define BLIST_SPARSELUN ((__force blist_flags_t)(1ULL << 6))
+/* Avoid LUNS >= 5 */
+#define BLIST_MAX5LUN ((__force blist_flags_t)(1ULL << 7))
+/* Treat as (removable) CD-ROM */
+#define BLIST_ISROM ((__force blist_flags_t)(1ULL << 8))
+/* LUNs past 7 on a SCSI-2 device */
+#define BLIST_LARGELUN ((__force blist_flags_t)(1ULL << 9))
+/* override additional length field */
+#define BLIST_INQUIRY_36 ((__force blist_flags_t)(1ULL << 10))
+/* ignore MEDIA CHANGE unit attention after resuming from runtime suspend */
+#define BLIST_IGN_MEDIA_CHANGE ((__force blist_flags_t)(1ULL << 11))
+/* do not do automatic start on add */
+#define BLIST_NOSTARTONADD ((__force blist_flags_t)(1ULL << 12))
+/* do not ask for VPD page size first on some broken targets */
+#define BLIST_NO_VPD_SIZE ((__force blist_flags_t)(1ULL << 13))
+#define __BLIST_UNUSED_14 ((__force blist_flags_t)(1ULL << 14))
+#define __BLIST_UNUSED_15 ((__force blist_flags_t)(1ULL << 15))
+#define __BLIST_UNUSED_16 ((__force blist_flags_t)(1ULL << 16))
+/* try REPORT_LUNS even for SCSI-2 devs (if HBA supports more than 8 LUNs) */
+#define BLIST_REPORTLUN2 ((__force blist_flags_t)(1ULL << 17))
+/* don't try REPORT_LUNS scan (SCSI-3 devs) */
+#define BLIST_NOREPORTLUN ((__force blist_flags_t)(1ULL << 18))
+/* don't use PREVENT-ALLOW commands */
+#define BLIST_NOT_LOCKABLE ((__force blist_flags_t)(1ULL << 19))
+/* device is actually for RAID config */
+#define BLIST_NO_ULD_ATTACH ((__force blist_flags_t)(1ULL << 20))
+/* select without ATN */
+#define BLIST_SELECT_NO_ATN ((__force blist_flags_t)(1ULL << 21))
+/* retry HARDWARE_ERROR */
+#define BLIST_RETRY_HWERROR ((__force blist_flags_t)(1ULL << 22))
+/* maximum 512 sector cdb length */
+#define BLIST_MAX_512 ((__force blist_flags_t)(1ULL << 23))
+#define __BLIST_UNUSED_24 ((__force blist_flags_t)(1ULL << 24))
+/* Disable T10 PI (DIF) */
+#define BLIST_NO_DIF ((__force blist_flags_t)(1ULL << 25))
+/* Ignore SBC-3 VPD pages */
+#define BLIST_SKIP_VPD_PAGES ((__force blist_flags_t)(1ULL << 26))
+#define __BLIST_UNUSED_27 ((__force blist_flags_t)(1ULL << 27))
+/* Attempt to read VPD pages */
+#define BLIST_TRY_VPD_PAGES ((__force blist_flags_t)(1ULL << 28))
+/* don't try to issue RSOC */
+#define BLIST_NO_RSOC ((__force blist_flags_t)(1ULL << 29))
+/* maximum 1024 sector cdb length */
+#define BLIST_MAX_1024 ((__force blist_flags_t)(1ULL << 30))
+/* Use UNMAP limit for WRITE SAME */
+#define BLIST_UNMAP_LIMIT_WS ((__force blist_flags_t)(1ULL << 31))
+/* Always retry ABORTED_COMMAND with Internal Target Failure */
+#define BLIST_RETRY_ITF ((__force blist_flags_t)(1ULL << 32))
+/* Always retry ABORTED_COMMAND with ASC 0xc1 */
+#define BLIST_RETRY_ASC_C1 ((__force blist_flags_t)(1ULL << 33))
+
+#define __BLIST_LAST_USED BLIST_RETRY_ASC_C1
+
+#define __BLIST_HIGH_UNUSED (~(__BLIST_LAST_USED | \
+ (__force blist_flags_t) \
+ ((__force __u64)__BLIST_LAST_USED - 1ULL)))
+#define __BLIST_UNUSED_MASK (__BLIST_UNUSED_14 | \
+ __BLIST_UNUSED_15 | \
+ __BLIST_UNUSED_16 | \
+ __BLIST_UNUSED_24 | \
+ __BLIST_UNUSED_27 | \
+ __BLIST_HIGH_UNUSED)
+
+#endif
diff --git a/include/scsi/scsi_dh.h b/include/scsi/scsi_dh.h
new file mode 100644
index 000000000..4df943c1b
--- /dev/null
+++ b/include/scsi/scsi_dh.h
@@ -0,0 +1,90 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Header file for SCSI device handler infrastructure.
+ *
+ * Modified version of patches posted by Mike Christie <michaelc@cs.wisc.edu>
+ *
+ * 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_NOMEM,
+ SCSI_DH_NOSYS,
+ SCSI_DH_DRIVER_MAX,
+};
+
+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;
+ enum scsi_disposition (*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 *);
+ blk_status_t (*prep_fn)(struct scsi_device *, struct request *);
+ int (*set_params)(struct scsi_device *, const char *);
+ void (*rescan)(struct scsi_device *);
+};
+
+#ifdef CONFIG_SCSI_DH
+extern int scsi_dh_activate(struct request_queue *, activate_complete, void *);
+extern int scsi_dh_attach(struct request_queue *, const char *);
+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_attach(struct request_queue *req, const char *name)
+{
+ return SCSI_DH_NOSYS;
+}
+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
new file mode 100644
index 000000000..4ce1988b2
--- /dev/null
+++ b/include/scsi/scsi_driver.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _SCSI_SCSI_DRIVER_H
+#define _SCSI_SCSI_DRIVER_H
+
+#include <linux/blk_types.h>
+#include <linux/device.h>
+#include <scsi/scsi_cmnd.h>
+
+struct module;
+struct request;
+
+struct scsi_driver {
+ struct device_driver gendrv;
+
+ void (*rescan)(struct device *);
+ blk_status_t (*init_command)(struct scsi_cmnd *);
+ void (*uninit_command)(struct scsi_cmnd *);
+ int (*done)(struct scsi_cmnd *);
+ int (*eh_action)(struct scsi_cmnd *, int);
+ void (*eh_reset)(struct scsi_cmnd *);
+};
+#define to_scsi_driver(drv) \
+ container_of((drv), struct scsi_driver, gendrv)
+
+extern int scsi_register_driver(struct device_driver *);
+#define scsi_unregister_driver(drv) \
+ driver_unregister(drv);
+
+extern int scsi_register_interface(struct class_interface *);
+#define scsi_unregister_interface(intf) \
+ class_interface_unregister(intf)
+
+/* make sure not to use it with passthrough commands */
+static inline struct scsi_driver *scsi_cmd_to_driver(struct scsi_cmnd *cmd)
+{
+ return to_scsi_driver(cmd->device->sdev_gendev.driver);
+}
+
+#endif /* _SCSI_SCSI_DRIVER_H */
diff --git a/include/scsi/scsi_eh.h b/include/scsi/scsi_eh.h
new file mode 100644
index 000000000..1ae08e813
--- /dev/null
+++ b/include/scsi/scsi_eh.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _SCSI_SCSI_EH_H
+#define _SCSI_SCSI_EH_H
+
+#include <linux/scatterlist.h>
+
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_common.h>
+struct scsi_device;
+struct Scsi_Host;
+
+extern void scsi_eh_finish_cmd(struct scsi_cmnd *scmd,
+ struct list_head *done_q);
+extern void scsi_eh_flush_done_q(struct list_head *done_q);
+extern void scsi_report_bus_reset(struct Scsi_Host *, int);
+extern void scsi_report_device_reset(struct Scsi_Host *, int, int);
+extern int scsi_block_when_processing_errors(struct scsi_device *);
+extern bool scsi_command_normalize_sense(const struct scsi_cmnd *cmd,
+ struct scsi_sense_hdr *sshdr);
+extern enum scsi_disposition scsi_check_sense(struct scsi_cmnd *);
+
+static inline bool scsi_sense_is_deferred(const struct scsi_sense_hdr *sshdr)
+{
+ return ((sshdr->response_code >= 0x70) && (sshdr->response_code & 1));
+}
+
+extern bool scsi_get_sense_info_fld(const u8 *sense_buffer, int sb_len,
+ u64 *info_out);
+
+extern int scsi_ioctl_reset(struct scsi_device *, int __user *);
+
+struct scsi_eh_save {
+ /* saved state */
+ int result;
+ unsigned int resid_len;
+ int eh_eflags;
+ enum dma_data_direction data_direction;
+ unsigned underflow;
+ unsigned char cmd_len;
+ unsigned char prot_op;
+ unsigned char cmnd[32];
+ struct scsi_data_buffer sdb;
+ 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
new file mode 100644
index 000000000..71def41b1
--- /dev/null
+++ b/include/scsi/scsi_host.h
@@ -0,0 +1,889 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _SCSI_SCSI_HOST_H
+#define _SCSI_SCSI_HOST_H
+
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+#include <linux/seq_file.h>
+#include <linux/blk-mq.h>
+#include <scsi/scsi.h>
+
+struct block_device;
+struct completion;
+struct module;
+struct scsi_cmnd;
+struct scsi_device;
+struct scsi_target;
+struct Scsi_Host;
+struct scsi_transport_template;
+
+
+#define SG_ALL SG_CHUNK_SIZE
+
+#define MODE_UNKNOWN 0x00
+#define MODE_INITIATOR 0x01
+#define MODE_TARGET 0x02
+
+struct scsi_host_template {
+ /*
+ * Put fields referenced in IO submission path together in
+ * same cacheline
+ */
+
+ /*
+ * Additional per-command data allocated for the driver.
+ */
+ unsigned int cmd_size;
+
+ /*
+ * The queuecommand function is used to queue up a scsi
+ * command block to the LLDD. When the driver finished
+ * processing the command the done callback is invoked.
+ *
+ * If queuecommand returns 0, then the driver has accepted the
+ * command. It must also push it to the HBA if the scsi_cmnd
+ * flag SCMD_LAST is set, or if the driver does not implement
+ * commit_rqs. The done() function must be called on the command
+ * when the driver has finished with it. (you may call done on the
+ * command before queuecommand returns, but in this case you
+ * *must* return 0 from queuecommand).
+ *
+ * Queuecommand may also reject the command, in which case it may
+ * not touch the command and must not call done() for it.
+ *
+ * There are two possible rejection returns:
+ *
+ * SCSI_MLQUEUE_DEVICE_BUSY: Block this device temporarily, but
+ * allow commands to other devices serviced by this host.
+ *
+ * SCSI_MLQUEUE_HOST_BUSY: Block all devices served by this
+ * host temporarily.
+ *
+ * For compatibility, any other non-zero return is treated the
+ * same as SCSI_MLQUEUE_HOST_BUSY.
+ *
+ * NOTE: "temporarily" means either until the next command for#
+ * this device/host completes, or a period of time determined by
+ * I/O pressure in the system if there are no other outstanding
+ * commands.
+ *
+ * STATUS: REQUIRED
+ */
+ int (* queuecommand)(struct Scsi_Host *, struct scsi_cmnd *);
+
+ /*
+ * The commit_rqs function is used to trigger a hardware
+ * doorbell after some requests have been queued with
+ * queuecommand, when an error is encountered before sending
+ * the request with SCMD_LAST set.
+ *
+ * STATUS: OPTIONAL
+ */
+ void (*commit_rqs)(struct Scsi_Host *, u16);
+
+ struct module *module;
+ const char *name;
+
+ /*
+ * The info function will return whatever useful information the
+ * developer sees fit. If not provided, then the name field will
+ * be used instead.
+ *
+ * Status: OPTIONAL
+ */
+ const char *(*info)(struct Scsi_Host *);
+
+ /*
+ * Ioctl interface
+ *
+ * Status: OPTIONAL
+ */
+ int (*ioctl)(struct scsi_device *dev, unsigned int cmd,
+ void __user *arg);
+
+
+#ifdef CONFIG_COMPAT
+ /*
+ * Compat handler. Handle 32bit ABI.
+ * When unknown ioctl is passed return -ENOIOCTLCMD.
+ *
+ * Status: OPTIONAL
+ */
+ int (*compat_ioctl)(struct scsi_device *dev, unsigned int cmd,
+ void __user *arg);
+#endif
+
+ int (*init_cmd_priv)(struct Scsi_Host *shost, struct scsi_cmnd *cmd);
+ int (*exit_cmd_priv)(struct Scsi_Host *shost, struct scsi_cmnd *cmd);
+
+ /*
+ * This is an error handling strategy routine. You don't need to
+ * define one of these if you don't want to - there is a default
+ * routine that is present that should work in most cases. For those
+ * driver authors that have the inclination and ability to write their
+ * own strategy routine, this is where it is specified. Note - the
+ * strategy routine is *ALWAYS* run in the context of the kernel eh
+ * thread. Thus you are guaranteed to *NOT* be in an interrupt
+ * handler when you execute this, and you are also guaranteed to
+ * *NOT* have any other commands being queued while you are in the
+ * strategy routine. When you return from this function, operations
+ * return to normal.
+ *
+ * See scsi_error.c scsi_unjam_host for additional comments about
+ * what this function should and should not be attempting to do.
+ *
+ * Status: REQUIRED (at least one of them)
+ */
+ int (* eh_abort_handler)(struct scsi_cmnd *);
+ int (* eh_device_reset_handler)(struct scsi_cmnd *);
+ int (* eh_target_reset_handler)(struct scsi_cmnd *);
+ int (* eh_bus_reset_handler)(struct scsi_cmnd *);
+ int (* eh_host_reset_handler)(struct scsi_cmnd *);
+
+ /*
+ * Before the mid layer attempts to scan for a new device where none
+ * currently exists, it will call this entry in your driver. Should
+ * your driver need to allocate any structs or perform any other init
+ * items in order to send commands to a currently unused target/lun
+ * combo, then this is where you can perform those allocations. This
+ * is specifically so that drivers won't have to perform any kind of
+ * "is this a new device" checks in their queuecommand routine,
+ * thereby making the hot path a bit quicker.
+ *
+ * Return values: 0 on success, non-0 on failure
+ *
+ * Deallocation: If we didn't find any devices at this ID, you will
+ * get an immediate call to slave_destroy(). If we find something
+ * here then you will get a call to slave_configure(), then the
+ * device will be used for however long it is kept around, then when
+ * the device is removed from the system (or * possibly at reboot
+ * time), you will then get a call to slave_destroy(). This is
+ * assuming you implement slave_configure and slave_destroy.
+ * However, if you allocate memory and hang it off the device struct,
+ * then you must implement the slave_destroy() routine at a minimum
+ * in order to avoid leaking memory
+ * each time a device is tore down.
+ *
+ * Status: OPTIONAL
+ */
+ int (* slave_alloc)(struct scsi_device *);
+
+ /*
+ * Once the device has responded to an INQUIRY and we know the
+ * device is online, we call into the low level driver with the
+ * struct scsi_device *. If the low level device driver implements
+ * this function, it *must* perform the task of setting the queue
+ * depth on the device. All other tasks are optional and depend
+ * on what the driver supports and various implementation details.
+ *
+ * Things currently recommended to be handled at this time include:
+ *
+ * 1. Setting the device queue depth. Proper setting of this is
+ * described in the comments for scsi_change_queue_depth.
+ * 2. Determining if the device supports the various synchronous
+ * negotiation protocols. The device struct will already have
+ * responded to INQUIRY and the results of the standard items
+ * will have been shoved into the various device flag bits, eg.
+ * device->sdtr will be true if the device supports SDTR messages.
+ * 3. Allocating command structs that the device will need.
+ * 4. Setting the default timeout on this device (if needed).
+ * 5. Anything else the low level driver might want to do on a device
+ * specific setup basis...
+ * 6. Return 0 on success, non-0 on error. The device will be marked
+ * as offline on error so that no access will occur. If you return
+ * non-0, your slave_destroy routine will never get called for this
+ * device, so don't leave any loose memory hanging around, clean
+ * up after yourself before returning non-0
+ *
+ * Status: OPTIONAL
+ */
+ int (* slave_configure)(struct scsi_device *);
+
+ /*
+ * Immediately prior to deallocating the device and after all activity
+ * has ceased the mid layer calls this point so that the low level
+ * driver may completely detach itself from the scsi device and vice
+ * versa. The low level driver is responsible for freeing any memory
+ * it allocated in the slave_alloc or slave_configure calls.
+ *
+ * Status: OPTIONAL
+ */
+ void (* slave_destroy)(struct scsi_device *);
+
+ /*
+ * Before the mid layer attempts to scan for a new device attached
+ * to a target where no target currently exists, it will call this
+ * entry in your driver. Should your driver need to allocate any
+ * structs or perform any other init items in order to send commands
+ * to a currently unused target, then this is where you can perform
+ * those allocations.
+ *
+ * Return values: 0 on success, non-0 on failure
+ *
+ * Status: OPTIONAL
+ */
+ int (* target_alloc)(struct scsi_target *);
+
+ /*
+ * Immediately prior to deallocating the target structure, and
+ * after all activity to attached scsi devices has ceased, the
+ * midlayer calls this point so that the driver may deallocate
+ * and terminate any references to the target.
+ *
+ * Status: OPTIONAL
+ */
+ void (* target_destroy)(struct scsi_target *);
+
+ /*
+ * If a host has the ability to discover targets on its own instead
+ * of scanning the entire bus, it can fill in this function and
+ * call scsi_scan_host(). This function will be called periodically
+ * until it returns 1 with the scsi_host and the elapsed time of
+ * the scan in jiffies.
+ *
+ * Status: OPTIONAL
+ */
+ int (* scan_finished)(struct Scsi_Host *, unsigned long);
+
+ /*
+ * If the host wants to be called before the scan starts, but
+ * after the midlayer has set up ready for the scan, it can fill
+ * in this function.
+ *
+ * Status: OPTIONAL
+ */
+ void (* scan_start)(struct Scsi_Host *);
+
+ /*
+ * Fill in this function to allow the queue depth of this host
+ * to be changeable (on a per device basis). Returns either
+ * the current queue depth setting (may be different from what
+ * was passed in) or an error. An error should only be
+ * returned if the requested depth is legal but the driver was
+ * unable to set it. If the requested depth is illegal, the
+ * driver should set and return the closest legal queue depth.
+ *
+ * Status: OPTIONAL
+ */
+ int (* change_queue_depth)(struct scsi_device *, int);
+
+ /*
+ * This functions lets the driver expose the queue mapping
+ * to the block layer.
+ *
+ * Status: OPTIONAL
+ */
+ void (* map_queues)(struct Scsi_Host *shost);
+
+ /*
+ * SCSI interface of blk_poll - poll for IO completions.
+ * Only applicable if SCSI LLD exposes multiple h/w queues.
+ *
+ * Return value: Number of completed entries found.
+ *
+ * Status: OPTIONAL
+ */
+ int (* mq_poll)(struct Scsi_Host *shost, unsigned int queue_num);
+
+ /*
+ * Check if scatterlists need to be padded for DMA draining.
+ *
+ * Status: OPTIONAL
+ */
+ bool (* dma_need_drain)(struct request *rq);
+
+ /*
+ * This function determines the BIOS parameters for a given
+ * harddisk. These tend to be numbers that are made up by
+ * the host adapter. Parameters:
+ * size, device, list (heads, sectors, cylinders)
+ *
+ * Status: OPTIONAL
+ */
+ int (* bios_param)(struct scsi_device *, struct block_device *,
+ sector_t, int []);
+
+ /*
+ * This function is called when one or more partitions on the
+ * device reach beyond the end of the device.
+ *
+ * Status: OPTIONAL
+ */
+ void (*unlock_native_capacity)(struct scsi_device *);
+
+ /*
+ * Can be used to export driver statistics and other infos to the
+ * world outside the kernel ie. userspace and it also provides an
+ * interface to feed the driver with information.
+ *
+ * Status: OBSOLETE
+ */
+ int (*show_info)(struct seq_file *, struct Scsi_Host *);
+ int (*write_info)(struct Scsi_Host *, char *, int);
+
+ /*
+ * This is an optional routine that allows the transport to become
+ * involved when a scsi io timer fires. The return value tells the
+ * timer routine how to finish the io timeout handling.
+ *
+ * Status: OPTIONAL
+ */
+ enum blk_eh_timer_return (*eh_timed_out)(struct scsi_cmnd *);
+ /*
+ * Optional routine that allows the transport to decide if a cmd
+ * is retryable. Return true if the transport is in a state the
+ * cmd should be retried on.
+ */
+ bool (*eh_should_retry_cmd)(struct scsi_cmnd *scmd);
+
+ /* This is an optional routine that allows transport to initiate
+ * LLD adapter or firmware reset using sysfs attribute.
+ *
+ * Return values: 0 on success, -ve value on failure.
+ *
+ * Status: OPTIONAL
+ */
+
+ int (*host_reset)(struct Scsi_Host *shost, int reset_type);
+#define SCSI_ADAPTER_RESET 1
+#define SCSI_FIRMWARE_RESET 2
+
+
+ /*
+ * Name of proc directory
+ */
+ const char *proc_name;
+
+ /*
+ * Used to store the procfs directory if a driver implements the
+ * show_info method.
+ */
+ struct proc_dir_entry *proc_dir;
+
+ /*
+ * This determines if we will use a non-interrupt driven
+ * or an interrupt driven scheme. It is set to the maximum number
+ * of simultaneous commands a single hw queue in HBA will accept.
+ */
+ int can_queue;
+
+ /*
+ * In many instances, especially where disconnect / reconnect are
+ * supported, our host also has an ID on the SCSI bus. If this is
+ * the case, then it must be reserved. Please set this_id to -1 if
+ * your setup is in single initiator mode, and the host lacks an
+ * ID.
+ */
+ int this_id;
+
+ /*
+ * This determines the degree to which the host adapter is capable
+ * of scatter-gather.
+ */
+ unsigned short sg_tablesize;
+ unsigned short sg_prot_tablesize;
+
+ /*
+ * Set this if the host adapter has limitations beside segment count.
+ */
+ unsigned int max_sectors;
+
+ /*
+ * Maximum size in bytes of a single segment.
+ */
+ unsigned int max_segment_size;
+
+ /*
+ * DMA scatter gather segment boundary limit. A segment crossing this
+ * boundary will be split in two.
+ */
+ unsigned long dma_boundary;
+
+ unsigned long virt_boundary_mask;
+
+ /*
+ * This specifies "machine infinity" for host templates which don't
+ * limit the transfer size. Note this limit represents an absolute
+ * maximum, and may be over the transfer limits allowed for
+ * individual devices (e.g. 256 for SCSI-1).
+ */
+#define SCSI_DEFAULT_MAX_SECTORS 1024
+
+ /*
+ * True if this host adapter can make good use of linked commands.
+ * This will allow more than one command to be queued to a given
+ * unit on a given host. Set this to the maximum number of command
+ * blocks to be provided for each device. Set this to 1 for one
+ * command block per lun, 2 for two, etc. Do not set this to 0.
+ * You should make sure that the host adapter will do the right thing
+ * before you try setting this above 1.
+ */
+ short cmd_per_lun;
+
+ /*
+ * present contains counter indicating how many boards of this
+ * type were found when we did the scan.
+ */
+ unsigned char present;
+
+ /* If use block layer to manage tags, this is tag allocation policy */
+ int tag_alloc_policy;
+
+ /*
+ * Track QUEUE_FULL events and reduce queue depth on demand.
+ */
+ unsigned track_queue_depth:1;
+
+ /*
+ * This specifies the mode that a LLD supports.
+ */
+ unsigned supported_mode:2;
+
+ /*
+ * True for emulated SCSI host adapters (e.g. ATAPI).
+ */
+ unsigned emulated:1;
+
+ /*
+ * True if the low-level driver performs its own reset-settle delays.
+ */
+ unsigned skip_settle_delay:1;
+
+ /* True if the controller does not support WRITE SAME */
+ unsigned no_write_same:1;
+
+ /* True if the host uses host-wide tagspace */
+ unsigned host_tagset:1;
+
+ /*
+ * Countdown for host blocking with no commands outstanding.
+ */
+ unsigned int max_host_blocked;
+
+ /*
+ * Default value for the blocking. If the queue is empty,
+ * host_blocked counts down in the request_fn until it restarts
+ * host operations as zero is reached.
+ *
+ * FIXME: This should probably be a value in the template
+ */
+#define SCSI_DEFAULT_HOST_BLOCKED 7
+
+ /*
+ * Pointer to the SCSI host sysfs attribute groups, NULL terminated.
+ */
+ const struct attribute_group **shost_groups;
+
+ /*
+ * Pointer to the SCSI device attribute groups for this host,
+ * NULL terminated.
+ */
+ const struct attribute_group **sdev_groups;
+
+ /*
+ * 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;
+
+ /* Delay for runtime autosuspend */
+ int rpm_autosuspend_delay;
+};
+
+/*
+ * 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); \
+ rc = func_name##_lck(cmd); \
+ spin_unlock_irqrestore(shost->host_lock, irq_flags); \
+ return rc; \
+ }
+
+
+/*
+ * shost state: If you alter this, you also need to alter scsi_sysfs.c
+ * (for the ascii descriptions) and the state model enforcer:
+ * scsi_host_set_state()
+ */
+enum scsi_host_state {
+ SHOST_CREATED = 1,
+ SHOST_RUNNING,
+ SHOST_CANCEL,
+ SHOST_DEL,
+ SHOST_RECOVERY,
+ SHOST_CANCEL_RECOVERY,
+ SHOST_DEL_RECOVERY,
+};
+
+struct Scsi_Host {
+ /*
+ * __devices is protected by the host_lock, but you should
+ * usually use scsi_device_lookup / shost_for_each_device
+ * to access it and don't care about locking yourself.
+ * In the rare case of being in irq context you can use
+ * their __ prefixed variants with the lock held. NEVER
+ * access this list directly from a driver.
+ */
+ struct list_head __devices;
+ struct list_head __targets;
+
+ struct list_head starved_list;
+
+ spinlock_t default_lock;
+ spinlock_t *host_lock;
+
+ struct mutex scan_mutex;/* serialize scanning activity */
+
+ struct list_head eh_abort_list;
+ struct list_head eh_cmd_q;
+ struct task_struct * ehandler; /* Error recovery thread. */
+ struct completion * eh_action; /* Wait for specific actions on the
+ host. */
+ wait_queue_head_t host_wait;
+ struct scsi_host_template *hostt;
+ struct scsi_transport_template *transportt;
+
+ struct kref tagset_refcnt;
+ struct completion tagset_freed;
+ /* Area to keep a shared tag map */
+ struct blk_mq_tag_set tag_set;
+
+ atomic_t host_blocked;
+
+ unsigned int host_failed; /* commands that failed.
+ protected by host_lock */
+ unsigned int host_eh_scheduled; /* EH scheduled without command */
+
+ unsigned int host_no; /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */
+
+ /* next two fields are used to bound the time spent in error handling */
+ int eh_deadline;
+ unsigned long last_reset;
+
+
+ /*
+ * These three parameters can be used to allow for wide scsi,
+ * and for host adapters that support multiple busses
+ * The last two should be set to 1 more than the actual max id
+ * or lun (e.g. 8 for SCSI parallel systems).
+ */
+ unsigned int max_channel;
+ unsigned int max_id;
+ u64 max_lun;
+
+ /*
+ * This is a unique identifier that must be assigned so that we
+ * have some way of identifying each detected host adapter properly
+ * and uniquely. For hosts that do not support more than one card
+ * in the system at one time, this does not need to be set. It is
+ * initialized to 0 in scsi_register.
+ */
+ unsigned int unique_id;
+
+ /*
+ * The maximum length of SCSI commands that this host can accept.
+ * Probably 12 for most host adapters, but could be 16 for others.
+ * or 260 if the driver supports variable length cdbs.
+ * For drivers that don't set this field, a value of 12 is
+ * assumed.
+ */
+ unsigned short max_cmd_len;
+
+ int this_id;
+ int can_queue;
+ short cmd_per_lun;
+ short unsigned int sg_tablesize;
+ short unsigned int sg_prot_tablesize;
+ unsigned int max_sectors;
+ unsigned int opt_sectors;
+ unsigned int max_segment_size;
+ unsigned long dma_boundary;
+ unsigned long virt_boundary_mask;
+ /*
+ * In scsi-mq mode, the number of hardware queues supported by the LLD.
+ *
+ * Note: it is assumed that each hardware queue has a queue depth of
+ * can_queue. In other words, the total queue depth per host
+ * is nr_hw_queues * can_queue. However, for when host_tagset is set,
+ * the total queue depth is can_queue.
+ */
+ unsigned nr_hw_queues;
+ unsigned nr_maps;
+ unsigned active_mode:2;
+
+ /*
+ * Host has requested that no further requests come through for the
+ * time being.
+ */
+ unsigned host_self_blocked:1;
+
+ /*
+ * Host uses correct SCSI ordering not PC ordering. The bit is
+ * set for the minority of drivers whose authors actually read
+ * the spec ;).
+ */
+ unsigned reverse_ordering:1;
+
+ /* Task mgmt function in progress */
+ unsigned tmf_in_progress:1;
+
+ /* Asynchronous scan in progress */
+ unsigned async_scan:1;
+
+ /* Don't resume host in EH */
+ unsigned eh_noresume:1;
+
+ /* The controller does not support WRITE SAME */
+ unsigned no_write_same:1;
+
+ /* True if the host uses host-wide tagspace */
+ unsigned host_tagset:1;
+
+ /* Host responded with short (<36 bytes) INQUIRY result */
+ unsigned short_inquiry:1;
+
+ /* The transport requires the LUN bits NOT to be stored in CDB[1] */
+ unsigned no_scsi2_lun_in_cdb:1;
+
+ /*
+ * Optional work queue to be utilized by the transport
+ */
+ char work_q_name[20];
+ struct workqueue_struct *work_q;
+
+ /*
+ * Task management function work queue
+ */
+ struct workqueue_struct *tmf_work_q;
+
+ /*
+ * Value host_blocked counts down from
+ */
+ unsigned int max_host_blocked;
+
+ /* Protection Information */
+ unsigned int prot_capabilities;
+ unsigned char prot_guard_type;
+
+ /* legacy crap */
+ unsigned long base;
+ unsigned long io_port;
+ unsigned char n_io_port;
+ unsigned char dma_channel;
+ unsigned int irq;
+
+
+ enum scsi_host_state shost_state;
+
+ /* ldm bits */
+ struct device shost_gendev, shost_dev;
+
+ /*
+ * Points to the transport data (if any) which is allocated
+ * separately
+ */
+ void *shost_data;
+
+ /*
+ * Points to the physical bus device we'd use to do DMA
+ * Needed just in case we have virtual hosts.
+ */
+ struct device *dma_dev;
+
+ /*
+ * We should ensure that this is aligned, both for better performance
+ * and also because some compilers (m68k) don't automatically force
+ * alignment to a long boundary.
+ */
+ unsigned long hostdata[] /* Used for storage of host specific stuff */
+ __attribute__ ((aligned (sizeof(unsigned long))));
+};
+
+#define class_to_shost(d) \
+ container_of(d, struct Scsi_Host, shost_dev)
+
+#define shost_printk(prefix, shost, fmt, a...) \
+ dev_printk(prefix, &(shost)->shost_gendev, fmt, ##a)
+
+static inline void *shost_priv(struct Scsi_Host *shost)
+{
+ return (void *)shost->hostdata;
+}
+
+int scsi_is_host_device(const struct device *);
+
+static inline struct Scsi_Host *dev_to_shost(struct device *dev)
+{
+ while (!scsi_is_host_device(dev)) {
+ if (!dev->parent)
+ return NULL;
+ dev = dev->parent;
+ }
+ return container_of(dev, struct Scsi_Host, shost_gendev);
+}
+
+static inline int scsi_host_in_recovery(struct Scsi_Host *shost)
+{
+ return shost->shost_state == SHOST_RECOVERY ||
+ shost->shost_state == SHOST_CANCEL_RECOVERY ||
+ shost->shost_state == SHOST_DEL_RECOVERY ||
+ shost->tmf_in_progress;
+}
+
+extern int scsi_queue_work(struct Scsi_Host *, struct work_struct *);
+extern void scsi_flush_work(struct Scsi_Host *);
+
+extern struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *, int);
+extern int __must_check scsi_add_host_with_dma(struct Scsi_Host *,
+ struct device *,
+ struct device *);
+extern void scsi_scan_host(struct Scsi_Host *);
+extern int scsi_rescan_device(struct scsi_device *sdev);
+extern void scsi_remove_host(struct Scsi_Host *);
+extern struct Scsi_Host *scsi_host_get(struct Scsi_Host *);
+extern int scsi_host_busy(struct Scsi_Host *shost);
+extern void scsi_host_put(struct Scsi_Host *t);
+extern struct Scsi_Host *scsi_host_lookup(unsigned int hostnum);
+extern const char *scsi_host_state_name(enum scsi_host_state);
+extern void scsi_host_complete_all_commands(struct Scsi_Host *shost,
+ enum scsi_host_status status);
+
+static inline int __must_check scsi_add_host(struct Scsi_Host *host,
+ struct device *dev)
+{
+ return scsi_add_host_with_dma(host, dev, dev);
+}
+
+static inline struct device *scsi_get_device(struct Scsi_Host *shost)
+{
+ return shost->shost_gendev.parent;
+}
+
+/**
+ * scsi_host_scan_allowed - Is scanning of this host allowed
+ * @shost: Pointer to Scsi_Host.
+ **/
+static inline int scsi_host_scan_allowed(struct Scsi_Host *shost)
+{
+ return shost->shost_state == SHOST_RUNNING ||
+ shost->shost_state == SHOST_RECOVERY;
+}
+
+extern void scsi_unblock_requests(struct Scsi_Host *);
+extern void scsi_block_requests(struct Scsi_Host *);
+extern int scsi_host_block(struct Scsi_Host *shost);
+extern int scsi_host_unblock(struct Scsi_Host *shost, int new_state);
+
+void scsi_host_busy_iter(struct Scsi_Host *,
+ bool (*fn)(struct scsi_cmnd *, void *), void *priv);
+
+struct class_container;
+
+/*
+ * 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;
+}
+
+extern int scsi_host_set_state(struct Scsi_Host *, enum scsi_host_state);
+
+#endif /* _SCSI_SCSI_HOST_H */
diff --git a/include/scsi/scsi_ioctl.h b/include/scsi/scsi_ioctl.h
new file mode 100644
index 000000000..beac64e38
--- /dev/null
+++ b/include/scsi/scsi_ioctl.h
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _SCSI_IOCTL_H
+#define _SCSI_IOCTL_H
+
+#define SCSI_IOCTL_SEND_COMMAND 1
+#define SCSI_IOCTL_TEST_UNIT_READY 2
+#define SCSI_IOCTL_BENCHMARK_COMMAND 3
+#define SCSI_IOCTL_SYNC 4 /* Request synchronous parameters */
+#define SCSI_IOCTL_START_UNIT 5
+#define SCSI_IOCTL_STOP_UNIT 6
+/* The door lock/unlock constants are compatible with Sun constants for
+ the cdrom */
+#define SCSI_IOCTL_DOORLOCK 0x5380 /* lock the eject mechanism */
+#define SCSI_IOCTL_DOORUNLOCK 0x5381 /* unlock the mechanism */
+
+#define SCSI_REMOVAL_PREVENT 1
+#define SCSI_REMOVAL_ALLOW 0
+
+#ifdef __KERNEL__
+
+struct gendisk;
+struct scsi_device;
+struct sg_io_hdr;
+
+/*
+ * Structures used for scsi_ioctl et al.
+ */
+
+typedef struct scsi_ioctl_command {
+ unsigned int inlen;
+ unsigned int outlen;
+ unsigned char data[];
+} Scsi_Ioctl_Command;
+
+typedef struct scsi_idlun {
+ __u32 dev_id;
+ __u32 host_unique_id;
+} Scsi_Idlun;
+
+/* Fibre Channel WWN, port_id struct */
+typedef struct scsi_fctargaddress {
+ __u32 host_port_id;
+ unsigned char host_wwn[8]; // include NULL term.
+} Scsi_FCTargAddress;
+
+int scsi_ioctl_block_when_processing_errors(struct scsi_device *sdev,
+ int cmd, bool ndelay);
+int scsi_ioctl(struct scsi_device *sdev, fmode_t mode, int cmd,
+ void __user *arg);
+int get_sg_io_hdr(struct sg_io_hdr *hdr, const void __user *argp);
+int put_sg_io_hdr(const struct sg_io_hdr *hdr, void __user *argp);
+bool scsi_cmd_allowed(unsigned char *cmd, fmode_t mode);
+
+#endif /* __KERNEL__ */
+#endif /* _SCSI_IOCTL_H */
diff --git a/include/scsi/scsi_proto.h b/include/scsi/scsi_proto.h
new file mode 100644
index 000000000..c03e35fc3
--- /dev/null
+++ b/include/scsi/scsi_proto.h
@@ -0,0 +1,345 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * This header file contains public constants and structures used by
+ * both the SCSI initiator and the SCSI target code.
+ *
+ * For documentation on the OPCODES, MESSAGES, and SENSE values,
+ * please consult the SCSI standard.
+ */
+
+#ifndef _SCSI_PROTO_H_
+#define _SCSI_PROTO_H_
+
+#include <linux/types.h>
+
+/*
+ * SCSI opcodes
+ */
+
+#define TEST_UNIT_READY 0x00
+#define REZERO_UNIT 0x01
+#define REQUEST_SENSE 0x03
+#define FORMAT_UNIT 0x04
+#define READ_BLOCK_LIMITS 0x05
+#define REASSIGN_BLOCKS 0x07
+#define INITIALIZE_ELEMENT_STATUS 0x07
+#define READ_6 0x08
+#define WRITE_6 0x0a
+#define SEEK_6 0x0b
+#define READ_REVERSE 0x0f
+#define WRITE_FILEMARKS 0x10
+#define SPACE 0x11
+#define INQUIRY 0x12
+#define RECOVER_BUFFERED_DATA 0x14
+#define MODE_SELECT 0x15
+#define RESERVE 0x16
+#define RELEASE 0x17
+#define COPY 0x18
+#define ERASE 0x19
+#define MODE_SENSE 0x1a
+#define START_STOP 0x1b
+#define RECEIVE_DIAGNOSTIC 0x1c
+#define SEND_DIAGNOSTIC 0x1d
+#define ALLOW_MEDIUM_REMOVAL 0x1e
+
+#define READ_FORMAT_CAPACITIES 0x23
+#define SET_WINDOW 0x24
+#define READ_CAPACITY 0x25
+#define READ_10 0x28
+#define WRITE_10 0x2a
+#define SEEK_10 0x2b
+#define POSITION_TO_ELEMENT 0x2b
+#define WRITE_VERIFY 0x2e
+#define VERIFY 0x2f
+#define SEARCH_HIGH 0x30
+#define SEARCH_EQUAL 0x31
+#define SEARCH_LOW 0x32
+#define SET_LIMITS 0x33
+#define PRE_FETCH 0x34
+#define READ_POSITION 0x34
+#define SYNCHRONIZE_CACHE 0x35
+#define LOCK_UNLOCK_CACHE 0x36
+#define READ_DEFECT_DATA 0x37
+#define MEDIUM_SCAN 0x38
+#define COMPARE 0x39
+#define COPY_VERIFY 0x3a
+#define WRITE_BUFFER 0x3b
+#define READ_BUFFER 0x3c
+#define UPDATE_BLOCK 0x3d
+#define READ_LONG 0x3e
+#define WRITE_LONG 0x3f
+#define CHANGE_DEFINITION 0x40
+#define WRITE_SAME 0x41
+#define UNMAP 0x42
+#define READ_TOC 0x43
+#define READ_HEADER 0x44
+#define GET_EVENT_STATUS_NOTIFICATION 0x4a
+#define LOG_SELECT 0x4c
+#define LOG_SENSE 0x4d
+#define XDWRITEREAD_10 0x53
+#define MODE_SELECT_10 0x55
+#define RESERVE_10 0x56
+#define RELEASE_10 0x57
+#define MODE_SENSE_10 0x5a
+#define PERSISTENT_RESERVE_IN 0x5e
+#define PERSISTENT_RESERVE_OUT 0x5f
+#define VARIABLE_LENGTH_CMD 0x7f
+#define REPORT_LUNS 0xa0
+#define SECURITY_PROTOCOL_IN 0xa2
+#define MAINTENANCE_IN 0xa3
+#define MAINTENANCE_OUT 0xa4
+#define MOVE_MEDIUM 0xa5
+#define EXCHANGE_MEDIUM 0xa6
+#define READ_12 0xa8
+#define SERVICE_ACTION_OUT_12 0xa9
+#define WRITE_12 0xaa
+#define READ_MEDIA_SERIAL_NUMBER 0xab /* Obsolete with SPC-2 */
+#define SERVICE_ACTION_IN_12 0xab
+#define WRITE_VERIFY_12 0xae
+#define VERIFY_12 0xaf
+#define SEARCH_HIGH_12 0xb0
+#define SEARCH_EQUAL_12 0xb1
+#define SEARCH_LOW_12 0xb2
+#define SECURITY_PROTOCOL_OUT 0xb5
+#define READ_ELEMENT_STATUS 0xb8
+#define SEND_VOLUME_TAG 0xb6
+#define WRITE_LONG_2 0xea
+#define EXTENDED_COPY 0x83
+#define RECEIVE_COPY_RESULTS 0x84
+#define ACCESS_CONTROL_IN 0x86
+#define ACCESS_CONTROL_OUT 0x87
+#define READ_16 0x88
+#define COMPARE_AND_WRITE 0x89
+#define WRITE_16 0x8a
+#define READ_ATTRIBUTE 0x8c
+#define WRITE_ATTRIBUTE 0x8d
+#define WRITE_VERIFY_16 0x8e
+#define VERIFY_16 0x8f
+#define SYNCHRONIZE_CACHE_16 0x91
+#define WRITE_SAME_16 0x93
+#define ZBC_OUT 0x94
+#define ZBC_IN 0x95
+#define SERVICE_ACTION_BIDIRECTIONAL 0x9d
+#define SERVICE_ACTION_IN_16 0x9e
+#define SERVICE_ACTION_OUT_16 0x9f
+/* values for service action in */
+#define SAI_READ_CAPACITY_16 0x10
+#define SAI_GET_LBA_STATUS 0x12
+#define SAI_REPORT_REFERRALS 0x13
+/* values for 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 ZBC_IN */
+#define ZI_REPORT_ZONES 0x00
+/* values for ZBC_OUT */
+#define ZO_CLOSE_ZONE 0x01
+#define ZO_FINISH_ZONE 0x02
+#define ZO_OPEN_ZONE 0x03
+#define ZO_RESET_WRITE_POINTER 0x04
+/* 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_VERIFY_32 0x0c
+#define WRITE_SAME_32 0x0d
+#define ATA_32 0x1ff0
+
+/* Values for T10/04-262r7 */
+#define ATA_16 0x85 /* 16-byte pass-thru */
+#define ATA_12 0xa1 /* 12-byte pass-thru */
+
+/* Vendor specific CDBs start here */
+#define VENDOR_SPECIFIC_CDB 0xc0
+
+/*
+ * SCSI command lengths
+ */
+
+#define SCSI_MAX_VARLEN_CDB_SIZE 260
+
+/* defined in T10 SCSI Primary Commands-2 (SPC2) */
+struct scsi_varlen_cdb_hdr {
+ __u8 opcode; /* opcode always == VARIABLE_LENGTH_CMD */
+ __u8 control;
+ __u8 misc[5];
+ __u8 additional_cdb_length; /* total cdb length - 8 */
+ __be16 service_action;
+ /* service specific data follows */
+};
+
+/*
+ * SCSI Architecture Model (SAM) Status codes. Taken from SAM-3 draft
+ * T10/1561-D Revision 4 Draft dated 7th November 2002.
+ */
+enum sam_status {
+ SAM_STAT_GOOD = 0x00,
+ SAM_STAT_CHECK_CONDITION = 0x02,
+ SAM_STAT_CONDITION_MET = 0x04,
+ SAM_STAT_BUSY = 0x08,
+ SAM_STAT_INTERMEDIATE = 0x10,
+ SAM_STAT_INTERMEDIATE_CONDITION_MET = 0x14,
+ SAM_STAT_RESERVATION_CONFLICT = 0x18,
+ SAM_STAT_COMMAND_TERMINATED = 0x22, /* obsolete in SAM-3 */
+ SAM_STAT_TASK_SET_FULL = 0x28,
+ SAM_STAT_ACA_ACTIVE = 0x30,
+ SAM_STAT_TASK_ABORTED = 0x40,
+};
+
+#define STATUS_MASK 0xfe
+/*
+ * SENSE KEYS
+ */
+
+#define NO_SENSE 0x00
+#define RECOVERED_ERROR 0x01
+#define NOT_READY 0x02
+#define MEDIUM_ERROR 0x03
+#define HARDWARE_ERROR 0x04
+#define ILLEGAL_REQUEST 0x05
+#define UNIT_ATTENTION 0x06
+#define DATA_PROTECT 0x07
+#define BLANK_CHECK 0x08
+#define VENDOR_SPECIFIC 0x09
+#define COPY_ABORTED 0x0a
+#define ABORTED_COMMAND 0x0b
+#define VOLUME_OVERFLOW 0x0d
+#define MISCOMPARE 0x0e
+
+
+/*
+ * DEVICE TYPES
+ * Please keep them in 0x%02x format for $MODALIAS to work
+ */
+
+#define TYPE_DISK 0x00
+#define TYPE_TAPE 0x01
+#define TYPE_PRINTER 0x02
+#define TYPE_PROCESSOR 0x03 /* HP scanners use this */
+#define TYPE_WORM 0x04 /* Treated as ROM by our system */
+#define TYPE_ROM 0x05
+#define TYPE_SCANNER 0x06
+#define TYPE_MOD 0x07 /* Magneto-optical disk -
+ * - treated as TYPE_DISK */
+#define TYPE_MEDIUM_CHANGER 0x08
+#define TYPE_COMM 0x09 /* Communications device */
+#define TYPE_RAID 0x0c
+#define TYPE_ENCLOSURE 0x0d /* Enclosure Services Device */
+#define TYPE_RBC 0x0e
+#define TYPE_OSD 0x11
+#define TYPE_ZBC 0x14
+#define TYPE_WLUN 0x1e /* well-known logical unit */
+#define TYPE_NO_LUN 0x7f
+
+/* SCSI protocols; these are taken from SPC-3 section 7.5 */
+enum scsi_protocol {
+ SCSI_PROTOCOL_FCP = 0, /* Fibre Channel */
+ SCSI_PROTOCOL_SPI = 1, /* parallel SCSI */
+ SCSI_PROTOCOL_SSA = 2, /* Serial Storage Architecture - Obsolete */
+ SCSI_PROTOCOL_SBP = 3, /* firewire */
+ SCSI_PROTOCOL_SRP = 4, /* Infiniband RDMA */
+ SCSI_PROTOCOL_ISCSI = 5,
+ SCSI_PROTOCOL_SAS = 6,
+ SCSI_PROTOCOL_ADT = 7, /* Media Changers */
+ SCSI_PROTOCOL_ATA = 8,
+ SCSI_PROTOCOL_UNSPEC = 0xf, /* No specific protocol */
+};
+
+/*
+ * ScsiLun: 8 byte LUN.
+ */
+struct scsi_lun {
+ __u8 scsi_lun[8];
+};
+
+/* SPC asymmetric access states */
+#define SCSI_ACCESS_STATE_OPTIMAL 0x00
+#define SCSI_ACCESS_STATE_ACTIVE 0x01
+#define SCSI_ACCESS_STATE_STANDBY 0x02
+#define SCSI_ACCESS_STATE_UNAVAILABLE 0x03
+#define SCSI_ACCESS_STATE_LBA 0x04
+#define SCSI_ACCESS_STATE_OFFLINE 0x0e
+#define SCSI_ACCESS_STATE_TRANSITIONING 0x0f
+
+/* Values for REPORT TARGET GROUP STATES */
+#define SCSI_ACCESS_STATE_MASK 0x0f
+#define SCSI_ACCESS_STATE_PREFERRED 0x80
+
+/* Reporting options for REPORT ZONES */
+enum zbc_zone_reporting_options {
+ ZBC_ZONE_REPORTING_OPTION_ALL = 0x00,
+ ZBC_ZONE_REPORTING_OPTION_EMPTY = 0x01,
+ ZBC_ZONE_REPORTING_OPTION_IMPLICIT_OPEN = 0x02,
+ ZBC_ZONE_REPORTING_OPTION_EXPLICIT_OPEN = 0x03,
+ ZBC_ZONE_REPORTING_OPTION_CLOSED = 0x04,
+ ZBC_ZONE_REPORTING_OPTION_FULL = 0x05,
+ ZBC_ZONE_REPORTING_OPTION_READONLY = 0x06,
+ ZBC_ZONE_REPORTING_OPTION_OFFLINE = 0x07,
+ /* 0x08 to 0x0f are reserved */
+ ZBC_ZONE_REPORTING_OPTION_NEED_RESET_WP = 0x10,
+ ZBC_ZONE_REPORTING_OPTION_NON_SEQWRITE = 0x11,
+ /* 0x12 to 0x3e are reserved */
+ ZBC_ZONE_REPORTING_OPTION_NON_WP = 0x3f,
+};
+
+#define ZBC_REPORT_ZONE_PARTIAL 0x80
+
+/* Zone types of REPORT ZONES zone descriptors */
+enum zbc_zone_type {
+ ZBC_ZONE_TYPE_CONV = 0x1,
+ ZBC_ZONE_TYPE_SEQWRITE_REQ = 0x2,
+ ZBC_ZONE_TYPE_SEQWRITE_PREF = 0x3,
+ ZBC_ZONE_TYPE_SEQ_OR_BEFORE_REQ = 0x4,
+ ZBC_ZONE_TYPE_GAP = 0x5,
+ /* 0x6 to 0xf are reserved */
+};
+
+/* Zone conditions of REPORT ZONES zone descriptors */
+enum zbc_zone_cond {
+ ZBC_ZONE_COND_NO_WP = 0x0,
+ ZBC_ZONE_COND_EMPTY = 0x1,
+ ZBC_ZONE_COND_IMP_OPEN = 0x2,
+ ZBC_ZONE_COND_EXP_OPEN = 0x3,
+ ZBC_ZONE_COND_CLOSED = 0x4,
+ /* 0x5 to 0xc are reserved */
+ ZBC_ZONE_COND_READONLY = 0xd,
+ ZBC_ZONE_COND_FULL = 0xe,
+ ZBC_ZONE_COND_OFFLINE = 0xf,
+};
+
+enum zbc_zone_alignment_method {
+ ZBC_CONSTANT_ZONE_LENGTH = 0x1,
+ ZBC_CONSTANT_ZONE_START_OFFSET = 0x8,
+};
+
+/* Version descriptor values for INQUIRY */
+enum scsi_version_descriptor {
+ SCSI_VERSION_DESCRIPTOR_FCP4 = 0x0a40,
+ SCSI_VERSION_DESCRIPTOR_ISCSI = 0x0960,
+ SCSI_VERSION_DESCRIPTOR_SAM5 = 0x00a0,
+ SCSI_VERSION_DESCRIPTOR_SAS3 = 0x0c60,
+ SCSI_VERSION_DESCRIPTOR_SBC3 = 0x04c0,
+ SCSI_VERSION_DESCRIPTOR_SBP3 = 0x0980,
+ SCSI_VERSION_DESCRIPTOR_SPC4 = 0x0460,
+ SCSI_VERSION_DESCRIPTOR_SRP = 0x0940
+};
+
+#endif /* _SCSI_PROTO_H_ */
diff --git a/include/scsi/scsi_status.h b/include/scsi/scsi_status.h
new file mode 100644
index 000000000..9cb85262d
--- /dev/null
+++ b/include/scsi/scsi_status.h
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _SCSI_SCSI_STATUS_H
+#define _SCSI_SCSI_STATUS_H
+
+#include <linux/types.h>
+#include <scsi/scsi_proto.h>
+
+/* Message codes. */
+enum scsi_msg_byte {
+ COMMAND_COMPLETE = 0x00,
+ EXTENDED_MESSAGE = 0x01,
+ SAVE_POINTERS = 0x02,
+ RESTORE_POINTERS = 0x03,
+ DISCONNECT = 0x04,
+ INITIATOR_ERROR = 0x05,
+ ABORT_TASK_SET = 0x06,
+ MESSAGE_REJECT = 0x07,
+ NOP = 0x08,
+ MSG_PARITY_ERROR = 0x09,
+ LINKED_CMD_COMPLETE = 0x0a,
+ LINKED_FLG_CMD_COMPLETE = 0x0b,
+ TARGET_RESET = 0x0c,
+ ABORT_TASK = 0x0d,
+ CLEAR_TASK_SET = 0x0e,
+ INITIATE_RECOVERY = 0x0f, /* SCSI-II only */
+ RELEASE_RECOVERY = 0x10, /* SCSI-II only */
+ TERMINATE_IO_PROC = 0x11, /* SCSI-II only */
+ CLEAR_ACA = 0x16,
+ LOGICAL_UNIT_RESET = 0x17,
+ SIMPLE_QUEUE_TAG = 0x20,
+ HEAD_OF_QUEUE_TAG = 0x21,
+ ORDERED_QUEUE_TAG = 0x22,
+ IGNORE_WIDE_RESIDUE = 0x23,
+ ACA = 0x24,
+ QAS_REQUEST = 0x55,
+
+ /* Old SCSI2 names, don't use in new code */
+ BUS_DEVICE_RESET = TARGET_RESET,
+ ABORT = ABORT_TASK_SET,
+};
+
+/* Host byte codes. */
+enum scsi_host_status {
+ DID_OK = 0x00, /* NO error */
+ DID_NO_CONNECT = 0x01, /* Couldn't connect before timeout period */
+ DID_BUS_BUSY = 0x02, /* BUS stayed busy through time out period */
+ DID_TIME_OUT = 0x03, /* TIMED OUT for other reason */
+ DID_BAD_TARGET = 0x04, /* BAD target. */
+ DID_ABORT = 0x05, /* Told to abort for some other reason */
+ DID_PARITY = 0x06, /* Parity error */
+ DID_ERROR = 0x07, /* Internal error */
+ DID_RESET = 0x08, /* Reset by somebody. */
+ DID_BAD_INTR = 0x09, /* Got an interrupt we weren't expecting. */
+ DID_PASSTHROUGH = 0x0a, /* Force command past mid-layer */
+ DID_SOFT_ERROR = 0x0b, /* The low level driver just wish a retry */
+ DID_IMM_RETRY = 0x0c, /* Retry without decrementing retry count */
+ DID_REQUEUE = 0x0d, /* Requeue command (no immediate retry) also
+ * without decrementing the retry count */
+ 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 */
+ DID_TRANSPORT_FAILFAST = 0x0f, /* Transport class fastfailed the io */
+ /*
+ * We used to have DID_TARGET_FAILURE, DID_NEXUS_FAILURE,
+ * DID_ALLOC_FAILURE and DID_MEDIUM_ERROR at 0x10 - 0x13. For compat
+ * with userspace apps that parse the host byte for SG IO, we leave
+ * that block of codes unused and start at 0x14 below.
+ */
+ DID_TRANSPORT_MARGINAL = 0x14, /* Transport marginal errors */
+};
+
+#endif /* _SCSI_SCSI_STATUS_H */
diff --git a/include/scsi/scsi_tcq.h b/include/scsi/scsi_tcq.h
new file mode 100644
index 000000000..ea7848e74
--- /dev/null
+++ b/include/scsi/scsi_tcq.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _SCSI_SCSI_TCQ_H
+#define _SCSI_SCSI_TCQ_H
+
+#include <linux/blkdev.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
+#define SCSI_NO_TAG (-1) /* identify no tag in use */
+
+
+#ifdef CONFIG_BLOCK
+/**
+ * scsi_host_find_tag - find the tagged command by host
+ * @shost: pointer to scsi_host
+ * @tag: tag
+ *
+ * Note: for devices using multiple hardware queues tag must have been
+ * generated by blk_mq_unique_tag().
+ **/
+static inline struct scsi_cmnd *scsi_host_find_tag(struct Scsi_Host *shost,
+ int tag)
+{
+ struct request *req = NULL;
+ u16 hwq;
+
+ if (tag == SCSI_NO_TAG)
+ return NULL;
+
+ hwq = blk_mq_unique_tag_to_hwq(tag);
+ if (hwq < shost->tag_set.nr_hw_queues) {
+ req = blk_mq_tag_to_rq(shost->tag_set.tags[hwq],
+ blk_mq_unique_tag_to_tag(tag));
+ }
+
+ if (!req || !blk_mq_request_started(req))
+ return NULL;
+ return blk_mq_rq_to_pdu(req);
+}
+
+#endif /* CONFIG_BLOCK */
+#endif /* _SCSI_SCSI_TCQ_H */
diff --git a/include/scsi/scsi_transport.h b/include/scsi/scsi_transport.h
new file mode 100644
index 000000000..a0458bda3
--- /dev/null
+++ b/include/scsi/scsi_transport.h
@@ -0,0 +1,88 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Transport specific attributes.
+ *
+ * Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved.
+ */
+#ifndef SCSI_TRANSPORT_H
+#define SCSI_TRANSPORT_H
+
+#include <linux/transport_class.h>
+#include <linux/blkdev.h>
+#include <linux/bug.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+
+struct scsi_transport_template {
+ /* the attribute containers */
+ struct transport_container host_attrs;
+ struct transport_container target_attrs;
+ struct transport_container device_attrs;
+
+ /*
+ * If set, called from sysfs and legacy procfs rescanning code.
+ */
+ int (*user_scan)(struct Scsi_Host *, uint, uint, u64);
+
+ /* The size of the specific transport attribute structure (a
+ * space of this size will be left at the end of the
+ * scsi_* structure */
+ int device_size;
+ int device_private_offset;
+ int target_size;
+ int target_private_offset;
+ int host_size;
+ /* no private offset for the host; there's an alternative mechanism */
+
+ /*
+ * True if the transport wants to use a host-based work-queue
+ */
+ unsigned int create_work_queue : 1;
+
+ /*
+ * Allows a transport to override the default error handler.
+ */
+ void (* eh_strategy_handler)(struct Scsi_Host *);
+};
+
+#define transport_class_to_shost(tc) \
+ dev_to_shost((tc)->parent)
+
+
+/* Private area maintenance. The driver requested allocations come
+ * directly after the transport class allocations (if any). The idea
+ * is that you *must* call these only once. The code assumes that the
+ * initial values are the ones the transport specific code requires */
+static inline void
+scsi_transport_reserve_target(struct scsi_transport_template * t, int space)
+{
+ BUG_ON(t->target_private_offset != 0);
+ t->target_private_offset = ALIGN(t->target_size, sizeof(void *));
+ t->target_size = t->target_private_offset + space;
+}
+static inline void
+scsi_transport_reserve_device(struct scsi_transport_template * t, int space)
+{
+ BUG_ON(t->device_private_offset != 0);
+ t->device_private_offset = ALIGN(t->device_size, sizeof(void *));
+ t->device_size = t->device_private_offset + space;
+}
+static inline void *
+scsi_transport_target_data(struct scsi_target *starget)
+{
+ struct Scsi_Host *shost = dev_to_shost(&starget->dev);
+ return (u8 *)starget->starget_data
+ + shost->transportt->target_private_offset;
+
+}
+static inline void *
+scsi_transport_device_data(struct scsi_device *sdev)
+{
+ struct Scsi_Host *shost = sdev->host;
+ return (u8 *)sdev->sdev_data
+ + shost->transportt->device_private_offset;
+}
+
+void __scsi_init_queue(struct Scsi_Host *shost, struct request_queue *q);
+
+#endif /* SCSI_TRANSPORT_H */
diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h
new file mode 100644
index 000000000..e80a7c542
--- /dev/null
+++ b/include/scsi/scsi_transport_fc.h
@@ -0,0 +1,882 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * FiberChannel transport specific attributes exported to sysfs.
+ *
+ * Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2004-2007 James Smart, Emulex Corporation
+ * Rewrite for host, target, device, and remote port attributes,
+ * statistics, and service functions...
+ */
+#ifndef SCSI_TRANSPORT_FC_H
+#define SCSI_TRANSPORT_FC_H
+
+#include <linux/sched.h>
+#include <linux/bsg-lib.h>
+#include <asm/unaligned.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_netlink.h>
+#include <scsi/scsi_host.h>
+
+struct scsi_transport_template;
+
+/*
+ * FC Port definitions - Following FC HBAAPI guidelines
+ *
+ * Note: Not all binary values for the different fields match HBAAPI.
+ * Instead, we use densely packed ordinal values or enums.
+ * We get away with this as we never present the actual binary values
+ * externally. For sysfs, we always present the string that describes
+ * the value. Thus, an admin doesn't need a magic HBAAPI decoder ring
+ * to understand the values. The HBAAPI user-space library is free to
+ * convert the strings into the HBAAPI-specified binary values.
+ *
+ * Note: Not all HBAAPI-defined values are contained in the definitions
+ * below. Those not appropriate to an fc_host (e.g. FCP initiator) have
+ * been removed.
+ */
+
+/*
+ * fc_port_type: If you alter this, you also need to alter scsi_transport_fc.c
+ * (for the ascii descriptions).
+ */
+enum fc_port_type {
+ FC_PORTTYPE_UNKNOWN,
+ FC_PORTTYPE_OTHER,
+ FC_PORTTYPE_NOTPRESENT,
+ FC_PORTTYPE_NPORT, /* Attached to FPort */
+ FC_PORTTYPE_NLPORT, /* (Public) Loop w/ FLPort */
+ FC_PORTTYPE_LPORT, /* (Private) Loop w/o FLPort */
+ FC_PORTTYPE_PTP, /* Point to Point w/ another NPort */
+ FC_PORTTYPE_NPIV, /* VPORT based on NPIV */
+};
+
+
+/*
+ * fc_port_state: If you alter this, you also need to alter scsi_transport_fc.c
+ * (for the ascii descriptions).
+ */
+enum fc_port_state {
+ FC_PORTSTATE_UNKNOWN,
+ FC_PORTSTATE_NOTPRESENT,
+ FC_PORTSTATE_ONLINE,
+ FC_PORTSTATE_OFFLINE, /* User has taken Port Offline */
+ FC_PORTSTATE_BLOCKED,
+ FC_PORTSTATE_BYPASSED,
+ FC_PORTSTATE_DIAGNOSTICS,
+ FC_PORTSTATE_LINKDOWN,
+ FC_PORTSTATE_ERROR,
+ FC_PORTSTATE_LOOPBACK,
+ FC_PORTSTATE_DELETED,
+ FC_PORTSTATE_MARGINAL,
+};
+
+
+/*
+ * fc_vport_state: If you alter this, you also need to alter
+ * scsi_transport_fc.c (for the ascii descriptions).
+ */
+enum fc_vport_state {
+ FC_VPORT_UNKNOWN,
+ FC_VPORT_ACTIVE,
+ FC_VPORT_DISABLED,
+ FC_VPORT_LINKDOWN,
+ FC_VPORT_INITIALIZING,
+ FC_VPORT_NO_FABRIC_SUPP,
+ FC_VPORT_NO_FABRIC_RSCS,
+ FC_VPORT_FABRIC_LOGOUT,
+ FC_VPORT_FABRIC_REJ_WWN,
+ FC_VPORT_FAILED,
+};
+
+
+
+/*
+ * FC Classes of Service
+ * Note: values are not enumerated, as they can be "or'd" together
+ * for reporting (e.g. report supported_classes). If you alter this list,
+ * you also need to alter scsi_transport_fc.c (for the ascii descriptions).
+ */
+#define FC_COS_UNSPECIFIED 0
+#define FC_COS_CLASS1 2
+#define FC_COS_CLASS2 4
+#define FC_COS_CLASS3 8
+#define FC_COS_CLASS4 0x10
+#define FC_COS_CLASS6 0x40
+
+/*
+ * FC Port Speeds
+ * Note: values are not enumerated, as they can be "or'd" together
+ * for reporting (e.g. report supported_speeds). If you alter this list,
+ * you also need to alter scsi_transport_fc.c (for the ascii descriptions).
+ */
+#define FC_PORTSPEED_UNKNOWN 0 /* Unknown - transceiver
+ incapable of reporting */
+#define FC_PORTSPEED_1GBIT 1
+#define FC_PORTSPEED_2GBIT 2
+#define FC_PORTSPEED_10GBIT 4
+#define FC_PORTSPEED_4GBIT 8
+#define FC_PORTSPEED_8GBIT 0x10
+#define FC_PORTSPEED_16GBIT 0x20
+#define FC_PORTSPEED_32GBIT 0x40
+#define FC_PORTSPEED_20GBIT 0x80
+#define FC_PORTSPEED_40GBIT 0x100
+#define FC_PORTSPEED_50GBIT 0x200
+#define FC_PORTSPEED_100GBIT 0x400
+#define FC_PORTSPEED_25GBIT 0x800
+#define FC_PORTSPEED_64GBIT 0x1000
+#define FC_PORTSPEED_128GBIT 0x2000
+#define FC_PORTSPEED_256GBIT 0x4000
+#define FC_PORTSPEED_NOT_NEGOTIATED (1 << 15) /* Speed not established */
+
+/*
+ * fc_tgtid_binding_type: If you alter this, you also need to alter
+ * scsi_transport_fc.c (for the ascii descriptions).
+ */
+enum fc_tgtid_binding_type {
+ FC_TGTID_BIND_NONE,
+ FC_TGTID_BIND_BY_WWPN,
+ FC_TGTID_BIND_BY_WWNN,
+ FC_TGTID_BIND_BY_ID,
+};
+
+/*
+ * FC Port Roles
+ * Note: values are not enumerated, as they can be "or'd" together
+ * for reporting (e.g. report roles). If you alter this list,
+ * you also need to alter scsi_transport_fc.c (for the ascii descriptions).
+ */
+#define FC_PORT_ROLE_UNKNOWN 0x00
+#define FC_PORT_ROLE_FCP_TARGET 0x01
+#define FC_PORT_ROLE_FCP_INITIATOR 0x02
+#define FC_PORT_ROLE_IP_PORT 0x04
+#define FC_PORT_ROLE_FCP_DUMMY_INITIATOR 0x08
+#define FC_PORT_ROLE_NVME_INITIATOR 0x10
+#define FC_PORT_ROLE_NVME_TARGET 0x20
+#define FC_PORT_ROLE_NVME_DISCOVERY 0x40
+
+/* The following are for compatibility */
+#define FC_RPORT_ROLE_UNKNOWN FC_PORT_ROLE_UNKNOWN
+#define FC_RPORT_ROLE_FCP_TARGET FC_PORT_ROLE_FCP_TARGET
+#define FC_RPORT_ROLE_FCP_INITIATOR FC_PORT_ROLE_FCP_INITIATOR
+#define FC_RPORT_ROLE_IP_PORT FC_PORT_ROLE_IP_PORT
+
+
+/* Macro for use in defining Virtual Port attributes */
+#define FC_VPORT_ATTR(_name,_mode,_show,_store) \
+struct device_attribute dev_attr_vport_##_name = \
+ __ATTR(_name,_mode,_show,_store)
+
+/*
+ * fc_vport_identifiers: This set of data contains all elements
+ * to uniquely identify and instantiate a FC virtual port.
+ *
+ * Notes:
+ * symbolic_name: The driver is to append the symbolic_name string data
+ * to the symbolic_node_name data that it generates by default.
+ * the resulting combination should then be registered with the switch.
+ * It is expected that things like Xen may stuff a VM title into
+ * this field.
+ */
+#define FC_VPORT_SYMBOLIC_NAMELEN 64
+struct fc_vport_identifiers {
+ u64 node_name;
+ u64 port_name;
+ u32 roles;
+ bool disable;
+ enum fc_port_type vport_type; /* only FC_PORTTYPE_NPIV allowed */
+ char symbolic_name[FC_VPORT_SYMBOLIC_NAMELEN];
+};
+
+/*
+ * FC Virtual Port Attributes
+ *
+ * This structure exists for each FC port is a virtual FC port. Virtual
+ * ports share the physical link with the Physical port. Each virtual
+ * ports has a unique presence on the SAN, and may be instantiated via
+ * NPIV, Virtual Fabrics, or via additional ALPAs. As the vport is a
+ * unique presence, each vport has it's own view of the fabric,
+ * authentication privilege, and priorities.
+ *
+ * A virtual port may support 1 or more FC4 roles. Typically it is a
+ * FCP Initiator. It could be a FCP Target, or exist sole for an IP over FC
+ * roles. FC port attributes for the vport will be reported on any
+ * fc_host class object allocated for an FCP Initiator.
+ *
+ * --
+ *
+ * Fixed attributes are not expected to change. The driver is
+ * expected to set these values after receiving the fc_vport structure
+ * via the vport_create() call from the transport.
+ * The transport fully manages all get functions w/o driver interaction.
+ *
+ * Dynamic attributes are expected to change. The driver participates
+ * in all get/set operations via functions provided by the driver.
+ *
+ * Private attributes are transport-managed values. They are fully
+ * managed by the transport w/o driver interaction.
+ */
+
+struct fc_vport {
+ /* Fixed Attributes */
+
+ /* Dynamic Attributes */
+
+ /* Private (Transport-managed) Attributes */
+ enum fc_vport_state vport_state;
+ enum fc_vport_state vport_last_state;
+ u64 node_name;
+ u64 port_name;
+ u32 roles;
+ u32 vport_id; /* Admin Identifier for the vport */
+ enum fc_port_type vport_type;
+ char symbolic_name[FC_VPORT_SYMBOLIC_NAMELEN];
+
+ /* exported data */
+ void *dd_data; /* Used for driver-specific storage */
+
+ /* internal data */
+ struct Scsi_Host *shost; /* Physical Port Parent */
+ unsigned int channel;
+ u32 number;
+ u8 flags;
+ struct list_head peers;
+ struct device dev;
+ struct work_struct vport_delete_work;
+} __attribute__((aligned(sizeof(unsigned long))));
+
+/* bit field values for struct fc_vport "flags" field: */
+#define FC_VPORT_CREATING 0x01
+#define FC_VPORT_DELETING 0x02
+#define FC_VPORT_DELETED 0x04
+#define FC_VPORT_DEL 0x06 /* Any DELETE state */
+
+#define dev_to_vport(d) \
+ container_of(d, struct fc_vport, dev)
+#define transport_class_to_vport(dev) \
+ dev_to_vport(dev->parent)
+#define vport_to_shost(v) \
+ (v->shost)
+#define vport_to_shost_channel(v) \
+ (v->channel)
+#define vport_to_parent(v) \
+ (v->dev.parent)
+
+
+/* Error return codes for vport_create() callback */
+#define VPCERR_UNSUPPORTED -ENOSYS /* no driver/adapter
+ support */
+#define VPCERR_BAD_WWN -ENOTUNIQ /* driver validation
+ of WWNs failed */
+#define VPCERR_NO_FABRIC_SUPP -EOPNOTSUPP /* Fabric connection
+ is loop or the
+ Fabric Port does
+ not support NPIV */
+
+/*
+ * fc_rport_identifiers: This set of data contains all elements
+ * to uniquely identify a remote FC port. The driver uses this data
+ * to report the existence of a remote FC port in the topology. Internally,
+ * the transport uses this data for attributes and to manage consistent
+ * target id bindings.
+ */
+struct fc_rport_identifiers {
+ u64 node_name;
+ u64 port_name;
+ u32 port_id;
+ u32 roles;
+};
+
+/*
+ * Fabric Performance Impact Notification Statistics
+ */
+struct fc_fpin_stats {
+ /* Delivery */
+ u64 dn;
+ u64 dn_unknown;
+ u64 dn_timeout;
+ u64 dn_unable_to_route;
+ u64 dn_device_specific;
+
+ /* Link Integrity */
+ u64 li;
+ u64 li_failure_unknown;
+ u64 li_link_failure_count;
+ u64 li_loss_of_sync_count;
+ u64 li_loss_of_signals_count;
+ u64 li_prim_seq_err_count;
+ u64 li_invalid_tx_word_count;
+ u64 li_invalid_crc_count;
+ u64 li_device_specific;
+
+ /* Congestion/Peer Congestion */
+ u64 cn;
+ u64 cn_clear;
+ u64 cn_lost_credit;
+ u64 cn_credit_stall;
+ u64 cn_oversubscription;
+ u64 cn_device_specific;
+};
+
+/* Macro for use in defining Remote Port attributes */
+#define FC_RPORT_ATTR(_name,_mode,_show,_store) \
+struct device_attribute dev_attr_rport_##_name = \
+ __ATTR(_name,_mode,_show,_store)
+
+
+/*
+ * FC Remote Port Attributes
+ *
+ * This structure exists for each remote FC port that a LLDD notifies
+ * the subsystem of. A remote FC port may or may not be a SCSI Target,
+ * also be a SCSI initiator, IP endpoint, etc. As such, the remote
+ * port is considered a separate entity, independent of "role" (such
+ * as scsi target).
+ *
+ * --
+ *
+ * Attributes are based on HBAAPI V2.0 definitions. Only those
+ * attributes that are determinable by the local port (aka Host)
+ * are contained.
+ *
+ * Fixed attributes are not expected to change. The driver is
+ * expected to set these values after successfully calling
+ * fc_remote_port_add(). The transport fully manages all get functions
+ * w/o driver interaction.
+ *
+ * Dynamic attributes are expected to change. The driver participates
+ * in all get/set operations via functions provided by the driver.
+ *
+ * Private attributes are transport-managed values. They are fully
+ * managed by the transport w/o driver interaction.
+ */
+
+struct fc_rport { /* aka fc_starget_attrs */
+ /* Fixed Attributes */
+ u32 maxframe_size;
+ u32 supported_classes;
+
+ /* Dynamic Attributes */
+ u32 dev_loss_tmo; /* Remote Port loss timeout in seconds. */
+ struct fc_fpin_stats fpin_stats;
+
+ /* Private (Transport-managed) Attributes */
+ u64 node_name;
+ u64 port_name;
+ u32 port_id;
+ u32 roles;
+ enum fc_port_state port_state; /* Will only be ONLINE or UNKNOWN */
+ u32 scsi_target_id;
+ u32 fast_io_fail_tmo;
+
+ /* exported data */
+ void *dd_data; /* Used for driver-specific storage */
+
+ /* internal data */
+ unsigned int channel;
+ u32 number;
+ u8 flags;
+ struct list_head peers;
+ struct device dev;
+ struct delayed_work dev_loss_work;
+ struct work_struct scan_work;
+ struct delayed_work fail_io_work;
+ struct work_struct stgt_delete_work;
+ struct work_struct rport_delete_work;
+ struct request_queue *rqst_q; /* bsg support */
+} __attribute__((aligned(sizeof(unsigned long))));
+
+/* bit field values for struct fc_rport "flags" field: */
+#define FC_RPORT_DEVLOSS_PENDING 0x01
+#define FC_RPORT_SCAN_PENDING 0x02
+#define FC_RPORT_FAST_FAIL_TIMEDOUT 0x04
+#define FC_RPORT_DEVLOSS_CALLBK_DONE 0x08
+
+#define dev_to_rport(d) \
+ container_of(d, struct fc_rport, dev)
+#define transport_class_to_rport(dev) \
+ dev_to_rport(dev->parent)
+#define rport_to_shost(r) \
+ dev_to_shost(r->dev.parent)
+
+/*
+ * FC SCSI Target Attributes
+ *
+ * The SCSI Target is considered an extension of a remote port (as
+ * a remote port can be more than a SCSI Target). Within the scsi
+ * subsystem, we leave the Target as a separate entity. Doing so
+ * provides backward compatibility with prior FC transport api's,
+ * and lets remote ports be handled entirely within the FC transport
+ * and independently from the scsi subsystem. The drawback is that
+ * some data will be duplicated.
+ */
+
+struct fc_starget_attrs { /* aka fc_target_attrs */
+ /* Dynamic Attributes */
+ u64 node_name;
+ u64 port_name;
+ u32 port_id;
+};
+
+#define fc_starget_node_name(x) \
+ (((struct fc_starget_attrs *)&(x)->starget_data)->node_name)
+#define fc_starget_port_name(x) \
+ (((struct fc_starget_attrs *)&(x)->starget_data)->port_name)
+#define fc_starget_port_id(x) \
+ (((struct fc_starget_attrs *)&(x)->starget_data)->port_id)
+
+#define starget_to_rport(s) \
+ scsi_is_fc_rport(s->dev.parent) ? dev_to_rport(s->dev.parent) : NULL
+
+
+/*
+ * FC Local Port (Host) Statistics
+ */
+
+/* FC Statistics - Following FC HBAAPI v2.0 guidelines */
+struct fc_host_statistics {
+ /* port statistics */
+ u64 seconds_since_last_reset;
+ u64 tx_frames;
+ u64 tx_words;
+ u64 rx_frames;
+ u64 rx_words;
+ u64 lip_count;
+ u64 nos_count;
+ u64 error_frames;
+ u64 dumped_frames;
+ u64 link_failure_count;
+ u64 loss_of_sync_count;
+ u64 loss_of_signal_count;
+ u64 prim_seq_protocol_err_count;
+ u64 invalid_tx_word_count;
+ u64 invalid_crc_count;
+
+ /* fc4 statistics (only FCP supported currently) */
+ u64 fcp_input_requests;
+ u64 fcp_output_requests;
+ u64 fcp_control_requests;
+ u64 fcp_input_megabytes;
+ u64 fcp_output_megabytes;
+ u64 fcp_packet_alloc_failures; /* fcp packet allocation failures */
+ u64 fcp_packet_aborts; /* fcp packet aborted */
+ u64 fcp_frame_alloc_failures; /* fcp frame allocation failures */
+
+ /* fc exches statistics */
+ u64 fc_no_free_exch; /* no free exch memory */
+ u64 fc_no_free_exch_xid; /* no free exch id */
+ u64 fc_xid_not_found; /* exch not found for a response */
+ u64 fc_xid_busy; /* exch exist for new a request */
+ u64 fc_seq_not_found; /* seq is not found for exchange */
+ u64 fc_non_bls_resp; /* a non BLS response frame with
+ a sequence responder in new exch */
+ /* Host Congestion Signals */
+ u64 cn_sig_warn;
+ u64 cn_sig_alarm;
+};
+
+
+/*
+ * 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_LINK_FPIN = 0x501,
+ FCH_EVT_VENDOR_UNIQUE = 0xffff,
+};
+
+
+/*
+ * FC Local Port (Host) Attributes
+ *
+ * Attributes are based on HBAAPI V2.0 definitions.
+ * Note: OSDeviceName is determined by user-space library
+ *
+ * Fixed attributes are not expected to change. The driver is
+ * expected to set these values after successfully calling scsi_add_host().
+ * The transport fully manages all get functions w/o driver interaction.
+ *
+ * Dynamic attributes are expected to change. The driver participates
+ * in all get/set operations via functions provided by the driver.
+ *
+ * Private attributes are transport-managed values. They are fully
+ * managed by the transport w/o driver interaction.
+ */
+
+#define FC_VENDOR_IDENTIFIER 8
+#define FC_FC4_LIST_SIZE 32
+#define FC_SYMBOLIC_NAME_SIZE 256
+#define FC_VERSION_STRING_SIZE 64
+#define FC_SERIAL_NUMBER_SIZE 64
+
+struct fc_host_attrs {
+ /* Fixed Attributes */
+ u64 node_name;
+ u64 port_name;
+ u64 permanent_port_name;
+ u32 supported_classes;
+ u8 supported_fc4s[FC_FC4_LIST_SIZE];
+ u32 supported_speeds;
+ u32 maxframe_size;
+ u16 max_npiv_vports;
+ u32 max_ct_payload;
+ u32 num_ports;
+ u32 num_discovered_ports;
+ u32 bootbios_state;
+ 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];
+ char vendor_identifier[FC_VENDOR_IDENTIFIER];
+ char bootbios_version[FC_SYMBOLIC_NAME_SIZE];
+
+
+ /* Dynamic Attributes */
+ u32 port_id;
+ enum fc_port_type port_type;
+ enum fc_port_state port_state;
+ u8 active_fc4s[FC_FC4_LIST_SIZE];
+ u32 speed;
+ u64 fabric_name;
+ char symbolic_name[FC_SYMBOLIC_NAME_SIZE];
+ char system_hostname[FC_SYMBOLIC_NAME_SIZE];
+ u32 dev_loss_tmo;
+ struct fc_fpin_stats fpin_stats;
+
+ /* Private (Transport-managed) Attributes */
+ enum fc_tgtid_binding_type tgtid_bind_type;
+
+ /* internal data */
+ struct list_head rports;
+ struct list_head rport_bindings;
+ struct list_head vports;
+ u32 next_rport_number;
+ u32 next_target_id;
+ u32 next_vport_number;
+ u16 npiv_vports_inuse;
+
+ /* work queues for rport state manipulation */
+ char work_q_name[20];
+ struct workqueue_struct *work_q;
+ char devloss_work_q_name[20];
+ struct workqueue_struct *devloss_work_q;
+
+ /* bsg support */
+ struct request_queue *rqst_q;
+
+ /* FDMI support version*/
+ u8 fdmi_version;
+};
+
+#define shost_to_fc_host(x) \
+ ((struct fc_host_attrs *)(x)->shost_data)
+
+#define fc_host_node_name(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->node_name)
+#define fc_host_port_name(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->port_name)
+#define fc_host_permanent_port_name(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->permanent_port_name)
+#define fc_host_supported_classes(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->supported_classes)
+#define fc_host_supported_fc4s(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->supported_fc4s)
+#define fc_host_supported_speeds(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->supported_speeds)
+#define fc_host_maxframe_size(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->maxframe_size)
+#define fc_host_max_npiv_vports(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->max_npiv_vports)
+#define fc_host_serial_number(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->serial_number)
+#define fc_host_manufacturer(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->manufacturer)
+#define fc_host_model(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->model)
+#define fc_host_model_description(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->model_description)
+#define fc_host_hardware_version(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->hardware_version)
+#define fc_host_driver_version(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->driver_version)
+#define fc_host_firmware_version(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->firmware_version)
+#define fc_host_optionrom_version(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->optionrom_version)
+#define fc_host_port_id(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->port_id)
+#define fc_host_port_type(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->port_type)
+#define fc_host_port_state(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->port_state)
+#define fc_host_active_fc4s(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->active_fc4s)
+#define fc_host_speed(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->speed)
+#define fc_host_fabric_name(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->fabric_name)
+#define fc_host_symbolic_name(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->symbolic_name)
+#define fc_host_system_hostname(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->system_hostname)
+#define fc_host_tgtid_bind_type(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->tgtid_bind_type)
+#define fc_host_rports(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->rports)
+#define fc_host_rport_bindings(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->rport_bindings)
+#define fc_host_vports(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->vports)
+#define fc_host_next_rport_number(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->next_rport_number)
+#define fc_host_next_target_id(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->next_target_id)
+#define fc_host_next_vport_number(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->next_vport_number)
+#define fc_host_npiv_vports_inuse(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->npiv_vports_inuse)
+#define fc_host_work_q_name(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->work_q_name)
+#define fc_host_work_q(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->work_q)
+#define fc_host_devloss_work_q_name(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->devloss_work_q_name)
+#define fc_host_devloss_work_q(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->devloss_work_q)
+#define fc_host_dev_loss_tmo(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->dev_loss_tmo)
+#define fc_host_max_ct_payload(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->max_ct_payload)
+#define fc_host_vendor_identifier(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->vendor_identifier)
+#define fc_host_num_discovered_ports(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->num_discovered_ports)
+#define fc_host_num_ports(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->num_ports)
+#define fc_host_bootbios_version(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->bootbios_version)
+#define fc_host_bootbios_state(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->bootbios_state)
+
+/* The functions by which the transport class and the driver communicate */
+struct fc_function_template {
+ void (*get_rport_dev_loss_tmo)(struct fc_rport *);
+ void (*set_rport_dev_loss_tmo)(struct fc_rport *, u32);
+
+ void (*get_starget_node_name)(struct scsi_target *);
+ void (*get_starget_port_name)(struct scsi_target *);
+ void (*get_starget_port_id)(struct scsi_target *);
+
+ void (*get_host_port_id)(struct Scsi_Host *);
+ void (*get_host_port_type)(struct Scsi_Host *);
+ void (*get_host_port_state)(struct Scsi_Host *);
+ void (*get_host_active_fc4s)(struct Scsi_Host *);
+ void (*get_host_speed)(struct Scsi_Host *);
+ void (*get_host_fabric_name)(struct Scsi_Host *);
+ void (*get_host_symbolic_name)(struct Scsi_Host *);
+ void (*set_host_system_hostname)(struct Scsi_Host *);
+
+ struct fc_host_statistics * (*get_fc_host_stats)(struct Scsi_Host *);
+ void (*reset_fc_host_stats)(struct Scsi_Host *);
+
+ int (*issue_fc_host_lip)(struct Scsi_Host *);
+
+ void (*dev_loss_tmo_callbk)(struct fc_rport *);
+ void (*terminate_rport_io)(struct fc_rport *);
+
+ void (*set_vport_symbolic_name)(struct fc_vport *);
+ int (*vport_create)(struct fc_vport *, bool);
+ int (*vport_disable)(struct fc_vport *, bool);
+ int (*vport_delete)(struct fc_vport *);
+
+ /* bsg support */
+ int (*bsg_request)(struct bsg_job *);
+ int (*bsg_timeout)(struct bsg_job *);
+
+ /* allocation lengths for host-specific data */
+ u32 dd_fcrport_size;
+ u32 dd_fcvport_size;
+ u32 dd_bsg_size;
+
+ /*
+ * The driver sets these to tell the transport class it
+ * wants the attributes displayed in sysfs. If the show_ flag
+ * is not set, the attribute will be private to the transport
+ * class
+ */
+
+ /* remote port fixed attributes */
+ unsigned long show_rport_maxframe_size:1;
+ unsigned long show_rport_supported_classes:1;
+ unsigned long show_rport_dev_loss_tmo:1;
+
+ /*
+ * target dynamic attributes
+ * These should all be "1" if the driver uses the remote port
+ * add/delete functions (so attributes reflect rport values).
+ */
+ unsigned long show_starget_node_name:1;
+ unsigned long show_starget_port_name:1;
+ unsigned long show_starget_port_id:1;
+
+ /* host fixed attributes */
+ unsigned long show_host_node_name:1;
+ unsigned long show_host_port_name:1;
+ unsigned long show_host_permanent_port_name:1;
+ unsigned long show_host_supported_classes:1;
+ unsigned long show_host_supported_fc4s:1;
+ unsigned long show_host_supported_speeds:1;
+ unsigned long show_host_maxframe_size:1;
+ unsigned long show_host_serial_number:1;
+ unsigned long show_host_manufacturer:1;
+ unsigned long show_host_model:1;
+ unsigned long show_host_model_description:1;
+ unsigned long show_host_hardware_version:1;
+ unsigned long show_host_driver_version:1;
+ unsigned long show_host_firmware_version:1;
+ unsigned long show_host_optionrom_version:1;
+ /* host dynamic attributes */
+ unsigned long show_host_port_id:1;
+ unsigned long show_host_port_type:1;
+ unsigned long show_host_port_state:1;
+ unsigned long show_host_active_fc4s:1;
+ unsigned long show_host_speed:1;
+ unsigned long show_host_fabric_name:1;
+ unsigned long show_host_symbolic_name:1;
+ unsigned long show_host_system_hostname:1;
+
+ unsigned long disable_target_scan:1;
+};
+
+/**
+ * fc_remote_port_chkready - called to validate the remote port state
+ * prior to initiating io to the port.
+ *
+ * Returns a scsi result code that can be returned by the LLDD.
+ *
+ * @rport: remote port to be checked
+ **/
+static inline int
+fc_remote_port_chkready(struct fc_rport *rport)
+{
+ int result;
+
+ switch (rport->port_state) {
+ case FC_PORTSTATE_ONLINE:
+ case FC_PORTSTATE_MARGINAL:
+ if (rport->roles & FC_PORT_ROLE_FCP_TARGET)
+ result = 0;
+ else if (rport->flags & FC_RPORT_DEVLOSS_PENDING)
+ result = DID_IMM_RETRY << 16;
+ else
+ result = DID_NO_CONNECT << 16;
+ break;
+ case FC_PORTSTATE_BLOCKED:
+ if (rport->flags & FC_RPORT_FAST_FAIL_TIMEDOUT)
+ result = DID_TRANSPORT_FAILFAST << 16;
+ else
+ result = DID_IMM_RETRY << 16;
+ break;
+ default:
+ result = DID_NO_CONNECT << 16;
+ break;
+ }
+ return result;
+}
+
+static inline u64 wwn_to_u64(const u8 *wwn)
+{
+ return get_unaligned_be64(wwn);
+}
+
+static inline void u64_to_wwn(u64 inm, u8 *wwn)
+{
+ put_unaligned_be64(inm, wwn);
+}
+
+/**
+ * fc_vport_set_state() - called to set a vport's state. Saves the old state,
+ * excepting the transitory states of initializing and sending the ELS
+ * traffic to instantiate the vport on the link.
+ *
+ * Assumes the driver has surrounded this with the proper locking to ensure
+ * a coherent state change.
+ *
+ * @vport: virtual port whose state is changing
+ * @new_state: new state
+ **/
+static inline void
+fc_vport_set_state(struct fc_vport *vport, enum fc_vport_state new_state)
+{
+ if ((new_state != FC_VPORT_UNKNOWN) &&
+ (new_state != FC_VPORT_INITIALIZING))
+ vport->vport_last_state = vport->vport_state;
+ vport->vport_state = new_state;
+}
+
+struct scsi_transport_template *fc_attach_transport(
+ struct fc_function_template *);
+void fc_release_transport(struct scsi_transport_template *);
+void fc_remove_host(struct Scsi_Host *);
+struct fc_rport *fc_remote_port_add(struct Scsi_Host *shost,
+ int channel, struct fc_rport_identifiers *ids);
+void fc_remote_port_delete(struct fc_rport *rport);
+void fc_remote_port_rolechg(struct fc_rport *rport, u32 roles);
+int scsi_is_fc_rport(const struct device *);
+u32 fc_get_event_number(void);
+void fc_host_post_event(struct Scsi_Host *shost, u32 event_number,
+ enum fc_host_event_code event_code, u32 event_data);
+void fc_host_post_vendor_event(struct Scsi_Host *shost, u32 event_number,
+ u32 data_len, char *data_buf, u64 vendor_id);
+struct fc_rport *fc_find_rport_by_wwpn(struct Scsi_Host *shost, u64 wwpn);
+void fc_host_post_fc_event(struct Scsi_Host *shost, u32 event_number,
+ enum fc_host_event_code event_code,
+ u32 data_len, char *data_buf, u64 vendor_id);
+ /* Note: when specifying vendor_id to fc_host_post_vendor_event()
+ * or fc_host_post_fc_event(), be sure to read the Vendor Type
+ * and ID formatting requirements specified in scsi_netlink.h
+ * Note: when calling fc_host_post_fc_event(), vendor_id may be
+ * specified as 0.
+ */
+void fc_host_fpin_rcv(struct Scsi_Host *shost, u32 fpin_len, char *fpin_buf);
+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_rport(struct fc_rport *rport);
+int fc_block_scsi_eh(struct scsi_cmnd *cmnd);
+enum blk_eh_timer_return fc_eh_timed_out(struct scsi_cmnd *scmd);
+bool fc_eh_should_retry_cmd(struct scsi_cmnd *scmd);
+
+static inline struct Scsi_Host *fc_bsg_to_shost(struct bsg_job *job)
+{
+ if (scsi_is_host_device(job->dev))
+ return dev_to_shost(job->dev);
+ return rport_to_shost(dev_to_rport(job->dev));
+}
+
+static inline struct fc_rport *fc_bsg_to_rport(struct bsg_job *job)
+{
+ if (scsi_is_fc_rport(job->dev))
+ return dev_to_rport(job->dev);
+ return NULL;
+}
+
+#endif /* SCSI_TRANSPORT_FC_H */
diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h
new file mode 100644
index 000000000..34c03707f
--- /dev/null
+++ b/include/scsi/scsi_transport_iscsi.h
@@ -0,0 +1,509 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * iSCSI transport class definitions
+ *
+ * Copyright (C) IBM Corporation, 2004
+ * Copyright (C) Mike Christie, 2004 - 2006
+ * Copyright (C) Dmitry Yusupov, 2004 - 2005
+ * Copyright (C) Alex Aizman, 2004 - 2005
+ */
+#ifndef SCSI_TRANSPORT_ISCSI_H
+#define SCSI_TRANSPORT_ISCSI_H
+
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <scsi/iscsi_if.h>
+
+struct scsi_transport_template;
+struct iscsi_transport;
+struct iscsi_endpoint;
+struct Scsi_Host;
+struct scsi_cmnd;
+struct iscsi_cls_conn;
+struct iscsi_conn;
+struct iscsi_task;
+struct sockaddr;
+struct iscsi_iface;
+struct bsg_job;
+struct iscsi_bus_flash_session;
+struct iscsi_bus_flash_conn;
+
+/**
+ * struct iscsi_transport - iSCSI Transport template
+ *
+ * @name: transport name
+ * @caps: iSCSI Data-Path capabilities
+ * @create_session: create new iSCSI session object
+ * @destroy_session: destroy existing iSCSI session object
+ * @create_conn: create new iSCSI connection
+ * @bind_conn: associate this connection with existing iSCSI session
+ * and specified transport descriptor
+ * @destroy_conn: destroy inactive iSCSI connection
+ * @set_param: set iSCSI parameter. Return 0 on success, -ENODATA
+ * when param is not supported, and a -Exx value on other
+ * error.
+ * @get_param get iSCSI parameter. Must return number of bytes
+ * copied to buffer on success, -ENODATA when param
+ * is not supported, and a -Exx value on other error
+ * @start_conn: set connection to be operational
+ * @stop_conn: suspend/recover/terminate connection
+ * @send_pdu: send iSCSI PDU, Login, Logout, NOP-Out, Reject, Text.
+ * @session_recovery_timedout: notify LLD a block during recovery timed out
+ * @init_task: Initialize a iscsi_task and any internal structs.
+ * When offloading the data path, this is called from
+ * queuecommand with the session lock, or from the
+ * iscsi_conn_send_pdu context with the session lock.
+ * When not offloading the data path, this is called
+ * from the scsi work queue without the session lock.
+ * @xmit_task Requests LLD to transfer cmd task. Returns 0 or the
+ * number of bytes transferred on success, and -Exyz
+ * value on error. When offloading the data path, this
+ * is called from queuecommand with the session lock, or
+ * from the iscsi_conn_send_pdu context with the session
+ * lock. When not offloading the data path, this is called
+ * from the scsi work queue without the session lock.
+ * @cleanup_task: requests LLD to fail task. Called with session lock
+ * and after the connection has been suspended and
+ * terminated during recovery. If called
+ * from abort task then connection is not suspended
+ * or terminated but sk_callback_lock is held
+ *
+ * Template API provided by iSCSI Transport
+ */
+struct iscsi_transport {
+ struct module *owner;
+ char *name;
+ unsigned int caps;
+
+ struct iscsi_cls_session *(*create_session) (struct iscsi_endpoint *ep,
+ uint16_t cmds_max, uint16_t qdepth,
+ uint32_t sn);
+ void (*destroy_session) (struct iscsi_cls_session *session);
+ struct iscsi_cls_conn *(*create_conn) (struct iscsi_cls_session *sess,
+ uint32_t cid);
+ void (*unbind_conn) (struct iscsi_cls_conn *conn, bool is_active);
+ int (*bind_conn) (struct iscsi_cls_session *session,
+ struct iscsi_cls_conn *cls_conn,
+ uint64_t transport_eph, int is_leading);
+ int (*start_conn) (struct iscsi_cls_conn *conn);
+ void (*stop_conn) (struct iscsi_cls_conn *conn, int flag);
+ void (*destroy_conn) (struct iscsi_cls_conn *conn);
+ int (*set_param) (struct iscsi_cls_conn *conn, enum iscsi_param param,
+ char *buf, int buflen);
+ int (*get_ep_param) (struct iscsi_endpoint *ep, enum iscsi_param param,
+ char *buf);
+ int (*get_conn_param) (struct iscsi_cls_conn *conn,
+ enum iscsi_param param, char *buf);
+ int (*get_session_param) (struct iscsi_cls_session *session,
+ enum iscsi_param param, char *buf);
+ int (*get_host_param) (struct Scsi_Host *shost,
+ enum iscsi_host_param param, char *buf);
+ int (*set_host_param) (struct Scsi_Host *shost,
+ enum iscsi_host_param param, char *buf,
+ int buflen);
+ int (*send_pdu) (struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
+ char *data, uint32_t data_size);
+ void (*get_stats) (struct iscsi_cls_conn *conn,
+ struct iscsi_stats *stats);
+
+ int (*init_task) (struct iscsi_task *task);
+ int (*xmit_task) (struct iscsi_task *task);
+ void (*cleanup_task) (struct iscsi_task *task);
+
+ int (*alloc_pdu) (struct iscsi_task *task, uint8_t opcode);
+ int (*xmit_pdu) (struct iscsi_task *task);
+ int (*init_pdu) (struct iscsi_task *task, unsigned int offset,
+ unsigned int count);
+ void (*parse_pdu_itt) (struct iscsi_conn *conn, itt_t itt,
+ int *index, int *age);
+
+ void (*session_recovery_timedout) (struct iscsi_cls_session *session);
+ struct iscsi_endpoint *(*ep_connect) (struct Scsi_Host *shost,
+ struct sockaddr *dst_addr,
+ int non_blocking);
+ int (*ep_poll) (struct iscsi_endpoint *ep, int timeout_ms);
+ void (*ep_disconnect) (struct iscsi_endpoint *ep);
+ int (*tgt_dscvr) (struct Scsi_Host *shost, enum iscsi_tgt_dscvr type,
+ uint32_t enable, struct sockaddr *dst_addr);
+ int (*set_path) (struct Scsi_Host *shost, struct iscsi_path *params);
+ int (*set_iface_param) (struct Scsi_Host *shost, void *data,
+ uint32_t len);
+ int (*get_iface_param) (struct iscsi_iface *iface,
+ enum iscsi_param_type param_type,
+ int param, char *buf);
+ umode_t (*attr_is_visible)(int param_type, int param);
+ int (*bsg_request)(struct bsg_job *job);
+ int (*send_ping) (struct Scsi_Host *shost, uint32_t iface_num,
+ uint32_t iface_type, uint32_t payload_size,
+ uint32_t pid, struct sockaddr *dst_addr);
+ int (*get_chap) (struct Scsi_Host *shost, uint16_t chap_tbl_idx,
+ uint32_t *num_entries, char *buf);
+ int (*delete_chap) (struct Scsi_Host *shost, uint16_t chap_tbl_idx);
+ int (*set_chap) (struct Scsi_Host *shost, void *data, int len);
+ int (*get_flashnode_param) (struct iscsi_bus_flash_session *fnode_sess,
+ int param, char *buf);
+ int (*set_flashnode_param) (struct iscsi_bus_flash_session *fnode_sess,
+ struct iscsi_bus_flash_conn *fnode_conn,
+ void *data, int len);
+ int (*new_flashnode) (struct Scsi_Host *shost, const char *buf,
+ int len);
+ int (*del_flashnode) (struct iscsi_bus_flash_session *fnode_sess);
+ int (*login_flashnode) (struct iscsi_bus_flash_session *fnode_sess,
+ struct iscsi_bus_flash_conn *fnode_conn);
+ int (*logout_flashnode) (struct iscsi_bus_flash_session *fnode_sess,
+ struct iscsi_bus_flash_conn *fnode_conn);
+ int (*logout_flashnode_sid) (struct iscsi_cls_session *cls_sess);
+ int (*get_host_stats) (struct Scsi_Host *shost, char *buf, int len);
+ u8 (*check_protection)(struct iscsi_task *task, sector_t *sector);
+};
+
+/*
+ * transport registration upcalls
+ */
+extern struct scsi_transport_template *iscsi_register_transport(struct iscsi_transport *tt);
+extern void iscsi_unregister_transport(struct iscsi_transport *tt);
+
+/*
+ * control plane upcalls
+ */
+extern void iscsi_conn_error_event(struct iscsi_cls_conn *conn,
+ enum iscsi_err error);
+extern void iscsi_conn_login_event(struct iscsi_cls_conn *conn,
+ enum iscsi_conn_state state);
+extern int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
+ char *data, uint32_t data_size);
+
+extern int iscsi_offload_mesg(struct Scsi_Host *shost,
+ struct iscsi_transport *transport, uint32_t type,
+ char *data, uint16_t data_size);
+
+extern void iscsi_post_host_event(uint32_t host_no,
+ struct iscsi_transport *transport,
+ enum iscsi_host_event_code code,
+ uint32_t data_size,
+ uint8_t *data);
+
+extern void iscsi_ping_comp_event(uint32_t host_no,
+ struct iscsi_transport *transport,
+ uint32_t status, uint32_t pid,
+ uint32_t data_size, uint8_t *data);
+
+/* iscsi class connection state */
+enum iscsi_connection_state {
+ ISCSI_CONN_UP = 0,
+ ISCSI_CONN_DOWN,
+ ISCSI_CONN_FAILED,
+ ISCSI_CONN_BOUND,
+};
+
+#define ISCSI_CLS_CONN_BIT_CLEANUP 1
+
+struct iscsi_cls_conn {
+ struct list_head conn_list; /* item in connlist */
+ void *dd_data; /* LLD private data */
+ struct iscsi_transport *transport;
+ uint32_t cid; /* connection id */
+ /*
+ * This protects the conn startup and binding/unbinding of the ep to
+ * the conn. Unbinding includes ep_disconnect and stop_conn.
+ */
+ struct mutex ep_mutex;
+ struct iscsi_endpoint *ep;
+
+ /* Used when accessing flags and queueing work. */
+ spinlock_t lock;
+ unsigned long flags;
+ struct work_struct cleanup_work;
+
+ struct device dev; /* sysfs transport/container device */
+ enum iscsi_connection_state state;
+};
+
+#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,
+};
+
+enum {
+ ISCSI_SESSION_TARGET_UNBOUND,
+ ISCSI_SESSION_TARGET_ALLOCATED,
+ ISCSI_SESSION_TARGET_SCANNED,
+ ISCSI_SESSION_TARGET_UNBINDING,
+ ISCSI_SESSION_TARGET_MAX,
+};
+
+#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;
+ struct work_struct destroy_work;
+
+ /* recovery fields */
+ int recovery_tmo;
+ bool recovery_tmo_sysfs_override;
+ struct delayed_work recovery_work;
+
+ struct workqueue_struct *workq;
+
+ 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 target_state; /* session target bind 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 {
+ 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;
+ int id;
+ struct iscsi_cls_conn *conn;
+};
+
+struct iscsi_iface {
+ struct device dev;
+ struct iscsi_transport *transport;
+ uint32_t iface_type; /* IPv4 or IPv6 */
+ uint32_t iface_num; /* iface number, 0 - n */
+ void *dd_data; /* LLD private data */
+};
+
+#define iscsi_dev_to_iface(_dev) \
+ container_of(_dev, struct iscsi_iface, dev)
+
+#define iscsi_iface_to_shost(_iface) \
+ dev_to_shost(_iface->dev.parent)
+
+
+struct iscsi_bus_flash_conn {
+ struct list_head conn_list; /* item in connlist */
+ void *dd_data; /* LLD private data */
+ struct iscsi_transport *transport;
+ struct device dev; /* sysfs transport/container device */
+ /* iscsi connection parameters */
+ uint32_t exp_statsn;
+ uint32_t statsn;
+ unsigned max_recv_dlength; /* initiator_max_recv_dsl*/
+ unsigned max_xmit_dlength; /* target_max_recv_dsl */
+ unsigned max_segment_size;
+ unsigned tcp_xmit_wsf;
+ unsigned tcp_recv_wsf;
+ int hdrdgst_en;
+ int datadgst_en;
+ int port;
+ char *ipaddress;
+ char *link_local_ipv6_addr;
+ char *redirect_ipaddr;
+ uint16_t keepalive_timeout;
+ uint16_t local_port;
+ uint8_t snack_req_en;
+ /* tcp timestamp negotiation status */
+ uint8_t tcp_timestamp_stat;
+ uint8_t tcp_nagle_disable;
+ /* tcp window scale factor */
+ uint8_t tcp_wsf_disable;
+ uint8_t tcp_timer_scale;
+ uint8_t tcp_timestamp_en;
+ uint8_t ipv4_tos;
+ uint8_t ipv6_traffic_class;
+ uint8_t ipv6_flow_label;
+ uint8_t fragment_disable;
+ /* Link local IPv6 address is assigned by firmware or driver */
+ uint8_t is_fw_assigned_ipv6;
+};
+
+#define iscsi_dev_to_flash_conn(_dev) \
+ container_of(_dev, struct iscsi_bus_flash_conn, dev)
+
+#define iscsi_flash_conn_to_flash_session(_conn) \
+ iscsi_dev_to_flash_session(_conn->dev.parent)
+
+#define ISID_SIZE 6
+
+struct iscsi_bus_flash_session {
+ struct list_head sess_list; /* item in session_list */
+ struct iscsi_transport *transport;
+ unsigned int target_id;
+ int flash_state; /* persistent or non-persistent */
+ void *dd_data; /* LLD private data */
+ struct device dev; /* sysfs transport/container device */
+ /* iscsi session parameters */
+ unsigned first_burst;
+ unsigned max_burst;
+ unsigned short max_r2t;
+ int default_taskmgmt_timeout;
+ int initial_r2t_en;
+ int imm_data_en;
+ int time2wait;
+ int time2retain;
+ int pdu_inorder_en;
+ int dataseq_inorder_en;
+ int erl;
+ int tpgt;
+ char *username;
+ char *username_in;
+ char *password;
+ char *password_in;
+ char *targetname;
+ char *targetalias;
+ char *portal_type;
+ uint16_t tsid;
+ uint16_t chap_in_idx;
+ uint16_t chap_out_idx;
+ /* index of iSCSI discovery session if the entry is
+ * discovered by iSCSI discovery session
+ */
+ uint16_t discovery_parent_idx;
+ /* indicates if discovery was done through iSNS discovery service
+ * or through sendTarget */
+ uint16_t discovery_parent_type;
+ /* Firmware auto sendtarget discovery disable */
+ uint8_t auto_snd_tgt_disable;
+ uint8_t discovery_sess;
+ /* indicates if this flashnode entry is enabled or disabled */
+ uint8_t entry_state;
+ uint8_t chap_auth_en;
+ /* enables firmware to auto logout the discovery session on discovery
+ * completion
+ */
+ uint8_t discovery_logout_en;
+ uint8_t bidi_chap_en;
+ /* makes authentication for discovery session optional */
+ uint8_t discovery_auth_optional;
+ uint8_t isid[ISID_SIZE];
+ uint8_t is_boot_target;
+};
+
+#define iscsi_dev_to_flash_session(_dev) \
+ container_of(_dev, struct iscsi_bus_flash_session, dev)
+
+#define iscsi_flash_session_to_shost(_session) \
+ dev_to_shost(_session->dev.parent)
+
+/*
+ * session and connection functions that can be used by HW iSCSI LLDs
+ */
+#define iscsi_cls_session_printk(prefix, _cls_session, fmt, a...) \
+ dev_printk(prefix, &(_cls_session)->dev, fmt, ##a)
+
+#define iscsi_cls_conn_printk(prefix, _cls_conn, fmt, a...) \
+ dev_printk(prefix, &(_cls_conn)->dev, fmt, ##a)
+
+extern int iscsi_session_chkready(struct iscsi_cls_session *session);
+extern int iscsi_is_session_online(struct iscsi_cls_session *session);
+extern struct iscsi_cls_session *iscsi_alloc_session(struct Scsi_Host *shost,
+ struct iscsi_transport *transport, int dd_size);
+extern int iscsi_add_session(struct iscsi_cls_session *session,
+ unsigned int target_id);
+extern int iscsi_session_event(struct iscsi_cls_session *session,
+ enum iscsi_uevent_e event);
+extern struct iscsi_cls_session *iscsi_create_session(struct Scsi_Host *shost,
+ struct iscsi_transport *t,
+ int dd_size,
+ unsigned int target_id);
+extern void iscsi_force_destroy_session(struct iscsi_cls_session *session);
+extern void iscsi_remove_session(struct iscsi_cls_session *session);
+extern void iscsi_free_session(struct iscsi_cls_session *session);
+extern struct iscsi_cls_conn *iscsi_alloc_conn(struct iscsi_cls_session *sess,
+ int dd_size, uint32_t cid);
+extern int iscsi_add_conn(struct iscsi_cls_conn *conn);
+extern void iscsi_remove_conn(struct iscsi_cls_conn *conn);
+extern void iscsi_put_conn(struct iscsi_cls_conn *conn);
+extern void iscsi_get_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 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 void iscsi_put_endpoint(struct iscsi_endpoint *ep);
+extern int iscsi_block_scsi_eh(struct scsi_cmnd *cmd);
+extern struct iscsi_iface *iscsi_create_iface(struct Scsi_Host *shost,
+ struct iscsi_transport *t,
+ uint32_t iface_type,
+ uint32_t iface_num, int dd_size);
+extern void iscsi_destroy_iface(struct iscsi_iface *iface);
+extern struct iscsi_iface *iscsi_lookup_iface(int handle);
+extern char *iscsi_get_port_speed_name(struct Scsi_Host *shost);
+extern char *iscsi_get_port_state_name(struct Scsi_Host *shost);
+extern int iscsi_is_session_dev(const struct device *dev);
+
+extern char *iscsi_get_discovery_parent_name(int parent_type);
+extern struct device *
+iscsi_find_flashnode(struct Scsi_Host *shost, void *data,
+ int (*fn)(struct device *dev, void *data));
+
+extern struct iscsi_bus_flash_session *
+iscsi_create_flashnode_sess(struct Scsi_Host *shost, int index,
+ struct iscsi_transport *transport, int dd_size);
+
+extern struct iscsi_bus_flash_conn *
+iscsi_create_flashnode_conn(struct Scsi_Host *shost,
+ struct iscsi_bus_flash_session *fnode_sess,
+ struct iscsi_transport *transport, int dd_size);
+
+extern void
+iscsi_destroy_flashnode_sess(struct iscsi_bus_flash_session *fnode_sess);
+
+extern void iscsi_destroy_all_flashnode(struct Scsi_Host *shost);
+extern int iscsi_flashnode_bus_match(struct device *dev,
+ struct device_driver *drv);
+extern struct device *
+iscsi_find_flashnode_sess(struct Scsi_Host *shost, void *data,
+ int (*fn)(struct device *dev, void *data));
+extern struct device *
+iscsi_find_flashnode_conn(struct iscsi_bus_flash_session *fnode_sess);
+
+extern char *
+iscsi_get_ipaddress_state_name(enum iscsi_ipaddress_state port_state);
+extern char *iscsi_get_router_state_name(enum iscsi_router_state router_state);
+#endif
diff --git a/include/scsi/scsi_transport_sas.h b/include/scsi/scsi_transport_sas.h
new file mode 100644
index 000000000..0e75b9277
--- /dev/null
+++ b/include/scsi/scsi_transport_sas.h
@@ -0,0 +1,245 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef SCSI_TRANSPORT_SAS_H
+#define SCSI_TRANSPORT_SAS_H
+
+#include <linux/transport_class.h>
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <scsi/sas.h>
+#include <linux/bsg-lib.h>
+
+struct scsi_transport_template;
+struct sas_rphy;
+struct request;
+
+#if !IS_ENABLED(CONFIG_SCSI_SAS_ATTRS)
+static inline int scsi_is_sas_rphy(const struct device *sdev)
+{
+ return 0;
+}
+#else
+extern int scsi_is_sas_rphy(const struct device *);
+#endif
+
+static inline int sas_protocol_ata(enum sas_protocol proto)
+{
+ return ((proto & SAS_PROTOCOL_SATA) ||
+ (proto & SAS_PROTOCOL_STP))? 1 : 0;
+}
+
+enum sas_linkrate {
+ /* These Values are defined in the SAS standard */
+ SAS_LINK_RATE_UNKNOWN = 0,
+ SAS_PHY_DISABLED = 1,
+ SAS_PHY_RESET_PROBLEM = 2,
+ SAS_SATA_SPINUP_HOLD = 3,
+ SAS_SATA_PORT_SELECTOR = 4,
+ SAS_PHY_RESET_IN_PROGRESS = 5,
+ SAS_LINK_RATE_1_5_GBPS = 8,
+ SAS_LINK_RATE_G1 = SAS_LINK_RATE_1_5_GBPS,
+ SAS_LINK_RATE_3_0_GBPS = 9,
+ SAS_LINK_RATE_G2 = SAS_LINK_RATE_3_0_GBPS,
+ SAS_LINK_RATE_6_0_GBPS = 10,
+ SAS_LINK_RATE_12_0_GBPS = 11,
+ SAS_LINK_RATE_22_5_GBPS = 12,
+ /* These are virtual to the transport class and may never
+ * be signalled normally since the standard defined field
+ * is only 4 bits */
+ SAS_LINK_RATE_FAILED = 0x10,
+ SAS_PHY_VIRTUAL = 0x11,
+};
+
+struct sas_identify {
+ enum sas_device_type device_type;
+ enum sas_protocol initiator_port_protocols;
+ enum sas_protocol target_port_protocols;
+ u64 sas_address;
+ u8 phy_identifier;
+};
+
+struct sas_phy {
+ struct device dev;
+ int number;
+ int enabled;
+
+ /* phy identification */
+ struct sas_identify identify;
+
+ /* phy attributes */
+ enum sas_linkrate negotiated_linkrate;
+ enum sas_linkrate minimum_linkrate_hw;
+ enum sas_linkrate minimum_linkrate;
+ enum sas_linkrate maximum_linkrate_hw;
+ enum sas_linkrate maximum_linkrate;
+
+ /* link error statistics */
+ u32 invalid_dword_count;
+ u32 running_disparity_error_count;
+ u32 loss_of_dword_sync_count;
+ u32 phy_reset_problem_count;
+
+ /* for the list of phys belonging to a port */
+ struct list_head port_siblings;
+
+ /* available to the lldd */
+ void *hostdata;
+};
+
+#define dev_to_phy(d) \
+ container_of((d), struct sas_phy, dev)
+#define transport_class_to_phy(dev) \
+ dev_to_phy((dev)->parent)
+#define phy_to_shost(phy) \
+ dev_to_shost((phy)->dev.parent)
+
+struct request_queue;
+struct sas_rphy {
+ struct device dev;
+ struct sas_identify identify;
+ struct list_head list;
+ struct request_queue *q;
+ u32 scsi_target_id;
+};
+
+#define dev_to_rphy(d) \
+ container_of((d), struct sas_rphy, dev)
+#define transport_class_to_rphy(dev) \
+ dev_to_rphy((dev)->parent)
+#define rphy_to_shost(rphy) \
+ dev_to_shost((rphy)->dev.parent)
+#define target_to_rphy(targ) \
+ dev_to_rphy((targ)->dev.parent)
+
+struct sas_end_device {
+ struct sas_rphy rphy;
+ /* flags */
+ unsigned ready_led_meaning:1;
+ unsigned tlr_supported:1;
+ unsigned tlr_enabled:1;
+ /* parameters */
+ u16 I_T_nexus_loss_timeout;
+ u16 initiator_response_timeout;
+};
+#define rphy_to_end_device(r) \
+ container_of((r), struct sas_end_device, rphy)
+
+struct sas_expander_device {
+ int level;
+ int next_port_id;
+
+ #define SAS_EXPANDER_VENDOR_ID_LEN 8
+ char vendor_id[SAS_EXPANDER_VENDOR_ID_LEN+1];
+ #define SAS_EXPANDER_PRODUCT_ID_LEN 16
+ char product_id[SAS_EXPANDER_PRODUCT_ID_LEN+1];
+ #define SAS_EXPANDER_PRODUCT_REV_LEN 4
+ char product_rev[SAS_EXPANDER_PRODUCT_REV_LEN+1];
+ #define SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN 8
+ char component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN+1];
+ u16 component_id;
+ u8 component_revision_id;
+
+ struct sas_rphy rphy;
+
+};
+#define rphy_to_expander_device(r) \
+ container_of((r), struct sas_expander_device, rphy)
+
+struct sas_port {
+ struct device dev;
+
+ int port_identifier;
+ int num_phys;
+ /* port flags */
+ unsigned int is_backlink:1;
+
+ /* the other end of the link */
+ struct sas_rphy *rphy;
+
+ struct mutex phy_list_mutex;
+ struct list_head phy_list;
+ struct list_head del_list; /* libsas only */
+};
+
+#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 *);
+ void (*smp_handler)(struct bsg_job *, struct Scsi_Host *,
+ struct sas_rphy *);
+};
+
+
+void sas_remove_children(struct device *);
+extern void sas_remove_host(struct Scsi_Host *);
+
+extern struct sas_phy *sas_phy_alloc(struct device *, int);
+extern void sas_phy_free(struct sas_phy *);
+extern int sas_phy_add(struct sas_phy *);
+extern void sas_phy_delete(struct sas_phy *);
+extern int scsi_is_sas_phy(const struct device *);
+
+u64 sas_get_address(struct scsi_device *);
+unsigned int sas_tlr_supported(struct scsi_device *);
+unsigned int sas_is_tlr_enabled(struct scsi_device *);
+void sas_disable_tlr(struct scsi_device *);
+void sas_enable_tlr(struct scsi_device *);
+
+extern struct sas_rphy *sas_end_device_alloc(struct sas_port *);
+extern struct sas_rphy *sas_expander_alloc(struct sas_port *, enum sas_device_type);
+void sas_rphy_free(struct sas_rphy *);
+extern int sas_rphy_add(struct sas_rphy *);
+extern void sas_rphy_remove(struct sas_rphy *);
+extern void sas_rphy_delete(struct sas_rphy *);
+extern void sas_rphy_unlink(struct sas_rphy *);
+
+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
new file mode 100644
index 000000000..78324502b
--- /dev/null
+++ b/include/scsi/scsi_transport_spi.h
@@ -0,0 +1,149 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Parallel SCSI (SPI) transport specific attributes exported to sysfs.
+ *
+ * Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved.
+ */
+#ifndef SCSI_TRANSPORT_SPI_H
+#define SCSI_TRANSPORT_SPI_H
+
+#include <linux/transport_class.h>
+#include <linux/mutex.h>
+
+struct scsi_transport_template;
+struct scsi_target;
+struct scsi_device;
+struct Scsi_Host;
+
+struct spi_transport_attrs {
+ int period; /* value in the PPR/SDTR command */
+ int min_period;
+ int offset;
+ int max_offset;
+ unsigned int width:1; /* 0 - narrow, 1 - wide */
+ unsigned int max_width:1;
+ unsigned int iu:1; /* Information Units enabled */
+ unsigned int max_iu:1;
+ unsigned int dt:1; /* DT clocking enabled */
+ unsigned int qas:1; /* Quick Arbitration and Selection enabled */
+ unsigned int max_qas:1;
+ unsigned int wr_flow:1; /* Write Flow control enabled */
+ unsigned int rd_strm:1; /* Read streaming enabled */
+ unsigned int rti:1; /* Retain Training Information */
+ unsigned int pcomp_en:1;/* Precompensation enabled */
+ unsigned int hold_mcs:1;/* Hold Margin Control Settings */
+ unsigned int initial_dv:1; /* DV done to this target yet */
+ unsigned long flags; /* flags field for drivers to use */
+ /* Device Properties fields */
+ unsigned int support_sync:1; /* synchronous support */
+ unsigned int support_wide:1; /* wide support */
+ unsigned int support_dt:1; /* allows DT phases */
+ unsigned int support_dt_only; /* disallows ST phases */
+ unsigned int support_ius; /* support Information Units */
+ unsigned int support_qas; /* supports quick arbitration and selection */
+ /* Private Fields */
+ unsigned int dv_pending:1; /* Internal flag: DV Requested */
+ unsigned int dv_in_progress:1; /* Internal: DV started */
+ struct mutex dv_mutex; /* semaphore to serialise dv */
+};
+
+enum spi_signal_type {
+ SPI_SIGNAL_UNKNOWN = 1,
+ SPI_SIGNAL_SE,
+ SPI_SIGNAL_LVD,
+ SPI_SIGNAL_HVD,
+};
+
+struct spi_host_attrs {
+ enum spi_signal_type signalling;
+};
+
+/* accessor functions */
+#define spi_period(x) (((struct spi_transport_attrs *)&(x)->starget_data)->period)
+#define spi_min_period(x) (((struct spi_transport_attrs *)&(x)->starget_data)->min_period)
+#define spi_offset(x) (((struct spi_transport_attrs *)&(x)->starget_data)->offset)
+#define spi_max_offset(x) (((struct spi_transport_attrs *)&(x)->starget_data)->max_offset)
+#define spi_width(x) (((struct spi_transport_attrs *)&(x)->starget_data)->width)
+#define spi_max_width(x) (((struct spi_transport_attrs *)&(x)->starget_data)->max_width)
+#define spi_iu(x) (((struct spi_transport_attrs *)&(x)->starget_data)->iu)
+#define spi_max_iu(x) (((struct spi_transport_attrs *)&(x)->starget_data)->max_iu)
+#define spi_dt(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dt)
+#define spi_qas(x) (((struct spi_transport_attrs *)&(x)->starget_data)->qas)
+#define spi_max_qas(x) (((struct spi_transport_attrs *)&(x)->starget_data)->max_qas)
+#define spi_wr_flow(x) (((struct spi_transport_attrs *)&(x)->starget_data)->wr_flow)
+#define spi_rd_strm(x) (((struct spi_transport_attrs *)&(x)->starget_data)->rd_strm)
+#define spi_rti(x) (((struct spi_transport_attrs *)&(x)->starget_data)->rti)
+#define spi_pcomp_en(x) (((struct spi_transport_attrs *)&(x)->starget_data)->pcomp_en)
+#define spi_hold_mcs(x) (((struct spi_transport_attrs *)&(x)->starget_data)->hold_mcs)
+#define spi_initial_dv(x) (((struct spi_transport_attrs *)&(x)->starget_data)->initial_dv)
+#define spi_dv_pending(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_pending)
+
+#define spi_support_sync(x) (((struct spi_transport_attrs *)&(x)->starget_data)->support_sync)
+#define spi_support_wide(x) (((struct spi_transport_attrs *)&(x)->starget_data)->support_wide)
+#define spi_support_dt(x) (((struct spi_transport_attrs *)&(x)->starget_data)->support_dt)
+#define spi_support_dt_only(x) (((struct spi_transport_attrs *)&(x)->starget_data)->support_dt_only)
+#define spi_support_ius(x) (((struct spi_transport_attrs *)&(x)->starget_data)->support_ius)
+#define spi_support_qas(x) (((struct spi_transport_attrs *)&(x)->starget_data)->support_qas)
+
+#define spi_flags(x) (((struct spi_transport_attrs *)&(x)->starget_data)->flags)
+#define spi_signalling(h) (((struct spi_host_attrs *)(h)->shost_data)->signalling)
+
+
+
+/* The functions by which the transport class and the driver communicate */
+struct spi_function_template {
+ void (*get_period)(struct scsi_target *);
+ void (*set_period)(struct scsi_target *, int);
+ void (*get_offset)(struct scsi_target *);
+ void (*set_offset)(struct scsi_target *, int);
+ void (*get_width)(struct scsi_target *);
+ void (*set_width)(struct scsi_target *, int);
+ void (*get_iu)(struct scsi_target *);
+ void (*set_iu)(struct scsi_target *, int);
+ void (*get_dt)(struct scsi_target *);
+ void (*set_dt)(struct scsi_target *, int);
+ void (*get_qas)(struct scsi_target *);
+ void (*set_qas)(struct scsi_target *, int);
+ void (*get_wr_flow)(struct scsi_target *);
+ void (*set_wr_flow)(struct scsi_target *, int);
+ void (*get_rd_strm)(struct scsi_target *);
+ void (*set_rd_strm)(struct scsi_target *, int);
+ void (*get_rti)(struct scsi_target *);
+ void (*set_rti)(struct scsi_target *, int);
+ void (*get_pcomp_en)(struct scsi_target *);
+ void (*set_pcomp_en)(struct scsi_target *, int);
+ void (*get_hold_mcs)(struct scsi_target *);
+ void (*set_hold_mcs)(struct scsi_target *, int);
+ void (*get_signalling)(struct Scsi_Host *);
+ void (*set_signalling)(struct Scsi_Host *, enum spi_signal_type);
+ int (*deny_binding)(struct scsi_target *);
+ /* The driver sets these to tell the transport class it
+ * wants the attributes displayed in sysfs. If the show_ flag
+ * is not set, the attribute will be private to the transport
+ * class */
+ unsigned long show_period:1;
+ unsigned long show_offset:1;
+ unsigned long show_width:1;
+ unsigned long show_iu:1;
+ unsigned long show_dt:1;
+ unsigned long show_qas:1;
+ unsigned long show_wr_flow:1;
+ unsigned long show_rd_strm:1;
+ unsigned long show_rti:1;
+ unsigned long show_pcomp_en:1;
+ unsigned long show_hold_mcs:1;
+};
+
+struct scsi_transport_template *spi_attach_transport(struct spi_function_template *);
+void spi_release_transport(struct scsi_transport_template *);
+void spi_schedule_dv_device(struct scsi_device *);
+void spi_dv_device(struct scsi_device *);
+void spi_display_xfer_agreement(struct scsi_target *);
+int spi_print_msg(const unsigned char *);
+int spi_populate_width_msg(unsigned char *msg, int width);
+int spi_populate_sync_msg(unsigned char *msg, int period, int offset);
+int spi_populate_ppr_msg(unsigned char *msg, int period, int offset, int width,
+ int options);
+int spi_populate_tag_msg(unsigned char *msg, struct scsi_cmnd *cmd);
+
+#endif /* SCSI_TRANSPORT_SPI_H */
diff --git a/include/scsi/scsi_transport_srp.h b/include/scsi/scsi_transport_srp.h
new file mode 100644
index 000000000..d22df1258
--- /dev/null
+++ b/include/scsi/scsi_transport_srp.h
@@ -0,0 +1,145 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#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.
+ */
+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);
+};
+
+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,
+ long dev_loss_tmo);
+int srp_parse_tmo(int *tmo, const char *buf);
+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);
+enum blk_eh_timer_return srp_timed_out(struct scsi_cmnd *scmd);
+
+/**
+ * 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/scsicam.h b/include/scsi/scsicam.h
new file mode 100644
index 000000000..08edd603e
--- /dev/null
+++ b/include/scsi/scsicam.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * scsicam.h - SCSI CAM support functions, use for HDIO_GETGEO, etc.
+ *
+ * Copyright 1993, 1994 Drew Eckhardt
+ * Visionary Computing
+ * (Unix and Linux consulting and custom programming)
+ * drew@Colorado.EDU
+ * +1 (303) 786-7975
+ *
+ * For more information, please consult the SCSI-CAM draft.
+ */
+
+#ifndef SCSICAM_H
+#define SCSICAM_H
+int scsicam_bios_param(struct block_device *bdev, sector_t capacity, int *ip);
+bool scsi_partsize(struct block_device *bdev, sector_t capacity, int geom[3]);
+unsigned char *scsi_bios_ptable(struct block_device *bdev);
+#endif /* def SCSICAM_H */
diff --git a/include/scsi/sg.h b/include/scsi/sg.h
new file mode 100644
index 000000000..068e35d36
--- /dev/null
+++ b/include/scsi/sg.h
@@ -0,0 +1,333 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _SCSI_GENERIC_H
+#define _SCSI_GENERIC_H
+
+#include <linux/compiler.h>
+
+/*
+ * History:
+ * Started: Aug 9 by Lawrence Foard (entropy@world.std.com), to allow user
+ * process control of SCSI devices.
+ * Development Sponsored by Killy Corp. NY NY
+ *
+ * Original driver (sg.h):
+ * Copyright (C) 1992 Lawrence Foard
+ * Version 2 and 3 extensions to driver:
+ * Copyright (C) 1998 - 2014 Douglas Gilbert
+ *
+ * Version: 3.5.36 (20140603)
+ * This version is for 2.6 and 3 series kernels.
+ *
+ * Documentation
+ * =============
+ * A web site for the SG device driver can be found at:
+ * http://sg.danny.cz/sg [alternatively check the MAINTAINERS file]
+ * The documentation for the sg version 3 driver can be found at:
+ * http://sg.danny.cz/sg/p/sg_v3_ho.html
+ * Also see: <kernel_source>/Documentation/scsi/scsi-generic.rst
+ *
+ * For utility and test programs see: http://sg.danny.cz/sg/sg3_utils.html
+ */
+
+
+typedef struct sg_iovec /* same structure as used by readv() Linux system */
+{ /* call. It defines one scatter-gather element. */
+ void __user *iov_base; /* Starting address */
+ size_t iov_len; /* Length in bytes */
+} sg_iovec_t;
+
+
+typedef struct sg_io_hdr
+{
+ int interface_id; /* [i] 'S' for SCSI generic (required) */
+ int dxfer_direction; /* [i] data transfer direction */
+ unsigned char cmd_len; /* [i] SCSI command length */
+ unsigned char mx_sb_len; /* [i] max length to write to sbp */
+ unsigned short iovec_count; /* [i] 0 implies no scatter gather */
+ unsigned int dxfer_len; /* [i] byte count of data transfer */
+ void __user *dxferp; /* [i], [*io] points to data transfer memory
+ or scatter gather list */
+ unsigned char __user *cmdp; /* [i], [*i] points to command to perform */
+ void __user *sbp; /* [i], [*o] points to sense_buffer memory */
+ unsigned int timeout; /* [i] MAX_UINT->no timeout (unit: millisec) */
+ unsigned int flags; /* [i] 0 -> default, see SG_FLAG... */
+ int pack_id; /* [i->o] unused internally (normally) */
+ void __user * usr_ptr; /* [i->o] unused internally */
+ unsigned char status; /* [o] scsi status */
+ unsigned char masked_status;/* [o] shifted, masked scsi status */
+ unsigned char msg_status; /* [o] messaging level data (optional) */
+ unsigned char sb_len_wr; /* [o] byte count actually written to sbp */
+ unsigned short host_status; /* [o] errors from host adapter */
+ unsigned short driver_status;/* [o] errors from software driver */
+ int resid; /* [o] dxfer_len - actual_transferred */
+ unsigned int duration; /* [o] time taken by cmd (unit: millisec) */
+ unsigned int info; /* [o] auxiliary information */
+} sg_io_hdr_t; /* 64 bytes long (on i386) */
+
+#if defined(__KERNEL__)
+#include <linux/compat.h>
+
+struct compat_sg_io_hdr {
+ compat_int_t interface_id; /* [i] 'S' for SCSI generic (required) */
+ compat_int_t dxfer_direction; /* [i] data transfer direction */
+ unsigned char cmd_len; /* [i] SCSI command length ( <= 16 bytes) */
+ unsigned char mx_sb_len; /* [i] max length to write to sbp */
+ unsigned short iovec_count; /* [i] 0 implies no scatter gather */
+ compat_uint_t dxfer_len; /* [i] byte count of data transfer */
+ compat_uint_t dxferp; /* [i], [*io] points to data transfer memory
+ or scatter gather list */
+ compat_uptr_t cmdp; /* [i], [*i] points to command to perform */
+ compat_uptr_t sbp; /* [i], [*o] points to sense_buffer memory */
+ compat_uint_t timeout; /* [i] MAX_UINT->no timeout (unit: millisec) */
+ compat_uint_t flags; /* [i] 0 -> default, see SG_FLAG... */
+ compat_int_t pack_id; /* [i->o] unused internally (normally) */
+ compat_uptr_t usr_ptr; /* [i->o] unused internally */
+ unsigned char status; /* [o] scsi status */
+ unsigned char masked_status; /* [o] shifted, masked scsi status */
+ unsigned char msg_status; /* [o] messaging level data (optional) */
+ unsigned char sb_len_wr; /* [o] byte count actually written to sbp */
+ unsigned short host_status; /* [o] errors from host adapter */
+ unsigned short driver_status; /* [o] errors from software driver */
+ compat_int_t resid; /* [o] dxfer_len - actual_transferred */
+ compat_uint_t duration; /* [o] time taken by cmd (unit: millisec) */
+ compat_uint_t info; /* [o] auxiliary information */
+};
+#endif
+
+#define SG_INTERFACE_ID_ORIG 'S'
+
+/* Use negative values to flag difference from original sg_header structure */
+#define SG_DXFER_NONE (-1) /* e.g. a SCSI Test Unit Ready command */
+#define SG_DXFER_TO_DEV (-2) /* e.g. a SCSI WRITE command */
+#define SG_DXFER_FROM_DEV (-3) /* e.g. a SCSI READ command */
+#define SG_DXFER_TO_FROM_DEV (-4) /* treated like SG_DXFER_FROM_DEV with the
+ additional property than during indirect
+ IO the user buffer is copied into the
+ kernel buffers before the transfer */
+#define SG_DXFER_UNKNOWN (-5) /* Unknown data direction */
+
+/* following flag values can be "or"-ed together */
+#define SG_FLAG_DIRECT_IO 1 /* default is indirect IO */
+#define SG_FLAG_UNUSED_LUN_INHIBIT 2 /* default is overwrite lun in SCSI */
+ /* command block (when <= SCSI_2) */
+#define SG_FLAG_MMAP_IO 4 /* request memory mapped IO */
+#define SG_FLAG_NO_DXFER 0x10000 /* no transfer of kernel buffers to/from */
+ /* user space (debug indirect IO) */
+/* defaults:: for sg driver: Q_AT_HEAD; for block layer: Q_AT_TAIL */
+#define SG_FLAG_Q_AT_TAIL 0x10
+#define SG_FLAG_Q_AT_HEAD 0x20
+
+/* following 'info' values are "or"-ed together */
+#define SG_INFO_OK_MASK 0x1
+#define SG_INFO_OK 0x0 /* no sense, host nor driver "noise" */
+#define SG_INFO_CHECK 0x1 /* something abnormal happened */
+
+#define SG_INFO_DIRECT_IO_MASK 0x6
+#define SG_INFO_INDIRECT_IO 0x0 /* data xfer via kernel buffers (or no xfer) */
+#define SG_INFO_DIRECT_IO 0x2 /* direct IO requested and performed */
+#define SG_INFO_MIXED_IO 0x4 /* part direct, part indirect IO */
+
+/*
+ * Obsolete DRIVER_SENSE driver byte
+ *
+ * Originally the SCSI midlayer would set the DRIVER_SENSE driver byte when
+ * a sense code was generated and a sense buffer was allocated.
+ * However, as nowadays every scsi command has a sense code allocated this
+ * distinction became moot as one could check the sense buffer directly.
+ * Consequently this byte is not set anymore from the midlayer, but SG will
+ * keep setting this byte to be compatible with previous releases.
+ */
+#define DRIVER_SENSE 0x08
+/* Obsolete driver_byte() declaration */
+#define driver_byte(result) (((result) >> 24) & 0xff)
+
+/*
+ * Original linux SCSI Status codes. They are shifted 1 bit right
+ * from those found in the SCSI standards.
+ */
+
+#define GOOD 0x00
+#define CHECK_CONDITION 0x01
+#define CONDITION_GOOD 0x02
+#define BUSY 0x04
+#define INTERMEDIATE_GOOD 0x08
+#define INTERMEDIATE_C_GOOD 0x0a
+#define RESERVATION_CONFLICT 0x0c
+#define COMMAND_TERMINATED 0x11
+#define QUEUE_FULL 0x14
+#define ACA_ACTIVE 0x18
+#define TASK_ABORTED 0x20
+
+/* Obsolete status_byte() declaration */
+#define status_byte(result) (((result) >> 1) & 0x7f)
+
+typedef struct sg_scsi_id { /* used by SG_GET_SCSI_ID ioctl() */
+ int host_no; /* as in "scsi<n>" where 'n' is one of 0, 1, 2 etc */
+ int channel;
+ int scsi_id; /* scsi id of target device */
+ int lun;
+ int scsi_type; /* TYPE_... defined in scsi/scsi.h */
+ short h_cmd_per_lun;/* host (adapter) maximum commands per lun */
+ short d_queue_depth;/* device (or adapter) maximum queue length */
+ int unused[2]; /* probably find a good use, set 0 for now */
+} sg_scsi_id_t; /* 32 bytes long on i386 */
+
+typedef struct sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */
+ char req_state; /* 0 -> not used, 1 -> written, 2 -> ready to read */
+ char orphan; /* 0 -> normal request, 1 -> from interrupted SG_IO */
+ char sg_io_owned; /* 0 -> complete with read(), 1 -> owned by SG_IO */
+ char problem; /* 0 -> no problem detected, 1 -> error to report */
+ int pack_id; /* pack_id associated with request */
+ void __user *usr_ptr; /* user provided pointer (in new interface) */
+ unsigned int duration; /* millisecs elapsed since written (req_state==1)
+ or request duration (req_state==2) */
+ int unused;
+} sg_req_info_t; /* 20 bytes long on i386 */
+
+
+/* IOCTLs: Those ioctls that are relevant to the SG 3.x drivers follow.
+ [Those that only apply to the SG 2.x drivers are at the end of the file.]
+ (_GET_s yield result via 'int *' 3rd argument unless otherwise indicated) */
+
+#define SG_EMULATED_HOST 0x2203 /* true for emulated host adapter (ATAPI) */
+
+/* Used to configure SCSI command transformation layer for ATAPI devices */
+/* Only supported by the ide-scsi driver */
+#define SG_SET_TRANSFORM 0x2204 /* N.B. 3rd arg is not pointer but value: */
+ /* 3rd arg = 0 to disable transform, 1 to enable it */
+#define SG_GET_TRANSFORM 0x2205
+
+#define SG_SET_RESERVED_SIZE 0x2275 /* request a new reserved buffer size */
+#define SG_GET_RESERVED_SIZE 0x2272 /* actual size of reserved buffer */
+
+/* The following ioctl has a 'sg_scsi_id_t *' object as its 3rd argument. */
+#define SG_GET_SCSI_ID 0x2276 /* Yields fd's bus, chan, dev, lun + type */
+/* SCSI id information can also be obtained from SCSI_IOCTL_GET_IDLUN */
+
+/* Override host setting and always DMA using low memory ( <16MB on i386) */
+#define SG_SET_FORCE_LOW_DMA 0x2279 /* 0-> use adapter setting, 1-> force */
+#define SG_GET_LOW_DMA 0x227a /* 0-> use all ram for dma; 1-> low dma ram */
+
+/* When SG_SET_FORCE_PACK_ID set to 1, pack_id is input to read() which
+ tries to fetch a packet with a matching pack_id, waits, or returns EAGAIN.
+ If pack_id is -1 then read oldest waiting. When ...FORCE_PACK_ID set to 0
+ then pack_id ignored by read() and oldest readable fetched. */
+#define SG_SET_FORCE_PACK_ID 0x227b
+#define SG_GET_PACK_ID 0x227c /* Yields oldest readable pack_id (or -1) */
+
+#define SG_GET_NUM_WAITING 0x227d /* Number of commands awaiting read() */
+
+/* Yields max scatter gather tablesize allowed by current host adapter */
+#define SG_GET_SG_TABLESIZE 0x227F /* 0 implies can't do scatter gather */
+
+#define SG_GET_VERSION_NUM 0x2282 /* Example: version 2.1.34 yields 20134 */
+
+/* Returns -EBUSY if occupied. 3rd argument pointer to int (see next) */
+#define SG_SCSI_RESET 0x2284
+/* Associated values that can be given to SG_SCSI_RESET follow.
+ * SG_SCSI_RESET_NO_ESCALATE may be OR-ed to the _DEVICE, _TARGET, _BUS
+ * or _HOST reset value so only that action is attempted. */
+#define SG_SCSI_RESET_NOTHING 0
+#define SG_SCSI_RESET_DEVICE 1
+#define SG_SCSI_RESET_BUS 2
+#define SG_SCSI_RESET_HOST 3
+#define SG_SCSI_RESET_TARGET 4
+#define SG_SCSI_RESET_NO_ESCALATE 0x100
+
+/* synchronous SCSI command ioctl, (only in version 3 interface) */
+#define SG_IO 0x2285 /* similar effect as write() followed by read() */
+
+#define SG_GET_REQUEST_TABLE 0x2286 /* yields table of active requests */
+
+/* How to treat EINTR during SG_IO ioctl(), only in SG 3.x series */
+#define SG_SET_KEEP_ORPHAN 0x2287 /* 1 -> hold for read(), 0 -> drop (def) */
+#define SG_GET_KEEP_ORPHAN 0x2288
+
+/* yields scsi midlevel's access_count for this SCSI device */
+#define SG_GET_ACCESS_COUNT 0x2289
+
+
+#define SG_SCATTER_SZ (8 * 4096)
+/* Largest size (in bytes) a single scatter-gather list element can have.
+ The value used by the driver is 'max(SG_SCATTER_SZ, PAGE_SIZE)'.
+ This value should be a power of 2 (and may be rounded up internally).
+ If scatter-gather is not supported by adapter then this value is the
+ largest data block that can be read/written by a single scsi command. */
+
+#define SG_DEFAULT_RETRIES 0
+
+/* Defaults, commented if they differ from original sg driver */
+#define SG_DEF_FORCE_PACK_ID 0
+#define SG_DEF_KEEP_ORPHAN 0
+#define SG_DEF_RESERVED_SIZE SG_SCATTER_SZ /* load time option */
+
+/* maximum outstanding requests, write() yields EDOM if exceeded */
+#define SG_MAX_QUEUE 16
+
+#define SG_BIG_BUFF SG_DEF_RESERVED_SIZE /* for backward compatibility */
+
+/* Alternate style type names, "..._t" variants preferred */
+typedef struct sg_io_hdr Sg_io_hdr;
+typedef struct sg_io_vec Sg_io_vec;
+typedef struct sg_scsi_id Sg_scsi_id;
+typedef struct sg_req_info Sg_req_info;
+
+
+/* vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */
+/* The older SG interface based on the 'sg_header' structure follows. */
+/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
+
+#define SG_MAX_SENSE 16 /* this only applies to the sg_header interface */
+
+struct sg_header
+{
+ int pack_len; /* [o] reply_len (ie useless), ignored as input */
+ int reply_len; /* [i] max length of expected reply (inc. sg_header) */
+ int pack_id; /* [io] id number of packet (use ints >= 0) */
+ int result; /* [o] 0==ok, else (+ve) Unix errno (best ignored) */
+ unsigned int twelve_byte:1;
+ /* [i] Force 12 byte command length for group 6 & 7 commands */
+ unsigned int target_status:5; /* [o] scsi status from target */
+ unsigned int host_status:8; /* [o] host status (see "DID" codes) */
+ unsigned int driver_status:8; /* [o] driver status+suggestion */
+ unsigned int other_flags:10; /* unused */
+ unsigned char sense_buffer[SG_MAX_SENSE]; /* [o] Output in 3 cases:
+ when target_status is CHECK_CONDITION or
+ when target_status is COMMAND_TERMINATED or
+ when (driver_status & DRIVER_SENSE) is true. */
+}; /* This structure is 36 bytes long on i386 */
+
+
+/* IOCTLs: The following are not required (or ignored) when the sg_io_hdr_t
+ interface is used. They are kept for backward compatibility with
+ the original and version 2 drivers. */
+
+#define SG_SET_TIMEOUT 0x2201 /* unit: jiffies (10ms on i386) */
+#define SG_GET_TIMEOUT 0x2202 /* yield timeout as _return_ value */
+
+/* Get/set command queuing state per fd (default is SG_DEF_COMMAND_Q.
+ Each time a sg_io_hdr_t object is seen on this file descriptor, this
+ command queuing flag is set on (overriding the previous setting). */
+#define SG_GET_COMMAND_Q 0x2270 /* Yields 0 (queuing off) or 1 (on) */
+#define SG_SET_COMMAND_Q 0x2271 /* Change queuing state with 0 or 1 */
+
+/* Turn on/off error sense trace (1 and 0 respectively, default is off).
+ Try using: "# cat /proc/scsi/sg/debug" instead in the v3 driver */
+#define SG_SET_DEBUG 0x227e /* 0 -> turn off debug */
+
+#define SG_NEXT_CMD_LEN 0x2283 /* override SCSI command length with given
+ number on the next write() on this file descriptor */
+
+
+/* Defaults, commented if they differ from original sg driver */
+#ifdef __KERNEL__
+#define SG_DEFAULT_TIMEOUT_USER (60*USER_HZ) /* HZ == 'jiffies in 1 second' */
+#else
+#define SG_DEFAULT_TIMEOUT (60*HZ) /* HZ == 'jiffies in 1 second' */
+#endif
+
+#define SG_DEF_COMMAND_Q 0 /* command queuing is always on when
+ the new interface is used */
+#define SG_DEF_UNDERRUN_FLAG 0
+
+#endif
diff --git a/include/scsi/srp.h b/include/scsi/srp.h
new file mode 100644
index 000000000..dfe0984b5
--- /dev/null
+++ b/include/scsi/srp.h
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * $Id$
+ */
+
+#ifndef SCSI_SRP_H
+#define SCSI_SRP_H
+
+/*
+ * Structures and constants for the SCSI RDMA Protocol (SRP) as
+ * defined by the INCITS T10 committee. This file was written using
+ * draft Revision 16a of the SRP standard.
+ */
+
+#include <linux/types.h>
+#include <scsi/scsi.h>
+
+enum {
+ SRP_LOGIN_REQ = 0x00,
+ SRP_TSK_MGMT = 0x01,
+ SRP_CMD = 0x02,
+ SRP_I_LOGOUT = 0x03,
+ SRP_LOGIN_RSP = 0xc0,
+ SRP_RSP = 0xc1,
+ SRP_LOGIN_REJ = 0xc2,
+ SRP_T_LOGOUT = 0x80,
+ SRP_CRED_REQ = 0x81,
+ SRP_AER_REQ = 0x82,
+ SRP_CRED_RSP = 0x41,
+ SRP_AER_RSP = 0x42
+};
+
+enum {
+ SRP_BUF_FORMAT_DIRECT = 1 << 1,
+ SRP_BUF_FORMAT_INDIRECT = 1 << 2
+};
+
+enum {
+ SRP_NO_DATA_DESC = 0,
+ SRP_DATA_DESC_DIRECT = 1,
+ SRP_DATA_DESC_INDIRECT = 2,
+ SRP_DATA_DESC_IMM = 3, /* new in SRP2 */
+};
+
+enum {
+ SRP_TSK_ABORT_TASK = 0x01,
+ SRP_TSK_ABORT_TASK_SET = 0x02,
+ SRP_TSK_CLEAR_TASK_SET = 0x04,
+ SRP_TSK_LUN_RESET = 0x08,
+ SRP_TSK_CLEAR_ACA = 0x40
+};
+
+enum srp_login_rej_reason {
+ SRP_LOGIN_REJ_UNABLE_ESTABLISH_CHANNEL = 0x00010000,
+ SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES = 0x00010001,
+ SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE = 0x00010002,
+ SRP_LOGIN_REJ_UNABLE_ASSOCIATE_CHANNEL = 0x00010003,
+ SRP_LOGIN_REJ_UNSUPPORTED_DESCRIPTOR_FMT = 0x00010004,
+ SRP_LOGIN_REJ_MULTI_CHANNEL_UNSUPPORTED = 0x00010005,
+ SRP_LOGIN_REJ_CHANNEL_LIMIT_REACHED = 0x00010006
+};
+
+enum {
+ SRP_REV10_IB_IO_CLASS = 0xff00,
+ SRP_REV16A_IB_IO_CLASS = 0x0100
+};
+
+struct srp_direct_buf {
+ __be64 va;
+ __be32 key;
+ __be32 len;
+};
+
+/*
+ * We need the packed attribute because the SRP spec puts the list of
+ * descriptors at an offset of 20, which is not aligned to the size of
+ * struct srp_direct_buf. The whole structure must be packed to avoid
+ * having the 20-byte structure padded to 24 bytes on 64-bit architectures.
+ */
+struct srp_indirect_buf {
+ struct srp_direct_buf table_desc __packed __aligned(4);
+ __be32 len;
+ struct srp_direct_buf desc_list[] __packed __aligned(4);
+};
+
+/* Immediate data buffer descriptor as defined in SRP2. */
+struct srp_imm_buf {
+ __be32 len;
+};
+
+/* srp_login_req.flags */
+enum {
+ SRP_MULTICHAN_SINGLE = 0,
+ SRP_MULTICHAN_MULTI = 1,
+ SRP_IMMED_REQUESTED = 0x80, /* new in SRP2 */
+};
+
+struct srp_login_req {
+ u8 opcode;
+ u8 reserved1[7];
+ u64 tag;
+ __be32 req_it_iu_len;
+ u8 reserved2[4];
+ __be16 req_buf_fmt;
+ u8 req_flags;
+ u8 reserved3[1];
+ __be16 imm_data_offset; /* new in SRP2 */
+ u8 reserved4[2];
+ u8 initiator_port_id[16];
+ u8 target_port_id[16];
+};
+
+/**
+ * struct srp_login_req_rdma - RDMA/CM login parameters.
+ *
+ * RDMA/CM over InfiniBand can only carry 92 - 36 = 56 bytes of private
+ * data. The %srp_login_req_rdma structure contains the same information as
+ * %srp_login_req but with the reserved data removed.
+ */
+struct srp_login_req_rdma {
+ u64 tag;
+ __be16 req_buf_fmt;
+ u8 req_flags;
+ u8 opcode;
+ __be32 req_it_iu_len;
+ u8 initiator_port_id[16];
+ u8 target_port_id[16];
+ __be16 imm_data_offset;
+ u8 reserved[6];
+};
+
+/* srp_login_rsp.rsp_flags */
+enum {
+ SRP_LOGIN_RSP_MULTICHAN_NO_CHAN = 0x0,
+ SRP_LOGIN_RSP_MULTICHAN_TERMINATED = 0x1,
+ SRP_LOGIN_RSP_MULTICHAN_MAINTAINED = 0x2,
+ SRP_LOGIN_RSP_IMMED_SUPP = 0x80, /* new in SRP2 */
+};
+
+/*
+ * The SRP spec defines the size of the LOGIN_RSP structure to be 52
+ * bytes, so it needs to be packed to avoid having it padded to 56
+ * bytes on 64-bit architectures.
+ */
+struct srp_login_rsp {
+ u8 opcode;
+ u8 reserved1[3];
+ __be32 req_lim_delta;
+ u64 tag __packed __aligned(4);
+ __be32 max_it_iu_len;
+ __be32 max_ti_iu_len;
+ __be16 buf_fmt;
+ u8 rsp_flags;
+ u8 reserved2[25];
+};
+
+struct srp_login_rej {
+ u8 opcode;
+ u8 reserved1[3];
+ __be32 reason;
+ u64 tag;
+ u8 reserved2[8];
+ __be16 buf_fmt;
+ u8 reserved3[6];
+};
+
+struct srp_i_logout {
+ u8 opcode;
+ u8 reserved[7];
+ u64 tag;
+};
+
+struct srp_t_logout {
+ u8 opcode;
+ u8 sol_not;
+ u8 reserved[2];
+ __be32 reason;
+ u64 tag;
+};
+
+struct srp_tsk_mgmt {
+ u8 opcode;
+ u8 sol_not;
+ u8 reserved1[6];
+ u64 tag;
+ u8 reserved2[4];
+ struct scsi_lun lun;
+ u8 reserved3[2];
+ u8 tsk_mgmt_func;
+ u8 reserved4;
+ u64 task_tag;
+ u8 reserved5[8];
+};
+
+struct srp_cmd {
+ u8 opcode;
+ u8 sol_not;
+ u8 reserved1[3];
+ u8 buf_fmt;
+ u8 data_out_desc_cnt;
+ u8 data_in_desc_cnt;
+ u64 tag;
+ u8 reserved2[4];
+ struct scsi_lun lun;
+ u8 reserved3;
+ u8 task_attr;
+ u8 reserved4;
+ u8 add_cdb_len;
+ u8 cdb[16];
+ u8 add_data[];
+};
+
+enum {
+ SRP_RSP_FLAG_RSPVALID = 1 << 0,
+ SRP_RSP_FLAG_SNSVALID = 1 << 1,
+ SRP_RSP_FLAG_DOOVER = 1 << 2,
+ SRP_RSP_FLAG_DOUNDER = 1 << 3,
+ SRP_RSP_FLAG_DIOVER = 1 << 4,
+ SRP_RSP_FLAG_DIUNDER = 1 << 5
+};
+
+/*
+ * The SRP spec defines the size of the RSP structure to be 36 bytes,
+ * so it needs to be packed to avoid having it padded to 40 bytes on
+ * 64-bit architectures.
+ */
+struct srp_rsp {
+ u8 opcode;
+ u8 sol_not;
+ u8 reserved1[2];
+ __be32 req_lim_delta;
+ u64 tag __packed __aligned(4);
+ u8 reserved2[2];
+ u8 flags;
+ u8 status;
+ __be32 data_out_res_cnt;
+ __be32 data_in_res_cnt;
+ __be32 sense_data_len;
+ __be32 resp_data_len;
+ u8 data[];
+};
+
+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 __packed __aligned(4);
+ u32 reserved2;
+ struct scsi_lun lun;
+ __be32 sense_data_len;
+ u32 reserved3;
+ u8 sense_data[];
+};
+
+struct srp_aer_rsp {
+ u8 opcode;
+ u8 reserved[7];
+ u64 tag;
+};
+
+#endif /* SCSI_SRP_H */
diff --git a/include/scsi/viosrp.h b/include/scsi/viosrp.h
new file mode 100644
index 000000000..6c5559d2b
--- /dev/null
+++ b/include/scsi/viosrp.h
@@ -0,0 +1,217 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*****************************************************************************/
+/* srp.h -- SCSI RDMA Protocol definitions */
+/* */
+/* Written By: Colin Devilbis, IBM Corporation */
+/* */
+/* Copyright (C) 2003 IBM Corporation */
+/* */
+/* */
+/* This file contains structures and definitions for IBM RPA (RS/6000 */
+/* platform architecture) implementation of the SRP (SCSI RDMA Protocol) */
+/* standard. SRP is used on IBM iSeries and pSeries platforms to send SCSI */
+/* commands between logical partitions. */
+/* */
+/* SRP Information Units (IUs) are sent on a "Command/Response Queue" (CRQ) */
+/* between partitions. The definitions in this file are architected, */
+/* and cannot be changed without breaking compatibility with other versions */
+/* of Linux and other operating systems (AIX, OS/400) that talk this protocol*/
+/* between logical partitions */
+/*****************************************************************************/
+#ifndef VIOSRP_H
+#define VIOSRP_H
+#include <scsi/srp.h>
+
+#define SRP_VERSION "16.a"
+#define SRP_MAX_IU_LEN 256
+#define SRP_MAX_LOC_LEN 32
+
+union srp_iu {
+ struct srp_login_req login_req;
+ struct srp_login_rsp login_rsp;
+ struct srp_login_rej login_rej;
+ struct srp_i_logout i_logout;
+ struct srp_t_logout t_logout;
+ struct srp_tsk_mgmt tsk_mgmt;
+ struct srp_cmd cmd;
+ struct srp_rsp rsp;
+ u8 reserved[SRP_MAX_IU_LEN];
+};
+
+enum viosrp_crq_headers {
+ VIOSRP_CRQ_FREE = 0x00,
+ VIOSRP_CRQ_CMD_RSP = 0x80,
+ VIOSRP_CRQ_INIT_RSP = 0xC0,
+ VIOSRP_CRQ_XPORT_EVENT = 0xFF
+};
+
+enum viosrp_crq_init_formats {
+ VIOSRP_CRQ_INIT = 0x01,
+ VIOSRP_CRQ_INIT_COMPLETE = 0x02
+};
+
+enum viosrp_crq_formats {
+ VIOSRP_SRP_FORMAT = 0x01,
+ VIOSRP_MAD_FORMAT = 0x02,
+ VIOSRP_OS400_FORMAT = 0x03,
+ VIOSRP_AIX_FORMAT = 0x04,
+ VIOSRP_LINUX_FORMAT = 0x05,
+ VIOSRP_INLINE_FORMAT = 0x06
+};
+
+enum viosrp_crq_status {
+ VIOSRP_OK = 0x0,
+ VIOSRP_NONRECOVERABLE_ERR = 0x1,
+ VIOSRP_VIOLATES_MAX_XFER = 0x2,
+ VIOSRP_PARTNER_PANIC = 0x3,
+ VIOSRP_DEVICE_BUSY = 0x8,
+ VIOSRP_ADAPTER_FAIL = 0x10,
+ VIOSRP_OK2 = 0x99,
+};
+
+struct viosrp_crq {
+ union {
+ __be64 high; /* High 64 bits */
+ struct {
+ u8 valid; /* used by RPA */
+ u8 format; /* SCSI vs out-of-band */
+ u8 reserved;
+ u8 status; /* non-scsi failure? (e.g. DMA failure) */
+ __be16 timeout; /* in seconds */
+ __be16 IU_length; /* in bytes */
+ };
+ };
+ __be64 IU_data_ptr; /* the TCE for transferring data */
+};
+
+/* MADs are Management requests above and beyond the IUs defined in the SRP
+ * standard.
+ */
+enum viosrp_mad_types {
+ VIOSRP_EMPTY_IU_TYPE = 0x01,
+ VIOSRP_ERROR_LOG_TYPE = 0x02,
+ VIOSRP_ADAPTER_INFO_TYPE = 0x03,
+ VIOSRP_CAPABILITIES_TYPE = 0x05,
+ VIOSRP_ENABLE_FAST_FAIL = 0x08,
+};
+
+enum viosrp_mad_status {
+ VIOSRP_MAD_SUCCESS = 0x00,
+ VIOSRP_MAD_NOT_SUPPORTED = 0xF1,
+ VIOSRP_MAD_FAILED = 0xF7,
+};
+
+enum viosrp_capability_type {
+ MIGRATION_CAPABILITIES = 0x01,
+ RESERVATION_CAPABILITIES = 0x02,
+};
+
+enum viosrp_capability_support {
+ SERVER_DOES_NOT_SUPPORTS_CAP = 0x0,
+ SERVER_SUPPORTS_CAP = 0x01,
+ SERVER_CAP_DATA = 0x02,
+};
+
+enum viosrp_reserve_type {
+ CLIENT_RESERVE_SCSI_2 = 0x01,
+};
+
+enum viosrp_capability_flag {
+ CLIENT_MIGRATED = 0x01,
+ CLIENT_RECONNECT = 0x02,
+ CAP_LIST_SUPPORTED = 0x04,
+ CAP_LIST_DATA = 0x08,
+};
+
+/*
+ * Common MAD header
+ */
+struct mad_common {
+ __be32 type;
+ __be16 status;
+ __be16 length;
+ __be64 tag;
+};
+
+/*
+ * All SRP (and MAD) requests normally flow from the
+ * client to the server. There is no way for the server to send
+ * an asynchronous message back to the client. The Empty IU is used
+ * to hang out a meaningless request to the server so that it can respond
+ * asynchrouously with something like a SCSI AER
+ */
+struct viosrp_empty_iu {
+ struct mad_common common;
+ __be64 buffer;
+ __be32 port;
+};
+
+struct viosrp_error_log {
+ struct mad_common common;
+ __be64 buffer;
+};
+
+struct viosrp_adapter_info {
+ struct mad_common common;
+ __be64 buffer;
+};
+
+struct viosrp_fast_fail {
+ struct mad_common common;
+};
+
+struct viosrp_capabilities {
+ struct mad_common common;
+ __be64 buffer;
+};
+
+struct mad_capability_common {
+ __be32 cap_type;
+ __be16 length;
+ __be16 server_support;
+};
+
+struct mad_reserve_cap {
+ struct mad_capability_common common;
+ __be32 type;
+};
+
+struct mad_migration_cap {
+ struct mad_capability_common common;
+ __be32 ecl;
+};
+
+struct capabilities {
+ __be32 flags;
+ char name[SRP_MAX_LOC_LEN];
+ char loc[SRP_MAX_LOC_LEN];
+ struct mad_migration_cap migration;
+ struct mad_reserve_cap reserve;
+};
+
+union mad_iu {
+ struct viosrp_empty_iu empty_iu;
+ struct viosrp_error_log error_log;
+ struct viosrp_adapter_info adapter_info;
+ struct viosrp_fast_fail fast_fail;
+ struct viosrp_capabilities capabilities;
+};
+
+union viosrp_iu {
+ union srp_iu srp;
+ union mad_iu mad;
+};
+
+struct mad_adapter_info_data {
+ char srp_version[8];
+ char partition_name[96];
+ __be32 partition_number;
+#define SRP_MAD_VERSION_1 1
+ __be32 mad_version;
+#define SRP_MAD_OS_LINUX 2
+#define SRP_MAD_OS_AIX 3
+ __be32 os_type;
+ __be32 port_max_txu[8]; /* per-port maximum transfer */
+};
+
+#endif