xref: /openbsd/sys/dev/ic/ufshci.c (revision c45d22d4)
1*c45d22d4Smglocker /*	$OpenBSD: ufshci.c,v 1.37 2024/06/14 20:52:07 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 
4590de4d2dSmglocker #ifdef HIBERNATE
4690de4d2dSmglocker #include <uvm/uvm_extern.h>
4790de4d2dSmglocker #include <sys/hibernate.h>
4890de4d2dSmglocker #include <sys/disklabel.h>
4990de4d2dSmglocker #include <sys/disk.h>
5090de4d2dSmglocker #endif
5190de4d2dSmglocker 
522095c737Smglocker #ifdef UFSHCI_DEBUG
532095c737Smglocker int ufshci_dbglvl = 1;
546920fd9bSmglocker #define DPRINTF(l, x...)	do { if ((l) <= ufshci_dbglvl) printf(x); } \
556920fd9bSmglocker 				    while (0)
562095c737Smglocker #else
576920fd9bSmglocker #define DPRINTF(l, x...)
582095c737Smglocker #endif
592095c737Smglocker 
602095c737Smglocker struct cfdriver ufshci_cd = {
612095c737Smglocker 	NULL, "ufshci", DV_DULL
622095c737Smglocker };
632095c737Smglocker 
642095c737Smglocker int			 ufshci_reset(struct ufshci_softc *);
6581f602bfSmglocker int			 ufshci_is_poll(struct ufshci_softc *, uint32_t);
662095c737Smglocker struct ufshci_dmamem	*ufshci_dmamem_alloc(struct ufshci_softc *, size_t);
672095c737Smglocker void			 ufshci_dmamem_free(struct ufshci_softc *,
682095c737Smglocker 			     struct ufshci_dmamem *);
6990de4d2dSmglocker int			 ufshci_alloc(struct ufshci_softc *);
702095c737Smglocker int			 ufshci_init(struct ufshci_softc *);
710fe5d515Smglocker void			 ufshci_disable(struct ufshci_softc *);
722095c737Smglocker int			 ufshci_doorbell_read(struct ufshci_softc *);
7312f70f1cSmglocker void			 ufshci_doorbell_write(struct ufshci_softc *, int);
7493bf5056Smglocker int			 ufshci_doorbell_poll(struct ufshci_softc *, int,
7593bf5056Smglocker 			     uint32_t);
7612f70f1cSmglocker int			 ufshci_utr_cmd_nop(struct ufshci_softc *,
7712f70f1cSmglocker 			     struct ufshci_ccb *, struct scsi_xfer *);
782095c737Smglocker int			 ufshci_utr_cmd_lun(struct ufshci_softc *,
7944c52867Smglocker 			     struct ufshci_ccb *, struct scsi_xfer *);
802095c737Smglocker int			 ufshci_utr_cmd_inquiry(struct ufshci_softc *,
8144c52867Smglocker 			     struct ufshci_ccb *, struct scsi_xfer *);
822095c737Smglocker int			 ufshci_utr_cmd_capacity16(struct ufshci_softc *,
8344c52867Smglocker 			     struct ufshci_ccb *, struct scsi_xfer *);
842095c737Smglocker int			 ufshci_utr_cmd_capacity(struct ufshci_softc *,
8544c52867Smglocker 			     struct ufshci_ccb *, struct scsi_xfer *);
86a2f0dcb2Smglocker int			 ufshci_utr_cmd_io(struct ufshci_softc *,
87a2f0dcb2Smglocker 			     struct ufshci_ccb *, struct scsi_xfer *, int);
882095c737Smglocker int			 ufshci_utr_cmd_sync(struct ufshci_softc *,
8944c52867Smglocker 			     struct ufshci_ccb *, struct scsi_xfer *,
9044c52867Smglocker 			     uint32_t, uint16_t);
910fe5d515Smglocker void			 ufshci_xfer_complete(struct ufshci_softc *);
922095c737Smglocker 
932095c737Smglocker /* SCSI */
942095c737Smglocker int			 ufshci_ccb_alloc(struct ufshci_softc *, int);
952095c737Smglocker void			*ufshci_ccb_get(void *);
962095c737Smglocker void			 ufshci_ccb_put(void *, void *);
972095c737Smglocker void			 ufshci_ccb_free(struct ufshci_softc*, int);
982095c737Smglocker 
992095c737Smglocker void			 ufshci_scsi_cmd(struct scsi_xfer *);
1002095c737Smglocker void			 ufshci_minphys(struct buf *, struct scsi_link *);
1012095c737Smglocker int			 ufshci_scsi_probe(struct scsi_link *);
1022095c737Smglocker void			 ufshci_scsi_free(struct scsi_link *);
1032095c737Smglocker 
1042095c737Smglocker void			 ufshci_scsi_inquiry(struct scsi_xfer *);
1052095c737Smglocker void			 ufshci_scsi_capacity16(struct scsi_xfer *);
1062095c737Smglocker void			 ufshci_scsi_capacity(struct scsi_xfer *);
1072095c737Smglocker void			 ufshci_scsi_sync(struct scsi_xfer *);
1082095c737Smglocker void			 ufshci_scsi_io(struct scsi_xfer *, int);
1092095c737Smglocker void			 ufshci_scsi_io_done(struct ufshci_softc *,
1102095c737Smglocker 			     struct ufshci_ccb *);
1112095c737Smglocker void			 ufshci_scsi_done(struct ufshci_softc *,
1122095c737Smglocker 			     struct ufshci_ccb *);
1132095c737Smglocker 
11490de4d2dSmglocker #if HIBERNATE
11590de4d2dSmglocker int			 ufshci_hibernate_io(dev_t, daddr_t, vaddr_t, size_t,
11690de4d2dSmglocker 			     int, void *);
11790de4d2dSmglocker #endif
11890de4d2dSmglocker 
1192095c737Smglocker const struct scsi_adapter ufshci_switch = {
1202095c737Smglocker 	ufshci_scsi_cmd, NULL, NULL, NULL, NULL
1212095c737Smglocker };
1222095c737Smglocker 
1232095c737Smglocker int
1242095c737Smglocker ufshci_intr(void *arg)
1252095c737Smglocker {
1262095c737Smglocker 	struct ufshci_softc *sc = arg;
1279251d8a3Smglocker 	uint32_t status, hcs;
1282095c737Smglocker 	int handled = 0;
1292095c737Smglocker 
1302095c737Smglocker 	status = UFSHCI_READ_4(sc, UFSHCI_REG_IS);
1316920fd9bSmglocker 	DPRINTF(3, "%s: status=0x%08x\n", __func__, status);
1322095c737Smglocker 
1332095c737Smglocker 	if (status == 0)
134*c45d22d4Smglocker 		return handled;
1352095c737Smglocker 
1362095c737Smglocker 	if (status & UFSHCI_REG_IS_UCCS) {
1376920fd9bSmglocker 		DPRINTF(3, "%s: UCCS interrupt\n", __func__);
1382095c737Smglocker 		handled = 1;
1392095c737Smglocker 	}
1402095c737Smglocker 	if (status & UFSHCI_REG_IS_UTRCS) {
1416920fd9bSmglocker 	  	DPRINTF(3, "%s: UTRCS interrupt\n", __func__);
1422095c737Smglocker 
14312f70f1cSmglocker 		ufshci_xfer_complete(sc);
14412f70f1cSmglocker 
1452095c737Smglocker 		handled = 1;
1462095c737Smglocker 	}
1479251d8a3Smglocker 	/* If Auto-Hibernate raises an interrupt, it's to yield an error. */
1489251d8a3Smglocker 	if (status & UFSHCI_REG_IS_UHES) {
1499251d8a3Smglocker 		hcs = UFSHCI_READ_4(sc, UFSHCI_REG_HCS);
1509251d8a3Smglocker 		printf("%s: Auto-Hibernate enter error UPMCRS=0x%x\n",
1519251d8a3Smglocker 		    __func__, UFSHCI_REG_HCS_UPMCRS(hcs));
152*c45d22d4Smglocker 		handled = 1;
1539251d8a3Smglocker 	}
1549251d8a3Smglocker 	if (status & UFSHCI_REG_IS_UHXS) {
1559251d8a3Smglocker 		hcs = UFSHCI_READ_4(sc, UFSHCI_REG_HCS);
1569251d8a3Smglocker 		printf("%s: Auto-Hibernate exit error UPMCRS=0x%x\n",
1579251d8a3Smglocker 		    __func__, UFSHCI_REG_HCS_UPMCRS(hcs));
158*c45d22d4Smglocker 		handled = 1;
1599251d8a3Smglocker 	}
1602095c737Smglocker 
1612095c737Smglocker 	if (handled == 0) {
1622095c737Smglocker 		printf("%s: UNKNOWN interrupt, status=0x%08x\n",
1632095c737Smglocker 		    sc->sc_dev.dv_xname, status);
1642095c737Smglocker 	}
1652095c737Smglocker 
1662095c737Smglocker 	/* ACK interrupt */
1672095c737Smglocker 	UFSHCI_WRITE_4(sc, UFSHCI_REG_IS, status);
1682095c737Smglocker 
169*c45d22d4Smglocker 	return handled;
1702095c737Smglocker }
1712095c737Smglocker 
1722095c737Smglocker int
1732095c737Smglocker ufshci_attach(struct ufshci_softc *sc)
1742095c737Smglocker {
1752095c737Smglocker 	struct scsibus_attach_args saa;
1762095c737Smglocker 
177e58b468bSmglocker 	mtx_init(&sc->sc_cmd_mtx, IPL_BIO);
1782095c737Smglocker 	mtx_init(&sc->sc_ccb_mtx, IPL_BIO);
1792095c737Smglocker 	SIMPLEQ_INIT(&sc->sc_ccb_list);
1802095c737Smglocker 	scsi_iopool_init(&sc->sc_iopool, sc, ufshci_ccb_get, ufshci_ccb_put);
1812095c737Smglocker 
1820fe5d515Smglocker 	if (ufshci_reset(sc))
1830fe5d515Smglocker 		return 1;
1842095c737Smglocker 
1852095c737Smglocker 	sc->sc_ver = UFSHCI_READ_4(sc, UFSHCI_REG_VER);
1862095c737Smglocker 	printf(", UFSHCI %d.%d%d\n",
1872095c737Smglocker 	    UFSHCI_REG_VER_MAJOR(sc->sc_ver),
1882095c737Smglocker 	    UFSHCI_REG_VER_MINOR(sc->sc_ver),
1892095c737Smglocker 	    UFSHCI_REG_VER_SUFFIX(sc->sc_ver));
1902095c737Smglocker 
1912095c737Smglocker 	sc->sc_cap = UFSHCI_READ_4(sc, UFSHCI_REG_CAP);
1922095c737Smglocker 	sc->sc_hcpid = UFSHCI_READ_4(sc, UFSHCI_REG_HCPID);
1932095c737Smglocker 	sc->sc_hcmid = UFSHCI_READ_4(sc, UFSHCI_REG_HCMID);
1942095c737Smglocker 	sc->sc_nutmrs = UFSHCI_REG_CAP_NUTMRS(sc->sc_cap) + 1;
1952095c737Smglocker 	sc->sc_rtt = UFSHCI_REG_CAP_RTT(sc->sc_cap) + 1;
1966920fd9bSmglocker 	sc->sc_nutrs = UFSHCI_REG_CAP_NUTRS(sc->sc_cap) + 1;
1976920fd9bSmglocker 
1986920fd9bSmglocker 	DPRINTF(1, "Capabilities (0x%08x):\n", sc->sc_cap);
1996920fd9bSmglocker 	DPRINTF(1, "CS=%d\n", sc->sc_cap & UFSHCI_REG_CAP_CS ? 1 : 0);
2006920fd9bSmglocker 	DPRINTF(1, "UICDMETMS=%d\n",
2016920fd9bSmglocker 	    sc->sc_cap & UFSHCI_REG_CAP_UICDMETMS ? 1 : 0);
2026920fd9bSmglocker 	DPRINTF(1, "OODDS=%d\n", sc->sc_cap & UFSHCI_REG_CAP_OODDS ? 1 : 0);
2036920fd9bSmglocker 	DPRINTF(1, "64AS=%d\n", sc->sc_cap & UFSHCI_REG_CAP_64AS ? 1 : 0);
2046920fd9bSmglocker 	DPRINTF(1, "AUTOH8=%d\n", sc->sc_cap & UFSHCI_REG_AUTOH8 ? 1 : 0);
2056920fd9bSmglocker 	DPRINTF(1, "NUTMRS=%d\n", sc->sc_nutmrs);
2066920fd9bSmglocker 	DPRINTF(1, "RTT=%d\n", sc->sc_rtt);
2076920fd9bSmglocker 	DPRINTF(1, "NUTRS=%d\n", sc->sc_nutrs);
2086920fd9bSmglocker 	DPRINTF(1, "HCPID=0x%08x\n", sc->sc_hcpid);
2096920fd9bSmglocker 	DPRINTF(1, "HCMID (0x%08x):\n", sc->sc_hcmid);
2106920fd9bSmglocker 	DPRINTF(1, " BI=0x%04x\n", UFSHCI_REG_HCMID_BI(sc->sc_hcmid));
2116920fd9bSmglocker 	DPRINTF(1, " MIC=0x%04x\n", UFSHCI_REG_HCMID_MIC(sc->sc_hcmid));
2126920fd9bSmglocker 
213d0fe8ebaSmglocker 	if (sc->sc_nutrs < UFSHCI_SLOTS_MIN ||
214d0fe8ebaSmglocker 	    sc->sc_nutrs > UFSHCI_SLOTS_MAX) {
215d0fe8ebaSmglocker 		printf("%s: Invalid NUTRS value %d (must be %d-%d)!\n",
216d0fe8ebaSmglocker 		    sc->sc_dev.dv_xname, sc->sc_nutrs,
217d0fe8ebaSmglocker 		    UFSHCI_SLOTS_MIN, UFSHCI_SLOTS_MAX);
2182095c737Smglocker 		return 1;
2192095c737Smglocker 	}
220d0fe8ebaSmglocker 	if (sc->sc_nutrs == UFSHCI_SLOTS_MAX)
221d0fe8ebaSmglocker 		sc->sc_iacth = UFSHCI_INTR_AGGR_COUNT_MAX;
222d0fe8ebaSmglocker 	else
223d0fe8ebaSmglocker 		sc->sc_iacth = sc->sc_nutrs;
2246920fd9bSmglocker 	DPRINTF(1, "Intr. aggr. counter threshold:\nIACTH=%d\n", sc->sc_iacth);
2252095c737Smglocker 
226ceedf4ccSmglocker 	/*
227ceedf4ccSmglocker 	 * XXX:
228ceedf4ccSmglocker 	 * At the moment normal interrupts work better for us than interrupt
229ceedf4ccSmglocker 	 * aggregation, because:
230ceedf4ccSmglocker 	 *
231ceedf4ccSmglocker 	 * 	1. With interrupt aggregation enabled, the I/O performance
232ceedf4ccSmglocker 	 *	   isn't better, but even slightly worse depending on the
233ceedf4ccSmglocker 	 *	   UFS controller and architecture.
234ceedf4ccSmglocker 	 *	2. With interrupt aggregation enabled we currently see
235ceedf4ccSmglocker 	 *	   intermittent SCSI command stalling.  Probably there is a
236ceedf4ccSmglocker 	 *	   race condition where new SCSI commands are getting
237ceedf4ccSmglocker 	 *	   scheduled, while we miss to reset the interrupt aggregation
238ceedf4ccSmglocker 	 *	   counter/timer, which leaves us with no more interrupts
239ceedf4ccSmglocker 	 *	   triggered.  This needs to be fixed, but I couldn't figure
240ceedf4ccSmglocker 	 *	   out yet how.
241ceedf4ccSmglocker 	 */
242ceedf4ccSmglocker #if 0
243ceedf4ccSmglocker 	sc->sc_flags |= UFSHCI_FLAGS_AGGR_INTR;	/* Enable intr. aggregation */
244ceedf4ccSmglocker #endif
24590de4d2dSmglocker 	/* Allocate the DMA buffers and initialize the controller. */
2460fe5d515Smglocker 	if (ufshci_alloc(sc))
2470fe5d515Smglocker 		return 1;
2480fe5d515Smglocker 	if (ufshci_init(sc))
2490fe5d515Smglocker 		return 1;
2502095c737Smglocker 
2512095c737Smglocker 	if (ufshci_ccb_alloc(sc, sc->sc_nutrs) != 0) {
2522095c737Smglocker 		printf("%s: %s: Can't allocate CCBs\n",
2532095c737Smglocker 		    sc->sc_dev.dv_xname, __func__);
2542095c737Smglocker 		return 1;
2552095c737Smglocker 	}
2562095c737Smglocker 
2579251d8a3Smglocker 	/* Enable Auto-Hibernate Idle Timer (AHIT) and set it to 150ms. */
2589251d8a3Smglocker 	if (sc->sc_cap & UFSHCI_REG_AUTOH8) {
2599251d8a3Smglocker 		UFSHCI_WRITE_4(sc, UFSHCI_REG_AHIT,
2609251d8a3Smglocker 		    UFSHCI_REG_AHIT_TS(UFSHCI_REG_AHIT_TS_1MS) | 150);
2619251d8a3Smglocker 	}
2629251d8a3Smglocker 
2632095c737Smglocker 	/* Attach to SCSI layer */
2642095c737Smglocker 	saa.saa_adapter = &ufshci_switch;
2652095c737Smglocker 	saa.saa_adapter_softc = sc;
2662095c737Smglocker 	saa.saa_adapter_buswidth = 2; /* XXX: What's the right value? */
2672095c737Smglocker 	saa.saa_luns = 1; /* XXX: Should we use ufshci_utr_cmd_lun() */
2682095c737Smglocker 	saa.saa_adapter_target = 0;
2692095c737Smglocker 	saa.saa_openings = sc->sc_nutrs;
2702095c737Smglocker 	saa.saa_pool = &sc->sc_iopool;
2712095c737Smglocker 	saa.saa_quirks = saa.saa_flags = 0;
2722095c737Smglocker 	saa.saa_wwpn = saa.saa_wwnn = 0;
2732095c737Smglocker 
2742095c737Smglocker 	config_found(&sc->sc_dev, &saa, scsiprint);
2752095c737Smglocker 
2762095c737Smglocker 	return 0;
2772095c737Smglocker }
2782095c737Smglocker 
2792095c737Smglocker int
2802095c737Smglocker ufshci_reset(struct ufshci_softc *sc)
2812095c737Smglocker {
2822095c737Smglocker 	int i;
2832095c737Smglocker 	int retry = 10;
2842095c737Smglocker 	uint32_t hce;
2852095c737Smglocker 
2862095c737Smglocker 	/*
2872095c737Smglocker 	 * 7.1.1 Host Controller Initialization: 2)
2882095c737Smglocker 	 * Reset and enable host controller
2892095c737Smglocker 	 */
2902095c737Smglocker 	UFSHCI_WRITE_4(sc, UFSHCI_REG_HCE, UFSHCI_REG_HCE_HCE);
291dedce11aSmglocker 
2922095c737Smglocker 	/* 7.1.1 Host Controller Initialization: 3) */
2932095c737Smglocker 	for (i = 0; i < retry; i++) {
2942095c737Smglocker 		hce = UFSHCI_READ_4(sc, UFSHCI_REG_HCE);
2952095c737Smglocker 		if (hce == 1)
2962095c737Smglocker 			break;
2972095c737Smglocker 		delay(1);
2982095c737Smglocker 	}
2992095c737Smglocker 	if (i == retry) {
3002095c737Smglocker 		printf("%s: Enabling Host Controller failed!\n",
3012095c737Smglocker 		    sc->sc_dev.dv_xname);
3020fe5d515Smglocker 		return 1;
3032095c737Smglocker 	}
3042095c737Smglocker 
3056920fd9bSmglocker 	DPRINTF(2, "\n%s: Host Controller enabled (i=%d)\n", __func__, i);
3062095c737Smglocker 
3072095c737Smglocker 	return 0;
3082095c737Smglocker }
3092095c737Smglocker 
3102095c737Smglocker int
31181f602bfSmglocker ufshci_is_poll(struct ufshci_softc *sc, uint32_t type)
3122095c737Smglocker {
3132095c737Smglocker 	uint32_t status;
3142095c737Smglocker 	int i, retry = 25;
3152095c737Smglocker 
3166920fd9bSmglocker 	DPRINTF(3, "%s\n", __func__);
3172095c737Smglocker 
3182095c737Smglocker 	for (i = 0; i < retry; i++) {
3192095c737Smglocker 		status = UFSHCI_READ_4(sc, UFSHCI_REG_IS);
32081f602bfSmglocker 		if (status & type)
3212095c737Smglocker 			break;
3222095c737Smglocker 		delay(10);
3232095c737Smglocker 	}
3242095c737Smglocker 	if (i == retry) {
3252095c737Smglocker 		printf("%s: %s: timeout\n", sc->sc_dev.dv_xname, __func__);
3260fe5d515Smglocker 		return 1;
3272095c737Smglocker 	}
3286920fd9bSmglocker 	DPRINTF(3, "%s: completed after %d retries\n", __func__, i);
3292095c737Smglocker 
3302095c737Smglocker 	/* ACK interrupt */
3312095c737Smglocker 	UFSHCI_WRITE_4(sc, UFSHCI_REG_IS, status);
3322095c737Smglocker 
3332095c737Smglocker 	return 0;
3342095c737Smglocker }
3352095c737Smglocker 
3362095c737Smglocker struct ufshci_dmamem *
3372095c737Smglocker ufshci_dmamem_alloc(struct ufshci_softc *sc, size_t size)
3382095c737Smglocker {
3392095c737Smglocker 	struct ufshci_dmamem *udm;
3402095c737Smglocker 	int nsegs;
3412095c737Smglocker 
3422095c737Smglocker 	udm = malloc(sizeof(*udm), M_DEVBUF, M_WAITOK | M_ZERO);
3432095c737Smglocker 	if (udm == NULL)
3442095c737Smglocker 		return NULL;
3452095c737Smglocker 
3462095c737Smglocker 	udm->udm_size = size;
3472095c737Smglocker 
3482095c737Smglocker 	if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
3494acd6882Smglocker 	    BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW |
3504acd6882Smglocker 	    (sc->sc_cap & UFSHCI_REG_CAP_64AS) ? BUS_DMA_64BIT : 0,
3512095c737Smglocker 	    &udm->udm_map) != 0)
3522095c737Smglocker 		goto udmfree;
3532095c737Smglocker 
3542095c737Smglocker 	if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &udm->udm_seg,
3552095c737Smglocker 	    1, &nsegs, BUS_DMA_WAITOK | BUS_DMA_ZERO) != 0)
3562095c737Smglocker 		goto destroy;
3572095c737Smglocker 
3582095c737Smglocker 	if (bus_dmamem_map(sc->sc_dmat, &udm->udm_seg, nsegs, size,
3592095c737Smglocker 	    &udm->udm_kva, BUS_DMA_WAITOK) != 0)
3602095c737Smglocker 		goto free;
3612095c737Smglocker 
3622095c737Smglocker 	if (bus_dmamap_load(sc->sc_dmat, udm->udm_map, udm->udm_kva, size,
3632095c737Smglocker 	    NULL, BUS_DMA_WAITOK) != 0)
3642095c737Smglocker 		goto unmap;
3652095c737Smglocker 
3666920fd9bSmglocker 	DPRINTF(2, "%s: size=%lu, page_size=%d, nsegs=%d\n",
3672095c737Smglocker 	    __func__, size, PAGE_SIZE, nsegs);
3682095c737Smglocker 
3692095c737Smglocker 	return udm;
3702095c737Smglocker 
3712095c737Smglocker unmap:
3722095c737Smglocker 	bus_dmamem_unmap(sc->sc_dmat, udm->udm_kva, size);
3732095c737Smglocker free:
3742095c737Smglocker 	bus_dmamem_free(sc->sc_dmat, &udm->udm_seg, 1);
3752095c737Smglocker destroy:
3762095c737Smglocker 	bus_dmamap_destroy(sc->sc_dmat, udm->udm_map);
3772095c737Smglocker udmfree:
3782095c737Smglocker 	free(udm, M_DEVBUF, sizeof(*udm));
3792095c737Smglocker 
3802095c737Smglocker 	return NULL;
3812095c737Smglocker }
3822095c737Smglocker 
3832095c737Smglocker void
3842095c737Smglocker ufshci_dmamem_free(struct ufshci_softc *sc, struct ufshci_dmamem *udm)
3852095c737Smglocker {
3862095c737Smglocker 	bus_dmamap_unload(sc->sc_dmat, udm->udm_map);
3872095c737Smglocker 	bus_dmamem_unmap(sc->sc_dmat, udm->udm_kva, udm->udm_size);
3882095c737Smglocker 	bus_dmamem_free(sc->sc_dmat, &udm->udm_seg, 1);
3892095c737Smglocker 	bus_dmamap_destroy(sc->sc_dmat, udm->udm_map);
3902095c737Smglocker 	free(udm, M_DEVBUF, sizeof(*udm));
3912095c737Smglocker }
3922095c737Smglocker 
3932095c737Smglocker int
39490de4d2dSmglocker ufshci_alloc(struct ufshci_softc *sc)
39590de4d2dSmglocker {
39690de4d2dSmglocker 	/* 7.1.1 Host Controller Initialization: 13) */
39790de4d2dSmglocker 	sc->sc_dmamem_utmrd = ufshci_dmamem_alloc(sc,
39890de4d2dSmglocker 	    sizeof(struct ufshci_utmrd) * sc->sc_nutmrs);
39990de4d2dSmglocker 	if (sc->sc_dmamem_utmrd == NULL) {
40090de4d2dSmglocker 		printf("%s: Can't allocate DMA memory for UTMRD\n",
40190de4d2dSmglocker 		    sc->sc_dev.dv_xname);
4020fe5d515Smglocker 		return 1;
40390de4d2dSmglocker 	}
40490de4d2dSmglocker 
40590de4d2dSmglocker 	/* 7.1.1 Host Controller Initialization: 15) */
40690de4d2dSmglocker 	sc->sc_dmamem_utrd = ufshci_dmamem_alloc(sc,
40790de4d2dSmglocker 	    sizeof(struct ufshci_utrd) * sc->sc_nutrs);
40890de4d2dSmglocker 	if (sc->sc_dmamem_utrd == NULL) {
40990de4d2dSmglocker 		printf("%s: Can't allocate DMA memory for UTRD\n",
41090de4d2dSmglocker 		    sc->sc_dev.dv_xname);
4110fe5d515Smglocker 		return 1;
41290de4d2dSmglocker 	}
41390de4d2dSmglocker 
41490de4d2dSmglocker 	/* Allocate UCDs. */
41590de4d2dSmglocker 	sc->sc_dmamem_ucd = ufshci_dmamem_alloc(sc,
41690de4d2dSmglocker 	    sizeof(struct ufshci_ucd) * sc->sc_nutrs);
41790de4d2dSmglocker 	if (sc->sc_dmamem_ucd == NULL) {
41890de4d2dSmglocker 		printf("%s: Can't allocate DMA memory for UCD\n",
41990de4d2dSmglocker 		    sc->sc_dev.dv_xname);
4200fe5d515Smglocker 		return 1;
42190de4d2dSmglocker 	}
42290de4d2dSmglocker 
42390de4d2dSmglocker 	return 0;
42490de4d2dSmglocker }
42590de4d2dSmglocker 
42690de4d2dSmglocker int
4272095c737Smglocker ufshci_init(struct ufshci_softc *sc)
4282095c737Smglocker {
4292095c737Smglocker 	uint32_t reg;
4302095c737Smglocker 	uint64_t dva;
4312095c737Smglocker 
4322095c737Smglocker 	/*
4332095c737Smglocker 	 * 7.1.1 Host Controller Initialization: 4)
4342095c737Smglocker 	 * TODO: Do we need to set DME_SET?
4352095c737Smglocker 	 */
4362095c737Smglocker 
4372095c737Smglocker 	/* 7.1.1 Host Controller Initialization: 5) */
4389251d8a3Smglocker 	if (sc->sc_cap & UFSHCI_REG_AUTOH8) {
4399251d8a3Smglocker 		UFSHCI_WRITE_4(sc, UFSHCI_REG_IE,
4409251d8a3Smglocker 		    UFSHCI_REG_IE_UTRCE | UFSHCI_REG_IE_UTMRCE |
4419251d8a3Smglocker 		    UFSHCI_REG_IS_UHES | UFSHCI_REG_IS_UHXS);
4429251d8a3Smglocker 	} else {
4432095c737Smglocker 		UFSHCI_WRITE_4(sc, UFSHCI_REG_IE,
4442095c737Smglocker 		    UFSHCI_REG_IE_UTRCE | UFSHCI_REG_IE_UTMRCE);
4459251d8a3Smglocker 	}
4462095c737Smglocker 
4472095c737Smglocker 	/* 7.1.1 Host Controller Initialization: 6) */
4482095c737Smglocker 	UFSHCI_WRITE_4(sc, UFSHCI_REG_UICCMD,
4492095c737Smglocker 	    UFSHCI_REG_UICCMD_CMDOP_DME_LINKSTARTUP);
4500fe5d515Smglocker 	if (ufshci_is_poll(sc, UFSHCI_REG_IS_UCCS))
4510fe5d515Smglocker 		return 1;
4522095c737Smglocker 
4532095c737Smglocker 	/*
4542095c737Smglocker 	 * 7.1.1 Host Controller Initialization: 7), 8), 9)
4552095c737Smglocker 	 * TODO: Implement retry in case UFSHCI_REG_HCS returns 0
4562095c737Smglocker 	 */
4572095c737Smglocker 	reg = UFSHCI_READ_4(sc, UFSHCI_REG_HCS);
4582095c737Smglocker 	if (reg & UFSHCI_REG_HCS_DP)
4596920fd9bSmglocker 		DPRINTF(2, "%s: Device Presence SET\n", __func__);
4602095c737Smglocker 	else
4616920fd9bSmglocker 		DPRINTF(2, "%s: Device Presence NOT SET\n", __func__);
4622095c737Smglocker 
4632095c737Smglocker 	/*
4642095c737Smglocker 	 * 7.1.1 Host Controller Initialization: 10)
4652095c737Smglocker 	 * TODO: Enable additional interrupt on the IE register
4662095c737Smglocker 	 */
4672095c737Smglocker 
4682095c737Smglocker 	/* 7.1.1 Host Controller Initialization: 11) */
469ceedf4ccSmglocker 	if (sc->sc_flags & UFSHCI_FLAGS_AGGR_INTR) {
470f0ed5855Smglocker 		UFSHCI_WRITE_4(sc, UFSHCI_REG_UTRIACR,
471f0ed5855Smglocker 		    UFSHCI_REG_UTRIACR_IAEN |
472f0ed5855Smglocker 		    UFSHCI_REG_UTRIACR_IAPWEN |
473f0ed5855Smglocker 		    UFSHCI_REG_UTRIACR_CTR |
474f0ed5855Smglocker 		    UFSHCI_REG_UTRIACR_IACTH(sc->sc_iacth) |
475f0ed5855Smglocker 		    UFSHCI_REG_UTRIACR_IATOVAL(UFSHCI_INTR_AGGR_TIMEOUT));
476ceedf4ccSmglocker 	} else {
477ceedf4ccSmglocker 		UFSHCI_WRITE_4(sc, UFSHCI_REG_UTRIACR, 0);
478ceedf4ccSmglocker 	}
4792095c737Smglocker 
4802095c737Smglocker 	/*
4812095c737Smglocker 	 * 7.1.1 Host Controller Initialization: 12)
4822095c737Smglocker 	 * TODO: More UIC commands to issue?
4832095c737Smglocker 	 */
4842095c737Smglocker 
4852095c737Smglocker 	/* 7.1.1 Host Controller Initialization: 14) */
4862095c737Smglocker 	dva = UFSHCI_DMA_DVA(sc->sc_dmamem_utmrd);
4876920fd9bSmglocker 	DPRINTF(2, "%s: utmrd dva=%llu\n", __func__, dva);
4882095c737Smglocker 	UFSHCI_WRITE_4(sc, UFSHCI_REG_UTMRLBA, (uint32_t)dva);
4892095c737Smglocker 	UFSHCI_WRITE_4(sc, UFSHCI_REG_UTMRLBAU, (uint32_t)(dva >> 32));
4902095c737Smglocker 
4912095c737Smglocker 	/* 7.1.1 Host Controller Initialization: 16) */
4922095c737Smglocker 	dva = UFSHCI_DMA_DVA(sc->sc_dmamem_utrd);
4936920fd9bSmglocker 	DPRINTF(2, "%s: utrd dva=%llu\n", __func__, dva);
4942095c737Smglocker 	UFSHCI_WRITE_4(sc, UFSHCI_REG_UTRLBA, (uint32_t)dva);
4952095c737Smglocker 	UFSHCI_WRITE_4(sc, UFSHCI_REG_UTRLBAU, (uint32_t)(dva >> 32));
4962095c737Smglocker 
4972095c737Smglocker 	/* 7.1.1 Host Controller Initialization: 17) */
4982095c737Smglocker 	UFSHCI_WRITE_4(sc, UFSHCI_REG_UTMRLRSR, UFSHCI_REG_UTMRLRSR_START);
4992095c737Smglocker 
5002095c737Smglocker 	/* 7.1.1 Host Controller Initialization: 18) */
5012095c737Smglocker 	UFSHCI_WRITE_4(sc, UFSHCI_REG_UTRLRSR, UFSHCI_REG_UTRLRSR_START);
5022095c737Smglocker 
5032095c737Smglocker 	/* 7.1.1 Host Controller Initialization: 19) */
5042095c737Smglocker 	/* TODO: bMaxNumOfRTT will be set as the minimum value of
5052095c737Smglocker 	 * bDeviceRTTCap and NORTT. ???
5062095c737Smglocker 	 */
5072095c737Smglocker 
5082095c737Smglocker 	return 0;
5092095c737Smglocker }
5102095c737Smglocker 
5110fe5d515Smglocker void
51290de4d2dSmglocker ufshci_disable(struct ufshci_softc *sc)
51390de4d2dSmglocker {
51490de4d2dSmglocker 	/* Stop run queues. */
51590de4d2dSmglocker 	UFSHCI_WRITE_4(sc, UFSHCI_REG_UTMRLRSR, UFSHCI_REG_UTMRLRSR_STOP);
51690de4d2dSmglocker 	UFSHCI_WRITE_4(sc, UFSHCI_REG_UTRLRSR, UFSHCI_REG_UTRLRSR_STOP);
51790de4d2dSmglocker 
51890de4d2dSmglocker 	/* Disable interrupts. */
51990de4d2dSmglocker 	UFSHCI_WRITE_4(sc, UFSHCI_REG_IE, 0);
52090de4d2dSmglocker }
52190de4d2dSmglocker 
52290de4d2dSmglocker int
5232095c737Smglocker ufshci_doorbell_read(struct ufshci_softc *sc)
5242095c737Smglocker {
5252095c737Smglocker 	uint32_t reg;
5262095c737Smglocker 
5272095c737Smglocker 	reg = UFSHCI_READ_4(sc, UFSHCI_REG_UTRLDBR);
5282095c737Smglocker 
5292095c737Smglocker 	return reg;
5302095c737Smglocker }
5312095c737Smglocker 
53212f70f1cSmglocker void
53312f70f1cSmglocker ufshci_doorbell_write(struct ufshci_softc *sc, int slot)
53412f70f1cSmglocker {
53512f70f1cSmglocker 	uint32_t reg;
53612f70f1cSmglocker 
537c4dc76d1Smglocker 	reg = (1U << slot);
53812f70f1cSmglocker 
53912f70f1cSmglocker 	UFSHCI_WRITE_4(sc, UFSHCI_REG_UTRLDBR, reg);
54012f70f1cSmglocker }
54112f70f1cSmglocker 
5422095c737Smglocker int
54393bf5056Smglocker ufshci_doorbell_poll(struct ufshci_softc *sc, int slot, uint32_t timeout_ms)
5442095c737Smglocker {
5452095c737Smglocker 	uint32_t reg;
54693bf5056Smglocker 	uint64_t timeout_us;
5472095c737Smglocker 
5486920fd9bSmglocker 	DPRINTF(3, "%s\n", __func__);
5492095c737Smglocker 
55093bf5056Smglocker 	for (timeout_us = timeout_ms * 1000; timeout_us != 0;
55193bf5056Smglocker 	    timeout_us -= 1000) {
5522095c737Smglocker 		reg = UFSHCI_READ_4(sc, UFSHCI_REG_UTRLDBR);
553c4dc76d1Smglocker 		if ((reg & (1U << slot)) == 0)
5542095c737Smglocker 			break;
55593bf5056Smglocker 		delay(1000);
5562095c737Smglocker 	}
55793bf5056Smglocker 	if (timeout_us == 0) {
5582095c737Smglocker 		printf("%s: %s: timeout\n", sc->sc_dev.dv_xname, __func__);
5590fe5d515Smglocker 		return 1;
5602095c737Smglocker 	}
5612095c737Smglocker 
5622095c737Smglocker 	return 0;
5632095c737Smglocker }
5642095c737Smglocker 
5652095c737Smglocker int
56612f70f1cSmglocker ufshci_utr_cmd_nop(struct ufshci_softc *sc, struct ufshci_ccb *ccb,
56712f70f1cSmglocker     struct scsi_xfer *xs)
5682095c737Smglocker {
5692095c737Smglocker 	int slot, off, len;
5702095c737Smglocker 	uint64_t dva;
5712095c737Smglocker 	struct ufshci_utrd *utrd;
5722095c737Smglocker 	struct ufshci_ucd *ucd;
5732095c737Smglocker 
5742095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 1) */
57512f70f1cSmglocker 	slot = ccb->ccb_slot;
576b3b05a10Smglocker 	utrd = UFSHCI_DMA_KVA(sc->sc_dmamem_utrd);
577b3b05a10Smglocker 	utrd += slot;
5782095c737Smglocker 	memset(utrd, 0, sizeof(*utrd));
5796920fd9bSmglocker 	DPRINTF(3, "%s: slot=%d\n", __func__, slot);
5802095c737Smglocker 
5812095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2a) */
5822095c737Smglocker 	utrd->dw0 = UFSHCI_UTRD_DW0_CT_UFS;
5832095c737Smglocker 
5842095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2b) */
5852095c737Smglocker 	utrd->dw0 |= UFSHCI_UTRD_DW0_DD_NO;
5862095c737Smglocker 
5872095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2c) */
588ceedf4ccSmglocker 	if (sc->sc_flags & UFSHCI_FLAGS_AGGR_INTR)
58912f70f1cSmglocker 		utrd->dw0 |= UFSHCI_UTRD_DW0_I_REG;
590ceedf4ccSmglocker 	else
591ceedf4ccSmglocker 		utrd->dw0 |= UFSHCI_UTRD_DW0_I_INT;
5922095c737Smglocker 
5932095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2d) */
5942095c737Smglocker 	utrd->dw2 = UFSHCI_UTRD_DW2_OCS_IOV;
5952095c737Smglocker 
5962095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2e) */
597b3b05a10Smglocker 	ucd = UFSHCI_DMA_KVA(sc->sc_dmamem_ucd);
598b3b05a10Smglocker 	ucd += slot;
5992095c737Smglocker 	memset(ucd, 0, sizeof(*ucd));
6002095c737Smglocker 
6012095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2f) */
6022095c737Smglocker 	ucd->cmd.hdr.tc = UPIU_TC_I2T_NOP_OUT;
6032095c737Smglocker 	ucd->cmd.hdr.flags = 0;
6042095c737Smglocker 	ucd->cmd.hdr.lun = 0;
60538304948Smglocker 	ucd->cmd.hdr.task_tag = slot;
6062095c737Smglocker 	ucd->cmd.hdr.cmd_set_type = 0; /* SCSI command */
6072095c737Smglocker 	ucd->cmd.hdr.query = 0;
6082095c737Smglocker 	ucd->cmd.hdr.response = 0;
6092095c737Smglocker 	ucd->cmd.hdr.status = 0;
6102095c737Smglocker 	ucd->cmd.hdr.ehs_len = 0;
6112095c737Smglocker 	ucd->cmd.hdr.device_info = 0;
6122095c737Smglocker 	ucd->cmd.hdr.ds_len = 0;
6132095c737Smglocker 
6142095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2g) */
6152095c737Smglocker 	/* Already done with above memset */
6162095c737Smglocker 
6172095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 3) */
6182095c737Smglocker 	dva = UFSHCI_DMA_DVA(sc->sc_dmamem_ucd);
6196920fd9bSmglocker 	DPRINTF(3, "%s: ucd dva=%llu\n", __func__, dva);
6202095c737Smglocker 	utrd->dw4 = (uint32_t)dva;
6212095c737Smglocker 	utrd->dw5 = (uint32_t)(dva >> 32);
6222095c737Smglocker 
6232095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 4) */
6242095c737Smglocker 	off = sizeof(struct upiu_command) / 4; /* DWORD offset */
6252095c737Smglocker 	utrd->dw6 = UFSHCI_UTRD_DW6_RUO(off);
6262095c737Smglocker 
6272095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 5) */
6282095c737Smglocker 	len = sizeof(struct upiu_response) / 4; /* DWORD length */
6292095c737Smglocker 	utrd->dw6 |= UFSHCI_UTRD_DW6_RUL(len);
6302095c737Smglocker 
6312095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 6) */
6322095c737Smglocker 	off = (sizeof(struct upiu_command) + sizeof(struct upiu_response)) / 4;
6332095c737Smglocker 	utrd->dw7 = UFSHCI_UTRD_DW7_PRDTO(off);
6342095c737Smglocker 
6352095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 7) */
6362095c737Smglocker 	utrd->dw7 |= UFSHCI_UTRD_DW7_PRDTL(0); /* No data xfer */
6372095c737Smglocker 
6382095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 9) */
6392095c737Smglocker 	if (UFSHCI_READ_4(sc, UFSHCI_REG_UTRLRSR) != 1) {
6402095c737Smglocker 		printf("%s: %s: UTRLRSR not set\n",
6412095c737Smglocker 		    sc->sc_dev.dv_xname, __func__);
6420fe5d515Smglocker 		return 1;
6432095c737Smglocker 	}
6442095c737Smglocker 
6453bc7f528Smglocker 	bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_utrd),
6463bc7f528Smglocker 	    sizeof(*utrd) * slot, sizeof(*utrd), BUS_DMASYNC_PREWRITE);
6473bc7f528Smglocker 	bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_ucd),
6483bc7f528Smglocker 	    sizeof(*ucd) * slot, sizeof(*ucd), BUS_DMASYNC_PREWRITE);
6493bc7f528Smglocker 
6502095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 14) */
65112f70f1cSmglocker 	ccb->ccb_status = CCB_STATUS_INPROGRESS;
65212f70f1cSmglocker 	ufshci_doorbell_write(sc, slot);
6532095c737Smglocker 
6542095c737Smglocker 	return 0;
6552095c737Smglocker }
6562095c737Smglocker 
6572095c737Smglocker int
6582095c737Smglocker ufshci_utr_cmd_lun(struct ufshci_softc *sc, struct ufshci_ccb *ccb,
65944c52867Smglocker     struct scsi_xfer *xs)
6602095c737Smglocker {
6612095c737Smglocker 	int slot, off, len, i;
6622095c737Smglocker 	uint64_t dva;
6632095c737Smglocker 	struct ufshci_utrd *utrd;
6642095c737Smglocker 	struct ufshci_ucd *ucd;
6652095c737Smglocker 	bus_dmamap_t dmap = ccb->ccb_dmamap;
6662095c737Smglocker 
6672095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 1) */
66812f70f1cSmglocker 	slot = ccb->ccb_slot;
669b3b05a10Smglocker 	utrd = UFSHCI_DMA_KVA(sc->sc_dmamem_utrd);
670b3b05a10Smglocker 	utrd += slot;
6712095c737Smglocker 	memset(utrd, 0, sizeof(*utrd));
6726920fd9bSmglocker 	DPRINTF(3, "%s: slot=%d\n", __func__, slot);
6732095c737Smglocker 
6742095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2a) */
6752095c737Smglocker 	utrd->dw0 = UFSHCI_UTRD_DW0_CT_UFS;
6762095c737Smglocker 
6772095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2b) */
6782095c737Smglocker 	utrd->dw0 |= UFSHCI_UTRD_DW0_DD_T2I;
6792095c737Smglocker 
6802095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2c) */
681ceedf4ccSmglocker         if (sc->sc_flags & UFSHCI_FLAGS_AGGR_INTR)
6822095c737Smglocker 		utrd->dw0 |= UFSHCI_UTRD_DW0_I_REG;
683ceedf4ccSmglocker         else
684ceedf4ccSmglocker 		utrd->dw0 |= UFSHCI_UTRD_DW0_I_INT;
6852095c737Smglocker 
6862095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2d) */
6872095c737Smglocker 	utrd->dw2 = UFSHCI_UTRD_DW2_OCS_IOV;
6882095c737Smglocker 
6892095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2e) */
690b3b05a10Smglocker 	ucd = UFSHCI_DMA_KVA(sc->sc_dmamem_ucd);
691b3b05a10Smglocker 	ucd += slot;
6922095c737Smglocker 	memset(ucd, 0, sizeof(*ucd));
6932095c737Smglocker 
6942095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2f) */
6952095c737Smglocker 	ucd->cmd.hdr.tc = UPIU_TC_I2T_COMMAND;
6962095c737Smglocker 	ucd->cmd.hdr.flags = (1 << 6); /* Bit-5 = Write, Bit-6 = Read */
6972095c737Smglocker 	ucd->cmd.hdr.lun = 0;
69838304948Smglocker 	ucd->cmd.hdr.task_tag = slot;
6992095c737Smglocker 	ucd->cmd.hdr.cmd_set_type = 0; /* SCSI command */
7002095c737Smglocker 	ucd->cmd.hdr.query = 0;
7012095c737Smglocker 	ucd->cmd.hdr.response = 0;
7022095c737Smglocker 	ucd->cmd.hdr.status = 0;
7032095c737Smglocker 	ucd->cmd.hdr.ehs_len = 0;
7042095c737Smglocker 	ucd->cmd.hdr.device_info = 0;
7052095c737Smglocker 	ucd->cmd.hdr.ds_len = 0;
7062095c737Smglocker 
70744c52867Smglocker 	ucd->cmd.expected_xfer_len = htobe32(xs->datalen);
7082095c737Smglocker 
7092095c737Smglocker 	ucd->cmd.cdb[0] = REPORT_LUNS;
7102095c737Smglocker 	ucd->cmd.cdb[6] = 0;
7112095c737Smglocker 	ucd->cmd.cdb[7] = 0;
7122095c737Smglocker 	ucd->cmd.cdb[8] = 0;
71344c52867Smglocker 	ucd->cmd.cdb[9] = xs->datalen;
7142095c737Smglocker 
7152095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2g) */
7162095c737Smglocker 	/* Already done with above memset */
7172095c737Smglocker 
7182095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 3) */
7192095c737Smglocker 	dva = UFSHCI_DMA_DVA(sc->sc_dmamem_ucd);
7206920fd9bSmglocker 	DPRINTF(3, "%s: ucd dva=%llu\n", __func__, dva);
7212095c737Smglocker 	utrd->dw4 = (uint32_t)dva;
7222095c737Smglocker 	utrd->dw5 = (uint32_t)(dva >> 32);
7232095c737Smglocker 
7242095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 4) */
7252095c737Smglocker 	off = sizeof(struct upiu_command) / 4; /* DWORD offset */
7262095c737Smglocker 	utrd->dw6 = UFSHCI_UTRD_DW6_RUO(off);
7272095c737Smglocker 
7282095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 5) */
7292095c737Smglocker 	len = sizeof(struct upiu_response) / 4; /* DWORD length */
7302095c737Smglocker 	utrd->dw6 |= UFSHCI_UTRD_DW6_RUL(len);
7312095c737Smglocker 
7322095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 6) */
7332095c737Smglocker 	off = (sizeof(struct upiu_command) + sizeof(struct upiu_response)) / 4;
7342095c737Smglocker 	utrd->dw7 = UFSHCI_UTRD_DW7_PRDTO(off);
7352095c737Smglocker 
7362095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 7) */
7372095c737Smglocker 	utrd->dw7 |= UFSHCI_UTRD_DW7_PRDTL(dmap->dm_nsegs);
7382095c737Smglocker 
7392095c737Smglocker 	/* Build PRDT data segment. */
7402095c737Smglocker 	for (i = 0; i < dmap->dm_nsegs; i++) {
7412095c737Smglocker 		dva = dmap->dm_segs[i].ds_addr;
7422095c737Smglocker 		ucd->prdt[i].dw0 = (uint32_t)dva;
7432095c737Smglocker 		ucd->prdt[i].dw1 = (uint32_t)(dva >> 32);
7442095c737Smglocker 		ucd->prdt[i].dw2 = 0;
7452095c737Smglocker 		ucd->prdt[i].dw3 = dmap->dm_segs[i].ds_len - 1;
7462095c737Smglocker 	}
7472095c737Smglocker 
7482095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 9) */
7492095c737Smglocker 	if (UFSHCI_READ_4(sc, UFSHCI_REG_UTRLRSR) != 1) {
7502095c737Smglocker 		printf("%s: %s: UTRLRSR not set\n",
7512095c737Smglocker 		    sc->sc_dev.dv_xname, __func__);
7520fe5d515Smglocker 		return 1;
7532095c737Smglocker 	}
7542095c737Smglocker 
7553bc7f528Smglocker 	bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_utrd),
7563bc7f528Smglocker 	    sizeof(*utrd) * slot, sizeof(*utrd), BUS_DMASYNC_PREWRITE);
7573bc7f528Smglocker 	bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_ucd),
7583bc7f528Smglocker 	    sizeof(*ucd) * slot, sizeof(*ucd), BUS_DMASYNC_PREWRITE);
7593bc7f528Smglocker 
7602095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 14) */
76112f70f1cSmglocker 	ccb->ccb_status = CCB_STATUS_INPROGRESS;
76212f70f1cSmglocker 	ufshci_doorbell_write(sc, slot);
7632095c737Smglocker 
7642095c737Smglocker 	return 0;
7652095c737Smglocker }
7662095c737Smglocker 
7672095c737Smglocker int
7682095c737Smglocker ufshci_utr_cmd_inquiry(struct ufshci_softc *sc, struct ufshci_ccb *ccb,
76944c52867Smglocker     struct scsi_xfer *xs)
7702095c737Smglocker {
7712095c737Smglocker 	int slot, off, len, i;
7722095c737Smglocker 	uint64_t dva;
7732095c737Smglocker 	struct ufshci_utrd *utrd;
7742095c737Smglocker 	struct ufshci_ucd *ucd;
7752095c737Smglocker 	bus_dmamap_t dmap = ccb->ccb_dmamap;
7762095c737Smglocker 
7772095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 1) */
77812f70f1cSmglocker 	slot = ccb->ccb_slot;
779b3b05a10Smglocker 	utrd = UFSHCI_DMA_KVA(sc->sc_dmamem_utrd);
780b3b05a10Smglocker 	utrd += slot;
7812095c737Smglocker 	memset(utrd, 0, sizeof(*utrd));
7826920fd9bSmglocker 	DPRINTF(3, "%s: slot=%d\n", __func__, slot);
7832095c737Smglocker 
7842095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2a) */
7852095c737Smglocker 	utrd->dw0 = UFSHCI_UTRD_DW0_CT_UFS;
7862095c737Smglocker 
7872095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2b) */
7882095c737Smglocker 	utrd->dw0 |= UFSHCI_UTRD_DW0_DD_T2I;
7892095c737Smglocker 
7902095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2c) */
791ceedf4ccSmglocker         if (sc->sc_flags & UFSHCI_FLAGS_AGGR_INTR)
7922095c737Smglocker 		utrd->dw0 |= UFSHCI_UTRD_DW0_I_REG;
793ceedf4ccSmglocker         else
794ceedf4ccSmglocker 		utrd->dw0 |= UFSHCI_UTRD_DW0_I_INT;
7952095c737Smglocker 
7962095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2d) */
7972095c737Smglocker 	utrd->dw2 = UFSHCI_UTRD_DW2_OCS_IOV;
7982095c737Smglocker 
7992095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2e) */
800b3b05a10Smglocker 	ucd = UFSHCI_DMA_KVA(sc->sc_dmamem_ucd);
801b3b05a10Smglocker 	ucd += slot;
8022095c737Smglocker 	memset(ucd, 0, sizeof(*ucd));
8032095c737Smglocker 
8042095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2f) */
8052095c737Smglocker 	ucd->cmd.hdr.tc = UPIU_TC_I2T_COMMAND;
8062095c737Smglocker 	ucd->cmd.hdr.flags = (1 << 6); /* Bit-5 = Write, Bit-6 = Read */
8072095c737Smglocker 	ucd->cmd.hdr.lun = 0;
80838304948Smglocker 	ucd->cmd.hdr.task_tag = slot;
8092095c737Smglocker 	ucd->cmd.hdr.cmd_set_type = 0; /* SCSI command */
8102095c737Smglocker 	ucd->cmd.hdr.query = 0;
8112095c737Smglocker 	ucd->cmd.hdr.response = 0;
8122095c737Smglocker 	ucd->cmd.hdr.status = 0;
8132095c737Smglocker 	ucd->cmd.hdr.ehs_len = 0;
8142095c737Smglocker 	ucd->cmd.hdr.device_info = 0;
8152095c737Smglocker 	ucd->cmd.hdr.ds_len = 0;
8162095c737Smglocker 
81744c52867Smglocker 	ucd->cmd.expected_xfer_len = htobe32(xs->datalen);
8182095c737Smglocker 
8192095c737Smglocker 	ucd->cmd.cdb[0] = INQUIRY; /* 0x12 */
8202095c737Smglocker 	ucd->cmd.cdb[3] = 0;
82144c52867Smglocker 	ucd->cmd.cdb[4] = xs->datalen;
8222095c737Smglocker 
8232095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2g) */
8242095c737Smglocker 	/* Already done with above memset */
8252095c737Smglocker 
8262095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 3) */
8272095c737Smglocker 	dva = UFSHCI_DMA_DVA(sc->sc_dmamem_ucd) + (sizeof(*ucd) * slot);
8286920fd9bSmglocker 	DPRINTF(3, "%s: ucd dva=%llu\n", __func__, dva);
8292095c737Smglocker 	utrd->dw4 = (uint32_t)dva;
8302095c737Smglocker 	utrd->dw5 = (uint32_t)(dva >> 32);
8312095c737Smglocker 
8322095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 4) */
8332095c737Smglocker 	off = sizeof(struct upiu_command) / 4; /* DWORD offset */
8342095c737Smglocker 	utrd->dw6 = UFSHCI_UTRD_DW6_RUO(off);
8352095c737Smglocker 
8362095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 5) */
8372095c737Smglocker 	len = sizeof(struct upiu_response) / 4; /* DWORD length */
8382095c737Smglocker 	utrd->dw6 |= UFSHCI_UTRD_DW6_RUL(len);
8392095c737Smglocker 
8402095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 6) */
8412095c737Smglocker 	off = (sizeof(struct upiu_command) + sizeof(struct upiu_response)) / 4;
8422095c737Smglocker 	utrd->dw7 = UFSHCI_UTRD_DW7_PRDTO(off);
8432095c737Smglocker 
8442095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 7) */
8452095c737Smglocker 	utrd->dw7 |= UFSHCI_UTRD_DW7_PRDTL(dmap->dm_nsegs);
8462095c737Smglocker 
8472095c737Smglocker 	/* Build PRDT data segment. */
8482095c737Smglocker 	for (i = 0; i < dmap->dm_nsegs; i++) {
8492095c737Smglocker 		dva = dmap->dm_segs[i].ds_addr;
8502095c737Smglocker 		ucd->prdt[i].dw0 = (uint32_t)dva;
8512095c737Smglocker 		ucd->prdt[i].dw1 = (uint32_t)(dva >> 32);
8522095c737Smglocker 		ucd->prdt[i].dw2 = 0;
8532095c737Smglocker 		ucd->prdt[i].dw3 = dmap->dm_segs[i].ds_len - 1;
8542095c737Smglocker 	}
8552095c737Smglocker 
8562095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 9) */
8572095c737Smglocker 	if (UFSHCI_READ_4(sc, UFSHCI_REG_UTRLRSR) != 1) {
8582095c737Smglocker 		printf("%s: %s: UTRLRSR not set\n",
8592095c737Smglocker 		    sc->sc_dev.dv_xname, __func__);
8600fe5d515Smglocker 		return 1;
8612095c737Smglocker 	}
8622095c737Smglocker 
8633bc7f528Smglocker 	bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_utrd),
8643bc7f528Smglocker 	    sizeof(*utrd) * slot, sizeof(*utrd), BUS_DMASYNC_PREWRITE);
8653bc7f528Smglocker 	bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_ucd),
8663bc7f528Smglocker 	    sizeof(*ucd) * slot, sizeof(*ucd), BUS_DMASYNC_PREWRITE);
8673bc7f528Smglocker 
8682095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 14) */
86912f70f1cSmglocker 	ccb->ccb_status = CCB_STATUS_INPROGRESS;
87012f70f1cSmglocker 	ufshci_doorbell_write(sc, slot);
8712095c737Smglocker 
8720fe5d515Smglocker 	return 0;
8732095c737Smglocker }
8742095c737Smglocker 
8752095c737Smglocker int
8762095c737Smglocker ufshci_utr_cmd_capacity16(struct ufshci_softc *sc, struct ufshci_ccb *ccb,
87744c52867Smglocker     struct scsi_xfer *xs)
8782095c737Smglocker {
8792095c737Smglocker 	int slot, off, len, i;
8802095c737Smglocker 	uint64_t dva;
8812095c737Smglocker 	struct ufshci_utrd *utrd;
8822095c737Smglocker 	struct ufshci_ucd *ucd;
8832095c737Smglocker 	bus_dmamap_t dmap = ccb->ccb_dmamap;
8842095c737Smglocker 
8852095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 1) */
88612f70f1cSmglocker 	slot = ccb->ccb_slot;
887b3b05a10Smglocker 	utrd = UFSHCI_DMA_KVA(sc->sc_dmamem_utrd);
888b3b05a10Smglocker 	utrd += slot;
8892095c737Smglocker 	memset(utrd, 0, sizeof(*utrd));
8906920fd9bSmglocker 	DPRINTF(3, "%s: slot=%d\n", __func__, slot);
8912095c737Smglocker 
8922095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2a) */
8932095c737Smglocker 	utrd->dw0 = UFSHCI_UTRD_DW0_CT_UFS;
8942095c737Smglocker 
8952095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2b) */
8962095c737Smglocker 	utrd->dw0 |= UFSHCI_UTRD_DW0_DD_T2I;
8972095c737Smglocker 
8982095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2c) */
899ceedf4ccSmglocker         if (sc->sc_flags & UFSHCI_FLAGS_AGGR_INTR)
9002095c737Smglocker 		utrd->dw0 |= UFSHCI_UTRD_DW0_I_REG;
901ceedf4ccSmglocker         else
902ceedf4ccSmglocker 		utrd->dw0 |= UFSHCI_UTRD_DW0_I_INT;
9032095c737Smglocker 
9042095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2d) */
9052095c737Smglocker 	utrd->dw2 = UFSHCI_UTRD_DW2_OCS_IOV;
9062095c737Smglocker 
9072095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2e) */
908b3b05a10Smglocker 	ucd = UFSHCI_DMA_KVA(sc->sc_dmamem_ucd);
909b3b05a10Smglocker 	ucd += slot;
9102095c737Smglocker 	memset(ucd, 0, sizeof(*ucd));
9112095c737Smglocker 
9122095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2f) */
9132095c737Smglocker 	ucd->cmd.hdr.tc = UPIU_TC_I2T_COMMAND;
9142095c737Smglocker 	ucd->cmd.hdr.flags = (1 << 6); /* Bit-5 = Write, Bit-6 = Read */
9152095c737Smglocker 	ucd->cmd.hdr.lun = 0;
91638304948Smglocker 	ucd->cmd.hdr.task_tag = slot;
9172095c737Smglocker 	ucd->cmd.hdr.cmd_set_type = 0; /* SCSI command */
9182095c737Smglocker 	ucd->cmd.hdr.query = 0;
9192095c737Smglocker 	ucd->cmd.hdr.response = 0;
9202095c737Smglocker 	ucd->cmd.hdr.status = 0;
9212095c737Smglocker 	ucd->cmd.hdr.ehs_len = 0;
9222095c737Smglocker 	ucd->cmd.hdr.device_info = 0;
9232095c737Smglocker 	ucd->cmd.hdr.ds_len = 0;
9242095c737Smglocker 
92544c52867Smglocker 	ucd->cmd.expected_xfer_len = htobe32(xs->datalen);
9262095c737Smglocker 
9272095c737Smglocker 	ucd->cmd.cdb[0] = READ_CAPACITY_16; /* 0x9e */
9282095c737Smglocker 	ucd->cmd.cdb[1] = 0x10; /* Service Action */
9292095c737Smglocker 	/* Logical Block Address = 0 for UFS */
9302095c737Smglocker 	ucd->cmd.cdb[10] = 0;
9312095c737Smglocker 	ucd->cmd.cdb[11] = 0;
9322095c737Smglocker 	ucd->cmd.cdb[12] = 0;
93344c52867Smglocker 	ucd->cmd.cdb[13] = xs->datalen;
9342095c737Smglocker 
9352095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2g) */
9362095c737Smglocker 	/* Already done with above memset */
9372095c737Smglocker 
9382095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 3) */
9392095c737Smglocker 	dva = UFSHCI_DMA_DVA(sc->sc_dmamem_ucd) + (sizeof(*ucd) * slot);
9406920fd9bSmglocker 	DPRINTF(3, "%s: ucd dva=%llu\n", __func__, dva);
9412095c737Smglocker 	utrd->dw4 = (uint32_t)dva;
9422095c737Smglocker 	utrd->dw5 = (uint32_t)(dva >> 32);
9432095c737Smglocker 
9442095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 4) */
9452095c737Smglocker 	off = sizeof(struct upiu_command) / 4; /* DWORD offset */
9462095c737Smglocker 	utrd->dw6 = UFSHCI_UTRD_DW6_RUO(off);
9472095c737Smglocker 
9482095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 5) */
9492095c737Smglocker 	len = sizeof(struct upiu_response) / 4; /* DWORD length */
9502095c737Smglocker 	utrd->dw6 |= UFSHCI_UTRD_DW6_RUL(len);
9512095c737Smglocker 
9522095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 6) */
9532095c737Smglocker 	off = (sizeof(struct upiu_command) + sizeof(struct upiu_response)) / 4;
9542095c737Smglocker 	utrd->dw7 = UFSHCI_UTRD_DW7_PRDTO(off);
9552095c737Smglocker 
9562095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 7) */
9572095c737Smglocker 	utrd->dw7 |= UFSHCI_UTRD_DW7_PRDTL(dmap->dm_nsegs);
9582095c737Smglocker 
9592095c737Smglocker 	/* Build PRDT data segment. */
9602095c737Smglocker 	for (i = 0; i < dmap->dm_nsegs; i++) {
9612095c737Smglocker 		dva = dmap->dm_segs[i].ds_addr;
9622095c737Smglocker 		ucd->prdt[i].dw0 = (uint32_t)dva;
9632095c737Smglocker 		ucd->prdt[i].dw1 = (uint32_t)(dva >> 32);
9642095c737Smglocker 		ucd->prdt[i].dw2 = 0;
9652095c737Smglocker 		ucd->prdt[i].dw3 = dmap->dm_segs[i].ds_len - 1;
9662095c737Smglocker 	}
9672095c737Smglocker 
9682095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 9) */
9692095c737Smglocker 	if (UFSHCI_READ_4(sc, UFSHCI_REG_UTRLRSR) != 1) {
9702095c737Smglocker 		printf("%s: %s: UTRLRSR not set\n",
9712095c737Smglocker 		    sc->sc_dev.dv_xname, __func__);
9720fe5d515Smglocker 		return 1;
9732095c737Smglocker 	}
9742095c737Smglocker 
9753bc7f528Smglocker 	bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_utrd),
9763bc7f528Smglocker 	    sizeof(*utrd) * slot, sizeof(*utrd), BUS_DMASYNC_PREWRITE);
9773bc7f528Smglocker 	bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_ucd),
9783bc7f528Smglocker 	    sizeof(*ucd) * slot, sizeof(*ucd), BUS_DMASYNC_PREWRITE);
9793bc7f528Smglocker 
9802095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 14) */
98112f70f1cSmglocker 	ccb->ccb_status = CCB_STATUS_INPROGRESS;
98212f70f1cSmglocker 	ufshci_doorbell_write(sc, slot);
9832095c737Smglocker 
9840fe5d515Smglocker 	return 0;
9852095c737Smglocker }
9862095c737Smglocker 
9872095c737Smglocker int
9882095c737Smglocker ufshci_utr_cmd_capacity(struct ufshci_softc *sc, struct ufshci_ccb *ccb,
98944c52867Smglocker     struct scsi_xfer *xs)
9902095c737Smglocker {
9912095c737Smglocker 	int slot, off, len, i;
9922095c737Smglocker 	uint64_t dva;
9932095c737Smglocker 	struct ufshci_utrd *utrd;
9942095c737Smglocker 	struct ufshci_ucd *ucd;
9952095c737Smglocker 	bus_dmamap_t dmap = ccb->ccb_dmamap;
9962095c737Smglocker 
9972095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 1) */
99812f70f1cSmglocker 	slot = ccb->ccb_slot;
999b3b05a10Smglocker 	utrd = UFSHCI_DMA_KVA(sc->sc_dmamem_utrd);
1000b3b05a10Smglocker 	utrd += slot;
10012095c737Smglocker 	memset(utrd, 0, sizeof(*utrd));
10026920fd9bSmglocker 	DPRINTF(3, "%s: slot=%d\n", __func__, slot);
10032095c737Smglocker 
10042095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2a) */
10052095c737Smglocker 	utrd->dw0 = UFSHCI_UTRD_DW0_CT_UFS;
10062095c737Smglocker 
10072095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2b) */
10082095c737Smglocker 	utrd->dw0 |= UFSHCI_UTRD_DW0_DD_T2I;
10092095c737Smglocker 
10102095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2c) */
1011ceedf4ccSmglocker         if (sc->sc_flags & UFSHCI_FLAGS_AGGR_INTR)
10122095c737Smglocker 		utrd->dw0 |= UFSHCI_UTRD_DW0_I_REG;
1013ceedf4ccSmglocker         else
1014ceedf4ccSmglocker 		utrd->dw0 |= UFSHCI_UTRD_DW0_I_INT;
10152095c737Smglocker 
10162095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2d) */
10172095c737Smglocker 	utrd->dw2 = UFSHCI_UTRD_DW2_OCS_IOV;
10182095c737Smglocker 
10192095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2e) */
1020b3b05a10Smglocker 	ucd = UFSHCI_DMA_KVA(sc->sc_dmamem_ucd);
1021b3b05a10Smglocker 	ucd += slot;
10222095c737Smglocker 	memset(ucd, 0, sizeof(*ucd));
10232095c737Smglocker 
10242095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2f) */
10252095c737Smglocker 	ucd->cmd.hdr.tc = UPIU_TC_I2T_COMMAND;
10262095c737Smglocker 	ucd->cmd.hdr.flags = (1 << 6); /* Bit-5 = Write, Bit-6 = Read */
10272095c737Smglocker 	ucd->cmd.hdr.lun = 0;
102838304948Smglocker 	ucd->cmd.hdr.task_tag = slot;
10292095c737Smglocker 	ucd->cmd.hdr.cmd_set_type = 0; /* SCSI command */
10302095c737Smglocker 	ucd->cmd.hdr.query = 0;
10312095c737Smglocker 	ucd->cmd.hdr.response = 0;
10322095c737Smglocker 	ucd->cmd.hdr.status = 0;
10332095c737Smglocker 	ucd->cmd.hdr.ehs_len = 0;
10342095c737Smglocker 	ucd->cmd.hdr.device_info = 0;
10352095c737Smglocker 	ucd->cmd.hdr.ds_len = 0;
10362095c737Smglocker 
103744c52867Smglocker 	ucd->cmd.expected_xfer_len = htobe32(xs->datalen);
10382095c737Smglocker 
10392095c737Smglocker 	ucd->cmd.cdb[0] = READ_CAPACITY; /* 0x25 */
10402095c737Smglocker 	/* Logical Block Address = 0 for UFS */
10412095c737Smglocker 	ucd->cmd.cdb[2] = 0;
10422095c737Smglocker 	ucd->cmd.cdb[3] = 0;
10432095c737Smglocker 	ucd->cmd.cdb[4] = 0;
10442095c737Smglocker 	ucd->cmd.cdb[5] = 0;
10452095c737Smglocker 
10462095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2g) */
10472095c737Smglocker 	/* Already done with above memset */
10482095c737Smglocker 
10492095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 3) */
10502095c737Smglocker 	dva = UFSHCI_DMA_DVA(sc->sc_dmamem_ucd) + (sizeof(*ucd) * slot);
10516920fd9bSmglocker 	DPRINTF(3, "%s: ucd dva=%llu\n", __func__, dva);
10522095c737Smglocker 	utrd->dw4 = (uint32_t)dva;
10532095c737Smglocker 	utrd->dw5 = (uint32_t)(dva >> 32);
10542095c737Smglocker 
10552095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 4) */
10562095c737Smglocker 	off = sizeof(struct upiu_command) / 4; /* DWORD offset */
10572095c737Smglocker 	utrd->dw6 = UFSHCI_UTRD_DW6_RUO(off);
10582095c737Smglocker 
10592095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 5) */
10602095c737Smglocker 	len = sizeof(struct upiu_response) / 4; /* DWORD length */
10612095c737Smglocker 	utrd->dw6 |= UFSHCI_UTRD_DW6_RUL(len);
10622095c737Smglocker 
10632095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 6) */
10642095c737Smglocker 	off = (sizeof(struct upiu_command) + sizeof(struct upiu_response)) / 4;
10652095c737Smglocker 	utrd->dw7 = UFSHCI_UTRD_DW7_PRDTO(off);
10662095c737Smglocker 
10672095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 7) */
10682095c737Smglocker 	utrd->dw7 |= UFSHCI_UTRD_DW7_PRDTL(dmap->dm_nsegs);
10692095c737Smglocker 
10702095c737Smglocker 	/* Build PRDT data segment. */
10712095c737Smglocker 	for (i = 0; i < dmap->dm_nsegs; i++) {
10722095c737Smglocker 		dva = dmap->dm_segs[i].ds_addr;
10732095c737Smglocker 		ucd->prdt[i].dw0 = (uint32_t)dva;
10742095c737Smglocker 		ucd->prdt[i].dw1 = (uint32_t)(dva >> 32);
10752095c737Smglocker 		ucd->prdt[i].dw2 = 0;
10762095c737Smglocker 		ucd->prdt[i].dw3 = dmap->dm_segs[i].ds_len - 1;
10772095c737Smglocker 	}
10782095c737Smglocker 
10792095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 9) */
10802095c737Smglocker 	if (UFSHCI_READ_4(sc, UFSHCI_REG_UTRLRSR) != 1) {
10812095c737Smglocker 		printf("%s: %s: UTRLRSR not set\n",
10822095c737Smglocker 		    sc->sc_dev.dv_xname, __func__);
10830fe5d515Smglocker 		return 1;
10842095c737Smglocker 	}
10852095c737Smglocker 
10863bc7f528Smglocker 	bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_utrd),
10873bc7f528Smglocker 	    sizeof(*utrd) * slot, sizeof(*utrd), BUS_DMASYNC_PREWRITE);
10883bc7f528Smglocker 	bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_ucd),
10893bc7f528Smglocker 	    sizeof(*ucd) * slot, sizeof(*ucd), BUS_DMASYNC_PREWRITE);
10903bc7f528Smglocker 
10912095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 14) */
109212f70f1cSmglocker 	ccb->ccb_status = CCB_STATUS_INPROGRESS;
109312f70f1cSmglocker 	ufshci_doorbell_write(sc, slot);
10942095c737Smglocker 
10950fe5d515Smglocker 	return 0;
10962095c737Smglocker }
10972095c737Smglocker 
10982095c737Smglocker int
1099a2f0dcb2Smglocker ufshci_utr_cmd_io(struct ufshci_softc *sc, struct ufshci_ccb *ccb,
1100a2f0dcb2Smglocker     struct scsi_xfer *xs, int dir)
11012095c737Smglocker {
11022095c737Smglocker 	int slot, off, len, i;
11032095c737Smglocker 	uint64_t dva;
11042095c737Smglocker 	struct ufshci_utrd *utrd;
11052095c737Smglocker 	struct ufshci_ucd *ucd;
11062095c737Smglocker 	bus_dmamap_t dmap = ccb->ccb_dmamap;
1107a9129097Smglocker 	uint32_t blocks;
1108a9129097Smglocker 	uint64_t lba;
11092095c737Smglocker 
11102095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 1) */
111112f70f1cSmglocker 	slot = ccb->ccb_slot;
1112b3b05a10Smglocker 	utrd = UFSHCI_DMA_KVA(sc->sc_dmamem_utrd);
1113b3b05a10Smglocker 	utrd += slot;
11142095c737Smglocker 	memset(utrd, 0, sizeof(*utrd));
11156920fd9bSmglocker 	DPRINTF(3, "%s: slot=%d\n", __func__, slot);
11162095c737Smglocker 
11172095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2a) */
11182095c737Smglocker 	utrd->dw0 = UFSHCI_UTRD_DW0_CT_UFS;
11192095c737Smglocker 
11202095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2b) */
1121a2f0dcb2Smglocker 	if (dir == SCSI_DATA_IN)
11222095c737Smglocker 		utrd->dw0 |= UFSHCI_UTRD_DW0_DD_T2I;
1123a2f0dcb2Smglocker 	else
11242095c737Smglocker 		utrd->dw0 |= UFSHCI_UTRD_DW0_DD_I2T;
11252095c737Smglocker 
11262095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2c) */
1127ceedf4ccSmglocker         if (sc->sc_flags & UFSHCI_FLAGS_AGGR_INTR)
11282095c737Smglocker 		utrd->dw0 |= UFSHCI_UTRD_DW0_I_REG;
1129ceedf4ccSmglocker         else
1130ceedf4ccSmglocker 		utrd->dw0 |= UFSHCI_UTRD_DW0_I_INT;
11312095c737Smglocker 
11322095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2d) */
11332095c737Smglocker 	utrd->dw2 = UFSHCI_UTRD_DW2_OCS_IOV;
11342095c737Smglocker 
11352095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2e) */
1136b3b05a10Smglocker 	ucd = UFSHCI_DMA_KVA(sc->sc_dmamem_ucd);
1137b3b05a10Smglocker 	ucd += slot;
11382095c737Smglocker 	memset(ucd, 0, sizeof(*ucd));
11392095c737Smglocker 
11402095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2f) */
11412095c737Smglocker 	ucd->cmd.hdr.tc = UPIU_TC_I2T_COMMAND;
1142a2f0dcb2Smglocker 	if (dir == SCSI_DATA_IN)
1143a2f0dcb2Smglocker 		ucd->cmd.hdr.flags = (1 << 6); /* Bit-6 = Read */
1144a2f0dcb2Smglocker 	else
1145a2f0dcb2Smglocker 		ucd->cmd.hdr.flags = (1 << 5); /* Bit-5 = Write */
11462095c737Smglocker 	ucd->cmd.hdr.lun = 0;
114738304948Smglocker 	ucd->cmd.hdr.task_tag = slot;
11482095c737Smglocker 	ucd->cmd.hdr.cmd_set_type = 0; /* SCSI command */
11492095c737Smglocker 	ucd->cmd.hdr.query = 0;
11502095c737Smglocker 	ucd->cmd.hdr.response = 0;
11512095c737Smglocker 	ucd->cmd.hdr.status = 0;
11522095c737Smglocker 	ucd->cmd.hdr.ehs_len = 0;
11532095c737Smglocker 	ucd->cmd.hdr.device_info = 0;
11542095c737Smglocker 	ucd->cmd.hdr.ds_len = 0;
11552095c737Smglocker 
1156a9129097Smglocker 	/*
1157a9129097Smglocker 	 * JESD220C-2_1.pdf, page 88, d) Expected Data Transfer Length:
1158a9129097Smglocker 	 * "When the COMMAND UPIU encodes a SCSI WRITE or SCSI READ command
1159a9129097Smglocker 	 * (specifically WRITE (6), READ (6), WRITE (10), READ (10),
1160a9129097Smglocker 	 * WRITE (16), or READ (16)), the value of this field shall be the
1161a9129097Smglocker 	 * product of the Logical Block Size (bLogicalBlockSize) and the
1162a9129097Smglocker 	 * TRANSFER LENGTH field of the CDB."
1163a9129097Smglocker 	 */
1164a9129097Smglocker 	scsi_cmd_rw_decode(&xs->cmd, &lba, &blocks);
1165a9129097Smglocker 	ucd->cmd.expected_xfer_len = htobe32(UFSHCI_LBS * blocks);
11662095c737Smglocker 
1167a2f0dcb2Smglocker 	memcpy(ucd->cmd.cdb, &xs->cmd, sizeof(ucd->cmd.cdb));
11682095c737Smglocker 
11692095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2g) */
11702095c737Smglocker 	/* Already done with above memset */
11712095c737Smglocker 
11722095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 3) */
11732095c737Smglocker 	dva = UFSHCI_DMA_DVA(sc->sc_dmamem_ucd) + (sizeof(*ucd) * slot);
11746920fd9bSmglocker 	DPRINTF(3, "%s: ucd dva=%llu\n", __func__, dva);
11752095c737Smglocker 	utrd->dw4 = (uint32_t)dva;
11762095c737Smglocker 	utrd->dw5 = (uint32_t)(dva >> 32);
11772095c737Smglocker 
11782095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 4) */
11792095c737Smglocker 	off = sizeof(struct upiu_command) / 4; /* DWORD offset */
11802095c737Smglocker 	utrd->dw6 = UFSHCI_UTRD_DW6_RUO(off);
11812095c737Smglocker 
11822095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 5) */
11832095c737Smglocker 	len = sizeof(struct upiu_response) / 4; /* DWORD length */
11842095c737Smglocker 	utrd->dw6 |= UFSHCI_UTRD_DW6_RUL(len);
11852095c737Smglocker 
11862095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 6) */
11872095c737Smglocker 	off = (sizeof(struct upiu_command) + sizeof(struct upiu_response)) / 4;
11882095c737Smglocker 	utrd->dw7 = UFSHCI_UTRD_DW7_PRDTO(off);
11892095c737Smglocker 
11902095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 7) */
11912095c737Smglocker 	utrd->dw7 |= UFSHCI_UTRD_DW7_PRDTL(dmap->dm_nsegs);
11922095c737Smglocker 
11932095c737Smglocker 	/* Build PRDT data segment. */
11942095c737Smglocker 	for (i = 0; i < dmap->dm_nsegs; i++) {
11952095c737Smglocker 		dva = dmap->dm_segs[i].ds_addr;
11962095c737Smglocker 		ucd->prdt[i].dw0 = (uint32_t)dva;
11972095c737Smglocker 		ucd->prdt[i].dw1 = (uint32_t)(dva >> 32);
11982095c737Smglocker 		ucd->prdt[i].dw2 = 0;
11992095c737Smglocker 		ucd->prdt[i].dw3 = dmap->dm_segs[i].ds_len - 1;
12002095c737Smglocker 	}
12012095c737Smglocker 
12022095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 9) */
12032095c737Smglocker 	if (UFSHCI_READ_4(sc, UFSHCI_REG_UTRLRSR) != 1) {
12042095c737Smglocker 		printf("%s: %s: UTRLRSR not set\n",
12052095c737Smglocker 		    sc->sc_dev.dv_xname, __func__);
12060fe5d515Smglocker 		return 1;
12072095c737Smglocker 	}
12082095c737Smglocker 
12093bc7f528Smglocker 	bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_utrd),
12103bc7f528Smglocker 	    sizeof(*utrd) * slot, sizeof(*utrd), BUS_DMASYNC_PREWRITE);
12113bc7f528Smglocker 	bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_ucd),
12123bc7f528Smglocker 	    sizeof(*ucd) * slot, sizeof(*ucd), BUS_DMASYNC_PREWRITE);
12133bc7f528Smglocker 
12142095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 14) */
121512f70f1cSmglocker 	ccb->ccb_status = CCB_STATUS_INPROGRESS;
121612f70f1cSmglocker 	ufshci_doorbell_write(sc, slot);
12172095c737Smglocker 
12180fe5d515Smglocker 	return 0;
12192095c737Smglocker }
12202095c737Smglocker 
12212095c737Smglocker int
12222095c737Smglocker ufshci_utr_cmd_sync(struct ufshci_softc *sc, struct ufshci_ccb *ccb,
122344c52867Smglocker     struct scsi_xfer *xs, uint32_t lba, uint16_t blocks)
12242095c737Smglocker {
12252095c737Smglocker 	int slot, off, len;
12262095c737Smglocker 	uint64_t dva;
12272095c737Smglocker 	struct ufshci_utrd *utrd;
12282095c737Smglocker 	struct ufshci_ucd *ucd;
12292095c737Smglocker 
12302095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 1) */
123112f70f1cSmglocker 	slot = ccb->ccb_slot;
1232b3b05a10Smglocker 	utrd = UFSHCI_DMA_KVA(sc->sc_dmamem_utrd);
1233b3b05a10Smglocker 	utrd += slot;
12342095c737Smglocker 	memset(utrd, 0, sizeof(*utrd));
12356920fd9bSmglocker 	DPRINTF(3, "%s: slot=%d\n", __func__, slot);
12362095c737Smglocker 
12372095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2a) */
12382095c737Smglocker 	utrd->dw0 = UFSHCI_UTRD_DW0_CT_UFS;
12392095c737Smglocker 
12402095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2b) */
12412095c737Smglocker 	utrd->dw0 |= UFSHCI_UTRD_DW0_DD_I2T;
12422095c737Smglocker 
12432095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2c) */
1244ceedf4ccSmglocker         if (sc->sc_flags & UFSHCI_FLAGS_AGGR_INTR)
12452095c737Smglocker 		utrd->dw0 |= UFSHCI_UTRD_DW0_I_REG;
1246ceedf4ccSmglocker         else
1247ceedf4ccSmglocker 		utrd->dw0 |= UFSHCI_UTRD_DW0_I_INT;
12482095c737Smglocker 
12492095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2d) */
12502095c737Smglocker 	utrd->dw2 = UFSHCI_UTRD_DW2_OCS_IOV;
12512095c737Smglocker 
12522095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2e) */
1253b3b05a10Smglocker 	ucd = UFSHCI_DMA_KVA(sc->sc_dmamem_ucd);
1254b3b05a10Smglocker 	ucd += slot;
12552095c737Smglocker 	memset(ucd, 0, sizeof(*ucd));
12562095c737Smglocker 
12572095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2f) */
12582095c737Smglocker 	ucd->cmd.hdr.tc = UPIU_TC_I2T_COMMAND;
12592095c737Smglocker 	ucd->cmd.hdr.flags = 0; /* No data transfer */
12602095c737Smglocker 	ucd->cmd.hdr.lun = 0;
126138304948Smglocker 	ucd->cmd.hdr.task_tag = slot;
12622095c737Smglocker 	ucd->cmd.hdr.cmd_set_type = 0; /* SCSI command */
12632095c737Smglocker 	ucd->cmd.hdr.query = 0;
12642095c737Smglocker 	ucd->cmd.hdr.response = 0;
12652095c737Smglocker 	ucd->cmd.hdr.status = 0;
12662095c737Smglocker 	ucd->cmd.hdr.ehs_len = 0;
12672095c737Smglocker 	ucd->cmd.hdr.device_info = 0;
12682095c737Smglocker 	ucd->cmd.hdr.ds_len = 0;
12692095c737Smglocker 
12702095c737Smglocker 	ucd->cmd.expected_xfer_len = htobe32(0); /* No data transfer */
12712095c737Smglocker 
12722095c737Smglocker 	ucd->cmd.cdb[0] = SYNCHRONIZE_CACHE; /* 0x35 */
12732095c737Smglocker 	ucd->cmd.cdb[2] = (lba >> 24) & 0xff;
12742095c737Smglocker 	ucd->cmd.cdb[3] = (lba >> 16) & 0xff;
12752095c737Smglocker 	ucd->cmd.cdb[4] = (lba >>  8) & 0xff;
12762095c737Smglocker 	ucd->cmd.cdb[5] = (lba >>  0) & 0xff;
12772095c737Smglocker 	ucd->cmd.cdb[7] = (blocks >> 8) & 0xff;
12782095c737Smglocker 	ucd->cmd.cdb[8] = (blocks >> 0) & 0xff;
12792095c737Smglocker 
12802095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 2g) */
12812095c737Smglocker 	/* Already done with above memset */
12822095c737Smglocker 
12832095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 3) */
12842095c737Smglocker 	dva = UFSHCI_DMA_DVA(sc->sc_dmamem_ucd) + (sizeof(*ucd) * slot);
12856920fd9bSmglocker 	DPRINTF(3, "%s: ucd dva=%llu\n", __func__, dva);
12862095c737Smglocker 	utrd->dw4 = (uint32_t)dva;
12872095c737Smglocker 	utrd->dw5 = (uint32_t)(dva >> 32);
12882095c737Smglocker 
12892095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 4) */
12902095c737Smglocker 	off = sizeof(struct upiu_command) / 4; /* DWORD offset */
12912095c737Smglocker 	utrd->dw6 = UFSHCI_UTRD_DW6_RUO(off);
12922095c737Smglocker 
12932095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 5) */
12942095c737Smglocker 	len = sizeof(struct upiu_response) / 4; /* DWORD length */
12952095c737Smglocker 	utrd->dw6 |= UFSHCI_UTRD_DW6_RUL(len);
12962095c737Smglocker 
12972095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 6) */
12982095c737Smglocker 	off = (sizeof(struct upiu_command) + sizeof(struct upiu_response)) / 4;
12992095c737Smglocker 	utrd->dw7 = UFSHCI_UTRD_DW7_PRDTO(off);
13002095c737Smglocker 
13012095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 7) */
13022095c737Smglocker 	utrd->dw7 |= UFSHCI_UTRD_DW7_PRDTL(0); /* No data xfer */
13032095c737Smglocker 
13042095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 9) */
13052095c737Smglocker 	if (UFSHCI_READ_4(sc, UFSHCI_REG_UTRLRSR) != 1) {
13062095c737Smglocker 		printf("%s: %s: UTRLRSR not set\n",
13072095c737Smglocker 		    sc->sc_dev.dv_xname, __func__);
13080fe5d515Smglocker 		return 1;
13092095c737Smglocker 	}
13102095c737Smglocker 
13113bc7f528Smglocker 	bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_utrd),
13123bc7f528Smglocker 	    sizeof(*utrd) * slot, sizeof(*utrd), BUS_DMASYNC_PREWRITE);
13133bc7f528Smglocker 	bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_ucd),
13143bc7f528Smglocker 	    sizeof(*ucd) * slot, sizeof(*ucd), BUS_DMASYNC_PREWRITE);
13153bc7f528Smglocker 
13162095c737Smglocker 	/* 7.2.1 Basic Steps when Building a UTP Transfer Request: 14) */
131712f70f1cSmglocker 	ccb->ccb_status = CCB_STATUS_INPROGRESS;
131812f70f1cSmglocker 	ufshci_doorbell_write(sc, slot);
13192095c737Smglocker 
13200fe5d515Smglocker 	return 0;
13212095c737Smglocker }
13222095c737Smglocker 
13230fe5d515Smglocker void
13242095c737Smglocker ufshci_xfer_complete(struct ufshci_softc *sc)
13252095c737Smglocker {
13262095c737Smglocker 	struct ufshci_ccb *ccb;
13272095c737Smglocker 	uint32_t reg;
132838304948Smglocker 	int i, timeout;
13292095c737Smglocker 
1330e58b468bSmglocker 	mtx_enter(&sc->sc_cmd_mtx);
1331e58b468bSmglocker 
133212f70f1cSmglocker 	/* Wait for all commands to complete. */
133338304948Smglocker 	for (timeout = 5000; timeout != 0; timeout--) {
133438304948Smglocker 		reg = ufshci_doorbell_read(sc);
133512f70f1cSmglocker 		if (reg == 0)
133612f70f1cSmglocker 			break;
133738304948Smglocker 		delay(10);
133812f70f1cSmglocker 	}
133938304948Smglocker 	if (timeout == 0)
134038304948Smglocker 		printf("%s: timeout (reg=0x%x)\n", __func__, reg);
13412095c737Smglocker 
13422095c737Smglocker 	for (i = 0; i < sc->sc_nutrs; i++) {
13432095c737Smglocker 		ccb = &sc->sc_ccbs[i];
13442095c737Smglocker 
134512f70f1cSmglocker 		/* Skip unused CCBs. */
134612f70f1cSmglocker 		if (ccb->ccb_status != CCB_STATUS_INPROGRESS)
13472095c737Smglocker 			continue;
13482095c737Smglocker 
13492095c737Smglocker 		if (ccb->ccb_done == NULL)
135012f70f1cSmglocker 			panic("ccb done wasn't defined");
135112f70f1cSmglocker 
135212f70f1cSmglocker 		/* 7.2.3: Clear completion notification 3b) */
135312f70f1cSmglocker 		UFSHCI_WRITE_4(sc, UFSHCI_REG_UTRLCNR, (1U << i));
135412f70f1cSmglocker 
135512f70f1cSmglocker 		/* 7.2.3: Mark software slot for re-use 3c) */
135612f70f1cSmglocker 		ccb->ccb_status = CCB_STATUS_READY2FREE;
135712f70f1cSmglocker 
13586920fd9bSmglocker 		DPRINTF(3, "slot %d completed\n", i);
135912f70f1cSmglocker 	}
1360f0ed5855Smglocker 
1361f0ed5855Smglocker 	/* 7.2.3: Reset Interrupt Aggregation Counter and Timer 4) */
1362ceedf4ccSmglocker 	if (sc->sc_flags & UFSHCI_FLAGS_AGGR_INTR) {
1363f0ed5855Smglocker 		UFSHCI_WRITE_4(sc, UFSHCI_REG_UTRIACR,
1364f0ed5855Smglocker 		    UFSHCI_REG_UTRIACR_IAEN | UFSHCI_REG_UTRIACR_CTR);
1365ceedf4ccSmglocker 	}
1366f0ed5855Smglocker 
1367e58b468bSmglocker 	mtx_leave(&sc->sc_cmd_mtx);
136812f70f1cSmglocker 
136912f70f1cSmglocker 	/*
137012f70f1cSmglocker 	 * Complete the CCB, which will re-schedule new transfers if any are
137112f70f1cSmglocker 	 * pending.
137212f70f1cSmglocker 	 */
137312f70f1cSmglocker 	for (i = 0; i < sc->sc_nutrs; i++) {
137412f70f1cSmglocker 		ccb = &sc->sc_ccbs[i];
137512f70f1cSmglocker 
137612f70f1cSmglocker 		/* 7.2.3: Process the transfer by higher OS layer 3a) */
137712f70f1cSmglocker 		if (ccb->ccb_status == CCB_STATUS_READY2FREE)
13782095c737Smglocker 			ccb->ccb_done(sc, ccb);
13792095c737Smglocker 	}
13802095c737Smglocker }
13812095c737Smglocker 
13824b489d0aSmglocker int
13834b489d0aSmglocker ufshci_activate(struct ufshci_softc *sc, int act)
13844b489d0aSmglocker {
13854b489d0aSmglocker 	int rv = 0;
13864b489d0aSmglocker 
13874b489d0aSmglocker 	switch (act) {
13884b489d0aSmglocker 	case DVACT_POWERDOWN:
13894b489d0aSmglocker 		DPRINTF(1, "%s: POWERDOWN\n", __func__);
13904b489d0aSmglocker 		rv = config_activate_children(&sc->sc_dev, act);
139190de4d2dSmglocker 		ufshci_disable(sc);
13924b489d0aSmglocker 		break;
13934b489d0aSmglocker 	case DVACT_RESUME:
13944b489d0aSmglocker 		DPRINTF(1, "%s: RESUME\n", __func__);
139590de4d2dSmglocker 		rv = ufshci_init(sc);
13964b489d0aSmglocker 		if (rv == 0)
13974b489d0aSmglocker 			rv = config_activate_children(&sc->sc_dev, act);
13984b489d0aSmglocker 		break;
13994b489d0aSmglocker 	default:
14004b489d0aSmglocker 		rv = config_activate_children(&sc->sc_dev, act);
14014b489d0aSmglocker 		break;
14024b489d0aSmglocker 	}
14034b489d0aSmglocker 
14044b489d0aSmglocker 	return rv;
14054b489d0aSmglocker }
14064b489d0aSmglocker 
14072095c737Smglocker /* SCSI */
14082095c737Smglocker 
14092095c737Smglocker int
14102095c737Smglocker ufshci_ccb_alloc(struct ufshci_softc *sc, int nccbs)
14112095c737Smglocker {
14122095c737Smglocker 	struct ufshci_ccb *ccb;
14132095c737Smglocker 	int i;
14142095c737Smglocker 
14156920fd9bSmglocker 	DPRINTF(2, "%s: nccbs=%d, dma_size=%d, dma_nsegs=%d, "
14162095c737Smglocker 	    "dma_segmaxsize=%d\n",
14172095c737Smglocker 	    __func__, nccbs, UFSHCI_UCD_PRDT_MAX_XFER, UFSHCI_UCD_PRDT_MAX_SEGS,
14182095c737Smglocker 	    UFSHCI_UCD_PRDT_MAX_XFER);
14192095c737Smglocker 
14202095c737Smglocker 	sc->sc_ccbs = mallocarray(nccbs, sizeof(*ccb), M_DEVBUF,
14212095c737Smglocker 	    M_WAITOK | M_CANFAIL);
14222095c737Smglocker 	if (sc->sc_ccbs == NULL)
14232095c737Smglocker 		return 1;
14242095c737Smglocker 
14252095c737Smglocker 	for (i = 0; i < nccbs; i++) {
14262095c737Smglocker 		ccb = &sc->sc_ccbs[i];
14272095c737Smglocker 
14282095c737Smglocker 		if (bus_dmamap_create(sc->sc_dmat, UFSHCI_UCD_PRDT_MAX_XFER,
14292095c737Smglocker 		    UFSHCI_UCD_PRDT_MAX_SEGS, UFSHCI_UCD_PRDT_MAX_XFER, 0,
14304acd6882Smglocker 		    BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW |
14314acd6882Smglocker 	    	    (sc->sc_cap & UFSHCI_REG_CAP_64AS) ? BUS_DMA_64BIT : 0,
14322095c737Smglocker 		    &ccb->ccb_dmamap) != 0)
14332095c737Smglocker 			goto free_maps;
14342095c737Smglocker 
14352095c737Smglocker 		ccb->ccb_cookie = NULL;
143632835f4cSmglocker 		ccb->ccb_status = CCB_STATUS_FREE;
143712f70f1cSmglocker 		ccb->ccb_slot = i;
14382095c737Smglocker 
14392095c737Smglocker 		SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_list, ccb, ccb_entry);
14402095c737Smglocker 	}
14412095c737Smglocker 
14422095c737Smglocker 	return 0;
14432095c737Smglocker 
14442095c737Smglocker free_maps:
14452095c737Smglocker 	ufshci_ccb_free(sc, nccbs);
14462095c737Smglocker 	return 1;
14472095c737Smglocker }
14482095c737Smglocker 
14492095c737Smglocker void *
14502095c737Smglocker ufshci_ccb_get(void *cookie)
14512095c737Smglocker {
14522095c737Smglocker 	struct ufshci_softc *sc = cookie;
14532095c737Smglocker 	struct ufshci_ccb *ccb;
14542095c737Smglocker 
14556920fd9bSmglocker 	DPRINTF(3, "%s\n", __func__);
14562095c737Smglocker 
14572095c737Smglocker 	mtx_enter(&sc->sc_ccb_mtx);
14582095c737Smglocker 	ccb = SIMPLEQ_FIRST(&sc->sc_ccb_list);
14592095c737Smglocker 	if (ccb != NULL)
14602095c737Smglocker 		SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_list, ccb_entry);
14612095c737Smglocker 	mtx_leave(&sc->sc_ccb_mtx);
14622095c737Smglocker 
14632095c737Smglocker 	return ccb;
14642095c737Smglocker }
14652095c737Smglocker 
14662095c737Smglocker void
14672095c737Smglocker ufshci_ccb_put(void *cookie, void *io)
14682095c737Smglocker {
14692095c737Smglocker 	struct ufshci_softc *sc = cookie;
14702095c737Smglocker 	struct ufshci_ccb *ccb = io;
14712095c737Smglocker 
14726920fd9bSmglocker 	DPRINTF(3, "%s\n", __func__);
14732095c737Smglocker 
14742095c737Smglocker 	mtx_enter(&sc->sc_ccb_mtx);
14752095c737Smglocker 	SIMPLEQ_INSERT_HEAD(&sc->sc_ccb_list, ccb, ccb_entry);
14762095c737Smglocker 	mtx_leave(&sc->sc_ccb_mtx);
14772095c737Smglocker }
14782095c737Smglocker 
14792095c737Smglocker void
14802095c737Smglocker ufshci_ccb_free(struct ufshci_softc *sc, int nccbs)
14812095c737Smglocker {
14822095c737Smglocker 	struct ufshci_ccb *ccb;
14832095c737Smglocker 
14846920fd9bSmglocker 	DPRINTF(3, "%s\n", __func__);
14852095c737Smglocker 
14862095c737Smglocker 	while ((ccb = SIMPLEQ_FIRST(&sc->sc_ccb_list)) != NULL) {
14872095c737Smglocker 		SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_list, ccb_entry);
14882095c737Smglocker 		bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmamap);
14892095c737Smglocker 	}
14902095c737Smglocker 
14912095c737Smglocker 	ufshci_dmamem_free(sc, sc->sc_dmamem_utrd);
14922095c737Smglocker 	free(sc->sc_ccbs, M_DEVBUF, nccbs * sizeof(*ccb));
14932095c737Smglocker }
14942095c737Smglocker 
14952095c737Smglocker void
14962095c737Smglocker ufshci_scsi_cmd(struct scsi_xfer *xs)
14972095c737Smglocker {
14982095c737Smglocker 	struct scsi_link *link = xs->sc_link;
14992095c737Smglocker 	struct ufshci_softc *sc = link->bus->sb_adapter_softc;
15002095c737Smglocker 
1501e58b468bSmglocker 	mtx_enter(&sc->sc_cmd_mtx);
1502e58b468bSmglocker 
15036920fd9bSmglocker 	DPRINTF(3, "%s: cmd=0x%x\n", __func__, xs->cmd.opcode);
15042095c737Smglocker 
15052095c737Smglocker 	switch (xs->cmd.opcode) {
15062095c737Smglocker 
15072095c737Smglocker 	case READ_COMMAND:
15082095c737Smglocker 	case READ_10:
15092095c737Smglocker 	case READ_12:
15102095c737Smglocker 	case READ_16:
15116920fd9bSmglocker 		DPRINTF(3, "io read\n");
15122095c737Smglocker 		ufshci_scsi_io(xs, SCSI_DATA_IN);
1513e58b468bSmglocker 		break;
15142095c737Smglocker 	case WRITE_COMMAND:
15152095c737Smglocker 	case WRITE_10:
15162095c737Smglocker 	case WRITE_12:
15172095c737Smglocker 	case WRITE_16:
15186920fd9bSmglocker 		DPRINTF(3, "io write\n");
15192095c737Smglocker 		ufshci_scsi_io(xs, SCSI_DATA_OUT);
1520e58b468bSmglocker 		break;
15212095c737Smglocker 	case SYNCHRONIZE_CACHE:
15226920fd9bSmglocker 		DPRINTF(3, "sync\n");
15232095c737Smglocker 		ufshci_scsi_sync(xs);
1524e58b468bSmglocker 		break;
15252095c737Smglocker 	case INQUIRY:
15266920fd9bSmglocker 		DPRINTF(3, "inquiry\n");
15272095c737Smglocker 		ufshci_scsi_inquiry(xs);
1528e58b468bSmglocker 		break;
15292095c737Smglocker 	case READ_CAPACITY_16:
15306920fd9bSmglocker 		DPRINTF(3, "capacity16\n");
15312095c737Smglocker 		ufshci_scsi_capacity16(xs);
1532e58b468bSmglocker 		break;
15332095c737Smglocker 	case READ_CAPACITY:
15346920fd9bSmglocker 		DPRINTF(3, "capacity\n");
15352095c737Smglocker 		ufshci_scsi_capacity(xs);
1536e58b468bSmglocker 		break;
15372095c737Smglocker 	case TEST_UNIT_READY:
15382095c737Smglocker 	case PREVENT_ALLOW:
15392095c737Smglocker 	case START_STOP:
15402095c737Smglocker 		xs->error = XS_NOERROR;
15412095c737Smglocker 		scsi_done(xs);
1542e58b468bSmglocker 		break;
15432095c737Smglocker 	default:
15446920fd9bSmglocker 		DPRINTF(3, "%s: unhandled scsi command 0x%02x\n",
15452095c737Smglocker 		    __func__, xs->cmd.opcode);
1546e58b468bSmglocker 		xs->error = XS_DRIVER_STUFFUP;
1547e58b468bSmglocker 		scsi_done(xs);
15482095c737Smglocker 		break;
15492095c737Smglocker 	}
15502095c737Smglocker 
1551e58b468bSmglocker 	mtx_leave(&sc->sc_cmd_mtx);
15522095c737Smglocker }
15532095c737Smglocker 
15542095c737Smglocker void
15552095c737Smglocker ufshci_minphys(struct buf *bp, struct scsi_link *link)
15562095c737Smglocker {
15576920fd9bSmglocker 	DPRINTF(3, "%s\n", __func__);
15582095c737Smglocker }
15592095c737Smglocker 
15602095c737Smglocker int
15612095c737Smglocker ufshci_scsi_probe(struct scsi_link *link)
15622095c737Smglocker {
15636920fd9bSmglocker 	DPRINTF(3, "%s\n", __func__);
15642095c737Smglocker 
15652095c737Smglocker 	return 0;
15662095c737Smglocker }
15672095c737Smglocker 
15682095c737Smglocker void
15692095c737Smglocker ufshci_scsi_free(struct scsi_link *link)
15702095c737Smglocker {
15716920fd9bSmglocker 	DPRINTF(3, "%s\n", __func__);
15722095c737Smglocker }
15732095c737Smglocker 
15742095c737Smglocker void
15752095c737Smglocker ufshci_scsi_inquiry(struct scsi_xfer *xs)
15762095c737Smglocker {
15772095c737Smglocker 	struct scsi_link *link = xs->sc_link;
15782095c737Smglocker 	struct ufshci_softc *sc = link->bus->sb_adapter_softc;
15792095c737Smglocker 	struct ufshci_ccb *ccb = xs->io;
15802095c737Smglocker 	bus_dmamap_t dmap = ccb->ccb_dmamap;
15812095c737Smglocker 	int error;
15822095c737Smglocker 
15836920fd9bSmglocker 	DPRINTF(3, "%s: INQUIRY (%s)\n",
15842095c737Smglocker 	    __func__, ISSET(xs->flags, SCSI_POLL) ? "poll"  : "no poll");
15852095c737Smglocker 
15862095c737Smglocker 	if (xs->datalen > UPIU_SCSI_RSP_INQUIRY_SIZE) {
15876920fd9bSmglocker 		DPRINTF(2, "%s: request len too large\n", __func__);
15882095c737Smglocker 		goto error1;
15892095c737Smglocker 	}
15902095c737Smglocker 
15912095c737Smglocker 	error = bus_dmamap_load(sc->sc_dmat, dmap, xs->data, xs->datalen, NULL,
15922095c737Smglocker 	    ISSET(xs->flags, SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
15930fe5d515Smglocker 	if (error) {
15942095c737Smglocker 		printf("%s: bus_dmamap_load error=%d\n", __func__, error);
15952095c737Smglocker 		goto error1;
15962095c737Smglocker 	}
15972095c737Smglocker 
15982095c737Smglocker 	bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize,
15992095c737Smglocker 	    BUS_DMASYNC_PREREAD);
16002095c737Smglocker 
16012095c737Smglocker 	ccb->ccb_cookie = xs;
16022095c737Smglocker 	ccb->ccb_done = ufshci_scsi_io_done;
16032095c737Smglocker 
16042095c737Smglocker 	/* Response length should be UPIU_SCSI_RSP_INQUIRY_SIZE. */
160512f70f1cSmglocker 	error = ufshci_utr_cmd_inquiry(sc, ccb, xs);
16060fe5d515Smglocker 	if (error)
16072095c737Smglocker 		goto error2;
16082095c737Smglocker 
16092095c737Smglocker 	if (ISSET(xs->flags, SCSI_POLL)) {
161093bf5056Smglocker 		if (ufshci_doorbell_poll(sc, ccb->ccb_slot, xs->timeout) == 0) {
16112095c737Smglocker 			ccb->ccb_done(sc, ccb);
16122095c737Smglocker 			return;
16132095c737Smglocker 		}
16142095c737Smglocker 		goto error2;
16152095c737Smglocker         }
16162095c737Smglocker 
16172095c737Smglocker 	return;
16182095c737Smglocker 
16192095c737Smglocker error2:
16202095c737Smglocker 	bus_dmamap_unload(sc->sc_dmat, dmap);
16212095c737Smglocker 	ccb->ccb_cookie = NULL;
162232835f4cSmglocker 	ccb->ccb_status = CCB_STATUS_FREE;
16232095c737Smglocker 	ccb->ccb_done = NULL;
16242095c737Smglocker error1:
16252095c737Smglocker 	xs->error = XS_DRIVER_STUFFUP;
16262095c737Smglocker 	scsi_done(xs);
16272095c737Smglocker }
16282095c737Smglocker 
16292095c737Smglocker void
16302095c737Smglocker ufshci_scsi_capacity16(struct scsi_xfer *xs)
16312095c737Smglocker {
16322095c737Smglocker 	struct scsi_link *link = xs->sc_link;
16332095c737Smglocker 	struct ufshci_softc *sc = link->bus->sb_adapter_softc;
16342095c737Smglocker 	struct ufshci_ccb *ccb = xs->io;
16352095c737Smglocker 	bus_dmamap_t dmap = ccb->ccb_dmamap;
16362095c737Smglocker 	int error;
16372095c737Smglocker 
16386920fd9bSmglocker 	DPRINTF(3, "%s: CAPACITY16 (%s)\n",
16392095c737Smglocker 	    __func__, ISSET(xs->flags, SCSI_POLL) ? "poll"  : "no poll");
16402095c737Smglocker 
16412095c737Smglocker 	if (xs->datalen > UPIU_SCSI_RSP_CAPACITY16_SIZE) {
16426920fd9bSmglocker 		DPRINTF(2, "%s: request len too large\n", __func__);
16432095c737Smglocker 		goto error1;
16442095c737Smglocker 	}
16452095c737Smglocker 
16462095c737Smglocker 	error = bus_dmamap_load(sc->sc_dmat, dmap, xs->data, xs->datalen, NULL,
16472095c737Smglocker 	    ISSET(xs->flags, SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
16480fe5d515Smglocker 	if (error) {
16492095c737Smglocker 		printf("%s: bus_dmamap_load error=%d\n", __func__, error);
16502095c737Smglocker 		goto error1;
16512095c737Smglocker 	}
16522095c737Smglocker 
16532095c737Smglocker 	bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize,
16542095c737Smglocker 	    BUS_DMASYNC_PREREAD);
16552095c737Smglocker 
16562095c737Smglocker 	ccb->ccb_cookie = xs;
16572095c737Smglocker 	ccb->ccb_done = ufshci_scsi_io_done;
16582095c737Smglocker 
16592095c737Smglocker 	/* Response length should be UPIU_SCSI_RSP_CAPACITY16_SIZE. */
166012f70f1cSmglocker 	error = ufshci_utr_cmd_capacity16(sc, ccb, xs);
16610fe5d515Smglocker 	if (error)
16622095c737Smglocker 		goto error2;
16632095c737Smglocker 
16642095c737Smglocker 	if (ISSET(xs->flags, SCSI_POLL)) {
166593bf5056Smglocker 		if (ufshci_doorbell_poll(sc, ccb->ccb_slot, xs->timeout) == 0) {
16662095c737Smglocker 			ccb->ccb_done(sc, ccb);
16672095c737Smglocker 			return;
16682095c737Smglocker 		}
16692095c737Smglocker 		goto error2;
16702095c737Smglocker 	}
16712095c737Smglocker 
16722095c737Smglocker 	return;
16732095c737Smglocker 
16742095c737Smglocker error2:
16752095c737Smglocker 	bus_dmamap_unload(sc->sc_dmat, dmap);
16762095c737Smglocker 	ccb->ccb_cookie = NULL;
167732835f4cSmglocker 	ccb->ccb_status = CCB_STATUS_FREE;
16782095c737Smglocker 	ccb->ccb_done = NULL;
16792095c737Smglocker error1:
16802095c737Smglocker 	xs->error = XS_DRIVER_STUFFUP;
16812095c737Smglocker 	scsi_done(xs);
16822095c737Smglocker }
16832095c737Smglocker 
16842095c737Smglocker void
16852095c737Smglocker ufshci_scsi_capacity(struct scsi_xfer *xs)
16862095c737Smglocker {
16872095c737Smglocker 	struct scsi_link *link = xs->sc_link;
16882095c737Smglocker 	struct ufshci_softc *sc = link->bus->sb_adapter_softc;
16892095c737Smglocker 	struct ufshci_ccb *ccb = xs->io;
16902095c737Smglocker 	bus_dmamap_t dmap = ccb->ccb_dmamap;
16912095c737Smglocker 	int error;
16922095c737Smglocker 
16936920fd9bSmglocker 	DPRINTF(3, "%s: CAPACITY (%s)\n",
16942095c737Smglocker 	    __func__, ISSET(xs->flags, SCSI_POLL) ? "poll"  : "no poll");
16952095c737Smglocker 
16962095c737Smglocker 	if (xs->datalen > UPIU_SCSI_RSP_CAPACITY_SIZE) {
16976920fd9bSmglocker 		DPRINTF(2, "%s: request len too large\n", __func__);
16982095c737Smglocker 		goto error1;
16992095c737Smglocker 	}
17002095c737Smglocker 
17012095c737Smglocker 	error = bus_dmamap_load(sc->sc_dmat, dmap, xs->data, xs->datalen, NULL,
17022095c737Smglocker 	    ISSET(xs->flags, SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
17030fe5d515Smglocker 	if (error) {
17042095c737Smglocker 		printf("%s: bus_dmamap_load error=%d\n", __func__, error);
17052095c737Smglocker 		goto error1;
17062095c737Smglocker         }
17072095c737Smglocker 
17082095c737Smglocker 	bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize,
17092095c737Smglocker 	    BUS_DMASYNC_PREREAD);
17102095c737Smglocker 
17112095c737Smglocker 	ccb->ccb_cookie = xs;
17122095c737Smglocker 	ccb->ccb_done = ufshci_scsi_io_done;
17132095c737Smglocker 
17142095c737Smglocker 	/* Response length should be UPIU_SCSI_RSP_CAPACITY_SIZE */
171512f70f1cSmglocker 	error = ufshci_utr_cmd_capacity(sc, ccb, xs);
17160fe5d515Smglocker 	if (error)
17172095c737Smglocker 		goto error2;
17182095c737Smglocker 
17192095c737Smglocker 	if (ISSET(xs->flags, SCSI_POLL)) {
172093bf5056Smglocker 		if (ufshci_doorbell_poll(sc, ccb->ccb_slot, xs->timeout) == 0) {
17212095c737Smglocker 			ccb->ccb_done(sc, ccb);
17222095c737Smglocker 			return;
17232095c737Smglocker 		}
17242095c737Smglocker 		goto error2;
17252095c737Smglocker 	}
17262095c737Smglocker 
17272095c737Smglocker 	return;
17282095c737Smglocker 
17292095c737Smglocker error2:
17302095c737Smglocker 	bus_dmamap_unload(sc->sc_dmat, dmap);
17312095c737Smglocker 	ccb->ccb_cookie = NULL;
173232835f4cSmglocker 	ccb->ccb_status = CCB_STATUS_FREE;
17332095c737Smglocker 	ccb->ccb_done = NULL;
17342095c737Smglocker error1:
17352095c737Smglocker 	xs->error = XS_DRIVER_STUFFUP;
17362095c737Smglocker 	scsi_done(xs);
17372095c737Smglocker }
17382095c737Smglocker 
17392095c737Smglocker void
17402095c737Smglocker ufshci_scsi_sync(struct scsi_xfer *xs)
17412095c737Smglocker {
17422095c737Smglocker 	struct scsi_link *link = xs->sc_link;
17432095c737Smglocker 	struct ufshci_softc *sc = link->bus->sb_adapter_softc;
17442095c737Smglocker 	struct ufshci_ccb *ccb = xs->io;
17452095c737Smglocker 	uint64_t lba;
17462095c737Smglocker 	uint32_t blocks;
174712f70f1cSmglocker 	int error;
17482095c737Smglocker 
17492095c737Smglocker 	/* lba = 0, blocks = 0: Synchronize all logical blocks. */
17502095c737Smglocker 	lba = 0; blocks = 0;
17512095c737Smglocker 
17526920fd9bSmglocker 	DPRINTF(3, "%s: SYNC, lba=%llu, blocks=%u (%s)\n",
17532095c737Smglocker 	    __func__, lba, blocks,
17542095c737Smglocker 	    ISSET(xs->flags, SCSI_POLL) ? "poll"  : "no poll");
17552095c737Smglocker 
17562095c737Smglocker 	ccb->ccb_cookie = xs;
17572095c737Smglocker 	ccb->ccb_done = ufshci_scsi_done;
17582095c737Smglocker 
175912f70f1cSmglocker 	error = ufshci_utr_cmd_sync(sc, ccb, xs, (uint32_t)lba,
17602095c737Smglocker 	    (uint16_t)blocks);
17610fe5d515Smglocker 	if (error)
17622095c737Smglocker 		goto error;
17632095c737Smglocker 
17642095c737Smglocker 	if (ISSET(xs->flags, SCSI_POLL)) {
176593bf5056Smglocker 		if (ufshci_doorbell_poll(sc, ccb->ccb_slot, xs->timeout) == 0) {
17662095c737Smglocker 			ccb->ccb_done(sc, ccb);
17672095c737Smglocker 			return;
17682095c737Smglocker 		}
17692095c737Smglocker 		goto error;
17702095c737Smglocker 	}
17712095c737Smglocker 
17722095c737Smglocker 	return;
17732095c737Smglocker 
17742095c737Smglocker error:
17752095c737Smglocker         ccb->ccb_cookie = NULL;
177632835f4cSmglocker 	ccb->ccb_status = CCB_STATUS_FREE;
17772095c737Smglocker         ccb->ccb_done = NULL;
17782095c737Smglocker 
17792095c737Smglocker 	xs->error = XS_DRIVER_STUFFUP;
17802095c737Smglocker 	scsi_done(xs);
17812095c737Smglocker }
17822095c737Smglocker 
17832095c737Smglocker void
17842095c737Smglocker ufshci_scsi_io(struct scsi_xfer *xs, int dir)
17852095c737Smglocker {
17862095c737Smglocker 	struct scsi_link *link = xs->sc_link;
17872095c737Smglocker 	struct ufshci_softc *sc = link->bus->sb_adapter_softc;
17882095c737Smglocker 	struct ufshci_ccb *ccb = xs->io;
17892095c737Smglocker 	bus_dmamap_t dmap = ccb->ccb_dmamap;
17902095c737Smglocker 	int error;
17912095c737Smglocker 
17922095c737Smglocker 	if ((xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) != dir)
17932095c737Smglocker 		goto error1;
17942095c737Smglocker 
17956920fd9bSmglocker 	DPRINTF(3, "%s: %s, datalen=%d (%s)\n", __func__,
1796898e5d06Smglocker 	    ISSET(xs->flags, SCSI_DATA_IN) ? "READ" : "WRITE", xs->datalen,
17972095c737Smglocker 	    ISSET(xs->flags, SCSI_POLL) ? "poll"  : "no poll");
17982095c737Smglocker 
17992095c737Smglocker 	error = bus_dmamap_load(sc->sc_dmat, dmap, xs->data, xs->datalen, NULL,
18002095c737Smglocker 	    ISSET(xs->flags, SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
18010fe5d515Smglocker 	if (error) {
18022095c737Smglocker 		printf("%s: bus_dmamap_load error=%d\n", __func__, error);
18032095c737Smglocker 		goto error1;
18042095c737Smglocker 	}
18052095c737Smglocker 
18062095c737Smglocker 	bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize,
18072095c737Smglocker 	    ISSET(xs->flags, SCSI_DATA_IN) ? BUS_DMASYNC_PREREAD :
18082095c737Smglocker 	    BUS_DMASYNC_PREWRITE);
18092095c737Smglocker 
18102095c737Smglocker 	ccb->ccb_cookie = xs;
18112095c737Smglocker 	ccb->ccb_done = ufshci_scsi_io_done;
18122095c737Smglocker 
1813a2f0dcb2Smglocker 	if (dir == SCSI_DATA_IN)
181412f70f1cSmglocker 		error = ufshci_utr_cmd_io(sc, ccb, xs, SCSI_DATA_IN);
1815a2f0dcb2Smglocker 	else
181612f70f1cSmglocker 		error = ufshci_utr_cmd_io(sc, ccb, xs, SCSI_DATA_OUT);
18170fe5d515Smglocker 	if (error)
18182095c737Smglocker 		goto error2;
18192095c737Smglocker 
18202095c737Smglocker 	if (ISSET(xs->flags, SCSI_POLL)) {
182193bf5056Smglocker 		if (ufshci_doorbell_poll(sc, ccb->ccb_slot, xs->timeout) == 0) {
18222095c737Smglocker 			ccb->ccb_done(sc, ccb);
18232095c737Smglocker 			return;
18242095c737Smglocker 		}
18252095c737Smglocker 		goto error2;
18262095c737Smglocker 	}
18272095c737Smglocker 
18282095c737Smglocker 	return;
18292095c737Smglocker 
18302095c737Smglocker error2:
18312095c737Smglocker 	bus_dmamap_unload(sc->sc_dmat, dmap);
18322095c737Smglocker 	ccb->ccb_cookie = NULL;
183332835f4cSmglocker 	ccb->ccb_status = CCB_STATUS_FREE;
18342095c737Smglocker 	ccb->ccb_done = NULL;
18352095c737Smglocker error1:
18362095c737Smglocker 	xs->error = XS_DRIVER_STUFFUP;
18372095c737Smglocker 	scsi_done(xs);
18382095c737Smglocker }
18392095c737Smglocker 
18402095c737Smglocker void
18412095c737Smglocker ufshci_scsi_io_done(struct ufshci_softc *sc, struct ufshci_ccb *ccb)
18422095c737Smglocker {
18432095c737Smglocker 	struct scsi_xfer *xs = ccb->ccb_cookie;
18442095c737Smglocker 	bus_dmamap_t dmap = ccb->ccb_dmamap;
18453bc7f528Smglocker 	struct ufshci_ucd *ucd;
18463bc7f528Smglocker 	struct ufshci_utrd *utrd;
18470b701acdSmglocker 
18482095c737Smglocker 	bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize,
18492095c737Smglocker 	    ISSET(xs->flags, SCSI_DATA_IN) ? BUS_DMASYNC_POSTREAD :
18502095c737Smglocker 	    BUS_DMASYNC_POSTWRITE);
18512095c737Smglocker 
18522095c737Smglocker 	bus_dmamap_unload(sc->sc_dmat, dmap);
18532095c737Smglocker 
18543bc7f528Smglocker 	bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_ucd),
18553bc7f528Smglocker 	    sizeof(*ucd) * ccb->ccb_slot, sizeof(*ucd),
18563bc7f528Smglocker 	    BUS_DMASYNC_POSTWRITE);
18573bc7f528Smglocker 	bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_utrd),
18583bc7f528Smglocker 	    sizeof(*utrd) * ccb->ccb_slot, sizeof(*utrd),
18593bc7f528Smglocker 	    BUS_DMASYNC_POSTWRITE);
18603bc7f528Smglocker 
1861effc6b3aSmglocker 	/* TODO: Do more checks on the Response UPIU in case of errors? */
1862effc6b3aSmglocker 	utrd = UFSHCI_DMA_KVA(sc->sc_dmamem_utrd);
1863effc6b3aSmglocker 	utrd += ccb->ccb_slot;
1864effc6b3aSmglocker 	ucd = UFSHCI_DMA_KVA(sc->sc_dmamem_ucd);
1865effc6b3aSmglocker 	ucd += ccb->ccb_slot;
1866effc6b3aSmglocker 	if (utrd->dw2 != UFSHCI_UTRD_DW2_OCS_SUCCESS) {
1867effc6b3aSmglocker 		printf("%s: error: slot=%d, ocs=0x%x, rsp-tc=0x%x\n",
1868effc6b3aSmglocker 		    __func__, ccb->ccb_slot, utrd->dw2, ucd->rsp.hdr.tc);
1869effc6b3aSmglocker 	}
1870effc6b3aSmglocker 
18712095c737Smglocker 	ccb->ccb_cookie = NULL;
187212f70f1cSmglocker 	ccb->ccb_status = CCB_STATUS_FREE;
18732095c737Smglocker 	ccb->ccb_done = NULL;
18742095c737Smglocker 
1875effc6b3aSmglocker 	xs->error = (utrd->dw2 == UFSHCI_UTRD_DW2_OCS_SUCCESS) ?
1876effc6b3aSmglocker 	    XS_NOERROR : XS_DRIVER_STUFFUP;
18772095c737Smglocker 	xs->status = SCSI_OK;
18782095c737Smglocker 	xs->resid = 0;
18792095c737Smglocker 	scsi_done(xs);
18802095c737Smglocker }
18812095c737Smglocker 
18822095c737Smglocker void
18832095c737Smglocker ufshci_scsi_done(struct ufshci_softc *sc, struct ufshci_ccb *ccb)
18842095c737Smglocker {
18852095c737Smglocker 	struct scsi_xfer *xs = ccb->ccb_cookie;
18863bc7f528Smglocker 	struct ufshci_ucd *ucd;
18873bc7f528Smglocker 	struct ufshci_utrd *utrd;
18883bc7f528Smglocker 
18893bc7f528Smglocker 	bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_ucd),
18903bc7f528Smglocker 	    sizeof(*ucd) * ccb->ccb_slot, sizeof(*ucd),
18913bc7f528Smglocker 	    BUS_DMASYNC_POSTWRITE);
18923bc7f528Smglocker 	bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_utrd),
18933bc7f528Smglocker 	    sizeof(*utrd) * ccb->ccb_slot, sizeof(*utrd),
18943bc7f528Smglocker 	    BUS_DMASYNC_POSTWRITE);
18952095c737Smglocker 
1896effc6b3aSmglocker 	/* TODO: Do more checks on the Response UPIU in case of errors? */
1897effc6b3aSmglocker 	utrd = UFSHCI_DMA_KVA(sc->sc_dmamem_utrd);
1898effc6b3aSmglocker 	utrd += ccb->ccb_slot;
1899effc6b3aSmglocker 	ucd = UFSHCI_DMA_KVA(sc->sc_dmamem_ucd);
1900effc6b3aSmglocker 	ucd += ccb->ccb_slot;
1901effc6b3aSmglocker 	if (utrd->dw2 != UFSHCI_UTRD_DW2_OCS_SUCCESS) {
1902effc6b3aSmglocker 		printf("%s: error: slot=%d, ocs=0x%x, rsp-tc=0x%x\n",
1903effc6b3aSmglocker 		    __func__, ccb->ccb_slot, utrd->dw2, ucd->rsp.hdr.tc);
1904effc6b3aSmglocker 	}
1905effc6b3aSmglocker 
19062095c737Smglocker 	ccb->ccb_cookie = NULL;
190712f70f1cSmglocker 	ccb->ccb_status = CCB_STATUS_FREE;
19082095c737Smglocker 	ccb->ccb_done = NULL;
19092095c737Smglocker 
1910effc6b3aSmglocker 	xs->error = (utrd->dw2 == UFSHCI_UTRD_DW2_OCS_SUCCESS) ?
1911effc6b3aSmglocker 	    XS_NOERROR : XS_DRIVER_STUFFUP;
19122095c737Smglocker 	xs->status = SCSI_OK;
19132095c737Smglocker 	xs->resid = 0;
19142095c737Smglocker 	scsi_done(xs);
19152095c737Smglocker }
191690de4d2dSmglocker 
191790de4d2dSmglocker #if HIBERNATE
191890de4d2dSmglocker int
191990de4d2dSmglocker ufshci_hibernate_io(dev_t dev, daddr_t blkno, vaddr_t addr, size_t size,
192090de4d2dSmglocker     int op, void *page)
192190de4d2dSmglocker {
192290de4d2dSmglocker 	struct ufshci_hibernate_page {
192390de4d2dSmglocker 		struct ufshci_utrd utrd;
192490de4d2dSmglocker 		struct ufshci_ucd ucd;
192590de4d2dSmglocker 
192690de4d2dSmglocker 		struct ufshci_softc *sc;	/* Copy of softc */
192790de4d2dSmglocker 
192890de4d2dSmglocker 		daddr_t	poffset;		/* Start of SWAP partition */
192990de4d2dSmglocker 		size_t psize;			/* Size of SWAP partition */
193090de4d2dSmglocker 		uint32_t secsize;		/* Our sector size */
193190de4d2dSmglocker 	} *my = page;
193290de4d2dSmglocker 	paddr_t data_phys, page_phys;
193390de4d2dSmglocker 	uint64_t data_bus_phys, page_bus_phys;
193490de4d2dSmglocker 	uint64_t timeout_us;
193590de4d2dSmglocker 	int off, len, slot;
193690de4d2dSmglocker 	uint32_t blocks, reg;
193790de4d2dSmglocker 	uint64_t lba;
193890de4d2dSmglocker 
193990de4d2dSmglocker 	if (op == HIB_INIT) {
194090de4d2dSmglocker 		struct device *disk;
194190de4d2dSmglocker 		struct device *scsibus;
194290de4d2dSmglocker 		extern struct cfdriver sd_cd;
194390de4d2dSmglocker 
194490de4d2dSmglocker 		/* Find ufshci softc. */
194590de4d2dSmglocker 		disk = disk_lookup(&sd_cd, DISKUNIT(dev));
194690de4d2dSmglocker 		if (disk == NULL)
194790de4d2dSmglocker 			return ENOTTY;
194890de4d2dSmglocker 		scsibus = disk->dv_parent;
194990de4d2dSmglocker 		my->sc = (struct ufshci_softc *)disk->dv_parent->dv_parent;
195090de4d2dSmglocker 
195190de4d2dSmglocker 		/* Stop run queues and disable interrupts. */
195290de4d2dSmglocker 		ufshci_disable(my->sc);
195390de4d2dSmglocker 
195490de4d2dSmglocker 		/* Tell the controler the new hibernate UTRD address. */
195590de4d2dSmglocker 		pmap_extract(pmap_kernel(), (vaddr_t)page, &page_phys);
195690de4d2dSmglocker 		page_bus_phys = page_phys + ((void *)&my->utrd - page);
195790de4d2dSmglocker 		UFSHCI_WRITE_4(my->sc, UFSHCI_REG_UTRLBA,
195890de4d2dSmglocker 		    (uint32_t)page_bus_phys);
195990de4d2dSmglocker 		UFSHCI_WRITE_4(my->sc, UFSHCI_REG_UTRLBAU,
196090de4d2dSmglocker 		    (uint32_t)(page_bus_phys >> 32));
196190de4d2dSmglocker 
196290de4d2dSmglocker 		/* Start run queues. */
196390de4d2dSmglocker 		UFSHCI_WRITE_4(my->sc, UFSHCI_REG_UTMRLRSR,
196490de4d2dSmglocker 		    UFSHCI_REG_UTMRLRSR_START);
196590de4d2dSmglocker 		UFSHCI_WRITE_4(my->sc, UFSHCI_REG_UTRLRSR,
196690de4d2dSmglocker 		    UFSHCI_REG_UTRLRSR_START);
196790de4d2dSmglocker 
196890de4d2dSmglocker 		my->poffset = blkno;
196990de4d2dSmglocker 		my->psize = size;
197090de4d2dSmglocker 		my->secsize = UFSHCI_LBS;
197190de4d2dSmglocker 
197290de4d2dSmglocker 		return 0;
197390de4d2dSmglocker 	}
197490de4d2dSmglocker 
197590de4d2dSmglocker 	if (op != HIB_W)
197690de4d2dSmglocker 		return 0;
197790de4d2dSmglocker 
197890de4d2dSmglocker 	if (blkno + (size / DEV_BSIZE) > my->psize)
197990de4d2dSmglocker 		return E2BIG;
198090de4d2dSmglocker 	blocks = size / my->secsize;
198190de4d2dSmglocker 	lba = (blkno + my->poffset) / (my->secsize / DEV_BSIZE);
198290de4d2dSmglocker 
198390de4d2dSmglocker 	/*
198490de4d2dSmglocker 	 * The following code is a ripped down version of ufshci_utr_cmd_io()
198590de4d2dSmglocker 	 * adapted for hibernate.
198690de4d2dSmglocker 	 */
198790de4d2dSmglocker 	slot = 0; /* We only use the first slot for hibernate */
198890de4d2dSmglocker 
198990de4d2dSmglocker 	memset(&my->utrd, 0, sizeof(struct ufshci_utrd));
199090de4d2dSmglocker 
199190de4d2dSmglocker 	my->utrd.dw0 = UFSHCI_UTRD_DW0_CT_UFS;
199290de4d2dSmglocker 	my->utrd.dw0 |= UFSHCI_UTRD_DW0_DD_I2T;
199390de4d2dSmglocker 	my->utrd.dw0 |= UFSHCI_UTRD_DW0_I_REG;
199490de4d2dSmglocker 	my->utrd.dw2 = UFSHCI_UTRD_DW2_OCS_IOV;
199590de4d2dSmglocker 
199690de4d2dSmglocker 	memset(&my->ucd, 0, sizeof(struct ufshci_ucd));
199790de4d2dSmglocker 
199890de4d2dSmglocker 	my->ucd.cmd.hdr.tc = UPIU_TC_I2T_COMMAND;
199990de4d2dSmglocker 	my->ucd.cmd.hdr.flags = (1 << 5); /* Bit-5 = Write */
200090de4d2dSmglocker 
200190de4d2dSmglocker 	my->ucd.cmd.hdr.lun = 0;
200290de4d2dSmglocker 	my->ucd.cmd.hdr.task_tag = slot;
200390de4d2dSmglocker 	my->ucd.cmd.hdr.cmd_set_type = 0; /* SCSI command */
200490de4d2dSmglocker 	my->ucd.cmd.hdr.query = 0;
200590de4d2dSmglocker 	my->ucd.cmd.hdr.response = 0;
200690de4d2dSmglocker 	my->ucd.cmd.hdr.status = 0;
200790de4d2dSmglocker 	my->ucd.cmd.hdr.ehs_len = 0;
200890de4d2dSmglocker 	my->ucd.cmd.hdr.device_info = 0;
200990de4d2dSmglocker 	my->ucd.cmd.hdr.ds_len = 0;
201090de4d2dSmglocker 
201190de4d2dSmglocker 	my->ucd.cmd.expected_xfer_len = htobe32(UFSHCI_LBS * blocks);
201290de4d2dSmglocker 	my->ucd.cmd.cdb[0] = WRITE_10; /* 0x2a */
201390de4d2dSmglocker 	my->ucd.cmd.cdb[1] = (1 << 3); /* FUA: Force Unit Access */
201490de4d2dSmglocker 	my->ucd.cmd.cdb[2] = (lba >> 24) & 0xff;
201590de4d2dSmglocker 	my->ucd.cmd.cdb[3] = (lba >> 16) & 0xff;
201690de4d2dSmglocker 	my->ucd.cmd.cdb[4] = (lba >>  8) & 0xff;
201790de4d2dSmglocker 	my->ucd.cmd.cdb[5] = (lba >>  0) & 0xff;
201890de4d2dSmglocker 	my->ucd.cmd.cdb[7] = (blocks >> 8) & 0xff;
201990de4d2dSmglocker 	my->ucd.cmd.cdb[8] = (blocks >> 0) & 0xff;
202090de4d2dSmglocker 
202190de4d2dSmglocker 	pmap_extract(pmap_kernel(), (vaddr_t)page, &page_phys);
202290de4d2dSmglocker 	page_bus_phys = page_phys + ((void *)&my->ucd - page);
202390de4d2dSmglocker 	my->utrd.dw4 = (uint32_t)page_bus_phys;
202490de4d2dSmglocker 	my->utrd.dw5 = (uint32_t)(page_bus_phys >> 32);
202590de4d2dSmglocker 
202690de4d2dSmglocker 	off = sizeof(struct upiu_command) / 4; /* DWORD offset */
202790de4d2dSmglocker 	my->utrd.dw6 = UFSHCI_UTRD_DW6_RUO(off);
202890de4d2dSmglocker 
202990de4d2dSmglocker 	len = sizeof(struct upiu_response) / 4; /* DWORD length */
203090de4d2dSmglocker 	my->utrd.dw6 |= UFSHCI_UTRD_DW6_RUL(len);
203190de4d2dSmglocker 
203290de4d2dSmglocker 	off = (sizeof(struct upiu_command) + sizeof(struct upiu_response)) / 4;
203390de4d2dSmglocker 	my->utrd.dw7 = UFSHCI_UTRD_DW7_PRDTO(off);
203490de4d2dSmglocker 
203590de4d2dSmglocker 	my->utrd.dw7 |= UFSHCI_UTRD_DW7_PRDTL(1); /* dm_nsegs */
203690de4d2dSmglocker 
203790de4d2dSmglocker 	pmap_extract(pmap_kernel(), (vaddr_t)addr, &data_phys);
203890de4d2dSmglocker 	data_bus_phys = data_phys;
203990de4d2dSmglocker 	my->ucd.prdt[0].dw0 = (uint32_t)data_bus_phys;
204090de4d2dSmglocker 	my->ucd.prdt[0].dw1 = (uint32_t)(data_bus_phys >> 32);
204190de4d2dSmglocker 	my->ucd.prdt[0].dw2 = 0;
204290de4d2dSmglocker 	my->ucd.prdt[0].dw3 = size - 1; /* ds_len */
204390de4d2dSmglocker 
204490de4d2dSmglocker 	if (UFSHCI_READ_4(my->sc, UFSHCI_REG_UTRLRSR) != 1)
204590de4d2dSmglocker 		return EIO;
204690de4d2dSmglocker 
204790de4d2dSmglocker 	ufshci_doorbell_write(my->sc, slot);
204890de4d2dSmglocker 
204990de4d2dSmglocker 	/* ufshci_doorbell_poll() adaption for hibernate. */
205090de4d2dSmglocker 	for (timeout_us = 1000000 * 1000; timeout_us != 0;
205190de4d2dSmglocker 	    timeout_us -= 1000) {
205290de4d2dSmglocker 		reg = UFSHCI_READ_4(my->sc, UFSHCI_REG_UTRLDBR);
205390de4d2dSmglocker 		if ((reg & (1U << slot)) == 0)
205490de4d2dSmglocker 			break;
205590de4d2dSmglocker 		delay(1000);
205690de4d2dSmglocker 	}
205790de4d2dSmglocker 	if (timeout_us == 0)
205890de4d2dSmglocker 		return EIO;
205990de4d2dSmglocker 	UFSHCI_WRITE_4(my->sc, UFSHCI_REG_UTRLCNR, (1U << slot));
206090de4d2dSmglocker 
206190de4d2dSmglocker 	/* Check if the command was succesfully executed. */
206290de4d2dSmglocker 	if (my->utrd.dw2 != UFSHCI_UTRD_DW2_OCS_SUCCESS)
206390de4d2dSmglocker 		return EIO;
206490de4d2dSmglocker 
206590de4d2dSmglocker 	return 0;
206690de4d2dSmglocker }
206790de4d2dSmglocker #endif /* HIBERNATE */
2068