1c3aac50fSPeter Wemm /* $FreeBSD$ */ 265adb54cSMatt Jacob /* 365adb54cSMatt Jacob * PCI specific probe and attach routines for Qlogic ISP SCSI adapters. 465adb54cSMatt Jacob * FreeBSD Version. 565adb54cSMatt Jacob * 684267b9eSMatt Jacob * Copyright (c) 1997, 1998, 1999, 2000 by Matthew Jacob 765adb54cSMatt Jacob * 865adb54cSMatt Jacob * Redistribution and use in source and binary forms, with or without 965adb54cSMatt Jacob * modification, are permitted provided that the following conditions 1065adb54cSMatt Jacob * are met: 1165adb54cSMatt Jacob * 1. Redistributions of source code must retain the above copyright 1265adb54cSMatt Jacob * notice immediately at the beginning of the file, without modification, 1365adb54cSMatt Jacob * this list of conditions, and the following disclaimer. 14aa57fd6fSMatt Jacob * 2. The name of the author may not be used to endorse or promote products 15aa57fd6fSMatt Jacob * derived from this software without specific prior written permission. 1665adb54cSMatt Jacob * 1765adb54cSMatt Jacob * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1865adb54cSMatt Jacob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1965adb54cSMatt Jacob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2065adb54cSMatt Jacob * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2165adb54cSMatt Jacob * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2265adb54cSMatt Jacob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2365adb54cSMatt Jacob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2465adb54cSMatt Jacob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2565adb54cSMatt Jacob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2665adb54cSMatt Jacob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2765adb54cSMatt Jacob * SUCH DAMAGE. 2865adb54cSMatt Jacob */ 29d720e6d5SJustin T. Gibbs 30960f6939SMatt Jacob #include <sys/param.h> 31960f6939SMatt Jacob #include <sys/systm.h> 32960f6939SMatt Jacob #include <sys/kernel.h> 33960f6939SMatt Jacob #include <sys/module.h> 34960f6939SMatt Jacob #include <sys/bus.h> 3565adb54cSMatt Jacob 3665adb54cSMatt Jacob #include <pci/pcireg.h> 3765adb54cSMatt Jacob #include <pci/pcivar.h> 3865adb54cSMatt Jacob 39d720e6d5SJustin T. Gibbs #include <machine/bus_memio.h> 40d720e6d5SJustin T. Gibbs #include <machine/bus_pio.h> 41d720e6d5SJustin T. Gibbs #include <machine/bus.h> 42960f6939SMatt Jacob #include <machine/resource.h> 43960f6939SMatt Jacob #include <sys/rman.h> 44960f6939SMatt Jacob #include <sys/malloc.h> 45960f6939SMatt Jacob 46960f6939SMatt Jacob #include <dev/isp/isp_freebsd.h> 47d59bd469SMatt Jacob 4865adb54cSMatt Jacob static u_int16_t isp_pci_rd_reg __P((struct ispsoftc *, int)); 4965adb54cSMatt Jacob static void isp_pci_wr_reg __P((struct ispsoftc *, int, u_int16_t)); 50d59bd469SMatt Jacob static u_int16_t isp_pci_rd_reg_1080 __P((struct ispsoftc *, int)); 51d59bd469SMatt Jacob static void isp_pci_wr_reg_1080 __P((struct ispsoftc *, int, u_int16_t)); 5265adb54cSMatt Jacob static int isp_pci_mbxdma __P((struct ispsoftc *)); 53d02373f1SMatt Jacob static int isp_pci_dmasetup __P((struct ispsoftc *, XS_T *, 549637d68cSMatt Jacob ispreq_t *, u_int16_t *, u_int16_t)); 55d720e6d5SJustin T. Gibbs static void 56d02373f1SMatt Jacob isp_pci_dmateardown __P((struct ispsoftc *, XS_T *, u_int32_t)); 5765adb54cSMatt Jacob 5865adb54cSMatt Jacob static void isp_pci_reset1 __P((struct ispsoftc *)); 59d02373f1SMatt Jacob static void isp_pci_dumpregs __P((struct ispsoftc *, const char *)); 6065adb54cSMatt Jacob 61fed92c47SMatt Jacob #ifndef ISP_CODE_ORG 62fed92c47SMatt Jacob #define ISP_CODE_ORG 0x1000 63fed92c47SMatt Jacob #endif 64fed92c47SMatt Jacob 6565adb54cSMatt Jacob static struct ispmdvec mdvec = { 6665adb54cSMatt Jacob isp_pci_rd_reg, 6765adb54cSMatt Jacob isp_pci_wr_reg, 6865adb54cSMatt Jacob isp_pci_mbxdma, 6965adb54cSMatt Jacob isp_pci_dmasetup, 70d720e6d5SJustin T. Gibbs isp_pci_dmateardown, 7165adb54cSMatt Jacob NULL, 7265adb54cSMatt Jacob isp_pci_reset1, 7365adb54cSMatt Jacob isp_pci_dumpregs, 7456aef503SMatt Jacob NULL, 75d02373f1SMatt Jacob BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64 7665adb54cSMatt Jacob }; 7765adb54cSMatt Jacob 78d59bd469SMatt Jacob static struct ispmdvec mdvec_1080 = { 79d59bd469SMatt Jacob isp_pci_rd_reg_1080, 80d59bd469SMatt Jacob isp_pci_wr_reg_1080, 81d59bd469SMatt Jacob isp_pci_mbxdma, 82d59bd469SMatt Jacob isp_pci_dmasetup, 83d59bd469SMatt Jacob isp_pci_dmateardown, 84d59bd469SMatt Jacob NULL, 85d59bd469SMatt Jacob isp_pci_reset1, 86d59bd469SMatt Jacob isp_pci_dumpregs, 8756aef503SMatt Jacob NULL, 88d02373f1SMatt Jacob BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64 89d59bd469SMatt Jacob }; 90d59bd469SMatt Jacob 91960f6939SMatt Jacob static struct ispmdvec mdvec_12160 = { 92960f6939SMatt Jacob isp_pci_rd_reg_1080, 93960f6939SMatt Jacob isp_pci_wr_reg_1080, 94960f6939SMatt Jacob isp_pci_mbxdma, 95960f6939SMatt Jacob isp_pci_dmasetup, 96960f6939SMatt Jacob isp_pci_dmateardown, 97960f6939SMatt Jacob NULL, 98960f6939SMatt Jacob isp_pci_reset1, 99960f6939SMatt Jacob isp_pci_dumpregs, 10056aef503SMatt Jacob NULL, 101d02373f1SMatt Jacob BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64 102960f6939SMatt Jacob }; 103960f6939SMatt Jacob 10465adb54cSMatt Jacob static struct ispmdvec mdvec_2100 = { 10565adb54cSMatt Jacob isp_pci_rd_reg, 10665adb54cSMatt Jacob isp_pci_wr_reg, 10765adb54cSMatt Jacob isp_pci_mbxdma, 10865adb54cSMatt Jacob isp_pci_dmasetup, 109d720e6d5SJustin T. Gibbs isp_pci_dmateardown, 11065adb54cSMatt Jacob NULL, 11165adb54cSMatt Jacob isp_pci_reset1, 112d02373f1SMatt Jacob isp_pci_dumpregs 11365adb54cSMatt Jacob }; 114222bb542SMatt Jacob 115222bb542SMatt Jacob static struct ispmdvec mdvec_2200 = { 116222bb542SMatt Jacob isp_pci_rd_reg, 117222bb542SMatt Jacob isp_pci_wr_reg, 118222bb542SMatt Jacob isp_pci_mbxdma, 119222bb542SMatt Jacob isp_pci_dmasetup, 120222bb542SMatt Jacob isp_pci_dmateardown, 121222bb542SMatt Jacob NULL, 122222bb542SMatt Jacob isp_pci_reset1, 123d02373f1SMatt Jacob isp_pci_dumpregs 124222bb542SMatt Jacob }; 125d951bbcaSMatt Jacob 12665adb54cSMatt Jacob #ifndef PCIM_CMD_INVEN 12765adb54cSMatt Jacob #define PCIM_CMD_INVEN 0x10 12865adb54cSMatt Jacob #endif 12965adb54cSMatt Jacob #ifndef PCIM_CMD_BUSMASTEREN 13065adb54cSMatt Jacob #define PCIM_CMD_BUSMASTEREN 0x0004 13165adb54cSMatt Jacob #endif 132d951bbcaSMatt Jacob #ifndef PCIM_CMD_PERRESPEN 133d951bbcaSMatt Jacob #define PCIM_CMD_PERRESPEN 0x0040 134d951bbcaSMatt Jacob #endif 135d951bbcaSMatt Jacob #ifndef PCIM_CMD_SEREN 136d951bbcaSMatt Jacob #define PCIM_CMD_SEREN 0x0100 137d951bbcaSMatt Jacob #endif 138d951bbcaSMatt Jacob 139d951bbcaSMatt Jacob #ifndef PCIR_COMMAND 140d951bbcaSMatt Jacob #define PCIR_COMMAND 0x04 141d951bbcaSMatt Jacob #endif 142d951bbcaSMatt Jacob 143d951bbcaSMatt Jacob #ifndef PCIR_CACHELNSZ 144d951bbcaSMatt Jacob #define PCIR_CACHELNSZ 0x0c 145d951bbcaSMatt Jacob #endif 146d951bbcaSMatt Jacob 147d951bbcaSMatt Jacob #ifndef PCIR_LATTIMER 148d951bbcaSMatt Jacob #define PCIR_LATTIMER 0x0d 149d951bbcaSMatt Jacob #endif 150d951bbcaSMatt Jacob 151ab6d0040SMatt Jacob #ifndef PCIR_ROMADDR 152ab6d0040SMatt Jacob #define PCIR_ROMADDR 0x30 153ab6d0040SMatt Jacob #endif 154ab6d0040SMatt Jacob 15565adb54cSMatt Jacob #ifndef PCI_VENDOR_QLOGIC 15665adb54cSMatt Jacob #define PCI_VENDOR_QLOGIC 0x1077 15765adb54cSMatt Jacob #endif 15865adb54cSMatt Jacob 15965adb54cSMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP1020 16065adb54cSMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP1020 0x1020 16165adb54cSMatt Jacob #endif 16265adb54cSMatt Jacob 163d59bd469SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP1080 164d59bd469SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP1080 0x1080 165d59bd469SMatt Jacob #endif 166d59bd469SMatt Jacob 167960f6939SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP12160 168960f6939SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP12160 0x1216 169960f6939SMatt Jacob #endif 170960f6939SMatt Jacob 171d59bd469SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP1240 172d59bd469SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP1240 0x1240 173d59bd469SMatt Jacob #endif 17465adb54cSMatt Jacob 17522e1dc85SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP1280 17622e1dc85SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP1280 0x1280 17722e1dc85SMatt Jacob #endif 17822e1dc85SMatt Jacob 17965adb54cSMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP2100 18065adb54cSMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP2100 0x2100 18165adb54cSMatt Jacob #endif 18265adb54cSMatt Jacob 183222bb542SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP2200 184222bb542SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP2200 0x2200 185222bb542SMatt Jacob #endif 186222bb542SMatt Jacob 18756aef503SMatt Jacob #define PCI_QLOGIC_ISP1020 \ 18856aef503SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP1020 << 16) | PCI_VENDOR_QLOGIC) 189d59bd469SMatt Jacob 190d59bd469SMatt Jacob #define PCI_QLOGIC_ISP1080 \ 191d59bd469SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP1080 << 16) | PCI_VENDOR_QLOGIC) 192d59bd469SMatt Jacob 193960f6939SMatt Jacob #define PCI_QLOGIC_ISP12160 \ 194960f6939SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP12160 << 16) | PCI_VENDOR_QLOGIC) 195960f6939SMatt Jacob 196d59bd469SMatt Jacob #define PCI_QLOGIC_ISP1240 \ 197d59bd469SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP1240 << 16) | PCI_VENDOR_QLOGIC) 198d59bd469SMatt Jacob 19922e1dc85SMatt Jacob #define PCI_QLOGIC_ISP1280 \ 20022e1dc85SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP1280 << 16) | PCI_VENDOR_QLOGIC) 20122e1dc85SMatt Jacob 20265adb54cSMatt Jacob #define PCI_QLOGIC_ISP2100 \ 20365adb54cSMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP2100 << 16) | PCI_VENDOR_QLOGIC) 20465adb54cSMatt Jacob 205222bb542SMatt Jacob #define PCI_QLOGIC_ISP2200 \ 206222bb542SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP2200 << 16) | PCI_VENDOR_QLOGIC) 207222bb542SMatt Jacob 208e11a1ee8SMatt Jacob /* 209e11a1ee8SMatt Jacob * Odd case for some AMI raid cards... We need to *not* attach to this. 210e11a1ee8SMatt Jacob */ 211e11a1ee8SMatt Jacob #define AMI_RAID_SUBVENDOR_ID 0x101e 212e11a1ee8SMatt Jacob 21365adb54cSMatt Jacob #define IO_MAP_REG 0x10 21465adb54cSMatt Jacob #define MEM_MAP_REG 0x14 21565adb54cSMatt Jacob 216d951bbcaSMatt Jacob #define PCI_DFLT_LTNCY 0x40 217d951bbcaSMatt Jacob #define PCI_DFLT_LNSZ 0x10 21865adb54cSMatt Jacob 219960f6939SMatt Jacob static int isp_pci_probe (device_t); 220960f6939SMatt Jacob static int isp_pci_attach (device_t); 22165adb54cSMatt Jacob 22265adb54cSMatt Jacob struct isp_pcisoftc { 22365adb54cSMatt Jacob struct ispsoftc pci_isp; 224960f6939SMatt Jacob device_t pci_dev; 225960f6939SMatt Jacob struct resource * pci_reg; 22665adb54cSMatt Jacob bus_space_tag_t pci_st; 22765adb54cSMatt Jacob bus_space_handle_t pci_sh; 228960f6939SMatt Jacob void * ih; 229d59bd469SMatt Jacob int16_t pci_poff[_NREG_BLKS]; 230d720e6d5SJustin T. Gibbs bus_dma_tag_t parent_dmat; 231d720e6d5SJustin T. Gibbs bus_dma_tag_t cntrol_dmat; 232d720e6d5SJustin T. Gibbs bus_dmamap_t cntrol_dmap; 233a95ae193SMatt Jacob bus_dmamap_t *dmaps; 23465adb54cSMatt Jacob }; 23556aef503SMatt Jacob ispfwfunc *isp_get_firmware_p = NULL; 23665adb54cSMatt Jacob 237960f6939SMatt Jacob static device_method_t isp_pci_methods[] = { 238960f6939SMatt Jacob /* Device interface */ 239960f6939SMatt Jacob DEVMETHOD(device_probe, isp_pci_probe), 240960f6939SMatt Jacob DEVMETHOD(device_attach, isp_pci_attach), 241960f6939SMatt Jacob { 0, 0 } 24265adb54cSMatt Jacob }; 243f09b1922SMatt Jacob static void isp_pci_intr __P((void *)); 24465adb54cSMatt Jacob 245960f6939SMatt Jacob static driver_t isp_pci_driver = { 246960f6939SMatt Jacob "isp", isp_pci_methods, sizeof (struct isp_pcisoftc) 247960f6939SMatt Jacob }; 248960f6939SMatt Jacob static devclass_t isp_devclass; 249960f6939SMatt Jacob DRIVER_MODULE(isp, pci, isp_pci_driver, isp_devclass, 0, 0); 25056aef503SMatt Jacob MODULE_VERSION(isp, 1); 25165adb54cSMatt Jacob 252960f6939SMatt Jacob static int 253960f6939SMatt Jacob isp_pci_probe(device_t dev) 25465adb54cSMatt Jacob { 255960f6939SMatt Jacob switch ((pci_get_device(dev) << 16) | (pci_get_vendor(dev))) { 25656aef503SMatt Jacob case PCI_QLOGIC_ISP1020: 257960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 1020/1040 PCI SCSI Adapter"); 25865adb54cSMatt Jacob break; 259d59bd469SMatt Jacob case PCI_QLOGIC_ISP1080: 260960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 1080 PCI SCSI Adapter"); 261c6608df3SMatt Jacob break; 262c6608df3SMatt Jacob case PCI_QLOGIC_ISP1240: 263960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 1240 PCI SCSI Adapter"); 264d59bd469SMatt Jacob break; 26522e1dc85SMatt Jacob case PCI_QLOGIC_ISP1280: 266960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 1280 PCI SCSI Adapter"); 267960f6939SMatt Jacob break; 268960f6939SMatt Jacob case PCI_QLOGIC_ISP12160: 269e11a1ee8SMatt Jacob if (pci_get_subvendor(dev) == AMI_RAID_SUBVENDOR_ID) { 270e11a1ee8SMatt Jacob return (ENXIO); 271e11a1ee8SMatt Jacob } 272960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 12160 PCI SCSI Adapter"); 27322e1dc85SMatt Jacob break; 27465adb54cSMatt Jacob case PCI_QLOGIC_ISP2100: 275960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 2100 PCI FC-AL Adapter"); 27665adb54cSMatt Jacob break; 2775542fe4bSMatt Jacob case PCI_QLOGIC_ISP2200: 278960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 2200 PCI FC-AL Adapter"); 2795542fe4bSMatt Jacob break; 28065adb54cSMatt Jacob default: 281960f6939SMatt Jacob return (ENXIO); 28265adb54cSMatt Jacob } 283d02373f1SMatt Jacob if (device_get_unit(dev) == 0 && bootverbose) { 284d02373f1SMatt Jacob printf("Qlogic ISP Driver, FreeBSD Version %d.%d, " 285a95ae193SMatt Jacob "Core Version %d.%d\n", 286d720e6d5SJustin T. Gibbs ISP_PLATFORM_VERSION_MAJOR, ISP_PLATFORM_VERSION_MINOR, 287d720e6d5SJustin T. Gibbs ISP_CORE_VERSION_MAJOR, ISP_CORE_VERSION_MINOR); 28865adb54cSMatt Jacob } 28956aef503SMatt Jacob /* 29056aef503SMatt Jacob * XXXX: Here is where we might load the f/w module 29156aef503SMatt Jacob * XXXX: (or increase a reference count to it). 29256aef503SMatt Jacob */ 293960f6939SMatt Jacob return (0); 29465adb54cSMatt Jacob } 29565adb54cSMatt Jacob 296960f6939SMatt Jacob static int 297960f6939SMatt Jacob isp_pci_attach(device_t dev) 29865adb54cSMatt Jacob { 299960f6939SMatt Jacob struct resource *regs, *irq; 3003395b056SMatt Jacob int unit, bitmap, rtp, rgd, iqd, m1, m2, isp_debug; 301960f6939SMatt Jacob u_int32_t data, cmd, linesz, psize, basetype; 30265adb54cSMatt Jacob struct isp_pcisoftc *pcs; 3033395b056SMatt Jacob struct ispsoftc *isp = NULL; 304c6608df3SMatt Jacob struct ispmdvec *mdvp; 305222bb542SMatt Jacob bus_size_t lim; 3063395b056SMatt Jacob #ifdef ISP_SMPLOCK 3073395b056SMatt Jacob int locksetup = 0; 3083395b056SMatt Jacob #endif 30965adb54cSMatt Jacob 310222bb542SMatt Jacob /* 3119ba86737SMatt Jacob * Figure out if we're supposed to skip this one. 3129ba86737SMatt Jacob */ 313960f6939SMatt Jacob unit = device_get_unit(dev); 3149ba86737SMatt Jacob if (getenv_int("isp_disable", &bitmap)) { 3159ba86737SMatt Jacob if (bitmap & (1 << unit)) { 316960f6939SMatt Jacob device_printf(dev, "not configuring\n"); 317960f6939SMatt Jacob return (ENODEV); 3189ba86737SMatt Jacob } 3199ba86737SMatt Jacob } 3209ba86737SMatt Jacob 3217cc0979fSDavid Malone pcs = malloc(sizeof (struct isp_pcisoftc), M_DEVBUF, M_NOWAIT | M_ZERO); 322960f6939SMatt Jacob if (pcs == NULL) { 323960f6939SMatt Jacob device_printf(dev, "cannot allocate softc\n"); 324960f6939SMatt Jacob return (ENOMEM); 325960f6939SMatt Jacob } 326960f6939SMatt Jacob 3279ba86737SMatt Jacob /* 328222bb542SMatt Jacob * Figure out which we should try first - memory mapping or i/o mapping? 329222bb542SMatt Jacob */ 33056aef503SMatt Jacob #ifdef __alpha__ 331960f6939SMatt Jacob m1 = PCIM_CMD_MEMEN; 332960f6939SMatt Jacob m2 = PCIM_CMD_PORTEN; 333222bb542SMatt Jacob #else 334960f6939SMatt Jacob m1 = PCIM_CMD_PORTEN; 335960f6939SMatt Jacob m2 = PCIM_CMD_MEMEN; 336222bb542SMatt Jacob #endif 337222bb542SMatt Jacob bitmap = 0; 338222bb542SMatt Jacob if (getenv_int("isp_mem_map", &bitmap)) { 339960f6939SMatt Jacob if (bitmap & (1 << unit)) { 340960f6939SMatt Jacob m1 = PCIM_CMD_MEMEN; 341960f6939SMatt Jacob m2 = PCIM_CMD_PORTEN; 342960f6939SMatt Jacob } 343222bb542SMatt Jacob } 344222bb542SMatt Jacob bitmap = 0; 345222bb542SMatt Jacob if (getenv_int("isp_io_map", &bitmap)) { 346960f6939SMatt Jacob if (bitmap & (1 << unit)) { 347960f6939SMatt Jacob m1 = PCIM_CMD_PORTEN; 348960f6939SMatt Jacob m2 = PCIM_CMD_MEMEN; 349960f6939SMatt Jacob } 350222bb542SMatt Jacob } 351222bb542SMatt Jacob 352ab6d0040SMatt Jacob linesz = PCI_DFLT_LNSZ; 353960f6939SMatt Jacob irq = regs = NULL; 354960f6939SMatt Jacob rgd = rtp = iqd = 0; 355960f6939SMatt Jacob 356960f6939SMatt Jacob cmd = pci_read_config(dev, PCIR_COMMAND, 1); 357960f6939SMatt Jacob if (cmd & m1) { 358960f6939SMatt Jacob rtp = (m1 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT; 359960f6939SMatt Jacob rgd = (m1 == PCIM_CMD_MEMEN)? MEM_MAP_REG : IO_MAP_REG; 360960f6939SMatt Jacob regs = bus_alloc_resource(dev, rtp, &rgd, 0, ~0, 1, RF_ACTIVE); 36165adb54cSMatt Jacob } 362960f6939SMatt Jacob if (regs == NULL && (cmd & m2)) { 363960f6939SMatt Jacob rtp = (m2 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT; 364960f6939SMatt Jacob rgd = (m2 == PCIM_CMD_MEMEN)? MEM_MAP_REG : IO_MAP_REG; 365960f6939SMatt Jacob regs = bus_alloc_resource(dev, rtp, &rgd, 0, ~0, 1, RF_ACTIVE); 36665adb54cSMatt Jacob } 367960f6939SMatt Jacob if (regs == NULL) { 368960f6939SMatt Jacob device_printf(dev, "unable to map any ports\n"); 369960f6939SMatt Jacob goto bad; 37065adb54cSMatt Jacob } 371222bb542SMatt Jacob if (bootverbose) 372f7dddf8aSMatt Jacob device_printf(dev, "using %s space register mapping\n", 373960f6939SMatt Jacob (rgd == IO_MAP_REG)? "I/O" : "Memory"); 374960f6939SMatt Jacob pcs->pci_dev = dev; 375960f6939SMatt Jacob pcs->pci_reg = regs; 376960f6939SMatt Jacob pcs->pci_st = rman_get_bustag(regs); 377960f6939SMatt Jacob pcs->pci_sh = rman_get_bushandle(regs); 37865adb54cSMatt Jacob 379d59bd469SMatt Jacob pcs->pci_poff[BIU_BLOCK >> _BLK_REG_SHFT] = BIU_REGS_OFF; 380d59bd469SMatt Jacob pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS_OFF; 381d59bd469SMatt Jacob pcs->pci_poff[SXP_BLOCK >> _BLK_REG_SHFT] = PCI_SXP_REGS_OFF; 382d59bd469SMatt Jacob pcs->pci_poff[RISC_BLOCK >> _BLK_REG_SHFT] = PCI_RISC_REGS_OFF; 383d59bd469SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = DMA_REGS_OFF; 384c6608df3SMatt Jacob mdvp = &mdvec; 385c6608df3SMatt Jacob basetype = ISP_HA_SCSI_UNKNOWN; 386c6608df3SMatt Jacob psize = sizeof (sdparam); 387222bb542SMatt Jacob lim = BUS_SPACE_MAXSIZE_32BIT; 38856aef503SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP1020) { 389c6608df3SMatt Jacob mdvp = &mdvec; 390c6608df3SMatt Jacob basetype = ISP_HA_SCSI_UNKNOWN; 391c6608df3SMatt Jacob psize = sizeof (sdparam); 392222bb542SMatt Jacob lim = BUS_SPACE_MAXSIZE_24BIT; 393d59bd469SMatt Jacob } 394960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP1080) { 395c6608df3SMatt Jacob mdvp = &mdvec_1080; 396c6608df3SMatt Jacob basetype = ISP_HA_SCSI_1080; 397c6608df3SMatt Jacob psize = sizeof (sdparam); 398c6608df3SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 399c6608df3SMatt Jacob ISP1080_DMA_REGS_OFF; 400c6608df3SMatt Jacob } 401960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP1240) { 402c6608df3SMatt Jacob mdvp = &mdvec_1080; 40322e1dc85SMatt Jacob basetype = ISP_HA_SCSI_1240; 40422e1dc85SMatt Jacob psize = 2 * sizeof (sdparam); 40522e1dc85SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 40622e1dc85SMatt Jacob ISP1080_DMA_REGS_OFF; 40722e1dc85SMatt Jacob } 408960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP1280) { 40922e1dc85SMatt Jacob mdvp = &mdvec_1080; 41022e1dc85SMatt Jacob basetype = ISP_HA_SCSI_1280; 411c6608df3SMatt Jacob psize = 2 * sizeof (sdparam); 412d59bd469SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 413d59bd469SMatt Jacob ISP1080_DMA_REGS_OFF; 414d59bd469SMatt Jacob } 415960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP12160) { 416960f6939SMatt Jacob mdvp = &mdvec_12160; 417960f6939SMatt Jacob basetype = ISP_HA_SCSI_12160; 418960f6939SMatt Jacob psize = 2 * sizeof (sdparam); 419960f6939SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 420960f6939SMatt Jacob ISP1080_DMA_REGS_OFF; 421960f6939SMatt Jacob } 422960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP2100) { 423c6608df3SMatt Jacob mdvp = &mdvec_2100; 424c6608df3SMatt Jacob basetype = ISP_HA_FC_2100; 425c6608df3SMatt Jacob psize = sizeof (fcparam); 426d59bd469SMatt Jacob pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = 427d59bd469SMatt Jacob PCI_MBOX_REGS2100_OFF; 428960f6939SMatt Jacob if (pci_get_revid(dev) < 3) { 429ab6d0040SMatt Jacob /* 430ab6d0040SMatt Jacob * XXX: Need to get the actual revision 431ab6d0040SMatt Jacob * XXX: number of the 2100 FB. At any rate, 432ab6d0040SMatt Jacob * XXX: lower cache line size for early revision 433ab6d0040SMatt Jacob * XXX; boards. 434ab6d0040SMatt Jacob */ 435ab6d0040SMatt Jacob linesz = 1; 436ab6d0040SMatt Jacob } 43765adb54cSMatt Jacob } 438960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP2200) { 439222bb542SMatt Jacob mdvp = &mdvec_2200; 440222bb542SMatt Jacob basetype = ISP_HA_FC_2200; 441222bb542SMatt Jacob psize = sizeof (fcparam); 442222bb542SMatt Jacob pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = 443222bb542SMatt Jacob PCI_MBOX_REGS2100_OFF; 444222bb542SMatt Jacob } 445c6608df3SMatt Jacob isp = &pcs->pci_isp; 4467cc0979fSDavid Malone isp->isp_param = malloc(psize, M_DEVBUF, M_NOWAIT | M_ZERO); 447c6608df3SMatt Jacob if (isp->isp_param == NULL) { 448960f6939SMatt Jacob device_printf(dev, "cannot allocate parameter data\n"); 449960f6939SMatt Jacob goto bad; 450c6608df3SMatt Jacob } 451c6608df3SMatt Jacob isp->isp_mdvec = mdvp; 452c6608df3SMatt Jacob isp->isp_type = basetype; 453960f6939SMatt Jacob isp->isp_revision = pci_get_revid(dev); 454c6608df3SMatt Jacob (void) snprintf(isp->isp_name, sizeof (isp->isp_name), "isp%d", unit); 455c6608df3SMatt Jacob isp->isp_osinfo.unit = unit; 45665adb54cSMatt Jacob 45756aef503SMatt Jacob /* 45856aef503SMatt Jacob * Try and find firmware for this device. 45956aef503SMatt Jacob */ 46056aef503SMatt Jacob 46156aef503SMatt Jacob if (isp_get_firmware_p) { 46256aef503SMatt Jacob int device = (int) pci_get_device(dev); 46356aef503SMatt Jacob #ifdef ISP_TARGET_MODE 46456aef503SMatt Jacob (*isp_get_firmware_p)(0, 1, device, &mdvp->dv_ispfw); 46556aef503SMatt Jacob #else 46656aef503SMatt Jacob (*isp_get_firmware_p)(0, 0, device, &mdvp->dv_ispfw); 46756aef503SMatt Jacob #endif 46856aef503SMatt Jacob } 46956aef503SMatt Jacob 47056aef503SMatt Jacob /* 471d951bbcaSMatt Jacob * Make sure that SERR, PERR, WRITE INVALIDATE and BUSMASTER 472d951bbcaSMatt Jacob * are set. 473d951bbcaSMatt Jacob */ 474960f6939SMatt Jacob cmd |= PCIM_CMD_SEREN | PCIM_CMD_PERRESPEN | 475960f6939SMatt Jacob PCIM_CMD_BUSMASTEREN | PCIM_CMD_INVEN; 476960f6939SMatt Jacob pci_write_config(dev, PCIR_COMMAND, cmd, 1); 477ab6d0040SMatt Jacob 478d951bbcaSMatt Jacob /* 479222bb542SMatt Jacob * Make sure the Cache Line Size register is set sensibly. 480d951bbcaSMatt Jacob */ 481960f6939SMatt Jacob data = pci_read_config(dev, PCIR_CACHELNSZ, 1); 482ab6d0040SMatt Jacob if (data != linesz) { 483d951bbcaSMatt Jacob data = PCI_DFLT_LNSZ; 484d02373f1SMatt Jacob isp_prt(isp, ISP_LOGCONFIG, "set PCI line size to %d", data); 485960f6939SMatt Jacob pci_write_config(dev, PCIR_CACHELNSZ, data, 1); 486d951bbcaSMatt Jacob } 487ab6d0040SMatt Jacob 488d951bbcaSMatt Jacob /* 489d951bbcaSMatt Jacob * Make sure the Latency Timer is sane. 490d951bbcaSMatt Jacob */ 491960f6939SMatt Jacob data = pci_read_config(dev, PCIR_LATTIMER, 1); 492d951bbcaSMatt Jacob if (data < PCI_DFLT_LTNCY) { 493d951bbcaSMatt Jacob data = PCI_DFLT_LTNCY; 494d02373f1SMatt Jacob isp_prt(isp, ISP_LOGCONFIG, "set PCI latency to %d", data); 495960f6939SMatt Jacob pci_write_config(dev, PCIR_LATTIMER, data, 1); 496d951bbcaSMatt Jacob } 497ab6d0040SMatt Jacob 498ab6d0040SMatt Jacob /* 499ab6d0040SMatt Jacob * Make sure we've disabled the ROM. 500ab6d0040SMatt Jacob */ 501960f6939SMatt Jacob data = pci_read_config(dev, PCIR_ROMADDR, 4); 502ab6d0040SMatt Jacob data &= ~1; 503960f6939SMatt Jacob pci_write_config(dev, PCIR_ROMADDR, data, 4); 50405fbcbb0SMatt Jacob 505d951bbcaSMatt Jacob 506086646f7SJustin T. Gibbs if (bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT, 507222bb542SMatt Jacob BUS_SPACE_MAXADDR, NULL, NULL, lim + 1, 508222bb542SMatt Jacob 255, lim, 0, &pcs->parent_dmat) != 0) { 509f7dddf8aSMatt Jacob device_printf(dev, "could not create master dma tag\n"); 510960f6939SMatt Jacob free(isp->isp_param, M_DEVBUF); 511d720e6d5SJustin T. Gibbs free(pcs, M_DEVBUF); 512960f6939SMatt Jacob return (ENXIO); 51365adb54cSMatt Jacob } 51465adb54cSMatt Jacob 515960f6939SMatt Jacob iqd = 0; 516960f6939SMatt Jacob irq = bus_alloc_resource(dev, SYS_RES_IRQ, &iqd, 0, ~0, 517960f6939SMatt Jacob 1, RF_ACTIVE | RF_SHAREABLE); 518960f6939SMatt Jacob if (irq == NULL) { 519960f6939SMatt Jacob device_printf(dev, "could not allocate interrupt\n"); 520960f6939SMatt Jacob goto bad; 521960f6939SMatt Jacob } 522960f6939SMatt Jacob 523222bb542SMatt Jacob if (getenv_int("isp_no_fwload", &bitmap)) { 524222bb542SMatt Jacob if (bitmap & (1 << unit)) 525222bb542SMatt Jacob isp->isp_confopts |= ISP_CFG_NORELOAD; 526222bb542SMatt Jacob } 527222bb542SMatt Jacob if (getenv_int("isp_fwload", &bitmap)) { 528222bb542SMatt Jacob if (bitmap & (1 << unit)) 529222bb542SMatt Jacob isp->isp_confopts &= ~ISP_CFG_NORELOAD; 530222bb542SMatt Jacob } 531222bb542SMatt Jacob if (getenv_int("isp_no_nvram", &bitmap)) { 532222bb542SMatt Jacob if (bitmap & (1 << unit)) 533222bb542SMatt Jacob isp->isp_confopts |= ISP_CFG_NONVRAM; 534222bb542SMatt Jacob } 535222bb542SMatt Jacob if (getenv_int("isp_nvram", &bitmap)) { 536222bb542SMatt Jacob if (bitmap & (1 << unit)) 537222bb542SMatt Jacob isp->isp_confopts &= ~ISP_CFG_NONVRAM; 538222bb542SMatt Jacob } 539222bb542SMatt Jacob if (getenv_int("isp_fcduplex", &bitmap)) { 540222bb542SMatt Jacob if (bitmap & (1 << unit)) 541222bb542SMatt Jacob isp->isp_confopts |= ISP_CFG_FULL_DUPLEX; 542222bb542SMatt Jacob } 543222bb542SMatt Jacob if (getenv_int("isp_no_fcduplex", &bitmap)) { 544222bb542SMatt Jacob if (bitmap & (1 << unit)) 545222bb542SMatt Jacob isp->isp_confopts &= ~ISP_CFG_FULL_DUPLEX; 546222bb542SMatt Jacob } 547960f6939SMatt Jacob if (getenv_int("isp_nport", &bitmap)) { 548960f6939SMatt Jacob if (bitmap & (1 << unit)) 549960f6939SMatt Jacob isp->isp_confopts |= ISP_CFG_NPORT; 550960f6939SMatt Jacob } 551222bb542SMatt Jacob /* 5529637d68cSMatt Jacob * Look for overriding WWN. This is a Node WWN so it binds to 5539637d68cSMatt Jacob * all FC instances. A Port WWN will be constructed from it 5549637d68cSMatt Jacob * as appropriate. 555222bb542SMatt Jacob */ 5569637d68cSMatt Jacob if (!getenv_quad("isp_wwn", (quad_t *) &isp->isp_osinfo.default_wwn)) { 5579637d68cSMatt Jacob int i; 5589637d68cSMatt Jacob u_int64_t seed = (u_int64_t) (intptr_t) isp; 559222bb542SMatt Jacob 5609637d68cSMatt Jacob seed <<= 16; 5619637d68cSMatt Jacob seed &= ((1LL << 48) - 1LL); 562222bb542SMatt Jacob /* 563222bb542SMatt Jacob * This isn't very random, but it's the best we can do for 5649637d68cSMatt Jacob * the real edge case of cards that don't have WWNs. If 5659637d68cSMatt Jacob * you recompile a new vers.c, you'll get a different WWN. 566222bb542SMatt Jacob */ 5679637d68cSMatt Jacob for (i = 0; version[i] != 0; i++) { 5689637d68cSMatt Jacob seed += version[i]; 5699637d68cSMatt Jacob } 5709637d68cSMatt Jacob /* 571d02373f1SMatt Jacob * Make sure the top nibble has something vaguely sensible 572d02373f1SMatt Jacob * (NAA == Locally Administered) 5739637d68cSMatt Jacob */ 574d02373f1SMatt Jacob isp->isp_osinfo.default_wwn |= (3LL << 60) | seed; 5759637d68cSMatt Jacob } else { 5769637d68cSMatt Jacob isp->isp_confopts |= ISP_CFG_OWNWWN; 577222bb542SMatt Jacob } 578d02373f1SMatt Jacob isp_debug = 0; 579a95ae193SMatt Jacob (void) getenv_int("isp_debug", &isp_debug); 580f09b1922SMatt Jacob 581f09b1922SMatt Jacob #ifdef ISP_SMPLOCK 582f09b1922SMatt Jacob /* Make sure the lock is set up. */ 583f09b1922SMatt Jacob mtx_init(&isp->isp_osinfo.lock, "isp", MTX_DEF); 584f09b1922SMatt Jacob locksetup++; 585f09b1922SMatt Jacob #endif 586f09b1922SMatt Jacob 587f09b1922SMatt Jacob #ifdef ISP_SMPLOCK 588f09b1922SMatt Jacob if (bus_setup_intr(dev, irq, INTR_TYPE_CAM | INTR_MPSAFE, 589f09b1922SMatt Jacob isp_pci_intr, isp, &pcs->ih)) { 590960f6939SMatt Jacob device_printf(dev, "could not setup interrupt\n"); 591960f6939SMatt Jacob goto bad; 592960f6939SMatt Jacob } 593f09b1922SMatt Jacob #else 594f09b1922SMatt Jacob if (bus_setup_intr(dev, irq, INTR_TYPE_CAM, 595f09b1922SMatt Jacob isp_pci_intr, isp, &pcs->ih)) { 596f09b1922SMatt Jacob device_printf(dev, "could not setup interrupt\n"); 597f09b1922SMatt Jacob goto bad; 598f09b1922SMatt Jacob } 599f09b1922SMatt Jacob #endif 600960f6939SMatt Jacob 60105fbcbb0SMatt Jacob /* 602d02373f1SMatt Jacob * Set up logging levels. 603d02373f1SMatt Jacob */ 604d02373f1SMatt Jacob if (isp_debug) { 605d02373f1SMatt Jacob isp->isp_dblev = isp_debug; 606d02373f1SMatt Jacob } else { 607d02373f1SMatt Jacob isp->isp_dblev = ISP_LOGWARN|ISP_LOGERR; 608d02373f1SMatt Jacob } 609d02373f1SMatt Jacob if (bootverbose) 610f7dddf8aSMatt Jacob isp->isp_dblev |= ISP_LOGCONFIG|ISP_LOGINFO; 611d02373f1SMatt Jacob 612d02373f1SMatt Jacob /* 61305fbcbb0SMatt Jacob * Make sure we're in reset state. 61405fbcbb0SMatt Jacob */ 6153395b056SMatt Jacob ISP_LOCK(isp); 61665adb54cSMatt Jacob isp_reset(isp); 617d02373f1SMatt Jacob 61865adb54cSMatt Jacob if (isp->isp_state != ISP_RESETSTATE) { 6193395b056SMatt Jacob ISP_UNLOCK(isp); 620960f6939SMatt Jacob goto bad; 62165adb54cSMatt Jacob } 62265adb54cSMatt Jacob isp_init(isp); 62365adb54cSMatt Jacob if (isp->isp_state != ISP_INITSTATE) { 624d59bd469SMatt Jacob /* If we're a Fibre Channel Card, we allow deferred attach */ 625222bb542SMatt Jacob if (IS_SCSI(isp)) { 62665adb54cSMatt Jacob isp_uninit(isp); 6273395b056SMatt Jacob ISP_UNLOCK(isp); 628960f6939SMatt Jacob goto bad; 629d59bd469SMatt Jacob } 63065adb54cSMatt Jacob } 63165adb54cSMatt Jacob isp_attach(isp); 63265adb54cSMatt Jacob if (isp->isp_state != ISP_RUNSTATE) { 633d59bd469SMatt Jacob /* If we're a Fibre Channel Card, we allow deferred attach */ 63492c49d78SMatt Jacob if (IS_SCSI(isp)) { 63565adb54cSMatt Jacob isp_uninit(isp); 6363395b056SMatt Jacob ISP_UNLOCK(isp); 637960f6939SMatt Jacob goto bad; 638960f6939SMatt Jacob } 639960f6939SMatt Jacob } 64056aef503SMatt Jacob /* 64156aef503SMatt Jacob * XXXX: Here is where we might unload the f/w module 64256aef503SMatt Jacob * XXXX: (or decrease the reference count to it). 64356aef503SMatt Jacob */ 6443395b056SMatt Jacob ISP_UNLOCK(isp); 645960f6939SMatt Jacob return (0); 646960f6939SMatt Jacob 647960f6939SMatt Jacob bad: 648960f6939SMatt Jacob 649960f6939SMatt Jacob if (pcs && pcs->ih) { 650960f6939SMatt Jacob (void) bus_teardown_intr(dev, irq, pcs->ih); 651960f6939SMatt Jacob } 652960f6939SMatt Jacob 6533395b056SMatt Jacob #ifdef ISP_SMPLOCK 6543395b056SMatt Jacob if (locksetup && isp) { 6553395b056SMatt Jacob mtx_destroy(&isp->isp_osinfo.lock); 6563395b056SMatt Jacob } 6573395b056SMatt Jacob #endif 6583395b056SMatt Jacob 659960f6939SMatt Jacob if (irq) { 660960f6939SMatt Jacob (void) bus_release_resource(dev, SYS_RES_IRQ, iqd, irq); 661960f6939SMatt Jacob } 6623395b056SMatt Jacob 6633395b056SMatt Jacob 664960f6939SMatt Jacob if (regs) { 665960f6939SMatt Jacob (void) bus_release_resource(dev, rtp, rgd, regs); 666960f6939SMatt Jacob } 6673395b056SMatt Jacob 668960f6939SMatt Jacob if (pcs) { 669960f6939SMatt Jacob if (pcs->pci_isp.isp_param) 670960f6939SMatt Jacob free(pcs->pci_isp.isp_param, M_DEVBUF); 67165adb54cSMatt Jacob free(pcs, M_DEVBUF); 67265adb54cSMatt Jacob } 6733395b056SMatt Jacob 67456aef503SMatt Jacob /* 67556aef503SMatt Jacob * XXXX: Here is where we might unload the f/w module 67656aef503SMatt Jacob * XXXX: (or decrease the reference count to it). 67756aef503SMatt Jacob */ 678960f6939SMatt Jacob return (ENXIO); 67965adb54cSMatt Jacob } 68065adb54cSMatt Jacob 681f09b1922SMatt Jacob static void 682f09b1922SMatt Jacob isp_pci_intr(void *arg) 683f09b1922SMatt Jacob { 684f09b1922SMatt Jacob struct ispsoftc *isp = arg; 685f09b1922SMatt Jacob ISP_LOCK(isp); 686f09b1922SMatt Jacob (void) isp_intr(isp); 687f09b1922SMatt Jacob ISP_UNLOCK(isp); 688f09b1922SMatt Jacob } 689f09b1922SMatt Jacob 69065adb54cSMatt Jacob static u_int16_t 691d59bd469SMatt Jacob isp_pci_rd_reg(isp, regoff) 692d59bd469SMatt Jacob struct ispsoftc *isp; 693d59bd469SMatt Jacob int regoff; 69465adb54cSMatt Jacob { 69565adb54cSMatt Jacob u_int16_t rv; 69665adb54cSMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 697d59bd469SMatt Jacob int offset, oldconf = 0; 69865adb54cSMatt Jacob 699d59bd469SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 70065adb54cSMatt Jacob /* 70165adb54cSMatt Jacob * We will assume that someone has paused the RISC processor. 70265adb54cSMatt Jacob */ 703d59bd469SMatt Jacob oldconf = isp_pci_rd_reg(isp, BIU_CONF1); 704d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oldconf | BIU_PCI_CONF1_SXP); 70565adb54cSMatt Jacob } 706d59bd469SMatt Jacob offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT]; 707d59bd469SMatt Jacob offset += (regoff & 0xff); 70865adb54cSMatt Jacob rv = bus_space_read_2(pcs->pci_st, pcs->pci_sh, offset); 709d59bd469SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 710d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oldconf); 71165adb54cSMatt Jacob } 71265adb54cSMatt Jacob return (rv); 71365adb54cSMatt Jacob } 71465adb54cSMatt Jacob 71565adb54cSMatt Jacob static void 716d59bd469SMatt Jacob isp_pci_wr_reg(isp, regoff, val) 717d59bd469SMatt Jacob struct ispsoftc *isp; 718d59bd469SMatt Jacob int regoff; 719d59bd469SMatt Jacob u_int16_t val; 72065adb54cSMatt Jacob { 72165adb54cSMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 722d59bd469SMatt Jacob int offset, oldconf = 0; 723d59bd469SMatt Jacob 724d59bd469SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 72565adb54cSMatt Jacob /* 72665adb54cSMatt Jacob * We will assume that someone has paused the RISC processor. 72765adb54cSMatt Jacob */ 728d59bd469SMatt Jacob oldconf = isp_pci_rd_reg(isp, BIU_CONF1); 729d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oldconf | BIU_PCI_CONF1_SXP); 73065adb54cSMatt Jacob } 731d59bd469SMatt Jacob offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT]; 732d59bd469SMatt Jacob offset += (regoff & 0xff); 73365adb54cSMatt Jacob bus_space_write_2(pcs->pci_st, pcs->pci_sh, offset, val); 734d59bd469SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 735d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oldconf); 73665adb54cSMatt Jacob } 73765adb54cSMatt Jacob } 73865adb54cSMatt Jacob 739d59bd469SMatt Jacob static u_int16_t 740d59bd469SMatt Jacob isp_pci_rd_reg_1080(isp, regoff) 741d59bd469SMatt Jacob struct ispsoftc *isp; 742d59bd469SMatt Jacob int regoff; 743d59bd469SMatt Jacob { 74422e1dc85SMatt Jacob u_int16_t rv, oc = 0; 745d59bd469SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 74622e1dc85SMatt Jacob int offset; 747d59bd469SMatt Jacob 74822e1dc85SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK || 74922e1dc85SMatt Jacob (regoff & _BLK_REG_MASK) == (SXP_BLOCK|SXP_BANK1_SELECT)) { 75022e1dc85SMatt Jacob u_int16_t tc; 751d59bd469SMatt Jacob /* 752d59bd469SMatt Jacob * We will assume that someone has paused the RISC processor. 753d59bd469SMatt Jacob */ 754d59bd469SMatt Jacob oc = isp_pci_rd_reg(isp, BIU_CONF1); 75522e1dc85SMatt Jacob tc = oc & ~BIU_PCI1080_CONF1_DMA; 75622e1dc85SMatt Jacob if (regoff & SXP_BANK1_SELECT) 75722e1dc85SMatt Jacob tc |= BIU_PCI1080_CONF1_SXP1; 75822e1dc85SMatt Jacob else 75922e1dc85SMatt Jacob tc |= BIU_PCI1080_CONF1_SXP0; 76022e1dc85SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, tc); 761d59bd469SMatt Jacob } else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) { 762d59bd469SMatt Jacob oc = isp_pci_rd_reg(isp, BIU_CONF1); 763d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oc | BIU_PCI1080_CONF1_DMA); 764d59bd469SMatt Jacob } 765d59bd469SMatt Jacob offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT]; 766d59bd469SMatt Jacob offset += (regoff & 0xff); 767d59bd469SMatt Jacob rv = bus_space_read_2(pcs->pci_st, pcs->pci_sh, offset); 76822e1dc85SMatt Jacob if (oc) { 769d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oc); 770d59bd469SMatt Jacob } 771d59bd469SMatt Jacob return (rv); 772d59bd469SMatt Jacob } 773d59bd469SMatt Jacob 774d59bd469SMatt Jacob static void 775d59bd469SMatt Jacob isp_pci_wr_reg_1080(isp, regoff, val) 776d59bd469SMatt Jacob struct ispsoftc *isp; 777d59bd469SMatt Jacob int regoff; 778d59bd469SMatt Jacob u_int16_t val; 779d59bd469SMatt Jacob { 780d59bd469SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 781d59bd469SMatt Jacob int offset, oc = 0; 782d59bd469SMatt Jacob 78322e1dc85SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK || 78422e1dc85SMatt Jacob (regoff & _BLK_REG_MASK) == (SXP_BLOCK|SXP_BANK1_SELECT)) { 78522e1dc85SMatt Jacob u_int16_t tc; 786d59bd469SMatt Jacob /* 787d59bd469SMatt Jacob * We will assume that someone has paused the RISC processor. 788d59bd469SMatt Jacob */ 789d59bd469SMatt Jacob oc = isp_pci_rd_reg(isp, BIU_CONF1); 79022e1dc85SMatt Jacob tc = oc & ~BIU_PCI1080_CONF1_DMA; 79122e1dc85SMatt Jacob if (regoff & SXP_BANK1_SELECT) 79222e1dc85SMatt Jacob tc |= BIU_PCI1080_CONF1_SXP1; 79322e1dc85SMatt Jacob else 79422e1dc85SMatt Jacob tc |= BIU_PCI1080_CONF1_SXP0; 79522e1dc85SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, tc); 796d59bd469SMatt Jacob } else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) { 797d59bd469SMatt Jacob oc = isp_pci_rd_reg(isp, BIU_CONF1); 798d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oc | BIU_PCI1080_CONF1_DMA); 799d59bd469SMatt Jacob } 800d59bd469SMatt Jacob offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT]; 801d59bd469SMatt Jacob offset += (regoff & 0xff); 802d59bd469SMatt Jacob bus_space_write_2(pcs->pci_st, pcs->pci_sh, offset, val); 80322e1dc85SMatt Jacob if (oc) { 804d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oc); 805d59bd469SMatt Jacob } 806d59bd469SMatt Jacob } 807d59bd469SMatt Jacob 808d720e6d5SJustin T. Gibbs static void isp_map_rquest __P((void *, bus_dma_segment_t *, int, int)); 809d720e6d5SJustin T. Gibbs static void isp_map_result __P((void *, bus_dma_segment_t *, int, int)); 810d720e6d5SJustin T. Gibbs static void isp_map_fcscrt __P((void *, bus_dma_segment_t *, int, int)); 811d720e6d5SJustin T. Gibbs 812222bb542SMatt Jacob struct imush { 813222bb542SMatt Jacob struct ispsoftc *isp; 814222bb542SMatt Jacob int error; 815222bb542SMatt Jacob }; 816222bb542SMatt Jacob 817d720e6d5SJustin T. Gibbs static void 81817e318c6SMatt Jacob isp_map_rquest(void *arg, bus_dma_segment_t *segs, int nseg, int error) 819d720e6d5SJustin T. Gibbs { 820222bb542SMatt Jacob struct imush *imushp = (struct imush *) arg; 821222bb542SMatt Jacob if (error) { 822222bb542SMatt Jacob imushp->error = error; 823222bb542SMatt Jacob } else { 824222bb542SMatt Jacob imushp->isp->isp_rquest_dma = segs->ds_addr; 825222bb542SMatt Jacob } 826d720e6d5SJustin T. Gibbs } 827d720e6d5SJustin T. Gibbs 828d720e6d5SJustin T. Gibbs static void 82917e318c6SMatt Jacob isp_map_result(void *arg, bus_dma_segment_t *segs, int nseg, int error) 830d720e6d5SJustin T. Gibbs { 831222bb542SMatt Jacob struct imush *imushp = (struct imush *) arg; 832222bb542SMatt Jacob if (error) { 833222bb542SMatt Jacob imushp->error = error; 834222bb542SMatt Jacob } else { 835222bb542SMatt Jacob imushp->isp->isp_result_dma = segs->ds_addr; 836222bb542SMatt Jacob } 837d720e6d5SJustin T. Gibbs } 838d720e6d5SJustin T. Gibbs 839d720e6d5SJustin T. Gibbs static void 84017e318c6SMatt Jacob isp_map_fcscrt(void *arg, bus_dma_segment_t *segs, int nseg, int error) 841d720e6d5SJustin T. Gibbs { 842222bb542SMatt Jacob struct imush *imushp = (struct imush *) arg; 843222bb542SMatt Jacob if (error) { 844222bb542SMatt Jacob imushp->error = error; 845222bb542SMatt Jacob } else { 846222bb542SMatt Jacob fcparam *fcp = imushp->isp->isp_param; 847d720e6d5SJustin T. Gibbs fcp->isp_scdma = segs->ds_addr; 848d720e6d5SJustin T. Gibbs } 849222bb542SMatt Jacob } 850d720e6d5SJustin T. Gibbs 851d720e6d5SJustin T. Gibbs static int 85217e318c6SMatt Jacob isp_pci_mbxdma(struct ispsoftc *isp) 853d720e6d5SJustin T. Gibbs { 854d720e6d5SJustin T. Gibbs struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp; 855d720e6d5SJustin T. Gibbs caddr_t base; 856d720e6d5SJustin T. Gibbs u_int32_t len; 857d720e6d5SJustin T. Gibbs int i, error; 858222bb542SMatt Jacob bus_size_t lim; 859222bb542SMatt Jacob struct imush im; 860222bb542SMatt Jacob 861222bb542SMatt Jacob 862a95ae193SMatt Jacob /* 863a95ae193SMatt Jacob * Already been here? If so, leave... 864a95ae193SMatt Jacob */ 865a95ae193SMatt Jacob if (isp->isp_rquest) { 866a95ae193SMatt Jacob return (0); 867a95ae193SMatt Jacob } 868a95ae193SMatt Jacob 869d02373f1SMatt Jacob len = sizeof (XS_T **) * isp->isp_maxcmds; 8707cc0979fSDavid Malone isp->isp_xflist = (XS_T **) malloc(len, M_DEVBUF, M_WAITOK | M_ZERO); 871a95ae193SMatt Jacob if (isp->isp_xflist == NULL) { 872d02373f1SMatt Jacob isp_prt(isp, ISP_LOGERR, "cannot alloc xflist array"); 873a95ae193SMatt Jacob return (1); 874a95ae193SMatt Jacob } 875a95ae193SMatt Jacob len = sizeof (bus_dmamap_t) * isp->isp_maxcmds; 876a95ae193SMatt Jacob pci->dmaps = (bus_dmamap_t *) malloc(len, M_DEVBUF, M_WAITOK); 877a95ae193SMatt Jacob if (pci->dmaps == NULL) { 878d02373f1SMatt Jacob isp_prt(isp, ISP_LOGERR, "can't alloc dma maps"); 879a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 880a95ae193SMatt Jacob return (1); 881a95ae193SMatt Jacob } 882a95ae193SMatt Jacob 88322e1dc85SMatt Jacob if (IS_FC(isp) || IS_ULTRA2(isp)) 884222bb542SMatt Jacob lim = BUS_SPACE_MAXADDR + 1; 885222bb542SMatt Jacob else 886222bb542SMatt Jacob lim = BUS_SPACE_MAXADDR_24BIT + 1; 887d720e6d5SJustin T. Gibbs 888d720e6d5SJustin T. Gibbs /* 889d720e6d5SJustin T. Gibbs * Allocate and map the request, result queues, plus FC scratch area. 890d720e6d5SJustin T. Gibbs */ 891d02373f1SMatt Jacob len = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)); 892d02373f1SMatt Jacob len += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)); 893222bb542SMatt Jacob if (IS_FC(isp)) { 894d720e6d5SJustin T. Gibbs len += ISP2100_SCRLEN; 895d720e6d5SJustin T. Gibbs } 896222bb542SMatt Jacob if (bus_dma_tag_create(pci->parent_dmat, PAGE_SIZE, lim, 897222bb542SMatt Jacob BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, len, 1, 898222bb542SMatt Jacob BUS_SPACE_MAXSIZE_32BIT, 0, &pci->cntrol_dmat) != 0) { 899f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 900f7dddf8aSMatt Jacob "cannot create a dma tag for control spaces"); 901a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 902a95ae193SMatt Jacob free(pci->dmaps, M_DEVBUF); 903d720e6d5SJustin T. Gibbs return (1); 904d720e6d5SJustin T. Gibbs } 905d720e6d5SJustin T. Gibbs if (bus_dmamem_alloc(pci->cntrol_dmat, (void **)&base, 906d720e6d5SJustin T. Gibbs BUS_DMA_NOWAIT, &pci->cntrol_dmap) != 0) { 907f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 9083486bfe0SMatt Jacob "cannot allocate %d bytes of CCB memory", len); 909a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 910a95ae193SMatt Jacob free(pci->dmaps, M_DEVBUF); 911d720e6d5SJustin T. Gibbs return (1); 912d720e6d5SJustin T. Gibbs } 913d720e6d5SJustin T. Gibbs 914d720e6d5SJustin T. Gibbs isp->isp_rquest = base; 915222bb542SMatt Jacob im.isp = isp; 916222bb542SMatt Jacob im.error = 0; 917d720e6d5SJustin T. Gibbs bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap, isp->isp_rquest, 918d02373f1SMatt Jacob ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)), isp_map_rquest, &im, 0); 919222bb542SMatt Jacob if (im.error) { 920f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 921f7dddf8aSMatt Jacob "error %d loading dma map for DMA request queue", im.error); 922a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 923a95ae193SMatt Jacob free(pci->dmaps, M_DEVBUF); 924a95ae193SMatt Jacob isp->isp_rquest = NULL; 925222bb542SMatt Jacob return (1); 926222bb542SMatt Jacob } 927d02373f1SMatt Jacob isp->isp_result = base + ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)); 928222bb542SMatt Jacob im.error = 0; 929d720e6d5SJustin T. Gibbs bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap, isp->isp_result, 930d02373f1SMatt Jacob ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)), isp_map_result, &im, 0); 931222bb542SMatt Jacob if (im.error) { 932f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 933f7dddf8aSMatt Jacob "error %d loading dma map for DMA result queue", im.error); 934a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 935a95ae193SMatt Jacob free(pci->dmaps, M_DEVBUF); 936a95ae193SMatt Jacob isp->isp_rquest = NULL; 937222bb542SMatt Jacob return (1); 938222bb542SMatt Jacob } 939d720e6d5SJustin T. Gibbs 940a95ae193SMatt Jacob for (i = 0; i < isp->isp_maxcmds; i++) { 941d720e6d5SJustin T. Gibbs error = bus_dmamap_create(pci->parent_dmat, 0, &pci->dmaps[i]); 942d720e6d5SJustin T. Gibbs if (error) { 943f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 944f7dddf8aSMatt Jacob "error %d creating per-cmd DMA maps", error); 945a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 946a95ae193SMatt Jacob free(pci->dmaps, M_DEVBUF); 947a95ae193SMatt Jacob isp->isp_rquest = NULL; 948d720e6d5SJustin T. Gibbs return (1); 949d720e6d5SJustin T. Gibbs } 950d720e6d5SJustin T. Gibbs } 951a95ae193SMatt Jacob 952222bb542SMatt Jacob if (IS_FC(isp)) { 95392c49d78SMatt Jacob fcparam *fcp = (fcparam *) isp->isp_param; 95492c49d78SMatt Jacob fcp->isp_scratch = base + 955d02373f1SMatt Jacob ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)) + 956d02373f1SMatt Jacob ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)); 957222bb542SMatt Jacob im.error = 0; 95892c49d78SMatt Jacob bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap, 959222bb542SMatt Jacob fcp->isp_scratch, ISP2100_SCRLEN, isp_map_fcscrt, &im, 0); 960222bb542SMatt Jacob if (im.error) { 961f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 962f7dddf8aSMatt Jacob "error %d loading FC scratch area", im.error); 963a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 964a95ae193SMatt Jacob free(pci->dmaps, M_DEVBUF); 965a95ae193SMatt Jacob isp->isp_rquest = NULL; 966222bb542SMatt Jacob return (1); 967222bb542SMatt Jacob } 96892c49d78SMatt Jacob } 969d720e6d5SJustin T. Gibbs return (0); 970d720e6d5SJustin T. Gibbs } 971d720e6d5SJustin T. Gibbs 972d720e6d5SJustin T. Gibbs typedef struct { 973d720e6d5SJustin T. Gibbs struct ispsoftc *isp; 9749e11e5beSMatt Jacob void *cmd_token; 9759e11e5beSMatt Jacob void *rq; 9769637d68cSMatt Jacob u_int16_t *iptrp; 9779637d68cSMatt Jacob u_int16_t optr; 978d720e6d5SJustin T. Gibbs u_int error; 979d720e6d5SJustin T. Gibbs } mush_t; 980d720e6d5SJustin T. Gibbs 9814873663cSMatt Jacob #define MUSHERR_NOQENTRIES -2 9824873663cSMatt Jacob 9839e11e5beSMatt Jacob #ifdef ISP_TARGET_MODE 9849e11e5beSMatt Jacob /* 9859e11e5beSMatt Jacob * We need to handle DMA for target mode differently from initiator mode. 9869e11e5beSMatt Jacob * 9879e11e5beSMatt Jacob * DMA mapping and construction and submission of CTIO Request Entries 9889e11e5beSMatt Jacob * and rendevous for completion are very tightly coupled because we start 9899e11e5beSMatt Jacob * out by knowing (per platform) how much data we have to move, but we 9909e11e5beSMatt Jacob * don't know, up front, how many DMA mapping segments will have to be used 9919e11e5beSMatt Jacob * cover that data, so we don't know how many CTIO Request Entries we 9929e11e5beSMatt Jacob * will end up using. Further, for performance reasons we may want to 9939e11e5beSMatt Jacob * (on the last CTIO for Fibre Channel), send status too (if all went well). 9949e11e5beSMatt Jacob * 9959e11e5beSMatt Jacob * The standard vector still goes through isp_pci_dmasetup, but the callback 9969e11e5beSMatt Jacob * for the DMA mapping routines comes here instead with the whole transfer 9979e11e5beSMatt Jacob * mapped and a pointer to a partially filled in already allocated request 9989e11e5beSMatt Jacob * queue entry. We finish the job. 9999e11e5beSMatt Jacob */ 100005fbcbb0SMatt Jacob static void tdma_mk __P((void *, bus_dma_segment_t *, int, int)); 100105fbcbb0SMatt Jacob static void tdma_mkfc __P((void *, bus_dma_segment_t *, int, int)); 10029e11e5beSMatt Jacob 1003d720e6d5SJustin T. Gibbs static void 100405fbcbb0SMatt Jacob tdma_mk(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 1005d720e6d5SJustin T. Gibbs { 1006d720e6d5SJustin T. Gibbs mush_t *mp; 10079e11e5beSMatt Jacob struct ccb_scsiio *csio; 1008d720e6d5SJustin T. Gibbs struct isp_pcisoftc *pci; 1009d720e6d5SJustin T. Gibbs bus_dmamap_t *dp; 101005fbcbb0SMatt Jacob u_int8_t scsi_status; 10119e11e5beSMatt Jacob ct_entry_t *cto; 101205fbcbb0SMatt Jacob u_int32_t handle, totxfr, sflags; 101305fbcbb0SMatt Jacob int nctios, send_status; 101405fbcbb0SMatt Jacob int32_t resid; 1015d720e6d5SJustin T. Gibbs 1016d720e6d5SJustin T. Gibbs mp = (mush_t *) arg; 1017d720e6d5SJustin T. Gibbs if (error) { 1018d720e6d5SJustin T. Gibbs mp->error = error; 1019d720e6d5SJustin T. Gibbs return; 1020d720e6d5SJustin T. Gibbs } 10219e11e5beSMatt Jacob csio = mp->cmd_token; 10229e11e5beSMatt Jacob cto = mp->rq; 10239e11e5beSMatt Jacob 102465b024e1SMatt Jacob cto->ct_xfrlen = 0; 102565b024e1SMatt Jacob cto->ct_seg_count = 0; 102665b024e1SMatt Jacob cto->ct_header.rqs_entry_count = 1; 102705fbcbb0SMatt Jacob MEMZERO(cto->ct_dataseg, sizeof(cto->ct_dataseg)); 102805fbcbb0SMatt Jacob 102905fbcbb0SMatt Jacob if (nseg == 0) { 103005fbcbb0SMatt Jacob cto->ct_header.rqs_seqno = 1; 103105fbcbb0SMatt Jacob ISP_TDQE(mp->isp, "tdma_mk[no data]", *mp->iptrp, cto); 1032d02373f1SMatt Jacob isp_prt(mp->isp, ISP_LOGTDEBUG1, 1033d02373f1SMatt Jacob "CTIO lun %d->iid%d flgs 0x%x sts 0x%x ssts 0x%x res %d", 103465b024e1SMatt Jacob csio->ccb_h.target_lun, cto->ct_iid, cto->ct_flags, 103565b024e1SMatt Jacob cto->ct_status, cto->ct_scsi_status, cto->ct_resid); 103605fbcbb0SMatt Jacob ISP_SWIZ_CTIO(mp->isp, cto, cto); 103765b024e1SMatt Jacob return; 103865b024e1SMatt Jacob } 103965b024e1SMatt Jacob 104065b024e1SMatt Jacob nctios = nseg / ISP_RQDSEG; 104165b024e1SMatt Jacob if (nseg % ISP_RQDSEG) { 104265b024e1SMatt Jacob nctios++; 104365b024e1SMatt Jacob } 104465b024e1SMatt Jacob 104505fbcbb0SMatt Jacob /* 104605fbcbb0SMatt Jacob * Save handle, and potentially any SCSI status, which we'll reinsert 104705fbcbb0SMatt Jacob * on the last CTIO we're going to send. 104805fbcbb0SMatt Jacob */ 104905fbcbb0SMatt Jacob handle = cto->ct_reserved; 105005fbcbb0SMatt Jacob cto->ct_reserved = 0; 105105fbcbb0SMatt Jacob cto->ct_header.rqs_seqno = 0; 105205fbcbb0SMatt Jacob send_status = (cto->ct_flags & CT_SENDSTATUS) != 0; 105305fbcbb0SMatt Jacob 105405fbcbb0SMatt Jacob if (send_status) { 105505fbcbb0SMatt Jacob sflags = cto->ct_flags & (CT_SENDSTATUS | CT_CCINCR); 105605fbcbb0SMatt Jacob cto->ct_flags &= ~(CT_SENDSTATUS | CT_CCINCR); 105705fbcbb0SMatt Jacob /* 105805fbcbb0SMatt Jacob * Preserve residual. 105905fbcbb0SMatt Jacob */ 106005fbcbb0SMatt Jacob resid = cto->ct_resid; 106105fbcbb0SMatt Jacob 106205fbcbb0SMatt Jacob /* 106305fbcbb0SMatt Jacob * Save actual SCSI status. 106405fbcbb0SMatt Jacob */ 106505fbcbb0SMatt Jacob scsi_status = cto->ct_scsi_status; 106605fbcbb0SMatt Jacob 106705fbcbb0SMatt Jacob /* 106805fbcbb0SMatt Jacob * We can't do a status at the same time as a data CTIO, so 106905fbcbb0SMatt Jacob * we need to synthesize an extra CTIO at this level. 107005fbcbb0SMatt Jacob */ 107105fbcbb0SMatt Jacob nctios++; 107205fbcbb0SMatt Jacob } else { 107305fbcbb0SMatt Jacob sflags = scsi_status = resid = 0; 107405fbcbb0SMatt Jacob } 107505fbcbb0SMatt Jacob 107605fbcbb0SMatt Jacob totxfr = cto->ct_resid = 0; 107705fbcbb0SMatt Jacob cto->ct_scsi_status = 0; 107805fbcbb0SMatt Jacob 10799e11e5beSMatt Jacob pci = (struct isp_pcisoftc *)mp->isp; 1080469b6b9eSMatt Jacob dp = &pci->dmaps[isp_handle_index(handle)]; 10819e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 1082d720e6d5SJustin T. Gibbs bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREREAD); 1083d720e6d5SJustin T. Gibbs } else { 1084d720e6d5SJustin T. Gibbs bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREWRITE); 1085d720e6d5SJustin T. Gibbs } 1086d720e6d5SJustin T. Gibbs 10879e11e5beSMatt Jacob 10889e11e5beSMatt Jacob while (nctios--) { 108905fbcbb0SMatt Jacob int seglim; 10909e11e5beSMatt Jacob 10919e11e5beSMatt Jacob seglim = nseg; 109205fbcbb0SMatt Jacob if (seglim) { 109305fbcbb0SMatt Jacob int seg; 109405fbcbb0SMatt Jacob 10959e11e5beSMatt Jacob if (seglim > ISP_RQDSEG) 10969e11e5beSMatt Jacob seglim = ISP_RQDSEG; 10979e11e5beSMatt Jacob 109805fbcbb0SMatt Jacob for (seg = 0; seg < seglim; seg++, nseg--) { 109905fbcbb0SMatt Jacob /* 110005fbcbb0SMatt Jacob * Unlike normal initiator commands, we don't 110105fbcbb0SMatt Jacob * do any swizzling here. 110205fbcbb0SMatt Jacob */ 11039e11e5beSMatt Jacob cto->ct_dataseg[seg].ds_count = dm_segs->ds_len; 110405fbcbb0SMatt Jacob cto->ct_dataseg[seg].ds_base = dm_segs->ds_addr; 11059e11e5beSMatt Jacob cto->ct_xfrlen += dm_segs->ds_len; 110605fbcbb0SMatt Jacob totxfr += dm_segs->ds_len; 11079e11e5beSMatt Jacob dm_segs++; 11089e11e5beSMatt Jacob } 11099e11e5beSMatt Jacob cto->ct_seg_count = seg; 11109e11e5beSMatt Jacob } else { 111105fbcbb0SMatt Jacob /* 111205fbcbb0SMatt Jacob * This case should only happen when we're sending an 111305fbcbb0SMatt Jacob * extra CTIO with final status. 111405fbcbb0SMatt Jacob */ 111505fbcbb0SMatt Jacob if (send_status == 0) { 1116f7dddf8aSMatt Jacob isp_prt(mp->isp, ISP_LOGWARN, 1117f7dddf8aSMatt Jacob "tdma_mk ran out of segments"); 111805fbcbb0SMatt Jacob mp->error = EINVAL; 111905fbcbb0SMatt Jacob return; 11209e11e5beSMatt Jacob } 112105fbcbb0SMatt Jacob } 112205fbcbb0SMatt Jacob 112305fbcbb0SMatt Jacob /* 112405fbcbb0SMatt Jacob * At this point, the fields ct_lun, ct_iid, ct_tagval, 112505fbcbb0SMatt Jacob * ct_tagtype, and ct_timeout have been carried over 112605fbcbb0SMatt Jacob * unchanged from what our caller had set. 112705fbcbb0SMatt Jacob * 112805fbcbb0SMatt Jacob * The dataseg fields and the seg_count fields we just got 112905fbcbb0SMatt Jacob * through setting. The data direction we've preserved all 113005fbcbb0SMatt Jacob * along and only clear it if we're now sending status. 113105fbcbb0SMatt Jacob */ 11329e11e5beSMatt Jacob 11339e11e5beSMatt Jacob if (nctios == 0) { 11349e11e5beSMatt Jacob /* 113505fbcbb0SMatt Jacob * We're the last in a sequence of CTIOs, so mark 113605fbcbb0SMatt Jacob * this CTIO and save the handle to the CCB such that 113705fbcbb0SMatt Jacob * when this CTIO completes we can free dma resources 113805fbcbb0SMatt Jacob * and do whatever else we need to do to finish the 113905fbcbb0SMatt Jacob * rest of the command. 11409e11e5beSMatt Jacob */ 11419e11e5beSMatt Jacob cto->ct_reserved = handle; 114205fbcbb0SMatt Jacob cto->ct_header.rqs_seqno = 1; 114305fbcbb0SMatt Jacob 114405fbcbb0SMatt Jacob if (send_status) { 11459e11e5beSMatt Jacob cto->ct_scsi_status = scsi_status; 114605fbcbb0SMatt Jacob cto->ct_flags |= sflags | CT_NO_DATA;; 114705fbcbb0SMatt Jacob cto->ct_resid = resid; 114842426921SMatt Jacob } 1149d02373f1SMatt Jacob if (send_status) { 1150d02373f1SMatt Jacob isp_prt(mp->isp, ISP_LOGTDEBUG1, 1151d02373f1SMatt Jacob "CTIO lun%d for ID %d ct_flags 0x%x scsi " 1152d02373f1SMatt Jacob "status %x resid %d", 1153d02373f1SMatt Jacob csio->ccb_h.target_lun, 115405fbcbb0SMatt Jacob cto->ct_iid, cto->ct_flags, 115505fbcbb0SMatt Jacob cto->ct_scsi_status, cto->ct_resid); 1156d02373f1SMatt Jacob } else { 1157d02373f1SMatt Jacob isp_prt(mp->isp, ISP_LOGTDEBUG1, 1158d02373f1SMatt Jacob "CTIO lun%d for ID%d ct_flags 0x%x", 1159d02373f1SMatt Jacob csio->ccb_h.target_lun, 116005fbcbb0SMatt Jacob cto->ct_iid, cto->ct_flags); 116105fbcbb0SMatt Jacob } 116205fbcbb0SMatt Jacob ISP_TDQE(mp->isp, "last tdma_mk", *mp->iptrp, cto); 116305fbcbb0SMatt Jacob ISP_SWIZ_CTIO(mp->isp, cto, cto); 11649e11e5beSMatt Jacob } else { 11659e11e5beSMatt Jacob ct_entry_t *octo = cto; 116605fbcbb0SMatt Jacob 116705fbcbb0SMatt Jacob /* 116805fbcbb0SMatt Jacob * Make sure handle fields are clean 116905fbcbb0SMatt Jacob */ 11709e11e5beSMatt Jacob cto->ct_reserved = 0; 11719e11e5beSMatt Jacob cto->ct_header.rqs_seqno = 0; 117205fbcbb0SMatt Jacob 1173d02373f1SMatt Jacob isp_prt(mp->isp, ISP_LOGTDEBUG1, 1174d02373f1SMatt Jacob "CTIO lun%d for ID%d ct_flags 0x%x", 1175d02373f1SMatt Jacob csio->ccb_h.target_lun, cto->ct_iid, cto->ct_flags); 117605fbcbb0SMatt Jacob ISP_TDQE(mp->isp, "tdma_mk", *mp->iptrp, cto); 117705fbcbb0SMatt Jacob 117805fbcbb0SMatt Jacob /* 117905fbcbb0SMatt Jacob * Get a new CTIO 118005fbcbb0SMatt Jacob */ 11819e11e5beSMatt Jacob cto = (ct_entry_t *) 11829e11e5beSMatt Jacob ISP_QUEUE_ENTRY(mp->isp->isp_rquest, *mp->iptrp); 11839e11e5beSMatt Jacob *mp->iptrp = 1184d02373f1SMatt Jacob ISP_NXT_QENTRY(*mp->iptrp, RQUEST_QUEUE_LEN(isp)); 11859e11e5beSMatt Jacob if (*mp->iptrp == mp->optr) { 1186f7dddf8aSMatt Jacob isp_prt(mp->isp, ISP_LOGWARN, 1187f7dddf8aSMatt Jacob "Queue Overflow in tdma_mk"); 11889e11e5beSMatt Jacob mp->error = MUSHERR_NOQENTRIES; 11899e11e5beSMatt Jacob return; 11909e11e5beSMatt Jacob } 11919e11e5beSMatt Jacob /* 11929e11e5beSMatt Jacob * Fill in the new CTIO with info from the old one. 11939e11e5beSMatt Jacob */ 11949e11e5beSMatt Jacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO; 11959e11e5beSMatt Jacob cto->ct_header.rqs_entry_count = 1; 11969e11e5beSMatt Jacob cto->ct_header.rqs_flags = 0; 11979e11e5beSMatt Jacob cto->ct_lun = octo->ct_lun; 11989e11e5beSMatt Jacob cto->ct_iid = octo->ct_iid; 11999e11e5beSMatt Jacob cto->ct_reserved2 = octo->ct_reserved2; 12009e11e5beSMatt Jacob cto->ct_tgt = octo->ct_tgt; 120105fbcbb0SMatt Jacob cto->ct_flags = octo->ct_flags; 12029e11e5beSMatt Jacob cto->ct_status = 0; 12039e11e5beSMatt Jacob cto->ct_scsi_status = 0; 12049e11e5beSMatt Jacob cto->ct_tag_val = octo->ct_tag_val; 12059e11e5beSMatt Jacob cto->ct_tag_type = octo->ct_tag_type; 12069e11e5beSMatt Jacob cto->ct_xfrlen = 0; 12079e11e5beSMatt Jacob cto->ct_resid = 0; 12089e11e5beSMatt Jacob cto->ct_timeout = octo->ct_timeout; 12099e11e5beSMatt Jacob cto->ct_seg_count = 0; 121005fbcbb0SMatt Jacob MEMZERO(cto->ct_dataseg, sizeof(cto->ct_dataseg)); 121105fbcbb0SMatt Jacob /* 121205fbcbb0SMatt Jacob * Now swizzle the old one for the consumption of the 121305fbcbb0SMatt Jacob * chip. 121405fbcbb0SMatt Jacob */ 121505fbcbb0SMatt Jacob ISP_SWIZ_CTIO(mp->isp, octo, octo); 12169e11e5beSMatt Jacob } 12179e11e5beSMatt Jacob } 12189e11e5beSMatt Jacob } 12199e11e5beSMatt Jacob 12209e11e5beSMatt Jacob static void 122105fbcbb0SMatt Jacob tdma_mkfc(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 12229e11e5beSMatt Jacob { 12239e11e5beSMatt Jacob mush_t *mp; 12249e11e5beSMatt Jacob struct ccb_scsiio *csio; 12259e11e5beSMatt Jacob struct isp_pcisoftc *pci; 12269e11e5beSMatt Jacob bus_dmamap_t *dp; 12279e11e5beSMatt Jacob ct2_entry_t *cto; 122865b024e1SMatt Jacob u_int16_t scsi_status, send_status, send_sense; 122905fbcbb0SMatt Jacob u_int32_t handle, totxfr, datalen; 123065b024e1SMatt Jacob u_int8_t sense[QLTM_SENSELEN]; 12319e11e5beSMatt Jacob int nctios; 12329e11e5beSMatt Jacob 12339e11e5beSMatt Jacob mp = (mush_t *) arg; 12349e11e5beSMatt Jacob if (error) { 12359e11e5beSMatt Jacob mp->error = error; 12369e11e5beSMatt Jacob return; 12379e11e5beSMatt Jacob } 12389e11e5beSMatt Jacob 123965b024e1SMatt Jacob csio = mp->cmd_token; 124065b024e1SMatt Jacob cto = mp->rq; 124165b024e1SMatt Jacob 124265b024e1SMatt Jacob if (nseg == 0) { 124365b024e1SMatt Jacob if ((cto->ct_flags & CT2_FLAG_MMASK) != CT2_FLAG_MODE1) { 1244f7dddf8aSMatt Jacob isp_prt(mp->isp, ISP_LOGWARN, 1245f7dddf8aSMatt Jacob "dma2_tgt_fc, a status CTIO2 without MODE1 " 1246f7dddf8aSMatt Jacob "set (0x%x)", cto->ct_flags); 124765b024e1SMatt Jacob mp->error = EINVAL; 124865b024e1SMatt Jacob return; 124965b024e1SMatt Jacob } 125065b024e1SMatt Jacob cto->ct_header.rqs_entry_count = 1; 125105fbcbb0SMatt Jacob cto->ct_header.rqs_seqno = 1; 125265b024e1SMatt Jacob /* ct_reserved contains the handle set by caller */ 125365b024e1SMatt Jacob /* 125465b024e1SMatt Jacob * We preserve ct_lun, ct_iid, ct_rxid. We set the data 125565b024e1SMatt Jacob * flags to NO DATA and clear relative offset flags. 125665b024e1SMatt Jacob * We preserve the ct_resid and the response area. 125765b024e1SMatt Jacob */ 125865b024e1SMatt Jacob cto->ct_flags |= CT2_NO_DATA; 125905fbcbb0SMatt Jacob if (cto->ct_resid > 0) 126005fbcbb0SMatt Jacob cto->ct_flags |= CT2_DATA_UNDER; 126105fbcbb0SMatt Jacob else if (cto->ct_resid < 0) 126205fbcbb0SMatt Jacob cto->ct_flags |= CT2_DATA_OVER; 126365b024e1SMatt Jacob cto->ct_seg_count = 0; 126465b024e1SMatt Jacob cto->ct_reloff = 0; 126565b024e1SMatt Jacob ISP_TDQE(mp->isp, "dma2_tgt_fc[no data]", *mp->iptrp, cto); 1266d02373f1SMatt Jacob isp_prt(mp->isp, ISP_LOGTDEBUG1, 1267d02373f1SMatt Jacob "CTIO2 RX_ID 0x%x lun %d->iid%d flgs 0x%x sts 0x%x ssts " 1268d02373f1SMatt Jacob "0x%x res %d", cto->ct_rxid, csio->ccb_h.target_lun, 1269d02373f1SMatt Jacob cto->ct_iid, cto->ct_flags, cto->ct_status, 127065b024e1SMatt Jacob cto->rsp.m1.ct_scsi_status, cto->ct_resid); 127165b024e1SMatt Jacob ISP_SWIZ_CTIO2(isp, cto, cto); 12729e11e5beSMatt Jacob return; 12739e11e5beSMatt Jacob } 12749e11e5beSMatt Jacob 127565b024e1SMatt Jacob if ((cto->ct_flags & CT2_FLAG_MMASK) != CT2_FLAG_MODE0) { 1276f7dddf8aSMatt Jacob isp_prt(mp->isp, ISP_LOGWARN, 1277f7dddf8aSMatt Jacob "dma2_tgt_fc, a data CTIO2 without MODE0 set " 1278f7dddf8aSMatt Jacob "(0x%x)", cto->ct_flags); 127965b024e1SMatt Jacob mp->error = EINVAL; 128065b024e1SMatt Jacob return; 128165b024e1SMatt Jacob } 128265b024e1SMatt Jacob 128365b024e1SMatt Jacob 128465b024e1SMatt Jacob nctios = nseg / ISP_RQDSEG_T2; 128565b024e1SMatt Jacob if (nseg % ISP_RQDSEG_T2) { 128665b024e1SMatt Jacob nctios++; 128765b024e1SMatt Jacob } 128865b024e1SMatt Jacob 12899e11e5beSMatt Jacob /* 129065b024e1SMatt Jacob * Save the handle, status, reloff, and residual. We'll reinsert the 129165b024e1SMatt Jacob * handle into the last CTIO2 we're going to send, and reinsert status 129265b024e1SMatt Jacob * and residual (and possibly sense data) if that's to be sent as well. 129365b024e1SMatt Jacob * 129465b024e1SMatt Jacob * We preserve ct_reloff and adjust it for each data CTIO2 we send past 129565b024e1SMatt Jacob * the first one. This is needed so that the FCP DATA IUs being sent 129665b024e1SMatt Jacob * out have the correct offset (they can arrive at the other end out 129765b024e1SMatt Jacob * of order). 12989e11e5beSMatt Jacob */ 129965b024e1SMatt Jacob 13009e11e5beSMatt Jacob handle = cto->ct_reserved; 13019e11e5beSMatt Jacob cto->ct_reserved = 0; 130265b024e1SMatt Jacob 130365b024e1SMatt Jacob if ((send_status = (cto->ct_flags & CT2_SENDSTATUS)) != 0) { 13049e11e5beSMatt Jacob cto->ct_flags &= ~CT2_SENDSTATUS; 13059e11e5beSMatt Jacob 130665b024e1SMatt Jacob /* 130705fbcbb0SMatt Jacob * Preserve residual, which is actually the total count. 130865b024e1SMatt Jacob */ 130905fbcbb0SMatt Jacob datalen = cto->ct_resid; 131065b024e1SMatt Jacob 131165b024e1SMatt Jacob /* 131265b024e1SMatt Jacob * Save actual SCSI status. We'll reinsert the 131365b024e1SMatt Jacob * CT2_SNSLEN_VALID later if appropriate. 131465b024e1SMatt Jacob */ 131565b024e1SMatt Jacob scsi_status = cto->rsp.m0.ct_scsi_status & 0xff; 131665b024e1SMatt Jacob send_sense = cto->rsp.m0.ct_scsi_status & CT2_SNSLEN_VALID; 131765b024e1SMatt Jacob 131865b024e1SMatt Jacob /* 131965b024e1SMatt Jacob * If we're sending status and have a CHECK CONDTION and 132065b024e1SMatt Jacob * have sense data, we send one more CTIO2 with just the 132165b024e1SMatt Jacob * status and sense data. The upper layers have stashed 132265b024e1SMatt Jacob * the sense data in the dataseg structure for us. 132365b024e1SMatt Jacob */ 132465b024e1SMatt Jacob 132565b024e1SMatt Jacob if ((scsi_status & 0xf) == SCSI_STATUS_CHECK_COND && 132665b024e1SMatt Jacob send_sense) { 132765b024e1SMatt Jacob bcopy(cto->rsp.m0.ct_dataseg, sense, QLTM_SENSELEN); 132865b024e1SMatt Jacob nctios++; 132965b024e1SMatt Jacob } 133065b024e1SMatt Jacob } else { 133105fbcbb0SMatt Jacob scsi_status = send_sense = datalen = 0; 133265b024e1SMatt Jacob } 133365b024e1SMatt Jacob 133465b024e1SMatt Jacob totxfr = cto->ct_resid = 0; 133565b024e1SMatt Jacob cto->rsp.m0.ct_scsi_status = 0; 133665b024e1SMatt Jacob bzero(&cto->rsp, sizeof (cto->rsp)); 133765b024e1SMatt Jacob 13389e11e5beSMatt Jacob pci = (struct isp_pcisoftc *)mp->isp; 1339469b6b9eSMatt Jacob dp = &pci->dmaps[isp_handle_index(handle)]; 13409e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 13419e11e5beSMatt Jacob bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREREAD); 13429e11e5beSMatt Jacob } else { 13439e11e5beSMatt Jacob bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREWRITE); 13449e11e5beSMatt Jacob } 13459e11e5beSMatt Jacob 13469e11e5beSMatt Jacob while (nctios--) { 13479e11e5beSMatt Jacob int seg, seglim; 13489e11e5beSMatt Jacob 13499e11e5beSMatt Jacob seglim = nseg; 135065b024e1SMatt Jacob if (seglim) { 13519e11e5beSMatt Jacob if (seglim > ISP_RQDSEG_T2) 13529e11e5beSMatt Jacob seglim = ISP_RQDSEG_T2; 13539e11e5beSMatt Jacob 13549e11e5beSMatt Jacob for (seg = 0; seg < seglim; seg++) { 135565b024e1SMatt Jacob cto->rsp.m0.ct_dataseg[seg].ds_base = 135665b024e1SMatt Jacob dm_segs->ds_addr; 135765b024e1SMatt Jacob cto->rsp.m0.ct_dataseg[seg].ds_count = 135865b024e1SMatt Jacob dm_segs->ds_len; 13599e11e5beSMatt Jacob cto->rsp.m0.ct_xfrlen += dm_segs->ds_len; 136065b024e1SMatt Jacob totxfr += dm_segs->ds_len; 13619e11e5beSMatt Jacob dm_segs++; 13629e11e5beSMatt Jacob } 13639e11e5beSMatt Jacob cto->ct_seg_count = seg; 13649e11e5beSMatt Jacob } else { 136565b024e1SMatt Jacob /* 136665b024e1SMatt Jacob * This case should only happen when we're sending a 136765b024e1SMatt Jacob * synthesized MODE1 final status with sense data. 136865b024e1SMatt Jacob */ 136965b024e1SMatt Jacob if (send_sense == 0) { 1370f7dddf8aSMatt Jacob isp_prt(mp->isp, ISP_LOGWARN, 1371f7dddf8aSMatt Jacob "dma2_tgt_fc ran out of segments, " 1372f7dddf8aSMatt Jacob "no SENSE DATA"); 137365b024e1SMatt Jacob mp->error = EINVAL; 137465b024e1SMatt Jacob return; 137565b024e1SMatt Jacob } 13769e11e5beSMatt Jacob } 13779e11e5beSMatt Jacob 13789e11e5beSMatt Jacob /* 137965b024e1SMatt Jacob * At this point, the fields ct_lun, ct_iid, ct_rxid, 138065b024e1SMatt Jacob * ct_timeout have been carried over unchanged from what 138165b024e1SMatt Jacob * our caller had set. 138265b024e1SMatt Jacob * 138365b024e1SMatt Jacob * The field ct_reloff is either what the caller set, or 138465b024e1SMatt Jacob * what we've added to below. 138565b024e1SMatt Jacob * 138665b024e1SMatt Jacob * The dataseg fields and the seg_count fields we just got 138765b024e1SMatt Jacob * through setting. The data direction we've preserved all 138865b024e1SMatt Jacob * along and only clear it if we're sending a MODE1 status 138965b024e1SMatt Jacob * as the last CTIO. 139065b024e1SMatt Jacob * 139165b024e1SMatt Jacob */ 139265b024e1SMatt Jacob 139365b024e1SMatt Jacob if (nctios == 0) { 139465b024e1SMatt Jacob 139565b024e1SMatt Jacob /* 139665b024e1SMatt Jacob * We're the last in a sequence of CTIO2s, so mark this 139765b024e1SMatt Jacob * CTIO2 and save the handle to the CCB such that when 139865b024e1SMatt Jacob * this CTIO2 completes we can free dma resources and 13999e11e5beSMatt Jacob * do whatever else we need to do to finish the rest 14009e11e5beSMatt Jacob * of the command. 14019e11e5beSMatt Jacob */ 140265b024e1SMatt Jacob 14039e11e5beSMatt Jacob cto->ct_reserved = handle; 140465b024e1SMatt Jacob cto->ct_header.rqs_seqno = 1; 140565b024e1SMatt Jacob 140665b024e1SMatt Jacob if (send_status) { 140765b024e1SMatt Jacob if (send_sense) { 140865b024e1SMatt Jacob bcopy(sense, cto->rsp.m1.ct_resp, 140965b024e1SMatt Jacob QLTM_SENSELEN); 141065b024e1SMatt Jacob cto->rsp.m1.ct_senselen = 141165b024e1SMatt Jacob QLTM_SENSELEN; 141265b024e1SMatt Jacob scsi_status |= CT2_SNSLEN_VALID; 141365b024e1SMatt Jacob cto->rsp.m1.ct_scsi_status = 141465b024e1SMatt Jacob scsi_status; 141565b024e1SMatt Jacob cto->ct_flags &= CT2_FLAG_MMASK; 141665b024e1SMatt Jacob cto->ct_flags |= CT2_FLAG_MODE1 | 141765b024e1SMatt Jacob CT2_NO_DATA| CT2_SENDSTATUS; 141865b024e1SMatt Jacob } else { 141965b024e1SMatt Jacob cto->rsp.m0.ct_scsi_status = 142065b024e1SMatt Jacob scsi_status; 142165b024e1SMatt Jacob cto->ct_flags |= CT2_SENDSTATUS; 142265b024e1SMatt Jacob } 142305fbcbb0SMatt Jacob /* 142405fbcbb0SMatt Jacob * Get 'real' residual and set flags based 142505fbcbb0SMatt Jacob * on it. 142605fbcbb0SMatt Jacob */ 142705fbcbb0SMatt Jacob cto->ct_resid = datalen - totxfr; 142805fbcbb0SMatt Jacob if (cto->ct_resid > 0) 142905fbcbb0SMatt Jacob cto->ct_flags |= CT2_DATA_UNDER; 143005fbcbb0SMatt Jacob else if (cto->ct_resid < 0) 143105fbcbb0SMatt Jacob cto->ct_flags |= CT2_DATA_OVER; 143265b024e1SMatt Jacob } 14339e11e5beSMatt Jacob ISP_TDQE(mp->isp, "last dma2_tgt_fc", *mp->iptrp, cto); 1434d02373f1SMatt Jacob isp_prt(mp->isp, ISP_LOGTDEBUG1, 1435d02373f1SMatt Jacob "CTIO2 RX_ID 0x%x lun %d->iid%d flgs 0x%x sts 0x%x" 1436d02373f1SMatt Jacob " ssts 0x%x res %d", cto->ct_rxid, 143765b024e1SMatt Jacob csio->ccb_h.target_lun, (int) cto->ct_iid, 143842426921SMatt Jacob cto->ct_flags, cto->ct_status, 143965b024e1SMatt Jacob cto->rsp.m1.ct_scsi_status, cto->ct_resid); 144065b024e1SMatt Jacob ISP_SWIZ_CTIO2(isp, cto, cto); 14419e11e5beSMatt Jacob } else { 14429e11e5beSMatt Jacob ct2_entry_t *octo = cto; 144365b024e1SMatt Jacob 144465b024e1SMatt Jacob /* 144565b024e1SMatt Jacob * Make sure handle fields are clean 144665b024e1SMatt Jacob */ 14479e11e5beSMatt Jacob cto->ct_reserved = 0; 14489e11e5beSMatt Jacob cto->ct_header.rqs_seqno = 0; 144965b024e1SMatt Jacob 14509e11e5beSMatt Jacob ISP_TDQE(mp->isp, "dma2_tgt_fc", *mp->iptrp, cto); 1451d02373f1SMatt Jacob isp_prt(mp->isp, ISP_LOGTDEBUG1, 1452d02373f1SMatt Jacob "CTIO2 RX_ID 0x%x lun %d->iid%d flgs 0x%x", 1453d02373f1SMatt Jacob cto->ct_rxid, csio->ccb_h.target_lun, 1454d02373f1SMatt Jacob (int) cto->ct_iid, cto->ct_flags); 145565b024e1SMatt Jacob /* 145665b024e1SMatt Jacob * Get a new CTIO2 145765b024e1SMatt Jacob */ 14589e11e5beSMatt Jacob cto = (ct2_entry_t *) 14599e11e5beSMatt Jacob ISP_QUEUE_ENTRY(mp->isp->isp_rquest, *mp->iptrp); 14609e11e5beSMatt Jacob *mp->iptrp = 1461d02373f1SMatt Jacob ISP_NXT_QENTRY(*mp->iptrp, RQUEST_QUEUE_LEN(isp)); 14629e11e5beSMatt Jacob if (*mp->iptrp == mp->optr) { 1463f7dddf8aSMatt Jacob isp_prt(mp->isp, ISP_LOGWARN, 1464f7dddf8aSMatt Jacob "Queue Overflow in dma2_tgt_fc"); 14659e11e5beSMatt Jacob mp->error = MUSHERR_NOQENTRIES; 14669e11e5beSMatt Jacob return; 14679e11e5beSMatt Jacob } 146865b024e1SMatt Jacob 14699e11e5beSMatt Jacob /* 147065b024e1SMatt Jacob * Fill in the new CTIO2 with info from the old one. 14719e11e5beSMatt Jacob */ 14729e11e5beSMatt Jacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2; 14739e11e5beSMatt Jacob cto->ct_header.rqs_entry_count = 1; 14749e11e5beSMatt Jacob cto->ct_header.rqs_flags = 0; 147565b024e1SMatt Jacob /* ct_header.rqs_seqno && ct_reserved done later */ 14769e11e5beSMatt Jacob cto->ct_lun = octo->ct_lun; 14779e11e5beSMatt Jacob cto->ct_iid = octo->ct_iid; 14789e11e5beSMatt Jacob cto->ct_rxid = octo->ct_rxid; 147965b024e1SMatt Jacob cto->ct_flags = octo->ct_flags; 14809e11e5beSMatt Jacob cto->ct_status = 0; 14819e11e5beSMatt Jacob cto->ct_resid = 0; 14829e11e5beSMatt Jacob cto->ct_timeout = octo->ct_timeout; 14839e11e5beSMatt Jacob cto->ct_seg_count = 0; 148465b024e1SMatt Jacob /* 148565b024e1SMatt Jacob * Adjust the new relative offset by the amount which 148665b024e1SMatt Jacob * is recorded in the data segment of the old CTIO2 we 148765b024e1SMatt Jacob * just finished filling out. 148865b024e1SMatt Jacob */ 148965b024e1SMatt Jacob cto->ct_reloff += octo->rsp.m0.ct_xfrlen; 14909e11e5beSMatt Jacob bzero(&cto->rsp, sizeof (cto->rsp)); 149165b024e1SMatt Jacob ISP_SWIZ_CTIO2(isp, cto, cto); 14929e11e5beSMatt Jacob } 14939e11e5beSMatt Jacob } 14949e11e5beSMatt Jacob } 14959e11e5beSMatt Jacob #endif 14969e11e5beSMatt Jacob 14979e11e5beSMatt Jacob static void dma2 __P((void *, bus_dma_segment_t *, int, int)); 14989e11e5beSMatt Jacob 14999e11e5beSMatt Jacob static void 15009e11e5beSMatt Jacob dma2(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 15019e11e5beSMatt Jacob { 15029e11e5beSMatt Jacob mush_t *mp; 15039e11e5beSMatt Jacob struct ccb_scsiio *csio; 15049e11e5beSMatt Jacob struct isp_pcisoftc *pci; 15059e11e5beSMatt Jacob bus_dmamap_t *dp; 15069e11e5beSMatt Jacob bus_dma_segment_t *eseg; 15079e11e5beSMatt Jacob ispreq_t *rq; 15089e11e5beSMatt Jacob ispcontreq_t *crq; 15099e11e5beSMatt Jacob int seglim, datalen; 15109e11e5beSMatt Jacob 15119e11e5beSMatt Jacob mp = (mush_t *) arg; 15129e11e5beSMatt Jacob if (error) { 15139e11e5beSMatt Jacob mp->error = error; 15149e11e5beSMatt Jacob return; 15159e11e5beSMatt Jacob } 15169e11e5beSMatt Jacob 15179e11e5beSMatt Jacob if (nseg < 1) { 1518f7dddf8aSMatt Jacob isp_prt(mp->isp, ISP_LOGERR, "bad segment count (%d)", nseg); 15199e11e5beSMatt Jacob mp->error = EFAULT; 15209e11e5beSMatt Jacob return; 15219e11e5beSMatt Jacob } 15229e11e5beSMatt Jacob csio = mp->cmd_token; 15239e11e5beSMatt Jacob rq = mp->rq; 15249e11e5beSMatt Jacob pci = (struct isp_pcisoftc *)mp->isp; 1525469b6b9eSMatt Jacob dp = &pci->dmaps[isp_handle_index(rq->req_handle)]; 15269e11e5beSMatt Jacob 15279e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 15289e11e5beSMatt Jacob bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREREAD); 15299e11e5beSMatt Jacob } else { 15309e11e5beSMatt Jacob bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREWRITE); 15319e11e5beSMatt Jacob } 15329e11e5beSMatt Jacob 15339e11e5beSMatt Jacob datalen = XS_XFRLEN(csio); 15349e11e5beSMatt Jacob 15359e11e5beSMatt Jacob /* 15369e11e5beSMatt Jacob * We're passed an initial partially filled in entry that 15379e11e5beSMatt Jacob * has most fields filled in except for data transfer 15389e11e5beSMatt Jacob * related values. 15399e11e5beSMatt Jacob * 15409e11e5beSMatt Jacob * Our job is to fill in the initial request queue entry and 15419e11e5beSMatt Jacob * then to start allocating and filling in continuation entries 15429e11e5beSMatt Jacob * until we've covered the entire transfer. 15439e11e5beSMatt Jacob */ 15449e11e5beSMatt Jacob 15459e11e5beSMatt Jacob if (IS_FC(mp->isp)) { 1546d720e6d5SJustin T. Gibbs seglim = ISP_RQDSEG_T2; 1547d720e6d5SJustin T. Gibbs ((ispreqt2_t *)rq)->req_totalcnt = datalen; 15489e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 15499e11e5beSMatt Jacob ((ispreqt2_t *)rq)->req_flags |= REQFLAG_DATA_IN; 15509e11e5beSMatt Jacob } else { 15519e11e5beSMatt Jacob ((ispreqt2_t *)rq)->req_flags |= REQFLAG_DATA_OUT; 15529e11e5beSMatt Jacob } 1553d720e6d5SJustin T. Gibbs } else { 1554e142669aSMatt Jacob if (csio->cdb_len > 12) { 1555e142669aSMatt Jacob seglim = 0; 1556e142669aSMatt Jacob } else { 1557d720e6d5SJustin T. Gibbs seglim = ISP_RQDSEG; 1558e142669aSMatt Jacob } 15599e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 15609e11e5beSMatt Jacob rq->req_flags |= REQFLAG_DATA_IN; 15619e11e5beSMatt Jacob } else { 15629e11e5beSMatt Jacob rq->req_flags |= REQFLAG_DATA_OUT; 15639e11e5beSMatt Jacob } 1564d720e6d5SJustin T. Gibbs } 1565d720e6d5SJustin T. Gibbs 1566d720e6d5SJustin T. Gibbs eseg = dm_segs + nseg; 1567d720e6d5SJustin T. Gibbs 1568d720e6d5SJustin T. Gibbs while (datalen != 0 && rq->req_seg_count < seglim && dm_segs != eseg) { 15699e11e5beSMatt Jacob if (IS_FC(mp->isp)) { 1570d720e6d5SJustin T. Gibbs ispreqt2_t *rq2 = (ispreqt2_t *)rq; 1571d720e6d5SJustin T. Gibbs rq2->req_dataseg[rq2->req_seg_count].ds_base = 1572d720e6d5SJustin T. Gibbs dm_segs->ds_addr; 1573d720e6d5SJustin T. Gibbs rq2->req_dataseg[rq2->req_seg_count].ds_count = 1574d720e6d5SJustin T. Gibbs dm_segs->ds_len; 1575d720e6d5SJustin T. Gibbs } else { 1576d720e6d5SJustin T. Gibbs rq->req_dataseg[rq->req_seg_count].ds_base = 1577d720e6d5SJustin T. Gibbs dm_segs->ds_addr; 1578d720e6d5SJustin T. Gibbs rq->req_dataseg[rq->req_seg_count].ds_count = 1579d720e6d5SJustin T. Gibbs dm_segs->ds_len; 1580d720e6d5SJustin T. Gibbs } 1581d720e6d5SJustin T. Gibbs datalen -= dm_segs->ds_len; 1582d720e6d5SJustin T. Gibbs #if 0 15839e11e5beSMatt Jacob if (IS_FC(mp->isp)) { 1584d720e6d5SJustin T. Gibbs ispreqt2_t *rq2 = (ispreqt2_t *)rq; 1585d720e6d5SJustin T. Gibbs printf("%s: seg0[%d] cnt 0x%x paddr 0x%08x\n", 15869e11e5beSMatt Jacob mp->isp->isp_name, rq->req_seg_count, 1587d720e6d5SJustin T. Gibbs rq2->req_dataseg[rq2->req_seg_count].ds_count, 1588d720e6d5SJustin T. Gibbs rq2->req_dataseg[rq2->req_seg_count].ds_base); 1589d720e6d5SJustin T. Gibbs } else { 1590d720e6d5SJustin T. Gibbs printf("%s: seg0[%d] cnt 0x%x paddr 0x%08x\n", 15919e11e5beSMatt Jacob mp->isp->isp_name, rq->req_seg_count, 1592d720e6d5SJustin T. Gibbs rq->req_dataseg[rq->req_seg_count].ds_count, 1593d720e6d5SJustin T. Gibbs rq->req_dataseg[rq->req_seg_count].ds_base); 1594d720e6d5SJustin T. Gibbs } 1595d720e6d5SJustin T. Gibbs #endif 1596d720e6d5SJustin T. Gibbs rq->req_seg_count++; 1597d720e6d5SJustin T. Gibbs dm_segs++; 1598d720e6d5SJustin T. Gibbs } 1599d720e6d5SJustin T. Gibbs 1600d720e6d5SJustin T. Gibbs while (datalen > 0 && dm_segs != eseg) { 16019e11e5beSMatt Jacob crq = (ispcontreq_t *) 16029e11e5beSMatt Jacob ISP_QUEUE_ENTRY(mp->isp->isp_rquest, *mp->iptrp); 1603d02373f1SMatt Jacob *mp->iptrp = ISP_NXT_QENTRY(*mp->iptrp, RQUEST_QUEUE_LEN(isp)); 16049e11e5beSMatt Jacob if (*mp->iptrp == mp->optr) { 16054873663cSMatt Jacob #if 0 16069e11e5beSMatt Jacob printf("%s: Request Queue Overflow++\n", 16079e11e5beSMatt Jacob mp->isp->isp_name); 16084873663cSMatt Jacob #endif 16094873663cSMatt Jacob mp->error = MUSHERR_NOQENTRIES; 1610d720e6d5SJustin T. Gibbs return; 1611d720e6d5SJustin T. Gibbs } 1612d720e6d5SJustin T. Gibbs rq->req_header.rqs_entry_count++; 1613d720e6d5SJustin T. Gibbs bzero((void *)crq, sizeof (*crq)); 1614d720e6d5SJustin T. Gibbs crq->req_header.rqs_entry_count = 1; 1615d720e6d5SJustin T. Gibbs crq->req_header.rqs_entry_type = RQSTYPE_DATASEG; 1616d720e6d5SJustin T. Gibbs 1617d720e6d5SJustin T. Gibbs seglim = 0; 1618d720e6d5SJustin T. Gibbs while (datalen > 0 && seglim < ISP_CDSEG && dm_segs != eseg) { 1619d720e6d5SJustin T. Gibbs crq->req_dataseg[seglim].ds_base = 1620d720e6d5SJustin T. Gibbs dm_segs->ds_addr; 1621d720e6d5SJustin T. Gibbs crq->req_dataseg[seglim].ds_count = 1622d720e6d5SJustin T. Gibbs dm_segs->ds_len; 1623d720e6d5SJustin T. Gibbs #if 0 1624d720e6d5SJustin T. Gibbs printf("%s: seg%d[%d] cnt 0x%x paddr 0x%08x\n", 16259e11e5beSMatt Jacob mp->isp->isp_name, rq->req_header.rqs_entry_count-1, 1626d720e6d5SJustin T. Gibbs seglim, crq->req_dataseg[seglim].ds_count, 1627d720e6d5SJustin T. Gibbs crq->req_dataseg[seglim].ds_base); 1628d720e6d5SJustin T. Gibbs #endif 1629d720e6d5SJustin T. Gibbs rq->req_seg_count++; 1630d720e6d5SJustin T. Gibbs dm_segs++; 1631d720e6d5SJustin T. Gibbs seglim++; 1632d720e6d5SJustin T. Gibbs datalen -= dm_segs->ds_len; 1633d720e6d5SJustin T. Gibbs } 1634d720e6d5SJustin T. Gibbs } 1635d720e6d5SJustin T. Gibbs } 1636d720e6d5SJustin T. Gibbs 1637d720e6d5SJustin T. Gibbs static int 16389e11e5beSMatt Jacob isp_pci_dmasetup(struct ispsoftc *isp, struct ccb_scsiio *csio, ispreq_t *rq, 16399637d68cSMatt Jacob u_int16_t *iptrp, u_int16_t optr) 1640d720e6d5SJustin T. Gibbs { 1641d720e6d5SJustin T. Gibbs struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp; 16420a5f7e8bSMatt Jacob bus_dmamap_t *dp = NULL; 1643d720e6d5SJustin T. Gibbs mush_t mush, *mp; 16449e11e5beSMatt Jacob void (*eptr) __P((void *, bus_dma_segment_t *, int, int)); 1645d720e6d5SJustin T. Gibbs 164665b024e1SMatt Jacob #ifdef ISP_TARGET_MODE 164765b024e1SMatt Jacob if (csio->ccb_h.func_code == XPT_CONT_TARGET_IO) { 164865b024e1SMatt Jacob if (IS_FC(isp)) { 164905fbcbb0SMatt Jacob eptr = tdma_mkfc; 165065b024e1SMatt Jacob } else { 165105fbcbb0SMatt Jacob eptr = tdma_mk; 165265b024e1SMatt Jacob } 165305fbcbb0SMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE || 165405fbcbb0SMatt Jacob (csio->dxfer_len == 0)) { 165565b024e1SMatt Jacob rq->req_seg_count = 1; 165665b024e1SMatt Jacob mp = &mush; 165765b024e1SMatt Jacob mp->isp = isp; 165865b024e1SMatt Jacob mp->cmd_token = csio; 165965b024e1SMatt Jacob mp->rq = rq; 166065b024e1SMatt Jacob mp->iptrp = iptrp; 166165b024e1SMatt Jacob mp->optr = optr; 166265b024e1SMatt Jacob mp->error = 0; 166365b024e1SMatt Jacob (*eptr)(mp, NULL, 0, 0); 166465b024e1SMatt Jacob goto exit; 166565b024e1SMatt Jacob } 166665b024e1SMatt Jacob } else 166765b024e1SMatt Jacob #endif 166865b024e1SMatt Jacob eptr = dma2; 166965b024e1SMatt Jacob 167042426921SMatt Jacob /* 167142426921SMatt Jacob * NB: if we need to do request queue entry swizzling, 167242426921SMatt Jacob * NB: this is where it would need to be done for cmds 167342426921SMatt Jacob * NB: that move no data. For commands that move data, 167442426921SMatt Jacob * NB: swizzling would take place in those functions. 167542426921SMatt Jacob */ 167605fbcbb0SMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE || 167705fbcbb0SMatt Jacob (csio->dxfer_len == 0)) { 167842426921SMatt Jacob rq->req_seg_count = 1; 167942426921SMatt Jacob return (CMD_QUEUED); 168042426921SMatt Jacob } 168142426921SMatt Jacob 1682d720e6d5SJustin T. Gibbs /* 1683d720e6d5SJustin T. Gibbs * Do a virtual grapevine step to collect info for 16844873663cSMatt Jacob * the callback dma allocation that we have to use... 1685d720e6d5SJustin T. Gibbs */ 1686d720e6d5SJustin T. Gibbs mp = &mush; 1687d720e6d5SJustin T. Gibbs mp->isp = isp; 16889e11e5beSMatt Jacob mp->cmd_token = csio; 1689d720e6d5SJustin T. Gibbs mp->rq = rq; 1690d720e6d5SJustin T. Gibbs mp->iptrp = iptrp; 1691d720e6d5SJustin T. Gibbs mp->optr = optr; 1692d720e6d5SJustin T. Gibbs mp->error = 0; 1693d720e6d5SJustin T. Gibbs 16949e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_SCATTER_VALID) == 0) { 16959e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DATA_PHYS) == 0) { 16964873663cSMatt Jacob int error, s; 1697469b6b9eSMatt Jacob dp = &pci->dmaps[isp_handle_index(rq->req_handle)]; 1698d720e6d5SJustin T. Gibbs s = splsoftvm(); 1699d720e6d5SJustin T. Gibbs error = bus_dmamap_load(pci->parent_dmat, *dp, 17009e11e5beSMatt Jacob csio->data_ptr, csio->dxfer_len, eptr, mp, 0); 1701d720e6d5SJustin T. Gibbs if (error == EINPROGRESS) { 1702d720e6d5SJustin T. Gibbs bus_dmamap_unload(pci->parent_dmat, *dp); 1703d720e6d5SJustin T. Gibbs mp->error = EINVAL; 1704f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 1705f7dddf8aSMatt Jacob "deferred dma allocation not supported"); 1706d720e6d5SJustin T. Gibbs } else if (error && mp->error == 0) { 17070a5f7e8bSMatt Jacob #ifdef DIAGNOSTIC 17080a5f7e8bSMatt Jacob printf("%s: error %d in dma mapping code\n", 17090a5f7e8bSMatt Jacob isp->isp_name, error); 17100a5f7e8bSMatt Jacob #endif 1711d720e6d5SJustin T. Gibbs mp->error = error; 1712d720e6d5SJustin T. Gibbs } 17134873663cSMatt Jacob splx(s); 1714d720e6d5SJustin T. Gibbs } else { 1715d720e6d5SJustin T. Gibbs /* Pointer to physical buffer */ 1716d720e6d5SJustin T. Gibbs struct bus_dma_segment seg; 1717d720e6d5SJustin T. Gibbs seg.ds_addr = (bus_addr_t)csio->data_ptr; 1718d720e6d5SJustin T. Gibbs seg.ds_len = csio->dxfer_len; 17199e11e5beSMatt Jacob (*eptr)(mp, &seg, 1, 0); 1720d720e6d5SJustin T. Gibbs } 1721d720e6d5SJustin T. Gibbs } else { 1722d720e6d5SJustin T. Gibbs struct bus_dma_segment *segs; 1723d720e6d5SJustin T. Gibbs 17249e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DATA_PHYS) != 0) { 1725f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 1726f7dddf8aSMatt Jacob "Physical segment pointers unsupported"); 1727d720e6d5SJustin T. Gibbs mp->error = EINVAL; 17289e11e5beSMatt Jacob } else if ((csio->ccb_h.flags & CAM_SG_LIST_PHYS) == 0) { 1729f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 1730f7dddf8aSMatt Jacob "Virtual segment addresses unsupported"); 1731d720e6d5SJustin T. Gibbs mp->error = EINVAL; 1732d720e6d5SJustin T. Gibbs } else { 1733d720e6d5SJustin T. Gibbs /* Just use the segments provided */ 1734d720e6d5SJustin T. Gibbs segs = (struct bus_dma_segment *) csio->data_ptr; 17359e11e5beSMatt Jacob (*eptr)(mp, segs, csio->sglist_cnt, 0); 1736d720e6d5SJustin T. Gibbs } 1737d720e6d5SJustin T. Gibbs } 1738003a310fSMatt Jacob #ifdef ISP_TARGET_MODE 173965b024e1SMatt Jacob exit: 1740003a310fSMatt Jacob #endif 1741d720e6d5SJustin T. Gibbs if (mp->error) { 17424873663cSMatt Jacob int retval = CMD_COMPLETE; 17434873663cSMatt Jacob if (mp->error == MUSHERR_NOQENTRIES) { 17444873663cSMatt Jacob retval = CMD_EAGAIN; 17454873663cSMatt Jacob } else if (mp->error == EFBIG) { 17460a5f7e8bSMatt Jacob XS_SETERR(csio, CAM_REQ_TOO_BIG); 1747d720e6d5SJustin T. Gibbs } else if (mp->error == EINVAL) { 17480a5f7e8bSMatt Jacob XS_SETERR(csio, CAM_REQ_INVALID); 1749d720e6d5SJustin T. Gibbs } else { 17500a5f7e8bSMatt Jacob XS_SETERR(csio, CAM_UNREC_HBA_ERROR); 1751d720e6d5SJustin T. Gibbs } 17524873663cSMatt Jacob return (retval); 17534873663cSMatt Jacob } else { 17540a5f7e8bSMatt Jacob /* 17550a5f7e8bSMatt Jacob * Check to see if we weren't cancelled while sleeping on 17560a5f7e8bSMatt Jacob * getting DMA resources... 17570a5f7e8bSMatt Jacob */ 17589e11e5beSMatt Jacob if ((csio->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG) { 17590a5f7e8bSMatt Jacob if (dp) { 17600a5f7e8bSMatt Jacob bus_dmamap_unload(pci->parent_dmat, *dp); 17610a5f7e8bSMatt Jacob } 17620a5f7e8bSMatt Jacob return (CMD_COMPLETE); 17630a5f7e8bSMatt Jacob } 17644873663cSMatt Jacob return (CMD_QUEUED); 1765d720e6d5SJustin T. Gibbs } 1766d720e6d5SJustin T. Gibbs } 1767d720e6d5SJustin T. Gibbs 1768d720e6d5SJustin T. Gibbs static void 1769d02373f1SMatt Jacob isp_pci_dmateardown(struct ispsoftc *isp, XS_T *xs, u_int32_t handle) 1770d720e6d5SJustin T. Gibbs { 1771d720e6d5SJustin T. Gibbs struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp; 1772469b6b9eSMatt Jacob bus_dmamap_t *dp = &pci->dmaps[isp_handle_index(handle)]; 1773a95ae193SMatt Jacob if ((xs->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 1774d720e6d5SJustin T. Gibbs bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_POSTREAD); 1775d720e6d5SJustin T. Gibbs } else { 1776d720e6d5SJustin T. Gibbs bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_POSTWRITE); 1777d720e6d5SJustin T. Gibbs } 1778d720e6d5SJustin T. Gibbs bus_dmamap_unload(pci->parent_dmat, *dp); 1779d720e6d5SJustin T. Gibbs } 1780d720e6d5SJustin T. Gibbs 178165adb54cSMatt Jacob 178265adb54cSMatt Jacob static void 178317e318c6SMatt Jacob isp_pci_reset1(struct ispsoftc *isp) 178465adb54cSMatt Jacob { 178565adb54cSMatt Jacob /* Make sure the BIOS is disabled */ 178665adb54cSMatt Jacob isp_pci_wr_reg(isp, HCCR, PCI_HCCR_CMD_BIOS); 1787469b6b9eSMatt Jacob /* and enable interrupts */ 1788469b6b9eSMatt Jacob ENABLE_INTS(isp); 178965adb54cSMatt Jacob } 179065adb54cSMatt Jacob 179165adb54cSMatt Jacob static void 1792d02373f1SMatt Jacob isp_pci_dumpregs(struct ispsoftc *isp, const char *msg) 179365adb54cSMatt Jacob { 179465adb54cSMatt Jacob struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp; 1795d02373f1SMatt Jacob if (msg) 1796d02373f1SMatt Jacob printf("%s: %s\n", isp->isp_name, msg); 1797d02373f1SMatt Jacob if (IS_SCSI(isp)) 1798d02373f1SMatt Jacob printf(" biu_conf1=%x", ISP_READ(isp, BIU_CONF1)); 1799d02373f1SMatt Jacob else 1800d02373f1SMatt Jacob printf(" biu_csr=%x", ISP_READ(isp, BIU2100_CSR)); 1801d02373f1SMatt Jacob printf(" biu_icr=%x biu_isr=%x biu_sema=%x ", ISP_READ(isp, BIU_ICR), 1802d02373f1SMatt Jacob ISP_READ(isp, BIU_ISR), ISP_READ(isp, BIU_SEMA)); 1803d02373f1SMatt Jacob printf("risc_hccr=%x\n", ISP_READ(isp, HCCR)); 1804d02373f1SMatt Jacob 1805d02373f1SMatt Jacob 1806d02373f1SMatt Jacob if (IS_SCSI(isp)) { 1807d02373f1SMatt Jacob ISP_WRITE(isp, HCCR, HCCR_CMD_PAUSE); 1808d02373f1SMatt Jacob printf(" cdma_conf=%x cdma_sts=%x cdma_fifostat=%x\n", 1809d02373f1SMatt Jacob ISP_READ(isp, CDMA_CONF), ISP_READ(isp, CDMA_STATUS), 1810d02373f1SMatt Jacob ISP_READ(isp, CDMA_FIFO_STS)); 1811d02373f1SMatt Jacob printf(" ddma_conf=%x ddma_sts=%x ddma_fifostat=%x\n", 1812d02373f1SMatt Jacob ISP_READ(isp, DDMA_CONF), ISP_READ(isp, DDMA_STATUS), 1813d02373f1SMatt Jacob ISP_READ(isp, DDMA_FIFO_STS)); 1814d02373f1SMatt Jacob printf(" sxp_int=%x sxp_gross=%x sxp(scsi_ctrl)=%x\n", 1815d02373f1SMatt Jacob ISP_READ(isp, SXP_INTERRUPT), 1816d02373f1SMatt Jacob ISP_READ(isp, SXP_GROSS_ERR), 1817d02373f1SMatt Jacob ISP_READ(isp, SXP_PINS_CTRL)); 1818d02373f1SMatt Jacob ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE); 1819d02373f1SMatt Jacob } 1820d02373f1SMatt Jacob printf(" mbox regs: %x %x %x %x %x\n", 1821d02373f1SMatt Jacob ISP_READ(isp, OUTMAILBOX0), ISP_READ(isp, OUTMAILBOX1), 1822d02373f1SMatt Jacob ISP_READ(isp, OUTMAILBOX2), ISP_READ(isp, OUTMAILBOX3), 1823d02373f1SMatt Jacob ISP_READ(isp, OUTMAILBOX4)); 1824d02373f1SMatt Jacob printf(" PCI Status Command/Status=%x\n", 1825960f6939SMatt Jacob pci_read_config(pci->pci_dev, PCIR_COMMAND, 1)); 182665adb54cSMatt Jacob } 1827