Signed-off-by: Ronnie Sahlberg <ronniesahlberg@xxxxxxxxx> --- 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@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html