1aad970f1SDavid E. O'Brien /*- 265adb54cSMatt Jacob * PCI specific probe and attach routines for Qlogic ISP SCSI adapters. 365adb54cSMatt Jacob * FreeBSD Version. 465adb54cSMatt Jacob * 55f5aafe1SMatt Jacob * Copyright (c) 1997, 1998, 1999, 2000, 2001 by Matthew Jacob 665adb54cSMatt Jacob * 765adb54cSMatt Jacob * Redistribution and use in source and binary forms, with or without 865adb54cSMatt Jacob * modification, are permitted provided that the following conditions 965adb54cSMatt Jacob * are met: 1065adb54cSMatt Jacob * 1. Redistributions of source code must retain the above copyright 1165adb54cSMatt Jacob * notice immediately at the beginning of the file, without modification, 1265adb54cSMatt Jacob * this list of conditions, and the following disclaimer. 13aa57fd6fSMatt Jacob * 2. The name of the author may not be used to endorse or promote products 14aa57fd6fSMatt Jacob * derived from this software without specific prior written permission. 1565adb54cSMatt Jacob * 1665adb54cSMatt Jacob * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1765adb54cSMatt Jacob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1865adb54cSMatt Jacob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1965adb54cSMatt Jacob * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2065adb54cSMatt Jacob * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2165adb54cSMatt Jacob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2265adb54cSMatt Jacob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2365adb54cSMatt Jacob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2465adb54cSMatt Jacob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2565adb54cSMatt Jacob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2665adb54cSMatt Jacob * SUCH DAMAGE. 2765adb54cSMatt Jacob */ 28d720e6d5SJustin T. Gibbs 29aad970f1SDavid E. O'Brien #include <sys/cdefs.h> 30aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$"); 31aad970f1SDavid E. O'Brien 32960f6939SMatt Jacob #include <sys/param.h> 33960f6939SMatt Jacob #include <sys/systm.h> 34960f6939SMatt Jacob #include <sys/kernel.h> 35960f6939SMatt Jacob #include <sys/module.h> 36960f6939SMatt Jacob #include <sys/bus.h> 3765adb54cSMatt Jacob 3877e6a3b2SWarner Losh #include <dev/pci/pcireg.h> 3977e6a3b2SWarner Losh #include <dev/pci/pcivar.h> 4065adb54cSMatt Jacob 41d720e6d5SJustin T. Gibbs #include <machine/bus_memio.h> 42d720e6d5SJustin T. Gibbs #include <machine/bus_pio.h> 43d720e6d5SJustin T. Gibbs #include <machine/bus.h> 44960f6939SMatt Jacob #include <machine/resource.h> 45960f6939SMatt Jacob #include <sys/rman.h> 46960f6939SMatt Jacob #include <sys/malloc.h> 47960f6939SMatt Jacob 48960f6939SMatt Jacob #include <dev/isp/isp_freebsd.h> 49d59bd469SMatt Jacob 50126ec864SMatt Jacob static u_int16_t isp_pci_rd_reg(struct ispsoftc *, int); 51126ec864SMatt Jacob static void isp_pci_wr_reg(struct ispsoftc *, int, u_int16_t); 52126ec864SMatt Jacob static u_int16_t isp_pci_rd_reg_1080(struct ispsoftc *, int); 53126ec864SMatt Jacob static void isp_pci_wr_reg_1080(struct ispsoftc *, int, u_int16_t); 54126ec864SMatt Jacob static int 55126ec864SMatt Jacob isp_pci_rd_isr(struct ispsoftc *, u_int16_t *, u_int16_t *, u_int16_t *); 56126ec864SMatt Jacob static int 57126ec864SMatt Jacob isp_pci_rd_isr_2300(struct ispsoftc *, u_int16_t *, u_int16_t *, u_int16_t *); 58126ec864SMatt Jacob static int isp_pci_mbxdma(struct ispsoftc *); 59126ec864SMatt Jacob static int 60126ec864SMatt Jacob isp_pci_dmasetup(struct ispsoftc *, XS_T *, ispreq_t *, u_int16_t *, u_int16_t); 61d720e6d5SJustin T. Gibbs static void 62126ec864SMatt Jacob isp_pci_dmateardown(struct ispsoftc *, XS_T *, u_int16_t); 6365adb54cSMatt Jacob 64126ec864SMatt Jacob static void isp_pci_reset1(struct ispsoftc *); 65126ec864SMatt Jacob static void isp_pci_dumpregs(struct ispsoftc *, const char *); 6665adb54cSMatt Jacob 6765adb54cSMatt Jacob static struct ispmdvec mdvec = { 68126ec864SMatt Jacob isp_pci_rd_isr, 6965adb54cSMatt Jacob isp_pci_rd_reg, 7065adb54cSMatt Jacob isp_pci_wr_reg, 7165adb54cSMatt Jacob isp_pci_mbxdma, 7265adb54cSMatt Jacob isp_pci_dmasetup, 73d720e6d5SJustin T. Gibbs isp_pci_dmateardown, 7465adb54cSMatt Jacob NULL, 7565adb54cSMatt Jacob isp_pci_reset1, 7665adb54cSMatt Jacob isp_pci_dumpregs, 7756aef503SMatt Jacob NULL, 78d02373f1SMatt Jacob BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64 7965adb54cSMatt Jacob }; 8065adb54cSMatt Jacob 81d59bd469SMatt Jacob static struct ispmdvec mdvec_1080 = { 82126ec864SMatt Jacob isp_pci_rd_isr, 83d59bd469SMatt Jacob isp_pci_rd_reg_1080, 84d59bd469SMatt Jacob isp_pci_wr_reg_1080, 85d59bd469SMatt Jacob isp_pci_mbxdma, 86d59bd469SMatt Jacob isp_pci_dmasetup, 87d59bd469SMatt Jacob isp_pci_dmateardown, 88d59bd469SMatt Jacob NULL, 89d59bd469SMatt Jacob isp_pci_reset1, 90d59bd469SMatt Jacob isp_pci_dumpregs, 9156aef503SMatt Jacob NULL, 92d02373f1SMatt Jacob BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64 93d59bd469SMatt Jacob }; 94d59bd469SMatt Jacob 95960f6939SMatt Jacob static struct ispmdvec mdvec_12160 = { 96126ec864SMatt Jacob isp_pci_rd_isr, 97960f6939SMatt Jacob isp_pci_rd_reg_1080, 98960f6939SMatt Jacob isp_pci_wr_reg_1080, 99960f6939SMatt Jacob isp_pci_mbxdma, 100960f6939SMatt Jacob isp_pci_dmasetup, 101960f6939SMatt Jacob isp_pci_dmateardown, 102960f6939SMatt Jacob NULL, 103960f6939SMatt Jacob isp_pci_reset1, 104960f6939SMatt Jacob isp_pci_dumpregs, 10556aef503SMatt Jacob NULL, 106d02373f1SMatt Jacob BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64 107960f6939SMatt Jacob }; 108960f6939SMatt Jacob 10965adb54cSMatt Jacob static struct ispmdvec mdvec_2100 = { 110126ec864SMatt Jacob isp_pci_rd_isr, 11165adb54cSMatt Jacob isp_pci_rd_reg, 11265adb54cSMatt Jacob isp_pci_wr_reg, 11365adb54cSMatt Jacob isp_pci_mbxdma, 11465adb54cSMatt Jacob isp_pci_dmasetup, 115d720e6d5SJustin T. Gibbs isp_pci_dmateardown, 11665adb54cSMatt Jacob NULL, 11765adb54cSMatt Jacob isp_pci_reset1, 118d02373f1SMatt Jacob isp_pci_dumpregs 11965adb54cSMatt Jacob }; 120222bb542SMatt Jacob 121222bb542SMatt Jacob static struct ispmdvec mdvec_2200 = { 122126ec864SMatt Jacob isp_pci_rd_isr, 123126ec864SMatt Jacob isp_pci_rd_reg, 124126ec864SMatt Jacob isp_pci_wr_reg, 125126ec864SMatt Jacob isp_pci_mbxdma, 126126ec864SMatt Jacob isp_pci_dmasetup, 127126ec864SMatt Jacob isp_pci_dmateardown, 128126ec864SMatt Jacob NULL, 129126ec864SMatt Jacob isp_pci_reset1, 130126ec864SMatt Jacob isp_pci_dumpregs 131126ec864SMatt Jacob }; 132126ec864SMatt Jacob 133126ec864SMatt Jacob static struct ispmdvec mdvec_2300 = { 134126ec864SMatt Jacob isp_pci_rd_isr_2300, 135222bb542SMatt Jacob isp_pci_rd_reg, 136222bb542SMatt Jacob isp_pci_wr_reg, 137222bb542SMatt Jacob isp_pci_mbxdma, 138222bb542SMatt Jacob isp_pci_dmasetup, 139222bb542SMatt Jacob isp_pci_dmateardown, 140222bb542SMatt Jacob NULL, 141222bb542SMatt Jacob isp_pci_reset1, 142d02373f1SMatt Jacob isp_pci_dumpregs 143222bb542SMatt Jacob }; 144d951bbcaSMatt Jacob 14565adb54cSMatt Jacob #ifndef PCIM_CMD_INVEN 14665adb54cSMatt Jacob #define PCIM_CMD_INVEN 0x10 14765adb54cSMatt Jacob #endif 14865adb54cSMatt Jacob #ifndef PCIM_CMD_BUSMASTEREN 14965adb54cSMatt Jacob #define PCIM_CMD_BUSMASTEREN 0x0004 15065adb54cSMatt Jacob #endif 151d951bbcaSMatt Jacob #ifndef PCIM_CMD_PERRESPEN 152d951bbcaSMatt Jacob #define PCIM_CMD_PERRESPEN 0x0040 153d951bbcaSMatt Jacob #endif 154d951bbcaSMatt Jacob #ifndef PCIM_CMD_SEREN 155d951bbcaSMatt Jacob #define PCIM_CMD_SEREN 0x0100 156d951bbcaSMatt Jacob #endif 157d951bbcaSMatt Jacob 158d951bbcaSMatt Jacob #ifndef PCIR_COMMAND 159d951bbcaSMatt Jacob #define PCIR_COMMAND 0x04 160d951bbcaSMatt Jacob #endif 161d951bbcaSMatt Jacob 162d951bbcaSMatt Jacob #ifndef PCIR_CACHELNSZ 163d951bbcaSMatt Jacob #define PCIR_CACHELNSZ 0x0c 164d951bbcaSMatt Jacob #endif 165d951bbcaSMatt Jacob 166d951bbcaSMatt Jacob #ifndef PCIR_LATTIMER 167d951bbcaSMatt Jacob #define PCIR_LATTIMER 0x0d 168d951bbcaSMatt Jacob #endif 169d951bbcaSMatt Jacob 170ab6d0040SMatt Jacob #ifndef PCIR_ROMADDR 171ab6d0040SMatt Jacob #define PCIR_ROMADDR 0x30 172ab6d0040SMatt Jacob #endif 173ab6d0040SMatt Jacob 17465adb54cSMatt Jacob #ifndef PCI_VENDOR_QLOGIC 17565adb54cSMatt Jacob #define PCI_VENDOR_QLOGIC 0x1077 17665adb54cSMatt Jacob #endif 17765adb54cSMatt Jacob 17865adb54cSMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP1020 17965adb54cSMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP1020 0x1020 18065adb54cSMatt Jacob #endif 18165adb54cSMatt Jacob 182d59bd469SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP1080 183d59bd469SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP1080 0x1080 184d59bd469SMatt Jacob #endif 185d59bd469SMatt Jacob 186f556e83bSMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP10160 187f556e83bSMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP10160 0x1016 188f556e83bSMatt Jacob #endif 189f556e83bSMatt Jacob 190960f6939SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP12160 191960f6939SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP12160 0x1216 192960f6939SMatt Jacob #endif 193960f6939SMatt Jacob 194d59bd469SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP1240 195d59bd469SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP1240 0x1240 196d59bd469SMatt Jacob #endif 19765adb54cSMatt Jacob 19822e1dc85SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP1280 19922e1dc85SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP1280 0x1280 20022e1dc85SMatt Jacob #endif 20122e1dc85SMatt Jacob 20265adb54cSMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP2100 20365adb54cSMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP2100 0x2100 20465adb54cSMatt Jacob #endif 20565adb54cSMatt Jacob 206222bb542SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP2200 207222bb542SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP2200 0x2200 208222bb542SMatt Jacob #endif 209222bb542SMatt Jacob 210126ec864SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP2300 211126ec864SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP2300 0x2300 212126ec864SMatt Jacob #endif 213126ec864SMatt Jacob 214126ec864SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP2312 215126ec864SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP2312 0x2312 216126ec864SMatt Jacob #endif 217126ec864SMatt Jacob 21856aef503SMatt Jacob #define PCI_QLOGIC_ISP1020 \ 21956aef503SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP1020 << 16) | PCI_VENDOR_QLOGIC) 220d59bd469SMatt Jacob 221d59bd469SMatt Jacob #define PCI_QLOGIC_ISP1080 \ 222d59bd469SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP1080 << 16) | PCI_VENDOR_QLOGIC) 223d59bd469SMatt Jacob 224f556e83bSMatt Jacob #define PCI_QLOGIC_ISP10160 \ 225f556e83bSMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP10160 << 16) | PCI_VENDOR_QLOGIC) 226f556e83bSMatt Jacob 227960f6939SMatt Jacob #define PCI_QLOGIC_ISP12160 \ 228960f6939SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP12160 << 16) | PCI_VENDOR_QLOGIC) 229960f6939SMatt Jacob 230d59bd469SMatt Jacob #define PCI_QLOGIC_ISP1240 \ 231d59bd469SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP1240 << 16) | PCI_VENDOR_QLOGIC) 232d59bd469SMatt Jacob 23322e1dc85SMatt Jacob #define PCI_QLOGIC_ISP1280 \ 23422e1dc85SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP1280 << 16) | PCI_VENDOR_QLOGIC) 23522e1dc85SMatt Jacob 23665adb54cSMatt Jacob #define PCI_QLOGIC_ISP2100 \ 23765adb54cSMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP2100 << 16) | PCI_VENDOR_QLOGIC) 23865adb54cSMatt Jacob 239222bb542SMatt Jacob #define PCI_QLOGIC_ISP2200 \ 240222bb542SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP2200 << 16) | PCI_VENDOR_QLOGIC) 241222bb542SMatt Jacob 242126ec864SMatt Jacob #define PCI_QLOGIC_ISP2300 \ 243126ec864SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP2300 << 16) | PCI_VENDOR_QLOGIC) 244126ec864SMatt Jacob 245126ec864SMatt Jacob #define PCI_QLOGIC_ISP2312 \ 246126ec864SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP2312 << 16) | PCI_VENDOR_QLOGIC) 247126ec864SMatt Jacob 248e11a1ee8SMatt Jacob /* 249e11a1ee8SMatt Jacob * Odd case for some AMI raid cards... We need to *not* attach to this. 250e11a1ee8SMatt Jacob */ 251e11a1ee8SMatt Jacob #define AMI_RAID_SUBVENDOR_ID 0x101e 252e11a1ee8SMatt Jacob 25365adb54cSMatt Jacob #define IO_MAP_REG 0x10 25465adb54cSMatt Jacob #define MEM_MAP_REG 0x14 25565adb54cSMatt Jacob 256d951bbcaSMatt Jacob #define PCI_DFLT_LTNCY 0x40 257d951bbcaSMatt Jacob #define PCI_DFLT_LNSZ 0x10 25865adb54cSMatt Jacob 259960f6939SMatt Jacob static int isp_pci_probe (device_t); 260960f6939SMatt Jacob static int isp_pci_attach (device_t); 26165adb54cSMatt Jacob 2621923f739SMatt Jacob 26365adb54cSMatt Jacob struct isp_pcisoftc { 26465adb54cSMatt Jacob struct ispsoftc pci_isp; 265960f6939SMatt Jacob device_t pci_dev; 266960f6939SMatt Jacob struct resource * pci_reg; 26765adb54cSMatt Jacob bus_space_tag_t pci_st; 26865adb54cSMatt Jacob bus_space_handle_t pci_sh; 269960f6939SMatt Jacob void * ih; 270d59bd469SMatt Jacob int16_t pci_poff[_NREG_BLKS]; 2711923f739SMatt Jacob bus_dma_tag_t dmat; 272a95ae193SMatt Jacob bus_dmamap_t *dmaps; 27365adb54cSMatt Jacob }; 27473030e03SMatt Jacob extern ispfwfunc *isp_get_firmware_p; 27565adb54cSMatt Jacob 276960f6939SMatt Jacob static device_method_t isp_pci_methods[] = { 277960f6939SMatt Jacob /* Device interface */ 278960f6939SMatt Jacob DEVMETHOD(device_probe, isp_pci_probe), 279960f6939SMatt Jacob DEVMETHOD(device_attach, isp_pci_attach), 280960f6939SMatt Jacob { 0, 0 } 28165adb54cSMatt Jacob }; 282126ec864SMatt Jacob static void isp_pci_intr(void *); 28365adb54cSMatt Jacob 284960f6939SMatt Jacob static driver_t isp_pci_driver = { 285960f6939SMatt Jacob "isp", isp_pci_methods, sizeof (struct isp_pcisoftc) 286960f6939SMatt Jacob }; 287960f6939SMatt Jacob static devclass_t isp_devclass; 288960f6939SMatt Jacob DRIVER_MODULE(isp, pci, isp_pci_driver, isp_devclass, 0, 0); 28965adb54cSMatt Jacob 290960f6939SMatt Jacob static int 291960f6939SMatt Jacob isp_pci_probe(device_t dev) 29265adb54cSMatt Jacob { 293960f6939SMatt Jacob switch ((pci_get_device(dev) << 16) | (pci_get_vendor(dev))) { 29456aef503SMatt Jacob case PCI_QLOGIC_ISP1020: 295960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 1020/1040 PCI SCSI Adapter"); 29665adb54cSMatt Jacob break; 297d59bd469SMatt Jacob case PCI_QLOGIC_ISP1080: 298960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 1080 PCI SCSI Adapter"); 299c6608df3SMatt Jacob break; 300c6608df3SMatt Jacob case PCI_QLOGIC_ISP1240: 301960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 1240 PCI SCSI Adapter"); 302d59bd469SMatt Jacob break; 30322e1dc85SMatt Jacob case PCI_QLOGIC_ISP1280: 304960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 1280 PCI SCSI Adapter"); 305960f6939SMatt Jacob break; 306f556e83bSMatt Jacob case PCI_QLOGIC_ISP10160: 307f556e83bSMatt Jacob device_set_desc(dev, "Qlogic ISP 10160 PCI SCSI Adapter"); 308f556e83bSMatt Jacob break; 309960f6939SMatt Jacob case PCI_QLOGIC_ISP12160: 310e11a1ee8SMatt Jacob if (pci_get_subvendor(dev) == AMI_RAID_SUBVENDOR_ID) { 311e11a1ee8SMatt Jacob return (ENXIO); 312e11a1ee8SMatt Jacob } 313960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 12160 PCI SCSI Adapter"); 31422e1dc85SMatt Jacob break; 31565adb54cSMatt Jacob case PCI_QLOGIC_ISP2100: 316960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 2100 PCI FC-AL Adapter"); 31765adb54cSMatt Jacob break; 3185542fe4bSMatt Jacob case PCI_QLOGIC_ISP2200: 319960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 2200 PCI FC-AL Adapter"); 3205542fe4bSMatt Jacob break; 321126ec864SMatt Jacob case PCI_QLOGIC_ISP2300: 322126ec864SMatt Jacob device_set_desc(dev, "Qlogic ISP 2300 PCI FC-AL Adapter"); 323126ec864SMatt Jacob break; 324126ec864SMatt Jacob case PCI_QLOGIC_ISP2312: 325126ec864SMatt Jacob device_set_desc(dev, "Qlogic ISP 2312 PCI FC-AL Adapter"); 326126ec864SMatt Jacob break; 32765adb54cSMatt Jacob default: 328960f6939SMatt Jacob return (ENXIO); 32965adb54cSMatt Jacob } 33073030e03SMatt Jacob if (isp_announced == 0 && bootverbose) { 331d02373f1SMatt Jacob printf("Qlogic ISP Driver, FreeBSD Version %d.%d, " 332a95ae193SMatt Jacob "Core Version %d.%d\n", 333d720e6d5SJustin T. Gibbs ISP_PLATFORM_VERSION_MAJOR, ISP_PLATFORM_VERSION_MINOR, 334d720e6d5SJustin T. Gibbs ISP_CORE_VERSION_MAJOR, ISP_CORE_VERSION_MINOR); 33573030e03SMatt Jacob isp_announced++; 33665adb54cSMatt Jacob } 33756aef503SMatt Jacob /* 33856aef503SMatt Jacob * XXXX: Here is where we might load the f/w module 33956aef503SMatt Jacob * XXXX: (or increase a reference count to it). 34056aef503SMatt Jacob */ 341960f6939SMatt Jacob return (0); 34265adb54cSMatt Jacob } 34365adb54cSMatt Jacob 344960f6939SMatt Jacob static int 345960f6939SMatt Jacob isp_pci_attach(device_t dev) 34665adb54cSMatt Jacob { 347960f6939SMatt Jacob struct resource *regs, *irq; 3486e5c5328SMatt Jacob int tval, rtp, rgd, iqd, m1, m2, isp_debug, role; 349960f6939SMatt Jacob u_int32_t data, cmd, linesz, psize, basetype; 35065adb54cSMatt Jacob struct isp_pcisoftc *pcs; 3513395b056SMatt Jacob struct ispsoftc *isp = NULL; 352c6608df3SMatt Jacob struct ispmdvec *mdvp; 35322941bd7SPeter Wemm const char *sptr; 3543395b056SMatt Jacob int locksetup = 0; 35565adb54cSMatt Jacob 356222bb542SMatt Jacob /* 3579ba86737SMatt Jacob * Figure out if we're supposed to skip this one. 3589ba86737SMatt Jacob */ 3596e5c5328SMatt Jacob 3606e5c5328SMatt Jacob tval = 0; 3616e5c5328SMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 3626e5c5328SMatt Jacob "disable", &tval) == 0 && tval) { 363b9b599feSMatt Jacob device_printf(dev, "device is disabled\n"); 364b9b599feSMatt Jacob /* but return 0 so the !$)$)*!$*) unit isn't reused */ 365b9b599feSMatt Jacob return (0); 366b9b599feSMatt Jacob } 3676e5c5328SMatt Jacob 36887ab7d39SMatt Jacob role = -1; 3696e5c5328SMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 37087ab7d39SMatt Jacob "role", &role) == 0 && role != -1) { 37187ab7d39SMatt Jacob role &= (ISP_ROLE_INITIATOR|ISP_ROLE_TARGET); 3726e5c5328SMatt Jacob device_printf(dev, "setting role to 0x%x\n", role); 3736e5c5328SMatt Jacob } else { 374b9b599feSMatt Jacob #ifdef ISP_TARGET_MODE 37587ab7d39SMatt Jacob role = ISP_ROLE_TARGET; 376b9b599feSMatt Jacob #else 377b9b599feSMatt Jacob role = ISP_DEFAULT_ROLES; 378b9b599feSMatt Jacob #endif 3799ba86737SMatt Jacob } 3809ba86737SMatt Jacob 3817cc0979fSDavid Malone pcs = malloc(sizeof (struct isp_pcisoftc), M_DEVBUF, M_NOWAIT | M_ZERO); 382960f6939SMatt Jacob if (pcs == NULL) { 383960f6939SMatt Jacob device_printf(dev, "cannot allocate softc\n"); 384960f6939SMatt Jacob return (ENOMEM); 385960f6939SMatt Jacob } 386960f6939SMatt Jacob 3879ba86737SMatt Jacob /* 388222bb542SMatt Jacob * Figure out which we should try first - memory mapping or i/o mapping? 389222bb542SMatt Jacob */ 39056aef503SMatt Jacob #ifdef __alpha__ 391960f6939SMatt Jacob m1 = PCIM_CMD_MEMEN; 392960f6939SMatt Jacob m2 = PCIM_CMD_PORTEN; 393222bb542SMatt Jacob #else 394960f6939SMatt Jacob m1 = PCIM_CMD_PORTEN; 395960f6939SMatt Jacob m2 = PCIM_CMD_MEMEN; 396222bb542SMatt Jacob #endif 3976e5c5328SMatt Jacob 3986e5c5328SMatt Jacob tval = 0; 3996e5c5328SMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 4006e5c5328SMatt Jacob "prefer_iomap", &tval) == 0 && tval != 0) { 401960f6939SMatt Jacob m1 = PCIM_CMD_PORTEN; 402960f6939SMatt Jacob m2 = PCIM_CMD_MEMEN; 403960f6939SMatt Jacob } 4046e5c5328SMatt Jacob tval = 0; 4056e5c5328SMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 4066e5c5328SMatt Jacob "prefer_memmap", &tval) == 0 && tval != 0) { 4076e5c5328SMatt Jacob m1 = PCIM_CMD_MEMEN; 4086e5c5328SMatt Jacob m2 = PCIM_CMD_PORTEN; 409222bb542SMatt Jacob } 410222bb542SMatt Jacob 411ab6d0040SMatt Jacob linesz = PCI_DFLT_LNSZ; 412960f6939SMatt Jacob irq = regs = NULL; 413960f6939SMatt Jacob rgd = rtp = iqd = 0; 414960f6939SMatt Jacob 415960f6939SMatt Jacob cmd = pci_read_config(dev, PCIR_COMMAND, 1); 416960f6939SMatt Jacob if (cmd & m1) { 417960f6939SMatt Jacob rtp = (m1 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT; 418960f6939SMatt Jacob rgd = (m1 == PCIM_CMD_MEMEN)? MEM_MAP_REG : IO_MAP_REG; 4195f96beb9SNate Lawson regs = bus_alloc_resource_any(dev, rtp, &rgd, RF_ACTIVE); 42065adb54cSMatt Jacob } 421960f6939SMatt Jacob if (regs == NULL && (cmd & m2)) { 422960f6939SMatt Jacob rtp = (m2 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT; 423960f6939SMatt Jacob rgd = (m2 == PCIM_CMD_MEMEN)? MEM_MAP_REG : IO_MAP_REG; 4245f96beb9SNate Lawson regs = bus_alloc_resource_any(dev, rtp, &rgd, RF_ACTIVE); 42565adb54cSMatt Jacob } 426960f6939SMatt Jacob if (regs == NULL) { 427960f6939SMatt Jacob device_printf(dev, "unable to map any ports\n"); 428960f6939SMatt Jacob goto bad; 42965adb54cSMatt Jacob } 430222bb542SMatt Jacob if (bootverbose) 431f7dddf8aSMatt Jacob device_printf(dev, "using %s space register mapping\n", 432960f6939SMatt Jacob (rgd == IO_MAP_REG)? "I/O" : "Memory"); 433960f6939SMatt Jacob pcs->pci_dev = dev; 434960f6939SMatt Jacob pcs->pci_reg = regs; 435960f6939SMatt Jacob pcs->pci_st = rman_get_bustag(regs); 436960f6939SMatt Jacob pcs->pci_sh = rman_get_bushandle(regs); 43765adb54cSMatt Jacob 438d59bd469SMatt Jacob pcs->pci_poff[BIU_BLOCK >> _BLK_REG_SHFT] = BIU_REGS_OFF; 439d59bd469SMatt Jacob pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS_OFF; 440d59bd469SMatt Jacob pcs->pci_poff[SXP_BLOCK >> _BLK_REG_SHFT] = PCI_SXP_REGS_OFF; 441d59bd469SMatt Jacob pcs->pci_poff[RISC_BLOCK >> _BLK_REG_SHFT] = PCI_RISC_REGS_OFF; 442d59bd469SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = DMA_REGS_OFF; 443c6608df3SMatt Jacob mdvp = &mdvec; 444c6608df3SMatt Jacob basetype = ISP_HA_SCSI_UNKNOWN; 445c6608df3SMatt Jacob psize = sizeof (sdparam); 44656aef503SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP1020) { 447c6608df3SMatt Jacob mdvp = &mdvec; 448c6608df3SMatt Jacob basetype = ISP_HA_SCSI_UNKNOWN; 449c6608df3SMatt Jacob psize = sizeof (sdparam); 450d59bd469SMatt Jacob } 451960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP1080) { 452c6608df3SMatt Jacob mdvp = &mdvec_1080; 453c6608df3SMatt Jacob basetype = ISP_HA_SCSI_1080; 454c6608df3SMatt Jacob psize = sizeof (sdparam); 455c6608df3SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 456c6608df3SMatt Jacob ISP1080_DMA_REGS_OFF; 457c6608df3SMatt Jacob } 458960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP1240) { 459c6608df3SMatt Jacob mdvp = &mdvec_1080; 46022e1dc85SMatt Jacob basetype = ISP_HA_SCSI_1240; 46122e1dc85SMatt Jacob psize = 2 * sizeof (sdparam); 46222e1dc85SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 46322e1dc85SMatt Jacob ISP1080_DMA_REGS_OFF; 46422e1dc85SMatt Jacob } 465960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP1280) { 46622e1dc85SMatt Jacob mdvp = &mdvec_1080; 46722e1dc85SMatt Jacob basetype = ISP_HA_SCSI_1280; 468c6608df3SMatt Jacob psize = 2 * sizeof (sdparam); 469d59bd469SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 470d59bd469SMatt Jacob ISP1080_DMA_REGS_OFF; 471d59bd469SMatt Jacob } 472f556e83bSMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP10160) { 473f556e83bSMatt Jacob mdvp = &mdvec_12160; 474f556e83bSMatt Jacob basetype = ISP_HA_SCSI_10160; 475f556e83bSMatt Jacob psize = sizeof (sdparam); 476f556e83bSMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 477f556e83bSMatt Jacob ISP1080_DMA_REGS_OFF; 478f556e83bSMatt Jacob } 479960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP12160) { 480960f6939SMatt Jacob mdvp = &mdvec_12160; 481960f6939SMatt Jacob basetype = ISP_HA_SCSI_12160; 482960f6939SMatt Jacob psize = 2 * sizeof (sdparam); 483960f6939SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 484960f6939SMatt Jacob ISP1080_DMA_REGS_OFF; 485960f6939SMatt Jacob } 486960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP2100) { 487c6608df3SMatt Jacob mdvp = &mdvec_2100; 488c6608df3SMatt Jacob basetype = ISP_HA_FC_2100; 489c6608df3SMatt Jacob psize = sizeof (fcparam); 490d59bd469SMatt Jacob pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = 491d59bd469SMatt Jacob PCI_MBOX_REGS2100_OFF; 492960f6939SMatt Jacob if (pci_get_revid(dev) < 3) { 493ab6d0040SMatt Jacob /* 494ab6d0040SMatt Jacob * XXX: Need to get the actual revision 495ab6d0040SMatt Jacob * XXX: number of the 2100 FB. At any rate, 496ab6d0040SMatt Jacob * XXX: lower cache line size for early revision 497ab6d0040SMatt Jacob * XXX; boards. 498ab6d0040SMatt Jacob */ 499ab6d0040SMatt Jacob linesz = 1; 500ab6d0040SMatt Jacob } 50165adb54cSMatt Jacob } 502960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP2200) { 503222bb542SMatt Jacob mdvp = &mdvec_2200; 504222bb542SMatt Jacob basetype = ISP_HA_FC_2200; 505222bb542SMatt Jacob psize = sizeof (fcparam); 506222bb542SMatt Jacob pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = 507222bb542SMatt Jacob PCI_MBOX_REGS2100_OFF; 508222bb542SMatt Jacob } 50975c1e828SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP2300) { 510126ec864SMatt Jacob mdvp = &mdvec_2300; 511126ec864SMatt Jacob basetype = ISP_HA_FC_2300; 512126ec864SMatt Jacob psize = sizeof (fcparam); 513126ec864SMatt Jacob pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = 514126ec864SMatt Jacob PCI_MBOX_REGS2300_OFF; 515126ec864SMatt Jacob } 51675c1e828SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP2312) { 51775c1e828SMatt Jacob mdvp = &mdvec_2300; 51875c1e828SMatt Jacob basetype = ISP_HA_FC_2312; 51975c1e828SMatt Jacob psize = sizeof (fcparam); 52075c1e828SMatt Jacob pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = 52175c1e828SMatt Jacob PCI_MBOX_REGS2300_OFF; 52275c1e828SMatt Jacob } 523c6608df3SMatt Jacob isp = &pcs->pci_isp; 5247cc0979fSDavid Malone isp->isp_param = malloc(psize, M_DEVBUF, M_NOWAIT | M_ZERO); 525c6608df3SMatt Jacob if (isp->isp_param == NULL) { 526960f6939SMatt Jacob device_printf(dev, "cannot allocate parameter data\n"); 527960f6939SMatt Jacob goto bad; 528c6608df3SMatt Jacob } 529c6608df3SMatt Jacob isp->isp_mdvec = mdvp; 530c6608df3SMatt Jacob isp->isp_type = basetype; 531960f6939SMatt Jacob isp->isp_revision = pci_get_revid(dev); 532b9b599feSMatt Jacob isp->isp_role = role; 5336e5c5328SMatt Jacob isp->isp_dev = dev; 53465adb54cSMatt Jacob 53556aef503SMatt Jacob /* 53656aef503SMatt Jacob * Try and find firmware for this device. 53756aef503SMatt Jacob */ 53856aef503SMatt Jacob 53956aef503SMatt Jacob if (isp_get_firmware_p) { 54056aef503SMatt Jacob int device = (int) pci_get_device(dev); 54156aef503SMatt Jacob #ifdef ISP_TARGET_MODE 54256aef503SMatt Jacob (*isp_get_firmware_p)(0, 1, device, &mdvp->dv_ispfw); 54356aef503SMatt Jacob #else 54456aef503SMatt Jacob (*isp_get_firmware_p)(0, 0, device, &mdvp->dv_ispfw); 54556aef503SMatt Jacob #endif 54656aef503SMatt Jacob } 54756aef503SMatt Jacob 54856aef503SMatt Jacob /* 549d951bbcaSMatt Jacob * Make sure that SERR, PERR, WRITE INVALIDATE and BUSMASTER 550d951bbcaSMatt Jacob * are set. 551d951bbcaSMatt Jacob */ 552960f6939SMatt Jacob cmd |= PCIM_CMD_SEREN | PCIM_CMD_PERRESPEN | 553960f6939SMatt Jacob PCIM_CMD_BUSMASTEREN | PCIM_CMD_INVEN; 55475c1e828SMatt Jacob if (IS_2300(isp)) { /* per QLogic errata */ 55575c1e828SMatt Jacob cmd &= ~PCIM_CMD_INVEN; 55675c1e828SMatt Jacob } 557fc087171SMatt Jacob if (IS_23XX(isp)) { 558fc087171SMatt Jacob /* 559fc087171SMatt Jacob * Can't tell if ROM will hang on 'ABOUT FIRMWARE' command. 560fc087171SMatt Jacob */ 561fc087171SMatt Jacob isp->isp_touched = 1; 562fc087171SMatt Jacob 563fc087171SMatt Jacob } 564960f6939SMatt Jacob pci_write_config(dev, PCIR_COMMAND, cmd, 1); 565ab6d0040SMatt Jacob 566d951bbcaSMatt Jacob /* 567222bb542SMatt Jacob * Make sure the Cache Line Size register is set sensibly. 568d951bbcaSMatt Jacob */ 569960f6939SMatt Jacob data = pci_read_config(dev, PCIR_CACHELNSZ, 1); 570ab6d0040SMatt Jacob if (data != linesz) { 571d951bbcaSMatt Jacob data = PCI_DFLT_LNSZ; 572d02373f1SMatt Jacob isp_prt(isp, ISP_LOGCONFIG, "set PCI line size to %d", data); 573960f6939SMatt Jacob pci_write_config(dev, PCIR_CACHELNSZ, data, 1); 574d951bbcaSMatt Jacob } 575ab6d0040SMatt Jacob 576d951bbcaSMatt Jacob /* 577d951bbcaSMatt Jacob * Make sure the Latency Timer is sane. 578d951bbcaSMatt Jacob */ 579960f6939SMatt Jacob data = pci_read_config(dev, PCIR_LATTIMER, 1); 580d951bbcaSMatt Jacob if (data < PCI_DFLT_LTNCY) { 581d951bbcaSMatt Jacob data = PCI_DFLT_LTNCY; 582d02373f1SMatt Jacob isp_prt(isp, ISP_LOGCONFIG, "set PCI latency to %d", data); 583960f6939SMatt Jacob pci_write_config(dev, PCIR_LATTIMER, data, 1); 584d951bbcaSMatt Jacob } 585ab6d0040SMatt Jacob 586ab6d0040SMatt Jacob /* 587ab6d0040SMatt Jacob * Make sure we've disabled the ROM. 588ab6d0040SMatt Jacob */ 589960f6939SMatt Jacob data = pci_read_config(dev, PCIR_ROMADDR, 4); 590ab6d0040SMatt Jacob data &= ~1; 591960f6939SMatt Jacob pci_write_config(dev, PCIR_ROMADDR, data, 4); 59205fbcbb0SMatt Jacob 593960f6939SMatt Jacob iqd = 0; 5945f96beb9SNate Lawson irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &iqd, 5955f96beb9SNate Lawson RF_ACTIVE | RF_SHAREABLE); 596960f6939SMatt Jacob if (irq == NULL) { 597960f6939SMatt Jacob device_printf(dev, "could not allocate interrupt\n"); 598960f6939SMatt Jacob goto bad; 599960f6939SMatt Jacob } 600960f6939SMatt Jacob 6016e5c5328SMatt Jacob tval = 0; 6026e5c5328SMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 6036e5c5328SMatt Jacob "fwload_disable", &tval) == 0 && tval != 0) { 604222bb542SMatt Jacob isp->isp_confopts |= ISP_CFG_NORELOAD; 605222bb542SMatt Jacob } 6066e5c5328SMatt Jacob tval = 0; 6076e5c5328SMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 6086e5c5328SMatt Jacob "ignore_nvram", &tval) == 0 && tval != 0) { 609222bb542SMatt Jacob isp->isp_confopts |= ISP_CFG_NONVRAM; 610222bb542SMatt Jacob } 6116e5c5328SMatt Jacob tval = 0; 6126e5c5328SMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 6136e5c5328SMatt Jacob "fullduplex", &tval) == 0 && tval != 0) { 614222bb542SMatt Jacob isp->isp_confopts |= ISP_CFG_FULL_DUPLEX; 615222bb542SMatt Jacob } 616d134aa0bSMatt Jacob #ifdef ISP_FW_CRASH_DUMP 617d134aa0bSMatt Jacob tval = 0; 618d134aa0bSMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 619d134aa0bSMatt Jacob "fw_dump_enable", &tval) == 0 && tval != 0) { 620d134aa0bSMatt Jacob size_t amt = 0; 621d134aa0bSMatt Jacob if (IS_2200(isp)) { 622d134aa0bSMatt Jacob amt = QLA2200_RISC_IMAGE_DUMP_SIZE; 623d134aa0bSMatt Jacob } else if (IS_23XX(isp)) { 624d134aa0bSMatt Jacob amt = QLA2300_RISC_IMAGE_DUMP_SIZE; 625d134aa0bSMatt Jacob } 626d134aa0bSMatt Jacob if (amt) { 627d134aa0bSMatt Jacob FCPARAM(isp)->isp_dump_data = 628a163d034SWarner Losh malloc(amt, M_DEVBUF, M_WAITOK | M_ZERO); 629d134aa0bSMatt Jacob } else { 630d134aa0bSMatt Jacob device_printf(dev, 631d134aa0bSMatt Jacob "f/w crash dumps not supported for this model\n"); 632d134aa0bSMatt Jacob } 633d134aa0bSMatt Jacob } 634d134aa0bSMatt Jacob #endif 635222bb542SMatt Jacob 6366e5c5328SMatt Jacob sptr = 0; 6376e5c5328SMatt Jacob if (resource_string_value(device_get_name(dev), device_get_unit(dev), 638559a1ad2SMatt Jacob "topology", (const char **) &sptr) == 0 && sptr != 0) { 6396e5c5328SMatt Jacob if (strcmp(sptr, "lport") == 0) { 6406e5c5328SMatt Jacob isp->isp_confopts |= ISP_CFG_LPORT; 6416e5c5328SMatt Jacob } else if (strcmp(sptr, "nport") == 0) { 6426e5c5328SMatt Jacob isp->isp_confopts |= ISP_CFG_NPORT; 6436e5c5328SMatt Jacob } else if (strcmp(sptr, "lport-only") == 0) { 6446e5c5328SMatt Jacob isp->isp_confopts |= ISP_CFG_LPORT_ONLY; 6456e5c5328SMatt Jacob } else if (strcmp(sptr, "nport-only") == 0) { 6466e5c5328SMatt Jacob isp->isp_confopts |= ISP_CFG_NPORT_ONLY; 6479637d68cSMatt Jacob } 6486e5c5328SMatt Jacob } 6496e5c5328SMatt Jacob 6509637d68cSMatt Jacob /* 6516e5c5328SMatt Jacob * Because the resource_*_value functions can neither return 6526e5c5328SMatt Jacob * 64 bit integer values, nor can they be directly coerced 6536e5c5328SMatt Jacob * to interpret the right hand side of the assignment as 6546e5c5328SMatt Jacob * you want them to interpret it, we have to force WWN 6556e5c5328SMatt Jacob * hint replacement to specify WWN strings with a leading 6566e5c5328SMatt Jacob * 'w' (e..g w50000000aaaa0001). Sigh. 6579637d68cSMatt Jacob */ 6586e5c5328SMatt Jacob sptr = 0; 6596e5c5328SMatt Jacob tval = resource_string_value(device_get_name(dev), device_get_unit(dev), 660559a1ad2SMatt Jacob "portwwn", (const char **) &sptr); 6616e5c5328SMatt Jacob if (tval == 0 && sptr != 0 && *sptr++ == 'w') { 6626e5c5328SMatt Jacob char *eptr = 0; 6636e5c5328SMatt Jacob isp->isp_osinfo.default_port_wwn = strtouq(sptr, &eptr, 16); 6646e5c5328SMatt Jacob if (eptr < sptr + 16 || isp->isp_osinfo.default_port_wwn == 0) { 6656e5c5328SMatt Jacob device_printf(dev, "mangled portwwn hint '%s'\n", sptr); 6666e5c5328SMatt Jacob isp->isp_osinfo.default_port_wwn = 0; 6679637d68cSMatt Jacob } else { 6683f02619fSMatt Jacob isp->isp_confopts |= ISP_CFG_OWNWWPN; 669222bb542SMatt Jacob } 6706e5c5328SMatt Jacob } 6716e5c5328SMatt Jacob if (isp->isp_osinfo.default_port_wwn == 0) { 6726e5c5328SMatt Jacob isp->isp_osinfo.default_port_wwn = 0x400000007F000009ull; 6736e5c5328SMatt Jacob } 6746e5c5328SMatt Jacob 6756e5c5328SMatt Jacob sptr = 0; 6766e5c5328SMatt Jacob tval = resource_string_value(device_get_name(dev), device_get_unit(dev), 677559a1ad2SMatt Jacob "nodewwn", (const char **) &sptr); 6786e5c5328SMatt Jacob if (tval == 0 && sptr != 0 && *sptr++ == 'w') { 6796e5c5328SMatt Jacob char *eptr = 0; 6806e5c5328SMatt Jacob isp->isp_osinfo.default_node_wwn = strtouq(sptr, &eptr, 16); 6816e5c5328SMatt Jacob if (eptr < sptr + 16 || isp->isp_osinfo.default_node_wwn == 0) { 6826e5c5328SMatt Jacob device_printf(dev, "mangled nodewwn hint '%s'\n", sptr); 6836e5c5328SMatt Jacob isp->isp_osinfo.default_node_wwn = 0; 6846e5c5328SMatt Jacob } else { 6853f02619fSMatt Jacob isp->isp_confopts |= ISP_CFG_OWNWWNN; 6866e5c5328SMatt Jacob } 6876e5c5328SMatt Jacob } 6886e5c5328SMatt Jacob if (isp->isp_osinfo.default_node_wwn == 0) { 6896e5c5328SMatt Jacob isp->isp_osinfo.default_node_wwn = 0x400000007F000009ull; 6906e5c5328SMatt Jacob } 6916e5c5328SMatt Jacob 69243722a42SMatt Jacob isp->isp_osinfo.default_id = -1; 693ed753e82SMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 694ed753e82SMatt Jacob "iid", &tval) == 0) { 695ed753e82SMatt Jacob isp->isp_osinfo.default_id = tval; 696ed753e82SMatt Jacob isp->isp_confopts |= ISP_CFG_OWNLOOPID; 697ed753e82SMatt Jacob } 69843722a42SMatt Jacob if (isp->isp_osinfo.default_id == -1) { 699ed753e82SMatt Jacob if (IS_FC(isp)) { 700ed753e82SMatt Jacob isp->isp_osinfo.default_id = 109; 701ed753e82SMatt Jacob } else { 702ed753e82SMatt Jacob isp->isp_osinfo.default_id = 7; 703ed753e82SMatt Jacob } 704ed753e82SMatt Jacob } 705ed753e82SMatt Jacob 706ed753e82SMatt Jacob isp_debug = 0; 7076e5c5328SMatt Jacob (void) resource_int_value(device_get_name(dev), device_get_unit(dev), 7086e5c5328SMatt Jacob "debug", &isp_debug); 709f09b1922SMatt Jacob 710f09b1922SMatt Jacob /* Make sure the lock is set up. */ 7116008862bSJohn Baldwin mtx_init(&isp->isp_osinfo.lock, "isp", NULL, MTX_DEF); 712f09b1922SMatt Jacob locksetup++; 713f09b1922SMatt Jacob 71472429e49SMatt Jacob if (bus_setup_intr(dev, irq, ISP_IFLAGS, isp_pci_intr, isp, &pcs->ih)) { 715f09b1922SMatt Jacob device_printf(dev, "could not setup interrupt\n"); 716f09b1922SMatt Jacob goto bad; 717f09b1922SMatt Jacob } 718960f6939SMatt Jacob 71905fbcbb0SMatt Jacob /* 720d02373f1SMatt Jacob * Set up logging levels. 721d02373f1SMatt Jacob */ 722d02373f1SMatt Jacob if (isp_debug) { 723d02373f1SMatt Jacob isp->isp_dblev = isp_debug; 724d02373f1SMatt Jacob } else { 725d02373f1SMatt Jacob isp->isp_dblev = ISP_LOGWARN|ISP_LOGERR; 726d02373f1SMatt Jacob } 727d02373f1SMatt Jacob if (bootverbose) 728f7dddf8aSMatt Jacob isp->isp_dblev |= ISP_LOGCONFIG|ISP_LOGINFO; 729d02373f1SMatt Jacob 730d02373f1SMatt Jacob /* 73175c1e828SMatt Jacob * Last minute checks... 73275c1e828SMatt Jacob */ 73375c1e828SMatt Jacob if (IS_2312(isp)) { 73475c1e828SMatt Jacob isp->isp_port = pci_get_function(dev); 73575c1e828SMatt Jacob } 73675c1e828SMatt Jacob 73775c1e828SMatt Jacob /* 73805fbcbb0SMatt Jacob * Make sure we're in reset state. 73905fbcbb0SMatt Jacob */ 7403395b056SMatt Jacob ISP_LOCK(isp); 74165adb54cSMatt Jacob isp_reset(isp); 74265adb54cSMatt Jacob if (isp->isp_state != ISP_RESETSTATE) { 7433395b056SMatt Jacob ISP_UNLOCK(isp); 744960f6939SMatt Jacob goto bad; 74565adb54cSMatt Jacob } 74665adb54cSMatt Jacob isp_init(isp); 747b9b599feSMatt Jacob if (isp->isp_role != ISP_ROLE_NONE && isp->isp_state != ISP_INITSTATE) { 74865adb54cSMatt Jacob isp_uninit(isp); 7493395b056SMatt Jacob ISP_UNLOCK(isp); 750960f6939SMatt Jacob goto bad; 751d59bd469SMatt Jacob } 75265adb54cSMatt Jacob isp_attach(isp); 753b9b599feSMatt Jacob if (isp->isp_role != ISP_ROLE_NONE && isp->isp_state != ISP_RUNSTATE) { 75465adb54cSMatt Jacob isp_uninit(isp); 7553395b056SMatt Jacob ISP_UNLOCK(isp); 756960f6939SMatt Jacob goto bad; 757960f6939SMatt Jacob } 75856aef503SMatt Jacob /* 75956aef503SMatt Jacob * XXXX: Here is where we might unload the f/w module 76056aef503SMatt Jacob * XXXX: (or decrease the reference count to it). 76156aef503SMatt Jacob */ 7623395b056SMatt Jacob ISP_UNLOCK(isp); 763960f6939SMatt Jacob return (0); 764960f6939SMatt Jacob 765960f6939SMatt Jacob bad: 766960f6939SMatt Jacob 767960f6939SMatt Jacob if (pcs && pcs->ih) { 768960f6939SMatt Jacob (void) bus_teardown_intr(dev, irq, pcs->ih); 769960f6939SMatt Jacob } 770960f6939SMatt Jacob 7713395b056SMatt Jacob if (locksetup && isp) { 7723395b056SMatt Jacob mtx_destroy(&isp->isp_osinfo.lock); 7733395b056SMatt Jacob } 7743395b056SMatt Jacob 775960f6939SMatt Jacob if (irq) { 776960f6939SMatt Jacob (void) bus_release_resource(dev, SYS_RES_IRQ, iqd, irq); 777960f6939SMatt Jacob } 7783395b056SMatt Jacob 7793395b056SMatt Jacob 780960f6939SMatt Jacob if (regs) { 781960f6939SMatt Jacob (void) bus_release_resource(dev, rtp, rgd, regs); 782960f6939SMatt Jacob } 7833395b056SMatt Jacob 784960f6939SMatt Jacob if (pcs) { 785960f6939SMatt Jacob if (pcs->pci_isp.isp_param) 786960f6939SMatt Jacob free(pcs->pci_isp.isp_param, M_DEVBUF); 78765adb54cSMatt Jacob free(pcs, M_DEVBUF); 78865adb54cSMatt Jacob } 7893395b056SMatt Jacob 79056aef503SMatt Jacob /* 79156aef503SMatt Jacob * XXXX: Here is where we might unload the f/w module 79256aef503SMatt Jacob * XXXX: (or decrease the reference count to it). 79356aef503SMatt Jacob */ 794960f6939SMatt Jacob return (ENXIO); 79565adb54cSMatt Jacob } 79665adb54cSMatt Jacob 797f09b1922SMatt Jacob static void 798f09b1922SMatt Jacob isp_pci_intr(void *arg) 799f09b1922SMatt Jacob { 800f09b1922SMatt Jacob struct ispsoftc *isp = arg; 801126ec864SMatt Jacob u_int16_t isr, sema, mbox; 802126ec864SMatt Jacob 803f09b1922SMatt Jacob ISP_LOCK(isp); 804126ec864SMatt Jacob isp->isp_intcnt++; 805126ec864SMatt Jacob if (ISP_READ_ISR(isp, &isr, &sema, &mbox) == 0) { 806126ec864SMatt Jacob isp->isp_intbogus++; 807126ec864SMatt Jacob } else { 808b96934e8SMatt Jacob int iok = isp->isp_osinfo.intsok; 809b96934e8SMatt Jacob isp->isp_osinfo.intsok = 0; 810126ec864SMatt Jacob isp_intr(isp, isr, sema, mbox); 811b96934e8SMatt Jacob isp->isp_osinfo.intsok = iok; 812126ec864SMatt Jacob } 813f09b1922SMatt Jacob ISP_UNLOCK(isp); 814f09b1922SMatt Jacob } 815f09b1922SMatt Jacob 816126ec864SMatt Jacob 817126ec864SMatt Jacob #define IspVirt2Off(a, x) \ 818126ec864SMatt Jacob (((struct isp_pcisoftc *)a)->pci_poff[((x) & _BLK_REG_MASK) >> \ 819126ec864SMatt Jacob _BLK_REG_SHFT] + ((x) & 0xff)) 820126ec864SMatt Jacob 821126ec864SMatt Jacob #define BXR2(pcs, off) \ 822126ec864SMatt Jacob bus_space_read_2(pcs->pci_st, pcs->pci_sh, off) 823126ec864SMatt Jacob #define BXW2(pcs, off, v) \ 824126ec864SMatt Jacob bus_space_write_2(pcs->pci_st, pcs->pci_sh, off, v) 825126ec864SMatt Jacob 826126ec864SMatt Jacob 827126ec864SMatt Jacob static INLINE int 828126ec864SMatt Jacob isp_pci_rd_debounced(struct ispsoftc *isp, int off, u_int16_t *rp) 829126ec864SMatt Jacob { 830126ec864SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 831126ec864SMatt Jacob u_int16_t val0, val1; 832126ec864SMatt Jacob int i = 0; 833126ec864SMatt Jacob 834126ec864SMatt Jacob do { 835126ec864SMatt Jacob val0 = BXR2(pcs, IspVirt2Off(isp, off)); 836126ec864SMatt Jacob val1 = BXR2(pcs, IspVirt2Off(isp, off)); 837126ec864SMatt Jacob } while (val0 != val1 && ++i < 1000); 838126ec864SMatt Jacob if (val0 != val1) { 839126ec864SMatt Jacob return (1); 840126ec864SMatt Jacob } 841126ec864SMatt Jacob *rp = val0; 842126ec864SMatt Jacob return (0); 843126ec864SMatt Jacob } 844126ec864SMatt Jacob 845126ec864SMatt Jacob static int 846126ec864SMatt Jacob isp_pci_rd_isr(struct ispsoftc *isp, u_int16_t *isrp, 847126ec864SMatt Jacob u_int16_t *semap, u_int16_t *mbp) 848126ec864SMatt Jacob { 849126ec864SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 850126ec864SMatt Jacob u_int16_t isr, sema; 851126ec864SMatt Jacob 852126ec864SMatt Jacob if (IS_2100(isp)) { 853126ec864SMatt Jacob if (isp_pci_rd_debounced(isp, BIU_ISR, &isr)) { 854126ec864SMatt Jacob return (0); 855126ec864SMatt Jacob } 856126ec864SMatt Jacob if (isp_pci_rd_debounced(isp, BIU_SEMA, &sema)) { 857126ec864SMatt Jacob return (0); 858126ec864SMatt Jacob } 859126ec864SMatt Jacob } else { 860126ec864SMatt Jacob isr = BXR2(pcs, IspVirt2Off(isp, BIU_ISR)); 861126ec864SMatt Jacob sema = BXR2(pcs, IspVirt2Off(isp, BIU_SEMA)); 862126ec864SMatt Jacob } 863126ec864SMatt Jacob isp_prt(isp, ISP_LOGDEBUG3, "ISR 0x%x SEMA 0x%x", isr, sema); 864126ec864SMatt Jacob isr &= INT_PENDING_MASK(isp); 865126ec864SMatt Jacob sema &= BIU_SEMA_LOCK; 866126ec864SMatt Jacob if (isr == 0 && sema == 0) { 867126ec864SMatt Jacob return (0); 868126ec864SMatt Jacob } 869126ec864SMatt Jacob *isrp = isr; 870126ec864SMatt Jacob if ((*semap = sema) != 0) { 871126ec864SMatt Jacob if (IS_2100(isp)) { 872126ec864SMatt Jacob if (isp_pci_rd_debounced(isp, OUTMAILBOX0, mbp)) { 873126ec864SMatt Jacob return (0); 874126ec864SMatt Jacob } 875126ec864SMatt Jacob } else { 876126ec864SMatt Jacob *mbp = BXR2(pcs, IspVirt2Off(isp, OUTMAILBOX0)); 877126ec864SMatt Jacob } 878126ec864SMatt Jacob } 879126ec864SMatt Jacob return (1); 880126ec864SMatt Jacob } 881126ec864SMatt Jacob 882126ec864SMatt Jacob static int 883126ec864SMatt Jacob isp_pci_rd_isr_2300(struct ispsoftc *isp, u_int16_t *isrp, 884126ec864SMatt Jacob u_int16_t *semap, u_int16_t *mbox0p) 885126ec864SMatt Jacob { 886126ec864SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 887126ec864SMatt Jacob u_int32_t r2hisr; 888126ec864SMatt Jacob 8893bd40330SMatt Jacob if (!(BXR2(pcs, IspVirt2Off(isp, BIU_ISR) & BIU2100_ISR_RISC_INT))) { 8903bd40330SMatt Jacob *isrp = 0; 891db4fa023SMatt Jacob return (0); 8923bd40330SMatt Jacob } 893126ec864SMatt Jacob r2hisr = bus_space_read_4(pcs->pci_st, pcs->pci_sh, 894126ec864SMatt Jacob IspVirt2Off(pcs, BIU_R2HSTSLO)); 895126ec864SMatt Jacob isp_prt(isp, ISP_LOGDEBUG3, "RISC2HOST ISR 0x%x", r2hisr); 896126ec864SMatt Jacob if ((r2hisr & BIU_R2HST_INTR) == 0) { 897126ec864SMatt Jacob *isrp = 0; 898126ec864SMatt Jacob return (0); 899126ec864SMatt Jacob } 900126ec864SMatt Jacob switch (r2hisr & BIU_R2HST_ISTAT_MASK) { 901126ec864SMatt Jacob case ISPR2HST_ROM_MBX_OK: 902126ec864SMatt Jacob case ISPR2HST_ROM_MBX_FAIL: 903126ec864SMatt Jacob case ISPR2HST_MBX_OK: 904126ec864SMatt Jacob case ISPR2HST_MBX_FAIL: 905126ec864SMatt Jacob case ISPR2HST_ASYNC_EVENT: 906126ec864SMatt Jacob *isrp = r2hisr & 0xffff; 907126ec864SMatt Jacob *mbox0p = (r2hisr >> 16); 908126ec864SMatt Jacob *semap = 1; 909126ec864SMatt Jacob return (1); 910fc3bbaaaSMatt Jacob case ISPR2HST_RIO_16: 911fc3bbaaaSMatt Jacob *isrp = r2hisr & 0xffff; 912fc3bbaaaSMatt Jacob *mbox0p = ASYNC_RIO1; 913fc3bbaaaSMatt Jacob *semap = 1; 914fc3bbaaaSMatt Jacob return (1); 915fc3bbaaaSMatt Jacob case ISPR2HST_FPOST: 916fc3bbaaaSMatt Jacob *isrp = r2hisr & 0xffff; 917fc3bbaaaSMatt Jacob *mbox0p = ASYNC_CMD_CMPLT; 918fc3bbaaaSMatt Jacob *semap = 1; 919fc3bbaaaSMatt Jacob return (1); 920fc3bbaaaSMatt Jacob case ISPR2HST_FPOST_CTIO: 921fc3bbaaaSMatt Jacob *isrp = r2hisr & 0xffff; 922fc3bbaaaSMatt Jacob *mbox0p = ASYNC_CTIO_DONE; 923fc3bbaaaSMatt Jacob *semap = 1; 924fc3bbaaaSMatt Jacob return (1); 925126ec864SMatt Jacob case ISPR2HST_RSPQ_UPDATE: 926126ec864SMatt Jacob *isrp = r2hisr & 0xffff; 927126ec864SMatt Jacob *mbox0p = 0; 928126ec864SMatt Jacob *semap = 0; 929126ec864SMatt Jacob return (1); 930126ec864SMatt Jacob default: 931126ec864SMatt Jacob return (0); 932126ec864SMatt Jacob } 933126ec864SMatt Jacob } 934126ec864SMatt Jacob 93565adb54cSMatt Jacob static u_int16_t 936126ec864SMatt Jacob isp_pci_rd_reg(struct ispsoftc *isp, int regoff) 93765adb54cSMatt Jacob { 93865adb54cSMatt Jacob u_int16_t rv; 93965adb54cSMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 940126ec864SMatt Jacob int oldconf = 0; 94165adb54cSMatt 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 rv = BXR2(pcs, IspVirt2Off(isp, regoff)); 951d59bd469SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 952126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), oldconf); 95365adb54cSMatt Jacob } 95465adb54cSMatt Jacob return (rv); 95565adb54cSMatt Jacob } 95665adb54cSMatt Jacob 95765adb54cSMatt Jacob static void 958126ec864SMatt Jacob isp_pci_wr_reg(struct ispsoftc *isp, int regoff, u_int16_t val) 95965adb54cSMatt Jacob { 96065adb54cSMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 961126ec864SMatt Jacob int oldconf = 0; 962d59bd469SMatt Jacob 963d59bd469SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 96465adb54cSMatt Jacob /* 96565adb54cSMatt Jacob * We will assume that someone has paused the RISC processor. 96665adb54cSMatt Jacob */ 967126ec864SMatt Jacob oldconf = BXR2(pcs, IspVirt2Off(isp, BIU_CONF1)); 968126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), 969126ec864SMatt Jacob oldconf | BIU_PCI_CONF1_SXP); 97065adb54cSMatt Jacob } 971126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, regoff), val); 972d59bd469SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 973126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), oldconf); 97465adb54cSMatt Jacob } 97565adb54cSMatt Jacob } 97665adb54cSMatt Jacob 977d59bd469SMatt Jacob static u_int16_t 978126ec864SMatt Jacob isp_pci_rd_reg_1080(struct ispsoftc *isp, int regoff) 979d59bd469SMatt Jacob { 98022e1dc85SMatt Jacob u_int16_t rv, oc = 0; 981d59bd469SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 982d59bd469SMatt Jacob 98322e1dc85SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK || 98422e1dc85SMatt Jacob (regoff & _BLK_REG_MASK) == (SXP_BLOCK|SXP_BANK1_SELECT)) { 98522e1dc85SMatt Jacob u_int16_t tc; 986d59bd469SMatt Jacob /* 987d59bd469SMatt Jacob * We will assume that someone has paused the RISC processor. 988d59bd469SMatt Jacob */ 989126ec864SMatt Jacob oc = BXR2(pcs, IspVirt2Off(isp, BIU_CONF1)); 99022e1dc85SMatt Jacob tc = oc & ~BIU_PCI1080_CONF1_DMA; 99122e1dc85SMatt Jacob if (regoff & SXP_BANK1_SELECT) 99222e1dc85SMatt Jacob tc |= BIU_PCI1080_CONF1_SXP1; 99322e1dc85SMatt Jacob else 99422e1dc85SMatt Jacob tc |= BIU_PCI1080_CONF1_SXP0; 995126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), tc); 996d59bd469SMatt Jacob } else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) { 997126ec864SMatt Jacob oc = BXR2(pcs, IspVirt2Off(isp, BIU_CONF1)); 998126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), 999126ec864SMatt Jacob oc | BIU_PCI1080_CONF1_DMA); 1000d59bd469SMatt Jacob } 1001126ec864SMatt Jacob rv = BXR2(pcs, IspVirt2Off(isp, regoff)); 100222e1dc85SMatt Jacob if (oc) { 1003126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), oc); 1004d59bd469SMatt Jacob } 1005d59bd469SMatt Jacob return (rv); 1006d59bd469SMatt Jacob } 1007d59bd469SMatt Jacob 1008d59bd469SMatt Jacob static void 1009126ec864SMatt Jacob isp_pci_wr_reg_1080(struct ispsoftc *isp, int regoff, u_int16_t val) 1010d59bd469SMatt Jacob { 1011d59bd469SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 1012126ec864SMatt Jacob int oc = 0; 1013d59bd469SMatt Jacob 101422e1dc85SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK || 101522e1dc85SMatt Jacob (regoff & _BLK_REG_MASK) == (SXP_BLOCK|SXP_BANK1_SELECT)) { 101622e1dc85SMatt Jacob u_int16_t tc; 1017d59bd469SMatt Jacob /* 1018d59bd469SMatt Jacob * We will assume that someone has paused the RISC processor. 1019d59bd469SMatt Jacob */ 1020126ec864SMatt Jacob oc = BXR2(pcs, IspVirt2Off(isp, BIU_CONF1)); 102122e1dc85SMatt Jacob tc = oc & ~BIU_PCI1080_CONF1_DMA; 102222e1dc85SMatt Jacob if (regoff & SXP_BANK1_SELECT) 102322e1dc85SMatt Jacob tc |= BIU_PCI1080_CONF1_SXP1; 102422e1dc85SMatt Jacob else 102522e1dc85SMatt Jacob tc |= BIU_PCI1080_CONF1_SXP0; 1026126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), tc); 1027d59bd469SMatt Jacob } else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) { 1028126ec864SMatt Jacob oc = BXR2(pcs, IspVirt2Off(isp, BIU_CONF1)); 1029126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), 1030126ec864SMatt Jacob oc | BIU_PCI1080_CONF1_DMA); 1031d59bd469SMatt Jacob } 1032126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, regoff), val); 103322e1dc85SMatt Jacob if (oc) { 1034126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), oc); 1035d59bd469SMatt Jacob } 1036d59bd469SMatt Jacob } 1037d59bd469SMatt Jacob 1038d720e6d5SJustin T. Gibbs 1039222bb542SMatt Jacob struct imush { 1040222bb542SMatt Jacob struct ispsoftc *isp; 1041222bb542SMatt Jacob int error; 1042222bb542SMatt Jacob }; 1043222bb542SMatt Jacob 10441923f739SMatt Jacob static void imc(void *, bus_dma_segment_t *, int, int); 10451923f739SMatt Jacob 1046d720e6d5SJustin T. Gibbs static void 10471923f739SMatt Jacob imc(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1048d720e6d5SJustin T. Gibbs { 1049222bb542SMatt Jacob struct imush *imushp = (struct imush *) arg; 1050222bb542SMatt Jacob if (error) { 1051222bb542SMatt Jacob imushp->error = error; 1052222bb542SMatt Jacob } else { 10531923f739SMatt Jacob struct ispsoftc *isp =imushp->isp; 10541923f739SMatt Jacob bus_addr_t addr = segs->ds_addr; 10551923f739SMatt Jacob 10561923f739SMatt Jacob isp->isp_rquest_dma = addr; 10571923f739SMatt Jacob addr += ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)); 10581923f739SMatt Jacob isp->isp_result_dma = addr; 10591923f739SMatt Jacob if (IS_FC(isp)) { 10601923f739SMatt Jacob addr += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)); 10611923f739SMatt Jacob FCPARAM(isp)->isp_scdma = addr; 10621923f739SMatt Jacob } 1063222bb542SMatt Jacob } 1064d720e6d5SJustin T. Gibbs } 1065d720e6d5SJustin T. Gibbs 1066029f13c6SMatt Jacob /* 1067029f13c6SMatt Jacob * Should be BUS_SPACE_MAXSIZE, but MAXPHYS is larger than BUS_SPACE_MAXSIZE 1068029f13c6SMatt Jacob */ 1069029f13c6SMatt Jacob #define ISP_NSEGS ((MAXPHYS / PAGE_SIZE) + 1) 1070d720e6d5SJustin T. Gibbs 1071d720e6d5SJustin T. Gibbs static int 107217e318c6SMatt Jacob isp_pci_mbxdma(struct ispsoftc *isp) 1073d720e6d5SJustin T. Gibbs { 10741923f739SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *)isp; 1075d720e6d5SJustin T. Gibbs caddr_t base; 1076d720e6d5SJustin T. Gibbs u_int32_t len; 10771923f739SMatt Jacob int i, error, ns; 1078435a9337SMatt Jacob bus_size_t alim, slim; 1079222bb542SMatt Jacob struct imush im; 1080222bb542SMatt Jacob 1081a95ae193SMatt Jacob /* 1082a95ae193SMatt Jacob * Already been here? If so, leave... 1083a95ae193SMatt Jacob */ 1084a95ae193SMatt Jacob if (isp->isp_rquest) { 1085a95ae193SMatt Jacob return (0); 1086a95ae193SMatt Jacob } 1087a95ae193SMatt Jacob 1088435a9337SMatt Jacob #ifdef ISP_DAC_SUPPORTED 1089435a9337SMatt Jacob alim = BUS_SPACE_UNRESTRICTED; 1090435a9337SMatt Jacob #else 1091435a9337SMatt Jacob alim = BUS_SPACE_MAXADDR_32BIT; 1092435a9337SMatt Jacob #endif 10931923f739SMatt Jacob if (IS_ULTRA2(isp) || IS_FC(isp) || IS_1240(isp)) { 1094435a9337SMatt Jacob slim = BUS_SPACE_MAXADDR_32BIT; 10951923f739SMatt Jacob } else { 1096435a9337SMatt Jacob slim = BUS_SPACE_MAXADDR_24BIT; 10971923f739SMatt Jacob } 10981923f739SMatt Jacob 109972429e49SMatt Jacob ISP_UNLOCK(isp); 1100435a9337SMatt Jacob if (bus_dma_tag_create(NULL, 1, slim+1, alim, alim, 1101f6b1c44dSScott Long NULL, NULL, BUS_SPACE_MAXSIZE, ISP_NSEGS, slim, 0, 1102f6b1c44dSScott Long busdma_lock_mutex, &Giant, &pcs->dmat)) { 11031923f739SMatt Jacob isp_prt(isp, ISP_LOGERR, "could not create master dma tag"); 110472429e49SMatt Jacob ISP_LOCK(isp); 11051923f739SMatt Jacob return(1); 11061923f739SMatt Jacob } 11071923f739SMatt Jacob 11081923f739SMatt Jacob 1109d02373f1SMatt Jacob len = sizeof (XS_T **) * isp->isp_maxcmds; 1110a163d034SWarner Losh isp->isp_xflist = (XS_T **) malloc(len, M_DEVBUF, M_WAITOK | M_ZERO); 1111a95ae193SMatt Jacob if (isp->isp_xflist == NULL) { 1112d02373f1SMatt Jacob isp_prt(isp, ISP_LOGERR, "cannot alloc xflist array"); 111372429e49SMatt Jacob ISP_LOCK(isp); 1114a95ae193SMatt Jacob return (1); 1115a95ae193SMatt Jacob } 111651e23558SNate Lawson #ifdef ISP_TARGET_MODE 111751e23558SNate Lawson len = sizeof (void **) * isp->isp_maxcmds; 111851e23558SNate Lawson isp->isp_tgtlist = (void **) malloc(len, M_DEVBUF, M_WAITOK | M_ZERO); 111951e23558SNate Lawson if (isp->isp_tgtlist == NULL) { 112051e23558SNate Lawson isp_prt(isp, ISP_LOGERR, "cannot alloc tgtlist array"); 112151e23558SNate Lawson ISP_LOCK(isp); 112251e23558SNate Lawson return (1); 112351e23558SNate Lawson } 112451e23558SNate Lawson #endif 1125a95ae193SMatt Jacob len = sizeof (bus_dmamap_t) * isp->isp_maxcmds; 1126a163d034SWarner Losh pcs->dmaps = (bus_dmamap_t *) malloc(len, M_DEVBUF, M_WAITOK); 11271923f739SMatt Jacob if (pcs->dmaps == NULL) { 11281923f739SMatt Jacob isp_prt(isp, ISP_LOGERR, "can't alloc dma map storage"); 1129a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 113051e23558SNate Lawson #ifdef ISP_TARGET_MODE 113151e23558SNate Lawson free(isp->isp_tgtlist, M_DEVBUF); 113251e23558SNate Lawson #endif 113372429e49SMatt Jacob ISP_LOCK(isp); 1134a95ae193SMatt Jacob return (1); 1135a95ae193SMatt Jacob } 1136a95ae193SMatt Jacob 1137d720e6d5SJustin T. Gibbs /* 1138d720e6d5SJustin T. Gibbs * Allocate and map the request, result queues, plus FC scratch area. 1139d720e6d5SJustin T. Gibbs */ 1140d02373f1SMatt Jacob len = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)); 1141d02373f1SMatt Jacob len += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)); 1142222bb542SMatt Jacob if (IS_FC(isp)) { 1143d720e6d5SJustin T. Gibbs len += ISP2100_SCRLEN; 1144d720e6d5SJustin T. Gibbs } 11451923f739SMatt Jacob 11461923f739SMatt Jacob ns = (len / PAGE_SIZE) + 1; 1147435a9337SMatt Jacob if (bus_dma_tag_create(pcs->dmat, QENTRY_LEN, slim+1, alim, alim, 1148f6b1c44dSScott Long NULL, NULL, len, ns, slim, 0, busdma_lock_mutex, &Giant, 1149f6b1c44dSScott Long &isp->isp_cdmat)) { 1150f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 1151f7dddf8aSMatt Jacob "cannot create a dma tag for control spaces"); 11521923f739SMatt Jacob free(pcs->dmaps, M_DEVBUF); 1153a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 115451e23558SNate Lawson #ifdef ISP_TARGET_MODE 115551e23558SNate Lawson free(isp->isp_tgtlist, M_DEVBUF); 115651e23558SNate Lawson #endif 115772429e49SMatt Jacob ISP_LOCK(isp); 1158d720e6d5SJustin T. Gibbs return (1); 1159d720e6d5SJustin T. Gibbs } 1160d720e6d5SJustin T. Gibbs 11611923f739SMatt Jacob if (bus_dmamem_alloc(isp->isp_cdmat, (void **)&base, BUS_DMA_NOWAIT, 11621923f739SMatt Jacob &isp->isp_cdmap) != 0) { 1163f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 11641923f739SMatt Jacob "cannot allocate %d bytes of CCB memory", len); 11651923f739SMatt Jacob bus_dma_tag_destroy(isp->isp_cdmat); 1166a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 116751e23558SNate Lawson #ifdef ISP_TARGET_MODE 116851e23558SNate Lawson free(isp->isp_tgtlist, M_DEVBUF); 116951e23558SNate Lawson #endif 11701923f739SMatt Jacob free(pcs->dmaps, M_DEVBUF); 117172429e49SMatt Jacob ISP_LOCK(isp); 1172222bb542SMatt Jacob return (1); 1173222bb542SMatt Jacob } 1174d720e6d5SJustin T. Gibbs 1175a95ae193SMatt Jacob for (i = 0; i < isp->isp_maxcmds; i++) { 11761923f739SMatt Jacob error = bus_dmamap_create(pcs->dmat, 0, &pcs->dmaps[i]); 1177d720e6d5SJustin T. Gibbs if (error) { 1178f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 1179f7dddf8aSMatt Jacob "error %d creating per-cmd DMA maps", error); 11801923f739SMatt Jacob while (--i >= 0) { 11811923f739SMatt Jacob bus_dmamap_destroy(pcs->dmat, pcs->dmaps[i]); 11821923f739SMatt Jacob } 11831923f739SMatt Jacob goto bad; 1184d720e6d5SJustin T. Gibbs } 1185d720e6d5SJustin T. Gibbs } 1186a95ae193SMatt Jacob 11871923f739SMatt Jacob im.isp = isp; 1188222bb542SMatt Jacob im.error = 0; 11891923f739SMatt Jacob bus_dmamap_load(isp->isp_cdmat, isp->isp_cdmap, base, len, imc, &im, 0); 1190222bb542SMatt Jacob if (im.error) { 1191f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 11921923f739SMatt Jacob "error %d loading dma map for control areas", im.error); 11931923f739SMatt Jacob goto bad; 1194222bb542SMatt Jacob } 11951923f739SMatt Jacob 11961923f739SMatt Jacob isp->isp_rquest = base; 11971923f739SMatt Jacob base += ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)); 11981923f739SMatt Jacob isp->isp_result = base; 11991923f739SMatt Jacob if (IS_FC(isp)) { 12001923f739SMatt Jacob base += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)); 12011923f739SMatt Jacob FCPARAM(isp)->isp_scratch = base; 120292c49d78SMatt Jacob } 120372429e49SMatt Jacob ISP_LOCK(isp); 1204d720e6d5SJustin T. Gibbs return (0); 12051923f739SMatt Jacob 12061923f739SMatt Jacob bad: 12071923f739SMatt Jacob bus_dmamem_free(isp->isp_cdmat, base, isp->isp_cdmap); 12081923f739SMatt Jacob bus_dma_tag_destroy(isp->isp_cdmat); 12091923f739SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 121051e23558SNate Lawson #ifdef ISP_TARGET_MODE 121151e23558SNate Lawson free(isp->isp_tgtlist, M_DEVBUF); 121251e23558SNate Lawson #endif 12131923f739SMatt Jacob free(pcs->dmaps, M_DEVBUF); 121472429e49SMatt Jacob ISP_LOCK(isp); 12151923f739SMatt Jacob isp->isp_rquest = NULL; 12161923f739SMatt Jacob return (1); 1217d720e6d5SJustin T. Gibbs } 1218d720e6d5SJustin T. Gibbs 1219d720e6d5SJustin T. Gibbs typedef struct { 1220d720e6d5SJustin T. Gibbs struct ispsoftc *isp; 12219e11e5beSMatt Jacob void *cmd_token; 12229e11e5beSMatt Jacob void *rq; 12234fd13c1bSMatt Jacob u_int16_t *nxtip; 12249637d68cSMatt Jacob u_int16_t optr; 1225d720e6d5SJustin T. Gibbs u_int error; 1226d720e6d5SJustin T. Gibbs } mush_t; 1227d720e6d5SJustin T. Gibbs 12284873663cSMatt Jacob #define MUSHERR_NOQENTRIES -2 12294873663cSMatt Jacob 12309e11e5beSMatt Jacob #ifdef ISP_TARGET_MODE 12319e11e5beSMatt Jacob /* 12329e11e5beSMatt Jacob * We need to handle DMA for target mode differently from initiator mode. 12339e11e5beSMatt Jacob * 12349e11e5beSMatt Jacob * DMA mapping and construction and submission of CTIO Request Entries 12359e11e5beSMatt Jacob * and rendevous for completion are very tightly coupled because we start 12369e11e5beSMatt Jacob * out by knowing (per platform) how much data we have to move, but we 12379e11e5beSMatt Jacob * don't know, up front, how many DMA mapping segments will have to be used 12389e11e5beSMatt Jacob * cover that data, so we don't know how many CTIO Request Entries we 12399e11e5beSMatt Jacob * will end up using. Further, for performance reasons we may want to 12409e11e5beSMatt Jacob * (on the last CTIO for Fibre Channel), send status too (if all went well). 12419e11e5beSMatt Jacob * 12429e11e5beSMatt Jacob * The standard vector still goes through isp_pci_dmasetup, but the callback 12439e11e5beSMatt Jacob * for the DMA mapping routines comes here instead with the whole transfer 12449e11e5beSMatt Jacob * mapped and a pointer to a partially filled in already allocated request 12459e11e5beSMatt Jacob * queue entry. We finish the job. 12469e11e5beSMatt Jacob */ 1247e9a2738aSMatt Jacob static void tdma_mk(void *, bus_dma_segment_t *, int, int); 1248e9a2738aSMatt Jacob static void tdma_mkfc(void *, bus_dma_segment_t *, int, int); 1249e9a2738aSMatt Jacob 1250e9a2738aSMatt Jacob #define STATUS_WITH_DATA 1 12519e11e5beSMatt Jacob 1252d720e6d5SJustin T. Gibbs static void 125305fbcbb0SMatt Jacob tdma_mk(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 1254d720e6d5SJustin T. Gibbs { 1255d720e6d5SJustin T. Gibbs mush_t *mp; 12569e11e5beSMatt Jacob struct ccb_scsiio *csio; 12574fd13c1bSMatt Jacob struct ispsoftc *isp; 12581923f739SMatt Jacob struct isp_pcisoftc *pcs; 1259d720e6d5SJustin T. Gibbs bus_dmamap_t *dp; 12604fd13c1bSMatt Jacob ct_entry_t *cto, *qe; 126105fbcbb0SMatt Jacob u_int8_t scsi_status; 12624fd13c1bSMatt Jacob u_int16_t curi, nxti, handle; 1263b96934e8SMatt Jacob u_int32_t sflags; 126405fbcbb0SMatt Jacob int32_t resid; 12654fd13c1bSMatt Jacob int nth_ctio, nctios, send_status; 1266d720e6d5SJustin T. Gibbs 1267d720e6d5SJustin T. Gibbs mp = (mush_t *) arg; 1268d720e6d5SJustin T. Gibbs if (error) { 1269d720e6d5SJustin T. Gibbs mp->error = error; 1270d720e6d5SJustin T. Gibbs return; 1271d720e6d5SJustin T. Gibbs } 12724fd13c1bSMatt Jacob 12734fd13c1bSMatt Jacob isp = mp->isp; 12749e11e5beSMatt Jacob csio = mp->cmd_token; 12759e11e5beSMatt Jacob cto = mp->rq; 12764fd13c1bSMatt Jacob curi = isp->isp_reqidx; 12774fd13c1bSMatt Jacob qe = (ct_entry_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, curi); 12789e11e5beSMatt Jacob 127965b024e1SMatt Jacob cto->ct_xfrlen = 0; 128065b024e1SMatt Jacob cto->ct_seg_count = 0; 128165b024e1SMatt Jacob cto->ct_header.rqs_entry_count = 1; 128205fbcbb0SMatt Jacob MEMZERO(cto->ct_dataseg, sizeof(cto->ct_dataseg)); 128305fbcbb0SMatt Jacob 128405fbcbb0SMatt Jacob if (nseg == 0) { 128505fbcbb0SMatt Jacob cto->ct_header.rqs_seqno = 1; 12864fd13c1bSMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, 1287e9a2738aSMatt Jacob "CTIO[%x] lun%d iid%d tag %x flgs %x sts %x ssts %x res %d", 12885f5aafe1SMatt Jacob cto->ct_fwhandle, csio->ccb_h.target_lun, cto->ct_iid, 1289e9a2738aSMatt Jacob cto->ct_tag_val, cto->ct_flags, cto->ct_status, 1290e9a2738aSMatt Jacob cto->ct_scsi_status, cto->ct_resid); 12914fd13c1bSMatt Jacob ISP_TDQE(isp, "tdma_mk[no data]", curi, cto); 12924fd13c1bSMatt Jacob isp_put_ctio(isp, cto, qe); 129365b024e1SMatt Jacob return; 129465b024e1SMatt Jacob } 129565b024e1SMatt Jacob 129665b024e1SMatt Jacob nctios = nseg / ISP_RQDSEG; 129765b024e1SMatt Jacob if (nseg % ISP_RQDSEG) { 129865b024e1SMatt Jacob nctios++; 129965b024e1SMatt Jacob } 130065b024e1SMatt Jacob 130105fbcbb0SMatt Jacob /* 13025f5aafe1SMatt Jacob * Save syshandle, and potentially any SCSI status, which we'll 13035f5aafe1SMatt Jacob * reinsert on the last CTIO we're going to send. 130405fbcbb0SMatt Jacob */ 13054fd13c1bSMatt Jacob 13065f5aafe1SMatt Jacob handle = cto->ct_syshandle; 13075f5aafe1SMatt Jacob cto->ct_syshandle = 0; 130805fbcbb0SMatt Jacob cto->ct_header.rqs_seqno = 0; 130905fbcbb0SMatt Jacob send_status = (cto->ct_flags & CT_SENDSTATUS) != 0; 131005fbcbb0SMatt Jacob 131105fbcbb0SMatt Jacob if (send_status) { 131205fbcbb0SMatt Jacob sflags = cto->ct_flags & (CT_SENDSTATUS | CT_CCINCR); 131305fbcbb0SMatt Jacob cto->ct_flags &= ~(CT_SENDSTATUS | CT_CCINCR); 131405fbcbb0SMatt Jacob /* 131505fbcbb0SMatt Jacob * Preserve residual. 131605fbcbb0SMatt Jacob */ 131705fbcbb0SMatt Jacob resid = cto->ct_resid; 131805fbcbb0SMatt Jacob 131905fbcbb0SMatt Jacob /* 132005fbcbb0SMatt Jacob * Save actual SCSI status. 132105fbcbb0SMatt Jacob */ 132205fbcbb0SMatt Jacob scsi_status = cto->ct_scsi_status; 132305fbcbb0SMatt Jacob 1324e9a2738aSMatt Jacob #ifndef STATUS_WITH_DATA 1325e9a2738aSMatt Jacob sflags |= CT_NO_DATA; 132605fbcbb0SMatt Jacob /* 132705fbcbb0SMatt Jacob * We can't do a status at the same time as a data CTIO, so 132805fbcbb0SMatt Jacob * we need to synthesize an extra CTIO at this level. 132905fbcbb0SMatt Jacob */ 133005fbcbb0SMatt Jacob nctios++; 1331b72b1569SMatt Jacob #endif 133205fbcbb0SMatt Jacob } else { 133305fbcbb0SMatt Jacob sflags = scsi_status = resid = 0; 133405fbcbb0SMatt Jacob } 133505fbcbb0SMatt Jacob 1336b96934e8SMatt Jacob cto->ct_resid = 0; 133705fbcbb0SMatt Jacob cto->ct_scsi_status = 0; 133805fbcbb0SMatt Jacob 13391923f739SMatt Jacob pcs = (struct isp_pcisoftc *)isp; 13401923f739SMatt Jacob dp = &pcs->dmaps[isp_handle_index(handle)]; 13419e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 13421923f739SMatt Jacob bus_dmamap_sync(pcs->dmat, *dp, BUS_DMASYNC_PREREAD); 1343d720e6d5SJustin T. Gibbs } else { 13441923f739SMatt Jacob bus_dmamap_sync(pcs->dmat, *dp, BUS_DMASYNC_PREWRITE); 1345d720e6d5SJustin T. Gibbs } 1346d720e6d5SJustin T. Gibbs 13474fd13c1bSMatt Jacob nxti = *mp->nxtip; 13489e11e5beSMatt Jacob 13494fd13c1bSMatt Jacob for (nth_ctio = 0; nth_ctio < nctios; nth_ctio++) { 135005fbcbb0SMatt Jacob int seglim; 13519e11e5beSMatt Jacob 13529e11e5beSMatt Jacob seglim = nseg; 135305fbcbb0SMatt Jacob if (seglim) { 135405fbcbb0SMatt Jacob int seg; 135505fbcbb0SMatt Jacob 13569e11e5beSMatt Jacob if (seglim > ISP_RQDSEG) 13579e11e5beSMatt Jacob seglim = ISP_RQDSEG; 13589e11e5beSMatt Jacob 135905fbcbb0SMatt Jacob for (seg = 0; seg < seglim; seg++, nseg--) { 136005fbcbb0SMatt Jacob /* 136105fbcbb0SMatt Jacob * Unlike normal initiator commands, we don't 136205fbcbb0SMatt Jacob * do any swizzling here. 136305fbcbb0SMatt Jacob */ 13649e11e5beSMatt Jacob cto->ct_dataseg[seg].ds_count = dm_segs->ds_len; 136505fbcbb0SMatt Jacob cto->ct_dataseg[seg].ds_base = dm_segs->ds_addr; 13669e11e5beSMatt Jacob cto->ct_xfrlen += dm_segs->ds_len; 13679e11e5beSMatt Jacob dm_segs++; 13689e11e5beSMatt Jacob } 13699e11e5beSMatt Jacob cto->ct_seg_count = seg; 13709e11e5beSMatt Jacob } else { 137105fbcbb0SMatt Jacob /* 137205fbcbb0SMatt Jacob * This case should only happen when we're sending an 137305fbcbb0SMatt Jacob * extra CTIO with final status. 137405fbcbb0SMatt Jacob */ 137505fbcbb0SMatt Jacob if (send_status == 0) { 13764fd13c1bSMatt Jacob isp_prt(isp, ISP_LOGWARN, 1377f7dddf8aSMatt Jacob "tdma_mk ran out of segments"); 137805fbcbb0SMatt Jacob mp->error = EINVAL; 137905fbcbb0SMatt Jacob return; 13809e11e5beSMatt Jacob } 138105fbcbb0SMatt Jacob } 138205fbcbb0SMatt Jacob 138305fbcbb0SMatt Jacob /* 138405fbcbb0SMatt Jacob * At this point, the fields ct_lun, ct_iid, ct_tagval, 138505fbcbb0SMatt Jacob * ct_tagtype, and ct_timeout have been carried over 138605fbcbb0SMatt Jacob * unchanged from what our caller had set. 138705fbcbb0SMatt Jacob * 138805fbcbb0SMatt Jacob * The dataseg fields and the seg_count fields we just got 138905fbcbb0SMatt Jacob * through setting. The data direction we've preserved all 139005fbcbb0SMatt Jacob * along and only clear it if we're now sending status. 139105fbcbb0SMatt Jacob */ 13929e11e5beSMatt Jacob 13934fd13c1bSMatt Jacob if (nth_ctio == nctios - 1) { 13949e11e5beSMatt Jacob /* 139505fbcbb0SMatt Jacob * We're the last in a sequence of CTIOs, so mark 139605fbcbb0SMatt Jacob * this CTIO and save the handle to the CCB such that 139705fbcbb0SMatt Jacob * when this CTIO completes we can free dma resources 139805fbcbb0SMatt Jacob * and do whatever else we need to do to finish the 1399e9a2738aSMatt Jacob * rest of the command. We *don't* give this to the 1400e9a2738aSMatt Jacob * firmware to work on- the caller will do that. 14019e11e5beSMatt Jacob */ 14024fd13c1bSMatt Jacob 14035f5aafe1SMatt Jacob cto->ct_syshandle = handle; 140405fbcbb0SMatt Jacob cto->ct_header.rqs_seqno = 1; 140505fbcbb0SMatt Jacob 140605fbcbb0SMatt Jacob if (send_status) { 14079e11e5beSMatt Jacob cto->ct_scsi_status = scsi_status; 1408b72b1569SMatt Jacob cto->ct_flags |= sflags; 140905fbcbb0SMatt Jacob cto->ct_resid = resid; 141042426921SMatt Jacob } 1411d02373f1SMatt Jacob if (send_status) { 14124fd13c1bSMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, 1413e9a2738aSMatt Jacob "CTIO[%x] lun%d iid %d tag %x ct_flags %x " 14145f5aafe1SMatt Jacob "scsi status %x resid %d", 14155f5aafe1SMatt Jacob cto->ct_fwhandle, csio->ccb_h.target_lun, 1416e9a2738aSMatt Jacob cto->ct_iid, cto->ct_tag_val, cto->ct_flags, 141705fbcbb0SMatt Jacob cto->ct_scsi_status, cto->ct_resid); 1418d02373f1SMatt Jacob } else { 14194fd13c1bSMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, 1420e9a2738aSMatt Jacob "CTIO[%x] lun%d iid%d tag %x ct_flags 0x%x", 14215f5aafe1SMatt Jacob cto->ct_fwhandle, csio->ccb_h.target_lun, 1422e9a2738aSMatt Jacob cto->ct_iid, cto->ct_tag_val, 1423e9a2738aSMatt Jacob cto->ct_flags); 142405fbcbb0SMatt Jacob } 14254fd13c1bSMatt Jacob isp_put_ctio(isp, cto, qe); 14264fd13c1bSMatt Jacob ISP_TDQE(isp, "last tdma_mk", curi, cto); 14274fd13c1bSMatt Jacob if (nctios > 1) { 14284fd13c1bSMatt Jacob MEMORYBARRIER(isp, SYNC_REQUEST, 14294fd13c1bSMatt Jacob curi, QENTRY_LEN); 14304fd13c1bSMatt Jacob } 14319e11e5beSMatt Jacob } else { 14324fd13c1bSMatt Jacob ct_entry_t *oqe = qe; 143305fbcbb0SMatt Jacob 143405fbcbb0SMatt Jacob /* 14355f5aafe1SMatt Jacob * Make sure syshandle fields are clean 143605fbcbb0SMatt Jacob */ 14375f5aafe1SMatt Jacob cto->ct_syshandle = 0; 14389e11e5beSMatt Jacob cto->ct_header.rqs_seqno = 0; 143905fbcbb0SMatt Jacob 14404fd13c1bSMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, 14415f5aafe1SMatt Jacob "CTIO[%x] lun%d for ID%d ct_flags 0x%x", 14425f5aafe1SMatt Jacob cto->ct_fwhandle, csio->ccb_h.target_lun, 14435f5aafe1SMatt Jacob cto->ct_iid, cto->ct_flags); 144405fbcbb0SMatt Jacob 144505fbcbb0SMatt Jacob /* 144605fbcbb0SMatt Jacob * Get a new CTIO 144705fbcbb0SMatt Jacob */ 14484fd13c1bSMatt Jacob qe = (ct_entry_t *) 14494fd13c1bSMatt Jacob ISP_QUEUE_ENTRY(isp->isp_rquest, nxti); 14504fd13c1bSMatt Jacob nxti = ISP_NXT_QENTRY(nxti, RQUEST_QUEUE_LEN(isp)); 14514fd13c1bSMatt Jacob if (nxti == mp->optr) { 14524fd13c1bSMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 1453f7dddf8aSMatt Jacob "Queue Overflow in tdma_mk"); 14549e11e5beSMatt Jacob mp->error = MUSHERR_NOQENTRIES; 14559e11e5beSMatt Jacob return; 14569e11e5beSMatt Jacob } 14574fd13c1bSMatt Jacob 14589e11e5beSMatt Jacob /* 14594fd13c1bSMatt Jacob * Now that we're done with the old CTIO, 14604fd13c1bSMatt Jacob * flush it out to the request queue. 14614fd13c1bSMatt Jacob */ 14624fd13c1bSMatt Jacob ISP_TDQE(isp, "dma_tgt_fc", curi, cto); 14634fd13c1bSMatt Jacob isp_put_ctio(isp, cto, oqe); 14644fd13c1bSMatt Jacob if (nth_ctio != 0) { 14654fd13c1bSMatt Jacob MEMORYBARRIER(isp, SYNC_REQUEST, curi, 14664fd13c1bSMatt Jacob QENTRY_LEN); 14674fd13c1bSMatt Jacob } 14684fd13c1bSMatt Jacob curi = ISP_NXT_QENTRY(curi, RQUEST_QUEUE_LEN(isp)); 14694fd13c1bSMatt Jacob 14704fd13c1bSMatt Jacob /* 14714fd13c1bSMatt Jacob * Reset some fields in the CTIO so we can reuse 14724fd13c1bSMatt Jacob * for the next one we'll flush to the request 14734fd13c1bSMatt Jacob * queue. 14749e11e5beSMatt Jacob */ 14759e11e5beSMatt Jacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO; 14769e11e5beSMatt Jacob cto->ct_header.rqs_entry_count = 1; 14779e11e5beSMatt Jacob cto->ct_header.rqs_flags = 0; 14789e11e5beSMatt Jacob cto->ct_status = 0; 14799e11e5beSMatt Jacob cto->ct_scsi_status = 0; 14809e11e5beSMatt Jacob cto->ct_xfrlen = 0; 14819e11e5beSMatt Jacob cto->ct_resid = 0; 14829e11e5beSMatt Jacob cto->ct_seg_count = 0; 148305fbcbb0SMatt Jacob MEMZERO(cto->ct_dataseg, sizeof(cto->ct_dataseg)); 14849e11e5beSMatt Jacob } 14859e11e5beSMatt Jacob } 14864fd13c1bSMatt Jacob *mp->nxtip = nxti; 14879e11e5beSMatt Jacob } 14889e11e5beSMatt Jacob 1489fc087171SMatt Jacob /* 1490fc087171SMatt Jacob * We don't have to do multiple CTIOs here. Instead, we can just do 1491fc087171SMatt Jacob * continuation segments as needed. This greatly simplifies the code 1492fc087171SMatt Jacob * improves performance. 1493fc087171SMatt Jacob */ 1494fc087171SMatt Jacob 14959e11e5beSMatt Jacob static void 149605fbcbb0SMatt Jacob tdma_mkfc(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 14979e11e5beSMatt Jacob { 14989e11e5beSMatt Jacob mush_t *mp; 14999e11e5beSMatt Jacob struct ccb_scsiio *csio; 15004fd13c1bSMatt Jacob struct ispsoftc *isp; 15014fd13c1bSMatt Jacob ct2_entry_t *cto, *qe; 15024fd13c1bSMatt Jacob u_int16_t curi, nxti; 1503fc087171SMatt Jacob int segcnt; 15049e11e5beSMatt Jacob 15059e11e5beSMatt Jacob mp = (mush_t *) arg; 15069e11e5beSMatt Jacob if (error) { 15079e11e5beSMatt Jacob mp->error = error; 15089e11e5beSMatt Jacob return; 15099e11e5beSMatt Jacob } 15109e11e5beSMatt Jacob 15114fd13c1bSMatt Jacob isp = mp->isp; 151265b024e1SMatt Jacob csio = mp->cmd_token; 151365b024e1SMatt Jacob cto = mp->rq; 1514fc087171SMatt Jacob 15154fd13c1bSMatt Jacob curi = isp->isp_reqidx; 15164fd13c1bSMatt Jacob qe = (ct2_entry_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, curi); 151765b024e1SMatt Jacob 151865b024e1SMatt Jacob if (nseg == 0) { 151965b024e1SMatt Jacob if ((cto->ct_flags & CT2_FLAG_MMASK) != CT2_FLAG_MODE1) { 15204fd13c1bSMatt Jacob isp_prt(isp, ISP_LOGWARN, 1521f7dddf8aSMatt Jacob "dma2_tgt_fc, a status CTIO2 without MODE1 " 1522f7dddf8aSMatt Jacob "set (0x%x)", cto->ct_flags); 152365b024e1SMatt Jacob mp->error = EINVAL; 152465b024e1SMatt Jacob return; 152565b024e1SMatt Jacob } 152665b024e1SMatt Jacob /* 152765b024e1SMatt Jacob * We preserve ct_lun, ct_iid, ct_rxid. We set the data 152865b024e1SMatt Jacob * flags to NO DATA and clear relative offset flags. 152965b024e1SMatt Jacob * We preserve the ct_resid and the response area. 153065b024e1SMatt Jacob */ 1531fc087171SMatt Jacob cto->ct_header.rqs_seqno = 1; 153265b024e1SMatt Jacob cto->ct_seg_count = 0; 153365b024e1SMatt Jacob cto->ct_reloff = 0; 15344fd13c1bSMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, 15355f5aafe1SMatt Jacob "CTIO2[%x] lun %d->iid%d flgs 0x%x sts 0x%x ssts " 1536d02373f1SMatt Jacob "0x%x res %d", cto->ct_rxid, csio->ccb_h.target_lun, 1537d02373f1SMatt Jacob cto->ct_iid, cto->ct_flags, cto->ct_status, 153865b024e1SMatt Jacob cto->rsp.m1.ct_scsi_status, cto->ct_resid); 15394fd13c1bSMatt Jacob isp_put_ctio2(isp, cto, qe); 15404fd13c1bSMatt Jacob ISP_TDQE(isp, "dma2_tgt_fc[no data]", curi, qe); 15419e11e5beSMatt Jacob return; 15429e11e5beSMatt Jacob } 15439e11e5beSMatt Jacob 154465b024e1SMatt Jacob if ((cto->ct_flags & CT2_FLAG_MMASK) != CT2_FLAG_MODE0) { 1545fc087171SMatt Jacob isp_prt(isp, ISP_LOGERR, 1546f7dddf8aSMatt Jacob "dma2_tgt_fc, a data CTIO2 without MODE0 set " 1547f7dddf8aSMatt Jacob "(0x%x)", cto->ct_flags); 154865b024e1SMatt Jacob mp->error = EINVAL; 154965b024e1SMatt Jacob return; 155065b024e1SMatt Jacob } 155165b024e1SMatt Jacob 155265b024e1SMatt Jacob 15534fd13c1bSMatt Jacob nxti = *mp->nxtip; 15544fd13c1bSMatt Jacob 1555fc087171SMatt Jacob /* 1556fc087171SMatt Jacob * Set up the CTIO2 data segments. 1557fc087171SMatt Jacob */ 1558fc087171SMatt Jacob for (segcnt = 0; cto->ct_seg_count < ISP_RQDSEG_T2 && segcnt < nseg; 1559fc087171SMatt Jacob cto->ct_seg_count++, segcnt++) { 1560fc087171SMatt Jacob cto->rsp.m0.ct_dataseg[cto->ct_seg_count].ds_base = 1561fc087171SMatt Jacob dm_segs[segcnt].ds_addr; 1562fc087171SMatt Jacob cto->rsp.m0.ct_dataseg[cto->ct_seg_count].ds_count = 1563fc087171SMatt Jacob dm_segs[segcnt].ds_len; 1564fc087171SMatt Jacob cto->rsp.m0.ct_xfrlen += dm_segs[segcnt].ds_len; 156576514802SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, 156676514802SMatt Jacob "isp_send_ctio2: ent0[%d]0x%llx:%lld", 156776514802SMatt Jacob cto->ct_seg_count, (long long)dm_segs[segcnt].ds_addr, 156876514802SMatt Jacob (long long)dm_segs[segcnt].ds_len); 1569fc087171SMatt Jacob } 15709e11e5beSMatt Jacob 1571fc087171SMatt Jacob while (segcnt < nseg) { 1572fc087171SMatt Jacob u_int16_t curip; 15734fd13c1bSMatt Jacob int seg; 1574fc087171SMatt Jacob ispcontreq_t local, *crq = &local, *qep; 15759e11e5beSMatt Jacob 1576fc087171SMatt Jacob qep = (ispcontreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, nxti); 1577fc087171SMatt Jacob curip = nxti; 1578fc087171SMatt Jacob nxti = ISP_NXT_QENTRY(curip, RQUEST_QUEUE_LEN(isp)); 15794fd13c1bSMatt Jacob if (nxti == mp->optr) { 1580fc087171SMatt Jacob ISP_UNLOCK(isp); 1581fc087171SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 1582fc087171SMatt Jacob "tdma_mkfc: request queue overflow"); 15839e11e5beSMatt Jacob mp->error = MUSHERR_NOQENTRIES; 15849e11e5beSMatt Jacob return; 15859e11e5beSMatt Jacob } 1586fc087171SMatt Jacob cto->ct_header.rqs_entry_count++; 1587fc087171SMatt Jacob MEMZERO((void *)crq, sizeof (*crq)); 1588fc087171SMatt Jacob crq->req_header.rqs_entry_count = 1; 1589fc087171SMatt Jacob crq->req_header.rqs_entry_type = RQSTYPE_DATASEG; 1590fc087171SMatt Jacob for (seg = 0; segcnt < nseg && seg < ISP_CDSEG; 1591fc087171SMatt Jacob segcnt++, seg++) { 1592fc087171SMatt Jacob crq->req_dataseg[seg].ds_base = dm_segs[segcnt].ds_addr; 1593fc087171SMatt Jacob crq->req_dataseg[seg].ds_count = dm_segs[segcnt].ds_len; 1594fc087171SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, 159576514802SMatt Jacob "isp_send_ctio2: ent%d[%d]0x%llx:%lld", 1596fc087171SMatt Jacob cto->ct_header.rqs_entry_count-1, seg, 159776514802SMatt Jacob (long long) dm_segs[segcnt].ds_addr, 159876514802SMatt Jacob (long long) dm_segs[segcnt].ds_len); 1599fc087171SMatt Jacob cto->rsp.m0.ct_xfrlen += dm_segs[segcnt].ds_len; 1600fc087171SMatt Jacob cto->ct_seg_count++; 1601fc087171SMatt Jacob } 1602fc087171SMatt Jacob MEMORYBARRIER(isp, SYNC_REQUEST, curip, QENTRY_LEN); 1603fc087171SMatt Jacob isp_put_cont_req(isp, crq, qep); 1604fc087171SMatt Jacob ISP_TDQE(isp, "cont entry", curi, qep); 1605fc087171SMatt Jacob } 160665b024e1SMatt Jacob 16079e11e5beSMatt Jacob /* 1608fc087171SMatt Jacob * No do final twiddling for the CTIO itself. 16094fd13c1bSMatt Jacob */ 1610fc087171SMatt Jacob cto->ct_header.rqs_seqno = 1; 1611fc087171SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, 1612fc087171SMatt Jacob "CTIO2[%x] lun %d->iid%d flgs 0x%x sts 0x%x ssts 0x%x resid %d", 1613fc087171SMatt Jacob cto->ct_rxid, csio->ccb_h.target_lun, (int) cto->ct_iid, 1614fc087171SMatt Jacob cto->ct_flags, cto->ct_status, cto->rsp.m1.ct_scsi_status, 1615fc087171SMatt Jacob cto->ct_resid); 1616fc087171SMatt Jacob isp_put_ctio2(isp, cto, qe); 1617fc087171SMatt Jacob ISP_TDQE(isp, "last dma2_tgt_fc", curi, qe); 16184fd13c1bSMatt Jacob *mp->nxtip = nxti; 16199e11e5beSMatt Jacob } 16209e11e5beSMatt Jacob #endif 16219e11e5beSMatt Jacob 1622126ec864SMatt Jacob static void dma2(void *, bus_dma_segment_t *, int, int); 16239e11e5beSMatt Jacob 16249e11e5beSMatt Jacob static void 16259e11e5beSMatt Jacob dma2(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 16269e11e5beSMatt Jacob { 16279e11e5beSMatt Jacob mush_t *mp; 16284fd13c1bSMatt Jacob struct ispsoftc *isp; 16299e11e5beSMatt Jacob struct ccb_scsiio *csio; 16301923f739SMatt Jacob struct isp_pcisoftc *pcs; 16319e11e5beSMatt Jacob bus_dmamap_t *dp; 16329e11e5beSMatt Jacob bus_dma_segment_t *eseg; 16339e11e5beSMatt Jacob ispreq_t *rq; 16349e11e5beSMatt Jacob int seglim, datalen; 16354fd13c1bSMatt Jacob u_int16_t nxti; 16369e11e5beSMatt Jacob 16379e11e5beSMatt Jacob mp = (mush_t *) arg; 16389e11e5beSMatt Jacob if (error) { 16399e11e5beSMatt Jacob mp->error = error; 16409e11e5beSMatt Jacob return; 16419e11e5beSMatt Jacob } 16429e11e5beSMatt Jacob 16439e11e5beSMatt Jacob if (nseg < 1) { 1644f7dddf8aSMatt Jacob isp_prt(mp->isp, ISP_LOGERR, "bad segment count (%d)", nseg); 16459e11e5beSMatt Jacob mp->error = EFAULT; 16469e11e5beSMatt Jacob return; 16479e11e5beSMatt Jacob } 16489e11e5beSMatt Jacob csio = mp->cmd_token; 16494fd13c1bSMatt Jacob isp = mp->isp; 16509e11e5beSMatt Jacob rq = mp->rq; 16511923f739SMatt Jacob pcs = (struct isp_pcisoftc *)mp->isp; 16521923f739SMatt Jacob dp = &pcs->dmaps[isp_handle_index(rq->req_handle)]; 16534fd13c1bSMatt Jacob nxti = *mp->nxtip; 16549e11e5beSMatt Jacob 16559e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 16561923f739SMatt Jacob bus_dmamap_sync(pcs->dmat, *dp, BUS_DMASYNC_PREREAD); 16579e11e5beSMatt Jacob } else { 16581923f739SMatt Jacob bus_dmamap_sync(pcs->dmat, *dp, BUS_DMASYNC_PREWRITE); 16599e11e5beSMatt Jacob } 16609e11e5beSMatt Jacob 16619e11e5beSMatt Jacob datalen = XS_XFRLEN(csio); 16629e11e5beSMatt Jacob 16639e11e5beSMatt Jacob /* 16649e11e5beSMatt Jacob * We're passed an initial partially filled in entry that 16659e11e5beSMatt Jacob * has most fields filled in except for data transfer 16669e11e5beSMatt Jacob * related values. 16679e11e5beSMatt Jacob * 16689e11e5beSMatt Jacob * Our job is to fill in the initial request queue entry and 16699e11e5beSMatt Jacob * then to start allocating and filling in continuation entries 16709e11e5beSMatt Jacob * until we've covered the entire transfer. 16719e11e5beSMatt Jacob */ 16729e11e5beSMatt Jacob 16734fd13c1bSMatt Jacob if (IS_FC(isp)) { 1674d720e6d5SJustin T. Gibbs seglim = ISP_RQDSEG_T2; 1675d720e6d5SJustin T. Gibbs ((ispreqt2_t *)rq)->req_totalcnt = datalen; 16769e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 16779e11e5beSMatt Jacob ((ispreqt2_t *)rq)->req_flags |= REQFLAG_DATA_IN; 16789e11e5beSMatt Jacob } else { 16799e11e5beSMatt Jacob ((ispreqt2_t *)rq)->req_flags |= REQFLAG_DATA_OUT; 16809e11e5beSMatt Jacob } 1681d720e6d5SJustin T. Gibbs } else { 1682e142669aSMatt Jacob if (csio->cdb_len > 12) { 1683e142669aSMatt Jacob seglim = 0; 1684e142669aSMatt Jacob } else { 1685d720e6d5SJustin T. Gibbs seglim = ISP_RQDSEG; 1686e142669aSMatt Jacob } 16879e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 16889e11e5beSMatt Jacob rq->req_flags |= REQFLAG_DATA_IN; 16899e11e5beSMatt Jacob } else { 16909e11e5beSMatt Jacob rq->req_flags |= REQFLAG_DATA_OUT; 16919e11e5beSMatt Jacob } 1692d720e6d5SJustin T. Gibbs } 1693d720e6d5SJustin T. Gibbs 1694d720e6d5SJustin T. Gibbs eseg = dm_segs + nseg; 1695d720e6d5SJustin T. Gibbs 1696d720e6d5SJustin T. Gibbs while (datalen != 0 && rq->req_seg_count < seglim && dm_segs != eseg) { 16974fd13c1bSMatt Jacob if (IS_FC(isp)) { 1698d720e6d5SJustin T. Gibbs ispreqt2_t *rq2 = (ispreqt2_t *)rq; 1699d720e6d5SJustin T. Gibbs rq2->req_dataseg[rq2->req_seg_count].ds_base = 1700d720e6d5SJustin T. Gibbs dm_segs->ds_addr; 1701d720e6d5SJustin T. Gibbs rq2->req_dataseg[rq2->req_seg_count].ds_count = 1702d720e6d5SJustin T. Gibbs dm_segs->ds_len; 1703d720e6d5SJustin T. Gibbs } else { 1704d720e6d5SJustin T. Gibbs rq->req_dataseg[rq->req_seg_count].ds_base = 1705d720e6d5SJustin T. Gibbs dm_segs->ds_addr; 1706d720e6d5SJustin T. Gibbs rq->req_dataseg[rq->req_seg_count].ds_count = 1707d720e6d5SJustin T. Gibbs dm_segs->ds_len; 1708d720e6d5SJustin T. Gibbs } 1709d720e6d5SJustin T. Gibbs datalen -= dm_segs->ds_len; 1710d720e6d5SJustin T. Gibbs rq->req_seg_count++; 1711d720e6d5SJustin T. Gibbs dm_segs++; 1712d720e6d5SJustin T. Gibbs } 1713d720e6d5SJustin T. Gibbs 1714d720e6d5SJustin T. Gibbs while (datalen > 0 && dm_segs != eseg) { 17154fd13c1bSMatt Jacob u_int16_t onxti; 17164fd13c1bSMatt Jacob ispcontreq_t local, *crq = &local, *cqe; 17174fd13c1bSMatt Jacob 17184fd13c1bSMatt Jacob cqe = (ispcontreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, nxti); 17194fd13c1bSMatt Jacob onxti = nxti; 17204fd13c1bSMatt Jacob nxti = ISP_NXT_QENTRY(onxti, RQUEST_QUEUE_LEN(isp)); 17214fd13c1bSMatt Jacob if (nxti == mp->optr) { 17224fd13c1bSMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, "Request Queue Overflow++"); 17234873663cSMatt Jacob mp->error = MUSHERR_NOQENTRIES; 1724d720e6d5SJustin T. Gibbs return; 1725d720e6d5SJustin T. Gibbs } 1726d720e6d5SJustin T. Gibbs rq->req_header.rqs_entry_count++; 17274fd13c1bSMatt Jacob MEMZERO((void *)crq, sizeof (*crq)); 1728d720e6d5SJustin T. Gibbs crq->req_header.rqs_entry_count = 1; 1729d720e6d5SJustin T. Gibbs crq->req_header.rqs_entry_type = RQSTYPE_DATASEG; 1730d720e6d5SJustin T. Gibbs 1731d720e6d5SJustin T. Gibbs seglim = 0; 1732d720e6d5SJustin T. Gibbs while (datalen > 0 && seglim < ISP_CDSEG && dm_segs != eseg) { 1733d720e6d5SJustin T. Gibbs crq->req_dataseg[seglim].ds_base = 1734d720e6d5SJustin T. Gibbs dm_segs->ds_addr; 1735d720e6d5SJustin T. Gibbs crq->req_dataseg[seglim].ds_count = 1736d720e6d5SJustin T. Gibbs dm_segs->ds_len; 1737d720e6d5SJustin T. Gibbs rq->req_seg_count++; 1738d720e6d5SJustin T. Gibbs dm_segs++; 1739d720e6d5SJustin T. Gibbs seglim++; 1740d720e6d5SJustin T. Gibbs datalen -= dm_segs->ds_len; 1741d720e6d5SJustin T. Gibbs } 17424fd13c1bSMatt Jacob isp_put_cont_req(isp, crq, cqe); 17434fd13c1bSMatt Jacob MEMORYBARRIER(isp, SYNC_REQUEST, onxti, QENTRY_LEN); 1744d720e6d5SJustin T. Gibbs } 17454fd13c1bSMatt Jacob *mp->nxtip = nxti; 1746d720e6d5SJustin T. Gibbs } 1747d720e6d5SJustin T. Gibbs 1748d720e6d5SJustin T. Gibbs static int 17499e11e5beSMatt Jacob isp_pci_dmasetup(struct ispsoftc *isp, struct ccb_scsiio *csio, ispreq_t *rq, 17504fd13c1bSMatt Jacob u_int16_t *nxtip, u_int16_t optr) 1751d720e6d5SJustin T. Gibbs { 17521923f739SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *)isp; 17534fd13c1bSMatt Jacob ispreq_t *qep; 17540a5f7e8bSMatt Jacob bus_dmamap_t *dp = NULL; 1755d720e6d5SJustin T. Gibbs mush_t mush, *mp; 1756126ec864SMatt Jacob void (*eptr)(void *, bus_dma_segment_t *, int, int); 1757d720e6d5SJustin T. Gibbs 17584fd13c1bSMatt Jacob qep = (ispreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, isp->isp_reqidx); 175965b024e1SMatt Jacob #ifdef ISP_TARGET_MODE 176065b024e1SMatt Jacob if (csio->ccb_h.func_code == XPT_CONT_TARGET_IO) { 176165b024e1SMatt Jacob if (IS_FC(isp)) { 176205fbcbb0SMatt Jacob eptr = tdma_mkfc; 176365b024e1SMatt Jacob } else { 176405fbcbb0SMatt Jacob eptr = tdma_mk; 176565b024e1SMatt Jacob } 176605fbcbb0SMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE || 176705fbcbb0SMatt Jacob (csio->dxfer_len == 0)) { 176865b024e1SMatt Jacob mp = &mush; 176965b024e1SMatt Jacob mp->isp = isp; 177065b024e1SMatt Jacob mp->cmd_token = csio; 1771e9a2738aSMatt Jacob mp->rq = rq; /* really a ct_entry_t or ct2_entry_t */ 17724fd13c1bSMatt Jacob mp->nxtip = nxtip; 177365b024e1SMatt Jacob mp->optr = optr; 177465b024e1SMatt Jacob mp->error = 0; 177565b024e1SMatt Jacob (*eptr)(mp, NULL, 0, 0); 17764fd13c1bSMatt Jacob goto mbxsync; 177765b024e1SMatt Jacob } 177865b024e1SMatt Jacob } else 177965b024e1SMatt Jacob #endif 178065b024e1SMatt Jacob eptr = dma2; 178165b024e1SMatt Jacob 17824fd13c1bSMatt Jacob 178305fbcbb0SMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE || 178405fbcbb0SMatt Jacob (csio->dxfer_len == 0)) { 178542426921SMatt Jacob rq->req_seg_count = 1; 17864fd13c1bSMatt Jacob goto mbxsync; 178742426921SMatt Jacob } 178842426921SMatt Jacob 1789d720e6d5SJustin T. Gibbs /* 1790d720e6d5SJustin T. Gibbs * Do a virtual grapevine step to collect info for 17914873663cSMatt Jacob * the callback dma allocation that we have to use... 1792d720e6d5SJustin T. Gibbs */ 1793d720e6d5SJustin T. Gibbs mp = &mush; 1794d720e6d5SJustin T. Gibbs mp->isp = isp; 17959e11e5beSMatt Jacob mp->cmd_token = csio; 1796d720e6d5SJustin T. Gibbs mp->rq = rq; 17974fd13c1bSMatt Jacob mp->nxtip = nxtip; 1798d720e6d5SJustin T. Gibbs mp->optr = optr; 1799d720e6d5SJustin T. Gibbs mp->error = 0; 1800d720e6d5SJustin T. Gibbs 18019e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_SCATTER_VALID) == 0) { 18029e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DATA_PHYS) == 0) { 18034873663cSMatt Jacob int error, s; 18041923f739SMatt Jacob dp = &pcs->dmaps[isp_handle_index(rq->req_handle)]; 1805d720e6d5SJustin T. Gibbs s = splsoftvm(); 18061923f739SMatt Jacob error = bus_dmamap_load(pcs->dmat, *dp, 18079e11e5beSMatt Jacob csio->data_ptr, csio->dxfer_len, eptr, mp, 0); 1808d720e6d5SJustin T. Gibbs if (error == EINPROGRESS) { 18091923f739SMatt Jacob bus_dmamap_unload(pcs->dmat, *dp); 1810d720e6d5SJustin T. Gibbs mp->error = EINVAL; 1811f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 1812f7dddf8aSMatt Jacob "deferred dma allocation not supported"); 1813d720e6d5SJustin T. Gibbs } else if (error && mp->error == 0) { 18140a5f7e8bSMatt Jacob #ifdef DIAGNOSTIC 18156e5c5328SMatt Jacob isp_prt(isp, ISP_LOGERR, 18166e5c5328SMatt Jacob "error %d in dma mapping code", error); 18170a5f7e8bSMatt Jacob #endif 1818d720e6d5SJustin T. Gibbs mp->error = error; 1819d720e6d5SJustin T. Gibbs } 18204873663cSMatt Jacob splx(s); 1821d720e6d5SJustin T. Gibbs } else { 1822d720e6d5SJustin T. Gibbs /* Pointer to physical buffer */ 1823d720e6d5SJustin T. Gibbs struct bus_dma_segment seg; 1824d720e6d5SJustin T. Gibbs seg.ds_addr = (bus_addr_t)csio->data_ptr; 1825d720e6d5SJustin T. Gibbs seg.ds_len = csio->dxfer_len; 18269e11e5beSMatt Jacob (*eptr)(mp, &seg, 1, 0); 1827d720e6d5SJustin T. Gibbs } 1828d720e6d5SJustin T. Gibbs } else { 1829d720e6d5SJustin T. Gibbs struct bus_dma_segment *segs; 1830d720e6d5SJustin T. Gibbs 18319e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DATA_PHYS) != 0) { 1832f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 1833f7dddf8aSMatt Jacob "Physical segment pointers unsupported"); 1834d720e6d5SJustin T. Gibbs mp->error = EINVAL; 18359e11e5beSMatt Jacob } else if ((csio->ccb_h.flags & CAM_SG_LIST_PHYS) == 0) { 1836f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 1837f7dddf8aSMatt Jacob "Virtual segment addresses unsupported"); 1838d720e6d5SJustin T. Gibbs mp->error = EINVAL; 1839d720e6d5SJustin T. Gibbs } else { 1840d720e6d5SJustin T. Gibbs /* Just use the segments provided */ 1841d720e6d5SJustin T. Gibbs segs = (struct bus_dma_segment *) csio->data_ptr; 18429e11e5beSMatt Jacob (*eptr)(mp, segs, csio->sglist_cnt, 0); 1843d720e6d5SJustin T. Gibbs } 1844d720e6d5SJustin T. Gibbs } 1845d720e6d5SJustin T. Gibbs if (mp->error) { 18464873663cSMatt Jacob int retval = CMD_COMPLETE; 18474873663cSMatt Jacob if (mp->error == MUSHERR_NOQENTRIES) { 18484873663cSMatt Jacob retval = CMD_EAGAIN; 18494873663cSMatt Jacob } else if (mp->error == EFBIG) { 18500a5f7e8bSMatt Jacob XS_SETERR(csio, CAM_REQ_TOO_BIG); 1851d720e6d5SJustin T. Gibbs } else if (mp->error == EINVAL) { 18520a5f7e8bSMatt Jacob XS_SETERR(csio, CAM_REQ_INVALID); 1853d720e6d5SJustin T. Gibbs } else { 18540a5f7e8bSMatt Jacob XS_SETERR(csio, CAM_UNREC_HBA_ERROR); 1855d720e6d5SJustin T. Gibbs } 18564873663cSMatt Jacob return (retval); 18570a5f7e8bSMatt Jacob } 18584fd13c1bSMatt Jacob mbxsync: 18594fd13c1bSMatt Jacob switch (rq->req_header.rqs_entry_type) { 18604fd13c1bSMatt Jacob case RQSTYPE_REQUEST: 18614fd13c1bSMatt Jacob isp_put_request(isp, rq, qep); 18624fd13c1bSMatt Jacob break; 18634fd13c1bSMatt Jacob case RQSTYPE_CMDONLY: 18644fd13c1bSMatt Jacob isp_put_extended_request(isp, (ispextreq_t *)rq, 18654fd13c1bSMatt Jacob (ispextreq_t *)qep); 18664fd13c1bSMatt Jacob break; 18674fd13c1bSMatt Jacob case RQSTYPE_T2RQS: 18684fd13c1bSMatt Jacob isp_put_request_t2(isp, (ispreqt2_t *) rq, (ispreqt2_t *) qep); 18694fd13c1bSMatt Jacob break; 18700a5f7e8bSMatt Jacob } 18714873663cSMatt Jacob return (CMD_QUEUED); 1872d720e6d5SJustin T. Gibbs } 1873d720e6d5SJustin T. Gibbs 1874d720e6d5SJustin T. Gibbs static void 1875d8d5f2adSMatt Jacob isp_pci_dmateardown(struct ispsoftc *isp, XS_T *xs, u_int16_t handle) 1876d720e6d5SJustin T. Gibbs { 18771923f739SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *)isp; 18781923f739SMatt Jacob bus_dmamap_t *dp = &pcs->dmaps[isp_handle_index(handle)]; 1879a95ae193SMatt Jacob if ((xs->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 18801923f739SMatt Jacob bus_dmamap_sync(pcs->dmat, *dp, BUS_DMASYNC_POSTREAD); 1881d720e6d5SJustin T. Gibbs } else { 18821923f739SMatt Jacob bus_dmamap_sync(pcs->dmat, *dp, BUS_DMASYNC_POSTWRITE); 1883d720e6d5SJustin T. Gibbs } 18841923f739SMatt Jacob bus_dmamap_unload(pcs->dmat, *dp); 1885d720e6d5SJustin T. Gibbs } 1886d720e6d5SJustin T. Gibbs 188765adb54cSMatt Jacob 188865adb54cSMatt Jacob static void 188917e318c6SMatt Jacob isp_pci_reset1(struct ispsoftc *isp) 189065adb54cSMatt Jacob { 189165adb54cSMatt Jacob /* Make sure the BIOS is disabled */ 189265adb54cSMatt Jacob isp_pci_wr_reg(isp, HCCR, PCI_HCCR_CMD_BIOS); 1893469b6b9eSMatt Jacob /* and enable interrupts */ 1894469b6b9eSMatt Jacob ENABLE_INTS(isp); 189565adb54cSMatt Jacob } 189665adb54cSMatt Jacob 189765adb54cSMatt Jacob static void 1898d02373f1SMatt Jacob isp_pci_dumpregs(struct ispsoftc *isp, const char *msg) 189965adb54cSMatt Jacob { 19001923f739SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *)isp; 1901d02373f1SMatt Jacob if (msg) 19026e5c5328SMatt Jacob printf("%s: %s\n", device_get_nameunit(isp->isp_dev), msg); 19036e5c5328SMatt Jacob else 19046e5c5328SMatt Jacob printf("%s:\n", device_get_nameunit(isp->isp_dev)); 1905d02373f1SMatt Jacob if (IS_SCSI(isp)) 1906d02373f1SMatt Jacob printf(" biu_conf1=%x", ISP_READ(isp, BIU_CONF1)); 1907d02373f1SMatt Jacob else 1908d02373f1SMatt Jacob printf(" biu_csr=%x", ISP_READ(isp, BIU2100_CSR)); 1909d02373f1SMatt Jacob printf(" biu_icr=%x biu_isr=%x biu_sema=%x ", ISP_READ(isp, BIU_ICR), 1910d02373f1SMatt Jacob ISP_READ(isp, BIU_ISR), ISP_READ(isp, BIU_SEMA)); 1911d02373f1SMatt Jacob printf("risc_hccr=%x\n", ISP_READ(isp, HCCR)); 1912d02373f1SMatt Jacob 1913d02373f1SMatt Jacob 1914d02373f1SMatt Jacob if (IS_SCSI(isp)) { 1915d02373f1SMatt Jacob ISP_WRITE(isp, HCCR, HCCR_CMD_PAUSE); 1916d02373f1SMatt Jacob printf(" cdma_conf=%x cdma_sts=%x cdma_fifostat=%x\n", 1917d02373f1SMatt Jacob ISP_READ(isp, CDMA_CONF), ISP_READ(isp, CDMA_STATUS), 1918d02373f1SMatt Jacob ISP_READ(isp, CDMA_FIFO_STS)); 1919d02373f1SMatt Jacob printf(" ddma_conf=%x ddma_sts=%x ddma_fifostat=%x\n", 1920d02373f1SMatt Jacob ISP_READ(isp, DDMA_CONF), ISP_READ(isp, DDMA_STATUS), 1921d02373f1SMatt Jacob ISP_READ(isp, DDMA_FIFO_STS)); 1922d02373f1SMatt Jacob printf(" sxp_int=%x sxp_gross=%x sxp(scsi_ctrl)=%x\n", 1923d02373f1SMatt Jacob ISP_READ(isp, SXP_INTERRUPT), 1924d02373f1SMatt Jacob ISP_READ(isp, SXP_GROSS_ERR), 1925d02373f1SMatt Jacob ISP_READ(isp, SXP_PINS_CTRL)); 1926d02373f1SMatt Jacob ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE); 1927d02373f1SMatt Jacob } 1928d02373f1SMatt Jacob printf(" mbox regs: %x %x %x %x %x\n", 1929d02373f1SMatt Jacob ISP_READ(isp, OUTMAILBOX0), ISP_READ(isp, OUTMAILBOX1), 1930d02373f1SMatt Jacob ISP_READ(isp, OUTMAILBOX2), ISP_READ(isp, OUTMAILBOX3), 1931d02373f1SMatt Jacob ISP_READ(isp, OUTMAILBOX4)); 1932d02373f1SMatt Jacob printf(" PCI Status Command/Status=%x\n", 19331923f739SMatt Jacob pci_read_config(pcs->pci_dev, PCIR_COMMAND, 1)); 193465adb54cSMatt Jacob } 1935