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