xref: /openbsd/sys/dev/ic/ufshci.c (revision ceedf4cc)
1*ceedf4ccSmglocker /*	$OpenBSD: ufshci.c,v 1.26 2024/05/20 12:42:45 mglocker Exp $ */
22095c737Smglocker 
32095c737Smglocker /*
42095c737Smglocker  * Copyright (c) 2022 Marcus Glocker <mglocker@openbsd.org>
52095c737Smglocker  *
62095c737Smglocker  * Permission to use, copy, modify, and distribute this software for any
72095c737Smglocker  * purpose with or without fee is hereby granted, provided that the above
82095c737Smglocker  * copyright notice and this permission notice appear in all copies.
92095c737Smglocker  *
102095c737Smglocker  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
112095c737Smglocker  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
122095c737Smglocker  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
132095c737Smglocker  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
142095c737Smglocker  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
152095c737Smglocker  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
162095c737Smglocker  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
172095c737Smglocker  */
182095c737Smglocker 
192095c737Smglocker /*
202095c737Smglocker  * Universal Flash Storage Host Controller Interface (UFSHCI) 2.1 driver based
212095c737Smglocker  * on the JEDEC JESD223C.pdf and JESD220C-2_1.pdf specifications.
222095c737Smglocker  */
232095c737Smglocker 
242095c737Smglocker #include <sys/param.h>
252095c737Smglocker #include <sys/systm.h>
262095c737Smglocker #include <sys/buf.h>
272095c737Smglocker #include <sys/kernel.h>
282095c737Smglocker #include <sys/malloc.h>
292095c737Smglocker #include <sys/device.h>
302095c737Smglocker #include <sys/queue.h>
312095c737Smglocker #include <sys/mutex.h>
322095c737Smglocker #include <sys/pool.h>
332095c737Smglocker 
342095c737Smglocker #include <sys/atomic.h>
352095c737Smglocker 
362095c737Smglocker #include <machine/bus.h>
372095c737Smglocker 
382095c737Smglocker #include <scsi/scsi_all.h>
392095c737Smglocker #include <scsi/scsi_disk.h>
402095c737Smglocker #include <scsi/scsiconf.h>
412095c737Smglocker 
422095c737Smglocker #include <dev/ic/ufshcivar.h>
432095c737Smglocker #include <dev/ic/ufshcireg.h>
442095c737Smglocker 
452095c737Smglocker #ifdef UFSHCI_DEBUG
462095c737Smglocker int ufshci_dbglvl = 1;
476920fd9bSmglocker #define DPRINTF(l, x...)	do { if ((l) <= ufshci_dbglvl) printf(x); } \
486920fd9bSmglocker 				    while (0)
492095c737Smglocker #else
506920fd9bSmglocker #define DPRINTF(l, x...)
512095c737Smglocker #endif
522095c737Smglocker 
532095c737Smglocker struct cfdriver ufshci_cd = {
542095c737Smglocker 	NULL, "ufshci", DV_DULL
552095c737Smglocker };
562095c737Smglocker 
572095c737Smglocker int			 ufshci_reset(struct ufshci_softc *);
582095c737Smglocker int			 ufshci_uccs_poll(struct ufshci_softc *);
592095c737Smglocker struct ufshci_dmamem	*ufshci_dmamem_alloc(struct ufshci_softc *, size_t);
602095c737Smglocker void			 ufshci_dmamem_free(struct ufshci_softc *,
612095c737Smglocker 			     struct ufshci_dmamem *);
622095c737Smglocker int			 ufshci_init(struct ufshci_softc *);
632095c737Smglocker int			 ufshci_doorbell_read(struct ufshci_softc *);
6412f70f1cSmglocker void			 ufshci_doorbell_write(struct ufshci_softc *, int);
652095c737Smglocker int			 ufshci_doorbell_poll(struct ufshci_softc *, int);
6612f70f1cSmglocker int			 ufshci_utr_cmd_nop(struct ufshci_softc *,
6712f70f1cSmglocker 			     struct ufshci_ccb *, struct scsi_xfer *);
682095c737Smglocker int			 ufshci_utr_cmd_lun(struct ufshci_softc *,
6944c52867Smglocker 			     struct ufshci_ccb *, struct scsi_xfer *);
702095c737Smglocker int			 ufshci_utr_cmd_inquiry(struct ufshci_softc *,
7144c52867Smglocker 			     struct ufshci_ccb *, struct scsi_xfer *);
722095c737Smglocker int			 ufshci_utr_cmd_capacity16(struct ufshci_softc *,
7344c52867Smglocker 			     struct ufshci_ccb *, struct scsi_xfer *);
742095c737Smglocker int			 ufshci_utr_cmd_capacity(struct ufshci_softc *,
7544c52867Smglocker 			     struct ufshci_ccb *, struct scsi_xfer *);
76a2f0dcb2Smglocker int			 ufshci_utr_cmd_io(struct ufshci_softc *,
77a2f0dcb2Smglocker 			     struct ufshci_ccb *, struct scsi_xfer *, int);
782095c737Smglocker int			 ufshci_utr_cmd_sync(struct ufshci_softc *,
7944c52867Smglocker 			     struct ufshci_ccb *, struct scsi_xfer *,
8044c52867Smglocker 			     uint32_t, uint16_t);
812095c737Smglocker int			 ufshci_xfer_complete(struct ufshci_softc *);
822095c737Smglocker 
832095c737Smglocker /* SCSI */
842095c737Smglocker int			 ufshci_ccb_alloc(struct ufshci_softc *, int);
852095c737Smglocker void			*ufshci_ccb_get(void *);
862095c737Smglocker void			 ufshci_ccb_put(void *, void *);
872095c737Smglocker void			 ufshci_ccb_free(struct ufshci_softc*, int);
882095c737Smglocker 
892095c737Smglocker void			 ufshci_scsi_cmd(struct scsi_xfer *);
902095c737Smglocker void			 ufshci_minphys(struct buf *, struct scsi_link *);
912095c737Smglocker int			 ufshci_scsi_probe(struct scsi_link *);
922095c737Smglocker void			 ufshci_scsi_free(struct scsi_link *);
932095c737Smglocker 
942095c737Smglocker void			 ufshci_scsi_inquiry(struct scsi_xfer *);
952095c737Smglocker void			 ufshci_scsi_capacity16(struct scsi_xfer *);
962095c737Smglocker void			 ufshci_scsi_capacity(struct scsi_xfer *);
972095c737Smglocker void			 ufshci_scsi_sync(struct scsi_xfer *);
982095c737Smglocker void			 ufshci_scsi_io(struct scsi_xfer *, int);
992095c737Smglocker void			 ufshci_scsi_io_done(struct ufshci_softc *,
1002095c737Smglocker 			     struct ufshci_ccb *);
1012095c737Smglocker void			 ufshci_scsi_done(struct ufshci_softc *,
1022095c737Smglocker 			     struct ufshci_ccb *);
1032095c737Smglocker 
1042095c737Smglocker const struct scsi_adapter ufshci_switch = {
1052095c737Smglocker 	ufshci_scsi_cmd, NULL, NULL, NULL, NULL
1062095c737Smglocker };
1072095c737Smglocker 
1082095c737Smglocker int
1092095c737Smglocker ufshci_intr(void *arg)
1102095c737Smglocker {
1112095c737Smglocker 	struct ufshci_softc *sc = arg;
1122095c737Smglocker 	uint32_t status;
1132095c737Smglocker 	int handled = 0;
1142095c737Smglocker 
1152095c737Smglocker 	status = UFSHCI_READ_4(sc, UFSHCI_REG_IS);
1166920fd9bSmglocker 	DPRINTF(3, "%s: status=0x%08x\n", __func__, status);
1172095c737Smglocker 
1182095c737Smglocker 	if (status == 0)
1192095c737Smglocker 		return 0;
1202095c737Smglocker 
1212095c737Smglocker 	if (status & UFSHCI_REG_IS_UCCS) {
1226920fd9bSmglocker 		DPRINTF(3, "%s: UCCS interrupt\n", __func__);
1232095c737Smglocker 		handled = 1;
1242095c737Smglocker 	}
1252095c737Smglocker 	if (status & UFSHCI_REG_IS_UTRCS) {
1266920fd9bSmglocker 	  	DPRINTF(3, "%s: UTRCS interrupt\n", __func__);
1272095c737Smglocker 
12812f70f1cSmglocker 		ufshci_xfer_complete(sc);
12912f70f1cSmglocker 
1302095c737Smglocker 		handled = 1;
1312095c737Smglocker 	}
1322095c737Smglocker 
1332095c737Smglocker 	if (handled == 0) {
1342095c737Smglocker 		printf("%s: UNKNOWN interrupt, status=0x%08x\n",
1352095c737Smglocker 		    sc->sc_dev.dv_xname, status);
1362095c737Smglocker 	}
1372095c737Smglocker 
1382095c737Smglocker 	/* ACK interrupt */
1392095c737Smglocker 	UFSHCI_WRITE_4(sc, UFSHCI_REG_IS, status);
1402095c737Smglocker 
1412095c737Smglocker 	return 1;
1422095c737Smglocker }
1432095c737Smglocker 
1442095c737Smglocker int
1452095c737Smglocker ufshci_attach(struct ufshci_softc *sc)
1462095c737Smglocker {
1472095c737Smglocker 	struct scsibus_attach_args saa;
1482095c737Smglocker 
149e58b468bSmglocker 	mtx_init(&sc->sc_cmd_mtx, IPL_BIO);
1502095c737Smglocker 	mtx_init(&sc->sc_ccb_mtx, IPL_BIO);
1512095c737Smglocker 	SIMPLEQ_INIT(&sc->sc_ccb_list);
1522095c737Smglocker 	scsi_iopool_init(&sc->sc_iopool, sc, ufshci_ccb_get, ufshci_ccb_put);
1532095c737Smglocker 
1542095c737Smglocker 	ufshci_reset(sc);
1552095c737Smglocker 
1562095c737Smglocker 	sc->sc_ver = UFSHCI_READ_4(sc, UFSHCI_REG_VER);
1572095c737Smglocker 	printf(", UFSHCI %d.%d%d\n",
1582095c737Smglocker 	    UFSHCI_REG_VER_MAJOR(sc->sc_ver),
1592095c737Smglocker 	    UFSHCI_REG_VER_MINOR(sc->sc_ver),
1602095c737Smglocker 	    UFSHCI_REG_VER_SUFFIX(sc->sc_ver));
1612095c737Smglocker 
1622095c737Smglocker 	sc->sc_cap = UFSHCI_READ_4(sc, UFSHCI_REG_CAP);
1632095c737Smglocker 	sc->sc_hcpid = UFSHCI_READ_4(sc, UFSHCI_REG_HCPID);
1642095c737Smglocker 	sc->sc_hcmid = UFSHCI_READ_4(sc, UFSHCI_REG_HCMID);
1652095c737Smglocker 	sc->sc_nutmrs = UFSHCI_REG_CAP_NUTMRS(sc->sc_cap) + 1;
1662095c737Smglocker 	sc->sc_rtt = UFSHCI_REG_CAP_RTT(sc->sc_cap) + 1;
1676920fd9bSmglocker 	sc->sc_nutrs = UFSHCI_REG_CAP_NUTRS(sc->sc_cap) + 1;
1686920fd9bSmglocker 
1696920fd9bSmglocker 	DPRINTF(1, "Capabilities (0x%08x):\n", sc->sc_cap);
1706920fd9bSmglocker 	DPRINTF(1, "CS=%d\n", sc->sc_cap & UFSHCI_REG_CAP_CS ? 1 : 0);
1716920fd9bSmglocker 	DPRINTF(1, "UICDMETMS=%d\n",
1726920fd9bSmglocker 	    sc->sc_cap & UFSHCI_REG_CAP_UICDMETMS ? 1 : 0);
1736920fd9bSmglocker 	DPRINTF(1, "OODDS=%d\n", sc->sc_cap & UFSHCI_REG_CAP_OODDS ? 1 : 0);
1746920fd9bSmglocker 	DPRINTF(1, "64AS=%d\n", sc->sc_cap & UFSHCI_REG_CAP_64AS ? 1 : 0);
1756920fd9bSmglocker 	DPRINTF(1, "AUTOH8=%d\n", sc->sc_cap & UFSHCI_REG_AUTOH8 ? 1 : 0);
1766920fd9bSmglocker 	DPRINTF(1, "NUTMRS=%d\n", sc->sc_nutmrs);
1776920fd9bSmglocker 	DPRINTF(1, "RTT=%d\n", sc->sc_rtt);
1786920fd9bSmglocker 	DPRINTF(1, "NUTRS=%d\n", sc->sc_nutrs);
1796920fd9bSmglocker 	DPRINTF(1, "HCPID=0x%08x\n", sc->sc_hcpid);
1806920fd9bSmglocker 	DPRINTF(1, "HCMID (0x%08x):\n", sc->sc_hcmid);
1816920fd9bSmglocker 	DPRINTF(1, " BI=0x%04x\n", UFSHCI_REG_HCMID_BI(sc->sc_hcmid));
1826920fd9bSmglocker 	DPRINTF(1, " MIC=0x%04x\n", UFSHCI_REG_HCMID_MIC(sc->sc_hcmid));
1836920fd9bSmglocker 
1842095c737Smglocker 	if (sc->sc_nutrs > 32) {
1852095c737Smglocker 		printf("%s: NUTRS can't be >32 (is %d)!\n",
1862095c737Smglocker 		    sc->sc_dev.dv_xname, sc->sc_nutrs);
1872095c737Smglocker 		return 1;
188240fdb4cSmglocker 	} else if (sc->sc_nutrs == 1) {
189240fdb4cSmglocker 		sc->sc_iacth = sc->sc_nutrs;
190240fdb4cSmglocker 	} else if (sc->sc_nutrs > 1) {
191240fdb4cSmglocker 		sc->sc_iacth = sc->sc_nutrs - 1;
1922095c737Smglocker 	}
1936920fd9bSmglocker 	DPRINTF(1, "Intr. aggr. counter threshold:\nIACTH=%d\n", sc->sc_iacth);
1942095c737Smglocker 
195*ceedf4ccSmglocker 	/*
196*ceedf4ccSmglocker 	 * XXX:
197*ceedf4ccSmglocker 	 * At the moment normal interrupts work better for us than interrupt
198*ceedf4ccSmglocker 	 * aggregation, because:
199*ceedf4ccSmglocker 	 *
200*ceedf4ccSmglocker 	 * 	1. With interrupt aggregation enabled, the I/O performance
201*ceedf4ccSmglocker 	 *	   isn't better, but even slightly worse depending on the
202*ceedf4ccSmglocker 	 *	   UFS controller and architecture.
203*ceedf4ccSmglocker 	 *	2. With interrupt aggregation enabled we currently see
204*ceedf4ccSmglocker 	 *	   intermittent SCSI command stalling.  Probably there is a
205*ceedf4ccSmglocker 	 *	   race condition where new SCSI commands are getting
206*ceedf4ccSmglocker 	 *	   scheduled, while we miss to reset the interrupt aggregation
207*ceedf4ccSmglocker 	 *	   counter/timer, which leaves us with no more interrupts
208*ceedf4ccSmglocker 	 *	   triggered.  This needs to be fixed, but I couldn't figure
209*ceedf4ccSmglocker 	 *	   out yet how.
210*ceedf4ccSmglocker 	 */
211*ceedf4ccSmglocker #if 0
212*ceedf4ccSmglocker 	sc->sc_flags |= UFSHCI_FLAGS_AGGR_INTR;	/* Enable intr. aggregation */
213*ceedf4ccSmglocker #endif
2142095c737Smglocker 	ufshci_init(sc);
2152095c737Smglocker 
2162095c737Smglocker 	if (ufshci_ccb_alloc(sc, sc->sc_nutrs) != 0) {
2172095c737Smglocker 		printf("%s: %s: Can't allocate CCBs\n",
2182095c737Smglocker 		    sc->sc_dev.dv_xname, __func__);
2192095c737Smglocker 		return 1;
2202095c737Smglocker 	}
2212095c737Smglocker 
2222095c737Smglocker 	/* Attach to SCSI layer */
2232095c737Smglocker 	saa.saa_adapter = &ufshci_switch;
2242095c737Smglocker 	saa.saa_adapter_softc = sc;
2252095c737Smglocker 	saa.saa_adapter_buswidth = 2; /* XXX: What's the right value? */
2262095c737Smglocker 	saa.saa_luns = 1; /* XXX: Should we use ufshci_utr_cmd_lun() */
2272095c737Smglocker 	saa.saa_adapter_target = 0;
2282095c737Smglocker 	saa.saa_openings = sc->sc_nutrs;
2292095c737Smglocker 	saa.saa_pool = &sc->sc_iopool;
2302095c737Smglocker 	saa.saa_quirks = saa.saa_flags = 0;
2312095c737Smglocker 	saa.saa_wwpn = saa.saa_wwnn = 0;
2322095c737Smglocker 
2332095c737Smglocker 	config_found(&sc->sc_dev, &saa, scsiprint);
2342095c737Smglocker 
2352095c737Smglocker 	return 0;
2362095c737Smglocker }
2372095c737Smglocker 
2382095c737Smglocker int
2392095c737Smglocker ufshci_reset(struct ufshci_softc *sc)
2402095c737Smglocker {
2412095c737Smglocker 	int i;
2422095c737Smglocker 	int retry = 10;
2432095c737Smglocker 	uint32_t hce;
2442095c737Smglocker 
2452095c737Smglocker 	/*
2462095c737Smglocker 	 * 7.1.1 Host Controller Initialization: 2)
2472095c737Smglocker 	 * Reset and enable host controller
2482095c737Smglocker 	 */
2492095c737Smglocker 	UFSHCI_WRITE_4(sc, UFSHCI_REG_HCE, UFSHCI_REG_HCE_HCE);
2502095c737Smglocker 	/* 7.1.1 Host Controller Initialization: 3) */
2512095c737Smglocker 	for (i = 0; i < retry; i++) {
2522095c737Smglocker 		hce = UFSHCI_READ_4(sc, UFSHCI_REG_HCE);
2532095c737Smglocker 		if (hce == 1)
2542095c737Smglocker 			break;
2552095c737Smglocker 		delay(1);
2562095c737Smglocker 	}
2572095c737Smglocker 	if (i == retry) {
2582095c737Smglocker 		printf("%s: Enabling Host Controller failed!\n",
2592095c737Smglocker 		    sc->sc_dev.dv_xname);
2602095c737Smglocker 		return -1;
2612095c737Smglocker 	}
2622095c737Smglocker 
2636920fd9bSmglocker 	DPRINTF(2, "\n%s: Host Controller enabled (i=%d)\n", __func__, i);
2642095c737Smglocker 
2652095c737Smglocker 	return 0;
2662095c737Smglocker }
2672095c737Smglocker 
2682095c737Smglocker int
2692095c737Smglocker ufshci_uccs_poll(struct ufshci_softc *sc)
2702095c737Smglocker {
2712095c737Smglocker 	uint32_t status;
2722095c737Smglocker 	int i, retry = 25;
2732095c737Smglocker 
2746920fd9bSmglocker 	DPRINTF(3, "%s\n", __func__);
2752095c737Smglocker 
2762095c737Smglocker 	for (i = 0; i < retry; i++) {
2772095c737Smglocker 		status = UFSHCI_READ_4(sc, UFSHCI_REG_IS);
2782095c737Smglocker 		if (status & UFSHCI_REG_IS_UCCS)
2792095c737Smglocker 			break;
2802095c737Smglocker 		delay(10);
2812095c737Smglocker 	}
2822095c737Smglocker 	if (i == retry) {
2832095c737Smglocker 		printf("%s: %s: timeout\n", sc->sc_dev.dv_xname, __func__);
2842095c737Smglocker 		return -1;
2852095c737Smglocker 	}
2866920fd9bSmglocker 	DPRINTF(3, "%s: completed after %d retries\n", __func__, i);
2872095c737Smglocker 
2882095c737Smglocker 	/* ACK interrupt */
2892095c737Smglocker 	UFSHCI_WRITE_4(sc, UFSHCI_REG_IS, status);
2902095c737Smglocker 
2912095c737Smglocker 	return 0;
2922095c737Smglocker }
2932095c737Smglocker 
2942095c737Smglocker struct ufshci_dmamem *
2952095c737Smglocker ufshci_dmamem_alloc(struct ufshci_softc *sc, size_t size)
2962095c737Smglocker {
2972095c737Smglocker 	struct ufshci_dmamem *udm;
2982095c737Smglocker 	int nsegs;
2992095c737Smglocker 
3002095c737Smglocker 	udm = malloc(sizeof(*udm), M_DEVBUF, M_WAITOK | M_ZERO);
3012095c737Smglocker 	if (udm == NULL)
3022095c737Smglocker 		return NULL;
3032095c737Smglocker 
3042095c737Smglocker 	udm->udm_size = size;
3052095c737Smglocker 
3062095c737Smglocker 	if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
3072095c737Smglocker 	    BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW | BUS_DMA_64BIT,
3082095c737Smglocker 	    &udm->udm_map) != 0)
3092095c737Smglocker 		goto udmfree;
3102095c737Smglocker 
3112095c737Smglocker 	if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &udm->udm_seg,
3122095c737Smglocker 	    1, &nsegs, BUS_DMA_WAITOK | BUS_DMA_ZERO) != 0)
3132095c737Smglocker 		goto destroy;
3142095c737Smglocker 
3152095c737Smglocker 	if (bus_dmamem_map(sc->sc_dmat, &udm->udm_seg, nsegs, size,
3162095c737Smglocker 	    &udm->udm_kva, BUS_DMA_WAITOK) != 0)
3172095c737Smglocker 		goto free;
3182095c737Smglocker 
3192095c737Smglocker 	if (bus_dmamap_load(sc->sc_dmat, udm->udm_map, udm->udm_kva, size,
3202095c737Smglocker 	    NULL, BUS_DMA_WAITOK) != 0)
3212095c737Smglocker 		goto unmap;
3222095c737Smglocker 
3236920fd9bSmglocker 	DPRINTF(2, "%s: size=%lu, page_size=%d, nsegs=%d\n",
3242095c737Smglocker 	    __func__, size, PAGE_SIZE, nsegs);
3252095c737Smglocker 
3262095c737Smglocker 	return udm;
3272095c737Smglocker 
3282095c737Smglocker unmap:
3292095c737Smglocker 	bus_dmamem_unmap(sc->sc_dmat, udm->udm_kva, size);
3302095c737Smglocker free:
3312095c737Smglocker 	bus_dmamem_free(sc->sc_dmat, &udm->udm_seg, 1);
3322095c737Smglocker destroy:
3332095c737Smglocker 	bus_dmamap_destroy(sc->sc_dmat, udm->udm_map);
3342095c737Smglocker udmfree:
3352095c737Smglocker 	free(udm, M_DEVBUF, sizeof(*udm));
3362095c737Smglocker 
3372095c737Smglocker 	return NULL;
3382095c737Smglocker }
3392095c737Smglocker 
3402095c737Smglocker void
3412095c737Smglocker ufshci_dmamem_free(struct ufshci_softc *sc, struct ufshci_dmamem *udm)
3422095c737Smglocker {
3432095c737Smglocker 	bus_dmamap_unload(sc->sc_dmat, udm->udm_map);
3442095c737Smglocker 	bus_dmamem_unmap(sc->sc_dmat, udm->udm_kva, udm->udm_size);
3452095c737Smglocker 	bus_dmamem_free(sc->sc_dmat, &udm->udm_seg, 1);
3462095c737Smglocker 	bus_dmamap_destroy(sc->sc_dmat, udm->udm_map);
3472095c737Smglocker 	free(udm, M_DEVBUF, sizeof(*udm));
3482095c737Smglocker }
3492095c737Smglocker 
3502095c737Smglocker int
3512095c737Smglocker ufshci_init(struct ufshci_softc *sc)
3522095c737Smglocker {
3532095c737Smglocker 	uint32_t reg;
3542095c737Smglocker 	uint64_t dva;
3552095c737Smglocker 
3562095c737Smglocker 	/*
3572095c737Smglocker 	 * 7.1.1 Host Controller Initialization: 4)
3582095c737Smglocker 	 * TODO: Do we need to set DME_SET?
3592095c737Smglocker 	 */
3602095c737Smglocker 
3612095c737Smglocker 	/* 7.1.1 Host Controller Initialization: 5) */
3622095c737Smglocker 	//UFSHCI_WRITE_4(sc, UFSHCI_REG_IE, UFSHCI_REG_IE_UCCE |
3632095c737Smglocker 	UFSHCI_WRITE_4(sc, UFSHCI_REG_IE,
3642095c737Smglocker 	    UFSHCI_REG_IE_UTRCE | UFSHCI_REG_IE_UTMRCE);
3652095c737Smglocker 
3662095c737Smglocker 	/* 7.1.1 Host Controller Initialization: 6) */
3672095c737Smglocker 	UFSHCI_WRITE_4(sc, UFSHCI_REG_UICCMD,
3682095c737Smglocker 	    UFSHCI_REG_UICCMD_CMDOP_DME_LINKSTARTUP);
3692095c737Smglocker 	if (ufshci_uccs_poll(sc) != 0)
3702095c737Smglocker 		return -1;
3712095c737Smglocker 
3722095c737Smglocker 	/*
3732095c737Smglocker 	 * 7.1.1 Host Controller Initialization: 7), 8), 9)
3742095c737Smglocker 	 * TODO: Implement retry in case UFSHCI_REG_HCS returns 0
3752095c737Smglocker 	 */
3762095c737Smglocker 	reg = UFSHCI_READ_4(sc, UFSHCI_REG_HCS);
3772095c737Smglocker 	if (reg & UFSHCI_REG_HCS_DP)
3786920fd9bSmglocker 		DPRINTF(2, "%s: Device Presence SET\n", __func__);
3792095c737Smglocker 	else
3806920fd9bSmglocker 		DPRINTF(2, "%s: Device Presence NOT SET\n", __func__);
3812095c737Smglocker 
3822095c737Smglocker 	/*
3832095c737Smglocker 	 * 7.1.1 Host Controller Initialization: 10)
3842095c737Smglocker 	 * TODO: Enable additional interrupt on the IE register
3852095c737Smglocker 	 */
3862095c737Smglocker 
3872095c737Smglocker 	/* 7.1.1 Host Controller Initialization: 11) */
388*ceedf4ccSmglocker 	if (sc->sc_flags & UFSHCI_FLAGS_AGGR_INTR) {
389f0ed5855Smglocker 		UFSHCI_WRITE_4(sc, UFSHCI_REG_UTRIACR,
390f0ed5855Smglocker 		    UFSHCI_REG_UTRIACR_IAEN |
391f0ed5855Smglocker 		    UFSHCI_REG_UTRIACR_IAPWEN |
392f0ed5855Smglocker 		    UFSHCI_REG_UTRIACR_CTR |
393f0ed5855Smglocker 		    UFSHCI_REG_UTRIACR_IACTH(sc->sc_iacth) |
394f0ed5855Smglocker 		    UFSHCI_REG_UTRIACR_IATOVAL(UFSHCI_INTR_AGGR_TIMEOUT));
395*ceedf4ccSmglocker 	} else {
396*ceedf4ccSmglocker 		UFSHCI_WRITE_4(sc, UFSHCI_REG_UTRIACR, 0);
397*ceedf4ccSmglocker 	}
3982095c737Smglocker 
3992095c737Smglocker 	/*
4002095c737Smglocker 	 * 7.1.1 Host Controller Initialization: 12)
4012095c737Smglocker 	 * TODO: More UIC commands to issue?
4022095c737Smglocker 	 */
4032095c737Smglocker 
4042095c737Smglocker 	/* 7.1.1 Host Controller Initialization: 13) */
4052095c737Smglocker 	sc->sc_dmamem_utmrd = ufshci_dmamem_alloc(sc,
4062095c737Smglocker 	    sizeof(struct ufshci_utmrd) * sc->sc_nutmrs);
4072095c737Smglocker 	if (sc->sc_dmamem_utmrd == NULL) {
4082095c737Smglocker 		printf("%s: Can't allocate DMA memory for UTMRD\n",
4092095c737Smglocker 		    sc->sc_dev.dv_xname);
4102095c737Smglocker 		return -1;
4112095c737Smglocker 	}
4122095c737Smglocker 	/* 7.1.1 Host Controller Initialization: 14) */
4132095c737Smglocker 	dva = UFSHCI_DMA_DVA(sc->sc_dmamem_utmrd);
4146920fd9bSmglocker 	DPRINTF(2, "%s: utmrd dva=%llu\n", __func__, dva);
4152095c737Smglocker 	UFSHCI_WRITE_4(sc, UFSHCI_REG_UTMRLBA, (uint32_t)dva);
4162095c737Smglocker 	UFSHCI_WRITE_4(sc, UFSHCI_REG_UTMRLBAU, (uint32_t)(dva >> 32));
4172095c737Smglocker 
4182095c737Smglocker 	/* 7.1.1 Host Controller Initialization: 15) */
4192095c737Smglocker 	sc->sc_dmamem_utrd = ufshci_dmamem_alloc(sc,
4202095c737Smglocker 	    sizeof(struct ufshci_utrd) * sc->sc_nutrs);
4212095c737Smglocker 	if (sc->sc_dmamem_utrd == NULL) {
4222095c737Smglocker 		printf("%s: Can't allocate DMA memory for UTRD\n",
4232095c737Smglocker 		    sc->sc_dev.dv_xname);
4242095c737Smglocker 		return -1;
4252095c737Smglocker 	}
4262095c737Smglocker 	/* 7.1.1 Host Controller Initialization: 16) */
4272095c737Smglocker 	dva = UFSHCI_DMA_DVA(sc->sc_dmamem_utrd);
4286920fd9bSmglocker 	DPRINTF(2, "%s: utrd dva=%llu\n", __func__, dva);
4292095c737Smglocker 	UFSHCI_WRITE_4(sc, UFSHCI_REG_UTRLBA, (uint32_t)dva);
4302095c737Smglocker 	UFSHCI_WRITE_4(sc, UFSHCI_REG_UTRLBAU, (uint32_t)(dva >> 32));
4312095c737Smglocker 
4322095c737Smglocker 
4332095c737Smglocker 	/* Allocate UCDs. */
4342095c737Smglocker 	sc->sc_dmamem_ucd = ufshci_dmamem_alloc(sc,
4352095c737Smglocker 	    sizeof(struct ufshci_ucd) * sc->sc_nutrs);
4362095c737Smglocker 	if (sc->sc_dmamem_ucd == NULL) {
4372095c737Smglocker 		printf("%s: Can't allocate DMA memory for UCD\n",
4382095c737Smglocker 		    sc->sc_dev.dv_xname);
4392095c737Smglocker 		return -1;
4402095c737Smglocker 	}
4412095c737Smglocker 
4422095c737Smglocker 	/* 7.1.1 Host Controller Initialization: 17) */
4432095c737Smglocker 	UFSHCI_WRITE_4(sc, UFSHCI_REG_UTMRLRSR, UFSHCI_REG_UTMRLRSR_START);
4442095c737Smglocker 
4452095c737Smglocker 	/* 7.1.1 Host Controller Initialization: 18) */
4462095c737Smglocker 	UFSHCI_WRITE_4(sc, UFSHCI_REG_UTRLRSR, UFSHCI_REG_UTRLRSR_START);
4472095c737Smglocker 
4482095c737Smglocker 	/* 7.1.1 Host Controller Initialization: 19) */
4492095c737Smglocker 	/* TODO: bMaxNumOfRTT will be set as the minimum value of
4502095c737Smglocker 	 * bDeviceRTTCap and NORTT. ???
4512095c737Smglocker 	 */
4522095c737Smglocker 
4532095c737Smglocker 	return 0;
4542095c737Smglocker }
4552095c737Smglocker 
4562095c737Smglocker int
4572095c737Smglocker ufshci_doorbell_read(struct ufshci_softc *sc)
4582095c737Smglocker {
4592095c737Smglocker 	uint32_t reg;
4602095c737Smglocker 
4612095c737Smglocker 	reg = UFSHCI_READ_4(sc, UFSHCI_REG_UTRLDBR);
4622095c737Smglocker 
4632095c737Smglocker 	return reg;
4642095c737Smglocker }
4652095c737Smglocker 
46612f70f1cSmglocker void
46712f70f1cSmglocker ufshci_doorbell_write(struct ufshci_softc *sc, int slot)
46812f70f1cSmglocker {
46912f70f1cSmglocker 	uint32_t reg;
47012f70f1cSmglocker 
471c4dc76d1Smglocker 	reg = (1U << slot);
47212f70f1cSmglocker 
47312f70f1cSmglocker 	UFSHCI_WRITE_4(sc, UFSHCI_REG_UTRLDBR, reg);
47412f70f1cSmglocker }
47512f70f1cSmglocker 
4762095c737Smglocker int
4772095c737Smglocker ufshci_doorbell_poll(struct ufshci_softc *sc, int slot)
4782095c737Smglocker {
4792095c737Smglocker 	uint32_t reg;
4802095c737Smglocker 	int i, retry = 25;
4812095c737Smglocker 
4826920fd9bSmglocker 	DPRINTF(3, "%s\n", __func__);
4832095c737Smglocker 
4842095c737Smglocker 	for (i = 0; i < retry; i++) {
4852095c737Smglocker 		reg = UFSHCI_READ_4(sc, UFSHCI_REG_UTRLDBR);
486c4dc76d1Smglocker 		if ((reg & (1U << slot)) == 0)
4872095c737Smglocker 			break;
4882095c737Smglocker 		delay(10);
4892095c737Smglocker 	}
4902095c737Smglocker 	if (i == retry) {
4912095c737Smglocker 		printf("%s: %s: timeout\n", sc->sc_dev.dv_xname, __func__);
4922095c737Smglocker 		return -1;
4932095c737Smglocker 	}
4942095c737Smglocker 
4952095c737Smglocker 	return 0;
4962095c737Smglocker }
4972095c737Smglocker 
4982095c737Smglocker int
49912f70f1cSmglocker ufshci_utr_cmd_nop(struct ufshci_softc *sc, struct ufshci_ccb *ccb,
50012f70f1cSmglocker     struct scsi_xfer *xs)
5012095c737Smglocker {
5022095c737Smglocker 	int slot, off, len;
5032095c737Smglocker 	uint64_t dva;
5042095c737Smglocker 	struct ufshci_utrd *utrd;
5052095c737Smglocker 	struct ufshci_ucd *ucd;
5062095c737Smglocker 
5072095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 1) */
50812f70f1cSmglocker 	slot = ccb->ccb_slot;
509b3b05a10Smglocker 	utrd = UFSHCI_DMA_KVA(sc->sc_dmamem_utrd);
510b3b05a10Smglocker 	utrd += slot;
5112095c737Smglocker 	memset(utrd, 0, sizeof(*utrd));
5126920fd9bSmglocker 	DPRINTF(3, "%s: slot=%d\n", __func__, slot);
5132095c737Smglocker 
5142095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2a) */
5152095c737Smglocker 	utrd->dw0 = UFSHCI_UTRD_DW0_CT_UFS;
5162095c737Smglocker 
5172095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2b) */
5182095c737Smglocker 	utrd->dw0 |= UFSHCI_UTRD_DW0_DD_NO;
5192095c737Smglocker 
5202095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2c) */
521*ceedf4ccSmglocker 	if (sc->sc_flags & UFSHCI_FLAGS_AGGR_INTR)
52212f70f1cSmglocker 		utrd->dw0 |= UFSHCI_UTRD_DW0_I_REG;
523*ceedf4ccSmglocker 	else
524*ceedf4ccSmglocker 		utrd->dw0 |= UFSHCI_UTRD_DW0_I_INT;
5252095c737Smglocker 
5262095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2d) */
5272095c737Smglocker 	utrd->dw2 = UFSHCI_UTRD_DW2_OCS_IOV;
5282095c737Smglocker 
5292095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2e) */
530b3b05a10Smglocker 	ucd = UFSHCI_DMA_KVA(sc->sc_dmamem_ucd);
531b3b05a10Smglocker 	ucd += slot;
5322095c737Smglocker 	memset(ucd, 0, sizeof(*ucd));
5332095c737Smglocker 
5342095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2f) */
5352095c737Smglocker 	ucd->cmd.hdr.tc = UPIU_TC_I2T_NOP_OUT;
5362095c737Smglocker 	ucd->cmd.hdr.flags = 0;
5372095c737Smglocker 	ucd->cmd.hdr.lun = 0;
53838304948Smglocker 	ucd->cmd.hdr.task_tag = slot;
5392095c737Smglocker 	ucd->cmd.hdr.cmd_set_type = 0; /* SCSI command */
5402095c737Smglocker 	ucd->cmd.hdr.query = 0;
5412095c737Smglocker 	ucd->cmd.hdr.response = 0;
5422095c737Smglocker 	ucd->cmd.hdr.status = 0;
5432095c737Smglocker 	ucd->cmd.hdr.ehs_len = 0;
5442095c737Smglocker 	ucd->cmd.hdr.device_info = 0;
5452095c737Smglocker 	ucd->cmd.hdr.ds_len = 0;
5462095c737Smglocker 
5472095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2g) */
5482095c737Smglocker 	/* Already done with above memset */
5492095c737Smglocker 
5502095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 3) */
5512095c737Smglocker 	dva = UFSHCI_DMA_DVA(sc->sc_dmamem_ucd);
5526920fd9bSmglocker 	DPRINTF(3, "%s: ucd dva=%llu\n", __func__, dva);
5532095c737Smglocker 	utrd->dw4 = (uint32_t)dva;
5542095c737Smglocker 	utrd->dw5 = (uint32_t)(dva >> 32);
5552095c737Smglocker 
5562095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 4) */
5572095c737Smglocker 	off = sizeof(struct upiu_command) / 4; /* DWORD offset */
5582095c737Smglocker 	utrd->dw6 = UFSHCI_UTRD_DW6_RUO(off);
5592095c737Smglocker 
5602095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 5) */
5612095c737Smglocker 	len = sizeof(struct upiu_response) / 4; /* DWORD length */
5622095c737Smglocker 	utrd->dw6 |= UFSHCI_UTRD_DW6_RUL(len);
5632095c737Smglocker 
5642095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 6) */
5652095c737Smglocker 	off = (sizeof(struct upiu_command) + sizeof(struct upiu_response)) / 4;
5662095c737Smglocker 	utrd->dw7 = UFSHCI_UTRD_DW7_PRDTO(off);
5672095c737Smglocker 
5682095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 7) */
5692095c737Smglocker 	utrd->dw7 |= UFSHCI_UTRD_DW7_PRDTL(0); /* No data xfer */
5702095c737Smglocker 
5712095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 9) */
5722095c737Smglocker 	if (UFSHCI_READ_4(sc, UFSHCI_REG_UTRLRSR) != 1) {
5732095c737Smglocker 		printf("%s: %s: UTRLRSR not set\n",
5742095c737Smglocker 		    sc->sc_dev.dv_xname, __func__);
5752095c737Smglocker 		return -1;
5762095c737Smglocker 	}
5772095c737Smglocker 
5783bc7f528Smglocker 	bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_utrd),
5793bc7f528Smglocker 	    sizeof(*utrd) * slot, sizeof(*utrd), BUS_DMASYNC_PREWRITE);
5803bc7f528Smglocker 	bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_ucd),
5813bc7f528Smglocker 	    sizeof(*ucd) * slot, sizeof(*ucd), BUS_DMASYNC_PREWRITE);
5823bc7f528Smglocker 
5832095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 14) */
58412f70f1cSmglocker 	ccb->ccb_status = CCB_STATUS_INPROGRESS;
58512f70f1cSmglocker 	ufshci_doorbell_write(sc, slot);
5862095c737Smglocker 
5872095c737Smglocker 	return 0;
5882095c737Smglocker }
5892095c737Smglocker 
5902095c737Smglocker int
5912095c737Smglocker ufshci_utr_cmd_lun(struct ufshci_softc *sc, struct ufshci_ccb *ccb,
59244c52867Smglocker     struct scsi_xfer *xs)
5932095c737Smglocker {
5942095c737Smglocker 	int slot, off, len, i;
5952095c737Smglocker 	uint64_t dva;
5962095c737Smglocker 	struct ufshci_utrd *utrd;
5972095c737Smglocker 	struct ufshci_ucd *ucd;
5982095c737Smglocker 	bus_dmamap_t dmap = ccb->ccb_dmamap;
5992095c737Smglocker 
6002095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 1) */
60112f70f1cSmglocker 	slot = ccb->ccb_slot;
602b3b05a10Smglocker 	utrd = UFSHCI_DMA_KVA(sc->sc_dmamem_utrd);
603b3b05a10Smglocker 	utrd += slot;
6042095c737Smglocker 	memset(utrd, 0, sizeof(*utrd));
6056920fd9bSmglocker 	DPRINTF(3, "%s: slot=%d\n", __func__, slot);
6062095c737Smglocker 
6072095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2a) */
6082095c737Smglocker 	utrd->dw0 = UFSHCI_UTRD_DW0_CT_UFS;
6092095c737Smglocker 
6102095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2b) */
6112095c737Smglocker 	utrd->dw0 |= UFSHCI_UTRD_DW0_DD_T2I;
6122095c737Smglocker 
6132095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2c) */
614*ceedf4ccSmglocker         if (sc->sc_flags & UFSHCI_FLAGS_AGGR_INTR)
6152095c737Smglocker 		utrd->dw0 |= UFSHCI_UTRD_DW0_I_REG;
616*ceedf4ccSmglocker         else
617*ceedf4ccSmglocker 		utrd->dw0 |= UFSHCI_UTRD_DW0_I_INT;
6182095c737Smglocker 
6192095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2d) */
6202095c737Smglocker 	utrd->dw2 = UFSHCI_UTRD_DW2_OCS_IOV;
6212095c737Smglocker 
6222095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2e) */
623b3b05a10Smglocker 	ucd = UFSHCI_DMA_KVA(sc->sc_dmamem_ucd);
624b3b05a10Smglocker 	ucd += slot;
6252095c737Smglocker 	memset(ucd, 0, sizeof(*ucd));
6262095c737Smglocker 
6272095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2f) */
6282095c737Smglocker 	ucd->cmd.hdr.tc = UPIU_TC_I2T_COMMAND;
6292095c737Smglocker 	ucd->cmd.hdr.flags = (1 << 6); /* Bit-5 = Write, Bit-6 = Read */
6302095c737Smglocker 	ucd->cmd.hdr.lun = 0;
63138304948Smglocker 	ucd->cmd.hdr.task_tag = slot;
6322095c737Smglocker 	ucd->cmd.hdr.cmd_set_type = 0; /* SCSI command */
6332095c737Smglocker 	ucd->cmd.hdr.query = 0;
6342095c737Smglocker 	ucd->cmd.hdr.response = 0;
6352095c737Smglocker 	ucd->cmd.hdr.status = 0;
6362095c737Smglocker 	ucd->cmd.hdr.ehs_len = 0;
6372095c737Smglocker 	ucd->cmd.hdr.device_info = 0;
6382095c737Smglocker 	ucd->cmd.hdr.ds_len = 0;
6392095c737Smglocker 
64044c52867Smglocker 	ucd->cmd.expected_xfer_len = htobe32(xs->datalen);
6412095c737Smglocker 
6422095c737Smglocker 	ucd->cmd.cdb[0] = REPORT_LUNS;
6432095c737Smglocker 	ucd->cmd.cdb[6] = 0;
6442095c737Smglocker 	ucd->cmd.cdb[7] = 0;
6452095c737Smglocker 	ucd->cmd.cdb[8] = 0;
64644c52867Smglocker 	ucd->cmd.cdb[9] = xs->datalen;
6472095c737Smglocker 
6482095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2g) */
6492095c737Smglocker 	/* Already done with above memset */
6502095c737Smglocker 
6512095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 3) */
6522095c737Smglocker 	dva = UFSHCI_DMA_DVA(sc->sc_dmamem_ucd);
6536920fd9bSmglocker 	DPRINTF(3, "%s: ucd dva=%llu\n", __func__, dva);
6542095c737Smglocker 	utrd->dw4 = (uint32_t)dva;
6552095c737Smglocker 	utrd->dw5 = (uint32_t)(dva >> 32);
6562095c737Smglocker 
6572095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 4) */
6582095c737Smglocker 	off = sizeof(struct upiu_command) / 4; /* DWORD offset */
6592095c737Smglocker 	utrd->dw6 = UFSHCI_UTRD_DW6_RUO(off);
6602095c737Smglocker 
6612095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 5) */
6622095c737Smglocker 	len = sizeof(struct upiu_response) / 4; /* DWORD length */
6632095c737Smglocker 	utrd->dw6 |= UFSHCI_UTRD_DW6_RUL(len);
6642095c737Smglocker 
6652095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 6) */
6662095c737Smglocker 	off = (sizeof(struct upiu_command) + sizeof(struct upiu_response)) / 4;
6672095c737Smglocker 	utrd->dw7 = UFSHCI_UTRD_DW7_PRDTO(off);
6682095c737Smglocker 
6692095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 7) */
6702095c737Smglocker 	utrd->dw7 |= UFSHCI_UTRD_DW7_PRDTL(dmap->dm_nsegs);
6712095c737Smglocker 
6722095c737Smglocker 	/* Build PRDT data segment. */
6732095c737Smglocker 	for (i = 0; i < dmap->dm_nsegs; i++) {
6742095c737Smglocker 		dva = dmap->dm_segs[i].ds_addr;
6752095c737Smglocker 		ucd->prdt[i].dw0 = (uint32_t)dva;
6762095c737Smglocker 		ucd->prdt[i].dw1 = (uint32_t)(dva >> 32);
6772095c737Smglocker 		ucd->prdt[i].dw2 = 0;
6782095c737Smglocker 		ucd->prdt[i].dw3 = dmap->dm_segs[i].ds_len - 1;
6792095c737Smglocker 	}
6802095c737Smglocker 
6812095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 9) */
6822095c737Smglocker 	if (UFSHCI_READ_4(sc, UFSHCI_REG_UTRLRSR) != 1) {
6832095c737Smglocker 		printf("%s: %s: UTRLRSR not set\n",
6842095c737Smglocker 		    sc->sc_dev.dv_xname, __func__);
6852095c737Smglocker 		return -1;
6862095c737Smglocker 	}
6872095c737Smglocker 
6883bc7f528Smglocker 	bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_utrd),
6893bc7f528Smglocker 	    sizeof(*utrd) * slot, sizeof(*utrd), BUS_DMASYNC_PREWRITE);
6903bc7f528Smglocker 	bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_ucd),
6913bc7f528Smglocker 	    sizeof(*ucd) * slot, sizeof(*ucd), BUS_DMASYNC_PREWRITE);
6923bc7f528Smglocker 
6932095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 14) */
69412f70f1cSmglocker 	ccb->ccb_status = CCB_STATUS_INPROGRESS;
69512f70f1cSmglocker 	ufshci_doorbell_write(sc, slot);
6962095c737Smglocker 
6972095c737Smglocker 	return 0;
6982095c737Smglocker }
6992095c737Smglocker 
7002095c737Smglocker int
7012095c737Smglocker ufshci_utr_cmd_inquiry(struct ufshci_softc *sc, struct ufshci_ccb *ccb,
70244c52867Smglocker     struct scsi_xfer *xs)
7032095c737Smglocker {
7042095c737Smglocker 	int slot, off, len, i;
7052095c737Smglocker 	uint64_t dva;
7062095c737Smglocker 	struct ufshci_utrd *utrd;
7072095c737Smglocker 	struct ufshci_ucd *ucd;
7082095c737Smglocker 	bus_dmamap_t dmap = ccb->ccb_dmamap;
7092095c737Smglocker 
7102095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 1) */
71112f70f1cSmglocker 	slot = ccb->ccb_slot;
712b3b05a10Smglocker 	utrd = UFSHCI_DMA_KVA(sc->sc_dmamem_utrd);
713b3b05a10Smglocker 	utrd += slot;
7142095c737Smglocker 	memset(utrd, 0, sizeof(*utrd));
7156920fd9bSmglocker 	DPRINTF(3, "%s: slot=%d\n", __func__, slot);
7162095c737Smglocker 
7172095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2a) */
7182095c737Smglocker 	utrd->dw0 = UFSHCI_UTRD_DW0_CT_UFS;
7192095c737Smglocker 
7202095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2b) */
7212095c737Smglocker 	utrd->dw0 |= UFSHCI_UTRD_DW0_DD_T2I;
7222095c737Smglocker 
7232095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2c) */
724*ceedf4ccSmglocker         if (sc->sc_flags & UFSHCI_FLAGS_AGGR_INTR)
7252095c737Smglocker 		utrd->dw0 |= UFSHCI_UTRD_DW0_I_REG;
726*ceedf4ccSmglocker         else
727*ceedf4ccSmglocker 		utrd->dw0 |= UFSHCI_UTRD_DW0_I_INT;
7282095c737Smglocker 
7292095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2d) */
7302095c737Smglocker 	utrd->dw2 = UFSHCI_UTRD_DW2_OCS_IOV;
7312095c737Smglocker 
7322095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2e) */
733b3b05a10Smglocker 	ucd = UFSHCI_DMA_KVA(sc->sc_dmamem_ucd);
734b3b05a10Smglocker 	ucd += slot;
7352095c737Smglocker 	memset(ucd, 0, sizeof(*ucd));
7362095c737Smglocker 
7372095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2f) */
7382095c737Smglocker 	ucd->cmd.hdr.tc = UPIU_TC_I2T_COMMAND;
7392095c737Smglocker 	ucd->cmd.hdr.flags = (1 << 6); /* Bit-5 = Write, Bit-6 = Read */
7402095c737Smglocker 	ucd->cmd.hdr.lun = 0;
74138304948Smglocker 	ucd->cmd.hdr.task_tag = slot;
7422095c737Smglocker 	ucd->cmd.hdr.cmd_set_type = 0; /* SCSI command */
7432095c737Smglocker 	ucd->cmd.hdr.query = 0;
7442095c737Smglocker 	ucd->cmd.hdr.response = 0;
7452095c737Smglocker 	ucd->cmd.hdr.status = 0;
7462095c737Smglocker 	ucd->cmd.hdr.ehs_len = 0;
7472095c737Smglocker 	ucd->cmd.hdr.device_info = 0;
7482095c737Smglocker 	ucd->cmd.hdr.ds_len = 0;
7492095c737Smglocker 
75044c52867Smglocker 	ucd->cmd.expected_xfer_len = htobe32(xs->datalen);
7512095c737Smglocker 
7522095c737Smglocker 	ucd->cmd.cdb[0] = INQUIRY; /* 0x12 */
7532095c737Smglocker 	ucd->cmd.cdb[3] = 0;
75444c52867Smglocker 	ucd->cmd.cdb[4] = xs->datalen;
7552095c737Smglocker 
7562095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2g) */
7572095c737Smglocker 	/* Already done with above memset */
7582095c737Smglocker 
7592095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 3) */
7602095c737Smglocker 	dva = UFSHCI_DMA_DVA(sc->sc_dmamem_ucd) + (sizeof(*ucd) * slot);
7616920fd9bSmglocker 	DPRINTF(3, "%s: ucd dva=%llu\n", __func__, dva);
7622095c737Smglocker 	utrd->dw4 = (uint32_t)dva;
7632095c737Smglocker 	utrd->dw5 = (uint32_t)(dva >> 32);
7642095c737Smglocker 
7652095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 4) */
7662095c737Smglocker 	off = sizeof(struct upiu_command) / 4; /* DWORD offset */
7672095c737Smglocker 	utrd->dw6 = UFSHCI_UTRD_DW6_RUO(off);
7682095c737Smglocker 
7692095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 5) */
7702095c737Smglocker 	len = sizeof(struct upiu_response) / 4; /* DWORD length */
7712095c737Smglocker 	utrd->dw6 |= UFSHCI_UTRD_DW6_RUL(len);
7722095c737Smglocker 
7732095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 6) */
7742095c737Smglocker 	off = (sizeof(struct upiu_command) + sizeof(struct upiu_response)) / 4;
7752095c737Smglocker 	utrd->dw7 = UFSHCI_UTRD_DW7_PRDTO(off);
7762095c737Smglocker 
7772095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 7) */
7782095c737Smglocker 	utrd->dw7 |= UFSHCI_UTRD_DW7_PRDTL(dmap->dm_nsegs);
7792095c737Smglocker 
7802095c737Smglocker 	/* Build PRDT data segment. */
7812095c737Smglocker 	for (i = 0; i < dmap->dm_nsegs; i++) {
7822095c737Smglocker 		dva = dmap->dm_segs[i].ds_addr;
7832095c737Smglocker 		ucd->prdt[i].dw0 = (uint32_t)dva;
7842095c737Smglocker 		ucd->prdt[i].dw1 = (uint32_t)(dva >> 32);
7852095c737Smglocker 		ucd->prdt[i].dw2 = 0;
7862095c737Smglocker 		ucd->prdt[i].dw3 = dmap->dm_segs[i].ds_len - 1;
7872095c737Smglocker 	}
7882095c737Smglocker 
7892095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 9) */
7902095c737Smglocker 	if (UFSHCI_READ_4(sc, UFSHCI_REG_UTRLRSR) != 1) {
7912095c737Smglocker 		printf("%s: %s: UTRLRSR not set\n",
7922095c737Smglocker 		    sc->sc_dev.dv_xname, __func__);
7932095c737Smglocker 		return -1;
7942095c737Smglocker 	}
7952095c737Smglocker 
7963bc7f528Smglocker 	bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_utrd),
7973bc7f528Smglocker 	    sizeof(*utrd) * slot, sizeof(*utrd), BUS_DMASYNC_PREWRITE);
7983bc7f528Smglocker 	bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_ucd),
7993bc7f528Smglocker 	    sizeof(*ucd) * slot, sizeof(*ucd), BUS_DMASYNC_PREWRITE);
8003bc7f528Smglocker 
8012095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 14) */
80212f70f1cSmglocker 	ccb->ccb_status = CCB_STATUS_INPROGRESS;
80312f70f1cSmglocker 	ufshci_doorbell_write(sc, slot);
8042095c737Smglocker 
8052095c737Smglocker 	return slot;
8062095c737Smglocker }
8072095c737Smglocker 
8082095c737Smglocker int
8092095c737Smglocker ufshci_utr_cmd_capacity16(struct ufshci_softc *sc, struct ufshci_ccb *ccb,
81044c52867Smglocker     struct scsi_xfer *xs)
8112095c737Smglocker {
8122095c737Smglocker 	int slot, off, len, i;
8132095c737Smglocker 	uint64_t dva;
8142095c737Smglocker 	struct ufshci_utrd *utrd;
8152095c737Smglocker 	struct ufshci_ucd *ucd;
8162095c737Smglocker 	bus_dmamap_t dmap = ccb->ccb_dmamap;
8172095c737Smglocker 
8182095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 1) */
81912f70f1cSmglocker 	slot = ccb->ccb_slot;
820b3b05a10Smglocker 	utrd = UFSHCI_DMA_KVA(sc->sc_dmamem_utrd);
821b3b05a10Smglocker 	utrd += slot;
8222095c737Smglocker 	memset(utrd, 0, sizeof(*utrd));
8236920fd9bSmglocker 	DPRINTF(3, "%s: slot=%d\n", __func__, slot);
8242095c737Smglocker 
8252095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2a) */
8262095c737Smglocker 	utrd->dw0 = UFSHCI_UTRD_DW0_CT_UFS;
8272095c737Smglocker 
8282095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2b) */
8292095c737Smglocker 	utrd->dw0 |= UFSHCI_UTRD_DW0_DD_T2I;
8302095c737Smglocker 
8312095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2c) */
832*ceedf4ccSmglocker         if (sc->sc_flags & UFSHCI_FLAGS_AGGR_INTR)
8332095c737Smglocker 		utrd->dw0 |= UFSHCI_UTRD_DW0_I_REG;
834*ceedf4ccSmglocker         else
835*ceedf4ccSmglocker 		utrd->dw0 |= UFSHCI_UTRD_DW0_I_INT;
8362095c737Smglocker 
8372095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2d) */
8382095c737Smglocker 	utrd->dw2 = UFSHCI_UTRD_DW2_OCS_IOV;
8392095c737Smglocker 
8402095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2e) */
841b3b05a10Smglocker 	ucd = UFSHCI_DMA_KVA(sc->sc_dmamem_ucd);
842b3b05a10Smglocker 	ucd += slot;
8432095c737Smglocker 	memset(ucd, 0, sizeof(*ucd));
8442095c737Smglocker 
8452095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2f) */
8462095c737Smglocker 	ucd->cmd.hdr.tc = UPIU_TC_I2T_COMMAND;
8472095c737Smglocker 	ucd->cmd.hdr.flags = (1 << 6); /* Bit-5 = Write, Bit-6 = Read */
8482095c737Smglocker 	ucd->cmd.hdr.lun = 0;
84938304948Smglocker 	ucd->cmd.hdr.task_tag = slot;
8502095c737Smglocker 	ucd->cmd.hdr.cmd_set_type = 0; /* SCSI command */
8512095c737Smglocker 	ucd->cmd.hdr.query = 0;
8522095c737Smglocker 	ucd->cmd.hdr.response = 0;
8532095c737Smglocker 	ucd->cmd.hdr.status = 0;
8542095c737Smglocker 	ucd->cmd.hdr.ehs_len = 0;
8552095c737Smglocker 	ucd->cmd.hdr.device_info = 0;
8562095c737Smglocker 	ucd->cmd.hdr.ds_len = 0;
8572095c737Smglocker 
85844c52867Smglocker 	ucd->cmd.expected_xfer_len = htobe32(xs->datalen);
8592095c737Smglocker 
8602095c737Smglocker 	ucd->cmd.cdb[0] = READ_CAPACITY_16; /* 0x9e */
8612095c737Smglocker 	ucd->cmd.cdb[1] = 0x10; /* Service Action */
8622095c737Smglocker 	/* Logical Block Address = 0 for UFS */
8632095c737Smglocker 	ucd->cmd.cdb[10] = 0;
8642095c737Smglocker 	ucd->cmd.cdb[11] = 0;
8652095c737Smglocker 	ucd->cmd.cdb[12] = 0;
86644c52867Smglocker 	ucd->cmd.cdb[13] = xs->datalen;
8672095c737Smglocker 
8682095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2g) */
8692095c737Smglocker 	/* Already done with above memset */
8702095c737Smglocker 
8712095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 3) */
8722095c737Smglocker 	dva = UFSHCI_DMA_DVA(sc->sc_dmamem_ucd) + (sizeof(*ucd) * slot);
8736920fd9bSmglocker 	DPRINTF(3, "%s: ucd dva=%llu\n", __func__, dva);
8742095c737Smglocker 	utrd->dw4 = (uint32_t)dva;
8752095c737Smglocker 	utrd->dw5 = (uint32_t)(dva >> 32);
8762095c737Smglocker 
8772095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 4) */
8782095c737Smglocker 	off = sizeof(struct upiu_command) / 4; /* DWORD offset */
8792095c737Smglocker 	utrd->dw6 = UFSHCI_UTRD_DW6_RUO(off);
8802095c737Smglocker 
8812095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 5) */
8822095c737Smglocker 	len = sizeof(struct upiu_response) / 4; /* DWORD length */
8832095c737Smglocker 	utrd->dw6 |= UFSHCI_UTRD_DW6_RUL(len);
8842095c737Smglocker 
8852095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 6) */
8862095c737Smglocker 	off = (sizeof(struct upiu_command) + sizeof(struct upiu_response)) / 4;
8872095c737Smglocker 	utrd->dw7 = UFSHCI_UTRD_DW7_PRDTO(off);
8882095c737Smglocker 
8892095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 7) */
8902095c737Smglocker 	utrd->dw7 |= UFSHCI_UTRD_DW7_PRDTL(dmap->dm_nsegs);
8912095c737Smglocker 
8922095c737Smglocker 	/* Build PRDT data segment. */
8932095c737Smglocker 	for (i = 0; i < dmap->dm_nsegs; i++) {
8942095c737Smglocker 		dva = dmap->dm_segs[i].ds_addr;
8952095c737Smglocker 		ucd->prdt[i].dw0 = (uint32_t)dva;
8962095c737Smglocker 		ucd->prdt[i].dw1 = (uint32_t)(dva >> 32);
8972095c737Smglocker 		ucd->prdt[i].dw2 = 0;
8982095c737Smglocker 		ucd->prdt[i].dw3 = dmap->dm_segs[i].ds_len - 1;
8992095c737Smglocker 	}
9002095c737Smglocker 
9012095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 9) */
9022095c737Smglocker 	if (UFSHCI_READ_4(sc, UFSHCI_REG_UTRLRSR) != 1) {
9032095c737Smglocker 		printf("%s: %s: UTRLRSR not set\n",
9042095c737Smglocker 		    sc->sc_dev.dv_xname, __func__);
9052095c737Smglocker 		return -1;
9062095c737Smglocker 	}
9072095c737Smglocker 
9083bc7f528Smglocker 	bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_utrd),
9093bc7f528Smglocker 	    sizeof(*utrd) * slot, sizeof(*utrd), BUS_DMASYNC_PREWRITE);
9103bc7f528Smglocker 	bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_ucd),
9113bc7f528Smglocker 	    sizeof(*ucd) * slot, sizeof(*ucd), BUS_DMASYNC_PREWRITE);
9123bc7f528Smglocker 
9132095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 14) */
91412f70f1cSmglocker 	ccb->ccb_status = CCB_STATUS_INPROGRESS;
91512f70f1cSmglocker 	ufshci_doorbell_write(sc, slot);
9162095c737Smglocker 
9172095c737Smglocker 	return slot;
9182095c737Smglocker }
9192095c737Smglocker 
9202095c737Smglocker int
9212095c737Smglocker ufshci_utr_cmd_capacity(struct ufshci_softc *sc, struct ufshci_ccb *ccb,
92244c52867Smglocker     struct scsi_xfer *xs)
9232095c737Smglocker {
9242095c737Smglocker 	int slot, off, len, i;
9252095c737Smglocker 	uint64_t dva;
9262095c737Smglocker 	struct ufshci_utrd *utrd;
9272095c737Smglocker 	struct ufshci_ucd *ucd;
9282095c737Smglocker 	bus_dmamap_t dmap = ccb->ccb_dmamap;
9292095c737Smglocker 
9302095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 1) */
93112f70f1cSmglocker 	slot = ccb->ccb_slot;
932b3b05a10Smglocker 	utrd = UFSHCI_DMA_KVA(sc->sc_dmamem_utrd);
933b3b05a10Smglocker 	utrd += slot;
9342095c737Smglocker 	memset(utrd, 0, sizeof(*utrd));
9356920fd9bSmglocker 	DPRINTF(3, "%s: slot=%d\n", __func__, slot);
9362095c737Smglocker 
9372095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2a) */
9382095c737Smglocker 	utrd->dw0 = UFSHCI_UTRD_DW0_CT_UFS;
9392095c737Smglocker 
9402095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2b) */
9412095c737Smglocker 	utrd->dw0 |= UFSHCI_UTRD_DW0_DD_T2I;
9422095c737Smglocker 
9432095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2c) */
944*ceedf4ccSmglocker         if (sc->sc_flags & UFSHCI_FLAGS_AGGR_INTR)
9452095c737Smglocker 		utrd->dw0 |= UFSHCI_UTRD_DW0_I_REG;
946*ceedf4ccSmglocker         else
947*ceedf4ccSmglocker 		utrd->dw0 |= UFSHCI_UTRD_DW0_I_INT;
9482095c737Smglocker 
9492095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2d) */
9502095c737Smglocker 	utrd->dw2 = UFSHCI_UTRD_DW2_OCS_IOV;
9512095c737Smglocker 
9522095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2e) */
953b3b05a10Smglocker 	ucd = UFSHCI_DMA_KVA(sc->sc_dmamem_ucd);
954b3b05a10Smglocker 	ucd += slot;
9552095c737Smglocker 	memset(ucd, 0, sizeof(*ucd));
9562095c737Smglocker 
9572095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2f) */
9582095c737Smglocker 	ucd->cmd.hdr.tc = UPIU_TC_I2T_COMMAND;
9592095c737Smglocker 	ucd->cmd.hdr.flags = (1 << 6); /* Bit-5 = Write, Bit-6 = Read */
9602095c737Smglocker 	ucd->cmd.hdr.lun = 0;
96138304948Smglocker 	ucd->cmd.hdr.task_tag = slot;
9622095c737Smglocker 	ucd->cmd.hdr.cmd_set_type = 0; /* SCSI command */
9632095c737Smglocker 	ucd->cmd.hdr.query = 0;
9642095c737Smglocker 	ucd->cmd.hdr.response = 0;
9652095c737Smglocker 	ucd->cmd.hdr.status = 0;
9662095c737Smglocker 	ucd->cmd.hdr.ehs_len = 0;
9672095c737Smglocker 	ucd->cmd.hdr.device_info = 0;
9682095c737Smglocker 	ucd->cmd.hdr.ds_len = 0;
9692095c737Smglocker 
97044c52867Smglocker 	ucd->cmd.expected_xfer_len = htobe32(xs->datalen);
9712095c737Smglocker 
9722095c737Smglocker 	ucd->cmd.cdb[0] = READ_CAPACITY; /* 0x25 */
9732095c737Smglocker 	/* Logical Block Address = 0 for UFS */
9742095c737Smglocker 	ucd->cmd.cdb[2] = 0;
9752095c737Smglocker 	ucd->cmd.cdb[3] = 0;
9762095c737Smglocker 	ucd->cmd.cdb[4] = 0;
9772095c737Smglocker 	ucd->cmd.cdb[5] = 0;
9782095c737Smglocker 
9792095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2g) */
9802095c737Smglocker 	/* Already done with above memset */
9812095c737Smglocker 
9822095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 3) */
9832095c737Smglocker 	dva = UFSHCI_DMA_DVA(sc->sc_dmamem_ucd) + (sizeof(*ucd) * slot);
9846920fd9bSmglocker 	DPRINTF(3, "%s: ucd dva=%llu\n", __func__, dva);
9852095c737Smglocker 	utrd->dw4 = (uint32_t)dva;
9862095c737Smglocker 	utrd->dw5 = (uint32_t)(dva >> 32);
9872095c737Smglocker 
9882095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 4) */
9892095c737Smglocker 	off = sizeof(struct upiu_command) / 4; /* DWORD offset */
9902095c737Smglocker 	utrd->dw6 = UFSHCI_UTRD_DW6_RUO(off);
9912095c737Smglocker 
9922095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 5) */
9932095c737Smglocker 	len = sizeof(struct upiu_response) / 4; /* DWORD length */
9942095c737Smglocker 	utrd->dw6 |= UFSHCI_UTRD_DW6_RUL(len);
9952095c737Smglocker 
9962095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 6) */
9972095c737Smglocker 	off = (sizeof(struct upiu_command) + sizeof(struct upiu_response)) / 4;
9982095c737Smglocker 	utrd->dw7 = UFSHCI_UTRD_DW7_PRDTO(off);
9992095c737Smglocker 
10002095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 7) */
10012095c737Smglocker 	utrd->dw7 |= UFSHCI_UTRD_DW7_PRDTL(dmap->dm_nsegs);
10022095c737Smglocker 
10032095c737Smglocker 	/* Build PRDT data segment. */
10042095c737Smglocker 	for (i = 0; i < dmap->dm_nsegs; i++) {
10052095c737Smglocker 		dva = dmap->dm_segs[i].ds_addr;
10062095c737Smglocker 		ucd->prdt[i].dw0 = (uint32_t)dva;
10072095c737Smglocker 		ucd->prdt[i].dw1 = (uint32_t)(dva >> 32);
10082095c737Smglocker 		ucd->prdt[i].dw2 = 0;
10092095c737Smglocker 		ucd->prdt[i].dw3 = dmap->dm_segs[i].ds_len - 1;
10102095c737Smglocker 	}
10112095c737Smglocker 
10122095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 9) */
10132095c737Smglocker 	if (UFSHCI_READ_4(sc, UFSHCI_REG_UTRLRSR) != 1) {
10142095c737Smglocker 		printf("%s: %s: UTRLRSR not set\n",
10152095c737Smglocker 		    sc->sc_dev.dv_xname, __func__);
10162095c737Smglocker 		return -1;
10172095c737Smglocker 	}
10182095c737Smglocker 
10193bc7f528Smglocker 	bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_utrd),
10203bc7f528Smglocker 	    sizeof(*utrd) * slot, sizeof(*utrd), BUS_DMASYNC_PREWRITE);
10213bc7f528Smglocker 	bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_ucd),
10223bc7f528Smglocker 	    sizeof(*ucd) * slot, sizeof(*ucd), BUS_DMASYNC_PREWRITE);
10233bc7f528Smglocker 
10242095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 14) */
102512f70f1cSmglocker 	ccb->ccb_status = CCB_STATUS_INPROGRESS;
102612f70f1cSmglocker 	ufshci_doorbell_write(sc, slot);
10272095c737Smglocker 
10282095c737Smglocker 	return slot;
10292095c737Smglocker }
10302095c737Smglocker 
10312095c737Smglocker int
1032a2f0dcb2Smglocker ufshci_utr_cmd_io(struct ufshci_softc *sc, struct ufshci_ccb *ccb,
1033a2f0dcb2Smglocker     struct scsi_xfer *xs, int dir)
10342095c737Smglocker {
10352095c737Smglocker 	int slot, off, len, i;
10362095c737Smglocker 	uint64_t dva;
10372095c737Smglocker 	struct ufshci_utrd *utrd;
10382095c737Smglocker 	struct ufshci_ucd *ucd;
10392095c737Smglocker 	bus_dmamap_t dmap = ccb->ccb_dmamap;
1040a9129097Smglocker 	uint32_t blocks;
1041a9129097Smglocker 	uint64_t lba;
10422095c737Smglocker 
10432095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 1) */
104412f70f1cSmglocker 	slot = ccb->ccb_slot;
1045b3b05a10Smglocker 	utrd = UFSHCI_DMA_KVA(sc->sc_dmamem_utrd);
1046b3b05a10Smglocker 	utrd += slot;
10472095c737Smglocker 	memset(utrd, 0, sizeof(*utrd));
10486920fd9bSmglocker 	DPRINTF(3, "%s: slot=%d\n", __func__, slot);
10492095c737Smglocker 
10502095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2a) */
10512095c737Smglocker 	utrd->dw0 = UFSHCI_UTRD_DW0_CT_UFS;
10522095c737Smglocker 
10532095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2b) */
1054a2f0dcb2Smglocker 	if (dir == SCSI_DATA_IN)
10552095c737Smglocker 		utrd->dw0 |= UFSHCI_UTRD_DW0_DD_T2I;
1056a2f0dcb2Smglocker 	else
10572095c737Smglocker 		utrd->dw0 |= UFSHCI_UTRD_DW0_DD_I2T;
10582095c737Smglocker 
10592095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2c) */
1060*ceedf4ccSmglocker         if (sc->sc_flags & UFSHCI_FLAGS_AGGR_INTR)
10612095c737Smglocker 		utrd->dw0 |= UFSHCI_UTRD_DW0_I_REG;
1062*ceedf4ccSmglocker         else
1063*ceedf4ccSmglocker 		utrd->dw0 |= UFSHCI_UTRD_DW0_I_INT;
10642095c737Smglocker 
10652095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2d) */
10662095c737Smglocker 	utrd->dw2 = UFSHCI_UTRD_DW2_OCS_IOV;
10672095c737Smglocker 
10682095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2e) */
1069b3b05a10Smglocker 	ucd = UFSHCI_DMA_KVA(sc->sc_dmamem_ucd);
1070b3b05a10Smglocker 	ucd += slot;
10712095c737Smglocker 	memset(ucd, 0, sizeof(*ucd));
10722095c737Smglocker 
10732095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2f) */
10742095c737Smglocker 	ucd->cmd.hdr.tc = UPIU_TC_I2T_COMMAND;
1075a2f0dcb2Smglocker 	if (dir == SCSI_DATA_IN)
1076a2f0dcb2Smglocker 		ucd->cmd.hdr.flags = (1 << 6); /* Bit-6 = Read */
1077a2f0dcb2Smglocker 	else
1078a2f0dcb2Smglocker 		ucd->cmd.hdr.flags = (1 << 5); /* Bit-5 = Write */
10792095c737Smglocker 	ucd->cmd.hdr.lun = 0;
108038304948Smglocker 	ucd->cmd.hdr.task_tag = slot;
10812095c737Smglocker 	ucd->cmd.hdr.cmd_set_type = 0; /* SCSI command */
10822095c737Smglocker 	ucd->cmd.hdr.query = 0;
10832095c737Smglocker 	ucd->cmd.hdr.response = 0;
10842095c737Smglocker 	ucd->cmd.hdr.status = 0;
10852095c737Smglocker 	ucd->cmd.hdr.ehs_len = 0;
10862095c737Smglocker 	ucd->cmd.hdr.device_info = 0;
10872095c737Smglocker 	ucd->cmd.hdr.ds_len = 0;
10882095c737Smglocker 
1089a9129097Smglocker 	/*
1090a9129097Smglocker 	 * JESD220C-2_1.pdf, page 88, d) Expected Data Transfer Length:
1091a9129097Smglocker 	 * "When the COMMAND UPIU encodes a SCSI WRITE or SCSI READ command
1092a9129097Smglocker 	 * (specifically WRITE (6), READ (6), WRITE (10), READ (10),
1093a9129097Smglocker 	 * WRITE (16), or READ (16)), the value of this field shall be the
1094a9129097Smglocker 	 * product of the Logical Block Size (bLogicalBlockSize) and the
1095a9129097Smglocker 	 * TRANSFER LENGTH field of the CDB."
1096a9129097Smglocker 	 */
1097a9129097Smglocker 	scsi_cmd_rw_decode(&xs->cmd, &lba, &blocks);
1098a9129097Smglocker 	ucd->cmd.expected_xfer_len = htobe32(UFSHCI_LBS * blocks);
10992095c737Smglocker 
1100a2f0dcb2Smglocker 	memcpy(ucd->cmd.cdb, &xs->cmd, sizeof(ucd->cmd.cdb));
11012095c737Smglocker 
11022095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2g) */
11032095c737Smglocker 	/* Already done with above memset */
11042095c737Smglocker 
11052095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 3) */
11062095c737Smglocker 	dva = UFSHCI_DMA_DVA(sc->sc_dmamem_ucd) + (sizeof(*ucd) * slot);
11076920fd9bSmglocker 	DPRINTF(3, "%s: ucd dva=%llu\n", __func__, dva);
11082095c737Smglocker 	utrd->dw4 = (uint32_t)dva;
11092095c737Smglocker 	utrd->dw5 = (uint32_t)(dva >> 32);
11102095c737Smglocker 
11112095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 4) */
11122095c737Smglocker 	off = sizeof(struct upiu_command) / 4; /* DWORD offset */
11132095c737Smglocker 	utrd->dw6 = UFSHCI_UTRD_DW6_RUO(off);
11142095c737Smglocker 
11152095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 5) */
11162095c737Smglocker 	len = sizeof(struct upiu_response) / 4; /* DWORD length */
11172095c737Smglocker 	utrd->dw6 |= UFSHCI_UTRD_DW6_RUL(len);
11182095c737Smglocker 
11192095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 6) */
11202095c737Smglocker 	off = (sizeof(struct upiu_command) + sizeof(struct upiu_response)) / 4;
11212095c737Smglocker 	utrd->dw7 = UFSHCI_UTRD_DW7_PRDTO(off);
11222095c737Smglocker 
11232095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 7) */
11242095c737Smglocker 	utrd->dw7 |= UFSHCI_UTRD_DW7_PRDTL(dmap->dm_nsegs);
11252095c737Smglocker 
11262095c737Smglocker 	/* Build PRDT data segment. */
11272095c737Smglocker 	for (i = 0; i < dmap->dm_nsegs; i++) {
11282095c737Smglocker 		dva = dmap->dm_segs[i].ds_addr;
11292095c737Smglocker 		ucd->prdt[i].dw0 = (uint32_t)dva;
11302095c737Smglocker 		ucd->prdt[i].dw1 = (uint32_t)(dva >> 32);
11312095c737Smglocker 		ucd->prdt[i].dw2 = 0;
11322095c737Smglocker 		ucd->prdt[i].dw3 = dmap->dm_segs[i].ds_len - 1;
11332095c737Smglocker 	}
11342095c737Smglocker 
11352095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 9) */
11362095c737Smglocker 	if (UFSHCI_READ_4(sc, UFSHCI_REG_UTRLRSR) != 1) {
11372095c737Smglocker 		printf("%s: %s: UTRLRSR not set\n",
11382095c737Smglocker 		    sc->sc_dev.dv_xname, __func__);
11392095c737Smglocker 		return -1;
11402095c737Smglocker 	}
11412095c737Smglocker 
11423bc7f528Smglocker 	bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_utrd),
11433bc7f528Smglocker 	    sizeof(*utrd) * slot, sizeof(*utrd), BUS_DMASYNC_PREWRITE);
11443bc7f528Smglocker 	bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_ucd),
11453bc7f528Smglocker 	    sizeof(*ucd) * slot, sizeof(*ucd), BUS_DMASYNC_PREWRITE);
11463bc7f528Smglocker 
11472095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 14) */
114812f70f1cSmglocker 	ccb->ccb_status = CCB_STATUS_INPROGRESS;
114912f70f1cSmglocker 	ufshci_doorbell_write(sc, slot);
11502095c737Smglocker 
11512095c737Smglocker 	return slot;
11522095c737Smglocker }
11532095c737Smglocker 
11542095c737Smglocker int
11552095c737Smglocker ufshci_utr_cmd_sync(struct ufshci_softc *sc, struct ufshci_ccb *ccb,
115644c52867Smglocker     struct scsi_xfer *xs, uint32_t lba, uint16_t blocks)
11572095c737Smglocker {
11582095c737Smglocker 	int slot, off, len;
11592095c737Smglocker 	uint64_t dva;
11602095c737Smglocker 	struct ufshci_utrd *utrd;
11612095c737Smglocker 	struct ufshci_ucd *ucd;
11622095c737Smglocker 
11632095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 1) */
116412f70f1cSmglocker 	slot = ccb->ccb_slot;
1165b3b05a10Smglocker 	utrd = UFSHCI_DMA_KVA(sc->sc_dmamem_utrd);
1166b3b05a10Smglocker 	utrd += slot;
11672095c737Smglocker 	memset(utrd, 0, sizeof(*utrd));
11686920fd9bSmglocker 	DPRINTF(3, "%s: slot=%d\n", __func__, slot);
11692095c737Smglocker 
11702095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2a) */
11712095c737Smglocker 	utrd->dw0 = UFSHCI_UTRD_DW0_CT_UFS;
11722095c737Smglocker 
11732095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2b) */
11742095c737Smglocker 	utrd->dw0 |= UFSHCI_UTRD_DW0_DD_I2T;
11752095c737Smglocker 
11762095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2c) */
1177*ceedf4ccSmglocker         if (sc->sc_flags & UFSHCI_FLAGS_AGGR_INTR)
11782095c737Smglocker 		utrd->dw0 |= UFSHCI_UTRD_DW0_I_REG;
1179*ceedf4ccSmglocker         else
1180*ceedf4ccSmglocker 		utrd->dw0 |= UFSHCI_UTRD_DW0_I_INT;
11812095c737Smglocker 
11822095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2d) */
11832095c737Smglocker 	utrd->dw2 = UFSHCI_UTRD_DW2_OCS_IOV;
11842095c737Smglocker 
11852095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2e) */
1186b3b05a10Smglocker 	ucd = UFSHCI_DMA_KVA(sc->sc_dmamem_ucd);
1187b3b05a10Smglocker 	ucd += slot;
11882095c737Smglocker 	memset(ucd, 0, sizeof(*ucd));
11892095c737Smglocker 
11902095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2f) */
11912095c737Smglocker 	ucd->cmd.hdr.tc = UPIU_TC_I2T_COMMAND;
11922095c737Smglocker 	ucd->cmd.hdr.flags = 0; /* No data transfer */
11932095c737Smglocker 	ucd->cmd.hdr.lun = 0;
119438304948Smglocker 	ucd->cmd.hdr.task_tag = slot;
11952095c737Smglocker 	ucd->cmd.hdr.cmd_set_type = 0; /* SCSI command */
11962095c737Smglocker 	ucd->cmd.hdr.query = 0;
11972095c737Smglocker 	ucd->cmd.hdr.response = 0;
11982095c737Smglocker 	ucd->cmd.hdr.status = 0;
11992095c737Smglocker 	ucd->cmd.hdr.ehs_len = 0;
12002095c737Smglocker 	ucd->cmd.hdr.device_info = 0;
12012095c737Smglocker 	ucd->cmd.hdr.ds_len = 0;
12022095c737Smglocker 
12032095c737Smglocker 	ucd->cmd.expected_xfer_len = htobe32(0); /* No data transfer */
12042095c737Smglocker 
12052095c737Smglocker 	ucd->cmd.cdb[0] = SYNCHRONIZE_CACHE; /* 0x35 */
12062095c737Smglocker 	ucd->cmd.cdb[2] = (lba >> 24) & 0xff;
12072095c737Smglocker 	ucd->cmd.cdb[3] = (lba >> 16) & 0xff;
12082095c737Smglocker 	ucd->cmd.cdb[4] = (lba >>  8) & 0xff;
12092095c737Smglocker 	ucd->cmd.cdb[5] = (lba >>  0) & 0xff;
12102095c737Smglocker 	ucd->cmd.cdb[7] = (blocks >> 8) & 0xff;
12112095c737Smglocker 	ucd->cmd.cdb[8] = (blocks >> 0) & 0xff;
12122095c737Smglocker 
12132095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2g) */
12142095c737Smglocker 	/* Already done with above memset */
12152095c737Smglocker 
12162095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 3) */
12172095c737Smglocker 	dva = UFSHCI_DMA_DVA(sc->sc_dmamem_ucd) + (sizeof(*ucd) * slot);
12186920fd9bSmglocker 	DPRINTF(3, "%s: ucd dva=%llu\n", __func__, dva);
12192095c737Smglocker 	utrd->dw4 = (uint32_t)dva;
12202095c737Smglocker 	utrd->dw5 = (uint32_t)(dva >> 32);
12212095c737Smglocker 
12222095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 4) */
12232095c737Smglocker 	off = sizeof(struct upiu_command) / 4; /* DWORD offset */
12242095c737Smglocker 	utrd->dw6 = UFSHCI_UTRD_DW6_RUO(off);
12252095c737Smglocker 
12262095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 5) */
12272095c737Smglocker 	len = sizeof(struct upiu_response) / 4; /* DWORD length */
12282095c737Smglocker 	utrd->dw6 |= UFSHCI_UTRD_DW6_RUL(len);
12292095c737Smglocker 
12302095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 6) */
12312095c737Smglocker 	off = (sizeof(struct upiu_command) + sizeof(struct upiu_response)) / 4;
12322095c737Smglocker 	utrd->dw7 = UFSHCI_UTRD_DW7_PRDTO(off);
12332095c737Smglocker 
12342095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 7) */
12352095c737Smglocker 	utrd->dw7 |= UFSHCI_UTRD_DW7_PRDTL(0); /* No data xfer */
12362095c737Smglocker 
12372095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 9) */
12382095c737Smglocker 	if (UFSHCI_READ_4(sc, UFSHCI_REG_UTRLRSR) != 1) {
12392095c737Smglocker 		printf("%s: %s: UTRLRSR not set\n",
12402095c737Smglocker 		    sc->sc_dev.dv_xname, __func__);
12412095c737Smglocker 		return -1;
12422095c737Smglocker 	}
12432095c737Smglocker 
12443bc7f528Smglocker 	bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_utrd),
12453bc7f528Smglocker 	    sizeof(*utrd) * slot, sizeof(*utrd), BUS_DMASYNC_PREWRITE);
12463bc7f528Smglocker 	bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_ucd),
12473bc7f528Smglocker 	    sizeof(*ucd) * slot, sizeof(*ucd), BUS_DMASYNC_PREWRITE);
12483bc7f528Smglocker 
12492095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 14) */
125012f70f1cSmglocker 	ccb->ccb_status = CCB_STATUS_INPROGRESS;
125112f70f1cSmglocker 	ufshci_doorbell_write(sc, slot);
12522095c737Smglocker 
12532095c737Smglocker 	return slot;
12542095c737Smglocker }
12552095c737Smglocker 
12562095c737Smglocker int
12572095c737Smglocker ufshci_xfer_complete(struct ufshci_softc *sc)
12582095c737Smglocker {
12592095c737Smglocker 	struct ufshci_ccb *ccb;
12602095c737Smglocker 	uint32_t reg;
126138304948Smglocker 	int i, timeout;
12622095c737Smglocker 
1263e58b468bSmglocker 	mtx_enter(&sc->sc_cmd_mtx);
1264e58b468bSmglocker 
126512f70f1cSmglocker 	/* Wait for all commands to complete. */
126638304948Smglocker 	for (timeout = 5000; timeout != 0; timeout--) {
126738304948Smglocker 		reg = ufshci_doorbell_read(sc);
126812f70f1cSmglocker 		if (reg == 0)
126912f70f1cSmglocker 			break;
127038304948Smglocker 		delay(10);
127112f70f1cSmglocker 	}
127238304948Smglocker 	if (timeout == 0)
127338304948Smglocker 		printf("%s: timeout (reg=0x%x)\n", __func__, reg);
12742095c737Smglocker 
12752095c737Smglocker 	for (i = 0; i < sc->sc_nutrs; i++) {
12762095c737Smglocker 		ccb = &sc->sc_ccbs[i];
12772095c737Smglocker 
127812f70f1cSmglocker 		/* Skip unused CCBs. */
127912f70f1cSmglocker 		if (ccb->ccb_status != CCB_STATUS_INPROGRESS)
12802095c737Smglocker 			continue;
12812095c737Smglocker 
12822095c737Smglocker 		if (ccb->ccb_done == NULL)
128312f70f1cSmglocker 			panic("ccb done wasn't defined");
128412f70f1cSmglocker 
128512f70f1cSmglocker 		/* 7.2.3: Clear completion notification 3b) */
128612f70f1cSmglocker 		UFSHCI_WRITE_4(sc, UFSHCI_REG_UTRLCNR, (1U << i));
128712f70f1cSmglocker 
128812f70f1cSmglocker 		/* 7.2.3: Mark software slot for re-use 3c) */
128912f70f1cSmglocker 		ccb->ccb_status = CCB_STATUS_READY2FREE;
129012f70f1cSmglocker 
12916920fd9bSmglocker 		DPRINTF(3, "slot %d completed\n", i);
129212f70f1cSmglocker 	}
1293f0ed5855Smglocker 
1294f0ed5855Smglocker 	/* 7.2.3: Reset Interrupt Aggregation Counter and Timer 4) */
1295*ceedf4ccSmglocker 	if (sc->sc_flags & UFSHCI_FLAGS_AGGR_INTR) {
1296f0ed5855Smglocker 		UFSHCI_WRITE_4(sc, UFSHCI_REG_UTRIACR,
1297f0ed5855Smglocker 		    UFSHCI_REG_UTRIACR_IAEN | UFSHCI_REG_UTRIACR_CTR);
1298*ceedf4ccSmglocker 	}
1299f0ed5855Smglocker 
1300e58b468bSmglocker 	mtx_leave(&sc->sc_cmd_mtx);
130112f70f1cSmglocker 
130212f70f1cSmglocker 	/*
130312f70f1cSmglocker 	 * Complete the CCB, which will re-schedule new transfers if any are
130412f70f1cSmglocker 	 * pending.
130512f70f1cSmglocker 	 */
130612f70f1cSmglocker 	for (i = 0; i < sc->sc_nutrs; i++) {
130712f70f1cSmglocker 		ccb = &sc->sc_ccbs[i];
130812f70f1cSmglocker 
130912f70f1cSmglocker 		/* 7.2.3: Process the transfer by higher OS layer 3a) */
131012f70f1cSmglocker 		if (ccb->ccb_status == CCB_STATUS_READY2FREE)
13112095c737Smglocker 			ccb->ccb_done(sc, ccb);
13122095c737Smglocker 	}
13132095c737Smglocker 
13142095c737Smglocker 	return 0;
13152095c737Smglocker }
13162095c737Smglocker 
13172095c737Smglocker /* SCSI */
13182095c737Smglocker 
13192095c737Smglocker int
13202095c737Smglocker ufshci_ccb_alloc(struct ufshci_softc *sc, int nccbs)
13212095c737Smglocker {
13222095c737Smglocker 	struct ufshci_ccb *ccb;
13232095c737Smglocker 	int i;
13242095c737Smglocker 
13256920fd9bSmglocker 	DPRINTF(2, "%s: nccbs=%d, dma_size=%d, dma_nsegs=%d, "
13262095c737Smglocker 	    "dma_segmaxsize=%d\n",
13272095c737Smglocker 	    __func__, nccbs, UFSHCI_UCD_PRDT_MAX_XFER, UFSHCI_UCD_PRDT_MAX_SEGS,
13282095c737Smglocker 	    UFSHCI_UCD_PRDT_MAX_XFER);
13292095c737Smglocker 
13302095c737Smglocker 	sc->sc_ccbs = mallocarray(nccbs, sizeof(*ccb), M_DEVBUF,
13312095c737Smglocker 	    M_WAITOK | M_CANFAIL);
13322095c737Smglocker 	if (sc->sc_ccbs == NULL)
13332095c737Smglocker 		return 1;
13342095c737Smglocker 
13352095c737Smglocker 	for (i = 0; i < nccbs; i++) {
13362095c737Smglocker 		ccb = &sc->sc_ccbs[i];
13372095c737Smglocker 
13382095c737Smglocker 		if (bus_dmamap_create(sc->sc_dmat, UFSHCI_UCD_PRDT_MAX_XFER,
13392095c737Smglocker 		    UFSHCI_UCD_PRDT_MAX_SEGS, UFSHCI_UCD_PRDT_MAX_XFER, 0,
13402095c737Smglocker 		    BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW | BUS_DMA_64BIT,
13412095c737Smglocker 		    &ccb->ccb_dmamap) != 0)
13422095c737Smglocker 			goto free_maps;
13432095c737Smglocker 
13442095c737Smglocker 		ccb->ccb_cookie = NULL;
134532835f4cSmglocker 		ccb->ccb_status = CCB_STATUS_FREE;
134612f70f1cSmglocker 		ccb->ccb_slot = i;
13472095c737Smglocker 
13482095c737Smglocker 		SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_list, ccb, ccb_entry);
13492095c737Smglocker 	}
13502095c737Smglocker 
13512095c737Smglocker 	return 0;
13522095c737Smglocker 
13532095c737Smglocker free_maps:
13542095c737Smglocker 	ufshci_ccb_free(sc, nccbs);
13552095c737Smglocker 	return 1;
13562095c737Smglocker }
13572095c737Smglocker 
13582095c737Smglocker void *
13592095c737Smglocker ufshci_ccb_get(void *cookie)
13602095c737Smglocker {
13612095c737Smglocker 	struct ufshci_softc *sc = cookie;
13622095c737Smglocker 	struct ufshci_ccb *ccb;
13632095c737Smglocker 
13646920fd9bSmglocker 	DPRINTF(3, "%s\n", __func__);
13652095c737Smglocker 
13662095c737Smglocker 	mtx_enter(&sc->sc_ccb_mtx);
13672095c737Smglocker 	ccb = SIMPLEQ_FIRST(&sc->sc_ccb_list);
13682095c737Smglocker 	if (ccb != NULL)
13692095c737Smglocker 		SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_list, ccb_entry);
13702095c737Smglocker 	mtx_leave(&sc->sc_ccb_mtx);
13712095c737Smglocker 
13722095c737Smglocker 	return ccb;
13732095c737Smglocker }
13742095c737Smglocker 
13752095c737Smglocker void
13762095c737Smglocker ufshci_ccb_put(void *cookie, void *io)
13772095c737Smglocker {
13782095c737Smglocker 	struct ufshci_softc *sc = cookie;
13792095c737Smglocker 	struct ufshci_ccb *ccb = io;
13802095c737Smglocker 
13816920fd9bSmglocker 	DPRINTF(3, "%s\n", __func__);
13822095c737Smglocker 
13832095c737Smglocker 	mtx_enter(&sc->sc_ccb_mtx);
13842095c737Smglocker 	SIMPLEQ_INSERT_HEAD(&sc->sc_ccb_list, ccb, ccb_entry);
13852095c737Smglocker 	mtx_leave(&sc->sc_ccb_mtx);
13862095c737Smglocker }
13872095c737Smglocker 
13882095c737Smglocker void
13892095c737Smglocker ufshci_ccb_free(struct ufshci_softc *sc, int nccbs)
13902095c737Smglocker {
13912095c737Smglocker 	struct ufshci_ccb *ccb;
13922095c737Smglocker 
13936920fd9bSmglocker 	DPRINTF(3, "%s\n", __func__);
13942095c737Smglocker 
13952095c737Smglocker 	while ((ccb = SIMPLEQ_FIRST(&sc->sc_ccb_list)) != NULL) {
13962095c737Smglocker 		SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_list, ccb_entry);
13972095c737Smglocker 		bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmamap);
13982095c737Smglocker 	}
13992095c737Smglocker 
14002095c737Smglocker 	ufshci_dmamem_free(sc, sc->sc_dmamem_utrd);
14012095c737Smglocker 	free(sc->sc_ccbs, M_DEVBUF, nccbs * sizeof(*ccb));
14022095c737Smglocker }
14032095c737Smglocker 
14042095c737Smglocker void
14052095c737Smglocker ufshci_scsi_cmd(struct scsi_xfer *xs)
14062095c737Smglocker {
14072095c737Smglocker 	struct scsi_link *link = xs->sc_link;
14082095c737Smglocker 	struct ufshci_softc *sc = link->bus->sb_adapter_softc;
14092095c737Smglocker 
1410e58b468bSmglocker 	mtx_enter(&sc->sc_cmd_mtx);
1411e58b468bSmglocker 
14126920fd9bSmglocker 	DPRINTF(3, "%s: cmd=0x%x\n", __func__, xs->cmd.opcode);
14132095c737Smglocker 
14142095c737Smglocker 	switch (xs->cmd.opcode) {
14152095c737Smglocker 
14162095c737Smglocker 	case READ_COMMAND:
14172095c737Smglocker 	case READ_10:
14182095c737Smglocker 	case READ_12:
14192095c737Smglocker 	case READ_16:
14206920fd9bSmglocker 		DPRINTF(3, "io read\n");
14212095c737Smglocker 		ufshci_scsi_io(xs, SCSI_DATA_IN);
1422e58b468bSmglocker 		break;
14232095c737Smglocker 
14242095c737Smglocker 	case WRITE_COMMAND:
14252095c737Smglocker 	case WRITE_10:
14262095c737Smglocker 	case WRITE_12:
14272095c737Smglocker 	case WRITE_16:
14286920fd9bSmglocker 		DPRINTF(3, "io write\n");
14292095c737Smglocker 		ufshci_scsi_io(xs, SCSI_DATA_OUT);
1430e58b468bSmglocker 		break;
14312095c737Smglocker 
14322095c737Smglocker 	case SYNCHRONIZE_CACHE:
14336920fd9bSmglocker 		DPRINTF(3, "sync\n");
14342095c737Smglocker 		ufshci_scsi_sync(xs);
1435e58b468bSmglocker 		break;
14362095c737Smglocker 
14372095c737Smglocker 	case INQUIRY:
14386920fd9bSmglocker 		DPRINTF(3, "inquiry\n");
14392095c737Smglocker 		ufshci_scsi_inquiry(xs);
1440e58b468bSmglocker 		break;
14412095c737Smglocker 
14422095c737Smglocker 	case READ_CAPACITY_16:
14436920fd9bSmglocker 		DPRINTF(3, "capacity16\n");
14442095c737Smglocker 		ufshci_scsi_capacity16(xs);
1445e58b468bSmglocker 		break;
14462095c737Smglocker 	case READ_CAPACITY:
14476920fd9bSmglocker 		DPRINTF(3, "capacity\n");
14482095c737Smglocker 		ufshci_scsi_capacity(xs);
1449e58b468bSmglocker 		break;
14502095c737Smglocker 
14512095c737Smglocker 	case TEST_UNIT_READY:
14522095c737Smglocker 	case PREVENT_ALLOW:
14532095c737Smglocker 	case START_STOP:
14542095c737Smglocker 		xs->error = XS_NOERROR;
14552095c737Smglocker 		scsi_done(xs);
1456e58b468bSmglocker 		break;
14572095c737Smglocker 	default:
14586920fd9bSmglocker 		DPRINTF(3, "%s: unhandled scsi command 0x%02x\n",
14592095c737Smglocker 		    __func__, xs->cmd.opcode);
1460e58b468bSmglocker 		xs->error = XS_DRIVER_STUFFUP;
1461e58b468bSmglocker 		scsi_done(xs);
14622095c737Smglocker 		break;
14632095c737Smglocker 	}
14642095c737Smglocker 
1465e58b468bSmglocker 	mtx_leave(&sc->sc_cmd_mtx);
14662095c737Smglocker }
14672095c737Smglocker 
14682095c737Smglocker void
14692095c737Smglocker ufshci_minphys(struct buf *bp, struct scsi_link *link)
14702095c737Smglocker {
14716920fd9bSmglocker 	DPRINTF(3, "%s\n", __func__);
14722095c737Smglocker }
14732095c737Smglocker 
14742095c737Smglocker int
14752095c737Smglocker ufshci_scsi_probe(struct scsi_link *link)
14762095c737Smglocker {
14776920fd9bSmglocker 	DPRINTF(3, "%s\n", __func__);
14782095c737Smglocker 
14792095c737Smglocker 	return 0;
14802095c737Smglocker }
14812095c737Smglocker 
14822095c737Smglocker void
14832095c737Smglocker ufshci_scsi_free(struct scsi_link *link)
14842095c737Smglocker {
14856920fd9bSmglocker 	DPRINTF(3, "%s\n", __func__);
14862095c737Smglocker }
14872095c737Smglocker 
14882095c737Smglocker void
14892095c737Smglocker ufshci_scsi_inquiry(struct scsi_xfer *xs)
14902095c737Smglocker {
14912095c737Smglocker 	struct scsi_link *link = xs->sc_link;
14922095c737Smglocker 	struct ufshci_softc *sc = link->bus->sb_adapter_softc;
14932095c737Smglocker 	struct ufshci_ccb *ccb = xs->io;
14942095c737Smglocker 	bus_dmamap_t dmap = ccb->ccb_dmamap;
14952095c737Smglocker 	int error;
14962095c737Smglocker 
14976920fd9bSmglocker 	DPRINTF(3, "%s: INQUIRY (%s)\n",
14982095c737Smglocker 	    __func__, ISSET(xs->flags, SCSI_POLL) ? "poll"  : "no poll");
14992095c737Smglocker 
15002095c737Smglocker 	if (xs->datalen > UPIU_SCSI_RSP_INQUIRY_SIZE) {
15016920fd9bSmglocker 		DPRINTF(2, "%s: request len too large\n", __func__);
15022095c737Smglocker 		goto error1;
15032095c737Smglocker 	}
15042095c737Smglocker 
15052095c737Smglocker 	error = bus_dmamap_load(sc->sc_dmat, dmap, xs->data, xs->datalen, NULL,
15062095c737Smglocker 	    ISSET(xs->flags, SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
15072095c737Smglocker 	if (error != 0) {
15082095c737Smglocker 		printf("%s: bus_dmamap_load error=%d\n", __func__, error);
15092095c737Smglocker 		goto error1;
15102095c737Smglocker 	}
15112095c737Smglocker 
15122095c737Smglocker 	bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize,
15132095c737Smglocker 	    BUS_DMASYNC_PREREAD);
15142095c737Smglocker 
15152095c737Smglocker 	ccb->ccb_cookie = xs;
15162095c737Smglocker 	ccb->ccb_done = ufshci_scsi_io_done;
15172095c737Smglocker 
15182095c737Smglocker 	/* Response length should be UPIU_SCSI_RSP_INQUIRY_SIZE. */
151912f70f1cSmglocker 	error = ufshci_utr_cmd_inquiry(sc, ccb, xs);
152012f70f1cSmglocker 	if (error == -1)
15212095c737Smglocker 		goto error2;
15222095c737Smglocker 
15232095c737Smglocker 	if (ISSET(xs->flags, SCSI_POLL)) {
15242095c737Smglocker 		if (ufshci_doorbell_poll(sc, ccb->ccb_slot) == 0) {
15252095c737Smglocker 			ccb->ccb_done(sc, ccb);
15262095c737Smglocker 			return;
15272095c737Smglocker 		}
15282095c737Smglocker 		goto error2;
15292095c737Smglocker         }
15302095c737Smglocker 
15312095c737Smglocker 	return;
15322095c737Smglocker 
15332095c737Smglocker error2:
15342095c737Smglocker 	bus_dmamap_unload(sc->sc_dmat, dmap);
15352095c737Smglocker 	ccb->ccb_cookie = NULL;
153632835f4cSmglocker 	ccb->ccb_status = CCB_STATUS_FREE;
15372095c737Smglocker 	ccb->ccb_done = NULL;
15382095c737Smglocker error1:
15392095c737Smglocker 	xs->error = XS_DRIVER_STUFFUP;
15402095c737Smglocker 	scsi_done(xs);
15412095c737Smglocker }
15422095c737Smglocker 
15432095c737Smglocker void
15442095c737Smglocker ufshci_scsi_capacity16(struct scsi_xfer *xs)
15452095c737Smglocker {
15462095c737Smglocker 	struct scsi_link *link = xs->sc_link;
15472095c737Smglocker 	struct ufshci_softc *sc = link->bus->sb_adapter_softc;
15482095c737Smglocker 	struct ufshci_ccb *ccb = xs->io;
15492095c737Smglocker 	bus_dmamap_t dmap = ccb->ccb_dmamap;
15502095c737Smglocker 	int error;
15512095c737Smglocker 
15526920fd9bSmglocker 	DPRINTF(3, "%s: CAPACITY16 (%s)\n",
15532095c737Smglocker 	    __func__, ISSET(xs->flags, SCSI_POLL) ? "poll"  : "no poll");
15542095c737Smglocker 
15552095c737Smglocker 	if (xs->datalen > UPIU_SCSI_RSP_CAPACITY16_SIZE) {
15566920fd9bSmglocker 		DPRINTF(2, "%s: request len too large\n", __func__);
15572095c737Smglocker 		goto error1;
15582095c737Smglocker 	}
15592095c737Smglocker 
15602095c737Smglocker 	error = bus_dmamap_load(sc->sc_dmat, dmap, xs->data, xs->datalen, NULL,
15612095c737Smglocker 	    ISSET(xs->flags, SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
15622095c737Smglocker 	if (error != 0) {
15632095c737Smglocker 		printf("%s: bus_dmamap_load error=%d\n", __func__, error);
15642095c737Smglocker 		goto error1;
15652095c737Smglocker 	}
15662095c737Smglocker 
15672095c737Smglocker 	bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize,
15682095c737Smglocker 	    BUS_DMASYNC_PREREAD);
15692095c737Smglocker 
15702095c737Smglocker 	ccb->ccb_cookie = xs;
15712095c737Smglocker 	ccb->ccb_done = ufshci_scsi_io_done;
15722095c737Smglocker 
15732095c737Smglocker 	/* Response length should be UPIU_SCSI_RSP_CAPACITY16_SIZE. */
157412f70f1cSmglocker 	error = ufshci_utr_cmd_capacity16(sc, ccb, xs);
157512f70f1cSmglocker 	if (error == -1)
15762095c737Smglocker 		goto error2;
15772095c737Smglocker 
15782095c737Smglocker 	if (ISSET(xs->flags, SCSI_POLL)) {
15792095c737Smglocker 		if (ufshci_doorbell_poll(sc, ccb->ccb_slot) == 0) {
15802095c737Smglocker 			ccb->ccb_done(sc, ccb);
15812095c737Smglocker 			return;
15822095c737Smglocker 		}
15832095c737Smglocker 		goto error2;
15842095c737Smglocker 	}
15852095c737Smglocker 
15862095c737Smglocker 	return;
15872095c737Smglocker 
15882095c737Smglocker error2:
15892095c737Smglocker 	bus_dmamap_unload(sc->sc_dmat, dmap);
15902095c737Smglocker 	ccb->ccb_cookie = NULL;
159132835f4cSmglocker 	ccb->ccb_status = CCB_STATUS_FREE;
15922095c737Smglocker 	ccb->ccb_done = NULL;
15932095c737Smglocker error1:
15942095c737Smglocker 	xs->error = XS_DRIVER_STUFFUP;
15952095c737Smglocker 	scsi_done(xs);
15962095c737Smglocker }
15972095c737Smglocker 
15982095c737Smglocker void
15992095c737Smglocker ufshci_scsi_capacity(struct scsi_xfer *xs)
16002095c737Smglocker {
16012095c737Smglocker 	struct scsi_link *link = xs->sc_link;
16022095c737Smglocker 	struct ufshci_softc *sc = link->bus->sb_adapter_softc;
16032095c737Smglocker 	struct ufshci_ccb *ccb = xs->io;
16042095c737Smglocker 	bus_dmamap_t dmap = ccb->ccb_dmamap;
16052095c737Smglocker 	int error;
16062095c737Smglocker 
16076920fd9bSmglocker 	DPRINTF(3, "%s: CAPACITY (%s)\n",
16082095c737Smglocker 	    __func__, ISSET(xs->flags, SCSI_POLL) ? "poll"  : "no poll");
16092095c737Smglocker 
16102095c737Smglocker 	if (xs->datalen > UPIU_SCSI_RSP_CAPACITY_SIZE) {
16116920fd9bSmglocker 		DPRINTF(2, "%s: request len too large\n", __func__);
16122095c737Smglocker 		goto error1;
16132095c737Smglocker 	}
16142095c737Smglocker 
16152095c737Smglocker 	error = bus_dmamap_load(sc->sc_dmat, dmap, xs->data, xs->datalen, NULL,
16162095c737Smglocker 	    ISSET(xs->flags, SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
16172095c737Smglocker 	if (error != 0) {
16182095c737Smglocker 		printf("%s: bus_dmamap_load error=%d\n", __func__, error);
16192095c737Smglocker 		goto error1;
16202095c737Smglocker         }
16212095c737Smglocker 
16222095c737Smglocker 	bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize,
16232095c737Smglocker 	    BUS_DMASYNC_PREREAD);
16242095c737Smglocker 
16252095c737Smglocker 	ccb->ccb_cookie = xs;
16262095c737Smglocker 	ccb->ccb_done = ufshci_scsi_io_done;
16272095c737Smglocker 
16282095c737Smglocker 	/* Response length should be UPIU_SCSI_RSP_CAPACITY_SIZE */
162912f70f1cSmglocker 	error = ufshci_utr_cmd_capacity(sc, ccb, xs);
163012f70f1cSmglocker 	if (error == -1)
16312095c737Smglocker 		goto error2;
16322095c737Smglocker 
16332095c737Smglocker 	if (ISSET(xs->flags, SCSI_POLL)) {
16342095c737Smglocker 		if (ufshci_doorbell_poll(sc, ccb->ccb_slot) == 0) {
16352095c737Smglocker 			ccb->ccb_done(sc, ccb);
16362095c737Smglocker 			return;
16372095c737Smglocker 		}
16382095c737Smglocker 		goto error2;
16392095c737Smglocker 	}
16402095c737Smglocker 
16412095c737Smglocker 	return;
16422095c737Smglocker 
16432095c737Smglocker error2:
16442095c737Smglocker 	bus_dmamap_unload(sc->sc_dmat, dmap);
16452095c737Smglocker 	ccb->ccb_cookie = NULL;
164632835f4cSmglocker 	ccb->ccb_status = CCB_STATUS_FREE;
16472095c737Smglocker 	ccb->ccb_done = NULL;
16482095c737Smglocker error1:
16492095c737Smglocker 	xs->error = XS_DRIVER_STUFFUP;
16502095c737Smglocker 	scsi_done(xs);
16512095c737Smglocker }
16522095c737Smglocker 
16532095c737Smglocker void
16542095c737Smglocker ufshci_scsi_sync(struct scsi_xfer *xs)
16552095c737Smglocker {
16562095c737Smglocker 	struct scsi_link *link = xs->sc_link;
16572095c737Smglocker 	struct ufshci_softc *sc = link->bus->sb_adapter_softc;
16582095c737Smglocker 	struct ufshci_ccb *ccb = xs->io;
16592095c737Smglocker 	uint64_t lba;
16602095c737Smglocker 	uint32_t blocks;
166112f70f1cSmglocker 	int error;
16622095c737Smglocker 
16632095c737Smglocker 	/* lba = 0, blocks = 0: Synchronize all logical blocks. */
16642095c737Smglocker 	lba = 0; blocks = 0;
16652095c737Smglocker 
16666920fd9bSmglocker 	DPRINTF(3, "%s: SYNC, lba=%llu, blocks=%u (%s)\n",
16672095c737Smglocker 	    __func__, lba, blocks,
16682095c737Smglocker 	    ISSET(xs->flags, SCSI_POLL) ? "poll"  : "no poll");
16692095c737Smglocker 
16702095c737Smglocker 	ccb->ccb_cookie = xs;
16712095c737Smglocker 	ccb->ccb_done = ufshci_scsi_done;
16722095c737Smglocker 
167312f70f1cSmglocker 	error = ufshci_utr_cmd_sync(sc, ccb, xs, (uint32_t)lba,
16742095c737Smglocker 	    (uint16_t)blocks);
167512f70f1cSmglocker 	if (error == -1)
16762095c737Smglocker 		goto error;
16772095c737Smglocker 
16782095c737Smglocker 	if (ISSET(xs->flags, SCSI_POLL)) {
16792095c737Smglocker 		if (ufshci_doorbell_poll(sc, ccb->ccb_slot) == 0) {
16802095c737Smglocker 			ccb->ccb_done(sc, ccb);
16812095c737Smglocker 			return;
16822095c737Smglocker 		}
16832095c737Smglocker 		goto error;
16842095c737Smglocker 	}
16852095c737Smglocker 
16862095c737Smglocker 	return;
16872095c737Smglocker 
16882095c737Smglocker error:
16892095c737Smglocker         ccb->ccb_cookie = NULL;
169032835f4cSmglocker 	ccb->ccb_status = CCB_STATUS_FREE;
16912095c737Smglocker         ccb->ccb_done = NULL;
16922095c737Smglocker 
16932095c737Smglocker 	xs->error = XS_DRIVER_STUFFUP;
16942095c737Smglocker 	scsi_done(xs);
16952095c737Smglocker }
16962095c737Smglocker 
16972095c737Smglocker void
16982095c737Smglocker ufshci_scsi_io(struct scsi_xfer *xs, int dir)
16992095c737Smglocker {
17002095c737Smglocker 	struct scsi_link *link = xs->sc_link;
17012095c737Smglocker 	struct ufshci_softc *sc = link->bus->sb_adapter_softc;
17022095c737Smglocker 	struct ufshci_ccb *ccb = xs->io;
17032095c737Smglocker 	bus_dmamap_t dmap = ccb->ccb_dmamap;
17042095c737Smglocker 	int error;
17052095c737Smglocker 
17062095c737Smglocker 	if ((xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) != dir)
17072095c737Smglocker 		goto error1;
17082095c737Smglocker 
17096920fd9bSmglocker 	DPRINTF(3, "%s: %s, datalen=%d (%s)\n", __func__,
1710898e5d06Smglocker 	    ISSET(xs->flags, SCSI_DATA_IN) ? "READ" : "WRITE", xs->datalen,
17112095c737Smglocker 	    ISSET(xs->flags, SCSI_POLL) ? "poll"  : "no poll");
17122095c737Smglocker 
17132095c737Smglocker 	error = bus_dmamap_load(sc->sc_dmat, dmap, xs->data, xs->datalen, NULL,
17142095c737Smglocker 	    ISSET(xs->flags, SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
17152095c737Smglocker 	if (error != 0) {
17162095c737Smglocker 		printf("%s: bus_dmamap_load error=%d\n", __func__, error);
17172095c737Smglocker 		goto error1;
17182095c737Smglocker 	}
17192095c737Smglocker 
17202095c737Smglocker 	bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize,
17212095c737Smglocker 	    ISSET(xs->flags, SCSI_DATA_IN) ? BUS_DMASYNC_PREREAD :
17222095c737Smglocker 	    BUS_DMASYNC_PREWRITE);
17232095c737Smglocker 
17242095c737Smglocker 	ccb->ccb_cookie = xs;
17252095c737Smglocker 	ccb->ccb_done = ufshci_scsi_io_done;
17262095c737Smglocker 
1727a2f0dcb2Smglocker 	if (dir == SCSI_DATA_IN)
172812f70f1cSmglocker 		error = ufshci_utr_cmd_io(sc, ccb, xs, SCSI_DATA_IN);
1729a2f0dcb2Smglocker 	else
173012f70f1cSmglocker 		error = ufshci_utr_cmd_io(sc, ccb, xs, SCSI_DATA_OUT);
173112f70f1cSmglocker 	if (error == -1)
17322095c737Smglocker 		goto error2;
17332095c737Smglocker 
17342095c737Smglocker 	if (ISSET(xs->flags, SCSI_POLL)) {
17352095c737Smglocker 		if (ufshci_doorbell_poll(sc, ccb->ccb_slot) == 0) {
17362095c737Smglocker 			ccb->ccb_done(sc, ccb);
17372095c737Smglocker 			return;
17382095c737Smglocker 		}
17392095c737Smglocker 		goto error2;
17402095c737Smglocker 	}
17412095c737Smglocker 
17422095c737Smglocker 	return;
17432095c737Smglocker 
17442095c737Smglocker error2:
17452095c737Smglocker 	bus_dmamap_unload(sc->sc_dmat, dmap);
17462095c737Smglocker 	ccb->ccb_cookie = NULL;
174732835f4cSmglocker 	ccb->ccb_status = CCB_STATUS_FREE;
17482095c737Smglocker 	ccb->ccb_done = NULL;
17492095c737Smglocker error1:
17502095c737Smglocker 	xs->error = XS_DRIVER_STUFFUP;
17512095c737Smglocker 	scsi_done(xs);
17522095c737Smglocker }
17532095c737Smglocker 
17542095c737Smglocker void
17552095c737Smglocker ufshci_scsi_io_done(struct ufshci_softc *sc, struct ufshci_ccb *ccb)
17562095c737Smglocker {
17572095c737Smglocker 	struct scsi_xfer *xs = ccb->ccb_cookie;
17582095c737Smglocker 	bus_dmamap_t dmap = ccb->ccb_dmamap;
17593bc7f528Smglocker 	struct ufshci_ucd *ucd;
17603bc7f528Smglocker 	struct ufshci_utrd *utrd;
17610b701acdSmglocker 
17622095c737Smglocker 	bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize,
17632095c737Smglocker 	    ISSET(xs->flags, SCSI_DATA_IN) ? BUS_DMASYNC_POSTREAD :
17642095c737Smglocker 	    BUS_DMASYNC_POSTWRITE);
17652095c737Smglocker 
17662095c737Smglocker 	bus_dmamap_unload(sc->sc_dmat, dmap);
17672095c737Smglocker 
17683bc7f528Smglocker 	bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_ucd),
17693bc7f528Smglocker 	    sizeof(*ucd) * ccb->ccb_slot, sizeof(*ucd),
17703bc7f528Smglocker 	    BUS_DMASYNC_POSTWRITE);
17713bc7f528Smglocker 	bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_utrd),
17723bc7f528Smglocker 	    sizeof(*utrd) * ccb->ccb_slot, sizeof(*utrd),
17733bc7f528Smglocker 	    BUS_DMASYNC_POSTWRITE);
17743bc7f528Smglocker 
1775effc6b3aSmglocker 	/* TODO: Do more checks on the Response UPIU in case of errors? */
1776effc6b3aSmglocker 	utrd = UFSHCI_DMA_KVA(sc->sc_dmamem_utrd);
1777effc6b3aSmglocker 	utrd += ccb->ccb_slot;
1778effc6b3aSmglocker 	ucd = UFSHCI_DMA_KVA(sc->sc_dmamem_ucd);
1779effc6b3aSmglocker 	ucd += ccb->ccb_slot;
1780effc6b3aSmglocker 	if (utrd->dw2 != UFSHCI_UTRD_DW2_OCS_SUCCESS) {
1781effc6b3aSmglocker 		printf("%s: error: slot=%d, ocs=0x%x, rsp-tc=0x%x\n",
1782effc6b3aSmglocker 		    __func__, ccb->ccb_slot, utrd->dw2, ucd->rsp.hdr.tc);
1783effc6b3aSmglocker 	}
1784effc6b3aSmglocker 
17852095c737Smglocker 	ccb->ccb_cookie = NULL;
178612f70f1cSmglocker 	ccb->ccb_status = CCB_STATUS_FREE;
17872095c737Smglocker 	ccb->ccb_done = NULL;
17882095c737Smglocker 
1789effc6b3aSmglocker 	xs->error = (utrd->dw2 == UFSHCI_UTRD_DW2_OCS_SUCCESS) ?
1790effc6b3aSmglocker 	    XS_NOERROR : XS_DRIVER_STUFFUP;
17912095c737Smglocker 	xs->status = SCSI_OK;
17922095c737Smglocker 	xs->resid = 0;
17932095c737Smglocker 	scsi_done(xs);
17942095c737Smglocker }
17952095c737Smglocker 
17962095c737Smglocker void
17972095c737Smglocker ufshci_scsi_done(struct ufshci_softc *sc, struct ufshci_ccb *ccb)
17982095c737Smglocker {
17992095c737Smglocker 	struct scsi_xfer *xs = ccb->ccb_cookie;
18003bc7f528Smglocker 	struct ufshci_ucd *ucd;
18013bc7f528Smglocker 	struct ufshci_utrd *utrd;
18023bc7f528Smglocker 
18033bc7f528Smglocker 	bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_ucd),
18043bc7f528Smglocker 	    sizeof(*ucd) * ccb->ccb_slot, sizeof(*ucd),
18053bc7f528Smglocker 	    BUS_DMASYNC_POSTWRITE);
18063bc7f528Smglocker 	bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_utrd),
18073bc7f528Smglocker 	    sizeof(*utrd) * ccb->ccb_slot, sizeof(*utrd),
18083bc7f528Smglocker 	    BUS_DMASYNC_POSTWRITE);
18092095c737Smglocker 
1810effc6b3aSmglocker 	/* TODO: Do more checks on the Response UPIU in case of errors? */
1811effc6b3aSmglocker 	utrd = UFSHCI_DMA_KVA(sc->sc_dmamem_utrd);
1812effc6b3aSmglocker 	utrd += ccb->ccb_slot;
1813effc6b3aSmglocker 	ucd = UFSHCI_DMA_KVA(sc->sc_dmamem_ucd);
1814effc6b3aSmglocker 	ucd += ccb->ccb_slot;
1815effc6b3aSmglocker 	if (utrd->dw2 != UFSHCI_UTRD_DW2_OCS_SUCCESS) {
1816effc6b3aSmglocker 		printf("%s: error: slot=%d, ocs=0x%x, rsp-tc=0x%x\n",
1817effc6b3aSmglocker 		    __func__, ccb->ccb_slot, utrd->dw2, ucd->rsp.hdr.tc);
1818effc6b3aSmglocker 	}
1819effc6b3aSmglocker 
18202095c737Smglocker 	ccb->ccb_cookie = NULL;
182112f70f1cSmglocker 	ccb->ccb_status = CCB_STATUS_FREE;
18222095c737Smglocker 	ccb->ccb_done = NULL;
18232095c737Smglocker 
1824effc6b3aSmglocker 	xs->error = (utrd->dw2 == UFSHCI_UTRD_DW2_OCS_SUCCESS) ?
1825effc6b3aSmglocker 	    XS_NOERROR : XS_DRIVER_STUFFUP;
18262095c737Smglocker 	xs->status = SCSI_OK;
18272095c737Smglocker 	xs->resid = 0;
18282095c737Smglocker 	scsi_done(xs);
18292095c737Smglocker }
1830