Merge branch 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[pandora-kernel.git] / drivers / target / target_core_cdb.c
index 38535eb..831468b 100644 (file)
@@ -32,6 +32,7 @@
 #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)
@@ -477,7 +478,7 @@ target_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf)
        if (cmd->data_length < 60)
                return 0;
 
-       buf[2] = 0x3c;
+       buf[3] = 0x3c;
        /* Set HEADSUP, ORDSUP, SIMPSUP */
        buf[5] = 0x07;
 
@@ -679,16 +680,18 @@ target_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf)
        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
@@ -700,6 +703,7 @@ target_emulate_inquiry(struct se_cmd *cmd)
        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;
        }
 
@@ -707,22 +711,31 @@ target_emulate_inquiry(struct se_cmd *cmd)
 
        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);
@@ -751,12 +764,14 @@ target_emulate_readcapacity(struct se_cmd *cmd)
 
        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);
@@ -784,6 +799,8 @@ target_emulate_readcapacity_16(struct se_cmd *cmd)
 
        transport_kunmap_first_data_page(cmd);
 
+       task->task_scsi_status = GOOD;
+       transport_complete_task(task, 1);
        return 0;
 }
 
@@ -922,14 +939,15 @@ target_modesense_dpofua(unsigned char *buf, int type)
        }
 }
 
-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];
 
@@ -953,7 +971,8 @@ target_emulate_modesense(struct se_cmd *cmd, int ten)
        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;
 
@@ -995,12 +1014,14 @@ target_emulate_modesense(struct se_cmd *cmd, int ten)
        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;
@@ -1009,7 +1030,8 @@ target_emulate_request_sense(struct se_cmd *cmd)
        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);
@@ -1059,7 +1081,8 @@ target_emulate_request_sense(struct se_cmd *cmd)
 
 end:
        transport_kunmap_first_data_page(cmd);
-
+       task->task_scsi_status = GOOD;
+       transport_complete_task(task, 1);
        return 0;
 }
 
@@ -1067,8 +1090,7 @@ end:
  * 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;
@@ -1079,6 +1101,13 @@ target_emulate_unmap(struct se_task *task)
        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;
@@ -1110,7 +1139,10 @@ target_emulate_unmap(struct se_task *task)
 
 err:
        transport_kunmap_first_data_page(cmd);
-
+       if (!ret) {
+               task->task_scsi_status = GOOD;
+               transport_complete_task(task, 1);
+       }
        return ret;
 }
 
@@ -1118,14 +1150,29 @@ err:
  * 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.
@@ -1144,127 +1191,32 @@ target_emulate_write_same(struct se_task *task, u32 num_blocks)
                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;
 }
 
 /*