Deleted Added
sdiff udiff text old ( 49360 ) new ( 49860 )
full compact
1/*
2 * Product specific probe and attach routines for:
3 * 27/284X and aic7770 motherboard SCSI controllers
4 *
5 * Copyright (c) 1994, 1995, 1996, 1997, 1998 Justin T. Gibbs.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice immediately at the beginning of the file, without modification,
13 * this list of conditions, and the following disclaimer.
14 * 2. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
21 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $Id: ahc_eisa.c,v 1.10 1999/05/17 21:56:00 gibbs Exp $
30 */
31
32#include "eisa.h"
33#if NEISA > 0
34
35#include <sys/param.h>
36#include <sys/systm.h>
37#include <sys/kernel.h>
38#include <sys/module.h>
39#include <sys/bus.h>
40
41#include <machine/bus_pio.h>
42#include <machine/bus.h>
43#include <machine/resource.h>
44#include <sys/rman.h>
45
46#include <i386/eisa/eisaconf.h>
47
48#include <cam/cam.h>
49#include <cam/cam_ccb.h>
50#include <cam/cam_sim.h>
51#include <cam/cam_xpt_sim.h>
52#include <cam/scsi/scsi_all.h>
53
54#include <dev/aic7xxx/aic7xxx.h>
55#include <dev/aic7xxx/93cx6.h>
56
57#include <aic7xxx_reg.h>
58
59#define EISA_DEVICE_ID_ADAPTEC_AIC7770 0x04907770
60#define EISA_DEVICE_ID_ADAPTEC_274x 0x04907771
61#define EISA_DEVICE_ID_ADAPTEC_284xB 0x04907756 /* BIOS enabled */
62#define EISA_DEVICE_ID_ADAPTEC_284x 0x04907757 /* BIOS disabled*/
63
64#define AHC_EISA_SLOT_OFFSET 0xc00
65#define AHC_EISA_IOSIZE 0x100
66#define INTDEF 0x5cul /* Interrupt Definition Register */
67
68static void aha2840_load_seeprom(struct ahc_softc *ahc);
69
70static const char *aic7770_match(eisa_id_t type);
71
72static const char*
73aic7770_match(eisa_id_t type)
74{
75 switch (type) {
76 case EISA_DEVICE_ID_ADAPTEC_AIC7770:
77 return ("Adaptec aic7770 SCSI host adapter");
78 break;
79 case EISA_DEVICE_ID_ADAPTEC_274x:
80 return ("Adaptec 274X SCSI host adapter");
81 break;
82 case EISA_DEVICE_ID_ADAPTEC_284xB:
83 case EISA_DEVICE_ID_ADAPTEC_284x:
84 return ("Adaptec 284X SCSI host adapter");
85 break;
86 default:
87 break;
88 }
89 return (NULL);
90}
91
92static int
93aic7770_probe(device_t dev)
94{
95 const char *desc;
96 u_int32_t iobase;
97 u_int32_t irq;
98 u_int8_t intdef;
99 u_int8_t hcntrl;
100 int shared;
101
102 desc = aic7770_match(eisa_get_id(dev));
103 if (!desc)
104 return (ENXIO);
105 device_set_desc(dev, desc);
106
107 iobase = (eisa_get_slot(dev) * EISA_SLOT_SIZE)
108 + AHC_EISA_SLOT_OFFSET;
109
110 /* Pause the card preseving the IRQ type */
111 hcntrl = inb(iobase + HCNTRL) & IRQMS;
112
113 outb(iobase + HCNTRL, hcntrl | PAUSE);
114
115 eisa_add_iospace(dev, iobase, AHC_EISA_IOSIZE, RESVADDR_NONE);
116 intdef = inb(INTDEF + iobase);
117 shared = (intdef & 0x80) ? EISA_TRIGGER_EDGE : EISA_TRIGGER_LEVEL;
118 irq = intdef & 0xf;
119 switch (irq) {
120 case 9:
121 case 10:
122 case 11:
123 case 12:
124 case 14:
125 case 15:
126 break;
127 default:
128 printf("aic7770 at slot %d: illegal "
129 "irq setting %d\n", eisa_get_slot(dev),
130 intdef);
131 irq = 0;
132 break;
133 }
134 if (irq == 0)
135 return ENXIO;
136
137 eisa_add_intr(dev, irq, shared);
138
139 return 0;
140}
141
142static int
143aic7770_attach(device_t dev)
144{
145 ahc_chip chip;
146 bus_dma_tag_t parent_dmat;
147 struct ahc_softc *ahc;
148 struct resource *io;
149 int error, rid;
150
151 rid = 0;
152 io = NULL;
153 ahc = NULL;
154 switch (eisa_get_id(dev)) {
155 case EISA_DEVICE_ID_ADAPTEC_274x:
156 case EISA_DEVICE_ID_ADAPTEC_AIC7770:
157 chip = AHC_AIC7770|AHC_EISA;
158 break;
159 case EISA_DEVICE_ID_ADAPTEC_284xB:
160 case EISA_DEVICE_ID_ADAPTEC_284x:
161 chip = AHC_AIC7770|AHC_VL;
162 break;
163 default:
164 printf("aic7770_attach: Unknown device type!\n");
165 goto bad;
166 }
167
168 /* XXX Should be a child of the EISA bus dma tag */
169 error = bus_dma_tag_create(/*parent*/NULL, /*alignment*/0,
170 /*boundary*/0,
171 /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
172 /*highaddr*/BUS_SPACE_MAXADDR,
173 /*filter*/NULL, /*filterarg*/NULL,
174 /*maxsize*/MAXBSIZE,
175 /*nsegments*/AHC_NSEG,
176 /*maxsegsz*/AHC_MAXTRANSFER_SIZE,
177 /*flags*/BUS_DMA_ALLOCNOW, &parent_dmat);
178
179 if (error != 0) {
180 printf("ahc_eisa_attach: Could not allocate DMA tag "
181 "- error %d\n", error);
182 goto bad;
183 }
184
185 io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
186 0, ~0, 1, RF_ACTIVE);
187 if (!io) {
188 device_printf(dev, "No I/O space?!\n");
189 return ENOMEM;
190 }
191
192 if (!(ahc = ahc_alloc(dev, io, SYS_RES_IOPORT, rid,
193 parent_dmat, chip, AHC_AIC7770_FE, AHC_FNONE,
194 NULL)))
195 goto bad;
196
197 io = NULL;
198
199 ahc->channel = 'A';
200 ahc->channel_b = 'B';
201 if (ahc_reset(ahc) != 0) {
202 goto bad;
203 }
204
205 /*
206 * The IRQMS bit enables level sensitive interrupts. Only allow
207 * IRQ sharing if it's set.
208 */
209 rid = 0;
210 ahc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
211 0, ~0, 1, RF_ACTIVE);
212 if (ahc->irq == NULL) {
213 device_printf(dev, "Can't allocate interrupt\n");
214 goto bad;
215 }
216 ahc->irq_res_type = SYS_RES_IRQ;
217
218 /*
219 * Tell the user what type of interrupts we're using.
220 * usefull for debugging irq problems
221 */
222 if (bootverbose) {
223 printf("%s: Using %s Interrupts\n",
224 ahc_name(ahc),
225 ahc->pause & IRQMS ?
226 "Level Sensitive" : "Edge Triggered");
227 }
228
229 /*
230 * Now that we know we own the resources we need, do the
231 * card initialization.
232 *
233 * First, the aic7770 card specific setup.
234 */
235 switch (chip & (AHC_EISA|AHC_VL)) {
236 case AHC_EISA:
237 {
238 u_int biosctrl;
239 u_int scsiconf;
240 u_int scsiconf1;
241#if DEBUG
242 int i;
243#endif
244
245 biosctrl = ahc_inb(ahc, HA_274_BIOSCTRL);
246 scsiconf = ahc_inb(ahc, SCSICONF);
247 scsiconf1 = ahc_inb(ahc, SCSICONF + 1);
248
249#if DEBUG
250 for (i = TARG_SCSIRATE; i <= HA_274_BIOSCTRL; i+=8) {
251 printf("0x%x, 0x%x, 0x%x, 0x%x, "
252 "0x%x, 0x%x, 0x%x, 0x%x\n",
253 ahc_inb(ahc, i),
254 ahc_inb(ahc, i+1),
255 ahc_inb(ahc, i+2),
256 ahc_inb(ahc, i+3),
257 ahc_inb(ahc, i+4),
258 ahc_inb(ahc, i+5),
259 ahc_inb(ahc, i+6),
260 ahc_inb(ahc, i+7));
261 }
262#endif
263
264 /* Get the primary channel information */
265 if ((biosctrl & CHANNEL_B_PRIMARY) != 0)
266 ahc->flags |= AHC_CHANNEL_B_PRIMARY;
267
268 if ((biosctrl & BIOSMODE) == BIOSDISABLED) {
269 ahc->flags |= AHC_USEDEFAULTS;
270 } else {
271 if ((ahc->features & AHC_WIDE) != 0) {
272 ahc->our_id = scsiconf1 & HWSCSIID;
273 if (scsiconf & TERM_ENB)
274 ahc->flags |= AHC_TERM_ENB_A;
275 } else {
276 ahc->our_id = scsiconf & HSCSIID;
277 ahc->our_id_b = scsiconf1 & HSCSIID;
278 if (scsiconf & TERM_ENB)
279 ahc->flags |= AHC_TERM_ENB_A;
280 if (scsiconf1 & TERM_ENB)
281 ahc->flags |= AHC_TERM_ENB_B;
282 }
283 }
284 /*
285 * We have no way to tell, so assume extended
286 * translation is enabled.
287 */
288 ahc->flags |= AHC_EXTENDED_TRANS_A|AHC_EXTENDED_TRANS_B;
289 break;
290 }
291 case AHC_VL:
292 {
293 aha2840_load_seeprom(ahc);
294 break;
295 }
296 default:
297 break;
298 }
299
300 /*
301 * See if we have a Rev E or higher aic7770. Anything below a
302 * Rev E will have a R/O autoflush disable configuration bit.
303 */
304 {
305 char *id_string;
306 u_int8_t sblkctl;
307 u_int8_t sblkctl_orig;
308
309 sblkctl_orig = ahc_inb(ahc, SBLKCTL);
310 sblkctl = sblkctl_orig ^ AUTOFLUSHDIS;
311 ahc_outb(ahc, SBLKCTL, sblkctl);
312 sblkctl = ahc_inb(ahc, SBLKCTL);
313 if (sblkctl != sblkctl_orig) {
314 id_string = "aic7770 >= Rev E, ";
315 /*
316 * Ensure autoflush is enabled
317 */
318 sblkctl &= ~AUTOFLUSHDIS;
319 ahc_outb(ahc, SBLKCTL, sblkctl);
320
321 } else
322 id_string = "aic7770 <= Rev C, ";
323
324 printf("%s: %s", ahc_name(ahc), id_string);
325 }
326
327 /* Setup the FIFO threshold and the bus off time */
328 {
329 u_int8_t hostconf = ahc_inb(ahc, HOSTCONF);
330 ahc_outb(ahc, BUSSPD, hostconf & DFTHRSH);
331 ahc_outb(ahc, BUSTIME, (hostconf << 2) & BOFF);
332 }
333
334 /*
335 * Generic aic7xxx initialization.
336 */
337 if (ahc_init(ahc)) {
338 /*
339 * The board's IRQ line is not yet enabled so it's safe
340 * to release the irq.
341 */
342 goto bad;
343 }
344
345 /*
346 * Enable the board's BUS drivers
347 */
348 ahc_outb(ahc, BCTL, ENABLE);
349
350 /* Attach sub-devices - always succeeds */
351 ahc_attach(ahc);
352
353 return 0;
354
355 bad:
356 if (ahc != NULL)
357 ahc_free(ahc);
358
359 if (io != NULL)
360 bus_release_resource(dev, SYS_RES_IOPORT, 0, io);
361
362 return -1;
363}
364
365/*
366 * Read the 284x SEEPROM.
367 */
368static void
369aha2840_load_seeprom(struct ahc_softc *ahc)
370{
371 struct seeprom_descriptor sd;
372 struct seeprom_config sc;
373 u_int16_t checksum = 0;
374 u_int8_t scsi_conf;
375 int have_seeprom;
376
377 sd.sd_tag = ahc->tag;
378 sd.sd_bsh = ahc->bsh;
379 sd.sd_control_offset = SEECTL_2840;
380 sd.sd_status_offset = STATUS_2840;
381 sd.sd_dataout_offset = STATUS_2840;
382 sd.sd_chip = C46;
383 sd.sd_MS = 0;
384 sd.sd_RDY = EEPROM_TF;
385 sd.sd_CS = CS_2840;
386 sd.sd_CK = CK_2840;
387 sd.sd_DO = DO_2840;
388 sd.sd_DI = DI_2840;
389
390 if (bootverbose)
391 printf("%s: Reading SEEPROM...", ahc_name(ahc));
392 have_seeprom = read_seeprom(&sd,
393 (u_int16_t *)&sc,
394 /*start_addr*/0,
395 sizeof(sc)/2);
396
397 if (have_seeprom) {
398 /* Check checksum */
399 int i;
400 int maxaddr = (sizeof(sc)/2) - 1;
401 u_int16_t *scarray = (u_int16_t *)&sc;
402
403 for (i = 0; i < maxaddr; i++)
404 checksum = checksum + scarray[i];
405 if (checksum != sc.checksum) {
406 if(bootverbose)
407 printf ("checksum error\n");
408 have_seeprom = 0;
409 } else if (bootverbose) {
410 printf("done.\n");
411 }
412 }
413
414 if (!have_seeprom) {
415 if (bootverbose)
416 printf("%s: No SEEPROM available\n", ahc_name(ahc));
417 ahc->flags |= AHC_USEDEFAULTS;
418 } else {
419 /*
420 * Put the data we've collected down into SRAM
421 * where ahc_init will find it.
422 */
423 int i;
424 int max_targ = (ahc->features & AHC_WIDE) != 0 ? 16 : 8;
425 u_int16_t discenable;
426
427 discenable = 0;
428 for (i = 0; i < max_targ; i++){
429 u_int8_t target_settings;
430 target_settings = (sc.device_flags[i] & CFXFER) << 4;
431 if (sc.device_flags[i] & CFSYNCH)
432 target_settings |= SOFS;
433 if (sc.device_flags[i] & CFWIDEB)
434 target_settings |= WIDEXFER;
435 if (sc.device_flags[i] & CFDISC)
436 discenable |= (0x01 << i);
437 ahc_outb(ahc, TARG_SCSIRATE + i, target_settings);
438 }
439 ahc_outb(ahc, DISC_DSB, ~(discenable & 0xff));
440 ahc_outb(ahc, DISC_DSB + 1, ~((discenable >> 8) & 0xff));
441
442 ahc->our_id = sc.brtime_id & CFSCSIID;
443
444 scsi_conf = (ahc->our_id & 0x7);
445 if (sc.adapter_control & CFSPARITY)
446 scsi_conf |= ENSPCHK;
447 if (sc.adapter_control & CFRESETB)
448 scsi_conf |= RESET_SCSI;
449
450 if (sc.bios_control & CF284XEXTEND)
451 ahc->flags |= AHC_EXTENDED_TRANS_A;
452 /* Set SCSICONF info */
453 ahc_outb(ahc, SCSICONF, scsi_conf);
454
455 if (sc.adapter_control & CF284XSTERM)
456 ahc->flags |= AHC_TERM_ENB_A;
457 }
458}
459
460static device_method_t ahc_eisa_methods[] = {
461 /* Device interface */
462 DEVMETHOD(device_probe, aic7770_probe),
463 DEVMETHOD(device_attach, aic7770_attach),
464
465 { 0, 0 }
466};
467
468static driver_t ahc_eisa_driver = {
469 "ahc",
470 ahc_eisa_methods,
471 1, /* unused */
472};
473
474static devclass_t ahc_devclass;
475
476DRIVER_MODULE(ahc, eisa, ahc_eisa_driver, ahc_devclass, 0, 0);
477
478#endif /* NEISA > 0 */