1321369Sdim/*- 2193323Sed * Low level routines for Second Generation 3353358Sdim * Advanced Systems Inc. SCSI controllers chips 4353358Sdim * 5353358Sdim * Copyright (c) 1998, 1999, 2000 Justin Gibbs. 6193323Sed * All rights reserved. 7193323Sed * 8193323Sed * Redistribution and use in source and binary forms, with or without 9193323Sed * modification, are permitted provided that the following conditions 10193323Sed * are met: 11193323Sed * 1. Redistributions of source code must retain the above copyright 12193323Sed * notice, this list of conditions, and the following disclaimer, 13193323Sed * without modification. 14193323Sed * 2. Redistributions in binary form must reproduce the above copyright 15193323Sed * notice, this list of conditions and the following disclaimer in the 16193323Sed * documentation and/or other materials provided with the distribution. 17193323Sed * 3. The name of the author may not be used to endorse or promote products 18249423Sdim * derived from this software without specific prior written permission. 19344779Sdim * 20193323Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21193323Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22276479Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23344779Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 24249423Sdim * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25327952Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26276479Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27249423Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28249423Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29344779Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30249423Sdim * SUCH DAMAGE. 31344779Sdim */ 32321369Sdim/*- 33321369Sdim * Ported from: 34321369Sdim * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters 35321369Sdim * 36193323Sed * Copyright (c) 1995-1998 Advanced System Products, Inc. 37193323Sed * All Rights Reserved. 38193323Sed * 39360784Sdim * Redistribution and use in source and binary forms, with or without 40309124Sdim * modification, are permitted provided that redistributions of source 41321369Sdim * code retain the above copyright notice and this comment without 42321369Sdim * modification. 43321369Sdim */ 44321369Sdim 45321369Sdim#include <sys/cdefs.h> 46321369Sdim__FBSDID("$FreeBSD$"); 47321369Sdim 48321369Sdim#include <sys/param.h> 49208599Srdivacky#include <sys/conf.h> 50327952Sdim#include <sys/lock.h> 51321369Sdim#include <sys/mutex.h> 52193323Sed#include <sys/systm.h> 53226633Sdim#include <sys/bus.h> 54193323Sed#include <sys/rman.h> 55193323Sed 56193323Sed#include <machine/bus.h> 57288943Sdim 58193323Sed#include <cam/cam.h> 59249423Sdim#include <cam/cam_ccb.h> 60249423Sdim#include <cam/cam_sim.h> 61249423Sdim#include <cam/cam_xpt_sim.h> 62249423Sdim#include <cam/scsi/scsi_all.h> 63296417Sdim 64314564Sdim#include <dev/advansys/adwlib.h> 65314564Sdim 66198090Srdivackyconst struct adw_eeprom adw_asc3550_default_eeprom = 67344779Sdim{ 68198090Srdivacky ADW_EEPROM_BIOS_ENABLE, /* cfg_lsw */ 69203954Srdivacky 0x0000, /* cfg_msw */ 70203954Srdivacky 0xFFFF, /* disc_enable */ 71203954Srdivacky 0xFFFF, /* wdtr_able */ 72203954Srdivacky { 0xFFFF }, /* sdtr_able */ 73203954Srdivacky 0xFFFF, /* start_motor */ 74327952Sdim 0xFFFF, /* tagqng_able */ 75327952Sdim 0xFFFF, /* bios_scan */ 76327952Sdim 0, /* scam_tolerant */ 77203954Srdivacky 7, /* adapter_scsi_id */ 78221345Sdim 0, /* bios_boot_delay */ 79221345Sdim 3, /* scsi_reset_delay */ 80234353Sdim 0, /* bios_id_lun */ 81234353Sdim 0, /* termination */ 82221345Sdim 0, /* reserved1 */ 83296417Sdim 0xFFE7, /* bios_ctrl */ 84296417Sdim { 0xFFFF }, /* ultra_able */ 85296417Sdim { 0 }, /* reserved2 */ 86341825Sdim ADW_DEF_MAX_HOST_QNG, /* max_host_qng */ 87341825Sdim ADW_DEF_MAX_DVC_QNG, /* max_dvc_qng */ 88341825Sdim 0, /* dvc_cntl */ 89341825Sdim { 0 }, /* bug_fix */ 90341825Sdim { 0, 0, 0 }, /* serial_number */ 91341825Sdim 0, /* check_sum */ 92341825Sdim { /* oem_name[16] */ 93341825Sdim 0, 0, 0, 0, 0, 0, 0, 0, 94341825Sdim 0, 0, 0, 0, 0, 0, 0, 0 95341825Sdim }, 96341825Sdim 0, /* dvc_err_code */ 97341825Sdim 0, /* adv_err_code */ 98341825Sdim 0, /* adv_err_addr */ 99344779Sdim 0, /* saved_dvc_err_code */ 100341825Sdim 0, /* saved_adv_err_code */ 101344779Sdim 0 /* saved_adv_err_addr */ 102344779Sdim}; 103344779Sdim 104344779Sdimconst struct adw_eeprom adw_asc38C0800_default_eeprom = 105353358Sdim{ 106344779Sdim ADW_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */ 107360784Sdim 0x0000, /* 01 cfg_msw */ 108360784Sdim 0xFFFF, /* 02 disc_enable */ 109221345Sdim 0xFFFF, /* 03 wdtr_able */ 110321369Sdim { 0x4444 }, /* 04 sdtr_speed1 */ 111198090Srdivacky 0xFFFF, /* 05 start_motor */ 112224145Sdim 0xFFFF, /* 06 tagqng_able */ 113321369Sdim 0xFFFF, /* 07 bios_scan */ 114193323Sed 0, /* 08 scam_tolerant */ 115249423Sdim 7, /* 09 adapter_scsi_id */ 116321369Sdim 0, /* bios_boot_delay */ 117321369Sdim 3, /* 10 scsi_reset_delay */ 118321369Sdim 0, /* bios_id_lun */ 119249423Sdim 0, /* 11 termination_se */ 120249423Sdim 0, /* termination_lvd */ 121341825Sdim 0xFFE7, /* 12 bios_ctrl */ 122221345Sdim { 0x4444 }, /* 13 sdtr_speed2 */ 123221345Sdim { 0x4444 }, /* 14 sdtr_speed3 */ 124221345Sdim ADW_DEF_MAX_HOST_QNG, /* 15 max_host_qng */ 125321369Sdim ADW_DEF_MAX_DVC_QNG, /* max_dvc_qng */ 126199481Srdivacky 0, /* 16 dvc_cntl */ 127199481Srdivacky { 0x4444 } , /* 17 sdtr_speed4 */ 128199481Srdivacky { 0, 0, 0 }, /* 18-20 serial_number */ 129199481Srdivacky 0, /* 21 check_sum */ 130199481Srdivacky { /* 22-29 oem_name[16] */ 131199481Srdivacky 0, 0, 0, 0, 0, 0, 0, 0, 132344779Sdim 0, 0, 0, 0, 0, 0, 0, 0 133344779Sdim }, 134344779Sdim 0, /* 30 dvc_err_code */ 135344779Sdim 0, /* 31 adv_err_code */ 136344779Sdim 0, /* 32 adv_err_addr */ 137344779Sdim 0, /* 33 saved_dvc_err_code */ 138344779Sdim 0, /* 34 saved_adv_err_code */ 139360661Sdim 0, /* 35 saved_adv_err_addr */ 140344779Sdim { /* 36 - 55 reserved */ 141344779Sdim 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 142344779Sdim 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 143344779Sdim }, 144360661Sdim 0, /* 56 cisptr_lsw */ 145360661Sdim 0, /* 57 cisprt_msw */ 146344779Sdim /* 58-59 sub-id */ 147344779Sdim (PCI_ID_ADVANSYS_38C0800_REV1 & PCI_ID_DEV_VENDOR_MASK) >> 32, 148360661Sdim}; 149344779Sdim 150360661Sdim#define ADW_MC_SDTR_OFFSET_ULTRA2_DT 0 151360661Sdim#define ADW_MC_SDTR_OFFSET_ULTRA2 1 152360661Sdim#define ADW_MC_SDTR_OFFSET_ULTRA 2 153344779Sdimconst struct adw_syncrate adw_syncrates[] = 154360661Sdim{ 155360661Sdim /* mc_sdtr period rate */ 156234353Sdim { ADW_MC_SDTR_80, 9, "80.0" }, 157344779Sdim { ADW_MC_SDTR_40, 10, "40.0" }, 158344779Sdim { ADW_MC_SDTR_20, 12, "20.0" }, 159344779Sdim { ADW_MC_SDTR_10, 25, "10.0" }, 160344779Sdim { ADW_MC_SDTR_5, 50, "5.0" }, 161344779Sdim { ADW_MC_SDTR_ASYNC, 0, "async" } 162344779Sdim}; 163344779Sdim 164344779Sdimconst int adw_num_syncrates = sizeof(adw_syncrates) / sizeof(adw_syncrates[0]); 165344779Sdim 166360661Sdimstatic u_int16_t adw_eeprom_read_16(struct adw_softc *adw, int addr); 167360661Sdimstatic void adw_eeprom_write_16(struct adw_softc *adw, int addr, 168344779Sdim u_int data); 169344779Sdimstatic void adw_eeprom_wait(struct adw_softc *adw); 170344779Sdim 171344779Sdimint 172344779Sdimadw_find_signature(struct adw_softc *adw) 173344779Sdim{ 174344779Sdim if (adw_inb(adw, ADW_SIGNATURE_BYTE) == ADW_CHIP_ID_BYTE 175344779Sdim && adw_inw(adw, ADW_SIGNATURE_WORD) == ADW_CHIP_ID_WORD) 176344779Sdim return (1); 177344779Sdim return (0); 178344779Sdim} 179344779Sdim 180344779Sdim/* 181344779Sdim * Reset Chip. 182344779Sdim */ 183344779Sdimvoid 184344779Sdimadw_reset_chip(struct adw_softc *adw) 185344779Sdim{ 186360661Sdim adw_outw(adw, ADW_CTRL_REG, ADW_CTRL_REG_CMD_RESET); 187360661Sdim DELAY(1000 * 100); 188360661Sdim adw_outw(adw, ADW_CTRL_REG, ADW_CTRL_REG_CMD_WR_IO_REG); 189360661Sdim 190344779Sdim /* 191344779Sdim * Initialize Chip registers. 192344779Sdim */ 193344779Sdim adw_outw(adw, ADW_SCSI_CFG1, 194344779Sdim adw_inw(adw, ADW_SCSI_CFG1) & ~ADW_SCSI_CFG1_BIG_ENDIAN); 195344779Sdim} 196344779Sdim 197344779Sdim/* 198344779Sdim * Reset the SCSI bus. 199344779Sdim */ 200344779Sdimint 201360661Sdimadw_reset_bus(struct adw_softc *adw) 202344779Sdim{ 203344779Sdim adw_idle_cmd_status_t status; 204344779Sdim 205344779Sdim if (!dumping) 206344779Sdim mtx_assert(&adw->lock, MA_OWNED); 207344779Sdim status = 208344779Sdim adw_idle_cmd_send(adw, ADW_IDLE_CMD_SCSI_RESET_START, /*param*/0); 209344779Sdim if (status != ADW_IDLE_CMD_SUCCESS) { 210360661Sdim xpt_print_path(adw->path); 211360661Sdim printf("Bus Reset start attempt failed\n"); 212360661Sdim return (1); 213344779Sdim } 214344779Sdim DELAY(ADW_BUS_RESET_HOLD_DELAY_US); 215344779Sdim status = 216360661Sdim adw_idle_cmd_send(adw, ADW_IDLE_CMD_SCSI_RESET_END, /*param*/0); 217360661Sdim if (status != ADW_IDLE_CMD_SUCCESS) { 218344779Sdim xpt_print_path(adw->path); 219360661Sdim printf("Bus Reset end attempt failed\n"); 220360661Sdim return (1); 221344779Sdim } 222344779Sdim return (0); 223344779Sdim} 224344779Sdim 225344779Sdim/* 226344779Sdim * Read the specified EEPROM location 227344779Sdim */ 228344779Sdimstatic u_int16_t 229344779Sdimadw_eeprom_read_16(struct adw_softc *adw, int addr) 230344779Sdim{ 231344779Sdim adw_outw(adw, ADW_EEP_CMD, ADW_EEP_CMD_READ | addr); 232344779Sdim adw_eeprom_wait(adw); 233344779Sdim return (adw_inw(adw, ADW_EEP_DATA)); 234344779Sdim} 235344779Sdim 236344779Sdimstatic void 237344779Sdimadw_eeprom_write_16(struct adw_softc *adw, int addr, u_int data) 238344779Sdim{ 239344779Sdim adw_outw(adw, ADW_EEP_DATA, data); 240344779Sdim adw_outw(adw, ADW_EEP_CMD, ADW_EEP_CMD_WRITE | addr); 241344779Sdim adw_eeprom_wait(adw); 242344779Sdim} 243344779Sdim 244344779Sdim/* 245193323Sed * Wait for and EEPROM command to complete 246193323Sed */ 247193323Sedstatic void 248193323Sedadw_eeprom_wait(struct adw_softc *adw) 249314564Sdim{ 250193323Sed int i; 251193323Sed 252288943Sdim for (i = 0; i < ADW_EEP_DELAY_MS; i++) { 253193323Sed if ((adw_inw(adw, ADW_EEP_CMD) & ADW_EEP_CMD_DONE) != 0) 254193323Sed break; 255193323Sed DELAY(1000); 256288943Sdim } 257288943Sdim if (i == ADW_EEP_DELAY_MS) 258224145Sdim panic("%s: Timedout Reading EEPROM", 259341825Sdim device_get_nameunit(adw->device)); 260288943Sdim} 261193323Sed 262193323Sed/* 263193323Sed * Read EEPROM configuration into the specified buffer. 264193323Sed * 265193323Sed * Return a checksum based on the EEPROM configuration read. 266321369Sdim */ 267321369Sdimu_int16_t 268321369Sdimadw_eeprom_read(struct adw_softc *adw, struct adw_eeprom *eep_buf) 269321369Sdim{ 270321369Sdim u_int16_t *wbuf; 271193323Sed u_int16_t wval; 272193323Sed u_int16_t chksum; 273193323Sed int eep_addr; 274327952Sdim 275327952Sdim wbuf = (u_int16_t *)eep_buf; 276327952Sdim chksum = 0; 277327952Sdim 278327952Sdim for (eep_addr = ADW_EEP_DVC_CFG_BEGIN; 279327952Sdim eep_addr < ADW_EEP_DVC_CFG_END; 280327952Sdim eep_addr++, wbuf++) { 281327952Sdim wval = adw_eeprom_read_16(adw, eep_addr); 282327952Sdim chksum += wval; 283327952Sdim *wbuf = wval; 284327952Sdim } 285288943Sdim 286221345Sdim /* checksum field is not counted in the checksum */ 287199481Srdivacky *wbuf = adw_eeprom_read_16(adw, eep_addr); 288288943Sdim wbuf++; 289218893Sdim 290221345Sdim /* Driver seeprom variables are not included in the checksum */ 291288943Sdim for (eep_addr = ADW_EEP_DVC_CTL_BEGIN; 292203954Srdivacky eep_addr < ADW_EEP_MAX_WORD_ADDR; 293199481Srdivacky eep_addr++, wbuf++) 294199481Srdivacky *wbuf = adw_eeprom_read_16(adw, eep_addr); 295199481Srdivacky 296288943Sdim return (chksum); 297314564Sdim} 298314564Sdim 299199481Srdivackyvoid 300221345Sdimadw_eeprom_write(struct adw_softc *adw, struct adw_eeprom *eep_buf) 301288943Sdim{ 302234353Sdim u_int16_t *wbuf; 303234353Sdim u_int16_t addr; 304234353Sdim u_int16_t chksum; 305234353Sdim 306288943Sdim wbuf = (u_int16_t *)eep_buf; 307341825Sdim chksum = 0; 308221345Sdim 309221345Sdim adw_outw(adw, ADW_EEP_CMD, ADW_EEP_CMD_WRITE_ABLE); 310221345Sdim adw_eeprom_wait(adw); 311288943Sdim 312221345Sdim /* 313221345Sdim * Write EEPROM until checksum. 314221345Sdim */ 315221345Sdim for (addr = ADW_EEP_DVC_CFG_BEGIN; 316288943Sdim addr < ADW_EEP_DVC_CFG_END; addr++, wbuf++) { 317221345Sdim chksum += *wbuf; 318341825Sdim adw_eeprom_write_16(adw, addr, *wbuf); 319221345Sdim } 320221345Sdim 321221345Sdim /* 322249423Sdim * Write calculated EEPROM checksum 323249423Sdim */ 324249423Sdim adw_eeprom_write_16(adw, addr, chksum); 325221345Sdim 326221345Sdim /* skip over buffer's checksum */ 327234353Sdim wbuf++; 328234353Sdim 329341825Sdim /* 330234353Sdim * Write the rest. 331234353Sdim */ 332288943Sdim for (addr = ADW_EEP_DVC_CTL_BEGIN; 333218893Sdim addr < ADW_EEP_MAX_WORD_ADDR; addr++, wbuf++) 334234353Sdim adw_eeprom_write_16(adw, addr, *wbuf); 335234353Sdim 336234353Sdim adw_outw(adw, ADW_EEP_CMD, ADW_EEP_CMD_WRITE_DISABLE); 337234353Sdim adw_eeprom_wait(adw); 338234353Sdim} 339234353Sdim 340234353Sdimint 341234353Sdimadw_init_chip(struct adw_softc *adw, u_int term_scsicfg1) 342234353Sdim{ 343234353Sdim u_int8_t biosmem[ADW_MC_BIOSLEN]; 344234353Sdim const u_int16_t *word_table; 345234353Sdim const u_int8_t *byte_codes; 346234353Sdim const u_int8_t *byte_codes_end; 347234353Sdim u_int bios_sig; 348234353Sdim u_int bytes_downloaded; 349234353Sdim u_int addr; 350234353Sdim u_int end_addr; 351234353Sdim u_int checksum; 352234353Sdim u_int scsicfg1; 353234353Sdim u_int tid; 354234353Sdim 355234353Sdim /* 356234353Sdim * Save the RISC memory BIOS region before writing the microcode. 357234353Sdim * The BIOS may already be loaded and using its RISC LRAM region 358234353Sdim * so its region must be saved and restored. 359234353Sdim */ 360234353Sdim for (addr = 0; addr < ADW_MC_BIOSLEN; addr++) 361234353Sdim biosmem[addr] = adw_lram_read_8(adw, ADW_MC_BIOSMEM + addr); 362234353Sdim 363234353Sdim /* 364234353Sdim * Save current per TID negotiated values if the BIOS has been 365234353Sdim * loaded (BIOS signature is present). These will be used if 366234353Sdim * we cannot get information from the EEPROM. 367234353Sdim */ 368249423Sdim addr = ADW_MC_BIOS_SIGNATURE - ADW_MC_BIOSMEM; 369218893Sdim bios_sig = biosmem[addr] 370199481Srdivacky | (biosmem[addr + 1] << 8); 371288943Sdim if (bios_sig == 0x55AA 372234353Sdim && (adw->flags & ADW_EEPROM_FAILED) != 0) { 373249423Sdim u_int major_ver; 374249423Sdim u_int minor_ver; 375249423Sdim u_int sdtr_able; 376234353Sdim 377249423Sdim addr = ADW_MC_BIOS_VERSION - ADW_MC_BIOSMEM; 378249423Sdim minor_ver = biosmem[addr + 1] & 0xF; 379249423Sdim major_ver = (biosmem[addr + 1] >> 4) & 0xF; 380249423Sdim if ((adw->chip == ADW_CHIP_ASC3550) 381249423Sdim && (major_ver <= 3 382249423Sdim || (major_ver == 3 && minor_ver <= 1))) { 383249423Sdim /* 384249423Sdim * BIOS 3.1 and earlier location of 385249423Sdim * 'wdtr_able' variable. 386249423Sdim */ 387249423Sdim adw->user_wdtr = 388249423Sdim adw_lram_read_16(adw, ADW_MC_WDTR_ABLE_BIOS_31); 389249423Sdim } else { 390249423Sdim adw->user_wdtr = 391249423Sdim adw_lram_read_16(adw, ADW_MC_WDTR_ABLE); 392249423Sdim } 393249423Sdim sdtr_able = adw_lram_read_16(adw, ADW_MC_SDTR_ABLE); 394249423Sdim for (tid = 0; tid < ADW_MAX_TID; tid++) { 395249423Sdim u_int tid_mask; 396249423Sdim u_int mc_sdtr; 397249423Sdim 398249423Sdim tid_mask = 0x1 << tid; 399288943Sdim if ((sdtr_able & tid_mask) == 0) 400288943Sdim mc_sdtr = ADW_MC_SDTR_ASYNC; 401221345Sdim else if ((adw->features & ADW_DT) != 0) 402288943Sdim mc_sdtr = ADW_MC_SDTR_80; 403276479Sdim else if ((adw->features & ADW_ULTRA2) != 0) 404309124Sdim mc_sdtr = ADW_MC_SDTR_40; 405276479Sdim else 406288943Sdim mc_sdtr = ADW_MC_SDTR_20; 407280031Sdim adw_set_user_sdtr(adw, tid, mc_sdtr); 408309124Sdim } 409280031Sdim adw->user_tagenb = adw_lram_read_16(adw, ADW_MC_TAGQNG_ABLE); 410341825Sdim } 411341825Sdim 412341825Sdim /* 413341825Sdim * Load the Microcode. 414288943Sdim * 415288943Sdim * Assume the following compressed format of the microcode buffer: 416224145Sdim * 417224145Sdim * 253 word (506 byte) table indexed by byte code followed 418224145Sdim * by the following byte codes: 419224145Sdim * 420224145Sdim * 1-Byte Code: 421224145Sdim * 00: Emit word 0 in table. 422288943Sdim * 01: Emit word 1 in table. 423224145Sdim * . 424193323Sed * FD: Emit word 253 in table. 425288943Sdim * 426288943Sdim * Multi-Byte Code: 427193323Sed * FD RESEVED 428344779Sdim * 429249423Sdim * FE WW WW: (3 byte code) 430193323Sed * Word to emit is the next word WW WW. 431193323Sed * FF BB WW WW: (4 byte code) 432193323Sed * Emit BB count times next word WW WW. 433193323Sed * 434193323Sed */ 435193323Sed bytes_downloaded = 0; 436193323Sed word_table = (const u_int16_t *)adw->mcode_data->mcode_buf; 437193323Sed byte_codes = (const u_int8_t *)&word_table[253]; 438193323Sed byte_codes_end = adw->mcode_data->mcode_buf 439193323Sed + adw->mcode_data->mcode_size; 440341825Sdim adw_outw(adw, ADW_RAM_ADDR, 0); 441341825Sdim while (byte_codes < byte_codes_end) { 442341825Sdim if (*byte_codes == 0xFF) { 443341825Sdim u_int16_t value; 444341825Sdim 445360784Sdim value = byte_codes[2] 446360784Sdim | byte_codes[3] << 8; 447360784Sdim adw_set_multi_2(adw, ADW_RAM_DATA, 448360784Sdim value, byte_codes[1]); 449360784Sdim bytes_downloaded += byte_codes[1]; 450360784Sdim byte_codes += 4; 451360784Sdim } else if (*byte_codes == 0xFE) { 452360784Sdim u_int16_t value; 453360784Sdim 454360784Sdim value = byte_codes[1] 455360784Sdim | byte_codes[2] << 8; 456360784Sdim adw_outw(adw, ADW_RAM_DATA, value); 457360784Sdim bytes_downloaded++; 458360784Sdim byte_codes += 3; 459360784Sdim } else { 460360784Sdim adw_outw(adw, ADW_RAM_DATA, word_table[*byte_codes]); 461327952Sdim bytes_downloaded++; 462327952Sdim byte_codes++; 463327952Sdim } 464327952Sdim } 465327952Sdim /* Convert from words to bytes */ 466327952Sdim bytes_downloaded *= 2; 467327952Sdim 468327952Sdim /* 469327952Sdim * Clear the rest of LRAM. 470327952Sdim */ 471327952Sdim for (addr = bytes_downloaded; addr < adw->memsize; addr += 2) 472327952Sdim adw_outw(adw, ADW_RAM_DATA, 0); 473327952Sdim 474327952Sdim /* 475327952Sdim * Verify the microcode checksum. 476288943Sdim */ 477193323Sed checksum = 0; 478218893Sdim adw_outw(adw, ADW_RAM_ADDR, 0); 479341825Sdim for (addr = 0; addr < bytes_downloaded; addr += 2) 480341825Sdim checksum += adw_inw(adw, ADW_RAM_DATA); 481341825Sdim 482218893Sdim if (checksum != adw->mcode_data->mcode_chksum) { 483321369Sdim device_printf(adw->device, "Firmware load failed!\n"); 484321369Sdim return (EIO); 485218893Sdim } 486249423Sdim 487249423Sdim /* 488218893Sdim * Restore the RISC memory BIOS region. 489249423Sdim */ 490249423Sdim for (addr = 0; addr < ADW_MC_BIOSLEN; addr++) 491218893Sdim adw_lram_write_8(adw, addr + ADW_MC_BIOSLEN, biosmem[addr]); 492276479Sdim 493296417Sdim /* 494276479Sdim * Calculate and write the microcode code checksum to 495276479Sdim * the microcode code checksum location. 496296417Sdim */ 497276479Sdim addr = adw_lram_read_16(adw, ADW_MC_CODE_BEGIN_ADDR); 498276479Sdim end_addr = adw_lram_read_16(adw, ADW_MC_CODE_END_ADDR); 499296417Sdim checksum = 0; 500296417Sdim adw_outw(adw, ADW_RAM_ADDR, addr); 501276479Sdim for (; addr < end_addr; addr += 2) 502276479Sdim checksum += adw_inw(adw, ADW_RAM_DATA); 503296417Sdim adw_lram_write_16(adw, ADW_MC_CODE_CHK_SUM, checksum); 504296417Sdim 505276479Sdim /* 506276479Sdim * Tell the microcode what kind of chip it's running on. 507296417Sdim */ 508276479Sdim adw_lram_write_16(adw, ADW_MC_CHIP_TYPE, adw->chip); 509276479Sdim 510296417Sdim /* 511276479Sdim * Leave WDTR and SDTR negotiation disabled until the XPT has 512296417Sdim * informed us of device capabilities, but do set the desired 513296417Sdim * user rates in case we receive an SDTR request from the target 514276479Sdim * before we negotiate. We turn on tagged queuing at the microcode 515296417Sdim * level for all devices, and modulate this on a per command basis. 516341825Sdim */ 517276479Sdim adw_lram_write_16(adw, ADW_MC_SDTR_SPEED1, adw->user_sdtr[0]); 518296417Sdim adw_lram_write_16(adw, ADW_MC_SDTR_SPEED2, adw->user_sdtr[1]); 519276479Sdim adw_lram_write_16(adw, ADW_MC_SDTR_SPEED3, adw->user_sdtr[2]); 520296417Sdim adw_lram_write_16(adw, ADW_MC_SDTR_SPEED4, adw->user_sdtr[3]); 521341825Sdim adw_lram_write_16(adw, ADW_MC_DISC_ENABLE, adw->user_discenb); 522276479Sdim for (tid = 0; tid < ADW_MAX_TID; tid++) { 523296417Sdim /* Cam limits the maximum number of commands for us */ 524296417Sdim adw_lram_write_8(adw, ADW_MC_NUMBER_OF_MAX_CMD + tid, 525276479Sdim adw->max_acbs); 526341825Sdim } 527276479Sdim adw_lram_write_16(adw, ADW_MC_TAGQNG_ABLE, ~0); 528296417Sdim 529276479Sdim /* 530341825Sdim * Set SCSI_CFG0 Microcode Default Value. 531276479Sdim * 532309124Sdim * The microcode will set the SCSI_CFG0 register using this value 533341825Sdim * after it is started. 534341825Sdim */ 535309124Sdim adw_lram_write_16(adw, ADW_MC_DEFAULT_SCSI_CFG0, 536309124Sdim ADW_SCSI_CFG0_PARITY_EN|ADW_SCSI_CFG0_SEL_TMO_LONG| 537341825Sdim ADW_SCSI_CFG0_OUR_ID_EN|adw->initiator_id); 538341825Sdim 539309124Sdim /* 540276479Sdim * Tell the MC about the memory size that 541288943Sdim * was setup by the probe code. 542288943Sdim */ 543288943Sdim adw_lram_write_16(adw, ADW_MC_DEFAULT_MEM_CFG, 544288943Sdim adw_inb(adw, ADW_MEM_CFG) & ADW_MEM_CFG_RAM_SZ_MASK); 545288943Sdim 546344779Sdim /* 547344779Sdim * Determine SCSI_CFG1 Microcode Default Value. 548344779Sdim * 549344779Sdim * The microcode will set the SCSI_CFG1 register using this value 550344779Sdim * after it is started below. 551344779Sdim */ 552344779Sdim scsicfg1 = adw_inw(adw, ADW_SCSI_CFG1); 553344779Sdim 554344779Sdim /* 555344779Sdim * If the internal narrow cable is reversed all of the SCSI_CTRL 556344779Sdim * register signals will be set. Check for and return an error if 557344779Sdim * this condition is found. 558344779Sdim */ 559344779Sdim if ((adw_inw(adw, ADW_SCSI_CTRL) & 0x3F07) == 0x3F07) { 560344779Sdim device_printf(adw->device, "Illegal Cable Config!\n"); 561344779Sdim device_printf(adw->device, "Internal cable is reversed!\n"); 562344779Sdim return (EIO); 563344779Sdim } 564344779Sdim 565344779Sdim /* 566344779Sdim * If this is a differential board and a single-ended device 567344779Sdim * is attached to one of the connectors, return an error. 568344779Sdim */ 569344779Sdim if ((adw->features & ADW_ULTRA) != 0) { 570344779Sdim if ((scsicfg1 & ADW_SCSI_CFG1_DIFF_MODE) != 0 571344779Sdim && (scsicfg1 & ADW_SCSI_CFG1_DIFF_SENSE) == 0) { 572344779Sdim device_printf(adw->device, "A Single Ended Device is " 573344779Sdim "attached to our differential bus!\n"); 574344779Sdim return (EIO); 575344779Sdim } 576341825Sdim } else { 577296417Sdim if ((scsicfg1 & ADW2_SCSI_CFG1_DEV_DETECT_HVD) != 0) { 578296417Sdim device_printf(adw->device, 579344779Sdim "A High Voltage Differential Device " 580193323Sed "is attached to this controller.\n"); 581344779Sdim device_printf(adw->device, 582344779Sdim "HVD devices are not supported.\n"); 583344779Sdim return (EIO); 584344779Sdim } 585344779Sdim } 586344779Sdim 587344779Sdim /* 588344779Sdim * Perform automatic termination control if desired. 589344779Sdim */ 590344779Sdim if ((adw->features & ADW_ULTRA2) != 0) { 591344779Sdim u_int cable_det; 592344779Sdim 593344779Sdim /* 594344779Sdim * Ultra2 Chips require termination disabled to 595344779Sdim * detect cable presence. 596344779Sdim */ 597276479Sdim adw_outw(adw, ADW_SCSI_CFG1, 598276479Sdim scsicfg1 | ADW2_SCSI_CFG1_DIS_TERM_DRV); 599344779Sdim cable_det = adw_inw(adw, ADW_SCSI_CFG1); 600344779Sdim adw_outw(adw, ADW_SCSI_CFG1, scsicfg1); 601344779Sdim 602344779Sdim /* SE Termination first if auto-term has been specified */ 603344779Sdim if ((term_scsicfg1 & ADW_SCSI_CFG1_TERM_CTL_MASK) == 0) { 604344779Sdim 605344779Sdim /* 606344779Sdim * For all SE cable configurations, high byte 607344779Sdim * termination is enabled. 608344779Sdim */ 609193323Sed term_scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_H; 610193323Sed if ((cable_det & ADW_SCSI_CFG1_INT8_MASK) != 0 611360661Sdim || (cable_det & ADW_SCSI_CFG1_INT16_MASK) != 0) { 612360661Sdim /* 613360661Sdim * If either cable is not present, the 614360661Sdim * low byte must be terminated as well. 615360661Sdim */ 616360661Sdim term_scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_L; 617360661Sdim } 618360661Sdim } 619360661Sdim 620360661Sdim /* LVD auto-term */ 621234353Sdim if ((term_scsicfg1 & ADW2_SCSI_CFG1_TERM_CTL_LVD) == 0 622234353Sdim && (term_scsicfg1 & ADW2_SCSI_CFG1_DIS_TERM_DRV) == 0) { 623234353Sdim /* 624234353Sdim * If both cables are installed, termination 625234353Sdim * is disabled. Otherwise it is enabled. 626234353Sdim */ 627234353Sdim if ((cable_det & ADW2_SCSI_CFG1_EXTLVD_MASK) != 0 628234353Sdim || (cable_det & ADW2_SCSI_CFG1_INTLVD_MASK) != 0) { 629234353Sdim 630288943Sdim term_scsicfg1 |= ADW2_SCSI_CFG1_TERM_CTL_LVD; 631234353Sdim } 632234353Sdim } 633234353Sdim term_scsicfg1 &= ~ADW2_SCSI_CFG1_DIS_TERM_DRV; 634234353Sdim } else { 635234353Sdim /* Ultra Controller Termination */ 636344779Sdim if ((term_scsicfg1 & ADW_SCSI_CFG1_TERM_CTL_MASK) == 0) { 637344779Sdim int cable_count; 638249423Sdim int wide_cable_count; 639249423Sdim 640314564Sdim cable_count = 0; 641234353Sdim wide_cable_count = 0; 642249423Sdim if ((scsicfg1 & ADW_SCSI_CFG1_INT16_MASK) == 0) { 643314564Sdim cable_count++; 644234353Sdim wide_cable_count++; 645234353Sdim } 646360784Sdim if ((scsicfg1 & ADW_SCSI_CFG1_INT8_MASK) == 0) 647360784Sdim cable_count++; 648360784Sdim 649360784Sdim /* There is only one external port */ 650360784Sdim if ((scsicfg1 & ADW_SCSI_CFG1_EXT16_MASK) == 0) { 651360784Sdim cable_count++; 652288943Sdim wide_cable_count++; 653288943Sdim } else if ((scsicfg1 & ADW_SCSI_CFG1_EXT8_MASK) == 0) 654234353Sdim cable_count++; 655234353Sdim 656234353Sdim if (cable_count == 3) { 657234353Sdim device_printf(adw->device, 658234353Sdim "Illegal Cable Config!\n"); 659234353Sdim device_printf(adw->device, 660288943Sdim "Only Two Ports may be used at a time!\n"); 661234353Sdim } else if (cable_count <= 1) { 662234353Sdim /* 663234353Sdim * At least two out of three cables missing. 664234353Sdim * Terminate both bytes. 665234353Sdim */ 666288943Sdim term_scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_H 667234353Sdim | ADW_SCSI_CFG1_TERM_CTL_L; 668234353Sdim } else if (wide_cable_count <= 1) { 669234353Sdim /* No two 16bit cables present. High on. */ 670234353Sdim term_scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_H; 671234353Sdim } 672234353Sdim } 673234353Sdim } 674234353Sdim 675234353Sdim /* Tell the user about our decission */ 676344779Sdim switch (term_scsicfg1 & ADW_SCSI_CFG1_TERM_CTL_MASK) { 677344779Sdim case ADW_SCSI_CFG1_TERM_CTL_MASK: 678344779Sdim printf("High & Low SE Term Enabled, "); 679344779Sdim break; 680344779Sdim case ADW_SCSI_CFG1_TERM_CTL_H: 681344779Sdim printf("High SE Termination Enabled, "); 682234353Sdim break; 683234353Sdim case ADW_SCSI_CFG1_TERM_CTL_L: 684234353Sdim printf("Low SE Term Enabled, "); 685234353Sdim break; 686288943Sdim default: 687234353Sdim break; 688234353Sdim } 689234353Sdim 690234353Sdim if ((adw->features & ADW_ULTRA2) != 0 691234353Sdim && (term_scsicfg1 & ADW2_SCSI_CFG1_TERM_CTL_LVD) != 0) 692234353Sdim printf("LVD Term Enabled, "); 693288943Sdim 694288943Sdim /* 695234353Sdim * Invert the TERM_CTL_H and TERM_CTL_L bits and then 696234353Sdim * set 'scsicfg1'. The TERM_POL bit does not need to be 697234353Sdim * referenced, because the hardware internally inverts 698234353Sdim * the Termination High and Low bits if TERM_POL is set. 699234353Sdim */ 700234353Sdim if ((adw->features & ADW_ULTRA2) != 0) { 701234353Sdim term_scsicfg1 = ~term_scsicfg1; 702288943Sdim term_scsicfg1 &= ADW_SCSI_CFG1_TERM_CTL_MASK 703288943Sdim | ADW2_SCSI_CFG1_TERM_CTL_LVD; 704234353Sdim scsicfg1 &= ~(ADW_SCSI_CFG1_TERM_CTL_MASK 705234353Sdim |ADW2_SCSI_CFG1_TERM_CTL_LVD 706234353Sdim |ADW_SCSI_CFG1_BIG_ENDIAN 707234353Sdim |ADW_SCSI_CFG1_TERM_POL 708234353Sdim |ADW2_SCSI_CFG1_DEV_DETECT); 709234353Sdim scsicfg1 |= term_scsicfg1; 710288943Sdim } else { 711234353Sdim term_scsicfg1 = ~term_scsicfg1 & ADW_SCSI_CFG1_TERM_CTL_MASK; 712234353Sdim scsicfg1 &= ~ADW_SCSI_CFG1_TERM_CTL_MASK; 713234353Sdim scsicfg1 |= term_scsicfg1 | ADW_SCSI_CFG1_TERM_CTL_MANUAL; 714234353Sdim scsicfg1 |= ADW_SCSI_CFG1_FLTR_DISABLE; 715234353Sdim } 716288943Sdim 717234353Sdim /* 718234353Sdim * Set SCSI_CFG1 Microcode Default Value 719234353Sdim * 720234353Sdim * The microcode will set the SCSI_CFG1 register using this value 721360784Sdim * after it is started below. 722234353Sdim */ 723234353Sdim adw_lram_write_16(adw, ADW_MC_DEFAULT_SCSI_CFG1, scsicfg1); 724288943Sdim 725234353Sdim /* 726234353Sdim * Only accept selections on our initiator target id. 727234353Sdim * This may change in target mode scenarios... 728234353Sdim */ 729360784Sdim adw_lram_write_16(adw, ADW_MC_DEFAULT_SEL_MASK, 730234353Sdim (0x01 << adw->initiator_id)); 731234353Sdim 732261991Sdim /* 733261991Sdim * Tell the microcode where it can find our 734234353Sdim * Initiator Command Queue (ICQ). It is 735234353Sdim * currently empty hence the "stopper" address. 736234353Sdim */ 737234353Sdim adw->commandq = adw->free_carriers; 738234353Sdim adw->free_carriers = carrierbotov(adw, adw->commandq->next_ba); 739234353Sdim adw->commandq->next_ba = ADW_CQ_STOPPER; 740234353Sdim adw_lram_write_32(adw, ADW_MC_ICQ, adw->commandq->carr_ba); 741234353Sdim 742288943Sdim /* 743234353Sdim * Tell the microcode where it can find our 744234353Sdim * Initiator Response Queue (IRQ). It too 745234353Sdim * is currently empty. 746234353Sdim */ 747288943Sdim adw->responseq = adw->free_carriers; 748234353Sdim adw->free_carriers = carrierbotov(adw, adw->responseq->next_ba); 749234353Sdim adw->responseq->next_ba = ADW_CQ_STOPPER; 750234353Sdim adw_lram_write_32(adw, ADW_MC_IRQ, adw->responseq->carr_ba); 751234353Sdim 752234353Sdim adw_outb(adw, ADW_INTR_ENABLES, 753341825Sdim ADW_INTR_ENABLE_HOST_INTR|ADW_INTR_ENABLE_GLOBAL_INTR); 754341825Sdim 755341825Sdim adw_outw(adw, ADW_PC, adw_lram_read_16(adw, ADW_MC_CODE_BEGIN_ADDR)); 756341825Sdim 757341825Sdim return (0); 758341825Sdim} 759288943Sdim 760234353Sdimvoid 761234353Sdimadw_set_user_sdtr(struct adw_softc *adw, u_int tid, u_int mc_sdtr) 762234353Sdim{ 763234353Sdim adw->user_sdtr[ADW_TARGET_GROUP(tid)] &= ~ADW_TARGET_GROUP_MASK(tid); 764288943Sdim adw->user_sdtr[ADW_TARGET_GROUP(tid)] |= 765239462Sdim mc_sdtr << ADW_TARGET_GROUP_SHIFT(tid); 766239462Sdim} 767239462Sdim 768239462Sdimu_int 769288943Sdimadw_get_user_sdtr(struct adw_softc *adw, u_int tid) 770288943Sdim{ 771234353Sdim u_int mc_sdtr; 772234353Sdim 773234353Sdim mc_sdtr = adw->user_sdtr[ADW_TARGET_GROUP(tid)]; 774234353Sdim mc_sdtr &= ADW_TARGET_GROUP_MASK(tid); 775234353Sdim mc_sdtr >>= ADW_TARGET_GROUP_SHIFT(tid); 776288943Sdim return (mc_sdtr); 777296417Sdim} 778296417Sdim 779288943Sdimvoid 780309124Sdimadw_set_chip_sdtr(struct adw_softc *adw, u_int tid, u_int sdtr) 781309124Sdim{ 782309124Sdim u_int mc_sdtr_offset; 783309124Sdim u_int mc_sdtr; 784309124Sdim 785288943Sdim mc_sdtr_offset = ADW_MC_SDTR_SPEED1; 786288943Sdim mc_sdtr_offset += ADW_TARGET_GROUP(tid) * 2; 787288943Sdim mc_sdtr = adw_lram_read_16(adw, mc_sdtr_offset); 788288943Sdim mc_sdtr &= ~ADW_TARGET_GROUP_MASK(tid); 789234353Sdim mc_sdtr |= sdtr << ADW_TARGET_GROUP_SHIFT(tid); 790234353Sdim adw_lram_write_16(adw, mc_sdtr_offset, mc_sdtr); 791234353Sdim} 792234353Sdim 793234353Sdimu_int 794288943Sdimadw_get_chip_sdtr(struct adw_softc *adw, u_int tid) 795234353Sdim{ 796234353Sdim u_int mc_sdtr_offset; 797234353Sdim u_int mc_sdtr; 798234353Sdim 799234353Sdim mc_sdtr_offset = ADW_MC_SDTR_SPEED1; 800234353Sdim mc_sdtr_offset += ADW_TARGET_GROUP(tid) * 2; 801234353Sdim mc_sdtr = adw_lram_read_16(adw, mc_sdtr_offset); 802234353Sdim mc_sdtr &= ADW_TARGET_GROUP_MASK(tid); 803234353Sdim mc_sdtr >>= ADW_TARGET_GROUP_SHIFT(tid); 804234353Sdim return (mc_sdtr); 805234353Sdim} 806341825Sdim 807280031Sdimu_int 808280031Sdimadw_find_sdtr(struct adw_softc *adw, u_int period) 809280031Sdim{ 810280031Sdim int i; 811280031Sdim 812280031Sdim i = 0; 813280031Sdim if ((adw->features & ADW_DT) == 0) 814280031Sdim i = ADW_MC_SDTR_OFFSET_ULTRA2; 815280031Sdim if ((adw->features & ADW_ULTRA2) == 0) 816280031Sdim i = ADW_MC_SDTR_OFFSET_ULTRA; 817280031Sdim if (period == 0) 818280031Sdim return ADW_MC_SDTR_ASYNC; 819280031Sdim 820341825Sdim for (; i < adw_num_syncrates; i++) { 821280031Sdim if (period <= adw_syncrates[i].period) 822280031Sdim return (adw_syncrates[i].mc_sdtr); 823280031Sdim } 824280031Sdim return ADW_MC_SDTR_ASYNC; 825280031Sdim} 826280031Sdim 827280031Sdimu_int 828280031Sdimadw_find_period(struct adw_softc *adw, u_int mc_sdtr) 829280031Sdim{ 830280031Sdim int i; 831280031Sdim 832280031Sdim for (i = 0; i < adw_num_syncrates; i++) { 833280031Sdim if (mc_sdtr == adw_syncrates[i].mc_sdtr) 834280031Sdim break; 835341825Sdim } 836280031Sdim return (adw_syncrates[i].period); 837280031Sdim} 838280031Sdim 839280031Sdimu_int 840280031Sdimadw_hshk_cfg_period_factor(u_int tinfo) 841280031Sdim{ 842280031Sdim tinfo &= ADW_HSHK_CFG_RATE_MASK; 843280031Sdim tinfo >>= ADW_HSHK_CFG_RATE_SHIFT; 844280031Sdim if (tinfo == 0x11) 845280031Sdim /* 80MHz/DT */ 846280031Sdim return (9); 847280031Sdim else if (tinfo == 0x10) 848280031Sdim /* 40MHz */ 849234353Sdim return (10); 850234353Sdim else 851234353Sdim return (((tinfo * 25) + 50) / 4); 852234353Sdim} 853288943Sdim 854234353Sdim/* 855234353Sdim * Send an idle command to the chip and wait for completion. 856234353Sdim */ 857243830Sdimadw_idle_cmd_status_t 858243830Sdimadw_idle_cmd_send(struct adw_softc *adw, adw_idle_cmd_t cmd, u_int parameter) 859243830Sdim{ 860243830Sdim u_int timeout; 861243830Sdim adw_idle_cmd_status_t status; 862234353Sdim 863234353Sdim if (!dumping) 864234353Sdim mtx_assert(&adw->lock, MA_OWNED); 865288943Sdim 866234353Sdim /* 867234353Sdim * Clear the idle command status which is set by the microcode 868234353Sdim * to a non-zero value to indicate when the command is completed. 869234353Sdim */ 870243830Sdim adw_lram_write_16(adw, ADW_MC_IDLE_CMD_STATUS, 0); 871243830Sdim 872243830Sdim /* 873243830Sdim * Write the idle command value after the idle command parameter 874243830Sdim * has been written to avoid a race condition. If the order is not 875234353Sdim * followed, the microcode may process the idle command before the 876234353Sdim * parameters have been written to LRAM. 877234353Sdim */ 878288943Sdim adw_lram_write_32(adw, ADW_MC_IDLE_CMD_PARAMETER, parameter); 879288943Sdim adw_lram_write_16(adw, ADW_MC_IDLE_CMD, cmd); 880288943Sdim 881288943Sdim /* 882288943Sdim * Tickle the RISC to tell it to process the idle command. 883353358Sdim */ 884353358Sdim adw_tickle_risc(adw, ADW_TICKLE_B); 885353358Sdim 886353358Sdim /* Wait for up to 10 seconds for the command to complete */ 887353358Sdim timeout = 5000000; 888360784Sdim while (--timeout) { 889353358Sdim status = adw_lram_read_16(adw, ADW_MC_IDLE_CMD_STATUS); 890353358Sdim if (status != 0) 891360784Sdim break; 892353358Sdim DELAY(20); 893353358Sdim } 894234353Sdim 895234353Sdim if (timeout == 0) 896234353Sdim panic("%s: Idle Command Timed Out!", 897234353Sdim device_get_nameunit(adw->device)); 898288943Sdim return (status); 899234353Sdim} 900234353Sdim