#include <target/target_core_transport.h>
#include <target/target_core_fabric_ops.h>
#include "target_core_ua.h"
+#include "target_core_cdb.h"
static void
target_fill_alua_data(struct se_port *port, unsigned char *buf)
if (cmd->data_length < 60)
return 0;
- buf[2] = 0x3c;
+ buf[3] = 0x3c;
/* Set HEADSUP, ORDSUP, SIMPSUP */
buf[5] = 0x07;
return 0;
}
-static int
-target_emulate_inquiry(struct se_cmd *cmd)
+int target_emulate_inquiry(struct se_task *task)
{
+ struct se_cmd *cmd = task->task_se_cmd;
struct se_device *dev = cmd->se_dev;
unsigned char *buf;
unsigned char *cdb = cmd->t_task_cdb;
int p, ret;
- if (!(cdb[1] & 0x1))
- return target_emulate_inquiry_std(cmd);
+ if (!(cdb[1] & 0x1)) {
+ ret = target_emulate_inquiry_std(cmd);
+ goto out;
+ }
/*
* Make sure we at least have 4 bytes of INQUIRY response
if (cmd->data_length < 4) {
pr_err("SCSI Inquiry payload length: %u"
" too small for EVPD=1\n", cmd->data_length);
+ cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD;
return -EINVAL;
}
buf[0] = dev->transport->get_device_type(dev);
- for (p = 0; p < ARRAY_SIZE(evpd_handlers); ++p)
+ for (p = 0; p < ARRAY_SIZE(evpd_handlers); ++p) {
if (cdb[2] == evpd_handlers[p].page) {
buf[1] = cdb[2];
ret = evpd_handlers[p].emulate(cmd, buf);
- transport_kunmap_first_data_page(cmd);
- return ret;
+ goto out_unmap;
}
+ }
- transport_kunmap_first_data_page(cmd);
pr_err("Unknown VPD Code: 0x%02x\n", cdb[2]);
- return -EINVAL;
+ cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE;
+ ret = -EINVAL;
+
+out_unmap:
+ transport_kunmap_first_data_page(cmd);
+out:
+ if (!ret) {
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
+ }
+ return ret;
}
-static int
-target_emulate_readcapacity(struct se_cmd *cmd)
+int target_emulate_readcapacity(struct se_task *task)
{
+ struct se_cmd *cmd = task->task_se_cmd;
struct se_device *dev = cmd->se_dev;
unsigned char *buf;
unsigned long long blocks_long = dev->transport->get_blocks(dev);
transport_kunmap_first_data_page(cmd);
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
return 0;
}
-static int
-target_emulate_readcapacity_16(struct se_cmd *cmd)
+int target_emulate_readcapacity_16(struct se_task *task)
{
+ struct se_cmd *cmd = task->task_se_cmd;
struct se_device *dev = cmd->se_dev;
unsigned char *buf;
unsigned long long blocks = dev->transport->get_blocks(dev);
transport_kunmap_first_data_page(cmd);
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
return 0;
}
}
}
-static int
-target_emulate_modesense(struct se_cmd *cmd, int ten)
+int target_emulate_modesense(struct se_task *task)
{
+ struct se_cmd *cmd = task->task_se_cmd;
struct se_device *dev = cmd->se_dev;
char *cdb = cmd->t_task_cdb;
unsigned char *rbuf;
int type = dev->transport->get_device_type(dev);
- int offset = (ten) ? 8 : 4;
+ int ten = (cmd->t_task_cdb[0] == MODE_SENSE_10);
+ int offset = ten ? 8 : 4;
int length = 0;
unsigned char buf[SE_MODE_PAGE_BUF];
default:
pr_err("MODE SENSE: unimplemented page/subpage: 0x%02x/0x%02x\n",
cdb[2] & 0x3f, cdb[3]);
- return PYX_TRANSPORT_UNKNOWN_MODE_PAGE;
+ cmd->scsi_sense_reason = TCM_UNKNOWN_MODE_PAGE;
+ return -EINVAL;
}
offset += length;
memcpy(rbuf, buf, offset);
transport_kunmap_first_data_page(cmd);
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
return 0;
}
-static int
-target_emulate_request_sense(struct se_cmd *cmd)
+int target_emulate_request_sense(struct se_task *task)
{
+ struct se_cmd *cmd = task->task_se_cmd;
unsigned char *cdb = cmd->t_task_cdb;
unsigned char *buf;
u8 ua_asc = 0, ua_ascq = 0;
if (cdb[1] & 0x01) {
pr_err("REQUEST_SENSE description emulation not"
" supported\n");
- return PYX_TRANSPORT_INVALID_CDB_FIELD;
+ cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD;
+ return -ENOSYS;
}
buf = transport_kmap_first_data_page(cmd);
end:
transport_kunmap_first_data_page(cmd);
-
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
return 0;
}
* Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support.
* Note this is not used for TCM/pSCSI passthrough
*/
-static int
-target_emulate_unmap(struct se_task *task)
+int target_emulate_unmap(struct se_task *task)
{
struct se_cmd *cmd = task->task_se_cmd;
struct se_device *dev = cmd->se_dev;
int ret = 0, offset;
unsigned short dl, bd_dl;
+ if (!dev->transport->do_discard) {
+ pr_err("UNMAP emulation not supported for: %s\n",
+ dev->transport->name);
+ cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE;
+ return -ENOSYS;
+ }
+
/* First UNMAP block descriptor starts at 8 byte offset */
offset = 8;
size -= 8;
err:
transport_kunmap_first_data_page(cmd);
-
+ if (!ret) {
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
+ }
return ret;
}
* Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support.
* Note this is not used for TCM/pSCSI passthrough
*/
-static int
-target_emulate_write_same(struct se_task *task, u32 num_blocks)
+int target_emulate_write_same(struct se_task *task)
{
struct se_cmd *cmd = task->task_se_cmd;
struct se_device *dev = cmd->se_dev;
sector_t range;
sector_t lba = cmd->t_task_lba;
+ u32 num_blocks;
int ret;
+
+ if (!dev->transport->do_discard) {
+ pr_err("WRITE_SAME emulation not supported"
+ " for: %s\n", dev->transport->name);
+ cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE;
+ return -ENOSYS;
+ }
+
+ if (cmd->t_task_cdb[0] == WRITE_SAME)
+ num_blocks = get_unaligned_be16(&cmd->t_task_cdb[7]);
+ else if (cmd->t_task_cdb[0] == WRITE_SAME_16)
+ num_blocks = get_unaligned_be32(&cmd->t_task_cdb[10]);
+ else /* WRITE_SAME_32 via VARIABLE_LENGTH_CMD */
+ num_blocks = get_unaligned_be32(&cmd->t_task_cdb[28]);
+
/*
* Use the explicit range when non zero is supplied, otherwise calculate
* the remaining range based on ->get_blocks() - starting LBA.
return ret;
}
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
return 0;
}
-int
-transport_emulate_control_cdb(struct se_task *task)
+int target_emulate_synchronize_cache(struct se_task *task)
{
+ struct se_device *dev = task->task_se_cmd->se_dev;
struct se_cmd *cmd = task->task_se_cmd;
- struct se_device *dev = cmd->se_dev;
- unsigned short service_action;
- int ret = 0;
- switch (cmd->t_task_cdb[0]) {
- case INQUIRY:
- ret = target_emulate_inquiry(cmd);
- break;
- case READ_CAPACITY:
- ret = target_emulate_readcapacity(cmd);
- break;
- case MODE_SENSE:
- ret = target_emulate_modesense(cmd, 0);
- break;
- case MODE_SENSE_10:
- ret = target_emulate_modesense(cmd, 1);
- break;
- case SERVICE_ACTION_IN:
- switch (cmd->t_task_cdb[1] & 0x1f) {
- case SAI_READ_CAPACITY_16:
- ret = target_emulate_readcapacity_16(cmd);
- break;
- default:
- pr_err("Unsupported SA: 0x%02x\n",
- cmd->t_task_cdb[1] & 0x1f);
- return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
- }
- break;
- case REQUEST_SENSE:
- ret = target_emulate_request_sense(cmd);
- break;
- case UNMAP:
- if (!dev->transport->do_discard) {
- pr_err("UNMAP emulation not supported for: %s\n",
- dev->transport->name);
- return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
- }
- ret = target_emulate_unmap(task);
- break;
- case WRITE_SAME:
- if (!dev->transport->do_discard) {
- pr_err("WRITE_SAME emulation not supported"
- " for: %s\n", dev->transport->name);
- return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
- }
- ret = target_emulate_write_same(task,
- get_unaligned_be16(&cmd->t_task_cdb[7]));
- break;
- case WRITE_SAME_16:
- if (!dev->transport->do_discard) {
- pr_err("WRITE_SAME_16 emulation not supported"
- " for: %s\n", dev->transport->name);
- return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
- }
- ret = target_emulate_write_same(task,
- get_unaligned_be32(&cmd->t_task_cdb[10]));
- break;
- case VARIABLE_LENGTH_CMD:
- service_action =
- get_unaligned_be16(&cmd->t_task_cdb[8]);
- switch (service_action) {
- case WRITE_SAME_32:
- if (!dev->transport->do_discard) {
- pr_err("WRITE_SAME_32 SA emulation not"
- " supported for: %s\n",
- dev->transport->name);
- return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
- }
- ret = target_emulate_write_same(task,
- get_unaligned_be32(&cmd->t_task_cdb[28]));
- break;
- default:
- pr_err("Unsupported VARIABLE_LENGTH_CMD SA:"
- " 0x%02x\n", service_action);
- break;
- }
- break;
- case SYNCHRONIZE_CACHE:
- case 0x91: /* SYNCHRONIZE_CACHE_16: */
- if (!dev->transport->do_sync_cache) {
- pr_err("SYNCHRONIZE_CACHE emulation not supported"
- " for: %s\n", dev->transport->name);
- return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
- }
- dev->transport->do_sync_cache(task);
- break;
- case ALLOW_MEDIUM_REMOVAL:
- case ERASE:
- case REZERO_UNIT:
- case SEEK_10:
- case SPACE:
- case START_STOP:
- case TEST_UNIT_READY:
- case VERIFY:
- case WRITE_FILEMARKS:
- break;
- default:
- pr_err("Unsupported SCSI Opcode: 0x%02x for %s\n",
- cmd->t_task_cdb[0], dev->transport->name);
- return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ if (!dev->transport->do_sync_cache) {
+ pr_err("SYNCHRONIZE_CACHE emulation not supported"
+ " for: %s\n", dev->transport->name);
+ cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE;
+ return -ENOSYS;
}
- if (ret < 0)
- return ret;
- /*
- * Handle the successful completion here unless a caller
- * has explictly requested an asychronous completion.
- */
- if (!(cmd->se_cmd_flags & SCF_EMULATE_CDB_ASYNC)) {
- task->task_scsi_status = GOOD;
- transport_complete_task(task, 1);
- }
+ dev->transport->do_sync_cache(task);
+ return 0;
+}
- return PYX_TRANSPORT_SENT_TO_TRANSPORT;
+int target_emulate_noop(struct se_task *task)
+{
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
+ return 0;
}
/*