ahc_eisa.c revision 47277
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.9 1999/05/17 21:51:41 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
101	desc = aic7770_match(eisa_get_id(dev));
102	if (!desc)
103		return (ENXIO);
104	device_set_desc(dev, desc);
105
106	iobase = (eisa_get_slot(dev) * EISA_SLOT_SIZE)
107	    + AHC_EISA_SLOT_OFFSET;
108
109		/* Pause the card preseving the IRQ type */
110	hcntrl = inb(iobase + HCNTRL) & IRQMS;
111
112	outb(iobase + HCNTRL, hcntrl | PAUSE);
113
114	eisa_add_iospace(dev, iobase, AHC_EISA_IOSIZE, RESVADDR_NONE);
115	intdef = inb(INTDEF + iobase);
116	irq = intdef & 0xf;
117	switch (irq) {
118	case 9:
119	case 10:
120	case 11:
121	case 12:
122	case 14:
123	case 15:
124	    break;
125	default:
126	    printf("aic7770 at slot %d: illegal "
127		   "irq setting %d\n", eisa_get_slot(dev),
128		   intdef);
129	    irq = 0;
130	    break;
131	}
132	if (irq == 0)
133	    return ENXIO;
134
135	eisa_add_intr(dev, irq);
136
137	return 0;
138}
139
140static int
141aic7770_attach(device_t dev)
142{
143	ahc_chip chip;
144	bus_dma_tag_t parent_dmat;
145	struct ahc_softc *ahc;
146	struct resource *io;
147	int error, rid;
148	int shared;
149
150	rid = 0;
151	io = NULL;
152	ahc = NULL;
153	switch (eisa_get_id(dev)) {
154	case EISA_DEVICE_ID_ADAPTEC_274x:
155	case EISA_DEVICE_ID_ADAPTEC_AIC7770:
156		chip = AHC_AIC7770|AHC_EISA;
157		break;
158	case EISA_DEVICE_ID_ADAPTEC_284xB:
159	case EISA_DEVICE_ID_ADAPTEC_284x:
160		chip = AHC_AIC7770|AHC_VL;
161		break;
162	default:
163		printf("aic7770_attach: Unknown device type!\n");
164		goto bad;
165	}
166
167	/* XXX Should be a child of the EISA bus dma tag */
168	error = bus_dma_tag_create(/*parent*/NULL, /*alignment*/0,
169				   /*boundary*/0,
170				   /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
171				   /*highaddr*/BUS_SPACE_MAXADDR,
172				   /*filter*/NULL, /*filterarg*/NULL,
173				   /*maxsize*/MAXBSIZE,
174				   /*nsegments*/AHC_NSEG,
175				   /*maxsegsz*/AHC_MAXTRANSFER_SIZE,
176				   /*flags*/BUS_DMA_ALLOCNOW, &parent_dmat);
177
178	if (error != 0) {
179		printf("ahc_eisa_attach: Could not allocate DMA tag "
180		       "- error %d\n", error);
181		goto bad;
182	}
183
184	io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
185				0, ~0, 1, RF_ACTIVE);
186	if (!io) {
187		device_printf(dev, "No I/O space?!\n");
188		return ENOMEM;
189	}
190
191	if (!(ahc = ahc_alloc(dev, io, SYS_RES_IOPORT, rid,
192			      parent_dmat, chip, AHC_AIC7770_FE, AHC_FNONE,
193			      NULL)))
194		goto bad;
195
196	io = NULL;
197
198	ahc->channel = 'A';
199	ahc->channel_b = 'B';
200	if (ahc_reset(ahc) != 0) {
201		goto bad;
202	}
203
204	/*
205	 * The IRQMS bit enables level sensitive interrupts. Only allow
206	 * IRQ sharing if it's set.
207	 */
208	shared = (ahc->pause & IRQMS) ? RF_SHAREABLE : 0;
209	rid = 0;
210	ahc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
211				      0, ~0, 1, shared  | 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 */
479