Am Tage des Herren Sun, 15 Jun 2025 06:09:39 GMT Warner Losh <i...@freebsd.org> schrieb:
> The branch main has been updated by imp: > > URL: > https://cgit.FreeBSD.org/src/commit/?id=1349a733cf2828e0040cabef89eeadc3ff00c40b > > commit 1349a733cf2828e0040cabef89eeadc3ff00c40b > Author: Jaeyoon Choi <j_yoon.c...@samsung.com> > AuthorDate: 2025-06-13 18:33:01 +0000 > Commit: Warner Losh <i...@freebsd.org> > CommitDate: 2025-06-15 06:08:56 +0000 > > ufshci: Introduce the ufshci(4) driver > > This commit adds a storage driver that supports the Universal Flash > Storage Host Controller Interface (UFSHCI) on FreeBSD. > > Universal Flash Storage (UFS) is a flash-based mobile storage device > that replaces eMMC, aiming for high performance with low power. The UFS > Host Controller Interface (UFSHCI) is the host side controller and > connects UFS device to a system bus, such as PCIe. > > The code targets the latest standards: > - UFS 4.1: https://www.jedec.org/standards-documents/docs/jesd220g > - UFSHCI 4.1: https://www.jedec.org/standards-documents/docs/jesd223f > > The ufshci(4) driver implements controller/device initialization, > interrupt, single-doorbell(SDB) queue based IO requests. Support for > multi-queue (MCQ) IO requests is planned for a later commit. > > Implemented features: > - PCIe bus support > - legacy(INTx) Interrupt Handling > - UIC command support > - UTP Transfer Request (UTR) support > - UTP Task Management Request (UTMR) support > - single doorbell queue (SDB) with multiple queue depth > - SCSI command set support > - sysctl > > Work in progress: > - multi-Circular Queue (per-CPU IO queues) > - MSI-X interrupt Support > - write booster > - write Protect > - Host Performance Booster (HPB) > - interrupt aggregation > - ARM based system bus support > - ufs-utils port > > Tests were performed on QEMU and an Intel-based laptop. > Since QEMU has an emulated UFS device, I tested on QEMU. > > How to test on QEMU: > 1. Run QEMU > $ qemu-system-x86_64 ... -device ufs -drive > file=blk1g.bin,format=raw,if=none,id=luimg -device ufs-lu,drive=luimg,lun=0 2. > Loading/unloading the ufshci module on QEMU $ kldload > /usr/obj/usr/src/amd64.amd64/sys/modules/ufshci/ufshci.ko $ kldunload ufshci > > Testing on real hardware: > - Samsung Galaxy Book S (Intel Lakefield) with UFS 3.0 > - Lenovo duet 3 11ian8 (Intel N100) with UFS 2.1 > > Sponsored by: Samsung Electronics > Reviewed by: imp > Differential Revision: https://reviews.freebsd.org/D50370 > --- > sbin/camcontrol/camcontrol.c | 13 + It seems changes to sources breaks buildkernel (at least for me) on customized kernel config: [...] --- camcontrol.pieo --- /usr/src/sbin/camcontrol/camcontrol.c:5407:23: error: use of undeclared identifier 'CTS_UFSHCI_VALID_MODE' --- all_subdir_bin --- --- all_subdir_bin/sleep --- ===> bin/sleep (all) --- all_subdir_sbin --- 5407 | if (ufshci->valid & CTS_UFSHCI_VALID_MODE) { | ^ [...] Kind regards, oh > sys/cam/cam_ccb.h | 20 + > sys/cam/scsi/scsi_xpt.c | 1 + > sys/dev/ufshci/ufshci.c | 76 +++ > sys/dev/ufshci/ufshci.h | 939 > ++++++++++++++++++++++++++++++++++++++ > sys/dev/ufshci/ufshci_ctrlr.c | 503 ++++++++++++++++++++ > sys/dev/ufshci/ufshci_ctrlr_cmd.c | 53 +++ > sys/dev/ufshci/ufshci_dev.c | 428 +++++++++++++++++ > sys/dev/ufshci/ufshci_pci.c | 260 +++++++++++ > sys/dev/ufshci/ufshci_private.h | 508 +++++++++++++++++++++ > sys/dev/ufshci/ufshci_reg.h | 469 +++++++++++++++++++ > sys/dev/ufshci/ufshci_req_queue.c | 490 ++++++++++++++++++++ > sys/dev/ufshci/ufshci_req_sdb.c | 427 +++++++++++++++++ > sys/dev/ufshci/ufshci_sim.c | 372 +++++++++++++++ > sys/dev/ufshci/ufshci_sysctl.c | 233 ++++++++++ > sys/dev/ufshci/ufshci_uic_cmd.c | 224 +++++++++ > sys/modules/ufshci/Makefile | 22 + > 17 files changed, 5038 insertions(+) > > diff --git a/sbin/camcontrol/camcontrol.c b/sbin/camcontrol/camcontrol.c > index a2e65055fcaa..19684c044ef5 100644 > --- a/sbin/camcontrol/camcontrol.c > +++ b/sbin/camcontrol/camcontrol.c > @@ -5400,6 +5400,19 @@ cts_print(struct cam_device *device, struct > ccb_trans_settings *cts) > nvmf_transport_type(nvmf->trtype)); > } > } > + if (cts->transport == XPORT_UFSHCI) { > + struct ccb_trans_settings_ufshci *ufshci = > + &cts->xport_specific.ufshci; > + > + if (ufshci->valid & CTS_UFSHCI_VALID_MODE) { > + fprintf(stdout, "%sHigh Speed Gear: %d (%d max)\n", > + pathstr, ufshci->hs_gear, ufshci->max_hs_gear); > + fprintf(stdout, "%sUnipro TX lanes: %d (%d max)\n", > pathstr, > + ufshci->tx_lanes, ufshci->max_tx_lanes); > + fprintf(stdout, "%sUnipro RX lanes: %d (%d max)\n", > pathstr, > + ufshci->rx_lanes, ufshci->max_rx_lanes); > + } > + } > if (cts->protocol == PROTO_ATA) { > struct ccb_trans_settings_ata *ata= > &cts->proto_specific.ata; > diff --git a/sys/cam/cam_ccb.h b/sys/cam/cam_ccb.h > index 15e136e8a072..da98b98ba7d1 100644 > --- a/sys/cam/cam_ccb.h > +++ b/sys/cam/cam_ccb.h > @@ -298,6 +298,7 @@ typedef enum { > XPORT_NVME, /* NVMe over PCIe */ > XPORT_MMCSD, /* MMC, SD, SDIO card */ > XPORT_NVMF, /* NVMe over Fabrics */ > + XPORT_UFSHCI, /* Universal Flash Storage Host Interface */ > } cam_xport; > > #define XPORT_IS_NVME(t) ((t) == XPORT_NVME || (t) == XPORT_NVMF) > @@ -1065,6 +1066,24 @@ struct ccb_trans_settings_nvmf > uint8_t trtype; > }; > > +struct ccb_trans_settings_ufshci > +{ > + u_int valid; /* Which fields to honor */ > + /* > + * Ensure the validity of the information for the Unipro link > + * (GEAR, SPEED, LANE) > + */ > +#define CTS_UFSHCI_VALID_LINK 0x01 > + uint32_t speed; > + uint8_t hs_gear; /* High Speed Gear (G1, G2, G3...) */ > + uint8_t tx_lanes; > + uint8_t rx_lanes; > + uint8_t max_hs_gear; /* Maximum HS Gear */ > + uint8_t max_tx_lanes; > + uint8_t max_rx_lanes; > +}; > + > + > #include <cam/mmc/mmc_bus.h> > struct ccb_trans_settings_mmc { > struct mmc_ios ios; > @@ -1138,6 +1157,7 @@ struct ccb_trans_settings { > struct ccb_trans_settings_sata sata; > struct ccb_trans_settings_nvme nvme; > struct ccb_trans_settings_nvmf nvmf; > + struct ccb_trans_settings_ufshci ufshci; > } xport_specific; > }; > > diff --git a/sys/cam/scsi/scsi_xpt.c b/sys/cam/scsi/scsi_xpt.c > index 2bb59cb2d92b..439dd2050a95 100644 > --- a/sys/cam/scsi/scsi_xpt.c > +++ b/sys/cam/scsi/scsi_xpt.c > @@ -618,6 +618,7 @@ SCSI_XPT_XPORT(usb, USB); > SCSI_XPT_XPORT(iscsi, ISCSI); > SCSI_XPT_XPORT(srp, SRP); > SCSI_XPT_XPORT(ppb, PPB); > +SCSI_XPT_XPORT(ufshci, UFSHCI); > > #undef SCSI_XPORT_XPORT > > diff --git a/sys/dev/ufshci/ufshci.c b/sys/dev/ufshci/ufshci.c > new file mode 100644 > index 000000000000..84a9629e74b0 > --- /dev/null > +++ b/sys/dev/ufshci/ufshci.c > @@ -0,0 +1,76 @@ > +/*- > + * Copyright (c) 2025, Samsung Electronics Co., Ltd. > + * Written by Jaeyoon Choi > + * > + * SPDX-License-Identifier: BSD-2-Clause > + */ > + > +#include <sys/param.h> > +#include <sys/bus.h> > +#include <sys/conf.h> > +#include <sys/module.h> > + > +#include "ufshci_private.h" > + > +MALLOC_DEFINE(M_UFSHCI, "ufshci", "ufshci(4) memory allocations"); > + > +int > +ufshci_attach(device_t dev) > +{ > + struct ufshci_controller *ctrlr = device_get_softc(dev); > + int status; > + > + status = ufshci_ctrlr_construct(ctrlr, dev); > + if (status != 0) { > + ufshci_ctrlr_destruct(ctrlr, dev); > + return (status); > + } > + > + ctrlr->config_hook.ich_func = ufshci_ctrlr_start_config_hook; > + ctrlr->config_hook.ich_arg = ctrlr; > + > + if (config_intrhook_establish(&ctrlr->config_hook) != 0) > + return (ENOMEM); > + > + return (0); > +} > + > +int > +ufshci_detach(device_t dev) > +{ > + struct ufshci_controller *ctrlr = device_get_softc(dev); > + > + config_intrhook_drain(&ctrlr->config_hook); > + > + ufshci_ctrlr_destruct(ctrlr, dev); > + > + return (0); > +} > + > +void > +ufshci_completion_poll_cb(void *arg, const struct ufshci_completion *cpl, > + bool error) > +{ > + struct ufshci_completion_poll_status *status = arg; > + > + /* > + * Copy status into the argument passed by the caller, so that the > + * caller can check the status to determine if the the request passed > + * or failed. > + */ > + memcpy(&status->cpl.response_upiu, &cpl->response_upiu, cpl->size); > + status->error = error; > + atomic_store_rel_int(&status->done, 1); > +} > + > +static int > +ufshci_modevent(module_t mod __unused, int type __unused, void *argp > __unused) > +{ > + return (0); > +} > + > +static moduledata_t ufshci_mod = { "ufshci", ufshci_modevent, 0 }; > + > +DECLARE_MODULE(ufshci, ufshci_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); > +MODULE_VERSION(ufshci, 1); > +MODULE_DEPEND(ufshci, cam, 1, 1, 1); > diff --git a/sys/dev/ufshci/ufshci.h b/sys/dev/ufshci/ufshci.h > new file mode 100644 > index 000000000000..9f0faaadeb57 > --- /dev/null > +++ b/sys/dev/ufshci/ufshci.h > @@ -0,0 +1,939 @@ > +/*- > + * Copyright (c) 2025, Samsung Electronics Co., Ltd. > + * Written by Jaeyoon Choi > + * > + * SPDX-License-Identifier: BSD-2-Clause > + */ > + > +#ifndef __UFSHCI_H__ > +#define __UFSHCI_H__ > + > +#include <sys/param.h> > +#include <sys/endian.h> > + > +/* > + * Note: This driver currently assumes a little-endian architecture. > + * Big-endian support is not yet implemented. > + */ > + > +/* MIPI UniPro spec 2.0, section 5.8.1 "PHY Adapter Common Attributes" */ > +#define PA_AvailTxDataLanes 0x1520 > +#define PA_AvailRxDataLanes 0x1540 > + > +/* > + * MIPI UniPro spec 2.0, section 5.8.2 "PHY Adapter M-PHY-Specific > + * Attributes" > + */ > +#define PA_ConnectedTxDataLanes 0x1561 > +#define PA_ConnectedRxDataLanes 0x1581 > +#define PA_MaxRxHSGear 0x1587 > +#define PA_Granularity 0x15AA > +#define PA_TActivate 0x15A8 > + > +#define PA_RemoteVerInfo 0x15A0 > +#define PA_LocalVerInfo 0x15A9 > + > +/* UFSHCI spec 4.1, section 7.4 "UIC Power Mode Change" */ > +#define PA_ActiveTxDataLanes 0x1560 > +#define PA_ActiveRxDataLanes 0x1580 > +#define PA_TxGear 0x1568 > +#define PA_RxGear 0x1583 > +#define PA_TxTermination 0x1569 > +#define PA_RxTermination 0x1584 > +#define PA_HSSeries 0x156A > +#define PA_PWRModeUserData0 0x15B0 > +#define PA_PWRModeUserData1 0x15B1 > +#define PA_PWRModeUserData2 0x15B2 > +#define PA_PWRModeUserData3 0x15B3 > +#define PA_PWRModeUserData4 0x15B4 > +#define PA_PWRModeUserData5 0x15B5 > + > +#define PA_TxHsAdaptType 0x15D4 > +#define PA_PWRMode 0x1571 > + > +#define DME_LocalFC0ProtectionTimeOutVal 0xD041 > +#define DME_LocalTC0ReplayTimeOutVal 0xD042 > +#define DME_LocalAFC0ReqTimeOutVal 0xD043 > + > +/* Currently, UFS uses TC0 only. */ > +#define DL_FC0ProtectionTimeOutVal_Default 8191 > +#define DL_TC0ReplayTimeOutVal_Default 65535 > +#define DL_AFC0ReqTimeOutVal_Default 32767 > + > +/* UFS Spec 4.1, section 6.4 "Reference Clock" */ > +enum ufshci_attribute_reference_clock { > + UFSHCI_REF_CLK_19_2MHz = 0x0, > + UFSHCI_REF_CLK_26MHz = 0x1, > + UFSHCI_REF_CLK_38_4MHz = 0x2, > + UFSHCI_REF_CLK_OBSOLETE = 0x3, > +}; > + > +/* UFS spec 4.1, section 9 "UFS UIC Layer: MIPI Unipro" */ > +enum ufshci_uic_cmd_opcode { > + /* Configuration */ > + UFSHCI_DME_GET = 0x01, > + UFSHCI_DME_SET = 0x02, > + UFSHCI_DME_PEER_GET = 0x03, > + UFSHCI_DME_PEER_SET = 0x04, > + /* Controll */ > + UFSHCI_DME_POWER_ON = 0x10, > + UFSHCI_DME_POWER_OFF = 0x11, > + UFSHCI_DME_ENABLE = 0x12, > + UFSHCI_DME_RESET = 0x14, > + UFSHCI_DME_ENDPOINT_RESET = 0x15, > + UFSHCI_DME_LINK_STARTUP = 0x16, > + UFSHCI_DME_HIBERNATE_ENTER = 0x17, > + UFSHCI_DME_HIBERNATE_EXIT = 0x18, > + UFSHCI_DME_TEST_MODE = 0x1a, > +}; > + > +/* UFSHCI spec 4.1, section 5.6.3 "Offset 98h: UICCMDARG2 – UIC Command > + * Argument" */ > +enum ufshci_uic_cmd_attr_set_type { > + UFSHCI_ATTR_SET_TYPE_NORMAL = 0, /* volatile value */ > + UFSHCI_ATTR_SET_TYPE_STATIC = 1, /* non-volatile reset value */ > +}; > + > +struct ufshci_uic_cmd { > + uint8_t opcode; > + uint32_t argument1; > + uint32_t argument2; > + uint32_t argument3; > +}; > + > +/* UFS spec 4.1, section 10.5 "UPIU Transactions" */ > +enum transaction_code { > + UFSHCI_UPIU_TRANSACTION_CODE_NOP_OUT = 0x00, > + UFSHCI_UPIU_TRANSACTION_CODE_COMMAND = 0x01, > + UFSHCI_UPIU_TRANSACTION_CODE_DATA_OUT = 0x02, > + UFSHCI_UPIU_TRANSACTION_CODE_TASK_MANAGEMENT_REQUEST = 0x04, > + UFSHCI_UPIU_TRANSACTION_CODE_QUERY_REQUEST = 0x16, > + UFSHCI_UPIU_TRANSACTION_CODE_NOP_IN = 0x20, > + UFSHCI_UPIU_TRANSACTION_CODE_RESPONSE = 0x21, > + UFSHCI_UPIU_TRANSACTION_CODE_DATA_IN = 0x22, > + UFSHCI_UPIU_TRANSACTION_CODE_TASK_MANAGEMENT_RESPONSE = 0x24, > + UFSHCI_UPIU_TRANSACTION_CODE_READY_TO_TRANSFER = 0x31, > + UFSHCI_UPIU_TRANSACTION_CODE_QUERY_RESPONSE = 0x36, > + UFSHCI_UPIU_TRANSACTION_CODE_REJECT_UPIU = 0x3f, > +}; > + > +enum overall_command_status { > + UFSHCI_DESC_SUCCESS = 0x0, > + UFSHCI_DESC_INVALID_COMMAND_TABLE_ATTRIBUTES = 0x01, > + UFSHCI_DESC_INVALID_PRDT_ATTRIBUTES = 0x02, > + UFSHCI_DESC_MISMATCH_DATA_BUFFER_SIZE = 0x03, > + UFSHCI_DESC_MISMATCH_RESPONSE_UPIU_SIZE = 0x04, > + UFSHCI_DESC_COMMUNICATION_FAILURE_WITHIN_UIC_LAYERS = 0x05, > + UFSHCI_DESC_ABORTED = 0x06, > + UFSHCI_DESC_HOST_CONTROLLER_FATAL_ERROR = 0x07, > + UFSHCI_DESC_DEVICEFATALERROR = 0x08, > + UFSHCI_DESC_INVALID_CRYPTO_CONFIGURATION = 0x09, > + UFSHCI_DESC_GENERAL_CRYPTO_ERROR = 0x0A, > + UFSHCI_DESC_INVALID = 0x0F, > +}; > + > +enum response_code { > + UFSHCI_RESPONSE_CODE_TARGET_SUCCESS = 0x00, > + UFSHCI_RESPONSE_CODE_TARGET_FAILURE = 0x01, > + UFSHCI_RESPONSE_CODE_PARAMETER_NOTREADABLE = 0xF6, > + UFSHCI_RESPONSE_CODE_PARAMETER_NOTWRITEABLE = 0xF7, > + UFSHCI_RESPONSE_CODE_PARAMETER_ALREADYWRITTEN = 0xF8, > + UFSHCI_RESPONSE_CODE_INVALID_LENGTH = 0xF9, > + UFSHCI_RESPONSE_CODE_INVALID_VALUE = 0xFA, > + UFSHCI_RESPONSE_CODE_INVALID_SELECTOR = 0xFB, > + UFSHCI_RESPONSE_CODE_INVALID_INDEX = 0xFC, > + UFSHCI_RESPONSE_CODE_INVALID_IDN = 0xFD, > + UFSHCI_RESPONSE_CODE_INVALID_OPCODE = 0xFE, > + UFSHCI_RESPONSE_CODE_GENERAL_FAILURE = 0xFF, > +}; > + > +/* UFSHCI spec 4.1, section 6.1.1 "UTP Transfer Request Descriptor" */ > +enum ufshci_command_type { > + UFSHCI_COMMAND_TYPE_UFS_STORAGE = 0x01, > + UFSHCI_COMMAND_TYPE_NULLIFIED_UTRD = 0x0F, > +}; > + > +enum ufshci_data_direction { > + UFSHCI_DATA_DIRECTION_NO_DATA_TRANSFER = 0x00, > + UFSHCI_DATA_DIRECTION_FROM_SYS_TO_TGT = 0x01, > + UFSHCI_DATA_DIRECTION_FROM_TGT_TO_SYS = 0x10, > + UFSHCI_DATA_DIRECTION_RESERVED = 0b11, > +}; > + > +enum ufshci_overall_command_status { > + UFSHCI_OCS_SUCCESS = 0x0, > + UFSHCI_OCS_INVALID_COMMAND_TABLE_ATTRIBUTES = 0x01, > + UFSHCI_OCS_INVALID_PRDT_ATTRIBUTES = 0x02, > + UFSHCI_OCS_MISMATCH_DATA_BUFFER_SIZE = 0x03, > + UFSHCI_OCS_MISMATCH_RESPONSE_UPIU_SIZE = 0x04, > + UFSHCI_OCS_COMMUNICATION_FAILURE_WITHIN_UIC_LAYERS = 0x05, > + UFSHCI_OCS_ABORTED = 0x06, > + UFSHCI_OCS_HOST_CONTROLLER_FATAL_ERROR = 0x07, > + UFSHCI_OCS_DEVICE_FATAL_ERROR = 0x08, > + UFSHCI_OCS_INVALID_CRYPTO_CONFIGURATION = 0x09, > + UFSHCI_OCS_GENERAL_CRYPTO_ERROR = 0x0A, > + UFSHCI_OCS_INVALID = 0xF, > +}; > + > +struct ufshci_utp_xfer_req_desc { > + /* dword 0 */ > + uint32_t cci : 8; /* [7:0] */ > + uint32_t total_ehs_length : 8; /* [15:8] */ > + uint32_t reserved0 : 7; /* [22:16] */ > + uint32_t ce : 1; /* [23] */ > + uint32_t interrupt : 1; /* [24] */ > + uint32_t data_direction : 2; /* [26:25] */ > + uint32_t reserved1 : 1; /* [27] */ > + uint32_t command_type : 4; /* [31:28] */ > + > + /* dword 1 */ > + uint32_t data_unit_number_lower; /* [31:0] */ > + > + /* dword 2 */ > + uint8_t overall_command_status; /* [7:0] */ > + uint8_t common_data_size; /* [15:8] */ > + uint16_t last_data_byte_count; /* [31:16] */ > + > + /* dword 3 */ > + uint32_t data_unit_number_upper; /* [31:0] */ > + > + /* dword 4 */ > + uint32_t utp_command_descriptor_base_address; /* [31:0] */ > + > + /* dword 5 */ > + uint32_t utp_command_descriptor_base_address_upper; /* [31:0] */ > + > + /* dword 6 */ > + uint16_t response_upiu_length; /* [15:0] */ > + uint16_t response_upiu_offset; /* [31:16] */ > + > + /* dword 7 */ > + uint16_t prdt_length; /* [15:0] */ > + uint16_t prdt_offset; /* [31:16] */ > +} __packed __aligned(8); > + > +_Static_assert(sizeof(struct ufshci_utp_xfer_req_desc) == 32, > + "ufshci_utp_xfer_req_desc must be 32 bytes"); > + > +/* > + * According to the UFSHCI specification, the size of the UTP command > + * descriptor is as follows. The size of the transfer request is not limited, > + * a transfer response can be as long as 65535 * dwords, and a PRDT can be as > + * long as 65565 * PRDT entry size(16 bytes). However, for ease of use, this > + * UFSHCI Driver imposes the following limits. The size of the transfer > + * request and the transfer response is 1024 bytes or less. The PRDT region > + * limits the number of scatter gathers to 256 + 1, using a total of 4096 + > + * 16 bytes. Therefore, only 8KB size is allocated for the UTP command > + * descriptor. > + */ > +#define UFSHCI_UTP_COMMAND_DESCRIPTOR_SIZE 8192 > +#define UFSHCI_UTP_XFER_REQ_SIZE 512 > +#define UFSHCI_UTP_XFER_RESP_SIZE 512 > + > +/* > + * To reduce the size of the UTP Command Descriptor(8KB), we must use only > + * 256 + 1 PRDT entries. The reason for adding the 1 is that if the data is > + * not aligned, one additional PRDT_ENTRY is used. > + */ > +#define UFSHCI_MAX_PRDT_ENTRY_COUNT (256 + 1) > + > +/* UFSHCI spec 4.1, section 6.1.2 "UTP Command Descriptor" */ > +struct ufshci_prdt_entry { > + /* dword 0 */ > + uint32_t data_base_address; /* [31:0] */ > + > + /* dword 1 */ > + uint32_t data_base_address_upper; /* [31:0] */ > + > + /* dword 2 */ > + uint32_t reserved; /* [31:0] */ > + > + /* dword 3 */ > + uint32_t data_byte_count; /* [17:0] Maximum byte > + * count is 256KB */ > +} __packed __aligned(8); > + > +_Static_assert(sizeof(struct ufshci_prdt_entry) == 16, > + "ufshci_prdt_entry must be 16 bytes"); > + > +struct ufshci_utp_cmd_desc { > + uint8_t command_upiu[UFSHCI_UTP_XFER_REQ_SIZE]; > + uint8_t response_upiu[UFSHCI_UTP_XFER_RESP_SIZE]; > + uint8_t prd_table[sizeof(struct ufshci_prdt_entry) * > + UFSHCI_MAX_PRDT_ENTRY_COUNT]; > + uint8_t padding[3072 - sizeof(struct ufshci_prdt_entry)]; > +} __packed __aligned(128); > + > +_Static_assert(sizeof(struct ufshci_utp_cmd_desc) == > + UFSHCI_UTP_COMMAND_DESCRIPTOR_SIZE, > + "ufshci_utp_cmd_desc must be 8192 bytes"); > + > +#define UFSHCI_UTP_TASK_MGMT_REQ_SIZE 32 > +#define UFSHCI_UTP_TASK_MGMT_RESP_SIZE 32 > + > +/* UFSHCI spec 4.1, section 6.3.1 "UTP Task Management Request Descriptor" */ > +struct ufshci_utp_task_mgmt_req_desc { > + /* dword 0 */ > + uint32_t reserved0 : 24; /* [23:0] */ > + uint32_t interrupt : 1; /* [24] */ > + uint32_t reserved1 : 7; /* [31:25] */ > + > + /* dword 1 */ > + uint32_t reserved2; /* [31:0] */ > + > + /* dword 2 */ > + uint8_t overall_command_status; /* [7:0] */ > + uint8_t reserved3; /* [15:8] */ > + uint16_t reserved4; /* [31:16] */ > + > + /* dword 3 */ > + uint32_t reserved5; /* [31:0] */ > + > + /* dword 4-11 */ > + uint8_t request_upiu[UFSHCI_UTP_TASK_MGMT_REQ_SIZE]; > + > + /* dword 12-19 */ > + uint8_t response_upiu[UFSHCI_UTP_TASK_MGMT_RESP_SIZE]; > + > +} __packed __aligned(8); > + > +_Static_assert(sizeof(struct ufshci_utp_task_mgmt_req_desc) == 80, > + "ufshci_utp_task_mgmt_req_desc must be 80 bytes"); > + > +/* UFS spec 4.1, section 10.6.2 "Basic Header Format" */ > +struct ufshci_upiu_header { > + /* dword 0 */ > + union { > + struct { > + uint8_t trans_code : 6; /* [5:0] */ > + uint8_t dd : 1; /* [6] */ > + uint8_t hd : 1; /* [7] */ > + }; > + uint8_t trans_type; > + }; > + union { > + struct { > + uint8_t task_attribute : 2; /* [1:0] */ > + uint8_t cp : 1; /* [2] */ > + uint8_t retransmit_indicator : 1; /* [3] */ > +#define UFSHCI_OPERATIONAL_FLAG_W 0x2 > +#define UFSHCI_OPERATIONAL_FLAG_R 0x4 > + uint8_t operational_flags : 4; /* [7:4] */ > + }; > + uint8_t flags; > + }; > + uint8_t lun; > + uint8_t task_tag; > + > + /* dword 1 */ > +#define UFSHCI_COMMAND_SET_TYPE_SCSI 0 > + uint8_t cmd_set_type : 4; /* [3:0] */ > + uint8_t iid : 4; /* [7:4] */ > + uint8_t ext_iid_or_function; > + uint8_t response; > + uint8_t ext_iid_or_status; > + > + /* dword 2 */ > + uint8_t ehs_length; > + uint8_t device_infomation; > + uint16_t data_segment_length; /* (Big-endian) */ > +} __packed __aligned(4); > + > +_Static_assert(sizeof(struct ufshci_upiu_header) == 12, > + "ufshci_upiu_header must be 12 bytes"); > + > +#define UFSHCI_MAX_UPIU_SIZE 512 > +#define UFSHCI_UPIU_ALIGNMENT 8 /* UPIU requires 64-bit alignment. */ > + > +struct ufshci_upiu { > + /* dword 0-2 */ > + struct ufshci_upiu_header header; > + /* dword 3-127 */ > + uint8_t > + reserved[UFSHCI_MAX_UPIU_SIZE - sizeof(struct ufshci_upiu_header)]; > +} __packed __aligned(8); > + > +_Static_assert(sizeof(struct ufshci_upiu) == 512, > + "ufshci_upiu must be 512 bytes"); > + > +struct ufshci_cmd_command_upiu { > + /* dword 0-2 */ > + struct ufshci_upiu_header header; > + /* dword 3 */ > + uint32_t expected_data_transfer_length; /* (Big-endian) */ > + > + /* dword 4-7 */ > + uint8_t cdb[16]; > + > +} __packed __aligned(4); > + > +_Static_assert(sizeof(struct ufshci_cmd_command_upiu) == 32, > + "bad size for ufshci_cmd_command_upiu"); > +_Static_assert(sizeof(struct ufshci_cmd_command_upiu) <= > + UFSHCI_UTP_XFER_REQ_SIZE, > + "bad size for ufshci_cmd_command_upiu"); > +_Static_assert(sizeof(struct ufshci_cmd_command_upiu) % > UFSHCI_UPIU_ALIGNMENT == > + 0, > + "UPIU requires 64-bit alignment"); > + > +struct ufshci_cmd_response_upiu { > + /* dword 0-2 */ > + struct ufshci_upiu_header header; > + /* dword 3 */ > + uint32_t residual_transfer_count; /* (Big-endian) */ > + > + /* dword 4-7 */ > + uint8_t reserved[16]; > + > + /* Sense Data */ > + uint16_t sense_data_len; /* (Big-endian) */ > + uint8_t sense_data[18]; > + > + /* Add padding to align the kUpiuAlignment. */ > + uint8_t padding[4]; > +} __packed __aligned(4); > + > +_Static_assert(sizeof(struct ufshci_cmd_response_upiu) == 56, > + "bad size for ufshci_cmd_response_upiu"); > +_Static_assert(sizeof(struct ufshci_cmd_response_upiu) <= > + UFSHCI_UTP_XFER_RESP_SIZE, > + "bad size for ufshci_cmd_response_upiu"); > +_Static_assert(sizeof(struct ufshci_cmd_response_upiu) % > + UFSHCI_UPIU_ALIGNMENT == > + 0, > + "UPIU requires 64-bit alignment"); > + > +/* UFS Spec 4.1, section 10.7.8 "QUERY REQUEST UPIU" */ > +enum ufshci_query_function { > + UFSHCI_QUERY_FUNC_STANDARD_READ_REQUEST = 0x01, > + UFSHCI_QUERY_FUNC_STANDARD_WRITE_REQUEST = 0x81, > +}; > + > +enum ufshci_query_opcode { > + UFSHCI_QUERY_OPCODE_NOP = 0, > + UFSHCI_QUERY_OPCODE_READ_DESCRIPTOR, > + UFSHCI_QUERY_OPCODE_WRITE_DESCRIPTOR, > + UFSHCI_QUERY_OPCODE_READ_ATTRIBUTE, > + UFSHCI_QUERY_OPCODE_WRITE_ATTRIBUTE, > + UFSHCI_QUERY_OPCODE_READ_FLAG, > + UFSHCI_QUERY_OPCODE_SET_FLAG, > + UFSHCI_QUERY_OPCODE_CLEAR_FLAG, > + UFSHCI_QUERY_OPCODE_TOGGLE_FLAG, > +}; > + > +struct ufshci_query_param { > + enum ufshci_query_function function; > + enum ufshci_query_opcode opcode; > + uint8_t type; > + uint8_t index; > + uint8_t selector; > + uint64_t value; > + size_t desc_size; > +}; > + > +struct ufshci_query_request_upiu { > + /* dword 0-2 */ > + struct ufshci_upiu_header header; > + /* dword 3 */ > + uint8_t opcode; > + uint8_t idn; > + uint8_t index; > + uint8_t selector; > + > + /* dword 4-5 */ > + union { > + /* The Write Attribute opcode uses 64 - bit value. */ > + uint64_t value_64; /* (Big-endian) */ > + struct { > + uint8_t reserved1[2]; > + uint16_t length; /* (Big-endian) */ > + uint32_t value_32; /* (Big-endian) */ > + }; > + } __packed __aligned(4); > + > + /* dword 6 */ > + uint32_t reserved2; > + > + /* dword 7 */ > + uint32_t reserved3; > + > + uint8_t command_data[256]; > +} __packed __aligned(4); > + > +_Static_assert(sizeof(struct ufshci_query_request_upiu) == 288, > + "bad size for ufshci_query_request_upiu"); > +_Static_assert(sizeof(struct ufshci_query_request_upiu) <= > + UFSHCI_UTP_XFER_REQ_SIZE, > + "bad size for ufshci_query_request_upiu"); > +_Static_assert(sizeof(struct ufshci_query_request_upiu) % > + UFSHCI_UPIU_ALIGNMENT == > + 0, > + "UPIU requires 64-bit alignment"); > + > +/* UFS Spec 4.1, section 10.7.9 "QUERY RESPONSE UPIU" */ > +enum ufshci_query_response_code { > + UFSHCI_QUERY_RESP_CODE_SUCCESS = 0x00, > + UFSHCI_QUERY_RESP_CODE_PARAMETER_NOT_READABLE = 0xf6, > + UFSHCI_QUERY_RESP_CODE_PARAMETER_NOT_WRITEABLE = 0xf7, > + UFSHCI_QUERY_RESP_CODE_PARAMETER_ALREADY_WRITTEN = 0xf8, > + UFSHCI_QUERY_RESP_CODE_INVALID_LENGTH = 0xf9, > + UFSHCI_QUERY_RESP_CODE_INVALID_VALUE = 0xfa, > + UFSHCI_QUERY_RESP_CODE_INVALID_SELECTOR = 0xfb, > + UFSHCI_QUERY_RESP_CODE_INVALID_INDEX = 0xfc, > + UFSHCI_QUERY_RESP_CODE_INVALID_IDN = 0xfd, > + UFSHCI_QUERY_RESP_CODE_INVALID_OPCODE = 0xfe, > + UFSHCI_QUERY_RESP_CODE_GENERAL_FAILURE = 0xff, > +}; > + > +struct ufshci_query_response_upiu { > + /* dword 0-2 */ > + struct ufshci_upiu_header header; > + /* dword 3 */ > + uint8_t opcode; > + uint8_t idn; > + uint8_t index; > + uint8_t selector; > + > + /* dword 4-5 */ > + union { > + /* The Read / Write Attribute opcodes use 64 - bit value. */ > + uint64_t value_64; /* (Big-endian) */ > + struct { > + uint8_t reserved1[2]; > + uint16_t length; /* (Big-endian) */ > + union { > + uint32_t value_32; /* (Big-endian) */ > + struct { > + uint8_t reserved2[3]; > + uint8_t flag_value; > + }; > + }; > + }; > + } __packed __aligned(4); > + > + /* dword 6 */ > + uint8_t reserved3[4]; > + > + /* dword 7 */ > + uint8_t reserved4[4]; > + > + uint8_t command_data[256]; > +} __packed __aligned(4); > + > +_Static_assert(sizeof(struct ufshci_query_response_upiu) == 288, > + "bad size for ufshci_query_response_upiu"); > +_Static_assert(sizeof(struct ufshci_query_response_upiu) <= > + UFSHCI_UTP_XFER_RESP_SIZE, > + "bad size for ufshci_query_response_upiu"); > +_Static_assert(sizeof(struct ufshci_query_response_upiu) % > + UFSHCI_UPIU_ALIGNMENT == > + 0, > + "UPIU requires 64-bit alignment"); > + > +/* UFS 4.1, section 10.7.11 "NOP OUT UPIU" */ > +struct ufshci_nop_out_upiu { > + /* dword 0-2 */ > + struct ufshci_upiu_header header; > + /* dword 3-7 */ > + uint8_t reserved[20]; > +} __packed __aligned(8); > +_Static_assert(sizeof(struct ufshci_nop_out_upiu) == 32, > + "ufshci_upiu_nop_out must be 32 bytes"); > + > +/* UFS 4.1, section 10.7.12 "NOP IN UPIU" */ > +struct ufshci_nop_in_upiu { > + /* dword 0-2 */ > + struct ufshci_upiu_header header; > + /* dword 3-7 */ > + uint8_t reserved[20]; > +} __packed __aligned(8); > +_Static_assert(sizeof(struct ufshci_nop_in_upiu) == 32, > + "ufshci_upiu_nop_in must be 32 bytes"); > + > +union ufshci_reponse_upiu { > + struct ufshci_upiu_header header; > + struct ufshci_cmd_response_upiu cmd_response_upiu; > + struct ufshci_query_response_upiu query_response_upiu; > + struct ufshci_nop_in_upiu nop_in_upiu; > +}; > + > +struct ufshci_completion { > + union ufshci_reponse_upiu response_upiu; > + size_t size; > +}; > + > +typedef void (*ufshci_cb_fn_t)(void *, const struct ufshci_completion *, > bool); > + > +/* > + * UFS Spec 4.1, section 14.1 "UFS Descriptors" > + * All descriptors use big-endian byte ordering. > + */ > +enum ufshci_descriptor_type { > + UFSHCI_DESC_TYPE_DEVICE = 0x00, > + UFSHCI_DESC_TYPE_CONFIGURATION = 0x01, > + UFSHCI_DESC_TYPE_UNIT = 0x02, > + UFSHCI_DESC_TYPE_INTERCONNECT = 0x04, > + UFSHCI_DESC_TYPE_STRING = 0x05, > + UFSHCI_DESC_TYPE_GEOMETRY = 0X07, > + UFSHCI_DESC_TYPE_POWER = 0x08, > + UFSHCI_DESC_TYPE_DEVICE_HEALTH = 0x09, > + UFSHCI_DESC_TYPE_FBO_EXTENSION_SPECIFICATION = 0x0a, > +}; > + > +/* > + * UFS Spec 4.1, section 14.1.5.2 "Device Descriptor" > + * DeviceDescriptor use big-endian byte ordering. > + */ > +struct ufshci_device_descriptor { > + uint8_t bLength; > + uint8_t bDescriptorIDN; > + uint8_t bDevice; > + uint8_t bDeviceClass; > + uint8_t bDeviceSubClass; > + uint8_t bProtocol; > + uint8_t bNumberLU; > + uint8_t bNumberWLU; > + uint8_t bBootEnable; > + uint8_t bDescrAccessEn; > + uint8_t bInitPowerMode; > + uint8_t bHighPriorityLUN; > + uint8_t bSecureRemovalType; > + uint8_t bSecurityLU; > + uint8_t bBackgroundOpsTermLat; > + uint8_t bInitActiveICCLevel; > + /* 0x10 */ > + uint16_t wSpecVersion; > + uint16_t wManufactureDate; > + uint8_t iManufacturerName; > + uint8_t iProductName; > + uint8_t iSerialNumber; > + uint8_t iOemID; > + uint16_t wManufacturerID; > + uint8_t bUD0BaseOffset; > + uint8_t bUDConfigPLength; > + uint8_t bDeviceRTTCap; > + uint16_t wPeriodicRTCUpdate; > + uint8_t bUfsFeaturesSupport; > + /* 0x20 */ > + uint8_t bFFUTimeout; > + uint8_t bQueueDepth; > + uint16_t wDeviceVersion; > + uint8_t bNumSecureWPArea; > + uint32_t dPSAMaxDataSize; > + uint8_t bPSAStateTimeout; > + uint8_t iProductRevisionLevel; > + uint8_t Reserved[5]; > + /* 0x2a */ > + /* 0x30 */ > + uint8_t ReservedUME[16]; > + /* 0x40 */ > + uint8_t ReservedHpb[3]; > + uint8_t Reserved2[12]; > + uint32_t dExtendedUfsFeaturesSupport; > + uint8_t bWriteBoosterBufferPreserveUserSpaceEn; > + uint8_t bWriteBoosterBufferType; > + uint32_t dNumSharedWriteBoosterBufferAllocUnits; > +} __packed; > + > +_Static_assert(sizeof(struct ufshci_device_descriptor) == 89, > + "bad size for ufshci_device_descriptor"); > + > +/* > + * UFS Spec 4.1, section 14.1.5.3 "Configuration Descriptor" > + * ConfigurationDescriptor use big-endian byte ordering. > + */ > +struct ufshci_unit_descriptor_configurable_parameters { > + uint8_t bLUEnable; > + uint8_t bBootLunID; > + uint8_t bLUWriteProtect; > + uint8_t bMemoryType; > + uint32_t dNumAllocUnits; > + uint8_t bDataReliability; > + uint8_t bLogicalBlockSize; > + uint8_t bProvisioningType; > + uint16_t wContextCapabilities; > + union { > + struct { > + uint8_t Reserved[3]; > + uint8_t ReservedHpb[6]; > + } __packed; > + uint16_t wZoneBufferAllocUnits; > + }; > + uint32_t dLUNumWriteBoosterBufferAllocUnits; > +} __packed; > + > +_Static_assert(sizeof(struct ufshci_unit_descriptor_configurable_parameters) > == > + 27, > + "bad size for ufshci_unit_descriptor_configurable_parameters"); > + > +#define UFSHCI_CONFIGURATION_DESCEIPTOR_LU_NUM 8 > + > +struct ufshci_configuration_descriptor { > + uint8_t bLength; > + uint8_t bDescriptorIDN; > + uint8_t bConfDescContinue; > + uint8_t bBootEnable; > + uint8_t bDescrAccessEn; > + uint8_t bInitPowerMode; > + uint8_t bHighPriorityLUN; > + uint8_t bSecureRemovalType; > + uint8_t bInitActiveICCLevel; > + uint16_t wPeriodicRTCUpdate; > + uint8_t Reserved; > + uint8_t bRPMBRegionEnable; > + uint8_t bRPMBRegion1Size; > + uint8_t bRPMBRegion2Size; > + uint8_t bRPMBRegion3Size; > + uint8_t bWriteBoosterBufferPreserveUserSpaceEn; > + uint8_t bWriteBoosterBufferType; > + uint32_t dNumSharedWriteBoosterBufferAllocUnits; > + /* 0x16 */ > + struct ufshci_unit_descriptor_configurable_parameters > + unit_config_params[UFSHCI_CONFIGURATION_DESCEIPTOR_LU_NUM]; > +} __packed; > + > +_Static_assert(sizeof(struct ufshci_configuration_descriptor) == (22 + 27 * > 8), > + "bad size for ufshci_configuration_descriptor"); > + > +/* > + * UFS Spec 4.1, section 14.1.5.4 "Geometry Descriptor" > + * GeometryDescriptor use big-endian byte ordering. > + */ > +struct ufshci_geometry_descriptor { > + uint8_t bLength; > + uint8_t bDescriptorIDN; > + uint8_t bMediaTechnology; > + uint8_t Reserved; > + uint64_t qTotalRawDeviceCapacity; > + uint8_t bMaxNumberLU; > + uint32_t dSegmentSize; > + /* 0x11 */ > + uint8_t bAllocationUnitSize; > + uint8_t bMinAddrBlockSize; > + uint8_t bOptimalReadBlockSize; > + uint8_t bOptimalWriteBlockSize; > + uint8_t bMaxInBufferSize; > + uint8_t bMaxOutBufferSize; > + uint8_t bRPMB_ReadWriteSize; > + uint8_t bDynamicCapacityResourcePolicy; > + uint8_t bDataOrdering; > + uint8_t bMaxContexIDNumber; > + uint8_t bSysDataTagUnitSize; > + uint8_t bSysDataTagResSize; > + uint8_t bSupportedSecRTypes; > + uint16_t wSupportedMemoryTypes; > + /* 0x20 */ > + uint32_t dSystemCodeMaxNAllocU; > + uint16_t wSystemCodeCapAdjFac; > + uint32_t dNonPersistMaxNAllocU; > + uint16_t wNonPersistCapAdjFac; > + uint32_t dEnhanced1MaxNAllocU; > + /* 0x30 */ > + uint16_t wEnhanced1CapAdjFac; > *** 4268 LINES SKIPPED *** > -- A FreeBSD user
pgpUI9nYTtdtL.pgp
Description: OpenPGP digital signature