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$"); 46119418Sobrien 4718781Sgibbs#include <sys/param.h> 48251164Sscottl#include <sys/conf.h> 49251164Sscottl#include <sys/lock.h> 5045846Sgibbs#include <sys/kernel.h> 51251164Sscottl#include <sys/mutex.h> 5218781Sgibbs#include <sys/systm.h> 5318781Sgibbs 5439217Sgibbs#include <machine/bus.h> 5559082Snyan#include <machine/resource.h> 5659082Snyan#include <sys/bus.h> 5759082Snyan#include <sys/rman.h> 5818781Sgibbs 5939217Sgibbs#include <cam/cam.h> 6039217Sgibbs#include <cam/cam_ccb.h> 6139217Sgibbs#include <cam/cam_sim.h> 6239217Sgibbs#include <cam/cam_xpt_sim.h> 6318781Sgibbs 6439217Sgibbs#include <cam/scsi/scsi_all.h> 6539217Sgibbs#include <cam/scsi/scsi_message.h> 6639217Sgibbs#include <cam/scsi/scsi_da.h> 6739217Sgibbs#include <cam/scsi/scsi_cd.h> 6839217Sgibbs 6918781Sgibbs#include <vm/vm.h> 7018781Sgibbs#include <vm/vm_param.h> 7118781Sgibbs#include <vm/pmap.h> 7218781Sgibbs 7339217Sgibbs#include <dev/advansys/advansys.h> 7418781Sgibbs#include <dev/advansys/advmcode.h> 7518781Sgibbs 7639217Sgibbsstruct adv_quirk_entry { 7739217Sgibbs struct scsi_inquiry_pattern inq_pat; 7839217Sgibbs u_int8_t quirks; 7939217Sgibbs#define ADV_QUIRK_FIX_ASYN_XFER_ALWAYS 0x01 8039217Sgibbs#define ADV_QUIRK_FIX_ASYN_XFER 0x02 8139217Sgibbs}; 8239217Sgibbs 8339217Sgibbsstatic struct adv_quirk_entry adv_quirk_table[] = 8439217Sgibbs{ 8539217Sgibbs { 8639217Sgibbs { T_CDROM, SIP_MEDIA_REMOVABLE, "HP", "*", "*" }, 8739217Sgibbs ADV_QUIRK_FIX_ASYN_XFER_ALWAYS|ADV_QUIRK_FIX_ASYN_XFER 8839217Sgibbs }, 8939217Sgibbs { 9039217Sgibbs { T_CDROM, SIP_MEDIA_REMOVABLE, "NEC", "CD-ROM DRIVE", "*" }, 9139217Sgibbs 0 9239217Sgibbs }, 9339217Sgibbs { 9439217Sgibbs { 9539217Sgibbs T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, 9639217Sgibbs "TANDBERG", " TDC 36", "*" 9739217Sgibbs }, 9839217Sgibbs 0 9939217Sgibbs }, 10039217Sgibbs { 10139217Sgibbs { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "WANGTEK", "*", "*" }, 10239217Sgibbs 0 10339217Sgibbs }, 10439217Sgibbs { 10539217Sgibbs { 10639217Sgibbs T_PROCESSOR, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED, 10739217Sgibbs "*", "*", "*" 10839217Sgibbs }, 10939217Sgibbs 0 11039217Sgibbs }, 11139217Sgibbs { 11239217Sgibbs { 11339217Sgibbs T_SCANNER, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED, 11439217Sgibbs "*", "*", "*" 11539217Sgibbs }, 11639217Sgibbs 0 11739217Sgibbs }, 11839217Sgibbs { 11939217Sgibbs /* Default quirk entry */ 12039217Sgibbs { 12139217Sgibbs T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED, 12239217Sgibbs /*vendor*/"*", /*product*/"*", /*revision*/"*" 12339217Sgibbs }, 12439217Sgibbs ADV_QUIRK_FIX_ASYN_XFER, 12539217Sgibbs } 12639217Sgibbs}; 12739217Sgibbs 12818781Sgibbs/* 12918781Sgibbs * Allowable periods in ns 13018781Sgibbs */ 13145575Seivindstatic u_int8_t adv_sdtr_period_tbl[] = 13218781Sgibbs{ 13318781Sgibbs 25, 13418781Sgibbs 30, 13518781Sgibbs 35, 13618781Sgibbs 40, 13718781Sgibbs 50, 13818781Sgibbs 60, 13918781Sgibbs 70, 14018781Sgibbs 85 14118781Sgibbs}; 14218781Sgibbs 14345575Seivindstatic u_int8_t adv_sdtr_period_tbl_ultra[] = 14439217Sgibbs{ 14539217Sgibbs 12, 14639217Sgibbs 19, 14739217Sgibbs 25, 14839217Sgibbs 32, 14939217Sgibbs 38, 15039217Sgibbs 44, 15139217Sgibbs 50, 15239217Sgibbs 57, 15339217Sgibbs 63, 15439217Sgibbs 69, 15539217Sgibbs 75, 15639217Sgibbs 82, 15739217Sgibbs 88, 15839217Sgibbs 94, 15939217Sgibbs 100, 16039217Sgibbs 107 16118781Sgibbs}; 16218781Sgibbs 16339217Sgibbsstruct ext_msg { 16439217Sgibbs u_int8_t msg_type; 16539217Sgibbs u_int8_t msg_len; 16639217Sgibbs u_int8_t msg_req; 16739217Sgibbs union { 16839217Sgibbs struct { 16939217Sgibbs u_int8_t sdtr_xfer_period; 17039217Sgibbs u_int8_t sdtr_req_ack_offset; 17139217Sgibbs } sdtr; 17239217Sgibbs struct { 17339217Sgibbs u_int8_t wdtr_width; 17439217Sgibbs } wdtr; 17539217Sgibbs struct { 17639217Sgibbs u_int8_t mdp[4]; 17739217Sgibbs } mdp; 17839217Sgibbs } u_ext_msg; 17939217Sgibbs u_int8_t res; 18039217Sgibbs}; 18139217Sgibbs 18239217Sgibbs#define xfer_period u_ext_msg.sdtr.sdtr_xfer_period 18339217Sgibbs#define req_ack_offset u_ext_msg.sdtr.sdtr_req_ack_offset 18439217Sgibbs#define wdtr_width u_ext_msg.wdtr.wdtr_width 18539217Sgibbs#define mdp_b3 u_ext_msg.mdp_b3 18639217Sgibbs#define mdp_b2 u_ext_msg.mdp_b2 18739217Sgibbs#define mdp_b1 u_ext_msg.mdp_b1 18839217Sgibbs#define mdp_b0 u_ext_msg.mdp_b0 18939217Sgibbs 19018781Sgibbs/* 19118781Sgibbs * Some of the early PCI adapters have problems with 19239217Sgibbs * async transfers. Instead use an offset of 1. 19318781Sgibbs */ 19439217Sgibbs#define ASYN_SDTR_DATA_FIX_PCI_REV_AB 0x41 19518781Sgibbs 19618781Sgibbs/* LRAM routines */ 19739217Sgibbsstatic void adv_read_lram_16_multi(struct adv_softc *adv, u_int16_t s_addr, 19839217Sgibbs u_int16_t *buffer, int count); 19939217Sgibbsstatic void adv_write_lram_16_multi(struct adv_softc *adv, 20039217Sgibbs u_int16_t s_addr, u_int16_t *buffer, 20139217Sgibbs int count); 20239217Sgibbsstatic void adv_mset_lram_16(struct adv_softc *adv, u_int16_t s_addr, 20339217Sgibbs u_int16_t set_value, int count); 20439217Sgibbsstatic u_int32_t adv_msum_lram_16(struct adv_softc *adv, u_int16_t s_addr, 20539217Sgibbs int count); 20618781Sgibbs 20739217Sgibbsstatic int adv_write_and_verify_lram_16(struct adv_softc *adv, 20839217Sgibbs u_int16_t addr, u_int16_t value); 20939217Sgibbsstatic u_int32_t adv_read_lram_32(struct adv_softc *adv, u_int16_t addr); 21018781Sgibbs 21118781Sgibbs 21239217Sgibbsstatic void adv_write_lram_32(struct adv_softc *adv, u_int16_t addr, 21339217Sgibbs u_int32_t value); 21439217Sgibbsstatic void adv_write_lram_32_multi(struct adv_softc *adv, 21539217Sgibbs u_int16_t s_addr, u_int32_t *buffer, 21639217Sgibbs int count); 21718781Sgibbs 21818781Sgibbs/* EEPROM routines */ 21939217Sgibbsstatic u_int16_t adv_read_eeprom_16(struct adv_softc *adv, u_int8_t addr); 22039217Sgibbsstatic u_int16_t adv_write_eeprom_16(struct adv_softc *adv, u_int8_t addr, 22139217Sgibbs u_int16_t value); 22239217Sgibbsstatic int adv_write_eeprom_cmd_reg(struct adv_softc *adv, 22339217Sgibbs u_int8_t cmd_reg); 22439217Sgibbsstatic int adv_set_eeprom_config_once(struct adv_softc *adv, 22539217Sgibbs struct adv_eeprom_config *eeconfig); 22618781Sgibbs 22718781Sgibbs/* Initialization */ 22839217Sgibbsstatic u_int32_t adv_load_microcode(struct adv_softc *adv, u_int16_t s_addr, 22939217Sgibbs u_int16_t *mcode_buf, u_int16_t mcode_size); 23018781Sgibbs 23139217Sgibbsstatic void adv_reinit_lram(struct adv_softc *adv); 23239217Sgibbsstatic void adv_init_lram(struct adv_softc *adv); 23339217Sgibbsstatic int adv_init_microcode_var(struct adv_softc *adv); 23439217Sgibbsstatic void adv_init_qlink_var(struct adv_softc *adv); 23539217Sgibbs 23618781Sgibbs/* Interrupts */ 23739217Sgibbsstatic void adv_disable_interrupt(struct adv_softc *adv); 23839217Sgibbsstatic void adv_enable_interrupt(struct adv_softc *adv); 23939217Sgibbsstatic void adv_toggle_irq_act(struct adv_softc *adv); 24018781Sgibbs 24118781Sgibbs/* Chip Control */ 24239217Sgibbsstatic int adv_host_req_chip_halt(struct adv_softc *adv); 24339217Sgibbsstatic void adv_set_chip_ih(struct adv_softc *adv, u_int16_t ins_code); 244153072Sru#if 0 24539217Sgibbsstatic u_int8_t adv_get_chip_scsi_ctrl(struct adv_softc *adv); 24618781Sgibbs#endif 24718781Sgibbs 24818781Sgibbs/* Queue handling and execution */ 24940027Sgibbsstatic __inline int 25040027Sgibbs adv_sgcount_to_qcount(int sgcount); 25140027Sgibbs 25240027Sgibbsstatic __inline int 25340027Sgibbsadv_sgcount_to_qcount(int sgcount) 25440027Sgibbs{ 25540027Sgibbs int n_sg_list_qs; 25640027Sgibbs 25740027Sgibbs n_sg_list_qs = ((sgcount - 1) / ADV_SG_LIST_PER_Q); 25840027Sgibbs if (((sgcount - 1) % ADV_SG_LIST_PER_Q) != 0) 25940027Sgibbs n_sg_list_qs++; 26040027Sgibbs return (n_sg_list_qs + 1); 26140027Sgibbs} 26240027Sgibbs 263111409Sobrien#if BYTE_ORDER == BIG_ENDIAN 264111342Sobrienstatic void adv_adj_endian_qdone_info(struct adv_q_done_info *); 265111342Sobrienstatic void adv_adj_scsiq_endian(struct adv_scsi_q *); 266111409Sobrien#endif 26739217Sgibbsstatic void adv_get_q_info(struct adv_softc *adv, u_int16_t s_addr, 26839217Sgibbs u_int16_t *inbuf, int words); 26939217Sgibbsstatic u_int adv_get_num_free_queues(struct adv_softc *adv, u_int8_t n_qs); 27039217Sgibbsstatic u_int8_t adv_alloc_free_queues(struct adv_softc *adv, 27139217Sgibbs u_int8_t free_q_head, u_int8_t n_free_q); 27239217Sgibbsstatic u_int8_t adv_alloc_free_queue(struct adv_softc *adv, 27339217Sgibbs u_int8_t free_q_head); 27439217Sgibbsstatic int adv_send_scsi_queue(struct adv_softc *adv, 27539217Sgibbs struct adv_scsi_q *scsiq, 27639217Sgibbs u_int8_t n_q_required); 27739217Sgibbsstatic void adv_put_ready_sg_list_queue(struct adv_softc *adv, 27839217Sgibbs struct adv_scsi_q *scsiq, 27939217Sgibbs u_int q_no); 28039217Sgibbsstatic void adv_put_ready_queue(struct adv_softc *adv, 28139217Sgibbs struct adv_scsi_q *scsiq, u_int q_no); 28239217Sgibbsstatic void adv_put_scsiq(struct adv_softc *adv, u_int16_t s_addr, 28339217Sgibbs u_int16_t *buffer, int words); 28418781Sgibbs 28539217Sgibbs/* Messages */ 28639217Sgibbsstatic void adv_handle_extmsg_in(struct adv_softc *adv, 28739217Sgibbs u_int16_t halt_q_addr, u_int8_t q_cntl, 28839217Sgibbs target_bit_vector target_id, 28939217Sgibbs int tid); 29039217Sgibbsstatic void adv_msgout_sdtr(struct adv_softc *adv, u_int8_t sdtr_period, 29139217Sgibbs u_int8_t sdtr_offset); 29239217Sgibbsstatic void adv_set_sdtr_reg_at_id(struct adv_softc *adv, int id, 29339217Sgibbs u_int8_t sdtr_data); 29418781Sgibbs 29518781Sgibbs 29619426Sgibbs/* Exported functions first */ 29718781Sgibbs 29839217Sgibbsvoid 29939217Sgibbsadvasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg) 30039217Sgibbs{ 30118781Sgibbs struct adv_softc *adv; 30239217Sgibbs 30339217Sgibbs adv = (struct adv_softc *)callback_arg; 304251164Sscottl mtx_assert(&adv->lock, MA_OWNED); 30539217Sgibbs switch (code) { 30639217Sgibbs case AC_FOUND_DEVICE: 30739217Sgibbs { 30839217Sgibbs struct ccb_getdev *cgd; 30939217Sgibbs target_bit_vector target_mask; 31039217Sgibbs int num_entries; 31139217Sgibbs caddr_t match; 31239217Sgibbs struct adv_quirk_entry *entry; 31339217Sgibbs struct adv_target_transinfo* tinfo; 31439217Sgibbs 31539217Sgibbs cgd = (struct ccb_getdev *)arg; 31639217Sgibbs 31739217Sgibbs target_mask = ADV_TID_TO_TARGET_MASK(cgd->ccb_h.target_id); 31839217Sgibbs 31939217Sgibbs num_entries = sizeof(adv_quirk_table)/sizeof(*adv_quirk_table); 32039217Sgibbs match = cam_quirkmatch((caddr_t)&cgd->inq_data, 32139217Sgibbs (caddr_t)adv_quirk_table, 32239217Sgibbs num_entries, sizeof(*adv_quirk_table), 32339217Sgibbs scsi_inquiry_match); 32439217Sgibbs 32539217Sgibbs if (match == NULL) 32639217Sgibbs panic("advasync: device didn't match wildcard entry!!"); 32739217Sgibbs 32839217Sgibbs entry = (struct adv_quirk_entry *)match; 32939217Sgibbs 33039217Sgibbs if (adv->bug_fix_control & ADV_BUG_FIX_ASYN_USE_SYN) { 33139217Sgibbs if ((entry->quirks & ADV_QUIRK_FIX_ASYN_XFER_ALWAYS)!=0) 33239217Sgibbs adv->fix_asyn_xfer_always |= target_mask; 33339217Sgibbs else 33439217Sgibbs adv->fix_asyn_xfer_always &= ~target_mask; 33539217Sgibbs /* 33639217Sgibbs * We start out life with all bits set and clear them 33739217Sgibbs * after we've determined that the fix isn't necessary. 33839217Sgibbs * It may well be that we've already cleared a target 33939217Sgibbs * before the full inquiry session completes, so don't 34039217Sgibbs * gratuitously set a target bit even if it has this 34139217Sgibbs * quirk. But, if the quirk exonerates a device, clear 34239217Sgibbs * the bit now. 34339217Sgibbs */ 34439217Sgibbs if ((entry->quirks & ADV_QUIRK_FIX_ASYN_XFER) == 0) 34539217Sgibbs adv->fix_asyn_xfer &= ~target_mask; 34639217Sgibbs } 34739217Sgibbs /* 34839217Sgibbs * Reset our sync settings now that we've determined 34939217Sgibbs * what quirks are in effect for the device. 35039217Sgibbs */ 35139217Sgibbs tinfo = &adv->tinfo[cgd->ccb_h.target_id]; 35239217Sgibbs adv_set_syncrate(adv, cgd->ccb_h.path, 35339217Sgibbs cgd->ccb_h.target_id, 35439217Sgibbs tinfo->current.period, 35539217Sgibbs tinfo->current.offset, 35639217Sgibbs ADV_TRANS_CUR); 35739217Sgibbs break; 35839217Sgibbs } 35939217Sgibbs case AC_LOST_DEVICE: 36039217Sgibbs { 36139217Sgibbs u_int target_mask; 36239217Sgibbs 36339217Sgibbs if (adv->bug_fix_control & ADV_BUG_FIX_ASYN_USE_SYN) { 36439217Sgibbs target_mask = 0x01 << xpt_path_target_id(path); 36539217Sgibbs adv->fix_asyn_xfer |= target_mask; 36639217Sgibbs } 36739217Sgibbs 36839217Sgibbs /* 36939217Sgibbs * Revert to async transfers 37039217Sgibbs * for the next device. 37139217Sgibbs */ 37239217Sgibbs adv_set_syncrate(adv, /*path*/NULL, 37339217Sgibbs xpt_path_target_id(path), 37439217Sgibbs /*period*/0, 37539217Sgibbs /*offset*/0, 37639217Sgibbs ADV_TRANS_GOAL|ADV_TRANS_CUR); 37739217Sgibbs } 37839217Sgibbs default: 37939217Sgibbs break; 38039217Sgibbs } 38139217Sgibbs} 38239217Sgibbs 38339217Sgibbsvoid 38439217Sgibbsadv_set_bank(struct adv_softc *adv, u_int8_t bank) 38518781Sgibbs{ 38639217Sgibbs u_int8_t control; 38739217Sgibbs 38839217Sgibbs /* 38939217Sgibbs * Start out with the bank reset to 0 39039217Sgibbs */ 39139217Sgibbs control = ADV_INB(adv, ADV_CHIP_CTRL) 39239217Sgibbs & (~(ADV_CC_SINGLE_STEP | ADV_CC_TEST 39339217Sgibbs | ADV_CC_DIAG | ADV_CC_SCSI_RESET 39439217Sgibbs | ADV_CC_CHIP_RESET | ADV_CC_BANK_ONE)); 39539217Sgibbs if (bank == 1) { 39639217Sgibbs control |= ADV_CC_BANK_ONE; 39739217Sgibbs } else if (bank == 2) { 39839217Sgibbs control |= ADV_CC_DIAG | ADV_CC_BANK_ONE; 39939217Sgibbs } 40039217Sgibbs ADV_OUTB(adv, ADV_CHIP_CTRL, control); 40139217Sgibbs} 40239217Sgibbs 40339217Sgibbsu_int8_t 40439217Sgibbsadv_read_lram_8(struct adv_softc *adv, u_int16_t addr) 40539217Sgibbs{ 40618781Sgibbs u_int8_t byte_data; 40718781Sgibbs u_int16_t word_data; 40818781Sgibbs 40918781Sgibbs /* 41018781Sgibbs * LRAM is accessed on 16bit boundaries. 41118781Sgibbs */ 41218781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, addr & 0xFFFE); 41318781Sgibbs word_data = ADV_INW(adv, ADV_LRAM_DATA); 41418781Sgibbs if (addr & 1) { 41518781Sgibbs#if BYTE_ORDER == BIG_ENDIAN 41618781Sgibbs byte_data = (u_int8_t)(word_data & 0xFF); 41718781Sgibbs#else 41818781Sgibbs byte_data = (u_int8_t)((word_data >> 8) & 0xFF); 41918781Sgibbs#endif 42018781Sgibbs } else { 42118781Sgibbs#if BYTE_ORDER == BIG_ENDIAN 42218781Sgibbs byte_data = (u_int8_t)((word_data >> 8) & 0xFF); 42318781Sgibbs#else 42418781Sgibbs byte_data = (u_int8_t)(word_data & 0xFF); 42518781Sgibbs#endif 42618781Sgibbs } 42718781Sgibbs return (byte_data); 42818781Sgibbs} 42918781Sgibbs 43018781Sgibbsvoid 43139217Sgibbsadv_write_lram_8(struct adv_softc *adv, u_int16_t addr, u_int8_t value) 43218781Sgibbs{ 43318781Sgibbs u_int16_t word_data; 43418781Sgibbs 43518781Sgibbs word_data = adv_read_lram_16(adv, addr & 0xFFFE); 43618781Sgibbs if (addr & 1) { 43718781Sgibbs word_data &= 0x00FF; 43818781Sgibbs word_data |= (((u_int8_t)value << 8) & 0xFF00); 43918781Sgibbs } else { 44018781Sgibbs word_data &= 0xFF00; 44118781Sgibbs word_data |= ((u_int8_t)value & 0x00FF); 44218781Sgibbs } 44318781Sgibbs adv_write_lram_16(adv, addr & 0xFFFE, word_data); 44418781Sgibbs} 44518781Sgibbs 44618781Sgibbs 44718781Sgibbsu_int16_t 44839217Sgibbsadv_read_lram_16(struct adv_softc *adv, u_int16_t addr) 44918781Sgibbs{ 45018781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, addr); 45118781Sgibbs return (ADV_INW(adv, ADV_LRAM_DATA)); 45218781Sgibbs} 45318781Sgibbs 45418781Sgibbsvoid 45539217Sgibbsadv_write_lram_16(struct adv_softc *adv, u_int16_t addr, u_int16_t value) 45618781Sgibbs{ 45718781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, addr); 45818781Sgibbs ADV_OUTW(adv, ADV_LRAM_DATA, value); 45918781Sgibbs} 46018781Sgibbs 46118781Sgibbs/* 46239217Sgibbs * Determine if there is a board at "iobase" by looking 46339217Sgibbs * for the AdvanSys signatures. Return 1 if a board is 46439217Sgibbs * found, 0 otherwise. 46518781Sgibbs */ 46639217Sgibbsint 467251164Sscottladv_find_signature(struct resource *res) 46839217Sgibbs{ 46939217Sgibbs u_int16_t signature; 47039217Sgibbs 471251164Sscottl if (bus_read_1(res, ADV_SIGNATURE_BYTE) == ADV_1000_ID1B) { 472251164Sscottl signature = bus_read_2(res, ADV_SIGNATURE_WORD); 47339217Sgibbs if ((signature == ADV_1000_ID0W) 47439217Sgibbs || (signature == ADV_1000_ID0W_FIX)) 47539217Sgibbs return (1); 47639217Sgibbs } 47739217Sgibbs return (0); 47839217Sgibbs} 47939217Sgibbs 48018781Sgibbsvoid 48139217Sgibbsadv_lib_init(struct adv_softc *adv) 48218781Sgibbs{ 48339217Sgibbs if ((adv->type & ADV_ULTRA) != 0) { 48439217Sgibbs adv->sdtr_period_tbl = adv_sdtr_period_tbl_ultra; 48539217Sgibbs adv->sdtr_period_tbl_size = sizeof(adv_sdtr_period_tbl_ultra); 48639217Sgibbs } else { 48739217Sgibbs adv->sdtr_period_tbl = adv_sdtr_period_tbl; 48839217Sgibbs adv->sdtr_period_tbl_size = sizeof(adv_sdtr_period_tbl); 48939217Sgibbs } 49018781Sgibbs} 49118781Sgibbs 49218781Sgibbsu_int16_t 49339217Sgibbsadv_get_eeprom_config(struct adv_softc *adv, struct 49439217Sgibbs adv_eeprom_config *eeprom_config) 49518781Sgibbs{ 49618781Sgibbs u_int16_t sum; 49718781Sgibbs u_int16_t *wbuf; 49818781Sgibbs u_int8_t cfg_beg; 49918781Sgibbs u_int8_t cfg_end; 50018781Sgibbs u_int8_t s_addr; 50118781Sgibbs 50218781Sgibbs wbuf = (u_int16_t *)eeprom_config; 50318781Sgibbs sum = 0; 50418781Sgibbs 50518781Sgibbs for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) { 50618781Sgibbs *wbuf = adv_read_eeprom_16(adv, s_addr); 50718781Sgibbs sum += *wbuf; 50818781Sgibbs } 50918781Sgibbs 51018781Sgibbs if (adv->type & ADV_VL) { 51118781Sgibbs cfg_beg = ADV_EEPROM_CFG_BEG_VL; 51218781Sgibbs cfg_end = ADV_EEPROM_MAX_ADDR_VL; 51318781Sgibbs } else { 51418781Sgibbs cfg_beg = ADV_EEPROM_CFG_BEG; 51518781Sgibbs cfg_end = ADV_EEPROM_MAX_ADDR; 51618781Sgibbs } 51718781Sgibbs 51818781Sgibbs for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) { 51918781Sgibbs *wbuf = adv_read_eeprom_16(adv, s_addr); 52018781Sgibbs sum += *wbuf; 521153072Sru#ifdef ADV_DEBUG_EEPROM 52218781Sgibbs printf("Addr 0x%x: 0x%04x\n", s_addr, *wbuf); 52318781Sgibbs#endif 52418781Sgibbs } 52518781Sgibbs *wbuf = adv_read_eeprom_16(adv, s_addr); 52618781Sgibbs return (sum); 52718781Sgibbs} 52818781Sgibbs 52918781Sgibbsint 53039217Sgibbsadv_set_eeprom_config(struct adv_softc *adv, 53139217Sgibbs struct adv_eeprom_config *eeprom_config) 53218781Sgibbs{ 53318781Sgibbs int retry; 53418781Sgibbs 53518781Sgibbs retry = 0; 53618781Sgibbs while (1) { 53718781Sgibbs if (adv_set_eeprom_config_once(adv, eeprom_config) == 0) { 53818781Sgibbs break; 53918781Sgibbs } 54018781Sgibbs if (++retry > ADV_EEPROM_MAX_RETRY) { 54118781Sgibbs break; 54218781Sgibbs } 54318781Sgibbs } 54418781Sgibbs return (retry > ADV_EEPROM_MAX_RETRY); 54518781Sgibbs} 54618781Sgibbs 54718781Sgibbsint 54855945Sgibbsadv_reset_chip(struct adv_softc *adv, int reset_bus) 54918781Sgibbs{ 55018781Sgibbs adv_stop_chip(adv); 55155945Sgibbs ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_CHIP_RESET | ADV_CC_HALT 55255945Sgibbs | (reset_bus ? ADV_CC_SCSI_RESET : 0)); 55355945Sgibbs DELAY(60); 55418781Sgibbs 55518781Sgibbs adv_set_chip_ih(adv, ADV_INS_RFLAG_WTM); 55618781Sgibbs adv_set_chip_ih(adv, ADV_INS_HALT); 55718781Sgibbs 55855945Sgibbs if (reset_bus) 55955945Sgibbs ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_CHIP_RESET | ADV_CC_HALT); 56055945Sgibbs 56118781Sgibbs ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_HALT); 56255945Sgibbs if (reset_bus) 56355945Sgibbs DELAY(200 * 1000); 56455945Sgibbs 56555945Sgibbs ADV_OUTW(adv, ADV_CHIP_STATUS, ADV_CIW_CLR_SCSI_RESET_INT); 56655945Sgibbs ADV_OUTW(adv, ADV_CHIP_STATUS, 0); 56718781Sgibbs return (adv_is_chip_halted(adv)); 56818781Sgibbs} 56918781Sgibbs 57018781Sgibbsint 57139217Sgibbsadv_test_external_lram(struct adv_softc* adv) 57218781Sgibbs{ 57318781Sgibbs u_int16_t q_addr; 57418781Sgibbs u_int16_t saved_value; 57518781Sgibbs int success; 57618781Sgibbs 57718781Sgibbs success = 0; 57818781Sgibbs 57918781Sgibbs q_addr = ADV_QNO_TO_QADDR(241); 58018781Sgibbs saved_value = adv_read_lram_16(adv, q_addr); 58118781Sgibbs if (adv_write_and_verify_lram_16(adv, q_addr, 0x55AA) == 0) { 58218781Sgibbs success = 1; 58318781Sgibbs adv_write_lram_16(adv, q_addr, saved_value); 58418781Sgibbs } 58518781Sgibbs return (success); 58618781Sgibbs} 58718781Sgibbs 58818781Sgibbs 58918781Sgibbsint 59039217Sgibbsadv_init_lram_and_mcode(struct adv_softc *adv) 59118781Sgibbs{ 59218781Sgibbs u_int32_t retval; 59339217Sgibbs 59418781Sgibbs adv_disable_interrupt(adv); 59518781Sgibbs 59618781Sgibbs adv_init_lram(adv); 59718781Sgibbs 59839217Sgibbs retval = adv_load_microcode(adv, 0, (u_int16_t *)adv_mcode, 59939217Sgibbs adv_mcode_size); 60018781Sgibbs if (retval != adv_mcode_chksum) { 601251164Sscottl device_printf(adv->dev, 602251164Sscottl "Microcode download failed checksum!\n"); 60318781Sgibbs return (1); 60418781Sgibbs } 60518781Sgibbs 60618781Sgibbs if (adv_init_microcode_var(adv) != 0) 60718781Sgibbs return (1); 60818781Sgibbs 60918781Sgibbs adv_enable_interrupt(adv); 61018781Sgibbs return (0); 61118781Sgibbs} 61218781Sgibbs 61318781Sgibbsu_int8_t 61439217Sgibbsadv_get_chip_irq(struct adv_softc *adv) 61518781Sgibbs{ 61618781Sgibbs u_int16_t cfg_lsw; 61718781Sgibbs u_int8_t chip_irq; 61818781Sgibbs 61918781Sgibbs cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW); 62018781Sgibbs 62118781Sgibbs if ((adv->type & ADV_VL) != 0) { 62218781Sgibbs chip_irq = (u_int8_t)(((cfg_lsw >> 2) & 0x07)); 62318781Sgibbs if ((chip_irq == 0) || 62418781Sgibbs (chip_irq == 4) || 62518781Sgibbs (chip_irq == 7)) { 62618781Sgibbs return (0); 62718781Sgibbs } 62818781Sgibbs return (chip_irq + (ADV_MIN_IRQ_NO - 1)); 62918781Sgibbs } 63018781Sgibbs chip_irq = (u_int8_t)(((cfg_lsw >> 2) & 0x03)); 63118781Sgibbs if (chip_irq == 3) 63218781Sgibbs chip_irq += 2; 63318781Sgibbs return (chip_irq + ADV_MIN_IRQ_NO); 63418781Sgibbs} 63518781Sgibbs 63618781Sgibbsu_int8_t 63739217Sgibbsadv_set_chip_irq(struct adv_softc *adv, u_int8_t irq_no) 63818781Sgibbs{ 63918781Sgibbs u_int16_t cfg_lsw; 64018781Sgibbs 64118781Sgibbs if ((adv->type & ADV_VL) != 0) { 64218781Sgibbs if (irq_no != 0) { 64339217Sgibbs if ((irq_no < ADV_MIN_IRQ_NO) 64439217Sgibbs || (irq_no > ADV_MAX_IRQ_NO)) { 64518781Sgibbs irq_no = 0; 64618781Sgibbs } else { 64718781Sgibbs irq_no -= ADV_MIN_IRQ_NO - 1; 64818781Sgibbs } 64918781Sgibbs } 65018781Sgibbs cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW) & 0xFFE3; 65118781Sgibbs cfg_lsw |= 0x0010; 65218781Sgibbs ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw); 65318781Sgibbs adv_toggle_irq_act(adv); 65418781Sgibbs 65518781Sgibbs cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW) & 0xFFE0; 65618781Sgibbs cfg_lsw |= (irq_no & 0x07) << 2; 65718781Sgibbs ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw); 65818781Sgibbs adv_toggle_irq_act(adv); 65918781Sgibbs } else if ((adv->type & ADV_ISA) != 0) { 66018781Sgibbs if (irq_no == 15) 66118781Sgibbs irq_no -= 2; 66218781Sgibbs irq_no -= ADV_MIN_IRQ_NO; 66318781Sgibbs cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW) & 0xFFF3; 66418781Sgibbs cfg_lsw |= (irq_no & 0x03) << 2; 66518781Sgibbs ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw); 66618781Sgibbs } 66718781Sgibbs return (adv_get_chip_irq(adv)); 66818781Sgibbs} 66918781Sgibbs 67039217Sgibbsvoid 67139217Sgibbsadv_set_chip_scsiid(struct adv_softc *adv, int new_id) 67239217Sgibbs{ 67339217Sgibbs u_int16_t cfg_lsw; 67439217Sgibbs 67539217Sgibbs cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW); 67639217Sgibbs if (ADV_CONFIG_SCSIID(cfg_lsw) == new_id) 67739217Sgibbs return; 67839217Sgibbs cfg_lsw &= ~ADV_CFG_LSW_SCSIID; 67939217Sgibbs cfg_lsw |= (new_id & ADV_MAX_TID) << ADV_CFG_LSW_SCSIID_SHIFT; 68039217Sgibbs ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw); 68139217Sgibbs} 68239217Sgibbs 68318781Sgibbsint 68439217Sgibbsadv_execute_scsi_queue(struct adv_softc *adv, struct adv_scsi_q *scsiq, 68539217Sgibbs u_int32_t datalen) 68618781Sgibbs{ 68739217Sgibbs struct adv_target_transinfo* tinfo; 68839217Sgibbs u_int32_t *p_data_addr; 68939217Sgibbs u_int32_t *p_data_bcount; 69039217Sgibbs int disable_syn_offset_one_fix; 69118781Sgibbs int retval; 69218781Sgibbs u_int n_q_required; 69318781Sgibbs u_int32_t addr; 69418781Sgibbs u_int8_t sg_entry_cnt; 69518781Sgibbs u_int8_t target_ix; 69618781Sgibbs u_int8_t sg_entry_cnt_minus_one; 69718781Sgibbs u_int8_t tid_no; 69818781Sgibbs 699251164Sscottl if (!dumping) 700251164Sscottl mtx_assert(&adv->lock, MA_OWNED); 70118781Sgibbs scsiq->q1.q_no = 0; 70218781Sgibbs retval = 1; /* Default to error case */ 70318781Sgibbs target_ix = scsiq->q2.target_ix; 70418781Sgibbs tid_no = ADV_TIX_TO_TID(target_ix); 70539217Sgibbs tinfo = &adv->tinfo[tid_no]; 70618781Sgibbs 70739217Sgibbs if (scsiq->cdbptr[0] == REQUEST_SENSE) { 70839217Sgibbs /* Renegotiate if appropriate. */ 70939217Sgibbs adv_set_syncrate(adv, /*struct cam_path */NULL, 71039217Sgibbs tid_no, /*period*/0, /*offset*/0, 71139217Sgibbs ADV_TRANS_CUR); 71239217Sgibbs if (tinfo->current.period != tinfo->goal.period) { 71339217Sgibbs adv_msgout_sdtr(adv, tinfo->goal.period, 71439217Sgibbs tinfo->goal.offset); 71518781Sgibbs scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT); 71618781Sgibbs } 71718781Sgibbs } 71818781Sgibbs 71918781Sgibbs if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) { 72018781Sgibbs sg_entry_cnt = scsiq->sg_head->entry_cnt; 72118781Sgibbs sg_entry_cnt_minus_one = sg_entry_cnt - 1; 72218781Sgibbs 72318781Sgibbs#ifdef DIAGNOSTIC 72418781Sgibbs if (sg_entry_cnt <= 1) 72539217Sgibbs panic("adv_execute_scsi_queue: Queue " 72639217Sgibbs "with QC_SG_HEAD set but %d segs.", sg_entry_cnt); 72718781Sgibbs 72818781Sgibbs if (sg_entry_cnt > ADV_MAX_SG_LIST) 72939217Sgibbs panic("adv_execute_scsi_queue: " 73039217Sgibbs "Queue with too many segs."); 73118781Sgibbs 73255945Sgibbs if ((adv->type & (ADV_ISA | ADV_VL | ADV_EISA)) != 0) { 73339505Sgibbs int i; 73439505Sgibbs 73518781Sgibbs for (i = 0; i < sg_entry_cnt_minus_one; i++) { 73618781Sgibbs addr = scsiq->sg_head->sg_list[i].addr + 73718781Sgibbs scsiq->sg_head->sg_list[i].bytes; 73818781Sgibbs 73918781Sgibbs if ((addr & 0x0003) != 0) 74039217Sgibbs panic("adv_execute_scsi_queue: SG " 74139217Sgibbs "with odd address or byte count"); 74218781Sgibbs } 74318781Sgibbs } 74418781Sgibbs#endif 74539217Sgibbs p_data_addr = 74639217Sgibbs &scsiq->sg_head->sg_list[sg_entry_cnt_minus_one].addr; 74739217Sgibbs p_data_bcount = 74839217Sgibbs &scsiq->sg_head->sg_list[sg_entry_cnt_minus_one].bytes; 74918781Sgibbs 75018781Sgibbs n_q_required = adv_sgcount_to_qcount(sg_entry_cnt); 75118781Sgibbs scsiq->sg_head->queue_cnt = n_q_required - 1; 75218781Sgibbs } else { 75318781Sgibbs p_data_addr = &scsiq->q1.data_addr; 75418781Sgibbs p_data_bcount = &scsiq->q1.data_cnt; 75518781Sgibbs n_q_required = 1; 75618781Sgibbs } 75718781Sgibbs 75839217Sgibbs disable_syn_offset_one_fix = FALSE; 75939217Sgibbs 76039217Sgibbs if ((adv->fix_asyn_xfer & scsiq->q1.target_id) != 0 76139217Sgibbs && (adv->fix_asyn_xfer_always & scsiq->q1.target_id) == 0) { 76239217Sgibbs 76339217Sgibbs if (datalen != 0) { 76439217Sgibbs if (datalen < 512) { 76539217Sgibbs disable_syn_offset_one_fix = TRUE; 76639217Sgibbs } else { 76739217Sgibbs if (scsiq->cdbptr[0] == INQUIRY 76839217Sgibbs || scsiq->cdbptr[0] == REQUEST_SENSE 76939217Sgibbs || scsiq->cdbptr[0] == READ_CAPACITY 77039217Sgibbs || scsiq->cdbptr[0] == MODE_SELECT_6 77139217Sgibbs || scsiq->cdbptr[0] == MODE_SENSE_6 77239217Sgibbs || scsiq->cdbptr[0] == MODE_SENSE_10 77339217Sgibbs || scsiq->cdbptr[0] == MODE_SELECT_10 77439217Sgibbs || scsiq->cdbptr[0] == READ_TOC) { 77539217Sgibbs disable_syn_offset_one_fix = TRUE; 77618781Sgibbs } 77718781Sgibbs } 77818781Sgibbs } 77918781Sgibbs } 78039217Sgibbs 78139217Sgibbs if (disable_syn_offset_one_fix) { 78239217Sgibbs scsiq->q2.tag_code &= 78339217Sgibbs ~(MSG_SIMPLE_Q_TAG|MSG_HEAD_OF_Q_TAG|MSG_ORDERED_Q_TAG); 78439217Sgibbs scsiq->q2.tag_code |= (ADV_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX 78539217Sgibbs | ADV_TAG_FLAG_DISABLE_DISCONNECT); 78639217Sgibbs } 78739217Sgibbs 78839217Sgibbs if ((adv->bug_fix_control & ADV_BUG_FIX_IF_NOT_DWB) != 0 78939217Sgibbs && (scsiq->cdbptr[0] == READ_10 || scsiq->cdbptr[0] == READ_6)) { 79039217Sgibbs u_int8_t extra_bytes; 79139217Sgibbs 79239217Sgibbs addr = *p_data_addr + *p_data_bcount; 79339217Sgibbs extra_bytes = addr & 0x0003; 79439217Sgibbs if (extra_bytes != 0 79539217Sgibbs && ((scsiq->q1.cntl & QC_SG_HEAD) != 0 79639217Sgibbs || (scsiq->q1.data_cnt & 0x01FF) == 0)) { 79739217Sgibbs scsiq->q2.tag_code |= ADV_TAG_FLAG_EXTRA_BYTES; 79839217Sgibbs scsiq->q1.extra_bytes = extra_bytes; 79939217Sgibbs *p_data_bcount -= extra_bytes; 80039217Sgibbs } 80139217Sgibbs } 80239217Sgibbs 80318781Sgibbs if ((adv_get_num_free_queues(adv, n_q_required) >= n_q_required) 80439217Sgibbs || ((scsiq->q1.cntl & QC_URGENT) != 0)) 80518781Sgibbs retval = adv_send_scsi_queue(adv, scsiq, n_q_required); 80618781Sgibbs 80718781Sgibbs return (retval); 80818781Sgibbs} 80918781Sgibbs 81018781Sgibbs 81118781Sgibbsu_int8_t 81239217Sgibbsadv_copy_lram_doneq(struct adv_softc *adv, u_int16_t q_addr, 81339217Sgibbs struct adv_q_done_info *scsiq, u_int32_t max_dma_count) 81418781Sgibbs{ 81539217Sgibbs u_int16_t val; 81639217Sgibbs u_int8_t sg_queue_cnt; 81718781Sgibbs 81818781Sgibbs adv_get_q_info(adv, q_addr + ADV_SCSIQ_DONE_INFO_BEG, 81918781Sgibbs (u_int16_t *)scsiq, 82018781Sgibbs (sizeof(scsiq->d2) + sizeof(scsiq->d3)) / 2); 82118781Sgibbs 82218781Sgibbs#if BYTE_ORDER == BIG_ENDIAN 82318781Sgibbs adv_adj_endian_qdone_info(scsiq); 82418781Sgibbs#endif 82518781Sgibbs 82618781Sgibbs val = adv_read_lram_16(adv, q_addr + ADV_SCSIQ_B_STATUS); 82718781Sgibbs scsiq->q_status = val & 0xFF; 82818781Sgibbs scsiq->q_no = (val >> 8) & 0XFF; 82918781Sgibbs 83018781Sgibbs val = adv_read_lram_16(adv, q_addr + ADV_SCSIQ_B_CNTL); 83118781Sgibbs scsiq->cntl = val & 0xFF; 83218781Sgibbs sg_queue_cnt = (val >> 8) & 0xFF; 83318781Sgibbs 83418781Sgibbs val = adv_read_lram_16(adv,q_addr + ADV_SCSIQ_B_SENSE_LEN); 83518781Sgibbs scsiq->sense_len = val & 0xFF; 83639217Sgibbs scsiq->extra_bytes = (val >> 8) & 0xFF; 83718781Sgibbs 83840133Sgibbs /* 83955945Sgibbs * Due to a bug in accessing LRAM on the 940UA, the residual 84055945Sgibbs * is split into separate high and low 16bit quantities. 84140133Sgibbs */ 84239217Sgibbs scsiq->remain_bytes = 84340133Sgibbs adv_read_lram_16(adv, q_addr + ADV_SCSIQ_DW_REMAIN_XFER_CNT); 84455945Sgibbs scsiq->remain_bytes |= 84555945Sgibbs adv_read_lram_16(adv, q_addr + ADV_SCSIQ_W_ALT_DC1) << 16; 84655945Sgibbs 84718781Sgibbs /* 84818781Sgibbs * XXX Is this just a safeguard or will the counter really 84918781Sgibbs * have bogus upper bits? 85018781Sgibbs */ 85118781Sgibbs scsiq->remain_bytes &= max_dma_count; 85218781Sgibbs 85318781Sgibbs return (sg_queue_cnt); 85418781Sgibbs} 85518781Sgibbs 85618781Sgibbsint 85739217Sgibbsadv_start_chip(struct adv_softc *adv) 85818781Sgibbs{ 85939217Sgibbs ADV_OUTB(adv, ADV_CHIP_CTRL, 0); 86039217Sgibbs if ((ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_HALTED) != 0) 86139217Sgibbs return (0); 86239217Sgibbs return (1); 86339217Sgibbs} 86439217Sgibbs 86539217Sgibbsint 86639217Sgibbsadv_stop_execution(struct adv_softc *adv) 86739217Sgibbs{ 86818781Sgibbs int count; 86918781Sgibbs 87018781Sgibbs count = 0; 87118781Sgibbs if (adv_read_lram_8(adv, ADV_STOP_CODE_B) == 0) { 87218781Sgibbs adv_write_lram_8(adv, ADV_STOP_CODE_B, 87318781Sgibbs ADV_STOP_REQ_RISC_STOP); 87418781Sgibbs do { 87518781Sgibbs if (adv_read_lram_8(adv, ADV_STOP_CODE_B) & 87618781Sgibbs ADV_STOP_ACK_RISC_STOP) { 87718781Sgibbs return (1); 87818781Sgibbs } 87918781Sgibbs DELAY(1000); 88018781Sgibbs } while (count++ < 20); 88118781Sgibbs } 88218781Sgibbs return (0); 88318781Sgibbs} 88418781Sgibbs 88518781Sgibbsint 88639217Sgibbsadv_is_chip_halted(struct adv_softc *adv) 88718781Sgibbs{ 88818781Sgibbs if ((ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_HALTED) != 0) { 88918781Sgibbs if ((ADV_INB(adv, ADV_CHIP_CTRL) & ADV_CC_HALT) != 0) { 89018781Sgibbs return (1); 89118781Sgibbs } 89218781Sgibbs } 89318781Sgibbs return (0); 89418781Sgibbs} 89518781Sgibbs 89618781Sgibbs/* 89718781Sgibbs * XXX The numeric constants and the loops in this routine 89818781Sgibbs * need to be documented. 89918781Sgibbs */ 90018781Sgibbsvoid 90139217Sgibbsadv_ack_interrupt(struct adv_softc *adv) 90218781Sgibbs{ 90318781Sgibbs u_int8_t host_flag; 90418781Sgibbs u_int8_t risc_flag; 90518781Sgibbs int loop; 90618781Sgibbs 90718781Sgibbs loop = 0; 90818781Sgibbs do { 90918781Sgibbs risc_flag = adv_read_lram_8(adv, ADVV_RISC_FLAG_B); 91018781Sgibbs if (loop++ > 0x7FFF) { 91118781Sgibbs break; 91218781Sgibbs } 91318781Sgibbs } while ((risc_flag & ADV_RISC_FLAG_GEN_INT) != 0); 91418781Sgibbs 91518781Sgibbs host_flag = adv_read_lram_8(adv, ADVV_HOST_FLAG_B); 91618781Sgibbs adv_write_lram_8(adv, ADVV_HOST_FLAG_B, 91718781Sgibbs host_flag | ADV_HOST_FLAG_ACK_INT); 91818781Sgibbs 91918781Sgibbs ADV_OUTW(adv, ADV_CHIP_STATUS, ADV_CIW_INT_ACK); 92018781Sgibbs loop = 0; 92118781Sgibbs while (ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_INT_PENDING) { 92218781Sgibbs ADV_OUTW(adv, ADV_CHIP_STATUS, ADV_CIW_INT_ACK); 92318781Sgibbs if (loop++ > 3) { 92418781Sgibbs break; 92518781Sgibbs } 92618781Sgibbs } 92718781Sgibbs 92818781Sgibbs adv_write_lram_8(adv, ADVV_HOST_FLAG_B, host_flag); 92918781Sgibbs} 93018781Sgibbs 93118781Sgibbs/* 93218781Sgibbs * Handle all conditions that may halt the chip waiting 93318781Sgibbs * for us to intervene. 93418781Sgibbs */ 93518781Sgibbsvoid 93639217Sgibbsadv_isr_chip_halted(struct adv_softc *adv) 93718781Sgibbs{ 93818781Sgibbs u_int16_t int_halt_code; 93939217Sgibbs u_int16_t halt_q_addr; 94039217Sgibbs target_bit_vector target_mask; 94139217Sgibbs target_bit_vector scsi_busy; 94218781Sgibbs u_int8_t halt_qp; 94318781Sgibbs u_int8_t target_ix; 94418781Sgibbs u_int8_t q_cntl; 94518781Sgibbs u_int8_t tid_no; 94618781Sgibbs 947251164Sscottl if (!dumping) 948251164Sscottl mtx_assert(&adv->lock, MA_OWNED); 94918781Sgibbs int_halt_code = adv_read_lram_16(adv, ADVV_HALTCODE_W); 95018781Sgibbs halt_qp = adv_read_lram_8(adv, ADVV_CURCDB_B); 95118781Sgibbs halt_q_addr = ADV_QNO_TO_QADDR(halt_qp); 95218781Sgibbs target_ix = adv_read_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_TARGET_IX); 95318781Sgibbs q_cntl = adv_read_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_CNTL); 95418781Sgibbs tid_no = ADV_TIX_TO_TID(target_ix); 95539217Sgibbs target_mask = ADV_TID_TO_TARGET_MASK(tid_no); 95639217Sgibbs if (int_halt_code == ADV_HALT_DISABLE_ASYN_USE_SYN_FIX) { 95718781Sgibbs /* 95839217Sgibbs * Temporarily disable the async fix by removing 95939217Sgibbs * this target from the list of affected targets, 96039217Sgibbs * setting our async rate, and then putting us 96139217Sgibbs * back into the mask. 96218781Sgibbs */ 96339217Sgibbs adv->fix_asyn_xfer &= ~target_mask; 96439217Sgibbs adv_set_syncrate(adv, /*struct cam_path */NULL, 96539217Sgibbs tid_no, /*period*/0, /*offset*/0, 96639217Sgibbs ADV_TRANS_ACTIVE); 96739217Sgibbs adv->fix_asyn_xfer |= target_mask; 96839217Sgibbs } else if (int_halt_code == ADV_HALT_ENABLE_ASYN_USE_SYN_FIX) { 96939217Sgibbs adv_set_syncrate(adv, /*struct cam_path */NULL, 97039217Sgibbs tid_no, /*period*/0, /*offset*/0, 97139217Sgibbs ADV_TRANS_ACTIVE); 97239217Sgibbs } else if (int_halt_code == ADV_HALT_EXTMSG_IN) { 97339217Sgibbs adv_handle_extmsg_in(adv, halt_q_addr, q_cntl, 97439217Sgibbs target_mask, tid_no); 97518781Sgibbs } else if (int_halt_code == ADV_HALT_CHK_CONDITION) { 97655945Sgibbs struct adv_target_transinfo* tinfo; 977251164Sscottl struct adv_ccb_info *cinfo; 97855945Sgibbs union ccb *ccb; 97955945Sgibbs u_int32_t cinfo_index; 98055945Sgibbs u_int8_t tag_code; 98155945Sgibbs u_int8_t q_status; 98218781Sgibbs 98339217Sgibbs tinfo = &adv->tinfo[tid_no]; 98418781Sgibbs q_cntl |= QC_REQ_SENSE; 98518781Sgibbs 98639217Sgibbs /* Renegotiate if appropriate. */ 98739217Sgibbs adv_set_syncrate(adv, /*struct cam_path */NULL, 98839217Sgibbs tid_no, /*period*/0, /*offset*/0, 98939217Sgibbs ADV_TRANS_CUR); 99039217Sgibbs if (tinfo->current.period != tinfo->goal.period) { 99139217Sgibbs adv_msgout_sdtr(adv, tinfo->goal.period, 99239217Sgibbs tinfo->goal.offset); 99318781Sgibbs q_cntl |= QC_MSG_OUT; 99418781Sgibbs } 99518781Sgibbs adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_CNTL, q_cntl); 99618781Sgibbs 99718781Sgibbs /* Don't tag request sense commands */ 99839217Sgibbs tag_code = adv_read_lram_8(adv, 99939217Sgibbs halt_q_addr + ADV_SCSIQ_B_TAG_CODE); 100039217Sgibbs tag_code &= 100139217Sgibbs ~(MSG_SIMPLE_Q_TAG|MSG_HEAD_OF_Q_TAG|MSG_ORDERED_Q_TAG); 100218781Sgibbs 100339217Sgibbs if ((adv->fix_asyn_xfer & target_mask) != 0 100439217Sgibbs && (adv->fix_asyn_xfer_always & target_mask) == 0) { 100539217Sgibbs tag_code |= (ADV_TAG_FLAG_DISABLE_DISCONNECT 100639217Sgibbs | ADV_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX); 100739217Sgibbs } 100839217Sgibbs adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_TAG_CODE, 100939217Sgibbs tag_code); 101039217Sgibbs q_status = adv_read_lram_8(adv, 101139217Sgibbs halt_q_addr + ADV_SCSIQ_B_STATUS); 101218781Sgibbs q_status |= (QS_READY | QS_BUSY); 101339217Sgibbs adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_STATUS, 101439217Sgibbs q_status); 101539217Sgibbs /* 101639217Sgibbs * Freeze the devq until we can handle the sense condition. 101739217Sgibbs */ 101855945Sgibbs cinfo_index = 101955945Sgibbs adv_read_lram_32(adv, halt_q_addr + ADV_SCSIQ_D_CINFO_IDX); 1020251164Sscottl cinfo = &adv->ccb_infos[cinfo_index]; 102155945Sgibbs ccb = adv->ccb_infos[cinfo_index].ccb; 102239217Sgibbs xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 102339217Sgibbs ccb->ccb_h.status |= CAM_DEV_QFRZN; 102439217Sgibbs adv_abort_ccb(adv, tid_no, ADV_TIX_TO_LUN(target_ix), 102539217Sgibbs /*ccb*/NULL, CAM_REQUEUE_REQ, 102639217Sgibbs /*queued_only*/TRUE); 102718781Sgibbs scsi_busy = adv_read_lram_8(adv, ADVV_SCSIBUSY_B); 102839217Sgibbs scsi_busy &= ~target_mask; 102918781Sgibbs adv_write_lram_8(adv, ADVV_SCSIBUSY_B, scsi_busy); 103045846Sgibbs /* 103145846Sgibbs * Ensure we have enough time to actually 103245846Sgibbs * retrieve the sense. 103345846Sgibbs */ 1034251164Sscottl callout_reset(&cinfo->timer, 5 * hz, adv_timeout, ccb); 103518781Sgibbs } else if (int_halt_code == ADV_HALT_SDTR_REJECTED) { 103639217Sgibbs struct ext_msg out_msg; 103718781Sgibbs 103818781Sgibbs adv_read_lram_16_multi(adv, ADVV_MSGOUT_BEG, 103918781Sgibbs (u_int16_t *) &out_msg, 104018781Sgibbs sizeof(out_msg)/2); 104118781Sgibbs 104239217Sgibbs if ((out_msg.msg_type == MSG_EXTENDED) 104339217Sgibbs && (out_msg.msg_len == MSG_EXT_SDTR_LEN) 104439217Sgibbs && (out_msg.msg_req == MSG_EXT_SDTR)) { 104518781Sgibbs 104639217Sgibbs /* Revert to Async */ 104739217Sgibbs adv_set_syncrate(adv, /*struct cam_path */NULL, 104839217Sgibbs tid_no, /*period*/0, /*offset*/0, 104939217Sgibbs ADV_TRANS_GOAL|ADV_TRANS_ACTIVE); 105018781Sgibbs } 105118781Sgibbs q_cntl &= ~QC_MSG_OUT; 105218781Sgibbs adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_CNTL, q_cntl); 105318781Sgibbs } else if (int_halt_code == ADV_HALT_SS_QUEUE_FULL) { 105439217Sgibbs u_int8_t scsi_status; 105539217Sgibbs union ccb *ccb; 105655945Sgibbs u_int32_t cinfo_index; 105739217Sgibbs 105839217Sgibbs scsi_status = adv_read_lram_8(adv, halt_q_addr 105939217Sgibbs + ADV_SCSIQ_SCSI_STATUS); 106055945Sgibbs cinfo_index = 106155945Sgibbs adv_read_lram_32(adv, halt_q_addr + ADV_SCSIQ_D_CINFO_IDX); 106255945Sgibbs ccb = adv->ccb_infos[cinfo_index].ccb; 106339217Sgibbs xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 106440733Sgibbs ccb->ccb_h.status |= CAM_DEV_QFRZN|CAM_SCSI_STATUS_ERROR; 106540733Sgibbs ccb->csio.scsi_status = SCSI_STATUS_QUEUE_FULL; 106639217Sgibbs adv_abort_ccb(adv, tid_no, ADV_TIX_TO_LUN(target_ix), 106739217Sgibbs /*ccb*/NULL, CAM_REQUEUE_REQ, 106839217Sgibbs /*queued_only*/TRUE); 106939217Sgibbs scsi_busy = adv_read_lram_8(adv, ADVV_SCSIBUSY_B); 107039217Sgibbs scsi_busy &= ~target_mask; 107139217Sgibbs adv_write_lram_8(adv, ADVV_SCSIBUSY_B, scsi_busy); 107255945Sgibbs } else { 107355945Sgibbs printf("Unhandled Halt Code %x\n", int_halt_code); 107439217Sgibbs } 107539217Sgibbs adv_write_lram_16(adv, ADVV_HALTCODE_W, 0); 107639217Sgibbs} 107718781Sgibbs 107839217Sgibbsvoid 107939217Sgibbsadv_sdtr_to_period_offset(struct adv_softc *adv, 108039217Sgibbs u_int8_t sync_data, u_int8_t *period, 108139217Sgibbs u_int8_t *offset, int tid) 108239217Sgibbs{ 108339217Sgibbs if (adv->fix_asyn_xfer & ADV_TID_TO_TARGET_MASK(tid) 108439217Sgibbs && (sync_data == ASYN_SDTR_DATA_FIX_PCI_REV_AB)) { 108539217Sgibbs *period = *offset = 0; 108639217Sgibbs } else { 108739217Sgibbs *period = adv->sdtr_period_tbl[((sync_data >> 4) & 0xF)]; 108839217Sgibbs *offset = sync_data & 0xF; 108939217Sgibbs } 109039217Sgibbs} 109139217Sgibbs 109239217Sgibbsvoid 109339217Sgibbsadv_set_syncrate(struct adv_softc *adv, struct cam_path *path, 109439217Sgibbs u_int tid, u_int period, u_int offset, u_int type) 109539217Sgibbs{ 109639217Sgibbs struct adv_target_transinfo* tinfo; 109739217Sgibbs u_int old_period; 109839217Sgibbs u_int old_offset; 109939217Sgibbs u_int8_t sdtr_data; 110039217Sgibbs 1101251164Sscottl mtx_assert(&adv->lock, MA_OWNED); 110239217Sgibbs tinfo = &adv->tinfo[tid]; 110339217Sgibbs 110439217Sgibbs /* Filter our input */ 110539217Sgibbs sdtr_data = adv_period_offset_to_sdtr(adv, &period, 110639217Sgibbs &offset, tid); 110739217Sgibbs 110839217Sgibbs old_period = tinfo->current.period; 110939217Sgibbs old_offset = tinfo->current.offset; 111039217Sgibbs 111139217Sgibbs if ((type & ADV_TRANS_CUR) != 0 111239217Sgibbs && ((old_period != period || old_offset != offset) 111339217Sgibbs || period == 0 || offset == 0) /*Changes in asyn fix settings*/) { 111439217Sgibbs int halted; 111539217Sgibbs 111639217Sgibbs halted = adv_is_chip_halted(adv); 111739217Sgibbs if (halted == 0) 111839217Sgibbs /* Must halt the chip first */ 111939217Sgibbs adv_host_req_chip_halt(adv); 112039217Sgibbs 112139217Sgibbs /* Update current hardware settings */ 112239217Sgibbs adv_set_sdtr_reg_at_id(adv, tid, sdtr_data); 112339217Sgibbs 112418781Sgibbs /* 112539217Sgibbs * If a target can run in sync mode, we don't need 112639217Sgibbs * to check it for sync problems. 112718781Sgibbs */ 112839217Sgibbs if (offset != 0) 112939217Sgibbs adv->fix_asyn_xfer &= ~ADV_TID_TO_TARGET_MASK(tid); 113018781Sgibbs 113139217Sgibbs if (halted == 0) 113239217Sgibbs /* Start the chip again */ 113339217Sgibbs adv_start_chip(adv); 113418781Sgibbs 113539217Sgibbs tinfo->current.period = period; 113639217Sgibbs tinfo->current.offset = offset; 113739217Sgibbs 113839217Sgibbs if (path != NULL) { 113939217Sgibbs /* 114039217Sgibbs * Tell the SCSI layer about the 114139217Sgibbs * new transfer parameters. 114239217Sgibbs */ 114339217Sgibbs struct ccb_trans_settings neg; 1144163816Smjacob memset(&neg, 0, sizeof (neg)); 1145163816Smjacob struct ccb_trans_settings_spi *spi = 1146163816Smjacob &neg.xport_specific.spi; 114739217Sgibbs 1148163816Smjacob neg.protocol = PROTO_SCSI; 1149163816Smjacob neg.protocol_version = SCSI_REV_2; 1150163816Smjacob neg.transport = XPORT_SPI; 1151163816Smjacob neg.transport_version = 2; 1152163816Smjacob 1153163816Smjacob spi->sync_offset = offset; 1154163816Smjacob spi->sync_period = period; 1155163816Smjacob spi->valid |= CTS_SPI_VALID_SYNC_OFFSET; 1156163816Smjacob spi->valid |= CTS_SPI_VALID_SYNC_RATE; 115739217Sgibbs xpt_setup_ccb(&neg.ccb_h, path, /*priority*/1); 115839217Sgibbs xpt_async(AC_TRANSFER_NEG, path, &neg); 115939217Sgibbs } 116039217Sgibbs } 116139217Sgibbs 116239217Sgibbs if ((type & ADV_TRANS_GOAL) != 0) { 116339217Sgibbs tinfo->goal.period = period; 116439217Sgibbs tinfo->goal.offset = offset; 116539217Sgibbs } 116639217Sgibbs 116739217Sgibbs if ((type & ADV_TRANS_USER) != 0) { 116839217Sgibbs tinfo->user.period = period; 116939217Sgibbs tinfo->user.offset = offset; 117039217Sgibbs } 117139217Sgibbs} 117239217Sgibbs 117339217Sgibbsu_int8_t 117439217Sgibbsadv_period_offset_to_sdtr(struct adv_softc *adv, u_int *period, 117539217Sgibbs u_int *offset, int tid) 117639217Sgibbs{ 117739217Sgibbs u_int i; 117839217Sgibbs u_int dummy_offset; 117939217Sgibbs u_int dummy_period; 118039217Sgibbs 118139217Sgibbs if (offset == NULL) { 118239217Sgibbs dummy_offset = 0; 118339217Sgibbs offset = &dummy_offset; 118439217Sgibbs } 118539217Sgibbs 118639217Sgibbs if (period == NULL) { 118739217Sgibbs dummy_period = 0; 118839217Sgibbs period = &dummy_period; 118939217Sgibbs } 119039217Sgibbs 119139217Sgibbs *offset = MIN(ADV_SYN_MAX_OFFSET, *offset); 119239217Sgibbs if (*period != 0 && *offset != 0) { 119339217Sgibbs for (i = 0; i < adv->sdtr_period_tbl_size; i++) { 119439217Sgibbs if (*period <= adv->sdtr_period_tbl[i]) { 119539217Sgibbs /* 119639217Sgibbs * When responding to a target that requests 119739217Sgibbs * sync, the requested rate may fall between 119839217Sgibbs * two rates that we can output, but still be 119939217Sgibbs * a rate that we can receive. Because of this, 120039217Sgibbs * we want to respond to the target with 120139217Sgibbs * the same rate that it sent to us even 120239217Sgibbs * if the period we use to send data to it 120339217Sgibbs * is lower. Only lower the response period 120439217Sgibbs * if we must. 120539217Sgibbs */ 120639217Sgibbs if (i == 0 /* Our maximum rate */) 120739217Sgibbs *period = adv->sdtr_period_tbl[0]; 120839217Sgibbs return ((i << 4) | *offset); 120918781Sgibbs } 121018781Sgibbs } 121118781Sgibbs } 121239217Sgibbs 121339217Sgibbs /* Must go async */ 121439217Sgibbs *period = 0; 121539217Sgibbs *offset = 0; 121639217Sgibbs if (adv->fix_asyn_xfer & ADV_TID_TO_TARGET_MASK(tid)) 121739217Sgibbs return (ASYN_SDTR_DATA_FIX_PCI_REV_AB); 121839217Sgibbs return (0); 121918781Sgibbs} 122018781Sgibbs 122118781Sgibbs/* Internal Routines */ 122218781Sgibbs 122318781Sgibbsstatic void 122439217Sgibbsadv_read_lram_16_multi(struct adv_softc *adv, u_int16_t s_addr, 122539217Sgibbs u_int16_t *buffer, int count) 122618781Sgibbs{ 122718781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr); 122818781Sgibbs ADV_INSW(adv, ADV_LRAM_DATA, buffer, count); 122918781Sgibbs} 123018781Sgibbs 123118781Sgibbsstatic void 123239217Sgibbsadv_write_lram_16_multi(struct adv_softc *adv, u_int16_t s_addr, 123339217Sgibbs u_int16_t *buffer, int count) 123418781Sgibbs{ 123518781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr); 123618781Sgibbs ADV_OUTSW(adv, ADV_LRAM_DATA, buffer, count); 123718781Sgibbs} 123818781Sgibbs 123918781Sgibbsstatic void 124039217Sgibbsadv_mset_lram_16(struct adv_softc *adv, u_int16_t s_addr, 124139217Sgibbs u_int16_t set_value, int count) 124218781Sgibbs{ 124318781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr); 1244251164Sscottl bus_set_multi_2(adv->res, adv->reg_off + ADV_LRAM_DATA, 1245251164Sscottl set_value, count); 124618781Sgibbs} 124718781Sgibbs 124818781Sgibbsstatic u_int32_t 124939217Sgibbsadv_msum_lram_16(struct adv_softc *adv, u_int16_t s_addr, int count) 125018781Sgibbs{ 125118781Sgibbs u_int32_t sum; 125218781Sgibbs int i; 125318781Sgibbs 125418781Sgibbs sum = 0; 125539217Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr); 125639217Sgibbs for (i = 0; i < count; i++) 125739217Sgibbs sum += ADV_INW(adv, ADV_LRAM_DATA); 125818781Sgibbs return (sum); 125918781Sgibbs} 126018781Sgibbs 126118781Sgibbsstatic int 126239217Sgibbsadv_write_and_verify_lram_16(struct adv_softc *adv, u_int16_t addr, 126339217Sgibbs u_int16_t value) 126418781Sgibbs{ 126518781Sgibbs int retval; 126618781Sgibbs 126718781Sgibbs retval = 0; 126818781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, addr); 126918781Sgibbs ADV_OUTW(adv, ADV_LRAM_DATA, value); 127039217Sgibbs DELAY(10000); 127118781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, addr); 127218781Sgibbs if (value != ADV_INW(adv, ADV_LRAM_DATA)) 127318781Sgibbs retval = 1; 127418781Sgibbs return (retval); 127518781Sgibbs} 127618781Sgibbs 127718781Sgibbsstatic u_int32_t 127839217Sgibbsadv_read_lram_32(struct adv_softc *adv, u_int16_t addr) 127918781Sgibbs{ 128018781Sgibbs u_int16_t val_low, val_high; 128118781Sgibbs 128218781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, addr); 128318781Sgibbs 128418781Sgibbs#if BYTE_ORDER == BIG_ENDIAN 128518781Sgibbs val_high = ADV_INW(adv, ADV_LRAM_DATA); 128618781Sgibbs val_low = ADV_INW(adv, ADV_LRAM_DATA); 128718781Sgibbs#else 128818781Sgibbs val_low = ADV_INW(adv, ADV_LRAM_DATA); 128918781Sgibbs val_high = ADV_INW(adv, ADV_LRAM_DATA); 129018781Sgibbs#endif 129118781Sgibbs 129218781Sgibbs return (((u_int32_t)val_high << 16) | (u_int32_t)val_low); 129318781Sgibbs} 129418781Sgibbs 129518781Sgibbsstatic void 129639217Sgibbsadv_write_lram_32(struct adv_softc *adv, u_int16_t addr, u_int32_t value) 129718781Sgibbs{ 129818781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, addr); 129918781Sgibbs 130018781Sgibbs#if BYTE_ORDER == BIG_ENDIAN 130118781Sgibbs ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)((value >> 16) & 0xFFFF)); 130218781Sgibbs ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)(value & 0xFFFF)); 130318781Sgibbs#else 130418781Sgibbs ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)(value & 0xFFFF)); 130518781Sgibbs ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)((value >> 16) & 0xFFFF)); 130618781Sgibbs#endif 130718781Sgibbs} 130818781Sgibbs 130918781Sgibbsstatic void 131039217Sgibbsadv_write_lram_32_multi(struct adv_softc *adv, u_int16_t s_addr, 131139217Sgibbs u_int32_t *buffer, int count) 131218781Sgibbs{ 131318781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr); 131439217Sgibbs ADV_OUTSW(adv, ADV_LRAM_DATA, (u_int16_t *)buffer, count * 2); 131518781Sgibbs} 131618781Sgibbs 131718781Sgibbsstatic u_int16_t 131839217Sgibbsadv_read_eeprom_16(struct adv_softc *adv, u_int8_t addr) 131918781Sgibbs{ 132018781Sgibbs u_int16_t read_wval; 132118781Sgibbs u_int8_t cmd_reg; 132218781Sgibbs 132318781Sgibbs adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE_DISABLE); 132418781Sgibbs DELAY(1000); 132518781Sgibbs cmd_reg = addr | ADV_EEPROM_CMD_READ; 132618781Sgibbs adv_write_eeprom_cmd_reg(adv, cmd_reg); 132718781Sgibbs DELAY(1000); 132818781Sgibbs read_wval = ADV_INW(adv, ADV_EEPROM_DATA); 132918781Sgibbs DELAY(1000); 133018781Sgibbs return (read_wval); 133118781Sgibbs} 133218781Sgibbs 133318781Sgibbsstatic u_int16_t 133439217Sgibbsadv_write_eeprom_16(struct adv_softc *adv, u_int8_t addr, u_int16_t value) 133518781Sgibbs{ 133618781Sgibbs u_int16_t read_value; 133718781Sgibbs 133818781Sgibbs read_value = adv_read_eeprom_16(adv, addr); 133918781Sgibbs if (read_value != value) { 134018781Sgibbs adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE_ENABLE); 134118781Sgibbs DELAY(1000); 134218781Sgibbs 134318781Sgibbs ADV_OUTW(adv, ADV_EEPROM_DATA, value); 134418781Sgibbs DELAY(1000); 134518781Sgibbs 134618781Sgibbs adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE | addr); 134718781Sgibbs DELAY(20 * 1000); 134818781Sgibbs 134918781Sgibbs adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE_DISABLE); 135018781Sgibbs DELAY(1000); 135118781Sgibbs read_value = adv_read_eeprom_16(adv, addr); 135218781Sgibbs } 135318781Sgibbs return (read_value); 135418781Sgibbs} 135518781Sgibbs 135618781Sgibbsstatic int 135739217Sgibbsadv_write_eeprom_cmd_reg(struct adv_softc *adv, u_int8_t cmd_reg) 135818781Sgibbs{ 135918781Sgibbs u_int8_t read_back; 136018781Sgibbs int retry; 136118781Sgibbs 136218781Sgibbs retry = 0; 136318781Sgibbs while (1) { 136418781Sgibbs ADV_OUTB(adv, ADV_EEPROM_CMD, cmd_reg); 136518781Sgibbs DELAY(1000); 136618781Sgibbs read_back = ADV_INB(adv, ADV_EEPROM_CMD); 136718781Sgibbs if (read_back == cmd_reg) { 136818781Sgibbs return (1); 136918781Sgibbs } 137018781Sgibbs if (retry++ > ADV_EEPROM_MAX_RETRY) { 137118781Sgibbs return (0); 137218781Sgibbs } 137318781Sgibbs } 137418781Sgibbs} 137518781Sgibbs 137618781Sgibbsstatic int 137739217Sgibbsadv_set_eeprom_config_once(struct adv_softc *adv, 137839217Sgibbs struct adv_eeprom_config *eeprom_config) 137918781Sgibbs{ 138018781Sgibbs int n_error; 138118781Sgibbs u_int16_t *wbuf; 138218781Sgibbs u_int16_t sum; 138318781Sgibbs u_int8_t s_addr; 138418781Sgibbs u_int8_t cfg_beg; 138518781Sgibbs u_int8_t cfg_end; 138618781Sgibbs 138718781Sgibbs wbuf = (u_int16_t *)eeprom_config; 138818781Sgibbs n_error = 0; 138918781Sgibbs sum = 0; 139018781Sgibbs for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) { 139118781Sgibbs sum += *wbuf; 139218781Sgibbs if (*wbuf != adv_write_eeprom_16(adv, s_addr, *wbuf)) { 139318781Sgibbs n_error++; 139418781Sgibbs } 139518781Sgibbs } 139618781Sgibbs if (adv->type & ADV_VL) { 139718781Sgibbs cfg_beg = ADV_EEPROM_CFG_BEG_VL; 139818781Sgibbs cfg_end = ADV_EEPROM_MAX_ADDR_VL; 139918781Sgibbs } else { 140018781Sgibbs cfg_beg = ADV_EEPROM_CFG_BEG; 140118781Sgibbs cfg_end = ADV_EEPROM_MAX_ADDR; 140218781Sgibbs } 140318781Sgibbs 140418781Sgibbs for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) { 140518781Sgibbs sum += *wbuf; 140618781Sgibbs if (*wbuf != adv_write_eeprom_16(adv, s_addr, *wbuf)) { 140718781Sgibbs n_error++; 140818781Sgibbs } 140918781Sgibbs } 141018781Sgibbs *wbuf = sum; 141118781Sgibbs if (sum != adv_write_eeprom_16(adv, s_addr, sum)) { 141218781Sgibbs n_error++; 141318781Sgibbs } 141418781Sgibbs wbuf = (u_int16_t *)eeprom_config; 141518781Sgibbs for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) { 141618781Sgibbs if (*wbuf != adv_read_eeprom_16(adv, s_addr)) { 141718781Sgibbs n_error++; 141818781Sgibbs } 141918781Sgibbs } 142018781Sgibbs for (s_addr = cfg_beg; s_addr <= cfg_end; s_addr++, wbuf++) { 142118781Sgibbs if (*wbuf != adv_read_eeprom_16(adv, s_addr)) { 142218781Sgibbs n_error++; 142318781Sgibbs } 142418781Sgibbs } 142518781Sgibbs return (n_error); 142618781Sgibbs} 142718781Sgibbs 142818781Sgibbsstatic u_int32_t 142939217Sgibbsadv_load_microcode(struct adv_softc *adv, u_int16_t s_addr, 143039217Sgibbs u_int16_t *mcode_buf, u_int16_t mcode_size) 143118781Sgibbs{ 143239217Sgibbs u_int32_t chksum; 143339217Sgibbs u_int16_t mcode_lram_size; 143439217Sgibbs u_int16_t mcode_chksum; 143518781Sgibbs 143618781Sgibbs mcode_lram_size = mcode_size >> 1; 143718781Sgibbs /* XXX Why zero the memory just before you write the whole thing?? */ 143839217Sgibbs adv_mset_lram_16(adv, s_addr, 0, mcode_lram_size); 143918781Sgibbs adv_write_lram_16_multi(adv, s_addr, mcode_buf, mcode_lram_size); 144018781Sgibbs 144118781Sgibbs chksum = adv_msum_lram_16(adv, s_addr, mcode_lram_size); 144218781Sgibbs mcode_chksum = (u_int16_t)adv_msum_lram_16(adv, ADV_CODE_SEC_BEG, 144339217Sgibbs ((mcode_size - s_addr 144439217Sgibbs - ADV_CODE_SEC_BEG) >> 1)); 144518781Sgibbs adv_write_lram_16(adv, ADVV_MCODE_CHKSUM_W, mcode_chksum); 144618781Sgibbs adv_write_lram_16(adv, ADVV_MCODE_SIZE_W, mcode_size); 144718781Sgibbs return (chksum); 144818781Sgibbs} 144918781Sgibbs 145018781Sgibbsstatic void 145139217Sgibbsadv_reinit_lram(struct adv_softc *adv) { 145239217Sgibbs adv_init_lram(adv); 145339217Sgibbs adv_init_qlink_var(adv); 145439217Sgibbs} 145539217Sgibbs 145639217Sgibbsstatic void 145739217Sgibbsadv_init_lram(struct adv_softc *adv) 145818781Sgibbs{ 145939217Sgibbs u_int8_t i; 146039217Sgibbs u_int16_t s_addr; 146118781Sgibbs 146218781Sgibbs adv_mset_lram_16(adv, ADV_QADR_BEG, 0, 146339217Sgibbs (((adv->max_openings + 2 + 1) * 64) >> 1)); 146418781Sgibbs 146518781Sgibbs i = ADV_MIN_ACTIVE_QNO; 146618781Sgibbs s_addr = ADV_QADR_BEG + ADV_QBLK_SIZE; 146718781Sgibbs 146818781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD, i + 1); 146918781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, adv->max_openings); 147018781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, i); 147118781Sgibbs i++; 147218781Sgibbs s_addr += ADV_QBLK_SIZE; 147318781Sgibbs for (; i < adv->max_openings; i++, s_addr += ADV_QBLK_SIZE) { 147418781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD, i + 1); 147518781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, i - 1); 147618781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, i); 147718781Sgibbs } 147818781Sgibbs 147918781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD, ADV_QLINK_END); 148018781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, adv->max_openings - 1); 148118781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, adv->max_openings); 148218781Sgibbs i++; 148318781Sgibbs s_addr += ADV_QBLK_SIZE; 148418781Sgibbs 148518781Sgibbs for (; i <= adv->max_openings + 3; i++, s_addr += ADV_QBLK_SIZE) { 148618781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD, i); 148718781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, i); 148818781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, i); 148918781Sgibbs } 149018781Sgibbs} 149118781Sgibbs 149218781Sgibbsstatic int 149339217Sgibbsadv_init_microcode_var(struct adv_softc *adv) 149418781Sgibbs{ 149539217Sgibbs int i; 149618781Sgibbs 149718781Sgibbs for (i = 0; i <= ADV_MAX_TID; i++) { 149839217Sgibbs 149939217Sgibbs /* Start out async all around */ 150039217Sgibbs adv_set_syncrate(adv, /*path*/NULL, 150139217Sgibbs i, 0, 0, 150239217Sgibbs ADV_TRANS_GOAL|ADV_TRANS_CUR); 150318781Sgibbs } 150418781Sgibbs 150518781Sgibbs adv_init_qlink_var(adv); 150618781Sgibbs 150718781Sgibbs adv_write_lram_8(adv, ADVV_DISC_ENABLE_B, adv->disc_enable); 150818781Sgibbs adv_write_lram_8(adv, ADVV_HOSTSCSI_ID_B, 0x01 << adv->scsi_id); 150918781Sgibbs 151039217Sgibbs adv_write_lram_32(adv, ADVV_OVERRUN_PADDR_D, adv->overrun_physbase); 151118781Sgibbs 151239217Sgibbs adv_write_lram_32(adv, ADVV_OVERRUN_BSIZE_D, ADV_OVERRUN_BSIZE); 151318781Sgibbs 151418781Sgibbs ADV_OUTW(adv, ADV_REG_PROG_COUNTER, ADV_MCODE_START_ADDR); 151518781Sgibbs if (ADV_INW(adv, ADV_REG_PROG_COUNTER) != ADV_MCODE_START_ADDR) { 1516251164Sscottl device_printf(adv->dev, 1517251164Sscottl "Unable to set program counter. Aborting.\n"); 151818781Sgibbs return (1); 151918781Sgibbs } 152018781Sgibbs return (0); 152118781Sgibbs} 152218781Sgibbs 152318781Sgibbsstatic void 152439217Sgibbsadv_init_qlink_var(struct adv_softc *adv) 152518781Sgibbs{ 152618781Sgibbs int i; 152718781Sgibbs u_int16_t lram_addr; 152818781Sgibbs 152918781Sgibbs adv_write_lram_8(adv, ADVV_NEXTRDY_B, 1); 153018781Sgibbs adv_write_lram_8(adv, ADVV_DONENEXT_B, adv->max_openings); 153118781Sgibbs 153218781Sgibbs adv_write_lram_16(adv, ADVV_FREE_Q_HEAD_W, 1); 153318781Sgibbs adv_write_lram_16(adv, ADVV_DONE_Q_TAIL_W, adv->max_openings); 153418781Sgibbs 153518781Sgibbs adv_write_lram_8(adv, ADVV_BUSY_QHEAD_B, 153618781Sgibbs (u_int8_t)((int) adv->max_openings + 1)); 153718781Sgibbs adv_write_lram_8(adv, ADVV_DISC1_QHEAD_B, 153818781Sgibbs (u_int8_t)((int) adv->max_openings + 2)); 153918781Sgibbs 154018781Sgibbs adv_write_lram_8(adv, ADVV_TOTAL_READY_Q_B, adv->max_openings); 154118781Sgibbs 154218781Sgibbs adv_write_lram_16(adv, ADVV_ASCDVC_ERR_CODE_W, 0); 154318781Sgibbs adv_write_lram_16(adv, ADVV_HALTCODE_W, 0); 154418781Sgibbs adv_write_lram_8(adv, ADVV_STOP_CODE_B, 0); 154518781Sgibbs adv_write_lram_8(adv, ADVV_SCSIBUSY_B, 0); 154618781Sgibbs adv_write_lram_8(adv, ADVV_WTM_FLAG_B, 0); 154739217Sgibbs adv_write_lram_8(adv, ADVV_Q_DONE_IN_PROGRESS_B, 0); 154818781Sgibbs 154918781Sgibbs lram_addr = ADV_QADR_BEG; 155018781Sgibbs for (i = 0; i < 32; i++, lram_addr += 2) 155118781Sgibbs adv_write_lram_16(adv, lram_addr, 0); 155218781Sgibbs} 155339217Sgibbs 155418781Sgibbsstatic void 155539217Sgibbsadv_disable_interrupt(struct adv_softc *adv) 155618781Sgibbs{ 155718781Sgibbs u_int16_t cfg; 155818781Sgibbs 155918781Sgibbs cfg = ADV_INW(adv, ADV_CONFIG_LSW); 156018781Sgibbs ADV_OUTW(adv, ADV_CONFIG_LSW, cfg & ~ADV_CFG_LSW_HOST_INT_ON); 156118781Sgibbs} 156218781Sgibbs 156318781Sgibbsstatic void 156439217Sgibbsadv_enable_interrupt(struct adv_softc *adv) 156518781Sgibbs{ 156618781Sgibbs u_int16_t cfg; 156718781Sgibbs 156818781Sgibbs cfg = ADV_INW(adv, ADV_CONFIG_LSW); 156918781Sgibbs ADV_OUTW(adv, ADV_CONFIG_LSW, cfg | ADV_CFG_LSW_HOST_INT_ON); 157018781Sgibbs} 157118781Sgibbs 157218781Sgibbsstatic void 157339217Sgibbsadv_toggle_irq_act(struct adv_softc *adv) 157418781Sgibbs{ 157518781Sgibbs ADV_OUTW(adv, ADV_CHIP_STATUS, ADV_CIW_IRQ_ACT); 157618781Sgibbs ADV_OUTW(adv, ADV_CHIP_STATUS, 0); 157718781Sgibbs} 157818781Sgibbs 157939217Sgibbsvoid 158039217Sgibbsadv_start_execution(struct adv_softc *adv) 158118781Sgibbs{ 158218781Sgibbs if (adv_read_lram_8(adv, ADV_STOP_CODE_B) != 0) { 158318781Sgibbs adv_write_lram_8(adv, ADV_STOP_CODE_B, 0); 158418781Sgibbs } 158518781Sgibbs} 158618781Sgibbs 158755945Sgibbsint 158839217Sgibbsadv_stop_chip(struct adv_softc *adv) 158918781Sgibbs{ 159018781Sgibbs u_int8_t cc_val; 159118781Sgibbs 159218781Sgibbs cc_val = ADV_INB(adv, ADV_CHIP_CTRL) 159318781Sgibbs & (~(ADV_CC_SINGLE_STEP | ADV_CC_TEST | ADV_CC_DIAG)); 159418781Sgibbs ADV_OUTB(adv, ADV_CHIP_CTRL, cc_val | ADV_CC_HALT); 159518781Sgibbs adv_set_chip_ih(adv, ADV_INS_HALT); 159618781Sgibbs adv_set_chip_ih(adv, ADV_INS_RFLAG_WTM); 159718781Sgibbs if ((ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_HALTED) == 0) { 159818781Sgibbs return (0); 159918781Sgibbs } 160018781Sgibbs return (1); 160118781Sgibbs} 160218781Sgibbs 160339217Sgibbsstatic int 160439217Sgibbsadv_host_req_chip_halt(struct adv_softc *adv) 160539217Sgibbs{ 160639217Sgibbs int count; 160739217Sgibbs u_int8_t saved_stop_code; 160839217Sgibbs 160939217Sgibbs if (adv_is_chip_halted(adv)) 161039217Sgibbs return (1); 161139217Sgibbs 161239217Sgibbs count = 0; 161339217Sgibbs saved_stop_code = adv_read_lram_8(adv, ADVV_STOP_CODE_B); 161439217Sgibbs adv_write_lram_8(adv, ADVV_STOP_CODE_B, 161539217Sgibbs ADV_STOP_HOST_REQ_RISC_HALT | ADV_STOP_REQ_RISC_STOP); 161639217Sgibbs while (adv_is_chip_halted(adv) == 0 161739217Sgibbs && count++ < 2000) 161839217Sgibbs ; 161939217Sgibbs 162039217Sgibbs adv_write_lram_8(adv, ADVV_STOP_CODE_B, saved_stop_code); 162139217Sgibbs return (count < 2000); 162239217Sgibbs} 162339217Sgibbs 162418781Sgibbsstatic void 162539217Sgibbsadv_set_chip_ih(struct adv_softc *adv, u_int16_t ins_code) 162618781Sgibbs{ 162718781Sgibbs adv_set_bank(adv, 1); 162818781Sgibbs ADV_OUTW(adv, ADV_REG_IH, ins_code); 162918781Sgibbs adv_set_bank(adv, 0); 163018781Sgibbs} 163118781Sgibbs 1632153072Sru#if 0 163318781Sgibbsstatic u_int8_t 163439217Sgibbsadv_get_chip_scsi_ctrl(struct adv_softc *adv) 163518781Sgibbs{ 163618781Sgibbs u_int8_t scsi_ctrl; 163718781Sgibbs 163818781Sgibbs adv_set_bank(adv, 1); 163918781Sgibbs scsi_ctrl = ADV_INB(adv, ADV_REG_SC); 164018781Sgibbs adv_set_bank(adv, 0); 164118781Sgibbs return (scsi_ctrl); 164218781Sgibbs} 164318781Sgibbs#endif 164418781Sgibbs 164518781Sgibbs/* 164618781Sgibbs * XXX Looks like more padding issues in this routine as well. 164718781Sgibbs * There has to be a way to turn this into an insw. 164818781Sgibbs */ 164918781Sgibbsstatic void 165039217Sgibbsadv_get_q_info(struct adv_softc *adv, u_int16_t s_addr, 165139217Sgibbs u_int16_t *inbuf, int words) 165218781Sgibbs{ 165318781Sgibbs int i; 165418781Sgibbs 165518781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr); 165618781Sgibbs for (i = 0; i < words; i++, inbuf++) { 165718781Sgibbs if (i == 5) { 165818781Sgibbs continue; 165918781Sgibbs } 166018781Sgibbs *inbuf = ADV_INW(adv, ADV_LRAM_DATA); 166118781Sgibbs } 166218781Sgibbs} 166318781Sgibbs 166418781Sgibbsstatic u_int 166539217Sgibbsadv_get_num_free_queues(struct adv_softc *adv, u_int8_t n_qs) 166618781Sgibbs{ 166718781Sgibbs u_int cur_used_qs; 166818781Sgibbs u_int cur_free_qs; 166918781Sgibbs 167039217Sgibbs cur_used_qs = adv->cur_active + ADV_MIN_FREE_Q; 167118781Sgibbs 167218781Sgibbs if ((cur_used_qs + n_qs) <= adv->max_openings) { 167318781Sgibbs cur_free_qs = adv->max_openings - cur_used_qs; 167418781Sgibbs return (cur_free_qs); 167518781Sgibbs } 167639217Sgibbs adv->openings_needed = n_qs; 167718781Sgibbs return (0); 167818781Sgibbs} 167918781Sgibbs 168018781Sgibbsstatic u_int8_t 168139217Sgibbsadv_alloc_free_queues(struct adv_softc *adv, u_int8_t free_q_head, 168239217Sgibbs u_int8_t n_free_q) 168318781Sgibbs{ 168418781Sgibbs int i; 168518781Sgibbs 168618781Sgibbs for (i = 0; i < n_free_q; i++) { 168718781Sgibbs free_q_head = adv_alloc_free_queue(adv, free_q_head); 168818781Sgibbs if (free_q_head == ADV_QLINK_END) 168918781Sgibbs break; 169018781Sgibbs } 169118781Sgibbs return (free_q_head); 169218781Sgibbs} 169318781Sgibbs 169418781Sgibbsstatic u_int8_t 169539217Sgibbsadv_alloc_free_queue(struct adv_softc *adv, u_int8_t free_q_head) 169618781Sgibbs{ 169718781Sgibbs u_int16_t q_addr; 169818781Sgibbs u_int8_t next_qp; 169918781Sgibbs u_int8_t q_status; 170018781Sgibbs 170118781Sgibbs next_qp = ADV_QLINK_END; 170218781Sgibbs q_addr = ADV_QNO_TO_QADDR(free_q_head); 170318781Sgibbs q_status = adv_read_lram_8(adv, q_addr + ADV_SCSIQ_B_STATUS); 170418781Sgibbs 170518781Sgibbs if ((q_status & QS_READY) == 0) 170618781Sgibbs next_qp = adv_read_lram_8(adv, q_addr + ADV_SCSIQ_B_FWD); 170718781Sgibbs 170818781Sgibbs return (next_qp); 170918781Sgibbs} 171018781Sgibbs 171118781Sgibbsstatic int 171239217Sgibbsadv_send_scsi_queue(struct adv_softc *adv, struct adv_scsi_q *scsiq, 171339217Sgibbs u_int8_t n_q_required) 171418781Sgibbs{ 171518781Sgibbs u_int8_t free_q_head; 171618781Sgibbs u_int8_t next_qp; 171718781Sgibbs u_int8_t tid_no; 171818781Sgibbs u_int8_t target_ix; 171918781Sgibbs int retval; 172018781Sgibbs 172118781Sgibbs retval = 1; 172218781Sgibbs target_ix = scsiq->q2.target_ix; 172318781Sgibbs tid_no = ADV_TIX_TO_TID(target_ix); 172418781Sgibbs free_q_head = adv_read_lram_16(adv, ADVV_FREE_Q_HEAD_W) & 0xFF; 172518781Sgibbs if ((next_qp = adv_alloc_free_queues(adv, free_q_head, n_q_required)) 172618781Sgibbs != ADV_QLINK_END) { 172718781Sgibbs scsiq->q1.q_no = free_q_head; 172818781Sgibbs 172918781Sgibbs /* 173018781Sgibbs * Now that we know our Q number, point our sense 173139217Sgibbs * buffer pointer to a bus dma mapped area where 173239217Sgibbs * we can dma the data to. 173318781Sgibbs */ 173439217Sgibbs scsiq->q1.sense_addr = adv->sense_physbase 173539217Sgibbs + ((free_q_head - 1) * sizeof(struct scsi_sense_data)); 173618781Sgibbs adv_put_ready_sg_list_queue(adv, scsiq, free_q_head); 173718781Sgibbs adv_write_lram_16(adv, ADVV_FREE_Q_HEAD_W, next_qp); 173818781Sgibbs adv->cur_active += n_q_required; 173918781Sgibbs retval = 0; 174018781Sgibbs } 174118781Sgibbs return (retval); 174218781Sgibbs} 174318781Sgibbs 174418781Sgibbs 174518781Sgibbsstatic void 174639217Sgibbsadv_put_ready_sg_list_queue(struct adv_softc *adv, struct adv_scsi_q *scsiq, 174739217Sgibbs u_int q_no) 174818781Sgibbs{ 174918781Sgibbs u_int8_t sg_list_dwords; 175018781Sgibbs u_int8_t sg_index, i; 175118781Sgibbs u_int8_t sg_entry_cnt; 175218781Sgibbs u_int8_t next_qp; 175318781Sgibbs u_int16_t q_addr; 175418781Sgibbs struct adv_sg_head *sg_head; 175518781Sgibbs struct adv_sg_list_q scsi_sg_q; 175618781Sgibbs 175718781Sgibbs sg_head = scsiq->sg_head; 175818781Sgibbs 175918781Sgibbs if (sg_head) { 176018781Sgibbs sg_entry_cnt = sg_head->entry_cnt - 1; 176118781Sgibbs#ifdef DIAGNOSTIC 176218781Sgibbs if (sg_entry_cnt == 0) 176339217Sgibbs panic("adv_put_ready_sg_list_queue: ScsiQ with " 176439217Sgibbs "a SG list but only one element"); 176518781Sgibbs if ((scsiq->q1.cntl & QC_SG_HEAD) == 0) 176639217Sgibbs panic("adv_put_ready_sg_list_queue: ScsiQ with " 176739217Sgibbs "a SG list but QC_SG_HEAD not set"); 176818781Sgibbs#endif 176918781Sgibbs q_addr = ADV_QNO_TO_QADDR(q_no); 177018781Sgibbs sg_index = 1; 177118781Sgibbs scsiq->q1.sg_queue_cnt = sg_head->queue_cnt; 177218781Sgibbs scsi_sg_q.sg_head_qp = q_no; 177318781Sgibbs scsi_sg_q.cntl = QCSG_SG_XFER_LIST; 177418781Sgibbs for (i = 0; i < sg_head->queue_cnt; i++) { 177518781Sgibbs u_int8_t segs_this_q; 177618781Sgibbs 177718781Sgibbs if (sg_entry_cnt > ADV_SG_LIST_PER_Q) 177818781Sgibbs segs_this_q = ADV_SG_LIST_PER_Q; 177918781Sgibbs else { 178018781Sgibbs /* This will be the last segment then */ 178118781Sgibbs segs_this_q = sg_entry_cnt; 178218781Sgibbs scsi_sg_q.cntl |= QCSG_SG_XFER_END; 178318781Sgibbs } 178418781Sgibbs scsi_sg_q.seq_no = i + 1; 178539217Sgibbs sg_list_dwords = segs_this_q << 1; 178618781Sgibbs if (i == 0) { 178718781Sgibbs scsi_sg_q.sg_list_cnt = segs_this_q; 178818781Sgibbs scsi_sg_q.sg_cur_list_cnt = segs_this_q; 178918781Sgibbs } else { 179018781Sgibbs scsi_sg_q.sg_list_cnt = segs_this_q - 1; 179118781Sgibbs scsi_sg_q.sg_cur_list_cnt = segs_this_q - 1; 179218781Sgibbs } 179318781Sgibbs next_qp = adv_read_lram_8(adv, q_addr + ADV_SCSIQ_B_FWD); 179418781Sgibbs scsi_sg_q.q_no = next_qp; 179518781Sgibbs q_addr = ADV_QNO_TO_QADDR(next_qp); 179618781Sgibbs 179739217Sgibbs adv_write_lram_16_multi(adv, 179839217Sgibbs q_addr + ADV_SCSIQ_SGHD_CPY_BEG, 179918781Sgibbs (u_int16_t *)&scsi_sg_q, 180018781Sgibbs sizeof(scsi_sg_q) >> 1); 180118781Sgibbs adv_write_lram_32_multi(adv, q_addr + ADV_SGQ_LIST_BEG, 180218781Sgibbs (u_int32_t *)&sg_head->sg_list[sg_index], 180318781Sgibbs sg_list_dwords); 180418781Sgibbs sg_entry_cnt -= segs_this_q; 180518781Sgibbs sg_index += ADV_SG_LIST_PER_Q; 180618781Sgibbs } 180718781Sgibbs } 180818781Sgibbs adv_put_ready_queue(adv, scsiq, q_no); 180918781Sgibbs} 181018781Sgibbs 181118781Sgibbsstatic void 181239217Sgibbsadv_put_ready_queue(struct adv_softc *adv, struct adv_scsi_q *scsiq, 181339217Sgibbs u_int q_no) 181418781Sgibbs{ 181539217Sgibbs struct adv_target_transinfo* tinfo; 181639217Sgibbs u_int q_addr; 181739217Sgibbs u_int tid_no; 181818781Sgibbs 181939217Sgibbs tid_no = ADV_TIX_TO_TID(scsiq->q2.target_ix); 182039217Sgibbs tinfo = &adv->tinfo[tid_no]; 182146581Sken if ((tinfo->current.period != tinfo->goal.period) 182246581Sken || (tinfo->current.offset != tinfo->goal.offset)) { 182318781Sgibbs 182439217Sgibbs adv_msgout_sdtr(adv, tinfo->goal.period, tinfo->goal.offset); 182518781Sgibbs scsiq->q1.cntl |= QC_MSG_OUT; 182618781Sgibbs } 182718781Sgibbs q_addr = ADV_QNO_TO_QADDR(q_no); 182818781Sgibbs 182918781Sgibbs scsiq->q1.status = QS_FREE; 183018781Sgibbs 183118781Sgibbs adv_write_lram_16_multi(adv, q_addr + ADV_SCSIQ_CDB_BEG, 183218781Sgibbs (u_int16_t *)scsiq->cdbptr, 183318781Sgibbs scsiq->q2.cdb_len >> 1); 183418781Sgibbs 183518781Sgibbs#if BYTE_ORDER == BIG_ENDIAN 183618781Sgibbs adv_adj_scsiq_endian(scsiq); 183718781Sgibbs#endif 183818781Sgibbs 183918781Sgibbs adv_put_scsiq(adv, q_addr + ADV_SCSIQ_CPY_BEG, 184018781Sgibbs (u_int16_t *) &scsiq->q1.cntl, 184118781Sgibbs ((sizeof(scsiq->q1) + sizeof(scsiq->q2)) / 2) - 1); 184218781Sgibbs 1843153072Sru#ifdef CC_WRITE_IO_COUNT 184418781Sgibbs adv_write_lram_16(adv, q_addr + ADV_SCSIQ_W_REQ_COUNT, 184518781Sgibbs adv->req_count); 184618781Sgibbs#endif 184718781Sgibbs 1848153072Sru#ifdef CC_CLEAR_DMA_REMAIN 184918781Sgibbs 185018781Sgibbs adv_write_lram_32(adv, q_addr + ADV_SCSIQ_DW_REMAIN_XFER_ADDR, 0); 185118781Sgibbs adv_write_lram_32(adv, q_addr + ADV_SCSIQ_DW_REMAIN_XFER_CNT, 0); 185218781Sgibbs#endif 185318781Sgibbs 185418781Sgibbs adv_write_lram_16(adv, q_addr + ADV_SCSIQ_B_STATUS, 185518781Sgibbs (scsiq->q1.q_no << 8) | QS_READY); 185618781Sgibbs} 185718781Sgibbs 185818781Sgibbsstatic void 185939217Sgibbsadv_put_scsiq(struct adv_softc *adv, u_int16_t s_addr, 186039217Sgibbs u_int16_t *buffer, int words) 186118781Sgibbs{ 186218781Sgibbs int i; 186318781Sgibbs 186418781Sgibbs /* 186518781Sgibbs * XXX This routine makes *gross* assumptions 186618781Sgibbs * about padding in the data structures. 186718781Sgibbs * Either the data structures should have explicit 186818781Sgibbs * padding members added, or they should have padding 186918781Sgibbs * turned off via compiler attributes depending on 187018781Sgibbs * which yields better overall performance. My hunch 187118781Sgibbs * would be that turning off padding would be the 187218781Sgibbs * faster approach as an outsw is much faster than 187318781Sgibbs * this crude loop and accessing un-aligned data 187418781Sgibbs * members isn't *that* expensive. The other choice 187518781Sgibbs * would be to modify the ASC script so that the 187618781Sgibbs * the adv_scsiq_1 structure can be re-arranged so 187718781Sgibbs * padding isn't required. 187818781Sgibbs */ 187918781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr); 188018781Sgibbs for (i = 0; i < words; i++, buffer++) { 188118781Sgibbs if (i == 2 || i == 10) { 188218781Sgibbs continue; 188318781Sgibbs } 188418781Sgibbs ADV_OUTW(adv, ADV_LRAM_DATA, *buffer); 188518781Sgibbs } 188618781Sgibbs} 188718781Sgibbs 1888111342Sobrien#if BYTE_ORDER == BIG_ENDIAN 1889111342Sobrienvoid 1890111342Sobrienadv_adj_endian_qdone_info(struct adv_q_done_info *scsiq) 1891111342Sobrien{ 1892111342Sobrien 1893111342Sobrien panic("adv(4) not supported on big-endian machines.\n"); 1894111342Sobrien} 1895111342Sobrien 1896111342Sobrienvoid 1897111342Sobrienadv_adj_scsiq_endian(struct adv_scsi_q *scsiq) 1898111342Sobrien{ 1899111342Sobrien 1900111342Sobrien panic("adv(4) not supported on big-endian machines.\n"); 1901111342Sobrien} 1902111342Sobrien#endif 1903111342Sobrien 190439217Sgibbsstatic void 190539217Sgibbsadv_handle_extmsg_in(struct adv_softc *adv, u_int16_t halt_q_addr, 190639217Sgibbs u_int8_t q_cntl, target_bit_vector target_mask, 190739217Sgibbs int tid_no) 190818781Sgibbs{ 190939217Sgibbs struct ext_msg ext_msg; 191018781Sgibbs 191139217Sgibbs adv_read_lram_16_multi(adv, ADVV_MSGIN_BEG, (u_int16_t *) &ext_msg, 191239217Sgibbs sizeof(ext_msg) >> 1); 191339217Sgibbs if ((ext_msg.msg_type == MSG_EXTENDED) 191439217Sgibbs && (ext_msg.msg_req == MSG_EXT_SDTR) 191539217Sgibbs && (ext_msg.msg_len == MSG_EXT_SDTR_LEN)) { 191655945Sgibbs union ccb *ccb; 191755945Sgibbs struct adv_target_transinfo* tinfo; 191855945Sgibbs u_int32_t cinfo_index; 191939217Sgibbs u_int period; 192039217Sgibbs u_int offset; 192139217Sgibbs int sdtr_accept; 192239217Sgibbs u_int8_t orig_offset; 192339217Sgibbs 192455945Sgibbs cinfo_index = 192555945Sgibbs adv_read_lram_32(adv, halt_q_addr + ADV_SCSIQ_D_CINFO_IDX); 192655945Sgibbs ccb = adv->ccb_infos[cinfo_index].ccb; 192739217Sgibbs tinfo = &adv->tinfo[tid_no]; 192839217Sgibbs sdtr_accept = TRUE; 192939217Sgibbs 193039217Sgibbs orig_offset = ext_msg.req_ack_offset; 193139217Sgibbs if (ext_msg.xfer_period < tinfo->goal.period) { 193239217Sgibbs sdtr_accept = FALSE; 193339217Sgibbs ext_msg.xfer_period = tinfo->goal.period; 193439217Sgibbs } 193539217Sgibbs 193639217Sgibbs /* Perform range checking */ 193739217Sgibbs period = ext_msg.xfer_period; 193839217Sgibbs offset = ext_msg.req_ack_offset; 193939217Sgibbs adv_period_offset_to_sdtr(adv, &period, &offset, tid_no); 194039217Sgibbs ext_msg.xfer_period = period; 194139217Sgibbs ext_msg.req_ack_offset = offset; 194239217Sgibbs 194339217Sgibbs /* Record our current sync settings */ 194439217Sgibbs adv_set_syncrate(adv, ccb->ccb_h.path, 194539217Sgibbs tid_no, ext_msg.xfer_period, 194639217Sgibbs ext_msg.req_ack_offset, 194739217Sgibbs ADV_TRANS_GOAL|ADV_TRANS_ACTIVE); 194839217Sgibbs 194939217Sgibbs /* Offset too high or large period forced async */ 195039217Sgibbs if (orig_offset != ext_msg.req_ack_offset) 195139217Sgibbs sdtr_accept = FALSE; 195239217Sgibbs 195339217Sgibbs if (sdtr_accept && (q_cntl & QC_MSG_OUT)) { 195439217Sgibbs /* Valid response to our requested negotiation */ 195539217Sgibbs q_cntl &= ~QC_MSG_OUT; 195639217Sgibbs } else { 195739217Sgibbs /* Must Respond */ 195839217Sgibbs q_cntl |= QC_MSG_OUT; 195939217Sgibbs adv_msgout_sdtr(adv, ext_msg.xfer_period, 196039217Sgibbs ext_msg.req_ack_offset); 196139217Sgibbs } 196239217Sgibbs 196339217Sgibbs } else if (ext_msg.msg_type == MSG_EXTENDED 196439217Sgibbs && ext_msg.msg_req == MSG_EXT_WDTR 196539217Sgibbs && ext_msg.msg_len == MSG_EXT_WDTR_LEN) { 196639217Sgibbs 196739217Sgibbs ext_msg.wdtr_width = 0; 196839217Sgibbs adv_write_lram_16_multi(adv, ADVV_MSGOUT_BEG, 196939217Sgibbs (u_int16_t *)&ext_msg, 197039217Sgibbs sizeof(ext_msg) >> 1); 197139217Sgibbs q_cntl |= QC_MSG_OUT; 197239217Sgibbs } else { 197339217Sgibbs 197439217Sgibbs ext_msg.msg_type = MSG_MESSAGE_REJECT; 197539217Sgibbs adv_write_lram_16_multi(adv, ADVV_MSGOUT_BEG, 197639217Sgibbs (u_int16_t *)&ext_msg, 197739217Sgibbs sizeof(ext_msg) >> 1); 197839217Sgibbs q_cntl |= QC_MSG_OUT; 197939217Sgibbs } 198039217Sgibbs adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_CNTL, q_cntl); 198139217Sgibbs} 198239217Sgibbs 198339217Sgibbsstatic void 198439217Sgibbsadv_msgout_sdtr(struct adv_softc *adv, u_int8_t sdtr_period, 198539217Sgibbs u_int8_t sdtr_offset) 198639217Sgibbs{ 198739217Sgibbs struct ext_msg sdtr_buf; 198839217Sgibbs 198918781Sgibbs sdtr_buf.msg_type = MSG_EXTENDED; 199018781Sgibbs sdtr_buf.msg_len = MSG_EXT_SDTR_LEN; 199118781Sgibbs sdtr_buf.msg_req = MSG_EXT_SDTR; 199218781Sgibbs sdtr_buf.xfer_period = sdtr_period; 199318781Sgibbs sdtr_offset &= ADV_SYN_MAX_OFFSET; 199418781Sgibbs sdtr_buf.req_ack_offset = sdtr_offset; 199518781Sgibbs adv_write_lram_16_multi(adv, ADVV_MSGOUT_BEG, 199618781Sgibbs (u_int16_t *) &sdtr_buf, 199718781Sgibbs sizeof(sdtr_buf) / 2); 199818781Sgibbs} 199918781Sgibbs 200039217Sgibbsint 200139217Sgibbsadv_abort_ccb(struct adv_softc *adv, int target, int lun, union ccb *ccb, 200239217Sgibbs u_int32_t status, int queued_only) 200318781Sgibbs{ 200439217Sgibbs u_int16_t q_addr; 200539217Sgibbs u_int8_t q_no; 200639217Sgibbs struct adv_q_done_info scsiq_buf; 200739217Sgibbs struct adv_q_done_info *scsiq; 200839217Sgibbs u_int8_t target_ix; 200939217Sgibbs int count; 201018781Sgibbs 2011251164Sscottl if (!dumping) 2012251164Sscottl mtx_assert(&adv->lock, MA_OWNED); 201339217Sgibbs scsiq = &scsiq_buf; 201439217Sgibbs target_ix = ADV_TIDLUN_TO_IX(target, lun); 201539217Sgibbs count = 0; 201639217Sgibbs for (q_no = ADV_MIN_ACTIVE_QNO; q_no <= adv->max_openings; q_no++) { 201755945Sgibbs struct adv_ccb_info *ccb_info; 201839217Sgibbs q_addr = ADV_QNO_TO_QADDR(q_no); 201939217Sgibbs 202039217Sgibbs adv_copy_lram_doneq(adv, q_addr, scsiq, adv->max_dma_count); 202155945Sgibbs ccb_info = &adv->ccb_infos[scsiq->d2.ccb_index]; 202239217Sgibbs if (((scsiq->q_status & QS_READY) != 0) 202339217Sgibbs && ((scsiq->q_status & QS_ABORTED) == 0) 202439217Sgibbs && ((scsiq->cntl & QCSG_SG_XFER_LIST) == 0) 202539217Sgibbs && (scsiq->d2.target_ix == target_ix) 202639217Sgibbs && (queued_only == 0 202739217Sgibbs || !(scsiq->q_status & (QS_DISC1|QS_DISC2|QS_BUSY|QS_DONE))) 202855945Sgibbs && (ccb == NULL || (ccb == ccb_info->ccb))) { 202939217Sgibbs union ccb *aborted_ccb; 203039217Sgibbs struct adv_ccb_info *cinfo; 203139217Sgibbs 203239217Sgibbs scsiq->q_status |= QS_ABORTED; 203339217Sgibbs adv_write_lram_8(adv, q_addr + ADV_SCSIQ_B_STATUS, 203439217Sgibbs scsiq->q_status); 203555945Sgibbs aborted_ccb = ccb_info->ccb; 203639217Sgibbs /* Don't clobber earlier error codes */ 203739217Sgibbs if ((aborted_ccb->ccb_h.status & CAM_STATUS_MASK) 203839217Sgibbs == CAM_REQ_INPROG) 203939217Sgibbs aborted_ccb->ccb_h.status |= status; 204039217Sgibbs cinfo = (struct adv_ccb_info *) 204139217Sgibbs aborted_ccb->ccb_h.ccb_cinfo_ptr; 204239217Sgibbs cinfo->state |= ACCB_ABORT_QUEUED; 204339217Sgibbs count++; 204418781Sgibbs } 204518781Sgibbs } 204639217Sgibbs return (count); 204718781Sgibbs} 204818781Sgibbs 204939217Sgibbsint 205055945Sgibbsadv_reset_bus(struct adv_softc *adv, int initiate_bus_reset) 205139217Sgibbs{ 205239217Sgibbs int count; 205339217Sgibbs int i; 205439217Sgibbs union ccb *ccb; 205539217Sgibbs 2056251164Sscottl if (!dumping) 2057251164Sscottl mtx_assert(&adv->lock, MA_OWNED); 205855945Sgibbs i = 200; 205955945Sgibbs while ((ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_SCSI_RESET_ACTIVE) != 0 206055945Sgibbs && i--) 206155945Sgibbs DELAY(1000); 206255945Sgibbs adv_reset_chip(adv, initiate_bus_reset); 206339217Sgibbs adv_reinit_lram(adv); 206455945Sgibbs for (i = 0; i <= ADV_MAX_TID; i++) 206555945Sgibbs adv_set_syncrate(adv, NULL, i, /*period*/0, 206655945Sgibbs /*offset*/0, ADV_TRANS_CUR); 206739217Sgibbs ADV_OUTW(adv, ADV_REG_PROG_COUNTER, ADV_MCODE_START_ADDR); 206839217Sgibbs 206939217Sgibbs /* Tell the XPT layer that a bus reset occured */ 207039217Sgibbs if (adv->path != NULL) 207139217Sgibbs xpt_async(AC_BUS_RESET, adv->path, NULL); 207239217Sgibbs 207339217Sgibbs count = 0; 207439217Sgibbs while ((ccb = (union ccb *)LIST_FIRST(&adv->pending_ccbs)) != NULL) { 207539217Sgibbs if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) 207639217Sgibbs ccb->ccb_h.status |= CAM_SCSI_BUS_RESET; 207739217Sgibbs adv_done(adv, ccb, QD_ABORTED_BY_HOST, 0, 0, 0); 207839217Sgibbs count++; 207939217Sgibbs } 208039217Sgibbs 208139217Sgibbs adv_start_chip(adv); 208239217Sgibbs return (count); 208339217Sgibbs} 208439217Sgibbs 208518781Sgibbsstatic void 208639217Sgibbsadv_set_sdtr_reg_at_id(struct adv_softc *adv, int tid, u_int8_t sdtr_data) 208718781Sgibbs{ 208839217Sgibbs int orig_id; 208939217Sgibbs 209039217Sgibbs adv_set_bank(adv, 1); 209139217Sgibbs orig_id = ffs(ADV_INB(adv, ADV_HOST_SCSIID)) - 1; 209239217Sgibbs ADV_OUTB(adv, ADV_HOST_SCSIID, tid); 209339217Sgibbs if (ADV_INB(adv, ADV_HOST_SCSIID) == (0x01 << tid)) { 209439217Sgibbs adv_set_bank(adv, 0); 209539217Sgibbs ADV_OUTB(adv, ADV_SYN_OFFSET, sdtr_data); 209639217Sgibbs } 209739217Sgibbs adv_set_bank(adv, 1); 209839217Sgibbs ADV_OUTB(adv, ADV_HOST_SCSIID, orig_id); 209939217Sgibbs adv_set_bank(adv, 0); 210018781Sgibbs} 2101