target/sbc: Seperate WRITE_SAME based on UNMAP flag in sbc_ops
authorNicholas Bellinger <nab@linux-iscsi.org>
Thu, 8 Nov 2012 04:01:10 +0000 (20:01 -0800)
committerNicholas Bellinger <nab@linux-iscsi.org>
Thu, 15 Nov 2012 20:04:52 +0000 (12:04 -0800)
This patch adds a new sbc_ops->execute_write_same_unmap() caller for use
with WRITE_SAME w/ UNMAP=1, and performs the ->execute_cmd() setup based
this bit within sbc_setup_write_same() code.

Also, makes the changes in sbc_parse_cdb() to handle a sense_reason_t
return from sbc_setup_write_same() on error.

Reported-by: Christoph Hellwig <hch@lst.de>
Cc: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
drivers/target/target_core_sbc.c
include/target/target_core_backend.h

index b8024219cd4fa9fec6b0ede1583f99f74fcc03fe..a5a8f463004b158bdf744e95b485c4f8c42723bf 100644 (file)
@@ -235,26 +235,30 @@ static inline unsigned long long transport_lba_64_ext(unsigned char *cdb)
        return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32;
 }
 
-static int sbc_write_same_supported(struct se_device *dev,
-               unsigned char *flags)
+static sense_reason_t
+sbc_setup_write_same(struct se_cmd *cmd, unsigned char *flags, struct sbc_ops *ops)
 {
        if ((flags[0] & 0x04) || (flags[0] & 0x02)) {
                pr_err("WRITE_SAME PBDATA and LBDATA"
                        " bits not supported for Block Discard"
                        " Emulation\n");
-               return -ENOSYS;
+               return TCM_UNSUPPORTED_SCSI_OPCODE;
        }
-
        /*
-        * Currently for the emulated case we only accept
-        * tpws with the UNMAP=1 bit set.
+        * Special case for WRITE_SAME w/ UNMAP=1 that ends up getting
+        * translated into block discard requests within backend code.
         */
-       if (!(flags[0] & 0x08)) {
-               pr_err("WRITE_SAME w/o UNMAP bit not"
-                       " supported for Block Discard Emulation\n");
-               return -ENOSYS;
+       if (flags[0] & 0x08) {
+               if (!ops->execute_write_same_unmap)
+                       return TCM_UNSUPPORTED_SCSI_OPCODE;
+
+               cmd->execute_cmd = ops->execute_write_same_unmap;
+               return 0;
        }
+       if (!ops->execute_write_same)
+               return TCM_UNSUPPORTED_SCSI_OPCODE;
 
+       cmd->execute_cmd = ops->execute_write_same;
        return 0;
 }
 
@@ -418,9 +422,6 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
                                cmd->se_cmd_flags |= SCF_FUA;
                        break;
                case WRITE_SAME_32:
-                       if (!ops->execute_write_same)
-                               return TCM_UNSUPPORTED_SCSI_OPCODE;
-
                        sectors = transport_get_sectors_32(cdb);
                        if (!sectors) {
                                pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not"
@@ -431,9 +432,9 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
                        size = sbc_get_size(cmd, 1);
                        cmd->t_task_lba = get_unaligned_be64(&cdb[12]);
 
-                       if (sbc_write_same_supported(dev, &cdb[10]) < 0)
-                               return TCM_UNSUPPORTED_SCSI_OPCODE;
-                       cmd->execute_cmd = ops->execute_write_same;
+                       ret = sbc_setup_write_same(cmd, &cdb[10], ops);
+                       if (ret < 0)
+                               return ret;
                        break;
                default:
                        pr_err("VARIABLE_LENGTH_CMD service action"
@@ -495,9 +496,6 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
                cmd->execute_cmd = ops->execute_unmap;
                break;
        case WRITE_SAME_16:
-               if (!ops->execute_write_same)
-                       return TCM_UNSUPPORTED_SCSI_OPCODE;
-
                sectors = transport_get_sectors_16(cdb);
                if (!sectors) {
                        pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n");
@@ -507,14 +505,11 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
                size = sbc_get_size(cmd, 1);
                cmd->t_task_lba = get_unaligned_be64(&cdb[2]);
 
-               if (sbc_write_same_supported(dev, &cdb[1]) < 0)
-                       return TCM_UNSUPPORTED_SCSI_OPCODE;
-               cmd->execute_cmd = ops->execute_write_same;
+               ret = sbc_setup_write_same(cmd, &cdb[1], ops);
+               if (ret < 0)
+                       return ret;
                break;
        case WRITE_SAME:
-               if (!ops->execute_write_same)
-                       return TCM_UNSUPPORTED_SCSI_OPCODE;
-
                sectors = transport_get_sectors_10(cdb);
                if (!sectors) {
                        pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n");
@@ -528,9 +523,9 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
                 * Follow sbcr26 with WRITE_SAME (10) and check for the existence
                 * of byte 1 bit 3 UNMAP instead of original reserved field
                 */
-               if (sbc_write_same_supported(dev, &cdb[1]) < 0)
-                       return TCM_UNSUPPORTED_SCSI_OPCODE;
-               cmd->execute_cmd = ops->execute_write_same;
+               ret = sbc_setup_write_same(cmd, &cdb[1], ops);
+               if (ret < 0)
+                       return ret;
                break;
        case VERIFY:
                size = 0;
index aa868090b9ab8e9aaadc943e3054291117e6a1cf..3393ab10766c628d41abb6c5a5e9e6ec9c7e4cf6 100644 (file)
@@ -41,6 +41,7 @@ struct sbc_ops {
        sense_reason_t (*execute_rw)(struct se_cmd *cmd);
        sense_reason_t (*execute_sync_cache)(struct se_cmd *cmd);
        sense_reason_t (*execute_write_same)(struct se_cmd *cmd);
+       sense_reason_t (*execute_write_same_unmap)(struct se_cmd *cmd);
        sense_reason_t (*execute_unmap)(struct se_cmd *cmd);
 };