xref: /freebsd/sys/dev/ufshci/ufshci_sim.c (revision 31407551c3d4d29905f77abddac3fd9b649e166b)
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_periph.h>
14 #include <cam/cam_sim.h>
15 #include <cam/cam_xpt_sim.h>
16 #include <cam/scsi/scsi_all.h>
17 #include <cam/scsi/scsi_message.h>
18 
19 #include "ufshci_private.h"
20 
21 #define sim2ctrlr(sim) ((struct ufshci_controller *)cam_sim_softc(sim))
22 
23 static void
ufshci_sim_scsiio_done(void * ccb_arg,const struct ufshci_completion * cpl,bool error)24 ufshci_sim_scsiio_done(void *ccb_arg, const struct ufshci_completion *cpl,
25     bool error)
26 {
27 	const uint8_t *sense_data;
28 	uint16_t sense_data_max_size;
29 	uint16_t sense_data_len;
30 
31 	union ccb *ccb = (union ccb *)ccb_arg;
32 
33 	/*
34 	 * Let the periph know the completion, and let it sort out what
35 	 * it means. Report an error or success based on OCS and UPIU
36 	 * response code. And We need to copy the sense data to be handled
37 	 * by the CAM.
38 	 */
39 	sense_data = cpl->response_upiu.cmd_response_upiu.sense_data;
40 	sense_data_max_size = sizeof(
41 	    cpl->response_upiu.cmd_response_upiu.sense_data);
42 	sense_data_len = be16toh(
43 	    cpl->response_upiu.cmd_response_upiu.sense_data_len);
44 	memcpy(&ccb->csio.sense_data, sense_data,
45 	    min(sense_data_len, sense_data_max_size));
46 
47 	ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
48 	if (error) {
49 		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
50 		xpt_done(ccb);
51 	} else {
52 		ccb->ccb_h.status = CAM_REQ_CMP;
53 		xpt_done_direct(ccb);
54 	}
55 }
56 
57 /*
58  * Complete the command as an illegal command with invalid field
59  */
60 static void
ufshci_sim_illegal_request(union ccb * ccb)61 ufshci_sim_illegal_request(union ccb *ccb)
62 {
63 	scsi_set_sense_data(&ccb->csio.sense_data,
64 	    /*sense_format*/ SSD_TYPE_NONE,
65 	    /*current_error*/ 1,
66 	    /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST,
67 	    /*asc*/ 0x24, /* 24h/00h INVALID FIELD IN CDB */
68 	    /*ascq*/ 0x00,
69 	    /*extra args*/ SSD_ELEM_NONE);
70 	ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
71 	ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID |
72 	    CAM_DEV_QFRZN;
73 	xpt_freeze_devq(ccb->ccb_h.path, 1);
74 	xpt_done(ccb);
75 }
76 
77 /*
78  * The SCSI LUN format and the UFS UPIU LUN format are different.
79  * This function converts the SCSI LUN format to the UFS UPIU LUN format.
80  */
81 uint8_t
ufshci_sim_translate_scsi_to_ufs_lun(lun_id_t scsi_lun)82 ufshci_sim_translate_scsi_to_ufs_lun(lun_id_t scsi_lun)
83 {
84 	const int address_format_offset = 8;
85 	uint8_t address_format = scsi_lun >> address_format_offset;
86 
87 	/* Well known logical unit */
88 	if (((address_format & RPL_LUNDATA_ATYP_MASK) ==
89 		RPL_LUNDATA_ATYP_EXTLUN) &&
90 	    ((address_format & RPL_LUNDATA_EXT_EAM_MASK) ==
91 		RPL_LUNDATA_EXT_EAM_WK))
92 		return ((scsi_lun & UFSHCI_UPIU_UNIT_NUMBER_ID_MASK) |
93 		    UFSHCI_UPIU_WLUN_ID_MASK);
94 
95 	/* Logical unit */
96 	return (scsi_lun & UFSHCI_UPIU_UNIT_NUMBER_ID_MASK);
97 }
98 
99 uint64_t
ufshci_sim_translate_ufs_to_scsi_lun(uint8_t ufs_lun)100 ufshci_sim_translate_ufs_to_scsi_lun(uint8_t ufs_lun)
101 {
102 	/* Logical unit */
103 	if (!(ufs_lun & UFSHCI_UPIU_WLUN_ID_MASK)) {
104 		return ufs_lun;
105 	}
106 
107 	/* Well known logical unit */
108 	return (((uint64_t)ufs_lun & ~UFSHCI_UPIU_WLUN_ID_MASK) |
109 	    (RPL_LUNDATA_ATYP_EXTLUN | RPL_LUNDATA_EXT_EAM_WK) << 8);
110 }
111 
112 static void
ufshchi_sim_scsiio(struct cam_sim * sim,union ccb * ccb)113 ufshchi_sim_scsiio(struct cam_sim *sim, union ccb *ccb)
114 {
115 	struct ccb_scsiio *csio = &ccb->csio;
116 	struct ufshci_request *req;
117 	void *payload;
118 	struct ufshci_cmd_command_upiu *upiu;
119 	uint8_t *cdb;
120 	uint32_t payload_len;
121 	bool is_write;
122 	struct ufshci_controller *ctrlr;
123 	uint8_t data_direction;
124 	int error;
125 
126 	/* UFS device cannot process these commands */
127 	if (csio->cdb_io.cdb_bytes[0] == MODE_SENSE_6 ||
128 	    csio->cdb_io.cdb_bytes[0] == MODE_SELECT_6 ||
129 	    csio->cdb_io.cdb_bytes[0] == READ_12 ||
130 	    csio->cdb_io.cdb_bytes[0] == WRITE_12) {
131 		ufshci_sim_illegal_request(ccb);
132 		return;
133 	}
134 
135 	ctrlr = sim2ctrlr(sim);
136 	payload = csio->data_ptr;
137 
138 	payload_len = csio->dxfer_len;
139 	is_write = csio->ccb_h.flags & CAM_DIR_OUT;
140 
141 	/* TODO: Check other data type */
142 	if ((csio->ccb_h.flags & CAM_DATA_MASK) == CAM_DATA_BIO)
143 		req = ufshci_allocate_request_bio((struct bio *)payload,
144 		    M_NOWAIT, ufshci_sim_scsiio_done, ccb);
145 	else
146 		req = ufshci_allocate_request_vaddr(payload, payload_len,
147 		    M_NOWAIT, ufshci_sim_scsiio_done, ccb);
148 
149 	req->request_size = sizeof(struct ufshci_cmd_command_upiu);
150 	req->response_size = sizeof(struct ufshci_cmd_response_upiu);
151 
152 	switch (ccb->ccb_h.flags & CAM_DIR_MASK) {
153 	case CAM_DIR_IN:
154 		data_direction = UFSHCI_DATA_DIRECTION_FROM_TGT_TO_SYS;
155 		break;
156 	case CAM_DIR_OUT:
157 		data_direction = UFSHCI_DATA_DIRECTION_FROM_SYS_TO_TGT;
158 		break;
159 	default:
160 		data_direction = UFSHCI_DATA_DIRECTION_NO_DATA_TRANSFER;
161 	}
162 	req->data_direction = data_direction;
163 
164 	upiu = (struct ufshci_cmd_command_upiu *)&req->request_upiu;
165 	memset(upiu, 0, req->request_size);
166 	upiu->header.trans_type = UFSHCI_UPIU_TRANSACTION_CODE_COMMAND;
167 	upiu->header.operational_flags = is_write ? UFSHCI_OPERATIONAL_FLAG_W :
168 						    UFSHCI_OPERATIONAL_FLAG_R;
169 	upiu->header.lun = ufshci_sim_translate_scsi_to_ufs_lun(
170 	    csio->ccb_h.target_lun);
171 	upiu->header.cmd_set_type = UFSHCI_COMMAND_SET_TYPE_SCSI;
172 
173 	upiu->expected_data_transfer_length = htobe32(payload_len);
174 
175 	ccb->ccb_h.status |= CAM_SIM_QUEUED;
176 
177 	if (csio->ccb_h.flags & CAM_CDB_POINTER)
178 		cdb = csio->cdb_io.cdb_ptr;
179 	else
180 		cdb = csio->cdb_io.cdb_bytes;
181 
182 	if (cdb == NULL || csio->cdb_len > sizeof(upiu->cdb)) {
183 		ccb->ccb_h.status = CAM_REQ_INVALID;
184 		xpt_done(ccb);
185 		return;
186 	}
187 	memcpy(upiu->cdb, cdb, csio->cdb_len);
188 
189 	error = ufshci_ctrlr_submit_io_request(ctrlr, req);
190 	if (error == EBUSY) {
191 		ccb->ccb_h.status = CAM_SCSI_BUSY;
192 		xpt_done(ccb);
193 		return;
194 	} else if (error) {
195 		ccb->ccb_h.status = CAM_REQ_INVALID;
196 		xpt_done(ccb);
197 		return;
198 	}
199 }
200 
201 static uint32_t
ufshci_link_kBps(struct ufshci_controller * ctrlr)202 ufshci_link_kBps(struct ufshci_controller *ctrlr)
203 {
204 	uint32_t gear = ctrlr->hs_gear;
205 	uint32_t lanes = ctrlr->rx_lanes;
206 
207 	/*
208 	 * per-lane effective bandwidth (KB/s, SI 1 KB = 1000 B)
209 	 * All HS-Gears use 8b/10b line coding, i.e. 80 % efficiency.
210 	 * - KB/s per lane = raw-rate(Gbps) × 0.8(8b/10b) / 8(bit)
211 	 */
212 	static const uint32_t kbps_per_lane[] = {
213 		0,	 /* unused */
214 		145920,	 /* HS-Gear1 : 1459.2 Mbps */
215 		291840,	 /* HS-Gear2 : 2918.4 Mbps */
216 		583680,	 /* HS-Gear3 : 5836.8 Mbps */
217 		1167360, /* HS-Gear4 : 11673.6 Mbps */
218 		2334720	 /* HS-Gear5 : 23347.2 Mbps */
219 	};
220 
221 	/* Sanity checks */
222 	if (gear >= nitems(kbps_per_lane))
223 		gear = 0; /* out-of-range -> treat as invalid */
224 
225 	if (lanes == 0 || lanes > 2)
226 		lanes = 1; /* UFS spec allows 1–2 data lanes */
227 
228 	return kbps_per_lane[gear] * lanes;
229 }
230 
231 static void
ufshci_cam_action(struct cam_sim * sim,union ccb * ccb)232 ufshci_cam_action(struct cam_sim *sim, union ccb *ccb)
233 {
234 	struct ufshci_controller *ctrlr = sim2ctrlr(sim);
235 
236 	if (ctrlr == NULL) {
237 		ccb->ccb_h.status = CAM_SEL_TIMEOUT;
238 		xpt_done(ccb);
239 		return;
240 	}
241 
242 	/* Perform the requested action */
243 	switch (ccb->ccb_h.func_code) {
244 	case XPT_SCSI_IO:
245 		ufshchi_sim_scsiio(sim, ccb);
246 		return;
247 	case XPT_PATH_INQ: {
248 		struct ccb_pathinq *cpi = &ccb->cpi;
249 		uint32_t need_scan_wluns = 0;
250 
251 		if (!(ctrlr->quirks & UFSHCI_QUIRK_SKIP_WELL_KNOWN_LUNS))
252 			need_scan_wluns = PIM_WLUNS;
253 
254 		cpi->version_num = 1;
255 		cpi->hba_inquiry = PI_SDTR_ABLE | PI_TAG_ABLE;
256 		cpi->target_sprt = 0;
257 		cpi->hba_misc = need_scan_wluns | PIM_UNMAPPED | PIM_NO_6_BYTE;
258 		cpi->hba_eng_cnt = 0;
259 		cpi->max_target = 0;
260 		cpi->max_lun = ctrlr->max_lun_count;
261 		cpi->async_flags = 0;
262 		cpi->maxio = ctrlr->max_xfer_size;
263 		cpi->initiator_id = 1;
264 		strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
265 		strlcpy(cpi->hba_vid, "UFSHCI", HBA_IDLEN);
266 		strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
267 		cpi->unit_number = cam_sim_unit(sim);
268 		cpi->base_transfer_speed = ufshci_link_kBps(ctrlr);
269 		cpi->transport = XPORT_UFSHCI;
270 		cpi->transport_version = 1;
271 		cpi->protocol = PROTO_SCSI;
272 		cpi->protocol_version = SCSI_REV_SPC5;
273 		ccb->ccb_h.status = CAM_REQ_CMP;
274 		break;
275 	}
276 	case XPT_RESET_BUS:
277 		ccb->ccb_h.status = CAM_REQ_CMP;
278 		break;
279 	case XPT_RESET_DEV:
280 		if (ufshci_dev_reset(ctrlr))
281 			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
282 		else
283 			ccb->ccb_h.status = CAM_REQ_CMP;
284 		break;
285 	case XPT_ABORT:
286 		ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
287 		break;
288 	case XPT_SET_TRAN_SETTINGS:
289 		ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
290 		break;
291 	case XPT_GET_TRAN_SETTINGS: {
292 		struct ccb_trans_settings *cts;
293 		struct ccb_trans_settings_ufshci *ufshcix;
294 
295 		cts = &ccb->cts;
296 		ufshcix = &cts->xport_specific.ufshci;
297 
298 		ufshcix->hs_gear = ctrlr->hs_gear;
299 		ufshcix->tx_lanes = ctrlr->tx_lanes;
300 		ufshcix->rx_lanes = ctrlr->rx_lanes;
301 		ufshcix->max_hs_gear = ctrlr->max_rx_hs_gear;
302 		ufshcix->max_tx_lanes = ctrlr->max_tx_lanes;
303 		ufshcix->max_rx_lanes = ctrlr->max_rx_lanes;
304 		ufshcix->valid = CTS_UFSHCI_VALID_LINK;
305 
306 		cts->transport = XPORT_UFSHCI;
307 		cts->transport_version = 1;
308 		cts->protocol = PROTO_SCSI;
309 		cts->protocol_version = SCSI_REV_SPC5;
310 		ccb->ccb_h.status = CAM_REQ_CMP;
311 		break;
312 	}
313 	case XPT_CALC_GEOMETRY:
314 		cam_calc_geometry(&ccb->ccg, 1);
315 		break;
316 	case XPT_NOOP:
317 		ccb->ccb_h.status = CAM_REQ_CMP;
318 		break;
319 	default:
320 		printf("invalid ccb=%p func=%#x\n", ccb, ccb->ccb_h.func_code);
321 		break;
322 	}
323 	xpt_done(ccb);
324 
325 	return;
326 }
327 
328 static void
ufshci_cam_poll(struct cam_sim * sim)329 ufshci_cam_poll(struct cam_sim *sim)
330 {
331 	struct ufshci_controller *ctrlr = sim2ctrlr(sim);
332 
333 	ufshci_ctrlr_poll(ctrlr);
334 }
335 
336 int
ufshci_sim_attach(struct ufshci_controller * ctrlr)337 ufshci_sim_attach(struct ufshci_controller *ctrlr)
338 {
339 	device_t dev;
340 	struct cam_devq *devq;
341 	int max_trans;
342 
343 	dev = ctrlr->dev;
344 	max_trans = ctrlr->max_hw_pend_io;
345 	if ((devq = cam_simq_alloc(max_trans)) == NULL) {
346 		printf("Failed to allocate a simq\n");
347 		return (ENOMEM);
348 	}
349 
350 	ctrlr->ufshci_sim = cam_sim_alloc(ufshci_cam_action, ufshci_cam_poll,
351 	    "ufshci", ctrlr, device_get_unit(dev), &ctrlr->sc_mtx, max_trans,
352 	    max_trans, devq);
353 	if (ctrlr->ufshci_sim == NULL) {
354 		printf("Failed to allocate a sim\n");
355 		cam_simq_free(devq);
356 		return (ENOMEM);
357 	}
358 
359 	mtx_lock(&ctrlr->sc_mtx);
360 	if (xpt_bus_register(ctrlr->ufshci_sim, ctrlr->dev, 0) != CAM_SUCCESS) {
361 		cam_sim_free(ctrlr->ufshci_sim, /*free_devq*/ TRUE);
362 		cam_simq_free(devq);
363 		mtx_unlock(&ctrlr->sc_mtx);
364 		printf("Failed to create a bus\n");
365 		return (ENOMEM);
366 	}
367 
368 	if (xpt_create_path(&ctrlr->ufshci_path, /*periph*/ NULL,
369 		cam_sim_path(ctrlr->ufshci_sim), CAM_TARGET_WILDCARD,
370 		CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
371 		xpt_bus_deregister(cam_sim_path(ctrlr->ufshci_sim));
372 		cam_sim_free(ctrlr->ufshci_sim, /*free_devq*/ TRUE);
373 		cam_simq_free(devq);
374 		mtx_unlock(&ctrlr->sc_mtx);
375 		printf("Failed to create a path\n");
376 		return (ENOMEM);
377 	}
378 	mtx_unlock(&ctrlr->sc_mtx);
379 
380 	return (0);
381 }
382 
383 void
ufshci_sim_detach(struct ufshci_controller * ctrlr)384 ufshci_sim_detach(struct ufshci_controller *ctrlr)
385 {
386 	int error;
387 
388 	if (ctrlr->ufshci_path != NULL) {
389 		xpt_free_path(ctrlr->ufshci_path);
390 		ctrlr->ufshci_path = NULL;
391 	}
392 
393 	if (ctrlr->ufshci_sim != NULL) {
394 		error = xpt_bus_deregister(cam_sim_path(ctrlr->ufshci_sim));
395 		if (error == 0) {
396 			/* accessing the softc is not possible after this */
397 			ctrlr->ufshci_sim->softc = NULL;
398 			ufshci_printf(ctrlr,
399 			    "%s: %s:%d:%d caling "
400 			    "cam_sim_free sim %p refc %u mtx %p\n",
401 			    __func__, ctrlr->sc_name,
402 			    cam_sim_path(ctrlr->ufshci_sim), ctrlr->sc_unit,
403 			    ctrlr->ufshci_sim, ctrlr->ufshci_sim->refcount,
404 			    ctrlr->ufshci_sim->mtx);
405 		} else {
406 			panic("%s: %s: CAM layer is busy: errno %d\n", __func__,
407 			    ctrlr->sc_name, error);
408 		}
409 
410 		cam_sim_free(ctrlr->ufshci_sim, /* free_devq */ TRUE);
411 		ctrlr->ufshci_sim = NULL;
412 	}
413 }
414 
415 struct cam_periph *
ufshci_sim_find_periph(struct ufshci_controller * ctrlr,uint8_t wlun)416 ufshci_sim_find_periph(struct ufshci_controller *ctrlr, uint8_t wlun)
417 {
418 	struct cam_path *path;
419 	struct cam_periph *periph = NULL;
420 	uint64_t scsi_lun;
421 	uint64_t timeout;
422 
423 	scsi_lun = ufshci_sim_translate_ufs_to_scsi_lun(wlun);
424 
425 	if (xpt_create_path(&path, /*periph*/ NULL,
426 		cam_sim_path(ctrlr->ufshci_sim), 0, scsi_lun) != CAM_REQ_CMP) {
427 		return NULL;
428 	}
429 
430 	/* Wait for the perip device to be found */
431 	timeout = ticks + MSEC_2_TICKS(ctrlr->device_init_timeout_in_ms);
432 
433 	while (1) {
434 		xpt_path_lock(path);
435 		periph = cam_periph_find(path, "pass");
436 		xpt_path_unlock(path);
437 
438 		if (periph) {
439 			xpt_free_path(path);
440 			break;
441 		}
442 
443 		if (timeout - ticks < 0) {
444 			ufshci_printf(ctrlr,
445 			    "Failed to find the Well known LUN(0x%x)\n", wlun);
446 			break;
447 		}
448 
449 		pause_sbt("ufshci_find_periph", ustosbt(100), 0, C_PREL(1));
450 	}
451 
452 	return periph;
453 }
454 
455 /* This function is called during suspend/resume. */
456 int
ufshci_sim_send_ssu(struct ufshci_controller * ctrlr,bool start,int power_condition,bool immed)457 ufshci_sim_send_ssu(struct ufshci_controller *ctrlr, bool start,
458     int power_condition, bool immed)
459 {
460 	struct cam_periph *periph = ctrlr->ufs_device_wlun_periph;
461 	union ccb *ccb;
462 	int err;
463 
464 	/* Acquire periph reference */
465 	if (periph && cam_periph_acquire(periph) != 0) {
466 		periph = NULL;
467 	}
468 
469 	if (periph == NULL) {
470 		/* If the periph device does not exist, it will try to find it
471 		 * again */
472 		periph = ufshci_sim_find_periph(ctrlr,
473 		    (uint8_t)UFSHCI_WLUN_UFS_DEVICE);
474 		if (periph)
475 			ctrlr->ufs_device_wlun_periph = periph;
476 	}
477 
478 	if (periph == NULL) {
479 		ufshci_printf(ctrlr,
480 		    "Well-known LUN `UFS Device (0x50)` not found\n");
481 		return ENODEV;
482 	}
483 	cam_periph_lock(periph);
484 	ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL);
485 	if (!ccb) {
486 		cam_periph_unlock(periph);
487 		cam_periph_release(periph);
488 		return ENOMEM;
489 	}
490 
491 	scsi_start_stop(&ccb->csio,
492 	    /*retries*/ 4,
493 	    /*cbfcnp*/ NULL,
494 	    /*tag_action*/ MSG_SIMPLE_Q_TAG,
495 	    /*start*/ start ? 1 : 0,
496 	    /*load_eject*/ 0,
497 	    /*immediate*/ immed ? 1 : 0,
498 	    /*power_condition*/ power_condition, SSD_MIN_SIZE,
499 	    ctrlr->device_init_timeout_in_ms);
500 
501 	ccb->ccb_h.flags |= CAM_DIR_NONE | CAM_DEV_QFRZDIS;
502 
503 	err = cam_periph_runccb(ccb, NULL, 0, SF_RETRY_UA, NULL);
504 
505 	cam_periph_unlock(periph);
506 	/* Release periph reference */
507 	cam_periph_release(periph);
508 
509 	return (err == 0) ? 0 : EIO;
510 }
511