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> 399cd7268eSMatt Jacob #if __FreeBSD_version < 500000 409cd7268eSMatt Jacob #include <sys/bus.h> 419cd7268eSMatt Jacob #include <pci/pcireg.h> 429cd7268eSMatt Jacob #include <pci/pcivar.h> 439cd7268eSMatt Jacob #include <machine/bus_memio.h> 449cd7268eSMatt Jacob #include <machine/bus_pio.h> 459cd7268eSMatt Jacob #else 4674a96f43SJohn Baldwin #include <sys/stdint.h> 4777e6a3b2SWarner Losh #include <dev/pci/pcireg.h> 4877e6a3b2SWarner Losh #include <dev/pci/pcivar.h> 499cd7268eSMatt Jacob #endif 50d720e6d5SJustin T. Gibbs #include <machine/bus.h> 51960f6939SMatt Jacob #include <machine/resource.h> 52960f6939SMatt Jacob #include <sys/rman.h> 53960f6939SMatt Jacob #include <sys/malloc.h> 54960f6939SMatt Jacob 55960f6939SMatt Jacob #include <dev/isp/isp_freebsd.h> 56d59bd469SMatt Jacob 579cd7268eSMatt Jacob #if __FreeBSD_version < 500000 589cd7268eSMatt Jacob #define BUS_PROBE_DEFAULT 0 599cd7268eSMatt Jacob #endif 6065adb54cSMatt Jacob 619cd7268eSMatt Jacob static uint16_t isp_pci_rd_reg(ispsoftc_t *, int); 629cd7268eSMatt Jacob static void isp_pci_wr_reg(ispsoftc_t *, int, uint16_t); 639cd7268eSMatt Jacob static uint16_t isp_pci_rd_reg_1080(ispsoftc_t *, int); 649cd7268eSMatt Jacob static void isp_pci_wr_reg_1080(ispsoftc_t *, int, uint16_t); 659cd7268eSMatt Jacob static int 669cd7268eSMatt Jacob isp_pci_rd_isr(ispsoftc_t *, uint16_t *, uint16_t *, uint16_t *); 679cd7268eSMatt Jacob static int 689cd7268eSMatt Jacob isp_pci_rd_isr_2300(ispsoftc_t *, uint16_t *, uint16_t *, uint16_t *); 699cd7268eSMatt Jacob static int isp_pci_mbxdma(ispsoftc_t *); 709cd7268eSMatt Jacob static int 719cd7268eSMatt Jacob isp_pci_dmasetup(ispsoftc_t *, XS_T *, ispreq_t *, uint16_t *, uint16_t); 729cd7268eSMatt Jacob static void 739cd7268eSMatt Jacob isp_pci_dmateardown(ispsoftc_t *, XS_T *, uint16_t); 749cd7268eSMatt Jacob 759cd7268eSMatt Jacob static void isp_pci_reset1(ispsoftc_t *); 769cd7268eSMatt Jacob static void isp_pci_dumpregs(ispsoftc_t *, const char *); 7765adb54cSMatt Jacob 7865adb54cSMatt Jacob static struct ispmdvec mdvec = { 79126ec864SMatt Jacob isp_pci_rd_isr, 8065adb54cSMatt Jacob isp_pci_rd_reg, 8165adb54cSMatt Jacob isp_pci_wr_reg, 8265adb54cSMatt Jacob isp_pci_mbxdma, 8365adb54cSMatt Jacob isp_pci_dmasetup, 84d720e6d5SJustin T. Gibbs isp_pci_dmateardown, 8565adb54cSMatt Jacob NULL, 8665adb54cSMatt Jacob isp_pci_reset1, 8765adb54cSMatt Jacob isp_pci_dumpregs, 8856aef503SMatt Jacob NULL, 89d02373f1SMatt Jacob BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64 9065adb54cSMatt Jacob }; 9165adb54cSMatt Jacob 92d59bd469SMatt Jacob static struct ispmdvec mdvec_1080 = { 93126ec864SMatt Jacob isp_pci_rd_isr, 94d59bd469SMatt Jacob isp_pci_rd_reg_1080, 95d59bd469SMatt Jacob isp_pci_wr_reg_1080, 96d59bd469SMatt Jacob isp_pci_mbxdma, 97d59bd469SMatt Jacob isp_pci_dmasetup, 98d59bd469SMatt Jacob isp_pci_dmateardown, 99d59bd469SMatt Jacob NULL, 100d59bd469SMatt Jacob isp_pci_reset1, 101d59bd469SMatt Jacob isp_pci_dumpregs, 10256aef503SMatt Jacob NULL, 103d02373f1SMatt Jacob BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64 104d59bd469SMatt Jacob }; 105d59bd469SMatt Jacob 106960f6939SMatt Jacob static struct ispmdvec mdvec_12160 = { 107126ec864SMatt Jacob isp_pci_rd_isr, 108960f6939SMatt Jacob isp_pci_rd_reg_1080, 109960f6939SMatt Jacob isp_pci_wr_reg_1080, 110960f6939SMatt Jacob isp_pci_mbxdma, 111960f6939SMatt Jacob isp_pci_dmasetup, 112960f6939SMatt Jacob isp_pci_dmateardown, 113960f6939SMatt Jacob NULL, 114960f6939SMatt Jacob isp_pci_reset1, 115960f6939SMatt Jacob isp_pci_dumpregs, 11656aef503SMatt Jacob NULL, 117d02373f1SMatt Jacob BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64 118960f6939SMatt Jacob }; 119960f6939SMatt Jacob 12065adb54cSMatt Jacob static struct ispmdvec mdvec_2100 = { 121126ec864SMatt Jacob isp_pci_rd_isr, 12265adb54cSMatt Jacob isp_pci_rd_reg, 12365adb54cSMatt Jacob isp_pci_wr_reg, 12465adb54cSMatt Jacob isp_pci_mbxdma, 12565adb54cSMatt Jacob isp_pci_dmasetup, 126d720e6d5SJustin T. Gibbs isp_pci_dmateardown, 12765adb54cSMatt Jacob NULL, 12865adb54cSMatt Jacob isp_pci_reset1, 129d02373f1SMatt Jacob isp_pci_dumpregs 13065adb54cSMatt Jacob }; 131222bb542SMatt Jacob 132222bb542SMatt Jacob static struct ispmdvec mdvec_2200 = { 133126ec864SMatt Jacob isp_pci_rd_isr, 134126ec864SMatt Jacob isp_pci_rd_reg, 135126ec864SMatt Jacob isp_pci_wr_reg, 136126ec864SMatt Jacob isp_pci_mbxdma, 137126ec864SMatt Jacob isp_pci_dmasetup, 138126ec864SMatt Jacob isp_pci_dmateardown, 139126ec864SMatt Jacob NULL, 140126ec864SMatt Jacob isp_pci_reset1, 141126ec864SMatt Jacob isp_pci_dumpregs 142126ec864SMatt Jacob }; 143126ec864SMatt Jacob 144126ec864SMatt Jacob static struct ispmdvec mdvec_2300 = { 145126ec864SMatt Jacob isp_pci_rd_isr_2300, 146222bb542SMatt Jacob isp_pci_rd_reg, 147222bb542SMatt Jacob isp_pci_wr_reg, 148222bb542SMatt Jacob isp_pci_mbxdma, 149222bb542SMatt Jacob isp_pci_dmasetup, 150222bb542SMatt Jacob isp_pci_dmateardown, 151222bb542SMatt Jacob NULL, 152222bb542SMatt Jacob isp_pci_reset1, 153d02373f1SMatt Jacob isp_pci_dumpregs 154222bb542SMatt Jacob }; 155d951bbcaSMatt Jacob 15665adb54cSMatt Jacob #ifndef PCIM_CMD_INVEN 15765adb54cSMatt Jacob #define PCIM_CMD_INVEN 0x10 15865adb54cSMatt Jacob #endif 15965adb54cSMatt Jacob #ifndef PCIM_CMD_BUSMASTEREN 16065adb54cSMatt Jacob #define PCIM_CMD_BUSMASTEREN 0x0004 16165adb54cSMatt Jacob #endif 162d951bbcaSMatt Jacob #ifndef PCIM_CMD_PERRESPEN 163d951bbcaSMatt Jacob #define PCIM_CMD_PERRESPEN 0x0040 164d951bbcaSMatt Jacob #endif 165d951bbcaSMatt Jacob #ifndef PCIM_CMD_SEREN 166d951bbcaSMatt Jacob #define PCIM_CMD_SEREN 0x0100 167d951bbcaSMatt Jacob #endif 168d951bbcaSMatt Jacob 169d951bbcaSMatt Jacob #ifndef PCIR_COMMAND 170d951bbcaSMatt Jacob #define PCIR_COMMAND 0x04 171d951bbcaSMatt Jacob #endif 172d951bbcaSMatt Jacob 173d951bbcaSMatt Jacob #ifndef PCIR_CACHELNSZ 174d951bbcaSMatt Jacob #define PCIR_CACHELNSZ 0x0c 175d951bbcaSMatt Jacob #endif 176d951bbcaSMatt Jacob 177d951bbcaSMatt Jacob #ifndef PCIR_LATTIMER 178d951bbcaSMatt Jacob #define PCIR_LATTIMER 0x0d 179d951bbcaSMatt Jacob #endif 180d951bbcaSMatt Jacob 181ab6d0040SMatt Jacob #ifndef PCIR_ROMADDR 182ab6d0040SMatt Jacob #define PCIR_ROMADDR 0x30 183ab6d0040SMatt Jacob #endif 184ab6d0040SMatt Jacob 18565adb54cSMatt Jacob #ifndef PCI_VENDOR_QLOGIC 18665adb54cSMatt Jacob #define PCI_VENDOR_QLOGIC 0x1077 18765adb54cSMatt Jacob #endif 18865adb54cSMatt Jacob 18965adb54cSMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP1020 19065adb54cSMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP1020 0x1020 19165adb54cSMatt Jacob #endif 19265adb54cSMatt Jacob 193d59bd469SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP1080 194d59bd469SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP1080 0x1080 195d59bd469SMatt Jacob #endif 196d59bd469SMatt Jacob 197f556e83bSMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP10160 198f556e83bSMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP10160 0x1016 199f556e83bSMatt Jacob #endif 200f556e83bSMatt Jacob 201960f6939SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP12160 202960f6939SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP12160 0x1216 203960f6939SMatt Jacob #endif 204960f6939SMatt Jacob 205d59bd469SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP1240 206d59bd469SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP1240 0x1240 207d59bd469SMatt Jacob #endif 20865adb54cSMatt Jacob 20922e1dc85SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP1280 21022e1dc85SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP1280 0x1280 21122e1dc85SMatt Jacob #endif 21222e1dc85SMatt Jacob 21365adb54cSMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP2100 21465adb54cSMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP2100 0x2100 21565adb54cSMatt Jacob #endif 21665adb54cSMatt Jacob 217222bb542SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP2200 218222bb542SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP2200 0x2200 219222bb542SMatt Jacob #endif 220222bb542SMatt Jacob 221126ec864SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP2300 222126ec864SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP2300 0x2300 223126ec864SMatt Jacob #endif 224126ec864SMatt Jacob 225126ec864SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP2312 226126ec864SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP2312 0x2312 227126ec864SMatt Jacob #endif 228126ec864SMatt Jacob 229e5265237SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP2322 230e5265237SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP2322 0x2322 231e5265237SMatt Jacob #endif 232e5265237SMatt Jacob 2338872e3d7SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP2422 2348872e3d7SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP2422 0x2422 2358872e3d7SMatt Jacob #endif 2368872e3d7SMatt Jacob 237dd1419abSMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP6312 238dd1419abSMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP6312 0x6312 239dd1419abSMatt Jacob #endif 240dd1419abSMatt Jacob 24156aef503SMatt Jacob #define PCI_QLOGIC_ISP1020 \ 24256aef503SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP1020 << 16) | PCI_VENDOR_QLOGIC) 243d59bd469SMatt Jacob 244d59bd469SMatt Jacob #define PCI_QLOGIC_ISP1080 \ 245d59bd469SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP1080 << 16) | PCI_VENDOR_QLOGIC) 246d59bd469SMatt Jacob 247f556e83bSMatt Jacob #define PCI_QLOGIC_ISP10160 \ 248f556e83bSMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP10160 << 16) | PCI_VENDOR_QLOGIC) 249f556e83bSMatt Jacob 250960f6939SMatt Jacob #define PCI_QLOGIC_ISP12160 \ 251960f6939SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP12160 << 16) | PCI_VENDOR_QLOGIC) 252960f6939SMatt Jacob 253d59bd469SMatt Jacob #define PCI_QLOGIC_ISP1240 \ 254d59bd469SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP1240 << 16) | PCI_VENDOR_QLOGIC) 255d59bd469SMatt Jacob 25622e1dc85SMatt Jacob #define PCI_QLOGIC_ISP1280 \ 25722e1dc85SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP1280 << 16) | PCI_VENDOR_QLOGIC) 25822e1dc85SMatt Jacob 25965adb54cSMatt Jacob #define PCI_QLOGIC_ISP2100 \ 26065adb54cSMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP2100 << 16) | PCI_VENDOR_QLOGIC) 26165adb54cSMatt Jacob 262222bb542SMatt Jacob #define PCI_QLOGIC_ISP2200 \ 263222bb542SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP2200 << 16) | PCI_VENDOR_QLOGIC) 264222bb542SMatt Jacob 265126ec864SMatt Jacob #define PCI_QLOGIC_ISP2300 \ 266126ec864SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP2300 << 16) | PCI_VENDOR_QLOGIC) 267126ec864SMatt Jacob 268126ec864SMatt Jacob #define PCI_QLOGIC_ISP2312 \ 269126ec864SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP2312 << 16) | PCI_VENDOR_QLOGIC) 270126ec864SMatt Jacob 271e5265237SMatt Jacob #define PCI_QLOGIC_ISP2322 \ 272e5265237SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP2322 << 16) | PCI_VENDOR_QLOGIC) 273e5265237SMatt Jacob 2746c426685SMatt Jacob #define PCI_QLOGIC_ISP2422 \ 2756c426685SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP2422 << 16) | PCI_VENDOR_QLOGIC) 2766c426685SMatt Jacob 277dd1419abSMatt Jacob #define PCI_QLOGIC_ISP6312 \ 278dd1419abSMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP6312 << 16) | PCI_VENDOR_QLOGIC) 279dd1419abSMatt Jacob 280e11a1ee8SMatt Jacob /* 281e11a1ee8SMatt Jacob * Odd case for some AMI raid cards... We need to *not* attach to this. 282e11a1ee8SMatt Jacob */ 283e11a1ee8SMatt Jacob #define AMI_RAID_SUBVENDOR_ID 0x101e 284e11a1ee8SMatt Jacob 28565adb54cSMatt Jacob #define IO_MAP_REG 0x10 28665adb54cSMatt Jacob #define MEM_MAP_REG 0x14 28765adb54cSMatt Jacob 288d951bbcaSMatt Jacob #define PCI_DFLT_LTNCY 0x40 289d951bbcaSMatt Jacob #define PCI_DFLT_LNSZ 0x10 29065adb54cSMatt Jacob 291960f6939SMatt Jacob static int isp_pci_probe (device_t); 292960f6939SMatt Jacob static int isp_pci_attach (device_t); 29365adb54cSMatt Jacob 2941923f739SMatt Jacob 29565adb54cSMatt Jacob struct isp_pcisoftc { 2969cd7268eSMatt Jacob ispsoftc_t pci_isp; 297960f6939SMatt Jacob device_t pci_dev; 298960f6939SMatt Jacob struct resource * pci_reg; 29965adb54cSMatt Jacob bus_space_tag_t pci_st; 30065adb54cSMatt Jacob bus_space_handle_t pci_sh; 301960f6939SMatt Jacob void * ih; 302d59bd469SMatt Jacob int16_t pci_poff[_NREG_BLKS]; 3031923f739SMatt Jacob bus_dma_tag_t dmat; 304a95ae193SMatt Jacob bus_dmamap_t *dmaps; 30565adb54cSMatt Jacob }; 30673030e03SMatt Jacob extern ispfwfunc *isp_get_firmware_p; 30765adb54cSMatt Jacob 308960f6939SMatt Jacob static device_method_t isp_pci_methods[] = { 309960f6939SMatt Jacob /* Device interface */ 310960f6939SMatt Jacob DEVMETHOD(device_probe, isp_pci_probe), 311960f6939SMatt Jacob DEVMETHOD(device_attach, isp_pci_attach), 312960f6939SMatt Jacob { 0, 0 } 31365adb54cSMatt Jacob }; 314126ec864SMatt Jacob static void isp_pci_intr(void *); 31565adb54cSMatt Jacob 316960f6939SMatt Jacob static driver_t isp_pci_driver = { 317960f6939SMatt Jacob "isp", isp_pci_methods, sizeof (struct isp_pcisoftc) 318960f6939SMatt Jacob }; 319960f6939SMatt Jacob static devclass_t isp_devclass; 320960f6939SMatt Jacob DRIVER_MODULE(isp, pci, isp_pci_driver, isp_devclass, 0, 0); 32165adb54cSMatt Jacob 322960f6939SMatt Jacob static int 323960f6939SMatt Jacob isp_pci_probe(device_t dev) 32465adb54cSMatt Jacob { 325960f6939SMatt Jacob switch ((pci_get_device(dev) << 16) | (pci_get_vendor(dev))) { 32656aef503SMatt Jacob case PCI_QLOGIC_ISP1020: 327960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 1020/1040 PCI SCSI Adapter"); 32865adb54cSMatt Jacob break; 329d59bd469SMatt Jacob case PCI_QLOGIC_ISP1080: 330960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 1080 PCI SCSI Adapter"); 331c6608df3SMatt Jacob break; 332c6608df3SMatt Jacob case PCI_QLOGIC_ISP1240: 333960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 1240 PCI SCSI Adapter"); 334d59bd469SMatt Jacob break; 33522e1dc85SMatt Jacob case PCI_QLOGIC_ISP1280: 336960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 1280 PCI SCSI Adapter"); 337960f6939SMatt Jacob break; 338f556e83bSMatt Jacob case PCI_QLOGIC_ISP10160: 339f556e83bSMatt Jacob device_set_desc(dev, "Qlogic ISP 10160 PCI SCSI Adapter"); 340f556e83bSMatt Jacob break; 341960f6939SMatt Jacob case PCI_QLOGIC_ISP12160: 342e11a1ee8SMatt Jacob if (pci_get_subvendor(dev) == AMI_RAID_SUBVENDOR_ID) { 343e11a1ee8SMatt Jacob return (ENXIO); 344e11a1ee8SMatt Jacob } 345960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 12160 PCI SCSI Adapter"); 34622e1dc85SMatt Jacob break; 34765adb54cSMatt Jacob case PCI_QLOGIC_ISP2100: 348960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 2100 PCI FC-AL Adapter"); 34965adb54cSMatt Jacob break; 3505542fe4bSMatt Jacob case PCI_QLOGIC_ISP2200: 351960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 2200 PCI FC-AL Adapter"); 3525542fe4bSMatt Jacob break; 353126ec864SMatt Jacob case PCI_QLOGIC_ISP2300: 354126ec864SMatt Jacob device_set_desc(dev, "Qlogic ISP 2300 PCI FC-AL Adapter"); 355126ec864SMatt Jacob break; 356126ec864SMatt Jacob case PCI_QLOGIC_ISP2312: 357126ec864SMatt Jacob device_set_desc(dev, "Qlogic ISP 2312 PCI FC-AL Adapter"); 358126ec864SMatt Jacob break; 359e5265237SMatt Jacob case PCI_QLOGIC_ISP2322: 360e5265237SMatt Jacob device_set_desc(dev, "Qlogic ISP 2322 PCI FC-AL Adapter"); 361e5265237SMatt Jacob break; 3628872e3d7SMatt Jacob case PCI_QLOGIC_ISP2422: 3638872e3d7SMatt Jacob device_set_desc(dev, "Qlogic ISP 2422 PCI FC-AL Adapter"); 3648872e3d7SMatt Jacob break; 365dd1419abSMatt Jacob case PCI_QLOGIC_ISP6312: 366dd1419abSMatt Jacob device_set_desc(dev, "Qlogic ISP 6312 PCI FC-AL Adapter"); 367dd1419abSMatt Jacob break; 36865adb54cSMatt Jacob default: 369960f6939SMatt Jacob return (ENXIO); 37065adb54cSMatt Jacob } 37173030e03SMatt Jacob if (isp_announced == 0 && bootverbose) { 372d02373f1SMatt Jacob printf("Qlogic ISP Driver, FreeBSD Version %d.%d, " 373a95ae193SMatt Jacob "Core Version %d.%d\n", 374d720e6d5SJustin T. Gibbs ISP_PLATFORM_VERSION_MAJOR, ISP_PLATFORM_VERSION_MINOR, 375d720e6d5SJustin T. Gibbs ISP_CORE_VERSION_MAJOR, ISP_CORE_VERSION_MINOR); 37673030e03SMatt Jacob isp_announced++; 37765adb54cSMatt Jacob } 37856aef503SMatt Jacob /* 37956aef503SMatt Jacob * XXXX: Here is where we might load the f/w module 38056aef503SMatt Jacob * XXXX: (or increase a reference count to it). 38156aef503SMatt Jacob */ 382b77e575eSWarner Losh return (BUS_PROBE_DEFAULT); 38365adb54cSMatt Jacob } 38465adb54cSMatt Jacob 3859cd7268eSMatt Jacob #if __FreeBSD_version < 500000 3869cd7268eSMatt Jacob static void 3879cd7268eSMatt Jacob isp_get_options(device_t dev, ispsoftc_t *isp) 38865adb54cSMatt Jacob { 3899cd7268eSMatt Jacob uint64_t wwn; 3909cd7268eSMatt Jacob int bitmap, unit; 39165adb54cSMatt Jacob 3929cd7268eSMatt Jacob unit = device_get_unit(dev); 3939cd7268eSMatt Jacob if (getenv_int("isp_disable", &bitmap)) { 3949cd7268eSMatt Jacob if (bitmap & (1 << unit)) { 3959cd7268eSMatt Jacob isp->isp_osinfo.disabled = 1; 3969cd7268eSMatt Jacob return; 3979cd7268eSMatt Jacob } 3989cd7268eSMatt Jacob } 3999cd7268eSMatt Jacob 4009cd7268eSMatt Jacob if (getenv_int("isp_no_fwload", &bitmap)) { 4019cd7268eSMatt Jacob if (bitmap & (1 << unit)) 4029cd7268eSMatt Jacob isp->isp_confopts |= ISP_CFG_NORELOAD; 4039cd7268eSMatt Jacob } 4049cd7268eSMatt Jacob if (getenv_int("isp_fwload", &bitmap)) { 4059cd7268eSMatt Jacob if (bitmap & (1 << unit)) 4069cd7268eSMatt Jacob isp->isp_confopts &= ~ISP_CFG_NORELOAD; 4079cd7268eSMatt Jacob } 4089cd7268eSMatt Jacob if (getenv_int("isp_no_nvram", &bitmap)) { 4099cd7268eSMatt Jacob if (bitmap & (1 << unit)) 4109cd7268eSMatt Jacob isp->isp_confopts |= ISP_CFG_NONVRAM; 4119cd7268eSMatt Jacob } 4129cd7268eSMatt Jacob if (getenv_int("isp_nvram", &bitmap)) { 4139cd7268eSMatt Jacob if (bitmap & (1 << unit)) 4149cd7268eSMatt Jacob isp->isp_confopts &= ~ISP_CFG_NONVRAM; 4159cd7268eSMatt Jacob } 4169cd7268eSMatt Jacob if (getenv_int("isp_fcduplex", &bitmap)) { 4179cd7268eSMatt Jacob if (bitmap & (1 << unit)) 4189cd7268eSMatt Jacob isp->isp_confopts |= ISP_CFG_FULL_DUPLEX; 4199cd7268eSMatt Jacob } 4209cd7268eSMatt Jacob if (getenv_int("isp_no_fcduplex", &bitmap)) { 4219cd7268eSMatt Jacob if (bitmap & (1 << unit)) 4229cd7268eSMatt Jacob isp->isp_confopts &= ~ISP_CFG_FULL_DUPLEX; 4239cd7268eSMatt Jacob } 4249cd7268eSMatt Jacob if (getenv_int("isp_nport", &bitmap)) { 4259cd7268eSMatt Jacob if (bitmap & (1 << unit)) 4269cd7268eSMatt Jacob isp->isp_confopts |= ISP_CFG_NPORT; 4279cd7268eSMatt Jacob } 4289cd7268eSMatt Jacob 4299cd7268eSMatt Jacob /* 4309cd7268eSMatt Jacob * Because the resource_*_value functions can neither return 4319cd7268eSMatt Jacob * 64 bit integer values, nor can they be directly coerced 4329cd7268eSMatt Jacob * to interpret the right hand side of the assignment as 4339cd7268eSMatt Jacob * you want them to interpret it, we have to force WWN 4349cd7268eSMatt Jacob * hint replacement to specify WWN strings with a leading 4359cd7268eSMatt Jacob * 'w' (e..g w50000000aaaa0001). Sigh. 4369cd7268eSMatt Jacob */ 4379cd7268eSMatt Jacob if (getenv_quad("isp_portwwn", &wwn)) { 4389cd7268eSMatt Jacob isp->isp_osinfo.default_port_wwn = wwn; 4399cd7268eSMatt Jacob isp->isp_confopts |= ISP_CFG_OWNWWPN; 4409cd7268eSMatt Jacob } 4419cd7268eSMatt Jacob if (isp->isp_osinfo.default_port_wwn == 0) { 4429cd7268eSMatt Jacob isp->isp_osinfo.default_port_wwn = 0x400000007F000009ull; 4439cd7268eSMatt Jacob } 4449cd7268eSMatt Jacob 4459cd7268eSMatt Jacob if (getenv_quad("isp_nodewwn", &wwn)) { 4469cd7268eSMatt Jacob isp->isp_osinfo.default_node_wwn = wwn; 4479cd7268eSMatt Jacob isp->isp_confopts |= ISP_CFG_OWNWWNN; 4489cd7268eSMatt Jacob } 4499cd7268eSMatt Jacob if (isp->isp_osinfo.default_node_wwn == 0) { 4509cd7268eSMatt Jacob isp->isp_osinfo.default_node_wwn = 0x400000007F000009ull; 4519cd7268eSMatt Jacob } 4529cd7268eSMatt Jacob 4539cd7268eSMatt Jacob bitmap = 0; 4549cd7268eSMatt Jacob (void) getenv_int("isp_debug", &bitmap); 4559cd7268eSMatt Jacob if (bitmap) { 4569cd7268eSMatt Jacob isp->isp_dblev = bitmap; 4579cd7268eSMatt Jacob } else { 4589cd7268eSMatt Jacob isp->isp_dblev = ISP_LOGWARN|ISP_LOGERR; 4599cd7268eSMatt Jacob } 4609cd7268eSMatt Jacob if (bootverbose) { 4619cd7268eSMatt Jacob isp->isp_dblev |= ISP_LOGCONFIG|ISP_LOGINFO; 4629cd7268eSMatt Jacob } 4639cd7268eSMatt Jacob 4649cd7268eSMatt Jacob #ifdef ISP_FW_CRASH_DUMP 4659cd7268eSMatt Jacob bitmap = 0; 4669cd7268eSMatt Jacob if (getenv_int("isp_fw_dump_enable", &bitmap)) { 4679cd7268eSMatt Jacob if (bitmap & (1 << unit) { 4689cd7268eSMatt Jacob size_t amt = 0; 4699cd7268eSMatt Jacob if (IS_2200(isp)) { 4709cd7268eSMatt Jacob amt = QLA2200_RISC_IMAGE_DUMP_SIZE; 4719cd7268eSMatt Jacob } else if (IS_23XX(isp)) { 4729cd7268eSMatt Jacob amt = QLA2300_RISC_IMAGE_DUMP_SIZE; 4739cd7268eSMatt Jacob } 4749cd7268eSMatt Jacob if (amt) { 4759cd7268eSMatt Jacob FCPARAM(isp)->isp_dump_data = 4769cd7268eSMatt Jacob malloc(amt, M_DEVBUF, M_WAITOK); 4779cd7268eSMatt Jacob bzero(FCPARAM(isp)->isp_dump_data, amt); 4789cd7268eSMatt Jacob } else { 4799cd7268eSMatt Jacob device_printf(dev, 4809cd7268eSMatt Jacob "f/w crash dumps not supported for card\n"); 4819cd7268eSMatt Jacob } 4829cd7268eSMatt Jacob } 4839cd7268eSMatt Jacob } 4849cd7268eSMatt Jacob #endif 4859cd7268eSMatt Jacob } 4869cd7268eSMatt Jacob 4879cd7268eSMatt Jacob static void 4889cd7268eSMatt Jacob isp_get_pci_options(device_t dev, int *m1, int *m2) 4899cd7268eSMatt Jacob { 4909cd7268eSMatt Jacob int bitmap; 4919cd7268eSMatt Jacob int unit = device_get_unit(dev); 4929cd7268eSMatt Jacob 4939cd7268eSMatt Jacob *m1 = PCIM_CMD_MEMEN; 4949cd7268eSMatt Jacob *m2 = PCIM_CMD_PORTEN; 4959cd7268eSMatt Jacob if (getenv_int("isp_mem_map", &bitmap)) { 4969cd7268eSMatt Jacob if (bitmap & (1 << unit)) { 4979cd7268eSMatt Jacob *m1 = PCIM_CMD_MEMEN; 4989cd7268eSMatt Jacob *m2 = PCIM_CMD_PORTEN; 4999cd7268eSMatt Jacob } 5009cd7268eSMatt Jacob } 5019cd7268eSMatt Jacob bitmap = 0; 5029cd7268eSMatt Jacob if (getenv_int("isp_io_map", &bitmap)) { 5039cd7268eSMatt Jacob if (bitmap & (1 << unit)) { 5049cd7268eSMatt Jacob *m1 = PCIM_CMD_PORTEN; 5059cd7268eSMatt Jacob *m2 = PCIM_CMD_MEMEN; 5069cd7268eSMatt Jacob } 5079cd7268eSMatt Jacob } 5089cd7268eSMatt Jacob } 5099cd7268eSMatt Jacob #else 5109cd7268eSMatt Jacob static void 5119cd7268eSMatt Jacob isp_get_options(device_t dev, ispsoftc_t *isp) 5129cd7268eSMatt Jacob { 5139cd7268eSMatt Jacob int tval; 5149cd7268eSMatt Jacob const char *sptr; 515222bb542SMatt Jacob /* 5169ba86737SMatt Jacob * Figure out if we're supposed to skip this one. 5179ba86737SMatt Jacob */ 5186e5c5328SMatt Jacob 5196e5c5328SMatt Jacob tval = 0; 5206e5c5328SMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 5216e5c5328SMatt Jacob "disable", &tval) == 0 && tval) { 5229cd7268eSMatt Jacob device_printf(dev, "disabled at user request\n"); 5239cd7268eSMatt Jacob isp->isp_osinfo.disabled = 1; 5249cd7268eSMatt Jacob return; 525b9b599feSMatt Jacob } 5266e5c5328SMatt Jacob 5279cd7268eSMatt Jacob tval = -1; 5286e5c5328SMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 5299cd7268eSMatt Jacob "role", &tval) == 0 && tval != -1) { 5309cd7268eSMatt Jacob tval &= (ISP_ROLE_INITIATOR|ISP_ROLE_TARGET); 5319cd7268eSMatt Jacob isp->isp_role = tval; 5329cd7268eSMatt Jacob device_printf(dev, "setting role to 0x%x\n", isp->isp_role); 5336e5c5328SMatt Jacob } else { 534b9b599feSMatt Jacob #ifdef ISP_TARGET_MODE 5359cd7268eSMatt Jacob isp->isp_role = ISP_ROLE_TARGET; 536b9b599feSMatt Jacob #else 5379cd7268eSMatt Jacob isp->isp_role = ISP_DEFAULT_ROLES; 538b9b599feSMatt Jacob #endif 5399ba86737SMatt Jacob } 5409ba86737SMatt Jacob 5419cd7268eSMatt Jacob tval = 0; 5429cd7268eSMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 5439cd7268eSMatt Jacob "fwload_disable", &tval) == 0 && tval != 0) { 5449cd7268eSMatt Jacob isp->isp_confopts |= ISP_CFG_NORELOAD; 5459cd7268eSMatt Jacob } 5469cd7268eSMatt Jacob tval = 0; 5479cd7268eSMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 5489cd7268eSMatt Jacob "ignore_nvram", &tval) == 0 && tval != 0) { 5499cd7268eSMatt Jacob isp->isp_confopts |= ISP_CFG_NONVRAM; 5509cd7268eSMatt Jacob } 5519cd7268eSMatt Jacob tval = 0; 5529cd7268eSMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 5539cd7268eSMatt Jacob "fullduplex", &tval) == 0 && tval != 0) { 5549cd7268eSMatt Jacob isp->isp_confopts |= ISP_CFG_FULL_DUPLEX; 5559cd7268eSMatt Jacob } 5569cd7268eSMatt Jacob #ifdef ISP_FW_CRASH_DUMP 5579cd7268eSMatt Jacob tval = 0; 5589cd7268eSMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 5599cd7268eSMatt Jacob "fw_dump_enable", &tval) == 0 && tval != 0) { 5609cd7268eSMatt Jacob size_t amt = 0; 5619cd7268eSMatt Jacob if (IS_2200(isp)) { 5629cd7268eSMatt Jacob amt = QLA2200_RISC_IMAGE_DUMP_SIZE; 5639cd7268eSMatt Jacob } else if (IS_23XX(isp)) { 5649cd7268eSMatt Jacob amt = QLA2300_RISC_IMAGE_DUMP_SIZE; 5659cd7268eSMatt Jacob } 5669cd7268eSMatt Jacob if (amt) { 5679cd7268eSMatt Jacob FCPARAM(isp)->isp_dump_data = 5689cd7268eSMatt Jacob malloc(amt, M_DEVBUF, M_WAITOK | M_ZERO); 5699cd7268eSMatt Jacob } else { 5709cd7268eSMatt Jacob device_printf(dev, 5719cd7268eSMatt Jacob "f/w crash dumps not supported for this model\n"); 5729cd7268eSMatt Jacob } 5739cd7268eSMatt Jacob } 5749cd7268eSMatt Jacob #endif 5759cd7268eSMatt Jacob 5769cd7268eSMatt Jacob sptr = 0; 5779cd7268eSMatt Jacob if (resource_string_value(device_get_name(dev), device_get_unit(dev), 5789cd7268eSMatt Jacob "topology", (const char **) &sptr) == 0 && sptr != 0) { 5799cd7268eSMatt Jacob if (strcmp(sptr, "lport") == 0) { 5809cd7268eSMatt Jacob isp->isp_confopts |= ISP_CFG_LPORT; 5819cd7268eSMatt Jacob } else if (strcmp(sptr, "nport") == 0) { 5829cd7268eSMatt Jacob isp->isp_confopts |= ISP_CFG_NPORT; 5839cd7268eSMatt Jacob } else if (strcmp(sptr, "lport-only") == 0) { 5849cd7268eSMatt Jacob isp->isp_confopts |= ISP_CFG_LPORT_ONLY; 5859cd7268eSMatt Jacob } else if (strcmp(sptr, "nport-only") == 0) { 5869cd7268eSMatt Jacob isp->isp_confopts |= ISP_CFG_NPORT_ONLY; 5879cd7268eSMatt Jacob } 588960f6939SMatt Jacob } 589960f6939SMatt Jacob 5909ba86737SMatt Jacob /* 5919cd7268eSMatt Jacob * Because the resource_*_value functions can neither return 5929cd7268eSMatt Jacob * 64 bit integer values, nor can they be directly coerced 5939cd7268eSMatt Jacob * to interpret the right hand side of the assignment as 5949cd7268eSMatt Jacob * you want them to interpret it, we have to force WWN 5959cd7268eSMatt Jacob * hint replacement to specify WWN strings with a leading 5969cd7268eSMatt Jacob * 'w' (e..g w50000000aaaa0001). Sigh. 5979cd7268eSMatt Jacob */ 5989cd7268eSMatt Jacob sptr = 0; 5999cd7268eSMatt Jacob tval = resource_string_value(device_get_name(dev), device_get_unit(dev), 6009cd7268eSMatt Jacob "portwwn", (const char **) &sptr); 6019cd7268eSMatt Jacob if (tval == 0 && sptr != 0 && *sptr++ == 'w') { 6029cd7268eSMatt Jacob char *eptr = 0; 6039cd7268eSMatt Jacob isp->isp_osinfo.default_port_wwn = strtouq(sptr, &eptr, 16); 6049cd7268eSMatt Jacob if (eptr < sptr + 16 || isp->isp_osinfo.default_port_wwn == 0) { 6059cd7268eSMatt Jacob device_printf(dev, "mangled portwwn hint '%s'\n", sptr); 6069cd7268eSMatt Jacob isp->isp_osinfo.default_port_wwn = 0; 6079cd7268eSMatt Jacob } else { 6089cd7268eSMatt Jacob isp->isp_confopts |= ISP_CFG_OWNWWPN; 6099cd7268eSMatt Jacob } 6109cd7268eSMatt Jacob } 6119cd7268eSMatt Jacob if (isp->isp_osinfo.default_port_wwn == 0) { 6129cd7268eSMatt Jacob isp->isp_osinfo.default_port_wwn = 0x400000007F000009ull; 6139cd7268eSMatt Jacob } 6149cd7268eSMatt Jacob 6159cd7268eSMatt Jacob sptr = 0; 6169cd7268eSMatt Jacob tval = resource_string_value(device_get_name(dev), device_get_unit(dev), 6179cd7268eSMatt Jacob "nodewwn", (const char **) &sptr); 6189cd7268eSMatt Jacob if (tval == 0 && sptr != 0 && *sptr++ == 'w') { 6199cd7268eSMatt Jacob char *eptr = 0; 6209cd7268eSMatt Jacob isp->isp_osinfo.default_node_wwn = strtouq(sptr, &eptr, 16); 6219cd7268eSMatt Jacob if (eptr < sptr + 16 || isp->isp_osinfo.default_node_wwn == 0) { 6229cd7268eSMatt Jacob device_printf(dev, "mangled nodewwn hint '%s'\n", sptr); 6239cd7268eSMatt Jacob isp->isp_osinfo.default_node_wwn = 0; 6249cd7268eSMatt Jacob } else { 6259cd7268eSMatt Jacob isp->isp_confopts |= ISP_CFG_OWNWWNN; 6269cd7268eSMatt Jacob } 6279cd7268eSMatt Jacob } 6289cd7268eSMatt Jacob if (isp->isp_osinfo.default_node_wwn == 0) { 6299cd7268eSMatt Jacob isp->isp_osinfo.default_node_wwn = 0x400000007F000009ull; 6309cd7268eSMatt Jacob } 6319cd7268eSMatt Jacob 6329cd7268eSMatt Jacob isp->isp_osinfo.default_id = -1; 6339cd7268eSMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 6349cd7268eSMatt Jacob "iid", &tval) == 0) { 6359cd7268eSMatt Jacob isp->isp_osinfo.default_id = tval; 6369cd7268eSMatt Jacob isp->isp_confopts |= ISP_CFG_OWNLOOPID; 6379cd7268eSMatt Jacob } 6389cd7268eSMatt Jacob if (isp->isp_osinfo.default_id == -1) { 6399cd7268eSMatt Jacob if (IS_FC(isp)) { 6409cd7268eSMatt Jacob isp->isp_osinfo.default_id = 109; 6419cd7268eSMatt Jacob } else { 6429cd7268eSMatt Jacob isp->isp_osinfo.default_id = 7; 6439cd7268eSMatt Jacob } 6449cd7268eSMatt Jacob } 6459cd7268eSMatt Jacob 6469cd7268eSMatt Jacob /* 6479cd7268eSMatt Jacob * Set up logging levels. 6489cd7268eSMatt Jacob */ 6499cd7268eSMatt Jacob tval = 0; 6509cd7268eSMatt Jacob (void) resource_int_value(device_get_name(dev), device_get_unit(dev), 6519cd7268eSMatt Jacob "debug", &tval); 6529cd7268eSMatt Jacob if (tval) { 6539cd7268eSMatt Jacob isp->isp_dblev = tval; 6549cd7268eSMatt Jacob } else { 6559cd7268eSMatt Jacob isp->isp_dblev = ISP_LOGWARN|ISP_LOGERR; 6569cd7268eSMatt Jacob } 6579cd7268eSMatt Jacob if (bootverbose) { 6589cd7268eSMatt Jacob isp->isp_dblev |= ISP_LOGCONFIG|ISP_LOGINFO; 6599cd7268eSMatt Jacob } 6609cd7268eSMatt Jacob 6619cd7268eSMatt Jacob } 6629cd7268eSMatt Jacob 6639cd7268eSMatt Jacob static void 6649cd7268eSMatt Jacob isp_get_pci_options(device_t dev, int *m1, int *m2) 6659cd7268eSMatt Jacob { 6669cd7268eSMatt Jacob int tval; 6679cd7268eSMatt Jacob /* 66869767099SMatt Jacob * Which we should try first - memory mapping or i/o mapping? 66969767099SMatt Jacob * 67069767099SMatt Jacob * We used to try memory first followed by i/o on alpha, otherwise 67169767099SMatt Jacob * the reverse, but we should just try memory first all the time now. 672222bb542SMatt Jacob */ 6739cd7268eSMatt Jacob *m1 = PCIM_CMD_MEMEN; 6749cd7268eSMatt Jacob *m2 = PCIM_CMD_PORTEN; 6756e5c5328SMatt Jacob 6766e5c5328SMatt Jacob tval = 0; 6776e5c5328SMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 6786e5c5328SMatt Jacob "prefer_iomap", &tval) == 0 && tval != 0) { 6799cd7268eSMatt Jacob *m1 = PCIM_CMD_PORTEN; 6809cd7268eSMatt Jacob *m2 = PCIM_CMD_MEMEN; 681960f6939SMatt Jacob } 6826e5c5328SMatt Jacob tval = 0; 6836e5c5328SMatt Jacob if (resource_int_value(device_get_name(dev), device_get_unit(dev), 6846e5c5328SMatt Jacob "prefer_memmap", &tval) == 0 && tval != 0) { 6859cd7268eSMatt Jacob *m1 = PCIM_CMD_MEMEN; 6869cd7268eSMatt Jacob *m2 = PCIM_CMD_PORTEN; 687222bb542SMatt Jacob } 6889cd7268eSMatt Jacob } 6899cd7268eSMatt Jacob #endif 6909cd7268eSMatt Jacob 6919cd7268eSMatt Jacob static int 6929cd7268eSMatt Jacob isp_pci_attach(device_t dev) 6939cd7268eSMatt Jacob { 6949cd7268eSMatt Jacob struct resource *regs, *irq; 6959cd7268eSMatt Jacob int rtp, rgd, iqd, m1, m2; 6969cd7268eSMatt Jacob uint32_t data, cmd, linesz, psize, basetype; 6979cd7268eSMatt Jacob struct isp_pcisoftc *pcs; 6989cd7268eSMatt Jacob ispsoftc_t *isp = NULL; 6999cd7268eSMatt Jacob struct ispmdvec *mdvp; 7009cd7268eSMatt Jacob #if __FreeBSD_version >= 500000 7019cd7268eSMatt Jacob int locksetup = 0; 7029cd7268eSMatt Jacob #endif 7039cd7268eSMatt Jacob 7049cd7268eSMatt Jacob pcs = device_get_softc(dev); 7059cd7268eSMatt Jacob if (pcs == NULL) { 7069cd7268eSMatt Jacob device_printf(dev, "cannot get softc\n"); 7079cd7268eSMatt Jacob return (ENOMEM); 7089cd7268eSMatt Jacob } 7099cd7268eSMatt Jacob memset(pcs, 0, sizeof (*pcs)); 7109cd7268eSMatt Jacob pcs->pci_dev = dev; 7119cd7268eSMatt Jacob isp = &pcs->pci_isp; 7129cd7268eSMatt Jacob 7139cd7268eSMatt Jacob /* 7149cd7268eSMatt Jacob * Get Generic Options 7159cd7268eSMatt Jacob */ 7169cd7268eSMatt Jacob isp_get_options(dev, isp); 7179cd7268eSMatt Jacob 7189cd7268eSMatt Jacob /* 7199cd7268eSMatt Jacob * Check to see if options have us disabled 7209cd7268eSMatt Jacob */ 7219cd7268eSMatt Jacob if (isp->isp_osinfo.disabled) { 7229cd7268eSMatt Jacob /* 7239cd7268eSMatt Jacob * But return zero to preserve unit numbering 7249cd7268eSMatt Jacob */ 7259cd7268eSMatt Jacob return (0); 7269cd7268eSMatt Jacob } 7279cd7268eSMatt Jacob 7289cd7268eSMatt Jacob /* 7299cd7268eSMatt Jacob * Get PCI options- which in this case are just mapping preferences. 7309cd7268eSMatt Jacob */ 7319cd7268eSMatt Jacob isp_get_pci_options(dev, &m1, &m2); 7329cd7268eSMatt Jacob 733222bb542SMatt Jacob 734ab6d0040SMatt Jacob linesz = PCI_DFLT_LNSZ; 735960f6939SMatt Jacob irq = regs = NULL; 736960f6939SMatt Jacob rgd = rtp = iqd = 0; 737960f6939SMatt Jacob 738b49c4674SMatt Jacob cmd = pci_read_config(dev, PCIR_COMMAND, 2); 739960f6939SMatt Jacob if (cmd & m1) { 740960f6939SMatt Jacob rtp = (m1 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT; 741960f6939SMatt Jacob rgd = (m1 == PCIM_CMD_MEMEN)? MEM_MAP_REG : IO_MAP_REG; 7425f96beb9SNate Lawson regs = bus_alloc_resource_any(dev, rtp, &rgd, RF_ACTIVE); 74365adb54cSMatt Jacob } 744960f6939SMatt Jacob if (regs == NULL && (cmd & m2)) { 745960f6939SMatt Jacob rtp = (m2 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT; 746960f6939SMatt Jacob rgd = (m2 == PCIM_CMD_MEMEN)? MEM_MAP_REG : IO_MAP_REG; 7475f96beb9SNate Lawson regs = bus_alloc_resource_any(dev, rtp, &rgd, RF_ACTIVE); 74865adb54cSMatt Jacob } 749960f6939SMatt Jacob if (regs == NULL) { 750960f6939SMatt Jacob device_printf(dev, "unable to map any ports\n"); 751960f6939SMatt Jacob goto bad; 75265adb54cSMatt Jacob } 7539cd7268eSMatt Jacob if (bootverbose) { 754f7dddf8aSMatt Jacob device_printf(dev, "using %s space register mapping\n", 755960f6939SMatt Jacob (rgd == IO_MAP_REG)? "I/O" : "Memory"); 7569cd7268eSMatt Jacob } 757960f6939SMatt Jacob pcs->pci_dev = dev; 758960f6939SMatt Jacob pcs->pci_reg = regs; 759960f6939SMatt Jacob pcs->pci_st = rman_get_bustag(regs); 760960f6939SMatt Jacob pcs->pci_sh = rman_get_bushandle(regs); 76165adb54cSMatt Jacob 762d59bd469SMatt Jacob pcs->pci_poff[BIU_BLOCK >> _BLK_REG_SHFT] = BIU_REGS_OFF; 763d59bd469SMatt Jacob pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS_OFF; 764d59bd469SMatt Jacob pcs->pci_poff[SXP_BLOCK >> _BLK_REG_SHFT] = PCI_SXP_REGS_OFF; 765d59bd469SMatt Jacob pcs->pci_poff[RISC_BLOCK >> _BLK_REG_SHFT] = PCI_RISC_REGS_OFF; 766d59bd469SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = DMA_REGS_OFF; 767c6608df3SMatt Jacob mdvp = &mdvec; 768c6608df3SMatt Jacob basetype = ISP_HA_SCSI_UNKNOWN; 769c6608df3SMatt Jacob psize = sizeof (sdparam); 77056aef503SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP1020) { 771c6608df3SMatt Jacob mdvp = &mdvec; 772c6608df3SMatt Jacob basetype = ISP_HA_SCSI_UNKNOWN; 773c6608df3SMatt Jacob psize = sizeof (sdparam); 774d59bd469SMatt Jacob } 775960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP1080) { 776c6608df3SMatt Jacob mdvp = &mdvec_1080; 777c6608df3SMatt Jacob basetype = ISP_HA_SCSI_1080; 778c6608df3SMatt Jacob psize = sizeof (sdparam); 779c6608df3SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 780c6608df3SMatt Jacob ISP1080_DMA_REGS_OFF; 781c6608df3SMatt Jacob } 782960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP1240) { 783c6608df3SMatt Jacob mdvp = &mdvec_1080; 78422e1dc85SMatt Jacob basetype = ISP_HA_SCSI_1240; 78522e1dc85SMatt Jacob psize = 2 * sizeof (sdparam); 78622e1dc85SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 78722e1dc85SMatt Jacob ISP1080_DMA_REGS_OFF; 78822e1dc85SMatt Jacob } 789960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP1280) { 79022e1dc85SMatt Jacob mdvp = &mdvec_1080; 79122e1dc85SMatt Jacob basetype = ISP_HA_SCSI_1280; 792c6608df3SMatt Jacob psize = 2 * sizeof (sdparam); 793d59bd469SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 794d59bd469SMatt Jacob ISP1080_DMA_REGS_OFF; 795d59bd469SMatt Jacob } 796f556e83bSMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP10160) { 797f556e83bSMatt Jacob mdvp = &mdvec_12160; 798f556e83bSMatt Jacob basetype = ISP_HA_SCSI_10160; 799f556e83bSMatt Jacob psize = sizeof (sdparam); 800f556e83bSMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 801f556e83bSMatt Jacob ISP1080_DMA_REGS_OFF; 802f556e83bSMatt Jacob } 803960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP12160) { 804960f6939SMatt Jacob mdvp = &mdvec_12160; 805960f6939SMatt Jacob basetype = ISP_HA_SCSI_12160; 806960f6939SMatt Jacob psize = 2 * sizeof (sdparam); 807960f6939SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 808960f6939SMatt Jacob ISP1080_DMA_REGS_OFF; 809960f6939SMatt Jacob } 810960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP2100) { 811c6608df3SMatt Jacob mdvp = &mdvec_2100; 812c6608df3SMatt Jacob basetype = ISP_HA_FC_2100; 813c6608df3SMatt Jacob psize = sizeof (fcparam); 814d59bd469SMatt Jacob pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = 815d59bd469SMatt Jacob PCI_MBOX_REGS2100_OFF; 816960f6939SMatt Jacob if (pci_get_revid(dev) < 3) { 817ab6d0040SMatt Jacob /* 818ab6d0040SMatt Jacob * XXX: Need to get the actual revision 819ab6d0040SMatt Jacob * XXX: number of the 2100 FB. At any rate, 820ab6d0040SMatt Jacob * XXX: lower cache line size for early revision 821ab6d0040SMatt Jacob * XXX; boards. 822ab6d0040SMatt Jacob */ 823ab6d0040SMatt Jacob linesz = 1; 824ab6d0040SMatt Jacob } 82565adb54cSMatt Jacob } 826960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP2200) { 827222bb542SMatt Jacob mdvp = &mdvec_2200; 828222bb542SMatt Jacob basetype = ISP_HA_FC_2200; 829222bb542SMatt Jacob psize = sizeof (fcparam); 830222bb542SMatt Jacob pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = 831222bb542SMatt Jacob PCI_MBOX_REGS2100_OFF; 832222bb542SMatt Jacob } 83375c1e828SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP2300) { 834126ec864SMatt Jacob mdvp = &mdvec_2300; 835126ec864SMatt Jacob basetype = ISP_HA_FC_2300; 836126ec864SMatt Jacob psize = sizeof (fcparam); 837126ec864SMatt Jacob pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = 838126ec864SMatt Jacob PCI_MBOX_REGS2300_OFF; 839126ec864SMatt Jacob } 840dd1419abSMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP2312 || 841dd1419abSMatt Jacob pci_get_devid(dev) == PCI_QLOGIC_ISP6312) { 84275c1e828SMatt Jacob mdvp = &mdvec_2300; 84375c1e828SMatt Jacob basetype = ISP_HA_FC_2312; 84475c1e828SMatt Jacob psize = sizeof (fcparam); 84575c1e828SMatt Jacob pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = 84675c1e828SMatt Jacob PCI_MBOX_REGS2300_OFF; 84775c1e828SMatt Jacob } 848e5265237SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP2322) { 849e5265237SMatt Jacob mdvp = &mdvec_2300; 850e5265237SMatt Jacob basetype = ISP_HA_FC_2322; 851e5265237SMatt Jacob psize = sizeof (fcparam); 852e5265237SMatt Jacob pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = 853e5265237SMatt Jacob PCI_MBOX_REGS2300_OFF; 854e5265237SMatt Jacob } 8558872e3d7SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP2422) { 8568872e3d7SMatt Jacob mdvp = &mdvec_2300; 8578872e3d7SMatt Jacob basetype = ISP_HA_FC_2422; 8588872e3d7SMatt Jacob psize = sizeof (fcparam); 8598872e3d7SMatt Jacob pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = 8608872e3d7SMatt Jacob PCI_MBOX_REGS2300_OFF; 8618872e3d7SMatt Jacob } 862c6608df3SMatt Jacob isp = &pcs->pci_isp; 8637cc0979fSDavid Malone isp->isp_param = malloc(psize, M_DEVBUF, M_NOWAIT | M_ZERO); 864c6608df3SMatt Jacob if (isp->isp_param == NULL) { 865960f6939SMatt Jacob device_printf(dev, "cannot allocate parameter data\n"); 866960f6939SMatt Jacob goto bad; 867c6608df3SMatt Jacob } 868c6608df3SMatt Jacob isp->isp_mdvec = mdvp; 869c6608df3SMatt Jacob isp->isp_type = basetype; 870960f6939SMatt Jacob isp->isp_revision = pci_get_revid(dev); 8716e5c5328SMatt Jacob isp->isp_dev = dev; 87265adb54cSMatt Jacob 87356aef503SMatt Jacob /* 87456aef503SMatt Jacob * Try and find firmware for this device. 87556aef503SMatt Jacob */ 87656aef503SMatt Jacob 877e5265237SMatt Jacob /* 878e5265237SMatt Jacob * Don't even attempt to get firmware for the 2322/2422 (yet) 879e5265237SMatt Jacob */ 880e5265237SMatt Jacob if (IS_2322(isp) == 0 && IS_24XX(isp) == 0 && isp_get_firmware_p) { 88156aef503SMatt Jacob int device = (int) pci_get_device(dev); 88256aef503SMatt Jacob #ifdef ISP_TARGET_MODE 88356aef503SMatt Jacob (*isp_get_firmware_p)(0, 1, device, &mdvp->dv_ispfw); 88456aef503SMatt Jacob #else 88556aef503SMatt Jacob (*isp_get_firmware_p)(0, 0, device, &mdvp->dv_ispfw); 88656aef503SMatt Jacob #endif 88756aef503SMatt Jacob } 88856aef503SMatt Jacob 88956aef503SMatt Jacob /* 890d951bbcaSMatt Jacob * Make sure that SERR, PERR, WRITE INVALIDATE and BUSMASTER 891d951bbcaSMatt Jacob * are set. 892d951bbcaSMatt Jacob */ 893960f6939SMatt Jacob cmd |= PCIM_CMD_SEREN | PCIM_CMD_PERRESPEN | 894960f6939SMatt Jacob PCIM_CMD_BUSMASTEREN | PCIM_CMD_INVEN; 89575c1e828SMatt Jacob if (IS_2300(isp)) { /* per QLogic errata */ 89675c1e828SMatt Jacob cmd &= ~PCIM_CMD_INVEN; 89775c1e828SMatt Jacob } 898fc087171SMatt Jacob if (IS_23XX(isp)) { 899fc087171SMatt Jacob /* 900fc087171SMatt Jacob * Can't tell if ROM will hang on 'ABOUT FIRMWARE' command. 901fc087171SMatt Jacob */ 902fc087171SMatt Jacob isp->isp_touched = 1; 903fc087171SMatt Jacob 904fc087171SMatt Jacob } 905b49c4674SMatt Jacob pci_write_config(dev, PCIR_COMMAND, cmd, 2); 906ab6d0040SMatt Jacob 907d951bbcaSMatt Jacob /* 908222bb542SMatt Jacob * Make sure the Cache Line Size register is set sensibly. 909d951bbcaSMatt Jacob */ 910960f6939SMatt Jacob data = pci_read_config(dev, PCIR_CACHELNSZ, 1); 911ab6d0040SMatt Jacob if (data != linesz) { 912d951bbcaSMatt Jacob data = PCI_DFLT_LNSZ; 913d02373f1SMatt Jacob isp_prt(isp, ISP_LOGCONFIG, "set PCI line size to %d", data); 914960f6939SMatt Jacob pci_write_config(dev, PCIR_CACHELNSZ, data, 1); 915d951bbcaSMatt Jacob } 916ab6d0040SMatt Jacob 917d951bbcaSMatt Jacob /* 918d951bbcaSMatt Jacob * Make sure the Latency Timer is sane. 919d951bbcaSMatt Jacob */ 920960f6939SMatt Jacob data = pci_read_config(dev, PCIR_LATTIMER, 1); 921d951bbcaSMatt Jacob if (data < PCI_DFLT_LTNCY) { 922d951bbcaSMatt Jacob data = PCI_DFLT_LTNCY; 923d02373f1SMatt Jacob isp_prt(isp, ISP_LOGCONFIG, "set PCI latency to %d", data); 924960f6939SMatt Jacob pci_write_config(dev, PCIR_LATTIMER, data, 1); 925d951bbcaSMatt Jacob } 926ab6d0040SMatt Jacob 927ab6d0040SMatt Jacob /* 928ab6d0040SMatt Jacob * Make sure we've disabled the ROM. 929ab6d0040SMatt Jacob */ 930960f6939SMatt Jacob data = pci_read_config(dev, PCIR_ROMADDR, 4); 931ab6d0040SMatt Jacob data &= ~1; 932960f6939SMatt Jacob pci_write_config(dev, PCIR_ROMADDR, data, 4); 93305fbcbb0SMatt Jacob 934960f6939SMatt Jacob iqd = 0; 9355f96beb9SNate Lawson irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &iqd, 9365f96beb9SNate Lawson RF_ACTIVE | RF_SHAREABLE); 937960f6939SMatt Jacob if (irq == NULL) { 938960f6939SMatt Jacob device_printf(dev, "could not allocate interrupt\n"); 939960f6939SMatt Jacob goto bad; 940960f6939SMatt Jacob } 941960f6939SMatt Jacob 9429cd7268eSMatt Jacob #if __FreeBSD_version >= 500000 943f09b1922SMatt Jacob /* Make sure the lock is set up. */ 9446008862bSJohn Baldwin mtx_init(&isp->isp_osinfo.lock, "isp", NULL, MTX_DEF); 945f09b1922SMatt Jacob locksetup++; 9469cd7268eSMatt Jacob #endif 947f09b1922SMatt Jacob 94872429e49SMatt Jacob if (bus_setup_intr(dev, irq, ISP_IFLAGS, isp_pci_intr, isp, &pcs->ih)) { 949f09b1922SMatt Jacob device_printf(dev, "could not setup interrupt\n"); 950f09b1922SMatt Jacob goto bad; 951f09b1922SMatt Jacob } 952960f6939SMatt Jacob 95305fbcbb0SMatt Jacob /* 95475c1e828SMatt Jacob * Last minute checks... 95575c1e828SMatt Jacob */ 956e5265237SMatt Jacob if (IS_23XX(isp)) { 95775c1e828SMatt Jacob isp->isp_port = pci_get_function(dev); 95875c1e828SMatt Jacob } 95975c1e828SMatt Jacob 96075c1e828SMatt Jacob /* 96105fbcbb0SMatt Jacob * Make sure we're in reset state. 96205fbcbb0SMatt Jacob */ 9633395b056SMatt Jacob ISP_LOCK(isp); 96465adb54cSMatt Jacob isp_reset(isp); 96565adb54cSMatt Jacob if (isp->isp_state != ISP_RESETSTATE) { 9663395b056SMatt Jacob ISP_UNLOCK(isp); 967960f6939SMatt Jacob goto bad; 96865adb54cSMatt Jacob } 96965adb54cSMatt Jacob isp_init(isp); 970b9b599feSMatt Jacob if (isp->isp_role != ISP_ROLE_NONE && isp->isp_state != ISP_INITSTATE) { 97165adb54cSMatt Jacob isp_uninit(isp); 9723395b056SMatt Jacob ISP_UNLOCK(isp); 973960f6939SMatt Jacob goto bad; 974d59bd469SMatt Jacob } 97565adb54cSMatt Jacob isp_attach(isp); 976b9b599feSMatt Jacob if (isp->isp_role != ISP_ROLE_NONE && isp->isp_state != ISP_RUNSTATE) { 97765adb54cSMatt Jacob isp_uninit(isp); 9783395b056SMatt Jacob ISP_UNLOCK(isp); 979960f6939SMatt Jacob goto bad; 980960f6939SMatt Jacob } 98156aef503SMatt Jacob /* 98256aef503SMatt Jacob * XXXX: Here is where we might unload the f/w module 98356aef503SMatt Jacob * XXXX: (or decrease the reference count to it). 98456aef503SMatt Jacob */ 9853395b056SMatt Jacob ISP_UNLOCK(isp); 986960f6939SMatt Jacob return (0); 987960f6939SMatt Jacob 988960f6939SMatt Jacob bad: 989960f6939SMatt Jacob 990960f6939SMatt Jacob if (pcs && pcs->ih) { 991960f6939SMatt Jacob (void) bus_teardown_intr(dev, irq, pcs->ih); 992960f6939SMatt Jacob } 993960f6939SMatt Jacob 9949cd7268eSMatt Jacob #if __FreeBSD_version >= 500000 9953395b056SMatt Jacob if (locksetup && isp) { 9963395b056SMatt Jacob mtx_destroy(&isp->isp_osinfo.lock); 9973395b056SMatt Jacob } 9989cd7268eSMatt Jacob #endif 9993395b056SMatt Jacob 1000960f6939SMatt Jacob if (irq) { 1001960f6939SMatt Jacob (void) bus_release_resource(dev, SYS_RES_IRQ, iqd, irq); 1002960f6939SMatt Jacob } 10033395b056SMatt Jacob 10043395b056SMatt Jacob 1005960f6939SMatt Jacob if (regs) { 1006960f6939SMatt Jacob (void) bus_release_resource(dev, rtp, rgd, regs); 1007960f6939SMatt Jacob } 10083395b056SMatt Jacob 1009960f6939SMatt Jacob if (pcs) { 10109cd7268eSMatt Jacob if (pcs->pci_isp.isp_param) { 10119cd7268eSMatt Jacob #ifdef ISP_FW_CRASH_DUMP 10129cd7268eSMatt Jacob if (IS_FC(isp) && FCPARAM(isp)->isp_dump_data) { 10139cd7268eSMatt Jacob free(FCPARAM(isp)->isp_dump_data, M_DEVBUF); 10149cd7268eSMatt Jacob } 10159cd7268eSMatt Jacob #endif 1016960f6939SMatt Jacob free(pcs->pci_isp.isp_param, M_DEVBUF); 10179cd7268eSMatt Jacob } 101865adb54cSMatt Jacob } 10193395b056SMatt Jacob 102056aef503SMatt Jacob /* 102156aef503SMatt Jacob * XXXX: Here is where we might unload the f/w module 102256aef503SMatt Jacob * XXXX: (or decrease the reference count to it). 102356aef503SMatt Jacob */ 1024960f6939SMatt Jacob return (ENXIO); 102565adb54cSMatt Jacob } 102665adb54cSMatt Jacob 1027f09b1922SMatt Jacob static void 1028f09b1922SMatt Jacob isp_pci_intr(void *arg) 1029f09b1922SMatt Jacob { 10309cd7268eSMatt Jacob ispsoftc_t *isp = arg; 10311dae40ebSMatt Jacob uint16_t isr, sema, mbox; 1032126ec864SMatt Jacob 1033f09b1922SMatt Jacob ISP_LOCK(isp); 1034126ec864SMatt Jacob isp->isp_intcnt++; 1035126ec864SMatt Jacob if (ISP_READ_ISR(isp, &isr, &sema, &mbox) == 0) { 1036126ec864SMatt Jacob isp->isp_intbogus++; 1037126ec864SMatt Jacob } else { 1038b96934e8SMatt Jacob int iok = isp->isp_osinfo.intsok; 1039b96934e8SMatt Jacob isp->isp_osinfo.intsok = 0; 1040126ec864SMatt Jacob isp_intr(isp, isr, sema, mbox); 1041b96934e8SMatt Jacob isp->isp_osinfo.intsok = iok; 1042126ec864SMatt Jacob } 1043f09b1922SMatt Jacob ISP_UNLOCK(isp); 1044f09b1922SMatt Jacob } 1045f09b1922SMatt Jacob 1046126ec864SMatt Jacob 1047126ec864SMatt Jacob #define IspVirt2Off(a, x) \ 1048126ec864SMatt Jacob (((struct isp_pcisoftc *)a)->pci_poff[((x) & _BLK_REG_MASK) >> \ 1049126ec864SMatt Jacob _BLK_REG_SHFT] + ((x) & 0xff)) 1050126ec864SMatt Jacob 1051126ec864SMatt Jacob #define BXR2(pcs, off) \ 1052126ec864SMatt Jacob bus_space_read_2(pcs->pci_st, pcs->pci_sh, off) 1053126ec864SMatt Jacob #define BXW2(pcs, off, v) \ 1054126ec864SMatt Jacob bus_space_write_2(pcs->pci_st, pcs->pci_sh, off, v) 1055126ec864SMatt Jacob 1056126ec864SMatt Jacob 105753af7d22SMatt Jacob static __inline int 10589cd7268eSMatt Jacob isp_pci_rd_debounced(ispsoftc_t *isp, int off, uint16_t *rp) 1059126ec864SMatt Jacob { 1060126ec864SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 10611dae40ebSMatt Jacob uint16_t val0, val1; 1062126ec864SMatt Jacob int i = 0; 1063126ec864SMatt Jacob 1064126ec864SMatt Jacob do { 1065126ec864SMatt Jacob val0 = BXR2(pcs, IspVirt2Off(isp, off)); 1066126ec864SMatt Jacob val1 = BXR2(pcs, IspVirt2Off(isp, off)); 1067126ec864SMatt Jacob } while (val0 != val1 && ++i < 1000); 1068126ec864SMatt Jacob if (val0 != val1) { 1069126ec864SMatt Jacob return (1); 1070126ec864SMatt Jacob } 1071126ec864SMatt Jacob *rp = val0; 1072126ec864SMatt Jacob return (0); 1073126ec864SMatt Jacob } 1074126ec864SMatt Jacob 1075126ec864SMatt Jacob static int 10769cd7268eSMatt Jacob isp_pci_rd_isr(ispsoftc_t *isp, uint16_t *isrp, 10771dae40ebSMatt Jacob uint16_t *semap, uint16_t *mbp) 1078126ec864SMatt Jacob { 1079126ec864SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 10801dae40ebSMatt Jacob uint16_t isr, sema; 1081126ec864SMatt Jacob 1082126ec864SMatt Jacob if (IS_2100(isp)) { 1083126ec864SMatt Jacob if (isp_pci_rd_debounced(isp, BIU_ISR, &isr)) { 1084126ec864SMatt Jacob return (0); 1085126ec864SMatt Jacob } 1086126ec864SMatt Jacob if (isp_pci_rd_debounced(isp, BIU_SEMA, &sema)) { 1087126ec864SMatt Jacob return (0); 1088126ec864SMatt Jacob } 1089126ec864SMatt Jacob } else { 1090126ec864SMatt Jacob isr = BXR2(pcs, IspVirt2Off(isp, BIU_ISR)); 1091126ec864SMatt Jacob sema = BXR2(pcs, IspVirt2Off(isp, BIU_SEMA)); 1092126ec864SMatt Jacob } 1093126ec864SMatt Jacob isp_prt(isp, ISP_LOGDEBUG3, "ISR 0x%x SEMA 0x%x", isr, sema); 1094126ec864SMatt Jacob isr &= INT_PENDING_MASK(isp); 1095126ec864SMatt Jacob sema &= BIU_SEMA_LOCK; 1096126ec864SMatt Jacob if (isr == 0 && sema == 0) { 1097126ec864SMatt Jacob return (0); 1098126ec864SMatt Jacob } 1099126ec864SMatt Jacob *isrp = isr; 1100126ec864SMatt Jacob if ((*semap = sema) != 0) { 1101126ec864SMatt Jacob if (IS_2100(isp)) { 1102126ec864SMatt Jacob if (isp_pci_rd_debounced(isp, OUTMAILBOX0, mbp)) { 1103126ec864SMatt Jacob return (0); 1104126ec864SMatt Jacob } 1105126ec864SMatt Jacob } else { 1106126ec864SMatt Jacob *mbp = BXR2(pcs, IspVirt2Off(isp, OUTMAILBOX0)); 1107126ec864SMatt Jacob } 1108126ec864SMatt Jacob } 1109126ec864SMatt Jacob return (1); 1110126ec864SMatt Jacob } 1111126ec864SMatt Jacob 1112126ec864SMatt Jacob static int 11139cd7268eSMatt Jacob isp_pci_rd_isr_2300(ispsoftc_t *isp, uint16_t *isrp, 11141dae40ebSMatt Jacob uint16_t *semap, uint16_t *mbox0p) 1115126ec864SMatt Jacob { 1116126ec864SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 11171dae40ebSMatt Jacob uint32_t r2hisr; 1118126ec864SMatt Jacob 11193bd40330SMatt Jacob if (!(BXR2(pcs, IspVirt2Off(isp, BIU_ISR) & BIU2100_ISR_RISC_INT))) { 11203bd40330SMatt Jacob *isrp = 0; 1121db4fa023SMatt Jacob return (0); 11223bd40330SMatt Jacob } 1123126ec864SMatt Jacob r2hisr = bus_space_read_4(pcs->pci_st, pcs->pci_sh, 1124126ec864SMatt Jacob IspVirt2Off(pcs, BIU_R2HSTSLO)); 1125126ec864SMatt Jacob isp_prt(isp, ISP_LOGDEBUG3, "RISC2HOST ISR 0x%x", r2hisr); 1126126ec864SMatt Jacob if ((r2hisr & BIU_R2HST_INTR) == 0) { 1127126ec864SMatt Jacob *isrp = 0; 1128126ec864SMatt Jacob return (0); 1129126ec864SMatt Jacob } 1130126ec864SMatt Jacob switch (r2hisr & BIU_R2HST_ISTAT_MASK) { 1131126ec864SMatt Jacob case ISPR2HST_ROM_MBX_OK: 1132126ec864SMatt Jacob case ISPR2HST_ROM_MBX_FAIL: 1133126ec864SMatt Jacob case ISPR2HST_MBX_OK: 1134126ec864SMatt Jacob case ISPR2HST_MBX_FAIL: 1135126ec864SMatt Jacob case ISPR2HST_ASYNC_EVENT: 1136126ec864SMatt Jacob *isrp = r2hisr & 0xffff; 1137126ec864SMatt Jacob *mbox0p = (r2hisr >> 16); 1138126ec864SMatt Jacob *semap = 1; 1139126ec864SMatt Jacob return (1); 1140fc3bbaaaSMatt Jacob case ISPR2HST_RIO_16: 1141fc3bbaaaSMatt Jacob *isrp = r2hisr & 0xffff; 1142fc3bbaaaSMatt Jacob *mbox0p = ASYNC_RIO1; 1143fc3bbaaaSMatt Jacob *semap = 1; 1144fc3bbaaaSMatt Jacob return (1); 1145fc3bbaaaSMatt Jacob case ISPR2HST_FPOST: 1146fc3bbaaaSMatt Jacob *isrp = r2hisr & 0xffff; 1147fc3bbaaaSMatt Jacob *mbox0p = ASYNC_CMD_CMPLT; 1148fc3bbaaaSMatt Jacob *semap = 1; 1149fc3bbaaaSMatt Jacob return (1); 1150fc3bbaaaSMatt Jacob case ISPR2HST_FPOST_CTIO: 1151fc3bbaaaSMatt Jacob *isrp = r2hisr & 0xffff; 1152fc3bbaaaSMatt Jacob *mbox0p = ASYNC_CTIO_DONE; 1153fc3bbaaaSMatt Jacob *semap = 1; 1154fc3bbaaaSMatt Jacob return (1); 1155126ec864SMatt Jacob case ISPR2HST_RSPQ_UPDATE: 1156126ec864SMatt Jacob *isrp = r2hisr & 0xffff; 1157126ec864SMatt Jacob *mbox0p = 0; 1158126ec864SMatt Jacob *semap = 0; 1159126ec864SMatt Jacob return (1); 1160126ec864SMatt Jacob default: 1161126ec864SMatt Jacob return (0); 1162126ec864SMatt Jacob } 1163126ec864SMatt Jacob } 1164126ec864SMatt Jacob 11651dae40ebSMatt Jacob static uint16_t 11669cd7268eSMatt Jacob isp_pci_rd_reg(ispsoftc_t *isp, int regoff) 116765adb54cSMatt Jacob { 11681dae40ebSMatt Jacob uint16_t rv; 116965adb54cSMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 1170126ec864SMatt Jacob int oldconf = 0; 117165adb54cSMatt Jacob 1172d59bd469SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 117365adb54cSMatt Jacob /* 117465adb54cSMatt Jacob * We will assume that someone has paused the RISC processor. 117565adb54cSMatt Jacob */ 1176126ec864SMatt Jacob oldconf = BXR2(pcs, IspVirt2Off(isp, BIU_CONF1)); 1177126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), 1178126ec864SMatt Jacob oldconf | BIU_PCI_CONF1_SXP); 117965adb54cSMatt Jacob } 1180126ec864SMatt Jacob rv = BXR2(pcs, IspVirt2Off(isp, regoff)); 1181d59bd469SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 1182126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), oldconf); 118365adb54cSMatt Jacob } 118465adb54cSMatt Jacob return (rv); 118565adb54cSMatt Jacob } 118665adb54cSMatt Jacob 118765adb54cSMatt Jacob static void 11889cd7268eSMatt Jacob isp_pci_wr_reg(ispsoftc_t *isp, int regoff, uint16_t val) 118965adb54cSMatt Jacob { 119065adb54cSMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 1191126ec864SMatt Jacob int oldconf = 0; 1192d59bd469SMatt Jacob 1193d59bd469SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 119465adb54cSMatt Jacob /* 119565adb54cSMatt Jacob * We will assume that someone has paused the RISC processor. 119665adb54cSMatt Jacob */ 1197126ec864SMatt Jacob oldconf = BXR2(pcs, IspVirt2Off(isp, BIU_CONF1)); 1198126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), 1199126ec864SMatt Jacob oldconf | BIU_PCI_CONF1_SXP); 120065adb54cSMatt Jacob } 1201126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, regoff), val); 1202d59bd469SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 1203126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), oldconf); 120465adb54cSMatt Jacob } 120565adb54cSMatt Jacob } 120665adb54cSMatt Jacob 12071dae40ebSMatt Jacob static uint16_t 12089cd7268eSMatt Jacob isp_pci_rd_reg_1080(ispsoftc_t *isp, int regoff) 1209d59bd469SMatt Jacob { 12101dae40ebSMatt Jacob uint16_t rv, oc = 0; 1211d59bd469SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 1212d59bd469SMatt Jacob 121322e1dc85SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK || 121422e1dc85SMatt Jacob (regoff & _BLK_REG_MASK) == (SXP_BLOCK|SXP_BANK1_SELECT)) { 12151dae40ebSMatt Jacob uint16_t tc; 1216d59bd469SMatt Jacob /* 1217d59bd469SMatt Jacob * We will assume that someone has paused the RISC processor. 1218d59bd469SMatt Jacob */ 1219126ec864SMatt Jacob oc = BXR2(pcs, IspVirt2Off(isp, BIU_CONF1)); 122022e1dc85SMatt Jacob tc = oc & ~BIU_PCI1080_CONF1_DMA; 122122e1dc85SMatt Jacob if (regoff & SXP_BANK1_SELECT) 122222e1dc85SMatt Jacob tc |= BIU_PCI1080_CONF1_SXP1; 122322e1dc85SMatt Jacob else 122422e1dc85SMatt Jacob tc |= BIU_PCI1080_CONF1_SXP0; 1225126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), tc); 1226d59bd469SMatt Jacob } else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) { 1227126ec864SMatt Jacob oc = BXR2(pcs, IspVirt2Off(isp, BIU_CONF1)); 1228126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), 1229126ec864SMatt Jacob oc | BIU_PCI1080_CONF1_DMA); 1230d59bd469SMatt Jacob } 1231126ec864SMatt Jacob rv = BXR2(pcs, IspVirt2Off(isp, regoff)); 123222e1dc85SMatt Jacob if (oc) { 1233126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), oc); 1234d59bd469SMatt Jacob } 1235d59bd469SMatt Jacob return (rv); 1236d59bd469SMatt Jacob } 1237d59bd469SMatt Jacob 1238d59bd469SMatt Jacob static void 12399cd7268eSMatt Jacob isp_pci_wr_reg_1080(ispsoftc_t *isp, int regoff, uint16_t val) 1240d59bd469SMatt Jacob { 1241d59bd469SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 1242126ec864SMatt Jacob int oc = 0; 1243d59bd469SMatt Jacob 124422e1dc85SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK || 124522e1dc85SMatt Jacob (regoff & _BLK_REG_MASK) == (SXP_BLOCK|SXP_BANK1_SELECT)) { 12461dae40ebSMatt Jacob uint16_t tc; 1247d59bd469SMatt Jacob /* 1248d59bd469SMatt Jacob * We will assume that someone has paused the RISC processor. 1249d59bd469SMatt Jacob */ 1250126ec864SMatt Jacob oc = BXR2(pcs, IspVirt2Off(isp, BIU_CONF1)); 125122e1dc85SMatt Jacob tc = oc & ~BIU_PCI1080_CONF1_DMA; 125222e1dc85SMatt Jacob if (regoff & SXP_BANK1_SELECT) 125322e1dc85SMatt Jacob tc |= BIU_PCI1080_CONF1_SXP1; 125422e1dc85SMatt Jacob else 125522e1dc85SMatt Jacob tc |= BIU_PCI1080_CONF1_SXP0; 1256126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), tc); 1257d59bd469SMatt Jacob } else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) { 1258126ec864SMatt Jacob oc = BXR2(pcs, IspVirt2Off(isp, BIU_CONF1)); 1259126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), 1260126ec864SMatt Jacob oc | BIU_PCI1080_CONF1_DMA); 1261d59bd469SMatt Jacob } 1262126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, regoff), val); 126322e1dc85SMatt Jacob if (oc) { 1264126ec864SMatt Jacob BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), oc); 1265d59bd469SMatt Jacob } 1266d59bd469SMatt Jacob } 1267d59bd469SMatt Jacob 1268d720e6d5SJustin T. Gibbs 1269222bb542SMatt Jacob struct imush { 12709cd7268eSMatt Jacob ispsoftc_t *isp; 1271222bb542SMatt Jacob int error; 1272222bb542SMatt Jacob }; 1273222bb542SMatt Jacob 12741923f739SMatt Jacob static void imc(void *, bus_dma_segment_t *, int, int); 12751923f739SMatt Jacob 1276d720e6d5SJustin T. Gibbs static void 12771923f739SMatt Jacob imc(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1278d720e6d5SJustin T. Gibbs { 1279222bb542SMatt Jacob struct imush *imushp = (struct imush *) arg; 1280222bb542SMatt Jacob if (error) { 1281222bb542SMatt Jacob imushp->error = error; 1282222bb542SMatt Jacob } else { 12839cd7268eSMatt Jacob ispsoftc_t *isp =imushp->isp; 12841923f739SMatt Jacob bus_addr_t addr = segs->ds_addr; 12851923f739SMatt Jacob 12861923f739SMatt Jacob isp->isp_rquest_dma = addr; 12871923f739SMatt Jacob addr += ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)); 12881923f739SMatt Jacob isp->isp_result_dma = addr; 12891923f739SMatt Jacob if (IS_FC(isp)) { 12901923f739SMatt Jacob addr += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)); 12911923f739SMatt Jacob FCPARAM(isp)->isp_scdma = addr; 12921923f739SMatt Jacob } 1293222bb542SMatt Jacob } 1294d720e6d5SJustin T. Gibbs } 1295d720e6d5SJustin T. Gibbs 1296029f13c6SMatt Jacob /* 1297029f13c6SMatt Jacob * Should be BUS_SPACE_MAXSIZE, but MAXPHYS is larger than BUS_SPACE_MAXSIZE 1298029f13c6SMatt Jacob */ 1299029f13c6SMatt Jacob #define ISP_NSEGS ((MAXPHYS / PAGE_SIZE) + 1) 1300d720e6d5SJustin T. Gibbs 13019cd7268eSMatt Jacob #if __FreeBSD_version < 500000 13029cd7268eSMatt Jacob #define isp_dma_tag_create bus_dma_tag_create 13039cd7268eSMatt Jacob #else 13049cd7268eSMatt Jacob #define isp_dma_tag_create(a, b, c, d, e, f, g, h, i, j, k, z) \ 13059cd7268eSMatt Jacob bus_dma_tag_create(a, b, c, d, e, f, g, h, i, j, k, \ 13069cd7268eSMatt Jacob busdma_lock_mutex, &Giant, z) 13079cd7268eSMatt Jacob #endif 13089cd7268eSMatt Jacob 1309d720e6d5SJustin T. Gibbs static int 13109cd7268eSMatt Jacob isp_pci_mbxdma(ispsoftc_t *isp) 1311d720e6d5SJustin T. Gibbs { 13121923f739SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *)isp; 1313d720e6d5SJustin T. Gibbs caddr_t base; 13141dae40ebSMatt Jacob uint32_t len; 13151923f739SMatt Jacob int i, error, ns; 131653af7d22SMatt Jacob bus_size_t slim; /* segment size */ 13174b2dc3c4SScott Long bus_addr_t llim; /* low limit of unavailable dma */ 131851effc8cSMatt Jacob bus_addr_t hlim; /* high limit of unavailable dma */ 1319222bb542SMatt Jacob struct imush im; 1320222bb542SMatt Jacob 1321a95ae193SMatt Jacob /* 1322a95ae193SMatt Jacob * Already been here? If so, leave... 1323a95ae193SMatt Jacob */ 1324a95ae193SMatt Jacob if (isp->isp_rquest) { 1325a95ae193SMatt Jacob return (0); 1326a95ae193SMatt Jacob } 1327a95ae193SMatt Jacob 132853af7d22SMatt Jacob hlim = BUS_SPACE_MAXADDR; 13291923f739SMatt Jacob if (IS_ULTRA2(isp) || IS_FC(isp) || IS_1240(isp)) { 133053af7d22SMatt Jacob slim = (bus_size_t) (1ULL << 32); 13311dae40ebSMatt Jacob #ifdef ISP_TARGET_MODE 13321dae40ebSMatt Jacob /* 13331dae40ebSMatt Jacob * XXX: Until Fixed Soon 13341dae40ebSMatt Jacob */ 13351dae40ebSMatt Jacob llim = BUS_SPACE_MAXADDR_32BIT; 13361dae40ebSMatt Jacob #else 13371dae40ebSMatt Jacob llim = BUS_SPACE_MAXADDR; 13381dae40ebSMatt Jacob #endif 13391923f739SMatt Jacob } else { 13401dae40ebSMatt Jacob llim = BUS_SPACE_MAXADDR_32BIT; 134153af7d22SMatt Jacob slim = (1 << 24); 13421923f739SMatt Jacob } 13431923f739SMatt Jacob 134472429e49SMatt Jacob ISP_UNLOCK(isp); 13459cd7268eSMatt Jacob if (isp_dma_tag_create(NULL, 1, slim, llim, hlim, 13469cd7268eSMatt Jacob NULL, NULL, BUS_SPACE_MAXSIZE, ISP_NSEGS, slim, 0, &pcs->dmat)) { 13471923f739SMatt Jacob isp_prt(isp, ISP_LOGERR, "could not create master dma tag"); 134872429e49SMatt Jacob ISP_LOCK(isp); 13491923f739SMatt Jacob return(1); 13501923f739SMatt Jacob } 13511923f739SMatt Jacob 13521923f739SMatt Jacob 1353d02373f1SMatt Jacob len = sizeof (XS_T **) * isp->isp_maxcmds; 1354a163d034SWarner Losh isp->isp_xflist = (XS_T **) malloc(len, M_DEVBUF, M_WAITOK | M_ZERO); 1355a95ae193SMatt Jacob if (isp->isp_xflist == NULL) { 1356d02373f1SMatt Jacob isp_prt(isp, ISP_LOGERR, "cannot alloc xflist array"); 135772429e49SMatt Jacob ISP_LOCK(isp); 1358a95ae193SMatt Jacob return (1); 1359a95ae193SMatt Jacob } 136051e23558SNate Lawson #ifdef ISP_TARGET_MODE 136151e23558SNate Lawson len = sizeof (void **) * isp->isp_maxcmds; 136251e23558SNate Lawson isp->isp_tgtlist = (void **) malloc(len, M_DEVBUF, M_WAITOK | M_ZERO); 136351e23558SNate Lawson if (isp->isp_tgtlist == NULL) { 136451e23558SNate Lawson isp_prt(isp, ISP_LOGERR, "cannot alloc tgtlist array"); 136551e23558SNate Lawson ISP_LOCK(isp); 136651e23558SNate Lawson return (1); 136751e23558SNate Lawson } 136851e23558SNate Lawson #endif 1369a95ae193SMatt Jacob len = sizeof (bus_dmamap_t) * isp->isp_maxcmds; 1370a163d034SWarner Losh pcs->dmaps = (bus_dmamap_t *) malloc(len, M_DEVBUF, M_WAITOK); 13711923f739SMatt Jacob if (pcs->dmaps == NULL) { 13721923f739SMatt Jacob isp_prt(isp, ISP_LOGERR, "can't alloc dma map storage"); 1373a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 137451e23558SNate Lawson #ifdef ISP_TARGET_MODE 137551e23558SNate Lawson free(isp->isp_tgtlist, M_DEVBUF); 137651e23558SNate Lawson #endif 137772429e49SMatt Jacob ISP_LOCK(isp); 1378a95ae193SMatt Jacob return (1); 1379a95ae193SMatt Jacob } 1380a95ae193SMatt Jacob 1381d720e6d5SJustin T. Gibbs /* 1382d720e6d5SJustin T. Gibbs * Allocate and map the request, result queues, plus FC scratch area. 1383d720e6d5SJustin T. Gibbs */ 1384d02373f1SMatt Jacob len = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)); 1385d02373f1SMatt Jacob len += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)); 1386222bb542SMatt Jacob if (IS_FC(isp)) { 1387d720e6d5SJustin T. Gibbs len += ISP2100_SCRLEN; 1388d720e6d5SJustin T. Gibbs } 13891923f739SMatt Jacob 13901923f739SMatt Jacob ns = (len / PAGE_SIZE) + 1; 139153af7d22SMatt Jacob /* 139253af7d22SMatt Jacob * Create a tag for the control spaces- force it to within 32 bits. 139353af7d22SMatt Jacob */ 13949cd7268eSMatt Jacob if (isp_dma_tag_create(pcs->dmat, QENTRY_LEN, slim, 139553af7d22SMatt Jacob BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, 13969cd7268eSMatt Jacob NULL, NULL, len, ns, slim, 0, &isp->isp_cdmat)) { 1397f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 1398f7dddf8aSMatt Jacob "cannot create a dma tag for control spaces"); 13991923f739SMatt Jacob free(pcs->dmaps, M_DEVBUF); 1400a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 140151e23558SNate Lawson #ifdef ISP_TARGET_MODE 140251e23558SNate Lawson free(isp->isp_tgtlist, M_DEVBUF); 140351e23558SNate Lawson #endif 140472429e49SMatt Jacob ISP_LOCK(isp); 1405d720e6d5SJustin T. Gibbs return (1); 1406d720e6d5SJustin T. Gibbs } 1407d720e6d5SJustin T. Gibbs 14081923f739SMatt Jacob if (bus_dmamem_alloc(isp->isp_cdmat, (void **)&base, BUS_DMA_NOWAIT, 14091923f739SMatt Jacob &isp->isp_cdmap) != 0) { 1410f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 14111923f739SMatt Jacob "cannot allocate %d bytes of CCB memory", len); 14121923f739SMatt Jacob bus_dma_tag_destroy(isp->isp_cdmat); 1413a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 141451e23558SNate Lawson #ifdef ISP_TARGET_MODE 141551e23558SNate Lawson free(isp->isp_tgtlist, M_DEVBUF); 141651e23558SNate Lawson #endif 14171923f739SMatt Jacob free(pcs->dmaps, M_DEVBUF); 141872429e49SMatt Jacob ISP_LOCK(isp); 1419222bb542SMatt Jacob return (1); 1420222bb542SMatt Jacob } 1421d720e6d5SJustin T. Gibbs 1422a95ae193SMatt Jacob for (i = 0; i < isp->isp_maxcmds; i++) { 14231923f739SMatt Jacob error = bus_dmamap_create(pcs->dmat, 0, &pcs->dmaps[i]); 1424d720e6d5SJustin T. Gibbs if (error) { 1425f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 1426f7dddf8aSMatt Jacob "error %d creating per-cmd DMA maps", error); 14271923f739SMatt Jacob while (--i >= 0) { 14281923f739SMatt Jacob bus_dmamap_destroy(pcs->dmat, pcs->dmaps[i]); 14291923f739SMatt Jacob } 14301923f739SMatt Jacob goto bad; 1431d720e6d5SJustin T. Gibbs } 1432d720e6d5SJustin T. Gibbs } 1433a95ae193SMatt Jacob 14341923f739SMatt Jacob im.isp = isp; 1435222bb542SMatt Jacob im.error = 0; 14361923f739SMatt Jacob bus_dmamap_load(isp->isp_cdmat, isp->isp_cdmap, base, len, imc, &im, 0); 1437222bb542SMatt Jacob if (im.error) { 1438f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 14391923f739SMatt Jacob "error %d loading dma map for control areas", im.error); 14401923f739SMatt Jacob goto bad; 1441222bb542SMatt Jacob } 14421923f739SMatt Jacob 14431923f739SMatt Jacob isp->isp_rquest = base; 14441923f739SMatt Jacob base += ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)); 14451923f739SMatt Jacob isp->isp_result = base; 14461923f739SMatt Jacob if (IS_FC(isp)) { 14471923f739SMatt Jacob base += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)); 14481923f739SMatt Jacob FCPARAM(isp)->isp_scratch = base; 144992c49d78SMatt Jacob } 145072429e49SMatt Jacob ISP_LOCK(isp); 1451d720e6d5SJustin T. Gibbs return (0); 14521923f739SMatt Jacob 14531923f739SMatt Jacob bad: 14541923f739SMatt Jacob bus_dmamem_free(isp->isp_cdmat, base, isp->isp_cdmap); 14551923f739SMatt Jacob bus_dma_tag_destroy(isp->isp_cdmat); 14561923f739SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 145751e23558SNate Lawson #ifdef ISP_TARGET_MODE 145851e23558SNate Lawson free(isp->isp_tgtlist, M_DEVBUF); 145951e23558SNate Lawson #endif 14601923f739SMatt Jacob free(pcs->dmaps, M_DEVBUF); 146172429e49SMatt Jacob ISP_LOCK(isp); 14621923f739SMatt Jacob isp->isp_rquest = NULL; 14631923f739SMatt Jacob return (1); 1464d720e6d5SJustin T. Gibbs } 1465d720e6d5SJustin T. Gibbs 1466d720e6d5SJustin T. Gibbs typedef struct { 14679cd7268eSMatt Jacob ispsoftc_t *isp; 14689e11e5beSMatt Jacob void *cmd_token; 14699e11e5beSMatt Jacob void *rq; 14701dae40ebSMatt Jacob uint16_t *nxtip; 14711dae40ebSMatt Jacob uint16_t optr; 14721dae40ebSMatt Jacob int error; 1473d720e6d5SJustin T. Gibbs } mush_t; 1474d720e6d5SJustin T. Gibbs 14754873663cSMatt Jacob #define MUSHERR_NOQENTRIES -2 14764873663cSMatt Jacob 14779e11e5beSMatt Jacob #ifdef ISP_TARGET_MODE 14789e11e5beSMatt Jacob /* 14799e11e5beSMatt Jacob * We need to handle DMA for target mode differently from initiator mode. 14809e11e5beSMatt Jacob * 14819e11e5beSMatt Jacob * DMA mapping and construction and submission of CTIO Request Entries 14829e11e5beSMatt Jacob * and rendevous for completion are very tightly coupled because we start 14839e11e5beSMatt Jacob * out by knowing (per platform) how much data we have to move, but we 14849e11e5beSMatt Jacob * don't know, up front, how many DMA mapping segments will have to be used 14859e11e5beSMatt Jacob * cover that data, so we don't know how many CTIO Request Entries we 14869e11e5beSMatt Jacob * will end up using. Further, for performance reasons we may want to 14879e11e5beSMatt Jacob * (on the last CTIO for Fibre Channel), send status too (if all went well). 14889e11e5beSMatt Jacob * 14899e11e5beSMatt Jacob * The standard vector still goes through isp_pci_dmasetup, but the callback 14909e11e5beSMatt Jacob * for the DMA mapping routines comes here instead with the whole transfer 14919e11e5beSMatt Jacob * mapped and a pointer to a partially filled in already allocated request 14929e11e5beSMatt Jacob * queue entry. We finish the job. 14939e11e5beSMatt Jacob */ 1494e9a2738aSMatt Jacob static void tdma_mk(void *, bus_dma_segment_t *, int, int); 1495e9a2738aSMatt Jacob static void tdma_mkfc(void *, bus_dma_segment_t *, int, int); 1496e9a2738aSMatt Jacob 1497e9a2738aSMatt Jacob #define STATUS_WITH_DATA 1 14989e11e5beSMatt Jacob 1499d720e6d5SJustin T. Gibbs static void 150005fbcbb0SMatt Jacob tdma_mk(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 1501d720e6d5SJustin T. Gibbs { 1502d720e6d5SJustin T. Gibbs mush_t *mp; 15039e11e5beSMatt Jacob struct ccb_scsiio *csio; 15049cd7268eSMatt Jacob ispsoftc_t *isp; 15051923f739SMatt Jacob struct isp_pcisoftc *pcs; 1506d720e6d5SJustin T. Gibbs bus_dmamap_t *dp; 15074fd13c1bSMatt Jacob ct_entry_t *cto, *qe; 15081dae40ebSMatt Jacob uint8_t scsi_status; 15091dae40ebSMatt Jacob uint16_t curi, nxti, handle; 15101dae40ebSMatt Jacob uint32_t sflags; 151105fbcbb0SMatt Jacob int32_t resid; 15124fd13c1bSMatt Jacob int nth_ctio, nctios, send_status; 1513d720e6d5SJustin T. Gibbs 1514d720e6d5SJustin T. Gibbs mp = (mush_t *) arg; 1515d720e6d5SJustin T. Gibbs if (error) { 1516d720e6d5SJustin T. Gibbs mp->error = error; 1517d720e6d5SJustin T. Gibbs return; 1518d720e6d5SJustin T. Gibbs } 15194fd13c1bSMatt Jacob 15204fd13c1bSMatt Jacob isp = mp->isp; 15219e11e5beSMatt Jacob csio = mp->cmd_token; 15229e11e5beSMatt Jacob cto = mp->rq; 15234fd13c1bSMatt Jacob curi = isp->isp_reqidx; 15244fd13c1bSMatt Jacob qe = (ct_entry_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, curi); 15259e11e5beSMatt Jacob 152665b024e1SMatt Jacob cto->ct_xfrlen = 0; 152765b024e1SMatt Jacob cto->ct_seg_count = 0; 152865b024e1SMatt Jacob cto->ct_header.rqs_entry_count = 1; 152905fbcbb0SMatt Jacob MEMZERO(cto->ct_dataseg, sizeof(cto->ct_dataseg)); 153005fbcbb0SMatt Jacob 153105fbcbb0SMatt Jacob if (nseg == 0) { 153205fbcbb0SMatt Jacob cto->ct_header.rqs_seqno = 1; 15334fd13c1bSMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, 1534e9a2738aSMatt Jacob "CTIO[%x] lun%d iid%d tag %x flgs %x sts %x ssts %x res %d", 15355f5aafe1SMatt Jacob cto->ct_fwhandle, csio->ccb_h.target_lun, cto->ct_iid, 1536e9a2738aSMatt Jacob cto->ct_tag_val, cto->ct_flags, cto->ct_status, 1537e9a2738aSMatt Jacob cto->ct_scsi_status, cto->ct_resid); 15384fd13c1bSMatt Jacob ISP_TDQE(isp, "tdma_mk[no data]", curi, cto); 15394fd13c1bSMatt Jacob isp_put_ctio(isp, cto, qe); 154065b024e1SMatt Jacob return; 154165b024e1SMatt Jacob } 154265b024e1SMatt Jacob 154365b024e1SMatt Jacob nctios = nseg / ISP_RQDSEG; 154465b024e1SMatt Jacob if (nseg % ISP_RQDSEG) { 154565b024e1SMatt Jacob nctios++; 154665b024e1SMatt Jacob } 154765b024e1SMatt Jacob 154805fbcbb0SMatt Jacob /* 15495f5aafe1SMatt Jacob * Save syshandle, and potentially any SCSI status, which we'll 15505f5aafe1SMatt Jacob * reinsert on the last CTIO we're going to send. 155105fbcbb0SMatt Jacob */ 15524fd13c1bSMatt Jacob 15535f5aafe1SMatt Jacob handle = cto->ct_syshandle; 15545f5aafe1SMatt Jacob cto->ct_syshandle = 0; 155505fbcbb0SMatt Jacob cto->ct_header.rqs_seqno = 0; 155605fbcbb0SMatt Jacob send_status = (cto->ct_flags & CT_SENDSTATUS) != 0; 155705fbcbb0SMatt Jacob 155805fbcbb0SMatt Jacob if (send_status) { 155905fbcbb0SMatt Jacob sflags = cto->ct_flags & (CT_SENDSTATUS | CT_CCINCR); 156005fbcbb0SMatt Jacob cto->ct_flags &= ~(CT_SENDSTATUS | CT_CCINCR); 156105fbcbb0SMatt Jacob /* 156205fbcbb0SMatt Jacob * Preserve residual. 156305fbcbb0SMatt Jacob */ 156405fbcbb0SMatt Jacob resid = cto->ct_resid; 156505fbcbb0SMatt Jacob 156605fbcbb0SMatt Jacob /* 156705fbcbb0SMatt Jacob * Save actual SCSI status. 156805fbcbb0SMatt Jacob */ 156905fbcbb0SMatt Jacob scsi_status = cto->ct_scsi_status; 157005fbcbb0SMatt Jacob 1571e9a2738aSMatt Jacob #ifndef STATUS_WITH_DATA 1572e9a2738aSMatt Jacob sflags |= CT_NO_DATA; 157305fbcbb0SMatt Jacob /* 157405fbcbb0SMatt Jacob * We can't do a status at the same time as a data CTIO, so 157505fbcbb0SMatt Jacob * we need to synthesize an extra CTIO at this level. 157605fbcbb0SMatt Jacob */ 157705fbcbb0SMatt Jacob nctios++; 1578b72b1569SMatt Jacob #endif 157905fbcbb0SMatt Jacob } else { 158005fbcbb0SMatt Jacob sflags = scsi_status = resid = 0; 158105fbcbb0SMatt Jacob } 158205fbcbb0SMatt Jacob 1583b96934e8SMatt Jacob cto->ct_resid = 0; 158405fbcbb0SMatt Jacob cto->ct_scsi_status = 0; 158505fbcbb0SMatt Jacob 15861923f739SMatt Jacob pcs = (struct isp_pcisoftc *)isp; 15871923f739SMatt Jacob dp = &pcs->dmaps[isp_handle_index(handle)]; 15889e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 15891923f739SMatt Jacob bus_dmamap_sync(pcs->dmat, *dp, BUS_DMASYNC_PREREAD); 1590d720e6d5SJustin T. Gibbs } else { 15911923f739SMatt Jacob bus_dmamap_sync(pcs->dmat, *dp, BUS_DMASYNC_PREWRITE); 1592d720e6d5SJustin T. Gibbs } 1593d720e6d5SJustin T. Gibbs 15944fd13c1bSMatt Jacob nxti = *mp->nxtip; 15959e11e5beSMatt Jacob 15964fd13c1bSMatt Jacob for (nth_ctio = 0; nth_ctio < nctios; nth_ctio++) { 159705fbcbb0SMatt Jacob int seglim; 15989e11e5beSMatt Jacob 15999e11e5beSMatt Jacob seglim = nseg; 160005fbcbb0SMatt Jacob if (seglim) { 160105fbcbb0SMatt Jacob int seg; 160205fbcbb0SMatt Jacob 16039e11e5beSMatt Jacob if (seglim > ISP_RQDSEG) 16049e11e5beSMatt Jacob seglim = ISP_RQDSEG; 16059e11e5beSMatt Jacob 160605fbcbb0SMatt Jacob for (seg = 0; seg < seglim; seg++, nseg--) { 160705fbcbb0SMatt Jacob /* 160805fbcbb0SMatt Jacob * Unlike normal initiator commands, we don't 160905fbcbb0SMatt Jacob * do any swizzling here. 161005fbcbb0SMatt Jacob */ 16119e11e5beSMatt Jacob cto->ct_dataseg[seg].ds_count = dm_segs->ds_len; 161205fbcbb0SMatt Jacob cto->ct_dataseg[seg].ds_base = dm_segs->ds_addr; 16139e11e5beSMatt Jacob cto->ct_xfrlen += dm_segs->ds_len; 16149e11e5beSMatt Jacob dm_segs++; 16159e11e5beSMatt Jacob } 16169e11e5beSMatt Jacob cto->ct_seg_count = seg; 16179e11e5beSMatt Jacob } else { 161805fbcbb0SMatt Jacob /* 161905fbcbb0SMatt Jacob * This case should only happen when we're sending an 162005fbcbb0SMatt Jacob * extra CTIO with final status. 162105fbcbb0SMatt Jacob */ 162205fbcbb0SMatt Jacob if (send_status == 0) { 16234fd13c1bSMatt Jacob isp_prt(isp, ISP_LOGWARN, 1624f7dddf8aSMatt Jacob "tdma_mk ran out of segments"); 162505fbcbb0SMatt Jacob mp->error = EINVAL; 162605fbcbb0SMatt Jacob return; 16279e11e5beSMatt Jacob } 162805fbcbb0SMatt Jacob } 162905fbcbb0SMatt Jacob 163005fbcbb0SMatt Jacob /* 163105fbcbb0SMatt Jacob * At this point, the fields ct_lun, ct_iid, ct_tagval, 163205fbcbb0SMatt Jacob * ct_tagtype, and ct_timeout have been carried over 163305fbcbb0SMatt Jacob * unchanged from what our caller had set. 163405fbcbb0SMatt Jacob * 163505fbcbb0SMatt Jacob * The dataseg fields and the seg_count fields we just got 163605fbcbb0SMatt Jacob * through setting. The data direction we've preserved all 163705fbcbb0SMatt Jacob * along and only clear it if we're now sending status. 163805fbcbb0SMatt Jacob */ 16399e11e5beSMatt Jacob 16404fd13c1bSMatt Jacob if (nth_ctio == nctios - 1) { 16419e11e5beSMatt Jacob /* 164205fbcbb0SMatt Jacob * We're the last in a sequence of CTIOs, so mark 164305fbcbb0SMatt Jacob * this CTIO and save the handle to the CCB such that 164405fbcbb0SMatt Jacob * when this CTIO completes we can free dma resources 164505fbcbb0SMatt Jacob * and do whatever else we need to do to finish the 1646e9a2738aSMatt Jacob * rest of the command. We *don't* give this to the 1647e9a2738aSMatt Jacob * firmware to work on- the caller will do that. 16489e11e5beSMatt Jacob */ 16494fd13c1bSMatt Jacob 16505f5aafe1SMatt Jacob cto->ct_syshandle = handle; 165105fbcbb0SMatt Jacob cto->ct_header.rqs_seqno = 1; 165205fbcbb0SMatt Jacob 165305fbcbb0SMatt Jacob if (send_status) { 16549e11e5beSMatt Jacob cto->ct_scsi_status = scsi_status; 1655b72b1569SMatt Jacob cto->ct_flags |= sflags; 165605fbcbb0SMatt Jacob cto->ct_resid = resid; 165742426921SMatt Jacob } 1658d02373f1SMatt Jacob if (send_status) { 16594fd13c1bSMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, 1660e9a2738aSMatt Jacob "CTIO[%x] lun%d iid %d tag %x ct_flags %x " 16615f5aafe1SMatt Jacob "scsi status %x resid %d", 16625f5aafe1SMatt Jacob cto->ct_fwhandle, csio->ccb_h.target_lun, 1663e9a2738aSMatt Jacob cto->ct_iid, cto->ct_tag_val, cto->ct_flags, 166405fbcbb0SMatt Jacob cto->ct_scsi_status, cto->ct_resid); 1665d02373f1SMatt Jacob } else { 16664fd13c1bSMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, 1667e9a2738aSMatt Jacob "CTIO[%x] lun%d iid%d tag %x ct_flags 0x%x", 16685f5aafe1SMatt Jacob cto->ct_fwhandle, csio->ccb_h.target_lun, 1669e9a2738aSMatt Jacob cto->ct_iid, cto->ct_tag_val, 1670e9a2738aSMatt Jacob cto->ct_flags); 167105fbcbb0SMatt Jacob } 16724fd13c1bSMatt Jacob isp_put_ctio(isp, cto, qe); 16734fd13c1bSMatt Jacob ISP_TDQE(isp, "last tdma_mk", curi, cto); 16744fd13c1bSMatt Jacob if (nctios > 1) { 16754fd13c1bSMatt Jacob MEMORYBARRIER(isp, SYNC_REQUEST, 16764fd13c1bSMatt Jacob curi, QENTRY_LEN); 16774fd13c1bSMatt Jacob } 16789e11e5beSMatt Jacob } else { 16794fd13c1bSMatt Jacob ct_entry_t *oqe = qe; 168005fbcbb0SMatt Jacob 168105fbcbb0SMatt Jacob /* 16825f5aafe1SMatt Jacob * Make sure syshandle fields are clean 168305fbcbb0SMatt Jacob */ 16845f5aafe1SMatt Jacob cto->ct_syshandle = 0; 16859e11e5beSMatt Jacob cto->ct_header.rqs_seqno = 0; 168605fbcbb0SMatt Jacob 16874fd13c1bSMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, 16885f5aafe1SMatt Jacob "CTIO[%x] lun%d for ID%d ct_flags 0x%x", 16895f5aafe1SMatt Jacob cto->ct_fwhandle, csio->ccb_h.target_lun, 16905f5aafe1SMatt Jacob cto->ct_iid, cto->ct_flags); 169105fbcbb0SMatt Jacob 169205fbcbb0SMatt Jacob /* 169305fbcbb0SMatt Jacob * Get a new CTIO 169405fbcbb0SMatt Jacob */ 16954fd13c1bSMatt Jacob qe = (ct_entry_t *) 16964fd13c1bSMatt Jacob ISP_QUEUE_ENTRY(isp->isp_rquest, nxti); 16974fd13c1bSMatt Jacob nxti = ISP_NXT_QENTRY(nxti, RQUEST_QUEUE_LEN(isp)); 16984fd13c1bSMatt Jacob if (nxti == mp->optr) { 16994fd13c1bSMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 1700f7dddf8aSMatt Jacob "Queue Overflow in tdma_mk"); 17019e11e5beSMatt Jacob mp->error = MUSHERR_NOQENTRIES; 17029e11e5beSMatt Jacob return; 17039e11e5beSMatt Jacob } 17044fd13c1bSMatt Jacob 17059e11e5beSMatt Jacob /* 17064fd13c1bSMatt Jacob * Now that we're done with the old CTIO, 17074fd13c1bSMatt Jacob * flush it out to the request queue. 17084fd13c1bSMatt Jacob */ 17094fd13c1bSMatt Jacob ISP_TDQE(isp, "dma_tgt_fc", curi, cto); 17104fd13c1bSMatt Jacob isp_put_ctio(isp, cto, oqe); 17114fd13c1bSMatt Jacob if (nth_ctio != 0) { 17124fd13c1bSMatt Jacob MEMORYBARRIER(isp, SYNC_REQUEST, curi, 17134fd13c1bSMatt Jacob QENTRY_LEN); 17144fd13c1bSMatt Jacob } 17154fd13c1bSMatt Jacob curi = ISP_NXT_QENTRY(curi, RQUEST_QUEUE_LEN(isp)); 17164fd13c1bSMatt Jacob 17174fd13c1bSMatt Jacob /* 17184fd13c1bSMatt Jacob * Reset some fields in the CTIO so we can reuse 17194fd13c1bSMatt Jacob * for the next one we'll flush to the request 17204fd13c1bSMatt Jacob * queue. 17219e11e5beSMatt Jacob */ 17229e11e5beSMatt Jacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO; 17239e11e5beSMatt Jacob cto->ct_header.rqs_entry_count = 1; 17249e11e5beSMatt Jacob cto->ct_header.rqs_flags = 0; 17259e11e5beSMatt Jacob cto->ct_status = 0; 17269e11e5beSMatt Jacob cto->ct_scsi_status = 0; 17279e11e5beSMatt Jacob cto->ct_xfrlen = 0; 17289e11e5beSMatt Jacob cto->ct_resid = 0; 17299e11e5beSMatt Jacob cto->ct_seg_count = 0; 173005fbcbb0SMatt Jacob MEMZERO(cto->ct_dataseg, sizeof(cto->ct_dataseg)); 17319e11e5beSMatt Jacob } 17329e11e5beSMatt Jacob } 17334fd13c1bSMatt Jacob *mp->nxtip = nxti; 17349e11e5beSMatt Jacob } 17359e11e5beSMatt Jacob 1736fc087171SMatt Jacob /* 1737fc087171SMatt Jacob * We don't have to do multiple CTIOs here. Instead, we can just do 1738fc087171SMatt Jacob * continuation segments as needed. This greatly simplifies the code 1739fc087171SMatt Jacob * improves performance. 1740fc087171SMatt Jacob */ 1741fc087171SMatt Jacob 17429e11e5beSMatt Jacob static void 174305fbcbb0SMatt Jacob tdma_mkfc(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 17449e11e5beSMatt Jacob { 17459e11e5beSMatt Jacob mush_t *mp; 17469e11e5beSMatt Jacob struct ccb_scsiio *csio; 17479cd7268eSMatt Jacob ispsoftc_t *isp; 17484fd13c1bSMatt Jacob ct2_entry_t *cto, *qe; 17491dae40ebSMatt Jacob uint16_t curi, nxti; 1750fc087171SMatt Jacob int segcnt; 17519e11e5beSMatt Jacob 17529e11e5beSMatt Jacob mp = (mush_t *) arg; 17539e11e5beSMatt Jacob if (error) { 17549e11e5beSMatt Jacob mp->error = error; 17559e11e5beSMatt Jacob return; 17569e11e5beSMatt Jacob } 17579e11e5beSMatt Jacob 17584fd13c1bSMatt Jacob isp = mp->isp; 175965b024e1SMatt Jacob csio = mp->cmd_token; 176065b024e1SMatt Jacob cto = mp->rq; 1761fc087171SMatt Jacob 17624fd13c1bSMatt Jacob curi = isp->isp_reqidx; 17634fd13c1bSMatt Jacob qe = (ct2_entry_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, curi); 176465b024e1SMatt Jacob 176565b024e1SMatt Jacob if (nseg == 0) { 176665b024e1SMatt Jacob if ((cto->ct_flags & CT2_FLAG_MMASK) != CT2_FLAG_MODE1) { 17674fd13c1bSMatt Jacob isp_prt(isp, ISP_LOGWARN, 1768f7dddf8aSMatt Jacob "dma2_tgt_fc, a status CTIO2 without MODE1 " 1769f7dddf8aSMatt Jacob "set (0x%x)", cto->ct_flags); 177065b024e1SMatt Jacob mp->error = EINVAL; 177165b024e1SMatt Jacob return; 177265b024e1SMatt Jacob } 177365b024e1SMatt Jacob /* 177465b024e1SMatt Jacob * We preserve ct_lun, ct_iid, ct_rxid. We set the data 177565b024e1SMatt Jacob * flags to NO DATA and clear relative offset flags. 177665b024e1SMatt Jacob * We preserve the ct_resid and the response area. 177765b024e1SMatt Jacob */ 1778fc087171SMatt Jacob cto->ct_header.rqs_seqno = 1; 177965b024e1SMatt Jacob cto->ct_seg_count = 0; 178065b024e1SMatt Jacob cto->ct_reloff = 0; 17814fd13c1bSMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, 17825f5aafe1SMatt Jacob "CTIO2[%x] lun %d->iid%d flgs 0x%x sts 0x%x ssts " 1783d02373f1SMatt Jacob "0x%x res %d", cto->ct_rxid, csio->ccb_h.target_lun, 1784d02373f1SMatt Jacob cto->ct_iid, cto->ct_flags, cto->ct_status, 178565b024e1SMatt Jacob cto->rsp.m1.ct_scsi_status, cto->ct_resid); 17864fd13c1bSMatt Jacob isp_put_ctio2(isp, cto, qe); 17874fd13c1bSMatt Jacob ISP_TDQE(isp, "dma2_tgt_fc[no data]", curi, qe); 17889e11e5beSMatt Jacob return; 17899e11e5beSMatt Jacob } 17909e11e5beSMatt Jacob 179165b024e1SMatt Jacob if ((cto->ct_flags & CT2_FLAG_MMASK) != CT2_FLAG_MODE0) { 1792fc087171SMatt Jacob isp_prt(isp, ISP_LOGERR, 1793f7dddf8aSMatt Jacob "dma2_tgt_fc, a data CTIO2 without MODE0 set " 1794f7dddf8aSMatt Jacob "(0x%x)", cto->ct_flags); 179565b024e1SMatt Jacob mp->error = EINVAL; 179665b024e1SMatt Jacob return; 179765b024e1SMatt Jacob } 179865b024e1SMatt Jacob 179965b024e1SMatt Jacob 18004fd13c1bSMatt Jacob nxti = *mp->nxtip; 18014fd13c1bSMatt Jacob 1802fc087171SMatt Jacob /* 1803fc087171SMatt Jacob * Set up the CTIO2 data segments. 1804fc087171SMatt Jacob */ 1805fc087171SMatt Jacob for (segcnt = 0; cto->ct_seg_count < ISP_RQDSEG_T2 && segcnt < nseg; 1806fc087171SMatt Jacob cto->ct_seg_count++, segcnt++) { 1807fc087171SMatt Jacob cto->rsp.m0.ct_dataseg[cto->ct_seg_count].ds_base = 1808fc087171SMatt Jacob dm_segs[segcnt].ds_addr; 1809fc087171SMatt Jacob cto->rsp.m0.ct_dataseg[cto->ct_seg_count].ds_count = 1810fc087171SMatt Jacob dm_segs[segcnt].ds_len; 1811fc087171SMatt Jacob cto->rsp.m0.ct_xfrlen += dm_segs[segcnt].ds_len; 18129cd7268eSMatt Jacob #if __FreeBSD_version < 500000 18139cd7268eSMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, 18149cd7268eSMatt Jacob "isp_send_ctio2: ent0[%d]0x%llx:%llu", 18159cd7268eSMatt Jacob cto->ct_seg_count, (uint64_t)dm_segs[segcnt].ds_addr, 18169cd7268eSMatt Jacob (uint64_t)dm_segs[segcnt].ds_len); 18179cd7268eSMatt Jacob #else 181876514802SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, 181974a96f43SJohn Baldwin "isp_send_ctio2: ent0[%d]0x%jx:%ju", 182074a96f43SJohn Baldwin cto->ct_seg_count, (uintmax_t)dm_segs[segcnt].ds_addr, 182174a96f43SJohn Baldwin (uintmax_t)dm_segs[segcnt].ds_len); 18229cd7268eSMatt Jacob #endif 1823fc087171SMatt Jacob } 18249e11e5beSMatt Jacob 1825fc087171SMatt Jacob while (segcnt < nseg) { 18261dae40ebSMatt Jacob uint16_t curip; 18274fd13c1bSMatt Jacob int seg; 1828fc087171SMatt Jacob ispcontreq_t local, *crq = &local, *qep; 18299e11e5beSMatt Jacob 1830fc087171SMatt Jacob qep = (ispcontreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, nxti); 1831fc087171SMatt Jacob curip = nxti; 1832fc087171SMatt Jacob nxti = ISP_NXT_QENTRY(curip, RQUEST_QUEUE_LEN(isp)); 18334fd13c1bSMatt Jacob if (nxti == mp->optr) { 1834fc087171SMatt Jacob ISP_UNLOCK(isp); 1835fc087171SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, 1836fc087171SMatt Jacob "tdma_mkfc: request queue overflow"); 18379e11e5beSMatt Jacob mp->error = MUSHERR_NOQENTRIES; 18389e11e5beSMatt Jacob return; 18399e11e5beSMatt Jacob } 1840fc087171SMatt Jacob cto->ct_header.rqs_entry_count++; 1841fc087171SMatt Jacob MEMZERO((void *)crq, sizeof (*crq)); 1842fc087171SMatt Jacob crq->req_header.rqs_entry_count = 1; 1843fc087171SMatt Jacob crq->req_header.rqs_entry_type = RQSTYPE_DATASEG; 1844fc087171SMatt Jacob for (seg = 0; segcnt < nseg && seg < ISP_CDSEG; 1845fc087171SMatt Jacob segcnt++, seg++) { 1846fc087171SMatt Jacob crq->req_dataseg[seg].ds_base = dm_segs[segcnt].ds_addr; 1847fc087171SMatt Jacob crq->req_dataseg[seg].ds_count = dm_segs[segcnt].ds_len; 18489cd7268eSMatt Jacob #if __FreeBSD_version < 500000 18499cd7268eSMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, 18509cd7268eSMatt Jacob "isp_send_ctio2: ent%d[%d]%llx:%llu", 18519cd7268eSMatt Jacob cto->ct_header.rqs_entry_count-1, seg, 18529cd7268eSMatt Jacob (uint64_t)dm_segs[segcnt].ds_addr, 18539cd7268eSMatt Jacob (uint64_t)dm_segs[segcnt].ds_len); 18549cd7268eSMatt Jacob #else 1855fc087171SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, 185674a96f43SJohn Baldwin "isp_send_ctio2: ent%d[%d]%jx:%ju", 1857fc087171SMatt Jacob cto->ct_header.rqs_entry_count-1, seg, 185874a96f43SJohn Baldwin (uintmax_t)dm_segs[segcnt].ds_addr, 185974a96f43SJohn Baldwin (uintmax_t)dm_segs[segcnt].ds_len); 18609cd7268eSMatt Jacob #endif 1861fc087171SMatt Jacob cto->rsp.m0.ct_xfrlen += dm_segs[segcnt].ds_len; 1862fc087171SMatt Jacob cto->ct_seg_count++; 1863fc087171SMatt Jacob } 1864fc087171SMatt Jacob MEMORYBARRIER(isp, SYNC_REQUEST, curip, QENTRY_LEN); 1865fc087171SMatt Jacob isp_put_cont_req(isp, crq, qep); 1866fc087171SMatt Jacob ISP_TDQE(isp, "cont entry", curi, qep); 1867fc087171SMatt Jacob } 186865b024e1SMatt Jacob 18699e11e5beSMatt Jacob /* 1870fc087171SMatt Jacob * No do final twiddling for the CTIO itself. 18714fd13c1bSMatt Jacob */ 1872fc087171SMatt Jacob cto->ct_header.rqs_seqno = 1; 1873fc087171SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, 1874fc087171SMatt Jacob "CTIO2[%x] lun %d->iid%d flgs 0x%x sts 0x%x ssts 0x%x resid %d", 1875fc087171SMatt Jacob cto->ct_rxid, csio->ccb_h.target_lun, (int) cto->ct_iid, 1876fc087171SMatt Jacob cto->ct_flags, cto->ct_status, cto->rsp.m1.ct_scsi_status, 1877fc087171SMatt Jacob cto->ct_resid); 1878fc087171SMatt Jacob isp_put_ctio2(isp, cto, qe); 1879fc087171SMatt Jacob ISP_TDQE(isp, "last dma2_tgt_fc", curi, qe); 18804fd13c1bSMatt Jacob *mp->nxtip = nxti; 18819e11e5beSMatt Jacob } 18829e11e5beSMatt Jacob #endif 18839e11e5beSMatt Jacob 18841dae40ebSMatt Jacob static void dma2_a64(void *, bus_dma_segment_t *, int, int); 1885126ec864SMatt Jacob static void dma2(void *, bus_dma_segment_t *, int, int); 18869e11e5beSMatt Jacob 18876de9bf77SMatt Jacob static void 18881dae40ebSMatt Jacob dma2_a64(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 18896de9bf77SMatt Jacob { 18906de9bf77SMatt Jacob mush_t *mp; 18919cd7268eSMatt Jacob ispsoftc_t *isp; 18926de9bf77SMatt Jacob struct ccb_scsiio *csio; 18936de9bf77SMatt Jacob struct isp_pcisoftc *pcs; 18946de9bf77SMatt Jacob bus_dmamap_t *dp; 18956de9bf77SMatt Jacob bus_dma_segment_t *eseg; 18966de9bf77SMatt Jacob ispreq64_t *rq; 18976de9bf77SMatt Jacob int seglim, datalen; 18981dae40ebSMatt Jacob uint16_t nxti; 18996de9bf77SMatt Jacob 19006de9bf77SMatt Jacob mp = (mush_t *) arg; 19016de9bf77SMatt Jacob if (error) { 19026de9bf77SMatt Jacob mp->error = error; 19036de9bf77SMatt Jacob return; 19046de9bf77SMatt Jacob } 19056de9bf77SMatt Jacob 19066de9bf77SMatt Jacob if (nseg < 1) { 19076de9bf77SMatt Jacob isp_prt(mp->isp, ISP_LOGERR, "bad segment count (%d)", nseg); 19086de9bf77SMatt Jacob mp->error = EFAULT; 19096de9bf77SMatt Jacob return; 19106de9bf77SMatt Jacob } 19116de9bf77SMatt Jacob csio = mp->cmd_token; 19126de9bf77SMatt Jacob isp = mp->isp; 19136de9bf77SMatt Jacob rq = mp->rq; 19146de9bf77SMatt Jacob pcs = (struct isp_pcisoftc *)mp->isp; 19156de9bf77SMatt Jacob dp = &pcs->dmaps[isp_handle_index(rq->req_handle)]; 19166de9bf77SMatt Jacob nxti = *mp->nxtip; 19176de9bf77SMatt Jacob 19186de9bf77SMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 19196de9bf77SMatt Jacob bus_dmamap_sync(pcs->dmat, *dp, BUS_DMASYNC_PREREAD); 19206de9bf77SMatt Jacob } else { 19216de9bf77SMatt Jacob bus_dmamap_sync(pcs->dmat, *dp, BUS_DMASYNC_PREWRITE); 19226de9bf77SMatt Jacob } 19236de9bf77SMatt Jacob datalen = XS_XFRLEN(csio); 19246de9bf77SMatt Jacob 19256de9bf77SMatt Jacob /* 19266de9bf77SMatt Jacob * We're passed an initial partially filled in entry that 19276de9bf77SMatt Jacob * has most fields filled in except for data transfer 19286de9bf77SMatt Jacob * related values. 19296de9bf77SMatt Jacob * 19306de9bf77SMatt Jacob * Our job is to fill in the initial request queue entry and 19316de9bf77SMatt Jacob * then to start allocating and filling in continuation entries 19326de9bf77SMatt Jacob * until we've covered the entire transfer. 19336de9bf77SMatt Jacob */ 19346de9bf77SMatt Jacob 19356de9bf77SMatt Jacob if (IS_FC(isp)) { 193669767099SMatt Jacob rq->req_header.rqs_entry_type = RQSTYPE_T3RQS; 19376de9bf77SMatt Jacob seglim = ISP_RQDSEG_T3; 19386de9bf77SMatt Jacob ((ispreqt3_t *)rq)->req_totalcnt = datalen; 19396de9bf77SMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 19406de9bf77SMatt Jacob ((ispreqt3_t *)rq)->req_flags |= REQFLAG_DATA_IN; 19416de9bf77SMatt Jacob } else { 19426de9bf77SMatt Jacob ((ispreqt3_t *)rq)->req_flags |= REQFLAG_DATA_OUT; 19436de9bf77SMatt Jacob } 19446de9bf77SMatt Jacob } else { 194569767099SMatt Jacob rq->req_header.rqs_entry_type = RQSTYPE_A64; 19466de9bf77SMatt Jacob if (csio->cdb_len > 12) { 19476de9bf77SMatt Jacob seglim = 0; 19486de9bf77SMatt Jacob } else { 19496de9bf77SMatt Jacob seglim = ISP_RQDSEG_A64; 19506de9bf77SMatt Jacob } 19516de9bf77SMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 19526de9bf77SMatt Jacob rq->req_flags |= REQFLAG_DATA_IN; 19536de9bf77SMatt Jacob } else { 19546de9bf77SMatt Jacob rq->req_flags |= REQFLAG_DATA_OUT; 19556de9bf77SMatt Jacob } 19566de9bf77SMatt Jacob } 19576de9bf77SMatt Jacob 19586de9bf77SMatt Jacob eseg = dm_segs + nseg; 19596de9bf77SMatt Jacob 19606de9bf77SMatt Jacob while (datalen != 0 && rq->req_seg_count < seglim && dm_segs != eseg) { 19616de9bf77SMatt Jacob if (IS_FC(isp)) { 19626de9bf77SMatt Jacob ispreqt3_t *rq3 = (ispreqt3_t *)rq; 19636de9bf77SMatt Jacob rq3->req_dataseg[rq3->req_seg_count].ds_base = 19641dae40ebSMatt Jacob DMA_LO32(dm_segs->ds_addr); 196569767099SMatt Jacob rq3->req_dataseg[rq3->req_seg_count].ds_basehi = 19661dae40ebSMatt Jacob DMA_HI32(dm_segs->ds_addr); 19676de9bf77SMatt Jacob rq3->req_dataseg[rq3->req_seg_count].ds_count = 19686de9bf77SMatt Jacob dm_segs->ds_len; 19696de9bf77SMatt Jacob } else { 19706de9bf77SMatt Jacob rq->req_dataseg[rq->req_seg_count].ds_base = 19711dae40ebSMatt Jacob DMA_LO32(dm_segs->ds_addr); 197269767099SMatt Jacob rq->req_dataseg[rq->req_seg_count].ds_basehi = 19731dae40ebSMatt Jacob DMA_HI32(dm_segs->ds_addr); 19746de9bf77SMatt Jacob rq->req_dataseg[rq->req_seg_count].ds_count = 19756de9bf77SMatt Jacob dm_segs->ds_len; 19766de9bf77SMatt Jacob } 19776de9bf77SMatt Jacob datalen -= dm_segs->ds_len; 19786de9bf77SMatt Jacob rq->req_seg_count++; 19796de9bf77SMatt Jacob dm_segs++; 19806de9bf77SMatt Jacob } 19816de9bf77SMatt Jacob 19826de9bf77SMatt Jacob while (datalen > 0 && dm_segs != eseg) { 19831dae40ebSMatt Jacob uint16_t onxti; 19846de9bf77SMatt Jacob ispcontreq64_t local, *crq = &local, *cqe; 19856de9bf77SMatt Jacob 19866de9bf77SMatt Jacob cqe = (ispcontreq64_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, nxti); 19876de9bf77SMatt Jacob onxti = nxti; 19886de9bf77SMatt Jacob nxti = ISP_NXT_QENTRY(onxti, RQUEST_QUEUE_LEN(isp)); 19896de9bf77SMatt Jacob if (nxti == mp->optr) { 19906de9bf77SMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, "Request Queue Overflow++"); 19916de9bf77SMatt Jacob mp->error = MUSHERR_NOQENTRIES; 19926de9bf77SMatt Jacob return; 19936de9bf77SMatt Jacob } 19946de9bf77SMatt Jacob rq->req_header.rqs_entry_count++; 19956de9bf77SMatt Jacob MEMZERO((void *)crq, sizeof (*crq)); 19966de9bf77SMatt Jacob crq->req_header.rqs_entry_count = 1; 19976de9bf77SMatt Jacob crq->req_header.rqs_entry_type = RQSTYPE_A64_CONT; 19986de9bf77SMatt Jacob 19996de9bf77SMatt Jacob seglim = 0; 20006de9bf77SMatt Jacob while (datalen > 0 && seglim < ISP_CDSEG64 && dm_segs != eseg) { 20016de9bf77SMatt Jacob crq->req_dataseg[seglim].ds_base = 20021dae40ebSMatt Jacob DMA_LO32(dm_segs->ds_addr); 200369767099SMatt Jacob crq->req_dataseg[seglim].ds_basehi = 20041dae40ebSMatt Jacob DMA_HI32(dm_segs->ds_addr); 20056de9bf77SMatt Jacob crq->req_dataseg[seglim].ds_count = 20066de9bf77SMatt Jacob dm_segs->ds_len; 20076de9bf77SMatt Jacob rq->req_seg_count++; 20086de9bf77SMatt Jacob dm_segs++; 20096de9bf77SMatt Jacob seglim++; 20106de9bf77SMatt Jacob datalen -= dm_segs->ds_len; 20116de9bf77SMatt Jacob } 20126de9bf77SMatt Jacob isp_put_cont64_req(isp, crq, cqe); 20136de9bf77SMatt Jacob MEMORYBARRIER(isp, SYNC_REQUEST, onxti, QENTRY_LEN); 20146de9bf77SMatt Jacob } 20156de9bf77SMatt Jacob *mp->nxtip = nxti; 20166de9bf77SMatt Jacob } 20171dae40ebSMatt Jacob 20189e11e5beSMatt Jacob static void 20199e11e5beSMatt Jacob dma2(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 20209e11e5beSMatt Jacob { 20219e11e5beSMatt Jacob mush_t *mp; 20229cd7268eSMatt Jacob ispsoftc_t *isp; 20239e11e5beSMatt Jacob struct ccb_scsiio *csio; 20241923f739SMatt Jacob struct isp_pcisoftc *pcs; 20259e11e5beSMatt Jacob bus_dmamap_t *dp; 20269e11e5beSMatt Jacob bus_dma_segment_t *eseg; 20279e11e5beSMatt Jacob ispreq_t *rq; 20289e11e5beSMatt Jacob int seglim, datalen; 20291dae40ebSMatt Jacob uint16_t nxti; 20309e11e5beSMatt Jacob 20319e11e5beSMatt Jacob mp = (mush_t *) arg; 20329e11e5beSMatt Jacob if (error) { 20339e11e5beSMatt Jacob mp->error = error; 20349e11e5beSMatt Jacob return; 20359e11e5beSMatt Jacob } 20369e11e5beSMatt Jacob 20379e11e5beSMatt Jacob if (nseg < 1) { 2038f7dddf8aSMatt Jacob isp_prt(mp->isp, ISP_LOGERR, "bad segment count (%d)", nseg); 20399e11e5beSMatt Jacob mp->error = EFAULT; 20409e11e5beSMatt Jacob return; 20419e11e5beSMatt Jacob } 20429e11e5beSMatt Jacob csio = mp->cmd_token; 20434fd13c1bSMatt Jacob isp = mp->isp; 20449e11e5beSMatt Jacob rq = mp->rq; 20451923f739SMatt Jacob pcs = (struct isp_pcisoftc *)mp->isp; 20461923f739SMatt Jacob dp = &pcs->dmaps[isp_handle_index(rq->req_handle)]; 20474fd13c1bSMatt Jacob nxti = *mp->nxtip; 20489e11e5beSMatt Jacob 20499e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 20501923f739SMatt Jacob bus_dmamap_sync(pcs->dmat, *dp, BUS_DMASYNC_PREREAD); 20519e11e5beSMatt Jacob } else { 20521923f739SMatt Jacob bus_dmamap_sync(pcs->dmat, *dp, BUS_DMASYNC_PREWRITE); 20539e11e5beSMatt Jacob } 20549e11e5beSMatt Jacob 20559e11e5beSMatt Jacob datalen = XS_XFRLEN(csio); 20569e11e5beSMatt Jacob 20579e11e5beSMatt Jacob /* 20589e11e5beSMatt Jacob * We're passed an initial partially filled in entry that 20599e11e5beSMatt Jacob * has most fields filled in except for data transfer 20609e11e5beSMatt Jacob * related values. 20619e11e5beSMatt Jacob * 20629e11e5beSMatt Jacob * Our job is to fill in the initial request queue entry and 20639e11e5beSMatt Jacob * then to start allocating and filling in continuation entries 20649e11e5beSMatt Jacob * until we've covered the entire transfer. 20659e11e5beSMatt Jacob */ 20669e11e5beSMatt Jacob 20674fd13c1bSMatt Jacob if (IS_FC(isp)) { 2068d720e6d5SJustin T. Gibbs seglim = ISP_RQDSEG_T2; 2069d720e6d5SJustin T. Gibbs ((ispreqt2_t *)rq)->req_totalcnt = datalen; 20709e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 20719e11e5beSMatt Jacob ((ispreqt2_t *)rq)->req_flags |= REQFLAG_DATA_IN; 20729e11e5beSMatt Jacob } else { 20739e11e5beSMatt Jacob ((ispreqt2_t *)rq)->req_flags |= REQFLAG_DATA_OUT; 20749e11e5beSMatt Jacob } 2075d720e6d5SJustin T. Gibbs } else { 2076e142669aSMatt Jacob if (csio->cdb_len > 12) { 2077e142669aSMatt Jacob seglim = 0; 2078e142669aSMatt Jacob } else { 2079d720e6d5SJustin T. Gibbs seglim = ISP_RQDSEG; 2080e142669aSMatt Jacob } 20819e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 20829e11e5beSMatt Jacob rq->req_flags |= REQFLAG_DATA_IN; 20839e11e5beSMatt Jacob } else { 20849e11e5beSMatt Jacob rq->req_flags |= REQFLAG_DATA_OUT; 20859e11e5beSMatt Jacob } 2086d720e6d5SJustin T. Gibbs } 2087d720e6d5SJustin T. Gibbs 2088d720e6d5SJustin T. Gibbs eseg = dm_segs + nseg; 2089d720e6d5SJustin T. Gibbs 2090d720e6d5SJustin T. Gibbs while (datalen != 0 && rq->req_seg_count < seglim && dm_segs != eseg) { 20914fd13c1bSMatt Jacob if (IS_FC(isp)) { 2092d720e6d5SJustin T. Gibbs ispreqt2_t *rq2 = (ispreqt2_t *)rq; 2093d720e6d5SJustin T. Gibbs rq2->req_dataseg[rq2->req_seg_count].ds_base = 20941dae40ebSMatt Jacob DMA_LO32(dm_segs->ds_addr); 2095d720e6d5SJustin T. Gibbs rq2->req_dataseg[rq2->req_seg_count].ds_count = 2096d720e6d5SJustin T. Gibbs dm_segs->ds_len; 2097d720e6d5SJustin T. Gibbs } else { 2098d720e6d5SJustin T. Gibbs rq->req_dataseg[rq->req_seg_count].ds_base = 20991dae40ebSMatt Jacob DMA_LO32(dm_segs->ds_addr); 2100d720e6d5SJustin T. Gibbs rq->req_dataseg[rq->req_seg_count].ds_count = 2101d720e6d5SJustin T. Gibbs dm_segs->ds_len; 2102d720e6d5SJustin T. Gibbs } 2103d720e6d5SJustin T. Gibbs datalen -= dm_segs->ds_len; 2104d720e6d5SJustin T. Gibbs rq->req_seg_count++; 2105d720e6d5SJustin T. Gibbs dm_segs++; 2106d720e6d5SJustin T. Gibbs } 2107d720e6d5SJustin T. Gibbs 2108d720e6d5SJustin T. Gibbs while (datalen > 0 && dm_segs != eseg) { 21091dae40ebSMatt Jacob uint16_t onxti; 21104fd13c1bSMatt Jacob ispcontreq_t local, *crq = &local, *cqe; 21114fd13c1bSMatt Jacob 21124fd13c1bSMatt Jacob cqe = (ispcontreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, nxti); 21134fd13c1bSMatt Jacob onxti = nxti; 21144fd13c1bSMatt Jacob nxti = ISP_NXT_QENTRY(onxti, RQUEST_QUEUE_LEN(isp)); 21154fd13c1bSMatt Jacob if (nxti == mp->optr) { 21164fd13c1bSMatt Jacob isp_prt(isp, ISP_LOGDEBUG0, "Request Queue Overflow++"); 21174873663cSMatt Jacob mp->error = MUSHERR_NOQENTRIES; 2118d720e6d5SJustin T. Gibbs return; 2119d720e6d5SJustin T. Gibbs } 2120d720e6d5SJustin T. Gibbs rq->req_header.rqs_entry_count++; 21214fd13c1bSMatt Jacob MEMZERO((void *)crq, sizeof (*crq)); 2122d720e6d5SJustin T. Gibbs crq->req_header.rqs_entry_count = 1; 2123d720e6d5SJustin T. Gibbs crq->req_header.rqs_entry_type = RQSTYPE_DATASEG; 2124d720e6d5SJustin T. Gibbs 2125d720e6d5SJustin T. Gibbs seglim = 0; 2126d720e6d5SJustin T. Gibbs while (datalen > 0 && seglim < ISP_CDSEG && dm_segs != eseg) { 2127d720e6d5SJustin T. Gibbs crq->req_dataseg[seglim].ds_base = 21281dae40ebSMatt Jacob DMA_LO32(dm_segs->ds_addr); 2129d720e6d5SJustin T. Gibbs crq->req_dataseg[seglim].ds_count = 2130d720e6d5SJustin T. Gibbs dm_segs->ds_len; 2131d720e6d5SJustin T. Gibbs rq->req_seg_count++; 2132d720e6d5SJustin T. Gibbs dm_segs++; 2133d720e6d5SJustin T. Gibbs seglim++; 2134d720e6d5SJustin T. Gibbs datalen -= dm_segs->ds_len; 2135d720e6d5SJustin T. Gibbs } 21364fd13c1bSMatt Jacob isp_put_cont_req(isp, crq, cqe); 21374fd13c1bSMatt Jacob MEMORYBARRIER(isp, SYNC_REQUEST, onxti, QENTRY_LEN); 2138d720e6d5SJustin T. Gibbs } 21394fd13c1bSMatt Jacob *mp->nxtip = nxti; 2140d720e6d5SJustin T. Gibbs } 2141d720e6d5SJustin T. Gibbs 21429cd7268eSMatt Jacob /* 21439cd7268eSMatt Jacob * We enter with ISP_LOCK held 21449cd7268eSMatt Jacob */ 2145d720e6d5SJustin T. Gibbs static int 21469cd7268eSMatt Jacob isp_pci_dmasetup(ispsoftc_t *isp, struct ccb_scsiio *csio, ispreq_t *rq, 21471dae40ebSMatt Jacob uint16_t *nxtip, uint16_t optr) 2148d720e6d5SJustin T. Gibbs { 21491923f739SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *)isp; 21504fd13c1bSMatt Jacob ispreq_t *qep; 21510a5f7e8bSMatt Jacob bus_dmamap_t *dp = NULL; 2152d720e6d5SJustin T. Gibbs mush_t mush, *mp; 2153126ec864SMatt Jacob void (*eptr)(void *, bus_dma_segment_t *, int, int); 2154d720e6d5SJustin T. Gibbs 21554fd13c1bSMatt Jacob qep = (ispreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, isp->isp_reqidx); 215665b024e1SMatt Jacob #ifdef ISP_TARGET_MODE 215765b024e1SMatt Jacob if (csio->ccb_h.func_code == XPT_CONT_TARGET_IO) { 215865b024e1SMatt Jacob if (IS_FC(isp)) { 215905fbcbb0SMatt Jacob eptr = tdma_mkfc; 216065b024e1SMatt Jacob } else { 216105fbcbb0SMatt Jacob eptr = tdma_mk; 216265b024e1SMatt Jacob } 216305fbcbb0SMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE || 216405fbcbb0SMatt Jacob (csio->dxfer_len == 0)) { 216565b024e1SMatt Jacob mp = &mush; 216665b024e1SMatt Jacob mp->isp = isp; 216765b024e1SMatt Jacob mp->cmd_token = csio; 2168e9a2738aSMatt Jacob mp->rq = rq; /* really a ct_entry_t or ct2_entry_t */ 21694fd13c1bSMatt Jacob mp->nxtip = nxtip; 217065b024e1SMatt Jacob mp->optr = optr; 217165b024e1SMatt Jacob mp->error = 0; 21729cd7268eSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 217365b024e1SMatt Jacob (*eptr)(mp, NULL, 0, 0); 21749cd7268eSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 21754fd13c1bSMatt Jacob goto mbxsync; 217665b024e1SMatt Jacob } 217765b024e1SMatt Jacob } else 217865b024e1SMatt Jacob #endif 21791dae40ebSMatt Jacob if (sizeof (bus_addr_t) > 4) { 21801dae40ebSMatt Jacob eptr = dma2_a64; 21811dae40ebSMatt Jacob } else { 218265b024e1SMatt Jacob eptr = dma2; 21831dae40ebSMatt Jacob } 218465b024e1SMatt Jacob 21854fd13c1bSMatt Jacob 218605fbcbb0SMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE || 218705fbcbb0SMatt Jacob (csio->dxfer_len == 0)) { 218842426921SMatt Jacob rq->req_seg_count = 1; 21894fd13c1bSMatt Jacob goto mbxsync; 219042426921SMatt Jacob } 219142426921SMatt Jacob 2192d720e6d5SJustin T. Gibbs /* 2193d720e6d5SJustin T. Gibbs * Do a virtual grapevine step to collect info for 21944873663cSMatt Jacob * the callback dma allocation that we have to use... 2195d720e6d5SJustin T. Gibbs */ 2196d720e6d5SJustin T. Gibbs mp = &mush; 2197d720e6d5SJustin T. Gibbs mp->isp = isp; 21989e11e5beSMatt Jacob mp->cmd_token = csio; 2199d720e6d5SJustin T. Gibbs mp->rq = rq; 22004fd13c1bSMatt Jacob mp->nxtip = nxtip; 2201d720e6d5SJustin T. Gibbs mp->optr = optr; 2202d720e6d5SJustin T. Gibbs mp->error = 0; 2203d720e6d5SJustin T. Gibbs 22049cd7268eSMatt Jacob ISPLOCK_2_CAMLOCK(isp); 22059e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_SCATTER_VALID) == 0) { 22069e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DATA_PHYS) == 0) { 22074873663cSMatt Jacob int error, s; 22081923f739SMatt Jacob dp = &pcs->dmaps[isp_handle_index(rq->req_handle)]; 2209d720e6d5SJustin T. Gibbs s = splsoftvm(); 22101923f739SMatt Jacob error = bus_dmamap_load(pcs->dmat, *dp, 22119e11e5beSMatt Jacob csio->data_ptr, csio->dxfer_len, eptr, mp, 0); 2212d720e6d5SJustin T. Gibbs if (error == EINPROGRESS) { 22131923f739SMatt Jacob bus_dmamap_unload(pcs->dmat, *dp); 2214d720e6d5SJustin T. Gibbs mp->error = EINVAL; 2215f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 2216f7dddf8aSMatt Jacob "deferred dma allocation not supported"); 2217d720e6d5SJustin T. Gibbs } else if (error && mp->error == 0) { 22180a5f7e8bSMatt Jacob #ifdef DIAGNOSTIC 22196e5c5328SMatt Jacob isp_prt(isp, ISP_LOGERR, 22206e5c5328SMatt Jacob "error %d in dma mapping code", error); 22210a5f7e8bSMatt Jacob #endif 2222d720e6d5SJustin T. Gibbs mp->error = error; 2223d720e6d5SJustin T. Gibbs } 22244873663cSMatt Jacob splx(s); 2225d720e6d5SJustin T. Gibbs } else { 2226d720e6d5SJustin T. Gibbs /* Pointer to physical buffer */ 2227d720e6d5SJustin T. Gibbs struct bus_dma_segment seg; 22286de9bf77SMatt Jacob seg.ds_addr = (bus_addr_t)(vm_offset_t)csio->data_ptr; 2229d720e6d5SJustin T. Gibbs seg.ds_len = csio->dxfer_len; 22309e11e5beSMatt Jacob (*eptr)(mp, &seg, 1, 0); 2231d720e6d5SJustin T. Gibbs } 2232d720e6d5SJustin T. Gibbs } else { 2233d720e6d5SJustin T. Gibbs struct bus_dma_segment *segs; 2234d720e6d5SJustin T. Gibbs 22359e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DATA_PHYS) != 0) { 2236f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 2237f7dddf8aSMatt Jacob "Physical segment pointers unsupported"); 2238d720e6d5SJustin T. Gibbs mp->error = EINVAL; 22399e11e5beSMatt Jacob } else if ((csio->ccb_h.flags & CAM_SG_LIST_PHYS) == 0) { 2240f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 2241f7dddf8aSMatt Jacob "Virtual segment addresses unsupported"); 2242d720e6d5SJustin T. Gibbs mp->error = EINVAL; 2243d720e6d5SJustin T. Gibbs } else { 2244d720e6d5SJustin T. Gibbs /* Just use the segments provided */ 2245d720e6d5SJustin T. Gibbs segs = (struct bus_dma_segment *) csio->data_ptr; 22469e11e5beSMatt Jacob (*eptr)(mp, segs, csio->sglist_cnt, 0); 2247d720e6d5SJustin T. Gibbs } 2248d720e6d5SJustin T. Gibbs } 22499cd7268eSMatt Jacob CAMLOCK_2_ISPLOCK(isp); 2250d720e6d5SJustin T. Gibbs if (mp->error) { 22514873663cSMatt Jacob int retval = CMD_COMPLETE; 22524873663cSMatt Jacob if (mp->error == MUSHERR_NOQENTRIES) { 22534873663cSMatt Jacob retval = CMD_EAGAIN; 22544873663cSMatt Jacob } else if (mp->error == EFBIG) { 22550a5f7e8bSMatt Jacob XS_SETERR(csio, CAM_REQ_TOO_BIG); 2256d720e6d5SJustin T. Gibbs } else if (mp->error == EINVAL) { 22570a5f7e8bSMatt Jacob XS_SETERR(csio, CAM_REQ_INVALID); 2258d720e6d5SJustin T. Gibbs } else { 22590a5f7e8bSMatt Jacob XS_SETERR(csio, CAM_UNREC_HBA_ERROR); 2260d720e6d5SJustin T. Gibbs } 22614873663cSMatt Jacob return (retval); 22620a5f7e8bSMatt Jacob } 22634fd13c1bSMatt Jacob mbxsync: 22644fd13c1bSMatt Jacob switch (rq->req_header.rqs_entry_type) { 22654fd13c1bSMatt Jacob case RQSTYPE_REQUEST: 22664fd13c1bSMatt Jacob isp_put_request(isp, rq, qep); 22674fd13c1bSMatt Jacob break; 22684fd13c1bSMatt Jacob case RQSTYPE_CMDONLY: 22694fd13c1bSMatt Jacob isp_put_extended_request(isp, (ispextreq_t *)rq, 22704fd13c1bSMatt Jacob (ispextreq_t *)qep); 22714fd13c1bSMatt Jacob break; 22724fd13c1bSMatt Jacob case RQSTYPE_T2RQS: 22734fd13c1bSMatt Jacob isp_put_request_t2(isp, (ispreqt2_t *) rq, (ispreqt2_t *) qep); 22744fd13c1bSMatt Jacob break; 22756de9bf77SMatt Jacob case RQSTYPE_A64: 22766de9bf77SMatt Jacob case RQSTYPE_T3RQS: 22776de9bf77SMatt Jacob isp_put_request_t3(isp, (ispreqt3_t *) rq, (ispreqt3_t *) qep); 22786de9bf77SMatt Jacob break; 22790a5f7e8bSMatt Jacob } 22804873663cSMatt Jacob return (CMD_QUEUED); 2281d720e6d5SJustin T. Gibbs } 2282d720e6d5SJustin T. Gibbs 2283d720e6d5SJustin T. Gibbs static void 22849cd7268eSMatt Jacob isp_pci_dmateardown(ispsoftc_t *isp, XS_T *xs, uint16_t handle) 2285d720e6d5SJustin T. Gibbs { 22861923f739SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *)isp; 22871923f739SMatt Jacob bus_dmamap_t *dp = &pcs->dmaps[isp_handle_index(handle)]; 2288a95ae193SMatt Jacob if ((xs->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 22891923f739SMatt Jacob bus_dmamap_sync(pcs->dmat, *dp, BUS_DMASYNC_POSTREAD); 2290d720e6d5SJustin T. Gibbs } else { 22911923f739SMatt Jacob bus_dmamap_sync(pcs->dmat, *dp, BUS_DMASYNC_POSTWRITE); 2292d720e6d5SJustin T. Gibbs } 22931923f739SMatt Jacob bus_dmamap_unload(pcs->dmat, *dp); 2294d720e6d5SJustin T. Gibbs } 2295d720e6d5SJustin T. Gibbs 229665adb54cSMatt Jacob 229765adb54cSMatt Jacob static void 22989cd7268eSMatt Jacob isp_pci_reset1(ispsoftc_t *isp) 229965adb54cSMatt Jacob { 230065adb54cSMatt Jacob /* Make sure the BIOS is disabled */ 230165adb54cSMatt Jacob isp_pci_wr_reg(isp, HCCR, PCI_HCCR_CMD_BIOS); 2302469b6b9eSMatt Jacob /* and enable interrupts */ 2303469b6b9eSMatt Jacob ENABLE_INTS(isp); 230465adb54cSMatt Jacob } 230565adb54cSMatt Jacob 230665adb54cSMatt Jacob static void 23079cd7268eSMatt Jacob isp_pci_dumpregs(ispsoftc_t *isp, const char *msg) 230865adb54cSMatt Jacob { 23091923f739SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *)isp; 2310d02373f1SMatt Jacob if (msg) 23116e5c5328SMatt Jacob printf("%s: %s\n", device_get_nameunit(isp->isp_dev), msg); 23126e5c5328SMatt Jacob else 23136e5c5328SMatt Jacob printf("%s:\n", device_get_nameunit(isp->isp_dev)); 2314d02373f1SMatt Jacob if (IS_SCSI(isp)) 2315d02373f1SMatt Jacob printf(" biu_conf1=%x", ISP_READ(isp, BIU_CONF1)); 2316d02373f1SMatt Jacob else 2317d02373f1SMatt Jacob printf(" biu_csr=%x", ISP_READ(isp, BIU2100_CSR)); 2318d02373f1SMatt Jacob printf(" biu_icr=%x biu_isr=%x biu_sema=%x ", ISP_READ(isp, BIU_ICR), 2319d02373f1SMatt Jacob ISP_READ(isp, BIU_ISR), ISP_READ(isp, BIU_SEMA)); 2320d02373f1SMatt Jacob printf("risc_hccr=%x\n", ISP_READ(isp, HCCR)); 2321d02373f1SMatt Jacob 2322d02373f1SMatt Jacob 2323d02373f1SMatt Jacob if (IS_SCSI(isp)) { 2324d02373f1SMatt Jacob ISP_WRITE(isp, HCCR, HCCR_CMD_PAUSE); 2325d02373f1SMatt Jacob printf(" cdma_conf=%x cdma_sts=%x cdma_fifostat=%x\n", 2326d02373f1SMatt Jacob ISP_READ(isp, CDMA_CONF), ISP_READ(isp, CDMA_STATUS), 2327d02373f1SMatt Jacob ISP_READ(isp, CDMA_FIFO_STS)); 2328d02373f1SMatt Jacob printf(" ddma_conf=%x ddma_sts=%x ddma_fifostat=%x\n", 2329d02373f1SMatt Jacob ISP_READ(isp, DDMA_CONF), ISP_READ(isp, DDMA_STATUS), 2330d02373f1SMatt Jacob ISP_READ(isp, DDMA_FIFO_STS)); 2331d02373f1SMatt Jacob printf(" sxp_int=%x sxp_gross=%x sxp(scsi_ctrl)=%x\n", 2332d02373f1SMatt Jacob ISP_READ(isp, SXP_INTERRUPT), 2333d02373f1SMatt Jacob ISP_READ(isp, SXP_GROSS_ERR), 2334d02373f1SMatt Jacob ISP_READ(isp, SXP_PINS_CTRL)); 2335d02373f1SMatt Jacob ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE); 2336d02373f1SMatt Jacob } 2337d02373f1SMatt Jacob printf(" mbox regs: %x %x %x %x %x\n", 2338d02373f1SMatt Jacob ISP_READ(isp, OUTMAILBOX0), ISP_READ(isp, OUTMAILBOX1), 2339d02373f1SMatt Jacob ISP_READ(isp, OUTMAILBOX2), ISP_READ(isp, OUTMAILBOX3), 2340d02373f1SMatt Jacob ISP_READ(isp, OUTMAILBOX4)); 2341d02373f1SMatt Jacob printf(" PCI Status Command/Status=%x\n", 23421923f739SMatt Jacob pci_read_config(pcs->pci_dev, PCIR_COMMAND, 1)); 234365adb54cSMatt Jacob } 2344