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 }; 24365adb54cSMatt Jacob 244960f6939SMatt Jacob static driver_t isp_pci_driver = { 245960f6939SMatt Jacob "isp", isp_pci_methods, sizeof (struct isp_pcisoftc) 246960f6939SMatt Jacob }; 247960f6939SMatt Jacob static devclass_t isp_devclass; 248960f6939SMatt Jacob DRIVER_MODULE(isp, pci, isp_pci_driver, isp_devclass, 0, 0); 24956aef503SMatt Jacob MODULE_VERSION(isp, 1); 25065adb54cSMatt Jacob 251960f6939SMatt Jacob static int 252960f6939SMatt Jacob isp_pci_probe(device_t dev) 25365adb54cSMatt Jacob { 254960f6939SMatt Jacob switch ((pci_get_device(dev) << 16) | (pci_get_vendor(dev))) { 25556aef503SMatt Jacob case PCI_QLOGIC_ISP1020: 256960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 1020/1040 PCI SCSI Adapter"); 25765adb54cSMatt Jacob break; 258d59bd469SMatt Jacob case PCI_QLOGIC_ISP1080: 259960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 1080 PCI SCSI Adapter"); 260c6608df3SMatt Jacob break; 261c6608df3SMatt Jacob case PCI_QLOGIC_ISP1240: 262960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 1240 PCI SCSI Adapter"); 263d59bd469SMatt Jacob break; 26422e1dc85SMatt Jacob case PCI_QLOGIC_ISP1280: 265960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 1280 PCI SCSI Adapter"); 266960f6939SMatt Jacob break; 267960f6939SMatt Jacob case PCI_QLOGIC_ISP12160: 268e11a1ee8SMatt Jacob if (pci_get_subvendor(dev) == AMI_RAID_SUBVENDOR_ID) { 269e11a1ee8SMatt Jacob return (ENXIO); 270e11a1ee8SMatt Jacob } 271960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 12160 PCI SCSI Adapter"); 27222e1dc85SMatt Jacob break; 27365adb54cSMatt Jacob case PCI_QLOGIC_ISP2100: 274960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 2100 PCI FC-AL Adapter"); 27565adb54cSMatt Jacob break; 2765542fe4bSMatt Jacob case PCI_QLOGIC_ISP2200: 277960f6939SMatt Jacob device_set_desc(dev, "Qlogic ISP 2200 PCI FC-AL Adapter"); 2785542fe4bSMatt Jacob break; 27965adb54cSMatt Jacob default: 280960f6939SMatt Jacob return (ENXIO); 28165adb54cSMatt Jacob } 282d02373f1SMatt Jacob if (device_get_unit(dev) == 0 && bootverbose) { 283d02373f1SMatt Jacob printf("Qlogic ISP Driver, FreeBSD Version %d.%d, " 284a95ae193SMatt Jacob "Core Version %d.%d\n", 285d720e6d5SJustin T. Gibbs ISP_PLATFORM_VERSION_MAJOR, ISP_PLATFORM_VERSION_MINOR, 286d720e6d5SJustin T. Gibbs ISP_CORE_VERSION_MAJOR, ISP_CORE_VERSION_MINOR); 28765adb54cSMatt Jacob } 28856aef503SMatt Jacob /* 28956aef503SMatt Jacob * XXXX: Here is where we might load the f/w module 29056aef503SMatt Jacob * XXXX: (or increase a reference count to it). 29156aef503SMatt Jacob */ 292960f6939SMatt Jacob return (0); 29365adb54cSMatt Jacob } 29465adb54cSMatt Jacob 295960f6939SMatt Jacob static int 296960f6939SMatt Jacob isp_pci_attach(device_t dev) 29765adb54cSMatt Jacob { 298960f6939SMatt Jacob struct resource *regs, *irq; 2993395b056SMatt Jacob int unit, bitmap, rtp, rgd, iqd, m1, m2, isp_debug; 300960f6939SMatt Jacob u_int32_t data, cmd, linesz, psize, basetype; 30165adb54cSMatt Jacob struct isp_pcisoftc *pcs; 3023395b056SMatt Jacob struct ispsoftc *isp = NULL; 303c6608df3SMatt Jacob struct ispmdvec *mdvp; 304222bb542SMatt Jacob bus_size_t lim; 3053395b056SMatt Jacob #ifdef ISP_SMPLOCK 3063395b056SMatt Jacob int locksetup = 0; 3073395b056SMatt Jacob #endif 30865adb54cSMatt Jacob 309222bb542SMatt Jacob /* 3109ba86737SMatt Jacob * Figure out if we're supposed to skip this one. 3119ba86737SMatt Jacob */ 312960f6939SMatt Jacob unit = device_get_unit(dev); 3139ba86737SMatt Jacob if (getenv_int("isp_disable", &bitmap)) { 3149ba86737SMatt Jacob if (bitmap & (1 << unit)) { 315960f6939SMatt Jacob device_printf(dev, "not configuring\n"); 316960f6939SMatt Jacob return (ENODEV); 3179ba86737SMatt Jacob } 3189ba86737SMatt Jacob } 3199ba86737SMatt Jacob 3207cc0979fSDavid Malone pcs = malloc(sizeof (struct isp_pcisoftc), M_DEVBUF, M_NOWAIT | M_ZERO); 321960f6939SMatt Jacob if (pcs == NULL) { 322960f6939SMatt Jacob device_printf(dev, "cannot allocate softc\n"); 323960f6939SMatt Jacob return (ENOMEM); 324960f6939SMatt Jacob } 325960f6939SMatt Jacob 3269ba86737SMatt Jacob /* 327222bb542SMatt Jacob * Figure out which we should try first - memory mapping or i/o mapping? 328222bb542SMatt Jacob */ 32956aef503SMatt Jacob #ifdef __alpha__ 330960f6939SMatt Jacob m1 = PCIM_CMD_MEMEN; 331960f6939SMatt Jacob m2 = PCIM_CMD_PORTEN; 332222bb542SMatt Jacob #else 333960f6939SMatt Jacob m1 = PCIM_CMD_PORTEN; 334960f6939SMatt Jacob m2 = PCIM_CMD_MEMEN; 335222bb542SMatt Jacob #endif 336222bb542SMatt Jacob bitmap = 0; 337222bb542SMatt Jacob if (getenv_int("isp_mem_map", &bitmap)) { 338960f6939SMatt Jacob if (bitmap & (1 << unit)) { 339960f6939SMatt Jacob m1 = PCIM_CMD_MEMEN; 340960f6939SMatt Jacob m2 = PCIM_CMD_PORTEN; 341960f6939SMatt Jacob } 342222bb542SMatt Jacob } 343222bb542SMatt Jacob bitmap = 0; 344222bb542SMatt Jacob if (getenv_int("isp_io_map", &bitmap)) { 345960f6939SMatt Jacob if (bitmap & (1 << unit)) { 346960f6939SMatt Jacob m1 = PCIM_CMD_PORTEN; 347960f6939SMatt Jacob m2 = PCIM_CMD_MEMEN; 348960f6939SMatt Jacob } 349222bb542SMatt Jacob } 350222bb542SMatt Jacob 351ab6d0040SMatt Jacob linesz = PCI_DFLT_LNSZ; 352960f6939SMatt Jacob irq = regs = NULL; 353960f6939SMatt Jacob rgd = rtp = iqd = 0; 354960f6939SMatt Jacob 355960f6939SMatt Jacob cmd = pci_read_config(dev, PCIR_COMMAND, 1); 356960f6939SMatt Jacob if (cmd & m1) { 357960f6939SMatt Jacob rtp = (m1 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT; 358960f6939SMatt Jacob rgd = (m1 == PCIM_CMD_MEMEN)? MEM_MAP_REG : IO_MAP_REG; 359960f6939SMatt Jacob regs = bus_alloc_resource(dev, rtp, &rgd, 0, ~0, 1, RF_ACTIVE); 36065adb54cSMatt Jacob } 361960f6939SMatt Jacob if (regs == NULL && (cmd & m2)) { 362960f6939SMatt Jacob rtp = (m2 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT; 363960f6939SMatt Jacob rgd = (m2 == PCIM_CMD_MEMEN)? MEM_MAP_REG : IO_MAP_REG; 364960f6939SMatt Jacob regs = bus_alloc_resource(dev, rtp, &rgd, 0, ~0, 1, RF_ACTIVE); 36565adb54cSMatt Jacob } 366960f6939SMatt Jacob if (regs == NULL) { 367960f6939SMatt Jacob device_printf(dev, "unable to map any ports\n"); 368960f6939SMatt Jacob goto bad; 36965adb54cSMatt Jacob } 370222bb542SMatt Jacob if (bootverbose) 371f7dddf8aSMatt Jacob device_printf(dev, "using %s space register mapping\n", 372960f6939SMatt Jacob (rgd == IO_MAP_REG)? "I/O" : "Memory"); 373960f6939SMatt Jacob pcs->pci_dev = dev; 374960f6939SMatt Jacob pcs->pci_reg = regs; 375960f6939SMatt Jacob pcs->pci_st = rman_get_bustag(regs); 376960f6939SMatt Jacob pcs->pci_sh = rman_get_bushandle(regs); 37765adb54cSMatt Jacob 378d59bd469SMatt Jacob pcs->pci_poff[BIU_BLOCK >> _BLK_REG_SHFT] = BIU_REGS_OFF; 379d59bd469SMatt Jacob pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS_OFF; 380d59bd469SMatt Jacob pcs->pci_poff[SXP_BLOCK >> _BLK_REG_SHFT] = PCI_SXP_REGS_OFF; 381d59bd469SMatt Jacob pcs->pci_poff[RISC_BLOCK >> _BLK_REG_SHFT] = PCI_RISC_REGS_OFF; 382d59bd469SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = DMA_REGS_OFF; 383c6608df3SMatt Jacob mdvp = &mdvec; 384c6608df3SMatt Jacob basetype = ISP_HA_SCSI_UNKNOWN; 385c6608df3SMatt Jacob psize = sizeof (sdparam); 386222bb542SMatt Jacob lim = BUS_SPACE_MAXSIZE_32BIT; 38756aef503SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP1020) { 388c6608df3SMatt Jacob mdvp = &mdvec; 389c6608df3SMatt Jacob basetype = ISP_HA_SCSI_UNKNOWN; 390c6608df3SMatt Jacob psize = sizeof (sdparam); 391222bb542SMatt Jacob lim = BUS_SPACE_MAXSIZE_24BIT; 392d59bd469SMatt Jacob } 393960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP1080) { 394c6608df3SMatt Jacob mdvp = &mdvec_1080; 395c6608df3SMatt Jacob basetype = ISP_HA_SCSI_1080; 396c6608df3SMatt Jacob psize = sizeof (sdparam); 397c6608df3SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 398c6608df3SMatt Jacob ISP1080_DMA_REGS_OFF; 399c6608df3SMatt Jacob } 400960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP1240) { 401c6608df3SMatt Jacob mdvp = &mdvec_1080; 40222e1dc85SMatt Jacob basetype = ISP_HA_SCSI_1240; 40322e1dc85SMatt Jacob psize = 2 * sizeof (sdparam); 40422e1dc85SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 40522e1dc85SMatt Jacob ISP1080_DMA_REGS_OFF; 40622e1dc85SMatt Jacob } 407960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP1280) { 40822e1dc85SMatt Jacob mdvp = &mdvec_1080; 40922e1dc85SMatt Jacob basetype = ISP_HA_SCSI_1280; 410c6608df3SMatt Jacob psize = 2 * sizeof (sdparam); 411d59bd469SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 412d59bd469SMatt Jacob ISP1080_DMA_REGS_OFF; 413d59bd469SMatt Jacob } 414960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP12160) { 415960f6939SMatt Jacob mdvp = &mdvec_12160; 416960f6939SMatt Jacob basetype = ISP_HA_SCSI_12160; 417960f6939SMatt Jacob psize = 2 * sizeof (sdparam); 418960f6939SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 419960f6939SMatt Jacob ISP1080_DMA_REGS_OFF; 420960f6939SMatt Jacob } 421960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP2100) { 422c6608df3SMatt Jacob mdvp = &mdvec_2100; 423c6608df3SMatt Jacob basetype = ISP_HA_FC_2100; 424c6608df3SMatt Jacob psize = sizeof (fcparam); 425d59bd469SMatt Jacob pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = 426d59bd469SMatt Jacob PCI_MBOX_REGS2100_OFF; 427960f6939SMatt Jacob if (pci_get_revid(dev) < 3) { 428ab6d0040SMatt Jacob /* 429ab6d0040SMatt Jacob * XXX: Need to get the actual revision 430ab6d0040SMatt Jacob * XXX: number of the 2100 FB. At any rate, 431ab6d0040SMatt Jacob * XXX: lower cache line size for early revision 432ab6d0040SMatt Jacob * XXX; boards. 433ab6d0040SMatt Jacob */ 434ab6d0040SMatt Jacob linesz = 1; 435ab6d0040SMatt Jacob } 43665adb54cSMatt Jacob } 437960f6939SMatt Jacob if (pci_get_devid(dev) == PCI_QLOGIC_ISP2200) { 438222bb542SMatt Jacob mdvp = &mdvec_2200; 439222bb542SMatt Jacob basetype = ISP_HA_FC_2200; 440222bb542SMatt Jacob psize = sizeof (fcparam); 441222bb542SMatt Jacob pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = 442222bb542SMatt Jacob PCI_MBOX_REGS2100_OFF; 443222bb542SMatt Jacob } 444c6608df3SMatt Jacob isp = &pcs->pci_isp; 4457cc0979fSDavid Malone isp->isp_param = malloc(psize, M_DEVBUF, M_NOWAIT | M_ZERO); 446c6608df3SMatt Jacob if (isp->isp_param == NULL) { 447960f6939SMatt Jacob device_printf(dev, "cannot allocate parameter data\n"); 448960f6939SMatt Jacob goto bad; 449c6608df3SMatt Jacob } 450c6608df3SMatt Jacob isp->isp_mdvec = mdvp; 451c6608df3SMatt Jacob isp->isp_type = basetype; 452960f6939SMatt Jacob isp->isp_revision = pci_get_revid(dev); 453c6608df3SMatt Jacob (void) snprintf(isp->isp_name, sizeof (isp->isp_name), "isp%d", unit); 454c6608df3SMatt Jacob isp->isp_osinfo.unit = unit; 45565adb54cSMatt Jacob 45656aef503SMatt Jacob /* 45756aef503SMatt Jacob * Try and find firmware for this device. 45856aef503SMatt Jacob */ 45956aef503SMatt Jacob 46056aef503SMatt Jacob if (isp_get_firmware_p) { 46156aef503SMatt Jacob int device = (int) pci_get_device(dev); 46256aef503SMatt Jacob #ifdef ISP_TARGET_MODE 46356aef503SMatt Jacob (*isp_get_firmware_p)(0, 1, device, &mdvp->dv_ispfw); 46456aef503SMatt Jacob #else 46556aef503SMatt Jacob (*isp_get_firmware_p)(0, 0, device, &mdvp->dv_ispfw); 46656aef503SMatt Jacob #endif 46756aef503SMatt Jacob } 46856aef503SMatt Jacob 46956aef503SMatt Jacob /* 470d951bbcaSMatt Jacob * Make sure that SERR, PERR, WRITE INVALIDATE and BUSMASTER 471d951bbcaSMatt Jacob * are set. 472d951bbcaSMatt Jacob */ 473960f6939SMatt Jacob cmd |= PCIM_CMD_SEREN | PCIM_CMD_PERRESPEN | 474960f6939SMatt Jacob PCIM_CMD_BUSMASTEREN | PCIM_CMD_INVEN; 475960f6939SMatt Jacob pci_write_config(dev, PCIR_COMMAND, cmd, 1); 476ab6d0040SMatt Jacob 477d951bbcaSMatt Jacob /* 478222bb542SMatt Jacob * Make sure the Cache Line Size register is set sensibly. 479d951bbcaSMatt Jacob */ 480960f6939SMatt Jacob data = pci_read_config(dev, PCIR_CACHELNSZ, 1); 481ab6d0040SMatt Jacob if (data != linesz) { 482d951bbcaSMatt Jacob data = PCI_DFLT_LNSZ; 483d02373f1SMatt Jacob isp_prt(isp, ISP_LOGCONFIG, "set PCI line size to %d", data); 484960f6939SMatt Jacob pci_write_config(dev, PCIR_CACHELNSZ, data, 1); 485d951bbcaSMatt Jacob } 486ab6d0040SMatt Jacob 487d951bbcaSMatt Jacob /* 488d951bbcaSMatt Jacob * Make sure the Latency Timer is sane. 489d951bbcaSMatt Jacob */ 490960f6939SMatt Jacob data = pci_read_config(dev, PCIR_LATTIMER, 1); 491d951bbcaSMatt Jacob if (data < PCI_DFLT_LTNCY) { 492d951bbcaSMatt Jacob data = PCI_DFLT_LTNCY; 493d02373f1SMatt Jacob isp_prt(isp, ISP_LOGCONFIG, "set PCI latency to %d", data); 494960f6939SMatt Jacob pci_write_config(dev, PCIR_LATTIMER, data, 1); 495d951bbcaSMatt Jacob } 496ab6d0040SMatt Jacob 497ab6d0040SMatt Jacob /* 498ab6d0040SMatt Jacob * Make sure we've disabled the ROM. 499ab6d0040SMatt Jacob */ 500960f6939SMatt Jacob data = pci_read_config(dev, PCIR_ROMADDR, 4); 501ab6d0040SMatt Jacob data &= ~1; 502960f6939SMatt Jacob pci_write_config(dev, PCIR_ROMADDR, data, 4); 50305fbcbb0SMatt Jacob 504d951bbcaSMatt Jacob 505086646f7SJustin T. Gibbs if (bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT, 506222bb542SMatt Jacob BUS_SPACE_MAXADDR, NULL, NULL, lim + 1, 507222bb542SMatt Jacob 255, lim, 0, &pcs->parent_dmat) != 0) { 508f7dddf8aSMatt Jacob device_printf(dev, "could not create master dma tag\n"); 509960f6939SMatt Jacob free(isp->isp_param, M_DEVBUF); 510d720e6d5SJustin T. Gibbs free(pcs, M_DEVBUF); 511960f6939SMatt Jacob return (ENXIO); 51265adb54cSMatt Jacob } 51365adb54cSMatt Jacob 514960f6939SMatt Jacob iqd = 0; 515960f6939SMatt Jacob irq = bus_alloc_resource(dev, SYS_RES_IRQ, &iqd, 0, ~0, 516960f6939SMatt Jacob 1, RF_ACTIVE | RF_SHAREABLE); 517960f6939SMatt Jacob if (irq == NULL) { 518960f6939SMatt Jacob device_printf(dev, "could not allocate interrupt\n"); 519960f6939SMatt Jacob goto bad; 520960f6939SMatt Jacob } 521960f6939SMatt Jacob 522222bb542SMatt Jacob if (getenv_int("isp_no_fwload", &bitmap)) { 523222bb542SMatt Jacob if (bitmap & (1 << unit)) 524222bb542SMatt Jacob isp->isp_confopts |= ISP_CFG_NORELOAD; 525222bb542SMatt Jacob } 526222bb542SMatt Jacob if (getenv_int("isp_fwload", &bitmap)) { 527222bb542SMatt Jacob if (bitmap & (1 << unit)) 528222bb542SMatt Jacob isp->isp_confopts &= ~ISP_CFG_NORELOAD; 529222bb542SMatt Jacob } 530222bb542SMatt Jacob if (getenv_int("isp_no_nvram", &bitmap)) { 531222bb542SMatt Jacob if (bitmap & (1 << unit)) 532222bb542SMatt Jacob isp->isp_confopts |= ISP_CFG_NONVRAM; 533222bb542SMatt Jacob } 534222bb542SMatt Jacob if (getenv_int("isp_nvram", &bitmap)) { 535222bb542SMatt Jacob if (bitmap & (1 << unit)) 536222bb542SMatt Jacob isp->isp_confopts &= ~ISP_CFG_NONVRAM; 537222bb542SMatt Jacob } 538222bb542SMatt Jacob if (getenv_int("isp_fcduplex", &bitmap)) { 539222bb542SMatt Jacob if (bitmap & (1 << unit)) 540222bb542SMatt Jacob isp->isp_confopts |= ISP_CFG_FULL_DUPLEX; 541222bb542SMatt Jacob } 542222bb542SMatt Jacob if (getenv_int("isp_no_fcduplex", &bitmap)) { 543222bb542SMatt Jacob if (bitmap & (1 << unit)) 544222bb542SMatt Jacob isp->isp_confopts &= ~ISP_CFG_FULL_DUPLEX; 545222bb542SMatt Jacob } 546960f6939SMatt Jacob if (getenv_int("isp_nport", &bitmap)) { 547960f6939SMatt Jacob if (bitmap & (1 << unit)) 548960f6939SMatt Jacob isp->isp_confopts |= ISP_CFG_NPORT; 549960f6939SMatt Jacob } 550222bb542SMatt Jacob /* 5519637d68cSMatt Jacob * Look for overriding WWN. This is a Node WWN so it binds to 5529637d68cSMatt Jacob * all FC instances. A Port WWN will be constructed from it 5539637d68cSMatt Jacob * as appropriate. 554222bb542SMatt Jacob */ 5559637d68cSMatt Jacob if (!getenv_quad("isp_wwn", (quad_t *) &isp->isp_osinfo.default_wwn)) { 5569637d68cSMatt Jacob int i; 5579637d68cSMatt Jacob u_int64_t seed = (u_int64_t) (intptr_t) isp; 558222bb542SMatt Jacob 5599637d68cSMatt Jacob seed <<= 16; 5609637d68cSMatt Jacob seed &= ((1LL << 48) - 1LL); 561222bb542SMatt Jacob /* 562222bb542SMatt Jacob * This isn't very random, but it's the best we can do for 5639637d68cSMatt Jacob * the real edge case of cards that don't have WWNs. If 5649637d68cSMatt Jacob * you recompile a new vers.c, you'll get a different WWN. 565222bb542SMatt Jacob */ 5669637d68cSMatt Jacob for (i = 0; version[i] != 0; i++) { 5679637d68cSMatt Jacob seed += version[i]; 5689637d68cSMatt Jacob } 5699637d68cSMatt Jacob /* 570d02373f1SMatt Jacob * Make sure the top nibble has something vaguely sensible 571d02373f1SMatt Jacob * (NAA == Locally Administered) 5729637d68cSMatt Jacob */ 573d02373f1SMatt Jacob isp->isp_osinfo.default_wwn |= (3LL << 60) | seed; 5749637d68cSMatt Jacob } else { 5759637d68cSMatt Jacob isp->isp_confopts |= ISP_CFG_OWNWWN; 576222bb542SMatt Jacob } 577d02373f1SMatt Jacob isp_debug = 0; 578a95ae193SMatt Jacob (void) getenv_int("isp_debug", &isp_debug); 579960f6939SMatt Jacob if (bus_setup_intr(dev, irq, INTR_TYPE_CAM, (void (*)(void *))isp_intr, 580960f6939SMatt Jacob isp, &pcs->ih)) { 581960f6939SMatt Jacob device_printf(dev, "could not setup interrupt\n"); 582960f6939SMatt Jacob goto bad; 583960f6939SMatt Jacob } 584960f6939SMatt Jacob 58505fbcbb0SMatt Jacob /* 586d02373f1SMatt Jacob * Set up logging levels. 587d02373f1SMatt Jacob */ 588d02373f1SMatt Jacob if (isp_debug) { 589d02373f1SMatt Jacob isp->isp_dblev = isp_debug; 590d02373f1SMatt Jacob } else { 591d02373f1SMatt Jacob isp->isp_dblev = ISP_LOGWARN|ISP_LOGERR; 592d02373f1SMatt Jacob } 593d02373f1SMatt Jacob if (bootverbose) 594f7dddf8aSMatt Jacob isp->isp_dblev |= ISP_LOGCONFIG|ISP_LOGINFO; 595d02373f1SMatt Jacob 5963395b056SMatt Jacob #ifdef ISP_SMPLOCK 5973395b056SMatt Jacob /* Make sure the lock is set up. */ 5983395b056SMatt Jacob mtx_init(&isp->isp_osinfo.lock, "isp", MTX_DEF); 5993395b056SMatt Jacob locksetup++; 6003395b056SMatt Jacob #endif 6013395b056SMatt Jacob 602d02373f1SMatt Jacob /* 60305fbcbb0SMatt Jacob * Make sure we're in reset state. 60405fbcbb0SMatt Jacob */ 6053395b056SMatt Jacob ISP_LOCK(isp); 60665adb54cSMatt Jacob isp_reset(isp); 607d02373f1SMatt Jacob 60865adb54cSMatt Jacob if (isp->isp_state != ISP_RESETSTATE) { 6093395b056SMatt Jacob ISP_UNLOCK(isp); 610960f6939SMatt Jacob goto bad; 61165adb54cSMatt Jacob } 61265adb54cSMatt Jacob isp_init(isp); 61365adb54cSMatt Jacob if (isp->isp_state != ISP_INITSTATE) { 614d59bd469SMatt Jacob /* If we're a Fibre Channel Card, we allow deferred attach */ 615222bb542SMatt Jacob if (IS_SCSI(isp)) { 61665adb54cSMatt Jacob isp_uninit(isp); 6173395b056SMatt Jacob ISP_UNLOCK(isp); 618960f6939SMatt Jacob goto bad; 619d59bd469SMatt Jacob } 62065adb54cSMatt Jacob } 62165adb54cSMatt Jacob isp_attach(isp); 62265adb54cSMatt Jacob if (isp->isp_state != ISP_RUNSTATE) { 623d59bd469SMatt Jacob /* If we're a Fibre Channel Card, we allow deferred attach */ 62492c49d78SMatt Jacob if (IS_SCSI(isp)) { 62565adb54cSMatt Jacob isp_uninit(isp); 6263395b056SMatt Jacob ISP_UNLOCK(isp); 627960f6939SMatt Jacob goto bad; 628960f6939SMatt Jacob } 629960f6939SMatt Jacob } 63056aef503SMatt Jacob /* 63156aef503SMatt Jacob * XXXX: Here is where we might unload the f/w module 63256aef503SMatt Jacob * XXXX: (or decrease the reference count to it). 63356aef503SMatt Jacob */ 6343395b056SMatt Jacob ISP_UNLOCK(isp); 635960f6939SMatt Jacob return (0); 636960f6939SMatt Jacob 637960f6939SMatt Jacob bad: 638960f6939SMatt Jacob 639960f6939SMatt Jacob if (pcs && pcs->ih) { 640960f6939SMatt Jacob (void) bus_teardown_intr(dev, irq, pcs->ih); 641960f6939SMatt Jacob } 642960f6939SMatt Jacob 6433395b056SMatt Jacob #ifdef ISP_SMPLOCK 6443395b056SMatt Jacob if (locksetup && isp) { 6453395b056SMatt Jacob mtx_destroy(&isp->isp_osinfo.lock); 6463395b056SMatt Jacob } 6473395b056SMatt Jacob #endif 6483395b056SMatt Jacob 649960f6939SMatt Jacob if (irq) { 650960f6939SMatt Jacob (void) bus_release_resource(dev, SYS_RES_IRQ, iqd, irq); 651960f6939SMatt Jacob } 6523395b056SMatt Jacob 6533395b056SMatt Jacob 654960f6939SMatt Jacob if (regs) { 655960f6939SMatt Jacob (void) bus_release_resource(dev, rtp, rgd, regs); 656960f6939SMatt Jacob } 6573395b056SMatt Jacob 658960f6939SMatt Jacob if (pcs) { 659960f6939SMatt Jacob if (pcs->pci_isp.isp_param) 660960f6939SMatt Jacob free(pcs->pci_isp.isp_param, M_DEVBUF); 66165adb54cSMatt Jacob free(pcs, M_DEVBUF); 66265adb54cSMatt Jacob } 6633395b056SMatt Jacob 66456aef503SMatt Jacob /* 66556aef503SMatt Jacob * XXXX: Here is where we might unload the f/w module 66656aef503SMatt Jacob * XXXX: (or decrease the reference count to it). 66756aef503SMatt Jacob */ 668960f6939SMatt Jacob return (ENXIO); 66965adb54cSMatt Jacob } 67065adb54cSMatt Jacob 67165adb54cSMatt Jacob static u_int16_t 672d59bd469SMatt Jacob isp_pci_rd_reg(isp, regoff) 673d59bd469SMatt Jacob struct ispsoftc *isp; 674d59bd469SMatt Jacob int regoff; 67565adb54cSMatt Jacob { 67665adb54cSMatt Jacob u_int16_t rv; 67765adb54cSMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 678d59bd469SMatt Jacob int offset, oldconf = 0; 67965adb54cSMatt Jacob 680d59bd469SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 68165adb54cSMatt Jacob /* 68265adb54cSMatt Jacob * We will assume that someone has paused the RISC processor. 68365adb54cSMatt Jacob */ 684d59bd469SMatt Jacob oldconf = isp_pci_rd_reg(isp, BIU_CONF1); 685d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oldconf | BIU_PCI_CONF1_SXP); 68665adb54cSMatt Jacob } 687d59bd469SMatt Jacob offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT]; 688d59bd469SMatt Jacob offset += (regoff & 0xff); 68965adb54cSMatt Jacob rv = bus_space_read_2(pcs->pci_st, pcs->pci_sh, offset); 690d59bd469SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 691d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oldconf); 69265adb54cSMatt Jacob } 69365adb54cSMatt Jacob return (rv); 69465adb54cSMatt Jacob } 69565adb54cSMatt Jacob 69665adb54cSMatt Jacob static void 697d59bd469SMatt Jacob isp_pci_wr_reg(isp, regoff, val) 698d59bd469SMatt Jacob struct ispsoftc *isp; 699d59bd469SMatt Jacob int regoff; 700d59bd469SMatt Jacob u_int16_t val; 70165adb54cSMatt Jacob { 70265adb54cSMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 703d59bd469SMatt Jacob int offset, oldconf = 0; 704d59bd469SMatt Jacob 705d59bd469SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 70665adb54cSMatt Jacob /* 70765adb54cSMatt Jacob * We will assume that someone has paused the RISC processor. 70865adb54cSMatt Jacob */ 709d59bd469SMatt Jacob oldconf = isp_pci_rd_reg(isp, BIU_CONF1); 710d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oldconf | BIU_PCI_CONF1_SXP); 71165adb54cSMatt Jacob } 712d59bd469SMatt Jacob offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT]; 713d59bd469SMatt Jacob offset += (regoff & 0xff); 71465adb54cSMatt Jacob bus_space_write_2(pcs->pci_st, pcs->pci_sh, offset, val); 715d59bd469SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 716d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oldconf); 71765adb54cSMatt Jacob } 71865adb54cSMatt Jacob } 71965adb54cSMatt Jacob 720d59bd469SMatt Jacob static u_int16_t 721d59bd469SMatt Jacob isp_pci_rd_reg_1080(isp, regoff) 722d59bd469SMatt Jacob struct ispsoftc *isp; 723d59bd469SMatt Jacob int regoff; 724d59bd469SMatt Jacob { 72522e1dc85SMatt Jacob u_int16_t rv, oc = 0; 726d59bd469SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 72722e1dc85SMatt Jacob int offset; 728d59bd469SMatt Jacob 72922e1dc85SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK || 73022e1dc85SMatt Jacob (regoff & _BLK_REG_MASK) == (SXP_BLOCK|SXP_BANK1_SELECT)) { 73122e1dc85SMatt Jacob u_int16_t tc; 732d59bd469SMatt Jacob /* 733d59bd469SMatt Jacob * We will assume that someone has paused the RISC processor. 734d59bd469SMatt Jacob */ 735d59bd469SMatt Jacob oc = isp_pci_rd_reg(isp, BIU_CONF1); 73622e1dc85SMatt Jacob tc = oc & ~BIU_PCI1080_CONF1_DMA; 73722e1dc85SMatt Jacob if (regoff & SXP_BANK1_SELECT) 73822e1dc85SMatt Jacob tc |= BIU_PCI1080_CONF1_SXP1; 73922e1dc85SMatt Jacob else 74022e1dc85SMatt Jacob tc |= BIU_PCI1080_CONF1_SXP0; 74122e1dc85SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, tc); 742d59bd469SMatt Jacob } else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) { 743d59bd469SMatt Jacob oc = isp_pci_rd_reg(isp, BIU_CONF1); 744d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oc | BIU_PCI1080_CONF1_DMA); 745d59bd469SMatt Jacob } 746d59bd469SMatt Jacob offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT]; 747d59bd469SMatt Jacob offset += (regoff & 0xff); 748d59bd469SMatt Jacob rv = bus_space_read_2(pcs->pci_st, pcs->pci_sh, offset); 74922e1dc85SMatt Jacob if (oc) { 750d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oc); 751d59bd469SMatt Jacob } 752d59bd469SMatt Jacob return (rv); 753d59bd469SMatt Jacob } 754d59bd469SMatt Jacob 755d59bd469SMatt Jacob static void 756d59bd469SMatt Jacob isp_pci_wr_reg_1080(isp, regoff, val) 757d59bd469SMatt Jacob struct ispsoftc *isp; 758d59bd469SMatt Jacob int regoff; 759d59bd469SMatt Jacob u_int16_t val; 760d59bd469SMatt Jacob { 761d59bd469SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 762d59bd469SMatt Jacob int offset, oc = 0; 763d59bd469SMatt Jacob 76422e1dc85SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK || 76522e1dc85SMatt Jacob (regoff & _BLK_REG_MASK) == (SXP_BLOCK|SXP_BANK1_SELECT)) { 76622e1dc85SMatt Jacob u_int16_t tc; 767d59bd469SMatt Jacob /* 768d59bd469SMatt Jacob * We will assume that someone has paused the RISC processor. 769d59bd469SMatt Jacob */ 770d59bd469SMatt Jacob oc = isp_pci_rd_reg(isp, BIU_CONF1); 77122e1dc85SMatt Jacob tc = oc & ~BIU_PCI1080_CONF1_DMA; 77222e1dc85SMatt Jacob if (regoff & SXP_BANK1_SELECT) 77322e1dc85SMatt Jacob tc |= BIU_PCI1080_CONF1_SXP1; 77422e1dc85SMatt Jacob else 77522e1dc85SMatt Jacob tc |= BIU_PCI1080_CONF1_SXP0; 77622e1dc85SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, tc); 777d59bd469SMatt Jacob } else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) { 778d59bd469SMatt Jacob oc = isp_pci_rd_reg(isp, BIU_CONF1); 779d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oc | BIU_PCI1080_CONF1_DMA); 780d59bd469SMatt Jacob } 781d59bd469SMatt Jacob offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT]; 782d59bd469SMatt Jacob offset += (regoff & 0xff); 783d59bd469SMatt Jacob bus_space_write_2(pcs->pci_st, pcs->pci_sh, offset, val); 78422e1dc85SMatt Jacob if (oc) { 785d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oc); 786d59bd469SMatt Jacob } 787d59bd469SMatt Jacob } 788d59bd469SMatt Jacob 789d720e6d5SJustin T. Gibbs static void isp_map_rquest __P((void *, bus_dma_segment_t *, int, int)); 790d720e6d5SJustin T. Gibbs static void isp_map_result __P((void *, bus_dma_segment_t *, int, int)); 791d720e6d5SJustin T. Gibbs static void isp_map_fcscrt __P((void *, bus_dma_segment_t *, int, int)); 792d720e6d5SJustin T. Gibbs 793222bb542SMatt Jacob struct imush { 794222bb542SMatt Jacob struct ispsoftc *isp; 795222bb542SMatt Jacob int error; 796222bb542SMatt Jacob }; 797222bb542SMatt Jacob 798d720e6d5SJustin T. Gibbs static void 79917e318c6SMatt Jacob isp_map_rquest(void *arg, bus_dma_segment_t *segs, int nseg, int error) 800d720e6d5SJustin T. Gibbs { 801222bb542SMatt Jacob struct imush *imushp = (struct imush *) arg; 802222bb542SMatt Jacob if (error) { 803222bb542SMatt Jacob imushp->error = error; 804222bb542SMatt Jacob } else { 805222bb542SMatt Jacob imushp->isp->isp_rquest_dma = segs->ds_addr; 806222bb542SMatt Jacob } 807d720e6d5SJustin T. Gibbs } 808d720e6d5SJustin T. Gibbs 809d720e6d5SJustin T. Gibbs static void 81017e318c6SMatt Jacob isp_map_result(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_result_dma = segs->ds_addr; 817222bb542SMatt Jacob } 818d720e6d5SJustin T. Gibbs } 819d720e6d5SJustin T. Gibbs 820d720e6d5SJustin T. Gibbs static void 82117e318c6SMatt Jacob isp_map_fcscrt(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 fcparam *fcp = imushp->isp->isp_param; 828d720e6d5SJustin T. Gibbs fcp->isp_scdma = segs->ds_addr; 829d720e6d5SJustin T. Gibbs } 830222bb542SMatt Jacob } 831d720e6d5SJustin T. Gibbs 832d720e6d5SJustin T. Gibbs static int 83317e318c6SMatt Jacob isp_pci_mbxdma(struct ispsoftc *isp) 834d720e6d5SJustin T. Gibbs { 835d720e6d5SJustin T. Gibbs struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp; 836d720e6d5SJustin T. Gibbs caddr_t base; 837d720e6d5SJustin T. Gibbs u_int32_t len; 838d720e6d5SJustin T. Gibbs int i, error; 839222bb542SMatt Jacob bus_size_t lim; 840222bb542SMatt Jacob struct imush im; 841222bb542SMatt Jacob 842222bb542SMatt Jacob 843a95ae193SMatt Jacob /* 844a95ae193SMatt Jacob * Already been here? If so, leave... 845a95ae193SMatt Jacob */ 846a95ae193SMatt Jacob if (isp->isp_rquest) { 847a95ae193SMatt Jacob return (0); 848a95ae193SMatt Jacob } 849a95ae193SMatt Jacob 850d02373f1SMatt Jacob len = sizeof (XS_T **) * isp->isp_maxcmds; 8517cc0979fSDavid Malone isp->isp_xflist = (XS_T **) malloc(len, M_DEVBUF, M_WAITOK | M_ZERO); 852a95ae193SMatt Jacob if (isp->isp_xflist == NULL) { 853d02373f1SMatt Jacob isp_prt(isp, ISP_LOGERR, "cannot alloc xflist array"); 854a95ae193SMatt Jacob return (1); 855a95ae193SMatt Jacob } 856a95ae193SMatt Jacob len = sizeof (bus_dmamap_t) * isp->isp_maxcmds; 857a95ae193SMatt Jacob pci->dmaps = (bus_dmamap_t *) malloc(len, M_DEVBUF, M_WAITOK); 858a95ae193SMatt Jacob if (pci->dmaps == NULL) { 859d02373f1SMatt Jacob isp_prt(isp, ISP_LOGERR, "can't alloc dma maps"); 860a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 861a95ae193SMatt Jacob return (1); 862a95ae193SMatt Jacob } 863a95ae193SMatt Jacob 86422e1dc85SMatt Jacob if (IS_FC(isp) || IS_ULTRA2(isp)) 865222bb542SMatt Jacob lim = BUS_SPACE_MAXADDR + 1; 866222bb542SMatt Jacob else 867222bb542SMatt Jacob lim = BUS_SPACE_MAXADDR_24BIT + 1; 868d720e6d5SJustin T. Gibbs 869d720e6d5SJustin T. Gibbs /* 870d720e6d5SJustin T. Gibbs * Allocate and map the request, result queues, plus FC scratch area. 871d720e6d5SJustin T. Gibbs */ 872d02373f1SMatt Jacob len = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)); 873d02373f1SMatt Jacob len += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)); 874222bb542SMatt Jacob if (IS_FC(isp)) { 875d720e6d5SJustin T. Gibbs len += ISP2100_SCRLEN; 876d720e6d5SJustin T. Gibbs } 877222bb542SMatt Jacob if (bus_dma_tag_create(pci->parent_dmat, PAGE_SIZE, lim, 878222bb542SMatt Jacob BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, len, 1, 879222bb542SMatt Jacob BUS_SPACE_MAXSIZE_32BIT, 0, &pci->cntrol_dmat) != 0) { 880f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 881f7dddf8aSMatt Jacob "cannot create a dma tag for control spaces"); 882a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 883a95ae193SMatt Jacob free(pci->dmaps, M_DEVBUF); 884d720e6d5SJustin T. Gibbs return (1); 885d720e6d5SJustin T. Gibbs } 886d720e6d5SJustin T. Gibbs if (bus_dmamem_alloc(pci->cntrol_dmat, (void **)&base, 887d720e6d5SJustin T. Gibbs BUS_DMA_NOWAIT, &pci->cntrol_dmap) != 0) { 888f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 889f7dddf8aSMatt Jacob "cannot allocate %d bytes of CCB memory"); 890a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 891a95ae193SMatt Jacob free(pci->dmaps, M_DEVBUF); 892d720e6d5SJustin T. Gibbs return (1); 893d720e6d5SJustin T. Gibbs } 894d720e6d5SJustin T. Gibbs 895d720e6d5SJustin T. Gibbs isp->isp_rquest = base; 896222bb542SMatt Jacob im.isp = isp; 897222bb542SMatt Jacob im.error = 0; 898d720e6d5SJustin T. Gibbs bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap, isp->isp_rquest, 899d02373f1SMatt Jacob ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)), isp_map_rquest, &im, 0); 900222bb542SMatt Jacob if (im.error) { 901f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 902f7dddf8aSMatt Jacob "error %d loading dma map for DMA request queue", im.error); 903a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 904a95ae193SMatt Jacob free(pci->dmaps, M_DEVBUF); 905a95ae193SMatt Jacob isp->isp_rquest = NULL; 906222bb542SMatt Jacob return (1); 907222bb542SMatt Jacob } 908d02373f1SMatt Jacob isp->isp_result = base + ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)); 909222bb542SMatt Jacob im.error = 0; 910d720e6d5SJustin T. Gibbs bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap, isp->isp_result, 911d02373f1SMatt Jacob ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)), isp_map_result, &im, 0); 912222bb542SMatt Jacob if (im.error) { 913f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 914f7dddf8aSMatt Jacob "error %d loading dma map for DMA result queue", 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 921a95ae193SMatt Jacob for (i = 0; i < isp->isp_maxcmds; i++) { 922d720e6d5SJustin T. Gibbs error = bus_dmamap_create(pci->parent_dmat, 0, &pci->dmaps[i]); 923d720e6d5SJustin T. Gibbs if (error) { 924f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 925f7dddf8aSMatt Jacob "error %d creating per-cmd DMA maps", error); 926a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 927a95ae193SMatt Jacob free(pci->dmaps, M_DEVBUF); 928a95ae193SMatt Jacob isp->isp_rquest = NULL; 929d720e6d5SJustin T. Gibbs return (1); 930d720e6d5SJustin T. Gibbs } 931d720e6d5SJustin T. Gibbs } 932a95ae193SMatt Jacob 933222bb542SMatt Jacob if (IS_FC(isp)) { 93492c49d78SMatt Jacob fcparam *fcp = (fcparam *) isp->isp_param; 93592c49d78SMatt Jacob fcp->isp_scratch = base + 936d02373f1SMatt Jacob ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)) + 937d02373f1SMatt Jacob ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)); 938222bb542SMatt Jacob im.error = 0; 93992c49d78SMatt Jacob bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap, 940222bb542SMatt Jacob fcp->isp_scratch, ISP2100_SCRLEN, isp_map_fcscrt, &im, 0); 941222bb542SMatt Jacob if (im.error) { 942f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 943f7dddf8aSMatt Jacob "error %d loading FC scratch area", im.error); 944a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 945a95ae193SMatt Jacob free(pci->dmaps, M_DEVBUF); 946a95ae193SMatt Jacob isp->isp_rquest = NULL; 947222bb542SMatt Jacob return (1); 948222bb542SMatt Jacob } 94992c49d78SMatt Jacob } 950d720e6d5SJustin T. Gibbs return (0); 951d720e6d5SJustin T. Gibbs } 952d720e6d5SJustin T. Gibbs 953d720e6d5SJustin T. Gibbs typedef struct { 954d720e6d5SJustin T. Gibbs struct ispsoftc *isp; 9559e11e5beSMatt Jacob void *cmd_token; 9569e11e5beSMatt Jacob void *rq; 9579637d68cSMatt Jacob u_int16_t *iptrp; 9589637d68cSMatt Jacob u_int16_t optr; 959d720e6d5SJustin T. Gibbs u_int error; 960d720e6d5SJustin T. Gibbs } mush_t; 961d720e6d5SJustin T. Gibbs 9624873663cSMatt Jacob #define MUSHERR_NOQENTRIES -2 9634873663cSMatt Jacob 9649e11e5beSMatt Jacob #ifdef ISP_TARGET_MODE 9659e11e5beSMatt Jacob /* 9669e11e5beSMatt Jacob * We need to handle DMA for target mode differently from initiator mode. 9679e11e5beSMatt Jacob * 9689e11e5beSMatt Jacob * DMA mapping and construction and submission of CTIO Request Entries 9699e11e5beSMatt Jacob * and rendevous for completion are very tightly coupled because we start 9709e11e5beSMatt Jacob * out by knowing (per platform) how much data we have to move, but we 9719e11e5beSMatt Jacob * don't know, up front, how many DMA mapping segments will have to be used 9729e11e5beSMatt Jacob * cover that data, so we don't know how many CTIO Request Entries we 9739e11e5beSMatt Jacob * will end up using. Further, for performance reasons we may want to 9749e11e5beSMatt Jacob * (on the last CTIO for Fibre Channel), send status too (if all went well). 9759e11e5beSMatt Jacob * 9769e11e5beSMatt Jacob * The standard vector still goes through isp_pci_dmasetup, but the callback 9779e11e5beSMatt Jacob * for the DMA mapping routines comes here instead with the whole transfer 9789e11e5beSMatt Jacob * mapped and a pointer to a partially filled in already allocated request 9799e11e5beSMatt Jacob * queue entry. We finish the job. 9809e11e5beSMatt Jacob */ 98105fbcbb0SMatt Jacob static void tdma_mk __P((void *, bus_dma_segment_t *, int, int)); 98205fbcbb0SMatt Jacob static void tdma_mkfc __P((void *, bus_dma_segment_t *, int, int)); 9839e11e5beSMatt Jacob 984d720e6d5SJustin T. Gibbs static void 98505fbcbb0SMatt Jacob tdma_mk(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 986d720e6d5SJustin T. Gibbs { 987d720e6d5SJustin T. Gibbs mush_t *mp; 9889e11e5beSMatt Jacob struct ccb_scsiio *csio; 989d720e6d5SJustin T. Gibbs struct isp_pcisoftc *pci; 990d720e6d5SJustin T. Gibbs bus_dmamap_t *dp; 99105fbcbb0SMatt Jacob u_int8_t scsi_status; 9929e11e5beSMatt Jacob ct_entry_t *cto; 99305fbcbb0SMatt Jacob u_int32_t handle, totxfr, sflags; 99405fbcbb0SMatt Jacob int nctios, send_status; 99505fbcbb0SMatt Jacob int32_t resid; 996d720e6d5SJustin T. Gibbs 997d720e6d5SJustin T. Gibbs mp = (mush_t *) arg; 998d720e6d5SJustin T. Gibbs if (error) { 999d720e6d5SJustin T. Gibbs mp->error = error; 1000d720e6d5SJustin T. Gibbs return; 1001d720e6d5SJustin T. Gibbs } 10029e11e5beSMatt Jacob csio = mp->cmd_token; 10039e11e5beSMatt Jacob cto = mp->rq; 10049e11e5beSMatt Jacob 100565b024e1SMatt Jacob cto->ct_xfrlen = 0; 100665b024e1SMatt Jacob cto->ct_seg_count = 0; 100765b024e1SMatt Jacob cto->ct_header.rqs_entry_count = 1; 100805fbcbb0SMatt Jacob MEMZERO(cto->ct_dataseg, sizeof(cto->ct_dataseg)); 100905fbcbb0SMatt Jacob 101005fbcbb0SMatt Jacob if (nseg == 0) { 101105fbcbb0SMatt Jacob cto->ct_header.rqs_seqno = 1; 101205fbcbb0SMatt Jacob ISP_TDQE(mp->isp, "tdma_mk[no data]", *mp->iptrp, cto); 1013d02373f1SMatt Jacob isp_prt(mp->isp, ISP_LOGTDEBUG1, 1014d02373f1SMatt Jacob "CTIO lun %d->iid%d flgs 0x%x sts 0x%x ssts 0x%x res %d", 101565b024e1SMatt Jacob csio->ccb_h.target_lun, cto->ct_iid, cto->ct_flags, 101665b024e1SMatt Jacob cto->ct_status, cto->ct_scsi_status, cto->ct_resid); 101705fbcbb0SMatt Jacob ISP_SWIZ_CTIO(mp->isp, cto, cto); 101865b024e1SMatt Jacob return; 101965b024e1SMatt Jacob } 102065b024e1SMatt Jacob 102165b024e1SMatt Jacob nctios = nseg / ISP_RQDSEG; 102265b024e1SMatt Jacob if (nseg % ISP_RQDSEG) { 102365b024e1SMatt Jacob nctios++; 102465b024e1SMatt Jacob } 102565b024e1SMatt Jacob 102605fbcbb0SMatt Jacob /* 102705fbcbb0SMatt Jacob * Save handle, and potentially any SCSI status, which we'll reinsert 102805fbcbb0SMatt Jacob * on the last CTIO we're going to send. 102905fbcbb0SMatt Jacob */ 103005fbcbb0SMatt Jacob handle = cto->ct_reserved; 103105fbcbb0SMatt Jacob cto->ct_reserved = 0; 103205fbcbb0SMatt Jacob cto->ct_header.rqs_seqno = 0; 103305fbcbb0SMatt Jacob send_status = (cto->ct_flags & CT_SENDSTATUS) != 0; 103405fbcbb0SMatt Jacob 103505fbcbb0SMatt Jacob if (send_status) { 103605fbcbb0SMatt Jacob sflags = cto->ct_flags & (CT_SENDSTATUS | CT_CCINCR); 103705fbcbb0SMatt Jacob cto->ct_flags &= ~(CT_SENDSTATUS | CT_CCINCR); 103805fbcbb0SMatt Jacob /* 103905fbcbb0SMatt Jacob * Preserve residual. 104005fbcbb0SMatt Jacob */ 104105fbcbb0SMatt Jacob resid = cto->ct_resid; 104205fbcbb0SMatt Jacob 104305fbcbb0SMatt Jacob /* 104405fbcbb0SMatt Jacob * Save actual SCSI status. 104505fbcbb0SMatt Jacob */ 104605fbcbb0SMatt Jacob scsi_status = cto->ct_scsi_status; 104705fbcbb0SMatt Jacob 104805fbcbb0SMatt Jacob /* 104905fbcbb0SMatt Jacob * We can't do a status at the same time as a data CTIO, so 105005fbcbb0SMatt Jacob * we need to synthesize an extra CTIO at this level. 105105fbcbb0SMatt Jacob */ 105205fbcbb0SMatt Jacob nctios++; 105305fbcbb0SMatt Jacob } else { 105405fbcbb0SMatt Jacob sflags = scsi_status = resid = 0; 105505fbcbb0SMatt Jacob } 105605fbcbb0SMatt Jacob 105705fbcbb0SMatt Jacob totxfr = cto->ct_resid = 0; 105805fbcbb0SMatt Jacob cto->ct_scsi_status = 0; 105905fbcbb0SMatt Jacob 10609e11e5beSMatt Jacob pci = (struct isp_pcisoftc *)mp->isp; 1061469b6b9eSMatt Jacob dp = &pci->dmaps[isp_handle_index(handle)]; 10629e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 1063d720e6d5SJustin T. Gibbs bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREREAD); 1064d720e6d5SJustin T. Gibbs } else { 1065d720e6d5SJustin T. Gibbs bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREWRITE); 1066d720e6d5SJustin T. Gibbs } 1067d720e6d5SJustin T. Gibbs 10689e11e5beSMatt Jacob 10699e11e5beSMatt Jacob while (nctios--) { 107005fbcbb0SMatt Jacob int seglim; 10719e11e5beSMatt Jacob 10729e11e5beSMatt Jacob seglim = nseg; 107305fbcbb0SMatt Jacob if (seglim) { 107405fbcbb0SMatt Jacob int seg; 107505fbcbb0SMatt Jacob 10769e11e5beSMatt Jacob if (seglim > ISP_RQDSEG) 10779e11e5beSMatt Jacob seglim = ISP_RQDSEG; 10789e11e5beSMatt Jacob 107905fbcbb0SMatt Jacob for (seg = 0; seg < seglim; seg++, nseg--) { 108005fbcbb0SMatt Jacob /* 108105fbcbb0SMatt Jacob * Unlike normal initiator commands, we don't 108205fbcbb0SMatt Jacob * do any swizzling here. 108305fbcbb0SMatt Jacob */ 10849e11e5beSMatt Jacob cto->ct_dataseg[seg].ds_count = dm_segs->ds_len; 108505fbcbb0SMatt Jacob cto->ct_dataseg[seg].ds_base = dm_segs->ds_addr; 10869e11e5beSMatt Jacob cto->ct_xfrlen += dm_segs->ds_len; 108705fbcbb0SMatt Jacob totxfr += dm_segs->ds_len; 10889e11e5beSMatt Jacob dm_segs++; 10899e11e5beSMatt Jacob } 10909e11e5beSMatt Jacob cto->ct_seg_count = seg; 10919e11e5beSMatt Jacob } else { 109205fbcbb0SMatt Jacob /* 109305fbcbb0SMatt Jacob * This case should only happen when we're sending an 109405fbcbb0SMatt Jacob * extra CTIO with final status. 109505fbcbb0SMatt Jacob */ 109605fbcbb0SMatt Jacob if (send_status == 0) { 1097f7dddf8aSMatt Jacob isp_prt(mp->isp, ISP_LOGWARN, 1098f7dddf8aSMatt Jacob "tdma_mk ran out of segments"); 109905fbcbb0SMatt Jacob mp->error = EINVAL; 110005fbcbb0SMatt Jacob return; 11019e11e5beSMatt Jacob } 110205fbcbb0SMatt Jacob } 110305fbcbb0SMatt Jacob 110405fbcbb0SMatt Jacob /* 110505fbcbb0SMatt Jacob * At this point, the fields ct_lun, ct_iid, ct_tagval, 110605fbcbb0SMatt Jacob * ct_tagtype, and ct_timeout have been carried over 110705fbcbb0SMatt Jacob * unchanged from what our caller had set. 110805fbcbb0SMatt Jacob * 110905fbcbb0SMatt Jacob * The dataseg fields and the seg_count fields we just got 111005fbcbb0SMatt Jacob * through setting. The data direction we've preserved all 111105fbcbb0SMatt Jacob * along and only clear it if we're now sending status. 111205fbcbb0SMatt Jacob */ 11139e11e5beSMatt Jacob 11149e11e5beSMatt Jacob if (nctios == 0) { 11159e11e5beSMatt Jacob /* 111605fbcbb0SMatt Jacob * We're the last in a sequence of CTIOs, so mark 111705fbcbb0SMatt Jacob * this CTIO and save the handle to the CCB such that 111805fbcbb0SMatt Jacob * when this CTIO completes we can free dma resources 111905fbcbb0SMatt Jacob * and do whatever else we need to do to finish the 112005fbcbb0SMatt Jacob * rest of the command. 11219e11e5beSMatt Jacob */ 11229e11e5beSMatt Jacob cto->ct_reserved = handle; 112305fbcbb0SMatt Jacob cto->ct_header.rqs_seqno = 1; 112405fbcbb0SMatt Jacob 112505fbcbb0SMatt Jacob if (send_status) { 11269e11e5beSMatt Jacob cto->ct_scsi_status = scsi_status; 112705fbcbb0SMatt Jacob cto->ct_flags |= sflags | CT_NO_DATA;; 112805fbcbb0SMatt Jacob cto->ct_resid = resid; 112942426921SMatt Jacob } 1130d02373f1SMatt Jacob if (send_status) { 1131d02373f1SMatt Jacob isp_prt(mp->isp, ISP_LOGTDEBUG1, 1132d02373f1SMatt Jacob "CTIO lun%d for ID %d ct_flags 0x%x scsi " 1133d02373f1SMatt Jacob "status %x resid %d", 1134d02373f1SMatt Jacob csio->ccb_h.target_lun, 113505fbcbb0SMatt Jacob cto->ct_iid, cto->ct_flags, 113605fbcbb0SMatt Jacob cto->ct_scsi_status, cto->ct_resid); 1137d02373f1SMatt Jacob } else { 1138d02373f1SMatt Jacob isp_prt(mp->isp, ISP_LOGTDEBUG1, 1139d02373f1SMatt Jacob "CTIO lun%d for ID%d ct_flags 0x%x", 1140d02373f1SMatt Jacob csio->ccb_h.target_lun, 114105fbcbb0SMatt Jacob cto->ct_iid, cto->ct_flags); 114205fbcbb0SMatt Jacob } 114305fbcbb0SMatt Jacob ISP_TDQE(mp->isp, "last tdma_mk", *mp->iptrp, cto); 114405fbcbb0SMatt Jacob ISP_SWIZ_CTIO(mp->isp, cto, cto); 11459e11e5beSMatt Jacob } else { 11469e11e5beSMatt Jacob ct_entry_t *octo = cto; 114705fbcbb0SMatt Jacob 114805fbcbb0SMatt Jacob /* 114905fbcbb0SMatt Jacob * Make sure handle fields are clean 115005fbcbb0SMatt Jacob */ 11519e11e5beSMatt Jacob cto->ct_reserved = 0; 11529e11e5beSMatt Jacob cto->ct_header.rqs_seqno = 0; 115305fbcbb0SMatt Jacob 1154d02373f1SMatt Jacob isp_prt(mp->isp, ISP_LOGTDEBUG1, 1155d02373f1SMatt Jacob "CTIO lun%d for ID%d ct_flags 0x%x", 1156d02373f1SMatt Jacob csio->ccb_h.target_lun, cto->ct_iid, cto->ct_flags); 115705fbcbb0SMatt Jacob ISP_TDQE(mp->isp, "tdma_mk", *mp->iptrp, cto); 115805fbcbb0SMatt Jacob 115905fbcbb0SMatt Jacob /* 116005fbcbb0SMatt Jacob * Get a new CTIO 116105fbcbb0SMatt Jacob */ 11629e11e5beSMatt Jacob cto = (ct_entry_t *) 11639e11e5beSMatt Jacob ISP_QUEUE_ENTRY(mp->isp->isp_rquest, *mp->iptrp); 11649e11e5beSMatt Jacob *mp->iptrp = 1165d02373f1SMatt Jacob ISP_NXT_QENTRY(*mp->iptrp, RQUEST_QUEUE_LEN(isp)); 11669e11e5beSMatt Jacob if (*mp->iptrp == mp->optr) { 1167f7dddf8aSMatt Jacob isp_prt(mp->isp, ISP_LOGWARN, 1168f7dddf8aSMatt Jacob "Queue Overflow in tdma_mk"); 11699e11e5beSMatt Jacob mp->error = MUSHERR_NOQENTRIES; 11709e11e5beSMatt Jacob return; 11719e11e5beSMatt Jacob } 11729e11e5beSMatt Jacob /* 11739e11e5beSMatt Jacob * Fill in the new CTIO with info from the old one. 11749e11e5beSMatt Jacob */ 11759e11e5beSMatt Jacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO; 11769e11e5beSMatt Jacob cto->ct_header.rqs_entry_count = 1; 11779e11e5beSMatt Jacob cto->ct_header.rqs_flags = 0; 11789e11e5beSMatt Jacob cto->ct_lun = octo->ct_lun; 11799e11e5beSMatt Jacob cto->ct_iid = octo->ct_iid; 11809e11e5beSMatt Jacob cto->ct_reserved2 = octo->ct_reserved2; 11819e11e5beSMatt Jacob cto->ct_tgt = octo->ct_tgt; 118205fbcbb0SMatt Jacob cto->ct_flags = octo->ct_flags; 11839e11e5beSMatt Jacob cto->ct_status = 0; 11849e11e5beSMatt Jacob cto->ct_scsi_status = 0; 11859e11e5beSMatt Jacob cto->ct_tag_val = octo->ct_tag_val; 11869e11e5beSMatt Jacob cto->ct_tag_type = octo->ct_tag_type; 11879e11e5beSMatt Jacob cto->ct_xfrlen = 0; 11889e11e5beSMatt Jacob cto->ct_resid = 0; 11899e11e5beSMatt Jacob cto->ct_timeout = octo->ct_timeout; 11909e11e5beSMatt Jacob cto->ct_seg_count = 0; 119105fbcbb0SMatt Jacob MEMZERO(cto->ct_dataseg, sizeof(cto->ct_dataseg)); 119205fbcbb0SMatt Jacob /* 119305fbcbb0SMatt Jacob * Now swizzle the old one for the consumption of the 119405fbcbb0SMatt Jacob * chip. 119505fbcbb0SMatt Jacob */ 119605fbcbb0SMatt Jacob ISP_SWIZ_CTIO(mp->isp, octo, octo); 11979e11e5beSMatt Jacob } 11989e11e5beSMatt Jacob } 11999e11e5beSMatt Jacob } 12009e11e5beSMatt Jacob 12019e11e5beSMatt Jacob static void 120205fbcbb0SMatt Jacob tdma_mkfc(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 12039e11e5beSMatt Jacob { 12049e11e5beSMatt Jacob mush_t *mp; 12059e11e5beSMatt Jacob struct ccb_scsiio *csio; 12069e11e5beSMatt Jacob struct isp_pcisoftc *pci; 12079e11e5beSMatt Jacob bus_dmamap_t *dp; 12089e11e5beSMatt Jacob ct2_entry_t *cto; 120965b024e1SMatt Jacob u_int16_t scsi_status, send_status, send_sense; 121005fbcbb0SMatt Jacob u_int32_t handle, totxfr, datalen; 121165b024e1SMatt Jacob u_int8_t sense[QLTM_SENSELEN]; 12129e11e5beSMatt Jacob int nctios; 12139e11e5beSMatt Jacob 12149e11e5beSMatt Jacob mp = (mush_t *) arg; 12159e11e5beSMatt Jacob if (error) { 12169e11e5beSMatt Jacob mp->error = error; 12179e11e5beSMatt Jacob return; 12189e11e5beSMatt Jacob } 12199e11e5beSMatt Jacob 122065b024e1SMatt Jacob csio = mp->cmd_token; 122165b024e1SMatt Jacob cto = mp->rq; 122265b024e1SMatt Jacob 122365b024e1SMatt Jacob if (nseg == 0) { 122465b024e1SMatt Jacob if ((cto->ct_flags & CT2_FLAG_MMASK) != CT2_FLAG_MODE1) { 1225f7dddf8aSMatt Jacob isp_prt(mp->isp, ISP_LOGWARN, 1226f7dddf8aSMatt Jacob "dma2_tgt_fc, a status CTIO2 without MODE1 " 1227f7dddf8aSMatt Jacob "set (0x%x)", cto->ct_flags); 122865b024e1SMatt Jacob mp->error = EINVAL; 122965b024e1SMatt Jacob return; 123065b024e1SMatt Jacob } 123165b024e1SMatt Jacob cto->ct_header.rqs_entry_count = 1; 123205fbcbb0SMatt Jacob cto->ct_header.rqs_seqno = 1; 123365b024e1SMatt Jacob /* ct_reserved contains the handle set by caller */ 123465b024e1SMatt Jacob /* 123565b024e1SMatt Jacob * We preserve ct_lun, ct_iid, ct_rxid. We set the data 123665b024e1SMatt Jacob * flags to NO DATA and clear relative offset flags. 123765b024e1SMatt Jacob * We preserve the ct_resid and the response area. 123865b024e1SMatt Jacob */ 123965b024e1SMatt Jacob cto->ct_flags |= CT2_NO_DATA; 124005fbcbb0SMatt Jacob if (cto->ct_resid > 0) 124105fbcbb0SMatt Jacob cto->ct_flags |= CT2_DATA_UNDER; 124205fbcbb0SMatt Jacob else if (cto->ct_resid < 0) 124305fbcbb0SMatt Jacob cto->ct_flags |= CT2_DATA_OVER; 124465b024e1SMatt Jacob cto->ct_seg_count = 0; 124565b024e1SMatt Jacob cto->ct_reloff = 0; 124665b024e1SMatt Jacob ISP_TDQE(mp->isp, "dma2_tgt_fc[no data]", *mp->iptrp, cto); 1247d02373f1SMatt Jacob isp_prt(mp->isp, ISP_LOGTDEBUG1, 1248d02373f1SMatt Jacob "CTIO2 RX_ID 0x%x lun %d->iid%d flgs 0x%x sts 0x%x ssts " 1249d02373f1SMatt Jacob "0x%x res %d", cto->ct_rxid, csio->ccb_h.target_lun, 1250d02373f1SMatt Jacob cto->ct_iid, cto->ct_flags, cto->ct_status, 125165b024e1SMatt Jacob cto->rsp.m1.ct_scsi_status, cto->ct_resid); 125265b024e1SMatt Jacob ISP_SWIZ_CTIO2(isp, cto, cto); 12539e11e5beSMatt Jacob return; 12549e11e5beSMatt Jacob } 12559e11e5beSMatt Jacob 125665b024e1SMatt Jacob if ((cto->ct_flags & CT2_FLAG_MMASK) != CT2_FLAG_MODE0) { 1257f7dddf8aSMatt Jacob isp_prt(mp->isp, ISP_LOGWARN, 1258f7dddf8aSMatt Jacob "dma2_tgt_fc, a data CTIO2 without MODE0 set " 1259f7dddf8aSMatt Jacob "(0x%x)", cto->ct_flags); 126065b024e1SMatt Jacob mp->error = EINVAL; 126165b024e1SMatt Jacob return; 126265b024e1SMatt Jacob } 126365b024e1SMatt Jacob 126465b024e1SMatt Jacob 126565b024e1SMatt Jacob nctios = nseg / ISP_RQDSEG_T2; 126665b024e1SMatt Jacob if (nseg % ISP_RQDSEG_T2) { 126765b024e1SMatt Jacob nctios++; 126865b024e1SMatt Jacob } 126965b024e1SMatt Jacob 12709e11e5beSMatt Jacob /* 127165b024e1SMatt Jacob * Save the handle, status, reloff, and residual. We'll reinsert the 127265b024e1SMatt Jacob * handle into the last CTIO2 we're going to send, and reinsert status 127365b024e1SMatt Jacob * and residual (and possibly sense data) if that's to be sent as well. 127465b024e1SMatt Jacob * 127565b024e1SMatt Jacob * We preserve ct_reloff and adjust it for each data CTIO2 we send past 127665b024e1SMatt Jacob * the first one. This is needed so that the FCP DATA IUs being sent 127765b024e1SMatt Jacob * out have the correct offset (they can arrive at the other end out 127865b024e1SMatt Jacob * of order). 12799e11e5beSMatt Jacob */ 128065b024e1SMatt Jacob 12819e11e5beSMatt Jacob handle = cto->ct_reserved; 12829e11e5beSMatt Jacob cto->ct_reserved = 0; 128365b024e1SMatt Jacob 128465b024e1SMatt Jacob if ((send_status = (cto->ct_flags & CT2_SENDSTATUS)) != 0) { 12859e11e5beSMatt Jacob cto->ct_flags &= ~CT2_SENDSTATUS; 12869e11e5beSMatt Jacob 128765b024e1SMatt Jacob /* 128805fbcbb0SMatt Jacob * Preserve residual, which is actually the total count. 128965b024e1SMatt Jacob */ 129005fbcbb0SMatt Jacob datalen = cto->ct_resid; 129165b024e1SMatt Jacob 129265b024e1SMatt Jacob /* 129365b024e1SMatt Jacob * Save actual SCSI status. We'll reinsert the 129465b024e1SMatt Jacob * CT2_SNSLEN_VALID later if appropriate. 129565b024e1SMatt Jacob */ 129665b024e1SMatt Jacob scsi_status = cto->rsp.m0.ct_scsi_status & 0xff; 129765b024e1SMatt Jacob send_sense = cto->rsp.m0.ct_scsi_status & CT2_SNSLEN_VALID; 129865b024e1SMatt Jacob 129965b024e1SMatt Jacob /* 130065b024e1SMatt Jacob * If we're sending status and have a CHECK CONDTION and 130165b024e1SMatt Jacob * have sense data, we send one more CTIO2 with just the 130265b024e1SMatt Jacob * status and sense data. The upper layers have stashed 130365b024e1SMatt Jacob * the sense data in the dataseg structure for us. 130465b024e1SMatt Jacob */ 130565b024e1SMatt Jacob 130665b024e1SMatt Jacob if ((scsi_status & 0xf) == SCSI_STATUS_CHECK_COND && 130765b024e1SMatt Jacob send_sense) { 130865b024e1SMatt Jacob bcopy(cto->rsp.m0.ct_dataseg, sense, QLTM_SENSELEN); 130965b024e1SMatt Jacob nctios++; 131065b024e1SMatt Jacob } 131165b024e1SMatt Jacob } else { 131205fbcbb0SMatt Jacob scsi_status = send_sense = datalen = 0; 131365b024e1SMatt Jacob } 131465b024e1SMatt Jacob 131565b024e1SMatt Jacob totxfr = cto->ct_resid = 0; 131665b024e1SMatt Jacob cto->rsp.m0.ct_scsi_status = 0; 131765b024e1SMatt Jacob bzero(&cto->rsp, sizeof (cto->rsp)); 131865b024e1SMatt Jacob 13199e11e5beSMatt Jacob pci = (struct isp_pcisoftc *)mp->isp; 1320469b6b9eSMatt Jacob dp = &pci->dmaps[isp_handle_index(handle)]; 13219e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 13229e11e5beSMatt Jacob bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREREAD); 13239e11e5beSMatt Jacob } else { 13249e11e5beSMatt Jacob bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREWRITE); 13259e11e5beSMatt Jacob } 13269e11e5beSMatt Jacob 13279e11e5beSMatt Jacob while (nctios--) { 13289e11e5beSMatt Jacob int seg, seglim; 13299e11e5beSMatt Jacob 13309e11e5beSMatt Jacob seglim = nseg; 133165b024e1SMatt Jacob if (seglim) { 13329e11e5beSMatt Jacob if (seglim > ISP_RQDSEG_T2) 13339e11e5beSMatt Jacob seglim = ISP_RQDSEG_T2; 13349e11e5beSMatt Jacob 13359e11e5beSMatt Jacob for (seg = 0; seg < seglim; seg++) { 133665b024e1SMatt Jacob cto->rsp.m0.ct_dataseg[seg].ds_base = 133765b024e1SMatt Jacob dm_segs->ds_addr; 133865b024e1SMatt Jacob cto->rsp.m0.ct_dataseg[seg].ds_count = 133965b024e1SMatt Jacob dm_segs->ds_len; 13409e11e5beSMatt Jacob cto->rsp.m0.ct_xfrlen += dm_segs->ds_len; 134165b024e1SMatt Jacob totxfr += dm_segs->ds_len; 13429e11e5beSMatt Jacob dm_segs++; 13439e11e5beSMatt Jacob } 13449e11e5beSMatt Jacob cto->ct_seg_count = seg; 13459e11e5beSMatt Jacob } else { 134665b024e1SMatt Jacob /* 134765b024e1SMatt Jacob * This case should only happen when we're sending a 134865b024e1SMatt Jacob * synthesized MODE1 final status with sense data. 134965b024e1SMatt Jacob */ 135065b024e1SMatt Jacob if (send_sense == 0) { 1351f7dddf8aSMatt Jacob isp_prt(mp->isp, ISP_LOGWARN, 1352f7dddf8aSMatt Jacob "dma2_tgt_fc ran out of segments, " 1353f7dddf8aSMatt Jacob "no SENSE DATA"); 135465b024e1SMatt Jacob mp->error = EINVAL; 135565b024e1SMatt Jacob return; 135665b024e1SMatt Jacob } 13579e11e5beSMatt Jacob } 13589e11e5beSMatt Jacob 13599e11e5beSMatt Jacob /* 136065b024e1SMatt Jacob * At this point, the fields ct_lun, ct_iid, ct_rxid, 136165b024e1SMatt Jacob * ct_timeout have been carried over unchanged from what 136265b024e1SMatt Jacob * our caller had set. 136365b024e1SMatt Jacob * 136465b024e1SMatt Jacob * The field ct_reloff is either what the caller set, or 136565b024e1SMatt Jacob * what we've added to below. 136665b024e1SMatt Jacob * 136765b024e1SMatt Jacob * The dataseg fields and the seg_count fields we just got 136865b024e1SMatt Jacob * through setting. The data direction we've preserved all 136965b024e1SMatt Jacob * along and only clear it if we're sending a MODE1 status 137065b024e1SMatt Jacob * as the last CTIO. 137165b024e1SMatt Jacob * 137265b024e1SMatt Jacob */ 137365b024e1SMatt Jacob 137465b024e1SMatt Jacob if (nctios == 0) { 137565b024e1SMatt Jacob 137665b024e1SMatt Jacob /* 137765b024e1SMatt Jacob * We're the last in a sequence of CTIO2s, so mark this 137865b024e1SMatt Jacob * CTIO2 and save the handle to the CCB such that when 137965b024e1SMatt Jacob * this CTIO2 completes we can free dma resources and 13809e11e5beSMatt Jacob * do whatever else we need to do to finish the rest 13819e11e5beSMatt Jacob * of the command. 13829e11e5beSMatt Jacob */ 138365b024e1SMatt Jacob 13849e11e5beSMatt Jacob cto->ct_reserved = handle; 138565b024e1SMatt Jacob cto->ct_header.rqs_seqno = 1; 138665b024e1SMatt Jacob 138765b024e1SMatt Jacob if (send_status) { 138865b024e1SMatt Jacob if (send_sense) { 138965b024e1SMatt Jacob bcopy(sense, cto->rsp.m1.ct_resp, 139065b024e1SMatt Jacob QLTM_SENSELEN); 139165b024e1SMatt Jacob cto->rsp.m1.ct_senselen = 139265b024e1SMatt Jacob QLTM_SENSELEN; 139365b024e1SMatt Jacob scsi_status |= CT2_SNSLEN_VALID; 139465b024e1SMatt Jacob cto->rsp.m1.ct_scsi_status = 139565b024e1SMatt Jacob scsi_status; 139665b024e1SMatt Jacob cto->ct_flags &= CT2_FLAG_MMASK; 139765b024e1SMatt Jacob cto->ct_flags |= CT2_FLAG_MODE1 | 139865b024e1SMatt Jacob CT2_NO_DATA| CT2_SENDSTATUS; 139965b024e1SMatt Jacob } else { 140065b024e1SMatt Jacob cto->rsp.m0.ct_scsi_status = 140165b024e1SMatt Jacob scsi_status; 140265b024e1SMatt Jacob cto->ct_flags |= CT2_SENDSTATUS; 140365b024e1SMatt Jacob } 140405fbcbb0SMatt Jacob /* 140505fbcbb0SMatt Jacob * Get 'real' residual and set flags based 140605fbcbb0SMatt Jacob * on it. 140705fbcbb0SMatt Jacob */ 140805fbcbb0SMatt Jacob cto->ct_resid = datalen - totxfr; 140905fbcbb0SMatt Jacob if (cto->ct_resid > 0) 141005fbcbb0SMatt Jacob cto->ct_flags |= CT2_DATA_UNDER; 141105fbcbb0SMatt Jacob else if (cto->ct_resid < 0) 141205fbcbb0SMatt Jacob cto->ct_flags |= CT2_DATA_OVER; 141365b024e1SMatt Jacob } 14149e11e5beSMatt Jacob ISP_TDQE(mp->isp, "last dma2_tgt_fc", *mp->iptrp, cto); 1415d02373f1SMatt Jacob isp_prt(mp->isp, ISP_LOGTDEBUG1, 1416d02373f1SMatt Jacob "CTIO2 RX_ID 0x%x lun %d->iid%d flgs 0x%x sts 0x%x" 1417d02373f1SMatt Jacob " ssts 0x%x res %d", cto->ct_rxid, 141865b024e1SMatt Jacob csio->ccb_h.target_lun, (int) cto->ct_iid, 141942426921SMatt Jacob cto->ct_flags, cto->ct_status, 142065b024e1SMatt Jacob cto->rsp.m1.ct_scsi_status, cto->ct_resid); 142165b024e1SMatt Jacob ISP_SWIZ_CTIO2(isp, cto, cto); 14229e11e5beSMatt Jacob } else { 14239e11e5beSMatt Jacob ct2_entry_t *octo = cto; 142465b024e1SMatt Jacob 142565b024e1SMatt Jacob /* 142665b024e1SMatt Jacob * Make sure handle fields are clean 142765b024e1SMatt Jacob */ 14289e11e5beSMatt Jacob cto->ct_reserved = 0; 14299e11e5beSMatt Jacob cto->ct_header.rqs_seqno = 0; 143065b024e1SMatt Jacob 14319e11e5beSMatt Jacob ISP_TDQE(mp->isp, "dma2_tgt_fc", *mp->iptrp, cto); 1432d02373f1SMatt Jacob isp_prt(mp->isp, ISP_LOGTDEBUG1, 1433d02373f1SMatt Jacob "CTIO2 RX_ID 0x%x lun %d->iid%d flgs 0x%x", 1434d02373f1SMatt Jacob cto->ct_rxid, csio->ccb_h.target_lun, 1435d02373f1SMatt Jacob (int) cto->ct_iid, cto->ct_flags); 143665b024e1SMatt Jacob /* 143765b024e1SMatt Jacob * Get a new CTIO2 143865b024e1SMatt Jacob */ 14399e11e5beSMatt Jacob cto = (ct2_entry_t *) 14409e11e5beSMatt Jacob ISP_QUEUE_ENTRY(mp->isp->isp_rquest, *mp->iptrp); 14419e11e5beSMatt Jacob *mp->iptrp = 1442d02373f1SMatt Jacob ISP_NXT_QENTRY(*mp->iptrp, RQUEST_QUEUE_LEN(isp)); 14439e11e5beSMatt Jacob if (*mp->iptrp == mp->optr) { 1444f7dddf8aSMatt Jacob isp_prt(mp->isp, ISP_LOGWARN, 1445f7dddf8aSMatt Jacob "Queue Overflow in dma2_tgt_fc"); 14469e11e5beSMatt Jacob mp->error = MUSHERR_NOQENTRIES; 14479e11e5beSMatt Jacob return; 14489e11e5beSMatt Jacob } 144965b024e1SMatt Jacob 14509e11e5beSMatt Jacob /* 145165b024e1SMatt Jacob * Fill in the new CTIO2 with info from the old one. 14529e11e5beSMatt Jacob */ 14539e11e5beSMatt Jacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2; 14549e11e5beSMatt Jacob cto->ct_header.rqs_entry_count = 1; 14559e11e5beSMatt Jacob cto->ct_header.rqs_flags = 0; 145665b024e1SMatt Jacob /* ct_header.rqs_seqno && ct_reserved done later */ 14579e11e5beSMatt Jacob cto->ct_lun = octo->ct_lun; 14589e11e5beSMatt Jacob cto->ct_iid = octo->ct_iid; 14599e11e5beSMatt Jacob cto->ct_rxid = octo->ct_rxid; 146065b024e1SMatt Jacob cto->ct_flags = octo->ct_flags; 14619e11e5beSMatt Jacob cto->ct_status = 0; 14629e11e5beSMatt Jacob cto->ct_resid = 0; 14639e11e5beSMatt Jacob cto->ct_timeout = octo->ct_timeout; 14649e11e5beSMatt Jacob cto->ct_seg_count = 0; 146565b024e1SMatt Jacob /* 146665b024e1SMatt Jacob * Adjust the new relative offset by the amount which 146765b024e1SMatt Jacob * is recorded in the data segment of the old CTIO2 we 146865b024e1SMatt Jacob * just finished filling out. 146965b024e1SMatt Jacob */ 147065b024e1SMatt Jacob cto->ct_reloff += octo->rsp.m0.ct_xfrlen; 14719e11e5beSMatt Jacob bzero(&cto->rsp, sizeof (cto->rsp)); 147265b024e1SMatt Jacob ISP_SWIZ_CTIO2(isp, cto, cto); 14739e11e5beSMatt Jacob } 14749e11e5beSMatt Jacob } 14759e11e5beSMatt Jacob } 14769e11e5beSMatt Jacob #endif 14779e11e5beSMatt Jacob 14789e11e5beSMatt Jacob static void dma2 __P((void *, bus_dma_segment_t *, int, int)); 14799e11e5beSMatt Jacob 14809e11e5beSMatt Jacob static void 14819e11e5beSMatt Jacob dma2(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 14829e11e5beSMatt Jacob { 14839e11e5beSMatt Jacob mush_t *mp; 14849e11e5beSMatt Jacob struct ccb_scsiio *csio; 14859e11e5beSMatt Jacob struct isp_pcisoftc *pci; 14869e11e5beSMatt Jacob bus_dmamap_t *dp; 14879e11e5beSMatt Jacob bus_dma_segment_t *eseg; 14889e11e5beSMatt Jacob ispreq_t *rq; 14899e11e5beSMatt Jacob ispcontreq_t *crq; 14909e11e5beSMatt Jacob int seglim, datalen; 14919e11e5beSMatt Jacob 14929e11e5beSMatt Jacob mp = (mush_t *) arg; 14939e11e5beSMatt Jacob if (error) { 14949e11e5beSMatt Jacob mp->error = error; 14959e11e5beSMatt Jacob return; 14969e11e5beSMatt Jacob } 14979e11e5beSMatt Jacob 14989e11e5beSMatt Jacob if (nseg < 1) { 1499f7dddf8aSMatt Jacob isp_prt(mp->isp, ISP_LOGERR, "bad segment count (%d)", nseg); 15009e11e5beSMatt Jacob mp->error = EFAULT; 15019e11e5beSMatt Jacob return; 15029e11e5beSMatt Jacob } 15039e11e5beSMatt Jacob csio = mp->cmd_token; 15049e11e5beSMatt Jacob rq = mp->rq; 15059e11e5beSMatt Jacob pci = (struct isp_pcisoftc *)mp->isp; 1506469b6b9eSMatt Jacob dp = &pci->dmaps[isp_handle_index(rq->req_handle)]; 15079e11e5beSMatt Jacob 15089e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 15099e11e5beSMatt Jacob bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREREAD); 15109e11e5beSMatt Jacob } else { 15119e11e5beSMatt Jacob bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREWRITE); 15129e11e5beSMatt Jacob } 15139e11e5beSMatt Jacob 15149e11e5beSMatt Jacob datalen = XS_XFRLEN(csio); 15159e11e5beSMatt Jacob 15169e11e5beSMatt Jacob /* 15179e11e5beSMatt Jacob * We're passed an initial partially filled in entry that 15189e11e5beSMatt Jacob * has most fields filled in except for data transfer 15199e11e5beSMatt Jacob * related values. 15209e11e5beSMatt Jacob * 15219e11e5beSMatt Jacob * Our job is to fill in the initial request queue entry and 15229e11e5beSMatt Jacob * then to start allocating and filling in continuation entries 15239e11e5beSMatt Jacob * until we've covered the entire transfer. 15249e11e5beSMatt Jacob */ 15259e11e5beSMatt Jacob 15269e11e5beSMatt Jacob if (IS_FC(mp->isp)) { 1527d720e6d5SJustin T. Gibbs seglim = ISP_RQDSEG_T2; 1528d720e6d5SJustin T. Gibbs ((ispreqt2_t *)rq)->req_totalcnt = datalen; 15299e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 15309e11e5beSMatt Jacob ((ispreqt2_t *)rq)->req_flags |= REQFLAG_DATA_IN; 15319e11e5beSMatt Jacob } else { 15329e11e5beSMatt Jacob ((ispreqt2_t *)rq)->req_flags |= REQFLAG_DATA_OUT; 15339e11e5beSMatt Jacob } 1534d720e6d5SJustin T. Gibbs } else { 1535e142669aSMatt Jacob if (csio->cdb_len > 12) { 1536e142669aSMatt Jacob seglim = 0; 1537e142669aSMatt Jacob } else { 1538d720e6d5SJustin T. Gibbs seglim = ISP_RQDSEG; 1539e142669aSMatt Jacob } 15409e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 15419e11e5beSMatt Jacob rq->req_flags |= REQFLAG_DATA_IN; 15429e11e5beSMatt Jacob } else { 15439e11e5beSMatt Jacob rq->req_flags |= REQFLAG_DATA_OUT; 15449e11e5beSMatt Jacob } 1545d720e6d5SJustin T. Gibbs } 1546d720e6d5SJustin T. Gibbs 1547d720e6d5SJustin T. Gibbs eseg = dm_segs + nseg; 1548d720e6d5SJustin T. Gibbs 1549d720e6d5SJustin T. Gibbs while (datalen != 0 && rq->req_seg_count < seglim && dm_segs != eseg) { 15509e11e5beSMatt Jacob if (IS_FC(mp->isp)) { 1551d720e6d5SJustin T. Gibbs ispreqt2_t *rq2 = (ispreqt2_t *)rq; 1552d720e6d5SJustin T. Gibbs rq2->req_dataseg[rq2->req_seg_count].ds_base = 1553d720e6d5SJustin T. Gibbs dm_segs->ds_addr; 1554d720e6d5SJustin T. Gibbs rq2->req_dataseg[rq2->req_seg_count].ds_count = 1555d720e6d5SJustin T. Gibbs dm_segs->ds_len; 1556d720e6d5SJustin T. Gibbs } else { 1557d720e6d5SJustin T. Gibbs rq->req_dataseg[rq->req_seg_count].ds_base = 1558d720e6d5SJustin T. Gibbs dm_segs->ds_addr; 1559d720e6d5SJustin T. Gibbs rq->req_dataseg[rq->req_seg_count].ds_count = 1560d720e6d5SJustin T. Gibbs dm_segs->ds_len; 1561d720e6d5SJustin T. Gibbs } 1562d720e6d5SJustin T. Gibbs datalen -= dm_segs->ds_len; 1563d720e6d5SJustin T. Gibbs #if 0 15649e11e5beSMatt Jacob if (IS_FC(mp->isp)) { 1565d720e6d5SJustin T. Gibbs ispreqt2_t *rq2 = (ispreqt2_t *)rq; 1566d720e6d5SJustin T. Gibbs printf("%s: seg0[%d] cnt 0x%x paddr 0x%08x\n", 15679e11e5beSMatt Jacob mp->isp->isp_name, rq->req_seg_count, 1568d720e6d5SJustin T. Gibbs rq2->req_dataseg[rq2->req_seg_count].ds_count, 1569d720e6d5SJustin T. Gibbs rq2->req_dataseg[rq2->req_seg_count].ds_base); 1570d720e6d5SJustin T. Gibbs } else { 1571d720e6d5SJustin T. Gibbs printf("%s: seg0[%d] cnt 0x%x paddr 0x%08x\n", 15729e11e5beSMatt Jacob mp->isp->isp_name, rq->req_seg_count, 1573d720e6d5SJustin T. Gibbs rq->req_dataseg[rq->req_seg_count].ds_count, 1574d720e6d5SJustin T. Gibbs rq->req_dataseg[rq->req_seg_count].ds_base); 1575d720e6d5SJustin T. Gibbs } 1576d720e6d5SJustin T. Gibbs #endif 1577d720e6d5SJustin T. Gibbs rq->req_seg_count++; 1578d720e6d5SJustin T. Gibbs dm_segs++; 1579d720e6d5SJustin T. Gibbs } 1580d720e6d5SJustin T. Gibbs 1581d720e6d5SJustin T. Gibbs while (datalen > 0 && dm_segs != eseg) { 15829e11e5beSMatt Jacob crq = (ispcontreq_t *) 15839e11e5beSMatt Jacob ISP_QUEUE_ENTRY(mp->isp->isp_rquest, *mp->iptrp); 1584d02373f1SMatt Jacob *mp->iptrp = ISP_NXT_QENTRY(*mp->iptrp, RQUEST_QUEUE_LEN(isp)); 15859e11e5beSMatt Jacob if (*mp->iptrp == mp->optr) { 15864873663cSMatt Jacob #if 0 15879e11e5beSMatt Jacob printf("%s: Request Queue Overflow++\n", 15889e11e5beSMatt Jacob mp->isp->isp_name); 15894873663cSMatt Jacob #endif 15904873663cSMatt Jacob mp->error = MUSHERR_NOQENTRIES; 1591d720e6d5SJustin T. Gibbs return; 1592d720e6d5SJustin T. Gibbs } 1593d720e6d5SJustin T. Gibbs rq->req_header.rqs_entry_count++; 1594d720e6d5SJustin T. Gibbs bzero((void *)crq, sizeof (*crq)); 1595d720e6d5SJustin T. Gibbs crq->req_header.rqs_entry_count = 1; 1596d720e6d5SJustin T. Gibbs crq->req_header.rqs_entry_type = RQSTYPE_DATASEG; 1597d720e6d5SJustin T. Gibbs 1598d720e6d5SJustin T. Gibbs seglim = 0; 1599d720e6d5SJustin T. Gibbs while (datalen > 0 && seglim < ISP_CDSEG && dm_segs != eseg) { 1600d720e6d5SJustin T. Gibbs crq->req_dataseg[seglim].ds_base = 1601d720e6d5SJustin T. Gibbs dm_segs->ds_addr; 1602d720e6d5SJustin T. Gibbs crq->req_dataseg[seglim].ds_count = 1603d720e6d5SJustin T. Gibbs dm_segs->ds_len; 1604d720e6d5SJustin T. Gibbs #if 0 1605d720e6d5SJustin T. Gibbs printf("%s: seg%d[%d] cnt 0x%x paddr 0x%08x\n", 16069e11e5beSMatt Jacob mp->isp->isp_name, rq->req_header.rqs_entry_count-1, 1607d720e6d5SJustin T. Gibbs seglim, crq->req_dataseg[seglim].ds_count, 1608d720e6d5SJustin T. Gibbs crq->req_dataseg[seglim].ds_base); 1609d720e6d5SJustin T. Gibbs #endif 1610d720e6d5SJustin T. Gibbs rq->req_seg_count++; 1611d720e6d5SJustin T. Gibbs dm_segs++; 1612d720e6d5SJustin T. Gibbs seglim++; 1613d720e6d5SJustin T. Gibbs datalen -= dm_segs->ds_len; 1614d720e6d5SJustin T. Gibbs } 1615d720e6d5SJustin T. Gibbs } 1616d720e6d5SJustin T. Gibbs } 1617d720e6d5SJustin T. Gibbs 1618d720e6d5SJustin T. Gibbs static int 16199e11e5beSMatt Jacob isp_pci_dmasetup(struct ispsoftc *isp, struct ccb_scsiio *csio, ispreq_t *rq, 16209637d68cSMatt Jacob u_int16_t *iptrp, u_int16_t optr) 1621d720e6d5SJustin T. Gibbs { 1622d720e6d5SJustin T. Gibbs struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp; 16230a5f7e8bSMatt Jacob bus_dmamap_t *dp = NULL; 1624d720e6d5SJustin T. Gibbs mush_t mush, *mp; 16259e11e5beSMatt Jacob void (*eptr) __P((void *, bus_dma_segment_t *, int, int)); 1626d720e6d5SJustin T. Gibbs 162765b024e1SMatt Jacob #ifdef ISP_TARGET_MODE 162865b024e1SMatt Jacob if (csio->ccb_h.func_code == XPT_CONT_TARGET_IO) { 162965b024e1SMatt Jacob if (IS_FC(isp)) { 163005fbcbb0SMatt Jacob eptr = tdma_mkfc; 163165b024e1SMatt Jacob } else { 163205fbcbb0SMatt Jacob eptr = tdma_mk; 163365b024e1SMatt Jacob } 163405fbcbb0SMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE || 163505fbcbb0SMatt Jacob (csio->dxfer_len == 0)) { 163665b024e1SMatt Jacob rq->req_seg_count = 1; 163765b024e1SMatt Jacob mp = &mush; 163865b024e1SMatt Jacob mp->isp = isp; 163965b024e1SMatt Jacob mp->cmd_token = csio; 164065b024e1SMatt Jacob mp->rq = rq; 164165b024e1SMatt Jacob mp->iptrp = iptrp; 164265b024e1SMatt Jacob mp->optr = optr; 164365b024e1SMatt Jacob mp->error = 0; 164465b024e1SMatt Jacob (*eptr)(mp, NULL, 0, 0); 164565b024e1SMatt Jacob goto exit; 164665b024e1SMatt Jacob } 164765b024e1SMatt Jacob } else 164865b024e1SMatt Jacob #endif 164965b024e1SMatt Jacob eptr = dma2; 165065b024e1SMatt Jacob 165142426921SMatt Jacob /* 165242426921SMatt Jacob * NB: if we need to do request queue entry swizzling, 165342426921SMatt Jacob * NB: this is where it would need to be done for cmds 165442426921SMatt Jacob * NB: that move no data. For commands that move data, 165542426921SMatt Jacob * NB: swizzling would take place in those functions. 165642426921SMatt Jacob */ 165705fbcbb0SMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE || 165805fbcbb0SMatt Jacob (csio->dxfer_len == 0)) { 165942426921SMatt Jacob rq->req_seg_count = 1; 166042426921SMatt Jacob return (CMD_QUEUED); 166142426921SMatt Jacob } 166242426921SMatt Jacob 1663d720e6d5SJustin T. Gibbs /* 1664d720e6d5SJustin T. Gibbs * Do a virtual grapevine step to collect info for 16654873663cSMatt Jacob * the callback dma allocation that we have to use... 1666d720e6d5SJustin T. Gibbs */ 1667d720e6d5SJustin T. Gibbs mp = &mush; 1668d720e6d5SJustin T. Gibbs mp->isp = isp; 16699e11e5beSMatt Jacob mp->cmd_token = csio; 1670d720e6d5SJustin T. Gibbs mp->rq = rq; 1671d720e6d5SJustin T. Gibbs mp->iptrp = iptrp; 1672d720e6d5SJustin T. Gibbs mp->optr = optr; 1673d720e6d5SJustin T. Gibbs mp->error = 0; 1674d720e6d5SJustin T. Gibbs 16759e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_SCATTER_VALID) == 0) { 16769e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DATA_PHYS) == 0) { 16774873663cSMatt Jacob int error, s; 1678469b6b9eSMatt Jacob dp = &pci->dmaps[isp_handle_index(rq->req_handle)]; 1679d720e6d5SJustin T. Gibbs s = splsoftvm(); 1680d720e6d5SJustin T. Gibbs error = bus_dmamap_load(pci->parent_dmat, *dp, 16819e11e5beSMatt Jacob csio->data_ptr, csio->dxfer_len, eptr, mp, 0); 1682d720e6d5SJustin T. Gibbs if (error == EINPROGRESS) { 1683d720e6d5SJustin T. Gibbs bus_dmamap_unload(pci->parent_dmat, *dp); 1684d720e6d5SJustin T. Gibbs mp->error = EINVAL; 1685f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 1686f7dddf8aSMatt Jacob "deferred dma allocation not supported"); 1687d720e6d5SJustin T. Gibbs } else if (error && mp->error == 0) { 16880a5f7e8bSMatt Jacob #ifdef DIAGNOSTIC 16890a5f7e8bSMatt Jacob printf("%s: error %d in dma mapping code\n", 16900a5f7e8bSMatt Jacob isp->isp_name, error); 16910a5f7e8bSMatt Jacob #endif 1692d720e6d5SJustin T. Gibbs mp->error = error; 1693d720e6d5SJustin T. Gibbs } 16944873663cSMatt Jacob splx(s); 1695d720e6d5SJustin T. Gibbs } else { 1696d720e6d5SJustin T. Gibbs /* Pointer to physical buffer */ 1697d720e6d5SJustin T. Gibbs struct bus_dma_segment seg; 1698d720e6d5SJustin T. Gibbs seg.ds_addr = (bus_addr_t)csio->data_ptr; 1699d720e6d5SJustin T. Gibbs seg.ds_len = csio->dxfer_len; 17009e11e5beSMatt Jacob (*eptr)(mp, &seg, 1, 0); 1701d720e6d5SJustin T. Gibbs } 1702d720e6d5SJustin T. Gibbs } else { 1703d720e6d5SJustin T. Gibbs struct bus_dma_segment *segs; 1704d720e6d5SJustin T. Gibbs 17059e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DATA_PHYS) != 0) { 1706f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 1707f7dddf8aSMatt Jacob "Physical segment pointers unsupported"); 1708d720e6d5SJustin T. Gibbs mp->error = EINVAL; 17099e11e5beSMatt Jacob } else if ((csio->ccb_h.flags & CAM_SG_LIST_PHYS) == 0) { 1710f7dddf8aSMatt Jacob isp_prt(isp, ISP_LOGERR, 1711f7dddf8aSMatt Jacob "Virtual segment addresses unsupported"); 1712d720e6d5SJustin T. Gibbs mp->error = EINVAL; 1713d720e6d5SJustin T. Gibbs } else { 1714d720e6d5SJustin T. Gibbs /* Just use the segments provided */ 1715d720e6d5SJustin T. Gibbs segs = (struct bus_dma_segment *) csio->data_ptr; 17169e11e5beSMatt Jacob (*eptr)(mp, segs, csio->sglist_cnt, 0); 1717d720e6d5SJustin T. Gibbs } 1718d720e6d5SJustin T. Gibbs } 1719003a310fSMatt Jacob #ifdef ISP_TARGET_MODE 172065b024e1SMatt Jacob exit: 1721003a310fSMatt Jacob #endif 1722d720e6d5SJustin T. Gibbs if (mp->error) { 17234873663cSMatt Jacob int retval = CMD_COMPLETE; 17244873663cSMatt Jacob if (mp->error == MUSHERR_NOQENTRIES) { 17254873663cSMatt Jacob retval = CMD_EAGAIN; 17264873663cSMatt Jacob } else if (mp->error == EFBIG) { 17270a5f7e8bSMatt Jacob XS_SETERR(csio, CAM_REQ_TOO_BIG); 1728d720e6d5SJustin T. Gibbs } else if (mp->error == EINVAL) { 17290a5f7e8bSMatt Jacob XS_SETERR(csio, CAM_REQ_INVALID); 1730d720e6d5SJustin T. Gibbs } else { 17310a5f7e8bSMatt Jacob XS_SETERR(csio, CAM_UNREC_HBA_ERROR); 1732d720e6d5SJustin T. Gibbs } 17334873663cSMatt Jacob return (retval); 17344873663cSMatt Jacob } else { 17350a5f7e8bSMatt Jacob /* 17360a5f7e8bSMatt Jacob * Check to see if we weren't cancelled while sleeping on 17370a5f7e8bSMatt Jacob * getting DMA resources... 17380a5f7e8bSMatt Jacob */ 17399e11e5beSMatt Jacob if ((csio->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG) { 17400a5f7e8bSMatt Jacob if (dp) { 17410a5f7e8bSMatt Jacob bus_dmamap_unload(pci->parent_dmat, *dp); 17420a5f7e8bSMatt Jacob } 17430a5f7e8bSMatt Jacob return (CMD_COMPLETE); 17440a5f7e8bSMatt Jacob } 17454873663cSMatt Jacob return (CMD_QUEUED); 1746d720e6d5SJustin T. Gibbs } 1747d720e6d5SJustin T. Gibbs } 1748d720e6d5SJustin T. Gibbs 1749d720e6d5SJustin T. Gibbs static void 1750d02373f1SMatt Jacob isp_pci_dmateardown(struct ispsoftc *isp, XS_T *xs, u_int32_t handle) 1751d720e6d5SJustin T. Gibbs { 1752d720e6d5SJustin T. Gibbs struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp; 1753469b6b9eSMatt Jacob bus_dmamap_t *dp = &pci->dmaps[isp_handle_index(handle)]; 1754a95ae193SMatt Jacob if ((xs->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 1755d720e6d5SJustin T. Gibbs bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_POSTREAD); 1756d720e6d5SJustin T. Gibbs } else { 1757d720e6d5SJustin T. Gibbs bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_POSTWRITE); 1758d720e6d5SJustin T. Gibbs } 1759d720e6d5SJustin T. Gibbs bus_dmamap_unload(pci->parent_dmat, *dp); 1760d720e6d5SJustin T. Gibbs } 1761d720e6d5SJustin T. Gibbs 176265adb54cSMatt Jacob 176365adb54cSMatt Jacob static void 176417e318c6SMatt Jacob isp_pci_reset1(struct ispsoftc *isp) 176565adb54cSMatt Jacob { 176665adb54cSMatt Jacob /* Make sure the BIOS is disabled */ 176765adb54cSMatt Jacob isp_pci_wr_reg(isp, HCCR, PCI_HCCR_CMD_BIOS); 1768469b6b9eSMatt Jacob /* and enable interrupts */ 1769469b6b9eSMatt Jacob ENABLE_INTS(isp); 177065adb54cSMatt Jacob } 177165adb54cSMatt Jacob 177265adb54cSMatt Jacob static void 1773d02373f1SMatt Jacob isp_pci_dumpregs(struct ispsoftc *isp, const char *msg) 177465adb54cSMatt Jacob { 177565adb54cSMatt Jacob struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp; 1776d02373f1SMatt Jacob if (msg) 1777d02373f1SMatt Jacob printf("%s: %s\n", isp->isp_name, msg); 1778d02373f1SMatt Jacob if (IS_SCSI(isp)) 1779d02373f1SMatt Jacob printf(" biu_conf1=%x", ISP_READ(isp, BIU_CONF1)); 1780d02373f1SMatt Jacob else 1781d02373f1SMatt Jacob printf(" biu_csr=%x", ISP_READ(isp, BIU2100_CSR)); 1782d02373f1SMatt Jacob printf(" biu_icr=%x biu_isr=%x biu_sema=%x ", ISP_READ(isp, BIU_ICR), 1783d02373f1SMatt Jacob ISP_READ(isp, BIU_ISR), ISP_READ(isp, BIU_SEMA)); 1784d02373f1SMatt Jacob printf("risc_hccr=%x\n", ISP_READ(isp, HCCR)); 1785d02373f1SMatt Jacob 1786d02373f1SMatt Jacob 1787d02373f1SMatt Jacob if (IS_SCSI(isp)) { 1788d02373f1SMatt Jacob ISP_WRITE(isp, HCCR, HCCR_CMD_PAUSE); 1789d02373f1SMatt Jacob printf(" cdma_conf=%x cdma_sts=%x cdma_fifostat=%x\n", 1790d02373f1SMatt Jacob ISP_READ(isp, CDMA_CONF), ISP_READ(isp, CDMA_STATUS), 1791d02373f1SMatt Jacob ISP_READ(isp, CDMA_FIFO_STS)); 1792d02373f1SMatt Jacob printf(" ddma_conf=%x ddma_sts=%x ddma_fifostat=%x\n", 1793d02373f1SMatt Jacob ISP_READ(isp, DDMA_CONF), ISP_READ(isp, DDMA_STATUS), 1794d02373f1SMatt Jacob ISP_READ(isp, DDMA_FIFO_STS)); 1795d02373f1SMatt Jacob printf(" sxp_int=%x sxp_gross=%x sxp(scsi_ctrl)=%x\n", 1796d02373f1SMatt Jacob ISP_READ(isp, SXP_INTERRUPT), 1797d02373f1SMatt Jacob ISP_READ(isp, SXP_GROSS_ERR), 1798d02373f1SMatt Jacob ISP_READ(isp, SXP_PINS_CTRL)); 1799d02373f1SMatt Jacob ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE); 1800d02373f1SMatt Jacob } 1801d02373f1SMatt Jacob printf(" mbox regs: %x %x %x %x %x\n", 1802d02373f1SMatt Jacob ISP_READ(isp, OUTMAILBOX0), ISP_READ(isp, OUTMAILBOX1), 1803d02373f1SMatt Jacob ISP_READ(isp, OUTMAILBOX2), ISP_READ(isp, OUTMAILBOX3), 1804d02373f1SMatt Jacob ISP_READ(isp, OUTMAILBOX4)); 1805d02373f1SMatt Jacob printf(" PCI Status Command/Status=%x\n", 1806960f6939SMatt Jacob pci_read_config(pci->pci_dev, PCIR_COMMAND, 1)); 180765adb54cSMatt Jacob } 1808