xref: /openbsd/sys/dev/ic/adwlib.c (revision 7d4909e3)
1*7d4909e3Skrw /*	$OpenBSD: adwlib.c,v 1.13 2001/04/11 04:05:16 krw Exp $ */
23976a5edSkrw /* $NetBSD: adwlib.c,v 1.20 2000/07/04 04:17:03 itojun Exp $        */
3379dd687Sdownsj 
4379dd687Sdownsj /*
5379dd687Sdownsj  * Low level routines for the Advanced Systems Inc. SCSI controllers chips
6379dd687Sdownsj  *
7466e5dfaSderaadt  * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc.
8379dd687Sdownsj  * All rights reserved.
9379dd687Sdownsj  *
10379dd687Sdownsj  * Author: Baldassare Dante Profeta <dante@mclink.it>
11379dd687Sdownsj  *
12379dd687Sdownsj  * Redistribution and use in source and binary forms, with or without
13379dd687Sdownsj  * modification, are permitted provided that the following conditions
14379dd687Sdownsj  * are met:
15379dd687Sdownsj  * 1. Redistributions of source code must retain the above copyright
16379dd687Sdownsj  *    notice, this list of conditions and the following disclaimer.
17379dd687Sdownsj  * 2. Redistributions in binary form must reproduce the above copyright
18379dd687Sdownsj  *    notice, this list of conditions and the following disclaimer in the
19379dd687Sdownsj  *    documentation and/or other materials provided with the distribution.
20379dd687Sdownsj  * 3. All advertising materials mentioning features or use of this software
21379dd687Sdownsj  *    must display the following acknowledgement:
22379dd687Sdownsj  *        This product includes software developed by the NetBSD
23379dd687Sdownsj  *        Foundation, Inc. and its contributors.
24379dd687Sdownsj  * 4. Neither the name of The NetBSD Foundation nor the names of its
25379dd687Sdownsj  *    contributors may be used to endorse or promote products derived
26379dd687Sdownsj  *    from this software without specific prior written permission.
27379dd687Sdownsj  *
28379dd687Sdownsj  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29379dd687Sdownsj  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30379dd687Sdownsj  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31379dd687Sdownsj  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32379dd687Sdownsj  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33379dd687Sdownsj  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34379dd687Sdownsj  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35379dd687Sdownsj  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36379dd687Sdownsj  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37379dd687Sdownsj  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38379dd687Sdownsj  * POSSIBILITY OF SUCH DAMAGE.
39379dd687Sdownsj  */
40379dd687Sdownsj /*
41379dd687Sdownsj  * Ported from:
42379dd687Sdownsj  */
43379dd687Sdownsj /*
44379dd687Sdownsj  * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
45379dd687Sdownsj  *
466be43703Skrw  * Copyright (c) 1995-2000 Advanced System Products, Inc.
47379dd687Sdownsj  * All Rights Reserved.
48379dd687Sdownsj  *
49379dd687Sdownsj  * Redistribution and use in source and binary forms, with or without
50379dd687Sdownsj  * modification, are permitted provided that redistributions of source
51379dd687Sdownsj  * code retain the above copyright notice and this comment without
52379dd687Sdownsj  * modification.
53379dd687Sdownsj  */
54379dd687Sdownsj 
55379dd687Sdownsj #include <sys/types.h>
56379dd687Sdownsj #include <sys/param.h>
57379dd687Sdownsj #include <sys/systm.h>
58379dd687Sdownsj #include <sys/malloc.h>
59379dd687Sdownsj #include <sys/kernel.h>
60379dd687Sdownsj #include <sys/queue.h>
61379dd687Sdownsj #include <sys/device.h>
62379dd687Sdownsj 
63379dd687Sdownsj #include <machine/bus.h>
64379dd687Sdownsj #include <machine/intr.h>
65379dd687Sdownsj 
66379dd687Sdownsj #include <scsi/scsi_all.h>
67379dd687Sdownsj #include <scsi/scsiconf.h>
68379dd687Sdownsj 
69466e5dfaSderaadt #include <dev/pci/pcidevs.h>
70466e5dfaSderaadt 
71379dd687Sdownsj #include <vm/vm.h>
72379dd687Sdownsj 
73379dd687Sdownsj #include <dev/ic/adwlib.h>
74*7d4909e3Skrw #include <dev/microcode/adw/adwmcode.h>
756be43703Skrw #include <dev/ic/adw.h>
76379dd687Sdownsj 
77379dd687Sdownsj 
78379dd687Sdownsj /* Static Functions */
79379dd687Sdownsj 
806be43703Skrw int AdwRamSelfTest __P((bus_space_tag_t, bus_space_handle_t, u_int8_t));
816be43703Skrw int AdwLoadMCode __P((bus_space_tag_t, bus_space_handle_t, u_int16_t *,
826be43703Skrw 								u_int8_t));
836be43703Skrw int AdwASC3550Cabling __P((bus_space_tag_t, bus_space_handle_t, ADW_DVC_CFG *));
846be43703Skrw int AdwASC38C0800Cabling __P((bus_space_tag_t, bus_space_handle_t,
856be43703Skrw 								ADW_DVC_CFG *));
866be43703Skrw int AdwASC38C1600Cabling __P((bus_space_tag_t, bus_space_handle_t,
876be43703Skrw 								ADW_DVC_CFG *));
88379dd687Sdownsj 
896be43703Skrw static u_int16_t AdwGetEEPROMConfig __P((bus_space_tag_t, bus_space_handle_t,
906be43703Skrw      							ADW_EEPROM *));
916be43703Skrw static void AdwSetEEPROMConfig __P((bus_space_tag_t, bus_space_handle_t,
926be43703Skrw 					                 ADW_EEPROM *));
936be43703Skrw static u_int16_t AdwReadEEPWord __P((bus_space_tag_t, bus_space_handle_t, int));
946be43703Skrw static void AdwWaitEEPCmd __P((bus_space_tag_t, bus_space_handle_t));
956be43703Skrw 
966be43703Skrw static void AdwInquiryHandling __P((ADW_SOFTC *, ADW_SCSI_REQ_Q *));
976be43703Skrw 
986be43703Skrw static void AdwSleepMilliSecond __P((u_int32_t));
996be43703Skrw static void AdwDelayMicroSecond __P((u_int32_t));
100379dd687Sdownsj 
101379dd687Sdownsj 
102379dd687Sdownsj /*
103379dd687Sdownsj  * EEPROM Configuration.
104379dd687Sdownsj  *
105379dd687Sdownsj  * All drivers should use this structure to set the default EEPROM
106379dd687Sdownsj  * configuration. The BIOS now uses this structure when it is built.
107e693526fSkrw  * Additional structure information can be found in adwlib.h where
108379dd687Sdownsj  * the structure is defined.
109379dd687Sdownsj  */
1106be43703Skrw const static ADW_EEPROM adw_3550_Default_EEPROM = {
111466e5dfaSderaadt 	ADW_EEPROM_BIOS_ENABLE,	/* 00 cfg_lsw */
112466e5dfaSderaadt 	0x0000,			/* 01 cfg_msw */
113466e5dfaSderaadt 	0xFFFF,			/* 02 disc_enable */
114466e5dfaSderaadt 	0xFFFF,			/* 03 wdtr_able */
1156be43703Skrw 	{ 0xFFFF },		/* 04 sdtr_able */
1166be43703Skrw 	0xFFFF,			/* 05 start_motor */
1176be43703Skrw 	0xFFFF,			/* 06 tagqng_able */
1186be43703Skrw 	0xFFFF,			/* 07 bios_scan */
1196be43703Skrw 	0,			/* 08 scam_tolerant */
1206be43703Skrw 	7,			/* 09 adapter_scsi_id */
1216be43703Skrw 	0,			/*    bios_boot_delay */
1226be43703Skrw 	3,			/* 10 scsi_reset_delay */
1236be43703Skrw 	0,			/*    bios_id_lun */
1246be43703Skrw 	0,			/* 11 termination */
1256be43703Skrw 	0,			/*    reserved1 */
1266be43703Skrw 	0xFFE7,			/* 12 bios_ctrl */
1276be43703Skrw 	{ 0xFFFF },		/* 13 ultra_able */
1286be43703Skrw 	{ 0 },			/* 14 reserved2 */
1296be43703Skrw 	ADW_DEF_MAX_HOST_QNG,	/* 15 max_host_qng */
1306be43703Skrw 	ADW_DEF_MAX_DVC_QNG,	/*    max_dvc_qng */
1316be43703Skrw 	0,			/* 16 dvc_cntl */
1326be43703Skrw 	{ 0 },			/* 17 bug_fix */
1336be43703Skrw 	{ 0,0,0 },		/* 18-20 serial_number[3] */
1346be43703Skrw 	0,			/* 21 check_sum */
1356be43703Skrw 	{			/* 22-29 oem_name[16] */
1366be43703Skrw 	  0,0,0,0,0,0,0,0,
1376be43703Skrw 	  0,0,0,0,0,0,0,0
1386be43703Skrw 	},
1396be43703Skrw 	0,			/* 30 dvc_err_code */
140a1d22770Skrw 	0,			/* 31 adw_err_code */
141a1d22770Skrw 	0,			/* 32 adw_err_addr */
1426be43703Skrw 	0,			/* 33 saved_dvc_err_code */
143a1d22770Skrw 	0,			/* 34 saved_adw_err_code */
144a1d22770Skrw 	0			/* 35 saved_adw_err_addr */
1456be43703Skrw };
1466be43703Skrw 
1476be43703Skrw const static ADW_EEPROM adw_38C0800_Default_EEPROM = {
1486be43703Skrw 	ADW_EEPROM_BIOS_ENABLE,	/* 00 cfg_lsw */
1496be43703Skrw 	0x0000,			/* 01 cfg_msw */
1506be43703Skrw 	0xFFFF,			/* 02 disc_enable */
1516be43703Skrw 	0xFFFF,			/* 03 wdtr_able */
1526be43703Skrw 	{ 0x4444 },		/* 04 sdtr_speed1 */
153466e5dfaSderaadt 	0xFFFF,			/* 05 start_motor */
154466e5dfaSderaadt 	0xFFFF,			/* 06 tagqng_able */
155466e5dfaSderaadt 	0xFFFF,			/* 07 bios_scan */
156466e5dfaSderaadt 	0,			/* 08 scam_tolerant */
157466e5dfaSderaadt 	7,			/* 09 adapter_scsi_id */
158466e5dfaSderaadt 	0,			/*    bios_boot_delay */
159466e5dfaSderaadt 	3,			/* 10 scsi_reset_delay */
160466e5dfaSderaadt 	0,			/*    bios_id_lun */
161466e5dfaSderaadt 	0,			/* 11 termination_se */
162466e5dfaSderaadt 	0,			/*    termination_lvd */
163466e5dfaSderaadt 	0xFFE7,			/* 12 bios_ctrl */
1646be43703Skrw 	{ 0x4444 },		/* 13 sdtr_speed2 */
1656be43703Skrw 	{ 0x4444 },		/* 14 sdtr_speed3 */
1666be43703Skrw 	ADW_DEF_MAX_HOST_QNG,	/* 15 max_host_qng */
1676be43703Skrw 	ADW_DEF_MAX_DVC_QNG,	/*    max_dvc_qng */
168466e5dfaSderaadt 	0,			/* 16 dvc_cntl */
1696be43703Skrw 	{ 0x4444 },		/* 17 sdtr_speed4 */
1706be43703Skrw 	{ 0,0,0 },		/* 18-20 serial_number[3] */
171466e5dfaSderaadt 	0,			/* 21 check_sum */
1726be43703Skrw 	{			/* 22-29 oem_name[16] */
1736be43703Skrw 	  0,0,0,0,0,0,0,0,
1746be43703Skrw 	  0,0,0,0,0,0,0,0
1756be43703Skrw 	},
176466e5dfaSderaadt 	0,			/* 30 dvc_err_code */
177a1d22770Skrw 	0,			/* 31 adw_err_code */
178a1d22770Skrw 	0,			/* 32 adw_err_addr */
179466e5dfaSderaadt 	0,			/* 33 saved_dvc_err_code */
180a1d22770Skrw 	0,			/* 34 saved_adw_err_code */
181a1d22770Skrw 	0,			/* 35 saved_adw_err_addr */
1826be43703Skrw 	{			/* 36-55 reserved1[16] */
1836be43703Skrw 	  0,0,0,0,0,0,0,0,0,0,
1846be43703Skrw 	  0,0,0,0,0,0,0,0,0,0
1856be43703Skrw 	},
186466e5dfaSderaadt 	0,			/* 56 cisptr_lsw */
187466e5dfaSderaadt 	0,			/* 57 cisprt_msw */
188466e5dfaSderaadt 	PCI_VENDOR_ADVSYS,	/* 58 subsysvid */
189466e5dfaSderaadt 	PCI_PRODUCT_ADVSYS_U2W,	/* 59 subsysid */
1906be43703Skrw 	{ 0,0,0,0 }		/* 60-63 reserved2[4] */
191466e5dfaSderaadt };
192466e5dfaSderaadt 
1936be43703Skrw const static ADW_EEPROM adw_38C1600_Default_EEPROM = {
1946be43703Skrw 	ADW_EEPROM_BIOS_ENABLE,	/* 00 cfg_lsw */
1956be43703Skrw 	0x0000,			/* 01 cfg_msw */
1966be43703Skrw 	0xFFFF,			/* 02 disc_enable */
1976be43703Skrw 	0xFFFF,			/* 03 wdtr_able */
1986be43703Skrw 	{ 0x5555 },		/* 04 sdtr_speed1 */
1996be43703Skrw 	0xFFFF,			/* 05 start_motor */
2006be43703Skrw 	0xFFFF,			/* 06 tagqng_able */
2016be43703Skrw 	0xFFFF,			/* 07 bios_scan */
2026be43703Skrw 	0,			/* 08 scam_tolerant */
2036be43703Skrw 	7,			/* 09 adapter_scsi_id */
2046be43703Skrw 	0,			/*    bios_boot_delay */
2056be43703Skrw 	3,			/* 10 scsi_reset_delay */
2066be43703Skrw 	0,			/*    bios_id_lun */
2076be43703Skrw 	0,			/* 11 termination_se */
2086be43703Skrw 	0,			/*    termination_lvd */
2096be43703Skrw 	0xFFE7,			/* 12 bios_ctrl */
2106be43703Skrw 	{ 0x5555 },		/* 13 sdtr_speed2 */
2116be43703Skrw 	{ 0x5555 },		/* 14 sdtr_speed3 */
2126be43703Skrw 	ADW_DEF_MAX_HOST_QNG,	/* 15 max_host_qng */
2136be43703Skrw 	ADW_DEF_MAX_DVC_QNG,	/*    max_dvc_qng */
2146be43703Skrw 	0,			/* 16 dvc_cntl */
2156be43703Skrw 	{ 0x5555 },		/* 17 sdtr_speed4 */
2166be43703Skrw 	{ 0,0,0 },		/* 18-20 serial_number[3] */
2176be43703Skrw 	0,			/* 21 check_sum */
2186be43703Skrw 	{			/* 22-29 oem_name[16] */
2196be43703Skrw 	  0,0,0,0,0,0,0,0,
2206be43703Skrw 	  0,0,0,0,0,0,0,0
2216be43703Skrw 	},
2226be43703Skrw 	0,			/* 30 dvc_err_code */
223a1d22770Skrw 	0,			/* 31 adw_err_code */
224a1d22770Skrw 	0,			/* 32 adw_err_addr */
2256be43703Skrw 	0,			/* 33 saved_dvc_err_code */
226a1d22770Skrw 	0,			/* 34 saved_adw_err_code */
227a1d22770Skrw 	0,			/* 35 saved_adw_err_addr */
2286be43703Skrw 	{			/* 36-55 reserved1[16] */
2296be43703Skrw 	  0,0,0,0,0,0,0,0,0,0,
2306be43703Skrw 	  0,0,0,0,0,0,0,0,0,0
2316be43703Skrw 	},
2326be43703Skrw 	0,			/* 56 cisptr_lsw */
2336be43703Skrw 	0,			/* 57 cisprt_msw */
2346be43703Skrw 	PCI_VENDOR_ADVSYS,	/* 58 subsysvid */
2356be43703Skrw 	PCI_PRODUCT_ADVSYS_U3W, /* 59 subsysid */
2366be43703Skrw 	{ 0,0,0,0 }		/* 60-63 reserved2[4] */
2376be43703Skrw };
2386be43703Skrw 
2396be43703Skrw 
240379dd687Sdownsj /*
2416be43703Skrw  * Read the board's EEPROM configuration. Set fields in ADW_SOFTC and
2426be43703Skrw  * ADW_DVC_CFG based on the EEPROM settings. The chip is stopped while
2436be43703Skrw  * all of this is done.
244379dd687Sdownsj  *
245379dd687Sdownsj  * For a non-fatal error return a warning code. If there are no warnings
246379dd687Sdownsj  * then 0 is returned.
2476be43703Skrw  *
2486be43703Skrw  * Note: Chip is stopped on entry.
249379dd687Sdownsj  */
250379dd687Sdownsj int
2516be43703Skrw AdwInitFromEEPROM(sc)
252379dd687Sdownsj ADW_SOFTC      *sc;
253379dd687Sdownsj {
254379dd687Sdownsj 	bus_space_tag_t iot = sc->sc_iot;
255379dd687Sdownsj 	bus_space_handle_t ioh = sc->sc_ioh;
2566be43703Skrw 	ADW_EEPROM		eep_config;
257379dd687Sdownsj 	u_int16_t		warn_code;
2586be43703Skrw 	u_int16_t		sdtr_speed = 0;
2596be43703Skrw 	u_int8_t		tid, termination;
260466e5dfaSderaadt 	int			i, j;
261379dd687Sdownsj 
262379dd687Sdownsj 
263379dd687Sdownsj 	warn_code = 0;
264379dd687Sdownsj 
265379dd687Sdownsj 	/*
2666be43703Skrw 	 * Read the board's EEPROM configuration.
2676be43703Skrw 	 *
2686be43703Skrw 	 * Set default values if a bad checksum is found.
2696be43703Skrw 	 *
2706be43703Skrw 	 * XXX - Don't handle big-endian access to EEPROM yet.
2716be43703Skrw 	 */
2726be43703Skrw 	if (AdwGetEEPROMConfig(iot, ioh, &eep_config) != eep_config.check_sum) {
2736be43703Skrw 		warn_code |= ADW_WARN_EEPROM_CHKSUM;
2746be43703Skrw 
2756be43703Skrw 		/*
2766be43703Skrw 		 * Set EEPROM default values.
2776be43703Skrw 		 */
2786be43703Skrw 		switch(sc->chip_type) {
2796be43703Skrw 		case ADW_CHIP_ASC3550:
2806be43703Skrw 			eep_config = adw_3550_Default_EEPROM;
2816be43703Skrw 			break;
2826be43703Skrw 		case ADW_CHIP_ASC38C0800:
2836be43703Skrw 			eep_config = adw_38C0800_Default_EEPROM;
2846be43703Skrw 			break;
2856be43703Skrw 		case ADW_CHIP_ASC38C1600:
2866be43703Skrw 			eep_config = adw_38C1600_Default_EEPROM;
2876be43703Skrw 
2886be43703Skrw // XXX	  TODO!!!	if (ASC_PCI_ID2FUNC(sc->cfg.pci_slot_info) != 0) {
2896be43703Skrw 			if (sc->cfg.pci_slot_info != 0) {
2906be43703Skrw 				u_int8_t lsw_msb;
2916be43703Skrw 
2926be43703Skrw 				lsw_msb = eep_config.cfg_lsw >> 8;
2936be43703Skrw 				/*
2946be43703Skrw 				 * Set Function 1 EEPROM Word 0 MSB
2956be43703Skrw 				 *
2966be43703Skrw 				 * Clear the BIOS_ENABLE (bit 14) and
2976be43703Skrw 				 * INTAB (bit 11) EEPROM bits.
2986be43703Skrw 				 *
2996be43703Skrw 				 * Disable Bit 14 (BIOS_ENABLE) to fix
3006be43703Skrw 				 * SPARC Ultra 60 and old Mac system booting
3016be43703Skrw 				 * problem. The Expansion ROM must
3026be43703Skrw 				 * be disabled in Function 1 for these systems.
3036be43703Skrw 				 */
3046be43703Skrw 				lsw_msb &= ~(((ADW_EEPROM_BIOS_ENABLE |
3056be43703Skrw 						ADW_EEPROM_INTAB) >> 8) & 0xFF);
3066be43703Skrw 				/*
3076be43703Skrw 				 * Set the INTAB (bit 11) if the GPIO 0 input
3086be43703Skrw 				 * indicates the Function 1 interrupt line is
3096be43703Skrw 				 * wired to INTA.
3106be43703Skrw 				 *
3116be43703Skrw 				 * Set/Clear Bit 11 (INTAB) from
3126be43703Skrw 				 * the GPIO bit 0 input:
3136be43703Skrw 				 *   1 - Function 1 intr line wired to INT A.
3146be43703Skrw 				 *   0 - Function 1 intr line wired to INT B.
3156be43703Skrw 				 *
3166be43703Skrw 				 * Note: Adapter boards always have Function 0
3176be43703Skrw 				 * wired to INTA.
3186be43703Skrw 				 * Put all 5 GPIO bits in input mode and then
3196be43703Skrw 				 * read their input values.
3206be43703Skrw 				 */
3216be43703Skrw 				ADW_WRITE_BYTE_REGISTER(iot, ioh,
3226be43703Skrw 							IOPB_GPIO_CNTL, 0);
3236be43703Skrw 				if (ADW_READ_BYTE_REGISTER(iot, ioh,
3246be43703Skrw 						IOPB_GPIO_DATA) & 0x01) {
3256be43703Skrw 					/*
3266be43703Skrw 					 * Function 1 interrupt wired to INTA;
3276be43703Skrw 					 * Set EEPROM bit.
3286be43703Skrw 					 */
3296be43703Skrw 					lsw_msb |= (ADW_EEPROM_INTAB >> 8)
3306be43703Skrw 							 & 0xFF;
3316be43703Skrw 				 }
3326be43703Skrw 				 eep_config.cfg_lsw &= 0x00FF;
3336be43703Skrw 				 eep_config.cfg_lsw |= lsw_msb << 8;
3346be43703Skrw 			}
3356be43703Skrw 			break;
3366be43703Skrw 		}
3376be43703Skrw 
3386be43703Skrw 		/*
3396be43703Skrw 		 * Assume the 6 byte board serial number that was read
3406be43703Skrw 		 * from EEPROM is correct even if the EEPROM checksum
3416be43703Skrw 		 * failed.
3426be43703Skrw 		 */
3436be43703Skrw 		for (i=2, j=1; i>=0; i--, j++) {
3446be43703Skrw 		eep_config.serial_number[i] =
345a1d22770Skrw 			AdwReadEEPWord(iot, ioh, ADW_EEP_DVC_CFG_END - j);
3466be43703Skrw 		}
3476be43703Skrw 
3486be43703Skrw 		AdwSetEEPROMConfig(iot, ioh, &eep_config);
3496be43703Skrw 	}
3506be43703Skrw 	/*
3516be43703Skrw 	 * Set sc and sc->cfg variables from the EEPROM configuration
3526be43703Skrw 	 * that was read.
3536be43703Skrw 	 *
3546be43703Skrw 	 * This is the mapping of EEPROM fields to Adw Library fields.
3556be43703Skrw 	 */
3566be43703Skrw 	sc->wdtr_able = eep_config.wdtr_able;
3576be43703Skrw 	if (sc->chip_type == ADW_CHIP_ASC3550) {
3586be43703Skrw 		sc->sdtr_able = eep_config.sdtr1.sdtr_able;
3596be43703Skrw 		sc->ultra_able = eep_config.sdtr2.ultra_able;
3606be43703Skrw 	} else {
3616be43703Skrw 		sc->sdtr_speed1 = eep_config.sdtr1.sdtr_speed1;
3626be43703Skrw 		sc->sdtr_speed2 = eep_config.sdtr2.sdtr_speed2;
3636be43703Skrw 		sc->sdtr_speed3 = eep_config.sdtr3.sdtr_speed3;
3646be43703Skrw 		sc->sdtr_speed4 = eep_config.sdtr4.sdtr_speed4;
3656be43703Skrw 	}
3666be43703Skrw 	sc->ppr_able = 0;
3676be43703Skrw 	sc->tagqng_able = eep_config.tagqng_able;
3686be43703Skrw 	sc->cfg.disc_enable = eep_config.disc_enable;
3696be43703Skrw 	sc->max_host_qng = eep_config.max_host_qng;
3706be43703Skrw 	sc->max_dvc_qng = eep_config.max_dvc_qng;
3716be43703Skrw 	sc->chip_scsi_id = (eep_config.adapter_scsi_id & ADW_MAX_TID);
3726be43703Skrw 	sc->start_motor = eep_config.start_motor;
3736be43703Skrw 	sc->scsi_reset_wait = eep_config.scsi_reset_delay;
3746be43703Skrw 	sc->bios_ctrl = eep_config.bios_ctrl;
3756be43703Skrw 	sc->no_scam = eep_config.scam_tolerant;
3766be43703Skrw 	sc->cfg.serial1 = eep_config.serial_number[0];
3776be43703Skrw 	sc->cfg.serial2 = eep_config.serial_number[1];
3786be43703Skrw 	sc->cfg.serial3 = eep_config.serial_number[2];
3796be43703Skrw 
3806be43703Skrw 	if (sc->chip_type == ADW_CHIP_ASC38C0800 ||
3816be43703Skrw 	    sc->chip_type == ADW_CHIP_ASC38C1600) {
3826be43703Skrw 		sc->sdtr_able = 0;
3836be43703Skrw 		for (tid = 0; tid <= ADW_MAX_TID; tid++) {
3846be43703Skrw 			if (tid == 0) {
3856be43703Skrw 				sdtr_speed = sc->sdtr_speed1;
3866be43703Skrw 			} else if (tid == 4) {
3876be43703Skrw 				sdtr_speed = sc->sdtr_speed2;
3886be43703Skrw 			} else if (tid == 8) {
3896be43703Skrw 				sdtr_speed = sc->sdtr_speed3;
3906be43703Skrw 			} else if (tid == 12) {
3916be43703Skrw 				sdtr_speed = sc->sdtr_speed4;
3926be43703Skrw 			}
3936be43703Skrw 			if (sdtr_speed & ADW_MAX_TID) {
3946be43703Skrw 				sc->sdtr_able |= (1 << tid);
3956be43703Skrw 			}
3966be43703Skrw 			sdtr_speed >>= 4;
3976be43703Skrw 		}
3986be43703Skrw 	}
3996be43703Skrw 
4006be43703Skrw 	/*
4016be43703Skrw 	 * Set the host maximum queuing (max. 253, min. 16) and the per device
4026be43703Skrw 	 * maximum queuing (max. 63, min. 4).
4036be43703Skrw 	 */
4046be43703Skrw 	if (eep_config.max_host_qng > ADW_DEF_MAX_HOST_QNG) {
4056be43703Skrw 		eep_config.max_host_qng = ADW_DEF_MAX_HOST_QNG;
4066be43703Skrw 	} else if (eep_config.max_host_qng < ADW_DEF_MIN_HOST_QNG)
4076be43703Skrw 	{
4086be43703Skrw 		/* If the value is zero, assume it is uninitialized. */
4096be43703Skrw 		if (eep_config.max_host_qng == 0) {
4106be43703Skrw 			eep_config.max_host_qng = ADW_DEF_MAX_HOST_QNG;
4116be43703Skrw 		} else {
4126be43703Skrw 			eep_config.max_host_qng = ADW_DEF_MIN_HOST_QNG;
4136be43703Skrw 		}
4146be43703Skrw 	}
4156be43703Skrw 
4166be43703Skrw 	if (eep_config.max_dvc_qng > ADW_DEF_MAX_DVC_QNG) {
4176be43703Skrw 		eep_config.max_dvc_qng = ADW_DEF_MAX_DVC_QNG;
4186be43703Skrw 	} else if (eep_config.max_dvc_qng < ADW_DEF_MIN_DVC_QNG) {
4196be43703Skrw 		/* If the value is zero, assume it is uninitialized. */
4206be43703Skrw 		if (eep_config.max_dvc_qng == 0) {
4216be43703Skrw 			eep_config.max_dvc_qng = ADW_DEF_MAX_DVC_QNG;
4226be43703Skrw 		} else {
4236be43703Skrw 			eep_config.max_dvc_qng = ADW_DEF_MIN_DVC_QNG;
4246be43703Skrw 		}
4256be43703Skrw 	}
4266be43703Skrw 
4276be43703Skrw 	/*
4286be43703Skrw 	 * If 'max_dvc_qng' is greater than 'max_host_qng', then
4296be43703Skrw 	 * set 'max_dvc_qng' to 'max_host_qng'.
4306be43703Skrw 	 */
4316be43703Skrw 	if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
4326be43703Skrw 		eep_config.max_dvc_qng = eep_config.max_host_qng;
4336be43703Skrw 	}
4346be43703Skrw 
4356be43703Skrw 	/*
436a1d22770Skrw 	 * Set ADW_SOFTC 'max_host_qng' and 'max_dvc_qng'
4376be43703Skrw 	 * values based on possibly adjusted EEPROM values.
4386be43703Skrw 	 */
4396be43703Skrw 	sc->max_host_qng = eep_config.max_host_qng;
4406be43703Skrw 	sc->max_dvc_qng = eep_config.max_dvc_qng;
4416be43703Skrw 
4426be43703Skrw 
4436be43703Skrw 	/*
4446be43703Skrw 	 * If the EEPROM 'termination' field is set to automatic (0), then set
445a1d22770Skrw 	 * the ADW_SOFTC.cfg 'termination' field to automatic also.
4466be43703Skrw 	 *
4476be43703Skrw 	 * If the termination is specified with a non-zero 'termination'
448a1d22770Skrw 	 * value check that a legal value is set and set the ADW_SOFTC.cfg
4496be43703Skrw 	 * 'termination' field appropriately.
4506be43703Skrw 	 */
4516be43703Skrw 
4526be43703Skrw 	switch(sc->chip_type) {
4536be43703Skrw 	case ADW_CHIP_ASC3550:
4546be43703Skrw 		sc->cfg.termination = 0;	/* auto termination */
4556be43703Skrw 		switch(eep_config.termination_se) {
4566be43703Skrw 		case 3:
4576be43703Skrw 			/* Enable manual control with low on / high on. */
4586be43703Skrw 			sc->cfg.termination |= ADW_TERM_CTL_L;
4596be43703Skrw 		case 2:
4606be43703Skrw 			/* Enable manual control with low off / high on. */
4616be43703Skrw 			sc->cfg.termination |= ADW_TERM_CTL_H;
4626be43703Skrw 		case 1:
4636be43703Skrw 			/* Enable manual control with low off / high off. */
4646be43703Skrw 			sc->cfg.termination |= ADW_TERM_CTL_SEL;
4656be43703Skrw 		case 0:
4666be43703Skrw 			break;
4676be43703Skrw 		default:
4686be43703Skrw 			warn_code |= ADW_WARN_EEPROM_TERMINATION;
4696be43703Skrw 		}
4706be43703Skrw 		break;
4716be43703Skrw 
4726be43703Skrw 	case ADW_CHIP_ASC38C0800:
4736be43703Skrw 	case ADW_CHIP_ASC38C1600:
4746be43703Skrw 		switch(eep_config.termination_se) {
4756be43703Skrw 		case 0:
4766be43703Skrw 			/* auto termination for SE */
4776be43703Skrw 			termination = 0;
4786be43703Skrw 			break;
4796be43703Skrw 		case 1:
4806be43703Skrw 			/* Enable manual control with low off / high off. */
4816be43703Skrw 			termination = 0;
4826be43703Skrw 			break;
4836be43703Skrw 		case 2:
4846be43703Skrw 			/* Enable manual control with low off / high on. */
4856be43703Skrw 			termination = ADW_TERM_SE_HI;
4866be43703Skrw 			break;
4876be43703Skrw 		case 3:
4886be43703Skrw 			/* Enable manual control with low on / high on. */
4896be43703Skrw 			termination = ADW_TERM_SE;
4906be43703Skrw 			break;
4916be43703Skrw 		default:
4926be43703Skrw 			/*
4936be43703Skrw 			 * The EEPROM 'termination_se' field contains a
4946be43703Skrw 			 * bad value. Use automatic termination instead.
4956be43703Skrw 			 */
4966be43703Skrw 			termination = 0;
4976be43703Skrw 			warn_code |= ADW_WARN_EEPROM_TERMINATION;
4986be43703Skrw 		}
4996be43703Skrw 
5006be43703Skrw 		switch(eep_config.termination_lvd) {
5016be43703Skrw 		case 0:
5026be43703Skrw 			/* auto termination for LVD */
5036be43703Skrw 			sc->cfg.termination = termination;
5046be43703Skrw 			break;
5056be43703Skrw 		case 1:
5066be43703Skrw 			/* Enable manual control with low off / high off. */
5076be43703Skrw 			sc->cfg.termination = termination;
5086be43703Skrw 			break;
5096be43703Skrw 		case 2:
5106be43703Skrw 			/* Enable manual control with low off / high on. */
5116be43703Skrw 			sc->cfg.termination = termination | ADW_TERM_LVD_HI;
5126be43703Skrw 			break;
5136be43703Skrw 		case 3:
5146be43703Skrw 			/* Enable manual control with low on / high on. */
5156be43703Skrw 			sc->cfg.termination = termination | ADW_TERM_LVD;
5166be43703Skrw 			break;
5176be43703Skrw 		default:
5186be43703Skrw 			/*
5196be43703Skrw 			 * The EEPROM 'termination_lvd' field contains a
5206be43703Skrw 			 * bad value. Use automatic termination instead.
5216be43703Skrw 			 */
5226be43703Skrw 			sc->cfg.termination = termination;
5236be43703Skrw 			warn_code |= ADW_WARN_EEPROM_TERMINATION;
5246be43703Skrw 		}
5256be43703Skrw 		break;
5266be43703Skrw 	}
5276be43703Skrw 
5286be43703Skrw 	return warn_code;
5296be43703Skrw }
5306be43703Skrw 
5316be43703Skrw 
5326be43703Skrw /*
5336be43703Skrw  * Initialize the ASC-3550/ASC-38C0800/ASC-38C1600.
5346be43703Skrw  *
5356be43703Skrw  * On failure return the error code.
5366be43703Skrw  */
5376be43703Skrw int
5386be43703Skrw AdwInitDriver(sc)
5396be43703Skrw ADW_SOFTC      *sc;
5406be43703Skrw {
5416be43703Skrw 	bus_space_tag_t iot = sc->sc_iot;
5426be43703Skrw 	bus_space_handle_t ioh = sc->sc_ioh;
5436be43703Skrw 	u_int16_t	error_code;
5446be43703Skrw 	int		word;
5456be43703Skrw 	int		i;
5466be43703Skrw 	u_int16_t	bios_mem[ADW_MC_BIOSLEN/2];	/* BIOS RISC Memory
5476be43703Skrw 								0x40-0x8F. */
5486be43703Skrw 	u_int16_t	wdtr_able = 0, sdtr_able, ppr_able, tagqng_able;
5496be43703Skrw 	u_int8_t	max_cmd[ADW_MAX_TID + 1];
5506be43703Skrw 	u_int8_t	tid;
5516be43703Skrw 
5526be43703Skrw 
5536be43703Skrw 	error_code = 0;
5546be43703Skrw 
5556be43703Skrw 	/*
556379dd687Sdownsj 	 * Save the RISC memory BIOS region before writing the microcode.
557379dd687Sdownsj 	 * The BIOS may already be loaded and using its RISC LRAM region
558379dd687Sdownsj 	 * so its region must be saved and restored.
559379dd687Sdownsj 	 *
560379dd687Sdownsj 	 * Note: This code makes the assumption, which is currently true,
561379dd687Sdownsj 	 * that a chip reset does not clear RISC LRAM.
562379dd687Sdownsj 	 */
5636be43703Skrw 	for (i = 0; i < ADW_MC_BIOSLEN/2; i++) {
5646be43703Skrw 		ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_BIOSMEM+(2*i), bios_mem[i]);
565466e5dfaSderaadt 	}
566466e5dfaSderaadt 
567466e5dfaSderaadt 	/*
568466e5dfaSderaadt 	 * Save current per TID negotiated values.
569466e5dfaSderaadt 	 */
5706be43703Skrw 	switch (sc->chip_type) {
5716be43703Skrw 	case ADW_CHIP_ASC3550:
5726be43703Skrw 		if (bios_mem[(ADW_MC_BIOS_SIGNATURE-ADW_MC_BIOSMEM)/2]==0x55AA){
573466e5dfaSderaadt 
574466e5dfaSderaadt 			u_int16_t  bios_version, major, minor;
575466e5dfaSderaadt 
5766be43703Skrw 			bios_version = bios_mem[(ADW_MC_BIOS_VERSION -
5776be43703Skrw 					ADW_MC_BIOSMEM) / 2];
578466e5dfaSderaadt 			major = (bios_version  >> 12) & 0xF;
579466e5dfaSderaadt 			minor = (bios_version  >> 8) & 0xF;
580466e5dfaSderaadt 			if (major < 3 || (major == 3 && minor == 1)) {
5816be43703Skrw 			    /*
5826be43703Skrw 			     * BIOS 3.1 and earlier location of
5836be43703Skrw 			     * 'wdtr_able' variable.
5846be43703Skrw 			     */
585466e5dfaSderaadt 			    ADW_READ_WORD_LRAM(iot, ioh, 0x120, wdtr_able);
586466e5dfaSderaadt 			} else {
5876be43703Skrw 			    ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_WDTR_ABLE,
5886be43703Skrw 					    wdtr_able);
589466e5dfaSderaadt 			}
590466e5dfaSderaadt 		}
5916be43703Skrw 		break;
5926be43703Skrw 
5936be43703Skrw 	case ADW_CHIP_ASC38C1600:
5946be43703Skrw 		ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_PPR_ABLE, ppr_able);
5956be43703Skrw 		/* FALLTHROUGH */
5966be43703Skrw 	case ADW_CHIP_ASC38C0800:
5976be43703Skrw 		ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_WDTR_ABLE, wdtr_able);
5986be43703Skrw 		break;
5996be43703Skrw 	}
6006be43703Skrw 	ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_SDTR_ABLE, sdtr_able);
6016be43703Skrw 	ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_TAGQNG_ABLE, tagqng_able);
602466e5dfaSderaadt 	for (tid = 0; tid <= ADW_MAX_TID; tid++) {
6036be43703Skrw 		ADW_READ_BYTE_LRAM(iot, ioh, ADW_MC_NUMBER_OF_MAX_CMD + tid,
604466e5dfaSderaadt 			max_cmd[tid]);
605379dd687Sdownsj 	}
606379dd687Sdownsj 
607379dd687Sdownsj 	/*
6086be43703Skrw 	 * Perform a RAM Built-In Self Test
6096be43703Skrw 	 */
6106be43703Skrw 	if((error_code = AdwRamSelfTest(iot, ioh, sc->chip_type))) {
6116be43703Skrw 		return error_code;
6126be43703Skrw 	}
6136be43703Skrw 
6146be43703Skrw 	/*
615379dd687Sdownsj 	 * Load the Microcode
6166be43703Skrw 	 */
6176be43703Skrw 	;
6186be43703Skrw 	if((error_code = AdwLoadMCode(iot, ioh, bios_mem, sc->chip_type))) {
6196be43703Skrw 		return error_code;
6206be43703Skrw 	}
6216be43703Skrw 
6226be43703Skrw 	/*
6236be43703Skrw 	 * Read microcode version and date.
6246be43703Skrw 	 */
6256be43703Skrw 	ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_VERSION_DATE, sc->cfg.mcode_date);
6266be43703Skrw 	ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_VERSION_NUM, sc->cfg.mcode_version);
6276be43703Skrw 
6286be43703Skrw 	/*
6296be43703Skrw 	 * If the PCI Configuration Command Register "Parity Error Response
6306be43703Skrw 	 * Control" Bit was clear (0), then set the microcode variable
6316be43703Skrw 	 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
6326be43703Skrw 	 * to ignore DMA parity errors.
6336be43703Skrw 	 */
6346be43703Skrw 	if (sc->cfg.control_flag & CONTROL_FLAG_IGNORE_PERR) {
6356be43703Skrw 		ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_CONTROL_FLAG, word);
6366be43703Skrw 		ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_CONTROL_FLAG,
6376be43703Skrw 					word | CONTROL_FLAG_IGNORE_PERR);
6386be43703Skrw 	}
6396be43703Skrw 
6406be43703Skrw 	switch (sc->chip_type) {
6416be43703Skrw 	case ADW_CHIP_ASC3550:
6426be43703Skrw 		/*
6436be43703Skrw 		 * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a
6446be43703Skrw 		 * FIFO threshold of 128 bytes.
6456be43703Skrw 		 * This register is only accessible to the host.
6466be43703Skrw 		 */
6476be43703Skrw 		ADW_WRITE_BYTE_REGISTER(iot, ioh, IOPB_DMA_CFG0,
6486be43703Skrw 				START_CTL_EMFU | READ_CMD_MRM);
6496be43703Skrw 		break;
6506be43703Skrw 
6516be43703Skrw 	case ADW_CHIP_ASC38C0800:
6526be43703Skrw 		/*
6536be43703Skrw 		 * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
6546be43703Skrw 		 * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
6556be43703Skrw 		 * cable detection and then we are able to read C_DET[3:0].
656379dd687Sdownsj 		 *
6576be43703Skrw 		 * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
6586be43703Skrw 		 * Microcode Default Value' section below.
6596be43703Skrw 		 */
6606be43703Skrw 		ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_SCSI_CFG1,
6616be43703Skrw 				ADW_READ_WORD_REGISTER(iot, ioh, IOPW_SCSI_CFG1)
6626be43703Skrw 				| ADW_DIS_TERM_DRV);
6636be43703Skrw 
6646be43703Skrw 		/*
6656be43703Skrw 		 * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and
6666be43703Skrw 		 * START_CTL_TH [3:2] bits for the default FIFO threshold.
6676be43703Skrw 		 *
6686be43703Skrw 		 * Note: ASC-38C0800 FIFO threshold has been changed to
6696be43703Skrw 		 * 256 bytes.
6706be43703Skrw 		 *
6716be43703Skrw 		 * For DMA Errata #4 set the BC_THRESH_ENB bit.
6726be43703Skrw 		 */
6736be43703Skrw 		ADW_WRITE_BYTE_REGISTER(iot, ioh, IOPB_DMA_CFG0,
6746be43703Skrw 						BC_THRESH_ENB | FIFO_THRESH_80B
6756be43703Skrw 						| START_CTL_TH | READ_CMD_MRM);
6766be43703Skrw 		break;
6776be43703Skrw 
6786be43703Skrw 	case ADW_CHIP_ASC38C1600:
6796be43703Skrw 		/*
6806be43703Skrw 		 * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
6816be43703Skrw 		 * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
6826be43703Skrw 		 * cable detection and then we are able to read C_DET[3:0].
6836be43703Skrw 		 *
6846be43703Skrw 		 * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
6856be43703Skrw 		 * Microcode Default Value' section below.
6866be43703Skrw 		 */
6876be43703Skrw 		ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_SCSI_CFG1,
6886be43703Skrw 				ADW_READ_WORD_REGISTER(iot, ioh, IOPW_SCSI_CFG1)
6896be43703Skrw 				| ADW_DIS_TERM_DRV);
6906be43703Skrw 
6916be43703Skrw 		/*
6926be43703Skrw 		 * If the BIOS control flag AIPP (Asynchronous Information
6936be43703Skrw 		 * Phase Protection) disable bit is not set, then set the
6946be43703Skrw 		 * firmware 'control_flag' CONTROL_FLAG_ENABLE_AIPP bit to
6956be43703Skrw 		 * enable AIPP checking and encoding.
6966be43703Skrw 		 */
6976be43703Skrw 		if ((sc->bios_ctrl & BIOS_CTRL_AIPP_DIS) == 0) {
6986be43703Skrw 			ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_CONTROL_FLAG, word);
6996be43703Skrw 			ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_CONTROL_FLAG,
7006be43703Skrw 					word | CONTROL_FLAG_ENABLE_AIPP);
7016be43703Skrw 		}
7026be43703Skrw 
7036be43703Skrw 		/*
7046be43703Skrw 		 * For ASC-38C1600 use DMA_CFG0 default values:
7056be43703Skrw 		 * FIFO_THRESH_80B [6:4], and START_CTL_TH [3:2].
7066be43703Skrw 		 */
7076be43703Skrw 		ADW_WRITE_BYTE_REGISTER(iot, ioh, IOPB_DMA_CFG0,
7086be43703Skrw 				FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM);
7096be43703Skrw 		break;
7106be43703Skrw 	}
7116be43703Skrw 
7126be43703Skrw 	/*
7136be43703Skrw 	 * Microcode operating variables for WDTR, SDTR, and command tag
714a1d22770Skrw 	 * queuing will be set in AdwInquiryHandling() based on what a
7156be43703Skrw 	 * device reports it is capable of in Inquiry byte 7.
7166be43703Skrw 	 *
7176be43703Skrw 	 * If SCSI Bus Resets have been disabled, then directly set
7186be43703Skrw 	 * SDTR and WDTR from the EEPROM configuration. This will allow
7196be43703Skrw 	 * the BIOS and warm boot to work without a SCSI bus hang on
7206be43703Skrw 	 * the Inquiry caused by host and target mismatched DTR values.
7216be43703Skrw 	 * Without the SCSI Bus Reset, before an Inquiry a device can't
7226be43703Skrw 	 * be assumed to be in Asynchronous, Narrow mode.
7236be43703Skrw 	 */
7246be43703Skrw 	if ((sc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
7256be43703Skrw 		ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_WDTR_ABLE, sc->wdtr_able);
7266be43703Skrw 		ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_SDTR_ABLE, sc->sdtr_able);
7276be43703Skrw 	}
7286be43703Skrw 
7296be43703Skrw 	/*
7306be43703Skrw 	 * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2,
7316be43703Skrw 	 * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID
7326be43703Skrw 	 * bitmask. These values determine the maximum SDTR speed negotiated
7336be43703Skrw 	 * with a device.
7346be43703Skrw 	 *
7356be43703Skrw 	 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
7366be43703Skrw 	 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
7376be43703Skrw 	 * without determining here whether the device supports SDTR.
7386be43703Skrw 	 */
7396be43703Skrw 	switch (sc->chip_type) {
7406be43703Skrw 	case ADW_CHIP_ASC3550:
7416be43703Skrw 		word = 0;
7426be43703Skrw 		for (tid = 0; tid <= ADW_MAX_TID; tid++) {
7436be43703Skrw 			if (ADW_TID_TO_TIDMASK(tid) & sc->ultra_able) {
7446be43703Skrw 				/* Set Ultra speed for TID 'tid'. */
7456be43703Skrw 				word |= (0x3 << (4 * (tid % 4)));
7466be43703Skrw 			} else {
7476be43703Skrw 				/* Set Fast speed for TID 'tid'. */
7486be43703Skrw 				word |= (0x2 << (4 * (tid % 4)));
7496be43703Skrw 			}
7506be43703Skrw 			/* Check if done with sdtr_speed1. */
7516be43703Skrw 			if (tid == 3) {
7526be43703Skrw 				ADW_WRITE_WORD_LRAM(iot, ioh,
7536be43703Skrw 						ADW_MC_SDTR_SPEED1, word);
7546be43703Skrw 				word = 0;
7556be43703Skrw 			/* Check if done with sdtr_speed2. */
7566be43703Skrw 			} else if (tid == 7) {
7576be43703Skrw 				ADW_WRITE_WORD_LRAM(iot, ioh,
7586be43703Skrw 						ADW_MC_SDTR_SPEED2, word);
7596be43703Skrw 				word = 0;
7606be43703Skrw 			/* Check if done with sdtr_speed3. */
7616be43703Skrw 			} else if (tid == 11) {
7626be43703Skrw 				ADW_WRITE_WORD_LRAM(iot, ioh,
7636be43703Skrw 						ADW_MC_SDTR_SPEED3, word);
7646be43703Skrw 				word = 0;
7656be43703Skrw 			/* Check if done with sdtr_speed4. */
7666be43703Skrw 			} else if (tid == 15) {
7676be43703Skrw 				ADW_WRITE_WORD_LRAM(iot, ioh,
7686be43703Skrw 						ADW_MC_SDTR_SPEED4, word);
7696be43703Skrw 				/* End of loop. */
7706be43703Skrw 			}
7716be43703Skrw 		}
7726be43703Skrw 
7736be43703Skrw 		/*
7746be43703Skrw 		 * Set microcode operating variable for the
7756be43703Skrw 		 * disconnect per TID bitmask.
7766be43703Skrw 		 */
7776be43703Skrw 		ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_DISC_ENABLE,
7786be43703Skrw 							sc->cfg.disc_enable);
7796be43703Skrw 		break;
7806be43703Skrw 
7816be43703Skrw 	case ADW_CHIP_ASC38C0800:
7826be43703Skrw 		/* FALLTHROUGH */
7836be43703Skrw 	case ADW_CHIP_ASC38C1600:
7846be43703Skrw 		ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_DISC_ENABLE,
7856be43703Skrw 							sc->cfg.disc_enable);
7866be43703Skrw 		ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_SDTR_SPEED1,
7876be43703Skrw 							sc->sdtr_speed1);
7886be43703Skrw 		ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_SDTR_SPEED2,
7896be43703Skrw 							sc->sdtr_speed2);
7906be43703Skrw 		ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_SDTR_SPEED3,
7916be43703Skrw 							sc->sdtr_speed3);
7926be43703Skrw 		ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_SDTR_SPEED4,
7936be43703Skrw 							sc->sdtr_speed4);
7946be43703Skrw 		break;
7956be43703Skrw 	}
7966be43703Skrw 
7976be43703Skrw 
7986be43703Skrw 	/*
7996be43703Skrw 	 * Set SCSI_CFG0 Microcode Default Value.
8006be43703Skrw 	 *
8016be43703Skrw 	 * The microcode will set the SCSI_CFG0 register using this value
8026be43703Skrw 	 * after it is started below.
8036be43703Skrw 	 */
8046be43703Skrw 	ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_DEFAULT_SCSI_CFG0,
8056be43703Skrw 		ADW_PARITY_EN | ADW_QUEUE_128 | ADW_SEL_TMO_LONG |
8066be43703Skrw 		ADW_OUR_ID_EN | sc->chip_scsi_id);
8076be43703Skrw 
8086be43703Skrw 
8096be43703Skrw 	switch(sc->chip_type) {
8106be43703Skrw 	case ADW_CHIP_ASC3550:
8116be43703Skrw 		error_code = AdwASC3550Cabling(iot, ioh, &sc->cfg);
8126be43703Skrw 		break;
8136be43703Skrw 
8146be43703Skrw 	case ADW_CHIP_ASC38C0800:
8156be43703Skrw 		error_code = AdwASC38C0800Cabling(iot, ioh, &sc->cfg);
8166be43703Skrw 		break;
8176be43703Skrw 
8186be43703Skrw 	case ADW_CHIP_ASC38C1600:
8196be43703Skrw 		error_code = AdwASC38C1600Cabling(iot, ioh, &sc->cfg);
8206be43703Skrw 		break;
8216be43703Skrw 	}
8226be43703Skrw 	if(error_code) {
8236be43703Skrw 		return error_code;
8246be43703Skrw 	}
8256be43703Skrw 
8266be43703Skrw 	/*
8276be43703Skrw 	 * Set SEL_MASK Microcode Default Value
8286be43703Skrw 	 *
8296be43703Skrw 	 * The microcode will set the SEL_MASK register using this value
8306be43703Skrw 	 * after it is started below.
8316be43703Skrw 	 */
8326be43703Skrw 	ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_DEFAULT_SEL_MASK,
8336be43703Skrw 		ADW_TID_TO_TIDMASK(sc->chip_scsi_id));
8346be43703Skrw 
8356be43703Skrw 	/*
8366be43703Skrw 	 * Create and Initialize Host->RISC Carrier lists
8376be43703Skrw 	 */
8386be43703Skrw 	sc->carr_freelist = AdwInitCarriers(sc->sc_dmamap_carrier,
8396be43703Skrw 						sc->sc_control->carriers);
8406be43703Skrw 
8416be43703Skrw 	/*
8426be43703Skrw 	 * Set-up the Host->RISC Initiator Command Queue (ICQ).
8436be43703Skrw 	 */
8446be43703Skrw 
8456be43703Skrw 	if ((sc->icq_sp = sc->carr_freelist) == NULL) {
8466be43703Skrw 		return ADW_IERR_NO_CARRIER;
8476be43703Skrw 	}
8486be43703Skrw 	sc->carr_freelist = ADW_CARRIER_VADDR(sc,
849a1d22770Skrw 			ADW_GET_CARRP(sc->icq_sp->next_ba));
8506be43703Skrw 
8516be43703Skrw 	/*
8526be43703Skrw 	 * The first command issued will be placed in the stopper carrier.
8536be43703Skrw 	 */
854a1d22770Skrw 	sc->icq_sp->next_ba = ADW_CQ_STOPPER;
8556be43703Skrw 
8566be43703Skrw 	/*
8576be43703Skrw 	 * Set RISC ICQ physical address start value.
8586be43703Skrw 	 */
8596be43703Skrw 	ADW_WRITE_DWORD_LRAM(iot, ioh, ADW_MC_ICQ, sc->icq_sp->carr_ba);
8606be43703Skrw 
8616be43703Skrw 	/*
8626be43703Skrw 	 * Initialize the COMMA register to the same value otherwise
8636be43703Skrw 	 * the RISC will prematurely detect a command is available.
8646be43703Skrw 	 */
8656be43703Skrw 	if(sc->chip_type == ADW_CHIP_ASC38C1600) {
8666be43703Skrw 		ADW_WRITE_DWORD_REGISTER(iot, ioh, IOPDW_COMMA,
8676be43703Skrw 							sc->icq_sp->carr_ba);
8686be43703Skrw 	}
8696be43703Skrw 
8706be43703Skrw 	/*
8716be43703Skrw 	 * Set-up the RISC->Host Initiator Response Queue (IRQ).
8726be43703Skrw 	 */
8736be43703Skrw 	if ((sc->irq_sp = sc->carr_freelist) == NULL) {
8746be43703Skrw 		return ADW_IERR_NO_CARRIER;
8756be43703Skrw 	}
8766be43703Skrw 	sc->carr_freelist = ADW_CARRIER_VADDR(sc,
877a1d22770Skrw 			ADW_GET_CARRP(sc->irq_sp->next_ba));
8786be43703Skrw 
8796be43703Skrw 	/*
8806be43703Skrw 	 * The first command completed by the RISC will be placed in
8816be43703Skrw 	 * the stopper.
8826be43703Skrw 	 *
883a1d22770Skrw 	 * Note: Set 'next_ba' to ADW_CQ_STOPPER. When the request is
884a1d22770Skrw 	 * completed the RISC will set the ADW_RQ_DONE bit.
8856be43703Skrw 	 */
886a1d22770Skrw 	sc->irq_sp->next_ba = ADW_CQ_STOPPER;
8876be43703Skrw 
8886be43703Skrw 	/*
8896be43703Skrw 	 * Set RISC IRQ physical address start value.
8906be43703Skrw 	 */
8916be43703Skrw 	ADW_WRITE_DWORD_LRAM(iot, ioh, ADW_MC_IRQ, sc->irq_sp->carr_ba);
8926be43703Skrw 	sc->carr_pending_cnt = 0;
8936be43703Skrw 
8946be43703Skrw 	ADW_WRITE_BYTE_REGISTER(iot, ioh, IOPB_INTR_ENABLES,
8956be43703Skrw 		(ADW_INTR_ENABLE_HOST_INTR | ADW_INTR_ENABLE_GLOBAL_INTR));
8966be43703Skrw 	ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_CODE_BEGIN_ADDR, word);
8976be43703Skrw 	ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_PC, word);
8986be43703Skrw 
8996be43703Skrw 	/* finally, finally, gentlemen, start your engine */
9006be43703Skrw 	ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_RISC_CSR, ADW_RISC_CSR_RUN);
9016be43703Skrw 
9026be43703Skrw 	/*
9036be43703Skrw 	 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
9046be43703Skrw 	 * Resets should be performed. The RISC has to be running
9056be43703Skrw 	 * to issue a SCSI Bus Reset.
9066be43703Skrw 	 */
9076be43703Skrw 	if (sc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS)
9086be43703Skrw 	{
9096be43703Skrw 		/*
9106be43703Skrw 		 * If the BIOS Signature is present in memory, restore the
9116be43703Skrw 		 * BIOS Handshake Configuration Table and do not perform
9126be43703Skrw 		 * a SCSI Bus Reset.
9136be43703Skrw 		 */
9146be43703Skrw 		if (bios_mem[(ADW_MC_BIOS_SIGNATURE - ADW_MC_BIOSMEM)/2] ==
9156be43703Skrw 				0x55AA) {
9166be43703Skrw 			/*
9176be43703Skrw 			 * Restore per TID negotiated values.
9186be43703Skrw 			 */
9196be43703Skrw 			ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_WDTR_ABLE,
9206be43703Skrw 					wdtr_able);
9216be43703Skrw 			ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_SDTR_ABLE,
9226be43703Skrw 					sdtr_able);
9236be43703Skrw 			ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_TAGQNG_ABLE,
9246be43703Skrw 					tagqng_able);
9256be43703Skrw 			for (tid = 0; tid <= ADW_MAX_TID; tid++) {
9266be43703Skrw 				ADW_WRITE_BYTE_LRAM(iot, ioh,
9276be43703Skrw 						ADW_MC_NUMBER_OF_MAX_CMD + tid,
9286be43703Skrw 						max_cmd[tid]);
9296be43703Skrw 			}
9306be43703Skrw 		} else {
9316be43703Skrw 			if (AdwResetCCB(sc) != ADW_TRUE) {
9326be43703Skrw 				error_code = ADW_WARN_BUSRESET_ERROR;
9336be43703Skrw 			}
9346be43703Skrw 		}
9356be43703Skrw 	}
9366be43703Skrw 
9376be43703Skrw 	return error_code;
9386be43703Skrw }
9396be43703Skrw 
9406be43703Skrw 
9416be43703Skrw int
9426be43703Skrw AdwRamSelfTest(iot, ioh, chip_type)
9436be43703Skrw 	bus_space_tag_t iot;
9446be43703Skrw 	bus_space_handle_t ioh;
9456be43703Skrw 	u_int8_t chip_type;
9466be43703Skrw {
9476be43703Skrw 	int		i;
9486be43703Skrw 	u_int8_t	byte;
9496be43703Skrw 
9506be43703Skrw 
9516be43703Skrw 	if ((chip_type == ADW_CHIP_ASC38C0800) ||
9526be43703Skrw 	    (chip_type == ADW_CHIP_ASC38C1600)) {
9536be43703Skrw 		/*
9546be43703Skrw 		 * RAM BIST (RAM Built-In Self Test)
9556be43703Skrw 		 *
9566be43703Skrw 		 * Address : I/O base + offset 0x38h register (byte).
9576be43703Skrw 		 * Function: Bit 7-6(RW) : RAM mode
9586be43703Skrw 		 *			    Normal Mode   : 0x00
9596be43703Skrw 		 *			    Pre-test Mode : 0x40
9606be43703Skrw 		 *			    RAM Test Mode : 0x80
9616be43703Skrw 		 *	     Bit 5	 : unused
9626be43703Skrw 		 *	     Bit 4(RO)   : Done bit
9636be43703Skrw 		 *	     Bit 3-0(RO) : Status
9646be43703Skrw 		 *			    Host Error    : 0x08
9656be43703Skrw 		 *			    Int_RAM Error : 0x04
9666be43703Skrw 		 *			    RISC Error    : 0x02
9676be43703Skrw 		 *			    SCSI Error    : 0x01
9686be43703Skrw 		 *			    No Error	  : 0x00
9696be43703Skrw 		 *
9706be43703Skrw 		 * Note: RAM BIST code should be put right here, before loading
9716be43703Skrw 		 * the microcode and after saving the RISC memory BIOS region.
9726be43703Skrw 		 */
9736be43703Skrw 
9746be43703Skrw 		/*
9756be43703Skrw 		 * LRAM Pre-test
9766be43703Skrw 		 *
9776be43703Skrw 		 * Write PRE_TEST_MODE (0x40) to register and wait for
9786be43703Skrw 		 * 10 milliseconds.
9796be43703Skrw 		 * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05),
9806be43703Skrw 		 * return an error. Reset to NORMAL_MODE (0x00) and do again.
9816be43703Skrw 		 * If cannot reset to NORMAL_MODE, return an error too.
9826be43703Skrw 		 */
9836be43703Skrw 		for (i = 0; i < 2; i++) {
9846be43703Skrw 			ADW_WRITE_BYTE_REGISTER(iot, ioh, IOPB_RAM_BIST,
9856be43703Skrw 					PRE_TEST_MODE);
9866be43703Skrw 			 /* Wait for 10ms before reading back. */
9876be43703Skrw 			AdwSleepMilliSecond(10);
9886be43703Skrw 			byte = ADW_READ_BYTE_REGISTER(iot, ioh, IOPB_RAM_BIST);
9896be43703Skrw 			if ((byte & RAM_TEST_DONE) == 0 || (byte & 0x0F) !=
9906be43703Skrw 					PRE_TEST_VALUE) {
9916be43703Skrw 				return ADW_IERR_BIST_PRE_TEST;
9926be43703Skrw 			}
9936be43703Skrw 
9946be43703Skrw 			ADW_WRITE_BYTE_REGISTER(iot, ioh, IOPB_RAM_BIST,
9956be43703Skrw 								NORMAL_MODE);
9966be43703Skrw 			/* Wait for 10ms before reading back. */
9976be43703Skrw 			AdwSleepMilliSecond(10);
9986be43703Skrw 			if (ADW_READ_BYTE_REGISTER(iot, ioh, IOPB_RAM_BIST)
9996be43703Skrw 			    != NORMAL_VALUE) {
10006be43703Skrw 				return ADW_IERR_BIST_PRE_TEST;
10016be43703Skrw 			}
10026be43703Skrw 		}
10036be43703Skrw 
10046be43703Skrw 		/*
10056be43703Skrw 		 * LRAM Test - It takes about 1.5 ms to run through the test.
10066be43703Skrw 		 *
10076be43703Skrw 		 * Write RAM_TEST_MODE (0x80) to register and wait for
10086be43703Skrw 		 * 10 milliseconds.
10096be43703Skrw 		 * If Done bit not set or Status not 0, save register byte,
10106be43703Skrw 		 * set the err_code, and return an error.
10116be43703Skrw 		 */
10126be43703Skrw 		ADW_WRITE_BYTE_REGISTER(iot, ioh, IOPB_RAM_BIST, RAM_TEST_MODE);
10136be43703Skrw 		/* Wait for 10ms before checking status. */
10146be43703Skrw 		AdwSleepMilliSecond(10);
10156be43703Skrw 
10166be43703Skrw 		byte = ADW_READ_BYTE_REGISTER(iot, ioh, IOPB_RAM_BIST);
10176be43703Skrw 		if ((byte & RAM_TEST_DONE)==0 || (byte & RAM_TEST_STATUS)!=0) {
10186be43703Skrw 			/* Get here if Done bit not set or Status not 0. */
10196be43703Skrw 			return ADW_IERR_BIST_RAM_TEST;
10206be43703Skrw 		}
10216be43703Skrw 
10226be43703Skrw 		/* We need to reset back to normal mode after LRAM test passes*/
10236be43703Skrw 		ADW_WRITE_BYTE_REGISTER(iot, ioh, IOPB_RAM_BIST, NORMAL_MODE);
10246be43703Skrw 	}
10256be43703Skrw 
10266be43703Skrw 	return 0;
10276be43703Skrw }
10286be43703Skrw 
10296be43703Skrw 
10306be43703Skrw int
10316be43703Skrw AdwLoadMCode(iot, ioh, bios_mem, chip_type)
10326be43703Skrw 	bus_space_tag_t iot;
10336be43703Skrw 	bus_space_handle_t ioh;
10346be43703Skrw 	u_int16_t *bios_mem;
10356be43703Skrw 	u_int8_t chip_type;
10366be43703Skrw {
10376be43703Skrw 	u_int8_t	*mcode_data;
10386be43703Skrw 	u_int32_t	 mcode_chksum;
10396be43703Skrw 	u_int16_t	 mcode_size;
10406be43703Skrw 	u_int32_t	sum;
10416be43703Skrw 	u_int16_t	code_sum;
10426be43703Skrw 	int		begin_addr;
10436be43703Skrw 	int		end_addr;
10446be43703Skrw 	int		word;
10456be43703Skrw 	int		adw_memsize;
10466be43703Skrw 	int		adw_mcode_expanded_size;
10476be43703Skrw 	int		i, j;
10486be43703Skrw 
10496be43703Skrw 
10506be43703Skrw 	switch(chip_type) {
10516be43703Skrw 	case ADW_CHIP_ASC3550:
10526be43703Skrw 		mcode_data = (u_int8_t *)adw_asc3550_mcode_data.mcode_data;
10536be43703Skrw 		mcode_chksum = (u_int32_t)adw_asc3550_mcode_data.mcode_chksum;
10546be43703Skrw 		mcode_size = (u_int16_t)adw_asc3550_mcode_data.mcode_size;
10556be43703Skrw 		adw_memsize = ADW_3550_MEMSIZE;
10566be43703Skrw 		break;
10576be43703Skrw 
10586be43703Skrw 	case ADW_CHIP_ASC38C0800:
10596be43703Skrw 		mcode_data = (u_int8_t *)adw_asc38C0800_mcode_data.mcode_data;
10606be43703Skrw 		mcode_chksum =(u_int32_t)adw_asc38C0800_mcode_data.mcode_chksum;
10616be43703Skrw 		mcode_size = (u_int16_t)adw_asc38C0800_mcode_data.mcode_size;
10626be43703Skrw 		adw_memsize = ADW_38C0800_MEMSIZE;
10636be43703Skrw 		break;
10646be43703Skrw 
10656be43703Skrw 	case ADW_CHIP_ASC38C1600:
10666be43703Skrw 		mcode_data = (u_int8_t *)adw_asc38C1600_mcode_data.mcode_data;
10676be43703Skrw 		mcode_chksum =(u_int32_t)adw_asc38C1600_mcode_data.mcode_chksum;
10686be43703Skrw 		mcode_size = (u_int16_t)adw_asc38C1600_mcode_data.mcode_size;
10696be43703Skrw 		adw_memsize = ADW_38C1600_MEMSIZE;
10706be43703Skrw 		break;
10716be43703Skrw 	}
10726be43703Skrw 
10736be43703Skrw 	/*
1074379dd687Sdownsj 	 * Write the microcode image to RISC memory starting at address 0.
1075379dd687Sdownsj 	 */
1076379dd687Sdownsj 	ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_RAM_ADDR, 0);
1077466e5dfaSderaadt 
1078466e5dfaSderaadt 	/* Assume the following compressed format of the microcode buffer:
1079466e5dfaSderaadt 	 *
1080466e5dfaSderaadt 	 *  254 word (508 byte) table indexed by byte code followed
1081466e5dfaSderaadt 	 *  by the following byte codes:
1082466e5dfaSderaadt 	 *
1083466e5dfaSderaadt 	 *    1-Byte Code:
1084466e5dfaSderaadt 	 *	00: Emit word 0 in table.
1085466e5dfaSderaadt 	 *	01: Emit word 1 in table.
1086466e5dfaSderaadt 	 *	.
1087466e5dfaSderaadt 	 *	FD: Emit word 253 in table.
1088466e5dfaSderaadt 	 *
1089466e5dfaSderaadt 	 *    Multi-Byte Code:
1090466e5dfaSderaadt 	 *	FE WW WW: (3 byte code) Word to emit is the next word WW WW.
1091466e5dfaSderaadt 	 *	FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
1092466e5dfaSderaadt 	 */
1093466e5dfaSderaadt 	word = 0;
10946be43703Skrw 	for (i = 253 * 2; i < mcode_size; i++) {
10956be43703Skrw 		if (mcode_data[i] == 0xff) {
10966be43703Skrw 			for (j = 0; j < mcode_data[i + 1]; j++) {
1097379dd687Sdownsj 				ADW_WRITE_WORD_AUTO_INC_LRAM(iot, ioh,
10986be43703Skrw 				  (((u_int16_t)mcode_data[i + 3] << 8) |
10996be43703Skrw 				  mcode_data[i + 2]));
1100466e5dfaSderaadt 				word++;
1101466e5dfaSderaadt 			}
1102466e5dfaSderaadt 			i += 3;
11036be43703Skrw 		} else if (mcode_data[i] == 0xfe) {
1104466e5dfaSderaadt 			ADW_WRITE_WORD_AUTO_INC_LRAM(iot, ioh,
11056be43703Skrw 			    (((u_int16_t)mcode_data[i + 2] << 8) |
11066be43703Skrw 			    mcode_data[i + 1]));
1107466e5dfaSderaadt 			i += 2;
1108466e5dfaSderaadt 			word++;
1109466e5dfaSderaadt 		} else {
1110466e5dfaSderaadt 			ADW_WRITE_WORD_AUTO_INC_LRAM(iot, ioh, (((u_int16_t)
11116be43703Skrw 			 mcode_data[(mcode_data[i] * 2) + 1] <<8) |
11126be43703Skrw 			 mcode_data[mcode_data[i] * 2]));
1113466e5dfaSderaadt 			word++;
1114466e5dfaSderaadt 		}
1115379dd687Sdownsj 	}
1116379dd687Sdownsj 
1117379dd687Sdownsj 	/*
1118466e5dfaSderaadt 	 * Set 'word' for later use to clear the rest of memory and save
1119466e5dfaSderaadt 	 * the expanded mcode size.
1120379dd687Sdownsj 	 */
1121466e5dfaSderaadt 	word *= 2;
11226be43703Skrw 	adw_mcode_expanded_size = word;
1123466e5dfaSderaadt 
1124466e5dfaSderaadt 	/*
11256be43703Skrw 	 * Clear the rest of the Internal RAM.
1126466e5dfaSderaadt 	 */
11276be43703Skrw 	for (; word < adw_memsize; word += 2) {
1128379dd687Sdownsj 		ADW_WRITE_WORD_AUTO_INC_LRAM(iot, ioh, 0);
1129379dd687Sdownsj 	}
1130379dd687Sdownsj 
1131379dd687Sdownsj 	/*
1132379dd687Sdownsj 	 * Verify the microcode checksum.
1133379dd687Sdownsj 	 */
1134379dd687Sdownsj 	sum = 0;
1135379dd687Sdownsj 	ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_RAM_ADDR, 0);
1136466e5dfaSderaadt 
11376be43703Skrw 	for (word = 0; word < adw_mcode_expanded_size; word += 2) {
1138379dd687Sdownsj 		sum += ADW_READ_WORD_AUTO_INC_LRAM(iot, ioh);
1139379dd687Sdownsj 	}
1140379dd687Sdownsj 
11416be43703Skrw 	if (sum != mcode_chksum) {
11426be43703Skrw 		return ADW_IERR_MCODE_CHKSUM;
1143466e5dfaSderaadt 	}
1144379dd687Sdownsj 
1145379dd687Sdownsj 	/*
1146379dd687Sdownsj 	 * Restore the RISC memory BIOS region.
1147379dd687Sdownsj 	 */
11486be43703Skrw 	for (i = 0; i < ADW_MC_BIOSLEN/2; i++) {
11496be43703Skrw 		if(chip_type == ADW_CHIP_ASC3550) {
11506be43703Skrw 			ADW_WRITE_BYTE_LRAM(iot, ioh, ADW_MC_BIOSMEM + (2 * i),
1151466e5dfaSderaadt 								bios_mem[i]);
11526be43703Skrw 		} else {
11536be43703Skrw 			ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_BIOSMEM + (2 * i),
11546be43703Skrw 								bios_mem[i]);
11556be43703Skrw 		}
1156379dd687Sdownsj 	}
1157379dd687Sdownsj 
1158379dd687Sdownsj 	/*
1159379dd687Sdownsj 	 * Calculate and write the microcode code checksum to the microcode
11606be43703Skrw 	 * code checksum location ADW_MC_CODE_CHK_SUM (0x2C).
1161379dd687Sdownsj 	 */
11626be43703Skrw 	ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_CODE_BEGIN_ADDR, begin_addr);
11636be43703Skrw 	ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_CODE_END_ADDR, end_addr);
1164379dd687Sdownsj 	code_sum = 0;
1165466e5dfaSderaadt 	ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_RAM_ADDR, begin_addr);
1166379dd687Sdownsj 	for (word = begin_addr; word < end_addr; word += 2) {
1167466e5dfaSderaadt 		code_sum += ADW_READ_WORD_AUTO_INC_LRAM(iot, ioh);
1168379dd687Sdownsj 	}
11696be43703Skrw 	ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_CODE_CHK_SUM, code_sum);
1170379dd687Sdownsj 
1171379dd687Sdownsj 	/*
11726be43703Skrw 	 * Set the chip type.
1173379dd687Sdownsj 	 */
11746be43703Skrw 	ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_CHIP_TYPE, chip_type);
1175379dd687Sdownsj 
11766be43703Skrw 	return 0;
1177379dd687Sdownsj }
1178379dd687Sdownsj 
1179466e5dfaSderaadt 
11806be43703Skrw int
11816be43703Skrw AdwASC3550Cabling(iot, ioh, cfg)
11826be43703Skrw 	bus_space_tag_t iot;
11836be43703Skrw 	bus_space_handle_t ioh;
11846be43703Skrw 	ADW_DVC_CFG *cfg;
11856be43703Skrw {
11866be43703Skrw 	u_int16_t	scsi_cfg1;
1187466e5dfaSderaadt 
1188379dd687Sdownsj 
1189379dd687Sdownsj 	/*
1190379dd687Sdownsj 	 * Determine SCSI_CFG1 Microcode Default Value.
1191379dd687Sdownsj 	 *
1192379dd687Sdownsj 	 * The microcode will set the SCSI_CFG1 register using this value
1193379dd687Sdownsj 	 * after it is started below.
1194379dd687Sdownsj 	 */
1195379dd687Sdownsj 
1196379dd687Sdownsj 	/* Read current SCSI_CFG1 Register value. */
1197379dd687Sdownsj 	scsi_cfg1 = ADW_READ_WORD_REGISTER(iot, ioh, IOPW_SCSI_CFG1);
1198379dd687Sdownsj 
1199379dd687Sdownsj 	/*
12006be43703Skrw 	 * If all three connectors are in use in ASC3550, return an error.
1201379dd687Sdownsj 	 */
1202379dd687Sdownsj 	if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 ||
1203379dd687Sdownsj 	     (scsi_cfg1 & CABLE_ILLEGAL_B) == 0) {
12046be43703Skrw 		return ADW_IERR_ILLEGAL_CONNECTION;
1205379dd687Sdownsj 	}
1206466e5dfaSderaadt 
1207379dd687Sdownsj 	/*
12086be43703Skrw 	 * If the cable is reversed all of the SCSI_CTRL register signals
12096be43703Skrw 	 * will be set. Check for and return an error if this condition is
12106be43703Skrw 	 * found.
1211379dd687Sdownsj 	 */
12126be43703Skrw 	if ((ADW_READ_WORD_REGISTER(iot,ioh, IOPW_SCSI_CTRL) & 0x3F07)==0x3F07){
12136be43703Skrw 		return ADW_IERR_REVERSED_CABLE;
1214379dd687Sdownsj 	}
1215379dd687Sdownsj 
1216379dd687Sdownsj 	/*
1217379dd687Sdownsj 	 * If this is a differential board and a single-ended device
1218379dd687Sdownsj 	 * is attached to one of the connectors, return an error.
1219379dd687Sdownsj 	 */
12206be43703Skrw 	if ((scsi_cfg1 & ADW_DIFF_MODE) &&
12216be43703Skrw 	    (scsi_cfg1 & ADW_DIFF_SENSE) == 0) {
12226be43703Skrw 		return ADW_IERR_SINGLE_END_DEVICE;
1223466e5dfaSderaadt 	}
1224379dd687Sdownsj 
1225379dd687Sdownsj 	/*
1226379dd687Sdownsj 	 * If automatic termination control is enabled, then set the
1227466e5dfaSderaadt 	 * termination value based on a table listed in a_condor.h.
1228379dd687Sdownsj 	 *
1229379dd687Sdownsj 	 * If manual termination was specified with an EEPROM setting
12306be43703Skrw 	 * then 'termination' was set-up in AdwInitFromEEPROM() and
1231379dd687Sdownsj 	 * is ready to be 'ored' into SCSI_CFG1.
1232379dd687Sdownsj 	 */
12336be43703Skrw 	if (cfg->termination == 0) {
1234379dd687Sdownsj 		/*
12356be43703Skrw 		 * The software always controls termination by setting
12366be43703Skrw 		 * TERM_CTL_SEL.
12376be43703Skrw 		 * If TERM_CTL_SEL were set to 0, the hardware would set
12386be43703Skrw 		 * termination.
1239379dd687Sdownsj 		 */
12406be43703Skrw 		cfg->termination |= ADW_TERM_CTL_SEL;
1241379dd687Sdownsj 
1242379dd687Sdownsj 		switch(scsi_cfg1 & ADW_CABLE_DETECT) {
1243466e5dfaSderaadt 			/* TERM_CTL_H: on, TERM_CTL_L: on */
12446be43703Skrw 			case 0x3: case 0x7: case 0xB:
12456be43703Skrw 			case 0xD: case 0xE: case 0xF:
12466be43703Skrw 				cfg->termination |=
12476be43703Skrw 				(ADW_TERM_CTL_H | ADW_TERM_CTL_L);
1248379dd687Sdownsj 				break;
1249379dd687Sdownsj 
1250466e5dfaSderaadt 			/* TERM_CTL_H: on, TERM_CTL_L: off */
12516be43703Skrw 			case 0x1: case 0x5: case 0x9:
12526be43703Skrw 			case 0xA: case 0xC:
12536be43703Skrw 				cfg->termination |= ADW_TERM_CTL_H;
1254379dd687Sdownsj 				break;
1255379dd687Sdownsj 
1256466e5dfaSderaadt 			/* TERM_CTL_H: off, TERM_CTL_L: off */
1257466e5dfaSderaadt 			case 0x2: case 0x6:
1258379dd687Sdownsj 				break;
1259379dd687Sdownsj 		}
1260379dd687Sdownsj 	}
1261466e5dfaSderaadt 
1262379dd687Sdownsj 	/*
1263466e5dfaSderaadt 	 * Clear any set TERM_CTL_H and TERM_CTL_L bits.
1264379dd687Sdownsj 	 */
1265379dd687Sdownsj 	scsi_cfg1 &= ~ADW_TERM_CTL;
1266379dd687Sdownsj 
1267379dd687Sdownsj 	/*
1268466e5dfaSderaadt 	 * Invert the TERM_CTL_H and TERM_CTL_L bits and then
1269466e5dfaSderaadt 	 * set 'scsi_cfg1'. The TERM_POL bit does not need to be
1270379dd687Sdownsj 	 * referenced, because the hardware internally inverts
1271466e5dfaSderaadt 	 * the Termination High and Low bits if TERM_POL is set.
1272379dd687Sdownsj 	 */
12736be43703Skrw 	scsi_cfg1 |= (ADW_TERM_CTL_SEL | (~cfg->termination & ADW_TERM_CTL));
1274379dd687Sdownsj 
1275379dd687Sdownsj 	/*
1276379dd687Sdownsj 	 * Set SCSI_CFG1 Microcode Default Value
1277379dd687Sdownsj 	 *
1278379dd687Sdownsj 	 * Set filter value and possibly modified termination control
1279379dd687Sdownsj 	 * bits in the Microcode SCSI_CFG1 Register Value.
1280379dd687Sdownsj 	 *
1281379dd687Sdownsj 	 * The microcode will set the SCSI_CFG1 register using this value
1282379dd687Sdownsj 	 * after it is started below.
1283379dd687Sdownsj 	 */
12846be43703Skrw 	ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_DEFAULT_SCSI_CFG1,
1285466e5dfaSderaadt 						ADW_FLTR_DISABLE | scsi_cfg1);
1286466e5dfaSderaadt 
1287466e5dfaSderaadt 	/*
1288466e5dfaSderaadt 	 * Set MEM_CFG Microcode Default Value
1289466e5dfaSderaadt 	 *
1290466e5dfaSderaadt 	 * The microcode will set the MEM_CFG register using this value
1291466e5dfaSderaadt 	 * after it is started below.
1292466e5dfaSderaadt 	 *
1293466e5dfaSderaadt 	 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
1294466e5dfaSderaadt 	 * are defined.
1295466e5dfaSderaadt 	 *
1296466e5dfaSderaadt 	 * ASC-3550 has 8KB internal memory.
1297466e5dfaSderaadt 	 */
12986be43703Skrw 	ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_DEFAULT_MEM_CFG,
1299466e5dfaSderaadt 						ADW_BIOS_EN | ADW_RAM_SZ_8KB);
1300379dd687Sdownsj 
13016be43703Skrw 	return 0;
1302dfb9bd9fSkrw }
1303466e5dfaSderaadt 
1304466e5dfaSderaadt 
1305466e5dfaSderaadt int
13066be43703Skrw AdwASC38C0800Cabling(iot, ioh, cfg)
13076be43703Skrw 	bus_space_tag_t iot;
13086be43703Skrw 	bus_space_handle_t ioh;
13096be43703Skrw 	ADW_DVC_CFG *cfg;
1310466e5dfaSderaadt {
1311466e5dfaSderaadt 	u_int16_t	scsi_cfg1;
1312466e5dfaSderaadt 
1313466e5dfaSderaadt 
1314466e5dfaSderaadt 	/*
1315466e5dfaSderaadt 	 * Determine SCSI_CFG1 Microcode Default Value.
1316466e5dfaSderaadt 	 *
1317466e5dfaSderaadt 	 * The microcode will set the SCSI_CFG1 register using this value
1318466e5dfaSderaadt 	 * after it is started below.
1319466e5dfaSderaadt 	 */
1320466e5dfaSderaadt 
1321466e5dfaSderaadt 	/* Read current SCSI_CFG1 Register value. */
1322466e5dfaSderaadt 	scsi_cfg1 = ADW_READ_WORD_REGISTER(iot, ioh, IOPW_SCSI_CFG1);
1323466e5dfaSderaadt 
1324466e5dfaSderaadt 	/*
13256be43703Skrw 	 * If the cable is reversed all of the SCSI_CTRL register signals
13266be43703Skrw 	 * will be set. Check for and return an error if this condition is
13276be43703Skrw 	 * found.
1328466e5dfaSderaadt 	 */
13296be43703Skrw 	if ((ADW_READ_WORD_REGISTER(iot,ioh, IOPW_SCSI_CTRL) & 0x3F07)==0x3F07){
13306be43703Skrw 		return ADW_IERR_REVERSED_CABLE;
1331466e5dfaSderaadt 	}
1332466e5dfaSderaadt 
1333466e5dfaSderaadt 	/*
13346be43703Skrw 	 * All kind of combinations of devices attached to one of four
13356be43703Skrw 	 * connectors are acceptable except HVD device attached.
13366be43703Skrw 	 * For example, LVD device can be attached to SE connector while
13376be43703Skrw 	 * SE device attached to LVD connector.
13386be43703Skrw 	 * If LVD device attached to SE connector, it only runs up to
13396be43703Skrw 	 * Ultra speed.
1340466e5dfaSderaadt 	 *
13416be43703Skrw 	 * If an HVD device is attached to one of LVD connectors, return
13426be43703Skrw 	 * an error.
13436be43703Skrw 	 * However, there is no way to detect HVD device attached to
13446be43703Skrw 	 * SE connectors.
1345466e5dfaSderaadt 	 */
1346466e5dfaSderaadt 	if (scsi_cfg1 & ADW_HVD) {
13476be43703Skrw 		return ADW_IERR_HVD_DEVICE;
1348466e5dfaSderaadt 	}
1349466e5dfaSderaadt 
1350466e5dfaSderaadt 	/*
1351466e5dfaSderaadt 	 * If either SE or LVD automatic termination control is enabled, then
1352466e5dfaSderaadt 	 * set the termination value based on a table listed in a_condor.h.
1353466e5dfaSderaadt 	 *
1354466e5dfaSderaadt 	 * If manual termination was specified with an EEPROM setting then
13556be43703Skrw 	 * 'termination' was set-up in AdwInitFromEEPROM() and is ready
13566be43703Skrw 	 * to be 'ored' into SCSI_CFG1.
1357466e5dfaSderaadt 	 */
13586be43703Skrw 	if ((cfg->termination & ADW_TERM_SE) == 0) {
1359466e5dfaSderaadt 		/* SE automatic termination control is enabled. */
1360466e5dfaSderaadt 		switch(scsi_cfg1 & ADW_C_DET_SE) {
1361466e5dfaSderaadt 			/* TERM_SE_HI: on, TERM_SE_LO: on */
1362466e5dfaSderaadt 			case 0x1: case 0x2: case 0x3:
13636be43703Skrw 				cfg->termination |= ADW_TERM_SE;
1364466e5dfaSderaadt 				break;
1365466e5dfaSderaadt 
1366466e5dfaSderaadt 			/* TERM_SE_HI: on, TERM_SE_LO: off */
1367466e5dfaSderaadt 			case 0x0:
13686be43703Skrw 				cfg->termination |= ADW_TERM_SE_HI;
1369466e5dfaSderaadt 				break;
1370466e5dfaSderaadt 		}
1371466e5dfaSderaadt 	}
1372466e5dfaSderaadt 
13736be43703Skrw 	if ((cfg->termination & ADW_TERM_LVD) == 0) {
1374466e5dfaSderaadt 		/* LVD automatic termination control is enabled. */
1375466e5dfaSderaadt 		switch(scsi_cfg1 & ADW_C_DET_LVD) {
1376466e5dfaSderaadt 			/* TERM_LVD_HI: on, TERM_LVD_LO: on */
1377466e5dfaSderaadt 			case 0x4: case 0x8: case 0xC:
13786be43703Skrw 				cfg->termination |= ADW_TERM_LVD;
1379466e5dfaSderaadt 				break;
1380466e5dfaSderaadt 
1381466e5dfaSderaadt 			/* TERM_LVD_HI: off, TERM_LVD_LO: off */
1382466e5dfaSderaadt 			case 0x0:
1383466e5dfaSderaadt 				break;
1384466e5dfaSderaadt 		}
1385466e5dfaSderaadt 	}
1386466e5dfaSderaadt 
1387466e5dfaSderaadt 	/*
1388466e5dfaSderaadt 	 * Clear any set TERM_SE and TERM_LVD bits.
1389466e5dfaSderaadt 	 */
1390466e5dfaSderaadt 	scsi_cfg1 &= (~ADW_TERM_SE & ~ADW_TERM_LVD);
1391466e5dfaSderaadt 
1392466e5dfaSderaadt 	/*
1393466e5dfaSderaadt 	 * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'.
1394466e5dfaSderaadt 	 */
13956be43703Skrw 	scsi_cfg1 |= (~cfg->termination & 0xF0);
1396466e5dfaSderaadt 
1397466e5dfaSderaadt 	/*
13986be43703Skrw 	 * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and
13996be43703Skrw 	 * HVD/LVD/SE bits and set possibly modified termination control bits
14006be43703Skrw 	 * in the Microcode SCSI_CFG1 Register Value.
1401466e5dfaSderaadt 	 */
1402466e5dfaSderaadt 	scsi_cfg1 &= (~ADW_BIG_ENDIAN & ~ADW_DIS_TERM_DRV &
1403466e5dfaSderaadt 					~ADW_TERM_POL & ~ADW_HVD_LVD_SE);
1404466e5dfaSderaadt 
1405466e5dfaSderaadt 	/*
1406466e5dfaSderaadt 	 * Set SCSI_CFG1 Microcode Default Value
1407466e5dfaSderaadt 	 *
1408466e5dfaSderaadt 	 * Set possibly modified termination control and reset DIS_TERM_DRV
1409466e5dfaSderaadt 	 * bits in the Microcode SCSI_CFG1 Register Value.
1410466e5dfaSderaadt 	 *
1411466e5dfaSderaadt 	 * The microcode will set the SCSI_CFG1 register using this value
1412466e5dfaSderaadt 	 * after it is started below.
1413466e5dfaSderaadt 	 */
14146be43703Skrw 	ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
1415466e5dfaSderaadt 
1416466e5dfaSderaadt 	/*
1417466e5dfaSderaadt 	 * Set MEM_CFG Microcode Default Value
1418466e5dfaSderaadt 	 *
1419466e5dfaSderaadt 	 * The microcode will set the MEM_CFG register using this value
1420466e5dfaSderaadt 	 * after it is started below.
1421466e5dfaSderaadt 	 *
1422466e5dfaSderaadt 	 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
1423466e5dfaSderaadt 	 * are defined.
1424466e5dfaSderaadt 	 *
1425466e5dfaSderaadt 	 * ASC-38C0800 has 16KB internal memory.
1426466e5dfaSderaadt 	 */
14276be43703Skrw 	ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_DEFAULT_MEM_CFG,
1428466e5dfaSderaadt 						ADW_BIOS_EN | ADW_RAM_SZ_16KB);
1429466e5dfaSderaadt 
14306be43703Skrw 	return 0;
14316be43703Skrw }
14326be43703Skrw 
14336be43703Skrw 
14346be43703Skrw int
14356be43703Skrw AdwASC38C1600Cabling(iot, ioh, cfg)
14366be43703Skrw 	bus_space_tag_t iot;
14376be43703Skrw 	bus_space_handle_t ioh;
14386be43703Skrw 	ADW_DVC_CFG *cfg;
14396be43703Skrw {
14406be43703Skrw 	u_int16_t	scsi_cfg1;
14416be43703Skrw 
14426be43703Skrw 
1443466e5dfaSderaadt 	/*
14446be43703Skrw 	 * Determine SCSI_CFG1 Microcode Default Value.
1445466e5dfaSderaadt 	 *
14466be43703Skrw 	 * The microcode will set the SCSI_CFG1 register using this value
14476be43703Skrw 	 * after it is started below.
14486be43703Skrw 	 * Each ASC-38C1600 function has only two cable detect bits.
14496be43703Skrw 	 * The bus mode override bits are in IOPB_SOFT_OVER_WR.
14506be43703Skrw 	 */
14516be43703Skrw 
14526be43703Skrw 	/* Read current SCSI_CFG1 Register value. */
14536be43703Skrw 	scsi_cfg1 = ADW_READ_WORD_REGISTER(iot, ioh, IOPW_SCSI_CFG1);
14546be43703Skrw 
14556be43703Skrw 	/*
14566be43703Skrw 	 * If the cable is reversed all of the SCSI_CTRL register signals
14576be43703Skrw 	 * will be set. Check for and return an error if this condition is
14586be43703Skrw 	 * found.
14596be43703Skrw 	 */
14606be43703Skrw 	if ((ADW_READ_WORD_REGISTER(iot,ioh, IOPW_SCSI_CTRL) & 0x3F07)==0x3F07){
14616be43703Skrw 		return ADW_IERR_REVERSED_CABLE;
14626be43703Skrw 	}
14636be43703Skrw 
14646be43703Skrw 	/*
14656be43703Skrw 	 * Each ASC-38C1600 function has two connectors. Only an HVD device
14666be43703Skrw 	 * can not be connected to either connector. An LVD device or SE device
14676be43703Skrw 	 * may be connected to either connecor. If an SE device is connected,
14686be43703Skrw 	 * then at most Ultra speed (20 Mhz) can be used on both connectors.
14696be43703Skrw 	 *
14706be43703Skrw 	 * If an HVD device is attached, return an error.
14716be43703Skrw 	 */
14726be43703Skrw 	if (scsi_cfg1 & ADW_HVD) {
14736be43703Skrw 		return ADW_IERR_HVD_DEVICE;
14746be43703Skrw 	}
14756be43703Skrw 
14766be43703Skrw 	/*
14776be43703Skrw 	 * Each function in the ASC-38C1600 uses only the SE cable detect and
14786be43703Skrw 	 * termination because there are two connectors for each function.
14796be43703Skrw 	 * Each function may use either LVD or SE mode.
14806be43703Skrw 	 * Corresponding the SE automatic termination control EEPROM bits are
14816be43703Skrw 	 * used for each function.
14826be43703Skrw 	 * Each function has its own EEPROM. If SE automatic control is enabled
14836be43703Skrw 	 * for the function, then set the termination value based on a table
14846be43703Skrw 	 * listed in adwlib.h.
14856be43703Skrw 	 *
14866be43703Skrw 	 * If manual termination is specified in the EEPROM for the function,
14876be43703Skrw 	 * then 'termination' was set-up in AdwInitFromEEPROM() and is
14886be43703Skrw 	 * ready to be 'ored' into SCSI_CFG1.
14896be43703Skrw 	 */
14906be43703Skrw 	if ((cfg->termination & ADW_TERM_SE) == 0) {
14916be43703Skrw 		/* SE automatic termination control is enabled. */
14926be43703Skrw 		switch(scsi_cfg1 & ADW_C_DET_SE) {
14936be43703Skrw 			/* TERM_SE_HI: on, TERM_SE_LO: on */
14946be43703Skrw 			case 0x1: case 0x2: case 0x3:
14956be43703Skrw 				cfg->termination |= ADW_TERM_SE;
14966be43703Skrw 				break;
14976be43703Skrw 
14986be43703Skrw 			case 0x0:
14996be43703Skrw 	/* !!!!TODO!!!! */
15006be43703Skrw //				if (ASC_PCI_ID2FUNC(cfg->pci_slot_info) == 0) {
15016be43703Skrw 				/* Function 0 - TERM_SE_HI: off, TERM_SE_LO: off */
15026be43703Skrw //				}
15036be43703Skrw //				else
15046be43703Skrw //				{
15056be43703Skrw 				/* Function 1 - TERM_SE_HI: on, TERM_SE_LO: off */
15066be43703Skrw 					cfg->termination |= ADW_TERM_SE_HI;
15076be43703Skrw //				}
15086be43703Skrw 				break;
15096be43703Skrw 			}
15106be43703Skrw 	}
15116be43703Skrw 
15126be43703Skrw 	/*
15136be43703Skrw 	 * Clear any set TERM_SE bits.
15146be43703Skrw 	 */
15156be43703Skrw 	scsi_cfg1 &= ~ADW_TERM_SE;
15166be43703Skrw 
15176be43703Skrw 	/*
15186be43703Skrw 	 * Invert the TERM_SE bits and then set 'scsi_cfg1'.
15196be43703Skrw 	 */
15206be43703Skrw 	scsi_cfg1 |= (~cfg->termination & ADW_TERM_SE);
15216be43703Skrw 
15226be43703Skrw 	/*
15236be43703Skrw 	 * Clear Big Endian and Terminator Polarity bits and set possibly
15246be43703Skrw 	 * modified termination control bits in the Microcode SCSI_CFG1
15256be43703Skrw 	 * Register Value.
15266be43703Skrw 	 */
15276be43703Skrw 	scsi_cfg1 &= (~ADW_BIG_ENDIAN & ~ADW_DIS_TERM_DRV & ~ADW_TERM_POL);
15286be43703Skrw 
15296be43703Skrw 	/*
15306be43703Skrw 	 * Set SCSI_CFG1 Microcode Default Value
15316be43703Skrw 	 *
15326be43703Skrw 	 * Set possibly modified termination control bits in the Microcode
15336be43703Skrw 	 * SCSI_CFG1 Register Value.
15346be43703Skrw 	 *
15356be43703Skrw 	 * The microcode will set the SCSI_CFG1 register using this value
1536466e5dfaSderaadt 	 * after it is started below.
1537466e5dfaSderaadt 	 */
15386be43703Skrw 	ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
1539466e5dfaSderaadt 
1540466e5dfaSderaadt 	/*
15416be43703Skrw 	 * Set MEM_CFG Microcode Default Value
1542466e5dfaSderaadt 	 *
15436be43703Skrw 	 * The microcode will set the MEM_CFG register using this value
15446be43703Skrw 	 * after it is started below.
1545379dd687Sdownsj 	 *
15466be43703Skrw 	 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
15476be43703Skrw 	 * are defined.
1548379dd687Sdownsj 	 *
15496be43703Skrw 	 * ASC-38C1600 has 32KB internal memory.
1550379dd687Sdownsj 	 */
15516be43703Skrw 	ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_DEFAULT_MEM_CFG,
15526be43703Skrw 						ADW_BIOS_EN | ADW_RAM_SZ_32KB);
1553379dd687Sdownsj 
15546be43703Skrw 	return 0;
1555466e5dfaSderaadt }
1556466e5dfaSderaadt 
1557466e5dfaSderaadt 
1558379dd687Sdownsj /*
1559379dd687Sdownsj  * Read EEPROM configuration into the specified buffer.
1560379dd687Sdownsj  *
1561379dd687Sdownsj  * Return a checksum based on the EEPROM configuration read.
1562379dd687Sdownsj  */
1563379dd687Sdownsj static u_int16_t
15646be43703Skrw AdwGetEEPROMConfig(iot, ioh, cfg_buf)
1565379dd687Sdownsj 	bus_space_tag_t		iot;
1566379dd687Sdownsj 	bus_space_handle_t	ioh;
15676be43703Skrw 	ADW_EEPROM		*cfg_buf;
1568379dd687Sdownsj {
1569379dd687Sdownsj 	u_int16_t	       wval, chksum;
1570379dd687Sdownsj 	u_int16_t	       *wbuf;
1571379dd687Sdownsj 	int		    eep_addr;
1572379dd687Sdownsj 
1573466e5dfaSderaadt 
1574379dd687Sdownsj 	wbuf = (u_int16_t *) cfg_buf;
1575379dd687Sdownsj 	chksum = 0;
1576379dd687Sdownsj 
1577a1d22770Skrw 	for (eep_addr = ADW_EEP_DVC_CFG_BEGIN;
1578a1d22770Skrw 		eep_addr < ADW_EEP_DVC_CFG_END;
1579379dd687Sdownsj 		eep_addr++, wbuf++) {
15806be43703Skrw 		wval = AdwReadEEPWord(iot, ioh, eep_addr);
1581379dd687Sdownsj 		chksum += wval;
1582379dd687Sdownsj 		*wbuf = wval;
1583379dd687Sdownsj 	}
1584466e5dfaSderaadt 
15856be43703Skrw 	*wbuf = AdwReadEEPWord(iot, ioh, eep_addr);
1586379dd687Sdownsj 	wbuf++;
1587a1d22770Skrw 	for (eep_addr = ADW_EEP_DVC_CTL_BEGIN;
1588a1d22770Skrw 			eep_addr < ADW_EEP_MAX_WORD_ADDR;
1589379dd687Sdownsj 			eep_addr++, wbuf++) {
15906be43703Skrw 		*wbuf = AdwReadEEPWord(iot, ioh, eep_addr);
1591466e5dfaSderaadt 	}
1592466e5dfaSderaadt 
1593466e5dfaSderaadt 	return chksum;
1594466e5dfaSderaadt }
1595466e5dfaSderaadt 
1596466e5dfaSderaadt 
1597379dd687Sdownsj /*
1598379dd687Sdownsj  * Read the EEPROM from specified location
1599379dd687Sdownsj  */
1600379dd687Sdownsj static u_int16_t
16016be43703Skrw AdwReadEEPWord(iot, ioh, eep_word_addr)
1602379dd687Sdownsj 	bus_space_tag_t		iot;
1603379dd687Sdownsj 	bus_space_handle_t	ioh;
1604379dd687Sdownsj 	int			eep_word_addr;
1605379dd687Sdownsj {
1606379dd687Sdownsj 	ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_EE_CMD,
1607a1d22770Skrw 		ADW_EEP_CMD_READ | eep_word_addr);
16086be43703Skrw 	AdwWaitEEPCmd(iot, ioh);
1609466e5dfaSderaadt 
1610379dd687Sdownsj 	return ADW_READ_WORD_REGISTER(iot, ioh, IOPW_EE_DATA);
1611379dd687Sdownsj }
1612379dd687Sdownsj 
1613466e5dfaSderaadt 
1614379dd687Sdownsj /*
1615379dd687Sdownsj  * Wait for EEPROM command to complete
1616379dd687Sdownsj  */
1617379dd687Sdownsj static void
16186be43703Skrw AdwWaitEEPCmd(iot, ioh)
1619379dd687Sdownsj 	bus_space_tag_t		iot;
1620379dd687Sdownsj 	bus_space_handle_t	ioh;
1621379dd687Sdownsj {
1622466e5dfaSderaadt 	int eep_delay_ms;
1623379dd687Sdownsj 
1624466e5dfaSderaadt 
1625a1d22770Skrw 	for (eep_delay_ms = 0; eep_delay_ms < ADW_EEP_DELAY_MS; eep_delay_ms++){
1626379dd687Sdownsj 		if (ADW_READ_WORD_REGISTER(iot, ioh, IOPW_EE_CMD) &
1627a1d22770Skrw 				ADW_EEP_CMD_DONE) {
1628379dd687Sdownsj 			break;
1629379dd687Sdownsj 		}
16306be43703Skrw 		AdwSleepMilliSecond(1);
1631379dd687Sdownsj 	}
1632379dd687Sdownsj 
1633466e5dfaSderaadt 	ADW_READ_WORD_REGISTER(iot, ioh, IOPW_EE_CMD);
1634379dd687Sdownsj }
1635379dd687Sdownsj 
1636466e5dfaSderaadt 
1637379dd687Sdownsj /*
1638379dd687Sdownsj  * Write the EEPROM from 'cfg_buf'.
1639379dd687Sdownsj  */
1640379dd687Sdownsj static void
16416be43703Skrw AdwSetEEPROMConfig(iot, ioh, cfg_buf)
1642379dd687Sdownsj 	bus_space_tag_t		iot;
1643379dd687Sdownsj 	bus_space_handle_t	ioh;
16446be43703Skrw 	ADW_EEPROM		*cfg_buf;
1645379dd687Sdownsj {
1646379dd687Sdownsj 	u_int16_t *wbuf;
1647379dd687Sdownsj 	u_int16_t addr, chksum;
1648379dd687Sdownsj 
1649466e5dfaSderaadt 
1650379dd687Sdownsj 	wbuf = (u_int16_t *) cfg_buf;
1651379dd687Sdownsj 	chksum = 0;
1652379dd687Sdownsj 
1653a1d22770Skrw 	ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_EE_CMD, ADW_EEP_CMD_WRITE_ABLE);
16546be43703Skrw 	AdwWaitEEPCmd(iot, ioh);
1655379dd687Sdownsj 
1656379dd687Sdownsj 	/*
1657466e5dfaSderaadt 	 * Write EEPROM from word 0 to word 20
1658379dd687Sdownsj 	 */
1659a1d22770Skrw 	for (addr = ADW_EEP_DVC_CFG_BEGIN;
1660a1d22770Skrw 	     addr < ADW_EEP_DVC_CFG_END; addr++, wbuf++) {
1661379dd687Sdownsj 		chksum += *wbuf;
1662379dd687Sdownsj 		ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_EE_DATA, *wbuf);
1663466e5dfaSderaadt 		ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_EE_CMD,
1664a1d22770Skrw 				ADW_EEP_CMD_WRITE | addr);
16656be43703Skrw 		AdwWaitEEPCmd(iot, ioh);
1666a1d22770Skrw 		AdwSleepMilliSecond(ADW_EEP_DELAY_MS);
1667379dd687Sdownsj 	}
1668379dd687Sdownsj 
1669379dd687Sdownsj 	/*
1670466e5dfaSderaadt 	 * Write EEPROM checksum at word 21
1671379dd687Sdownsj 	 */
1672379dd687Sdownsj 	ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_EE_DATA, chksum);
1673379dd687Sdownsj 	ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_EE_CMD,
1674a1d22770Skrw 			ADW_EEP_CMD_WRITE | addr);
16756be43703Skrw 	AdwWaitEEPCmd(iot, ioh);
1676379dd687Sdownsj 	wbuf++;        /* skip over check_sum */
1677379dd687Sdownsj 
1678379dd687Sdownsj 	/*
1679466e5dfaSderaadt 	 * Write EEPROM OEM name at words 22 to 29
1680379dd687Sdownsj 	 */
1681a1d22770Skrw 	for (addr = ADW_EEP_DVC_CTL_BEGIN;
1682a1d22770Skrw 	     addr < ADW_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
1683379dd687Sdownsj 		ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_EE_DATA, *wbuf);
1684466e5dfaSderaadt 		ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_EE_CMD,
1685a1d22770Skrw 				ADW_EEP_CMD_WRITE | addr);
16866be43703Skrw 		AdwWaitEEPCmd(iot, ioh);
1687379dd687Sdownsj 	}
1688466e5dfaSderaadt 
1689379dd687Sdownsj 	ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_EE_CMD,
1690a1d22770Skrw 			ADW_EEP_CMD_WRITE_DISABLE);
16916be43703Skrw 	AdwWaitEEPCmd(iot, ioh);
1692466e5dfaSderaadt 
1693379dd687Sdownsj 	return;
1694379dd687Sdownsj }
1695379dd687Sdownsj 
1696466e5dfaSderaadt 
1697379dd687Sdownsj /*
16986be43703Skrw  * AdwExeScsiQueue() - Send a request to the RISC microcode program.
1699379dd687Sdownsj  *
1700466e5dfaSderaadt  *   Allocate a carrier structure, point the carrier to the ADW_SCSI_REQ_Q,
1701466e5dfaSderaadt  *   add the carrier to the ICQ (Initiator Command Queue), and tickle the
1702466e5dfaSderaadt  *   RISC to notify it a new command is ready to be executed.
1703379dd687Sdownsj  *
1704466e5dfaSderaadt  * If 'done_status' is not set to QD_DO_RETRY, then 'error_retry' will be
1705466e5dfaSderaadt  * set to SCSI_MAX_RETRY.
1706379dd687Sdownsj  *
1707379dd687Sdownsj  * Return:
1708466e5dfaSderaadt  *      ADW_SUCCESS(1) - The request was successfully queued.
1709466e5dfaSderaadt  *      ADW_BUSY(0) -    Resource unavailable; Retry again after pending
1710466e5dfaSderaadt  *                       request completes.
1711466e5dfaSderaadt  *      ADW_ERROR(-1) -  Invalid ADW_SCSI_REQ_Q request structure
1712466e5dfaSderaadt  *                       host IC error.
1713379dd687Sdownsj  */
1714379dd687Sdownsj int
17156be43703Skrw AdwExeScsiQueue(sc, scsiq)
1716379dd687Sdownsj ADW_SOFTC	*sc;
1717379dd687Sdownsj ADW_SCSI_REQ_Q	*scsiq;
1718379dd687Sdownsj {
1719466e5dfaSderaadt 	bus_space_tag_t iot = sc->sc_iot;
1720466e5dfaSderaadt 	bus_space_handle_t ioh = sc->sc_ioh;
1721466e5dfaSderaadt 	ADW_CCB		*ccb;
1722466e5dfaSderaadt 	long		req_size;
1723466e5dfaSderaadt 	u_int32_t	req_paddr;
17246be43703Skrw 	ADW_CARRIER	*new_carrp;
1725466e5dfaSderaadt 
1726466e5dfaSderaadt 	/*
1727466e5dfaSderaadt 	 * The ADW_SCSI_REQ_Q 'target_id' field should never exceed ADW_MAX_TID.
1728466e5dfaSderaadt 	 */
1729466e5dfaSderaadt 	if (scsiq->target_id > ADW_MAX_TID) {
1730466e5dfaSderaadt 		scsiq->host_status = QHSTA_M_INVALID_DEVICE;
1731466e5dfaSderaadt 		scsiq->done_status = QD_WITH_ERROR;
1732466e5dfaSderaadt 		return ADW_ERROR;
1733379dd687Sdownsj 	}
1734379dd687Sdownsj 
17356be43703Skrw 	/*
1736a1d22770Skrw 	 * Beginning of CRITICAL SECTION: ASSUME splbio() in effect
17376be43703Skrw 	 */
17386be43703Skrw 
1739466e5dfaSderaadt 	ccb = adw_ccb_phys_kv(sc, scsiq->ccb_ptr);
1740466e5dfaSderaadt 
1741466e5dfaSderaadt 	/*
17426be43703Skrw 	 * Allocate a carrier and initialize fields.
1743466e5dfaSderaadt 	 */
17446be43703Skrw 	if ((new_carrp = sc->carr_freelist) == NULL) {
1745466e5dfaSderaadt 		return ADW_BUSY;
1746466e5dfaSderaadt 	}
17476be43703Skrw 	sc->carr_freelist = ADW_CARRIER_VADDR(sc,
1748a1d22770Skrw 			ADW_GET_CARRP(new_carrp->next_ba));
1749466e5dfaSderaadt 	sc->carr_pending_cnt++;
1750466e5dfaSderaadt 
1751466e5dfaSderaadt 	/*
17526be43703Skrw 	 * Set the carrier to be a stopper by setting 'next_ba'
1753466e5dfaSderaadt 	 * to the stopper value. The current stopper will be changed
1754466e5dfaSderaadt 	 * below to point to the new stopper.
1755466e5dfaSderaadt 	 */
1756a1d22770Skrw 	new_carrp->next_ba = ADW_CQ_STOPPER;
1757466e5dfaSderaadt 
1758466e5dfaSderaadt 	req_size = sizeof(ADW_SCSI_REQ_Q);
1759466e5dfaSderaadt 	req_paddr = sc->sc_dmamap_control->dm_segs[0].ds_addr +
1760466e5dfaSderaadt 		ADW_CCB_OFF(ccb) + offsetof(struct adw_ccb, scsiq);
1761466e5dfaSderaadt 
1762466e5dfaSderaadt 	/* Save physical address of ADW_SCSI_REQ_Q and Carrier. */
1763466e5dfaSderaadt 	scsiq->scsiq_rptr = req_paddr;
1764466e5dfaSderaadt 
1765466e5dfaSderaadt 	/*
1766a1d22770Skrw 	 * Every ADW_SCSI_REQ_Q.carr_ba is byte swapped to little-endian
1767466e5dfaSderaadt 	 * order during initialization.
1768466e5dfaSderaadt 	 */
17696be43703Skrw 	scsiq->carr_ba = sc->icq_sp->carr_ba;
17706be43703Skrw 	scsiq->carr_va = sc->icq_sp->carr_ba;
1771466e5dfaSderaadt 
1772466e5dfaSderaadt 	/*
1773466e5dfaSderaadt 	 * Use the current stopper to send the ADW_SCSI_REQ_Q command to
1774466e5dfaSderaadt 	 * the microcode. The newly allocated stopper will become the new
1775466e5dfaSderaadt 	 * stopper.
1776466e5dfaSderaadt 	 */
17776be43703Skrw 	sc->icq_sp->areq_ba = req_paddr;
1778466e5dfaSderaadt 
1779466e5dfaSderaadt 	/*
17806be43703Skrw 	 * Set the 'next_ba' pointer for the old stopper to be the
1781466e5dfaSderaadt 	 * physical address of the new stopper. The RISC can only
1782466e5dfaSderaadt 	 * follow physical addresses.
1783466e5dfaSderaadt 	 */
17846be43703Skrw 	sc->icq_sp->next_ba = new_carrp->carr_ba;
1785466e5dfaSderaadt 
17866be43703Skrw #if ADW_DEBUG
17876be43703Skrw 	printf("icq 0x%x, 0x%x, 0x%x, 0x%x\n",
17886be43703Skrw 			sc->icq_sp->carr_id,
17896be43703Skrw 			sc->icq_sp->carr_ba,
17906be43703Skrw 			sc->icq_sp->areq_ba,
17916be43703Skrw 			sc->icq_sp->next_ba);
17926be43703Skrw #endif
1793466e5dfaSderaadt 	/*
1794466e5dfaSderaadt 	 * Set the host adapter stopper pointer to point to the new carrier.
1795466e5dfaSderaadt 	 */
1796466e5dfaSderaadt 	sc->icq_sp = new_carrp;
1797466e5dfaSderaadt 
17986be43703Skrw 	if (sc->chip_type == ADW_CHIP_ASC3550 ||
17996be43703Skrw 	    sc->chip_type == ADW_CHIP_ASC38C0800) {
1800466e5dfaSderaadt 		/*
18016be43703Skrw 		 * Tickle the RISC to tell it to read its Command Queue Head
18026be43703Skrw 		 * pointer.
1803466e5dfaSderaadt 		 */
18043976a5edSkrw 		ADW_WRITE_BYTE_REGISTER(iot, ioh, IOPB_TICKLE, ADW_TICKLE_A);
18056be43703Skrw 		if (sc->chip_type == ADW_CHIP_ASC3550) {
1806466e5dfaSderaadt 			/*
1807466e5dfaSderaadt 			 * Clear the tickle value. In the ASC-3550 the RISC flag
1808466e5dfaSderaadt 			 * command 'clr_tickle_a' does not work unless the host
1809466e5dfaSderaadt 			 * value is cleared.
1810466e5dfaSderaadt 			 */
18116be43703Skrw 			ADW_WRITE_BYTE_REGISTER(iot, ioh, IOPB_TICKLE,
18123976a5edSkrw 					ADW_TICKLE_NOP);
1813466e5dfaSderaadt 		}
18146be43703Skrw 	} else if (sc->chip_type == ADW_CHIP_ASC38C1600) {
18156be43703Skrw 		/*
18166be43703Skrw 		 * Notify the RISC a carrier is ready by writing the physical
18176be43703Skrw 		 * address of the new carrier stopper to the COMMA register.
18186be43703Skrw 		 */
18196be43703Skrw 		ADW_WRITE_DWORD_REGISTER(iot, ioh, IOPDW_COMMA,
18206be43703Skrw 				new_carrp->carr_ba);
18216be43703Skrw 	}
18226be43703Skrw 
18236be43703Skrw 	/*
18246be43703Skrw 	 * End of CRITICAL SECTION: Must be protected within splbio/splx pair
18256be43703Skrw 	 */
1826466e5dfaSderaadt 
1827466e5dfaSderaadt 	return ADW_SUCCESS;
1828466e5dfaSderaadt }
1829466e5dfaSderaadt 
1830466e5dfaSderaadt 
1831466e5dfaSderaadt void
18326be43703Skrw AdwResetChip(iot, ioh)
1833466e5dfaSderaadt 	bus_space_tag_t iot;
1834466e5dfaSderaadt 	bus_space_handle_t ioh;
1835466e5dfaSderaadt {
1836466e5dfaSderaadt 
1837466e5dfaSderaadt 	/*
1838466e5dfaSderaadt 	 * Reset Chip.
1839466e5dfaSderaadt 	 */
1840466e5dfaSderaadt 	ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_CTRL_REG,
1841466e5dfaSderaadt 			ADW_CTRL_REG_CMD_RESET);
18426be43703Skrw 	AdwSleepMilliSecond(100);
1843466e5dfaSderaadt 	ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_CTRL_REG,
1844466e5dfaSderaadt 			ADW_CTRL_REG_CMD_WR_IO_REG);
1845466e5dfaSderaadt }
1846466e5dfaSderaadt 
1847466e5dfaSderaadt 
1848379dd687Sdownsj /*
1849379dd687Sdownsj  * Reset SCSI Bus and purge all outstanding requests.
1850379dd687Sdownsj  *
1851379dd687Sdownsj  * Return Value:
1852379dd687Sdownsj  *      ADW_TRUE(1) -   All requests are purged and SCSI Bus is reset.
1853466e5dfaSderaadt  *      ADW_FALSE(0) -  Microcode command failed.
1854466e5dfaSderaadt  *      ADW_ERROR(-1) - Microcode command timed-out. Microcode or IC
1855466e5dfaSderaadt  *                      may be hung which requires driver recovery.
1856379dd687Sdownsj  */
1857379dd687Sdownsj int
18586be43703Skrw AdwResetCCB(sc)
1859379dd687Sdownsj ADW_SOFTC	*sc;
1860379dd687Sdownsj {
1861379dd687Sdownsj 	int	    status;
1862379dd687Sdownsj 
1863466e5dfaSderaadt 	/*
1864466e5dfaSderaadt 	 * Send the SCSI Bus Reset idle start idle command which asserts
1865466e5dfaSderaadt 	 * the SCSI Bus Reset signal.
1866466e5dfaSderaadt 	 */
18676be43703Skrw 	status = AdwSendIdleCmd(sc, (u_int16_t) IDLE_CMD_SCSI_RESET_START, 0L);
18686be43703Skrw 	if (status != ADW_TRUE) {
1869379dd687Sdownsj 		return status;
1870379dd687Sdownsj 	}
1871379dd687Sdownsj 
1872379dd687Sdownsj 	/*
1873466e5dfaSderaadt 	 * Delay for the specified SCSI Bus Reset hold time.
1874466e5dfaSderaadt 	 *
1875466e5dfaSderaadt 	 * The hold time delay is done on the host because the RISC has no
1876466e5dfaSderaadt 	 * microsecond accurate timer.
1877379dd687Sdownsj 	 */
1878a1d22770Skrw 	AdwDelayMicroSecond((u_int16_t) ADW_SCSI_RESET_HOLD_TIME_US);
1879466e5dfaSderaadt 
1880466e5dfaSderaadt 	/*
1881466e5dfaSderaadt 	 * Send the SCSI Bus Reset end idle command which de-asserts
1882466e5dfaSderaadt 	 * the SCSI Bus Reset signal and purges any pending requests.
1883466e5dfaSderaadt 	 */
18846be43703Skrw 	status = AdwSendIdleCmd(sc, (u_int16_t) IDLE_CMD_SCSI_RESET_END, 0L);
18856be43703Skrw 	if (status != ADW_TRUE) {
1886466e5dfaSderaadt 		return status;
1887466e5dfaSderaadt 	}
1888466e5dfaSderaadt 
18896be43703Skrw 	AdwSleepMilliSecond((u_int32_t) sc->scsi_reset_wait * 1000);
1890466e5dfaSderaadt 
1891466e5dfaSderaadt 	return status;
1892466e5dfaSderaadt }
1893466e5dfaSderaadt 
1894466e5dfaSderaadt 
1895466e5dfaSderaadt /*
1896466e5dfaSderaadt  * Reset chip and SCSI Bus.
1897466e5dfaSderaadt  *
1898466e5dfaSderaadt  * Return Value:
1899466e5dfaSderaadt  *      ADW_TRUE(1) -   Chip re-initialization and SCSI Bus Reset successful.
1900466e5dfaSderaadt  *      ADW_FALSE(0) -  Chip re-initialization and SCSI Bus Reset failure.
1901466e5dfaSderaadt  */
1902466e5dfaSderaadt int
19036be43703Skrw AdwResetSCSIBus(sc)
1904379dd687Sdownsj ADW_SOFTC	*sc;
1905379dd687Sdownsj {
1906379dd687Sdownsj 	bus_space_tag_t iot = sc->sc_iot;
1907379dd687Sdownsj 	bus_space_handle_t ioh = sc->sc_ioh;
1908466e5dfaSderaadt 	int		status;
19096be43703Skrw 	u_int16_t	wdtr_able, sdtr_able, ppr_able, tagqng_able;
1910466e5dfaSderaadt 	u_int8_t	tid, max_cmd[ADW_MAX_TID + 1];
1911466e5dfaSderaadt 	u_int16_t	bios_sig;
1912379dd687Sdownsj 
1913379dd687Sdownsj 
1914379dd687Sdownsj 	/*
1915466e5dfaSderaadt 	 * Save current per TID negotiated values.
1916379dd687Sdownsj 	 */
19176be43703Skrw 	ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_WDTR_ABLE, wdtr_able);
19186be43703Skrw 	ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_SDTR_ABLE, sdtr_able);
19196be43703Skrw 	if (sc->chip_type == ADW_CHIP_ASC38C1600) {
19206be43703Skrw 		ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_PPR_ABLE, ppr_able);
19216be43703Skrw 	}
19226be43703Skrw 	ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_TAGQNG_ABLE, tagqng_able);
19236be43703Skrw 	for (tid = 0; tid <= ADW_MAX_TID; tid++) {
19246be43703Skrw 		ADW_READ_BYTE_LRAM(iot, ioh, ADW_MC_NUMBER_OF_MAX_CMD + tid,
1925466e5dfaSderaadt 			max_cmd[tid]);
1926466e5dfaSderaadt 	}
1927379dd687Sdownsj 
1928466e5dfaSderaadt 	/*
19296be43703Skrw 	 * Force the AdwInitAscDriver() function to perform a SCSI Bus Reset
19306be43703Skrw 	 * by clearing the BIOS signature word.
1931466e5dfaSderaadt 	 * The initialization functions assumes a SCSI Bus Reset is not
1932466e5dfaSderaadt 	 * needed if the BIOS signature word is present.
1933466e5dfaSderaadt 	 */
19346be43703Skrw 	ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_BIOS_SIGNATURE, bios_sig);
19356be43703Skrw 	ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_BIOS_SIGNATURE, 0);
1936466e5dfaSderaadt 
1937466e5dfaSderaadt 	/*
1938466e5dfaSderaadt 	 * Stop chip and reset it.
1939466e5dfaSderaadt 	 */
1940466e5dfaSderaadt 	ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_RISC_CSR, ADW_RISC_CSR_STOP);
1941466e5dfaSderaadt 	ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_CTRL_REG,
1942466e5dfaSderaadt 			ADW_CTRL_REG_CMD_RESET);
19436be43703Skrw 	AdwSleepMilliSecond(100);
1944466e5dfaSderaadt 	ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_CTRL_REG,
1945466e5dfaSderaadt 			ADW_CTRL_REG_CMD_WR_IO_REG);
1946466e5dfaSderaadt 
1947466e5dfaSderaadt 	/*
1948a1d22770Skrw 	 * Reset Adw Library error code, if any, and try
1949466e5dfaSderaadt 	 * re-initializing the chip.
19506be43703Skrw 	 * Then translate initialization return value to status value.
1951466e5dfaSderaadt 	 */
19526be43703Skrw 	status = (AdwInitDriver(sc) == 0)? ADW_TRUE : ADW_FALSE;
1953466e5dfaSderaadt 
1954466e5dfaSderaadt 	/*
1955466e5dfaSderaadt 	 * Restore the BIOS signature word.
1956466e5dfaSderaadt 	 */
19576be43703Skrw 	ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_BIOS_SIGNATURE, bios_sig);
1958466e5dfaSderaadt 
1959466e5dfaSderaadt 	/*
1960466e5dfaSderaadt 	 * Restore per TID negotiated values.
1961466e5dfaSderaadt 	 */
19626be43703Skrw 	ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_WDTR_ABLE, wdtr_able);
19636be43703Skrw 	ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_SDTR_ABLE, sdtr_able);
19646be43703Skrw 	if (sc->chip_type == ADW_CHIP_ASC38C1600) {
19656be43703Skrw 		ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_PPR_ABLE, ppr_able);
19666be43703Skrw 	}
19676be43703Skrw 	ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_TAGQNG_ABLE, tagqng_able);
1968466e5dfaSderaadt 	for (tid = 0; tid <= ADW_MAX_TID; tid++) {
19696be43703Skrw 		ADW_WRITE_BYTE_LRAM(iot, ioh, ADW_MC_NUMBER_OF_MAX_CMD + tid,
1970466e5dfaSderaadt 			max_cmd[tid]);
1971466e5dfaSderaadt 	}
1972466e5dfaSderaadt 
1973466e5dfaSderaadt 	return status;
1974379dd687Sdownsj }
1975379dd687Sdownsj 
1976379dd687Sdownsj 
1977379dd687Sdownsj /*
1978a1d22770Skrw  * Adw Library Interrupt Service Routine
1979379dd687Sdownsj  *
1980379dd687Sdownsj  *  This function is called by a driver's interrupt service routine.
1981379dd687Sdownsj  *  The function disables and re-enables interrupts.
1982379dd687Sdownsj  *
19836be43703Skrw  *  Note: AdwISR() can be called when interrupts are disabled or even
1984379dd687Sdownsj  *  when there is no hardware interrupt condition present. It will
1985379dd687Sdownsj  *  always check for completed idle commands and microcode requests.
1986379dd687Sdownsj  *  This is an important feature that shouldn't be changed because it
1987379dd687Sdownsj  *  allows commands to be completed from polling mode loops.
1988379dd687Sdownsj  *
1989379dd687Sdownsj  * Return:
1990379dd687Sdownsj  *   ADW_TRUE(1) - interrupt was pending
1991379dd687Sdownsj  *   ADW_FALSE(0) - no interrupt was pending
1992379dd687Sdownsj  */
1993379dd687Sdownsj int
19946be43703Skrw AdwISR(sc)
1995379dd687Sdownsj ADW_SOFTC	*sc;
1996379dd687Sdownsj {
1997379dd687Sdownsj 	bus_space_tag_t iot = sc->sc_iot;
1998379dd687Sdownsj 	bus_space_handle_t ioh = sc->sc_ioh;
1999379dd687Sdownsj 	u_int8_t	int_stat;
2000466e5dfaSderaadt 	u_int16_t	target_bit;
2001466e5dfaSderaadt 	ADW_CARRIER	*free_carrp/*, *ccb_carr*/;
2002466e5dfaSderaadt 	u_int32_t	irq_next_pa;
2003379dd687Sdownsj 	ADW_SCSI_REQ_Q	*scsiq;
2004466e5dfaSderaadt 	ADW_CCB		*ccb;
20056be43703Skrw 	int		s;
2006379dd687Sdownsj 
2007379dd687Sdownsj 
20086be43703Skrw 	s = splbio();
20096be43703Skrw 
2010379dd687Sdownsj 	/* Reading the register clears the interrupt. */
2011379dd687Sdownsj 	int_stat = ADW_READ_BYTE_REGISTER(iot, ioh, IOPB_INTR_STATUS_REG);
2012379dd687Sdownsj 
2013466e5dfaSderaadt 	if ((int_stat & (ADW_INTR_STATUS_INTRA | ADW_INTR_STATUS_INTRB |
2014466e5dfaSderaadt 	     ADW_INTR_STATUS_INTRC)) == 0) {
20156be43703Skrw 		splx(s);
2016466e5dfaSderaadt 		return ADW_FALSE;
2017466e5dfaSderaadt 	}
2018466e5dfaSderaadt 
2019466e5dfaSderaadt 	/*
2020466e5dfaSderaadt 	 * Notify the driver of an asynchronous microcode condition by
2021a1d22770Skrw 	 * calling the ADW_SOFTC.async_callback function. The function
20226be43703Skrw 	 * is passed the microcode ADW_MC_INTRB_CODE byte value.
2023466e5dfaSderaadt 	 */
2024379dd687Sdownsj 	if (int_stat & ADW_INTR_STATUS_INTRB) {
2025466e5dfaSderaadt 		u_int8_t intrb_code;
2026466e5dfaSderaadt 
20276be43703Skrw 		ADW_READ_BYTE_LRAM(iot, ioh, ADW_MC_INTRB_CODE, intrb_code);
20286be43703Skrw 
20296be43703Skrw 		if (sc->chip_type == ADW_CHIP_ASC3550 ||
20306be43703Skrw 	    	    sc->chip_type == ADW_CHIP_ASC38C0800) {
2031a1d22770Skrw 			if (intrb_code == ADW_ASYNC_CARRIER_READY_FAILURE &&
2032466e5dfaSderaadt 				sc->carr_pending_cnt != 0) {
20336be43703Skrw 				ADW_WRITE_BYTE_REGISTER(iot, ioh,
20343976a5edSkrw 					IOPB_TICKLE, ADW_TICKLE_A);
20356be43703Skrw 				if (sc->chip_type == ADW_CHIP_ASC3550) {
20366be43703Skrw 					ADW_WRITE_BYTE_REGISTER(iot, ioh,
20373976a5edSkrw 						IOPB_TICKLE, ADW_TICKLE_NOP);
20386be43703Skrw 				}
2039379dd687Sdownsj 			}
2040379dd687Sdownsj 		}
2041379dd687Sdownsj 
2042466e5dfaSderaadt 		if (sc->async_callback != 0) {
2043466e5dfaSderaadt 		    (*(ADW_ASYNC_CALLBACK)sc->async_callback)(sc, intrb_code);
2044466e5dfaSderaadt 		}
2045466e5dfaSderaadt 	}
2046379dd687Sdownsj 
2047379dd687Sdownsj 	/*
2048466e5dfaSderaadt 	 * Check if the IRQ stopper carrier contains a completed request.
2049379dd687Sdownsj 	 */
2050a1d22770Skrw 	while (((irq_next_pa = sc->irq_sp->next_ba) & ADW_RQ_DONE) != 0)
2051379dd687Sdownsj 	{
20526be43703Skrw #if ADW_DEBUG
20536be43703Skrw 		printf("irq 0x%x, 0x%x, 0x%x, 0x%x\n",
20546be43703Skrw 				sc->irq_sp->carr_id,
20556be43703Skrw 				sc->irq_sp->carr_ba,
20566be43703Skrw 				sc->irq_sp->areq_ba,
20576be43703Skrw 				sc->irq_sp->next_ba);
20586be43703Skrw #endif
2059466e5dfaSderaadt 		/*
20606be43703Skrw 		 * Get a pointer to the newly completed ADW_SCSI_REQ_Q
20616be43703Skrw 		 * structure.
20626be43703Skrw 		 * The RISC will have set 'areq_ba' to a virtual address.
2063466e5dfaSderaadt 		 *
2064a1d22770Skrw 		 * The firmware will have copied the ADW_SCSI_REQ_Q.ccb_ptr
2065a1d22770Skrw 		 * field to the carrier ADW_CARRIER.areq_ba field.
20666be43703Skrw 		 * The conversion below complements the conversion of
2067a1d22770Skrw 		 * ADW_SCSI_REQ_Q.ccb_ptr' in AdwExeScsiQueue().
2068466e5dfaSderaadt 		 */
20696be43703Skrw 		ccb = adw_ccb_phys_kv(sc, sc->irq_sp->areq_ba);
2070466e5dfaSderaadt 		scsiq = &ccb->scsiq;
20716be43703Skrw 		scsiq->ccb_ptr = sc->irq_sp->areq_ba;
2072379dd687Sdownsj 
20736be43703Skrw 		/*
20746be43703Skrw 		 * Request finished with good status and the queue was not
20756be43703Skrw 		 * DMAed to host memory by the firmware. Set all status fields
20766be43703Skrw 		 * to indicate good status.
20776be43703Skrw 		 */
2078a1d22770Skrw 		if ((irq_next_pa & ADW_RQ_GOOD) != 0) {
20796be43703Skrw 			scsiq->done_status = QD_NO_ERROR;
20806be43703Skrw 			scsiq->host_status = scsiq->scsi_status = 0;
20816be43703Skrw 			scsiq->data_cnt = 0L;
2082379dd687Sdownsj 		}
2083379dd687Sdownsj 
2084466e5dfaSderaadt 		/*
2085466e5dfaSderaadt 		 * Advance the stopper pointer to the next carrier
2086466e5dfaSderaadt 		 * ignoring the lower four bits. Free the previous
2087466e5dfaSderaadt 		 * stopper carrier.
2088466e5dfaSderaadt 		 */
2089466e5dfaSderaadt 		free_carrp = sc->irq_sp;
2090a1d22770Skrw 		sc->irq_sp = ADW_CARRIER_VADDR(sc, ADW_GET_CARRP(irq_next_pa));
2091466e5dfaSderaadt 
20926be43703Skrw 		free_carrp->next_ba = (sc->carr_freelist == NULL)? NULL
20936be43703Skrw 					: sc->carr_freelist->carr_ba;
2094466e5dfaSderaadt 		sc->carr_freelist = free_carrp;
2095466e5dfaSderaadt 		sc->carr_pending_cnt--;
2096466e5dfaSderaadt 
2097379dd687Sdownsj 		target_bit = ADW_TID_TO_TIDMASK(scsiq->target_id);
2098379dd687Sdownsj 
2099379dd687Sdownsj 		/*
2100379dd687Sdownsj 		 * Clear request microcode control flag.
2101379dd687Sdownsj 		 */
2102379dd687Sdownsj 		scsiq->cntl = 0;
2103379dd687Sdownsj 
2104379dd687Sdownsj 		/*
2105379dd687Sdownsj 		 * Check Condition handling
2106379dd687Sdownsj 		 */
2107379dd687Sdownsj 		/*
2108379dd687Sdownsj 		 * If the command that completed was a SCSI INQUIRY and
2109379dd687Sdownsj 		 * LUN 0 was sent the command, then process the INQUIRY
2110379dd687Sdownsj 		 * command information for the device.
2111379dd687Sdownsj 		 */
2112466e5dfaSderaadt 		if (scsiq->done_status == QD_NO_ERROR &&
2113379dd687Sdownsj 		    scsiq->cdb[0] == INQUIRY &&
2114379dd687Sdownsj 		    scsiq->target_lun == 0) {
21156be43703Skrw 			AdwInquiryHandling(sc, scsiq);
2116379dd687Sdownsj 		}
2117379dd687Sdownsj 
2118379dd687Sdownsj 		/*
2119379dd687Sdownsj 		 * Notify the driver of the completed request by passing
2120379dd687Sdownsj 		 * the ADW_SCSI_REQ_Q pointer to its callback function.
2121379dd687Sdownsj 		 */
2122379dd687Sdownsj 		(*(ADW_ISR_CALLBACK)sc->isr_callback)(sc, scsiq);
2123379dd687Sdownsj 		/*
2124379dd687Sdownsj 		 * Note: After the driver callback function is called, 'scsiq'
2125379dd687Sdownsj 		 * can no longer be referenced.
2126379dd687Sdownsj 		 *
2127379dd687Sdownsj 		 * Fall through and continue processing other completed
2128379dd687Sdownsj 		 * requests...
2129379dd687Sdownsj 		 */
2130379dd687Sdownsj 	}
2131466e5dfaSderaadt 
21326be43703Skrw 	splx(s);
21336be43703Skrw 
2134466e5dfaSderaadt 	return ADW_TRUE;
2135379dd687Sdownsj }
2136379dd687Sdownsj 
2137466e5dfaSderaadt 
2138379dd687Sdownsj /*
2139379dd687Sdownsj  * Send an idle command to the chip and wait for completion.
2140379dd687Sdownsj  *
2141466e5dfaSderaadt  * Command completion is polled for once per microsecond.
2142466e5dfaSderaadt  *
2143466e5dfaSderaadt  * The function can be called from anywhere including an interrupt handler.
2144e693526fSkrw  * But the function is not re-entrant, so it uses the splbio/splx()
2145466e5dfaSderaadt  * functions to prevent reentrancy.
2146379dd687Sdownsj  *
2147379dd687Sdownsj  * Return Values:
2148379dd687Sdownsj  *   ADW_TRUE - command completed successfully
2149379dd687Sdownsj  *   ADW_FALSE - command failed
2150466e5dfaSderaadt  *   ADW_ERROR - command timed out
2151379dd687Sdownsj  */
2152379dd687Sdownsj int
21536be43703Skrw AdwSendIdleCmd(sc, idle_cmd, idle_cmd_parameter)
2154379dd687Sdownsj ADW_SOFTC      *sc;
2155379dd687Sdownsj u_int16_t       idle_cmd;
2156379dd687Sdownsj u_int32_t       idle_cmd_parameter;
2157379dd687Sdownsj {
2158379dd687Sdownsj 	bus_space_tag_t iot = sc->sc_iot;
2159379dd687Sdownsj 	bus_space_handle_t ioh = sc->sc_ioh;
21606be43703Skrw 	u_int16_t	result;
21616be43703Skrw 	u_int32_t	i, j, s;
2162379dd687Sdownsj 
2163e693526fSkrw 	s = splbio();
2164466e5dfaSderaadt 
2165466e5dfaSderaadt 	/*
2166466e5dfaSderaadt 	 * Clear the idle command status which is set by the microcode
2167466e5dfaSderaadt 	 * to a non-zero value to indicate when the command is completed.
2168466e5dfaSderaadt 	 */
21696be43703Skrw 	ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_IDLE_CMD_STATUS, (u_int16_t) 0);
2170379dd687Sdownsj 
2171379dd687Sdownsj 	/*
2172379dd687Sdownsj 	 * Write the idle command value after the idle command parameter
2173379dd687Sdownsj 	 * has been written to avoid a race condition. If the order is not
2174379dd687Sdownsj 	 * followed, the microcode may process the idle command before the
2175379dd687Sdownsj 	 * parameters have been written to LRAM.
2176379dd687Sdownsj 	 */
21776be43703Skrw 	ADW_WRITE_DWORD_LRAM(iot, ioh, ADW_MC_IDLE_CMD_PARAMETER,
2178379dd687Sdownsj 			idle_cmd_parameter);
21796be43703Skrw 	ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_IDLE_CMD, idle_cmd);
2180379dd687Sdownsj 
2181379dd687Sdownsj 	/*
2182466e5dfaSderaadt 	 * Tickle the RISC to tell it to process the idle command.
2183379dd687Sdownsj 	 */
21843976a5edSkrw 	ADW_WRITE_BYTE_REGISTER(iot, ioh, IOPB_TICKLE, ADW_TICKLE_B);
21856be43703Skrw 	if (sc->chip_type == ADW_CHIP_ASC3550) {
2186379dd687Sdownsj 		/*
2187466e5dfaSderaadt 		 * Clear the tickle value. In the ASC-3550 the RISC flag
2188466e5dfaSderaadt 		 * command 'clr_tickle_b' does not work unless the host
2189466e5dfaSderaadt 		 * value is cleared.
2190379dd687Sdownsj 		 */
21913976a5edSkrw 		ADW_WRITE_BYTE_REGISTER(iot, ioh, IOPB_TICKLE, ADW_TICKLE_NOP);
2192379dd687Sdownsj 	}
2193379dd687Sdownsj 
2194466e5dfaSderaadt 	/* Wait for up to 100 millisecond for the idle command to timeout. */
2195466e5dfaSderaadt 	for (i = 0; i < SCSI_WAIT_100_MSEC; i++) {
2196466e5dfaSderaadt 		/* Poll once each microsecond for command completion. */
2197466e5dfaSderaadt 		for (j = 0; j < SCSI_US_PER_MSEC; j++) {
21986be43703Skrw 			ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_IDLE_CMD_STATUS,
21996be43703Skrw 									result);
2200466e5dfaSderaadt 			if (result != 0) {
2201e693526fSkrw 				splx(s);
2202466e5dfaSderaadt 				return result;
2203466e5dfaSderaadt 			}
22046be43703Skrw 			AdwDelayMicroSecond(1);
2205379dd687Sdownsj 		}
2206379dd687Sdownsj 	}
2207379dd687Sdownsj 
2208e693526fSkrw 	splx(s);
2209466e5dfaSderaadt 	return ADW_ERROR;
2210379dd687Sdownsj }
2211379dd687Sdownsj 
2212379dd687Sdownsj 
2213379dd687Sdownsj /*
2214379dd687Sdownsj  * Inquiry Information Byte 7 Handling
2215379dd687Sdownsj  *
2216379dd687Sdownsj  * Handle SCSI Inquiry Command information for a device by setting
2217379dd687Sdownsj  * microcode operating variables that affect WDTR, SDTR, and Tag
2218379dd687Sdownsj  * Queuing.
2219379dd687Sdownsj  */
2220379dd687Sdownsj static void
22216be43703Skrw AdwInquiryHandling(sc, scsiq)
2222379dd687Sdownsj ADW_SOFTC	*sc;
2223379dd687Sdownsj ADW_SCSI_REQ_Q *scsiq;
2224379dd687Sdownsj {
2225cb847534Skrw #ifndef FAILSAFE
2226379dd687Sdownsj 	bus_space_tag_t iot = sc->sc_iot;
2227379dd687Sdownsj 	bus_space_handle_t ioh = sc->sc_ioh;
2228379dd687Sdownsj 	u_int8_t		tid;
2229466e5dfaSderaadt 	ADW_SCSI_INQUIRY	*inq;
2230466e5dfaSderaadt 	u_int16_t		tidmask;
2231466e5dfaSderaadt 	u_int16_t		cfg_word;
2232466e5dfaSderaadt 
2233379dd687Sdownsj 
2234379dd687Sdownsj 	/*
22356be43703Skrw 	 * AdwInquiryHandling() requires up to INQUIRY information Byte 7
2236379dd687Sdownsj 	 * to be available.
2237379dd687Sdownsj 	 *
2238379dd687Sdownsj 	 * If less than 8 bytes of INQUIRY information were requested or less
2239379dd687Sdownsj 	 * than 8 bytes were transferred, then return. cdb[4] is the request
2240379dd687Sdownsj 	 * length and the ADW_SCSI_REQ_Q 'data_cnt' field is set by the
2241379dd687Sdownsj 	 * microcode to the transfer residual count.
2242379dd687Sdownsj 	 */
2243466e5dfaSderaadt 
2244379dd687Sdownsj 	if (scsiq->cdb[4] < 8 || (scsiq->cdb[4] - scsiq->data_cnt) < 8) {
2245379dd687Sdownsj 		return;
2246379dd687Sdownsj 	}
2247466e5dfaSderaadt 
2248379dd687Sdownsj 	tid = scsiq->target_id;
2249466e5dfaSderaadt 
2250466e5dfaSderaadt         inq = (ADW_SCSI_INQUIRY *) scsiq->vdata_addr;
2251379dd687Sdownsj 
2252379dd687Sdownsj 	/*
2253379dd687Sdownsj 	 * WDTR, SDTR, and Tag Queuing cannot be enabled for old devices.
2254379dd687Sdownsj 	 */
22556be43703Skrw 	if ((inq->rsp_data_fmt < 2) /*SCSI-1 | CCS*/ &&
22566be43703Skrw 	    (inq->ansi_apr_ver < 2)) {
2257379dd687Sdownsj 		return;
2258379dd687Sdownsj 	} else {
2259379dd687Sdownsj 		/*
2260379dd687Sdownsj 		 * INQUIRY Byte 7 Handling
2261379dd687Sdownsj 		 *
2262379dd687Sdownsj 		 * Use a device's INQUIRY byte 7 to determine whether it
2263379dd687Sdownsj 		 * supports WDTR, SDTR, and Tag Queuing. If the feature
2264379dd687Sdownsj 		 * is enabled in the EEPROM and the device supports the
2265379dd687Sdownsj 		 * feature, then enable it in the microcode.
2266379dd687Sdownsj 		 */
2267379dd687Sdownsj 
2268379dd687Sdownsj 		tidmask = ADW_TID_TO_TIDMASK(tid);
2269466e5dfaSderaadt 
2270379dd687Sdownsj 		/*
2271379dd687Sdownsj 		 * Wide Transfers
2272379dd687Sdownsj 		 *
2273379dd687Sdownsj 		 * If the EEPROM enabled WDTR for the device and the device
2274379dd687Sdownsj 		 * supports wide bus (16 bit) transfers, then turn on the
2275379dd687Sdownsj 		 * device's 'wdtr_able' bit and write the new value to the
2276379dd687Sdownsj 		 * microcode.
2277379dd687Sdownsj 		 */
2278466e5dfaSderaadt #ifdef SCSI_ADW_WDTR_DISABLE
2279ea94bb9bSmillert 	if(!(tidmask & SCSI_ADW_WDTR_DISABLE))
2280466e5dfaSderaadt #endif /* SCSI_ADW_WDTR_DISABLE */
2281466e5dfaSderaadt 		if ((sc->wdtr_able & tidmask) && inq->WBus16) {
22826be43703Skrw 			ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_WDTR_ABLE,
2283379dd687Sdownsj 					cfg_word);
2284379dd687Sdownsj 			if ((cfg_word & tidmask) == 0) {
2285379dd687Sdownsj 				cfg_word |= tidmask;
22866be43703Skrw 				ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_WDTR_ABLE,
2287379dd687Sdownsj 						cfg_word);
2288379dd687Sdownsj 
2289379dd687Sdownsj 				/*
22906be43703Skrw 				 * Clear the microcode "SDTR negotiation" and
22916be43703Skrw 				 * "WDTR negotiation" done indicators for the
22926be43703Skrw 				 * target to cause it to negotiate with the new
22936be43703Skrw 				 * setting set above.
2294466e5dfaSderaadt 				 * WDTR when accepted causes the target to enter
22956be43703Skrw 				 * asynchronous mode, so SDTR must be negotiated
2296379dd687Sdownsj 				 */
22976be43703Skrw 				ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_SDTR_DONE,
2298466e5dfaSderaadt 						cfg_word);
2299466e5dfaSderaadt 				cfg_word &= ~tidmask;
23006be43703Skrw 				ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_SDTR_DONE,
2301466e5dfaSderaadt 						cfg_word);
23026be43703Skrw 				ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_WDTR_DONE,
2303379dd687Sdownsj 						cfg_word);
2304379dd687Sdownsj 				cfg_word &= ~tidmask;
23056be43703Skrw 				ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_WDTR_DONE,
2306379dd687Sdownsj 						cfg_word);
2307379dd687Sdownsj 			}
2308379dd687Sdownsj 		}
2309466e5dfaSderaadt 
2310379dd687Sdownsj 		/*
2311379dd687Sdownsj 		 * Synchronous Transfers
2312379dd687Sdownsj 		 *
2313379dd687Sdownsj 		 * If the EEPROM enabled SDTR for the device and the device
2314379dd687Sdownsj 		 * supports synchronous transfers, then turn on the device's
2315379dd687Sdownsj 		 * 'sdtr_able' bit. Write the new value to the microcode.
2316379dd687Sdownsj 		 */
2317466e5dfaSderaadt #ifdef SCSI_ADW_SDTR_DISABLE
2318ea94bb9bSmillert 	if(!(tidmask & SCSI_ADW_SDTR_DISABLE))
2319466e5dfaSderaadt #endif /* SCSI_ADW_SDTR_DISABLE */
2320466e5dfaSderaadt 		if ((sc->sdtr_able & tidmask) && inq->Sync) {
23216be43703Skrw 			ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_SDTR_ABLE,cfg_word);
2322379dd687Sdownsj 			if ((cfg_word & tidmask) == 0) {
2323379dd687Sdownsj 				cfg_word |= tidmask;
23246be43703Skrw 				ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_SDTR_ABLE,
2325379dd687Sdownsj 						cfg_word);
2326379dd687Sdownsj 
2327379dd687Sdownsj 				/*
23286be43703Skrw 				 * Clear the microcode "SDTR negotiation"
23296be43703Skrw 				 * done indicator for the target to cause it
23306be43703Skrw 				 * to negotiate with the new setting set above.
2331379dd687Sdownsj 				 */
23326be43703Skrw 				ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_SDTR_DONE,
2333379dd687Sdownsj 						cfg_word);
2334379dd687Sdownsj 				cfg_word &= ~tidmask;
23356be43703Skrw 				ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_SDTR_DONE,
2336379dd687Sdownsj 						cfg_word);
2337379dd687Sdownsj 			}
2338379dd687Sdownsj 		}
23396be43703Skrw 		/*
23406be43703Skrw 		 * If the Inquiry data included enough space for the SPI-3
23416be43703Skrw 		 * Clocking field, then check if DT mode is supported.
23426be43703Skrw 		 */
23436be43703Skrw 		if (sc->chip_type == ADW_CHIP_ASC38C1600 &&
23446be43703Skrw 		   (scsiq->cdb[4] >= 57 ||
23456be43703Skrw 		   (scsiq->cdb[4] - scsiq->data_cnt) >= 57)) {
23466be43703Skrw 			/*
23476be43703Skrw 			 * PPR (Parallel Protocol Request) Capable
23486be43703Skrw 			 *
23496be43703Skrw 			 * If the device supports DT mode, then it must be
23506be43703Skrw 			 * PPR capable.
23516be43703Skrw 			 * The PPR message will be used in place of the SDTR
23526be43703Skrw 			 * and WDTR messages to negotiate synchronous speed
23536be43703Skrw 			 * and offset, transfer width, and protocol options.
23546be43703Skrw 			 */
23556be43703Skrw                          if((inq->Clocking) & INQ_CLOCKING_DT_ONLY){
23566be43703Skrw 				ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_PPR_ABLE,
23576be43703Skrw 						sc->ppr_able);
23586be43703Skrw 				sc->ppr_able |= tidmask;
23596be43703Skrw 				ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_PPR_ABLE,
23606be43703Skrw 						sc->ppr_able);
23616be43703Skrw 			}
23626be43703Skrw 		}
2363466e5dfaSderaadt 
2364379dd687Sdownsj 		/*
2365466e5dfaSderaadt 		 * If the EEPROM enabled Tag Queuing for the device and the
2366466e5dfaSderaadt 		 * device supports Tag Queueing, then turn on the device's
2367379dd687Sdownsj 		 * 'tagqng_enable' bit in the microcode and set the microcode
2368a1d22770Skrw 		 * maximum command count to the ADW_SOFTC 'max_dvc_qng'
2369379dd687Sdownsj 		 * value.
2370379dd687Sdownsj 		 *
2371379dd687Sdownsj 		 * Tag Queuing is disabled for the BIOS which runs in polled
2372379dd687Sdownsj 		 * mode and would see no benefit from Tag Queuing. Also by
2373379dd687Sdownsj 		 * disabling Tag Queuing in the BIOS devices with Tag Queuing
2374379dd687Sdownsj 		 * bugs will at least work with the BIOS.
2375379dd687Sdownsj 		 */
2376466e5dfaSderaadt #ifdef SCSI_ADW_TAGQ_DISABLE
2377ea94bb9bSmillert 	if(!(tidmask & SCSI_ADW_TAGQ_DISABLE))
2378466e5dfaSderaadt #endif /* SCSI_ADW_TAGQ_DISABLE */
2379466e5dfaSderaadt 		if ((sc->tagqng_able & tidmask) && inq->CmdQue) {
23806be43703Skrw 			ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_TAGQNG_ABLE,
2381379dd687Sdownsj 					cfg_word);
2382379dd687Sdownsj 			cfg_word |= tidmask;
23836be43703Skrw 			ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_TAGQNG_ABLE,
2384379dd687Sdownsj 					cfg_word);
2385466e5dfaSderaadt 
2386379dd687Sdownsj 			ADW_WRITE_BYTE_LRAM(iot, ioh,
23876be43703Skrw 					ADW_MC_NUMBER_OF_MAX_CMD + tid,
2388379dd687Sdownsj 					sc->max_dvc_qng);
2389379dd687Sdownsj 		}
2390379dd687Sdownsj 	}
2391cb847534Skrw #endif /* FAILSAFE */
2392379dd687Sdownsj }
2393379dd687Sdownsj 
2394466e5dfaSderaadt 
2395379dd687Sdownsj static void
23966be43703Skrw AdwSleepMilliSecond(n)
2397466e5dfaSderaadt u_int32_t	n;
2398379dd687Sdownsj {
2399379dd687Sdownsj 
2400379dd687Sdownsj 	DELAY(n * 1000);
2401379dd687Sdownsj }
2402379dd687Sdownsj 
2403466e5dfaSderaadt 
2404379dd687Sdownsj static void
24056be43703Skrw AdwDelayMicroSecond(n)
2406466e5dfaSderaadt u_int32_t	n;
2407379dd687Sdownsj {
2408379dd687Sdownsj 
2409379dd687Sdownsj 	DELAY(n);
2410379dd687Sdownsj }
2411466e5dfaSderaadt 
2412