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

Attachment: pgpUI9nYTtdtL.pgp
Description: OpenPGP digital signature

Reply via email to