ufshci: add a control device node

The driver only exposed a CAM SIM. Userland had no way to reach the
device for anything that is not a SCSI command, so reading a descriptor
or an attribute was impossible.

Add /dev/ufshci%d as a root only node and the ioctl ABI header for it.
The node answers no ioctl yet. The header pulls in ufshci.h, which
declares bool only under _KERNEL, so include stdbool.h for userland the
way nvme.h already does.

Reviewed by:	imp (mentor)
Sponsored by:	Samsung Electronics
Differential Revision:	https://reviews.freebsd.org/D59558
This commit is contained in:
Jaeyoon Choi committed 2026-09-15 01:44:33 +00:00
1 parent d3e5082ce4
commit 28fefc441e
6 files changed
+137

No files matched your search

+3
View File
@@ -9,6 +9,9 @@
#define __UFSHCI_H__
#include <sys/param.h>
#ifndef _KERNEL
#include <stdbool.h>
#endif
#include <sys/endian.h>
/*
+6
View File
@@ -459,12 +459,18 @@ ufshci_ctrlr_construct(struct ufshci_controller *ctrlr, device_t dev)
TASK_INIT(&ctrlr->reset_task, 0, ufshci_ctrlr_reset_task, ctrlr);
error = ufshci_ioctl_construct(ctrlr, dev);
if (error)
return (error);
return (0);
}
void
ufshci_ctrlr_destruct(struct ufshci_controller *ctrlr, device_t dev)
{
ufshci_ioctl_destruct(ctrlr);
if (ctrlr->resource == NULL)
goto nores;
+67
View File
@@ -0,0 +1,67 @@
/*-
* Copyright (c) 2026, Samsung Electronics Co., Ltd.
* Written by Jaeyoon Choi
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <sys/param.h>
#include <sys/conf.h>
#include <sys/ioccom.h>
#include "ufshci_private.h"
#include "ufshci_ioctl.h"
static d_ioctl_t ufshci_ioctl;
static struct cdevsw ufshci_cdevsw = {
.d_version = D_VERSION,
.d_ioctl = ufshci_ioctl,
.d_name = "ufshci",
};
static int
ufshci_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int flag,
struct thread *td)
{
switch (cmd) {
default:
return (ENOTTY);
}
}
int
ufshci_ioctl_construct(struct ufshci_controller *ctrlr, device_t dev)
{
struct make_dev_args md_args;
int error;
/*
* Set si_drv1 as the node is created. A separate assignment after
* make_dev leaves a window where an open that races the attach finds
* it unset.
*/
make_dev_args_init(&md_args);
md_args.mda_devsw = &ufshci_cdevsw;
md_args.mda_uid = UID_ROOT;
md_args.mda_gid = GID_WHEEL;
md_args.mda_mode = 0600;
md_args.mda_unit = device_get_unit(dev);
md_args.mda_si_drv1 = ctrlr;
error = make_dev_s(&md_args, &ctrlr->cdev, "ufshci%d",
device_get_unit(dev));
if (error != 0)
return (error);
return (0);
}
void
ufshci_ioctl_destruct(struct ufshci_controller *ctrlr)
{
if (ctrlr->cdev != NULL) {
destroy_dev(ctrlr->cdev);
ctrlr->cdev = NULL;
}
}
+54
View File
@@ -0,0 +1,54 @@
/*-
* Copyright (c) 2026, Samsung Electronics Co., Ltd.
* Written by Jaeyoon Choi
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#ifndef __UFSHCI_IOCTL_H__
#define __UFSHCI_IOCTL_H__
#include <sys/ioccom.h>
#include <dev/ufshci/ufshci.h>
#define UFSHCI_PT_FLAG_DATA_IN 0x01 /* device -> host */
#define UFSHCI_PT_FLAG_DATA_OUT 0x02 /* host -> device */
/*
* Largest data buffer a single passthrough request may carry. A transfer
* this long covers 256 pages of 4096 bytes, and one more when the buffer
* does not start on a page boundary, which is what the PRDT holds.
*/
#define UFSHCI_PT_MAX_XFER (1024 * 1024)
/*
* req_upiu and resp_upiu carry the UPIU whole, including its EHS and its
* data segment. A query request keeps its descriptor bytes in that data
* segment, so such a request leaves buf NULL and len zero.
*
* buf is the separate buffer a command UPIU moves through the PRDT. Only
* a command UPIU uses it.
*/
struct ufshci_pt_command {
struct ufshci_upiu req_upiu; /* [in] */
struct ufshci_upiu resp_upiu; /* [out] */
void *buf; /* [in] PRDT payload, may be NULL */
uint32_t len; /* [in] length of buf */
uint32_t flags; /* [in] UFSHCI_PT_FLAG_* */
uint32_t timeout_ms; /* [in] 0 means the driver default */
uint32_t xfer_len; /* [out] bytes actually moved */
uint8_t ocs; /* [out] overall command status */
uint8_t reserved[7];
};
struct ufshci_pt_uic_command {
struct ufshci_uic_cmd cmd; /* [in/out] opcode and argument1..3 */
uint32_t timeout_ms; /* [in] */
uint32_t result; /* [out] UICCMDARG2 result code */
};
#define UFSHCI_PASSTHROUGH_CMD _IOWR('u', 0, struct ufshci_pt_command)
#define UFSHCI_PASSTHROUGH_UIC _IOWR('u', 1, struct ufshci_pt_uic_command)
#endif /* __UFSHCI_IOCTL_H__ */
+6
View File
@@ -302,6 +302,7 @@ struct ufshci_device {
*/
struct ufshci_controller {
device_t dev;
struct cdev *cdev;
uint32_t quirks;
#define UFSHCI_QUIRK_IGNORE_UIC_POWER_MODE \
@@ -457,6 +458,11 @@ void ufshci_ctrlr_poll(struct ufshci_controller *ctrlr);
int ufshci_ctrlr_submit_task_mgmt_request(struct ufshci_controller *ctrlr,
struct ufshci_request *req);
/* ioctl */
int ufshci_ioctl_construct(struct ufshci_controller *ctrlr,
device_t dev);
void ufshci_ioctl_destruct(struct ufshci_controller *ctrlr);
int ufshci_ctrlr_submit_transfer_request(struct ufshci_controller *ctrlr,
struct ufshci_request *req);
int ufshci_ctrlr_send_nop(struct ufshci_controller *ctrlr);
+1
View File
@@ -12,6 +12,7 @@ SRCS = ufshci.c \
ufshci_req_queue.c \
ufshci_req_sdb.c \
ufshci_sim.c \
ufshci_ioctl.c \
ufshci_sysctl.c \
acpi_if.h \
bus_if.h \