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
ahc_isa_irq(bus_space_tag_t iot,bus_space_handle_t ioh)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
ahc_isa_idstring(bus_space_tag_t iot,bus_space_handle_t ioh,char * idstring)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
ahc_isa_match(struct isa_attach_args * ia,bus_addr_t iobase)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
ahc_isa_probe(struct device * parent,void * match,void * aux)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
ahc_isa_attach(struct device * parent,struct device * self,void * aux)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
aha2840_load_seeprom(struct ahc_softc * ahc)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 *)≻
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