- Cleanups and improvements in handling various special commands properties
authorvlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Fri, 1 May 2009 19:26:10 +0000 (19:26 +0000)
committervlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Fri, 1 May 2009 19:26:10 +0000 (19:26 +0000)
 - REQUEST SENSE handling improved
 - READ CAPACITY(16) handling improved
 - New write_medium member added to scst_user's scst_user_scsi_cmd_reply_parse
 - scst_user docs updated
 - Other minot cleanups

git-svn-id: https://scst.svn.sourceforge.net/svnroot/scst/trunk@816 d57e44dd-8a1f-0410-8b47-8ef2f437770f

19 files changed:
doc/scst_user_spec.txt
scst/include/scst.h
scst/include/scst_const.h
scst/include/scst_user.h
scst/src/dev_handlers/scst_cdrom.c
scst/src/dev_handlers/scst_changer.c
scst/src/dev_handlers/scst_disk.c
scst/src/dev_handlers/scst_modisk.c
scst/src/dev_handlers/scst_processor.c
scst/src/dev_handlers/scst_raid.c
scst/src/dev_handlers/scst_tape.c
scst/src/dev_handlers/scst_user.c
scst/src/dev_handlers/scst_vdisk.c
scst/src/scst_cdbprobe.h
scst/src/scst_lib.c
scst/src/scst_priv.h
scst/src/scst_proc.c
scst/src/scst_targ.c
usr/fileio/common.c

index 54c8096..e858464 100644 (file)
@@ -785,6 +785,7 @@ struct scst_user_scsi_cmd_reply_parse
 {
        uint8_t queue_type;
        uint8_t data_direction;
+       uint8_t write_medium;
        int32_t data_len;
        int32_t bufflen;
 },
@@ -795,6 +796,9 @@ where:
  
  - data_direction - command's data flow direction, one of SCST_DATA_* constants
 
+ - write_medium - true, if command writes data to medium, so should be
+   forbidden for read-only devices, false otherwise
+
  - data_len - command's data length
  
  - bufflen - command's buffer length
index 1709c5f..f6af5fe 100644 (file)
@@ -477,12 +477,17 @@ typedef enum dma_data_direction scst_data_direction;
 
 enum scst_cdb_flags {
        /* SCST_TRANSFER_LEN_TYPE_FIXED must be equiv 1 (FIXED_BIT in cdb) */
-       SCST_TRANSFER_LEN_TYPE_FIXED = 0x01,
-       SCST_SMALL_TIMEOUT = 0x02,
-       SCST_LONG_TIMEOUT = 0x04,
-       SCST_UNKNOWN_LENGTH = 0x08,
-       SCST_INFO_INVALID = 0x10,
-       SCST_VERIFY_BYTCHK_MISMATCH_ALLOWED = 0x20,
+       SCST_TRANSFER_LEN_TYPE_FIXED =          0x001,
+       SCST_SMALL_TIMEOUT =                    0x002,
+       SCST_LONG_TIMEOUT =                     0x004,
+       SCST_UNKNOWN_LENGTH =                   0x008,
+       SCST_INFO_NOT_FOUND =                   0x010, /* must be single bit */
+       SCST_VERIFY_BYTCHK_MISMATCH_ALLOWED =   0x020,
+       SCST_IMPLICIT_HQ =                      0x040,
+       SCST_SKIP_UA =                          0x080,
+       SCST_WRITE_MEDIUM =                     0x100,
+       SCST_LOCAL_CMD =                        0x200,
+       SCST_LOCAL_EXEC_NEEDED =                0x400,
 };
 
 /*
@@ -1605,6 +1610,13 @@ struct scst_tgt_dev {
 
        /* internal tmp list entry */
        struct list_head extra_tgt_dev_list_entry;
+
+       /*
+        * Stored Unit Attention sense and its length for possible
+        * subsequent RQUEST SENSE. Both protected by tgt_dev_lock.
+        */
+       unsigned short tgt_dev_valid_sense_len;
+       uint8_t tgt_dev_sense[SCST_SENSE_BUFFERSIZE];
 };
 
 /*
@@ -2051,14 +2063,9 @@ enum dma_data_direction scst_to_tgt_dma_dir(int scst_dir);
  * Returns 1, if cmd's CDB is locally handled by SCST and 0 otherwise.
  * Dev handlers parse() and dev_done() not called for such commands.
  */
-static inline int scst_is_cmd_local(struct scst_cmd *cmd)
+static inline bool scst_is_cmd_local(struct scst_cmd *cmd)
 {
-       int res = 0;
-       switch (cmd->cdb[0]) {
-       case REPORT_LUNS:
-               res = 1;
-       }
-       return res;
+       return (cmd->op_flags & SCST_LOCAL_CMD) != 0;
 }
 
 /*
index 376e239..bb7af8e 100644 (file)
@@ -295,7 +295,7 @@ static inline int scst_is_ua_sense(const uint8_t *sense)
  *************************************************************/
 #define SCST_SENSE_ASC_UA_RESET      0x29
 #define READ_CAP_LEN                8
-#define READ_CAP16_LEN              12
+#define READ_CAP16_LEN              32
 #define BYTCHK                      0x02
 #define POSITION_LEN_SHORT           20
 #define POSITION_LEN_LONG            32
index cc2d771..dc2e5cd 100644 (file)
@@ -206,6 +206,7 @@ struct scst_user_get_cmd {
 struct scst_user_scsi_cmd_reply_parse {
        uint8_t queue_type;
        uint8_t data_direction;
+       uint8_t write_medium;
        int32_t data_len;
        int32_t bufflen;
 };
index 8437b09..a73deaf 100644 (file)
@@ -75,7 +75,7 @@ static int cdrom_attach(struct scst_device *dev)
        TRACE_ENTRY();
 
        if (dev->scsi_dev == NULL ||
-           dev->scsi_dev->type != dev->handler->type) {
+           dev->scsi_dev->type != dev->type) {
                PRINT_ERROR("%s", "SCSI device not define or illegal type");
                res = -ENODEV;
                goto out;
index bfbd338..5c5fdf8 100644 (file)
@@ -65,7 +65,7 @@ static int changer_attach(struct scst_device *dev)
        TRACE_ENTRY();
 
        if (dev->scsi_dev == NULL ||
-           dev->scsi_dev->type != dev->handler->type) {
+           dev->scsi_dev->type != dev->type) {
                PRINT_ERROR("%s", "SCSI device not define or illegal type");
                res = -ENODEV;
                goto out;
index 53dbe17..cba330a 100644 (file)
@@ -151,7 +151,7 @@ static int disk_attach(struct scst_device *dev)
        TRACE_ENTRY();
 
        if (dev->scsi_dev == NULL ||
-           dev->scsi_dev->type != dev->handler->type) {
+           dev->scsi_dev->type != dev->type) {
                PRINT_ERROR("%s", "SCSI device not define or illegal type");
                res = -ENODEV;
                goto out;
index fc36709..99f5eb3 100644 (file)
@@ -151,7 +151,7 @@ static int modisk_attach(struct scst_device *dev)
        TRACE_ENTRY();
 
        if (dev->scsi_dev == NULL ||
-           dev->scsi_dev->type != dev->handler->type) {
+           dev->scsi_dev->type != dev->type) {
                PRINT_ERROR("%s", "SCSI device not define or illegal type");
                res = -ENODEV;
                goto out;
index 3e5e27a..2caf640 100644 (file)
@@ -65,7 +65,7 @@ static int processor_attach(struct scst_device *dev)
        TRACE_ENTRY();
 
        if (dev->scsi_dev == NULL ||
-           dev->scsi_dev->type != dev->handler->type) {
+           dev->scsi_dev->type != dev->type) {
                PRINT_ERROR("%s", "SCSI device not define or illegal type");
                res = -ENODEV;
                goto out;
index 3903135..37e481c 100644 (file)
@@ -65,7 +65,7 @@ static int raid_attach(struct scst_device *dev)
        TRACE_ENTRY();
 
        if (dev->scsi_dev == NULL ||
-           dev->scsi_dev->type != dev->handler->type) {
+           dev->scsi_dev->type != dev->type) {
                PRINT_ERROR("%s", "SCSI device not define or illegal type");
                res = -ENODEV;
                goto out;
index 355cc36..e2a320e 100644 (file)
@@ -154,7 +154,7 @@ static int tape_attach(struct scst_device *dev)
        TRACE_ENTRY();
 
        if (dev->scsi_dev == NULL ||
-           dev->scsi_dev->type != dev->handler->type) {
+           dev->scsi_dev->type != dev->type) {
                PRINT_ERROR("%s", "SCSI device not define or illegal type");
                res = -ENODEV;
                goto out;
index 8d18f92..52a4510 100644 (file)
@@ -760,14 +760,14 @@ static int dev_user_parse(struct scst_cmd *cmd)
        case SCST_USER_PARSE_STANDARD:
                TRACE_DBG("PARSE STANDARD: ucmd %p", ucmd);
                rc = dev->generic_parse(cmd, dev_user_get_block);
-               if ((rc != 0) || (cmd->op_flags & SCST_INFO_INVALID))
+               if ((rc != 0) || (cmd->op_flags & SCST_INFO_NOT_FOUND))
                        goto out_invalid;
                break;
 
        case SCST_USER_PARSE_EXCEPTION:
                TRACE_DBG("PARSE EXCEPTION: ucmd %p", ucmd);
                rc = dev->generic_parse(cmd, dev_user_get_block);
-               if ((rc == 0) && (!(cmd->op_flags & SCST_INFO_INVALID)))
+               if ((rc == 0) && (!(cmd->op_flags & SCST_INFO_NOT_FOUND)))
                        break;
                else if (rc == SCST_CMD_STATE_NEED_THREAD_CTX) {
                        TRACE_MEM("Restarting PARSE to thread context "
@@ -828,8 +828,7 @@ out:
        return res;
 
 out_invalid:
-       PRINT_ERROR("PARSE failed (ucmd %p, rc %d, invalid %d)", ucmd, rc,
-               cmd->op_flags & SCST_INFO_INVALID);
+       PRINT_ERROR("PARSE failed (ucmd %p, rc %d)", ucmd, rc);
        scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_invalid_opcode));
 
 out_error:
@@ -1249,6 +1248,8 @@ static int dev_user_process_reply_parse(struct scst_user_cmd *ucmd,
        cmd->data_direction = preply->data_direction;
        cmd->bufflen = preply->bufflen;
        cmd->data_len = preply->data_len;
+       if (preply->write_medium)
+               cmd->op_flags |= SCST_WRITE_MEDIUM;
 
 out_process:
        scst_process_active_cmd(cmd, false);
index 22e07ef..654372d 100644 (file)
@@ -507,7 +507,7 @@ static int vdisk_attach(struct scst_device *dev)
                goto out;
        }
 
-       vd = (dev->handler->type == TYPE_DISK) ?
+       vd = (dev->type == TYPE_DISK) ?
                                &vdisk_dev_list :
                                &vcdrom_dev_list;
 
@@ -530,7 +530,7 @@ static int vdisk_attach(struct scst_device *dev)
 
        virt_dev->dev = dev;
 
-       if (dev->handler->type == TYPE_ROM)
+       if (dev->type == TYPE_ROM)
                virt_dev->rd_only_flag = 1;
 
        if (!virt_dev->cdrom_empty) {
@@ -547,7 +547,7 @@ static int vdisk_attach(struct scst_device *dev)
        } else
                virt_dev->file_size = 0;
 
-       if (dev->handler->type == TYPE_DISK) {
+       if (dev->type == TYPE_DISK) {
                virt_dev->nblocks =
                        virt_dev->file_size >> virt_dev->block_shift;
        } else {
@@ -561,7 +561,7 @@ static int vdisk_attach(struct scst_device *dev)
                PRINT_INFO("Attached SCSI target virtual %s %s "
                      "(file=\"%s\", fs=%lldMB, bs=%d, nblocks=%lld,"
                      " cyln=%lld%s)",
-                     (dev->handler->type == TYPE_DISK) ? "disk" : "cdrom",
+                     (dev->type == TYPE_DISK) ? "disk" : "cdrom",
                      virt_dev->name, virt_dev->file_name,
                      virt_dev->file_size >> 20, virt_dev->block_size,
                      (long long unsigned int)virt_dev->nblocks,
@@ -1209,7 +1209,7 @@ static void vdisk_exec_inquiry(struct scst_cmd *cmd)
                goto out_put;
        }
 
-       buf[0] = cmd->dev->handler->type;      /* type dev */
+       buf[0] = cmd->dev->type;      /* type dev */
        if ((buf[0] == TYPE_ROM) || virt_dev->removable)
                buf[1] = 0x80;      /* removable */
        /* Vital Product */
@@ -1548,7 +1548,7 @@ static void vdisk_exec_mode_sense(struct scst_cmd *cmd)
        blocksize = virt_dev->block_size;
        nblocks = virt_dev->nblocks;
 
-       type = cmd->dev->handler->type;    /* type dev */
+       type = cmd->dev->type;    /* type dev */
        dbd = cmd->cdb[1] & DBD;
        pcontrol = (cmd->cdb[2] & 0xc0) >> 6;
        pcode = cmd->cdb[2] & 0x3f;
@@ -1904,6 +1904,7 @@ static void vdisk_exec_read_capacity16(struct scst_cmd *cmd)
        nblocks = virt_dev->nblocks - 1;
 
        memset(buffer, 0, sizeof(buffer));
+
        buffer[0] = nblocks >> 56;
        buffer[1] = (nblocks >> 48) & 0xFF;
        buffer[2] = (nblocks >> 40) & 0xFF;
@@ -1918,6 +1919,25 @@ static void vdisk_exec_read_capacity16(struct scst_cmd *cmd)
        buffer[10] = (blocksize >> (BYTE * 1)) & 0xFF;
        buffer[11] = (blocksize >> (BYTE * 0)) & 0xFF;
 
+       switch (blocksize) {
+       case 512:
+               buffer[13] = 3;
+               break;
+       case 1024:
+               buffer[13] = 2;
+               break;
+       case 2048:
+               buffer[13] = 1;
+               break;
+       default:
+               PRINT_ERROR("%s: Unexpected block size %d",
+                       cmd->op_name, blocksize);
+               /* go through */
+       case 4096:
+               buffer[13] = 0;
+               break;
+       }
+
        length = scst_get_buf_first(cmd, &address);
        if (unlikely(length <= 0)) {
                if (length < 0) {
@@ -1953,7 +1973,7 @@ static void vdisk_exec_read_toc(struct scst_cmd *cmd)
 
        TRACE_ENTRY();
 
-       if (cmd->dev->handler->type != TYPE_ROM) {
+       if (cmd->dev->type != TYPE_ROM) {
                PRINT_ERROR("%s", "READ TOC for non-CDROM device");
                scst_set_cmd_error(cmd,
                        SCST_LOAD_SENSE(scst_sense_invalid_opcode));
@@ -2040,7 +2060,7 @@ static void vdisk_exec_prevent_allow_medium_removal(struct scst_cmd *cmd)
 
        TRACE_DBG("PERSIST/PREVENT 0x%02x", cmd->cdb[4]);
 
-       if (cmd->dev->handler->type == TYPE_ROM) {
+       if (cmd->dev->type == TYPE_ROM) {
                spin_lock(&virt_dev->flags_lock);
                virt_dev->prevent_allow_medium_removal =
                        cmd->cdb[4] & 0x01 ? 1 : 0;
index dc9ca60..23f3e0d 100644 (file)
@@ -31,6 +31,7 @@ static int get_trans_len_4(struct scst_cmd *cmd, uint8_t off);
 /* for special commands */
 static int get_trans_len_block_limit(struct scst_cmd *cmd, uint8_t off);
 static int get_trans_len_read_capacity(struct scst_cmd *cmd, uint8_t off);
+static int get_trans_len_serv_act_in(struct scst_cmd *cmd, uint8_t off);
 static int get_trans_len_single(struct scst_cmd *cmd, uint8_t off);
 static int get_trans_len_none(struct scst_cmd *cmd, uint8_t off);
 static int get_trans_len_read_pos(struct scst_cmd *cmd, uint8_t off);
@@ -80,7 +81,7 @@ struct scst_sdbops {
        uint8_t direction;      /* init   --> target: SCST_DATA_WRITE
                                 * target --> init:   SCST_DATA_READ
                                 */
-       uint8_t flags;          /* opcode --  various flags */
+       uint16_t flags;         /* opcode --  various flags */
        uint8_t off;            /* length offset in cdb */
        int (*get_trans_len)(struct scst_cmd *cmd, uint8_t off)
                __attribute__ ((aligned));
@@ -111,7 +112,8 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
 
        /* 6-bytes length CDB */
        {0x00, "MMMMMMMMMMMMMMMM", "TEST UNIT READY",
-        SCST_DATA_NONE, SCST_SMALL_TIMEOUT, 0, get_trans_len_none},
+        /* let's be HQ to don't look dead under high load */
+        SCST_DATA_NONE, SCST_SMALL_TIMEOUT|SCST_IMPLICIT_HQ, 0, get_trans_len_none},
        {0x01, " M              ", "REWIND",
         SCST_DATA_NONE, SCST_LONG_TIMEOUT, 0, get_trans_len_none},
        {0x01, "O V OO OO       ", "REZERO UNIT",
@@ -119,12 +121,13 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
        {0x02, "VVVVVV  V       ", "REQUEST BLOCK ADDR",
         SCST_DATA_NONE, SCST_SMALL_TIMEOUT, 0, get_trans_len_none},
        {0x03, "MMMMMMMMMMMMMMMM", "REQUEST SENSE",
-        SCST_DATA_READ, SCST_SMALL_TIMEOUT, 4, get_trans_len_1},
+        SCST_DATA_READ, SCST_SMALL_TIMEOUT|SCST_SKIP_UA|SCST_LOCAL_EXEC_NEEDED,
+        4, get_trans_len_1},
        {0x04, "M    O O        ", "FORMAT UNIT",
-        SCST_DATA_WRITE, SCST_LONG_TIMEOUT|SCST_UNKNOWN_LENGTH,
+        SCST_DATA_WRITE, SCST_LONG_TIMEOUT|SCST_UNKNOWN_LENGTH|SCST_WRITE_MEDIUM,
         0, get_trans_len_none},
        {0x04, "  O             ", "FORMAT",
-        SCST_DATA_NONE, FLAG_NONE, 0, get_trans_len_none},
+        SCST_DATA_NONE, SCST_WRITE_MEDIUM, 0, get_trans_len_none},
        {0x05, "VMVVVV  V       ", "READ BLOCK LIMITS",
         SCST_DATA_READ, SCST_SMALL_TIMEOUT, 0, get_trans_len_block_limit},
        {0x06, "VVVVVV  V       ", "",
@@ -132,7 +135,7 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
        {0x07, "        O       ", "INITIALIZE ELEMENT STATUS",
         SCST_DATA_NONE, SCST_LONG_TIMEOUT, 0, get_trans_len_none},
        {0x07, "OVV O  OV       ", "REASSIGN BLOCKS",
-        SCST_DATA_NONE, FLAG_NONE, 0, get_trans_len_none},
+        SCST_DATA_NONE, SCST_WRITE_MEDIUM, 0, get_trans_len_none},
        {0x08, "O               ", "READ(6)",
         SCST_DATA_READ, SCST_TRANSFER_LEN_TYPE_FIXED, 4, get_trans_len_1_256},
        {0x08, " MV OO OV       ", "READ(6)",
@@ -144,9 +147,11 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
        {0x09, "VVVVVV  V       ", "",
         SCST_DATA_NONE, FLAG_NONE, 0, get_trans_len_none},
        {0x0A, "O               ", "WRITE(6)",
-        SCST_DATA_WRITE, SCST_TRANSFER_LEN_TYPE_FIXED, 4, get_trans_len_1_256},
+        SCST_DATA_WRITE, SCST_TRANSFER_LEN_TYPE_FIXED|SCST_WRITE_MEDIUM,
+        4, get_trans_len_1_256},
        {0x0A, " M  O  OV       ", "WRITE(6)",
-        SCST_DATA_WRITE, SCST_TRANSFER_LEN_TYPE_FIXED, 2, get_trans_len_3},
+        SCST_DATA_WRITE, SCST_TRANSFER_LEN_TYPE_FIXED|SCST_WRITE_MEDIUM,
+        2, get_trans_len_3},
        {0x0A, "  M             ", "PRINT",
         SCST_DATA_NONE, FLAG_NONE, 0, get_trans_len_none},
        {0x0A, "         M      ", "SEND MESSAGE(6)",
@@ -162,19 +167,21 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
        {0x0C, "VVVVVV  V       ", "SEEK BLOCK",
         SCST_DATA_NONE, SCST_LONG_TIMEOUT, 0, get_trans_len_none},
        {0x0D, "VVVVVV  V       ", "PARTITION",
-        SCST_DATA_NONE, SCST_LONG_TIMEOUT, 0, get_trans_len_none},
+        SCST_DATA_NONE, SCST_LONG_TIMEOUT|SCST_WRITE_MEDIUM,
+        0, get_trans_len_none},
        {0x0E, "VVVVVV  V       ", "",
         SCST_DATA_NONE, FLAG_NONE, 0, get_trans_len_none},
        {0x0F, "VOVVVV  V       ", "READ REVERSE",
         SCST_DATA_READ, SCST_TRANSFER_LEN_TYPE_FIXED, 2, get_trans_len_3},
        {0x10, "VM V V          ", "WRITE FILEMARKS",
-        SCST_DATA_NONE, FLAG_NONE, 0, get_trans_len_none},
+        SCST_DATA_NONE, SCST_WRITE_MEDIUM, 0, get_trans_len_none},
        {0x10, "  O O           ", "SYNCHRONIZE BUFFER",
         SCST_DATA_NONE, FLAG_NONE, 0, get_trans_len_none},
        {0x11, "VMVVVV          ", "SPACE",
         SCST_DATA_NONE, SCST_LONG_TIMEOUT, 0, get_trans_len_none},
        {0x12, "MMMMMMMMMMMMMMMM", "INQUIRY",
-        SCST_DATA_READ, SCST_SMALL_TIMEOUT, 4, get_trans_len_1},
+        SCST_DATA_READ, SCST_SMALL_TIMEOUT|SCST_IMPLICIT_HQ|SCST_SKIP_UA,
+        4, get_trans_len_1},
        {0x13, "VOVVVV          ", "VERIFY(6)",
         SCST_DATA_NONE, SCST_TRANSFER_LEN_TYPE_FIXED|
                         SCST_VERIFY_BYTCHK_MISMATCH_ALLOWED,
@@ -182,15 +189,18 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
        {0x14, "VOOVVV          ", "RECOVER BUFFERED DATA",
         SCST_DATA_READ, SCST_TRANSFER_LEN_TYPE_FIXED, 2, get_trans_len_3},
        {0x15, "OMOOOOOOOOOOOOOO", "MODE SELECT(6)",
-        SCST_DATA_WRITE, FLAG_NONE, 4, get_trans_len_1},
+        SCST_DATA_WRITE, SCST_LOCAL_EXEC_NEEDED, 4, get_trans_len_1},
        {0x16, "MMMMMMMMMMMMMMMM", "RESERVE",
-        SCST_DATA_NONE, SCST_SMALL_TIMEOUT, 0, get_trans_len_none},
+        SCST_DATA_NONE, SCST_SMALL_TIMEOUT|SCST_LOCAL_EXEC_NEEDED,
+        0, get_trans_len_none},
        {0x17, "MMMMMMMMMMMMMMMM", "RELEASE",
-        SCST_DATA_NONE, SCST_SMALL_TIMEOUT, 0, get_trans_len_none},
+        SCST_DATA_NONE, SCST_SMALL_TIMEOUT|SCST_LOCAL_EXEC_NEEDED,
+        0, get_trans_len_none},
        {0x18, "OOOOOOOO        ", "COPY",
         SCST_DATA_WRITE, SCST_LONG_TIMEOUT, 2, get_trans_len_3},
        {0x19, "VMVVVV          ", "ERASE",
-        SCST_DATA_NONE, SCST_LONG_TIMEOUT, 0, get_trans_len_none},
+        SCST_DATA_NONE, SCST_LONG_TIMEOUT|SCST_WRITE_MEDIUM,
+        0, get_trans_len_none},
        {0x1A, "OMOOOOOOOOOOOOOO", "MODE SENSE(6)",
         SCST_DATA_READ, SCST_SMALL_TIMEOUT, 4, get_trans_len_1},
        {0x1B, "      O         ", "SCAN",
@@ -222,7 +232,7 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
        {0x24, "V   VVM         ", "SET WINDOW",
         SCST_DATA_WRITE, FLAG_NONE, 6, get_trans_len_3},
        {0x25, "M   MM M        ", "READ CAPACITY",
-        SCST_DATA_READ, FLAG_NONE, 0, get_trans_len_read_capacity},
+        SCST_DATA_READ, SCST_IMPLICIT_HQ, 0, get_trans_len_read_capacity},
        {0x25, "      O         ", "GET WINDOW",
         SCST_DATA_READ, FLAG_NONE, 6, get_trans_len_3},
        {0x26, "V   VV          ", "",
@@ -236,7 +246,8 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
        {0x29, "V   VV O        ", "READ GENERATION",
         SCST_DATA_READ, FLAG_NONE, 8, get_trans_len_1},
        {0x2A, "O   MO M        ", "WRITE(10)",
-        SCST_DATA_WRITE, SCST_TRANSFER_LEN_TYPE_FIXED, 7, get_trans_len_2},
+        SCST_DATA_WRITE, SCST_TRANSFER_LEN_TYPE_FIXED|SCST_WRITE_MEDIUM,
+        7, get_trans_len_2},
        {0x2A, "         O      ", "SEND MESSAGE(10)",
         SCST_DATA_WRITE, FLAG_NONE, 7, get_trans_len_2},
        {0x2A, "      O         ", "SEND(10)",
@@ -248,11 +259,13 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
        {0x2B, "O   OO O        ", "SEEK(10)",
         SCST_DATA_NONE, FLAG_NONE, 0, get_trans_len_none},
        {0x2C, "V    O O        ", "ERASE(10)",
-        SCST_DATA_NONE, SCST_LONG_TIMEOUT, 0, get_trans_len_none},
+        SCST_DATA_NONE, SCST_LONG_TIMEOUT|SCST_WRITE_MEDIUM,
+        0, get_trans_len_none},
        {0x2D, "V   O  O        ", "READ UPDATED BLOCK",
         SCST_DATA_READ, SCST_TRANSFER_LEN_TYPE_FIXED, 0, get_trans_len_single},
        {0x2E, "O   OO O        ", "WRITE AND VERIFY(10)",
-        SCST_DATA_WRITE, SCST_TRANSFER_LEN_TYPE_FIXED, 7, get_trans_len_2},
+        SCST_DATA_WRITE, SCST_TRANSFER_LEN_TYPE_FIXED|SCST_WRITE_MEDIUM,
+        7, get_trans_len_2},
        {0x2F, "O   OO O        ", "VERIFY(10)",
         SCST_DATA_NONE, SCST_TRANSFER_LEN_TYPE_FIXED|
                         SCST_VERIFY_BYTCHK_MISMATCH_ALLOWED,
@@ -287,11 +300,11 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
        {0x3E, "O   OO O        ", "READ LONG",
         SCST_DATA_READ, FLAG_NONE, 7, get_trans_len_2},
        {0x3F, "O   O  O        ", "WRITE LONG",
-        SCST_DATA_WRITE, FLAG_NONE, 7, get_trans_len_2},
+        SCST_DATA_WRITE, SCST_WRITE_MEDIUM, 7, get_trans_len_2},
        {0x40, "OOOOOOOOOO      ", "CHANGE DEFINITION",
         SCST_DATA_WRITE, SCST_SMALL_TIMEOUT, 8, get_trans_len_1},
        {0x41, "O    O          ", "WRITE SAME",
-        SCST_DATA_WRITE, SCST_TRANSFER_LEN_TYPE_FIXED,
+        SCST_DATA_WRITE, SCST_TRANSFER_LEN_TYPE_FIXED|SCST_WRITE_MEDIUM,
         0, get_trans_len_single},
        {0x42, "     O          ", "READ SUB-CHANNEL",
         SCST_DATA_READ, FLAG_NONE, 7, get_trans_len_2},
@@ -324,11 +337,11 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
        {0x4F, "                ", "",
         SCST_DATA_NONE, FLAG_NONE, 0, get_trans_len_none},
        {0x50, "                ", "XDWRITE",
-        SCST_DATA_NONE, FLAG_NONE, 0, get_trans_len_none},
+        SCST_DATA_NONE, SCST_WRITE_MEDIUM, 0, get_trans_len_none},
        {0x51, "     O          ", "READ DISC INFORMATION",
         SCST_DATA_READ, FLAG_NONE, 7, get_trans_len_2},
        {0x51, "                ", "XPWRITE",
-        SCST_DATA_NONE, FLAG_NONE, 0, get_trans_len_none},
+        SCST_DATA_NONE, SCST_WRITE_MEDIUM, 0, get_trans_len_none},
        {0x52, "     O          ", "READ TRACK INFORMATION",
         SCST_DATA_READ, FLAG_NONE, 7, get_trans_len_2},
        {0x53, "     O          ", "RESERVE TRACK",
@@ -336,13 +349,15 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
        {0x54, "     O          ", "SEND OPC INFORMATION",
         SCST_DATA_WRITE, FLAG_NONE, 7, get_trans_len_2},
        {0x55, "OOOOOOOOOOOOOOOO", "MODE SELECT(10)",
-        SCST_DATA_WRITE, FLAG_NONE, 7, get_trans_len_2},
+        SCST_DATA_WRITE, SCST_LOCAL_EXEC_NEEDED, 7, get_trans_len_2},
        {0x56, "OOOOOOOOOOOOOOOO", "RESERVE(10)",
-        SCST_DATA_NONE, SCST_SMALL_TIMEOUT, 0, get_trans_len_none},
+        SCST_DATA_NONE, SCST_SMALL_TIMEOUT|SCST_LOCAL_EXEC_NEEDED,
+        0, get_trans_len_none},
        {0x57, "OOOOOOOOOOOOOOOO", "RELEASE(10)",
-        SCST_DATA_NONE, SCST_SMALL_TIMEOUT, 0, get_trans_len_none},
+        SCST_DATA_NONE, SCST_SMALL_TIMEOUT|SCST_LOCAL_EXEC_NEEDED,
+        0, get_trans_len_none},
        {0x58, "     O          ", "REPAIR TRACK",
-        SCST_DATA_NONE, FLAG_NONE, 0, get_trans_len_none},
+        SCST_DATA_NONE, SCST_WRITE_MEDIUM, 0, get_trans_len_none},
        {0x59, "                ", "",
         SCST_DATA_NONE, FLAG_NONE, 0, get_trans_len_none},
        {0x5A, "OOOOOOOOOOOOOOOO", "MODE SENSE(10)",
@@ -353,22 +368,22 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
         SCST_DATA_READ, FLAG_NONE, 7, get_trans_len_2},
        {0x5D, "     O          ", "SEND CUE SHEET",
         SCST_DATA_WRITE, FLAG_NONE, 6, get_trans_len_3},
-       {0x5E, "OOOOO OOOO      ", "PERSISTENT_RESERV_IN",
+       {0x5E, "OOOOO OOOO      ", "PERSISTENT RESERV IN",
         SCST_DATA_READ, FLAG_NONE, 5, get_trans_len_4},
-       {0x5F, "OOOOO OOOO      ", "PERSISTENT_RESERV_OUT",
+       {0x5F, "OOOOO OOOO      ", "PERSISTENT RESERV OUT",
         SCST_DATA_WRITE, FLAG_NONE, 5, get_trans_len_4},
 
        /* 16-bytes length CDB */
        {0x80, "O   OO O        ", "XDWRITE EXTENDED",
-        SCST_DATA_NONE, FLAG_NONE, 0, get_trans_len_none},
+        SCST_DATA_NONE, SCST_WRITE_MEDIUM, 0, get_trans_len_none},
        {0x80, " M              ", "WRITE FILEMARKS",
-        SCST_DATA_NONE, FLAG_NONE, 0, get_trans_len_none},
+        SCST_DATA_NONE, SCST_WRITE_MEDIUM, 0, get_trans_len_none},
        {0x81, "O   OO O        ", "REBUILD",
-        SCST_DATA_WRITE, FLAG_NONE, 10, get_trans_len_4},
+        SCST_DATA_WRITE, SCST_WRITE_MEDIUM, 10, get_trans_len_4},
        {0x82, "O   OO O        ", "REGENERATE",
-        SCST_DATA_WRITE, FLAG_NONE, 10, get_trans_len_4},
+        SCST_DATA_WRITE, SCST_WRITE_MEDIUM, 10, get_trans_len_4},
        {0x83, "OOOOOOOOOOOOOOOO", "EXTENDED COPY",
-        SCST_DATA_WRITE, FLAG_NONE, 10, get_trans_len_4},
+        SCST_DATA_WRITE, SCST_WRITE_MEDIUM, 10, get_trans_len_4},
        {0x84, "OOOOOOOOOOOOOOOO", "RECEIVE COPY RESULT",
         SCST_DATA_WRITE, FLAG_NONE, 10, get_trans_len_4},
        {0x86, "OOOOOOOOOO      ", "ACCESS CONTROL IN",
@@ -378,13 +393,15 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
        {0x88, "M   MMMM        ", "READ(16)",
         SCST_DATA_READ, SCST_TRANSFER_LEN_TYPE_FIXED, 10, get_trans_len_4},
        {0x8A, "O   OO O        ", "WRITE(16)",
-        SCST_DATA_WRITE, SCST_TRANSFER_LEN_TYPE_FIXED, 10, get_trans_len_4},
+        SCST_DATA_WRITE, SCST_TRANSFER_LEN_TYPE_FIXED|SCST_WRITE_MEDIUM,
+        10, get_trans_len_4},
        {0x8C, "OOOOOOOOOO      ", "READ ATTRIBUTE",
         SCST_DATA_READ, FLAG_NONE, 10, get_trans_len_4},
        {0x8D, "OOOOOOOOOO      ", "WRITE ATTRIBUTE",
-        SCST_DATA_WRITE, FLAG_NONE, 10, get_trans_len_4},
+        SCST_DATA_WRITE, SCST_WRITE_MEDIUM, 10, get_trans_len_4},
        {0x8E, "O   OO O        ", "WRITE AND VERIFY(16)",
-        SCST_DATA_WRITE, SCST_TRANSFER_LEN_TYPE_FIXED, 10, get_trans_len_4},
+        SCST_DATA_WRITE, SCST_TRANSFER_LEN_TYPE_FIXED|SCST_WRITE_MEDIUM,
+        10, get_trans_len_4},
        {0x8F, "O   OO O        ", "VERIFY(16)",
         SCST_DATA_NONE, SCST_TRANSFER_LEN_TYPE_FIXED|
                         SCST_VERIFY_BYTCHK_MISMATCH_ALLOWED,
@@ -400,15 +417,19 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
        {0x92, " O              ", "LOCATE(16)",
         SCST_DATA_NONE, SCST_LONG_TIMEOUT, 0, get_trans_len_none},
        {0x93, "O    O          ", "WRITE SAME(16)",
-        SCST_DATA_WRITE, SCST_TRANSFER_LEN_TYPE_FIXED, 10, get_trans_len_4},
+        SCST_DATA_WRITE, SCST_TRANSFER_LEN_TYPE_FIXED|SCST_WRITE_MEDIUM,
+        10, get_trans_len_4},
        {0x93, " M              ", "ERASE(16)",
-        SCST_DATA_NONE, SCST_LONG_TIMEOUT, 0, get_trans_len_none},
+        SCST_DATA_NONE, SCST_LONG_TIMEOUT|SCST_WRITE_MEDIUM,
+        0, get_trans_len_none},
        {0x9E, "O               ", "SERVICE ACTION IN",
-        SCST_DATA_READ, SCST_UNKNOWN_LENGTH, 0, get_trans_len_none},
+        SCST_DATA_READ, FLAG_NONE, 0, get_trans_len_serv_act_in},
 
        /* 12-bytes length CDB */
-       {0xA0, "VVVVVVVVVV  M   ", "REPORT LUN",
-        SCST_DATA_READ, SCST_SMALL_TIMEOUT, 6, get_trans_len_4},
+       {0xA0, "VVVVVVVVVV  M   ", "REPORT LUNS",
+        SCST_DATA_READ, SCST_SMALL_TIMEOUT|SCST_IMPLICIT_HQ|SCST_SKIP_UA|
+                        SCST_LOCAL_CMD|SCST_LOCAL_EXEC_NEEDED,
+        6, get_trans_len_4},
        {0xA1, "     O          ", "BLANK",
         SCST_DATA_NONE, SCST_LONG_TIMEOUT, 0, get_trans_len_none},
        {0xA2, "                ", "",
@@ -438,19 +459,21 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
        {0xA9, "     O          ", "PLAY TRACK RELATIVE(12)",
         SCST_DATA_NONE, FLAG_NONE, 0, get_trans_len_none},
        {0xAA, "O   OO O        ", "WRITE(12)",
-        SCST_DATA_WRITE, SCST_TRANSFER_LEN_TYPE_FIXED, 6, get_trans_len_4},
+        SCST_DATA_WRITE, SCST_TRANSFER_LEN_TYPE_FIXED|SCST_WRITE_MEDIUM,
+        6, get_trans_len_4},
        {0xAA, "         O      ", "SEND MESSAGE(12)",
         SCST_DATA_WRITE, FLAG_NONE, 6, get_trans_len_4},
        {0xAB, "                ", "",
         SCST_DATA_NONE, FLAG_NONE, 0, get_trans_len_none},
        {0xAC, "       O        ", "ERASE(12)",
-        SCST_DATA_NONE, FLAG_NONE, 0, get_trans_len_none},
+        SCST_DATA_NONE, SCST_WRITE_MEDIUM, 0, get_trans_len_none},
        {0xAC, "     M          ", "GET PERFORMANCE",
         SCST_DATA_READ, SCST_UNKNOWN_LENGTH, 0, get_trans_len_none},
        {0xAD, "     O          ", "READ DVD STRUCTURE",
         SCST_DATA_READ, FLAG_NONE, 8, get_trans_len_2},
        {0xAE, "O   OO O        ", "WRITE AND VERIFY(12)",
-        SCST_DATA_WRITE, SCST_TRANSFER_LEN_TYPE_FIXED, 6, get_trans_len_4},
+        SCST_DATA_WRITE, SCST_TRANSFER_LEN_TYPE_FIXED|SCST_WRITE_MEDIUM,
+        6, get_trans_len_4},
        {0xAF, "O   OO O        ", "VERIFY(12)",
         SCST_DATA_NONE, SCST_TRANSFER_LEN_TYPE_FIXED|
                         SCST_VERIFY_BYTCHK_MISMATCH_ALLOWED,
@@ -505,14 +528,6 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
         SCST_DATA_NONE, SCST_LONG_TIMEOUT, 0, get_trans_len_none}
 };
 
-/* Notes:
-       Unknown op's:
-       #define SCSIOP_XDWRITE_EXTENDED         0x80
-       #define SCSIOP_REBUILD                  0x81
-       #define SCSIOP_EA                       0xea
-       #define WRITE_LONG_2                    0xea
-*/
-
 #define SCST_CDB_TBL_SIZE \
        ((int)(sizeof(scst_scsi_op_table)/sizeof(struct scst_sdbops)))
 
index b212a5e..bcc78cd 100644 (file)
@@ -2487,6 +2487,23 @@ static int get_trans_len_read_capacity(struct scst_cmd *cmd, uint8_t off)
        return 0;
 }
 
+static int get_trans_len_serv_act_in(struct scst_cmd *cmd, uint8_t off)
+{
+       int res = 0;
+
+       TRACE_ENTRY();
+
+       if ((cmd->cdb[1] & 0x1f) == SAI_READ_CAPACITY_16) {
+               cmd->op_name = "READ CAPACITY(16)";
+               cmd->bufflen = READ_CAP16_LEN;
+               cmd->op_flags |= SCST_IMPLICIT_HQ;
+       } else
+               cmd->op_flags |= SCST_UNKNOWN_LENGTH;
+
+       TRACE_EXIT_RES(res);
+       return res;
+}
+
 static int get_trans_len_single(struct scst_cmd *cmd, uint8_t off)
 {
        cmd->bufflen = 1;
@@ -2600,7 +2617,7 @@ static int get_trans_len_none(struct scst_cmd *cmd, uint8_t off)
 
 int scst_get_cdb_info(struct scst_cmd *cmd)
 {
-       int dev_type = cmd->dev->handler->type;
+       int dev_type = cmd->dev->type;
        int i, res = 0;
        uint8_t op;
        const struct scst_sdbops *ptr = NULL;
@@ -2638,12 +2655,12 @@ int scst_get_cdb_info(struct scst_cmd *cmd)
                i++;
        }
 
-       if (ptr == NULL) {
+       if (unlikely(ptr == NULL)) {
                /* opcode not found or now not used !!! */
                TRACE(TRACE_SCSI, "Unknown opcode 0x%x for type %d", op,
                      dev_type);
                res = -1;
-               cmd->op_flags = SCST_INFO_INVALID;
+               cmd->op_flags = SCST_INFO_NOT_FOUND;
                goto out;
        }
 
@@ -2654,7 +2671,7 @@ int scst_get_cdb_info(struct scst_cmd *cmd)
        res = (*ptr->get_trans_len)(cmd, ptr->off);
 
 out:
-       TRACE_EXIT();
+       TRACE_EXIT_RES(res);
        return res;
 }
 EXPORT_SYMBOL(scst_get_cdb_info);
@@ -2811,12 +2828,6 @@ int scst_sbc_generic_parse(struct scst_cmd *cmd,
              cmd->op_name, cmd->data_direction, cmd->op_flags, cmd->bufflen);
 
        switch (cmd->cdb[0]) {
-       case SERVICE_ACTION_IN:
-               if ((cmd->cdb[1] & 0x1f) == SAI_READ_CAPACITY_16) {
-                       cmd->bufflen = READ_CAP16_LEN;
-                       cmd->data_direction = SCST_DATA_READ;
-               }
-               break;
        case VERIFY_6:
        case VERIFY:
        case VERIFY_12:
index f87e124..224e20e 100644 (file)
@@ -413,23 +413,14 @@ void scst_process_reset(struct scst_device *dev,
        struct scst_session *originator, struct scst_cmd *exclude_cmd,
        struct scst_mgmt_cmd *mcmd, bool setUA);
 
-static inline int scst_is_ua_command(struct scst_cmd *cmd)
+static inline bool scst_is_ua_command(struct scst_cmd *cmd)
 {
-       return (cmd->cdb[0] != INQUIRY) &&
-              (cmd->cdb[0] != REQUEST_SENSE) &&
-              (cmd->cdb[0] != REPORT_LUNS);
+       return (cmd->op_flags & SCST_SKIP_UA) == 0;
 }
 
-static inline int scst_is_implicit_hq(struct scst_cmd *cmd)
+static inline bool scst_is_implicit_hq(struct scst_cmd *cmd)
 {
-       return (cmd->cdb[0] == INQUIRY) ||
-              (cmd->cdb[0] == REPORT_LUNS) ||
-              ((cmd->dev->type == TYPE_DISK) &&
-                       ((cmd->cdb[0] == READ_CAPACITY) ||
-                        ((cmd->cdb[0] == SERVICE_ACTION_IN) &&
-                         ((cmd->cdb[1] & 0x1f) == SAI_READ_CAPACITY_16)))) ||
-              /* Let's don't look dead under high load */
-              (cmd->cdb[0] == TEST_UNIT_READY);
+       return (cmd->op_flags & SCST_IMPLICIT_HQ) != 0;
 }
 
 /*
index 5c3dce3..9b1db4c 100644 (file)
@@ -1460,7 +1460,7 @@ static int scst_proc_assign_handler(char *buf)
 
        if (dev->scsi_dev->type != handler->type) {
                PRINT_ERROR("Type %d of device %s differs from type "
-                       "%d of dev handler %s", dev->handler->type,
+                       "%d of dev handler %s", dev->type,
                        dev->handler->name, handler->type, handler->name);
                res = -EINVAL;
                goto out;
index 6bd888c..e65c9cd 100644 (file)
@@ -1440,7 +1440,7 @@ static int scst_report_luns_local(struct scst_cmd *cmd)
        if (unlikely(buffer_size == 0))
                goto out_compl;
        else if (unlikely(buffer_size < 0))
-               goto out_err;
+               goto out_hw_err;
 
        if (buffer_size < 16)
                goto out_put_err;
@@ -1491,7 +1491,7 @@ inc_dev_cnt:
        if (unlikely(buffer_size == 0))
                goto out_compl;
        else if (unlikely(buffer_size < 0))
-               goto out_err;
+               goto out_hw_err;
 
        dev_cnt *= 8;
        buffer[0] = (dev_cnt >> 24) & 0xff;
@@ -1557,10 +1557,108 @@ out_err:
 
 out_put_hw_err:
        scst_put_buf(cmd, buffer);
+       
+out_hw_err:
        scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error));
        goto out_compl;
 }
 
+static int scst_request_sense_local(struct scst_cmd *cmd)
+{
+       int res = SCST_EXEC_COMPLETED, rc;
+       struct scst_tgt_dev *tgt_dev = cmd->tgt_dev;
+       uint8_t *buffer;
+       int buffer_size = 0;
+
+       TRACE_ENTRY();
+
+       rc = scst_check_local_events(cmd);
+       if (unlikely(rc != 0))
+               goto out_done;
+
+       cmd->status = 0;
+       cmd->msg_status = 0;
+       cmd->host_status = DID_OK;
+       cmd->driver_status = 0;
+
+       spin_lock_bh(&tgt_dev->tgt_dev_lock);
+
+       if (tgt_dev->tgt_dev_valid_sense_len == 0)
+               goto out_not_completed;
+
+       TRACE(TRACE_SCSI, "%s: Returning stored sense", cmd->op_name);
+
+       buffer_size = scst_get_buf_first(cmd, &buffer);
+       if (unlikely(buffer_size == 0))
+               goto out_compl;
+       else if (unlikely(buffer_size < 0))
+               goto out_hw_err;
+
+       memset(buffer, 0, buffer_size);
+
+       if (((tgt_dev->tgt_dev_sense[0] == 0x70) ||
+            (tgt_dev->tgt_dev_sense[0] == 0x71)) && (cmd->cdb[1] & 1)) {
+               PRINT_WARNING("%s: Fixed format of the saved sense, but "
+                       "descriptor format requested. Convertion will "
+                       "truncated data", cmd->op_name);
+               PRINT_BUFFER("Original sense", tgt_dev->tgt_dev_sense,
+                       tgt_dev->tgt_dev_valid_sense_len);
+
+               buffer_size = min(SCST_STANDARD_SENSE_LEN, buffer_size);
+               scst_set_sense(buffer, buffer_size, true,
+                       tgt_dev->tgt_dev_sense[2], tgt_dev->tgt_dev_sense[12],
+                       tgt_dev->tgt_dev_sense[13]);
+       } else if (((tgt_dev->tgt_dev_sense[0] == 0x72) ||
+                   (tgt_dev->tgt_dev_sense[0] == 0x73)) && !(cmd->cdb[1] & 1)) {
+               PRINT_WARNING("%s: Descriptor format of the "
+                       "saved sense, but fixed format requested. Convertion "
+                       "will truncated data", cmd->op_name);
+               PRINT_BUFFER("Original sense", tgt_dev->tgt_dev_sense,
+                       tgt_dev->tgt_dev_valid_sense_len);
+
+               buffer_size = min(SCST_STANDARD_SENSE_LEN, buffer_size);
+               scst_set_sense(buffer, buffer_size, false,
+                       tgt_dev->tgt_dev_sense[1], tgt_dev->tgt_dev_sense[2],
+                       tgt_dev->tgt_dev_sense[3]);
+       } else {
+               if (buffer_size >= tgt_dev->tgt_dev_valid_sense_len)
+                       buffer_size = tgt_dev->tgt_dev_valid_sense_len;
+               else {
+                       PRINT_WARNING("%s: Being returned sense truncated to "
+                               "size %d (needed %d)", cmd->op_name,
+                               buffer_size, tgt_dev->tgt_dev_valid_sense_len);
+               }
+               memcpy(buffer, tgt_dev->tgt_dev_sense, buffer_size);
+       }
+
+       scst_put_buf(cmd, buffer);
+
+out_compl:
+       tgt_dev->tgt_dev_valid_sense_len = 0;
+       scst_set_resp_data_len(cmd, buffer_size);
+
+       spin_unlock_bh(&tgt_dev->tgt_dev_lock);
+
+       cmd->completed = 1;
+
+out_done:
+       /* Report the result */
+       cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT, SCST_CONTEXT_SAME);
+
+out:
+       TRACE_EXIT_RES(res);
+       return res;
+
+out_hw_err:
+       scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error));
+       goto out_compl;
+
+out_not_completed:
+       spin_unlock_bh(&tgt_dev->tgt_dev_lock);
+       res = SCST_EXEC_NOT_COMPLETED;
+       goto out;
+}
+
 static int scst_pre_select(struct scst_cmd *cmd)
 {
        int res = SCST_EXEC_NOT_COMPLETED;
@@ -2044,16 +2142,8 @@ static int scst_do_local_exec(struct scst_cmd *cmd)
        TRACE_ENTRY();
 
        /* Check READ_ONLY device status */
-       if (((tgt_dev->acg_dev->rd_only_flag) || cmd->dev->swp) &&
-           (cmd->cdb[0] == WRITE_6 ||  /* ToDo: full list of the modify cmds */
-            cmd->cdb[0] == WRITE_10 ||
-            cmd->cdb[0] == WRITE_12 ||
-            cmd->cdb[0] == WRITE_16 ||
-            cmd->cdb[0] == WRITE_VERIFY ||
-            cmd->cdb[0] == WRITE_VERIFY_12 ||
-            cmd->cdb[0] == WRITE_VERIFY_16 ||
-            (cmd->dev->handler->type == TYPE_TAPE &&
-             (cmd->cdb[0] == ERASE || cmd->cdb[0] == WRITE_FILEMARKS)))) {
+       if ((cmd->op_flags & SCST_WRITE_MEDIUM) &&
+           ((tgt_dev->acg_dev->rd_only_flag) || cmd->dev->swp)) {
                PRINT_WARNING("Attempt of write access to read-only device: "
                        "initiator %s, LUN %lld, op %x",
                        cmd->sess->initiator_name, cmd->lun, cmd->cdb[0]);
@@ -2067,6 +2157,11 @@ static int scst_do_local_exec(struct scst_cmd *cmd)
         * scst_is_cmd_local() in scst.h, if necessary
         */
 
+       if (!(cmd->op_flags & SCST_LOCAL_EXEC_NEEDED)) {
+               res = SCST_EXEC_NOT_COMPLETED;
+               goto out;
+       }
+
        switch (cmd->cdb[0]) {
        case MODE_SELECT:
        case MODE_SELECT_10:
@@ -2084,6 +2179,9 @@ static int scst_do_local_exec(struct scst_cmd *cmd)
        case REPORT_LUNS:
                res = scst_report_luns_local(cmd);
                break;
+       case REQUEST_SENSE:
+               res = scst_request_sense_local(cmd);
+               break;
        default:
                res = SCST_EXEC_NOT_COMPLETED;
                break;
@@ -2453,7 +2551,7 @@ static int scst_pre_dev_done(struct scst_cmd *cmd)
                goto out;
 
        if (likely(scsi_status_is_good(cmd->status))) {
-               unsigned char type = cmd->dev->handler->type;
+               unsigned char type = cmd->dev->type;
                if (unlikely((cmd->cdb[0] == MODE_SENSE ||
                              cmd->cdb[0] == MODE_SENSE_10)) &&
                    cmd->tgt_dev->acg_dev->rd_only_flag &&
@@ -2824,6 +2922,28 @@ static int scst_pre_xmit_response(struct scst_cmd *cmd)
 
        if (unlikely(test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags)))
                scst_xmit_process_aborted_cmd(cmd);
+       else if (unlikely(cmd->status == SAM_STAT_CHECK_CONDITION) &&
+                SCST_SENSE_VALID(cmd->sense) &&
+                !test_bit(SCST_CMD_NO_RESP, &cmd->cmd_flags)) {
+               struct scst_tgt_dev *tgt_dev = cmd->tgt_dev;
+
+               TRACE_DBG("Storing sense (cmd %p)", cmd);
+
+               spin_lock_bh(&tgt_dev->tgt_dev_lock);
+
+               if (cmd->sense_bufflen <= sizeof(tgt_dev->tgt_dev_sense))
+                       tgt_dev->tgt_dev_valid_sense_len = cmd->sense_bufflen;
+               else {
+                       tgt_dev->tgt_dev_valid_sense_len = sizeof(tgt_dev->tgt_dev_sense);
+                       PRINT_ERROR("Stored sense truncated to size %d "
+                               "(needed %d)", tgt_dev->tgt_dev_valid_sense_len,
+                               cmd->sense_bufflen);
+               }
+               memcpy(tgt_dev->tgt_dev_sense, cmd->sense, 
+                       tgt_dev->tgt_dev_valid_sense_len);
+
+               spin_unlock_bh(&tgt_dev->tgt_dev_lock);
+       }
 
        if (unlikely(test_bit(SCST_CMD_NO_RESP, &cmd->cmd_flags))) {
                TRACE_MGMT_DBG("Flag NO_RESP set for cmd %p (tag %llu),"
index b94da94..b1f5505 100644 (file)
@@ -1469,6 +1469,7 @@ static void exec_read_capacity16(struct vdisk_cmd *vcmd)
        nblocks = dev->nblocks - 1;
 
        memset(buffer, 0, sizeof(buffer));
+
        buffer[0] = nblocks >> 56;
        buffer[1] = (nblocks >> 48) & 0xFF;
        buffer[2] = (nblocks >> 40) & 0xFF;
@@ -1483,6 +1484,25 @@ static void exec_read_capacity16(struct vdisk_cmd *vcmd)
        buffer[10] = (blocksize >> (BYTE * 1)) & 0xFF;
        buffer[11] = (blocksize >> (BYTE * 0)) & 0xFF;
 
+       switch (blocksize) {
+       case 512:
+               buffer[13] = 3;
+               break;
+       case 1024:
+               buffer[13] = 2;
+               break;
+       case 2048:
+               buffer[13] = 1;
+               break;
+       default:
+               PRINT_ERROR("READ CAPACITY(16): Unexpected block size %d6",
+                       blocksize);
+               /* go through */
+       case 4096:
+               buffer[13] = 0;
+               break;
+       }
+
        if (length > READ_CAP16_LEN)
                length = READ_CAP16_LEN;
        memcpy(address, buffer, length);