1aad970f1SDavid E. O'Brien /*- 265adb54cSMatt Jacob * PCI specific probe and attach routines for Qlogic ISP SCSI adapters. 365adb54cSMatt Jacob * FreeBSD Version. 465adb54cSMatt Jacob * 5e5265237SMatt Jacob * Copyright (c) 1997-2006 by Matthew Jacob 6e5265237SMatt Jacob * All rights reserved. 765adb54cSMatt Jacob * 865adb54cSMatt Jacob * Redistribution and use in source and binary forms, with or without 965adb54cSMatt Jacob * modification, are permitted provided that the following conditions 1065adb54cSMatt Jacob * are met: 1165adb54cSMatt Jacob * 1. Redistributions of source code must retain the above copyright 1265adb54cSMatt Jacob * notice immediately at the beginning of the file, without modification, 1365adb54cSMatt Jacob * this list of conditions, and the following disclaimer. 14aa57fd6fSMatt Jacob * 2. The name of the author may not be used to endorse or promote products 15aa57fd6fSMatt Jacob * derived from this software without specific prior written permission. 1665adb54cSMatt Jacob * 1765adb54cSMatt Jacob * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1865adb54cSMatt Jacob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1965adb54cSMatt Jacob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2065adb54cSMatt Jacob * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2165adb54cSMatt Jacob * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2265adb54cSMatt Jacob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2365adb54cSMatt Jacob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2465adb54cSMatt Jacob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2565adb54cSMatt Jacob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2665adb54cSMatt Jacob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2765adb54cSMatt Jacob * SUCH DAMAGE. 28e5265237SMatt Jacob * 2965adb54cSMatt Jacob */ 30d720e6d5SJustin T. Gibbs 31aad970f1SDavid E. O'Brien #include <sys/cdefs.h> 32aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$"); 33aad970f1SDavid E. O'Brien 34960f6939SMatt Jacob #include <sys/param.h> 35960f6939SMatt Jacob #include <sys/systm.h> 36960f6939SMatt Jacob #include <sys/kernel.h> 37960f6939SMatt Jacob #include <sys/module.h> 38960f6939SMatt Jacob #include <sys/bus.h> 3974a96f43SJohn Baldwin #include <sys/stdint.h> 4065adb54cSMatt Jacob 4177e6a3b2SWarner Losh #include <dev/pci/pcireg.h> 4277e6a3b2SWarner Losh #include <dev/pci/pcivar.h> 4365adb54cSMatt Jacob 44d720e6d5SJustin T. Gibbs #include <machine/bus.h> 45960f6939SMatt Jacob #include <machine/resource.h> 46960f6939SMatt Jacob #include <sys/rman.h> 47960f6939SMatt Jacob #include <sys/malloc.h> 48960f6939SMatt Jacob 49960f6939SMatt Jacob #include <dev/isp/isp_freebsd.h> 50d59bd469SMatt Jacob 511dae40ebSMatt Jacob static uint16_t isp_pci_rd_reg(struct ispsoftc *, int); 521dae40ebSMatt Jacob static void isp_pci_wr_reg(struct ispsoftc *, int, uint16_t); 531dae40ebSMatt Jacob static uint16_t isp_pci_rd_reg_1080(struct ispsoftc *, int); 541dae40ebSMatt Jacob static void isp_pci_wr_reg_1080(struct ispsoftc *, int, uint16_t); 55126ec864SMatt Jacob static int 561dae40ebSMatt Jacob isp_pci_rd_isr(struct ispsoftc *, uint16_t *, uint16_t *, uint16_t *); 57126ec864SMatt Jacob static int 581dae40ebSMatt Jacob isp_pci_rd_isr_2300(struct ispsoftc *, uint16_t *, uint16_t *, uint16_t *); 59126ec864SMatt Jacob static int isp_pci_mbxdma(struct ispsoftc *); 60126ec864SMatt Jacob static int 611dae40ebSMatt Jacob isp_pci_dmasetup(struct ispsoftc *, XS_T *, ispreq_t *, uint16_t *, uint16_t); 62d720e6d5SJustin T. Gibbs static void 631dae40ebSMatt Jacob isp_pci_dmateardown(struct ispsoftc *, XS_T *, uint16_t); 6465adb54cSMatt Jacob 65126ec864SMatt Jacob static void isp_pci_reset1(struct ispsoftc *); 66126ec864SMatt Jacob static void isp_pci_dumpregs(struct ispsoftc *, const char *); 6765adb54cSMatt Jacob 6865adb54cSMatt Jacob static struct ispmdvec mdvec = { 69126ec864SMatt Jacob isp_pci_rd_isr, 7065adb54cSMatt Jacob isp_pci_rd_reg, 7165adb54cSMatt Jacob isp_pci_wr_reg, 7265adb54cSMatt Jacob isp_pci_mbxdma, 7365adb54cSMatt Jacob isp_pci_dmasetup, 74d720e6d5SJustin T. Gibbs isp_pci_dmateardown, 7565adb54cSMatt Jacob NULL, 7665adb54cSMatt Jacob isp_pci_reset1, 7765adb54cSMatt Jacob isp_pci_dumpregs, 7856aef503SMatt Jacob NULL, 79d02373f1SMatt Jacob BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64 8065adb54cSMatt Jacob }; 8165adb54cSMatt Jacob 82d59bd469SMatt Jacob static struct ispmdvec mdvec_1080 = { 83126ec864SMatt Jacob isp_pci_rd_isr, 84d59bd469SMatt Jacob isp_pci_rd_reg_1080, 85d59bd469SMatt Jacob isp_pci_wr_reg_1080, 86d59bd469SMatt Jacob isp_pci_mbxdma, 87d59bd469SMatt Jacob isp_pci_dmasetup, 88d59bd469SMatt Jacob isp_pci_dmateardown, 89d59bd469SMatt Jacob NULL, 90d59bd469SMatt Jacob isp_pci_reset1, 91d59bd469SMatt Jacob isp_pci_dumpregs, 9256aef503SMatt Jacob NULL, 93d02373f1SMatt Jacob BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64 94d59bd469SMatt Jacob }; 95d59bd469SMatt Jacob 96960f6939SMatt Jacob static struct ispmdvec mdvec_12160 = { 97126ec864SMatt Jacob isp_pci_rd_isr, 98960f6939SMatt Jacob isp_pci_rd_reg_1080, 99960f6939SMatt Jacob isp_pci_wr_reg_1080, 100960f6939SMatt Jacob isp_pci_mbxdma, 101960f6939SMatt Jacob isp_pci_dmasetup, 102960f6939SMatt Jacob isp_pci_dmateardown, 103960f6939SMatt Jacob NULL, 104960f6939SMatt Jacob isp_pci_reset1, 105960f6939SMatt Jacob isp_pci_dumpregs, 10656aef503SMatt Jacob NULL, 107d02373f1SMatt Jacob BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64 108960f6939SMatt Jacob }; 109960f6939SMatt Jacob 11065adb54cSMatt Jacob static struct ispmdvec mdvec_2100 = { 111126ec864SMatt Jacob isp_pci_rd_isr, 11265adb54cSMatt Jacob isp_pci_rd_reg, 11365adb54cSMatt Jacob isp_pci_wr_reg, 11465adb54cSMatt Jacob isp_pci_mbxdma, 11565adb54cSMatt Jacob isp_pci_dmasetup, 116d720e6d5SJustin T. Gibbs isp_pci_dmateardown, 11765adb54cSMatt Jacob NULL, 11865adb54cSMatt Jacob isp_pci_reset1, 119d02373f1SMatt Jacob isp_pci_dumpregs 12065adb54cSMatt Jacob }; 121222bb542SMatt Jacob 122222bb542SMatt Jacob static struct ispmdvec mdvec_2200 = { 123126ec864SMatt Jacob isp_pci_rd_isr, 124126ec864SMatt Jacob isp_pci_rd_reg, 125126ec864SMatt Jacob isp_pci_wr_reg, 126126ec864SMatt Jacob isp_pci_mbxdma, 127126ec864SMatt Jacob isp_pci_dmasetup, 128126ec864SMatt Jacob isp_pci_dmateardown, 129126ec864SMatt Jacob NULL, 130126ec864SMatt Jacob isp_pci_reset1, 131126ec864SMatt Jacob isp_pci_dumpregs 132126ec864SMatt Jacob }; 133126ec864SMatt Jacob 134126ec864SMatt Jacob static struct ispmdvec mdvec_2300 = { 135126ec864SMatt Jacob isp_pci_rd_isr_2300, 136222bb542SMatt Jacob isp_pci_rd_reg, 137222bb542SMatt Jacob isp_pci_wr_reg, 138222bb542SMatt Jacob isp_pci_mbxdma, 139222bb542SMatt Jacob isp_pci_dmasetup, 140222bb542SMatt Jacob isp_pci_dmateardown, 141222bb542SMatt Jacob NULL, 142222bb542SMatt Jacob isp_pci_reset1, 143d02373f1SMatt Jacob isp_pci_dumpregs 144222bb542SMatt Jacob }; 145d951bbcaSMatt Jacob 14665adb54cSMatt Jacob #ifndef PCIM_CMD_INVEN 14765adb54cSMatt Jacob #define PCIM_CMD_INVEN 0x10 14865adb54cSMatt Jacob #endif 14965adb54cSMatt Jacob #ifndef PCIM_CMD_BUSMASTEREN 15065adb54cSMatt Jacob #define PCIM_CMD_BUSMASTEREN 0x0004 15165adb54cSMatt Jacob #endif 152d951bbcaSMatt Jacob #ifndef PCIM_CMD_PERRESPEN 153d951bbcaSMatt Jacob #define PCIM_CMD_PERRESPEN 0x0040 154d951bbcaSMatt Jacob #endif 155d951bbcaSMatt Jacob #ifndef PCIM_CMD_SEREN 156d951bbcaSMatt Jacob #define PCIM_CMD_SEREN 0x0100 157d951bbcaSMatt Jacob #endif 158d951bbcaSMatt Jacob 159d951bbcaSMatt Jacob #ifndef PCIR_COMMAND 160d951bbcaSMatt Jacob #define PCIR_COMMAND 0x04 161d951bbcaSMatt Jacob #endif 162d951bbcaSMatt Jacob 163d951bbcaSMatt Jacob #ifndef PCIR_CACHELNSZ 164d951bbcaSMatt Jacob #define PCIR_CACHELNSZ 0x0c 165d951bbcaSMatt Jacob #endif 166d951bbcaSMatt Jacob 167d951bbcaSMatt Jacob #ifndef PCIR_LATTIMER 168d951bbcaSMatt Jacob #define PCIR_LATTIMER 0x0d 169d951bbcaSMatt Jacob #endif 170d951bbcaSMatt Jacob 171ab6d0040SMatt Jacob #ifndef PCIR_ROMADDR 172ab6d0040SMatt Jacob #define PCIR_ROMADDR 0x30 173ab6d0040SMatt Jacob #endif 174ab6d0040SMatt Jacob 17565adb54cSMatt Jacob #ifndef PCI_VENDOR_QLOGIC 17665adb54cSMatt Jacob #define PCI_VENDOR_QLOGIC 0x1077 17765adb54cSMatt Jacob #endif 17865adb54cSMatt Jacob 17965adb54cSMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP1020 18065adb54cSMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP1020 0x1020 18165adb54cSMatt Jacob #endif 18265adb54cSMatt Jacob 183d59bd469SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP1080 184d59bd469SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP1080 0x1080 185d59bd469SMatt Jacob #endif 186d59bd469SMatt Jacob 187f556e83bSMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP10160 188f556e83bSMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP10160 0x1016 189f556e83bSMatt Jacob #endif 190f556e83bSMatt Jacob 191960f6939SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP12160 192960f6939SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP12160 0x1216 193960f6939SMatt Jacob #endif 194960f6939SMatt Jacob 195d59bd469SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP1240 196d59bd469SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP1240 0x1240 197d59bd469SMatt Jacob #endif 19865adb54cSMatt Jacob 19922e1dc85SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP1280 20022e1dc85SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP1280 0x1280 20122e1dc85SMatt Jacob #endif 20222e1dc85SMatt Jacob 20365adb54cSMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP2100 20465adb54cSMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP2100 0x2100 20565adb54cSMatt Jacob #endif 20665adb54cSMatt Jacob 207222bb542SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP2200 208222bb542SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP2200 0x2200 209222bb542SMatt Jacob #endif 210222bb542SMatt Jacob 211126ec864SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP2300 212126ec864SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP2300 0x2300 213126ec864SMatt Jacob #endif 214126ec864SMatt Jacob 215126ec864SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP2312 216126ec864SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP2312 0x2312 217126ec864SMatt Jacob #endif 218126ec864SMatt Jacob 219e5265237SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP2322 220e5265237SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP2322 0x2322 221e5265237SMatt Jacob #endif 222e5265237SMatt Jacob 2238872e3d7SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP2422 2248872e3d7SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP2422 0x2422 2258872e3d7SMatt Jacob #endif 2268872e3d7SMatt Jacob 227dd1419abSMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP6312 228dd1419abSMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP6312 0x6312 229dd1419abSMatt Jacob #endif 230dd1419abSMatt Jacob 23156aef503SMatt Jacob #define PCI_QLOGIC_ISP1020 \ 23256aef503SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP1020 << 16) | PCI_VENDOR_QLOGIC) 233d59bd469SMatt Jacob 234d59bd469SMatt Jacob #define PCI_QLOGIC_ISP1080 \ 235d59bd469SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP1080 << 16) | PCI_VENDOR_QLOGIC) 236d59bd469SMatt Jacob 237f556e83bSMatt Jacob #define PCI_QLOGIC_ISP10160 \ 238f556e83bSMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP10160 << 16) | PCI_VENDOR_QLOGIC) 239f556e83bSMatt Jacob 240960f6939SMatt Jacob #define PCI_QLOGIC_ISP12160 \ 241960f6939SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP12160 << 16) | PCI_VENDOR_QLOGIC) 242960f6939SMatt Jacob 243d59bd469SMatt Jacob #define PCI_QLOGIC_ISP1240 \ 244d59bd469SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP1240 << 16) | PCI_VENDOR_QLOGIC) 245d59bd469SMatt Jacob 24622e1dc85SMatt Jacob #define PCI_QLOGIC_ISP1280 \ 24722e1dc85SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP1280 << 16) | PCI_VENDOR_QLOGIC) 24822e1dc85SMatt Jacob 24965adb54cSMatt Jacob #define PCI_QLOGIC_ISP2100 \ 25065adb54cSMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP2100 << 16) | PCI_VENDOR_QLOGIC) 25165adb54cSMatt Jacob 252222bb542SMatt Jacob #define PCI_QLOGIC_ISP2200 \ 253222bb542SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP2200 << 16) | PCI_VENDOR_QLOGIC) 254222bb542SMatt Jacob 255126ec864SMatt Jacob #define PCI_QLOGIC_ISP2300 \ 256126ec864SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP2300 << 16) | PCI_VENDOR_QLOGIC) 257126ec864SMatt Jacob 258126ec864SMatt Jacob #define PCI_QLOGIC_ISP2312 \ 259126ec864SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP2312 << 16) | PCI_VENDOR_QLOGIC) 260126ec864SMatt Jacob 261e5265237SMatt Jacob #define PCI_QLOGIC_ISP2322 \ 262e5265237SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP2322 << 16) | PCI_VENDOR_QLOGIC) 263e5265237SMatt Jacob 2646c426685SMatt Jacob #define PCI_QLOGIC_ISP2422 \ 2656c426685SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP2422 << 16) | PCI_VENDOR_QLOGIC) 2666c426685SMatt Jacob 267dd1419abSMatt Jacob #define PCI_QLOGIC_ISP6312 \ 268dd1419abSMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP6312 << 16) | PCI_VENDOR_QLOGIC) 269dd1419abSMatt Jacob 270e11a1ee8SMatt Jacob /* 271e11a1ee8SMatt Jacob * Odd case for some AMI raid cards... We need to *not* attach to this. 272e11a1ee8SMatt Jacob */ 273e11a1ee8SMatt Jacob #define AMI_RAID_SUBVENDOR_ID 0x101e 274e11a1ee8SMatt Jacob 27565adb54cSMatt Jacob #define IO_MAP_REG 0x10 27665adb54cSMatt Jacob #define MEM_MAP_REG 0x14 27765adb54cSMatt Jacob 278d951bbcaSMatt Jacob #define PCI_DFLT_LTNCY 0x40 279d951bbcaSMatt Jacob #define PCI_DFLT_LNSZ 0x10 28065adb54cSMatt Jacob 281960f6939SMatt Jacob static int isp_pci_probe (device_t); 282960f6939SMatt Jacob static int isp_pci_attach (device_t); 28365adb54cSMatt Jacob 2841923f739SMatt Jacob 28565adb54cSMatt Jacob struct isp_pcisoftc { 28665adb54cSMatt Jacob struct ispsoftc pci_isp; 287960f6939SMatt Jacob device_t pci_dev; 288960f6939SMatt Jacob struct resource * pci_reg; 28965adb54cSMatt Jacob bus_space_tag_t pci_st; 29065adb54cSMatt Jacob bus_space_handle_t pci_sh; 291960f6939SMatt Jacob void * ih; 292d59bd469SMatt Jacob int16_t pci_poff[_NREG_BLKS]; 2931923f739SMatt Jacob bus_dma_tag_t dmat; 294a95ae193SMatt Jacob bus_dmamap_t *dmaps; 29565adb54cSMatt Jacob }; 29673030e03SMatt Jacob extern ispfwfunc *isp_get_firmware_p; 29765adb54cSMatt Jacob 298960f6939SMatt Jacob static device_method_t isp_pci_methods[] = { 299960f6939SMatt Jacob /* Device interface */ 300960f6939SMatt Jacob DEVMETHOD(device_probe, isp_pci_probe), 301960f6939SMatt Jacob DEVMETHOD(device_attach, isp_pci_attach), 302960f6939SMatt Jacob { 0, 0 } 30365adb54cSMatt Jacob }; 304126ec864SMatt Jacob static void isp_pci_intr(void *); 30565adb54cSMatt Jacob 306960f6939SMatt Jacob static driver_t isp_pci_driver = { 307960f6939SMatt Jacob "isp", isp_pci_methods, sizeof (struct isp_pcisoftc) 308960f6939SMatt Jacob }; 309960f6939SMatt Jacob static devclass_t isp_devclass; 310960f6939SMatt Jacob DRIVER_MODULE(isp, pci, isp_pci_driver, isp_devclass, 0, 0); 31165adb54cSMatt Jacob 312960f6939SMatt Jacob static int 313960f6939SMatt Jacob isp_pci_probe(device_t dev) 31465adb54cSMatt Jacob { 315960f6939SMatt Jacob switch ((pci_get_device(dev) << 16) | (pci_get_vendor(dev))) { 31656aef503SMatt Jacob case PCI_QLOGIC_ISP1020: 317960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 1020/1040 PCI SCSI Adapter"); 31865adb54cSMatt Jacob break; 319d59bd469SMatt Jacob case PCI_QLOGIC_ISP1080: 320960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 1080 PCI SCSI Adapter"); 321c6608df3SMatt Jacob break; 322c6608df3SMatt Jacob case PCI_QLOGIC_ISP1240: 323960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 1240 PCI SCSI Adapter"); 324d59bd469SMatt Jacob break; 32522e1dc85SMatt Jacob case PCI_QLOGIC_ISP1280: 326960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 1280 PCI SCSI Adapter"); 327960f6939SMatt Jacob break; 328f556e83bSMatt Jacob case PCI_QLOGIC_ISP10160: 329f556e83bSMatt Jacob device_set_desc(dev, "Qlogic ISP 10160 PCI SCSI Adapter"); 330f556e83bSMatt Jacob break; 331960f6939SMatt Jacob case PCI_QLOGIC_ISP12160: 332e11a1ee8SMatt Jacob if (pci_get_subvendor(dev) == AMI_RAID_SUBVENDOR_ID) { 333e11a1ee8SMatt Jacob return (ENXIO); 334e11a1ee8SMatt Jacob } 335960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 12160 PCI SCSI Adapter"); 33622e1dc85SMatt Jacob break; 33765adb54cSMatt Jacob case PCI_QLOGIC_ISP2100: 338960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 2100 PCI FC-AL Adapter"); 33965adb54cSMatt Jacob break; 3405542fe4bSMatt Jacob case PCI_QLOGIC_ISP2200: 341960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 2200 PCI FC-AL Adapter"); 3425542fe4bSMatt Jacob break; 343126ec864SMatt Jacob case PCI_QLOGIC_ISP2300: 344126ec864SMatt Jacob device_set_desc(dev, "Qlogic ISP 2300 PCI FC-AL Adapter"); 345126ec864SMatt Jacob break; 346126ec864SMatt Jacob case PCI_QLOGIC_ISP2312: 347126ec864SMatt Jacob device_set_desc(dev, "Qlogic ISP 2312 PCI FC-AL Adapter"); 348126ec864SMatt Jacob break; 349e5265237SMatt Jacob case PCI_QLOGIC_ISP2322: 350e5265237SMatt Jacob device_set_desc(dev, "Qlogic ISP 2322 PCI FC-AL Adapter"); 351e5265237SMatt Jacob break; 3528872e3d7SMatt Jacob case PCI_QLOGIC_ISP2422: 3538872e3d7SMatt Jacob device_set_desc(dev, "Qlogic ISP 2422 PCI FC-AL Adapter"); 3548872e3d7SMatt Jacob break; 355dd1419abSMatt Jacob case PCI_QLOGIC_ISP6312: 356dd1419abSMatt Jacob device_set_desc(dev, "Qlogic ISP 6312 PCI FC-AL Adapter"); 357dd1419abSMatt Jacob break; 35865adb54cSMatt Jacob default: 359960f6939SMatt Jacob return (ENXIO); 36065adb54cSMatt Jacob } 36173030e03SMatt Jacob if (isp_announced == 0 && bootverbose) { 362d02373f1SMatt Jacob printf("Qlogic ISP Driver, FreeBSD Version %d.%d, " 363a95ae193SMatt Jacob "Core Version %d.%d\n", 364d720e6d5SJustin T. Gibbs ISP_PLATFORM_VERSION_MAJOR, ISP_PLATFORM_VERSION_MINOR, 365d720e6d5SJustin T. Gibbs ISP_CORE_VERSION_MAJOR, ISP_CORE_VERSION_MINOR); 36673030e03SMatt Jacob isp_announced++; 36765adb54cSMatt Jacob } 36856aef503SMatt Jacob /* 36956aef503SMatt Jacob * XXXX: Here is where we might load the f/w module 37056aef503SMatt Jacob * XXXX: (or increase a reference count to it). 37156aef503SMatt Jacob */ 372b77e575eSWarner Losh return (BUS_PROBE_DEFAULT); 37365adb54cSMatt Jacob } 37465adb54cSMatt Jacob 375960f6939SMatt Jacob static int 376960f6939SMatt Jacob isp_pci_attach(device_t dev) 37765adb54cSMatt Jacob { 378960f6939SMatt Jacob struct resource *regs, *irq; 3796e5c5328SMatt Jacob int tval, rtp, rgd, iqd, m1, m2, isp_debug, role; 3801dae40ebSMatt Jacob uint32_t data, cmd, linesz, psize, basetype; 38165adb54cSMatt Jacob struct isp_pcisoftc *pcs; 3823395b056SMatt Jacob struct ispsoftc *isp = NULL; 383c6608df3SMatt Jacob struct ispmdvec *mdvp; 38422941bd7SPeter Wemm const char *sptr; 3853395b056SMatt Jacob int locksetup = 0; 38665adb54cSMatt Jacob 387222bb542SMatt Jacob /* 3889ba86737SMatt Jacob * Figure out if we're supposed to skip this one. 3899ba86737SMatt Jacob */ 3906e5c5328SMatt Jacob 3916e5c5328SMatt Jacob tval = 0; 3926e5c5328SMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 3936e5c5328SMatt Jacob "disable", &tval) == 0 && tval) { 394b9b599feSMatt Jacob device_printf(dev, "device is disabled\n"); 395b9b599feSMatt Jacob /* but return 0 so the !$)$)*!$*) unit isn't reused */ 396b9b599feSMatt Jacob return (0); 397b9b599feSMatt Jacob } 3986e5c5328SMatt Jacob 39987ab7d39SMatt Jacob role = -1; 4006e5c5328SMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 40187ab7d39SMatt Jacob "role", &role) == 0 && role != -1) { 40287ab7d39SMatt Jacob role &= (ISP_ROLE_INITIATOR|ISP_ROLE_TARGET); 4036e5c5328SMatt Jacob device_printf(dev, "setting role to 0x%x\n", role); 4046e5c5328SMatt Jacob } else { 405b9b599feSMatt Jacob #ifdef ISP_TARGET_MODE 40687ab7d39SMatt Jacob role = ISP_ROLE_TARGET; 407b9b599feSMatt Jacob #else 408b9b599feSMatt Jacob role = ISP_DEFAULT_ROLES; 409b9b599feSMatt Jacob #endif 4109ba86737SMatt Jacob } 4119ba86737SMatt Jacob 4127cc0979fSDavid Malone pcs = malloc(sizeof (struct isp_pcisoftc), M_DEVBUF, M_NOWAIT | M_ZERO); 413960f6939SMatt Jacob if (pcs == NULL) { 414960f6939SMatt Jacob device_printf(dev, "cannot allocate softc\n"); 415960f6939SMatt Jacob return (ENOMEM); 416960f6939SMatt Jacob } 417960f6939SMatt Jacob 4189ba86737SMatt Jacob /* 41969767099SMatt Jacob * Which we should try first - memory mapping or i/o mapping? 42069767099SMatt Jacob * 42169767099SMatt Jacob * We used to try memory first followed by i/o on alpha, otherwise 42269767099SMatt Jacob * the reverse, but we should just try memory first all the time now. 423222bb542SMatt Jacob */ 424960f6939SMatt Jacob m1 = PCIM_CMD_MEMEN; 425960f6939SMatt Jacob m2 = PCIM_CMD_PORTEN; 4266e5c5328SMatt Jacob 4276e5c5328SMatt Jacob tval = 0; 4286e5c5328SMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 4296e5c5328SMatt Jacob "prefer_iomap", &tval) == 0 && tval != 0) { 430960f6939SMatt Jacob m1 = PCIM_CMD_PORTEN; 431960f6939SMatt Jacob m2 = PCIM_CMD_MEMEN; 432960f6939SMatt Jacob } 4336e5c5328SMatt Jacob tval = 0; 4346e5c5328SMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 4356e5c5328SMatt Jacob "prefer_memmap", &tval) == 0 && tval != 0) { 4366e5c5328SMatt Jacob m1 = PCIM_CMD_MEMEN; 4376e5c5328SMatt Jacob m2 = PCIM_CMD_PORTEN; 438222bb542SMatt Jacob } 439222bb542SMatt Jacob 440ab6d0040SMatt Jacob linesz = PCI_DFLT_LNSZ; 441960f6939SMatt Jacob irq = regs = NULL; 442960f6939SMatt Jacob rgd = rtp = iqd = 0; 443960f6939SMatt Jacob 444b49c4674SMatt Jacob cmd = pci_read_config(dev, PCIR_COMMAND, 2); 445960f6939SMatt Jacob if (cmd & m1) { 446960f6939SMatt Jacob rtp = (m1 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT; 447960f6939SMatt Jacob rgd = (m1 == PCIM_CMD_MEMEN)? MEM_MAP_REG : IO_MAP_REG; 4485f96beb9SNate Lawson regs = bus_alloc_resource_any(dev, rtp, &rgd, RF_ACTIVE); 44965adb54cSMatt Jacob } 450960f6939SMatt Jacob if (regs == NULL && (cmd & m2)) { 451960f6939SMatt Jacob rtp = (m2 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT; 452960f6939SMatt Jacob rgd = (m2 == PCIM_CMD_MEMEN)? MEM_MAP_REG : IO_MAP_REG; 4535f96beb9SNate Lawson regs = bus_alloc_resource_any(dev, rtp, &rgd, RF_ACTIVE); 45465adb54cSMatt Jacob } 455960f6939SMatt Jacob if (regs == NULL) { 456960f6939SMatt Jacob device_printf(dev, "unable to map any ports\n"); 457960f6939SMatt Jacob goto bad; 45865adb54cSMatt Jacob } 459222bb542SMatt Jacob if (bootverbose) 460f7dddf8aSMatt Jacob device_printf(dev, "using %s space register mapping\n", 461960f6939SMatt Jacob (rgd == IO_MAP_REG)? "I/O" : "Memory"); 462960f6939SMatt Jacob pcs->pci_dev = dev; 463960f6939SMatt Jacob pcs->pci_reg = regs; 464960f6939SMatt Jacob pcs->pci_st = rman_get_bustag(regs); 465960f6939SMatt Jacob pcs->pci_sh = rman_get_bushandle(regs); 46665adb54cSMatt Jacob 467d59bd469SMatt Jacob pcs->pci_poff[BIU_BLOCK >> _BLK_REG_SHFT] = BIU_REGS_OFF; 468d59bd469SMatt Jacob pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS_OFF; 469d59bd469SMatt Jacob pcs->pci_poff[SXP_BLOCK >> _BLK_REG_SHFT] = PCI_SXP_REGS_OFF; 470d59bd469SMatt Jacob pcs->pci_poff[RISC_BLOCK >> _BLK_REG_SHFT] = PCI_RISC_REGS_OFF; 471d59bd469SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = DMA_REGS_OFF; 472c6608df3SMatt Jacob mdvp = &mdvec; 473c6608df3SMatt Jacob basetype = ISP_HA_SCSI_UNKNOWN; 474c6608df3SMatt Jacob psize = sizeof (sdparam); 47556aef503SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP1020) { 476c6608df3SMatt Jacob mdvp = &mdvec; 477c6608df3SMatt Jacob basetype = ISP_HA_SCSI_UNKNOWN; 478c6608df3SMatt Jacob psize = sizeof (sdparam); 479d59bd469SMatt Jacob } 480960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP1080) { 481c6608df3SMatt Jacob mdvp = &mdvec_1080; 482c6608df3SMatt Jacob basetype = ISP_HA_SCSI_1080; 483c6608df3SMatt Jacob psize = sizeof (sdparam); 484c6608df3SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 485c6608df3SMatt Jacob ISP1080_DMA_REGS_OFF; 486c6608df3SMatt Jacob } 487960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP1240) { 488c6608df3SMatt Jacob mdvp = &mdvec_1080; 48922e1dc85SMatt Jacob basetype = ISP_HA_SCSI_1240; 49022e1dc85SMatt Jacob psize = 2 * sizeof (sdparam); 49122e1dc85SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 49222e1dc85SMatt Jacob ISP1080_DMA_REGS_OFF; 49322e1dc85SMatt Jacob } 494960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP1280) { 49522e1dc85SMatt Jacob mdvp = &mdvec_1080; 49622e1dc85SMatt Jacob basetype = ISP_HA_SCSI_1280; 497c6608df3SMatt Jacob psize = 2 * sizeof (sdparam); 498d59bd469SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 499d59bd469SMatt Jacob ISP1080_DMA_REGS_OFF; 500d59bd469SMatt Jacob } 501f556e83bSMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP10160) { 502f556e83bSMatt Jacob mdvp = &mdvec_12160; 503f556e83bSMatt Jacob basetype = ISP_HA_SCSI_10160; 504f556e83bSMatt Jacob psize = sizeof (sdparam); 505f556e83bSMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 506f556e83bSMatt Jacob ISP1080_DMA_REGS_OFF; 507f556e83bSMatt Jacob } 508960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP12160) { 509960f6939SMatt Jacob mdvp = &mdvec_12160; 510960f6939SMatt Jacob basetype = ISP_HA_SCSI_12160; 511960f6939SMatt Jacob psize = 2 * sizeof (sdparam); 512960f6939SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 513960f6939SMatt Jacob ISP1080_DMA_REGS_OFF; 514960f6939SMatt Jacob } 515960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP2100) { 516c6608df3SMatt Jacob mdvp = &mdvec_2100; 517c6608df3SMatt Jacob basetype = ISP_HA_FC_2100; 518c6608df3SMatt Jacob psize = sizeof (fcparam); 519d59bd469SMatt Jacob pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = 520d59bd469SMatt Jacob PCI_MBOX_REGS2100_OFF; 521960f6939SMatt Jacob if (pci_get_revid(dev) < 3) { 522ab6d0040SMatt Jacob /* 523ab6d0040SMatt Jacob * XXX: Need to get the actual revision 524ab6d0040SMatt Jacob * XXX: number of the 2100 FB. At any rate, 525ab6d0040SMatt Jacob * XXX: lower cache line size for early revision 526ab6d0040SMatt Jacob * XXX; boards. 527ab6d0040SMatt Jacob */ 528ab6d0040SMatt Jacob linesz = 1; 529ab6d0040SMatt Jacob } 53065adb54cSMatt Jacob } 531960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP2200) { 532222bb542SMatt Jacob mdvp = &mdvec_2200; 533222bb542SMatt Jacob basetype = ISP_HA_FC_2200; 534222bb542SMatt Jacob psize = sizeof (fcparam); 535222bb542SMatt Jacob pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = 536222bb542SMatt Jacob PCI_MBOX_REGS2100_OFF; 537222bb542SMatt Jacob } 53875c1e828SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP2300) { 539126ec864SMatt Jacob mdvp = &mdvec_2300; 540126ec864SMatt Jacob basetype = ISP_HA_FC_2300; 541126ec864SMatt Jacob psize = sizeof (fcparam); 542126ec864SMatt Jacob pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = 543126ec864SMatt Jacob PCI_MBOX_REGS2300_OFF; 544126ec864SMatt Jacob } 545dd1419abSMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP2312 || 546dd1419abSMatt Jacob pci_get_devid(dev) == PCI_QLOGIC_ISP6312) { 54775c1e828SMatt Jacob mdvp = &mdvec_2300; 54875c1e828SMatt Jacob basetype = ISP_HA_FC_2312; 54975c1e828SMatt Jacob psize = sizeof (fcparam); 55075c1e828SMatt Jacob pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = 55175c1e828SMatt Jacob PCI_MBOX_REGS2300_OFF; 55275c1e828SMatt Jacob } 553e5265237SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP2322) { 554e5265237SMatt Jacob mdvp = &mdvec_2300; 555e5265237SMatt Jacob basetype = ISP_HA_FC_2322; 556e5265237SMatt Jacob psize = sizeof (fcparam); 557e5265237SMatt Jacob pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = 558e5265237SMatt Jacob PCI_MBOX_REGS2300_OFF; 559e5265237SMatt Jacob } 5608872e3d7SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP2422) { 5618872e3d7SMatt Jacob mdvp = &mdvec_2300; 5628872e3d7SMatt Jacob basetype = ISP_HA_FC_2422; 5638872e3d7SMatt Jacob psize = sizeof (fcparam); 5648872e3d7SMatt Jacob pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = 5658872e3d7SMatt Jacob PCI_MBOX_REGS2300_OFF; 5668872e3d7SMatt Jacob } 567c6608df3SMatt Jacob isp = &pcs->pci_isp; 5687cc0979fSDavid Malone isp->isp_param = malloc(psize, M_DEVBUF, M_NOWAIT | M_ZERO); 569c6608df3SMatt Jacob if (isp->isp_param == NULL) { 570960f6939SMatt Jacob device_printf(dev, "cannot allocate parameter data\n"); 571960f6939SMatt Jacob goto bad; 572c6608df3SMatt Jacob } 573c6608df3SMatt Jacob isp->isp_mdvec = mdvp; 574c6608df3SMatt Jacob isp->isp_type = basetype; 575960f6939SMatt Jacob isp->isp_revision = pci_get_revid(dev); 576b9b599feSMatt Jacob isp->isp_role = role; 5776e5c5328SMatt Jacob isp->isp_dev = dev; 57865adb54cSMatt Jacob 57956aef503SMatt Jacob /* 58056aef503SMatt Jacob * Try and find firmware for this device. 58156aef503SMatt Jacob */ 58256aef503SMatt Jacob 583e5265237SMatt Jacob /* 584e5265237SMatt Jacob * Don't even attempt to get firmware for the 2322/2422 (yet) 585e5265237SMatt Jacob */ 586e5265237SMatt Jacob if (IS_2322(isp) == 0 && IS_24XX(isp) == 0 && isp_get_firmware_p) { 58756aef503SMatt Jacob int device = (int) pci_get_device(dev); 58856aef503SMatt Jacob #ifdef ISP_TARGET_MODE 58956aef503SMatt Jacob (*isp_get_firmware_p)(0, 1, device, &mdvp->dv_ispfw); 59056aef503SMatt Jacob #else 59156aef503SMatt Jacob (*isp_get_firmware_p)(0, 0, device, &mdvp->dv_ispfw); 59256aef503SMatt Jacob #endif 59356aef503SMatt Jacob } 59456aef503SMatt Jacob 59556aef503SMatt Jacob /* 596d951bbcaSMatt Jacob * Make sure that SERR, PERR, WRITE INVALIDATE and BUSMASTER 597d951bbcaSMatt Jacob * are set. 598d951bbcaSMatt Jacob */ 599960f6939SMatt Jacob cmd |= PCIM_CMD_SEREN | PCIM_CMD_PERRESPEN | 600960f6939SMatt Jacob PCIM_CMD_BUSMASTEREN | PCIM_CMD_INVEN; 60175c1e828SMatt Jacob if (IS_2300(isp)) { /* per QLogic errata */ 60275c1e828SMatt Jacob cmd &= ~PCIM_CMD_INVEN; 60375c1e828SMatt Jacob } 604fc087171SMatt Jacob if (IS_23XX(isp)) { 605fc087171SMatt Jacob /* 606fc087171SMatt Jacob * Can't tell if ROM will hang on 'ABOUT FIRMWARE' command. 607fc087171SMatt Jacob */ 608fc087171SMatt Jacob isp->isp_touched = 1; 609fc087171SMatt Jacob 610fc087171SMatt Jacob } 611b49c4674SMatt Jacob pci_write_config(dev, PCIR_COMMAND, cmd, 2); 612ab6d0040SMatt Jacob 613d951bbcaSMatt Jacob /* 614222bb542SMatt Jacob * Make sure the Cache Line Size register is set sensibly. 615d951bbcaSMatt Jacob */ 616960f6939SMatt Jacob data = pci_read_config(dev, PCIR_CACHELNSZ, 1); 617ab6d0040SMatt Jacob if (data != linesz) { 618d951bbcaSMatt Jacob data = PCI_DFLT_LNSZ; 619d02373f1SMatt Jacob isp_prt(isp, ISP_LOGCONFIG, "set PCI line size to %d", data); 620960f6939SMatt Jacob pci_write_config(dev, PCIR_CACHELNSZ, data, 1); 621d951bbcaSMatt Jacob } 622ab6d0040SMatt Jacob 623d951bbcaSMatt Jacob /* 624d951bbcaSMatt Jacob * Make sure the Latency Timer is sane. 625d951bbcaSMatt Jacob */ 626960f6939SMatt Jacob data = pci_read_config(dev, PCIR_LATTIMER, 1); 627d951bbcaSMatt Jacob if (data < PCI_DFLT_LTNCY) { 628d951bbcaSMatt Jacob data = PCI_DFLT_LTNCY; 629d02373f1SMatt Jacob isp_prt(isp, ISP_LOGCONFIG, "set PCI latency to %d", data); 630960f6939SMatt Jacob pci_write_config(dev, PCIR_LATTIMER, data, 1); 631d951bbcaSMatt Jacob } 632ab6d0040SMatt Jacob 633ab6d0040SMatt Jacob /* 634ab6d0040SMatt Jacob * Make sure we've disabled the ROM. 635ab6d0040SMatt Jacob */ 636960f6939SMatt Jacob data = pci_read_config(dev, PCIR_ROMADDR, 4); 637ab6d0040SMatt Jacob data &= ~1; 638960f6939SMatt Jacob pci_write_config(dev, PCIR_ROMADDR, data, 4); 63905fbcbb0SMatt Jacob 640960f6939SMatt Jacob iqd = 0; 6415f96beb9SNate Lawson irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &iqd, 6425f96beb9SNate Lawson RF_ACTIVE | RF_SHAREABLE); 643960f6939SMatt Jacob if (irq == NULL) { 644960f6939SMatt Jacob device_printf(dev, "could not allocate interrupt\n"); 645960f6939SMatt Jacob goto bad; 646960f6939SMatt Jacob } 647960f6939SMatt Jacob 6486e5c5328SMatt Jacob tval = 0; 6496e5c5328SMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 6506e5c5328SMatt Jacob "fwload_disable", &tval) == 0 && tval != 0) { 651222bb542SMatt Jacob isp->isp_confopts |= ISP_CFG_NORELOAD; 652222bb542SMatt Jacob } 6536e5c5328SMatt Jacob tval = 0; 6546e5c5328SMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 6556e5c5328SMatt Jacob "ignore_nvram", &tval) == 0 && tval != 0) { 656222bb542SMatt Jacob isp->isp_confopts |= ISP_CFG_NONVRAM; 657222bb542SMatt Jacob } 6586e5c5328SMatt Jacob tval = 0; 6596e5c5328SMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 6606e5c5328SMatt Jacob "fullduplex", &tval) == 0 && tval != 0) { 661222bb542SMatt Jacob isp->isp_confopts |= ISP_CFG_FULL_DUPLEX; 662222bb542SMatt Jacob } 663d134aa0bSMatt Jacob #ifdef ISP_FW_CRASH_DUMP 664d134aa0bSMatt Jacob tval = 0; 665d134aa0bSMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 666d134aa0bSMatt Jacob "fw_dump_enable", &tval) == 0 && tval != 0) { 667d134aa0bSMatt Jacob size_t amt = 0; 668d134aa0bSMatt Jacob if (IS_2200(isp)) { 669d134aa0bSMatt Jacob amt = QLA2200_RISC_IMAGE_DUMP_SIZE; 670d134aa0bSMatt Jacob } else if (IS_23XX(isp)) { 671d134aa0bSMatt Jacob amt = QLA2300_RISC_IMAGE_DUMP_SIZE; 672d134aa0bSMatt Jacob } 673d134aa0bSMatt Jacob if (amt) { 674d134aa0bSMatt Jacob FCPARAM(isp)->isp_dump_data = 675a163d034SWarner Losh malloc(amt, M_DEVBUF, M_WAITOK | M_ZERO); 676d134aa0bSMatt Jacob } else { 677d134aa0bSMatt Jacob device_printf(dev, 678d134aa0bSMatt Jacob "f/w crash dumps not supported for this model\n"); 679d134aa0bSMatt Jacob } 680d134aa0bSMatt Jacob } 681d134aa0bSMatt Jacob #endif 682222bb542SMatt Jacob 6836e5c5328SMatt Jacob sptr = 0; 6846e5c5328SMatt Jacob if (resource_string_value(device_get_name(dev), device_get_unit(dev), 685559a1ad2SMatt Jacob "topology", (const char **) &sptr) == 0 && sptr != 0) { 6866e5c5328SMatt Jacob if (strcmp(sptr, "lport") == 0) { 6876e5c5328SMatt Jacob isp->isp_confopts |= ISP_CFG_LPORT; 6886e5c5328SMatt Jacob } else if (strcmp(sptr, "nport") == 0) { 6896e5c5328SMatt Jacob isp->isp_confopts |= ISP_CFG_NPORT; 6906e5c5328SMatt Jacob } else if (strcmp(sptr, "lport-only") == 0) { 6916e5c5328SMatt Jacob isp->isp_confopts |= ISP_CFG_LPORT_ONLY; 6926e5c5328SMatt Jacob } else if (strcmp(sptr, "nport-only") == 0) { 6936e5c5328SMatt Jacob isp->isp_confopts |= ISP_CFG_NPORT_ONLY; 6949637d68cSMatt Jacob } 6956e5c5328SMatt Jacob } 6966e5c5328SMatt Jacob 6979637d68cSMatt Jacob /* 6986e5c5328SMatt Jacob * Because the resource_*_value functions can neither return 6996e5c5328SMatt Jacob * 64 bit integer values, nor can they be directly coerced 7006e5c5328SMatt Jacob * to interpret the right hand side of the assignment as 7016e5c5328SMatt Jacob * you want them to interpret it, we have to force WWN 7026e5c5328SMatt Jacob * hint replacement to specify WWN strings with a leading 7036e5c5328SMatt Jacob * 'w' (e..g w50000000aaaa0001). Sigh. 7049637d68cSMatt Jacob */ 7056e5c5328SMatt Jacob sptr = 0; 7066e5c5328SMatt Jacob tval = resource_string_value(device_get_name(dev), device_get_unit(dev), 707559a1ad2SMatt Jacob "portwwn", (const char **) &sptr); 7086e5c5328SMatt Jacob if (tval == 0 && sptr != 0 && *sptr++ == 'w') { 7096e5c5328SMatt Jacob char *eptr = 0; 7106e5c5328SMatt Jacob isp->isp_osinfo.default_port_wwn = strtouq(sptr, &eptr, 16); 7116e5c5328SMatt Jacob if (eptr < sptr + 16 || isp->isp_osinfo.default_port_wwn == 0) { 7126e5c5328SMatt Jacob device_printf(dev, "mangled portwwn hint '%s'\n", sptr); 7136e5c5328SMatt Jacob isp->isp_osinfo.default_port_wwn = 0; 7149637d68cSMatt Jacob } else { 7153f02619fSMatt Jacob isp->isp_confopts |= ISP_CFG_OWNWWPN; 716222bb542SMatt Jacob } 7176e5c5328SMatt Jacob } 7186e5c5328SMatt Jacob if (isp->isp_osinfo.default_port_wwn == 0) { 7196e5c5328SMatt Jacob isp->isp_osinfo.default_port_wwn = 0x400000007F000009ull; 7206e5c5328SMatt Jacob } 7216e5c5328SMatt Jacob 7226e5c5328SMatt Jacob sptr = 0; 7236e5c5328SMatt Jacob tval = resource_string_value(device_get_name(dev), device_get_unit(dev), 724559a1ad2SMatt Jacob "nodewwn", (const char **) &sptr); 7256e5c5328SMatt Jacob if (tval == 0 && sptr != 0 && *sptr++ == 'w') { 7266e5c5328SMatt Jacob char *eptr = 0; 7276e5c5328SMatt Jacob isp->isp_osinfo.default_node_wwn = strtouq(sptr, &eptr, 16); 7286e5c5328SMatt Jacob if (eptr < sptr + 16 || isp->isp_osinfo.default_node_wwn == 0) { 7296e5c5328SMatt Jacob device_printf(dev, "mangled nodewwn hint '%s'\n", sptr); 7306e5c5328SMatt Jacob isp->isp_osinfo.default_node_wwn = 0; 7316e5c5328SMatt Jacob } else { 7323f02619fSMatt Jacob isp->isp_confopts |= ISP_CFG_OWNWWNN; 7336e5c5328SMatt Jacob } 7346e5c5328SMatt Jacob } 7356e5c5328SMatt Jacob if (isp->isp_osinfo.default_node_wwn == 0) { 7366e5c5328SMatt Jacob isp->isp_osinfo.default_node_wwn = 0x400000007F000009ull; 7376e5c5328SMatt Jacob } 7386e5c5328SMatt Jacob 73943722a42SMatt Jacob isp->isp_osinfo.default_id = -1; 740ed753e82SMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 741ed753e82SMatt Jacob "iid", &tval) == 0) { 742ed753e82SMatt Jacob isp->isp_osinfo.default_id = tval; 743ed753e82SMatt Jacob isp->isp_confopts |= ISP_CFG_OWNLOOPID; 744ed753e82SMatt Jacob } 74543722a42SMatt Jacob if (isp->isp_osinfo.default_id == -1) { 746ed753e82SMatt Jacob if (IS_FC(isp)) { 747ed753e82SMatt Jacob isp->isp_osinfo.default_id = 109; 748ed753e82SMatt Jacob } else { 749ed753e82SMatt Jacob isp->isp_osinfo.default_id = 7; 750ed753e82SMatt Jacob } 751ed753e82SMatt Jacob } 752ed753e82SMatt Jacob 753ed753e82SMatt Jacob isp_debug = 0; 7546e5c5328SMatt Jacob (void) resource_int_value(device_get_name(dev), device_get_unit(dev), 7556e5c5328SMatt Jacob "debug", &isp_debug); 756f09b1922SMatt Jacob 757f09b1922SMatt Jacob /* Make sure the lock is set up. */ 7586008862bSJohn Baldwin mtx_init(&isp->isp_osinfo.lock, "isp", NULL, MTX_DEF); 759f09b1922SMatt Jacob locksetup++; 760f09b1922SMatt Jacob 76172429e49SMatt Jacob if (bus_setup_intr(dev, irq, ISP_IFLAGS, isp_pci_intr, isp, &pcs->ih)) { 762f09b1922SMatt Jacob device_printf(dev, "could not setup interrupt\n"); 763f09b1922SMatt Jacob goto bad; 764f09b1922SMatt Jacob } 765960f6939SMatt Jacob 76605fbcbb0SMatt Jacob /* 767d02373f1SMatt Jacob * Set up logging levels. 768d02373f1SMatt Jacob */ 769d02373f1SMatt Jacob if (isp_debug) { 770d02373f1SMatt Jacob isp->isp_dblev = isp_debug; 771d02373f1SMatt Jacob } else { 772d02373f1SMatt Jacob isp->isp_dblev = ISP_LOGWARN|ISP_LOGERR; 773d02373f1SMatt Jacob } 774d02373f1SMatt Jacob if (bootverbose) 775f7dddf8aSMatt Jacob isp->isp_dblev |= ISP_LOGCONFIG|ISP_LOGINFO; 776d02373f1SMatt Jacob 777d02373f1SMatt Jacob /* 77875c1e828SMatt Jacob * Last minute checks... 77975c1e828SMatt Jacob */ 780e5265237SMatt Jacob if (IS_23XX(isp)) { 78175c1e828SMatt Jacob isp->isp_port = pci_get_function(dev); 78275c1e828SMatt Jacob } 78375c1e828SMatt Jacob 78475c1e828SMatt Jacob /* 78505fbcbb0SMatt Jacob * Make sure we're in reset state. 78605fbcbb0SMatt Jacob */ 7873395b056SMatt Jacob ISP_LOCK(isp); 78865adb54cSMatt Jacob isp_reset(isp); 78965adb54cSMatt Jacob if (isp->isp_state != ISP_RESETSTATE) { 7903395b056SMatt Jacob ISP_UNLOCK(isp); 791960f6939SMatt Jacob goto bad; 79265adb54cSMatt Jacob } 79365adb54cSMatt Jacob isp_init(isp); 794b9b599feSMatt Jacob if (isp->isp_role != ISP_ROLE_NONE && isp->isp_state != ISP_INITSTATE) { 79565adb54cSMatt Jacob isp_uninit(isp); 7963395b056SMatt Jacob ISP_UNLOCK(isp); 797960f6939SMatt Jacob goto bad; 798d59bd469SMatt Jacob } 79965adb54cSMatt Jacob isp_attach(isp); 800b9b599feSMatt Jacob if (isp->isp_role != ISP_ROLE_NONE && isp->isp_state != ISP_RUNSTATE) { 80165adb54cSMatt Jacob isp_uninit(isp); 8023395b056SMatt Jacob ISP_UNLOCK(isp); 803960f6939SMatt Jacob goto bad; 804960f6939SMatt Jacob } 80556aef503SMatt Jacob /* 80656aef503SMatt Jacob * XXXX: Here is where we might unload the f/w module 80756aef503SMatt Jacob * XXXX: (or decrease the reference count to it). 80856aef503SMatt Jacob */ 8093395b056SMatt Jacob ISP_UNLOCK(isp); 810960f6939SMatt Jacob return (0); 811960f6939SMatt Jacob 812960f6939SMatt Jacob bad: 813960f6939SMatt Jacob 814960f6939SMatt Jacob if (pcs && pcs->ih) { 815960f6939SMatt Jacob (void) bus_teardown_intr(dev, irq, pcs->ih); 816960f6939SMatt Jacob } 817960f6939SMatt Jacob 8183395b056SMatt Jacob if (locksetup && isp) { 8193395b056SMatt Jacob mtx_destroy(&isp->isp_osinfo.lock); 8203395b056SMatt Jacob } 8213395b056SMatt Jacob 822960f6939SMatt Jacob if (irq) { 823960f6939SMatt Jacob (void) bus_release_resource(dev, SYS_RES_IRQ, iqd, irq); 824960f6939SMatt Jacob } 8253395b056SMatt Jacob 8263395b056SMatt Jacob 827960f6939SMatt Jacob if (regs) { 828960f6939SMatt Jacob (void) bus_release_resource(dev, rtp, rgd, regs); 829960f6939SMatt Jacob } 8303395b056SMatt Jacob 831960f6939SMatt Jacob if (pcs) { 832960f6939SMatt Jacob if (pcs->pci_isp.isp_param) 833960f6939SMatt Jacob free(pcs->pci_isp.isp_param, M_DEVBUF); 83465adb54cSMatt Jacob free(pcs, M_DEVBUF); 83565adb54cSMatt Jacob } 8363395b056SMatt Jacob 83756aef503SMatt Jacob /* 83856aef503SMatt Jacob * XXXX: Here is where we might unload the f/w module 83956aef503SMatt Jacob * XXXX: (or decrease the reference count to it). 84056aef503SMatt Jacob */ 841960f6939SMatt Jacob return (ENXIO); 84265adb54cSMatt Jacob } 84365adb54cSMatt Jacob 844f09b1922SMatt Jacob static void 845f09b1922SMatt Jacob isp_pci_intr(void *arg) 846f09b1922SMatt Jacob { 847f09b1922SMatt Jacob struct ispsoftc *isp = arg; 8481dae40ebSMatt Jacob uint16_t isr, sema, mbox; 849126ec864SMatt Jacob 850f09b1922SMatt Jacob ISP_LOCK(isp); 851126ec864SMatt Jacob isp->isp_intcnt++; 852126ec864SMatt Jacob if (ISP_READ_ISR(isp, &isr, &sema, &mbox) == 0) { 853126ec864SMatt Jacob isp->isp_intbogus++; 854126ec864SMatt Jacob } else { 855b96934e8SMatt Jacob int iok = isp->isp_osinfo.intsok; 856b96934e8SMatt Jacob isp->isp_osinfo.intsok = 0; 857126ec864SMatt Jacob isp_intr(isp, isr, sema, mbox); 858b96934e8SMatt Jacob isp->isp_osinfo.intsok = iok; 859126ec864SMatt Jacob } 860f09b1922SMatt Jacob ISP_UNLOCK(isp); 861f09b1922SMatt Jacob } 862f09b1922SMatt Jacob 863126ec864SMatt Jacob 864126ec864SMatt Jacob #define IspVirt2Off(a, x) \ 865126ec864SMatt Jacob (((struct isp_pcisoftc *)a)->pci_poff[((x) & _BLK_REG_MASK) >> \ 866126ec864SMatt Jacob _BLK_REG_SHFT] + ((x) & 0xff)) 867126ec864SMatt Jacob 868126ec864SMatt Jacob #define BXR2(pcs, off) \ 869126ec864SMatt Jacob bus_space_read_2(pcs->pci_st, pcs->pci_sh, off) 870126ec864SMatt Jacob #define BXW2(pcs, off, v) \ 871126ec864SMatt Jacob bus_space_write_2(pcs->pci_st, pcs->pci_sh, off, v) 872126ec864SMatt Jacob 873126ec864SMatt Jacob 87453af7d22SMatt Jacob static __inline int 8751dae40ebSMatt Jacob isp_pci_rd_debounced(struct ispsoftc *isp, int off, uint16_t *rp) 876126ec864SMatt Jacob { 877126ec864SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 8781dae40ebSMatt Jacob uint16_t val0, val1; 879126ec864SMatt Jacob int i = 0; 880126ec864SMatt Jacob 881126ec864SMatt Jacob do { 882126ec864SMatt Jacob val0 = BXR2(pcs, IspVirt2Off(isp, off)); 883126ec864SMatt Jacob val1 = BXR2(pcs, IspVirt2Off(isp, off)); 884126ec864SMatt Jacob } while (val0 != val1 && ++i < 1000); 885126ec864SMatt Jacob if (val0 != val1) { 886126ec864SMatt Jacob return (1); 887126ec864SMatt Jacob } 888126ec864SMatt Jacob *rp = val0; 889126ec864SMatt Jacob return (0); 890126ec864SMatt Jacob } 891126ec864SMatt Jacob 892126ec864SMatt Jacob static int 8931dae40ebSMatt Jacob isp_pci_rd_isr(struct ispsoftc *isp, uint16_t *isrp, 8941dae40ebSMatt Jacob uint16_t *semap, uint16_t *mbp) 895126ec864SMatt Jacob { 896126ec864SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 8971dae40ebSMatt Jacob uint16_t isr, sema; 898126ec864SMatt Jacob 899126ec864SMatt Jacob if (IS_2100(isp)) { 900126ec864SMatt Jacob if (isp_pci_rd_debounced(isp, BIU_ISR, &isr)) { 901126ec864SMatt Jacob return (0); 902126ec864SMatt Jacob } 903126ec864SMatt Jacob if (isp_pci_rd_debounced(isp, BIU_SEMA, &sema)) { 904126ec864SMatt Jacob return (0); 905126ec864SMatt Jacob } 906126ec864SMatt Jacob } else { 907126ec864SMatt Jacob isr = BXR2(pcs, IspVirt2Off(isp, BIU_ISR)); 908126ec864SMatt Jacob sema = BXR2(pcs, IspVirt2Off(isp, BIU_SEMA)); 909126ec864SMatt Jacob } 910126ec864SMatt Jacob isp_prt(isp, ISP_LOGDEBUG3, "ISR 0x%x SEMA 0x%x", isr, sema); 911126ec864SMatt Jacob isr &= INT_PENDING_MASK(isp); 912126ec864SMatt Jacob sema &= BIU_SEMA_LOCK; 913126ec864SMatt Jacob if (isr == 0 && sema == 0) { 914126ec864SMatt Jacob return (0); 915126ec864SMatt Jacob } 916126ec864SMatt Jacob *isrp = isr; 917126ec864SMatt Jacob if ((*semap = sema) != 0) { 918126ec864SMatt Jacob if (IS_2100(isp)) { 919126ec864SMatt Jacob if (isp_pci_rd_debounced(isp, OUTMAILBOX0, mbp)) { 920126ec864SMatt Jacob return (0); 921126ec864SMatt Jacob } 922126ec864SMatt Jacob } else { 923126ec864SMatt Jacob *mbp = BXR2(pcs, IspVirt2Off(isp, OUTMAILBOX0)); 924126ec864SMatt Jacob } 925126ec864SMatt Jacob } 926126ec864SMatt Jacob return (1); 927126ec864SMatt Jacob } 928126ec864SMatt Jacob 929126ec864SMatt Jacob static int 9301dae40ebSMatt Jacob isp_pci_rd_isr_2300(struct ispsoftc *isp, uint16_t *isrp, 9311dae40ebSMatt Jacob uint16_t *semap, uint16_t *mbox0p) 932126ec864SMatt Jacob { 933126ec864SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 9341dae40ebSMatt Jacob uint32_t r2hisr; 935126ec864SMatt Jacob 9363bd40330SMatt Jacob if (!(BXR2(pcs, IspVirt2Off(isp, BIU_ISR) & BIU2100_ISR_RISC_INT))) { 9373bd40330SMatt Jacob *isrp = 0; 938db4fa023SMatt Jacob return (0); 9393bd40330SMatt Jacob } 940126ec864SMatt Jacob r2hisr = bus_space_read_4(pcs->pci_st, pcs->pci_sh, 941126ec864SMatt Jacob IspVirt2Off(pcs, BIU_R2HSTSLO)); 942126ec864SMatt Jacob isp_prt(isp, ISP_LOGDEBUG3, "RISC2HOST ISR 0x%x", r2hisr); 943126ec864SMatt Jacob if ((r2hisr & BIU_R2HST_INTR) == 0) { 944126ec864SMatt Jacob *isrp = 0; 945126ec864SMatt Jacob return (0); 946126ec864SMatt Jacob } 947126ec864SMatt Jacob switch (r2hisr & BIU_R2HST_ISTAT_MASK) { 948126ec864SMatt Jacob case ISPR2HST_ROM_MBX_OK: 949126ec864SMatt Jacob case ISPR2HST_ROM_MBX_FAIL: 950126ec864SMatt Jacob case ISPR2HST_MBX_OK: 951126ec864SMatt Jacob case ISPR2HST_MBX_FAIL: 952126ec864SMatt Jacob case ISPR2HST_ASYNC_EVENT: 953126ec864SMatt Jacob *isrp = r2hisr & 0xffff; 954126ec864SMatt Jacob *mbox0p = (r2hisr >> 16); 955126ec864SMatt Jacob *semap = 1; 956126ec864SMatt Jacob return (1); 957fc3bbaaaSMatt Jacob case ISPR2HST_RIO_16: 958fc3bbaaaSMatt Jacob *isrp = r2hisr & 0xffff; 959fc3bbaaaSMatt Jacob *mbox0p = ASYNC_RIO1; 960fc3bbaaaSMatt Jacob *semap = 1; 961fc3bbaaaSMatt Jacob return (1); 962fc3bbaaaSMatt Jacob case ISPR2HST_FPOST: 963fc3bbaaaSMatt Jacob *isrp = r2hisr & 0xffff; 964fc3bbaaaSMatt Jacob *mbox0p = ASYNC_CMD_CMPLT; 965fc3bbaaaSMatt Jacob *semap = 1; 966fc3bbaaaSMatt Jacob return (1); 967fc3bbaaaSMatt Jacob case ISPR2HST_FPOST_CTIO: 968fc3bbaaaSMatt Jacob *isrp = r2hisr & 0xffff; 969fc3bbaaaSMatt Jacob *mbox0p = ASYNC_CTIO_DONE; 970fc3bbaaaSMatt Jacob *semap = 1; 971fc3bbaaaSMatt Jacob return (1); 972126ec864SMatt Jacob case ISPR2HST_RSPQ_UPDATE: 973126ec864SMatt Jacob *isrp = r2hisr & 0xffff; 974126ec864SMatt Jacob *mbox0p = 0; 975126ec864SMatt Jacob *semap = 0; 976126ec864SMatt Jacob return (1); 977126ec864SMatt Jacob default: 978126ec864SMatt Jacob return (0); 979126ec864SMatt Jacob } 980126ec864SMatt Jacob } 981126ec864SMatt Jacob 9821dae40ebSMatt Jacob static uint16_t 983126ec864SMatt Jacob isp_pci_rd_reg(struct ispsoftc *isp, int regoff) 98465adb54cSMatt Jacob { 9851dae40ebSMatt Jacob uint16_t rv; 98665adb54cSMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 987126ec864SMatt Jacob int oldconf = 0; 98865adb54cSMatt Jacob 989d59bd469SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 99065adb54cSMatt Jacob /* 99165adb54cSMatt Jacob * We will assume that someone has paused the RISC processor. 99265adb54cSMatt Jacob */ 993126ec864SMatt Jacob oldconf = BXR2(pcs, IspVirt2Off(isp, BIU_CONF1)); 994126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), 995126ec864SMatt Jacob oldconf | BIU_PCI_CONF1_SXP); 99665adb54cSMatt Jacob } 997126ec864SMatt Jacob rv = BXR2(pcs, IspVirt2Off(isp, regoff)); 998d59bd469SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 999126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), oldconf); 100065adb54cSMatt Jacob } 100165adb54cSMatt Jacob return (rv); 100265adb54cSMatt Jacob } 100365adb54cSMatt Jacob 100465adb54cSMatt Jacob static void 10051dae40ebSMatt Jacob isp_pci_wr_reg(struct ispsoftc *isp, int regoff, uint16_t val) 100665adb54cSMatt Jacob { 100765adb54cSMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 1008126ec864SMatt Jacob int oldconf = 0; 1009d59bd469SMatt Jacob 1010d59bd469SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 101165adb54cSMatt Jacob /* 101265adb54cSMatt Jacob * We will assume that someone has paused the RISC processor. 101365adb54cSMatt Jacob */ 1014126ec864SMatt Jacob oldconf = BXR2(pcs, IspVirt2Off(isp, BIU_CONF1)); 1015126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), 1016126ec864SMatt Jacob oldconf | BIU_PCI_CONF1_SXP); 101765adb54cSMatt Jacob } 1018126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, regoff), val); 1019d59bd469SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 1020126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), oldconf); 102165adb54cSMatt Jacob } 102265adb54cSMatt Jacob } 102365adb54cSMatt Jacob 10241dae40ebSMatt Jacob static uint16_t 1025126ec864SMatt Jacob isp_pci_rd_reg_1080(struct ispsoftc *isp, int regoff) 1026d59bd469SMatt Jacob { 10271dae40ebSMatt Jacob uint16_t rv, oc = 0; 1028d59bd469SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 1029d59bd469SMatt Jacob 103022e1dc85SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK || 103122e1dc85SMatt Jacob (regoff & _BLK_REG_MASK) == (SXP_BLOCK|SXP_BANK1_SELECT)) { 10321dae40ebSMatt Jacob uint16_t tc; 1033d59bd469SMatt Jacob /* 1034d59bd469SMatt Jacob * We will assume that someone has paused the RISC processor. 1035d59bd469SMatt Jacob */ 1036126ec864SMatt Jacob oc = BXR2(pcs, IspVirt2Off(isp, BIU_CONF1)); 103722e1dc85SMatt Jacob tc = oc & ~BIU_PCI1080_CONF1_DMA; 103822e1dc85SMatt Jacob if (regoff & SXP_BANK1_SELECT) 103922e1dc85SMatt Jacob tc |= BIU_PCI1080_CONF1_SXP1; 104022e1dc85SMatt Jacob else 104122e1dc85SMatt Jacob tc |= BIU_PCI1080_CONF1_SXP0; 1042126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), tc); 1043d59bd469SMatt Jacob } else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) { 1044126ec864SMatt Jacob oc = BXR2(pcs, IspVirt2Off(isp, BIU_CONF1)); 1045126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), 1046126ec864SMatt Jacob oc | BIU_PCI1080_CONF1_DMA); 1047d59bd469SMatt Jacob } 1048126ec864SMatt Jacob rv = BXR2(pcs, IspVirt2Off(isp, regoff)); 104922e1dc85SMatt Jacob if (oc) { 1050126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), oc); 1051d59bd469SMatt Jacob } 1052d59bd469SMatt Jacob return (rv); 1053d59bd469SMatt Jacob } 1054d59bd469SMatt Jacob 1055d59bd469SMatt Jacob static void 10561dae40ebSMatt Jacob isp_pci_wr_reg_1080(struct ispsoftc *isp, int regoff, uint16_t val) 1057d59bd469SMatt Jacob { 1058d59bd469SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 1059126ec864SMatt Jacob int oc = 0; 1060d59bd469SMatt Jacob 106122e1dc85SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK || 106222e1dc85SMatt Jacob (regoff & _BLK_REG_MASK) == (SXP_BLOCK|SXP_BANK1_SELECT)) { 10631dae40ebSMatt Jacob uint16_t tc; 1064d59bd469SMatt Jacob /* 1065d59bd469SMatt Jacob * We will assume that someone has paused the RISC processor. 1066d59bd469SMatt Jacob */ 1067126ec864SMatt Jacob oc = BXR2(pcs, IspVirt2Off(isp, BIU_CONF1)); 106822e1dc85SMatt Jacob tc = oc & ~BIU_PCI1080_CONF1_DMA; 106922e1dc85SMatt Jacob if (regoff & SXP_BANK1_SELECT) 107022e1dc85SMatt Jacob tc |= BIU_PCI1080_CONF1_SXP1; 107122e1dc85SMatt Jacob else 107222e1dc85SMatt Jacob tc |= BIU_PCI1080_CONF1_SXP0; 1073126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), tc); 1074d59bd469SMatt Jacob } else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) { 1075126ec864SMatt Jacob oc = BXR2(pcs, IspVirt2Off(isp, BIU_CONF1)); 1076126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), 1077126ec864SMatt Jacob oc | BIU_PCI1080_CONF1_DMA); 1078d59bd469SMatt Jacob } 1079126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, regoff), val); 108022e1dc85SMatt Jacob if (oc) { 1081126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), oc); 1082d59bd469SMatt Jacob } 1083d59bd469SMatt Jacob } 1084d59bd469SMatt Jacob 1085d720e6d5SJustin T. Gibbs 1086222bb542SMatt Jacob struct imush { 1087222bb542SMatt Jacob struct ispsoftc *isp; 1088222bb542SMatt Jacob int error; 1089222bb542SMatt Jacob }; 1090222bb542SMatt Jacob 10911923f739SMatt Jacob static void imc(void *, bus_dma_segment_t *, int, int); 10921923f739SMatt Jacob 1093d720e6d5SJustin T. Gibbs static void 10941923f739SMatt Jacob imc(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1095d720e6d5SJustin T. Gibbs { 1096222bb542SMatt Jacob struct imush *imushp = (struct imush *) arg; 1097222bb542SMatt Jacob if (error) { 1098222bb542SMatt Jacob imushp->error = error; 1099222bb542SMatt Jacob } else { 11001923f739SMatt Jacob struct ispsoftc *isp =imushp->isp; 11011923f739SMatt Jacob bus_addr_t addr = segs->ds_addr; 11021923f739SMatt Jacob 11031923f739SMatt Jacob isp->isp_rquest_dma = addr; 11041923f739SMatt Jacob addr += ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)); 11051923f739SMatt Jacob isp->isp_result_dma = addr; 11061923f739SMatt Jacob if (IS_FC(isp)) { 11071923f739SMatt Jacob addr += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)); 11081923f739SMatt Jacob FCPARAM(isp)->isp_scdma = addr; 11091923f739SMatt Jacob } 1110222bb542SMatt Jacob } 1111d720e6d5SJustin T. Gibbs } 1112d720e6d5SJustin T. Gibbs 1113029f13c6SMatt Jacob /* 1114029f13c6SMatt Jacob * Should be BUS_SPACE_MAXSIZE, but MAXPHYS is larger than BUS_SPACE_MAXSIZE 1115029f13c6SMatt Jacob */ 1116029f13c6SMatt Jacob #define ISP_NSEGS ((MAXPHYS / PAGE_SIZE) + 1) 1117d720e6d5SJustin T. Gibbs 1118d720e6d5SJustin T. Gibbs static int 111917e318c6SMatt Jacob isp_pci_mbxdma(struct ispsoftc *isp) 1120d720e6d5SJustin T. Gibbs { 11211923f739SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *)isp; 1122d720e6d5SJustin T. Gibbs caddr_t base; 11231dae40ebSMatt Jacob uint32_t len; 11241923f739SMatt Jacob int i, error, ns; 112553af7d22SMatt Jacob bus_size_t slim; /* segment size */ 11264b2dc3c4SScott Long bus_addr_t llim; /* low limit of unavailable dma */ 112751effc8cSMatt Jacob bus_addr_t hlim; /* high limit of unavailable dma */ 1128222bb542SMatt Jacob struct imush im; 1129222bb542SMatt Jacob 1130a95ae193SMatt Jacob /* 1131a95ae193SMatt Jacob * Already been here? If so, leave... 1132a95ae193SMatt Jacob */ 1133a95ae193SMatt Jacob if (isp->isp_rquest) { 1134a95ae193SMatt Jacob return (0); 1135a95ae193SMatt Jacob } 1136a95ae193SMatt Jacob 113753af7d22SMatt Jacob hlim = BUS_SPACE_MAXADDR; 11381923f739SMatt Jacob if (IS_ULTRA2(isp) || IS_FC(isp) || IS_1240(isp)) { 113953af7d22SMatt Jacob slim = (bus_size_t) (1ULL << 32); 11401dae40ebSMatt Jacob #ifdef ISP_TARGET_MODE 11411dae40ebSMatt Jacob /* 11421dae40ebSMatt Jacob * XXX: Until Fixed Soon 11431dae40ebSMatt Jacob */ 11441dae40ebSMatt Jacob llim = BUS_SPACE_MAXADDR_32BIT; 11451dae40ebSMatt Jacob #else 11461dae40ebSMatt Jacob llim = BUS_SPACE_MAXADDR; 11471dae40ebSMatt Jacob #endif 11481923f739SMatt Jacob } else { 11491dae40ebSMatt Jacob llim = BUS_SPACE_MAXADDR_32BIT; 115053af7d22SMatt Jacob slim = (1 << 24); 11511923f739SMatt Jacob } 11521923f739SMatt Jacob 115372429e49SMatt Jacob ISP_UNLOCK(isp); 115453af7d22SMatt Jacob if (bus_dma_tag_create(NULL, 1, slim, llim, hlim, 1155f6b1c44dSScott Long NULL, NULL, BUS_SPACE_MAXSIZE, ISP_NSEGS, slim, 0, 1156f6b1c44dSScott Long busdma_lock_mutex, &Giant, &pcs->dmat)) { 11571923f739SMatt Jacob isp_prt(isp, ISP_LOGERR, "could not create master dma tag"); 115872429e49SMatt Jacob ISP_LOCK(isp); 11591923f739SMatt Jacob return(1); 11601923f739SMatt Jacob } 11611923f739SMatt Jacob 11621923f739SMatt Jacob 1163d02373f1SMatt Jacob len = sizeof (XS_T **) * isp->isp_maxcmds; 1164a163d034SWarner Losh isp->isp_xflist = (XS_T **) malloc(len, M_DEVBUF, M_WAITOK | M_ZERO); 1165a95ae193SMatt Jacob if (isp->isp_xflist == NULL) { 1166d02373f1SMatt Jacob isp_prt(isp, ISP_LOGERR, "cannot alloc xflist array"); 116772429e49SMatt Jacob ISP_LOCK(isp); 1168a95ae193SMatt Jacob return (1); 1169a95ae193SMatt Jacob } 117051e23558SNate Lawson #ifdef ISP_TARGET_MODE 117151e23558SNate Lawson len = sizeof (void **) * isp->isp_maxcmds; 117251e23558SNate Lawson isp->isp_tgtlist = (void **) malloc(len, M_DEVBUF, M_WAITOK | M_ZERO); 117351e23558SNate Lawson if (isp->isp_tgtlist == NULL) { 117451e23558SNate Lawson isp_prt(isp, ISP_LOGERR, "cannot alloc tgtlist array"); 117551e23558SNate Lawson ISP_LOCK(isp); 117651e23558SNate Lawson return (1); 117751e23558SNate Lawson } 117851e23558SNate Lawson #endif 1179a95ae193SMatt Jacob len = sizeof (bus_dmamap_t) * isp->isp_maxcmds; 1180a163d034SWarner Losh pcs->dmaps = (bus_dmamap_t *) malloc(len, M_DEVBUF, M_WAITOK); 11811923f739SMatt Jacob if (pcs->dmaps == NULL) { 11821923f739SMatt Jacob isp_prt(isp, ISP_LOGERR, "can't alloc dma map storage"); 1183a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 118451e23558SNate Lawson #ifdef ISP_TARGET_MODE 118551e23558SNate Lawson free(isp->isp_tgtlist, M_DEVBUF); 118651e23558SNate Lawson #endif 118772429e49SMatt Jacob ISP_LOCK(isp); 1188a95ae193SMatt Jacob return (1); 1189a95ae193SMatt Jacob } 1190a95ae193SMatt Jacob 1191d720e6d5SJustin T. Gibbs /* 1192d720e6d5SJustin T. Gibbs * Allocate and map the request, result queues, plus FC scratch area. 1193d720e6d5SJustin T. Gibbs */ 1194d02373f1SMatt Jacob len = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)); 1195d02373f1SMatt Jacob len += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)); 1196222bb542SMatt Jacob if (IS_FC(isp)) { 1197d720e6d5SJustin T. Gibbs len += ISP2100_SCRLEN; 1198d720e6d5SJustin T. Gibbs } 11991923f739SMatt Jacob 12001923f739SMatt Jacob ns = (len / PAGE_SIZE) + 1; 120153af7d22SMatt Jacob /* 120253af7d22SMatt Jacob * Create a tag for the control spaces- force it to within 32 bits. 120353af7d22SMatt Jacob */ 120453af7d22SMatt Jacob if (bus_dma_tag_create(pcs->dmat, QENTRY_LEN, slim, 120553af7d22SMatt Jacob BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, 1206f6b1c44dSScott Long NULL, NULL, len, ns, slim, 0, busdma_lock_mutex, &Giant, 1207f6b1c44dSScott Long &isp->isp_cdmat)) { 1208f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 1209f7dddf8aSMatt Jacob "cannot create a dma tag for control spaces"); 12101923f739SMatt Jacob free(pcs->dmaps, M_DEVBUF); 1211a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 121251e23558SNate Lawson #ifdef ISP_TARGET_MODE 121351e23558SNate Lawson free(isp->isp_tgtlist, M_DEVBUF); 121451e23558SNate Lawson #endif 121572429e49SMatt Jacob ISP_LOCK(isp); 1216d720e6d5SJustin T. Gibbs return (1); 1217d720e6d5SJustin T. Gibbs } 1218d720e6d5SJustin T. Gibbs 12191923f739SMatt Jacob if (bus_dmamem_alloc(isp->isp_cdmat, (void **)&base, BUS_DMA_NOWAIT, 12201923f739SMatt Jacob &isp->isp_cdmap) != 0) { 1221f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 12221923f739SMatt Jacob "cannot allocate %d bytes of CCB memory", len); 12231923f739SMatt Jacob bus_dma_tag_destroy(isp->isp_cdmat); 1224a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 122551e23558SNate Lawson #ifdef ISP_TARGET_MODE 122651e23558SNate Lawson free(isp->isp_tgtlist, M_DEVBUF); 122751e23558SNate Lawson #endif 12281923f739SMatt Jacob free(pcs->dmaps, M_DEVBUF); 122972429e49SMatt Jacob ISP_LOCK(isp); 1230222bb542SMatt Jacob return (1); 1231222bb542SMatt Jacob } 1232d720e6d5SJustin T. Gibbs 1233a95ae193SMatt Jacob for (i = 0; i < isp->isp_maxcmds; i++) { 12341923f739SMatt Jacob error = bus_dmamap_create(pcs->dmat, 0, &pcs->dmaps[i]); 1235d720e6d5SJustin T. Gibbs if (error) { 1236f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 1237f7dddf8aSMatt Jacob "error %d creating per-cmd DMA maps", error); 12381923f739SMatt Jacob while (--i >= 0) { 12391923f739SMatt Jacob bus_dmamap_destroy(pcs->dmat, pcs->dmaps[i]); 12401923f739SMatt Jacob } 12411923f739SMatt Jacob goto bad; 1242d720e6d5SJustin T. Gibbs } 1243d720e6d5SJustin T. Gibbs } 1244a95ae193SMatt Jacob 12451923f739SMatt Jacob im.isp = isp; 1246222bb542SMatt Jacob im.error = 0; 12471923f739SMatt Jacob bus_dmamap_load(isp->isp_cdmat, isp->isp_cdmap, base, len, imc, &im, 0); 1248222bb542SMatt Jacob if (im.error) { 1249f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 12501923f739SMatt Jacob "error %d loading dma map for control areas", im.error); 12511923f739SMatt Jacob goto bad; 1252222bb542SMatt Jacob } 12531923f739SMatt Jacob 12541923f739SMatt Jacob isp->isp_rquest = base; 12551923f739SMatt Jacob base += ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)); 12561923f739SMatt Jacob isp->isp_result = base; 12571923f739SMatt Jacob if (IS_FC(isp)) { 12581923f739SMatt Jacob base += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)); 12591923f739SMatt Jacob FCPARAM(isp)->isp_scratch = base; 126092c49d78SMatt Jacob } 126172429e49SMatt Jacob ISP_LOCK(isp); 1262d720e6d5SJustin T. Gibbs return (0); 12631923f739SMatt Jacob 12641923f739SMatt Jacob bad: 12651923f739SMatt Jacob bus_dmamem_free(isp->isp_cdmat, base, isp->isp_cdmap); 12661923f739SMatt Jacob bus_dma_tag_destroy(isp->isp_cdmat); 12671923f739SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 126851e23558SNate Lawson #ifdef ISP_TARGET_MODE 126951e23558SNate Lawson free(isp->isp_tgtlist, M_DEVBUF); 127051e23558SNate Lawson #endif 12711923f739SMatt Jacob free(pcs->dmaps, M_DEVBUF); 127272429e49SMatt Jacob ISP_LOCK(isp); 12731923f739SMatt Jacob isp->isp_rquest = NULL; 12741923f739SMatt Jacob return (1); 1275d720e6d5SJustin T. Gibbs } 1276d720e6d5SJustin T. Gibbs 1277d720e6d5SJustin T. Gibbs typedef struct { 1278d720e6d5SJustin T. Gibbs struct ispsoftc *isp; 12799e11e5beSMatt Jacob void *cmd_token; 12809e11e5beSMatt Jacob void *rq; 12811dae40ebSMatt Jacob uint16_t *nxtip; 12821dae40ebSMatt Jacob uint16_t optr; 12831dae40ebSMatt Jacob int error; 1284d720e6d5SJustin T. Gibbs } mush_t; 1285d720e6d5SJustin T. Gibbs 12864873663cSMatt Jacob #define MUSHERR_NOQENTRIES -2 12874873663cSMatt Jacob 12889e11e5beSMatt Jacob #ifdef ISP_TARGET_MODE 12899e11e5beSMatt Jacob /* 12909e11e5beSMatt Jacob * We need to handle DMA for target mode differently from initiator mode. 12919e11e5beSMatt Jacob * 12929e11e5beSMatt Jacob * DMA mapping and construction and submission of CTIO Request Entries 12939e11e5beSMatt Jacob * and rendevous for completion are very tightly coupled because we start 12949e11e5beSMatt Jacob * out by knowing (per platform) how much data we have to move, but we 12959e11e5beSMatt Jacob * don't know, up front, how many DMA mapping segments will have to be used 12969e11e5beSMatt Jacob * cover that data, so we don't know how many CTIO Request Entries we 12979e11e5beSMatt Jacob * will end up using. Further, for performance reasons we may want to 12989e11e5beSMatt Jacob * (on the last CTIO for Fibre Channel), send status too (if all went well). 12999e11e5beSMatt Jacob * 13009e11e5beSMatt Jacob * The standard vector still goes through isp_pci_dmasetup, but the callback 13019e11e5beSMatt Jacob * for the DMA mapping routines comes here instead with the whole transfer 13029e11e5beSMatt Jacob * mapped and a pointer to a partially filled in already allocated request 13039e11e5beSMatt Jacob * queue entry. We finish the job. 13049e11e5beSMatt Jacob */ 1305e9a2738aSMatt Jacob static void tdma_mk(void *, bus_dma_segment_t *, int, int); 1306e9a2738aSMatt Jacob static void tdma_mkfc(void *, bus_dma_segment_t *, int, int); 1307e9a2738aSMatt Jacob 1308e9a2738aSMatt Jacob #define STATUS_WITH_DATA 1 13099e11e5beSMatt Jacob 1310d720e6d5SJustin T. Gibbs static void 131105fbcbb0SMatt Jacob tdma_mk(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 1312d720e6d5SJustin T. Gibbs { 1313d720e6d5SJustin T. Gibbs mush_t *mp; 13149e11e5beSMatt Jacob struct ccb_scsiio *csio; 13154fd13c1bSMatt Jacob struct ispsoftc *isp; 13161923f739SMatt Jacob struct isp_pcisoftc *pcs; 1317d720e6d5SJustin T. Gibbs bus_dmamap_t *dp; 13184fd13c1bSMatt Jacob ct_entry_t *cto, *qe; 13191dae40ebSMatt Jacob uint8_t scsi_status; 13201dae40ebSMatt Jacob uint16_t curi, nxti, handle; 13211dae40ebSMatt Jacob uint32_t sflags; 132205fbcbb0SMatt Jacob int32_t resid; 13234fd13c1bSMatt Jacob int nth_ctio, nctios, send_status; 1324d720e6d5SJustin T. Gibbs 1325d720e6d5SJustin T. Gibbs mp = (mush_t *) arg; 1326d720e6d5SJustin T. Gibbs if (error) { 1327d720e6d5SJustin T. Gibbs mp->error = error; 1328d720e6d5SJustin T. Gibbs return; 1329d720e6d5SJustin T. Gibbs } 13304fd13c1bSMatt Jacob 13314fd13c1bSMatt Jacob isp = mp->isp; 13329e11e5beSMatt Jacob csio = mp->cmd_token; 13339e11e5beSMatt Jacob cto = mp->rq; 13344fd13c1bSMatt Jacob curi = isp->isp_reqidx; 13354fd13c1bSMatt Jacob qe = (ct_entry_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, curi); 13369e11e5beSMatt Jacob 133765b024e1SMatt Jacob cto->ct_xfrlen = 0; 133865b024e1SMatt Jacob cto->ct_seg_count = 0; 133965b024e1SMatt Jacob cto->ct_header.rqs_entry_count = 1; 134005fbcbb0SMatt Jacob MEMZERO(cto->ct_dataseg, sizeof(cto->ct_dataseg)); 134105fbcbb0SMatt Jacob 134205fbcbb0SMatt Jacob if (nseg == 0) { 134305fbcbb0SMatt Jacob cto->ct_header.rqs_seqno = 1; 13444fd13c1bSMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, 1345e9a2738aSMatt Jacob "CTIO[%x] lun%d iid%d tag %x flgs %x sts %x ssts %x res %d", 13465f5aafe1SMatt Jacob cto->ct_fwhandle, csio->ccb_h.target_lun, cto->ct_iid, 1347e9a2738aSMatt Jacob cto->ct_tag_val, cto->ct_flags, cto->ct_status, 1348e9a2738aSMatt Jacob cto->ct_scsi_status, cto->ct_resid); 13494fd13c1bSMatt Jacob ISP_TDQE(isp, "tdma_mk[no data]", curi, cto); 13504fd13c1bSMatt Jacob isp_put_ctio(isp, cto, qe); 135165b024e1SMatt Jacob return; 135265b024e1SMatt Jacob } 135365b024e1SMatt Jacob 135465b024e1SMatt Jacob nctios = nseg / ISP_RQDSEG; 135565b024e1SMatt Jacob if (nseg % ISP_RQDSEG) { 135665b024e1SMatt Jacob nctios++; 135765b024e1SMatt Jacob } 135865b024e1SMatt Jacob 135905fbcbb0SMatt Jacob /* 13605f5aafe1SMatt Jacob * Save syshandle, and potentially any SCSI status, which we'll 13615f5aafe1SMatt Jacob * reinsert on the last CTIO we're going to send. 136205fbcbb0SMatt Jacob */ 13634fd13c1bSMatt Jacob 13645f5aafe1SMatt Jacob handle = cto->ct_syshandle; 13655f5aafe1SMatt Jacob cto->ct_syshandle = 0; 136605fbcbb0SMatt Jacob cto->ct_header.rqs_seqno = 0; 136705fbcbb0SMatt Jacob send_status = (cto->ct_flags & CT_SENDSTATUS) != 0; 136805fbcbb0SMatt Jacob 136905fbcbb0SMatt Jacob if (send_status) { 137005fbcbb0SMatt Jacob sflags = cto->ct_flags & (CT_SENDSTATUS | CT_CCINCR); 137105fbcbb0SMatt Jacob cto->ct_flags &= ~(CT_SENDSTATUS | CT_CCINCR); 137205fbcbb0SMatt Jacob /* 137305fbcbb0SMatt Jacob * Preserve residual. 137405fbcbb0SMatt Jacob */ 137505fbcbb0SMatt Jacob resid = cto->ct_resid; 137605fbcbb0SMatt Jacob 137705fbcbb0SMatt Jacob /* 137805fbcbb0SMatt Jacob * Save actual SCSI status. 137905fbcbb0SMatt Jacob */ 138005fbcbb0SMatt Jacob scsi_status = cto->ct_scsi_status; 138105fbcbb0SMatt Jacob 1382e9a2738aSMatt Jacob #ifndef STATUS_WITH_DATA 1383e9a2738aSMatt Jacob sflags |= CT_NO_DATA; 138405fbcbb0SMatt Jacob /* 138505fbcbb0SMatt Jacob * We can't do a status at the same time as a data CTIO, so 138605fbcbb0SMatt Jacob * we need to synthesize an extra CTIO at this level. 138705fbcbb0SMatt Jacob */ 138805fbcbb0SMatt Jacob nctios++; 1389b72b1569SMatt Jacob #endif 139005fbcbb0SMatt Jacob } else { 139105fbcbb0SMatt Jacob sflags = scsi_status = resid = 0; 139205fbcbb0SMatt Jacob } 139305fbcbb0SMatt Jacob 1394b96934e8SMatt Jacob cto->ct_resid = 0; 139505fbcbb0SMatt Jacob cto->ct_scsi_status = 0; 139605fbcbb0SMatt Jacob 13971923f739SMatt Jacob pcs = (struct isp_pcisoftc *)isp; 13981923f739SMatt Jacob dp = &pcs->dmaps[isp_handle_index(handle)]; 13999e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 14001923f739SMatt Jacob bus_dmamap_sync(pcs->dmat, *dp, BUS_DMASYNC_PREREAD); 1401d720e6d5SJustin T. Gibbs } else { 14021923f739SMatt Jacob bus_dmamap_sync(pcs->dmat, *dp, BUS_DMASYNC_PREWRITE); 1403d720e6d5SJustin T. Gibbs } 1404d720e6d5SJustin T. Gibbs 14054fd13c1bSMatt Jacob nxti = *mp->nxtip; 14069e11e5beSMatt Jacob 14074fd13c1bSMatt Jacob for (nth_ctio = 0; nth_ctio < nctios; nth_ctio++) { 140805fbcbb0SMatt Jacob int seglim; 14099e11e5beSMatt Jacob 14109e11e5beSMatt Jacob seglim = nseg; 141105fbcbb0SMatt Jacob if (seglim) { 141205fbcbb0SMatt Jacob int seg; 141305fbcbb0SMatt Jacob 14149e11e5beSMatt Jacob if (seglim > ISP_RQDSEG) 14159e11e5beSMatt Jacob seglim = ISP_RQDSEG; 14169e11e5beSMatt Jacob 141705fbcbb0SMatt Jacob for (seg = 0; seg < seglim; seg++, nseg--) { 141805fbcbb0SMatt Jacob /* 141905fbcbb0SMatt Jacob * Unlike normal initiator commands, we don't 142005fbcbb0SMatt Jacob * do any swizzling here. 142105fbcbb0SMatt Jacob */ 14229e11e5beSMatt Jacob cto->ct_dataseg[seg].ds_count = dm_segs->ds_len; 142305fbcbb0SMatt Jacob cto->ct_dataseg[seg].ds_base = dm_segs->ds_addr; 14249e11e5beSMatt Jacob cto->ct_xfrlen += dm_segs->ds_len; 14259e11e5beSMatt Jacob dm_segs++; 14269e11e5beSMatt Jacob } 14279e11e5beSMatt Jacob cto->ct_seg_count = seg; 14289e11e5beSMatt Jacob } else { 142905fbcbb0SMatt Jacob /* 143005fbcbb0SMatt Jacob * This case should only happen when we're sending an 143105fbcbb0SMatt Jacob * extra CTIO with final status. 143205fbcbb0SMatt Jacob */ 143305fbcbb0SMatt Jacob if (send_status == 0) { 14344fd13c1bSMatt Jacob isp_prt(isp, ISP_LOGWARN, 1435f7dddf8aSMatt Jacob "tdma_mk ran out of segments"); 143605fbcbb0SMatt Jacob mp->error = EINVAL; 143705fbcbb0SMatt Jacob return; 14389e11e5beSMatt Jacob } 143905fbcbb0SMatt Jacob } 144005fbcbb0SMatt Jacob 144105fbcbb0SMatt Jacob /* 144205fbcbb0SMatt Jacob * At this point, the fields ct_lun, ct_iid, ct_tagval, 144305fbcbb0SMatt Jacob * ct_tagtype, and ct_timeout have been carried over 144405fbcbb0SMatt Jacob * unchanged from what our caller had set. 144505fbcbb0SMatt Jacob * 144605fbcbb0SMatt Jacob * The dataseg fields and the seg_count fields we just got 144705fbcbb0SMatt Jacob * through setting. The data direction we've preserved all 144805fbcbb0SMatt Jacob * along and only clear it if we're now sending status. 144905fbcbb0SMatt Jacob */ 14509e11e5beSMatt Jacob 14514fd13c1bSMatt Jacob if (nth_ctio == nctios - 1) { 14529e11e5beSMatt Jacob /* 145305fbcbb0SMatt Jacob * We're the last in a sequence of CTIOs, so mark 145405fbcbb0SMatt Jacob * this CTIO and save the handle to the CCB such that 145505fbcbb0SMatt Jacob * when this CTIO completes we can free dma resources 145605fbcbb0SMatt Jacob * and do whatever else we need to do to finish the 1457e9a2738aSMatt Jacob * rest of the command. We *don't* give this to the 1458e9a2738aSMatt Jacob * firmware to work on- the caller will do that. 14599e11e5beSMatt Jacob */ 14604fd13c1bSMatt Jacob 14615f5aafe1SMatt Jacob cto->ct_syshandle = handle; 146205fbcbb0SMatt Jacob cto->ct_header.rqs_seqno = 1; 146305fbcbb0SMatt Jacob 146405fbcbb0SMatt Jacob if (send_status) { 14659e11e5beSMatt Jacob cto->ct_scsi_status = scsi_status; 1466b72b1569SMatt Jacob cto->ct_flags |= sflags; 146705fbcbb0SMatt Jacob cto->ct_resid = resid; 146842426921SMatt Jacob } 1469d02373f1SMatt Jacob if (send_status) { 14704fd13c1bSMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, 1471e9a2738aSMatt Jacob "CTIO[%x] lun%d iid %d tag %x ct_flags %x " 14725f5aafe1SMatt Jacob "scsi status %x resid %d", 14735f5aafe1SMatt Jacob cto->ct_fwhandle, csio->ccb_h.target_lun, 1474e9a2738aSMatt Jacob cto->ct_iid, cto->ct_tag_val, cto->ct_flags, 147505fbcbb0SMatt Jacob cto->ct_scsi_status, cto->ct_resid); 1476d02373f1SMatt Jacob } else { 14774fd13c1bSMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, 1478e9a2738aSMatt Jacob "CTIO[%x] lun%d iid%d tag %x ct_flags 0x%x", 14795f5aafe1SMatt Jacob cto->ct_fwhandle, csio->ccb_h.target_lun, 1480e9a2738aSMatt Jacob cto->ct_iid, cto->ct_tag_val, 1481e9a2738aSMatt Jacob cto->ct_flags); 148205fbcbb0SMatt Jacob } 14834fd13c1bSMatt Jacob isp_put_ctio(isp, cto, qe); 14844fd13c1bSMatt Jacob ISP_TDQE(isp, "last tdma_mk", curi, cto); 14854fd13c1bSMatt Jacob if (nctios > 1) { 14864fd13c1bSMatt Jacob MEMORYBARRIER(isp, SYNC_REQUEST, 14874fd13c1bSMatt Jacob curi, QENTRY_LEN); 14884fd13c1bSMatt Jacob } 14899e11e5beSMatt Jacob } else { 14904fd13c1bSMatt Jacob ct_entry_t *oqe = qe; 149105fbcbb0SMatt Jacob 149205fbcbb0SMatt Jacob /* 14935f5aafe1SMatt Jacob * Make sure syshandle fields are clean 149405fbcbb0SMatt Jacob */ 14955f5aafe1SMatt Jacob cto->ct_syshandle = 0; 14969e11e5beSMatt Jacob cto->ct_header.rqs_seqno = 0; 149705fbcbb0SMatt Jacob 14984fd13c1bSMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, 14995f5aafe1SMatt Jacob "CTIO[%x] lun%d for ID%d ct_flags 0x%x", 15005f5aafe1SMatt Jacob cto->ct_fwhandle, csio->ccb_h.target_lun, 15015f5aafe1SMatt Jacob cto->ct_iid, cto->ct_flags); 150205fbcbb0SMatt Jacob 150305fbcbb0SMatt Jacob /* 150405fbcbb0SMatt Jacob * Get a new CTIO 150505fbcbb0SMatt Jacob */ 15064fd13c1bSMatt Jacob qe = (ct_entry_t *) 15074fd13c1bSMatt Jacob ISP_QUEUE_ENTRY(isp->isp_rquest, nxti); 15084fd13c1bSMatt Jacob nxti = ISP_NXT_QENTRY(nxti, RQUEST_QUEUE_LEN(isp)); 15094fd13c1bSMatt Jacob if (nxti == mp->optr) { 15104fd13c1bSMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 1511f7dddf8aSMatt Jacob "Queue Overflow in tdma_mk"); 15129e11e5beSMatt Jacob mp->error = MUSHERR_NOQENTRIES; 15139e11e5beSMatt Jacob return; 15149e11e5beSMatt Jacob } 15154fd13c1bSMatt Jacob 15169e11e5beSMatt Jacob /* 15174fd13c1bSMatt Jacob * Now that we're done with the old CTIO, 15184fd13c1bSMatt Jacob * flush it out to the request queue. 15194fd13c1bSMatt Jacob */ 15204fd13c1bSMatt Jacob ISP_TDQE(isp, "dma_tgt_fc", curi, cto); 15214fd13c1bSMatt Jacob isp_put_ctio(isp, cto, oqe); 15224fd13c1bSMatt Jacob if (nth_ctio != 0) { 15234fd13c1bSMatt Jacob MEMORYBARRIER(isp, SYNC_REQUEST, curi, 15244fd13c1bSMatt Jacob QENTRY_LEN); 15254fd13c1bSMatt Jacob } 15264fd13c1bSMatt Jacob curi = ISP_NXT_QENTRY(curi, RQUEST_QUEUE_LEN(isp)); 15274fd13c1bSMatt Jacob 15284fd13c1bSMatt Jacob /* 15294fd13c1bSMatt Jacob * Reset some fields in the CTIO so we can reuse 15304fd13c1bSMatt Jacob * for the next one we'll flush to the request 15314fd13c1bSMatt Jacob * queue. 15329e11e5beSMatt Jacob */ 15339e11e5beSMatt Jacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO; 15349e11e5beSMatt Jacob cto->ct_header.rqs_entry_count = 1; 15359e11e5beSMatt Jacob cto->ct_header.rqs_flags = 0; 15369e11e5beSMatt Jacob cto->ct_status = 0; 15379e11e5beSMatt Jacob cto->ct_scsi_status = 0; 15389e11e5beSMatt Jacob cto->ct_xfrlen = 0; 15399e11e5beSMatt Jacob cto->ct_resid = 0; 15409e11e5beSMatt Jacob cto->ct_seg_count = 0; 154105fbcbb0SMatt Jacob MEMZERO(cto->ct_dataseg, sizeof(cto->ct_dataseg)); 15429e11e5beSMatt Jacob } 15439e11e5beSMatt Jacob } 15444fd13c1bSMatt Jacob *mp->nxtip = nxti; 15459e11e5beSMatt Jacob } 15469e11e5beSMatt Jacob 1547fc087171SMatt Jacob /* 1548fc087171SMatt Jacob * We don't have to do multiple CTIOs here. Instead, we can just do 1549fc087171SMatt Jacob * continuation segments as needed. This greatly simplifies the code 1550fc087171SMatt Jacob * improves performance. 1551fc087171SMatt Jacob */ 1552fc087171SMatt Jacob 15539e11e5beSMatt Jacob static void 155405fbcbb0SMatt Jacob tdma_mkfc(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 15559e11e5beSMatt Jacob { 15569e11e5beSMatt Jacob mush_t *mp; 15579e11e5beSMatt Jacob struct ccb_scsiio *csio; 15584fd13c1bSMatt Jacob struct ispsoftc *isp; 15594fd13c1bSMatt Jacob ct2_entry_t *cto, *qe; 15601dae40ebSMatt Jacob uint16_t curi, nxti; 1561fc087171SMatt Jacob int segcnt; 15629e11e5beSMatt Jacob 15639e11e5beSMatt Jacob mp = (mush_t *) arg; 15649e11e5beSMatt Jacob if (error) { 15659e11e5beSMatt Jacob mp->error = error; 15669e11e5beSMatt Jacob return; 15679e11e5beSMatt Jacob } 15689e11e5beSMatt Jacob 15694fd13c1bSMatt Jacob isp = mp->isp; 157065b024e1SMatt Jacob csio = mp->cmd_token; 157165b024e1SMatt Jacob cto = mp->rq; 1572fc087171SMatt Jacob 15734fd13c1bSMatt Jacob curi = isp->isp_reqidx; 15744fd13c1bSMatt Jacob qe = (ct2_entry_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, curi); 157565b024e1SMatt Jacob 157665b024e1SMatt Jacob if (nseg == 0) { 157765b024e1SMatt Jacob if ((cto->ct_flags & CT2_FLAG_MMASK) != CT2_FLAG_MODE1) { 15784fd13c1bSMatt Jacob isp_prt(isp, ISP_LOGWARN, 1579f7dddf8aSMatt Jacob "dma2_tgt_fc, a status CTIO2 without MODE1 " 1580f7dddf8aSMatt Jacob "set (0x%x)", cto->ct_flags); 158165b024e1SMatt Jacob mp->error = EINVAL; 158265b024e1SMatt Jacob return; 158365b024e1SMatt Jacob } 158465b024e1SMatt Jacob /* 158565b024e1SMatt Jacob * We preserve ct_lun, ct_iid, ct_rxid. We set the data 158665b024e1SMatt Jacob * flags to NO DATA and clear relative offset flags. 158765b024e1SMatt Jacob * We preserve the ct_resid and the response area. 158865b024e1SMatt Jacob */ 1589fc087171SMatt Jacob cto->ct_header.rqs_seqno = 1; 159065b024e1SMatt Jacob cto->ct_seg_count = 0; 159165b024e1SMatt Jacob cto->ct_reloff = 0; 15924fd13c1bSMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, 15935f5aafe1SMatt Jacob "CTIO2[%x] lun %d->iid%d flgs 0x%x sts 0x%x ssts " 1594d02373f1SMatt Jacob "0x%x res %d", cto->ct_rxid, csio->ccb_h.target_lun, 1595d02373f1SMatt Jacob cto->ct_iid, cto->ct_flags, cto->ct_status, 159665b024e1SMatt Jacob cto->rsp.m1.ct_scsi_status, cto->ct_resid); 15974fd13c1bSMatt Jacob isp_put_ctio2(isp, cto, qe); 15984fd13c1bSMatt Jacob ISP_TDQE(isp, "dma2_tgt_fc[no data]", curi, qe); 15999e11e5beSMatt Jacob return; 16009e11e5beSMatt Jacob } 16019e11e5beSMatt Jacob 160265b024e1SMatt Jacob if ((cto->ct_flags & CT2_FLAG_MMASK) != CT2_FLAG_MODE0) { 1603fc087171SMatt Jacob isp_prt(isp, ISP_LOGERR, 1604f7dddf8aSMatt Jacob "dma2_tgt_fc, a data CTIO2 without MODE0 set " 1605f7dddf8aSMatt Jacob "(0x%x)", cto->ct_flags); 160665b024e1SMatt Jacob mp->error = EINVAL; 160765b024e1SMatt Jacob return; 160865b024e1SMatt Jacob } 160965b024e1SMatt Jacob 161065b024e1SMatt Jacob 16114fd13c1bSMatt Jacob nxti = *mp->nxtip; 16124fd13c1bSMatt Jacob 1613fc087171SMatt Jacob /* 1614fc087171SMatt Jacob * Set up the CTIO2 data segments. 1615fc087171SMatt Jacob */ 1616fc087171SMatt Jacob for (segcnt = 0; cto->ct_seg_count < ISP_RQDSEG_T2 && segcnt < nseg; 1617fc087171SMatt Jacob cto->ct_seg_count++, segcnt++) { 1618fc087171SMatt Jacob cto->rsp.m0.ct_dataseg[cto->ct_seg_count].ds_base = 1619fc087171SMatt Jacob dm_segs[segcnt].ds_addr; 1620fc087171SMatt Jacob cto->rsp.m0.ct_dataseg[cto->ct_seg_count].ds_count = 1621fc087171SMatt Jacob dm_segs[segcnt].ds_len; 1622fc087171SMatt Jacob cto->rsp.m0.ct_xfrlen += dm_segs[segcnt].ds_len; 162376514802SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, 162474a96f43SJohn Baldwin "isp_send_ctio2: ent0[%d]0x%jx:%ju", 162574a96f43SJohn Baldwin cto->ct_seg_count, (uintmax_t)dm_segs[segcnt].ds_addr, 162674a96f43SJohn Baldwin (uintmax_t)dm_segs[segcnt].ds_len); 1627fc087171SMatt Jacob } 16289e11e5beSMatt Jacob 1629fc087171SMatt Jacob while (segcnt < nseg) { 16301dae40ebSMatt Jacob uint16_t curip; 16314fd13c1bSMatt Jacob int seg; 1632fc087171SMatt Jacob ispcontreq_t local, *crq = &local, *qep; 16339e11e5beSMatt Jacob 1634fc087171SMatt Jacob qep = (ispcontreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, nxti); 1635fc087171SMatt Jacob curip = nxti; 1636fc087171SMatt Jacob nxti = ISP_NXT_QENTRY(curip, RQUEST_QUEUE_LEN(isp)); 16374fd13c1bSMatt Jacob if (nxti == mp->optr) { 1638fc087171SMatt Jacob ISP_UNLOCK(isp); 1639fc087171SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 1640fc087171SMatt Jacob "tdma_mkfc: request queue overflow"); 16419e11e5beSMatt Jacob mp->error = MUSHERR_NOQENTRIES; 16429e11e5beSMatt Jacob return; 16439e11e5beSMatt Jacob } 1644fc087171SMatt Jacob cto->ct_header.rqs_entry_count++; 1645fc087171SMatt Jacob MEMZERO((void *)crq, sizeof (*crq)); 1646fc087171SMatt Jacob crq->req_header.rqs_entry_count = 1; 1647fc087171SMatt Jacob crq->req_header.rqs_entry_type = RQSTYPE_DATASEG; 1648fc087171SMatt Jacob for (seg = 0; segcnt < nseg && seg < ISP_CDSEG; 1649fc087171SMatt Jacob segcnt++, seg++) { 1650fc087171SMatt Jacob crq->req_dataseg[seg].ds_base = dm_segs[segcnt].ds_addr; 1651fc087171SMatt Jacob crq->req_dataseg[seg].ds_count = dm_segs[segcnt].ds_len; 1652fc087171SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, 165374a96f43SJohn Baldwin "isp_send_ctio2: ent%d[%d]%jx:%ju", 1654fc087171SMatt Jacob cto->ct_header.rqs_entry_count-1, seg, 165574a96f43SJohn Baldwin (uintmax_t)dm_segs[segcnt].ds_addr, 165674a96f43SJohn Baldwin (uintmax_t)dm_segs[segcnt].ds_len); 1657fc087171SMatt Jacob cto->rsp.m0.ct_xfrlen += dm_segs[segcnt].ds_len; 1658fc087171SMatt Jacob cto->ct_seg_count++; 1659fc087171SMatt Jacob } 1660fc087171SMatt Jacob MEMORYBARRIER(isp, SYNC_REQUEST, curip, QENTRY_LEN); 1661fc087171SMatt Jacob isp_put_cont_req(isp, crq, qep); 1662fc087171SMatt Jacob ISP_TDQE(isp, "cont entry", curi, qep); 1663fc087171SMatt Jacob } 166465b024e1SMatt Jacob 16659e11e5beSMatt Jacob /* 1666fc087171SMatt Jacob * No do final twiddling for the CTIO itself. 16674fd13c1bSMatt Jacob */ 1668fc087171SMatt Jacob cto->ct_header.rqs_seqno = 1; 1669fc087171SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, 1670fc087171SMatt Jacob "CTIO2[%x] lun %d->iid%d flgs 0x%x sts 0x%x ssts 0x%x resid %d", 1671fc087171SMatt Jacob cto->ct_rxid, csio->ccb_h.target_lun, (int) cto->ct_iid, 1672fc087171SMatt Jacob cto->ct_flags, cto->ct_status, cto->rsp.m1.ct_scsi_status, 1673fc087171SMatt Jacob cto->ct_resid); 1674fc087171SMatt Jacob isp_put_ctio2(isp, cto, qe); 1675fc087171SMatt Jacob ISP_TDQE(isp, "last dma2_tgt_fc", curi, qe); 16764fd13c1bSMatt Jacob *mp->nxtip = nxti; 16779e11e5beSMatt Jacob } 16789e11e5beSMatt Jacob #endif 16799e11e5beSMatt Jacob 16801dae40ebSMatt Jacob static void dma2_a64(void *, bus_dma_segment_t *, int, int); 1681126ec864SMatt Jacob static void dma2(void *, bus_dma_segment_t *, int, int); 16829e11e5beSMatt Jacob 16836de9bf77SMatt Jacob static void 16841dae40ebSMatt Jacob dma2_a64(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 16856de9bf77SMatt Jacob { 16866de9bf77SMatt Jacob mush_t *mp; 16876de9bf77SMatt Jacob struct ispsoftc *isp; 16886de9bf77SMatt Jacob struct ccb_scsiio *csio; 16896de9bf77SMatt Jacob struct isp_pcisoftc *pcs; 16906de9bf77SMatt Jacob bus_dmamap_t *dp; 16916de9bf77SMatt Jacob bus_dma_segment_t *eseg; 16926de9bf77SMatt Jacob ispreq64_t *rq; 16936de9bf77SMatt Jacob int seglim, datalen; 16941dae40ebSMatt Jacob uint16_t nxti; 16956de9bf77SMatt Jacob 16966de9bf77SMatt Jacob mp = (mush_t *) arg; 16976de9bf77SMatt Jacob if (error) { 16986de9bf77SMatt Jacob mp->error = error; 16996de9bf77SMatt Jacob return; 17006de9bf77SMatt Jacob } 17016de9bf77SMatt Jacob 17026de9bf77SMatt Jacob if (nseg < 1) { 17036de9bf77SMatt Jacob isp_prt(mp->isp, ISP_LOGERR, "bad segment count (%d)", nseg); 17046de9bf77SMatt Jacob mp->error = EFAULT; 17056de9bf77SMatt Jacob return; 17066de9bf77SMatt Jacob } 17076de9bf77SMatt Jacob csio = mp->cmd_token; 17086de9bf77SMatt Jacob isp = mp->isp; 17096de9bf77SMatt Jacob rq = mp->rq; 17106de9bf77SMatt Jacob pcs = (struct isp_pcisoftc *)mp->isp; 17116de9bf77SMatt Jacob dp = &pcs->dmaps[isp_handle_index(rq->req_handle)]; 17126de9bf77SMatt Jacob nxti = *mp->nxtip; 17136de9bf77SMatt Jacob 17146de9bf77SMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 17156de9bf77SMatt Jacob bus_dmamap_sync(pcs->dmat, *dp, BUS_DMASYNC_PREREAD); 17166de9bf77SMatt Jacob } else { 17176de9bf77SMatt Jacob bus_dmamap_sync(pcs->dmat, *dp, BUS_DMASYNC_PREWRITE); 17186de9bf77SMatt Jacob } 17196de9bf77SMatt Jacob datalen = XS_XFRLEN(csio); 17206de9bf77SMatt Jacob 17216de9bf77SMatt Jacob /* 17226de9bf77SMatt Jacob * We're passed an initial partially filled in entry that 17236de9bf77SMatt Jacob * has most fields filled in except for data transfer 17246de9bf77SMatt Jacob * related values. 17256de9bf77SMatt Jacob * 17266de9bf77SMatt Jacob * Our job is to fill in the initial request queue entry and 17276de9bf77SMatt Jacob * then to start allocating and filling in continuation entries 17286de9bf77SMatt Jacob * until we've covered the entire transfer. 17296de9bf77SMatt Jacob */ 17306de9bf77SMatt Jacob 17316de9bf77SMatt Jacob if (IS_FC(isp)) { 173269767099SMatt Jacob rq->req_header.rqs_entry_type = RQSTYPE_T3RQS; 17336de9bf77SMatt Jacob seglim = ISP_RQDSEG_T3; 17346de9bf77SMatt Jacob ((ispreqt3_t *)rq)->req_totalcnt = datalen; 17356de9bf77SMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 17366de9bf77SMatt Jacob ((ispreqt3_t *)rq)->req_flags |= REQFLAG_DATA_IN; 17376de9bf77SMatt Jacob } else { 17386de9bf77SMatt Jacob ((ispreqt3_t *)rq)->req_flags |= REQFLAG_DATA_OUT; 17396de9bf77SMatt Jacob } 17406de9bf77SMatt Jacob } else { 174169767099SMatt Jacob rq->req_header.rqs_entry_type = RQSTYPE_A64; 17426de9bf77SMatt Jacob if (csio->cdb_len > 12) { 17436de9bf77SMatt Jacob seglim = 0; 17446de9bf77SMatt Jacob } else { 17456de9bf77SMatt Jacob seglim = ISP_RQDSEG_A64; 17466de9bf77SMatt Jacob } 17476de9bf77SMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 17486de9bf77SMatt Jacob rq->req_flags |= REQFLAG_DATA_IN; 17496de9bf77SMatt Jacob } else { 17506de9bf77SMatt Jacob rq->req_flags |= REQFLAG_DATA_OUT; 17516de9bf77SMatt Jacob } 17526de9bf77SMatt Jacob } 17536de9bf77SMatt Jacob 17546de9bf77SMatt Jacob eseg = dm_segs + nseg; 17556de9bf77SMatt Jacob 17566de9bf77SMatt Jacob while (datalen != 0 && rq->req_seg_count < seglim && dm_segs != eseg) { 17576de9bf77SMatt Jacob if (IS_FC(isp)) { 17586de9bf77SMatt Jacob ispreqt3_t *rq3 = (ispreqt3_t *)rq; 17596de9bf77SMatt Jacob rq3->req_dataseg[rq3->req_seg_count].ds_base = 17601dae40ebSMatt Jacob DMA_LO32(dm_segs->ds_addr); 176169767099SMatt Jacob rq3->req_dataseg[rq3->req_seg_count].ds_basehi = 17621dae40ebSMatt Jacob DMA_HI32(dm_segs->ds_addr); 17636de9bf77SMatt Jacob rq3->req_dataseg[rq3->req_seg_count].ds_count = 17646de9bf77SMatt Jacob dm_segs->ds_len; 17656de9bf77SMatt Jacob } else { 17666de9bf77SMatt Jacob rq->req_dataseg[rq->req_seg_count].ds_base = 17671dae40ebSMatt Jacob DMA_LO32(dm_segs->ds_addr); 176869767099SMatt Jacob rq->req_dataseg[rq->req_seg_count].ds_basehi = 17691dae40ebSMatt Jacob DMA_HI32(dm_segs->ds_addr); 17706de9bf77SMatt Jacob rq->req_dataseg[rq->req_seg_count].ds_count = 17716de9bf77SMatt Jacob dm_segs->ds_len; 17726de9bf77SMatt Jacob } 17736de9bf77SMatt Jacob datalen -= dm_segs->ds_len; 17746de9bf77SMatt Jacob rq->req_seg_count++; 17756de9bf77SMatt Jacob dm_segs++; 17766de9bf77SMatt Jacob } 17776de9bf77SMatt Jacob 17786de9bf77SMatt Jacob while (datalen > 0 && dm_segs != eseg) { 17791dae40ebSMatt Jacob uint16_t onxti; 17806de9bf77SMatt Jacob ispcontreq64_t local, *crq = &local, *cqe; 17816de9bf77SMatt Jacob 17826de9bf77SMatt Jacob cqe = (ispcontreq64_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, nxti); 17836de9bf77SMatt Jacob onxti = nxti; 17846de9bf77SMatt Jacob nxti = ISP_NXT_QENTRY(onxti, RQUEST_QUEUE_LEN(isp)); 17856de9bf77SMatt Jacob if (nxti == mp->optr) { 17866de9bf77SMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, "Request Queue Overflow++"); 17876de9bf77SMatt Jacob mp->error = MUSHERR_NOQENTRIES; 17886de9bf77SMatt Jacob return; 17896de9bf77SMatt Jacob } 17906de9bf77SMatt Jacob rq->req_header.rqs_entry_count++; 17916de9bf77SMatt Jacob MEMZERO((void *)crq, sizeof (*crq)); 17926de9bf77SMatt Jacob crq->req_header.rqs_entry_count = 1; 17936de9bf77SMatt Jacob crq->req_header.rqs_entry_type = RQSTYPE_A64_CONT; 17946de9bf77SMatt Jacob 17956de9bf77SMatt Jacob seglim = 0; 17966de9bf77SMatt Jacob while (datalen > 0 && seglim < ISP_CDSEG64 && dm_segs != eseg) { 17976de9bf77SMatt Jacob crq->req_dataseg[seglim].ds_base = 17981dae40ebSMatt Jacob DMA_LO32(dm_segs->ds_addr); 179969767099SMatt Jacob crq->req_dataseg[seglim].ds_basehi = 18001dae40ebSMatt Jacob DMA_HI32(dm_segs->ds_addr); 18016de9bf77SMatt Jacob crq->req_dataseg[seglim].ds_count = 18026de9bf77SMatt Jacob dm_segs->ds_len; 18036de9bf77SMatt Jacob rq->req_seg_count++; 18046de9bf77SMatt Jacob dm_segs++; 18056de9bf77SMatt Jacob seglim++; 18066de9bf77SMatt Jacob datalen -= dm_segs->ds_len; 18076de9bf77SMatt Jacob } 18086de9bf77SMatt Jacob isp_put_cont64_req(isp, crq, cqe); 18096de9bf77SMatt Jacob MEMORYBARRIER(isp, SYNC_REQUEST, onxti, QENTRY_LEN); 18106de9bf77SMatt Jacob } 18116de9bf77SMatt Jacob *mp->nxtip = nxti; 18126de9bf77SMatt Jacob } 18131dae40ebSMatt Jacob 18149e11e5beSMatt Jacob static void 18159e11e5beSMatt Jacob dma2(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 18169e11e5beSMatt Jacob { 18179e11e5beSMatt Jacob mush_t *mp; 18184fd13c1bSMatt Jacob struct ispsoftc *isp; 18199e11e5beSMatt Jacob struct ccb_scsiio *csio; 18201923f739SMatt Jacob struct isp_pcisoftc *pcs; 18219e11e5beSMatt Jacob bus_dmamap_t *dp; 18229e11e5beSMatt Jacob bus_dma_segment_t *eseg; 18239e11e5beSMatt Jacob ispreq_t *rq; 18249e11e5beSMatt Jacob int seglim, datalen; 18251dae40ebSMatt Jacob uint16_t nxti; 18269e11e5beSMatt Jacob 18279e11e5beSMatt Jacob mp = (mush_t *) arg; 18289e11e5beSMatt Jacob if (error) { 18299e11e5beSMatt Jacob mp->error = error; 18309e11e5beSMatt Jacob return; 18319e11e5beSMatt Jacob } 18329e11e5beSMatt Jacob 18339e11e5beSMatt Jacob if (nseg < 1) { 1834f7dddf8aSMatt Jacob isp_prt(mp->isp, ISP_LOGERR, "bad segment count (%d)", nseg); 18359e11e5beSMatt Jacob mp->error = EFAULT; 18369e11e5beSMatt Jacob return; 18379e11e5beSMatt Jacob } 18389e11e5beSMatt Jacob csio = mp->cmd_token; 18394fd13c1bSMatt Jacob isp = mp->isp; 18409e11e5beSMatt Jacob rq = mp->rq; 18411923f739SMatt Jacob pcs = (struct isp_pcisoftc *)mp->isp; 18421923f739SMatt Jacob dp = &pcs->dmaps[isp_handle_index(rq->req_handle)]; 18434fd13c1bSMatt Jacob nxti = *mp->nxtip; 18449e11e5beSMatt Jacob 18459e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 18461923f739SMatt Jacob bus_dmamap_sync(pcs->dmat, *dp, BUS_DMASYNC_PREREAD); 18479e11e5beSMatt Jacob } else { 18481923f739SMatt Jacob bus_dmamap_sync(pcs->dmat, *dp, BUS_DMASYNC_PREWRITE); 18499e11e5beSMatt Jacob } 18509e11e5beSMatt Jacob 18519e11e5beSMatt Jacob datalen = XS_XFRLEN(csio); 18529e11e5beSMatt Jacob 18539e11e5beSMatt Jacob /* 18549e11e5beSMatt Jacob * We're passed an initial partially filled in entry that 18559e11e5beSMatt Jacob * has most fields filled in except for data transfer 18569e11e5beSMatt Jacob * related values. 18579e11e5beSMatt Jacob * 18589e11e5beSMatt Jacob * Our job is to fill in the initial request queue entry and 18599e11e5beSMatt Jacob * then to start allocating and filling in continuation entries 18609e11e5beSMatt Jacob * until we've covered the entire transfer. 18619e11e5beSMatt Jacob */ 18629e11e5beSMatt Jacob 18634fd13c1bSMatt Jacob if (IS_FC(isp)) { 1864d720e6d5SJustin T. Gibbs seglim = ISP_RQDSEG_T2; 1865d720e6d5SJustin T. Gibbs ((ispreqt2_t *)rq)->req_totalcnt = datalen; 18669e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 18679e11e5beSMatt Jacob ((ispreqt2_t *)rq)->req_flags |= REQFLAG_DATA_IN; 18689e11e5beSMatt Jacob } else { 18699e11e5beSMatt Jacob ((ispreqt2_t *)rq)->req_flags |= REQFLAG_DATA_OUT; 18709e11e5beSMatt Jacob } 1871d720e6d5SJustin T. Gibbs } else { 1872e142669aSMatt Jacob if (csio->cdb_len > 12) { 1873e142669aSMatt Jacob seglim = 0; 1874e142669aSMatt Jacob } else { 1875d720e6d5SJustin T. Gibbs seglim = ISP_RQDSEG; 1876e142669aSMatt Jacob } 18779e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 18789e11e5beSMatt Jacob rq->req_flags |= REQFLAG_DATA_IN; 18799e11e5beSMatt Jacob } else { 18809e11e5beSMatt Jacob rq->req_flags |= REQFLAG_DATA_OUT; 18819e11e5beSMatt Jacob } 1882d720e6d5SJustin T. Gibbs } 1883d720e6d5SJustin T. Gibbs 1884d720e6d5SJustin T. Gibbs eseg = dm_segs + nseg; 1885d720e6d5SJustin T. Gibbs 1886d720e6d5SJustin T. Gibbs while (datalen != 0 && rq->req_seg_count < seglim && dm_segs != eseg) { 18874fd13c1bSMatt Jacob if (IS_FC(isp)) { 1888d720e6d5SJustin T. Gibbs ispreqt2_t *rq2 = (ispreqt2_t *)rq; 1889d720e6d5SJustin T. Gibbs rq2->req_dataseg[rq2->req_seg_count].ds_base = 18901dae40ebSMatt Jacob DMA_LO32(dm_segs->ds_addr); 1891d720e6d5SJustin T. Gibbs rq2->req_dataseg[rq2->req_seg_count].ds_count = 1892d720e6d5SJustin T. Gibbs dm_segs->ds_len; 1893d720e6d5SJustin T. Gibbs } else { 1894d720e6d5SJustin T. Gibbs rq->req_dataseg[rq->req_seg_count].ds_base = 18951dae40ebSMatt Jacob DMA_LO32(dm_segs->ds_addr); 1896d720e6d5SJustin T. Gibbs rq->req_dataseg[rq->req_seg_count].ds_count = 1897d720e6d5SJustin T. Gibbs dm_segs->ds_len; 1898d720e6d5SJustin T. Gibbs } 1899d720e6d5SJustin T. Gibbs datalen -= dm_segs->ds_len; 1900d720e6d5SJustin T. Gibbs rq->req_seg_count++; 1901d720e6d5SJustin T. Gibbs dm_segs++; 1902d720e6d5SJustin T. Gibbs } 1903d720e6d5SJustin T. Gibbs 1904d720e6d5SJustin T. Gibbs while (datalen > 0 && dm_segs != eseg) { 19051dae40ebSMatt Jacob uint16_t onxti; 19064fd13c1bSMatt Jacob ispcontreq_t local, *crq = &local, *cqe; 19074fd13c1bSMatt Jacob 19084fd13c1bSMatt Jacob cqe = (ispcontreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, nxti); 19094fd13c1bSMatt Jacob onxti = nxti; 19104fd13c1bSMatt Jacob nxti = ISP_NXT_QENTRY(onxti, RQUEST_QUEUE_LEN(isp)); 19114fd13c1bSMatt Jacob if (nxti == mp->optr) { 19124fd13c1bSMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, "Request Queue Overflow++"); 19134873663cSMatt Jacob mp->error = MUSHERR_NOQENTRIES; 1914d720e6d5SJustin T. Gibbs return; 1915d720e6d5SJustin T. Gibbs } 1916d720e6d5SJustin T. Gibbs rq->req_header.rqs_entry_count++; 19174fd13c1bSMatt Jacob MEMZERO((void *)crq, sizeof (*crq)); 1918d720e6d5SJustin T. Gibbs crq->req_header.rqs_entry_count = 1; 1919d720e6d5SJustin T. Gibbs crq->req_header.rqs_entry_type = RQSTYPE_DATASEG; 1920d720e6d5SJustin T. Gibbs 1921d720e6d5SJustin T. Gibbs seglim = 0; 1922d720e6d5SJustin T. Gibbs while (datalen > 0 && seglim < ISP_CDSEG && dm_segs != eseg) { 1923d720e6d5SJustin T. Gibbs crq->req_dataseg[seglim].ds_base = 19241dae40ebSMatt Jacob DMA_LO32(dm_segs->ds_addr); 1925d720e6d5SJustin T. Gibbs crq->req_dataseg[seglim].ds_count = 1926d720e6d5SJustin T. Gibbs dm_segs->ds_len; 1927d720e6d5SJustin T. Gibbs rq->req_seg_count++; 1928d720e6d5SJustin T. Gibbs dm_segs++; 1929d720e6d5SJustin T. Gibbs seglim++; 1930d720e6d5SJustin T. Gibbs datalen -= dm_segs->ds_len; 1931d720e6d5SJustin T. Gibbs } 19324fd13c1bSMatt Jacob isp_put_cont_req(isp, crq, cqe); 19334fd13c1bSMatt Jacob MEMORYBARRIER(isp, SYNC_REQUEST, onxti, QENTRY_LEN); 1934d720e6d5SJustin T. Gibbs } 19354fd13c1bSMatt Jacob *mp->nxtip = nxti; 1936d720e6d5SJustin T. Gibbs } 1937d720e6d5SJustin T. Gibbs 1938d720e6d5SJustin T. Gibbs static int 19399e11e5beSMatt Jacob isp_pci_dmasetup(struct ispsoftc *isp, struct ccb_scsiio *csio, ispreq_t *rq, 19401dae40ebSMatt Jacob uint16_t *nxtip, uint16_t optr) 1941d720e6d5SJustin T. Gibbs { 19421923f739SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *)isp; 19434fd13c1bSMatt Jacob ispreq_t *qep; 19440a5f7e8bSMatt Jacob bus_dmamap_t *dp = NULL; 1945d720e6d5SJustin T. Gibbs mush_t mush, *mp; 1946126ec864SMatt Jacob void (*eptr)(void *, bus_dma_segment_t *, int, int); 1947d720e6d5SJustin T. Gibbs 19484fd13c1bSMatt Jacob qep = (ispreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, isp->isp_reqidx); 194965b024e1SMatt Jacob #ifdef ISP_TARGET_MODE 195065b024e1SMatt Jacob if (csio->ccb_h.func_code == XPT_CONT_TARGET_IO) { 195165b024e1SMatt Jacob if (IS_FC(isp)) { 195205fbcbb0SMatt Jacob eptr = tdma_mkfc; 195365b024e1SMatt Jacob } else { 195405fbcbb0SMatt Jacob eptr = tdma_mk; 195565b024e1SMatt Jacob } 195605fbcbb0SMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE || 195705fbcbb0SMatt Jacob (csio->dxfer_len == 0)) { 195865b024e1SMatt Jacob mp = &mush; 195965b024e1SMatt Jacob mp->isp = isp; 196065b024e1SMatt Jacob mp->cmd_token = csio; 1961e9a2738aSMatt Jacob mp->rq = rq; /* really a ct_entry_t or ct2_entry_t */ 19624fd13c1bSMatt Jacob mp->nxtip = nxtip; 196365b024e1SMatt Jacob mp->optr = optr; 196465b024e1SMatt Jacob mp->error = 0; 196565b024e1SMatt Jacob (*eptr)(mp, NULL, 0, 0); 19664fd13c1bSMatt Jacob goto mbxsync; 196765b024e1SMatt Jacob } 196865b024e1SMatt Jacob } else 196965b024e1SMatt Jacob #endif 19701dae40ebSMatt Jacob if (sizeof (bus_addr_t) > 4) { 19711dae40ebSMatt Jacob eptr = dma2_a64; 19721dae40ebSMatt Jacob } else { 197365b024e1SMatt Jacob eptr = dma2; 19741dae40ebSMatt Jacob } 197565b024e1SMatt Jacob 19764fd13c1bSMatt Jacob 197705fbcbb0SMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE || 197805fbcbb0SMatt Jacob (csio->dxfer_len == 0)) { 197942426921SMatt Jacob rq->req_seg_count = 1; 19804fd13c1bSMatt Jacob goto mbxsync; 198142426921SMatt Jacob } 198242426921SMatt Jacob 1983d720e6d5SJustin T. Gibbs /* 1984d720e6d5SJustin T. Gibbs * Do a virtual grapevine step to collect info for 19854873663cSMatt Jacob * the callback dma allocation that we have to use... 1986d720e6d5SJustin T. Gibbs */ 1987d720e6d5SJustin T. Gibbs mp = &mush; 1988d720e6d5SJustin T. Gibbs mp->isp = isp; 19899e11e5beSMatt Jacob mp->cmd_token = csio; 1990d720e6d5SJustin T. Gibbs mp->rq = rq; 19914fd13c1bSMatt Jacob mp->nxtip = nxtip; 1992d720e6d5SJustin T. Gibbs mp->optr = optr; 1993d720e6d5SJustin T. Gibbs mp->error = 0; 1994d720e6d5SJustin T. Gibbs 19959e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_SCATTER_VALID) == 0) { 19969e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DATA_PHYS) == 0) { 19974873663cSMatt Jacob int error, s; 19981923f739SMatt Jacob dp = &pcs->dmaps[isp_handle_index(rq->req_handle)]; 1999d720e6d5SJustin T. Gibbs s = splsoftvm(); 20001923f739SMatt Jacob error = bus_dmamap_load(pcs->dmat, *dp, 20019e11e5beSMatt Jacob csio->data_ptr, csio->dxfer_len, eptr, mp, 0); 2002d720e6d5SJustin T. Gibbs if (error == EINPROGRESS) { 20031923f739SMatt Jacob bus_dmamap_unload(pcs->dmat, *dp); 2004d720e6d5SJustin T. Gibbs mp->error = EINVAL; 2005f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 2006f7dddf8aSMatt Jacob "deferred dma allocation not supported"); 2007d720e6d5SJustin T. Gibbs } else if (error && mp->error == 0) { 20080a5f7e8bSMatt Jacob #ifdef DIAGNOSTIC 20096e5c5328SMatt Jacob isp_prt(isp, ISP_LOGERR, 20106e5c5328SMatt Jacob "error %d in dma mapping code", error); 20110a5f7e8bSMatt Jacob #endif 2012d720e6d5SJustin T. Gibbs mp->error = error; 2013d720e6d5SJustin T. Gibbs } 20144873663cSMatt Jacob splx(s); 2015d720e6d5SJustin T. Gibbs } else { 2016d720e6d5SJustin T. Gibbs /* Pointer to physical buffer */ 2017d720e6d5SJustin T. Gibbs struct bus_dma_segment seg; 20186de9bf77SMatt Jacob seg.ds_addr = (bus_addr_t)(vm_offset_t)csio->data_ptr; 2019d720e6d5SJustin T. Gibbs seg.ds_len = csio->dxfer_len; 20209e11e5beSMatt Jacob (*eptr)(mp, &seg, 1, 0); 2021d720e6d5SJustin T. Gibbs } 2022d720e6d5SJustin T. Gibbs } else { 2023d720e6d5SJustin T. Gibbs struct bus_dma_segment *segs; 2024d720e6d5SJustin T. Gibbs 20259e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DATA_PHYS) != 0) { 2026f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 2027f7dddf8aSMatt Jacob "Physical segment pointers unsupported"); 2028d720e6d5SJustin T. Gibbs mp->error = EINVAL; 20299e11e5beSMatt Jacob } else if ((csio->ccb_h.flags & CAM_SG_LIST_PHYS) == 0) { 2030f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 2031f7dddf8aSMatt Jacob "Virtual segment addresses unsupported"); 2032d720e6d5SJustin T. Gibbs mp->error = EINVAL; 2033d720e6d5SJustin T. Gibbs } else { 2034d720e6d5SJustin T. Gibbs /* Just use the segments provided */ 2035d720e6d5SJustin T. Gibbs segs = (struct bus_dma_segment *) csio->data_ptr; 20369e11e5beSMatt Jacob (*eptr)(mp, segs, csio->sglist_cnt, 0); 2037d720e6d5SJustin T. Gibbs } 2038d720e6d5SJustin T. Gibbs } 2039d720e6d5SJustin T. Gibbs if (mp->error) { 20404873663cSMatt Jacob int retval = CMD_COMPLETE; 20414873663cSMatt Jacob if (mp->error == MUSHERR_NOQENTRIES) { 20424873663cSMatt Jacob retval = CMD_EAGAIN; 20434873663cSMatt Jacob } else if (mp->error == EFBIG) { 20440a5f7e8bSMatt Jacob XS_SETERR(csio, CAM_REQ_TOO_BIG); 2045d720e6d5SJustin T. Gibbs } else if (mp->error == EINVAL) { 20460a5f7e8bSMatt Jacob XS_SETERR(csio, CAM_REQ_INVALID); 2047d720e6d5SJustin T. Gibbs } else { 20480a5f7e8bSMatt Jacob XS_SETERR(csio, CAM_UNREC_HBA_ERROR); 2049d720e6d5SJustin T. Gibbs } 20504873663cSMatt Jacob return (retval); 20510a5f7e8bSMatt Jacob } 20524fd13c1bSMatt Jacob mbxsync: 20534fd13c1bSMatt Jacob switch (rq->req_header.rqs_entry_type) { 20544fd13c1bSMatt Jacob case RQSTYPE_REQUEST: 20554fd13c1bSMatt Jacob isp_put_request(isp, rq, qep); 20564fd13c1bSMatt Jacob break; 20574fd13c1bSMatt Jacob case RQSTYPE_CMDONLY: 20584fd13c1bSMatt Jacob isp_put_extended_request(isp, (ispextreq_t *)rq, 20594fd13c1bSMatt Jacob (ispextreq_t *)qep); 20604fd13c1bSMatt Jacob break; 20614fd13c1bSMatt Jacob case RQSTYPE_T2RQS: 20624fd13c1bSMatt Jacob isp_put_request_t2(isp, (ispreqt2_t *) rq, (ispreqt2_t *) qep); 20634fd13c1bSMatt Jacob break; 20646de9bf77SMatt Jacob case RQSTYPE_A64: 20656de9bf77SMatt Jacob case RQSTYPE_T3RQS: 20666de9bf77SMatt Jacob isp_put_request_t3(isp, (ispreqt3_t *) rq, (ispreqt3_t *) qep); 20676de9bf77SMatt Jacob break; 20680a5f7e8bSMatt Jacob } 20694873663cSMatt Jacob return (CMD_QUEUED); 2070d720e6d5SJustin T. Gibbs } 2071d720e6d5SJustin T. Gibbs 2072d720e6d5SJustin T. Gibbs static void 20731dae40ebSMatt Jacob isp_pci_dmateardown(struct ispsoftc *isp, XS_T *xs, uint16_t handle) 2074d720e6d5SJustin T. Gibbs { 20751923f739SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *)isp; 20761923f739SMatt Jacob bus_dmamap_t *dp = &pcs->dmaps[isp_handle_index(handle)]; 2077a95ae193SMatt Jacob if ((xs->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 20781923f739SMatt Jacob bus_dmamap_sync(pcs->dmat, *dp, BUS_DMASYNC_POSTREAD); 2079d720e6d5SJustin T. Gibbs } else { 20801923f739SMatt Jacob bus_dmamap_sync(pcs->dmat, *dp, BUS_DMASYNC_POSTWRITE); 2081d720e6d5SJustin T. Gibbs } 20821923f739SMatt Jacob bus_dmamap_unload(pcs->dmat, *dp); 2083d720e6d5SJustin T. Gibbs } 2084d720e6d5SJustin T. Gibbs 208565adb54cSMatt Jacob 208665adb54cSMatt Jacob static void 208717e318c6SMatt Jacob isp_pci_reset1(struct ispsoftc *isp) 208865adb54cSMatt Jacob { 208965adb54cSMatt Jacob /* Make sure the BIOS is disabled */ 209065adb54cSMatt Jacob isp_pci_wr_reg(isp, HCCR, PCI_HCCR_CMD_BIOS); 2091469b6b9eSMatt Jacob /* and enable interrupts */ 2092469b6b9eSMatt Jacob ENABLE_INTS(isp); 209365adb54cSMatt Jacob } 209465adb54cSMatt Jacob 209565adb54cSMatt Jacob static void 2096d02373f1SMatt Jacob isp_pci_dumpregs(struct ispsoftc *isp, const char *msg) 209765adb54cSMatt Jacob { 20981923f739SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *)isp; 2099d02373f1SMatt Jacob if (msg) 21006e5c5328SMatt Jacob printf("%s: %s\n", device_get_nameunit(isp->isp_dev), msg); 21016e5c5328SMatt Jacob else 21026e5c5328SMatt Jacob printf("%s:\n", device_get_nameunit(isp->isp_dev)); 2103d02373f1SMatt Jacob if (IS_SCSI(isp)) 2104d02373f1SMatt Jacob printf(" biu_conf1=%x", ISP_READ(isp, BIU_CONF1)); 2105d02373f1SMatt Jacob else 2106d02373f1SMatt Jacob printf(" biu_csr=%x", ISP_READ(isp, BIU2100_CSR)); 2107d02373f1SMatt Jacob printf(" biu_icr=%x biu_isr=%x biu_sema=%x ", ISP_READ(isp, BIU_ICR), 2108d02373f1SMatt Jacob ISP_READ(isp, BIU_ISR), ISP_READ(isp, BIU_SEMA)); 2109d02373f1SMatt Jacob printf("risc_hccr=%x\n", ISP_READ(isp, HCCR)); 2110d02373f1SMatt Jacob 2111d02373f1SMatt Jacob 2112d02373f1SMatt Jacob if (IS_SCSI(isp)) { 2113d02373f1SMatt Jacob ISP_WRITE(isp, HCCR, HCCR_CMD_PAUSE); 2114d02373f1SMatt Jacob printf(" cdma_conf=%x cdma_sts=%x cdma_fifostat=%x\n", 2115d02373f1SMatt Jacob ISP_READ(isp, CDMA_CONF), ISP_READ(isp, CDMA_STATUS), 2116d02373f1SMatt Jacob ISP_READ(isp, CDMA_FIFO_STS)); 2117d02373f1SMatt Jacob printf(" ddma_conf=%x ddma_sts=%x ddma_fifostat=%x\n", 2118d02373f1SMatt Jacob ISP_READ(isp, DDMA_CONF), ISP_READ(isp, DDMA_STATUS), 2119d02373f1SMatt Jacob ISP_READ(isp, DDMA_FIFO_STS)); 2120d02373f1SMatt Jacob printf(" sxp_int=%x sxp_gross=%x sxp(scsi_ctrl)=%x\n", 2121d02373f1SMatt Jacob ISP_READ(isp, SXP_INTERRUPT), 2122d02373f1SMatt Jacob ISP_READ(isp, SXP_GROSS_ERR), 2123d02373f1SMatt Jacob ISP_READ(isp, SXP_PINS_CTRL)); 2124d02373f1SMatt Jacob ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE); 2125d02373f1SMatt Jacob } 2126d02373f1SMatt Jacob printf(" mbox regs: %x %x %x %x %x\n", 2127d02373f1SMatt Jacob ISP_READ(isp, OUTMAILBOX0), ISP_READ(isp, OUTMAILBOX1), 2128d02373f1SMatt Jacob ISP_READ(isp, OUTMAILBOX2), ISP_READ(isp, OUTMAILBOX3), 2129d02373f1SMatt Jacob ISP_READ(isp, OUTMAILBOX4)); 2130d02373f1SMatt Jacob printf(" PCI Status Command/Status=%x\n", 21311923f739SMatt Jacob pci_read_config(pcs->pci_dev, PCIR_COMMAND, 1)); 213265adb54cSMatt Jacob } 2133