adv_isa.c revision 45577
118781Sgibbs/* 218781Sgibbs * Device probe and attach routines for the following 318781Sgibbs * Advanced Systems Inc. SCSI controllers: 418781Sgibbs * 539217Sgibbs * Connectivity Products: 639217Sgibbs * ABP510/5150 - Bus-Master ISA (240 CDB) * 739217Sgibbs * ABP5140 - Bus-Master ISA PnP (16 CDB) * ** 839217Sgibbs * ABP5142 - Bus-Master ISA PnP with floppy (16 CDB) *** 918781Sgibbs * 1039217Sgibbs * Single Channel Products: 1139217Sgibbs * ABP542 - Bus-Master ISA with floppy (240 CDB) 1239217Sgibbs * ABP842 - Bus-Master VL (240 CDB) 1318781Sgibbs * 1439217Sgibbs * Dual Channel Products: 1539217Sgibbs * ABP852 - Dual Channel Bus-Master VL (240 CDB Per Channel) 1618781Sgibbs * 1739217Sgibbs * * This board has been shipped by HP with the 4020i CD-R drive. 1839217Sgibbs * The board has no BIOS so it cannot control a boot device, but 1939217Sgibbs * it can control any secondary SCSI device. 2039217Sgibbs * ** This board has been sold by SIIG as the i540 SpeedMaster. 2139217Sgibbs * *** This board has been sold by SIIG as the i542 SpeedMaster. 2239217Sgibbs * 2339217Sgibbs * Copyright (c) 1996, 1997 Justin T. Gibbs. 2418781Sgibbs * All rights reserved. 2518781Sgibbs * 2618781Sgibbs * Redistribution and use in source and binary forms, with or without 2718781Sgibbs * modification, are permitted provided that the following conditions 2818781Sgibbs * are met: 2918781Sgibbs * 1. Redistributions of source code must retain the above copyright 3039217Sgibbs * notice, this list of conditions, and the following disclaimer, 3139217Sgibbs * without modification, immediately at the beginning of the file. 3239217Sgibbs * 2. The name of the author may not be used to endorse or promote products 3318781Sgibbs * derived from this software without specific prior written permission. 3418781Sgibbs * 3518781Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 3618781Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 3718781Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 3818781Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 3918781Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 4018781Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 4118781Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4218781Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 4318781Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 4418781Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 4518781Sgibbs * SUCH DAMAGE. 4618781Sgibbs * 4745577Seivind * $Id: adv_isa.c,v 1.8 1998/12/22 18:14:12 gibbs Exp $ 4818781Sgibbs */ 4918781Sgibbs 5018781Sgibbs#include <sys/param.h> 5118781Sgibbs#include <sys/systm.h> 5239217Sgibbs#include <sys/malloc.h> 5318781Sgibbs 5439217Sgibbs#include <machine/bus_pio.h> 5539217Sgibbs#include <machine/bus.h> 5639217Sgibbs 5718781Sgibbs#include <i386/isa/isa.h> 5818781Sgibbs#include <i386/isa/isa_device.h> 5918781Sgibbs 6039217Sgibbs#include <dev/advansys/advansys.h> 6118781Sgibbs 6239217Sgibbs#include <cam/scsi/scsi_all.h> 6339217Sgibbs 6418781Sgibbs#define ADV_ISA_MAX_DMA_ADDR (0x00FFFFFFL) 6518781Sgibbs#define ADV_ISA_MAX_DMA_COUNT (0x00FFFFFFL) 6618781Sgibbs 6718781Sgibbs#define ADV_VL_MAX_DMA_ADDR (0x07FFFFFFL) 6818781Sgibbs#define ADV_VL_MAX_DMA_COUNT (0x07FFFFFFL) 6918781Sgibbs 7039217Sgibbs/* 7139217Sgibbs * The overrun buffer shared amongst all ISA/VL adapters. 7239217Sgibbs */ 7339217Sgibbsstatic u_int8_t* overrun_buf; 7442012Sgibbsstatic bus_dma_tag_t overrun_dmat; 7542012Sgibbsstatic bus_dmamap_t overrun_dmamap; 7642012Sgibbsstatic bus_addr_t overrun_physbase; 7739217Sgibbs 7818781Sgibbs/* Possible port addresses an ISA or VL adapter can live at */ 7945577Seivindstatic u_int16_t adv_isa_ioports[] = 8018781Sgibbs{ 8118781Sgibbs 0x100, 8218781Sgibbs 0x110, /* First selection in BIOS setup */ 8318781Sgibbs 0x120, 8418781Sgibbs 0x130, /* Second selection in BIOS setup */ 8518781Sgibbs 0x140, 8618781Sgibbs 0x150, /* Third selection in BIOS setup */ 8718781Sgibbs 0x190, /* Fourth selection in BIOS setup */ 8818781Sgibbs 0x210, /* Fifth selection in BIOS setup */ 8918781Sgibbs 0x230, /* Sixth selection in BIOS setup */ 9018781Sgibbs 0x250, /* Seventh selection in BIOS setup */ 9118781Sgibbs 0x330 /* Eighth and default selection in BIOS setup */ 9218781Sgibbs}; 9318781Sgibbs 9439217Sgibbs#define MAX_ISA_IOPORT_INDEX (sizeof(adv_isa_ioports)/sizeof(u_int16_t) - 1) 9518781Sgibbs 9639217Sgibbsstatic int advisaprobe(struct isa_device *id); 9739217Sgibbsstatic int advisaattach(struct isa_device *id); 9839217Sgibbsstatic void adv_set_isapnp_wait_for_key(void); 9939217Sgibbsstatic int adv_get_isa_dma_channel(struct adv_softc *adv); 10039217Sgibbsstatic int adv_set_isa_dma_settings(struct adv_softc *adv); 10118781Sgibbs 10239217Sgibbsvoid adv_isa_intr(void *unit); 10318781Sgibbs 10418781Sgibbsstruct isa_driver advdriver = 10518781Sgibbs{ 10618781Sgibbs advisaprobe, 10718781Sgibbs advisaattach, 10818781Sgibbs "adv" 10918781Sgibbs}; 11018781Sgibbs 11118781Sgibbsstatic int 11239217Sgibbsadvisaprobe(struct isa_device *id) 11318781Sgibbs{ 11418781Sgibbs int port_index; 11518781Sgibbs int max_port_index; 11618781Sgibbs 11718781Sgibbs /* 11818781Sgibbs * Default to scanning all possible device locations. 11918781Sgibbs */ 12018781Sgibbs port_index = 0; 12118781Sgibbs max_port_index = MAX_ISA_IOPORT_INDEX; 12218781Sgibbs 12318781Sgibbs if (id->id_iobase > 0) { 12418781Sgibbs for (;port_index <= max_port_index; port_index++) 12541048Sgibbs if (id->id_iobase <= adv_isa_ioports[port_index]) 12618781Sgibbs break; 12718781Sgibbs if ((port_index > max_port_index) 12818781Sgibbs || (id->id_iobase != adv_isa_ioports[port_index])) { 12918781Sgibbs printf("adv%d: Invalid baseport of 0x%x specified. " 13018781Sgibbs "Neerest valid baseport is 0x%x. Failing " 13118781Sgibbs "probe.\n", id->id_unit, id->id_iobase, 13218781Sgibbs (port_index <= max_port_index) ? 13318781Sgibbs adv_isa_ioports[port_index] : 13418781Sgibbs adv_isa_ioports[max_port_index]); 13518781Sgibbs return 0; 13618781Sgibbs } 13718781Sgibbs max_port_index = port_index; 13818781Sgibbs } 13918781Sgibbs 14018781Sgibbs /* Perform the actual probing */ 14118781Sgibbs adv_set_isapnp_wait_for_key(); 14218781Sgibbs for (;port_index <= max_port_index; port_index++) { 14318781Sgibbs u_int16_t port_addr = adv_isa_ioports[port_index]; 14439217Sgibbs bus_size_t maxsegsz; 14539217Sgibbs bus_size_t maxsize; 14639217Sgibbs bus_addr_t lowaddr; 14739217Sgibbs int error; 14839217Sgibbs 14918781Sgibbs if (port_addr == 0) 15018781Sgibbs /* Already been attached */ 15118781Sgibbs continue; 15240265Simp id->id_iobase = port_addr; 15340265Simp if (haveseen_isadev(id, CC_IOADDR | CC_QUIET)) 15440160Simp continue; 15540160Simp 15639217Sgibbs if (adv_find_signature(I386_BUS_SPACE_IO, port_addr)) { 15718781Sgibbs /* 15818781Sgibbs * Got one. Now allocate our softc 15918781Sgibbs * and see if we can initialize the card. 16018781Sgibbs */ 16118781Sgibbs struct adv_softc *adv; 16239217Sgibbs adv = adv_alloc(id->id_unit, I386_BUS_SPACE_IO, 16339217Sgibbs port_addr); 16418781Sgibbs if (adv == NULL) 16518781Sgibbs return (0); 16618781Sgibbs 16739217Sgibbs adv_unit++; 16839217Sgibbs 16939217Sgibbs id->id_iobase = adv->bsh; 17039217Sgibbs 17118781Sgibbs /* 17239217Sgibbs * Stop the chip. 17339217Sgibbs */ 17439217Sgibbs ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_HALT); 17539217Sgibbs ADV_OUTW(adv, ADV_CHIP_STATUS, 0); 17639217Sgibbs /* 17718781Sgibbs * Determine the chip version. 17818781Sgibbs */ 17918781Sgibbs adv->chip_version = ADV_INB(adv, 18018781Sgibbs ADV_NONEISA_CHIP_REVISION); 18139217Sgibbs if ((adv->chip_version >= ADV_CHIP_MIN_VER_VL) 18239217Sgibbs && (adv->chip_version <= ADV_CHIP_MAX_VER_VL)) { 18339217Sgibbs adv->type = ADV_VL; 18439217Sgibbs maxsegsz = ADV_VL_MAX_DMA_COUNT; 18539217Sgibbs maxsize = BUS_SPACE_MAXSIZE_32BIT; 18639217Sgibbs lowaddr = ADV_VL_MAX_DMA_ADDR; 18739217Sgibbs id->id_drq = -1; 18839217Sgibbs } else if ((adv->chip_version >= ADV_CHIP_MIN_VER_ISA) 18939217Sgibbs && (adv->chip_version <= ADV_CHIP_MAX_VER_ISA)) { 19039217Sgibbs if (adv->chip_version >= ADV_CHIP_MIN_VER_ISA_PNP) { 19139217Sgibbs adv->type = ADV_ISAPNP; 19239217Sgibbs ADV_OUTB(adv, ADV_REG_IFC, 19339217Sgibbs ADV_IFC_INIT_DEFAULT); 19439217Sgibbs } else { 19539217Sgibbs adv->type = ADV_ISA; 19639217Sgibbs } 19739217Sgibbs maxsegsz = ADV_ISA_MAX_DMA_COUNT; 19839217Sgibbs maxsize = BUS_SPACE_MAXSIZE_24BIT; 19939217Sgibbs lowaddr = ADV_ISA_MAX_DMA_ADDR; 20039217Sgibbs adv->isa_dma_speed = ADV_DEF_ISA_DMA_SPEED; 20139217Sgibbs adv->isa_dma_channel = 20239217Sgibbs adv_get_isa_dma_channel(adv); 20339217Sgibbs id->id_drq = adv->isa_dma_channel; 20439217Sgibbs } else { 20539217Sgibbs panic("advisaprobe: Unknown card revision\n"); 20639217Sgibbs } 20739217Sgibbs 20839217Sgibbs /* 20939217Sgibbs * Allocate a parent dmatag for all tags created 21039217Sgibbs * by the MI portions of the advansys driver 21139217Sgibbs */ 21239217Sgibbs /* XXX Should be a child of the ISA bus dma tag */ 21339217Sgibbs error = 21439217Sgibbs bus_dma_tag_create(/*parent*/NULL, 21539217Sgibbs /*alignemnt*/0, 21639217Sgibbs /*boundary*/0, 21739217Sgibbs lowaddr, 21839217Sgibbs /*highaddr*/BUS_SPACE_MAXADDR, 21939217Sgibbs /*filter*/NULL, 22039217Sgibbs /*filterarg*/NULL, 22139217Sgibbs maxsize, 22239217Sgibbs /*nsegs*/BUS_SPACE_UNRESTRICTED, 22339217Sgibbs maxsegsz, 22439217Sgibbs /*flags*/0, 22539217Sgibbs &adv->parent_dmat); 22639217Sgibbs 22739217Sgibbs if (error != 0) { 22839217Sgibbs printf("%s: Could not allocate DMA tag - error %d\n", 22939217Sgibbs adv_name(adv), error); 23039217Sgibbs adv_free(adv); 23139217Sgibbs return (0); 23239217Sgibbs } 23339217Sgibbs 23439217Sgibbs adv->init_level++; 23539217Sgibbs 23639217Sgibbs if (overrun_buf == NULL) { 23739217Sgibbs /* Need to allocate our overrun buffer */ 23839217Sgibbs if (bus_dma_tag_create(adv->parent_dmat, 23939217Sgibbs /*alignment*/8, 24039217Sgibbs /*boundary*/0, 24139217Sgibbs ADV_ISA_MAX_DMA_ADDR, 24239217Sgibbs BUS_SPACE_MAXADDR, 24339217Sgibbs /*filter*/NULL, 24439217Sgibbs /*filterarg*/NULL, 24539217Sgibbs ADV_OVERRUN_BSIZE, 24639217Sgibbs /*nsegments*/1, 24739217Sgibbs BUS_SPACE_MAXSIZE_32BIT, 24839217Sgibbs /*flags*/0, 24939217Sgibbs &overrun_dmat) != 0) { 25039217Sgibbs adv_free(adv); 25139217Sgibbs return (0); 25239217Sgibbs } 25339217Sgibbs if (bus_dmamem_alloc(overrun_dmat, 25439217Sgibbs (void **)&overrun_buf, 25539217Sgibbs BUS_DMA_NOWAIT, 25639217Sgibbs &overrun_dmamap) != 0) { 25739217Sgibbs bus_dma_tag_destroy(overrun_dmat); 25839217Sgibbs adv_free(adv); 25939217Sgibbs return (0); 26039217Sgibbs } 26139217Sgibbs /* And permanently map it in */ 26239217Sgibbs bus_dmamap_load(overrun_dmat, overrun_dmamap, 26339217Sgibbs overrun_buf, ADV_OVERRUN_BSIZE, 26439217Sgibbs adv_map, &overrun_physbase, 26539217Sgibbs /*flags*/0); 26639217Sgibbs } 26739217Sgibbs 26839217Sgibbs adv->overrun_physbase = overrun_physbase; 26918781Sgibbs 27018781Sgibbs if (adv_init(adv) != 0) { 27118781Sgibbs adv_free(adv); 27218781Sgibbs return (0); 27318781Sgibbs } 27439217Sgibbs 27518781Sgibbs switch (adv->type) { 27618781Sgibbs case ADV_ISAPNP: 27739217Sgibbs if (adv->chip_version == ADV_CHIP_VER_ASYN_BUG){ 27839217Sgibbs adv->bug_fix_control 27939217Sgibbs |= ADV_BUG_FIX_ASYN_USE_SYN; 28039217Sgibbs adv->fix_asyn_xfer = ~0; 28139217Sgibbs } 28218781Sgibbs /* Fall Through */ 28318781Sgibbs case ADV_ISA: 28418781Sgibbs adv->max_dma_count = ADV_ISA_MAX_DMA_COUNT; 28539217Sgibbs adv->max_dma_addr = ADV_ISA_MAX_DMA_ADDR; 28639217Sgibbs adv_set_isa_dma_settings(adv); 28718781Sgibbs break; 28818781Sgibbs 28918781Sgibbs case ADV_VL: 29018781Sgibbs adv->max_dma_count = ADV_VL_MAX_DMA_COUNT; 29139217Sgibbs adv->max_dma_addr = ADV_VL_MAX_DMA_ADDR; 29218781Sgibbs break; 29339217Sgibbs default: 29439217Sgibbs panic("advisaprobe: Invalid card type\n"); 29518781Sgibbs } 29618781Sgibbs 29718781Sgibbs /* Determine our IRQ */ 29818781Sgibbs if (id->id_irq == 0 /* irq ? */) 29918781Sgibbs id->id_irq = 1 << adv_get_chip_irq(adv); 30018781Sgibbs else 30118781Sgibbs adv_set_chip_irq(adv, ffs(id->id_irq) - 1); 30240160Simp 30339217Sgibbs id->id_intr = adv_isa_intr; 30418781Sgibbs 30518781Sgibbs /* Mark as probed */ 30618781Sgibbs adv_isa_ioports[port_index] = 0; 30739217Sgibbs return 1; 30818781Sgibbs } 30918781Sgibbs } 31018781Sgibbs 31139217Sgibbs return 0; 31218781Sgibbs} 31318781Sgibbs 31418781Sgibbsstatic int 31539217Sgibbsadvisaattach(struct isa_device *id) 31618781Sgibbs{ 31718781Sgibbs struct adv_softc *adv; 31818781Sgibbs 31918781Sgibbs adv = advsoftcs[id->id_unit]; 32018781Sgibbs return (adv_attach(adv)); 32118781Sgibbs} 32218781Sgibbs 32339217Sgibbsstatic int 32439217Sgibbsadv_get_isa_dma_channel(struct adv_softc *adv) 32539217Sgibbs{ 32639217Sgibbs int channel; 32739217Sgibbs 32839217Sgibbs channel = ADV_INW(adv, ADV_CONFIG_LSW) & ADV_CFG_LSW_ISA_DMA_CHANNEL; 32939217Sgibbs if (channel == 0x03) 33039217Sgibbs return (0); 33139217Sgibbs else if (channel == 0x00) 33239217Sgibbs return (7); 33339217Sgibbs return (channel + 4); 33439217Sgibbs} 33539217Sgibbs 33639217Sgibbsstatic int 33739217Sgibbsadv_set_isa_dma_settings(struct adv_softc *adv) 33839217Sgibbs{ 33939217Sgibbs u_int16_t cfg_lsw; 34039217Sgibbs u_int8_t value; 34139217Sgibbs 34239217Sgibbs if ((adv->isa_dma_channel >= 5) && (adv->isa_dma_channel <= 7)) { 34339217Sgibbs if (adv->isa_dma_channel == 7) 34439217Sgibbs value = 0x00; 34539217Sgibbs else 34639217Sgibbs value = adv->isa_dma_channel - 4; 34739217Sgibbs cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW) 34839217Sgibbs & ~ADV_CFG_LSW_ISA_DMA_CHANNEL; 34939217Sgibbs cfg_lsw |= value; 35039217Sgibbs ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw); 35139217Sgibbs 35239217Sgibbs adv->isa_dma_speed &= 0x07; 35339217Sgibbs adv_set_bank(adv, 1); 35439217Sgibbs ADV_OUTB(adv, ADV_DMA_SPEED, adv->isa_dma_speed); 35539217Sgibbs adv_set_bank(adv, 0); 35639217Sgibbs isa_dmacascade(adv->isa_dma_channel); 35739217Sgibbs } 35839217Sgibbs return (0); 35939217Sgibbs} 36039217Sgibbs 36118781Sgibbsstatic void 36218781Sgibbsadv_set_isapnp_wait_for_key(void) 36318781Sgibbs{ 36418781Sgibbs static int isapnp_wait_set = 0; 36518781Sgibbs if (isapnp_wait_set == 0) { 36618781Sgibbs outb(ADV_ISA_PNP_PORT_ADDR, 0x02); 36718781Sgibbs outb(ADV_ISA_PNP_PORT_WRITE, 0x02); 36818781Sgibbs isapnp_wait_set++; 36918781Sgibbs } 37018781Sgibbs return; 37118781Sgibbs} 37218781Sgibbs 37318781Sgibbs/* 37418781Sgibbs * Handle an ISA interrupt. 37518781Sgibbs * XXX should go away as soon as ISA interrupt handlers 37618781Sgibbs * take a (void *) arg. 37718781Sgibbs */ 37845577Seivindstatic void 37939217Sgibbsadv_isa_intr(void *unit) 38018781Sgibbs{ 38139217Sgibbs struct adv_softc *arg = advsoftcs[(int)unit]; 38218781Sgibbs adv_intr((void *)arg); 38318781Sgibbs} 384