1139749Simp/*- 240024Sgibbs * Low level routines for Second Generation 340024Sgibbs * Advanced Systems Inc. SCSI controllers chips 440024Sgibbs * 556979Sgibbs * Copyright (c) 1998, 1999, 2000 Justin Gibbs. 640024Sgibbs * All rights reserved. 740024Sgibbs * 840024Sgibbs * Redistribution and use in source and binary forms, with or without 940024Sgibbs * modification, are permitted provided that the following conditions 1040024Sgibbs * are met: 1140024Sgibbs * 1. Redistributions of source code must retain the above copyright 1240024Sgibbs * notice, this list of conditions, and the following disclaimer, 1356979Sgibbs * without modification. 1440024Sgibbs * 2. Redistributions in binary form must reproduce the above copyright 1540024Sgibbs * notice, this list of conditions and the following disclaimer in the 1640024Sgibbs * documentation and/or other materials provided with the distribution. 1740024Sgibbs * 3. The name of the author may not be used to endorse or promote products 1840024Sgibbs * derived from this software without specific prior written permission. 1940024Sgibbs * 2040024Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2140024Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2240024Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2340024Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2440024Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2540024Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2640024Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2740024Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2840024Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2940024Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3040024Sgibbs * SUCH DAMAGE. 3140024Sgibbs */ 32139749Simp/*- 3340024Sgibbs * Ported from: 3440024Sgibbs * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters 3540024Sgibbs * 3640024Sgibbs * Copyright (c) 1995-1998 Advanced System Products, Inc. 3740024Sgibbs * All Rights Reserved. 3840024Sgibbs * 3940024Sgibbs * Redistribution and use in source and binary forms, with or without 4040024Sgibbs * modification, are permitted provided that redistributions of source 4140024Sgibbs * code retain the above copyright notice and this comment without 4240024Sgibbs * modification. 4340024Sgibbs */ 4442410Sbde 45119418Sobrien#include <sys/cdefs.h> 46119418Sobrien__FBSDID("$FreeBSD$"); 47119418Sobrien 4851680Seivind#include <sys/param.h> 49241588Sjhb#include <sys/conf.h> 50241588Sjhb#include <sys/lock.h> 51241588Sjhb#include <sys/mutex.h> 5240024Sgibbs#include <sys/systm.h> 5356979Sgibbs#include <sys/bus.h> 54241588Sjhb#include <sys/rman.h> 5540024Sgibbs 5640024Sgibbs#include <machine/bus.h> 5740024Sgibbs 5840024Sgibbs#include <cam/cam.h> 5959082Snyan#include <cam/cam_ccb.h> 6059082Snyan#include <cam/cam_sim.h> 6159082Snyan#include <cam/cam_xpt_sim.h> 6240024Sgibbs#include <cam/scsi/scsi_all.h> 6340024Sgibbs 6440024Sgibbs#include <dev/advansys/adwlib.h> 6540024Sgibbs 6656979Sgibbsconst struct adw_eeprom adw_asc3550_default_eeprom = 6756979Sgibbs{ 6856979Sgibbs ADW_EEPROM_BIOS_ENABLE, /* cfg_lsw */ 6956979Sgibbs 0x0000, /* cfg_msw */ 7056979Sgibbs 0xFFFF, /* disc_enable */ 7156979Sgibbs 0xFFFF, /* wdtr_able */ 7256979Sgibbs { 0xFFFF }, /* sdtr_able */ 7356979Sgibbs 0xFFFF, /* start_motor */ 7456979Sgibbs 0xFFFF, /* tagqng_able */ 7556979Sgibbs 0xFFFF, /* bios_scan */ 7656979Sgibbs 0, /* scam_tolerant */ 7756979Sgibbs 7, /* adapter_scsi_id */ 7856979Sgibbs 0, /* bios_boot_delay */ 7956979Sgibbs 3, /* scsi_reset_delay */ 8056979Sgibbs 0, /* bios_id_lun */ 8156979Sgibbs 0, /* termination */ 8256979Sgibbs 0, /* reserved1 */ 8356979Sgibbs 0xFFE7, /* bios_ctrl */ 8456979Sgibbs { 0xFFFF }, /* ultra_able */ 8556979Sgibbs { 0 }, /* reserved2 */ 8656979Sgibbs ADW_DEF_MAX_HOST_QNG, /* max_host_qng */ 8756979Sgibbs ADW_DEF_MAX_DVC_QNG, /* max_dvc_qng */ 8856979Sgibbs 0, /* dvc_cntl */ 8956979Sgibbs { 0 }, /* bug_fix */ 9056979Sgibbs { 0, 0, 0 }, /* serial_number */ 9156979Sgibbs 0, /* check_sum */ 9256979Sgibbs { /* oem_name[16] */ 9356979Sgibbs 0, 0, 0, 0, 0, 0, 0, 0, 9456979Sgibbs 0, 0, 0, 0, 0, 0, 0, 0 9540024Sgibbs }, 9656979Sgibbs 0, /* dvc_err_code */ 9756979Sgibbs 0, /* adv_err_code */ 9856979Sgibbs 0, /* adv_err_addr */ 9956979Sgibbs 0, /* saved_dvc_err_code */ 10056979Sgibbs 0, /* saved_adv_err_code */ 10156979Sgibbs 0 /* saved_adv_err_addr */ 10256979Sgibbs}; 10356979Sgibbs 10456979Sgibbsconst struct adw_eeprom adw_asc38C0800_default_eeprom = 10556979Sgibbs{ 10656979Sgibbs ADW_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */ 10756979Sgibbs 0x0000, /* 01 cfg_msw */ 10856979Sgibbs 0xFFFF, /* 02 disc_enable */ 10956979Sgibbs 0xFFFF, /* 03 wdtr_able */ 11056979Sgibbs { 0x4444 }, /* 04 sdtr_speed1 */ 11156979Sgibbs 0xFFFF, /* 05 start_motor */ 11256979Sgibbs 0xFFFF, /* 06 tagqng_able */ 11356979Sgibbs 0xFFFF, /* 07 bios_scan */ 11456979Sgibbs 0, /* 08 scam_tolerant */ 11556979Sgibbs 7, /* 09 adapter_scsi_id */ 11656979Sgibbs 0, /* bios_boot_delay */ 11756979Sgibbs 3, /* 10 scsi_reset_delay */ 11856979Sgibbs 0, /* bios_id_lun */ 11956979Sgibbs 0, /* 11 termination_se */ 12056979Sgibbs 0, /* termination_lvd */ 12156979Sgibbs 0xFFE7, /* 12 bios_ctrl */ 12256979Sgibbs { 0x4444 }, /* 13 sdtr_speed2 */ 12356979Sgibbs { 0x4444 }, /* 14 sdtr_speed3 */ 12456979Sgibbs ADW_DEF_MAX_HOST_QNG, /* 15 max_host_qng */ 12556979Sgibbs ADW_DEF_MAX_DVC_QNG, /* max_dvc_qng */ 12656979Sgibbs 0, /* 16 dvc_cntl */ 12756979Sgibbs { 0x4444 } , /* 17 sdtr_speed4 */ 12856979Sgibbs { 0, 0, 0 }, /* 18-20 serial_number */ 12956979Sgibbs 0, /* 21 check_sum */ 13056979Sgibbs { /* 22-29 oem_name[16] */ 13140024Sgibbs 0, 0, 0, 0, 0, 0, 0, 0, 13240024Sgibbs 0, 0, 0, 0, 0, 0, 0, 0 13340024Sgibbs }, 13456979Sgibbs 0, /* 30 dvc_err_code */ 13556979Sgibbs 0, /* 31 adv_err_code */ 13656979Sgibbs 0, /* 32 adv_err_addr */ 13756979Sgibbs 0, /* 33 saved_dvc_err_code */ 13856979Sgibbs 0, /* 34 saved_adv_err_code */ 13956979Sgibbs 0, /* 35 saved_adv_err_addr */ 14056979Sgibbs { /* 36 - 55 reserved */ 14156979Sgibbs 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14256979Sgibbs 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14356979Sgibbs }, 14456979Sgibbs 0, /* 56 cisptr_lsw */ 14556979Sgibbs 0, /* 57 cisprt_msw */ 14656979Sgibbs /* 58-59 sub-id */ 14756979Sgibbs (PCI_ID_ADVANSYS_38C0800_REV1 & PCI_ID_DEV_VENDOR_MASK) >> 32, 14840024Sgibbs}; 14940024Sgibbs 15056979Sgibbs#define ADW_MC_SDTR_OFFSET_ULTRA2_DT 0 15156979Sgibbs#define ADW_MC_SDTR_OFFSET_ULTRA2 1 15256979Sgibbs#define ADW_MC_SDTR_OFFSET_ULTRA 2 15356979Sgibbsconst struct adw_syncrate adw_syncrates[] = 15456979Sgibbs{ 15556979Sgibbs /* mc_sdtr period rate */ 15656979Sgibbs { ADW_MC_SDTR_80, 9, "80.0" }, 15756979Sgibbs { ADW_MC_SDTR_40, 10, "40.0" }, 15856979Sgibbs { ADW_MC_SDTR_20, 12, "20.0" }, 15956979Sgibbs { ADW_MC_SDTR_10, 25, "10.0" }, 16056979Sgibbs { ADW_MC_SDTR_5, 50, "5.0" }, 16156979Sgibbs { ADW_MC_SDTR_ASYNC, 0, "async" } 16256979Sgibbs}; 16356979Sgibbs 16456979Sgibbsconst int adw_num_syncrates = sizeof(adw_syncrates) / sizeof(adw_syncrates[0]); 16556979Sgibbs 16640024Sgibbsstatic u_int16_t adw_eeprom_read_16(struct adw_softc *adw, int addr); 16740024Sgibbsstatic void adw_eeprom_write_16(struct adw_softc *adw, int addr, 16840024Sgibbs u_int data); 16940024Sgibbsstatic void adw_eeprom_wait(struct adw_softc *adw); 17040024Sgibbs 17140024Sgibbsint 17256979Sgibbsadw_find_signature(struct adw_softc *adw) 17340024Sgibbs{ 17456979Sgibbs if (adw_inb(adw, ADW_SIGNATURE_BYTE) == ADW_CHIP_ID_BYTE 17556979Sgibbs && adw_inw(adw, ADW_SIGNATURE_WORD) == ADW_CHIP_ID_WORD) 17640024Sgibbs return (1); 17740024Sgibbs return (0); 17840024Sgibbs} 17940024Sgibbs 18040024Sgibbs/* 18140024Sgibbs * Reset Chip. 18240024Sgibbs */ 18340024Sgibbsvoid 18440024Sgibbsadw_reset_chip(struct adw_softc *adw) 18540024Sgibbs{ 18640024Sgibbs adw_outw(adw, ADW_CTRL_REG, ADW_CTRL_REG_CMD_RESET); 18756979Sgibbs DELAY(1000 * 100); 18840024Sgibbs adw_outw(adw, ADW_CTRL_REG, ADW_CTRL_REG_CMD_WR_IO_REG); 18940024Sgibbs 19040024Sgibbs /* 19140024Sgibbs * Initialize Chip registers. 19240024Sgibbs */ 19340024Sgibbs adw_outw(adw, ADW_SCSI_CFG1, 19440024Sgibbs adw_inw(adw, ADW_SCSI_CFG1) & ~ADW_SCSI_CFG1_BIG_ENDIAN); 19540024Sgibbs} 19640024Sgibbs 19740024Sgibbs/* 19857679Sgibbs * Reset the SCSI bus. 19957679Sgibbs */ 20057679Sgibbsint 20157679Sgibbsadw_reset_bus(struct adw_softc *adw) 20257679Sgibbs{ 20357679Sgibbs adw_idle_cmd_status_t status; 20457679Sgibbs 205241588Sjhb if (!dumping) 206241588Sjhb mtx_assert(&adw->lock, MA_OWNED); 20757679Sgibbs status = 20857679Sgibbs adw_idle_cmd_send(adw, ADW_IDLE_CMD_SCSI_RESET_START, /*param*/0); 20957679Sgibbs if (status != ADW_IDLE_CMD_SUCCESS) { 21057679Sgibbs xpt_print_path(adw->path); 21157679Sgibbs printf("Bus Reset start attempt failed\n"); 21257679Sgibbs return (1); 21357679Sgibbs } 21457679Sgibbs DELAY(ADW_BUS_RESET_HOLD_DELAY_US); 21557679Sgibbs status = 21657679Sgibbs adw_idle_cmd_send(adw, ADW_IDLE_CMD_SCSI_RESET_END, /*param*/0); 21757679Sgibbs if (status != ADW_IDLE_CMD_SUCCESS) { 21857679Sgibbs xpt_print_path(adw->path); 21957679Sgibbs printf("Bus Reset end attempt failed\n"); 22057679Sgibbs return (1); 22157679Sgibbs } 22257679Sgibbs return (0); 22357679Sgibbs} 22457679Sgibbs 22557679Sgibbs/* 22640024Sgibbs * Read the specified EEPROM location 22740024Sgibbs */ 22840024Sgibbsstatic u_int16_t 22940024Sgibbsadw_eeprom_read_16(struct adw_softc *adw, int addr) 23040024Sgibbs{ 23140024Sgibbs adw_outw(adw, ADW_EEP_CMD, ADW_EEP_CMD_READ | addr); 23240024Sgibbs adw_eeprom_wait(adw); 23340024Sgibbs return (adw_inw(adw, ADW_EEP_DATA)); 23440024Sgibbs} 23540024Sgibbs 23640024Sgibbsstatic void 23740024Sgibbsadw_eeprom_write_16(struct adw_softc *adw, int addr, u_int data) 23840024Sgibbs{ 23940024Sgibbs adw_outw(adw, ADW_EEP_DATA, data); 24040024Sgibbs adw_outw(adw, ADW_EEP_CMD, ADW_EEP_CMD_WRITE | addr); 24140024Sgibbs adw_eeprom_wait(adw); 24240024Sgibbs} 24340024Sgibbs 24440024Sgibbs/* 24540024Sgibbs * Wait for and EEPROM command to complete 24640024Sgibbs */ 24740024Sgibbsstatic void 24840024Sgibbsadw_eeprom_wait(struct adw_softc *adw) 24940024Sgibbs{ 25040024Sgibbs int i; 25140024Sgibbs 25240024Sgibbs for (i = 0; i < ADW_EEP_DELAY_MS; i++) { 25340024Sgibbs if ((adw_inw(adw, ADW_EEP_CMD) & ADW_EEP_CMD_DONE) != 0) 25440024Sgibbs break; 25540024Sgibbs DELAY(1000); 25640024Sgibbs } 25740024Sgibbs if (i == ADW_EEP_DELAY_MS) 258241588Sjhb panic("%s: Timedout Reading EEPROM", 259241588Sjhb device_get_nameunit(adw->device)); 26040024Sgibbs} 26140024Sgibbs 26240024Sgibbs/* 26340024Sgibbs * Read EEPROM configuration into the specified buffer. 26440024Sgibbs * 26540024Sgibbs * Return a checksum based on the EEPROM configuration read. 26640024Sgibbs */ 26740024Sgibbsu_int16_t 26840024Sgibbsadw_eeprom_read(struct adw_softc *adw, struct adw_eeprom *eep_buf) 26940024Sgibbs{ 27040024Sgibbs u_int16_t *wbuf; 27140024Sgibbs u_int16_t wval; 27240024Sgibbs u_int16_t chksum; 27340024Sgibbs int eep_addr; 27440024Sgibbs 27540024Sgibbs wbuf = (u_int16_t *)eep_buf; 27640024Sgibbs chksum = 0; 27740024Sgibbs 27840024Sgibbs for (eep_addr = ADW_EEP_DVC_CFG_BEGIN; 27940024Sgibbs eep_addr < ADW_EEP_DVC_CFG_END; 28040024Sgibbs eep_addr++, wbuf++) { 28140024Sgibbs wval = adw_eeprom_read_16(adw, eep_addr); 28240024Sgibbs chksum += wval; 28340024Sgibbs *wbuf = wval; 28440024Sgibbs } 28540024Sgibbs 28640024Sgibbs /* checksum field is not counted in the checksum */ 28740024Sgibbs *wbuf = adw_eeprom_read_16(adw, eep_addr); 28840024Sgibbs wbuf++; 28940024Sgibbs 29040024Sgibbs /* Driver seeprom variables are not included in the checksum */ 29140024Sgibbs for (eep_addr = ADW_EEP_DVC_CTL_BEGIN; 29240024Sgibbs eep_addr < ADW_EEP_MAX_WORD_ADDR; 29340024Sgibbs eep_addr++, wbuf++) 29440024Sgibbs *wbuf = adw_eeprom_read_16(adw, eep_addr); 29540024Sgibbs 29640024Sgibbs return (chksum); 29740024Sgibbs} 29840024Sgibbs 29940024Sgibbsvoid 30040024Sgibbsadw_eeprom_write(struct adw_softc *adw, struct adw_eeprom *eep_buf) 30140024Sgibbs{ 30240024Sgibbs u_int16_t *wbuf; 30340024Sgibbs u_int16_t addr; 30440024Sgibbs u_int16_t chksum; 30540024Sgibbs 30640024Sgibbs wbuf = (u_int16_t *)eep_buf; 30740024Sgibbs chksum = 0; 30840024Sgibbs 30940024Sgibbs adw_outw(adw, ADW_EEP_CMD, ADW_EEP_CMD_WRITE_ABLE); 31040024Sgibbs adw_eeprom_wait(adw); 31140024Sgibbs 31240024Sgibbs /* 31340024Sgibbs * Write EEPROM until checksum. 31440024Sgibbs */ 31540024Sgibbs for (addr = ADW_EEP_DVC_CFG_BEGIN; 31640024Sgibbs addr < ADW_EEP_DVC_CFG_END; addr++, wbuf++) { 31740024Sgibbs chksum += *wbuf; 31840024Sgibbs adw_eeprom_write_16(adw, addr, *wbuf); 31940024Sgibbs } 32040024Sgibbs 32140024Sgibbs /* 32240024Sgibbs * Write calculated EEPROM checksum 32340024Sgibbs */ 32440024Sgibbs adw_eeprom_write_16(adw, addr, chksum); 32540024Sgibbs 32640024Sgibbs /* skip over buffer's checksum */ 32740024Sgibbs wbuf++; 32840024Sgibbs 32940024Sgibbs /* 33040024Sgibbs * Write the rest. 33140024Sgibbs */ 33240024Sgibbs for (addr = ADW_EEP_DVC_CTL_BEGIN; 33340024Sgibbs addr < ADW_EEP_MAX_WORD_ADDR; addr++, wbuf++) 33440024Sgibbs adw_eeprom_write_16(adw, addr, *wbuf); 33540024Sgibbs 33640024Sgibbs adw_outw(adw, ADW_EEP_CMD, ADW_EEP_CMD_WRITE_DISABLE); 33740024Sgibbs adw_eeprom_wait(adw); 33840024Sgibbs} 33940024Sgibbs 34040024Sgibbsint 34140024Sgibbsadw_init_chip(struct adw_softc *adw, u_int term_scsicfg1) 34240024Sgibbs{ 34356979Sgibbs u_int8_t biosmem[ADW_MC_BIOSLEN]; 34456979Sgibbs const u_int16_t *word_table; 34556979Sgibbs const u_int8_t *byte_codes; 34656979Sgibbs const u_int8_t *byte_codes_end; 34756979Sgibbs u_int bios_sig; 34856979Sgibbs u_int bytes_downloaded; 34956979Sgibbs u_int addr; 35056979Sgibbs u_int end_addr; 35156979Sgibbs u_int checksum; 35256979Sgibbs u_int scsicfg1; 35356979Sgibbs u_int tid; 35440024Sgibbs 35540024Sgibbs /* 35640024Sgibbs * Save the RISC memory BIOS region before writing the microcode. 35740024Sgibbs * The BIOS may already be loaded and using its RISC LRAM region 35840024Sgibbs * so its region must be saved and restored. 35940024Sgibbs */ 36040024Sgibbs for (addr = 0; addr < ADW_MC_BIOSLEN; addr++) 36140024Sgibbs biosmem[addr] = adw_lram_read_8(adw, ADW_MC_BIOSMEM + addr); 36240024Sgibbs 36340024Sgibbs /* 36456979Sgibbs * Save current per TID negotiated values if the BIOS has been 36556979Sgibbs * loaded (BIOS signature is present). These will be used if 36656979Sgibbs * we cannot get information from the EEPROM. 36740024Sgibbs */ 36856979Sgibbs addr = ADW_MC_BIOS_SIGNATURE - ADW_MC_BIOSMEM; 36956979Sgibbs bios_sig = biosmem[addr] 37056979Sgibbs | (biosmem[addr + 1] << 8); 37156979Sgibbs if (bios_sig == 0x55AA 37256979Sgibbs && (adw->flags & ADW_EEPROM_FAILED) != 0) { 37356979Sgibbs u_int major_ver; 37456979Sgibbs u_int minor_ver; 37556979Sgibbs u_int sdtr_able; 37656979Sgibbs 37756979Sgibbs addr = ADW_MC_BIOS_VERSION - ADW_MC_BIOSMEM; 37856979Sgibbs minor_ver = biosmem[addr + 1] & 0xF; 37956979Sgibbs major_ver = (biosmem[addr + 1] >> 4) & 0xF; 38056979Sgibbs if ((adw->chip == ADW_CHIP_ASC3550) 38156979Sgibbs && (major_ver <= 3 382142160Sscottl || (major_ver == 3 && minor_ver <= 1))) { 38356979Sgibbs /* 38456979Sgibbs * BIOS 3.1 and earlier location of 38556979Sgibbs * 'wdtr_able' variable. 38656979Sgibbs */ 38756979Sgibbs adw->user_wdtr = 38856979Sgibbs adw_lram_read_16(adw, ADW_MC_WDTR_ABLE_BIOS_31); 38956979Sgibbs } else { 39056979Sgibbs adw->user_wdtr = 39156979Sgibbs adw_lram_read_16(adw, ADW_MC_WDTR_ABLE); 39256979Sgibbs } 39356979Sgibbs sdtr_able = adw_lram_read_16(adw, ADW_MC_SDTR_ABLE); 39456979Sgibbs for (tid = 0; tid < ADW_MAX_TID; tid++) { 39556979Sgibbs u_int tid_mask; 39656979Sgibbs u_int mc_sdtr; 39756979Sgibbs 39856979Sgibbs tid_mask = 0x1 << tid; 39956979Sgibbs if ((sdtr_able & tid_mask) == 0) 40056979Sgibbs mc_sdtr = ADW_MC_SDTR_ASYNC; 40156979Sgibbs else if ((adw->features & ADW_DT) != 0) 40256979Sgibbs mc_sdtr = ADW_MC_SDTR_80; 40356979Sgibbs else if ((adw->features & ADW_ULTRA2) != 0) 40456979Sgibbs mc_sdtr = ADW_MC_SDTR_40; 40556979Sgibbs else 40656979Sgibbs mc_sdtr = ADW_MC_SDTR_20; 40756979Sgibbs adw_set_user_sdtr(adw, tid, mc_sdtr); 40856979Sgibbs } 40956979Sgibbs adw->user_tagenb = adw_lram_read_16(adw, ADW_MC_TAGQNG_ABLE); 41056979Sgibbs } 41156979Sgibbs 41256979Sgibbs /* 41356979Sgibbs * Load the Microcode. 41456979Sgibbs * 41556979Sgibbs * Assume the following compressed format of the microcode buffer: 41656979Sgibbs * 41756979Sgibbs * 253 word (506 byte) table indexed by byte code followed 41856979Sgibbs * by the following byte codes: 41956979Sgibbs * 42056979Sgibbs * 1-Byte Code: 42156979Sgibbs * 00: Emit word 0 in table. 42256979Sgibbs * 01: Emit word 1 in table. 42356979Sgibbs * . 42456979Sgibbs * FD: Emit word 253 in table. 42556979Sgibbs * 42656979Sgibbs * Multi-Byte Code: 42756979Sgibbs * FD RESEVED 42856979Sgibbs * 42956979Sgibbs * FE WW WW: (3 byte code) 43056979Sgibbs * Word to emit is the next word WW WW. 43156979Sgibbs * FF BB WW WW: (4 byte code) 43256979Sgibbs * Emit BB count times next word WW WW. 43356979Sgibbs * 43456979Sgibbs */ 43556979Sgibbs bytes_downloaded = 0; 43656979Sgibbs word_table = (const u_int16_t *)adw->mcode_data->mcode_buf; 43756979Sgibbs byte_codes = (const u_int8_t *)&word_table[253]; 43856979Sgibbs byte_codes_end = adw->mcode_data->mcode_buf 43956979Sgibbs + adw->mcode_data->mcode_size; 44040024Sgibbs adw_outw(adw, ADW_RAM_ADDR, 0); 44156979Sgibbs while (byte_codes < byte_codes_end) { 44256979Sgibbs if (*byte_codes == 0xFF) { 44356979Sgibbs u_int16_t value; 44440024Sgibbs 44556979Sgibbs value = byte_codes[2] 44656979Sgibbs | byte_codes[3] << 8; 44756979Sgibbs adw_set_multi_2(adw, ADW_RAM_DATA, 44856979Sgibbs value, byte_codes[1]); 44956979Sgibbs bytes_downloaded += byte_codes[1]; 45056979Sgibbs byte_codes += 4; 45156979Sgibbs } else if (*byte_codes == 0xFE) { 45256979Sgibbs u_int16_t value; 45356979Sgibbs 45456979Sgibbs value = byte_codes[1] 45556979Sgibbs | byte_codes[2] << 8; 45656979Sgibbs adw_outw(adw, ADW_RAM_DATA, value); 45756979Sgibbs bytes_downloaded++; 45856979Sgibbs byte_codes += 3; 45956979Sgibbs } else { 46056979Sgibbs adw_outw(adw, ADW_RAM_DATA, word_table[*byte_codes]); 46156979Sgibbs bytes_downloaded++; 46256979Sgibbs byte_codes++; 46356979Sgibbs } 46456979Sgibbs } 46556979Sgibbs /* Convert from words to bytes */ 46656979Sgibbs bytes_downloaded *= 2; 46756979Sgibbs 46840024Sgibbs /* 46940024Sgibbs * Clear the rest of LRAM. 47040024Sgibbs */ 47156979Sgibbs for (addr = bytes_downloaded; addr < adw->memsize; addr += 2) 47240024Sgibbs adw_outw(adw, ADW_RAM_DATA, 0); 47340024Sgibbs 47440024Sgibbs /* 47540024Sgibbs * Verify the microcode checksum. 47640024Sgibbs */ 47740024Sgibbs checksum = 0; 47840024Sgibbs adw_outw(adw, ADW_RAM_ADDR, 0); 47956979Sgibbs for (addr = 0; addr < bytes_downloaded; addr += 2) 48040024Sgibbs checksum += adw_inw(adw, ADW_RAM_DATA); 48140024Sgibbs 48256979Sgibbs if (checksum != adw->mcode_data->mcode_chksum) { 483241588Sjhb device_printf(adw->device, "Firmware load failed!\n"); 48456979Sgibbs return (EIO); 48540024Sgibbs } 48640024Sgibbs 48740024Sgibbs /* 48840024Sgibbs * Restore the RISC memory BIOS region. 48940024Sgibbs */ 49040024Sgibbs for (addr = 0; addr < ADW_MC_BIOSLEN; addr++) 49140024Sgibbs adw_lram_write_8(adw, addr + ADW_MC_BIOSLEN, biosmem[addr]); 49240024Sgibbs 49340024Sgibbs /* 49440024Sgibbs * Calculate and write the microcode code checksum to 49540024Sgibbs * the microcode code checksum location. 49640024Sgibbs */ 49756979Sgibbs addr = adw_lram_read_16(adw, ADW_MC_CODE_BEGIN_ADDR); 49856979Sgibbs end_addr = adw_lram_read_16(adw, ADW_MC_CODE_END_ADDR); 49940024Sgibbs checksum = 0; 50056979Sgibbs adw_outw(adw, ADW_RAM_ADDR, addr); 50156979Sgibbs for (; addr < end_addr; addr += 2) 50256979Sgibbs checksum += adw_inw(adw, ADW_RAM_DATA); 50340024Sgibbs adw_lram_write_16(adw, ADW_MC_CODE_CHK_SUM, checksum); 50440024Sgibbs 50540024Sgibbs /* 50656979Sgibbs * Tell the microcode what kind of chip it's running on. 50740024Sgibbs */ 50856979Sgibbs adw_lram_write_16(adw, ADW_MC_CHIP_TYPE, adw->chip); 50940024Sgibbs 51040024Sgibbs /* 51140024Sgibbs * Leave WDTR and SDTR negotiation disabled until the XPT has 51256979Sgibbs * informed us of device capabilities, but do set the desired 51356979Sgibbs * user rates in case we receive an SDTR request from the target 51456979Sgibbs * before we negotiate. We turn on tagged queuing at the microcode 51556979Sgibbs * level for all devices, and modulate this on a per command basis. 51640024Sgibbs */ 51756979Sgibbs adw_lram_write_16(adw, ADW_MC_SDTR_SPEED1, adw->user_sdtr[0]); 51856979Sgibbs adw_lram_write_16(adw, ADW_MC_SDTR_SPEED2, adw->user_sdtr[1]); 51956979Sgibbs adw_lram_write_16(adw, ADW_MC_SDTR_SPEED3, adw->user_sdtr[2]); 52056979Sgibbs adw_lram_write_16(adw, ADW_MC_SDTR_SPEED4, adw->user_sdtr[3]); 52140024Sgibbs adw_lram_write_16(adw, ADW_MC_DISC_ENABLE, adw->user_discenb); 52256979Sgibbs for (tid = 0; tid < ADW_MAX_TID; tid++) { 52356979Sgibbs /* Cam limits the maximum number of commands for us */ 52456979Sgibbs adw_lram_write_8(adw, ADW_MC_NUMBER_OF_MAX_CMD + tid, 52556979Sgibbs adw->max_acbs); 52656979Sgibbs } 52740024Sgibbs adw_lram_write_16(adw, ADW_MC_TAGQNG_ABLE, ~0); 52840024Sgibbs 52940024Sgibbs /* 53040024Sgibbs * Set SCSI_CFG0 Microcode Default Value. 53140024Sgibbs * 53240024Sgibbs * The microcode will set the SCSI_CFG0 register using this value 53340024Sgibbs * after it is started. 53440024Sgibbs */ 53540024Sgibbs adw_lram_write_16(adw, ADW_MC_DEFAULT_SCSI_CFG0, 53640024Sgibbs ADW_SCSI_CFG0_PARITY_EN|ADW_SCSI_CFG0_SEL_TMO_LONG| 53740024Sgibbs ADW_SCSI_CFG0_OUR_ID_EN|adw->initiator_id); 53856979Sgibbs 53940024Sgibbs /* 54056979Sgibbs * Tell the MC about the memory size that 54156979Sgibbs * was setup by the probe code. 54256979Sgibbs */ 54356979Sgibbs adw_lram_write_16(adw, ADW_MC_DEFAULT_MEM_CFG, 54456979Sgibbs adw_inb(adw, ADW_MEM_CFG) & ADW_MEM_CFG_RAM_SZ_MASK); 54556979Sgibbs 54656979Sgibbs /* 54740024Sgibbs * Determine SCSI_CFG1 Microcode Default Value. 54840024Sgibbs * 54940024Sgibbs * The microcode will set the SCSI_CFG1 register using this value 55040024Sgibbs * after it is started below. 55140024Sgibbs */ 55240024Sgibbs scsicfg1 = adw_inw(adw, ADW_SCSI_CFG1); 55340024Sgibbs 55440024Sgibbs /* 55540024Sgibbs * If the internal narrow cable is reversed all of the SCSI_CTRL 55640024Sgibbs * register signals will be set. Check for and return an error if 55740024Sgibbs * this condition is found. 55840024Sgibbs */ 55940024Sgibbs if ((adw_inw(adw, ADW_SCSI_CTRL) & 0x3F07) == 0x3F07) { 560241588Sjhb device_printf(adw->device, "Illegal Cable Config!\n"); 561241588Sjhb device_printf(adw->device, "Internal cable is reversed!\n"); 56256979Sgibbs return (EIO); 56340024Sgibbs } 56440024Sgibbs 56540024Sgibbs /* 56640024Sgibbs * If this is a differential board and a single-ended device 56740024Sgibbs * is attached to one of the connectors, return an error. 56840024Sgibbs */ 56956979Sgibbs if ((adw->features & ADW_ULTRA) != 0) { 57056979Sgibbs if ((scsicfg1 & ADW_SCSI_CFG1_DIFF_MODE) != 0 57156979Sgibbs && (scsicfg1 & ADW_SCSI_CFG1_DIFF_SENSE) == 0) { 572241588Sjhb device_printf(adw->device, "A Single Ended Device is " 573241588Sjhb "attached to our differential bus!\n"); 57456979Sgibbs return (EIO); 57556979Sgibbs } 57656979Sgibbs } else { 57756979Sgibbs if ((scsicfg1 & ADW2_SCSI_CFG1_DEV_DETECT_HVD) != 0) { 578241588Sjhb device_printf(adw->device, 579241588Sjhb "A High Voltage Differential Device " 580241588Sjhb "is attached to this controller.\n"); 581241588Sjhb device_printf(adw->device, 582241588Sjhb "HVD devices are not supported.\n"); 58356979Sgibbs return (EIO); 58456979Sgibbs } 58540024Sgibbs } 58640024Sgibbs 58740024Sgibbs /* 58840024Sgibbs * Perform automatic termination control if desired. 58940024Sgibbs */ 59056979Sgibbs if ((adw->features & ADW_ULTRA2) != 0) { 59156979Sgibbs u_int cable_det; 59256979Sgibbs 59356979Sgibbs /* 59456979Sgibbs * Ultra2 Chips require termination disabled to 59556979Sgibbs * detect cable presence. 59656979Sgibbs */ 59756979Sgibbs adw_outw(adw, ADW_SCSI_CFG1, 59856979Sgibbs scsicfg1 | ADW2_SCSI_CFG1_DIS_TERM_DRV); 59956979Sgibbs cable_det = adw_inw(adw, ADW_SCSI_CFG1); 60056979Sgibbs adw_outw(adw, ADW_SCSI_CFG1, scsicfg1); 60156979Sgibbs 60256979Sgibbs /* SE Termination first if auto-term has been specified */ 60356979Sgibbs if ((term_scsicfg1 & ADW_SCSI_CFG1_TERM_CTL_MASK) == 0) { 60456979Sgibbs 60556979Sgibbs /* 60656979Sgibbs * For all SE cable configurations, high byte 60756979Sgibbs * termination is enabled. 60856979Sgibbs */ 60940024Sgibbs term_scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_H; 61056979Sgibbs if ((cable_det & ADW_SCSI_CFG1_INT8_MASK) != 0 61156979Sgibbs || (cable_det & ADW_SCSI_CFG1_INT16_MASK) != 0) { 61256979Sgibbs /* 61356979Sgibbs * If either cable is not present, the 61456979Sgibbs * low byte must be terminated as well. 61556979Sgibbs */ 61656979Sgibbs term_scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_L; 61756979Sgibbs } 61840024Sgibbs } 61956979Sgibbs 62056979Sgibbs /* LVD auto-term */ 62156979Sgibbs if ((term_scsicfg1 & ADW2_SCSI_CFG1_TERM_CTL_LVD) == 0 62256979Sgibbs && (term_scsicfg1 & ADW2_SCSI_CFG1_DIS_TERM_DRV) == 0) { 62356979Sgibbs /* 62456979Sgibbs * If both cables are installed, termination 62556979Sgibbs * is disabled. Otherwise it is enabled. 62656979Sgibbs */ 62756979Sgibbs if ((cable_det & ADW2_SCSI_CFG1_EXTLVD_MASK) != 0 62856979Sgibbs || (cable_det & ADW2_SCSI_CFG1_INTLVD_MASK) != 0) { 62956979Sgibbs 63056979Sgibbs term_scsicfg1 |= ADW2_SCSI_CFG1_TERM_CTL_LVD; 63156979Sgibbs } 63256979Sgibbs } 63356979Sgibbs term_scsicfg1 &= ~ADW2_SCSI_CFG1_DIS_TERM_DRV; 63456979Sgibbs } else { 63556979Sgibbs /* Ultra Controller Termination */ 63656979Sgibbs if ((term_scsicfg1 & ADW_SCSI_CFG1_TERM_CTL_MASK) == 0) { 63756979Sgibbs int cable_count; 63856979Sgibbs int wide_cable_count; 63956979Sgibbs 64056979Sgibbs cable_count = 0; 64156979Sgibbs wide_cable_count = 0; 64256979Sgibbs if ((scsicfg1 & ADW_SCSI_CFG1_INT16_MASK) == 0) { 64356979Sgibbs cable_count++; 64456979Sgibbs wide_cable_count++; 64556979Sgibbs } 64656979Sgibbs if ((scsicfg1 & ADW_SCSI_CFG1_INT8_MASK) == 0) 64756979Sgibbs cable_count++; 64856979Sgibbs 64956979Sgibbs /* There is only one external port */ 65056979Sgibbs if ((scsicfg1 & ADW_SCSI_CFG1_EXT16_MASK) == 0) { 65156979Sgibbs cable_count++; 65256979Sgibbs wide_cable_count++; 65356979Sgibbs } else if ((scsicfg1 & ADW_SCSI_CFG1_EXT8_MASK) == 0) 65456979Sgibbs cable_count++; 65556979Sgibbs 65656979Sgibbs if (cable_count == 3) { 657241588Sjhb device_printf(adw->device, 658241588Sjhb "Illegal Cable Config!\n"); 659241588Sjhb device_printf(adw->device, 660241588Sjhb "Only Two Ports may be used at a time!\n"); 66156979Sgibbs } else if (cable_count <= 1) { 66256979Sgibbs /* 66356979Sgibbs * At least two out of three cables missing. 66456979Sgibbs * Terminate both bytes. 66556979Sgibbs */ 66656979Sgibbs term_scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_H 66756979Sgibbs | ADW_SCSI_CFG1_TERM_CTL_L; 66856979Sgibbs } else if (wide_cable_count <= 1) { 66956979Sgibbs /* No two 16bit cables present. High on. */ 67056979Sgibbs term_scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_H; 67156979Sgibbs } 67256979Sgibbs } 67340024Sgibbs } 67440024Sgibbs 67540024Sgibbs /* Tell the user about our decission */ 67640024Sgibbs switch (term_scsicfg1 & ADW_SCSI_CFG1_TERM_CTL_MASK) { 67740024Sgibbs case ADW_SCSI_CFG1_TERM_CTL_MASK: 67856979Sgibbs printf("High & Low SE Term Enabled, "); 67940024Sgibbs break; 68040024Sgibbs case ADW_SCSI_CFG1_TERM_CTL_H: 68156979Sgibbs printf("High SE Termination Enabled, "); 68240024Sgibbs break; 68340024Sgibbs case ADW_SCSI_CFG1_TERM_CTL_L: 68456979Sgibbs printf("Low SE Term Enabled, "); 68540024Sgibbs break; 68640024Sgibbs default: 68740024Sgibbs break; 68840024Sgibbs } 68940024Sgibbs 69056979Sgibbs if ((adw->features & ADW_ULTRA2) != 0 69156979Sgibbs && (term_scsicfg1 & ADW2_SCSI_CFG1_TERM_CTL_LVD) != 0) 69256979Sgibbs printf("LVD Term Enabled, "); 69356979Sgibbs 69440024Sgibbs /* 69540024Sgibbs * Invert the TERM_CTL_H and TERM_CTL_L bits and then 69640024Sgibbs * set 'scsicfg1'. The TERM_POL bit does not need to be 69740024Sgibbs * referenced, because the hardware internally inverts 69840024Sgibbs * the Termination High and Low bits if TERM_POL is set. 69940024Sgibbs */ 70056979Sgibbs if ((adw->features & ADW_ULTRA2) != 0) { 70156979Sgibbs term_scsicfg1 = ~term_scsicfg1; 70256979Sgibbs term_scsicfg1 &= ADW_SCSI_CFG1_TERM_CTL_MASK 70356979Sgibbs | ADW2_SCSI_CFG1_TERM_CTL_LVD; 70456979Sgibbs scsicfg1 &= ~(ADW_SCSI_CFG1_TERM_CTL_MASK 70556979Sgibbs |ADW2_SCSI_CFG1_TERM_CTL_LVD 70656979Sgibbs |ADW_SCSI_CFG1_BIG_ENDIAN 70756979Sgibbs |ADW_SCSI_CFG1_TERM_POL 70856979Sgibbs |ADW2_SCSI_CFG1_DEV_DETECT); 70956979Sgibbs scsicfg1 |= term_scsicfg1; 71056979Sgibbs } else { 71156979Sgibbs term_scsicfg1 = ~term_scsicfg1 & ADW_SCSI_CFG1_TERM_CTL_MASK; 71256979Sgibbs scsicfg1 &= ~ADW_SCSI_CFG1_TERM_CTL_MASK; 71356979Sgibbs scsicfg1 |= term_scsicfg1 | ADW_SCSI_CFG1_TERM_CTL_MANUAL; 71456979Sgibbs scsicfg1 |= ADW_SCSI_CFG1_FLTR_DISABLE; 71556979Sgibbs } 71640024Sgibbs 71740024Sgibbs /* 71840024Sgibbs * Set SCSI_CFG1 Microcode Default Value 71940024Sgibbs * 72040024Sgibbs * The microcode will set the SCSI_CFG1 register using this value 72140024Sgibbs * after it is started below. 72240024Sgibbs */ 72356979Sgibbs adw_lram_write_16(adw, ADW_MC_DEFAULT_SCSI_CFG1, scsicfg1); 72440024Sgibbs 72540024Sgibbs /* 72640024Sgibbs * Only accept selections on our initiator target id. 72740024Sgibbs * This may change in target mode scenarios... 72840024Sgibbs */ 72940024Sgibbs adw_lram_write_16(adw, ADW_MC_DEFAULT_SEL_MASK, 73040024Sgibbs (0x01 << adw->initiator_id)); 73140024Sgibbs 73240024Sgibbs /* 73356979Sgibbs * Tell the microcode where it can find our 73456979Sgibbs * Initiator Command Queue (ICQ). It is 73556979Sgibbs * currently empty hence the "stopper" address. 73640024Sgibbs */ 73756979Sgibbs adw->commandq = adw->free_carriers; 73856979Sgibbs adw->free_carriers = carrierbotov(adw, adw->commandq->next_ba); 73956979Sgibbs adw->commandq->next_ba = ADW_CQ_STOPPER; 74056979Sgibbs adw_lram_write_32(adw, ADW_MC_ICQ, adw->commandq->carr_ba); 74140024Sgibbs 74240024Sgibbs /* 74356979Sgibbs * Tell the microcode where it can find our 74456979Sgibbs * Initiator Response Queue (IRQ). It too 74556979Sgibbs * is currently empty. 74640024Sgibbs */ 74756979Sgibbs adw->responseq = adw->free_carriers; 74856979Sgibbs adw->free_carriers = carrierbotov(adw, adw->responseq->next_ba); 74956979Sgibbs adw->responseq->next_ba = ADW_CQ_STOPPER; 75056979Sgibbs adw_lram_write_32(adw, ADW_MC_IRQ, adw->responseq->carr_ba); 75140024Sgibbs 75240024Sgibbs adw_outb(adw, ADW_INTR_ENABLES, 75340024Sgibbs ADW_INTR_ENABLE_HOST_INTR|ADW_INTR_ENABLE_GLOBAL_INTR); 75440024Sgibbs 75540024Sgibbs adw_outw(adw, ADW_PC, adw_lram_read_16(adw, ADW_MC_CODE_BEGIN_ADDR)); 75640024Sgibbs 75740024Sgibbs return (0); 75840024Sgibbs} 75940024Sgibbs 76056979Sgibbsvoid 76156979Sgibbsadw_set_user_sdtr(struct adw_softc *adw, u_int tid, u_int mc_sdtr) 76256979Sgibbs{ 76356979Sgibbs adw->user_sdtr[ADW_TARGET_GROUP(tid)] &= ~ADW_TARGET_GROUP_MASK(tid); 76456979Sgibbs adw->user_sdtr[ADW_TARGET_GROUP(tid)] |= 76556979Sgibbs mc_sdtr << ADW_TARGET_GROUP_SHIFT(tid); 76656979Sgibbs} 76756979Sgibbs 76856979Sgibbsu_int 76956979Sgibbsadw_get_user_sdtr(struct adw_softc *adw, u_int tid) 77056979Sgibbs{ 77156979Sgibbs u_int mc_sdtr; 77256979Sgibbs 77356979Sgibbs mc_sdtr = adw->user_sdtr[ADW_TARGET_GROUP(tid)]; 77456979Sgibbs mc_sdtr &= ADW_TARGET_GROUP_MASK(tid); 77556979Sgibbs mc_sdtr >>= ADW_TARGET_GROUP_SHIFT(tid); 77656979Sgibbs return (mc_sdtr); 77756979Sgibbs} 77856979Sgibbs 77956979Sgibbsvoid 78056979Sgibbsadw_set_chip_sdtr(struct adw_softc *adw, u_int tid, u_int sdtr) 78156979Sgibbs{ 78256979Sgibbs u_int mc_sdtr_offset; 78356979Sgibbs u_int mc_sdtr; 78456979Sgibbs 78556979Sgibbs mc_sdtr_offset = ADW_MC_SDTR_SPEED1; 78656979Sgibbs mc_sdtr_offset += ADW_TARGET_GROUP(tid) * 2; 78756979Sgibbs mc_sdtr = adw_lram_read_16(adw, mc_sdtr_offset); 78856979Sgibbs mc_sdtr &= ~ADW_TARGET_GROUP_MASK(tid); 78956979Sgibbs mc_sdtr |= sdtr << ADW_TARGET_GROUP_SHIFT(tid); 79056979Sgibbs adw_lram_write_16(adw, mc_sdtr_offset, mc_sdtr); 79156979Sgibbs} 79256979Sgibbs 79356979Sgibbsu_int 79456979Sgibbsadw_get_chip_sdtr(struct adw_softc *adw, u_int tid) 79556979Sgibbs{ 79656979Sgibbs u_int mc_sdtr_offset; 79756979Sgibbs u_int mc_sdtr; 79856979Sgibbs 79956979Sgibbs mc_sdtr_offset = ADW_MC_SDTR_SPEED1; 80056979Sgibbs mc_sdtr_offset += ADW_TARGET_GROUP(tid) * 2; 80156979Sgibbs mc_sdtr = adw_lram_read_16(adw, mc_sdtr_offset); 80256979Sgibbs mc_sdtr &= ADW_TARGET_GROUP_MASK(tid); 80356979Sgibbs mc_sdtr >>= ADW_TARGET_GROUP_SHIFT(tid); 80456979Sgibbs return (mc_sdtr); 80556979Sgibbs} 80656979Sgibbs 80756979Sgibbsu_int 80856979Sgibbsadw_find_sdtr(struct adw_softc *adw, u_int period) 80956979Sgibbs{ 81056979Sgibbs int i; 81156979Sgibbs 81256979Sgibbs i = 0; 81356979Sgibbs if ((adw->features & ADW_DT) == 0) 81456979Sgibbs i = ADW_MC_SDTR_OFFSET_ULTRA2; 81556979Sgibbs if ((adw->features & ADW_ULTRA2) == 0) 81656979Sgibbs i = ADW_MC_SDTR_OFFSET_ULTRA; 81756979Sgibbs if (period == 0) 81856979Sgibbs return ADW_MC_SDTR_ASYNC; 81956979Sgibbs 82056979Sgibbs for (; i < adw_num_syncrates; i++) { 82156979Sgibbs if (period <= adw_syncrates[i].period) 82256979Sgibbs return (adw_syncrates[i].mc_sdtr); 82356979Sgibbs } 82456979Sgibbs return ADW_MC_SDTR_ASYNC; 82556979Sgibbs} 82656979Sgibbs 82756979Sgibbsu_int 82856979Sgibbsadw_find_period(struct adw_softc *adw, u_int mc_sdtr) 82956979Sgibbs{ 83056979Sgibbs int i; 83156979Sgibbs 83256979Sgibbs for (i = 0; i < adw_num_syncrates; i++) { 83356979Sgibbs if (mc_sdtr == adw_syncrates[i].mc_sdtr) 83456979Sgibbs break; 83556979Sgibbs } 83656979Sgibbs return (adw_syncrates[i].period); 83756979Sgibbs} 83856979Sgibbs 83956979Sgibbsu_int 84056979Sgibbsadw_hshk_cfg_period_factor(u_int tinfo) 84156979Sgibbs{ 84256979Sgibbs tinfo &= ADW_HSHK_CFG_RATE_MASK; 84356979Sgibbs tinfo >>= ADW_HSHK_CFG_RATE_SHIFT; 84456979Sgibbs if (tinfo == 0x11) 84556979Sgibbs /* 80MHz/DT */ 84656979Sgibbs return (9); 84756979Sgibbs else if (tinfo == 0x10) 84856979Sgibbs /* 40MHz */ 84956979Sgibbs return (10); 85056979Sgibbs else 85156979Sgibbs return (((tinfo * 25) + 50) / 4); 85256979Sgibbs} 85356979Sgibbs 85440024Sgibbs/* 85557679Sgibbs * Send an idle command to the chip and wait for completion. 85640024Sgibbs */ 85757679Sgibbsadw_idle_cmd_status_t 85840024Sgibbsadw_idle_cmd_send(struct adw_softc *adw, adw_idle_cmd_t cmd, u_int parameter) 85940024Sgibbs{ 86057679Sgibbs u_int timeout; 86157679Sgibbs adw_idle_cmd_status_t status; 86240024Sgibbs 863241588Sjhb if (!dumping) 864241588Sjhb mtx_assert(&adw->lock, MA_OWNED); 86540024Sgibbs 86657679Sgibbs /* 86757679Sgibbs * Clear the idle command status which is set by the microcode 86857679Sgibbs * to a non-zero value to indicate when the command is completed. 86957679Sgibbs */ 87057679Sgibbs adw_lram_write_16(adw, ADW_MC_IDLE_CMD_STATUS, 0); 87140024Sgibbs 87240024Sgibbs /* 87340024Sgibbs * Write the idle command value after the idle command parameter 87440024Sgibbs * has been written to avoid a race condition. If the order is not 87540024Sgibbs * followed, the microcode may process the idle command before the 87640024Sgibbs * parameters have been written to LRAM. 87740024Sgibbs */ 87857679Sgibbs adw_lram_write_32(adw, ADW_MC_IDLE_CMD_PARAMETER, parameter); 87940024Sgibbs adw_lram_write_16(adw, ADW_MC_IDLE_CMD, cmd); 88056979Sgibbs 88156979Sgibbs /* 88256979Sgibbs * Tickle the RISC to tell it to process the idle command. 88356979Sgibbs */ 88456979Sgibbs adw_tickle_risc(adw, ADW_TICKLE_B); 88540024Sgibbs 88640024Sgibbs /* Wait for up to 10 seconds for the command to complete */ 88757679Sgibbs timeout = 5000000; 88840024Sgibbs while (--timeout) { 88956979Sgibbs status = adw_lram_read_16(adw, ADW_MC_IDLE_CMD_STATUS); 89056979Sgibbs if (status != 0) 89140024Sgibbs break; 89257679Sgibbs DELAY(20); 89340024Sgibbs } 89440024Sgibbs 89540024Sgibbs if (timeout == 0) 896241588Sjhb panic("%s: Idle Command Timed Out!", 897241588Sjhb device_get_nameunit(adw->device)); 89840024Sgibbs return (status); 89940024Sgibbs} 900