xref: /freebsd/sys/dev/ufshci/ufshci_sim.c (revision 6b841d70960a3a0ec4e43392683053878c403f9c)
1 /*-
2  * Copyright (c) 2025, Samsung Electronics Co., Ltd.
3  * Written by Jaeyoon Choi
4  *
5  * SPDX-License-Identifier: BSD-2-Clause
6  */
7 
8 #include <sys/param.h>
9 
10 #include <cam/cam.h>
11 #include <cam/cam_ccb.h>
12 #include <cam/cam_debug.h>
13 #include <cam/cam_sim.h>
14 #include <cam/cam_xpt_sim.h>
15 #include <cam/scsi/scsi_all.h>
16 
17 #include "ufshci_private.h"
18 
19 #define sim2ctrlr(sim) ((struct ufshci_controller *)cam_sim_softc(sim))
20 
21 static void
ufshci_sim_scsiio_done(void * ccb_arg,const struct ufshci_completion * cpl,bool error)22 ufshci_sim_scsiio_done(void *ccb_arg, const struct ufshci_completion *cpl,
23     bool error)
24 {
25 	const uint8_t *sense_data;
26 	uint16_t sense_data_max_size;
27 	uint16_t sense_data_len;
28 
29 	union ccb *ccb = (union ccb *)ccb_arg;
30 
31 	/*
32 	 * Let the periph know the completion, and let it sort out what
33 	 * it means. Report an error or success based on OCS and UPIU
34 	 * response code. And We need to copy the sense data to be handled
35 	 * by the CAM.
36 	 */
37 	sense_data = cpl->response_upiu.cmd_response_upiu.sense_data;
38 	sense_data_max_size = sizeof(
39 	    cpl->response_upiu.cmd_response_upiu.sense_data);
40 	sense_data_len = be16toh(
41 	    cpl->response_upiu.cmd_response_upiu.sense_data_len);
42 	memcpy(&ccb->csio.sense_data, sense_data,
43 	    min(sense_data_len, sense_data_max_size));
44 
45 	ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
46 	if (error) {
47 		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
48 		xpt_done(ccb);
49 	} else {
50 		ccb->ccb_h.status = CAM_REQ_CMP;
51 		xpt_done_direct(ccb);
52 	}
53 }
54 
55 /*
56  * Complete the command as an illegal command with invalid field
57  */
58 static void
ufshci_sim_illegal_request(union ccb * ccb)59 ufshci_sim_illegal_request(union ccb *ccb)
60 {
61 	scsi_set_sense_data(&ccb->csio.sense_data,
62 	    /*sense_format*/ SSD_TYPE_NONE,
63 	    /*current_error*/ 1,
64 	    /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST,
65 	    /*asc*/ 0x24, /* 24h/00h INVALID FIELD IN CDB */
66 	    /*ascq*/ 0x00,
67 	    /*extra args*/ SSD_ELEM_NONE);
68 	ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
69 	ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID |
70 	    CAM_DEV_QFRZN;
71 	xpt_freeze_devq(ccb->ccb_h.path, 1);
72 	xpt_done(ccb);
73 }
74 
75 static void
ufshchi_sim_scsiio(struct cam_sim * sim,union ccb * ccb)76 ufshchi_sim_scsiio(struct cam_sim *sim, union ccb *ccb)
77 {
78 	struct ccb_scsiio *csio = &ccb->csio;
79 	struct ufshci_request *req;
80 	void *payload;
81 	struct ufshci_cmd_command_upiu *upiu;
82 	uint8_t *cdb;
83 	uint32_t payload_len;
84 	bool is_write;
85 	struct ufshci_controller *ctrlr;
86 	uint8_t data_direction;
87 	int error;
88 
89 	/* UFS device cannot process these commands */
90 	if (csio->cdb_io.cdb_bytes[0] == MODE_SENSE_6 ||
91 	    csio->cdb_io.cdb_bytes[0] == MODE_SELECT_6 ||
92 	    csio->cdb_io.cdb_bytes[0] == READ_12 ||
93 	    csio->cdb_io.cdb_bytes[0] == WRITE_12) {
94 		ufshci_sim_illegal_request(ccb);
95 		return;
96 	}
97 
98 	ctrlr = sim2ctrlr(sim);
99 	payload = csio->data_ptr;
100 
101 	payload_len = csio->dxfer_len;
102 	is_write = csio->ccb_h.flags & CAM_DIR_OUT;
103 
104 	/* TODO: Check other data type */
105 	if ((csio->ccb_h.flags & CAM_DATA_MASK) == CAM_DATA_BIO)
106 		req = ufshci_allocate_request_bio((struct bio *)payload,
107 		    M_NOWAIT, ufshci_sim_scsiio_done, ccb);
108 	else
109 		req = ufshci_allocate_request_vaddr(payload, payload_len,
110 		    M_NOWAIT, ufshci_sim_scsiio_done, ccb);
111 
112 	req->request_size = sizeof(struct ufshci_cmd_command_upiu);
113 	req->response_size = sizeof(struct ufshci_cmd_response_upiu);
114 
115 	switch (ccb->ccb_h.flags & CAM_DIR_MASK) {
116 	case CAM_DIR_IN:
117 		data_direction = UFSHCI_DATA_DIRECTION_FROM_TGT_TO_SYS;
118 		break;
119 	case CAM_DIR_OUT:
120 		data_direction = UFSHCI_DATA_DIRECTION_FROM_SYS_TO_TGT;
121 		break;
122 	default:
123 		data_direction = UFSHCI_DATA_DIRECTION_NO_DATA_TRANSFER;
124 	}
125 	req->data_direction = data_direction;
126 
127 	upiu = (struct ufshci_cmd_command_upiu *)&req->request_upiu;
128 	memset(upiu, 0, req->request_size);
129 	upiu->header.trans_type = UFSHCI_UPIU_TRANSACTION_CODE_COMMAND;
130 	upiu->header.operational_flags = is_write ? UFSHCI_OPERATIONAL_FLAG_W :
131 						    UFSHCI_OPERATIONAL_FLAG_R;
132 	upiu->header.lun = csio->ccb_h.target_lun;
133 	upiu->header.cmd_set_type = UFSHCI_COMMAND_SET_TYPE_SCSI;
134 
135 	upiu->expected_data_transfer_length = htobe32(payload_len);
136 
137 	ccb->ccb_h.status |= CAM_SIM_QUEUED;
138 
139 	if (csio->ccb_h.flags & CAM_CDB_POINTER)
140 		cdb = csio->cdb_io.cdb_ptr;
141 	else
142 		cdb = csio->cdb_io.cdb_bytes;
143 
144 	if (cdb == NULL || csio->cdb_len > sizeof(upiu->cdb)) {
145 		ccb->ccb_h.status = CAM_REQ_INVALID;
146 		xpt_done(ccb);
147 		return;
148 	}
149 	memcpy(upiu->cdb, cdb, csio->cdb_len);
150 
151 	error = ufshci_ctrlr_submit_io_request(ctrlr, req);
152 	if (error == EBUSY) {
153 		ccb->ccb_h.status = CAM_SCSI_BUSY;
154 		xpt_done(ccb);
155 		return;
156 	} else if (error) {
157 		ccb->ccb_h.status = CAM_REQ_INVALID;
158 		xpt_done(ccb);
159 		return;
160 	}
161 }
162 
163 static uint32_t
ufshci_link_kBps(struct ufshci_controller * ctrlr)164 ufshci_link_kBps(struct ufshci_controller *ctrlr)
165 {
166 	uint32_t gear = ctrlr->hs_gear;
167 	uint32_t lanes = ctrlr->rx_lanes;
168 
169 	/*
170 	 * per-lane effective bandwidth (KB/s, SI 1 KB = 1000 B)
171 	 * All HS-Gears use 8b/10b line coding, i.e. 80 % efficiency.
172 	 * - KB/s per lane = raw-rate(Gbps) × 0.8(8b/10b) / 8(bit)
173 	 */
174 	static const uint32_t kbps_per_lane[] = {
175 		0,	 /* unused */
176 		145920,	 /* HS-Gear1 : 1459.2 Mbps */
177 		291840,	 /* HS-Gear2 : 2918.4 Mbps */
178 		583680,	 /* HS-Gear3 : 5836.8 Mbps */
179 		1167360, /* HS-Gear4 : 11673.6 Mbps */
180 		2334720	 /* HS-Gear5 : 23347.2 Mbps */
181 	};
182 
183 	/* Sanity checks */
184 	if (gear >= nitems(kbps_per_lane))
185 		gear = 0; /* out-of-range -> treat as invalid */
186 
187 	if (lanes == 0 || lanes > 2)
188 		lanes = 1; /* UFS spec allows 1–2 data lanes */
189 
190 	return kbps_per_lane[gear] * lanes;
191 }
192 
193 static void
ufshci_cam_action(struct cam_sim * sim,union ccb * ccb)194 ufshci_cam_action(struct cam_sim *sim, union ccb *ccb)
195 {
196 	struct ufshci_controller *ctrlr = sim2ctrlr(sim);
197 
198 	if (ctrlr == NULL) {
199 		ccb->ccb_h.status = CAM_SEL_TIMEOUT;
200 		xpt_done(ccb);
201 		return;
202 	}
203 
204 	/* Perform the requested action */
205 	switch (ccb->ccb_h.func_code) {
206 	case XPT_SCSI_IO:
207 		ufshchi_sim_scsiio(sim, ccb);
208 		return;
209 	case XPT_PATH_INQ: {
210 		struct ccb_pathinq *cpi = &ccb->cpi;
211 
212 		cpi->version_num = 1;
213 		cpi->hba_inquiry = PI_SDTR_ABLE | PI_TAG_ABLE;
214 		cpi->target_sprt = 0;
215 		cpi->hba_misc = PIM_UNMAPPED | PIM_NO_6_BYTE;
216 		cpi->hba_eng_cnt = 0;
217 		cpi->max_target = 0;
218 		cpi->max_lun = ctrlr->max_lun_count;
219 		cpi->async_flags = 0;
220 		cpi->maxio = ctrlr->max_xfer_size;
221 		cpi->initiator_id = 1;
222 		strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
223 		strlcpy(cpi->hba_vid, "UFSHCI", HBA_IDLEN);
224 		strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
225 		cpi->unit_number = cam_sim_unit(sim);
226 		cpi->base_transfer_speed = ufshci_link_kBps(ctrlr);
227 		cpi->transport = XPORT_UFSHCI;
228 		cpi->transport_version = 1;
229 		cpi->protocol = PROTO_SCSI;
230 		cpi->protocol_version = SCSI_REV_SPC5;
231 		ccb->ccb_h.status = CAM_REQ_CMP;
232 		break;
233 	}
234 	case XPT_RESET_BUS:
235 		ccb->ccb_h.status = CAM_REQ_CMP;
236 		break;
237 	case XPT_RESET_DEV:
238 		if (ufshci_dev_reset(ctrlr))
239 			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
240 		else
241 			ccb->ccb_h.status = CAM_REQ_CMP;
242 		break;
243 	case XPT_ABORT:
244 		ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
245 		break;
246 	case XPT_SET_TRAN_SETTINGS:
247 		ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
248 		break;
249 	case XPT_GET_TRAN_SETTINGS: {
250 		struct ccb_trans_settings *cts;
251 		struct ccb_trans_settings_ufshci *ufshcix;
252 
253 		cts = &ccb->cts;
254 		ufshcix = &cts->xport_specific.ufshci;
255 
256 		ufshcix->hs_gear = ctrlr->hs_gear;
257 		ufshcix->tx_lanes = ctrlr->tx_lanes;
258 		ufshcix->rx_lanes = ctrlr->rx_lanes;
259 		ufshcix->max_hs_gear = ctrlr->max_rx_hs_gear;
260 		ufshcix->max_tx_lanes = ctrlr->max_tx_lanes;
261 		ufshcix->max_rx_lanes = ctrlr->max_rx_lanes;
262 		ufshcix->valid = CTS_UFSHCI_VALID_LINK;
263 
264 		cts->transport = XPORT_UFSHCI;
265 		cts->transport_version = 1;
266 		cts->protocol = PROTO_SCSI;
267 		cts->protocol_version = SCSI_REV_SPC5;
268 		ccb->ccb_h.status = CAM_REQ_CMP;
269 		break;
270 	}
271 	case XPT_CALC_GEOMETRY:
272 		cam_calc_geometry(&ccb->ccg, 1);
273 		break;
274 	case XPT_NOOP:
275 		ccb->ccb_h.status = CAM_REQ_CMP;
276 		break;
277 	default:
278 		printf("invalid ccb=%p func=%#x\n", ccb, ccb->ccb_h.func_code);
279 		break;
280 	}
281 	xpt_done(ccb);
282 
283 	return;
284 }
285 
286 static void
ufshci_cam_poll(struct cam_sim * sim)287 ufshci_cam_poll(struct cam_sim *sim)
288 {
289 	struct ufshci_controller *ctrlr = sim2ctrlr(sim);
290 
291 	ufshci_ctrlr_poll(ctrlr);
292 }
293 
294 int
ufshci_sim_attach(struct ufshci_controller * ctrlr)295 ufshci_sim_attach(struct ufshci_controller *ctrlr)
296 {
297 	device_t dev;
298 	struct cam_devq *devq;
299 	int max_trans;
300 
301 	dev = ctrlr->dev;
302 	max_trans = ctrlr->max_hw_pend_io;
303 	if ((devq = cam_simq_alloc(max_trans)) == NULL) {
304 		printf("Failed to allocate a simq\n");
305 		return (ENOMEM);
306 	}
307 
308 	ctrlr->ufshci_sim = cam_sim_alloc(ufshci_cam_action, ufshci_cam_poll,
309 	    "ufshci", ctrlr, device_get_unit(dev), &ctrlr->sc_mtx, max_trans,
310 	    max_trans, devq);
311 	if (ctrlr->ufshci_sim == NULL) {
312 		printf("Failed to allocate a sim\n");
313 		cam_simq_free(devq);
314 		return (ENOMEM);
315 	}
316 
317 	mtx_lock(&ctrlr->sc_mtx);
318 	if (xpt_bus_register(ctrlr->ufshci_sim, ctrlr->dev, 0) != CAM_SUCCESS) {
319 		cam_sim_free(ctrlr->ufshci_sim, /*free_devq*/ TRUE);
320 		cam_simq_free(devq);
321 		mtx_unlock(&ctrlr->sc_mtx);
322 		printf("Failed to create a bus\n");
323 		return (ENOMEM);
324 	}
325 
326 	if (xpt_create_path(&ctrlr->ufshci_path, /*periph*/ NULL,
327 		cam_sim_path(ctrlr->ufshci_sim), CAM_TARGET_WILDCARD,
328 		CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
329 		xpt_bus_deregister(cam_sim_path(ctrlr->ufshci_sim));
330 		cam_sim_free(ctrlr->ufshci_sim, /*free_devq*/ TRUE);
331 		cam_simq_free(devq);
332 		mtx_unlock(&ctrlr->sc_mtx);
333 		printf("Failed to create a path\n");
334 		return (ENOMEM);
335 	}
336 	mtx_unlock(&ctrlr->sc_mtx);
337 
338 	return (0);
339 }
340 
341 void
ufshci_sim_detach(struct ufshci_controller * ctrlr)342 ufshci_sim_detach(struct ufshci_controller *ctrlr)
343 {
344 	int error;
345 
346 	if (ctrlr->ufshci_path != NULL) {
347 		xpt_free_path(ctrlr->ufshci_path);
348 		ctrlr->ufshci_path = NULL;
349 	}
350 
351 	if (ctrlr->ufshci_sim != NULL) {
352 		error = xpt_bus_deregister(cam_sim_path(ctrlr->ufshci_sim));
353 		if (error == 0) {
354 			/* accessing the softc is not possible after this */
355 			ctrlr->ufshci_sim->softc = NULL;
356 			ufshci_printf(ctrlr,
357 			    "%s: %s:%d:%d caling "
358 			    "cam_sim_free sim %p refc %u mtx %p\n",
359 			    __func__, ctrlr->sc_name,
360 			    cam_sim_path(ctrlr->ufshci_sim), ctrlr->sc_unit,
361 			    ctrlr->ufshci_sim, ctrlr->ufshci_sim->refcount,
362 			    ctrlr->ufshci_sim->mtx);
363 		} else {
364 			panic("%s: %s: CAM layer is busy: errno %d\n", __func__,
365 			    ctrlr->sc_name, error);
366 		}
367 
368 		cam_sim_free(ctrlr->ufshci_sim, /* free_devq */ TRUE);
369 		ctrlr->ufshci_sim = NULL;
370 	}
371 }
372