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