advansys.c revision 55945
139217Sgibbs/* 239217Sgibbs * Generic driver for the Advanced Systems Inc. SCSI controllers 339217Sgibbs * Product specific probe and attach routines can be found in: 439217Sgibbs * 539217Sgibbs * i386/isa/adv_isa.c ABP5140, ABP542, ABP5150, ABP842, ABP852 639217Sgibbs * i386/eisa/adv_eisa.c ABP742, ABP752 739217Sgibbs * pci/adv_pci.c ABP920, ABP930, ABP930U, ABP930UA, ABP940, ABP940U, 839217Sgibbs * ABP940UA, ABP950, ABP960, ABP960U, ABP960UA, 939217Sgibbs * ABP970, ABP970U 1039217Sgibbs * 1155945Sgibbs * Copyright (c) 1996-2000 Justin Gibbs. 1239217Sgibbs * All rights reserved. 1339217Sgibbs * 1439217Sgibbs * Redistribution and use in source and binary forms, with or without 1539217Sgibbs * modification, are permitted provided that the following conditions 1639217Sgibbs * are met: 1739217Sgibbs * 1. Redistributions of source code must retain the above copyright 1839217Sgibbs * notice, this list of conditions, and the following disclaimer, 1939217Sgibbs * without modification, immediately at the beginning of the file. 2039217Sgibbs * 2. The name of the author may not be used to endorse or promote products 2139217Sgibbs * derived from this software without specific prior written permission. 2239217Sgibbs * 2339217Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2439217Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2539217Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2639217Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2739217Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2839217Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2939217Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3039217Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3139217Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3239217Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3339217Sgibbs * SUCH DAMAGE. 3439217Sgibbs * 3550477Speter * $FreeBSD: head/sys/dev/advansys/advansys.c 55945 2000-01-14 03:33:38Z gibbs $ 3639217Sgibbs */ 3739217Sgibbs/* 3839217Sgibbs * Ported from: 3939217Sgibbs * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters 4039217Sgibbs * 4139217Sgibbs * Copyright (c) 1995-1997 Advanced System Products, Inc. 4239217Sgibbs * All Rights Reserved. 4339217Sgibbs * 4439217Sgibbs * Redistribution and use in source and binary forms, with or without 4539217Sgibbs * modification, are permitted provided that redistributions of source 4639217Sgibbs * code retain the above copyright notice and this comment without 4739217Sgibbs * modification. 4839217Sgibbs */ 4939217Sgibbs 5039217Sgibbs#include <sys/param.h> 5139217Sgibbs#include <sys/systm.h> 5239217Sgibbs#include <sys/malloc.h> 5339217Sgibbs#include <sys/buf.h> 5439217Sgibbs#include <sys/kernel.h> 5539217Sgibbs 5639217Sgibbs#include <machine/bus_pio.h> 5739217Sgibbs#include <machine/bus.h> 5839217Sgibbs#include <machine/clock.h> 5939217Sgibbs 6039217Sgibbs#include <cam/cam.h> 6139217Sgibbs#include <cam/cam_ccb.h> 6239217Sgibbs#include <cam/cam_sim.h> 6339217Sgibbs#include <cam/cam_xpt_sim.h> 6439217Sgibbs#include <cam/cam_xpt_periph.h> 6539217Sgibbs#include <cam/cam_debug.h> 6639217Sgibbs 6739217Sgibbs#include <cam/scsi/scsi_all.h> 6839217Sgibbs#include <cam/scsi/scsi_message.h> 6939217Sgibbs 7039217Sgibbs#include <vm/vm.h> 7139217Sgibbs#include <vm/vm_param.h> 7239217Sgibbs#include <vm/pmap.h> 7339217Sgibbs 7439217Sgibbs#include <dev/advansys/advansys.h> 7539217Sgibbs 7639217Sgibbsu_long adv_unit; 7739217Sgibbs 7839217Sgibbsstatic void adv_action(struct cam_sim *sim, union ccb *ccb); 7939217Sgibbsstatic void adv_execute_ccb(void *arg, bus_dma_segment_t *dm_segs, 8039217Sgibbs int nsegments, int error); 8139217Sgibbsstatic void adv_poll(struct cam_sim *sim); 8239217Sgibbsstatic void adv_run_doneq(struct adv_softc *adv); 8339217Sgibbsstatic struct adv_ccb_info * 8439217Sgibbs adv_alloc_ccb_info(struct adv_softc *adv); 8539217Sgibbsstatic void adv_destroy_ccb_info(struct adv_softc *adv, 8640420Sgibbs struct adv_ccb_info *cinfo); 8739217Sgibbsstatic __inline struct adv_ccb_info * 8839217Sgibbs adv_get_ccb_info(struct adv_softc *adv); 8939217Sgibbsstatic __inline void adv_free_ccb_info(struct adv_softc *adv, 9039217Sgibbs struct adv_ccb_info *cinfo); 9155945Sgibbsstatic __inline void adv_set_state(struct adv_softc *adv, adv_state state); 9255945Sgibbsstatic __inline void adv_clear_state(struct adv_softc *adv, union ccb* ccb); 9355945Sgibbsstatic void adv_clear_state_really(struct adv_softc *adv, union ccb* ccb); 9439217Sgibbs 9539217Sgibbsstruct adv_softc *advsoftcs[NADV]; /* XXX Config should handle this */ 9639217Sgibbs 9739217Sgibbsstatic __inline struct adv_ccb_info * 9839217Sgibbsadv_get_ccb_info(struct adv_softc *adv) 9939217Sgibbs{ 10039217Sgibbs struct adv_ccb_info *cinfo; 10139217Sgibbs int opri; 10239217Sgibbs 10339217Sgibbs opri = splcam(); 10439217Sgibbs if ((cinfo = SLIST_FIRST(&adv->free_ccb_infos)) != NULL) { 10539217Sgibbs SLIST_REMOVE_HEAD(&adv->free_ccb_infos, links); 10639217Sgibbs } else { 10739217Sgibbs cinfo = adv_alloc_ccb_info(adv); 10839217Sgibbs } 10939217Sgibbs splx(opri); 11039217Sgibbs 11139217Sgibbs return (cinfo); 11239217Sgibbs} 11339217Sgibbs 11439217Sgibbsstatic __inline void 11539217Sgibbsadv_free_ccb_info(struct adv_softc *adv, struct adv_ccb_info *cinfo) 11639217Sgibbs{ 11739217Sgibbs int opri; 11839217Sgibbs 11939217Sgibbs opri = splcam(); 12039217Sgibbs cinfo->state = ACCB_FREE; 12139217Sgibbs SLIST_INSERT_HEAD(&adv->free_ccb_infos, cinfo, links); 12239217Sgibbs splx(opri); 12339217Sgibbs} 12439217Sgibbs 12555945Sgibbsstatic __inline void 12655945Sgibbsadv_set_state(struct adv_softc *adv, adv_state state) 12755945Sgibbs{ 12855945Sgibbs if (adv->state == 0) 12955945Sgibbs xpt_freeze_simq(adv->sim, /*count*/1); 13055945Sgibbs adv->state |= state; 13155945Sgibbs} 13255945Sgibbs 13355945Sgibbsstatic __inline void 13455945Sgibbsadv_clear_state(struct adv_softc *adv, union ccb* ccb) 13555945Sgibbs{ 13655945Sgibbs if (adv->state != 0) 13755945Sgibbs adv_clear_state_really(adv, ccb); 13855945Sgibbs} 13955945Sgibbs 14055945Sgibbsstatic void 14155945Sgibbsadv_clear_state_really(struct adv_softc *adv, union ccb* ccb) 14255945Sgibbs{ 14355945Sgibbs if ((adv->state & ADV_BUSDMA_BLOCK_CLEARED) != 0) 14455945Sgibbs adv->state &= ~(ADV_BUSDMA_BLOCK_CLEARED|ADV_BUSDMA_BLOCK); 14555945Sgibbs if ((adv->state & ADV_RESOURCE_SHORTAGE) != 0) { 14655945Sgibbs int openings; 14755945Sgibbs 14855945Sgibbs openings = adv->max_openings - adv->cur_active - ADV_MIN_FREE_Q; 14955945Sgibbs if (openings >= adv->openings_needed) { 15055945Sgibbs adv->state &= ~ADV_RESOURCE_SHORTAGE; 15155945Sgibbs adv->openings_needed = 0; 15255945Sgibbs } 15355945Sgibbs } 15455945Sgibbs 15555945Sgibbs if ((adv->state & ADV_IN_TIMEOUT) != 0) { 15655945Sgibbs struct adv_ccb_info *cinfo; 15755945Sgibbs 15855945Sgibbs cinfo = (struct adv_ccb_info *)ccb->ccb_h.ccb_cinfo_ptr; 15955945Sgibbs if ((cinfo->state & ACCB_RECOVERY_CCB) != 0) { 16055945Sgibbs struct ccb_hdr *ccb_h; 16155945Sgibbs 16255945Sgibbs /* 16355945Sgibbs * We now traverse our list of pending CCBs 16455945Sgibbs * and reinstate their timeouts. 16555945Sgibbs */ 16655945Sgibbs ccb_h = LIST_FIRST(&adv->pending_ccbs); 16755945Sgibbs while (ccb_h != NULL) { 16855945Sgibbs ccb_h->timeout_ch = 16955945Sgibbs timeout(adv_timeout, (caddr_t)ccb_h, 17055945Sgibbs (ccb_h->timeout * hz) / 1000); 17155945Sgibbs ccb_h = LIST_NEXT(ccb_h, sim_links.le); 17255945Sgibbs } 17355945Sgibbs adv->state &= ~ADV_IN_TIMEOUT; 17455945Sgibbs printf("%s: No longer in timeout\n", adv_name(adv)); 17555945Sgibbs } 17655945Sgibbs } 17755945Sgibbs if (adv->state == 0) 17855945Sgibbs ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 17955945Sgibbs} 18055945Sgibbs 18139217Sgibbsvoid 18239217Sgibbsadv_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) 18339217Sgibbs{ 18439217Sgibbs bus_addr_t* physaddr; 18539217Sgibbs 18639217Sgibbs physaddr = (bus_addr_t*)arg; 18739217Sgibbs *physaddr = segs->ds_addr; 18839217Sgibbs} 18939217Sgibbs 19039217Sgibbschar * 19139217Sgibbsadv_name(struct adv_softc *adv) 19239217Sgibbs{ 19339217Sgibbs static char name[10]; 19439217Sgibbs 19541514Sarchie snprintf(name, sizeof(name), "adv%d", adv->unit); 19639217Sgibbs return (name); 19739217Sgibbs} 19839217Sgibbs 19939217Sgibbsstatic void 20039217Sgibbsadv_action(struct cam_sim *sim, union ccb *ccb) 20139217Sgibbs{ 20239217Sgibbs struct adv_softc *adv; 20339217Sgibbs 20439217Sgibbs CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("adv_action\n")); 20539217Sgibbs 20639217Sgibbs adv = (struct adv_softc *)cam_sim_softc(sim); 20739217Sgibbs 20839217Sgibbs switch (ccb->ccb_h.func_code) { 20939217Sgibbs /* Common cases first */ 21039217Sgibbs case XPT_SCSI_IO: /* Execute the requested I/O operation */ 21139217Sgibbs { 21239217Sgibbs struct ccb_hdr *ccb_h; 21339217Sgibbs struct ccb_scsiio *csio; 21439217Sgibbs struct adv_ccb_info *cinfo; 21539217Sgibbs 21639217Sgibbs ccb_h = &ccb->ccb_h; 21739217Sgibbs csio = &ccb->csio; 21839217Sgibbs cinfo = adv_get_ccb_info(adv); 21939217Sgibbs if (cinfo == NULL) 22039217Sgibbs panic("XXX Handle CCB info error!!!"); 22139217Sgibbs 22239217Sgibbs ccb_h->ccb_cinfo_ptr = cinfo; 22355945Sgibbs cinfo->ccb = ccb; 22439217Sgibbs 22539217Sgibbs /* Only use S/G if there is a transfer */ 22639217Sgibbs if ((ccb_h->flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 22739217Sgibbs if ((ccb_h->flags & CAM_SCATTER_VALID) == 0) { 22839217Sgibbs /* 22939217Sgibbs * We've been given a pointer 23039217Sgibbs * to a single buffer 23139217Sgibbs */ 23239217Sgibbs if ((ccb_h->flags & CAM_DATA_PHYS) == 0) { 23339217Sgibbs int s; 23439217Sgibbs int error; 23539217Sgibbs 23639217Sgibbs s = splsoftvm(); 23739217Sgibbs error = 23839217Sgibbs bus_dmamap_load(adv->buffer_dmat, 23939217Sgibbs cinfo->dmamap, 24039217Sgibbs csio->data_ptr, 24139217Sgibbs csio->dxfer_len, 24239217Sgibbs adv_execute_ccb, 24339217Sgibbs csio, /*flags*/0); 24439217Sgibbs if (error == EINPROGRESS) { 24539217Sgibbs /* 24639217Sgibbs * So as to maintain ordering, 24739217Sgibbs * freeze the controller queue 24839217Sgibbs * until our mapping is 24939217Sgibbs * returned. 25039217Sgibbs */ 25155945Sgibbs adv_set_state(adv, 25255945Sgibbs ADV_BUSDMA_BLOCK); 25339217Sgibbs } 25439217Sgibbs splx(s); 25539217Sgibbs } else { 25639217Sgibbs struct bus_dma_segment seg; 25739217Sgibbs 25839217Sgibbs /* Pointer to physical buffer */ 25939217Sgibbs seg.ds_addr = 26039217Sgibbs (bus_addr_t)csio->data_ptr; 26139217Sgibbs seg.ds_len = csio->dxfer_len; 26239217Sgibbs adv_execute_ccb(csio, &seg, 1, 0); 26339217Sgibbs } 26439217Sgibbs } else { 26539217Sgibbs struct bus_dma_segment *segs; 26639217Sgibbs if ((ccb_h->flags & CAM_DATA_PHYS) != 0) 26739217Sgibbs panic("adv_setup_data - Physical " 26839217Sgibbs "segment pointers unsupported"); 26939217Sgibbs 27039217Sgibbs if ((ccb_h->flags & CAM_SG_LIST_PHYS) == 0) 27139217Sgibbs panic("adv_setup_data - Virtual " 27239217Sgibbs "segment addresses unsupported"); 27339217Sgibbs 27439217Sgibbs /* Just use the segments provided */ 27539217Sgibbs segs = (struct bus_dma_segment *)csio->data_ptr; 27639217Sgibbs adv_execute_ccb(ccb, segs, csio->sglist_cnt, 0); 27739217Sgibbs } 27839217Sgibbs } else { 27939217Sgibbs adv_execute_ccb(ccb, NULL, 0, 0); 28039217Sgibbs } 28139217Sgibbs break; 28239217Sgibbs } 28339217Sgibbs case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ 28439217Sgibbs case XPT_TARGET_IO: /* Execute target I/O request */ 28539217Sgibbs case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */ 28639217Sgibbs case XPT_CONT_TARGET_IO: /* Continue Host Target I/O Connection*/ 28739217Sgibbs case XPT_EN_LUN: /* Enable LUN as a target */ 28839217Sgibbs case XPT_ABORT: /* Abort the specified CCB */ 28939217Sgibbs /* XXX Implement */ 29039217Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 29139217Sgibbs xpt_done(ccb); 29239217Sgibbs break; 29339217Sgibbs case XPT_SET_TRAN_SETTINGS: 29439217Sgibbs { 29539217Sgibbs struct ccb_trans_settings *cts; 29639217Sgibbs target_bit_vector targ_mask; 29746581Sken struct adv_transinfo *tconf; 29839217Sgibbs u_int update_type; 29939217Sgibbs int s; 30039217Sgibbs 30139217Sgibbs cts = &ccb->cts; 30239217Sgibbs targ_mask = ADV_TID_TO_TARGET_MASK(cts->ccb_h.target_id); 30339217Sgibbs update_type = 0; 30446581Sken 30546581Sken /* 30646581Sken * The user must specify which type of settings he wishes 30746581Sken * to change. 30846581Sken */ 30946581Sken if (((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) 31046581Sken && ((cts->flags & CCB_TRANS_USER_SETTINGS) == 0)) { 31146581Sken tconf = &adv->tinfo[cts->ccb_h.target_id].current; 31239217Sgibbs update_type |= ADV_TRANS_GOAL; 31346581Sken } else if (((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) 31446581Sken && ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) == 0)) { 31546581Sken tconf = &adv->tinfo[cts->ccb_h.target_id].user; 31639217Sgibbs update_type |= ADV_TRANS_USER; 31746581Sken } else { 31846581Sken ccb->ccb_h.status = CAM_REQ_INVALID; 31946581Sken break; 32046581Sken } 32139217Sgibbs 32239217Sgibbs s = splcam(); 32339217Sgibbs 32439217Sgibbs if ((update_type & ADV_TRANS_GOAL) != 0) { 32539217Sgibbs if ((cts->valid & CCB_TRANS_DISC_VALID) != 0) { 32639217Sgibbs if ((cts->flags & CCB_TRANS_DISC_ENB) != 0) 32739217Sgibbs adv->disc_enable |= targ_mask; 32839217Sgibbs else 32939217Sgibbs adv->disc_enable &= ~targ_mask; 33039217Sgibbs adv_write_lram_8(adv, ADVV_DISC_ENABLE_B, 33139217Sgibbs adv->disc_enable); 33239217Sgibbs } 33339217Sgibbs 33439217Sgibbs if ((cts->valid & CCB_TRANS_TQ_VALID) != 0) { 33539217Sgibbs if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) 33639217Sgibbs adv->cmd_qng_enabled |= targ_mask; 33739217Sgibbs else 33839217Sgibbs adv->cmd_qng_enabled &= ~targ_mask; 33939217Sgibbs } 34039217Sgibbs } 34139217Sgibbs 34239217Sgibbs if ((update_type & ADV_TRANS_USER) != 0) { 34339217Sgibbs if ((cts->valid & CCB_TRANS_DISC_VALID) != 0) { 34439217Sgibbs if ((cts->flags & CCB_TRANS_DISC_ENB) != 0) 34539217Sgibbs adv->user_disc_enable |= targ_mask; 34639217Sgibbs else 34739217Sgibbs adv->user_disc_enable &= ~targ_mask; 34839217Sgibbs } 34939217Sgibbs 35039217Sgibbs if ((cts->valid & CCB_TRANS_TQ_VALID) != 0) { 35139217Sgibbs if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) 35239217Sgibbs adv->user_cmd_qng_enabled |= targ_mask; 35339217Sgibbs else 35439217Sgibbs adv->user_cmd_qng_enabled &= ~targ_mask; 35539217Sgibbs } 35639217Sgibbs } 35739217Sgibbs 35846581Sken /* 35946581Sken * If the user specifies either the sync rate, or offset, 36046581Sken * but not both, the unspecified parameter defaults to its 36146581Sken * current value in transfer negotiations. 36246581Sken */ 36346581Sken if (((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0) 36446581Sken || ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0)) { 36546581Sken /* 36646581Sken * If the user provided a sync rate but no offset, 36746581Sken * use the current offset. 36846581Sken */ 36939217Sgibbs if ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) == 0) 37046581Sken cts->sync_offset = tconf->offset; 37139217Sgibbs 37246581Sken /* 37346581Sken * If the user provided an offset but no sync rate, 37446581Sken * use the current sync rate. 37546581Sken */ 37646581Sken if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) == 0) 37746581Sken cts->sync_period = tconf->period; 37846581Sken 37939217Sgibbs adv_period_offset_to_sdtr(adv, &cts->sync_period, 38039217Sgibbs &cts->sync_offset, 38139217Sgibbs cts->ccb_h.target_id); 38239217Sgibbs 38339217Sgibbs adv_set_syncrate(adv, /*struct cam_path */NULL, 38439217Sgibbs cts->ccb_h.target_id, cts->sync_period, 38539217Sgibbs cts->sync_offset, update_type); 38639217Sgibbs } 38746581Sken 38839217Sgibbs splx(s); 38939217Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 39039217Sgibbs xpt_done(ccb); 39139217Sgibbs break; 39239217Sgibbs } 39339217Sgibbs case XPT_GET_TRAN_SETTINGS: 39439217Sgibbs /* Get default/user set transfer settings for the target */ 39539217Sgibbs { 39639217Sgibbs struct ccb_trans_settings *cts; 39739217Sgibbs struct adv_transinfo *tconf; 39839217Sgibbs target_bit_vector target_mask; 39939217Sgibbs int s; 40039217Sgibbs 40139217Sgibbs cts = &ccb->cts; 40239217Sgibbs target_mask = ADV_TID_TO_TARGET_MASK(cts->ccb_h.target_id); 40339217Sgibbs 40439217Sgibbs cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB); 40539217Sgibbs 40639217Sgibbs s = splcam(); 40739217Sgibbs if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) { 40839217Sgibbs tconf = &adv->tinfo[cts->ccb_h.target_id].current; 40939217Sgibbs if ((adv->disc_enable & target_mask) != 0) 41039217Sgibbs cts->flags |= CCB_TRANS_DISC_ENB; 41139217Sgibbs if ((adv->cmd_qng_enabled & target_mask) != 0) 41239217Sgibbs cts->flags |= CCB_TRANS_TAG_ENB; 41339217Sgibbs } else { 41439217Sgibbs tconf = &adv->tinfo[cts->ccb_h.target_id].user; 41539217Sgibbs if ((adv->user_disc_enable & target_mask) != 0) 41639217Sgibbs cts->flags |= CCB_TRANS_DISC_ENB; 41739217Sgibbs if ((adv->user_cmd_qng_enabled & target_mask) != 0) 41839217Sgibbs cts->flags |= CCB_TRANS_TAG_ENB; 41939217Sgibbs } 42039217Sgibbs 42139217Sgibbs cts->sync_period = tconf->period; 42239217Sgibbs cts->sync_offset = tconf->offset; 42339217Sgibbs splx(s); 42439217Sgibbs 42539217Sgibbs cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 42639217Sgibbs cts->valid = CCB_TRANS_SYNC_RATE_VALID 42739217Sgibbs | CCB_TRANS_SYNC_OFFSET_VALID 42839217Sgibbs | CCB_TRANS_BUS_WIDTH_VALID 42939217Sgibbs | CCB_TRANS_DISC_VALID 43039217Sgibbs | CCB_TRANS_TQ_VALID; 43139217Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 43239217Sgibbs xpt_done(ccb); 43339217Sgibbs break; 43439217Sgibbs } 43539217Sgibbs case XPT_CALC_GEOMETRY: 43639217Sgibbs { 43739217Sgibbs struct ccb_calc_geometry *ccg; 43839217Sgibbs u_int32_t size_mb; 43939217Sgibbs u_int32_t secs_per_cylinder; 44039217Sgibbs int extended; 44139217Sgibbs 44239217Sgibbs ccg = &ccb->ccg; 44339217Sgibbs size_mb = ccg->volume_size 44439217Sgibbs / ((1024L * 1024L) / ccg->block_size); 44539217Sgibbs extended = (adv->control & ADV_CNTL_BIOS_GT_1GB) != 0; 44639217Sgibbs 44739217Sgibbs if (size_mb > 1024 && extended) { 44839217Sgibbs ccg->heads = 255; 44939217Sgibbs ccg->secs_per_track = 63; 45039217Sgibbs } else { 45139217Sgibbs ccg->heads = 64; 45239217Sgibbs ccg->secs_per_track = 32; 45339217Sgibbs } 45439217Sgibbs secs_per_cylinder = ccg->heads * ccg->secs_per_track; 45539217Sgibbs ccg->cylinders = ccg->volume_size / secs_per_cylinder; 45639217Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 45739217Sgibbs xpt_done(ccb); 45839217Sgibbs break; 45939217Sgibbs } 46039217Sgibbs case XPT_RESET_BUS: /* Reset the specified SCSI bus */ 46139217Sgibbs { 46239217Sgibbs int s; 46339217Sgibbs 46439217Sgibbs s = splcam(); 46539217Sgibbs adv_stop_execution(adv); 46655945Sgibbs adv_reset_bus(adv, /*initiate_reset*/TRUE); 46739217Sgibbs adv_start_execution(adv); 46839217Sgibbs splx(s); 46939217Sgibbs 47039217Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 47139217Sgibbs xpt_done(ccb); 47239217Sgibbs break; 47339217Sgibbs } 47439217Sgibbs case XPT_TERM_IO: /* Terminate the I/O process */ 47539217Sgibbs /* XXX Implement */ 47639217Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 47739217Sgibbs xpt_done(ccb); 47839217Sgibbs break; 47939217Sgibbs case XPT_PATH_INQ: /* Path routing inquiry */ 48039217Sgibbs { 48139217Sgibbs struct ccb_pathinq *cpi = &ccb->cpi; 48239217Sgibbs 48339217Sgibbs cpi->version_num = 1; /* XXX??? */ 48439217Sgibbs cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE; 48539217Sgibbs cpi->target_sprt = 0; 48639217Sgibbs cpi->hba_misc = 0; 48739217Sgibbs cpi->hba_eng_cnt = 0; 48839217Sgibbs cpi->max_target = 7; 48939217Sgibbs cpi->max_lun = 7; 49039217Sgibbs cpi->initiator_id = adv->scsi_id; 49139217Sgibbs cpi->bus_id = cam_sim_bus(sim); 49246581Sken cpi->base_transfer_speed = 3300; 49339217Sgibbs strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 49439217Sgibbs strncpy(cpi->hba_vid, "Advansys", HBA_IDLEN); 49539217Sgibbs strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 49639217Sgibbs cpi->unit_number = cam_sim_unit(sim); 49739217Sgibbs cpi->ccb_h.status = CAM_REQ_CMP; 49839217Sgibbs xpt_done(ccb); 49939217Sgibbs break; 50039217Sgibbs } 50139217Sgibbs default: 50239217Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 50339217Sgibbs xpt_done(ccb); 50439217Sgibbs break; 50539217Sgibbs } 50639217Sgibbs} 50739217Sgibbs 50839217Sgibbs/* 50939217Sgibbs * Currently, the output of bus_dmammap_load suits our needs just 51039217Sgibbs * fine, but should it change, we'd need to do something here. 51139217Sgibbs */ 51239217Sgibbs#define adv_fixup_dmasegs(adv, dm_segs) (struct adv_sg_entry *)(dm_segs) 51339217Sgibbs 51439217Sgibbsstatic void 51539217Sgibbsadv_execute_ccb(void *arg, bus_dma_segment_t *dm_segs, 51639217Sgibbs int nsegments, int error) 51739217Sgibbs{ 51839217Sgibbs struct ccb_scsiio *csio; 51939217Sgibbs struct ccb_hdr *ccb_h; 52039217Sgibbs struct cam_sim *sim; 52139217Sgibbs struct adv_softc *adv; 52239217Sgibbs struct adv_ccb_info *cinfo; 52339217Sgibbs struct adv_scsi_q scsiq; 52439217Sgibbs struct adv_sg_head sghead; 52539217Sgibbs int s; 52639217Sgibbs 52739217Sgibbs csio = (struct ccb_scsiio *)arg; 52839217Sgibbs ccb_h = &csio->ccb_h; 52939217Sgibbs sim = xpt_path_sim(ccb_h->path); 53039217Sgibbs adv = (struct adv_softc *)cam_sim_softc(sim); 53139217Sgibbs cinfo = (struct adv_ccb_info *)csio->ccb_h.ccb_cinfo_ptr; 53239217Sgibbs 53355945Sgibbs /* 53455945Sgibbs * Setup our done routine to release the simq on 53555945Sgibbs * the next ccb that completes. 53655945Sgibbs */ 53755945Sgibbs if ((adv->state & ADV_BUSDMA_BLOCK) != 0) 53855945Sgibbs adv->state |= ADV_BUSDMA_BLOCK_CLEARED; 53955945Sgibbs 54039217Sgibbs if ((ccb_h->flags & CAM_CDB_POINTER) != 0) { 54139217Sgibbs if ((ccb_h->flags & CAM_CDB_PHYS) == 0) { 54239217Sgibbs /* XXX Need phystovirt!!!! */ 54339217Sgibbs /* How about pmap_kenter??? */ 54439217Sgibbs scsiq.cdbptr = csio->cdb_io.cdb_ptr; 54539217Sgibbs } else { 54639217Sgibbs scsiq.cdbptr = csio->cdb_io.cdb_ptr; 54739217Sgibbs } 54839217Sgibbs } else { 54939217Sgibbs scsiq.cdbptr = csio->cdb_io.cdb_bytes; 55039217Sgibbs } 55139217Sgibbs /* 55239217Sgibbs * Build up the request 55339217Sgibbs */ 55439217Sgibbs scsiq.q1.status = 0; 55539217Sgibbs scsiq.q1.q_no = 0; 55639217Sgibbs scsiq.q1.cntl = 0; 55739217Sgibbs scsiq.q1.sg_queue_cnt = 0; 55839217Sgibbs scsiq.q1.target_id = ADV_TID_TO_TARGET_MASK(ccb_h->target_id); 55939217Sgibbs scsiq.q1.target_lun = ccb_h->target_lun; 56039217Sgibbs scsiq.q1.sense_len = csio->sense_len; 56139217Sgibbs scsiq.q1.extra_bytes = 0; 56255945Sgibbs scsiq.q2.ccb_index = cinfo - adv->ccb_infos; 56339217Sgibbs scsiq.q2.target_ix = ADV_TIDLUN_TO_IX(ccb_h->target_id, 56439217Sgibbs ccb_h->target_lun); 56539217Sgibbs scsiq.q2.flag = 0; 56639217Sgibbs scsiq.q2.cdb_len = csio->cdb_len; 56739217Sgibbs if ((ccb_h->flags & CAM_TAG_ACTION_VALID) != 0) 56839217Sgibbs scsiq.q2.tag_code = csio->tag_action; 56939217Sgibbs else 57039217Sgibbs scsiq.q2.tag_code = 0; 57139217Sgibbs scsiq.q2.vm_id = 0; 57239217Sgibbs 57339217Sgibbs if (nsegments != 0) { 57439217Sgibbs bus_dmasync_op_t op; 57539217Sgibbs 57639217Sgibbs scsiq.q1.data_addr = dm_segs->ds_addr; 57739217Sgibbs scsiq.q1.data_cnt = dm_segs->ds_len; 57839217Sgibbs if (nsegments > 1) { 57939217Sgibbs scsiq.q1.cntl |= QC_SG_HEAD; 58039217Sgibbs sghead.entry_cnt 58139217Sgibbs = sghead.entry_to_copy 58239217Sgibbs = nsegments; 58339217Sgibbs sghead.res = 0; 58439217Sgibbs sghead.sg_list = adv_fixup_dmasegs(adv, dm_segs); 58539217Sgibbs scsiq.sg_head = &sghead; 58639217Sgibbs } else { 58739217Sgibbs scsiq.sg_head = NULL; 58839217Sgibbs } 58939217Sgibbs if ((ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_IN) 59039217Sgibbs op = BUS_DMASYNC_PREREAD; 59139217Sgibbs else 59239217Sgibbs op = BUS_DMASYNC_PREWRITE; 59339217Sgibbs bus_dmamap_sync(adv->buffer_dmat, cinfo->dmamap, op); 59439217Sgibbs } else { 59539217Sgibbs scsiq.q1.data_addr = 0; 59639217Sgibbs scsiq.q1.data_cnt = 0; 59739217Sgibbs scsiq.sg_head = NULL; 59839217Sgibbs } 59939217Sgibbs 60040027Sgibbs s = splcam(); 60140027Sgibbs 60240027Sgibbs /* 60340027Sgibbs * Last time we need to check if this SCB needs to 60440027Sgibbs * be aborted. 60540027Sgibbs */ 60640027Sgibbs if (ccb_h->status != CAM_REQ_INPROG) { 60755945Sgibbs if (nsegments != 0) 60840027Sgibbs bus_dmamap_unload(adv->buffer_dmat, cinfo->dmamap); 60955945Sgibbs adv_clear_state(adv, (union ccb *)csio); 61040027Sgibbs adv_free_ccb_info(adv, cinfo); 61140027Sgibbs xpt_done((union ccb *)csio); 61240027Sgibbs splx(s); 61340027Sgibbs return; 61440027Sgibbs } 61540027Sgibbs 61639217Sgibbs if (adv_execute_scsi_queue(adv, &scsiq, csio->dxfer_len) != 0) { 61739217Sgibbs /* Temporary resource shortage */ 61855945Sgibbs adv_set_state(adv, ADV_RESOURCE_SHORTAGE); 61955945Sgibbs if (nsegments != 0) 62039217Sgibbs bus_dmamap_unload(adv->buffer_dmat, cinfo->dmamap); 62155945Sgibbs csio->ccb_h.status = CAM_REQUEUE_REQ; 62255945Sgibbs adv_clear_state(adv, (union ccb *)csio); 62339217Sgibbs adv_free_ccb_info(adv, cinfo); 62439217Sgibbs xpt_done((union ccb *)csio); 62539217Sgibbs splx(s); 62639217Sgibbs return; 62739217Sgibbs } 62840027Sgibbs cinfo->state |= ACCB_ACTIVE; 62939217Sgibbs ccb_h->status |= CAM_SIM_QUEUED; 63039217Sgibbs LIST_INSERT_HEAD(&adv->pending_ccbs, ccb_h, sim_links.le); 63139217Sgibbs /* Schedule our timeout */ 63239217Sgibbs ccb_h->timeout_ch = 63339217Sgibbs timeout(adv_timeout, csio, (ccb_h->timeout * hz)/1000); 63439217Sgibbs splx(s); 63539217Sgibbs} 63639217Sgibbs 63739217Sgibbsstatic struct adv_ccb_info * 63839217Sgibbsadv_alloc_ccb_info(struct adv_softc *adv) 63939217Sgibbs{ 64039217Sgibbs int error; 64139217Sgibbs struct adv_ccb_info *cinfo; 64239217Sgibbs 64355945Sgibbs cinfo = &adv->ccb_infos[adv->ccb_infos_allocated]; 64439217Sgibbs cinfo->state = ACCB_FREE; 64539217Sgibbs error = bus_dmamap_create(adv->buffer_dmat, /*flags*/0, 64639217Sgibbs &cinfo->dmamap); 64739217Sgibbs if (error != 0) { 64839217Sgibbs printf("%s: Unable to allocate CCB info " 64939217Sgibbs "dmamap - error %d\n", adv_name(adv), error); 65055945Sgibbs return (NULL); 65139217Sgibbs } 65255945Sgibbs adv->ccb_infos_allocated++; 65339217Sgibbs return (cinfo); 65439217Sgibbs} 65539217Sgibbs 65639217Sgibbsstatic void 65739217Sgibbsadv_destroy_ccb_info(struct adv_softc *adv, struct adv_ccb_info *cinfo) 65839217Sgibbs{ 65939217Sgibbs bus_dmamap_destroy(adv->buffer_dmat, cinfo->dmamap); 66039217Sgibbs} 66139217Sgibbs 66239217Sgibbsvoid 66339217Sgibbsadv_timeout(void *arg) 66439217Sgibbs{ 66539217Sgibbs int s; 66639217Sgibbs union ccb *ccb; 66739217Sgibbs struct adv_softc *adv; 66839217Sgibbs struct adv_ccb_info *cinfo; 66939217Sgibbs 67039217Sgibbs ccb = (union ccb *)arg; 67139217Sgibbs adv = (struct adv_softc *)xpt_path_sim(ccb->ccb_h.path)->softc; 67239217Sgibbs cinfo = (struct adv_ccb_info *)ccb->ccb_h.ccb_cinfo_ptr; 67339217Sgibbs 67439217Sgibbs xpt_print_path(ccb->ccb_h.path); 67539217Sgibbs printf("Timed out\n"); 67639217Sgibbs 67739217Sgibbs s = splcam(); 67839217Sgibbs /* Have we been taken care of already?? */ 67939217Sgibbs if (cinfo == NULL || cinfo->state == ACCB_FREE) { 68039217Sgibbs splx(s); 68139217Sgibbs return; 68239217Sgibbs } 68339217Sgibbs 68439217Sgibbs adv_stop_execution(adv); 68539217Sgibbs 68639217Sgibbs if ((cinfo->state & ACCB_ABORT_QUEUED) == 0) { 68739217Sgibbs struct ccb_hdr *ccb_h; 68839217Sgibbs 68939217Sgibbs /* 69039217Sgibbs * In order to simplify the recovery process, we ask the XPT 69139217Sgibbs * layer to halt the queue of new transactions and we traverse 69239217Sgibbs * the list of pending CCBs and remove their timeouts. This 69339217Sgibbs * means that the driver attempts to clear only one error 69439217Sgibbs * condition at a time. In general, timeouts that occur 69539217Sgibbs * close together are related anyway, so there is no benefit 69639217Sgibbs * in attempting to handle errors in parrallel. Timeouts will 69739217Sgibbs * be reinstated when the recovery process ends. 69839217Sgibbs */ 69955945Sgibbs adv_set_state(adv, ADV_IN_TIMEOUT); 70039217Sgibbs 70139217Sgibbs /* This CCB is the CCB representing our recovery actions */ 70239217Sgibbs cinfo->state |= ACCB_RECOVERY_CCB|ACCB_ABORT_QUEUED; 70339217Sgibbs 70439217Sgibbs ccb_h = LIST_FIRST(&adv->pending_ccbs); 70539217Sgibbs while (ccb_h != NULL) { 70639217Sgibbs untimeout(adv_timeout, ccb_h, ccb_h->timeout_ch); 70739217Sgibbs ccb_h = LIST_NEXT(ccb_h, sim_links.le); 70839217Sgibbs } 70939217Sgibbs 71039217Sgibbs /* XXX Should send a BDR */ 71139217Sgibbs /* Attempt an abort as our first tact */ 71239217Sgibbs xpt_print_path(ccb->ccb_h.path); 71339217Sgibbs printf("Attempting abort\n"); 71439217Sgibbs adv_abort_ccb(adv, ccb->ccb_h.target_id, 71539217Sgibbs ccb->ccb_h.target_lun, ccb, 71639217Sgibbs CAM_CMD_TIMEOUT, /*queued_only*/FALSE); 71739217Sgibbs ccb->ccb_h.timeout_ch = 71839217Sgibbs timeout(adv_timeout, ccb, 2 * hz); 71939217Sgibbs } else { 72039217Sgibbs /* Our attempt to perform an abort failed, go for a reset */ 72139217Sgibbs xpt_print_path(ccb->ccb_h.path); 72239217Sgibbs printf("Resetting bus\n"); 72339217Sgibbs ccb->ccb_h.status &= ~CAM_STATUS_MASK; 72439217Sgibbs ccb->ccb_h.status |= CAM_CMD_TIMEOUT; 72555945Sgibbs adv_reset_bus(adv, /*initiate_reset*/TRUE); 72639217Sgibbs } 72739217Sgibbs adv_start_execution(adv); 72839217Sgibbs splx(s); 72939217Sgibbs} 73039217Sgibbs 73139217Sgibbsstruct adv_softc * 73239217Sgibbsadv_alloc(int unit, bus_space_tag_t tag, bus_space_handle_t bsh) 73339217Sgibbs{ 73439217Sgibbs struct adv_softc *adv; 73539217Sgibbs 73639217Sgibbs if (unit >= NADV) { 73739217Sgibbs printf("adv: unit number (%d) too high\n", unit); 73839217Sgibbs return NULL; 73939217Sgibbs } 74039217Sgibbs 74139217Sgibbs /* 74239217Sgibbs * Allocate a storage area for us 74339217Sgibbs */ 74439217Sgibbs if (advsoftcs[unit]) { 74539217Sgibbs printf("adv%d: memory already allocated\n", unit); 74639217Sgibbs return NULL; 74739217Sgibbs } 74839217Sgibbs 74939217Sgibbs adv = malloc(sizeof(struct adv_softc), M_DEVBUF, M_NOWAIT); 75039217Sgibbs if (!adv) { 75139217Sgibbs printf("adv%d: cannot malloc!\n", unit); 75239217Sgibbs return NULL; 75339217Sgibbs } 75439217Sgibbs bzero(adv, sizeof(struct adv_softc)); 75539217Sgibbs LIST_INIT(&adv->pending_ccbs); 75639217Sgibbs SLIST_INIT(&adv->free_ccb_infos); 75739217Sgibbs advsoftcs[unit] = adv; 75839217Sgibbs adv->unit = unit; 75939217Sgibbs adv->tag = tag; 76039217Sgibbs adv->bsh = bsh; 76139217Sgibbs 76239217Sgibbs return(adv); 76339217Sgibbs} 76439217Sgibbs 76539217Sgibbsvoid 76639217Sgibbsadv_free(struct adv_softc *adv) 76739217Sgibbs{ 76839217Sgibbs switch (adv->init_level) { 76955945Sgibbs case 6: 77039217Sgibbs { 77139217Sgibbs struct adv_ccb_info *cinfo; 77239217Sgibbs 77339217Sgibbs while ((cinfo = SLIST_FIRST(&adv->free_ccb_infos)) != NULL) { 77439217Sgibbs SLIST_REMOVE_HEAD(&adv->free_ccb_infos, links); 77540420Sgibbs adv_destroy_ccb_info(adv, cinfo); 77639217Sgibbs } 77739217Sgibbs 77839217Sgibbs bus_dmamap_unload(adv->sense_dmat, adv->sense_dmamap); 77939217Sgibbs } 78055945Sgibbs case 5: 78139217Sgibbs bus_dmamem_free(adv->sense_dmat, adv->sense_buffers, 78239217Sgibbs adv->sense_dmamap); 78355945Sgibbs case 4: 78455945Sgibbs bus_dma_tag_destroy(adv->sense_dmat); 78539217Sgibbs case 3: 78655945Sgibbs bus_dma_tag_destroy(adv->buffer_dmat); 78739217Sgibbs case 2: 78855945Sgibbs bus_dma_tag_destroy(adv->parent_dmat); 78939217Sgibbs case 1: 79055945Sgibbs free(adv->ccb_infos, M_DEVBUF); 79139217Sgibbs case 0: 79239217Sgibbs break; 79339217Sgibbs } 79439217Sgibbs free(adv, M_DEVBUF); 79539217Sgibbs} 79639217Sgibbs 79739217Sgibbsint 79839217Sgibbsadv_init(struct adv_softc *adv) 79939217Sgibbs{ 80039217Sgibbs struct adv_eeprom_config eeprom_config; 80139217Sgibbs int checksum, i; 80255945Sgibbs int max_sync; 80339217Sgibbs u_int16_t config_lsw; 80439217Sgibbs u_int16_t config_msw; 80539217Sgibbs 80639217Sgibbs adv_lib_init(adv); 80739217Sgibbs 80855945Sgibbs /* 80955945Sgibbs * Stop script execution. 81055945Sgibbs */ 81155945Sgibbs adv_write_lram_16(adv, ADV_HALTCODE_W, 0x00FE); 81255945Sgibbs adv_stop_execution(adv); 81355945Sgibbs if (adv_stop_chip(adv) == 0 || adv_is_chip_halted(adv) == 0) { 81439217Sgibbs printf("adv%d: Unable to halt adapter. Initialization" 81539217Sgibbs "failed\n", adv->unit); 81639217Sgibbs return (1); 81739217Sgibbs } 81839217Sgibbs ADV_OUTW(adv, ADV_REG_PROG_COUNTER, ADV_MCODE_START_ADDR); 81939217Sgibbs if (ADV_INW(adv, ADV_REG_PROG_COUNTER) != ADV_MCODE_START_ADDR) { 82039217Sgibbs printf("adv%d: Unable to set program counter. Initialization" 82139217Sgibbs "failed\n", adv->unit); 82239217Sgibbs return (1); 82339217Sgibbs } 82439217Sgibbs 82539217Sgibbs config_msw = ADV_INW(adv, ADV_CONFIG_MSW); 82639217Sgibbs config_lsw = ADV_INW(adv, ADV_CONFIG_LSW); 82739217Sgibbs 82839217Sgibbs if ((config_msw & ADV_CFG_MSW_CLR_MASK) != 0) { 82955945Sgibbs config_msw &= ~ADV_CFG_MSW_CLR_MASK; 83039217Sgibbs /* 83139217Sgibbs * XXX The Linux code flags this as an error, 83239217Sgibbs * but what should we report to the user??? 83339217Sgibbs * It seems that clearing the config register 83439217Sgibbs * makes this error recoverable. 83539217Sgibbs */ 83639217Sgibbs ADV_OUTW(adv, ADV_CONFIG_MSW, config_msw); 83739217Sgibbs } 83839217Sgibbs 83939217Sgibbs /* Suck in the configuration from the EEProm */ 84039217Sgibbs checksum = adv_get_eeprom_config(adv, &eeprom_config); 84139217Sgibbs 84239217Sgibbs if (ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_AUTO_CONFIG) { 84339217Sgibbs /* 84439217Sgibbs * XXX The Linux code sets a warning level for this 84539217Sgibbs * condition, yet nothing of meaning is printed to 84639217Sgibbs * the user. What does this mean??? 84739217Sgibbs */ 84839217Sgibbs if (adv->chip_version == 3) { 84955945Sgibbs if (eeprom_config.cfg_lsw != config_lsw) 85055945Sgibbs eeprom_config.cfg_lsw = config_lsw; 85139217Sgibbs if (eeprom_config.cfg_msw != config_msw) { 85255945Sgibbs eeprom_config.cfg_msw = config_msw; 85339217Sgibbs } 85439217Sgibbs } 85539217Sgibbs } 85639217Sgibbs if (checksum == eeprom_config.chksum) { 85755945Sgibbs 85839217Sgibbs /* Range/Sanity checking */ 85939217Sgibbs if (eeprom_config.max_total_qng < ADV_MIN_TOTAL_QNG) { 86039217Sgibbs eeprom_config.max_total_qng = ADV_MIN_TOTAL_QNG; 86139217Sgibbs } 86239217Sgibbs if (eeprom_config.max_total_qng > ADV_MAX_TOTAL_QNG) { 86339217Sgibbs eeprom_config.max_total_qng = ADV_MAX_TOTAL_QNG; 86439217Sgibbs } 86539217Sgibbs if (eeprom_config.max_tag_qng > eeprom_config.max_total_qng) { 86639217Sgibbs eeprom_config.max_tag_qng = eeprom_config.max_total_qng; 86739217Sgibbs } 86839217Sgibbs if (eeprom_config.max_tag_qng < ADV_MIN_TAG_Q_PER_DVC) { 86939217Sgibbs eeprom_config.max_tag_qng = ADV_MIN_TAG_Q_PER_DVC; 87039217Sgibbs } 87139217Sgibbs adv->max_openings = eeprom_config.max_total_qng; 87239217Sgibbs adv->user_disc_enable = eeprom_config.disc_enable; 87339217Sgibbs adv->user_cmd_qng_enabled = eeprom_config.use_cmd_qng; 87439217Sgibbs adv->isa_dma_speed = EEPROM_DMA_SPEED(eeprom_config); 87539217Sgibbs adv->scsi_id = EEPROM_SCSIID(eeprom_config) & ADV_MAX_TID; 87639217Sgibbs EEPROM_SET_SCSIID(eeprom_config, adv->scsi_id); 87739217Sgibbs adv->control = eeprom_config.cntl; 87855945Sgibbs for (i = 0; i <= ADV_MAX_TID; i++) { 87955945Sgibbs u_int8_t sync_data; 88055945Sgibbs 88155945Sgibbs if ((eeprom_config.init_sdtr & (0x1 << i)) == 0) 88255945Sgibbs sync_data = 0; 88355945Sgibbs else 88455945Sgibbs sync_data = eeprom_config.sdtr_data[i]; 88539217Sgibbs adv_sdtr_to_period_offset(adv, 88655945Sgibbs sync_data, 88739217Sgibbs &adv->tinfo[i].user.period, 88839217Sgibbs &adv->tinfo[i].user.offset, 88939217Sgibbs i); 89055945Sgibbs } 89155945Sgibbs config_lsw = eeprom_config.cfg_lsw; 89255945Sgibbs eeprom_config.cfg_msw = config_msw; 89339217Sgibbs } else { 89439217Sgibbs u_int8_t sync_data; 89539217Sgibbs 89639217Sgibbs printf("adv%d: Warning EEPROM Checksum mismatch. " 89739217Sgibbs "Using default device parameters\n", adv->unit); 89839217Sgibbs 89939217Sgibbs /* Set reasonable defaults since we can't read the EEPROM */ 90039217Sgibbs adv->isa_dma_speed = /*ADV_DEF_ISA_DMA_SPEED*/1; 90139217Sgibbs adv->max_openings = ADV_DEF_MAX_TOTAL_QNG; 90239217Sgibbs adv->disc_enable = TARGET_BIT_VECTOR_SET; 90339217Sgibbs adv->user_disc_enable = TARGET_BIT_VECTOR_SET; 90439217Sgibbs adv->cmd_qng_enabled = TARGET_BIT_VECTOR_SET; 90539217Sgibbs adv->user_cmd_qng_enabled = TARGET_BIT_VECTOR_SET; 90639217Sgibbs adv->scsi_id = 7; 90755945Sgibbs adv->control = 0xFFFF; 90839217Sgibbs 90955945Sgibbs if (adv->chip_version == ADV_CHIP_VER_PCI_ULTRA_3050) 91055945Sgibbs /* Default to no Ultra to support the 3030 */ 91155945Sgibbs adv->control &= ~ADV_CNTL_SDTR_ENABLE_ULTRA; 91239217Sgibbs sync_data = ADV_DEF_SDTR_OFFSET | (ADV_DEF_SDTR_INDEX << 4); 91355945Sgibbs for (i = 0; i <= ADV_MAX_TID; i++) { 91439217Sgibbs adv_sdtr_to_period_offset(adv, sync_data, 91539217Sgibbs &adv->tinfo[i].user.period, 91639217Sgibbs &adv->tinfo[i].user.offset, 91739217Sgibbs i); 91855945Sgibbs } 91955945Sgibbs config_lsw |= ADV_CFG_LSW_SCSI_PARITY_ON; 92039217Sgibbs } 92155945Sgibbs config_msw &= ~ADV_CFG_MSW_CLR_MASK; 92255945Sgibbs config_lsw |= ADV_CFG_LSW_HOST_INT_ON; 92355945Sgibbs if ((adv->type & (ADV_PCI|ADV_ULTRA)) == (ADV_PCI|ADV_ULTRA) 92455945Sgibbs && (adv->control & ADV_CNTL_SDTR_ENABLE_ULTRA) == 0) 92555945Sgibbs /* 25ns or 10MHz */ 92655945Sgibbs max_sync = 25; 92755945Sgibbs else 92855945Sgibbs /* Unlimited */ 92955945Sgibbs max_sync = 0; 93055945Sgibbs for (i = 0; i <= ADV_MAX_TID; i++) { 93155945Sgibbs if (adv->tinfo[i].user.period < max_sync) 93255945Sgibbs adv->tinfo[i].user.period = max_sync; 93355945Sgibbs } 93439217Sgibbs 93555945Sgibbs if (adv_test_external_lram(adv) == 0) { 93655945Sgibbs printf("No external RAM\n"); 93755945Sgibbs if ((adv->type & (ADV_PCI|ADV_ULTRA)) == (ADV_PCI|ADV_ULTRA)) { 93855945Sgibbs eeprom_config.max_total_qng = 93955945Sgibbs ADV_MAX_PCI_ULTRA_INRAM_TOTAL_QNG; 94055945Sgibbs eeprom_config.max_tag_qng = 94155945Sgibbs ADV_MAX_PCI_ULTRA_INRAM_TAG_QNG; 94255945Sgibbs } else { 94355945Sgibbs eeprom_config.cfg_msw |= 0x0800; 94455945Sgibbs config_msw |= 0x0800; 94555945Sgibbs eeprom_config.max_total_qng = 94655945Sgibbs ADV_MAX_PCI_INRAM_TOTAL_QNG; 94755945Sgibbs eeprom_config.max_tag_qng = ADV_MAX_INRAM_TAG_QNG; 94855945Sgibbs } 94955945Sgibbs adv->max_openings = eeprom_config.max_total_qng; 95055945Sgibbs } 95155945Sgibbs ADV_OUTW(adv, ADV_CONFIG_MSW, config_msw); 95255945Sgibbs ADV_OUTW(adv, ADV_CONFIG_LSW, config_lsw); 95355945Sgibbs#if 0 95455945Sgibbs /* 95555945Sgibbs * Don't write the eeprom data back for now. 95655945Sgibbs * I'd rather not mess up the user's card. We also don't 95755945Sgibbs * fully sanitize the eeprom settings above for the write-back 95855945Sgibbs * to be 100% correct. 95955945Sgibbs */ 96039217Sgibbs if (adv_set_eeprom_config(adv, &eeprom_config) != 0) 96139217Sgibbs printf("%s: WARNING! Failure writing to EEPROM.\n", 96239217Sgibbs adv_name(adv)); 96355945Sgibbs#endif 96439217Sgibbs 96539217Sgibbs adv_set_chip_scsiid(adv, adv->scsi_id); 96639217Sgibbs if (adv_init_lram_and_mcode(adv)) 96739217Sgibbs return (1); 96839217Sgibbs 96939217Sgibbs adv->disc_enable = adv->user_disc_enable; 97039217Sgibbs 97139217Sgibbs adv_write_lram_8(adv, ADVV_DISC_ENABLE_B, adv->disc_enable); 97239217Sgibbs for (i = 0; i <= ADV_MAX_TID; i++) { 97339217Sgibbs /* 97439217Sgibbs * Start off in async mode. 97539217Sgibbs */ 97639217Sgibbs adv_set_syncrate(adv, /*struct cam_path */NULL, 97739217Sgibbs i, /*period*/0, /*offset*/0, 97839217Sgibbs ADV_TRANS_CUR); 97939217Sgibbs /* 98039217Sgibbs * Enable the use of tagged commands on all targets. 98139217Sgibbs * This allows the kernel driver to make up it's own mind 98239217Sgibbs * as it sees fit to tag queue instead of having the 98339217Sgibbs * firmware try and second guess the tag_code settins. 98439217Sgibbs */ 98539217Sgibbs adv_write_lram_8(adv, ADVV_MAX_DVC_QNG_BEG + i, 98639217Sgibbs adv->max_openings); 98739217Sgibbs } 98839217Sgibbs adv_write_lram_8(adv, ADVV_USE_TAGGED_QNG_B, TARGET_BIT_VECTOR_SET); 98939217Sgibbs adv_write_lram_8(adv, ADVV_CAN_TAGGED_QNG_B, TARGET_BIT_VECTOR_SET); 99039217Sgibbs printf("adv%d: AdvanSys %s Host Adapter, SCSI ID %d, queue depth %d\n", 99155945Sgibbs adv->unit, (adv->type & ADV_ULTRA) && (max_sync == 0) 99255945Sgibbs ? "Ultra SCSI" : "SCSI", 99339217Sgibbs adv->scsi_id, adv->max_openings); 99439217Sgibbs return (0); 99539217Sgibbs} 99639217Sgibbs 99739217Sgibbsvoid 99839217Sgibbsadv_intr(void *arg) 99939217Sgibbs{ 100039217Sgibbs struct adv_softc *adv; 100139217Sgibbs u_int16_t chipstat; 100239217Sgibbs u_int16_t saved_ram_addr; 100339217Sgibbs u_int8_t ctrl_reg; 100439217Sgibbs u_int8_t saved_ctrl_reg; 100539217Sgibbs u_int8_t host_flag; 100639217Sgibbs 100739217Sgibbs adv = (struct adv_softc *)arg; 100839217Sgibbs 100955945Sgibbs chipstat = ADV_INW(adv, ADV_CHIP_STATUS); 101055945Sgibbs 101155945Sgibbs /* Is it for us? */ 101255945Sgibbs if ((chipstat & (ADV_CSW_INT_PENDING|ADV_CSW_SCSI_RESET_LATCH)) == 0) 101355945Sgibbs return; 101455945Sgibbs 101539217Sgibbs ctrl_reg = ADV_INB(adv, ADV_CHIP_CTRL); 101639217Sgibbs saved_ctrl_reg = ctrl_reg & (~(ADV_CC_SCSI_RESET | ADV_CC_CHIP_RESET | 101739217Sgibbs ADV_CC_SINGLE_STEP | ADV_CC_DIAG | 101839217Sgibbs ADV_CC_TEST)); 101939217Sgibbs 102055945Sgibbs if ((chipstat & (ADV_CSW_SCSI_RESET_LATCH|ADV_CSW_SCSI_RESET_ACTIVE))) { 102155945Sgibbs printf("Detected Bus Reset\n"); 102255945Sgibbs adv_reset_bus(adv, /*initiate_reset*/FALSE); 102355945Sgibbs return; 102455945Sgibbs } 102539217Sgibbs 102655945Sgibbs if ((chipstat & ADV_CSW_INT_PENDING) != 0) { 102739217Sgibbs 102839217Sgibbs saved_ram_addr = ADV_INW(adv, ADV_LRAM_ADDR); 102939217Sgibbs host_flag = adv_read_lram_8(adv, ADVV_HOST_FLAG_B); 103039217Sgibbs adv_write_lram_8(adv, ADVV_HOST_FLAG_B, 103139217Sgibbs host_flag | ADV_HOST_FLAG_IN_ISR); 103239217Sgibbs 103339217Sgibbs adv_ack_interrupt(adv); 103439217Sgibbs 103555945Sgibbs if ((chipstat & ADV_CSW_HALTED) != 0 103655945Sgibbs && (ctrl_reg & ADV_CC_SINGLE_STEP) != 0) { 103739217Sgibbs adv_isr_chip_halted(adv); 103839217Sgibbs saved_ctrl_reg &= ~ADV_CC_HALT; 103939217Sgibbs } else { 104039217Sgibbs adv_run_doneq(adv); 104139217Sgibbs } 104239217Sgibbs ADV_OUTW(adv, ADV_LRAM_ADDR, saved_ram_addr); 104339217Sgibbs#ifdef DIAGNOSTIC 104439217Sgibbs if (ADV_INW(adv, ADV_LRAM_ADDR) != saved_ram_addr) 104539217Sgibbs panic("adv_intr: Unable to set LRAM addr"); 104639217Sgibbs#endif 104739217Sgibbs adv_write_lram_8(adv, ADVV_HOST_FLAG_B, host_flag); 104839217Sgibbs } 104939217Sgibbs 105039217Sgibbs ADV_OUTB(adv, ADV_CHIP_CTRL, saved_ctrl_reg); 105139217Sgibbs} 105239217Sgibbs 105339217Sgibbsvoid 105439217Sgibbsadv_run_doneq(struct adv_softc *adv) 105539217Sgibbs{ 105639217Sgibbs struct adv_q_done_info scsiq; 105739217Sgibbs u_int doneq_head; 105839217Sgibbs u_int done_qno; 105939217Sgibbs 106039217Sgibbs doneq_head = adv_read_lram_16(adv, ADVV_DONE_Q_TAIL_W) & 0xFF; 106139217Sgibbs done_qno = adv_read_lram_8(adv, ADV_QNO_TO_QADDR(doneq_head) 106239217Sgibbs + ADV_SCSIQ_B_FWD); 106339217Sgibbs while (done_qno != ADV_QLINK_END) { 106439217Sgibbs union ccb* ccb; 106555945Sgibbs struct adv_ccb_info *cinfo; 106639217Sgibbs u_int done_qaddr; 106739217Sgibbs u_int sg_queue_cnt; 106839217Sgibbs int aborted; 106939217Sgibbs 107039217Sgibbs done_qaddr = ADV_QNO_TO_QADDR(done_qno); 107139217Sgibbs 107239217Sgibbs /* Pull status from this request */ 107339217Sgibbs sg_queue_cnt = adv_copy_lram_doneq(adv, done_qaddr, &scsiq, 107439217Sgibbs adv->max_dma_count); 107539217Sgibbs 107639217Sgibbs /* Mark it as free */ 107739217Sgibbs adv_write_lram_8(adv, done_qaddr + ADV_SCSIQ_B_STATUS, 107839505Sgibbs scsiq.q_status & ~(QS_READY|QS_ABORTED)); 107939217Sgibbs 108039217Sgibbs /* Process request based on retrieved info */ 108139217Sgibbs if ((scsiq.cntl & QC_SG_HEAD) != 0) { 108239217Sgibbs u_int i; 108339217Sgibbs 108439217Sgibbs /* 108539217Sgibbs * S/G based request. Free all of the queue 108639217Sgibbs * structures that contained S/G information. 108739217Sgibbs */ 108839217Sgibbs for (i = 0; i < sg_queue_cnt; i++) { 108939217Sgibbs done_qno = adv_read_lram_8(adv, done_qaddr 109039217Sgibbs + ADV_SCSIQ_B_FWD); 109139217Sgibbs 109239217Sgibbs#ifdef DIAGNOSTIC 109339505Sgibbs if (done_qno == ADV_QLINK_END) { 109439217Sgibbs panic("adv_qdone: Corrupted SG " 109539217Sgibbs "list encountered"); 109639217Sgibbs } 109739217Sgibbs#endif 109839505Sgibbs done_qaddr = ADV_QNO_TO_QADDR(done_qno); 109939505Sgibbs 110039217Sgibbs /* Mark SG queue as free */ 110139217Sgibbs adv_write_lram_8(adv, done_qaddr 110239217Sgibbs + ADV_SCSIQ_B_STATUS, QS_FREE); 110339217Sgibbs } 110439217Sgibbs } else 110539217Sgibbs sg_queue_cnt = 0; 110639217Sgibbs#ifdef DIAGNOSTIC 110739505Sgibbs if (adv->cur_active < (sg_queue_cnt + 1)) 110839217Sgibbs panic("adv_qdone: Attempting to free more " 110939217Sgibbs "queues than are active"); 111039217Sgibbs#endif 111139217Sgibbs adv->cur_active -= sg_queue_cnt + 1; 111239217Sgibbs 111339217Sgibbs aborted = (scsiq.q_status & QS_ABORTED) != 0; 111439217Sgibbs 111539217Sgibbs if ((scsiq.q_status != QS_DONE) 111639217Sgibbs && (scsiq.q_status & QS_ABORTED) == 0) 111739217Sgibbs panic("adv_qdone: completed scsiq with unknown status"); 111839217Sgibbs 111939217Sgibbs scsiq.remain_bytes += scsiq.extra_bytes; 112039217Sgibbs 112139217Sgibbs if ((scsiq.d3.done_stat == QD_WITH_ERROR) && 112239217Sgibbs (scsiq.d3.host_stat == QHSTA_M_DATA_OVER_RUN)) { 112339217Sgibbs if ((scsiq.cntl & (QC_DATA_IN|QC_DATA_OUT)) == 0) { 112439217Sgibbs scsiq.d3.done_stat = QD_NO_ERROR; 112539217Sgibbs scsiq.d3.host_stat = QHSTA_NO_ERROR; 112639217Sgibbs } 112739217Sgibbs } 112839217Sgibbs 112955945Sgibbs cinfo = &adv->ccb_infos[scsiq.d2.ccb_index]; 113055945Sgibbs ccb = cinfo->ccb; 113139217Sgibbs ccb->csio.resid = scsiq.remain_bytes; 113255945Sgibbs adv_done(adv, ccb, 113339217Sgibbs scsiq.d3.done_stat, scsiq.d3.host_stat, 113439217Sgibbs scsiq.d3.scsi_stat, scsiq.q_no); 113539217Sgibbs 113639217Sgibbs doneq_head = done_qno; 113740027Sgibbs done_qno = adv_read_lram_8(adv, done_qaddr + ADV_SCSIQ_B_FWD); 113839217Sgibbs } 113939217Sgibbs adv_write_lram_16(adv, ADVV_DONE_Q_TAIL_W, doneq_head); 114039217Sgibbs} 114139217Sgibbs 114239217Sgibbs 114339217Sgibbsvoid 114439217Sgibbsadv_done(struct adv_softc *adv, union ccb *ccb, u_int done_stat, 114539217Sgibbs u_int host_stat, u_int scsi_status, u_int q_no) 114639217Sgibbs{ 114739217Sgibbs struct adv_ccb_info *cinfo; 114839217Sgibbs 114939217Sgibbs cinfo = (struct adv_ccb_info *)ccb->ccb_h.ccb_cinfo_ptr; 115045443Sgibbs LIST_REMOVE(&ccb->ccb_h, sim_links.le); 115145443Sgibbs untimeout(adv_timeout, ccb, ccb->ccb_h.timeout_ch); 115239217Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 115339217Sgibbs bus_dmasync_op_t op; 115439217Sgibbs 115539217Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 115639217Sgibbs op = BUS_DMASYNC_POSTREAD; 115739217Sgibbs else 115839217Sgibbs op = BUS_DMASYNC_POSTWRITE; 115939217Sgibbs bus_dmamap_sync(adv->buffer_dmat, cinfo->dmamap, op); 116039217Sgibbs bus_dmamap_unload(adv->buffer_dmat, cinfo->dmamap); 116139217Sgibbs } 116239217Sgibbs 116339217Sgibbs switch (done_stat) { 116439217Sgibbs case QD_NO_ERROR: 116545443Sgibbs if (host_stat == QHSTA_NO_ERROR) { 116639217Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 116739217Sgibbs break; 116839217Sgibbs } 116945443Sgibbs xpt_print_path(ccb->ccb_h.path); 117045443Sgibbs printf("adv_done - queue done without error, " 117145443Sgibbs "but host status non-zero(%x)\n", host_stat); 117245443Sgibbs /*FALLTHROUGH*/ 117339217Sgibbs case QD_WITH_ERROR: 117439217Sgibbs switch (host_stat) { 117545443Sgibbs case QHSTA_M_TARGET_STATUS_BUSY: 117645443Sgibbs case QHSTA_M_BAD_QUEUE_FULL_OR_BUSY: 117745443Sgibbs /* 117845443Sgibbs * Assume that if we were a tagged transaction 117945443Sgibbs * the target reported queue full. Otherwise, 118045443Sgibbs * report busy. The firmware really should just 118145443Sgibbs * pass the original status back up to us even 118245443Sgibbs * if it thinks the target was in error for 118345443Sgibbs * returning this status as no other transactions 118445443Sgibbs * from this initiator are in effect, but this 118545443Sgibbs * ignores multi-initiator setups and there is 118645443Sgibbs * evidence that the firmware gets its per-device 118745443Sgibbs * transaction counts screwed up occassionally. 118845443Sgibbs */ 118945443Sgibbs ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR; 119045443Sgibbs if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0 119145443Sgibbs && host_stat != QHSTA_M_TARGET_STATUS_BUSY) 119245443Sgibbs scsi_status = SCSI_STATUS_QUEUE_FULL; 119345443Sgibbs else 119445443Sgibbs scsi_status = SCSI_STATUS_BUSY; 119545443Sgibbs adv_abort_ccb(adv, ccb->ccb_h.target_id, 119645443Sgibbs ccb->ccb_h.target_lun, 119745443Sgibbs /*ccb*/NULL, CAM_REQUEUE_REQ, 119845443Sgibbs /*queued_only*/TRUE); 119945443Sgibbs /*FALLTHROUGH*/ 120045443Sgibbs case QHSTA_M_NO_AUTO_REQ_SENSE: 120139217Sgibbs case QHSTA_NO_ERROR: 120239217Sgibbs ccb->csio.scsi_status = scsi_status; 120339217Sgibbs switch (scsi_status) { 120439217Sgibbs case SCSI_STATUS_CHECK_COND: 120539217Sgibbs case SCSI_STATUS_CMD_TERMINATED: 120639217Sgibbs ccb->ccb_h.status |= CAM_AUTOSNS_VALID; 120739217Sgibbs /* Structure copy */ 120839217Sgibbs ccb->csio.sense_data = 120939217Sgibbs adv->sense_buffers[q_no - 1]; 121039217Sgibbs /* FALLTHROUGH */ 121139217Sgibbs case SCSI_STATUS_BUSY: 121239217Sgibbs case SCSI_STATUS_RESERV_CONFLICT: 121339217Sgibbs case SCSI_STATUS_QUEUE_FULL: 121439217Sgibbs case SCSI_STATUS_COND_MET: 121539217Sgibbs case SCSI_STATUS_INTERMED: 121639217Sgibbs case SCSI_STATUS_INTERMED_COND_MET: 121739217Sgibbs ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR; 121839217Sgibbs break; 121939217Sgibbs case SCSI_STATUS_OK: 122039217Sgibbs ccb->ccb_h.status |= CAM_REQ_CMP; 122139217Sgibbs break; 122239217Sgibbs } 122339217Sgibbs break; 122439217Sgibbs case QHSTA_M_SEL_TIMEOUT: 122539217Sgibbs ccb->ccb_h.status = CAM_SEL_TIMEOUT; 122639217Sgibbs break; 122745443Sgibbs case QHSTA_M_DATA_OVER_RUN: 122845443Sgibbs ccb->ccb_h.status = CAM_DATA_RUN_ERR; 122945443Sgibbs break; 123045443Sgibbs case QHSTA_M_UNEXPECTED_BUS_FREE: 123145443Sgibbs ccb->ccb_h.status = CAM_UNEXP_BUSFREE; 123245443Sgibbs break; 123345443Sgibbs case QHSTA_M_BAD_BUS_PHASE_SEQ: 123445443Sgibbs ccb->ccb_h.status = CAM_SEQUENCE_FAIL; 123545443Sgibbs break; 123645443Sgibbs case QHSTA_M_BAD_CMPL_STATUS_IN: 123745443Sgibbs /* No command complete after a status message */ 123845443Sgibbs ccb->ccb_h.status = CAM_SEQUENCE_FAIL; 123945443Sgibbs break; 124045443Sgibbs case QHSTA_D_EXE_SCSI_Q_BUSY_TIMEOUT: 124145443Sgibbs case QHSTA_M_WTM_TIMEOUT: 124245443Sgibbs case QHSTA_M_HUNG_REQ_SCSI_BUS_RESET: 124345443Sgibbs /* The SCSI bus hung in a phase */ 124445443Sgibbs ccb->ccb_h.status = CAM_SEQUENCE_FAIL; 124555945Sgibbs adv_reset_bus(adv, /*initiate_reset*/TRUE); 124645443Sgibbs break; 124745846Sgibbs case QHSTA_M_AUTO_REQ_SENSE_FAIL: 124845846Sgibbs ccb->ccb_h.status = CAM_AUTOSENSE_FAIL; 124945846Sgibbs break; 125045443Sgibbs case QHSTA_D_QDONE_SG_LIST_CORRUPTED: 125145443Sgibbs case QHSTA_D_ASC_DVC_ERROR_CODE_SET: 125245443Sgibbs case QHSTA_D_HOST_ABORT_FAILED: 125345443Sgibbs case QHSTA_D_EXE_SCSI_Q_FAILED: 125445443Sgibbs case QHSTA_D_ASPI_NO_BUF_POOL: 125545443Sgibbs case QHSTA_M_BAD_TAG_CODE: 125645443Sgibbs case QHSTA_D_LRAM_CMP_ERROR: 125745443Sgibbs case QHSTA_M_MICRO_CODE_ERROR_HALT: 125839217Sgibbs default: 125945443Sgibbs panic("%s: Unhandled Host status error %x", 126045443Sgibbs adv_name(adv), host_stat); 126145443Sgibbs /* NOTREACHED */ 126239217Sgibbs } 126339217Sgibbs break; 126439217Sgibbs 126539217Sgibbs case QD_ABORTED_BY_HOST: 126639217Sgibbs /* Don't clobber any, more explicit, error codes we've set */ 126739217Sgibbs if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) 126839217Sgibbs ccb->ccb_h.status = CAM_REQ_ABORTED; 126939217Sgibbs break; 127039217Sgibbs 127139217Sgibbs default: 127240733Sgibbs xpt_print_path(ccb->ccb_h.path); 127340733Sgibbs printf("adv_done - queue done with unknown status %x:%x\n", 127440733Sgibbs done_stat, host_stat); 127539217Sgibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 127639217Sgibbs break; 127739217Sgibbs } 127855945Sgibbs adv_clear_state(adv, ccb); 127939217Sgibbs if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP 128039217Sgibbs && (ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { 128139217Sgibbs xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 128239217Sgibbs ccb->ccb_h.status |= CAM_DEV_QFRZN; 128339217Sgibbs } 128439217Sgibbs adv_free_ccb_info(adv, cinfo); 128555945Sgibbs /* 128655945Sgibbs * Null this out so that we catch driver bugs that cause a 128755945Sgibbs * ccb to be completed twice. 128855945Sgibbs */ 128955945Sgibbs ccb->ccb_h.ccb_cinfo_ptr = NULL; 129039217Sgibbs ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 129139217Sgibbs xpt_done(ccb); 129239217Sgibbs} 129339217Sgibbs 129439217Sgibbs/* 129539217Sgibbs * Function to poll for command completion when 129639217Sgibbs * interrupts are disabled (crash dumps) 129739217Sgibbs */ 129839217Sgibbsstatic void 129939217Sgibbsadv_poll(struct cam_sim *sim) 130039217Sgibbs{ 130139217Sgibbs adv_intr(cam_sim_softc(sim)); 130239217Sgibbs} 130339217Sgibbs 130439217Sgibbs/* 130539217Sgibbs * Attach all the sub-devices we can find 130639217Sgibbs */ 130739217Sgibbsint 130839217Sgibbsadv_attach(adv) 130939217Sgibbs struct adv_softc *adv; 131039217Sgibbs{ 131139217Sgibbs struct ccb_setasync csa; 131239217Sgibbs struct cam_devq *devq; 131355945Sgibbs int max_sg; 131439217Sgibbs 131539217Sgibbs /* 131655945Sgibbs * Allocate an array of ccb mapping structures. We put the 131755945Sgibbs * index of the ccb_info structure into the queue representing 131855945Sgibbs * a transaction and use it for mapping the queue to the 131955945Sgibbs * upper level SCSI transaction it represents. 132055945Sgibbs */ 132155945Sgibbs adv->ccb_infos = malloc(sizeof(*adv->ccb_infos) * adv->max_openings, 132255945Sgibbs M_DEVBUF, M_NOWAIT); 132355945Sgibbs 132455945Sgibbs if (adv->ccb_infos == NULL) 132555945Sgibbs goto error_exit; 132655945Sgibbs 132755945Sgibbs adv->init_level++; 132855945Sgibbs 132955945Sgibbs /* 133039217Sgibbs * Create our DMA tags. These tags define the kinds of device 133139217Sgibbs * accessable memory allocations and memory mappings we will 133239217Sgibbs * need to perform during normal operation. 133339217Sgibbs * 133439217Sgibbs * Unless we need to further restrict the allocation, we rely 133539217Sgibbs * on the restrictions of the parent dmat, hence the common 133639217Sgibbs * use of MAXADDR and MAXSIZE. 133755945Sgibbs * 133855945Sgibbs * The ASC boards use chains of "queues" (the transactional 133955945Sgibbs * resources on the board) to represent long S/G lists. 134055945Sgibbs * The first queue represents the command and holds a 134155945Sgibbs * single address and data pair. The queues that follow 134255945Sgibbs * can each hold ADV_SG_LIST_PER_Q entries. Given the 134355945Sgibbs * total number of queues, we can express the largest 134455945Sgibbs * transaction we can map. We reserve a few queues for 134555945Sgibbs * error recovery. Take those into account as well. 134655945Sgibbs * 134755945Sgibbs * There is a way to take an interrupt to download the 134855945Sgibbs * next batch of S/G entries if there are more than 255 134955945Sgibbs * of them (the counter in the queue structure is a u_int8_t). 135055945Sgibbs * We don't use this feature, so limit the S/G list size 135155945Sgibbs * accordingly. 135239217Sgibbs */ 135355945Sgibbs max_sg = (adv->max_openings - ADV_MIN_FREE_Q - 1) * ADV_SG_LIST_PER_Q; 135455945Sgibbs if (max_sg > 255) 135555945Sgibbs max_sg = 255; 135639217Sgibbs 135739217Sgibbs /* DMA tag for mapping buffers into device visible space. */ 135849860Sgibbs if (bus_dma_tag_create(adv->parent_dmat, /*alignment*/1, /*boundary*/0, 135939217Sgibbs /*lowaddr*/BUS_SPACE_MAXADDR, 136039217Sgibbs /*highaddr*/BUS_SPACE_MAXADDR, 136139217Sgibbs /*filter*/NULL, /*filterarg*/NULL, 136255945Sgibbs /*maxsize*/MAXPHYS, 136355945Sgibbs /*nsegments*/max_sg, 136439217Sgibbs /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, 136539217Sgibbs /*flags*/BUS_DMA_ALLOCNOW, 136639217Sgibbs &adv->buffer_dmat) != 0) { 136739217Sgibbs goto error_exit; 136839217Sgibbs } 136939217Sgibbs adv->init_level++; 137039217Sgibbs 137139217Sgibbs /* DMA tag for our sense buffers */ 137249860Sgibbs if (bus_dma_tag_create(adv->parent_dmat, /*alignment*/1, /*boundary*/0, 137339217Sgibbs /*lowaddr*/BUS_SPACE_MAXADDR, 137439217Sgibbs /*highaddr*/BUS_SPACE_MAXADDR, 137539217Sgibbs /*filter*/NULL, /*filterarg*/NULL, 137639217Sgibbs sizeof(struct scsi_sense_data)*adv->max_openings, 137739217Sgibbs /*nsegments*/1, 137839217Sgibbs /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, 137939217Sgibbs /*flags*/0, &adv->sense_dmat) != 0) { 138039217Sgibbs goto error_exit; 138139217Sgibbs } 138239217Sgibbs 138339217Sgibbs adv->init_level++; 138439217Sgibbs 138539217Sgibbs /* Allocation for our sense buffers */ 138639217Sgibbs if (bus_dmamem_alloc(adv->sense_dmat, (void **)&adv->sense_buffers, 138739217Sgibbs BUS_DMA_NOWAIT, &adv->sense_dmamap) != 0) { 138839217Sgibbs goto error_exit; 138939217Sgibbs } 139039217Sgibbs 139139217Sgibbs adv->init_level++; 139239217Sgibbs 139339217Sgibbs /* And permanently map them */ 139439217Sgibbs bus_dmamap_load(adv->sense_dmat, adv->sense_dmamap, 139539217Sgibbs adv->sense_buffers, 139639217Sgibbs sizeof(struct scsi_sense_data)*adv->max_openings, 139739217Sgibbs adv_map, &adv->sense_physbase, /*flags*/0); 139839217Sgibbs 139939217Sgibbs adv->init_level++; 140039217Sgibbs 140139217Sgibbs /* 140239217Sgibbs * Fire up the chip 140339217Sgibbs */ 140439217Sgibbs if (adv_start_chip(adv) != 1) { 140539217Sgibbs printf("adv%d: Unable to start on board processor. Aborting.\n", 140639217Sgibbs adv->unit); 140739217Sgibbs return (0); 140839217Sgibbs } 140939217Sgibbs 141039217Sgibbs /* 141139217Sgibbs * Create the device queue for our SIM. 141239217Sgibbs */ 141339217Sgibbs devq = cam_simq_alloc(adv->max_openings); 141439217Sgibbs if (devq == NULL) 141539217Sgibbs return (0); 141639217Sgibbs 141739217Sgibbs /* 141839217Sgibbs * Construct our SIM entry. 141939217Sgibbs */ 142039217Sgibbs adv->sim = cam_sim_alloc(adv_action, adv_poll, "adv", adv, adv->unit, 142139217Sgibbs 1, adv->max_openings, devq); 142239217Sgibbs if (adv->sim == NULL) 142339217Sgibbs return (0); 142439217Sgibbs 142539217Sgibbs /* 142639217Sgibbs * Register the bus. 142739217Sgibbs * 142839217Sgibbs * XXX Twin Channel EISA Cards??? 142939217Sgibbs */ 143039217Sgibbs if (xpt_bus_register(adv->sim, 0) != CAM_SUCCESS) { 143139217Sgibbs cam_sim_free(adv->sim, /*free devq*/TRUE); 143239217Sgibbs return (0); 143339217Sgibbs } 143439217Sgibbs 143539217Sgibbs if (xpt_create_path(&adv->path, /*periph*/NULL, cam_sim_path(adv->sim), 143639217Sgibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) 143739217Sgibbs == CAM_REQ_CMP) { 143839217Sgibbs xpt_setup_ccb(&csa.ccb_h, adv->path, /*priority*/5); 143939217Sgibbs csa.ccb_h.func_code = XPT_SASYNC_CB; 144039217Sgibbs csa.event_enable = AC_FOUND_DEVICE|AC_LOST_DEVICE; 144139217Sgibbs csa.callback = advasync; 144239217Sgibbs csa.callback_arg = adv; 144339217Sgibbs xpt_action((union ccb *)&csa); 144439217Sgibbs } 144539217Sgibbs return (1); 144639217Sgibbs 144739217Sgibbserror_exit: 144839217Sgibbs return (0); 144939217Sgibbs} 1450