summaryrefslogtreecommitdiff
path: root/include/scsi
diff options
context:
space:
mode:
Diffstat (limited to 'include/scsi')
-rw-r--r--include/scsi/scsi.h3
-rw-r--r--include/scsi/scsi_cmnd.h86
-rw-r--r--include/scsi/scsi_device.h17
-rw-r--r--include/scsi/scsi_dh.h11
-rw-r--r--include/scsi/scsi_eh.h2
-rw-r--r--include/scsi/scsi_host.h86
6 files changed, 202 insertions, 3 deletions
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
index 00137a7769ee..5c40cc537d4c 100644
--- a/include/scsi/scsi.h
+++ b/include/scsi/scsi.h
@@ -106,6 +106,7 @@
#define VARIABLE_LENGTH_CMD 0x7f
#define REPORT_LUNS 0xa0
#define MAINTENANCE_IN 0xa3
+#define MAINTENANCE_OUT 0xa4
#define MOVE_MEDIUM 0xa5
#define EXCHANGE_MEDIUM 0xa6
#define READ_12 0xa8
@@ -125,6 +126,8 @@
#define SAI_READ_CAPACITY_16 0x10
/* values for maintenance in */
#define MI_REPORT_TARGET_PGS 0x0a
+/* values for maintenance out */
+#define MO_SET_TARGET_PGS 0x0a
/* Values for T10/04-262r7 */
#define ATA_16 0x85 /* 16-byte pass-thru */
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
index 66c944849d6b..f9f6e793575c 100644
--- a/include/scsi/scsi_cmnd.h
+++ b/include/scsi/scsi_cmnd.h
@@ -77,6 +77,9 @@ struct scsi_cmnd {
int allowed;
int timeout_per_command;
+ unsigned char prot_op;
+ unsigned char prot_type;
+
unsigned short cmd_len;
enum dma_data_direction sc_data_direction;
@@ -87,6 +90,8 @@ struct scsi_cmnd {
/* These elements define the operation we ultimately want to perform */
struct scsi_data_buffer sdb;
+ struct scsi_data_buffer *prot_sdb;
+
unsigned underflow; /* Return error if less than
this amount is transferred */
@@ -208,4 +213,85 @@ static inline int scsi_sg_copy_to_buffer(struct scsi_cmnd *cmd,
buf, buflen);
}
+/*
+ * The operations below are hints that tell the controller driver how
+ * to handle I/Os with DIF or similar types of protection information.
+ */
+enum scsi_prot_operations {
+ /* Normal I/O */
+ SCSI_PROT_NORMAL = 0,
+
+ /* OS-HBA: Protected, HBA-Target: Unprotected */
+ SCSI_PROT_READ_INSERT,
+ SCSI_PROT_WRITE_STRIP,
+
+ /* OS-HBA: Unprotected, HBA-Target: Protected */
+ SCSI_PROT_READ_STRIP,
+ SCSI_PROT_WRITE_INSERT,
+
+ /* OS-HBA: Protected, HBA-Target: Protected */
+ SCSI_PROT_READ_PASS,
+ SCSI_PROT_WRITE_PASS,
+
+ /* OS-HBA: Protected, HBA-Target: Protected, checksum conversion */
+ SCSI_PROT_READ_CONVERT,
+ SCSI_PROT_WRITE_CONVERT,
+};
+
+static inline void scsi_set_prot_op(struct scsi_cmnd *scmd, unsigned char op)
+{
+ scmd->prot_op = op;
+}
+
+static inline unsigned char scsi_get_prot_op(struct scsi_cmnd *scmd)
+{
+ return scmd->prot_op;
+}
+
+/*
+ * The controller usually does not know anything about the target it
+ * is communicating with. However, when DIX is enabled the controller
+ * must be know target type so it can verify the protection
+ * information passed along with the I/O.
+ */
+enum scsi_prot_target_type {
+ SCSI_PROT_DIF_TYPE0 = 0,
+ SCSI_PROT_DIF_TYPE1,
+ SCSI_PROT_DIF_TYPE2,
+ SCSI_PROT_DIF_TYPE3,
+};
+
+static inline void scsi_set_prot_type(struct scsi_cmnd *scmd, unsigned char type)
+{
+ scmd->prot_type = type;
+}
+
+static inline unsigned char scsi_get_prot_type(struct scsi_cmnd *scmd)
+{
+ return scmd->prot_type;
+}
+
+static inline sector_t scsi_get_lba(struct scsi_cmnd *scmd)
+{
+ return scmd->request->sector;
+}
+
+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)
+
#endif /* _SCSI_SCSI_CMND_H */
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index 6467f78b191f..291d56a19167 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -140,7 +140,8 @@ struct scsi_device {
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; /* Always read last sector in a 1 sector read */
+ unsigned last_sector_bug:1; /* do not use multisector accesses on
+ SD_LAST_BUGGY_SECTORS */
DECLARE_BITMAP(supported_events, SDEV_EVT_MAXBITS); /* supported events */
struct list_head event_list; /* asserted events */
@@ -167,15 +168,22 @@ struct scsi_device {
unsigned long sdev_data[0];
} __attribute__((aligned(sizeof(unsigned long))));
+struct scsi_dh_devlist {
+ char *vendor;
+ char *model;
+};
+
struct scsi_device_handler {
/* Used by the infrastructure */
struct list_head list; /* list of scsi_device_handlers */
- struct notifier_block nb;
/* Filled by the hardware handler */
struct module *module;
const char *name;
+ const struct scsi_dh_devlist *devlist;
int (*check_sense)(struct scsi_device *, struct scsi_sense_hdr *);
+ int (*attach)(struct scsi_device *);
+ void (*detach)(struct scsi_device *);
int (*activate)(struct scsi_device *);
int (*prep_fn)(struct scsi_device *, struct request *);
};
@@ -416,6 +424,11 @@ static inline int scsi_device_enclosure(struct scsi_device *sdev)
return sdev->inquiry[6] & (1<<6);
}
+static inline int scsi_device_protection(struct scsi_device *sdev)
+{
+ return sdev->inquiry[5] & (1<<0);
+}
+
#define MODULE_ALIAS_SCSI_DEVICE(type) \
MODULE_ALIAS("scsi:t-" __stringify(type) "*")
#define SCSI_DEVICE_MODALIAS_FMT "scsi:t-0x%02x"
diff --git a/include/scsi/scsi_dh.h b/include/scsi/scsi_dh.h
index 3ad2303d1a16..33efce20c26c 100644
--- a/include/scsi/scsi_dh.h
+++ b/include/scsi/scsi_dh.h
@@ -32,6 +32,7 @@ enum {
*/
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 */
/*
@@ -57,6 +58,8 @@ enum {
#if defined(CONFIG_SCSI_DH) || defined(CONFIG_SCSI_DH_MODULE)
extern int scsi_dh_activate(struct request_queue *);
extern int scsi_dh_handler_exist(const char *);
+extern int scsi_dh_attach(struct request_queue *, const char *);
+extern void scsi_dh_detach(struct request_queue *);
#else
static inline int scsi_dh_activate(struct request_queue *req)
{
@@ -66,4 +69,12 @@ static inline int scsi_dh_handler_exist(const char *name)
{
return 0;
}
+static inline int scsi_dh_attach(struct request_queue *req, const char *name)
+{
+ return SCSI_DH_NOSYS;
+}
+static inline void scsi_dh_detach(struct request_queue *q)
+{
+ return;
+}
#endif
diff --git a/include/scsi/scsi_eh.h b/include/scsi/scsi_eh.h
index 2a9add21267d..06a8790893ef 100644
--- a/include/scsi/scsi_eh.h
+++ b/include/scsi/scsi_eh.h
@@ -74,7 +74,9 @@ struct scsi_eh_save {
/* saved state */
int result;
enum dma_data_direction data_direction;
+ unsigned underflow;
unsigned char cmd_len;
+ unsigned char prot_op;
unsigned char *cmnd;
struct scsi_data_buffer sdb;
struct request *next_rq;
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index a594bac4a77d..44a55d1bf530 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -547,7 +547,7 @@ struct Scsi_Host {
unsigned int host_failed; /* commands that failed. */
unsigned int host_eh_scheduled; /* EH scheduled without command */
- unsigned short host_no; /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */
+ unsigned int host_no; /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */
int resetting; /* if set, it means that last_reset is a valid value */
unsigned long last_reset;
@@ -636,6 +636,10 @@ struct Scsi_Host {
*/
unsigned int max_host_blocked;
+ /* Protection Information */
+ unsigned int prot_capabilities;
+ unsigned char prot_guard_type;
+
/*
* q used for scsi_tgt msgs, async events or any other requests that
* need to be processed in userspace
@@ -756,6 +760,86 @@ extern struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost,
extern void scsi_free_host_dev(struct scsi_device *);
extern struct scsi_device *scsi_get_host_dev(struct Scsi_Host *);
+/*
+ * DIF defines the exchange of protection information between
+ * initiator and SBC block device.
+ *
+ * DIX defines the exchange of protection information between OS and
+ * initiator.
+ */
+enum scsi_host_prot_capabilities {
+ SHOST_DIF_TYPE1_PROTECTION = 1 << 0, /* T10 DIF Type 1 */
+ SHOST_DIF_TYPE2_PROTECTION = 1 << 1, /* T10 DIF Type 2 */
+ SHOST_DIF_TYPE3_PROTECTION = 1 << 2, /* T10 DIF Type 3 */
+
+ SHOST_DIX_TYPE0_PROTECTION = 1 << 3, /* DIX between OS and HBA only */
+ SHOST_DIX_TYPE1_PROTECTION = 1 << 4, /* DIX with DIF Type 1 */
+ SHOST_DIX_TYPE2_PROTECTION = 1 << 5, /* DIX with DIF Type 2 */
+ SHOST_DIX_TYPE3_PROTECTION = 1 << 6, /* DIX with DIF Type 3 */
+};
+
+/*
+ * SCSI hosts which support the Data Integrity Extensions must
+ * indicate their capabilities by setting the prot_capabilities using
+ * this call.
+ */
+static inline void scsi_host_set_prot(struct Scsi_Host *shost, unsigned int mask)
+{
+ shost->prot_capabilities = mask;
+}
+
+static inline unsigned int scsi_host_get_prot(struct Scsi_Host *shost)
+{
+ return shost->prot_capabilities;
+}
+
+static inline unsigned int scsi_host_dif_capable(struct Scsi_Host *shost, unsigned int target_type)
+{
+ switch (target_type) {
+ case 1: return shost->prot_capabilities & SHOST_DIF_TYPE1_PROTECTION;
+ case 2: return shost->prot_capabilities & SHOST_DIF_TYPE2_PROTECTION;
+ case 3: return shost->prot_capabilities & SHOST_DIF_TYPE3_PROTECTION;
+ }
+
+ return 0;
+}
+
+static inline unsigned int scsi_host_dix_capable(struct Scsi_Host *shost, unsigned int target_type)
+{
+ switch (target_type) {
+ case 0: return shost->prot_capabilities & SHOST_DIX_TYPE0_PROTECTION;
+ case 1: return shost->prot_capabilities & SHOST_DIX_TYPE1_PROTECTION;
+ case 2: return shost->prot_capabilities & SHOST_DIX_TYPE2_PROTECTION;
+ case 3: return shost->prot_capabilities & SHOST_DIX_TYPE3_PROTECTION;
+ }
+
+ return 0;
+}
+
+/*
+ * All DIX-capable initiators must support the T10-mandated CRC
+ * checksum. Controllers can optionally implement the IP checksum
+ * scheme which has much lower impact on system performance. Note
+ * that the main rationale for the checksum is to match integrity
+ * metadata with data. Detecting bit errors are a job for ECC memory
+ * and buses.
+ */
+
+enum scsi_host_guard_type {
+ SHOST_DIX_GUARD_CRC = 1 << 0,
+ SHOST_DIX_GUARD_IP = 1 << 1,
+};
+
+static inline void scsi_host_set_guard(struct Scsi_Host *shost, unsigned char type)
+{
+ shost->prot_guard_type = type;
+}
+
+static inline unsigned char scsi_host_get_guard(struct Scsi_Host *shost)
+{
+ return shost->prot_guard_type;
+}
+
/* legacy interfaces */
extern struct Scsi_Host *scsi_register(struct scsi_host_template *, int);
extern void scsi_unregister(struct Scsi_Host *);