[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