REPORT SUPPORTED OPERATION CODES added

git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@5418 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2014-04-16 01:02:50 +00:00
parent 14a331e0f2
commit d57ea322de
5 changed files with 903 additions and 3 deletions

View File

@@ -661,6 +661,7 @@ struct scst_acg;
struct scst_acg_dev;
struct scst_acn;
struct scst_aen;
struct scst_opcode_descriptor;
/*
* SCST uses 64-bit numbers to represent LUN's internally. The value
@@ -1374,6 +1375,29 @@ struct scst_dev_type {
*/
bool (*on_sg_tablesize_low) (struct scst_cmd *cmd);
/*
* Called to return array of supported opcodes in out_supp_opcodes
* argument with out_supp_opcodes_cnt elements count or execute
* REPORT SUPPORTED OPERATION CODES command in place. Must return
* 0 on success or any other code otherwise. In the latter case,
* cmd supposed to have correct sense set.
*
* OPTIONAL
*/
int (*get_supported_opcodes) (struct scst_cmd *cmd,
const struct scst_opcode_descriptor ***out_supp_opcodes,
int *out_supp_opcodes_cnt);
/*
* Called to put (release) array of supported opcodes returned
* by get_supported_opcodes() callback.
*
* OPTIONAL
*/
void (*put_supported_opcodes) (struct scst_cmd *cmd,
const struct scst_opcode_descriptor **supp_opcodes,
int supp_opcodes_cnt);
/*
* Called when new device is attaching to the dev handler
* Returns 0 on success, error code otherwise.
@@ -2896,6 +2920,58 @@ struct scst_aen {
int delivery_status;
};
#define SCST_OD_DEFAULT_CONTROL_BYTE 0
struct scst_opcode_descriptor {
uint16_t od_serv_action;
uint8_t od_opcode;
uint8_t od_serv_action_valid:1;
uint8_t od_support:3; /* SUPPORT bits */
uint16_t od_cdb_size;
uint8_t od_comm_specific_timeout;
uint32_t od_nominal_timeout;
uint32_t od_recommended_timeout;
uint8_t od_cdb_usage_bits[];
} __packed;
extern const struct scst_opcode_descriptor scst_op_descr_log_select;
extern const struct scst_opcode_descriptor scst_op_descr_log_sense;
extern const struct scst_opcode_descriptor scst_op_descr_mode_select6;
extern const struct scst_opcode_descriptor scst_op_descr_mode_sense6;
extern const struct scst_opcode_descriptor scst_op_descr_mode_select10;
extern const struct scst_opcode_descriptor scst_op_descr_mode_sense10;
extern const struct scst_opcode_descriptor scst_op_descr_rtpg;
extern const struct scst_opcode_descriptor scst_op_descr_stpg;
extern const struct scst_opcode_descriptor scst_op_descr_send_diagnostic;
extern const struct scst_opcode_descriptor scst_op_descr_inquiry;
extern const struct scst_opcode_descriptor scst_op_descr_tur;
extern const struct scst_opcode_descriptor scst_op_descr_reserve6;
extern const struct scst_opcode_descriptor scst_op_descr_release6;
extern const struct scst_opcode_descriptor scst_op_descr_reserve10;
extern const struct scst_opcode_descriptor scst_op_descr_release10;
extern const struct scst_opcode_descriptor scst_op_descr_pr_in;
extern const struct scst_opcode_descriptor scst_op_descr_pr_out;
extern const struct scst_opcode_descriptor scst_op_descr_report_luns;
extern const struct scst_opcode_descriptor scst_op_descr_request_sense;
extern const struct scst_opcode_descriptor scst_op_descr_report_supp_tm_fns;
extern const struct scst_opcode_descriptor scst_op_descr_report_supp_opcodes;
#define SCST_OPCODE_DESCRIPTORS \
&scst_op_descr_inquiry, \
&scst_op_descr_tur, \
&scst_op_descr_reserve6, \
&scst_op_descr_release6, \
&scst_op_descr_reserve10, \
&scst_op_descr_release10, \
&scst_op_descr_pr_in, \
&scst_op_descr_pr_out, \
&scst_op_descr_report_luns, \
&scst_op_descr_request_sense, \
&scst_op_descr_report_supp_opcodes, \
&scst_op_descr_report_supp_tm_fns,
#ifndef smp_mb__after_set_bit
/* There is no smp_mb__after_set_bit() in the kernel */
#define smp_mb__after_set_bit() smp_mb()

View File

@@ -571,6 +571,7 @@ enum scst_tg_sup {
** Various timeouts
*************************************************************/
#define SCST_DEFAULT_TIMEOUT (30 * HZ)
#define SCST_DEFAULT_NOMINAL_TIMEOUT_SEC 1
#define SCST_GENERIC_CHANGER_TIMEOUT (3 * HZ)
#define SCST_GENERIC_CHANGER_LONG_TIMEOUT (14000 * HZ)
@@ -586,8 +587,8 @@ enum scst_tg_sup {
#define SCST_GENERIC_MODISK_REG_TIMEOUT (900 * HZ)
#define SCST_GENERIC_MODISK_LONG_TIMEOUT (14000 * HZ)
#define SCST_GENERIC_DISK_SMALL_TIMEOUT (3 * HZ)
#define SCST_GENERIC_DISK_REG_TIMEOUT (30 * HZ)
#define SCST_GENERIC_DISK_SMALL_TIMEOUT (10 * HZ)
#define SCST_GENERIC_DISK_REG_TIMEOUT (60 * HZ)
#define SCST_GENERIC_DISK_LONG_TIMEOUT (3600 * HZ)
#define SCST_GENERIC_RAID_TIMEOUT (3 * HZ)

View File

@@ -244,6 +244,12 @@ static int vdisk_attach(struct scst_device *dev);
static void vdisk_detach(struct scst_device *dev);
static int vdisk_attach_tgt(struct scst_tgt_dev *tgt_dev);
static void vdisk_detach_tgt(struct scst_tgt_dev *tgt_dev);
static int vdisk_get_supported_opcodes(struct scst_cmd *cmd,
const struct scst_opcode_descriptor ***out_supp_opcodes,
int *out_supp_opcodes_cnt);
static int vcdrom_get_supported_opcodes(struct scst_cmd *cmd,
const struct scst_opcode_descriptor ***out_supp_opcodes,
int *out_supp_opcodes_cnt);
static int fileio_alloc_data_buf(struct scst_cmd *cmd);
static int vdisk_parse(struct scst_cmd *);
static int vcdrom_parse(struct scst_cmd *);
@@ -565,6 +571,7 @@ static struct scst_dev_type vdisk_file_devtype = {
.exec = vdisk_exec,
.on_free_cmd = fileio_on_free_cmd,
.task_mgmt_fn_done = vdisk_task_mgmt_fn_done,
.get_supported_opcodes = vdisk_get_supported_opcodes,
.devt_priv = (void *)fileio_ops,
#ifdef CONFIG_SCST_PROC
.read_proc = vdisk_read_proc,
@@ -613,6 +620,7 @@ static struct scst_dev_type vdisk_blk_devtype = {
.parse = non_fileio_parse,
.exec = non_fileio_exec,
.task_mgmt_fn_done = vdisk_task_mgmt_fn_done,
.get_supported_opcodes = vdisk_get_supported_opcodes,
.devt_priv = (void *)blockio_ops,
#ifndef CONFIG_SCST_PROC
.add_device = vdisk_add_blockio_device,
@@ -655,6 +663,7 @@ static struct scst_dev_type vdisk_null_devtype = {
.exec = non_fileio_exec,
.task_mgmt_fn_done = vdisk_task_mgmt_fn_done,
.devt_priv = (void *)nullio_ops,
.get_supported_opcodes = vdisk_get_supported_opcodes,
#ifndef CONFIG_SCST_PROC
.add_device = vdisk_add_nullio_device,
.del_device = vdisk_del_device,
@@ -694,6 +703,7 @@ static struct scst_dev_type vcdrom_devtype = {
.exec = vcdrom_exec,
.on_free_cmd = fileio_on_free_cmd,
.task_mgmt_fn_done = vdisk_task_mgmt_fn_done,
.get_supported_opcodes = vcdrom_get_supported_opcodes,
#ifdef CONFIG_SCST_PROC
.read_proc = vcdrom_read_proc,
.write_proc = vcdrom_write_proc,
@@ -1398,6 +1408,311 @@ static enum compl_status_e vdisk_invalid_opcode(struct vdisk_cmd_params *p)
return INVALID_OPCODE;
}
#define VDEV_DEF_RDPROTECT 0
#define VDEV_DEF_WRPROTECT 0
#define VDEV_DEF_VRPROTECT 0
#define VDEF_DEF_GROUP_NUM 0
static const struct scst_opcode_descriptor scst_op_descr_cwr = {
.od_opcode = COMPARE_AND_WRITE,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 16,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { COMPARE_AND_WRITE, VDEV_DEF_WRPROTECT | 0x18, \
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
0, 0, 0, 0xFF, VDEF_DEF_GROUP_NUM, \
SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_format_unit = {
.od_opcode = FORMAT_UNIT,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 6,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_LONG_TIMEOUT/HZ,
.od_cdb_usage_bits = { FORMAT_UNIT, 0xF0, 0, 0, 0, SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_get_lba_status = {
.od_opcode = SERVICE_ACTION_IN,
.od_serv_action = SAI_GET_LBA_STATUS,
.od_serv_action_valid = 1,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 16,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { SERVICE_ACTION_IN, SAI_GET_LBA_STATUS, \
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
0xFF, 0xFF, 0xFF, 0xFF, 0, \
SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_allow_medium_removal = {
.od_opcode = ALLOW_MEDIUM_REMOVAL,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 6,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { ALLOW_MEDIUM_REMOVAL, 0, 0, 0, 3, SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_read6 = {
.od_opcode = READ_6,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 6,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { READ_6, 0x1F, \
0xFF, 0xFF, 0xFF, SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_read10 = {
.od_opcode = READ_10,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 10,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { READ_10, VDEV_DEF_RDPROTECT | 0x18, \
0xFF, 0xFF, 0xFF, 0xFF, VDEF_DEF_GROUP_NUM, \
0xFF, 0xFF, SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_read12 = {
.od_opcode = READ_12,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 12,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { READ_12, VDEV_DEF_RDPROTECT | 0x18, \
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
VDEF_DEF_GROUP_NUM, SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_read16 = {
.od_opcode = READ_16,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 16,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { READ_16, VDEV_DEF_RDPROTECT | 0x18, \
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
0xFF, 0xFF, 0xFF, 0xFF, VDEF_DEF_GROUP_NUM, \
SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_read_capacity = {
.od_opcode = READ_CAPACITY,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 10,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { READ_CAPACITY, 0, 0, 0, 0, 0, 0, \
0, 0, SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_read_capacity16 = {
.od_opcode = SERVICE_ACTION_IN,
.od_serv_action = SAI_READ_CAPACITY_16,
.od_serv_action_valid = 1,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 16,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { SERVICE_ACTION_IN, SAI_READ_CAPACITY_16, \
0, 0, 0, 0, 0, 0, 0, 0, \
0xFF, 0xFF, 0xFF, 0xFF, 0, \
SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_start_stop_unit = {
.od_opcode = START_STOP,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 6,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { START_STOP, 1, 0, 0xF, 0xF7, SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_sync_cache10 = {
.od_opcode = SYNCHRONIZE_CACHE,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 10,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { SYNCHRONIZE_CACHE, 2, \
0xFF, 0xFF, 0xFF, 0xFF, VDEF_DEF_GROUP_NUM, \
0xFF, 0xFF, SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_sync_cache16 = {
.od_opcode = SYNCHRONIZE_CACHE_16,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 16,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { SYNCHRONIZE_CACHE_16, 2, \
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
0xFF, 0xFF, 0xFF, 0xFF, VDEF_DEF_GROUP_NUM, \
SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_unmap = {
.od_opcode = UNMAP,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 10,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { UNMAP, 0, 0, 0, 0, 0, VDEF_DEF_GROUP_NUM, \
0xFF, 0xFF, SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_verify10 = {
.od_opcode = VERIFY,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 10,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { VERIFY, VDEV_DEF_VRPROTECT | 0x16, \
0xFF, 0xFF, 0xFF, 0xFF, VDEF_DEF_GROUP_NUM, \
0xFF, 0xFF, SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_verify12 = {
.od_opcode = VERIFY_12,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 12,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { VERIFY_12, VDEV_DEF_VRPROTECT | 0x16, \
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
VDEF_DEF_GROUP_NUM, SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_verify16 = {
.od_opcode = VERIFY_16,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 16,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { VERIFY_16, VDEV_DEF_VRPROTECT | 0x16, \
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
0xFF, 0xFF, 0xFF, 0xFF, VDEF_DEF_GROUP_NUM, \
SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_write6 = {
.od_opcode = WRITE_6,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 6,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { WRITE_6, 0x1F, \
0xFF, 0xFF, 0xFF, SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_write10 = {
.od_opcode = WRITE_10,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 10,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { WRITE_10, VDEV_DEF_WRPROTECT | 0x1A, \
0xFF, 0xFF, 0xFF, 0xFF, VDEF_DEF_GROUP_NUM, \
0xFF, 0xFF, SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_write12 = {
.od_opcode = WRITE_12,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 12,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { WRITE_12, VDEV_DEF_WRPROTECT | 0x1A, \
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
VDEF_DEF_GROUP_NUM, SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_write16 = {
.od_opcode = WRITE_16,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 16,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { WRITE_16, VDEV_DEF_WRPROTECT | 0x1A, \
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
0xFF, 0xFF, 0xFF, 0xFF, VDEF_DEF_GROUP_NUM, \
SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_write_verify10 = {
.od_opcode = WRITE_VERIFY,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 10,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { WRITE_VERIFY, VDEV_DEF_WRPROTECT | 0x16, \
0xFF, 0xFF, 0xFF, 0xFF, VDEF_DEF_GROUP_NUM, \
0xFF, 0xFF, SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_write_verify12 = {
.od_opcode = WRITE_VERIFY_12,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 12,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { WRITE_VERIFY_12, VDEV_DEF_WRPROTECT | 0x16, \
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
VDEF_DEF_GROUP_NUM, SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_write_verify16 = {
.od_opcode = WRITE_VERIFY_16,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 16,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { WRITE_VERIFY_16, VDEV_DEF_WRPROTECT | 0x16, \
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
0xFF, 0xFF, 0xFF, 0xFF, VDEF_DEF_GROUP_NUM, \
SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_write_same10 = {
.od_opcode = WRITE_SAME,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 10,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { WRITE_SAME, VDEV_DEF_WRPROTECT | 0x8, \
0xFF, 0xFF, 0xFF, 0xFF, VDEF_DEF_GROUP_NUM, \
0xFF, 0xFF, SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_write_same16 = {
.od_opcode = WRITE_SAME_16,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 16,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { WRITE_SAME_16, VDEV_DEF_WRPROTECT | 0x8, \
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
0xFF, 0xFF, 0xFF, 0xFF, VDEF_DEF_GROUP_NUM, \
SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_read_toc = {
.od_opcode = READ_TOC,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 10,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { READ_TOC, 0, 0xF, 0, 0, 0, 0xFF, \
0xFF, 0xFF, SCST_OD_DEFAULT_CONTROL_BYTE },
};
#define SHARED_OPS \
[SYNCHRONIZE_CACHE] = vdisk_synchronize_cache, \
[SYNCHRONIZE_CACHE_16] = vdisk_synchronize_cache, \
@@ -1427,6 +1742,34 @@ static enum compl_status_e vdisk_invalid_opcode(struct vdisk_cmd_params *p)
[SEND_DIAGNOSTIC] = vdisk_exec_send_diagnostic, \
[FORMAT_UNIT] = vdisk_exec_format_unit,
#define SHARED_OPCODE_DESCRIPTORS \
&scst_op_descr_sync_cache10, \
&scst_op_descr_sync_cache16, \
&scst_op_descr_mode_sense6, \
&scst_op_descr_mode_sense10, \
&scst_op_descr_mode_select6, \
&scst_op_descr_mode_select10, \
&scst_op_descr_log_select, \
&scst_op_descr_log_sense, \
&scst_op_descr_start_stop_unit, \
&scst_op_descr_read_capacity, \
&scst_op_descr_send_diagnostic, \
&scst_op_descr_rtpg, \
&scst_op_descr_read6, \
&scst_op_descr_read10, \
&scst_op_descr_read12, \
&scst_op_descr_read16, \
&scst_op_descr_write6, \
&scst_op_descr_write10, \
&scst_op_descr_write12, \
&scst_op_descr_write16, \
&scst_op_descr_write_verify10, \
&scst_op_descr_write_verify12, \
&scst_op_descr_write_verify16, \
&scst_op_descr_verify10, \
&scst_op_descr_verify12, \
&scst_op_descr_verify16,
static vdisk_op_fn blockio_ops[256] = {
[READ_6] = blockio_exec_read,
[READ_10] = blockio_exec_read,
@@ -1481,6 +1824,45 @@ static vdisk_op_fn nullio_ops[256] = {
SHARED_OPS
};
static const struct scst_opcode_descriptor *vdisk_opcode_descriptors[] = {
SHARED_OPCODE_DESCRIPTORS
#if 0 /* it's INVALID OPCODE currently */
&scst_op_descr_get_lba_status,
#endif
&scst_op_descr_read_capacity16,
&scst_op_descr_write_same10,
&scst_op_descr_write_same16,
&scst_op_descr_unmap,
&scst_op_descr_format_unit,
&scst_op_descr_cwr,
SCST_OPCODE_DESCRIPTORS
};
static const struct scst_opcode_descriptor *vcdrom_opcode_descriptors[] = {
SHARED_OPCODE_DESCRIPTORS
&scst_op_descr_allow_medium_removal,
&scst_op_descr_read_toc,
SCST_OPCODE_DESCRIPTORS
};
static int vdisk_get_supported_opcodes(struct scst_cmd *cmd,
const struct scst_opcode_descriptor ***out_supp_opcodes,
int *out_supp_opcodes_cnt)
{
*out_supp_opcodes = vdisk_opcode_descriptors;
*out_supp_opcodes_cnt = ARRAY_SIZE(vdisk_opcode_descriptors);
return 0;
}
static int vcdrom_get_supported_opcodes(struct scst_cmd *cmd,
const struct scst_opcode_descriptor ***out_supp_opcodes,
int *out_supp_opcodes_cnt)
{
*out_supp_opcodes = vcdrom_opcode_descriptors;
*out_supp_opcodes_cnt = ARRAY_SIZE(vcdrom_opcode_descriptors);
return 0;
}
/*
* Compute p->loff and p->fua.
* Returns true for success or false otherwise and set error in the commeand.
@@ -3535,6 +3917,7 @@ out:
static enum compl_status_e vdisk_exec_get_lba_status(struct vdisk_cmd_params *p)
{
/* Changing it don't forget to add it to vdisk_opcode_descriptors! */
return INVALID_OPCODE;
}

View File

@@ -88,6 +88,240 @@ static int sg_copy(struct scatterlist *dst_sg, struct scatterlist *src_sg,
static void scst_free_descriptors(struct scst_cmd *cmd);
const struct scst_opcode_descriptor scst_op_descr_inquiry = {
.od_opcode = INQUIRY,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 6,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { INQUIRY, 1, 0xFF, 0xFF, 0xFF, SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_inquiry);
const struct scst_opcode_descriptor scst_op_descr_tur = {
.od_opcode = TEST_UNIT_READY,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 6,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { TEST_UNIT_READY, 0, 0, 0, 0, SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_tur);
const struct scst_opcode_descriptor scst_op_descr_log_select = {
.od_opcode = LOG_SELECT,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 10,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { LOG_SELECT, 3, 0xFF, 0xFF, 0, 0, 0, 0xFF, 0xFF, \
SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_log_select);
const struct scst_opcode_descriptor scst_op_descr_log_sense = {
.od_opcode = LOG_SENSE,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 10,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { LOG_SENSE, 1, 0xFF, 0xFF, 0, 0xFF, 0xFF, 0xFF, 0xFF, \
SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_log_sense);
const struct scst_opcode_descriptor scst_op_descr_mode_select6 = {
.od_opcode = MODE_SELECT,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 6,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { MODE_SELECT, 0x11, 0, 0, 0xFF, SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_mode_select6);
const struct scst_opcode_descriptor scst_op_descr_mode_sense6 = {
.od_opcode = MODE_SENSE,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 6,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { MODE_SENSE, 8, 0xFF, 0xFF, 0xFF, SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_mode_sense6);
const struct scst_opcode_descriptor scst_op_descr_mode_select10 = {
.od_opcode = MODE_SELECT_10,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 10,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { MODE_SELECT_10, 0x11, 0, 0, 0, 0, 0, 0xFF, 0xFF, \
SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_mode_select10);
const struct scst_opcode_descriptor scst_op_descr_mode_sense10 = {
.od_opcode = MODE_SENSE_10,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 10,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { MODE_SENSE_10, 0x18, 0xFF, 0xFF, 0, 0, 0, 0xFF, 0xFF, \
SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_mode_sense10);
const struct scst_opcode_descriptor scst_op_descr_rtpg = {
.od_opcode = MAINTENANCE_IN,
.od_serv_action = MI_REPORT_TARGET_PGS,
.od_serv_action_valid = 1,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 12,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { MAINTENANCE_IN, 0xE0|MI_REPORT_TARGET_PGS, 0, 0, \
0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0, SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_rtpg);
const struct scst_opcode_descriptor scst_op_descr_stpg = {
.od_opcode = MAINTENANCE_OUT,
.od_serv_action = MO_SET_TARGET_PGS,
.od_serv_action_valid = 1,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 12,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { MAINTENANCE_IN, MO_SET_TARGET_PGS, 0, 0, 0, 0, \
0xFF, 0xFF, 0xFF, 0xFF, 0, SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_stpg);
const struct scst_opcode_descriptor scst_op_descr_send_diagnostic = {
.od_opcode = SEND_DIAGNOSTIC,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 6,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { SEND_DIAGNOSTIC, 0xF7, 0, 0xFF, 0xFF, \
SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_send_diagnostic);
const struct scst_opcode_descriptor scst_op_descr_reserve6 = {
.od_opcode = RESERVE,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 6,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { RESERVE, 0, 0, 0, 0, SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_reserve6);
const struct scst_opcode_descriptor scst_op_descr_release6 = {
.od_opcode = RELEASE,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 6,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { RELEASE, 0, 0, 0, 0, SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_release6);
const struct scst_opcode_descriptor scst_op_descr_reserve10 = {
.od_opcode = RESERVE_10,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 10,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { RESERVE_10, 0, 0, 0, 0, 0, 0, 0, 0, \
SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_reserve10);
const struct scst_opcode_descriptor scst_op_descr_release10 = {
.od_opcode = RELEASE_10,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 10,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { RELEASE_10, 0, 0, 0, 0, 0, 0, 0, 0, \
SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_release10);
const struct scst_opcode_descriptor scst_op_descr_pr_in = {
.od_opcode = PERSISTENT_RESERVE_IN,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 10,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { PERSISTENT_RESERVE_IN, 0x1F, 0, 0, 0, 0, 0, 0xFF, 0xFF, \
SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_pr_in);
const struct scst_opcode_descriptor scst_op_descr_pr_out = {
.od_opcode = PERSISTENT_RESERVE_OUT,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 10,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { PERSISTENT_RESERVE_OUT, 0x1F, 0xFF, 0, 0, 0xFF, \
0xFF, 0xFF, 0xFF, SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_pr_out);
const struct scst_opcode_descriptor scst_op_descr_report_luns = {
.od_opcode = REPORT_LUNS,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 12,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { REPORT_LUNS, 0, 0xFF, 0, 0, 0, 0xFF, 0xFF, \
0xFF, 0xFF, 0, SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_report_luns);
const struct scst_opcode_descriptor scst_op_descr_request_sense = {
.od_opcode = REQUEST_SENSE,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 6,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { REQUEST_SENSE, 1, 0, 0, 0xFF, SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_request_sense);
const struct scst_opcode_descriptor scst_op_descr_report_supp_tm_fns = {
.od_opcode = MAINTENANCE_IN,
.od_serv_action = MI_REPORT_SUPPORTED_TASK_MANAGEMENT_FUNCTIONS,
.od_serv_action_valid = 1,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 12,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { MAINTENANCE_IN, MI_REPORT_SUPPORTED_TASK_MANAGEMENT_FUNCTIONS, \
0x80, 0, 0, 0, 0xFF, 0xFF, 0xFF, \
0xFF, 0, SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_report_supp_tm_fns);
const struct scst_opcode_descriptor scst_op_descr_report_supp_opcodes = {
.od_opcode = MAINTENANCE_IN,
.od_serv_action = MI_REPORT_SUPPORTED_OPERATION_CODES,
.od_serv_action_valid = 1,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 12,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { MAINTENANCE_IN, MI_REPORT_SUPPORTED_OPERATION_CODES, \
0x87, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
0xFF, 0, SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_report_supp_opcodes);
struct scst_sdbops;
static int get_cdb_info_len_10(struct scst_cmd *cmd,
@@ -6901,7 +7135,8 @@ static int get_cdb_info_min(struct scst_cmd *cmd,
break;
case MI_REPORT_SUPPORTED_OPERATION_CODES:
cmd->op_name = "REPORT SUPPORTED OPERATION CODES";
cmd->op_flags |= SCST_WRITE_EXCL_ALLOWED;
cmd->op_flags |= SCST_WRITE_EXCL_ALLOWED |
SCST_LOCAL_CMD | SCST_FULLY_LOCAL_CMD;
break;
case MI_REPORT_SUPPORTED_TASK_MANAGEMENT_FUNCTIONS:
cmd->op_name = "REPORT SUPPORTED TASK MANAGEMENT FUNCTIONS";

View File

@@ -2111,6 +2111,208 @@ out_compl:
return res;
}
static int scst_report_supported_opcodes(struct scst_cmd *cmd)
{
int res = SCST_EXEC_COMPLETED;
int length, buf_len, i, offs;
uint8_t *address;
uint8_t *buf;
bool inline_buf;
bool rctd = cmd->cdb[2] >> 7;
int options = cmd->cdb[2] & 7;
int req_opcode = cmd->cdb[3];
int req_sa = get_unaligned_be16(&cmd->cdb[4]);
const struct scst_opcode_descriptor *op = NULL;
const struct scst_opcode_descriptor **supp_opcodes = NULL;
int supp_opcodes_cnt;
TRACE_ENTRY();
if (cmd->devt->get_supported_opcodes == NULL) {
TRACE(TRACE_MINOR, "Unknown opcode 0x%02x", cmd->cdb[0]);
scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_invalid_opcode));
goto out_compl;
} else {
int rc = cmd->devt->get_supported_opcodes(cmd, &supp_opcodes,
&supp_opcodes_cnt);
if (rc != 0)
goto out_compl;
}
TRACE_DBG("cmd %p, options %d, req_opcode %x, req_sa %x, rctd %d",
cmd, options, req_opcode, req_sa, rctd);
switch (options) {
case 0: /* all */
buf_len = 4;
for (i = 0; i < supp_opcodes_cnt; i++) {
buf_len += 8;
if (rctd)
buf_len += 12;
}
break;
case 1:
buf_len = 0;
for (i = 0; i < supp_opcodes_cnt; i++) {
if (req_opcode == supp_opcodes[i]->od_opcode) {
op = supp_opcodes[i];
if (op->od_serv_action_valid) {
TRACE(TRACE_MINOR, "Requested opcode %x "
"with unexpected service action "
"(dev %s, initiator %s)",
req_opcode, cmd->dev->virt_name,
cmd->sess->initiator_name);
scst_set_invalid_field_in_cdb(cmd, 2,
SCST_INVAL_FIELD_BIT_OFFS_VALID | 0);
goto out_compl;
}
buf_len = 4 + op->od_cdb_size;
if (rctd)
buf_len += 12;
break;
}
}
if (op == NULL) {
TRACE(TRACE_MINOR, "Requested opcode %x not found "
"(dev %s, initiator %s)", req_opcode,
cmd->dev->virt_name, cmd->sess->initiator_name);
buf_len = 4;
}
break;
case 2:
buf_len = 0;
for (i = 0; i < supp_opcodes_cnt; i++) {
if (req_opcode == supp_opcodes[i]->od_opcode) {
op = supp_opcodes[i];
if (!op->od_serv_action_valid) {
TRACE(TRACE_MINOR, "Requested opcode %x "
"without expected service action "
"(dev %s, initiator %s)",
req_opcode, cmd->dev->virt_name,
cmd->sess->initiator_name);
scst_set_invalid_field_in_cdb(cmd, 2,
SCST_INVAL_FIELD_BIT_OFFS_VALID | 0);
goto out_compl;
}
if (req_sa != op->od_serv_action) {
op = NULL; /* reset it */
continue;
}
buf_len = 4 + op->od_cdb_size;
if (rctd)
buf_len += 12;
break;
}
}
if (op == NULL) {
TRACE(TRACE_MINOR, "Requested opcode %x/%x not found "
"(dev %s, initiator %s)", req_opcode, req_sa,
cmd->dev->virt_name, cmd->sess->initiator_name);
buf_len = 4;
}
break;
default:
PRINT_ERROR("REPORT SUPPORTED OPERATION CODES: REPORTING OPTIONS "
"%x not supported (dev %s, initiator %s)", options,
cmd->dev->virt_name, cmd->sess->initiator_name);
scst_set_invalid_field_in_cdb(cmd, 2,
SCST_INVAL_FIELD_BIT_OFFS_VALID | 0);
goto out_compl;
}
length = scst_get_buf_full_sense(cmd, &address);
TRACE_DBG("length %d, buf_len %d, op %p", length, buf_len, op);
if (unlikely(length <= 0))
goto out_compl;
if (length >= buf_len) {
buf = address;
inline_buf = true;
} else {
buf = vzalloc(buf_len); /* it can be big */
if (buf == NULL) {
PRINT_ERROR("Unable to allocate REPORT SUPPORTED "
"OPERATION CODES buffer with size %d", buf_len);
scst_set_busy(cmd);
goto out_err_put;
}
inline_buf = false;
}
memset(buf, 0, sizeof(buf));
switch(options) {
case 0: /* all */
put_unaligned_be32(buf_len - 3, &buf[0]);
offs = 4;
for (i = 0; i < supp_opcodes_cnt; i++) {
op = supp_opcodes[i];
buf[offs] = op->od_opcode;
if (op->od_serv_action_valid) {
put_unaligned_be16(op->od_serv_action, &buf[offs + 2]);
buf[offs + 5] |= 1;
}
put_unaligned_be16(op->od_cdb_size, &buf[offs + 6]);
offs += 8;
if (rctd) {
buf[(offs - 8) + 5] |= 2;
buf[offs + 1] = 0xA;
buf[offs + 3] = op->od_comm_specific_timeout;
put_unaligned_be32(op->od_nominal_timeout, &buf[offs + 4]);
put_unaligned_be32(op->od_recommended_timeout, &buf[offs + 8]);
offs += 12;
}
}
break;
case 1:
case 2:
if (op != NULL) {
buf[1] |= op->od_support;
put_unaligned_be16(op->od_cdb_size, &buf[2]);
memcpy(&buf[4], op->od_cdb_usage_bits, op->od_cdb_size);
if (rctd) {
buf[1] |= 0x80;
offs = 4 + op->od_cdb_size;
buf[offs + 1] = 0xA;
buf[offs + 3] = op->od_comm_specific_timeout;
put_unaligned_be32(op->od_nominal_timeout, &buf[offs + 4]);
put_unaligned_be32(op->od_recommended_timeout, &buf[offs + 8]);
}
}
break;
default:
sBUG_ON(1);
goto out_compl;
}
if (length > buf_len)
length = buf_len;
if (!inline_buf) {
memcpy(address, buf, length);
vfree(buf);
}
scst_put_buf_full(cmd, address);
if (length < cmd->resp_data_len)
scst_set_resp_data_len(cmd, length);
out_compl:
if ((supp_opcodes != NULL) && (cmd->devt->put_supported_opcodes != NULL))
cmd->devt->put_supported_opcodes(cmd, supp_opcodes, supp_opcodes_cnt);
cmd->completed = 1;
/* Report the result */
cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT, SCST_CONTEXT_SAME);
TRACE_EXIT_RES(res);
return res;
out_err_put:
scst_put_buf_full(cmd, address);
goto out_compl;
}
static int scst_maintenance_in(struct scst_cmd *cmd)
{
int res;
@@ -2121,6 +2323,9 @@ static int scst_maintenance_in(struct scst_cmd *cmd)
case MI_REPORT_SUPPORTED_TASK_MANAGEMENT_FUNCTIONS:
res = scst_report_supported_tm_fns(cmd);
break;
case MI_REPORT_SUPPORTED_OPERATION_CODES:
res = scst_report_supported_opcodes(cmd);
break;
default:
res = SCST_EXEC_NOT_COMPLETED;
break;