advlib.c revision 139749
1139749Simp/*- 218781Sgibbs * Low level routines for the Advanced Systems Inc. SCSI controllers chips 318781Sgibbs * 455945Sgibbs * Copyright (c) 1996-1997, 1999-2000 Justin 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 1139217Sgibbs * notice, this list of conditions, and the following disclaimer, 1239217Sgibbs * without modification, immediately at the beginning of the file. 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 */ 31139749Simp/*- 3218781Sgibbs * Ported from: 3318781Sgibbs * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters 3418781Sgibbs * 3518781Sgibbs * Copyright (c) 1995-1996 Advanced System Products, Inc. 3618781Sgibbs * All Rights Reserved. 3718781Sgibbs * 3818781Sgibbs * Redistribution and use in source and binary forms, with or without 3918781Sgibbs * modification, are permitted provided that redistributions of source 4018781Sgibbs * code retain the above copyright notice and this comment without 4118781Sgibbs * modification. 4218781Sgibbs */ 4318781Sgibbs 44119418Sobrien#include <sys/cdefs.h> 45119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/advansys/advlib.c 139749 2005-01-06 01:43:34Z imp $"); 46119418Sobrien 4718781Sgibbs#include <sys/param.h> 4845846Sgibbs#include <sys/kernel.h> 4918781Sgibbs#include <sys/systm.h> 5018781Sgibbs 5139217Sgibbs#include <machine/bus_pio.h> 5239217Sgibbs#include <machine/bus.h> 5359082Snyan#include <machine/resource.h> 5459082Snyan#include <sys/bus.h> 5559082Snyan#include <sys/rman.h> 5618781Sgibbs 5739217Sgibbs#include <cam/cam.h> 5839217Sgibbs#include <cam/cam_ccb.h> 5939217Sgibbs#include <cam/cam_sim.h> 6039217Sgibbs#include <cam/cam_xpt_sim.h> 6118781Sgibbs 6239217Sgibbs#include <cam/scsi/scsi_all.h> 6339217Sgibbs#include <cam/scsi/scsi_message.h> 6439217Sgibbs#include <cam/scsi/scsi_da.h> 6539217Sgibbs#include <cam/scsi/scsi_cd.h> 6639217Sgibbs 6718781Sgibbs#include <vm/vm.h> 6818781Sgibbs#include <vm/vm_param.h> 6918781Sgibbs#include <vm/pmap.h> 7018781Sgibbs 7139217Sgibbs#include <dev/advansys/advansys.h> 7218781Sgibbs#include <dev/advansys/advmcode.h> 7318781Sgibbs 7439217Sgibbsstruct adv_quirk_entry { 7539217Sgibbs struct scsi_inquiry_pattern inq_pat; 7639217Sgibbs u_int8_t quirks; 7739217Sgibbs#define ADV_QUIRK_FIX_ASYN_XFER_ALWAYS 0x01 7839217Sgibbs#define ADV_QUIRK_FIX_ASYN_XFER 0x02 7939217Sgibbs}; 8039217Sgibbs 8139217Sgibbsstatic struct adv_quirk_entry adv_quirk_table[] = 8239217Sgibbs{ 8339217Sgibbs { 8439217Sgibbs { T_CDROM, SIP_MEDIA_REMOVABLE, "HP", "*", "*" }, 8539217Sgibbs ADV_QUIRK_FIX_ASYN_XFER_ALWAYS|ADV_QUIRK_FIX_ASYN_XFER 8639217Sgibbs }, 8739217Sgibbs { 8839217Sgibbs { T_CDROM, SIP_MEDIA_REMOVABLE, "NEC", "CD-ROM DRIVE", "*" }, 8939217Sgibbs 0 9039217Sgibbs }, 9139217Sgibbs { 9239217Sgibbs { 9339217Sgibbs T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, 9439217Sgibbs "TANDBERG", " TDC 36", "*" 9539217Sgibbs }, 9639217Sgibbs 0 9739217Sgibbs }, 9839217Sgibbs { 9939217Sgibbs { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "WANGTEK", "*", "*" }, 10039217Sgibbs 0 10139217Sgibbs }, 10239217Sgibbs { 10339217Sgibbs { 10439217Sgibbs T_PROCESSOR, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED, 10539217Sgibbs "*", "*", "*" 10639217Sgibbs }, 10739217Sgibbs 0 10839217Sgibbs }, 10939217Sgibbs { 11039217Sgibbs { 11139217Sgibbs T_SCANNER, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED, 11239217Sgibbs "*", "*", "*" 11339217Sgibbs }, 11439217Sgibbs 0 11539217Sgibbs }, 11639217Sgibbs { 11739217Sgibbs /* Default quirk entry */ 11839217Sgibbs { 11939217Sgibbs T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED, 12039217Sgibbs /*vendor*/"*", /*product*/"*", /*revision*/"*" 12139217Sgibbs }, 12239217Sgibbs ADV_QUIRK_FIX_ASYN_XFER, 12339217Sgibbs } 12439217Sgibbs}; 12539217Sgibbs 12618781Sgibbs/* 12718781Sgibbs * Allowable periods in ns 12818781Sgibbs */ 12945575Seivindstatic u_int8_t adv_sdtr_period_tbl[] = 13018781Sgibbs{ 13118781Sgibbs 25, 13218781Sgibbs 30, 13318781Sgibbs 35, 13418781Sgibbs 40, 13518781Sgibbs 50, 13618781Sgibbs 60, 13718781Sgibbs 70, 13818781Sgibbs 85 13918781Sgibbs}; 14018781Sgibbs 14145575Seivindstatic u_int8_t adv_sdtr_period_tbl_ultra[] = 14239217Sgibbs{ 14339217Sgibbs 12, 14439217Sgibbs 19, 14539217Sgibbs 25, 14639217Sgibbs 32, 14739217Sgibbs 38, 14839217Sgibbs 44, 14939217Sgibbs 50, 15039217Sgibbs 57, 15139217Sgibbs 63, 15239217Sgibbs 69, 15339217Sgibbs 75, 15439217Sgibbs 82, 15539217Sgibbs 88, 15639217Sgibbs 94, 15739217Sgibbs 100, 15839217Sgibbs 107 15918781Sgibbs}; 16018781Sgibbs 16139217Sgibbsstruct ext_msg { 16239217Sgibbs u_int8_t msg_type; 16339217Sgibbs u_int8_t msg_len; 16439217Sgibbs u_int8_t msg_req; 16539217Sgibbs union { 16639217Sgibbs struct { 16739217Sgibbs u_int8_t sdtr_xfer_period; 16839217Sgibbs u_int8_t sdtr_req_ack_offset; 16939217Sgibbs } sdtr; 17039217Sgibbs struct { 17139217Sgibbs u_int8_t wdtr_width; 17239217Sgibbs } wdtr; 17339217Sgibbs struct { 17439217Sgibbs u_int8_t mdp[4]; 17539217Sgibbs } mdp; 17639217Sgibbs } u_ext_msg; 17739217Sgibbs u_int8_t res; 17839217Sgibbs}; 17939217Sgibbs 18039217Sgibbs#define xfer_period u_ext_msg.sdtr.sdtr_xfer_period 18139217Sgibbs#define req_ack_offset u_ext_msg.sdtr.sdtr_req_ack_offset 18239217Sgibbs#define wdtr_width u_ext_msg.wdtr.wdtr_width 18339217Sgibbs#define mdp_b3 u_ext_msg.mdp_b3 18439217Sgibbs#define mdp_b2 u_ext_msg.mdp_b2 18539217Sgibbs#define mdp_b1 u_ext_msg.mdp_b1 18639217Sgibbs#define mdp_b0 u_ext_msg.mdp_b0 18739217Sgibbs 18818781Sgibbs/* 18918781Sgibbs * Some of the early PCI adapters have problems with 19039217Sgibbs * async transfers. Instead use an offset of 1. 19118781Sgibbs */ 19239217Sgibbs#define ASYN_SDTR_DATA_FIX_PCI_REV_AB 0x41 19318781Sgibbs 19418781Sgibbs/* LRAM routines */ 19539217Sgibbsstatic void adv_read_lram_16_multi(struct adv_softc *adv, u_int16_t s_addr, 19639217Sgibbs u_int16_t *buffer, int count); 19739217Sgibbsstatic void adv_write_lram_16_multi(struct adv_softc *adv, 19839217Sgibbs u_int16_t s_addr, u_int16_t *buffer, 19939217Sgibbs int count); 20039217Sgibbsstatic void adv_mset_lram_16(struct adv_softc *adv, u_int16_t s_addr, 20139217Sgibbs u_int16_t set_value, int count); 20239217Sgibbsstatic u_int32_t adv_msum_lram_16(struct adv_softc *adv, u_int16_t s_addr, 20339217Sgibbs int count); 20418781Sgibbs 20539217Sgibbsstatic int adv_write_and_verify_lram_16(struct adv_softc *adv, 20639217Sgibbs u_int16_t addr, u_int16_t value); 20739217Sgibbsstatic u_int32_t adv_read_lram_32(struct adv_softc *adv, u_int16_t addr); 20818781Sgibbs 20918781Sgibbs 21039217Sgibbsstatic void adv_write_lram_32(struct adv_softc *adv, u_int16_t addr, 21139217Sgibbs u_int32_t value); 21239217Sgibbsstatic void adv_write_lram_32_multi(struct adv_softc *adv, 21339217Sgibbs u_int16_t s_addr, u_int32_t *buffer, 21439217Sgibbs int count); 21518781Sgibbs 21618781Sgibbs/* EEPROM routines */ 21739217Sgibbsstatic u_int16_t adv_read_eeprom_16(struct adv_softc *adv, u_int8_t addr); 21839217Sgibbsstatic u_int16_t adv_write_eeprom_16(struct adv_softc *adv, u_int8_t addr, 21939217Sgibbs u_int16_t value); 22039217Sgibbsstatic int adv_write_eeprom_cmd_reg(struct adv_softc *adv, 22139217Sgibbs u_int8_t cmd_reg); 22239217Sgibbsstatic int adv_set_eeprom_config_once(struct adv_softc *adv, 22339217Sgibbs struct adv_eeprom_config *eeconfig); 22418781Sgibbs 22518781Sgibbs/* Initialization */ 22639217Sgibbsstatic u_int32_t adv_load_microcode(struct adv_softc *adv, u_int16_t s_addr, 22739217Sgibbs u_int16_t *mcode_buf, u_int16_t mcode_size); 22818781Sgibbs 22939217Sgibbsstatic void adv_reinit_lram(struct adv_softc *adv); 23039217Sgibbsstatic void adv_init_lram(struct adv_softc *adv); 23139217Sgibbsstatic int adv_init_microcode_var(struct adv_softc *adv); 23239217Sgibbsstatic void adv_init_qlink_var(struct adv_softc *adv); 23339217Sgibbs 23418781Sgibbs/* Interrupts */ 23539217Sgibbsstatic void adv_disable_interrupt(struct adv_softc *adv); 23639217Sgibbsstatic void adv_enable_interrupt(struct adv_softc *adv); 23739217Sgibbsstatic void adv_toggle_irq_act(struct adv_softc *adv); 23818781Sgibbs 23918781Sgibbs/* Chip Control */ 24039217Sgibbsstatic int adv_host_req_chip_halt(struct adv_softc *adv); 24139217Sgibbsstatic void adv_set_chip_ih(struct adv_softc *adv, u_int16_t ins_code); 24218781Sgibbs#if UNUSED 24339217Sgibbsstatic u_int8_t adv_get_chip_scsi_ctrl(struct adv_softc *adv); 24418781Sgibbs#endif 24518781Sgibbs 24618781Sgibbs/* Queue handling and execution */ 24740027Sgibbsstatic __inline int 24840027Sgibbs adv_sgcount_to_qcount(int sgcount); 24940027Sgibbs 25040027Sgibbsstatic __inline int 25140027Sgibbsadv_sgcount_to_qcount(int sgcount) 25240027Sgibbs{ 25340027Sgibbs int n_sg_list_qs; 25440027Sgibbs 25540027Sgibbs n_sg_list_qs = ((sgcount - 1) / ADV_SG_LIST_PER_Q); 25640027Sgibbs if (((sgcount - 1) % ADV_SG_LIST_PER_Q) != 0) 25740027Sgibbs n_sg_list_qs++; 25840027Sgibbs return (n_sg_list_qs + 1); 25940027Sgibbs} 26040027Sgibbs 261111409Sobrien#if BYTE_ORDER == BIG_ENDIAN 262111342Sobrienstatic void adv_adj_endian_qdone_info(struct adv_q_done_info *); 263111342Sobrienstatic void adv_adj_scsiq_endian(struct adv_scsi_q *); 264111409Sobrien#endif 26539217Sgibbsstatic void adv_get_q_info(struct adv_softc *adv, u_int16_t s_addr, 26639217Sgibbs u_int16_t *inbuf, int words); 26739217Sgibbsstatic u_int adv_get_num_free_queues(struct adv_softc *adv, u_int8_t n_qs); 26839217Sgibbsstatic u_int8_t adv_alloc_free_queues(struct adv_softc *adv, 26939217Sgibbs u_int8_t free_q_head, u_int8_t n_free_q); 27039217Sgibbsstatic u_int8_t adv_alloc_free_queue(struct adv_softc *adv, 27139217Sgibbs u_int8_t free_q_head); 27239217Sgibbsstatic int adv_send_scsi_queue(struct adv_softc *adv, 27339217Sgibbs struct adv_scsi_q *scsiq, 27439217Sgibbs u_int8_t n_q_required); 27539217Sgibbsstatic void adv_put_ready_sg_list_queue(struct adv_softc *adv, 27639217Sgibbs struct adv_scsi_q *scsiq, 27739217Sgibbs u_int q_no); 27839217Sgibbsstatic void adv_put_ready_queue(struct adv_softc *adv, 27939217Sgibbs struct adv_scsi_q *scsiq, u_int q_no); 28039217Sgibbsstatic void adv_put_scsiq(struct adv_softc *adv, u_int16_t s_addr, 28139217Sgibbs u_int16_t *buffer, int words); 28218781Sgibbs 28339217Sgibbs/* Messages */ 28439217Sgibbsstatic void adv_handle_extmsg_in(struct adv_softc *adv, 28539217Sgibbs u_int16_t halt_q_addr, u_int8_t q_cntl, 28639217Sgibbs target_bit_vector target_id, 28739217Sgibbs int tid); 28839217Sgibbsstatic void adv_msgout_sdtr(struct adv_softc *adv, u_int8_t sdtr_period, 28939217Sgibbs u_int8_t sdtr_offset); 29039217Sgibbsstatic void adv_set_sdtr_reg_at_id(struct adv_softc *adv, int id, 29139217Sgibbs u_int8_t sdtr_data); 29218781Sgibbs 29318781Sgibbs 29419426Sgibbs/* Exported functions first */ 29518781Sgibbs 29639217Sgibbsvoid 29739217Sgibbsadvasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg) 29839217Sgibbs{ 29918781Sgibbs struct adv_softc *adv; 30039217Sgibbs 30139217Sgibbs adv = (struct adv_softc *)callback_arg; 30239217Sgibbs switch (code) { 30339217Sgibbs case AC_FOUND_DEVICE: 30439217Sgibbs { 30539217Sgibbs struct ccb_getdev *cgd; 30639217Sgibbs target_bit_vector target_mask; 30739217Sgibbs int num_entries; 30839217Sgibbs caddr_t match; 30939217Sgibbs struct adv_quirk_entry *entry; 31039217Sgibbs struct adv_target_transinfo* tinfo; 31139217Sgibbs 31239217Sgibbs cgd = (struct ccb_getdev *)arg; 31339217Sgibbs 31439217Sgibbs target_mask = ADV_TID_TO_TARGET_MASK(cgd->ccb_h.target_id); 31539217Sgibbs 31639217Sgibbs num_entries = sizeof(adv_quirk_table)/sizeof(*adv_quirk_table); 31739217Sgibbs match = cam_quirkmatch((caddr_t)&cgd->inq_data, 31839217Sgibbs (caddr_t)adv_quirk_table, 31939217Sgibbs num_entries, sizeof(*adv_quirk_table), 32039217Sgibbs scsi_inquiry_match); 32139217Sgibbs 32239217Sgibbs if (match == NULL) 32339217Sgibbs panic("advasync: device didn't match wildcard entry!!"); 32439217Sgibbs 32539217Sgibbs entry = (struct adv_quirk_entry *)match; 32639217Sgibbs 32739217Sgibbs if (adv->bug_fix_control & ADV_BUG_FIX_ASYN_USE_SYN) { 32839217Sgibbs if ((entry->quirks & ADV_QUIRK_FIX_ASYN_XFER_ALWAYS)!=0) 32939217Sgibbs adv->fix_asyn_xfer_always |= target_mask; 33039217Sgibbs else 33139217Sgibbs adv->fix_asyn_xfer_always &= ~target_mask; 33239217Sgibbs /* 33339217Sgibbs * We start out life with all bits set and clear them 33439217Sgibbs * after we've determined that the fix isn't necessary. 33539217Sgibbs * It may well be that we've already cleared a target 33639217Sgibbs * before the full inquiry session completes, so don't 33739217Sgibbs * gratuitously set a target bit even if it has this 33839217Sgibbs * quirk. But, if the quirk exonerates a device, clear 33939217Sgibbs * the bit now. 34039217Sgibbs */ 34139217Sgibbs if ((entry->quirks & ADV_QUIRK_FIX_ASYN_XFER) == 0) 34239217Sgibbs adv->fix_asyn_xfer &= ~target_mask; 34339217Sgibbs } 34439217Sgibbs /* 34539217Sgibbs * Reset our sync settings now that we've determined 34639217Sgibbs * what quirks are in effect for the device. 34739217Sgibbs */ 34839217Sgibbs tinfo = &adv->tinfo[cgd->ccb_h.target_id]; 34939217Sgibbs adv_set_syncrate(adv, cgd->ccb_h.path, 35039217Sgibbs cgd->ccb_h.target_id, 35139217Sgibbs tinfo->current.period, 35239217Sgibbs tinfo->current.offset, 35339217Sgibbs ADV_TRANS_CUR); 35439217Sgibbs break; 35539217Sgibbs } 35639217Sgibbs case AC_LOST_DEVICE: 35739217Sgibbs { 35839217Sgibbs u_int target_mask; 35939217Sgibbs 36039217Sgibbs if (adv->bug_fix_control & ADV_BUG_FIX_ASYN_USE_SYN) { 36139217Sgibbs target_mask = 0x01 << xpt_path_target_id(path); 36239217Sgibbs adv->fix_asyn_xfer |= target_mask; 36339217Sgibbs } 36439217Sgibbs 36539217Sgibbs /* 36639217Sgibbs * Revert to async transfers 36739217Sgibbs * for the next device. 36839217Sgibbs */ 36939217Sgibbs adv_set_syncrate(adv, /*path*/NULL, 37039217Sgibbs xpt_path_target_id(path), 37139217Sgibbs /*period*/0, 37239217Sgibbs /*offset*/0, 37339217Sgibbs ADV_TRANS_GOAL|ADV_TRANS_CUR); 37439217Sgibbs } 37539217Sgibbs default: 37639217Sgibbs break; 37739217Sgibbs } 37839217Sgibbs} 37939217Sgibbs 38039217Sgibbsvoid 38139217Sgibbsadv_set_bank(struct adv_softc *adv, u_int8_t bank) 38218781Sgibbs{ 38339217Sgibbs u_int8_t control; 38439217Sgibbs 38539217Sgibbs /* 38639217Sgibbs * Start out with the bank reset to 0 38739217Sgibbs */ 38839217Sgibbs control = ADV_INB(adv, ADV_CHIP_CTRL) 38939217Sgibbs & (~(ADV_CC_SINGLE_STEP | ADV_CC_TEST 39039217Sgibbs | ADV_CC_DIAG | ADV_CC_SCSI_RESET 39139217Sgibbs | ADV_CC_CHIP_RESET | ADV_CC_BANK_ONE)); 39239217Sgibbs if (bank == 1) { 39339217Sgibbs control |= ADV_CC_BANK_ONE; 39439217Sgibbs } else if (bank == 2) { 39539217Sgibbs control |= ADV_CC_DIAG | ADV_CC_BANK_ONE; 39639217Sgibbs } 39739217Sgibbs ADV_OUTB(adv, ADV_CHIP_CTRL, control); 39839217Sgibbs} 39939217Sgibbs 40039217Sgibbsu_int8_t 40139217Sgibbsadv_read_lram_8(struct adv_softc *adv, u_int16_t addr) 40239217Sgibbs{ 40318781Sgibbs u_int8_t byte_data; 40418781Sgibbs u_int16_t word_data; 40518781Sgibbs 40618781Sgibbs /* 40718781Sgibbs * LRAM is accessed on 16bit boundaries. 40818781Sgibbs */ 40918781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, addr & 0xFFFE); 41018781Sgibbs word_data = ADV_INW(adv, ADV_LRAM_DATA); 41118781Sgibbs if (addr & 1) { 41218781Sgibbs#if BYTE_ORDER == BIG_ENDIAN 41318781Sgibbs byte_data = (u_int8_t)(word_data & 0xFF); 41418781Sgibbs#else 41518781Sgibbs byte_data = (u_int8_t)((word_data >> 8) & 0xFF); 41618781Sgibbs#endif 41718781Sgibbs } else { 41818781Sgibbs#if BYTE_ORDER == BIG_ENDIAN 41918781Sgibbs byte_data = (u_int8_t)((word_data >> 8) & 0xFF); 42018781Sgibbs#else 42118781Sgibbs byte_data = (u_int8_t)(word_data & 0xFF); 42218781Sgibbs#endif 42318781Sgibbs } 42418781Sgibbs return (byte_data); 42518781Sgibbs} 42618781Sgibbs 42718781Sgibbsvoid 42839217Sgibbsadv_write_lram_8(struct adv_softc *adv, u_int16_t addr, u_int8_t value) 42918781Sgibbs{ 43018781Sgibbs u_int16_t word_data; 43118781Sgibbs 43218781Sgibbs word_data = adv_read_lram_16(adv, addr & 0xFFFE); 43318781Sgibbs if (addr & 1) { 43418781Sgibbs word_data &= 0x00FF; 43518781Sgibbs word_data |= (((u_int8_t)value << 8) & 0xFF00); 43618781Sgibbs } else { 43718781Sgibbs word_data &= 0xFF00; 43818781Sgibbs word_data |= ((u_int8_t)value & 0x00FF); 43918781Sgibbs } 44018781Sgibbs adv_write_lram_16(adv, addr & 0xFFFE, word_data); 44118781Sgibbs} 44218781Sgibbs 44318781Sgibbs 44418781Sgibbsu_int16_t 44539217Sgibbsadv_read_lram_16(struct adv_softc *adv, u_int16_t addr) 44618781Sgibbs{ 44718781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, addr); 44818781Sgibbs return (ADV_INW(adv, ADV_LRAM_DATA)); 44918781Sgibbs} 45018781Sgibbs 45118781Sgibbsvoid 45239217Sgibbsadv_write_lram_16(struct adv_softc *adv, u_int16_t addr, u_int16_t value) 45318781Sgibbs{ 45418781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, addr); 45518781Sgibbs ADV_OUTW(adv, ADV_LRAM_DATA, value); 45618781Sgibbs} 45718781Sgibbs 45818781Sgibbs/* 45939217Sgibbs * Determine if there is a board at "iobase" by looking 46039217Sgibbs * for the AdvanSys signatures. Return 1 if a board is 46139217Sgibbs * found, 0 otherwise. 46218781Sgibbs */ 46339217Sgibbsint 46439217Sgibbsadv_find_signature(bus_space_tag_t tag, bus_space_handle_t bsh) 46539217Sgibbs{ 46639217Sgibbs u_int16_t signature; 46739217Sgibbs 46839217Sgibbs if (bus_space_read_1(tag, bsh, ADV_SIGNATURE_BYTE) == ADV_1000_ID1B) { 46939217Sgibbs signature = bus_space_read_2(tag, bsh, ADV_SIGNATURE_WORD); 47039217Sgibbs if ((signature == ADV_1000_ID0W) 47139217Sgibbs || (signature == ADV_1000_ID0W_FIX)) 47239217Sgibbs return (1); 47339217Sgibbs } 47439217Sgibbs return (0); 47539217Sgibbs} 47639217Sgibbs 47718781Sgibbsvoid 47839217Sgibbsadv_lib_init(struct adv_softc *adv) 47918781Sgibbs{ 48039217Sgibbs if ((adv->type & ADV_ULTRA) != 0) { 48139217Sgibbs adv->sdtr_period_tbl = adv_sdtr_period_tbl_ultra; 48239217Sgibbs adv->sdtr_period_tbl_size = sizeof(adv_sdtr_period_tbl_ultra); 48339217Sgibbs } else { 48439217Sgibbs adv->sdtr_period_tbl = adv_sdtr_period_tbl; 48539217Sgibbs adv->sdtr_period_tbl_size = sizeof(adv_sdtr_period_tbl); 48639217Sgibbs } 48718781Sgibbs} 48818781Sgibbs 48918781Sgibbsu_int16_t 49039217Sgibbsadv_get_eeprom_config(struct adv_softc *adv, struct 49139217Sgibbs adv_eeprom_config *eeprom_config) 49218781Sgibbs{ 49318781Sgibbs u_int16_t sum; 49418781Sgibbs u_int16_t *wbuf; 49518781Sgibbs u_int8_t cfg_beg; 49618781Sgibbs u_int8_t cfg_end; 49718781Sgibbs u_int8_t s_addr; 49818781Sgibbs 49918781Sgibbs wbuf = (u_int16_t *)eeprom_config; 50018781Sgibbs sum = 0; 50118781Sgibbs 50218781Sgibbs for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) { 50318781Sgibbs *wbuf = adv_read_eeprom_16(adv, s_addr); 50418781Sgibbs sum += *wbuf; 50518781Sgibbs } 50618781Sgibbs 50718781Sgibbs if (adv->type & ADV_VL) { 50818781Sgibbs cfg_beg = ADV_EEPROM_CFG_BEG_VL; 50918781Sgibbs cfg_end = ADV_EEPROM_MAX_ADDR_VL; 51018781Sgibbs } else { 51118781Sgibbs cfg_beg = ADV_EEPROM_CFG_BEG; 51218781Sgibbs cfg_end = ADV_EEPROM_MAX_ADDR; 51318781Sgibbs } 51418781Sgibbs 51518781Sgibbs for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) { 51618781Sgibbs *wbuf = adv_read_eeprom_16(adv, s_addr); 51718781Sgibbs sum += *wbuf; 51818781Sgibbs#if ADV_DEBUG_EEPROM 51918781Sgibbs printf("Addr 0x%x: 0x%04x\n", s_addr, *wbuf); 52018781Sgibbs#endif 52118781Sgibbs } 52218781Sgibbs *wbuf = adv_read_eeprom_16(adv, s_addr); 52318781Sgibbs return (sum); 52418781Sgibbs} 52518781Sgibbs 52618781Sgibbsint 52739217Sgibbsadv_set_eeprom_config(struct adv_softc *adv, 52839217Sgibbs struct adv_eeprom_config *eeprom_config) 52918781Sgibbs{ 53018781Sgibbs int retry; 53118781Sgibbs 53218781Sgibbs retry = 0; 53318781Sgibbs while (1) { 53418781Sgibbs if (adv_set_eeprom_config_once(adv, eeprom_config) == 0) { 53518781Sgibbs break; 53618781Sgibbs } 53718781Sgibbs if (++retry > ADV_EEPROM_MAX_RETRY) { 53818781Sgibbs break; 53918781Sgibbs } 54018781Sgibbs } 54118781Sgibbs return (retry > ADV_EEPROM_MAX_RETRY); 54218781Sgibbs} 54318781Sgibbs 54418781Sgibbsint 54555945Sgibbsadv_reset_chip(struct adv_softc *adv, int reset_bus) 54618781Sgibbs{ 54718781Sgibbs adv_stop_chip(adv); 54855945Sgibbs ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_CHIP_RESET | ADV_CC_HALT 54955945Sgibbs | (reset_bus ? ADV_CC_SCSI_RESET : 0)); 55055945Sgibbs DELAY(60); 55118781Sgibbs 55218781Sgibbs adv_set_chip_ih(adv, ADV_INS_RFLAG_WTM); 55318781Sgibbs adv_set_chip_ih(adv, ADV_INS_HALT); 55418781Sgibbs 55555945Sgibbs if (reset_bus) 55655945Sgibbs ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_CHIP_RESET | ADV_CC_HALT); 55755945Sgibbs 55818781Sgibbs ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_HALT); 55955945Sgibbs if (reset_bus) 56055945Sgibbs DELAY(200 * 1000); 56155945Sgibbs 56255945Sgibbs ADV_OUTW(adv, ADV_CHIP_STATUS, ADV_CIW_CLR_SCSI_RESET_INT); 56355945Sgibbs ADV_OUTW(adv, ADV_CHIP_STATUS, 0); 56418781Sgibbs return (adv_is_chip_halted(adv)); 56518781Sgibbs} 56618781Sgibbs 56718781Sgibbsint 56839217Sgibbsadv_test_external_lram(struct adv_softc* adv) 56918781Sgibbs{ 57018781Sgibbs u_int16_t q_addr; 57118781Sgibbs u_int16_t saved_value; 57218781Sgibbs int success; 57318781Sgibbs 57418781Sgibbs success = 0; 57518781Sgibbs 57618781Sgibbs q_addr = ADV_QNO_TO_QADDR(241); 57718781Sgibbs saved_value = adv_read_lram_16(adv, q_addr); 57818781Sgibbs if (adv_write_and_verify_lram_16(adv, q_addr, 0x55AA) == 0) { 57918781Sgibbs success = 1; 58018781Sgibbs adv_write_lram_16(adv, q_addr, saved_value); 58118781Sgibbs } 58218781Sgibbs return (success); 58318781Sgibbs} 58418781Sgibbs 58518781Sgibbs 58618781Sgibbsint 58739217Sgibbsadv_init_lram_and_mcode(struct adv_softc *adv) 58818781Sgibbs{ 58918781Sgibbs u_int32_t retval; 59039217Sgibbs 59118781Sgibbs adv_disable_interrupt(adv); 59218781Sgibbs 59318781Sgibbs adv_init_lram(adv); 59418781Sgibbs 59539217Sgibbs retval = adv_load_microcode(adv, 0, (u_int16_t *)adv_mcode, 59639217Sgibbs adv_mcode_size); 59718781Sgibbs if (retval != adv_mcode_chksum) { 59818781Sgibbs printf("adv%d: Microcode download failed checksum!\n", 59918781Sgibbs adv->unit); 60018781Sgibbs return (1); 60118781Sgibbs } 60218781Sgibbs 60318781Sgibbs if (adv_init_microcode_var(adv) != 0) 60418781Sgibbs return (1); 60518781Sgibbs 60618781Sgibbs adv_enable_interrupt(adv); 60718781Sgibbs return (0); 60818781Sgibbs} 60918781Sgibbs 61018781Sgibbsu_int8_t 61139217Sgibbsadv_get_chip_irq(struct adv_softc *adv) 61218781Sgibbs{ 61318781Sgibbs u_int16_t cfg_lsw; 61418781Sgibbs u_int8_t chip_irq; 61518781Sgibbs 61618781Sgibbs cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW); 61718781Sgibbs 61818781Sgibbs if ((adv->type & ADV_VL) != 0) { 61918781Sgibbs chip_irq = (u_int8_t)(((cfg_lsw >> 2) & 0x07)); 62018781Sgibbs if ((chip_irq == 0) || 62118781Sgibbs (chip_irq == 4) || 62218781Sgibbs (chip_irq == 7)) { 62318781Sgibbs return (0); 62418781Sgibbs } 62518781Sgibbs return (chip_irq + (ADV_MIN_IRQ_NO - 1)); 62618781Sgibbs } 62718781Sgibbs chip_irq = (u_int8_t)(((cfg_lsw >> 2) & 0x03)); 62818781Sgibbs if (chip_irq == 3) 62918781Sgibbs chip_irq += 2; 63018781Sgibbs return (chip_irq + ADV_MIN_IRQ_NO); 63118781Sgibbs} 63218781Sgibbs 63318781Sgibbsu_int8_t 63439217Sgibbsadv_set_chip_irq(struct adv_softc *adv, u_int8_t irq_no) 63518781Sgibbs{ 63618781Sgibbs u_int16_t cfg_lsw; 63718781Sgibbs 63818781Sgibbs if ((adv->type & ADV_VL) != 0) { 63918781Sgibbs if (irq_no != 0) { 64039217Sgibbs if ((irq_no < ADV_MIN_IRQ_NO) 64139217Sgibbs || (irq_no > ADV_MAX_IRQ_NO)) { 64218781Sgibbs irq_no = 0; 64318781Sgibbs } else { 64418781Sgibbs irq_no -= ADV_MIN_IRQ_NO - 1; 64518781Sgibbs } 64618781Sgibbs } 64718781Sgibbs cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW) & 0xFFE3; 64818781Sgibbs cfg_lsw |= 0x0010; 64918781Sgibbs ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw); 65018781Sgibbs adv_toggle_irq_act(adv); 65118781Sgibbs 65218781Sgibbs cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW) & 0xFFE0; 65318781Sgibbs cfg_lsw |= (irq_no & 0x07) << 2; 65418781Sgibbs ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw); 65518781Sgibbs adv_toggle_irq_act(adv); 65618781Sgibbs } else if ((adv->type & ADV_ISA) != 0) { 65718781Sgibbs if (irq_no == 15) 65818781Sgibbs irq_no -= 2; 65918781Sgibbs irq_no -= ADV_MIN_IRQ_NO; 66018781Sgibbs cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW) & 0xFFF3; 66118781Sgibbs cfg_lsw |= (irq_no & 0x03) << 2; 66218781Sgibbs ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw); 66318781Sgibbs } 66418781Sgibbs return (adv_get_chip_irq(adv)); 66518781Sgibbs} 66618781Sgibbs 66739217Sgibbsvoid 66839217Sgibbsadv_set_chip_scsiid(struct adv_softc *adv, int new_id) 66939217Sgibbs{ 67039217Sgibbs u_int16_t cfg_lsw; 67139217Sgibbs 67239217Sgibbs cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW); 67339217Sgibbs if (ADV_CONFIG_SCSIID(cfg_lsw) == new_id) 67439217Sgibbs return; 67539217Sgibbs cfg_lsw &= ~ADV_CFG_LSW_SCSIID; 67639217Sgibbs cfg_lsw |= (new_id & ADV_MAX_TID) << ADV_CFG_LSW_SCSIID_SHIFT; 67739217Sgibbs ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw); 67839217Sgibbs} 67939217Sgibbs 68018781Sgibbsint 68139217Sgibbsadv_execute_scsi_queue(struct adv_softc *adv, struct adv_scsi_q *scsiq, 68239217Sgibbs u_int32_t datalen) 68318781Sgibbs{ 68439217Sgibbs struct adv_target_transinfo* tinfo; 68539217Sgibbs u_int32_t *p_data_addr; 68639217Sgibbs u_int32_t *p_data_bcount; 68739217Sgibbs int disable_syn_offset_one_fix; 68818781Sgibbs int retval; 68918781Sgibbs u_int n_q_required; 69018781Sgibbs u_int32_t addr; 69118781Sgibbs u_int8_t sg_entry_cnt; 69218781Sgibbs u_int8_t target_ix; 69318781Sgibbs u_int8_t sg_entry_cnt_minus_one; 69418781Sgibbs u_int8_t tid_no; 69518781Sgibbs 69618781Sgibbs scsiq->q1.q_no = 0; 69718781Sgibbs retval = 1; /* Default to error case */ 69818781Sgibbs target_ix = scsiq->q2.target_ix; 69918781Sgibbs tid_no = ADV_TIX_TO_TID(target_ix); 70039217Sgibbs tinfo = &adv->tinfo[tid_no]; 70118781Sgibbs 70239217Sgibbs if (scsiq->cdbptr[0] == REQUEST_SENSE) { 70339217Sgibbs /* Renegotiate if appropriate. */ 70439217Sgibbs adv_set_syncrate(adv, /*struct cam_path */NULL, 70539217Sgibbs tid_no, /*period*/0, /*offset*/0, 70639217Sgibbs ADV_TRANS_CUR); 70739217Sgibbs if (tinfo->current.period != tinfo->goal.period) { 70839217Sgibbs adv_msgout_sdtr(adv, tinfo->goal.period, 70939217Sgibbs tinfo->goal.offset); 71018781Sgibbs scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT); 71118781Sgibbs } 71218781Sgibbs } 71318781Sgibbs 71418781Sgibbs if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) { 71518781Sgibbs sg_entry_cnt = scsiq->sg_head->entry_cnt; 71618781Sgibbs sg_entry_cnt_minus_one = sg_entry_cnt - 1; 71718781Sgibbs 71818781Sgibbs#ifdef DIAGNOSTIC 71918781Sgibbs if (sg_entry_cnt <= 1) 72039217Sgibbs panic("adv_execute_scsi_queue: Queue " 72139217Sgibbs "with QC_SG_HEAD set but %d segs.", sg_entry_cnt); 72218781Sgibbs 72318781Sgibbs if (sg_entry_cnt > ADV_MAX_SG_LIST) 72439217Sgibbs panic("adv_execute_scsi_queue: " 72539217Sgibbs "Queue with too many segs."); 72618781Sgibbs 72755945Sgibbs if ((adv->type & (ADV_ISA | ADV_VL | ADV_EISA)) != 0) { 72839505Sgibbs int i; 72939505Sgibbs 73018781Sgibbs for (i = 0; i < sg_entry_cnt_minus_one; i++) { 73118781Sgibbs addr = scsiq->sg_head->sg_list[i].addr + 73218781Sgibbs scsiq->sg_head->sg_list[i].bytes; 73318781Sgibbs 73418781Sgibbs if ((addr & 0x0003) != 0) 73539217Sgibbs panic("adv_execute_scsi_queue: SG " 73639217Sgibbs "with odd address or byte count"); 73718781Sgibbs } 73818781Sgibbs } 73918781Sgibbs#endif 74039217Sgibbs p_data_addr = 74139217Sgibbs &scsiq->sg_head->sg_list[sg_entry_cnt_minus_one].addr; 74239217Sgibbs p_data_bcount = 74339217Sgibbs &scsiq->sg_head->sg_list[sg_entry_cnt_minus_one].bytes; 74418781Sgibbs 74518781Sgibbs n_q_required = adv_sgcount_to_qcount(sg_entry_cnt); 74618781Sgibbs scsiq->sg_head->queue_cnt = n_q_required - 1; 74718781Sgibbs } else { 74818781Sgibbs p_data_addr = &scsiq->q1.data_addr; 74918781Sgibbs p_data_bcount = &scsiq->q1.data_cnt; 75018781Sgibbs n_q_required = 1; 75118781Sgibbs } 75218781Sgibbs 75339217Sgibbs disable_syn_offset_one_fix = FALSE; 75439217Sgibbs 75539217Sgibbs if ((adv->fix_asyn_xfer & scsiq->q1.target_id) != 0 75639217Sgibbs && (adv->fix_asyn_xfer_always & scsiq->q1.target_id) == 0) { 75739217Sgibbs 75839217Sgibbs if (datalen != 0) { 75939217Sgibbs if (datalen < 512) { 76039217Sgibbs disable_syn_offset_one_fix = TRUE; 76139217Sgibbs } else { 76239217Sgibbs if (scsiq->cdbptr[0] == INQUIRY 76339217Sgibbs || scsiq->cdbptr[0] == REQUEST_SENSE 76439217Sgibbs || scsiq->cdbptr[0] == READ_CAPACITY 76539217Sgibbs || scsiq->cdbptr[0] == MODE_SELECT_6 76639217Sgibbs || scsiq->cdbptr[0] == MODE_SENSE_6 76739217Sgibbs || scsiq->cdbptr[0] == MODE_SENSE_10 76839217Sgibbs || scsiq->cdbptr[0] == MODE_SELECT_10 76939217Sgibbs || scsiq->cdbptr[0] == READ_TOC) { 77039217Sgibbs disable_syn_offset_one_fix = TRUE; 77118781Sgibbs } 77218781Sgibbs } 77318781Sgibbs } 77418781Sgibbs } 77539217Sgibbs 77639217Sgibbs if (disable_syn_offset_one_fix) { 77739217Sgibbs scsiq->q2.tag_code &= 77839217Sgibbs ~(MSG_SIMPLE_Q_TAG|MSG_HEAD_OF_Q_TAG|MSG_ORDERED_Q_TAG); 77939217Sgibbs scsiq->q2.tag_code |= (ADV_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX 78039217Sgibbs | ADV_TAG_FLAG_DISABLE_DISCONNECT); 78139217Sgibbs } 78239217Sgibbs 78339217Sgibbs if ((adv->bug_fix_control & ADV_BUG_FIX_IF_NOT_DWB) != 0 78439217Sgibbs && (scsiq->cdbptr[0] == READ_10 || scsiq->cdbptr[0] == READ_6)) { 78539217Sgibbs u_int8_t extra_bytes; 78639217Sgibbs 78739217Sgibbs addr = *p_data_addr + *p_data_bcount; 78839217Sgibbs extra_bytes = addr & 0x0003; 78939217Sgibbs if (extra_bytes != 0 79039217Sgibbs && ((scsiq->q1.cntl & QC_SG_HEAD) != 0 79139217Sgibbs || (scsiq->q1.data_cnt & 0x01FF) == 0)) { 79239217Sgibbs scsiq->q2.tag_code |= ADV_TAG_FLAG_EXTRA_BYTES; 79339217Sgibbs scsiq->q1.extra_bytes = extra_bytes; 79439217Sgibbs *p_data_bcount -= extra_bytes; 79539217Sgibbs } 79639217Sgibbs } 79739217Sgibbs 79818781Sgibbs if ((adv_get_num_free_queues(adv, n_q_required) >= n_q_required) 79939217Sgibbs || ((scsiq->q1.cntl & QC_URGENT) != 0)) 80018781Sgibbs retval = adv_send_scsi_queue(adv, scsiq, n_q_required); 80118781Sgibbs 80218781Sgibbs return (retval); 80318781Sgibbs} 80418781Sgibbs 80518781Sgibbs 80618781Sgibbsu_int8_t 80739217Sgibbsadv_copy_lram_doneq(struct adv_softc *adv, u_int16_t q_addr, 80839217Sgibbs struct adv_q_done_info *scsiq, u_int32_t max_dma_count) 80918781Sgibbs{ 81039217Sgibbs u_int16_t val; 81139217Sgibbs u_int8_t sg_queue_cnt; 81218781Sgibbs 81318781Sgibbs adv_get_q_info(adv, q_addr + ADV_SCSIQ_DONE_INFO_BEG, 81418781Sgibbs (u_int16_t *)scsiq, 81518781Sgibbs (sizeof(scsiq->d2) + sizeof(scsiq->d3)) / 2); 81618781Sgibbs 81718781Sgibbs#if BYTE_ORDER == BIG_ENDIAN 81818781Sgibbs adv_adj_endian_qdone_info(scsiq); 81918781Sgibbs#endif 82018781Sgibbs 82118781Sgibbs val = adv_read_lram_16(adv, q_addr + ADV_SCSIQ_B_STATUS); 82218781Sgibbs scsiq->q_status = val & 0xFF; 82318781Sgibbs scsiq->q_no = (val >> 8) & 0XFF; 82418781Sgibbs 82518781Sgibbs val = adv_read_lram_16(adv, q_addr + ADV_SCSIQ_B_CNTL); 82618781Sgibbs scsiq->cntl = val & 0xFF; 82718781Sgibbs sg_queue_cnt = (val >> 8) & 0xFF; 82818781Sgibbs 82918781Sgibbs val = adv_read_lram_16(adv,q_addr + ADV_SCSIQ_B_SENSE_LEN); 83018781Sgibbs scsiq->sense_len = val & 0xFF; 83139217Sgibbs scsiq->extra_bytes = (val >> 8) & 0xFF; 83218781Sgibbs 83340133Sgibbs /* 83455945Sgibbs * Due to a bug in accessing LRAM on the 940UA, the residual 83555945Sgibbs * is split into separate high and low 16bit quantities. 83640133Sgibbs */ 83739217Sgibbs scsiq->remain_bytes = 83840133Sgibbs adv_read_lram_16(adv, q_addr + ADV_SCSIQ_DW_REMAIN_XFER_CNT); 83955945Sgibbs scsiq->remain_bytes |= 84055945Sgibbs adv_read_lram_16(adv, q_addr + ADV_SCSIQ_W_ALT_DC1) << 16; 84155945Sgibbs 84218781Sgibbs /* 84318781Sgibbs * XXX Is this just a safeguard or will the counter really 84418781Sgibbs * have bogus upper bits? 84518781Sgibbs */ 84618781Sgibbs scsiq->remain_bytes &= max_dma_count; 84718781Sgibbs 84818781Sgibbs return (sg_queue_cnt); 84918781Sgibbs} 85018781Sgibbs 85118781Sgibbsint 85239217Sgibbsadv_start_chip(struct adv_softc *adv) 85318781Sgibbs{ 85439217Sgibbs ADV_OUTB(adv, ADV_CHIP_CTRL, 0); 85539217Sgibbs if ((ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_HALTED) != 0) 85639217Sgibbs return (0); 85739217Sgibbs return (1); 85839217Sgibbs} 85939217Sgibbs 86039217Sgibbsint 86139217Sgibbsadv_stop_execution(struct adv_softc *adv) 86239217Sgibbs{ 86318781Sgibbs int count; 86418781Sgibbs 86518781Sgibbs count = 0; 86618781Sgibbs if (adv_read_lram_8(adv, ADV_STOP_CODE_B) == 0) { 86718781Sgibbs adv_write_lram_8(adv, ADV_STOP_CODE_B, 86818781Sgibbs ADV_STOP_REQ_RISC_STOP); 86918781Sgibbs do { 87018781Sgibbs if (adv_read_lram_8(adv, ADV_STOP_CODE_B) & 87118781Sgibbs ADV_STOP_ACK_RISC_STOP) { 87218781Sgibbs return (1); 87318781Sgibbs } 87418781Sgibbs DELAY(1000); 87518781Sgibbs } while (count++ < 20); 87618781Sgibbs } 87718781Sgibbs return (0); 87818781Sgibbs} 87918781Sgibbs 88018781Sgibbsint 88139217Sgibbsadv_is_chip_halted(struct adv_softc *adv) 88218781Sgibbs{ 88318781Sgibbs if ((ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_HALTED) != 0) { 88418781Sgibbs if ((ADV_INB(adv, ADV_CHIP_CTRL) & ADV_CC_HALT) != 0) { 88518781Sgibbs return (1); 88618781Sgibbs } 88718781Sgibbs } 88818781Sgibbs return (0); 88918781Sgibbs} 89018781Sgibbs 89118781Sgibbs/* 89218781Sgibbs * XXX The numeric constants and the loops in this routine 89318781Sgibbs * need to be documented. 89418781Sgibbs */ 89518781Sgibbsvoid 89639217Sgibbsadv_ack_interrupt(struct adv_softc *adv) 89718781Sgibbs{ 89818781Sgibbs u_int8_t host_flag; 89918781Sgibbs u_int8_t risc_flag; 90018781Sgibbs int loop; 90118781Sgibbs 90218781Sgibbs loop = 0; 90318781Sgibbs do { 90418781Sgibbs risc_flag = adv_read_lram_8(adv, ADVV_RISC_FLAG_B); 90518781Sgibbs if (loop++ > 0x7FFF) { 90618781Sgibbs break; 90718781Sgibbs } 90818781Sgibbs } while ((risc_flag & ADV_RISC_FLAG_GEN_INT) != 0); 90918781Sgibbs 91018781Sgibbs host_flag = adv_read_lram_8(adv, ADVV_HOST_FLAG_B); 91118781Sgibbs adv_write_lram_8(adv, ADVV_HOST_FLAG_B, 91218781Sgibbs host_flag | ADV_HOST_FLAG_ACK_INT); 91318781Sgibbs 91418781Sgibbs ADV_OUTW(adv, ADV_CHIP_STATUS, ADV_CIW_INT_ACK); 91518781Sgibbs loop = 0; 91618781Sgibbs while (ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_INT_PENDING) { 91718781Sgibbs ADV_OUTW(adv, ADV_CHIP_STATUS, ADV_CIW_INT_ACK); 91818781Sgibbs if (loop++ > 3) { 91918781Sgibbs break; 92018781Sgibbs } 92118781Sgibbs } 92218781Sgibbs 92318781Sgibbs adv_write_lram_8(adv, ADVV_HOST_FLAG_B, host_flag); 92418781Sgibbs} 92518781Sgibbs 92618781Sgibbs/* 92718781Sgibbs * Handle all conditions that may halt the chip waiting 92818781Sgibbs * for us to intervene. 92918781Sgibbs */ 93018781Sgibbsvoid 93139217Sgibbsadv_isr_chip_halted(struct adv_softc *adv) 93218781Sgibbs{ 93318781Sgibbs u_int16_t int_halt_code; 93439217Sgibbs u_int16_t halt_q_addr; 93539217Sgibbs target_bit_vector target_mask; 93639217Sgibbs target_bit_vector scsi_busy; 93718781Sgibbs u_int8_t halt_qp; 93818781Sgibbs u_int8_t target_ix; 93918781Sgibbs u_int8_t q_cntl; 94018781Sgibbs u_int8_t tid_no; 94118781Sgibbs 94218781Sgibbs int_halt_code = adv_read_lram_16(adv, ADVV_HALTCODE_W); 94318781Sgibbs halt_qp = adv_read_lram_8(adv, ADVV_CURCDB_B); 94418781Sgibbs halt_q_addr = ADV_QNO_TO_QADDR(halt_qp); 94518781Sgibbs target_ix = adv_read_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_TARGET_IX); 94618781Sgibbs q_cntl = adv_read_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_CNTL); 94718781Sgibbs tid_no = ADV_TIX_TO_TID(target_ix); 94839217Sgibbs target_mask = ADV_TID_TO_TARGET_MASK(tid_no); 94939217Sgibbs if (int_halt_code == ADV_HALT_DISABLE_ASYN_USE_SYN_FIX) { 95018781Sgibbs /* 95139217Sgibbs * Temporarily disable the async fix by removing 95239217Sgibbs * this target from the list of affected targets, 95339217Sgibbs * setting our async rate, and then putting us 95439217Sgibbs * back into the mask. 95518781Sgibbs */ 95639217Sgibbs adv->fix_asyn_xfer &= ~target_mask; 95739217Sgibbs adv_set_syncrate(adv, /*struct cam_path */NULL, 95839217Sgibbs tid_no, /*period*/0, /*offset*/0, 95939217Sgibbs ADV_TRANS_ACTIVE); 96039217Sgibbs adv->fix_asyn_xfer |= target_mask; 96139217Sgibbs } else if (int_halt_code == ADV_HALT_ENABLE_ASYN_USE_SYN_FIX) { 96239217Sgibbs adv_set_syncrate(adv, /*struct cam_path */NULL, 96339217Sgibbs tid_no, /*period*/0, /*offset*/0, 96439217Sgibbs ADV_TRANS_ACTIVE); 96539217Sgibbs } else if (int_halt_code == ADV_HALT_EXTMSG_IN) { 96639217Sgibbs adv_handle_extmsg_in(adv, halt_q_addr, q_cntl, 96739217Sgibbs target_mask, tid_no); 96818781Sgibbs } else if (int_halt_code == ADV_HALT_CHK_CONDITION) { 96955945Sgibbs struct adv_target_transinfo* tinfo; 97055945Sgibbs union ccb *ccb; 97155945Sgibbs u_int32_t cinfo_index; 97255945Sgibbs u_int8_t tag_code; 97355945Sgibbs u_int8_t q_status; 97418781Sgibbs 97539217Sgibbs tinfo = &adv->tinfo[tid_no]; 97618781Sgibbs q_cntl |= QC_REQ_SENSE; 97718781Sgibbs 97839217Sgibbs /* Renegotiate if appropriate. */ 97939217Sgibbs adv_set_syncrate(adv, /*struct cam_path */NULL, 98039217Sgibbs tid_no, /*period*/0, /*offset*/0, 98139217Sgibbs ADV_TRANS_CUR); 98239217Sgibbs if (tinfo->current.period != tinfo->goal.period) { 98339217Sgibbs adv_msgout_sdtr(adv, tinfo->goal.period, 98439217Sgibbs tinfo->goal.offset); 98518781Sgibbs q_cntl |= QC_MSG_OUT; 98618781Sgibbs } 98718781Sgibbs adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_CNTL, q_cntl); 98818781Sgibbs 98918781Sgibbs /* Don't tag request sense commands */ 99039217Sgibbs tag_code = adv_read_lram_8(adv, 99139217Sgibbs halt_q_addr + ADV_SCSIQ_B_TAG_CODE); 99239217Sgibbs tag_code &= 99339217Sgibbs ~(MSG_SIMPLE_Q_TAG|MSG_HEAD_OF_Q_TAG|MSG_ORDERED_Q_TAG); 99418781Sgibbs 99539217Sgibbs if ((adv->fix_asyn_xfer & target_mask) != 0 99639217Sgibbs && (adv->fix_asyn_xfer_always & target_mask) == 0) { 99739217Sgibbs tag_code |= (ADV_TAG_FLAG_DISABLE_DISCONNECT 99839217Sgibbs | ADV_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX); 99939217Sgibbs } 100039217Sgibbs adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_TAG_CODE, 100139217Sgibbs tag_code); 100239217Sgibbs q_status = adv_read_lram_8(adv, 100339217Sgibbs halt_q_addr + ADV_SCSIQ_B_STATUS); 100418781Sgibbs q_status |= (QS_READY | QS_BUSY); 100539217Sgibbs adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_STATUS, 100639217Sgibbs q_status); 100739217Sgibbs /* 100839217Sgibbs * Freeze the devq until we can handle the sense condition. 100939217Sgibbs */ 101055945Sgibbs cinfo_index = 101155945Sgibbs adv_read_lram_32(adv, halt_q_addr + ADV_SCSIQ_D_CINFO_IDX); 101255945Sgibbs ccb = adv->ccb_infos[cinfo_index].ccb; 101339217Sgibbs xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 101439217Sgibbs ccb->ccb_h.status |= CAM_DEV_QFRZN; 101539217Sgibbs adv_abort_ccb(adv, tid_no, ADV_TIX_TO_LUN(target_ix), 101639217Sgibbs /*ccb*/NULL, CAM_REQUEUE_REQ, 101739217Sgibbs /*queued_only*/TRUE); 101818781Sgibbs scsi_busy = adv_read_lram_8(adv, ADVV_SCSIBUSY_B); 101939217Sgibbs scsi_busy &= ~target_mask; 102018781Sgibbs adv_write_lram_8(adv, ADVV_SCSIBUSY_B, scsi_busy); 102145846Sgibbs /* 102245846Sgibbs * Ensure we have enough time to actually 102345846Sgibbs * retrieve the sense. 102445846Sgibbs */ 102545846Sgibbs untimeout(adv_timeout, (caddr_t)ccb, ccb->ccb_h.timeout_ch); 102645846Sgibbs ccb->ccb_h.timeout_ch = 102745846Sgibbs timeout(adv_timeout, (caddr_t)ccb, 5 * hz); 102818781Sgibbs } else if (int_halt_code == ADV_HALT_SDTR_REJECTED) { 102939217Sgibbs struct ext_msg out_msg; 103018781Sgibbs 103118781Sgibbs adv_read_lram_16_multi(adv, ADVV_MSGOUT_BEG, 103218781Sgibbs (u_int16_t *) &out_msg, 103318781Sgibbs sizeof(out_msg)/2); 103418781Sgibbs 103539217Sgibbs if ((out_msg.msg_type == MSG_EXTENDED) 103639217Sgibbs && (out_msg.msg_len == MSG_EXT_SDTR_LEN) 103739217Sgibbs && (out_msg.msg_req == MSG_EXT_SDTR)) { 103818781Sgibbs 103939217Sgibbs /* Revert to Async */ 104039217Sgibbs adv_set_syncrate(adv, /*struct cam_path */NULL, 104139217Sgibbs tid_no, /*period*/0, /*offset*/0, 104239217Sgibbs ADV_TRANS_GOAL|ADV_TRANS_ACTIVE); 104318781Sgibbs } 104418781Sgibbs q_cntl &= ~QC_MSG_OUT; 104518781Sgibbs adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_CNTL, q_cntl); 104618781Sgibbs } else if (int_halt_code == ADV_HALT_SS_QUEUE_FULL) { 104739217Sgibbs u_int8_t scsi_status; 104839217Sgibbs union ccb *ccb; 104955945Sgibbs u_int32_t cinfo_index; 105039217Sgibbs 105139217Sgibbs scsi_status = adv_read_lram_8(adv, halt_q_addr 105239217Sgibbs + ADV_SCSIQ_SCSI_STATUS); 105355945Sgibbs cinfo_index = 105455945Sgibbs adv_read_lram_32(adv, halt_q_addr + ADV_SCSIQ_D_CINFO_IDX); 105555945Sgibbs ccb = adv->ccb_infos[cinfo_index].ccb; 105639217Sgibbs xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 105740733Sgibbs ccb->ccb_h.status |= CAM_DEV_QFRZN|CAM_SCSI_STATUS_ERROR; 105840733Sgibbs ccb->csio.scsi_status = SCSI_STATUS_QUEUE_FULL; 105939217Sgibbs adv_abort_ccb(adv, tid_no, ADV_TIX_TO_LUN(target_ix), 106039217Sgibbs /*ccb*/NULL, CAM_REQUEUE_REQ, 106139217Sgibbs /*queued_only*/TRUE); 106239217Sgibbs scsi_busy = adv_read_lram_8(adv, ADVV_SCSIBUSY_B); 106339217Sgibbs scsi_busy &= ~target_mask; 106439217Sgibbs adv_write_lram_8(adv, ADVV_SCSIBUSY_B, scsi_busy); 106555945Sgibbs } else { 106655945Sgibbs printf("Unhandled Halt Code %x\n", int_halt_code); 106739217Sgibbs } 106839217Sgibbs adv_write_lram_16(adv, ADVV_HALTCODE_W, 0); 106939217Sgibbs} 107018781Sgibbs 107139217Sgibbsvoid 107239217Sgibbsadv_sdtr_to_period_offset(struct adv_softc *adv, 107339217Sgibbs u_int8_t sync_data, u_int8_t *period, 107439217Sgibbs u_int8_t *offset, int tid) 107539217Sgibbs{ 107639217Sgibbs if (adv->fix_asyn_xfer & ADV_TID_TO_TARGET_MASK(tid) 107739217Sgibbs && (sync_data == ASYN_SDTR_DATA_FIX_PCI_REV_AB)) { 107839217Sgibbs *period = *offset = 0; 107939217Sgibbs } else { 108039217Sgibbs *period = adv->sdtr_period_tbl[((sync_data >> 4) & 0xF)]; 108139217Sgibbs *offset = sync_data & 0xF; 108239217Sgibbs } 108339217Sgibbs} 108439217Sgibbs 108539217Sgibbsvoid 108639217Sgibbsadv_set_syncrate(struct adv_softc *adv, struct cam_path *path, 108739217Sgibbs u_int tid, u_int period, u_int offset, u_int type) 108839217Sgibbs{ 108939217Sgibbs struct adv_target_transinfo* tinfo; 109039217Sgibbs u_int old_period; 109139217Sgibbs u_int old_offset; 109239217Sgibbs u_int8_t sdtr_data; 109339217Sgibbs 109439217Sgibbs tinfo = &adv->tinfo[tid]; 109539217Sgibbs 109639217Sgibbs /* Filter our input */ 109739217Sgibbs sdtr_data = adv_period_offset_to_sdtr(adv, &period, 109839217Sgibbs &offset, tid); 109939217Sgibbs 110039217Sgibbs old_period = tinfo->current.period; 110139217Sgibbs old_offset = tinfo->current.offset; 110239217Sgibbs 110339217Sgibbs if ((type & ADV_TRANS_CUR) != 0 110439217Sgibbs && ((old_period != period || old_offset != offset) 110539217Sgibbs || period == 0 || offset == 0) /*Changes in asyn fix settings*/) { 110639217Sgibbs int s; 110739217Sgibbs int halted; 110839217Sgibbs 110939217Sgibbs s = splcam(); 111039217Sgibbs halted = adv_is_chip_halted(adv); 111139217Sgibbs if (halted == 0) 111239217Sgibbs /* Must halt the chip first */ 111339217Sgibbs adv_host_req_chip_halt(adv); 111439217Sgibbs 111539217Sgibbs /* Update current hardware settings */ 111639217Sgibbs adv_set_sdtr_reg_at_id(adv, tid, sdtr_data); 111739217Sgibbs 111818781Sgibbs /* 111939217Sgibbs * If a target can run in sync mode, we don't need 112039217Sgibbs * to check it for sync problems. 112118781Sgibbs */ 112239217Sgibbs if (offset != 0) 112339217Sgibbs adv->fix_asyn_xfer &= ~ADV_TID_TO_TARGET_MASK(tid); 112418781Sgibbs 112539217Sgibbs if (halted == 0) 112639217Sgibbs /* Start the chip again */ 112739217Sgibbs adv_start_chip(adv); 112818781Sgibbs 112939217Sgibbs splx(s); 113039217Sgibbs tinfo->current.period = period; 113139217Sgibbs tinfo->current.offset = offset; 113239217Sgibbs 113339217Sgibbs if (path != NULL) { 113439217Sgibbs /* 113539217Sgibbs * Tell the SCSI layer about the 113639217Sgibbs * new transfer parameters. 113739217Sgibbs */ 113839217Sgibbs struct ccb_trans_settings neg; 113939217Sgibbs 114039217Sgibbs neg.sync_period = period; 114139217Sgibbs neg.sync_offset = offset; 114239217Sgibbs neg.valid = CCB_TRANS_SYNC_RATE_VALID 114339217Sgibbs | CCB_TRANS_SYNC_OFFSET_VALID; 114439217Sgibbs xpt_setup_ccb(&neg.ccb_h, path, /*priority*/1); 114539217Sgibbs xpt_async(AC_TRANSFER_NEG, path, &neg); 114639217Sgibbs } 114739217Sgibbs } 114839217Sgibbs 114939217Sgibbs if ((type & ADV_TRANS_GOAL) != 0) { 115039217Sgibbs tinfo->goal.period = period; 115139217Sgibbs tinfo->goal.offset = offset; 115239217Sgibbs } 115339217Sgibbs 115439217Sgibbs if ((type & ADV_TRANS_USER) != 0) { 115539217Sgibbs tinfo->user.period = period; 115639217Sgibbs tinfo->user.offset = offset; 115739217Sgibbs } 115839217Sgibbs} 115939217Sgibbs 116039217Sgibbsu_int8_t 116139217Sgibbsadv_period_offset_to_sdtr(struct adv_softc *adv, u_int *period, 116239217Sgibbs u_int *offset, int tid) 116339217Sgibbs{ 116439217Sgibbs u_int i; 116539217Sgibbs u_int dummy_offset; 116639217Sgibbs u_int dummy_period; 116739217Sgibbs 116839217Sgibbs if (offset == NULL) { 116939217Sgibbs dummy_offset = 0; 117039217Sgibbs offset = &dummy_offset; 117139217Sgibbs } 117239217Sgibbs 117339217Sgibbs if (period == NULL) { 117439217Sgibbs dummy_period = 0; 117539217Sgibbs period = &dummy_period; 117639217Sgibbs } 117739217Sgibbs 117839217Sgibbs *offset = MIN(ADV_SYN_MAX_OFFSET, *offset); 117939217Sgibbs if (*period != 0 && *offset != 0) { 118039217Sgibbs for (i = 0; i < adv->sdtr_period_tbl_size; i++) { 118139217Sgibbs if (*period <= adv->sdtr_period_tbl[i]) { 118239217Sgibbs /* 118339217Sgibbs * When responding to a target that requests 118439217Sgibbs * sync, the requested rate may fall between 118539217Sgibbs * two rates that we can output, but still be 118639217Sgibbs * a rate that we can receive. Because of this, 118739217Sgibbs * we want to respond to the target with 118839217Sgibbs * the same rate that it sent to us even 118939217Sgibbs * if the period we use to send data to it 119039217Sgibbs * is lower. Only lower the response period 119139217Sgibbs * if we must. 119239217Sgibbs */ 119339217Sgibbs if (i == 0 /* Our maximum rate */) 119439217Sgibbs *period = adv->sdtr_period_tbl[0]; 119539217Sgibbs return ((i << 4) | *offset); 119618781Sgibbs } 119718781Sgibbs } 119818781Sgibbs } 119939217Sgibbs 120039217Sgibbs /* Must go async */ 120139217Sgibbs *period = 0; 120239217Sgibbs *offset = 0; 120339217Sgibbs if (adv->fix_asyn_xfer & ADV_TID_TO_TARGET_MASK(tid)) 120439217Sgibbs return (ASYN_SDTR_DATA_FIX_PCI_REV_AB); 120539217Sgibbs return (0); 120618781Sgibbs} 120718781Sgibbs 120818781Sgibbs/* Internal Routines */ 120918781Sgibbs 121018781Sgibbsstatic void 121139217Sgibbsadv_read_lram_16_multi(struct adv_softc *adv, u_int16_t s_addr, 121239217Sgibbs u_int16_t *buffer, int count) 121318781Sgibbs{ 121418781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr); 121518781Sgibbs ADV_INSW(adv, ADV_LRAM_DATA, buffer, count); 121618781Sgibbs} 121718781Sgibbs 121818781Sgibbsstatic void 121939217Sgibbsadv_write_lram_16_multi(struct adv_softc *adv, u_int16_t s_addr, 122039217Sgibbs u_int16_t *buffer, int count) 122118781Sgibbs{ 122218781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr); 122318781Sgibbs ADV_OUTSW(adv, ADV_LRAM_DATA, buffer, count); 122418781Sgibbs} 122518781Sgibbs 122618781Sgibbsstatic void 122739217Sgibbsadv_mset_lram_16(struct adv_softc *adv, u_int16_t s_addr, 122839217Sgibbs u_int16_t set_value, int count) 122918781Sgibbs{ 123018781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr); 123139217Sgibbs bus_space_set_multi_2(adv->tag, adv->bsh, ADV_LRAM_DATA, 123239217Sgibbs set_value, count); 123318781Sgibbs} 123418781Sgibbs 123518781Sgibbsstatic u_int32_t 123639217Sgibbsadv_msum_lram_16(struct adv_softc *adv, u_int16_t s_addr, int count) 123718781Sgibbs{ 123818781Sgibbs u_int32_t sum; 123918781Sgibbs int i; 124018781Sgibbs 124118781Sgibbs sum = 0; 124239217Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr); 124339217Sgibbs for (i = 0; i < count; i++) 124439217Sgibbs sum += ADV_INW(adv, ADV_LRAM_DATA); 124518781Sgibbs return (sum); 124618781Sgibbs} 124718781Sgibbs 124818781Sgibbsstatic int 124939217Sgibbsadv_write_and_verify_lram_16(struct adv_softc *adv, u_int16_t addr, 125039217Sgibbs u_int16_t value) 125118781Sgibbs{ 125218781Sgibbs int retval; 125318781Sgibbs 125418781Sgibbs retval = 0; 125518781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, addr); 125618781Sgibbs ADV_OUTW(adv, ADV_LRAM_DATA, value); 125739217Sgibbs DELAY(10000); 125818781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, addr); 125918781Sgibbs if (value != ADV_INW(adv, ADV_LRAM_DATA)) 126018781Sgibbs retval = 1; 126118781Sgibbs return (retval); 126218781Sgibbs} 126318781Sgibbs 126418781Sgibbsstatic u_int32_t 126539217Sgibbsadv_read_lram_32(struct adv_softc *adv, u_int16_t addr) 126618781Sgibbs{ 126718781Sgibbs u_int16_t val_low, val_high; 126818781Sgibbs 126918781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, addr); 127018781Sgibbs 127118781Sgibbs#if BYTE_ORDER == BIG_ENDIAN 127218781Sgibbs val_high = ADV_INW(adv, ADV_LRAM_DATA); 127318781Sgibbs val_low = ADV_INW(adv, ADV_LRAM_DATA); 127418781Sgibbs#else 127518781Sgibbs val_low = ADV_INW(adv, ADV_LRAM_DATA); 127618781Sgibbs val_high = ADV_INW(adv, ADV_LRAM_DATA); 127718781Sgibbs#endif 127818781Sgibbs 127918781Sgibbs return (((u_int32_t)val_high << 16) | (u_int32_t)val_low); 128018781Sgibbs} 128118781Sgibbs 128218781Sgibbsstatic void 128339217Sgibbsadv_write_lram_32(struct adv_softc *adv, u_int16_t addr, u_int32_t value) 128418781Sgibbs{ 128518781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, addr); 128618781Sgibbs 128718781Sgibbs#if BYTE_ORDER == BIG_ENDIAN 128818781Sgibbs ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)((value >> 16) & 0xFFFF)); 128918781Sgibbs ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)(value & 0xFFFF)); 129018781Sgibbs#else 129118781Sgibbs ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)(value & 0xFFFF)); 129218781Sgibbs ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)((value >> 16) & 0xFFFF)); 129318781Sgibbs#endif 129418781Sgibbs} 129518781Sgibbs 129618781Sgibbsstatic void 129739217Sgibbsadv_write_lram_32_multi(struct adv_softc *adv, u_int16_t s_addr, 129839217Sgibbs u_int32_t *buffer, int count) 129918781Sgibbs{ 130018781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr); 130139217Sgibbs ADV_OUTSW(adv, ADV_LRAM_DATA, (u_int16_t *)buffer, count * 2); 130218781Sgibbs} 130318781Sgibbs 130418781Sgibbsstatic u_int16_t 130539217Sgibbsadv_read_eeprom_16(struct adv_softc *adv, u_int8_t addr) 130618781Sgibbs{ 130718781Sgibbs u_int16_t read_wval; 130818781Sgibbs u_int8_t cmd_reg; 130918781Sgibbs 131018781Sgibbs adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE_DISABLE); 131118781Sgibbs DELAY(1000); 131218781Sgibbs cmd_reg = addr | ADV_EEPROM_CMD_READ; 131318781Sgibbs adv_write_eeprom_cmd_reg(adv, cmd_reg); 131418781Sgibbs DELAY(1000); 131518781Sgibbs read_wval = ADV_INW(adv, ADV_EEPROM_DATA); 131618781Sgibbs DELAY(1000); 131718781Sgibbs return (read_wval); 131818781Sgibbs} 131918781Sgibbs 132018781Sgibbsstatic u_int16_t 132139217Sgibbsadv_write_eeprom_16(struct adv_softc *adv, u_int8_t addr, u_int16_t value) 132218781Sgibbs{ 132318781Sgibbs u_int16_t read_value; 132418781Sgibbs 132518781Sgibbs read_value = adv_read_eeprom_16(adv, addr); 132618781Sgibbs if (read_value != value) { 132718781Sgibbs adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE_ENABLE); 132818781Sgibbs DELAY(1000); 132918781Sgibbs 133018781Sgibbs ADV_OUTW(adv, ADV_EEPROM_DATA, value); 133118781Sgibbs DELAY(1000); 133218781Sgibbs 133318781Sgibbs adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE | addr); 133418781Sgibbs DELAY(20 * 1000); 133518781Sgibbs 133618781Sgibbs adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE_DISABLE); 133718781Sgibbs DELAY(1000); 133818781Sgibbs read_value = adv_read_eeprom_16(adv, addr); 133918781Sgibbs } 134018781Sgibbs return (read_value); 134118781Sgibbs} 134218781Sgibbs 134318781Sgibbsstatic int 134439217Sgibbsadv_write_eeprom_cmd_reg(struct adv_softc *adv, u_int8_t cmd_reg) 134518781Sgibbs{ 134618781Sgibbs u_int8_t read_back; 134718781Sgibbs int retry; 134818781Sgibbs 134918781Sgibbs retry = 0; 135018781Sgibbs while (1) { 135118781Sgibbs ADV_OUTB(adv, ADV_EEPROM_CMD, cmd_reg); 135218781Sgibbs DELAY(1000); 135318781Sgibbs read_back = ADV_INB(adv, ADV_EEPROM_CMD); 135418781Sgibbs if (read_back == cmd_reg) { 135518781Sgibbs return (1); 135618781Sgibbs } 135718781Sgibbs if (retry++ > ADV_EEPROM_MAX_RETRY) { 135818781Sgibbs return (0); 135918781Sgibbs } 136018781Sgibbs } 136118781Sgibbs} 136218781Sgibbs 136318781Sgibbsstatic int 136439217Sgibbsadv_set_eeprom_config_once(struct adv_softc *adv, 136539217Sgibbs struct adv_eeprom_config *eeprom_config) 136618781Sgibbs{ 136718781Sgibbs int n_error; 136818781Sgibbs u_int16_t *wbuf; 136918781Sgibbs u_int16_t sum; 137018781Sgibbs u_int8_t s_addr; 137118781Sgibbs u_int8_t cfg_beg; 137218781Sgibbs u_int8_t cfg_end; 137318781Sgibbs 137418781Sgibbs wbuf = (u_int16_t *)eeprom_config; 137518781Sgibbs n_error = 0; 137618781Sgibbs sum = 0; 137718781Sgibbs for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) { 137818781Sgibbs sum += *wbuf; 137918781Sgibbs if (*wbuf != adv_write_eeprom_16(adv, s_addr, *wbuf)) { 138018781Sgibbs n_error++; 138118781Sgibbs } 138218781Sgibbs } 138318781Sgibbs if (adv->type & ADV_VL) { 138418781Sgibbs cfg_beg = ADV_EEPROM_CFG_BEG_VL; 138518781Sgibbs cfg_end = ADV_EEPROM_MAX_ADDR_VL; 138618781Sgibbs } else { 138718781Sgibbs cfg_beg = ADV_EEPROM_CFG_BEG; 138818781Sgibbs cfg_end = ADV_EEPROM_MAX_ADDR; 138918781Sgibbs } 139018781Sgibbs 139118781Sgibbs for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) { 139218781Sgibbs sum += *wbuf; 139318781Sgibbs if (*wbuf != adv_write_eeprom_16(adv, s_addr, *wbuf)) { 139418781Sgibbs n_error++; 139518781Sgibbs } 139618781Sgibbs } 139718781Sgibbs *wbuf = sum; 139818781Sgibbs if (sum != adv_write_eeprom_16(adv, s_addr, sum)) { 139918781Sgibbs n_error++; 140018781Sgibbs } 140118781Sgibbs wbuf = (u_int16_t *)eeprom_config; 140218781Sgibbs for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) { 140318781Sgibbs if (*wbuf != adv_read_eeprom_16(adv, s_addr)) { 140418781Sgibbs n_error++; 140518781Sgibbs } 140618781Sgibbs } 140718781Sgibbs for (s_addr = cfg_beg; s_addr <= cfg_end; s_addr++, wbuf++) { 140818781Sgibbs if (*wbuf != adv_read_eeprom_16(adv, s_addr)) { 140918781Sgibbs n_error++; 141018781Sgibbs } 141118781Sgibbs } 141218781Sgibbs return (n_error); 141318781Sgibbs} 141418781Sgibbs 141518781Sgibbsstatic u_int32_t 141639217Sgibbsadv_load_microcode(struct adv_softc *adv, u_int16_t s_addr, 141739217Sgibbs u_int16_t *mcode_buf, u_int16_t mcode_size) 141818781Sgibbs{ 141939217Sgibbs u_int32_t chksum; 142039217Sgibbs u_int16_t mcode_lram_size; 142139217Sgibbs u_int16_t mcode_chksum; 142218781Sgibbs 142318781Sgibbs mcode_lram_size = mcode_size >> 1; 142418781Sgibbs /* XXX Why zero the memory just before you write the whole thing?? */ 142539217Sgibbs adv_mset_lram_16(adv, s_addr, 0, mcode_lram_size); 142618781Sgibbs adv_write_lram_16_multi(adv, s_addr, mcode_buf, mcode_lram_size); 142718781Sgibbs 142818781Sgibbs chksum = adv_msum_lram_16(adv, s_addr, mcode_lram_size); 142918781Sgibbs mcode_chksum = (u_int16_t)adv_msum_lram_16(adv, ADV_CODE_SEC_BEG, 143039217Sgibbs ((mcode_size - s_addr 143139217Sgibbs - ADV_CODE_SEC_BEG) >> 1)); 143218781Sgibbs adv_write_lram_16(adv, ADVV_MCODE_CHKSUM_W, mcode_chksum); 143318781Sgibbs adv_write_lram_16(adv, ADVV_MCODE_SIZE_W, mcode_size); 143418781Sgibbs return (chksum); 143518781Sgibbs} 143618781Sgibbs 143718781Sgibbsstatic void 143839217Sgibbsadv_reinit_lram(struct adv_softc *adv) { 143939217Sgibbs adv_init_lram(adv); 144039217Sgibbs adv_init_qlink_var(adv); 144139217Sgibbs} 144239217Sgibbs 144339217Sgibbsstatic void 144439217Sgibbsadv_init_lram(struct adv_softc *adv) 144518781Sgibbs{ 144639217Sgibbs u_int8_t i; 144739217Sgibbs u_int16_t s_addr; 144818781Sgibbs 144918781Sgibbs adv_mset_lram_16(adv, ADV_QADR_BEG, 0, 145039217Sgibbs (((adv->max_openings + 2 + 1) * 64) >> 1)); 145118781Sgibbs 145218781Sgibbs i = ADV_MIN_ACTIVE_QNO; 145318781Sgibbs s_addr = ADV_QADR_BEG + ADV_QBLK_SIZE; 145418781Sgibbs 145518781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD, i + 1); 145618781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, adv->max_openings); 145718781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, i); 145818781Sgibbs i++; 145918781Sgibbs s_addr += ADV_QBLK_SIZE; 146018781Sgibbs for (; i < adv->max_openings; i++, s_addr += ADV_QBLK_SIZE) { 146118781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD, i + 1); 146218781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, i - 1); 146318781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, i); 146418781Sgibbs } 146518781Sgibbs 146618781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD, ADV_QLINK_END); 146718781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, adv->max_openings - 1); 146818781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, adv->max_openings); 146918781Sgibbs i++; 147018781Sgibbs s_addr += ADV_QBLK_SIZE; 147118781Sgibbs 147218781Sgibbs for (; i <= adv->max_openings + 3; i++, s_addr += ADV_QBLK_SIZE) { 147318781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD, i); 147418781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, i); 147518781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, i); 147618781Sgibbs } 147718781Sgibbs} 147818781Sgibbs 147918781Sgibbsstatic int 148039217Sgibbsadv_init_microcode_var(struct adv_softc *adv) 148118781Sgibbs{ 148239217Sgibbs int i; 148318781Sgibbs 148418781Sgibbs for (i = 0; i <= ADV_MAX_TID; i++) { 148539217Sgibbs 148639217Sgibbs /* Start out async all around */ 148739217Sgibbs adv_set_syncrate(adv, /*path*/NULL, 148839217Sgibbs i, 0, 0, 148939217Sgibbs ADV_TRANS_GOAL|ADV_TRANS_CUR); 149018781Sgibbs } 149118781Sgibbs 149218781Sgibbs adv_init_qlink_var(adv); 149318781Sgibbs 149418781Sgibbs adv_write_lram_8(adv, ADVV_DISC_ENABLE_B, adv->disc_enable); 149518781Sgibbs adv_write_lram_8(adv, ADVV_HOSTSCSI_ID_B, 0x01 << adv->scsi_id); 149618781Sgibbs 149739217Sgibbs adv_write_lram_32(adv, ADVV_OVERRUN_PADDR_D, adv->overrun_physbase); 149818781Sgibbs 149939217Sgibbs adv_write_lram_32(adv, ADVV_OVERRUN_BSIZE_D, ADV_OVERRUN_BSIZE); 150018781Sgibbs 150118781Sgibbs ADV_OUTW(adv, ADV_REG_PROG_COUNTER, ADV_MCODE_START_ADDR); 150218781Sgibbs if (ADV_INW(adv, ADV_REG_PROG_COUNTER) != ADV_MCODE_START_ADDR) { 150339217Sgibbs printf("adv%d: Unable to set program counter. Aborting.\n", 150418781Sgibbs adv->unit); 150518781Sgibbs return (1); 150618781Sgibbs } 150718781Sgibbs return (0); 150818781Sgibbs} 150918781Sgibbs 151018781Sgibbsstatic void 151139217Sgibbsadv_init_qlink_var(struct adv_softc *adv) 151218781Sgibbs{ 151318781Sgibbs int i; 151418781Sgibbs u_int16_t lram_addr; 151518781Sgibbs 151618781Sgibbs adv_write_lram_8(adv, ADVV_NEXTRDY_B, 1); 151718781Sgibbs adv_write_lram_8(adv, ADVV_DONENEXT_B, adv->max_openings); 151818781Sgibbs 151918781Sgibbs adv_write_lram_16(adv, ADVV_FREE_Q_HEAD_W, 1); 152018781Sgibbs adv_write_lram_16(adv, ADVV_DONE_Q_TAIL_W, adv->max_openings); 152118781Sgibbs 152218781Sgibbs adv_write_lram_8(adv, ADVV_BUSY_QHEAD_B, 152318781Sgibbs (u_int8_t)((int) adv->max_openings + 1)); 152418781Sgibbs adv_write_lram_8(adv, ADVV_DISC1_QHEAD_B, 152518781Sgibbs (u_int8_t)((int) adv->max_openings + 2)); 152618781Sgibbs 152718781Sgibbs adv_write_lram_8(adv, ADVV_TOTAL_READY_Q_B, adv->max_openings); 152818781Sgibbs 152918781Sgibbs adv_write_lram_16(adv, ADVV_ASCDVC_ERR_CODE_W, 0); 153018781Sgibbs adv_write_lram_16(adv, ADVV_HALTCODE_W, 0); 153118781Sgibbs adv_write_lram_8(adv, ADVV_STOP_CODE_B, 0); 153218781Sgibbs adv_write_lram_8(adv, ADVV_SCSIBUSY_B, 0); 153318781Sgibbs adv_write_lram_8(adv, ADVV_WTM_FLAG_B, 0); 153439217Sgibbs adv_write_lram_8(adv, ADVV_Q_DONE_IN_PROGRESS_B, 0); 153518781Sgibbs 153618781Sgibbs lram_addr = ADV_QADR_BEG; 153718781Sgibbs for (i = 0; i < 32; i++, lram_addr += 2) 153818781Sgibbs adv_write_lram_16(adv, lram_addr, 0); 153918781Sgibbs} 154039217Sgibbs 154118781Sgibbsstatic void 154239217Sgibbsadv_disable_interrupt(struct adv_softc *adv) 154318781Sgibbs{ 154418781Sgibbs u_int16_t cfg; 154518781Sgibbs 154618781Sgibbs cfg = ADV_INW(adv, ADV_CONFIG_LSW); 154718781Sgibbs ADV_OUTW(adv, ADV_CONFIG_LSW, cfg & ~ADV_CFG_LSW_HOST_INT_ON); 154818781Sgibbs} 154918781Sgibbs 155018781Sgibbsstatic void 155139217Sgibbsadv_enable_interrupt(struct adv_softc *adv) 155218781Sgibbs{ 155318781Sgibbs u_int16_t cfg; 155418781Sgibbs 155518781Sgibbs cfg = ADV_INW(adv, ADV_CONFIG_LSW); 155618781Sgibbs ADV_OUTW(adv, ADV_CONFIG_LSW, cfg | ADV_CFG_LSW_HOST_INT_ON); 155718781Sgibbs} 155818781Sgibbs 155918781Sgibbsstatic void 156039217Sgibbsadv_toggle_irq_act(struct adv_softc *adv) 156118781Sgibbs{ 156218781Sgibbs ADV_OUTW(adv, ADV_CHIP_STATUS, ADV_CIW_IRQ_ACT); 156318781Sgibbs ADV_OUTW(adv, ADV_CHIP_STATUS, 0); 156418781Sgibbs} 156518781Sgibbs 156639217Sgibbsvoid 156739217Sgibbsadv_start_execution(struct adv_softc *adv) 156818781Sgibbs{ 156918781Sgibbs if (adv_read_lram_8(adv, ADV_STOP_CODE_B) != 0) { 157018781Sgibbs adv_write_lram_8(adv, ADV_STOP_CODE_B, 0); 157118781Sgibbs } 157218781Sgibbs} 157318781Sgibbs 157455945Sgibbsint 157539217Sgibbsadv_stop_chip(struct adv_softc *adv) 157618781Sgibbs{ 157718781Sgibbs u_int8_t cc_val; 157818781Sgibbs 157918781Sgibbs cc_val = ADV_INB(adv, ADV_CHIP_CTRL) 158018781Sgibbs & (~(ADV_CC_SINGLE_STEP | ADV_CC_TEST | ADV_CC_DIAG)); 158118781Sgibbs ADV_OUTB(adv, ADV_CHIP_CTRL, cc_val | ADV_CC_HALT); 158218781Sgibbs adv_set_chip_ih(adv, ADV_INS_HALT); 158318781Sgibbs adv_set_chip_ih(adv, ADV_INS_RFLAG_WTM); 158418781Sgibbs if ((ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_HALTED) == 0) { 158518781Sgibbs return (0); 158618781Sgibbs } 158718781Sgibbs return (1); 158818781Sgibbs} 158918781Sgibbs 159039217Sgibbsstatic int 159139217Sgibbsadv_host_req_chip_halt(struct adv_softc *adv) 159239217Sgibbs{ 159339217Sgibbs int count; 159439217Sgibbs u_int8_t saved_stop_code; 159539217Sgibbs 159639217Sgibbs if (adv_is_chip_halted(adv)) 159739217Sgibbs return (1); 159839217Sgibbs 159939217Sgibbs count = 0; 160039217Sgibbs saved_stop_code = adv_read_lram_8(adv, ADVV_STOP_CODE_B); 160139217Sgibbs adv_write_lram_8(adv, ADVV_STOP_CODE_B, 160239217Sgibbs ADV_STOP_HOST_REQ_RISC_HALT | ADV_STOP_REQ_RISC_STOP); 160339217Sgibbs while (adv_is_chip_halted(adv) == 0 160439217Sgibbs && count++ < 2000) 160539217Sgibbs ; 160639217Sgibbs 160739217Sgibbs adv_write_lram_8(adv, ADVV_STOP_CODE_B, saved_stop_code); 160839217Sgibbs return (count < 2000); 160939217Sgibbs} 161039217Sgibbs 161118781Sgibbsstatic void 161239217Sgibbsadv_set_chip_ih(struct adv_softc *adv, u_int16_t ins_code) 161318781Sgibbs{ 161418781Sgibbs adv_set_bank(adv, 1); 161518781Sgibbs ADV_OUTW(adv, ADV_REG_IH, ins_code); 161618781Sgibbs adv_set_bank(adv, 0); 161718781Sgibbs} 161818781Sgibbs 161918781Sgibbs#if UNUSED 162018781Sgibbsstatic u_int8_t 162139217Sgibbsadv_get_chip_scsi_ctrl(struct adv_softc *adv) 162218781Sgibbs{ 162318781Sgibbs u_int8_t scsi_ctrl; 162418781Sgibbs 162518781Sgibbs adv_set_bank(adv, 1); 162618781Sgibbs scsi_ctrl = ADV_INB(adv, ADV_REG_SC); 162718781Sgibbs adv_set_bank(adv, 0); 162818781Sgibbs return (scsi_ctrl); 162918781Sgibbs} 163018781Sgibbs#endif 163118781Sgibbs 163218781Sgibbs/* 163318781Sgibbs * XXX Looks like more padding issues in this routine as well. 163418781Sgibbs * There has to be a way to turn this into an insw. 163518781Sgibbs */ 163618781Sgibbsstatic void 163739217Sgibbsadv_get_q_info(struct adv_softc *adv, u_int16_t s_addr, 163839217Sgibbs u_int16_t *inbuf, int words) 163918781Sgibbs{ 164018781Sgibbs int i; 164118781Sgibbs 164218781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr); 164318781Sgibbs for (i = 0; i < words; i++, inbuf++) { 164418781Sgibbs if (i == 5) { 164518781Sgibbs continue; 164618781Sgibbs } 164718781Sgibbs *inbuf = ADV_INW(adv, ADV_LRAM_DATA); 164818781Sgibbs } 164918781Sgibbs} 165018781Sgibbs 165118781Sgibbsstatic u_int 165239217Sgibbsadv_get_num_free_queues(struct adv_softc *adv, u_int8_t n_qs) 165318781Sgibbs{ 165418781Sgibbs u_int cur_used_qs; 165518781Sgibbs u_int cur_free_qs; 165618781Sgibbs 165739217Sgibbs cur_used_qs = adv->cur_active + ADV_MIN_FREE_Q; 165818781Sgibbs 165918781Sgibbs if ((cur_used_qs + n_qs) <= adv->max_openings) { 166018781Sgibbs cur_free_qs = adv->max_openings - cur_used_qs; 166118781Sgibbs return (cur_free_qs); 166218781Sgibbs } 166339217Sgibbs adv->openings_needed = n_qs; 166418781Sgibbs return (0); 166518781Sgibbs} 166618781Sgibbs 166718781Sgibbsstatic u_int8_t 166839217Sgibbsadv_alloc_free_queues(struct adv_softc *adv, u_int8_t free_q_head, 166939217Sgibbs u_int8_t n_free_q) 167018781Sgibbs{ 167118781Sgibbs int i; 167218781Sgibbs 167318781Sgibbs for (i = 0; i < n_free_q; i++) { 167418781Sgibbs free_q_head = adv_alloc_free_queue(adv, free_q_head); 167518781Sgibbs if (free_q_head == ADV_QLINK_END) 167618781Sgibbs break; 167718781Sgibbs } 167818781Sgibbs return (free_q_head); 167918781Sgibbs} 168018781Sgibbs 168118781Sgibbsstatic u_int8_t 168239217Sgibbsadv_alloc_free_queue(struct adv_softc *adv, u_int8_t free_q_head) 168318781Sgibbs{ 168418781Sgibbs u_int16_t q_addr; 168518781Sgibbs u_int8_t next_qp; 168618781Sgibbs u_int8_t q_status; 168718781Sgibbs 168818781Sgibbs next_qp = ADV_QLINK_END; 168918781Sgibbs q_addr = ADV_QNO_TO_QADDR(free_q_head); 169018781Sgibbs q_status = adv_read_lram_8(adv, q_addr + ADV_SCSIQ_B_STATUS); 169118781Sgibbs 169218781Sgibbs if ((q_status & QS_READY) == 0) 169318781Sgibbs next_qp = adv_read_lram_8(adv, q_addr + ADV_SCSIQ_B_FWD); 169418781Sgibbs 169518781Sgibbs return (next_qp); 169618781Sgibbs} 169718781Sgibbs 169818781Sgibbsstatic int 169939217Sgibbsadv_send_scsi_queue(struct adv_softc *adv, struct adv_scsi_q *scsiq, 170039217Sgibbs u_int8_t n_q_required) 170118781Sgibbs{ 170218781Sgibbs u_int8_t free_q_head; 170318781Sgibbs u_int8_t next_qp; 170418781Sgibbs u_int8_t tid_no; 170518781Sgibbs u_int8_t target_ix; 170618781Sgibbs int retval; 170718781Sgibbs 170818781Sgibbs retval = 1; 170918781Sgibbs target_ix = scsiq->q2.target_ix; 171018781Sgibbs tid_no = ADV_TIX_TO_TID(target_ix); 171118781Sgibbs free_q_head = adv_read_lram_16(adv, ADVV_FREE_Q_HEAD_W) & 0xFF; 171218781Sgibbs if ((next_qp = adv_alloc_free_queues(adv, free_q_head, n_q_required)) 171318781Sgibbs != ADV_QLINK_END) { 171418781Sgibbs scsiq->q1.q_no = free_q_head; 171518781Sgibbs 171618781Sgibbs /* 171718781Sgibbs * Now that we know our Q number, point our sense 171839217Sgibbs * buffer pointer to a bus dma mapped area where 171939217Sgibbs * we can dma the data to. 172018781Sgibbs */ 172139217Sgibbs scsiq->q1.sense_addr = adv->sense_physbase 172239217Sgibbs + ((free_q_head - 1) * sizeof(struct scsi_sense_data)); 172318781Sgibbs adv_put_ready_sg_list_queue(adv, scsiq, free_q_head); 172418781Sgibbs adv_write_lram_16(adv, ADVV_FREE_Q_HEAD_W, next_qp); 172518781Sgibbs adv->cur_active += n_q_required; 172618781Sgibbs retval = 0; 172718781Sgibbs } 172818781Sgibbs return (retval); 172918781Sgibbs} 173018781Sgibbs 173118781Sgibbs 173218781Sgibbsstatic void 173339217Sgibbsadv_put_ready_sg_list_queue(struct adv_softc *adv, struct adv_scsi_q *scsiq, 173439217Sgibbs u_int q_no) 173518781Sgibbs{ 173618781Sgibbs u_int8_t sg_list_dwords; 173718781Sgibbs u_int8_t sg_index, i; 173818781Sgibbs u_int8_t sg_entry_cnt; 173918781Sgibbs u_int8_t next_qp; 174018781Sgibbs u_int16_t q_addr; 174118781Sgibbs struct adv_sg_head *sg_head; 174218781Sgibbs struct adv_sg_list_q scsi_sg_q; 174318781Sgibbs 174418781Sgibbs sg_head = scsiq->sg_head; 174518781Sgibbs 174618781Sgibbs if (sg_head) { 174718781Sgibbs sg_entry_cnt = sg_head->entry_cnt - 1; 174818781Sgibbs#ifdef DIAGNOSTIC 174918781Sgibbs if (sg_entry_cnt == 0) 175039217Sgibbs panic("adv_put_ready_sg_list_queue: ScsiQ with " 175139217Sgibbs "a SG list but only one element"); 175218781Sgibbs if ((scsiq->q1.cntl & QC_SG_HEAD) == 0) 175339217Sgibbs panic("adv_put_ready_sg_list_queue: ScsiQ with " 175439217Sgibbs "a SG list but QC_SG_HEAD not set"); 175518781Sgibbs#endif 175618781Sgibbs q_addr = ADV_QNO_TO_QADDR(q_no); 175718781Sgibbs sg_index = 1; 175818781Sgibbs scsiq->q1.sg_queue_cnt = sg_head->queue_cnt; 175918781Sgibbs scsi_sg_q.sg_head_qp = q_no; 176018781Sgibbs scsi_sg_q.cntl = QCSG_SG_XFER_LIST; 176118781Sgibbs for (i = 0; i < sg_head->queue_cnt; i++) { 176218781Sgibbs u_int8_t segs_this_q; 176318781Sgibbs 176418781Sgibbs if (sg_entry_cnt > ADV_SG_LIST_PER_Q) 176518781Sgibbs segs_this_q = ADV_SG_LIST_PER_Q; 176618781Sgibbs else { 176718781Sgibbs /* This will be the last segment then */ 176818781Sgibbs segs_this_q = sg_entry_cnt; 176918781Sgibbs scsi_sg_q.cntl |= QCSG_SG_XFER_END; 177018781Sgibbs } 177118781Sgibbs scsi_sg_q.seq_no = i + 1; 177239217Sgibbs sg_list_dwords = segs_this_q << 1; 177318781Sgibbs if (i == 0) { 177418781Sgibbs scsi_sg_q.sg_list_cnt = segs_this_q; 177518781Sgibbs scsi_sg_q.sg_cur_list_cnt = segs_this_q; 177618781Sgibbs } else { 177718781Sgibbs scsi_sg_q.sg_list_cnt = segs_this_q - 1; 177818781Sgibbs scsi_sg_q.sg_cur_list_cnt = segs_this_q - 1; 177918781Sgibbs } 178018781Sgibbs next_qp = adv_read_lram_8(adv, q_addr + ADV_SCSIQ_B_FWD); 178118781Sgibbs scsi_sg_q.q_no = next_qp; 178218781Sgibbs q_addr = ADV_QNO_TO_QADDR(next_qp); 178318781Sgibbs 178439217Sgibbs adv_write_lram_16_multi(adv, 178539217Sgibbs q_addr + ADV_SCSIQ_SGHD_CPY_BEG, 178618781Sgibbs (u_int16_t *)&scsi_sg_q, 178718781Sgibbs sizeof(scsi_sg_q) >> 1); 178818781Sgibbs adv_write_lram_32_multi(adv, q_addr + ADV_SGQ_LIST_BEG, 178918781Sgibbs (u_int32_t *)&sg_head->sg_list[sg_index], 179018781Sgibbs sg_list_dwords); 179118781Sgibbs sg_entry_cnt -= segs_this_q; 179218781Sgibbs sg_index += ADV_SG_LIST_PER_Q; 179318781Sgibbs } 179418781Sgibbs } 179518781Sgibbs adv_put_ready_queue(adv, scsiq, q_no); 179618781Sgibbs} 179718781Sgibbs 179818781Sgibbsstatic void 179939217Sgibbsadv_put_ready_queue(struct adv_softc *adv, struct adv_scsi_q *scsiq, 180039217Sgibbs u_int q_no) 180118781Sgibbs{ 180239217Sgibbs struct adv_target_transinfo* tinfo; 180339217Sgibbs u_int q_addr; 180439217Sgibbs u_int tid_no; 180518781Sgibbs 180639217Sgibbs tid_no = ADV_TIX_TO_TID(scsiq->q2.target_ix); 180739217Sgibbs tinfo = &adv->tinfo[tid_no]; 180846581Sken if ((tinfo->current.period != tinfo->goal.period) 180946581Sken || (tinfo->current.offset != tinfo->goal.offset)) { 181018781Sgibbs 181139217Sgibbs adv_msgout_sdtr(adv, tinfo->goal.period, tinfo->goal.offset); 181218781Sgibbs scsiq->q1.cntl |= QC_MSG_OUT; 181318781Sgibbs } 181418781Sgibbs q_addr = ADV_QNO_TO_QADDR(q_no); 181518781Sgibbs 181618781Sgibbs scsiq->q1.status = QS_FREE; 181718781Sgibbs 181818781Sgibbs adv_write_lram_16_multi(adv, q_addr + ADV_SCSIQ_CDB_BEG, 181918781Sgibbs (u_int16_t *)scsiq->cdbptr, 182018781Sgibbs scsiq->q2.cdb_len >> 1); 182118781Sgibbs 182218781Sgibbs#if BYTE_ORDER == BIG_ENDIAN 182318781Sgibbs adv_adj_scsiq_endian(scsiq); 182418781Sgibbs#endif 182518781Sgibbs 182618781Sgibbs adv_put_scsiq(adv, q_addr + ADV_SCSIQ_CPY_BEG, 182718781Sgibbs (u_int16_t *) &scsiq->q1.cntl, 182818781Sgibbs ((sizeof(scsiq->q1) + sizeof(scsiq->q2)) / 2) - 1); 182918781Sgibbs 183018781Sgibbs#if CC_WRITE_IO_COUNT 183118781Sgibbs adv_write_lram_16(adv, q_addr + ADV_SCSIQ_W_REQ_COUNT, 183218781Sgibbs adv->req_count); 183318781Sgibbs#endif 183418781Sgibbs 183518781Sgibbs#if CC_CLEAR_DMA_REMAIN 183618781Sgibbs 183718781Sgibbs adv_write_lram_32(adv, q_addr + ADV_SCSIQ_DW_REMAIN_XFER_ADDR, 0); 183818781Sgibbs adv_write_lram_32(adv, q_addr + ADV_SCSIQ_DW_REMAIN_XFER_CNT, 0); 183918781Sgibbs#endif 184018781Sgibbs 184118781Sgibbs adv_write_lram_16(adv, q_addr + ADV_SCSIQ_B_STATUS, 184218781Sgibbs (scsiq->q1.q_no << 8) | QS_READY); 184318781Sgibbs} 184418781Sgibbs 184518781Sgibbsstatic void 184639217Sgibbsadv_put_scsiq(struct adv_softc *adv, u_int16_t s_addr, 184739217Sgibbs u_int16_t *buffer, int words) 184818781Sgibbs{ 184918781Sgibbs int i; 185018781Sgibbs 185118781Sgibbs /* 185218781Sgibbs * XXX This routine makes *gross* assumptions 185318781Sgibbs * about padding in the data structures. 185418781Sgibbs * Either the data structures should have explicit 185518781Sgibbs * padding members added, or they should have padding 185618781Sgibbs * turned off via compiler attributes depending on 185718781Sgibbs * which yields better overall performance. My hunch 185818781Sgibbs * would be that turning off padding would be the 185918781Sgibbs * faster approach as an outsw is much faster than 186018781Sgibbs * this crude loop and accessing un-aligned data 186118781Sgibbs * members isn't *that* expensive. The other choice 186218781Sgibbs * would be to modify the ASC script so that the 186318781Sgibbs * the adv_scsiq_1 structure can be re-arranged so 186418781Sgibbs * padding isn't required. 186518781Sgibbs */ 186618781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr); 186718781Sgibbs for (i = 0; i < words; i++, buffer++) { 186818781Sgibbs if (i == 2 || i == 10) { 186918781Sgibbs continue; 187018781Sgibbs } 187118781Sgibbs ADV_OUTW(adv, ADV_LRAM_DATA, *buffer); 187218781Sgibbs } 187318781Sgibbs} 187418781Sgibbs 1875111342Sobrien#if BYTE_ORDER == BIG_ENDIAN 1876111342Sobrienvoid 1877111342Sobrienadv_adj_endian_qdone_info(struct adv_q_done_info *scsiq) 1878111342Sobrien{ 1879111342Sobrien 1880111342Sobrien panic("adv(4) not supported on big-endian machines.\n"); 1881111342Sobrien} 1882111342Sobrien 1883111342Sobrienvoid 1884111342Sobrienadv_adj_scsiq_endian(struct adv_scsi_q *scsiq) 1885111342Sobrien{ 1886111342Sobrien 1887111342Sobrien panic("adv(4) not supported on big-endian machines.\n"); 1888111342Sobrien} 1889111342Sobrien#endif 1890111342Sobrien 189139217Sgibbsstatic void 189239217Sgibbsadv_handle_extmsg_in(struct adv_softc *adv, u_int16_t halt_q_addr, 189339217Sgibbs u_int8_t q_cntl, target_bit_vector target_mask, 189439217Sgibbs int tid_no) 189518781Sgibbs{ 189639217Sgibbs struct ext_msg ext_msg; 189718781Sgibbs 189839217Sgibbs adv_read_lram_16_multi(adv, ADVV_MSGIN_BEG, (u_int16_t *) &ext_msg, 189939217Sgibbs sizeof(ext_msg) >> 1); 190039217Sgibbs if ((ext_msg.msg_type == MSG_EXTENDED) 190139217Sgibbs && (ext_msg.msg_req == MSG_EXT_SDTR) 190239217Sgibbs && (ext_msg.msg_len == MSG_EXT_SDTR_LEN)) { 190355945Sgibbs union ccb *ccb; 190455945Sgibbs struct adv_target_transinfo* tinfo; 190555945Sgibbs u_int32_t cinfo_index; 190639217Sgibbs u_int period; 190739217Sgibbs u_int offset; 190839217Sgibbs int sdtr_accept; 190939217Sgibbs u_int8_t orig_offset; 191039217Sgibbs 191155945Sgibbs cinfo_index = 191255945Sgibbs adv_read_lram_32(adv, halt_q_addr + ADV_SCSIQ_D_CINFO_IDX); 191355945Sgibbs ccb = adv->ccb_infos[cinfo_index].ccb; 191439217Sgibbs tinfo = &adv->tinfo[tid_no]; 191539217Sgibbs sdtr_accept = TRUE; 191639217Sgibbs 191739217Sgibbs orig_offset = ext_msg.req_ack_offset; 191839217Sgibbs if (ext_msg.xfer_period < tinfo->goal.period) { 191939217Sgibbs sdtr_accept = FALSE; 192039217Sgibbs ext_msg.xfer_period = tinfo->goal.period; 192139217Sgibbs } 192239217Sgibbs 192339217Sgibbs /* Perform range checking */ 192439217Sgibbs period = ext_msg.xfer_period; 192539217Sgibbs offset = ext_msg.req_ack_offset; 192639217Sgibbs adv_period_offset_to_sdtr(adv, &period, &offset, tid_no); 192739217Sgibbs ext_msg.xfer_period = period; 192839217Sgibbs ext_msg.req_ack_offset = offset; 192939217Sgibbs 193039217Sgibbs /* Record our current sync settings */ 193139217Sgibbs adv_set_syncrate(adv, ccb->ccb_h.path, 193239217Sgibbs tid_no, ext_msg.xfer_period, 193339217Sgibbs ext_msg.req_ack_offset, 193439217Sgibbs ADV_TRANS_GOAL|ADV_TRANS_ACTIVE); 193539217Sgibbs 193639217Sgibbs /* Offset too high or large period forced async */ 193739217Sgibbs if (orig_offset != ext_msg.req_ack_offset) 193839217Sgibbs sdtr_accept = FALSE; 193939217Sgibbs 194039217Sgibbs if (sdtr_accept && (q_cntl & QC_MSG_OUT)) { 194139217Sgibbs /* Valid response to our requested negotiation */ 194239217Sgibbs q_cntl &= ~QC_MSG_OUT; 194339217Sgibbs } else { 194439217Sgibbs /* Must Respond */ 194539217Sgibbs q_cntl |= QC_MSG_OUT; 194639217Sgibbs adv_msgout_sdtr(adv, ext_msg.xfer_period, 194739217Sgibbs ext_msg.req_ack_offset); 194839217Sgibbs } 194939217Sgibbs 195039217Sgibbs } else if (ext_msg.msg_type == MSG_EXTENDED 195139217Sgibbs && ext_msg.msg_req == MSG_EXT_WDTR 195239217Sgibbs && ext_msg.msg_len == MSG_EXT_WDTR_LEN) { 195339217Sgibbs 195439217Sgibbs ext_msg.wdtr_width = 0; 195539217Sgibbs adv_write_lram_16_multi(adv, ADVV_MSGOUT_BEG, 195639217Sgibbs (u_int16_t *)&ext_msg, 195739217Sgibbs sizeof(ext_msg) >> 1); 195839217Sgibbs q_cntl |= QC_MSG_OUT; 195939217Sgibbs } else { 196039217Sgibbs 196139217Sgibbs ext_msg.msg_type = MSG_MESSAGE_REJECT; 196239217Sgibbs adv_write_lram_16_multi(adv, ADVV_MSGOUT_BEG, 196339217Sgibbs (u_int16_t *)&ext_msg, 196439217Sgibbs sizeof(ext_msg) >> 1); 196539217Sgibbs q_cntl |= QC_MSG_OUT; 196639217Sgibbs } 196739217Sgibbs adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_CNTL, q_cntl); 196839217Sgibbs} 196939217Sgibbs 197039217Sgibbsstatic void 197139217Sgibbsadv_msgout_sdtr(struct adv_softc *adv, u_int8_t sdtr_period, 197239217Sgibbs u_int8_t sdtr_offset) 197339217Sgibbs{ 197439217Sgibbs struct ext_msg sdtr_buf; 197539217Sgibbs 197618781Sgibbs sdtr_buf.msg_type = MSG_EXTENDED; 197718781Sgibbs sdtr_buf.msg_len = MSG_EXT_SDTR_LEN; 197818781Sgibbs sdtr_buf.msg_req = MSG_EXT_SDTR; 197918781Sgibbs sdtr_buf.xfer_period = sdtr_period; 198018781Sgibbs sdtr_offset &= ADV_SYN_MAX_OFFSET; 198118781Sgibbs sdtr_buf.req_ack_offset = sdtr_offset; 198218781Sgibbs adv_write_lram_16_multi(adv, ADVV_MSGOUT_BEG, 198318781Sgibbs (u_int16_t *) &sdtr_buf, 198418781Sgibbs sizeof(sdtr_buf) / 2); 198518781Sgibbs} 198618781Sgibbs 198739217Sgibbsint 198839217Sgibbsadv_abort_ccb(struct adv_softc *adv, int target, int lun, union ccb *ccb, 198939217Sgibbs u_int32_t status, int queued_only) 199018781Sgibbs{ 199139217Sgibbs u_int16_t q_addr; 199239217Sgibbs u_int8_t q_no; 199339217Sgibbs struct adv_q_done_info scsiq_buf; 199439217Sgibbs struct adv_q_done_info *scsiq; 199539217Sgibbs u_int8_t target_ix; 199639217Sgibbs int count; 199718781Sgibbs 199839217Sgibbs scsiq = &scsiq_buf; 199939217Sgibbs target_ix = ADV_TIDLUN_TO_IX(target, lun); 200039217Sgibbs count = 0; 200139217Sgibbs for (q_no = ADV_MIN_ACTIVE_QNO; q_no <= adv->max_openings; q_no++) { 200255945Sgibbs struct adv_ccb_info *ccb_info; 200339217Sgibbs q_addr = ADV_QNO_TO_QADDR(q_no); 200439217Sgibbs 200539217Sgibbs adv_copy_lram_doneq(adv, q_addr, scsiq, adv->max_dma_count); 200655945Sgibbs ccb_info = &adv->ccb_infos[scsiq->d2.ccb_index]; 200739217Sgibbs if (((scsiq->q_status & QS_READY) != 0) 200839217Sgibbs && ((scsiq->q_status & QS_ABORTED) == 0) 200939217Sgibbs && ((scsiq->cntl & QCSG_SG_XFER_LIST) == 0) 201039217Sgibbs && (scsiq->d2.target_ix == target_ix) 201139217Sgibbs && (queued_only == 0 201239217Sgibbs || !(scsiq->q_status & (QS_DISC1|QS_DISC2|QS_BUSY|QS_DONE))) 201355945Sgibbs && (ccb == NULL || (ccb == ccb_info->ccb))) { 201439217Sgibbs union ccb *aborted_ccb; 201539217Sgibbs struct adv_ccb_info *cinfo; 201639217Sgibbs 201739217Sgibbs scsiq->q_status |= QS_ABORTED; 201839217Sgibbs adv_write_lram_8(adv, q_addr + ADV_SCSIQ_B_STATUS, 201939217Sgibbs scsiq->q_status); 202055945Sgibbs aborted_ccb = ccb_info->ccb; 202139217Sgibbs /* Don't clobber earlier error codes */ 202239217Sgibbs if ((aborted_ccb->ccb_h.status & CAM_STATUS_MASK) 202339217Sgibbs == CAM_REQ_INPROG) 202439217Sgibbs aborted_ccb->ccb_h.status |= status; 202539217Sgibbs cinfo = (struct adv_ccb_info *) 202639217Sgibbs aborted_ccb->ccb_h.ccb_cinfo_ptr; 202739217Sgibbs cinfo->state |= ACCB_ABORT_QUEUED; 202839217Sgibbs count++; 202918781Sgibbs } 203018781Sgibbs } 203139217Sgibbs return (count); 203218781Sgibbs} 203318781Sgibbs 203439217Sgibbsint 203555945Sgibbsadv_reset_bus(struct adv_softc *adv, int initiate_bus_reset) 203639217Sgibbs{ 203739217Sgibbs int count; 203839217Sgibbs int i; 203939217Sgibbs union ccb *ccb; 204039217Sgibbs 204155945Sgibbs i = 200; 204255945Sgibbs while ((ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_SCSI_RESET_ACTIVE) != 0 204355945Sgibbs && i--) 204455945Sgibbs DELAY(1000); 204555945Sgibbs adv_reset_chip(adv, initiate_bus_reset); 204639217Sgibbs adv_reinit_lram(adv); 204755945Sgibbs for (i = 0; i <= ADV_MAX_TID; i++) 204855945Sgibbs adv_set_syncrate(adv, NULL, i, /*period*/0, 204955945Sgibbs /*offset*/0, ADV_TRANS_CUR); 205039217Sgibbs ADV_OUTW(adv, ADV_REG_PROG_COUNTER, ADV_MCODE_START_ADDR); 205139217Sgibbs 205239217Sgibbs /* Tell the XPT layer that a bus reset occured */ 205339217Sgibbs if (adv->path != NULL) 205439217Sgibbs xpt_async(AC_BUS_RESET, adv->path, NULL); 205539217Sgibbs 205639217Sgibbs count = 0; 205739217Sgibbs while ((ccb = (union ccb *)LIST_FIRST(&adv->pending_ccbs)) != NULL) { 205839217Sgibbs if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) 205939217Sgibbs ccb->ccb_h.status |= CAM_SCSI_BUS_RESET; 206039217Sgibbs adv_done(adv, ccb, QD_ABORTED_BY_HOST, 0, 0, 0); 206139217Sgibbs count++; 206239217Sgibbs } 206339217Sgibbs 206439217Sgibbs adv_start_chip(adv); 206539217Sgibbs return (count); 206639217Sgibbs} 206739217Sgibbs 206818781Sgibbsstatic void 206939217Sgibbsadv_set_sdtr_reg_at_id(struct adv_softc *adv, int tid, u_int8_t sdtr_data) 207018781Sgibbs{ 207139217Sgibbs int orig_id; 207239217Sgibbs 207339217Sgibbs adv_set_bank(adv, 1); 207439217Sgibbs orig_id = ffs(ADV_INB(adv, ADV_HOST_SCSIID)) - 1; 207539217Sgibbs ADV_OUTB(adv, ADV_HOST_SCSIID, tid); 207639217Sgibbs if (ADV_INB(adv, ADV_HOST_SCSIID) == (0x01 << tid)) { 207739217Sgibbs adv_set_bank(adv, 0); 207839217Sgibbs ADV_OUTB(adv, ADV_SYN_OFFSET, sdtr_data); 207939217Sgibbs } 208039217Sgibbs adv_set_bank(adv, 1); 208139217Sgibbs ADV_OUTB(adv, ADV_HOST_SCSIID, orig_id); 208239217Sgibbs adv_set_bank(adv, 0); 208318781Sgibbs} 2084