From 0a5c401474482bc7ad9d6fa07c5056d624e2ed2c Mon Sep 17 00:00:00 2001 From: gibbs Date: Tue, 15 Sep 1998 07:03:43 +0000 Subject: Advance Systems SCSI Host Adapter driver for CAM. Currently only support the 8bit SCSI AdvanSys products. --- sys/i386/isa/adv_isa.c | 264 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 203 insertions(+), 61 deletions(-) (limited to 'sys/i386/isa/adv_isa.c') diff --git a/sys/i386/isa/adv_isa.c b/sys/i386/isa/adv_isa.c index e7c8915..aa311d6 100644 --- a/sys/i386/isa/adv_isa.c +++ b/sys/i386/isa/adv_isa.c @@ -2,30 +2,34 @@ * Device probe and attach routines for the following * Advanced Systems Inc. SCSI controllers: * - * Connectivity Products: - * ABP5140 - Bus-Master PnP ISA 16 CDB + * Connectivity Products: + * ABP510/5150 - Bus-Master ISA (240 CDB) * + * ABP5140 - Bus-Master ISA PnP (16 CDB) * ** + * ABP5142 - Bus-Master ISA PnP with floppy (16 CDB) *** * - * Single Channel Products: - * ABP542 - Bus-Master ISA 240 CDB - * ABP5150 - Bus-Master ISA 240 CDB (shipped by HP with the 4020i CD-R drive) - * ABP842 - Bus-Master VL 240 CDB + * Single Channel Products: + * ABP542 - Bus-Master ISA with floppy (240 CDB) + * ABP842 - Bus-Master VL (240 CDB) * - * Dual Channel Products: - * ABP852 - Dual Channel Bus-Master VL 240 CDB Per Channel + * Dual Channel Products: + * ABP852 - Dual Channel Bus-Master VL (240 CDB Per Channel) * - * Copyright (c) 1996 Justin T. Gibbs. + * * This board has been shipped by HP with the 4020i CD-R drive. + * The board has no BIOS so it cannot control a boot device, but + * it can control any secondary SCSI device. + * ** This board has been sold by SIIG as the i540 SpeedMaster. + * *** This board has been sold by SIIG as the i542 SpeedMaster. + * + * Copyright (c) 1996, 1997 Justin T. Gibbs. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright - * notice immediately at the beginning of the file, without modification, - * this list of conditions, and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND @@ -40,16 +44,22 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id$ + * $Id: adv_isa.c,v 1.3 1997/02/22 09:35:51 peter Exp $ */ #include #include +#include + +#include +#include #include #include -#include +#include + +#include #define ADV_ISA_MAX_DMA_ADDR (0x00FFFFFFL) #define ADV_ISA_MAX_DMA_COUNT (0x00FFFFFFL) @@ -57,6 +67,14 @@ #define ADV_VL_MAX_DMA_ADDR (0x07FFFFFFL) #define ADV_VL_MAX_DMA_COUNT (0x07FFFFFFL) +/* + * The overrun buffer shared amongst all ISA/VL adapters. + */ +static u_int8_t* overrun_buf; +bus_dma_tag_t overrun_dmat; +bus_dmamap_t overrun_dmamap; +bus_addr_t overrun_physbase; + /* Possible port addresses an ISA or VL adapter can live at */ u_int16_t adv_isa_ioports[] = { @@ -73,14 +91,15 @@ u_int16_t adv_isa_ioports[] = 0x330 /* Eighth and default selection in BIOS setup */ }; -#define MAX_ISA_IOPORT_INDEX (sizeof(adv_isa_ioports)/sizeof(u_short) - 1) +#define MAX_ISA_IOPORT_INDEX (sizeof(adv_isa_ioports)/sizeof(u_int16_t) - 1) -static int advisaprobe __P((struct isa_device *id)); -static int advisaattach __P((struct isa_device *id)); -static void adv_set_isapnp_wait_for_key __P((void)); -static int adv_find_signature __P((u_int16_t iobase)); +static int advisaprobe(struct isa_device *id); +static int advisaattach(struct isa_device *id); +static void adv_set_isapnp_wait_for_key(void); +static int adv_get_isa_dma_channel(struct adv_softc *adv); +static int adv_set_isa_dma_settings(struct adv_softc *adv); -void adv_isa_intr __P((int unit)); +void adv_isa_intr(void *unit); struct isa_driver advdriver = { @@ -90,8 +109,7 @@ struct isa_driver advdriver = }; static int -advisaprobe(id) - struct isa_device *id; +advisaprobe(struct isa_device *id) { int port_index; int max_port_index; @@ -123,65 +141,173 @@ advisaprobe(id) adv_set_isapnp_wait_for_key(); for (;port_index <= max_port_index; port_index++) { u_int16_t port_addr = adv_isa_ioports[port_index]; + bus_size_t maxsegsz; + bus_size_t maxsize; + bus_addr_t lowaddr; + int error; + if (port_addr == 0) /* Already been attached */ continue; - if (adv_find_signature(port_addr)) { + if (adv_find_signature(I386_BUS_SPACE_IO, port_addr)) { /* * Got one. Now allocate our softc * and see if we can initialize the card. */ struct adv_softc *adv; - adv = adv_alloc(id->id_unit, port_addr); + adv = adv_alloc(id->id_unit, I386_BUS_SPACE_IO, + port_addr); if (adv == NULL) return (0); - id->id_iobase = adv->iobase; + adv_unit++; + + id->id_iobase = adv->bsh; + + /* + * Stop the chip. + */ + ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_HALT); + ADV_OUTW(adv, ADV_CHIP_STATUS, 0); /* * Determine the chip version. */ adv->chip_version = ADV_INB(adv, ADV_NONEISA_CHIP_REVISION); + if ((adv->chip_version >= ADV_CHIP_MIN_VER_VL) + && (adv->chip_version <= ADV_CHIP_MAX_VER_VL)) { + adv->type = ADV_VL; + maxsegsz = ADV_VL_MAX_DMA_COUNT; + maxsize = BUS_SPACE_MAXSIZE_32BIT; + lowaddr = ADV_VL_MAX_DMA_ADDR; + id->id_drq = -1; + } else if ((adv->chip_version >= ADV_CHIP_MIN_VER_ISA) + && (adv->chip_version <= ADV_CHIP_MAX_VER_ISA)) { + if (adv->chip_version >= ADV_CHIP_MIN_VER_ISA_PNP) { + adv->type = ADV_ISAPNP; + ADV_OUTB(adv, ADV_REG_IFC, + ADV_IFC_INIT_DEFAULT); + } else { + adv->type = ADV_ISA; + } + maxsegsz = ADV_ISA_MAX_DMA_COUNT; + maxsize = BUS_SPACE_MAXSIZE_24BIT; + lowaddr = ADV_ISA_MAX_DMA_ADDR; + adv->isa_dma_speed = ADV_DEF_ISA_DMA_SPEED; + adv->isa_dma_channel = + adv_get_isa_dma_channel(adv); + id->id_drq = adv->isa_dma_channel; + } else { + panic("advisaprobe: Unknown card revision\n"); + } + + /* + * Allocate a parent dmatag for all tags created + * by the MI portions of the advansys driver + */ + /* XXX Should be a child of the ISA bus dma tag */ + error = + bus_dma_tag_create(/*parent*/NULL, + /*alignemnt*/0, + /*boundary*/0, + lowaddr, + /*highaddr*/BUS_SPACE_MAXADDR, + /*filter*/NULL, + /*filterarg*/NULL, + maxsize, + /*nsegs*/BUS_SPACE_UNRESTRICTED, + maxsegsz, + /*flags*/0, + &adv->parent_dmat); + + if (error != 0) { + printf("%s: Could not allocate DMA tag - error %d\n", + adv_name(adv), error); + adv_free(adv); + return (0); + } + + adv->init_level++; + + if (overrun_buf == NULL) { + /* Need to allocate our overrun buffer */ + if (bus_dma_tag_create(adv->parent_dmat, + /*alignment*/8, + /*boundary*/0, + ADV_ISA_MAX_DMA_ADDR, + BUS_SPACE_MAXADDR, + /*filter*/NULL, + /*filterarg*/NULL, + ADV_OVERRUN_BSIZE, + /*nsegments*/1, + BUS_SPACE_MAXSIZE_32BIT, + /*flags*/0, + &overrun_dmat) != 0) { + adv_free(adv); + return (0); + } + if (bus_dmamem_alloc(overrun_dmat, + (void **)&overrun_buf, + BUS_DMA_NOWAIT, + &overrun_dmamap) != 0) { + bus_dma_tag_destroy(overrun_dmat); + adv_free(adv); + return (0); + } + /* And permanently map it in */ + bus_dmamap_load(overrun_dmat, overrun_dmamap, + overrun_buf, ADV_OVERRUN_BSIZE, + adv_map, &overrun_physbase, + /*flags*/0); + } + + adv->overrun_physbase = overrun_physbase; if (adv_init(adv) != 0) { adv_free(adv); return (0); } + switch (adv->type) { case ADV_ISAPNP: - if (adv->chip_version == ADV_CHIP_VER_ASYN_BUG) - adv->needs_async_bug_fix = TARGET_BIT_VECTOR_SET; + if (adv->chip_version == ADV_CHIP_VER_ASYN_BUG){ + adv->bug_fix_control + |= ADV_BUG_FIX_ASYN_USE_SYN; + adv->fix_asyn_xfer = ~0; + } /* Fall Through */ case ADV_ISA: adv->max_dma_count = ADV_ISA_MAX_DMA_COUNT; + adv->max_dma_addr = ADV_ISA_MAX_DMA_ADDR; + adv_set_isa_dma_settings(adv); break; case ADV_VL: adv->max_dma_count = ADV_VL_MAX_DMA_COUNT; + adv->max_dma_addr = ADV_VL_MAX_DMA_ADDR; break; + default: + panic("advisaprobe: Invalid card type\n"); } - if ((adv->type & ADV_ISAPNP) == ADV_ISAPNP) { - } - /* Determine our IRQ */ if (id->id_irq == 0 /* irq ? */) id->id_irq = 1 << adv_get_chip_irq(adv); else adv_set_chip_irq(adv, ffs(id->id_irq) - 1); + id->id_intr = adv_isa_intr; /* Mark as probed */ adv_isa_ioports[port_index] = 0; - break; + return 1; } } - return 1; + return 0; } static int -advisaattach(id) - struct isa_device *id; +advisaattach(struct isa_device *id) { struct adv_softc *adv; @@ -189,6 +315,44 @@ advisaattach(id) return (adv_attach(adv)); } +static int +adv_get_isa_dma_channel(struct adv_softc *adv) +{ + int channel; + + channel = ADV_INW(adv, ADV_CONFIG_LSW) & ADV_CFG_LSW_ISA_DMA_CHANNEL; + if (channel == 0x03) + return (0); + else if (channel == 0x00) + return (7); + return (channel + 4); +} + +static int +adv_set_isa_dma_settings(struct adv_softc *adv) +{ + u_int16_t cfg_lsw; + u_int8_t value; + + if ((adv->isa_dma_channel >= 5) && (adv->isa_dma_channel <= 7)) { + if (adv->isa_dma_channel == 7) + value = 0x00; + else + value = adv->isa_dma_channel - 4; + cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW) + & ~ADV_CFG_LSW_ISA_DMA_CHANNEL; + cfg_lsw |= value; + ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw); + + adv->isa_dma_speed &= 0x07; + adv_set_bank(adv, 1); + ADV_OUTB(adv, ADV_DMA_SPEED, adv->isa_dma_speed); + adv_set_bank(adv, 0); + isa_dmacascade(adv->isa_dma_channel); + } + return (0); +} + static void adv_set_isapnp_wait_for_key(void) { @@ -202,35 +366,13 @@ adv_set_isapnp_wait_for_key(void) } /* - * Determine if there is a board at "iobase" by looking - * for the AdvanSys signatures. Return 1 if a board is - * found, 0 otherwise. - */ -static int -adv_find_signature(iobase) - u_int16_t iobase; -{ - u_int16_t signature; - - if (inb(iobase + ADV_SIGNATURE_BYTE) == ADV_1000_ID1B) { - signature = inw(iobase + ADV_SIGNATURE_WORD ); - if ((signature == ADV_1000_ID0W) - || (signature == ADV_1000_ID0W_FIX)) - return (1); - } - return (0); -} - - -/* * Handle an ISA interrupt. * XXX should go away as soon as ISA interrupt handlers * take a (void *) arg. */ void -adv_isa_intr(unit) - int unit; +adv_isa_intr(void *unit) { - struct adv_softc *arg = advsoftcs[unit]; + struct adv_softc *arg = advsoftcs[(int)unit]; adv_intr((void *)arg); } -- cgit v1.1