[PATCH 1/2] scsi: ufs: Add the aggregated read query opcode and its reply format

From: Hyeoncheol Jeong

Date: Mon Sep 14 2026 - 04:51:40 EST


UFS 5.0 adds the AGGREGATED READ query opcode (0x9): a single QUERY
RESPONSE UPIU returns many descriptors, attributes and flags as a chain
of typed groups (JESD220H 10.7.9.14).

Add the AGGREGATION TYPE mask, the group types and the group header, and
let ufshcd_copy_query_response() copy the reply's data segment like a
descriptor read, recording its length in struct ufs_query_res.

Signed-off-by: Hyeoncheol Jeong <hyenc.jeong@xxxxxxxxxxx>
---
drivers/ufs/core/ufshcd.c | 7 +++++--
include/ufs/ufs.h | 43 +++++++++++++++++++++++++++++++++++++++
include/ufs/ufshcd.h | 2 ++
3 files changed, 50 insertions(+), 2 deletions(-)

diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index 2ba244cf40ac..3c404d9bc18c 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -2473,10 +2473,13 @@ int ufshcd_copy_query_response(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
struct ufs_query_res *query_res = &hba->dev_cmd.query.response;

memcpy(&query_res->upiu_res, &lrbp->ucd_rsp_ptr->qr, QUERY_OSF_SIZE);
+ query_res->data_segment_length =
+ be16_to_cpu(lrbp->ucd_rsp_ptr->header.data_segment_length);

- /* Get the descriptor */
+ /* Get the descriptor or aggregated data packet */
if (hba->dev_cmd.query.descriptor &&
- lrbp->ucd_rsp_ptr->qr.opcode == UPIU_QUERY_OPCODE_READ_DESC) {
+ (lrbp->ucd_rsp_ptr->qr.opcode == UPIU_QUERY_OPCODE_READ_DESC ||
+ lrbp->ucd_rsp_ptr->qr.opcode == UPIU_QUERY_OPCODE_AGGREGATED_READ)) {
u8 *descp = (u8 *)lrbp->ucd_rsp_ptr +
GENERAL_UPIU_REQUEST_SIZE;
u16 resp_len;
diff --git a/include/ufs/ufs.h b/include/ufs/ufs.h
index afbb32654fab..7ae5c1933dfb 100644
--- a/include/ufs/ufs.h
+++ b/include/ufs/ufs.h
@@ -30,6 +30,7 @@ static_assert(sizeof(struct utp_upiu_query) == 20);
* (ALIGNED_DEVMAN_RSP_SIZE) minus the fixed UPIU header it follows.
*/
#define QUERY_AGGREGATED_MAX_SIZE (4096 - GENERAL_UPIU_REQUEST_SIZE)
+#define QUERY_AGG_GROUP_HDR_SIZE 4
#define QUERY_DESC_MIN_SIZE 2
#define QUERY_DESC_HDR_SIZE 2
#define QUERY_OSF_SIZE (GENERAL_UPIU_REQUEST_SIZE - \
@@ -569,6 +570,48 @@ enum ufs_dev_pwr_mode {

#define UFS_WB_BUF_REMAIN_PERCENT(val) ((val) / 10)

+/* AGGREGATION TYPE field of an AGGREGATED READ query request */
+enum ufs_agg_type {
+ UFS_AGG_TYPE_ALL_FLAGS = BIT(0),
+ UFS_AGG_TYPE_ALL_ATTRS = BIT(1),
+ UFS_AGG_TYPE_DEVICE_DESC = BIT(2),
+ /* Unit descriptors and the RPMB unit descriptor */
+ UFS_AGG_TYPE_UNIT_DESC = BIT(3),
+ UFS_AGG_TYPE_INTERCONNECT_DESC = BIT(4),
+ UFS_AGG_TYPE_STRING_DESC = BIT(5),
+ /* Geometry descriptor and power descriptor */
+ UFS_AGG_TYPE_GEOMETRY_POWER_DESC = BIT(6),
+ UFS_AGG_TYPE_HEALTH_DESC = BIT(7),
+};
+
+/* Group Type field of an aggregated data packet group header. */
+enum ufs_agg_group_type {
+ UFS_AGG_GROUP_FLAGS = 0x01,
+ UFS_AGG_GROUP_ATTRS = 0x02,
+ /* Any descriptor with a unique IDN, i.e. all but the string ones */
+ UFS_AGG_GROUP_DESCS = 0x03,
+ UFS_AGG_GROUP_MANUFACTURER_STR = 0x04,
+ UFS_AGG_GROUP_PRODUCT_NAME_STR = 0x05,
+ UFS_AGG_GROUP_OEM_ID_STR = 0x06,
+ UFS_AGG_GROUP_SERIAL_NUMBER_STR = 0x07,
+ UFS_AGG_GROUP_PRODUCT_REV_STR = 0x08,
+};
+
+/**
+ * struct utp_agg_group_header - aggregated data packet group header
+ * @group_type: type of the data carried by this group, see ufs_agg_group_type
+ * @reserved: reserved
+ * @next_group_offset: byte offset from the start of the packet to the next
+ * group; zero ends the chain
+ */
+struct utp_agg_group_header {
+ u8 group_type;
+ u8 reserved;
+ __be16 next_group_offset;
+};
+
+static_assert(sizeof(struct utp_agg_group_header) == QUERY_AGG_GROUP_HDR_SIZE);
+
/**
* struct utp_cmd_rsp - RESPONSE UPIU structure
* @residual_transfer_count: Residual transfer count DW-3
diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h
index dfd302f2dc7c..1a5e181ff9e3 100644
--- a/include/ufs/ufshcd.h
+++ b/include/ufs/ufshcd.h
@@ -213,9 +213,11 @@ struct ufs_query_req {
/**
* struct ufs_query_res - UPIU QUERY
* @upiu_res: query response data
+ * @data_segment_length: response data segment length
*/
struct ufs_query_res {
struct utp_upiu_query upiu_res;
+ u16 data_segment_length;
};

/**
--
2.25.1