Home | History | Annotate | Line # | Download | only in isa
ahc_isa.c revision 1.7
      1 /*	$NetBSD: ahc_isa.c,v 1.7 1997/10/04 17:30:15 thorpej Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
      9  * NASA Ames Research Center.
     10  *
     11  * Redistribution and use in source and binary forms, with or without
     12  * modification, are permitted provided that the following conditions
     13  * are met:
     14  * 1. Redistributions of source code must retain the above copyright
     15  *    notice, this list of conditions and the following disclaimer.
     16  * 2. Redistributions in binary form must reproduce the above copyright
     17  *    notice, this list of conditions and the following disclaimer in the
     18  *    documentation and/or other materials provided with the distribution.
     19  * 3. All advertising materials mentioning features or use of this software
     20  *    must display the following acknowledgement:
     21  *	This product includes software developed by the NetBSD
     22  *	Foundation, Inc. and its contributors.
     23  * 4. Neither the name of The NetBSD Foundation nor the names of its
     24  *    contributors may be used to endorse or promote products derived
     25  *    from this software without specific prior written permission.
     26  *
     27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     37  * POSSIBILITY OF SUCH DAMAGE.
     38  */
     39 
     40 /*
     41  * Product specific probe and attach routines for:
     42  * 	284X VLbus SCSI controllers
     43  *
     44  * Copyright (c) 1995, 1996 Christopher G. Demetriou.
     45  * All rights reserved.
     46  *
     47  * Copyright (c) 1994, 1995, 1996 Justin T. Gibbs.
     48  * All rights reserved.
     49  *
     50  * Redistribution and use in source and binary forms, with or without
     51  * modification, are permitted provided that the following conditions
     52  * are met:
     53  * 1. Redistributions of source code must retain the above copyright
     54  *    notice immediately at the beginning of the file, without modification,
     55  *    this list of conditions, and the following disclaimer.
     56  * 2. Redistributions in binary form must reproduce the above copyright
     57  *    notice, this list of conditions and the following disclaimer in the
     58  *    documentation and/or other materials provided with the distribution.
     59  * 3. All advertising materials mentioning features or use of this software
     60  *    must display the following acknowledgement:
     61  *	This product includes software developed by Christopher G. Demetriou
     62  *	for the NetBSD Project.
     63  * 4. The name of the author may not be used to endorse or promote products
     64  *    derived from this software without specific prior written permission.
     65  *
     66  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     67  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     68  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     69  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
     70  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     71  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     72  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     73  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     74  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     75  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     76  * SUCH DAMAGE.
     77  */
     78 
     79 /*
     80  * This front-end driver is really sort of a hack.  The AHA-284X likes
     81  * to masquerade as an EISA device.  However, on VLbus machines with
     82  * no EISA signature in the BIOS, the EISA bus will never be scanned.
     83  * This is intended to catch the 284X controllers on those systems
     84  * by looking in "EISA i/o space" for 284X controllers.
     85  *
     86  * This relies heavily on i/o port accounting.  We also just use the
     87  * EISA macros for everything ... it's a real waste to redefine them.
     88  *
     89  * Note: there isn't any #ifdef for FreeBSD in this file, since the
     90  * FreeBSD EISA driver handles all cases of the 284X.
     91  *
     92  *	-- Jason R. Thorpe <thorpej (at) NetBSD.ORG>
     93  *	   July 12, 1996
     94  *
     95  * TODO: some code could be shared with ahc_eisa.c, but it would probably
     96  * be a logistical mightmare to even try.
     97  */
     98 
     99 #include <sys/param.h>
    100 #include <sys/systm.h>
    101 #include <sys/kernel.h>
    102 #include <sys/device.h>
    103 #include <sys/queue.h>
    104 #include <sys/malloc.h>
    105 
    106 #include <machine/bus.h>
    107 #include <machine/intr.h>
    108 
    109 #include <dev/scsipi/scsi_all.h>
    110 #include <dev/scsipi/scsipi_all.h>
    111 #include <dev/scsipi/scsiconf.h>
    112 
    113 #include <dev/isa/isavar.h>
    114 
    115 #include <dev/eisa/eisareg.h>
    116 #include <dev/eisa/eisavar.h>
    117 #include <dev/eisa/eisadevs.h>
    118 
    119 #include <dev/ic/aic7xxxreg.h>
    120 #include <dev/ic/aic7xxxvar.h>
    121 
    122 /* IO port address setting range as EISA slot number */
    123 #define AHC_ISA_MIN_SLOT	0x1	/* from iobase = 0x1c00 */
    124 #define AHC_ISA_MAX_SLOT	0xe	/* to   iobase = 0xec00 */
    125 
    126 #define AHC_ISA_SLOT_OFFSET	0xc00	/* offset from EISA IO space */
    127 #define AHC_ISA_IOSIZE		0x100
    128 
    129 /*
    130  * I/O port offsets
    131  */
    132 #define INTDEF			0x5cul	/* Interrupt Definition Register */
    133 #define	AHC_ISA_VID		(EISA_SLOTOFF_VID - AHC_ISA_SLOT_OFFSET)
    134 #define	AHC_ISA_PID		(EISA_SLOTOFF_PID - AHC_ISA_SLOT_OFFSET)
    135 #define	AHC_ISA_PRIMING		AHC_ISA_VID	/* enable vendor/product ID */
    136 
    137 /*
    138  * AHC_ISA_PRIMING register values (write)
    139  */
    140 #define	AHC_ISA_PRIMING_VID(index)	(AHC_ISA_VID + (index))
    141 #define	AHC_ISA_PRIMING_PID(index)	(AHC_ISA_PID + (index))
    142 
    143 int	ahc_isa_irq __P((bus_space_tag_t, bus_space_handle_t));
    144 int	ahc_isa_idstring __P((bus_space_tag_t, bus_space_handle_t, char *));
    145 int	ahc_isa_match __P((struct isa_attach_args *, bus_addr_t));
    146 
    147 int	ahc_isa_probe __P((struct device *, void *, void *));
    148 void	ahc_isa_attach __P((struct device *, struct device *, void *));
    149 
    150 struct cfattach ahc_isa_ca = {
    151 	sizeof(struct ahc_data), ahc_isa_probe, ahc_isa_attach
    152 };
    153 
    154 /*
    155  * This keeps track of which slots are to be checked next if the
    156  * iobase locator is a wildcard.  A simple static variable isn't enough,
    157  * since it's conceivable that a system might have more than one ISA
    158  * bus.
    159  *
    160  * The "bus" member is the unit number of the parent ISA bus, e.g. "0"
    161  * for "isa0".
    162  */
    163 struct ahc_isa_slot {
    164 	LIST_ENTRY(ahc_isa_slot)	link;
    165 	int				bus;
    166 	int				slot;
    167 };
    168 static LIST_HEAD(, ahc_isa_slot) ahc_isa_all_slots;
    169 static int ahc_isa_slot_initialized;
    170 
    171 /*
    172  * Return irq setting of the board, otherwise -1.
    173  */
    174 int
    175 ahc_isa_irq(iot, ioh)
    176 	bus_space_tag_t iot;
    177 	bus_space_handle_t ioh;
    178 {
    179 	int irq;
    180 	u_char intdef;
    181 
    182 	ahc_reset("ahc_isa", iot, ioh);
    183 	intdef = bus_space_read_1(iot, ioh, INTDEF);
    184 	switch (irq = (intdef & 0xf)) {
    185 	case 9:
    186 	case 10:
    187 	case 11:
    188 	case 12:
    189 	case 14:
    190 	case 15:
    191 		break;
    192 	default:
    193 		printf("ahc_isa_irq: illegal irq setting %d\n", intdef);
    194 		return -1;
    195 	}
    196 
    197 	/* Note that we are going and return (to probe) */
    198 	return irq;
    199 }
    200 
    201 int
    202 ahc_isa_idstring(iot, ioh, idstring)
    203 	bus_space_tag_t iot;
    204 	bus_space_handle_t ioh;
    205 	char *idstring;
    206 {
    207 	u_int8_t vid[EISA_NVIDREGS], pid[EISA_NPIDREGS];
    208 	int i;
    209 
    210 	/* Get the vendor ID bytes */
    211 	for (i = 0; i < EISA_NVIDREGS; i++) {
    212 		bus_space_write_1(iot, ioh, AHC_ISA_PRIMING,
    213 		    AHC_ISA_PRIMING_VID(i));
    214 		vid[i] = bus_space_read_1(iot, ioh, AHC_ISA_VID + i);
    215 	}
    216 
    217 	/* Check for device existence */
    218 	if (EISA_VENDID_NODEV(vid)) {
    219 #if 0
    220 		printf("ahc_isa_idstring: no device at 0x%lx\n",
    221 		    ioh); /* XXX knows about ioh guts */
    222 		printf("\t(0x%x, 0x%x)\n", vid[0], vid[1]);
    223 #endif
    224 		return (0);
    225 	}
    226 
    227 	/* And check that the firmware didn't biff something badly */
    228 	if (EISA_VENDID_IDDELAY(vid)) {
    229 		printf("ahc_isa_idstring: BIOS biffed it at 0x%lx\n",
    230 		    ioh);	/* XXX knows about ioh guts */
    231 		return (0);
    232 	}
    233 
    234 	/* Get the product ID bytes */
    235 	for (i = 0; i < EISA_NPIDREGS; i++) {
    236 		bus_space_write_1(iot, ioh, AHC_ISA_PRIMING,
    237 		    AHC_ISA_PRIMING_PID(i));
    238 		pid[i] = bus_space_read_1(iot, ioh, AHC_ISA_PID + i);
    239 	}
    240 
    241 	/* Create the ID string from the vendor and product IDs */
    242 	idstring[0] = EISA_VENDID_0(vid);
    243 	idstring[1] = EISA_VENDID_1(vid);
    244 	idstring[2] = EISA_VENDID_2(vid);
    245 	idstring[3] = EISA_PRODID_0(pid);
    246 	idstring[4] = EISA_PRODID_1(pid);
    247 	idstring[5] = EISA_PRODID_2(pid);
    248 	idstring[6] = EISA_PRODID_3(pid);
    249 	idstring[7] = '\0';		/* sanity */
    250 
    251 	return (1);
    252 }
    253 
    254 int
    255 ahc_isa_match(ia, iobase)
    256 	struct isa_attach_args *ia;
    257 	bus_addr_t iobase;
    258 {
    259 	bus_space_tag_t iot = ia->ia_iot;
    260 	bus_space_handle_t ioh;
    261 	int irq;
    262 	char idstring[EISA_IDSTRINGLEN];
    263 
    264 	/*
    265 	 * Get a mapping for the while slot-specific address
    266 	 * space.  If we can't, assume nothing's there, but
    267 	 * warn about it.
    268 	 */
    269 	if (bus_space_map(iot, iobase, AHC_ISA_IOSIZE, 0, &ioh)) {
    270 #if 0
    271 		/*
    272 		 * Don't print anything out here, since this could
    273 		 * be common on machines configured to look for
    274 		 * ahc_eisa and ahc_isa.
    275 		 */
    276 		printf("ahc_isa_match: can't map I/O space for 0x%x\n",
    277 		    iobase);
    278 #endif
    279 		return (0);
    280 	}
    281 
    282 	if (!ahc_isa_idstring(iot, ioh, idstring))
    283 		irq = -1;	/* cannot get the ID string */
    284 	else if (strcmp(idstring, "ADP7756") &&
    285 	    strcmp(idstring, "ADP7757"))
    286 		irq = -1;	/* unknown ID strings */
    287 	else
    288 		irq = ahc_isa_irq(iot, ioh);
    289 
    290 	bus_space_unmap(iot, ioh, AHC_ISA_IOSIZE);
    291 
    292 	if (irq < 0)
    293 		return (0);
    294 
    295 	if (ia->ia_irq != IRQUNK &&
    296 	    ia->ia_irq != irq) {
    297 		printf("ahc_isa_match: irq mismatch (kernel %d, card %d)\n",
    298 		    ia->ia_irq, irq);
    299 		return (0);
    300 	}
    301 
    302 	/* We have a match */
    303 	ia->ia_iobase = iobase;
    304 	ia->ia_irq = irq;
    305 	ia->ia_iosize = AHC_ISA_IOSIZE;
    306 	ia->ia_msize = 0;
    307 	return (1);
    308 }
    309 
    310 /*
    311  * Check the slots looking for a board we recognise
    312  * If we find one, note it's address (slot) and call
    313  * the actual probe routine to check it out.
    314  */
    315 int
    316 ahc_isa_probe(parent, match, aux)
    317         struct device *parent;
    318         void *match, *aux;
    319 {
    320 	struct isa_attach_args *ia = aux;
    321 	struct ahc_isa_slot *as;
    322 
    323 	if (ahc_isa_slot_initialized == 0) {
    324 		LIST_INIT(&ahc_isa_all_slots);
    325 		ahc_isa_slot_initialized = 1;
    326 	}
    327 
    328 	if (ia->ia_iobase != IOBASEUNK)
    329 		return (ahc_isa_match(ia, ia->ia_iobase));
    330 
    331 	/*
    332 	 * Find this bus's state.  If we don't yet have a slot
    333 	 * marker, allocate and initialize one.
    334 	 */
    335 	for (as = ahc_isa_all_slots.lh_first; as != NULL;
    336 	    as = as->link.le_next)
    337 		if (as->bus == parent->dv_unit)
    338 			goto found_slot_marker;
    339 
    340 	/*
    341 	 * Don't have one, so make one.
    342 	 */
    343 	as = (struct ahc_isa_slot *)
    344 	    malloc(sizeof(struct ahc_isa_slot), M_DEVBUF, M_NOWAIT);
    345 	if (as == NULL)
    346 		panic("ahc_isa_probe: can't allocate slot marker");
    347 
    348 	as->bus = parent->dv_unit;
    349 	as->slot = AHC_ISA_MIN_SLOT;
    350 	LIST_INSERT_HEAD(&ahc_isa_all_slots, as, link);
    351 
    352  found_slot_marker:
    353 
    354 	for (; as->slot <= AHC_ISA_MAX_SLOT; as->slot++) {
    355 		if (ahc_isa_match(ia, EISA_SLOT_ADDR(as->slot) +
    356 		    AHC_ISA_SLOT_OFFSET)) {
    357 			as->slot++; /* next slot to search */
    358 			return (1);
    359 		}
    360 	}
    361 
    362 	/* No matching cards were found. */
    363 	return (0);
    364 }
    365 
    366 void
    367 ahc_isa_attach(parent, self, aux)
    368 	struct device *parent, *self;
    369 	void *aux;
    370 {
    371 	ahc_type type;
    372 	struct ahc_data *ahc = (void *)self;
    373 	struct isa_attach_args *ia = aux;
    374 	bus_space_tag_t iot = ia->ia_iot;
    375 	bus_space_handle_t ioh;
    376 	int irq;
    377 	char idstring[EISA_IDSTRINGLEN];
    378 	const char *model;
    379 
    380 	if (bus_space_map(iot, ia->ia_iobase, ia->ia_iosize, 0, &ioh))
    381 		panic("ahc_isa_attach: could not map slot I/O addresses");
    382 	if (!ahc_isa_idstring(iot, ioh, idstring))
    383 		panic("ahc_isa_attach: could not read ID string");
    384 	if ((irq = ahc_isa_irq(iot, ioh)) < 0)
    385 		panic("ahc_isa_attach: ahc_isa_irq failed!");
    386 
    387 	if (strcmp(idstring, "ADP7756") == 0) {
    388 		model = EISA_PRODUCT_ADP7756;
    389 		type = AHC_284;
    390 	} else if (strcmp(idstring, "ADP7757") == 0) {
    391 		model = EISA_PRODUCT_ADP7757;
    392 		type = AHC_284;
    393 	} else {
    394 		panic("ahc_isa_attach: Unknown device type %s\n", idstring);
    395 	}
    396 	printf(": %s\n", model);
    397 
    398 	ahc_construct(ahc, iot, ioh, type, AHC_FNONE);
    399 
    400 #ifdef DEBUG
    401 	/*
    402 	 * Tell the user what type of interrupts we're using.
    403 	 * usefull for debugging irq problems
    404 	 */
    405 	printf( "%s: Using %s Interrupts\n", ahc_name(ahc),
    406 	    ahc->pause & IRQMS ?  "Level Sensitive" : "Edge Triggered");
    407 #endif
    408 
    409 	/*
    410 	 * Now that we know we own the resources we need, do the
    411 	 * card initialization.
    412 	 *
    413 	 * First, the aic7770 card specific setup.
    414 	 */
    415 
    416 	/* XXX
    417 	 * On AHA-284x,
    418 	 * all values are automagically intialized at
    419 	 * POST for these cards, so we can always rely
    420 	 * on the Scratch Ram values.  However, we should
    421 	 * read the SEEPROM here (Dan has the code to do
    422 	 * it) so we can say what kind of translation the
    423 	 * BIOS is using.  Printing out the geometry could
    424 	 * save a lot of users the grief of failed installs.
    425 	 */
    426 
    427 	/*
    428 	 * See if we have a Rev E or higher aic7770. Anything below a
    429 	 * Rev E will have a R/O autoflush disable configuration bit.
    430 	 * It's still not clear exactly what is differenent about the Rev E.
    431 	 * We think it allows 8 bit entries in the QOUTFIFO to support
    432 	 * "paging" SCBs so you can have more than 4 commands active at
    433 	 * once.
    434 	 */
    435 	{
    436 		char *id_string;
    437 		u_char sblkctl;
    438 		u_char sblkctl_orig;
    439 
    440 		sblkctl_orig = AHC_INB(ahc, SBLKCTL);
    441 		sblkctl = sblkctl_orig ^ AUTOFLUSHDIS;
    442 		AHC_OUTB(ahc, SBLKCTL, sblkctl);
    443 		sblkctl = AHC_INB(ahc, SBLKCTL);
    444 		if(sblkctl != sblkctl_orig)
    445 		{
    446 			id_string = "aic7770 >= Rev E, ";
    447 			/*
    448 			 * Ensure autoflush is enabled
    449 			 */
    450 			sblkctl &= ~AUTOFLUSHDIS;
    451 			AHC_OUTB(ahc, SBLKCTL, sblkctl);
    452 
    453 			/* Allow paging on this adapter */
    454 			ahc->flags |= AHC_PAGESCBS;
    455 		}
    456 		else
    457 			id_string = "aic7770 <= Rev C, ";
    458 
    459 		printf("%s: %s", ahc_name(ahc), id_string);
    460 	}
    461 
    462 	/* Setup the FIFO threshold and the bus off time */
    463 	{
    464 		u_char hostconf = AHC_INB(ahc, HOSTCONF);
    465 		AHC_OUTB(ahc, BUSSPD, hostconf & DFTHRSH);
    466 		AHC_OUTB(ahc, BUSTIME, (hostconf << 2) & BOFF);
    467 	}
    468 
    469 	/*
    470 	 * Generic aic7xxx initialization.
    471 	 */
    472 	if(ahc_init(ahc)){
    473 		ahc_free(ahc);
    474 		return;
    475 	}
    476 
    477 	/*
    478 	 * Enable the board's BUS drivers
    479 	 */
    480 	AHC_OUTB(ahc, BCTL, ENABLE);
    481 
    482 	/*
    483 	 * The IRQMS bit enables level sensitive interrupts only allow
    484 	 * IRQ sharing if its set.
    485 	 */
    486 	ahc->sc_ih = isa_intr_establish(ia->ia_ic, irq,
    487 	    ahc->pause & IRQMS ? IST_LEVEL : IST_EDGE, IPL_BIO, ahc_intr, ahc);
    488 	if (ahc->sc_ih == NULL) {
    489 		printf("%s: couldn't establish interrupt\n",
    490 		       ahc->sc_dev.dv_xname);
    491 		ahc_free(ahc);
    492 		return;
    493 	}
    494 
    495 	/* Attach sub-devices - always succeeds */
    496 	ahc_attach(ahc);
    497 }
    498