1139749Simp/*- 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 */ 4718781Sgibbs 48119418Sobrien#include <sys/cdefs.h> 49119418Sobrien__FBSDID("$FreeBSD: releng/11.0/sys/dev/advansys/adv_isa.c 298431 2016-04-21 19:40:10Z pfg $"); 50119418Sobrien 5118781Sgibbs#include <sys/param.h> 5218781Sgibbs#include <sys/systm.h> 5359082Snyan#include <sys/kernel.h> 54129879Sphk#include <sys/module.h> 55117126Sscottl#include <sys/lock.h> 56117126Sscottl#include <sys/mutex.h> 5718781Sgibbs 5839217Sgibbs#include <machine/bus.h> 5959082Snyan#include <machine/resource.h> 6059082Snyan#include <sys/bus.h> 6159082Snyan#include <sys/rman.h> 6239217Sgibbs 6359082Snyan#include <isa/isavar.h> 6418781Sgibbs 6539217Sgibbs#include <dev/advansys/advansys.h> 6618781Sgibbs 6739217Sgibbs#include <cam/scsi/scsi_all.h> 6839217Sgibbs 6918781Sgibbs#define ADV_ISA_MAX_DMA_ADDR (0x00FFFFFFL) 7018781Sgibbs#define ADV_ISA_MAX_DMA_COUNT (0x00FFFFFFL) 7118781Sgibbs 7218781Sgibbs#define ADV_VL_MAX_DMA_ADDR (0x07FFFFFFL) 7318781Sgibbs#define ADV_VL_MAX_DMA_COUNT (0x07FFFFFFL) 7418781Sgibbs 7539217Sgibbs/* 7639217Sgibbs * The overrun buffer shared amongst all ISA/VL adapters. 7739217Sgibbs */ 7839217Sgibbsstatic u_int8_t* overrun_buf; 7942012Sgibbsstatic bus_dma_tag_t overrun_dmat; 8042012Sgibbsstatic bus_dmamap_t overrun_dmamap; 8142012Sgibbsstatic bus_addr_t overrun_physbase; 8239217Sgibbs 8318781Sgibbs/* Possible port addresses an ISA or VL adapter can live at */ 8445577Seivindstatic u_int16_t adv_isa_ioports[] = 8518781Sgibbs{ 8618781Sgibbs 0x100, 8718781Sgibbs 0x110, /* First selection in BIOS setup */ 8818781Sgibbs 0x120, 8918781Sgibbs 0x130, /* Second selection in BIOS setup */ 9018781Sgibbs 0x140, 9118781Sgibbs 0x150, /* Third selection in BIOS setup */ 9218781Sgibbs 0x190, /* Fourth selection in BIOS setup */ 9318781Sgibbs 0x210, /* Fifth selection in BIOS setup */ 9418781Sgibbs 0x230, /* Sixth selection in BIOS setup */ 9518781Sgibbs 0x250, /* Seventh selection in BIOS setup */ 9618781Sgibbs 0x330 /* Eighth and default selection in BIOS setup */ 9718781Sgibbs}; 9818781Sgibbs 99298431Spfg#define MAX_ISA_IOPORT_INDEX (nitems(adv_isa_ioports) - 1) 10018781Sgibbs 10159082Snyanstatic int adv_isa_probe(device_t dev); 10259082Snyanstatic int adv_isa_attach(device_t dev); 10339217Sgibbsstatic void adv_set_isapnp_wait_for_key(void); 10439217Sgibbsstatic int adv_get_isa_dma_channel(struct adv_softc *adv); 10539217Sgibbsstatic int adv_set_isa_dma_settings(struct adv_softc *adv); 10618781Sgibbs 10718781Sgibbsstatic int 10859082Snyanadv_isa_probe(device_t dev) 10918781Sgibbs{ 11018781Sgibbs int port_index; 11118781Sgibbs int max_port_index; 112294883Sjhibbits rman_res_t iobase, iocount, irq; 11376309Snyan int user_iobase = 0; 11459082Snyan int rid = 0; 11559082Snyan void *ih; 11659082Snyan struct resource *iores, *irqres; 11718781Sgibbs 11818781Sgibbs /* 119147970Sjhb * We don't know of any PnP ID's for these cards. 120147970Sjhb */ 121147970Sjhb if (isa_get_logicalid(dev) != 0) 122147970Sjhb return (ENXIO); 123147970Sjhb 124147970Sjhb /* 12518781Sgibbs * Default to scanning all possible device locations. 12618781Sgibbs */ 12718781Sgibbs port_index = 0; 12818781Sgibbs max_port_index = MAX_ISA_IOPORT_INDEX; 12918781Sgibbs 13076309Snyan if (bus_get_resource(dev, SYS_RES_IOPORT, 0, &iobase, &iocount) == 0) { 13176309Snyan user_iobase = 1; 13218781Sgibbs for (;port_index <= max_port_index; port_index++) 13359082Snyan if (iobase <= adv_isa_ioports[port_index]) 13418781Sgibbs break; 13518781Sgibbs if ((port_index > max_port_index) 13659082Snyan || (iobase != adv_isa_ioports[port_index])) { 13759534Sphk if (bootverbose) 138241492Sjhb device_printf(dev, 139297000Sjhibbits "Invalid baseport of 0x%jx specified. " 140241492Sjhb "Nearest valid baseport is 0x%x. Failing " 141241492Sjhb "probe.\n", iobase, 142241492Sjhb (port_index <= max_port_index) ? 143241492Sjhb adv_isa_ioports[port_index] : 144241492Sjhb adv_isa_ioports[max_port_index]); 14559082Snyan return ENXIO; 14618781Sgibbs } 14718781Sgibbs max_port_index = port_index; 14818781Sgibbs } 14918781Sgibbs 15018781Sgibbs /* Perform the actual probing */ 15118781Sgibbs adv_set_isapnp_wait_for_key(); 15218781Sgibbs for (;port_index <= max_port_index; port_index++) { 15318781Sgibbs u_int16_t port_addr = adv_isa_ioports[port_index]; 15439217Sgibbs bus_size_t maxsegsz; 15539217Sgibbs bus_size_t maxsize; 15639217Sgibbs bus_addr_t lowaddr; 15739217Sgibbs int error; 15859171Snyan struct adv_softc *adv; 15939217Sgibbs 16018781Sgibbs if (port_addr == 0) 16118781Sgibbs /* Already been attached */ 16218781Sgibbs continue; 16359082Snyan 16459082Snyan if (bus_set_resource(dev, SYS_RES_IOPORT, 0, port_addr, 1)) 16540160Simp continue; 16640160Simp 16759082Snyan /* XXX what is the real portsize? */ 168127135Snjl iores = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, 169127135Snjl RF_ACTIVE); 17059082Snyan if (iores == NULL) 17159082Snyan continue; 17259082Snyan 173241492Sjhb if (adv_find_signature(iores) == 0) { 17459171Snyan bus_release_resource(dev, SYS_RES_IOPORT, 0, iores); 17559171Snyan continue; 17659171Snyan } 17718781Sgibbs 17859171Snyan /* 17959171Snyan * Got one. Now allocate our softc 18059171Snyan * and see if we can initialize the card. 18159171Snyan */ 182241492Sjhb adv = adv_alloc(dev, iores, 0); 18359171Snyan if (adv == NULL) { 18459171Snyan bus_release_resource(dev, SYS_RES_IOPORT, 0, iores); 18576309Snyan break; 18659171Snyan } 18759171Snyan 18859171Snyan /* 18959171Snyan * Stop the chip. 19059171Snyan */ 19159171Snyan ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_HALT); 19259171Snyan ADV_OUTW(adv, ADV_CHIP_STATUS, 0); 19359171Snyan /* 19459171Snyan * Determine the chip version. 19559171Snyan */ 19659171Snyan adv->chip_version = ADV_INB(adv, ADV_NONEISA_CHIP_REVISION); 19759171Snyan if ((adv->chip_version >= ADV_CHIP_MIN_VER_VL) 19859171Snyan && (adv->chip_version <= ADV_CHIP_MAX_VER_VL)) { 19959171Snyan adv->type = ADV_VL; 20059171Snyan maxsegsz = ADV_VL_MAX_DMA_COUNT; 20159171Snyan maxsize = BUS_SPACE_MAXSIZE_32BIT; 20259171Snyan lowaddr = ADV_VL_MAX_DMA_ADDR; 20359171Snyan bus_delete_resource(dev, SYS_RES_DRQ, 0); 20459171Snyan } else if ((adv->chip_version >= ADV_CHIP_MIN_VER_ISA) 20559171Snyan && (adv->chip_version <= ADV_CHIP_MAX_VER_ISA)) { 20659171Snyan if (adv->chip_version >= ADV_CHIP_MIN_VER_ISA_PNP) { 20759171Snyan adv->type = ADV_ISAPNP; 20859171Snyan ADV_OUTB(adv, ADV_REG_IFC, 20959171Snyan ADV_IFC_INIT_DEFAULT); 21039217Sgibbs } else { 21159171Snyan adv->type = ADV_ISA; 21239217Sgibbs } 21359171Snyan maxsegsz = ADV_ISA_MAX_DMA_COUNT; 21459171Snyan maxsize = BUS_SPACE_MAXSIZE_24BIT; 21559171Snyan lowaddr = ADV_ISA_MAX_DMA_ADDR; 21659171Snyan adv->isa_dma_speed = ADV_DEF_ISA_DMA_SPEED; 21759171Snyan adv->isa_dma_channel = adv_get_isa_dma_channel(adv); 21859171Snyan bus_set_resource(dev, SYS_RES_DRQ, 0, 21959171Snyan adv->isa_dma_channel, 1); 22059171Snyan } else { 22159171Snyan panic("advisaprobe: Unknown card revision\n"); 22259171Snyan } 22339217Sgibbs 22459171Snyan /* 22559171Snyan * Allocate a parent dmatag for all tags created 22659171Snyan * by the MI portions of the advansys driver 22759171Snyan */ 228112782Smdodd error = bus_dma_tag_create( 229232883Sscottl /* parent */ bus_get_dma_tag(dev), 230112782Smdodd /* alignemnt */ 1, 231112782Smdodd /* boundary */ 0, 232112782Smdodd /* lowaddr */ lowaddr, 233112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 234112782Smdodd /* filter */ NULL, 235112782Smdodd /* filterarg */ NULL, 236112782Smdodd /* maxsize */ maxsize, 237112782Smdodd /* nsegments */ ~0, 238112782Smdodd /* maxsegsz */ maxsegsz, 239112782Smdodd /* flags */ 0, 240241492Sjhb /* lockfunc */ NULL, 241241492Sjhb /* lockarg */ NULL, 242112782Smdodd &adv->parent_dmat); 24359171Snyan 24459171Snyan if (error != 0) { 245241492Sjhb device_printf(dev, 246241492Sjhb "Could not allocate DMA tag - error %d\n", error); 24759171Snyan adv_free(adv); 24859171Snyan bus_release_resource(dev, SYS_RES_IOPORT, 0, iores); 24976309Snyan break; 25059171Snyan } 25159171Snyan 25272147Sjhb adv->init_level += 2; 25359171Snyan 25459171Snyan if (overrun_buf == NULL) { 25559171Snyan /* Need to allocate our overrun buffer */ 256112782Smdodd if (bus_dma_tag_create( 257112782Smdodd /* parent */ adv->parent_dmat, 258112782Smdodd /* alignment */ 8, 259112782Smdodd /* boundary */ 0, 260112782Smdodd /* lowaddr */ ADV_ISA_MAX_DMA_ADDR, 261112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 262112782Smdodd /* filter */ NULL, 263112782Smdodd /* filterarg */ NULL, 264112782Smdodd /* maxsize */ ADV_OVERRUN_BSIZE, 265112782Smdodd /* nsegments */ 1, 266112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT, 267112782Smdodd /* flags */ 0, 268117126Sscottl /* lockfunc */ NULL, 269117126Sscottl /* lockarg */ NULL, 270112782Smdodd &overrun_dmat) != 0) { 27159171Snyan adv_free(adv); 27259171Snyan bus_release_resource(dev, SYS_RES_IOPORT, 0, 27359171Snyan iores); 27476309Snyan break; 27539217Sgibbs } 27659171Snyan if (bus_dmamem_alloc(overrun_dmat, 27759171Snyan (void **)&overrun_buf, 27859171Snyan BUS_DMA_NOWAIT, 27959171Snyan &overrun_dmamap) != 0) { 28059171Snyan bus_dma_tag_destroy(overrun_dmat); 28118781Sgibbs adv_free(adv); 28259171Snyan bus_release_resource(dev, SYS_RES_IOPORT, 0, 28359171Snyan iores); 28476309Snyan break; 28518781Sgibbs } 28659171Snyan /* And permanently map it in */ 28759171Snyan bus_dmamap_load(overrun_dmat, overrun_dmamap, 28859171Snyan overrun_buf, ADV_OVERRUN_BSIZE, 28959171Snyan adv_map, &overrun_physbase, 29059171Snyan /*flags*/0); 29159171Snyan } 29239217Sgibbs 29359171Snyan adv->overrun_physbase = overrun_physbase; 29418781Sgibbs 29559171Snyan if (adv_init(adv) != 0) { 29672147Sjhb bus_dmamap_unload(overrun_dmat, overrun_dmamap); 29772147Sjhb bus_dmamem_free(overrun_dmat, overrun_buf, 29872147Sjhb overrun_dmamap); 29972147Sjhb bus_dma_tag_destroy(overrun_dmat); 30059171Snyan adv_free(adv); 30159171Snyan bus_release_resource(dev, SYS_RES_IOPORT, 0, iores); 30276309Snyan break; 30359171Snyan } 30459171Snyan 30559171Snyan switch (adv->type) { 30659171Snyan case ADV_ISAPNP: 30759171Snyan if (adv->chip_version == ADV_CHIP_VER_ASYN_BUG) { 30859171Snyan adv->bug_fix_control 30959171Snyan |= ADV_BUG_FIX_ASYN_USE_SYN; 31059171Snyan adv->fix_asyn_xfer = ~0; 31118781Sgibbs } 31259171Snyan /* Fall Through */ 31359171Snyan case ADV_ISA: 31459171Snyan adv->max_dma_count = ADV_ISA_MAX_DMA_COUNT; 31559171Snyan adv->max_dma_addr = ADV_ISA_MAX_DMA_ADDR; 31659171Snyan adv_set_isa_dma_settings(adv); 31759171Snyan break; 31859171Snyan 31959171Snyan case ADV_VL: 32059171Snyan adv->max_dma_count = ADV_VL_MAX_DMA_COUNT; 32159171Snyan adv->max_dma_addr = ADV_VL_MAX_DMA_ADDR; 32259171Snyan break; 32359171Snyan default: 32459171Snyan panic("advisaprobe: Invalid card type\n"); 32559171Snyan } 32618781Sgibbs 32759171Snyan /* Determine our IRQ */ 32859171Snyan if (bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, NULL)) 32959171Snyan bus_set_resource(dev, SYS_RES_IRQ, 0, 33059171Snyan adv_get_chip_irq(adv), 1); 33159171Snyan else 33259171Snyan adv_set_chip_irq(adv, irq); 33340160Simp 334127135Snjl irqres = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 335127135Snjl RF_ACTIVE); 33659171Snyan if (irqres == NULL || 337241492Sjhb bus_setup_intr(dev, irqres, INTR_TYPE_CAM|INTR_ENTROPY| 338241492Sjhb INTR_MPSAFE, NULL, adv_intr, adv, &ih) != 0) { 339241492Sjhb if (irqres != NULL) 340241492Sjhb bus_release_resource(dev, SYS_RES_IRQ, rid, 341241492Sjhb irqres); 34272147Sjhb bus_dmamap_unload(overrun_dmat, overrun_dmamap); 34372147Sjhb bus_dmamem_free(overrun_dmat, overrun_buf, 34472147Sjhb overrun_dmamap); 34572147Sjhb bus_dma_tag_destroy(overrun_dmat); 34659171Snyan adv_free(adv); 34759171Snyan bus_release_resource(dev, SYS_RES_IOPORT, 0, iores); 34876309Snyan break; 34959171Snyan } 35059082Snyan 35159171Snyan /* Mark as probed */ 35259171Snyan adv_isa_ioports[port_index] = 0; 35359171Snyan return 0; 35418781Sgibbs } 35518781Sgibbs 35676309Snyan if (user_iobase) 35776309Snyan bus_set_resource(dev, SYS_RES_IOPORT, 0, iobase, iocount); 35876309Snyan else 35976309Snyan bus_delete_resource(dev, SYS_RES_IOPORT, 0); 36076309Snyan 36159082Snyan return ENXIO; 36218781Sgibbs} 36318781Sgibbs 36418781Sgibbsstatic int 36559082Snyanadv_isa_attach(device_t dev) 36618781Sgibbs{ 36759082Snyan struct adv_softc *adv = device_get_softc(dev); 36818781Sgibbs 36918781Sgibbs return (adv_attach(adv)); 37018781Sgibbs} 37118781Sgibbs 37239217Sgibbsstatic int 37339217Sgibbsadv_get_isa_dma_channel(struct adv_softc *adv) 37439217Sgibbs{ 37539217Sgibbs int channel; 37639217Sgibbs 37739217Sgibbs channel = ADV_INW(adv, ADV_CONFIG_LSW) & ADV_CFG_LSW_ISA_DMA_CHANNEL; 37839217Sgibbs if (channel == 0x03) 37939217Sgibbs return (0); 38039217Sgibbs else if (channel == 0x00) 38139217Sgibbs return (7); 38239217Sgibbs return (channel + 4); 38339217Sgibbs} 38439217Sgibbs 38539217Sgibbsstatic int 38639217Sgibbsadv_set_isa_dma_settings(struct adv_softc *adv) 38739217Sgibbs{ 38839217Sgibbs u_int16_t cfg_lsw; 38939217Sgibbs u_int8_t value; 39039217Sgibbs 39139217Sgibbs if ((adv->isa_dma_channel >= 5) && (adv->isa_dma_channel <= 7)) { 39239217Sgibbs if (adv->isa_dma_channel == 7) 39339217Sgibbs value = 0x00; 39439217Sgibbs else 39539217Sgibbs value = adv->isa_dma_channel - 4; 39639217Sgibbs cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW) 39739217Sgibbs & ~ADV_CFG_LSW_ISA_DMA_CHANNEL; 39839217Sgibbs cfg_lsw |= value; 39939217Sgibbs ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw); 40039217Sgibbs 40139217Sgibbs adv->isa_dma_speed &= 0x07; 40239217Sgibbs adv_set_bank(adv, 1); 40339217Sgibbs ADV_OUTB(adv, ADV_DMA_SPEED, adv->isa_dma_speed); 40439217Sgibbs adv_set_bank(adv, 0); 40539217Sgibbs isa_dmacascade(adv->isa_dma_channel); 40639217Sgibbs } 40739217Sgibbs return (0); 40839217Sgibbs} 40939217Sgibbs 41018781Sgibbsstatic void 41118781Sgibbsadv_set_isapnp_wait_for_key(void) 41218781Sgibbs{ 41318781Sgibbs static int isapnp_wait_set = 0; 41418781Sgibbs if (isapnp_wait_set == 0) { 41518781Sgibbs outb(ADV_ISA_PNP_PORT_ADDR, 0x02); 41618781Sgibbs outb(ADV_ISA_PNP_PORT_WRITE, 0x02); 41718781Sgibbs isapnp_wait_set++; 41818781Sgibbs } 41918781Sgibbs} 42018781Sgibbs 42159082Snyanstatic device_method_t adv_isa_methods[] = { 42259082Snyan /* Device interface */ 42359082Snyan DEVMETHOD(device_probe, adv_isa_probe), 42459082Snyan DEVMETHOD(device_attach, adv_isa_attach), 42559082Snyan { 0, 0 } 42659082Snyan}; 42759082Snyan 42859082Snyanstatic driver_t adv_isa_driver = { 42959082Snyan "adv", adv_isa_methods, sizeof(struct adv_softc) 43059082Snyan}; 43159082Snyan 43259082Snyanstatic devclass_t adv_isa_devclass; 43359082SnyanDRIVER_MODULE(adv, isa, adv_isa_driver, adv_isa_devclass, 0, 0); 434165102SmjacobMODULE_DEPEND(adv, isa, 1, 1, 1); 435