1c3aac50fSPeter Wemm /* $FreeBSD$ */ 265adb54cSMatt Jacob /* 365adb54cSMatt Jacob * PCI specific probe and attach routines for Qlogic ISP SCSI adapters. 465adb54cSMatt Jacob * FreeBSD Version. 565adb54cSMatt Jacob * 665adb54cSMatt Jacob *--------------------------------------- 7222bb542SMatt Jacob * Copyright (c) 1997, 1998, 1999 by Matthew Jacob 865adb54cSMatt Jacob * NASA/Ames Research Center 965adb54cSMatt Jacob * All rights reserved. 1065adb54cSMatt Jacob *--------------------------------------- 1165adb54cSMatt Jacob * 1265adb54cSMatt Jacob * Redistribution and use in source and binary forms, with or without 1365adb54cSMatt Jacob * modification, are permitted provided that the following conditions 1465adb54cSMatt Jacob * are met: 1565adb54cSMatt Jacob * 1. Redistributions of source code must retain the above copyright 1665adb54cSMatt Jacob * notice immediately at the beginning of the file, without modification, 1765adb54cSMatt Jacob * this list of conditions, and the following disclaimer. 1865adb54cSMatt Jacob * 2. Redistributions in binary form must reproduce the above copyright 1965adb54cSMatt Jacob * notice, this list of conditions and the following disclaimer in the 2065adb54cSMatt Jacob * documentation and/or other materials provided with the distribution. 2165adb54cSMatt Jacob * 3. The name of the author may not be used to endorse or promote products 2265adb54cSMatt Jacob * derived from this software without specific prior written permission. 2365adb54cSMatt Jacob * 2465adb54cSMatt Jacob * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2565adb54cSMatt Jacob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2665adb54cSMatt Jacob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2765adb54cSMatt Jacob * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2865adb54cSMatt Jacob * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2965adb54cSMatt Jacob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3065adb54cSMatt Jacob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3165adb54cSMatt Jacob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3265adb54cSMatt Jacob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3365adb54cSMatt Jacob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3465adb54cSMatt Jacob * SUCH DAMAGE. 3565adb54cSMatt Jacob */ 3665adb54cSMatt Jacob #include <dev/isp/isp_freebsd.h> 3765adb54cSMatt Jacob #include <dev/isp/asm_pci.h> 38d720e6d5SJustin T. Gibbs #include <sys/malloc.h> 39d720e6d5SJustin T. Gibbs #include <vm/vm.h> 40d720e6d5SJustin T. Gibbs #include <vm/pmap.h> 41d720e6d5SJustin T. Gibbs 4265adb54cSMatt Jacob 4365adb54cSMatt Jacob #include <pci/pcireg.h> 4465adb54cSMatt Jacob #include <pci/pcivar.h> 4565adb54cSMatt Jacob 46d720e6d5SJustin T. Gibbs #include <machine/bus_memio.h> 47d720e6d5SJustin T. Gibbs #include <machine/bus_pio.h> 48d720e6d5SJustin T. Gibbs #include <machine/bus.h> 49a95ae193SMatt Jacob #include <machine/md_var.h> 50d59bd469SMatt Jacob 5165adb54cSMatt Jacob static u_int16_t isp_pci_rd_reg __P((struct ispsoftc *, int)); 5265adb54cSMatt Jacob static void isp_pci_wr_reg __P((struct ispsoftc *, int, u_int16_t)); 53d59bd469SMatt Jacob #ifndef ISP_DISABLE_1080_SUPPORT 54d59bd469SMatt Jacob static u_int16_t isp_pci_rd_reg_1080 __P((struct ispsoftc *, int)); 55d59bd469SMatt Jacob static void isp_pci_wr_reg_1080 __P((struct ispsoftc *, int, u_int16_t)); 56d59bd469SMatt Jacob #endif 5765adb54cSMatt Jacob static int isp_pci_mbxdma __P((struct ispsoftc *)); 5865adb54cSMatt Jacob static int isp_pci_dmasetup __P((struct ispsoftc *, ISP_SCSI_XFER_T *, 599637d68cSMatt Jacob ispreq_t *, u_int16_t *, u_int16_t)); 60d720e6d5SJustin T. Gibbs static void 61d720e6d5SJustin T. Gibbs isp_pci_dmateardown __P((struct ispsoftc *, ISP_SCSI_XFER_T *, u_int32_t)); 6265adb54cSMatt Jacob 6365adb54cSMatt Jacob static void isp_pci_reset1 __P((struct ispsoftc *)); 6465adb54cSMatt Jacob static void isp_pci_dumpregs __P((struct ispsoftc *)); 6565adb54cSMatt Jacob 66fed92c47SMatt Jacob #ifndef ISP_CODE_ORG 67fed92c47SMatt Jacob #define ISP_CODE_ORG 0x1000 68fed92c47SMatt Jacob #endif 69fed92c47SMatt Jacob #ifndef ISP_1040_RISC_CODE 70fed92c47SMatt Jacob #define ISP_1040_RISC_CODE NULL 71fed92c47SMatt Jacob #endif 72fed92c47SMatt Jacob #ifndef ISP_1080_RISC_CODE 73fed92c47SMatt Jacob #define ISP_1080_RISC_CODE NULL 74fed92c47SMatt Jacob #endif 75fed92c47SMatt Jacob #ifndef ISP_2100_RISC_CODE 76fed92c47SMatt Jacob #define ISP_2100_RISC_CODE NULL 77fed92c47SMatt Jacob #endif 78fed92c47SMatt Jacob #ifndef ISP_2200_RISC_CODE 79fed92c47SMatt Jacob #define ISP_2200_RISC_CODE NULL 80fed92c47SMatt Jacob #endif 81fed92c47SMatt Jacob 82d59bd469SMatt Jacob #ifndef ISP_DISABLE_1020_SUPPORT 8365adb54cSMatt Jacob static struct ispmdvec mdvec = { 8465adb54cSMatt Jacob isp_pci_rd_reg, 8565adb54cSMatt Jacob isp_pci_wr_reg, 8665adb54cSMatt Jacob isp_pci_mbxdma, 8765adb54cSMatt Jacob isp_pci_dmasetup, 88d720e6d5SJustin T. Gibbs isp_pci_dmateardown, 8965adb54cSMatt Jacob NULL, 9065adb54cSMatt Jacob isp_pci_reset1, 9165adb54cSMatt Jacob isp_pci_dumpregs, 92fed92c47SMatt Jacob ISP_1040_RISC_CODE, 93fed92c47SMatt Jacob 0, 9465adb54cSMatt Jacob ISP_CODE_ORG, 95a95ae193SMatt Jacob 0, 96285e230dSMatt Jacob BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64, 97d720e6d5SJustin T. Gibbs 0 9865adb54cSMatt Jacob }; 99d59bd469SMatt Jacob #endif 10065adb54cSMatt Jacob 101d59bd469SMatt Jacob #ifndef ISP_DISABLE_1080_SUPPORT 102d59bd469SMatt Jacob static struct ispmdvec mdvec_1080 = { 103d59bd469SMatt Jacob isp_pci_rd_reg_1080, 104d59bd469SMatt Jacob isp_pci_wr_reg_1080, 105d59bd469SMatt Jacob isp_pci_mbxdma, 106d59bd469SMatt Jacob isp_pci_dmasetup, 107d59bd469SMatt Jacob isp_pci_dmateardown, 108d59bd469SMatt Jacob NULL, 109d59bd469SMatt Jacob isp_pci_reset1, 110d59bd469SMatt Jacob isp_pci_dumpregs, 111fed92c47SMatt Jacob ISP_1080_RISC_CODE, 112fed92c47SMatt Jacob 0, 113fed92c47SMatt Jacob ISP_CODE_ORG, 114a95ae193SMatt Jacob 0, 115d59bd469SMatt Jacob BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64, 116d59bd469SMatt Jacob 0 117d59bd469SMatt Jacob }; 118d59bd469SMatt Jacob #endif 119d59bd469SMatt Jacob 120d59bd469SMatt Jacob #ifndef ISP_DISABLE_2100_SUPPORT 12165adb54cSMatt Jacob static struct ispmdvec mdvec_2100 = { 12265adb54cSMatt Jacob isp_pci_rd_reg, 12365adb54cSMatt Jacob isp_pci_wr_reg, 12465adb54cSMatt Jacob isp_pci_mbxdma, 12565adb54cSMatt Jacob isp_pci_dmasetup, 126d720e6d5SJustin T. Gibbs isp_pci_dmateardown, 12765adb54cSMatt Jacob NULL, 12865adb54cSMatt Jacob isp_pci_reset1, 12965adb54cSMatt Jacob isp_pci_dumpregs, 130fed92c47SMatt Jacob ISP_2100_RISC_CODE, 131fed92c47SMatt Jacob 0, 132fed92c47SMatt Jacob ISP_CODE_ORG, 133a95ae193SMatt Jacob 0, 134a95ae193SMatt Jacob 0, 135d720e6d5SJustin T. Gibbs 0 13665adb54cSMatt Jacob }; 1375542fe4bSMatt Jacob #endif 138222bb542SMatt Jacob 13986cb5d6bSMatt Jacob #ifndef ISP_DISABLE_2200_SUPPORT 140222bb542SMatt Jacob static struct ispmdvec mdvec_2200 = { 141222bb542SMatt Jacob isp_pci_rd_reg, 142222bb542SMatt Jacob isp_pci_wr_reg, 143222bb542SMatt Jacob isp_pci_mbxdma, 144222bb542SMatt Jacob isp_pci_dmasetup, 145222bb542SMatt Jacob isp_pci_dmateardown, 146222bb542SMatt Jacob NULL, 147222bb542SMatt Jacob isp_pci_reset1, 148222bb542SMatt Jacob isp_pci_dumpregs, 149fed92c47SMatt Jacob ISP_2200_RISC_CODE, 150fed92c47SMatt Jacob 0, 151fed92c47SMatt Jacob ISP_CODE_ORG, 152a95ae193SMatt Jacob 0, 153222bb542SMatt Jacob 0, 154222bb542SMatt Jacob 0 155222bb542SMatt Jacob }; 156d59bd469SMatt Jacob #endif 15765adb54cSMatt Jacob 158d951bbcaSMatt Jacob #ifndef SCSI_ISP_PREFER_MEM_MAP 159d951bbcaSMatt Jacob #define SCSI_ISP_PREFER_MEM_MAP 0 160d951bbcaSMatt Jacob #endif 161d951bbcaSMatt Jacob 16265adb54cSMatt Jacob #ifndef PCIM_CMD_INVEN 16365adb54cSMatt Jacob #define PCIM_CMD_INVEN 0x10 16465adb54cSMatt Jacob #endif 16565adb54cSMatt Jacob #ifndef PCIM_CMD_BUSMASTEREN 16665adb54cSMatt Jacob #define PCIM_CMD_BUSMASTEREN 0x0004 16765adb54cSMatt Jacob #endif 168d951bbcaSMatt Jacob #ifndef PCIM_CMD_PERRESPEN 169d951bbcaSMatt Jacob #define PCIM_CMD_PERRESPEN 0x0040 170d951bbcaSMatt Jacob #endif 171d951bbcaSMatt Jacob #ifndef PCIM_CMD_SEREN 172d951bbcaSMatt Jacob #define PCIM_CMD_SEREN 0x0100 173d951bbcaSMatt Jacob #endif 174d951bbcaSMatt Jacob 175d951bbcaSMatt Jacob #ifndef PCIR_COMMAND 176d951bbcaSMatt Jacob #define PCIR_COMMAND 0x04 177d951bbcaSMatt Jacob #endif 178d951bbcaSMatt Jacob 179d951bbcaSMatt Jacob #ifndef PCIR_CACHELNSZ 180d951bbcaSMatt Jacob #define PCIR_CACHELNSZ 0x0c 181d951bbcaSMatt Jacob #endif 182d951bbcaSMatt Jacob 183d951bbcaSMatt Jacob #ifndef PCIR_LATTIMER 184d951bbcaSMatt Jacob #define PCIR_LATTIMER 0x0d 185d951bbcaSMatt Jacob #endif 186d951bbcaSMatt Jacob 187ab6d0040SMatt Jacob #ifndef PCIR_ROMADDR 188ab6d0040SMatt Jacob #define PCIR_ROMADDR 0x30 189ab6d0040SMatt Jacob #endif 190ab6d0040SMatt Jacob 19165adb54cSMatt Jacob #ifndef PCI_VENDOR_QLOGIC 19265adb54cSMatt Jacob #define PCI_VENDOR_QLOGIC 0x1077 19365adb54cSMatt Jacob #endif 19465adb54cSMatt Jacob 19565adb54cSMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP1020 19665adb54cSMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP1020 0x1020 19765adb54cSMatt Jacob #endif 19865adb54cSMatt Jacob 199d59bd469SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP1080 200d59bd469SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP1080 0x1080 201d59bd469SMatt Jacob #endif 202d59bd469SMatt Jacob 203d59bd469SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP1240 204d59bd469SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP1240 0x1240 205d59bd469SMatt Jacob #endif 20665adb54cSMatt Jacob 20722e1dc85SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP1280 20822e1dc85SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP1280 0x1280 20922e1dc85SMatt Jacob #endif 21022e1dc85SMatt Jacob 21165adb54cSMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP2100 21265adb54cSMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP2100 0x2100 21365adb54cSMatt Jacob #endif 21465adb54cSMatt Jacob 215222bb542SMatt Jacob #ifndef PCI_PRODUCT_QLOGIC_ISP2200 216222bb542SMatt Jacob #define PCI_PRODUCT_QLOGIC_ISP2200 0x2200 217222bb542SMatt Jacob #endif 218222bb542SMatt Jacob 219d59bd469SMatt Jacob #define PCI_QLOGIC_ISP ((PCI_PRODUCT_QLOGIC_ISP1020 << 16) | PCI_VENDOR_QLOGIC) 220d59bd469SMatt Jacob 221d59bd469SMatt Jacob #define PCI_QLOGIC_ISP1080 \ 222d59bd469SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP1080 << 16) | PCI_VENDOR_QLOGIC) 223d59bd469SMatt Jacob 224d59bd469SMatt Jacob #define PCI_QLOGIC_ISP1240 \ 225d59bd469SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP1240 << 16) | PCI_VENDOR_QLOGIC) 226d59bd469SMatt Jacob 22722e1dc85SMatt Jacob #define PCI_QLOGIC_ISP1280 \ 22822e1dc85SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP1280 << 16) | PCI_VENDOR_QLOGIC) 22922e1dc85SMatt Jacob 23065adb54cSMatt Jacob #define PCI_QLOGIC_ISP2100 \ 23165adb54cSMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP2100 << 16) | PCI_VENDOR_QLOGIC) 23265adb54cSMatt Jacob 233222bb542SMatt Jacob #define PCI_QLOGIC_ISP2200 \ 234222bb542SMatt Jacob ((PCI_PRODUCT_QLOGIC_ISP2200 << 16) | PCI_VENDOR_QLOGIC) 235222bb542SMatt Jacob 23665adb54cSMatt Jacob #define IO_MAP_REG 0x10 23765adb54cSMatt Jacob #define MEM_MAP_REG 0x14 23865adb54cSMatt Jacob 239d951bbcaSMatt Jacob #define PCI_DFLT_LTNCY 0x40 240d951bbcaSMatt Jacob #define PCI_DFLT_LNSZ 0x10 24165adb54cSMatt Jacob 242222bb542SMatt Jacob static const char *isp_pci_probe __P((pcici_t tag, pcidi_t type)); 24365adb54cSMatt Jacob static void isp_pci_attach __P((pcici_t config_d, int unit)); 24465adb54cSMatt Jacob 245d720e6d5SJustin T. Gibbs /* This distinguishing define is not right, but it does work */ 246a185f9b1SMatt Jacob #ifdef __alpha__ 247a185f9b1SMatt Jacob #define IO_SPACE_MAPPING ALPHA_BUS_SPACE_IO 248a185f9b1SMatt Jacob #define MEM_SPACE_MAPPING ALPHA_BUS_SPACE_MEM 249a185f9b1SMatt Jacob #else 250a185f9b1SMatt Jacob #define IO_SPACE_MAPPING I386_BUS_SPACE_IO 251a185f9b1SMatt Jacob #define MEM_SPACE_MAPPING I386_BUS_SPACE_MEM 252a185f9b1SMatt Jacob #endif 25365adb54cSMatt Jacob 25465adb54cSMatt Jacob struct isp_pcisoftc { 25565adb54cSMatt Jacob struct ispsoftc pci_isp; 25665adb54cSMatt Jacob pcici_t pci_id; 25765adb54cSMatt Jacob bus_space_tag_t pci_st; 25865adb54cSMatt Jacob bus_space_handle_t pci_sh; 259d59bd469SMatt Jacob int16_t pci_poff[_NREG_BLKS]; 260d720e6d5SJustin T. Gibbs bus_dma_tag_t parent_dmat; 261d720e6d5SJustin T. Gibbs bus_dma_tag_t cntrol_dmat; 262d720e6d5SJustin T. Gibbs bus_dmamap_t cntrol_dmap; 263a95ae193SMatt Jacob bus_dmamap_t *dmaps; 26465adb54cSMatt Jacob }; 26565adb54cSMatt Jacob 266d720e6d5SJustin T. Gibbs static u_long ispunit; 26765adb54cSMatt Jacob 26866235db5SEivind Eklund static struct pci_device isp_pci_driver = { 26965adb54cSMatt Jacob "isp", 27065adb54cSMatt Jacob isp_pci_probe, 27165adb54cSMatt Jacob isp_pci_attach, 272d720e6d5SJustin T. Gibbs &ispunit, 27365adb54cSMatt Jacob NULL 27465adb54cSMatt Jacob }; 27596b3554eSPeter Wemm COMPAT_PCI_DRIVER (isp_pci, isp_pci_driver); 27665adb54cSMatt Jacob 27765adb54cSMatt Jacob 278222bb542SMatt Jacob static const char * 27917e318c6SMatt Jacob isp_pci_probe(pcici_t tag, pcidi_t type) 28065adb54cSMatt Jacob { 28165adb54cSMatt Jacob static int oneshot = 1; 28265adb54cSMatt Jacob char *x; 28365adb54cSMatt Jacob 28465adb54cSMatt Jacob switch (type) { 285d59bd469SMatt Jacob #ifndef ISP_DISABLE_1020_SUPPORT 28665adb54cSMatt Jacob case PCI_QLOGIC_ISP: 287d59bd469SMatt Jacob x = "Qlogic ISP 1020/1040 PCI SCSI Adapter"; 28865adb54cSMatt Jacob break; 289d59bd469SMatt Jacob #endif 290d59bd469SMatt Jacob #ifndef ISP_DISABLE_1080_SUPPORT 291d59bd469SMatt Jacob case PCI_QLOGIC_ISP1080: 292c6608df3SMatt Jacob x = "Qlogic ISP 1080 PCI SCSI Adapter"; 293c6608df3SMatt Jacob break; 294c6608df3SMatt Jacob case PCI_QLOGIC_ISP1240: 295c6608df3SMatt Jacob x = "Qlogic ISP 1240 PCI SCSI Adapter"; 296d59bd469SMatt Jacob break; 29722e1dc85SMatt Jacob case PCI_QLOGIC_ISP1280: 29822e1dc85SMatt Jacob x = "Qlogic ISP 1280 PCI SCSI Adapter"; 29922e1dc85SMatt Jacob break; 300d59bd469SMatt Jacob #endif 301d59bd469SMatt Jacob #ifndef ISP_DISABLE_2100_SUPPORT 30265adb54cSMatt Jacob case PCI_QLOGIC_ISP2100: 30365adb54cSMatt Jacob x = "Qlogic ISP 2100 PCI FC-AL Adapter"; 30465adb54cSMatt Jacob break; 305d59bd469SMatt Jacob #endif 3065542fe4bSMatt Jacob #ifndef ISP_DISABLE_2200_SUPPORT 3075542fe4bSMatt Jacob case PCI_QLOGIC_ISP2200: 3085542fe4bSMatt Jacob x = "Qlogic ISP 2200 PCI FC-AL Adapter"; 3095542fe4bSMatt Jacob break; 3105542fe4bSMatt Jacob #endif 31165adb54cSMatt Jacob default: 31265adb54cSMatt Jacob return (NULL); 31365adb54cSMatt Jacob } 31465adb54cSMatt Jacob if (oneshot) { 31565adb54cSMatt Jacob oneshot = 0; 316a95ae193SMatt Jacob CFGPRINTF("Qlogic ISP Driver, FreeBSD Version %d.%d, " 317a95ae193SMatt Jacob "Core Version %d.%d\n", 318d720e6d5SJustin T. Gibbs ISP_PLATFORM_VERSION_MAJOR, ISP_PLATFORM_VERSION_MINOR, 319d720e6d5SJustin T. Gibbs ISP_CORE_VERSION_MAJOR, ISP_CORE_VERSION_MINOR); 32065adb54cSMatt Jacob } 32165adb54cSMatt Jacob return (x); 32265adb54cSMatt Jacob } 32365adb54cSMatt Jacob 32465adb54cSMatt Jacob static void 325222bb542SMatt Jacob isp_pci_attach(pcici_t cfid, int unit) 32665adb54cSMatt Jacob { 3279637d68cSMatt Jacob #ifdef SCSI_ISP_WWN 3289637d68cSMatt Jacob const char *name = SCSI_ISP_WWN; 3299637d68cSMatt Jacob char *vtp = NULL; 3309637d68cSMatt Jacob #endif 331222bb542SMatt Jacob int mapped, prefer_mem_map, bitmap; 332a185f9b1SMatt Jacob pci_port_t io_port; 3339637d68cSMatt Jacob u_int32_t data, rev, linesz, psize, basetype; 33465adb54cSMatt Jacob struct isp_pcisoftc *pcs; 33565adb54cSMatt Jacob struct ispsoftc *isp; 33665adb54cSMatt Jacob vm_offset_t vaddr, paddr; 337c6608df3SMatt Jacob struct ispmdvec *mdvp; 338222bb542SMatt Jacob bus_size_t lim; 33965adb54cSMatt Jacob ISP_LOCKVAL_DECL; 34065adb54cSMatt Jacob 34165adb54cSMatt Jacob pcs = malloc(sizeof (struct isp_pcisoftc), M_DEVBUF, M_NOWAIT); 34265adb54cSMatt Jacob if (pcs == NULL) { 3439bffbcd4SBruce Evans printf("isp%d: cannot allocate softc\n", unit); 34465adb54cSMatt Jacob return; 34565adb54cSMatt Jacob } 34665adb54cSMatt Jacob bzero(pcs, sizeof (struct isp_pcisoftc)); 34765adb54cSMatt Jacob 348222bb542SMatt Jacob /* 3499ba86737SMatt Jacob * Figure out if we're supposed to skip this one. 3509ba86737SMatt Jacob */ 3519ba86737SMatt Jacob if (getenv_int("isp_disable", &bitmap)) { 3529ba86737SMatt Jacob if (bitmap & (1 << unit)) { 3539ba86737SMatt Jacob printf("isp%d: not configuring\n", unit); 3549ba86737SMatt Jacob return; 3559ba86737SMatt Jacob } 3569ba86737SMatt Jacob } 3579ba86737SMatt Jacob 3589ba86737SMatt Jacob /* 359222bb542SMatt Jacob * Figure out which we should try first - memory mapping or i/o mapping? 360222bb542SMatt Jacob */ 361222bb542SMatt Jacob #if SCSI_ISP_PREFER_MEM_MAP == 1 362222bb542SMatt Jacob prefer_mem_map = 1; 363222bb542SMatt Jacob #else 364222bb542SMatt Jacob prefer_mem_map = 0; 365222bb542SMatt Jacob #endif 366222bb542SMatt Jacob bitmap = 0; 367222bb542SMatt Jacob if (getenv_int("isp_mem_map", &bitmap)) { 368222bb542SMatt Jacob if (bitmap & (1 << unit)) 369222bb542SMatt Jacob prefer_mem_map = 1; 370222bb542SMatt Jacob } 371222bb542SMatt Jacob bitmap = 0; 372222bb542SMatt Jacob if (getenv_int("isp_io_map", &bitmap)) { 373222bb542SMatt Jacob if (bitmap & (1 << unit)) 374222bb542SMatt Jacob prefer_mem_map = 0; 375222bb542SMatt Jacob } 376222bb542SMatt Jacob 37765adb54cSMatt Jacob vaddr = paddr = NULL; 37865adb54cSMatt Jacob mapped = 0; 379ab6d0040SMatt Jacob linesz = PCI_DFLT_LNSZ; 380d951bbcaSMatt Jacob /* 381d951bbcaSMatt Jacob * Note that pci_conf_read is a 32 bit word aligned function. 382d951bbcaSMatt Jacob */ 383222bb542SMatt Jacob data = pci_conf_read(cfid, PCIR_COMMAND); 384222bb542SMatt Jacob if (prefer_mem_map) { 385222bb542SMatt Jacob if (data & PCI_COMMAND_MEM_ENABLE) { 386222bb542SMatt Jacob if (pci_map_mem(cfid, MEM_MAP_REG, &vaddr, &paddr)) { 387a185f9b1SMatt Jacob pcs->pci_st = MEM_SPACE_MAPPING; 388a185f9b1SMatt Jacob pcs->pci_sh = vaddr; 38965adb54cSMatt Jacob mapped++; 39065adb54cSMatt Jacob } 39165adb54cSMatt Jacob } 392a185f9b1SMatt Jacob if (mapped == 0 && (data & PCI_COMMAND_IO_ENABLE)) { 393222bb542SMatt Jacob if (pci_map_port(cfid, PCI_MAP_REG_START, &io_port)) { 394a185f9b1SMatt Jacob pcs->pci_st = IO_SPACE_MAPPING; 395a185f9b1SMatt Jacob pcs->pci_sh = io_port; 39665adb54cSMatt Jacob mapped++; 39765adb54cSMatt Jacob } 39865adb54cSMatt Jacob } 399222bb542SMatt Jacob } else { 400222bb542SMatt Jacob if (data & PCI_COMMAND_IO_ENABLE) { 401222bb542SMatt Jacob if (pci_map_port(cfid, PCI_MAP_REG_START, &io_port)) { 402d951bbcaSMatt Jacob pcs->pci_st = IO_SPACE_MAPPING; 403d951bbcaSMatt Jacob pcs->pci_sh = io_port; 404d951bbcaSMatt Jacob mapped++; 405d951bbcaSMatt Jacob } 406d951bbcaSMatt Jacob } 407d951bbcaSMatt Jacob if (mapped == 0 && (data & PCI_COMMAND_MEM_ENABLE)) { 408222bb542SMatt Jacob if (pci_map_mem(cfid, MEM_MAP_REG, &vaddr, &paddr)) { 409d951bbcaSMatt Jacob pcs->pci_st = MEM_SPACE_MAPPING; 410d951bbcaSMatt Jacob pcs->pci_sh = vaddr; 411d951bbcaSMatt Jacob mapped++; 412d951bbcaSMatt Jacob } 413d951bbcaSMatt Jacob } 414222bb542SMatt Jacob } 41565adb54cSMatt Jacob if (mapped == 0) { 4169bffbcd4SBruce Evans printf("isp%d: unable to map any ports!\n", unit); 41765adb54cSMatt Jacob free(pcs, M_DEVBUF); 41865adb54cSMatt Jacob return; 41965adb54cSMatt Jacob } 420222bb542SMatt Jacob if (bootverbose) 42165adb54cSMatt Jacob printf("isp%d: using %s space register mapping\n", unit, 422a185f9b1SMatt Jacob pcs->pci_st == IO_SPACE_MAPPING? "I/O" : "Memory"); 42365adb54cSMatt Jacob 424222bb542SMatt Jacob data = pci_conf_read(cfid, PCI_ID_REG); 4259637d68cSMatt Jacob rev = pci_conf_read(cfid, PCI_CLASS_REG) & 0xff; /* revision */ 426d59bd469SMatt Jacob pcs->pci_poff[BIU_BLOCK >> _BLK_REG_SHFT] = BIU_REGS_OFF; 427d59bd469SMatt Jacob pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS_OFF; 428d59bd469SMatt Jacob pcs->pci_poff[SXP_BLOCK >> _BLK_REG_SHFT] = PCI_SXP_REGS_OFF; 429d59bd469SMatt Jacob pcs->pci_poff[RISC_BLOCK >> _BLK_REG_SHFT] = PCI_RISC_REGS_OFF; 430d59bd469SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = DMA_REGS_OFF; 431c6608df3SMatt Jacob /* 432c6608df3SMatt Jacob * GCC! 433c6608df3SMatt Jacob */ 434c6608df3SMatt Jacob mdvp = &mdvec; 435c6608df3SMatt Jacob basetype = ISP_HA_SCSI_UNKNOWN; 436c6608df3SMatt Jacob psize = sizeof (sdparam); 437222bb542SMatt Jacob lim = BUS_SPACE_MAXSIZE_32BIT; 438d59bd469SMatt Jacob #ifndef ISP_DISABLE_1020_SUPPORT 43965adb54cSMatt Jacob if (data == PCI_QLOGIC_ISP) { 440c6608df3SMatt Jacob mdvp = &mdvec; 441c6608df3SMatt Jacob basetype = ISP_HA_SCSI_UNKNOWN; 442c6608df3SMatt Jacob psize = sizeof (sdparam); 443222bb542SMatt Jacob lim = BUS_SPACE_MAXSIZE_24BIT; 444d59bd469SMatt Jacob } 445d59bd469SMatt Jacob #endif 446d59bd469SMatt Jacob #ifndef ISP_DISABLE_1080_SUPPORT 447c6608df3SMatt Jacob if (data == PCI_QLOGIC_ISP1080) { 448c6608df3SMatt Jacob mdvp = &mdvec_1080; 449c6608df3SMatt Jacob basetype = ISP_HA_SCSI_1080; 450c6608df3SMatt Jacob psize = sizeof (sdparam); 451c6608df3SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 452c6608df3SMatt Jacob ISP1080_DMA_REGS_OFF; 453c6608df3SMatt Jacob } 454c6608df3SMatt Jacob if (data == PCI_QLOGIC_ISP1240) { 455c6608df3SMatt Jacob mdvp = &mdvec_1080; 45622e1dc85SMatt Jacob basetype = ISP_HA_SCSI_1240; 45722e1dc85SMatt Jacob psize = 2 * sizeof (sdparam); 45822e1dc85SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 45922e1dc85SMatt Jacob ISP1080_DMA_REGS_OFF; 46022e1dc85SMatt Jacob } 46122e1dc85SMatt Jacob if (data == PCI_QLOGIC_ISP1280) { 46222e1dc85SMatt Jacob mdvp = &mdvec_1080; 46322e1dc85SMatt Jacob basetype = ISP_HA_SCSI_1280; 464c6608df3SMatt Jacob psize = 2 * sizeof (sdparam); 465d59bd469SMatt Jacob pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 466d59bd469SMatt Jacob ISP1080_DMA_REGS_OFF; 467d59bd469SMatt Jacob } 468d59bd469SMatt Jacob #endif 469d59bd469SMatt Jacob #ifndef ISP_DISABLE_2100_SUPPORT 470d59bd469SMatt Jacob if (data == PCI_QLOGIC_ISP2100) { 471c6608df3SMatt Jacob mdvp = &mdvec_2100; 472c6608df3SMatt Jacob basetype = ISP_HA_FC_2100; 473c6608df3SMatt Jacob psize = sizeof (fcparam); 474d59bd469SMatt Jacob pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = 475d59bd469SMatt Jacob PCI_MBOX_REGS2100_OFF; 4769637d68cSMatt Jacob if (rev < 3) { 477ab6d0040SMatt Jacob /* 478ab6d0040SMatt Jacob * XXX: Need to get the actual revision 479ab6d0040SMatt Jacob * XXX: number of the 2100 FB. At any rate, 480ab6d0040SMatt Jacob * XXX: lower cache line size for early revision 481ab6d0040SMatt Jacob * XXX; boards. 482ab6d0040SMatt Jacob */ 483ab6d0040SMatt Jacob linesz = 1; 484ab6d0040SMatt Jacob } 48565adb54cSMatt Jacob } 4865542fe4bSMatt Jacob #endif 4875542fe4bSMatt Jacob #ifndef ISP_DISABLE_2200_SUPPORT 488222bb542SMatt Jacob if (data == PCI_QLOGIC_ISP2200) { 489222bb542SMatt Jacob mdvp = &mdvec_2200; 490222bb542SMatt Jacob basetype = ISP_HA_FC_2200; 491222bb542SMatt Jacob psize = sizeof (fcparam); 492222bb542SMatt Jacob pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = 493222bb542SMatt Jacob PCI_MBOX_REGS2100_OFF; 494222bb542SMatt Jacob } 495d59bd469SMatt Jacob #endif 496c6608df3SMatt Jacob isp = &pcs->pci_isp; 497c6608df3SMatt Jacob isp->isp_param = malloc(psize, M_DEVBUF, M_NOWAIT); 498c6608df3SMatt Jacob if (isp->isp_param == NULL) { 499c6608df3SMatt Jacob printf("isp%d: cannot allocate parameter data\n", unit); 500c6608df3SMatt Jacob return; 501c6608df3SMatt Jacob } 502c6608df3SMatt Jacob bzero(isp->isp_param, psize); 503c6608df3SMatt Jacob isp->isp_mdvec = mdvp; 504c6608df3SMatt Jacob isp->isp_type = basetype; 5059637d68cSMatt Jacob isp->isp_revision = rev; 506c6608df3SMatt Jacob (void) snprintf(isp->isp_name, sizeof (isp->isp_name), "isp%d", unit); 507c6608df3SMatt Jacob isp->isp_osinfo.unit = unit; 50865adb54cSMatt Jacob 509d951bbcaSMatt Jacob ISP_LOCK(isp); 510ab6d0040SMatt Jacob 511d951bbcaSMatt Jacob /* 512d951bbcaSMatt Jacob * Make sure that SERR, PERR, WRITE INVALIDATE and BUSMASTER 513d951bbcaSMatt Jacob * are set. 514d951bbcaSMatt Jacob */ 515222bb542SMatt Jacob data = pci_cfgread(cfid, PCIR_COMMAND, 2); 516d951bbcaSMatt Jacob data |= PCIM_CMD_SEREN | 517d951bbcaSMatt Jacob PCIM_CMD_PERRESPEN | 518d951bbcaSMatt Jacob PCIM_CMD_BUSMASTEREN | 519d951bbcaSMatt Jacob PCIM_CMD_INVEN; 520222bb542SMatt Jacob pci_cfgwrite(cfid, PCIR_COMMAND, 2, data); 521ab6d0040SMatt Jacob 522d951bbcaSMatt Jacob /* 523222bb542SMatt Jacob * Make sure the Cache Line Size register is set sensibly. 524d951bbcaSMatt Jacob */ 525222bb542SMatt Jacob data = pci_cfgread(cfid, PCIR_CACHELNSZ, 1); 526ab6d0040SMatt Jacob if (data != linesz) { 527d951bbcaSMatt Jacob data = PCI_DFLT_LNSZ; 528a95ae193SMatt Jacob CFGPRINTF("%s: set PCI line size to %d\n", isp->isp_name, data); 529222bb542SMatt Jacob pci_cfgwrite(cfid, PCIR_CACHELNSZ, data, 1); 530d951bbcaSMatt Jacob } 531ab6d0040SMatt Jacob 532d951bbcaSMatt Jacob /* 533d951bbcaSMatt Jacob * Make sure the Latency Timer is sane. 534d951bbcaSMatt Jacob */ 535222bb542SMatt Jacob data = pci_cfgread(cfid, PCIR_LATTIMER, 1); 536d951bbcaSMatt Jacob if (data < PCI_DFLT_LTNCY) { 537d951bbcaSMatt Jacob data = PCI_DFLT_LTNCY; 538a95ae193SMatt Jacob CFGPRINTF("%s: set PCI latency to %d\n", isp->isp_name, data); 539222bb542SMatt Jacob pci_cfgwrite(cfid, PCIR_LATTIMER, data, 1); 540d951bbcaSMatt Jacob } 541ab6d0040SMatt Jacob 542ab6d0040SMatt Jacob /* 543ab6d0040SMatt Jacob * Make sure we've disabled the ROM. 544ab6d0040SMatt Jacob */ 545222bb542SMatt Jacob data = pci_cfgread(cfid, PCIR_ROMADDR, 4); 546ab6d0040SMatt Jacob data &= ~1; 547222bb542SMatt Jacob pci_cfgwrite(cfid, PCIR_ROMADDR, data, 4); 548d951bbcaSMatt Jacob ISP_UNLOCK(isp); 549d951bbcaSMatt Jacob 550086646f7SJustin T. Gibbs if (bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT, 551222bb542SMatt Jacob BUS_SPACE_MAXADDR, NULL, NULL, lim + 1, 552222bb542SMatt Jacob 255, lim, 0, &pcs->parent_dmat) != 0) { 553d720e6d5SJustin T. Gibbs printf("%s: could not create master dma tag\n", isp->isp_name); 554d720e6d5SJustin T. Gibbs free(pcs, M_DEVBUF); 555d720e6d5SJustin T. Gibbs return; 556d720e6d5SJustin T. Gibbs } 557222bb542SMatt Jacob if (pci_map_int(cfid, (void (*)(void *))isp_intr, 55865adb54cSMatt Jacob (void *)isp, &IMASK) == 0) { 5599bffbcd4SBruce Evans printf("%s: could not map interrupt\n", isp->isp_name); 56065adb54cSMatt Jacob free(pcs, M_DEVBUF); 56165adb54cSMatt Jacob return; 56265adb54cSMatt Jacob } 56365adb54cSMatt Jacob 564222bb542SMatt Jacob pcs->pci_id = cfid; 565d951bbcaSMatt Jacob #ifdef SCSI_ISP_NO_FWLOAD_MASK 566d951bbcaSMatt Jacob if (SCSI_ISP_NO_FWLOAD_MASK && (SCSI_ISP_NO_FWLOAD_MASK & (1 << unit))) 567d951bbcaSMatt Jacob isp->isp_confopts |= ISP_CFG_NORELOAD; 568d951bbcaSMatt Jacob #endif 569222bb542SMatt Jacob if (getenv_int("isp_no_fwload", &bitmap)) { 570222bb542SMatt Jacob if (bitmap & (1 << unit)) 571222bb542SMatt Jacob isp->isp_confopts |= ISP_CFG_NORELOAD; 572222bb542SMatt Jacob } 573222bb542SMatt Jacob if (getenv_int("isp_fwload", &bitmap)) { 574222bb542SMatt Jacob if (bitmap & (1 << unit)) 575222bb542SMatt Jacob isp->isp_confopts &= ~ISP_CFG_NORELOAD; 576222bb542SMatt Jacob } 577222bb542SMatt Jacob 578d951bbcaSMatt Jacob #ifdef SCSI_ISP_NO_NVRAM_MASK 579ab6d0040SMatt Jacob if (SCSI_ISP_NO_NVRAM_MASK && (SCSI_ISP_NO_NVRAM_MASK & (1 << unit))) { 580ab6d0040SMatt Jacob printf("%s: ignoring NVRAM\n", isp->isp_name); 581d951bbcaSMatt Jacob isp->isp_confopts |= ISP_CFG_NONVRAM; 582ab6d0040SMatt Jacob } 583d951bbcaSMatt Jacob #endif 584222bb542SMatt Jacob if (getenv_int("isp_no_nvram", &bitmap)) { 585222bb542SMatt Jacob if (bitmap & (1 << unit)) 586222bb542SMatt Jacob isp->isp_confopts |= ISP_CFG_NONVRAM; 587222bb542SMatt Jacob } 588222bb542SMatt Jacob if (getenv_int("isp_nvram", &bitmap)) { 589222bb542SMatt Jacob if (bitmap & (1 << unit)) 590222bb542SMatt Jacob isp->isp_confopts &= ~ISP_CFG_NONVRAM; 591222bb542SMatt Jacob } 592222bb542SMatt Jacob 593222bb542SMatt Jacob #ifdef SCSI_ISP_FCDUPLEX 594222bb542SMatt Jacob if (IS_FC(isp)) { 595222bb542SMatt Jacob if (SCSI_ISP_FCDUPLEX && (SCSI_ISP_FCDUPLEX & (1 << unit))) { 596222bb542SMatt Jacob isp->isp_confopts |= ISP_CFG_FULL_DUPLEX; 597222bb542SMatt Jacob } 598222bb542SMatt Jacob } 599222bb542SMatt Jacob #endif 600222bb542SMatt Jacob if (getenv_int("isp_fcduplex", &bitmap)) { 601222bb542SMatt Jacob if (bitmap & (1 << unit)) 602222bb542SMatt Jacob isp->isp_confopts |= ISP_CFG_FULL_DUPLEX; 603222bb542SMatt Jacob } 604222bb542SMatt Jacob if (getenv_int("isp_no_fcduplex", &bitmap)) { 605222bb542SMatt Jacob if (bitmap & (1 << unit)) 606222bb542SMatt Jacob isp->isp_confopts &= ~ISP_CFG_FULL_DUPLEX; 607222bb542SMatt Jacob } 608222bb542SMatt Jacob /* 6099637d68cSMatt Jacob * Look for overriding WWN. This is a Node WWN so it binds to 6109637d68cSMatt Jacob * all FC instances. A Port WWN will be constructed from it 6119637d68cSMatt Jacob * as appropriate. 612222bb542SMatt Jacob */ 6139637d68cSMatt Jacob #ifdef SCSI_ISP_WWN 6149637d68cSMatt Jacob isp->isp_osinfo.default_wwn = strtoq(name, &vtp, 16); 6159637d68cSMatt Jacob if (vtp != name && *vtp == 0) { 6169637d68cSMatt Jacob isp->isp_confopts |= ISP_CFG_OWNWWN; 6179637d68cSMatt Jacob } else 6189637d68cSMatt Jacob #endif 6199637d68cSMatt Jacob if (!getenv_quad("isp_wwn", (quad_t *) &isp->isp_osinfo.default_wwn)) { 6209637d68cSMatt Jacob int i; 6219637d68cSMatt Jacob u_int64_t seed = (u_int64_t) (intptr_t) isp; 622222bb542SMatt Jacob 6239637d68cSMatt Jacob seed <<= 16; 6249637d68cSMatt Jacob seed &= ((1LL << 48) - 1LL); 625222bb542SMatt Jacob /* 626222bb542SMatt Jacob * This isn't very random, but it's the best we can do for 6279637d68cSMatt Jacob * the real edge case of cards that don't have WWNs. If 6289637d68cSMatt Jacob * you recompile a new vers.c, you'll get a different WWN. 629222bb542SMatt Jacob */ 6309637d68cSMatt Jacob for (i = 0; version[i] != 0; i++) { 6319637d68cSMatt Jacob seed += version[i]; 6329637d68cSMatt Jacob } 6339637d68cSMatt Jacob /* 6349637d68cSMatt Jacob * Make sure the top nibble has something vaguely sensible. 6359637d68cSMatt Jacob */ 6369637d68cSMatt Jacob isp->isp_osinfo.default_wwn |= (4LL << 60) | seed; 6379637d68cSMatt Jacob } else { 6389637d68cSMatt Jacob isp->isp_confopts |= ISP_CFG_OWNWWN; 639222bb542SMatt Jacob } 640a95ae193SMatt Jacob (void) getenv_int("isp_debug", &isp_debug); 641d720e6d5SJustin T. Gibbs ISP_LOCK(isp); 64265adb54cSMatt Jacob isp_reset(isp); 64365adb54cSMatt Jacob if (isp->isp_state != ISP_RESETSTATE) { 644222bb542SMatt Jacob (void) pci_unmap_int(cfid); 645d720e6d5SJustin T. Gibbs ISP_UNLOCK(isp); 64665adb54cSMatt Jacob free(pcs, M_DEVBUF); 64765adb54cSMatt Jacob return; 64865adb54cSMatt Jacob } 64965adb54cSMatt Jacob isp_init(isp); 65065adb54cSMatt Jacob if (isp->isp_state != ISP_INITSTATE) { 651d59bd469SMatt Jacob /* If we're a Fibre Channel Card, we allow deferred attach */ 652222bb542SMatt Jacob if (IS_SCSI(isp)) { 65365adb54cSMatt Jacob isp_uninit(isp); 654222bb542SMatt Jacob (void) pci_unmap_int(cfid); /* Does nothing */ 655c6608df3SMatt Jacob ISP_UNLOCK(isp); 65665adb54cSMatt Jacob free(pcs, M_DEVBUF); 657c6608df3SMatt Jacob return; 658d59bd469SMatt Jacob } 65965adb54cSMatt Jacob } 66065adb54cSMatt Jacob isp_attach(isp); 66165adb54cSMatt Jacob if (isp->isp_state != ISP_RUNSTATE) { 662d59bd469SMatt Jacob /* If we're a Fibre Channel Card, we allow deferred attach */ 66392c49d78SMatt Jacob if (IS_SCSI(isp)) { 66465adb54cSMatt Jacob isp_uninit(isp); 665222bb542SMatt Jacob (void) pci_unmap_int(cfid); /* Does nothing */ 666c6608df3SMatt Jacob ISP_UNLOCK(isp); 66765adb54cSMatt Jacob free(pcs, M_DEVBUF); 668c6608df3SMatt Jacob return; 66965adb54cSMatt Jacob } 670d59bd469SMatt Jacob } 671d720e6d5SJustin T. Gibbs ISP_UNLOCK(isp); 67265adb54cSMatt Jacob } 67365adb54cSMatt Jacob 67465adb54cSMatt Jacob static u_int16_t 675d59bd469SMatt Jacob isp_pci_rd_reg(isp, regoff) 676d59bd469SMatt Jacob struct ispsoftc *isp; 677d59bd469SMatt Jacob int regoff; 67865adb54cSMatt Jacob { 67965adb54cSMatt Jacob u_int16_t rv; 68065adb54cSMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 681d59bd469SMatt Jacob int offset, oldconf = 0; 68265adb54cSMatt Jacob 683d59bd469SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 68465adb54cSMatt Jacob /* 68565adb54cSMatt Jacob * We will assume that someone has paused the RISC processor. 68665adb54cSMatt Jacob */ 687d59bd469SMatt Jacob oldconf = isp_pci_rd_reg(isp, BIU_CONF1); 688d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oldconf | BIU_PCI_CONF1_SXP); 68965adb54cSMatt Jacob } 690d59bd469SMatt Jacob offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT]; 691d59bd469SMatt Jacob offset += (regoff & 0xff); 69265adb54cSMatt Jacob rv = bus_space_read_2(pcs->pci_st, pcs->pci_sh, offset); 693d59bd469SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 694d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oldconf); 69565adb54cSMatt Jacob } 69665adb54cSMatt Jacob return (rv); 69765adb54cSMatt Jacob } 69865adb54cSMatt Jacob 69965adb54cSMatt Jacob static void 700d59bd469SMatt Jacob isp_pci_wr_reg(isp, regoff, val) 701d59bd469SMatt Jacob struct ispsoftc *isp; 702d59bd469SMatt Jacob int regoff; 703d59bd469SMatt Jacob u_int16_t val; 70465adb54cSMatt Jacob { 70565adb54cSMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 706d59bd469SMatt Jacob int offset, oldconf = 0; 707d59bd469SMatt Jacob 708d59bd469SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 70965adb54cSMatt Jacob /* 71065adb54cSMatt Jacob * We will assume that someone has paused the RISC processor. 71165adb54cSMatt Jacob */ 712d59bd469SMatt Jacob oldconf = isp_pci_rd_reg(isp, BIU_CONF1); 713d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oldconf | BIU_PCI_CONF1_SXP); 71465adb54cSMatt Jacob } 715d59bd469SMatt Jacob offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT]; 716d59bd469SMatt Jacob offset += (regoff & 0xff); 71765adb54cSMatt Jacob bus_space_write_2(pcs->pci_st, pcs->pci_sh, offset, val); 718d59bd469SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 719d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oldconf); 72065adb54cSMatt Jacob } 72165adb54cSMatt Jacob } 72265adb54cSMatt Jacob 723d59bd469SMatt Jacob #ifndef ISP_DISABLE_1080_SUPPORT 724d59bd469SMatt Jacob static u_int16_t 725d59bd469SMatt Jacob isp_pci_rd_reg_1080(isp, regoff) 726d59bd469SMatt Jacob struct ispsoftc *isp; 727d59bd469SMatt Jacob int regoff; 728d59bd469SMatt Jacob { 72922e1dc85SMatt Jacob u_int16_t rv, oc = 0; 730d59bd469SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 73122e1dc85SMatt Jacob int offset; 732d59bd469SMatt Jacob 73322e1dc85SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK || 73422e1dc85SMatt Jacob (regoff & _BLK_REG_MASK) == (SXP_BLOCK|SXP_BANK1_SELECT)) { 73522e1dc85SMatt Jacob u_int16_t tc; 736d59bd469SMatt Jacob /* 737d59bd469SMatt Jacob * We will assume that someone has paused the RISC processor. 738d59bd469SMatt Jacob */ 739d59bd469SMatt Jacob oc = isp_pci_rd_reg(isp, BIU_CONF1); 74022e1dc85SMatt Jacob tc = oc & ~BIU_PCI1080_CONF1_DMA; 74122e1dc85SMatt Jacob if (regoff & SXP_BANK1_SELECT) 74222e1dc85SMatt Jacob tc |= BIU_PCI1080_CONF1_SXP1; 74322e1dc85SMatt Jacob else 74422e1dc85SMatt Jacob tc |= BIU_PCI1080_CONF1_SXP0; 74522e1dc85SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, tc); 746d59bd469SMatt Jacob } else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) { 747d59bd469SMatt Jacob oc = isp_pci_rd_reg(isp, BIU_CONF1); 748d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oc | BIU_PCI1080_CONF1_DMA); 749d59bd469SMatt Jacob } 750d59bd469SMatt Jacob offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT]; 751d59bd469SMatt Jacob offset += (regoff & 0xff); 752d59bd469SMatt Jacob rv = bus_space_read_2(pcs->pci_st, pcs->pci_sh, offset); 75322e1dc85SMatt Jacob if (oc) { 754d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oc); 755d59bd469SMatt Jacob } 756d59bd469SMatt Jacob return (rv); 757d59bd469SMatt Jacob } 758d59bd469SMatt Jacob 759d59bd469SMatt Jacob static void 760d59bd469SMatt Jacob isp_pci_wr_reg_1080(isp, regoff, val) 761d59bd469SMatt Jacob struct ispsoftc *isp; 762d59bd469SMatt Jacob int regoff; 763d59bd469SMatt Jacob u_int16_t val; 764d59bd469SMatt Jacob { 765d59bd469SMatt Jacob struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 766d59bd469SMatt Jacob int offset, oc = 0; 767d59bd469SMatt Jacob 76822e1dc85SMatt Jacob if ((regoff & _BLK_REG_MASK) == SXP_BLOCK || 76922e1dc85SMatt Jacob (regoff & _BLK_REG_MASK) == (SXP_BLOCK|SXP_BANK1_SELECT)) { 77022e1dc85SMatt Jacob u_int16_t tc; 771d59bd469SMatt Jacob /* 772d59bd469SMatt Jacob * We will assume that someone has paused the RISC processor. 773d59bd469SMatt Jacob */ 774d59bd469SMatt Jacob oc = isp_pci_rd_reg(isp, BIU_CONF1); 77522e1dc85SMatt Jacob tc = oc & ~BIU_PCI1080_CONF1_DMA; 77622e1dc85SMatt Jacob if (regoff & SXP_BANK1_SELECT) 77722e1dc85SMatt Jacob tc |= BIU_PCI1080_CONF1_SXP1; 77822e1dc85SMatt Jacob else 77922e1dc85SMatt Jacob tc |= BIU_PCI1080_CONF1_SXP0; 78022e1dc85SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, tc); 781d59bd469SMatt Jacob } else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) { 782d59bd469SMatt Jacob oc = isp_pci_rd_reg(isp, BIU_CONF1); 783d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oc | BIU_PCI1080_CONF1_DMA); 784d59bd469SMatt Jacob } 785d59bd469SMatt Jacob offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT]; 786d59bd469SMatt Jacob offset += (regoff & 0xff); 787d59bd469SMatt Jacob bus_space_write_2(pcs->pci_st, pcs->pci_sh, offset, val); 78822e1dc85SMatt Jacob if (oc) { 789d59bd469SMatt Jacob isp_pci_wr_reg(isp, BIU_CONF1, oc); 790d59bd469SMatt Jacob } 791d59bd469SMatt Jacob } 792d59bd469SMatt Jacob #endif 793d59bd469SMatt Jacob 794d59bd469SMatt Jacob 795d720e6d5SJustin T. Gibbs static void isp_map_rquest __P((void *, bus_dma_segment_t *, int, int)); 796d720e6d5SJustin T. Gibbs static void isp_map_result __P((void *, bus_dma_segment_t *, int, int)); 797d720e6d5SJustin T. Gibbs static void isp_map_fcscrt __P((void *, bus_dma_segment_t *, int, int)); 798d720e6d5SJustin T. Gibbs 799222bb542SMatt Jacob struct imush { 800222bb542SMatt Jacob struct ispsoftc *isp; 801222bb542SMatt Jacob int error; 802222bb542SMatt Jacob }; 803222bb542SMatt Jacob 804d720e6d5SJustin T. Gibbs static void 80517e318c6SMatt Jacob isp_map_rquest(void *arg, bus_dma_segment_t *segs, int nseg, int error) 806d720e6d5SJustin T. Gibbs { 807222bb542SMatt Jacob struct imush *imushp = (struct imush *) arg; 808222bb542SMatt Jacob if (error) { 809222bb542SMatt Jacob imushp->error = error; 810222bb542SMatt Jacob } else { 811222bb542SMatt Jacob imushp->isp->isp_rquest_dma = segs->ds_addr; 812222bb542SMatt Jacob } 813d720e6d5SJustin T. Gibbs } 814d720e6d5SJustin T. Gibbs 815d720e6d5SJustin T. Gibbs static void 81617e318c6SMatt Jacob isp_map_result(void *arg, bus_dma_segment_t *segs, int nseg, int error) 817d720e6d5SJustin T. Gibbs { 818222bb542SMatt Jacob struct imush *imushp = (struct imush *) arg; 819222bb542SMatt Jacob if (error) { 820222bb542SMatt Jacob imushp->error = error; 821222bb542SMatt Jacob } else { 822222bb542SMatt Jacob imushp->isp->isp_result_dma = segs->ds_addr; 823222bb542SMatt Jacob } 824d720e6d5SJustin T. Gibbs } 825d720e6d5SJustin T. Gibbs 826d720e6d5SJustin T. Gibbs static void 82717e318c6SMatt Jacob isp_map_fcscrt(void *arg, bus_dma_segment_t *segs, int nseg, int error) 828d720e6d5SJustin T. Gibbs { 829222bb542SMatt Jacob struct imush *imushp = (struct imush *) arg; 830222bb542SMatt Jacob if (error) { 831222bb542SMatt Jacob imushp->error = error; 832222bb542SMatt Jacob } else { 833222bb542SMatt Jacob fcparam *fcp = imushp->isp->isp_param; 834d720e6d5SJustin T. Gibbs fcp->isp_scdma = segs->ds_addr; 835d720e6d5SJustin T. Gibbs } 836222bb542SMatt Jacob } 837d720e6d5SJustin T. Gibbs 838d720e6d5SJustin T. Gibbs static int 83917e318c6SMatt Jacob isp_pci_mbxdma(struct ispsoftc *isp) 840d720e6d5SJustin T. Gibbs { 841d720e6d5SJustin T. Gibbs struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp; 842d720e6d5SJustin T. Gibbs caddr_t base; 843d720e6d5SJustin T. Gibbs u_int32_t len; 844d720e6d5SJustin T. Gibbs int i, error; 845222bb542SMatt Jacob bus_size_t lim; 846222bb542SMatt Jacob struct imush im; 847222bb542SMatt Jacob 848222bb542SMatt Jacob 849a95ae193SMatt Jacob /* 850a95ae193SMatt Jacob * Already been here? If so, leave... 851a95ae193SMatt Jacob */ 852a95ae193SMatt Jacob if (isp->isp_rquest) { 853a95ae193SMatt Jacob return (0); 854a95ae193SMatt Jacob } 855a95ae193SMatt Jacob 856a95ae193SMatt Jacob len = sizeof (ISP_SCSI_XFER_T **) * isp->isp_maxcmds; 857a95ae193SMatt Jacob isp->isp_xflist = (ISP_SCSI_XFER_T **) malloc(len, M_DEVBUF, M_WAITOK); 858a95ae193SMatt Jacob if (isp->isp_xflist == NULL) { 859a95ae193SMatt Jacob printf("%s: can't alloc xflist array\n", isp->isp_name); 860a95ae193SMatt Jacob return (1); 861a95ae193SMatt Jacob } 862a95ae193SMatt Jacob bzero(isp->isp_xflist, len); 863a95ae193SMatt Jacob len = sizeof (bus_dmamap_t) * isp->isp_maxcmds; 864a95ae193SMatt Jacob pci->dmaps = (bus_dmamap_t *) malloc(len, M_DEVBUF, M_WAITOK); 865a95ae193SMatt Jacob if (pci->dmaps == NULL) { 866a95ae193SMatt Jacob printf("%s: can't alloc dma maps\n", isp->isp_name); 867a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 868a95ae193SMatt Jacob return (1); 869a95ae193SMatt Jacob } 870a95ae193SMatt Jacob 87122e1dc85SMatt Jacob if (IS_FC(isp) || IS_ULTRA2(isp)) 872222bb542SMatt Jacob lim = BUS_SPACE_MAXADDR + 1; 873222bb542SMatt Jacob else 874222bb542SMatt Jacob lim = BUS_SPACE_MAXADDR_24BIT + 1; 875d720e6d5SJustin T. Gibbs 876d720e6d5SJustin T. Gibbs /* 877d720e6d5SJustin T. Gibbs * Allocate and map the request, result queues, plus FC scratch area. 878d720e6d5SJustin T. Gibbs */ 879d720e6d5SJustin T. Gibbs len = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN); 880d720e6d5SJustin T. Gibbs len += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN); 881222bb542SMatt Jacob if (IS_FC(isp)) { 882d720e6d5SJustin T. Gibbs len += ISP2100_SCRLEN; 883d720e6d5SJustin T. Gibbs } 884222bb542SMatt Jacob if (bus_dma_tag_create(pci->parent_dmat, PAGE_SIZE, lim, 885222bb542SMatt Jacob BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, len, 1, 886222bb542SMatt Jacob BUS_SPACE_MAXSIZE_32BIT, 0, &pci->cntrol_dmat) != 0) { 887d720e6d5SJustin T. Gibbs printf("%s: cannot create a dma tag for control spaces\n", 888d720e6d5SJustin T. Gibbs isp->isp_name); 889a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 890a95ae193SMatt Jacob free(pci->dmaps, M_DEVBUF); 891d720e6d5SJustin T. Gibbs return (1); 892d720e6d5SJustin T. Gibbs } 893d720e6d5SJustin T. Gibbs if (bus_dmamem_alloc(pci->cntrol_dmat, (void **)&base, 894d720e6d5SJustin T. Gibbs BUS_DMA_NOWAIT, &pci->cntrol_dmap) != 0) { 8954873663cSMatt Jacob printf("%s: cannot allocate %d bytes of CCB memory\n", 8964873663cSMatt Jacob isp->isp_name, len); 897a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 898a95ae193SMatt Jacob free(pci->dmaps, M_DEVBUF); 899d720e6d5SJustin T. Gibbs return (1); 900d720e6d5SJustin T. Gibbs } 901d720e6d5SJustin T. Gibbs 902d720e6d5SJustin T. Gibbs isp->isp_rquest = base; 903222bb542SMatt Jacob im.isp = isp; 904222bb542SMatt Jacob im.error = 0; 905d720e6d5SJustin T. Gibbs bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap, isp->isp_rquest, 906222bb542SMatt Jacob ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN), isp_map_rquest, &im, 0); 907222bb542SMatt Jacob if (im.error) { 908222bb542SMatt Jacob printf("%s: error %d loading dma map for DMA request queue\n", 909222bb542SMatt Jacob isp->isp_name, im.error); 910a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 911a95ae193SMatt Jacob free(pci->dmaps, M_DEVBUF); 912a95ae193SMatt Jacob isp->isp_rquest = NULL; 913222bb542SMatt Jacob return (1); 914222bb542SMatt Jacob } 915d720e6d5SJustin T. Gibbs isp->isp_result = base + ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN); 916222bb542SMatt Jacob im.error = 0; 917d720e6d5SJustin T. Gibbs bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap, isp->isp_result, 918222bb542SMatt Jacob ISP_QUEUE_SIZE(RESULT_QUEUE_LEN), isp_map_result, &im, 0); 919222bb542SMatt Jacob if (im.error) { 920222bb542SMatt Jacob printf("%s: error %d loading dma map for DMA result queue\n", 921222bb542SMatt Jacob isp->isp_name, 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 } 927d720e6d5SJustin T. Gibbs 928a95ae193SMatt Jacob for (i = 0; i < isp->isp_maxcmds; i++) { 929d720e6d5SJustin T. Gibbs error = bus_dmamap_create(pci->parent_dmat, 0, &pci->dmaps[i]); 930d720e6d5SJustin T. Gibbs if (error) { 931a95ae193SMatt Jacob printf("%s: error %d creating per-cmd DMA maps\n", 932d720e6d5SJustin T. Gibbs isp->isp_name, error); 933a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 934a95ae193SMatt Jacob free(pci->dmaps, M_DEVBUF); 935a95ae193SMatt Jacob isp->isp_rquest = NULL; 936d720e6d5SJustin T. Gibbs return (1); 937d720e6d5SJustin T. Gibbs } 938d720e6d5SJustin T. Gibbs } 939a95ae193SMatt Jacob 940222bb542SMatt Jacob if (IS_FC(isp)) { 94192c49d78SMatt Jacob fcparam *fcp = (fcparam *) isp->isp_param; 94292c49d78SMatt Jacob fcp->isp_scratch = base + 94392c49d78SMatt Jacob ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN) + 94492c49d78SMatt Jacob ISP_QUEUE_SIZE(RESULT_QUEUE_LEN); 945222bb542SMatt Jacob im.error = 0; 94692c49d78SMatt Jacob bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap, 947222bb542SMatt Jacob fcp->isp_scratch, ISP2100_SCRLEN, isp_map_fcscrt, &im, 0); 948222bb542SMatt Jacob if (im.error) { 949222bb542SMatt Jacob printf("%s: error %d loading FC scratch area\n", 950222bb542SMatt Jacob isp->isp_name, im.error); 951a95ae193SMatt Jacob free(isp->isp_xflist, M_DEVBUF); 952a95ae193SMatt Jacob free(pci->dmaps, M_DEVBUF); 953a95ae193SMatt Jacob isp->isp_rquest = NULL; 954222bb542SMatt Jacob return (1); 955222bb542SMatt Jacob } 95692c49d78SMatt Jacob } 957d720e6d5SJustin T. Gibbs return (0); 958d720e6d5SJustin T. Gibbs } 959d720e6d5SJustin T. Gibbs 960d720e6d5SJustin T. Gibbs typedef struct { 961d720e6d5SJustin T. Gibbs struct ispsoftc *isp; 9629e11e5beSMatt Jacob void *cmd_token; 9639e11e5beSMatt Jacob void *rq; 9649637d68cSMatt Jacob u_int16_t *iptrp; 9659637d68cSMatt Jacob u_int16_t optr; 966d720e6d5SJustin T. Gibbs u_int error; 967d720e6d5SJustin T. Gibbs } mush_t; 968d720e6d5SJustin T. Gibbs 9694873663cSMatt Jacob #define MUSHERR_NOQENTRIES -2 9704873663cSMatt Jacob 9719e11e5beSMatt Jacob #ifdef ISP_TARGET_MODE 9729e11e5beSMatt Jacob /* 9739e11e5beSMatt Jacob * We need to handle DMA for target mode differently from initiator mode. 9749e11e5beSMatt Jacob * 9759e11e5beSMatt Jacob * DMA mapping and construction and submission of CTIO Request Entries 9769e11e5beSMatt Jacob * and rendevous for completion are very tightly coupled because we start 9779e11e5beSMatt Jacob * out by knowing (per platform) how much data we have to move, but we 9789e11e5beSMatt Jacob * don't know, up front, how many DMA mapping segments will have to be used 9799e11e5beSMatt Jacob * cover that data, so we don't know how many CTIO Request Entries we 9809e11e5beSMatt Jacob * will end up using. Further, for performance reasons we may want to 9819e11e5beSMatt Jacob * (on the last CTIO for Fibre Channel), send status too (if all went well). 9829e11e5beSMatt Jacob * 9839e11e5beSMatt Jacob * The standard vector still goes through isp_pci_dmasetup, but the callback 9849e11e5beSMatt Jacob * for the DMA mapping routines comes here instead with the whole transfer 9859e11e5beSMatt Jacob * mapped and a pointer to a partially filled in already allocated request 9869e11e5beSMatt Jacob * queue entry. We finish the job. 9879e11e5beSMatt Jacob */ 9889e11e5beSMatt Jacob static void dma2_tgt __P((void *, bus_dma_segment_t *, int, int)); 9899e11e5beSMatt Jacob static void dma2_tgt_fc __P((void *, bus_dma_segment_t *, int, int)); 9909e11e5beSMatt Jacob 991d720e6d5SJustin T. Gibbs static void 9929e11e5beSMatt Jacob dma2_tgt(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 993d720e6d5SJustin T. Gibbs { 994d720e6d5SJustin T. Gibbs mush_t *mp; 9959e11e5beSMatt Jacob struct ccb_scsiio *csio; 996d720e6d5SJustin T. Gibbs struct isp_pcisoftc *pci; 997d720e6d5SJustin T. Gibbs bus_dmamap_t *dp; 9989e11e5beSMatt Jacob u_int8_t scsi_status, send_status; 9999e11e5beSMatt Jacob ct_entry_t *cto; 10009e11e5beSMatt Jacob u_int32_t handle; 10019e11e5beSMatt Jacob int nctios; 1002d720e6d5SJustin T. Gibbs 1003d720e6d5SJustin T. Gibbs mp = (mush_t *) arg; 1004d720e6d5SJustin T. Gibbs if (error) { 1005d720e6d5SJustin T. Gibbs mp->error = error; 1006d720e6d5SJustin T. Gibbs return; 1007d720e6d5SJustin T. Gibbs } 1008d720e6d5SJustin T. Gibbs 1009d720e6d5SJustin T. Gibbs if (nseg < 1) { 10109e11e5beSMatt Jacob printf("%s: bad segment count (%d)\n", mp->isp->isp_name, nseg); 1011d720e6d5SJustin T. Gibbs mp->error = EFAULT; 1012d720e6d5SJustin T. Gibbs return; 1013d720e6d5SJustin T. Gibbs } 1014a95ae193SMatt Jacob 10159e11e5beSMatt Jacob csio = mp->cmd_token; 10169e11e5beSMatt Jacob cto = mp->rq; 10179e11e5beSMatt Jacob 10189e11e5beSMatt Jacob /* 10199e11e5beSMatt Jacob * Save handle, and potentially any SCSI status, which 10209e11e5beSMatt Jacob * we'll reinsert on the last CTIO we're going to send. 10219e11e5beSMatt Jacob */ 10229e11e5beSMatt Jacob handle = cto->ct_reserved; 10239e11e5beSMatt Jacob cto->ct_reserved = 0; 10249e11e5beSMatt Jacob scsi_status = cto->ct_scsi_status; 10259e11e5beSMatt Jacob cto->ct_scsi_status = 0; 10269e11e5beSMatt Jacob send_status = cto->ct_flags & CT_SENDSTATUS; 10279e11e5beSMatt Jacob cto->ct_flags &= ~CT_SENDSTATUS; 10289e11e5beSMatt Jacob 10299e11e5beSMatt Jacob pci = (struct isp_pcisoftc *)mp->isp; 10309e11e5beSMatt Jacob dp = &pci->dmaps[handle - 1]; 10319e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 1032d720e6d5SJustin T. Gibbs bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREREAD); 1033d720e6d5SJustin T. Gibbs } else { 1034d720e6d5SJustin T. Gibbs bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREWRITE); 1035d720e6d5SJustin T. Gibbs } 1036d720e6d5SJustin T. Gibbs 10379e11e5beSMatt Jacob nctios = nseg / ISP_RQDSEG; 10389e11e5beSMatt Jacob if (nseg % ISP_RQDSEG) { 10399e11e5beSMatt Jacob nctios++; 10409e11e5beSMatt Jacob } 10419e11e5beSMatt Jacob 10429e11e5beSMatt Jacob cto->ct_xfrlen = 0; 10439e11e5beSMatt Jacob cto->ct_resid = 0; 10449e11e5beSMatt Jacob cto->ct_seg_count = 0; 10459e11e5beSMatt Jacob bzero(cto->ct_dataseg, sizeof (cto->ct_dataseg)); 10469e11e5beSMatt Jacob 10479e11e5beSMatt Jacob while (nctios--) { 10489e11e5beSMatt Jacob int seg, seglim; 10499e11e5beSMatt Jacob 10509e11e5beSMatt Jacob seglim = nseg; 10519e11e5beSMatt Jacob if (seglim > ISP_RQDSEG) 10529e11e5beSMatt Jacob seglim = ISP_RQDSEG; 10539e11e5beSMatt Jacob 10549e11e5beSMatt Jacob for (seg = 0; seg < seglim; seg++) { 10559e11e5beSMatt Jacob cto->ct_dataseg[seg].ds_base = dm_segs->ds_addr; 10569e11e5beSMatt Jacob cto->ct_dataseg[seg].ds_count = dm_segs->ds_len; 10579e11e5beSMatt Jacob cto->ct_xfrlen += dm_segs->ds_len; 10589e11e5beSMatt Jacob dm_segs++; 10599e11e5beSMatt Jacob } 10609e11e5beSMatt Jacob 10619e11e5beSMatt Jacob cto->ct_seg_count = seg; 10629e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 10639e11e5beSMatt Jacob cto->ct_flags |= CT_DATA_IN; 10649e11e5beSMatt Jacob } else { 10659e11e5beSMatt Jacob cto->ct_flags |= CT_DATA_OUT; 10669e11e5beSMatt Jacob } 10679e11e5beSMatt Jacob 10689e11e5beSMatt Jacob if (nctios == 0) { 10699e11e5beSMatt Jacob /* 10709e11e5beSMatt Jacob * We're the last in a sequence of CTIOs, so mark this 10719e11e5beSMatt Jacob * CTIO and save the handle to the CCB such that when 10729e11e5beSMatt Jacob * this CTIO completes we can free dma resources and 10739e11e5beSMatt Jacob * do whatever else we need to do to finish the rest 10749e11e5beSMatt Jacob * of the command. 10759e11e5beSMatt Jacob */ 10769e11e5beSMatt Jacob cto->ct_header.rqs_seqno = 1; 10779e11e5beSMatt Jacob cto->ct_reserved = handle; 10789e11e5beSMatt Jacob cto->ct_scsi_status = scsi_status; 10799e11e5beSMatt Jacob cto->ct_flags |= send_status; 10809e11e5beSMatt Jacob ISP_TDQE(mp->isp, "last dma2_tgt", *mp->iptrp, cto); 10819e11e5beSMatt Jacob } else { 10829e11e5beSMatt Jacob ct_entry_t *octo = cto; 10839e11e5beSMatt Jacob cto->ct_reserved = 0; 10849e11e5beSMatt Jacob cto->ct_header.rqs_seqno = 0; 10859e11e5beSMatt Jacob ISP_TDQE(mp->isp, "dma2_tgt", *mp->iptrp, cto); 10869e11e5beSMatt Jacob cto = (ct_entry_t *) 10879e11e5beSMatt Jacob ISP_QUEUE_ENTRY(mp->isp->isp_rquest, *mp->iptrp); 10889e11e5beSMatt Jacob *mp->iptrp = 10899e11e5beSMatt Jacob ISP_NXT_QENTRY(*mp->iptrp, RQUEST_QUEUE_LEN); 10909e11e5beSMatt Jacob if (*mp->iptrp == mp->optr) { 10919e11e5beSMatt Jacob printf("%s: Queue Overflow in dma2_tgt\n", 10929e11e5beSMatt Jacob mp->isp->isp_name); 10939e11e5beSMatt Jacob mp->error = MUSHERR_NOQENTRIES; 10949e11e5beSMatt Jacob return; 10959e11e5beSMatt Jacob } 10969e11e5beSMatt Jacob /* 10979e11e5beSMatt Jacob * Fill in the new CTIO with info from the old one. 10989e11e5beSMatt Jacob */ 10999e11e5beSMatt Jacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO; 11009e11e5beSMatt Jacob cto->ct_header.rqs_entry_count = 1; 11019e11e5beSMatt Jacob cto->ct_header.rqs_flags = 0; 11029e11e5beSMatt Jacob /* ct_header.rqs_seqno && ct_reserved filled in later */ 11039e11e5beSMatt Jacob cto->ct_lun = octo->ct_lun; 11049e11e5beSMatt Jacob cto->ct_iid = octo->ct_iid; 11059e11e5beSMatt Jacob cto->ct_reserved2 = octo->ct_reserved2; 11069e11e5beSMatt Jacob cto->ct_tgt = octo->ct_tgt; 11079e11e5beSMatt Jacob cto->ct_flags = octo->ct_flags & ~CT_DATAMASK; 11089e11e5beSMatt Jacob cto->ct_status = 0; 11099e11e5beSMatt Jacob cto->ct_scsi_status = 0; 11109e11e5beSMatt Jacob cto->ct_tag_val = octo->ct_tag_val; 11119e11e5beSMatt Jacob cto->ct_tag_type = octo->ct_tag_type; 11129e11e5beSMatt Jacob cto->ct_xfrlen = 0; 11139e11e5beSMatt Jacob cto->ct_resid = 0; 11149e11e5beSMatt Jacob cto->ct_timeout = octo->ct_timeout; 11159e11e5beSMatt Jacob cto->ct_seg_count = 0; 11169e11e5beSMatt Jacob bzero(cto->ct_dataseg, sizeof (cto->ct_dataseg)); 11179e11e5beSMatt Jacob } 11189e11e5beSMatt Jacob } 11199e11e5beSMatt Jacob } 11209e11e5beSMatt Jacob 11219e11e5beSMatt Jacob static void 11229e11e5beSMatt Jacob dma2_tgt_fc(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 11239e11e5beSMatt Jacob { 11249e11e5beSMatt Jacob mush_t *mp; 11259e11e5beSMatt Jacob struct ccb_scsiio *csio; 11269e11e5beSMatt Jacob struct isp_pcisoftc *pci; 11279e11e5beSMatt Jacob bus_dmamap_t *dp; 11289e11e5beSMatt Jacob ct2_entry_t *cto; 11299e11e5beSMatt Jacob u_int16_t scsi_status, send_status; 11309e11e5beSMatt Jacob u_int32_t handle, reloff; 11319e11e5beSMatt Jacob int nctios; 11329e11e5beSMatt Jacob 11339e11e5beSMatt Jacob mp = (mush_t *) arg; 11349e11e5beSMatt Jacob if (error) { 11359e11e5beSMatt Jacob mp->error = error; 11369e11e5beSMatt Jacob return; 11379e11e5beSMatt Jacob } 11389e11e5beSMatt Jacob 11399e11e5beSMatt Jacob if (nseg < 1) { 11409e11e5beSMatt Jacob printf("%s: bad segment count (%d)\n", mp->isp->isp_name, nseg); 11419e11e5beSMatt Jacob mp->error = EFAULT; 11429e11e5beSMatt Jacob return; 11439e11e5beSMatt Jacob } 11449e11e5beSMatt Jacob 11459e11e5beSMatt Jacob csio = mp->cmd_token; 11469e11e5beSMatt Jacob cto = mp->rq; 11479e11e5beSMatt Jacob /* 11489e11e5beSMatt Jacob * Save handle, and potentially any SCSI status, which 11499e11e5beSMatt Jacob * we'll reinsert on the last CTIO we're going to send. 11509e11e5beSMatt Jacob */ 11519e11e5beSMatt Jacob handle = cto->ct_reserved; 11529e11e5beSMatt Jacob cto->ct_reserved = 0; 11539e11e5beSMatt Jacob scsi_status = cto->rsp.m0.ct_scsi_status; 11549e11e5beSMatt Jacob cto->rsp.m0.ct_scsi_status = 0; 11559e11e5beSMatt Jacob send_status = cto->ct_flags & CT2_SENDSTATUS; 11569e11e5beSMatt Jacob cto->ct_flags &= ~CT2_SENDSTATUS; 11579e11e5beSMatt Jacob 11589e11e5beSMatt Jacob pci = (struct isp_pcisoftc *)mp->isp; 11599e11e5beSMatt Jacob dp = &pci->dmaps[handle - 1]; 11609e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 11619e11e5beSMatt Jacob bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREREAD); 11629e11e5beSMatt Jacob } else { 11639e11e5beSMatt Jacob bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREWRITE); 11649e11e5beSMatt Jacob } 11659e11e5beSMatt Jacob 11669e11e5beSMatt Jacob nctios = nseg / ISP_RQDSEG_T2; 11679e11e5beSMatt Jacob if (nseg % ISP_RQDSEG_T2) { 11689e11e5beSMatt Jacob nctios++; 11699e11e5beSMatt Jacob } 11709e11e5beSMatt Jacob 11719e11e5beSMatt Jacob cto->ct_reloff = 0; 11729e11e5beSMatt Jacob cto->ct_resid = 0; 11739e11e5beSMatt Jacob cto->ct_seg_count = 0; 11749e11e5beSMatt Jacob cto->ct_reloff = reloff = 0; 11759e11e5beSMatt Jacob bzero(&cto->rsp, sizeof (cto->rsp)); 11769e11e5beSMatt Jacob 11779e11e5beSMatt Jacob while (nctios--) { 11789e11e5beSMatt Jacob int seg, seglim; 11799e11e5beSMatt Jacob 11809e11e5beSMatt Jacob seglim = nseg; 11819e11e5beSMatt Jacob if (seglim > ISP_RQDSEG_T2) 11829e11e5beSMatt Jacob seglim = ISP_RQDSEG_T2; 11839e11e5beSMatt Jacob 11849e11e5beSMatt Jacob for (seg = 0; seg < seglim; seg++) { 11859e11e5beSMatt Jacob cto->rsp.m0.ct_dataseg[seg].ds_base = dm_segs->ds_addr; 11869e11e5beSMatt Jacob cto->rsp.m0.ct_dataseg[seg].ds_count = dm_segs->ds_len; 11879e11e5beSMatt Jacob cto->rsp.m0.ct_xfrlen += dm_segs->ds_len; 11889e11e5beSMatt Jacob reloff += dm_segs->ds_len; 11899e11e5beSMatt Jacob dm_segs++; 11909e11e5beSMatt Jacob } 11919e11e5beSMatt Jacob 11929e11e5beSMatt Jacob cto->ct_seg_count = seg; 11939e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 11949e11e5beSMatt Jacob cto->ct_flags |= CT2_DATA_IN; 11959e11e5beSMatt Jacob } else { 11969e11e5beSMatt Jacob cto->ct_flags |= CT2_DATA_OUT; 11979e11e5beSMatt Jacob } 11989e11e5beSMatt Jacob 11999e11e5beSMatt Jacob if (nctios == 0) { 12009e11e5beSMatt Jacob /* 12019e11e5beSMatt Jacob * We're the last in a sequence of CTIOs, so mark this 12029e11e5beSMatt Jacob * CTIO and save the handle to the CCB such that when 12039e11e5beSMatt Jacob * this CTIO completes we can free dma resources and 12049e11e5beSMatt Jacob * do whatever else we need to do to finish the rest 12059e11e5beSMatt Jacob * of the command. 12069e11e5beSMatt Jacob */ 12079e11e5beSMatt Jacob cto->ct_header.rqs_seqno = 1; 12089e11e5beSMatt Jacob cto->ct_reserved = handle; 12099e11e5beSMatt Jacob cto->rsp.m0.ct_scsi_status = scsi_status; 12109e11e5beSMatt Jacob cto->ct_flags |= send_status; 12119e11e5beSMatt Jacob ISP_TDQE(mp->isp, "last dma2_tgt_fc", *mp->iptrp, cto); 12129e11e5beSMatt Jacob } else { 12139e11e5beSMatt Jacob ct2_entry_t *octo = cto; 12149e11e5beSMatt Jacob cto->ct_reserved = 0; 12159e11e5beSMatt Jacob cto->ct_header.rqs_seqno = 0; 12169e11e5beSMatt Jacob ISP_TDQE(mp->isp, "dma2_tgt_fc", *mp->iptrp, cto); 12179e11e5beSMatt Jacob cto = (ct2_entry_t *) 12189e11e5beSMatt Jacob ISP_QUEUE_ENTRY(mp->isp->isp_rquest, *mp->iptrp); 12199e11e5beSMatt Jacob *mp->iptrp = 12209e11e5beSMatt Jacob ISP_NXT_QENTRY(*mp->iptrp, RQUEST_QUEUE_LEN); 12219e11e5beSMatt Jacob if (*mp->iptrp == mp->optr) { 12229e11e5beSMatt Jacob printf("%s: Queue Overflow in dma2_tgt_fc\n", 12239e11e5beSMatt Jacob mp->isp->isp_name); 12249e11e5beSMatt Jacob mp->error = MUSHERR_NOQENTRIES; 12259e11e5beSMatt Jacob return; 12269e11e5beSMatt Jacob } 12279e11e5beSMatt Jacob /* 12289e11e5beSMatt Jacob * Fill in the new CTIO with info from the old one. 12299e11e5beSMatt Jacob */ 12309e11e5beSMatt Jacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2; 12319e11e5beSMatt Jacob cto->ct_header.rqs_entry_count = 1; 12329e11e5beSMatt Jacob cto->ct_header.rqs_flags = 0; 12339e11e5beSMatt Jacob /* ct_header.rqs_seqno && ct_reserved filled in later */ 12349e11e5beSMatt Jacob cto->ct_lun = octo->ct_lun; 12359e11e5beSMatt Jacob cto->ct_iid = octo->ct_iid; 12369e11e5beSMatt Jacob cto->ct_rxid = octo->ct_rxid; 12379e11e5beSMatt Jacob cto->ct_flags = octo->ct_flags & ~CT2_DATAMASK; 12389e11e5beSMatt Jacob cto->ct_status = 0; 12399e11e5beSMatt Jacob cto->ct_resid = 0; 12409e11e5beSMatt Jacob cto->ct_timeout = octo->ct_timeout; 12419e11e5beSMatt Jacob cto->ct_seg_count = 0; 12429e11e5beSMatt Jacob cto->ct_reloff = reloff; 12439e11e5beSMatt Jacob bzero(&cto->rsp, sizeof (cto->rsp)); 12449e11e5beSMatt Jacob } 12459e11e5beSMatt Jacob } 12469e11e5beSMatt Jacob } 12479e11e5beSMatt Jacob #endif 12489e11e5beSMatt Jacob 12499e11e5beSMatt Jacob static void dma2 __P((void *, bus_dma_segment_t *, int, int)); 12509e11e5beSMatt Jacob 12519e11e5beSMatt Jacob static void 12529e11e5beSMatt Jacob dma2(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 12539e11e5beSMatt Jacob { 12549e11e5beSMatt Jacob mush_t *mp; 12559e11e5beSMatt Jacob struct ccb_scsiio *csio; 12569e11e5beSMatt Jacob struct isp_pcisoftc *pci; 12579e11e5beSMatt Jacob bus_dmamap_t *dp; 12589e11e5beSMatt Jacob bus_dma_segment_t *eseg; 12599e11e5beSMatt Jacob ispreq_t *rq; 12609e11e5beSMatt Jacob ispcontreq_t *crq; 12619e11e5beSMatt Jacob int seglim, datalen; 12629e11e5beSMatt Jacob 12639e11e5beSMatt Jacob mp = (mush_t *) arg; 12649e11e5beSMatt Jacob if (error) { 12659e11e5beSMatt Jacob mp->error = error; 12669e11e5beSMatt Jacob return; 12679e11e5beSMatt Jacob } 12689e11e5beSMatt Jacob 12699e11e5beSMatt Jacob if (nseg < 1) { 12709e11e5beSMatt Jacob printf("%s: bad segment count (%d)\n", mp->isp->isp_name, nseg); 12719e11e5beSMatt Jacob mp->error = EFAULT; 12729e11e5beSMatt Jacob return; 12739e11e5beSMatt Jacob } 12749e11e5beSMatt Jacob csio = mp->cmd_token; 12759e11e5beSMatt Jacob rq = mp->rq; 12769e11e5beSMatt Jacob pci = (struct isp_pcisoftc *)mp->isp; 12779e11e5beSMatt Jacob dp = &pci->dmaps[rq->req_handle - 1]; 12789e11e5beSMatt Jacob 12799e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 12809e11e5beSMatt Jacob bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREREAD); 12819e11e5beSMatt Jacob } else { 12829e11e5beSMatt Jacob bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREWRITE); 12839e11e5beSMatt Jacob } 12849e11e5beSMatt Jacob 12859e11e5beSMatt Jacob datalen = XS_XFRLEN(csio); 12869e11e5beSMatt Jacob 12879e11e5beSMatt Jacob /* 12889e11e5beSMatt Jacob * We're passed an initial partially filled in entry that 12899e11e5beSMatt Jacob * has most fields filled in except for data transfer 12909e11e5beSMatt Jacob * related values. 12919e11e5beSMatt Jacob * 12929e11e5beSMatt Jacob * Our job is to fill in the initial request queue entry and 12939e11e5beSMatt Jacob * then to start allocating and filling in continuation entries 12949e11e5beSMatt Jacob * until we've covered the entire transfer. 12959e11e5beSMatt Jacob */ 12969e11e5beSMatt Jacob 12979e11e5beSMatt Jacob if (IS_FC(mp->isp)) { 1298d720e6d5SJustin T. Gibbs seglim = ISP_RQDSEG_T2; 1299d720e6d5SJustin T. Gibbs ((ispreqt2_t *)rq)->req_totalcnt = datalen; 13009e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 13019e11e5beSMatt Jacob ((ispreqt2_t *)rq)->req_flags |= REQFLAG_DATA_IN; 13029e11e5beSMatt Jacob } else { 13039e11e5beSMatt Jacob ((ispreqt2_t *)rq)->req_flags |= REQFLAG_DATA_OUT; 13049e11e5beSMatt Jacob } 1305d720e6d5SJustin T. Gibbs } else { 1306d720e6d5SJustin T. Gibbs seglim = ISP_RQDSEG; 13079e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 13089e11e5beSMatt Jacob rq->req_flags |= REQFLAG_DATA_IN; 13099e11e5beSMatt Jacob } else { 13109e11e5beSMatt Jacob rq->req_flags |= REQFLAG_DATA_OUT; 13119e11e5beSMatt Jacob } 1312d720e6d5SJustin T. Gibbs } 1313d720e6d5SJustin T. Gibbs 1314d720e6d5SJustin T. Gibbs eseg = dm_segs + nseg; 1315d720e6d5SJustin T. Gibbs 1316d720e6d5SJustin T. Gibbs while (datalen != 0 && rq->req_seg_count < seglim && dm_segs != eseg) { 13179e11e5beSMatt Jacob if (IS_FC(mp->isp)) { 1318d720e6d5SJustin T. Gibbs ispreqt2_t *rq2 = (ispreqt2_t *)rq; 1319d720e6d5SJustin T. Gibbs rq2->req_dataseg[rq2->req_seg_count].ds_base = 1320d720e6d5SJustin T. Gibbs dm_segs->ds_addr; 1321d720e6d5SJustin T. Gibbs rq2->req_dataseg[rq2->req_seg_count].ds_count = 1322d720e6d5SJustin T. Gibbs dm_segs->ds_len; 1323d720e6d5SJustin T. Gibbs } else { 1324d720e6d5SJustin T. Gibbs rq->req_dataseg[rq->req_seg_count].ds_base = 1325d720e6d5SJustin T. Gibbs dm_segs->ds_addr; 1326d720e6d5SJustin T. Gibbs rq->req_dataseg[rq->req_seg_count].ds_count = 1327d720e6d5SJustin T. Gibbs dm_segs->ds_len; 1328d720e6d5SJustin T. Gibbs } 1329d720e6d5SJustin T. Gibbs datalen -= dm_segs->ds_len; 1330d720e6d5SJustin T. Gibbs #if 0 13319e11e5beSMatt Jacob if (IS_FC(mp->isp)) { 1332d720e6d5SJustin T. Gibbs ispreqt2_t *rq2 = (ispreqt2_t *)rq; 1333d720e6d5SJustin T. Gibbs printf("%s: seg0[%d] cnt 0x%x paddr 0x%08x\n", 13349e11e5beSMatt Jacob mp->isp->isp_name, rq->req_seg_count, 1335d720e6d5SJustin T. Gibbs rq2->req_dataseg[rq2->req_seg_count].ds_count, 1336d720e6d5SJustin T. Gibbs rq2->req_dataseg[rq2->req_seg_count].ds_base); 1337d720e6d5SJustin T. Gibbs } else { 1338d720e6d5SJustin T. Gibbs printf("%s: seg0[%d] cnt 0x%x paddr 0x%08x\n", 13399e11e5beSMatt Jacob mp->isp->isp_name, rq->req_seg_count, 1340d720e6d5SJustin T. Gibbs rq->req_dataseg[rq->req_seg_count].ds_count, 1341d720e6d5SJustin T. Gibbs rq->req_dataseg[rq->req_seg_count].ds_base); 1342d720e6d5SJustin T. Gibbs } 1343d720e6d5SJustin T. Gibbs #endif 1344d720e6d5SJustin T. Gibbs rq->req_seg_count++; 1345d720e6d5SJustin T. Gibbs dm_segs++; 1346d720e6d5SJustin T. Gibbs } 1347d720e6d5SJustin T. Gibbs 1348d720e6d5SJustin T. Gibbs while (datalen > 0 && dm_segs != eseg) { 13499e11e5beSMatt Jacob crq = (ispcontreq_t *) 13509e11e5beSMatt Jacob ISP_QUEUE_ENTRY(mp->isp->isp_rquest, *mp->iptrp); 13519e11e5beSMatt Jacob *mp->iptrp = ISP_NXT_QENTRY(*mp->iptrp, RQUEST_QUEUE_LEN); 13529e11e5beSMatt Jacob if (*mp->iptrp == mp->optr) { 13534873663cSMatt Jacob #if 0 13549e11e5beSMatt Jacob printf("%s: Request Queue Overflow++\n", 13559e11e5beSMatt Jacob mp->isp->isp_name); 13564873663cSMatt Jacob #endif 13574873663cSMatt Jacob mp->error = MUSHERR_NOQENTRIES; 1358d720e6d5SJustin T. Gibbs return; 1359d720e6d5SJustin T. Gibbs } 1360d720e6d5SJustin T. Gibbs rq->req_header.rqs_entry_count++; 1361d720e6d5SJustin T. Gibbs bzero((void *)crq, sizeof (*crq)); 1362d720e6d5SJustin T. Gibbs crq->req_header.rqs_entry_count = 1; 1363d720e6d5SJustin T. Gibbs crq->req_header.rqs_entry_type = RQSTYPE_DATASEG; 1364d720e6d5SJustin T. Gibbs 1365d720e6d5SJustin T. Gibbs seglim = 0; 1366d720e6d5SJustin T. Gibbs while (datalen > 0 && seglim < ISP_CDSEG && dm_segs != eseg) { 1367d720e6d5SJustin T. Gibbs crq->req_dataseg[seglim].ds_base = 1368d720e6d5SJustin T. Gibbs dm_segs->ds_addr; 1369d720e6d5SJustin T. Gibbs crq->req_dataseg[seglim].ds_count = 1370d720e6d5SJustin T. Gibbs dm_segs->ds_len; 1371d720e6d5SJustin T. Gibbs #if 0 1372d720e6d5SJustin T. Gibbs printf("%s: seg%d[%d] cnt 0x%x paddr 0x%08x\n", 13739e11e5beSMatt Jacob mp->isp->isp_name, rq->req_header.rqs_entry_count-1, 1374d720e6d5SJustin T. Gibbs seglim, crq->req_dataseg[seglim].ds_count, 1375d720e6d5SJustin T. Gibbs crq->req_dataseg[seglim].ds_base); 1376d720e6d5SJustin T. Gibbs #endif 1377d720e6d5SJustin T. Gibbs rq->req_seg_count++; 1378d720e6d5SJustin T. Gibbs dm_segs++; 1379d720e6d5SJustin T. Gibbs seglim++; 1380d720e6d5SJustin T. Gibbs datalen -= dm_segs->ds_len; 1381d720e6d5SJustin T. Gibbs } 1382d720e6d5SJustin T. Gibbs } 1383d720e6d5SJustin T. Gibbs } 1384d720e6d5SJustin T. Gibbs 1385d720e6d5SJustin T. Gibbs static int 13869e11e5beSMatt Jacob isp_pci_dmasetup(struct ispsoftc *isp, struct ccb_scsiio *csio, ispreq_t *rq, 13879637d68cSMatt Jacob u_int16_t *iptrp, u_int16_t optr) 1388d720e6d5SJustin T. Gibbs { 1389d720e6d5SJustin T. Gibbs struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp; 13900a5f7e8bSMatt Jacob bus_dmamap_t *dp = NULL; 1391d720e6d5SJustin T. Gibbs mush_t mush, *mp; 13929e11e5beSMatt Jacob void (*eptr) __P((void *, bus_dma_segment_t *, int, int)); 1393d720e6d5SJustin T. Gibbs 13949e11e5beSMatt Jacob #ifdef ISP_TARGET_MODE 13959e11e5beSMatt Jacob if (csio->ccb_h.func_code == XPT_CONT_TARGET_IO) { 13969e11e5beSMatt Jacob if (IS_FC(isp)) { 13979e11e5beSMatt Jacob eptr = dma2_tgt_fc; 13989e11e5beSMatt Jacob } else { 13999e11e5beSMatt Jacob eptr = dma2_tgt; 14009e11e5beSMatt Jacob } 14019e11e5beSMatt Jacob } else 14029e11e5beSMatt Jacob #endif 14039e11e5beSMatt Jacob eptr = dma2; 1404d720e6d5SJustin T. Gibbs 14059e11e5beSMatt Jacob /* 14069e11e5beSMatt Jacob * NB: if we need to do request queue entry swizzling, 14079e11e5beSMatt Jacob * NB: this is where it would need to be done for cmds 14089e11e5beSMatt Jacob * NB: that move no data. For commands that move data, 14099e11e5beSMatt Jacob * NB: swizzling would take place in those functions. 14109e11e5beSMatt Jacob */ 14119e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE) { 1412d720e6d5SJustin T. Gibbs rq->req_seg_count = 1; 14134873663cSMatt Jacob return (CMD_QUEUED); 1414d720e6d5SJustin T. Gibbs } 1415d720e6d5SJustin T. Gibbs 1416d720e6d5SJustin T. Gibbs /* 1417d720e6d5SJustin T. Gibbs * Do a virtual grapevine step to collect info for 14184873663cSMatt Jacob * the callback dma allocation that we have to use... 1419d720e6d5SJustin T. Gibbs */ 1420d720e6d5SJustin T. Gibbs mp = &mush; 1421d720e6d5SJustin T. Gibbs mp->isp = isp; 14229e11e5beSMatt Jacob mp->cmd_token = csio; 1423d720e6d5SJustin T. Gibbs mp->rq = rq; 1424d720e6d5SJustin T. Gibbs mp->iptrp = iptrp; 1425d720e6d5SJustin T. Gibbs mp->optr = optr; 1426d720e6d5SJustin T. Gibbs mp->error = 0; 1427d720e6d5SJustin T. Gibbs 14289e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_SCATTER_VALID) == 0) { 14299e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DATA_PHYS) == 0) { 14304873663cSMatt Jacob int error, s; 14310a5f7e8bSMatt Jacob dp = &pci->dmaps[rq->req_handle - 1]; 1432d720e6d5SJustin T. Gibbs s = splsoftvm(); 1433d720e6d5SJustin T. Gibbs error = bus_dmamap_load(pci->parent_dmat, *dp, 14349e11e5beSMatt Jacob csio->data_ptr, csio->dxfer_len, eptr, mp, 0); 1435d720e6d5SJustin T. Gibbs if (error == EINPROGRESS) { 1436d720e6d5SJustin T. Gibbs bus_dmamap_unload(pci->parent_dmat, *dp); 1437d720e6d5SJustin T. Gibbs mp->error = EINVAL; 14384873663cSMatt Jacob printf("%s: deferred dma allocation not " 14394873663cSMatt Jacob "supported\n", isp->isp_name); 1440d720e6d5SJustin T. Gibbs } else if (error && mp->error == 0) { 14410a5f7e8bSMatt Jacob #ifdef DIAGNOSTIC 14420a5f7e8bSMatt Jacob printf("%s: error %d in dma mapping code\n", 14430a5f7e8bSMatt Jacob isp->isp_name, error); 14440a5f7e8bSMatt Jacob #endif 1445d720e6d5SJustin T. Gibbs mp->error = error; 1446d720e6d5SJustin T. Gibbs } 14474873663cSMatt Jacob splx(s); 1448d720e6d5SJustin T. Gibbs } else { 1449d720e6d5SJustin T. Gibbs /* Pointer to physical buffer */ 1450d720e6d5SJustin T. Gibbs struct bus_dma_segment seg; 1451d720e6d5SJustin T. Gibbs seg.ds_addr = (bus_addr_t)csio->data_ptr; 1452d720e6d5SJustin T. Gibbs seg.ds_len = csio->dxfer_len; 14539e11e5beSMatt Jacob (*eptr)(mp, &seg, 1, 0); 1454d720e6d5SJustin T. Gibbs } 1455d720e6d5SJustin T. Gibbs } else { 1456d720e6d5SJustin T. Gibbs struct bus_dma_segment *segs; 1457d720e6d5SJustin T. Gibbs 14589e11e5beSMatt Jacob if ((csio->ccb_h.flags & CAM_DATA_PHYS) != 0) { 1459d720e6d5SJustin T. Gibbs printf("%s: Physical segment pointers unsupported", 1460d720e6d5SJustin T. Gibbs isp->isp_name); 1461d720e6d5SJustin T. Gibbs mp->error = EINVAL; 14629e11e5beSMatt Jacob } else if ((csio->ccb_h.flags & CAM_SG_LIST_PHYS) == 0) { 1463d720e6d5SJustin T. Gibbs printf("%s: Virtual segment addresses unsupported", 1464d720e6d5SJustin T. Gibbs isp->isp_name); 1465d720e6d5SJustin T. Gibbs mp->error = EINVAL; 1466d720e6d5SJustin T. Gibbs } else { 1467d720e6d5SJustin T. Gibbs /* Just use the segments provided */ 1468d720e6d5SJustin T. Gibbs segs = (struct bus_dma_segment *) csio->data_ptr; 14699e11e5beSMatt Jacob (*eptr)(mp, segs, csio->sglist_cnt, 0); 1470d720e6d5SJustin T. Gibbs } 1471d720e6d5SJustin T. Gibbs } 1472d720e6d5SJustin T. Gibbs if (mp->error) { 14734873663cSMatt Jacob int retval = CMD_COMPLETE; 14744873663cSMatt Jacob if (mp->error == MUSHERR_NOQENTRIES) { 14754873663cSMatt Jacob retval = CMD_EAGAIN; 14764873663cSMatt Jacob } else if (mp->error == EFBIG) { 14770a5f7e8bSMatt Jacob XS_SETERR(csio, CAM_REQ_TOO_BIG); 1478d720e6d5SJustin T. Gibbs } else if (mp->error == EINVAL) { 14790a5f7e8bSMatt Jacob XS_SETERR(csio, CAM_REQ_INVALID); 1480d720e6d5SJustin T. Gibbs } else { 14810a5f7e8bSMatt Jacob XS_SETERR(csio, CAM_UNREC_HBA_ERROR); 1482d720e6d5SJustin T. Gibbs } 14834873663cSMatt Jacob return (retval); 14844873663cSMatt Jacob } else { 14850a5f7e8bSMatt Jacob /* 14860a5f7e8bSMatt Jacob * Check to see if we weren't cancelled while sleeping on 14870a5f7e8bSMatt Jacob * getting DMA resources... 14880a5f7e8bSMatt Jacob */ 14899e11e5beSMatt Jacob if ((csio->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG) { 14900a5f7e8bSMatt Jacob if (dp) { 14910a5f7e8bSMatt Jacob bus_dmamap_unload(pci->parent_dmat, *dp); 14920a5f7e8bSMatt Jacob } 14930a5f7e8bSMatt Jacob return (CMD_COMPLETE); 14940a5f7e8bSMatt Jacob } 14954873663cSMatt Jacob return (CMD_QUEUED); 1496d720e6d5SJustin T. Gibbs } 1497d720e6d5SJustin T. Gibbs } 1498d720e6d5SJustin T. Gibbs 1499d720e6d5SJustin T. Gibbs static void 1500a95ae193SMatt Jacob isp_pci_dmateardown(struct ispsoftc *isp, ISP_SCSI_XFER_T *xs, u_int32_t handle) 1501d720e6d5SJustin T. Gibbs { 1502d720e6d5SJustin T. Gibbs struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp; 1503a95ae193SMatt Jacob bus_dmamap_t *dp = &pci->dmaps[handle - 1]; 1504a95ae193SMatt Jacob KASSERT((handle > 0 && handle <= isp->isp_maxcmds), 1505a95ae193SMatt Jacob ("bad handle in isp_pci_dmateardonw")); 1506a95ae193SMatt Jacob if ((xs->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 1507d720e6d5SJustin T. Gibbs bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_POSTREAD); 1508d720e6d5SJustin T. Gibbs } else { 1509d720e6d5SJustin T. Gibbs bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_POSTWRITE); 1510d720e6d5SJustin T. Gibbs } 1511d720e6d5SJustin T. Gibbs bus_dmamap_unload(pci->parent_dmat, *dp); 1512d720e6d5SJustin T. Gibbs } 1513d720e6d5SJustin T. Gibbs 151465adb54cSMatt Jacob 151565adb54cSMatt Jacob static void 151617e318c6SMatt Jacob isp_pci_reset1(struct ispsoftc *isp) 151765adb54cSMatt Jacob { 151865adb54cSMatt Jacob /* Make sure the BIOS is disabled */ 151965adb54cSMatt Jacob isp_pci_wr_reg(isp, HCCR, PCI_HCCR_CMD_BIOS); 152065adb54cSMatt Jacob } 152165adb54cSMatt Jacob 152265adb54cSMatt Jacob static void 152317e318c6SMatt Jacob isp_pci_dumpregs(struct ispsoftc *isp) 152465adb54cSMatt Jacob { 152565adb54cSMatt Jacob struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp; 15269bffbcd4SBruce Evans printf("%s: PCI Status Command/Status=%lx\n", pci->pci_isp.isp_name, 1527d951bbcaSMatt Jacob pci_conf_read(pci->pci_id, PCIR_COMMAND)); 152865adb54cSMatt Jacob } 1529