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