[stgt] [PATCH 2/2] Add support for reading a single opcode/serviceaction from REPORT SUPPORTED OPCODES
Ronnie Sahlberg
ronniesahlberg at gmail.com
Sun May 19 22:17:51 CEST 2013
Signed-off-by: Ronnie Sahlberg <ronniesahlberg at gmail.com>
---
usr/scsi.c | 219 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
usr/scsi.h | 4 +
usr/spc.c | 61 +++++++++++++++++
usr/tgtd.h | 2 +
4 files changed, 286 insertions(+), 0 deletions(-)
diff --git a/usr/scsi.c b/usr/scsi.c
index 6f41b0b..2636a5c 100644
--- a/usr/scsi.c
+++ b/usr/scsi.c
@@ -56,6 +56,225 @@ int get_scsi_cdb_size(struct scsi_cmd *cmd)
return CDB_SIZE(cmd);
}
+const unsigned char *get_scsi_cdb_usage_data(unsigned char op, unsigned char sa)
+{
+ static const unsigned char usage[16];
+
+ static const unsigned char allow_medium_removal[] = {
+ 0xff, 0x00, 0x00, 0x00, 0x03, 0x07};
+ static const unsigned char send_diagnostics[] = {
+ 0xff, 0xff, 0x00, 0xff, 0xff, 0x07};
+ static const unsigned char start_stop[] = {
+ 0xff, 0x01, 0x00, 0x0f, 0xf7, 0x07};
+ static const unsigned char mode_sense[] = {
+ 0xff, 0x08, 0xff, 0xff, 0xff, 0x07};
+ static const unsigned char mode_select[] = {
+ 0xff, 0x11, 0x00, 0x00, 0xff, 0x07};
+ static const unsigned char reserve_release[] = {
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x07};
+ static const unsigned char inquiry[] = {
+ 0xff, 0x01, 0xff, 0xff, 0xff, 0x07};
+ static const unsigned char read_write_6[] = {
+ 0xff, 0x1f, 0xff, 0xff, 0xff, 0x07};
+ static const unsigned char format_unit[] = {
+ 0xff, 0xff, 0x00, 0x00, 0x00, 0x07};
+ static const unsigned char request_sense[] = {
+ 0xff, 0x01, 0x00, 0x00, 0xff, 0x07};
+ static const unsigned char test_unit_ready[] = {
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x07};
+
+ static const unsigned char persistent_reserve_in[] = {
+ 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x07};
+ static const unsigned char persistent_reserve_out[] = {
+ 0xff, 0x1f, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff,
+ 0xff, 0x07};
+ static const unsigned char mode_sense_10[] = {
+ 0xff, 0x18, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x07};
+ static const unsigned char mode_select_10[] = {
+ 0xff, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x07};
+ static const unsigned char unmap[] = {
+ 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x07};
+ static const unsigned char write_same_10[] = {
+ 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff,
+ 0xff, 0x07};
+ static const unsigned char pre_fetch_10[] = {
+ 0xff, 0x02, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff,
+ 0xff, 0x07};
+ static const unsigned char synchronize_cache_10[] = {
+ 0xff, 0x06, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff,
+ 0xff, 0x07};
+ static const unsigned char verify_10[] = {
+ 0xff, 0xf2, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff,
+ 0xff, 0x07};
+ static const unsigned char write_10[] = {
+ 0xff, 0xfa, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff,
+ 0xff, 0x07};
+ static const unsigned char read_10[] = {
+ 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff,
+ 0xff, 0x07};
+ static const unsigned char read_capacity[] = {
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x07};
+
+ static const unsigned char verify_12[] = {
+ 0xff, 0xf2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0x00, 0x07};
+ static const unsigned char write_12[] = {
+ 0xff, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0x00, 0x07};
+ static const unsigned char read_12[] = {
+ 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0x00, 0x07};
+ static const unsigned char rep_sup_opcodes[] = {
+ 0xff, 0x1f, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0x00, 0x07};
+ static const unsigned char report_luns[] = {
+ 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0xff, 0x00, 0x07};
+
+ static const unsigned char get_lba_status[] = {
+ 0xff, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x07};
+ static const unsigned char read_capacity_16[] = {
+ 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x07};
+ static const unsigned char write_same_16[] = {
+ 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x07};
+ static const unsigned char synchronize_cache_16[] = {
+ 0xff, 0x06, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x07};
+ static const unsigned char pre_fetch_16[] = {
+ 0xff, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x07};
+ static const unsigned char verify_16[] = {
+ 0xff, 0xf2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x07};
+ static const unsigned char orwrite_16[] = {
+ 0xff, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x07};
+ static const unsigned char compare_and_write[] = {
+ 0xff, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x07};
+ static const unsigned char read_16[] = {
+ 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x07};
+
+ switch (op) {
+ case TEST_UNIT_READY:
+ return test_unit_ready;
+ case REQUEST_SENSE:
+ return request_sense;
+ case FORMAT_UNIT:
+ return format_unit;
+ case READ_6:
+ case WRITE_6:
+ return read_write_6;
+ case INQUIRY:
+ return inquiry;
+ case MODE_SELECT:
+ return mode_select;
+ case RELEASE:
+ case RESERVE:
+ return reserve_release;
+ case MODE_SENSE:
+ return mode_sense;
+ case START_STOP:
+ return start_stop;
+ case SEND_DIAGNOSTIC:
+ return send_diagnostics;
+ case ALLOW_MEDIUM_REMOVAL:
+ return allow_medium_removal;
+ case READ_CAPACITY:
+ return read_capacity;
+ case READ_10:
+ return read_10;
+ case WRITE_10:
+ return write_10;
+ case WRITE_VERIFY:
+ case VERIFY_10:
+ return verify_10;
+ case PRE_FETCH_10:
+ return pre_fetch_10;
+ case SYNCHRONIZE_CACHE:
+ return synchronize_cache_10;
+ case WRITE_SAME:
+ return write_same_10;
+ case UNMAP:
+ return unmap;
+ case MODE_SELECT_10:
+ return mode_select_10;
+ case MODE_SENSE_10:
+ return mode_sense_10;
+ case PERSISTENT_RESERVE_IN:
+ switch (sa) {
+ case PR_IN_READ_KEYS:
+ case PR_IN_READ_RESERVATION:
+ case PR_IN_REPORT_CAPABILITIES:
+ case PR_IN_READ_FULL_STATUS:
+ return persistent_reserve_in;
+ }
+ break;
+ case PERSISTENT_RESERVE_OUT:
+ switch (sa) {
+ case PR_OUT_REGISTER:
+ case PR_OUT_RESERVE:
+ case PR_OUT_RELEASE:
+ case PR_OUT_CLEAR:
+ case PR_OUT_PREEMPT:
+ case PR_OUT_PREEMPT_AND_ABORT:
+ case PR_OUT_REGISTER_AND_IGNORE_EXISTING_KEY:
+ case PR_OUT_REGISTER_AND_MOVE:
+ return persistent_reserve_out;
+ }
+ break;
+ case READ_16:
+ return read_16;
+ case COMPARE_AND_WRITE:
+ return compare_and_write;
+ case WRITE_16:
+ case ORWRITE_16:
+ return orwrite_16;
+ case WRITE_VERIFY_16:
+ case VERIFY_16:
+ return verify_16;
+ case PRE_FETCH_16:
+ return pre_fetch_16;
+ case SYNCHRONIZE_CACHE_16:
+ return synchronize_cache_16;
+ case WRITE_SAME_16:
+ return write_same_16;
+ case SERVICE_ACTION_IN:
+ switch (sa) {
+ case SAI_READ_CAPACITY_16:
+ return read_capacity_16;
+ case SAI_GET_LBA_STATUS:
+ return get_lba_status;
+ }
+ break;
+ case REPORT_LUNS:
+ return report_luns;
+ case MAINT_PROTOCOL_IN:
+ switch (sa) {
+ case MPI_REPORT_SUPPORTED_OPCODES:
+ return rep_sup_opcodes;
+ }
+ break;
+ case READ_12:
+ return read_12;
+ case VERIFY_12:
+ case WRITE_VERIFY_12:
+ return verify_12;
+ case WRITE_12:
+ return write_12;
+ }
+ return usage;
+}
+
void sense_data_build(struct scsi_cmd *cmd, uint8_t key, uint16_t asc)
{
diff --git a/usr/scsi.h b/usr/scsi.h
index 043df1f..1edcfd7 100644
--- a/usr/scsi.h
+++ b/usr/scsi.h
@@ -84,6 +84,7 @@
#define SAI_READ_CAPACITY_16 0x10
#define SAI_GET_LBA_STATUS 0x12
#define REPORT_LUNS 0xa0
+#define MAINT_PROTOCOL_IN 0xa3
#define MOVE_MEDIUM 0xa5
#define EXCHANGE_MEDIUM 0xa6
#define READ_12 0xa8
@@ -97,6 +98,9 @@
#define SEND_VOLUME_TAG 0xb6
#define WRITE_LONG_2 0xea
+/* Service actions for opcode 0xa3 */
+#define MPI_REPORT_SUPPORTED_OPCODES 0x0c
+
#define SAM_STAT_GOOD 0x00
#define SAM_STAT_CHECK_CONDITION 0x02
#define SAM_STAT_CONDITION_MET 0x04
diff --git a/usr/spc.c b/usr/spc.c
index e5d3b51..22b5e5d 100644
--- a/usr/spc.c
+++ b/usr/spc.c
@@ -793,9 +793,59 @@ static int report_opcodes_all(struct scsi_cmd *cmd, int rctd,
return SAM_STAT_GOOD;
}
+static int report_opcode_one(struct scsi_cmd *cmd, int rctd, uint8_t opcode,
+ uint16_t sa, int is_service_action, uint32_t alloc_len)
+{
+ struct device_type_operations *ops;
+ uint8_t buf[256], *data;
+ uint32_t avail_len, actual_len;
+ int cdb_length;
+
+ ops = cmd->dev->dev_type_template.ops;
+
+ if ((is_service_action && !ops[opcode].service_actions)
+ || (!is_service_action && ops[opcode].service_actions)) {
+ return SAM_STAT_CHECK_CONDITION;
+ }
+
+ memset(buf, 0, sizeof(buf));
+ data = &buf[0];
+
+ /* reserved */
+ data++;
+
+ /* ctdp and support */
+ *data++ = rctd ? 0x83 : 0x03;
+
+ /* cdb length */
+ cdb_length = get_scsi_command_size(opcode);
+ *data++ = (cdb_length >> 8) & 0xff;
+ *data++ = cdb_length & 0xff;
+
+ /* cdb usage data */
+ memcpy(data, get_scsi_cdb_usage_data(opcode, sa), cdb_length);
+ data += cdb_length;
+
+ /* timeout descriptor */
+ if (rctd) {
+ /* length == 0x0a */
+ data[1] = 0x0a;
+ data += 12;
+ }
+
+
+ avail_len = data - &buf[0];
+ actual_len = spc_memcpy(scsi_get_in_buffer(cmd), &alloc_len,
+ buf, avail_len);
+ scsi_set_in_resid_by_actual(cmd, actual_len);
+
+ return SAM_STAT_GOOD;
+}
+
int spc_report_supported_opcodes(int host_no, struct scsi_cmd *cmd)
{
uint8_t reporting_options;
+ uint8_t opcode;
uint16_t requested_service_action;
uint32_t alloc_len;
int rctd;
@@ -804,6 +854,7 @@ int spc_report_supported_opcodes(int host_no, struct scsi_cmd *cmd)
uint16_t asc = ASC_INVALID_FIELD_IN_CDB;
reporting_options = cmd->scb[2] & 0x07;
+ opcode = cmd->scb[3];
requested_service_action = get_unaligned_be16(&cmd->scb[4]);
alloc_len = get_unaligned_be32(&cmd->scb[6]);
@@ -817,7 +868,17 @@ int spc_report_supported_opcodes(int host_no, struct scsi_cmd *cmd)
ret = report_opcodes_all(cmd, rctd, alloc_len);
break;
case 0x01: /* report one no service action*/
+ ret = report_opcode_one(cmd, rctd, opcode,
+ requested_service_action, 0, alloc_len);
+ if (ret)
+ goto sense;
+ break;
case 0x02: /* report one service action */
+ ret = report_opcode_one(cmd, rctd, opcode,
+ requested_service_action, 1, alloc_len);
+ if (ret)
+ goto sense;
+ break;
default:
goto sense;
}
diff --git a/usr/tgtd.h b/usr/tgtd.h
index 662ce61..7fbd65b 100644
--- a/usr/tgtd.h
+++ b/usr/tgtd.h
@@ -326,6 +326,8 @@ extern int scsi_is_io_opcode(unsigned char op);
extern enum data_direction scsi_data_dir_opcode(unsigned char op);
extern int get_scsi_cdb_size(struct scsi_cmd *cmd);
extern int get_scsi_command_size(unsigned char op);
+extern const unsigned char *get_scsi_cdb_usage_data(unsigned char op,
+ unsigned char sa);
extern enum scsi_target_state tgt_get_target_state(int tid);
extern tgtadm_err tgt_set_target_state(int tid, char *str);
--
1.7.3.1
--
To unsubscribe from this list: send the line "unsubscribe stgt" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
More information about the stgt
mailing list