isp_pci.c revision 50477
1116742Ssam/* $FreeBSD: head/sys/dev/isp/isp_pci.c 50477 1999-08-28 01:08:13Z peter $ */ 2116904Ssam/* 3186904Ssam * PCI specific probe and attach routines for Qlogic ISP SCSI adapters. 4116742Ssam * FreeBSD Version. 5116742Ssam * 6116742Ssam *--------------------------------------- 7116742Ssam * Copyright (c) 1997, 1998, 1999 by Matthew Jacob 8116742Ssam * NASA/Ames Research Center 9116742Ssam * All rights reserved. 10116742Ssam *--------------------------------------- 11116742Ssam * 12116742Ssam * Redistribution and use in source and binary forms, with or without 13116742Ssam * modification, are permitted provided that the following conditions 14116742Ssam * are met: 15116904Ssam * 1. Redistributions of source code must retain the above copyright 16116904Ssam * notice immediately at the beginning of the file, without modification, 17116904Ssam * this list of conditions, and the following disclaimer. 18116904Ssam * 2. Redistributions in binary form must reproduce the above copyright 19116904Ssam * notice, this list of conditions and the following disclaimer in the 20116904Ssam * documentation and/or other materials provided with the distribution. 21116904Ssam * 3. The name of the author may not be used to endorse or promote products 22116904Ssam * derived from this software without specific prior written permission. 23116904Ssam * 24116904Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 25116904Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26116742Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27116742Ssam * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 28116742Ssam * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29116742Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30116742Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31116742Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32116742Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33116742Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34138568Ssam * SUCH DAMAGE. 35138568Ssam */ 36138568Ssam#include <dev/isp/isp_freebsd.h> 37116742Ssam#include <dev/isp/asm_pci.h> 38138568Ssam#include <sys/malloc.h> 39161146Ssam#include <vm/vm.h> 40138568Ssam#include <vm/pmap.h> 41138568Ssam#include <vm/vm_extern.h> 42170530Ssam 43170530Ssam 44170530Ssam#include <pci/pcireg.h> 45170530Ssam#include <pci/pcivar.h> 46170530Ssam 47170530Ssam#include <machine/bus_memio.h> 48170530Ssam#include <machine/bus_pio.h> 49170530Ssam#include <machine/bus.h> 50138568Ssam#include <machine/md_var.h> 51170530Ssam 52170530Ssam 53170530Ssamstatic u_int16_t isp_pci_rd_reg __P((struct ispsoftc *, int)); 54170530Ssamstatic void isp_pci_wr_reg __P((struct ispsoftc *, int, u_int16_t)); 55170530Ssam#ifndef ISP_DISABLE_1080_SUPPORT 56170530Ssamstatic u_int16_t isp_pci_rd_reg_1080 __P((struct ispsoftc *, int)); 57170530Ssamstatic void isp_pci_wr_reg_1080 __P((struct ispsoftc *, int, u_int16_t)); 58170530Ssam#endif 59170530Ssamstatic int isp_pci_mbxdma __P((struct ispsoftc *)); 60170530Ssamstatic int isp_pci_dmasetup __P((struct ispsoftc *, ISP_SCSI_XFER_T *, 61170530Ssam ispreq_t *, u_int8_t *, u_int8_t)); 62170530Ssamstatic void 63173273Ssamisp_pci_dmateardown __P((struct ispsoftc *, ISP_SCSI_XFER_T *, u_int32_t)); 64138568Ssam 65170530Ssamstatic void isp_pci_reset1 __P((struct ispsoftc *)); 66170530Ssamstatic void isp_pci_dumpregs __P((struct ispsoftc *)); 67193239Ssam 68170530Ssam#ifndef ISP_DISABLE_1020_SUPPORT 69170530Ssamstatic struct ispmdvec mdvec = { 70170530Ssam isp_pci_rd_reg, 71170530Ssam isp_pci_wr_reg, 72138568Ssam isp_pci_mbxdma, 73170530Ssam isp_pci_dmasetup, 74170530Ssam isp_pci_dmateardown, 75138568Ssam NULL, 76170530Ssam isp_pci_reset1, 77138568Ssam isp_pci_dumpregs, 78138568Ssam ISP_RISC_CODE, 79170530Ssam ISP_CODE_LENGTH, 80170530Ssam ISP_CODE_ORG, 81170530Ssam ISP_CODE_VERSION, 82170530Ssam BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64, 83170530Ssam 0 84170530Ssam}; 85170530Ssam#endif 86170530Ssam 87193239Ssam#ifndef ISP_DISABLE_1080_SUPPORT 88138568Ssamstatic struct ispmdvec mdvec_1080 = { 89138568Ssam isp_pci_rd_reg_1080, 90138568Ssam isp_pci_wr_reg_1080, 91138568Ssam isp_pci_mbxdma, 92138568Ssam isp_pci_dmasetup, 93121180Ssam isp_pci_dmateardown, 94170530Ssam NULL, 95170530Ssam isp_pci_reset1, 96170530Ssam isp_pci_dumpregs, 97170530Ssam ISP1080_RISC_CODE, 98170530Ssam ISP1080_CODE_LENGTH, 99170530Ssam ISP1080_CODE_ORG, 100170530Ssam ISP1080_CODE_VERSION, 101170530Ssam BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64, 102170530Ssam 0 103170530Ssam}; 104170530Ssam#endif 105170530Ssam 106193239Ssam#ifndef ISP_DISABLE_2100_SUPPORT 107170530Ssamstatic struct ispmdvec mdvec_2100 = { 108170530Ssam isp_pci_rd_reg, 109170530Ssam isp_pci_wr_reg, 110170530Ssam isp_pci_mbxdma, 111170530Ssam isp_pci_dmasetup, 112170530Ssam isp_pci_dmateardown, 113170530Ssam NULL, 114170530Ssam isp_pci_reset1, 115170530Ssam isp_pci_dumpregs, 116170530Ssam ISP2100_RISC_CODE, 117170530Ssam ISP2100_CODE_LENGTH, 118170530Ssam ISP2100_CODE_ORG, 119170530Ssam ISP2100_CODE_VERSION, 120170530Ssam 0, /* Irrelevant to the 2100 */ 121170530Ssam 0 122170530Ssam}; 123170530Ssam#endif 124170530Ssam 125170530Ssam#ifndef ISP_DISABLE_2200_SUPPORT 126170530Ssamstatic struct ispmdvec mdvec_2200 = { 127170530Ssam isp_pci_rd_reg, 128170530Ssam isp_pci_wr_reg, 129170530Ssam isp_pci_mbxdma, 130170530Ssam isp_pci_dmasetup, 131170530Ssam isp_pci_dmateardown, 132170530Ssam NULL, 133170530Ssam isp_pci_reset1, 134170530Ssam isp_pci_dumpregs, 135170530Ssam ISP2200_RISC_CODE, 136170530Ssam ISP2200_CODE_LENGTH, 137170530Ssam ISP2100_CODE_ORG, 138170530Ssam ISP2200_CODE_VERSION, 139170530Ssam 0, 140170530Ssam 0 141170530Ssam}; 142170530Ssam#endif 143170530Ssam 144170530Ssam#ifndef SCSI_ISP_PREFER_MEM_MAP 145170530Ssam#define SCSI_ISP_PREFER_MEM_MAP 0 146170530Ssam#endif 147170530Ssam 148170530Ssam#ifndef PCIM_CMD_INVEN 149170530Ssam#define PCIM_CMD_INVEN 0x10 150170530Ssam#endif 151170530Ssam#ifndef PCIM_CMD_BUSMASTEREN 152170530Ssam#define PCIM_CMD_BUSMASTEREN 0x0004 153170530Ssam#endif 154170530Ssam#ifndef PCIM_CMD_PERRESPEN 155170530Ssam#define PCIM_CMD_PERRESPEN 0x0040 156170530Ssam#endif 157170530Ssam#ifndef PCIM_CMD_SEREN 158170530Ssam#define PCIM_CMD_SEREN 0x0100 159170530Ssam#endif 160170530Ssam 161170530Ssam#ifndef PCIR_COMMAND 162170530Ssam#define PCIR_COMMAND 0x04 163170530Ssam#endif 164170530Ssam 165170530Ssam#ifndef PCIR_CACHELNSZ 166170530Ssam#define PCIR_CACHELNSZ 0x0c 167170530Ssam#endif 168170530Ssam 169170530Ssam#ifndef PCIR_LATTIMER 170170530Ssam#define PCIR_LATTIMER 0x0d 171170530Ssam#endif 172170530Ssam 173170530Ssam#ifndef PCIR_ROMADDR 174170530Ssam#define PCIR_ROMADDR 0x30 175170530Ssam#endif 176170530Ssam 177170530Ssam#ifndef PCI_VENDOR_QLOGIC 178170530Ssam#define PCI_VENDOR_QLOGIC 0x1077 179170530Ssam#endif 180170530Ssam 181170530Ssam#ifndef PCI_PRODUCT_QLOGIC_ISP1020 182170530Ssam#define PCI_PRODUCT_QLOGIC_ISP1020 0x1020 183170530Ssam#endif 184170530Ssam 185170530Ssam#ifndef PCI_PRODUCT_QLOGIC_ISP1080 186170530Ssam#define PCI_PRODUCT_QLOGIC_ISP1080 0x1080 187170530Ssam#endif 188170530Ssam 189170530Ssam#ifndef PCI_PRODUCT_QLOGIC_ISP1240 190170530Ssam#define PCI_PRODUCT_QLOGIC_ISP1240 0x1240 191170530Ssam#endif 192173273Ssam 193170530Ssam#ifndef PCI_PRODUCT_QLOGIC_ISP2100 194170530Ssam#define PCI_PRODUCT_QLOGIC_ISP2100 0x2100 195170530Ssam#endif 196170530Ssam 197173273Ssam#ifndef PCI_PRODUCT_QLOGIC_ISP2200 198173273Ssam#define PCI_PRODUCT_QLOGIC_ISP2200 0x2200 199173273Ssam#endif 200173273Ssam 201178354Ssam#define PCI_QLOGIC_ISP ((PCI_PRODUCT_QLOGIC_ISP1020 << 16) | PCI_VENDOR_QLOGIC) 202178354Ssam 203173273Ssam#define PCI_QLOGIC_ISP1080 \ 204173273Ssam ((PCI_PRODUCT_QLOGIC_ISP1080 << 16) | PCI_VENDOR_QLOGIC) 205173273Ssam 206173273Ssam#define PCI_QLOGIC_ISP1240 \ 207173273Ssam ((PCI_PRODUCT_QLOGIC_ISP1240 << 16) | PCI_VENDOR_QLOGIC) 208173273Ssam 209173273Ssam#define PCI_QLOGIC_ISP2100 \ 210173273Ssam ((PCI_PRODUCT_QLOGIC_ISP2100 << 16) | PCI_VENDOR_QLOGIC) 211173273Ssam 212182829Ssam#define PCI_QLOGIC_ISP2200 \ 213173273Ssam ((PCI_PRODUCT_QLOGIC_ISP2200 << 16) | PCI_VENDOR_QLOGIC) 214173273Ssam 215173273Ssam#define IO_MAP_REG 0x10 216178354Ssam#define MEM_MAP_REG 0x14 217178354Ssam 218178354Ssam#define PCI_DFLT_LTNCY 0x40 219178354Ssam#define PCI_DFLT_LNSZ 0x10 220178354Ssam 221186904Ssamstatic const char *isp_pci_probe __P((pcici_t tag, pcidi_t type)); 222190579Ssamstatic void isp_pci_attach __P((pcici_t config_d, int unit)); 223193239Ssam 224193239Ssam/* This distinguishing define is not right, but it does work */ 225193239Ssam#ifdef __alpha__ 226195618Srpaulo#define IO_SPACE_MAPPING ALPHA_BUS_SPACE_IO 227195618Srpaulo#define MEM_SPACE_MAPPING ALPHA_BUS_SPACE_MEM 228195618Srpaulo#else 229195618Srpaulo#define IO_SPACE_MAPPING I386_BUS_SPACE_IO 230195618Srpaulo#define MEM_SPACE_MAPPING I386_BUS_SPACE_MEM 231195618Srpaulo#endif 232195618Srpaulo 233195618Srpaulostruct isp_pcisoftc { 234195618Srpaulo struct ispsoftc pci_isp; 235195618Srpaulo pcici_t pci_id; 236195618Srpaulo bus_space_tag_t pci_st; 237195618Srpaulo bus_space_handle_t pci_sh; 238195784Srpaulo int16_t pci_poff[_NREG_BLKS]; 239195784Srpaulo bus_dma_tag_t parent_dmat; 240195784Srpaulo bus_dma_tag_t cntrol_dmat; 241195784Srpaulo bus_dmamap_t cntrol_dmap; 242195757Ssam bus_dmamap_t dmaps[MAXISPREQUEST]; 243195908Srpaulo}; 244232244Sadrian 245234018Sadrianstatic u_long ispunit; 246234018Sadrian 247234018Sadrianstatic struct pci_device isp_pci_driver = { 248234018Sadrian "isp", 249234018Sadrian isp_pci_probe, 250121180Ssam isp_pci_attach, 251121180Ssam &ispunit, 252138568Ssam NULL 253138568Ssam}; 254138568SsamCOMPAT_PCI_DRIVER (isp_pci, isp_pci_driver); 255138568Ssam 256138568Ssam 257138568Ssamstatic const char * 258138568Ssamisp_pci_probe(pcici_t tag, pcidi_t type) 259138568Ssam{ 260138568Ssam static int oneshot = 1; 261138568Ssam char *x; 262138568Ssam 263138568Ssam switch (type) { 264138568Ssam#ifndef ISP_DISABLE_1020_SUPPORT 265138568Ssam case PCI_QLOGIC_ISP: 266138568Ssam x = "Qlogic ISP 1020/1040 PCI SCSI Adapter"; 267173273Ssam break; 268138568Ssam#endif 269138568Ssam#ifndef ISP_DISABLE_1080_SUPPORT 270170530Ssam case PCI_QLOGIC_ISP1080: 271170530Ssam x = "Qlogic ISP 1080 PCI SCSI Adapter"; 272170530Ssam break; 273170530Ssam case PCI_QLOGIC_ISP1240: 274170530Ssam x = "Qlogic ISP 1240 PCI SCSI Adapter"; 275138568Ssam break; 276138568Ssam#endif 277170530Ssam#ifndef ISP_DISABLE_2100_SUPPORT 278170530Ssam case PCI_QLOGIC_ISP2100: 279170530Ssam x = "Qlogic ISP 2100 PCI FC-AL Adapter"; 280170530Ssam break; 281138568Ssam#endif 282138568Ssam#ifndef ISP_DISABLE_2200_SUPPORT 283138568Ssam case PCI_QLOGIC_ISP2200: 284138568Ssam x = "Qlogic ISP 2200 PCI FC-AL Adapter"; 285138568Ssam break; 286138568Ssam#endif 287138568Ssam default: 288170530Ssam return (NULL); 289170530Ssam } 290138568Ssam if (oneshot) { 291138568Ssam oneshot = 0; 292138568Ssam printf("%s Version %d.%d, Core Version %d.%d\n", PVS, 293138568Ssam ISP_PLATFORM_VERSION_MAJOR, ISP_PLATFORM_VERSION_MINOR, 294138568Ssam ISP_CORE_VERSION_MAJOR, ISP_CORE_VERSION_MINOR); 295138568Ssam } 296138568Ssam return (x); 297138568Ssam} 298138568Ssam 299170530Ssamstatic void 300138568Ssamisp_pci_attach(pcici_t cfid, int unit) 301138568Ssam{ 302138568Ssam int mapped, prefer_mem_map, bitmap; 303138568Ssam pci_port_t io_port; 304138568Ssam u_int32_t data, linesz, psize, basetype; 305178354Ssam struct isp_pcisoftc *pcs; 306170530Ssam struct ispsoftc *isp; 307170530Ssam vm_offset_t vaddr, paddr; 308170530Ssam struct ispmdvec *mdvp; 309170530Ssam bus_size_t lim; 310138568Ssam ISP_LOCKVAL_DECL; 311138568Ssam 312138568Ssam pcs = malloc(sizeof (struct isp_pcisoftc), M_DEVBUF, M_NOWAIT); 313138568Ssam if (pcs == NULL) { 314138568Ssam printf("isp%d: cannot allocate softc\n", unit); 315138568Ssam return; 316138568Ssam } 317138568Ssam bzero(pcs, sizeof (struct isp_pcisoftc)); 318138568Ssam 319138568Ssam /* 320138568Ssam * Figure out if we're supposed to skip this one. 321149028Ssam */ 322149028Ssam if (getenv_int("isp_disable", &bitmap)) { 323178354Ssam if (bitmap & (1 << unit)) { 324138568Ssam printf("isp%d: not configuring\n", unit); 325138568Ssam return; 326149028Ssam } 327170530Ssam } 328195561Ssam 329149028Ssam /* 330138568Ssam * Figure out which we should try first - memory mapping or i/o mapping? 331195618Srpaulo */ 332195618Srpaulo#if SCSI_ISP_PREFER_MEM_MAP == 1 333195618Srpaulo prefer_mem_map = 1; 334195618Srpaulo#else 335195618Srpaulo prefer_mem_map = 0; 336195618Srpaulo#endif 337195618Srpaulo bitmap = 0; 338195618Srpaulo if (getenv_int("isp_mem_map", &bitmap)) { 339195618Srpaulo if (bitmap & (1 << unit)) 340195784Srpaulo prefer_mem_map = 1; 341203556Srpaulo } 342234894Smonthadar bitmap = 0; 343234894Smonthadar if (getenv_int("isp_io_map", &bitmap)) { 344234894Smonthadar if (bitmap & (1 << unit)) 345246501Smonthadar prefer_mem_map = 0; 346203422Srpaulo } 347203422Srpaulo 348203422Srpaulo vaddr = paddr = NULL; 349195908Srpaulo mapped = 0; 350195784Srpaulo linesz = PCI_DFLT_LNSZ; 351195784Srpaulo /* 352195784Srpaulo * Note that pci_conf_read is a 32 bit word aligned function. 353195784Srpaulo */ 354195784Srpaulo data = pci_conf_read(cfid, PCIR_COMMAND); 355195618Srpaulo if (prefer_mem_map) { 356195618Srpaulo if (data & PCI_COMMAND_MEM_ENABLE) { 357195618Srpaulo if (pci_map_mem(cfid, MEM_MAP_REG, &vaddr, &paddr)) { 358195618Srpaulo pcs->pci_st = MEM_SPACE_MAPPING; 359195618Srpaulo pcs->pci_sh = vaddr; 360195618Srpaulo mapped++; 361195618Srpaulo } 362195618Srpaulo } 363195618Srpaulo if (mapped == 0 && (data & PCI_COMMAND_IO_ENABLE)) { 364195618Srpaulo if (pci_map_port(cfid, PCI_MAP_REG_START, &io_port)) { 365195618Srpaulo pcs->pci_st = IO_SPACE_MAPPING; 366195618Srpaulo pcs->pci_sh = io_port; 367187801Ssam mapped++; 368187801Ssam } 369187801Ssam } 370187801Ssam } else { 371138568Ssam if (data & PCI_COMMAND_IO_ENABLE) { 372138568Ssam if (pci_map_port(cfid, PCI_MAP_REG_START, &io_port)) { 373187801Ssam pcs->pci_st = IO_SPACE_MAPPING; 374138568Ssam pcs->pci_sh = io_port; 375138568Ssam mapped++; 376138568Ssam } 377138568Ssam } 378138568Ssam if (mapped == 0 && (data & PCI_COMMAND_MEM_ENABLE)) { 379138568Ssam if (pci_map_mem(cfid, MEM_MAP_REG, &vaddr, &paddr)) { 380138568Ssam pcs->pci_st = MEM_SPACE_MAPPING; 381187801Ssam pcs->pci_sh = vaddr; 382138568Ssam mapped++; 383187801Ssam } 384187801Ssam } 385187801Ssam } 386187801Ssam if (mapped == 0) { 387187801Ssam printf("isp%d: unable to map any ports!\n", unit); 388138568Ssam free(pcs, M_DEVBUF); 389138568Ssam return; 390138568Ssam } 391138568Ssam if (bootverbose) 392170530Ssam printf("isp%d: using %s space register mapping\n", unit, 393170530Ssam pcs->pci_st == IO_SPACE_MAPPING? "I/O" : "Memory"); 394170530Ssam 395138568Ssam data = pci_conf_read(cfid, PCI_ID_REG); 396170530Ssam pcs->pci_poff[BIU_BLOCK >> _BLK_REG_SHFT] = BIU_REGS_OFF; 397170530Ssam pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS_OFF; 398170530Ssam pcs->pci_poff[SXP_BLOCK >> _BLK_REG_SHFT] = PCI_SXP_REGS_OFF; 399170530Ssam pcs->pci_poff[RISC_BLOCK >> _BLK_REG_SHFT] = PCI_RISC_REGS_OFF; 400170530Ssam pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = DMA_REGS_OFF; 401138568Ssam /* 402138568Ssam * GCC! 403138568Ssam */ 404138568Ssam mdvp = &mdvec; 405138568Ssam basetype = ISP_HA_SCSI_UNKNOWN; 406138568Ssam psize = sizeof (sdparam); 407138568Ssam lim = BUS_SPACE_MAXSIZE_32BIT; 408170530Ssam#ifndef ISP_DISABLE_1020_SUPPORT 409170530Ssam if (data == PCI_QLOGIC_ISP) { 410138568Ssam mdvp = &mdvec; 411138568Ssam basetype = ISP_HA_SCSI_UNKNOWN; 412138568Ssam psize = sizeof (sdparam); 413138568Ssam lim = BUS_SPACE_MAXSIZE_24BIT; 414138568Ssam } 415138568Ssam#endif 416138568Ssam#ifndef ISP_DISABLE_1080_SUPPORT 417138568Ssam if (data == PCI_QLOGIC_ISP1080) { 418138568Ssam mdvp = &mdvec_1080; 419178354Ssam basetype = ISP_HA_SCSI_1080; 420170530Ssam psize = sizeof (sdparam); 421170530Ssam pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 422170530Ssam ISP1080_DMA_REGS_OFF; 423173272Ssam } 424194136Ssam if (data == PCI_QLOGIC_ISP1240) { 425170530Ssam mdvp = &mdvec_1080; 426161146Ssam basetype = ISP_HA_SCSI_12X0; 427170530Ssam psize = 2 * sizeof (sdparam); 428170530Ssam pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = 429170530Ssam ISP1080_DMA_REGS_OFF; 430170530Ssam } 431170530Ssam#endif 432138568Ssam#ifndef ISP_DISABLE_2100_SUPPORT 433170530Ssam if (data == PCI_QLOGIC_ISP2100) { 434178354Ssam mdvp = &mdvec_2100; 435170530Ssam basetype = ISP_HA_FC_2100; 436170530Ssam psize = sizeof (fcparam); 437170530Ssam pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = 438172225Ssam PCI_MBOX_REGS2100_OFF; 439172225Ssam data = pci_conf_read(cfid, PCI_CLASS_REG); 440172225Ssam if ((data & 0xff) < 3) { 441170530Ssam /* 442178354Ssam * XXX: Need to get the actual revision 443194136Ssam * XXX: number of the 2100 FB. At any rate, 444178354Ssam * XXX: lower cache line size for early revision 445178354Ssam * XXX; boards. 446195618Srpaulo */ 447195618Srpaulo linesz = 1; 448195618Srpaulo } 449195618Srpaulo } 450138568Ssam#endif 451138568Ssam#ifndef ISP_DISABLE_2200_SUPPORT 452138568Ssam if (data == PCI_QLOGIC_ISP2200) { 453138568Ssam mdvp = &mdvec_2200; 454138568Ssam basetype = ISP_HA_FC_2200; 455138568Ssam psize = sizeof (fcparam); 456138568Ssam pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = 457138568Ssam PCI_MBOX_REGS2100_OFF; 458138568Ssam } 459138568Ssam#endif 460138568Ssam isp = &pcs->pci_isp; 461170530Ssam isp->isp_param = malloc(psize, M_DEVBUF, M_NOWAIT); 462170530Ssam if (isp->isp_param == NULL) { 463138568Ssam printf("isp%d: cannot allocate parameter data\n", unit); 464138568Ssam return; 465138568Ssam } 466138568Ssam bzero(isp->isp_param, psize); 467138568Ssam isp->isp_mdvec = mdvp; 468138568Ssam isp->isp_type = basetype; 469138568Ssam (void) snprintf(isp->isp_name, sizeof (isp->isp_name), "isp%d", unit); 470138568Ssam isp->isp_osinfo.unit = unit; 471170530Ssam 472170530Ssam ISP_LOCK(isp); 473138568Ssam 474138568Ssam /* 475138568Ssam * Make sure that SERR, PERR, WRITE INVALIDATE and BUSMASTER 476178354Ssam * are set. 477178354Ssam */ 478178354Ssam data = pci_cfgread(cfid, PCIR_COMMAND, 2); 479178354Ssam data |= PCIM_CMD_SEREN | 480178354Ssam PCIM_CMD_PERRESPEN | 481178354Ssam PCIM_CMD_BUSMASTEREN | 482138568Ssam PCIM_CMD_INVEN; 483138568Ssam pci_cfgwrite(cfid, PCIR_COMMAND, 2, data); 484138568Ssam 485138568Ssam /* 486138568Ssam * Make sure the Cache Line Size register is set sensibly. 487178354Ssam */ 488178354Ssam data = pci_cfgread(cfid, PCIR_CACHELNSZ, 1); 489178354Ssam if (data != linesz) { 490178354Ssam data = PCI_DFLT_LNSZ; 491178354Ssam printf("%s: set PCI line size to %d\n", isp->isp_name, data); 492178354Ssam pci_cfgwrite(cfid, PCIR_CACHELNSZ, data, 1); 493178354Ssam } 494178354Ssam 495178354Ssam /* 496178354Ssam * Make sure the Latency Timer is sane. 497178354Ssam */ 498178354Ssam data = pci_cfgread(cfid, PCIR_LATTIMER, 1); 499178354Ssam if (data < PCI_DFLT_LTNCY) { 500178354Ssam data = PCI_DFLT_LTNCY; 501178354Ssam printf("%s: set PCI latency to %d\n", isp->isp_name, data); 502178354Ssam pci_cfgwrite(cfid, PCIR_LATTIMER, data, 1); 503178354Ssam } 504178354Ssam 505178354Ssam /* 506178354Ssam * Make sure we've disabled the ROM. 507178354Ssam */ 508178354Ssam data = pci_cfgread(cfid, PCIR_ROMADDR, 4); 509178354Ssam data &= ~1; 510178354Ssam pci_cfgwrite(cfid, PCIR_ROMADDR, data, 4); 511178354Ssam ISP_UNLOCK(isp); 512178354Ssam 513178354Ssam if (bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT, 514178354Ssam BUS_SPACE_MAXADDR, NULL, NULL, lim + 1, 515178354Ssam 255, lim, 0, &pcs->parent_dmat) != 0) { 516178354Ssam printf("%s: could not create master dma tag\n", isp->isp_name); 517178354Ssam free(pcs, M_DEVBUF); 518178354Ssam return; 519178354Ssam } 520178354Ssam if (pci_map_int(cfid, (void (*)(void *))isp_intr, 521178354Ssam (void *)isp, &IMASK) == 0) { 522178354Ssam printf("%s: could not map interrupt\n", isp->isp_name); 523178354Ssam free(pcs, M_DEVBUF); 524178354Ssam return; 525178354Ssam } 526178354Ssam 527178354Ssam pcs->pci_id = cfid; 528178354Ssam#ifdef SCSI_ISP_NO_FWLOAD_MASK 529178354Ssam if (SCSI_ISP_NO_FWLOAD_MASK && (SCSI_ISP_NO_FWLOAD_MASK & (1 << unit))) 530178354Ssam isp->isp_confopts |= ISP_CFG_NORELOAD; 531178354Ssam#endif 532178354Ssam if (getenv_int("isp_no_fwload", &bitmap)) { 533178354Ssam if (bitmap & (1 << unit)) 534178354Ssam isp->isp_confopts |= ISP_CFG_NORELOAD; 535178354Ssam } 536178354Ssam if (getenv_int("isp_fwload", &bitmap)) { 537178354Ssam if (bitmap & (1 << unit)) 538178354Ssam isp->isp_confopts &= ~ISP_CFG_NORELOAD; 539178354Ssam } 540178354Ssam 541187801Ssam#ifdef SCSI_ISP_NO_NVRAM_MASK 542187801Ssam if (SCSI_ISP_NO_NVRAM_MASK && (SCSI_ISP_NO_NVRAM_MASK & (1 << unit))) { 543187801Ssam printf("%s: ignoring NVRAM\n", isp->isp_name); 544187801Ssam isp->isp_confopts |= ISP_CFG_NONVRAM; 545187801Ssam } 546178354Ssam#endif 547178354Ssam if (getenv_int("isp_no_nvram", &bitmap)) { 548178354Ssam if (bitmap & (1 << unit)) 549178354Ssam isp->isp_confopts |= ISP_CFG_NONVRAM; 550178354Ssam } 551178354Ssam if (getenv_int("isp_nvram", &bitmap)) { 552178354Ssam if (bitmap & (1 << unit)) 553178354Ssam isp->isp_confopts &= ~ISP_CFG_NONVRAM; 554178354Ssam } 555178354Ssam 556178354Ssam#ifdef SCSI_ISP_FCDUPLEX 557178354Ssam if (IS_FC(isp)) { 558187801Ssam if (SCSI_ISP_FCDUPLEX && (SCSI_ISP_FCDUPLEX & (1 << unit))) { 559187801Ssam isp->isp_confopts |= ISP_CFG_FULL_DUPLEX; 560187801Ssam } 561187801Ssam } 562187801Ssam#endif 563178354Ssam if (getenv_int("isp_fcduplex", &bitmap)) { 564178354Ssam if (bitmap & (1 << unit)) 565178354Ssam isp->isp_confopts |= ISP_CFG_FULL_DUPLEX; 566178354Ssam } 567178354Ssam if (getenv_int("isp_no_fcduplex", &bitmap)) { 568178354Ssam if (bitmap & (1 << unit)) 569178354Ssam isp->isp_confopts &= ~ISP_CFG_FULL_DUPLEX; 570178354Ssam } 571178354Ssam 572178354Ssam if (getenv_int("isp_seed", &isp->isp_osinfo.seed)) { 573178354Ssam isp->isp_osinfo.seed <<= 8; 574178354Ssam isp->isp_osinfo.seed += (unit + 1); 575178354Ssam } else { 576178354Ssam /* 577178354Ssam * poor man's attempt at pseudo randomness. 578116742Ssam */ 579116742Ssam long i = (intptr_t) isp; 580116742Ssam 581116742Ssam i >>= 5; 582116742Ssam i &= 0x7; 583116742Ssam 584116742Ssam /* 585170530Ssam * This isn't very random, but it's the best we can do for 586116742Ssam * the real edge case of cards that don't have WWNs. 587223145Skevlo */ 588116742Ssam isp->isp_osinfo.seed += ((int) cfid->bus) << 16; 589116742Ssam isp->isp_osinfo.seed += ((int) cfid->slot) << 8; 590116742Ssam isp->isp_osinfo.seed += ((int) cfid->func); 591116742Ssam while (version[i]) 592170530Ssam isp->isp_osinfo.seed += (int) version[i++]; 593116742Ssam isp->isp_osinfo.seed <<= 8; 594116742Ssam isp->isp_osinfo.seed += (unit + 1); 595116742Ssam } 596116742Ssam 597116742Ssam ISP_LOCK(isp); 598116742Ssam isp_reset(isp); 599116742Ssam if (isp->isp_state != ISP_RESETSTATE) { 600116742Ssam (void) pci_unmap_int(cfid); 601116742Ssam ISP_UNLOCK(isp); 602116742Ssam free(pcs, M_DEVBUF); 603116742Ssam return; 604116742Ssam } 605116742Ssam isp_init(isp); 606116742Ssam if (isp->isp_state != ISP_INITSTATE) { 607116742Ssam /* If we're a Fibre Channel Card, we allow deferred attach */ 608116742Ssam if (IS_SCSI(isp)) { 609116742Ssam isp_uninit(isp); 610116742Ssam (void) pci_unmap_int(cfid); /* Does nothing */ 611116742Ssam ISP_UNLOCK(isp); 612116742Ssam free(pcs, M_DEVBUF); 613116742Ssam return; 614116742Ssam } 615120480Ssam } 616127648Ssam isp_attach(isp); 617127648Ssam if (isp->isp_state != ISP_RUNSTATE) { 618127648Ssam /* If we're a Fibre Channel Card, we allow deferred attach */ 619127648Ssam if (IS_SCSI(isp)) { 620138568Ssam isp_uninit(isp); 621138568Ssam (void) pci_unmap_int(cfid); /* Does nothing */ 622138568Ssam ISP_UNLOCK(isp); 623138568Ssam free(pcs, M_DEVBUF); 624138568Ssam return; 625138568Ssam } 626138568Ssam } 627138568Ssam ISP_UNLOCK(isp); 628178354Ssam#ifdef __alpha__ 629178354Ssam /* 630154541Ssam * THIS SHOULD NOT HAVE TO BE HERE 631138568Ssam */ 632138568Ssam alpha_register_pci_scsi(cfid->bus, cfid->slot, isp->isp_sim); 633138568Ssam#endif 634138568Ssam} 635138568Ssam 636138568Ssamstatic u_int16_t 637178354Ssamisp_pci_rd_reg(isp, regoff) 638178354Ssam struct ispsoftc *isp; 639138568Ssam int regoff; 640138568Ssam{ 641138568Ssam u_int16_t rv; 642138568Ssam struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 643138568Ssam int offset, oldconf = 0; 644138568Ssam 645161146Ssam if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 646138568Ssam /* 647138568Ssam * We will assume that someone has paused the RISC processor. 648138568Ssam */ 649138568Ssam oldconf = isp_pci_rd_reg(isp, BIU_CONF1); 650138568Ssam isp_pci_wr_reg(isp, BIU_CONF1, oldconf | BIU_PCI_CONF1_SXP); 651138568Ssam } 652138568Ssam offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT]; 653138568Ssam offset += (regoff & 0xff); 654138568Ssam rv = bus_space_read_2(pcs->pci_st, pcs->pci_sh, offset); 655138568Ssam if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 656147794Ssam isp_pci_wr_reg(isp, BIU_CONF1, oldconf); 657170530Ssam } 658170530Ssam return (rv); 659170530Ssam} 660170530Ssam 661170530Ssamstatic void 662170530Ssamisp_pci_wr_reg(isp, regoff, val) 663178354Ssam struct ispsoftc *isp; 664148292Ssam int regoff; 665153421Ssam u_int16_t val; 666154541Ssam{ 667160686Ssam struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 668161146Ssam int offset, oldconf = 0; 669170530Ssam 670170530Ssam if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 671170530Ssam /* 672170530Ssam * We will assume that someone has paused the RISC processor. 673170530Ssam */ 674170530Ssam oldconf = isp_pci_rd_reg(isp, BIU_CONF1); 675170530Ssam isp_pci_wr_reg(isp, BIU_CONF1, oldconf | BIU_PCI_CONF1_SXP); 676170530Ssam } 677170530Ssam offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT]; 678170530Ssam offset += (regoff & 0xff); 679178354Ssam bus_space_write_2(pcs->pci_st, pcs->pci_sh, offset, val); 680170530Ssam if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 681178354Ssam isp_pci_wr_reg(isp, BIU_CONF1, oldconf); 682172062Ssam } 683178354Ssam} 684178354Ssam 685178354Ssam#ifndef ISP_DISABLE_1080_SUPPORT 686178354Ssamstatic u_int16_t 687178354Ssamisp_pci_rd_reg_1080(isp, regoff) 688178354Ssam struct ispsoftc *isp; 689178354Ssam int regoff; 690173273Ssam{ 691178354Ssam u_int16_t rv; 692178354Ssam struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 693173273Ssam int offset, oc = 0; 694178354Ssam 695178354Ssam if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 696178354Ssam /* 697178354Ssam * We will assume that someone has paused the RISC processor. 698183255Ssam */ 699183256Ssam oc = isp_pci_rd_reg(isp, BIU_CONF1); 700193548Ssam isp_pci_wr_reg(isp, BIU_CONF1, oc | BIU_PCI1080_CONF1_SXP); 701193548Ssam } else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) { 702116742Ssam oc = isp_pci_rd_reg(isp, BIU_CONF1); 703195618Srpaulo isp_pci_wr_reg(isp, BIU_CONF1, oc | BIU_PCI1080_CONF1_DMA); 704195618Srpaulo } 705195618Srpaulo offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT]; 706195618Srpaulo offset += (regoff & 0xff); 707195618Srpaulo rv = bus_space_read_2(pcs->pci_st, pcs->pci_sh, offset); 708195618Srpaulo if ((regoff & _BLK_REG_MASK) == SXP_BLOCK || 709195618Srpaulo ((regoff & _BLK_REG_MASK) == DMA_BLOCK)) { 710195618Srpaulo isp_pci_wr_reg(isp, BIU_CONF1, oc); 711195618Srpaulo } 712195618Srpaulo return (rv); 713195618Srpaulo} 714234892Smonthadar 715195618Srpaulostatic void 716195618Srpauloisp_pci_wr_reg_1080(isp, regoff, val) 717195618Srpaulo struct ispsoftc *isp; 718195618Srpaulo int regoff; 719195618Srpaulo u_int16_t val; 720186904Ssam{ 721186904Ssam struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; 722186904Ssam int offset, oc = 0; 723186904Ssam 724186904Ssam if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) { 725227331Sadrian /* 726227331Sadrian * We will assume that someone has paused the RISC processor. 727227331Sadrian */ 728227331Sadrian oc = isp_pci_rd_reg(isp, BIU_CONF1); 729227331Sadrian isp_pci_wr_reg(isp, BIU_CONF1, oc | BIU_PCI1080_CONF1_SXP); 730138568Ssam } else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) { 731178354Ssam oc = isp_pci_rd_reg(isp, BIU_CONF1); 732178354Ssam isp_pci_wr_reg(isp, BIU_CONF1, oc | BIU_PCI1080_CONF1_DMA); 733178354Ssam } 734178354Ssam offset = pcs->pci_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT]; 735178354Ssam offset += (regoff & 0xff); 736178354Ssam bus_space_write_2(pcs->pci_st, pcs->pci_sh, offset, val); 737178354Ssam if ((regoff & _BLK_REG_MASK) == SXP_BLOCK || 738178354Ssam ((regoff & _BLK_REG_MASK) == DMA_BLOCK)) { 739178354Ssam isp_pci_wr_reg(isp, BIU_CONF1, oc); 740178354Ssam } 741178354Ssam} 742178354Ssam#endif 743178354Ssam 744178354Ssam 745178354Ssamstatic void isp_map_rquest __P((void *, bus_dma_segment_t *, int, int)); 746178354Ssamstatic void isp_map_result __P((void *, bus_dma_segment_t *, int, int)); 747178354Ssamstatic void isp_map_fcscrt __P((void *, bus_dma_segment_t *, int, int)); 748178354Ssam 749178354Ssamstruct imush { 750178354Ssam struct ispsoftc *isp; 751178354Ssam int error; 752178354Ssam}; 753178354Ssam 754178354Ssamstatic void 755178354Ssamisp_map_rquest(void *arg, bus_dma_segment_t *segs, int nseg, int error) 756178354Ssam{ 757178354Ssam struct imush *imushp = (struct imush *) arg; 758178354Ssam if (error) { 759178354Ssam imushp->error = error; 760178354Ssam } else { 761178354Ssam imushp->isp->isp_rquest_dma = segs->ds_addr; 762178354Ssam } 763178354Ssam} 764178354Ssam 765178354Ssamstatic void 766178354Ssamisp_map_result(void *arg, bus_dma_segment_t *segs, int nseg, int error) 767178354Ssam{ 768178354Ssam struct imush *imushp = (struct imush *) arg; 769178354Ssam if (error) { 770178354Ssam imushp->error = error; 771178354Ssam } else { 772178354Ssam imushp->isp->isp_result_dma = segs->ds_addr; 773178354Ssam } 774178354Ssam} 775178354Ssam 776178354Ssamstatic void 777178354Ssamisp_map_fcscrt(void *arg, bus_dma_segment_t *segs, int nseg, int error) 778178354Ssam{ 779178354Ssam struct imush *imushp = (struct imush *) arg; 780178354Ssam if (error) { 781178354Ssam imushp->error = error; 782178354Ssam } else { 783178354Ssam fcparam *fcp = imushp->isp->isp_param; 784178354Ssam fcp->isp_scdma = segs->ds_addr; 785178354Ssam } 786178354Ssam} 787178354Ssam 788178354Ssamstatic int 789178354Ssamisp_pci_mbxdma(struct ispsoftc *isp) 790138568Ssam{ 791154541Ssam struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp; 792154541Ssam caddr_t base; 793154541Ssam u_int32_t len; 794154541Ssam int i, error; 795154541Ssam bus_size_t lim; 796138568Ssam struct imush im; 797138568Ssam 798178354Ssam 799178354Ssam if (IS_FC(isp) || IS_1080(isp) || IS_12X0(isp)) 800170530Ssam lim = BUS_SPACE_MAXADDR + 1; 801170530Ssam else 802170530Ssam lim = BUS_SPACE_MAXADDR_24BIT + 1; 803154541Ssam 804154541Ssam /* 805199076Srpaulo * Allocate and map the request, result queues, plus FC scratch area. 806170530Ssam */ 807170530Ssam len = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN); 808170530Ssam len += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN); 809170530Ssam if (IS_FC(isp)) { 810170530Ssam len += ISP2100_SCRLEN; 811170530Ssam } 812195618Srpaulo if (bus_dma_tag_create(pci->parent_dmat, PAGE_SIZE, lim, 813195618Srpaulo BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, len, 1, 814195618Srpaulo BUS_SPACE_MAXSIZE_32BIT, 0, &pci->cntrol_dmat) != 0) { 815138568Ssam printf("%s: cannot create a dma tag for control spaces\n", 816121180Ssam isp->isp_name); 817178354Ssam return (1); 818178354Ssam } 819178354Ssam if (bus_dmamem_alloc(pci->cntrol_dmat, (void **)&base, 820178354Ssam BUS_DMA_NOWAIT, &pci->cntrol_dmap) != 0) { 821178354Ssam printf("%s: cannot allocate %d bytes of CCB memory\n", 822178354Ssam isp->isp_name, len); 823178354Ssam return (1); 824178354Ssam } 825178354Ssam 826178354Ssam isp->isp_rquest = base; 827178354Ssam im.isp = isp; 828178354Ssam im.error = 0; 829178354Ssam bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap, isp->isp_rquest, 830178354Ssam ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN), isp_map_rquest, &im, 0); 831178354Ssam if (im.error) { 832178354Ssam printf("%s: error %d loading dma map for DMA request queue\n", 833178354Ssam isp->isp_name, im.error); 834178354Ssam return (1); 835178354Ssam } 836178354Ssam isp->isp_result = base + ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN); 837178354Ssam im.error = 0; 838178354Ssam bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap, isp->isp_result, 839178354Ssam ISP_QUEUE_SIZE(RESULT_QUEUE_LEN), isp_map_result, &im, 0); 840178354Ssam if (im.error) { 841178354Ssam printf("%s: error %d loading dma map for DMA result queue\n", 842178354Ssam isp->isp_name, im.error); 843178354Ssam return (1); 844178354Ssam } 845178354Ssam 846178354Ssam /* 847170530Ssam * Use this opportunity to initialize/create data DMA maps. 848170530Ssam */ 849178354Ssam for (i = 0; i < MAXISPREQUEST; i++) { 850178354Ssam error = bus_dmamap_create(pci->parent_dmat, 0, &pci->dmaps[i]); 851178354Ssam if (error) { 852178354Ssam printf("%s: error %d creating mailbox DMA maps\n", 853170530Ssam isp->isp_name, error); 854178354Ssam return (1); 855178354Ssam } 856178354Ssam } 857178354Ssam if (IS_FC(isp)) { 858186904Ssam fcparam *fcp = (fcparam *) isp->isp_param; 859116742Ssam fcp->isp_scratch = base + 860116742Ssam ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN) + 861116742Ssam ISP_QUEUE_SIZE(RESULT_QUEUE_LEN); 862 im.error = 0; 863 bus_dmamap_load(pci->cntrol_dmat, pci->cntrol_dmap, 864 fcp->isp_scratch, ISP2100_SCRLEN, isp_map_fcscrt, &im, 0); 865 if (im.error) { 866 printf("%s: error %d loading FC scratch area\n", 867 isp->isp_name, im.error); 868 return (1); 869 } 870 } 871 return (0); 872} 873 874static void dma2 __P((void *, bus_dma_segment_t *, int, int)); 875typedef struct { 876 struct ispsoftc *isp; 877 ISP_SCSI_XFER_T *ccb; 878 ispreq_t *rq; 879 u_int8_t *iptrp; 880 u_int8_t optr; 881 u_int error; 882} mush_t; 883 884#define MUSHERR_NOQENTRIES -2 885 886static void 887dma2(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 888{ 889 mush_t *mp; 890 ISP_SCSI_XFER_T *ccb; 891 struct ispsoftc *isp; 892 struct isp_pcisoftc *pci; 893 bus_dmamap_t *dp; 894 bus_dma_segment_t *eseg; 895 ispreq_t *rq; 896 u_int8_t *iptrp; 897 u_int8_t optr; 898 ispcontreq_t *crq; 899 int drq, seglim, datalen; 900 901 mp = (mush_t *) arg; 902 if (error) { 903 mp->error = error; 904 return; 905 } 906 907 isp = mp->isp; 908 if (nseg < 1) { 909 printf("%s: zero or negative segment count\n", isp->isp_name); 910 mp->error = EFAULT; 911 return; 912 } 913 ccb = mp->ccb; 914 rq = mp->rq; 915 iptrp = mp->iptrp; 916 optr = mp->optr; 917 918 pci = (struct isp_pcisoftc *)isp; 919 dp = &pci->dmaps[rq->req_handle - 1]; 920 if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 921 bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREREAD); 922 drq = REQFLAG_DATA_IN; 923 } else { 924 bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREWRITE); 925 drq = REQFLAG_DATA_OUT; 926 } 927 928 datalen = XS_XFRLEN(ccb); 929 if (IS_FC(isp)) { 930 seglim = ISP_RQDSEG_T2; 931 ((ispreqt2_t *)rq)->req_totalcnt = datalen; 932 ((ispreqt2_t *)rq)->req_flags |= drq; 933 } else { 934 seglim = ISP_RQDSEG; 935 rq->req_flags |= drq; 936 } 937 938 eseg = dm_segs + nseg; 939 940 while (datalen != 0 && rq->req_seg_count < seglim && dm_segs != eseg) { 941 if (IS_FC(isp)) { 942 ispreqt2_t *rq2 = (ispreqt2_t *)rq; 943 rq2->req_dataseg[rq2->req_seg_count].ds_base = 944 dm_segs->ds_addr; 945 rq2->req_dataseg[rq2->req_seg_count].ds_count = 946 dm_segs->ds_len; 947 } else { 948 rq->req_dataseg[rq->req_seg_count].ds_base = 949 dm_segs->ds_addr; 950 rq->req_dataseg[rq->req_seg_count].ds_count = 951 dm_segs->ds_len; 952 } 953 datalen -= dm_segs->ds_len; 954#if 0 955 if (IS_FC(isp)) { 956 ispreqt2_t *rq2 = (ispreqt2_t *)rq; 957 printf("%s: seg0[%d] cnt 0x%x paddr 0x%08x\n", 958 isp->isp_name, rq->req_seg_count, 959 rq2->req_dataseg[rq2->req_seg_count].ds_count, 960 rq2->req_dataseg[rq2->req_seg_count].ds_base); 961 } else { 962 printf("%s: seg0[%d] cnt 0x%x paddr 0x%08x\n", 963 isp->isp_name, rq->req_seg_count, 964 rq->req_dataseg[rq->req_seg_count].ds_count, 965 rq->req_dataseg[rq->req_seg_count].ds_base); 966 } 967#endif 968 rq->req_seg_count++; 969 dm_segs++; 970 } 971 972 while (datalen > 0 && dm_segs != eseg) { 973 crq = (ispcontreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, *iptrp); 974 *iptrp = ISP_NXT_QENTRY(*iptrp, RQUEST_QUEUE_LEN); 975 if (*iptrp == optr) { 976#if 0 977 printf("%s: Request Queue Overflow++\n", isp->isp_name); 978#endif 979 mp->error = MUSHERR_NOQENTRIES; 980 return; 981 } 982 rq->req_header.rqs_entry_count++; 983 bzero((void *)crq, sizeof (*crq)); 984 crq->req_header.rqs_entry_count = 1; 985 crq->req_header.rqs_entry_type = RQSTYPE_DATASEG; 986 987 seglim = 0; 988 while (datalen > 0 && seglim < ISP_CDSEG && dm_segs != eseg) { 989 crq->req_dataseg[seglim].ds_base = 990 dm_segs->ds_addr; 991 crq->req_dataseg[seglim].ds_count = 992 dm_segs->ds_len; 993#if 0 994 printf("%s: seg%d[%d] cnt 0x%x paddr 0x%08x\n", 995 isp->isp_name, rq->req_header.rqs_entry_count-1, 996 seglim, crq->req_dataseg[seglim].ds_count, 997 crq->req_dataseg[seglim].ds_base); 998#endif 999 rq->req_seg_count++; 1000 dm_segs++; 1001 seglim++; 1002 datalen -= dm_segs->ds_len; 1003 } 1004 } 1005} 1006 1007static int 1008isp_pci_dmasetup(struct ispsoftc *isp, ISP_SCSI_XFER_T *ccb, ispreq_t *rq, 1009 u_int8_t *iptrp, u_int8_t optr) 1010{ 1011 struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp; 1012 struct ccb_hdr *ccb_h; 1013 struct ccb_scsiio *csio; 1014 bus_dmamap_t *dp = NULL; 1015 mush_t mush, *mp; 1016 1017 csio = (struct ccb_scsiio *) ccb; 1018 ccb_h = &csio->ccb_h; 1019 1020 if ((ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_NONE) { 1021 rq->req_seg_count = 1; 1022 return (CMD_QUEUED); 1023 } 1024 1025 /* 1026 * Do a virtual grapevine step to collect info for 1027 * the callback dma allocation that we have to use... 1028 */ 1029 mp = &mush; 1030 mp->isp = isp; 1031 mp->ccb = ccb; 1032 mp->rq = rq; 1033 mp->iptrp = iptrp; 1034 mp->optr = optr; 1035 mp->error = 0; 1036 1037 if ((ccb_h->flags & CAM_SCATTER_VALID) == 0) { 1038 if ((ccb_h->flags & CAM_DATA_PHYS) == 0) { 1039 int error, s; 1040 1041 dp = &pci->dmaps[rq->req_handle - 1]; 1042 s = splsoftvm(); 1043 error = bus_dmamap_load(pci->parent_dmat, *dp, 1044 csio->data_ptr, csio->dxfer_len, dma2, mp, 0); 1045 if (error == EINPROGRESS) { 1046 bus_dmamap_unload(pci->parent_dmat, *dp); 1047 mp->error = EINVAL; 1048 printf("%s: deferred dma allocation not " 1049 "supported\n", isp->isp_name); 1050 } else if (error && mp->error == 0) { 1051#ifdef DIAGNOSTIC 1052 printf("%s: error %d in dma mapping code\n", 1053 isp->isp_name, error); 1054#endif 1055 mp->error = error; 1056 } 1057 splx(s); 1058 } else { 1059 /* Pointer to physical buffer */ 1060 struct bus_dma_segment seg; 1061 seg.ds_addr = (bus_addr_t)csio->data_ptr; 1062 seg.ds_len = csio->dxfer_len; 1063 dma2(mp, &seg, 1, 0); 1064 } 1065 } else { 1066 struct bus_dma_segment *segs; 1067 1068 if ((ccb_h->flags & CAM_DATA_PHYS) != 0) { 1069 printf("%s: Physical segment pointers unsupported", 1070 isp->isp_name); 1071 mp->error = EINVAL; 1072 } else if ((ccb_h->flags & CAM_SG_LIST_PHYS) == 0) { 1073 printf("%s: Virtual segment addresses unsupported", 1074 isp->isp_name); 1075 mp->error = EINVAL; 1076 } else { 1077 /* Just use the segments provided */ 1078 segs = (struct bus_dma_segment *) csio->data_ptr; 1079 dma2(mp, segs, csio->sglist_cnt, 0); 1080 } 1081 } 1082 if (mp->error) { 1083 int retval = CMD_COMPLETE; 1084 if (mp->error == MUSHERR_NOQENTRIES) { 1085 retval = CMD_EAGAIN; 1086 } else if (mp->error == EFBIG) { 1087 XS_SETERR(csio, CAM_REQ_TOO_BIG); 1088 } else if (mp->error == EINVAL) { 1089 XS_SETERR(csio, CAM_REQ_INVALID); 1090 } else { 1091 XS_SETERR(csio, CAM_UNREC_HBA_ERROR); 1092 } 1093 return (retval); 1094 } else { 1095 /* 1096 * Check to see if we weren't cancelled while sleeping on 1097 * getting DMA resources... 1098 */ 1099 if ((ccb_h->status & CAM_STATUS_MASK) != CAM_REQ_INPROG) { 1100 if (dp) { 1101 bus_dmamap_unload(pci->parent_dmat, *dp); 1102 } 1103 return (CMD_COMPLETE); 1104 } 1105 return (CMD_QUEUED); 1106 } 1107} 1108 1109static void 1110isp_pci_dmateardown(struct ispsoftc *isp, ISP_SCSI_XFER_T *ccb, 1111 u_int32_t handle) 1112{ 1113 struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp; 1114 bus_dmamap_t *dp = &pci->dmaps[handle]; 1115 1116 if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { 1117 bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_POSTREAD); 1118 } else { 1119 bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_POSTWRITE); 1120 } 1121 bus_dmamap_unload(pci->parent_dmat, *dp); 1122} 1123 1124 1125static void 1126isp_pci_reset1(struct ispsoftc *isp) 1127{ 1128 /* Make sure the BIOS is disabled */ 1129 isp_pci_wr_reg(isp, HCCR, PCI_HCCR_CMD_BIOS); 1130} 1131 1132static void 1133isp_pci_dumpregs(struct ispsoftc *isp) 1134{ 1135 struct isp_pcisoftc *pci = (struct isp_pcisoftc *)isp; 1136 printf("%s: PCI Status Command/Status=%lx\n", pci->pci_isp.isp_name, 1137 pci_conf_read(pci->pci_id, PCIR_COMMAND)); 1138} 1139