All of lore.kernel.org
 help / color / mirror / Atom feed
From: Mikail Sadic <mikail.sadic@ibm.com>
To: clg@kaod.org, peter.maydell@linaro.org
Cc: Mikail Sadic <mikail.sadic@ibm.com>,
	pbonzini@redhat.com, ninad@linux.ibm.com, titusr@google.com,
	jeuk20.kim@samsung.com, philmd@mailo.com,
	steven_lee@aspeedtech.com, leetroy@gmail.com,
	jamin_lin@aspeedtech.com, kane_chen@aspeedtech.com,
	andrew@codeconstruct.com.au, joel@jms.id.au,
	calebs@linux.ibm.com, milesg@linux.ibm.com, qemu-arm@nongnu.org,
	qemu-devel@nongnu.org
Subject: [PATCH v3 6/8] ufs: Make the logical block size configurable and answer absent LUNs
Date: Mon, 10 Aug 2026 13:57:44 -0500	[thread overview]
Message-ID: <20260810185748.1253-7-mikail.sadic@ibm.com> (raw)
In-Reply-To: <20260810185748.1253-1-mikail.sadic@ibm.com>

Two things the ufs-lu model hardcodes that hardware does not.

The logical block size is fixed at UFS_BLOCK_SIZE (4096), both in the unit
descriptor the logical unit reports and in the block size of the scsi-hd
backing it. UFS does not require that: the unit descriptor carries a
base-2 exponent, and 512-byte blocks are common on real hardware and in
images built for it. Add a 'logical-block-size' property that sets both,
defaulting to UFS_BLOCK_SIZE so the ufs PCI device keeps the geometry and
the property set it has today. Restrict it to powers of two from 512 bytes
to UFS_BLOCK_SIZE, and reject a drive shorter than one block, which would
otherwise realize a unit reporting zero blocks.

An INQUIRY addressed to a logical unit that is not mapped fails the
request outright. SPC has a specific answer for this case: return the
standard INQUIRY data with the peripheral qualifier and device type saying
that no device is present on that logical unit, with GOOD status, so that
a host enumerating logical units can tell an absent unit from a transport
error. hw/scsi/scsi-bus.c already answers this way for a target's
unsupported logical units. Do the same for an unmapped ufs-lu, using
TYPE_NO_LUN. Commands other than a standard INQUIRY still fail, now with
LOGICAL UNIT NOT SUPPORTED sense data rather than an unadorned request
failure. The invalid-LUN trace point is unchanged.

Both are needed by the AST2700 UFS controller added later in this series:
the OpenBMC images it boots are laid out for 512-byte sectors, and U-Boot
logs an OCS failure for every unpopulated logical unit while probing it.

Signed-off-by: Mikail Sadic <mikail.sadic@ibm.com>
---
 hw/ufs/ufs.h |  3 +++
 hw/ufs/lu.c  | 67 +++++++++++++++++++++++++++++++++++++++++++++++++---
 hw/ufs/ufs.c |  2 +-
 3 files changed, 68 insertions(+), 4 deletions(-)

diff --git a/hw/ufs/ufs.h b/hw/ufs/ufs.h
index aa8361d93d..47d1c72ef3 100644
--- a/hw/ufs/ufs.h
+++ b/hw/ufs/ufs.h
@@ -21,6 +21,7 @@
 #define UFS_MAX_MCQ_QNUM 32
 #define UFS_BLOCK_SIZE_SHIFT 12
 #define UFS_BLOCK_SIZE (1 << UFS_BLOCK_SIZE_SHIFT)
+#define UFS_MIN_BLOCK_SIZE 512
 
 typedef struct UfsBusClass {
     BusClass parent_class;
@@ -80,6 +81,7 @@ typedef UfsReqResult (*UfsScsiOp)(struct UfsLu *, UfsRequest *);
 typedef struct UfsLu {
     DeviceState qdev;
     uint8_t lun;
+    uint32_t logical_block_size;
     UnitDescriptor unit_desc;
     SCSIBus bus;
     SCSIDevice *scsi_dev;
@@ -303,6 +305,7 @@ void ufs_build_query_response(UfsRequest *req);
 void ufs_complete_req(UfsRequest *req, UfsReqResult req_result);
 void ufs_wb_update_avail_buffer(UfsHc *u);
 void ufs_init_wlu(UfsLu *wlu, uint8_t wlun);
+UfsReqResult ufs_emulate_absent_lun(UfsRequest *req);
 bool ufs_realize(UfsHc *u, DeviceState *dev, AddressSpace *dma_as,
                  Error **errp);
 void ufs_unrealize(UfsHc *u);
diff --git a/hw/ufs/lu.c b/hw/ufs/lu.c
index eeca865eb5..b1aba79a53 100644
--- a/hw/ufs/lu.c
+++ b/hw/ufs/lu.c
@@ -308,6 +308,44 @@ static int ufs_emulate_wlun_inquiry(UfsRequest *req, uint8_t *outbuf,
     return SCSI_INQUIRY_LEN;
 }
 
+/*
+ * A logical unit that is not mapped answers a standard INQUIRY as "not
+ * connected" with GOOD status, as hardware does, so that a host bus scan
+ * skips it instead of reporting a controller error. Any other command is
+ * rejected.
+ */
+UfsReqResult ufs_emulate_absent_lun(UfsRequest *req)
+{
+    QEMU_UNINITIALIZED uint8_t outbuf[SCSI_INQUIRY_LEN];
+    uint8_t sense_buf[UFS_SENSE_SIZE];
+    uint8_t scsi_status;
+    int len = 0;
+
+    if (req->req_upiu.sc.cdb[0] == INQUIRY &&
+        !(req->req_upiu.sc.cdb[1] & 0x1)) {
+        memset(outbuf, 0, sizeof(outbuf));
+        outbuf[0] = TYPE_NO_LUN;
+        outbuf[3] = 0x2;
+        outbuf[4] = SCSI_INQUIRY_LEN - 5;
+        len = SCSI_INQUIRY_LEN;
+        scsi_status = GOOD;
+    } else {
+        scsi_build_sense(sense_buf, SENSE_CODE(LUN_NOT_SUPPORTED));
+        scsi_status = CHECK_CONDITION;
+    }
+
+    len = MIN(len, (int)req->data_len);
+    if (scsi_status == GOOD && len > 0 &&
+        dma_buf_read(outbuf, len, NULL, req->sg, MEMTXATTRS_UNSPECIFIED) !=
+            MEMTX_OK) {
+        return UFS_REQUEST_FAIL;
+    }
+
+    ufs_build_scsi_response_upiu(req, sense_buf, sizeof(sense_buf), len,
+                                 scsi_status);
+    return UFS_REQUEST_SUCCESS;
+}
+
 static UfsReqResult ufs_emulate_scsi_cmd(UfsLu *lu, UfsRequest *req)
 {
     uint8_t lun = lu->lun;
@@ -394,6 +432,8 @@ static UfsReqResult ufs_process_scsi_cmd(UfsLu *lu, UfsRequest *req)
 static const Property ufs_lu_props[] = {
     DEFINE_PROP_DRIVE("drive", UfsLu, conf.blk),
     DEFINE_PROP_UINT8("lun", UfsLu, lun, 0),
+    DEFINE_PROP_UINT32("logical-block-size", UfsLu, logical_block_size,
+                       UFS_BLOCK_SIZE),
 };
 
 static bool ufs_add_lu(UfsHc *u, UfsLu *lu, Error **errp)
@@ -435,7 +475,7 @@ static void ufs_init_lu(UfsLu *lu)
     lu->unit_desc.length = sizeof(UnitDescriptor);
     lu->unit_desc.descriptor_idn = UFS_QUERY_DESC_IDN_UNIT;
     lu->unit_desc.lu_enable = 0x01;
-    lu->unit_desc.logical_block_size = UFS_BLOCK_SIZE_SHIFT;
+    lu->unit_desc.logical_block_size = ctz32(lu->logical_block_size);
     lu->unit_desc.unit_index = lu->lun;
     lu->unit_desc.logical_block_count =
         cpu_to_be64(brdv_len / (1 << lu->unit_desc.logical_block_size));
@@ -455,6 +495,25 @@ static bool ufs_lu_check_constraints(UfsLu *lu, Error **errp)
         return false;
     }
 
+    if (!is_power_of_2(lu->logical_block_size)) {
+        error_setg(errp, "logical-block-size must be a power of 2, not %"
+                   PRIu32, lu->logical_block_size);
+        return false;
+    }
+
+    if (lu->logical_block_size < UFS_MIN_BLOCK_SIZE ||
+        lu->logical_block_size > UFS_BLOCK_SIZE) {
+        error_setg(errp, "logical-block-size must be between %d and %d bytes",
+                   UFS_MIN_BLOCK_SIZE, UFS_BLOCK_SIZE);
+        return false;
+    }
+
+    if (blk_getlength(lu->conf.blk) < lu->logical_block_size) {
+        error_setg(errp, "drive is smaller than one %" PRIu32 "-byte block",
+                   lu->logical_block_size);
+        return false;
+    }
+
     return true;
 }
 
@@ -475,8 +534,10 @@ static void ufs_init_scsi_device(UfsLu *lu, BlockBackend *blk, Error **errp)
     scsi_dev = qdev_new("scsi-hd");
     object_property_add_child(OBJECT(&lu->bus), "ufs-scsi", OBJECT(scsi_dev));
 
-    qdev_prop_set_uint32(scsi_dev, "physical_block_size", UFS_BLOCK_SIZE);
-    qdev_prop_set_uint32(scsi_dev, "logical_block_size", UFS_BLOCK_SIZE);
+    qdev_prop_set_uint32(scsi_dev, "physical_block_size",
+                         lu->logical_block_size);
+    qdev_prop_set_uint32(scsi_dev, "logical_block_size",
+                         lu->logical_block_size);
     qdev_prop_set_uint32(scsi_dev, "scsi-id", 0);
     qdev_prop_set_uint32(scsi_dev, "lun", lu->lun);
     if (!qdev_prop_set_drive_err(scsi_dev, "drive", blk, errp)) {
diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c
index 36c674af32..016876eb63 100644
--- a/hw/ufs/ufs.c
+++ b/hw/ufs/ufs.c
@@ -1083,7 +1083,7 @@ static UfsReqResult ufs_exec_scsi_cmd(UfsRequest *req)
 
     if (!is_wlun(lun) && (lun >= UFS_MAX_LUS || u->lus[lun] == NULL)) {
         trace_ufs_err_scsi_cmd_invalid_lun(lun);
-        return UFS_REQUEST_FAIL;
+        return ufs_emulate_absent_lun(req);
     }
 
     switch (lun) {
-- 
2.53.0



  parent reply	other threads:[~2026-08-10 19:00 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-10 18:57 [PATCH v3 0/8] Add IBM Huygens BMC machine for AST2700 Mikail Sadic
2026-08-10 18:57 ` [PATCH v3 1/8] fsi/cfam: Add common CFAM base class Mikail Sadic
2026-08-11 13:36   ` Miles Glenn
2026-08-10 18:57 ` [PATCH v3 2/8] fsi/cfam: Add CFAM-S model Mikail Sadic
2026-08-10 18:57 ` [PATCH v3 3/8] arm/aspeed: Wire AST2700 FSI controllers to APB-to-OPB bridges Mikail Sadic
2026-08-11  4:32   ` Cédric Le Goater
2026-08-10 18:57 ` [PATCH v3 4/8] i2c/aspeed: Fix DMA receive first-byte handling for block reads Mikail Sadic
2026-08-11  4:30   ` Cédric Le Goater
2026-08-11  7:33     ` Jamin Lin
2026-08-10 18:57 ` [PATCH v3 5/8] hw/sensor: Add UCD90320 model Mikail Sadic
2026-08-10 18:57 ` Mikail Sadic [this message]
2026-08-10 18:57 ` [PATCH v3 7/8] ufs/aspeed: Add AST2700 UFS host controller Mikail Sadic
2026-08-10 18:57 ` [PATCH v3 8/8] arm/aspeed: Add AST2700 Huygens machine Mikail Sadic
2026-08-11  4:35   ` Cédric Le Goater

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=20260810185748.1253-7-mikail.sadic@ibm.com \
    --to=mikail.sadic@ibm.com \
    --cc=andrew@codeconstruct.com.au \
    --cc=calebs@linux.ibm.com \
    --cc=clg@kaod.org \
    --cc=jamin_lin@aspeedtech.com \
    --cc=jeuk20.kim@samsung.com \
    --cc=joel@jms.id.au \
    --cc=kane_chen@aspeedtech.com \
    --cc=leetroy@gmail.com \
    --cc=milesg@linux.ibm.com \
    --cc=ninad@linux.ibm.com \
    --cc=pbonzini@redhat.com \
    --cc=peter.maydell@linaro.org \
    --cc=philmd@mailo.com \
    --cc=qemu-arm@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    --cc=steven_lee@aspeedtech.com \
    --cc=titusr@google.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.