All of lore.kernel.org
 help / color / mirror / Atom feed
From: Damien Le Moal <dlemoal@kernel.org>
To: Jens Axboe <axboe@kernel.dk>,
	linux-block@vger.kernel.org, Christoph Hellwig <hch@lst.de>,
	linux-scsi@vger.kernel.org,
	"Martin K . Petersen" <martin.petersen@oracle.com>
Subject: [PATCH v8 11/12] scsi: sd_zbc: define storage element management operations
Date: Mon,  9 Nov 2026 18:51:43 +0900	[thread overview]
Message-ID: <20261109095144.819709-12-dlemoal@kernel.org> (raw)
In-Reply-To: <20261109095144.819709-1-dlemoal@kernel.org>

Define the storage element management operations using struct blk_se_ops.
These operations are valid only on SMR disks supporting the storage
element depopulation featu, with support for the GET PHYSICAL ELEMENTS
STATUS command being mandatory. The support for the modify_zones operation
is already indicated by the depop_modify_zones_supported SCSI disk flag.
sd_zbc_check_depop_supported() is modified to add detection for the
command RESTORE ELEMENTS AND REBUILD, which is indicated with the new
SCSI disk flag depop_restore_supported.

Both the remove_element and restore_elements operations will block
until the operation completes or an error is detected.

Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
---
 drivers/scsi/sd.c     |   3 +
 drivers/scsi/sd.h     |   3 +
 drivers/scsi/sd_zbc.c | 471 +++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 476 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index dc45df819c42..34b44d72b2b7 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -3939,6 +3939,9 @@ static const struct block_device_operations sd_fops = {
 	.get_unique_id		= sd_get_unique_id,
 	.free_disk		= scsi_disk_free_disk,
 	.pr_ops			= &sd_pr_ops,
+#ifdef CONFIG_BLK_DEV_ZONED
+	.se_ops			= &sd_zbc_se_ops,
+#endif
 };
 
 /**
diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h
index 84c87d0f05d8..8a32e5f771d8 100644
--- a/drivers/scsi/sd.h
+++ b/drivers/scsi/sd.h
@@ -158,6 +158,7 @@ struct scsi_disk {
 	unsigned	use_atomic_write_boundary : 1;
 	unsigned	depop_report_supported : 1;
 	unsigned	depop_modify_zones_supported : 1;
+	unsigned	depop_restore_supported : 1;
 };
 #define to_scsi_disk(obj) container_of(obj, struct scsi_disk, disk_dev)
 
@@ -244,6 +245,8 @@ unsigned int sd_zbc_complete(struct scsi_cmnd *cmd, unsigned int good_bytes,
 int sd_zbc_report_zones(struct gendisk *disk, sector_t sector,
 		unsigned int nr_zones, struct blk_report_zones_args *args);
 
+extern const struct blk_se_ops sd_zbc_se_ops;
+
 #else /* CONFIG_BLK_DEV_ZONED */
 
 static inline int sd_zbc_read_zones(struct scsi_disk *sdkp,
diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c
index bf2e60071d57..3bad1392f0e2 100644
--- a/drivers/scsi/sd_zbc.c
+++ b/drivers/scsi/sd_zbc.c
@@ -12,6 +12,7 @@
 #include <linux/vmalloc.h>
 #include <linux/sched/mm.h>
 #include <linux/mutex.h>
+#include <linux/delay.h>
 
 #include <linux/unaligned.h>
 
@@ -522,7 +523,8 @@ static int sd_zbc_check_capacity(struct scsi_disk *sdkp, unsigned char *buf,
  * @sdkp: Target SCSI disk
  * @buf: command buffer
  *
- * Check if the device supports the REMOVE ELEMENT AND MODIFY ZONES command.
+ * Check if the device supports the storage elements depopulation management
+ * commands.
  */
 static void sd_zbc_check_depop_supported(struct scsi_disk *sdkp,
 					 unsigned char *buf)
@@ -534,6 +536,7 @@ static void sd_zbc_check_depop_supported(struct scsi_disk *sdkp,
 				   SAI_GET_PHYSICAL_ELEMENT_STATUS) == 1;
 	if (!sdkp->depop_report_supported) {
 		sdkp->depop_modify_zones_supported = false;
+		sdkp->depop_restore_supported = false;
 		return;
 	}
 
@@ -541,6 +544,11 @@ static void sd_zbc_check_depop_supported(struct scsi_disk *sdkp,
 		scsi_report_opcode(sdkp->device, buf, SD_BUF_SIZE,
 				   SERVICE_ACTION_IN_16,
 				   SAI_REMOVE_ELEMENT_AND_MODIFY_ZONES) == 1;
+
+	sdkp->depop_restore_supported =
+		scsi_report_opcode(sdkp->device, buf, SD_BUF_SIZE,
+				   SERVICE_ACTION_IN_16,
+				   SAI_RESTORE_ELEMENTS_AND_REBUILD) == 1;
 }
 
 static void sd_zbc_print_zones(struct scsi_disk *sdkp)
@@ -548,6 +556,11 @@ static void sd_zbc_print_zones(struct scsi_disk *sdkp)
 	if (sdkp->device->type != TYPE_ZBC || !sdkp->capacity)
 		return;
 
+	if (sdkp->depop_modify_zones_supported)
+		sd_printk(KERN_NOTICE, sdkp, "Depop modify zones supported\n");
+	if (sdkp->depop_restore_supported)
+		sd_printk(KERN_NOTICE, sdkp, "Depop restoration supported\n");
+
 	if (sdkp->capacity & (sdkp->zone_info.zone_blocks - 1))
 		sd_printk(KERN_NOTICE, sdkp,
 			  "%u zones of %u logical blocks + 1 runt zone\n",
@@ -560,6 +573,462 @@ static void sd_zbc_print_zones(struct scsi_disk *sdkp)
 			  sdkp->zone_info.zone_blocks);
 }
 
+static void sd_zbc_parse_storage_element(struct scsi_disk *sdkp, u8 *desc,
+					 struct blk_se *element)
+{
+	struct scsi_device *sdp = sdkp->device;
+	sector_t zone_sectors = sd_zbc_zone_sectors(sdkp);
+	u64 capacity;
+
+	memset(element, 0, sizeof(*element));
+
+	element->id = get_unaligned_be32(&desc[4]);
+	element->restore_allowed = desc[13] & 0x01;
+
+	switch (desc[14]) {
+	case SCSI_PHYS_ELEM_TYPE_ALL_ACCESS_STORAGE:
+		element->type = BLK_SE_TYPE_RDWR;
+		capacity = get_unaligned_be64(&desc[16]);
+		if (!zone_sectors || capacity == ULLONG_MAX)
+			element->nr_zones = 0;
+		else
+			element->nr_zones =
+				logical_to_sectors(sdp, capacity) >>
+					ilog2(zone_sectors);
+		break;
+	case SCSI_PHYS_ELEM_TYPE_FRAC_ACCESS_STORAGE:
+		element->paired_id = get_unaligned_be32(&desc[16]);
+		if (desc[20] & 0x01)
+			element->type = BLK_SE_TYPE_READ;
+		else
+			element->type = BLK_SE_TYPE_WRITE;
+		element->nr_zones = get_unaligned_be64(&desc[24]);
+		break;
+	default:
+		element->type = BLK_SE_TYPE_UNKNOWN;
+	}
+
+	if (desc[15] >= SCSI_PHYS_ELEM_HEALTH_WITHIN_SPEC_LIMITS_MIN &&
+	    desc[15] <= SCSI_PHYS_ELEM_HEALTH_WITHIN_SPEC_LIMITS_MAX) {
+		element->status = BLK_SE_STS_OK;
+		return;
+	}
+
+	if (desc[15] >= SCSI_PHYS_ELEM_HEALTH_OUTSIDE_SPEC_LIMITS_MIN &&
+	    desc[15] <= SCSI_PHYS_ELEM_HEALTH_OUTSIDE_SPEC_LIMITS_MAX) {
+		element->status = BLK_SE_STS_DEGRADED;
+		return;
+	}
+
+	switch (desc[15]) {
+	case SCSI_PHYS_ELEM_HEALTH_AT_SPEC_LIMITS:
+		element->status = BLK_SE_STS_OK_LIMIT;
+		break;
+	case SCSI_PHYS_ELEM_HEALTH_DEPOP_REVOKE_ERR:
+		element->status = BLK_SE_STS_RESTORE_ERROR;
+		break;
+	case SCSI_PHYS_ELEM_HEALTH_DEPOP_REVOKE_IN_PROGRESS:
+		element->status = BLK_SE_STS_RESTORE_IN_PROGRESS;
+		break;
+	case SCSI_PHYS_ELEM_HEALTH_DEPOP_ERR:
+		element->status = BLK_SE_STS_REMOVE_ERROR;
+		break;
+	case SCSI_PHYS_ELEM_HEALTH_DEPOP_IN_PROGRESS:
+		element->status = BLK_SE_STS_REMOVE_IN_PROGRESS;
+		break;
+	case SCSI_PHYS_ELEM_HEALTH_DEPOP_OK:
+		element->status = BLK_SE_STS_REMOVED;
+		break;
+	case SCSI_PHYS_ELEM_HEALTH_NOT_REPORTED:
+	default:
+		element->status = BLK_SE_STS_UNKNOWN;
+		break;
+	}
+}
+
+/*
+ * Large hard limit on the number of storage elements. This accommodates all
+ * known devices today and likely forever :)
+ */
+#define SD_ZBC_MAX_STORAGE_ELEMENTS	255
+
+struct sd_zbc_se_report {
+	struct blk_se *elements;
+	unsigned int nr_elements;
+	unsigned int nr_reported_elements;
+	bool need_free_elements;
+	u8 *buf;
+	unsigned int buf_size;
+};
+
+static int sd_zbc_alloc_se_report(struct blk_se *elements,
+				  unsigned int nr_elements,
+				  bool alloc_elements,
+				  struct sd_zbc_se_report *rep)
+{
+	/*
+	 * We need at least 32B for the report header and 32B for each
+	 * descriptor. Note that we use GFP_KERNEL here, which may block. That
+	 * is fine when called from ioctl context. When called from a file
+	 * system, the FS can use memalloc_noio_save()/restore() or
+	 * memalloc_nofs_save()/restore() if GFP_NOFS is required to avoid I/Os
+	 * and/or FS re-entry.
+	 */
+	rep->need_free_elements = alloc_elements;
+	rep->nr_elements = min(SD_ZBC_MAX_STORAGE_ELEMENTS, nr_elements);
+	rep->buf_size = ALIGN((rep->nr_elements + 1) * 32, SECTOR_SIZE);
+	rep->buf = kzalloc(rep->buf_size, GFP_KERNEL);
+	if (!rep->buf)
+		return -ENOMEM;
+
+	if (!alloc_elements) {
+		rep->elements = elements;
+		return 0;
+	}
+
+	rep->elements =
+		kzalloc_objs(struct blk_se, rep->nr_elements, GFP_KERNEL);
+	if (!rep->elements) {
+		kfree(rep->buf);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static void sd_zbc_free_se_report(struct sd_zbc_se_report *rep)
+{
+	kfree(rep->buf);
+	if (rep->need_free_elements)
+		kfree(rep->elements);
+}
+
+static int sd_zbc_report_se(struct scsi_disk *sdkp,
+			    struct sd_zbc_se_report *rep)
+{
+	struct scsi_device *sdp = sdkp->device;
+	const int timeout = sdp->request_queue->rq_timeout;
+	struct scsi_sense_hdr sshdr;
+	struct scsi_failure failure_defs[] = {
+		/* Allow up to retry 3 times */
+		{
+			.result = SCMD_FAILURE_RESULT_ANY,
+			.allowed = 3,
+		},
+		{}
+	};
+	struct scsi_failures failures = {
+		.failure_definitions = failure_defs,
+	};
+	const struct scsi_exec_args exec_args = {
+		.sshdr = &sshdr,
+		.failures = &failures,
+	};
+	unsigned char cmd[16];
+	unsigned int nr_descs;
+	int i, result;
+	u8 *desc;
+
+	memset(cmd, 0, 16);
+	cmd[0] = SERVICE_ACTION_IN_16;
+	cmd[1] = SAI_GET_PHYSICAL_ELEMENT_STATUS;
+	put_unaligned_be32(rep->buf_size, &cmd[10]);
+
+	result = scsi_execute_cmd(sdp, cmd, REQ_OP_DRV_IN,
+			rep->buf, rep->buf_size, timeout, 1, &exec_args);
+	if (result) {
+		if (result > 0) {
+			sd_print_result(sdkp, "GET PHYSICAL ELEMENT STATUS",
+					result);
+			if (scsi_sense_valid(&sshdr))
+				sd_print_sense_hdr(sdkp, &sshdr);
+			return -EIO;
+		}
+		return result;
+	}
+
+	nr_descs = get_unaligned_be32(&rep->buf[0]);
+	if (!nr_descs) {
+		sd_printk(KERN_ERR, sdkp,
+			  "Invalid number of phys element descriptors\n");
+		return -EIO;
+	}
+	if (nr_descs > SD_ZBC_MAX_STORAGE_ELEMENTS) {
+		sd_printk(KERN_ERR, sdkp,
+			  "Too many phys element descriptors\n");
+		return -EIO;
+	}
+
+	if (!rep->elements) {
+		rep->nr_reported_elements = nr_descs;
+		return 0;
+	}
+
+	nr_descs = get_unaligned_be32(&rep->buf[4]);
+	if (!nr_descs) {
+		sd_printk(KERN_ERR, sdkp,
+			"Invalid number of reported phys element descriptors\n");
+		return -EIO;
+	}
+
+	desc = &rep->buf[32];
+	for (i = 0; i < min(rep->nr_elements, nr_descs); i++, desc += 32)
+		sd_zbc_parse_storage_element(sdkp, desc, &rep->elements[i]);
+	rep->nr_reported_elements = i;
+
+	return 0;
+}
+
+static int sd_zbc_report_storage_elements(struct gendisk *disk,
+					  struct blk_se *elements,
+					  unsigned int *nr_elements)
+{
+	struct scsi_disk *sdkp = scsi_disk(disk);
+	struct sd_zbc_se_report rep;
+	int ret;
+
+	if (!sdkp->depop_report_supported)
+		return -EOPNOTSUPP;
+
+	ret = sd_zbc_alloc_se_report(elements, *nr_elements, false, &rep);
+	if (ret)
+		return ret;
+
+	ret = sd_zbc_report_se(sdkp, &rep);
+	if (!ret)
+		*nr_elements = rep.nr_reported_elements;
+
+	sd_zbc_free_se_report(&rep);
+
+	return ret;
+}
+
+static int sd_zbc_execute_storage_element_cmd(struct scsi_disk *sdkp,
+					      u8 action, u32 element_id)
+{
+	struct scsi_device *sdp = sdkp->device;
+	const int timeout = sdp->request_queue->rq_timeout;
+	struct scsi_sense_hdr sshdr;
+	const struct scsi_exec_args exec_args = {
+		.sshdr = &sshdr,
+	};
+	unsigned char cmd[16];
+	const char *cmd_name;
+	int result;
+
+	memset(cmd, 0, sizeof(cmd));
+	cmd[0] = SERVICE_ACTION_IN_16;
+	cmd[1] = action;
+	if (action == SAI_REMOVE_ELEMENT_AND_MODIFY_ZONES) {
+		put_unaligned_be32(element_id, &cmd[10]);
+		cmd_name = "REMOVE ELEMENT AND MODIFY ZONES";
+	} else {
+		cmd_name = "RESTORE ELEMENTS AND REBUILD";
+	}
+
+	result = scsi_execute_cmd(sdp, cmd, REQ_OP_DRV_IN, NULL, 0,
+				  timeout, 1, &exec_args);
+	if (result) {
+		sd_printk(KERN_ERR, sdkp, "%s failed\n", cmd_name);
+		if (result > 0) {
+			if (scsi_sense_valid(&sshdr))
+				sd_print_sense_hdr(sdkp, &sshdr);
+			result = -EIO;
+		}
+		return result;
+	}
+
+	return 0;
+}
+
+/*
+ * Wait for the completion of a storage element remove operation. Note that the
+ * standards advise to use pollable sense data with the REQUEST SENSE command to
+ * detect if a remove operation is in progress. However, since REQUEST SENSE
+ * will return sense data only for the last executed command, and since we are
+ * not blocking commands, this method would be unreliable as we may end up
+ * seeing sense data (or no sense data) for a command that is not the REMOVE
+ * ELEMENT AND MODIFY ZONES we issued.
+ */
+static int sd_zbc_wait_for_se_removal(struct scsi_disk *sdkp,
+				      struct sd_zbc_se_report *rep,
+				      unsigned int element_id)
+{
+	bool element_checked, element_removed;
+	int ret, in_progress;
+	unsigned int i;
+
+	/*
+	 * Poll the storage elements health to see that we get the element we
+	 * are interested in and that its removal completed. Since we do not
+	 * know how long the operation may take, we cannot have a timeout on
+	 * this loop. So check for fatal signals so that the user can terminate
+	 * this loop if the device misbehaves.
+	 */
+	do {
+		/* Let the operation proceed and check. */
+		msleep(1000);
+
+		ret = sd_zbc_report_se(sdkp, rep);
+		if (ret)
+			return ret;
+
+		element_checked = false;
+		element_removed = false;
+		in_progress = 0;
+		for (i = 0; i < rep->nr_elements; i++) {
+			if (rep->elements[i].id == element_id)
+				element_checked = true;
+			switch (rep->elements[i].status) {
+			case BLK_SE_STS_REMOVED:
+				if (rep->elements[i].id == element_id)
+					element_removed = true;
+				break;
+			case BLK_SE_STS_REMOVE_IN_PROGRESS:
+				in_progress++;
+				break;
+			case BLK_SE_STS_REMOVE_ERROR:
+				if (rep->elements[i].id == element_id)
+					return -EIO;
+				break;
+			default:
+				break;
+			}
+		}
+
+		if (!element_checked)
+			return -EIO;
+		if (element_removed && !in_progress)
+			return 0;
+	} while (!fatal_signal_pending(current));
+
+	return -EINTR;
+}
+
+static int sd_zbc_remove_storage_element(struct gendisk *disk,
+					 unsigned int element_id)
+{
+	struct scsi_disk *sdkp = scsi_disk(disk);
+	struct sd_zbc_se_report rep;
+	int ret;
+
+	if (!sdkp->depop_modify_zones_supported)
+		return -EOPNOTSUPP;
+
+	/*
+	 * Get the resources we need to prepare for waiting for the operation to
+	 * complete.
+	 */
+	ret = sd_zbc_alloc_se_report(NULL, disk->nr_storage_elements,
+				     true, &rep);
+	if (ret)
+		return ret;
+
+	/*
+	 * Execute the remove command and wait for the element removal operation
+	 * to complete.
+	 */
+	ret = sd_zbc_execute_storage_element_cmd(sdkp,
+			SAI_REMOVE_ELEMENT_AND_MODIFY_ZONES, element_id);
+	if (!ret)
+		ret = sd_zbc_wait_for_se_removal(sdkp, &rep, element_id);
+	if (!ret)
+		sd_printk(KERN_NOTICE, sdkp,
+			  "Removed storage element %u\n", element_id);
+
+	sd_zbc_free_se_report(&rep);
+
+	return ret;
+}
+
+/*
+ * Wait for the completion of the restoration of removed storage elements.
+ * See the note for sd_zbc_wait_for_se_removal().
+ */
+static int sd_zbc_wait_for_se_restore(struct scsi_disk *sdkp,
+				      struct sd_zbc_se_report *rep)
+{
+	int ret, in_progress;
+	unsigned int i;
+
+	/*
+	 * Poll the storage elements health to see if we have any element still
+	 * being restored or if we got errors. Since we do not know how long the
+	 * operation may take, we cannot have a timeout on this loop. So check
+	 * for fatal signals so that the user can terminate this retry loop if
+	 * the device misbehaves.
+	 */
+	do {
+		/* Let the operation proceed and check. */
+		msleep(1000);
+
+		ret = sd_zbc_report_se(sdkp, rep);
+		if (ret)
+			return ret;
+
+		in_progress = 0;
+		for (i = 0; i < rep->nr_elements; i++) {
+			switch (rep->elements[i].status) {
+			case BLK_SE_STS_RESTORE_IN_PROGRESS:
+				in_progress++;
+				break;
+			case BLK_SE_STS_REMOVED:
+			case BLK_SE_STS_RESTORE_ERROR:
+				if (rep->elements[i].restore_allowed)
+					ret = -EIO;
+				break;
+			default:
+				break;
+			}
+		}
+
+		if (!in_progress)
+			return ret;
+	} while (!fatal_signal_pending(current));
+
+	return -EINTR;
+}
+
+static int sd_zbc_restore_storage_elements(struct gendisk *disk)
+{
+	struct scsi_disk *sdkp = scsi_disk(disk);
+	struct sd_zbc_se_report rep;
+	int ret;
+
+	if (!sdkp->depop_restore_supported)
+		return -EOPNOTSUPP;
+
+	/*
+	 * Get the resources we need to prepare for waiting for the operation to
+	 * complete.
+	 */
+	ret = sd_zbc_alloc_se_report(NULL, disk->nr_storage_elements,
+				     true, &rep);
+	if (ret)
+		return ret;
+
+	/*
+	 * Execute the restore command and wait for the elements restoration
+	 * operation to complete.
+	 */
+	ret = sd_zbc_execute_storage_element_cmd(sdkp,
+					SAI_RESTORE_ELEMENTS_AND_REBUILD, 0);
+	if (!ret)
+		ret = sd_zbc_wait_for_se_restore(sdkp, &rep);
+	if (!ret)
+		sd_printk(KERN_NOTICE, sdkp, "Restored storage elements\n");
+
+	sd_zbc_free_se_report(&rep);
+
+	return ret;
+}
+
+const struct blk_se_ops sd_zbc_se_ops = {
+	.report_elements	= sd_zbc_report_storage_elements,
+	.remove_element		= sd_zbc_remove_storage_element,
+	.restore_elements	= sd_zbc_restore_storage_elements,
+};
+
 /*
  * Call blk_revalidate_disk_zones() if any of the zoned disk properties have
  * changed that make it necessary to call that function. Called by
-- 
2.56.0


  parent reply	other threads:[~2026-11-09  9:51 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-09  9:51 [PATCH v8 00/12] Add support for storage element depopulation Damien Le Moal
2026-11-09  9:51 ` [PATCH v8 01/12] block: introduce disk_zone_is_offline() Damien Le Moal
2026-11-09  9:51 ` [PATCH v8 02/12] block: refactor blk_revalidate_disk_zones() Damien Le Moal
2026-11-09  9:51 ` [PATCH v8 03/12] block: allow dropping all zone write plugs on revalidation Damien Le Moal
2026-11-09 11:13   ` Hannes Reinecke
2026-11-11 15:23   ` Christoph Hellwig
2026-11-09  9:51 ` [PATCH v8 04/12] block: introduce storage element management Damien Le Moal
2026-11-09 11:14   ` Hannes Reinecke
2026-11-11 15:24   ` Christoph Hellwig
2026-11-09  9:51 ` [PATCH v8 05/12] block: add storage element management ioctls Damien Le Moal
2026-11-09 11:15   ` Hannes Reinecke
2026-11-11 15:25   ` Christoph Hellwig
2026-11-09  9:51 ` [PATCH v8 06/12] zloop: fix zone reporting consistency Damien Le Moal
2026-11-09 10:06   ` sashiko-bot
2026-11-09 11:16   ` Hannes Reinecke
2026-11-11 15:27   ` Christoph Hellwig
2026-11-09  9:51 ` [PATCH v8 07/12] zloop: add storage element emulation Damien Le Moal
2026-11-09 10:15   ` sashiko-bot
2026-11-09 11:17   ` Hannes Reinecke
2026-11-09  9:51 ` [PATCH v8 08/12] zloop: add degrade_element control command Damien Le Moal
2026-11-09  9:51 ` [PATCH v8 09/12] scsi: scsi_proto: refine the definition of storage element health Damien Le Moal
2026-11-09 11:17   ` Hannes Reinecke
2026-11-11 15:28   ` Christoph Hellwig
2026-11-09  9:51 ` [PATCH v8 10/12] scsi: sd_zbc: always revalidate zones for disks supporting head depopulation Damien Le Moal
2026-11-09 11:18   ` Hannes Reinecke
2026-11-11 15:29   ` Christoph Hellwig
2026-11-09  9:51 ` Damien Le Moal [this message]
2026-11-09 10:13   ` [PATCH v8 11/12] scsi: sd_zbc: define storage element management operations sashiko-bot
2026-11-09 11:21   ` Hannes Reinecke
2026-11-09  9:51 ` [PATCH v8 12/12] scsi: sd: fail read commands to offline zones early Damien Le Moal

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261109095144.819709-12-dlemoal@kernel.org \
    --to=dlemoal@kernel.org \
    --cc=axboe@kernel.dk \
    --cc=hch@lst.de \
    --cc=linux-block@vger.kernel.org \
    --cc=linux-scsi@vger.kernel.org \
    --cc=martin.petersen@oracle.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.