advansys.c revision 115343
1165138Syongari/* 2165138Syongari * Generic driver for the Advanced Systems Inc. SCSI controllers 3165138Syongari * Product specific probe and attach routines can be found in: 4165138Syongari * 5165138Syongari * i386/isa/adv_isa.c ABP5140, ABP542, ABP5150, ABP842, ABP852 6165138Syongari * i386/eisa/adv_eisa.c ABP742, ABP752 7165138Syongari * pci/adv_pci.c ABP920, ABP930, ABP930U, ABP930UA, ABP940, ABP940U, 8165138Syongari * ABP940UA, ABP950, ABP960, ABP960U, ABP960UA, 9165138Syongari * ABP970, ABP970U 10165138Syongari * 11165138Syongari * Copyright (c) 1996-2000 Justin Gibbs. 12165138Syongari * All rights reserved. 13165138Syongari * 14165138Syongari * Redistribution and use in source and binary forms, with or without 15165138Syongari * modification, are permitted provided that the following conditions 16165138Syongari * are met: 17165138Syongari * 1. Redistributions of source code must retain the above copyright 18165138Syongari * notice, this list of conditions, and the following disclaimer, 19165138Syongari * without modification, immediately at the beginning of the file. 20165138Syongari * 2. The name of the author may not be used to endorse or promote products 21165138Syongari * derived from this software without specific prior written permission. 22165138Syongari * 23165138Syongari * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24165138Syongari * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25165138Syongari * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26165138Syongari * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 27165138Syongari * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28165138Syongari * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29165138Syongari * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30165138Syongari * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31165138Syongari * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32165138Syongari * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33165138Syongari * SUCH DAMAGE. 34165138Syongari * 35165138Syongari * $FreeBSD: head/sys/dev/advansys/advansys.c 115343 2003-05-27 04:59:59Z scottl $ 36165138Syongari */ 37165138Syongari/* 38165138Syongari * Ported from: 39165138Syongari * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters 40165138Syongari * 41165138Syongari * Copyright (c) 1995-1997 Advanced System Products, Inc. 42165138Syongari * All Rights Reserved. 43165138Syongari * 44165138Syongari * Redistribution and use in source and binary forms, with or without 45165138Syongari * modification, are permitted provided that redistributions of source 46165138Syongari * code retain the above copyright notice and this comment without 47165138Syongari * modification. 48165138Syongari */ 49165138Syongari 50165138Syongari#include <sys/param.h> 51165138Syongari#include <sys/systm.h> 52165138Syongari#include <sys/malloc.h> 53165138Syongari#include <sys/kernel.h> 54165138Syongari 55165138Syongari#include <machine/bus_pio.h> 56165138Syongari#include <machine/bus.h> 57165138Syongari#include <machine/resource.h> 58165138Syongari#include <sys/bus.h> 59165138Syongari#include <sys/rman.h> 60165138Syongari 61165138Syongari#include <cam/cam.h> 62165138Syongari#include <cam/cam_ccb.h> 63165138Syongari#include <cam/cam_sim.h> 64165138Syongari#include <cam/cam_xpt_sim.h> 65165138Syongari#include <cam/cam_xpt_periph.h> 66165138Syongari#include <cam/cam_debug.h> 67165138Syongari 68165138Syongari#include <cam/scsi/scsi_all.h> 69165138Syongari#include <cam/scsi/scsi_message.h> 70165138Syongari 71165138Syongari#include <vm/vm.h> 72165138Syongari#include <vm/vm_param.h> 73165138Syongari#include <vm/pmap.h> 74165138Syongari 75165138Syongari#include <dev/advansys/advansys.h> 76165138Syongari 77165138Syongaristatic void adv_action(struct cam_sim *sim, union ccb *ccb); 78165138Syongaristatic void adv_execute_ccb(void *arg, bus_dma_segment_t *dm_segs, 79165138Syongari int nsegments, int error); 80165138Syongaristatic void adv_poll(struct cam_sim *sim); 81165138Syongaristatic void adv_run_doneq(struct adv_softc *adv); 82165138Syongaristatic struct adv_ccb_info * 83165138Syongari adv_alloc_ccb_info(struct adv_softc *adv); 84165138Syongaristatic void adv_destroy_ccb_info(struct adv_softc *adv, 85165138Syongari struct adv_ccb_info *cinfo); 86165138Syongaristatic __inline struct adv_ccb_info * 87165138Syongari adv_get_ccb_info(struct adv_softc *adv); 88165138Syongaristatic __inline void adv_free_ccb_info(struct adv_softc *adv, 89165138Syongari struct adv_ccb_info *cinfo); 90165138Syongaristatic __inline void adv_set_state(struct adv_softc *adv, adv_state state); 91165138Syongaristatic __inline void adv_clear_state(struct adv_softc *adv, union ccb* ccb); 92165138Syongaristatic void adv_clear_state_really(struct adv_softc *adv, union ccb* ccb); 93165138Syongari 94165138Syongaristatic __inline struct adv_ccb_info * 95165138Syongariadv_get_ccb_info(struct adv_softc *adv) 96165138Syongari{ 97165138Syongari struct adv_ccb_info *cinfo; 98165138Syongari int opri; 99165138Syongari 100165138Syongari opri = splcam(); 101165138Syongari if ((cinfo = SLIST_FIRST(&adv->free_ccb_infos)) != NULL) { 102165138Syongari SLIST_REMOVE_HEAD(&adv->free_ccb_infos, links); 103165138Syongari } else { 104165138Syongari cinfo = adv_alloc_ccb_info(adv); 105165138Syongari } 106165138Syongari splx(opri); 107165138Syongari 108165138Syongari return (cinfo); 109165138Syongari} 110165138Syongari 111165138Syongaristatic __inline void 112165138Syongariadv_free_ccb_info(struct adv_softc *adv, struct adv_ccb_info *cinfo) 113165138Syongari{ 114165138Syongari int opri; 115165138Syongari 116165138Syongari opri = splcam(); 117165138Syongari cinfo->state = ACCB_FREE; 118165138Syongari SLIST_INSERT_HEAD(&adv->free_ccb_infos, cinfo, links); 119165138Syongari splx(opri); 120165138Syongari} 121165138Syongari 122165138Syongaristatic __inline void 123165138Syongariadv_set_state(struct adv_softc *adv, adv_state state) 124165138Syongari{ 125165138Syongari if (adv->state == 0) 126165138Syongari xpt_freeze_simq(adv->sim, /*count*/1); 127165138Syongari adv->state |= state; 128165138Syongari} 129165138Syongari 130165138Syongaristatic __inline void 131165138Syongariadv_clear_state(struct adv_softc *adv, union ccb* ccb) 132165138Syongari{ 133165138Syongari if (adv->state != 0) 134165138Syongari adv_clear_state_really(adv, ccb); 135165138Syongari} 136165138Syongari 137165138Syongaristatic void 138165138Syongariadv_clear_state_really(struct adv_softc *adv, union ccb* ccb) 139165138Syongari{ 140165138Syongari if ((adv->state & ADV_BUSDMA_BLOCK_CLEARED) != 0) 141165138Syongari adv->state &= ~(ADV_BUSDMA_BLOCK_CLEARED|ADV_BUSDMA_BLOCK); 142165138Syongari if ((adv->state & ADV_RESOURCE_SHORTAGE) != 0) { 143165138Syongari int openings; 144165138Syongari 145165138Syongari openings = adv->max_openings - adv->cur_active - ADV_MIN_FREE_Q; 146165138Syongari if (openings >= adv->openings_needed) { 147165138Syongari adv->state &= ~ADV_RESOURCE_SHORTAGE; 148165138Syongari adv->openings_needed = 0; 149165138Syongari } 150165138Syongari } 151165138Syongari 152165138Syongari if ((adv->state & ADV_IN_TIMEOUT) != 0) { 153165138Syongari struct adv_ccb_info *cinfo; 154165138Syongari 155165138Syongari cinfo = (struct adv_ccb_info *)ccb->ccb_h.ccb_cinfo_ptr; 156165138Syongari if ((cinfo->state & ACCB_RECOVERY_CCB) != 0) { 157165138Syongari struct ccb_hdr *ccb_h; 158165138Syongari 159165138Syongari /* 160165138Syongari * We now traverse our list of pending CCBs 161165138Syongari * and reinstate their timeouts. 162165138Syongari */ 163165138Syongari ccb_h = LIST_FIRST(&adv->pending_ccbs); 164165138Syongari while (ccb_h != NULL) { 165165138Syongari ccb_h->timeout_ch = 166165138Syongari timeout(adv_timeout, (caddr_t)ccb_h, 167165138Syongari (ccb_h->timeout * hz) / 1000); 168165138Syongari ccb_h = LIST_NEXT(ccb_h, sim_links.le); 169165138Syongari } 170165138Syongari adv->state &= ~ADV_IN_TIMEOUT; 171165138Syongari printf("%s: No longer in timeout\n", adv_name(adv)); 172165138Syongari } 173165138Syongari } 174165138Syongari if (adv->state == 0) 175165138Syongari ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 176165138Syongari} 177165138Syongari 178165138Syongarivoid 179165138Syongariadv_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) 180165138Syongari{ 181165138Syongari bus_addr_t* physaddr; 182165138Syongari 183165138Syongari physaddr = (bus_addr_t*)arg; 184165138Syongari *physaddr = segs->ds_addr; 185165138Syongari} 186165138Syongari 187165138Syongarichar * 188165138Syongariadv_name(struct adv_softc *adv) 189165138Syongari{ 190165138Syongari static char name[10]; 191165138Syongari 192165138Syongari snprintf(name, sizeof(name), "adv%d", adv->unit); 193165138Syongari return (name); 194165138Syongari} 195165138Syongari 196165138Syongaristatic void 197165138Syongariadv_action(struct cam_sim *sim, union ccb *ccb) 198165138Syongari{ 199165138Syongari struct adv_softc *adv; 200165138Syongari 201165138Syongari CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("adv_action\n")); 202165138Syongari 203165138Syongari adv = (struct adv_softc *)cam_sim_softc(sim); 204165138Syongari 205165138Syongari switch (ccb->ccb_h.func_code) { 206165138Syongari /* Common cases first */ 207165138Syongari case XPT_SCSI_IO: /* Execute the requested I/O operation */ 208165138Syongari { 209165138Syongari struct ccb_hdr *ccb_h; 210165138Syongari struct ccb_scsiio *csio; 211165138Syongari struct adv_ccb_info *cinfo; 212165138Syongari 213165138Syongari ccb_h = &ccb->ccb_h; 214165138Syongari csio = &ccb->csio; 215165138Syongari cinfo = adv_get_ccb_info(adv); 216165138Syongari if (cinfo == NULL) 217165138Syongari panic("XXX Handle CCB info error!!!"); 218165138Syongari 219165138Syongari ccb_h->ccb_cinfo_ptr = cinfo; 220165138Syongari cinfo->ccb = ccb; 221165138Syongari 222165138Syongari /* Only use S/G if there is a transfer */ 223165138Syongari if ((ccb_h->flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 224165138Syongari if ((ccb_h->flags & CAM_SCATTER_VALID) == 0) { 225165138Syongari /* 226165138Syongari * We've been given a pointer 227165138Syongari * to a single buffer 228165138Syongari */ 229165138Syongari if ((ccb_h->flags & CAM_DATA_PHYS) == 0) { 230165138Syongari int s; 231165138Syongari int error; 232165138Syongari 233165138Syongari s = splsoftvm(); 234165138Syongari error = 235165138Syongari bus_dmamap_load(adv->buffer_dmat, 236165138Syongari cinfo->dmamap, 237165138Syongari csio->data_ptr, 238165138Syongari csio->dxfer_len, 239165138Syongari adv_execute_ccb, 240165138Syongari csio, /*flags*/0); 241165138Syongari if (error == EINPROGRESS) { 242165138Syongari /* 243165138Syongari * So as to maintain ordering, 244165138Syongari * freeze the controller queue 245165138Syongari * until our mapping is 246165138Syongari * returned. 247165138Syongari */ 248165138Syongari adv_set_state(adv, 249165138Syongari ADV_BUSDMA_BLOCK); 250165138Syongari } 251165138Syongari splx(s); 252165138Syongari } else { 253165138Syongari struct bus_dma_segment seg; 254165138Syongari 255165138Syongari /* Pointer to physical buffer */ 256165138Syongari seg.ds_addr = 257165138Syongari (bus_addr_t)csio->data_ptr; 258165138Syongari seg.ds_len = csio->dxfer_len; 259165138Syongari adv_execute_ccb(csio, &seg, 1, 0); 260165138Syongari } 261165138Syongari } else { 262165138Syongari struct bus_dma_segment *segs; 263165138Syongari if ((ccb_h->flags & CAM_DATA_PHYS) != 0) 264165138Syongari panic("adv_setup_data - Physical " 265165138Syongari "segment pointers unsupported"); 266165138Syongari 267165138Syongari if ((ccb_h->flags & CAM_SG_LIST_PHYS) == 0) 268165138Syongari panic("adv_setup_data - Virtual " 269165138Syongari "segment addresses unsupported"); 270165138Syongari 271165138Syongari /* Just use the segments provided */ 272165138Syongari segs = (struct bus_dma_segment *)csio->data_ptr; 273165138Syongari adv_execute_ccb(ccb, segs, csio->sglist_cnt, 0); 274165138Syongari } 275165138Syongari } else { 276165138Syongari adv_execute_ccb(ccb, NULL, 0, 0); 277165138Syongari } 278165138Syongari break; 279165138Syongari } 280165138Syongari case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ 281165138Syongari case XPT_TARGET_IO: /* Execute target I/O request */ 282165138Syongari case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */ 283165138Syongari case XPT_CONT_TARGET_IO: /* Continue Host Target I/O Connection*/ 284165138Syongari case XPT_EN_LUN: /* Enable LUN as a target */ 285165138Syongari case XPT_ABORT: /* Abort the specified CCB */ 286165138Syongari /* XXX Implement */ 287165138Syongari ccb->ccb_h.status = CAM_REQ_INVALID; 288165138Syongari xpt_done(ccb); 289165138Syongari break; 290165138Syongari case XPT_SET_TRAN_SETTINGS: 291165138Syongari { 292165138Syongari struct ccb_trans_settings *cts; 293165138Syongari target_bit_vector targ_mask; 294165138Syongari struct adv_transinfo *tconf; 295165138Syongari u_int update_type; 296165138Syongari int s; 297165138Syongari 298165138Syongari cts = &ccb->cts; 299165138Syongari targ_mask = ADV_TID_TO_TARGET_MASK(cts->ccb_h.target_id); 300165138Syongari update_type = 0; 301165138Syongari 302165138Syongari /* 303165138Syongari * The user must specify which type of settings he wishes 304165138Syongari * to change. 305165138Syongari */ 306165138Syongari if (((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) 307165138Syongari && ((cts->flags & CCB_TRANS_USER_SETTINGS) == 0)) { 308165138Syongari tconf = &adv->tinfo[cts->ccb_h.target_id].current; 309165138Syongari update_type |= ADV_TRANS_GOAL; 310165138Syongari } else if (((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) 311165138Syongari && ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) == 0)) { 312165138Syongari tconf = &adv->tinfo[cts->ccb_h.target_id].user; 313165138Syongari update_type |= ADV_TRANS_USER; 314165138Syongari } else { 315165138Syongari ccb->ccb_h.status = CAM_REQ_INVALID; 316165138Syongari break; 317165138Syongari } 318165138Syongari 319165138Syongari s = splcam(); 320165138Syongari 321165138Syongari if ((update_type & ADV_TRANS_GOAL) != 0) { 322165138Syongari if ((cts->valid & CCB_TRANS_DISC_VALID) != 0) { 323165138Syongari if ((cts->flags & CCB_TRANS_DISC_ENB) != 0) 324165138Syongari adv->disc_enable |= targ_mask; 325165138Syongari else 326165138Syongari adv->disc_enable &= ~targ_mask; 327165138Syongari adv_write_lram_8(adv, ADVV_DISC_ENABLE_B, 328165138Syongari adv->disc_enable); 329165138Syongari } 330165138Syongari 331165138Syongari if ((cts->valid & CCB_TRANS_TQ_VALID) != 0) { 332165138Syongari if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) 333165138Syongari adv->cmd_qng_enabled |= targ_mask; 334165138Syongari else 335165138Syongari adv->cmd_qng_enabled &= ~targ_mask; 336165138Syongari } 337165138Syongari } 338165138Syongari 339165138Syongari if ((update_type & ADV_TRANS_USER) != 0) { 340165138Syongari if ((cts->valid & CCB_TRANS_DISC_VALID) != 0) { 341165138Syongari if ((cts->flags & CCB_TRANS_DISC_ENB) != 0) 342165138Syongari adv->user_disc_enable |= targ_mask; 343165138Syongari else 344165138Syongari adv->user_disc_enable &= ~targ_mask; 345165138Syongari } 346165138Syongari 347165138Syongari if ((cts->valid & CCB_TRANS_TQ_VALID) != 0) { 348165138Syongari if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) 349165138Syongari adv->user_cmd_qng_enabled |= targ_mask; 350165138Syongari else 351165138Syongari adv->user_cmd_qng_enabled &= ~targ_mask; 352165138Syongari } 353165138Syongari } 354165138Syongari 355165138Syongari /* 356165138Syongari * If the user specifies either the sync rate, or offset, 357165138Syongari * but not both, the unspecified parameter defaults to its 358165138Syongari * current value in transfer negotiations. 359165138Syongari */ 360165138Syongari if (((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0) 361165138Syongari || ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0)) { 362165138Syongari /* 363165138Syongari * If the user provided a sync rate but no offset, 364165138Syongari * use the current offset. 365165138Syongari */ 366165138Syongari if ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) == 0) 367165138Syongari cts->sync_offset = tconf->offset; 368165138Syongari 369165138Syongari /* 370165138Syongari * If the user provided an offset but no sync rate, 371165138Syongari * use the current sync rate. 372165138Syongari */ 373165138Syongari if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) == 0) 374165138Syongari cts->sync_period = tconf->period; 375165138Syongari 376165138Syongari adv_period_offset_to_sdtr(adv, &cts->sync_period, 377165138Syongari &cts->sync_offset, 378165138Syongari cts->ccb_h.target_id); 379165138Syongari 380165138Syongari adv_set_syncrate(adv, /*struct cam_path */NULL, 381165138Syongari cts->ccb_h.target_id, cts->sync_period, 382165138Syongari cts->sync_offset, update_type); 383165138Syongari } 384165138Syongari 385165138Syongari splx(s); 386165138Syongari ccb->ccb_h.status = CAM_REQ_CMP; 387165138Syongari xpt_done(ccb); 388165138Syongari break; 389165138Syongari } 390165138Syongari case XPT_GET_TRAN_SETTINGS: 391165138Syongari /* Get default/user set transfer settings for the target */ 392165138Syongari { 393165138Syongari struct ccb_trans_settings *cts; 394165138Syongari struct adv_transinfo *tconf; 395165138Syongari target_bit_vector target_mask; 396165138Syongari int s; 397165138Syongari 398165138Syongari cts = &ccb->cts; 399165138Syongari target_mask = ADV_TID_TO_TARGET_MASK(cts->ccb_h.target_id); 400165138Syongari 401165138Syongari cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB); 402165138Syongari 403165138Syongari s = splcam(); 404165138Syongari if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) { 405165138Syongari tconf = &adv->tinfo[cts->ccb_h.target_id].current; 406165138Syongari if ((adv->disc_enable & target_mask) != 0) 407165138Syongari cts->flags |= CCB_TRANS_DISC_ENB; 408165138Syongari if ((adv->cmd_qng_enabled & target_mask) != 0) 409165138Syongari cts->flags |= CCB_TRANS_TAG_ENB; 410165138Syongari } else { 411165138Syongari tconf = &adv->tinfo[cts->ccb_h.target_id].user; 412165138Syongari if ((adv->user_disc_enable & target_mask) != 0) 413165138Syongari cts->flags |= CCB_TRANS_DISC_ENB; 414165138Syongari if ((adv->user_cmd_qng_enabled & target_mask) != 0) 415165138Syongari cts->flags |= CCB_TRANS_TAG_ENB; 416165138Syongari } 417165138Syongari 418165138Syongari cts->sync_period = tconf->period; 419165138Syongari cts->sync_offset = tconf->offset; 420165138Syongari splx(s); 421165138Syongari 422165138Syongari cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 423165138Syongari cts->valid = CCB_TRANS_SYNC_RATE_VALID 424165138Syongari | CCB_TRANS_SYNC_OFFSET_VALID 425165138Syongari | CCB_TRANS_BUS_WIDTH_VALID 426165138Syongari | CCB_TRANS_DISC_VALID 427165138Syongari | CCB_TRANS_TQ_VALID; 428165138Syongari ccb->ccb_h.status = CAM_REQ_CMP; 429165138Syongari xpt_done(ccb); 430165138Syongari break; 431165138Syongari } 432165138Syongari case XPT_CALC_GEOMETRY: 433165138Syongari { 434165138Syongari struct ccb_calc_geometry *ccg; 435165138Syongari u_int32_t size_mb; 436165138Syongari u_int32_t secs_per_cylinder; 437165138Syongari int extended; 438165138Syongari 439165138Syongari ccg = &ccb->ccg; 440165138Syongari size_mb = ccg->volume_size 441165138Syongari / ((1024L * 1024L) / ccg->block_size); 442165138Syongari extended = (adv->control & ADV_CNTL_BIOS_GT_1GB) != 0; 443165138Syongari 444165138Syongari if (size_mb > 1024 && extended) { 445165138Syongari ccg->heads = 255; 446165138Syongari ccg->secs_per_track = 63; 447165138Syongari } else { 448165138Syongari ccg->heads = 64; 449165138Syongari ccg->secs_per_track = 32; 450165138Syongari } 451165138Syongari secs_per_cylinder = ccg->heads * ccg->secs_per_track; 452165138Syongari ccg->cylinders = ccg->volume_size / secs_per_cylinder; 453165138Syongari ccb->ccb_h.status = CAM_REQ_CMP; 454165138Syongari xpt_done(ccb); 455165138Syongari break; 456165138Syongari } 457165138Syongari case XPT_RESET_BUS: /* Reset the specified SCSI bus */ 458165138Syongari { 459165138Syongari int s; 460165138Syongari 461165138Syongari s = splcam(); 462165138Syongari adv_stop_execution(adv); 463165138Syongari adv_reset_bus(adv, /*initiate_reset*/TRUE); 464165138Syongari adv_start_execution(adv); 465165138Syongari splx(s); 466165138Syongari 467165138Syongari ccb->ccb_h.status = CAM_REQ_CMP; 468165138Syongari xpt_done(ccb); 469165138Syongari break; 470165138Syongari } 471165138Syongari case XPT_TERM_IO: /* Terminate the I/O process */ 472165138Syongari /* XXX Implement */ 473165138Syongari ccb->ccb_h.status = CAM_REQ_INVALID; 474165138Syongari xpt_done(ccb); 475165138Syongari break; 476165138Syongari case XPT_PATH_INQ: /* Path routing inquiry */ 477165138Syongari { 478165138Syongari struct ccb_pathinq *cpi = &ccb->cpi; 479165138Syongari 480165138Syongari cpi->version_num = 1; /* XXX??? */ 481165138Syongari cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE; 482165138Syongari cpi->target_sprt = 0; 483165138Syongari cpi->hba_misc = 0; 484165138Syongari cpi->hba_eng_cnt = 0; 485165138Syongari cpi->max_target = 7; 486165138Syongari cpi->max_lun = 7; 487165138Syongari cpi->initiator_id = adv->scsi_id; 488165138Syongari cpi->bus_id = cam_sim_bus(sim); 489165138Syongari cpi->base_transfer_speed = 3300; 490165138Syongari strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 491165138Syongari strncpy(cpi->hba_vid, "Advansys", HBA_IDLEN); 492165138Syongari strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 493165138Syongari cpi->unit_number = cam_sim_unit(sim); 494165138Syongari cpi->ccb_h.status = CAM_REQ_CMP; 495165138Syongari xpt_done(ccb); 496165138Syongari break; 497165138Syongari } 498165138Syongari default: 499165138Syongari ccb->ccb_h.status = CAM_REQ_INVALID; 500165138Syongari xpt_done(ccb); 501165138Syongari break; 502165138Syongari } 503165138Syongari} 504165138Syongari 505165138Syongari/* 506165138Syongari * Currently, the output of bus_dmammap_load suits our needs just 507165138Syongari * fine, but should it change, we'd need to do something here. 508165138Syongari */ 509165138Syongari#define adv_fixup_dmasegs(adv, dm_segs) (struct adv_sg_entry *)(dm_segs) 510165138Syongari 511165138Syongaristatic void 512165138Syongariadv_execute_ccb(void *arg, bus_dma_segment_t *dm_segs, 513165138Syongari int nsegments, int error) 514165138Syongari{ 515165138Syongari struct ccb_scsiio *csio; 516165138Syongari struct ccb_hdr *ccb_h; 517165138Syongari struct cam_sim *sim; 518165138Syongari struct adv_softc *adv; 519165138Syongari struct adv_ccb_info *cinfo; 520165138Syongari struct adv_scsi_q scsiq; 521165138Syongari struct adv_sg_head sghead; 522165138Syongari int s; 523165138Syongari 524165138Syongari csio = (struct ccb_scsiio *)arg; 525165138Syongari ccb_h = &csio->ccb_h; 526165138Syongari sim = xpt_path_sim(ccb_h->path); 527165138Syongari adv = (struct adv_softc *)cam_sim_softc(sim); 528165138Syongari cinfo = (struct adv_ccb_info *)csio->ccb_h.ccb_cinfo_ptr; 529165138Syongari 530165138Syongari /* 531165138Syongari * Setup our done routine to release the simq on 532165138Syongari * the next ccb that completes. 533165138Syongari */ 534165138Syongari if ((adv->state & ADV_BUSDMA_BLOCK) != 0) 535165138Syongari adv->state |= ADV_BUSDMA_BLOCK_CLEARED; 536165138Syongari 537165138Syongari if ((ccb_h->flags & CAM_CDB_POINTER) != 0) { 538165138Syongari if ((ccb_h->flags & CAM_CDB_PHYS) == 0) { 539165138Syongari /* XXX Need phystovirt!!!! */ 540165138Syongari /* How about pmap_kenter??? */ 541165138Syongari scsiq.cdbptr = csio->cdb_io.cdb_ptr; 542165138Syongari } else { 543165138Syongari scsiq.cdbptr = csio->cdb_io.cdb_ptr; 544165138Syongari } 545165138Syongari } else { 546165138Syongari scsiq.cdbptr = csio->cdb_io.cdb_bytes; 547165138Syongari } 548165138Syongari /* 549165138Syongari * Build up the request 550165138Syongari */ 551165138Syongari scsiq.q1.status = 0; 552165138Syongari scsiq.q1.q_no = 0; 553165138Syongari scsiq.q1.cntl = 0; 554165138Syongari scsiq.q1.sg_queue_cnt = 0; 555165138Syongari scsiq.q1.target_id = ADV_TID_TO_TARGET_MASK(ccb_h->target_id); 556165138Syongari scsiq.q1.target_lun = ccb_h->target_lun; 557165138Syongari scsiq.q1.sense_len = csio->sense_len; 558165138Syongari scsiq.q1.extra_bytes = 0; 559165138Syongari scsiq.q2.ccb_index = cinfo - adv->ccb_infos; 560165138Syongari scsiq.q2.target_ix = ADV_TIDLUN_TO_IX(ccb_h->target_id, 561165138Syongari ccb_h->target_lun); 562165138Syongari scsiq.q2.flag = 0; 563165138Syongari scsiq.q2.cdb_len = csio->cdb_len; 564165138Syongari if ((ccb_h->flags & CAM_TAG_ACTION_VALID) != 0) 565165138Syongari scsiq.q2.tag_code = csio->tag_action; 566165138Syongari else 567165138Syongari scsiq.q2.tag_code = 0; 568165138Syongari scsiq.q2.vm_id = 0; 569165138Syongari 570165138Syongari if (nsegments != 0) { 571165138Syongari bus_dmasync_op_t op; 572165138Syongari 573165138Syongari scsiq.q1.data_addr = dm_segs->ds_addr; 574165138Syongari scsiq.q1.data_cnt = dm_segs->ds_len; 575165138Syongari if (nsegments > 1) { 576165138Syongari scsiq.q1.cntl |= QC_SG_HEAD; 577165138Syongari sghead.entry_cnt 578165138Syongari = sghead.entry_to_copy 579165138Syongari = nsegments; 580165138Syongari sghead.res = 0; 581165138Syongari sghead.sg_list = adv_fixup_dmasegs(adv, dm_segs); 582165138Syongari scsiq.sg_head = &sghead; 583165138Syongari } else { 584165138Syongari scsiq.sg_head = NULL; 585165138Syongari } 586165138Syongari if ((ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_IN) 587165138Syongari op = BUS_DMASYNC_PREREAD; 588165138Syongari else 589165138Syongari op = BUS_DMASYNC_PREWRITE; 590165138Syongari bus_dmamap_sync(adv->buffer_dmat, cinfo->dmamap, op); 591165138Syongari } else { 592165138Syongari scsiq.q1.data_addr = 0; 593165138Syongari scsiq.q1.data_cnt = 0; 594165138Syongari scsiq.sg_head = NULL; 595165138Syongari } 596165138Syongari 597165138Syongari s = splcam(); 598165138Syongari 599165138Syongari /* 600165138Syongari * Last time we need to check if this SCB needs to 601165138Syongari * be aborted. 602165138Syongari */ 603165138Syongari if (ccb_h->status != CAM_REQ_INPROG) { 604165138Syongari if (nsegments != 0) 605165138Syongari bus_dmamap_unload(adv->buffer_dmat, cinfo->dmamap); 606165138Syongari adv_clear_state(adv, (union ccb *)csio); 607165138Syongari adv_free_ccb_info(adv, cinfo); 608165138Syongari xpt_done((union ccb *)csio); 609165138Syongari splx(s); 610165138Syongari return; 611165138Syongari } 612165138Syongari 613165138Syongari if (adv_execute_scsi_queue(adv, &scsiq, csio->dxfer_len) != 0) { 614165138Syongari /* Temporary resource shortage */ 615165138Syongari adv_set_state(adv, ADV_RESOURCE_SHORTAGE); 616165138Syongari if (nsegments != 0) 617165138Syongari bus_dmamap_unload(adv->buffer_dmat, cinfo->dmamap); 618165138Syongari csio->ccb_h.status = CAM_REQUEUE_REQ; 619165138Syongari adv_clear_state(adv, (union ccb *)csio); 620165138Syongari adv_free_ccb_info(adv, cinfo); 621165138Syongari xpt_done((union ccb *)csio); 622165138Syongari splx(s); 623165138Syongari return; 624165138Syongari } 625165138Syongari cinfo->state |= ACCB_ACTIVE; 626165138Syongari ccb_h->status |= CAM_SIM_QUEUED; 627165138Syongari LIST_INSERT_HEAD(&adv->pending_ccbs, ccb_h, sim_links.le); 628165138Syongari /* Schedule our timeout */ 629165138Syongari ccb_h->timeout_ch = 630165138Syongari timeout(adv_timeout, csio, (ccb_h->timeout * hz)/1000); 631165138Syongari splx(s); 632165138Syongari} 633165138Syongari 634165138Syongaristatic struct adv_ccb_info * 635165138Syongariadv_alloc_ccb_info(struct adv_softc *adv) 636165138Syongari{ 637165138Syongari int error; 638165138Syongari struct adv_ccb_info *cinfo; 639165138Syongari 640165138Syongari cinfo = &adv->ccb_infos[adv->ccb_infos_allocated]; 641165138Syongari cinfo->state = ACCB_FREE; 642165138Syongari error = bus_dmamap_create(adv->buffer_dmat, /*flags*/0, 643165138Syongari &cinfo->dmamap); 644165138Syongari if (error != 0) { 645165138Syongari printf("%s: Unable to allocate CCB info " 646165138Syongari "dmamap - error %d\n", adv_name(adv), error); 647165138Syongari return (NULL); 648165138Syongari } 649165138Syongari adv->ccb_infos_allocated++; 650165138Syongari return (cinfo); 651165138Syongari} 652165138Syongari 653165138Syongaristatic void 654165138Syongariadv_destroy_ccb_info(struct adv_softc *adv, struct adv_ccb_info *cinfo) 655165138Syongari{ 656165138Syongari bus_dmamap_destroy(adv->buffer_dmat, cinfo->dmamap); 657165138Syongari} 658165138Syongari 659165138Syongarivoid 660165138Syongariadv_timeout(void *arg) 661165138Syongari{ 662165138Syongari int s; 663165138Syongari union ccb *ccb; 664165138Syongari struct adv_softc *adv; 665165138Syongari struct adv_ccb_info *cinfo; 666165138Syongari 667165138Syongari ccb = (union ccb *)arg; 668165138Syongari adv = (struct adv_softc *)xpt_path_sim(ccb->ccb_h.path)->softc; 669165138Syongari cinfo = (struct adv_ccb_info *)ccb->ccb_h.ccb_cinfo_ptr; 670165138Syongari 671165138Syongari xpt_print_path(ccb->ccb_h.path); 672165138Syongari printf("Timed out\n"); 673165138Syongari 674165138Syongari s = splcam(); 675165138Syongari /* Have we been taken care of already?? */ 676165138Syongari if (cinfo == NULL || cinfo->state == ACCB_FREE) { 677165138Syongari splx(s); 678165138Syongari return; 679165138Syongari } 680165138Syongari 681165138Syongari adv_stop_execution(adv); 682165138Syongari 683165138Syongari if ((cinfo->state & ACCB_ABORT_QUEUED) == 0) { 684165138Syongari struct ccb_hdr *ccb_h; 685165138Syongari 686165138Syongari /* 687165138Syongari * In order to simplify the recovery process, we ask the XPT 688165138Syongari * layer to halt the queue of new transactions and we traverse 689165138Syongari * the list of pending CCBs and remove their timeouts. This 690165138Syongari * means that the driver attempts to clear only one error 691165138Syongari * condition at a time. In general, timeouts that occur 692165138Syongari * close together are related anyway, so there is no benefit 693165138Syongari * in attempting to handle errors in parrallel. Timeouts will 694165138Syongari * be reinstated when the recovery process ends. 695165138Syongari */ 696165138Syongari adv_set_state(adv, ADV_IN_TIMEOUT); 697165138Syongari 698165138Syongari /* This CCB is the CCB representing our recovery actions */ 699165138Syongari cinfo->state |= ACCB_RECOVERY_CCB|ACCB_ABORT_QUEUED; 700165138Syongari 701165138Syongari ccb_h = LIST_FIRST(&adv->pending_ccbs); 702165138Syongari while (ccb_h != NULL) { 703165138Syongari untimeout(adv_timeout, ccb_h, ccb_h->timeout_ch); 704165138Syongari ccb_h = LIST_NEXT(ccb_h, sim_links.le); 705165138Syongari } 706165138Syongari 707165138Syongari /* XXX Should send a BDR */ 708165138Syongari /* Attempt an abort as our first tact */ 709165138Syongari xpt_print_path(ccb->ccb_h.path); 710165138Syongari printf("Attempting abort\n"); 711165138Syongari adv_abort_ccb(adv, ccb->ccb_h.target_id, 712165138Syongari ccb->ccb_h.target_lun, ccb, 713165138Syongari CAM_CMD_TIMEOUT, /*queued_only*/FALSE); 714165138Syongari ccb->ccb_h.timeout_ch = 715165138Syongari timeout(adv_timeout, ccb, 2 * hz); 716165138Syongari } else { 717165138Syongari /* Our attempt to perform an abort failed, go for a reset */ 718165138Syongari xpt_print_path(ccb->ccb_h.path); 719165138Syongari printf("Resetting bus\n"); 720165138Syongari ccb->ccb_h.status &= ~CAM_STATUS_MASK; 721165138Syongari ccb->ccb_h.status |= CAM_CMD_TIMEOUT; 722165138Syongari adv_reset_bus(adv, /*initiate_reset*/TRUE); 723165138Syongari } 724165138Syongari adv_start_execution(adv); 725165138Syongari splx(s); 726165138Syongari} 727165138Syongari 728165138Syongaristruct adv_softc * 729165138Syongariadv_alloc(device_t dev, bus_space_tag_t tag, bus_space_handle_t bsh) 730165138Syongari{ 731165138Syongari struct adv_softc *adv = device_get_softc(dev); 732165138Syongari 733165138Syongari /* 734165138Syongari * Allocate a storage area for us 735165138Syongari */ 736165138Syongari LIST_INIT(&adv->pending_ccbs); 737165138Syongari SLIST_INIT(&adv->free_ccb_infos); 738165138Syongari adv->dev = dev; 739165138Syongari adv->unit = device_get_unit(dev); 740165138Syongari adv->tag = tag; 741165138Syongari adv->bsh = bsh; 742165138Syongari 743165138Syongari return(adv); 744165138Syongari} 745165138Syongari 746165138Syongarivoid 747165138Syongariadv_free(struct adv_softc *adv) 748165138Syongari{ 749165138Syongari switch (adv->init_level) { 750165138Syongari case 6: 751165138Syongari { 752165138Syongari struct adv_ccb_info *cinfo; 753165138Syongari 754165138Syongari while ((cinfo = SLIST_FIRST(&adv->free_ccb_infos)) != NULL) { 755165138Syongari SLIST_REMOVE_HEAD(&adv->free_ccb_infos, links); 756165138Syongari adv_destroy_ccb_info(adv, cinfo); 757165138Syongari } 758165138Syongari 759165138Syongari bus_dmamap_unload(adv->sense_dmat, adv->sense_dmamap); 760165138Syongari } 761165138Syongari case 5: 762165138Syongari bus_dmamem_free(adv->sense_dmat, adv->sense_buffers, 763165138Syongari adv->sense_dmamap); 764165138Syongari case 4: 765165138Syongari bus_dma_tag_destroy(adv->sense_dmat); 766165138Syongari case 3: 767165138Syongari bus_dma_tag_destroy(adv->buffer_dmat); 768165138Syongari case 2: 769165138Syongari bus_dma_tag_destroy(adv->parent_dmat); 770165138Syongari case 1: 771165138Syongari if (adv->ccb_infos != NULL) 772165138Syongari free(adv->ccb_infos, M_DEVBUF); 773165138Syongari case 0: 774165138Syongari break; 775165138Syongari } 776165138Syongari} 777165138Syongari 778165138Syongariint 779165138Syongariadv_init(struct adv_softc *adv) 780165138Syongari{ 781165138Syongari struct adv_eeprom_config eeprom_config; 782165138Syongari int checksum, i; 783165138Syongari int max_sync; 784165138Syongari u_int16_t config_lsw; 785165138Syongari u_int16_t config_msw; 786165138Syongari 787165138Syongari adv_lib_init(adv); 788165138Syongari 789165138Syongari /* 790165138Syongari * Stop script execution. 791165138Syongari */ 792165138Syongari adv_write_lram_16(adv, ADV_HALTCODE_W, 0x00FE); 793165138Syongari adv_stop_execution(adv); 794165138Syongari if (adv_stop_chip(adv) == 0 || adv_is_chip_halted(adv) == 0) { 795165138Syongari printf("adv%d: Unable to halt adapter. Initialization" 796165138Syongari "failed\n", adv->unit); 797165138Syongari return (1); 798165138Syongari } 799165138Syongari ADV_OUTW(adv, ADV_REG_PROG_COUNTER, ADV_MCODE_START_ADDR); 800165138Syongari if (ADV_INW(adv, ADV_REG_PROG_COUNTER) != ADV_MCODE_START_ADDR) { 801165138Syongari printf("adv%d: Unable to set program counter. Initialization" 802165138Syongari "failed\n", adv->unit); 803165138Syongari return (1); 804165138Syongari } 805165138Syongari 806165138Syongari config_msw = ADV_INW(adv, ADV_CONFIG_MSW); 807165138Syongari config_lsw = ADV_INW(adv, ADV_CONFIG_LSW); 808165138Syongari 809165138Syongari if ((config_msw & ADV_CFG_MSW_CLR_MASK) != 0) { 810165138Syongari config_msw &= ~ADV_CFG_MSW_CLR_MASK; 811165138Syongari /* 812165138Syongari * XXX The Linux code flags this as an error, 813165138Syongari * but what should we report to the user??? 814165138Syongari * It seems that clearing the config register 815165138Syongari * makes this error recoverable. 816165138Syongari */ 817165138Syongari ADV_OUTW(adv, ADV_CONFIG_MSW, config_msw); 818165138Syongari } 819165138Syongari 820165138Syongari /* Suck in the configuration from the EEProm */ 821165138Syongari checksum = adv_get_eeprom_config(adv, &eeprom_config); 822165138Syongari 823165138Syongari if (ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_AUTO_CONFIG) { 824165138Syongari /* 825165138Syongari * XXX The Linux code sets a warning level for this 826165138Syongari * condition, yet nothing of meaning is printed to 827165138Syongari * the user. What does this mean??? 828165138Syongari */ 829165138Syongari if (adv->chip_version == 3) { 830165138Syongari if (eeprom_config.cfg_lsw != config_lsw) 831165138Syongari eeprom_config.cfg_lsw = config_lsw; 832165138Syongari if (eeprom_config.cfg_msw != config_msw) { 833165138Syongari eeprom_config.cfg_msw = config_msw; 834165138Syongari } 835165138Syongari } 836165138Syongari } 837165138Syongari if (checksum == eeprom_config.chksum) { 838165138Syongari 839165138Syongari /* Range/Sanity checking */ 840165138Syongari if (eeprom_config.max_total_qng < ADV_MIN_TOTAL_QNG) { 841165138Syongari eeprom_config.max_total_qng = ADV_MIN_TOTAL_QNG; 842165138Syongari } 843165138Syongari if (eeprom_config.max_total_qng > ADV_MAX_TOTAL_QNG) { 844165138Syongari eeprom_config.max_total_qng = ADV_MAX_TOTAL_QNG; 845165138Syongari } 846165138Syongari if (eeprom_config.max_tag_qng > eeprom_config.max_total_qng) { 847165138Syongari eeprom_config.max_tag_qng = eeprom_config.max_total_qng; 848165138Syongari } 849165138Syongari if (eeprom_config.max_tag_qng < ADV_MIN_TAG_Q_PER_DVC) { 850165138Syongari eeprom_config.max_tag_qng = ADV_MIN_TAG_Q_PER_DVC; 851165138Syongari } 852165138Syongari adv->max_openings = eeprom_config.max_total_qng; 853165138Syongari adv->user_disc_enable = eeprom_config.disc_enable; 854165138Syongari adv->user_cmd_qng_enabled = eeprom_config.use_cmd_qng; 855165138Syongari adv->isa_dma_speed = EEPROM_DMA_SPEED(eeprom_config); 856165138Syongari adv->scsi_id = EEPROM_SCSIID(eeprom_config) & ADV_MAX_TID; 857165138Syongari EEPROM_SET_SCSIID(eeprom_config, adv->scsi_id); 858165138Syongari adv->control = eeprom_config.cntl; 859165138Syongari for (i = 0; i <= ADV_MAX_TID; i++) { 860165138Syongari u_int8_t sync_data; 861165138Syongari 862165138Syongari if ((eeprom_config.init_sdtr & (0x1 << i)) == 0) 863165138Syongari sync_data = 0; 864165138Syongari else 865165138Syongari sync_data = eeprom_config.sdtr_data[i]; 866165138Syongari adv_sdtr_to_period_offset(adv, 867165138Syongari sync_data, 868165138Syongari &adv->tinfo[i].user.period, 869165138Syongari &adv->tinfo[i].user.offset, 870165138Syongari i); 871165138Syongari } 872165138Syongari config_lsw = eeprom_config.cfg_lsw; 873165138Syongari eeprom_config.cfg_msw = config_msw; 874165138Syongari } else { 875165138Syongari u_int8_t sync_data; 876165138Syongari 877165138Syongari printf("adv%d: Warning EEPROM Checksum mismatch. " 878165138Syongari "Using default device parameters\n", adv->unit); 879165138Syongari 880165138Syongari /* Set reasonable defaults since we can't read the EEPROM */ 881165138Syongari adv->isa_dma_speed = /*ADV_DEF_ISA_DMA_SPEED*/1; 882165138Syongari adv->max_openings = ADV_DEF_MAX_TOTAL_QNG; 883165138Syongari adv->disc_enable = TARGET_BIT_VECTOR_SET; 884165138Syongari adv->user_disc_enable = TARGET_BIT_VECTOR_SET; 885165138Syongari adv->cmd_qng_enabled = TARGET_BIT_VECTOR_SET; 886165138Syongari adv->user_cmd_qng_enabled = TARGET_BIT_VECTOR_SET; 887165138Syongari adv->scsi_id = 7; 888165138Syongari adv->control = 0xFFFF; 889165138Syongari 890165138Syongari if (adv->chip_version == ADV_CHIP_VER_PCI_ULTRA_3050) 891165138Syongari /* Default to no Ultra to support the 3030 */ 892165138Syongari adv->control &= ~ADV_CNTL_SDTR_ENABLE_ULTRA; 893165138Syongari sync_data = ADV_DEF_SDTR_OFFSET | (ADV_DEF_SDTR_INDEX << 4); 894165138Syongari for (i = 0; i <= ADV_MAX_TID; i++) { 895165138Syongari adv_sdtr_to_period_offset(adv, sync_data, 896165138Syongari &adv->tinfo[i].user.period, 897165138Syongari &adv->tinfo[i].user.offset, 898165138Syongari i); 899165138Syongari } 900165138Syongari config_lsw |= ADV_CFG_LSW_SCSI_PARITY_ON; 901165138Syongari } 902165138Syongari config_msw &= ~ADV_CFG_MSW_CLR_MASK; 903165138Syongari config_lsw |= ADV_CFG_LSW_HOST_INT_ON; 904165138Syongari if ((adv->type & (ADV_PCI|ADV_ULTRA)) == (ADV_PCI|ADV_ULTRA) 905165138Syongari && (adv->control & ADV_CNTL_SDTR_ENABLE_ULTRA) == 0) 906165138Syongari /* 25ns or 10MHz */ 907165138Syongari max_sync = 25; 908165138Syongari else 909165138Syongari /* Unlimited */ 910165138Syongari max_sync = 0; 911165138Syongari for (i = 0; i <= ADV_MAX_TID; i++) { 912165138Syongari if (adv->tinfo[i].user.period < max_sync) 913165138Syongari adv->tinfo[i].user.period = max_sync; 914165138Syongari } 915165138Syongari 916165138Syongari if (adv_test_external_lram(adv) == 0) { 917165138Syongari if ((adv->type & (ADV_PCI|ADV_ULTRA)) == (ADV_PCI|ADV_ULTRA)) { 918165138Syongari eeprom_config.max_total_qng = 919165138Syongari ADV_MAX_PCI_ULTRA_INRAM_TOTAL_QNG; 920165138Syongari eeprom_config.max_tag_qng = 921165138Syongari ADV_MAX_PCI_ULTRA_INRAM_TAG_QNG; 922165138Syongari } else { 923165138Syongari eeprom_config.cfg_msw |= 0x0800; 924165138Syongari config_msw |= 0x0800; 925165138Syongari eeprom_config.max_total_qng = 926165138Syongari ADV_MAX_PCI_INRAM_TOTAL_QNG; 927165138Syongari eeprom_config.max_tag_qng = ADV_MAX_INRAM_TAG_QNG; 928165138Syongari } 929165138Syongari adv->max_openings = eeprom_config.max_total_qng; 930165138Syongari } 931165138Syongari ADV_OUTW(adv, ADV_CONFIG_MSW, config_msw); 932165138Syongari ADV_OUTW(adv, ADV_CONFIG_LSW, config_lsw); 933165138Syongari#if 0 934165138Syongari /* 935165138Syongari * Don't write the eeprom data back for now. 936165138Syongari * I'd rather not mess up the user's card. We also don't 937165138Syongari * fully sanitize the eeprom settings above for the write-back 938165138Syongari * to be 100% correct. 939165138Syongari */ 940165138Syongari if (adv_set_eeprom_config(adv, &eeprom_config) != 0) 941165138Syongari printf("%s: WARNING! Failure writing to EEPROM.\n", 942165138Syongari adv_name(adv)); 943165138Syongari#endif 944165138Syongari 945165138Syongari adv_set_chip_scsiid(adv, adv->scsi_id); 946165138Syongari if (adv_init_lram_and_mcode(adv)) 947165138Syongari return (1); 948165138Syongari 949165138Syongari adv->disc_enable = adv->user_disc_enable; 950165138Syongari 951165138Syongari adv_write_lram_8(adv, ADVV_DISC_ENABLE_B, adv->disc_enable); 952165138Syongari for (i = 0; i <= ADV_MAX_TID; i++) { 953165138Syongari /* 954165138Syongari * Start off in async mode. 955165138Syongari */ 956165138Syongari adv_set_syncrate(adv, /*struct cam_path */NULL, 957165138Syongari i, /*period*/0, /*offset*/0, 958165138Syongari ADV_TRANS_CUR); 959165138Syongari /* 960165138Syongari * Enable the use of tagged commands on all targets. 961165138Syongari * This allows the kernel driver to make up it's own mind 962165138Syongari * as it sees fit to tag queue instead of having the 963165138Syongari * firmware try and second guess the tag_code settins. 964165138Syongari */ 965165138Syongari adv_write_lram_8(adv, ADVV_MAX_DVC_QNG_BEG + i, 966165138Syongari adv->max_openings); 967165138Syongari } 968165138Syongari adv_write_lram_8(adv, ADVV_USE_TAGGED_QNG_B, TARGET_BIT_VECTOR_SET); 969165138Syongari adv_write_lram_8(adv, ADVV_CAN_TAGGED_QNG_B, TARGET_BIT_VECTOR_SET); 970165138Syongari printf("adv%d: AdvanSys %s Host Adapter, SCSI ID %d, queue depth %d\n", 971165138Syongari adv->unit, (adv->type & ADV_ULTRA) && (max_sync == 0) 972165138Syongari ? "Ultra SCSI" : "SCSI", 973165138Syongari adv->scsi_id, adv->max_openings); 974165138Syongari return (0); 975165138Syongari} 976165138Syongari 977165138Syongarivoid 978165138Syongariadv_intr(void *arg) 979165138Syongari{ 980165138Syongari struct adv_softc *adv; 981165138Syongari u_int16_t chipstat; 982165138Syongari u_int16_t saved_ram_addr; 983165138Syongari u_int8_t ctrl_reg; 984165138Syongari u_int8_t saved_ctrl_reg; 985165138Syongari u_int8_t host_flag; 986165138Syongari 987165138Syongari adv = (struct adv_softc *)arg; 988165138Syongari 989165138Syongari chipstat = ADV_INW(adv, ADV_CHIP_STATUS); 990165138Syongari 991165138Syongari /* Is it for us? */ 992165138Syongari if ((chipstat & (ADV_CSW_INT_PENDING|ADV_CSW_SCSI_RESET_LATCH)) == 0) 993165138Syongari return; 994165138Syongari 995165138Syongari ctrl_reg = ADV_INB(adv, ADV_CHIP_CTRL); 996165138Syongari saved_ctrl_reg = ctrl_reg & (~(ADV_CC_SCSI_RESET | ADV_CC_CHIP_RESET | 997165138Syongari ADV_CC_SINGLE_STEP | ADV_CC_DIAG | 998165138Syongari ADV_CC_TEST)); 999165138Syongari 1000165138Syongari if ((chipstat & (ADV_CSW_SCSI_RESET_LATCH|ADV_CSW_SCSI_RESET_ACTIVE))) { 1001165138Syongari printf("Detected Bus Reset\n"); 1002165138Syongari adv_reset_bus(adv, /*initiate_reset*/FALSE); 1003165138Syongari return; 1004165138Syongari } 1005165138Syongari 1006165138Syongari if ((chipstat & ADV_CSW_INT_PENDING) != 0) { 1007165138Syongari 1008165138Syongari saved_ram_addr = ADV_INW(adv, ADV_LRAM_ADDR); 1009165138Syongari host_flag = adv_read_lram_8(adv, ADVV_HOST_FLAG_B); 1010165138Syongari adv_write_lram_8(adv, ADVV_HOST_FLAG_B, 1011165138Syongari host_flag | ADV_HOST_FLAG_IN_ISR); 1012165138Syongari 1013165138Syongari adv_ack_interrupt(adv); 1014165138Syongari 1015165138Syongari if ((chipstat & ADV_CSW_HALTED) != 0 1016165138Syongari && (ctrl_reg & ADV_CC_SINGLE_STEP) != 0) { 1017165138Syongari adv_isr_chip_halted(adv); 1018165138Syongari saved_ctrl_reg &= ~ADV_CC_HALT; 1019165138Syongari } else { 1020165138Syongari adv_run_doneq(adv); 1021165138Syongari } 1022165138Syongari ADV_OUTW(adv, ADV_LRAM_ADDR, saved_ram_addr); 1023165138Syongari#ifdef DIAGNOSTIC 1024165138Syongari if (ADV_INW(adv, ADV_LRAM_ADDR) != saved_ram_addr) 1025165138Syongari panic("adv_intr: Unable to set LRAM addr"); 1026165138Syongari#endif 1027165138Syongari adv_write_lram_8(adv, ADVV_HOST_FLAG_B, host_flag); 1028165138Syongari } 1029165138Syongari 1030165138Syongari ADV_OUTB(adv, ADV_CHIP_CTRL, saved_ctrl_reg); 1031165138Syongari} 1032165138Syongari 1033165138Syongaristatic void 1034165138Syongariadv_run_doneq(struct adv_softc *adv) 1035165138Syongari{ 1036165138Syongari struct adv_q_done_info scsiq; 1037165138Syongari u_int doneq_head; 1038165138Syongari u_int done_qno; 1039165138Syongari 1040165138Syongari doneq_head = adv_read_lram_16(adv, ADVV_DONE_Q_TAIL_W) & 0xFF; 1041165138Syongari done_qno = adv_read_lram_8(adv, ADV_QNO_TO_QADDR(doneq_head) 1042165138Syongari + ADV_SCSIQ_B_FWD); 1043165138Syongari while (done_qno != ADV_QLINK_END) { 1044165138Syongari union ccb* ccb; 1045165138Syongari struct adv_ccb_info *cinfo; 1046165138Syongari u_int done_qaddr; 1047165138Syongari u_int sg_queue_cnt; 1048165138Syongari int aborted; 1049165138Syongari 1050165138Syongari done_qaddr = ADV_QNO_TO_QADDR(done_qno); 1051165138Syongari 1052165138Syongari /* Pull status from this request */ 1053165138Syongari sg_queue_cnt = adv_copy_lram_doneq(adv, done_qaddr, &scsiq, 1054165138Syongari adv->max_dma_count); 1055165138Syongari 1056165138Syongari /* Mark it as free */ 1057165138Syongari adv_write_lram_8(adv, done_qaddr + ADV_SCSIQ_B_STATUS, 1058165138Syongari scsiq.q_status & ~(QS_READY|QS_ABORTED)); 1059165138Syongari 1060165138Syongari /* Process request based on retrieved info */ 1061165138Syongari if ((scsiq.cntl & QC_SG_HEAD) != 0) { 1062165138Syongari u_int i; 1063165138Syongari 1064165138Syongari /* 1065165138Syongari * S/G based request. Free all of the queue 1066165138Syongari * structures that contained S/G information. 1067165138Syongari */ 1068165138Syongari for (i = 0; i < sg_queue_cnt; i++) { 1069165138Syongari done_qno = adv_read_lram_8(adv, done_qaddr 1070165138Syongari + ADV_SCSIQ_B_FWD); 1071165138Syongari 1072165138Syongari#ifdef DIAGNOSTIC 1073165138Syongari if (done_qno == ADV_QLINK_END) { 1074165138Syongari panic("adv_qdone: Corrupted SG " 1075165138Syongari "list encountered"); 1076165138Syongari } 1077165138Syongari#endif 1078165138Syongari done_qaddr = ADV_QNO_TO_QADDR(done_qno); 1079165138Syongari 1080165138Syongari /* Mark SG queue as free */ 1081165138Syongari adv_write_lram_8(adv, done_qaddr 1082165138Syongari + ADV_SCSIQ_B_STATUS, QS_FREE); 1083165138Syongari } 1084165138Syongari } else 1085165138Syongari sg_queue_cnt = 0; 1086165138Syongari#ifdef DIAGNOSTIC 1087165138Syongari if (adv->cur_active < (sg_queue_cnt + 1)) 1088165138Syongari panic("adv_qdone: Attempting to free more " 1089165138Syongari "queues than are active"); 1090165138Syongari#endif 1091165138Syongari adv->cur_active -= sg_queue_cnt + 1; 1092165138Syongari 1093165138Syongari aborted = (scsiq.q_status & QS_ABORTED) != 0; 1094165138Syongari 1095165138Syongari if ((scsiq.q_status != QS_DONE) 1096165138Syongari && (scsiq.q_status & QS_ABORTED) == 0) 1097165138Syongari panic("adv_qdone: completed scsiq with unknown status"); 1098165138Syongari 1099165138Syongari scsiq.remain_bytes += scsiq.extra_bytes; 1100165138Syongari 1101165138Syongari if ((scsiq.d3.done_stat == QD_WITH_ERROR) && 1102165138Syongari (scsiq.d3.host_stat == QHSTA_M_DATA_OVER_RUN)) { 1103165138Syongari if ((scsiq.cntl & (QC_DATA_IN|QC_DATA_OUT)) == 0) { 1104165138Syongari scsiq.d3.done_stat = QD_NO_ERROR; 1105165138Syongari scsiq.d3.host_stat = QHSTA_NO_ERROR; 1106165138Syongari } 1107165138Syongari } 1108165138Syongari 1109165138Syongari cinfo = &adv->ccb_infos[scsiq.d2.ccb_index]; 1110165138Syongari ccb = cinfo->ccb; 1111165138Syongari ccb->csio.resid = scsiq.remain_bytes; 1112165138Syongari adv_done(adv, ccb, 1113165138Syongari scsiq.d3.done_stat, scsiq.d3.host_stat, 1114165138Syongari scsiq.d3.scsi_stat, scsiq.q_no); 1115165138Syongari 1116165138Syongari doneq_head = done_qno; 1117165138Syongari done_qno = adv_read_lram_8(adv, done_qaddr + ADV_SCSIQ_B_FWD); 1118165138Syongari } 1119165138Syongari adv_write_lram_16(adv, ADVV_DONE_Q_TAIL_W, doneq_head); 1120165138Syongari} 1121165138Syongari 1122165138Syongari 1123165138Syongarivoid 1124165138Syongariadv_done(struct adv_softc *adv, union ccb *ccb, u_int done_stat, 1125165138Syongari u_int host_stat, u_int scsi_status, u_int q_no) 1126165138Syongari{ 1127165138Syongari struct adv_ccb_info *cinfo; 1128165138Syongari 1129165138Syongari cinfo = (struct adv_ccb_info *)ccb->ccb_h.ccb_cinfo_ptr; 1130165138Syongari LIST_REMOVE(&ccb->ccb_h, sim_links.le); 1131165138Syongari untimeout(adv_timeout, ccb, ccb->ccb_h.timeout_ch); 1132165138Syongari if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 1133165138Syongari bus_dmasync_op_t op; 1134165138Syongari 1135165138Syongari if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 1136165138Syongari op = BUS_DMASYNC_POSTREAD; 1137165138Syongari else 1138165138Syongari op = BUS_DMASYNC_POSTWRITE; 1139165138Syongari bus_dmamap_sync(adv->buffer_dmat, cinfo->dmamap, op); 1140165138Syongari bus_dmamap_unload(adv->buffer_dmat, cinfo->dmamap); 1141165138Syongari } 1142165138Syongari 1143165138Syongari switch (done_stat) { 1144165138Syongari case QD_NO_ERROR: 1145165138Syongari if (host_stat == QHSTA_NO_ERROR) { 1146165138Syongari ccb->ccb_h.status = CAM_REQ_CMP; 1147165138Syongari break; 1148165138Syongari } 1149165138Syongari xpt_print_path(ccb->ccb_h.path); 1150165138Syongari printf("adv_done - queue done without error, " 1151165138Syongari "but host status non-zero(%x)\n", host_stat); 1152165138Syongari /*FALLTHROUGH*/ 1153165138Syongari case QD_WITH_ERROR: 1154165138Syongari switch (host_stat) { 1155165138Syongari case QHSTA_M_TARGET_STATUS_BUSY: 1156165138Syongari case QHSTA_M_BAD_QUEUE_FULL_OR_BUSY: 1157165138Syongari /* 1158165138Syongari * Assume that if we were a tagged transaction 1159165138Syongari * the target reported queue full. Otherwise, 1160165138Syongari * report busy. The firmware really should just 1161165138Syongari * pass the original status back up to us even 1162165138Syongari * if it thinks the target was in error for 1163165138Syongari * returning this status as no other transactions 1164165138Syongari * from this initiator are in effect, but this 1165165138Syongari * ignores multi-initiator setups and there is 1166165138Syongari * evidence that the firmware gets its per-device 1167165138Syongari * transaction counts screwed up occassionally. 1168165138Syongari */ 1169165138Syongari ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR; 1170165138Syongari if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0 1171165138Syongari && host_stat != QHSTA_M_TARGET_STATUS_BUSY) 1172165138Syongari scsi_status = SCSI_STATUS_QUEUE_FULL; 1173165138Syongari else 1174165138Syongari scsi_status = SCSI_STATUS_BUSY; 1175165138Syongari adv_abort_ccb(adv, ccb->ccb_h.target_id, 1176165138Syongari ccb->ccb_h.target_lun, 1177165138Syongari /*ccb*/NULL, CAM_REQUEUE_REQ, 1178165138Syongari /*queued_only*/TRUE); 1179165138Syongari /*FALLTHROUGH*/ 1180165138Syongari case QHSTA_M_NO_AUTO_REQ_SENSE: 1181165138Syongari case QHSTA_NO_ERROR: 1182165138Syongari ccb->csio.scsi_status = scsi_status; 1183165138Syongari switch (scsi_status) { 1184165138Syongari case SCSI_STATUS_CHECK_COND: 1185165138Syongari case SCSI_STATUS_CMD_TERMINATED: 1186165138Syongari ccb->ccb_h.status |= CAM_AUTOSNS_VALID; 1187165138Syongari /* Structure copy */ 1188165138Syongari ccb->csio.sense_data = 1189165138Syongari adv->sense_buffers[q_no - 1]; 1190165138Syongari /* FALLTHROUGH */ 1191165138Syongari case SCSI_STATUS_BUSY: 1192165138Syongari case SCSI_STATUS_RESERV_CONFLICT: 1193165138Syongari case SCSI_STATUS_QUEUE_FULL: 1194165138Syongari case SCSI_STATUS_COND_MET: 1195165138Syongari case SCSI_STATUS_INTERMED: 1196165138Syongari case SCSI_STATUS_INTERMED_COND_MET: 1197165138Syongari ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR; 1198165138Syongari break; 1199165138Syongari case SCSI_STATUS_OK: 1200165138Syongari ccb->ccb_h.status |= CAM_REQ_CMP; 1201165138Syongari break; 1202165138Syongari } 1203165138Syongari break; 1204165138Syongari case QHSTA_M_SEL_TIMEOUT: 1205165138Syongari ccb->ccb_h.status = CAM_SEL_TIMEOUT; 1206165138Syongari break; 1207165138Syongari case QHSTA_M_DATA_OVER_RUN: 1208165138Syongari ccb->ccb_h.status = CAM_DATA_RUN_ERR; 1209165138Syongari break; 1210165138Syongari case QHSTA_M_UNEXPECTED_BUS_FREE: 1211165138Syongari ccb->ccb_h.status = CAM_UNEXP_BUSFREE; 1212165138Syongari break; 1213165138Syongari case QHSTA_M_BAD_BUS_PHASE_SEQ: 1214165138Syongari ccb->ccb_h.status = CAM_SEQUENCE_FAIL; 1215165138Syongari break; 1216165138Syongari case QHSTA_M_BAD_CMPL_STATUS_IN: 1217165138Syongari /* No command complete after a status message */ 1218165138Syongari ccb->ccb_h.status = CAM_SEQUENCE_FAIL; 1219165138Syongari break; 1220165138Syongari case QHSTA_D_EXE_SCSI_Q_BUSY_TIMEOUT: 1221165138Syongari case QHSTA_M_WTM_TIMEOUT: 1222165138Syongari case QHSTA_M_HUNG_REQ_SCSI_BUS_RESET: 1223165138Syongari /* The SCSI bus hung in a phase */ 1224165138Syongari ccb->ccb_h.status = CAM_SEQUENCE_FAIL; 1225165138Syongari adv_reset_bus(adv, /*initiate_reset*/TRUE); 1226165138Syongari break; 1227165138Syongari case QHSTA_M_AUTO_REQ_SENSE_FAIL: 1228165138Syongari ccb->ccb_h.status = CAM_AUTOSENSE_FAIL; 1229165138Syongari break; 1230165138Syongari case QHSTA_D_QDONE_SG_LIST_CORRUPTED: 1231165138Syongari case QHSTA_D_ASC_DVC_ERROR_CODE_SET: 1232165138Syongari case QHSTA_D_HOST_ABORT_FAILED: 1233165138Syongari case QHSTA_D_EXE_SCSI_Q_FAILED: 1234165138Syongari case QHSTA_D_ASPI_NO_BUF_POOL: 1235165138Syongari case QHSTA_M_BAD_TAG_CODE: 1236165138Syongari case QHSTA_D_LRAM_CMP_ERROR: 1237165138Syongari case QHSTA_M_MICRO_CODE_ERROR_HALT: 1238165138Syongari default: 1239165138Syongari panic("%s: Unhandled Host status error %x", 1240165138Syongari adv_name(adv), host_stat); 1241165138Syongari /* NOTREACHED */ 1242165138Syongari } 1243165138Syongari break; 1244165138Syongari 1245165138Syongari case QD_ABORTED_BY_HOST: 1246165138Syongari /* Don't clobber any, more explicit, error codes we've set */ 1247165138Syongari if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) 1248165138Syongari ccb->ccb_h.status = CAM_REQ_ABORTED; 1249165138Syongari break; 1250165138Syongari 1251165138Syongari default: 1252165138Syongari xpt_print_path(ccb->ccb_h.path); 1253165138Syongari printf("adv_done - queue done with unknown status %x:%x\n", 1254165138Syongari done_stat, host_stat); 1255165138Syongari ccb->ccb_h.status = CAM_REQ_CMP_ERR; 1256165138Syongari break; 1257165138Syongari } 1258165138Syongari adv_clear_state(adv, ccb); 1259165138Syongari if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP 1260165138Syongari && (ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { 1261165138Syongari xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 1262165138Syongari ccb->ccb_h.status |= CAM_DEV_QFRZN; 1263165138Syongari } 1264165138Syongari adv_free_ccb_info(adv, cinfo); 1265165138Syongari /* 1266165138Syongari * Null this out so that we catch driver bugs that cause a 1267165138Syongari * ccb to be completed twice. 1268165138Syongari */ 1269165138Syongari ccb->ccb_h.ccb_cinfo_ptr = NULL; 1270165138Syongari ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 1271165138Syongari xpt_done(ccb); 1272165138Syongari} 1273165138Syongari 1274165138Syongari/* 1275165138Syongari * Function to poll for command completion when 1276165138Syongari * interrupts are disabled (crash dumps) 1277165138Syongari */ 1278165138Syongaristatic void 1279165138Syongariadv_poll(struct cam_sim *sim) 1280165138Syongari{ 1281165138Syongari adv_intr(cam_sim_softc(sim)); 1282165138Syongari} 1283165138Syongari 1284165138Syongari/* 1285165138Syongari * Attach all the sub-devices we can find 1286165138Syongari */ 1287165138Syongariint 1288165138Syongariadv_attach(adv) 1289165138Syongari struct adv_softc *adv; 1290165138Syongari{ 1291165138Syongari struct ccb_setasync csa; 1292165138Syongari struct cam_devq *devq; 1293165138Syongari int max_sg; 1294165138Syongari 1295165138Syongari /* 1296165138Syongari * Allocate an array of ccb mapping structures. We put the 1297165138Syongari * index of the ccb_info structure into the queue representing 1298165138Syongari * a transaction and use it for mapping the queue to the 1299165138Syongari * upper level SCSI transaction it represents. 1300165138Syongari */ 1301165138Syongari adv->ccb_infos = malloc(sizeof(*adv->ccb_infos) * adv->max_openings, 1302165138Syongari M_DEVBUF, M_NOWAIT); 1303165138Syongari 1304165138Syongari if (adv->ccb_infos == NULL) 1305165138Syongari return (ENOMEM); 1306165138Syongari 1307165138Syongari adv->init_level++; 1308165138Syongari 1309165138Syongari /* 1310165138Syongari * Create our DMA tags. These tags define the kinds of device 1311165138Syongari * accessible memory allocations and memory mappings we will 1312165138Syongari * need to perform during normal operation. 1313165138Syongari * 1314165138Syongari * Unless we need to further restrict the allocation, we rely 1315165138Syongari * on the restrictions of the parent dmat, hence the common 1316165138Syongari * use of MAXADDR and MAXSIZE. 1317165138Syongari * 1318165138Syongari * The ASC boards use chains of "queues" (the transactional 1319165138Syongari * resources on the board) to represent long S/G lists. 1320165138Syongari * The first queue represents the command and holds a 1321165138Syongari * single address and data pair. The queues that follow 1322165138Syongari * can each hold ADV_SG_LIST_PER_Q entries. Given the 1323165138Syongari * total number of queues, we can express the largest 1324165138Syongari * transaction we can map. We reserve a few queues for 1325165138Syongari * error recovery. Take those into account as well. 1326165138Syongari * 1327165138Syongari * There is a way to take an interrupt to download the 1328165138Syongari * next batch of S/G entries if there are more than 255 1329165138Syongari * of them (the counter in the queue structure is a u_int8_t). 1330165138Syongari * We don't use this feature, so limit the S/G list size 1331165138Syongari * accordingly. 1332165138Syongari */ 1333165138Syongari max_sg = (adv->max_openings - ADV_MIN_FREE_Q - 1) * ADV_SG_LIST_PER_Q; 1334165138Syongari if (max_sg > 255) 1335165138Syongari max_sg = 255; 1336165138Syongari 1337165138Syongari /* DMA tag for mapping buffers into device visible space. */ 1338165138Syongari if (bus_dma_tag_create( 1339165138Syongari /* parent */ adv->parent_dmat, 1340165138Syongari /* alignment */ 1, 1341165138Syongari /* boundary */ 0, 1342165138Syongari /* lowaddr */ BUS_SPACE_MAXADDR, 1343165138Syongari /* highaddr */ BUS_SPACE_MAXADDR, 1344165138Syongari /* filter */ NULL, 1345165138Syongari /* filterarg */ NULL, 1346165138Syongari /* maxsize */ MAXPHYS, 1347165138Syongari /* nsegments */ max_sg, 1348165138Syongari /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT, 1349165138Syongari /* flags */ BUS_DMA_ALLOCNOW, 1350165138Syongari &adv->buffer_dmat) != 0) { 1351165138Syongari return (ENXIO); 1352165138Syongari } 1353165138Syongari adv->init_level++; 1354165138Syongari 1355165138Syongari /* DMA tag for our sense buffers */ 1356165138Syongari if (bus_dma_tag_create( 1357165138Syongari /* parent */ adv->parent_dmat, 1358165138Syongari /* alignment */ 1, 1359165138Syongari /* boundary */ 0, 1360165138Syongari /* lowaddr */ BUS_SPACE_MAXADDR, 1361165138Syongari /* highaddr */ BUS_SPACE_MAXADDR, 1362165138Syongari /* filter */ NULL, 1363165138Syongari /* filterarg */ NULL, 1364165138Syongari /* maxsize */ sizeof(struct scsi_sense_data) * 1365165138Syongari adv->max_openings, 1366165138Syongari /* nsegments */ 1, 1367165138Syongari /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT, 1368165138Syongari /* flags */ 0, 1369165138Syongari &adv->sense_dmat) != 0) { 1370165138Syongari return (ENXIO); 1371165138Syongari } 1372165138Syongari 1373165138Syongari adv->init_level++; 1374165138Syongari 1375165138Syongari /* Allocation for our sense buffers */ 1376165138Syongari if (bus_dmamem_alloc(adv->sense_dmat, (void **)&adv->sense_buffers, 1377165138Syongari BUS_DMA_NOWAIT, &adv->sense_dmamap) != 0) { 1378165138Syongari return (ENOMEM); 1379165138Syongari } 1380165138Syongari 1381165138Syongari adv->init_level++; 1382165138Syongari 1383165138Syongari /* And permanently map them */ 1384165138Syongari bus_dmamap_load(adv->sense_dmat, adv->sense_dmamap, 1385165138Syongari adv->sense_buffers, 1386165138Syongari sizeof(struct scsi_sense_data)*adv->max_openings, 1387165138Syongari adv_map, &adv->sense_physbase, /*flags*/0); 1388165138Syongari 1389165138Syongari adv->init_level++; 1390165138Syongari 1391165138Syongari /* 1392165138Syongari * Fire up the chip 1393165138Syongari */ 1394165138Syongari if (adv_start_chip(adv) != 1) { 1395165138Syongari printf("adv%d: Unable to start on board processor. Aborting.\n", 1396165138Syongari adv->unit); 1397165138Syongari return (ENXIO); 1398165138Syongari } 1399165138Syongari 1400165138Syongari /* 1401165138Syongari * Create the device queue for our SIM. 1402165138Syongari */ 1403165138Syongari devq = cam_simq_alloc(adv->max_openings); 1404165138Syongari if (devq == NULL) 1405165138Syongari return (ENOMEM); 1406165138Syongari 1407165138Syongari /* 1408165138Syongari * Construct our SIM entry. 1409165138Syongari */ 1410165138Syongari adv->sim = cam_sim_alloc(adv_action, adv_poll, "adv", adv, adv->unit, 1411165138Syongari 1, adv->max_openings, devq); 1412165138Syongari if (adv->sim == NULL) 1413165138Syongari return (ENOMEM); 1414165138Syongari 1415165138Syongari /* 1416165138Syongari * Register the bus. 1417165138Syongari * 1418165138Syongari * XXX Twin Channel EISA Cards??? 1419165138Syongari */ 1420165138Syongari if (xpt_bus_register(adv->sim, 0) != CAM_SUCCESS) { 1421165138Syongari cam_sim_free(adv->sim, /*free devq*/TRUE); 1422165138Syongari return (ENXIO); 1423165138Syongari } 1424165138Syongari 1425165138Syongari if (xpt_create_path(&adv->path, /*periph*/NULL, cam_sim_path(adv->sim), 1426165138Syongari CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) 1427165138Syongari != CAM_REQ_CMP) { 1428165138Syongari xpt_bus_deregister(cam_sim_path(adv->sim)); 1429165138Syongari cam_sim_free(adv->sim, /*free devq*/TRUE); 1430165138Syongari return (ENXIO); 1431165138Syongari } 1432165138Syongari 1433165138Syongari xpt_setup_ccb(&csa.ccb_h, adv->path, /*priority*/5); 1434165138Syongari csa.ccb_h.func_code = XPT_SASYNC_CB; 1435165138Syongari csa.event_enable = AC_FOUND_DEVICE|AC_LOST_DEVICE; 1436165138Syongari csa.callback = advasync; 1437165138Syongari csa.callback_arg = adv; 1438165138Syongari xpt_action((union ccb *)&csa); 1439165138Syongari return (0); 1440165138Syongari} 1441165138Syongari