xref: /openbsd/sys/arch/i386/isa/ahc_isa.c (revision 4bdff4be)
1 /*	$OpenBSD: ahc_isa.c,v 1.21 2022/02/21 12:53:39 jsg Exp $	*/
2 /*	$NetBSD: ahc_isa.c,v 1.5 1996/10/21 22:27:39 thorpej Exp $	*/
3 
4 /*
5  * Product specific probe and attach routines for:
6  * 	284X VLbus SCSI controllers
7  *
8  * Copyright (c) 1996 Jason R. Thorpe.
9  * All rights reserved.
10  *
11  * Copyright (c) 1995, 1996 Christopher G. Demetriou.
12  * All rights reserved.
13  *
14  * Copyright (c) 1994, 1995, 1996 Justin T. Gibbs.
15  * All rights reserved.
16  *
17  * Redistribution and use in source and binary forms, with or without
18  * modification, are permitted provided that the following conditions
19  * are met:
20  * 1. Redistributions of source code must retain the above copyright
21  *    notice immediately at the beginning of the file, without modification,
22  *    this list of conditions, and the following disclaimer.
23  * 2. Redistributions in binary form must reproduce the above copyright
24  *    notice, this list of conditions and the following disclaimer in the
25  *    documentation and/or other materials provided with the distribution.
26  * 3. All advertising materials mentioning features or use of this software
27  *    must display the following acknowledgement:
28  *	This product includes software developed by Christopher G. Demetriou
29  *	for the NetBSD Project.
30  * 4. The name of the author may not be used to endorse or promote products
31  *    derived from this software without specific prior written permission.
32  *
33  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
34  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
37  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
38  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
39  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
41  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
42  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43  * SUCH DAMAGE.
44  */
45 
46 /*
47  * This front-end driver is really sort of a hack.  The AHA-284X likes
48  * to masquerade as an EISA device.  However, on VLbus machines with
49  * no EISA signature in the BIOS, the EISA bus will never be scanned.
50  * This is intended to catch the 284X controllers on those systems
51  * by looking in "EISA i/o space" for 284X controllers.
52  *
53  * This relies heavily on i/o port accounting.  We also just use the
54  * EISA macros for everything ... it's a real waste to redefine them.
55  *
56  * Note: there isn't any #ifdef for FreeBSD in this file, since the
57  * FreeBSD EISA driver handles all cases of the 284X.
58  *
59  *	-- Jason R. Thorpe <thorpej@NetBSD.ORG>
60  *	   July 12, 1996
61  *
62  * TODO: some code could be shared with ahc_eisa.c, but it would probably
63  * be a logistical mightmare to even try.
64  */
65 
66 #include <sys/param.h>
67 #include <sys/systm.h>
68 #include <sys/kernel.h>
69 #include <sys/device.h>
70 #include <sys/queue.h>
71 #include <sys/malloc.h>
72 
73 #include <machine/bus.h>
74 #include <machine/intr.h>
75 
76 #include <scsi/scsi_all.h>
77 #include <scsi/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/aic7xxx_openbsd.h>
86 #include <dev/ic/aic7xxx_inline.h>
87 #include <dev/ic/smc93cx6var.h>
88 
89 #ifdef DEBUG
90 #define bootverbose	1
91 #else
92 #define bootverbose	0
93 #endif
94 
95 /* IO port address setting range as EISA slot number */
96 #define AHC_ISA_MIN_SLOT	0x1	/* from iobase = 0x1c00 */
97 #define AHC_ISA_MAX_SLOT	0xe	/* to   iobase = 0xec00 */
98 
99 #define AHC_ISA_SLOT_OFFSET	0xc00	/* offset from EISA IO space */
100 #define AHC_ISA_IOSIZE		0x100
101 
102 /*
103  * I/O port offsets
104  */
105 #define	AHC_ISA_VID		(EISA_SLOTOFF_VID - AHC_ISA_SLOT_OFFSET)
106 #define	AHC_ISA_PID		(EISA_SLOTOFF_PID - AHC_ISA_SLOT_OFFSET)
107 #define	AHC_ISA_PRIMING		AHC_ISA_VID	/* enable vendor/product ID */
108 
109 /*
110  * AHC_ISA_PRIMING register values (write)
111  */
112 #define	AHC_ISA_PRIMING_VID(index)	(AHC_ISA_VID + (index))
113 #define	AHC_ISA_PRIMING_PID(index)	(AHC_ISA_PID + (index))
114 
115 int	ahc_isa_irq(bus_space_tag_t, bus_space_handle_t);
116 int	ahc_isa_idstring(bus_space_tag_t, bus_space_handle_t, char *);
117 int	ahc_isa_match(struct isa_attach_args *, bus_addr_t);
118 
119 int	ahc_isa_probe(struct device *, void *, void *);
120 void	ahc_isa_attach(struct device *, struct device *, void *);
121 void	aha2840_load_seeprom(struct ahc_softc *ahc);
122 
123 const struct cfattach ahc_isa_ca = {
124 	sizeof(struct ahc_softc), ahc_isa_probe, ahc_isa_attach
125 };
126 
127 /*
128  * This keeps track of which slots are to be checked next if the
129  * iobase locator is a wildcard.  A simple static variable isn't enough,
130  * since it's conceivable that a system might have more than one ISA
131  * bus.
132  *
133  * The "bus" member is the unit number of the parent ISA bus, e.g. "0"
134  * for "isa0".
135  */
136 struct ahc_isa_slot {
137 	LIST_ENTRY(ahc_isa_slot)	link;
138 	int				bus;
139 	int				slot;
140 };
141 static LIST_HEAD(, ahc_isa_slot) ahc_isa_all_slots;
142 static int ahc_isa_slot_initialized;
143 
144 /*
145  * Return irq setting of the board, otherwise -1.
146  */
147 int
148 ahc_isa_irq(bus_space_tag_t iot, bus_space_handle_t ioh)
149 {
150 	int irq;
151 	u_char intdef;
152 	u_char hcntrl;
153 
154 	/* Pause the card preserving the IRQ type */
155 	hcntrl = bus_space_read_1(iot, ioh, HCNTRL) & IRQMS;
156 	bus_space_write_1(iot, ioh, HCNTRL, hcntrl | PAUSE);
157 
158 	intdef = bus_space_read_1(iot, ioh, INTDEF);
159 	switch (irq = (intdef & VECTOR)) {
160 	case 9:
161 	case 10:
162 	case 11:
163 	case 12:
164 	case 14:
165 	case 15:
166 		break;
167 	default:
168 		printf("ahc_isa_irq: illegal irq setting %d\n", intdef);
169 		return -1;
170 	}
171 
172 	/* Note that we are going and return (to probe) */
173 	return irq;
174 }
175 
176 int
177 ahc_isa_idstring(bus_space_tag_t iot, bus_space_handle_t ioh, char *idstring)
178 {
179 	u_int8_t vid[EISA_NVIDREGS], pid[EISA_NPIDREGS];
180 	int i;
181 
182 	/* Get the vendor ID bytes */
183 	for (i = 0; i < EISA_NVIDREGS; i++) {
184 		bus_space_write_1(iot, ioh, AHC_ISA_PRIMING,
185 		    AHC_ISA_PRIMING_VID(i));
186 		vid[i] = bus_space_read_1(iot, ioh, AHC_ISA_VID + i);
187 	}
188 
189 	/* Check for device existence */
190 	if (EISA_VENDID_NODEV(vid)) {
191 #if 0
192 		printf("ahc_isa_idstring: no device at 0x%lx\n",
193 		    ioh); /* XXX knows about ioh guts */
194 		printf("\t(0x%x, 0x%x)\n", vid[0], vid[1]);
195 #endif
196 		return (0);
197 	}
198 
199 	/* And check that the firmware didn't biff something badly */
200 	if (EISA_VENDID_IDDELAY(vid)) {
201 		printf("ahc_isa_idstring: BIOS biffed it at 0x%lx\n",
202 		    ioh);	/* XXX knows about ioh guts */
203 		return (0);
204 	}
205 
206 	/* Get the product ID bytes */
207 	for (i = 0; i < EISA_NPIDREGS; i++) {
208 		bus_space_write_1(iot, ioh, AHC_ISA_PRIMING,
209 		    AHC_ISA_PRIMING_PID(i));
210 		pid[i] = bus_space_read_1(iot, ioh, AHC_ISA_PID + i);
211 	}
212 
213 	/* Create the ID string from the vendor and product IDs */
214 	idstring[0] = EISA_VENDID_0(vid);
215 	idstring[1] = EISA_VENDID_1(vid);
216 	idstring[2] = EISA_VENDID_2(vid);
217 	idstring[3] = EISA_PRODID_0(pid);
218 	idstring[4] = EISA_PRODID_1(pid);
219 	idstring[5] = EISA_PRODID_2(pid);
220 	idstring[6] = EISA_PRODID_3(pid);
221 	idstring[7] = '\0';		/* sanity */
222 
223 	return (1);
224 }
225 
226 int
227 ahc_isa_match(struct isa_attach_args *ia, bus_addr_t iobase)
228 {
229 	bus_space_tag_t iot = ia->ia_iot;
230 	bus_space_handle_t ioh;
231 	int irq;
232 	char idstring[EISA_IDSTRINGLEN];
233 
234 	/*
235 	 * Get a mapping for the while slot-specific address
236 	 * space.  If we can't, assume nothing's there, but
237 	 * warn about it.
238 	 */
239 	if (bus_space_map(iot, iobase, AHC_ISA_IOSIZE, 0, &ioh)) {
240 #if 0
241 		/*
242 		 * Don't print anything out here, since this could
243 		 * be common on machines configured to look for
244 		 * ahc_eisa and ahc_isa.
245 		 */
246 		printf("ahc_isa_match: can't map i/o space for 0x%x\n",
247 		    iobase);
248 #endif
249 		return (0);
250 	}
251 
252 	if (!ahc_isa_idstring(iot, ioh, idstring))
253 		irq = -1;	/* cannot get the ID string */
254 	else if (strcmp(idstring, "ADP7756") &&
255 	    strcmp(idstring, "ADP7757"))
256 		irq = -1;	/* unknown ID strings */
257 	else
258 		irq = ahc_isa_irq(iot, ioh);
259 
260 	bus_space_unmap(iot, ioh, AHC_ISA_IOSIZE);
261 
262 	if (irq < 0)
263 		return (0);
264 
265 	if (ia->ia_irq != IRQUNK &&
266 	    ia->ia_irq != irq) {
267 		printf("ahc_isa_match: irq mismatch (kernel %d, card %d)\n",
268 		       ia->ia_irq, irq);
269 		return (0);
270 	}
271 
272 	/* We have a match */
273 	ia->ia_iobase = iobase;
274 	ia->ia_irq = irq;
275 	ia->ia_iosize = AHC_ISA_IOSIZE;
276 	ia->ia_msize = 0;
277 	return (1);
278 }
279 
280 /*
281  * Check the slots looking for a board we recognise
282  * If we find one, note its address (slot) and call
283  * the actual probe routine to check it out.
284  */
285 int
286 ahc_isa_probe(struct device *parent, void *match, void *aux)
287 {
288 	struct isa_attach_args *ia = aux;
289 	struct ahc_isa_slot *as;
290 
291 	if (ahc_isa_slot_initialized == 0) {
292 		LIST_INIT(&ahc_isa_all_slots);
293 		ahc_isa_slot_initialized = 1;
294 	}
295 
296 	if (ia->ia_iobase != IOBASEUNK)
297 		return (ahc_isa_match(ia, ia->ia_iobase));
298 
299 	/*
300 	 * Find this bus's state.  If we don't yet have a slot
301 	 * marker, allocate and initialize one.
302 	 */
303 	LIST_FOREACH(as, &ahc_isa_all_slots, link)
304 		if (as->bus == parent->dv_unit)
305 			goto found_slot_marker;
306 
307 	/*
308 	 * Don't have one, so make one.
309 	 */
310 	as = (struct ahc_isa_slot *)
311 	    malloc(sizeof(struct ahc_isa_slot), M_DEVBUF, M_NOWAIT);
312 	if (as == NULL)
313 		panic("ahc_isa_probe: can't allocate slot marker");
314 
315 	as->bus = parent->dv_unit;
316 	as->slot = AHC_ISA_MIN_SLOT;
317 	LIST_INSERT_HEAD(&ahc_isa_all_slots, as, link);
318 
319  found_slot_marker:
320 
321 	for (; as->slot <= AHC_ISA_MAX_SLOT; as->slot++) {
322 		if (ahc_isa_match(ia, EISA_SLOT_ADDR(as->slot) +
323 		    AHC_ISA_SLOT_OFFSET)) {
324 			as->slot++; /* next slot to search */
325 			return (1);
326 		}
327 	}
328 
329 	/* No matching cards were found. */
330 	return (0);
331 }
332 
333 void
334 ahc_isa_attach(struct device *parent, struct device *self, void *aux)
335 {
336 	struct ahc_softc *ahc = (void *)self;
337 	struct isa_attach_args *ia = aux;
338 	bus_space_tag_t iot = ia->ia_iot;
339 	bus_space_handle_t ioh;
340 	int irq;
341 	char idstring[EISA_IDSTRINGLEN];
342 	const char *model;
343 	u_int intdef;
344 
345 	ahc_set_name(ahc, ahc->sc_dev.dv_xname);
346 	ahc_set_unit(ahc, ahc->sc_dev.dv_unit);
347 
348 	/* set dma tags */
349 	ahc->parent_dmat = ia->ia_dmat;
350 
351 	ahc->chip = AHC_VL; /* We are a VL Bus Controller */
352 
353 	if (bus_space_map(iot, ia->ia_iobase, ia->ia_iosize, 0, &ioh))
354 		panic("ahc_isa_attach: can't map slot i/o addresses");
355 	if (!ahc_isa_idstring(iot, ioh, idstring))
356 		panic("ahc_isa_attach: could not read ID string");
357 	if ((irq = ahc_isa_irq(iot, ioh)) < 0)
358 		panic("ahc_isa_attach: ahc_isa_irq failed!");
359 
360 	if (strcmp(idstring, "ADP7756") == 0) {
361 		model = EISA_PRODUCT_ADP7756;
362 	} else if (strcmp(idstring, "ADP7757") == 0) {
363 		model = EISA_PRODUCT_ADP7757;
364 	} else {
365 		panic("ahc_isa_attach: Unknown device type %s", idstring);
366 	}
367 	printf(": %s\n", model);
368 
369 	ahc->channel = 'A';
370 	ahc->chip = AHC_AIC7770;
371 	ahc->features = AHC_AIC7770_FE;
372 	ahc->bugs |= AHC_TMODE_WIDEODD_BUG;
373 	ahc->flags |= AHC_PAGESCBS;
374 
375 	/* set tag and handle */
376 	ahc->tag = iot;
377 	ahc->bsh = ioh;
378 
379 #ifdef DEBUG
380 	/*
381 	 * Tell the user what type of interrupts we're using.
382 	 * useful for debugging irq problems
383 	 */
384 	printf( "%s: Using %s Interrupts\n", ahc_name(ahc),
385 	    ahc->pause & IRQMS ?  "Level Sensitive" : "Edge Triggered");
386 #endif
387 
388 	if (ahc_reset(ahc, /*reinit*/FALSE) != 0)
389 		return;
390 
391 	/* See if we are edge triggered */
392 	intdef = ahc_inb(ahc, INTDEF);
393 	if ((intdef & EDGE_TRIG) != 0)
394 		ahc->flags |= AHC_EDGE_INTERRUPT;
395 
396 	/*
397 	 * Now that we know we own the resources we need, do the
398 	 * card initialization.
399 	 */
400 	aha2840_load_seeprom(ahc);
401 
402 	/*
403 	 * See if we have a Rev E or higher aic7770. Anything below a
404 	 * Rev E will have a R/O autoflush disable configuration bit.
405 	 * It's still not clear exactly what is different about the Rev E.
406 	 * We think it allows 8 bit entries in the QOUTFIFO to support
407 	 * "paging" SCBs so you can have more than 4 commands active at
408 	 * once.
409 	 */
410 	{
411 		char *id_string;
412 		u_char sblkctl;
413 		u_char sblkctl_orig;
414 
415 		sblkctl_orig = ahc_inb(ahc, SBLKCTL);
416 		sblkctl = sblkctl_orig ^ AUTOFLUSHDIS;
417 		ahc_outb(ahc, SBLKCTL, sblkctl);
418 		sblkctl = ahc_inb(ahc, SBLKCTL);
419 		if(sblkctl != sblkctl_orig)
420 		{
421 			id_string = "aic7770 >= Rev E, ";
422 			/*
423 			 * Ensure autoflush is enabled
424 			 */
425 			sblkctl &= ~AUTOFLUSHDIS;
426 			ahc_outb(ahc, SBLKCTL, sblkctl);
427 
428 			/* Allow paging on this adapter */
429 			ahc->flags |= AHC_PAGESCBS;
430 		}
431 		else
432 			id_string = "aic7770 <= Rev C, ";
433 
434 		printf("%s: %s", ahc_name(ahc), id_string);
435 	}
436 
437 	/* Setup the FIFO threshold and the bus off time */
438 	{
439 		u_char hostconf = ahc_inb(ahc, HOSTCONF);
440 		ahc_outb(ahc, BUSSPD, hostconf & DFTHRSH);
441 		ahc_outb(ahc, BUSTIME, (hostconf << 2) & BOFF);
442 	}
443 
444 	/*
445 	 * Generic aic7xxx initialization.
446 	 */
447 	if(ahc_init(ahc)){
448 		ahc_free(ahc);
449 		return;
450 	}
451 
452 	/*
453 	 * Link this softc in with all other ahc instances.
454 	 */
455 	ahc_softc_insert(ahc);
456 
457 	/*
458 	 * Enable the board's BUS drivers
459 	 */
460 	ahc_outb(ahc, BCTL, ENABLE);
461 
462 	/*
463 	 * The IRQMS bit enables level sensitive interrupts only allow
464 	 * IRQ sharing if its set.
465 	 */
466 	ahc->ih = isa_intr_establish(ia->ia_ic, irq,
467 	    ahc->pause & IRQMS ? IST_LEVEL : IST_EDGE, IPL_BIO, ahc_platform_intr,
468 	    ahc, ahc->sc_dev.dv_xname);
469 	if (ahc->ih == NULL) {
470 		printf("%s: couldn't establish interrupt\n",
471 		       ahc->sc_dev.dv_xname);
472 		ahc_free(ahc);
473 		return;
474 	}
475 
476 	ahc_intr_enable(ahc, TRUE);
477 
478 	/* Attach sub-devices - always succeeds */
479 	ahc_attach(ahc);
480 }
481 
482 /*
483  * Read the 284x SEEPROM.
484  */
485 void
486 aha2840_load_seeprom(struct ahc_softc *ahc)
487 {
488 	struct	  seeprom_descriptor sd;
489 	struct	  seeprom_config sc;
490 	u_int16_t checksum = 0;
491 	u_int8_t  scsi_conf;
492 	int	  have_seeprom;
493 
494 	sd.sd_tag = ahc->tag;
495 	sd.sd_bsh = ahc->bsh;
496 	sd.sd_regsize = 1;
497 	sd.sd_control_offset = SEECTL_2840;
498 	sd.sd_status_offset = STATUS_2840;
499 	sd.sd_dataout_offset = STATUS_2840;
500 	sd.sd_chip = C46;
501 	sd.sd_MS = 0;
502 	sd.sd_RDY = EEPROM_TF;
503 	sd.sd_CS = CS_2840;
504 	sd.sd_CK = CK_2840;
505 	sd.sd_DO = DO_2840;
506 	sd.sd_DI = DI_2840;
507 
508 	if (bootverbose)
509 		printf("%s: Reading SEEPROM...", ahc_name(ahc));
510 	have_seeprom = read_seeprom(&sd,
511 				    (u_int16_t *)&sc,
512 				    /*start_addr*/0,
513 				    sizeof(sc)/2);
514 
515 	if (have_seeprom) {
516 		/* Check checksum */
517 		int i;
518 		int maxaddr = (sizeof(sc)/2) - 1;
519 		u_int16_t *scarray = (u_int16_t *)&sc;
520 
521 		for (i = 0; i < maxaddr; i++)
522 			checksum = checksum + scarray[i];
523 		if (checksum != sc.checksum) {
524 			if(bootverbose)
525 				printf ("checksum error\n");
526 			have_seeprom = 0;
527 		} else if (bootverbose) {
528 			printf("done.\n");
529 		}
530 	}
531 
532 	if (!have_seeprom) {
533 		if (bootverbose)
534 			printf("%s: No SEEPROM available\n", ahc_name(ahc));
535 		ahc->flags |= AHC_USEDEFAULTS;
536 	} else {
537 		/*
538 		 * Put the data we've collected down into SRAM
539 		 * where ahc_init will find it.
540 		 */
541 		int i;
542 		int max_targ = (ahc->features & AHC_WIDE) != 0 ? 16 : 8;
543 		u_int16_t discenable;
544 
545 		discenable = 0;
546 		for (i = 0; i < max_targ; i++){
547 	                u_int8_t target_settings;
548 			target_settings = (sc.device_flags[i] & CFXFER) << 4;
549 			if (sc.device_flags[i] & CFSYNCH)
550 				target_settings |= SOFS;
551 			if (sc.device_flags[i] & CFWIDEB)
552 				target_settings |= WIDEXFER;
553 			if (sc.device_flags[i] & CFDISC)
554 				discenable |= (0x01 << i);
555 			ahc_outb(ahc, TARG_SCSIRATE + i, target_settings);
556 		}
557 		ahc_outb(ahc, DISC_DSB, ~(discenable & 0xff));
558 		ahc_outb(ahc, DISC_DSB + 1, ~((discenable >> 8) & 0xff));
559 
560 		ahc->our_id = sc.brtime_id & CFSCSIID;
561 
562 		scsi_conf = (ahc->our_id & 0x7);
563 		if (sc.adapter_control & CFSPARITY)
564 			scsi_conf |= ENSPCHK;
565 		if (sc.adapter_control & CFRESETB)
566 			scsi_conf |= RESET_SCSI;
567 
568 		if (sc.bios_control & CF284XEXTEND)
569 			ahc->flags |= AHC_EXTENDED_TRANS_A;
570 		/* Set SCSICONF info */
571 		ahc_outb(ahc, SCSICONF, scsi_conf);
572 
573 		if (sc.adapter_control & CF284XSTERM)
574 			ahc->flags |= AHC_TERM_ENB_A;
575 	}
576 }
577