1*3b9d585eSjsg /* $OpenBSD: adwlib.c,v 1.30 2024/04/13 23:44:11 jsg 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 *
21379dd687Sdownsj * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22379dd687Sdownsj * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23379dd687Sdownsj * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24379dd687Sdownsj * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25379dd687Sdownsj * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26379dd687Sdownsj * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27379dd687Sdownsj * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28379dd687Sdownsj * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29379dd687Sdownsj * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30379dd687Sdownsj * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31379dd687Sdownsj * POSSIBILITY OF SUCH DAMAGE.
32379dd687Sdownsj */
33379dd687Sdownsj /*
34379dd687Sdownsj * Ported from:
35379dd687Sdownsj */
36379dd687Sdownsj /*
37379dd687Sdownsj * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
38379dd687Sdownsj *
396be43703Skrw * Copyright (c) 1995-2000 Advanced System Products, Inc.
40379dd687Sdownsj * All Rights Reserved.
41379dd687Sdownsj *
42379dd687Sdownsj * Redistribution and use in source and binary forms, with or without
43379dd687Sdownsj * modification, are permitted provided that redistributions of source
44379dd687Sdownsj * code retain the above copyright notice and this comment without
45379dd687Sdownsj * modification.
46379dd687Sdownsj */
47379dd687Sdownsj
48379dd687Sdownsj #include <sys/param.h>
49379dd687Sdownsj #include <sys/systm.h>
50379dd687Sdownsj #include <sys/malloc.h>
51379dd687Sdownsj #include <sys/kernel.h>
52379dd687Sdownsj #include <sys/queue.h>
53379dd687Sdownsj #include <sys/device.h>
54379dd687Sdownsj
55379dd687Sdownsj #include <machine/bus.h>
56379dd687Sdownsj #include <machine/intr.h>
57379dd687Sdownsj
58379dd687Sdownsj #include <scsi/scsi_all.h>
59379dd687Sdownsj #include <scsi/scsiconf.h>
60379dd687Sdownsj
61466e5dfaSderaadt #include <dev/pci/pcidevs.h>
62466e5dfaSderaadt
63379dd687Sdownsj #include <dev/ic/adwlib.h>
647d4909e3Skrw #include <dev/microcode/adw/adwmcode.h>
656be43703Skrw #include <dev/ic/adw.h>
66379dd687Sdownsj
67379dd687Sdownsj
68c4071fd1Smillert int AdwRamSelfTest(bus_space_tag_t, bus_space_handle_t, u_int8_t);
69c4071fd1Smillert int AdwLoadMCode(bus_space_tag_t, bus_space_handle_t, u_int16_t *,
70c4071fd1Smillert u_int8_t);
71c4071fd1Smillert int AdwASC3550Cabling(bus_space_tag_t, bus_space_handle_t, ADW_DVC_CFG *);
72c4071fd1Smillert int AdwASC38C0800Cabling(bus_space_tag_t, bus_space_handle_t,
73c4071fd1Smillert ADW_DVC_CFG *);
74c4071fd1Smillert int AdwASC38C1600Cabling(bus_space_tag_t, bus_space_handle_t,
75c4071fd1Smillert ADW_DVC_CFG *);
76379dd687Sdownsj
77c4071fd1Smillert u_int16_t AdwGetEEPROMConfig(bus_space_tag_t, bus_space_handle_t,
78c4071fd1Smillert ADW_EEPROM *);
79c4071fd1Smillert void AdwSetEEPROMConfig(bus_space_tag_t, bus_space_handle_t,
80c4071fd1Smillert ADW_EEPROM *);
81c4071fd1Smillert u_int16_t AdwReadEEPWord(bus_space_tag_t, bus_space_handle_t, int);
82c4071fd1Smillert void AdwWaitEEPCmd(bus_space_tag_t, bus_space_handle_t);
836be43703Skrw
84c4071fd1Smillert void AdwInquiryHandling(ADW_SOFTC *, ADW_SCSI_REQ_Q *);
856be43703Skrw
86c4071fd1Smillert void AdwSleepMilliSecond(u_int32_t);
87c4071fd1Smillert void AdwDelayMicroSecond(u_int32_t);
88379dd687Sdownsj
89379dd687Sdownsj
90379dd687Sdownsj /*
91379dd687Sdownsj * EEPROM Configuration.
92379dd687Sdownsj *
93379dd687Sdownsj * All drivers should use this structure to set the default EEPROM
94379dd687Sdownsj * configuration. The BIOS now uses this structure when it is built.
95e693526fSkrw * Additional structure information can be found in adwlib.h where
96379dd687Sdownsj * the structure is defined.
97379dd687Sdownsj */
988f47c760Sjsg static const ADW_EEPROM adw_3550_Default_EEPROM = {
99466e5dfaSderaadt ADW_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
100466e5dfaSderaadt 0x0000, /* 01 cfg_msw */
101466e5dfaSderaadt 0xFFFF, /* 02 disc_enable */
102466e5dfaSderaadt 0xFFFF, /* 03 wdtr_able */
1036be43703Skrw { 0xFFFF }, /* 04 sdtr_able */
1046be43703Skrw 0xFFFF, /* 05 start_motor */
1056be43703Skrw 0xFFFF, /* 06 tagqng_able */
1066be43703Skrw 0xFFFF, /* 07 bios_scan */
1076be43703Skrw 0, /* 08 scam_tolerant */
1086be43703Skrw 7, /* 09 adapter_scsi_id */
1096be43703Skrw 0, /* bios_boot_delay */
1106be43703Skrw 3, /* 10 scsi_reset_delay */
1116be43703Skrw 0, /* bios_id_lun */
1126be43703Skrw 0, /* 11 termination */
1136be43703Skrw 0, /* reserved1 */
1146be43703Skrw 0xFFE7, /* 12 bios_ctrl */
1156be43703Skrw { 0xFFFF }, /* 13 ultra_able */
1166be43703Skrw { 0 }, /* 14 reserved2 */
1176be43703Skrw ADW_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
1186be43703Skrw ADW_DEF_MAX_DVC_QNG, /* max_dvc_qng */
1196be43703Skrw 0, /* 16 dvc_cntl */
1206be43703Skrw { 0 }, /* 17 bug_fix */
1216be43703Skrw { 0,0,0 }, /* 18-20 serial_number[3] */
1226be43703Skrw 0, /* 21 check_sum */
1236be43703Skrw { /* 22-29 oem_name[16] */
1246be43703Skrw 0,0,0,0,0,0,0,0,
1256be43703Skrw 0,0,0,0,0,0,0,0
1266be43703Skrw },
1276be43703Skrw 0, /* 30 dvc_err_code */
128a1d22770Skrw 0, /* 31 adw_err_code */
129a1d22770Skrw 0, /* 32 adw_err_addr */
1306be43703Skrw 0, /* 33 saved_dvc_err_code */
131a1d22770Skrw 0, /* 34 saved_adw_err_code */
132a1d22770Skrw 0 /* 35 saved_adw_err_addr */
1336be43703Skrw };
1346be43703Skrw
1358f47c760Sjsg static const ADW_EEPROM adw_38C0800_Default_EEPROM = {
1366be43703Skrw ADW_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
1376be43703Skrw 0x0000, /* 01 cfg_msw */
1386be43703Skrw 0xFFFF, /* 02 disc_enable */
1396be43703Skrw 0xFFFF, /* 03 wdtr_able */
1406be43703Skrw { 0x4444 }, /* 04 sdtr_speed1 */
141466e5dfaSderaadt 0xFFFF, /* 05 start_motor */
142466e5dfaSderaadt 0xFFFF, /* 06 tagqng_able */
143466e5dfaSderaadt 0xFFFF, /* 07 bios_scan */
144466e5dfaSderaadt 0, /* 08 scam_tolerant */
145466e5dfaSderaadt 7, /* 09 adapter_scsi_id */
146466e5dfaSderaadt 0, /* bios_boot_delay */
147466e5dfaSderaadt 3, /* 10 scsi_reset_delay */
148466e5dfaSderaadt 0, /* bios_id_lun */
149466e5dfaSderaadt 0, /* 11 termination_se */
150466e5dfaSderaadt 0, /* termination_lvd */
151466e5dfaSderaadt 0xFFE7, /* 12 bios_ctrl */
1526be43703Skrw { 0x4444 }, /* 13 sdtr_speed2 */
1536be43703Skrw { 0x4444 }, /* 14 sdtr_speed3 */
1546be43703Skrw ADW_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
1556be43703Skrw ADW_DEF_MAX_DVC_QNG, /* max_dvc_qng */
156466e5dfaSderaadt 0, /* 16 dvc_cntl */
1576be43703Skrw { 0x4444 }, /* 17 sdtr_speed4 */
1586be43703Skrw { 0,0,0 }, /* 18-20 serial_number[3] */
159466e5dfaSderaadt 0, /* 21 check_sum */
1606be43703Skrw { /* 22-29 oem_name[16] */
1616be43703Skrw 0,0,0,0,0,0,0,0,
1626be43703Skrw 0,0,0,0,0,0,0,0
1636be43703Skrw },
164466e5dfaSderaadt 0, /* 30 dvc_err_code */
165a1d22770Skrw 0, /* 31 adw_err_code */
166a1d22770Skrw 0, /* 32 adw_err_addr */
167466e5dfaSderaadt 0, /* 33 saved_dvc_err_code */
168a1d22770Skrw 0, /* 34 saved_adw_err_code */
169a1d22770Skrw 0, /* 35 saved_adw_err_addr */
1706be43703Skrw { /* 36-55 reserved1[16] */
1716be43703Skrw 0,0,0,0,0,0,0,0,0,0,
1726be43703Skrw 0,0,0,0,0,0,0,0,0,0
1736be43703Skrw },
174466e5dfaSderaadt 0, /* 56 cisptr_lsw */
175466e5dfaSderaadt 0, /* 57 cisprt_msw */
176466e5dfaSderaadt PCI_VENDOR_ADVSYS, /* 58 subsysvid */
177466e5dfaSderaadt PCI_PRODUCT_ADVSYS_U2W, /* 59 subsysid */
1786be43703Skrw { 0,0,0,0 } /* 60-63 reserved2[4] */
179466e5dfaSderaadt };
180466e5dfaSderaadt
1818f47c760Sjsg static const ADW_EEPROM adw_38C1600_Default_EEPROM = {
1826be43703Skrw ADW_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
1836be43703Skrw 0x0000, /* 01 cfg_msw */
1846be43703Skrw 0xFFFF, /* 02 disc_enable */
1856be43703Skrw 0xFFFF, /* 03 wdtr_able */
1866be43703Skrw { 0x5555 }, /* 04 sdtr_speed1 */
1876be43703Skrw 0xFFFF, /* 05 start_motor */
1886be43703Skrw 0xFFFF, /* 06 tagqng_able */
1896be43703Skrw 0xFFFF, /* 07 bios_scan */
1906be43703Skrw 0, /* 08 scam_tolerant */
1916be43703Skrw 7, /* 09 adapter_scsi_id */
1926be43703Skrw 0, /* bios_boot_delay */
1936be43703Skrw 3, /* 10 scsi_reset_delay */
1946be43703Skrw 0, /* bios_id_lun */
1956be43703Skrw 0, /* 11 termination_se */
1966be43703Skrw 0, /* termination_lvd */
1976be43703Skrw 0xFFE7, /* 12 bios_ctrl */
1986be43703Skrw { 0x5555 }, /* 13 sdtr_speed2 */
1996be43703Skrw { 0x5555 }, /* 14 sdtr_speed3 */
2006be43703Skrw ADW_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
2016be43703Skrw ADW_DEF_MAX_DVC_QNG, /* max_dvc_qng */
2026be43703Skrw 0, /* 16 dvc_cntl */
2036be43703Skrw { 0x5555 }, /* 17 sdtr_speed4 */
2046be43703Skrw { 0,0,0 }, /* 18-20 serial_number[3] */
2056be43703Skrw 0, /* 21 check_sum */
2066be43703Skrw { /* 22-29 oem_name[16] */
2076be43703Skrw 0,0,0,0,0,0,0,0,
2086be43703Skrw 0,0,0,0,0,0,0,0
2096be43703Skrw },
2106be43703Skrw 0, /* 30 dvc_err_code */
211a1d22770Skrw 0, /* 31 adw_err_code */
212a1d22770Skrw 0, /* 32 adw_err_addr */
2136be43703Skrw 0, /* 33 saved_dvc_err_code */
214a1d22770Skrw 0, /* 34 saved_adw_err_code */
215a1d22770Skrw 0, /* 35 saved_adw_err_addr */
2166be43703Skrw { /* 36-55 reserved1[16] */
2176be43703Skrw 0,0,0,0,0,0,0,0,0,0,
2186be43703Skrw 0,0,0,0,0,0,0,0,0,0
2196be43703Skrw },
2206be43703Skrw 0, /* 56 cisptr_lsw */
2216be43703Skrw 0, /* 57 cisprt_msw */
2226be43703Skrw PCI_VENDOR_ADVSYS, /* 58 subsysvid */
2236be43703Skrw PCI_PRODUCT_ADVSYS_U3W, /* 59 subsysid */
2246be43703Skrw { 0,0,0,0 } /* 60-63 reserved2[4] */
2256be43703Skrw };
2266be43703Skrw
2276be43703Skrw
228379dd687Sdownsj /*
2296be43703Skrw * Read the board's EEPROM configuration. Set fields in ADW_SOFTC and
2306be43703Skrw * ADW_DVC_CFG based on the EEPROM settings. The chip is stopped while
2316be43703Skrw * all of this is done.
232379dd687Sdownsj *
233379dd687Sdownsj * For a non-fatal error return a warning code. If there are no warnings
234379dd687Sdownsj * then 0 is returned.
2356be43703Skrw *
2366be43703Skrw * Note: Chip is stopped on entry.
237379dd687Sdownsj */
238379dd687Sdownsj int
AdwInitFromEEPROM(ADW_SOFTC * sc)239855b2726Sdhill AdwInitFromEEPROM(ADW_SOFTC *sc)
240379dd687Sdownsj {
241379dd687Sdownsj bus_space_tag_t iot = sc->sc_iot;
242379dd687Sdownsj bus_space_handle_t ioh = sc->sc_ioh;
2436be43703Skrw ADW_EEPROM eep_config;
244379dd687Sdownsj u_int16_t warn_code;
2456be43703Skrw u_int16_t sdtr_speed = 0;
2466be43703Skrw u_int8_t tid, termination;
247466e5dfaSderaadt int i, j;
248379dd687Sdownsj
249379dd687Sdownsj
250379dd687Sdownsj warn_code = 0;
251379dd687Sdownsj
252379dd687Sdownsj /*
2536be43703Skrw * Read the board's EEPROM configuration.
2546be43703Skrw *
2556be43703Skrw * Set default values if a bad checksum is found.
2566be43703Skrw *
2576be43703Skrw * XXX - Don't handle big-endian access to EEPROM yet.
2586be43703Skrw */
2596be43703Skrw if (AdwGetEEPROMConfig(iot, ioh, &eep_config) != eep_config.check_sum) {
2606be43703Skrw warn_code |= ADW_WARN_EEPROM_CHKSUM;
2616be43703Skrw
2626be43703Skrw /*
2636be43703Skrw * Set EEPROM default values.
2646be43703Skrw */
2656be43703Skrw switch(sc->chip_type) {
2666be43703Skrw case ADW_CHIP_ASC3550:
2676be43703Skrw eep_config = adw_3550_Default_EEPROM;
2686be43703Skrw break;
2696be43703Skrw case ADW_CHIP_ASC38C0800:
2706be43703Skrw eep_config = adw_38C0800_Default_EEPROM;
2716be43703Skrw break;
2726be43703Skrw case ADW_CHIP_ASC38C1600:
2736be43703Skrw eep_config = adw_38C1600_Default_EEPROM;
2746be43703Skrw
2756be43703Skrw // XXX TODO!!! if (ASC_PCI_ID2FUNC(sc->cfg.pci_slot_info) != 0) {
2766be43703Skrw if (sc->cfg.pci_slot_info != 0) {
2776be43703Skrw u_int8_t lsw_msb;
2786be43703Skrw
2796be43703Skrw lsw_msb = eep_config.cfg_lsw >> 8;
2806be43703Skrw /*
2816be43703Skrw * Set Function 1 EEPROM Word 0 MSB
2826be43703Skrw *
2836be43703Skrw * Clear the BIOS_ENABLE (bit 14) and
2846be43703Skrw * INTAB (bit 11) EEPROM bits.
2856be43703Skrw *
2866be43703Skrw * Disable Bit 14 (BIOS_ENABLE) to fix
2876be43703Skrw * SPARC Ultra 60 and old Mac system booting
2886be43703Skrw * problem. The Expansion ROM must
2896be43703Skrw * be disabled in Function 1 for these systems.
2906be43703Skrw */
2916be43703Skrw lsw_msb &= ~(((ADW_EEPROM_BIOS_ENABLE |
2926be43703Skrw ADW_EEPROM_INTAB) >> 8) & 0xFF);
2936be43703Skrw /*
2946be43703Skrw * Set the INTAB (bit 11) if the GPIO 0 input
2956be43703Skrw * indicates the Function 1 interrupt line is
2966be43703Skrw * wired to INTA.
2976be43703Skrw *
2986be43703Skrw * Set/Clear Bit 11 (INTAB) from
2996be43703Skrw * the GPIO bit 0 input:
3006be43703Skrw * 1 - Function 1 intr line wired to INT A.
3016be43703Skrw * 0 - Function 1 intr line wired to INT B.
3026be43703Skrw *
3036be43703Skrw * Note: Adapter boards always have Function 0
3046be43703Skrw * wired to INTA.
3056be43703Skrw * Put all 5 GPIO bits in input mode and then
3066be43703Skrw * read their input values.
3076be43703Skrw */
3086be43703Skrw ADW_WRITE_BYTE_REGISTER(iot, ioh,
3096be43703Skrw IOPB_GPIO_CNTL, 0);
3106be43703Skrw if (ADW_READ_BYTE_REGISTER(iot, ioh,
3116be43703Skrw IOPB_GPIO_DATA) & 0x01) {
3126be43703Skrw /*
3136be43703Skrw * Function 1 interrupt wired to INTA;
3146be43703Skrw * Set EEPROM bit.
3156be43703Skrw */
3166be43703Skrw lsw_msb |= (ADW_EEPROM_INTAB >> 8)
3176be43703Skrw & 0xFF;
3186be43703Skrw }
3196be43703Skrw eep_config.cfg_lsw &= 0x00FF;
3206be43703Skrw eep_config.cfg_lsw |= lsw_msb << 8;
3216be43703Skrw }
3226be43703Skrw break;
3236be43703Skrw }
3246be43703Skrw
3256be43703Skrw /*
3266be43703Skrw * Assume the 6 byte board serial number that was read
3276be43703Skrw * from EEPROM is correct even if the EEPROM checksum
3286be43703Skrw * failed.
3296be43703Skrw */
3306be43703Skrw for (i = 2, j = 1; i >= 0; i--, j++) {
3316be43703Skrw eep_config.serial_number[i] =
332a1d22770Skrw AdwReadEEPWord(iot, ioh, ADW_EEP_DVC_CFG_END - j);
3336be43703Skrw }
3346be43703Skrw
3356be43703Skrw AdwSetEEPROMConfig(iot, ioh, &eep_config);
3366be43703Skrw }
3376be43703Skrw /*
3386be43703Skrw * Set sc and sc->cfg variables from the EEPROM configuration
3396be43703Skrw * that was read.
3406be43703Skrw *
3416be43703Skrw * This is the mapping of EEPROM fields to Adw Library fields.
3426be43703Skrw */
3436be43703Skrw sc->wdtr_able = eep_config.wdtr_able;
3446be43703Skrw if (sc->chip_type == ADW_CHIP_ASC3550) {
3456be43703Skrw sc->sdtr_able = eep_config.sdtr1.sdtr_able;
3466be43703Skrw sc->ultra_able = eep_config.sdtr2.ultra_able;
3476be43703Skrw } else {
3486be43703Skrw sc->sdtr_speed1 = eep_config.sdtr1.sdtr_speed1;
3496be43703Skrw sc->sdtr_speed2 = eep_config.sdtr2.sdtr_speed2;
3506be43703Skrw sc->sdtr_speed3 = eep_config.sdtr3.sdtr_speed3;
3516be43703Skrw sc->sdtr_speed4 = eep_config.sdtr4.sdtr_speed4;
3526be43703Skrw }
3536be43703Skrw sc->ppr_able = 0;
3546be43703Skrw sc->tagqng_able = eep_config.tagqng_able;
3556be43703Skrw sc->cfg.disc_enable = eep_config.disc_enable;
3566be43703Skrw sc->max_host_qng = eep_config.max_host_qng;
3576be43703Skrw sc->max_dvc_qng = eep_config.max_dvc_qng;
3586be43703Skrw sc->chip_scsi_id = (eep_config.adapter_scsi_id & ADW_MAX_TID);
3596be43703Skrw sc->start_motor = eep_config.start_motor;
3606be43703Skrw sc->scsi_reset_wait = eep_config.scsi_reset_delay;
3616be43703Skrw sc->bios_ctrl = eep_config.bios_ctrl;
3626be43703Skrw sc->no_scam = eep_config.scam_tolerant;
3636be43703Skrw sc->cfg.serial1 = eep_config.serial_number[0];
3646be43703Skrw sc->cfg.serial2 = eep_config.serial_number[1];
3656be43703Skrw sc->cfg.serial3 = eep_config.serial_number[2];
3666be43703Skrw
3676be43703Skrw if (sc->chip_type == ADW_CHIP_ASC38C0800 ||
3686be43703Skrw sc->chip_type == ADW_CHIP_ASC38C1600) {
3696be43703Skrw sc->sdtr_able = 0;
3706be43703Skrw for (tid = 0; tid <= ADW_MAX_TID; tid++) {
3716be43703Skrw if (tid == 0) {
3726be43703Skrw sdtr_speed = sc->sdtr_speed1;
3736be43703Skrw } else if (tid == 4) {
3746be43703Skrw sdtr_speed = sc->sdtr_speed2;
3756be43703Skrw } else if (tid == 8) {
3766be43703Skrw sdtr_speed = sc->sdtr_speed3;
3776be43703Skrw } else if (tid == 12) {
3786be43703Skrw sdtr_speed = sc->sdtr_speed4;
3796be43703Skrw }
3806be43703Skrw if (sdtr_speed & ADW_MAX_TID) {
3816be43703Skrw sc->sdtr_able |= (1 << tid);
3826be43703Skrw }
3836be43703Skrw sdtr_speed >>= 4;
3846be43703Skrw }
3856be43703Skrw }
3866be43703Skrw
3876be43703Skrw /*
3886be43703Skrw * Set the host maximum queuing (max. 253, min. 16) and the per device
3896be43703Skrw * maximum queuing (max. 63, min. 4).
3906be43703Skrw */
3916be43703Skrw if (eep_config.max_host_qng > ADW_DEF_MAX_HOST_QNG) {
3926be43703Skrw eep_config.max_host_qng = ADW_DEF_MAX_HOST_QNG;
3936be43703Skrw } else if (eep_config.max_host_qng < ADW_DEF_MIN_HOST_QNG)
3946be43703Skrw {
3956be43703Skrw /* If the value is zero, assume it is uninitialized. */
3966be43703Skrw if (eep_config.max_host_qng == 0) {
3976be43703Skrw eep_config.max_host_qng = ADW_DEF_MAX_HOST_QNG;
3986be43703Skrw } else {
3996be43703Skrw eep_config.max_host_qng = ADW_DEF_MIN_HOST_QNG;
4006be43703Skrw }
4016be43703Skrw }
4026be43703Skrw
4036be43703Skrw if (eep_config.max_dvc_qng > ADW_DEF_MAX_DVC_QNG) {
4046be43703Skrw eep_config.max_dvc_qng = ADW_DEF_MAX_DVC_QNG;
4056be43703Skrw } else if (eep_config.max_dvc_qng < ADW_DEF_MIN_DVC_QNG) {
4066be43703Skrw /* If the value is zero, assume it is uninitialized. */
4076be43703Skrw if (eep_config.max_dvc_qng == 0) {
4086be43703Skrw eep_config.max_dvc_qng = ADW_DEF_MAX_DVC_QNG;
4096be43703Skrw } else {
4106be43703Skrw eep_config.max_dvc_qng = ADW_DEF_MIN_DVC_QNG;
4116be43703Skrw }
4126be43703Skrw }
4136be43703Skrw
4146be43703Skrw /*
4156be43703Skrw * If 'max_dvc_qng' is greater than 'max_host_qng', then
4166be43703Skrw * set 'max_dvc_qng' to 'max_host_qng'.
4176be43703Skrw */
4186be43703Skrw if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
4196be43703Skrw eep_config.max_dvc_qng = eep_config.max_host_qng;
4206be43703Skrw }
4216be43703Skrw
4226be43703Skrw /*
423a1d22770Skrw * Set ADW_SOFTC 'max_host_qng' and 'max_dvc_qng'
4246be43703Skrw * values based on possibly adjusted EEPROM values.
4256be43703Skrw */
4266be43703Skrw sc->max_host_qng = eep_config.max_host_qng;
4276be43703Skrw sc->max_dvc_qng = eep_config.max_dvc_qng;
4286be43703Skrw
4296be43703Skrw
4306be43703Skrw /*
4316be43703Skrw * If the EEPROM 'termination' field is set to automatic (0), then set
432a1d22770Skrw * the ADW_SOFTC.cfg 'termination' field to automatic also.
4336be43703Skrw *
4346be43703Skrw * If the termination is specified with a non-zero 'termination'
435a1d22770Skrw * value check that a legal value is set and set the ADW_SOFTC.cfg
4366be43703Skrw * 'termination' field appropriately.
4376be43703Skrw */
4386be43703Skrw
4396be43703Skrw switch(sc->chip_type) {
4406be43703Skrw case ADW_CHIP_ASC3550:
4416be43703Skrw sc->cfg.termination = 0; /* auto termination */
4426be43703Skrw switch(eep_config.termination_se) {
4436be43703Skrw case 3:
4446be43703Skrw /* Enable manual control with low on / high on. */
4456be43703Skrw sc->cfg.termination |= ADW_TERM_CTL_L;
4466be43703Skrw case 2:
4476be43703Skrw /* Enable manual control with low off / high on. */
4486be43703Skrw sc->cfg.termination |= ADW_TERM_CTL_H;
4496be43703Skrw case 1:
4506be43703Skrw /* Enable manual control with low off / high off. */
4516be43703Skrw sc->cfg.termination |= ADW_TERM_CTL_SEL;
4526be43703Skrw case 0:
4536be43703Skrw break;
4546be43703Skrw default:
4556be43703Skrw warn_code |= ADW_WARN_EEPROM_TERMINATION;
4566be43703Skrw }
4576be43703Skrw break;
4586be43703Skrw
4596be43703Skrw case ADW_CHIP_ASC38C0800:
4606be43703Skrw case ADW_CHIP_ASC38C1600:
4616be43703Skrw switch(eep_config.termination_se) {
4626be43703Skrw case 0:
4636be43703Skrw /* auto termination for SE */
4646be43703Skrw termination = 0;
4656be43703Skrw break;
4666be43703Skrw case 1:
4676be43703Skrw /* Enable manual control with low off / high off. */
4686be43703Skrw termination = 0;
4696be43703Skrw break;
4706be43703Skrw case 2:
4716be43703Skrw /* Enable manual control with low off / high on. */
4726be43703Skrw termination = ADW_TERM_SE_HI;
4736be43703Skrw break;
4746be43703Skrw case 3:
4756be43703Skrw /* Enable manual control with low on / high on. */
4766be43703Skrw termination = ADW_TERM_SE;
4776be43703Skrw break;
4786be43703Skrw default:
4796be43703Skrw /*
4806be43703Skrw * The EEPROM 'termination_se' field contains a
4816be43703Skrw * bad value. Use automatic termination instead.
4826be43703Skrw */
4836be43703Skrw termination = 0;
4846be43703Skrw warn_code |= ADW_WARN_EEPROM_TERMINATION;
4856be43703Skrw }
4866be43703Skrw
4876be43703Skrw switch(eep_config.termination_lvd) {
4886be43703Skrw case 0:
4896be43703Skrw /* auto termination for LVD */
4906be43703Skrw sc->cfg.termination = termination;
4916be43703Skrw break;
4926be43703Skrw case 1:
4936be43703Skrw /* Enable manual control with low off / high off. */
4946be43703Skrw sc->cfg.termination = termination;
4956be43703Skrw break;
4966be43703Skrw case 2:
4976be43703Skrw /* Enable manual control with low off / high on. */
4986be43703Skrw sc->cfg.termination = termination | ADW_TERM_LVD_HI;
4996be43703Skrw break;
5006be43703Skrw case 3:
5016be43703Skrw /* Enable manual control with low on / high on. */
5026be43703Skrw sc->cfg.termination = termination | ADW_TERM_LVD;
5036be43703Skrw break;
5046be43703Skrw default:
5056be43703Skrw /*
5066be43703Skrw * The EEPROM 'termination_lvd' field contains a
5076be43703Skrw * bad value. Use automatic termination instead.
5086be43703Skrw */
5096be43703Skrw sc->cfg.termination = termination;
5106be43703Skrw warn_code |= ADW_WARN_EEPROM_TERMINATION;
5116be43703Skrw }
5126be43703Skrw break;
5136be43703Skrw }
5146be43703Skrw
5156be43703Skrw return warn_code;
5166be43703Skrw }
5176be43703Skrw
5186be43703Skrw
5196be43703Skrw /*
5206be43703Skrw * Initialize the ASC-3550/ASC-38C0800/ASC-38C1600.
5216be43703Skrw *
5226be43703Skrw * On failure return the error code.
5236be43703Skrw */
5246be43703Skrw int
AdwInitDriver(ADW_SOFTC * sc)525855b2726Sdhill AdwInitDriver(ADW_SOFTC *sc)
5266be43703Skrw {
5276be43703Skrw bus_space_tag_t iot = sc->sc_iot;
5286be43703Skrw bus_space_handle_t ioh = sc->sc_ioh;
5296be43703Skrw u_int16_t error_code;
5306be43703Skrw int word;
5316be43703Skrw int i;
5326be43703Skrw u_int16_t bios_mem[ADW_MC_BIOSLEN/2]; /* BIOS RISC Memory
5336be43703Skrw 0x40-0x8F. */
5346be43703Skrw u_int16_t wdtr_able = 0, sdtr_able, ppr_able, tagqng_able;
5356be43703Skrw u_int8_t max_cmd[ADW_MAX_TID + 1];
5366be43703Skrw u_int8_t tid;
5376be43703Skrw
5386be43703Skrw
5396be43703Skrw error_code = 0;
5406be43703Skrw
5416be43703Skrw /*
542379dd687Sdownsj * Save the RISC memory BIOS region before writing the microcode.
543379dd687Sdownsj * The BIOS may already be loaded and using its RISC LRAM region
544379dd687Sdownsj * so its region must be saved and restored.
545379dd687Sdownsj *
546379dd687Sdownsj * Note: This code makes the assumption, which is currently true,
547379dd687Sdownsj * that a chip reset does not clear RISC LRAM.
548379dd687Sdownsj */
5496be43703Skrw for (i = 0; i < ADW_MC_BIOSLEN/2; i++) {
5506be43703Skrw ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_BIOSMEM+(2*i), bios_mem[i]);
551466e5dfaSderaadt }
552466e5dfaSderaadt
553466e5dfaSderaadt /*
554466e5dfaSderaadt * Save current per TID negotiated values.
555466e5dfaSderaadt */
5566be43703Skrw switch (sc->chip_type) {
5576be43703Skrw case ADW_CHIP_ASC3550:
5586be43703Skrw if (bios_mem[(ADW_MC_BIOS_SIGNATURE-ADW_MC_BIOSMEM)/2]==0x55AA){
559466e5dfaSderaadt
560466e5dfaSderaadt u_int16_t bios_version, major, minor;
561466e5dfaSderaadt
5626be43703Skrw bios_version = bios_mem[(ADW_MC_BIOS_VERSION -
5636be43703Skrw ADW_MC_BIOSMEM) / 2];
564466e5dfaSderaadt major = (bios_version >> 12) & 0xF;
565466e5dfaSderaadt minor = (bios_version >> 8) & 0xF;
566466e5dfaSderaadt if (major < 3 || (major == 3 && minor == 1)) {
5676be43703Skrw /*
5686be43703Skrw * BIOS 3.1 and earlier location of
5696be43703Skrw * 'wdtr_able' variable.
5706be43703Skrw */
571466e5dfaSderaadt ADW_READ_WORD_LRAM(iot, ioh, 0x120, wdtr_able);
572466e5dfaSderaadt } else {
5736be43703Skrw ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_WDTR_ABLE,
5746be43703Skrw wdtr_able);
575466e5dfaSderaadt }
576466e5dfaSderaadt }
5776be43703Skrw break;
5786be43703Skrw
5796be43703Skrw case ADW_CHIP_ASC38C1600:
5806be43703Skrw ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_PPR_ABLE, ppr_able);
5816be43703Skrw /* FALLTHROUGH */
5826be43703Skrw case ADW_CHIP_ASC38C0800:
5836be43703Skrw ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_WDTR_ABLE, wdtr_able);
5846be43703Skrw break;
5856be43703Skrw }
5866be43703Skrw ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_SDTR_ABLE, sdtr_able);
5876be43703Skrw ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_TAGQNG_ABLE, tagqng_able);
588466e5dfaSderaadt for (tid = 0; tid <= ADW_MAX_TID; tid++) {
5896be43703Skrw ADW_READ_BYTE_LRAM(iot, ioh, ADW_MC_NUMBER_OF_MAX_CMD + tid,
590466e5dfaSderaadt max_cmd[tid]);
591379dd687Sdownsj }
592379dd687Sdownsj
593379dd687Sdownsj /*
5946be43703Skrw * Perform a RAM Built-In Self Test
5956be43703Skrw */
5966be43703Skrw if((error_code = AdwRamSelfTest(iot, ioh, sc->chip_type))) {
5976be43703Skrw return error_code;
5986be43703Skrw }
5996be43703Skrw
6006be43703Skrw /*
601379dd687Sdownsj * Load the Microcode
6026be43703Skrw */
6036be43703Skrw ;
6046be43703Skrw if((error_code = AdwLoadMCode(iot, ioh, bios_mem, sc->chip_type))) {
6056be43703Skrw return error_code;
6066be43703Skrw }
6076be43703Skrw
6086be43703Skrw /*
6096be43703Skrw * Read microcode version and date.
6106be43703Skrw */
6116be43703Skrw ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_VERSION_DATE, sc->cfg.mcode_date);
6126be43703Skrw ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_VERSION_NUM, sc->cfg.mcode_version);
6136be43703Skrw
6146be43703Skrw /*
6156be43703Skrw * If the PCI Configuration Command Register "Parity Error Response
6166be43703Skrw * Control" Bit was clear (0), then set the microcode variable
6176be43703Skrw * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
6186be43703Skrw * to ignore DMA parity errors.
6196be43703Skrw */
6206be43703Skrw if (sc->cfg.control_flag & CONTROL_FLAG_IGNORE_PERR) {
6216be43703Skrw ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_CONTROL_FLAG, word);
6226be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_CONTROL_FLAG,
6236be43703Skrw word | CONTROL_FLAG_IGNORE_PERR);
6246be43703Skrw }
6256be43703Skrw
6266be43703Skrw switch (sc->chip_type) {
6276be43703Skrw case ADW_CHIP_ASC3550:
6286be43703Skrw /*
6296be43703Skrw * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a
6306be43703Skrw * FIFO threshold of 128 bytes.
6316be43703Skrw * This register is only accessible to the host.
6326be43703Skrw */
6336be43703Skrw ADW_WRITE_BYTE_REGISTER(iot, ioh, IOPB_DMA_CFG0,
6346be43703Skrw START_CTL_EMFU | READ_CMD_MRM);
6356be43703Skrw break;
6366be43703Skrw
6376be43703Skrw case ADW_CHIP_ASC38C0800:
6386be43703Skrw /*
6396be43703Skrw * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
6406be43703Skrw * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
6416be43703Skrw * cable detection and then we are able to read C_DET[3:0].
642379dd687Sdownsj *
6436be43703Skrw * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
6446be43703Skrw * Microcode Default Value' section below.
6456be43703Skrw */
6466be43703Skrw ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_SCSI_CFG1,
6476be43703Skrw ADW_READ_WORD_REGISTER(iot, ioh, IOPW_SCSI_CFG1)
6486be43703Skrw | ADW_DIS_TERM_DRV);
6496be43703Skrw
6506be43703Skrw /*
6516be43703Skrw * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and
6526be43703Skrw * START_CTL_TH [3:2] bits for the default FIFO threshold.
6536be43703Skrw *
6546be43703Skrw * Note: ASC-38C0800 FIFO threshold has been changed to
6556be43703Skrw * 256 bytes.
6566be43703Skrw *
6576be43703Skrw * For DMA Errata #4 set the BC_THRESH_ENB bit.
6586be43703Skrw */
6596be43703Skrw ADW_WRITE_BYTE_REGISTER(iot, ioh, IOPB_DMA_CFG0,
6606be43703Skrw BC_THRESH_ENB | FIFO_THRESH_80B
6616be43703Skrw | START_CTL_TH | READ_CMD_MRM);
6626be43703Skrw break;
6636be43703Skrw
6646be43703Skrw case ADW_CHIP_ASC38C1600:
6656be43703Skrw /*
6666be43703Skrw * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
6676be43703Skrw * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
6686be43703Skrw * cable detection and then we are able to read C_DET[3:0].
6696be43703Skrw *
6706be43703Skrw * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
6716be43703Skrw * Microcode Default Value' section below.
6726be43703Skrw */
6736be43703Skrw ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_SCSI_CFG1,
6746be43703Skrw ADW_READ_WORD_REGISTER(iot, ioh, IOPW_SCSI_CFG1)
6756be43703Skrw | ADW_DIS_TERM_DRV);
6766be43703Skrw
6776be43703Skrw /*
6786be43703Skrw * If the BIOS control flag AIPP (Asynchronous Information
6796be43703Skrw * Phase Protection) disable bit is not set, then set the
6806be43703Skrw * firmware 'control_flag' CONTROL_FLAG_ENABLE_AIPP bit to
6816be43703Skrw * enable AIPP checking and encoding.
6826be43703Skrw */
6836be43703Skrw if ((sc->bios_ctrl & BIOS_CTRL_AIPP_DIS) == 0) {
6846be43703Skrw ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_CONTROL_FLAG, word);
6856be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_CONTROL_FLAG,
6866be43703Skrw word | CONTROL_FLAG_ENABLE_AIPP);
6876be43703Skrw }
6886be43703Skrw
6896be43703Skrw /*
6906be43703Skrw * For ASC-38C1600 use DMA_CFG0 default values:
6916be43703Skrw * FIFO_THRESH_80B [6:4], and START_CTL_TH [3:2].
6926be43703Skrw */
6936be43703Skrw ADW_WRITE_BYTE_REGISTER(iot, ioh, IOPB_DMA_CFG0,
6946be43703Skrw FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM);
6956be43703Skrw break;
6966be43703Skrw }
6976be43703Skrw
6986be43703Skrw /*
6996be43703Skrw * Microcode operating variables for WDTR, SDTR, and command tag
700a1d22770Skrw * queuing will be set in AdwInquiryHandling() based on what a
7016be43703Skrw * device reports it is capable of in Inquiry byte 7.
7026be43703Skrw *
7036be43703Skrw * If SCSI Bus Resets have been disabled, then directly set
7046be43703Skrw * SDTR and WDTR from the EEPROM configuration. This will allow
7056be43703Skrw * the BIOS and warm boot to work without a SCSI bus hang on
7066be43703Skrw * the Inquiry caused by host and target mismatched DTR values.
7076be43703Skrw * Without the SCSI Bus Reset, before an Inquiry a device can't
7086be43703Skrw * be assumed to be in Asynchronous, Narrow mode.
7096be43703Skrw */
7106be43703Skrw if ((sc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
7116be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_WDTR_ABLE, sc->wdtr_able);
7126be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_SDTR_ABLE, sc->sdtr_able);
7136be43703Skrw }
7146be43703Skrw
7156be43703Skrw /*
7166be43703Skrw * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2,
7176be43703Skrw * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID
7186be43703Skrw * bitmask. These values determine the maximum SDTR speed negotiated
7196be43703Skrw * with a device.
7206be43703Skrw *
7216be43703Skrw * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
7226be43703Skrw * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
7236be43703Skrw * without determining here whether the device supports SDTR.
7246be43703Skrw */
7256be43703Skrw switch (sc->chip_type) {
7266be43703Skrw case ADW_CHIP_ASC3550:
7276be43703Skrw word = 0;
7286be43703Skrw for (tid = 0; tid <= ADW_MAX_TID; tid++) {
7296be43703Skrw if (ADW_TID_TO_TIDMASK(tid) & sc->ultra_able) {
7306be43703Skrw /* Set Ultra speed for TID 'tid'. */
7316be43703Skrw word |= (0x3 << (4 * (tid % 4)));
7326be43703Skrw } else {
7336be43703Skrw /* Set Fast speed for TID 'tid'. */
7346be43703Skrw word |= (0x2 << (4 * (tid % 4)));
7356be43703Skrw }
7366be43703Skrw /* Check if done with sdtr_speed1. */
7376be43703Skrw if (tid == 3) {
7386be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh,
7396be43703Skrw ADW_MC_SDTR_SPEED1, word);
7406be43703Skrw word = 0;
7416be43703Skrw /* Check if done with sdtr_speed2. */
7426be43703Skrw } else if (tid == 7) {
7436be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh,
7446be43703Skrw ADW_MC_SDTR_SPEED2, word);
7456be43703Skrw word = 0;
7466be43703Skrw /* Check if done with sdtr_speed3. */
7476be43703Skrw } else if (tid == 11) {
7486be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh,
7496be43703Skrw ADW_MC_SDTR_SPEED3, word);
7506be43703Skrw word = 0;
7516be43703Skrw /* Check if done with sdtr_speed4. */
7526be43703Skrw } else if (tid == 15) {
7536be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh,
7546be43703Skrw ADW_MC_SDTR_SPEED4, word);
7556be43703Skrw /* End of loop. */
7566be43703Skrw }
7576be43703Skrw }
7586be43703Skrw
7596be43703Skrw /*
7606be43703Skrw * Set microcode operating variable for the
7616be43703Skrw * disconnect per TID bitmask.
7626be43703Skrw */
7636be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_DISC_ENABLE,
7646be43703Skrw sc->cfg.disc_enable);
7656be43703Skrw break;
7666be43703Skrw
7676be43703Skrw case ADW_CHIP_ASC38C0800:
7686be43703Skrw /* FALLTHROUGH */
7696be43703Skrw case ADW_CHIP_ASC38C1600:
7706be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_DISC_ENABLE,
7716be43703Skrw sc->cfg.disc_enable);
7726be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_SDTR_SPEED1,
7736be43703Skrw sc->sdtr_speed1);
7746be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_SDTR_SPEED2,
7756be43703Skrw sc->sdtr_speed2);
7766be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_SDTR_SPEED3,
7776be43703Skrw sc->sdtr_speed3);
7786be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_SDTR_SPEED4,
7796be43703Skrw sc->sdtr_speed4);
7806be43703Skrw break;
7816be43703Skrw }
7826be43703Skrw
7836be43703Skrw
7846be43703Skrw /*
7856be43703Skrw * Set SCSI_CFG0 Microcode Default Value.
7866be43703Skrw *
7876be43703Skrw * The microcode will set the SCSI_CFG0 register using this value
7886be43703Skrw * after it is started below.
7896be43703Skrw */
7906be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_DEFAULT_SCSI_CFG0,
7916be43703Skrw ADW_PARITY_EN | ADW_QUEUE_128 | ADW_SEL_TMO_LONG |
7926be43703Skrw ADW_OUR_ID_EN | sc->chip_scsi_id);
7936be43703Skrw
7946be43703Skrw
7956be43703Skrw switch(sc->chip_type) {
7966be43703Skrw case ADW_CHIP_ASC3550:
7976be43703Skrw error_code = AdwASC3550Cabling(iot, ioh, &sc->cfg);
7986be43703Skrw break;
7996be43703Skrw
8006be43703Skrw case ADW_CHIP_ASC38C0800:
8016be43703Skrw error_code = AdwASC38C0800Cabling(iot, ioh, &sc->cfg);
8026be43703Skrw break;
8036be43703Skrw
8046be43703Skrw case ADW_CHIP_ASC38C1600:
8056be43703Skrw error_code = AdwASC38C1600Cabling(iot, ioh, &sc->cfg);
8066be43703Skrw break;
8076be43703Skrw }
8086be43703Skrw if(error_code) {
8096be43703Skrw return error_code;
8106be43703Skrw }
8116be43703Skrw
8126be43703Skrw /*
8136be43703Skrw * Set SEL_MASK Microcode Default Value
8146be43703Skrw *
8156be43703Skrw * The microcode will set the SEL_MASK register using this value
8166be43703Skrw * after it is started below.
8176be43703Skrw */
8186be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_DEFAULT_SEL_MASK,
8196be43703Skrw ADW_TID_TO_TIDMASK(sc->chip_scsi_id));
8206be43703Skrw
8216be43703Skrw /*
8226be43703Skrw * Create and Initialize Host->RISC Carrier lists
8236be43703Skrw */
8246be43703Skrw sc->carr_freelist = AdwInitCarriers(sc->sc_dmamap_carrier,
8256be43703Skrw sc->sc_control->carriers);
8266be43703Skrw
8276be43703Skrw /*
8286be43703Skrw * Set-up the Host->RISC Initiator Command Queue (ICQ).
8296be43703Skrw */
8306be43703Skrw
8316be43703Skrw if ((sc->icq_sp = sc->carr_freelist) == NULL) {
8326be43703Skrw return ADW_IERR_NO_CARRIER;
8336be43703Skrw }
8346be43703Skrw sc->carr_freelist = ADW_CARRIER_VADDR(sc,
835a1d22770Skrw ADW_GET_CARRP(sc->icq_sp->next_ba));
8366be43703Skrw
8376be43703Skrw /*
8386be43703Skrw * The first command issued will be placed in the stopper carrier.
8396be43703Skrw */
840a1d22770Skrw sc->icq_sp->next_ba = ADW_CQ_STOPPER;
8416be43703Skrw
8426be43703Skrw /*
8436be43703Skrw * Set RISC ICQ physical address start value.
8446be43703Skrw */
8456be43703Skrw ADW_WRITE_DWORD_LRAM(iot, ioh, ADW_MC_ICQ, sc->icq_sp->carr_ba);
8466be43703Skrw
8476be43703Skrw /*
8486be43703Skrw * Initialize the COMMA register to the same value otherwise
8496be43703Skrw * the RISC will prematurely detect a command is available.
8506be43703Skrw */
8516be43703Skrw if(sc->chip_type == ADW_CHIP_ASC38C1600) {
8526be43703Skrw ADW_WRITE_DWORD_REGISTER(iot, ioh, IOPDW_COMMA,
8536be43703Skrw sc->icq_sp->carr_ba);
8546be43703Skrw }
8556be43703Skrw
8566be43703Skrw /*
8576be43703Skrw * Set-up the RISC->Host Initiator Response Queue (IRQ).
8586be43703Skrw */
8596be43703Skrw if ((sc->irq_sp = sc->carr_freelist) == NULL) {
8606be43703Skrw return ADW_IERR_NO_CARRIER;
8616be43703Skrw }
8626be43703Skrw sc->carr_freelist = ADW_CARRIER_VADDR(sc,
863a1d22770Skrw ADW_GET_CARRP(sc->irq_sp->next_ba));
8646be43703Skrw
8656be43703Skrw /*
8666be43703Skrw * The first command completed by the RISC will be placed in
8676be43703Skrw * the stopper.
8686be43703Skrw *
869a1d22770Skrw * Note: Set 'next_ba' to ADW_CQ_STOPPER. When the request is
870a1d22770Skrw * completed the RISC will set the ADW_RQ_DONE bit.
8716be43703Skrw */
872a1d22770Skrw sc->irq_sp->next_ba = ADW_CQ_STOPPER;
8736be43703Skrw
8746be43703Skrw /*
8756be43703Skrw * Set RISC IRQ physical address start value.
8766be43703Skrw */
8776be43703Skrw ADW_WRITE_DWORD_LRAM(iot, ioh, ADW_MC_IRQ, sc->irq_sp->carr_ba);
8786be43703Skrw sc->carr_pending_cnt = 0;
8796be43703Skrw
8806be43703Skrw ADW_WRITE_BYTE_REGISTER(iot, ioh, IOPB_INTR_ENABLES,
8816be43703Skrw (ADW_INTR_ENABLE_HOST_INTR | ADW_INTR_ENABLE_GLOBAL_INTR));
8826be43703Skrw ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_CODE_BEGIN_ADDR, word);
8836be43703Skrw ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_PC, word);
8846be43703Skrw
8856be43703Skrw /* finally, finally, gentlemen, start your engine */
8866be43703Skrw ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_RISC_CSR, ADW_RISC_CSR_RUN);
8876be43703Skrw
8886be43703Skrw /*
8896be43703Skrw * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
8906be43703Skrw * Resets should be performed. The RISC has to be running
8916be43703Skrw * to issue a SCSI Bus Reset.
8926be43703Skrw */
8936be43703Skrw if (sc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS)
8946be43703Skrw {
8956be43703Skrw /*
8966be43703Skrw * If the BIOS Signature is present in memory, restore the
8976be43703Skrw * BIOS Handshake Configuration Table and do not perform
8986be43703Skrw * a SCSI Bus Reset.
8996be43703Skrw */
9006be43703Skrw if (bios_mem[(ADW_MC_BIOS_SIGNATURE - ADW_MC_BIOSMEM)/2] ==
9016be43703Skrw 0x55AA) {
9026be43703Skrw /*
9036be43703Skrw * Restore per TID negotiated values.
9046be43703Skrw */
9056be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_WDTR_ABLE,
9066be43703Skrw wdtr_able);
9076be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_SDTR_ABLE,
9086be43703Skrw sdtr_able);
9096be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_TAGQNG_ABLE,
9106be43703Skrw tagqng_able);
9116be43703Skrw for (tid = 0; tid <= ADW_MAX_TID; tid++) {
9126be43703Skrw ADW_WRITE_BYTE_LRAM(iot, ioh,
9136be43703Skrw ADW_MC_NUMBER_OF_MAX_CMD + tid,
9146be43703Skrw max_cmd[tid]);
9156be43703Skrw }
9166be43703Skrw } else {
9176be43703Skrw if (AdwResetCCB(sc) != ADW_TRUE) {
9186be43703Skrw error_code = ADW_WARN_BUSRESET_ERROR;
9196be43703Skrw }
9206be43703Skrw }
9216be43703Skrw }
9226be43703Skrw
9236be43703Skrw return error_code;
9246be43703Skrw }
9256be43703Skrw
9266be43703Skrw
9276be43703Skrw int
AdwRamSelfTest(bus_space_tag_t iot,bus_space_handle_t ioh,u_int8_t chip_type)928855b2726Sdhill AdwRamSelfTest(bus_space_tag_t iot, bus_space_handle_t ioh, u_int8_t chip_type)
9296be43703Skrw {
9306be43703Skrw int i;
9316be43703Skrw u_int8_t byte;
9326be43703Skrw
9336be43703Skrw
9346be43703Skrw if ((chip_type == ADW_CHIP_ASC38C0800) ||
9356be43703Skrw (chip_type == ADW_CHIP_ASC38C1600)) {
9366be43703Skrw /*
9376be43703Skrw * RAM BIST (RAM Built-In Self Test)
9386be43703Skrw *
9396be43703Skrw * Address : I/O base + offset 0x38h register (byte).
9406be43703Skrw * Function: Bit 7-6(RW) : RAM mode
9416be43703Skrw * Normal Mode : 0x00
9426be43703Skrw * Pre-test Mode : 0x40
9436be43703Skrw * RAM Test Mode : 0x80
9446be43703Skrw * Bit 5 : unused
9456be43703Skrw * Bit 4(RO) : Done bit
9466be43703Skrw * Bit 3-0(RO) : Status
9476be43703Skrw * Host Error : 0x08
9486be43703Skrw * Int_RAM Error : 0x04
9496be43703Skrw * RISC Error : 0x02
9506be43703Skrw * SCSI Error : 0x01
9516be43703Skrw * No Error : 0x00
9526be43703Skrw *
9536be43703Skrw * Note: RAM BIST code should be put right here, before loading
9546be43703Skrw * the microcode and after saving the RISC memory BIOS region.
9556be43703Skrw */
9566be43703Skrw
9576be43703Skrw /*
9586be43703Skrw * LRAM Pre-test
9596be43703Skrw *
9606be43703Skrw * Write PRE_TEST_MODE (0x40) to register and wait for
9616be43703Skrw * 10 milliseconds.
9626be43703Skrw * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05),
9636be43703Skrw * return an error. Reset to NORMAL_MODE (0x00) and do again.
9646be43703Skrw * If cannot reset to NORMAL_MODE, return an error too.
9656be43703Skrw */
9666be43703Skrw for (i = 0; i < 2; i++) {
9676be43703Skrw ADW_WRITE_BYTE_REGISTER(iot, ioh, IOPB_RAM_BIST,
9686be43703Skrw PRE_TEST_MODE);
9696be43703Skrw /* Wait for 10ms before reading back. */
9706be43703Skrw AdwSleepMilliSecond(10);
9716be43703Skrw byte = ADW_READ_BYTE_REGISTER(iot, ioh, IOPB_RAM_BIST);
9726be43703Skrw if ((byte & RAM_TEST_DONE) == 0 || (byte & 0x0F) !=
9736be43703Skrw PRE_TEST_VALUE) {
9746be43703Skrw return ADW_IERR_BIST_PRE_TEST;
9756be43703Skrw }
9766be43703Skrw
9776be43703Skrw ADW_WRITE_BYTE_REGISTER(iot, ioh, IOPB_RAM_BIST,
9786be43703Skrw NORMAL_MODE);
9796be43703Skrw /* Wait for 10ms before reading back. */
9806be43703Skrw AdwSleepMilliSecond(10);
9816be43703Skrw if (ADW_READ_BYTE_REGISTER(iot, ioh, IOPB_RAM_BIST)
9826be43703Skrw != NORMAL_VALUE) {
9836be43703Skrw return ADW_IERR_BIST_PRE_TEST;
9846be43703Skrw }
9856be43703Skrw }
9866be43703Skrw
9876be43703Skrw /*
9886be43703Skrw * LRAM Test - It takes about 1.5 ms to run through the test.
9896be43703Skrw *
9906be43703Skrw * Write RAM_TEST_MODE (0x80) to register and wait for
9916be43703Skrw * 10 milliseconds.
9926be43703Skrw * If Done bit not set or Status not 0, save register byte,
9936be43703Skrw * set the err_code, and return an error.
9946be43703Skrw */
9956be43703Skrw ADW_WRITE_BYTE_REGISTER(iot, ioh, IOPB_RAM_BIST, RAM_TEST_MODE);
9966be43703Skrw /* Wait for 10ms before checking status. */
9976be43703Skrw AdwSleepMilliSecond(10);
9986be43703Skrw
9996be43703Skrw byte = ADW_READ_BYTE_REGISTER(iot, ioh, IOPB_RAM_BIST);
10006be43703Skrw if ((byte & RAM_TEST_DONE)==0 || (byte & RAM_TEST_STATUS)!=0) {
10016be43703Skrw /* Get here if Done bit not set or Status not 0. */
10026be43703Skrw return ADW_IERR_BIST_RAM_TEST;
10036be43703Skrw }
10046be43703Skrw
10056be43703Skrw /* We need to reset back to normal mode after LRAM test passes*/
10066be43703Skrw ADW_WRITE_BYTE_REGISTER(iot, ioh, IOPB_RAM_BIST, NORMAL_MODE);
10076be43703Skrw }
10086be43703Skrw
10096be43703Skrw return 0;
10106be43703Skrw }
10116be43703Skrw
10126be43703Skrw
10136be43703Skrw int
AdwLoadMCode(bus_space_tag_t iot,bus_space_handle_t ioh,u_int16_t * bios_mem,u_int8_t chip_type)1014855b2726Sdhill AdwLoadMCode(bus_space_tag_t iot, bus_space_handle_t ioh, u_int16_t *bios_mem,
1015855b2726Sdhill u_int8_t chip_type)
10166be43703Skrw {
1017826c7026Stedu u_int8_t *mcode_data = NULL;
1018826c7026Stedu u_int32_t mcode_chksum = 0;
1019826c7026Stedu u_int16_t mcode_size = 0;
10206be43703Skrw u_int32_t sum;
10216be43703Skrw u_int16_t code_sum;
10226be43703Skrw int begin_addr;
10236be43703Skrw int end_addr;
10246be43703Skrw int word;
1025826c7026Stedu int adw_memsize = 0;
10266be43703Skrw int adw_mcode_expanded_size;
10276be43703Skrw int i, j;
10286be43703Skrw
10296be43703Skrw
10306be43703Skrw switch(chip_type) {
10316be43703Skrw case ADW_CHIP_ASC3550:
10326be43703Skrw mcode_data = (u_int8_t *)adw_asc3550_mcode_data.mcode_data;
10336be43703Skrw mcode_chksum = (u_int32_t)adw_asc3550_mcode_data.mcode_chksum;
10346be43703Skrw mcode_size = (u_int16_t)adw_asc3550_mcode_data.mcode_size;
10356be43703Skrw adw_memsize = ADW_3550_MEMSIZE;
10366be43703Skrw break;
10376be43703Skrw
10386be43703Skrw case ADW_CHIP_ASC38C0800:
10396be43703Skrw mcode_data = (u_int8_t *)adw_asc38C0800_mcode_data.mcode_data;
10406be43703Skrw mcode_chksum =(u_int32_t)adw_asc38C0800_mcode_data.mcode_chksum;
10416be43703Skrw mcode_size = (u_int16_t)adw_asc38C0800_mcode_data.mcode_size;
10426be43703Skrw adw_memsize = ADW_38C0800_MEMSIZE;
10436be43703Skrw break;
10446be43703Skrw
10456be43703Skrw case ADW_CHIP_ASC38C1600:
10466be43703Skrw mcode_data = (u_int8_t *)adw_asc38C1600_mcode_data.mcode_data;
10476be43703Skrw mcode_chksum =(u_int32_t)adw_asc38C1600_mcode_data.mcode_chksum;
10486be43703Skrw mcode_size = (u_int16_t)adw_asc38C1600_mcode_data.mcode_size;
10496be43703Skrw adw_memsize = ADW_38C1600_MEMSIZE;
10506be43703Skrw break;
10516be43703Skrw }
10526be43703Skrw
10536be43703Skrw /*
1054379dd687Sdownsj * Write the microcode image to RISC memory starting at address 0.
1055379dd687Sdownsj */
1056379dd687Sdownsj ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_RAM_ADDR, 0);
1057466e5dfaSderaadt
1058466e5dfaSderaadt /* Assume the following compressed format of the microcode buffer:
1059466e5dfaSderaadt *
1060466e5dfaSderaadt * 254 word (508 byte) table indexed by byte code followed
1061466e5dfaSderaadt * by the following byte codes:
1062466e5dfaSderaadt *
1063466e5dfaSderaadt * 1-Byte Code:
1064466e5dfaSderaadt * 00: Emit word 0 in table.
1065466e5dfaSderaadt * 01: Emit word 1 in table.
1066466e5dfaSderaadt * .
1067466e5dfaSderaadt * FD: Emit word 253 in table.
1068466e5dfaSderaadt *
1069466e5dfaSderaadt * Multi-Byte Code:
1070466e5dfaSderaadt * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
1071466e5dfaSderaadt * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
1072466e5dfaSderaadt */
1073466e5dfaSderaadt word = 0;
10746be43703Skrw for (i = 253 * 2; i < mcode_size; i++) {
10756be43703Skrw if (mcode_data[i] == 0xff) {
10766be43703Skrw for (j = 0; j < mcode_data[i + 1]; j++) {
1077379dd687Sdownsj ADW_WRITE_WORD_AUTO_INC_LRAM(iot, ioh,
10786be43703Skrw (((u_int16_t)mcode_data[i + 3] << 8) |
10796be43703Skrw mcode_data[i + 2]));
1080466e5dfaSderaadt word++;
1081466e5dfaSderaadt }
1082466e5dfaSderaadt i += 3;
10836be43703Skrw } else if (mcode_data[i] == 0xfe) {
1084466e5dfaSderaadt ADW_WRITE_WORD_AUTO_INC_LRAM(iot, ioh,
10856be43703Skrw (((u_int16_t)mcode_data[i + 2] << 8) |
10866be43703Skrw mcode_data[i + 1]));
1087466e5dfaSderaadt i += 2;
1088466e5dfaSderaadt word++;
1089466e5dfaSderaadt } else {
1090466e5dfaSderaadt ADW_WRITE_WORD_AUTO_INC_LRAM(iot, ioh, (((u_int16_t)
10916be43703Skrw mcode_data[(mcode_data[i] * 2) + 1] <<8) |
10926be43703Skrw mcode_data[mcode_data[i] * 2]));
1093466e5dfaSderaadt word++;
1094466e5dfaSderaadt }
1095379dd687Sdownsj }
1096379dd687Sdownsj
1097379dd687Sdownsj /*
1098466e5dfaSderaadt * Set 'word' for later use to clear the rest of memory and save
1099466e5dfaSderaadt * the expanded mcode size.
1100379dd687Sdownsj */
1101466e5dfaSderaadt word *= 2;
11026be43703Skrw adw_mcode_expanded_size = word;
1103466e5dfaSderaadt
1104466e5dfaSderaadt /*
11056be43703Skrw * Clear the rest of the Internal RAM.
1106466e5dfaSderaadt */
11076be43703Skrw for (; word < adw_memsize; word += 2) {
1108379dd687Sdownsj ADW_WRITE_WORD_AUTO_INC_LRAM(iot, ioh, 0);
1109379dd687Sdownsj }
1110379dd687Sdownsj
1111379dd687Sdownsj /*
1112379dd687Sdownsj * Verify the microcode checksum.
1113379dd687Sdownsj */
1114379dd687Sdownsj sum = 0;
1115379dd687Sdownsj ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_RAM_ADDR, 0);
1116466e5dfaSderaadt
11176be43703Skrw for (word = 0; word < adw_mcode_expanded_size; word += 2) {
1118379dd687Sdownsj sum += ADW_READ_WORD_AUTO_INC_LRAM(iot, ioh);
1119379dd687Sdownsj }
1120379dd687Sdownsj
11216be43703Skrw if (sum != mcode_chksum) {
11226be43703Skrw return ADW_IERR_MCODE_CHKSUM;
1123466e5dfaSderaadt }
1124379dd687Sdownsj
1125379dd687Sdownsj /*
1126379dd687Sdownsj * Restore the RISC memory BIOS region.
1127379dd687Sdownsj */
11286be43703Skrw for (i = 0; i < ADW_MC_BIOSLEN/2; i++) {
11296be43703Skrw if(chip_type == ADW_CHIP_ASC3550) {
11306be43703Skrw ADW_WRITE_BYTE_LRAM(iot, ioh, ADW_MC_BIOSMEM + (2 * i),
1131466e5dfaSderaadt bios_mem[i]);
11326be43703Skrw } else {
11336be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_BIOSMEM + (2 * i),
11346be43703Skrw bios_mem[i]);
11356be43703Skrw }
1136379dd687Sdownsj }
1137379dd687Sdownsj
1138379dd687Sdownsj /*
1139379dd687Sdownsj * Calculate and write the microcode code checksum to the microcode
11406be43703Skrw * code checksum location ADW_MC_CODE_CHK_SUM (0x2C).
1141379dd687Sdownsj */
11426be43703Skrw ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_CODE_BEGIN_ADDR, begin_addr);
11436be43703Skrw ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_CODE_END_ADDR, end_addr);
1144379dd687Sdownsj code_sum = 0;
1145466e5dfaSderaadt ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_RAM_ADDR, begin_addr);
1146379dd687Sdownsj for (word = begin_addr; word < end_addr; word += 2) {
1147466e5dfaSderaadt code_sum += ADW_READ_WORD_AUTO_INC_LRAM(iot, ioh);
1148379dd687Sdownsj }
11496be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_CODE_CHK_SUM, code_sum);
1150379dd687Sdownsj
1151379dd687Sdownsj /*
11526be43703Skrw * Set the chip type.
1153379dd687Sdownsj */
11546be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_CHIP_TYPE, chip_type);
1155379dd687Sdownsj
11566be43703Skrw return 0;
1157379dd687Sdownsj }
1158379dd687Sdownsj
1159466e5dfaSderaadt
11606be43703Skrw int
AdwASC3550Cabling(bus_space_tag_t iot,bus_space_handle_t ioh,ADW_DVC_CFG * cfg)1161855b2726Sdhill AdwASC3550Cabling(bus_space_tag_t iot, bus_space_handle_t ioh, ADW_DVC_CFG *cfg)
11626be43703Skrw {
11636be43703Skrw u_int16_t scsi_cfg1;
1164466e5dfaSderaadt
1165379dd687Sdownsj
1166379dd687Sdownsj /*
1167379dd687Sdownsj * Determine SCSI_CFG1 Microcode Default Value.
1168379dd687Sdownsj *
1169379dd687Sdownsj * The microcode will set the SCSI_CFG1 register using this value
1170379dd687Sdownsj * after it is started below.
1171379dd687Sdownsj */
1172379dd687Sdownsj
1173379dd687Sdownsj /* Read current SCSI_CFG1 Register value. */
1174379dd687Sdownsj scsi_cfg1 = ADW_READ_WORD_REGISTER(iot, ioh, IOPW_SCSI_CFG1);
1175379dd687Sdownsj
1176379dd687Sdownsj /*
11776be43703Skrw * If all three connectors are in use in ASC3550, return an error.
1178379dd687Sdownsj */
1179379dd687Sdownsj if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 ||
1180379dd687Sdownsj (scsi_cfg1 & CABLE_ILLEGAL_B) == 0) {
11816be43703Skrw return ADW_IERR_ILLEGAL_CONNECTION;
1182379dd687Sdownsj }
1183466e5dfaSderaadt
1184379dd687Sdownsj /*
11856be43703Skrw * If the cable is reversed all of the SCSI_CTRL register signals
11866be43703Skrw * will be set. Check for and return an error if this condition is
11876be43703Skrw * found.
1188379dd687Sdownsj */
11896be43703Skrw if ((ADW_READ_WORD_REGISTER(iot,ioh, IOPW_SCSI_CTRL) & 0x3F07)==0x3F07){
11906be43703Skrw return ADW_IERR_REVERSED_CABLE;
1191379dd687Sdownsj }
1192379dd687Sdownsj
1193379dd687Sdownsj /*
1194379dd687Sdownsj * If this is a differential board and a single-ended device
1195379dd687Sdownsj * is attached to one of the connectors, return an error.
1196379dd687Sdownsj */
11976be43703Skrw if ((scsi_cfg1 & ADW_DIFF_MODE) &&
11986be43703Skrw (scsi_cfg1 & ADW_DIFF_SENSE) == 0) {
11996be43703Skrw return ADW_IERR_SINGLE_END_DEVICE;
1200466e5dfaSderaadt }
1201379dd687Sdownsj
1202379dd687Sdownsj /*
1203379dd687Sdownsj * If automatic termination control is enabled, then set the
1204466e5dfaSderaadt * termination value based on a table listed in a_condor.h.
1205379dd687Sdownsj *
1206379dd687Sdownsj * If manual termination was specified with an EEPROM setting
12076be43703Skrw * then 'termination' was set-up in AdwInitFromEEPROM() and
1208379dd687Sdownsj * is ready to be 'ored' into SCSI_CFG1.
1209379dd687Sdownsj */
12106be43703Skrw if (cfg->termination == 0) {
1211379dd687Sdownsj /*
12126be43703Skrw * The software always controls termination by setting
12136be43703Skrw * TERM_CTL_SEL.
12146be43703Skrw * If TERM_CTL_SEL were set to 0, the hardware would set
12156be43703Skrw * termination.
1216379dd687Sdownsj */
12176be43703Skrw cfg->termination |= ADW_TERM_CTL_SEL;
1218379dd687Sdownsj
1219379dd687Sdownsj switch(scsi_cfg1 & ADW_CABLE_DETECT) {
1220466e5dfaSderaadt /* TERM_CTL_H: on, TERM_CTL_L: on */
12216be43703Skrw case 0x3: case 0x7: case 0xB:
12226be43703Skrw case 0xD: case 0xE: case 0xF:
12236be43703Skrw cfg->termination |=
12246be43703Skrw (ADW_TERM_CTL_H | ADW_TERM_CTL_L);
1225379dd687Sdownsj break;
1226379dd687Sdownsj
1227466e5dfaSderaadt /* TERM_CTL_H: on, TERM_CTL_L: off */
12286be43703Skrw case 0x1: case 0x5: case 0x9:
12296be43703Skrw case 0xA: case 0xC:
12306be43703Skrw cfg->termination |= ADW_TERM_CTL_H;
1231379dd687Sdownsj break;
1232379dd687Sdownsj
1233466e5dfaSderaadt /* TERM_CTL_H: off, TERM_CTL_L: off */
1234466e5dfaSderaadt case 0x2: case 0x6:
1235379dd687Sdownsj break;
1236379dd687Sdownsj }
1237379dd687Sdownsj }
1238466e5dfaSderaadt
1239379dd687Sdownsj /*
1240466e5dfaSderaadt * Clear any set TERM_CTL_H and TERM_CTL_L bits.
1241379dd687Sdownsj */
1242379dd687Sdownsj scsi_cfg1 &= ~ADW_TERM_CTL;
1243379dd687Sdownsj
1244379dd687Sdownsj /*
1245466e5dfaSderaadt * Invert the TERM_CTL_H and TERM_CTL_L bits and then
1246466e5dfaSderaadt * set 'scsi_cfg1'. The TERM_POL bit does not need to be
1247379dd687Sdownsj * referenced, because the hardware internally inverts
1248466e5dfaSderaadt * the Termination High and Low bits if TERM_POL is set.
1249379dd687Sdownsj */
12506be43703Skrw scsi_cfg1 |= (ADW_TERM_CTL_SEL | (~cfg->termination & ADW_TERM_CTL));
1251379dd687Sdownsj
1252379dd687Sdownsj /*
1253379dd687Sdownsj * Set SCSI_CFG1 Microcode Default Value
1254379dd687Sdownsj *
1255379dd687Sdownsj * Set filter value and possibly modified termination control
1256379dd687Sdownsj * bits in the Microcode SCSI_CFG1 Register Value.
1257379dd687Sdownsj *
1258379dd687Sdownsj * The microcode will set the SCSI_CFG1 register using this value
1259379dd687Sdownsj * after it is started below.
1260379dd687Sdownsj */
12616be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_DEFAULT_SCSI_CFG1,
1262466e5dfaSderaadt ADW_FLTR_DISABLE | scsi_cfg1);
1263466e5dfaSderaadt
1264466e5dfaSderaadt /*
1265466e5dfaSderaadt * Set MEM_CFG Microcode Default Value
1266466e5dfaSderaadt *
1267466e5dfaSderaadt * The microcode will set the MEM_CFG register using this value
1268466e5dfaSderaadt * after it is started below.
1269466e5dfaSderaadt *
1270466e5dfaSderaadt * MEM_CFG may be accessed as a word or byte, but only bits 0-7
1271466e5dfaSderaadt * are defined.
1272466e5dfaSderaadt *
1273466e5dfaSderaadt * ASC-3550 has 8KB internal memory.
1274466e5dfaSderaadt */
12756be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_DEFAULT_MEM_CFG,
1276466e5dfaSderaadt ADW_BIOS_EN | ADW_RAM_SZ_8KB);
1277379dd687Sdownsj
12786be43703Skrw return 0;
1279dfb9bd9fSkrw }
1280466e5dfaSderaadt
1281466e5dfaSderaadt
1282466e5dfaSderaadt int
AdwASC38C0800Cabling(bus_space_tag_t iot,bus_space_handle_t ioh,ADW_DVC_CFG * cfg)1283855b2726Sdhill AdwASC38C0800Cabling(bus_space_tag_t iot, bus_space_handle_t ioh,
1284855b2726Sdhill ADW_DVC_CFG *cfg)
1285466e5dfaSderaadt {
1286466e5dfaSderaadt u_int16_t scsi_cfg1;
1287466e5dfaSderaadt
1288466e5dfaSderaadt
1289466e5dfaSderaadt /*
1290466e5dfaSderaadt * Determine SCSI_CFG1 Microcode Default Value.
1291466e5dfaSderaadt *
1292466e5dfaSderaadt * The microcode will set the SCSI_CFG1 register using this value
1293466e5dfaSderaadt * after it is started below.
1294466e5dfaSderaadt */
1295466e5dfaSderaadt
1296466e5dfaSderaadt /* Read current SCSI_CFG1 Register value. */
1297466e5dfaSderaadt scsi_cfg1 = ADW_READ_WORD_REGISTER(iot, ioh, IOPW_SCSI_CFG1);
1298466e5dfaSderaadt
1299466e5dfaSderaadt /*
13006be43703Skrw * If the cable is reversed all of the SCSI_CTRL register signals
13016be43703Skrw * will be set. Check for and return an error if this condition is
13026be43703Skrw * found.
1303466e5dfaSderaadt */
13046be43703Skrw if ((ADW_READ_WORD_REGISTER(iot,ioh, IOPW_SCSI_CTRL) & 0x3F07)==0x3F07){
13056be43703Skrw return ADW_IERR_REVERSED_CABLE;
1306466e5dfaSderaadt }
1307466e5dfaSderaadt
1308466e5dfaSderaadt /*
13096be43703Skrw * All kind of combinations of devices attached to one of four
13106be43703Skrw * connectors are acceptable except HVD device attached.
13116be43703Skrw * For example, LVD device can be attached to SE connector while
13126be43703Skrw * SE device attached to LVD connector.
13136be43703Skrw * If LVD device attached to SE connector, it only runs up to
13146be43703Skrw * Ultra speed.
1315466e5dfaSderaadt *
13166be43703Skrw * If an HVD device is attached to one of LVD connectors, return
13176be43703Skrw * an error.
13186be43703Skrw * However, there is no way to detect HVD device attached to
13196be43703Skrw * SE connectors.
1320466e5dfaSderaadt */
1321466e5dfaSderaadt if (scsi_cfg1 & ADW_HVD) {
13226be43703Skrw return ADW_IERR_HVD_DEVICE;
1323466e5dfaSderaadt }
1324466e5dfaSderaadt
1325466e5dfaSderaadt /*
1326466e5dfaSderaadt * If either SE or LVD automatic termination control is enabled, then
1327466e5dfaSderaadt * set the termination value based on a table listed in a_condor.h.
1328466e5dfaSderaadt *
1329466e5dfaSderaadt * If manual termination was specified with an EEPROM setting then
13306be43703Skrw * 'termination' was set-up in AdwInitFromEEPROM() and is ready
13316be43703Skrw * to be 'ored' into SCSI_CFG1.
1332466e5dfaSderaadt */
13336be43703Skrw if ((cfg->termination & ADW_TERM_SE) == 0) {
1334466e5dfaSderaadt /* SE automatic termination control is enabled. */
1335466e5dfaSderaadt switch(scsi_cfg1 & ADW_C_DET_SE) {
1336466e5dfaSderaadt /* TERM_SE_HI: on, TERM_SE_LO: on */
1337466e5dfaSderaadt case 0x1: case 0x2: case 0x3:
13386be43703Skrw cfg->termination |= ADW_TERM_SE;
1339466e5dfaSderaadt break;
1340466e5dfaSderaadt
1341466e5dfaSderaadt /* TERM_SE_HI: on, TERM_SE_LO: off */
1342466e5dfaSderaadt case 0x0:
13436be43703Skrw cfg->termination |= ADW_TERM_SE_HI;
1344466e5dfaSderaadt break;
1345466e5dfaSderaadt }
1346466e5dfaSderaadt }
1347466e5dfaSderaadt
13486be43703Skrw if ((cfg->termination & ADW_TERM_LVD) == 0) {
1349466e5dfaSderaadt /* LVD automatic termination control is enabled. */
1350466e5dfaSderaadt switch(scsi_cfg1 & ADW_C_DET_LVD) {
1351466e5dfaSderaadt /* TERM_LVD_HI: on, TERM_LVD_LO: on */
1352466e5dfaSderaadt case 0x4: case 0x8: case 0xC:
13536be43703Skrw cfg->termination |= ADW_TERM_LVD;
1354466e5dfaSderaadt break;
1355466e5dfaSderaadt
1356466e5dfaSderaadt /* TERM_LVD_HI: off, TERM_LVD_LO: off */
1357466e5dfaSderaadt case 0x0:
1358466e5dfaSderaadt break;
1359466e5dfaSderaadt }
1360466e5dfaSderaadt }
1361466e5dfaSderaadt
1362466e5dfaSderaadt /*
1363466e5dfaSderaadt * Clear any set TERM_SE and TERM_LVD bits.
1364466e5dfaSderaadt */
1365466e5dfaSderaadt scsi_cfg1 &= (~ADW_TERM_SE & ~ADW_TERM_LVD);
1366466e5dfaSderaadt
1367466e5dfaSderaadt /*
1368466e5dfaSderaadt * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'.
1369466e5dfaSderaadt */
13706be43703Skrw scsi_cfg1 |= (~cfg->termination & 0xF0);
1371466e5dfaSderaadt
1372466e5dfaSderaadt /*
13736be43703Skrw * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and
13746be43703Skrw * HVD/LVD/SE bits and set possibly modified termination control bits
13756be43703Skrw * in the Microcode SCSI_CFG1 Register Value.
1376466e5dfaSderaadt */
1377466e5dfaSderaadt scsi_cfg1 &= (~ADW_BIG_ENDIAN & ~ADW_DIS_TERM_DRV &
1378466e5dfaSderaadt ~ADW_TERM_POL & ~ADW_HVD_LVD_SE);
1379466e5dfaSderaadt
1380466e5dfaSderaadt /*
1381466e5dfaSderaadt * Set SCSI_CFG1 Microcode Default Value
1382466e5dfaSderaadt *
1383466e5dfaSderaadt * Set possibly modified termination control and reset DIS_TERM_DRV
1384466e5dfaSderaadt * bits in the Microcode SCSI_CFG1 Register Value.
1385466e5dfaSderaadt *
1386466e5dfaSderaadt * The microcode will set the SCSI_CFG1 register using this value
1387466e5dfaSderaadt * after it is started below.
1388466e5dfaSderaadt */
13896be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
1390466e5dfaSderaadt
1391466e5dfaSderaadt /*
1392466e5dfaSderaadt * Set MEM_CFG Microcode Default Value
1393466e5dfaSderaadt *
1394466e5dfaSderaadt * The microcode will set the MEM_CFG register using this value
1395466e5dfaSderaadt * after it is started below.
1396466e5dfaSderaadt *
1397466e5dfaSderaadt * MEM_CFG may be accessed as a word or byte, but only bits 0-7
1398466e5dfaSderaadt * are defined.
1399466e5dfaSderaadt *
1400466e5dfaSderaadt * ASC-38C0800 has 16KB internal memory.
1401466e5dfaSderaadt */
14026be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_DEFAULT_MEM_CFG,
1403466e5dfaSderaadt ADW_BIOS_EN | ADW_RAM_SZ_16KB);
1404466e5dfaSderaadt
14056be43703Skrw return 0;
14066be43703Skrw }
14076be43703Skrw
14086be43703Skrw
14096be43703Skrw int
AdwASC38C1600Cabling(bus_space_tag_t iot,bus_space_handle_t ioh,ADW_DVC_CFG * cfg)1410855b2726Sdhill AdwASC38C1600Cabling(bus_space_tag_t iot, bus_space_handle_t ioh,
1411855b2726Sdhill ADW_DVC_CFG *cfg)
14126be43703Skrw {
14136be43703Skrw u_int16_t scsi_cfg1;
14146be43703Skrw
14156be43703Skrw
1416466e5dfaSderaadt /*
14176be43703Skrw * Determine SCSI_CFG1 Microcode Default Value.
1418466e5dfaSderaadt *
14196be43703Skrw * The microcode will set the SCSI_CFG1 register using this value
14206be43703Skrw * after it is started below.
14216be43703Skrw * Each ASC-38C1600 function has only two cable detect bits.
14226be43703Skrw * The bus mode override bits are in IOPB_SOFT_OVER_WR.
14236be43703Skrw */
14246be43703Skrw
14256be43703Skrw /* Read current SCSI_CFG1 Register value. */
14266be43703Skrw scsi_cfg1 = ADW_READ_WORD_REGISTER(iot, ioh, IOPW_SCSI_CFG1);
14276be43703Skrw
14286be43703Skrw /*
14296be43703Skrw * If the cable is reversed all of the SCSI_CTRL register signals
14306be43703Skrw * will be set. Check for and return an error if this condition is
14316be43703Skrw * found.
14326be43703Skrw */
14336be43703Skrw if ((ADW_READ_WORD_REGISTER(iot,ioh, IOPW_SCSI_CTRL) & 0x3F07)==0x3F07){
14346be43703Skrw return ADW_IERR_REVERSED_CABLE;
14356be43703Skrw }
14366be43703Skrw
14376be43703Skrw /*
14386be43703Skrw * Each ASC-38C1600 function has two connectors. Only an HVD device
14396be43703Skrw * cannot be connected to either connector. An LVD device or SE device
14402408ed96Sjmc * may be connected to either connector. If an SE device is connected,
144154c6c021Smickey * then at most Ultra speed (20 MHz) can be used on both connectors.
14426be43703Skrw *
14436be43703Skrw * If an HVD device is attached, return an error.
14446be43703Skrw */
14456be43703Skrw if (scsi_cfg1 & ADW_HVD) {
14466be43703Skrw return ADW_IERR_HVD_DEVICE;
14476be43703Skrw }
14486be43703Skrw
14496be43703Skrw /*
14506be43703Skrw * Each function in the ASC-38C1600 uses only the SE cable detect and
14516be43703Skrw * termination because there are two connectors for each function.
14526be43703Skrw * Each function may use either LVD or SE mode.
14536be43703Skrw * Corresponding the SE automatic termination control EEPROM bits are
14546be43703Skrw * used for each function.
14556be43703Skrw * Each function has its own EEPROM. If SE automatic control is enabled
14566be43703Skrw * for the function, then set the termination value based on a table
14576be43703Skrw * listed in adwlib.h.
14586be43703Skrw *
14596be43703Skrw * If manual termination is specified in the EEPROM for the function,
14606be43703Skrw * then 'termination' was set-up in AdwInitFromEEPROM() and is
14616be43703Skrw * ready to be 'ored' into SCSI_CFG1.
14626be43703Skrw */
14636be43703Skrw if ((cfg->termination & ADW_TERM_SE) == 0) {
14646be43703Skrw /* SE automatic termination control is enabled. */
14656be43703Skrw switch(scsi_cfg1 & ADW_C_DET_SE) {
14666be43703Skrw /* TERM_SE_HI: on, TERM_SE_LO: on */
14676be43703Skrw case 0x1: case 0x2: case 0x3:
14686be43703Skrw cfg->termination |= ADW_TERM_SE;
14696be43703Skrw break;
14706be43703Skrw
14716be43703Skrw case 0x0:
14726be43703Skrw /* !!!!TODO!!!! */
14736be43703Skrw // if (ASC_PCI_ID2FUNC(cfg->pci_slot_info) == 0) {
14746be43703Skrw /* Function 0 - TERM_SE_HI: off, TERM_SE_LO: off */
14756be43703Skrw // }
14766be43703Skrw // else
14776be43703Skrw // {
14786be43703Skrw /* Function 1 - TERM_SE_HI: on, TERM_SE_LO: off */
14796be43703Skrw cfg->termination |= ADW_TERM_SE_HI;
14806be43703Skrw // }
14816be43703Skrw break;
14826be43703Skrw }
14836be43703Skrw }
14846be43703Skrw
14856be43703Skrw /*
14866be43703Skrw * Clear any set TERM_SE bits.
14876be43703Skrw */
14886be43703Skrw scsi_cfg1 &= ~ADW_TERM_SE;
14896be43703Skrw
14906be43703Skrw /*
14916be43703Skrw * Invert the TERM_SE bits and then set 'scsi_cfg1'.
14926be43703Skrw */
14936be43703Skrw scsi_cfg1 |= (~cfg->termination & ADW_TERM_SE);
14946be43703Skrw
14956be43703Skrw /*
14966be43703Skrw * Clear Big Endian and Terminator Polarity bits and set possibly
14976be43703Skrw * modified termination control bits in the Microcode SCSI_CFG1
14986be43703Skrw * Register Value.
14996be43703Skrw */
15006be43703Skrw scsi_cfg1 &= (~ADW_BIG_ENDIAN & ~ADW_DIS_TERM_DRV & ~ADW_TERM_POL);
15016be43703Skrw
15026be43703Skrw /*
15036be43703Skrw * Set SCSI_CFG1 Microcode Default Value
15046be43703Skrw *
15056be43703Skrw * Set possibly modified termination control bits in the Microcode
15066be43703Skrw * SCSI_CFG1 Register Value.
15076be43703Skrw *
15086be43703Skrw * The microcode will set the SCSI_CFG1 register using this value
1509466e5dfaSderaadt * after it is started below.
1510466e5dfaSderaadt */
15116be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
1512466e5dfaSderaadt
1513466e5dfaSderaadt /*
15146be43703Skrw * Set MEM_CFG Microcode Default Value
1515466e5dfaSderaadt *
15166be43703Skrw * The microcode will set the MEM_CFG register using this value
15176be43703Skrw * after it is started below.
1518379dd687Sdownsj *
15196be43703Skrw * MEM_CFG may be accessed as a word or byte, but only bits 0-7
15206be43703Skrw * are defined.
1521379dd687Sdownsj *
15226be43703Skrw * ASC-38C1600 has 32KB internal memory.
1523379dd687Sdownsj */
15246be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_DEFAULT_MEM_CFG,
15256be43703Skrw ADW_BIOS_EN | ADW_RAM_SZ_32KB);
1526379dd687Sdownsj
15276be43703Skrw return 0;
1528466e5dfaSderaadt }
1529466e5dfaSderaadt
1530466e5dfaSderaadt
1531379dd687Sdownsj /*
1532379dd687Sdownsj * Read EEPROM configuration into the specified buffer.
1533379dd687Sdownsj *
1534379dd687Sdownsj * Return a checksum based on the EEPROM configuration read.
1535379dd687Sdownsj */
153633bed6b7Skrw u_int16_t
AdwGetEEPROMConfig(bus_space_tag_t iot,bus_space_handle_t ioh,ADW_EEPROM * cfg_buf)1537855b2726Sdhill AdwGetEEPROMConfig(bus_space_tag_t iot, bus_space_handle_t ioh,
1538855b2726Sdhill ADW_EEPROM *cfg_buf)
1539379dd687Sdownsj {
1540379dd687Sdownsj u_int16_t wval, chksum;
1541379dd687Sdownsj u_int16_t *wbuf;
1542379dd687Sdownsj int eep_addr;
1543379dd687Sdownsj
1544466e5dfaSderaadt
1545379dd687Sdownsj wbuf = (u_int16_t *) cfg_buf;
1546379dd687Sdownsj chksum = 0;
1547379dd687Sdownsj
1548a1d22770Skrw for (eep_addr = ADW_EEP_DVC_CFG_BEGIN;
1549a1d22770Skrw eep_addr < ADW_EEP_DVC_CFG_END;
1550379dd687Sdownsj eep_addr++, wbuf++) {
15516be43703Skrw wval = AdwReadEEPWord(iot, ioh, eep_addr);
1552379dd687Sdownsj chksum += wval;
1553379dd687Sdownsj *wbuf = wval;
1554379dd687Sdownsj }
1555466e5dfaSderaadt
15566be43703Skrw *wbuf = AdwReadEEPWord(iot, ioh, eep_addr);
1557379dd687Sdownsj wbuf++;
1558a1d22770Skrw for (eep_addr = ADW_EEP_DVC_CTL_BEGIN;
1559a1d22770Skrw eep_addr < ADW_EEP_MAX_WORD_ADDR;
1560379dd687Sdownsj eep_addr++, wbuf++) {
15616be43703Skrw *wbuf = AdwReadEEPWord(iot, ioh, eep_addr);
1562466e5dfaSderaadt }
1563466e5dfaSderaadt
1564466e5dfaSderaadt return chksum;
1565466e5dfaSderaadt }
1566466e5dfaSderaadt
1567466e5dfaSderaadt
1568379dd687Sdownsj /*
1569379dd687Sdownsj * Read the EEPROM from specified location
1570379dd687Sdownsj */
157133bed6b7Skrw u_int16_t
AdwReadEEPWord(bus_space_tag_t iot,bus_space_handle_t ioh,int eep_word_addr)1572855b2726Sdhill AdwReadEEPWord(bus_space_tag_t iot, bus_space_handle_t ioh, int eep_word_addr)
1573379dd687Sdownsj {
1574379dd687Sdownsj ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_EE_CMD,
1575a1d22770Skrw ADW_EEP_CMD_READ | eep_word_addr);
15766be43703Skrw AdwWaitEEPCmd(iot, ioh);
1577466e5dfaSderaadt
1578379dd687Sdownsj return ADW_READ_WORD_REGISTER(iot, ioh, IOPW_EE_DATA);
1579379dd687Sdownsj }
1580379dd687Sdownsj
1581466e5dfaSderaadt
1582379dd687Sdownsj /*
1583379dd687Sdownsj * Wait for EEPROM command to complete
1584379dd687Sdownsj */
158533bed6b7Skrw void
AdwWaitEEPCmd(bus_space_tag_t iot,bus_space_handle_t ioh)1586855b2726Sdhill AdwWaitEEPCmd(bus_space_tag_t iot, bus_space_handle_t ioh)
1587379dd687Sdownsj {
1588466e5dfaSderaadt int eep_delay_ms;
1589379dd687Sdownsj
1590466e5dfaSderaadt
1591a1d22770Skrw for (eep_delay_ms = 0; eep_delay_ms < ADW_EEP_DELAY_MS; eep_delay_ms++){
1592379dd687Sdownsj if (ADW_READ_WORD_REGISTER(iot, ioh, IOPW_EE_CMD) &
1593a1d22770Skrw ADW_EEP_CMD_DONE) {
1594379dd687Sdownsj break;
1595379dd687Sdownsj }
15966be43703Skrw AdwSleepMilliSecond(1);
1597379dd687Sdownsj }
1598379dd687Sdownsj
1599466e5dfaSderaadt ADW_READ_WORD_REGISTER(iot, ioh, IOPW_EE_CMD);
1600379dd687Sdownsj }
1601379dd687Sdownsj
1602466e5dfaSderaadt
1603379dd687Sdownsj /*
1604379dd687Sdownsj * Write the EEPROM from 'cfg_buf'.
1605379dd687Sdownsj */
160633bed6b7Skrw void
AdwSetEEPROMConfig(bus_space_tag_t iot,bus_space_handle_t ioh,ADW_EEPROM * cfg_buf)1607855b2726Sdhill AdwSetEEPROMConfig(bus_space_tag_t iot, bus_space_handle_t ioh,
1608855b2726Sdhill ADW_EEPROM *cfg_buf)
1609379dd687Sdownsj {
1610379dd687Sdownsj u_int16_t *wbuf;
1611379dd687Sdownsj u_int16_t addr, chksum;
1612379dd687Sdownsj
1613466e5dfaSderaadt
1614379dd687Sdownsj wbuf = (u_int16_t *) cfg_buf;
1615379dd687Sdownsj chksum = 0;
1616379dd687Sdownsj
1617a1d22770Skrw ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_EE_CMD, ADW_EEP_CMD_WRITE_ABLE);
16186be43703Skrw AdwWaitEEPCmd(iot, ioh);
1619379dd687Sdownsj
1620379dd687Sdownsj /*
1621466e5dfaSderaadt * Write EEPROM from word 0 to word 20
1622379dd687Sdownsj */
1623a1d22770Skrw for (addr = ADW_EEP_DVC_CFG_BEGIN;
1624a1d22770Skrw addr < ADW_EEP_DVC_CFG_END; addr++, wbuf++) {
1625379dd687Sdownsj chksum += *wbuf;
1626379dd687Sdownsj ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_EE_DATA, *wbuf);
1627466e5dfaSderaadt ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_EE_CMD,
1628a1d22770Skrw ADW_EEP_CMD_WRITE | addr);
16296be43703Skrw AdwWaitEEPCmd(iot, ioh);
1630a1d22770Skrw AdwSleepMilliSecond(ADW_EEP_DELAY_MS);
1631379dd687Sdownsj }
1632379dd687Sdownsj
1633379dd687Sdownsj /*
1634466e5dfaSderaadt * Write EEPROM checksum at word 21
1635379dd687Sdownsj */
1636379dd687Sdownsj ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_EE_DATA, chksum);
1637379dd687Sdownsj ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_EE_CMD,
1638a1d22770Skrw ADW_EEP_CMD_WRITE | addr);
16396be43703Skrw AdwWaitEEPCmd(iot, ioh);
1640379dd687Sdownsj wbuf++; /* skip over check_sum */
1641379dd687Sdownsj
1642379dd687Sdownsj /*
1643466e5dfaSderaadt * Write EEPROM OEM name at words 22 to 29
1644379dd687Sdownsj */
1645a1d22770Skrw for (addr = ADW_EEP_DVC_CTL_BEGIN;
1646a1d22770Skrw addr < ADW_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
1647379dd687Sdownsj ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_EE_DATA, *wbuf);
1648466e5dfaSderaadt ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_EE_CMD,
1649a1d22770Skrw ADW_EEP_CMD_WRITE | addr);
16506be43703Skrw AdwWaitEEPCmd(iot, ioh);
1651379dd687Sdownsj }
1652466e5dfaSderaadt
1653379dd687Sdownsj ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_EE_CMD,
1654a1d22770Skrw ADW_EEP_CMD_WRITE_DISABLE);
16556be43703Skrw AdwWaitEEPCmd(iot, ioh);
1656466e5dfaSderaadt
1657379dd687Sdownsj return;
1658379dd687Sdownsj }
1659379dd687Sdownsj
1660466e5dfaSderaadt
1661379dd687Sdownsj /*
16626be43703Skrw * AdwExeScsiQueue() - Send a request to the RISC microcode program.
1663379dd687Sdownsj *
1664466e5dfaSderaadt * Allocate a carrier structure, point the carrier to the ADW_SCSI_REQ_Q,
1665466e5dfaSderaadt * add the carrier to the ICQ (Initiator Command Queue), and tickle the
1666466e5dfaSderaadt * RISC to notify it a new command is ready to be executed.
1667379dd687Sdownsj *
1668466e5dfaSderaadt * If 'done_status' is not set to QD_DO_RETRY, then 'error_retry' will be
1669466e5dfaSderaadt * set to SCSI_MAX_RETRY.
1670379dd687Sdownsj *
1671379dd687Sdownsj * Return:
1672466e5dfaSderaadt * ADW_SUCCESS(1) - The request was successfully queued.
1673466e5dfaSderaadt * ADW_BUSY(0) - Resource unavailable; Retry again after pending
1674466e5dfaSderaadt * request completes.
1675466e5dfaSderaadt * ADW_ERROR(-1) - Invalid ADW_SCSI_REQ_Q request structure
1676466e5dfaSderaadt * host IC error.
1677379dd687Sdownsj */
1678379dd687Sdownsj int
AdwExeScsiQueue(ADW_SOFTC * sc,ADW_SCSI_REQ_Q * scsiq)1679855b2726Sdhill AdwExeScsiQueue(ADW_SOFTC *sc, ADW_SCSI_REQ_Q *scsiq)
1680379dd687Sdownsj {
1681466e5dfaSderaadt bus_space_tag_t iot = sc->sc_iot;
1682466e5dfaSderaadt bus_space_handle_t ioh = sc->sc_ioh;
1683466e5dfaSderaadt ADW_CCB *ccb;
1684466e5dfaSderaadt long req_size;
1685466e5dfaSderaadt u_int32_t req_paddr;
16866be43703Skrw ADW_CARRIER *new_carrp;
1687466e5dfaSderaadt
1688466e5dfaSderaadt /*
1689466e5dfaSderaadt * The ADW_SCSI_REQ_Q 'target_id' field should never exceed ADW_MAX_TID.
1690466e5dfaSderaadt */
1691466e5dfaSderaadt if (scsiq->target_id > ADW_MAX_TID) {
1692466e5dfaSderaadt scsiq->host_status = QHSTA_M_INVALID_DEVICE;
1693466e5dfaSderaadt scsiq->done_status = QD_WITH_ERROR;
1694466e5dfaSderaadt return ADW_ERROR;
1695379dd687Sdownsj }
1696379dd687Sdownsj
16976be43703Skrw /*
1698a1d22770Skrw * Beginning of CRITICAL SECTION: ASSUME splbio() in effect
16996be43703Skrw */
17006be43703Skrw
1701466e5dfaSderaadt ccb = adw_ccb_phys_kv(sc, scsiq->ccb_ptr);
1702466e5dfaSderaadt
1703466e5dfaSderaadt /*
17046be43703Skrw * Allocate a carrier and initialize fields.
1705466e5dfaSderaadt */
17066be43703Skrw if ((new_carrp = sc->carr_freelist) == NULL) {
1707466e5dfaSderaadt return ADW_BUSY;
1708466e5dfaSderaadt }
17096be43703Skrw sc->carr_freelist = ADW_CARRIER_VADDR(sc,
1710a1d22770Skrw ADW_GET_CARRP(new_carrp->next_ba));
1711466e5dfaSderaadt sc->carr_pending_cnt++;
1712466e5dfaSderaadt
1713466e5dfaSderaadt /*
17146be43703Skrw * Set the carrier to be a stopper by setting 'next_ba'
1715466e5dfaSderaadt * to the stopper value. The current stopper will be changed
1716466e5dfaSderaadt * below to point to the new stopper.
1717466e5dfaSderaadt */
1718a1d22770Skrw new_carrp->next_ba = ADW_CQ_STOPPER;
1719466e5dfaSderaadt
1720466e5dfaSderaadt req_size = sizeof(ADW_SCSI_REQ_Q);
1721466e5dfaSderaadt req_paddr = sc->sc_dmamap_control->dm_segs[0].ds_addr +
1722466e5dfaSderaadt ADW_CCB_OFF(ccb) + offsetof(struct adw_ccb, scsiq);
1723466e5dfaSderaadt
1724466e5dfaSderaadt /* Save physical address of ADW_SCSI_REQ_Q and Carrier. */
1725466e5dfaSderaadt scsiq->scsiq_rptr = req_paddr;
1726466e5dfaSderaadt
1727466e5dfaSderaadt /*
1728a1d22770Skrw * Every ADW_SCSI_REQ_Q.carr_ba is byte swapped to little-endian
1729466e5dfaSderaadt * order during initialization.
1730466e5dfaSderaadt */
17316be43703Skrw scsiq->carr_ba = sc->icq_sp->carr_ba;
17326be43703Skrw scsiq->carr_va = sc->icq_sp->carr_ba;
1733466e5dfaSderaadt
1734466e5dfaSderaadt /*
1735466e5dfaSderaadt * Use the current stopper to send the ADW_SCSI_REQ_Q command to
1736466e5dfaSderaadt * the microcode. The newly allocated stopper will become the new
1737466e5dfaSderaadt * stopper.
1738466e5dfaSderaadt */
17396be43703Skrw sc->icq_sp->areq_ba = req_paddr;
1740466e5dfaSderaadt
1741466e5dfaSderaadt /*
17426be43703Skrw * Set the 'next_ba' pointer for the old stopper to be the
1743466e5dfaSderaadt * physical address of the new stopper. The RISC can only
1744466e5dfaSderaadt * follow physical addresses.
1745466e5dfaSderaadt */
17466be43703Skrw sc->icq_sp->next_ba = new_carrp->carr_ba;
1747466e5dfaSderaadt
17486be43703Skrw #if ADW_DEBUG
17496be43703Skrw printf("icq 0x%x, 0x%x, 0x%x, 0x%x\n",
17506be43703Skrw sc->icq_sp->carr_id,
17516be43703Skrw sc->icq_sp->carr_ba,
17526be43703Skrw sc->icq_sp->areq_ba,
17536be43703Skrw sc->icq_sp->next_ba);
17546be43703Skrw #endif
1755466e5dfaSderaadt /*
1756466e5dfaSderaadt * Set the host adapter stopper pointer to point to the new carrier.
1757466e5dfaSderaadt */
1758466e5dfaSderaadt sc->icq_sp = new_carrp;
1759466e5dfaSderaadt
17606be43703Skrw if (sc->chip_type == ADW_CHIP_ASC3550 ||
17616be43703Skrw sc->chip_type == ADW_CHIP_ASC38C0800) {
1762466e5dfaSderaadt /*
17636be43703Skrw * Tickle the RISC to tell it to read its Command Queue Head
17646be43703Skrw * pointer.
1765466e5dfaSderaadt */
17663976a5edSkrw ADW_WRITE_BYTE_REGISTER(iot, ioh, IOPB_TICKLE, ADW_TICKLE_A);
17676be43703Skrw if (sc->chip_type == ADW_CHIP_ASC3550) {
1768466e5dfaSderaadt /*
1769466e5dfaSderaadt * Clear the tickle value. In the ASC-3550 the RISC flag
1770466e5dfaSderaadt * command 'clr_tickle_a' does not work unless the host
1771466e5dfaSderaadt * value is cleared.
1772466e5dfaSderaadt */
17736be43703Skrw ADW_WRITE_BYTE_REGISTER(iot, ioh, IOPB_TICKLE,
17743976a5edSkrw ADW_TICKLE_NOP);
1775466e5dfaSderaadt }
17766be43703Skrw } else if (sc->chip_type == ADW_CHIP_ASC38C1600) {
17776be43703Skrw /*
17786be43703Skrw * Notify the RISC a carrier is ready by writing the physical
17796be43703Skrw * address of the new carrier stopper to the COMMA register.
17806be43703Skrw */
17816be43703Skrw ADW_WRITE_DWORD_REGISTER(iot, ioh, IOPDW_COMMA,
17826be43703Skrw new_carrp->carr_ba);
17836be43703Skrw }
17846be43703Skrw
17856be43703Skrw /*
17866be43703Skrw * End of CRITICAL SECTION: Must be protected within splbio/splx pair
17876be43703Skrw */
1788466e5dfaSderaadt
1789466e5dfaSderaadt return ADW_SUCCESS;
1790466e5dfaSderaadt }
1791466e5dfaSderaadt
1792466e5dfaSderaadt
1793466e5dfaSderaadt void
AdwResetChip(bus_space_tag_t iot,bus_space_handle_t ioh)1794855b2726Sdhill AdwResetChip(bus_space_tag_t iot, bus_space_handle_t ioh)
1795466e5dfaSderaadt {
1796466e5dfaSderaadt
1797466e5dfaSderaadt /*
1798466e5dfaSderaadt * Reset Chip.
1799466e5dfaSderaadt */
1800466e5dfaSderaadt ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_CTRL_REG,
1801466e5dfaSderaadt ADW_CTRL_REG_CMD_RESET);
18026be43703Skrw AdwSleepMilliSecond(100);
1803466e5dfaSderaadt ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_CTRL_REG,
1804466e5dfaSderaadt ADW_CTRL_REG_CMD_WR_IO_REG);
1805466e5dfaSderaadt }
1806466e5dfaSderaadt
1807466e5dfaSderaadt
1808379dd687Sdownsj /*
1809379dd687Sdownsj * Reset SCSI Bus and purge all outstanding requests.
1810379dd687Sdownsj *
1811379dd687Sdownsj * Return Value:
1812379dd687Sdownsj * ADW_TRUE(1) - All requests are purged and SCSI Bus is reset.
1813466e5dfaSderaadt * ADW_FALSE(0) - Microcode command failed.
1814466e5dfaSderaadt * ADW_ERROR(-1) - Microcode command timed-out. Microcode or IC
1815466e5dfaSderaadt * may be hung which requires driver recovery.
1816379dd687Sdownsj */
1817379dd687Sdownsj int
AdwResetCCB(ADW_SOFTC * sc)1818855b2726Sdhill AdwResetCCB(ADW_SOFTC *sc)
1819379dd687Sdownsj {
1820379dd687Sdownsj int status;
1821379dd687Sdownsj
1822466e5dfaSderaadt /*
1823466e5dfaSderaadt * Send the SCSI Bus Reset idle start idle command which asserts
1824466e5dfaSderaadt * the SCSI Bus Reset signal.
1825466e5dfaSderaadt */
18266be43703Skrw status = AdwSendIdleCmd(sc, (u_int16_t) IDLE_CMD_SCSI_RESET_START, 0L);
18276be43703Skrw if (status != ADW_TRUE) {
1828379dd687Sdownsj return status;
1829379dd687Sdownsj }
1830379dd687Sdownsj
1831379dd687Sdownsj /*
1832466e5dfaSderaadt * Delay for the specified SCSI Bus Reset hold time.
1833466e5dfaSderaadt *
1834466e5dfaSderaadt * The hold time delay is done on the host because the RISC has no
1835466e5dfaSderaadt * microsecond accurate timer.
1836379dd687Sdownsj */
1837a1d22770Skrw AdwDelayMicroSecond((u_int16_t) ADW_SCSI_RESET_HOLD_TIME_US);
1838466e5dfaSderaadt
1839466e5dfaSderaadt /*
1840466e5dfaSderaadt * Send the SCSI Bus Reset end idle command which de-asserts
1841466e5dfaSderaadt * the SCSI Bus Reset signal and purges any pending requests.
1842466e5dfaSderaadt */
18436be43703Skrw status = AdwSendIdleCmd(sc, (u_int16_t) IDLE_CMD_SCSI_RESET_END, 0L);
18446be43703Skrw if (status != ADW_TRUE) {
1845466e5dfaSderaadt return status;
1846466e5dfaSderaadt }
1847466e5dfaSderaadt
18486be43703Skrw AdwSleepMilliSecond((u_int32_t) sc->scsi_reset_wait * 1000);
1849466e5dfaSderaadt
1850466e5dfaSderaadt return status;
1851466e5dfaSderaadt }
1852466e5dfaSderaadt
1853466e5dfaSderaadt
1854466e5dfaSderaadt /*
1855466e5dfaSderaadt * Reset chip and SCSI Bus.
1856466e5dfaSderaadt *
1857466e5dfaSderaadt * Return Value:
1858466e5dfaSderaadt * ADW_TRUE(1) - Chip re-initialization and SCSI Bus Reset successful.
1859466e5dfaSderaadt * ADW_FALSE(0) - Chip re-initialization and SCSI Bus Reset failure.
1860466e5dfaSderaadt */
1861466e5dfaSderaadt int
AdwResetSCSIBus(ADW_SOFTC * sc)1862855b2726Sdhill AdwResetSCSIBus(ADW_SOFTC *sc)
1863379dd687Sdownsj {
1864379dd687Sdownsj bus_space_tag_t iot = sc->sc_iot;
1865379dd687Sdownsj bus_space_handle_t ioh = sc->sc_ioh;
1866466e5dfaSderaadt int status;
1867826c7026Stedu u_int16_t wdtr_able, sdtr_able, ppr_able = 0, tagqng_able;
1868466e5dfaSderaadt u_int8_t tid, max_cmd[ADW_MAX_TID + 1];
1869466e5dfaSderaadt u_int16_t bios_sig;
1870379dd687Sdownsj
1871379dd687Sdownsj
1872379dd687Sdownsj /*
1873466e5dfaSderaadt * Save current per TID negotiated values.
1874379dd687Sdownsj */
18756be43703Skrw ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_WDTR_ABLE, wdtr_able);
18766be43703Skrw ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_SDTR_ABLE, sdtr_able);
18776be43703Skrw if (sc->chip_type == ADW_CHIP_ASC38C1600) {
18786be43703Skrw ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_PPR_ABLE, ppr_able);
18796be43703Skrw }
18806be43703Skrw ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_TAGQNG_ABLE, tagqng_able);
18816be43703Skrw for (tid = 0; tid <= ADW_MAX_TID; tid++) {
18826be43703Skrw ADW_READ_BYTE_LRAM(iot, ioh, ADW_MC_NUMBER_OF_MAX_CMD + tid,
1883466e5dfaSderaadt max_cmd[tid]);
1884466e5dfaSderaadt }
1885379dd687Sdownsj
1886466e5dfaSderaadt /*
18876be43703Skrw * Force the AdwInitAscDriver() function to perform a SCSI Bus Reset
18886be43703Skrw * by clearing the BIOS signature word.
1889466e5dfaSderaadt * The initialization functions assumes a SCSI Bus Reset is not
1890466e5dfaSderaadt * needed if the BIOS signature word is present.
1891466e5dfaSderaadt */
18926be43703Skrw ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_BIOS_SIGNATURE, bios_sig);
18936be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_BIOS_SIGNATURE, 0);
1894466e5dfaSderaadt
1895466e5dfaSderaadt /*
1896466e5dfaSderaadt * Stop chip and reset it.
1897466e5dfaSderaadt */
1898466e5dfaSderaadt ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_RISC_CSR, ADW_RISC_CSR_STOP);
1899466e5dfaSderaadt ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_CTRL_REG,
1900466e5dfaSderaadt ADW_CTRL_REG_CMD_RESET);
19016be43703Skrw AdwSleepMilliSecond(100);
1902466e5dfaSderaadt ADW_WRITE_WORD_REGISTER(iot, ioh, IOPW_CTRL_REG,
1903466e5dfaSderaadt ADW_CTRL_REG_CMD_WR_IO_REG);
1904466e5dfaSderaadt
1905466e5dfaSderaadt /*
1906a1d22770Skrw * Reset Adw Library error code, if any, and try
1907466e5dfaSderaadt * re-initializing the chip.
19086be43703Skrw * Then translate initialization return value to status value.
1909466e5dfaSderaadt */
19106be43703Skrw status = (AdwInitDriver(sc) == 0)? ADW_TRUE : ADW_FALSE;
1911466e5dfaSderaadt
1912466e5dfaSderaadt /*
1913466e5dfaSderaadt * Restore the BIOS signature word.
1914466e5dfaSderaadt */
19156be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_BIOS_SIGNATURE, bios_sig);
1916466e5dfaSderaadt
1917466e5dfaSderaadt /*
1918466e5dfaSderaadt * Restore per TID negotiated values.
1919466e5dfaSderaadt */
19206be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_WDTR_ABLE, wdtr_able);
19216be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_SDTR_ABLE, sdtr_able);
19226be43703Skrw if (sc->chip_type == ADW_CHIP_ASC38C1600) {
19236be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_PPR_ABLE, ppr_able);
19246be43703Skrw }
19256be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_TAGQNG_ABLE, tagqng_able);
1926466e5dfaSderaadt for (tid = 0; tid <= ADW_MAX_TID; tid++) {
19276be43703Skrw ADW_WRITE_BYTE_LRAM(iot, ioh, ADW_MC_NUMBER_OF_MAX_CMD + tid,
1928466e5dfaSderaadt max_cmd[tid]);
1929466e5dfaSderaadt }
1930466e5dfaSderaadt
1931466e5dfaSderaadt return status;
1932379dd687Sdownsj }
1933379dd687Sdownsj
1934379dd687Sdownsj
1935379dd687Sdownsj /*
1936a1d22770Skrw * Adw Library Interrupt Service Routine
1937379dd687Sdownsj *
1938379dd687Sdownsj * This function is called by a driver's interrupt service routine.
1939379dd687Sdownsj * The function disables and re-enables interrupts.
1940379dd687Sdownsj *
19416be43703Skrw * Note: AdwISR() can be called when interrupts are disabled or even
1942379dd687Sdownsj * when there is no hardware interrupt condition present. It will
1943379dd687Sdownsj * always check for completed idle commands and microcode requests.
1944379dd687Sdownsj * This is an important feature that shouldn't be changed because it
1945379dd687Sdownsj * allows commands to be completed from polling mode loops.
1946379dd687Sdownsj *
1947379dd687Sdownsj * Return:
1948379dd687Sdownsj * ADW_TRUE(1) - interrupt was pending
1949379dd687Sdownsj * ADW_FALSE(0) - no interrupt was pending
1950379dd687Sdownsj */
1951379dd687Sdownsj int
AdwISR(ADW_SOFTC * sc)1952855b2726Sdhill AdwISR(ADW_SOFTC *sc)
1953379dd687Sdownsj {
1954379dd687Sdownsj bus_space_tag_t iot = sc->sc_iot;
1955379dd687Sdownsj bus_space_handle_t ioh = sc->sc_ioh;
1956379dd687Sdownsj u_int8_t int_stat;
1957466e5dfaSderaadt u_int16_t target_bit;
1958466e5dfaSderaadt ADW_CARRIER *free_carrp/*, *ccb_carr*/;
1959466e5dfaSderaadt u_int32_t irq_next_pa;
1960379dd687Sdownsj ADW_SCSI_REQ_Q *scsiq;
1961466e5dfaSderaadt ADW_CCB *ccb;
19626be43703Skrw int s;
1963379dd687Sdownsj
1964379dd687Sdownsj
19656be43703Skrw s = splbio();
19666be43703Skrw
1967379dd687Sdownsj /* Reading the register clears the interrupt. */
1968379dd687Sdownsj int_stat = ADW_READ_BYTE_REGISTER(iot, ioh, IOPB_INTR_STATUS_REG);
1969379dd687Sdownsj
1970466e5dfaSderaadt if ((int_stat & (ADW_INTR_STATUS_INTRA | ADW_INTR_STATUS_INTRB |
1971466e5dfaSderaadt ADW_INTR_STATUS_INTRC)) == 0) {
19726be43703Skrw splx(s);
1973466e5dfaSderaadt return ADW_FALSE;
1974466e5dfaSderaadt }
1975466e5dfaSderaadt
1976466e5dfaSderaadt /*
1977466e5dfaSderaadt * Notify the driver of an asynchronous microcode condition by
1978a1d22770Skrw * calling the ADW_SOFTC.async_callback function. The function
19796be43703Skrw * is passed the microcode ADW_MC_INTRB_CODE byte value.
1980466e5dfaSderaadt */
1981379dd687Sdownsj if (int_stat & ADW_INTR_STATUS_INTRB) {
1982466e5dfaSderaadt u_int8_t intrb_code;
1983466e5dfaSderaadt
19846be43703Skrw ADW_READ_BYTE_LRAM(iot, ioh, ADW_MC_INTRB_CODE, intrb_code);
19856be43703Skrw
19866be43703Skrw if (sc->chip_type == ADW_CHIP_ASC3550 ||
19876be43703Skrw sc->chip_type == ADW_CHIP_ASC38C0800) {
1988a1d22770Skrw if (intrb_code == ADW_ASYNC_CARRIER_READY_FAILURE &&
1989466e5dfaSderaadt sc->carr_pending_cnt != 0) {
19906be43703Skrw ADW_WRITE_BYTE_REGISTER(iot, ioh,
19913976a5edSkrw IOPB_TICKLE, ADW_TICKLE_A);
19926be43703Skrw if (sc->chip_type == ADW_CHIP_ASC3550) {
19936be43703Skrw ADW_WRITE_BYTE_REGISTER(iot, ioh,
19943976a5edSkrw IOPB_TICKLE, ADW_TICKLE_NOP);
19956be43703Skrw }
1996379dd687Sdownsj }
1997379dd687Sdownsj }
1998379dd687Sdownsj
1999466e5dfaSderaadt if (sc->async_callback != 0) {
2000466e5dfaSderaadt (*(ADW_ASYNC_CALLBACK)sc->async_callback)(sc, intrb_code);
2001466e5dfaSderaadt }
2002466e5dfaSderaadt }
2003379dd687Sdownsj
2004379dd687Sdownsj /*
2005466e5dfaSderaadt * Check if the IRQ stopper carrier contains a completed request.
2006379dd687Sdownsj */
2007a1d22770Skrw while (((irq_next_pa = sc->irq_sp->next_ba) & ADW_RQ_DONE) != 0)
2008379dd687Sdownsj {
20096be43703Skrw #if ADW_DEBUG
20106be43703Skrw printf("irq 0x%x, 0x%x, 0x%x, 0x%x\n",
20116be43703Skrw sc->irq_sp->carr_id,
20126be43703Skrw sc->irq_sp->carr_ba,
20136be43703Skrw sc->irq_sp->areq_ba,
20146be43703Skrw sc->irq_sp->next_ba);
20156be43703Skrw #endif
2016466e5dfaSderaadt /*
20176be43703Skrw * Get a pointer to the newly completed ADW_SCSI_REQ_Q
20186be43703Skrw * structure.
20196be43703Skrw * The RISC will have set 'areq_ba' to a virtual address.
2020466e5dfaSderaadt *
2021a1d22770Skrw * The firmware will have copied the ADW_SCSI_REQ_Q.ccb_ptr
2022a1d22770Skrw * field to the carrier ADW_CARRIER.areq_ba field.
20236be43703Skrw * The conversion below complements the conversion of
2024a1d22770Skrw * ADW_SCSI_REQ_Q.ccb_ptr' in AdwExeScsiQueue().
2025466e5dfaSderaadt */
20266be43703Skrw ccb = adw_ccb_phys_kv(sc, sc->irq_sp->areq_ba);
2027466e5dfaSderaadt scsiq = &ccb->scsiq;
20286be43703Skrw scsiq->ccb_ptr = sc->irq_sp->areq_ba;
2029379dd687Sdownsj
20306be43703Skrw /*
20316be43703Skrw * Request finished with good status and the queue was not
20326be43703Skrw * DMAed to host memory by the firmware. Set all status fields
20336be43703Skrw * to indicate good status.
20346be43703Skrw */
2035a1d22770Skrw if ((irq_next_pa & ADW_RQ_GOOD) != 0) {
20366be43703Skrw scsiq->done_status = QD_NO_ERROR;
20376be43703Skrw scsiq->host_status = scsiq->scsi_status = 0;
20386be43703Skrw scsiq->data_cnt = 0L;
2039379dd687Sdownsj }
2040379dd687Sdownsj
2041466e5dfaSderaadt /*
2042466e5dfaSderaadt * Advance the stopper pointer to the next carrier
2043466e5dfaSderaadt * ignoring the lower four bits. Free the previous
2044466e5dfaSderaadt * stopper carrier.
2045466e5dfaSderaadt */
2046466e5dfaSderaadt free_carrp = sc->irq_sp;
2047a1d22770Skrw sc->irq_sp = ADW_CARRIER_VADDR(sc, ADW_GET_CARRP(irq_next_pa));
2048466e5dfaSderaadt
204988ee6abdSmiod free_carrp->next_ba = (sc->carr_freelist == NULL) ? 0
20506be43703Skrw : sc->carr_freelist->carr_ba;
2051466e5dfaSderaadt sc->carr_freelist = free_carrp;
2052466e5dfaSderaadt sc->carr_pending_cnt--;
2053466e5dfaSderaadt
2054379dd687Sdownsj target_bit = ADW_TID_TO_TIDMASK(scsiq->target_id);
2055379dd687Sdownsj
2056379dd687Sdownsj /*
2057379dd687Sdownsj * Clear request microcode control flag.
2058379dd687Sdownsj */
2059379dd687Sdownsj scsiq->cntl = 0;
2060379dd687Sdownsj
2061379dd687Sdownsj /*
2062379dd687Sdownsj * Check Condition handling
2063379dd687Sdownsj */
2064379dd687Sdownsj /*
2065379dd687Sdownsj * If the command that completed was a SCSI INQUIRY and
2066379dd687Sdownsj * LUN 0 was sent the command, then process the INQUIRY
2067379dd687Sdownsj * command information for the device.
2068379dd687Sdownsj */
2069466e5dfaSderaadt if (scsiq->done_status == QD_NO_ERROR &&
2070379dd687Sdownsj scsiq->cdb[0] == INQUIRY &&
2071379dd687Sdownsj scsiq->target_lun == 0) {
20726be43703Skrw AdwInquiryHandling(sc, scsiq);
2073379dd687Sdownsj }
2074379dd687Sdownsj
2075379dd687Sdownsj /*
2076379dd687Sdownsj * Notify the driver of the completed request by passing
2077379dd687Sdownsj * the ADW_SCSI_REQ_Q pointer to its callback function.
2078379dd687Sdownsj */
2079379dd687Sdownsj (*(ADW_ISR_CALLBACK)sc->isr_callback)(sc, scsiq);
2080379dd687Sdownsj /*
2081379dd687Sdownsj * Note: After the driver callback function is called, 'scsiq'
2082379dd687Sdownsj * can no longer be referenced.
2083379dd687Sdownsj *
2084379dd687Sdownsj * Fall through and continue processing other completed
2085379dd687Sdownsj * requests...
2086379dd687Sdownsj */
2087379dd687Sdownsj }
2088466e5dfaSderaadt
20896be43703Skrw splx(s);
20906be43703Skrw
2091466e5dfaSderaadt return ADW_TRUE;
2092379dd687Sdownsj }
2093379dd687Sdownsj
2094466e5dfaSderaadt
2095379dd687Sdownsj /*
2096379dd687Sdownsj * Send an idle command to the chip and wait for completion.
2097379dd687Sdownsj *
2098466e5dfaSderaadt * Command completion is polled for once per microsecond.
2099466e5dfaSderaadt *
2100466e5dfaSderaadt * The function can be called from anywhere including an interrupt handler.
2101e693526fSkrw * But the function is not re-entrant, so it uses the splbio/splx()
2102466e5dfaSderaadt * functions to prevent reentrancy.
2103379dd687Sdownsj *
2104379dd687Sdownsj * Return Values:
2105379dd687Sdownsj * ADW_TRUE - command completed successfully
2106379dd687Sdownsj * ADW_FALSE - command failed
2107466e5dfaSderaadt * ADW_ERROR - command timed out
2108379dd687Sdownsj */
2109379dd687Sdownsj int
AdwSendIdleCmd(ADW_SOFTC * sc,u_int16_t idle_cmd,u_int32_t idle_cmd_parameter)2110855b2726Sdhill AdwSendIdleCmd(ADW_SOFTC *sc, u_int16_t idle_cmd, u_int32_t idle_cmd_parameter)
2111379dd687Sdownsj {
2112379dd687Sdownsj bus_space_tag_t iot = sc->sc_iot;
2113379dd687Sdownsj bus_space_handle_t ioh = sc->sc_ioh;
21146be43703Skrw u_int16_t result;
21156be43703Skrw u_int32_t i, j, s;
2116379dd687Sdownsj
2117e693526fSkrw s = splbio();
2118466e5dfaSderaadt
2119466e5dfaSderaadt /*
2120466e5dfaSderaadt * Clear the idle command status which is set by the microcode
2121466e5dfaSderaadt * to a non-zero value to indicate when the command is completed.
2122466e5dfaSderaadt */
21236be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_IDLE_CMD_STATUS, (u_int16_t) 0);
2124379dd687Sdownsj
2125379dd687Sdownsj /*
2126379dd687Sdownsj * Write the idle command value after the idle command parameter
2127379dd687Sdownsj * has been written to avoid a race condition. If the order is not
2128379dd687Sdownsj * followed, the microcode may process the idle command before the
2129379dd687Sdownsj * parameters have been written to LRAM.
2130379dd687Sdownsj */
21316be43703Skrw ADW_WRITE_DWORD_LRAM(iot, ioh, ADW_MC_IDLE_CMD_PARAMETER,
2132379dd687Sdownsj idle_cmd_parameter);
21336be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_IDLE_CMD, idle_cmd);
2134379dd687Sdownsj
2135379dd687Sdownsj /*
2136466e5dfaSderaadt * Tickle the RISC to tell it to process the idle command.
2137379dd687Sdownsj */
21383976a5edSkrw ADW_WRITE_BYTE_REGISTER(iot, ioh, IOPB_TICKLE, ADW_TICKLE_B);
21396be43703Skrw if (sc->chip_type == ADW_CHIP_ASC3550) {
2140379dd687Sdownsj /*
2141466e5dfaSderaadt * Clear the tickle value. In the ASC-3550 the RISC flag
2142466e5dfaSderaadt * command 'clr_tickle_b' does not work unless the host
2143466e5dfaSderaadt * value is cleared.
2144379dd687Sdownsj */
21453976a5edSkrw ADW_WRITE_BYTE_REGISTER(iot, ioh, IOPB_TICKLE, ADW_TICKLE_NOP);
2146379dd687Sdownsj }
2147379dd687Sdownsj
2148466e5dfaSderaadt /* Wait for up to 100 millisecond for the idle command to timeout. */
2149466e5dfaSderaadt for (i = 0; i < SCSI_WAIT_100_MSEC; i++) {
2150466e5dfaSderaadt /* Poll once each microsecond for command completion. */
2151466e5dfaSderaadt for (j = 0; j < SCSI_US_PER_MSEC; j++) {
21526be43703Skrw ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_IDLE_CMD_STATUS,
21536be43703Skrw result);
2154466e5dfaSderaadt if (result != 0) {
2155e693526fSkrw splx(s);
2156466e5dfaSderaadt return result;
2157466e5dfaSderaadt }
21586be43703Skrw AdwDelayMicroSecond(1);
2159379dd687Sdownsj }
2160379dd687Sdownsj }
2161379dd687Sdownsj
2162e693526fSkrw splx(s);
2163466e5dfaSderaadt return ADW_ERROR;
2164379dd687Sdownsj }
2165379dd687Sdownsj
2166379dd687Sdownsj
2167379dd687Sdownsj /*
2168379dd687Sdownsj * Inquiry Information Byte 7 Handling
2169379dd687Sdownsj *
2170379dd687Sdownsj * Handle SCSI Inquiry Command information for a device by setting
2171379dd687Sdownsj * microcode operating variables that affect WDTR, SDTR, and Tag
2172379dd687Sdownsj * Queuing.
2173379dd687Sdownsj */
217433bed6b7Skrw void
AdwInquiryHandling(ADW_SOFTC * sc,ADW_SCSI_REQ_Q * scsiq)2175855b2726Sdhill AdwInquiryHandling(ADW_SOFTC *sc, ADW_SCSI_REQ_Q *scsiq)
2176379dd687Sdownsj {
2177cb847534Skrw #ifndef FAILSAFE
2178379dd687Sdownsj bus_space_tag_t iot = sc->sc_iot;
2179379dd687Sdownsj bus_space_handle_t ioh = sc->sc_ioh;
2180379dd687Sdownsj u_int8_t tid;
2181466e5dfaSderaadt ADW_SCSI_INQUIRY *inq;
2182466e5dfaSderaadt u_int16_t tidmask;
2183466e5dfaSderaadt u_int16_t cfg_word;
2184466e5dfaSderaadt
2185379dd687Sdownsj
2186379dd687Sdownsj /*
21876be43703Skrw * AdwInquiryHandling() requires up to INQUIRY information Byte 7
2188379dd687Sdownsj * to be available.
2189379dd687Sdownsj *
2190379dd687Sdownsj * If less than 8 bytes of INQUIRY information were requested or less
2191379dd687Sdownsj * than 8 bytes were transferred, then return. cdb[4] is the request
2192379dd687Sdownsj * length and the ADW_SCSI_REQ_Q 'data_cnt' field is set by the
2193379dd687Sdownsj * microcode to the transfer residual count.
2194379dd687Sdownsj */
2195466e5dfaSderaadt
2196379dd687Sdownsj if (scsiq->cdb[4] < 8 || (scsiq->cdb[4] - scsiq->data_cnt) < 8) {
2197379dd687Sdownsj return;
2198379dd687Sdownsj }
2199466e5dfaSderaadt
2200379dd687Sdownsj tid = scsiq->target_id;
2201466e5dfaSderaadt
2202466e5dfaSderaadt inq = (ADW_SCSI_INQUIRY *) scsiq->vdata_addr;
2203379dd687Sdownsj
2204379dd687Sdownsj /*
2205379dd687Sdownsj * WDTR, SDTR, and Tag Queuing cannot be enabled for old devices.
2206379dd687Sdownsj */
22076be43703Skrw if ((inq->rsp_data_fmt < 2) /*SCSI-1 | CCS*/ &&
22086be43703Skrw (inq->ansi_apr_ver < 2)) {
2209379dd687Sdownsj return;
2210379dd687Sdownsj } else {
2211379dd687Sdownsj /*
2212379dd687Sdownsj * INQUIRY Byte 7 Handling
2213379dd687Sdownsj *
2214379dd687Sdownsj * Use a device's INQUIRY byte 7 to determine whether it
2215379dd687Sdownsj * supports WDTR, SDTR, and Tag Queuing. If the feature
2216379dd687Sdownsj * is enabled in the EEPROM and the device supports the
2217379dd687Sdownsj * feature, then enable it in the microcode.
2218379dd687Sdownsj */
2219379dd687Sdownsj
2220379dd687Sdownsj tidmask = ADW_TID_TO_TIDMASK(tid);
2221466e5dfaSderaadt
2222379dd687Sdownsj /*
2223379dd687Sdownsj * Wide Transfers
2224379dd687Sdownsj *
2225379dd687Sdownsj * If the EEPROM enabled WDTR for the device and the device
2226379dd687Sdownsj * supports wide bus (16 bit) transfers, then turn on the
2227379dd687Sdownsj * device's 'wdtr_able' bit and write the new value to the
2228379dd687Sdownsj * microcode.
2229379dd687Sdownsj */
2230466e5dfaSderaadt #ifdef SCSI_ADW_WDTR_DISABLE
2231ea94bb9bSmillert if(!(tidmask & SCSI_ADW_WDTR_DISABLE))
2232466e5dfaSderaadt #endif /* SCSI_ADW_WDTR_DISABLE */
2233466e5dfaSderaadt if ((sc->wdtr_able & tidmask) && inq->WBus16) {
22346be43703Skrw ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_WDTR_ABLE,
2235379dd687Sdownsj cfg_word);
2236379dd687Sdownsj if ((cfg_word & tidmask) == 0) {
2237379dd687Sdownsj cfg_word |= tidmask;
22386be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_WDTR_ABLE,
2239379dd687Sdownsj cfg_word);
2240379dd687Sdownsj
2241379dd687Sdownsj /*
22426be43703Skrw * Clear the microcode "SDTR negotiation" and
22436be43703Skrw * "WDTR negotiation" done indicators for the
22446be43703Skrw * target to cause it to negotiate with the new
22456be43703Skrw * setting set above.
2246466e5dfaSderaadt * WDTR when accepted causes the target to enter
22476be43703Skrw * asynchronous mode, so SDTR must be negotiated
2248379dd687Sdownsj */
22496be43703Skrw ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_SDTR_DONE,
2250466e5dfaSderaadt cfg_word);
2251466e5dfaSderaadt cfg_word &= ~tidmask;
22526be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_SDTR_DONE,
2253466e5dfaSderaadt cfg_word);
22546be43703Skrw ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_WDTR_DONE,
2255379dd687Sdownsj cfg_word);
2256379dd687Sdownsj cfg_word &= ~tidmask;
22576be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_WDTR_DONE,
2258379dd687Sdownsj cfg_word);
2259379dd687Sdownsj }
2260379dd687Sdownsj }
2261466e5dfaSderaadt
2262379dd687Sdownsj /*
2263379dd687Sdownsj * Synchronous Transfers
2264379dd687Sdownsj *
2265379dd687Sdownsj * If the EEPROM enabled SDTR for the device and the device
2266379dd687Sdownsj * supports synchronous transfers, then turn on the device's
2267379dd687Sdownsj * 'sdtr_able' bit. Write the new value to the microcode.
2268379dd687Sdownsj */
2269466e5dfaSderaadt #ifdef SCSI_ADW_SDTR_DISABLE
2270ea94bb9bSmillert if(!(tidmask & SCSI_ADW_SDTR_DISABLE))
2271466e5dfaSderaadt #endif /* SCSI_ADW_SDTR_DISABLE */
2272466e5dfaSderaadt if ((sc->sdtr_able & tidmask) && inq->Sync) {
22736be43703Skrw ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_SDTR_ABLE,cfg_word);
2274379dd687Sdownsj if ((cfg_word & tidmask) == 0) {
2275379dd687Sdownsj cfg_word |= tidmask;
22766be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_SDTR_ABLE,
2277379dd687Sdownsj cfg_word);
2278379dd687Sdownsj
2279379dd687Sdownsj /*
22806be43703Skrw * Clear the microcode "SDTR negotiation"
22816be43703Skrw * done indicator for the target to cause it
22826be43703Skrw * to negotiate with the new setting set above.
2283379dd687Sdownsj */
22846be43703Skrw ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_SDTR_DONE,
2285379dd687Sdownsj cfg_word);
2286379dd687Sdownsj cfg_word &= ~tidmask;
22876be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_SDTR_DONE,
2288379dd687Sdownsj cfg_word);
2289379dd687Sdownsj }
2290379dd687Sdownsj }
22916be43703Skrw /*
22926be43703Skrw * If the Inquiry data included enough space for the SPI-3
22936be43703Skrw * Clocking field, then check if DT mode is supported.
22946be43703Skrw */
22956be43703Skrw if (sc->chip_type == ADW_CHIP_ASC38C1600 &&
22966be43703Skrw (scsiq->cdb[4] >= 57 ||
22976be43703Skrw (scsiq->cdb[4] - scsiq->data_cnt) >= 57)) {
22986be43703Skrw /*
22996be43703Skrw * PPR (Parallel Protocol Request) Capable
23006be43703Skrw *
23016be43703Skrw * If the device supports DT mode, then it must be
23026be43703Skrw * PPR capable.
23036be43703Skrw * The PPR message will be used in place of the SDTR
23046be43703Skrw * and WDTR messages to negotiate synchronous speed
23056be43703Skrw * and offset, transfer width, and protocol options.
23066be43703Skrw */
23076be43703Skrw if((inq->Clocking) & INQ_CLOCKING_DT_ONLY){
23086be43703Skrw ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_PPR_ABLE,
23096be43703Skrw sc->ppr_able);
23106be43703Skrw sc->ppr_able |= tidmask;
23116be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_PPR_ABLE,
23126be43703Skrw sc->ppr_able);
23136be43703Skrw }
23146be43703Skrw }
2315466e5dfaSderaadt
2316379dd687Sdownsj /*
2317466e5dfaSderaadt * If the EEPROM enabled Tag Queuing for the device and the
2318466e5dfaSderaadt * device supports Tag Queueing, then turn on the device's
2319379dd687Sdownsj * 'tagqng_enable' bit in the microcode and set the microcode
2320a1d22770Skrw * maximum command count to the ADW_SOFTC 'max_dvc_qng'
2321379dd687Sdownsj * value.
2322379dd687Sdownsj *
2323379dd687Sdownsj * Tag Queuing is disabled for the BIOS which runs in polled
2324379dd687Sdownsj * mode and would see no benefit from Tag Queuing. Also by
2325379dd687Sdownsj * disabling Tag Queuing in the BIOS devices with Tag Queuing
2326379dd687Sdownsj * bugs will at least work with the BIOS.
2327379dd687Sdownsj */
2328466e5dfaSderaadt #ifdef SCSI_ADW_TAGQ_DISABLE
2329ea94bb9bSmillert if(!(tidmask & SCSI_ADW_TAGQ_DISABLE))
2330466e5dfaSderaadt #endif /* SCSI_ADW_TAGQ_DISABLE */
2331466e5dfaSderaadt if ((sc->tagqng_able & tidmask) && inq->CmdQue) {
23326be43703Skrw ADW_READ_WORD_LRAM(iot, ioh, ADW_MC_TAGQNG_ABLE,
2333379dd687Sdownsj cfg_word);
2334379dd687Sdownsj cfg_word |= tidmask;
23356be43703Skrw ADW_WRITE_WORD_LRAM(iot, ioh, ADW_MC_TAGQNG_ABLE,
2336379dd687Sdownsj cfg_word);
2337466e5dfaSderaadt
2338379dd687Sdownsj ADW_WRITE_BYTE_LRAM(iot, ioh,
23396be43703Skrw ADW_MC_NUMBER_OF_MAX_CMD + tid,
2340379dd687Sdownsj sc->max_dvc_qng);
2341379dd687Sdownsj }
2342379dd687Sdownsj }
2343cb847534Skrw #endif /* FAILSAFE */
2344379dd687Sdownsj }
2345379dd687Sdownsj
2346466e5dfaSderaadt
234733bed6b7Skrw void
AdwSleepMilliSecond(u_int32_t n)2348855b2726Sdhill AdwSleepMilliSecond(u_int32_t n)
2349379dd687Sdownsj {
2350379dd687Sdownsj
2351379dd687Sdownsj DELAY(n * 1000);
2352379dd687Sdownsj }
2353379dd687Sdownsj
2354466e5dfaSderaadt
235533bed6b7Skrw void
AdwDelayMicroSecond(u_int32_t n)2356855b2726Sdhill AdwDelayMicroSecond(u_int32_t n)
2357379dd687Sdownsj {
2358379dd687Sdownsj
2359379dd687Sdownsj DELAY(n);
2360379dd687Sdownsj }
2361466e5dfaSderaadt
2362