1c3aac50fSPeter Wemm /* $FreeBSD$ */ 265adb54cSMatt Jacob /* 365adb54cSMatt Jacob * PCI specific probe and attach routines for Qlogic ISP SCSI adapters. 465adb54cSMatt Jacob * FreeBSD Version. 565adb54cSMatt Jacob * 665adb54cSMatt Jacob *--------------------------------------- 7222bb542SMatt Jacob * Copyright (c) 1997, 1998, 1999 by Matthew Jacob 865adb54cSMatt Jacob * NASA/Ames Research Center 965adb54cSMatt Jacob * All rights reserved. 1065adb54cSMatt Jacob *--------------------------------------- 1165adb54cSMatt Jacob * 1265adb54cSMatt Jacob * Redistribution and use in source and binary forms, with or without 1365adb54cSMatt Jacob * modification, are permitted provided that the following conditions 1465adb54cSMatt Jacob * are met: 1565adb54cSMatt Jacob * 1. Redistributions of source code must retain the above copyright 1665adb54cSMatt Jacob * notice immediately at the beginning of the file, without modification, 1765adb54cSMatt Jacob * this list of conditions, and the following disclaimer. 1865adb54cSMatt Jacob * 2. Redistributions in binary form must reproduce the above copyright 1965adb54cSMatt Jacob * notice, this list of conditions and the following disclaimer in the 2065adb54cSMatt Jacob * documentation and/or other materials provided with the distribution. 2165adb54cSMatt Jacob * 3. The name of the author may not be used to endorse or promote products 2265adb54cSMatt Jacob * derived from this software without specific prior written permission. 2365adb54cSMatt Jacob * 2465adb54cSMatt Jacob * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2565adb54cSMatt Jacob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2665adb54cSMatt Jacob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2765adb54cSMatt Jacob * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2865adb54cSMatt Jacob * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2965adb54cSMatt Jacob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3065adb54cSMatt Jacob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3165adb54cSMatt Jacob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3265adb54cSMatt Jacob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3365adb54cSMatt Jacob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3465adb54cSMatt Jacob * SUCH DAMAGE. 3565adb54cSMatt Jacob */ 36d720e6d5SJustin T. Gibbs 37960f6939SMatt Jacob #include <sys/param.h> 38960f6939SMatt Jacob #include <sys/systm.h> 39960f6939SMatt Jacob #include <sys/kernel.h> 40960f6939SMatt Jacob #include <sys/module.h> 41960f6939SMatt Jacob #include <sys/bus.h> 4265adb54cSMatt Jacob 4365adb54cSMatt Jacob #include <pci/pcireg.h> 4465adb54cSMatt Jacob #include <pci/pcivar.h> 4565adb54cSMatt Jacob 46d720e6d5SJustin T. Gibbs #include <machine/bus_memio.h> 47d720e6d5SJustin T. Gibbs #include <machine/bus_pio.h> 48d720e6d5SJustin T. Gibbs #include <machine/bus.h> 49960f6939SMatt Jacob #include <machine/resource.h> 50960f6939SMatt Jacob #include <machine/clock.h> 51960f6939SMatt Jacob #include <sys/rman.h> 52960f6939SMatt Jacob #include <sys/malloc.h> 53960f6939SMatt Jacob 54960f6939SMatt Jacob #include <dev/isp/isp_freebsd.h> 55d59bd469SMatt Jacob 5665adb54cSMatt Jacob static u_int16_t isp_pci_rd_reg __P((struct ispsoftc *, int)); 5765adb54cSMatt Jacob static void isp_pci_wr_reg __P((struct ispsoftc *, int, u_int16_t)); 58d59bd469SMatt Jacob static u_int16_t isp_pci_rd_reg_1080 __P((struct ispsoftc *, int)); 59d59bd469SMatt Jacob static void isp_pci_wr_reg_1080 __P((struct ispsoftc *, int, u_int16_t)); 6065adb54cSMatt Jacob static int isp_pci_mbxdma __P((struct ispsoftc *)); 6165adb54cSMatt Jacob static int isp_pci_dmasetup __P((struct ispsoftc *, ISP_SCSI_XFER_T *, 629637d68cSMatt Jacob ispreq_t *, u_int16_t *, u_int16_t)); 63d720e6d5SJustin T. Gibbs static void 64d720e6d5SJustin T. Gibbs isp_pci_dmateardown __P((struct ispsoftc *, ISP_SCSI_XFER_T *, u_int32_t)); 6565adb54cSMatt Jacob 6665adb54cSMatt Jacob static void isp_pci_reset1 __P((struct ispsoftc *)); 6765adb54cSMatt Jacob static void isp_pci_dumpregs __P((struct ispsoftc *)); 6865adb54cSMatt Jacob 69fed92c47SMatt Jacob #ifndef ISP_CODE_ORG 70fed92c47SMatt Jacob #define ISP_CODE_ORG 0x1000 71fed92c47SMatt Jacob #endif 72fed92c47SMatt Jacob 7365adb54cSMatt Jacob static struct ispmdvec mdvec = { 7465adb54cSMatt Jacob isp_pci_rd_reg, 7565adb54cSMatt Jacob isp_pci_wr_reg, 7665adb54cSMatt Jacob isp_pci_mbxdma, 7765adb54cSMatt Jacob isp_pci_dmasetup, 78d720e6d5SJustin T. Gibbs isp_pci_dmateardown, 7965adb54cSMatt Jacob NULL, 8065adb54cSMatt Jacob isp_pci_reset1, 8165adb54cSMatt Jacob isp_pci_dumpregs, 8256aef503SMatt Jacob NULL, 83fed92c47SMatt Jacob 0, 8465adb54cSMatt Jacob ISP_CODE_ORG, 85a95ae193SMatt Jacob 0, 86285e230dSMatt Jacob BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64, 87d720e6d5SJustin T. Gibbs 0 8865adb54cSMatt Jacob }; 8965adb54cSMatt Jacob 90d59bd469SMatt Jacob static struct ispmdvec mdvec_1080 = { 91d59bd469SMatt Jacob isp_pci_rd_reg_1080, 92d59bd469SMatt Jacob isp_pci_wr_reg_1080, 93d59bd469SMatt Jacob isp_pci_mbxdma, 94d59bd469SMatt Jacob isp_pci_dmasetup, 95d59bd469SMatt Jacob isp_pci_dmateardown, 96d59bd469SMatt Jacob NULL, 97d59bd469SMatt Jacob isp_pci_reset1, 98d59bd469SMatt Jacob isp_pci_dumpregs, 9956aef503SMatt Jacob NULL, 100fed92c47SMatt Jacob 0, 101fed92c47SMatt Jacob ISP_CODE_ORG, 102a95ae193SMatt Jacob 0, 103d59bd469SMatt Jacob BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64, 104d59bd469SMatt Jacob 0 105d59bd469SMatt Jacob }; 106d59bd469SMatt Jacob 107960f6939SMatt Jacob static struct ispmdvec mdvec_12160 = { 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, 117960f6939SMatt Jacob 0, 11856aef503SMatt Jacob NULL, 119960f6939SMatt Jacob 0, 120960f6939SMatt Jacob BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64, 121960f6939SMatt Jacob 0 122960f6939SMatt Jacob }; 123960f6939SMatt Jacob 12465adb54cSMatt Jacob static struct ispmdvec mdvec_2100 = { 12565adb54cSMatt Jacob isp_pci_rd_reg, 12665adb54cSMatt Jacob isp_pci_wr_reg, 12765adb54cSMatt Jacob isp_pci_mbxdma, 12865adb54cSMatt Jacob isp_pci_dmasetup, 129d720e6d5SJustin T. Gibbs isp_pci_dmateardown, 13065adb54cSMatt Jacob NULL, 13165adb54cSMatt Jacob isp_pci_reset1, 13265adb54cSMatt Jacob isp_pci_dumpregs, 13356aef503SMatt Jacob NULL, 134fed92c47SMatt Jacob 0, 135fed92c47SMatt Jacob ISP_CODE_ORG, 136a95ae193SMatt Jacob 0, 137a95ae193SMatt Jacob 0, 138d720e6d5SJustin T. Gibbs 0 13965adb54cSMatt Jacob }; 140222bb542SMatt Jacob 141222bb542SMatt Jacob static struct ispmdvec mdvec_2200 = { 142222bb542SMatt Jacob isp_pci_rd_reg, 143222bb542SMatt Jacob isp_pci_wr_reg, 144222bb542SMatt Jacob isp_pci_mbxdma, 145222bb542SMatt Jacob isp_pci_dmasetup, 146222bb542SMatt Jacob isp_pci_dmateardown, 147222bb542SMatt Jacob NULL, 148222bb542SMatt Jacob isp_pci_reset1, 149222bb542SMatt Jacob isp_pci_dumpregs, 15056aef503SMatt Jacob NULL, 151fed92c47SMatt Jacob 0, 152fed92c47SMatt Jacob ISP_CODE_ORG, 153a95ae193SMatt Jacob 0, 154222bb542SMatt Jacob 0, 155222bb542SMatt Jacob 0 156222bb542SMatt Jacob }; 157d951bbcaSMatt Jacob 15865adb54cSMatt Jacob #ifndef PCIM_CMD_INVEN 15965adb54cSMatt Jacob #define PCIM_CMD_INVEN 0x10 16065adb54cSMatt Jacob #endif 16165adb54cSMatt Jacob #ifndef PCIM_CMD_BUSMASTEREN 16265adb54cSMatt Jacob #define PCIM_CMD_BUSMASTEREN 0x0004 16365adb54cSMatt Jacob #endif 164d951bbcaSMatt Jacob #ifndef PCIM_CMD_PERRESPEN 165d951bbcaSMatt Jacob #define PCIM_CMD_PERRESPEN 0x0040 166d951bbcaSMatt Jacob #endif 167d951bbcaSMatt Jacob #ifndef PCIM_CMD_SEREN 168d951bbcaSMatt Jacob #define PCIM_CMD_SEREN 0x0100 169d951bbcaSMatt Jacob #endif 170d951bbcaSMatt Jacob 171d951bbcaSMatt Jacob #ifndef PCIR_COMMAND 172d951bbcaSMatt Jacob #define PCIR_COMMAND 0x04 173d951bbcaSMatt Jacob #endif 174d951bbcaSMatt Jacob 175d951bbcaSMatt Jacob #ifndef PCIR_CACHELNSZ 176d951bbcaSMatt Jacob #define PCIR_CACHELNSZ 0x0c 177d951bbcaSMatt Jacob #endif 178d951bbcaSMatt Jacob 179d951bbcaSMatt Jacob #ifndef PCIR_LATTIMER 180d951bbcaSMatt Jacob #define PCIR_LATTIMER 0x0d 181d951bbcaSMatt Jacob #endif 182d951bbcaSMatt Jacob 183ab6d0040SMatt Jacob #ifndef PCIR_ROMADDR 184ab6d0040SMatt Jacob #define PCIR_ROMADDR 0x30 185ab6d0040SMatt Jacob #endif 186ab6d0040SMatt Jacob 18765adb54cSMatt Jacob #ifndef PCI_VENDOR_QLOGIC 18865adb54cSMatt Jacob #define PCI_VENDOR_QLOGIC 0x1077 18965adb54cSMatt Jacob #endif 19065adb54cSMatt Jacob 19165adb54cSMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP1020 19265adb54cSMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP1020 0x1020 19365adb54cSMatt Jacob #endif 19465adb54cSMatt Jacob 195d59bd469SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP1080 196d59bd469SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP1080 0x1080 197d59bd469SMatt Jacob #endif 198d59bd469SMatt Jacob 199960f6939SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP12160 200960f6939SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP12160 0x1216 201960f6939SMatt Jacob #endif 202960f6939SMatt Jacob 203d59bd469SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP1240 204d59bd469SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP1240 0x1240 205d59bd469SMatt Jacob #endif 20665adb54cSMatt Jacob 20722e1dc85SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP1280 20822e1dc85SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP1280 0x1280 20922e1dc85SMatt Jacob #endif 21022e1dc85SMatt Jacob 21165adb54cSMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP2100 21265adb54cSMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP2100 0x2100 21365adb54cSMatt Jacob #endif 21465adb54cSMatt Jacob 215222bb542SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP2200 216222bb542SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP2200 0x2200 217222bb542SMatt Jacob #endif 218222bb542SMatt Jacob 21956aef503SMatt Jacob #define PCI_QLOGIC_ISP1020 \ 22056aef503SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP1020 << 16) | PCI_VENDOR_QLOGIC) 221d59bd469SMatt Jacob 222d59bd469SMatt Jacob #define PCI_QLOGIC_ISP1080 \ 223d59bd469SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP1080 << 16) | PCI_VENDOR_QLOGIC) 224d59bd469SMatt Jacob 225960f6939SMatt Jacob #define PCI_QLOGIC_ISP12160 \ 226960f6939SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP12160 << 16) | PCI_VENDOR_QLOGIC) 227960f6939SMatt Jacob 228d59bd469SMatt Jacob #define PCI_QLOGIC_ISP1240 \ 229d59bd469SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP1240 << 16) | PCI_VENDOR_QLOGIC) 230d59bd469SMatt Jacob 23122e1dc85SMatt Jacob #define PCI_QLOGIC_ISP1280 \ 23222e1dc85SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP1280 << 16) | PCI_VENDOR_QLOGIC) 23322e1dc85SMatt Jacob 23465adb54cSMatt Jacob #define PCI_QLOGIC_ISP2100 \ 23565adb54cSMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP2100 << 16) | PCI_VENDOR_QLOGIC) 23665adb54cSMatt Jacob 237222bb542SMatt Jacob #define PCI_QLOGIC_ISP2200 \ 238222bb542SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP2200 << 16) | PCI_VENDOR_QLOGIC) 239222bb542SMatt Jacob 24065adb54cSMatt Jacob #define IO_MAP_REG 0x10 24165adb54cSMatt Jacob #define MEM_MAP_REG 0x14 24265adb54cSMatt Jacob 243d951bbcaSMatt Jacob #define PCI_DFLT_LTNCY 0x40 244d951bbcaSMatt Jacob #define PCI_DFLT_LNSZ 0x10 24565adb54cSMatt Jacob 246960f6939SMatt Jacob static int isp_pci_probe (device_t); 247960f6939SMatt Jacob static int isp_pci_attach (device_t); 24865adb54cSMatt Jacob 249d720e6d5SJustin T. Gibbs /* This distinguishing define is not right, but it does work */ 250a185f9b1SMatt Jacob #ifdef __alpha__ 251a185f9b1SMatt Jacob #define IO_SPACE_MAPPING ALPHA_BUS_SPACE_IO 252a185f9b1SMatt Jacob #define MEM_SPACE_MAPPING ALPHA_BUS_SPACE_MEM 253a185f9b1SMatt Jacob #else 254a185f9b1SMatt Jacob #define IO_SPACE_MAPPING I386_BUS_SPACE_IO 255a185f9b1SMatt Jacob #define MEM_SPACE_MAPPING I386_BUS_SPACE_MEM 256a185f9b1SMatt Jacob #endif 25765adb54cSMatt Jacob 25865adb54cSMatt Jacob struct isp_pcisoftc { 25965adb54cSMatt Jacob struct ispsoftc pci_isp; 260960f6939SMatt Jacob device_t pci_dev; 261960f6939SMatt Jacob struct resource * pci_reg; 26265adb54cSMatt Jacob bus_space_tag_t pci_st; 26365adb54cSMatt Jacob bus_space_handle_t pci_sh; 264960f6939SMatt Jacob void * ih; 265d59bd469SMatt Jacob int16_t pci_poff[_NREG_BLKS]; 266d720e6d5SJustin T. Gibbs bus_dma_tag_t parent_dmat; 267d720e6d5SJustin T. Gibbs bus_dma_tag_t cntrol_dmat; 268d720e6d5SJustin T. Gibbs bus_dmamap_t cntrol_dmap; 269a95ae193SMatt Jacob bus_dmamap_t *dmaps; 27065adb54cSMatt Jacob }; 27156aef503SMatt Jacob ispfwfunc *isp_get_firmware_p = NULL; 27265adb54cSMatt Jacob 273960f6939SMatt Jacob static device_method_t isp_pci_methods[] = { 274960f6939SMatt Jacob /* Device interface */ 275960f6939SMatt Jacob DEVMETHOD(device_probe, isp_pci_probe), 276960f6939SMatt Jacob DEVMETHOD(device_attach, isp_pci_attach), 277960f6939SMatt Jacob { 0, 0 } 27865adb54cSMatt Jacob }; 27965adb54cSMatt Jacob 280960f6939SMatt Jacob static driver_t isp_pci_driver = { 281960f6939SMatt Jacob "isp", isp_pci_methods, sizeof (struct isp_pcisoftc) 282960f6939SMatt Jacob }; 283960f6939SMatt Jacob static devclass_t isp_devclass; 284960f6939SMatt Jacob DRIVER_MODULE(isp, pci, isp_pci_driver, isp_devclass, 0, 0); 28556aef503SMatt Jacob MODULE_VERSION(isp, 1); 28665adb54cSMatt Jacob 287960f6939SMatt Jacob static int 288960f6939SMatt Jacob isp_pci_probe(device_t dev) 28965adb54cSMatt Jacob { 290960f6939SMatt Jacob switch ((pci_get_device(dev) << 16) | (pci_get_vendor(dev))) { 29156aef503SMatt Jacob case PCI_QLOGIC_ISP1020: 292960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 1020/1040 PCI SCSI Adapter"); 29365adb54cSMatt Jacob break; 294d59bd469SMatt Jacob case PCI_QLOGIC_ISP1080: 295960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 1080 PCI SCSI Adapter"); 296c6608df3SMatt Jacob break; 297c6608df3SMatt Jacob case PCI_QLOGIC_ISP1240: 298960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 1240 PCI SCSI Adapter"); 299d59bd469SMatt Jacob break; 30022e1dc85SMatt Jacob case PCI_QLOGIC_ISP1280: 301960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 1280 PCI SCSI Adapter"); 302960f6939SMatt Jacob break; 303960f6939SMatt Jacob case PCI_QLOGIC_ISP12160: 304960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 12160 PCI SCSI Adapter"); 30522e1dc85SMatt Jacob break; 30665adb54cSMatt Jacob case PCI_QLOGIC_ISP2100: 307960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 2100 PCI FC-AL Adapter"); 30865adb54cSMatt Jacob break; 3095542fe4bSMatt Jacob case PCI_QLOGIC_ISP2200: 310960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 2200 PCI FC-AL Adapter"); 3115542fe4bSMatt Jacob break; 31265adb54cSMatt Jacob default: 313960f6939SMatt Jacob return (ENXIO); 31465adb54cSMatt Jacob } 315960f6939SMatt Jacob if (device_get_unit(dev) == 0) { 316a95ae193SMatt Jacob CFGPRINTF("Qlogic ISP Driver, FreeBSD Version %d.%d, " 317a95ae193SMatt Jacob "Core Version %d.%d\n", 318d720e6d5SJustin T. Gibbs ISP_PLATFORM_VERSION_MAJOR, ISP_PLATFORM_VERSION_MINOR, 319d720e6d5SJustin T. Gibbs ISP_CORE_VERSION_MAJOR, ISP_CORE_VERSION_MINOR); 32065adb54cSMatt Jacob } 32156aef503SMatt Jacob /* 32256aef503SMatt Jacob * XXXX: Here is where we might load the f/w module 32356aef503SMatt Jacob * XXXX: (or increase a reference count to it). 32456aef503SMatt Jacob */ 325960f6939SMatt Jacob return (0); 32665adb54cSMatt Jacob } 32765adb54cSMatt Jacob 328960f6939SMatt Jacob static int 329960f6939SMatt Jacob isp_pci_attach(device_t dev) 33065adb54cSMatt Jacob { 331960f6939SMatt Jacob struct resource *regs, *irq; 332469b6b9eSMatt Jacob int unit, bitmap, rtp, rgd, iqd, m1, m2, s; 333960f6939SMatt Jacob u_int32_t data, cmd, linesz, psize, basetype; 33465adb54cSMatt Jacob struct isp_pcisoftc *pcs; 33565adb54cSMatt Jacob struct ispsoftc *isp; 336c6608df3SMatt Jacob struct ispmdvec *mdvp; 337222bb542SMatt Jacob bus_size_t lim; 33865adb54cSMatt Jacob 339222bb542SMatt Jacob /* 3409ba86737SMatt Jacob * Figure out if we're supposed to skip this one. 3419ba86737SMatt Jacob */ 342960f6939SMatt Jacob unit = device_get_unit(dev); 3439ba86737SMatt Jacob if (getenv_int("isp_disable", &bitmap)) { 3449ba86737SMatt Jacob if (bitmap & (1 << unit)) { 345960f6939SMatt Jacob device_printf(dev, "not configuring\n"); 346960f6939SMatt Jacob return (ENODEV); 3479ba86737SMatt Jacob } 3489ba86737SMatt Jacob } 3499ba86737SMatt Jacob 350960f6939SMatt Jacob pcs = malloc(sizeof (struct isp_pcisoftc), M_DEVBUF, M_NOWAIT); 351960f6939SMatt Jacob if (pcs == NULL) { 352960f6939SMatt Jacob device_printf(dev, "cannot allocate softc\n"); 353960f6939SMatt Jacob return (ENOMEM); 354960f6939SMatt Jacob } 355960f6939SMatt Jacob bzero(pcs, sizeof (struct isp_pcisoftc)); 356960f6939SMatt Jacob 3579ba86737SMatt Jacob /* 358222bb542SMatt Jacob * Figure out which we should try first - memory mapping or i/o mapping? 359222bb542SMatt Jacob */ 36056aef503SMatt Jacob #ifdef __alpha__ 361960f6939SMatt Jacob m1 = PCIM_CMD_MEMEN; 362960f6939SMatt Jacob m2 = PCIM_CMD_PORTEN; 363222bb542SMatt Jacob #else 364960f6939SMatt Jacob m1 = PCIM_CMD_PORTEN; 365960f6939SMatt Jacob m2 = PCIM_CMD_MEMEN; 366222bb542SMatt Jacob #endif 367222bb542SMatt Jacob bitmap = 0; 368222bb542SMatt Jacob if (getenv_int("isp_mem_map", &bitmap)) { 369960f6939SMatt Jacob if (bitmap & (1 << unit)) { 370960f6939SMatt Jacob m1 = PCIM_CMD_MEMEN; 371960f6939SMatt Jacob m2 = PCIM_CMD_PORTEN; 372960f6939SMatt Jacob } 373222bb542SMatt Jacob } 374222bb542SMatt Jacob bitmap = 0; 375222bb542SMatt Jacob if (getenv_int("isp_io_map", &bitmap)) { 376960f6939SMatt Jacob if (bitmap & (1 << unit)) { 377960f6939SMatt Jacob m1 = PCIM_CMD_PORTEN; 378960f6939SMatt Jacob m2 = PCIM_CMD_MEMEN; 379960f6939SMatt Jacob } 380222bb542SMatt Jacob } 381222bb542SMatt Jacob 382ab6d0040SMatt Jacob linesz = PCI_DFLT_LNSZ; 383960f6939SMatt Jacob irq = regs = NULL; 384960f6939SMatt Jacob rgd = rtp = iqd = 0; 385960f6939SMatt Jacob 386960f6939SMatt Jacob cmd = pci_read_config(dev, PCIR_COMMAND, 1); 387960f6939SMatt Jacob if (cmd & m1) { 388960f6939SMatt Jacob rtp = (m1 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT; 389960f6939SMatt Jacob rgd = (m1 == PCIM_CMD_MEMEN)? MEM_MAP_REG : IO_MAP_REG; 390960f6939SMatt Jacob regs = bus_alloc_resource(dev, rtp, &rgd, 0, ~0, 1, RF_ACTIVE); 39165adb54cSMatt Jacob } 392960f6939SMatt Jacob if (regs == NULL && (cmd & m2)) { 393960f6939SMatt Jacob rtp = (m2 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT; 394960f6939SMatt Jacob rgd = (m2 == PCIM_CMD_MEMEN)? MEM_MAP_REG : IO_MAP_REG; 395960f6939SMatt Jacob regs = bus_alloc_resource(dev, rtp, &rgd, 0, ~0, 1, RF_ACTIVE); 39665adb54cSMatt Jacob } 397960f6939SMatt Jacob if (regs == NULL) { 398960f6939SMatt Jacob device_printf(dev, "unable to map any ports\n"); 399960f6939SMatt Jacob goto bad; 40065adb54cSMatt Jacob } 401222bb542SMatt Jacob if (bootverbose) 40265adb54cSMatt Jacob printf("isp%d: using %s space register mapping\n", unit, 403960f6939SMatt Jacob (rgd == IO_MAP_REG)? "I/O" : "Memory"); 404960f6939SMatt Jacob pcs->pci_dev = dev; 405960f6939SMatt Jacob pcs->pci_reg = regs; 406960f6939SMatt Jacob pcs->pci_st = rman_get_bustag(regs); 407960f6939SMatt Jacob pcs->pci_sh = rman_get_bushandle(regs); 40865adb54cSMatt Jacob 409d59bd469SMatt Jacob pcs->pci_poff[BIU_BLOCK >> _BLK_REG_SHFT] = BIU_REGS_OFF; 410d59bd469SMatt Jacob pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS_OFF; 411d59bd469SMatt Jacob pcs->pci_poff[SXP_BLOCK >> _BLK_REG_SHFT] = PCI_SXP_REGS_OFF; 412d59bd469SMatt Jacob pcs->pci_poff[RISC_BLOCK >> _BLK_REG_SHFT] = PCI_RISC_REGS_OFF; 413d59bd469SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = DMA_REGS_OFF; 414c6608df3SMatt Jacob mdvp = &mdvec; 415c6608df3SMatt Jacob basetype = ISP_HA_SCSI_UNKNOWN; 416c6608df3SMatt Jacob psize = sizeof (sdparam); 417222bb542SMatt Jacob lim = BUS_SPACE_MAXSIZE_32BIT; 41856aef503SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP1020) { 419c6608df3SMatt Jacob mdvp = &mdvec; 420c6608df3SMatt Jacob basetype = ISP_HA_SCSI_UNKNOWN; 421c6608df3SMatt Jacob psize = sizeof (sdparam); 422222bb542SMatt Jacob lim = BUS_SPACE_MAXSIZE_24BIT; 423d59bd469SMatt Jacob } 424960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP1080) { 425c6608df3SMatt Jacob mdvp = &mdvec_1080; 426c6608df3SMatt Jacob basetype = ISP_HA_SCSI_1080; 427c6608df3SMatt Jacob psize = sizeof (sdparam); 428c6608df3SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 429c6608df3SMatt Jacob ISP1080_DMA_REGS_OFF; 430c6608df3SMatt Jacob } 431960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP1240) { 432c6608df3SMatt Jacob mdvp = &mdvec_1080; 43322e1dc85SMatt Jacob basetype = ISP_HA_SCSI_1240; 43422e1dc85SMatt Jacob psize = 2 * sizeof (sdparam); 43522e1dc85SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 43622e1dc85SMatt Jacob ISP1080_DMA_REGS_OFF; 43722e1dc85SMatt Jacob } 438960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP1280) { 43922e1dc85SMatt Jacob mdvp = &mdvec_1080; 44022e1dc85SMatt Jacob basetype = ISP_HA_SCSI_1280; 441c6608df3SMatt Jacob psize = 2 * sizeof (sdparam); 442d59bd469SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 443d59bd469SMatt Jacob ISP1080_DMA_REGS_OFF; 444d59bd469SMatt Jacob } 445960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP12160) { 446960f6939SMatt Jacob mdvp = &mdvec_12160; 447960f6939SMatt Jacob basetype = ISP_HA_SCSI_12160; 448960f6939SMatt Jacob psize = 2 * sizeof (sdparam); 449960f6939SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 450960f6939SMatt Jacob ISP1080_DMA_REGS_OFF; 451960f6939SMatt Jacob } 452960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP2100) { 453c6608df3SMatt Jacob mdvp = &mdvec_2100; 454c6608df3SMatt Jacob basetype = ISP_HA_FC_2100; 455c6608df3SMatt Jacob psize = sizeof (fcparam); 456d59bd469SMatt Jacob pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = 457d59bd469SMatt Jacob PCI_MBOX_REGS2100_OFF; 458960f6939SMatt Jacob if (pci_get_revid(dev) < 3) { 459ab6d0040SMatt Jacob /* 460ab6d0040SMatt Jacob * XXX: Need to get the actual revision 461ab6d0040SMatt Jacob * XXX: number of the 2100 FB. At any rate, 462ab6d0040SMatt Jacob * XXX: lower cache line size for early revision 463ab6d0040SMatt Jacob * XXX; boards. 464ab6d0040SMatt Jacob */ 465ab6d0040SMatt Jacob linesz = 1; 466ab6d0040SMatt Jacob } 46765adb54cSMatt Jacob } 468960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP2200) { 469222bb542SMatt Jacob mdvp = &mdvec_2200; 470222bb542SMatt Jacob basetype = ISP_HA_FC_2200; 471222bb542SMatt Jacob psize = sizeof (fcparam); 472222bb542SMatt Jacob pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = 473222bb542SMatt Jacob PCI_MBOX_REGS2100_OFF; 474222bb542SMatt Jacob } 475c6608df3SMatt Jacob isp = &pcs->pci_isp; 476c6608df3SMatt Jacob isp->isp_param = malloc(psize, M_DEVBUF, M_NOWAIT); 477c6608df3SMatt Jacob if (isp->isp_param == NULL) { 478960f6939SMatt Jacob device_printf(dev, "cannot allocate parameter data\n"); 479960f6939SMatt Jacob goto bad; 480c6608df3SMatt Jacob } 481c6608df3SMatt Jacob bzero(isp->isp_param, psize); 482c6608df3SMatt Jacob isp->isp_mdvec = mdvp; 483c6608df3SMatt Jacob isp->isp_type = basetype; 484960f6939SMatt Jacob isp->isp_revision = pci_get_revid(dev); 485c6608df3SMatt Jacob (void) snprintf(isp->isp_name, sizeof (isp->isp_name), "isp%d", unit); 486c6608df3SMatt Jacob isp->isp_osinfo.unit = unit; 48765adb54cSMatt Jacob 48856aef503SMatt Jacob /* 48956aef503SMatt Jacob * Try and find firmware for this device. 49056aef503SMatt Jacob */ 49156aef503SMatt Jacob 49256aef503SMatt Jacob if (isp_get_firmware_p) { 49356aef503SMatt Jacob int device = (int) pci_get_device(dev); 49456aef503SMatt Jacob #ifdef ISP_TARGET_MODE 49556aef503SMatt Jacob (*isp_get_firmware_p)(0, 1, device, &mdvp->dv_ispfw); 49656aef503SMatt Jacob #else 49756aef503SMatt Jacob (*isp_get_firmware_p)(0, 0, device, &mdvp->dv_ispfw); 49856aef503SMatt Jacob #endif 49956aef503SMatt Jacob } 50056aef503SMatt Jacob 50156aef503SMatt Jacob /* 50256aef503SMatt Jacob * 50356aef503SMatt Jacob */ 50456aef503SMatt Jacob 505469b6b9eSMatt Jacob s = splbio(); 506d951bbcaSMatt Jacob /* 507d951bbcaSMatt Jacob * Make sure that SERR, PERR, WRITE INVALIDATE and BUSMASTER 508d951bbcaSMatt Jacob * are set. 509d951bbcaSMatt Jacob */ 510960f6939SMatt Jacob cmd |= PCIM_CMD_SEREN | PCIM_CMD_PERRESPEN | 511960f6939SMatt Jacob PCIM_CMD_BUSMASTEREN | PCIM_CMD_INVEN; 512960f6939SMatt Jacob pci_write_config(dev, PCIR_COMMAND, cmd, 1); 513ab6d0040SMatt Jacob 514d951bbcaSMatt Jacob /* 515222bb542SMatt Jacob * Make sure the Cache Line Size register is set sensibly. 516d951bbcaSMatt Jacob */ 517960f6939SMatt Jacob data = pci_read_config(dev, PCIR_CACHELNSZ, 1); 518ab6d0040SMatt Jacob if (data != linesz) { 519d951bbcaSMatt Jacob data = PCI_DFLT_LNSZ; 520a95ae193SMatt Jacob CFGPRINTF("%s: set PCI line size to %d\n", isp->isp_name, data); 521960f6939SMatt Jacob pci_write_config(dev, PCIR_CACHELNSZ, data, 1); 522d951bbcaSMatt Jacob } 523ab6d0040SMatt Jacob 524d951bbcaSMatt Jacob /* 525d951bbcaSMatt Jacob * Make sure the Latency Timer is sane. 526d951bbcaSMatt Jacob */ 527960f6939SMatt Jacob data = pci_read_config(dev, PCIR_LATTIMER, 1); 528d951bbcaSMatt Jacob if (data < PCI_DFLT_LTNCY) { 529d951bbcaSMatt Jacob data = PCI_DFLT_LTNCY; 530a95ae193SMatt Jacob CFGPRINTF("%s: set PCI latency to %d\n", isp->isp_name, data); 531960f6939SMatt Jacob pci_write_config(dev, PCIR_LATTIMER, data, 1); 532d951bbcaSMatt Jacob } 533ab6d0040SMatt Jacob 534ab6d0040SMatt Jacob /* 535ab6d0040SMatt Jacob * Make sure we've disabled the ROM. 536ab6d0040SMatt Jacob */ 537960f6939SMatt Jacob data = pci_read_config(dev, PCIR_ROMADDR, 4); 538ab6d0040SMatt Jacob data &= ~1; 539960f6939SMatt Jacob pci_write_config(dev, PCIR_ROMADDR, data, 4); 54005fbcbb0SMatt Jacob 541d951bbcaSMatt Jacob 542086646f7SJustin T. Gibbs if (bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT, 543222bb542SMatt Jacob BUS_SPACE_MAXADDR, NULL, NULL, lim + 1, 544222bb542SMatt Jacob 255, lim, 0, &pcs->parent_dmat) != 0) { 54505fbcbb0SMatt Jacob splx(s); 546d720e6d5SJustin T. Gibbs printf("%s: could not create master dma tag\n", isp->isp_name); 547960f6939SMatt Jacob free(isp->isp_param, M_DEVBUF); 548d720e6d5SJustin T. Gibbs free(pcs, M_DEVBUF); 549960f6939SMatt Jacob return (ENXIO); 55065adb54cSMatt Jacob } 55165adb54cSMatt Jacob 552960f6939SMatt Jacob iqd = 0; 553960f6939SMatt Jacob irq = bus_alloc_resource(dev, SYS_RES_IRQ, &iqd, 0, ~0, 554960f6939SMatt Jacob 1, RF_ACTIVE | RF_SHAREABLE); 555960f6939SMatt Jacob if (irq == NULL) { 556960f6939SMatt Jacob device_printf(dev, "could not allocate interrupt\n"); 557960f6939SMatt Jacob goto bad; 558960f6939SMatt Jacob } 559960f6939SMatt Jacob 560222bb542SMatt Jacob if (getenv_int("isp_no_fwload", &bitmap)) { 561222bb542SMatt Jacob if (bitmap & (1 << unit)) 562222bb542SMatt Jacob isp->isp_confopts |= ISP_CFG_NORELOAD; 563222bb542SMatt Jacob } 564222bb542SMatt Jacob if (getenv_int("isp_fwload", &bitmap)) { 565222bb542SMatt Jacob if (bitmap & (1 << unit)) 566222bb542SMatt Jacob isp->isp_confopts &= ~ISP_CFG_NORELOAD; 567222bb542SMatt Jacob } 568222bb542SMatt Jacob if (getenv_int("isp_no_nvram", &bitmap)) { 569222bb542SMatt Jacob if (bitmap & (1 << unit)) 570222bb542SMatt Jacob isp->isp_confopts |= ISP_CFG_NONVRAM; 571222bb542SMatt Jacob } 572222bb542SMatt Jacob if (getenv_int("isp_nvram", &bitmap)) { 573222bb542SMatt Jacob if (bitmap & (1 << unit)) 574222bb542SMatt Jacob isp->isp_confopts &= ~ISP_CFG_NONVRAM; 575222bb542SMatt Jacob } 576222bb542SMatt Jacob if (getenv_int("isp_fcduplex", &bitmap)) { 577222bb542SMatt Jacob if (bitmap & (1 << unit)) 578222bb542SMatt Jacob isp->isp_confopts |= ISP_CFG_FULL_DUPLEX; 579222bb542SMatt Jacob } 580222bb542SMatt Jacob if (getenv_int("isp_no_fcduplex", &bitmap)) { 581222bb542SMatt Jacob if (bitmap & (1 << unit)) 582222bb542SMatt Jacob isp->isp_confopts &= ~ISP_CFG_FULL_DUPLEX; 583222bb542SMatt Jacob } 584960f6939SMatt Jacob if (getenv_int("isp_nport", &bitmap)) { 585960f6939SMatt Jacob if (bitmap & (1 << unit)) 586960f6939SMatt Jacob isp->isp_confopts |= ISP_CFG_NPORT; 587960f6939SMatt Jacob } 588222bb542SMatt Jacob /* 5899637d68cSMatt Jacob * Look for overriding WWN. This is a Node WWN so it binds to 5909637d68cSMatt Jacob * all FC instances. A Port WWN will be constructed from it 5919637d68cSMatt Jacob * as appropriate. 592222bb542SMatt Jacob */ 5939637d68cSMatt Jacob if (!getenv_quad("isp_wwn", (quad_t *) &isp->isp_osinfo.default_wwn)) { 5949637d68cSMatt Jacob int i; 5959637d68cSMatt Jacob u_int64_t seed = (u_int64_t) (intptr_t) isp; 596222bb542SMatt Jacob 5979637d68cSMatt Jacob seed <<= 16; 5989637d68cSMatt Jacob seed &= ((1LL << 48) - 1LL); 599222bb542SMatt Jacob /* 600222bb542SMatt Jacob * This isn't very random, but it's the best we can do for 6019637d68cSMatt Jacob * the real edge case of cards that don't have WWNs. If 6029637d68cSMatt Jacob * you recompile a new vers.c, you'll get a different WWN. 603222bb542SMatt Jacob */ 6049637d68cSMatt Jacob for (i = 0; version[i] != 0; i++) { 6059637d68cSMatt Jacob seed += version[i]; 6069637d68cSMatt Jacob } 6079637d68cSMatt Jacob /* 6089637d68cSMatt Jacob * Make sure the top nibble has something vaguely sensible. 6099637d68cSMatt Jacob */ 6109637d68cSMatt Jacob isp->isp_osinfo.default_wwn |= (4LL << 60) | seed; 6119637d68cSMatt Jacob } else { 6129637d68cSMatt Jacob isp->isp_confopts |= ISP_CFG_OWNWWN; 613222bb542SMatt Jacob } 614a95ae193SMatt Jacob (void) getenv_int("isp_debug", &isp_debug); 61542426921SMatt Jacob #ifdef ISP_TARGET_MODE 61642426921SMatt Jacob (void) getenv_int("isp_tdebug", &isp_tdebug); 61742426921SMatt Jacob #endif 618960f6939SMatt Jacob if (bus_setup_intr(dev, irq, INTR_TYPE_CAM, (void (*)(void *))isp_intr, 619960f6939SMatt Jacob isp, &pcs->ih)) { 620469b6b9eSMatt Jacob splx(s); 621960f6939SMatt Jacob device_printf(dev, "could not setup interrupt\n"); 622960f6939SMatt Jacob goto bad; 623960f6939SMatt Jacob } 624960f6939SMatt Jacob 62505fbcbb0SMatt Jacob /* 62605fbcbb0SMatt Jacob * Make sure we're in reset state. 62705fbcbb0SMatt Jacob */ 62865adb54cSMatt Jacob isp_reset(isp); 62965adb54cSMatt Jacob if (isp->isp_state != ISP_RESETSTATE) { 630469b6b9eSMatt Jacob splx(s); 631960f6939SMatt Jacob goto bad; 63265adb54cSMatt Jacob } 63365adb54cSMatt Jacob isp_init(isp); 63465adb54cSMatt Jacob if (isp->isp_state != ISP_INITSTATE) { 635d59bd469SMatt Jacob /* If we're a Fibre Channel Card, we allow deferred attach */ 636222bb542SMatt Jacob if (IS_SCSI(isp)) { 63765adb54cSMatt Jacob isp_uninit(isp); 638469b6b9eSMatt Jacob splx(s); 639960f6939SMatt Jacob goto bad; 640d59bd469SMatt Jacob } 64165adb54cSMatt Jacob } 64265adb54cSMatt Jacob isp_attach(isp); 64365adb54cSMatt Jacob if (isp->isp_state != ISP_RUNSTATE) { 644d59bd469SMatt Jacob /* If we're a Fibre Channel Card, we allow deferred attach */ 64592c49d78SMatt Jacob if (IS_SCSI(isp)) { 64665adb54cSMatt Jacob isp_uninit(isp); 647469b6b9eSMatt Jacob splx(s); 648960f6939SMatt Jacob goto bad; 649960f6939SMatt Jacob } 650960f6939SMatt Jacob } 651469b6b9eSMatt Jacob splx(s); 65256aef503SMatt Jacob /* 65356aef503SMatt Jacob * XXXX: Here is where we might unload the f/w module 65456aef503SMatt Jacob * XXXX: (or decrease the reference count to it). 65556aef503SMatt Jacob */ 656960f6939SMatt Jacob return (0); 657960f6939SMatt Jacob 658960f6939SMatt Jacob bad: 659960f6939SMatt Jacob 660960f6939SMatt Jacob if (pcs && pcs->ih) { 661960f6939SMatt Jacob (void) bus_teardown_intr(dev, irq, pcs->ih); 662960f6939SMatt Jacob } 663960f6939SMatt Jacob 664960f6939SMatt Jacob if (irq) { 665960f6939SMatt Jacob (void) bus_release_resource(dev, SYS_RES_IRQ, iqd, irq); 666960f6939SMatt Jacob } 667960f6939SMatt Jacob if (regs) { 668960f6939SMatt Jacob (void) bus_release_resource(dev, rtp, rgd, regs); 669960f6939SMatt Jacob } 670960f6939SMatt Jacob if (pcs) { 671960f6939SMatt Jacob if (pcs->pci_isp.isp_param) 672960f6939SMatt Jacob free(pcs->pci_isp.isp_param, M_DEVBUF); 67365adb54cSMatt Jacob free(pcs, M_DEVBUF); 67465adb54cSMatt Jacob } 67556aef503SMatt Jacob /* 67656aef503SMatt Jacob * XXXX: Here is where we might unload the f/w module 67756aef503SMatt Jacob * XXXX: (or decrease the reference count to it). 67856aef503SMatt Jacob */ 679960f6939SMatt Jacob return (ENXIO); 68065adb54cSMatt Jacob } 68165adb54cSMatt Jacob 68265adb54cSMatt Jacob static u_int16_t 683d59bd469SMatt Jacob isp_pci_rd_reg(isp, regoff) 684d59bd469SMatt Jacob struct ispsoftc *isp; 685d59bd469SMatt Jacob int regoff; 68665adb54cSMatt Jacob { 68765adb54cSMatt Jacob u_int16_t rv; 68865adb54cSMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 689d59bd469SMatt Jacob int offset, oldconf = 0; 69065adb54cSMatt Jacob 691d59bd469SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 69265adb54cSMatt Jacob /* 69365adb54cSMatt Jacob * We will assume that someone has paused the RISC processor. 69465adb54cSMatt Jacob */ 695d59bd469SMatt Jacob oldconf = isp_pci_rd_reg(isp, BIU_CONF1); 696d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oldconf | BIU_PCI_CONF1_SXP); 69765adb54cSMatt Jacob } 698d59bd469SMatt Jacob offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT]; 699d59bd469SMatt Jacob offset += (regoff & 0xff); 70065adb54cSMatt Jacob rv = bus_space_read_2(pcs->pci_st, pcs->pci_sh, offset); 701d59bd469SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 702d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oldconf); 70365adb54cSMatt Jacob } 70465adb54cSMatt Jacob return (rv); 70565adb54cSMatt Jacob } 70665adb54cSMatt Jacob 70765adb54cSMatt Jacob static void 708d59bd469SMatt Jacob isp_pci_wr_reg(isp, regoff, val) 709d59bd469SMatt Jacob struct ispsoftc *isp; 710d59bd469SMatt Jacob int regoff; 711d59bd469SMatt Jacob u_int16_t val; 71265adb54cSMatt Jacob { 71365adb54cSMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 714d59bd469SMatt Jacob int offset, oldconf = 0; 715d59bd469SMatt Jacob 716d59bd469SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 71765adb54cSMatt Jacob /* 71865adb54cSMatt Jacob * We will assume that someone has paused the RISC processor. 71965adb54cSMatt Jacob */ 720d59bd469SMatt Jacob oldconf = isp_pci_rd_reg(isp, BIU_CONF1); 721d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oldconf | BIU_PCI_CONF1_SXP); 72265adb54cSMatt Jacob } 723d59bd469SMatt Jacob offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT]; 724d59bd469SMatt Jacob offset += (regoff & 0xff); 72565adb54cSMatt Jacob bus_space_write_2(pcs->pci_st, pcs->pci_sh, offset, val); 726d59bd469SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 727d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oldconf); 72865adb54cSMatt Jacob } 72965adb54cSMatt Jacob } 73065adb54cSMatt Jacob 731d59bd469SMatt Jacob static u_int16_t 732d59bd469SMatt Jacob isp_pci_rd_reg_1080(isp, regoff) 733d59bd469SMatt Jacob struct ispsoftc *isp; 734d59bd469SMatt Jacob int regoff; 735d59bd469SMatt Jacob { 73622e1dc85SMatt Jacob u_int16_t rv, oc = 0; 737d59bd469SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 73822e1dc85SMatt Jacob int offset; 739d59bd469SMatt Jacob 74022e1dc85SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK || 74122e1dc85SMatt Jacob (regoff & _BLK_REG_MASK) == (SXP_BLOCK|SXP_BANK1_SELECT)) { 74222e1dc85SMatt Jacob u_int16_t tc; 743d59bd469SMatt Jacob /* 744d59bd469SMatt Jacob * We will assume that someone has paused the RISC processor. 745d59bd469SMatt Jacob */ 746d59bd469SMatt Jacob oc = isp_pci_rd_reg(isp, BIU_CONF1); 74722e1dc85SMatt Jacob tc = oc & ~BIU_PCI1080_CONF1_DMA; 74822e1dc85SMatt Jacob if (regoff & SXP_BANK1_SELECT) 74922e1dc85SMatt Jacob tc |= BIU_PCI1080_CONF1_SXP1; 75022e1dc85SMatt Jacob else 75122e1dc85SMatt Jacob tc |= BIU_PCI1080_CONF1_SXP0; 75222e1dc85SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, tc); 753d59bd469SMatt Jacob } else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) { 754d59bd469SMatt Jacob oc = isp_pci_rd_reg(isp, BIU_CONF1); 755d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oc | BIU_PCI1080_CONF1_DMA); 756d59bd469SMatt Jacob } 757d59bd469SMatt Jacob offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT]; 758d59bd469SMatt Jacob offset += (regoff & 0xff); 759d59bd469SMatt Jacob rv = bus_space_read_2(pcs->pci_st, pcs->pci_sh, offset); 76022e1dc85SMatt Jacob if (oc) { 761d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oc); 762d59bd469SMatt Jacob } 763d59bd469SMatt Jacob return (rv); 764d59bd469SMatt Jacob } 765d59bd469SMatt Jacob 766d59bd469SMatt Jacob static void 767d59bd469SMatt Jacob isp_pci_wr_reg_1080(isp, regoff, val) 768d59bd469SMatt Jacob struct ispsoftc *isp; 769d59bd469SMatt Jacob int regoff; 770d59bd469SMatt Jacob u_int16_t val; 771d59bd469SMatt Jacob { 772d59bd469SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 773d59bd469SMatt Jacob int offset, oc = 0; 774d59bd469SMatt Jacob 77522e1dc85SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK || 77622e1dc85SMatt Jacob (regoff & _BLK_REG_MASK) == (SXP_BLOCK|SXP_BANK1_SELECT)) { 77722e1dc85SMatt Jacob u_int16_t tc; 778d59bd469SMatt Jacob /* 779d59bd469SMatt Jacob * We will assume that someone has paused the RISC processor. 780d59bd469SMatt Jacob */ 781d59bd469SMatt Jacob oc = isp_pci_rd_reg(isp, BIU_CONF1); 78222e1dc85SMatt Jacob tc = oc & ~BIU_PCI1080_CONF1_DMA; 78322e1dc85SMatt Jacob if (regoff & SXP_BANK1_SELECT) 78422e1dc85SMatt Jacob tc |= BIU_PCI1080_CONF1_SXP1; 78522e1dc85SMatt Jacob else 78622e1dc85SMatt Jacob tc |= BIU_PCI1080_CONF1_SXP0; 78722e1dc85SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, tc); 788d59bd469SMatt Jacob } else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) { 789d59bd469SMatt Jacob oc = isp_pci_rd_reg(isp, BIU_CONF1); 790d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oc | BIU_PCI1080_CONF1_DMA); 791d59bd469SMatt Jacob } 792d59bd469SMatt Jacob offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT]; 793d59bd469SMatt Jacob offset += (regoff & 0xff); 794d59bd469SMatt Jacob bus_space_write_2(pcs->pci_st, pcs->pci_sh, offset, val); 79522e1dc85SMatt Jacob if (oc) { 796d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oc); 797d59bd469SMatt Jacob } 798d59bd469SMatt Jacob } 799d59bd469SMatt Jacob 800d720e6d5SJustin T. Gibbs static void isp_map_rquest __P((void *, bus_dma_segment_t *, int, int)); 801d720e6d5SJustin T. Gibbs static void isp_map_result __P((void *, bus_dma_segment_t *, int, int)); 802d720e6d5SJustin T. Gibbs static void isp_map_fcscrt __P((void *, bus_dma_segment_t *, int, int)); 803d720e6d5SJustin T. Gibbs 804222bb542SMatt Jacob struct imush { 805222bb542SMatt Jacob struct ispsoftc *isp; 806222bb542SMatt Jacob int error; 807222bb542SMatt Jacob }; 808222bb542SMatt Jacob 809d720e6d5SJustin T. Gibbs static void 81017e318c6SMatt Jacob isp_map_rquest(void *arg, bus_dma_segment_t *segs, int nseg, int error) 811d720e6d5SJustin T. Gibbs { 812222bb542SMatt Jacob struct imush *imushp = (struct imush *) arg; 813222bb542SMatt Jacob if (error) { 814222bb542SMatt Jacob imushp->error = error; 815222bb542SMatt Jacob } else { 816222bb542SMatt Jacob imushp->isp->isp_rquest_dma = segs->ds_addr; 817222bb542SMatt Jacob } 818d720e6d5SJustin T. Gibbs } 819d720e6d5SJustin T. Gibbs 820d720e6d5SJustin T. Gibbs static void 82117e318c6SMatt Jacob isp_map_result(void *arg, bus_dma_segment_t *segs, int nseg, int error) 822d720e6d5SJustin T. Gibbs { 823222bb542SMatt Jacob struct imush *imushp = (struct imush *) arg; 824222bb542SMatt Jacob if (error) { 825222bb542SMatt Jacob imushp->error = error; 826222bb542SMatt Jacob } else { 827222bb542SMatt Jacob imushp->isp->isp_result_dma = segs->ds_addr; 828222bb542SMatt Jacob } 829d720e6d5SJustin T. Gibbs } 830d720e6d5SJustin T. Gibbs 831d720e6d5SJustin T. Gibbs static void 83217e318c6SMatt Jacob isp_map_fcscrt(void *arg, bus_dma_segment_t *segs, int nseg, int error) 833d720e6d5SJustin T. Gibbs { 834222bb542SMatt Jacob struct imush *imushp = (struct imush *) arg; 835222bb542SMatt Jacob if (error) { 836222bb542SMatt Jacob imushp->error = error; 837222bb542SMatt Jacob } else { 838222bb542SMatt Jacob fcparam *fcp = imushp->isp->isp_param; 839d720e6d5SJustin T. Gibbs fcp->isp_scdma = segs->ds_addr; 840d720e6d5SJustin T. Gibbs } 841222bb542SMatt Jacob } 842d720e6d5SJustin T. Gibbs 843d720e6d5SJustin T. Gibbs static int 84417e318c6SMatt Jacob isp_pci_mbxdma(struct ispsoftc *isp) 845d720e6d5SJustin T. Gibbs { 846d720e6d5SJustin T. Gibbs struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp; 847d720e6d5SJustin T. Gibbs caddr_t base; 848d720e6d5SJustin T. Gibbs u_int32_t len; 849d720e6d5SJustin T. Gibbs int i, error; 850222bb542SMatt Jacob bus_size_t lim; 851222bb542SMatt Jacob struct imush im; 852222bb542SMatt Jacob 853222bb542SMatt Jacob 854a95ae193SMatt Jacob /* 855a95ae193SMatt Jacob * Already been here? If so, leave... 856a95ae193SMatt Jacob */ 857a95ae193SMatt Jacob if (isp->isp_rquest) { 858a95ae193SMatt Jacob return (0); 859a95ae193SMatt Jacob } 860a95ae193SMatt Jacob 861a95ae193SMatt Jacob len = sizeof (ISP_SCSI_XFER_T **) * isp->isp_maxcmds; 862a95ae193SMatt Jacob isp->isp_xflist = (ISP_SCSI_XFER_T **) malloc(len, M_DEVBUF, M_WAITOK); 863a95ae193SMatt Jacob if (isp->isp_xflist == NULL) { 864a95ae193SMatt Jacob printf("%s: can't alloc xflist array\n", isp->isp_name); 865a95ae193SMatt Jacob return (1); 866a95ae193SMatt Jacob } 867a95ae193SMatt Jacob bzero(isp->isp_xflist, len); 868a95ae193SMatt Jacob len = sizeof (bus_dmamap_t) * isp->isp_maxcmds; 869a95ae193SMatt Jacob pci->dmaps = (bus_dmamap_t *) malloc(len, M_DEVBUF, M_WAITOK); 870a95ae193SMatt Jacob if (pci->dmaps == NULL) { 871a95ae193SMatt Jacob printf("%s: can't alloc dma maps\n", isp->isp_name); 872a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 873a95ae193SMatt Jacob return (1); 874a95ae193SMatt Jacob } 875a95ae193SMatt Jacob 87622e1dc85SMatt Jacob if (IS_FC(isp) || IS_ULTRA2(isp)) 877222bb542SMatt Jacob lim = BUS_SPACE_MAXADDR + 1; 878222bb542SMatt Jacob else 879222bb542SMatt Jacob lim = BUS_SPACE_MAXADDR_24BIT + 1; 880d720e6d5SJustin T. Gibbs 881d720e6d5SJustin T. Gibbs /* 882d720e6d5SJustin T. Gibbs * Allocate and map the request, result queues, plus FC scratch area. 883d720e6d5SJustin T. Gibbs */ 884d720e6d5SJustin T. Gibbs len = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN); 885d720e6d5SJustin T. Gibbs len += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN); 886222bb542SMatt Jacob if (IS_FC(isp)) { 887d720e6d5SJustin T. Gibbs len += ISP2100_SCRLEN; 888d720e6d5SJustin T. Gibbs } 889222bb542SMatt Jacob if (bus_dma_tag_create(pci->parent_dmat, PAGE_SIZE, lim, 890222bb542SMatt Jacob BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, len, 1, 891222bb542SMatt Jacob BUS_SPACE_MAXSIZE_32BIT, 0, &pci->cntrol_dmat) != 0) { 892d720e6d5SJustin T. Gibbs printf("%s: cannot create a dma tag for control spaces\n", 893d720e6d5SJustin T. Gibbs isp->isp_name); 894a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 895a95ae193SMatt Jacob free(pci->dmaps, M_DEVBUF); 896d720e6d5SJustin T. Gibbs return (1); 897d720e6d5SJustin T. Gibbs } 898d720e6d5SJustin T. Gibbs if (bus_dmamem_alloc(pci->cntrol_dmat, (void **)&base, 899d720e6d5SJustin T. Gibbs BUS_DMA_NOWAIT, &pci->cntrol_dmap) != 0) { 9004873663cSMatt Jacob printf("%s: cannot allocate %d bytes of CCB memory\n", 9014873663cSMatt Jacob isp->isp_name, len); 902a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 903a95ae193SMatt Jacob free(pci->dmaps, M_DEVBUF); 904d720e6d5SJustin T. Gibbs return (1); 905d720e6d5SJustin T. Gibbs } 906d720e6d5SJustin T. Gibbs 907d720e6d5SJustin T. Gibbs isp->isp_rquest = base; 908222bb542SMatt Jacob im.isp = isp; 909222bb542SMatt Jacob im.error = 0; 910d720e6d5SJustin T. Gibbs bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap, isp->isp_rquest, 911222bb542SMatt Jacob ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN), isp_map_rquest, &im, 0); 912222bb542SMatt Jacob if (im.error) { 913222bb542SMatt Jacob printf("%s: error %d loading dma map for DMA request queue\n", 914222bb542SMatt Jacob isp->isp_name, im.error); 915a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 916a95ae193SMatt Jacob free(pci->dmaps, M_DEVBUF); 917a95ae193SMatt Jacob isp->isp_rquest = NULL; 918222bb542SMatt Jacob return (1); 919222bb542SMatt Jacob } 920d720e6d5SJustin T. Gibbs isp->isp_result = base + ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN); 921222bb542SMatt Jacob im.error = 0; 922d720e6d5SJustin T. Gibbs bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap, isp->isp_result, 923222bb542SMatt Jacob ISP_QUEUE_SIZE(RESULT_QUEUE_LEN), isp_map_result, &im, 0); 924222bb542SMatt Jacob if (im.error) { 925222bb542SMatt Jacob printf("%s: error %d loading dma map for DMA result queue\n", 926222bb542SMatt Jacob isp->isp_name, im.error); 927a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 928a95ae193SMatt Jacob free(pci->dmaps, M_DEVBUF); 929a95ae193SMatt Jacob isp->isp_rquest = NULL; 930222bb542SMatt Jacob return (1); 931222bb542SMatt Jacob } 932d720e6d5SJustin T. Gibbs 933a95ae193SMatt Jacob for (i = 0; i < isp->isp_maxcmds; i++) { 934d720e6d5SJustin T. Gibbs error = bus_dmamap_create(pci->parent_dmat, 0, &pci->dmaps[i]); 935d720e6d5SJustin T. Gibbs if (error) { 936a95ae193SMatt Jacob printf("%s: error %d creating per-cmd DMA maps\n", 937d720e6d5SJustin T. Gibbs isp->isp_name, error); 938a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 939a95ae193SMatt Jacob free(pci->dmaps, M_DEVBUF); 940a95ae193SMatt Jacob isp->isp_rquest = NULL; 941d720e6d5SJustin T. Gibbs return (1); 942d720e6d5SJustin T. Gibbs } 943d720e6d5SJustin T. Gibbs } 944a95ae193SMatt Jacob 945222bb542SMatt Jacob if (IS_FC(isp)) { 94692c49d78SMatt Jacob fcparam *fcp = (fcparam *) isp->isp_param; 94792c49d78SMatt Jacob fcp->isp_scratch = base + 94892c49d78SMatt Jacob ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN) + 94992c49d78SMatt Jacob ISP_QUEUE_SIZE(RESULT_QUEUE_LEN); 950222bb542SMatt Jacob im.error = 0; 95192c49d78SMatt Jacob bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap, 952222bb542SMatt Jacob fcp->isp_scratch, ISP2100_SCRLEN, isp_map_fcscrt, &im, 0); 953222bb542SMatt Jacob if (im.error) { 954222bb542SMatt Jacob printf("%s: error %d loading FC scratch area\n", 955222bb542SMatt Jacob isp->isp_name, im.error); 956a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 957a95ae193SMatt Jacob free(pci->dmaps, M_DEVBUF); 958a95ae193SMatt Jacob isp->isp_rquest = NULL; 959222bb542SMatt Jacob return (1); 960222bb542SMatt Jacob } 96192c49d78SMatt Jacob } 962d720e6d5SJustin T. Gibbs return (0); 963d720e6d5SJustin T. Gibbs } 964d720e6d5SJustin T. Gibbs 965d720e6d5SJustin T. Gibbs typedef struct { 966d720e6d5SJustin T. Gibbs struct ispsoftc *isp; 9679e11e5beSMatt Jacob void *cmd_token; 9689e11e5beSMatt Jacob void *rq; 9699637d68cSMatt Jacob u_int16_t *iptrp; 9709637d68cSMatt Jacob u_int16_t optr; 971d720e6d5SJustin T. Gibbs u_int error; 972d720e6d5SJustin T. Gibbs } mush_t; 973d720e6d5SJustin T. Gibbs 9744873663cSMatt Jacob #define MUSHERR_NOQENTRIES -2 9754873663cSMatt Jacob 9769e11e5beSMatt Jacob #ifdef ISP_TARGET_MODE 9779e11e5beSMatt Jacob /* 9789e11e5beSMatt Jacob * We need to handle DMA for target mode differently from initiator mode. 9799e11e5beSMatt Jacob * 9809e11e5beSMatt Jacob * DMA mapping and construction and submission of CTIO Request Entries 9819e11e5beSMatt Jacob * and rendevous for completion are very tightly coupled because we start 9829e11e5beSMatt Jacob * out by knowing (per platform) how much data we have to move, but we 9839e11e5beSMatt Jacob * don't know, up front, how many DMA mapping segments will have to be used 9849e11e5beSMatt Jacob * cover that data, so we don't know how many CTIO Request Entries we 9859e11e5beSMatt Jacob * will end up using. Further, for performance reasons we may want to 9869e11e5beSMatt Jacob * (on the last CTIO for Fibre Channel), send status too (if all went well). 9879e11e5beSMatt Jacob * 9889e11e5beSMatt Jacob * The standard vector still goes through isp_pci_dmasetup, but the callback 9899e11e5beSMatt Jacob * for the DMA mapping routines comes here instead with the whole transfer 9909e11e5beSMatt Jacob * mapped and a pointer to a partially filled in already allocated request 9919e11e5beSMatt Jacob * queue entry. We finish the job. 9929e11e5beSMatt Jacob */ 99305fbcbb0SMatt Jacob static void tdma_mk __P((void *, bus_dma_segment_t *, int, int)); 99405fbcbb0SMatt Jacob static void tdma_mkfc __P((void *, bus_dma_segment_t *, int, int)); 9959e11e5beSMatt Jacob 996d720e6d5SJustin T. Gibbs static void 99705fbcbb0SMatt Jacob tdma_mk(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 998d720e6d5SJustin T. Gibbs { 999d720e6d5SJustin T. Gibbs mush_t *mp; 10009e11e5beSMatt Jacob struct ccb_scsiio *csio; 1001d720e6d5SJustin T. Gibbs struct isp_pcisoftc *pci; 1002d720e6d5SJustin T. Gibbs bus_dmamap_t *dp; 100305fbcbb0SMatt Jacob u_int8_t scsi_status; 10049e11e5beSMatt Jacob ct_entry_t *cto; 100505fbcbb0SMatt Jacob u_int32_t handle, totxfr, sflags; 100605fbcbb0SMatt Jacob int nctios, send_status; 100705fbcbb0SMatt Jacob int32_t resid; 1008d720e6d5SJustin T. Gibbs 1009d720e6d5SJustin T. Gibbs mp = (mush_t *) arg; 1010d720e6d5SJustin T. Gibbs if (error) { 1011d720e6d5SJustin T. Gibbs mp->error = error; 1012d720e6d5SJustin T. Gibbs return; 1013d720e6d5SJustin T. Gibbs } 10149e11e5beSMatt Jacob csio = mp->cmd_token; 10159e11e5beSMatt Jacob cto = mp->rq; 10169e11e5beSMatt Jacob 101765b024e1SMatt Jacob cto->ct_xfrlen = 0; 101865b024e1SMatt Jacob cto->ct_seg_count = 0; 101965b024e1SMatt Jacob cto->ct_header.rqs_entry_count = 1; 102005fbcbb0SMatt Jacob MEMZERO(cto->ct_dataseg, sizeof(cto->ct_dataseg)); 102105fbcbb0SMatt Jacob 102205fbcbb0SMatt Jacob if (nseg == 0) { 102305fbcbb0SMatt Jacob cto->ct_header.rqs_seqno = 1; 102405fbcbb0SMatt Jacob ISP_TDQE(mp->isp, "tdma_mk[no data]", *mp->iptrp, cto); 102565b024e1SMatt Jacob if (isp_tdebug) { 102665b024e1SMatt Jacob printf("%s:CTIO lun %d->iid%d flgs 0x%x sts 0x%x ssts " 102705fbcbb0SMatt Jacob "0x%x res %d\n", mp->isp->isp_name, 102865b024e1SMatt Jacob csio->ccb_h.target_lun, cto->ct_iid, cto->ct_flags, 102965b024e1SMatt Jacob cto->ct_status, cto->ct_scsi_status, cto->ct_resid); 103065b024e1SMatt Jacob } 103105fbcbb0SMatt Jacob ISP_SWIZ_CTIO(mp->isp, cto, cto); 103265b024e1SMatt Jacob return; 103365b024e1SMatt Jacob } 103465b024e1SMatt Jacob 103565b024e1SMatt Jacob nctios = nseg / ISP_RQDSEG; 103665b024e1SMatt Jacob if (nseg % ISP_RQDSEG) { 103765b024e1SMatt Jacob nctios++; 103865b024e1SMatt Jacob } 103965b024e1SMatt Jacob 104005fbcbb0SMatt Jacob /* 104105fbcbb0SMatt Jacob * Save handle, and potentially any SCSI status, which we'll reinsert 104205fbcbb0SMatt Jacob * on the last CTIO we're going to send. 104305fbcbb0SMatt Jacob */ 104405fbcbb0SMatt Jacob handle = cto->ct_reserved; 104505fbcbb0SMatt Jacob cto->ct_reserved = 0; 104605fbcbb0SMatt Jacob cto->ct_header.rqs_seqno = 0; 104705fbcbb0SMatt Jacob send_status = (cto->ct_flags & CT_SENDSTATUS) != 0; 104805fbcbb0SMatt Jacob 104905fbcbb0SMatt Jacob if (send_status) { 105005fbcbb0SMatt Jacob sflags = cto->ct_flags & (CT_SENDSTATUS | CT_CCINCR); 105105fbcbb0SMatt Jacob cto->ct_flags &= ~(CT_SENDSTATUS | CT_CCINCR); 105205fbcbb0SMatt Jacob /* 105305fbcbb0SMatt Jacob * Preserve residual. 105405fbcbb0SMatt Jacob */ 105505fbcbb0SMatt Jacob resid = cto->ct_resid; 105605fbcbb0SMatt Jacob 105705fbcbb0SMatt Jacob /* 105805fbcbb0SMatt Jacob * Save actual SCSI status. 105905fbcbb0SMatt Jacob */ 106005fbcbb0SMatt Jacob scsi_status = cto->ct_scsi_status; 106105fbcbb0SMatt Jacob 106205fbcbb0SMatt Jacob /* 106305fbcbb0SMatt Jacob * We can't do a status at the same time as a data CTIO, so 106405fbcbb0SMatt Jacob * we need to synthesize an extra CTIO at this level. 106505fbcbb0SMatt Jacob */ 106605fbcbb0SMatt Jacob nctios++; 106705fbcbb0SMatt Jacob } else { 106805fbcbb0SMatt Jacob sflags = scsi_status = resid = 0; 106905fbcbb0SMatt Jacob } 107005fbcbb0SMatt Jacob 107105fbcbb0SMatt Jacob totxfr = cto->ct_resid = 0; 107205fbcbb0SMatt Jacob cto->ct_scsi_status = 0; 107305fbcbb0SMatt Jacob 10749e11e5beSMatt Jacob pci = (struct isp_pcisoftc *)mp->isp; 1075469b6b9eSMatt Jacob dp = &pci->dmaps[isp_handle_index(handle)]; 10769e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 1077d720e6d5SJustin T. Gibbs bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREREAD); 1078d720e6d5SJustin T. Gibbs } else { 1079d720e6d5SJustin T. Gibbs bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREWRITE); 1080d720e6d5SJustin T. Gibbs } 1081d720e6d5SJustin T. Gibbs 10829e11e5beSMatt Jacob 10839e11e5beSMatt Jacob while (nctios--) { 108405fbcbb0SMatt Jacob int seglim; 10859e11e5beSMatt Jacob 10869e11e5beSMatt Jacob seglim = nseg; 108705fbcbb0SMatt Jacob if (seglim) { 108805fbcbb0SMatt Jacob int seg; 108905fbcbb0SMatt Jacob 10909e11e5beSMatt Jacob if (seglim > ISP_RQDSEG) 10919e11e5beSMatt Jacob seglim = ISP_RQDSEG; 10929e11e5beSMatt Jacob 109305fbcbb0SMatt Jacob for (seg = 0; seg < seglim; seg++, nseg--) { 109405fbcbb0SMatt Jacob /* 109505fbcbb0SMatt Jacob * Unlike normal initiator commands, we don't 109605fbcbb0SMatt Jacob * do any swizzling here. 109705fbcbb0SMatt Jacob */ 10989e11e5beSMatt Jacob cto->ct_dataseg[seg].ds_count = dm_segs->ds_len; 109905fbcbb0SMatt Jacob cto->ct_dataseg[seg].ds_base = dm_segs->ds_addr; 11009e11e5beSMatt Jacob cto->ct_xfrlen += dm_segs->ds_len; 110105fbcbb0SMatt Jacob totxfr += dm_segs->ds_len; 11029e11e5beSMatt Jacob dm_segs++; 11039e11e5beSMatt Jacob } 11049e11e5beSMatt Jacob cto->ct_seg_count = seg; 11059e11e5beSMatt Jacob } else { 110605fbcbb0SMatt Jacob /* 110705fbcbb0SMatt Jacob * This case should only happen when we're sending an 110805fbcbb0SMatt Jacob * extra CTIO with final status. 110905fbcbb0SMatt Jacob */ 111005fbcbb0SMatt Jacob if (send_status == 0) { 111105fbcbb0SMatt Jacob printf("%s: tdma_mk ran out of segments\n", 111205fbcbb0SMatt Jacob mp->isp->isp_name); 111305fbcbb0SMatt Jacob mp->error = EINVAL; 111405fbcbb0SMatt Jacob return; 11159e11e5beSMatt Jacob } 111605fbcbb0SMatt Jacob } 111705fbcbb0SMatt Jacob 111805fbcbb0SMatt Jacob /* 111905fbcbb0SMatt Jacob * At this point, the fields ct_lun, ct_iid, ct_tagval, 112005fbcbb0SMatt Jacob * ct_tagtype, and ct_timeout have been carried over 112105fbcbb0SMatt Jacob * unchanged from what our caller had set. 112205fbcbb0SMatt Jacob * 112305fbcbb0SMatt Jacob * The dataseg fields and the seg_count fields we just got 112405fbcbb0SMatt Jacob * through setting. The data direction we've preserved all 112505fbcbb0SMatt Jacob * along and only clear it if we're now sending status. 112605fbcbb0SMatt Jacob */ 11279e11e5beSMatt Jacob 11289e11e5beSMatt Jacob if (nctios == 0) { 11299e11e5beSMatt Jacob /* 113005fbcbb0SMatt Jacob * We're the last in a sequence of CTIOs, so mark 113105fbcbb0SMatt Jacob * this CTIO and save the handle to the CCB such that 113205fbcbb0SMatt Jacob * when this CTIO completes we can free dma resources 113305fbcbb0SMatt Jacob * and do whatever else we need to do to finish the 113405fbcbb0SMatt Jacob * rest of the command. 11359e11e5beSMatt Jacob */ 11369e11e5beSMatt Jacob cto->ct_reserved = handle; 113705fbcbb0SMatt Jacob cto->ct_header.rqs_seqno = 1; 113805fbcbb0SMatt Jacob 113905fbcbb0SMatt Jacob if (send_status) { 11409e11e5beSMatt Jacob cto->ct_scsi_status = scsi_status; 114105fbcbb0SMatt Jacob cto->ct_flags |= sflags | CT_NO_DATA;; 114205fbcbb0SMatt Jacob cto->ct_resid = resid; 114342426921SMatt Jacob } 114405fbcbb0SMatt Jacob if (isp_tdebug && send_status) { 114505fbcbb0SMatt Jacob printf("%s:CTIO lun%d for ID%d ct_flags 0x%x " 114605fbcbb0SMatt Jacob "scsi_status 0x%x res %d\n", 114705fbcbb0SMatt Jacob mp->isp->isp_name, csio->ccb_h.target_lun, 114805fbcbb0SMatt Jacob cto->ct_iid, cto->ct_flags, 114905fbcbb0SMatt Jacob cto->ct_scsi_status, cto->ct_resid); 115005fbcbb0SMatt Jacob } else if (isp_tdebug) { 115105fbcbb0SMatt Jacob printf("%s:CTIO lun%d for ID%d ct_flags 0x%x\n", 115205fbcbb0SMatt Jacob mp->isp->isp_name, csio->ccb_h.target_lun, 115305fbcbb0SMatt Jacob cto->ct_iid, cto->ct_flags); 115405fbcbb0SMatt Jacob } 115505fbcbb0SMatt Jacob ISP_TDQE(mp->isp, "last tdma_mk", *mp->iptrp, cto); 115605fbcbb0SMatt Jacob ISP_SWIZ_CTIO(mp->isp, cto, cto); 11579e11e5beSMatt Jacob } else { 11589e11e5beSMatt Jacob ct_entry_t *octo = cto; 115905fbcbb0SMatt Jacob 116005fbcbb0SMatt Jacob /* 116105fbcbb0SMatt Jacob * Make sure handle fields are clean 116205fbcbb0SMatt Jacob */ 11639e11e5beSMatt Jacob cto->ct_reserved = 0; 11649e11e5beSMatt Jacob cto->ct_header.rqs_seqno = 0; 116505fbcbb0SMatt Jacob 116642426921SMatt Jacob if (isp_tdebug) { 116705fbcbb0SMatt Jacob printf("%s:CTIO lun%d for ID%d ct_flags 0x%x\n", 116805fbcbb0SMatt Jacob mp->isp->isp_name, csio->ccb_h.target_lun, 116905fbcbb0SMatt Jacob cto->ct_iid, cto->ct_flags); 117042426921SMatt Jacob } 117105fbcbb0SMatt Jacob ISP_TDQE(mp->isp, "tdma_mk", *mp->iptrp, cto); 117205fbcbb0SMatt Jacob 117305fbcbb0SMatt Jacob /* 117405fbcbb0SMatt Jacob * Get a new CTIO 117505fbcbb0SMatt Jacob */ 11769e11e5beSMatt Jacob cto = (ct_entry_t *) 11779e11e5beSMatt Jacob ISP_QUEUE_ENTRY(mp->isp->isp_rquest, *mp->iptrp); 11789e11e5beSMatt Jacob *mp->iptrp = 11799e11e5beSMatt Jacob ISP_NXT_QENTRY(*mp->iptrp, RQUEST_QUEUE_LEN); 11809e11e5beSMatt Jacob if (*mp->iptrp == mp->optr) { 118105fbcbb0SMatt Jacob printf("%s: Queue Overflow in tdma_mk\n", 11829e11e5beSMatt Jacob mp->isp->isp_name); 11839e11e5beSMatt Jacob mp->error = MUSHERR_NOQENTRIES; 11849e11e5beSMatt Jacob return; 11859e11e5beSMatt Jacob } 11869e11e5beSMatt Jacob /* 11879e11e5beSMatt Jacob * Fill in the new CTIO with info from the old one. 11889e11e5beSMatt Jacob */ 11899e11e5beSMatt Jacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO; 11909e11e5beSMatt Jacob cto->ct_header.rqs_entry_count = 1; 11919e11e5beSMatt Jacob cto->ct_header.rqs_flags = 0; 11929e11e5beSMatt Jacob cto->ct_lun = octo->ct_lun; 11939e11e5beSMatt Jacob cto->ct_iid = octo->ct_iid; 11949e11e5beSMatt Jacob cto->ct_reserved2 = octo->ct_reserved2; 11959e11e5beSMatt Jacob cto->ct_tgt = octo->ct_tgt; 119605fbcbb0SMatt Jacob cto->ct_flags = octo->ct_flags; 11979e11e5beSMatt Jacob cto->ct_status = 0; 11989e11e5beSMatt Jacob cto->ct_scsi_status = 0; 11999e11e5beSMatt Jacob cto->ct_tag_val = octo->ct_tag_val; 12009e11e5beSMatt Jacob cto->ct_tag_type = octo->ct_tag_type; 12019e11e5beSMatt Jacob cto->ct_xfrlen = 0; 12029e11e5beSMatt Jacob cto->ct_resid = 0; 12039e11e5beSMatt Jacob cto->ct_timeout = octo->ct_timeout; 12049e11e5beSMatt Jacob cto->ct_seg_count = 0; 120505fbcbb0SMatt Jacob MEMZERO(cto->ct_dataseg, sizeof(cto->ct_dataseg)); 120605fbcbb0SMatt Jacob /* 120705fbcbb0SMatt Jacob * Now swizzle the old one for the consumption of the 120805fbcbb0SMatt Jacob * chip. 120905fbcbb0SMatt Jacob */ 121005fbcbb0SMatt Jacob ISP_SWIZ_CTIO(mp->isp, octo, octo); 12119e11e5beSMatt Jacob } 12129e11e5beSMatt Jacob } 12139e11e5beSMatt Jacob } 12149e11e5beSMatt Jacob 12159e11e5beSMatt Jacob static void 121605fbcbb0SMatt Jacob tdma_mkfc(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 12179e11e5beSMatt Jacob { 12189e11e5beSMatt Jacob mush_t *mp; 12199e11e5beSMatt Jacob struct ccb_scsiio *csio; 12209e11e5beSMatt Jacob struct isp_pcisoftc *pci; 12219e11e5beSMatt Jacob bus_dmamap_t *dp; 12229e11e5beSMatt Jacob ct2_entry_t *cto; 122365b024e1SMatt Jacob u_int16_t scsi_status, send_status, send_sense; 122405fbcbb0SMatt Jacob u_int32_t handle, totxfr, datalen; 122565b024e1SMatt Jacob u_int8_t sense[QLTM_SENSELEN]; 12269e11e5beSMatt Jacob int nctios; 12279e11e5beSMatt Jacob 12289e11e5beSMatt Jacob mp = (mush_t *) arg; 12299e11e5beSMatt Jacob if (error) { 12309e11e5beSMatt Jacob mp->error = error; 12319e11e5beSMatt Jacob return; 12329e11e5beSMatt Jacob } 12339e11e5beSMatt Jacob 123465b024e1SMatt Jacob csio = mp->cmd_token; 123565b024e1SMatt Jacob cto = mp->rq; 123665b024e1SMatt Jacob 123765b024e1SMatt Jacob if (nseg == 0) { 123865b024e1SMatt Jacob if ((cto->ct_flags & CT2_FLAG_MMASK) != CT2_FLAG_MODE1) { 123965b024e1SMatt Jacob printf("%s: dma2_tgt_fc, a status CTIO2 without MODE1 " 124065b024e1SMatt Jacob "set (0x%x)\n", mp->isp->isp_name, cto->ct_flags); 124165b024e1SMatt Jacob mp->error = EINVAL; 124265b024e1SMatt Jacob return; 124365b024e1SMatt Jacob } 124465b024e1SMatt Jacob cto->ct_header.rqs_entry_count = 1; 124505fbcbb0SMatt Jacob cto->ct_header.rqs_seqno = 1; 124665b024e1SMatt Jacob /* ct_reserved contains the handle set by caller */ 124765b024e1SMatt Jacob /* 124865b024e1SMatt Jacob * We preserve ct_lun, ct_iid, ct_rxid. We set the data 124965b024e1SMatt Jacob * flags to NO DATA and clear relative offset flags. 125065b024e1SMatt Jacob * We preserve the ct_resid and the response area. 125165b024e1SMatt Jacob */ 125265b024e1SMatt Jacob cto->ct_flags |= CT2_NO_DATA; 125305fbcbb0SMatt Jacob if (cto->ct_resid > 0) 125405fbcbb0SMatt Jacob cto->ct_flags |= CT2_DATA_UNDER; 125505fbcbb0SMatt Jacob else if (cto->ct_resid < 0) 125605fbcbb0SMatt Jacob cto->ct_flags |= CT2_DATA_OVER; 125765b024e1SMatt Jacob cto->ct_seg_count = 0; 125865b024e1SMatt Jacob cto->ct_reloff = 0; 125965b024e1SMatt Jacob ISP_TDQE(mp->isp, "dma2_tgt_fc[no data]", *mp->iptrp, cto); 126065b024e1SMatt Jacob if (isp_tdebug) { 126165b024e1SMatt Jacob scsi_status = cto->rsp.m1.ct_scsi_status; 126265b024e1SMatt Jacob printf("%s:CTIO2 RX_ID 0x%x lun %d->iid%d flgs 0x%x " 126305fbcbb0SMatt Jacob "sts 0x%x ssts 0x%x res %d\n", mp->isp->isp_name, 126465b024e1SMatt Jacob cto->ct_rxid, csio->ccb_h.target_lun, cto->ct_iid, 126565b024e1SMatt Jacob cto->ct_flags, cto->ct_status, 126665b024e1SMatt Jacob cto->rsp.m1.ct_scsi_status, cto->ct_resid); 126765b024e1SMatt Jacob } 126865b024e1SMatt Jacob ISP_SWIZ_CTIO2(isp, cto, cto); 12699e11e5beSMatt Jacob return; 12709e11e5beSMatt Jacob } 12719e11e5beSMatt Jacob 127265b024e1SMatt Jacob if ((cto->ct_flags & CT2_FLAG_MMASK) != CT2_FLAG_MODE0) { 127365b024e1SMatt Jacob printf("%s: dma2_tgt_fc, a data CTIO2 without MODE0 set " 127465b024e1SMatt Jacob "(0x%x)\n\n", mp->isp->isp_name, cto->ct_flags); 127565b024e1SMatt Jacob mp->error = EINVAL; 127665b024e1SMatt Jacob return; 127765b024e1SMatt Jacob } 127865b024e1SMatt Jacob 127965b024e1SMatt Jacob 128065b024e1SMatt Jacob nctios = nseg / ISP_RQDSEG_T2; 128165b024e1SMatt Jacob if (nseg % ISP_RQDSEG_T2) { 128265b024e1SMatt Jacob nctios++; 128365b024e1SMatt Jacob } 128465b024e1SMatt Jacob 12859e11e5beSMatt Jacob /* 128665b024e1SMatt Jacob * Save the handle, status, reloff, and residual. We'll reinsert the 128765b024e1SMatt Jacob * handle into the last CTIO2 we're going to send, and reinsert status 128865b024e1SMatt Jacob * and residual (and possibly sense data) if that's to be sent as well. 128965b024e1SMatt Jacob * 129065b024e1SMatt Jacob * We preserve ct_reloff and adjust it for each data CTIO2 we send past 129165b024e1SMatt Jacob * the first one. This is needed so that the FCP DATA IUs being sent 129265b024e1SMatt Jacob * out have the correct offset (they can arrive at the other end out 129365b024e1SMatt Jacob * of order). 12949e11e5beSMatt Jacob */ 129565b024e1SMatt Jacob 12969e11e5beSMatt Jacob handle = cto->ct_reserved; 12979e11e5beSMatt Jacob cto->ct_reserved = 0; 129865b024e1SMatt Jacob 129965b024e1SMatt Jacob if ((send_status = (cto->ct_flags & CT2_SENDSTATUS)) != 0) { 13009e11e5beSMatt Jacob cto->ct_flags &= ~CT2_SENDSTATUS; 13019e11e5beSMatt Jacob 130265b024e1SMatt Jacob /* 130305fbcbb0SMatt Jacob * Preserve residual, which is actually the total count. 130465b024e1SMatt Jacob */ 130505fbcbb0SMatt Jacob datalen = cto->ct_resid; 130665b024e1SMatt Jacob 130765b024e1SMatt Jacob /* 130865b024e1SMatt Jacob * Save actual SCSI status. We'll reinsert the 130965b024e1SMatt Jacob * CT2_SNSLEN_VALID later if appropriate. 131065b024e1SMatt Jacob */ 131165b024e1SMatt Jacob scsi_status = cto->rsp.m0.ct_scsi_status & 0xff; 131265b024e1SMatt Jacob send_sense = cto->rsp.m0.ct_scsi_status & CT2_SNSLEN_VALID; 131365b024e1SMatt Jacob 131465b024e1SMatt Jacob /* 131565b024e1SMatt Jacob * If we're sending status and have a CHECK CONDTION and 131665b024e1SMatt Jacob * have sense data, we send one more CTIO2 with just the 131765b024e1SMatt Jacob * status and sense data. The upper layers have stashed 131865b024e1SMatt Jacob * the sense data in the dataseg structure for us. 131965b024e1SMatt Jacob */ 132065b024e1SMatt Jacob 132165b024e1SMatt Jacob if ((scsi_status & 0xf) == SCSI_STATUS_CHECK_COND && 132265b024e1SMatt Jacob send_sense) { 132365b024e1SMatt Jacob bcopy(cto->rsp.m0.ct_dataseg, sense, QLTM_SENSELEN); 132465b024e1SMatt Jacob nctios++; 132565b024e1SMatt Jacob } 132665b024e1SMatt Jacob } else { 132705fbcbb0SMatt Jacob scsi_status = send_sense = datalen = 0; 132865b024e1SMatt Jacob } 132965b024e1SMatt Jacob 133065b024e1SMatt Jacob totxfr = cto->ct_resid = 0; 133165b024e1SMatt Jacob cto->rsp.m0.ct_scsi_status = 0; 133265b024e1SMatt Jacob bzero(&cto->rsp, sizeof (cto->rsp)); 133365b024e1SMatt Jacob 13349e11e5beSMatt Jacob pci = (struct isp_pcisoftc *)mp->isp; 1335469b6b9eSMatt Jacob dp = &pci->dmaps[isp_handle_index(handle)]; 13369e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 13379e11e5beSMatt Jacob bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREREAD); 13389e11e5beSMatt Jacob } else { 13399e11e5beSMatt Jacob bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREWRITE); 13409e11e5beSMatt Jacob } 13419e11e5beSMatt Jacob 13429e11e5beSMatt Jacob while (nctios--) { 13439e11e5beSMatt Jacob int seg, seglim; 13449e11e5beSMatt Jacob 13459e11e5beSMatt Jacob seglim = nseg; 134665b024e1SMatt Jacob if (seglim) { 13479e11e5beSMatt Jacob if (seglim > ISP_RQDSEG_T2) 13489e11e5beSMatt Jacob seglim = ISP_RQDSEG_T2; 13499e11e5beSMatt Jacob 13509e11e5beSMatt Jacob for (seg = 0; seg < seglim; seg++) { 135165b024e1SMatt Jacob cto->rsp.m0.ct_dataseg[seg].ds_base = 135265b024e1SMatt Jacob dm_segs->ds_addr; 135365b024e1SMatt Jacob cto->rsp.m0.ct_dataseg[seg].ds_count = 135465b024e1SMatt Jacob dm_segs->ds_len; 13559e11e5beSMatt Jacob cto->rsp.m0.ct_xfrlen += dm_segs->ds_len; 135665b024e1SMatt Jacob totxfr += dm_segs->ds_len; 13579e11e5beSMatt Jacob dm_segs++; 13589e11e5beSMatt Jacob } 13599e11e5beSMatt Jacob cto->ct_seg_count = seg; 13609e11e5beSMatt Jacob } else { 136165b024e1SMatt Jacob /* 136265b024e1SMatt Jacob * This case should only happen when we're sending a 136365b024e1SMatt Jacob * synthesized MODE1 final status with sense data. 136465b024e1SMatt Jacob */ 136565b024e1SMatt Jacob if (send_sense == 0) { 136665b024e1SMatt Jacob printf("%s: dma2_tgt_fc ran out of segments, " 136765b024e1SMatt Jacob "no SENSE DATA\n", mp->isp->isp_name); 136865b024e1SMatt Jacob mp->error = EINVAL; 136965b024e1SMatt Jacob return; 137065b024e1SMatt Jacob } 13719e11e5beSMatt Jacob } 13729e11e5beSMatt Jacob 13739e11e5beSMatt Jacob /* 137465b024e1SMatt Jacob * At this point, the fields ct_lun, ct_iid, ct_rxid, 137565b024e1SMatt Jacob * ct_timeout have been carried over unchanged from what 137665b024e1SMatt Jacob * our caller had set. 137765b024e1SMatt Jacob * 137865b024e1SMatt Jacob * The field ct_reloff is either what the caller set, or 137965b024e1SMatt Jacob * what we've added to below. 138065b024e1SMatt Jacob * 138165b024e1SMatt Jacob * The dataseg fields and the seg_count fields we just got 138265b024e1SMatt Jacob * through setting. The data direction we've preserved all 138365b024e1SMatt Jacob * along and only clear it if we're sending a MODE1 status 138465b024e1SMatt Jacob * as the last CTIO. 138565b024e1SMatt Jacob * 138665b024e1SMatt Jacob */ 138765b024e1SMatt Jacob 138865b024e1SMatt Jacob if (nctios == 0) { 138965b024e1SMatt Jacob 139065b024e1SMatt Jacob /* 139165b024e1SMatt Jacob * We're the last in a sequence of CTIO2s, so mark this 139265b024e1SMatt Jacob * CTIO2 and save the handle to the CCB such that when 139365b024e1SMatt Jacob * this CTIO2 completes we can free dma resources and 13949e11e5beSMatt Jacob * do whatever else we need to do to finish the rest 13959e11e5beSMatt Jacob * of the command. 13969e11e5beSMatt Jacob */ 139765b024e1SMatt Jacob 13989e11e5beSMatt Jacob cto->ct_reserved = handle; 139965b024e1SMatt Jacob cto->ct_header.rqs_seqno = 1; 140065b024e1SMatt Jacob 140165b024e1SMatt Jacob if (send_status) { 140265b024e1SMatt Jacob if (send_sense) { 140365b024e1SMatt Jacob bcopy(sense, cto->rsp.m1.ct_resp, 140465b024e1SMatt Jacob QLTM_SENSELEN); 140565b024e1SMatt Jacob cto->rsp.m1.ct_senselen = 140665b024e1SMatt Jacob QLTM_SENSELEN; 140765b024e1SMatt Jacob scsi_status |= CT2_SNSLEN_VALID; 140865b024e1SMatt Jacob cto->rsp.m1.ct_scsi_status = 140965b024e1SMatt Jacob scsi_status; 141065b024e1SMatt Jacob cto->ct_flags &= CT2_FLAG_MMASK; 141165b024e1SMatt Jacob cto->ct_flags |= CT2_FLAG_MODE1 | 141265b024e1SMatt Jacob CT2_NO_DATA| CT2_SENDSTATUS; 141365b024e1SMatt Jacob } else { 141465b024e1SMatt Jacob cto->rsp.m0.ct_scsi_status = 141565b024e1SMatt Jacob scsi_status; 141665b024e1SMatt Jacob cto->ct_flags |= CT2_SENDSTATUS; 141765b024e1SMatt Jacob } 141805fbcbb0SMatt Jacob /* 141905fbcbb0SMatt Jacob * Get 'real' residual and set flags based 142005fbcbb0SMatt Jacob * on it. 142105fbcbb0SMatt Jacob */ 142205fbcbb0SMatt Jacob cto->ct_resid = datalen - totxfr; 142305fbcbb0SMatt Jacob if (cto->ct_resid > 0) 142405fbcbb0SMatt Jacob cto->ct_flags |= CT2_DATA_UNDER; 142505fbcbb0SMatt Jacob else if (cto->ct_resid < 0) 142605fbcbb0SMatt Jacob cto->ct_flags |= CT2_DATA_OVER; 142765b024e1SMatt Jacob } 14289e11e5beSMatt Jacob ISP_TDQE(mp->isp, "last dma2_tgt_fc", *mp->iptrp, cto); 142942426921SMatt Jacob if (isp_tdebug) { 143042426921SMatt Jacob printf("%s:CTIO2 RX_ID 0x%x lun %d->iid%d flgs" 143105fbcbb0SMatt Jacob "0x%x sts 0x%x ssts 0x%x res %d\n", 143265b024e1SMatt Jacob mp->isp->isp_name, cto->ct_rxid, 143365b024e1SMatt Jacob csio->ccb_h.target_lun, (int) cto->ct_iid, 143442426921SMatt Jacob cto->ct_flags, cto->ct_status, 143565b024e1SMatt Jacob cto->rsp.m1.ct_scsi_status, cto->ct_resid); 143642426921SMatt Jacob } 143765b024e1SMatt Jacob ISP_SWIZ_CTIO2(isp, cto, cto); 14389e11e5beSMatt Jacob } else { 14399e11e5beSMatt Jacob ct2_entry_t *octo = cto; 144065b024e1SMatt Jacob 144165b024e1SMatt Jacob /* 144265b024e1SMatt Jacob * Make sure handle fields are clean 144365b024e1SMatt Jacob */ 14449e11e5beSMatt Jacob cto->ct_reserved = 0; 14459e11e5beSMatt Jacob cto->ct_header.rqs_seqno = 0; 144665b024e1SMatt Jacob 14479e11e5beSMatt Jacob ISP_TDQE(mp->isp, "dma2_tgt_fc", *mp->iptrp, cto); 144842426921SMatt Jacob if (isp_tdebug) { 144942426921SMatt Jacob printf("%s:CTIO2 RX_ID 0x%x lun %d->iid%d flgs" 145065b024e1SMatt Jacob "0x%x\n", mp->isp->isp_name, cto->ct_rxid, 145165b024e1SMatt Jacob csio->ccb_h.target_lun, (int) cto->ct_iid, 145265b024e1SMatt Jacob cto->ct_flags); 145342426921SMatt Jacob } 145465b024e1SMatt Jacob /* 145565b024e1SMatt Jacob * Get a new CTIO2 145665b024e1SMatt Jacob */ 14579e11e5beSMatt Jacob cto = (ct2_entry_t *) 14589e11e5beSMatt Jacob ISP_QUEUE_ENTRY(mp->isp->isp_rquest, *mp->iptrp); 14599e11e5beSMatt Jacob *mp->iptrp = 14609e11e5beSMatt Jacob ISP_NXT_QENTRY(*mp->iptrp, RQUEST_QUEUE_LEN); 14619e11e5beSMatt Jacob if (*mp->iptrp == mp->optr) { 14629e11e5beSMatt Jacob printf("%s: Queue Overflow in dma2_tgt_fc\n", 14639e11e5beSMatt Jacob mp->isp->isp_name); 14649e11e5beSMatt Jacob mp->error = MUSHERR_NOQENTRIES; 14659e11e5beSMatt Jacob return; 14669e11e5beSMatt Jacob } 146765b024e1SMatt Jacob 14689e11e5beSMatt Jacob /* 146965b024e1SMatt Jacob * Fill in the new CTIO2 with info from the old one. 14709e11e5beSMatt Jacob */ 14719e11e5beSMatt Jacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2; 14729e11e5beSMatt Jacob cto->ct_header.rqs_entry_count = 1; 14739e11e5beSMatt Jacob cto->ct_header.rqs_flags = 0; 147465b024e1SMatt Jacob /* ct_header.rqs_seqno && ct_reserved done later */ 14759e11e5beSMatt Jacob cto->ct_lun = octo->ct_lun; 14769e11e5beSMatt Jacob cto->ct_iid = octo->ct_iid; 14779e11e5beSMatt Jacob cto->ct_rxid = octo->ct_rxid; 147865b024e1SMatt Jacob cto->ct_flags = octo->ct_flags; 14799e11e5beSMatt Jacob cto->ct_status = 0; 14809e11e5beSMatt Jacob cto->ct_resid = 0; 14819e11e5beSMatt Jacob cto->ct_timeout = octo->ct_timeout; 14829e11e5beSMatt Jacob cto->ct_seg_count = 0; 148365b024e1SMatt Jacob /* 148465b024e1SMatt Jacob * Adjust the new relative offset by the amount which 148565b024e1SMatt Jacob * is recorded in the data segment of the old CTIO2 we 148665b024e1SMatt Jacob * just finished filling out. 148765b024e1SMatt Jacob */ 148865b024e1SMatt Jacob cto->ct_reloff += octo->rsp.m0.ct_xfrlen; 14899e11e5beSMatt Jacob bzero(&cto->rsp, sizeof (cto->rsp)); 149065b024e1SMatt Jacob ISP_SWIZ_CTIO2(isp, cto, cto); 14919e11e5beSMatt Jacob } 14929e11e5beSMatt Jacob } 14939e11e5beSMatt Jacob } 14949e11e5beSMatt Jacob #endif 14959e11e5beSMatt Jacob 14969e11e5beSMatt Jacob static void dma2 __P((void *, bus_dma_segment_t *, int, int)); 14979e11e5beSMatt Jacob 14989e11e5beSMatt Jacob static void 14999e11e5beSMatt Jacob dma2(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 15009e11e5beSMatt Jacob { 15019e11e5beSMatt Jacob mush_t *mp; 15029e11e5beSMatt Jacob struct ccb_scsiio *csio; 15039e11e5beSMatt Jacob struct isp_pcisoftc *pci; 15049e11e5beSMatt Jacob bus_dmamap_t *dp; 15059e11e5beSMatt Jacob bus_dma_segment_t *eseg; 15069e11e5beSMatt Jacob ispreq_t *rq; 15079e11e5beSMatt Jacob ispcontreq_t *crq; 15089e11e5beSMatt Jacob int seglim, datalen; 15099e11e5beSMatt Jacob 15109e11e5beSMatt Jacob mp = (mush_t *) arg; 15119e11e5beSMatt Jacob if (error) { 15129e11e5beSMatt Jacob mp->error = error; 15139e11e5beSMatt Jacob return; 15149e11e5beSMatt Jacob } 15159e11e5beSMatt Jacob 15169e11e5beSMatt Jacob if (nseg < 1) { 15179e11e5beSMatt Jacob printf("%s: bad segment count (%d)\n", mp->isp->isp_name, nseg); 15189e11e5beSMatt Jacob mp->error = EFAULT; 15199e11e5beSMatt Jacob return; 15209e11e5beSMatt Jacob } 15219e11e5beSMatt Jacob csio = mp->cmd_token; 15229e11e5beSMatt Jacob rq = mp->rq; 15239e11e5beSMatt Jacob pci = (struct isp_pcisoftc *)mp->isp; 1524469b6b9eSMatt Jacob dp = &pci->dmaps[isp_handle_index(rq->req_handle)]; 15259e11e5beSMatt Jacob 15269e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 15279e11e5beSMatt Jacob bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREREAD); 15289e11e5beSMatt Jacob } else { 15299e11e5beSMatt Jacob bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREWRITE); 15309e11e5beSMatt Jacob } 15319e11e5beSMatt Jacob 15329e11e5beSMatt Jacob datalen = XS_XFRLEN(csio); 15339e11e5beSMatt Jacob 15349e11e5beSMatt Jacob /* 15359e11e5beSMatt Jacob * We're passed an initial partially filled in entry that 15369e11e5beSMatt Jacob * has most fields filled in except for data transfer 15379e11e5beSMatt Jacob * related values. 15389e11e5beSMatt Jacob * 15399e11e5beSMatt Jacob * Our job is to fill in the initial request queue entry and 15409e11e5beSMatt Jacob * then to start allocating and filling in continuation entries 15419e11e5beSMatt Jacob * until we've covered the entire transfer. 15429e11e5beSMatt Jacob */ 15439e11e5beSMatt Jacob 15449e11e5beSMatt Jacob if (IS_FC(mp->isp)) { 1545d720e6d5SJustin T. Gibbs seglim = ISP_RQDSEG_T2; 1546d720e6d5SJustin T. Gibbs ((ispreqt2_t *)rq)->req_totalcnt = datalen; 15479e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 15489e11e5beSMatt Jacob ((ispreqt2_t *)rq)->req_flags |= REQFLAG_DATA_IN; 15499e11e5beSMatt Jacob } else { 15509e11e5beSMatt Jacob ((ispreqt2_t *)rq)->req_flags |= REQFLAG_DATA_OUT; 15519e11e5beSMatt Jacob } 1552d720e6d5SJustin T. Gibbs } else { 1553e142669aSMatt Jacob if (csio->cdb_len > 12) { 1554e142669aSMatt Jacob seglim = 0; 1555e142669aSMatt Jacob } else { 1556d720e6d5SJustin T. Gibbs seglim = ISP_RQDSEG; 1557e142669aSMatt Jacob } 15589e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 15599e11e5beSMatt Jacob rq->req_flags |= REQFLAG_DATA_IN; 15609e11e5beSMatt Jacob } else { 15619e11e5beSMatt Jacob rq->req_flags |= REQFLAG_DATA_OUT; 15629e11e5beSMatt Jacob } 1563d720e6d5SJustin T. Gibbs } 1564d720e6d5SJustin T. Gibbs 1565d720e6d5SJustin T. Gibbs eseg = dm_segs + nseg; 1566d720e6d5SJustin T. Gibbs 1567d720e6d5SJustin T. Gibbs while (datalen != 0 && rq->req_seg_count < seglim && dm_segs != eseg) { 15689e11e5beSMatt Jacob if (IS_FC(mp->isp)) { 1569d720e6d5SJustin T. Gibbs ispreqt2_t *rq2 = (ispreqt2_t *)rq; 1570d720e6d5SJustin T. Gibbs rq2->req_dataseg[rq2->req_seg_count].ds_base = 1571d720e6d5SJustin T. Gibbs dm_segs->ds_addr; 1572d720e6d5SJustin T. Gibbs rq2->req_dataseg[rq2->req_seg_count].ds_count = 1573d720e6d5SJustin T. Gibbs dm_segs->ds_len; 1574d720e6d5SJustin T. Gibbs } else { 1575d720e6d5SJustin T. Gibbs rq->req_dataseg[rq->req_seg_count].ds_base = 1576d720e6d5SJustin T. Gibbs dm_segs->ds_addr; 1577d720e6d5SJustin T. Gibbs rq->req_dataseg[rq->req_seg_count].ds_count = 1578d720e6d5SJustin T. Gibbs dm_segs->ds_len; 1579d720e6d5SJustin T. Gibbs } 1580d720e6d5SJustin T. Gibbs datalen -= dm_segs->ds_len; 1581d720e6d5SJustin T. Gibbs #if 0 15829e11e5beSMatt Jacob if (IS_FC(mp->isp)) { 1583d720e6d5SJustin T. Gibbs ispreqt2_t *rq2 = (ispreqt2_t *)rq; 1584d720e6d5SJustin T. Gibbs printf("%s: seg0[%d] cnt 0x%x paddr 0x%08x\n", 15859e11e5beSMatt Jacob mp->isp->isp_name, rq->req_seg_count, 1586d720e6d5SJustin T. Gibbs rq2->req_dataseg[rq2->req_seg_count].ds_count, 1587d720e6d5SJustin T. Gibbs rq2->req_dataseg[rq2->req_seg_count].ds_base); 1588d720e6d5SJustin T. Gibbs } else { 1589d720e6d5SJustin T. Gibbs printf("%s: seg0[%d] cnt 0x%x paddr 0x%08x\n", 15909e11e5beSMatt Jacob mp->isp->isp_name, rq->req_seg_count, 1591d720e6d5SJustin T. Gibbs rq->req_dataseg[rq->req_seg_count].ds_count, 1592d720e6d5SJustin T. Gibbs rq->req_dataseg[rq->req_seg_count].ds_base); 1593d720e6d5SJustin T. Gibbs } 1594d720e6d5SJustin T. Gibbs #endif 1595d720e6d5SJustin T. Gibbs rq->req_seg_count++; 1596d720e6d5SJustin T. Gibbs dm_segs++; 1597d720e6d5SJustin T. Gibbs } 1598d720e6d5SJustin T. Gibbs 1599d720e6d5SJustin T. Gibbs while (datalen > 0 && dm_segs != eseg) { 16009e11e5beSMatt Jacob crq = (ispcontreq_t *) 16019e11e5beSMatt Jacob ISP_QUEUE_ENTRY(mp->isp->isp_rquest, *mp->iptrp); 16029e11e5beSMatt Jacob *mp->iptrp = ISP_NXT_QENTRY(*mp->iptrp, RQUEST_QUEUE_LEN); 16039e11e5beSMatt Jacob if (*mp->iptrp == mp->optr) { 16044873663cSMatt Jacob #if 0 16059e11e5beSMatt Jacob printf("%s: Request Queue Overflow++\n", 16069e11e5beSMatt Jacob mp->isp->isp_name); 16074873663cSMatt Jacob #endif 16084873663cSMatt Jacob mp->error = MUSHERR_NOQENTRIES; 1609d720e6d5SJustin T. Gibbs return; 1610d720e6d5SJustin T. Gibbs } 1611d720e6d5SJustin T. Gibbs rq->req_header.rqs_entry_count++; 1612d720e6d5SJustin T. Gibbs bzero((void *)crq, sizeof (*crq)); 1613d720e6d5SJustin T. Gibbs crq->req_header.rqs_entry_count = 1; 1614d720e6d5SJustin T. Gibbs crq->req_header.rqs_entry_type = RQSTYPE_DATASEG; 1615d720e6d5SJustin T. Gibbs 1616d720e6d5SJustin T. Gibbs seglim = 0; 1617d720e6d5SJustin T. Gibbs while (datalen > 0 && seglim < ISP_CDSEG && dm_segs != eseg) { 1618d720e6d5SJustin T. Gibbs crq->req_dataseg[seglim].ds_base = 1619d720e6d5SJustin T. Gibbs dm_segs->ds_addr; 1620d720e6d5SJustin T. Gibbs crq->req_dataseg[seglim].ds_count = 1621d720e6d5SJustin T. Gibbs dm_segs->ds_len; 1622d720e6d5SJustin T. Gibbs #if 0 1623d720e6d5SJustin T. Gibbs printf("%s: seg%d[%d] cnt 0x%x paddr 0x%08x\n", 16249e11e5beSMatt Jacob mp->isp->isp_name, rq->req_header.rqs_entry_count-1, 1625d720e6d5SJustin T. Gibbs seglim, crq->req_dataseg[seglim].ds_count, 1626d720e6d5SJustin T. Gibbs crq->req_dataseg[seglim].ds_base); 1627d720e6d5SJustin T. Gibbs #endif 1628d720e6d5SJustin T. Gibbs rq->req_seg_count++; 1629d720e6d5SJustin T. Gibbs dm_segs++; 1630d720e6d5SJustin T. Gibbs seglim++; 1631d720e6d5SJustin T. Gibbs datalen -= dm_segs->ds_len; 1632d720e6d5SJustin T. Gibbs } 1633d720e6d5SJustin T. Gibbs } 1634d720e6d5SJustin T. Gibbs } 1635d720e6d5SJustin T. Gibbs 1636d720e6d5SJustin T. Gibbs static int 16379e11e5beSMatt Jacob isp_pci_dmasetup(struct ispsoftc *isp, struct ccb_scsiio *csio, ispreq_t *rq, 16389637d68cSMatt Jacob u_int16_t *iptrp, u_int16_t optr) 1639d720e6d5SJustin T. Gibbs { 1640d720e6d5SJustin T. Gibbs struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp; 16410a5f7e8bSMatt Jacob bus_dmamap_t *dp = NULL; 1642d720e6d5SJustin T. Gibbs mush_t mush, *mp; 16439e11e5beSMatt Jacob void (*eptr) __P((void *, bus_dma_segment_t *, int, int)); 1644d720e6d5SJustin T. Gibbs 164565b024e1SMatt Jacob #ifdef ISP_TARGET_MODE 164665b024e1SMatt Jacob if (csio->ccb_h.func_code == XPT_CONT_TARGET_IO) { 164765b024e1SMatt Jacob if (IS_FC(isp)) { 164805fbcbb0SMatt Jacob eptr = tdma_mkfc; 164965b024e1SMatt Jacob } else { 165005fbcbb0SMatt Jacob eptr = tdma_mk; 165165b024e1SMatt Jacob } 165205fbcbb0SMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE || 165305fbcbb0SMatt Jacob (csio->dxfer_len == 0)) { 165465b024e1SMatt Jacob rq->req_seg_count = 1; 165565b024e1SMatt Jacob mp = &mush; 165665b024e1SMatt Jacob mp->isp = isp; 165765b024e1SMatt Jacob mp->cmd_token = csio; 165865b024e1SMatt Jacob mp->rq = rq; 165965b024e1SMatt Jacob mp->iptrp = iptrp; 166065b024e1SMatt Jacob mp->optr = optr; 166165b024e1SMatt Jacob mp->error = 0; 166265b024e1SMatt Jacob (*eptr)(mp, NULL, 0, 0); 166365b024e1SMatt Jacob goto exit; 166465b024e1SMatt Jacob } 166565b024e1SMatt Jacob } else 166665b024e1SMatt Jacob #endif 166765b024e1SMatt Jacob eptr = dma2; 166865b024e1SMatt Jacob 166942426921SMatt Jacob /* 167042426921SMatt Jacob * NB: if we need to do request queue entry swizzling, 167142426921SMatt Jacob * NB: this is where it would need to be done for cmds 167242426921SMatt Jacob * NB: that move no data. For commands that move data, 167342426921SMatt Jacob * NB: swizzling would take place in those functions. 167442426921SMatt Jacob */ 167505fbcbb0SMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE || 167605fbcbb0SMatt Jacob (csio->dxfer_len == 0)) { 167742426921SMatt Jacob rq->req_seg_count = 1; 167842426921SMatt Jacob return (CMD_QUEUED); 167942426921SMatt Jacob } 168042426921SMatt Jacob 1681d720e6d5SJustin T. Gibbs /* 1682d720e6d5SJustin T. Gibbs * Do a virtual grapevine step to collect info for 16834873663cSMatt Jacob * the callback dma allocation that we have to use... 1684d720e6d5SJustin T. Gibbs */ 1685d720e6d5SJustin T. Gibbs mp = &mush; 1686d720e6d5SJustin T. Gibbs mp->isp = isp; 16879e11e5beSMatt Jacob mp->cmd_token = csio; 1688d720e6d5SJustin T. Gibbs mp->rq = rq; 1689d720e6d5SJustin T. Gibbs mp->iptrp = iptrp; 1690d720e6d5SJustin T. Gibbs mp->optr = optr; 1691d720e6d5SJustin T. Gibbs mp->error = 0; 1692d720e6d5SJustin T. Gibbs 16939e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_SCATTER_VALID) == 0) { 16949e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DATA_PHYS) == 0) { 16954873663cSMatt Jacob int error, s; 1696469b6b9eSMatt Jacob dp = &pci->dmaps[isp_handle_index(rq->req_handle)]; 1697d720e6d5SJustin T. Gibbs s = splsoftvm(); 1698d720e6d5SJustin T. Gibbs error = bus_dmamap_load(pci->parent_dmat, *dp, 16999e11e5beSMatt Jacob csio->data_ptr, csio->dxfer_len, eptr, mp, 0); 1700d720e6d5SJustin T. Gibbs if (error == EINPROGRESS) { 1701d720e6d5SJustin T. Gibbs bus_dmamap_unload(pci->parent_dmat, *dp); 1702d720e6d5SJustin T. Gibbs mp->error = EINVAL; 17034873663cSMatt Jacob printf("%s: deferred dma allocation not " 17044873663cSMatt Jacob "supported\n", isp->isp_name); 1705d720e6d5SJustin T. Gibbs } else if (error && mp->error == 0) { 17060a5f7e8bSMatt Jacob #ifdef DIAGNOSTIC 17070a5f7e8bSMatt Jacob printf("%s: error %d in dma mapping code\n", 17080a5f7e8bSMatt Jacob isp->isp_name, error); 17090a5f7e8bSMatt Jacob #endif 1710d720e6d5SJustin T. Gibbs mp->error = error; 1711d720e6d5SJustin T. Gibbs } 17124873663cSMatt Jacob splx(s); 1713d720e6d5SJustin T. Gibbs } else { 1714d720e6d5SJustin T. Gibbs /* Pointer to physical buffer */ 1715d720e6d5SJustin T. Gibbs struct bus_dma_segment seg; 1716d720e6d5SJustin T. Gibbs seg.ds_addr = (bus_addr_t)csio->data_ptr; 1717d720e6d5SJustin T. Gibbs seg.ds_len = csio->dxfer_len; 17189e11e5beSMatt Jacob (*eptr)(mp, &seg, 1, 0); 1719d720e6d5SJustin T. Gibbs } 1720d720e6d5SJustin T. Gibbs } else { 1721d720e6d5SJustin T. Gibbs struct bus_dma_segment *segs; 1722d720e6d5SJustin T. Gibbs 17239e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DATA_PHYS) != 0) { 1724d720e6d5SJustin T. Gibbs printf("%s: Physical segment pointers unsupported", 1725d720e6d5SJustin T. Gibbs isp->isp_name); 1726d720e6d5SJustin T. Gibbs mp->error = EINVAL; 17279e11e5beSMatt Jacob } else if ((csio->ccb_h.flags & CAM_SG_LIST_PHYS) == 0) { 1728d720e6d5SJustin T. Gibbs printf("%s: Virtual segment addresses unsupported", 1729d720e6d5SJustin T. Gibbs isp->isp_name); 1730d720e6d5SJustin T. Gibbs mp->error = EINVAL; 1731d720e6d5SJustin T. Gibbs } else { 1732d720e6d5SJustin T. Gibbs /* Just use the segments provided */ 1733d720e6d5SJustin T. Gibbs segs = (struct bus_dma_segment *) csio->data_ptr; 17349e11e5beSMatt Jacob (*eptr)(mp, segs, csio->sglist_cnt, 0); 1735d720e6d5SJustin T. Gibbs } 1736d720e6d5SJustin T. Gibbs } 1737003a310fSMatt Jacob #ifdef ISP_TARGET_MODE 173865b024e1SMatt Jacob exit: 1739003a310fSMatt Jacob #endif 1740d720e6d5SJustin T. Gibbs if (mp->error) { 17414873663cSMatt Jacob int retval = CMD_COMPLETE; 17424873663cSMatt Jacob if (mp->error == MUSHERR_NOQENTRIES) { 17434873663cSMatt Jacob retval = CMD_EAGAIN; 17444873663cSMatt Jacob } else if (mp->error == EFBIG) { 17450a5f7e8bSMatt Jacob XS_SETERR(csio, CAM_REQ_TOO_BIG); 1746d720e6d5SJustin T. Gibbs } else if (mp->error == EINVAL) { 17470a5f7e8bSMatt Jacob XS_SETERR(csio, CAM_REQ_INVALID); 1748d720e6d5SJustin T. Gibbs } else { 17490a5f7e8bSMatt Jacob XS_SETERR(csio, CAM_UNREC_HBA_ERROR); 1750d720e6d5SJustin T. Gibbs } 17514873663cSMatt Jacob return (retval); 17524873663cSMatt Jacob } else { 17530a5f7e8bSMatt Jacob /* 17540a5f7e8bSMatt Jacob * Check to see if we weren't cancelled while sleeping on 17550a5f7e8bSMatt Jacob * getting DMA resources... 17560a5f7e8bSMatt Jacob */ 17579e11e5beSMatt Jacob if ((csio->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG) { 17580a5f7e8bSMatt Jacob if (dp) { 17590a5f7e8bSMatt Jacob bus_dmamap_unload(pci->parent_dmat, *dp); 17600a5f7e8bSMatt Jacob } 17610a5f7e8bSMatt Jacob return (CMD_COMPLETE); 17620a5f7e8bSMatt Jacob } 17634873663cSMatt Jacob return (CMD_QUEUED); 1764d720e6d5SJustin T. Gibbs } 1765d720e6d5SJustin T. Gibbs } 1766d720e6d5SJustin T. Gibbs 1767d720e6d5SJustin T. Gibbs static void 1768a95ae193SMatt Jacob isp_pci_dmateardown(struct ispsoftc *isp, ISP_SCSI_XFER_T *xs, u_int32_t handle) 1769d720e6d5SJustin T. Gibbs { 1770d720e6d5SJustin T. Gibbs struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp; 1771469b6b9eSMatt Jacob bus_dmamap_t *dp = &pci->dmaps[isp_handle_index(handle)]; 1772a95ae193SMatt Jacob if ((xs->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 1773d720e6d5SJustin T. Gibbs bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_POSTREAD); 1774d720e6d5SJustin T. Gibbs } else { 1775d720e6d5SJustin T. Gibbs bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_POSTWRITE); 1776d720e6d5SJustin T. Gibbs } 1777d720e6d5SJustin T. Gibbs bus_dmamap_unload(pci->parent_dmat, *dp); 1778d720e6d5SJustin T. Gibbs } 1779d720e6d5SJustin T. Gibbs 178065adb54cSMatt Jacob 178165adb54cSMatt Jacob static void 178217e318c6SMatt Jacob isp_pci_reset1(struct ispsoftc *isp) 178365adb54cSMatt Jacob { 178465adb54cSMatt Jacob /* Make sure the BIOS is disabled */ 178565adb54cSMatt Jacob isp_pci_wr_reg(isp, HCCR, PCI_HCCR_CMD_BIOS); 1786469b6b9eSMatt Jacob /* and enable interrupts */ 1787469b6b9eSMatt Jacob ENABLE_INTS(isp); 178865adb54cSMatt Jacob } 178965adb54cSMatt Jacob 179065adb54cSMatt Jacob static void 179117e318c6SMatt Jacob isp_pci_dumpregs(struct ispsoftc *isp) 179265adb54cSMatt Jacob { 179365adb54cSMatt Jacob struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp; 1794960f6939SMatt Jacob printf("%s: PCI Status Command/Status=%x\n", pci->pci_isp.isp_name, 1795960f6939SMatt Jacob pci_read_config(pci->pci_dev, PCIR_COMMAND, 1)); 179665adb54cSMatt Jacob } 1797