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 48126ec864SMatt Jacob static u_int16_t isp_pci_rd_reg(struct ispsoftc *, int); 49126ec864SMatt Jacob static void isp_pci_wr_reg(struct ispsoftc *, int, u_int16_t); 50126ec864SMatt Jacob static u_int16_t isp_pci_rd_reg_1080(struct ispsoftc *, int); 51126ec864SMatt Jacob static void isp_pci_wr_reg_1080(struct ispsoftc *, int, u_int16_t); 52126ec864SMatt Jacob static int 53126ec864SMatt Jacob isp_pci_rd_isr(struct ispsoftc *, u_int16_t *, u_int16_t *, u_int16_t *); 54126ec864SMatt Jacob static int 55126ec864SMatt Jacob isp_pci_rd_isr_2300(struct ispsoftc *, u_int16_t *, u_int16_t *, u_int16_t *); 56126ec864SMatt Jacob static int isp_pci_mbxdma(struct ispsoftc *); 57126ec864SMatt Jacob static int 58126ec864SMatt Jacob isp_pci_dmasetup(struct ispsoftc *, XS_T *, ispreq_t *, u_int16_t *, u_int16_t); 59d720e6d5SJustin T. Gibbs static void 60126ec864SMatt Jacob isp_pci_dmateardown(struct ispsoftc *, XS_T *, u_int16_t); 6165adb54cSMatt Jacob 62126ec864SMatt Jacob static void isp_pci_reset1(struct ispsoftc *); 63126ec864SMatt Jacob static void isp_pci_dumpregs(struct ispsoftc *, const char *); 6465adb54cSMatt Jacob 65fed92c47SMatt Jacob #ifndef ISP_CODE_ORG 66fed92c47SMatt Jacob #define ISP_CODE_ORG 0x1000 67fed92c47SMatt Jacob #endif 68fed92c47SMatt Jacob 6965adb54cSMatt Jacob static struct ispmdvec mdvec = { 70126ec864SMatt Jacob isp_pci_rd_isr, 7165adb54cSMatt Jacob isp_pci_rd_reg, 7265adb54cSMatt Jacob isp_pci_wr_reg, 7365adb54cSMatt Jacob isp_pci_mbxdma, 7465adb54cSMatt Jacob isp_pci_dmasetup, 75d720e6d5SJustin T. Gibbs isp_pci_dmateardown, 7665adb54cSMatt Jacob NULL, 7765adb54cSMatt Jacob isp_pci_reset1, 7865adb54cSMatt Jacob isp_pci_dumpregs, 7956aef503SMatt Jacob NULL, 80d02373f1SMatt Jacob BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64 8165adb54cSMatt Jacob }; 8265adb54cSMatt Jacob 83d59bd469SMatt Jacob static struct ispmdvec mdvec_1080 = { 84126ec864SMatt Jacob isp_pci_rd_isr, 85d59bd469SMatt Jacob isp_pci_rd_reg_1080, 86d59bd469SMatt Jacob isp_pci_wr_reg_1080, 87d59bd469SMatt Jacob isp_pci_mbxdma, 88d59bd469SMatt Jacob isp_pci_dmasetup, 89d59bd469SMatt Jacob isp_pci_dmateardown, 90d59bd469SMatt Jacob NULL, 91d59bd469SMatt Jacob isp_pci_reset1, 92d59bd469SMatt Jacob isp_pci_dumpregs, 9356aef503SMatt Jacob NULL, 94d02373f1SMatt Jacob BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64 95d59bd469SMatt Jacob }; 96d59bd469SMatt Jacob 97960f6939SMatt Jacob static struct ispmdvec mdvec_12160 = { 98126ec864SMatt Jacob isp_pci_rd_isr, 99960f6939SMatt Jacob isp_pci_rd_reg_1080, 100960f6939SMatt Jacob isp_pci_wr_reg_1080, 101960f6939SMatt Jacob isp_pci_mbxdma, 102960f6939SMatt Jacob isp_pci_dmasetup, 103960f6939SMatt Jacob isp_pci_dmateardown, 104960f6939SMatt Jacob NULL, 105960f6939SMatt Jacob isp_pci_reset1, 106960f6939SMatt Jacob isp_pci_dumpregs, 10756aef503SMatt Jacob NULL, 108d02373f1SMatt Jacob BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64 109960f6939SMatt Jacob }; 110960f6939SMatt Jacob 11165adb54cSMatt Jacob static struct ispmdvec mdvec_2100 = { 112126ec864SMatt Jacob isp_pci_rd_isr, 11365adb54cSMatt Jacob isp_pci_rd_reg, 11465adb54cSMatt Jacob isp_pci_wr_reg, 11565adb54cSMatt Jacob isp_pci_mbxdma, 11665adb54cSMatt Jacob isp_pci_dmasetup, 117d720e6d5SJustin T. Gibbs isp_pci_dmateardown, 11865adb54cSMatt Jacob NULL, 11965adb54cSMatt Jacob isp_pci_reset1, 120d02373f1SMatt Jacob isp_pci_dumpregs 12165adb54cSMatt Jacob }; 122222bb542SMatt Jacob 123222bb542SMatt Jacob static struct ispmdvec mdvec_2200 = { 124126ec864SMatt Jacob isp_pci_rd_isr, 125126ec864SMatt Jacob isp_pci_rd_reg, 126126ec864SMatt Jacob isp_pci_wr_reg, 127126ec864SMatt Jacob isp_pci_mbxdma, 128126ec864SMatt Jacob isp_pci_dmasetup, 129126ec864SMatt Jacob isp_pci_dmateardown, 130126ec864SMatt Jacob NULL, 131126ec864SMatt Jacob isp_pci_reset1, 132126ec864SMatt Jacob isp_pci_dumpregs 133126ec864SMatt Jacob }; 134126ec864SMatt Jacob 135126ec864SMatt Jacob static struct ispmdvec mdvec_2300 = { 136126ec864SMatt Jacob isp_pci_rd_isr_2300, 137222bb542SMatt Jacob isp_pci_rd_reg, 138222bb542SMatt Jacob isp_pci_wr_reg, 139222bb542SMatt Jacob isp_pci_mbxdma, 140222bb542SMatt Jacob isp_pci_dmasetup, 141222bb542SMatt Jacob isp_pci_dmateardown, 142222bb542SMatt Jacob NULL, 143222bb542SMatt Jacob isp_pci_reset1, 144d02373f1SMatt Jacob isp_pci_dumpregs 145222bb542SMatt Jacob }; 146d951bbcaSMatt Jacob 14765adb54cSMatt Jacob #ifndef PCIM_CMD_INVEN 14865adb54cSMatt Jacob #define PCIM_CMD_INVEN 0x10 14965adb54cSMatt Jacob #endif 15065adb54cSMatt Jacob #ifndef PCIM_CMD_BUSMASTEREN 15165adb54cSMatt Jacob #define PCIM_CMD_BUSMASTEREN 0x0004 15265adb54cSMatt Jacob #endif 153d951bbcaSMatt Jacob #ifndef PCIM_CMD_PERRESPEN 154d951bbcaSMatt Jacob #define PCIM_CMD_PERRESPEN 0x0040 155d951bbcaSMatt Jacob #endif 156d951bbcaSMatt Jacob #ifndef PCIM_CMD_SEREN 157d951bbcaSMatt Jacob #define PCIM_CMD_SEREN 0x0100 158d951bbcaSMatt Jacob #endif 159d951bbcaSMatt Jacob 160d951bbcaSMatt Jacob #ifndef PCIR_COMMAND 161d951bbcaSMatt Jacob #define PCIR_COMMAND 0x04 162d951bbcaSMatt Jacob #endif 163d951bbcaSMatt Jacob 164d951bbcaSMatt Jacob #ifndef PCIR_CACHELNSZ 165d951bbcaSMatt Jacob #define PCIR_CACHELNSZ 0x0c 166d951bbcaSMatt Jacob #endif 167d951bbcaSMatt Jacob 168d951bbcaSMatt Jacob #ifndef PCIR_LATTIMER 169d951bbcaSMatt Jacob #define PCIR_LATTIMER 0x0d 170d951bbcaSMatt Jacob #endif 171d951bbcaSMatt Jacob 172ab6d0040SMatt Jacob #ifndef PCIR_ROMADDR 173ab6d0040SMatt Jacob #define PCIR_ROMADDR 0x30 174ab6d0040SMatt Jacob #endif 175ab6d0040SMatt Jacob 17665adb54cSMatt Jacob #ifndef PCI_VENDOR_QLOGIC 17765adb54cSMatt Jacob #define PCI_VENDOR_QLOGIC 0x1077 17865adb54cSMatt Jacob #endif 17965adb54cSMatt Jacob 18065adb54cSMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP1020 18165adb54cSMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP1020 0x1020 18265adb54cSMatt Jacob #endif 18365adb54cSMatt Jacob 184d59bd469SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP1080 185d59bd469SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP1080 0x1080 186d59bd469SMatt Jacob #endif 187d59bd469SMatt Jacob 188960f6939SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP12160 189960f6939SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP12160 0x1216 190960f6939SMatt Jacob #endif 191960f6939SMatt Jacob 192d59bd469SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP1240 193d59bd469SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP1240 0x1240 194d59bd469SMatt Jacob #endif 19565adb54cSMatt Jacob 19622e1dc85SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP1280 19722e1dc85SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP1280 0x1280 19822e1dc85SMatt Jacob #endif 19922e1dc85SMatt Jacob 20065adb54cSMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP2100 20165adb54cSMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP2100 0x2100 20265adb54cSMatt Jacob #endif 20365adb54cSMatt Jacob 204222bb542SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP2200 205222bb542SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP2200 0x2200 206222bb542SMatt Jacob #endif 207222bb542SMatt Jacob 208126ec864SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP2300 209126ec864SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP2300 0x2300 210126ec864SMatt Jacob #endif 211126ec864SMatt Jacob 212126ec864SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP2312 213126ec864SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP2312 0x2312 214126ec864SMatt Jacob #endif 215126ec864SMatt Jacob 21656aef503SMatt Jacob #define PCI_QLOGIC_ISP1020 \ 21756aef503SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP1020 << 16) | PCI_VENDOR_QLOGIC) 218d59bd469SMatt Jacob 219d59bd469SMatt Jacob #define PCI_QLOGIC_ISP1080 \ 220d59bd469SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP1080 << 16) | PCI_VENDOR_QLOGIC) 221d59bd469SMatt Jacob 222960f6939SMatt Jacob #define PCI_QLOGIC_ISP12160 \ 223960f6939SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP12160 << 16) | PCI_VENDOR_QLOGIC) 224960f6939SMatt Jacob 225d59bd469SMatt Jacob #define PCI_QLOGIC_ISP1240 \ 226d59bd469SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP1240 << 16) | PCI_VENDOR_QLOGIC) 227d59bd469SMatt Jacob 22822e1dc85SMatt Jacob #define PCI_QLOGIC_ISP1280 \ 22922e1dc85SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP1280 << 16) | PCI_VENDOR_QLOGIC) 23022e1dc85SMatt Jacob 23165adb54cSMatt Jacob #define PCI_QLOGIC_ISP2100 \ 23265adb54cSMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP2100 << 16) | PCI_VENDOR_QLOGIC) 23365adb54cSMatt Jacob 234222bb542SMatt Jacob #define PCI_QLOGIC_ISP2200 \ 235222bb542SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP2200 << 16) | PCI_VENDOR_QLOGIC) 236222bb542SMatt Jacob 237126ec864SMatt Jacob #define PCI_QLOGIC_ISP2300 \ 238126ec864SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP2300 << 16) | PCI_VENDOR_QLOGIC) 239126ec864SMatt Jacob 240126ec864SMatt Jacob #define PCI_QLOGIC_ISP2312 \ 241126ec864SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP2312 << 16) | PCI_VENDOR_QLOGIC) 242126ec864SMatt Jacob 243e11a1ee8SMatt Jacob /* 244e11a1ee8SMatt Jacob * Odd case for some AMI raid cards... We need to *not* attach to this. 245e11a1ee8SMatt Jacob */ 246e11a1ee8SMatt Jacob #define AMI_RAID_SUBVENDOR_ID 0x101e 247e11a1ee8SMatt Jacob 24865adb54cSMatt Jacob #define IO_MAP_REG 0x10 24965adb54cSMatt Jacob #define MEM_MAP_REG 0x14 25065adb54cSMatt Jacob 251d951bbcaSMatt Jacob #define PCI_DFLT_LTNCY 0x40 252d951bbcaSMatt Jacob #define PCI_DFLT_LNSZ 0x10 25365adb54cSMatt Jacob 254960f6939SMatt Jacob static int isp_pci_probe (device_t); 255960f6939SMatt Jacob static int isp_pci_attach (device_t); 25665adb54cSMatt Jacob 2571923f739SMatt Jacob 25865adb54cSMatt Jacob struct isp_pcisoftc { 25965adb54cSMatt Jacob struct ispsoftc pci_isp; 260960f6939SMatt Jacob device_t pci_dev; 261960f6939SMatt Jacob struct resource * pci_reg; 26265adb54cSMatt Jacob bus_space_tag_t pci_st; 26365adb54cSMatt Jacob bus_space_handle_t pci_sh; 264960f6939SMatt Jacob void * ih; 265d59bd469SMatt Jacob int16_t pci_poff[_NREG_BLKS]; 2661923f739SMatt Jacob bus_dma_tag_t dmat; 267a95ae193SMatt Jacob bus_dmamap_t *dmaps; 26865adb54cSMatt Jacob }; 26956aef503SMatt Jacob ispfwfunc *isp_get_firmware_p = NULL; 27065adb54cSMatt Jacob 271960f6939SMatt Jacob static device_method_t isp_pci_methods[] = { 272960f6939SMatt Jacob /* Device interface */ 273960f6939SMatt Jacob DEVMETHOD(device_probe, isp_pci_probe), 274960f6939SMatt Jacob DEVMETHOD(device_attach, isp_pci_attach), 275960f6939SMatt Jacob { 0, 0 } 27665adb54cSMatt Jacob }; 277126ec864SMatt Jacob static void isp_pci_intr(void *); 27865adb54cSMatt Jacob 279960f6939SMatt Jacob static driver_t isp_pci_driver = { 280960f6939SMatt Jacob "isp", isp_pci_methods, sizeof (struct isp_pcisoftc) 281960f6939SMatt Jacob }; 282960f6939SMatt Jacob static devclass_t isp_devclass; 283960f6939SMatt Jacob DRIVER_MODULE(isp, pci, isp_pci_driver, isp_devclass, 0, 0); 28456aef503SMatt Jacob MODULE_VERSION(isp, 1); 28565adb54cSMatt Jacob 286960f6939SMatt Jacob static int 287960f6939SMatt Jacob isp_pci_probe(device_t dev) 28865adb54cSMatt Jacob { 289960f6939SMatt Jacob switch ((pci_get_device(dev) << 16) | (pci_get_vendor(dev))) { 29056aef503SMatt Jacob case PCI_QLOGIC_ISP1020: 291960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 1020/1040 PCI SCSI Adapter"); 29265adb54cSMatt Jacob break; 293d59bd469SMatt Jacob case PCI_QLOGIC_ISP1080: 294960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 1080 PCI SCSI Adapter"); 295c6608df3SMatt Jacob break; 296c6608df3SMatt Jacob case PCI_QLOGIC_ISP1240: 297960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 1240 PCI SCSI Adapter"); 298d59bd469SMatt Jacob break; 29922e1dc85SMatt Jacob case PCI_QLOGIC_ISP1280: 300960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 1280 PCI SCSI Adapter"); 301960f6939SMatt Jacob break; 302960f6939SMatt Jacob case PCI_QLOGIC_ISP12160: 303e11a1ee8SMatt Jacob if (pci_get_subvendor(dev) == AMI_RAID_SUBVENDOR_ID) { 304e11a1ee8SMatt Jacob return (ENXIO); 305e11a1ee8SMatt Jacob } 306960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 12160 PCI SCSI Adapter"); 30722e1dc85SMatt Jacob break; 30865adb54cSMatt Jacob case PCI_QLOGIC_ISP2100: 309960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 2100 PCI FC-AL Adapter"); 31065adb54cSMatt Jacob break; 3115542fe4bSMatt Jacob case PCI_QLOGIC_ISP2200: 312960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 2200 PCI FC-AL Adapter"); 3135542fe4bSMatt Jacob break; 314126ec864SMatt Jacob case PCI_QLOGIC_ISP2300: 315126ec864SMatt Jacob device_set_desc(dev, "Qlogic ISP 2300 PCI FC-AL Adapter"); 316126ec864SMatt Jacob break; 317126ec864SMatt Jacob case PCI_QLOGIC_ISP2312: 318126ec864SMatt Jacob device_set_desc(dev, "Qlogic ISP 2312 PCI FC-AL Adapter"); 319126ec864SMatt Jacob break; 32065adb54cSMatt Jacob default: 321960f6939SMatt Jacob return (ENXIO); 32265adb54cSMatt Jacob } 323d02373f1SMatt Jacob if (device_get_unit(dev) == 0 && bootverbose) { 324d02373f1SMatt Jacob printf("Qlogic ISP Driver, FreeBSD Version %d.%d, " 325a95ae193SMatt Jacob "Core Version %d.%d\n", 326d720e6d5SJustin T. Gibbs ISP_PLATFORM_VERSION_MAJOR, ISP_PLATFORM_VERSION_MINOR, 327d720e6d5SJustin T. Gibbs ISP_CORE_VERSION_MAJOR, ISP_CORE_VERSION_MINOR); 32865adb54cSMatt Jacob } 32956aef503SMatt Jacob /* 33056aef503SMatt Jacob * XXXX: Here is where we might load the f/w module 33156aef503SMatt Jacob * XXXX: (or increase a reference count to it). 33256aef503SMatt Jacob */ 333960f6939SMatt Jacob return (0); 33465adb54cSMatt Jacob } 33565adb54cSMatt Jacob 336960f6939SMatt Jacob static int 337960f6939SMatt Jacob isp_pci_attach(device_t dev) 33865adb54cSMatt Jacob { 339960f6939SMatt Jacob struct resource *regs, *irq; 3406e5c5328SMatt Jacob int tval, rtp, rgd, iqd, m1, m2, isp_debug, role; 341960f6939SMatt Jacob u_int32_t data, cmd, linesz, psize, basetype; 34265adb54cSMatt Jacob struct isp_pcisoftc *pcs; 3433395b056SMatt Jacob struct ispsoftc *isp = NULL; 344c6608df3SMatt Jacob struct ispmdvec *mdvp; 34522941bd7SPeter Wemm const char *sptr; 3463395b056SMatt Jacob int locksetup = 0; 34765adb54cSMatt Jacob 348222bb542SMatt Jacob /* 3499ba86737SMatt Jacob * Figure out if we're supposed to skip this one. 350b9b599feSMatt Jacob * If we are, we actually go to ISP_ROLE_NONE. 3519ba86737SMatt Jacob */ 3526e5c5328SMatt Jacob 3536e5c5328SMatt Jacob tval = 0; 3546e5c5328SMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 3556e5c5328SMatt Jacob "disable", &tval) == 0 && tval) { 356b9b599feSMatt Jacob device_printf(dev, "device is disabled\n"); 357b9b599feSMatt Jacob /* but return 0 so the !$)$)*!$*) unit isn't reused */ 358b9b599feSMatt Jacob return (0); 359b9b599feSMatt Jacob } 3606e5c5328SMatt Jacob 3616e5c5328SMatt Jacob role = 0; 3626e5c5328SMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 3636e5c5328SMatt Jacob "role", &role) == 0 && 3646e5c5328SMatt Jacob ((role & ~(ISP_ROLE_INITIATOR|ISP_ROLE_TARGET)) == 0)) { 3656e5c5328SMatt Jacob device_printf(dev, "setting role to 0x%x\n", role); 3666e5c5328SMatt Jacob } else { 367b9b599feSMatt Jacob #ifdef ISP_TARGET_MODE 368b9b599feSMatt Jacob role = ISP_ROLE_INITIATOR|ISP_ROLE_TARGET; 369b9b599feSMatt Jacob #else 370b9b599feSMatt Jacob role = ISP_DEFAULT_ROLES; 371b9b599feSMatt Jacob #endif 3729ba86737SMatt Jacob } 3739ba86737SMatt Jacob 3747cc0979fSDavid Malone pcs = malloc(sizeof (struct isp_pcisoftc), M_DEVBUF, M_NOWAIT | M_ZERO); 375960f6939SMatt Jacob if (pcs == NULL) { 376960f6939SMatt Jacob device_printf(dev, "cannot allocate softc\n"); 377960f6939SMatt Jacob return (ENOMEM); 378960f6939SMatt Jacob } 379960f6939SMatt Jacob 3809ba86737SMatt Jacob /* 381222bb542SMatt Jacob * Figure out which we should try first - memory mapping or i/o mapping? 382222bb542SMatt Jacob */ 38356aef503SMatt Jacob #ifdef __alpha__ 384960f6939SMatt Jacob m1 = PCIM_CMD_MEMEN; 385960f6939SMatt Jacob m2 = PCIM_CMD_PORTEN; 386222bb542SMatt Jacob #else 387960f6939SMatt Jacob m1 = PCIM_CMD_PORTEN; 388960f6939SMatt Jacob m2 = PCIM_CMD_MEMEN; 389222bb542SMatt Jacob #endif 3906e5c5328SMatt Jacob 3916e5c5328SMatt Jacob tval = 0; 3926e5c5328SMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 3936e5c5328SMatt Jacob "prefer_iomap", &tval) == 0 && tval != 0) { 394960f6939SMatt Jacob m1 = PCIM_CMD_PORTEN; 395960f6939SMatt Jacob m2 = PCIM_CMD_MEMEN; 396960f6939SMatt Jacob } 3976e5c5328SMatt Jacob tval = 0; 3986e5c5328SMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 3996e5c5328SMatt Jacob "prefer_memmap", &tval) == 0 && tval != 0) { 4006e5c5328SMatt Jacob m1 = PCIM_CMD_MEMEN; 4016e5c5328SMatt Jacob m2 = PCIM_CMD_PORTEN; 402222bb542SMatt Jacob } 403222bb542SMatt Jacob 404ab6d0040SMatt Jacob linesz = PCI_DFLT_LNSZ; 405960f6939SMatt Jacob irq = regs = NULL; 406960f6939SMatt Jacob rgd = rtp = iqd = 0; 407960f6939SMatt Jacob 408960f6939SMatt Jacob cmd = pci_read_config(dev, PCIR_COMMAND, 1); 409960f6939SMatt Jacob if (cmd & m1) { 410960f6939SMatt Jacob rtp = (m1 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT; 411960f6939SMatt Jacob rgd = (m1 == PCIM_CMD_MEMEN)? MEM_MAP_REG : IO_MAP_REG; 412960f6939SMatt Jacob regs = bus_alloc_resource(dev, rtp, &rgd, 0, ~0, 1, RF_ACTIVE); 41365adb54cSMatt Jacob } 414960f6939SMatt Jacob if (regs == NULL && (cmd & m2)) { 415960f6939SMatt Jacob rtp = (m2 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT; 416960f6939SMatt Jacob rgd = (m2 == PCIM_CMD_MEMEN)? MEM_MAP_REG : IO_MAP_REG; 417960f6939SMatt Jacob regs = bus_alloc_resource(dev, rtp, &rgd, 0, ~0, 1, RF_ACTIVE); 41865adb54cSMatt Jacob } 419960f6939SMatt Jacob if (regs == NULL) { 420960f6939SMatt Jacob device_printf(dev, "unable to map any ports\n"); 421960f6939SMatt Jacob goto bad; 42265adb54cSMatt Jacob } 423222bb542SMatt Jacob if (bootverbose) 424f7dddf8aSMatt Jacob device_printf(dev, "using %s space register mapping\n", 425960f6939SMatt Jacob (rgd == IO_MAP_REG)? "I/O" : "Memory"); 426960f6939SMatt Jacob pcs->pci_dev = dev; 427960f6939SMatt Jacob pcs->pci_reg = regs; 428960f6939SMatt Jacob pcs->pci_st = rman_get_bustag(regs); 429960f6939SMatt Jacob pcs->pci_sh = rman_get_bushandle(regs); 43065adb54cSMatt Jacob 431d59bd469SMatt Jacob pcs->pci_poff[BIU_BLOCK >> _BLK_REG_SHFT] = BIU_REGS_OFF; 432d59bd469SMatt Jacob pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS_OFF; 433d59bd469SMatt Jacob pcs->pci_poff[SXP_BLOCK >> _BLK_REG_SHFT] = PCI_SXP_REGS_OFF; 434d59bd469SMatt Jacob pcs->pci_poff[RISC_BLOCK >> _BLK_REG_SHFT] = PCI_RISC_REGS_OFF; 435d59bd469SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = DMA_REGS_OFF; 436c6608df3SMatt Jacob mdvp = &mdvec; 437c6608df3SMatt Jacob basetype = ISP_HA_SCSI_UNKNOWN; 438c6608df3SMatt Jacob psize = sizeof (sdparam); 43956aef503SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP1020) { 440c6608df3SMatt Jacob mdvp = &mdvec; 441c6608df3SMatt Jacob basetype = ISP_HA_SCSI_UNKNOWN; 442c6608df3SMatt Jacob psize = sizeof (sdparam); 443d59bd469SMatt Jacob } 444960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP1080) { 445c6608df3SMatt Jacob mdvp = &mdvec_1080; 446c6608df3SMatt Jacob basetype = ISP_HA_SCSI_1080; 447c6608df3SMatt Jacob psize = sizeof (sdparam); 448c6608df3SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 449c6608df3SMatt Jacob ISP1080_DMA_REGS_OFF; 450c6608df3SMatt Jacob } 451960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP1240) { 452c6608df3SMatt Jacob mdvp = &mdvec_1080; 45322e1dc85SMatt Jacob basetype = ISP_HA_SCSI_1240; 45422e1dc85SMatt Jacob psize = 2 * sizeof (sdparam); 45522e1dc85SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 45622e1dc85SMatt Jacob ISP1080_DMA_REGS_OFF; 45722e1dc85SMatt Jacob } 458960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP1280) { 45922e1dc85SMatt Jacob mdvp = &mdvec_1080; 46022e1dc85SMatt Jacob basetype = ISP_HA_SCSI_1280; 461c6608df3SMatt Jacob psize = 2 * sizeof (sdparam); 462d59bd469SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 463d59bd469SMatt Jacob ISP1080_DMA_REGS_OFF; 464d59bd469SMatt Jacob } 465960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP12160) { 466960f6939SMatt Jacob mdvp = &mdvec_12160; 467960f6939SMatt Jacob basetype = ISP_HA_SCSI_12160; 468960f6939SMatt Jacob psize = 2 * sizeof (sdparam); 469960f6939SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 470960f6939SMatt Jacob ISP1080_DMA_REGS_OFF; 471960f6939SMatt Jacob } 472960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP2100) { 473c6608df3SMatt Jacob mdvp = &mdvec_2100; 474c6608df3SMatt Jacob basetype = ISP_HA_FC_2100; 475c6608df3SMatt Jacob psize = sizeof (fcparam); 476d59bd469SMatt Jacob pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = 477d59bd469SMatt Jacob PCI_MBOX_REGS2100_OFF; 478960f6939SMatt Jacob if (pci_get_revid(dev) < 3) { 479ab6d0040SMatt Jacob /* 480ab6d0040SMatt Jacob * XXX: Need to get the actual revision 481ab6d0040SMatt Jacob * XXX: number of the 2100 FB. At any rate, 482ab6d0040SMatt Jacob * XXX: lower cache line size for early revision 483ab6d0040SMatt Jacob * XXX; boards. 484ab6d0040SMatt Jacob */ 485ab6d0040SMatt Jacob linesz = 1; 486ab6d0040SMatt Jacob } 48765adb54cSMatt Jacob } 488960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP2200) { 489222bb542SMatt Jacob mdvp = &mdvec_2200; 490222bb542SMatt Jacob basetype = ISP_HA_FC_2200; 491222bb542SMatt Jacob psize = sizeof (fcparam); 492222bb542SMatt Jacob pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = 493222bb542SMatt Jacob PCI_MBOX_REGS2100_OFF; 494222bb542SMatt Jacob } 49575c1e828SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP2300) { 496126ec864SMatt Jacob mdvp = &mdvec_2300; 497126ec864SMatt Jacob basetype = ISP_HA_FC_2300; 498126ec864SMatt Jacob psize = sizeof (fcparam); 499126ec864SMatt Jacob pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = 500126ec864SMatt Jacob PCI_MBOX_REGS2300_OFF; 501126ec864SMatt Jacob } 50275c1e828SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP2312) { 50375c1e828SMatt Jacob mdvp = &mdvec_2300; 50475c1e828SMatt Jacob basetype = ISP_HA_FC_2312; 50575c1e828SMatt Jacob psize = sizeof (fcparam); 50675c1e828SMatt Jacob pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = 50775c1e828SMatt Jacob PCI_MBOX_REGS2300_OFF; 50875c1e828SMatt Jacob } 509c6608df3SMatt Jacob isp = &pcs->pci_isp; 5107cc0979fSDavid Malone isp->isp_param = malloc(psize, M_DEVBUF, M_NOWAIT | M_ZERO); 511c6608df3SMatt Jacob if (isp->isp_param == NULL) { 512960f6939SMatt Jacob device_printf(dev, "cannot allocate parameter data\n"); 513960f6939SMatt Jacob goto bad; 514c6608df3SMatt Jacob } 515c6608df3SMatt Jacob isp->isp_mdvec = mdvp; 516c6608df3SMatt Jacob isp->isp_type = basetype; 517960f6939SMatt Jacob isp->isp_revision = pci_get_revid(dev); 518b9b599feSMatt Jacob isp->isp_role = role; 5196e5c5328SMatt Jacob isp->isp_dev = dev; 52065adb54cSMatt Jacob 52156aef503SMatt Jacob /* 52256aef503SMatt Jacob * Try and find firmware for this device. 52356aef503SMatt Jacob */ 52456aef503SMatt Jacob 52556aef503SMatt Jacob if (isp_get_firmware_p) { 52656aef503SMatt Jacob int device = (int) pci_get_device(dev); 52756aef503SMatt Jacob #ifdef ISP_TARGET_MODE 52856aef503SMatt Jacob (*isp_get_firmware_p)(0, 1, device, &mdvp->dv_ispfw); 52956aef503SMatt Jacob #else 53056aef503SMatt Jacob (*isp_get_firmware_p)(0, 0, device, &mdvp->dv_ispfw); 53156aef503SMatt Jacob #endif 53256aef503SMatt Jacob } 53356aef503SMatt Jacob 53456aef503SMatt Jacob /* 535d951bbcaSMatt Jacob * Make sure that SERR, PERR, WRITE INVALIDATE and BUSMASTER 536d951bbcaSMatt Jacob * are set. 537d951bbcaSMatt Jacob */ 538960f6939SMatt Jacob cmd |= PCIM_CMD_SEREN | PCIM_CMD_PERRESPEN | 539960f6939SMatt Jacob PCIM_CMD_BUSMASTEREN | PCIM_CMD_INVEN; 54075c1e828SMatt Jacob if (IS_2300(isp)) { /* per QLogic errata */ 54175c1e828SMatt Jacob cmd &= ~PCIM_CMD_INVEN; 54275c1e828SMatt Jacob } 543fc087171SMatt Jacob if (IS_23XX(isp)) { 544fc087171SMatt Jacob /* 545fc087171SMatt Jacob * Can't tell if ROM will hang on 'ABOUT FIRMWARE' command. 546fc087171SMatt Jacob */ 547fc087171SMatt Jacob isp->isp_touched = 1; 548fc087171SMatt Jacob 549fc087171SMatt Jacob } 550960f6939SMatt Jacob pci_write_config(dev, PCIR_COMMAND, cmd, 1); 551ab6d0040SMatt Jacob 552d951bbcaSMatt Jacob /* 553222bb542SMatt Jacob * Make sure the Cache Line Size register is set sensibly. 554d951bbcaSMatt Jacob */ 555960f6939SMatt Jacob data = pci_read_config(dev, PCIR_CACHELNSZ, 1); 556ab6d0040SMatt Jacob if (data != linesz) { 557d951bbcaSMatt Jacob data = PCI_DFLT_LNSZ; 558d02373f1SMatt Jacob isp_prt(isp, ISP_LOGCONFIG, "set PCI line size to %d", data); 559960f6939SMatt Jacob pci_write_config(dev, PCIR_CACHELNSZ, data, 1); 560d951bbcaSMatt Jacob } 561ab6d0040SMatt Jacob 562d951bbcaSMatt Jacob /* 563d951bbcaSMatt Jacob * Make sure the Latency Timer is sane. 564d951bbcaSMatt Jacob */ 565960f6939SMatt Jacob data = pci_read_config(dev, PCIR_LATTIMER, 1); 566d951bbcaSMatt Jacob if (data < PCI_DFLT_LTNCY) { 567d951bbcaSMatt Jacob data = PCI_DFLT_LTNCY; 568d02373f1SMatt Jacob isp_prt(isp, ISP_LOGCONFIG, "set PCI latency to %d", data); 569960f6939SMatt Jacob pci_write_config(dev, PCIR_LATTIMER, data, 1); 570d951bbcaSMatt Jacob } 571ab6d0040SMatt Jacob 572ab6d0040SMatt Jacob /* 573ab6d0040SMatt Jacob * Make sure we've disabled the ROM. 574ab6d0040SMatt Jacob */ 575960f6939SMatt Jacob data = pci_read_config(dev, PCIR_ROMADDR, 4); 576ab6d0040SMatt Jacob data &= ~1; 577960f6939SMatt Jacob pci_write_config(dev, PCIR_ROMADDR, data, 4); 57805fbcbb0SMatt Jacob 579960f6939SMatt Jacob iqd = 0; 580960f6939SMatt Jacob irq = bus_alloc_resource(dev, SYS_RES_IRQ, &iqd, 0, ~0, 581960f6939SMatt Jacob 1, RF_ACTIVE | RF_SHAREABLE); 582960f6939SMatt Jacob if (irq == NULL) { 583960f6939SMatt Jacob device_printf(dev, "could not allocate interrupt\n"); 584960f6939SMatt Jacob goto bad; 585960f6939SMatt Jacob } 586960f6939SMatt Jacob 5876e5c5328SMatt Jacob tval = 0; 5886e5c5328SMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 5896e5c5328SMatt Jacob "fwload_disable", &tval) == 0 && tval != 0) { 590222bb542SMatt Jacob isp->isp_confopts |= ISP_CFG_NORELOAD; 591222bb542SMatt Jacob } 5926e5c5328SMatt Jacob tval = 0; 5936e5c5328SMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 5946e5c5328SMatt Jacob "ignore_nvram", &tval) == 0 && tval != 0) { 595222bb542SMatt Jacob isp->isp_confopts |= ISP_CFG_NONVRAM; 596222bb542SMatt Jacob } 5976e5c5328SMatt Jacob tval = 0; 5986e5c5328SMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 5996e5c5328SMatt Jacob "fullduplex", &tval) == 0 && tval != 0) { 600222bb542SMatt Jacob isp->isp_confopts |= ISP_CFG_FULL_DUPLEX; 601222bb542SMatt Jacob } 602d134aa0bSMatt Jacob #ifdef ISP_FW_CRASH_DUMP 603d134aa0bSMatt Jacob tval = 0; 604d134aa0bSMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 605d134aa0bSMatt Jacob "fw_dump_enable", &tval) == 0 && tval != 0) { 606d134aa0bSMatt Jacob size_t amt = 0; 607d134aa0bSMatt Jacob if (IS_2200(isp)) { 608d134aa0bSMatt Jacob amt = QLA2200_RISC_IMAGE_DUMP_SIZE; 609d134aa0bSMatt Jacob } else if (IS_23XX(isp)) { 610d134aa0bSMatt Jacob amt = QLA2300_RISC_IMAGE_DUMP_SIZE; 611d134aa0bSMatt Jacob } 612d134aa0bSMatt Jacob if (amt) { 613d134aa0bSMatt Jacob FCPARAM(isp)->isp_dump_data = 614d134aa0bSMatt Jacob malloc(amt, M_DEVBUF, M_WAITOK | M_ZERO); 615d134aa0bSMatt Jacob } else { 616d134aa0bSMatt Jacob device_printf(dev, 617d134aa0bSMatt Jacob "f/w crash dumps not supported for this model\n"); 618d134aa0bSMatt Jacob } 619d134aa0bSMatt Jacob } 620d134aa0bSMatt Jacob #endif 621222bb542SMatt Jacob 6226e5c5328SMatt Jacob sptr = 0; 6236e5c5328SMatt Jacob if (resource_string_value(device_get_name(dev), device_get_unit(dev), 624559a1ad2SMatt Jacob "topology", (const char **) &sptr) == 0 && sptr != 0) { 6256e5c5328SMatt Jacob if (strcmp(sptr, "lport") == 0) { 6266e5c5328SMatt Jacob isp->isp_confopts |= ISP_CFG_LPORT; 6276e5c5328SMatt Jacob } else if (strcmp(sptr, "nport") == 0) { 6286e5c5328SMatt Jacob isp->isp_confopts |= ISP_CFG_NPORT; 6296e5c5328SMatt Jacob } else if (strcmp(sptr, "lport-only") == 0) { 6306e5c5328SMatt Jacob isp->isp_confopts |= ISP_CFG_LPORT_ONLY; 6316e5c5328SMatt Jacob } else if (strcmp(sptr, "nport-only") == 0) { 6326e5c5328SMatt Jacob isp->isp_confopts |= ISP_CFG_NPORT_ONLY; 6339637d68cSMatt Jacob } 6346e5c5328SMatt Jacob } 6356e5c5328SMatt Jacob 6369637d68cSMatt Jacob /* 6376e5c5328SMatt Jacob * Because the resource_*_value functions can neither return 6386e5c5328SMatt Jacob * 64 bit integer values, nor can they be directly coerced 6396e5c5328SMatt Jacob * to interpret the right hand side of the assignment as 6406e5c5328SMatt Jacob * you want them to interpret it, we have to force WWN 6416e5c5328SMatt Jacob * hint replacement to specify WWN strings with a leading 6426e5c5328SMatt Jacob * 'w' (e..g w50000000aaaa0001). Sigh. 6439637d68cSMatt Jacob */ 6446e5c5328SMatt Jacob sptr = 0; 6456e5c5328SMatt Jacob tval = resource_string_value(device_get_name(dev), device_get_unit(dev), 646559a1ad2SMatt Jacob "portwwn", (const char **) &sptr); 6476e5c5328SMatt Jacob if (tval == 0 && sptr != 0 && *sptr++ == 'w') { 6486e5c5328SMatt Jacob char *eptr = 0; 6496e5c5328SMatt Jacob isp->isp_osinfo.default_port_wwn = strtouq(sptr, &eptr, 16); 6506e5c5328SMatt Jacob if (eptr < sptr + 16 || isp->isp_osinfo.default_port_wwn == 0) { 6516e5c5328SMatt Jacob device_printf(dev, "mangled portwwn hint '%s'\n", sptr); 6526e5c5328SMatt Jacob isp->isp_osinfo.default_port_wwn = 0; 6539637d68cSMatt Jacob } else { 6543f02619fSMatt Jacob isp->isp_confopts |= ISP_CFG_OWNWWPN; 655222bb542SMatt Jacob } 6566e5c5328SMatt Jacob } 6576e5c5328SMatt Jacob if (isp->isp_osinfo.default_port_wwn == 0) { 6586e5c5328SMatt Jacob isp->isp_osinfo.default_port_wwn = 0x400000007F000009ull; 6596e5c5328SMatt Jacob } 6606e5c5328SMatt Jacob 6616e5c5328SMatt Jacob sptr = 0; 6626e5c5328SMatt Jacob tval = resource_string_value(device_get_name(dev), device_get_unit(dev), 663559a1ad2SMatt Jacob "nodewwn", (const char **) &sptr); 6646e5c5328SMatt Jacob if (tval == 0 && sptr != 0 && *sptr++ == 'w') { 6656e5c5328SMatt Jacob char *eptr = 0; 6666e5c5328SMatt Jacob isp->isp_osinfo.default_node_wwn = strtouq(sptr, &eptr, 16); 6676e5c5328SMatt Jacob if (eptr < sptr + 16 || isp->isp_osinfo.default_node_wwn == 0) { 6686e5c5328SMatt Jacob device_printf(dev, "mangled nodewwn hint '%s'\n", sptr); 6696e5c5328SMatt Jacob isp->isp_osinfo.default_node_wwn = 0; 6706e5c5328SMatt Jacob } else { 6713f02619fSMatt Jacob isp->isp_confopts |= ISP_CFG_OWNWWNN; 6726e5c5328SMatt Jacob } 6736e5c5328SMatt Jacob } 6746e5c5328SMatt Jacob if (isp->isp_osinfo.default_node_wwn == 0) { 6756e5c5328SMatt Jacob isp->isp_osinfo.default_node_wwn = 0x400000007F000009ull; 6766e5c5328SMatt Jacob } 6776e5c5328SMatt Jacob 678ed753e82SMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 679ed753e82SMatt Jacob "iid", &tval) == 0) { 680ed753e82SMatt Jacob isp->isp_osinfo.default_id = tval; 681ed753e82SMatt Jacob isp->isp_confopts |= ISP_CFG_OWNLOOPID; 682ed753e82SMatt Jacob } 683ed753e82SMatt Jacob if (isp->isp_osinfo.default_id == 0) { 684ed753e82SMatt Jacob if (IS_FC(isp)) { 685ed753e82SMatt Jacob isp->isp_osinfo.default_id = 109; 686ed753e82SMatt Jacob } else { 687ed753e82SMatt Jacob isp->isp_osinfo.default_id = 7; 688ed753e82SMatt Jacob } 689ed753e82SMatt Jacob } 690ed753e82SMatt Jacob 691ed753e82SMatt Jacob isp_debug = 0; 692d02373f1SMatt Jacob isp_debug = 0; 6936e5c5328SMatt Jacob (void) resource_int_value(device_get_name(dev), device_get_unit(dev), 6946e5c5328SMatt Jacob "debug", &isp_debug); 695f09b1922SMatt Jacob 696f09b1922SMatt Jacob /* Make sure the lock is set up. */ 6976008862bSJohn Baldwin mtx_init(&isp->isp_osinfo.lock, "isp", NULL, MTX_DEF); 698f09b1922SMatt Jacob locksetup++; 699f09b1922SMatt Jacob 7005d571944SMatt Jacob #ifdef ISP_SMPLOCK 7015d571944SMatt Jacob #define INTR_FLAGS INTR_TYPE_CAM | INTR_MPSAFE | INTR_ENTROPY 702f09b1922SMatt Jacob #else 7035d571944SMatt Jacob #define INTR_FLAGS INTR_TYPE_CAM | INTR_ENTROPY 7045d571944SMatt Jacob #endif 7055d571944SMatt Jacob if (bus_setup_intr(dev, irq, INTR_FLAGS, isp_pci_intr, isp, &pcs->ih)) { 706f09b1922SMatt Jacob device_printf(dev, "could not setup interrupt\n"); 707f09b1922SMatt Jacob goto bad; 708f09b1922SMatt Jacob } 709960f6939SMatt Jacob 71005fbcbb0SMatt Jacob /* 711d02373f1SMatt Jacob * Set up logging levels. 712d02373f1SMatt Jacob */ 713d02373f1SMatt Jacob if (isp_debug) { 714d02373f1SMatt Jacob isp->isp_dblev = isp_debug; 715d02373f1SMatt Jacob } else { 716d02373f1SMatt Jacob isp->isp_dblev = ISP_LOGWARN|ISP_LOGERR; 717d02373f1SMatt Jacob } 718d02373f1SMatt Jacob if (bootverbose) 719f7dddf8aSMatt Jacob isp->isp_dblev |= ISP_LOGCONFIG|ISP_LOGINFO; 720d02373f1SMatt Jacob 721d02373f1SMatt Jacob /* 72275c1e828SMatt Jacob * Last minute checks... 72375c1e828SMatt Jacob */ 72475c1e828SMatt Jacob if (IS_2312(isp)) { 72575c1e828SMatt Jacob isp->isp_port = pci_get_function(dev); 72675c1e828SMatt Jacob } 72775c1e828SMatt Jacob 72875c1e828SMatt Jacob /* 72905fbcbb0SMatt Jacob * Make sure we're in reset state. 73005fbcbb0SMatt Jacob */ 7313395b056SMatt Jacob ISP_LOCK(isp); 73265adb54cSMatt Jacob isp_reset(isp); 73365adb54cSMatt Jacob if (isp->isp_state != ISP_RESETSTATE) { 7343395b056SMatt Jacob ISP_UNLOCK(isp); 735960f6939SMatt Jacob goto bad; 73665adb54cSMatt Jacob } 73765adb54cSMatt Jacob isp_init(isp); 738b9b599feSMatt Jacob if (isp->isp_role != ISP_ROLE_NONE && isp->isp_state != ISP_INITSTATE) { 73965adb54cSMatt Jacob isp_uninit(isp); 7403395b056SMatt Jacob ISP_UNLOCK(isp); 741960f6939SMatt Jacob goto bad; 742d59bd469SMatt Jacob } 74365adb54cSMatt Jacob isp_attach(isp); 744b9b599feSMatt Jacob if (isp->isp_role != ISP_ROLE_NONE && isp->isp_state != ISP_RUNSTATE) { 74565adb54cSMatt Jacob isp_uninit(isp); 7463395b056SMatt Jacob ISP_UNLOCK(isp); 747960f6939SMatt Jacob goto bad; 748960f6939SMatt Jacob } 74956aef503SMatt Jacob /* 75056aef503SMatt Jacob * XXXX: Here is where we might unload the f/w module 75156aef503SMatt Jacob * XXXX: (or decrease the reference count to it). 75256aef503SMatt Jacob */ 7533395b056SMatt Jacob ISP_UNLOCK(isp); 754960f6939SMatt Jacob return (0); 755960f6939SMatt Jacob 756960f6939SMatt Jacob bad: 757960f6939SMatt Jacob 758960f6939SMatt Jacob if (pcs && pcs->ih) { 759960f6939SMatt Jacob (void) bus_teardown_intr(dev, irq, pcs->ih); 760960f6939SMatt Jacob } 761960f6939SMatt Jacob 7623395b056SMatt Jacob if (locksetup && isp) { 7633395b056SMatt Jacob mtx_destroy(&isp->isp_osinfo.lock); 7643395b056SMatt Jacob } 7653395b056SMatt Jacob 766960f6939SMatt Jacob if (irq) { 767960f6939SMatt Jacob (void) bus_release_resource(dev, SYS_RES_IRQ, iqd, irq); 768960f6939SMatt Jacob } 7693395b056SMatt Jacob 7703395b056SMatt Jacob 771960f6939SMatt Jacob if (regs) { 772960f6939SMatt Jacob (void) bus_release_resource(dev, rtp, rgd, regs); 773960f6939SMatt Jacob } 7743395b056SMatt Jacob 775960f6939SMatt Jacob if (pcs) { 776960f6939SMatt Jacob if (pcs->pci_isp.isp_param) 777960f6939SMatt Jacob free(pcs->pci_isp.isp_param, M_DEVBUF); 77865adb54cSMatt Jacob free(pcs, M_DEVBUF); 77965adb54cSMatt Jacob } 7803395b056SMatt Jacob 78156aef503SMatt Jacob /* 78256aef503SMatt Jacob * XXXX: Here is where we might unload the f/w module 78356aef503SMatt Jacob * XXXX: (or decrease the reference count to it). 78456aef503SMatt Jacob */ 785960f6939SMatt Jacob return (ENXIO); 78665adb54cSMatt Jacob } 78765adb54cSMatt Jacob 788f09b1922SMatt Jacob static void 789f09b1922SMatt Jacob isp_pci_intr(void *arg) 790f09b1922SMatt Jacob { 791f09b1922SMatt Jacob struct ispsoftc *isp = arg; 792126ec864SMatt Jacob u_int16_t isr, sema, mbox; 793126ec864SMatt Jacob 794f09b1922SMatt Jacob ISP_LOCK(isp); 795126ec864SMatt Jacob isp->isp_intcnt++; 796126ec864SMatt Jacob if (ISP_READ_ISR(isp, &isr, &sema, &mbox) == 0) { 797126ec864SMatt Jacob isp->isp_intbogus++; 798126ec864SMatt Jacob } else { 799b96934e8SMatt Jacob int iok = isp->isp_osinfo.intsok; 800b96934e8SMatt Jacob isp->isp_osinfo.intsok = 0; 801126ec864SMatt Jacob isp_intr(isp, isr, sema, mbox); 802b96934e8SMatt Jacob isp->isp_osinfo.intsok = iok; 803126ec864SMatt Jacob } 804f09b1922SMatt Jacob ISP_UNLOCK(isp); 805f09b1922SMatt Jacob } 806f09b1922SMatt Jacob 807126ec864SMatt Jacob 808126ec864SMatt Jacob #define IspVirt2Off(a, x) \ 809126ec864SMatt Jacob (((struct isp_pcisoftc *)a)->pci_poff[((x) & _BLK_REG_MASK) >> \ 810126ec864SMatt Jacob _BLK_REG_SHFT] + ((x) & 0xff)) 811126ec864SMatt Jacob 812126ec864SMatt Jacob #define BXR2(pcs, off) \ 813126ec864SMatt Jacob bus_space_read_2(pcs->pci_st, pcs->pci_sh, off) 814126ec864SMatt Jacob #define BXW2(pcs, off, v) \ 815126ec864SMatt Jacob bus_space_write_2(pcs->pci_st, pcs->pci_sh, off, v) 816126ec864SMatt Jacob 817126ec864SMatt Jacob 818126ec864SMatt Jacob static INLINE int 819126ec864SMatt Jacob isp_pci_rd_debounced(struct ispsoftc *isp, int off, u_int16_t *rp) 820126ec864SMatt Jacob { 821126ec864SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 822126ec864SMatt Jacob u_int16_t val0, val1; 823126ec864SMatt Jacob int i = 0; 824126ec864SMatt Jacob 825126ec864SMatt Jacob do { 826126ec864SMatt Jacob val0 = BXR2(pcs, IspVirt2Off(isp, off)); 827126ec864SMatt Jacob val1 = BXR2(pcs, IspVirt2Off(isp, off)); 828126ec864SMatt Jacob } while (val0 != val1 && ++i < 1000); 829126ec864SMatt Jacob if (val0 != val1) { 830126ec864SMatt Jacob return (1); 831126ec864SMatt Jacob } 832126ec864SMatt Jacob *rp = val0; 833126ec864SMatt Jacob return (0); 834126ec864SMatt Jacob } 835126ec864SMatt Jacob 836126ec864SMatt Jacob static int 837126ec864SMatt Jacob isp_pci_rd_isr(struct ispsoftc *isp, u_int16_t *isrp, 838126ec864SMatt Jacob u_int16_t *semap, u_int16_t *mbp) 839126ec864SMatt Jacob { 840126ec864SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 841126ec864SMatt Jacob u_int16_t isr, sema; 842126ec864SMatt Jacob 843126ec864SMatt Jacob if (IS_2100(isp)) { 844126ec864SMatt Jacob if (isp_pci_rd_debounced(isp, BIU_ISR, &isr)) { 845126ec864SMatt Jacob return (0); 846126ec864SMatt Jacob } 847126ec864SMatt Jacob if (isp_pci_rd_debounced(isp, BIU_SEMA, &sema)) { 848126ec864SMatt Jacob return (0); 849126ec864SMatt Jacob } 850126ec864SMatt Jacob } else { 851126ec864SMatt Jacob isr = BXR2(pcs, IspVirt2Off(isp, BIU_ISR)); 852126ec864SMatt Jacob sema = BXR2(pcs, IspVirt2Off(isp, BIU_SEMA)); 853126ec864SMatt Jacob } 854126ec864SMatt Jacob isp_prt(isp, ISP_LOGDEBUG3, "ISR 0x%x SEMA 0x%x", isr, sema); 855126ec864SMatt Jacob isr &= INT_PENDING_MASK(isp); 856126ec864SMatt Jacob sema &= BIU_SEMA_LOCK; 857126ec864SMatt Jacob if (isr == 0 && sema == 0) { 858126ec864SMatt Jacob return (0); 859126ec864SMatt Jacob } 860126ec864SMatt Jacob *isrp = isr; 861126ec864SMatt Jacob if ((*semap = sema) != 0) { 862126ec864SMatt Jacob if (IS_2100(isp)) { 863126ec864SMatt Jacob if (isp_pci_rd_debounced(isp, OUTMAILBOX0, mbp)) { 864126ec864SMatt Jacob return (0); 865126ec864SMatt Jacob } 866126ec864SMatt Jacob } else { 867126ec864SMatt Jacob *mbp = BXR2(pcs, IspVirt2Off(isp, OUTMAILBOX0)); 868126ec864SMatt Jacob } 869126ec864SMatt Jacob } 870126ec864SMatt Jacob return (1); 871126ec864SMatt Jacob } 872126ec864SMatt Jacob 873126ec864SMatt Jacob static int 874126ec864SMatt Jacob isp_pci_rd_isr_2300(struct ispsoftc *isp, u_int16_t *isrp, 875126ec864SMatt Jacob u_int16_t *semap, u_int16_t *mbox0p) 876126ec864SMatt Jacob { 877126ec864SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 878126ec864SMatt Jacob u_int32_t r2hisr; 879126ec864SMatt Jacob 8803bd40330SMatt Jacob if (!(BXR2(pcs, IspVirt2Off(isp, BIU_ISR) & BIU2100_ISR_RISC_INT))) { 8813bd40330SMatt Jacob *isrp = 0; 882db4fa023SMatt Jacob return (0); 8833bd40330SMatt Jacob } 884126ec864SMatt Jacob r2hisr = bus_space_read_4(pcs->pci_st, pcs->pci_sh, 885126ec864SMatt Jacob IspVirt2Off(pcs, BIU_R2HSTSLO)); 886126ec864SMatt Jacob isp_prt(isp, ISP_LOGDEBUG3, "RISC2HOST ISR 0x%x", r2hisr); 887126ec864SMatt Jacob if ((r2hisr & BIU_R2HST_INTR) == 0) { 888126ec864SMatt Jacob *isrp = 0; 889126ec864SMatt Jacob return (0); 890126ec864SMatt Jacob } 891126ec864SMatt Jacob switch (r2hisr & BIU_R2HST_ISTAT_MASK) { 892126ec864SMatt Jacob case ISPR2HST_ROM_MBX_OK: 893126ec864SMatt Jacob case ISPR2HST_ROM_MBX_FAIL: 894126ec864SMatt Jacob case ISPR2HST_MBX_OK: 895126ec864SMatt Jacob case ISPR2HST_MBX_FAIL: 896126ec864SMatt Jacob case ISPR2HST_ASYNC_EVENT: 89775c1e828SMatt Jacob case ISPR2HST_RIO_16: 898126ec864SMatt Jacob case ISPR2HST_FPOST: 899126ec864SMatt Jacob case ISPR2HST_FPOST_CTIO: 900126ec864SMatt Jacob *isrp = r2hisr & 0xffff; 901126ec864SMatt Jacob *mbox0p = (r2hisr >> 16); 902126ec864SMatt Jacob *semap = 1; 903126ec864SMatt Jacob return (1); 904126ec864SMatt Jacob case ISPR2HST_RSPQ_UPDATE: 905126ec864SMatt Jacob *isrp = r2hisr & 0xffff; 906126ec864SMatt Jacob *mbox0p = 0; 907126ec864SMatt Jacob *semap = 0; 908126ec864SMatt Jacob return (1); 909126ec864SMatt Jacob default: 910126ec864SMatt Jacob return (0); 911126ec864SMatt Jacob } 912126ec864SMatt Jacob } 913126ec864SMatt Jacob 91465adb54cSMatt Jacob static u_int16_t 915126ec864SMatt Jacob isp_pci_rd_reg(struct ispsoftc *isp, int regoff) 91665adb54cSMatt Jacob { 91765adb54cSMatt Jacob u_int16_t rv; 91865adb54cSMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 919126ec864SMatt Jacob int oldconf = 0; 92065adb54cSMatt Jacob 921d59bd469SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 92265adb54cSMatt Jacob /* 92365adb54cSMatt Jacob * We will assume that someone has paused the RISC processor. 92465adb54cSMatt Jacob */ 925126ec864SMatt Jacob oldconf = BXR2(pcs, IspVirt2Off(isp, BIU_CONF1)); 926126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), 927126ec864SMatt Jacob oldconf | BIU_PCI_CONF1_SXP); 92865adb54cSMatt Jacob } 929126ec864SMatt Jacob rv = BXR2(pcs, IspVirt2Off(isp, regoff)); 930d59bd469SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 931126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), oldconf); 93265adb54cSMatt Jacob } 93365adb54cSMatt Jacob return (rv); 93465adb54cSMatt Jacob } 93565adb54cSMatt Jacob 93665adb54cSMatt Jacob static void 937126ec864SMatt Jacob isp_pci_wr_reg(struct ispsoftc *isp, int regoff, u_int16_t val) 93865adb54cSMatt Jacob { 93965adb54cSMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 940126ec864SMatt Jacob int oldconf = 0; 941d59bd469SMatt Jacob 942d59bd469SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 94365adb54cSMatt Jacob /* 94465adb54cSMatt Jacob * We will assume that someone has paused the RISC processor. 94565adb54cSMatt Jacob */ 946126ec864SMatt Jacob oldconf = BXR2(pcs, IspVirt2Off(isp, BIU_CONF1)); 947126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), 948126ec864SMatt Jacob oldconf | BIU_PCI_CONF1_SXP); 94965adb54cSMatt Jacob } 950126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, regoff), val); 951d59bd469SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 952126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), oldconf); 95365adb54cSMatt Jacob } 95465adb54cSMatt Jacob } 95565adb54cSMatt Jacob 956d59bd469SMatt Jacob static u_int16_t 957126ec864SMatt Jacob isp_pci_rd_reg_1080(struct ispsoftc *isp, int regoff) 958d59bd469SMatt Jacob { 95922e1dc85SMatt Jacob u_int16_t rv, oc = 0; 960d59bd469SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 961d59bd469SMatt Jacob 96222e1dc85SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK || 96322e1dc85SMatt Jacob (regoff & _BLK_REG_MASK) == (SXP_BLOCK|SXP_BANK1_SELECT)) { 96422e1dc85SMatt Jacob u_int16_t tc; 965d59bd469SMatt Jacob /* 966d59bd469SMatt Jacob * We will assume that someone has paused the RISC processor. 967d59bd469SMatt Jacob */ 968126ec864SMatt Jacob oc = BXR2(pcs, IspVirt2Off(isp, BIU_CONF1)); 96922e1dc85SMatt Jacob tc = oc & ~BIU_PCI1080_CONF1_DMA; 97022e1dc85SMatt Jacob if (regoff & SXP_BANK1_SELECT) 97122e1dc85SMatt Jacob tc |= BIU_PCI1080_CONF1_SXP1; 97222e1dc85SMatt Jacob else 97322e1dc85SMatt Jacob tc |= BIU_PCI1080_CONF1_SXP0; 974126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), tc); 975d59bd469SMatt Jacob } else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) { 976126ec864SMatt Jacob oc = BXR2(pcs, IspVirt2Off(isp, BIU_CONF1)); 977126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), 978126ec864SMatt Jacob oc | BIU_PCI1080_CONF1_DMA); 979d59bd469SMatt Jacob } 980126ec864SMatt Jacob rv = BXR2(pcs, IspVirt2Off(isp, regoff)); 98122e1dc85SMatt Jacob if (oc) { 982126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), oc); 983d59bd469SMatt Jacob } 984d59bd469SMatt Jacob return (rv); 985d59bd469SMatt Jacob } 986d59bd469SMatt Jacob 987d59bd469SMatt Jacob static void 988126ec864SMatt Jacob isp_pci_wr_reg_1080(struct ispsoftc *isp, int regoff, u_int16_t val) 989d59bd469SMatt Jacob { 990d59bd469SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 991126ec864SMatt Jacob int oc = 0; 992d59bd469SMatt Jacob 99322e1dc85SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK || 99422e1dc85SMatt Jacob (regoff & _BLK_REG_MASK) == (SXP_BLOCK|SXP_BANK1_SELECT)) { 99522e1dc85SMatt Jacob u_int16_t tc; 996d59bd469SMatt Jacob /* 997d59bd469SMatt Jacob * We will assume that someone has paused the RISC processor. 998d59bd469SMatt Jacob */ 999126ec864SMatt Jacob oc = BXR2(pcs, IspVirt2Off(isp, BIU_CONF1)); 100022e1dc85SMatt Jacob tc = oc & ~BIU_PCI1080_CONF1_DMA; 100122e1dc85SMatt Jacob if (regoff & SXP_BANK1_SELECT) 100222e1dc85SMatt Jacob tc |= BIU_PCI1080_CONF1_SXP1; 100322e1dc85SMatt Jacob else 100422e1dc85SMatt Jacob tc |= BIU_PCI1080_CONF1_SXP0; 1005126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), tc); 1006d59bd469SMatt Jacob } else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) { 1007126ec864SMatt Jacob oc = BXR2(pcs, IspVirt2Off(isp, BIU_CONF1)); 1008126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), 1009126ec864SMatt Jacob oc | BIU_PCI1080_CONF1_DMA); 1010d59bd469SMatt Jacob } 1011126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, regoff), val); 101222e1dc85SMatt Jacob if (oc) { 1013126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), oc); 1014d59bd469SMatt Jacob } 1015d59bd469SMatt Jacob } 1016d59bd469SMatt Jacob 1017d720e6d5SJustin T. Gibbs 1018222bb542SMatt Jacob struct imush { 1019222bb542SMatt Jacob struct ispsoftc *isp; 1020222bb542SMatt Jacob int error; 1021222bb542SMatt Jacob }; 1022222bb542SMatt Jacob 10231923f739SMatt Jacob static void imc(void *, bus_dma_segment_t *, int, int); 10241923f739SMatt Jacob 1025d720e6d5SJustin T. Gibbs static void 10261923f739SMatt Jacob imc(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1027d720e6d5SJustin T. Gibbs { 1028222bb542SMatt Jacob struct imush *imushp = (struct imush *) arg; 1029222bb542SMatt Jacob if (error) { 1030222bb542SMatt Jacob imushp->error = error; 1031222bb542SMatt Jacob } else { 10321923f739SMatt Jacob struct ispsoftc *isp =imushp->isp; 10331923f739SMatt Jacob bus_addr_t addr = segs->ds_addr; 10341923f739SMatt Jacob 10351923f739SMatt Jacob isp->isp_rquest_dma = addr; 10361923f739SMatt Jacob addr += ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)); 10371923f739SMatt Jacob isp->isp_result_dma = addr; 10381923f739SMatt Jacob if (IS_FC(isp)) { 10391923f739SMatt Jacob addr += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)); 10401923f739SMatt Jacob FCPARAM(isp)->isp_scdma = addr; 10411923f739SMatt Jacob } 1042222bb542SMatt Jacob } 1043d720e6d5SJustin T. Gibbs } 1044d720e6d5SJustin T. Gibbs 1045029f13c6SMatt Jacob /* 1046029f13c6SMatt Jacob * Should be BUS_SPACE_MAXSIZE, but MAXPHYS is larger than BUS_SPACE_MAXSIZE 1047029f13c6SMatt Jacob */ 1048029f13c6SMatt Jacob #define ISP_NSEGS ((MAXPHYS / PAGE_SIZE) + 1) 1049d720e6d5SJustin T. Gibbs 1050d720e6d5SJustin T. Gibbs static int 105117e318c6SMatt Jacob isp_pci_mbxdma(struct ispsoftc *isp) 1052d720e6d5SJustin T. Gibbs { 10531923f739SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *)isp; 1054d720e6d5SJustin T. Gibbs caddr_t base; 1055d720e6d5SJustin T. Gibbs u_int32_t len; 10561923f739SMatt Jacob int i, error, ns; 10571923f739SMatt Jacob bus_size_t bl; 1058222bb542SMatt Jacob struct imush im; 1059222bb542SMatt Jacob 1060a95ae193SMatt Jacob /* 1061a95ae193SMatt Jacob * Already been here? If so, leave... 1062a95ae193SMatt Jacob */ 1063a95ae193SMatt Jacob if (isp->isp_rquest) { 1064a95ae193SMatt Jacob return (0); 1065a95ae193SMatt Jacob } 1066a95ae193SMatt Jacob 10671923f739SMatt Jacob if (IS_ULTRA2(isp) || IS_FC(isp) || IS_1240(isp)) { 10681923f739SMatt Jacob bl = BUS_SPACE_UNRESTRICTED; 10691923f739SMatt Jacob } else { 10701923f739SMatt Jacob bl = BUS_SPACE_MAXADDR_24BIT; 10711923f739SMatt Jacob } 10721923f739SMatt Jacob 10731923f739SMatt Jacob if (bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR, 10741923f739SMatt Jacob BUS_SPACE_MAXADDR, NULL, NULL, BUS_SPACE_MAXSIZE, 10751923f739SMatt Jacob ISP_NSEGS, bl, 0, &pcs->dmat)) { 10761923f739SMatt Jacob isp_prt(isp, ISP_LOGERR, "could not create master dma tag"); 10771923f739SMatt Jacob return(1); 10781923f739SMatt Jacob } 10791923f739SMatt Jacob 10801923f739SMatt Jacob 1081d02373f1SMatt Jacob len = sizeof (XS_T **) * isp->isp_maxcmds; 10827cc0979fSDavid Malone isp->isp_xflist = (XS_T **) malloc(len, M_DEVBUF, M_WAITOK | M_ZERO); 1083a95ae193SMatt Jacob if (isp->isp_xflist == NULL) { 1084d02373f1SMatt Jacob isp_prt(isp, ISP_LOGERR, "cannot alloc xflist array"); 1085a95ae193SMatt Jacob return (1); 1086a95ae193SMatt Jacob } 1087a95ae193SMatt Jacob len = sizeof (bus_dmamap_t) * isp->isp_maxcmds; 10881923f739SMatt Jacob pcs->dmaps = (bus_dmamap_t *) malloc(len, M_DEVBUF, M_WAITOK); 10891923f739SMatt Jacob if (pcs->dmaps == NULL) { 10901923f739SMatt Jacob isp_prt(isp, ISP_LOGERR, "can't alloc dma map storage"); 1091a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 1092a95ae193SMatt Jacob return (1); 1093a95ae193SMatt Jacob } 1094a95ae193SMatt Jacob 1095d720e6d5SJustin T. Gibbs /* 1096d720e6d5SJustin T. Gibbs * Allocate and map the request, result queues, plus FC scratch area. 1097d720e6d5SJustin T. Gibbs */ 1098d02373f1SMatt Jacob len = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)); 1099d02373f1SMatt Jacob len += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)); 1100222bb542SMatt Jacob if (IS_FC(isp)) { 1101d720e6d5SJustin T. Gibbs len += ISP2100_SCRLEN; 1102d720e6d5SJustin T. Gibbs } 11031923f739SMatt Jacob 11041923f739SMatt Jacob ns = (len / PAGE_SIZE) + 1; 11051923f739SMatt Jacob if (bus_dma_tag_create(pcs->dmat, QENTRY_LEN, 0, BUS_SPACE_MAXADDR, 11061923f739SMatt Jacob BUS_SPACE_MAXADDR, NULL, NULL, len, ns, bl, 0, &isp->isp_cdmat)) { 1107f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 1108f7dddf8aSMatt Jacob "cannot create a dma tag for control spaces"); 11091923f739SMatt Jacob free(pcs->dmaps, M_DEVBUF); 1110a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 1111d720e6d5SJustin T. Gibbs return (1); 1112d720e6d5SJustin T. Gibbs } 1113d720e6d5SJustin T. Gibbs 11141923f739SMatt Jacob if (bus_dmamem_alloc(isp->isp_cdmat, (void **)&base, BUS_DMA_NOWAIT, 11151923f739SMatt Jacob &isp->isp_cdmap) != 0) { 1116f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 11171923f739SMatt Jacob "cannot allocate %d bytes of CCB memory", len); 11181923f739SMatt Jacob bus_dma_tag_destroy(isp->isp_cdmat); 1119a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 11201923f739SMatt Jacob free(pcs->dmaps, M_DEVBUF); 1121222bb542SMatt Jacob return (1); 1122222bb542SMatt Jacob } 1123d720e6d5SJustin T. Gibbs 1124a95ae193SMatt Jacob for (i = 0; i < isp->isp_maxcmds; i++) { 11251923f739SMatt Jacob error = bus_dmamap_create(pcs->dmat, 0, &pcs->dmaps[i]); 1126d720e6d5SJustin T. Gibbs if (error) { 1127f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 1128f7dddf8aSMatt Jacob "error %d creating per-cmd DMA maps", error); 11291923f739SMatt Jacob while (--i >= 0) { 11301923f739SMatt Jacob bus_dmamap_destroy(pcs->dmat, pcs->dmaps[i]); 11311923f739SMatt Jacob } 11321923f739SMatt Jacob goto bad; 1133d720e6d5SJustin T. Gibbs } 1134d720e6d5SJustin T. Gibbs } 1135a95ae193SMatt Jacob 11361923f739SMatt Jacob im.isp = isp; 1137222bb542SMatt Jacob im.error = 0; 11381923f739SMatt Jacob bus_dmamap_load(isp->isp_cdmat, isp->isp_cdmap, base, len, imc, &im, 0); 1139222bb542SMatt Jacob if (im.error) { 1140f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 11411923f739SMatt Jacob "error %d loading dma map for control areas", im.error); 11421923f739SMatt Jacob goto bad; 1143222bb542SMatt Jacob } 11441923f739SMatt Jacob 11451923f739SMatt Jacob isp->isp_rquest = base; 11461923f739SMatt Jacob base += ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)); 11471923f739SMatt Jacob isp->isp_result = base; 11481923f739SMatt Jacob if (IS_FC(isp)) { 11491923f739SMatt Jacob base += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)); 11501923f739SMatt Jacob FCPARAM(isp)->isp_scratch = base; 115192c49d78SMatt Jacob } 1152d720e6d5SJustin T. Gibbs return (0); 11531923f739SMatt Jacob 11541923f739SMatt Jacob bad: 11551923f739SMatt Jacob bus_dmamem_free(isp->isp_cdmat, base, isp->isp_cdmap); 11561923f739SMatt Jacob bus_dma_tag_destroy(isp->isp_cdmat); 11571923f739SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 11581923f739SMatt Jacob free(pcs->dmaps, M_DEVBUF); 11591923f739SMatt Jacob isp->isp_rquest = NULL; 11601923f739SMatt Jacob return (1); 1161d720e6d5SJustin T. Gibbs } 1162d720e6d5SJustin T. Gibbs 1163d720e6d5SJustin T. Gibbs typedef struct { 1164d720e6d5SJustin T. Gibbs struct ispsoftc *isp; 11659e11e5beSMatt Jacob void *cmd_token; 11669e11e5beSMatt Jacob void *rq; 11674fd13c1bSMatt Jacob u_int16_t *nxtip; 11689637d68cSMatt Jacob u_int16_t optr; 1169d720e6d5SJustin T. Gibbs u_int error; 1170d720e6d5SJustin T. Gibbs } mush_t; 1171d720e6d5SJustin T. Gibbs 11724873663cSMatt Jacob #define MUSHERR_NOQENTRIES -2 11734873663cSMatt Jacob 11749e11e5beSMatt Jacob #ifdef ISP_TARGET_MODE 11759e11e5beSMatt Jacob /* 11769e11e5beSMatt Jacob * We need to handle DMA for target mode differently from initiator mode. 11779e11e5beSMatt Jacob * 11789e11e5beSMatt Jacob * DMA mapping and construction and submission of CTIO Request Entries 11799e11e5beSMatt Jacob * and rendevous for completion are very tightly coupled because we start 11809e11e5beSMatt Jacob * out by knowing (per platform) how much data we have to move, but we 11819e11e5beSMatt Jacob * don't know, up front, how many DMA mapping segments will have to be used 11829e11e5beSMatt Jacob * cover that data, so we don't know how many CTIO Request Entries we 11839e11e5beSMatt Jacob * will end up using. Further, for performance reasons we may want to 11849e11e5beSMatt Jacob * (on the last CTIO for Fibre Channel), send status too (if all went well). 11859e11e5beSMatt Jacob * 11869e11e5beSMatt Jacob * The standard vector still goes through isp_pci_dmasetup, but the callback 11879e11e5beSMatt Jacob * for the DMA mapping routines comes here instead with the whole transfer 11889e11e5beSMatt Jacob * mapped and a pointer to a partially filled in already allocated request 11899e11e5beSMatt Jacob * queue entry. We finish the job. 11909e11e5beSMatt Jacob */ 1191e9a2738aSMatt Jacob static void tdma_mk(void *, bus_dma_segment_t *, int, int); 1192e9a2738aSMatt Jacob static void tdma_mkfc(void *, bus_dma_segment_t *, int, int); 1193e9a2738aSMatt Jacob 1194e9a2738aSMatt Jacob #define STATUS_WITH_DATA 1 11959e11e5beSMatt Jacob 1196d720e6d5SJustin T. Gibbs static void 119705fbcbb0SMatt Jacob tdma_mk(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 1198d720e6d5SJustin T. Gibbs { 1199d720e6d5SJustin T. Gibbs mush_t *mp; 12009e11e5beSMatt Jacob struct ccb_scsiio *csio; 12014fd13c1bSMatt Jacob struct ispsoftc *isp; 12021923f739SMatt Jacob struct isp_pcisoftc *pcs; 1203d720e6d5SJustin T. Gibbs bus_dmamap_t *dp; 12044fd13c1bSMatt Jacob ct_entry_t *cto, *qe; 120505fbcbb0SMatt Jacob u_int8_t scsi_status; 12064fd13c1bSMatt Jacob u_int16_t curi, nxti, handle; 1207b96934e8SMatt Jacob u_int32_t sflags; 120805fbcbb0SMatt Jacob int32_t resid; 12094fd13c1bSMatt Jacob int nth_ctio, nctios, send_status; 1210d720e6d5SJustin T. Gibbs 1211d720e6d5SJustin T. Gibbs mp = (mush_t *) arg; 1212d720e6d5SJustin T. Gibbs if (error) { 1213d720e6d5SJustin T. Gibbs mp->error = error; 1214d720e6d5SJustin T. Gibbs return; 1215d720e6d5SJustin T. Gibbs } 12164fd13c1bSMatt Jacob 12174fd13c1bSMatt Jacob isp = mp->isp; 12189e11e5beSMatt Jacob csio = mp->cmd_token; 12199e11e5beSMatt Jacob cto = mp->rq; 12204fd13c1bSMatt Jacob curi = isp->isp_reqidx; 12214fd13c1bSMatt Jacob qe = (ct_entry_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, curi); 12229e11e5beSMatt Jacob 122365b024e1SMatt Jacob cto->ct_xfrlen = 0; 122465b024e1SMatt Jacob cto->ct_seg_count = 0; 122565b024e1SMatt Jacob cto->ct_header.rqs_entry_count = 1; 122605fbcbb0SMatt Jacob MEMZERO(cto->ct_dataseg, sizeof(cto->ct_dataseg)); 122705fbcbb0SMatt Jacob 122805fbcbb0SMatt Jacob if (nseg == 0) { 122905fbcbb0SMatt Jacob cto->ct_header.rqs_seqno = 1; 12304fd13c1bSMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, 1231e9a2738aSMatt Jacob "CTIO[%x] lun%d iid%d tag %x flgs %x sts %x ssts %x res %d", 12325f5aafe1SMatt Jacob cto->ct_fwhandle, csio->ccb_h.target_lun, cto->ct_iid, 1233e9a2738aSMatt Jacob cto->ct_tag_val, cto->ct_flags, cto->ct_status, 1234e9a2738aSMatt Jacob cto->ct_scsi_status, cto->ct_resid); 12354fd13c1bSMatt Jacob ISP_TDQE(isp, "tdma_mk[no data]", curi, cto); 12364fd13c1bSMatt Jacob isp_put_ctio(isp, cto, qe); 123765b024e1SMatt Jacob return; 123865b024e1SMatt Jacob } 123965b024e1SMatt Jacob 124065b024e1SMatt Jacob nctios = nseg / ISP_RQDSEG; 124165b024e1SMatt Jacob if (nseg % ISP_RQDSEG) { 124265b024e1SMatt Jacob nctios++; 124365b024e1SMatt Jacob } 124465b024e1SMatt Jacob 124505fbcbb0SMatt Jacob /* 12465f5aafe1SMatt Jacob * Save syshandle, and potentially any SCSI status, which we'll 12475f5aafe1SMatt Jacob * reinsert on the last CTIO we're going to send. 124805fbcbb0SMatt Jacob */ 12494fd13c1bSMatt Jacob 12505f5aafe1SMatt Jacob handle = cto->ct_syshandle; 12515f5aafe1SMatt Jacob cto->ct_syshandle = 0; 125205fbcbb0SMatt Jacob cto->ct_header.rqs_seqno = 0; 125305fbcbb0SMatt Jacob send_status = (cto->ct_flags & CT_SENDSTATUS) != 0; 125405fbcbb0SMatt Jacob 125505fbcbb0SMatt Jacob if (send_status) { 125605fbcbb0SMatt Jacob sflags = cto->ct_flags & (CT_SENDSTATUS | CT_CCINCR); 125705fbcbb0SMatt Jacob cto->ct_flags &= ~(CT_SENDSTATUS | CT_CCINCR); 125805fbcbb0SMatt Jacob /* 125905fbcbb0SMatt Jacob * Preserve residual. 126005fbcbb0SMatt Jacob */ 126105fbcbb0SMatt Jacob resid = cto->ct_resid; 126205fbcbb0SMatt Jacob 126305fbcbb0SMatt Jacob /* 126405fbcbb0SMatt Jacob * Save actual SCSI status. 126505fbcbb0SMatt Jacob */ 126605fbcbb0SMatt Jacob scsi_status = cto->ct_scsi_status; 126705fbcbb0SMatt Jacob 1268e9a2738aSMatt Jacob #ifndef STATUS_WITH_DATA 1269e9a2738aSMatt Jacob sflags |= CT_NO_DATA; 127005fbcbb0SMatt Jacob /* 127105fbcbb0SMatt Jacob * We can't do a status at the same time as a data CTIO, so 127205fbcbb0SMatt Jacob * we need to synthesize an extra CTIO at this level. 127305fbcbb0SMatt Jacob */ 127405fbcbb0SMatt Jacob nctios++; 1275b72b1569SMatt Jacob #endif 127605fbcbb0SMatt Jacob } else { 127705fbcbb0SMatt Jacob sflags = scsi_status = resid = 0; 127805fbcbb0SMatt Jacob } 127905fbcbb0SMatt Jacob 1280b96934e8SMatt Jacob cto->ct_resid = 0; 128105fbcbb0SMatt Jacob cto->ct_scsi_status = 0; 128205fbcbb0SMatt Jacob 12831923f739SMatt Jacob pcs = (struct isp_pcisoftc *)isp; 12841923f739SMatt Jacob dp = &pcs->dmaps[isp_handle_index(handle)]; 12859e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 12861923f739SMatt Jacob bus_dmamap_sync(pcs->dmat, *dp, BUS_DMASYNC_PREREAD); 1287d720e6d5SJustin T. Gibbs } else { 12881923f739SMatt Jacob bus_dmamap_sync(pcs->dmat, *dp, BUS_DMASYNC_PREWRITE); 1289d720e6d5SJustin T. Gibbs } 1290d720e6d5SJustin T. Gibbs 12914fd13c1bSMatt Jacob nxti = *mp->nxtip; 12929e11e5beSMatt Jacob 12934fd13c1bSMatt Jacob for (nth_ctio = 0; nth_ctio < nctios; nth_ctio++) { 129405fbcbb0SMatt Jacob int seglim; 12959e11e5beSMatt Jacob 12969e11e5beSMatt Jacob seglim = nseg; 129705fbcbb0SMatt Jacob if (seglim) { 129805fbcbb0SMatt Jacob int seg; 129905fbcbb0SMatt Jacob 13009e11e5beSMatt Jacob if (seglim > ISP_RQDSEG) 13019e11e5beSMatt Jacob seglim = ISP_RQDSEG; 13029e11e5beSMatt Jacob 130305fbcbb0SMatt Jacob for (seg = 0; seg < seglim; seg++, nseg--) { 130405fbcbb0SMatt Jacob /* 130505fbcbb0SMatt Jacob * Unlike normal initiator commands, we don't 130605fbcbb0SMatt Jacob * do any swizzling here. 130705fbcbb0SMatt Jacob */ 13089e11e5beSMatt Jacob cto->ct_dataseg[seg].ds_count = dm_segs->ds_len; 130905fbcbb0SMatt Jacob cto->ct_dataseg[seg].ds_base = dm_segs->ds_addr; 13109e11e5beSMatt Jacob cto->ct_xfrlen += dm_segs->ds_len; 13119e11e5beSMatt Jacob dm_segs++; 13129e11e5beSMatt Jacob } 13139e11e5beSMatt Jacob cto->ct_seg_count = seg; 13149e11e5beSMatt Jacob } else { 131505fbcbb0SMatt Jacob /* 131605fbcbb0SMatt Jacob * This case should only happen when we're sending an 131705fbcbb0SMatt Jacob * extra CTIO with final status. 131805fbcbb0SMatt Jacob */ 131905fbcbb0SMatt Jacob if (send_status == 0) { 13204fd13c1bSMatt Jacob isp_prt(isp, ISP_LOGWARN, 1321f7dddf8aSMatt Jacob "tdma_mk ran out of segments"); 132205fbcbb0SMatt Jacob mp->error = EINVAL; 132305fbcbb0SMatt Jacob return; 13249e11e5beSMatt Jacob } 132505fbcbb0SMatt Jacob } 132605fbcbb0SMatt Jacob 132705fbcbb0SMatt Jacob /* 132805fbcbb0SMatt Jacob * At this point, the fields ct_lun, ct_iid, ct_tagval, 132905fbcbb0SMatt Jacob * ct_tagtype, and ct_timeout have been carried over 133005fbcbb0SMatt Jacob * unchanged from what our caller had set. 133105fbcbb0SMatt Jacob * 133205fbcbb0SMatt Jacob * The dataseg fields and the seg_count fields we just got 133305fbcbb0SMatt Jacob * through setting. The data direction we've preserved all 133405fbcbb0SMatt Jacob * along and only clear it if we're now sending status. 133505fbcbb0SMatt Jacob */ 13369e11e5beSMatt Jacob 13374fd13c1bSMatt Jacob if (nth_ctio == nctios - 1) { 13389e11e5beSMatt Jacob /* 133905fbcbb0SMatt Jacob * We're the last in a sequence of CTIOs, so mark 134005fbcbb0SMatt Jacob * this CTIO and save the handle to the CCB such that 134105fbcbb0SMatt Jacob * when this CTIO completes we can free dma resources 134205fbcbb0SMatt Jacob * and do whatever else we need to do to finish the 1343e9a2738aSMatt Jacob * rest of the command. We *don't* give this to the 1344e9a2738aSMatt Jacob * firmware to work on- the caller will do that. 13459e11e5beSMatt Jacob */ 13464fd13c1bSMatt Jacob 13475f5aafe1SMatt Jacob cto->ct_syshandle = handle; 134805fbcbb0SMatt Jacob cto->ct_header.rqs_seqno = 1; 134905fbcbb0SMatt Jacob 135005fbcbb0SMatt Jacob if (send_status) { 13519e11e5beSMatt Jacob cto->ct_scsi_status = scsi_status; 1352b72b1569SMatt Jacob cto->ct_flags |= sflags; 135305fbcbb0SMatt Jacob cto->ct_resid = resid; 135442426921SMatt Jacob } 1355d02373f1SMatt Jacob if (send_status) { 13564fd13c1bSMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, 1357e9a2738aSMatt Jacob "CTIO[%x] lun%d iid %d tag %x ct_flags %x " 13585f5aafe1SMatt Jacob "scsi status %x resid %d", 13595f5aafe1SMatt Jacob cto->ct_fwhandle, csio->ccb_h.target_lun, 1360e9a2738aSMatt Jacob cto->ct_iid, cto->ct_tag_val, cto->ct_flags, 136105fbcbb0SMatt Jacob cto->ct_scsi_status, cto->ct_resid); 1362d02373f1SMatt Jacob } else { 13634fd13c1bSMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, 1364e9a2738aSMatt Jacob "CTIO[%x] lun%d iid%d tag %x ct_flags 0x%x", 13655f5aafe1SMatt Jacob cto->ct_fwhandle, csio->ccb_h.target_lun, 1366e9a2738aSMatt Jacob cto->ct_iid, cto->ct_tag_val, 1367e9a2738aSMatt Jacob cto->ct_flags); 136805fbcbb0SMatt Jacob } 13694fd13c1bSMatt Jacob isp_put_ctio(isp, cto, qe); 13704fd13c1bSMatt Jacob ISP_TDQE(isp, "last tdma_mk", curi, cto); 13714fd13c1bSMatt Jacob if (nctios > 1) { 13724fd13c1bSMatt Jacob MEMORYBARRIER(isp, SYNC_REQUEST, 13734fd13c1bSMatt Jacob curi, QENTRY_LEN); 13744fd13c1bSMatt Jacob } 13759e11e5beSMatt Jacob } else { 13764fd13c1bSMatt Jacob ct_entry_t *oqe = qe; 137705fbcbb0SMatt Jacob 137805fbcbb0SMatt Jacob /* 13795f5aafe1SMatt Jacob * Make sure syshandle fields are clean 138005fbcbb0SMatt Jacob */ 13815f5aafe1SMatt Jacob cto->ct_syshandle = 0; 13829e11e5beSMatt Jacob cto->ct_header.rqs_seqno = 0; 138305fbcbb0SMatt Jacob 13844fd13c1bSMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, 13855f5aafe1SMatt Jacob "CTIO[%x] lun%d for ID%d ct_flags 0x%x", 13865f5aafe1SMatt Jacob cto->ct_fwhandle, csio->ccb_h.target_lun, 13875f5aafe1SMatt Jacob cto->ct_iid, cto->ct_flags); 138805fbcbb0SMatt Jacob 138905fbcbb0SMatt Jacob /* 139005fbcbb0SMatt Jacob * Get a new CTIO 139105fbcbb0SMatt Jacob */ 13924fd13c1bSMatt Jacob qe = (ct_entry_t *) 13934fd13c1bSMatt Jacob ISP_QUEUE_ENTRY(isp->isp_rquest, nxti); 13944fd13c1bSMatt Jacob nxti = ISP_NXT_QENTRY(nxti, RQUEST_QUEUE_LEN(isp)); 13954fd13c1bSMatt Jacob if (nxti == mp->optr) { 13964fd13c1bSMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 1397f7dddf8aSMatt Jacob "Queue Overflow in tdma_mk"); 13989e11e5beSMatt Jacob mp->error = MUSHERR_NOQENTRIES; 13999e11e5beSMatt Jacob return; 14009e11e5beSMatt Jacob } 14014fd13c1bSMatt Jacob 14029e11e5beSMatt Jacob /* 14034fd13c1bSMatt Jacob * Now that we're done with the old CTIO, 14044fd13c1bSMatt Jacob * flush it out to the request queue. 14054fd13c1bSMatt Jacob */ 14064fd13c1bSMatt Jacob ISP_TDQE(isp, "dma_tgt_fc", curi, cto); 14074fd13c1bSMatt Jacob isp_put_ctio(isp, cto, oqe); 14084fd13c1bSMatt Jacob if (nth_ctio != 0) { 14094fd13c1bSMatt Jacob MEMORYBARRIER(isp, SYNC_REQUEST, curi, 14104fd13c1bSMatt Jacob QENTRY_LEN); 14114fd13c1bSMatt Jacob } 14124fd13c1bSMatt Jacob curi = ISP_NXT_QENTRY(curi, RQUEST_QUEUE_LEN(isp)); 14134fd13c1bSMatt Jacob 14144fd13c1bSMatt Jacob /* 14154fd13c1bSMatt Jacob * Reset some fields in the CTIO so we can reuse 14164fd13c1bSMatt Jacob * for the next one we'll flush to the request 14174fd13c1bSMatt Jacob * queue. 14189e11e5beSMatt Jacob */ 14199e11e5beSMatt Jacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO; 14209e11e5beSMatt Jacob cto->ct_header.rqs_entry_count = 1; 14219e11e5beSMatt Jacob cto->ct_header.rqs_flags = 0; 14229e11e5beSMatt Jacob cto->ct_status = 0; 14239e11e5beSMatt Jacob cto->ct_scsi_status = 0; 14249e11e5beSMatt Jacob cto->ct_xfrlen = 0; 14259e11e5beSMatt Jacob cto->ct_resid = 0; 14269e11e5beSMatt Jacob cto->ct_seg_count = 0; 142705fbcbb0SMatt Jacob MEMZERO(cto->ct_dataseg, sizeof(cto->ct_dataseg)); 14289e11e5beSMatt Jacob } 14299e11e5beSMatt Jacob } 14304fd13c1bSMatt Jacob *mp->nxtip = nxti; 14319e11e5beSMatt Jacob } 14329e11e5beSMatt Jacob 1433fc087171SMatt Jacob /* 1434fc087171SMatt Jacob * We don't have to do multiple CTIOs here. Instead, we can just do 1435fc087171SMatt Jacob * continuation segments as needed. This greatly simplifies the code 1436fc087171SMatt Jacob * improves performance. 1437fc087171SMatt Jacob */ 1438fc087171SMatt Jacob 14399e11e5beSMatt Jacob static void 144005fbcbb0SMatt Jacob tdma_mkfc(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 14419e11e5beSMatt Jacob { 14429e11e5beSMatt Jacob mush_t *mp; 14439e11e5beSMatt Jacob struct ccb_scsiio *csio; 14444fd13c1bSMatt Jacob struct ispsoftc *isp; 14454fd13c1bSMatt Jacob ct2_entry_t *cto, *qe; 14464fd13c1bSMatt Jacob u_int16_t curi, nxti; 1447fc087171SMatt Jacob int segcnt; 14489e11e5beSMatt Jacob 14499e11e5beSMatt Jacob mp = (mush_t *) arg; 14509e11e5beSMatt Jacob if (error) { 14519e11e5beSMatt Jacob mp->error = error; 14529e11e5beSMatt Jacob return; 14539e11e5beSMatt Jacob } 14549e11e5beSMatt Jacob 14554fd13c1bSMatt Jacob isp = mp->isp; 145665b024e1SMatt Jacob csio = mp->cmd_token; 145765b024e1SMatt Jacob cto = mp->rq; 1458fc087171SMatt Jacob 14594fd13c1bSMatt Jacob curi = isp->isp_reqidx; 14604fd13c1bSMatt Jacob qe = (ct2_entry_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, curi); 146165b024e1SMatt Jacob 146265b024e1SMatt Jacob if (nseg == 0) { 146365b024e1SMatt Jacob if ((cto->ct_flags & CT2_FLAG_MMASK) != CT2_FLAG_MODE1) { 14644fd13c1bSMatt Jacob isp_prt(isp, ISP_LOGWARN, 1465f7dddf8aSMatt Jacob "dma2_tgt_fc, a status CTIO2 without MODE1 " 1466f7dddf8aSMatt Jacob "set (0x%x)", cto->ct_flags); 146765b024e1SMatt Jacob mp->error = EINVAL; 146865b024e1SMatt Jacob return; 146965b024e1SMatt Jacob } 147065b024e1SMatt Jacob /* 147165b024e1SMatt Jacob * We preserve ct_lun, ct_iid, ct_rxid. We set the data 147265b024e1SMatt Jacob * flags to NO DATA and clear relative offset flags. 147365b024e1SMatt Jacob * We preserve the ct_resid and the response area. 147465b024e1SMatt Jacob */ 1475fc087171SMatt Jacob cto->ct_header.rqs_seqno = 1; 147665b024e1SMatt Jacob cto->ct_seg_count = 0; 147765b024e1SMatt Jacob cto->ct_reloff = 0; 14784fd13c1bSMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, 14795f5aafe1SMatt Jacob "CTIO2[%x] lun %d->iid%d flgs 0x%x sts 0x%x ssts " 1480d02373f1SMatt Jacob "0x%x res %d", cto->ct_rxid, csio->ccb_h.target_lun, 1481d02373f1SMatt Jacob cto->ct_iid, cto->ct_flags, cto->ct_status, 148265b024e1SMatt Jacob cto->rsp.m1.ct_scsi_status, cto->ct_resid); 14834fd13c1bSMatt Jacob isp_put_ctio2(isp, cto, qe); 14844fd13c1bSMatt Jacob ISP_TDQE(isp, "dma2_tgt_fc[no data]", curi, qe); 14859e11e5beSMatt Jacob return; 14869e11e5beSMatt Jacob } 14879e11e5beSMatt Jacob 148865b024e1SMatt Jacob if ((cto->ct_flags & CT2_FLAG_MMASK) != CT2_FLAG_MODE0) { 1489fc087171SMatt Jacob isp_prt(isp, ISP_LOGERR, 1490f7dddf8aSMatt Jacob "dma2_tgt_fc, a data CTIO2 without MODE0 set " 1491f7dddf8aSMatt Jacob "(0x%x)", cto->ct_flags); 149265b024e1SMatt Jacob mp->error = EINVAL; 149365b024e1SMatt Jacob return; 149465b024e1SMatt Jacob } 149565b024e1SMatt Jacob 149665b024e1SMatt Jacob 14974fd13c1bSMatt Jacob nxti = *mp->nxtip; 14984fd13c1bSMatt Jacob 1499fc087171SMatt Jacob /* 1500fc087171SMatt Jacob * Set up the CTIO2 data segments. 1501fc087171SMatt Jacob */ 1502fc087171SMatt Jacob for (segcnt = 0; cto->ct_seg_count < ISP_RQDSEG_T2 && segcnt < nseg; 1503fc087171SMatt Jacob cto->ct_seg_count++, segcnt++) { 1504fc087171SMatt Jacob cto->rsp.m0.ct_dataseg[cto->ct_seg_count].ds_base = 1505fc087171SMatt Jacob dm_segs[segcnt].ds_addr; 1506fc087171SMatt Jacob cto->rsp.m0.ct_dataseg[cto->ct_seg_count].ds_count = 1507fc087171SMatt Jacob dm_segs[segcnt].ds_len; 1508fc087171SMatt Jacob cto->rsp.m0.ct_xfrlen += dm_segs[segcnt].ds_len; 1509fc087171SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, "isp_send_ctio2: ent0[%d]0x%x:%d", 1510fc087171SMatt Jacob cto->ct_seg_count, dm_segs[segcnt].ds_addr, 1511fc087171SMatt Jacob dm_segs[segcnt].ds_len); 1512fc087171SMatt Jacob } 15139e11e5beSMatt Jacob 1514fc087171SMatt Jacob while (segcnt < nseg) { 1515fc087171SMatt Jacob u_int16_t curip; 15164fd13c1bSMatt Jacob int seg; 1517fc087171SMatt Jacob ispcontreq_t local, *crq = &local, *qep; 15189e11e5beSMatt Jacob 1519fc087171SMatt Jacob qep = (ispcontreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, nxti); 1520fc087171SMatt Jacob curip = nxti; 1521fc087171SMatt Jacob nxti = ISP_NXT_QENTRY(curip, RQUEST_QUEUE_LEN(isp)); 15224fd13c1bSMatt Jacob if (nxti == mp->optr) { 1523fc087171SMatt Jacob ISP_UNLOCK(isp); 1524fc087171SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 1525fc087171SMatt Jacob "tdma_mkfc: request queue overflow"); 15269e11e5beSMatt Jacob mp->error = MUSHERR_NOQENTRIES; 15279e11e5beSMatt Jacob return; 15289e11e5beSMatt Jacob } 1529fc087171SMatt Jacob cto->ct_header.rqs_entry_count++; 1530fc087171SMatt Jacob MEMZERO((void *)crq, sizeof (*crq)); 1531fc087171SMatt Jacob crq->req_header.rqs_entry_count = 1; 1532fc087171SMatt Jacob crq->req_header.rqs_entry_type = RQSTYPE_DATASEG; 1533fc087171SMatt Jacob for (seg = 0; segcnt < nseg && seg < ISP_CDSEG; 1534fc087171SMatt Jacob segcnt++, seg++) { 1535fc087171SMatt Jacob crq->req_dataseg[seg].ds_base = dm_segs[segcnt].ds_addr; 1536fc087171SMatt Jacob crq->req_dataseg[seg].ds_count = dm_segs[segcnt].ds_len; 1537fc087171SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, 1538fc087171SMatt Jacob "isp_send_ctio2: ent%d[%d]%x:%u", 1539fc087171SMatt Jacob cto->ct_header.rqs_entry_count-1, seg, 1540fc087171SMatt Jacob dm_segs[segcnt].ds_addr, dm_segs[segcnt].ds_len); 1541fc087171SMatt Jacob cto->rsp.m0.ct_xfrlen += dm_segs[segcnt].ds_len; 1542fc087171SMatt Jacob cto->ct_seg_count++; 1543fc087171SMatt Jacob } 1544fc087171SMatt Jacob MEMORYBARRIER(isp, SYNC_REQUEST, curip, QENTRY_LEN); 1545fc087171SMatt Jacob isp_put_cont_req(isp, crq, qep); 1546fc087171SMatt Jacob ISP_TDQE(isp, "cont entry", curi, qep); 1547fc087171SMatt Jacob } 154865b024e1SMatt Jacob 15499e11e5beSMatt Jacob /* 1550fc087171SMatt Jacob * No do final twiddling for the CTIO itself. 15514fd13c1bSMatt Jacob */ 1552fc087171SMatt Jacob cto->ct_header.rqs_seqno = 1; 1553fc087171SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, 1554fc087171SMatt Jacob "CTIO2[%x] lun %d->iid%d flgs 0x%x sts 0x%x ssts 0x%x resid %d", 1555fc087171SMatt Jacob cto->ct_rxid, csio->ccb_h.target_lun, (int) cto->ct_iid, 1556fc087171SMatt Jacob cto->ct_flags, cto->ct_status, cto->rsp.m1.ct_scsi_status, 1557fc087171SMatt Jacob cto->ct_resid); 1558fc087171SMatt Jacob isp_put_ctio2(isp, cto, qe); 1559fc087171SMatt Jacob ISP_TDQE(isp, "last dma2_tgt_fc", curi, qe); 15604fd13c1bSMatt Jacob *mp->nxtip = nxti; 15619e11e5beSMatt Jacob } 15629e11e5beSMatt Jacob #endif 15639e11e5beSMatt Jacob 1564126ec864SMatt Jacob static void dma2(void *, bus_dma_segment_t *, int, int); 15659e11e5beSMatt Jacob 15669e11e5beSMatt Jacob static void 15679e11e5beSMatt Jacob dma2(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 15689e11e5beSMatt Jacob { 15699e11e5beSMatt Jacob mush_t *mp; 15704fd13c1bSMatt Jacob struct ispsoftc *isp; 15719e11e5beSMatt Jacob struct ccb_scsiio *csio; 15721923f739SMatt Jacob struct isp_pcisoftc *pcs; 15739e11e5beSMatt Jacob bus_dmamap_t *dp; 15749e11e5beSMatt Jacob bus_dma_segment_t *eseg; 15759e11e5beSMatt Jacob ispreq_t *rq; 15769e11e5beSMatt Jacob int seglim, datalen; 15774fd13c1bSMatt Jacob u_int16_t nxti; 15789e11e5beSMatt Jacob 15799e11e5beSMatt Jacob mp = (mush_t *) arg; 15809e11e5beSMatt Jacob if (error) { 15819e11e5beSMatt Jacob mp->error = error; 15829e11e5beSMatt Jacob return; 15839e11e5beSMatt Jacob } 15849e11e5beSMatt Jacob 15859e11e5beSMatt Jacob if (nseg < 1) { 1586f7dddf8aSMatt Jacob isp_prt(mp->isp, ISP_LOGERR, "bad segment count (%d)", nseg); 15879e11e5beSMatt Jacob mp->error = EFAULT; 15889e11e5beSMatt Jacob return; 15899e11e5beSMatt Jacob } 15909e11e5beSMatt Jacob csio = mp->cmd_token; 15914fd13c1bSMatt Jacob isp = mp->isp; 15929e11e5beSMatt Jacob rq = mp->rq; 15931923f739SMatt Jacob pcs = (struct isp_pcisoftc *)mp->isp; 15941923f739SMatt Jacob dp = &pcs->dmaps[isp_handle_index(rq->req_handle)]; 15954fd13c1bSMatt Jacob nxti = *mp->nxtip; 15969e11e5beSMatt Jacob 15979e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 15981923f739SMatt Jacob bus_dmamap_sync(pcs->dmat, *dp, BUS_DMASYNC_PREREAD); 15999e11e5beSMatt Jacob } else { 16001923f739SMatt Jacob bus_dmamap_sync(pcs->dmat, *dp, BUS_DMASYNC_PREWRITE); 16019e11e5beSMatt Jacob } 16029e11e5beSMatt Jacob 16039e11e5beSMatt Jacob datalen = XS_XFRLEN(csio); 16049e11e5beSMatt Jacob 16059e11e5beSMatt Jacob /* 16069e11e5beSMatt Jacob * We're passed an initial partially filled in entry that 16079e11e5beSMatt Jacob * has most fields filled in except for data transfer 16089e11e5beSMatt Jacob * related values. 16099e11e5beSMatt Jacob * 16109e11e5beSMatt Jacob * Our job is to fill in the initial request queue entry and 16119e11e5beSMatt Jacob * then to start allocating and filling in continuation entries 16129e11e5beSMatt Jacob * until we've covered the entire transfer. 16139e11e5beSMatt Jacob */ 16149e11e5beSMatt Jacob 16154fd13c1bSMatt Jacob if (IS_FC(isp)) { 1616d720e6d5SJustin T. Gibbs seglim = ISP_RQDSEG_T2; 1617d720e6d5SJustin T. Gibbs ((ispreqt2_t *)rq)->req_totalcnt = datalen; 16189e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 16199e11e5beSMatt Jacob ((ispreqt2_t *)rq)->req_flags |= REQFLAG_DATA_IN; 16209e11e5beSMatt Jacob } else { 16219e11e5beSMatt Jacob ((ispreqt2_t *)rq)->req_flags |= REQFLAG_DATA_OUT; 16229e11e5beSMatt Jacob } 1623d720e6d5SJustin T. Gibbs } else { 1624e142669aSMatt Jacob if (csio->cdb_len > 12) { 1625e142669aSMatt Jacob seglim = 0; 1626e142669aSMatt Jacob } else { 1627d720e6d5SJustin T. Gibbs seglim = ISP_RQDSEG; 1628e142669aSMatt Jacob } 16299e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 16309e11e5beSMatt Jacob rq->req_flags |= REQFLAG_DATA_IN; 16319e11e5beSMatt Jacob } else { 16329e11e5beSMatt Jacob rq->req_flags |= REQFLAG_DATA_OUT; 16339e11e5beSMatt Jacob } 1634d720e6d5SJustin T. Gibbs } 1635d720e6d5SJustin T. Gibbs 1636d720e6d5SJustin T. Gibbs eseg = dm_segs + nseg; 1637d720e6d5SJustin T. Gibbs 1638d720e6d5SJustin T. Gibbs while (datalen != 0 && rq->req_seg_count < seglim && dm_segs != eseg) { 16394fd13c1bSMatt Jacob if (IS_FC(isp)) { 1640d720e6d5SJustin T. Gibbs ispreqt2_t *rq2 = (ispreqt2_t *)rq; 1641d720e6d5SJustin T. Gibbs rq2->req_dataseg[rq2->req_seg_count].ds_base = 1642d720e6d5SJustin T. Gibbs dm_segs->ds_addr; 1643d720e6d5SJustin T. Gibbs rq2->req_dataseg[rq2->req_seg_count].ds_count = 1644d720e6d5SJustin T. Gibbs dm_segs->ds_len; 1645d720e6d5SJustin T. Gibbs } else { 1646d720e6d5SJustin T. Gibbs rq->req_dataseg[rq->req_seg_count].ds_base = 1647d720e6d5SJustin T. Gibbs dm_segs->ds_addr; 1648d720e6d5SJustin T. Gibbs rq->req_dataseg[rq->req_seg_count].ds_count = 1649d720e6d5SJustin T. Gibbs dm_segs->ds_len; 1650d720e6d5SJustin T. Gibbs } 1651d720e6d5SJustin T. Gibbs datalen -= dm_segs->ds_len; 1652d720e6d5SJustin T. Gibbs rq->req_seg_count++; 1653d720e6d5SJustin T. Gibbs dm_segs++; 1654d720e6d5SJustin T. Gibbs } 1655d720e6d5SJustin T. Gibbs 1656d720e6d5SJustin T. Gibbs while (datalen > 0 && dm_segs != eseg) { 16574fd13c1bSMatt Jacob u_int16_t onxti; 16584fd13c1bSMatt Jacob ispcontreq_t local, *crq = &local, *cqe; 16594fd13c1bSMatt Jacob 16604fd13c1bSMatt Jacob cqe = (ispcontreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, nxti); 16614fd13c1bSMatt Jacob onxti = nxti; 16624fd13c1bSMatt Jacob nxti = ISP_NXT_QENTRY(onxti, RQUEST_QUEUE_LEN(isp)); 16634fd13c1bSMatt Jacob if (nxti == mp->optr) { 16644fd13c1bSMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, "Request Queue Overflow++"); 16654873663cSMatt Jacob mp->error = MUSHERR_NOQENTRIES; 1666d720e6d5SJustin T. Gibbs return; 1667d720e6d5SJustin T. Gibbs } 1668d720e6d5SJustin T. Gibbs rq->req_header.rqs_entry_count++; 16694fd13c1bSMatt Jacob MEMZERO((void *)crq, sizeof (*crq)); 1670d720e6d5SJustin T. Gibbs crq->req_header.rqs_entry_count = 1; 1671d720e6d5SJustin T. Gibbs crq->req_header.rqs_entry_type = RQSTYPE_DATASEG; 1672d720e6d5SJustin T. Gibbs 1673d720e6d5SJustin T. Gibbs seglim = 0; 1674d720e6d5SJustin T. Gibbs while (datalen > 0 && seglim < ISP_CDSEG && dm_segs != eseg) { 1675d720e6d5SJustin T. Gibbs crq->req_dataseg[seglim].ds_base = 1676d720e6d5SJustin T. Gibbs dm_segs->ds_addr; 1677d720e6d5SJustin T. Gibbs crq->req_dataseg[seglim].ds_count = 1678d720e6d5SJustin T. Gibbs dm_segs->ds_len; 1679d720e6d5SJustin T. Gibbs rq->req_seg_count++; 1680d720e6d5SJustin T. Gibbs dm_segs++; 1681d720e6d5SJustin T. Gibbs seglim++; 1682d720e6d5SJustin T. Gibbs datalen -= dm_segs->ds_len; 1683d720e6d5SJustin T. Gibbs } 16844fd13c1bSMatt Jacob isp_put_cont_req(isp, crq, cqe); 16854fd13c1bSMatt Jacob MEMORYBARRIER(isp, SYNC_REQUEST, onxti, QENTRY_LEN); 1686d720e6d5SJustin T. Gibbs } 16874fd13c1bSMatt Jacob *mp->nxtip = nxti; 1688d720e6d5SJustin T. Gibbs } 1689d720e6d5SJustin T. Gibbs 1690d720e6d5SJustin T. Gibbs static int 16919e11e5beSMatt Jacob isp_pci_dmasetup(struct ispsoftc *isp, struct ccb_scsiio *csio, ispreq_t *rq, 16924fd13c1bSMatt Jacob u_int16_t *nxtip, u_int16_t optr) 1693d720e6d5SJustin T. Gibbs { 16941923f739SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *)isp; 16954fd13c1bSMatt Jacob ispreq_t *qep; 16960a5f7e8bSMatt Jacob bus_dmamap_t *dp = NULL; 1697d720e6d5SJustin T. Gibbs mush_t mush, *mp; 1698126ec864SMatt Jacob void (*eptr)(void *, bus_dma_segment_t *, int, int); 1699d720e6d5SJustin T. Gibbs 17004fd13c1bSMatt Jacob qep = (ispreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, isp->isp_reqidx); 170165b024e1SMatt Jacob #ifdef ISP_TARGET_MODE 170265b024e1SMatt Jacob if (csio->ccb_h.func_code == XPT_CONT_TARGET_IO) { 170365b024e1SMatt Jacob if (IS_FC(isp)) { 170405fbcbb0SMatt Jacob eptr = tdma_mkfc; 170565b024e1SMatt Jacob } else { 170605fbcbb0SMatt Jacob eptr = tdma_mk; 170765b024e1SMatt Jacob } 170805fbcbb0SMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE || 170905fbcbb0SMatt Jacob (csio->dxfer_len == 0)) { 171065b024e1SMatt Jacob mp = &mush; 171165b024e1SMatt Jacob mp->isp = isp; 171265b024e1SMatt Jacob mp->cmd_token = csio; 1713e9a2738aSMatt Jacob mp->rq = rq; /* really a ct_entry_t or ct2_entry_t */ 17144fd13c1bSMatt Jacob mp->nxtip = nxtip; 171565b024e1SMatt Jacob mp->optr = optr; 171665b024e1SMatt Jacob mp->error = 0; 171765b024e1SMatt Jacob (*eptr)(mp, NULL, 0, 0); 17184fd13c1bSMatt Jacob goto mbxsync; 171965b024e1SMatt Jacob } 172065b024e1SMatt Jacob } else 172165b024e1SMatt Jacob #endif 172265b024e1SMatt Jacob eptr = dma2; 172365b024e1SMatt Jacob 17244fd13c1bSMatt Jacob 172505fbcbb0SMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE || 172605fbcbb0SMatt Jacob (csio->dxfer_len == 0)) { 172742426921SMatt Jacob rq->req_seg_count = 1; 17284fd13c1bSMatt Jacob goto mbxsync; 172942426921SMatt Jacob } 173042426921SMatt Jacob 1731d720e6d5SJustin T. Gibbs /* 1732d720e6d5SJustin T. Gibbs * Do a virtual grapevine step to collect info for 17334873663cSMatt Jacob * the callback dma allocation that we have to use... 1734d720e6d5SJustin T. Gibbs */ 1735d720e6d5SJustin T. Gibbs mp = &mush; 1736d720e6d5SJustin T. Gibbs mp->isp = isp; 17379e11e5beSMatt Jacob mp->cmd_token = csio; 1738d720e6d5SJustin T. Gibbs mp->rq = rq; 17394fd13c1bSMatt Jacob mp->nxtip = nxtip; 1740d720e6d5SJustin T. Gibbs mp->optr = optr; 1741d720e6d5SJustin T. Gibbs mp->error = 0; 1742d720e6d5SJustin T. Gibbs 17439e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_SCATTER_VALID) == 0) { 17449e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DATA_PHYS) == 0) { 17454873663cSMatt Jacob int error, s; 17461923f739SMatt Jacob dp = &pcs->dmaps[isp_handle_index(rq->req_handle)]; 1747d720e6d5SJustin T. Gibbs s = splsoftvm(); 17481923f739SMatt Jacob error = bus_dmamap_load(pcs->dmat, *dp, 17499e11e5beSMatt Jacob csio->data_ptr, csio->dxfer_len, eptr, mp, 0); 1750d720e6d5SJustin T. Gibbs if (error == EINPROGRESS) { 17511923f739SMatt Jacob bus_dmamap_unload(pcs->dmat, *dp); 1752d720e6d5SJustin T. Gibbs mp->error = EINVAL; 1753f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 1754f7dddf8aSMatt Jacob "deferred dma allocation not supported"); 1755d720e6d5SJustin T. Gibbs } else if (error && mp->error == 0) { 17560a5f7e8bSMatt Jacob #ifdef DIAGNOSTIC 17576e5c5328SMatt Jacob isp_prt(isp, ISP_LOGERR, 17586e5c5328SMatt Jacob "error %d in dma mapping code", error); 17590a5f7e8bSMatt Jacob #endif 1760d720e6d5SJustin T. Gibbs mp->error = error; 1761d720e6d5SJustin T. Gibbs } 17624873663cSMatt Jacob splx(s); 1763d720e6d5SJustin T. Gibbs } else { 1764d720e6d5SJustin T. Gibbs /* Pointer to physical buffer */ 1765d720e6d5SJustin T. Gibbs struct bus_dma_segment seg; 1766d720e6d5SJustin T. Gibbs seg.ds_addr = (bus_addr_t)csio->data_ptr; 1767d720e6d5SJustin T. Gibbs seg.ds_len = csio->dxfer_len; 17689e11e5beSMatt Jacob (*eptr)(mp, &seg, 1, 0); 1769d720e6d5SJustin T. Gibbs } 1770d720e6d5SJustin T. Gibbs } else { 1771d720e6d5SJustin T. Gibbs struct bus_dma_segment *segs; 1772d720e6d5SJustin T. Gibbs 17739e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DATA_PHYS) != 0) { 1774f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 1775f7dddf8aSMatt Jacob "Physical segment pointers unsupported"); 1776d720e6d5SJustin T. Gibbs mp->error = EINVAL; 17779e11e5beSMatt Jacob } else if ((csio->ccb_h.flags & CAM_SG_LIST_PHYS) == 0) { 1778f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 1779f7dddf8aSMatt Jacob "Virtual segment addresses unsupported"); 1780d720e6d5SJustin T. Gibbs mp->error = EINVAL; 1781d720e6d5SJustin T. Gibbs } else { 1782d720e6d5SJustin T. Gibbs /* Just use the segments provided */ 1783d720e6d5SJustin T. Gibbs segs = (struct bus_dma_segment *) csio->data_ptr; 17849e11e5beSMatt Jacob (*eptr)(mp, segs, csio->sglist_cnt, 0); 1785d720e6d5SJustin T. Gibbs } 1786d720e6d5SJustin T. Gibbs } 1787d720e6d5SJustin T. Gibbs if (mp->error) { 17884873663cSMatt Jacob int retval = CMD_COMPLETE; 17894873663cSMatt Jacob if (mp->error == MUSHERR_NOQENTRIES) { 17904873663cSMatt Jacob retval = CMD_EAGAIN; 17914873663cSMatt Jacob } else if (mp->error == EFBIG) { 17920a5f7e8bSMatt Jacob XS_SETERR(csio, CAM_REQ_TOO_BIG); 1793d720e6d5SJustin T. Gibbs } else if (mp->error == EINVAL) { 17940a5f7e8bSMatt Jacob XS_SETERR(csio, CAM_REQ_INVALID); 1795d720e6d5SJustin T. Gibbs } else { 17960a5f7e8bSMatt Jacob XS_SETERR(csio, CAM_UNREC_HBA_ERROR); 1797d720e6d5SJustin T. Gibbs } 17984873663cSMatt Jacob return (retval); 17990a5f7e8bSMatt Jacob } 18004fd13c1bSMatt Jacob mbxsync: 18014fd13c1bSMatt Jacob switch (rq->req_header.rqs_entry_type) { 18024fd13c1bSMatt Jacob case RQSTYPE_REQUEST: 18034fd13c1bSMatt Jacob isp_put_request(isp, rq, qep); 18044fd13c1bSMatt Jacob break; 18054fd13c1bSMatt Jacob case RQSTYPE_CMDONLY: 18064fd13c1bSMatt Jacob isp_put_extended_request(isp, (ispextreq_t *)rq, 18074fd13c1bSMatt Jacob (ispextreq_t *)qep); 18084fd13c1bSMatt Jacob break; 18094fd13c1bSMatt Jacob case RQSTYPE_T2RQS: 18104fd13c1bSMatt Jacob isp_put_request_t2(isp, (ispreqt2_t *) rq, (ispreqt2_t *) qep); 18114fd13c1bSMatt Jacob break; 18120a5f7e8bSMatt Jacob } 18134873663cSMatt Jacob return (CMD_QUEUED); 1814d720e6d5SJustin T. Gibbs } 1815d720e6d5SJustin T. Gibbs 1816d720e6d5SJustin T. Gibbs static void 1817d8d5f2adSMatt Jacob isp_pci_dmateardown(struct ispsoftc *isp, XS_T *xs, u_int16_t handle) 1818d720e6d5SJustin T. Gibbs { 18191923f739SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *)isp; 18201923f739SMatt Jacob bus_dmamap_t *dp = &pcs->dmaps[isp_handle_index(handle)]; 1821a95ae193SMatt Jacob if ((xs->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 18221923f739SMatt Jacob bus_dmamap_sync(pcs->dmat, *dp, BUS_DMASYNC_POSTREAD); 1823d720e6d5SJustin T. Gibbs } else { 18241923f739SMatt Jacob bus_dmamap_sync(pcs->dmat, *dp, BUS_DMASYNC_POSTWRITE); 1825d720e6d5SJustin T. Gibbs } 18261923f739SMatt Jacob bus_dmamap_unload(pcs->dmat, *dp); 1827d720e6d5SJustin T. Gibbs } 1828d720e6d5SJustin T. Gibbs 182965adb54cSMatt Jacob 183065adb54cSMatt Jacob static void 183117e318c6SMatt Jacob isp_pci_reset1(struct ispsoftc *isp) 183265adb54cSMatt Jacob { 183365adb54cSMatt Jacob /* Make sure the BIOS is disabled */ 183465adb54cSMatt Jacob isp_pci_wr_reg(isp, HCCR, PCI_HCCR_CMD_BIOS); 1835469b6b9eSMatt Jacob /* and enable interrupts */ 1836469b6b9eSMatt Jacob ENABLE_INTS(isp); 183765adb54cSMatt Jacob } 183865adb54cSMatt Jacob 183965adb54cSMatt Jacob static void 1840d02373f1SMatt Jacob isp_pci_dumpregs(struct ispsoftc *isp, const char *msg) 184165adb54cSMatt Jacob { 18421923f739SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *)isp; 1843d02373f1SMatt Jacob if (msg) 18446e5c5328SMatt Jacob printf("%s: %s\n", device_get_nameunit(isp->isp_dev), msg); 18456e5c5328SMatt Jacob else 18466e5c5328SMatt Jacob printf("%s:\n", device_get_nameunit(isp->isp_dev)); 1847d02373f1SMatt Jacob if (IS_SCSI(isp)) 1848d02373f1SMatt Jacob printf(" biu_conf1=%x", ISP_READ(isp, BIU_CONF1)); 1849d02373f1SMatt Jacob else 1850d02373f1SMatt Jacob printf(" biu_csr=%x", ISP_READ(isp, BIU2100_CSR)); 1851d02373f1SMatt Jacob printf(" biu_icr=%x biu_isr=%x biu_sema=%x ", ISP_READ(isp, BIU_ICR), 1852d02373f1SMatt Jacob ISP_READ(isp, BIU_ISR), ISP_READ(isp, BIU_SEMA)); 1853d02373f1SMatt Jacob printf("risc_hccr=%x\n", ISP_READ(isp, HCCR)); 1854d02373f1SMatt Jacob 1855d02373f1SMatt Jacob 1856d02373f1SMatt Jacob if (IS_SCSI(isp)) { 1857d02373f1SMatt Jacob ISP_WRITE(isp, HCCR, HCCR_CMD_PAUSE); 1858d02373f1SMatt Jacob printf(" cdma_conf=%x cdma_sts=%x cdma_fifostat=%x\n", 1859d02373f1SMatt Jacob ISP_READ(isp, CDMA_CONF), ISP_READ(isp, CDMA_STATUS), 1860d02373f1SMatt Jacob ISP_READ(isp, CDMA_FIFO_STS)); 1861d02373f1SMatt Jacob printf(" ddma_conf=%x ddma_sts=%x ddma_fifostat=%x\n", 1862d02373f1SMatt Jacob ISP_READ(isp, DDMA_CONF), ISP_READ(isp, DDMA_STATUS), 1863d02373f1SMatt Jacob ISP_READ(isp, DDMA_FIFO_STS)); 1864d02373f1SMatt Jacob printf(" sxp_int=%x sxp_gross=%x sxp(scsi_ctrl)=%x\n", 1865d02373f1SMatt Jacob ISP_READ(isp, SXP_INTERRUPT), 1866d02373f1SMatt Jacob ISP_READ(isp, SXP_GROSS_ERR), 1867d02373f1SMatt Jacob ISP_READ(isp, SXP_PINS_CTRL)); 1868d02373f1SMatt Jacob ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE); 1869d02373f1SMatt Jacob } 1870d02373f1SMatt Jacob printf(" mbox regs: %x %x %x %x %x\n", 1871d02373f1SMatt Jacob ISP_READ(isp, OUTMAILBOX0), ISP_READ(isp, OUTMAILBOX1), 1872d02373f1SMatt Jacob ISP_READ(isp, OUTMAILBOX2), ISP_READ(isp, OUTMAILBOX3), 1873d02373f1SMatt Jacob ISP_READ(isp, OUTMAILBOX4)); 1874d02373f1SMatt Jacob printf(" PCI Status Command/Status=%x\n", 18751923f739SMatt Jacob pci_read_config(pcs->pci_dev, PCIR_COMMAND, 1)); 187665adb54cSMatt Jacob } 1877