]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
scsi: target: Add WRITE_ATOMIC_16 handler
authorMike Christie <michael.christie@oracle.com>
Mon, 20 Oct 2025 10:38:17 +0000 (10:38 +0000)
committerMartin K. Petersen <martin.petersen@oracle.com>
Mon, 3 Nov 2025 02:40:02 +0000 (21:40 -0500)
Add the core LIO code to process the WRITE_ATOMIC_16 command.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
jpg: fix return code from sbc_check_atomic, reformat
Signed-off-by: John Garry <john.g.garry@oracle.com>
Link: https://patch.msgid.link/20251020103820.2917593-5-john.g.garry@oracle.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/target/target_core_sbc.c
include/target/target_core_base.h

index fe8beb7dbab12ab6eba74b107b429ae97b7413a1..abe91dc8722e4c54be75a3a9f2e55e1395aac303 100644 (file)
@@ -764,6 +764,49 @@ sbc_check_dpofua(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb)
        return 0;
 }
 
+static sense_reason_t
+sbc_check_atomic(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb)
+{
+       struct se_dev_attrib *attrib = &dev->dev_attrib;
+       u16 boundary, transfer_len;
+       u64 lba;
+
+       lba = transport_lba_64(cdb);
+       boundary = get_unaligned_be16(&cdb[10]);
+       transfer_len = get_unaligned_be16(&cdb[12]);
+
+       if (!attrib->atomic_max_len)
+               return TCM_UNSUPPORTED_SCSI_OPCODE;
+
+       if (boundary) {
+               if (transfer_len > attrib->atomic_max_with_boundary)
+                       return TCM_INVALID_CDB_FIELD;
+
+               if (boundary > attrib->atomic_max_boundary)
+                       return TCM_INVALID_CDB_FIELD;
+       } else {
+               if (transfer_len > attrib->atomic_max_len)
+                       return TCM_INVALID_CDB_FIELD;
+       }
+
+       if (attrib->atomic_granularity) {
+               if (transfer_len % attrib->atomic_granularity)
+                       return TCM_INVALID_CDB_FIELD;
+
+               if (boundary && boundary % attrib->atomic_granularity)
+                       return TCM_INVALID_CDB_FIELD;
+       }
+
+       if (dev->dev_attrib.atomic_alignment) {
+               u64 _lba = lba;
+
+               if (do_div(_lba, dev->dev_attrib.atomic_alignment))
+                       return TCM_INVALID_CDB_FIELD;
+       }
+
+       return 0;
+}
+
 sense_reason_t
 sbc_parse_cdb(struct se_cmd *cmd, struct exec_cmd_ops *ops)
 {
@@ -861,6 +904,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct exec_cmd_ops *ops)
                break;
        case WRITE_16:
        case WRITE_VERIFY_16:
+       case WRITE_ATOMIC_16:
                sectors = transport_get_sectors_16(cdb);
                cmd->t_task_lba = transport_lba_64(cdb);
 
@@ -872,6 +916,13 @@ sbc_parse_cdb(struct se_cmd *cmd, struct exec_cmd_ops *ops)
                        return ret;
 
                cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
+               if (cdb[0] == WRITE_ATOMIC_16) {
+                       cmd->se_cmd_flags |= SCF_ATOMIC;
+
+                       ret = sbc_check_atomic(dev, cmd, cdb);
+                       if (ret)
+                               return ret;
+               }
                cmd->execute_cmd = sbc_execute_rw;
                break;
        case VARIABLE_LENGTH_CMD:
index 70ece58d30780de5898c2205d681cda03de087e4..56333b5726c8b8423f4c1c5818f8d218473c15c5 100644 (file)
@@ -158,6 +158,7 @@ enum se_cmd_flags_table {
        SCF_TASK_ATTR_SET                       = (1 << 17),
        SCF_TREAT_READ_AS_NORMAL                = (1 << 18),
        SCF_TASK_ORDERED_SYNC                   = (1 << 19),
+       SCF_ATOMIC                              = (1 << 20),
 };
 
 /*