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 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 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 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 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 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 /* TODO: Implement Task Management CMD*/ 245 ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 246 break; 247 case XPT_SET_TRAN_SETTINGS: 248 ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 249 break; 250 case XPT_GET_TRAN_SETTINGS: { 251 struct ccb_trans_settings *cts; 252 struct ccb_trans_settings_ufshci *ufshcix; 253 254 cts = &ccb->cts; 255 ufshcix = &cts->xport_specific.ufshci; 256 257 ufshcix->hs_gear = ctrlr->hs_gear; 258 ufshcix->tx_lanes = ctrlr->tx_lanes; 259 ufshcix->rx_lanes = ctrlr->rx_lanes; 260 ufshcix->max_hs_gear = ctrlr->max_rx_hs_gear; 261 ufshcix->max_tx_lanes = ctrlr->max_tx_lanes; 262 ufshcix->max_rx_lanes = ctrlr->max_rx_lanes; 263 ufshcix->valid = CTS_UFSHCI_VALID_LINK; 264 265 cts->transport = XPORT_UFSHCI; 266 cts->transport_version = 1; 267 cts->protocol = PROTO_SCSI; 268 cts->protocol_version = SCSI_REV_SPC5; 269 ccb->ccb_h.status = CAM_REQ_CMP; 270 break; 271 } 272 case XPT_CALC_GEOMETRY: 273 cam_calc_geometry(&ccb->ccg, 1); 274 break; 275 case XPT_NOOP: 276 ccb->ccb_h.status = CAM_REQ_CMP; 277 break; 278 default: 279 printf("invalid ccb=%p func=%#x\n", ccb, ccb->ccb_h.func_code); 280 break; 281 } 282 xpt_done(ccb); 283 284 return; 285 } 286 287 static void 288 ufshci_cam_poll(struct cam_sim *sim) 289 { 290 struct ufshci_controller *ctrlr = sim2ctrlr(sim); 291 292 ufshci_ctrlr_poll(ctrlr); 293 } 294 295 int 296 ufshci_sim_attach(struct ufshci_controller *ctrlr) 297 { 298 device_t dev; 299 struct cam_devq *devq; 300 int max_trans; 301 302 dev = ctrlr->dev; 303 max_trans = ctrlr->max_hw_pend_io; 304 if ((devq = cam_simq_alloc(max_trans)) == NULL) { 305 printf("Failed to allocate a simq\n"); 306 return (ENOMEM); 307 } 308 309 ctrlr->ufshci_sim = cam_sim_alloc(ufshci_cam_action, ufshci_cam_poll, 310 "ufshci", ctrlr, device_get_unit(dev), &ctrlr->sc_mtx, max_trans, 311 max_trans, devq); 312 if (ctrlr->ufshci_sim == NULL) { 313 printf("Failed to allocate a sim\n"); 314 cam_simq_free(devq); 315 return (ENOMEM); 316 } 317 318 mtx_lock(&ctrlr->sc_mtx); 319 if (xpt_bus_register(ctrlr->ufshci_sim, ctrlr->dev, 0) != CAM_SUCCESS) { 320 cam_sim_free(ctrlr->ufshci_sim, /*free_devq*/ TRUE); 321 cam_simq_free(devq); 322 mtx_unlock(&ctrlr->sc_mtx); 323 printf("Failed to create a bus\n"); 324 return (ENOMEM); 325 } 326 327 if (xpt_create_path(&ctrlr->ufshci_path, /*periph*/ NULL, 328 cam_sim_path(ctrlr->ufshci_sim), CAM_TARGET_WILDCARD, 329 CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 330 xpt_bus_deregister(cam_sim_path(ctrlr->ufshci_sim)); 331 cam_sim_free(ctrlr->ufshci_sim, /*free_devq*/ TRUE); 332 cam_simq_free(devq); 333 mtx_unlock(&ctrlr->sc_mtx); 334 printf("Failed to create a path\n"); 335 return (ENOMEM); 336 } 337 mtx_unlock(&ctrlr->sc_mtx); 338 339 return (0); 340 } 341 342 void 343 ufshci_sim_detach(struct ufshci_controller *ctrlr) 344 { 345 int error; 346 347 if (ctrlr->ufshci_path != NULL) { 348 xpt_free_path(ctrlr->ufshci_path); 349 ctrlr->ufshci_path = NULL; 350 } 351 352 if (ctrlr->ufshci_sim != NULL) { 353 error = xpt_bus_deregister(cam_sim_path(ctrlr->ufshci_sim)); 354 if (error == 0) { 355 /* accessing the softc is not possible after this */ 356 ctrlr->ufshci_sim->softc = NULL; 357 ufshci_printf(ctrlr, 358 "%s: %s:%d:%d caling " 359 "cam_sim_free sim %p refc %u mtx %p\n", 360 __func__, ctrlr->sc_name, 361 cam_sim_path(ctrlr->ufshci_sim), ctrlr->sc_unit, 362 ctrlr->ufshci_sim, ctrlr->ufshci_sim->refcount, 363 ctrlr->ufshci_sim->mtx); 364 } else { 365 panic("%s: %s: CAM layer is busy: errno %d\n", __func__, 366 ctrlr->sc_name, error); 367 } 368 369 cam_sim_free(ctrlr->ufshci_sim, /* free_devq */ TRUE); 370 ctrlr->ufshci_sim = NULL; 371 } 372 } 373