target: Add (obsolete) checking for PMI/LBA fields in READ CAPACITY(10)
authorRoland Dreier <roland@purestorage.com>
Thu, 27 Jun 2013 00:36:19 +0000 (17:36 -0700)
committerNicholas Bellinger <nab@linux-iscsi.org>
Mon, 8 Jul 2013 01:36:45 +0000 (18:36 -0700)
The SBC-2 specification of READ CAPACITY(10) has PMI and LOGICAL BLOCK
ADDRESS fields in the CDB; in SBC-3 these fields are simply listed as
obsolete.  However, SBC-2 also has the language

    If the PMI bit is set to zero and the LOGICAL BLOCK ADDRESS field
    is not set to zero, the device server shall terminate the command
    with CHECK CONDITION status with the sense key set to ILLEGAL
    REQUEST and the additional sense code set to INVALID FIELD IN CDB.

and in fact at least the Windows SCSI compliance test checks this
behavior.  Since no one following SBC-3 is going to set these fields,
we might as well include the check from SBC-2 and pass this test.

Signed-off-by: Roland Dreier <roland@purestorage.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
drivers/target/target_core_sbc.c

index ee0cb9d969296971f1344cfa4c29c15fd4c8de80..8a462773d0c84cec3ae46f1006d75e12dec75279 100644 (file)
@@ -38,11 +38,27 @@ static sense_reason_t
 sbc_emulate_readcapacity(struct se_cmd *cmd)
 {
        struct se_device *dev = cmd->se_dev;
+       unsigned char *cdb = cmd->t_task_cdb;
        unsigned long long blocks_long = dev->transport->get_blocks(dev);
        unsigned char *rbuf;
        unsigned char buf[8];
        u32 blocks;
 
+       /*
+        * SBC-2 says:
+        *   If the PMI bit is set to zero and the LOGICAL BLOCK
+        *   ADDRESS field is not set to zero, the device server shall
+        *   terminate the command with CHECK CONDITION status with
+        *   the sense key set to ILLEGAL REQUEST and the additional
+        *   sense code set to INVALID FIELD IN CDB.
+        *
+        * In SBC-3, these fields are obsolete, but some SCSI
+        * compliance tests actually check this, so we might as well
+        * follow SBC-2.
+        */
+       if (!(cdb[8] & 1) && !!(cdb[2] | cdb[3] | cdb[4] | cdb[5]))
+               return TCM_INVALID_CDB_FIELD;
+
        if (blocks_long >= 0x00000000ffffffff)
                blocks = 0xffffffff;
        else