From 3434be392051a2fdb295df3cfe07bf75235250a0 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 20 Oct 2025 10:38:14 +0000 Subject: scsi: target: Rename target_configure_unmap_from_queue() Rename target_configure_unmap_from_queue() to target_configure_unmap_from_bdev() since it now takes a bdev. Signed-off-by: Mike Christie Signed-off-by: John Garry Reviewed-by: John Garry Link: https://patch.msgid.link/20251020103820.2917593-2-john.g.garry@oracle.com Signed-off-by: Martin K. Petersen --- include/target/target_core_backend.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index 4063a701081b..d394306f8f49 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -121,8 +121,8 @@ sense_reason_t passthrough_parse_cdb(struct se_cmd *cmd, bool target_sense_desc_format(struct se_device *dev); sector_t target_to_linux_sector(struct se_device *dev, sector_t lb); -bool target_configure_unmap_from_queue(struct se_dev_attrib *attrib, - struct block_device *bdev); +bool target_configure_unmap_from_bdev(struct se_dev_attrib *attrib, + struct block_device *bdev); static inline bool target_dev_configured(struct se_device *se_dev) { -- cgit v1.2.3 From d505447b8d78f4d81a67d492ac72b8d3a1805e72 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 20 Oct 2025 10:38:15 +0000 Subject: scsi: target: Add atomic se_device fields Add atomic fields to the se_device and export them in configfs. Initially only target_core_iblock will be supported and we will inherit all the settings from the block layer. Signed-off-by: Mike Christie jpg: Stop being allowed to configure atomic write alignment, Signed-off-by: John Garry Link: https://patch.msgid.link/20251020103820.2917593-3-john.g.garry@oracle.com Signed-off-by: Martin K. Petersen --- drivers/target/target_core_configfs.c | 15 +++++++++++++++ include/target/target_core_base.h | 5 +++++ 2 files changed, 20 insertions(+) (limited to 'include') diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index b19acd662726..5470c1258445 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -578,6 +578,11 @@ DEF_CONFIGFS_ATTRIB_SHOW(unmap_zeroes_data); DEF_CONFIGFS_ATTRIB_SHOW(max_write_same_len); DEF_CONFIGFS_ATTRIB_SHOW(emulate_rsoc); DEF_CONFIGFS_ATTRIB_SHOW(submit_type); +DEF_CONFIGFS_ATTRIB_SHOW(atomic_max_len); +DEF_CONFIGFS_ATTRIB_SHOW(atomic_alignment); +DEF_CONFIGFS_ATTRIB_SHOW(atomic_granularity); +DEF_CONFIGFS_ATTRIB_SHOW(atomic_max_with_boundary); +DEF_CONFIGFS_ATTRIB_SHOW(atomic_max_boundary); #define DEF_CONFIGFS_ATTRIB_STORE_U32(_name) \ static ssize_t _name##_store(struct config_item *item, const char *page,\ @@ -1300,6 +1305,11 @@ CONFIGFS_ATTR(, max_write_same_len); CONFIGFS_ATTR(, alua_support); CONFIGFS_ATTR(, pgr_support); CONFIGFS_ATTR(, submit_type); +CONFIGFS_ATTR_RO(, atomic_max_len); +CONFIGFS_ATTR_RO(, atomic_alignment); +CONFIGFS_ATTR_RO(, atomic_granularity); +CONFIGFS_ATTR_RO(, atomic_max_with_boundary); +CONFIGFS_ATTR_RO(, atomic_max_boundary); /* * dev_attrib attributes for devices using the target core SBC/SPC @@ -1343,6 +1353,11 @@ struct configfs_attribute *sbc_attrib_attrs[] = { &attr_pgr_support, &attr_emulate_rsoc, &attr_submit_type, + &attr_atomic_alignment, + &attr_atomic_max_len, + &attr_atomic_granularity, + &attr_atomic_max_with_boundary, + &attr_atomic_max_boundary, NULL, }; EXPORT_SYMBOL(sbc_attrib_attrs); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index c4d9116904aa..70ece58d3078 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -731,6 +731,11 @@ struct se_dev_attrib { u32 unmap_granularity; u32 unmap_granularity_alignment; u32 max_write_same_len; + u32 atomic_max_len; + u32 atomic_alignment; + u32 atomic_granularity; + u32 atomic_max_with_boundary; + u32 atomic_max_boundary; u8 submit_type; struct se_device *da_dev; struct config_group da_group; -- cgit v1.2.3 From c486634fe2b10301bd8f0319c70a919433bfdf17 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 20 Oct 2025 10:38:16 +0000 Subject: scsi: target: Add helper to set up atomic values from block_device Add a helper function that sets up the atomic value based on a block_device similar to what we do for unmap. Signed-off-by: Mike Christie jpg: Set atomic alignment, drop atomic_supported reference Signed-off-by: John Garry Link: https://patch.msgid.link/20251020103820.2917593-4-john.g.garry@oracle.com Signed-off-by: Martin K. Petersen --- drivers/target/target_core_device.c | 17 +++++++++++++++++ include/target/target_core_backend.h | 2 ++ 2 files changed, 19 insertions(+) (limited to 'include') diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 83fe3d9a9681..39a2d9c3eb9e 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -840,6 +840,23 @@ free_device: return NULL; } +void target_configure_write_atomic_from_bdev(struct se_dev_attrib *attrib, + struct block_device *bdev) +{ + struct request_queue *q = bdev_get_queue(bdev); + int block_size = bdev_logical_block_size(bdev); + + if (!bdev_can_atomic_write(bdev)) + return; + + attrib->atomic_max_len = queue_atomic_write_max_bytes(q) / block_size; + attrib->atomic_granularity = attrib->atomic_alignment = + queue_atomic_write_unit_min_bytes(q) / block_size; + attrib->atomic_max_with_boundary = 0; + attrib->atomic_max_boundary = 0; +} +EXPORT_SYMBOL_GPL(target_configure_write_atomic_from_bdev); + /* * Check if the underlying struct block_device supports discard and if yes * configure the UNMAP parameters. diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index d394306f8f49..e32de80854b6 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -123,6 +123,8 @@ bool target_sense_desc_format(struct se_device *dev); sector_t target_to_linux_sector(struct se_device *dev, sector_t lb); bool target_configure_unmap_from_bdev(struct se_dev_attrib *attrib, struct block_device *bdev); +void target_configure_write_atomic_from_bdev(struct se_dev_attrib *attrib, + struct block_device *bdev); static inline bool target_dev_configured(struct se_device *se_dev) { -- cgit v1.2.3 From 526145725106b490b0c2d9f200b705b17a3da6b6 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 20 Oct 2025 10:38:17 +0000 Subject: scsi: target: Add WRITE_ATOMIC_16 handler Add the core LIO code to process the WRITE_ATOMIC_16 command. Signed-off-by: Mike Christie jpg: fix return code from sbc_check_atomic, reformat Signed-off-by: John Garry Link: https://patch.msgid.link/20251020103820.2917593-5-john.g.garry@oracle.com Signed-off-by: Martin K. Petersen --- drivers/target/target_core_sbc.c | 51 +++++++++++++++++++++++++++++++++++++++ include/target/target_core_base.h | 1 + 2 files changed, 52 insertions(+) (limited to 'include') diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index fe8beb7dbab1..abe91dc8722e 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -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: diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 70ece58d3078..56333b5726c8 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -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), }; /* -- cgit v1.2.3