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