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