adv_isa.c revision 112782
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 * 4750477Speter * $FreeBSD: head/sys/dev/advansys/adv_isa.c 112782 2003-03-29 09:46:10Z mdodd $ 4818781Sgibbs */ 4918781Sgibbs 5018781Sgibbs#include <sys/param.h> 5118781Sgibbs#include <sys/systm.h> 5259082Snyan#include <sys/kernel.h> 5318781Sgibbs 5439217Sgibbs#include <machine/bus_pio.h> 5539217Sgibbs#include <machine/bus.h> 5659082Snyan#include <machine/resource.h> 5759082Snyan#include <sys/bus.h> 5859082Snyan#include <sys/rman.h> 5939217Sgibbs 6059082Snyan#include <isa/isavar.h> 6118781Sgibbs 6239217Sgibbs#include <dev/advansys/advansys.h> 6318781Sgibbs 6439217Sgibbs#include <cam/scsi/scsi_all.h> 6539217Sgibbs 6618781Sgibbs#define ADV_ISA_MAX_DMA_ADDR (0x00FFFFFFL) 6718781Sgibbs#define ADV_ISA_MAX_DMA_COUNT (0x00FFFFFFL) 6818781Sgibbs 6918781Sgibbs#define ADV_VL_MAX_DMA_ADDR (0x07FFFFFFL) 7018781Sgibbs#define ADV_VL_MAX_DMA_COUNT (0x07FFFFFFL) 7118781Sgibbs 7239217Sgibbs/* 7339217Sgibbs * The overrun buffer shared amongst all ISA/VL adapters. 7439217Sgibbs */ 7539217Sgibbsstatic u_int8_t* overrun_buf; 7642012Sgibbsstatic bus_dma_tag_t overrun_dmat; 7742012Sgibbsstatic bus_dmamap_t overrun_dmamap; 7842012Sgibbsstatic bus_addr_t overrun_physbase; 7939217Sgibbs 8018781Sgibbs/* Possible port addresses an ISA or VL adapter can live at */ 8145577Seivindstatic u_int16_t adv_isa_ioports[] = 8218781Sgibbs{ 8318781Sgibbs 0x100, 8418781Sgibbs 0x110, /* First selection in BIOS setup */ 8518781Sgibbs 0x120, 8618781Sgibbs 0x130, /* Second selection in BIOS setup */ 8718781Sgibbs 0x140, 8818781Sgibbs 0x150, /* Third selection in BIOS setup */ 8918781Sgibbs 0x190, /* Fourth selection in BIOS setup */ 9018781Sgibbs 0x210, /* Fifth selection in BIOS setup */ 9118781Sgibbs 0x230, /* Sixth selection in BIOS setup */ 9218781Sgibbs 0x250, /* Seventh selection in BIOS setup */ 9318781Sgibbs 0x330 /* Eighth and default selection in BIOS setup */ 9418781Sgibbs}; 9518781Sgibbs 9639217Sgibbs#define MAX_ISA_IOPORT_INDEX (sizeof(adv_isa_ioports)/sizeof(u_int16_t) - 1) 9718781Sgibbs 9859082Snyanstatic int adv_isa_probe(device_t dev); 9959082Snyanstatic int adv_isa_attach(device_t dev); 10039217Sgibbsstatic void adv_set_isapnp_wait_for_key(void); 10139217Sgibbsstatic int adv_get_isa_dma_channel(struct adv_softc *adv); 10239217Sgibbsstatic int adv_set_isa_dma_settings(struct adv_softc *adv); 10318781Sgibbs 10418781Sgibbsstatic int 10559082Snyanadv_isa_probe(device_t dev) 10618781Sgibbs{ 10718781Sgibbs int port_index; 10818781Sgibbs int max_port_index; 10976309Snyan u_long iobase, iocount, irq; 11076309Snyan int user_iobase = 0; 11159082Snyan int rid = 0; 11259082Snyan void *ih; 11359082Snyan struct resource *iores, *irqres; 11418781Sgibbs 11518781Sgibbs /* 11618781Sgibbs * Default to scanning all possible device locations. 11718781Sgibbs */ 11818781Sgibbs port_index = 0; 11918781Sgibbs max_port_index = MAX_ISA_IOPORT_INDEX; 12018781Sgibbs 12176309Snyan if (bus_get_resource(dev, SYS_RES_IOPORT, 0, &iobase, &iocount) == 0) { 12276309Snyan user_iobase = 1; 12318781Sgibbs for (;port_index <= max_port_index; port_index++) 12459082Snyan if (iobase <= adv_isa_ioports[port_index]) 12518781Sgibbs break; 12618781Sgibbs if ((port_index > max_port_index) 12759082Snyan || (iobase != adv_isa_ioports[port_index])) { 12859534Sphk if (bootverbose) 12959534Sphk printf("adv%d: Invalid baseport of 0x%lx specified. " 13059534Sphk "Nearest valid baseport is 0x%x. Failing " 13159082Snyan "probe.\n", device_get_unit(dev), iobase, 13218781Sgibbs (port_index <= max_port_index) ? 13318781Sgibbs adv_isa_ioports[port_index] : 13418781Sgibbs adv_isa_ioports[max_port_index]); 13559082Snyan return ENXIO; 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; 14859171Snyan struct adv_softc *adv; 14939217Sgibbs 15018781Sgibbs if (port_addr == 0) 15118781Sgibbs /* Already been attached */ 15218781Sgibbs continue; 15359082Snyan 15459082Snyan if (bus_set_resource(dev, SYS_RES_IOPORT, 0, port_addr, 1)) 15540160Simp continue; 15640160Simp 15759082Snyan /* XXX what is the real portsize? */ 15859082Snyan iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, 15959082Snyan RF_ACTIVE); 16059082Snyan if (iores == NULL) 16159082Snyan continue; 16259082Snyan 16359082Snyan if (adv_find_signature(rman_get_bustag(iores), 16459171Snyan rman_get_bushandle(iores)) == 0) { 16559171Snyan bus_release_resource(dev, SYS_RES_IOPORT, 0, iores); 16659171Snyan continue; 16759171Snyan } 16818781Sgibbs 16959171Snyan /* 17059171Snyan * Got one. Now allocate our softc 17159171Snyan * and see if we can initialize the card. 17259171Snyan */ 17359171Snyan adv = adv_alloc(dev, rman_get_bustag(iores), 17459171Snyan rman_get_bushandle(iores)); 17559171Snyan if (adv == NULL) { 17659171Snyan bus_release_resource(dev, SYS_RES_IOPORT, 0, iores); 17776309Snyan break; 17859171Snyan } 17959171Snyan 18059171Snyan /* 18159171Snyan * Stop the chip. 18259171Snyan */ 18359171Snyan ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_HALT); 18459171Snyan ADV_OUTW(adv, ADV_CHIP_STATUS, 0); 18559171Snyan /* 18659171Snyan * Determine the chip version. 18759171Snyan */ 18859171Snyan adv->chip_version = ADV_INB(adv, ADV_NONEISA_CHIP_REVISION); 18959171Snyan if ((adv->chip_version >= ADV_CHIP_MIN_VER_VL) 19059171Snyan && (adv->chip_version <= ADV_CHIP_MAX_VER_VL)) { 19159171Snyan adv->type = ADV_VL; 19259171Snyan maxsegsz = ADV_VL_MAX_DMA_COUNT; 19359171Snyan maxsize = BUS_SPACE_MAXSIZE_32BIT; 19459171Snyan lowaddr = ADV_VL_MAX_DMA_ADDR; 19559171Snyan bus_delete_resource(dev, SYS_RES_DRQ, 0); 19659171Snyan } else if ((adv->chip_version >= ADV_CHIP_MIN_VER_ISA) 19759171Snyan && (adv->chip_version <= ADV_CHIP_MAX_VER_ISA)) { 19859171Snyan if (adv->chip_version >= ADV_CHIP_MIN_VER_ISA_PNP) { 19959171Snyan adv->type = ADV_ISAPNP; 20059171Snyan ADV_OUTB(adv, ADV_REG_IFC, 20159171Snyan ADV_IFC_INIT_DEFAULT); 20239217Sgibbs } else { 20359171Snyan adv->type = ADV_ISA; 20439217Sgibbs } 20559171Snyan maxsegsz = ADV_ISA_MAX_DMA_COUNT; 20659171Snyan maxsize = BUS_SPACE_MAXSIZE_24BIT; 20759171Snyan lowaddr = ADV_ISA_MAX_DMA_ADDR; 20859171Snyan adv->isa_dma_speed = ADV_DEF_ISA_DMA_SPEED; 20959171Snyan adv->isa_dma_channel = adv_get_isa_dma_channel(adv); 21059171Snyan bus_set_resource(dev, SYS_RES_DRQ, 0, 21159171Snyan adv->isa_dma_channel, 1); 21259171Snyan } else { 21359171Snyan panic("advisaprobe: Unknown card revision\n"); 21459171Snyan } 21539217Sgibbs 21659171Snyan /* 21759171Snyan * Allocate a parent dmatag for all tags created 21859171Snyan * by the MI portions of the advansys driver 21959171Snyan */ 22059171Snyan /* XXX Should be a child of the ISA bus dma tag */ 221112782Smdodd error = bus_dma_tag_create( 222112782Smdodd /* parent */ NULL, 223112782Smdodd /* alignemnt */ 1, 224112782Smdodd /* boundary */ 0, 225112782Smdodd /* lowaddr */ lowaddr, 226112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 227112782Smdodd /* filter */ NULL, 228112782Smdodd /* filterarg */ NULL, 229112782Smdodd /* maxsize */ maxsize, 230112782Smdodd /* nsegments */ ~0, 231112782Smdodd /* maxsegsz */ maxsegsz, 232112782Smdodd /* flags */ 0, 233112782Smdodd &adv->parent_dmat); 23459171Snyan 23559171Snyan if (error != 0) { 23659171Snyan printf("%s: Could not allocate DMA tag - error %d\n", 23759171Snyan adv_name(adv), error); 23859171Snyan adv_free(adv); 23959171Snyan bus_release_resource(dev, SYS_RES_IOPORT, 0, iores); 24076309Snyan break; 24159171Snyan } 24259171Snyan 24372147Sjhb adv->init_level += 2; 24459171Snyan 24559171Snyan if (overrun_buf == NULL) { 24659171Snyan /* Need to allocate our overrun buffer */ 247112782Smdodd if (bus_dma_tag_create( 248112782Smdodd /* parent */ adv->parent_dmat, 249112782Smdodd /* alignment */ 8, 250112782Smdodd /* boundary */ 0, 251112782Smdodd /* lowaddr */ ADV_ISA_MAX_DMA_ADDR, 252112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 253112782Smdodd /* filter */ NULL, 254112782Smdodd /* filterarg */ NULL, 255112782Smdodd /* maxsize */ ADV_OVERRUN_BSIZE, 256112782Smdodd /* nsegments */ 1, 257112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT, 258112782Smdodd /* flags */ 0, 259112782Smdodd &overrun_dmat) != 0) { 26059171Snyan adv_free(adv); 26159171Snyan bus_release_resource(dev, SYS_RES_IOPORT, 0, 26259171Snyan iores); 26376309Snyan break; 26439217Sgibbs } 26559171Snyan if (bus_dmamem_alloc(overrun_dmat, 26659171Snyan (void **)&overrun_buf, 26759171Snyan BUS_DMA_NOWAIT, 26859171Snyan &overrun_dmamap) != 0) { 26959171Snyan bus_dma_tag_destroy(overrun_dmat); 27018781Sgibbs adv_free(adv); 27159171Snyan bus_release_resource(dev, SYS_RES_IOPORT, 0, 27259171Snyan iores); 27376309Snyan break; 27418781Sgibbs } 27559171Snyan /* And permanently map it in */ 27659171Snyan bus_dmamap_load(overrun_dmat, overrun_dmamap, 27759171Snyan overrun_buf, ADV_OVERRUN_BSIZE, 27859171Snyan adv_map, &overrun_physbase, 27959171Snyan /*flags*/0); 28059171Snyan } 28139217Sgibbs 28259171Snyan adv->overrun_physbase = overrun_physbase; 28318781Sgibbs 28459171Snyan if (adv_init(adv) != 0) { 28572147Sjhb bus_dmamap_unload(overrun_dmat, overrun_dmamap); 28672147Sjhb bus_dmamem_free(overrun_dmat, overrun_buf, 28772147Sjhb overrun_dmamap); 28872147Sjhb bus_dma_tag_destroy(overrun_dmat); 28959171Snyan adv_free(adv); 29059171Snyan bus_release_resource(dev, SYS_RES_IOPORT, 0, iores); 29176309Snyan break; 29259171Snyan } 29359171Snyan 29459171Snyan switch (adv->type) { 29559171Snyan case ADV_ISAPNP: 29659171Snyan if (adv->chip_version == ADV_CHIP_VER_ASYN_BUG) { 29759171Snyan adv->bug_fix_control 29859171Snyan |= ADV_BUG_FIX_ASYN_USE_SYN; 29959171Snyan adv->fix_asyn_xfer = ~0; 30018781Sgibbs } 30159171Snyan /* Fall Through */ 30259171Snyan case ADV_ISA: 30359171Snyan adv->max_dma_count = ADV_ISA_MAX_DMA_COUNT; 30459171Snyan adv->max_dma_addr = ADV_ISA_MAX_DMA_ADDR; 30559171Snyan adv_set_isa_dma_settings(adv); 30659171Snyan break; 30759171Snyan 30859171Snyan case ADV_VL: 30959171Snyan adv->max_dma_count = ADV_VL_MAX_DMA_COUNT; 31059171Snyan adv->max_dma_addr = ADV_VL_MAX_DMA_ADDR; 31159171Snyan break; 31259171Snyan default: 31359171Snyan panic("advisaprobe: Invalid card type\n"); 31459171Snyan } 31518781Sgibbs 31659171Snyan /* Determine our IRQ */ 31759171Snyan if (bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, NULL)) 31859171Snyan bus_set_resource(dev, SYS_RES_IRQ, 0, 31959171Snyan adv_get_chip_irq(adv), 1); 32059171Snyan else 32159171Snyan adv_set_chip_irq(adv, irq); 32240160Simp 32359171Snyan irqres = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, 32459171Snyan RF_ACTIVE); 32559171Snyan if (irqres == NULL || 32676309Snyan bus_setup_intr(dev, irqres, INTR_TYPE_CAM|INTR_ENTROPY, 32776309Snyan adv_intr, adv, &ih)) { 32872147Sjhb bus_dmamap_unload(overrun_dmat, overrun_dmamap); 32972147Sjhb bus_dmamem_free(overrun_dmat, overrun_buf, 33072147Sjhb overrun_dmamap); 33172147Sjhb bus_dma_tag_destroy(overrun_dmat); 33259171Snyan adv_free(adv); 33359171Snyan bus_release_resource(dev, SYS_RES_IOPORT, 0, iores); 33476309Snyan break; 33559171Snyan } 33659082Snyan 33759171Snyan /* Mark as probed */ 33859171Snyan adv_isa_ioports[port_index] = 0; 33959171Snyan return 0; 34018781Sgibbs } 34118781Sgibbs 34276309Snyan if (user_iobase) 34376309Snyan bus_set_resource(dev, SYS_RES_IOPORT, 0, iobase, iocount); 34476309Snyan else 34576309Snyan bus_delete_resource(dev, SYS_RES_IOPORT, 0); 34676309Snyan 34759082Snyan return ENXIO; 34818781Sgibbs} 34918781Sgibbs 35018781Sgibbsstatic int 35159082Snyanadv_isa_attach(device_t dev) 35218781Sgibbs{ 35359082Snyan struct adv_softc *adv = device_get_softc(dev); 35418781Sgibbs 35518781Sgibbs return (adv_attach(adv)); 35618781Sgibbs} 35718781Sgibbs 35839217Sgibbsstatic int 35939217Sgibbsadv_get_isa_dma_channel(struct adv_softc *adv) 36039217Sgibbs{ 36139217Sgibbs int channel; 36239217Sgibbs 36339217Sgibbs channel = ADV_INW(adv, ADV_CONFIG_LSW) & ADV_CFG_LSW_ISA_DMA_CHANNEL; 36439217Sgibbs if (channel == 0x03) 36539217Sgibbs return (0); 36639217Sgibbs else if (channel == 0x00) 36739217Sgibbs return (7); 36839217Sgibbs return (channel + 4); 36939217Sgibbs} 37039217Sgibbs 37139217Sgibbsstatic int 37239217Sgibbsadv_set_isa_dma_settings(struct adv_softc *adv) 37339217Sgibbs{ 37439217Sgibbs u_int16_t cfg_lsw; 37539217Sgibbs u_int8_t value; 37639217Sgibbs 37739217Sgibbs if ((adv->isa_dma_channel >= 5) && (adv->isa_dma_channel <= 7)) { 37839217Sgibbs if (adv->isa_dma_channel == 7) 37939217Sgibbs value = 0x00; 38039217Sgibbs else 38139217Sgibbs value = adv->isa_dma_channel - 4; 38239217Sgibbs cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW) 38339217Sgibbs & ~ADV_CFG_LSW_ISA_DMA_CHANNEL; 38439217Sgibbs cfg_lsw |= value; 38539217Sgibbs ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw); 38639217Sgibbs 38739217Sgibbs adv->isa_dma_speed &= 0x07; 38839217Sgibbs adv_set_bank(adv, 1); 38939217Sgibbs ADV_OUTB(adv, ADV_DMA_SPEED, adv->isa_dma_speed); 39039217Sgibbs adv_set_bank(adv, 0); 39139217Sgibbs isa_dmacascade(adv->isa_dma_channel); 39239217Sgibbs } 39339217Sgibbs return (0); 39439217Sgibbs} 39539217Sgibbs 39618781Sgibbsstatic void 39718781Sgibbsadv_set_isapnp_wait_for_key(void) 39818781Sgibbs{ 39918781Sgibbs static int isapnp_wait_set = 0; 40018781Sgibbs if (isapnp_wait_set == 0) { 40118781Sgibbs outb(ADV_ISA_PNP_PORT_ADDR, 0x02); 40218781Sgibbs outb(ADV_ISA_PNP_PORT_WRITE, 0x02); 40318781Sgibbs isapnp_wait_set++; 40418781Sgibbs } 40518781Sgibbs} 40618781Sgibbs 40759082Snyanstatic device_method_t adv_isa_methods[] = { 40859082Snyan /* Device interface */ 40959082Snyan DEVMETHOD(device_probe, adv_isa_probe), 41059082Snyan DEVMETHOD(device_attach, adv_isa_attach), 41159082Snyan { 0, 0 } 41259082Snyan}; 41359082Snyan 41459082Snyanstatic driver_t adv_isa_driver = { 41559082Snyan "adv", adv_isa_methods, sizeof(struct adv_softc) 41659082Snyan}; 41759082Snyan 41859082Snyanstatic devclass_t adv_isa_devclass; 41959082SnyanDRIVER_MODULE(adv, isa, adv_isa_driver, adv_isa_devclass, 0, 0); 420