advansys.c revision 45443
1219089Spjd/* 2219089Spjd * Generic driver for the Advanced Systems Inc. SCSI controllers 3219089Spjd * Product specific probe and attach routines can be found in: 4219089Spjd * 5219089Spjd * i386/isa/adv_isa.c ABP5140, ABP542, ABP5150, ABP842, ABP852 6219089Spjd * i386/eisa/adv_eisa.c ABP742, ABP752 7219089Spjd * pci/adv_pci.c ABP920, ABP930, ABP930U, ABP930UA, ABP940, ABP940U, 8219089Spjd * ABP940UA, ABP950, ABP960, ABP960U, ABP960UA, 9219089Spjd * ABP970, ABP970U 10219089Spjd * 11219089Spjd * Copyright (c) 1996-1998 Justin Gibbs. 12219089Spjd * All rights reserved. 13219089Spjd * 14219089Spjd * Redistribution and use in source and binary forms, with or without 15219089Spjd * modification, are permitted provided that the following conditions 16219089Spjd * are met: 17219089Spjd * 1. Redistributions of source code must retain the above copyright 18219089Spjd * notice, this list of conditions, and the following disclaimer, 19219089Spjd * without modification, immediately at the beginning of the file. 20219089Spjd * 2. The name of the author may not be used to endorse or promote products 21219089Spjd * derived from this software without specific prior written permission. 22219089Spjd * 23249195Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24219089Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25219089Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26219089Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 27219089Spjd * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28219089Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29219089Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30219089Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31219089Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32219089Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33219089Spjd * SUCH DAMAGE. 34219089Spjd * 35219089Spjd * $Id: advansys.c,v 1.7 1998/12/22 18:12:09 gibbs Exp $ 36219089Spjd */ 37219089Spjd/* 38219089Spjd * Ported from: 39219089Spjd * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters 40219089Spjd * 41219089Spjd * Copyright (c) 1995-1997 Advanced System Products, Inc. 42219089Spjd * All Rights Reserved. 43219089Spjd * 44219089Spjd * Redistribution and use in source and binary forms, with or without 45219089Spjd * modification, are permitted provided that redistributions of source 46219089Spjd * code retain the above copyright notice and this comment without 47219089Spjd * modification. 48236884Smm */ 49219089Spjd 50219089Spjd#include <sys/param.h> 51219089Spjd#include <sys/systm.h> 52219089Spjd#include <sys/malloc.h> 53219089Spjd#include <sys/buf.h> 54219089Spjd#include <sys/kernel.h> 55219089Spjd 56219089Spjd#include <machine/bus_pio.h> 57219089Spjd#include <machine/bus.h> 58248571Smm#include <machine/clock.h> 59219089Spjd 60219089Spjd#include <cam/cam.h> 61237972Smm#include <cam/cam_ccb.h> 62237972Smm#include <cam/cam_sim.h> 63237972Smm#include <cam/cam_xpt_sim.h> 64237972Smm#include <cam/cam_xpt_periph.h> 65219089Spjd#include <cam/cam_debug.h> 66237972Smm 67237972Smm#include <cam/scsi/scsi_all.h> 68237972Smm#include <cam/scsi/scsi_message.h> 69237972Smm 70219089Spjd#include <vm/vm.h> 71219089Spjd#include <vm/vm_param.h> 72237972Smm#include <vm/pmap.h> 73237972Smm 74237972Smm#include <dev/advansys/advansys.h> 75237972Smm 76237972Smmu_long adv_unit; 77237972Smm 78237972Smmstatic void adv_action(struct cam_sim *sim, union ccb *ccb); 79237972Smmstatic void adv_execute_ccb(void *arg, bus_dma_segment_t *dm_segs, 80237972Smm int nsegments, int error); 81237972Smmstatic void adv_poll(struct cam_sim *sim); 82237972Smmstatic void adv_run_doneq(struct adv_softc *adv); 83237972Smmstatic struct adv_ccb_info * 84237972Smm adv_alloc_ccb_info(struct adv_softc *adv); 85237972Smmstatic void adv_destroy_ccb_info(struct adv_softc *adv, 86237972Smm struct adv_ccb_info *cinfo); 87237972Smmstatic __inline struct adv_ccb_info * 88237972Smm adv_get_ccb_info(struct adv_softc *adv); 89237972Smmstatic __inline void adv_free_ccb_info(struct adv_softc *adv, 90237972Smm struct adv_ccb_info *cinfo); 91237972Smm 92237972Smm 93237972Smmstruct adv_softc *advsoftcs[NADV]; /* XXX Config should handle this */ 94237972Smm 95237972Smmstatic __inline struct adv_ccb_info * 96237972Smmadv_get_ccb_info(struct adv_softc *adv) 97237972Smm{ 98237972Smm struct adv_ccb_info *cinfo; 99237972Smm int opri; 100237972Smm 101237972Smm opri = splcam(); 102219089Spjd if ((cinfo = SLIST_FIRST(&adv->free_ccb_infos)) != NULL) { 103219089Spjd SLIST_REMOVE_HEAD(&adv->free_ccb_infos, links); 104219089Spjd } else { 105219089Spjd cinfo = adv_alloc_ccb_info(adv); 106219089Spjd } 107219089Spjd splx(opri); 108219089Spjd 109219089Spjd return (cinfo); 110219089Spjd} 111219089Spjd 112219089Spjdstatic __inline void 113219089Spjdadv_free_ccb_info(struct adv_softc *adv, struct adv_ccb_info *cinfo) 114219089Spjd{ 115219089Spjd int opri; 116219089Spjd 117219089Spjd opri = splcam(); 118219089Spjd cinfo->state = ACCB_FREE; 119219089Spjd SLIST_INSERT_HEAD(&adv->free_ccb_infos, cinfo, links); 120219089Spjd splx(opri); 121219089Spjd} 122219089Spjd 123219089Spjdvoid 124219089Spjdadv_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) 125219089Spjd{ 126219089Spjd bus_addr_t* physaddr; 127219089Spjd 128249858Smm physaddr = (bus_addr_t*)arg; 129249858Smm *physaddr = segs->ds_addr; 130249858Smm} 131249858Smm 132249858Smmchar * 133249858Smmadv_name(struct adv_softc *adv) 134249858Smm{ 135249858Smm static char name[10]; 136249858Smm 137219089Spjd snprintf(name, sizeof(name), "adv%d", adv->unit); 138219089Spjd return (name); 139219089Spjd} 140219089Spjd 141219089Spjdstatic void 142219089Spjdadv_action(struct cam_sim *sim, union ccb *ccb) 143219089Spjd{ 144219089Spjd struct adv_softc *adv; 145219089Spjd 146219089Spjd CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("adv_action\n")); 147219089Spjd 148219089Spjd adv = (struct adv_softc *)cam_sim_softc(sim); 149219089Spjd 150219089Spjd switch (ccb->ccb_h.func_code) { 151219089Spjd /* Common cases first */ 152219089Spjd case XPT_SCSI_IO: /* Execute the requested I/O operation */ 153219089Spjd { 154219089Spjd struct ccb_hdr *ccb_h; 155219089Spjd struct ccb_scsiio *csio; 156219089Spjd struct adv_ccb_info *cinfo; 157219089Spjd 158219089Spjd ccb_h = &ccb->ccb_h; 159219089Spjd csio = &ccb->csio; 160219089Spjd cinfo = adv_get_ccb_info(adv); 161219089Spjd if (cinfo == NULL) 162219089Spjd panic("XXX Handle CCB info error!!!"); 163219089Spjd 164219089Spjd ccb_h->ccb_cinfo_ptr = cinfo; 165219089Spjd 166219089Spjd /* Only use S/G if there is a transfer */ 167219089Spjd if ((ccb_h->flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 168219089Spjd if ((ccb_h->flags & CAM_SCATTER_VALID) == 0) { 169219089Spjd /* 170219089Spjd * We've been given a pointer 171219089Spjd * to a single buffer 172219089Spjd */ 173219089Spjd if ((ccb_h->flags & CAM_DATA_PHYS) == 0) { 174219089Spjd int s; 175219089Spjd int error; 176219089Spjd 177219089Spjd s = splsoftvm(); 178219089Spjd error = 179219089Spjd bus_dmamap_load(adv->buffer_dmat, 180219089Spjd cinfo->dmamap, 181219089Spjd csio->data_ptr, 182219089Spjd csio->dxfer_len, 183219089Spjd adv_execute_ccb, 184219089Spjd csio, /*flags*/0); 185219089Spjd if (error == EINPROGRESS) { 186219089Spjd /* 187219089Spjd * So as to maintain ordering, 188219089Spjd * freeze the controller queue 189219089Spjd * until our mapping is 190219089Spjd * returned. 191219089Spjd */ 192219089Spjd xpt_freeze_simq(adv->sim, 193219089Spjd /*count*/1); 194219089Spjd cinfo->state |= 195219089Spjd ACCB_RELEASE_SIMQ; 196248571Smm } 197219089Spjd splx(s); 198248571Smm } else { 199219089Spjd struct bus_dma_segment seg; 200219089Spjd 201249195Smm /* Pointer to physical buffer */ 202219089Spjd seg.ds_addr = 203219089Spjd (bus_addr_t)csio->data_ptr; 204219089Spjd seg.ds_len = csio->dxfer_len; 205219089Spjd adv_execute_ccb(csio, &seg, 1, 0); 206219089Spjd } 207248571Smm } else { 208219089Spjd struct bus_dma_segment *segs; 209248571Smm if ((ccb_h->flags & CAM_DATA_PHYS) != 0) 210248571Smm panic("adv_setup_data - Physical " 211219089Spjd "segment pointers unsupported"); 212219089Spjd 213219089Spjd if ((ccb_h->flags & CAM_SG_LIST_PHYS) == 0) 214219089Spjd panic("adv_setup_data - Virtual " 215219089Spjd "segment addresses unsupported"); 216219089Spjd 217219089Spjd /* Just use the segments provided */ 218219089Spjd segs = (struct bus_dma_segment *)csio->data_ptr; 219219089Spjd adv_execute_ccb(ccb, segs, csio->sglist_cnt, 0); 220219089Spjd } 221219089Spjd } else { 222219089Spjd adv_execute_ccb(ccb, NULL, 0, 0); 223219089Spjd } 224219089Spjd break; 225219089Spjd } 226219089Spjd case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ 227254112Sdelphij case XPT_TARGET_IO: /* Execute target I/O request */ 228219089Spjd case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */ 229219089Spjd case XPT_CONT_TARGET_IO: /* Continue Host Target I/O Connection*/ 230219089Spjd case XPT_EN_LUN: /* Enable LUN as a target */ 231219089Spjd case XPT_ABORT: /* Abort the specified CCB */ 232219089Spjd /* XXX Implement */ 233219089Spjd ccb->ccb_h.status = CAM_REQ_INVALID; 234219089Spjd xpt_done(ccb); 235219089Spjd break; 236219089Spjd case XPT_SET_TRAN_SETTINGS: 237219089Spjd { 238219089Spjd struct ccb_trans_settings *cts; 239219089Spjd target_bit_vector targ_mask; 240219089Spjd struct adv_target_transinfo *tconf; 241219089Spjd u_int update_type; 242219089Spjd int s; 243219089Spjd 244219089Spjd cts = &ccb->cts; 245219089Spjd targ_mask = ADV_TID_TO_TARGET_MASK(cts->ccb_h.target_id); 246219089Spjd tconf = &adv->tinfo[cts->ccb_h.target_id]; 247219089Spjd update_type = 0; 248219089Spjd if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) 249219089Spjd update_type |= ADV_TRANS_GOAL; 250219089Spjd if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) 251219089Spjd update_type |= ADV_TRANS_USER; 252219089Spjd 253219089Spjd s = splcam(); 254219089Spjd 255219089Spjd if ((update_type & ADV_TRANS_GOAL) != 0) { 256219089Spjd if ((cts->valid & CCB_TRANS_DISC_VALID) != 0) { 257219089Spjd if ((cts->flags & CCB_TRANS_DISC_ENB) != 0) 258219089Spjd adv->disc_enable |= targ_mask; 259219089Spjd else 260219089Spjd adv->disc_enable &= ~targ_mask; 261219089Spjd adv_write_lram_8(adv, ADVV_DISC_ENABLE_B, 262219089Spjd adv->disc_enable); 263219089Spjd } 264219089Spjd 265219089Spjd if ((cts->valid & CCB_TRANS_TQ_VALID) != 0) { 266219089Spjd if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) 267219089Spjd adv->cmd_qng_enabled |= targ_mask; 268219089Spjd else 269219089Spjd adv->cmd_qng_enabled &= ~targ_mask; 270248571Smm } 271219089Spjd } 272219089Spjd 273219089Spjd if ((update_type & ADV_TRANS_USER) != 0) { 274219089Spjd if ((cts->valid & CCB_TRANS_DISC_VALID) != 0) { 275219089Spjd if ((cts->flags & CCB_TRANS_DISC_ENB) != 0) 276219089Spjd adv->user_disc_enable |= targ_mask; 277219089Spjd else 278219089Spjd adv->user_disc_enable &= ~targ_mask; 279219089Spjd } 280219089Spjd 281219089Spjd if ((cts->valid & CCB_TRANS_TQ_VALID) != 0) { 282219089Spjd if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) 283219089Spjd adv->user_cmd_qng_enabled |= targ_mask; 284219089Spjd else 285219089Spjd adv->user_cmd_qng_enabled &= ~targ_mask; 286219089Spjd } 287219089Spjd } 288219089Spjd 289219089Spjd if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0) { 290219089Spjd if ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) == 0) 291219089Spjd cts->sync_offset = 0; 292219089Spjd 293219089Spjd adv_period_offset_to_sdtr(adv, &cts->sync_period, 294219089Spjd &cts->sync_offset, 295219089Spjd cts->ccb_h.target_id); 296219089Spjd 297219089Spjd adv_set_syncrate(adv, /*struct cam_path */NULL, 298219089Spjd cts->ccb_h.target_id, cts->sync_period, 299219089Spjd cts->sync_offset, update_type); 300219089Spjd } 301219089Spjd splx(s); 302219089Spjd ccb->ccb_h.status = CAM_REQ_CMP; 303219089Spjd xpt_done(ccb); 304219089Spjd break; 305219089Spjd } 306219089Spjd case XPT_GET_TRAN_SETTINGS: 307219089Spjd /* Get default/user set transfer settings for the target */ 308219089Spjd { 309219089Spjd struct ccb_trans_settings *cts; 310219089Spjd struct adv_transinfo *tconf; 311219089Spjd target_bit_vector target_mask; 312219089Spjd int s; 313219089Spjd 314219089Spjd cts = &ccb->cts; 315219089Spjd target_mask = ADV_TID_TO_TARGET_MASK(cts->ccb_h.target_id); 316219089Spjd 317219089Spjd cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB); 318219089Spjd 319248571Smm s = splcam(); 320219089Spjd if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) { 321219089Spjd tconf = &adv->tinfo[cts->ccb_h.target_id].current; 322219089Spjd if ((adv->disc_enable & target_mask) != 0) 323219089Spjd cts->flags |= CCB_TRANS_DISC_ENB; 324219089Spjd if ((adv->cmd_qng_enabled & target_mask) != 0) 325219089Spjd cts->flags |= CCB_TRANS_TAG_ENB; 326219089Spjd } else { 327219089Spjd tconf = &adv->tinfo[cts->ccb_h.target_id].user; 328219089Spjd if ((adv->user_disc_enable & target_mask) != 0) 329219089Spjd cts->flags |= CCB_TRANS_DISC_ENB; 330219089Spjd if ((adv->user_cmd_qng_enabled & target_mask) != 0) 331219089Spjd cts->flags |= CCB_TRANS_TAG_ENB; 332219089Spjd } 333219089Spjd 334219089Spjd cts->sync_period = tconf->period; 335219089Spjd cts->sync_offset = tconf->offset; 336219089Spjd splx(s); 337219089Spjd 338219089Spjd cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 339219089Spjd cts->valid = CCB_TRANS_SYNC_RATE_VALID 340219089Spjd | CCB_TRANS_SYNC_OFFSET_VALID 341219089Spjd | CCB_TRANS_BUS_WIDTH_VALID 342219089Spjd | CCB_TRANS_DISC_VALID 343219089Spjd | CCB_TRANS_TQ_VALID; 344219089Spjd ccb->ccb_h.status = CAM_REQ_CMP; 345219089Spjd xpt_done(ccb); 346219089Spjd break; 347219089Spjd } 348219089Spjd case XPT_CALC_GEOMETRY: 349219089Spjd { 350219089Spjd struct ccb_calc_geometry *ccg; 351219089Spjd u_int32_t size_mb; 352219089Spjd u_int32_t secs_per_cylinder; 353219089Spjd int extended; 354219089Spjd 355219089Spjd ccg = &ccb->ccg; 356219089Spjd size_mb = ccg->volume_size 357248571Smm / ((1024L * 1024L) / ccg->block_size); 358219089Spjd extended = (adv->control & ADV_CNTL_BIOS_GT_1GB) != 0; 359248571Smm 360219089Spjd if (size_mb > 1024 && extended) { 361219089Spjd ccg->heads = 255; 362249195Smm ccg->secs_per_track = 63; 363219089Spjd } else { 364219089Spjd ccg->heads = 64; 365219089Spjd ccg->secs_per_track = 32; 366219089Spjd } 367219089Spjd secs_per_cylinder = ccg->heads * ccg->secs_per_track; 368248571Smm ccg->cylinders = ccg->volume_size / secs_per_cylinder; 369219089Spjd ccb->ccb_h.status = CAM_REQ_CMP; 370248571Smm xpt_done(ccb); 371219089Spjd break; 372219089Spjd } 373219089Spjd case XPT_RESET_BUS: /* Reset the specified SCSI bus */ 374219089Spjd { 375219089Spjd int s; 376219089Spjd 377219089Spjd s = splcam(); 378219089Spjd adv_stop_execution(adv); 379248571Smm adv_reset_bus(adv); 380248571Smm adv_start_execution(adv); 381219089Spjd splx(s); 382219089Spjd 383219089Spjd ccb->ccb_h.status = CAM_REQ_CMP; 384219089Spjd xpt_done(ccb); 385219089Spjd break; 386219089Spjd } 387219089Spjd case XPT_TERM_IO: /* Terminate the I/O process */ 388219089Spjd /* XXX Implement */ 389219089Spjd ccb->ccb_h.status = CAM_REQ_INVALID; 390219089Spjd xpt_done(ccb); 391219089Spjd break; 392219089Spjd case XPT_PATH_INQ: /* Path routing inquiry */ 393219089Spjd { 394219089Spjd struct ccb_pathinq *cpi = &ccb->cpi; 395219089Spjd 396219089Spjd cpi->version_num = 1; /* XXX??? */ 397219089Spjd cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE; 398219089Spjd cpi->target_sprt = 0; 399219089Spjd cpi->hba_misc = 0; 400219089Spjd cpi->hba_eng_cnt = 0; 401240868Spjd cpi->max_target = 7; 402240868Spjd cpi->max_lun = 7; 403219089Spjd cpi->initiator_id = adv->scsi_id; 404219089Spjd cpi->bus_id = cam_sim_bus(sim); 405219089Spjd strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 406219089Spjd strncpy(cpi->hba_vid, "Advansys", HBA_IDLEN); 407219089Spjd strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 408219089Spjd cpi->unit_number = cam_sim_unit(sim); 409219089Spjd cpi->ccb_h.status = CAM_REQ_CMP; 410219089Spjd xpt_done(ccb); 411219089Spjd break; 412219089Spjd } 413219089Spjd default: 414219089Spjd ccb->ccb_h.status = CAM_REQ_INVALID; 415219089Spjd xpt_done(ccb); 416219089Spjd break; 417248571Smm } 418219089Spjd} 419219089Spjd 420219089Spjd/* 421219089Spjd * Currently, the output of bus_dmammap_load suits our needs just 422219089Spjd * fine, but should it change, we'd need to do something here. 423219089Spjd */ 424219089Spjd#define adv_fixup_dmasegs(adv, dm_segs) (struct adv_sg_entry *)(dm_segs) 425219089Spjd 426219089Spjdstatic void 427237972Smmadv_execute_ccb(void *arg, bus_dma_segment_t *dm_segs, 428219089Spjd int nsegments, int error) 429219089Spjd{ 430219089Spjd struct ccb_scsiio *csio; 431219089Spjd struct ccb_hdr *ccb_h; 432219089Spjd struct cam_sim *sim; 433219089Spjd struct adv_softc *adv; 434219089Spjd struct adv_ccb_info *cinfo; 435219089Spjd struct adv_scsi_q scsiq; 436236884Smm struct adv_sg_head sghead; 437219089Spjd int s; 438219089Spjd 439219089Spjd csio = (struct ccb_scsiio *)arg; 440219089Spjd ccb_h = &csio->ccb_h; 441219089Spjd sim = xpt_path_sim(ccb_h->path); 442219089Spjd adv = (struct adv_softc *)cam_sim_softc(sim); 443219089Spjd cinfo = (struct adv_ccb_info *)csio->ccb_h.ccb_cinfo_ptr; 444219089Spjd 445219089Spjd if ((ccb_h->flags & CAM_CDB_POINTER) != 0) { 446219089Spjd if ((ccb_h->flags & CAM_CDB_PHYS) == 0) { 447219089Spjd /* XXX Need phystovirt!!!! */ 448219089Spjd /* How about pmap_kenter??? */ 449219089Spjd scsiq.cdbptr = csio->cdb_io.cdb_ptr; 450219089Spjd } else { 451219089Spjd scsiq.cdbptr = csio->cdb_io.cdb_ptr; 452219089Spjd } 453219089Spjd } else { 454219089Spjd scsiq.cdbptr = csio->cdb_io.cdb_bytes; 455219089Spjd } 456219089Spjd /* 457219089Spjd * Build up the request 458219089Spjd */ 459219089Spjd scsiq.q1.status = 0; 460219089Spjd scsiq.q1.q_no = 0; 461219089Spjd scsiq.q1.cntl = 0; 462219089Spjd scsiq.q1.sg_queue_cnt = 0; 463219089Spjd scsiq.q1.target_id = ADV_TID_TO_TARGET_MASK(ccb_h->target_id); 464219089Spjd scsiq.q1.target_lun = ccb_h->target_lun; 465219089Spjd scsiq.q1.sense_len = csio->sense_len; 466219089Spjd scsiq.q1.extra_bytes = 0; 467219089Spjd scsiq.q2.ccb_ptr = (u_int32_t)csio; 468219089Spjd scsiq.q2.target_ix = ADV_TIDLUN_TO_IX(ccb_h->target_id, 469219089Spjd ccb_h->target_lun); 470219089Spjd scsiq.q2.flag = 0; 471219089Spjd scsiq.q2.cdb_len = csio->cdb_len; 472219089Spjd if ((ccb_h->flags & CAM_TAG_ACTION_VALID) != 0) 473219089Spjd scsiq.q2.tag_code = csio->tag_action; 474219089Spjd else 475219089Spjd scsiq.q2.tag_code = 0; 476219089Spjd scsiq.q2.vm_id = 0; 477219089Spjd 478219089Spjd if (nsegments != 0) { 479219089Spjd bus_dmasync_op_t op; 480219089Spjd 481219089Spjd scsiq.q1.data_addr = dm_segs->ds_addr; 482219089Spjd scsiq.q1.data_cnt = dm_segs->ds_len; 483219089Spjd if (nsegments > 1) { 484219089Spjd scsiq.q1.cntl |= QC_SG_HEAD; 485219089Spjd sghead.entry_cnt 486219089Spjd = sghead.entry_to_copy 487219089Spjd = nsegments; 488219089Spjd sghead.res = 0; 489219089Spjd sghead.sg_list = adv_fixup_dmasegs(adv, dm_segs); 490219089Spjd scsiq.sg_head = &sghead; 491219089Spjd } else { 492219089Spjd scsiq.sg_head = NULL; 493219089Spjd } 494219089Spjd if ((ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_IN) 495219089Spjd op = BUS_DMASYNC_PREREAD; 496219089Spjd else 497219089Spjd op = BUS_DMASYNC_PREWRITE; 498219089Spjd bus_dmamap_sync(adv->buffer_dmat, cinfo->dmamap, op); 499219089Spjd } else { 500219089Spjd scsiq.q1.data_addr = 0; 501219089Spjd scsiq.q1.data_cnt = 0; 502219089Spjd scsiq.sg_head = NULL; 503219089Spjd } 504219089Spjd 505219089Spjd s = splcam(); 506219089Spjd 507219089Spjd /* 508219089Spjd * Last time we need to check if this SCB needs to 509219089Spjd * be aborted. 510219089Spjd */ 511219089Spjd if (ccb_h->status != CAM_REQ_INPROG) { 512219089Spjd if (nsegments != 0) { 513219089Spjd bus_dmamap_unload(adv->buffer_dmat, cinfo->dmamap); 514219089Spjd } 515219089Spjd if ((cinfo->state & ACCB_RELEASE_SIMQ) != 0) { 516219089Spjd ccb_h->status |= CAM_RELEASE_SIMQ; 517219089Spjd } 518219089Spjd adv_free_ccb_info(adv, cinfo); 519219089Spjd xpt_done((union ccb *)csio); 520219089Spjd splx(s); 521219089Spjd return; 522219089Spjd } 523219089Spjd 524219089Spjd if (adv_execute_scsi_queue(adv, &scsiq, csio->dxfer_len) != 0) { 525219089Spjd /* Temporary resource shortage */ 526219089Spjd if (nsegments != 0) { 527219089Spjd bus_dmamap_unload(adv->buffer_dmat, cinfo->dmamap); 528219089Spjd } 529219089Spjd ccb_h->status = CAM_REQUEUE_REQ; 530219089Spjd if ((cinfo->state & ACCB_RELEASE_SIMQ) != 0) 531219089Spjd ccb_h->status |= CAM_RELEASE_SIMQ; 532219089Spjd 533219089Spjd /* Unfreeze when resources are available */ 534219089Spjd xpt_freeze_simq(adv->sim, /*count*/1); 535219089Spjd 536219089Spjd adv_free_ccb_info(adv, cinfo); 537219089Spjd xpt_done((union ccb *)csio); 538219089Spjd splx(s); 539219089Spjd return; 540219089Spjd } 541219089Spjd cinfo->state |= ACCB_ACTIVE; 542219089Spjd ccb_h->status |= CAM_SIM_QUEUED; 543219089Spjd LIST_INSERT_HEAD(&adv->pending_ccbs, ccb_h, sim_links.le); 544219089Spjd /* Schedule our timeout */ 545219089Spjd ccb_h->timeout_ch = 546219089Spjd timeout(adv_timeout, csio, (ccb_h->timeout * hz)/1000); 547219089Spjd splx(s); 548219089Spjd} 549219089Spjd 550219089Spjdstatic struct adv_ccb_info * 551219089Spjdadv_alloc_ccb_info(struct adv_softc *adv) 552219089Spjd{ 553219089Spjd int error; 554219089Spjd struct adv_ccb_info *cinfo; 555219089Spjd 556219089Spjd cinfo = malloc(sizeof(*cinfo), M_DEVBUF, M_NOWAIT); 557219089Spjd if (cinfo == NULL) { 558219089Spjd printf("%s: Can't malloc CCB info\n", adv_name(adv)); 559219089Spjd return (NULL); 560219089Spjd } 561219089Spjd cinfo->state = ACCB_FREE; 562219089Spjd error = bus_dmamap_create(adv->buffer_dmat, /*flags*/0, 563219089Spjd &cinfo->dmamap); 564219089Spjd if (error != 0) { 565219089Spjd printf("%s: Unable to allocate CCB info " 566219089Spjd "dmamap - error %d\n", adv_name(adv), error); 567219089Spjd free(cinfo, M_DEVBUF); 568219089Spjd cinfo = NULL; 569219089Spjd } 570219089Spjd return (cinfo); 571219089Spjd} 572219089Spjd 573219089Spjdstatic void 574219089Spjdadv_destroy_ccb_info(struct adv_softc *adv, struct adv_ccb_info *cinfo) 575219089Spjd{ 576246666Smm bus_dmamap_destroy(adv->buffer_dmat, cinfo->dmamap); 577219089Spjd free(cinfo, M_DEVBUF); 578219089Spjd} 579219089Spjd 580219089Spjdvoid 581219089Spjdadv_timeout(void *arg) 582219089Spjd{ 583219089Spjd int s; 584219089Spjd union ccb *ccb; 585219089Spjd struct adv_softc *adv; 586219089Spjd struct adv_ccb_info *cinfo; 587236884Smm 588219089Spjd ccb = (union ccb *)arg; 589219089Spjd adv = (struct adv_softc *)xpt_path_sim(ccb->ccb_h.path)->softc; 590219089Spjd cinfo = (struct adv_ccb_info *)ccb->ccb_h.ccb_cinfo_ptr; 591219089Spjd 592219089Spjd xpt_print_path(ccb->ccb_h.path); 593236884Smm printf("Timed out\n"); 594219089Spjd 595219089Spjd s = splcam(); 596219089Spjd /* Have we been taken care of already?? */ 597219089Spjd if (cinfo == NULL || cinfo->state == ACCB_FREE) { 598219089Spjd splx(s); 599219089Spjd return; 600219089Spjd } 601219089Spjd 602219089Spjd adv_stop_execution(adv); 603219089Spjd 604219089Spjd if ((cinfo->state & ACCB_ABORT_QUEUED) == 0) { 605219089Spjd struct ccb_hdr *ccb_h; 606219089Spjd 607219089Spjd /* 608219089Spjd * In order to simplify the recovery process, we ask the XPT 609219089Spjd * layer to halt the queue of new transactions and we traverse 610219089Spjd * the list of pending CCBs and remove their timeouts. This 611219089Spjd * means that the driver attempts to clear only one error 612219089Spjd * condition at a time. In general, timeouts that occur 613219089Spjd * close together are related anyway, so there is no benefit 614219089Spjd * in attempting to handle errors in parrallel. Timeouts will 615219089Spjd * be reinstated when the recovery process ends. 616219089Spjd */ 617219089Spjd if ((cinfo->state & ACCB_RELEASE_SIMQ) == 0) { 618219089Spjd xpt_freeze_simq(adv->sim, /*count*/1); 619219089Spjd cinfo->state |= ACCB_RELEASE_SIMQ; 620219089Spjd } 621219089Spjd 622219089Spjd /* This CCB is the CCB representing our recovery actions */ 623219089Spjd cinfo->state |= ACCB_RECOVERY_CCB|ACCB_ABORT_QUEUED; 624219089Spjd 625219089Spjd ccb_h = LIST_FIRST(&adv->pending_ccbs); 626219089Spjd while (ccb_h != NULL) { 627219089Spjd untimeout(adv_timeout, ccb_h, ccb_h->timeout_ch); 628219089Spjd ccb_h = LIST_NEXT(ccb_h, sim_links.le); 629219089Spjd } 630219089Spjd 631219089Spjd /* XXX Should send a BDR */ 632219089Spjd /* Attempt an abort as our first tact */ 633219089Spjd xpt_print_path(ccb->ccb_h.path); 634246666Smm printf("Attempting abort\n"); 635219089Spjd adv_abort_ccb(adv, ccb->ccb_h.target_id, 636219089Spjd ccb->ccb_h.target_lun, ccb, 637219089Spjd CAM_CMD_TIMEOUT, /*queued_only*/FALSE); 638219089Spjd ccb->ccb_h.timeout_ch = 639219089Spjd timeout(adv_timeout, ccb, 2 * hz); 640219089Spjd } else { 641219089Spjd /* Our attempt to perform an abort failed, go for a reset */ 642219089Spjd xpt_print_path(ccb->ccb_h.path); 643219089Spjd printf("Resetting bus\n"); 644219089Spjd ccb->ccb_h.status &= ~CAM_STATUS_MASK; 645219089Spjd ccb->ccb_h.status |= CAM_CMD_TIMEOUT; 646219089Spjd adv_reset_bus(adv); 647219089Spjd } 648219089Spjd adv_start_execution(adv); 649219089Spjd splx(s); 650219089Spjd} 651219089Spjd 652219089Spjdstruct adv_softc * 653219089Spjdadv_alloc(int unit, bus_space_tag_t tag, bus_space_handle_t bsh) 654219089Spjd{ 655219089Spjd struct adv_softc *adv; 656246666Smm 657219089Spjd if (unit >= NADV) { 658219089Spjd printf("adv: unit number (%d) too high\n", unit); 659219089Spjd return NULL; 660219089Spjd } 661219089Spjd 662219089Spjd /* 663219089Spjd * Allocate a storage area for us 664219089Spjd */ 665219089Spjd if (advsoftcs[unit]) { 666219089Spjd printf("adv%d: memory already allocated\n", unit); 667219089Spjd return NULL; 668246666Smm } 669219089Spjd 670219089Spjd adv = malloc(sizeof(struct adv_softc), M_DEVBUF, M_NOWAIT); 671219089Spjd if (!adv) { 672219089Spjd printf("adv%d: cannot malloc!\n", unit); 673219089Spjd return NULL; 674219089Spjd } 675219089Spjd bzero(adv, sizeof(struct adv_softc)); 676219089Spjd LIST_INIT(&adv->pending_ccbs); 677219089Spjd SLIST_INIT(&adv->free_ccb_infos); 678219089Spjd advsoftcs[unit] = adv; 679219089Spjd adv->unit = unit; 680219089Spjd adv->tag = tag; 681219089Spjd adv->bsh = bsh; 682219089Spjd 683219089Spjd return(adv); 684219089Spjd} 685219089Spjd 686219089Spjdvoid 687219089Spjdadv_free(struct adv_softc *adv) 688219089Spjd{ 689219089Spjd switch (adv->init_level) { 690246666Smm case 5: 691219089Spjd { 692219089Spjd struct adv_ccb_info *cinfo; 693219089Spjd 694219089Spjd while ((cinfo = SLIST_FIRST(&adv->free_ccb_infos)) != NULL) { 695219089Spjd SLIST_REMOVE_HEAD(&adv->free_ccb_infos, links); 696219089Spjd adv_destroy_ccb_info(adv, cinfo); 697219089Spjd } 698219089Spjd 699219089Spjd bus_dmamap_unload(adv->sense_dmat, adv->sense_dmamap); 700219089Spjd } 701219089Spjd case 4: 702219089Spjd bus_dmamem_free(adv->sense_dmat, adv->sense_buffers, 703219089Spjd adv->sense_dmamap); 704219089Spjd case 3: 705219089Spjd bus_dma_tag_destroy(adv->sense_dmat); 706219089Spjd case 2: 707219089Spjd bus_dma_tag_destroy(adv->buffer_dmat); 708219089Spjd case 1: 709219089Spjd bus_dma_tag_destroy(adv->parent_dmat); 710219089Spjd case 0: 711219089Spjd break; 712219089Spjd } 713219089Spjd free(adv, M_DEVBUF); 714219089Spjd} 715219089Spjd 716219089Spjdint 717219089Spjdadv_init(struct adv_softc *adv) 718219089Spjd{ 719219089Spjd struct adv_eeprom_config eeprom_config; 720219089Spjd int checksum, i; 721219089Spjd u_int16_t config_lsw; 722219089Spjd u_int16_t config_msw; 723219089Spjd 724219089Spjd adv_reset_chip_and_scsi_bus(adv); 725219089Spjd adv_lib_init(adv); 726219089Spjd 727219089Spjd /* 728219089Spjd * Stop script execution. 729219089Spjd */ 730219089Spjd adv_write_lram_16(adv, ADV_HALTCODE_W, 0x00FE); 731219089Spjd adv_stop_execution(adv); 732219089Spjd if (adv_is_chip_halted(adv) == 0) { 733219089Spjd printf("adv%d: Unable to halt adapter. Initialization" 734219089Spjd "failed\n", adv->unit); 735219089Spjd return (1); 736219089Spjd } 737219089Spjd ADV_OUTW(adv, ADV_REG_PROG_COUNTER, ADV_MCODE_START_ADDR); 738219089Spjd if (ADV_INW(adv, ADV_REG_PROG_COUNTER) != ADV_MCODE_START_ADDR) { 739219089Spjd printf("adv%d: Unable to set program counter. Initialization" 740219089Spjd "failed\n", adv->unit); 741219089Spjd return (1); 742219089Spjd } 743219089Spjd 744219089Spjd config_msw = ADV_INW(adv, ADV_CONFIG_MSW); 745219089Spjd config_lsw = ADV_INW(adv, ADV_CONFIG_LSW); 746219089Spjd 747219089Spjd if ((config_msw & ADV_CFG_MSW_CLR_MASK) != 0) { 748219089Spjd config_msw &= (~(ADV_CFG_MSW_CLR_MASK)); 749219089Spjd /* 750219089Spjd * XXX The Linux code flags this as an error, 751219089Spjd * but what should we report to the user??? 752219089Spjd * It seems that clearing the config register 753219089Spjd * makes this error recoverable. 754219089Spjd */ 755219089Spjd ADV_OUTW(adv, ADV_CONFIG_MSW, config_msw); 756219089Spjd } 757219089Spjd 758219089Spjd /* Suck in the configuration from the EEProm */ 759219089Spjd checksum = adv_get_eeprom_config(adv, &eeprom_config); 760219089Spjd 761219089Spjd eeprom_config.cfg_msw &= (~(ADV_CFG_MSW_CLR_MASK)); 762219089Spjd 763219089Spjd if (ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_AUTO_CONFIG) { 764219089Spjd /* 765219089Spjd * XXX The Linux code sets a warning level for this 766219089Spjd * condition, yet nothing of meaning is printed to 767219089Spjd * the user. What does this mean??? 768219089Spjd */ 769219089Spjd if (adv->chip_version == 3) { 770219089Spjd if (eeprom_config.cfg_lsw != config_lsw) { 771219089Spjd eeprom_config.cfg_lsw = 772219089Spjd ADV_INW(adv, ADV_CONFIG_LSW); 773219089Spjd } 774219089Spjd if (eeprom_config.cfg_msw != config_msw) { 775219089Spjd eeprom_config.cfg_msw = 776219089Spjd ADV_INW(adv, ADV_CONFIG_MSW); 777219089Spjd } 778219089Spjd } 779219089Spjd } 780219089Spjd eeprom_config.cfg_lsw |= ADV_CFG_LSW_HOST_INT_ON; 781219089Spjd if (adv_test_external_lram(adv) == 0) { 782219089Spjd /* 783219089Spjd * XXX What about non PCI cards with no 784219089Spjd * external LRAM???? 785219089Spjd */ 786219089Spjd if ((adv->type & (ADV_PCI|ADV_ULTRA)) == (ADV_PCI|ADV_ULTRA)) { 787219089Spjd eeprom_config.max_total_qng = 788219089Spjd ADV_MAX_PCI_ULTRA_INRAM_TOTAL_QNG; 789219089Spjd eeprom_config.max_tag_qng = 790219089Spjd ADV_MAX_PCI_ULTRA_INRAM_TAG_QNG; 791219089Spjd } else { 792219089Spjd eeprom_config.cfg_msw |= 0x0800; 793219089Spjd config_msw |= 0x0800; 794219089Spjd ADV_OUTW(adv, ADV_CONFIG_MSW, config_msw); 795219089Spjd eeprom_config.max_total_qng = 796219089Spjd ADV_MAX_PCI_INRAM_TOTAL_QNG; 797219089Spjd eeprom_config.max_tag_qng = ADV_MAX_INRAM_TAG_QNG; 798219089Spjd } 799219089Spjd adv->max_openings = eeprom_config.max_total_qng; 800219089Spjd } 801219089Spjd if (checksum == eeprom_config.chksum) { 802219089Spjd /* Range/Sanity checking */ 803219089Spjd if (eeprom_config.max_total_qng < ADV_MIN_TOTAL_QNG) { 804254112Sdelphij eeprom_config.max_total_qng = ADV_MIN_TOTAL_QNG; 805219089Spjd } 806219089Spjd if (eeprom_config.max_total_qng > ADV_MAX_TOTAL_QNG) { 807219089Spjd eeprom_config.max_total_qng = ADV_MAX_TOTAL_QNG; 808219089Spjd } 809219089Spjd if (eeprom_config.max_tag_qng > eeprom_config.max_total_qng) { 810219089Spjd eeprom_config.max_tag_qng = eeprom_config.max_total_qng; 811219089Spjd } 812219089Spjd if (eeprom_config.max_tag_qng < ADV_MIN_TAG_Q_PER_DVC) { 813219089Spjd eeprom_config.max_tag_qng = ADV_MIN_TAG_Q_PER_DVC; 814219089Spjd } 815219089Spjd adv->max_openings = eeprom_config.max_total_qng; 816219089Spjd 817219089Spjd adv->user_disc_enable = eeprom_config.disc_enable; 818219089Spjd adv->user_cmd_qng_enabled = eeprom_config.use_cmd_qng; 819219089Spjd adv->isa_dma_speed = EEPROM_DMA_SPEED(eeprom_config); 820219089Spjd adv->scsi_id = EEPROM_SCSIID(eeprom_config) & ADV_MAX_TID; 821219089Spjd EEPROM_SET_SCSIID(eeprom_config, adv->scsi_id); 822219089Spjd adv->control = eeprom_config.cntl; 823219089Spjd for (i = 0; i <= ADV_MAX_TID; i++) 824219089Spjd adv_sdtr_to_period_offset(adv, 825219089Spjd eeprom_config.sdtr_data[i], 826219089Spjd &adv->tinfo[i].user.period, 827219089Spjd &adv->tinfo[i].user.offset, 828219089Spjd i); 829219089Spjd } else { 830219089Spjd u_int8_t sync_data; 831219089Spjd 832219089Spjd printf("adv%d: Warning EEPROM Checksum mismatch. " 833219089Spjd "Using default device parameters\n", adv->unit); 834219089Spjd 835219089Spjd /* Set reasonable defaults since we can't read the EEPROM */ 836219089Spjd adv->isa_dma_speed = /*ADV_DEF_ISA_DMA_SPEED*/1; 837219089Spjd adv->max_openings = ADV_DEF_MAX_TOTAL_QNG; 838219089Spjd adv->disc_enable = TARGET_BIT_VECTOR_SET; 839219089Spjd adv->user_disc_enable = TARGET_BIT_VECTOR_SET; 840219089Spjd adv->cmd_qng_enabled = TARGET_BIT_VECTOR_SET; 841219089Spjd adv->user_cmd_qng_enabled = TARGET_BIT_VECTOR_SET; 842219089Spjd adv->scsi_id = 7; 843219089Spjd 844219089Spjd sync_data = ADV_DEF_SDTR_OFFSET | (ADV_DEF_SDTR_INDEX << 4); 845219089Spjd for (i = 0; i <= ADV_MAX_TID; i++) 846219089Spjd adv_sdtr_to_period_offset(adv, sync_data, 847219089Spjd &adv->tinfo[i].user.period, 848219089Spjd &adv->tinfo[i].user.offset, 849219089Spjd i); 850219089Spjd } 851219089Spjd 852219089Spjd if (adv_set_eeprom_config(adv, &eeprom_config) != 0) 853219089Spjd printf("%s: WARNING! Failure writing to EEPROM.\n", 854219089Spjd adv_name(adv)); 855219089Spjd 856219089Spjd adv_set_chip_scsiid(adv, adv->scsi_id); 857219089Spjd if (adv_init_lram_and_mcode(adv)) 858219089Spjd return (1); 859219089Spjd 860219089Spjd adv->disc_enable = adv->user_disc_enable; 861219089Spjd 862219089Spjd adv_write_lram_8(adv, ADVV_DISC_ENABLE_B, adv->disc_enable); 863219089Spjd for (i = 0; i <= ADV_MAX_TID; i++) { 864219089Spjd /* 865219089Spjd * Start off in async mode. 866219089Spjd */ 867219089Spjd adv_set_syncrate(adv, /*struct cam_path */NULL, 868219089Spjd i, /*period*/0, /*offset*/0, 869219089Spjd ADV_TRANS_CUR); 870219089Spjd /* 871219089Spjd * Enable the use of tagged commands on all targets. 872219089Spjd * This allows the kernel driver to make up it's own mind 873219089Spjd * as it sees fit to tag queue instead of having the 874219089Spjd * firmware try and second guess the tag_code settins. 875219089Spjd */ 876219089Spjd adv_write_lram_8(adv, ADVV_MAX_DVC_QNG_BEG + i, 877219089Spjd adv->max_openings); 878219089Spjd } 879219089Spjd adv_write_lram_8(adv, ADVV_USE_TAGGED_QNG_B, TARGET_BIT_VECTOR_SET); 880219089Spjd adv_write_lram_8(adv, ADVV_CAN_TAGGED_QNG_B, TARGET_BIT_VECTOR_SET); 881219089Spjd printf("adv%d: AdvanSys %s Host Adapter, SCSI ID %d, queue depth %d\n", 882219089Spjd adv->unit, (adv->type & ADV_ULTRA) ? "Ultra SCSI" : "SCSI", 883219089Spjd adv->scsi_id, adv->max_openings); 884219089Spjd return (0); 885219089Spjd} 886219089Spjd 887219089Spjdvoid 888219089Spjdadv_intr(void *arg) 889219089Spjd{ 890219089Spjd struct adv_softc *adv; 891219089Spjd u_int16_t chipstat; 892219089Spjd u_int16_t saved_ram_addr; 893219089Spjd u_int8_t ctrl_reg; 894219089Spjd u_int8_t saved_ctrl_reg; 895219089Spjd u_int8_t host_flag; 896219089Spjd 897219089Spjd adv = (struct adv_softc *)arg; 898219089Spjd 899219089Spjd ctrl_reg = ADV_INB(adv, ADV_CHIP_CTRL); 900219089Spjd saved_ctrl_reg = ctrl_reg & (~(ADV_CC_SCSI_RESET | ADV_CC_CHIP_RESET | 901219089Spjd ADV_CC_SINGLE_STEP | ADV_CC_DIAG | 902219089Spjd ADV_CC_TEST)); 903219089Spjd 904219089Spjd 905219089Spjd if ((chipstat = ADV_INW(adv, ADV_CHIP_STATUS)) & ADV_CSW_INT_PENDING) { 906219089Spjd 907219089Spjd saved_ram_addr = ADV_INW(adv, ADV_LRAM_ADDR); 908219089Spjd host_flag = adv_read_lram_8(adv, ADVV_HOST_FLAG_B); 909219089Spjd adv_write_lram_8(adv, ADVV_HOST_FLAG_B, 910219089Spjd host_flag | ADV_HOST_FLAG_IN_ISR); 911219089Spjd 912219089Spjd adv_ack_interrupt(adv); 913219089Spjd 914219089Spjd if ((chipstat & ADV_CSW_HALTED) 915219089Spjd && (ctrl_reg & ADV_CC_SINGLE_STEP)) { 916219089Spjd adv_isr_chip_halted(adv); 917219089Spjd saved_ctrl_reg &= ~ADV_CC_HALT; 918219089Spjd } else { 919219089Spjd adv_run_doneq(adv); 920219089Spjd } 921219089Spjd ADV_OUTW(adv, ADV_LRAM_ADDR, saved_ram_addr); 922219089Spjd#ifdef DIAGNOSTIC 923219089Spjd if (ADV_INW(adv, ADV_LRAM_ADDR) != saved_ram_addr) 924219089Spjd panic("adv_intr: Unable to set LRAM addr"); 925219089Spjd#endif 926219089Spjd adv_write_lram_8(adv, ADVV_HOST_FLAG_B, host_flag); 927219089Spjd } 928219089Spjd 929219089Spjd ADV_OUTB(adv, ADV_CHIP_CTRL, saved_ctrl_reg); 930219089Spjd} 931219089Spjd 932219089Spjdvoid 933219089Spjdadv_run_doneq(struct adv_softc *adv) 934219089Spjd{ 935219089Spjd struct adv_q_done_info scsiq; 936219089Spjd u_int doneq_head; 937219089Spjd u_int done_qno; 938219089Spjd 939219089Spjd doneq_head = adv_read_lram_16(adv, ADVV_DONE_Q_TAIL_W) & 0xFF; 940219089Spjd done_qno = adv_read_lram_8(adv, ADV_QNO_TO_QADDR(doneq_head) 941219089Spjd + ADV_SCSIQ_B_FWD); 942219089Spjd while (done_qno != ADV_QLINK_END) { 943219089Spjd union ccb* ccb; 944219089Spjd u_int done_qaddr; 945219089Spjd u_int sg_queue_cnt; 946219089Spjd int aborted; 947219089Spjd 948219089Spjd done_qaddr = ADV_QNO_TO_QADDR(done_qno); 949219089Spjd 950219089Spjd /* Pull status from this request */ 951219089Spjd sg_queue_cnt = adv_copy_lram_doneq(adv, done_qaddr, &scsiq, 952219089Spjd adv->max_dma_count); 953219089Spjd 954219089Spjd /* Mark it as free */ 955219089Spjd adv_write_lram_8(adv, done_qaddr + ADV_SCSIQ_B_STATUS, 956219089Spjd scsiq.q_status & ~(QS_READY|QS_ABORTED)); 957219089Spjd 958219089Spjd /* Process request based on retrieved info */ 959219089Spjd if ((scsiq.cntl & QC_SG_HEAD) != 0) { 960219089Spjd u_int i; 961219089Spjd 962219089Spjd /* 963219089Spjd * S/G based request. Free all of the queue 964219089Spjd * structures that contained S/G information. 965219089Spjd */ 966219089Spjd for (i = 0; i < sg_queue_cnt; i++) { 967219089Spjd done_qno = adv_read_lram_8(adv, done_qaddr 968219089Spjd + ADV_SCSIQ_B_FWD); 969219089Spjd 970219089Spjd#ifdef DIAGNOSTIC 971219089Spjd if (done_qno == ADV_QLINK_END) { 972219089Spjd panic("adv_qdone: Corrupted SG " 973219089Spjd "list encountered"); 974219089Spjd } 975219089Spjd#endif 976219089Spjd done_qaddr = ADV_QNO_TO_QADDR(done_qno); 977219089Spjd 978219089Spjd /* Mark SG queue as free */ 979219089Spjd adv_write_lram_8(adv, done_qaddr 980219089Spjd + ADV_SCSIQ_B_STATUS, QS_FREE); 981219089Spjd } 982219089Spjd } else 983219089Spjd sg_queue_cnt = 0; 984219089Spjd#ifdef DIAGNOSTIC 985219089Spjd if (adv->cur_active < (sg_queue_cnt + 1)) 986219089Spjd panic("adv_qdone: Attempting to free more " 987219089Spjd "queues than are active"); 988219089Spjd#endif 989248571Smm adv->cur_active -= sg_queue_cnt + 1; 990219089Spjd 991219089Spjd aborted = (scsiq.q_status & QS_ABORTED) != 0; 992219089Spjd 993219089Spjd if ((scsiq.q_status != QS_DONE) 994219089Spjd && (scsiq.q_status & QS_ABORTED) == 0) 995219089Spjd panic("adv_qdone: completed scsiq with unknown status"); 996248571Smm 997248571Smm scsiq.remain_bytes += scsiq.extra_bytes; 998248571Smm 999248571Smm if ((scsiq.d3.done_stat == QD_WITH_ERROR) && 1000219089Spjd (scsiq.d3.host_stat == QHSTA_M_DATA_OVER_RUN)) { 1001219089Spjd if ((scsiq.cntl & (QC_DATA_IN|QC_DATA_OUT)) == 0) { 1002219089Spjd scsiq.d3.done_stat = QD_NO_ERROR; 1003248571Smm scsiq.d3.host_stat = QHSTA_NO_ERROR; 1004248571Smm } 1005248571Smm } 1006248571Smm 1007219089Spjd ccb = (union ccb *)scsiq.d2.ccb_ptr; 1008248571Smm ccb->csio.resid = scsiq.remain_bytes; 1009248571Smm adv_done(adv, (union ccb *)scsiq.d2.ccb_ptr, 1010248571Smm scsiq.d3.done_stat, scsiq.d3.host_stat, 1011248571Smm scsiq.d3.scsi_stat, scsiq.q_no); 1012219089Spjd 1013248571Smm doneq_head = done_qno; 1014248571Smm done_qno = adv_read_lram_8(adv, done_qaddr + ADV_SCSIQ_B_FWD); 1015248571Smm } 1016219089Spjd adv_write_lram_16(adv, ADVV_DONE_Q_TAIL_W, doneq_head); 1017219089Spjd} 1018219089Spjd 1019219089Spjd 1020219089Spjdvoid 1021219089Spjdadv_done(struct adv_softc *adv, union ccb *ccb, u_int done_stat, 1022219089Spjd u_int host_stat, u_int scsi_status, u_int q_no) 1023219089Spjd{ 1024219089Spjd struct adv_ccb_info *cinfo; 1025219089Spjd 1026219089Spjd cinfo = (struct adv_ccb_info *)ccb->ccb_h.ccb_cinfo_ptr; 1027219089Spjd /* 1028219089Spjd * Null this out so that we catch driver bugs that cause a 1029219089Spjd * ccb to be completed twice. 1030219089Spjd */ 1031219089Spjd ccb->ccb_h.ccb_cinfo_ptr = NULL; 1032219089Spjd 1033219089Spjd LIST_REMOVE(&ccb->ccb_h, sim_links.le); 1034219089Spjd untimeout(adv_timeout, ccb, ccb->ccb_h.timeout_ch); 1035219089Spjd if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 1036219089Spjd bus_dmasync_op_t op; 1037219089Spjd 1038219089Spjd if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 1039219089Spjd op = BUS_DMASYNC_POSTREAD; 1040219089Spjd else 1041219089Spjd op = BUS_DMASYNC_POSTWRITE; 1042219089Spjd bus_dmamap_sync(adv->buffer_dmat, cinfo->dmamap, op); 1043219089Spjd bus_dmamap_unload(adv->buffer_dmat, cinfo->dmamap); 1044219089Spjd } 1045219089Spjd 1046219089Spjd switch (done_stat) { 1047219089Spjd case QD_NO_ERROR: 1048219089Spjd if (host_stat == QHSTA_NO_ERROR) { 1049219089Spjd ccb->ccb_h.status = CAM_REQ_CMP; 1050219089Spjd break; 1051219089Spjd } 1052219089Spjd xpt_print_path(ccb->ccb_h.path); 1053219089Spjd printf("adv_done - queue done without error, " 1054219089Spjd "but host status non-zero(%x)\n", host_stat); 1055219089Spjd /*FALLTHROUGH*/ 1056219089Spjd case QD_WITH_ERROR: 1057219089Spjd switch (host_stat) { 1058219089Spjd case QHSTA_M_TARGET_STATUS_BUSY: 1059219089Spjd case QHSTA_M_BAD_QUEUE_FULL_OR_BUSY: 1060219089Spjd /* 1061219089Spjd * Assume that if we were a tagged transaction 1062219089Spjd * the target reported queue full. Otherwise, 1063219089Spjd * report busy. The firmware really should just 1064219089Spjd * pass the original status back up to us even 1065219089Spjd * if it thinks the target was in error for 1066219089Spjd * returning this status as no other transactions 1067219089Spjd * from this initiator are in effect, but this 1068219089Spjd * ignores multi-initiator setups and there is 1069219089Spjd * evidence that the firmware gets its per-device 1070219089Spjd * transaction counts screwed up occassionally. 1071219089Spjd */ 1072219089Spjd ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR; 1073219089Spjd if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0 1074219089Spjd && host_stat != QHSTA_M_TARGET_STATUS_BUSY) 1075219089Spjd scsi_status = SCSI_STATUS_QUEUE_FULL; 1076219089Spjd else 1077219089Spjd scsi_status = SCSI_STATUS_BUSY; 1078219089Spjd adv_abort_ccb(adv, ccb->ccb_h.target_id, 1079219089Spjd ccb->ccb_h.target_lun, 1080219089Spjd /*ccb*/NULL, CAM_REQUEUE_REQ, 1081219089Spjd /*queued_only*/TRUE); 1082219089Spjd /*FALLTHROUGH*/ 1083219089Spjd case QHSTA_M_NO_AUTO_REQ_SENSE: 1084219089Spjd case QHSTA_NO_ERROR: 1085219089Spjd ccb->csio.scsi_status = scsi_status; 1086219089Spjd switch (scsi_status) { 1087219089Spjd case SCSI_STATUS_CHECK_COND: 1088219089Spjd case SCSI_STATUS_CMD_TERMINATED: 1089219089Spjd ccb->ccb_h.status |= CAM_AUTOSNS_VALID; 1090219089Spjd /* Structure copy */ 1091219089Spjd ccb->csio.sense_data = 1092219089Spjd adv->sense_buffers[q_no - 1]; 1093219089Spjd /* FALLTHROUGH */ 1094219089Spjd case SCSI_STATUS_BUSY: 1095219089Spjd case SCSI_STATUS_RESERV_CONFLICT: 1096219089Spjd case SCSI_STATUS_QUEUE_FULL: 1097219089Spjd case SCSI_STATUS_COND_MET: 1098219089Spjd case SCSI_STATUS_INTERMED: 1099219089Spjd case SCSI_STATUS_INTERMED_COND_MET: 1100219089Spjd ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR; 1101219089Spjd break; 1102219089Spjd case SCSI_STATUS_OK: 1103219089Spjd ccb->ccb_h.status |= CAM_REQ_CMP; 1104248571Smm break; 1105219089Spjd } 1106219089Spjd break; 1107248571Smm case QHSTA_M_SEL_TIMEOUT: 1108219089Spjd ccb->ccb_h.status = CAM_SEL_TIMEOUT; 1109219089Spjd break; 1110219089Spjd case QHSTA_M_DATA_OVER_RUN: 1111219089Spjd ccb->ccb_h.status = CAM_DATA_RUN_ERR; 1112219089Spjd break; 1113248571Smm case QHSTA_M_UNEXPECTED_BUS_FREE: 1114248571Smm ccb->ccb_h.status = CAM_UNEXP_BUSFREE; 1115219089Spjd break; 1116219089Spjd case QHSTA_M_BAD_BUS_PHASE_SEQ: 1117219089Spjd ccb->ccb_h.status = CAM_SEQUENCE_FAIL; 1118219089Spjd break; 1119219089Spjd case QHSTA_M_BAD_CMPL_STATUS_IN: 1120219089Spjd /* No command complete after a status message */ 1121219089Spjd ccb->ccb_h.status = CAM_SEQUENCE_FAIL; 1122219089Spjd break; 1123219089Spjd case QHSTA_D_EXE_SCSI_Q_BUSY_TIMEOUT: 1124248571Smm case QHSTA_M_WTM_TIMEOUT: 1125219089Spjd case QHSTA_M_HUNG_REQ_SCSI_BUS_RESET: 1126219089Spjd /* The SCSI bus hung in a phase */ 1127219089Spjd ccb->ccb_h.status = CAM_SEQUENCE_FAIL; 1128219089Spjd adv_reset_bus(adv); 1129219089Spjd break; 1130219089Spjd case QHSTA_D_QDONE_SG_LIST_CORRUPTED: 1131248571Smm case QHSTA_D_ASC_DVC_ERROR_CODE_SET: 1132219089Spjd case QHSTA_D_HOST_ABORT_FAILED: 1133219089Spjd case QHSTA_D_EXE_SCSI_Q_FAILED: 1134219089Spjd case QHSTA_D_ASPI_NO_BUF_POOL: 1135219089Spjd case QHSTA_M_AUTO_REQ_SENSE_FAIL: 1136219089Spjd case QHSTA_M_BAD_TAG_CODE: 1137219089Spjd case QHSTA_D_LRAM_CMP_ERROR: 1138219089Spjd case QHSTA_M_MICRO_CODE_ERROR_HALT: 1139219089Spjd default: 1140219089Spjd panic("%s: Unhandled Host status error %x", 1141219089Spjd adv_name(adv), host_stat); 1142219089Spjd /* NOTREACHED */ 1143219089Spjd } 1144219089Spjd break; 1145219089Spjd 1146219089Spjd case QD_ABORTED_BY_HOST: 1147219089Spjd /* Don't clobber any, more explicit, error codes we've set */ 1148219089Spjd if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) 1149219089Spjd ccb->ccb_h.status = CAM_REQ_ABORTED; 1150219089Spjd break; 1151219089Spjd 1152219089Spjd default: 1153219089Spjd xpt_print_path(ccb->ccb_h.path); 1154219089Spjd printf("adv_done - queue done with unknown status %x:%x\n", 1155219089Spjd done_stat, host_stat); 1156219089Spjd ccb->ccb_h.status = CAM_REQ_CMP_ERR; 1157219089Spjd break; 1158219089Spjd } 1159219089Spjd if ((cinfo->state & ACCB_RELEASE_SIMQ) != 0) 1160219089Spjd ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 1161219089Spjd else if (adv->openings_needed > 0) { 1162219089Spjd int openings; 1163219089Spjd 1164219089Spjd openings = adv->max_openings - adv->cur_active - ADV_MIN_FREE_Q; 1165219089Spjd if (openings >= adv->openings_needed) { 1166219089Spjd ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 1167219089Spjd adv->openings_needed = 0; 1168219089Spjd } 1169219089Spjd } 1170219089Spjd if ((cinfo->state & ACCB_RECOVERY_CCB) != 0) { 1171219089Spjd /* 1172219089Spjd * We now traverse our list of pending CCBs and reinstate 1173219089Spjd * their timeouts. 1174219089Spjd */ 1175219089Spjd struct ccb_hdr *ccb_h; 1176219089Spjd 1177219089Spjd ccb_h = LIST_FIRST(&adv->pending_ccbs); 1178219089Spjd while (ccb_h != NULL) { 1179219089Spjd ccb_h->timeout_ch = 1180219089Spjd timeout(adv_timeout, (caddr_t)ccb_h, 1181219089Spjd (ccb_h->timeout * hz) / 1000); 1182219089Spjd ccb_h = LIST_NEXT(ccb_h, sim_links.le); 1183219089Spjd } 1184219089Spjd printf("%s: No longer in timeout\n", adv_name(adv)); 1185219089Spjd } 1186219089Spjd if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP 1187219089Spjd && (ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { 1188219089Spjd xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 1189219089Spjd ccb->ccb_h.status |= CAM_DEV_QFRZN; 1190219089Spjd } 1191219089Spjd adv_free_ccb_info(adv, cinfo); 1192219089Spjd ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 1193219089Spjd xpt_done(ccb); 1194219089Spjd} 1195219089Spjd 1196219089Spjd/* 1197219089Spjd * Function to poll for command completion when 1198219089Spjd * interrupts are disabled (crash dumps) 1199219089Spjd */ 1200219089Spjdstatic void 1201219089Spjdadv_poll(struct cam_sim *sim) 1202219089Spjd{ 1203219089Spjd adv_intr(cam_sim_softc(sim)); 1204219089Spjd} 1205219089Spjd 1206219089Spjd/* 1207219089Spjd * Attach all the sub-devices we can find 1208219089Spjd */ 1209219089Spjdint 1210219089Spjdadv_attach(adv) 1211219089Spjd struct adv_softc *adv; 1212219089Spjd{ 1213219089Spjd struct ccb_setasync csa; 1214219089Spjd struct cam_devq *devq; 1215219089Spjd 1216219089Spjd /* 1217219089Spjd * Create our DMA tags. These tags define the kinds of device 1218219089Spjd * accessable memory allocations and memory mappings we will 1219219089Spjd * need to perform during normal operation. 1220219089Spjd * 1221219089Spjd * Unless we need to further restrict the allocation, we rely 1222219089Spjd * on the restrictions of the parent dmat, hence the common 1223219089Spjd * use of MAXADDR and MAXSIZE. 1224219089Spjd */ 1225219089Spjd 1226219089Spjd /* DMA tag for mapping buffers into device visible space. */ 1227219089Spjd if (bus_dma_tag_create(adv->parent_dmat, /*alignment*/0, /*boundary*/0, 1228219089Spjd /*lowaddr*/BUS_SPACE_MAXADDR, 1229219089Spjd /*highaddr*/BUS_SPACE_MAXADDR, 1230219089Spjd /*filter*/NULL, /*filterarg*/NULL, 1231219089Spjd /*maxsize*/MAXBSIZE, 1232219089Spjd /*nsegments*/ADV_MAX_SG_LIST, 1233219089Spjd /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, 1234219089Spjd /*flags*/BUS_DMA_ALLOCNOW, 1235219089Spjd &adv->buffer_dmat) != 0) { 1236219089Spjd goto error_exit; 1237219089Spjd } 1238219089Spjd adv->init_level++; 1239219089Spjd 1240219089Spjd /* DMA tag for our sense buffers */ 1241219089Spjd if (bus_dma_tag_create(adv->parent_dmat, /*alignment*/0, /*boundary*/0, 1242219089Spjd /*lowaddr*/BUS_SPACE_MAXADDR, 1243219089Spjd /*highaddr*/BUS_SPACE_MAXADDR, 1244219089Spjd /*filter*/NULL, /*filterarg*/NULL, 1245219089Spjd sizeof(struct scsi_sense_data)*adv->max_openings, 1246219089Spjd /*nsegments*/1, 1247219089Spjd /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, 1248219089Spjd /*flags*/0, &adv->sense_dmat) != 0) { 1249254112Sdelphij goto error_exit; 1250219089Spjd } 1251219089Spjd 1252219089Spjd adv->init_level++; 1253219089Spjd 1254219089Spjd /* Allocation for our sense buffers */ 1255219089Spjd if (bus_dmamem_alloc(adv->sense_dmat, (void **)&adv->sense_buffers, 1256219089Spjd BUS_DMA_NOWAIT, &adv->sense_dmamap) != 0) { 1257219089Spjd goto error_exit; 1258219089Spjd } 1259219089Spjd 1260219089Spjd adv->init_level++; 1261219089Spjd 1262219089Spjd /* And permanently map them */ 1263219089Spjd bus_dmamap_load(adv->sense_dmat, adv->sense_dmamap, 1264219089Spjd adv->sense_buffers, 1265219089Spjd sizeof(struct scsi_sense_data)*adv->max_openings, 1266219089Spjd adv_map, &adv->sense_physbase, /*flags*/0); 1267219089Spjd 1268219089Spjd adv->init_level++; 1269219089Spjd 1270219089Spjd /* 1271219089Spjd * Fire up the chip 1272219089Spjd */ 1273219089Spjd if (adv_start_chip(adv) != 1) { 1274219089Spjd printf("adv%d: Unable to start on board processor. Aborting.\n", 1275219089Spjd adv->unit); 1276219089Spjd return (0); 1277219089Spjd } 1278219089Spjd 1279219089Spjd /* 1280219089Spjd * Create the device queue for our SIM. 1281219089Spjd */ 1282219089Spjd devq = cam_simq_alloc(adv->max_openings); 1283219089Spjd if (devq == NULL) 1284219089Spjd return (0); 1285219089Spjd 1286248571Smm /* 1287248571Smm * Construct our SIM entry. 1288219089Spjd */ 1289219089Spjd adv->sim = cam_sim_alloc(adv_action, adv_poll, "adv", adv, adv->unit, 1290219089Spjd 1, adv->max_openings, devq); 1291219089Spjd if (adv->sim == NULL) 1292219089Spjd return (0); 1293219089Spjd 1294219089Spjd /* 1295219089Spjd * Register the bus. 1296219089Spjd * 1297219089Spjd * XXX Twin Channel EISA Cards??? 1298219089Spjd */ 1299219089Spjd if (xpt_bus_register(adv->sim, 0) != CAM_SUCCESS) { 1300219089Spjd cam_sim_free(adv->sim, /*free devq*/TRUE); 1301219089Spjd return (0); 1302219089Spjd } 1303219089Spjd 1304219089Spjd if (xpt_create_path(&adv->path, /*periph*/NULL, cam_sim_path(adv->sim), 1305219089Spjd CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) 1306219089Spjd == CAM_REQ_CMP) { 1307219089Spjd xpt_setup_ccb(&csa.ccb_h, adv->path, /*priority*/5); 1308219089Spjd csa.ccb_h.func_code = XPT_SASYNC_CB; 1309219089Spjd csa.event_enable = AC_FOUND_DEVICE|AC_LOST_DEVICE; 1310219089Spjd csa.callback = advasync; 1311219089Spjd csa.callback_arg = adv; 1312219089Spjd xpt_action((union ccb *)&csa); 1313219089Spjd } 1314219089Spjd return (1); 1315219089Spjd 1316219089Spjderror_exit: 1317219089Spjd return (0); 1318219089Spjd} 1319219089Spjd