advlib.c revision 19426
118781Sgibbs/* 218781Sgibbs * Low level routines for the Advanced Systems Inc. SCSI controllers chips 318781Sgibbs * 418781Sgibbs * Copyright (c) 1996 Justin T. Gibbs. 518781Sgibbs * All rights reserved. 618781Sgibbs * 718781Sgibbs * Redistribution and use in source and binary forms, with or without 818781Sgibbs * modification, are permitted provided that the following conditions 918781Sgibbs * are met: 1018781Sgibbs * 1. Redistributions of source code must retain the above copyright 1118781Sgibbs * notice immediately at the beginning of the file, without modification, 1218781Sgibbs * this list of conditions, and the following disclaimer. 1318781Sgibbs * 2. Redistributions in binary form must reproduce the above copyright 1418781Sgibbs * notice, this list of conditions and the following disclaimer in the 1518781Sgibbs * documentation and/or other materials provided with the distribution. 1618781Sgibbs * 3. The name of the author may not be used to endorse or promote products 1718781Sgibbs * derived from this software without specific prior written permission. 1818781Sgibbs * 1918781Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2018781Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2118781Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2218781Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2318781Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2418781Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2518781Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2618781Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2718781Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2818781Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2918781Sgibbs * SUCH DAMAGE. 3018781Sgibbs * 3119426Sgibbs * $Id: advlib.c,v 1.1.1.1 1996/10/07 02:07:06 gibbs Exp $ 3218781Sgibbs */ 3318781Sgibbs/* 3418781Sgibbs * Ported from: 3518781Sgibbs * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters 3618781Sgibbs * 3718781Sgibbs * Copyright (c) 1995-1996 Advanced System Products, Inc. 3818781Sgibbs * All Rights Reserved. 3918781Sgibbs * 4018781Sgibbs * Redistribution and use in source and binary forms, with or without 4118781Sgibbs * modification, are permitted provided that redistributions of source 4218781Sgibbs * code retain the above copyright notice and this comment without 4318781Sgibbs * modification. 4418781Sgibbs */ 4518781Sgibbs 4618781Sgibbs#include <sys/param.h> 4718781Sgibbs#include <sys/systm.h> 4818781Sgibbs 4918781Sgibbs#include <machine/clock.h> 5018781Sgibbs 5118781Sgibbs#include <scsi/scsi_all.h> 5218781Sgibbs#include <scsi/scsi_message.h> 5318781Sgibbs#include <scsi/scsi_disk.h> 5418781Sgibbs 5518781Sgibbs#include <vm/vm.h> 5618781Sgibbs#include <vm/vm_param.h> 5718781Sgibbs#include <vm/pmap.h> 5818781Sgibbs 5918781Sgibbs#include <dev/advansys/advlib.h> 6018781Sgibbs#include <dev/advansys/advmcode.h> 6118781Sgibbs 6218781Sgibbs/* 6318781Sgibbs * Allowable periods in ns 6418781Sgibbs */ 6518781Sgibbsu_int8_t adv_sdtr_period_tbl[] = 6618781Sgibbs{ 6718781Sgibbs 25, 6818781Sgibbs 30, 6918781Sgibbs 35, 7018781Sgibbs 40, 7118781Sgibbs 50, 7218781Sgibbs 60, 7318781Sgibbs 70, 7418781Sgibbs 85 7518781Sgibbs}; 7618781Sgibbs 7718781Sgibbsstruct sdtr_xmsg { 7818781Sgibbs u_int8_t msg_type; 7918781Sgibbs u_int8_t msg_len; 8018781Sgibbs u_int8_t msg_req; 8118781Sgibbs u_int8_t xfer_period; 8218781Sgibbs u_int8_t req_ack_offset; 8318781Sgibbs u_int8_t res; 8418781Sgibbs}; 8518781Sgibbs 8618781Sgibbs/* 8718781Sgibbs * Some of the early PCI adapters have problems with 8818781Sgibbs * async transfers. Instead try to use an offset of 8918781Sgibbs * 1. 9018781Sgibbs */ 9118781Sgibbs#define ASYN_SDTR_DATA_FIX 0x41 9218781Sgibbs 9318781Sgibbs/* LRAM routines */ 9418781Sgibbsstatic void adv_read_lram_16_multi __P((struct adv_softc *adv, u_int16_t s_addr, 9518781Sgibbs u_int16_t *buffer, int count)); 9618781Sgibbsstatic void adv_write_lram_16_multi __P((struct adv_softc *adv, 9718781Sgibbs u_int16_t s_addr, u_int16_t *buffer, 9818781Sgibbs int count)); 9918781Sgibbsstatic void adv_mset_lram_16 __P((struct adv_softc *adv, 10018781Sgibbs u_int16_t s_addr, u_int16_t set_value, 10118781Sgibbs int count)); 10218781Sgibbsstatic u_int32_t adv_msum_lram_16 __P((struct adv_softc *adv, u_int16_t s_addr, int count)); 10318781Sgibbs 10418781Sgibbsstatic int adv_write_and_verify_lram_16 __P((struct adv_softc *adv, 10518781Sgibbs u_int16_t addr, u_int16_t value)); 10618781Sgibbsstatic u_int32_t adv_read_lram_32 __P((struct adv_softc *adv, u_int16_t addr)); 10718781Sgibbs 10818781Sgibbs 10918781Sgibbsstatic void adv_write_lram_32 __P((struct adv_softc *adv, u_int16_t addr, 11018781Sgibbs u_int32_t value)); 11118781Sgibbsstatic void adv_write_lram_32_multi __P((struct adv_softc *adv, u_int16_t s_addr, 11218781Sgibbs u_int32_t *buffer, int count)); 11318781Sgibbs 11418781Sgibbs/* EEPROM routines */ 11518781Sgibbsstatic u_int16_t adv_read_eeprom_16 __P((struct adv_softc *adv, u_int8_t addr)); 11618781Sgibbsstatic u_int16_t adv_write_eeprom_16 __P((struct adv_softc *adv, u_int8_t addr, u_int16_t value)); 11718781Sgibbsstatic int adv_write_eeprom_cmd_reg __P((struct adv_softc *adv, u_int8_t cmd_reg)); 11818781Sgibbsstatic int adv_set_eeprom_config_once __P((struct adv_softc *adv, 11918781Sgibbs struct adv_eeprom_config *eeprom_config)); 12018781Sgibbs 12118781Sgibbs/* Initialization */ 12219426Sgibbsstatic u_int32_t adv_load_microcode __P((struct adv_softc *adv, 12319426Sgibbs u_int16_t s_addr, u_int16_t *mcode_buf, u_int16_t mcode_size)); 12418781Sgibbsstatic void adv_init_lram __P((struct adv_softc *adv)); 12518781Sgibbsstatic int adv_init_microcode_var __P((struct adv_softc *adv)); 12618781Sgibbsstatic void adv_init_qlink_var __P((struct adv_softc *adv)); 12718781Sgibbs 12818781Sgibbs/* Interrupts */ 12918781Sgibbsstatic void adv_disable_interrupt __P((struct adv_softc *adv)); 13018781Sgibbsstatic void adv_enable_interrupt __P((struct adv_softc *adv)); 13118781Sgibbsstatic void adv_toggle_irq_act __P((struct adv_softc *adv)); 13218781Sgibbs 13318781Sgibbs/* Chip Control */ 13418781Sgibbs#if UNUSED 13518781Sgibbsstatic void adv_start_execution __P((struct adv_softc *adv)); 13618781Sgibbs#endif 13718781Sgibbsstatic int adv_start_chip __P((struct adv_softc *adv)); 13818781Sgibbsstatic int adv_stop_chip __P((struct adv_softc *adv)); 13919426Sgibbsstatic void adv_set_chip_ih __P((struct adv_softc *adv, 14019426Sgibbs u_int16_t ins_code)); 14118781Sgibbsstatic void adv_set_bank __P((struct adv_softc *adv, u_int8_t bank)); 14218781Sgibbs#if UNUSED 14318781Sgibbsstatic u_int8_t adv_get_chip_scsi_ctrl __P((struct adv_softc *adv)); 14418781Sgibbs#endif 14518781Sgibbs 14618781Sgibbs/* Queue handling and execution */ 14718781Sgibbsstatic int adv_sgcount_to_qcount __P((int sgcount)); 14818781Sgibbsstatic void adv_get_q_info __P((struct adv_softc *adv, u_int16_t s_addr, u_int16_t *inbuf, 14918781Sgibbs int words)); 15019426Sgibbsstatic u_int adv_get_num_free_queues __P((struct adv_softc *adv, 15119426Sgibbs u_int8_t n_qs)); 15219426Sgibbsstatic u_int8_t adv_alloc_free_queues __P((struct adv_softc *adv, 15319426Sgibbs u_int8_t free_q_head, 15418781Sgibbs u_int8_t n_free_q)); 15519426Sgibbsstatic u_int8_t adv_alloc_free_queue __P((struct adv_softc *adv, 15619426Sgibbs u_int8_t free_q_head)); 15719426Sgibbsstatic int adv_send_scsi_queue __P((struct adv_softc *adv, 15819426Sgibbs struct adv_scsi_q *scsiq, 15918781Sgibbs u_int8_t n_q_required)); 16019426Sgibbsstatic void adv_put_ready_sg_list_queue __P((struct adv_softc *adv, 16119426Sgibbs struct adv_scsi_q *scsiq, 16218781Sgibbs u_int8_t q_no)); 16319426Sgibbsstatic void adv_put_ready_queue __P((struct adv_softc *adv, 16419426Sgibbs struct adv_scsi_q *scsiq, 16519426Sgibbs u_int8_t q_no)); 16619426Sgibbsstatic void adv_put_scsiq __P((struct adv_softc *adv, u_int16_t s_addr, 16719426Sgibbs u_int16_t *buffer, int words)); 16818781Sgibbs 16918781Sgibbs/* SDTR */ 17019426Sgibbsstatic u_int8_t adv_msgout_sdtr __P((struct adv_softc *adv, 17119426Sgibbs u_int8_t sdtr_period, 17219426Sgibbs u_int8_t sdtr_offset)); 17319426Sgibbsstatic u_int8_t adv_get_card_sync_setting __P((u_int8_t period, 17419426Sgibbs u_int8_t offset)); 17519426Sgibbsstatic void adv_set_chip_sdtr __P((struct adv_softc *adv, 17619426Sgibbs u_int8_t sdtr_data, 17718781Sgibbs u_int8_t tid_no)); 17818781Sgibbs 17918781Sgibbs 18019426Sgibbs/* Exported functions first */ 18118781Sgibbs 18218781Sgibbsu_int8_t 18318781Sgibbsadv_read_lram_8(adv, addr) 18418781Sgibbs struct adv_softc *adv; 18518781Sgibbs u_int16_t addr; 18618781Sgibbs 18718781Sgibbs{ 18818781Sgibbs u_int8_t byte_data; 18918781Sgibbs u_int16_t word_data; 19018781Sgibbs 19118781Sgibbs /* 19218781Sgibbs * LRAM is accessed on 16bit boundaries. 19318781Sgibbs */ 19418781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, addr & 0xFFFE); 19518781Sgibbs word_data = ADV_INW(adv, ADV_LRAM_DATA); 19618781Sgibbs if (addr & 1) { 19718781Sgibbs#if BYTE_ORDER == BIG_ENDIAN 19818781Sgibbs byte_data = (u_int8_t)(word_data & 0xFF); 19918781Sgibbs#else 20018781Sgibbs byte_data = (u_int8_t)((word_data >> 8) & 0xFF); 20118781Sgibbs#endif 20218781Sgibbs } else { 20318781Sgibbs#if BYTE_ORDER == BIG_ENDIAN 20418781Sgibbs byte_data = (u_int8_t)((word_data >> 8) & 0xFF); 20518781Sgibbs#else 20618781Sgibbs byte_data = (u_int8_t)(word_data & 0xFF); 20718781Sgibbs#endif 20818781Sgibbs } 20918781Sgibbs return (byte_data); 21018781Sgibbs} 21118781Sgibbs 21218781Sgibbsvoid 21318781Sgibbsadv_write_lram_8(adv, addr, value) 21418781Sgibbs struct adv_softc *adv; 21518781Sgibbs u_int16_t addr; 21618781Sgibbs u_int8_t value; 21718781Sgibbs{ 21818781Sgibbs u_int16_t word_data; 21918781Sgibbs 22018781Sgibbs word_data = adv_read_lram_16(adv, addr & 0xFFFE); 22118781Sgibbs if (addr & 1) { 22218781Sgibbs word_data &= 0x00FF; 22318781Sgibbs word_data |= (((u_int8_t)value << 8) & 0xFF00); 22418781Sgibbs } else { 22518781Sgibbs word_data &= 0xFF00; 22618781Sgibbs word_data |= ((u_int8_t)value & 0x00FF); 22718781Sgibbs } 22818781Sgibbs adv_write_lram_16(adv, addr & 0xFFFE, word_data); 22918781Sgibbs} 23018781Sgibbs 23118781Sgibbs 23218781Sgibbsu_int16_t 23318781Sgibbsadv_read_lram_16(adv, addr) 23418781Sgibbs struct adv_softc *adv; 23518781Sgibbs u_int16_t addr; 23618781Sgibbs{ 23718781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, addr); 23818781Sgibbs return (ADV_INW(adv, ADV_LRAM_DATA)); 23918781Sgibbs} 24018781Sgibbs 24118781Sgibbsvoid 24218781Sgibbsadv_write_lram_16(adv, addr, value) 24318781Sgibbs struct adv_softc *adv; 24418781Sgibbs u_int16_t addr; 24518781Sgibbs u_int16_t value; 24618781Sgibbs{ 24718781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, addr); 24818781Sgibbs ADV_OUTW(adv, ADV_LRAM_DATA, value); 24918781Sgibbs} 25018781Sgibbs 25118781Sgibbs 25218781Sgibbs/* 25318781Sgibbs * Return the fully qualified board type for the adapter. 25418781Sgibbs * The chip_revision must be set before this function is called. 25518781Sgibbs */ 25618781Sgibbsvoid 25718781Sgibbsadv_get_board_type(adv) 25818781Sgibbs struct adv_softc *adv; 25918781Sgibbs{ 26018781Sgibbs if ((adv->chip_version >= ADV_CHIP_MIN_VER_VL) && 26118781Sgibbs (adv->chip_version <= ADV_CHIP_MAX_VER_VL)) { 26218781Sgibbs if (((adv->iobase & 0x0C30) == 0x0C30) || 26318781Sgibbs ((adv->iobase & 0x0C50) == 0x0C50)) { 26418781Sgibbs adv->type = ADV_EISA; 26518781Sgibbs } else 26618781Sgibbs adv->type = ADV_VL; 26718781Sgibbs } else if ((adv->chip_version >= ADV_CHIP_MIN_VER_ISA) && 26818781Sgibbs (adv->chip_version <= ADV_CHIP_MAX_VER_ISA)) { 26918781Sgibbs if (adv->chip_version >= ADV_CHIP_MIN_VER_ISA_PNP) { 27018781Sgibbs adv->type = ADV_ISAPNP; 27118781Sgibbs } else 27218781Sgibbs adv->type = ADV_ISA; 27318781Sgibbs } else if ((adv->chip_version >= ADV_CHIP_MIN_VER_PCI) && 27418781Sgibbs (adv->chip_version <= ADV_CHIP_MAX_VER_PCI)) { 27518781Sgibbs adv->type = ADV_PCI; 27618781Sgibbs } else 27718781Sgibbs panic("adv_get_board_type: Unknown board type encountered"); 27818781Sgibbs} 27918781Sgibbs 28018781Sgibbsu_int16_t 28118781Sgibbsadv_get_eeprom_config(adv, eeprom_config) 28218781Sgibbs struct adv_softc *adv; 28318781Sgibbs struct adv_eeprom_config *eeprom_config; 28418781Sgibbs{ 28518781Sgibbs u_int16_t sum; 28618781Sgibbs u_int16_t *wbuf; 28718781Sgibbs u_int8_t cfg_beg; 28818781Sgibbs u_int8_t cfg_end; 28918781Sgibbs u_int8_t s_addr; 29018781Sgibbs 29118781Sgibbs wbuf = (u_int16_t *)eeprom_config; 29218781Sgibbs sum = 0; 29318781Sgibbs 29418781Sgibbs for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) { 29518781Sgibbs *wbuf = adv_read_eeprom_16(adv, s_addr); 29618781Sgibbs sum += *wbuf; 29718781Sgibbs } 29818781Sgibbs 29918781Sgibbs if (adv->type & ADV_VL) { 30018781Sgibbs cfg_beg = ADV_EEPROM_CFG_BEG_VL; 30118781Sgibbs cfg_end = ADV_EEPROM_MAX_ADDR_VL; 30218781Sgibbs } else { 30318781Sgibbs cfg_beg = ADV_EEPROM_CFG_BEG; 30418781Sgibbs cfg_end = ADV_EEPROM_MAX_ADDR; 30518781Sgibbs } 30618781Sgibbs 30718781Sgibbs for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) { 30818781Sgibbs *wbuf = adv_read_eeprom_16(adv, s_addr); 30918781Sgibbs sum += *wbuf; 31018781Sgibbs#if ADV_DEBUG_EEPROM 31118781Sgibbs printf("Addr 0x%x: 0x%04x\n", s_addr, *wbuf); 31218781Sgibbs#endif 31318781Sgibbs } 31418781Sgibbs *wbuf = adv_read_eeprom_16(adv, s_addr); 31518781Sgibbs return (sum); 31618781Sgibbs} 31718781Sgibbs 31818781Sgibbsint 31918781Sgibbsadv_set_eeprom_config(adv, eeprom_config) 32018781Sgibbs struct adv_softc *adv; 32118781Sgibbs struct adv_eeprom_config *eeprom_config; 32218781Sgibbs{ 32318781Sgibbs int retry; 32418781Sgibbs 32518781Sgibbs retry = 0; 32618781Sgibbs while (1) { 32718781Sgibbs if (adv_set_eeprom_config_once(adv, eeprom_config) == 0) { 32818781Sgibbs break; 32918781Sgibbs } 33018781Sgibbs if (++retry > ADV_EEPROM_MAX_RETRY) { 33118781Sgibbs break; 33218781Sgibbs } 33318781Sgibbs } 33418781Sgibbs return (retry > ADV_EEPROM_MAX_RETRY); 33518781Sgibbs} 33618781Sgibbs 33718781Sgibbsint 33818781Sgibbsadv_reset_chip_and_scsi_bus(adv) 33918781Sgibbs struct adv_softc *adv; 34018781Sgibbs{ 34118781Sgibbs adv_stop_chip(adv); 34218781Sgibbs ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_CHIP_RESET | ADV_CC_SCSI_RESET | ADV_CC_HALT); 34318781Sgibbs DELAY(200 * 1000); 34418781Sgibbs 34518781Sgibbs adv_set_chip_ih(adv, ADV_INS_RFLAG_WTM); 34618781Sgibbs adv_set_chip_ih(adv, ADV_INS_HALT); 34718781Sgibbs 34818781Sgibbs ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_CHIP_RESET | ADV_CC_HALT); 34918781Sgibbs ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_HALT); 35018781Sgibbs DELAY(200 * 1000); 35118781Sgibbs return (adv_is_chip_halted(adv)); 35218781Sgibbs} 35318781Sgibbs 35418781Sgibbsint 35518781Sgibbsadv_test_external_lram(adv) 35618781Sgibbs struct adv_softc* adv; 35718781Sgibbs{ 35818781Sgibbs u_int16_t q_addr; 35918781Sgibbs u_int16_t saved_value; 36018781Sgibbs int success; 36118781Sgibbs 36218781Sgibbs success = 0; 36318781Sgibbs 36418781Sgibbs /* XXX Why 241? */ 36518781Sgibbs q_addr = ADV_QNO_TO_QADDR(241); 36618781Sgibbs saved_value = adv_read_lram_16(adv, q_addr); 36718781Sgibbs if (adv_write_and_verify_lram_16(adv, q_addr, 0x55AA) == 0) { 36818781Sgibbs success = 1; 36918781Sgibbs adv_write_lram_16(adv, q_addr, saved_value); 37018781Sgibbs } 37118781Sgibbs return (success); 37218781Sgibbs} 37318781Sgibbs 37418781Sgibbs 37518781Sgibbsint 37618781Sgibbsadv_init_lram_and_mcode(adv) 37718781Sgibbs struct adv_softc *adv; 37818781Sgibbs{ 37918781Sgibbs u_int32_t retval; 38018781Sgibbs adv_disable_interrupt(adv); 38118781Sgibbs 38218781Sgibbs adv_init_lram(adv); 38318781Sgibbs 38418781Sgibbs retval = adv_load_microcode(adv, 0, (u_int16_t *)adv_mcode, adv_mcode_size); 38518781Sgibbs if (retval != adv_mcode_chksum) { 38618781Sgibbs printf("adv%d: Microcode download failed checksum!\n", 38718781Sgibbs adv->unit); 38818781Sgibbs return (1); 38918781Sgibbs } 39018781Sgibbs 39118781Sgibbs if (adv_init_microcode_var(adv) != 0) 39218781Sgibbs return (1); 39318781Sgibbs 39418781Sgibbs adv_enable_interrupt(adv); 39518781Sgibbs return (0); 39618781Sgibbs} 39718781Sgibbs 39818781Sgibbsu_int8_t 39918781Sgibbsadv_get_chip_irq(adv) 40018781Sgibbs struct adv_softc *adv; 40118781Sgibbs{ 40218781Sgibbs u_int16_t cfg_lsw; 40318781Sgibbs u_int8_t chip_irq; 40418781Sgibbs 40518781Sgibbs cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW); 40618781Sgibbs 40718781Sgibbs if ((adv->type & ADV_VL) != 0) { 40818781Sgibbs chip_irq = (u_int8_t)(((cfg_lsw >> 2) & 0x07)); 40918781Sgibbs if ((chip_irq == 0) || 41018781Sgibbs (chip_irq == 4) || 41118781Sgibbs (chip_irq == 7)) { 41218781Sgibbs return (0); 41318781Sgibbs } 41418781Sgibbs return (chip_irq + (ADV_MIN_IRQ_NO - 1)); 41518781Sgibbs } 41618781Sgibbs chip_irq = (u_int8_t)(((cfg_lsw >> 2) & 0x03)); 41718781Sgibbs if (chip_irq == 3) 41818781Sgibbs chip_irq += 2; 41918781Sgibbs return (chip_irq + ADV_MIN_IRQ_NO); 42018781Sgibbs} 42118781Sgibbs 42218781Sgibbsu_int8_t 42318781Sgibbsadv_set_chip_irq(adv, irq_no) 42418781Sgibbs struct adv_softc *adv; 42518781Sgibbs u_int8_t irq_no; 42618781Sgibbs{ 42718781Sgibbs u_int16_t cfg_lsw; 42818781Sgibbs 42918781Sgibbs if ((adv->type & ADV_VL) != 0) { 43018781Sgibbs if (irq_no != 0) { 43118781Sgibbs if ((irq_no < ADV_MIN_IRQ_NO) || (irq_no > ADV_MAX_IRQ_NO)) { 43218781Sgibbs irq_no = 0; 43318781Sgibbs } else { 43418781Sgibbs irq_no -= ADV_MIN_IRQ_NO - 1; 43518781Sgibbs } 43618781Sgibbs } 43718781Sgibbs cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW) & 0xFFE3; 43818781Sgibbs cfg_lsw |= 0x0010; 43918781Sgibbs ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw); 44018781Sgibbs adv_toggle_irq_act(adv); 44118781Sgibbs 44218781Sgibbs cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW) & 0xFFE0; 44318781Sgibbs cfg_lsw |= (irq_no & 0x07) << 2; 44418781Sgibbs ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw); 44518781Sgibbs adv_toggle_irq_act(adv); 44618781Sgibbs } else if ((adv->type & ADV_ISA) != 0) { 44718781Sgibbs if (irq_no == 15) 44818781Sgibbs irq_no -= 2; 44918781Sgibbs irq_no -= ADV_MIN_IRQ_NO; 45018781Sgibbs cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW) & 0xFFF3; 45118781Sgibbs cfg_lsw |= (irq_no & 0x03) << 2; 45218781Sgibbs ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw); 45318781Sgibbs } 45418781Sgibbs return (adv_get_chip_irq(adv)); 45518781Sgibbs} 45618781Sgibbs 45718781Sgibbsint 45818781Sgibbsadv_execute_scsi_queue(adv, scsiq) 45918781Sgibbs struct adv_softc *adv; 46018781Sgibbs struct adv_scsi_q *scsiq; 46118781Sgibbs{ 46218781Sgibbs int retval; 46318781Sgibbs u_int n_q_required; 46418781Sgibbs int s; 46518781Sgibbs u_int32_t addr; 46618781Sgibbs u_int8_t sg_entry_cnt; 46718781Sgibbs u_int8_t target_ix; 46818781Sgibbs u_int8_t sg_entry_cnt_minus_one; 46918781Sgibbs u_int8_t tid_no; 47018781Sgibbs u_int8_t sdtr_data; 47118781Sgibbs u_int32_t *p_data_addr; 47218781Sgibbs u_int32_t *p_data_bcount; 47318781Sgibbs 47418781Sgibbs scsiq->q1.q_no = 0; 47518781Sgibbs retval = 1; /* Default to error case */ 47618781Sgibbs target_ix = scsiq->q2.target_ix; 47718781Sgibbs tid_no = ADV_TIX_TO_TID(target_ix); 47818781Sgibbs 47918781Sgibbs n_q_required = 1; 48018781Sgibbs 48118781Sgibbs s = splbio(); 48218781Sgibbs if (scsiq->cdbptr->opcode == REQUEST_SENSE) { 48318781Sgibbs if (((adv->initiate_sdtr & scsiq->q1.target_id) != 0) 48418781Sgibbs && ((adv->sdtr_done & scsiq->q1.target_id) != 0)) { 48518781Sgibbs int sdtr_index; 48618781Sgibbs 48718781Sgibbs sdtr_data = adv_read_lram_8(adv, ADVV_SDTR_DATA_BEG + tid_no); 48818781Sgibbs sdtr_index = (sdtr_data >> 4); 48918781Sgibbs adv_msgout_sdtr(adv, adv_sdtr_period_tbl[sdtr_index], 49018781Sgibbs (sdtr_data & ADV_SYN_MAX_OFFSET)); 49118781Sgibbs scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT); 49218781Sgibbs } 49318781Sgibbs } 49418781Sgibbs 49518781Sgibbs if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) { 49618781Sgibbs sg_entry_cnt = scsiq->sg_head->entry_cnt; 49718781Sgibbs sg_entry_cnt_minus_one = sg_entry_cnt - 1; 49818781Sgibbs 49918781Sgibbs#ifdef DIAGNOSTIC 50018781Sgibbs if (sg_entry_cnt <= 1) 50118781Sgibbs panic("adv_execute_scsi_queue: Queue with QC_SG_HEAD set but %d segs.", sg_entry_cnt); 50218781Sgibbs 50318781Sgibbs if (sg_entry_cnt > ADV_MAX_SG_LIST) 50418781Sgibbs panic("adv_execute_scsi_queue: Queue with too many segs."); 50518781Sgibbs 50618781Sgibbs if (adv->type & (ADV_ISA | ADV_VL | ADV_EISA)) { 50718781Sgibbs for (i = 0; i < sg_entry_cnt_minus_one; i++) { 50818781Sgibbs addr = scsiq->sg_head->sg_list[i].addr + 50918781Sgibbs scsiq->sg_head->sg_list[i].bytes; 51018781Sgibbs 51118781Sgibbs if ((addr & 0x0003) != 0) 51218781Sgibbs panic("adv_execute_scsi_queue: SG with odd address or byte count"); 51318781Sgibbs } 51418781Sgibbs } 51518781Sgibbs#endif 51618781Sgibbs p_data_addr = &scsiq->sg_head->sg_list[sg_entry_cnt_minus_one].addr; 51718781Sgibbs p_data_bcount = &scsiq->sg_head->sg_list[sg_entry_cnt_minus_one].bytes; 51818781Sgibbs 51918781Sgibbs n_q_required = adv_sgcount_to_qcount(sg_entry_cnt); 52018781Sgibbs scsiq->sg_head->queue_cnt = n_q_required - 1; 52118781Sgibbs } else { 52218781Sgibbs p_data_addr = &scsiq->q1.data_addr; 52318781Sgibbs p_data_bcount = &scsiq->q1.data_cnt; 52418781Sgibbs n_q_required = 1; 52518781Sgibbs } 52618781Sgibbs 52718781Sgibbs if (adv->bug_fix_control & ADV_BUG_FIX_ADD_ONE_BYTE) { 52818781Sgibbs addr = *p_data_addr + *p_data_bcount; 52918781Sgibbs if ((addr & 0x0003) != 0) { 53018781Sgibbs /* 53118781Sgibbs * XXX Is this extra test (the one on data_cnt) really only supposed to apply 53218781Sgibbs * to the non SG case or was it a bug due to code duplication? 53318781Sgibbs */ 53418781Sgibbs if ((scsiq->q1.cntl & QC_SG_HEAD) != 0 || (scsiq->q1.data_cnt & 0x01FF) == 0) { 53518781Sgibbs if ((scsiq->cdbptr->opcode == READ_COMMAND) || 53618781Sgibbs (scsiq->cdbptr->opcode == READ_BIG)) { 53718781Sgibbs if ((scsiq->q2.tag_code & ADV_TAG_FLAG_ADD_ONE_BYTE) == 0) { 53818781Sgibbs (*p_data_bcount)++; 53918781Sgibbs scsiq->q2.tag_code |= ADV_TAG_FLAG_ADD_ONE_BYTE; 54018781Sgibbs } 54118781Sgibbs } 54218781Sgibbs 54318781Sgibbs } 54418781Sgibbs } 54518781Sgibbs } 54618781Sgibbs 54718781Sgibbs if ((adv_get_num_free_queues(adv, n_q_required) >= n_q_required) 54818781Sgibbs || ((scsiq->q1.cntl & QC_URGENT) != 0)) 54918781Sgibbs retval = adv_send_scsi_queue(adv, scsiq, n_q_required); 55018781Sgibbs 55118781Sgibbs splx(s); 55218781Sgibbs return (retval); 55318781Sgibbs} 55418781Sgibbs 55518781Sgibbs 55618781Sgibbsu_int8_t 55718781Sgibbsadv_copy_lram_doneq(adv, q_addr, scsiq, max_dma_count) 55818781Sgibbs struct adv_softc *adv; 55918781Sgibbs u_int16_t q_addr; 56018781Sgibbs struct adv_q_done_info *scsiq; 56118781Sgibbs u_int32_t max_dma_count; 56218781Sgibbs{ 56318781Sgibbs u_int16_t val; 56418781Sgibbs u_int8_t sg_queue_cnt; 56518781Sgibbs 56618781Sgibbs adv_get_q_info(adv, q_addr + ADV_SCSIQ_DONE_INFO_BEG, 56718781Sgibbs (u_int16_t *)scsiq, 56818781Sgibbs (sizeof(scsiq->d2) + sizeof(scsiq->d3)) / 2); 56918781Sgibbs 57018781Sgibbs#if BYTE_ORDER == BIG_ENDIAN 57118781Sgibbs adv_adj_endian_qdone_info(scsiq); 57218781Sgibbs#endif 57318781Sgibbs 57418781Sgibbs val = adv_read_lram_16(adv, q_addr + ADV_SCSIQ_B_STATUS); 57518781Sgibbs scsiq->q_status = val & 0xFF; 57618781Sgibbs scsiq->q_no = (val >> 8) & 0XFF; 57718781Sgibbs 57818781Sgibbs val = adv_read_lram_16(adv, q_addr + ADV_SCSIQ_B_CNTL); 57918781Sgibbs scsiq->cntl = val & 0xFF; 58018781Sgibbs sg_queue_cnt = (val >> 8) & 0xFF; 58118781Sgibbs 58218781Sgibbs val = adv_read_lram_16(adv,q_addr + ADV_SCSIQ_B_SENSE_LEN); 58318781Sgibbs scsiq->sense_len = val & 0xFF; 58418781Sgibbs scsiq->user_def = (val >> 8) & 0xFF; 58518781Sgibbs 58618781Sgibbs scsiq->remain_bytes = adv_read_lram_32(adv, 58718781Sgibbs q_addr + ADV_SCSIQ_DW_REMAIN_XFER_CNT); 58818781Sgibbs /* 58918781Sgibbs * XXX Is this just a safeguard or will the counter really 59018781Sgibbs * have bogus upper bits? 59118781Sgibbs */ 59218781Sgibbs scsiq->remain_bytes &= max_dma_count; 59318781Sgibbs 59418781Sgibbs return (sg_queue_cnt); 59518781Sgibbs} 59618781Sgibbs 59718781Sgibbsint 59818781Sgibbsadv_stop_execution(adv) 59918781Sgibbs struct adv_softc *adv; 60018781Sgibbs{ 60118781Sgibbs int count; 60218781Sgibbs 60318781Sgibbs count = 0; 60418781Sgibbs if (adv_read_lram_8(adv, ADV_STOP_CODE_B) == 0) { 60518781Sgibbs adv_write_lram_8(adv, ADV_STOP_CODE_B, 60618781Sgibbs ADV_STOP_REQ_RISC_STOP); 60718781Sgibbs do { 60818781Sgibbs if (adv_read_lram_8(adv, ADV_STOP_CODE_B) & 60918781Sgibbs ADV_STOP_ACK_RISC_STOP) { 61018781Sgibbs return (1); 61118781Sgibbs } 61218781Sgibbs DELAY(1000); 61318781Sgibbs } while (count++ < 20); 61418781Sgibbs } 61518781Sgibbs return (0); 61618781Sgibbs} 61718781Sgibbs 61818781Sgibbsint 61918781Sgibbsadv_is_chip_halted(adv) 62018781Sgibbs struct adv_softc *adv; 62118781Sgibbs{ 62218781Sgibbs if ((ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_HALTED) != 0) { 62318781Sgibbs if ((ADV_INB(adv, ADV_CHIP_CTRL) & ADV_CC_HALT) != 0) { 62418781Sgibbs return (1); 62518781Sgibbs } 62618781Sgibbs } 62718781Sgibbs return (0); 62818781Sgibbs} 62918781Sgibbs 63018781Sgibbs/* 63118781Sgibbs * XXX The numeric constants and the loops in this routine 63218781Sgibbs * need to be documented. 63318781Sgibbs */ 63418781Sgibbsvoid 63518781Sgibbsadv_ack_interrupt(adv) 63618781Sgibbs struct adv_softc *adv; 63718781Sgibbs{ 63818781Sgibbs u_int8_t host_flag; 63918781Sgibbs u_int8_t risc_flag; 64018781Sgibbs int loop; 64118781Sgibbs 64218781Sgibbs loop = 0; 64318781Sgibbs do { 64418781Sgibbs risc_flag = adv_read_lram_8(adv, ADVV_RISC_FLAG_B); 64518781Sgibbs if (loop++ > 0x7FFF) { 64618781Sgibbs break; 64718781Sgibbs } 64818781Sgibbs } while ((risc_flag & ADV_RISC_FLAG_GEN_INT) != 0); 64918781Sgibbs 65018781Sgibbs host_flag = adv_read_lram_8(adv, ADVV_HOST_FLAG_B); 65118781Sgibbs adv_write_lram_8(adv, ADVV_HOST_FLAG_B, 65218781Sgibbs host_flag | ADV_HOST_FLAG_ACK_INT); 65318781Sgibbs 65418781Sgibbs ADV_OUTW(adv, ADV_CHIP_STATUS, ADV_CIW_INT_ACK); 65518781Sgibbs loop = 0; 65618781Sgibbs while (ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_INT_PENDING) { 65718781Sgibbs ADV_OUTW(adv, ADV_CHIP_STATUS, ADV_CIW_INT_ACK); 65818781Sgibbs if (loop++ > 3) { 65918781Sgibbs break; 66018781Sgibbs } 66118781Sgibbs } 66218781Sgibbs 66318781Sgibbs adv_write_lram_8(adv, ADVV_HOST_FLAG_B, host_flag); 66418781Sgibbs} 66518781Sgibbs 66618781Sgibbs/* 66718781Sgibbs * Handle all conditions that may halt the chip waiting 66818781Sgibbs * for us to intervene. 66918781Sgibbs */ 67018781Sgibbsvoid 67118781Sgibbsadv_isr_chip_halted(adv) 67218781Sgibbs struct adv_softc *adv; 67318781Sgibbs{ 67418781Sgibbs u_int16_t int_halt_code; 67518781Sgibbs u_int8_t halt_qp; 67618781Sgibbs u_int16_t halt_q_addr; 67718781Sgibbs u_int8_t target_ix; 67818781Sgibbs u_int8_t q_cntl; 67918781Sgibbs u_int8_t tid_no; 68018781Sgibbs target_bit_vector target_id; 68118781Sgibbs target_bit_vector scsi_busy; 68218781Sgibbs u_int8_t asyn_sdtr; 68318781Sgibbs u_int8_t sdtr_data; 68418781Sgibbs 68518781Sgibbs int_halt_code = adv_read_lram_16(adv, ADVV_HALTCODE_W); 68618781Sgibbs halt_qp = adv_read_lram_8(adv, ADVV_CURCDB_B); 68718781Sgibbs halt_q_addr = ADV_QNO_TO_QADDR(halt_qp); 68818781Sgibbs target_ix = adv_read_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_TARGET_IX); 68918781Sgibbs q_cntl = adv_read_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_CNTL); 69018781Sgibbs tid_no = ADV_TIX_TO_TID(target_ix); 69118781Sgibbs target_id = ADV_TID_TO_TARGET_ID(tid_no); 69218781Sgibbs if (adv->needs_async_bug_fix & target_id) 69318781Sgibbs asyn_sdtr = ASYN_SDTR_DATA_FIX; 69418781Sgibbs else 69518781Sgibbs asyn_sdtr = 0; 69618781Sgibbs if (int_halt_code == ADV_HALT_EXTMSG_IN) { 69718781Sgibbs struct sdtr_xmsg sdtr_xmsg; 69818781Sgibbs int sdtr_accept; 69918781Sgibbs 70018781Sgibbs adv_read_lram_16_multi(adv, ADVV_MSGIN_BEG, 70118781Sgibbs (u_int16_t *) &sdtr_xmsg, 70218781Sgibbs sizeof(sdtr_xmsg) >> 1); 70318781Sgibbs if ((sdtr_xmsg.msg_type == MSG_EXTENDED) && 70418781Sgibbs (sdtr_xmsg.msg_len == MSG_EXT_SDTR_LEN)) { 70518781Sgibbs sdtr_accept = TRUE; 70618781Sgibbs if (sdtr_xmsg.msg_req == MSG_EXT_SDTR) { 70718781Sgibbs if (sdtr_xmsg.req_ack_offset > ADV_SYN_MAX_OFFSET) { 70818781Sgibbs 70918781Sgibbs sdtr_accept = FALSE; 71018781Sgibbs sdtr_xmsg.req_ack_offset = ADV_SYN_MAX_OFFSET; 71118781Sgibbs } 71218781Sgibbs sdtr_data = adv_get_card_sync_setting(sdtr_xmsg.xfer_period, 71318781Sgibbs sdtr_xmsg.req_ack_offset); 71418781Sgibbs if (sdtr_xmsg.req_ack_offset == 0) { 71518781Sgibbs q_cntl &= ~QC_MSG_OUT; 71618781Sgibbs adv->initiate_sdtr &= ~target_id; 71718781Sgibbs adv->sdtr_done &= ~target_id; 71818781Sgibbs adv_set_chip_sdtr(adv, asyn_sdtr, tid_no); 71918781Sgibbs } else if (sdtr_data == 0) { 72018781Sgibbs q_cntl |= QC_MSG_OUT; 72118781Sgibbs adv->initiate_sdtr &= ~target_id; 72218781Sgibbs adv->sdtr_done &= ~target_id; 72318781Sgibbs adv_set_chip_sdtr(adv, asyn_sdtr, tid_no); 72418781Sgibbs } else { 72518781Sgibbs if (sdtr_accept && (q_cntl & QC_MSG_OUT)) { 72618781Sgibbs q_cntl &= ~QC_MSG_OUT; 72718781Sgibbs adv->sdtr_done |= target_id; 72818781Sgibbs adv->initiate_sdtr |= target_id; 72918781Sgibbs adv->needs_async_bug_fix &= ~target_id; 73018781Sgibbs adv_set_chip_sdtr(adv, sdtr_data, tid_no); 73118781Sgibbs } else { 73218781Sgibbs 73318781Sgibbs q_cntl |= QC_MSG_OUT; 73418781Sgibbs 73518781Sgibbs adv_msgout_sdtr(adv, 73618781Sgibbs sdtr_xmsg.xfer_period, 73718781Sgibbs sdtr_xmsg.req_ack_offset); 73818781Sgibbs adv->needs_async_bug_fix &= ~target_id; 73918781Sgibbs adv_set_chip_sdtr(adv, sdtr_data, tid_no); 74018781Sgibbs adv->sdtr_done |= target_id; 74118781Sgibbs adv->initiate_sdtr |= target_id; 74218781Sgibbs } 74318781Sgibbs } 74418781Sgibbs 74518781Sgibbs adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_CNTL, q_cntl); 74618781Sgibbs } 74718781Sgibbs } 74818781Sgibbs /* 74918781Sgibbs * XXX Hey, shouldn't we be rejecting any messages we don't understand? 75018781Sgibbs * The old code also did not un-halt the processor if it recieved 75118781Sgibbs * an extended message that it didn't understand. That didn't 75218781Sgibbs * seem right, so I changed this routine to always un-halt the 75318781Sgibbs * processor at the end. 75418781Sgibbs */ 75518781Sgibbs } else if (int_halt_code == ADV_HALT_CHK_CONDITION) { 75618781Sgibbs u_int8_t tag_code; 75718781Sgibbs u_int8_t q_status; 75818781Sgibbs 75918781Sgibbs q_cntl |= QC_REQ_SENSE; 76018781Sgibbs if (((adv->initiate_sdtr & target_id) != 0) && 76118781Sgibbs ((adv->sdtr_done & target_id) != 0)) { 76218781Sgibbs 76318781Sgibbs sdtr_data = adv_read_lram_8(adv, ADVV_SDTR_DATA_BEG + tid_no); 76418781Sgibbs /* XXX Macrotize the extraction of the index from sdtr_data ??? */ 76518781Sgibbs adv_msgout_sdtr(adv, adv_sdtr_period_tbl[(sdtr_data >> 4) & 0x0F], 76618781Sgibbs sdtr_data & ADV_SYN_MAX_OFFSET); 76718781Sgibbs q_cntl |= QC_MSG_OUT; 76818781Sgibbs } 76918781Sgibbs adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_CNTL, q_cntl); 77018781Sgibbs 77118781Sgibbs /* Don't tag request sense commands */ 77218781Sgibbs tag_code = adv_read_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_TAG_CODE); 77318781Sgibbs tag_code &= ~(MSG_SIMPLE_Q_TAG|MSG_HEAD_OF_Q_TAG|MSG_ORDERED_Q_TAG); 77418781Sgibbs adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_TAG_CODE, tag_code); 77518781Sgibbs 77618781Sgibbs q_status = adv_read_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_STATUS); 77718781Sgibbs q_status |= (QS_READY | QS_BUSY); 77818781Sgibbs adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_STATUS, q_status); 77918781Sgibbs 78018781Sgibbs scsi_busy = adv_read_lram_8(adv, ADVV_SCSIBUSY_B); 78118781Sgibbs scsi_busy &= ~target_id; 78218781Sgibbs adv_write_lram_8(adv, ADVV_SCSIBUSY_B, scsi_busy); 78318781Sgibbs } else if (int_halt_code == ADV_HALT_SDTR_REJECTED) { 78418781Sgibbs struct sdtr_xmsg out_msg; 78518781Sgibbs 78618781Sgibbs adv_read_lram_16_multi(adv, ADVV_MSGOUT_BEG, 78718781Sgibbs (u_int16_t *) &out_msg, 78818781Sgibbs sizeof(out_msg)/2); 78918781Sgibbs 79018781Sgibbs if ((out_msg.msg_type == MSG_EXTENDED) && 79118781Sgibbs (out_msg.msg_len == MSG_EXT_SDTR_LEN) && 79218781Sgibbs (out_msg.msg_req == MSG_EXT_SDTR)) { 79318781Sgibbs 79418781Sgibbs adv->initiate_sdtr &= ~target_id; 79518781Sgibbs adv->sdtr_done &= ~target_id; 79618781Sgibbs adv_set_chip_sdtr(adv, asyn_sdtr, tid_no); 79718781Sgibbs } 79818781Sgibbs q_cntl &= ~QC_MSG_OUT; 79918781Sgibbs adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_CNTL, q_cntl); 80018781Sgibbs } else if (int_halt_code == ADV_HALT_SS_QUEUE_FULL) { 80118781Sgibbs u_int8_t cur_dvc_qng; 80218781Sgibbs u_int8_t scsi_status; 80318781Sgibbs 80418781Sgibbs /* 80518781Sgibbs * XXX It would be nice if we could push the responsibility for handling 80618781Sgibbs * this situation onto the generic SCSI layer as other drivers do. 80718781Sgibbs * This would be done by completing the command with the status byte 80818781Sgibbs * set to QUEUE_FULL, whereupon it will request that any transactions 80918781Sgibbs * pending on the target that where scheduled after this one be aborted 81018781Sgibbs * (so as to maintain queue ordering) and the number of requests the 81118781Sgibbs * upper level will attempt to send this target will be reduced. 81218781Sgibbs * 81318781Sgibbs * With this current strategy, am I guaranteed that once I unbusy the 81418781Sgibbs * target the queued up transactions will be sent in the order they 81518781Sgibbs * were queued? If the ASC chip does a round-robin on all queued 81618781Sgibbs * transactions looking for queues to run, the order is not guaranteed. 81718781Sgibbs */ 81818781Sgibbs scsi_status = adv_read_lram_8(adv, halt_q_addr + ADV_SCSIQ_SCSI_STATUS); 81918781Sgibbs cur_dvc_qng = adv_read_lram_8(adv, ADV_QADR_BEG + target_ix); 82018781Sgibbs printf("adv%d: Queue full - target %d, active transactions %d\n", adv->unit, 82118781Sgibbs tid_no, cur_dvc_qng); 82218781Sgibbs#if 0 82318781Sgibbs /* XXX FIX LATER */ 82418781Sgibbs if ((cur_dvc_qng > 0) && (adv->cur_dvc_qng[tid_no] > 0)) { 82518781Sgibbs scsi_busy = adv_read_lram_8(adv, ADVV_SCSIBUSY_B); 82618781Sgibbs scsi_busy |= target_id; 82718781Sgibbs adv_write_lram_8(adv, ADVV_SCSIBUSY_B, scsi_busy); 82818781Sgibbs asc_dvc->queue_full_or_busy |= target_id; 82918781Sgibbs 83018781Sgibbs if (scsi_status == SS_QUEUE_FULL) { 83118781Sgibbs if (cur_dvc_qng > ASC_MIN_TAGGED_CMD) { 83218781Sgibbs cur_dvc_qng -= 1; 83318781Sgibbs asc_dvc->max_dvc_qng[tid_no] = cur_dvc_qng; 83418781Sgibbs 83518781Sgibbs adv_write_lram_8(adv, ADVV_MAX_DVC_QNG_BEG + tid_no, 83618781Sgibbs cur_dvc_qng); 83718781Sgibbs } 83818781Sgibbs } 83918781Sgibbs } 84018781Sgibbs#endif 84118781Sgibbs } 84218781Sgibbs adv_write_lram_16(adv, ADVV_HALTCODE_W, 0); 84318781Sgibbs} 84418781Sgibbs 84518781Sgibbs/* Internal Routines */ 84618781Sgibbs 84718781Sgibbsstatic void 84818781Sgibbsadv_read_lram_16_multi(adv, s_addr, buffer, count) 84918781Sgibbs struct adv_softc *adv; 85018781Sgibbs u_int16_t s_addr; 85118781Sgibbs u_int16_t *buffer; 85218781Sgibbs int count; 85318781Sgibbs{ 85418781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr); 85518781Sgibbs ADV_INSW(adv, ADV_LRAM_DATA, buffer, count); 85618781Sgibbs} 85718781Sgibbs 85818781Sgibbsstatic void 85918781Sgibbsadv_write_lram_16_multi(adv, s_addr, buffer, count) 86018781Sgibbs struct adv_softc *adv; 86118781Sgibbs u_int16_t s_addr; 86218781Sgibbs u_int16_t *buffer; 86318781Sgibbs int count; 86418781Sgibbs{ 86518781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr); 86618781Sgibbs ADV_OUTSW(adv, ADV_LRAM_DATA, buffer, count); 86718781Sgibbs} 86818781Sgibbs 86918781Sgibbsstatic void 87018781Sgibbsadv_mset_lram_16(adv, s_addr, set_value, count) 87118781Sgibbs struct adv_softc *adv; 87218781Sgibbs u_int16_t s_addr; 87318781Sgibbs u_int16_t set_value; 87418781Sgibbs int count; 87518781Sgibbs{ 87618781Sgibbs int i; 87718781Sgibbs 87818781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr); 87918781Sgibbs for (i = 0; i < count; i++) 88018781Sgibbs ADV_OUTW(adv, ADV_LRAM_DATA, set_value); 88118781Sgibbs} 88218781Sgibbs 88318781Sgibbsstatic u_int32_t 88418781Sgibbsadv_msum_lram_16(adv, s_addr, count) 88518781Sgibbs struct adv_softc *adv; 88618781Sgibbs u_int16_t s_addr; 88718781Sgibbs int count; 88818781Sgibbs{ 88918781Sgibbs u_int32_t sum; 89018781Sgibbs int i; 89118781Sgibbs 89218781Sgibbs sum = 0; 89318781Sgibbs for (i = 0; i < count; i++, s_addr += 2) 89418781Sgibbs sum += adv_read_lram_16(adv, s_addr); 89518781Sgibbs return (sum); 89618781Sgibbs} 89718781Sgibbs 89818781Sgibbsstatic int 89918781Sgibbsadv_write_and_verify_lram_16(adv, addr, value) 90018781Sgibbs struct adv_softc *adv; 90118781Sgibbs u_int16_t addr; 90218781Sgibbs u_int16_t value; 90318781Sgibbs{ 90418781Sgibbs int retval; 90518781Sgibbs 90618781Sgibbs retval = 0; 90718781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, addr); 90818781Sgibbs ADV_OUTW(adv, ADV_LRAM_DATA, value); 90918781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, addr); 91018781Sgibbs if (value != ADV_INW(adv, ADV_LRAM_DATA)) 91118781Sgibbs retval = 1; 91218781Sgibbs return (retval); 91318781Sgibbs} 91418781Sgibbs 91518781Sgibbsstatic u_int32_t 91618781Sgibbsadv_read_lram_32(adv, addr) 91718781Sgibbs struct adv_softc *adv; 91818781Sgibbs u_int16_t addr; 91918781Sgibbs{ 92018781Sgibbs u_int16_t val_low, val_high; 92118781Sgibbs 92218781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, addr); 92318781Sgibbs 92418781Sgibbs#if BYTE_ORDER == BIG_ENDIAN 92518781Sgibbs val_high = ADV_INW(adv, ADV_LRAM_DATA); 92618781Sgibbs val_low = ADV_INW(adv, ADV_LRAM_DATA); 92718781Sgibbs#else 92818781Sgibbs val_low = ADV_INW(adv, ADV_LRAM_DATA); 92918781Sgibbs val_high = ADV_INW(adv, ADV_LRAM_DATA); 93018781Sgibbs#endif 93118781Sgibbs 93218781Sgibbs return (((u_int32_t)val_high << 16) | (u_int32_t)val_low); 93318781Sgibbs} 93418781Sgibbs 93518781Sgibbsstatic void 93618781Sgibbsadv_write_lram_32(adv, addr, value) 93718781Sgibbs struct adv_softc *adv; 93818781Sgibbs u_int16_t addr; 93918781Sgibbs u_int32_t value; 94018781Sgibbs{ 94118781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, addr); 94218781Sgibbs 94318781Sgibbs#if BYTE_ORDER == BIG_ENDIAN 94418781Sgibbs ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)((value >> 16) & 0xFFFF)); 94518781Sgibbs ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)(value & 0xFFFF)); 94618781Sgibbs#else 94718781Sgibbs ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)(value & 0xFFFF)); 94818781Sgibbs ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)((value >> 16) & 0xFFFF)); 94918781Sgibbs#endif 95018781Sgibbs} 95118781Sgibbs 95218781Sgibbsstatic void 95318781Sgibbsadv_write_lram_32_multi(adv, s_addr, buffer, count) 95418781Sgibbs struct adv_softc *adv; 95518781Sgibbs u_int16_t s_addr; 95618781Sgibbs u_int32_t *buffer; 95718781Sgibbs int count; 95818781Sgibbs{ 95918781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr); 96018781Sgibbs ADV_OUTSW(adv, ADV_LRAM_DATA, buffer, count * 2); 96118781Sgibbs} 96218781Sgibbs 96318781Sgibbsstatic u_int16_t 96418781Sgibbsadv_read_eeprom_16(adv, addr) 96518781Sgibbs struct adv_softc *adv; 96618781Sgibbs u_int8_t addr; 96718781Sgibbs{ 96818781Sgibbs u_int16_t read_wval; 96918781Sgibbs u_int8_t cmd_reg; 97018781Sgibbs 97118781Sgibbs adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE_DISABLE); 97218781Sgibbs DELAY(1000); 97318781Sgibbs cmd_reg = addr | ADV_EEPROM_CMD_READ; 97418781Sgibbs adv_write_eeprom_cmd_reg(adv, cmd_reg); 97518781Sgibbs DELAY(1000); 97618781Sgibbs read_wval = ADV_INW(adv, ADV_EEPROM_DATA); 97718781Sgibbs DELAY(1000); 97818781Sgibbs return (read_wval); 97918781Sgibbs} 98018781Sgibbs 98118781Sgibbsstatic u_int16_t 98218781Sgibbsadv_write_eeprom_16(adv, addr, value) 98318781Sgibbs struct adv_softc *adv; 98418781Sgibbs u_int8_t addr; 98518781Sgibbs u_int16_t value; 98618781Sgibbs{ 98718781Sgibbs u_int16_t read_value; 98818781Sgibbs 98918781Sgibbs read_value = adv_read_eeprom_16(adv, addr); 99018781Sgibbs if (read_value != value) { 99118781Sgibbs adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE_ENABLE); 99218781Sgibbs DELAY(1000); 99318781Sgibbs 99418781Sgibbs ADV_OUTW(adv, ADV_EEPROM_DATA, value); 99518781Sgibbs DELAY(1000); 99618781Sgibbs 99718781Sgibbs adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE | addr); 99818781Sgibbs DELAY(20 * 1000); 99918781Sgibbs 100018781Sgibbs adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE_DISABLE); 100118781Sgibbs DELAY(1000); 100218781Sgibbs read_value = adv_read_eeprom_16(adv, addr); 100318781Sgibbs } 100418781Sgibbs return (read_value); 100518781Sgibbs} 100618781Sgibbs 100718781Sgibbsstatic int 100818781Sgibbsadv_write_eeprom_cmd_reg(adv, cmd_reg) 100918781Sgibbs struct adv_softc *adv; 101018781Sgibbs u_int8_t cmd_reg; 101118781Sgibbs{ 101218781Sgibbs u_int8_t read_back; 101318781Sgibbs int retry; 101418781Sgibbs 101518781Sgibbs retry = 0; 101618781Sgibbs while (1) { 101718781Sgibbs ADV_OUTB(adv, ADV_EEPROM_CMD, cmd_reg); 101818781Sgibbs DELAY(1000); 101918781Sgibbs read_back = ADV_INB(adv, ADV_EEPROM_CMD); 102018781Sgibbs if (read_back == cmd_reg) { 102118781Sgibbs return (1); 102218781Sgibbs } 102318781Sgibbs if (retry++ > ADV_EEPROM_MAX_RETRY) { 102418781Sgibbs return (0); 102518781Sgibbs } 102618781Sgibbs } 102718781Sgibbs} 102818781Sgibbs 102918781Sgibbsstatic int 103018781Sgibbsadv_set_eeprom_config_once(adv, eeprom_config) 103118781Sgibbs struct adv_softc *adv; 103218781Sgibbs struct adv_eeprom_config *eeprom_config; 103318781Sgibbs{ 103418781Sgibbs int n_error; 103518781Sgibbs u_int16_t *wbuf; 103618781Sgibbs u_int16_t sum; 103718781Sgibbs u_int8_t s_addr; 103818781Sgibbs u_int8_t cfg_beg; 103918781Sgibbs u_int8_t cfg_end; 104018781Sgibbs 104118781Sgibbs wbuf = (u_int16_t *)eeprom_config; 104218781Sgibbs n_error = 0; 104318781Sgibbs sum = 0; 104418781Sgibbs for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) { 104518781Sgibbs sum += *wbuf; 104618781Sgibbs if (*wbuf != adv_write_eeprom_16(adv, s_addr, *wbuf)) { 104718781Sgibbs n_error++; 104818781Sgibbs } 104918781Sgibbs } 105018781Sgibbs if (adv->type & ADV_VL) { 105118781Sgibbs cfg_beg = ADV_EEPROM_CFG_BEG_VL; 105218781Sgibbs cfg_end = ADV_EEPROM_MAX_ADDR_VL; 105318781Sgibbs } else { 105418781Sgibbs cfg_beg = ADV_EEPROM_CFG_BEG; 105518781Sgibbs cfg_end = ADV_EEPROM_MAX_ADDR; 105618781Sgibbs } 105718781Sgibbs 105818781Sgibbs for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) { 105918781Sgibbs sum += *wbuf; 106018781Sgibbs if (*wbuf != adv_write_eeprom_16(adv, s_addr, *wbuf)) { 106118781Sgibbs n_error++; 106218781Sgibbs } 106318781Sgibbs } 106418781Sgibbs *wbuf = sum; 106518781Sgibbs if (sum != adv_write_eeprom_16(adv, s_addr, sum)) { 106618781Sgibbs n_error++; 106718781Sgibbs } 106818781Sgibbs wbuf = (u_int16_t *)eeprom_config; 106918781Sgibbs for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) { 107018781Sgibbs if (*wbuf != adv_read_eeprom_16(adv, s_addr)) { 107118781Sgibbs n_error++; 107218781Sgibbs } 107318781Sgibbs } 107418781Sgibbs for (s_addr = cfg_beg; s_addr <= cfg_end; s_addr++, wbuf++) { 107518781Sgibbs if (*wbuf != adv_read_eeprom_16(adv, s_addr)) { 107618781Sgibbs n_error++; 107718781Sgibbs } 107818781Sgibbs } 107918781Sgibbs return (n_error); 108018781Sgibbs} 108118781Sgibbs 108218781Sgibbsstatic u_int32_t 108318781Sgibbsadv_load_microcode(adv, s_addr, mcode_buf, mcode_size) 108418781Sgibbs struct adv_softc *adv; 108518781Sgibbs u_int16_t s_addr; 108618781Sgibbs u_int16_t *mcode_buf; 108718781Sgibbs u_int16_t mcode_size; 108818781Sgibbs{ 108918781Sgibbs u_int32_t chksum; 109018781Sgibbs u_int16_t mcode_lram_size; 109118781Sgibbs u_int16_t mcode_chksum; 109218781Sgibbs 109318781Sgibbs mcode_lram_size = mcode_size >> 1; 109418781Sgibbs /* XXX Why zero the memory just before you write the whole thing?? */ 109518781Sgibbs /* adv_mset_lram_16(adv, s_addr, 0, mcode_lram_size);*/ 109618781Sgibbs adv_write_lram_16_multi(adv, s_addr, mcode_buf, mcode_lram_size); 109718781Sgibbs 109818781Sgibbs chksum = adv_msum_lram_16(adv, s_addr, mcode_lram_size); 109918781Sgibbs mcode_chksum = (u_int16_t)adv_msum_lram_16(adv, ADV_CODE_SEC_BEG, 110018781Sgibbs ((mcode_size - s_addr - ADV_CODE_SEC_BEG) >> 1)); 110118781Sgibbs adv_write_lram_16(adv, ADVV_MCODE_CHKSUM_W, mcode_chksum); 110218781Sgibbs adv_write_lram_16(adv, ADVV_MCODE_SIZE_W, mcode_size); 110318781Sgibbs return (chksum); 110418781Sgibbs} 110518781Sgibbs 110618781Sgibbsstatic void 110718781Sgibbsadv_init_lram(adv) 110818781Sgibbs struct adv_softc *adv; 110918781Sgibbs{ 111018781Sgibbs u_int8_t i; 111118781Sgibbs u_int16_t s_addr; 111218781Sgibbs 111318781Sgibbs adv_mset_lram_16(adv, ADV_QADR_BEG, 0, 111418781Sgibbs (u_int16_t)((((int)adv->max_openings + 2 + 1) * 64) >> 1)); 111518781Sgibbs 111618781Sgibbs i = ADV_MIN_ACTIVE_QNO; 111718781Sgibbs s_addr = ADV_QADR_BEG + ADV_QBLK_SIZE; 111818781Sgibbs 111918781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD, i + 1); 112018781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, adv->max_openings); 112118781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, i); 112218781Sgibbs i++; 112318781Sgibbs s_addr += ADV_QBLK_SIZE; 112418781Sgibbs for (; i < adv->max_openings; i++, s_addr += ADV_QBLK_SIZE) { 112518781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD, i + 1); 112618781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, i - 1); 112718781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, i); 112818781Sgibbs } 112918781Sgibbs 113018781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD, ADV_QLINK_END); 113118781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, adv->max_openings - 1); 113218781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, adv->max_openings); 113318781Sgibbs i++; 113418781Sgibbs s_addr += ADV_QBLK_SIZE; 113518781Sgibbs 113618781Sgibbs for (; i <= adv->max_openings + 3; i++, s_addr += ADV_QBLK_SIZE) { 113718781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD, i); 113818781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, i); 113918781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, i); 114018781Sgibbs } 114118781Sgibbs} 114218781Sgibbs 114318781Sgibbsstatic int 114418781Sgibbsadv_init_microcode_var(adv) 114518781Sgibbs struct adv_softc *adv; 114618781Sgibbs{ 114718781Sgibbs int i; 114818781Sgibbs 114918781Sgibbs for (i = 0; i <= ADV_MAX_TID; i++) { 115018781Sgibbs adv_write_lram_8(adv, ADVV_SDTR_DATA_BEG + i, 115118781Sgibbs adv->sdtr_data[i]); 115218781Sgibbs } 115318781Sgibbs 115418781Sgibbs adv_init_qlink_var(adv); 115518781Sgibbs 115618781Sgibbs /* XXX Again, what about wide busses??? */ 115718781Sgibbs adv_write_lram_8(adv, ADVV_DISC_ENABLE_B, adv->disc_enable); 115818781Sgibbs adv_write_lram_8(adv, ADVV_HOSTSCSI_ID_B, 0x01 << adv->scsi_id); 115918781Sgibbs 116018781Sgibbs /* What are the extra 8 bytes for?? */ 116118781Sgibbs adv_write_lram_32(adv, ADVV_OVERRUN_PADDR_D, vtophys(&(adv->overrun_buf[0])) + 8); 116218781Sgibbs 116318781Sgibbs adv_write_lram_32(adv, ADVV_OVERRUN_BSIZE_D, ADV_OVERRUN_BSIZE - 8); 116418781Sgibbs 116518781Sgibbs#if 0 116618781Sgibbs /* If we're going to print anything, RCS ids are more meaningful */ 116718781Sgibbs mcode_date = adv_read_lram_16(adv, ADVV_MC_DATE_W); 116818781Sgibbs mcode_version = adv_read_lram_16(adv, ADVV_MC_VER_W); 116918781Sgibbs#endif 117018781Sgibbs ADV_OUTW(adv, ADV_REG_PROG_COUNTER, ADV_MCODE_START_ADDR); 117118781Sgibbs if (ADV_INW(adv, ADV_REG_PROG_COUNTER) != ADV_MCODE_START_ADDR) { 117218781Sgibbs printf("adv%d: Unable to set program counter. Aborting.\n", adv->unit); 117318781Sgibbs return (1); 117418781Sgibbs } 117518781Sgibbs if (adv_start_chip(adv) != 1) { 117618781Sgibbs printf("adv%d: Unable to start on board processor. Aborting.\n", 117718781Sgibbs adv->unit); 117818781Sgibbs return (1); 117918781Sgibbs } 118018781Sgibbs return (0); 118118781Sgibbs} 118218781Sgibbs 118318781Sgibbsstatic void 118418781Sgibbsadv_init_qlink_var(adv) 118518781Sgibbs struct adv_softc *adv; 118618781Sgibbs{ 118718781Sgibbs int i; 118818781Sgibbs u_int16_t lram_addr; 118918781Sgibbs 119018781Sgibbs adv_write_lram_8(adv, ADVV_NEXTRDY_B, 1); 119118781Sgibbs adv_write_lram_8(adv, ADVV_DONENEXT_B, adv->max_openings); 119218781Sgibbs 119318781Sgibbs adv_write_lram_16(adv, ADVV_FREE_Q_HEAD_W, 1); 119418781Sgibbs adv_write_lram_16(adv, ADVV_DONE_Q_TAIL_W, adv->max_openings); 119518781Sgibbs 119618781Sgibbs adv_write_lram_8(adv, ADVV_BUSY_QHEAD_B, 119718781Sgibbs (u_int8_t)((int) adv->max_openings + 1)); 119818781Sgibbs adv_write_lram_8(adv, ADVV_DISC1_QHEAD_B, 119918781Sgibbs (u_int8_t)((int) adv->max_openings + 2)); 120018781Sgibbs 120118781Sgibbs adv_write_lram_8(adv, ADVV_TOTAL_READY_Q_B, adv->max_openings); 120218781Sgibbs 120318781Sgibbs adv_write_lram_16(adv, ADVV_ASCDVC_ERR_CODE_W, 0); 120418781Sgibbs adv_write_lram_16(adv, ADVV_HALTCODE_W, 0); 120518781Sgibbs adv_write_lram_8(adv, ADVV_STOP_CODE_B, 0); 120618781Sgibbs adv_write_lram_8(adv, ADVV_SCSIBUSY_B, 0); 120718781Sgibbs adv_write_lram_8(adv, ADVV_WTM_FLAG_B, 0); 120818781Sgibbs 120918781Sgibbs adv_write_lram_8(adv, ADVV_CDBCNT_B, 0); 121018781Sgibbs 121118781Sgibbs lram_addr = ADV_QADR_BEG; 121218781Sgibbs for (i = 0; i < 32; i++, lram_addr += 2) 121318781Sgibbs adv_write_lram_16(adv, lram_addr, 0); 121418781Sgibbs} 121518781Sgibbsstatic void 121618781Sgibbsadv_disable_interrupt(adv) 121718781Sgibbs struct adv_softc *adv; 121818781Sgibbs{ 121918781Sgibbs u_int16_t cfg; 122018781Sgibbs 122118781Sgibbs cfg = ADV_INW(adv, ADV_CONFIG_LSW); 122218781Sgibbs ADV_OUTW(adv, ADV_CONFIG_LSW, cfg & ~ADV_CFG_LSW_HOST_INT_ON); 122318781Sgibbs} 122418781Sgibbs 122518781Sgibbsstatic void 122618781Sgibbsadv_enable_interrupt(adv) 122718781Sgibbs struct adv_softc *adv; 122818781Sgibbs{ 122918781Sgibbs u_int16_t cfg; 123018781Sgibbs 123118781Sgibbs cfg = ADV_INW(adv, ADV_CONFIG_LSW); 123218781Sgibbs ADV_OUTW(adv, ADV_CONFIG_LSW, cfg | ADV_CFG_LSW_HOST_INT_ON); 123318781Sgibbs} 123418781Sgibbs 123518781Sgibbsstatic void 123618781Sgibbsadv_toggle_irq_act(adv) 123718781Sgibbs struct adv_softc *adv; 123818781Sgibbs{ 123918781Sgibbs ADV_OUTW(adv, ADV_CHIP_STATUS, ADV_CIW_IRQ_ACT); 124018781Sgibbs ADV_OUTW(adv, ADV_CHIP_STATUS, 0); 124118781Sgibbs} 124218781Sgibbs 124318781Sgibbs#if UNUSED 124418781Sgibbsstatic void 124518781Sgibbsadv_start_execution(adv) 124618781Sgibbs struct adv_softc *adv; 124718781Sgibbs{ 124818781Sgibbs if (adv_read_lram_8(adv, ADV_STOP_CODE_B) != 0) { 124918781Sgibbs adv_write_lram_8(adv, ADV_STOP_CODE_B, 0); 125018781Sgibbs } 125118781Sgibbs} 125218781Sgibbs#endif 125318781Sgibbs 125418781Sgibbsstatic int 125518781Sgibbsadv_start_chip(adv) 125618781Sgibbs struct adv_softc *adv; 125718781Sgibbs{ 125818781Sgibbs ADV_OUTB(adv, ADV_CHIP_CTRL, 0); 125918781Sgibbs if ((ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_HALTED) != 0) 126018781Sgibbs return (0); 126118781Sgibbs return (1); 126218781Sgibbs} 126318781Sgibbs 126418781Sgibbsstatic int 126518781Sgibbsadv_stop_chip(adv) 126618781Sgibbs struct adv_softc *adv; 126718781Sgibbs{ 126818781Sgibbs u_int8_t cc_val; 126918781Sgibbs 127018781Sgibbs cc_val = ADV_INB(adv, ADV_CHIP_CTRL) 127118781Sgibbs & (~(ADV_CC_SINGLE_STEP | ADV_CC_TEST | ADV_CC_DIAG)); 127218781Sgibbs ADV_OUTB(adv, ADV_CHIP_CTRL, cc_val | ADV_CC_HALT); 127318781Sgibbs adv_set_chip_ih(adv, ADV_INS_HALT); 127418781Sgibbs adv_set_chip_ih(adv, ADV_INS_RFLAG_WTM); 127518781Sgibbs if ((ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_HALTED) == 0) { 127618781Sgibbs return (0); 127718781Sgibbs } 127818781Sgibbs return (1); 127918781Sgibbs} 128018781Sgibbs 128118781Sgibbsstatic void 128218781Sgibbsadv_set_chip_ih(adv, ins_code) 128318781Sgibbs struct adv_softc *adv; 128418781Sgibbs u_int16_t ins_code; 128518781Sgibbs{ 128618781Sgibbs adv_set_bank(adv, 1); 128718781Sgibbs ADV_OUTW(adv, ADV_REG_IH, ins_code); 128818781Sgibbs adv_set_bank(adv, 0); 128918781Sgibbs} 129018781Sgibbs 129118781Sgibbsstatic void 129218781Sgibbsadv_set_bank(adv, bank) 129318781Sgibbs struct adv_softc *adv; 129418781Sgibbs u_int8_t bank; 129518781Sgibbs{ 129618781Sgibbs u_int8_t control; 129718781Sgibbs 129818781Sgibbs /* 129918781Sgibbs * Start out with the bank reset to 0 130018781Sgibbs */ 130118781Sgibbs control = ADV_INB(adv, ADV_CHIP_CTRL) 130218781Sgibbs & (~(ADV_CC_SINGLE_STEP | ADV_CC_TEST 130318781Sgibbs | ADV_CC_DIAG | ADV_CC_SCSI_RESET 130418781Sgibbs | ADV_CC_CHIP_RESET | ADV_CC_BANK_ONE)); 130518781Sgibbs if (bank == 1) { 130618781Sgibbs control |= ADV_CC_BANK_ONE; 130718781Sgibbs } else if (bank == 2) { 130818781Sgibbs control |= ADV_CC_DIAG | ADV_CC_BANK_ONE; 130918781Sgibbs } 131018781Sgibbs ADV_OUTB(adv, ADV_CHIP_CTRL, control); 131118781Sgibbs} 131218781Sgibbs 131318781Sgibbs#if UNUSED 131418781Sgibbsstatic u_int8_t 131518781Sgibbsadv_get_chip_scsi_ctrl(adv) 131618781Sgibbs struct adv_softc *adv; 131718781Sgibbs{ 131818781Sgibbs u_int8_t scsi_ctrl; 131918781Sgibbs 132018781Sgibbs adv_set_bank(adv, 1); 132118781Sgibbs scsi_ctrl = ADV_INB(adv, ADV_REG_SC); 132218781Sgibbs adv_set_bank(adv, 0); 132318781Sgibbs return (scsi_ctrl); 132418781Sgibbs} 132518781Sgibbs#endif 132618781Sgibbs 132718781Sgibbsstatic int 132818781Sgibbsadv_sgcount_to_qcount(sgcount) 132918781Sgibbs int sgcount; 133018781Sgibbs{ 133118781Sgibbs int n_sg_list_qs; 133218781Sgibbs 133318781Sgibbs n_sg_list_qs = ((sgcount - 1) / ADV_SG_LIST_PER_Q); 133418781Sgibbs if (((sgcount - 1) % ADV_SG_LIST_PER_Q) != 0) 133518781Sgibbs n_sg_list_qs++; 133618781Sgibbs return (n_sg_list_qs + 1); 133718781Sgibbs} 133818781Sgibbs 133918781Sgibbs/* 134018781Sgibbs * XXX Looks like more padding issues in this routine as well. 134118781Sgibbs * There has to be a way to turn this into an insw. 134218781Sgibbs */ 134318781Sgibbsstatic void 134418781Sgibbsadv_get_q_info(adv, s_addr, inbuf, words) 134518781Sgibbs struct adv_softc *adv; 134618781Sgibbs u_int16_t s_addr; 134718781Sgibbs u_int16_t *inbuf; 134818781Sgibbs int words; 134918781Sgibbs{ 135018781Sgibbs int i; 135118781Sgibbs 135218781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr); 135318781Sgibbs for (i = 0; i < words; i++, inbuf++) { 135418781Sgibbs if (i == 5) { 135518781Sgibbs continue; 135618781Sgibbs } 135718781Sgibbs *inbuf = ADV_INW(adv, ADV_LRAM_DATA); 135818781Sgibbs } 135918781Sgibbs} 136018781Sgibbs 136118781Sgibbsstatic u_int 136218781Sgibbsadv_get_num_free_queues(adv, n_qs) 136318781Sgibbs struct adv_softc *adv; 136418781Sgibbs u_int8_t n_qs; 136518781Sgibbs{ 136618781Sgibbs u_int cur_used_qs; 136718781Sgibbs u_int cur_free_qs; 136818781Sgibbs 136918781Sgibbs if (n_qs == 1) 137018781Sgibbs cur_used_qs = adv->cur_active + 137118781Sgibbs adv->openings_needed + 137218781Sgibbs ADV_MIN_FREE_Q; 137318781Sgibbs else 137418781Sgibbs cur_used_qs = adv->cur_active + 137518781Sgibbs ADV_MIN_FREE_Q; 137618781Sgibbs 137718781Sgibbs if ((cur_used_qs + n_qs) <= adv->max_openings) { 137818781Sgibbs cur_free_qs = adv->max_openings - cur_used_qs; 137918781Sgibbs return (cur_free_qs); 138018781Sgibbs } 138118781Sgibbs if (n_qs > 1) 138218781Sgibbs if (n_qs > adv->openings_needed) 138318781Sgibbs adv->openings_needed = n_qs; 138418781Sgibbs return (0); 138518781Sgibbs} 138618781Sgibbs 138718781Sgibbsstatic u_int8_t 138818781Sgibbsadv_alloc_free_queues(adv, free_q_head, n_free_q) 138918781Sgibbs struct adv_softc *adv; 139018781Sgibbs u_int8_t free_q_head; 139118781Sgibbs u_int8_t n_free_q; 139218781Sgibbs{ 139318781Sgibbs int i; 139418781Sgibbs 139518781Sgibbs for (i = 0; i < n_free_q; i++) { 139618781Sgibbs free_q_head = adv_alloc_free_queue(adv, free_q_head); 139718781Sgibbs if (free_q_head == ADV_QLINK_END) 139818781Sgibbs break; 139918781Sgibbs } 140018781Sgibbs return (free_q_head); 140118781Sgibbs} 140218781Sgibbs 140318781Sgibbsstatic u_int8_t 140418781Sgibbsadv_alloc_free_queue(adv, free_q_head) 140518781Sgibbs struct adv_softc *adv; 140618781Sgibbs u_int8_t free_q_head; 140718781Sgibbs{ 140818781Sgibbs u_int16_t q_addr; 140918781Sgibbs u_int8_t next_qp; 141018781Sgibbs u_int8_t q_status; 141118781Sgibbs 141218781Sgibbs next_qp = ADV_QLINK_END; 141318781Sgibbs q_addr = ADV_QNO_TO_QADDR(free_q_head); 141418781Sgibbs q_status = adv_read_lram_8(adv, q_addr + ADV_SCSIQ_B_STATUS); 141518781Sgibbs 141618781Sgibbs if ((q_status & QS_READY) == 0) 141718781Sgibbs next_qp = adv_read_lram_8(adv, q_addr + ADV_SCSIQ_B_FWD); 141818781Sgibbs 141918781Sgibbs return (next_qp); 142018781Sgibbs} 142118781Sgibbs 142218781Sgibbsstatic int 142318781Sgibbsadv_send_scsi_queue(adv, scsiq, n_q_required) 142418781Sgibbs struct adv_softc *adv; 142518781Sgibbs struct adv_scsi_q *scsiq; 142618781Sgibbs u_int8_t n_q_required; 142718781Sgibbs{ 142818781Sgibbs u_int8_t free_q_head; 142918781Sgibbs u_int8_t next_qp; 143018781Sgibbs u_int8_t tid_no; 143118781Sgibbs u_int8_t target_ix; 143218781Sgibbs int retval; 143318781Sgibbs 143418781Sgibbs retval = 1; 143518781Sgibbs target_ix = scsiq->q2.target_ix; 143618781Sgibbs tid_no = ADV_TIX_TO_TID(target_ix); 143718781Sgibbs free_q_head = adv_read_lram_16(adv, ADVV_FREE_Q_HEAD_W) & 0xFF; 143818781Sgibbs if ((next_qp = adv_alloc_free_queues(adv, free_q_head, n_q_required)) 143918781Sgibbs != ADV_QLINK_END) { 144018781Sgibbs if (n_q_required > 1) { 144118781Sgibbs /* 144218781Sgibbs * Only reset the shortage value when processing 144318781Sgibbs * a "normal" request and not error recovery or 144418781Sgibbs * other requests that dip into our reserved queues. 144518781Sgibbs * Generally speaking, a normal request will need more 144618781Sgibbs * than one queue. 144718781Sgibbs */ 144818781Sgibbs adv->openings_needed = 0; 144918781Sgibbs } 145018781Sgibbs scsiq->q1.q_no = free_q_head; 145118781Sgibbs 145218781Sgibbs /* 145318781Sgibbs * Now that we know our Q number, point our sense 145418781Sgibbs * buffer pointer to an area below 16M if we are 145518781Sgibbs * an ISA adapter. 145618781Sgibbs */ 145718781Sgibbs if (adv->sense_buffers != NULL) 145818781Sgibbs scsiq->q1.sense_addr = (u_int32_t)vtophys(&(adv->sense_buffers[free_q_head])); 145918781Sgibbs adv_put_ready_sg_list_queue(adv, scsiq, free_q_head); 146018781Sgibbs adv_write_lram_16(adv, ADVV_FREE_Q_HEAD_W, next_qp); 146118781Sgibbs adv->cur_active += n_q_required; 146218781Sgibbs retval = 0; 146318781Sgibbs } 146418781Sgibbs return (retval); 146518781Sgibbs} 146618781Sgibbs 146718781Sgibbs 146818781Sgibbsstatic void 146918781Sgibbsadv_put_ready_sg_list_queue(adv, scsiq, q_no) 147018781Sgibbs struct adv_softc *adv; 147118781Sgibbs struct adv_scsi_q *scsiq; 147218781Sgibbs u_int8_t q_no; 147318781Sgibbs{ 147418781Sgibbs u_int8_t sg_list_dwords; 147518781Sgibbs u_int8_t sg_index, i; 147618781Sgibbs u_int8_t sg_entry_cnt; 147718781Sgibbs u_int8_t next_qp; 147818781Sgibbs u_int16_t q_addr; 147918781Sgibbs struct adv_sg_head *sg_head; 148018781Sgibbs struct adv_sg_list_q scsi_sg_q; 148118781Sgibbs 148218781Sgibbs sg_head = scsiq->sg_head; 148318781Sgibbs 148418781Sgibbs if (sg_head) { 148518781Sgibbs sg_entry_cnt = sg_head->entry_cnt - 1; 148618781Sgibbs#ifdef DIAGNOSTIC 148718781Sgibbs if (sg_entry_cnt == 0) 148818781Sgibbs panic("adv_put_ready_sg_list_queue: ScsiQ with a SG list but only one element"); 148918781Sgibbs if ((scsiq->q1.cntl & QC_SG_HEAD) == 0) 149018781Sgibbs panic("adv_put_ready_sg_list_queue: ScsiQ with a SG list but QC_SG_HEAD not set"); 149118781Sgibbs#endif 149218781Sgibbs q_addr = ADV_QNO_TO_QADDR(q_no); 149318781Sgibbs sg_index = 1; 149418781Sgibbs scsiq->q1.sg_queue_cnt = sg_head->queue_cnt; 149518781Sgibbs scsi_sg_q.sg_head_qp = q_no; 149618781Sgibbs scsi_sg_q.cntl = QCSG_SG_XFER_LIST; 149718781Sgibbs for (i = 0; i < sg_head->queue_cnt; i++) { 149818781Sgibbs u_int8_t segs_this_q; 149918781Sgibbs 150018781Sgibbs if (sg_entry_cnt > ADV_SG_LIST_PER_Q) 150118781Sgibbs segs_this_q = ADV_SG_LIST_PER_Q; 150218781Sgibbs else { 150318781Sgibbs /* This will be the last segment then */ 150418781Sgibbs segs_this_q = sg_entry_cnt; 150518781Sgibbs scsi_sg_q.cntl |= QCSG_SG_XFER_END; 150618781Sgibbs } 150718781Sgibbs scsi_sg_q.seq_no = i + 1; 150818781Sgibbs sg_list_dwords = segs_this_q * 2; 150918781Sgibbs if (i == 0) { 151018781Sgibbs scsi_sg_q.sg_list_cnt = segs_this_q; 151118781Sgibbs scsi_sg_q.sg_cur_list_cnt = segs_this_q; 151218781Sgibbs } else { 151318781Sgibbs scsi_sg_q.sg_list_cnt = segs_this_q - 1; 151418781Sgibbs scsi_sg_q.sg_cur_list_cnt = segs_this_q - 1; 151518781Sgibbs } 151618781Sgibbs next_qp = adv_read_lram_8(adv, q_addr + ADV_SCSIQ_B_FWD); 151718781Sgibbs scsi_sg_q.q_no = next_qp; 151818781Sgibbs q_addr = ADV_QNO_TO_QADDR(next_qp); 151918781Sgibbs 152018781Sgibbs adv_write_lram_16_multi(adv, q_addr + ADV_SCSIQ_SGHD_CPY_BEG, 152118781Sgibbs (u_int16_t *)&scsi_sg_q, 152218781Sgibbs sizeof(scsi_sg_q) >> 1); 152318781Sgibbs adv_write_lram_32_multi(adv, q_addr + ADV_SGQ_LIST_BEG, 152418781Sgibbs (u_int32_t *)&sg_head->sg_list[sg_index], 152518781Sgibbs sg_list_dwords); 152618781Sgibbs sg_entry_cnt -= segs_this_q; 152718781Sgibbs sg_index += ADV_SG_LIST_PER_Q; 152818781Sgibbs } 152918781Sgibbs } 153018781Sgibbs adv_put_ready_queue(adv, scsiq, q_no); 153118781Sgibbs} 153218781Sgibbs 153318781Sgibbsstatic void 153418781Sgibbsadv_put_ready_queue(adv, scsiq, q_no) 153518781Sgibbs struct adv_softc *adv; 153618781Sgibbs struct adv_scsi_q *scsiq; 153718781Sgibbs u_int8_t q_no; 153818781Sgibbs{ 153918781Sgibbs u_int16_t q_addr; 154018781Sgibbs u_int8_t tid_no; 154118781Sgibbs u_int8_t sdtr_data; 154218781Sgibbs u_int8_t syn_period_ix; 154318781Sgibbs u_int8_t syn_offset; 154418781Sgibbs 154518781Sgibbs if (((adv->initiate_sdtr & scsiq->q1.target_id) != 0) && 154618781Sgibbs ((adv->sdtr_done & scsiq->q1.target_id) == 0)) { 154718781Sgibbs 154818781Sgibbs tid_no = ADV_TIX_TO_TID(scsiq->q2.target_ix); 154918781Sgibbs 155018781Sgibbs sdtr_data = adv_read_lram_8(adv, ADVV_SDTR_DATA_BEG + tid_no); 155118781Sgibbs syn_period_ix = (sdtr_data >> 4) & (ADV_SYN_XFER_NO - 1); 155218781Sgibbs syn_offset = sdtr_data & ADV_SYN_MAX_OFFSET; 155318781Sgibbs adv_msgout_sdtr(adv, adv_sdtr_period_tbl[syn_period_ix], 155418781Sgibbs syn_offset); 155518781Sgibbs 155618781Sgibbs scsiq->q1.cntl |= QC_MSG_OUT; 155718781Sgibbs } 155818781Sgibbs q_addr = ADV_QNO_TO_QADDR(q_no); 155918781Sgibbs 156018781Sgibbs scsiq->q1.status = QS_FREE; 156118781Sgibbs 156218781Sgibbs adv_write_lram_16_multi(adv, q_addr + ADV_SCSIQ_CDB_BEG, 156318781Sgibbs (u_int16_t *)scsiq->cdbptr, 156418781Sgibbs scsiq->q2.cdb_len >> 1); 156518781Sgibbs 156618781Sgibbs#if BYTE_ORDER == BIG_ENDIAN 156718781Sgibbs adv_adj_scsiq_endian(scsiq); 156818781Sgibbs#endif 156918781Sgibbs 157018781Sgibbs adv_put_scsiq(adv, q_addr + ADV_SCSIQ_CPY_BEG, 157118781Sgibbs (u_int16_t *) &scsiq->q1.cntl, 157218781Sgibbs ((sizeof(scsiq->q1) + sizeof(scsiq->q2)) / 2) - 1); 157318781Sgibbs 157418781Sgibbs#if CC_WRITE_IO_COUNT 157518781Sgibbs adv_write_lram_16(adv, q_addr + ADV_SCSIQ_W_REQ_COUNT, 157618781Sgibbs adv->req_count); 157718781Sgibbs#endif 157818781Sgibbs 157918781Sgibbs#if CC_CLEAR_DMA_REMAIN 158018781Sgibbs 158118781Sgibbs adv_write_lram_32(adv, q_addr + ADV_SCSIQ_DW_REMAIN_XFER_ADDR, 0); 158218781Sgibbs adv_write_lram_32(adv, q_addr + ADV_SCSIQ_DW_REMAIN_XFER_CNT, 0); 158318781Sgibbs#endif 158418781Sgibbs 158518781Sgibbs adv_write_lram_16(adv, q_addr + ADV_SCSIQ_B_STATUS, 158618781Sgibbs (scsiq->q1.q_no << 8) | QS_READY); 158718781Sgibbs} 158818781Sgibbs 158918781Sgibbsstatic void 159018781Sgibbsadv_put_scsiq(adv, s_addr, buffer, words) 159118781Sgibbs struct adv_softc *adv; 159218781Sgibbs u_int16_t s_addr; 159318781Sgibbs u_int16_t *buffer; 159418781Sgibbs int words; 159518781Sgibbs{ 159618781Sgibbs int i; 159718781Sgibbs 159818781Sgibbs /* 159918781Sgibbs * XXX This routine makes *gross* assumptions 160018781Sgibbs * about padding in the data structures. 160118781Sgibbs * Either the data structures should have explicit 160218781Sgibbs * padding members added, or they should have padding 160318781Sgibbs * turned off via compiler attributes depending on 160418781Sgibbs * which yields better overall performance. My hunch 160518781Sgibbs * would be that turning off padding would be the 160618781Sgibbs * faster approach as an outsw is much faster than 160718781Sgibbs * this crude loop and accessing un-aligned data 160818781Sgibbs * members isn't *that* expensive. The other choice 160918781Sgibbs * would be to modify the ASC script so that the 161018781Sgibbs * the adv_scsiq_1 structure can be re-arranged so 161118781Sgibbs * padding isn't required. 161218781Sgibbs */ 161318781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr); 161418781Sgibbs for (i = 0; i < words; i++, buffer++) { 161518781Sgibbs if (i == 2 || i == 10) { 161618781Sgibbs continue; 161718781Sgibbs } 161818781Sgibbs ADV_OUTW(adv, ADV_LRAM_DATA, *buffer); 161918781Sgibbs } 162018781Sgibbs} 162118781Sgibbs 162218781Sgibbsstatic u_int8_t 162318781Sgibbsadv_msgout_sdtr(adv, sdtr_period, sdtr_offset) 162418781Sgibbs struct adv_softc *adv; 162518781Sgibbs u_int8_t sdtr_period; 162618781Sgibbs u_int8_t sdtr_offset; 162718781Sgibbs{ 162818781Sgibbs struct sdtr_xmsg sdtr_buf; 162918781Sgibbs 163018781Sgibbs sdtr_buf.msg_type = MSG_EXTENDED; 163118781Sgibbs sdtr_buf.msg_len = MSG_EXT_SDTR_LEN; 163218781Sgibbs sdtr_buf.msg_req = MSG_EXT_SDTR; 163318781Sgibbs sdtr_buf.xfer_period = sdtr_period; 163418781Sgibbs sdtr_offset &= ADV_SYN_MAX_OFFSET; 163518781Sgibbs sdtr_buf.req_ack_offset = sdtr_offset; 163618781Sgibbs adv_write_lram_16_multi(adv, ADVV_MSGOUT_BEG, 163718781Sgibbs (u_int16_t *) &sdtr_buf, 163818781Sgibbs sizeof(sdtr_buf) / 2); 163918781Sgibbs 164018781Sgibbs return (adv_get_card_sync_setting(sdtr_period, sdtr_offset)); 164118781Sgibbs} 164218781Sgibbs 164318781Sgibbsstatic u_int8_t 164418781Sgibbsadv_get_card_sync_setting(period, offset) 164518781Sgibbs u_int8_t period; 164618781Sgibbs u_int8_t offset; 164718781Sgibbs{ 164818781Sgibbs u_int i; 164918781Sgibbs 165018781Sgibbs if (period >= adv_sdtr_period_tbl[0]) { 165118781Sgibbs for (i = 0; i < sizeof(adv_sdtr_period_tbl); i++) { 165218781Sgibbs if (period <= adv_sdtr_period_tbl[i]) 165318781Sgibbs return ((adv_sdtr_period_tbl[i] << 4) | offset); 165418781Sgibbs } 165518781Sgibbs } 165618781Sgibbs return (0); 165718781Sgibbs} 165818781Sgibbs 165918781Sgibbsstatic void 166018781Sgibbsadv_set_chip_sdtr(adv, sdtr_data, tid_no) 166118781Sgibbs struct adv_softc *adv; 166218781Sgibbs u_int8_t sdtr_data; 166318781Sgibbs u_int8_t tid_no; 166418781Sgibbs{ 166518781Sgibbs ADV_OUTB(adv, ADV_SYN_OFFSET, sdtr_data); 166618781Sgibbs adv_write_lram_8(adv, ADVV_SDTR_DONE_BEG + tid_no, sdtr_data); 166718781Sgibbs} 1668