advlib.c revision 153072
1139749Simp/*- 218781Sgibbs * Low level routines for the Advanced Systems Inc. SCSI controllers chips 318781Sgibbs * 455945Sgibbs * Copyright (c) 1996-1997, 1999-2000 Justin Gibbs. 518781Sgibbs * All rights reserved. 618781Sgibbs * 718781Sgibbs * Redistribution and use in source and binary forms, with or without 818781Sgibbs * modification, are permitted provided that the following conditions 918781Sgibbs * are met: 1018781Sgibbs * 1. Redistributions of source code must retain the above copyright 1139217Sgibbs * notice, this list of conditions, and the following disclaimer, 1239217Sgibbs * without modification, immediately at the beginning of the file. 1318781Sgibbs * 2. Redistributions in binary form must reproduce the above copyright 1418781Sgibbs * notice, this list of conditions and the following disclaimer in the 1518781Sgibbs * documentation and/or other materials provided with the distribution. 1618781Sgibbs * 3. The name of the author may not be used to endorse or promote products 1718781Sgibbs * derived from this software without specific prior written permission. 1818781Sgibbs * 1918781Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2018781Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2118781Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2218781Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2318781Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2418781Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2518781Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2618781Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2718781Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2818781Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2918781Sgibbs * SUCH DAMAGE. 3018781Sgibbs */ 31139749Simp/*- 3218781Sgibbs * Ported from: 3318781Sgibbs * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters 3418781Sgibbs * 3518781Sgibbs * Copyright (c) 1995-1996 Advanced System Products, Inc. 3618781Sgibbs * All Rights Reserved. 3718781Sgibbs * 3818781Sgibbs * Redistribution and use in source and binary forms, with or without 3918781Sgibbs * modification, are permitted provided that redistributions of source 4018781Sgibbs * code retain the above copyright notice and this comment without 4118781Sgibbs * modification. 4218781Sgibbs */ 4318781Sgibbs 44119418Sobrien#include <sys/cdefs.h> 45119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/advansys/advlib.c 153072 2005-12-04 02:12:43Z ru $"); 46119418Sobrien 4718781Sgibbs#include <sys/param.h> 4845846Sgibbs#include <sys/kernel.h> 4918781Sgibbs#include <sys/systm.h> 5018781Sgibbs 5139217Sgibbs#include <machine/bus.h> 5259082Snyan#include <machine/resource.h> 5359082Snyan#include <sys/bus.h> 5459082Snyan#include <sys/rman.h> 5518781Sgibbs 5639217Sgibbs#include <cam/cam.h> 5739217Sgibbs#include <cam/cam_ccb.h> 5839217Sgibbs#include <cam/cam_sim.h> 5939217Sgibbs#include <cam/cam_xpt_sim.h> 6018781Sgibbs 6139217Sgibbs#include <cam/scsi/scsi_all.h> 6239217Sgibbs#include <cam/scsi/scsi_message.h> 6339217Sgibbs#include <cam/scsi/scsi_da.h> 6439217Sgibbs#include <cam/scsi/scsi_cd.h> 6539217Sgibbs 6618781Sgibbs#include <vm/vm.h> 6718781Sgibbs#include <vm/vm_param.h> 6818781Sgibbs#include <vm/pmap.h> 6918781Sgibbs 7039217Sgibbs#include <dev/advansys/advansys.h> 7118781Sgibbs#include <dev/advansys/advmcode.h> 7218781Sgibbs 7339217Sgibbsstruct adv_quirk_entry { 7439217Sgibbs struct scsi_inquiry_pattern inq_pat; 7539217Sgibbs u_int8_t quirks; 7639217Sgibbs#define ADV_QUIRK_FIX_ASYN_XFER_ALWAYS 0x01 7739217Sgibbs#define ADV_QUIRK_FIX_ASYN_XFER 0x02 7839217Sgibbs}; 7939217Sgibbs 8039217Sgibbsstatic struct adv_quirk_entry adv_quirk_table[] = 8139217Sgibbs{ 8239217Sgibbs { 8339217Sgibbs { T_CDROM, SIP_MEDIA_REMOVABLE, "HP", "*", "*" }, 8439217Sgibbs ADV_QUIRK_FIX_ASYN_XFER_ALWAYS|ADV_QUIRK_FIX_ASYN_XFER 8539217Sgibbs }, 8639217Sgibbs { 8739217Sgibbs { T_CDROM, SIP_MEDIA_REMOVABLE, "NEC", "CD-ROM DRIVE", "*" }, 8839217Sgibbs 0 8939217Sgibbs }, 9039217Sgibbs { 9139217Sgibbs { 9239217Sgibbs T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, 9339217Sgibbs "TANDBERG", " TDC 36", "*" 9439217Sgibbs }, 9539217Sgibbs 0 9639217Sgibbs }, 9739217Sgibbs { 9839217Sgibbs { T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "WANGTEK", "*", "*" }, 9939217Sgibbs 0 10039217Sgibbs }, 10139217Sgibbs { 10239217Sgibbs { 10339217Sgibbs T_PROCESSOR, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED, 10439217Sgibbs "*", "*", "*" 10539217Sgibbs }, 10639217Sgibbs 0 10739217Sgibbs }, 10839217Sgibbs { 10939217Sgibbs { 11039217Sgibbs T_SCANNER, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED, 11139217Sgibbs "*", "*", "*" 11239217Sgibbs }, 11339217Sgibbs 0 11439217Sgibbs }, 11539217Sgibbs { 11639217Sgibbs /* Default quirk entry */ 11739217Sgibbs { 11839217Sgibbs T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED, 11939217Sgibbs /*vendor*/"*", /*product*/"*", /*revision*/"*" 12039217Sgibbs }, 12139217Sgibbs ADV_QUIRK_FIX_ASYN_XFER, 12239217Sgibbs } 12339217Sgibbs}; 12439217Sgibbs 12518781Sgibbs/* 12618781Sgibbs * Allowable periods in ns 12718781Sgibbs */ 12845575Seivindstatic u_int8_t adv_sdtr_period_tbl[] = 12918781Sgibbs{ 13018781Sgibbs 25, 13118781Sgibbs 30, 13218781Sgibbs 35, 13318781Sgibbs 40, 13418781Sgibbs 50, 13518781Sgibbs 60, 13618781Sgibbs 70, 13718781Sgibbs 85 13818781Sgibbs}; 13918781Sgibbs 14045575Seivindstatic u_int8_t adv_sdtr_period_tbl_ultra[] = 14139217Sgibbs{ 14239217Sgibbs 12, 14339217Sgibbs 19, 14439217Sgibbs 25, 14539217Sgibbs 32, 14639217Sgibbs 38, 14739217Sgibbs 44, 14839217Sgibbs 50, 14939217Sgibbs 57, 15039217Sgibbs 63, 15139217Sgibbs 69, 15239217Sgibbs 75, 15339217Sgibbs 82, 15439217Sgibbs 88, 15539217Sgibbs 94, 15639217Sgibbs 100, 15739217Sgibbs 107 15818781Sgibbs}; 15918781Sgibbs 16039217Sgibbsstruct ext_msg { 16139217Sgibbs u_int8_t msg_type; 16239217Sgibbs u_int8_t msg_len; 16339217Sgibbs u_int8_t msg_req; 16439217Sgibbs union { 16539217Sgibbs struct { 16639217Sgibbs u_int8_t sdtr_xfer_period; 16739217Sgibbs u_int8_t sdtr_req_ack_offset; 16839217Sgibbs } sdtr; 16939217Sgibbs struct { 17039217Sgibbs u_int8_t wdtr_width; 17139217Sgibbs } wdtr; 17239217Sgibbs struct { 17339217Sgibbs u_int8_t mdp[4]; 17439217Sgibbs } mdp; 17539217Sgibbs } u_ext_msg; 17639217Sgibbs u_int8_t res; 17739217Sgibbs}; 17839217Sgibbs 17939217Sgibbs#define xfer_period u_ext_msg.sdtr.sdtr_xfer_period 18039217Sgibbs#define req_ack_offset u_ext_msg.sdtr.sdtr_req_ack_offset 18139217Sgibbs#define wdtr_width u_ext_msg.wdtr.wdtr_width 18239217Sgibbs#define mdp_b3 u_ext_msg.mdp_b3 18339217Sgibbs#define mdp_b2 u_ext_msg.mdp_b2 18439217Sgibbs#define mdp_b1 u_ext_msg.mdp_b1 18539217Sgibbs#define mdp_b0 u_ext_msg.mdp_b0 18639217Sgibbs 18718781Sgibbs/* 18818781Sgibbs * Some of the early PCI adapters have problems with 18939217Sgibbs * async transfers. Instead use an offset of 1. 19018781Sgibbs */ 19139217Sgibbs#define ASYN_SDTR_DATA_FIX_PCI_REV_AB 0x41 19218781Sgibbs 19318781Sgibbs/* LRAM routines */ 19439217Sgibbsstatic void adv_read_lram_16_multi(struct adv_softc *adv, u_int16_t s_addr, 19539217Sgibbs u_int16_t *buffer, int count); 19639217Sgibbsstatic void adv_write_lram_16_multi(struct adv_softc *adv, 19739217Sgibbs u_int16_t s_addr, u_int16_t *buffer, 19839217Sgibbs int count); 19939217Sgibbsstatic void adv_mset_lram_16(struct adv_softc *adv, u_int16_t s_addr, 20039217Sgibbs u_int16_t set_value, int count); 20139217Sgibbsstatic u_int32_t adv_msum_lram_16(struct adv_softc *adv, u_int16_t s_addr, 20239217Sgibbs int count); 20318781Sgibbs 20439217Sgibbsstatic int adv_write_and_verify_lram_16(struct adv_softc *adv, 20539217Sgibbs u_int16_t addr, u_int16_t value); 20639217Sgibbsstatic u_int32_t adv_read_lram_32(struct adv_softc *adv, u_int16_t addr); 20718781Sgibbs 20818781Sgibbs 20939217Sgibbsstatic void adv_write_lram_32(struct adv_softc *adv, u_int16_t addr, 21039217Sgibbs u_int32_t value); 21139217Sgibbsstatic void adv_write_lram_32_multi(struct adv_softc *adv, 21239217Sgibbs u_int16_t s_addr, u_int32_t *buffer, 21339217Sgibbs int count); 21418781Sgibbs 21518781Sgibbs/* EEPROM routines */ 21639217Sgibbsstatic u_int16_t adv_read_eeprom_16(struct adv_softc *adv, u_int8_t addr); 21739217Sgibbsstatic u_int16_t adv_write_eeprom_16(struct adv_softc *adv, u_int8_t addr, 21839217Sgibbs u_int16_t value); 21939217Sgibbsstatic int adv_write_eeprom_cmd_reg(struct adv_softc *adv, 22039217Sgibbs u_int8_t cmd_reg); 22139217Sgibbsstatic int adv_set_eeprom_config_once(struct adv_softc *adv, 22239217Sgibbs struct adv_eeprom_config *eeconfig); 22318781Sgibbs 22418781Sgibbs/* Initialization */ 22539217Sgibbsstatic u_int32_t adv_load_microcode(struct adv_softc *adv, u_int16_t s_addr, 22639217Sgibbs u_int16_t *mcode_buf, u_int16_t mcode_size); 22718781Sgibbs 22839217Sgibbsstatic void adv_reinit_lram(struct adv_softc *adv); 22939217Sgibbsstatic void adv_init_lram(struct adv_softc *adv); 23039217Sgibbsstatic int adv_init_microcode_var(struct adv_softc *adv); 23139217Sgibbsstatic void adv_init_qlink_var(struct adv_softc *adv); 23239217Sgibbs 23318781Sgibbs/* Interrupts */ 23439217Sgibbsstatic void adv_disable_interrupt(struct adv_softc *adv); 23539217Sgibbsstatic void adv_enable_interrupt(struct adv_softc *adv); 23639217Sgibbsstatic void adv_toggle_irq_act(struct adv_softc *adv); 23718781Sgibbs 23818781Sgibbs/* Chip Control */ 23939217Sgibbsstatic int adv_host_req_chip_halt(struct adv_softc *adv); 24039217Sgibbsstatic void adv_set_chip_ih(struct adv_softc *adv, u_int16_t ins_code); 241153072Sru#if 0 24239217Sgibbsstatic u_int8_t adv_get_chip_scsi_ctrl(struct adv_softc *adv); 24318781Sgibbs#endif 24418781Sgibbs 24518781Sgibbs/* Queue handling and execution */ 24640027Sgibbsstatic __inline int 24740027Sgibbs adv_sgcount_to_qcount(int sgcount); 24840027Sgibbs 24940027Sgibbsstatic __inline int 25040027Sgibbsadv_sgcount_to_qcount(int sgcount) 25140027Sgibbs{ 25240027Sgibbs int n_sg_list_qs; 25340027Sgibbs 25440027Sgibbs n_sg_list_qs = ((sgcount - 1) / ADV_SG_LIST_PER_Q); 25540027Sgibbs if (((sgcount - 1) % ADV_SG_LIST_PER_Q) != 0) 25640027Sgibbs n_sg_list_qs++; 25740027Sgibbs return (n_sg_list_qs + 1); 25840027Sgibbs} 25940027Sgibbs 260111409Sobrien#if BYTE_ORDER == BIG_ENDIAN 261111342Sobrienstatic void adv_adj_endian_qdone_info(struct adv_q_done_info *); 262111342Sobrienstatic void adv_adj_scsiq_endian(struct adv_scsi_q *); 263111409Sobrien#endif 26439217Sgibbsstatic void adv_get_q_info(struct adv_softc *adv, u_int16_t s_addr, 26539217Sgibbs u_int16_t *inbuf, int words); 26639217Sgibbsstatic u_int adv_get_num_free_queues(struct adv_softc *adv, u_int8_t n_qs); 26739217Sgibbsstatic u_int8_t adv_alloc_free_queues(struct adv_softc *adv, 26839217Sgibbs u_int8_t free_q_head, u_int8_t n_free_q); 26939217Sgibbsstatic u_int8_t adv_alloc_free_queue(struct adv_softc *adv, 27039217Sgibbs u_int8_t free_q_head); 27139217Sgibbsstatic int adv_send_scsi_queue(struct adv_softc *adv, 27239217Sgibbs struct adv_scsi_q *scsiq, 27339217Sgibbs u_int8_t n_q_required); 27439217Sgibbsstatic void adv_put_ready_sg_list_queue(struct adv_softc *adv, 27539217Sgibbs struct adv_scsi_q *scsiq, 27639217Sgibbs u_int q_no); 27739217Sgibbsstatic void adv_put_ready_queue(struct adv_softc *adv, 27839217Sgibbs struct adv_scsi_q *scsiq, u_int q_no); 27939217Sgibbsstatic void adv_put_scsiq(struct adv_softc *adv, u_int16_t s_addr, 28039217Sgibbs u_int16_t *buffer, int words); 28118781Sgibbs 28239217Sgibbs/* Messages */ 28339217Sgibbsstatic void adv_handle_extmsg_in(struct adv_softc *adv, 28439217Sgibbs u_int16_t halt_q_addr, u_int8_t q_cntl, 28539217Sgibbs target_bit_vector target_id, 28639217Sgibbs int tid); 28739217Sgibbsstatic void adv_msgout_sdtr(struct adv_softc *adv, u_int8_t sdtr_period, 28839217Sgibbs u_int8_t sdtr_offset); 28939217Sgibbsstatic void adv_set_sdtr_reg_at_id(struct adv_softc *adv, int id, 29039217Sgibbs u_int8_t sdtr_data); 29118781Sgibbs 29218781Sgibbs 29319426Sgibbs/* Exported functions first */ 29418781Sgibbs 29539217Sgibbsvoid 29639217Sgibbsadvasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg) 29739217Sgibbs{ 29818781Sgibbs struct adv_softc *adv; 29939217Sgibbs 30039217Sgibbs adv = (struct adv_softc *)callback_arg; 30139217Sgibbs switch (code) { 30239217Sgibbs case AC_FOUND_DEVICE: 30339217Sgibbs { 30439217Sgibbs struct ccb_getdev *cgd; 30539217Sgibbs target_bit_vector target_mask; 30639217Sgibbs int num_entries; 30739217Sgibbs caddr_t match; 30839217Sgibbs struct adv_quirk_entry *entry; 30939217Sgibbs struct adv_target_transinfo* tinfo; 31039217Sgibbs 31139217Sgibbs cgd = (struct ccb_getdev *)arg; 31239217Sgibbs 31339217Sgibbs target_mask = ADV_TID_TO_TARGET_MASK(cgd->ccb_h.target_id); 31439217Sgibbs 31539217Sgibbs num_entries = sizeof(adv_quirk_table)/sizeof(*adv_quirk_table); 31639217Sgibbs match = cam_quirkmatch((caddr_t)&cgd->inq_data, 31739217Sgibbs (caddr_t)adv_quirk_table, 31839217Sgibbs num_entries, sizeof(*adv_quirk_table), 31939217Sgibbs scsi_inquiry_match); 32039217Sgibbs 32139217Sgibbs if (match == NULL) 32239217Sgibbs panic("advasync: device didn't match wildcard entry!!"); 32339217Sgibbs 32439217Sgibbs entry = (struct adv_quirk_entry *)match; 32539217Sgibbs 32639217Sgibbs if (adv->bug_fix_control & ADV_BUG_FIX_ASYN_USE_SYN) { 32739217Sgibbs if ((entry->quirks & ADV_QUIRK_FIX_ASYN_XFER_ALWAYS)!=0) 32839217Sgibbs adv->fix_asyn_xfer_always |= target_mask; 32939217Sgibbs else 33039217Sgibbs adv->fix_asyn_xfer_always &= ~target_mask; 33139217Sgibbs /* 33239217Sgibbs * We start out life with all bits set and clear them 33339217Sgibbs * after we've determined that the fix isn't necessary. 33439217Sgibbs * It may well be that we've already cleared a target 33539217Sgibbs * before the full inquiry session completes, so don't 33639217Sgibbs * gratuitously set a target bit even if it has this 33739217Sgibbs * quirk. But, if the quirk exonerates a device, clear 33839217Sgibbs * the bit now. 33939217Sgibbs */ 34039217Sgibbs if ((entry->quirks & ADV_QUIRK_FIX_ASYN_XFER) == 0) 34139217Sgibbs adv->fix_asyn_xfer &= ~target_mask; 34239217Sgibbs } 34339217Sgibbs /* 34439217Sgibbs * Reset our sync settings now that we've determined 34539217Sgibbs * what quirks are in effect for the device. 34639217Sgibbs */ 34739217Sgibbs tinfo = &adv->tinfo[cgd->ccb_h.target_id]; 34839217Sgibbs adv_set_syncrate(adv, cgd->ccb_h.path, 34939217Sgibbs cgd->ccb_h.target_id, 35039217Sgibbs tinfo->current.period, 35139217Sgibbs tinfo->current.offset, 35239217Sgibbs ADV_TRANS_CUR); 35339217Sgibbs break; 35439217Sgibbs } 35539217Sgibbs case AC_LOST_DEVICE: 35639217Sgibbs { 35739217Sgibbs u_int target_mask; 35839217Sgibbs 35939217Sgibbs if (adv->bug_fix_control & ADV_BUG_FIX_ASYN_USE_SYN) { 36039217Sgibbs target_mask = 0x01 << xpt_path_target_id(path); 36139217Sgibbs adv->fix_asyn_xfer |= target_mask; 36239217Sgibbs } 36339217Sgibbs 36439217Sgibbs /* 36539217Sgibbs * Revert to async transfers 36639217Sgibbs * for the next device. 36739217Sgibbs */ 36839217Sgibbs adv_set_syncrate(adv, /*path*/NULL, 36939217Sgibbs xpt_path_target_id(path), 37039217Sgibbs /*period*/0, 37139217Sgibbs /*offset*/0, 37239217Sgibbs ADV_TRANS_GOAL|ADV_TRANS_CUR); 37339217Sgibbs } 37439217Sgibbs default: 37539217Sgibbs break; 37639217Sgibbs } 37739217Sgibbs} 37839217Sgibbs 37939217Sgibbsvoid 38039217Sgibbsadv_set_bank(struct adv_softc *adv, u_int8_t bank) 38118781Sgibbs{ 38239217Sgibbs u_int8_t control; 38339217Sgibbs 38439217Sgibbs /* 38539217Sgibbs * Start out with the bank reset to 0 38639217Sgibbs */ 38739217Sgibbs control = ADV_INB(adv, ADV_CHIP_CTRL) 38839217Sgibbs & (~(ADV_CC_SINGLE_STEP | ADV_CC_TEST 38939217Sgibbs | ADV_CC_DIAG | ADV_CC_SCSI_RESET 39039217Sgibbs | ADV_CC_CHIP_RESET | ADV_CC_BANK_ONE)); 39139217Sgibbs if (bank == 1) { 39239217Sgibbs control |= ADV_CC_BANK_ONE; 39339217Sgibbs } else if (bank == 2) { 39439217Sgibbs control |= ADV_CC_DIAG | ADV_CC_BANK_ONE; 39539217Sgibbs } 39639217Sgibbs ADV_OUTB(adv, ADV_CHIP_CTRL, control); 39739217Sgibbs} 39839217Sgibbs 39939217Sgibbsu_int8_t 40039217Sgibbsadv_read_lram_8(struct adv_softc *adv, u_int16_t addr) 40139217Sgibbs{ 40218781Sgibbs u_int8_t byte_data; 40318781Sgibbs u_int16_t word_data; 40418781Sgibbs 40518781Sgibbs /* 40618781Sgibbs * LRAM is accessed on 16bit boundaries. 40718781Sgibbs */ 40818781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, addr & 0xFFFE); 40918781Sgibbs word_data = ADV_INW(adv, ADV_LRAM_DATA); 41018781Sgibbs if (addr & 1) { 41118781Sgibbs#if BYTE_ORDER == BIG_ENDIAN 41218781Sgibbs byte_data = (u_int8_t)(word_data & 0xFF); 41318781Sgibbs#else 41418781Sgibbs byte_data = (u_int8_t)((word_data >> 8) & 0xFF); 41518781Sgibbs#endif 41618781Sgibbs } else { 41718781Sgibbs#if BYTE_ORDER == BIG_ENDIAN 41818781Sgibbs byte_data = (u_int8_t)((word_data >> 8) & 0xFF); 41918781Sgibbs#else 42018781Sgibbs byte_data = (u_int8_t)(word_data & 0xFF); 42118781Sgibbs#endif 42218781Sgibbs } 42318781Sgibbs return (byte_data); 42418781Sgibbs} 42518781Sgibbs 42618781Sgibbsvoid 42739217Sgibbsadv_write_lram_8(struct adv_softc *adv, u_int16_t addr, u_int8_t value) 42818781Sgibbs{ 42918781Sgibbs u_int16_t word_data; 43018781Sgibbs 43118781Sgibbs word_data = adv_read_lram_16(adv, addr & 0xFFFE); 43218781Sgibbs if (addr & 1) { 43318781Sgibbs word_data &= 0x00FF; 43418781Sgibbs word_data |= (((u_int8_t)value << 8) & 0xFF00); 43518781Sgibbs } else { 43618781Sgibbs word_data &= 0xFF00; 43718781Sgibbs word_data |= ((u_int8_t)value & 0x00FF); 43818781Sgibbs } 43918781Sgibbs adv_write_lram_16(adv, addr & 0xFFFE, word_data); 44018781Sgibbs} 44118781Sgibbs 44218781Sgibbs 44318781Sgibbsu_int16_t 44439217Sgibbsadv_read_lram_16(struct adv_softc *adv, u_int16_t addr) 44518781Sgibbs{ 44618781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, addr); 44718781Sgibbs return (ADV_INW(adv, ADV_LRAM_DATA)); 44818781Sgibbs} 44918781Sgibbs 45018781Sgibbsvoid 45139217Sgibbsadv_write_lram_16(struct adv_softc *adv, u_int16_t addr, u_int16_t value) 45218781Sgibbs{ 45318781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, addr); 45418781Sgibbs ADV_OUTW(adv, ADV_LRAM_DATA, value); 45518781Sgibbs} 45618781Sgibbs 45718781Sgibbs/* 45839217Sgibbs * Determine if there is a board at "iobase" by looking 45939217Sgibbs * for the AdvanSys signatures. Return 1 if a board is 46039217Sgibbs * found, 0 otherwise. 46118781Sgibbs */ 46239217Sgibbsint 46339217Sgibbsadv_find_signature(bus_space_tag_t tag, bus_space_handle_t bsh) 46439217Sgibbs{ 46539217Sgibbs u_int16_t signature; 46639217Sgibbs 46739217Sgibbs if (bus_space_read_1(tag, bsh, ADV_SIGNATURE_BYTE) == ADV_1000_ID1B) { 46839217Sgibbs signature = bus_space_read_2(tag, bsh, ADV_SIGNATURE_WORD); 46939217Sgibbs if ((signature == ADV_1000_ID0W) 47039217Sgibbs || (signature == ADV_1000_ID0W_FIX)) 47139217Sgibbs return (1); 47239217Sgibbs } 47339217Sgibbs return (0); 47439217Sgibbs} 47539217Sgibbs 47618781Sgibbsvoid 47739217Sgibbsadv_lib_init(struct adv_softc *adv) 47818781Sgibbs{ 47939217Sgibbs if ((adv->type & ADV_ULTRA) != 0) { 48039217Sgibbs adv->sdtr_period_tbl = adv_sdtr_period_tbl_ultra; 48139217Sgibbs adv->sdtr_period_tbl_size = sizeof(adv_sdtr_period_tbl_ultra); 48239217Sgibbs } else { 48339217Sgibbs adv->sdtr_period_tbl = adv_sdtr_period_tbl; 48439217Sgibbs adv->sdtr_period_tbl_size = sizeof(adv_sdtr_period_tbl); 48539217Sgibbs } 48618781Sgibbs} 48718781Sgibbs 48818781Sgibbsu_int16_t 48939217Sgibbsadv_get_eeprom_config(struct adv_softc *adv, struct 49039217Sgibbs adv_eeprom_config *eeprom_config) 49118781Sgibbs{ 49218781Sgibbs u_int16_t sum; 49318781Sgibbs u_int16_t *wbuf; 49418781Sgibbs u_int8_t cfg_beg; 49518781Sgibbs u_int8_t cfg_end; 49618781Sgibbs u_int8_t s_addr; 49718781Sgibbs 49818781Sgibbs wbuf = (u_int16_t *)eeprom_config; 49918781Sgibbs sum = 0; 50018781Sgibbs 50118781Sgibbs for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) { 50218781Sgibbs *wbuf = adv_read_eeprom_16(adv, s_addr); 50318781Sgibbs sum += *wbuf; 50418781Sgibbs } 50518781Sgibbs 50618781Sgibbs if (adv->type & ADV_VL) { 50718781Sgibbs cfg_beg = ADV_EEPROM_CFG_BEG_VL; 50818781Sgibbs cfg_end = ADV_EEPROM_MAX_ADDR_VL; 50918781Sgibbs } else { 51018781Sgibbs cfg_beg = ADV_EEPROM_CFG_BEG; 51118781Sgibbs cfg_end = ADV_EEPROM_MAX_ADDR; 51218781Sgibbs } 51318781Sgibbs 51418781Sgibbs for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) { 51518781Sgibbs *wbuf = adv_read_eeprom_16(adv, s_addr); 51618781Sgibbs sum += *wbuf; 517153072Sru#ifdef ADV_DEBUG_EEPROM 51818781Sgibbs printf("Addr 0x%x: 0x%04x\n", s_addr, *wbuf); 51918781Sgibbs#endif 52018781Sgibbs } 52118781Sgibbs *wbuf = adv_read_eeprom_16(adv, s_addr); 52218781Sgibbs return (sum); 52318781Sgibbs} 52418781Sgibbs 52518781Sgibbsint 52639217Sgibbsadv_set_eeprom_config(struct adv_softc *adv, 52739217Sgibbs struct adv_eeprom_config *eeprom_config) 52818781Sgibbs{ 52918781Sgibbs int retry; 53018781Sgibbs 53118781Sgibbs retry = 0; 53218781Sgibbs while (1) { 53318781Sgibbs if (adv_set_eeprom_config_once(adv, eeprom_config) == 0) { 53418781Sgibbs break; 53518781Sgibbs } 53618781Sgibbs if (++retry > ADV_EEPROM_MAX_RETRY) { 53718781Sgibbs break; 53818781Sgibbs } 53918781Sgibbs } 54018781Sgibbs return (retry > ADV_EEPROM_MAX_RETRY); 54118781Sgibbs} 54218781Sgibbs 54318781Sgibbsint 54455945Sgibbsadv_reset_chip(struct adv_softc *adv, int reset_bus) 54518781Sgibbs{ 54618781Sgibbs adv_stop_chip(adv); 54755945Sgibbs ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_CHIP_RESET | ADV_CC_HALT 54855945Sgibbs | (reset_bus ? ADV_CC_SCSI_RESET : 0)); 54955945Sgibbs DELAY(60); 55018781Sgibbs 55118781Sgibbs adv_set_chip_ih(adv, ADV_INS_RFLAG_WTM); 55218781Sgibbs adv_set_chip_ih(adv, ADV_INS_HALT); 55318781Sgibbs 55455945Sgibbs if (reset_bus) 55555945Sgibbs ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_CHIP_RESET | ADV_CC_HALT); 55655945Sgibbs 55718781Sgibbs ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_HALT); 55855945Sgibbs if (reset_bus) 55955945Sgibbs DELAY(200 * 1000); 56055945Sgibbs 56155945Sgibbs ADV_OUTW(adv, ADV_CHIP_STATUS, ADV_CIW_CLR_SCSI_RESET_INT); 56255945Sgibbs ADV_OUTW(adv, ADV_CHIP_STATUS, 0); 56318781Sgibbs return (adv_is_chip_halted(adv)); 56418781Sgibbs} 56518781Sgibbs 56618781Sgibbsint 56739217Sgibbsadv_test_external_lram(struct adv_softc* adv) 56818781Sgibbs{ 56918781Sgibbs u_int16_t q_addr; 57018781Sgibbs u_int16_t saved_value; 57118781Sgibbs int success; 57218781Sgibbs 57318781Sgibbs success = 0; 57418781Sgibbs 57518781Sgibbs q_addr = ADV_QNO_TO_QADDR(241); 57618781Sgibbs saved_value = adv_read_lram_16(adv, q_addr); 57718781Sgibbs if (adv_write_and_verify_lram_16(adv, q_addr, 0x55AA) == 0) { 57818781Sgibbs success = 1; 57918781Sgibbs adv_write_lram_16(adv, q_addr, saved_value); 58018781Sgibbs } 58118781Sgibbs return (success); 58218781Sgibbs} 58318781Sgibbs 58418781Sgibbs 58518781Sgibbsint 58639217Sgibbsadv_init_lram_and_mcode(struct adv_softc *adv) 58718781Sgibbs{ 58818781Sgibbs u_int32_t retval; 58939217Sgibbs 59018781Sgibbs adv_disable_interrupt(adv); 59118781Sgibbs 59218781Sgibbs adv_init_lram(adv); 59318781Sgibbs 59439217Sgibbs retval = adv_load_microcode(adv, 0, (u_int16_t *)adv_mcode, 59539217Sgibbs adv_mcode_size); 59618781Sgibbs if (retval != adv_mcode_chksum) { 59718781Sgibbs printf("adv%d: Microcode download failed checksum!\n", 59818781Sgibbs adv->unit); 59918781Sgibbs return (1); 60018781Sgibbs } 60118781Sgibbs 60218781Sgibbs if (adv_init_microcode_var(adv) != 0) 60318781Sgibbs return (1); 60418781Sgibbs 60518781Sgibbs adv_enable_interrupt(adv); 60618781Sgibbs return (0); 60718781Sgibbs} 60818781Sgibbs 60918781Sgibbsu_int8_t 61039217Sgibbsadv_get_chip_irq(struct adv_softc *adv) 61118781Sgibbs{ 61218781Sgibbs u_int16_t cfg_lsw; 61318781Sgibbs u_int8_t chip_irq; 61418781Sgibbs 61518781Sgibbs cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW); 61618781Sgibbs 61718781Sgibbs if ((adv->type & ADV_VL) != 0) { 61818781Sgibbs chip_irq = (u_int8_t)(((cfg_lsw >> 2) & 0x07)); 61918781Sgibbs if ((chip_irq == 0) || 62018781Sgibbs (chip_irq == 4) || 62118781Sgibbs (chip_irq == 7)) { 62218781Sgibbs return (0); 62318781Sgibbs } 62418781Sgibbs return (chip_irq + (ADV_MIN_IRQ_NO - 1)); 62518781Sgibbs } 62618781Sgibbs chip_irq = (u_int8_t)(((cfg_lsw >> 2) & 0x03)); 62718781Sgibbs if (chip_irq == 3) 62818781Sgibbs chip_irq += 2; 62918781Sgibbs return (chip_irq + ADV_MIN_IRQ_NO); 63018781Sgibbs} 63118781Sgibbs 63218781Sgibbsu_int8_t 63339217Sgibbsadv_set_chip_irq(struct adv_softc *adv, u_int8_t irq_no) 63418781Sgibbs{ 63518781Sgibbs u_int16_t cfg_lsw; 63618781Sgibbs 63718781Sgibbs if ((adv->type & ADV_VL) != 0) { 63818781Sgibbs if (irq_no != 0) { 63939217Sgibbs if ((irq_no < ADV_MIN_IRQ_NO) 64039217Sgibbs || (irq_no > ADV_MAX_IRQ_NO)) { 64118781Sgibbs irq_no = 0; 64218781Sgibbs } else { 64318781Sgibbs irq_no -= ADV_MIN_IRQ_NO - 1; 64418781Sgibbs } 64518781Sgibbs } 64618781Sgibbs cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW) & 0xFFE3; 64718781Sgibbs cfg_lsw |= 0x0010; 64818781Sgibbs ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw); 64918781Sgibbs adv_toggle_irq_act(adv); 65018781Sgibbs 65118781Sgibbs cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW) & 0xFFE0; 65218781Sgibbs cfg_lsw |= (irq_no & 0x07) << 2; 65318781Sgibbs ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw); 65418781Sgibbs adv_toggle_irq_act(adv); 65518781Sgibbs } else if ((adv->type & ADV_ISA) != 0) { 65618781Sgibbs if (irq_no == 15) 65718781Sgibbs irq_no -= 2; 65818781Sgibbs irq_no -= ADV_MIN_IRQ_NO; 65918781Sgibbs cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW) & 0xFFF3; 66018781Sgibbs cfg_lsw |= (irq_no & 0x03) << 2; 66118781Sgibbs ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw); 66218781Sgibbs } 66318781Sgibbs return (adv_get_chip_irq(adv)); 66418781Sgibbs} 66518781Sgibbs 66639217Sgibbsvoid 66739217Sgibbsadv_set_chip_scsiid(struct adv_softc *adv, int new_id) 66839217Sgibbs{ 66939217Sgibbs u_int16_t cfg_lsw; 67039217Sgibbs 67139217Sgibbs cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW); 67239217Sgibbs if (ADV_CONFIG_SCSIID(cfg_lsw) == new_id) 67339217Sgibbs return; 67439217Sgibbs cfg_lsw &= ~ADV_CFG_LSW_SCSIID; 67539217Sgibbs cfg_lsw |= (new_id & ADV_MAX_TID) << ADV_CFG_LSW_SCSIID_SHIFT; 67639217Sgibbs ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw); 67739217Sgibbs} 67839217Sgibbs 67918781Sgibbsint 68039217Sgibbsadv_execute_scsi_queue(struct adv_softc *adv, struct adv_scsi_q *scsiq, 68139217Sgibbs u_int32_t datalen) 68218781Sgibbs{ 68339217Sgibbs struct adv_target_transinfo* tinfo; 68439217Sgibbs u_int32_t *p_data_addr; 68539217Sgibbs u_int32_t *p_data_bcount; 68639217Sgibbs int disable_syn_offset_one_fix; 68718781Sgibbs int retval; 68818781Sgibbs u_int n_q_required; 68918781Sgibbs u_int32_t addr; 69018781Sgibbs u_int8_t sg_entry_cnt; 69118781Sgibbs u_int8_t target_ix; 69218781Sgibbs u_int8_t sg_entry_cnt_minus_one; 69318781Sgibbs u_int8_t tid_no; 69418781Sgibbs 69518781Sgibbs scsiq->q1.q_no = 0; 69618781Sgibbs retval = 1; /* Default to error case */ 69718781Sgibbs target_ix = scsiq->q2.target_ix; 69818781Sgibbs tid_no = ADV_TIX_TO_TID(target_ix); 69939217Sgibbs tinfo = &adv->tinfo[tid_no]; 70018781Sgibbs 70139217Sgibbs if (scsiq->cdbptr[0] == REQUEST_SENSE) { 70239217Sgibbs /* Renegotiate if appropriate. */ 70339217Sgibbs adv_set_syncrate(adv, /*struct cam_path */NULL, 70439217Sgibbs tid_no, /*period*/0, /*offset*/0, 70539217Sgibbs ADV_TRANS_CUR); 70639217Sgibbs if (tinfo->current.period != tinfo->goal.period) { 70739217Sgibbs adv_msgout_sdtr(adv, tinfo->goal.period, 70839217Sgibbs tinfo->goal.offset); 70918781Sgibbs scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT); 71018781Sgibbs } 71118781Sgibbs } 71218781Sgibbs 71318781Sgibbs if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) { 71418781Sgibbs sg_entry_cnt = scsiq->sg_head->entry_cnt; 71518781Sgibbs sg_entry_cnt_minus_one = sg_entry_cnt - 1; 71618781Sgibbs 71718781Sgibbs#ifdef DIAGNOSTIC 71818781Sgibbs if (sg_entry_cnt <= 1) 71939217Sgibbs panic("adv_execute_scsi_queue: Queue " 72039217Sgibbs "with QC_SG_HEAD set but %d segs.", sg_entry_cnt); 72118781Sgibbs 72218781Sgibbs if (sg_entry_cnt > ADV_MAX_SG_LIST) 72339217Sgibbs panic("adv_execute_scsi_queue: " 72439217Sgibbs "Queue with too many segs."); 72518781Sgibbs 72655945Sgibbs if ((adv->type & (ADV_ISA | ADV_VL | ADV_EISA)) != 0) { 72739505Sgibbs int i; 72839505Sgibbs 72918781Sgibbs for (i = 0; i < sg_entry_cnt_minus_one; i++) { 73018781Sgibbs addr = scsiq->sg_head->sg_list[i].addr + 73118781Sgibbs scsiq->sg_head->sg_list[i].bytes; 73218781Sgibbs 73318781Sgibbs if ((addr & 0x0003) != 0) 73439217Sgibbs panic("adv_execute_scsi_queue: SG " 73539217Sgibbs "with odd address or byte count"); 73618781Sgibbs } 73718781Sgibbs } 73818781Sgibbs#endif 73939217Sgibbs p_data_addr = 74039217Sgibbs &scsiq->sg_head->sg_list[sg_entry_cnt_minus_one].addr; 74139217Sgibbs p_data_bcount = 74239217Sgibbs &scsiq->sg_head->sg_list[sg_entry_cnt_minus_one].bytes; 74318781Sgibbs 74418781Sgibbs n_q_required = adv_sgcount_to_qcount(sg_entry_cnt); 74518781Sgibbs scsiq->sg_head->queue_cnt = n_q_required - 1; 74618781Sgibbs } else { 74718781Sgibbs p_data_addr = &scsiq->q1.data_addr; 74818781Sgibbs p_data_bcount = &scsiq->q1.data_cnt; 74918781Sgibbs n_q_required = 1; 75018781Sgibbs } 75118781Sgibbs 75239217Sgibbs disable_syn_offset_one_fix = FALSE; 75339217Sgibbs 75439217Sgibbs if ((adv->fix_asyn_xfer & scsiq->q1.target_id) != 0 75539217Sgibbs && (adv->fix_asyn_xfer_always & scsiq->q1.target_id) == 0) { 75639217Sgibbs 75739217Sgibbs if (datalen != 0) { 75839217Sgibbs if (datalen < 512) { 75939217Sgibbs disable_syn_offset_one_fix = TRUE; 76039217Sgibbs } else { 76139217Sgibbs if (scsiq->cdbptr[0] == INQUIRY 76239217Sgibbs || scsiq->cdbptr[0] == REQUEST_SENSE 76339217Sgibbs || scsiq->cdbptr[0] == READ_CAPACITY 76439217Sgibbs || scsiq->cdbptr[0] == MODE_SELECT_6 76539217Sgibbs || scsiq->cdbptr[0] == MODE_SENSE_6 76639217Sgibbs || scsiq->cdbptr[0] == MODE_SENSE_10 76739217Sgibbs || scsiq->cdbptr[0] == MODE_SELECT_10 76839217Sgibbs || scsiq->cdbptr[0] == READ_TOC) { 76939217Sgibbs disable_syn_offset_one_fix = TRUE; 77018781Sgibbs } 77118781Sgibbs } 77218781Sgibbs } 77318781Sgibbs } 77439217Sgibbs 77539217Sgibbs if (disable_syn_offset_one_fix) { 77639217Sgibbs scsiq->q2.tag_code &= 77739217Sgibbs ~(MSG_SIMPLE_Q_TAG|MSG_HEAD_OF_Q_TAG|MSG_ORDERED_Q_TAG); 77839217Sgibbs scsiq->q2.tag_code |= (ADV_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX 77939217Sgibbs | ADV_TAG_FLAG_DISABLE_DISCONNECT); 78039217Sgibbs } 78139217Sgibbs 78239217Sgibbs if ((adv->bug_fix_control & ADV_BUG_FIX_IF_NOT_DWB) != 0 78339217Sgibbs && (scsiq->cdbptr[0] == READ_10 || scsiq->cdbptr[0] == READ_6)) { 78439217Sgibbs u_int8_t extra_bytes; 78539217Sgibbs 78639217Sgibbs addr = *p_data_addr + *p_data_bcount; 78739217Sgibbs extra_bytes = addr & 0x0003; 78839217Sgibbs if (extra_bytes != 0 78939217Sgibbs && ((scsiq->q1.cntl & QC_SG_HEAD) != 0 79039217Sgibbs || (scsiq->q1.data_cnt & 0x01FF) == 0)) { 79139217Sgibbs scsiq->q2.tag_code |= ADV_TAG_FLAG_EXTRA_BYTES; 79239217Sgibbs scsiq->q1.extra_bytes = extra_bytes; 79339217Sgibbs *p_data_bcount -= extra_bytes; 79439217Sgibbs } 79539217Sgibbs } 79639217Sgibbs 79718781Sgibbs if ((adv_get_num_free_queues(adv, n_q_required) >= n_q_required) 79839217Sgibbs || ((scsiq->q1.cntl & QC_URGENT) != 0)) 79918781Sgibbs retval = adv_send_scsi_queue(adv, scsiq, n_q_required); 80018781Sgibbs 80118781Sgibbs return (retval); 80218781Sgibbs} 80318781Sgibbs 80418781Sgibbs 80518781Sgibbsu_int8_t 80639217Sgibbsadv_copy_lram_doneq(struct adv_softc *adv, u_int16_t q_addr, 80739217Sgibbs struct adv_q_done_info *scsiq, u_int32_t max_dma_count) 80818781Sgibbs{ 80939217Sgibbs u_int16_t val; 81039217Sgibbs u_int8_t sg_queue_cnt; 81118781Sgibbs 81218781Sgibbs adv_get_q_info(adv, q_addr + ADV_SCSIQ_DONE_INFO_BEG, 81318781Sgibbs (u_int16_t *)scsiq, 81418781Sgibbs (sizeof(scsiq->d2) + sizeof(scsiq->d3)) / 2); 81518781Sgibbs 81618781Sgibbs#if BYTE_ORDER == BIG_ENDIAN 81718781Sgibbs adv_adj_endian_qdone_info(scsiq); 81818781Sgibbs#endif 81918781Sgibbs 82018781Sgibbs val = adv_read_lram_16(adv, q_addr + ADV_SCSIQ_B_STATUS); 82118781Sgibbs scsiq->q_status = val & 0xFF; 82218781Sgibbs scsiq->q_no = (val >> 8) & 0XFF; 82318781Sgibbs 82418781Sgibbs val = adv_read_lram_16(adv, q_addr + ADV_SCSIQ_B_CNTL); 82518781Sgibbs scsiq->cntl = val & 0xFF; 82618781Sgibbs sg_queue_cnt = (val >> 8) & 0xFF; 82718781Sgibbs 82818781Sgibbs val = adv_read_lram_16(adv,q_addr + ADV_SCSIQ_B_SENSE_LEN); 82918781Sgibbs scsiq->sense_len = val & 0xFF; 83039217Sgibbs scsiq->extra_bytes = (val >> 8) & 0xFF; 83118781Sgibbs 83240133Sgibbs /* 83355945Sgibbs * Due to a bug in accessing LRAM on the 940UA, the residual 83455945Sgibbs * is split into separate high and low 16bit quantities. 83540133Sgibbs */ 83639217Sgibbs scsiq->remain_bytes = 83740133Sgibbs adv_read_lram_16(adv, q_addr + ADV_SCSIQ_DW_REMAIN_XFER_CNT); 83855945Sgibbs scsiq->remain_bytes |= 83955945Sgibbs adv_read_lram_16(adv, q_addr + ADV_SCSIQ_W_ALT_DC1) << 16; 84055945Sgibbs 84118781Sgibbs /* 84218781Sgibbs * XXX Is this just a safeguard or will the counter really 84318781Sgibbs * have bogus upper bits? 84418781Sgibbs */ 84518781Sgibbs scsiq->remain_bytes &= max_dma_count; 84618781Sgibbs 84718781Sgibbs return (sg_queue_cnt); 84818781Sgibbs} 84918781Sgibbs 85018781Sgibbsint 85139217Sgibbsadv_start_chip(struct adv_softc *adv) 85218781Sgibbs{ 85339217Sgibbs ADV_OUTB(adv, ADV_CHIP_CTRL, 0); 85439217Sgibbs if ((ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_HALTED) != 0) 85539217Sgibbs return (0); 85639217Sgibbs return (1); 85739217Sgibbs} 85839217Sgibbs 85939217Sgibbsint 86039217Sgibbsadv_stop_execution(struct adv_softc *adv) 86139217Sgibbs{ 86218781Sgibbs int count; 86318781Sgibbs 86418781Sgibbs count = 0; 86518781Sgibbs if (adv_read_lram_8(adv, ADV_STOP_CODE_B) == 0) { 86618781Sgibbs adv_write_lram_8(adv, ADV_STOP_CODE_B, 86718781Sgibbs ADV_STOP_REQ_RISC_STOP); 86818781Sgibbs do { 86918781Sgibbs if (adv_read_lram_8(adv, ADV_STOP_CODE_B) & 87018781Sgibbs ADV_STOP_ACK_RISC_STOP) { 87118781Sgibbs return (1); 87218781Sgibbs } 87318781Sgibbs DELAY(1000); 87418781Sgibbs } while (count++ < 20); 87518781Sgibbs } 87618781Sgibbs return (0); 87718781Sgibbs} 87818781Sgibbs 87918781Sgibbsint 88039217Sgibbsadv_is_chip_halted(struct adv_softc *adv) 88118781Sgibbs{ 88218781Sgibbs if ((ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_HALTED) != 0) { 88318781Sgibbs if ((ADV_INB(adv, ADV_CHIP_CTRL) & ADV_CC_HALT) != 0) { 88418781Sgibbs return (1); 88518781Sgibbs } 88618781Sgibbs } 88718781Sgibbs return (0); 88818781Sgibbs} 88918781Sgibbs 89018781Sgibbs/* 89118781Sgibbs * XXX The numeric constants and the loops in this routine 89218781Sgibbs * need to be documented. 89318781Sgibbs */ 89418781Sgibbsvoid 89539217Sgibbsadv_ack_interrupt(struct adv_softc *adv) 89618781Sgibbs{ 89718781Sgibbs u_int8_t host_flag; 89818781Sgibbs u_int8_t risc_flag; 89918781Sgibbs int loop; 90018781Sgibbs 90118781Sgibbs loop = 0; 90218781Sgibbs do { 90318781Sgibbs risc_flag = adv_read_lram_8(adv, ADVV_RISC_FLAG_B); 90418781Sgibbs if (loop++ > 0x7FFF) { 90518781Sgibbs break; 90618781Sgibbs } 90718781Sgibbs } while ((risc_flag & ADV_RISC_FLAG_GEN_INT) != 0); 90818781Sgibbs 90918781Sgibbs host_flag = adv_read_lram_8(adv, ADVV_HOST_FLAG_B); 91018781Sgibbs adv_write_lram_8(adv, ADVV_HOST_FLAG_B, 91118781Sgibbs host_flag | ADV_HOST_FLAG_ACK_INT); 91218781Sgibbs 91318781Sgibbs ADV_OUTW(adv, ADV_CHIP_STATUS, ADV_CIW_INT_ACK); 91418781Sgibbs loop = 0; 91518781Sgibbs while (ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_INT_PENDING) { 91618781Sgibbs ADV_OUTW(adv, ADV_CHIP_STATUS, ADV_CIW_INT_ACK); 91718781Sgibbs if (loop++ > 3) { 91818781Sgibbs break; 91918781Sgibbs } 92018781Sgibbs } 92118781Sgibbs 92218781Sgibbs adv_write_lram_8(adv, ADVV_HOST_FLAG_B, host_flag); 92318781Sgibbs} 92418781Sgibbs 92518781Sgibbs/* 92618781Sgibbs * Handle all conditions that may halt the chip waiting 92718781Sgibbs * for us to intervene. 92818781Sgibbs */ 92918781Sgibbsvoid 93039217Sgibbsadv_isr_chip_halted(struct adv_softc *adv) 93118781Sgibbs{ 93218781Sgibbs u_int16_t int_halt_code; 93339217Sgibbs u_int16_t halt_q_addr; 93439217Sgibbs target_bit_vector target_mask; 93539217Sgibbs target_bit_vector scsi_busy; 93618781Sgibbs u_int8_t halt_qp; 93718781Sgibbs u_int8_t target_ix; 93818781Sgibbs u_int8_t q_cntl; 93918781Sgibbs u_int8_t tid_no; 94018781Sgibbs 94118781Sgibbs int_halt_code = adv_read_lram_16(adv, ADVV_HALTCODE_W); 94218781Sgibbs halt_qp = adv_read_lram_8(adv, ADVV_CURCDB_B); 94318781Sgibbs halt_q_addr = ADV_QNO_TO_QADDR(halt_qp); 94418781Sgibbs target_ix = adv_read_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_TARGET_IX); 94518781Sgibbs q_cntl = adv_read_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_CNTL); 94618781Sgibbs tid_no = ADV_TIX_TO_TID(target_ix); 94739217Sgibbs target_mask = ADV_TID_TO_TARGET_MASK(tid_no); 94839217Sgibbs if (int_halt_code == ADV_HALT_DISABLE_ASYN_USE_SYN_FIX) { 94918781Sgibbs /* 95039217Sgibbs * Temporarily disable the async fix by removing 95139217Sgibbs * this target from the list of affected targets, 95239217Sgibbs * setting our async rate, and then putting us 95339217Sgibbs * back into the mask. 95418781Sgibbs */ 95539217Sgibbs adv->fix_asyn_xfer &= ~target_mask; 95639217Sgibbs adv_set_syncrate(adv, /*struct cam_path */NULL, 95739217Sgibbs tid_no, /*period*/0, /*offset*/0, 95839217Sgibbs ADV_TRANS_ACTIVE); 95939217Sgibbs adv->fix_asyn_xfer |= target_mask; 96039217Sgibbs } else if (int_halt_code == ADV_HALT_ENABLE_ASYN_USE_SYN_FIX) { 96139217Sgibbs adv_set_syncrate(adv, /*struct cam_path */NULL, 96239217Sgibbs tid_no, /*period*/0, /*offset*/0, 96339217Sgibbs ADV_TRANS_ACTIVE); 96439217Sgibbs } else if (int_halt_code == ADV_HALT_EXTMSG_IN) { 96539217Sgibbs adv_handle_extmsg_in(adv, halt_q_addr, q_cntl, 96639217Sgibbs target_mask, tid_no); 96718781Sgibbs } else if (int_halt_code == ADV_HALT_CHK_CONDITION) { 96855945Sgibbs struct adv_target_transinfo* tinfo; 96955945Sgibbs union ccb *ccb; 97055945Sgibbs u_int32_t cinfo_index; 97155945Sgibbs u_int8_t tag_code; 97255945Sgibbs u_int8_t q_status; 97318781Sgibbs 97439217Sgibbs tinfo = &adv->tinfo[tid_no]; 97518781Sgibbs q_cntl |= QC_REQ_SENSE; 97618781Sgibbs 97739217Sgibbs /* Renegotiate if appropriate. */ 97839217Sgibbs adv_set_syncrate(adv, /*struct cam_path */NULL, 97939217Sgibbs tid_no, /*period*/0, /*offset*/0, 98039217Sgibbs ADV_TRANS_CUR); 98139217Sgibbs if (tinfo->current.period != tinfo->goal.period) { 98239217Sgibbs adv_msgout_sdtr(adv, tinfo->goal.period, 98339217Sgibbs tinfo->goal.offset); 98418781Sgibbs q_cntl |= QC_MSG_OUT; 98518781Sgibbs } 98618781Sgibbs adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_CNTL, q_cntl); 98718781Sgibbs 98818781Sgibbs /* Don't tag request sense commands */ 98939217Sgibbs tag_code = adv_read_lram_8(adv, 99039217Sgibbs halt_q_addr + ADV_SCSIQ_B_TAG_CODE); 99139217Sgibbs tag_code &= 99239217Sgibbs ~(MSG_SIMPLE_Q_TAG|MSG_HEAD_OF_Q_TAG|MSG_ORDERED_Q_TAG); 99318781Sgibbs 99439217Sgibbs if ((adv->fix_asyn_xfer & target_mask) != 0 99539217Sgibbs && (adv->fix_asyn_xfer_always & target_mask) == 0) { 99639217Sgibbs tag_code |= (ADV_TAG_FLAG_DISABLE_DISCONNECT 99739217Sgibbs | ADV_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX); 99839217Sgibbs } 99939217Sgibbs adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_TAG_CODE, 100039217Sgibbs tag_code); 100139217Sgibbs q_status = adv_read_lram_8(adv, 100239217Sgibbs halt_q_addr + ADV_SCSIQ_B_STATUS); 100318781Sgibbs q_status |= (QS_READY | QS_BUSY); 100439217Sgibbs adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_STATUS, 100539217Sgibbs q_status); 100639217Sgibbs /* 100739217Sgibbs * Freeze the devq until we can handle the sense condition. 100839217Sgibbs */ 100955945Sgibbs cinfo_index = 101055945Sgibbs adv_read_lram_32(adv, halt_q_addr + ADV_SCSIQ_D_CINFO_IDX); 101155945Sgibbs ccb = adv->ccb_infos[cinfo_index].ccb; 101239217Sgibbs xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 101339217Sgibbs ccb->ccb_h.status |= CAM_DEV_QFRZN; 101439217Sgibbs adv_abort_ccb(adv, tid_no, ADV_TIX_TO_LUN(target_ix), 101539217Sgibbs /*ccb*/NULL, CAM_REQUEUE_REQ, 101639217Sgibbs /*queued_only*/TRUE); 101718781Sgibbs scsi_busy = adv_read_lram_8(adv, ADVV_SCSIBUSY_B); 101839217Sgibbs scsi_busy &= ~target_mask; 101918781Sgibbs adv_write_lram_8(adv, ADVV_SCSIBUSY_B, scsi_busy); 102045846Sgibbs /* 102145846Sgibbs * Ensure we have enough time to actually 102245846Sgibbs * retrieve the sense. 102345846Sgibbs */ 102445846Sgibbs untimeout(adv_timeout, (caddr_t)ccb, ccb->ccb_h.timeout_ch); 102545846Sgibbs ccb->ccb_h.timeout_ch = 102645846Sgibbs timeout(adv_timeout, (caddr_t)ccb, 5 * hz); 102718781Sgibbs } else if (int_halt_code == ADV_HALT_SDTR_REJECTED) { 102839217Sgibbs struct ext_msg out_msg; 102918781Sgibbs 103018781Sgibbs adv_read_lram_16_multi(adv, ADVV_MSGOUT_BEG, 103118781Sgibbs (u_int16_t *) &out_msg, 103218781Sgibbs sizeof(out_msg)/2); 103318781Sgibbs 103439217Sgibbs if ((out_msg.msg_type == MSG_EXTENDED) 103539217Sgibbs && (out_msg.msg_len == MSG_EXT_SDTR_LEN) 103639217Sgibbs && (out_msg.msg_req == MSG_EXT_SDTR)) { 103718781Sgibbs 103839217Sgibbs /* Revert to Async */ 103939217Sgibbs adv_set_syncrate(adv, /*struct cam_path */NULL, 104039217Sgibbs tid_no, /*period*/0, /*offset*/0, 104139217Sgibbs ADV_TRANS_GOAL|ADV_TRANS_ACTIVE); 104218781Sgibbs } 104318781Sgibbs q_cntl &= ~QC_MSG_OUT; 104418781Sgibbs adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_CNTL, q_cntl); 104518781Sgibbs } else if (int_halt_code == ADV_HALT_SS_QUEUE_FULL) { 104639217Sgibbs u_int8_t scsi_status; 104739217Sgibbs union ccb *ccb; 104855945Sgibbs u_int32_t cinfo_index; 104939217Sgibbs 105039217Sgibbs scsi_status = adv_read_lram_8(adv, halt_q_addr 105139217Sgibbs + ADV_SCSIQ_SCSI_STATUS); 105255945Sgibbs cinfo_index = 105355945Sgibbs adv_read_lram_32(adv, halt_q_addr + ADV_SCSIQ_D_CINFO_IDX); 105455945Sgibbs ccb = adv->ccb_infos[cinfo_index].ccb; 105539217Sgibbs xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 105640733Sgibbs ccb->ccb_h.status |= CAM_DEV_QFRZN|CAM_SCSI_STATUS_ERROR; 105740733Sgibbs ccb->csio.scsi_status = SCSI_STATUS_QUEUE_FULL; 105839217Sgibbs adv_abort_ccb(adv, tid_no, ADV_TIX_TO_LUN(target_ix), 105939217Sgibbs /*ccb*/NULL, CAM_REQUEUE_REQ, 106039217Sgibbs /*queued_only*/TRUE); 106139217Sgibbs scsi_busy = adv_read_lram_8(adv, ADVV_SCSIBUSY_B); 106239217Sgibbs scsi_busy &= ~target_mask; 106339217Sgibbs adv_write_lram_8(adv, ADVV_SCSIBUSY_B, scsi_busy); 106455945Sgibbs } else { 106555945Sgibbs printf("Unhandled Halt Code %x\n", int_halt_code); 106639217Sgibbs } 106739217Sgibbs adv_write_lram_16(adv, ADVV_HALTCODE_W, 0); 106839217Sgibbs} 106918781Sgibbs 107039217Sgibbsvoid 107139217Sgibbsadv_sdtr_to_period_offset(struct adv_softc *adv, 107239217Sgibbs u_int8_t sync_data, u_int8_t *period, 107339217Sgibbs u_int8_t *offset, int tid) 107439217Sgibbs{ 107539217Sgibbs if (adv->fix_asyn_xfer & ADV_TID_TO_TARGET_MASK(tid) 107639217Sgibbs && (sync_data == ASYN_SDTR_DATA_FIX_PCI_REV_AB)) { 107739217Sgibbs *period = *offset = 0; 107839217Sgibbs } else { 107939217Sgibbs *period = adv->sdtr_period_tbl[((sync_data >> 4) & 0xF)]; 108039217Sgibbs *offset = sync_data & 0xF; 108139217Sgibbs } 108239217Sgibbs} 108339217Sgibbs 108439217Sgibbsvoid 108539217Sgibbsadv_set_syncrate(struct adv_softc *adv, struct cam_path *path, 108639217Sgibbs u_int tid, u_int period, u_int offset, u_int type) 108739217Sgibbs{ 108839217Sgibbs struct adv_target_transinfo* tinfo; 108939217Sgibbs u_int old_period; 109039217Sgibbs u_int old_offset; 109139217Sgibbs u_int8_t sdtr_data; 109239217Sgibbs 109339217Sgibbs tinfo = &adv->tinfo[tid]; 109439217Sgibbs 109539217Sgibbs /* Filter our input */ 109639217Sgibbs sdtr_data = adv_period_offset_to_sdtr(adv, &period, 109739217Sgibbs &offset, tid); 109839217Sgibbs 109939217Sgibbs old_period = tinfo->current.period; 110039217Sgibbs old_offset = tinfo->current.offset; 110139217Sgibbs 110239217Sgibbs if ((type & ADV_TRANS_CUR) != 0 110339217Sgibbs && ((old_period != period || old_offset != offset) 110439217Sgibbs || period == 0 || offset == 0) /*Changes in asyn fix settings*/) { 110539217Sgibbs int s; 110639217Sgibbs int halted; 110739217Sgibbs 110839217Sgibbs s = splcam(); 110939217Sgibbs halted = adv_is_chip_halted(adv); 111039217Sgibbs if (halted == 0) 111139217Sgibbs /* Must halt the chip first */ 111239217Sgibbs adv_host_req_chip_halt(adv); 111339217Sgibbs 111439217Sgibbs /* Update current hardware settings */ 111539217Sgibbs adv_set_sdtr_reg_at_id(adv, tid, sdtr_data); 111639217Sgibbs 111718781Sgibbs /* 111839217Sgibbs * If a target can run in sync mode, we don't need 111939217Sgibbs * to check it for sync problems. 112018781Sgibbs */ 112139217Sgibbs if (offset != 0) 112239217Sgibbs adv->fix_asyn_xfer &= ~ADV_TID_TO_TARGET_MASK(tid); 112318781Sgibbs 112439217Sgibbs if (halted == 0) 112539217Sgibbs /* Start the chip again */ 112639217Sgibbs adv_start_chip(adv); 112718781Sgibbs 112839217Sgibbs splx(s); 112939217Sgibbs tinfo->current.period = period; 113039217Sgibbs tinfo->current.offset = offset; 113139217Sgibbs 113239217Sgibbs if (path != NULL) { 113339217Sgibbs /* 113439217Sgibbs * Tell the SCSI layer about the 113539217Sgibbs * new transfer parameters. 113639217Sgibbs */ 113739217Sgibbs struct ccb_trans_settings neg; 113839217Sgibbs 113939217Sgibbs neg.sync_period = period; 114039217Sgibbs neg.sync_offset = offset; 114139217Sgibbs neg.valid = CCB_TRANS_SYNC_RATE_VALID 114239217Sgibbs | CCB_TRANS_SYNC_OFFSET_VALID; 114339217Sgibbs xpt_setup_ccb(&neg.ccb_h, path, /*priority*/1); 114439217Sgibbs xpt_async(AC_TRANSFER_NEG, path, &neg); 114539217Sgibbs } 114639217Sgibbs } 114739217Sgibbs 114839217Sgibbs if ((type & ADV_TRANS_GOAL) != 0) { 114939217Sgibbs tinfo->goal.period = period; 115039217Sgibbs tinfo->goal.offset = offset; 115139217Sgibbs } 115239217Sgibbs 115339217Sgibbs if ((type & ADV_TRANS_USER) != 0) { 115439217Sgibbs tinfo->user.period = period; 115539217Sgibbs tinfo->user.offset = offset; 115639217Sgibbs } 115739217Sgibbs} 115839217Sgibbs 115939217Sgibbsu_int8_t 116039217Sgibbsadv_period_offset_to_sdtr(struct adv_softc *adv, u_int *period, 116139217Sgibbs u_int *offset, int tid) 116239217Sgibbs{ 116339217Sgibbs u_int i; 116439217Sgibbs u_int dummy_offset; 116539217Sgibbs u_int dummy_period; 116639217Sgibbs 116739217Sgibbs if (offset == NULL) { 116839217Sgibbs dummy_offset = 0; 116939217Sgibbs offset = &dummy_offset; 117039217Sgibbs } 117139217Sgibbs 117239217Sgibbs if (period == NULL) { 117339217Sgibbs dummy_period = 0; 117439217Sgibbs period = &dummy_period; 117539217Sgibbs } 117639217Sgibbs 117739217Sgibbs *offset = MIN(ADV_SYN_MAX_OFFSET, *offset); 117839217Sgibbs if (*period != 0 && *offset != 0) { 117939217Sgibbs for (i = 0; i < adv->sdtr_period_tbl_size; i++) { 118039217Sgibbs if (*period <= adv->sdtr_period_tbl[i]) { 118139217Sgibbs /* 118239217Sgibbs * When responding to a target that requests 118339217Sgibbs * sync, the requested rate may fall between 118439217Sgibbs * two rates that we can output, but still be 118539217Sgibbs * a rate that we can receive. Because of this, 118639217Sgibbs * we want to respond to the target with 118739217Sgibbs * the same rate that it sent to us even 118839217Sgibbs * if the period we use to send data to it 118939217Sgibbs * is lower. Only lower the response period 119039217Sgibbs * if we must. 119139217Sgibbs */ 119239217Sgibbs if (i == 0 /* Our maximum rate */) 119339217Sgibbs *period = adv->sdtr_period_tbl[0]; 119439217Sgibbs return ((i << 4) | *offset); 119518781Sgibbs } 119618781Sgibbs } 119718781Sgibbs } 119839217Sgibbs 119939217Sgibbs /* Must go async */ 120039217Sgibbs *period = 0; 120139217Sgibbs *offset = 0; 120239217Sgibbs if (adv->fix_asyn_xfer & ADV_TID_TO_TARGET_MASK(tid)) 120339217Sgibbs return (ASYN_SDTR_DATA_FIX_PCI_REV_AB); 120439217Sgibbs return (0); 120518781Sgibbs} 120618781Sgibbs 120718781Sgibbs/* Internal Routines */ 120818781Sgibbs 120918781Sgibbsstatic void 121039217Sgibbsadv_read_lram_16_multi(struct adv_softc *adv, u_int16_t s_addr, 121139217Sgibbs u_int16_t *buffer, int count) 121218781Sgibbs{ 121318781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr); 121418781Sgibbs ADV_INSW(adv, ADV_LRAM_DATA, buffer, count); 121518781Sgibbs} 121618781Sgibbs 121718781Sgibbsstatic void 121839217Sgibbsadv_write_lram_16_multi(struct adv_softc *adv, u_int16_t s_addr, 121939217Sgibbs u_int16_t *buffer, int count) 122018781Sgibbs{ 122118781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr); 122218781Sgibbs ADV_OUTSW(adv, ADV_LRAM_DATA, buffer, count); 122318781Sgibbs} 122418781Sgibbs 122518781Sgibbsstatic void 122639217Sgibbsadv_mset_lram_16(struct adv_softc *adv, u_int16_t s_addr, 122739217Sgibbs u_int16_t set_value, int count) 122818781Sgibbs{ 122918781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr); 123039217Sgibbs bus_space_set_multi_2(adv->tag, adv->bsh, ADV_LRAM_DATA, 123139217Sgibbs set_value, count); 123218781Sgibbs} 123318781Sgibbs 123418781Sgibbsstatic u_int32_t 123539217Sgibbsadv_msum_lram_16(struct adv_softc *adv, u_int16_t s_addr, int count) 123618781Sgibbs{ 123718781Sgibbs u_int32_t sum; 123818781Sgibbs int i; 123918781Sgibbs 124018781Sgibbs sum = 0; 124139217Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr); 124239217Sgibbs for (i = 0; i < count; i++) 124339217Sgibbs sum += ADV_INW(adv, ADV_LRAM_DATA); 124418781Sgibbs return (sum); 124518781Sgibbs} 124618781Sgibbs 124718781Sgibbsstatic int 124839217Sgibbsadv_write_and_verify_lram_16(struct adv_softc *adv, u_int16_t addr, 124939217Sgibbs u_int16_t value) 125018781Sgibbs{ 125118781Sgibbs int retval; 125218781Sgibbs 125318781Sgibbs retval = 0; 125418781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, addr); 125518781Sgibbs ADV_OUTW(adv, ADV_LRAM_DATA, value); 125639217Sgibbs DELAY(10000); 125718781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, addr); 125818781Sgibbs if (value != ADV_INW(adv, ADV_LRAM_DATA)) 125918781Sgibbs retval = 1; 126018781Sgibbs return (retval); 126118781Sgibbs} 126218781Sgibbs 126318781Sgibbsstatic u_int32_t 126439217Sgibbsadv_read_lram_32(struct adv_softc *adv, u_int16_t addr) 126518781Sgibbs{ 126618781Sgibbs u_int16_t val_low, val_high; 126718781Sgibbs 126818781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, addr); 126918781Sgibbs 127018781Sgibbs#if BYTE_ORDER == BIG_ENDIAN 127118781Sgibbs val_high = ADV_INW(adv, ADV_LRAM_DATA); 127218781Sgibbs val_low = ADV_INW(adv, ADV_LRAM_DATA); 127318781Sgibbs#else 127418781Sgibbs val_low = ADV_INW(adv, ADV_LRAM_DATA); 127518781Sgibbs val_high = ADV_INW(adv, ADV_LRAM_DATA); 127618781Sgibbs#endif 127718781Sgibbs 127818781Sgibbs return (((u_int32_t)val_high << 16) | (u_int32_t)val_low); 127918781Sgibbs} 128018781Sgibbs 128118781Sgibbsstatic void 128239217Sgibbsadv_write_lram_32(struct adv_softc *adv, u_int16_t addr, u_int32_t value) 128318781Sgibbs{ 128418781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, addr); 128518781Sgibbs 128618781Sgibbs#if BYTE_ORDER == BIG_ENDIAN 128718781Sgibbs ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)((value >> 16) & 0xFFFF)); 128818781Sgibbs ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)(value & 0xFFFF)); 128918781Sgibbs#else 129018781Sgibbs ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)(value & 0xFFFF)); 129118781Sgibbs ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)((value >> 16) & 0xFFFF)); 129218781Sgibbs#endif 129318781Sgibbs} 129418781Sgibbs 129518781Sgibbsstatic void 129639217Sgibbsadv_write_lram_32_multi(struct adv_softc *adv, u_int16_t s_addr, 129739217Sgibbs u_int32_t *buffer, int count) 129818781Sgibbs{ 129918781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr); 130039217Sgibbs ADV_OUTSW(adv, ADV_LRAM_DATA, (u_int16_t *)buffer, count * 2); 130118781Sgibbs} 130218781Sgibbs 130318781Sgibbsstatic u_int16_t 130439217Sgibbsadv_read_eeprom_16(struct adv_softc *adv, u_int8_t addr) 130518781Sgibbs{ 130618781Sgibbs u_int16_t read_wval; 130718781Sgibbs u_int8_t cmd_reg; 130818781Sgibbs 130918781Sgibbs adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE_DISABLE); 131018781Sgibbs DELAY(1000); 131118781Sgibbs cmd_reg = addr | ADV_EEPROM_CMD_READ; 131218781Sgibbs adv_write_eeprom_cmd_reg(adv, cmd_reg); 131318781Sgibbs DELAY(1000); 131418781Sgibbs read_wval = ADV_INW(adv, ADV_EEPROM_DATA); 131518781Sgibbs DELAY(1000); 131618781Sgibbs return (read_wval); 131718781Sgibbs} 131818781Sgibbs 131918781Sgibbsstatic u_int16_t 132039217Sgibbsadv_write_eeprom_16(struct adv_softc *adv, u_int8_t addr, u_int16_t value) 132118781Sgibbs{ 132218781Sgibbs u_int16_t read_value; 132318781Sgibbs 132418781Sgibbs read_value = adv_read_eeprom_16(adv, addr); 132518781Sgibbs if (read_value != value) { 132618781Sgibbs adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE_ENABLE); 132718781Sgibbs DELAY(1000); 132818781Sgibbs 132918781Sgibbs ADV_OUTW(adv, ADV_EEPROM_DATA, value); 133018781Sgibbs DELAY(1000); 133118781Sgibbs 133218781Sgibbs adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE | addr); 133318781Sgibbs DELAY(20 * 1000); 133418781Sgibbs 133518781Sgibbs adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE_DISABLE); 133618781Sgibbs DELAY(1000); 133718781Sgibbs read_value = adv_read_eeprom_16(adv, addr); 133818781Sgibbs } 133918781Sgibbs return (read_value); 134018781Sgibbs} 134118781Sgibbs 134218781Sgibbsstatic int 134339217Sgibbsadv_write_eeprom_cmd_reg(struct adv_softc *adv, u_int8_t cmd_reg) 134418781Sgibbs{ 134518781Sgibbs u_int8_t read_back; 134618781Sgibbs int retry; 134718781Sgibbs 134818781Sgibbs retry = 0; 134918781Sgibbs while (1) { 135018781Sgibbs ADV_OUTB(adv, ADV_EEPROM_CMD, cmd_reg); 135118781Sgibbs DELAY(1000); 135218781Sgibbs read_back = ADV_INB(adv, ADV_EEPROM_CMD); 135318781Sgibbs if (read_back == cmd_reg) { 135418781Sgibbs return (1); 135518781Sgibbs } 135618781Sgibbs if (retry++ > ADV_EEPROM_MAX_RETRY) { 135718781Sgibbs return (0); 135818781Sgibbs } 135918781Sgibbs } 136018781Sgibbs} 136118781Sgibbs 136218781Sgibbsstatic int 136339217Sgibbsadv_set_eeprom_config_once(struct adv_softc *adv, 136439217Sgibbs struct adv_eeprom_config *eeprom_config) 136518781Sgibbs{ 136618781Sgibbs int n_error; 136718781Sgibbs u_int16_t *wbuf; 136818781Sgibbs u_int16_t sum; 136918781Sgibbs u_int8_t s_addr; 137018781Sgibbs u_int8_t cfg_beg; 137118781Sgibbs u_int8_t cfg_end; 137218781Sgibbs 137318781Sgibbs wbuf = (u_int16_t *)eeprom_config; 137418781Sgibbs n_error = 0; 137518781Sgibbs sum = 0; 137618781Sgibbs for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) { 137718781Sgibbs sum += *wbuf; 137818781Sgibbs if (*wbuf != adv_write_eeprom_16(adv, s_addr, *wbuf)) { 137918781Sgibbs n_error++; 138018781Sgibbs } 138118781Sgibbs } 138218781Sgibbs if (adv->type & ADV_VL) { 138318781Sgibbs cfg_beg = ADV_EEPROM_CFG_BEG_VL; 138418781Sgibbs cfg_end = ADV_EEPROM_MAX_ADDR_VL; 138518781Sgibbs } else { 138618781Sgibbs cfg_beg = ADV_EEPROM_CFG_BEG; 138718781Sgibbs cfg_end = ADV_EEPROM_MAX_ADDR; 138818781Sgibbs } 138918781Sgibbs 139018781Sgibbs for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) { 139118781Sgibbs sum += *wbuf; 139218781Sgibbs if (*wbuf != adv_write_eeprom_16(adv, s_addr, *wbuf)) { 139318781Sgibbs n_error++; 139418781Sgibbs } 139518781Sgibbs } 139618781Sgibbs *wbuf = sum; 139718781Sgibbs if (sum != adv_write_eeprom_16(adv, s_addr, sum)) { 139818781Sgibbs n_error++; 139918781Sgibbs } 140018781Sgibbs wbuf = (u_int16_t *)eeprom_config; 140118781Sgibbs for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) { 140218781Sgibbs if (*wbuf != adv_read_eeprom_16(adv, s_addr)) { 140318781Sgibbs n_error++; 140418781Sgibbs } 140518781Sgibbs } 140618781Sgibbs for (s_addr = cfg_beg; s_addr <= cfg_end; s_addr++, wbuf++) { 140718781Sgibbs if (*wbuf != adv_read_eeprom_16(adv, s_addr)) { 140818781Sgibbs n_error++; 140918781Sgibbs } 141018781Sgibbs } 141118781Sgibbs return (n_error); 141218781Sgibbs} 141318781Sgibbs 141418781Sgibbsstatic u_int32_t 141539217Sgibbsadv_load_microcode(struct adv_softc *adv, u_int16_t s_addr, 141639217Sgibbs u_int16_t *mcode_buf, u_int16_t mcode_size) 141718781Sgibbs{ 141839217Sgibbs u_int32_t chksum; 141939217Sgibbs u_int16_t mcode_lram_size; 142039217Sgibbs u_int16_t mcode_chksum; 142118781Sgibbs 142218781Sgibbs mcode_lram_size = mcode_size >> 1; 142318781Sgibbs /* XXX Why zero the memory just before you write the whole thing?? */ 142439217Sgibbs adv_mset_lram_16(adv, s_addr, 0, mcode_lram_size); 142518781Sgibbs adv_write_lram_16_multi(adv, s_addr, mcode_buf, mcode_lram_size); 142618781Sgibbs 142718781Sgibbs chksum = adv_msum_lram_16(adv, s_addr, mcode_lram_size); 142818781Sgibbs mcode_chksum = (u_int16_t)adv_msum_lram_16(adv, ADV_CODE_SEC_BEG, 142939217Sgibbs ((mcode_size - s_addr 143039217Sgibbs - ADV_CODE_SEC_BEG) >> 1)); 143118781Sgibbs adv_write_lram_16(adv, ADVV_MCODE_CHKSUM_W, mcode_chksum); 143218781Sgibbs adv_write_lram_16(adv, ADVV_MCODE_SIZE_W, mcode_size); 143318781Sgibbs return (chksum); 143418781Sgibbs} 143518781Sgibbs 143618781Sgibbsstatic void 143739217Sgibbsadv_reinit_lram(struct adv_softc *adv) { 143839217Sgibbs adv_init_lram(adv); 143939217Sgibbs adv_init_qlink_var(adv); 144039217Sgibbs} 144139217Sgibbs 144239217Sgibbsstatic void 144339217Sgibbsadv_init_lram(struct adv_softc *adv) 144418781Sgibbs{ 144539217Sgibbs u_int8_t i; 144639217Sgibbs u_int16_t s_addr; 144718781Sgibbs 144818781Sgibbs adv_mset_lram_16(adv, ADV_QADR_BEG, 0, 144939217Sgibbs (((adv->max_openings + 2 + 1) * 64) >> 1)); 145018781Sgibbs 145118781Sgibbs i = ADV_MIN_ACTIVE_QNO; 145218781Sgibbs s_addr = ADV_QADR_BEG + ADV_QBLK_SIZE; 145318781Sgibbs 145418781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD, i + 1); 145518781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, adv->max_openings); 145618781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, i); 145718781Sgibbs i++; 145818781Sgibbs s_addr += ADV_QBLK_SIZE; 145918781Sgibbs for (; i < adv->max_openings; i++, s_addr += ADV_QBLK_SIZE) { 146018781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD, i + 1); 146118781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, i - 1); 146218781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, i); 146318781Sgibbs } 146418781Sgibbs 146518781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD, ADV_QLINK_END); 146618781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, adv->max_openings - 1); 146718781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, adv->max_openings); 146818781Sgibbs i++; 146918781Sgibbs s_addr += ADV_QBLK_SIZE; 147018781Sgibbs 147118781Sgibbs for (; i <= adv->max_openings + 3; i++, s_addr += ADV_QBLK_SIZE) { 147218781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD, i); 147318781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, i); 147418781Sgibbs adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, i); 147518781Sgibbs } 147618781Sgibbs} 147718781Sgibbs 147818781Sgibbsstatic int 147939217Sgibbsadv_init_microcode_var(struct adv_softc *adv) 148018781Sgibbs{ 148139217Sgibbs int i; 148218781Sgibbs 148318781Sgibbs for (i = 0; i <= ADV_MAX_TID; i++) { 148439217Sgibbs 148539217Sgibbs /* Start out async all around */ 148639217Sgibbs adv_set_syncrate(adv, /*path*/NULL, 148739217Sgibbs i, 0, 0, 148839217Sgibbs ADV_TRANS_GOAL|ADV_TRANS_CUR); 148918781Sgibbs } 149018781Sgibbs 149118781Sgibbs adv_init_qlink_var(adv); 149218781Sgibbs 149318781Sgibbs adv_write_lram_8(adv, ADVV_DISC_ENABLE_B, adv->disc_enable); 149418781Sgibbs adv_write_lram_8(adv, ADVV_HOSTSCSI_ID_B, 0x01 << adv->scsi_id); 149518781Sgibbs 149639217Sgibbs adv_write_lram_32(adv, ADVV_OVERRUN_PADDR_D, adv->overrun_physbase); 149718781Sgibbs 149839217Sgibbs adv_write_lram_32(adv, ADVV_OVERRUN_BSIZE_D, ADV_OVERRUN_BSIZE); 149918781Sgibbs 150018781Sgibbs ADV_OUTW(adv, ADV_REG_PROG_COUNTER, ADV_MCODE_START_ADDR); 150118781Sgibbs if (ADV_INW(adv, ADV_REG_PROG_COUNTER) != ADV_MCODE_START_ADDR) { 150239217Sgibbs printf("adv%d: Unable to set program counter. Aborting.\n", 150318781Sgibbs adv->unit); 150418781Sgibbs return (1); 150518781Sgibbs } 150618781Sgibbs return (0); 150718781Sgibbs} 150818781Sgibbs 150918781Sgibbsstatic void 151039217Sgibbsadv_init_qlink_var(struct adv_softc *adv) 151118781Sgibbs{ 151218781Sgibbs int i; 151318781Sgibbs u_int16_t lram_addr; 151418781Sgibbs 151518781Sgibbs adv_write_lram_8(adv, ADVV_NEXTRDY_B, 1); 151618781Sgibbs adv_write_lram_8(adv, ADVV_DONENEXT_B, adv->max_openings); 151718781Sgibbs 151818781Sgibbs adv_write_lram_16(adv, ADVV_FREE_Q_HEAD_W, 1); 151918781Sgibbs adv_write_lram_16(adv, ADVV_DONE_Q_TAIL_W, adv->max_openings); 152018781Sgibbs 152118781Sgibbs adv_write_lram_8(adv, ADVV_BUSY_QHEAD_B, 152218781Sgibbs (u_int8_t)((int) adv->max_openings + 1)); 152318781Sgibbs adv_write_lram_8(adv, ADVV_DISC1_QHEAD_B, 152418781Sgibbs (u_int8_t)((int) adv->max_openings + 2)); 152518781Sgibbs 152618781Sgibbs adv_write_lram_8(adv, ADVV_TOTAL_READY_Q_B, adv->max_openings); 152718781Sgibbs 152818781Sgibbs adv_write_lram_16(adv, ADVV_ASCDVC_ERR_CODE_W, 0); 152918781Sgibbs adv_write_lram_16(adv, ADVV_HALTCODE_W, 0); 153018781Sgibbs adv_write_lram_8(adv, ADVV_STOP_CODE_B, 0); 153118781Sgibbs adv_write_lram_8(adv, ADVV_SCSIBUSY_B, 0); 153218781Sgibbs adv_write_lram_8(adv, ADVV_WTM_FLAG_B, 0); 153339217Sgibbs adv_write_lram_8(adv, ADVV_Q_DONE_IN_PROGRESS_B, 0); 153418781Sgibbs 153518781Sgibbs lram_addr = ADV_QADR_BEG; 153618781Sgibbs for (i = 0; i < 32; i++, lram_addr += 2) 153718781Sgibbs adv_write_lram_16(adv, lram_addr, 0); 153818781Sgibbs} 153939217Sgibbs 154018781Sgibbsstatic void 154139217Sgibbsadv_disable_interrupt(struct adv_softc *adv) 154218781Sgibbs{ 154318781Sgibbs u_int16_t cfg; 154418781Sgibbs 154518781Sgibbs cfg = ADV_INW(adv, ADV_CONFIG_LSW); 154618781Sgibbs ADV_OUTW(adv, ADV_CONFIG_LSW, cfg & ~ADV_CFG_LSW_HOST_INT_ON); 154718781Sgibbs} 154818781Sgibbs 154918781Sgibbsstatic void 155039217Sgibbsadv_enable_interrupt(struct adv_softc *adv) 155118781Sgibbs{ 155218781Sgibbs u_int16_t cfg; 155318781Sgibbs 155418781Sgibbs cfg = ADV_INW(adv, ADV_CONFIG_LSW); 155518781Sgibbs ADV_OUTW(adv, ADV_CONFIG_LSW, cfg | ADV_CFG_LSW_HOST_INT_ON); 155618781Sgibbs} 155718781Sgibbs 155818781Sgibbsstatic void 155939217Sgibbsadv_toggle_irq_act(struct adv_softc *adv) 156018781Sgibbs{ 156118781Sgibbs ADV_OUTW(adv, ADV_CHIP_STATUS, ADV_CIW_IRQ_ACT); 156218781Sgibbs ADV_OUTW(adv, ADV_CHIP_STATUS, 0); 156318781Sgibbs} 156418781Sgibbs 156539217Sgibbsvoid 156639217Sgibbsadv_start_execution(struct adv_softc *adv) 156718781Sgibbs{ 156818781Sgibbs if (adv_read_lram_8(adv, ADV_STOP_CODE_B) != 0) { 156918781Sgibbs adv_write_lram_8(adv, ADV_STOP_CODE_B, 0); 157018781Sgibbs } 157118781Sgibbs} 157218781Sgibbs 157355945Sgibbsint 157439217Sgibbsadv_stop_chip(struct adv_softc *adv) 157518781Sgibbs{ 157618781Sgibbs u_int8_t cc_val; 157718781Sgibbs 157818781Sgibbs cc_val = ADV_INB(adv, ADV_CHIP_CTRL) 157918781Sgibbs & (~(ADV_CC_SINGLE_STEP | ADV_CC_TEST | ADV_CC_DIAG)); 158018781Sgibbs ADV_OUTB(adv, ADV_CHIP_CTRL, cc_val | ADV_CC_HALT); 158118781Sgibbs adv_set_chip_ih(adv, ADV_INS_HALT); 158218781Sgibbs adv_set_chip_ih(adv, ADV_INS_RFLAG_WTM); 158318781Sgibbs if ((ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_HALTED) == 0) { 158418781Sgibbs return (0); 158518781Sgibbs } 158618781Sgibbs return (1); 158718781Sgibbs} 158818781Sgibbs 158939217Sgibbsstatic int 159039217Sgibbsadv_host_req_chip_halt(struct adv_softc *adv) 159139217Sgibbs{ 159239217Sgibbs int count; 159339217Sgibbs u_int8_t saved_stop_code; 159439217Sgibbs 159539217Sgibbs if (adv_is_chip_halted(adv)) 159639217Sgibbs return (1); 159739217Sgibbs 159839217Sgibbs count = 0; 159939217Sgibbs saved_stop_code = adv_read_lram_8(adv, ADVV_STOP_CODE_B); 160039217Sgibbs adv_write_lram_8(adv, ADVV_STOP_CODE_B, 160139217Sgibbs ADV_STOP_HOST_REQ_RISC_HALT | ADV_STOP_REQ_RISC_STOP); 160239217Sgibbs while (adv_is_chip_halted(adv) == 0 160339217Sgibbs && count++ < 2000) 160439217Sgibbs ; 160539217Sgibbs 160639217Sgibbs adv_write_lram_8(adv, ADVV_STOP_CODE_B, saved_stop_code); 160739217Sgibbs return (count < 2000); 160839217Sgibbs} 160939217Sgibbs 161018781Sgibbsstatic void 161139217Sgibbsadv_set_chip_ih(struct adv_softc *adv, u_int16_t ins_code) 161218781Sgibbs{ 161318781Sgibbs adv_set_bank(adv, 1); 161418781Sgibbs ADV_OUTW(adv, ADV_REG_IH, ins_code); 161518781Sgibbs adv_set_bank(adv, 0); 161618781Sgibbs} 161718781Sgibbs 1618153072Sru#if 0 161918781Sgibbsstatic u_int8_t 162039217Sgibbsadv_get_chip_scsi_ctrl(struct adv_softc *adv) 162118781Sgibbs{ 162218781Sgibbs u_int8_t scsi_ctrl; 162318781Sgibbs 162418781Sgibbs adv_set_bank(adv, 1); 162518781Sgibbs scsi_ctrl = ADV_INB(adv, ADV_REG_SC); 162618781Sgibbs adv_set_bank(adv, 0); 162718781Sgibbs return (scsi_ctrl); 162818781Sgibbs} 162918781Sgibbs#endif 163018781Sgibbs 163118781Sgibbs/* 163218781Sgibbs * XXX Looks like more padding issues in this routine as well. 163318781Sgibbs * There has to be a way to turn this into an insw. 163418781Sgibbs */ 163518781Sgibbsstatic void 163639217Sgibbsadv_get_q_info(struct adv_softc *adv, u_int16_t s_addr, 163739217Sgibbs u_int16_t *inbuf, int words) 163818781Sgibbs{ 163918781Sgibbs int i; 164018781Sgibbs 164118781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr); 164218781Sgibbs for (i = 0; i < words; i++, inbuf++) { 164318781Sgibbs if (i == 5) { 164418781Sgibbs continue; 164518781Sgibbs } 164618781Sgibbs *inbuf = ADV_INW(adv, ADV_LRAM_DATA); 164718781Sgibbs } 164818781Sgibbs} 164918781Sgibbs 165018781Sgibbsstatic u_int 165139217Sgibbsadv_get_num_free_queues(struct adv_softc *adv, u_int8_t n_qs) 165218781Sgibbs{ 165318781Sgibbs u_int cur_used_qs; 165418781Sgibbs u_int cur_free_qs; 165518781Sgibbs 165639217Sgibbs cur_used_qs = adv->cur_active + ADV_MIN_FREE_Q; 165718781Sgibbs 165818781Sgibbs if ((cur_used_qs + n_qs) <= adv->max_openings) { 165918781Sgibbs cur_free_qs = adv->max_openings - cur_used_qs; 166018781Sgibbs return (cur_free_qs); 166118781Sgibbs } 166239217Sgibbs adv->openings_needed = n_qs; 166318781Sgibbs return (0); 166418781Sgibbs} 166518781Sgibbs 166618781Sgibbsstatic u_int8_t 166739217Sgibbsadv_alloc_free_queues(struct adv_softc *adv, u_int8_t free_q_head, 166839217Sgibbs u_int8_t n_free_q) 166918781Sgibbs{ 167018781Sgibbs int i; 167118781Sgibbs 167218781Sgibbs for (i = 0; i < n_free_q; i++) { 167318781Sgibbs free_q_head = adv_alloc_free_queue(adv, free_q_head); 167418781Sgibbs if (free_q_head == ADV_QLINK_END) 167518781Sgibbs break; 167618781Sgibbs } 167718781Sgibbs return (free_q_head); 167818781Sgibbs} 167918781Sgibbs 168018781Sgibbsstatic u_int8_t 168139217Sgibbsadv_alloc_free_queue(struct adv_softc *adv, u_int8_t free_q_head) 168218781Sgibbs{ 168318781Sgibbs u_int16_t q_addr; 168418781Sgibbs u_int8_t next_qp; 168518781Sgibbs u_int8_t q_status; 168618781Sgibbs 168718781Sgibbs next_qp = ADV_QLINK_END; 168818781Sgibbs q_addr = ADV_QNO_TO_QADDR(free_q_head); 168918781Sgibbs q_status = adv_read_lram_8(adv, q_addr + ADV_SCSIQ_B_STATUS); 169018781Sgibbs 169118781Sgibbs if ((q_status & QS_READY) == 0) 169218781Sgibbs next_qp = adv_read_lram_8(adv, q_addr + ADV_SCSIQ_B_FWD); 169318781Sgibbs 169418781Sgibbs return (next_qp); 169518781Sgibbs} 169618781Sgibbs 169718781Sgibbsstatic int 169839217Sgibbsadv_send_scsi_queue(struct adv_softc *adv, struct adv_scsi_q *scsiq, 169939217Sgibbs u_int8_t n_q_required) 170018781Sgibbs{ 170118781Sgibbs u_int8_t free_q_head; 170218781Sgibbs u_int8_t next_qp; 170318781Sgibbs u_int8_t tid_no; 170418781Sgibbs u_int8_t target_ix; 170518781Sgibbs int retval; 170618781Sgibbs 170718781Sgibbs retval = 1; 170818781Sgibbs target_ix = scsiq->q2.target_ix; 170918781Sgibbs tid_no = ADV_TIX_TO_TID(target_ix); 171018781Sgibbs free_q_head = adv_read_lram_16(adv, ADVV_FREE_Q_HEAD_W) & 0xFF; 171118781Sgibbs if ((next_qp = adv_alloc_free_queues(adv, free_q_head, n_q_required)) 171218781Sgibbs != ADV_QLINK_END) { 171318781Sgibbs scsiq->q1.q_no = free_q_head; 171418781Sgibbs 171518781Sgibbs /* 171618781Sgibbs * Now that we know our Q number, point our sense 171739217Sgibbs * buffer pointer to a bus dma mapped area where 171839217Sgibbs * we can dma the data to. 171918781Sgibbs */ 172039217Sgibbs scsiq->q1.sense_addr = adv->sense_physbase 172139217Sgibbs + ((free_q_head - 1) * sizeof(struct scsi_sense_data)); 172218781Sgibbs adv_put_ready_sg_list_queue(adv, scsiq, free_q_head); 172318781Sgibbs adv_write_lram_16(adv, ADVV_FREE_Q_HEAD_W, next_qp); 172418781Sgibbs adv->cur_active += n_q_required; 172518781Sgibbs retval = 0; 172618781Sgibbs } 172718781Sgibbs return (retval); 172818781Sgibbs} 172918781Sgibbs 173018781Sgibbs 173118781Sgibbsstatic void 173239217Sgibbsadv_put_ready_sg_list_queue(struct adv_softc *adv, struct adv_scsi_q *scsiq, 173339217Sgibbs u_int q_no) 173418781Sgibbs{ 173518781Sgibbs u_int8_t sg_list_dwords; 173618781Sgibbs u_int8_t sg_index, i; 173718781Sgibbs u_int8_t sg_entry_cnt; 173818781Sgibbs u_int8_t next_qp; 173918781Sgibbs u_int16_t q_addr; 174018781Sgibbs struct adv_sg_head *sg_head; 174118781Sgibbs struct adv_sg_list_q scsi_sg_q; 174218781Sgibbs 174318781Sgibbs sg_head = scsiq->sg_head; 174418781Sgibbs 174518781Sgibbs if (sg_head) { 174618781Sgibbs sg_entry_cnt = sg_head->entry_cnt - 1; 174718781Sgibbs#ifdef DIAGNOSTIC 174818781Sgibbs if (sg_entry_cnt == 0) 174939217Sgibbs panic("adv_put_ready_sg_list_queue: ScsiQ with " 175039217Sgibbs "a SG list but only one element"); 175118781Sgibbs if ((scsiq->q1.cntl & QC_SG_HEAD) == 0) 175239217Sgibbs panic("adv_put_ready_sg_list_queue: ScsiQ with " 175339217Sgibbs "a SG list but QC_SG_HEAD not set"); 175418781Sgibbs#endif 175518781Sgibbs q_addr = ADV_QNO_TO_QADDR(q_no); 175618781Sgibbs sg_index = 1; 175718781Sgibbs scsiq->q1.sg_queue_cnt = sg_head->queue_cnt; 175818781Sgibbs scsi_sg_q.sg_head_qp = q_no; 175918781Sgibbs scsi_sg_q.cntl = QCSG_SG_XFER_LIST; 176018781Sgibbs for (i = 0; i < sg_head->queue_cnt; i++) { 176118781Sgibbs u_int8_t segs_this_q; 176218781Sgibbs 176318781Sgibbs if (sg_entry_cnt > ADV_SG_LIST_PER_Q) 176418781Sgibbs segs_this_q = ADV_SG_LIST_PER_Q; 176518781Sgibbs else { 176618781Sgibbs /* This will be the last segment then */ 176718781Sgibbs segs_this_q = sg_entry_cnt; 176818781Sgibbs scsi_sg_q.cntl |= QCSG_SG_XFER_END; 176918781Sgibbs } 177018781Sgibbs scsi_sg_q.seq_no = i + 1; 177139217Sgibbs sg_list_dwords = segs_this_q << 1; 177218781Sgibbs if (i == 0) { 177318781Sgibbs scsi_sg_q.sg_list_cnt = segs_this_q; 177418781Sgibbs scsi_sg_q.sg_cur_list_cnt = segs_this_q; 177518781Sgibbs } else { 177618781Sgibbs scsi_sg_q.sg_list_cnt = segs_this_q - 1; 177718781Sgibbs scsi_sg_q.sg_cur_list_cnt = segs_this_q - 1; 177818781Sgibbs } 177918781Sgibbs next_qp = adv_read_lram_8(adv, q_addr + ADV_SCSIQ_B_FWD); 178018781Sgibbs scsi_sg_q.q_no = next_qp; 178118781Sgibbs q_addr = ADV_QNO_TO_QADDR(next_qp); 178218781Sgibbs 178339217Sgibbs adv_write_lram_16_multi(adv, 178439217Sgibbs q_addr + ADV_SCSIQ_SGHD_CPY_BEG, 178518781Sgibbs (u_int16_t *)&scsi_sg_q, 178618781Sgibbs sizeof(scsi_sg_q) >> 1); 178718781Sgibbs adv_write_lram_32_multi(adv, q_addr + ADV_SGQ_LIST_BEG, 178818781Sgibbs (u_int32_t *)&sg_head->sg_list[sg_index], 178918781Sgibbs sg_list_dwords); 179018781Sgibbs sg_entry_cnt -= segs_this_q; 179118781Sgibbs sg_index += ADV_SG_LIST_PER_Q; 179218781Sgibbs } 179318781Sgibbs } 179418781Sgibbs adv_put_ready_queue(adv, scsiq, q_no); 179518781Sgibbs} 179618781Sgibbs 179718781Sgibbsstatic void 179839217Sgibbsadv_put_ready_queue(struct adv_softc *adv, struct adv_scsi_q *scsiq, 179939217Sgibbs u_int q_no) 180018781Sgibbs{ 180139217Sgibbs struct adv_target_transinfo* tinfo; 180239217Sgibbs u_int q_addr; 180339217Sgibbs u_int tid_no; 180418781Sgibbs 180539217Sgibbs tid_no = ADV_TIX_TO_TID(scsiq->q2.target_ix); 180639217Sgibbs tinfo = &adv->tinfo[tid_no]; 180746581Sken if ((tinfo->current.period != tinfo->goal.period) 180846581Sken || (tinfo->current.offset != tinfo->goal.offset)) { 180918781Sgibbs 181039217Sgibbs adv_msgout_sdtr(adv, tinfo->goal.period, tinfo->goal.offset); 181118781Sgibbs scsiq->q1.cntl |= QC_MSG_OUT; 181218781Sgibbs } 181318781Sgibbs q_addr = ADV_QNO_TO_QADDR(q_no); 181418781Sgibbs 181518781Sgibbs scsiq->q1.status = QS_FREE; 181618781Sgibbs 181718781Sgibbs adv_write_lram_16_multi(adv, q_addr + ADV_SCSIQ_CDB_BEG, 181818781Sgibbs (u_int16_t *)scsiq->cdbptr, 181918781Sgibbs scsiq->q2.cdb_len >> 1); 182018781Sgibbs 182118781Sgibbs#if BYTE_ORDER == BIG_ENDIAN 182218781Sgibbs adv_adj_scsiq_endian(scsiq); 182318781Sgibbs#endif 182418781Sgibbs 182518781Sgibbs adv_put_scsiq(adv, q_addr + ADV_SCSIQ_CPY_BEG, 182618781Sgibbs (u_int16_t *) &scsiq->q1.cntl, 182718781Sgibbs ((sizeof(scsiq->q1) + sizeof(scsiq->q2)) / 2) - 1); 182818781Sgibbs 1829153072Sru#ifdef CC_WRITE_IO_COUNT 183018781Sgibbs adv_write_lram_16(adv, q_addr + ADV_SCSIQ_W_REQ_COUNT, 183118781Sgibbs adv->req_count); 183218781Sgibbs#endif 183318781Sgibbs 1834153072Sru#ifdef CC_CLEAR_DMA_REMAIN 183518781Sgibbs 183618781Sgibbs adv_write_lram_32(adv, q_addr + ADV_SCSIQ_DW_REMAIN_XFER_ADDR, 0); 183718781Sgibbs adv_write_lram_32(adv, q_addr + ADV_SCSIQ_DW_REMAIN_XFER_CNT, 0); 183818781Sgibbs#endif 183918781Sgibbs 184018781Sgibbs adv_write_lram_16(adv, q_addr + ADV_SCSIQ_B_STATUS, 184118781Sgibbs (scsiq->q1.q_no << 8) | QS_READY); 184218781Sgibbs} 184318781Sgibbs 184418781Sgibbsstatic void 184539217Sgibbsadv_put_scsiq(struct adv_softc *adv, u_int16_t s_addr, 184639217Sgibbs u_int16_t *buffer, int words) 184718781Sgibbs{ 184818781Sgibbs int i; 184918781Sgibbs 185018781Sgibbs /* 185118781Sgibbs * XXX This routine makes *gross* assumptions 185218781Sgibbs * about padding in the data structures. 185318781Sgibbs * Either the data structures should have explicit 185418781Sgibbs * padding members added, or they should have padding 185518781Sgibbs * turned off via compiler attributes depending on 185618781Sgibbs * which yields better overall performance. My hunch 185718781Sgibbs * would be that turning off padding would be the 185818781Sgibbs * faster approach as an outsw is much faster than 185918781Sgibbs * this crude loop and accessing un-aligned data 186018781Sgibbs * members isn't *that* expensive. The other choice 186118781Sgibbs * would be to modify the ASC script so that the 186218781Sgibbs * the adv_scsiq_1 structure can be re-arranged so 186318781Sgibbs * padding isn't required. 186418781Sgibbs */ 186518781Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr); 186618781Sgibbs for (i = 0; i < words; i++, buffer++) { 186718781Sgibbs if (i == 2 || i == 10) { 186818781Sgibbs continue; 186918781Sgibbs } 187018781Sgibbs ADV_OUTW(adv, ADV_LRAM_DATA, *buffer); 187118781Sgibbs } 187218781Sgibbs} 187318781Sgibbs 1874111342Sobrien#if BYTE_ORDER == BIG_ENDIAN 1875111342Sobrienvoid 1876111342Sobrienadv_adj_endian_qdone_info(struct adv_q_done_info *scsiq) 1877111342Sobrien{ 1878111342Sobrien 1879111342Sobrien panic("adv(4) not supported on big-endian machines.\n"); 1880111342Sobrien} 1881111342Sobrien 1882111342Sobrienvoid 1883111342Sobrienadv_adj_scsiq_endian(struct adv_scsi_q *scsiq) 1884111342Sobrien{ 1885111342Sobrien 1886111342Sobrien panic("adv(4) not supported on big-endian machines.\n"); 1887111342Sobrien} 1888111342Sobrien#endif 1889111342Sobrien 189039217Sgibbsstatic void 189139217Sgibbsadv_handle_extmsg_in(struct adv_softc *adv, u_int16_t halt_q_addr, 189239217Sgibbs u_int8_t q_cntl, target_bit_vector target_mask, 189339217Sgibbs int tid_no) 189418781Sgibbs{ 189539217Sgibbs struct ext_msg ext_msg; 189618781Sgibbs 189739217Sgibbs adv_read_lram_16_multi(adv, ADVV_MSGIN_BEG, (u_int16_t *) &ext_msg, 189839217Sgibbs sizeof(ext_msg) >> 1); 189939217Sgibbs if ((ext_msg.msg_type == MSG_EXTENDED) 190039217Sgibbs && (ext_msg.msg_req == MSG_EXT_SDTR) 190139217Sgibbs && (ext_msg.msg_len == MSG_EXT_SDTR_LEN)) { 190255945Sgibbs union ccb *ccb; 190355945Sgibbs struct adv_target_transinfo* tinfo; 190455945Sgibbs u_int32_t cinfo_index; 190539217Sgibbs u_int period; 190639217Sgibbs u_int offset; 190739217Sgibbs int sdtr_accept; 190839217Sgibbs u_int8_t orig_offset; 190939217Sgibbs 191055945Sgibbs cinfo_index = 191155945Sgibbs adv_read_lram_32(adv, halt_q_addr + ADV_SCSIQ_D_CINFO_IDX); 191255945Sgibbs ccb = adv->ccb_infos[cinfo_index].ccb; 191339217Sgibbs tinfo = &adv->tinfo[tid_no]; 191439217Sgibbs sdtr_accept = TRUE; 191539217Sgibbs 191639217Sgibbs orig_offset = ext_msg.req_ack_offset; 191739217Sgibbs if (ext_msg.xfer_period < tinfo->goal.period) { 191839217Sgibbs sdtr_accept = FALSE; 191939217Sgibbs ext_msg.xfer_period = tinfo->goal.period; 192039217Sgibbs } 192139217Sgibbs 192239217Sgibbs /* Perform range checking */ 192339217Sgibbs period = ext_msg.xfer_period; 192439217Sgibbs offset = ext_msg.req_ack_offset; 192539217Sgibbs adv_period_offset_to_sdtr(adv, &period, &offset, tid_no); 192639217Sgibbs ext_msg.xfer_period = period; 192739217Sgibbs ext_msg.req_ack_offset = offset; 192839217Sgibbs 192939217Sgibbs /* Record our current sync settings */ 193039217Sgibbs adv_set_syncrate(adv, ccb->ccb_h.path, 193139217Sgibbs tid_no, ext_msg.xfer_period, 193239217Sgibbs ext_msg.req_ack_offset, 193339217Sgibbs ADV_TRANS_GOAL|ADV_TRANS_ACTIVE); 193439217Sgibbs 193539217Sgibbs /* Offset too high or large period forced async */ 193639217Sgibbs if (orig_offset != ext_msg.req_ack_offset) 193739217Sgibbs sdtr_accept = FALSE; 193839217Sgibbs 193939217Sgibbs if (sdtr_accept && (q_cntl & QC_MSG_OUT)) { 194039217Sgibbs /* Valid response to our requested negotiation */ 194139217Sgibbs q_cntl &= ~QC_MSG_OUT; 194239217Sgibbs } else { 194339217Sgibbs /* Must Respond */ 194439217Sgibbs q_cntl |= QC_MSG_OUT; 194539217Sgibbs adv_msgout_sdtr(adv, ext_msg.xfer_period, 194639217Sgibbs ext_msg.req_ack_offset); 194739217Sgibbs } 194839217Sgibbs 194939217Sgibbs } else if (ext_msg.msg_type == MSG_EXTENDED 195039217Sgibbs && ext_msg.msg_req == MSG_EXT_WDTR 195139217Sgibbs && ext_msg.msg_len == MSG_EXT_WDTR_LEN) { 195239217Sgibbs 195339217Sgibbs ext_msg.wdtr_width = 0; 195439217Sgibbs adv_write_lram_16_multi(adv, ADVV_MSGOUT_BEG, 195539217Sgibbs (u_int16_t *)&ext_msg, 195639217Sgibbs sizeof(ext_msg) >> 1); 195739217Sgibbs q_cntl |= QC_MSG_OUT; 195839217Sgibbs } else { 195939217Sgibbs 196039217Sgibbs ext_msg.msg_type = MSG_MESSAGE_REJECT; 196139217Sgibbs adv_write_lram_16_multi(adv, ADVV_MSGOUT_BEG, 196239217Sgibbs (u_int16_t *)&ext_msg, 196339217Sgibbs sizeof(ext_msg) >> 1); 196439217Sgibbs q_cntl |= QC_MSG_OUT; 196539217Sgibbs } 196639217Sgibbs adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_CNTL, q_cntl); 196739217Sgibbs} 196839217Sgibbs 196939217Sgibbsstatic void 197039217Sgibbsadv_msgout_sdtr(struct adv_softc *adv, u_int8_t sdtr_period, 197139217Sgibbs u_int8_t sdtr_offset) 197239217Sgibbs{ 197339217Sgibbs struct ext_msg sdtr_buf; 197439217Sgibbs 197518781Sgibbs sdtr_buf.msg_type = MSG_EXTENDED; 197618781Sgibbs sdtr_buf.msg_len = MSG_EXT_SDTR_LEN; 197718781Sgibbs sdtr_buf.msg_req = MSG_EXT_SDTR; 197818781Sgibbs sdtr_buf.xfer_period = sdtr_period; 197918781Sgibbs sdtr_offset &= ADV_SYN_MAX_OFFSET; 198018781Sgibbs sdtr_buf.req_ack_offset = sdtr_offset; 198118781Sgibbs adv_write_lram_16_multi(adv, ADVV_MSGOUT_BEG, 198218781Sgibbs (u_int16_t *) &sdtr_buf, 198318781Sgibbs sizeof(sdtr_buf) / 2); 198418781Sgibbs} 198518781Sgibbs 198639217Sgibbsint 198739217Sgibbsadv_abort_ccb(struct adv_softc *adv, int target, int lun, union ccb *ccb, 198839217Sgibbs u_int32_t status, int queued_only) 198918781Sgibbs{ 199039217Sgibbs u_int16_t q_addr; 199139217Sgibbs u_int8_t q_no; 199239217Sgibbs struct adv_q_done_info scsiq_buf; 199339217Sgibbs struct adv_q_done_info *scsiq; 199439217Sgibbs u_int8_t target_ix; 199539217Sgibbs int count; 199618781Sgibbs 199739217Sgibbs scsiq = &scsiq_buf; 199839217Sgibbs target_ix = ADV_TIDLUN_TO_IX(target, lun); 199939217Sgibbs count = 0; 200039217Sgibbs for (q_no = ADV_MIN_ACTIVE_QNO; q_no <= adv->max_openings; q_no++) { 200155945Sgibbs struct adv_ccb_info *ccb_info; 200239217Sgibbs q_addr = ADV_QNO_TO_QADDR(q_no); 200339217Sgibbs 200439217Sgibbs adv_copy_lram_doneq(adv, q_addr, scsiq, adv->max_dma_count); 200555945Sgibbs ccb_info = &adv->ccb_infos[scsiq->d2.ccb_index]; 200639217Sgibbs if (((scsiq->q_status & QS_READY) != 0) 200739217Sgibbs && ((scsiq->q_status & QS_ABORTED) == 0) 200839217Sgibbs && ((scsiq->cntl & QCSG_SG_XFER_LIST) == 0) 200939217Sgibbs && (scsiq->d2.target_ix == target_ix) 201039217Sgibbs && (queued_only == 0 201139217Sgibbs || !(scsiq->q_status & (QS_DISC1|QS_DISC2|QS_BUSY|QS_DONE))) 201255945Sgibbs && (ccb == NULL || (ccb == ccb_info->ccb))) { 201339217Sgibbs union ccb *aborted_ccb; 201439217Sgibbs struct adv_ccb_info *cinfo; 201539217Sgibbs 201639217Sgibbs scsiq->q_status |= QS_ABORTED; 201739217Sgibbs adv_write_lram_8(adv, q_addr + ADV_SCSIQ_B_STATUS, 201839217Sgibbs scsiq->q_status); 201955945Sgibbs aborted_ccb = ccb_info->ccb; 202039217Sgibbs /* Don't clobber earlier error codes */ 202139217Sgibbs if ((aborted_ccb->ccb_h.status & CAM_STATUS_MASK) 202239217Sgibbs == CAM_REQ_INPROG) 202339217Sgibbs aborted_ccb->ccb_h.status |= status; 202439217Sgibbs cinfo = (struct adv_ccb_info *) 202539217Sgibbs aborted_ccb->ccb_h.ccb_cinfo_ptr; 202639217Sgibbs cinfo->state |= ACCB_ABORT_QUEUED; 202739217Sgibbs count++; 202818781Sgibbs } 202918781Sgibbs } 203039217Sgibbs return (count); 203118781Sgibbs} 203218781Sgibbs 203339217Sgibbsint 203455945Sgibbsadv_reset_bus(struct adv_softc *adv, int initiate_bus_reset) 203539217Sgibbs{ 203639217Sgibbs int count; 203739217Sgibbs int i; 203839217Sgibbs union ccb *ccb; 203939217Sgibbs 204055945Sgibbs i = 200; 204155945Sgibbs while ((ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_SCSI_RESET_ACTIVE) != 0 204255945Sgibbs && i--) 204355945Sgibbs DELAY(1000); 204455945Sgibbs adv_reset_chip(adv, initiate_bus_reset); 204539217Sgibbs adv_reinit_lram(adv); 204655945Sgibbs for (i = 0; i <= ADV_MAX_TID; i++) 204755945Sgibbs adv_set_syncrate(adv, NULL, i, /*period*/0, 204855945Sgibbs /*offset*/0, ADV_TRANS_CUR); 204939217Sgibbs ADV_OUTW(adv, ADV_REG_PROG_COUNTER, ADV_MCODE_START_ADDR); 205039217Sgibbs 205139217Sgibbs /* Tell the XPT layer that a bus reset occured */ 205239217Sgibbs if (adv->path != NULL) 205339217Sgibbs xpt_async(AC_BUS_RESET, adv->path, NULL); 205439217Sgibbs 205539217Sgibbs count = 0; 205639217Sgibbs while ((ccb = (union ccb *)LIST_FIRST(&adv->pending_ccbs)) != NULL) { 205739217Sgibbs if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) 205839217Sgibbs ccb->ccb_h.status |= CAM_SCSI_BUS_RESET; 205939217Sgibbs adv_done(adv, ccb, QD_ABORTED_BY_HOST, 0, 0, 0); 206039217Sgibbs count++; 206139217Sgibbs } 206239217Sgibbs 206339217Sgibbs adv_start_chip(adv); 206439217Sgibbs return (count); 206539217Sgibbs} 206639217Sgibbs 206718781Sgibbsstatic void 206839217Sgibbsadv_set_sdtr_reg_at_id(struct adv_softc *adv, int tid, u_int8_t sdtr_data) 206918781Sgibbs{ 207039217Sgibbs int orig_id; 207139217Sgibbs 207239217Sgibbs adv_set_bank(adv, 1); 207339217Sgibbs orig_id = ffs(ADV_INB(adv, ADV_HOST_SCSIID)) - 1; 207439217Sgibbs ADV_OUTB(adv, ADV_HOST_SCSIID, tid); 207539217Sgibbs if (ADV_INB(adv, ADV_HOST_SCSIID) == (0x01 << tid)) { 207639217Sgibbs adv_set_bank(adv, 0); 207739217Sgibbs ADV_OUTB(adv, ADV_SYN_OFFSET, sdtr_data); 207839217Sgibbs } 207939217Sgibbs adv_set_bank(adv, 1); 208039217Sgibbs ADV_OUTB(adv, ADV_HOST_SCSIID, orig_id); 208139217Sgibbs adv_set_bank(adv, 0); 208218781Sgibbs} 2083