Annotation of sys/arch/i386/isa/ahc_isa.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: ahc_isa.c,v 1.16 2007/04/10 17:47:54 miod 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: 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 preseving 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: could not 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: * usefull 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 differenent 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 *)≻
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: }
CVSweb