xref: /freebsd/sys/dev/aic7xxx/aic7770.c (revision 5521ff5a4d1929056e7ffc982fac3341ca54df7c)
1 /*
2  * Product specific probe and attach routines for:
3  * 	27/284X and aic7770 motherboard SCSI controllers
4  *
5  * Copyright (c) 1994-1998, 2000, 2001 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  * Alternatively, this software may be distributed under the terms of the
18  * GNU Public License ("GPL").
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
24  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * $Id: //depot/src/aic7xxx/aic7770.c#11 $
33  *
34  * $FreeBSD$
35  */
36 
37 #include <dev/aic7xxx/aic7xxx_freebsd.h>
38 #include <dev/aic7xxx/aic7xxx_inline.h>
39 #include <dev/aic7xxx/aic7xxx_93cx6.h>
40 
41 #define ID_AIC7770	0x04907770
42 #define ID_AHA_274x	0x04907771
43 #define ID_AHA_284xB	0x04907756 /* BIOS enabled */
44 #define ID_AHA_284x	0x04907757 /* BIOS disabled*/
45 
46 static void aha2840_load_seeprom(struct ahc_softc *ahc);
47 static ahc_device_setup_t ahc_aic7770_VL_setup;
48 static ahc_device_setup_t ahc_aic7770_EISA_setup;;
49 static ahc_device_setup_t ahc_aic7770_setup;
50 
51 
52 struct aic7770_identity aic7770_ident_table [] =
53 {
54 	{
55 		ID_AHA_274x,
56 		0xFFFFFFFF,
57 		"Adaptec 274X SCSI adapter",
58 		ahc_aic7770_EISA_setup
59 	},
60 	{
61 		ID_AHA_284xB,
62 		0xFFFFFFFE,
63 		"Adaptec 284X SCSI adapter",
64 		ahc_aic7770_VL_setup
65 	},
66 	/* Generic chip probes for devices we don't know 'exactly' */
67 	{
68 		ID_AIC7770,
69 		0xFFFFFFFF,
70 		"Adaptec aic7770 SCSI adapter",
71 		ahc_aic7770_EISA_setup
72 	}
73 };
74 const int ahc_num_aic7770_devs = NUM_ELEMENTS(aic7770_ident_table);
75 
76 struct aic7770_identity *
77 aic7770_find_device(uint32_t id)
78 {
79 	struct	aic7770_identity *entry;
80 	int	i;
81 
82 	for (i = 0; i < ahc_num_aic7770_devs; i++) {
83 		entry = &aic7770_ident_table[i];
84 		if (entry->full_id == (id & entry->id_mask))
85 			return (entry);
86 	}
87 	return (NULL);
88 }
89 
90 int
91 aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry)
92 {
93 	struct	ahc_probe_config probe_config;
94 	int	error;
95 	u_int	hostconf;
96 	u_int   irq;
97 	u_int	intdef;
98 
99 	ahc_init_probe_config(&probe_config);
100 	error = entry->setup(ahc->dev_softc, &probe_config);
101 	if (error != 0)
102 		return (error);
103 
104 	error = aic7770_map_registers(ahc);
105 	if (error != 0)
106 		return (error);
107 
108 	probe_config.description = entry->name;
109 	error = ahc_softc_init(ahc, &probe_config);
110 
111 	error = ahc_reset(ahc);
112 	if (error != 0)
113 		return (error);
114 
115 	/* Make sure we have a valid interrupt vector */
116 	intdef = ahc_inb(ahc, INTDEF);
117 	irq = intdef & VECTOR;
118 	switch (irq) {
119 	case 9:
120 	case 10:
121 	case 11:
122 	case 12:
123 	case 14:
124 	case 15:
125 		break;
126 	default:
127 		printf("aic7770_config: illegal irq setting %d\n", intdef);
128 		return (ENXIO);
129 	}
130 
131 	if ((intdef & EDGE_TRIG) != 0)
132 		ahc->flags |= AHC_EDGE_INTERRUPT;
133 
134 	switch (probe_config.chip & (AHC_EISA|AHC_VL)) {
135 	case AHC_EISA:
136 	{
137 		u_int biosctrl;
138 		u_int scsiconf;
139 		u_int scsiconf1;
140 
141 		biosctrl = ahc_inb(ahc, HA_274_BIOSCTRL);
142 		scsiconf = ahc_inb(ahc, SCSICONF);
143 		scsiconf1 = ahc_inb(ahc, SCSICONF + 1);
144 
145 		/* Get the primary channel information */
146 		if ((biosctrl & CHANNEL_B_PRIMARY) != 0)
147 			ahc->flags |= 1;
148 
149 		if ((biosctrl & BIOSMODE) == BIOSDISABLED) {
150 			ahc->flags |= AHC_USEDEFAULTS;
151 		} else {
152 			if ((ahc->features & AHC_WIDE) != 0) {
153 				ahc->our_id = scsiconf1 & HWSCSIID;
154 				if (scsiconf & TERM_ENB)
155 					ahc->flags |= AHC_TERM_ENB_A;
156 			} else {
157 				ahc->our_id = scsiconf & HSCSIID;
158 				ahc->our_id_b = scsiconf1 & HSCSIID;
159 				if (scsiconf & TERM_ENB)
160 					ahc->flags |= AHC_TERM_ENB_A;
161 				if (scsiconf1 & TERM_ENB)
162 					ahc->flags |= AHC_TERM_ENB_B;
163 			}
164 		}
165 		/*
166 		 * We have no way to tell, so assume extended
167 		 * translation is enabled.
168 		 */
169 		ahc->flags |= AHC_EXTENDED_TRANS_A|AHC_EXTENDED_TRANS_B;
170 		break;
171 	}
172 	case AHC_VL:
173 	{
174 		aha2840_load_seeprom(ahc);
175 		break;
176 	}
177 	default:
178 		break;
179 	}
180 
181 	/*
182 	 * Ensure autoflush is enabled
183 	 */
184 	ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~AUTOFLUSHDIS);
185 
186 	/* Setup the FIFO threshold and the bus off time */
187 	hostconf = ahc_inb(ahc, HOSTCONF);
188 	ahc_outb(ahc, BUSSPD, hostconf & DFTHRSH);
189 	ahc_outb(ahc, BUSTIME, (hostconf << 2) & BOFF);
190 
191 	/*
192 	 * Generic aic7xxx initialization.
193 	 */
194 	error = ahc_init(ahc);
195 	if (error != 0)
196 		return (error);
197 
198 	/*
199 	 * Link this softc in with all other ahc instances.
200 	 */
201 	ahc_softc_insert(ahc);
202 
203 	error = aic7770_map_int(ahc, irq);
204 	if (error != 0)
205 		return (error);
206 
207 	/*
208 	 * Enable the board's BUS drivers
209 	 */
210 	ahc_outb(ahc, BCTL, ENABLE);
211 
212 	/*
213 	 * Allow interrupts.
214 	 */
215 	ahc_intr_enable(ahc, TRUE);
216 
217 	return (0);
218 }
219 
220 /*
221  * Read the 284x SEEPROM.
222  */
223 static void
224 aha2840_load_seeprom(struct ahc_softc *ahc)
225 {
226 	struct	  seeprom_descriptor sd;
227 	struct	  seeprom_config sc;
228 	uint16_t  checksum = 0;
229 	uint8_t   scsi_conf;
230 	int	  have_seeprom;
231 
232 	sd.sd_ahc = ahc;
233 	sd.sd_control_offset = SEECTL_2840;
234 	sd.sd_status_offset = STATUS_2840;
235 	sd.sd_dataout_offset = STATUS_2840;
236 	sd.sd_chip = C46;
237 	sd.sd_MS = 0;
238 	sd.sd_RDY = EEPROM_TF;
239 	sd.sd_CS = CS_2840;
240 	sd.sd_CK = CK_2840;
241 	sd.sd_DO = DO_2840;
242 	sd.sd_DI = DI_2840;
243 
244 	if (bootverbose)
245 		printf("%s: Reading SEEPROM...", ahc_name(ahc));
246 	have_seeprom = read_seeprom(&sd,
247 				    (uint16_t *)&sc,
248 				    /*start_addr*/0,
249 				    sizeof(sc)/2);
250 
251 	if (have_seeprom) {
252 		/* Check checksum */
253 		int i;
254 		int maxaddr = (sizeof(sc)/2) - 1;
255 		uint16_t *scarray = (uint16_t *)&sc;
256 
257 		for (i = 0; i < maxaddr; i++)
258 			checksum = checksum + scarray[i];
259 		if (checksum != sc.checksum) {
260 			if(bootverbose)
261 				printf ("checksum error\n");
262 			have_seeprom = 0;
263 		} else if (bootverbose) {
264 			printf("done.\n");
265 		}
266 	}
267 
268 	if (!have_seeprom) {
269 		if (bootverbose)
270 			printf("%s: No SEEPROM available\n", ahc_name(ahc));
271 		ahc->flags |= AHC_USEDEFAULTS;
272 	} else {
273 		/*
274 		 * Put the data we've collected down into SRAM
275 		 * where ahc_init will find it.
276 		 */
277 		int i;
278 		int max_targ = (ahc->features & AHC_WIDE) != 0 ? 16 : 8;
279 		uint16_t discenable;
280 
281 		discenable = 0;
282 		for (i = 0; i < max_targ; i++){
283 	                uint8_t target_settings;
284 			target_settings = (sc.device_flags[i] & CFXFER) << 4;
285 			if (sc.device_flags[i] & CFSYNCH)
286 				target_settings |= SOFS;
287 			if (sc.device_flags[i] & CFWIDEB)
288 				target_settings |= WIDEXFER;
289 			if (sc.device_flags[i] & CFDISC)
290 				discenable |= (0x01 << i);
291 			ahc_outb(ahc, TARG_SCSIRATE + i, target_settings);
292 		}
293 		ahc_outb(ahc, DISC_DSB, ~(discenable & 0xff));
294 		ahc_outb(ahc, DISC_DSB + 1, ~((discenable >> 8) & 0xff));
295 
296 		ahc->our_id = sc.brtime_id & CFSCSIID;
297 
298 		scsi_conf = (ahc->our_id & 0x7);
299 		if (sc.adapter_control & CFSPARITY)
300 			scsi_conf |= ENSPCHK;
301 		if (sc.adapter_control & CFRESETB)
302 			scsi_conf |= RESET_SCSI;
303 
304 		if (sc.bios_control & CF284XEXTEND)
305 			ahc->flags |= AHC_EXTENDED_TRANS_A;
306 		/* Set SCSICONF info */
307 		ahc_outb(ahc, SCSICONF, scsi_conf);
308 
309 		if (sc.adapter_control & CF284XSTERM)
310 			ahc->flags |= AHC_TERM_ENB_A;
311 	}
312 }
313 
314 static int
315 ahc_aic7770_VL_setup(ahc_dev_softc_t dev, struct ahc_probe_config *probe_config)
316 {
317 	int error;
318 
319 	error = ahc_aic7770_setup(dev, probe_config);
320 	probe_config->chip |= AHC_VL;
321 	return (error);
322 }
323 
324 static int
325 ahc_aic7770_EISA_setup(ahc_dev_softc_t dev,
326 		       struct ahc_probe_config *probe_config)
327 {
328 	int error;
329 
330 	error = ahc_aic7770_setup(dev, probe_config);
331 	probe_config->chip |= AHC_EISA;
332 	return (error);
333 }
334 
335 static int
336 ahc_aic7770_setup(ahc_dev_softc_t dev, struct ahc_probe_config *probe_config)
337 {
338 	probe_config->channel = 'A';
339 	probe_config->channel_b = 'B';
340 	probe_config->chip = AHC_AIC7770;
341 	probe_config->features = AHC_AIC7770_FE;
342 	probe_config->bugs |= AHC_TMODE_WIDEODD_BUG;
343 	probe_config->flags |= AHC_PAGESCBS;
344 	return (0);
345 }
346