1c3aac50fSPeter Wemm /* $FreeBSD$ */ 265adb54cSMatt Jacob /* 365adb54cSMatt Jacob * PCI specific probe and attach routines for Qlogic ISP SCSI adapters. 465adb54cSMatt Jacob * FreeBSD Version. 565adb54cSMatt Jacob * 65f5aafe1SMatt Jacob * Copyright (c) 1997, 1998, 1999, 2000, 2001 by Matthew Jacob 765adb54cSMatt Jacob * 865adb54cSMatt Jacob * Redistribution and use in source and binary forms, with or without 965adb54cSMatt Jacob * modification, are permitted provided that the following conditions 1065adb54cSMatt Jacob * are met: 1165adb54cSMatt Jacob * 1. Redistributions of source code must retain the above copyright 1265adb54cSMatt Jacob * notice immediately at the beginning of the file, without modification, 1365adb54cSMatt Jacob * this list of conditions, and the following disclaimer. 14aa57fd6fSMatt Jacob * 2. The name of the author may not be used to endorse or promote products 15aa57fd6fSMatt Jacob * derived from this software without specific prior written permission. 1665adb54cSMatt Jacob * 1765adb54cSMatt Jacob * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1865adb54cSMatt Jacob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1965adb54cSMatt Jacob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2065adb54cSMatt Jacob * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2165adb54cSMatt Jacob * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2265adb54cSMatt Jacob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2365adb54cSMatt Jacob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2465adb54cSMatt Jacob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2565adb54cSMatt Jacob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2665adb54cSMatt Jacob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2765adb54cSMatt Jacob * SUCH DAMAGE. 2865adb54cSMatt Jacob */ 29d720e6d5SJustin T. Gibbs 30960f6939SMatt Jacob #include <sys/param.h> 31960f6939SMatt Jacob #include <sys/systm.h> 32960f6939SMatt Jacob #include <sys/kernel.h> 33960f6939SMatt Jacob #include <sys/module.h> 34960f6939SMatt Jacob #include <sys/bus.h> 3565adb54cSMatt Jacob 3665adb54cSMatt Jacob #include <pci/pcireg.h> 3765adb54cSMatt Jacob #include <pci/pcivar.h> 3865adb54cSMatt Jacob 39d720e6d5SJustin T. Gibbs #include <machine/bus_memio.h> 40d720e6d5SJustin T. Gibbs #include <machine/bus_pio.h> 41d720e6d5SJustin T. Gibbs #include <machine/bus.h> 42960f6939SMatt Jacob #include <machine/resource.h> 43960f6939SMatt Jacob #include <sys/rman.h> 44960f6939SMatt Jacob #include <sys/malloc.h> 45960f6939SMatt Jacob 46960f6939SMatt Jacob #include <dev/isp/isp_freebsd.h> 47d59bd469SMatt Jacob 4865adb54cSMatt Jacob static u_int16_t isp_pci_rd_reg __P((struct ispsoftc *, int)); 4965adb54cSMatt Jacob static void isp_pci_wr_reg __P((struct ispsoftc *, int, u_int16_t)); 50d59bd469SMatt Jacob static u_int16_t isp_pci_rd_reg_1080 __P((struct ispsoftc *, int)); 51d59bd469SMatt Jacob static void isp_pci_wr_reg_1080 __P((struct ispsoftc *, int, u_int16_t)); 5265adb54cSMatt Jacob static int isp_pci_mbxdma __P((struct ispsoftc *)); 53d02373f1SMatt Jacob static int isp_pci_dmasetup __P((struct ispsoftc *, XS_T *, 549637d68cSMatt Jacob ispreq_t *, u_int16_t *, u_int16_t)); 55d720e6d5SJustin T. Gibbs static void 56d8d5f2adSMatt Jacob isp_pci_dmateardown __P((struct ispsoftc *, XS_T *, u_int16_t)); 5765adb54cSMatt Jacob 5865adb54cSMatt Jacob static void isp_pci_reset1 __P((struct ispsoftc *)); 59d02373f1SMatt Jacob static void isp_pci_dumpregs __P((struct ispsoftc *, const char *)); 6065adb54cSMatt Jacob 61fed92c47SMatt Jacob #ifndef ISP_CODE_ORG 62fed92c47SMatt Jacob #define ISP_CODE_ORG 0x1000 63fed92c47SMatt Jacob #endif 64fed92c47SMatt Jacob 6565adb54cSMatt Jacob static struct ispmdvec mdvec = { 6665adb54cSMatt Jacob isp_pci_rd_reg, 6765adb54cSMatt Jacob isp_pci_wr_reg, 6865adb54cSMatt Jacob isp_pci_mbxdma, 6965adb54cSMatt Jacob isp_pci_dmasetup, 70d720e6d5SJustin T. Gibbs isp_pci_dmateardown, 7165adb54cSMatt Jacob NULL, 7265adb54cSMatt Jacob isp_pci_reset1, 7365adb54cSMatt Jacob isp_pci_dumpregs, 7456aef503SMatt Jacob NULL, 75d02373f1SMatt Jacob BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64 7665adb54cSMatt Jacob }; 7765adb54cSMatt Jacob 78d59bd469SMatt Jacob static struct ispmdvec mdvec_1080 = { 79d59bd469SMatt Jacob isp_pci_rd_reg_1080, 80d59bd469SMatt Jacob isp_pci_wr_reg_1080, 81d59bd469SMatt Jacob isp_pci_mbxdma, 82d59bd469SMatt Jacob isp_pci_dmasetup, 83d59bd469SMatt Jacob isp_pci_dmateardown, 84d59bd469SMatt Jacob NULL, 85d59bd469SMatt Jacob isp_pci_reset1, 86d59bd469SMatt Jacob isp_pci_dumpregs, 8756aef503SMatt Jacob NULL, 88d02373f1SMatt Jacob BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64 89d59bd469SMatt Jacob }; 90d59bd469SMatt Jacob 91960f6939SMatt Jacob static struct ispmdvec mdvec_12160 = { 92960f6939SMatt Jacob isp_pci_rd_reg_1080, 93960f6939SMatt Jacob isp_pci_wr_reg_1080, 94960f6939SMatt Jacob isp_pci_mbxdma, 95960f6939SMatt Jacob isp_pci_dmasetup, 96960f6939SMatt Jacob isp_pci_dmateardown, 97960f6939SMatt Jacob NULL, 98960f6939SMatt Jacob isp_pci_reset1, 99960f6939SMatt Jacob isp_pci_dumpregs, 10056aef503SMatt Jacob NULL, 101d02373f1SMatt Jacob BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64 102960f6939SMatt Jacob }; 103960f6939SMatt Jacob 10465adb54cSMatt Jacob static struct ispmdvec mdvec_2100 = { 10565adb54cSMatt Jacob isp_pci_rd_reg, 10665adb54cSMatt Jacob isp_pci_wr_reg, 10765adb54cSMatt Jacob isp_pci_mbxdma, 10865adb54cSMatt Jacob isp_pci_dmasetup, 109d720e6d5SJustin T. Gibbs isp_pci_dmateardown, 11065adb54cSMatt Jacob NULL, 11165adb54cSMatt Jacob isp_pci_reset1, 112d02373f1SMatt Jacob isp_pci_dumpregs 11365adb54cSMatt Jacob }; 114222bb542SMatt Jacob 115222bb542SMatt Jacob static struct ispmdvec mdvec_2200 = { 116222bb542SMatt Jacob isp_pci_rd_reg, 117222bb542SMatt Jacob isp_pci_wr_reg, 118222bb542SMatt Jacob isp_pci_mbxdma, 119222bb542SMatt Jacob isp_pci_dmasetup, 120222bb542SMatt Jacob isp_pci_dmateardown, 121222bb542SMatt Jacob NULL, 122222bb542SMatt Jacob isp_pci_reset1, 123d02373f1SMatt Jacob isp_pci_dumpregs 124222bb542SMatt Jacob }; 125d951bbcaSMatt Jacob 12665adb54cSMatt Jacob #ifndef PCIM_CMD_INVEN 12765adb54cSMatt Jacob #define PCIM_CMD_INVEN 0x10 12865adb54cSMatt Jacob #endif 12965adb54cSMatt Jacob #ifndef PCIM_CMD_BUSMASTEREN 13065adb54cSMatt Jacob #define PCIM_CMD_BUSMASTEREN 0x0004 13165adb54cSMatt Jacob #endif 132d951bbcaSMatt Jacob #ifndef PCIM_CMD_PERRESPEN 133d951bbcaSMatt Jacob #define PCIM_CMD_PERRESPEN 0x0040 134d951bbcaSMatt Jacob #endif 135d951bbcaSMatt Jacob #ifndef PCIM_CMD_SEREN 136d951bbcaSMatt Jacob #define PCIM_CMD_SEREN 0x0100 137d951bbcaSMatt Jacob #endif 138d951bbcaSMatt Jacob 139d951bbcaSMatt Jacob #ifndef PCIR_COMMAND 140d951bbcaSMatt Jacob #define PCIR_COMMAND 0x04 141d951bbcaSMatt Jacob #endif 142d951bbcaSMatt Jacob 143d951bbcaSMatt Jacob #ifndef PCIR_CACHELNSZ 144d951bbcaSMatt Jacob #define PCIR_CACHELNSZ 0x0c 145d951bbcaSMatt Jacob #endif 146d951bbcaSMatt Jacob 147d951bbcaSMatt Jacob #ifndef PCIR_LATTIMER 148d951bbcaSMatt Jacob #define PCIR_LATTIMER 0x0d 149d951bbcaSMatt Jacob #endif 150d951bbcaSMatt Jacob 151ab6d0040SMatt Jacob #ifndef PCIR_ROMADDR 152ab6d0040SMatt Jacob #define PCIR_ROMADDR 0x30 153ab6d0040SMatt Jacob #endif 154ab6d0040SMatt Jacob 15565adb54cSMatt Jacob #ifndef PCI_VENDOR_QLOGIC 15665adb54cSMatt Jacob #define PCI_VENDOR_QLOGIC 0x1077 15765adb54cSMatt Jacob #endif 15865adb54cSMatt Jacob 15965adb54cSMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP1020 16065adb54cSMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP1020 0x1020 16165adb54cSMatt Jacob #endif 16265adb54cSMatt Jacob 163d59bd469SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP1080 164d59bd469SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP1080 0x1080 165d59bd469SMatt Jacob #endif 166d59bd469SMatt Jacob 167960f6939SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP12160 168960f6939SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP12160 0x1216 169960f6939SMatt Jacob #endif 170960f6939SMatt Jacob 171d59bd469SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP1240 172d59bd469SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP1240 0x1240 173d59bd469SMatt Jacob #endif 17465adb54cSMatt Jacob 17522e1dc85SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP1280 17622e1dc85SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP1280 0x1280 17722e1dc85SMatt Jacob #endif 17822e1dc85SMatt Jacob 17965adb54cSMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP2100 18065adb54cSMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP2100 0x2100 18165adb54cSMatt Jacob #endif 18265adb54cSMatt Jacob 183222bb542SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP2200 184222bb542SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP2200 0x2200 185222bb542SMatt Jacob #endif 186222bb542SMatt Jacob 18756aef503SMatt Jacob #define PCI_QLOGIC_ISP1020 \ 18856aef503SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP1020 << 16) | PCI_VENDOR_QLOGIC) 189d59bd469SMatt Jacob 190d59bd469SMatt Jacob #define PCI_QLOGIC_ISP1080 \ 191d59bd469SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP1080 << 16) | PCI_VENDOR_QLOGIC) 192d59bd469SMatt Jacob 193960f6939SMatt Jacob #define PCI_QLOGIC_ISP12160 \ 194960f6939SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP12160 << 16) | PCI_VENDOR_QLOGIC) 195960f6939SMatt Jacob 196d59bd469SMatt Jacob #define PCI_QLOGIC_ISP1240 \ 197d59bd469SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP1240 << 16) | PCI_VENDOR_QLOGIC) 198d59bd469SMatt Jacob 19922e1dc85SMatt Jacob #define PCI_QLOGIC_ISP1280 \ 20022e1dc85SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP1280 << 16) | PCI_VENDOR_QLOGIC) 20122e1dc85SMatt Jacob 20265adb54cSMatt Jacob #define PCI_QLOGIC_ISP2100 \ 20365adb54cSMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP2100 << 16) | PCI_VENDOR_QLOGIC) 20465adb54cSMatt Jacob 205222bb542SMatt Jacob #define PCI_QLOGIC_ISP2200 \ 206222bb542SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP2200 << 16) | PCI_VENDOR_QLOGIC) 207222bb542SMatt Jacob 208e11a1ee8SMatt Jacob /* 209e11a1ee8SMatt Jacob * Odd case for some AMI raid cards... We need to *not* attach to this. 210e11a1ee8SMatt Jacob */ 211e11a1ee8SMatt Jacob #define AMI_RAID_SUBVENDOR_ID 0x101e 212e11a1ee8SMatt Jacob 21365adb54cSMatt Jacob #define IO_MAP_REG 0x10 21465adb54cSMatt Jacob #define MEM_MAP_REG 0x14 21565adb54cSMatt Jacob 216d951bbcaSMatt Jacob #define PCI_DFLT_LTNCY 0x40 217d951bbcaSMatt Jacob #define PCI_DFLT_LNSZ 0x10 21865adb54cSMatt Jacob 219960f6939SMatt Jacob static int isp_pci_probe (device_t); 220960f6939SMatt Jacob static int isp_pci_attach (device_t); 22165adb54cSMatt Jacob 22265adb54cSMatt Jacob struct isp_pcisoftc { 22365adb54cSMatt Jacob struct ispsoftc pci_isp; 224960f6939SMatt Jacob device_t pci_dev; 225960f6939SMatt Jacob struct resource * pci_reg; 22665adb54cSMatt Jacob bus_space_tag_t pci_st; 22765adb54cSMatt Jacob bus_space_handle_t pci_sh; 228960f6939SMatt Jacob void * ih; 229d59bd469SMatt Jacob int16_t pci_poff[_NREG_BLKS]; 230d720e6d5SJustin T. Gibbs bus_dma_tag_t parent_dmat; 231d720e6d5SJustin T. Gibbs bus_dma_tag_t cntrol_dmat; 232d720e6d5SJustin T. Gibbs bus_dmamap_t cntrol_dmap; 233a95ae193SMatt Jacob bus_dmamap_t *dmaps; 23465adb54cSMatt Jacob }; 23556aef503SMatt Jacob ispfwfunc *isp_get_firmware_p = NULL; 23665adb54cSMatt Jacob 237960f6939SMatt Jacob static device_method_t isp_pci_methods[] = { 238960f6939SMatt Jacob /* Device interface */ 239960f6939SMatt Jacob DEVMETHOD(device_probe, isp_pci_probe), 240960f6939SMatt Jacob DEVMETHOD(device_attach, isp_pci_attach), 241960f6939SMatt Jacob { 0, 0 } 24265adb54cSMatt Jacob }; 243f09b1922SMatt Jacob static void isp_pci_intr __P((void *)); 24465adb54cSMatt Jacob 245960f6939SMatt Jacob static driver_t isp_pci_driver = { 246960f6939SMatt Jacob "isp", isp_pci_methods, sizeof (struct isp_pcisoftc) 247960f6939SMatt Jacob }; 248960f6939SMatt Jacob static devclass_t isp_devclass; 249960f6939SMatt Jacob DRIVER_MODULE(isp, pci, isp_pci_driver, isp_devclass, 0, 0); 25056aef503SMatt Jacob MODULE_VERSION(isp, 1); 25165adb54cSMatt Jacob 252960f6939SMatt Jacob static int 253960f6939SMatt Jacob isp_pci_probe(device_t dev) 25465adb54cSMatt Jacob { 255960f6939SMatt Jacob switch ((pci_get_device(dev) << 16) | (pci_get_vendor(dev))) { 25656aef503SMatt Jacob case PCI_QLOGIC_ISP1020: 257960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 1020/1040 PCI SCSI Adapter"); 25865adb54cSMatt Jacob break; 259d59bd469SMatt Jacob case PCI_QLOGIC_ISP1080: 260960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 1080 PCI SCSI Adapter"); 261c6608df3SMatt Jacob break; 262c6608df3SMatt Jacob case PCI_QLOGIC_ISP1240: 263960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 1240 PCI SCSI Adapter"); 264d59bd469SMatt Jacob break; 26522e1dc85SMatt Jacob case PCI_QLOGIC_ISP1280: 266960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 1280 PCI SCSI Adapter"); 267960f6939SMatt Jacob break; 268960f6939SMatt Jacob case PCI_QLOGIC_ISP12160: 269e11a1ee8SMatt Jacob if (pci_get_subvendor(dev) == AMI_RAID_SUBVENDOR_ID) { 270e11a1ee8SMatt Jacob return (ENXIO); 271e11a1ee8SMatt Jacob } 272960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 12160 PCI SCSI Adapter"); 27322e1dc85SMatt Jacob break; 27465adb54cSMatt Jacob case PCI_QLOGIC_ISP2100: 275960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 2100 PCI FC-AL Adapter"); 27665adb54cSMatt Jacob break; 2775542fe4bSMatt Jacob case PCI_QLOGIC_ISP2200: 278960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 2200 PCI FC-AL Adapter"); 2795542fe4bSMatt Jacob break; 28065adb54cSMatt Jacob default: 281960f6939SMatt Jacob return (ENXIO); 28265adb54cSMatt Jacob } 283d02373f1SMatt Jacob if (device_get_unit(dev) == 0 && bootverbose) { 284d02373f1SMatt Jacob printf("Qlogic ISP Driver, FreeBSD Version %d.%d, " 285a95ae193SMatt Jacob "Core Version %d.%d\n", 286d720e6d5SJustin T. Gibbs ISP_PLATFORM_VERSION_MAJOR, ISP_PLATFORM_VERSION_MINOR, 287d720e6d5SJustin T. Gibbs ISP_CORE_VERSION_MAJOR, ISP_CORE_VERSION_MINOR); 28865adb54cSMatt Jacob } 28956aef503SMatt Jacob /* 29056aef503SMatt Jacob * XXXX: Here is where we might load the f/w module 29156aef503SMatt Jacob * XXXX: (or increase a reference count to it). 29256aef503SMatt Jacob */ 293960f6939SMatt Jacob return (0); 29465adb54cSMatt Jacob } 29565adb54cSMatt Jacob 296960f6939SMatt Jacob static int 297960f6939SMatt Jacob isp_pci_attach(device_t dev) 29865adb54cSMatt Jacob { 299960f6939SMatt Jacob struct resource *regs, *irq; 3006e5c5328SMatt Jacob int tval, rtp, rgd, iqd, m1, m2, isp_debug, role; 301960f6939SMatt Jacob u_int32_t data, cmd, linesz, psize, basetype; 30265adb54cSMatt Jacob struct isp_pcisoftc *pcs; 3033395b056SMatt Jacob struct ispsoftc *isp = NULL; 304c6608df3SMatt Jacob struct ispmdvec *mdvp; 305222bb542SMatt Jacob bus_size_t lim; 3066e5c5328SMatt Jacob char *sptr; 3073395b056SMatt Jacob #ifdef ISP_SMPLOCK 3083395b056SMatt Jacob int locksetup = 0; 3093395b056SMatt Jacob #endif 31065adb54cSMatt Jacob 311222bb542SMatt Jacob /* 3129ba86737SMatt Jacob * Figure out if we're supposed to skip this one. 313b9b599feSMatt Jacob * If we are, we actually go to ISP_ROLE_NONE. 3149ba86737SMatt Jacob */ 3156e5c5328SMatt Jacob 3166e5c5328SMatt Jacob tval = 0; 3176e5c5328SMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 3186e5c5328SMatt Jacob "disable", &tval) == 0 && tval) { 319b9b599feSMatt Jacob device_printf(dev, "device is disabled\n"); 320b9b599feSMatt Jacob /* but return 0 so the !$)$)*!$*) unit isn't reused */ 321b9b599feSMatt Jacob return (0); 322b9b599feSMatt Jacob } 3236e5c5328SMatt Jacob 3246e5c5328SMatt Jacob role = 0; 3256e5c5328SMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 3266e5c5328SMatt Jacob "role", &role) == 0 && 3276e5c5328SMatt Jacob ((role & ~(ISP_ROLE_INITIATOR|ISP_ROLE_TARGET)) == 0)) { 3286e5c5328SMatt Jacob device_printf(dev, "setting role to 0x%x\n", role); 3296e5c5328SMatt Jacob } else { 330b9b599feSMatt Jacob #ifdef ISP_TARGET_MODE 331b9b599feSMatt Jacob role = ISP_ROLE_INITIATOR|ISP_ROLE_TARGET; 332b9b599feSMatt Jacob #else 333b9b599feSMatt Jacob role = ISP_DEFAULT_ROLES; 334b9b599feSMatt Jacob #endif 3359ba86737SMatt Jacob } 3369ba86737SMatt Jacob 3377cc0979fSDavid Malone pcs = malloc(sizeof (struct isp_pcisoftc), M_DEVBUF, M_NOWAIT | M_ZERO); 338960f6939SMatt Jacob if (pcs == NULL) { 339960f6939SMatt Jacob device_printf(dev, "cannot allocate softc\n"); 340960f6939SMatt Jacob return (ENOMEM); 341960f6939SMatt Jacob } 342960f6939SMatt Jacob 3439ba86737SMatt Jacob /* 344222bb542SMatt Jacob * Figure out which we should try first - memory mapping or i/o mapping? 345222bb542SMatt Jacob */ 34656aef503SMatt Jacob #ifdef __alpha__ 347960f6939SMatt Jacob m1 = PCIM_CMD_MEMEN; 348960f6939SMatt Jacob m2 = PCIM_CMD_PORTEN; 349222bb542SMatt Jacob #else 350960f6939SMatt Jacob m1 = PCIM_CMD_PORTEN; 351960f6939SMatt Jacob m2 = PCIM_CMD_MEMEN; 352222bb542SMatt Jacob #endif 3536e5c5328SMatt Jacob 3546e5c5328SMatt Jacob tval = 0; 3556e5c5328SMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 3566e5c5328SMatt Jacob "prefer_iomap", &tval) == 0 && tval != 0) { 357960f6939SMatt Jacob m1 = PCIM_CMD_PORTEN; 358960f6939SMatt Jacob m2 = PCIM_CMD_MEMEN; 359960f6939SMatt Jacob } 3606e5c5328SMatt Jacob tval = 0; 3616e5c5328SMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 3626e5c5328SMatt Jacob "prefer_memmap", &tval) == 0 && tval != 0) { 3636e5c5328SMatt Jacob m1 = PCIM_CMD_MEMEN; 3646e5c5328SMatt Jacob m2 = PCIM_CMD_PORTEN; 365222bb542SMatt Jacob } 366222bb542SMatt Jacob 367ab6d0040SMatt Jacob linesz = PCI_DFLT_LNSZ; 368960f6939SMatt Jacob irq = regs = NULL; 369960f6939SMatt Jacob rgd = rtp = iqd = 0; 370960f6939SMatt Jacob 371960f6939SMatt Jacob cmd = pci_read_config(dev, PCIR_COMMAND, 1); 372960f6939SMatt Jacob if (cmd & m1) { 373960f6939SMatt Jacob rtp = (m1 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT; 374960f6939SMatt Jacob rgd = (m1 == PCIM_CMD_MEMEN)? MEM_MAP_REG : IO_MAP_REG; 375960f6939SMatt Jacob regs = bus_alloc_resource(dev, rtp, &rgd, 0, ~0, 1, RF_ACTIVE); 37665adb54cSMatt Jacob } 377960f6939SMatt Jacob if (regs == NULL && (cmd & m2)) { 378960f6939SMatt Jacob rtp = (m2 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT; 379960f6939SMatt Jacob rgd = (m2 == PCIM_CMD_MEMEN)? MEM_MAP_REG : IO_MAP_REG; 380960f6939SMatt Jacob regs = bus_alloc_resource(dev, rtp, &rgd, 0, ~0, 1, RF_ACTIVE); 38165adb54cSMatt Jacob } 382960f6939SMatt Jacob if (regs == NULL) { 383960f6939SMatt Jacob device_printf(dev, "unable to map any ports\n"); 384960f6939SMatt Jacob goto bad; 38565adb54cSMatt Jacob } 386222bb542SMatt Jacob if (bootverbose) 387f7dddf8aSMatt Jacob device_printf(dev, "using %s space register mapping\n", 388960f6939SMatt Jacob (rgd == IO_MAP_REG)? "I/O" : "Memory"); 389960f6939SMatt Jacob pcs->pci_dev = dev; 390960f6939SMatt Jacob pcs->pci_reg = regs; 391960f6939SMatt Jacob pcs->pci_st = rman_get_bustag(regs); 392960f6939SMatt Jacob pcs->pci_sh = rman_get_bushandle(regs); 39365adb54cSMatt Jacob 394d59bd469SMatt Jacob pcs->pci_poff[BIU_BLOCK >> _BLK_REG_SHFT] = BIU_REGS_OFF; 395d59bd469SMatt Jacob pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS_OFF; 396d59bd469SMatt Jacob pcs->pci_poff[SXP_BLOCK >> _BLK_REG_SHFT] = PCI_SXP_REGS_OFF; 397d59bd469SMatt Jacob pcs->pci_poff[RISC_BLOCK >> _BLK_REG_SHFT] = PCI_RISC_REGS_OFF; 398d59bd469SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = DMA_REGS_OFF; 399c6608df3SMatt Jacob mdvp = &mdvec; 400c6608df3SMatt Jacob basetype = ISP_HA_SCSI_UNKNOWN; 401c6608df3SMatt Jacob psize = sizeof (sdparam); 402222bb542SMatt Jacob lim = BUS_SPACE_MAXSIZE_32BIT; 40356aef503SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP1020) { 404c6608df3SMatt Jacob mdvp = &mdvec; 405c6608df3SMatt Jacob basetype = ISP_HA_SCSI_UNKNOWN; 406c6608df3SMatt Jacob psize = sizeof (sdparam); 407222bb542SMatt Jacob lim = BUS_SPACE_MAXSIZE_24BIT; 408d59bd469SMatt Jacob } 409960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP1080) { 410c6608df3SMatt Jacob mdvp = &mdvec_1080; 411c6608df3SMatt Jacob basetype = ISP_HA_SCSI_1080; 412c6608df3SMatt Jacob psize = sizeof (sdparam); 413c6608df3SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 414c6608df3SMatt Jacob ISP1080_DMA_REGS_OFF; 415c6608df3SMatt Jacob } 416960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP1240) { 417c6608df3SMatt Jacob mdvp = &mdvec_1080; 41822e1dc85SMatt Jacob basetype = ISP_HA_SCSI_1240; 41922e1dc85SMatt Jacob psize = 2 * sizeof (sdparam); 42022e1dc85SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 42122e1dc85SMatt Jacob ISP1080_DMA_REGS_OFF; 42222e1dc85SMatt Jacob } 423960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP1280) { 42422e1dc85SMatt Jacob mdvp = &mdvec_1080; 42522e1dc85SMatt Jacob basetype = ISP_HA_SCSI_1280; 426c6608df3SMatt Jacob psize = 2 * sizeof (sdparam); 427d59bd469SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 428d59bd469SMatt Jacob ISP1080_DMA_REGS_OFF; 429d59bd469SMatt Jacob } 430960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP12160) { 431960f6939SMatt Jacob mdvp = &mdvec_12160; 432960f6939SMatt Jacob basetype = ISP_HA_SCSI_12160; 433960f6939SMatt Jacob psize = 2 * sizeof (sdparam); 434960f6939SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 435960f6939SMatt Jacob ISP1080_DMA_REGS_OFF; 436960f6939SMatt Jacob } 437960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP2100) { 438c6608df3SMatt Jacob mdvp = &mdvec_2100; 439c6608df3SMatt Jacob basetype = ISP_HA_FC_2100; 440c6608df3SMatt Jacob psize = sizeof (fcparam); 441d59bd469SMatt Jacob pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = 442d59bd469SMatt Jacob PCI_MBOX_REGS2100_OFF; 443960f6939SMatt Jacob if (pci_get_revid(dev) < 3) { 444ab6d0040SMatt Jacob /* 445ab6d0040SMatt Jacob * XXX: Need to get the actual revision 446ab6d0040SMatt Jacob * XXX: number of the 2100 FB. At any rate, 447ab6d0040SMatt Jacob * XXX: lower cache line size for early revision 448ab6d0040SMatt Jacob * XXX; boards. 449ab6d0040SMatt Jacob */ 450ab6d0040SMatt Jacob linesz = 1; 451ab6d0040SMatt Jacob } 45265adb54cSMatt Jacob } 453960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP2200) { 454222bb542SMatt Jacob mdvp = &mdvec_2200; 455222bb542SMatt Jacob basetype = ISP_HA_FC_2200; 456222bb542SMatt Jacob psize = sizeof (fcparam); 457222bb542SMatt Jacob pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = 458222bb542SMatt Jacob PCI_MBOX_REGS2100_OFF; 459222bb542SMatt Jacob } 460c6608df3SMatt Jacob isp = &pcs->pci_isp; 4617cc0979fSDavid Malone isp->isp_param = malloc(psize, M_DEVBUF, M_NOWAIT | M_ZERO); 462c6608df3SMatt Jacob if (isp->isp_param == NULL) { 463960f6939SMatt Jacob device_printf(dev, "cannot allocate parameter data\n"); 464960f6939SMatt Jacob goto bad; 465c6608df3SMatt Jacob } 466c6608df3SMatt Jacob isp->isp_mdvec = mdvp; 467c6608df3SMatt Jacob isp->isp_type = basetype; 468960f6939SMatt Jacob isp->isp_revision = pci_get_revid(dev); 469b9b599feSMatt Jacob isp->isp_role = role; 4706e5c5328SMatt Jacob isp->isp_dev = dev; 47165adb54cSMatt Jacob 47256aef503SMatt Jacob /* 47356aef503SMatt Jacob * Try and find firmware for this device. 47456aef503SMatt Jacob */ 47556aef503SMatt Jacob 47656aef503SMatt Jacob if (isp_get_firmware_p) { 47756aef503SMatt Jacob int device = (int) pci_get_device(dev); 47856aef503SMatt Jacob #ifdef ISP_TARGET_MODE 47956aef503SMatt Jacob (*isp_get_firmware_p)(0, 1, device, &mdvp->dv_ispfw); 48056aef503SMatt Jacob #else 48156aef503SMatt Jacob (*isp_get_firmware_p)(0, 0, device, &mdvp->dv_ispfw); 48256aef503SMatt Jacob #endif 48356aef503SMatt Jacob } 48456aef503SMatt Jacob 48556aef503SMatt Jacob /* 486d951bbcaSMatt Jacob * Make sure that SERR, PERR, WRITE INVALIDATE and BUSMASTER 487d951bbcaSMatt Jacob * are set. 488d951bbcaSMatt Jacob */ 489960f6939SMatt Jacob cmd |= PCIM_CMD_SEREN | PCIM_CMD_PERRESPEN | 490960f6939SMatt Jacob PCIM_CMD_BUSMASTEREN | PCIM_CMD_INVEN; 491960f6939SMatt Jacob pci_write_config(dev, PCIR_COMMAND, cmd, 1); 492ab6d0040SMatt Jacob 493d951bbcaSMatt Jacob /* 494222bb542SMatt Jacob * Make sure the Cache Line Size register is set sensibly. 495d951bbcaSMatt Jacob */ 496960f6939SMatt Jacob data = pci_read_config(dev, PCIR_CACHELNSZ, 1); 497ab6d0040SMatt Jacob if (data != linesz) { 498d951bbcaSMatt Jacob data = PCI_DFLT_LNSZ; 499d02373f1SMatt Jacob isp_prt(isp, ISP_LOGCONFIG, "set PCI line size to %d", data); 500960f6939SMatt Jacob pci_write_config(dev, PCIR_CACHELNSZ, data, 1); 501d951bbcaSMatt Jacob } 502ab6d0040SMatt Jacob 503d951bbcaSMatt Jacob /* 504d951bbcaSMatt Jacob * Make sure the Latency Timer is sane. 505d951bbcaSMatt Jacob */ 506960f6939SMatt Jacob data = pci_read_config(dev, PCIR_LATTIMER, 1); 507d951bbcaSMatt Jacob if (data < PCI_DFLT_LTNCY) { 508d951bbcaSMatt Jacob data = PCI_DFLT_LTNCY; 509d02373f1SMatt Jacob isp_prt(isp, ISP_LOGCONFIG, "set PCI latency to %d", data); 510960f6939SMatt Jacob pci_write_config(dev, PCIR_LATTIMER, data, 1); 511d951bbcaSMatt Jacob } 512ab6d0040SMatt Jacob 513ab6d0040SMatt Jacob /* 514ab6d0040SMatt Jacob * Make sure we've disabled the ROM. 515ab6d0040SMatt Jacob */ 516960f6939SMatt Jacob data = pci_read_config(dev, PCIR_ROMADDR, 4); 517ab6d0040SMatt Jacob data &= ~1; 518960f6939SMatt Jacob pci_write_config(dev, PCIR_ROMADDR, data, 4); 51905fbcbb0SMatt Jacob 520d951bbcaSMatt Jacob 521086646f7SJustin T. Gibbs if (bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT, 522222bb542SMatt Jacob BUS_SPACE_MAXADDR, NULL, NULL, lim + 1, 523222bb542SMatt Jacob 255, lim, 0, &pcs->parent_dmat) != 0) { 524f7dddf8aSMatt Jacob device_printf(dev, "could not create master dma tag\n"); 525960f6939SMatt Jacob free(isp->isp_param, M_DEVBUF); 526d720e6d5SJustin T. Gibbs free(pcs, M_DEVBUF); 527960f6939SMatt Jacob return (ENXIO); 52865adb54cSMatt Jacob } 52965adb54cSMatt Jacob 530960f6939SMatt Jacob iqd = 0; 531960f6939SMatt Jacob irq = bus_alloc_resource(dev, SYS_RES_IRQ, &iqd, 0, ~0, 532960f6939SMatt Jacob 1, RF_ACTIVE | RF_SHAREABLE); 533960f6939SMatt Jacob if (irq == NULL) { 534960f6939SMatt Jacob device_printf(dev, "could not allocate interrupt\n"); 535960f6939SMatt Jacob goto bad; 536960f6939SMatt Jacob } 537960f6939SMatt Jacob 5386e5c5328SMatt Jacob tval = 0; 5396e5c5328SMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 5406e5c5328SMatt Jacob "fwload_disable", &tval) == 0 && tval != 0) { 541222bb542SMatt Jacob isp->isp_confopts |= ISP_CFG_NORELOAD; 542222bb542SMatt Jacob } 5436e5c5328SMatt Jacob tval = 0; 5446e5c5328SMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 5456e5c5328SMatt Jacob "ignore_nvram", &tval) == 0 && tval != 0) { 546222bb542SMatt Jacob isp->isp_confopts |= ISP_CFG_NONVRAM; 547222bb542SMatt Jacob } 5486e5c5328SMatt Jacob tval = 0; 5496e5c5328SMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 5506e5c5328SMatt Jacob "fullduplex", &tval) == 0 && tval != 0) { 551222bb542SMatt Jacob isp->isp_confopts |= ISP_CFG_FULL_DUPLEX; 552222bb542SMatt Jacob } 553222bb542SMatt Jacob 5546e5c5328SMatt Jacob sptr = 0; 5556e5c5328SMatt Jacob if (resource_string_value(device_get_name(dev), device_get_unit(dev), 5566e5c5328SMatt Jacob "topology", &sptr) == 0 && sptr != 0) { 5576e5c5328SMatt Jacob if (strcmp(sptr, "lport") == 0) { 5586e5c5328SMatt Jacob isp->isp_confopts |= ISP_CFG_LPORT; 5596e5c5328SMatt Jacob } else if (strcmp(sptr, "nport") == 0) { 5606e5c5328SMatt Jacob isp->isp_confopts |= ISP_CFG_NPORT; 5616e5c5328SMatt Jacob } else if (strcmp(sptr, "lport-only") == 0) { 5626e5c5328SMatt Jacob isp->isp_confopts |= ISP_CFG_LPORT_ONLY; 5636e5c5328SMatt Jacob } else if (strcmp(sptr, "nport-only") == 0) { 5646e5c5328SMatt Jacob isp->isp_confopts |= ISP_CFG_NPORT_ONLY; 5659637d68cSMatt Jacob } 5666e5c5328SMatt Jacob } 5676e5c5328SMatt Jacob 5689637d68cSMatt Jacob /* 5696e5c5328SMatt Jacob * Because the resource_*_value functions can neither return 5706e5c5328SMatt Jacob * 64 bit integer values, nor can they be directly coerced 5716e5c5328SMatt Jacob * to interpret the right hand side of the assignment as 5726e5c5328SMatt Jacob * you want them to interpret it, we have to force WWN 5736e5c5328SMatt Jacob * hint replacement to specify WWN strings with a leading 5746e5c5328SMatt Jacob * 'w' (e..g w50000000aaaa0001). Sigh. 5759637d68cSMatt Jacob */ 5766e5c5328SMatt Jacob sptr = 0; 5776e5c5328SMatt Jacob tval = resource_string_value(device_get_name(dev), device_get_unit(dev), 5786e5c5328SMatt Jacob "portwwn", &sptr); 5796e5c5328SMatt Jacob if (tval == 0 && sptr != 0 && *sptr++ == 'w') { 5806e5c5328SMatt Jacob char *eptr = 0; 5816e5c5328SMatt Jacob isp->isp_osinfo.default_port_wwn = strtouq(sptr, &eptr, 16); 5826e5c5328SMatt Jacob if (eptr < sptr + 16 || isp->isp_osinfo.default_port_wwn == 0) { 5836e5c5328SMatt Jacob device_printf(dev, "mangled portwwn hint '%s'\n", sptr); 5846e5c5328SMatt Jacob isp->isp_osinfo.default_port_wwn = 0; 5859637d68cSMatt Jacob } else { 5869637d68cSMatt Jacob isp->isp_confopts |= ISP_CFG_OWNWWN; 587222bb542SMatt Jacob } 5886e5c5328SMatt Jacob } 5896e5c5328SMatt Jacob if (isp->isp_osinfo.default_port_wwn == 0) { 5906e5c5328SMatt Jacob isp->isp_osinfo.default_port_wwn = 0x400000007F000009ull; 5916e5c5328SMatt Jacob } 5926e5c5328SMatt Jacob 5936e5c5328SMatt Jacob sptr = 0; 5946e5c5328SMatt Jacob tval = resource_string_value(device_get_name(dev), device_get_unit(dev), 5956e5c5328SMatt Jacob "nodewwn", &sptr); 5966e5c5328SMatt Jacob if (tval == 0 && sptr != 0 && *sptr++ == 'w') { 5976e5c5328SMatt Jacob char *eptr = 0; 5986e5c5328SMatt Jacob isp->isp_osinfo.default_node_wwn = strtouq(sptr, &eptr, 16); 5996e5c5328SMatt Jacob if (eptr < sptr + 16 || isp->isp_osinfo.default_node_wwn == 0) { 6006e5c5328SMatt Jacob device_printf(dev, "mangled nodewwn hint '%s'\n", sptr); 6016e5c5328SMatt Jacob isp->isp_osinfo.default_node_wwn = 0; 6026e5c5328SMatt Jacob } else { 6036e5c5328SMatt Jacob isp->isp_confopts |= ISP_CFG_OWNWWN; 6046e5c5328SMatt Jacob } 6056e5c5328SMatt Jacob } 6066e5c5328SMatt Jacob if (isp->isp_osinfo.default_node_wwn == 0) { 6076e5c5328SMatt Jacob isp->isp_osinfo.default_node_wwn = 0x400000007F000009ull; 6086e5c5328SMatt Jacob } 6096e5c5328SMatt Jacob 610d02373f1SMatt Jacob isp_debug = 0; 6116e5c5328SMatt Jacob (void) resource_int_value(device_get_name(dev), device_get_unit(dev), 6126e5c5328SMatt Jacob "debug", &isp_debug); 613f09b1922SMatt Jacob 614f09b1922SMatt Jacob #ifdef ISP_SMPLOCK 615f09b1922SMatt Jacob /* Make sure the lock is set up. */ 616f09b1922SMatt Jacob mtx_init(&isp->isp_osinfo.lock, "isp", MTX_DEF); 617f09b1922SMatt Jacob locksetup++; 618f09b1922SMatt Jacob 619ed34d0adSMark Murray if (bus_setup_intr(dev, irq, INTR_TYPE_CAM | INTR_MPSAFE | INTR_ENTROPY, 620f09b1922SMatt Jacob isp_pci_intr, isp, &pcs->ih)) { 621960f6939SMatt Jacob device_printf(dev, "could not setup interrupt\n"); 622960f6939SMatt Jacob goto bad; 623960f6939SMatt Jacob } 624f09b1922SMatt Jacob #else 625ed34d0adSMark Murray if (bus_setup_intr(dev, irq, INTR_TYPE_CAM | INTR_ENTROPY, 626f09b1922SMatt Jacob isp_pci_intr, isp, &pcs->ih)) { 627f09b1922SMatt Jacob device_printf(dev, "could not setup interrupt\n"); 628f09b1922SMatt Jacob goto bad; 629f09b1922SMatt Jacob } 630f09b1922SMatt Jacob #endif 631960f6939SMatt Jacob 63205fbcbb0SMatt Jacob /* 633d02373f1SMatt Jacob * Set up logging levels. 634d02373f1SMatt Jacob */ 635d02373f1SMatt Jacob if (isp_debug) { 636d02373f1SMatt Jacob isp->isp_dblev = isp_debug; 637d02373f1SMatt Jacob } else { 638d02373f1SMatt Jacob isp->isp_dblev = ISP_LOGWARN|ISP_LOGERR; 639d02373f1SMatt Jacob } 640d02373f1SMatt Jacob if (bootverbose) 641f7dddf8aSMatt Jacob isp->isp_dblev |= ISP_LOGCONFIG|ISP_LOGINFO; 642d02373f1SMatt Jacob 643d02373f1SMatt Jacob /* 64405fbcbb0SMatt Jacob * Make sure we're in reset state. 64505fbcbb0SMatt Jacob */ 6463395b056SMatt Jacob ISP_LOCK(isp); 64765adb54cSMatt Jacob isp_reset(isp); 64865adb54cSMatt Jacob if (isp->isp_state != ISP_RESETSTATE) { 6493395b056SMatt Jacob ISP_UNLOCK(isp); 650960f6939SMatt Jacob goto bad; 65165adb54cSMatt Jacob } 65265adb54cSMatt Jacob isp_init(isp); 653b9b599feSMatt Jacob if (isp->isp_role != ISP_ROLE_NONE && isp->isp_state != ISP_INITSTATE) { 65465adb54cSMatt Jacob isp_uninit(isp); 6553395b056SMatt Jacob ISP_UNLOCK(isp); 656960f6939SMatt Jacob goto bad; 657d59bd469SMatt Jacob } 65865adb54cSMatt Jacob isp_attach(isp); 659b9b599feSMatt Jacob if (isp->isp_role != ISP_ROLE_NONE && isp->isp_state != ISP_RUNSTATE) { 66065adb54cSMatt Jacob isp_uninit(isp); 6613395b056SMatt Jacob ISP_UNLOCK(isp); 662960f6939SMatt Jacob goto bad; 663960f6939SMatt Jacob } 66456aef503SMatt Jacob /* 66556aef503SMatt Jacob * XXXX: Here is where we might unload the f/w module 66656aef503SMatt Jacob * XXXX: (or decrease the reference count to it). 66756aef503SMatt Jacob */ 6683395b056SMatt Jacob ISP_UNLOCK(isp); 669960f6939SMatt Jacob return (0); 670960f6939SMatt Jacob 671960f6939SMatt Jacob bad: 672960f6939SMatt Jacob 673960f6939SMatt Jacob if (pcs && pcs->ih) { 674960f6939SMatt Jacob (void) bus_teardown_intr(dev, irq, pcs->ih); 675960f6939SMatt Jacob } 676960f6939SMatt Jacob 6773395b056SMatt Jacob #ifdef ISP_SMPLOCK 6783395b056SMatt Jacob if (locksetup && isp) { 6793395b056SMatt Jacob mtx_destroy(&isp->isp_osinfo.lock); 6803395b056SMatt Jacob } 6813395b056SMatt Jacob #endif 6823395b056SMatt Jacob 683960f6939SMatt Jacob if (irq) { 684960f6939SMatt Jacob (void) bus_release_resource(dev, SYS_RES_IRQ, iqd, irq); 685960f6939SMatt Jacob } 6863395b056SMatt Jacob 6873395b056SMatt Jacob 688960f6939SMatt Jacob if (regs) { 689960f6939SMatt Jacob (void) bus_release_resource(dev, rtp, rgd, regs); 690960f6939SMatt Jacob } 6913395b056SMatt Jacob 692960f6939SMatt Jacob if (pcs) { 693960f6939SMatt Jacob if (pcs->pci_isp.isp_param) 694960f6939SMatt Jacob free(pcs->pci_isp.isp_param, M_DEVBUF); 69565adb54cSMatt Jacob free(pcs, M_DEVBUF); 69665adb54cSMatt Jacob } 6973395b056SMatt Jacob 69856aef503SMatt Jacob /* 69956aef503SMatt Jacob * XXXX: Here is where we might unload the f/w module 70056aef503SMatt Jacob * XXXX: (or decrease the reference count to it). 70156aef503SMatt Jacob */ 702960f6939SMatt Jacob return (ENXIO); 70365adb54cSMatt Jacob } 70465adb54cSMatt Jacob 705f09b1922SMatt Jacob static void 706f09b1922SMatt Jacob isp_pci_intr(void *arg) 707f09b1922SMatt Jacob { 708f09b1922SMatt Jacob struct ispsoftc *isp = arg; 709f09b1922SMatt Jacob ISP_LOCK(isp); 710f09b1922SMatt Jacob (void) isp_intr(isp); 711f09b1922SMatt Jacob ISP_UNLOCK(isp); 712f09b1922SMatt Jacob } 713f09b1922SMatt Jacob 71465adb54cSMatt Jacob static u_int16_t 715d59bd469SMatt Jacob isp_pci_rd_reg(isp, regoff) 716d59bd469SMatt Jacob struct ispsoftc *isp; 717d59bd469SMatt Jacob int regoff; 71865adb54cSMatt Jacob { 71965adb54cSMatt Jacob u_int16_t rv; 72065adb54cSMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 721d59bd469SMatt Jacob int offset, oldconf = 0; 72265adb54cSMatt Jacob 723d59bd469SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 72465adb54cSMatt Jacob /* 72565adb54cSMatt Jacob * We will assume that someone has paused the RISC processor. 72665adb54cSMatt Jacob */ 727d59bd469SMatt Jacob oldconf = isp_pci_rd_reg(isp, BIU_CONF1); 728d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oldconf | BIU_PCI_CONF1_SXP); 72965adb54cSMatt Jacob } 730d59bd469SMatt Jacob offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT]; 731d59bd469SMatt Jacob offset += (regoff & 0xff); 73265adb54cSMatt Jacob rv = bus_space_read_2(pcs->pci_st, pcs->pci_sh, offset); 733d59bd469SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 734d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oldconf); 73565adb54cSMatt Jacob } 73665adb54cSMatt Jacob return (rv); 73765adb54cSMatt Jacob } 73865adb54cSMatt Jacob 73965adb54cSMatt Jacob static void 740d59bd469SMatt Jacob isp_pci_wr_reg(isp, regoff, val) 741d59bd469SMatt Jacob struct ispsoftc *isp; 742d59bd469SMatt Jacob int regoff; 743d59bd469SMatt Jacob u_int16_t val; 74465adb54cSMatt Jacob { 74565adb54cSMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 746d59bd469SMatt Jacob int offset, oldconf = 0; 747d59bd469SMatt Jacob 748d59bd469SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 74965adb54cSMatt Jacob /* 75065adb54cSMatt Jacob * We will assume that someone has paused the RISC processor. 75165adb54cSMatt Jacob */ 752d59bd469SMatt Jacob oldconf = isp_pci_rd_reg(isp, BIU_CONF1); 753d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oldconf | BIU_PCI_CONF1_SXP); 75465adb54cSMatt Jacob } 755d59bd469SMatt Jacob offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT]; 756d59bd469SMatt Jacob offset += (regoff & 0xff); 75765adb54cSMatt Jacob bus_space_write_2(pcs->pci_st, pcs->pci_sh, offset, val); 758d59bd469SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 759d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oldconf); 76065adb54cSMatt Jacob } 76165adb54cSMatt Jacob } 76265adb54cSMatt Jacob 763d59bd469SMatt Jacob static u_int16_t 764d59bd469SMatt Jacob isp_pci_rd_reg_1080(isp, regoff) 765d59bd469SMatt Jacob struct ispsoftc *isp; 766d59bd469SMatt Jacob int regoff; 767d59bd469SMatt Jacob { 76822e1dc85SMatt Jacob u_int16_t rv, oc = 0; 769d59bd469SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 77022e1dc85SMatt Jacob int offset; 771d59bd469SMatt Jacob 77222e1dc85SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK || 77322e1dc85SMatt Jacob (regoff & _BLK_REG_MASK) == (SXP_BLOCK|SXP_BANK1_SELECT)) { 77422e1dc85SMatt Jacob u_int16_t tc; 775d59bd469SMatt Jacob /* 776d59bd469SMatt Jacob * We will assume that someone has paused the RISC processor. 777d59bd469SMatt Jacob */ 778d59bd469SMatt Jacob oc = isp_pci_rd_reg(isp, BIU_CONF1); 77922e1dc85SMatt Jacob tc = oc & ~BIU_PCI1080_CONF1_DMA; 78022e1dc85SMatt Jacob if (regoff & SXP_BANK1_SELECT) 78122e1dc85SMatt Jacob tc |= BIU_PCI1080_CONF1_SXP1; 78222e1dc85SMatt Jacob else 78322e1dc85SMatt Jacob tc |= BIU_PCI1080_CONF1_SXP0; 78422e1dc85SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, tc); 785d59bd469SMatt Jacob } else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) { 786d59bd469SMatt Jacob oc = isp_pci_rd_reg(isp, BIU_CONF1); 787d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oc | BIU_PCI1080_CONF1_DMA); 788d59bd469SMatt Jacob } 789d59bd469SMatt Jacob offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT]; 790d59bd469SMatt Jacob offset += (regoff & 0xff); 791d59bd469SMatt Jacob rv = bus_space_read_2(pcs->pci_st, pcs->pci_sh, offset); 79222e1dc85SMatt Jacob if (oc) { 793d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oc); 794d59bd469SMatt Jacob } 795d59bd469SMatt Jacob return (rv); 796d59bd469SMatt Jacob } 797d59bd469SMatt Jacob 798d59bd469SMatt Jacob static void 799d59bd469SMatt Jacob isp_pci_wr_reg_1080(isp, regoff, val) 800d59bd469SMatt Jacob struct ispsoftc *isp; 801d59bd469SMatt Jacob int regoff; 802d59bd469SMatt Jacob u_int16_t val; 803d59bd469SMatt Jacob { 804d59bd469SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 805d59bd469SMatt Jacob int offset, oc = 0; 806d59bd469SMatt Jacob 80722e1dc85SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK || 80822e1dc85SMatt Jacob (regoff & _BLK_REG_MASK) == (SXP_BLOCK|SXP_BANK1_SELECT)) { 80922e1dc85SMatt Jacob u_int16_t tc; 810d59bd469SMatt Jacob /* 811d59bd469SMatt Jacob * We will assume that someone has paused the RISC processor. 812d59bd469SMatt Jacob */ 813d59bd469SMatt Jacob oc = isp_pci_rd_reg(isp, BIU_CONF1); 81422e1dc85SMatt Jacob tc = oc & ~BIU_PCI1080_CONF1_DMA; 81522e1dc85SMatt Jacob if (regoff & SXP_BANK1_SELECT) 81622e1dc85SMatt Jacob tc |= BIU_PCI1080_CONF1_SXP1; 81722e1dc85SMatt Jacob else 81822e1dc85SMatt Jacob tc |= BIU_PCI1080_CONF1_SXP0; 81922e1dc85SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, tc); 820d59bd469SMatt Jacob } else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) { 821d59bd469SMatt Jacob oc = isp_pci_rd_reg(isp, BIU_CONF1); 822d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oc | BIU_PCI1080_CONF1_DMA); 823d59bd469SMatt Jacob } 824d59bd469SMatt Jacob offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT]; 825d59bd469SMatt Jacob offset += (regoff & 0xff); 826d59bd469SMatt Jacob bus_space_write_2(pcs->pci_st, pcs->pci_sh, offset, val); 82722e1dc85SMatt Jacob if (oc) { 828d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oc); 829d59bd469SMatt Jacob } 830d59bd469SMatt Jacob } 831d59bd469SMatt Jacob 832d720e6d5SJustin T. Gibbs static void isp_map_rquest __P((void *, bus_dma_segment_t *, int, int)); 833d720e6d5SJustin T. Gibbs static void isp_map_result __P((void *, bus_dma_segment_t *, int, int)); 834d720e6d5SJustin T. Gibbs static void isp_map_fcscrt __P((void *, bus_dma_segment_t *, int, int)); 835d720e6d5SJustin T. Gibbs 836222bb542SMatt Jacob struct imush { 837222bb542SMatt Jacob struct ispsoftc *isp; 838222bb542SMatt Jacob int error; 839222bb542SMatt Jacob }; 840222bb542SMatt Jacob 841d720e6d5SJustin T. Gibbs static void 84217e318c6SMatt Jacob isp_map_rquest(void *arg, bus_dma_segment_t *segs, int nseg, int error) 843d720e6d5SJustin T. Gibbs { 844222bb542SMatt Jacob struct imush *imushp = (struct imush *) arg; 845222bb542SMatt Jacob if (error) { 846222bb542SMatt Jacob imushp->error = error; 847222bb542SMatt Jacob } else { 848222bb542SMatt Jacob imushp->isp->isp_rquest_dma = segs->ds_addr; 849222bb542SMatt Jacob } 850d720e6d5SJustin T. Gibbs } 851d720e6d5SJustin T. Gibbs 852d720e6d5SJustin T. Gibbs static void 85317e318c6SMatt Jacob isp_map_result(void *arg, bus_dma_segment_t *segs, int nseg, int error) 854d720e6d5SJustin T. Gibbs { 855222bb542SMatt Jacob struct imush *imushp = (struct imush *) arg; 856222bb542SMatt Jacob if (error) { 857222bb542SMatt Jacob imushp->error = error; 858222bb542SMatt Jacob } else { 859222bb542SMatt Jacob imushp->isp->isp_result_dma = segs->ds_addr; 860222bb542SMatt Jacob } 861d720e6d5SJustin T. Gibbs } 862d720e6d5SJustin T. Gibbs 863d720e6d5SJustin T. Gibbs static void 86417e318c6SMatt Jacob isp_map_fcscrt(void *arg, bus_dma_segment_t *segs, int nseg, int error) 865d720e6d5SJustin T. Gibbs { 866222bb542SMatt Jacob struct imush *imushp = (struct imush *) arg; 867222bb542SMatt Jacob if (error) { 868222bb542SMatt Jacob imushp->error = error; 869222bb542SMatt Jacob } else { 870222bb542SMatt Jacob fcparam *fcp = imushp->isp->isp_param; 871d720e6d5SJustin T. Gibbs fcp->isp_scdma = segs->ds_addr; 872d720e6d5SJustin T. Gibbs } 873222bb542SMatt Jacob } 874d720e6d5SJustin T. Gibbs 875d720e6d5SJustin T. Gibbs static int 87617e318c6SMatt Jacob isp_pci_mbxdma(struct ispsoftc *isp) 877d720e6d5SJustin T. Gibbs { 878d720e6d5SJustin T. Gibbs struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp; 879d720e6d5SJustin T. Gibbs caddr_t base; 880d720e6d5SJustin T. Gibbs u_int32_t len; 881d720e6d5SJustin T. Gibbs int i, error; 882222bb542SMatt Jacob bus_size_t lim; 883222bb542SMatt Jacob struct imush im; 884222bb542SMatt Jacob 885222bb542SMatt Jacob 886a95ae193SMatt Jacob /* 887a95ae193SMatt Jacob * Already been here? If so, leave... 888a95ae193SMatt Jacob */ 889a95ae193SMatt Jacob if (isp->isp_rquest) { 890a95ae193SMatt Jacob return (0); 891a95ae193SMatt Jacob } 892a95ae193SMatt Jacob 893d02373f1SMatt Jacob len = sizeof (XS_T **) * isp->isp_maxcmds; 8947cc0979fSDavid Malone isp->isp_xflist = (XS_T **) malloc(len, M_DEVBUF, M_WAITOK | M_ZERO); 895a95ae193SMatt Jacob if (isp->isp_xflist == NULL) { 896d02373f1SMatt Jacob isp_prt(isp, ISP_LOGERR, "cannot alloc xflist array"); 897a95ae193SMatt Jacob return (1); 898a95ae193SMatt Jacob } 899a95ae193SMatt Jacob len = sizeof (bus_dmamap_t) * isp->isp_maxcmds; 900a95ae193SMatt Jacob pci->dmaps = (bus_dmamap_t *) malloc(len, M_DEVBUF, M_WAITOK); 901a95ae193SMatt Jacob if (pci->dmaps == NULL) { 902d02373f1SMatt Jacob isp_prt(isp, ISP_LOGERR, "can't alloc dma maps"); 903a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 904a95ae193SMatt Jacob return (1); 905a95ae193SMatt Jacob } 906a95ae193SMatt Jacob 90722e1dc85SMatt Jacob if (IS_FC(isp) || IS_ULTRA2(isp)) 908222bb542SMatt Jacob lim = BUS_SPACE_MAXADDR + 1; 909222bb542SMatt Jacob else 910222bb542SMatt Jacob lim = BUS_SPACE_MAXADDR_24BIT + 1; 911d720e6d5SJustin T. Gibbs 912d720e6d5SJustin T. Gibbs /* 913d720e6d5SJustin T. Gibbs * Allocate and map the request, result queues, plus FC scratch area. 914d720e6d5SJustin T. Gibbs */ 915d02373f1SMatt Jacob len = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)); 916d02373f1SMatt Jacob len += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)); 917222bb542SMatt Jacob if (IS_FC(isp)) { 918d720e6d5SJustin T. Gibbs len += ISP2100_SCRLEN; 919d720e6d5SJustin T. Gibbs } 920222bb542SMatt Jacob if (bus_dma_tag_create(pci->parent_dmat, PAGE_SIZE, lim, 921222bb542SMatt Jacob BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, len, 1, 922222bb542SMatt Jacob BUS_SPACE_MAXSIZE_32BIT, 0, &pci->cntrol_dmat) != 0) { 923f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 924f7dddf8aSMatt Jacob "cannot create a dma tag for control spaces"); 925a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 926a95ae193SMatt Jacob free(pci->dmaps, M_DEVBUF); 927d720e6d5SJustin T. Gibbs return (1); 928d720e6d5SJustin T. Gibbs } 929d720e6d5SJustin T. Gibbs if (bus_dmamem_alloc(pci->cntrol_dmat, (void **)&base, 930d720e6d5SJustin T. Gibbs BUS_DMA_NOWAIT, &pci->cntrol_dmap) != 0) { 931f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 9323486bfe0SMatt Jacob "cannot allocate %d bytes of CCB memory", len); 933a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 934a95ae193SMatt Jacob free(pci->dmaps, M_DEVBUF); 935d720e6d5SJustin T. Gibbs return (1); 936d720e6d5SJustin T. Gibbs } 937d720e6d5SJustin T. Gibbs 938d720e6d5SJustin T. Gibbs isp->isp_rquest = base; 939222bb542SMatt Jacob im.isp = isp; 940222bb542SMatt Jacob im.error = 0; 941d720e6d5SJustin T. Gibbs bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap, isp->isp_rquest, 942d02373f1SMatt Jacob ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)), isp_map_rquest, &im, 0); 943222bb542SMatt Jacob if (im.error) { 944f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 945f7dddf8aSMatt Jacob "error %d loading dma map for DMA request queue", im.error); 946a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 947a95ae193SMatt Jacob free(pci->dmaps, M_DEVBUF); 948a95ae193SMatt Jacob isp->isp_rquest = NULL; 949222bb542SMatt Jacob return (1); 950222bb542SMatt Jacob } 951d02373f1SMatt Jacob isp->isp_result = base + ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)); 952222bb542SMatt Jacob im.error = 0; 953d720e6d5SJustin T. Gibbs bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap, isp->isp_result, 954d02373f1SMatt Jacob ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)), isp_map_result, &im, 0); 955222bb542SMatt Jacob if (im.error) { 956f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 957f7dddf8aSMatt Jacob "error %d loading dma map for DMA result queue", im.error); 958a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 959a95ae193SMatt Jacob free(pci->dmaps, M_DEVBUF); 960a95ae193SMatt Jacob isp->isp_rquest = NULL; 961222bb542SMatt Jacob return (1); 962222bb542SMatt Jacob } 963d720e6d5SJustin T. Gibbs 964a95ae193SMatt Jacob for (i = 0; i < isp->isp_maxcmds; i++) { 965d720e6d5SJustin T. Gibbs error = bus_dmamap_create(pci->parent_dmat, 0, &pci->dmaps[i]); 966d720e6d5SJustin T. Gibbs if (error) { 967f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 968f7dddf8aSMatt Jacob "error %d creating per-cmd DMA maps", error); 969a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 970a95ae193SMatt Jacob free(pci->dmaps, M_DEVBUF); 971a95ae193SMatt Jacob isp->isp_rquest = NULL; 972d720e6d5SJustin T. Gibbs return (1); 973d720e6d5SJustin T. Gibbs } 974d720e6d5SJustin T. Gibbs } 975a95ae193SMatt Jacob 976222bb542SMatt Jacob if (IS_FC(isp)) { 97792c49d78SMatt Jacob fcparam *fcp = (fcparam *) isp->isp_param; 97892c49d78SMatt Jacob fcp->isp_scratch = base + 979d02373f1SMatt Jacob ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)) + 980d02373f1SMatt Jacob ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)); 981222bb542SMatt Jacob im.error = 0; 98292c49d78SMatt Jacob bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap, 983222bb542SMatt Jacob fcp->isp_scratch, ISP2100_SCRLEN, isp_map_fcscrt, &im, 0); 984222bb542SMatt Jacob if (im.error) { 985f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 986f7dddf8aSMatt Jacob "error %d loading FC scratch area", im.error); 987a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 988a95ae193SMatt Jacob free(pci->dmaps, M_DEVBUF); 989a95ae193SMatt Jacob isp->isp_rquest = NULL; 990222bb542SMatt Jacob return (1); 991222bb542SMatt Jacob } 99292c49d78SMatt Jacob } 993d720e6d5SJustin T. Gibbs return (0); 994d720e6d5SJustin T. Gibbs } 995d720e6d5SJustin T. Gibbs 996d720e6d5SJustin T. Gibbs typedef struct { 997d720e6d5SJustin T. Gibbs struct ispsoftc *isp; 9989e11e5beSMatt Jacob void *cmd_token; 9999e11e5beSMatt Jacob void *rq; 10009637d68cSMatt Jacob u_int16_t *iptrp; 10019637d68cSMatt Jacob u_int16_t optr; 1002d720e6d5SJustin T. Gibbs u_int error; 1003d720e6d5SJustin T. Gibbs } mush_t; 1004d720e6d5SJustin T. Gibbs 10054873663cSMatt Jacob #define MUSHERR_NOQENTRIES -2 10064873663cSMatt Jacob 10079e11e5beSMatt Jacob #ifdef ISP_TARGET_MODE 10089e11e5beSMatt Jacob /* 10099e11e5beSMatt Jacob * We need to handle DMA for target mode differently from initiator mode. 10109e11e5beSMatt Jacob * 10119e11e5beSMatt Jacob * DMA mapping and construction and submission of CTIO Request Entries 10129e11e5beSMatt Jacob * and rendevous for completion are very tightly coupled because we start 10139e11e5beSMatt Jacob * out by knowing (per platform) how much data we have to move, but we 10149e11e5beSMatt Jacob * don't know, up front, how many DMA mapping segments will have to be used 10159e11e5beSMatt Jacob * cover that data, so we don't know how many CTIO Request Entries we 10169e11e5beSMatt Jacob * will end up using. Further, for performance reasons we may want to 10179e11e5beSMatt Jacob * (on the last CTIO for Fibre Channel), send status too (if all went well). 10189e11e5beSMatt Jacob * 10199e11e5beSMatt Jacob * The standard vector still goes through isp_pci_dmasetup, but the callback 10209e11e5beSMatt Jacob * for the DMA mapping routines comes here instead with the whole transfer 10219e11e5beSMatt Jacob * mapped and a pointer to a partially filled in already allocated request 10229e11e5beSMatt Jacob * queue entry. We finish the job. 10239e11e5beSMatt Jacob */ 102405fbcbb0SMatt Jacob static void tdma_mk __P((void *, bus_dma_segment_t *, int, int)); 102505fbcbb0SMatt Jacob static void tdma_mkfc __P((void *, bus_dma_segment_t *, int, int)); 10269e11e5beSMatt Jacob 1027d720e6d5SJustin T. Gibbs static void 102805fbcbb0SMatt Jacob tdma_mk(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 1029d720e6d5SJustin T. Gibbs { 1030d720e6d5SJustin T. Gibbs mush_t *mp; 10319e11e5beSMatt Jacob struct ccb_scsiio *csio; 1032d720e6d5SJustin T. Gibbs struct isp_pcisoftc *pci; 1033d720e6d5SJustin T. Gibbs bus_dmamap_t *dp; 103405fbcbb0SMatt Jacob u_int8_t scsi_status; 10359e11e5beSMatt Jacob ct_entry_t *cto; 10365f5aafe1SMatt Jacob u_int16_t handle; 10375f5aafe1SMatt Jacob u_int32_t totxfr, sflags; 103805fbcbb0SMatt Jacob int nctios, send_status; 103905fbcbb0SMatt Jacob int32_t resid; 1040d720e6d5SJustin T. Gibbs 1041d720e6d5SJustin T. Gibbs mp = (mush_t *) arg; 1042d720e6d5SJustin T. Gibbs if (error) { 1043d720e6d5SJustin T. Gibbs mp->error = error; 1044d720e6d5SJustin T. Gibbs return; 1045d720e6d5SJustin T. Gibbs } 10469e11e5beSMatt Jacob csio = mp->cmd_token; 10479e11e5beSMatt Jacob cto = mp->rq; 10489e11e5beSMatt Jacob 104965b024e1SMatt Jacob cto->ct_xfrlen = 0; 105065b024e1SMatt Jacob cto->ct_seg_count = 0; 105165b024e1SMatt Jacob cto->ct_header.rqs_entry_count = 1; 105205fbcbb0SMatt Jacob MEMZERO(cto->ct_dataseg, sizeof(cto->ct_dataseg)); 105305fbcbb0SMatt Jacob 105405fbcbb0SMatt Jacob if (nseg == 0) { 105505fbcbb0SMatt Jacob cto->ct_header.rqs_seqno = 1; 105605fbcbb0SMatt Jacob ISP_TDQE(mp->isp, "tdma_mk[no data]", *mp->iptrp, cto); 1057d02373f1SMatt Jacob isp_prt(mp->isp, ISP_LOGTDEBUG1, 10585f5aafe1SMatt Jacob "CTIO[%x] lun%d->iid%d flgs 0x%x sts 0x%x ssts 0x%x res %d", 10595f5aafe1SMatt Jacob cto->ct_fwhandle, csio->ccb_h.target_lun, cto->ct_iid, 10605f5aafe1SMatt Jacob cto->ct_flags, cto->ct_status, cto->ct_scsi_status, 10615f5aafe1SMatt Jacob cto->ct_resid); 106205fbcbb0SMatt Jacob ISP_SWIZ_CTIO(mp->isp, cto, cto); 106365b024e1SMatt Jacob return; 106465b024e1SMatt Jacob } 106565b024e1SMatt Jacob 106665b024e1SMatt Jacob nctios = nseg / ISP_RQDSEG; 106765b024e1SMatt Jacob if (nseg % ISP_RQDSEG) { 106865b024e1SMatt Jacob nctios++; 106965b024e1SMatt Jacob } 107065b024e1SMatt Jacob 107105fbcbb0SMatt Jacob /* 10725f5aafe1SMatt Jacob * Save syshandle, and potentially any SCSI status, which we'll 10735f5aafe1SMatt Jacob * reinsert on the last CTIO we're going to send. 107405fbcbb0SMatt Jacob */ 10755f5aafe1SMatt Jacob handle = cto->ct_syshandle; 10765f5aafe1SMatt Jacob cto->ct_syshandle = 0; 107705fbcbb0SMatt Jacob cto->ct_header.rqs_seqno = 0; 107805fbcbb0SMatt Jacob send_status = (cto->ct_flags & CT_SENDSTATUS) != 0; 107905fbcbb0SMatt Jacob 108005fbcbb0SMatt Jacob if (send_status) { 108105fbcbb0SMatt Jacob sflags = cto->ct_flags & (CT_SENDSTATUS | CT_CCINCR); 108205fbcbb0SMatt Jacob cto->ct_flags &= ~(CT_SENDSTATUS | CT_CCINCR); 108305fbcbb0SMatt Jacob /* 108405fbcbb0SMatt Jacob * Preserve residual. 108505fbcbb0SMatt Jacob */ 108605fbcbb0SMatt Jacob resid = cto->ct_resid; 108705fbcbb0SMatt Jacob 108805fbcbb0SMatt Jacob /* 108905fbcbb0SMatt Jacob * Save actual SCSI status. 109005fbcbb0SMatt Jacob */ 109105fbcbb0SMatt Jacob scsi_status = cto->ct_scsi_status; 109205fbcbb0SMatt Jacob 109305fbcbb0SMatt Jacob /* 109405fbcbb0SMatt Jacob * We can't do a status at the same time as a data CTIO, so 109505fbcbb0SMatt Jacob * we need to synthesize an extra CTIO at this level. 109605fbcbb0SMatt Jacob */ 109705fbcbb0SMatt Jacob nctios++; 109805fbcbb0SMatt Jacob } else { 109905fbcbb0SMatt Jacob sflags = scsi_status = resid = 0; 110005fbcbb0SMatt Jacob } 110105fbcbb0SMatt Jacob 110205fbcbb0SMatt Jacob totxfr = cto->ct_resid = 0; 110305fbcbb0SMatt Jacob cto->ct_scsi_status = 0; 110405fbcbb0SMatt Jacob 11059e11e5beSMatt Jacob pci = (struct isp_pcisoftc *)mp->isp; 1106469b6b9eSMatt Jacob dp = &pci->dmaps[isp_handle_index(handle)]; 11079e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 1108d720e6d5SJustin T. Gibbs bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREREAD); 1109d720e6d5SJustin T. Gibbs } else { 1110d720e6d5SJustin T. Gibbs bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREWRITE); 1111d720e6d5SJustin T. Gibbs } 1112d720e6d5SJustin T. Gibbs 11139e11e5beSMatt Jacob 11149e11e5beSMatt Jacob while (nctios--) { 111505fbcbb0SMatt Jacob int seglim; 11169e11e5beSMatt Jacob 11179e11e5beSMatt Jacob seglim = nseg; 111805fbcbb0SMatt Jacob if (seglim) { 111905fbcbb0SMatt Jacob int seg; 112005fbcbb0SMatt Jacob 11219e11e5beSMatt Jacob if (seglim > ISP_RQDSEG) 11229e11e5beSMatt Jacob seglim = ISP_RQDSEG; 11239e11e5beSMatt Jacob 112405fbcbb0SMatt Jacob for (seg = 0; seg < seglim; seg++, nseg--) { 112505fbcbb0SMatt Jacob /* 112605fbcbb0SMatt Jacob * Unlike normal initiator commands, we don't 112705fbcbb0SMatt Jacob * do any swizzling here. 112805fbcbb0SMatt Jacob */ 11299e11e5beSMatt Jacob cto->ct_dataseg[seg].ds_count = dm_segs->ds_len; 113005fbcbb0SMatt Jacob cto->ct_dataseg[seg].ds_base = dm_segs->ds_addr; 11319e11e5beSMatt Jacob cto->ct_xfrlen += dm_segs->ds_len; 113205fbcbb0SMatt Jacob totxfr += dm_segs->ds_len; 11339e11e5beSMatt Jacob dm_segs++; 11349e11e5beSMatt Jacob } 11359e11e5beSMatt Jacob cto->ct_seg_count = seg; 11369e11e5beSMatt Jacob } else { 113705fbcbb0SMatt Jacob /* 113805fbcbb0SMatt Jacob * This case should only happen when we're sending an 113905fbcbb0SMatt Jacob * extra CTIO with final status. 114005fbcbb0SMatt Jacob */ 114105fbcbb0SMatt Jacob if (send_status == 0) { 1142f7dddf8aSMatt Jacob isp_prt(mp->isp, ISP_LOGWARN, 1143f7dddf8aSMatt Jacob "tdma_mk ran out of segments"); 114405fbcbb0SMatt Jacob mp->error = EINVAL; 114505fbcbb0SMatt Jacob return; 11469e11e5beSMatt Jacob } 114705fbcbb0SMatt Jacob } 114805fbcbb0SMatt Jacob 114905fbcbb0SMatt Jacob /* 115005fbcbb0SMatt Jacob * At this point, the fields ct_lun, ct_iid, ct_tagval, 115105fbcbb0SMatt Jacob * ct_tagtype, and ct_timeout have been carried over 115205fbcbb0SMatt Jacob * unchanged from what our caller had set. 115305fbcbb0SMatt Jacob * 115405fbcbb0SMatt Jacob * The dataseg fields and the seg_count fields we just got 115505fbcbb0SMatt Jacob * through setting. The data direction we've preserved all 115605fbcbb0SMatt Jacob * along and only clear it if we're now sending status. 115705fbcbb0SMatt Jacob */ 11589e11e5beSMatt Jacob 11599e11e5beSMatt Jacob if (nctios == 0) { 11609e11e5beSMatt Jacob /* 116105fbcbb0SMatt Jacob * We're the last in a sequence of CTIOs, so mark 116205fbcbb0SMatt Jacob * this CTIO and save the handle to the CCB such that 116305fbcbb0SMatt Jacob * when this CTIO completes we can free dma resources 116405fbcbb0SMatt Jacob * and do whatever else we need to do to finish the 116505fbcbb0SMatt Jacob * rest of the command. 11669e11e5beSMatt Jacob */ 11675f5aafe1SMatt Jacob cto->ct_syshandle = handle; 116805fbcbb0SMatt Jacob cto->ct_header.rqs_seqno = 1; 116905fbcbb0SMatt Jacob 117005fbcbb0SMatt Jacob if (send_status) { 11719e11e5beSMatt Jacob cto->ct_scsi_status = scsi_status; 117205fbcbb0SMatt Jacob cto->ct_flags |= sflags | CT_NO_DATA;; 117305fbcbb0SMatt Jacob cto->ct_resid = resid; 117442426921SMatt Jacob } 1175d02373f1SMatt Jacob if (send_status) { 1176d02373f1SMatt Jacob isp_prt(mp->isp, ISP_LOGTDEBUG1, 11775f5aafe1SMatt Jacob "CTIO[%x] lun%d for ID %d ct_flags 0x%x " 11785f5aafe1SMatt Jacob "scsi status %x resid %d", 11795f5aafe1SMatt Jacob cto->ct_fwhandle, csio->ccb_h.target_lun, 118005fbcbb0SMatt Jacob cto->ct_iid, cto->ct_flags, 118105fbcbb0SMatt Jacob cto->ct_scsi_status, cto->ct_resid); 1182d02373f1SMatt Jacob } else { 1183d02373f1SMatt Jacob isp_prt(mp->isp, ISP_LOGTDEBUG1, 11845f5aafe1SMatt Jacob "CTIO[%x] lun%d for ID%d ct_flags 0x%x", 11855f5aafe1SMatt Jacob cto->ct_fwhandle, csio->ccb_h.target_lun, 118605fbcbb0SMatt Jacob cto->ct_iid, cto->ct_flags); 118705fbcbb0SMatt Jacob } 118805fbcbb0SMatt Jacob ISP_TDQE(mp->isp, "last tdma_mk", *mp->iptrp, cto); 118905fbcbb0SMatt Jacob ISP_SWIZ_CTIO(mp->isp, cto, cto); 11909e11e5beSMatt Jacob } else { 11919e11e5beSMatt Jacob ct_entry_t *octo = cto; 119205fbcbb0SMatt Jacob 119305fbcbb0SMatt Jacob /* 11945f5aafe1SMatt Jacob * Make sure syshandle fields are clean 119505fbcbb0SMatt Jacob */ 11965f5aafe1SMatt Jacob cto->ct_syshandle = 0; 11979e11e5beSMatt Jacob cto->ct_header.rqs_seqno = 0; 119805fbcbb0SMatt Jacob 1199d02373f1SMatt Jacob isp_prt(mp->isp, ISP_LOGTDEBUG1, 12005f5aafe1SMatt Jacob "CTIO[%x] lun%d for ID%d ct_flags 0x%x", 12015f5aafe1SMatt Jacob cto->ct_fwhandle, csio->ccb_h.target_lun, 12025f5aafe1SMatt Jacob cto->ct_iid, cto->ct_flags); 120305fbcbb0SMatt Jacob ISP_TDQE(mp->isp, "tdma_mk", *mp->iptrp, cto); 120405fbcbb0SMatt Jacob 120505fbcbb0SMatt Jacob /* 120605fbcbb0SMatt Jacob * Get a new CTIO 120705fbcbb0SMatt Jacob */ 12089e11e5beSMatt Jacob cto = (ct_entry_t *) 12099e11e5beSMatt Jacob ISP_QUEUE_ENTRY(mp->isp->isp_rquest, *mp->iptrp); 12109e11e5beSMatt Jacob *mp->iptrp = 1211d02373f1SMatt Jacob ISP_NXT_QENTRY(*mp->iptrp, RQUEST_QUEUE_LEN(isp)); 12129e11e5beSMatt Jacob if (*mp->iptrp == mp->optr) { 12135f5aafe1SMatt Jacob isp_prt(mp->isp, ISP_LOGTDEBUG0, 1214f7dddf8aSMatt Jacob "Queue Overflow in tdma_mk"); 12159e11e5beSMatt Jacob mp->error = MUSHERR_NOQENTRIES; 12169e11e5beSMatt Jacob return; 12179e11e5beSMatt Jacob } 12189e11e5beSMatt Jacob /* 12199e11e5beSMatt Jacob * Fill in the new CTIO with info from the old one. 12209e11e5beSMatt Jacob */ 12219e11e5beSMatt Jacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO; 12229e11e5beSMatt Jacob cto->ct_header.rqs_entry_count = 1; 12235f5aafe1SMatt Jacob cto->ct_fwhandle = octo->ct_fwhandle; 12249e11e5beSMatt Jacob cto->ct_header.rqs_flags = 0; 12259e11e5beSMatt Jacob cto->ct_lun = octo->ct_lun; 12269e11e5beSMatt Jacob cto->ct_iid = octo->ct_iid; 12279e11e5beSMatt Jacob cto->ct_reserved2 = octo->ct_reserved2; 12289e11e5beSMatt Jacob cto->ct_tgt = octo->ct_tgt; 122905fbcbb0SMatt Jacob cto->ct_flags = octo->ct_flags; 12309e11e5beSMatt Jacob cto->ct_status = 0; 12319e11e5beSMatt Jacob cto->ct_scsi_status = 0; 12329e11e5beSMatt Jacob cto->ct_tag_val = octo->ct_tag_val; 12339e11e5beSMatt Jacob cto->ct_tag_type = octo->ct_tag_type; 12349e11e5beSMatt Jacob cto->ct_xfrlen = 0; 12359e11e5beSMatt Jacob cto->ct_resid = 0; 12369e11e5beSMatt Jacob cto->ct_timeout = octo->ct_timeout; 12379e11e5beSMatt Jacob cto->ct_seg_count = 0; 123805fbcbb0SMatt Jacob MEMZERO(cto->ct_dataseg, sizeof(cto->ct_dataseg)); 123905fbcbb0SMatt Jacob /* 124005fbcbb0SMatt Jacob * Now swizzle the old one for the consumption of the 124105fbcbb0SMatt Jacob * chip. 124205fbcbb0SMatt Jacob */ 124305fbcbb0SMatt Jacob ISP_SWIZ_CTIO(mp->isp, octo, octo); 12449e11e5beSMatt Jacob } 12459e11e5beSMatt Jacob } 12469e11e5beSMatt Jacob } 12479e11e5beSMatt Jacob 12489e11e5beSMatt Jacob static void 124905fbcbb0SMatt Jacob tdma_mkfc(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 12509e11e5beSMatt Jacob { 12519e11e5beSMatt Jacob mush_t *mp; 12529e11e5beSMatt Jacob struct ccb_scsiio *csio; 12539e11e5beSMatt Jacob struct isp_pcisoftc *pci; 12549e11e5beSMatt Jacob bus_dmamap_t *dp; 12559e11e5beSMatt Jacob ct2_entry_t *cto; 12565f5aafe1SMatt Jacob u_int16_t scsi_status, send_status, send_sense, handle; 12575f5aafe1SMatt Jacob u_int32_t totxfr, datalen; 125865b024e1SMatt Jacob u_int8_t sense[QLTM_SENSELEN]; 12599e11e5beSMatt Jacob int nctios; 12609e11e5beSMatt Jacob 12619e11e5beSMatt Jacob mp = (mush_t *) arg; 12629e11e5beSMatt Jacob if (error) { 12639e11e5beSMatt Jacob mp->error = error; 12649e11e5beSMatt Jacob return; 12659e11e5beSMatt Jacob } 12669e11e5beSMatt Jacob 126765b024e1SMatt Jacob csio = mp->cmd_token; 126865b024e1SMatt Jacob cto = mp->rq; 126965b024e1SMatt Jacob 127065b024e1SMatt Jacob if (nseg == 0) { 127165b024e1SMatt Jacob if ((cto->ct_flags & CT2_FLAG_MMASK) != CT2_FLAG_MODE1) { 1272f7dddf8aSMatt Jacob isp_prt(mp->isp, ISP_LOGWARN, 1273f7dddf8aSMatt Jacob "dma2_tgt_fc, a status CTIO2 without MODE1 " 1274f7dddf8aSMatt Jacob "set (0x%x)", cto->ct_flags); 127565b024e1SMatt Jacob mp->error = EINVAL; 127665b024e1SMatt Jacob return; 127765b024e1SMatt Jacob } 127865b024e1SMatt Jacob cto->ct_header.rqs_entry_count = 1; 127905fbcbb0SMatt Jacob cto->ct_header.rqs_seqno = 1; 12805f5aafe1SMatt Jacob /* ct_syshandle contains the handle set by caller */ 128165b024e1SMatt Jacob /* 128265b024e1SMatt Jacob * We preserve ct_lun, ct_iid, ct_rxid. We set the data 128365b024e1SMatt Jacob * flags to NO DATA and clear relative offset flags. 128465b024e1SMatt Jacob * We preserve the ct_resid and the response area. 128565b024e1SMatt Jacob */ 128665b024e1SMatt Jacob cto->ct_flags |= CT2_NO_DATA; 128705fbcbb0SMatt Jacob if (cto->ct_resid > 0) 128805fbcbb0SMatt Jacob cto->ct_flags |= CT2_DATA_UNDER; 128905fbcbb0SMatt Jacob else if (cto->ct_resid < 0) 129005fbcbb0SMatt Jacob cto->ct_flags |= CT2_DATA_OVER; 129165b024e1SMatt Jacob cto->ct_seg_count = 0; 129265b024e1SMatt Jacob cto->ct_reloff = 0; 129365b024e1SMatt Jacob ISP_TDQE(mp->isp, "dma2_tgt_fc[no data]", *mp->iptrp, cto); 1294d02373f1SMatt Jacob isp_prt(mp->isp, ISP_LOGTDEBUG1, 12955f5aafe1SMatt Jacob "CTIO2[%x] lun %d->iid%d flgs 0x%x sts 0x%x ssts " 1296d02373f1SMatt Jacob "0x%x res %d", cto->ct_rxid, csio->ccb_h.target_lun, 1297d02373f1SMatt Jacob cto->ct_iid, cto->ct_flags, cto->ct_status, 129865b024e1SMatt Jacob cto->rsp.m1.ct_scsi_status, cto->ct_resid); 129965b024e1SMatt Jacob ISP_SWIZ_CTIO2(isp, cto, cto); 13009e11e5beSMatt Jacob return; 13019e11e5beSMatt Jacob } 13029e11e5beSMatt Jacob 130365b024e1SMatt Jacob if ((cto->ct_flags & CT2_FLAG_MMASK) != CT2_FLAG_MODE0) { 1304f7dddf8aSMatt Jacob isp_prt(mp->isp, ISP_LOGWARN, 1305f7dddf8aSMatt Jacob "dma2_tgt_fc, a data CTIO2 without MODE0 set " 1306f7dddf8aSMatt Jacob "(0x%x)", cto->ct_flags); 130765b024e1SMatt Jacob mp->error = EINVAL; 130865b024e1SMatt Jacob return; 130965b024e1SMatt Jacob } 131065b024e1SMatt Jacob 131165b024e1SMatt Jacob 131265b024e1SMatt Jacob nctios = nseg / ISP_RQDSEG_T2; 131365b024e1SMatt Jacob if (nseg % ISP_RQDSEG_T2) { 131465b024e1SMatt Jacob nctios++; 131565b024e1SMatt Jacob } 131665b024e1SMatt Jacob 13179e11e5beSMatt Jacob /* 131865b024e1SMatt Jacob * Save the handle, status, reloff, and residual. We'll reinsert the 131965b024e1SMatt Jacob * handle into the last CTIO2 we're going to send, and reinsert status 132065b024e1SMatt Jacob * and residual (and possibly sense data) if that's to be sent as well. 132165b024e1SMatt Jacob * 132265b024e1SMatt Jacob * We preserve ct_reloff and adjust it for each data CTIO2 we send past 132365b024e1SMatt Jacob * the first one. This is needed so that the FCP DATA IUs being sent 132465b024e1SMatt Jacob * out have the correct offset (they can arrive at the other end out 132565b024e1SMatt Jacob * of order). 13269e11e5beSMatt Jacob */ 132765b024e1SMatt Jacob 13285f5aafe1SMatt Jacob handle = cto->ct_syshandle; 13295f5aafe1SMatt Jacob cto->ct_syshandle = 0; 133065b024e1SMatt Jacob 133165b024e1SMatt Jacob if ((send_status = (cto->ct_flags & CT2_SENDSTATUS)) != 0) { 13329e11e5beSMatt Jacob cto->ct_flags &= ~CT2_SENDSTATUS; 13339e11e5beSMatt Jacob 133465b024e1SMatt Jacob /* 133505fbcbb0SMatt Jacob * Preserve residual, which is actually the total count. 133665b024e1SMatt Jacob */ 133705fbcbb0SMatt Jacob datalen = cto->ct_resid; 133865b024e1SMatt Jacob 133965b024e1SMatt Jacob /* 134065b024e1SMatt Jacob * Save actual SCSI status. We'll reinsert the 134165b024e1SMatt Jacob * CT2_SNSLEN_VALID later if appropriate. 134265b024e1SMatt Jacob */ 134365b024e1SMatt Jacob scsi_status = cto->rsp.m0.ct_scsi_status & 0xff; 134465b024e1SMatt Jacob send_sense = cto->rsp.m0.ct_scsi_status & CT2_SNSLEN_VALID; 134565b024e1SMatt Jacob 134665b024e1SMatt Jacob /* 134765b024e1SMatt Jacob * If we're sending status and have a CHECK CONDTION and 134865b024e1SMatt Jacob * have sense data, we send one more CTIO2 with just the 134965b024e1SMatt Jacob * status and sense data. The upper layers have stashed 135065b024e1SMatt Jacob * the sense data in the dataseg structure for us. 135165b024e1SMatt Jacob */ 135265b024e1SMatt Jacob 135365b024e1SMatt Jacob if ((scsi_status & 0xf) == SCSI_STATUS_CHECK_COND && 135465b024e1SMatt Jacob send_sense) { 135565b024e1SMatt Jacob bcopy(cto->rsp.m0.ct_dataseg, sense, QLTM_SENSELEN); 135665b024e1SMatt Jacob nctios++; 135765b024e1SMatt Jacob } 135865b024e1SMatt Jacob } else { 135905fbcbb0SMatt Jacob scsi_status = send_sense = datalen = 0; 136065b024e1SMatt Jacob } 136165b024e1SMatt Jacob 136265b024e1SMatt Jacob totxfr = cto->ct_resid = 0; 136365b024e1SMatt Jacob cto->rsp.m0.ct_scsi_status = 0; 136465b024e1SMatt Jacob bzero(&cto->rsp, sizeof (cto->rsp)); 136565b024e1SMatt Jacob 13669e11e5beSMatt Jacob pci = (struct isp_pcisoftc *)mp->isp; 1367469b6b9eSMatt Jacob dp = &pci->dmaps[isp_handle_index(handle)]; 13689e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 13699e11e5beSMatt Jacob bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREREAD); 13709e11e5beSMatt Jacob } else { 13719e11e5beSMatt Jacob bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREWRITE); 13729e11e5beSMatt Jacob } 13739e11e5beSMatt Jacob 13749e11e5beSMatt Jacob while (nctios--) { 13759e11e5beSMatt Jacob int seg, seglim; 13769e11e5beSMatt Jacob 13779e11e5beSMatt Jacob seglim = nseg; 137865b024e1SMatt Jacob if (seglim) { 13799e11e5beSMatt Jacob if (seglim > ISP_RQDSEG_T2) 13809e11e5beSMatt Jacob seglim = ISP_RQDSEG_T2; 13819e11e5beSMatt Jacob 13829e11e5beSMatt Jacob for (seg = 0; seg < seglim; seg++) { 138365b024e1SMatt Jacob cto->rsp.m0.ct_dataseg[seg].ds_base = 138465b024e1SMatt Jacob dm_segs->ds_addr; 138565b024e1SMatt Jacob cto->rsp.m0.ct_dataseg[seg].ds_count = 138665b024e1SMatt Jacob dm_segs->ds_len; 13879e11e5beSMatt Jacob cto->rsp.m0.ct_xfrlen += dm_segs->ds_len; 138865b024e1SMatt Jacob totxfr += dm_segs->ds_len; 13899e11e5beSMatt Jacob dm_segs++; 13909e11e5beSMatt Jacob } 13919e11e5beSMatt Jacob cto->ct_seg_count = seg; 13929e11e5beSMatt Jacob } else { 139365b024e1SMatt Jacob /* 139465b024e1SMatt Jacob * This case should only happen when we're sending a 139565b024e1SMatt Jacob * synthesized MODE1 final status with sense data. 139665b024e1SMatt Jacob */ 139765b024e1SMatt Jacob if (send_sense == 0) { 1398f7dddf8aSMatt Jacob isp_prt(mp->isp, ISP_LOGWARN, 1399f7dddf8aSMatt Jacob "dma2_tgt_fc ran out of segments, " 1400f7dddf8aSMatt Jacob "no SENSE DATA"); 140165b024e1SMatt Jacob mp->error = EINVAL; 140265b024e1SMatt Jacob return; 140365b024e1SMatt Jacob } 14049e11e5beSMatt Jacob } 14059e11e5beSMatt Jacob 14069e11e5beSMatt Jacob /* 140765b024e1SMatt Jacob * At this point, the fields ct_lun, ct_iid, ct_rxid, 140865b024e1SMatt Jacob * ct_timeout have been carried over unchanged from what 140965b024e1SMatt Jacob * our caller had set. 141065b024e1SMatt Jacob * 141165b024e1SMatt Jacob * The field ct_reloff is either what the caller set, or 141265b024e1SMatt Jacob * what we've added to below. 141365b024e1SMatt Jacob * 141465b024e1SMatt Jacob * The dataseg fields and the seg_count fields we just got 141565b024e1SMatt Jacob * through setting. The data direction we've preserved all 141665b024e1SMatt Jacob * along and only clear it if we're sending a MODE1 status 141765b024e1SMatt Jacob * as the last CTIO. 141865b024e1SMatt Jacob * 141965b024e1SMatt Jacob */ 142065b024e1SMatt Jacob 142165b024e1SMatt Jacob if (nctios == 0) { 142265b024e1SMatt Jacob 142365b024e1SMatt Jacob /* 142465b024e1SMatt Jacob * We're the last in a sequence of CTIO2s, so mark this 142565b024e1SMatt Jacob * CTIO2 and save the handle to the CCB such that when 142665b024e1SMatt Jacob * this CTIO2 completes we can free dma resources and 14279e11e5beSMatt Jacob * do whatever else we need to do to finish the rest 14289e11e5beSMatt Jacob * of the command. 14299e11e5beSMatt Jacob */ 143065b024e1SMatt Jacob 14315f5aafe1SMatt Jacob cto->ct_syshandle = handle; 143265b024e1SMatt Jacob cto->ct_header.rqs_seqno = 1; 143365b024e1SMatt Jacob 143465b024e1SMatt Jacob if (send_status) { 143565b024e1SMatt Jacob if (send_sense) { 143665b024e1SMatt Jacob bcopy(sense, cto->rsp.m1.ct_resp, 143765b024e1SMatt Jacob QLTM_SENSELEN); 143865b024e1SMatt Jacob cto->rsp.m1.ct_senselen = 143965b024e1SMatt Jacob QLTM_SENSELEN; 144065b024e1SMatt Jacob scsi_status |= CT2_SNSLEN_VALID; 144165b024e1SMatt Jacob cto->rsp.m1.ct_scsi_status = 144265b024e1SMatt Jacob scsi_status; 144365b024e1SMatt Jacob cto->ct_flags &= CT2_FLAG_MMASK; 144465b024e1SMatt Jacob cto->ct_flags |= CT2_FLAG_MODE1 | 144565b024e1SMatt Jacob CT2_NO_DATA| CT2_SENDSTATUS; 144665b024e1SMatt Jacob } else { 144765b024e1SMatt Jacob cto->rsp.m0.ct_scsi_status = 144865b024e1SMatt Jacob scsi_status; 144965b024e1SMatt Jacob cto->ct_flags |= CT2_SENDSTATUS; 145065b024e1SMatt Jacob } 145105fbcbb0SMatt Jacob /* 145205fbcbb0SMatt Jacob * Get 'real' residual and set flags based 145305fbcbb0SMatt Jacob * on it. 145405fbcbb0SMatt Jacob */ 145505fbcbb0SMatt Jacob cto->ct_resid = datalen - totxfr; 145605fbcbb0SMatt Jacob if (cto->ct_resid > 0) 145705fbcbb0SMatt Jacob cto->ct_flags |= CT2_DATA_UNDER; 145805fbcbb0SMatt Jacob else if (cto->ct_resid < 0) 145905fbcbb0SMatt Jacob cto->ct_flags |= CT2_DATA_OVER; 146065b024e1SMatt Jacob } 14619e11e5beSMatt Jacob ISP_TDQE(mp->isp, "last dma2_tgt_fc", *mp->iptrp, cto); 1462d02373f1SMatt Jacob isp_prt(mp->isp, ISP_LOGTDEBUG1, 14635f5aafe1SMatt Jacob "CTIO2[%x] lun %d->iid%d flgs 0x%x sts 0x%x" 1464d02373f1SMatt Jacob " ssts 0x%x res %d", cto->ct_rxid, 146565b024e1SMatt Jacob csio->ccb_h.target_lun, (int) cto->ct_iid, 146642426921SMatt Jacob cto->ct_flags, cto->ct_status, 146765b024e1SMatt Jacob cto->rsp.m1.ct_scsi_status, cto->ct_resid); 146865b024e1SMatt Jacob ISP_SWIZ_CTIO2(isp, cto, cto); 14699e11e5beSMatt Jacob } else { 14709e11e5beSMatt Jacob ct2_entry_t *octo = cto; 147165b024e1SMatt Jacob 147265b024e1SMatt Jacob /* 147365b024e1SMatt Jacob * Make sure handle fields are clean 147465b024e1SMatt Jacob */ 14755f5aafe1SMatt Jacob cto->ct_syshandle = 0; 14769e11e5beSMatt Jacob cto->ct_header.rqs_seqno = 0; 147765b024e1SMatt Jacob 14789e11e5beSMatt Jacob ISP_TDQE(mp->isp, "dma2_tgt_fc", *mp->iptrp, cto); 1479d02373f1SMatt Jacob isp_prt(mp->isp, ISP_LOGTDEBUG1, 14805f5aafe1SMatt Jacob "CTIO2[%x] lun %d->iid%d flgs 0x%x", 1481d02373f1SMatt Jacob cto->ct_rxid, csio->ccb_h.target_lun, 1482d02373f1SMatt Jacob (int) cto->ct_iid, cto->ct_flags); 148365b024e1SMatt Jacob /* 148465b024e1SMatt Jacob * Get a new CTIO2 148565b024e1SMatt Jacob */ 14869e11e5beSMatt Jacob cto = (ct2_entry_t *) 14879e11e5beSMatt Jacob ISP_QUEUE_ENTRY(mp->isp->isp_rquest, *mp->iptrp); 14889e11e5beSMatt Jacob *mp->iptrp = 1489d02373f1SMatt Jacob ISP_NXT_QENTRY(*mp->iptrp, RQUEST_QUEUE_LEN(isp)); 14909e11e5beSMatt Jacob if (*mp->iptrp == mp->optr) { 1491f7dddf8aSMatt Jacob isp_prt(mp->isp, ISP_LOGWARN, 1492f7dddf8aSMatt Jacob "Queue Overflow in dma2_tgt_fc"); 14939e11e5beSMatt Jacob mp->error = MUSHERR_NOQENTRIES; 14949e11e5beSMatt Jacob return; 14959e11e5beSMatt Jacob } 149665b024e1SMatt Jacob 14979e11e5beSMatt Jacob /* 149865b024e1SMatt Jacob * Fill in the new CTIO2 with info from the old one. 14999e11e5beSMatt Jacob */ 15009e11e5beSMatt Jacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2; 15019e11e5beSMatt Jacob cto->ct_header.rqs_entry_count = 1; 15029e11e5beSMatt Jacob cto->ct_header.rqs_flags = 0; 15035f5aafe1SMatt Jacob /* ct_header.rqs_seqno && ct_syshandle done later */ 15045f5aafe1SMatt Jacob cto->ct_fwhandle = octo->ct_fwhandle; 15059e11e5beSMatt Jacob cto->ct_lun = octo->ct_lun; 15069e11e5beSMatt Jacob cto->ct_iid = octo->ct_iid; 15079e11e5beSMatt Jacob cto->ct_rxid = octo->ct_rxid; 150865b024e1SMatt Jacob cto->ct_flags = octo->ct_flags; 15099e11e5beSMatt Jacob cto->ct_status = 0; 15109e11e5beSMatt Jacob cto->ct_resid = 0; 15119e11e5beSMatt Jacob cto->ct_timeout = octo->ct_timeout; 15129e11e5beSMatt Jacob cto->ct_seg_count = 0; 151365b024e1SMatt Jacob /* 151465b024e1SMatt Jacob * Adjust the new relative offset by the amount which 151565b024e1SMatt Jacob * is recorded in the data segment of the old CTIO2 we 151665b024e1SMatt Jacob * just finished filling out. 151765b024e1SMatt Jacob */ 151865b024e1SMatt Jacob cto->ct_reloff += octo->rsp.m0.ct_xfrlen; 15199e11e5beSMatt Jacob bzero(&cto->rsp, sizeof (cto->rsp)); 152065b024e1SMatt Jacob ISP_SWIZ_CTIO2(isp, cto, cto); 15219e11e5beSMatt Jacob } 15229e11e5beSMatt Jacob } 15239e11e5beSMatt Jacob } 15249e11e5beSMatt Jacob #endif 15259e11e5beSMatt Jacob 15269e11e5beSMatt Jacob static void dma2 __P((void *, bus_dma_segment_t *, int, int)); 15279e11e5beSMatt Jacob 15289e11e5beSMatt Jacob static void 15299e11e5beSMatt Jacob dma2(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 15309e11e5beSMatt Jacob { 15319e11e5beSMatt Jacob mush_t *mp; 15329e11e5beSMatt Jacob struct ccb_scsiio *csio; 15339e11e5beSMatt Jacob struct isp_pcisoftc *pci; 15349e11e5beSMatt Jacob bus_dmamap_t *dp; 15359e11e5beSMatt Jacob bus_dma_segment_t *eseg; 15369e11e5beSMatt Jacob ispreq_t *rq; 15379e11e5beSMatt Jacob ispcontreq_t *crq; 15389e11e5beSMatt Jacob int seglim, datalen; 15399e11e5beSMatt Jacob 15409e11e5beSMatt Jacob mp = (mush_t *) arg; 15419e11e5beSMatt Jacob if (error) { 15429e11e5beSMatt Jacob mp->error = error; 15439e11e5beSMatt Jacob return; 15449e11e5beSMatt Jacob } 15459e11e5beSMatt Jacob 15469e11e5beSMatt Jacob if (nseg < 1) { 1547f7dddf8aSMatt Jacob isp_prt(mp->isp, ISP_LOGERR, "bad segment count (%d)", nseg); 15489e11e5beSMatt Jacob mp->error = EFAULT; 15499e11e5beSMatt Jacob return; 15509e11e5beSMatt Jacob } 15519e11e5beSMatt Jacob csio = mp->cmd_token; 15529e11e5beSMatt Jacob rq = mp->rq; 15539e11e5beSMatt Jacob pci = (struct isp_pcisoftc *)mp->isp; 1554469b6b9eSMatt Jacob dp = &pci->dmaps[isp_handle_index(rq->req_handle)]; 15559e11e5beSMatt Jacob 15569e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 15579e11e5beSMatt Jacob bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREREAD); 15589e11e5beSMatt Jacob } else { 15599e11e5beSMatt Jacob bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREWRITE); 15609e11e5beSMatt Jacob } 15619e11e5beSMatt Jacob 15629e11e5beSMatt Jacob datalen = XS_XFRLEN(csio); 15639e11e5beSMatt Jacob 15649e11e5beSMatt Jacob /* 15659e11e5beSMatt Jacob * We're passed an initial partially filled in entry that 15669e11e5beSMatt Jacob * has most fields filled in except for data transfer 15679e11e5beSMatt Jacob * related values. 15689e11e5beSMatt Jacob * 15699e11e5beSMatt Jacob * Our job is to fill in the initial request queue entry and 15709e11e5beSMatt Jacob * then to start allocating and filling in continuation entries 15719e11e5beSMatt Jacob * until we've covered the entire transfer. 15729e11e5beSMatt Jacob */ 15739e11e5beSMatt Jacob 15749e11e5beSMatt Jacob if (IS_FC(mp->isp)) { 1575d720e6d5SJustin T. Gibbs seglim = ISP_RQDSEG_T2; 1576d720e6d5SJustin T. Gibbs ((ispreqt2_t *)rq)->req_totalcnt = datalen; 15779e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 15789e11e5beSMatt Jacob ((ispreqt2_t *)rq)->req_flags |= REQFLAG_DATA_IN; 15799e11e5beSMatt Jacob } else { 15809e11e5beSMatt Jacob ((ispreqt2_t *)rq)->req_flags |= REQFLAG_DATA_OUT; 15819e11e5beSMatt Jacob } 1582d720e6d5SJustin T. Gibbs } else { 1583e142669aSMatt Jacob if (csio->cdb_len > 12) { 1584e142669aSMatt Jacob seglim = 0; 1585e142669aSMatt Jacob } else { 1586d720e6d5SJustin T. Gibbs seglim = ISP_RQDSEG; 1587e142669aSMatt Jacob } 15889e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 15899e11e5beSMatt Jacob rq->req_flags |= REQFLAG_DATA_IN; 15909e11e5beSMatt Jacob } else { 15919e11e5beSMatt Jacob rq->req_flags |= REQFLAG_DATA_OUT; 15929e11e5beSMatt Jacob } 1593d720e6d5SJustin T. Gibbs } 1594d720e6d5SJustin T. Gibbs 1595d720e6d5SJustin T. Gibbs eseg = dm_segs + nseg; 1596d720e6d5SJustin T. Gibbs 1597d720e6d5SJustin T. Gibbs while (datalen != 0 && rq->req_seg_count < seglim && dm_segs != eseg) { 15989e11e5beSMatt Jacob if (IS_FC(mp->isp)) { 1599d720e6d5SJustin T. Gibbs ispreqt2_t *rq2 = (ispreqt2_t *)rq; 1600d720e6d5SJustin T. Gibbs rq2->req_dataseg[rq2->req_seg_count].ds_base = 1601d720e6d5SJustin T. Gibbs dm_segs->ds_addr; 1602d720e6d5SJustin T. Gibbs rq2->req_dataseg[rq2->req_seg_count].ds_count = 1603d720e6d5SJustin T. Gibbs dm_segs->ds_len; 1604d720e6d5SJustin T. Gibbs } else { 1605d720e6d5SJustin T. Gibbs rq->req_dataseg[rq->req_seg_count].ds_base = 1606d720e6d5SJustin T. Gibbs dm_segs->ds_addr; 1607d720e6d5SJustin T. Gibbs rq->req_dataseg[rq->req_seg_count].ds_count = 1608d720e6d5SJustin T. Gibbs dm_segs->ds_len; 1609d720e6d5SJustin T. Gibbs } 1610d720e6d5SJustin T. Gibbs datalen -= dm_segs->ds_len; 1611d720e6d5SJustin T. Gibbs #if 0 16129e11e5beSMatt Jacob if (IS_FC(mp->isp)) { 1613d720e6d5SJustin T. Gibbs ispreqt2_t *rq2 = (ispreqt2_t *)rq; 16146e5c5328SMatt Jacob device_printf(mp->isp->isp_dev, 16156e5c5328SMatt Jacob "seg0[%d] cnt 0x%x paddr 0x%08x\n", 16166e5c5328SMatt Jacob rq->req_seg_count, 1617d720e6d5SJustin T. Gibbs rq2->req_dataseg[rq2->req_seg_count].ds_count, 1618d720e6d5SJustin T. Gibbs rq2->req_dataseg[rq2->req_seg_count].ds_base); 1619d720e6d5SJustin T. Gibbs } else { 16206e5c5328SMatt Jacob device_printf(mp->isp->isp_dev, 16216e5c5328SMatt Jacob "seg0[%d] cnt 0x%x paddr 0x%08x\n", 16226e5c5328SMatt Jacob rq->req_seg_count, 1623d720e6d5SJustin T. Gibbs rq->req_dataseg[rq->req_seg_count].ds_count, 1624d720e6d5SJustin T. Gibbs rq->req_dataseg[rq->req_seg_count].ds_base); 1625d720e6d5SJustin T. Gibbs } 1626d720e6d5SJustin T. Gibbs #endif 1627d720e6d5SJustin T. Gibbs rq->req_seg_count++; 1628d720e6d5SJustin T. Gibbs dm_segs++; 1629d720e6d5SJustin T. Gibbs } 1630d720e6d5SJustin T. Gibbs 1631d720e6d5SJustin T. Gibbs while (datalen > 0 && dm_segs != eseg) { 16329e11e5beSMatt Jacob crq = (ispcontreq_t *) 16339e11e5beSMatt Jacob ISP_QUEUE_ENTRY(mp->isp->isp_rquest, *mp->iptrp); 1634d02373f1SMatt Jacob *mp->iptrp = ISP_NXT_QENTRY(*mp->iptrp, RQUEST_QUEUE_LEN(isp)); 16359e11e5beSMatt Jacob if (*mp->iptrp == mp->optr) { 16366e5c5328SMatt Jacob isp_prt(mp->isp, 16376e5c5328SMatt Jacob ISP_LOGDEBUG0, "Request Queue Overflow++"); 16384873663cSMatt Jacob mp->error = MUSHERR_NOQENTRIES; 1639d720e6d5SJustin T. Gibbs return; 1640d720e6d5SJustin T. Gibbs } 1641d720e6d5SJustin T. Gibbs rq->req_header.rqs_entry_count++; 1642d720e6d5SJustin T. Gibbs bzero((void *)crq, sizeof (*crq)); 1643d720e6d5SJustin T. Gibbs crq->req_header.rqs_entry_count = 1; 1644d720e6d5SJustin T. Gibbs crq->req_header.rqs_entry_type = RQSTYPE_DATASEG; 1645d720e6d5SJustin T. Gibbs 1646d720e6d5SJustin T. Gibbs seglim = 0; 1647d720e6d5SJustin T. Gibbs while (datalen > 0 && seglim < ISP_CDSEG && dm_segs != eseg) { 1648d720e6d5SJustin T. Gibbs crq->req_dataseg[seglim].ds_base = 1649d720e6d5SJustin T. Gibbs dm_segs->ds_addr; 1650d720e6d5SJustin T. Gibbs crq->req_dataseg[seglim].ds_count = 1651d720e6d5SJustin T. Gibbs dm_segs->ds_len; 1652d720e6d5SJustin T. Gibbs #if 0 16536e5c5328SMatt Jacob device_printf(mp->isp->isp_dev, 16546e5c5328SMatt Jacob "seg%d[%d] cnt 0x%x paddr 0x%08x\n", 16556e5c5328SMatt Jacob rq->req_header.rqs_entry_count-1, 1656d720e6d5SJustin T. Gibbs seglim, crq->req_dataseg[seglim].ds_count, 1657d720e6d5SJustin T. Gibbs crq->req_dataseg[seglim].ds_base); 1658d720e6d5SJustin T. Gibbs #endif 1659d720e6d5SJustin T. Gibbs rq->req_seg_count++; 1660d720e6d5SJustin T. Gibbs dm_segs++; 1661d720e6d5SJustin T. Gibbs seglim++; 1662d720e6d5SJustin T. Gibbs datalen -= dm_segs->ds_len; 1663d720e6d5SJustin T. Gibbs } 1664d720e6d5SJustin T. Gibbs } 1665d720e6d5SJustin T. Gibbs } 1666d720e6d5SJustin T. Gibbs 1667d720e6d5SJustin T. Gibbs static int 16689e11e5beSMatt Jacob isp_pci_dmasetup(struct ispsoftc *isp, struct ccb_scsiio *csio, ispreq_t *rq, 16699637d68cSMatt Jacob u_int16_t *iptrp, u_int16_t optr) 1670d720e6d5SJustin T. Gibbs { 1671d720e6d5SJustin T. Gibbs struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp; 16720a5f7e8bSMatt Jacob bus_dmamap_t *dp = NULL; 1673d720e6d5SJustin T. Gibbs mush_t mush, *mp; 16749e11e5beSMatt Jacob void (*eptr) __P((void *, bus_dma_segment_t *, int, int)); 1675d720e6d5SJustin T. Gibbs 167665b024e1SMatt Jacob #ifdef ISP_TARGET_MODE 167765b024e1SMatt Jacob if (csio->ccb_h.func_code == XPT_CONT_TARGET_IO) { 167865b024e1SMatt Jacob if (IS_FC(isp)) { 167905fbcbb0SMatt Jacob eptr = tdma_mkfc; 168065b024e1SMatt Jacob } else { 168105fbcbb0SMatt Jacob eptr = tdma_mk; 168265b024e1SMatt Jacob } 168305fbcbb0SMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE || 168405fbcbb0SMatt Jacob (csio->dxfer_len == 0)) { 168565b024e1SMatt Jacob rq->req_seg_count = 1; 168665b024e1SMatt Jacob mp = &mush; 168765b024e1SMatt Jacob mp->isp = isp; 168865b024e1SMatt Jacob mp->cmd_token = csio; 168965b024e1SMatt Jacob mp->rq = rq; 169065b024e1SMatt Jacob mp->iptrp = iptrp; 169165b024e1SMatt Jacob mp->optr = optr; 169265b024e1SMatt Jacob mp->error = 0; 169365b024e1SMatt Jacob (*eptr)(mp, NULL, 0, 0); 169465b024e1SMatt Jacob goto exit; 169565b024e1SMatt Jacob } 169665b024e1SMatt Jacob } else 169765b024e1SMatt Jacob #endif 169865b024e1SMatt Jacob eptr = dma2; 169965b024e1SMatt Jacob 170042426921SMatt Jacob /* 170142426921SMatt Jacob * NB: if we need to do request queue entry swizzling, 170242426921SMatt Jacob * NB: this is where it would need to be done for cmds 170342426921SMatt Jacob * NB: that move no data. For commands that move data, 170442426921SMatt Jacob * NB: swizzling would take place in those functions. 170542426921SMatt Jacob */ 170605fbcbb0SMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE || 170705fbcbb0SMatt Jacob (csio->dxfer_len == 0)) { 170842426921SMatt Jacob rq->req_seg_count = 1; 170942426921SMatt Jacob return (CMD_QUEUED); 171042426921SMatt Jacob } 171142426921SMatt Jacob 1712d720e6d5SJustin T. Gibbs /* 1713d720e6d5SJustin T. Gibbs * Do a virtual grapevine step to collect info for 17144873663cSMatt Jacob * the callback dma allocation that we have to use... 1715d720e6d5SJustin T. Gibbs */ 1716d720e6d5SJustin T. Gibbs mp = &mush; 1717d720e6d5SJustin T. Gibbs mp->isp = isp; 17189e11e5beSMatt Jacob mp->cmd_token = csio; 1719d720e6d5SJustin T. Gibbs mp->rq = rq; 1720d720e6d5SJustin T. Gibbs mp->iptrp = iptrp; 1721d720e6d5SJustin T. Gibbs mp->optr = optr; 1722d720e6d5SJustin T. Gibbs mp->error = 0; 1723d720e6d5SJustin T. Gibbs 17249e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_SCATTER_VALID) == 0) { 17259e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DATA_PHYS) == 0) { 17264873663cSMatt Jacob int error, s; 1727469b6b9eSMatt Jacob dp = &pci->dmaps[isp_handle_index(rq->req_handle)]; 1728d720e6d5SJustin T. Gibbs s = splsoftvm(); 1729d720e6d5SJustin T. Gibbs error = bus_dmamap_load(pci->parent_dmat, *dp, 17309e11e5beSMatt Jacob csio->data_ptr, csio->dxfer_len, eptr, mp, 0); 1731d720e6d5SJustin T. Gibbs if (error == EINPROGRESS) { 1732d720e6d5SJustin T. Gibbs bus_dmamap_unload(pci->parent_dmat, *dp); 1733d720e6d5SJustin T. Gibbs mp->error = EINVAL; 1734f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 1735f7dddf8aSMatt Jacob "deferred dma allocation not supported"); 1736d720e6d5SJustin T. Gibbs } else if (error && mp->error == 0) { 17370a5f7e8bSMatt Jacob #ifdef DIAGNOSTIC 17386e5c5328SMatt Jacob isp_prt(isp, ISP_LOGERR, 17396e5c5328SMatt Jacob "error %d in dma mapping code", error); 17400a5f7e8bSMatt Jacob #endif 1741d720e6d5SJustin T. Gibbs mp->error = error; 1742d720e6d5SJustin T. Gibbs } 17434873663cSMatt Jacob splx(s); 1744d720e6d5SJustin T. Gibbs } else { 1745d720e6d5SJustin T. Gibbs /* Pointer to physical buffer */ 1746d720e6d5SJustin T. Gibbs struct bus_dma_segment seg; 1747d720e6d5SJustin T. Gibbs seg.ds_addr = (bus_addr_t)csio->data_ptr; 1748d720e6d5SJustin T. Gibbs seg.ds_len = csio->dxfer_len; 17499e11e5beSMatt Jacob (*eptr)(mp, &seg, 1, 0); 1750d720e6d5SJustin T. Gibbs } 1751d720e6d5SJustin T. Gibbs } else { 1752d720e6d5SJustin T. Gibbs struct bus_dma_segment *segs; 1753d720e6d5SJustin T. Gibbs 17549e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DATA_PHYS) != 0) { 1755f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 1756f7dddf8aSMatt Jacob "Physical segment pointers unsupported"); 1757d720e6d5SJustin T. Gibbs mp->error = EINVAL; 17589e11e5beSMatt Jacob } else if ((csio->ccb_h.flags & CAM_SG_LIST_PHYS) == 0) { 1759f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 1760f7dddf8aSMatt Jacob "Virtual segment addresses unsupported"); 1761d720e6d5SJustin T. Gibbs mp->error = EINVAL; 1762d720e6d5SJustin T. Gibbs } else { 1763d720e6d5SJustin T. Gibbs /* Just use the segments provided */ 1764d720e6d5SJustin T. Gibbs segs = (struct bus_dma_segment *) csio->data_ptr; 17659e11e5beSMatt Jacob (*eptr)(mp, segs, csio->sglist_cnt, 0); 1766d720e6d5SJustin T. Gibbs } 1767d720e6d5SJustin T. Gibbs } 1768003a310fSMatt Jacob #ifdef ISP_TARGET_MODE 176965b024e1SMatt Jacob exit: 1770003a310fSMatt Jacob #endif 1771d720e6d5SJustin T. Gibbs if (mp->error) { 17724873663cSMatt Jacob int retval = CMD_COMPLETE; 17734873663cSMatt Jacob if (mp->error == MUSHERR_NOQENTRIES) { 17744873663cSMatt Jacob retval = CMD_EAGAIN; 17754873663cSMatt Jacob } else if (mp->error == EFBIG) { 17760a5f7e8bSMatt Jacob XS_SETERR(csio, CAM_REQ_TOO_BIG); 1777d720e6d5SJustin T. Gibbs } else if (mp->error == EINVAL) { 17780a5f7e8bSMatt Jacob XS_SETERR(csio, CAM_REQ_INVALID); 1779d720e6d5SJustin T. Gibbs } else { 17800a5f7e8bSMatt Jacob XS_SETERR(csio, CAM_UNREC_HBA_ERROR); 1781d720e6d5SJustin T. Gibbs } 17824873663cSMatt Jacob return (retval); 17834873663cSMatt Jacob } else { 17840a5f7e8bSMatt Jacob /* 17850a5f7e8bSMatt Jacob * Check to see if we weren't cancelled while sleeping on 17860a5f7e8bSMatt Jacob * getting DMA resources... 17870a5f7e8bSMatt Jacob */ 17889e11e5beSMatt Jacob if ((csio->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG) { 17890a5f7e8bSMatt Jacob if (dp) { 17900a5f7e8bSMatt Jacob bus_dmamap_unload(pci->parent_dmat, *dp); 17910a5f7e8bSMatt Jacob } 17920a5f7e8bSMatt Jacob return (CMD_COMPLETE); 17930a5f7e8bSMatt Jacob } 17944873663cSMatt Jacob return (CMD_QUEUED); 1795d720e6d5SJustin T. Gibbs } 1796d720e6d5SJustin T. Gibbs } 1797d720e6d5SJustin T. Gibbs 1798d720e6d5SJustin T. Gibbs static void 1799d8d5f2adSMatt Jacob isp_pci_dmateardown(struct ispsoftc *isp, XS_T *xs, u_int16_t handle) 1800d720e6d5SJustin T. Gibbs { 1801d720e6d5SJustin T. Gibbs struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp; 1802469b6b9eSMatt Jacob bus_dmamap_t *dp = &pci->dmaps[isp_handle_index(handle)]; 1803a95ae193SMatt Jacob if ((xs->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 1804d720e6d5SJustin T. Gibbs bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_POSTREAD); 1805d720e6d5SJustin T. Gibbs } else { 1806d720e6d5SJustin T. Gibbs bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_POSTWRITE); 1807d720e6d5SJustin T. Gibbs } 1808d720e6d5SJustin T. Gibbs bus_dmamap_unload(pci->parent_dmat, *dp); 1809d720e6d5SJustin T. Gibbs } 1810d720e6d5SJustin T. Gibbs 181165adb54cSMatt Jacob 181265adb54cSMatt Jacob static void 181317e318c6SMatt Jacob isp_pci_reset1(struct ispsoftc *isp) 181465adb54cSMatt Jacob { 181565adb54cSMatt Jacob /* Make sure the BIOS is disabled */ 181665adb54cSMatt Jacob isp_pci_wr_reg(isp, HCCR, PCI_HCCR_CMD_BIOS); 1817469b6b9eSMatt Jacob /* and enable interrupts */ 1818469b6b9eSMatt Jacob ENABLE_INTS(isp); 181965adb54cSMatt Jacob } 182065adb54cSMatt Jacob 182165adb54cSMatt Jacob static void 1822d02373f1SMatt Jacob isp_pci_dumpregs(struct ispsoftc *isp, const char *msg) 182365adb54cSMatt Jacob { 182465adb54cSMatt Jacob struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp; 1825d02373f1SMatt Jacob if (msg) 18266e5c5328SMatt Jacob printf("%s: %s\n", device_get_nameunit(isp->isp_dev), msg); 18276e5c5328SMatt Jacob else 18286e5c5328SMatt Jacob printf("%s:\n", device_get_nameunit(isp->isp_dev)); 1829d02373f1SMatt Jacob if (IS_SCSI(isp)) 1830d02373f1SMatt Jacob printf(" biu_conf1=%x", ISP_READ(isp, BIU_CONF1)); 1831d02373f1SMatt Jacob else 1832d02373f1SMatt Jacob printf(" biu_csr=%x", ISP_READ(isp, BIU2100_CSR)); 1833d02373f1SMatt Jacob printf(" biu_icr=%x biu_isr=%x biu_sema=%x ", ISP_READ(isp, BIU_ICR), 1834d02373f1SMatt Jacob ISP_READ(isp, BIU_ISR), ISP_READ(isp, BIU_SEMA)); 1835d02373f1SMatt Jacob printf("risc_hccr=%x\n", ISP_READ(isp, HCCR)); 1836d02373f1SMatt Jacob 1837d02373f1SMatt Jacob 1838d02373f1SMatt Jacob if (IS_SCSI(isp)) { 1839d02373f1SMatt Jacob ISP_WRITE(isp, HCCR, HCCR_CMD_PAUSE); 1840d02373f1SMatt Jacob printf(" cdma_conf=%x cdma_sts=%x cdma_fifostat=%x\n", 1841d02373f1SMatt Jacob ISP_READ(isp, CDMA_CONF), ISP_READ(isp, CDMA_STATUS), 1842d02373f1SMatt Jacob ISP_READ(isp, CDMA_FIFO_STS)); 1843d02373f1SMatt Jacob printf(" ddma_conf=%x ddma_sts=%x ddma_fifostat=%x\n", 1844d02373f1SMatt Jacob ISP_READ(isp, DDMA_CONF), ISP_READ(isp, DDMA_STATUS), 1845d02373f1SMatt Jacob ISP_READ(isp, DDMA_FIFO_STS)); 1846d02373f1SMatt Jacob printf(" sxp_int=%x sxp_gross=%x sxp(scsi_ctrl)=%x\n", 1847d02373f1SMatt Jacob ISP_READ(isp, SXP_INTERRUPT), 1848d02373f1SMatt Jacob ISP_READ(isp, SXP_GROSS_ERR), 1849d02373f1SMatt Jacob ISP_READ(isp, SXP_PINS_CTRL)); 1850d02373f1SMatt Jacob ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE); 1851d02373f1SMatt Jacob } 1852d02373f1SMatt Jacob printf(" mbox regs: %x %x %x %x %x\n", 1853d02373f1SMatt Jacob ISP_READ(isp, OUTMAILBOX0), ISP_READ(isp, OUTMAILBOX1), 1854d02373f1SMatt Jacob ISP_READ(isp, OUTMAILBOX2), ISP_READ(isp, OUTMAILBOX3), 1855d02373f1SMatt Jacob ISP_READ(isp, OUTMAILBOX4)); 1856d02373f1SMatt Jacob printf(" PCI Status Command/Status=%x\n", 1857960f6939SMatt Jacob pci_read_config(pci->pci_dev, PCIR_COMMAND, 1)); 185865adb54cSMatt Jacob } 1859