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