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> 48241492Sjhb#include <sys/conf.h> 49241492Sjhb#include <sys/lock.h> 5045846Sgibbs#include <sys/kernel.h> 51241492Sjhb#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; 304241492Sjhb 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 319298431Spfg num_entries = nitems(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 467241492Sjhbadv_find_signature(struct resource *res) 46839217Sgibbs{ 46939217Sgibbs u_int16_t signature; 47039217Sgibbs 471241492Sjhb if (bus_read_1(res, ADV_SIGNATURE_BYTE) == ADV_1000_ID1B) { 472241492Sjhb 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) { 601241492Sjhb device_printf(adv->dev, 602241492Sjhb "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 699241492Sjhb if (!dumping) 700241492Sjhb 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 947241492Sjhb if (!dumping) 948241492Sjhb 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; 977241492Sjhb 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); 1020241492Sjhb 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 */ 1034241492Sjhb 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 union ccb *ccb; 105555945Sgibbs u_int32_t cinfo_index; 105639217Sgibbs 1057263954Simp adv_read_lram_8(adv, halt_q_addr + ADV_SCSIQ_SCSI_STATUS); 105855945Sgibbs cinfo_index = 105955945Sgibbs adv_read_lram_32(adv, halt_q_addr + ADV_SCSIQ_D_CINFO_IDX); 106055945Sgibbs ccb = adv->ccb_infos[cinfo_index].ccb; 106139217Sgibbs xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 106240733Sgibbs ccb->ccb_h.status |= CAM_DEV_QFRZN|CAM_SCSI_STATUS_ERROR; 106340733Sgibbs ccb->csio.scsi_status = SCSI_STATUS_QUEUE_FULL; 106439217Sgibbs adv_abort_ccb(adv, tid_no, ADV_TIX_TO_LUN(target_ix), 106539217Sgibbs /*ccb*/NULL, CAM_REQUEUE_REQ, 106639217Sgibbs /*queued_only*/TRUE); 106739217Sgibbs scsi_busy = adv_read_lram_8(adv, ADVV_SCSIBUSY_B); 106839217Sgibbs scsi_busy &= ~target_mask; 106939217Sgibbs adv_write_lram_8(adv, ADVV_SCSIBUSY_B, scsi_busy); 107055945Sgibbs } else { 107155945Sgibbs printf("Unhandled Halt Code %x\n", int_halt_code); 107239217Sgibbs } 107339217Sgibbs adv_write_lram_16(adv, ADVV_HALTCODE_W, 0); 107439217Sgibbs} 107518781Sgibbs 107639217Sgibbsvoid 107739217Sgibbsadv_sdtr_to_period_offset(struct adv_softc *adv, 107839217Sgibbs u_int8_t sync_data, u_int8_t *period, 107939217Sgibbs u_int8_t *offset, int tid) 108039217Sgibbs{ 108139217Sgibbs if (adv->fix_asyn_xfer & ADV_TID_TO_TARGET_MASK(tid) 108239217Sgibbs && (sync_data == ASYN_SDTR_DATA_FIX_PCI_REV_AB)) { 108339217Sgibbs *period = *offset = 0; 108439217Sgibbs } else { 108539217Sgibbs *period = adv->sdtr_period_tbl[((sync_data >> 4) & 0xF)]; 108639217Sgibbs *offset = sync_data & 0xF; 108739217Sgibbs } 108839217Sgibbs} 108939217Sgibbs 109039217Sgibbsvoid 109139217Sgibbsadv_set_syncrate(struct adv_softc *adv, struct cam_path *path, 109239217Sgibbs u_int tid, u_int period, u_int offset, u_int type) 109339217Sgibbs{ 109439217Sgibbs struct adv_target_transinfo* tinfo; 109539217Sgibbs u_int old_period; 109639217Sgibbs u_int old_offset; 109739217Sgibbs u_int8_t sdtr_data; 109839217Sgibbs 1099241492Sjhb mtx_assert(&adv->lock, MA_OWNED); 110039217Sgibbs tinfo = &adv->tinfo[tid]; 110139217Sgibbs 110239217Sgibbs /* Filter our input */ 110339217Sgibbs sdtr_data = adv_period_offset_to_sdtr(adv, &period, 110439217Sgibbs &offset, tid); 110539217Sgibbs 110639217Sgibbs old_period = tinfo->current.period; 110739217Sgibbs old_offset = tinfo->current.offset; 110839217Sgibbs 110939217Sgibbs if ((type & ADV_TRANS_CUR) != 0 111039217Sgibbs && ((old_period != period || old_offset != offset) 111139217Sgibbs || period == 0 || offset == 0) /*Changes in asyn fix settings*/) { 111239217Sgibbs int halted; 111339217Sgibbs 111439217Sgibbs halted = adv_is_chip_halted(adv); 111539217Sgibbs if (halted == 0) 111639217Sgibbs /* Must halt the chip first */ 111739217Sgibbs adv_host_req_chip_halt(adv); 111839217Sgibbs 111939217Sgibbs /* Update current hardware settings */ 112039217Sgibbs adv_set_sdtr_reg_at_id(adv, tid, sdtr_data); 112139217Sgibbs 112218781Sgibbs /* 112339217Sgibbs * If a target can run in sync mode, we don't need 112439217Sgibbs * to check it for sync problems. 112518781Sgibbs */ 112639217Sgibbs if (offset != 0) 112739217Sgibbs adv->fix_asyn_xfer &= ~ADV_TID_TO_TARGET_MASK(tid); 112818781Sgibbs 112939217Sgibbs if (halted == 0) 113039217Sgibbs /* Start the chip again */ 113139217Sgibbs adv_start_chip(adv); 113218781Sgibbs 113339217Sgibbs tinfo->current.period = period; 113439217Sgibbs tinfo->current.offset = offset; 113539217Sgibbs 113639217Sgibbs if (path != NULL) { 113739217Sgibbs /* 113839217Sgibbs * Tell the SCSI layer about the 113939217Sgibbs * new transfer parameters. 114039217Sgibbs */ 114139217Sgibbs struct ccb_trans_settings neg; 1142163816Smjacob memset(&neg, 0, sizeof (neg)); 1143163816Smjacob struct ccb_trans_settings_spi *spi = 1144163816Smjacob &neg.xport_specific.spi; 114539217Sgibbs 1146163816Smjacob neg.protocol = PROTO_SCSI; 1147163816Smjacob neg.protocol_version = SCSI_REV_2; 1148163816Smjacob neg.transport = XPORT_SPI; 1149163816Smjacob neg.transport_version = 2; 1150163816Smjacob 1151163816Smjacob spi->sync_offset = offset; 1152163816Smjacob spi->sync_period = period; 1153163816Smjacob spi->valid |= CTS_SPI_VALID_SYNC_OFFSET; 1154163816Smjacob spi->valid |= CTS_SPI_VALID_SYNC_RATE; 115539217Sgibbs xpt_setup_ccb(&neg.ccb_h, path, /*priority*/1); 115639217Sgibbs xpt_async(AC_TRANSFER_NEG, path, &neg); 115739217Sgibbs } 115839217Sgibbs } 115939217Sgibbs 116039217Sgibbs if ((type & ADV_TRANS_GOAL) != 0) { 116139217Sgibbs tinfo->goal.period = period; 116239217Sgibbs tinfo->goal.offset = offset; 116339217Sgibbs } 116439217Sgibbs 116539217Sgibbs if ((type & ADV_TRANS_USER) != 0) { 116639217Sgibbs tinfo->user.period = period; 116739217Sgibbs tinfo->user.offset = offset; 116839217Sgibbs } 116939217Sgibbs} 117039217Sgibbs 117139217Sgibbsu_int8_t 117239217Sgibbsadv_period_offset_to_sdtr(struct adv_softc *adv, u_int *period, 117339217Sgibbs u_int *offset, int tid) 117439217Sgibbs{ 117539217Sgibbs u_int i; 117639217Sgibbs u_int dummy_offset; 117739217Sgibbs u_int dummy_period; 117839217Sgibbs 117939217Sgibbs if (offset == NULL) { 118039217Sgibbs dummy_offset = 0; 118139217Sgibbs offset = &dummy_offset; 118239217Sgibbs } 118339217Sgibbs 118439217Sgibbs if (period == NULL) { 118539217Sgibbs dummy_period = 0; 118639217Sgibbs period = &dummy_period; 118739217Sgibbs } 118839217Sgibbs 118939217Sgibbs *offset = MIN(ADV_SYN_MAX_OFFSET, *offset); 119039217Sgibbs if (*period != 0 && *offset != 0) { 119139217Sgibbs for (i = 0; i < adv->sdtr_period_tbl_size; i++) { 119239217Sgibbs if (*period <= adv->sdtr_period_tbl[i]) { 119339217Sgibbs /* 119439217Sgibbs * When responding to a target that requests 119539217Sgibbs * sync, the requested rate may fall between 119639217Sgibbs * two rates that we can output, but still be 119739217Sgibbs * a rate that we can receive. Because of this, 119839217Sgibbs * we want to respond to the target with 119939217Sgibbs * the same rate that it sent to us even 120039217Sgibbs * if the period we use to send data to it 120139217Sgibbs * is lower. Only lower the response period 120239217Sgibbs * if we must. 120339217Sgibbs */ 120439217Sgibbs if (i == 0 /* Our maximum rate */) 120539217Sgibbs *period = adv->sdtr_period_tbl[0]; 120639217Sgibbs return ((i << 4) | *offset); 120718781Sgibbs } 120818781Sgibbs } 120918781Sgibbs } 121039217Sgibbs 121139217Sgibbs /* Must go async */ 121239217Sgibbs *period = 0; 121339217Sgibbs *offset = 0; 121439217Sgibbs if (adv->fix_asyn_xfer & ADV_TID_TO_TARGET_MASK(tid)) 121539217Sgibbs return (ASYN_SDTR_DATA_FIX_PCI_REV_AB); 121639217Sgibbs return (0); 121718781Sgibbs} 121818781Sgibbs 121918781Sgibbs/* Internal Routines */ 122018781Sgibbs 122118781Sgibbsstatic void 122239217Sgibbsadv_read_lram_16_multi(struct adv_softc *adv, u_int16_t s_addr, 122339217Sgibbs u_int16_t *buffer, int count) 122418781Sgibbs{ 122518781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr); 122618781Sgibbs ADV_INSW(adv, ADV_LRAM_DATA, buffer, count); 122718781Sgibbs} 122818781Sgibbs 122918781Sgibbsstatic void 123039217Sgibbsadv_write_lram_16_multi(struct adv_softc *adv, u_int16_t s_addr, 123139217Sgibbs u_int16_t *buffer, int count) 123218781Sgibbs{ 123318781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr); 123418781Sgibbs ADV_OUTSW(adv, ADV_LRAM_DATA, buffer, count); 123518781Sgibbs} 123618781Sgibbs 123718781Sgibbsstatic void 123839217Sgibbsadv_mset_lram_16(struct adv_softc *adv, u_int16_t s_addr, 123939217Sgibbs u_int16_t set_value, int count) 124018781Sgibbs{ 124118781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr); 1242241492Sjhb bus_set_multi_2(adv->res, adv->reg_off + ADV_LRAM_DATA, 1243241492Sjhb set_value, count); 124418781Sgibbs} 124518781Sgibbs 124618781Sgibbsstatic u_int32_t 124739217Sgibbsadv_msum_lram_16(struct adv_softc *adv, u_int16_t s_addr, int count) 124818781Sgibbs{ 124918781Sgibbs u_int32_t sum; 125018781Sgibbs int i; 125118781Sgibbs 125218781Sgibbs sum = 0; 125339217Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr); 125439217Sgibbs for (i = 0; i < count; i++) 125539217Sgibbs sum += ADV_INW(adv, ADV_LRAM_DATA); 125618781Sgibbs return (sum); 125718781Sgibbs} 125818781Sgibbs 125918781Sgibbsstatic int 126039217Sgibbsadv_write_and_verify_lram_16(struct adv_softc *adv, u_int16_t addr, 126139217Sgibbs u_int16_t value) 126218781Sgibbs{ 126318781Sgibbs int retval; 126418781Sgibbs 126518781Sgibbs retval = 0; 126618781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, addr); 126718781Sgibbs ADV_OUTW(adv, ADV_LRAM_DATA, value); 126839217Sgibbs DELAY(10000); 126918781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, addr); 127018781Sgibbs if (value != ADV_INW(adv, ADV_LRAM_DATA)) 127118781Sgibbs retval = 1; 127218781Sgibbs return (retval); 127318781Sgibbs} 127418781Sgibbs 127518781Sgibbsstatic u_int32_t 127639217Sgibbsadv_read_lram_32(struct adv_softc *adv, u_int16_t addr) 127718781Sgibbs{ 127818781Sgibbs u_int16_t val_low, val_high; 127918781Sgibbs 128018781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, addr); 128118781Sgibbs 128218781Sgibbs#if BYTE_ORDER == BIG_ENDIAN 128318781Sgibbs val_high = ADV_INW(adv, ADV_LRAM_DATA); 128418781Sgibbs val_low = ADV_INW(adv, ADV_LRAM_DATA); 128518781Sgibbs#else 128618781Sgibbs val_low = ADV_INW(adv, ADV_LRAM_DATA); 128718781Sgibbs val_high = ADV_INW(adv, ADV_LRAM_DATA); 128818781Sgibbs#endif 128918781Sgibbs 129018781Sgibbs return (((u_int32_t)val_high << 16) | (u_int32_t)val_low); 129118781Sgibbs} 129218781Sgibbs 129318781Sgibbsstatic void 129439217Sgibbsadv_write_lram_32(struct adv_softc *adv, u_int16_t addr, u_int32_t value) 129518781Sgibbs{ 129618781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, addr); 129718781Sgibbs 129818781Sgibbs#if BYTE_ORDER == BIG_ENDIAN 129918781Sgibbs ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)((value >> 16) & 0xFFFF)); 130018781Sgibbs ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)(value & 0xFFFF)); 130118781Sgibbs#else 130218781Sgibbs ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)(value & 0xFFFF)); 130318781Sgibbs ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)((value >> 16) & 0xFFFF)); 130418781Sgibbs#endif 130518781Sgibbs} 130618781Sgibbs 130718781Sgibbsstatic void 130839217Sgibbsadv_write_lram_32_multi(struct adv_softc *adv, u_int16_t s_addr, 130939217Sgibbs u_int32_t *buffer, int count) 131018781Sgibbs{ 131118781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr); 131239217Sgibbs ADV_OUTSW(adv, ADV_LRAM_DATA, (u_int16_t *)buffer, count * 2); 131318781Sgibbs} 131418781Sgibbs 131518781Sgibbsstatic u_int16_t 131639217Sgibbsadv_read_eeprom_16(struct adv_softc *adv, u_int8_t addr) 131718781Sgibbs{ 131818781Sgibbs u_int16_t read_wval; 131918781Sgibbs u_int8_t cmd_reg; 132018781Sgibbs 132118781Sgibbs adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE_DISABLE); 132218781Sgibbs DELAY(1000); 132318781Sgibbs cmd_reg = addr | ADV_EEPROM_CMD_READ; 132418781Sgibbs adv_write_eeprom_cmd_reg(adv, cmd_reg); 132518781Sgibbs DELAY(1000); 132618781Sgibbs read_wval = ADV_INW(adv, ADV_EEPROM_DATA); 132718781Sgibbs DELAY(1000); 132818781Sgibbs return (read_wval); 132918781Sgibbs} 133018781Sgibbs 133118781Sgibbsstatic u_int16_t 133239217Sgibbsadv_write_eeprom_16(struct adv_softc *adv, u_int8_t addr, u_int16_t value) 133318781Sgibbs{ 133418781Sgibbs u_int16_t read_value; 133518781Sgibbs 133618781Sgibbs read_value = adv_read_eeprom_16(adv, addr); 133718781Sgibbs if (read_value != value) { 133818781Sgibbs adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE_ENABLE); 133918781Sgibbs DELAY(1000); 134018781Sgibbs 134118781Sgibbs ADV_OUTW(adv, ADV_EEPROM_DATA, value); 134218781Sgibbs DELAY(1000); 134318781Sgibbs 134418781Sgibbs adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE | addr); 134518781Sgibbs DELAY(20 * 1000); 134618781Sgibbs 134718781Sgibbs adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE_DISABLE); 134818781Sgibbs DELAY(1000); 134918781Sgibbs read_value = adv_read_eeprom_16(adv, addr); 135018781Sgibbs } 135118781Sgibbs return (read_value); 135218781Sgibbs} 135318781Sgibbs 135418781Sgibbsstatic int 135539217Sgibbsadv_write_eeprom_cmd_reg(struct adv_softc *adv, u_int8_t cmd_reg) 135618781Sgibbs{ 135718781Sgibbs u_int8_t read_back; 135818781Sgibbs int retry; 135918781Sgibbs 136018781Sgibbs retry = 0; 136118781Sgibbs while (1) { 136218781Sgibbs ADV_OUTB(adv, ADV_EEPROM_CMD, cmd_reg); 136318781Sgibbs DELAY(1000); 136418781Sgibbs read_back = ADV_INB(adv, ADV_EEPROM_CMD); 136518781Sgibbs if (read_back == cmd_reg) { 136618781Sgibbs return (1); 136718781Sgibbs } 136818781Sgibbs if (retry++ > ADV_EEPROM_MAX_RETRY) { 136918781Sgibbs return (0); 137018781Sgibbs } 137118781Sgibbs } 137218781Sgibbs} 137318781Sgibbs 137418781Sgibbsstatic int 137539217Sgibbsadv_set_eeprom_config_once(struct adv_softc *adv, 137639217Sgibbs struct adv_eeprom_config *eeprom_config) 137718781Sgibbs{ 137818781Sgibbs int n_error; 137918781Sgibbs u_int16_t *wbuf; 138018781Sgibbs u_int16_t sum; 138118781Sgibbs u_int8_t s_addr; 138218781Sgibbs u_int8_t cfg_beg; 138318781Sgibbs u_int8_t cfg_end; 138418781Sgibbs 138518781Sgibbs wbuf = (u_int16_t *)eeprom_config; 138618781Sgibbs n_error = 0; 138718781Sgibbs sum = 0; 138818781Sgibbs for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) { 138918781Sgibbs sum += *wbuf; 139018781Sgibbs if (*wbuf != adv_write_eeprom_16(adv, s_addr, *wbuf)) { 139118781Sgibbs n_error++; 139218781Sgibbs } 139318781Sgibbs } 139418781Sgibbs if (adv->type & ADV_VL) { 139518781Sgibbs cfg_beg = ADV_EEPROM_CFG_BEG_VL; 139618781Sgibbs cfg_end = ADV_EEPROM_MAX_ADDR_VL; 139718781Sgibbs } else { 139818781Sgibbs cfg_beg = ADV_EEPROM_CFG_BEG; 139918781Sgibbs cfg_end = ADV_EEPROM_MAX_ADDR; 140018781Sgibbs } 140118781Sgibbs 140218781Sgibbs for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) { 140318781Sgibbs sum += *wbuf; 140418781Sgibbs if (*wbuf != adv_write_eeprom_16(adv, s_addr, *wbuf)) { 140518781Sgibbs n_error++; 140618781Sgibbs } 140718781Sgibbs } 140818781Sgibbs *wbuf = sum; 140918781Sgibbs if (sum != adv_write_eeprom_16(adv, s_addr, sum)) { 141018781Sgibbs n_error++; 141118781Sgibbs } 141218781Sgibbs wbuf = (u_int16_t *)eeprom_config; 141318781Sgibbs for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) { 141418781Sgibbs if (*wbuf != adv_read_eeprom_16(adv, s_addr)) { 141518781Sgibbs n_error++; 141618781Sgibbs } 141718781Sgibbs } 141818781Sgibbs for (s_addr = cfg_beg; s_addr <= cfg_end; s_addr++, wbuf++) { 141918781Sgibbs if (*wbuf != adv_read_eeprom_16(adv, s_addr)) { 142018781Sgibbs n_error++; 142118781Sgibbs } 142218781Sgibbs } 142318781Sgibbs return (n_error); 142418781Sgibbs} 142518781Sgibbs 142618781Sgibbsstatic u_int32_t 142739217Sgibbsadv_load_microcode(struct adv_softc *adv, u_int16_t s_addr, 142839217Sgibbs u_int16_t *mcode_buf, u_int16_t mcode_size) 142918781Sgibbs{ 143039217Sgibbs u_int32_t chksum; 143139217Sgibbs u_int16_t mcode_lram_size; 143239217Sgibbs u_int16_t mcode_chksum; 143318781Sgibbs 143418781Sgibbs mcode_lram_size = mcode_size >> 1; 143518781Sgibbs /* XXX Why zero the memory just before you write the whole thing?? */ 143639217Sgibbs adv_mset_lram_16(adv, s_addr, 0, mcode_lram_size); 143718781Sgibbs adv_write_lram_16_multi(adv, s_addr, mcode_buf, mcode_lram_size); 143818781Sgibbs 143918781Sgibbs chksum = adv_msum_lram_16(adv, s_addr, mcode_lram_size); 144018781Sgibbs mcode_chksum = (u_int16_t)adv_msum_lram_16(adv, ADV_CODE_SEC_BEG, 144139217Sgibbs ((mcode_size - s_addr 144239217Sgibbs - ADV_CODE_SEC_BEG) >> 1)); 144318781Sgibbs adv_write_lram_16(adv, ADVV_MCODE_CHKSUM_W, mcode_chksum); 144418781Sgibbs adv_write_lram_16(adv, ADVV_MCODE_SIZE_W, mcode_size); 144518781Sgibbs return (chksum); 144618781Sgibbs} 144718781Sgibbs 144818781Sgibbsstatic void 144939217Sgibbsadv_reinit_lram(struct adv_softc *adv) { 145039217Sgibbs adv_init_lram(adv); 145139217Sgibbs adv_init_qlink_var(adv); 145239217Sgibbs} 145339217Sgibbs 145439217Sgibbsstatic void 145539217Sgibbsadv_init_lram(struct adv_softc *adv) 145618781Sgibbs{ 145739217Sgibbs u_int8_t i; 145839217Sgibbs u_int16_t s_addr; 145918781Sgibbs 146018781Sgibbs adv_mset_lram_16(adv, ADV_QADR_BEG, 0, 146139217Sgibbs (((adv->max_openings + 2 + 1) * 64) >> 1)); 146218781Sgibbs 146318781Sgibbs i = ADV_MIN_ACTIVE_QNO; 146418781Sgibbs s_addr = ADV_QADR_BEG + ADV_QBLK_SIZE; 146518781Sgibbs 146618781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD, i + 1); 146718781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, adv->max_openings); 146818781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, i); 146918781Sgibbs i++; 147018781Sgibbs s_addr += ADV_QBLK_SIZE; 147118781Sgibbs for (; i < adv->max_openings; i++, s_addr += ADV_QBLK_SIZE) { 147218781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD, i + 1); 147318781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, i - 1); 147418781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, i); 147518781Sgibbs } 147618781Sgibbs 147718781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD, ADV_QLINK_END); 147818781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, adv->max_openings - 1); 147918781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, adv->max_openings); 148018781Sgibbs i++; 148118781Sgibbs s_addr += ADV_QBLK_SIZE; 148218781Sgibbs 148318781Sgibbs for (; i <= adv->max_openings + 3; i++, s_addr += ADV_QBLK_SIZE) { 148418781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD, i); 148518781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, i); 148618781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, i); 148718781Sgibbs } 148818781Sgibbs} 148918781Sgibbs 149018781Sgibbsstatic int 149139217Sgibbsadv_init_microcode_var(struct adv_softc *adv) 149218781Sgibbs{ 149339217Sgibbs int i; 149418781Sgibbs 149518781Sgibbs for (i = 0; i <= ADV_MAX_TID; i++) { 149639217Sgibbs 149739217Sgibbs /* Start out async all around */ 149839217Sgibbs adv_set_syncrate(adv, /*path*/NULL, 149939217Sgibbs i, 0, 0, 150039217Sgibbs ADV_TRANS_GOAL|ADV_TRANS_CUR); 150118781Sgibbs } 150218781Sgibbs 150318781Sgibbs adv_init_qlink_var(adv); 150418781Sgibbs 150518781Sgibbs adv_write_lram_8(adv, ADVV_DISC_ENABLE_B, adv->disc_enable); 150618781Sgibbs adv_write_lram_8(adv, ADVV_HOSTSCSI_ID_B, 0x01 << adv->scsi_id); 150718781Sgibbs 150839217Sgibbs adv_write_lram_32(adv, ADVV_OVERRUN_PADDR_D, adv->overrun_physbase); 150918781Sgibbs 151039217Sgibbs adv_write_lram_32(adv, ADVV_OVERRUN_BSIZE_D, ADV_OVERRUN_BSIZE); 151118781Sgibbs 151218781Sgibbs ADV_OUTW(adv, ADV_REG_PROG_COUNTER, ADV_MCODE_START_ADDR); 151318781Sgibbs if (ADV_INW(adv, ADV_REG_PROG_COUNTER) != ADV_MCODE_START_ADDR) { 1514241492Sjhb device_printf(adv->dev, 1515241492Sjhb "Unable to set program counter. Aborting.\n"); 151618781Sgibbs return (1); 151718781Sgibbs } 151818781Sgibbs return (0); 151918781Sgibbs} 152018781Sgibbs 152118781Sgibbsstatic void 152239217Sgibbsadv_init_qlink_var(struct adv_softc *adv) 152318781Sgibbs{ 152418781Sgibbs int i; 152518781Sgibbs u_int16_t lram_addr; 152618781Sgibbs 152718781Sgibbs adv_write_lram_8(adv, ADVV_NEXTRDY_B, 1); 152818781Sgibbs adv_write_lram_8(adv, ADVV_DONENEXT_B, adv->max_openings); 152918781Sgibbs 153018781Sgibbs adv_write_lram_16(adv, ADVV_FREE_Q_HEAD_W, 1); 153118781Sgibbs adv_write_lram_16(adv, ADVV_DONE_Q_TAIL_W, adv->max_openings); 153218781Sgibbs 153318781Sgibbs adv_write_lram_8(adv, ADVV_BUSY_QHEAD_B, 153418781Sgibbs (u_int8_t)((int) adv->max_openings + 1)); 153518781Sgibbs adv_write_lram_8(adv, ADVV_DISC1_QHEAD_B, 153618781Sgibbs (u_int8_t)((int) adv->max_openings + 2)); 153718781Sgibbs 153818781Sgibbs adv_write_lram_8(adv, ADVV_TOTAL_READY_Q_B, adv->max_openings); 153918781Sgibbs 154018781Sgibbs adv_write_lram_16(adv, ADVV_ASCDVC_ERR_CODE_W, 0); 154118781Sgibbs adv_write_lram_16(adv, ADVV_HALTCODE_W, 0); 154218781Sgibbs adv_write_lram_8(adv, ADVV_STOP_CODE_B, 0); 154318781Sgibbs adv_write_lram_8(adv, ADVV_SCSIBUSY_B, 0); 154418781Sgibbs adv_write_lram_8(adv, ADVV_WTM_FLAG_B, 0); 154539217Sgibbs adv_write_lram_8(adv, ADVV_Q_DONE_IN_PROGRESS_B, 0); 154618781Sgibbs 154718781Sgibbs lram_addr = ADV_QADR_BEG; 154818781Sgibbs for (i = 0; i < 32; i++, lram_addr += 2) 154918781Sgibbs adv_write_lram_16(adv, lram_addr, 0); 155018781Sgibbs} 155139217Sgibbs 155218781Sgibbsstatic void 155339217Sgibbsadv_disable_interrupt(struct adv_softc *adv) 155418781Sgibbs{ 155518781Sgibbs u_int16_t cfg; 155618781Sgibbs 155718781Sgibbs cfg = ADV_INW(adv, ADV_CONFIG_LSW); 155818781Sgibbs ADV_OUTW(adv, ADV_CONFIG_LSW, cfg & ~ADV_CFG_LSW_HOST_INT_ON); 155918781Sgibbs} 156018781Sgibbs 156118781Sgibbsstatic void 156239217Sgibbsadv_enable_interrupt(struct adv_softc *adv) 156318781Sgibbs{ 156418781Sgibbs u_int16_t cfg; 156518781Sgibbs 156618781Sgibbs cfg = ADV_INW(adv, ADV_CONFIG_LSW); 156718781Sgibbs ADV_OUTW(adv, ADV_CONFIG_LSW, cfg | ADV_CFG_LSW_HOST_INT_ON); 156818781Sgibbs} 156918781Sgibbs 157018781Sgibbsstatic void 157139217Sgibbsadv_toggle_irq_act(struct adv_softc *adv) 157218781Sgibbs{ 157318781Sgibbs ADV_OUTW(adv, ADV_CHIP_STATUS, ADV_CIW_IRQ_ACT); 157418781Sgibbs ADV_OUTW(adv, ADV_CHIP_STATUS, 0); 157518781Sgibbs} 157618781Sgibbs 157739217Sgibbsvoid 157839217Sgibbsadv_start_execution(struct adv_softc *adv) 157918781Sgibbs{ 158018781Sgibbs if (adv_read_lram_8(adv, ADV_STOP_CODE_B) != 0) { 158118781Sgibbs adv_write_lram_8(adv, ADV_STOP_CODE_B, 0); 158218781Sgibbs } 158318781Sgibbs} 158418781Sgibbs 158555945Sgibbsint 158639217Sgibbsadv_stop_chip(struct adv_softc *adv) 158718781Sgibbs{ 158818781Sgibbs u_int8_t cc_val; 158918781Sgibbs 159018781Sgibbs cc_val = ADV_INB(adv, ADV_CHIP_CTRL) 159118781Sgibbs & (~(ADV_CC_SINGLE_STEP | ADV_CC_TEST | ADV_CC_DIAG)); 159218781Sgibbs ADV_OUTB(adv, ADV_CHIP_CTRL, cc_val | ADV_CC_HALT); 159318781Sgibbs adv_set_chip_ih(adv, ADV_INS_HALT); 159418781Sgibbs adv_set_chip_ih(adv, ADV_INS_RFLAG_WTM); 159518781Sgibbs if ((ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_HALTED) == 0) { 159618781Sgibbs return (0); 159718781Sgibbs } 159818781Sgibbs return (1); 159918781Sgibbs} 160018781Sgibbs 160139217Sgibbsstatic int 160239217Sgibbsadv_host_req_chip_halt(struct adv_softc *adv) 160339217Sgibbs{ 160439217Sgibbs int count; 160539217Sgibbs u_int8_t saved_stop_code; 160639217Sgibbs 160739217Sgibbs if (adv_is_chip_halted(adv)) 160839217Sgibbs return (1); 160939217Sgibbs 161039217Sgibbs count = 0; 161139217Sgibbs saved_stop_code = adv_read_lram_8(adv, ADVV_STOP_CODE_B); 161239217Sgibbs adv_write_lram_8(adv, ADVV_STOP_CODE_B, 161339217Sgibbs ADV_STOP_HOST_REQ_RISC_HALT | ADV_STOP_REQ_RISC_STOP); 161439217Sgibbs while (adv_is_chip_halted(adv) == 0 161539217Sgibbs && count++ < 2000) 161639217Sgibbs ; 161739217Sgibbs 161839217Sgibbs adv_write_lram_8(adv, ADVV_STOP_CODE_B, saved_stop_code); 161939217Sgibbs return (count < 2000); 162039217Sgibbs} 162139217Sgibbs 162218781Sgibbsstatic void 162339217Sgibbsadv_set_chip_ih(struct adv_softc *adv, u_int16_t ins_code) 162418781Sgibbs{ 162518781Sgibbs adv_set_bank(adv, 1); 162618781Sgibbs ADV_OUTW(adv, ADV_REG_IH, ins_code); 162718781Sgibbs adv_set_bank(adv, 0); 162818781Sgibbs} 162918781Sgibbs 1630153072Sru#if 0 163118781Sgibbsstatic u_int8_t 163239217Sgibbsadv_get_chip_scsi_ctrl(struct adv_softc *adv) 163318781Sgibbs{ 163418781Sgibbs u_int8_t scsi_ctrl; 163518781Sgibbs 163618781Sgibbs adv_set_bank(adv, 1); 163718781Sgibbs scsi_ctrl = ADV_INB(adv, ADV_REG_SC); 163818781Sgibbs adv_set_bank(adv, 0); 163918781Sgibbs return (scsi_ctrl); 164018781Sgibbs} 164118781Sgibbs#endif 164218781Sgibbs 164318781Sgibbs/* 164418781Sgibbs * XXX Looks like more padding issues in this routine as well. 164518781Sgibbs * There has to be a way to turn this into an insw. 164618781Sgibbs */ 164718781Sgibbsstatic void 164839217Sgibbsadv_get_q_info(struct adv_softc *adv, u_int16_t s_addr, 164939217Sgibbs u_int16_t *inbuf, int words) 165018781Sgibbs{ 165118781Sgibbs int i; 165218781Sgibbs 165318781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr); 165418781Sgibbs for (i = 0; i < words; i++, inbuf++) { 165518781Sgibbs if (i == 5) { 165618781Sgibbs continue; 165718781Sgibbs } 165818781Sgibbs *inbuf = ADV_INW(adv, ADV_LRAM_DATA); 165918781Sgibbs } 166018781Sgibbs} 166118781Sgibbs 166218781Sgibbsstatic u_int 166339217Sgibbsadv_get_num_free_queues(struct adv_softc *adv, u_int8_t n_qs) 166418781Sgibbs{ 166518781Sgibbs u_int cur_used_qs; 166618781Sgibbs u_int cur_free_qs; 166718781Sgibbs 166839217Sgibbs cur_used_qs = adv->cur_active + ADV_MIN_FREE_Q; 166918781Sgibbs 167018781Sgibbs if ((cur_used_qs + n_qs) <= adv->max_openings) { 167118781Sgibbs cur_free_qs = adv->max_openings - cur_used_qs; 167218781Sgibbs return (cur_free_qs); 167318781Sgibbs } 167439217Sgibbs adv->openings_needed = n_qs; 167518781Sgibbs return (0); 167618781Sgibbs} 167718781Sgibbs 167818781Sgibbsstatic u_int8_t 167939217Sgibbsadv_alloc_free_queues(struct adv_softc *adv, u_int8_t free_q_head, 168039217Sgibbs u_int8_t n_free_q) 168118781Sgibbs{ 168218781Sgibbs int i; 168318781Sgibbs 168418781Sgibbs for (i = 0; i < n_free_q; i++) { 168518781Sgibbs free_q_head = adv_alloc_free_queue(adv, free_q_head); 168618781Sgibbs if (free_q_head == ADV_QLINK_END) 168718781Sgibbs break; 168818781Sgibbs } 168918781Sgibbs return (free_q_head); 169018781Sgibbs} 169118781Sgibbs 169218781Sgibbsstatic u_int8_t 169339217Sgibbsadv_alloc_free_queue(struct adv_softc *adv, u_int8_t free_q_head) 169418781Sgibbs{ 169518781Sgibbs u_int16_t q_addr; 169618781Sgibbs u_int8_t next_qp; 169718781Sgibbs u_int8_t q_status; 169818781Sgibbs 169918781Sgibbs next_qp = ADV_QLINK_END; 170018781Sgibbs q_addr = ADV_QNO_TO_QADDR(free_q_head); 170118781Sgibbs q_status = adv_read_lram_8(adv, q_addr + ADV_SCSIQ_B_STATUS); 170218781Sgibbs 170318781Sgibbs if ((q_status & QS_READY) == 0) 170418781Sgibbs next_qp = adv_read_lram_8(adv, q_addr + ADV_SCSIQ_B_FWD); 170518781Sgibbs 170618781Sgibbs return (next_qp); 170718781Sgibbs} 170818781Sgibbs 170918781Sgibbsstatic int 171039217Sgibbsadv_send_scsi_queue(struct adv_softc *adv, struct adv_scsi_q *scsiq, 171139217Sgibbs u_int8_t n_q_required) 171218781Sgibbs{ 171318781Sgibbs u_int8_t free_q_head; 171418781Sgibbs u_int8_t next_qp; 171518781Sgibbs int retval; 171618781Sgibbs 171718781Sgibbs retval = 1; 171818781Sgibbs free_q_head = adv_read_lram_16(adv, ADVV_FREE_Q_HEAD_W) & 0xFF; 171918781Sgibbs if ((next_qp = adv_alloc_free_queues(adv, free_q_head, n_q_required)) 172018781Sgibbs != ADV_QLINK_END) { 172118781Sgibbs scsiq->q1.q_no = free_q_head; 172218781Sgibbs 172318781Sgibbs /* 172418781Sgibbs * Now that we know our Q number, point our sense 172539217Sgibbs * buffer pointer to a bus dma mapped area where 172639217Sgibbs * we can dma the data to. 172718781Sgibbs */ 172839217Sgibbs scsiq->q1.sense_addr = adv->sense_physbase 172939217Sgibbs + ((free_q_head - 1) * sizeof(struct scsi_sense_data)); 173018781Sgibbs adv_put_ready_sg_list_queue(adv, scsiq, free_q_head); 173118781Sgibbs adv_write_lram_16(adv, ADVV_FREE_Q_HEAD_W, next_qp); 173218781Sgibbs adv->cur_active += n_q_required; 173318781Sgibbs retval = 0; 173418781Sgibbs } 173518781Sgibbs return (retval); 173618781Sgibbs} 173718781Sgibbs 173818781Sgibbs 173918781Sgibbsstatic void 174039217Sgibbsadv_put_ready_sg_list_queue(struct adv_softc *adv, struct adv_scsi_q *scsiq, 174139217Sgibbs u_int q_no) 174218781Sgibbs{ 174318781Sgibbs u_int8_t sg_list_dwords; 174418781Sgibbs u_int8_t sg_index, i; 174518781Sgibbs u_int8_t sg_entry_cnt; 174618781Sgibbs u_int8_t next_qp; 174718781Sgibbs u_int16_t q_addr; 174818781Sgibbs struct adv_sg_head *sg_head; 174918781Sgibbs struct adv_sg_list_q scsi_sg_q; 175018781Sgibbs 175118781Sgibbs sg_head = scsiq->sg_head; 175218781Sgibbs 175318781Sgibbs if (sg_head) { 175418781Sgibbs sg_entry_cnt = sg_head->entry_cnt - 1; 175518781Sgibbs#ifdef DIAGNOSTIC 175618781Sgibbs if (sg_entry_cnt == 0) 175739217Sgibbs panic("adv_put_ready_sg_list_queue: ScsiQ with " 175839217Sgibbs "a SG list but only one element"); 175918781Sgibbs if ((scsiq->q1.cntl & QC_SG_HEAD) == 0) 176039217Sgibbs panic("adv_put_ready_sg_list_queue: ScsiQ with " 176139217Sgibbs "a SG list but QC_SG_HEAD not set"); 176218781Sgibbs#endif 176318781Sgibbs q_addr = ADV_QNO_TO_QADDR(q_no); 176418781Sgibbs sg_index = 1; 176518781Sgibbs scsiq->q1.sg_queue_cnt = sg_head->queue_cnt; 176618781Sgibbs scsi_sg_q.sg_head_qp = q_no; 176718781Sgibbs scsi_sg_q.cntl = QCSG_SG_XFER_LIST; 176818781Sgibbs for (i = 0; i < sg_head->queue_cnt; i++) { 176918781Sgibbs u_int8_t segs_this_q; 177018781Sgibbs 177118781Sgibbs if (sg_entry_cnt > ADV_SG_LIST_PER_Q) 177218781Sgibbs segs_this_q = ADV_SG_LIST_PER_Q; 177318781Sgibbs else { 177418781Sgibbs /* This will be the last segment then */ 177518781Sgibbs segs_this_q = sg_entry_cnt; 177618781Sgibbs scsi_sg_q.cntl |= QCSG_SG_XFER_END; 177718781Sgibbs } 177818781Sgibbs scsi_sg_q.seq_no = i + 1; 177939217Sgibbs sg_list_dwords = segs_this_q << 1; 178018781Sgibbs if (i == 0) { 178118781Sgibbs scsi_sg_q.sg_list_cnt = segs_this_q; 178218781Sgibbs scsi_sg_q.sg_cur_list_cnt = segs_this_q; 178318781Sgibbs } else { 178418781Sgibbs scsi_sg_q.sg_list_cnt = segs_this_q - 1; 178518781Sgibbs scsi_sg_q.sg_cur_list_cnt = segs_this_q - 1; 178618781Sgibbs } 178718781Sgibbs next_qp = adv_read_lram_8(adv, q_addr + ADV_SCSIQ_B_FWD); 178818781Sgibbs scsi_sg_q.q_no = next_qp; 178918781Sgibbs q_addr = ADV_QNO_TO_QADDR(next_qp); 179018781Sgibbs 179139217Sgibbs adv_write_lram_16_multi(adv, 179239217Sgibbs q_addr + ADV_SCSIQ_SGHD_CPY_BEG, 179318781Sgibbs (u_int16_t *)&scsi_sg_q, 179418781Sgibbs sizeof(scsi_sg_q) >> 1); 179518781Sgibbs adv_write_lram_32_multi(adv, q_addr + ADV_SGQ_LIST_BEG, 179618781Sgibbs (u_int32_t *)&sg_head->sg_list[sg_index], 179718781Sgibbs sg_list_dwords); 179818781Sgibbs sg_entry_cnt -= segs_this_q; 179918781Sgibbs sg_index += ADV_SG_LIST_PER_Q; 180018781Sgibbs } 180118781Sgibbs } 180218781Sgibbs adv_put_ready_queue(adv, scsiq, q_no); 180318781Sgibbs} 180418781Sgibbs 180518781Sgibbsstatic void 180639217Sgibbsadv_put_ready_queue(struct adv_softc *adv, struct adv_scsi_q *scsiq, 180739217Sgibbs u_int q_no) 180818781Sgibbs{ 180939217Sgibbs struct adv_target_transinfo* tinfo; 181039217Sgibbs u_int q_addr; 181139217Sgibbs u_int tid_no; 181218781Sgibbs 181339217Sgibbs tid_no = ADV_TIX_TO_TID(scsiq->q2.target_ix); 181439217Sgibbs tinfo = &adv->tinfo[tid_no]; 181546581Sken if ((tinfo->current.period != tinfo->goal.period) 181646581Sken || (tinfo->current.offset != tinfo->goal.offset)) { 181718781Sgibbs 181839217Sgibbs adv_msgout_sdtr(adv, tinfo->goal.period, tinfo->goal.offset); 181918781Sgibbs scsiq->q1.cntl |= QC_MSG_OUT; 182018781Sgibbs } 182118781Sgibbs q_addr = ADV_QNO_TO_QADDR(q_no); 182218781Sgibbs 182318781Sgibbs scsiq->q1.status = QS_FREE; 182418781Sgibbs 182518781Sgibbs adv_write_lram_16_multi(adv, q_addr + ADV_SCSIQ_CDB_BEG, 182618781Sgibbs (u_int16_t *)scsiq->cdbptr, 182718781Sgibbs scsiq->q2.cdb_len >> 1); 182818781Sgibbs 182918781Sgibbs#if BYTE_ORDER == BIG_ENDIAN 183018781Sgibbs adv_adj_scsiq_endian(scsiq); 183118781Sgibbs#endif 183218781Sgibbs 183318781Sgibbs adv_put_scsiq(adv, q_addr + ADV_SCSIQ_CPY_BEG, 183418781Sgibbs (u_int16_t *) &scsiq->q1.cntl, 183518781Sgibbs ((sizeof(scsiq->q1) + sizeof(scsiq->q2)) / 2) - 1); 183618781Sgibbs 1837153072Sru#ifdef CC_WRITE_IO_COUNT 183818781Sgibbs adv_write_lram_16(adv, q_addr + ADV_SCSIQ_W_REQ_COUNT, 183918781Sgibbs adv->req_count); 184018781Sgibbs#endif 184118781Sgibbs 1842153072Sru#ifdef CC_CLEAR_DMA_REMAIN 184318781Sgibbs 184418781Sgibbs adv_write_lram_32(adv, q_addr + ADV_SCSIQ_DW_REMAIN_XFER_ADDR, 0); 184518781Sgibbs adv_write_lram_32(adv, q_addr + ADV_SCSIQ_DW_REMAIN_XFER_CNT, 0); 184618781Sgibbs#endif 184718781Sgibbs 184818781Sgibbs adv_write_lram_16(adv, q_addr + ADV_SCSIQ_B_STATUS, 184918781Sgibbs (scsiq->q1.q_no << 8) | QS_READY); 185018781Sgibbs} 185118781Sgibbs 185218781Sgibbsstatic void 185339217Sgibbsadv_put_scsiq(struct adv_softc *adv, u_int16_t s_addr, 185439217Sgibbs u_int16_t *buffer, int words) 185518781Sgibbs{ 185618781Sgibbs int i; 185718781Sgibbs 185818781Sgibbs /* 185918781Sgibbs * XXX This routine makes *gross* assumptions 186018781Sgibbs * about padding in the data structures. 186118781Sgibbs * Either the data structures should have explicit 186218781Sgibbs * padding members added, or they should have padding 186318781Sgibbs * turned off via compiler attributes depending on 186418781Sgibbs * which yields better overall performance. My hunch 186518781Sgibbs * would be that turning off padding would be the 186618781Sgibbs * faster approach as an outsw is much faster than 186718781Sgibbs * this crude loop and accessing un-aligned data 186818781Sgibbs * members isn't *that* expensive. The other choice 186918781Sgibbs * would be to modify the ASC script so that the 187018781Sgibbs * the adv_scsiq_1 structure can be re-arranged so 187118781Sgibbs * padding isn't required. 187218781Sgibbs */ 187318781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr); 187418781Sgibbs for (i = 0; i < words; i++, buffer++) { 187518781Sgibbs if (i == 2 || i == 10) { 187618781Sgibbs continue; 187718781Sgibbs } 187818781Sgibbs ADV_OUTW(adv, ADV_LRAM_DATA, *buffer); 187918781Sgibbs } 188018781Sgibbs} 188118781Sgibbs 1882111342Sobrien#if BYTE_ORDER == BIG_ENDIAN 1883111342Sobrienvoid 1884111342Sobrienadv_adj_endian_qdone_info(struct adv_q_done_info *scsiq) 1885111342Sobrien{ 1886111342Sobrien 1887111342Sobrien panic("adv(4) not supported on big-endian machines.\n"); 1888111342Sobrien} 1889111342Sobrien 1890111342Sobrienvoid 1891111342Sobrienadv_adj_scsiq_endian(struct adv_scsi_q *scsiq) 1892111342Sobrien{ 1893111342Sobrien 1894111342Sobrien panic("adv(4) not supported on big-endian machines.\n"); 1895111342Sobrien} 1896111342Sobrien#endif 1897111342Sobrien 189839217Sgibbsstatic void 189939217Sgibbsadv_handle_extmsg_in(struct adv_softc *adv, u_int16_t halt_q_addr, 190039217Sgibbs u_int8_t q_cntl, target_bit_vector target_mask, 190139217Sgibbs int tid_no) 190218781Sgibbs{ 190339217Sgibbs struct ext_msg ext_msg; 190418781Sgibbs 190539217Sgibbs adv_read_lram_16_multi(adv, ADVV_MSGIN_BEG, (u_int16_t *) &ext_msg, 190639217Sgibbs sizeof(ext_msg) >> 1); 190739217Sgibbs if ((ext_msg.msg_type == MSG_EXTENDED) 190839217Sgibbs && (ext_msg.msg_req == MSG_EXT_SDTR) 190939217Sgibbs && (ext_msg.msg_len == MSG_EXT_SDTR_LEN)) { 191055945Sgibbs union ccb *ccb; 191155945Sgibbs struct adv_target_transinfo* tinfo; 191255945Sgibbs u_int32_t cinfo_index; 191339217Sgibbs u_int period; 191439217Sgibbs u_int offset; 191539217Sgibbs int sdtr_accept; 191639217Sgibbs u_int8_t orig_offset; 191739217Sgibbs 191855945Sgibbs cinfo_index = 191955945Sgibbs adv_read_lram_32(adv, halt_q_addr + ADV_SCSIQ_D_CINFO_IDX); 192055945Sgibbs ccb = adv->ccb_infos[cinfo_index].ccb; 192139217Sgibbs tinfo = &adv->tinfo[tid_no]; 192239217Sgibbs sdtr_accept = TRUE; 192339217Sgibbs 192439217Sgibbs orig_offset = ext_msg.req_ack_offset; 192539217Sgibbs if (ext_msg.xfer_period < tinfo->goal.period) { 192639217Sgibbs sdtr_accept = FALSE; 192739217Sgibbs ext_msg.xfer_period = tinfo->goal.period; 192839217Sgibbs } 192939217Sgibbs 193039217Sgibbs /* Perform range checking */ 193139217Sgibbs period = ext_msg.xfer_period; 193239217Sgibbs offset = ext_msg.req_ack_offset; 193339217Sgibbs adv_period_offset_to_sdtr(adv, &period, &offset, tid_no); 193439217Sgibbs ext_msg.xfer_period = period; 193539217Sgibbs ext_msg.req_ack_offset = offset; 193639217Sgibbs 193739217Sgibbs /* Record our current sync settings */ 193839217Sgibbs adv_set_syncrate(adv, ccb->ccb_h.path, 193939217Sgibbs tid_no, ext_msg.xfer_period, 194039217Sgibbs ext_msg.req_ack_offset, 194139217Sgibbs ADV_TRANS_GOAL|ADV_TRANS_ACTIVE); 194239217Sgibbs 194339217Sgibbs /* Offset too high or large period forced async */ 194439217Sgibbs if (orig_offset != ext_msg.req_ack_offset) 194539217Sgibbs sdtr_accept = FALSE; 194639217Sgibbs 194739217Sgibbs if (sdtr_accept && (q_cntl & QC_MSG_OUT)) { 194839217Sgibbs /* Valid response to our requested negotiation */ 194939217Sgibbs q_cntl &= ~QC_MSG_OUT; 195039217Sgibbs } else { 195139217Sgibbs /* Must Respond */ 195239217Sgibbs q_cntl |= QC_MSG_OUT; 195339217Sgibbs adv_msgout_sdtr(adv, ext_msg.xfer_period, 195439217Sgibbs ext_msg.req_ack_offset); 195539217Sgibbs } 195639217Sgibbs 195739217Sgibbs } else if (ext_msg.msg_type == MSG_EXTENDED 195839217Sgibbs && ext_msg.msg_req == MSG_EXT_WDTR 195939217Sgibbs && ext_msg.msg_len == MSG_EXT_WDTR_LEN) { 196039217Sgibbs 196139217Sgibbs ext_msg.wdtr_width = 0; 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 } else { 196739217Sgibbs 196839217Sgibbs ext_msg.msg_type = MSG_MESSAGE_REJECT; 196939217Sgibbs adv_write_lram_16_multi(adv, ADVV_MSGOUT_BEG, 197039217Sgibbs (u_int16_t *)&ext_msg, 197139217Sgibbs sizeof(ext_msg) >> 1); 197239217Sgibbs q_cntl |= QC_MSG_OUT; 197339217Sgibbs } 197439217Sgibbs adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_CNTL, q_cntl); 197539217Sgibbs} 197639217Sgibbs 197739217Sgibbsstatic void 197839217Sgibbsadv_msgout_sdtr(struct adv_softc *adv, u_int8_t sdtr_period, 197939217Sgibbs u_int8_t sdtr_offset) 198039217Sgibbs{ 198139217Sgibbs struct ext_msg sdtr_buf; 198239217Sgibbs 198318781Sgibbs sdtr_buf.msg_type = MSG_EXTENDED; 198418781Sgibbs sdtr_buf.msg_len = MSG_EXT_SDTR_LEN; 198518781Sgibbs sdtr_buf.msg_req = MSG_EXT_SDTR; 198618781Sgibbs sdtr_buf.xfer_period = sdtr_period; 198718781Sgibbs sdtr_offset &= ADV_SYN_MAX_OFFSET; 198818781Sgibbs sdtr_buf.req_ack_offset = sdtr_offset; 198918781Sgibbs adv_write_lram_16_multi(adv, ADVV_MSGOUT_BEG, 199018781Sgibbs (u_int16_t *) &sdtr_buf, 199118781Sgibbs sizeof(sdtr_buf) / 2); 199218781Sgibbs} 199318781Sgibbs 199439217Sgibbsint 199539217Sgibbsadv_abort_ccb(struct adv_softc *adv, int target, int lun, union ccb *ccb, 199639217Sgibbs u_int32_t status, int queued_only) 199718781Sgibbs{ 199839217Sgibbs u_int16_t q_addr; 199939217Sgibbs u_int8_t q_no; 200039217Sgibbs struct adv_q_done_info scsiq_buf; 200139217Sgibbs struct adv_q_done_info *scsiq; 200239217Sgibbs u_int8_t target_ix; 200339217Sgibbs int count; 200418781Sgibbs 2005241492Sjhb if (!dumping) 2006241492Sjhb mtx_assert(&adv->lock, MA_OWNED); 200739217Sgibbs scsiq = &scsiq_buf; 200839217Sgibbs target_ix = ADV_TIDLUN_TO_IX(target, lun); 200939217Sgibbs count = 0; 201039217Sgibbs for (q_no = ADV_MIN_ACTIVE_QNO; q_no <= adv->max_openings; q_no++) { 201155945Sgibbs struct adv_ccb_info *ccb_info; 201239217Sgibbs q_addr = ADV_QNO_TO_QADDR(q_no); 201339217Sgibbs 201439217Sgibbs adv_copy_lram_doneq(adv, q_addr, scsiq, adv->max_dma_count); 201555945Sgibbs ccb_info = &adv->ccb_infos[scsiq->d2.ccb_index]; 201639217Sgibbs if (((scsiq->q_status & QS_READY) != 0) 201739217Sgibbs && ((scsiq->q_status & QS_ABORTED) == 0) 201839217Sgibbs && ((scsiq->cntl & QCSG_SG_XFER_LIST) == 0) 201939217Sgibbs && (scsiq->d2.target_ix == target_ix) 202039217Sgibbs && (queued_only == 0 202139217Sgibbs || !(scsiq->q_status & (QS_DISC1|QS_DISC2|QS_BUSY|QS_DONE))) 202255945Sgibbs && (ccb == NULL || (ccb == ccb_info->ccb))) { 202339217Sgibbs union ccb *aborted_ccb; 202439217Sgibbs struct adv_ccb_info *cinfo; 202539217Sgibbs 202639217Sgibbs scsiq->q_status |= QS_ABORTED; 202739217Sgibbs adv_write_lram_8(adv, q_addr + ADV_SCSIQ_B_STATUS, 202839217Sgibbs scsiq->q_status); 202955945Sgibbs aborted_ccb = ccb_info->ccb; 203039217Sgibbs /* Don't clobber earlier error codes */ 203139217Sgibbs if ((aborted_ccb->ccb_h.status & CAM_STATUS_MASK) 203239217Sgibbs == CAM_REQ_INPROG) 203339217Sgibbs aborted_ccb->ccb_h.status |= status; 203439217Sgibbs cinfo = (struct adv_ccb_info *) 203539217Sgibbs aborted_ccb->ccb_h.ccb_cinfo_ptr; 203639217Sgibbs cinfo->state |= ACCB_ABORT_QUEUED; 203739217Sgibbs count++; 203818781Sgibbs } 203918781Sgibbs } 204039217Sgibbs return (count); 204118781Sgibbs} 204218781Sgibbs 204339217Sgibbsint 204455945Sgibbsadv_reset_bus(struct adv_softc *adv, int initiate_bus_reset) 204539217Sgibbs{ 204639217Sgibbs int count; 204739217Sgibbs int i; 204839217Sgibbs union ccb *ccb; 204939217Sgibbs 2050241492Sjhb if (!dumping) 2051241492Sjhb mtx_assert(&adv->lock, MA_OWNED); 205255945Sgibbs i = 200; 205355945Sgibbs while ((ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_SCSI_RESET_ACTIVE) != 0 205455945Sgibbs && i--) 205555945Sgibbs DELAY(1000); 205655945Sgibbs adv_reset_chip(adv, initiate_bus_reset); 205739217Sgibbs adv_reinit_lram(adv); 205855945Sgibbs for (i = 0; i <= ADV_MAX_TID; i++) 205955945Sgibbs adv_set_syncrate(adv, NULL, i, /*period*/0, 206055945Sgibbs /*offset*/0, ADV_TRANS_CUR); 206139217Sgibbs ADV_OUTW(adv, ADV_REG_PROG_COUNTER, ADV_MCODE_START_ADDR); 206239217Sgibbs 2063298955Spfg /* Tell the XPT layer that a bus reset occurred */ 206439217Sgibbs if (adv->path != NULL) 206539217Sgibbs xpt_async(AC_BUS_RESET, adv->path, NULL); 206639217Sgibbs 206739217Sgibbs count = 0; 206839217Sgibbs while ((ccb = (union ccb *)LIST_FIRST(&adv->pending_ccbs)) != NULL) { 206939217Sgibbs if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) 207039217Sgibbs ccb->ccb_h.status |= CAM_SCSI_BUS_RESET; 207139217Sgibbs adv_done(adv, ccb, QD_ABORTED_BY_HOST, 0, 0, 0); 207239217Sgibbs count++; 207339217Sgibbs } 207439217Sgibbs 207539217Sgibbs adv_start_chip(adv); 207639217Sgibbs return (count); 207739217Sgibbs} 207839217Sgibbs 207918781Sgibbsstatic void 208039217Sgibbsadv_set_sdtr_reg_at_id(struct adv_softc *adv, int tid, u_int8_t sdtr_data) 208118781Sgibbs{ 208239217Sgibbs int orig_id; 208339217Sgibbs 208439217Sgibbs adv_set_bank(adv, 1); 208539217Sgibbs orig_id = ffs(ADV_INB(adv, ADV_HOST_SCSIID)) - 1; 208639217Sgibbs ADV_OUTB(adv, ADV_HOST_SCSIID, tid); 208739217Sgibbs if (ADV_INB(adv, ADV_HOST_SCSIID) == (0x01 << tid)) { 208839217Sgibbs adv_set_bank(adv, 0); 208939217Sgibbs ADV_OUTB(adv, ADV_SYN_OFFSET, sdtr_data); 209039217Sgibbs } 209139217Sgibbs adv_set_bank(adv, 1); 209239217Sgibbs ADV_OUTB(adv, ADV_HOST_SCSIID, orig_id); 209339217Sgibbs adv_set_bank(adv, 0); 209418781Sgibbs} 2095