1139749Simp/*- 2218909Sbrucec * CAM SCSI interface for the Advanced Systems Inc. 340024Sgibbs * Second Generation SCSI controllers. 440024Sgibbs * 540024Sgibbs * Product specific probe and attach routines can be found in: 640024Sgibbs * 756979Sgibbs * adw_pci.c ABP[3]940UW, ABP950UW, ABP3940U2W 840024Sgibbs * 956979Sgibbs * Copyright (c) 1998, 1999, 2000 Justin Gibbs. 1040024Sgibbs * All rights reserved. 1140024Sgibbs * 1240024Sgibbs * Redistribution and use in source and binary forms, with or without 1340024Sgibbs * modification, are permitted provided that the following conditions 1440024Sgibbs * are met: 1540024Sgibbs * 1. Redistributions of source code must retain the above copyright 1640024Sgibbs * notice, this list of conditions, and the following disclaimer, 1756979Sgibbs * without modification. 1840024Sgibbs * 2. The name of the author may not be used to endorse or promote products 1940024Sgibbs * derived from this software without specific prior written permission. 2040024Sgibbs * 2140024Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2240024Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2340024Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2440024Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2540024Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2640024Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2740024Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2840024Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2940024Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3040024Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3140024Sgibbs * SUCH DAMAGE. 3240024Sgibbs */ 3340024Sgibbs/* 3440024Sgibbs * Ported from: 3540024Sgibbs * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters 3640024Sgibbs * 3740024Sgibbs * Copyright (c) 1995-1998 Advanced System Products, Inc. 3840024Sgibbs * All Rights Reserved. 3940024Sgibbs * 4040024Sgibbs * Redistribution and use in source and binary forms, with or without 4140024Sgibbs * modification, are permitted provided that redistributions of source 4240024Sgibbs * code retain the above copyright notice and this comment without 4340024Sgibbs * modification. 4440024Sgibbs */ 4540024Sgibbs 46119418Sobrien#include <sys/cdefs.h> 47119418Sobrien__FBSDID("$FreeBSD: stable/11/sys/dev/advansys/adwcam.c 335137 2018-06-14 14:45:08Z mav $"); 48119418Sobrien 4940024Sgibbs#include <sys/param.h> 50241588Sjhb#include <sys/conf.h> 5140024Sgibbs#include <sys/systm.h> 5240024Sgibbs#include <sys/kernel.h> 5340024Sgibbs#include <sys/malloc.h> 54117126Sscottl#include <sys/lock.h> 55165102Smjacob#include <sys/module.h> 56117126Sscottl#include <sys/mutex.h> 5756979Sgibbs#include <sys/bus.h> 5840024Sgibbs 5940024Sgibbs#include <machine/bus.h> 6056979Sgibbs#include <machine/resource.h> 6140024Sgibbs 6256979Sgibbs#include <sys/rman.h> 6356979Sgibbs 6440024Sgibbs#include <cam/cam.h> 6540024Sgibbs#include <cam/cam_ccb.h> 6640024Sgibbs#include <cam/cam_sim.h> 6740024Sgibbs#include <cam/cam_xpt_sim.h> 6840024Sgibbs#include <cam/cam_debug.h> 6940024Sgibbs 7040024Sgibbs#include <cam/scsi/scsi_message.h> 7140024Sgibbs 7240024Sgibbs#include <dev/advansys/adwvar.h> 7340024Sgibbs 7440024Sgibbs/* Definitions for our use of the SIM private CCB area */ 7540024Sgibbs#define ccb_acb_ptr spriv_ptr0 7640024Sgibbs#define ccb_adw_ptr spriv_ptr1 7740024Sgibbs 7840024Sgibbsstatic __inline struct acb* adwgetacb(struct adw_softc *adw); 7940024Sgibbsstatic __inline void adwfreeacb(struct adw_softc *adw, 8040024Sgibbs struct acb *acb); 8140024Sgibbs 8240024Sgibbsstatic void adwmapmem(void *arg, bus_dma_segment_t *segs, 8340024Sgibbs int nseg, int error); 8440024Sgibbsstatic struct sg_map_node* 8540024Sgibbs adwallocsgmap(struct adw_softc *adw); 8640024Sgibbsstatic int adwallocacbs(struct adw_softc *adw); 8740024Sgibbs 8840024Sgibbsstatic void adwexecuteacb(void *arg, bus_dma_segment_t *dm_segs, 8940024Sgibbs int nseg, int error); 9040024Sgibbsstatic void adw_action(struct cam_sim *sim, union ccb *ccb); 91241588Sjhbstatic void adw_intr_locked(struct adw_softc *adw); 9240024Sgibbsstatic void adw_poll(struct cam_sim *sim); 9340024Sgibbsstatic void adw_async(void *callback_arg, u_int32_t code, 9440024Sgibbs struct cam_path *path, void *arg); 9540024Sgibbsstatic void adwprocesserror(struct adw_softc *adw, struct acb *acb); 9640024Sgibbsstatic void adwtimeout(void *arg); 9740024Sgibbsstatic void adw_handle_device_reset(struct adw_softc *adw, 9840024Sgibbs u_int target); 9940024Sgibbsstatic void adw_handle_bus_reset(struct adw_softc *adw, 10040024Sgibbs int initiated); 10140024Sgibbs 10240024Sgibbsstatic __inline struct acb* 10340024Sgibbsadwgetacb(struct adw_softc *adw) 10440024Sgibbs{ 10540024Sgibbs struct acb* acb; 10640024Sgibbs 107241588Sjhb if (!dumping) 108241588Sjhb mtx_assert(&adw->lock, MA_OWNED); 10940024Sgibbs if ((acb = SLIST_FIRST(&adw->free_acb_list)) != NULL) { 11040024Sgibbs SLIST_REMOVE_HEAD(&adw->free_acb_list, links); 11140024Sgibbs } else if (adw->num_acbs < adw->max_acbs) { 11240024Sgibbs adwallocacbs(adw); 11340024Sgibbs acb = SLIST_FIRST(&adw->free_acb_list); 11440024Sgibbs if (acb == NULL) 115241588Sjhb device_printf(adw->device, "Can't malloc ACB\n"); 11640024Sgibbs else { 11740024Sgibbs SLIST_REMOVE_HEAD(&adw->free_acb_list, links); 11840024Sgibbs } 11940024Sgibbs } 12040024Sgibbs 12140024Sgibbs return (acb); 12240024Sgibbs} 12340024Sgibbs 12440024Sgibbsstatic __inline void 12540024Sgibbsadwfreeacb(struct adw_softc *adw, struct acb *acb) 12640024Sgibbs{ 12740024Sgibbs 128241588Sjhb if (!dumping) 129241588Sjhb mtx_assert(&adw->lock, MA_OWNED); 13040024Sgibbs if ((acb->state & ACB_ACTIVE) != 0) 13140024Sgibbs LIST_REMOVE(&acb->ccb->ccb_h, sim_links.le); 13240024Sgibbs if ((acb->state & ACB_RELEASE_SIMQ) != 0) 13340024Sgibbs acb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 13440024Sgibbs else if ((adw->state & ADW_RESOURCE_SHORTAGE) != 0 13540024Sgibbs && (acb->ccb->ccb_h.status & CAM_RELEASE_SIMQ) == 0) { 13640024Sgibbs acb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 13740024Sgibbs adw->state &= ~ADW_RESOURCE_SHORTAGE; 13840024Sgibbs } 13940024Sgibbs acb->state = ACB_FREE; 14040024Sgibbs SLIST_INSERT_HEAD(&adw->free_acb_list, acb, links); 14140024Sgibbs} 14240024Sgibbs 14340024Sgibbsstatic void 14440024Sgibbsadwmapmem(void *arg, bus_dma_segment_t *segs, int nseg, int error) 14540024Sgibbs{ 14640024Sgibbs bus_addr_t *busaddrp; 14740024Sgibbs 14840024Sgibbs busaddrp = (bus_addr_t *)arg; 14940024Sgibbs *busaddrp = segs->ds_addr; 15040024Sgibbs} 15140024Sgibbs 15240024Sgibbsstatic struct sg_map_node * 15340024Sgibbsadwallocsgmap(struct adw_softc *adw) 15440024Sgibbs{ 15540024Sgibbs struct sg_map_node *sg_map; 15640024Sgibbs 15740024Sgibbs sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT); 15840024Sgibbs 15940024Sgibbs if (sg_map == NULL) 16040024Sgibbs return (NULL); 16140024Sgibbs 16240024Sgibbs /* Allocate S/G space for the next batch of ACBS */ 16340024Sgibbs if (bus_dmamem_alloc(adw->sg_dmat, (void **)&sg_map->sg_vaddr, 16440024Sgibbs BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) { 16540024Sgibbs free(sg_map, M_DEVBUF); 16640024Sgibbs return (NULL); 16740024Sgibbs } 16840024Sgibbs 16940024Sgibbs SLIST_INSERT_HEAD(&adw->sg_maps, sg_map, links); 17040024Sgibbs 17140024Sgibbs bus_dmamap_load(adw->sg_dmat, sg_map->sg_dmamap, sg_map->sg_vaddr, 17240024Sgibbs PAGE_SIZE, adwmapmem, &sg_map->sg_physaddr, /*flags*/0); 17340024Sgibbs 17440024Sgibbs bzero(sg_map->sg_vaddr, PAGE_SIZE); 17540024Sgibbs return (sg_map); 17640024Sgibbs} 17740024Sgibbs 17840024Sgibbs/* 17940024Sgibbs * Allocate another chunk of CCB's. Return count of entries added. 18040024Sgibbs */ 18140024Sgibbsstatic int 18240024Sgibbsadwallocacbs(struct adw_softc *adw) 18340024Sgibbs{ 18440024Sgibbs struct acb *next_acb; 18540024Sgibbs struct sg_map_node *sg_map; 18640024Sgibbs bus_addr_t busaddr; 18740024Sgibbs struct adw_sg_block *blocks; 18840024Sgibbs int newcount; 18940024Sgibbs int i; 19040024Sgibbs 19140024Sgibbs next_acb = &adw->acbs[adw->num_acbs]; 19240024Sgibbs sg_map = adwallocsgmap(adw); 19340024Sgibbs 19440024Sgibbs if (sg_map == NULL) 19540024Sgibbs return (0); 19640024Sgibbs 19740024Sgibbs blocks = sg_map->sg_vaddr; 19840024Sgibbs busaddr = sg_map->sg_physaddr; 19940024Sgibbs 20040024Sgibbs newcount = (PAGE_SIZE / (ADW_SG_BLOCKCNT * sizeof(*blocks))); 20140024Sgibbs for (i = 0; adw->num_acbs < adw->max_acbs && i < newcount; i++) { 20240024Sgibbs int error; 20340024Sgibbs 20440024Sgibbs error = bus_dmamap_create(adw->buffer_dmat, /*flags*/0, 20540024Sgibbs &next_acb->dmamap); 20640024Sgibbs if (error != 0) 20740024Sgibbs break; 20856979Sgibbs next_acb->queue.scsi_req_baddr = acbvtob(adw, next_acb); 20956979Sgibbs next_acb->queue.scsi_req_bo = acbvtobo(adw, next_acb); 21056979Sgibbs next_acb->queue.sense_baddr = 21156979Sgibbs acbvtob(adw, next_acb) + offsetof(struct acb, sense_data); 21240024Sgibbs next_acb->sg_blocks = blocks; 21340024Sgibbs next_acb->sg_busaddr = busaddr; 21440024Sgibbs next_acb->state = ACB_FREE; 215241588Sjhb callout_init_mtx(&next_acb->timer, &adw->lock, 0); 21640024Sgibbs SLIST_INSERT_HEAD(&adw->free_acb_list, next_acb, links); 21740024Sgibbs blocks += ADW_SG_BLOCKCNT; 21840024Sgibbs busaddr += ADW_SG_BLOCKCNT * sizeof(*blocks); 21940024Sgibbs next_acb++; 22040024Sgibbs adw->num_acbs++; 22140024Sgibbs } 22240024Sgibbs return (i); 22340024Sgibbs} 22440024Sgibbs 22540024Sgibbsstatic void 22640024Sgibbsadwexecuteacb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 22740024Sgibbs{ 22840024Sgibbs struct acb *acb; 22940024Sgibbs union ccb *ccb; 23040024Sgibbs struct adw_softc *adw; 23140024Sgibbs 23240024Sgibbs acb = (struct acb *)arg; 23340024Sgibbs ccb = acb->ccb; 23440024Sgibbs adw = (struct adw_softc *)ccb->ccb_h.ccb_adw_ptr; 23540024Sgibbs 236241588Sjhb if (!dumping) 237241588Sjhb mtx_assert(&adw->lock, MA_OWNED); 23840024Sgibbs if (error != 0) { 23940024Sgibbs if (error != EFBIG) 240241588Sjhb device_printf(adw->device, "Unexepected error 0x%x " 241241588Sjhb "returned from bus_dmamap_load\n", error); 24240024Sgibbs if (ccb->ccb_h.status == CAM_REQ_INPROG) { 24340024Sgibbs xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 24440024Sgibbs ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN; 24540024Sgibbs } 24640024Sgibbs adwfreeacb(adw, acb); 24740024Sgibbs xpt_done(ccb); 24840024Sgibbs return; 24940024Sgibbs } 25040024Sgibbs 25140024Sgibbs if (nseg != 0) { 252115343Sscottl bus_dmasync_op_t op; 25340024Sgibbs 25440024Sgibbs acb->queue.data_addr = dm_segs[0].ds_addr; 25540024Sgibbs acb->queue.data_cnt = ccb->csio.dxfer_len; 25640024Sgibbs if (nseg > 1) { 25740024Sgibbs struct adw_sg_block *sg_block; 25840024Sgibbs struct adw_sg_elm *sg; 25940024Sgibbs bus_addr_t sg_busaddr; 26040024Sgibbs u_int sg_index; 26140024Sgibbs bus_dma_segment_t *end_seg; 26240024Sgibbs 26340024Sgibbs end_seg = dm_segs + nseg; 26440024Sgibbs 26540024Sgibbs sg_busaddr = acb->sg_busaddr; 26640024Sgibbs sg_index = 0; 26740024Sgibbs /* Copy the segments into our SG list */ 26840024Sgibbs for (sg_block = acb->sg_blocks;; sg_block++) { 26956979Sgibbs u_int i; 27040024Sgibbs 27140024Sgibbs sg = sg_block->sg_list; 27256979Sgibbs for (i = 0; i < ADW_NO_OF_SG_PER_BLOCK; i++) { 27356979Sgibbs if (dm_segs >= end_seg) 27456979Sgibbs break; 27556979Sgibbs 27640024Sgibbs sg->sg_addr = dm_segs->ds_addr; 27740024Sgibbs sg->sg_count = dm_segs->ds_len; 27840024Sgibbs sg++; 27940024Sgibbs dm_segs++; 28040024Sgibbs } 28156979Sgibbs sg_block->sg_cnt = i; 28256979Sgibbs sg_index += i; 28340024Sgibbs if (dm_segs == end_seg) { 28440024Sgibbs sg_block->sg_busaddr_next = 0; 28540024Sgibbs break; 28640024Sgibbs } else { 28740024Sgibbs sg_busaddr += 28840024Sgibbs sizeof(struct adw_sg_block); 28940024Sgibbs sg_block->sg_busaddr_next = sg_busaddr; 29040024Sgibbs } 29140024Sgibbs } 29240024Sgibbs acb->queue.sg_real_addr = acb->sg_busaddr; 29340024Sgibbs } else { 29440024Sgibbs acb->queue.sg_real_addr = 0; 29540024Sgibbs } 29640024Sgibbs 29740024Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 29840024Sgibbs op = BUS_DMASYNC_PREREAD; 29940024Sgibbs else 30040024Sgibbs op = BUS_DMASYNC_PREWRITE; 30140024Sgibbs 30240024Sgibbs bus_dmamap_sync(adw->buffer_dmat, acb->dmamap, op); 30340024Sgibbs 30440024Sgibbs } else { 30540024Sgibbs acb->queue.data_addr = 0; 30640024Sgibbs acb->queue.data_cnt = 0; 30740024Sgibbs acb->queue.sg_real_addr = 0; 30840024Sgibbs } 30940024Sgibbs 31040024Sgibbs /* 31140024Sgibbs * Last time we need to check if this CCB needs to 31240024Sgibbs * be aborted. 31340024Sgibbs */ 31440024Sgibbs if (ccb->ccb_h.status != CAM_REQ_INPROG) { 31540024Sgibbs if (nseg != 0) 31640024Sgibbs bus_dmamap_unload(adw->buffer_dmat, acb->dmamap); 31740024Sgibbs adwfreeacb(adw, acb); 31840024Sgibbs xpt_done(ccb); 31940024Sgibbs return; 32040024Sgibbs } 32157679Sgibbs 32240024Sgibbs acb->state |= ACB_ACTIVE; 32340024Sgibbs ccb->ccb_h.status |= CAM_SIM_QUEUED; 32440024Sgibbs LIST_INSERT_HEAD(&adw->pending_ccbs, &ccb->ccb_h, sim_links.le); 325274819Ssmh callout_reset_sbt(&acb->timer, SBT_1MS * ccb->ccb_h.timeout, 0, 326274819Ssmh adwtimeout, acb, 0); 32740024Sgibbs 32856979Sgibbs adw_send_acb(adw, acb, acbvtob(adw, acb)); 32940024Sgibbs} 33040024Sgibbs 33140024Sgibbsstatic void 33240024Sgibbsadw_action(struct cam_sim *sim, union ccb *ccb) 33340024Sgibbs{ 33440024Sgibbs struct adw_softc *adw; 33540024Sgibbs 33640024Sgibbs CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("adw_action\n")); 33740024Sgibbs 33840024Sgibbs adw = (struct adw_softc *)cam_sim_softc(sim); 339241588Sjhb if (!dumping) 340241588Sjhb mtx_assert(&adw->lock, MA_OWNED); 34140024Sgibbs 34240024Sgibbs switch (ccb->ccb_h.func_code) { 34340024Sgibbs /* Common cases first */ 34440024Sgibbs case XPT_SCSI_IO: /* Execute the requested I/O operation */ 34540024Sgibbs { 34640024Sgibbs struct ccb_scsiio *csio; 34740024Sgibbs struct acb *acb; 348246713Skib int error; 34940024Sgibbs 35040024Sgibbs csio = &ccb->csio; 35156979Sgibbs 35240024Sgibbs /* Max supported CDB length is 12 bytes */ 35340024Sgibbs if (csio->cdb_len > 12) { 35440024Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 35540024Sgibbs xpt_done(ccb); 35640024Sgibbs return; 35740024Sgibbs } 35840024Sgibbs 35940024Sgibbs if ((acb = adwgetacb(adw)) == NULL) { 36040024Sgibbs adw->state |= ADW_RESOURCE_SHORTAGE; 36140024Sgibbs xpt_freeze_simq(sim, /*count*/1); 36240024Sgibbs ccb->ccb_h.status = CAM_REQUEUE_REQ; 36340024Sgibbs xpt_done(ccb); 36440024Sgibbs return; 36540024Sgibbs } 36640024Sgibbs 36756979Sgibbs /* Link acb and ccb so we can find one from the other */ 36840024Sgibbs acb->ccb = ccb; 36940024Sgibbs ccb->ccb_h.ccb_acb_ptr = acb; 37040024Sgibbs ccb->ccb_h.ccb_adw_ptr = adw; 37140024Sgibbs 37240024Sgibbs acb->queue.cntl = 0; 37356979Sgibbs acb->queue.target_cmd = 0; 37440024Sgibbs acb->queue.target_id = ccb->ccb_h.target_id; 37540024Sgibbs acb->queue.target_lun = ccb->ccb_h.target_lun; 37640024Sgibbs 37756979Sgibbs acb->queue.mflag = 0; 37840024Sgibbs acb->queue.sense_len = 37940024Sgibbs MIN(csio->sense_len, sizeof(acb->sense_data)); 38040024Sgibbs acb->queue.cdb_len = csio->cdb_len; 38156979Sgibbs if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0) { 38256979Sgibbs switch (csio->tag_action) { 38356979Sgibbs case MSG_SIMPLE_Q_TAG: 38457679Sgibbs acb->queue.scsi_cntl = ADW_QSC_SIMPLE_Q_TAG; 38556979Sgibbs break; 38656979Sgibbs case MSG_HEAD_OF_Q_TAG: 38756979Sgibbs acb->queue.scsi_cntl = ADW_QSC_HEAD_OF_Q_TAG; 38856979Sgibbs break; 38956979Sgibbs case MSG_ORDERED_Q_TAG: 39056979Sgibbs acb->queue.scsi_cntl = ADW_QSC_ORDERED_Q_TAG; 39156979Sgibbs break; 39257679Sgibbs default: 39357679Sgibbs acb->queue.scsi_cntl = ADW_QSC_NO_TAGMSG; 39457679Sgibbs break; 39556979Sgibbs } 39656979Sgibbs } else 39756979Sgibbs acb->queue.scsi_cntl = ADW_QSC_NO_TAGMSG; 39840024Sgibbs 39956979Sgibbs if ((ccb->ccb_h.flags & CAM_DIS_DISCONNECT) != 0) 40056979Sgibbs acb->queue.scsi_cntl |= ADW_QSC_NO_DISC; 40140024Sgibbs 40240024Sgibbs acb->queue.done_status = 0; 40340024Sgibbs acb->queue.scsi_status = 0; 40440024Sgibbs acb->queue.host_status = 0; 40556979Sgibbs acb->queue.sg_wk_ix = 0; 40640024Sgibbs if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) { 40740024Sgibbs if ((ccb->ccb_h.flags & CAM_CDB_PHYS) == 0) { 40840024Sgibbs bcopy(csio->cdb_io.cdb_ptr, 40940024Sgibbs acb->queue.cdb, csio->cdb_len); 41040024Sgibbs } else { 41140024Sgibbs /* I guess I could map it in... */ 41240024Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 41340024Sgibbs adwfreeacb(adw, acb); 41440024Sgibbs xpt_done(ccb); 41540024Sgibbs return; 41640024Sgibbs } 41740024Sgibbs } else { 41840024Sgibbs bcopy(csio->cdb_io.cdb_bytes, 41940024Sgibbs acb->queue.cdb, csio->cdb_len); 42040024Sgibbs } 42140024Sgibbs 422246713Skib error = bus_dmamap_load_ccb(adw->buffer_dmat, 423246713Skib acb->dmamap, 424246713Skib ccb, 425246713Skib adwexecuteacb, 426246713Skib acb, /*flags*/0); 427246713Skib if (error == EINPROGRESS) { 428246713Skib /* 429246713Skib * So as to maintain ordering, freeze the controller 430246713Skib * queue until our mapping is returned. 431246713Skib */ 432246713Skib xpt_freeze_simq(sim, 1); 433246713Skib acb->state |= CAM_RELEASE_SIMQ; 43440024Sgibbs } 43540024Sgibbs break; 43640024Sgibbs } 43740024Sgibbs case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ 43840024Sgibbs { 43940024Sgibbs adw_idle_cmd_status_t status; 44040024Sgibbs 44157679Sgibbs status = adw_idle_cmd_send(adw, ADW_IDLE_CMD_DEVICE_RESET, 44257679Sgibbs ccb->ccb_h.target_id); 44340024Sgibbs if (status == ADW_IDLE_CMD_SUCCESS) { 44440024Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 44540024Sgibbs if (bootverbose) { 44640024Sgibbs xpt_print_path(ccb->ccb_h.path); 44740024Sgibbs printf("BDR Delivered\n"); 44840024Sgibbs } 44940024Sgibbs } else 45040024Sgibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 45140024Sgibbs xpt_done(ccb); 45240024Sgibbs break; 45340024Sgibbs } 45440024Sgibbs case XPT_ABORT: /* Abort the specified CCB */ 45540024Sgibbs /* XXX Implement */ 45640024Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 45740024Sgibbs xpt_done(ccb); 45840024Sgibbs break; 45940024Sgibbs case XPT_SET_TRAN_SETTINGS: 46040024Sgibbs { 461163816Smjacob struct ccb_trans_settings_scsi *scsi; 462163816Smjacob struct ccb_trans_settings_spi *spi; 46340024Sgibbs struct ccb_trans_settings *cts; 46440024Sgibbs u_int target_mask; 46540024Sgibbs 46640024Sgibbs cts = &ccb->cts; 46740024Sgibbs target_mask = 0x01 << ccb->ccb_h.target_id; 46840024Sgibbs 469163816Smjacob scsi = &cts->proto_specific.scsi; 470163816Smjacob spi = &cts->xport_specific.spi; 471163816Smjacob if (cts->type == CTS_TYPE_CURRENT_SETTINGS) { 472163816Smjacob u_int sdtrdone; 473163816Smjacob 474163816Smjacob sdtrdone = adw_lram_read_16(adw, ADW_MC_SDTR_DONE); 475163816Smjacob if ((spi->valid & CTS_SPI_VALID_DISC) != 0) { 476163816Smjacob u_int discenb; 477163816Smjacob 478163816Smjacob discenb = 479163816Smjacob adw_lram_read_16(adw, ADW_MC_DISC_ENABLE); 480163816Smjacob 481163816Smjacob if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0) 482163816Smjacob discenb |= target_mask; 483163816Smjacob else 484163816Smjacob discenb &= ~target_mask; 485163816Smjacob 486163816Smjacob adw_lram_write_16(adw, ADW_MC_DISC_ENABLE, 487163816Smjacob discenb); 488163816Smjacob } 489163816Smjacob 490163816Smjacob if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) { 491163816Smjacob 492163816Smjacob if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) 493163816Smjacob adw->tagenb |= target_mask; 494163816Smjacob else 495163816Smjacob adw->tagenb &= ~target_mask; 496163816Smjacob } 497163816Smjacob 498163816Smjacob if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) { 499163816Smjacob u_int wdtrenb_orig; 500163816Smjacob u_int wdtrenb; 501163816Smjacob u_int wdtrdone; 502163816Smjacob 503163816Smjacob wdtrenb_orig = 504163816Smjacob adw_lram_read_16(adw, ADW_MC_WDTR_ABLE); 505163816Smjacob wdtrenb = wdtrenb_orig; 506163816Smjacob wdtrdone = adw_lram_read_16(adw, 507163816Smjacob ADW_MC_WDTR_DONE); 508163816Smjacob switch (spi->bus_width) { 509163816Smjacob case MSG_EXT_WDTR_BUS_32_BIT: 510163816Smjacob case MSG_EXT_WDTR_BUS_16_BIT: 511163816Smjacob wdtrenb |= target_mask; 512163816Smjacob break; 513163816Smjacob case MSG_EXT_WDTR_BUS_8_BIT: 514163816Smjacob default: 515163816Smjacob wdtrenb &= ~target_mask; 516163816Smjacob break; 517163816Smjacob } 518163816Smjacob if (wdtrenb != wdtrenb_orig) { 519163816Smjacob adw_lram_write_16(adw, 520163816Smjacob ADW_MC_WDTR_ABLE, 521163816Smjacob wdtrenb); 522163816Smjacob wdtrdone &= ~target_mask; 523163816Smjacob adw_lram_write_16(adw, 524163816Smjacob ADW_MC_WDTR_DONE, 525163816Smjacob wdtrdone); 526163816Smjacob /* Wide negotiation forces async */ 527163816Smjacob sdtrdone &= ~target_mask; 528163816Smjacob adw_lram_write_16(adw, 529163816Smjacob ADW_MC_SDTR_DONE, 530163816Smjacob sdtrdone); 531163816Smjacob } 532163816Smjacob } 533163816Smjacob 534163816Smjacob if (((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0) 535163816Smjacob || ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0)) { 536163816Smjacob u_int sdtr_orig; 537163816Smjacob u_int sdtr; 538163816Smjacob u_int sdtrable_orig; 539163816Smjacob u_int sdtrable; 540163816Smjacob 541163816Smjacob sdtr = adw_get_chip_sdtr(adw, 542163816Smjacob ccb->ccb_h.target_id); 543163816Smjacob sdtr_orig = sdtr; 544163816Smjacob sdtrable = adw_lram_read_16(adw, 545163816Smjacob ADW_MC_SDTR_ABLE); 546163816Smjacob sdtrable_orig = sdtrable; 547163816Smjacob 548163816Smjacob if ((spi->valid 549163816Smjacob & CTS_SPI_VALID_SYNC_RATE) != 0) { 550163816Smjacob 551163816Smjacob sdtr = 552163816Smjacob adw_find_sdtr(adw, 553163816Smjacob spi->sync_period); 554163816Smjacob } 555163816Smjacob 556163816Smjacob if ((spi->valid 557163816Smjacob & CTS_SPI_VALID_SYNC_OFFSET) != 0) { 558163816Smjacob if (spi->sync_offset == 0) 559163816Smjacob sdtr = ADW_MC_SDTR_ASYNC; 560163816Smjacob } 561163816Smjacob 562163816Smjacob if (sdtr == ADW_MC_SDTR_ASYNC) 563163816Smjacob sdtrable &= ~target_mask; 564163816Smjacob else 565163816Smjacob sdtrable |= target_mask; 566163816Smjacob if (sdtr != sdtr_orig 567163816Smjacob || sdtrable != sdtrable_orig) { 568163816Smjacob adw_set_chip_sdtr(adw, 569163816Smjacob ccb->ccb_h.target_id, 570163816Smjacob sdtr); 571163816Smjacob sdtrdone &= ~target_mask; 572163816Smjacob adw_lram_write_16(adw, ADW_MC_SDTR_ABLE, 573163816Smjacob sdtrable); 574163816Smjacob adw_lram_write_16(adw, ADW_MC_SDTR_DONE, 575163816Smjacob sdtrdone); 576163816Smjacob 577163816Smjacob } 578163816Smjacob } 579163816Smjacob } 58040024Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 58140024Sgibbs xpt_done(ccb); 58240024Sgibbs break; 58340024Sgibbs } 58440024Sgibbs case XPT_GET_TRAN_SETTINGS: 58540024Sgibbs /* Get default/user set transfer settings for the target */ 58640024Sgibbs { 587163816Smjacob struct ccb_trans_settings_scsi *scsi; 588163816Smjacob struct ccb_trans_settings_spi *spi; 58940024Sgibbs struct ccb_trans_settings *cts; 59040024Sgibbs u_int target_mask; 59140024Sgibbs 59240024Sgibbs cts = &ccb->cts; 59340024Sgibbs target_mask = 0x01 << ccb->ccb_h.target_id; 594163816Smjacob cts->protocol = PROTO_SCSI; 595163816Smjacob cts->protocol_version = SCSI_REV_2; 596163816Smjacob cts->transport = XPORT_SPI; 597163816Smjacob cts->transport_version = 2; 598163816Smjacob 599163816Smjacob scsi = &cts->proto_specific.scsi; 600163816Smjacob spi = &cts->xport_specific.spi; 601163816Smjacob if (cts->type == CTS_TYPE_CURRENT_SETTINGS) { 60256979Sgibbs u_int mc_sdtr; 60356979Sgibbs 604163816Smjacob spi->flags = 0; 605163816Smjacob if ((adw->user_discenb & target_mask) != 0) 606163816Smjacob spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 607163816Smjacob 608163816Smjacob if ((adw->user_tagenb & target_mask) != 0) 609163816Smjacob scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 610163816Smjacob 611163816Smjacob if ((adw->user_wdtr & target_mask) != 0) 612163816Smjacob spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 613163816Smjacob else 614163816Smjacob spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 615163816Smjacob 616163816Smjacob mc_sdtr = adw_get_user_sdtr(adw, ccb->ccb_h.target_id); 617163816Smjacob spi->sync_period = adw_find_period(adw, mc_sdtr); 618163816Smjacob if (spi->sync_period != 0) 619163816Smjacob spi->sync_offset = 15; /* XXX ??? */ 620163816Smjacob else 621163816Smjacob spi->sync_offset = 0; 622163816Smjacob 623163816Smjacob 624163816Smjacob } else { 625163816Smjacob u_int targ_tinfo; 626163816Smjacob 627163816Smjacob spi->flags = 0; 628163816Smjacob if ((adw_lram_read_16(adw, ADW_MC_DISC_ENABLE) 629163816Smjacob & target_mask) != 0) 630163816Smjacob spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 631163816Smjacob 632163816Smjacob if ((adw->tagenb & target_mask) != 0) 633163816Smjacob scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 634163816Smjacob 635163816Smjacob targ_tinfo = 636163816Smjacob adw_lram_read_16(adw, 637163816Smjacob ADW_MC_DEVICE_HSHK_CFG_TABLE 638163816Smjacob + (2 * ccb->ccb_h.target_id)); 639163816Smjacob 640163816Smjacob if ((targ_tinfo & ADW_HSHK_CFG_WIDE_XFR) != 0) 641163816Smjacob spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 642163816Smjacob else 643163816Smjacob spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 644163816Smjacob 645163816Smjacob spi->sync_period = 646163816Smjacob adw_hshk_cfg_period_factor(targ_tinfo); 647163816Smjacob 648163816Smjacob spi->sync_offset = targ_tinfo & ADW_HSHK_CFG_OFFSET; 649163816Smjacob if (spi->sync_period == 0) 650163816Smjacob spi->sync_offset = 0; 651163816Smjacob 652163816Smjacob if (spi->sync_offset == 0) 653163816Smjacob spi->sync_period = 0; 654163816Smjacob } 655163816Smjacob 656163816Smjacob spi->valid = CTS_SPI_VALID_SYNC_RATE 657163816Smjacob | CTS_SPI_VALID_SYNC_OFFSET 658163816Smjacob | CTS_SPI_VALID_BUS_WIDTH 659163816Smjacob | CTS_SPI_VALID_DISC; 660163816Smjacob scsi->valid = CTS_SCSI_VALID_TQ; 66140024Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 66240024Sgibbs xpt_done(ccb); 66340024Sgibbs break; 66440024Sgibbs } 66540024Sgibbs case XPT_CALC_GEOMETRY: 66640024Sgibbs { 66740024Sgibbs /* 66840024Sgibbs * XXX Use Adaptec translation until I find out how to 66940024Sgibbs * get this information from the card. 67040024Sgibbs */ 671116351Snjl cam_calc_geometry(&ccb->ccg, /*extended*/1); 67240024Sgibbs xpt_done(ccb); 67340024Sgibbs break; 67440024Sgibbs } 67540024Sgibbs case XPT_RESET_BUS: /* Reset the specified SCSI bus */ 67640024Sgibbs { 67757679Sgibbs int failure; 67840024Sgibbs 67957679Sgibbs failure = adw_reset_bus(adw); 68057679Sgibbs if (failure != 0) { 68140024Sgibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 68257679Sgibbs } else { 68357679Sgibbs if (bootverbose) { 68457679Sgibbs xpt_print_path(adw->path); 68557679Sgibbs printf("Bus Reset Delivered\n"); 68657679Sgibbs } 68757679Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 68856979Sgibbs } 68940024Sgibbs xpt_done(ccb); 69040024Sgibbs break; 69140024Sgibbs } 69240024Sgibbs case XPT_TERM_IO: /* Terminate the I/O process */ 69340024Sgibbs /* XXX Implement */ 69440024Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 69540024Sgibbs xpt_done(ccb); 69640024Sgibbs break; 69740024Sgibbs case XPT_PATH_INQ: /* Path routing inquiry */ 69840024Sgibbs { 69940024Sgibbs struct ccb_pathinq *cpi = &ccb->cpi; 70040024Sgibbs 70140024Sgibbs cpi->version_num = 1; 70240024Sgibbs cpi->hba_inquiry = PI_WIDE_16|PI_SDTR_ABLE|PI_TAG_ABLE; 70340024Sgibbs cpi->target_sprt = 0; 70440024Sgibbs cpi->hba_misc = 0; 70540024Sgibbs cpi->hba_eng_cnt = 0; 70640024Sgibbs cpi->max_target = ADW_MAX_TID; 70740024Sgibbs cpi->max_lun = ADW_MAX_LUN; 70840024Sgibbs cpi->initiator_id = adw->initiator_id; 70940024Sgibbs cpi->bus_id = cam_sim_bus(sim); 71046581Sken cpi->base_transfer_speed = 3300; 711315812Smav strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 712315812Smav strlcpy(cpi->hba_vid, "AdvanSys", HBA_IDLEN); 713315812Smav strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 71440024Sgibbs cpi->unit_number = cam_sim_unit(sim); 715335137Smav cpi->transport = XPORT_SPI; 716335137Smav cpi->transport_version = 2; 717335137Smav cpi->protocol = PROTO_SCSI; 718335137Smav cpi->protocol_version = SCSI_REV_2; 71940024Sgibbs cpi->ccb_h.status = CAM_REQ_CMP; 72040024Sgibbs xpt_done(ccb); 72140024Sgibbs break; 72240024Sgibbs } 72340024Sgibbs default: 72440024Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 72540024Sgibbs xpt_done(ccb); 72640024Sgibbs break; 72740024Sgibbs } 72840024Sgibbs} 72940024Sgibbs 73040024Sgibbsstatic void 73140024Sgibbsadw_poll(struct cam_sim *sim) 73240024Sgibbs{ 733241588Sjhb adw_intr_locked(cam_sim_softc(sim)); 73440024Sgibbs} 73540024Sgibbs 73640024Sgibbsstatic void 73740024Sgibbsadw_async(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg) 73840024Sgibbs{ 73940024Sgibbs} 74040024Sgibbs 74140024Sgibbsstruct adw_softc * 74256979Sgibbsadw_alloc(device_t dev, struct resource *regs, int regs_type, int regs_id) 74340024Sgibbs{ 74440024Sgibbs struct adw_softc *adw; 745241588Sjhb 746241588Sjhb adw = device_get_softc(dev); 74740024Sgibbs LIST_INIT(&adw->pending_ccbs); 74840024Sgibbs SLIST_INIT(&adw->sg_maps); 749241588Sjhb mtx_init(&adw->lock, "adw", NULL, MTX_DEF); 75056979Sgibbs adw->device = dev; 75156979Sgibbs adw->regs_res_type = regs_type; 75256979Sgibbs adw->regs_res_id = regs_id; 75356979Sgibbs adw->regs = regs; 75440024Sgibbs return(adw); 75540024Sgibbs} 75640024Sgibbs 75740024Sgibbsvoid 75840024Sgibbsadw_free(struct adw_softc *adw) 75940024Sgibbs{ 76040024Sgibbs switch (adw->init_level) { 76156979Sgibbs case 9: 76240024Sgibbs { 76340024Sgibbs struct sg_map_node *sg_map; 76440024Sgibbs 76540024Sgibbs while ((sg_map = SLIST_FIRST(&adw->sg_maps)) != NULL) { 76640024Sgibbs SLIST_REMOVE_HEAD(&adw->sg_maps, links); 76740024Sgibbs bus_dmamap_unload(adw->sg_dmat, 76840024Sgibbs sg_map->sg_dmamap); 76940024Sgibbs bus_dmamem_free(adw->sg_dmat, sg_map->sg_vaddr, 77040024Sgibbs sg_map->sg_dmamap); 77140024Sgibbs free(sg_map, M_DEVBUF); 77240024Sgibbs } 77340024Sgibbs bus_dma_tag_destroy(adw->sg_dmat); 77440024Sgibbs } 77556979Sgibbs case 8: 77640024Sgibbs bus_dmamap_unload(adw->acb_dmat, adw->acb_dmamap); 77756979Sgibbs case 7: 77840024Sgibbs bus_dmamem_free(adw->acb_dmat, adw->acbs, 77940024Sgibbs adw->acb_dmamap); 78056979Sgibbs case 6: 78156979Sgibbs bus_dma_tag_destroy(adw->acb_dmat); 78256979Sgibbs case 5: 78356979Sgibbs bus_dmamap_unload(adw->carrier_dmat, adw->carrier_dmamap); 78456979Sgibbs case 4: 78556979Sgibbs bus_dmamem_free(adw->carrier_dmat, adw->carriers, 78656979Sgibbs adw->carrier_dmamap); 78740024Sgibbs case 3: 78856979Sgibbs bus_dma_tag_destroy(adw->carrier_dmat); 78940024Sgibbs case 2: 79040024Sgibbs bus_dma_tag_destroy(adw->buffer_dmat); 79140024Sgibbs case 1: 79240024Sgibbs bus_dma_tag_destroy(adw->parent_dmat); 79340024Sgibbs case 0: 79440024Sgibbs break; 79540024Sgibbs } 796138502Srsm 797138502Srsm if (adw->regs != NULL) 798138502Srsm bus_release_resource(adw->device, 799138502Srsm adw->regs_res_type, 800138502Srsm adw->regs_res_id, 801138502Srsm adw->regs); 802138502Srsm 803138502Srsm if (adw->irq != NULL) 804138502Srsm bus_release_resource(adw->device, 805138502Srsm adw->irq_res_type, 806138502Srsm 0, adw->irq); 807138502Srsm 808138502Srsm if (adw->sim != NULL) { 809138502Srsm if (adw->path != NULL) { 810138502Srsm xpt_async(AC_LOST_DEVICE, adw->path, NULL); 811138502Srsm xpt_free_path(adw->path); 812138502Srsm } 813138502Srsm xpt_bus_deregister(cam_sim_path(adw->sim)); 814138502Srsm cam_sim_free(adw->sim, /*free_devq*/TRUE); 815138502Srsm } 816241588Sjhb mtx_destroy(&adw->lock); 81740024Sgibbs} 81840024Sgibbs 81940024Sgibbsint 82040024Sgibbsadw_init(struct adw_softc *adw) 82140024Sgibbs{ 82240024Sgibbs struct adw_eeprom eep_config; 82356979Sgibbs u_int tid; 82456979Sgibbs u_int i; 82540024Sgibbs u_int16_t checksum; 82640024Sgibbs u_int16_t scsicfg1; 82740024Sgibbs 82840024Sgibbs checksum = adw_eeprom_read(adw, &eep_config); 82940024Sgibbs bcopy(eep_config.serial_number, adw->serial_number, 83040024Sgibbs sizeof(adw->serial_number)); 83140024Sgibbs if (checksum != eep_config.checksum) { 83240024Sgibbs u_int16_t serial_number[3]; 83340024Sgibbs 83456979Sgibbs adw->flags |= ADW_EEPROM_FAILED; 835241588Sjhb device_printf(adw->device, 836241588Sjhb "EEPROM checksum failed. Restoring Defaults\n"); 83740024Sgibbs 83840024Sgibbs /* 83940024Sgibbs * Restore the default EEPROM settings. 84040024Sgibbs * Assume the 6 byte board serial number that was read 84140024Sgibbs * from EEPROM is correct even if the EEPROM checksum 84240024Sgibbs * failed. 84340024Sgibbs */ 84456979Sgibbs bcopy(adw->default_eeprom, &eep_config, sizeof(eep_config)); 84540024Sgibbs bcopy(adw->serial_number, eep_config.serial_number, 84640024Sgibbs sizeof(serial_number)); 84740024Sgibbs adw_eeprom_write(adw, &eep_config); 84840024Sgibbs } 84940024Sgibbs 85040024Sgibbs /* Pull eeprom information into our softc. */ 85140024Sgibbs adw->bios_ctrl = eep_config.bios_ctrl; 85240024Sgibbs adw->user_wdtr = eep_config.wdtr_able; 85356979Sgibbs for (tid = 0; tid < ADW_MAX_TID; tid++) { 85456979Sgibbs u_int mc_sdtr; 85556979Sgibbs u_int16_t tid_mask; 85656979Sgibbs 85756979Sgibbs tid_mask = 0x1 << tid; 85856979Sgibbs if ((adw->features & ADW_ULTRA) != 0) { 85956979Sgibbs /* 86056979Sgibbs * Ultra chips store sdtr and ultraenb 86156979Sgibbs * bits in their seeprom, so we must 86256979Sgibbs * construct valid mc_sdtr entries for 86356979Sgibbs * indirectly. 86456979Sgibbs */ 86556979Sgibbs if (eep_config.sync1.sync_enable & tid_mask) { 86656979Sgibbs if (eep_config.sync2.ultra_enable & tid_mask) 86756979Sgibbs mc_sdtr = ADW_MC_SDTR_20; 86856979Sgibbs else 86956979Sgibbs mc_sdtr = ADW_MC_SDTR_10; 87056979Sgibbs } else 87156979Sgibbs mc_sdtr = ADW_MC_SDTR_ASYNC; 87256979Sgibbs } else { 87356979Sgibbs switch (ADW_TARGET_GROUP(tid)) { 87456979Sgibbs case 3: 87556979Sgibbs mc_sdtr = eep_config.sync4.sdtr4; 87656979Sgibbs break; 87756979Sgibbs case 2: 87856979Sgibbs mc_sdtr = eep_config.sync3.sdtr3; 87956979Sgibbs break; 88056979Sgibbs case 1: 88156979Sgibbs mc_sdtr = eep_config.sync2.sdtr2; 88256979Sgibbs break; 88356979Sgibbs default: /* Shut up compiler */ 88456979Sgibbs case 0: 88556979Sgibbs mc_sdtr = eep_config.sync1.sdtr1; 88656979Sgibbs break; 88756979Sgibbs } 88856979Sgibbs mc_sdtr >>= ADW_TARGET_GROUP_SHIFT(tid); 88956979Sgibbs mc_sdtr &= 0xFF; 89056979Sgibbs } 89156979Sgibbs adw_set_user_sdtr(adw, tid, mc_sdtr); 89256979Sgibbs } 89340024Sgibbs adw->user_tagenb = eep_config.tagqng_able; 89440024Sgibbs adw->user_discenb = eep_config.disc_enable; 89540024Sgibbs adw->max_acbs = eep_config.max_host_qng; 89640024Sgibbs adw->initiator_id = (eep_config.adapter_scsi_id & ADW_MAX_TID); 89740024Sgibbs 89840024Sgibbs /* 89940024Sgibbs * Sanity check the number of host openings. 90040024Sgibbs */ 90140024Sgibbs if (adw->max_acbs > ADW_DEF_MAX_HOST_QNG) 90240024Sgibbs adw->max_acbs = ADW_DEF_MAX_HOST_QNG; 90340024Sgibbs else if (adw->max_acbs < ADW_DEF_MIN_HOST_QNG) { 90440024Sgibbs /* If the value is zero, assume it is uninitialized. */ 90540024Sgibbs if (adw->max_acbs == 0) 90640024Sgibbs adw->max_acbs = ADW_DEF_MAX_HOST_QNG; 90740024Sgibbs else 90840024Sgibbs adw->max_acbs = ADW_DEF_MIN_HOST_QNG; 90940024Sgibbs } 91040024Sgibbs 91140024Sgibbs scsicfg1 = 0; 91256979Sgibbs if ((adw->features & ADW_ULTRA2) != 0) { 91356979Sgibbs switch (eep_config.termination_lvd) { 91456979Sgibbs default: 915241588Sjhb device_printf(adw->device, 916241588Sjhb "Invalid EEPROM LVD Termination Settings.\n"); 917241588Sjhb device_printf(adw->device, 918241588Sjhb "Reverting to Automatic LVD Termination\n"); 91956979Sgibbs /* FALLTHROUGH */ 92056979Sgibbs case ADW_EEPROM_TERM_AUTO: 92156979Sgibbs break; 92256979Sgibbs case ADW_EEPROM_TERM_BOTH_ON: 92356979Sgibbs scsicfg1 |= ADW2_SCSI_CFG1_TERM_LVD_LO; 92456979Sgibbs /* FALLTHROUGH */ 92556979Sgibbs case ADW_EEPROM_TERM_HIGH_ON: 92656979Sgibbs scsicfg1 |= ADW2_SCSI_CFG1_TERM_LVD_HI; 92756979Sgibbs /* FALLTHROUGH */ 92856979Sgibbs case ADW_EEPROM_TERM_OFF: 92956979Sgibbs scsicfg1 |= ADW2_SCSI_CFG1_DIS_TERM_DRV; 93056979Sgibbs break; 93156979Sgibbs } 93256979Sgibbs } 93356979Sgibbs 93456979Sgibbs switch (eep_config.termination_se) { 93540024Sgibbs default: 936241588Sjhb device_printf(adw->device, 937241588Sjhb "Invalid SE EEPROM Termination Settings.\n"); 938241588Sjhb device_printf(adw->device, 939241588Sjhb "Reverting to Automatic SE Termination\n"); 94040024Sgibbs /* FALLTHROUGH */ 94140024Sgibbs case ADW_EEPROM_TERM_AUTO: 94240024Sgibbs break; 94340024Sgibbs case ADW_EEPROM_TERM_BOTH_ON: 94440024Sgibbs scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_L; 94540024Sgibbs /* FALLTHROUGH */ 94640024Sgibbs case ADW_EEPROM_TERM_HIGH_ON: 94740024Sgibbs scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_H; 94840024Sgibbs /* FALLTHROUGH */ 94940024Sgibbs case ADW_EEPROM_TERM_OFF: 95040024Sgibbs scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_MANUAL; 95140024Sgibbs break; 95240024Sgibbs } 953241588Sjhb device_printf(adw->device, "SCSI ID %d, ", adw->initiator_id); 95440024Sgibbs 95540024Sgibbs /* DMA tag for mapping buffers into device visible space. */ 956112782Smdodd if (bus_dma_tag_create( 957112782Smdodd /* parent */ adw->parent_dmat, 958112782Smdodd /* alignment */ 1, 959112782Smdodd /* boundary */ 0, 960112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, 961112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 962112782Smdodd /* filter */ NULL, 963112782Smdodd /* filterarg */ NULL, 964280347Smav /* maxsize */ DFLTPHYS, 965112782Smdodd /* nsegments */ ADW_SGSIZE, 966112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT, 967112782Smdodd /* flags */ BUS_DMA_ALLOCNOW, 968117126Sscottl /* lockfunc */ busdma_lock_mutex, 969241588Sjhb /* lockarg */ &adw->lock, 970112782Smdodd &adw->buffer_dmat) != 0) { 97156979Sgibbs return (ENOMEM); 97240024Sgibbs } 97340024Sgibbs 97440024Sgibbs adw->init_level++; 97540024Sgibbs 97656979Sgibbs /* DMA tag for our ccb carrier structures */ 977112782Smdodd if (bus_dma_tag_create( 978112782Smdodd /* parent */ adw->parent_dmat, 979112782Smdodd /* alignment */ 0x10, 980112782Smdodd /* boundary */ 0, 981112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, 982112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 983112782Smdodd /* filter */ NULL, 984112782Smdodd /* filterarg */ NULL, 985112782Smdodd /* maxsize */ (adw->max_acbs + 986112782Smdodd ADW_NUM_CARRIER_QUEUES + 1) * 987112782Smdodd sizeof(struct adw_carrier), 988112782Smdodd /* nsegments */ 1, 989112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT, 990112782Smdodd /* flags */ 0, 991241588Sjhb /* lockfunc */ NULL, 992241588Sjhb /* lockarg */ NULL, 993112782Smdodd &adw->carrier_dmat) != 0) { 99456979Sgibbs return (ENOMEM); 99556979Sgibbs } 99656979Sgibbs 99756979Sgibbs adw->init_level++; 99856979Sgibbs 99956979Sgibbs /* Allocation for our ccb carrier structures */ 100056979Sgibbs if (bus_dmamem_alloc(adw->carrier_dmat, (void **)&adw->carriers, 100156979Sgibbs BUS_DMA_NOWAIT, &adw->carrier_dmamap) != 0) { 100256979Sgibbs return (ENOMEM); 100356979Sgibbs } 100456979Sgibbs 100556979Sgibbs adw->init_level++; 100656979Sgibbs 100756979Sgibbs /* And permanently map them */ 100856979Sgibbs bus_dmamap_load(adw->carrier_dmat, adw->carrier_dmamap, 100956979Sgibbs adw->carriers, 101056979Sgibbs (adw->max_acbs + ADW_NUM_CARRIER_QUEUES + 1) 101156979Sgibbs * sizeof(struct adw_carrier), 101256979Sgibbs adwmapmem, &adw->carrier_busbase, /*flags*/0); 101356979Sgibbs 101456979Sgibbs /* Clear them out. */ 101556979Sgibbs bzero(adw->carriers, (adw->max_acbs + ADW_NUM_CARRIER_QUEUES + 1) 101656979Sgibbs * sizeof(struct adw_carrier)); 101756979Sgibbs 101856979Sgibbs /* Setup our free carrier list */ 101956979Sgibbs adw->free_carriers = adw->carriers; 102056979Sgibbs for (i = 0; i < adw->max_acbs + ADW_NUM_CARRIER_QUEUES; i++) { 102156979Sgibbs adw->carriers[i].carr_offset = 102256979Sgibbs carriervtobo(adw, &adw->carriers[i]); 102356979Sgibbs adw->carriers[i].carr_ba = 102456979Sgibbs carriervtob(adw, &adw->carriers[i]); 102556979Sgibbs adw->carriers[i].areq_ba = 0; 102656979Sgibbs adw->carriers[i].next_ba = 102756979Sgibbs carriervtobo(adw, &adw->carriers[i+1]); 102856979Sgibbs } 102956979Sgibbs /* Terminal carrier. Never leaves the freelist */ 103056979Sgibbs adw->carriers[i].carr_offset = 103156979Sgibbs carriervtobo(adw, &adw->carriers[i]); 103256979Sgibbs adw->carriers[i].carr_ba = 103356979Sgibbs carriervtob(adw, &adw->carriers[i]); 103456979Sgibbs adw->carriers[i].areq_ba = 0; 103556979Sgibbs adw->carriers[i].next_ba = ~0; 103656979Sgibbs 103756979Sgibbs adw->init_level++; 103856979Sgibbs 103956979Sgibbs /* DMA tag for our acb structures */ 1040112782Smdodd if (bus_dma_tag_create( 1041112782Smdodd /* parent */ adw->parent_dmat, 1042112782Smdodd /* alignment */ 1, 1043112782Smdodd /* boundary */ 0, 1044112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR, 1045112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 1046112782Smdodd /* filter */ NULL, 1047112782Smdodd /* filterarg */ NULL, 1048112782Smdodd /* maxsize */ adw->max_acbs * sizeof(struct acb), 1049112782Smdodd /* nsegments */ 1, 1050112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT, 1051112782Smdodd /* flags */ 0, 1052241588Sjhb /* lockfunc */ NULL, 1053241588Sjhb /* lockarg */ NULL, 1054112782Smdodd &adw->acb_dmat) != 0) { 105556979Sgibbs return (ENOMEM); 105640024Sgibbs } 105740024Sgibbs 105840024Sgibbs adw->init_level++; 105940024Sgibbs 106040024Sgibbs /* Allocation for our ccbs */ 106140024Sgibbs if (bus_dmamem_alloc(adw->acb_dmat, (void **)&adw->acbs, 106256979Sgibbs BUS_DMA_NOWAIT, &adw->acb_dmamap) != 0) 106356979Sgibbs return (ENOMEM); 106440024Sgibbs 106540024Sgibbs adw->init_level++; 106640024Sgibbs 106740024Sgibbs /* And permanently map them */ 106840024Sgibbs bus_dmamap_load(adw->acb_dmat, adw->acb_dmamap, 106940024Sgibbs adw->acbs, 107040024Sgibbs adw->max_acbs * sizeof(struct acb), 107140024Sgibbs adwmapmem, &adw->acb_busbase, /*flags*/0); 107240024Sgibbs 107340024Sgibbs /* Clear them out. */ 107440024Sgibbs bzero(adw->acbs, adw->max_acbs * sizeof(struct acb)); 107540024Sgibbs 107640024Sgibbs /* DMA tag for our S/G structures. We allocate in page sized chunks */ 1077112782Smdodd if (bus_dma_tag_create( 1078112782Smdodd /* parent */ adw->parent_dmat, 1079112782Smdodd /* alignment */ 1, 1080112782Smdodd /* boundary */ 0, 1081112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR, 1082112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 1083112782Smdodd /* filter */ NULL, 1084112782Smdodd /* filterarg */ NULL, 1085112782Smdodd /* maxsize */ PAGE_SIZE, 1086112782Smdodd /* nsegments */ 1, 1087112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT, 1088112782Smdodd /* flags */ 0, 1089241588Sjhb /* lockfunc */ NULL, 1090241588Sjhb /* lockarg */ NULL, 1091112782Smdodd &adw->sg_dmat) != 0) { 109256979Sgibbs return (ENOMEM); 109340024Sgibbs } 109440024Sgibbs 109540024Sgibbs adw->init_level++; 109640024Sgibbs 109740024Sgibbs /* Allocate our first batch of ccbs */ 1098241588Sjhb mtx_lock(&adw->lock); 1099241588Sjhb if (adwallocacbs(adw) == 0) { 1100241588Sjhb mtx_unlock(&adw->lock); 110156979Sgibbs return (ENOMEM); 1102241588Sjhb } 110340024Sgibbs 1104241588Sjhb if (adw_init_chip(adw, scsicfg1) != 0) { 1105241588Sjhb mtx_unlock(&adw->lock); 110656979Sgibbs return (ENXIO); 1107241588Sjhb } 110856979Sgibbs 110956979Sgibbs printf("Queue Depth %d\n", adw->max_acbs); 1110241588Sjhb mtx_unlock(&adw->lock); 111156979Sgibbs 111240024Sgibbs return (0); 111340024Sgibbs} 111440024Sgibbs 111540024Sgibbs/* 111640024Sgibbs * Attach all the sub-devices we can find 111740024Sgibbs */ 111840024Sgibbsint 111940024Sgibbsadw_attach(struct adw_softc *adw) 112040024Sgibbs{ 112140024Sgibbs struct ccb_setasync csa; 112240024Sgibbs struct cam_devq *devq; 112356979Sgibbs int error; 112440024Sgibbs 112556979Sgibbs /* Hook up our interrupt handler */ 1126241588Sjhb error = bus_setup_intr(adw->device, adw->irq, 1127241588Sjhb INTR_TYPE_CAM | INTR_ENTROPY | INTR_MPSAFE, NULL, adw_intr, adw, 1128241588Sjhb &adw->ih); 1129241588Sjhb if (error != 0) { 113056979Sgibbs device_printf(adw->device, "bus_setup_intr() failed: %d\n", 113156979Sgibbs error); 1132241588Sjhb return (error); 113356979Sgibbs } 113456979Sgibbs 113540024Sgibbs /* Start the Risc processor now that we are fully configured. */ 113640024Sgibbs adw_outw(adw, ADW_RISC_CSR, ADW_RISC_CSR_RUN); 113740024Sgibbs 113840024Sgibbs /* 113940024Sgibbs * Create the device queue for our SIM. 114040024Sgibbs */ 114140024Sgibbs devq = cam_simq_alloc(adw->max_acbs); 114240024Sgibbs if (devq == NULL) 114356979Sgibbs return (ENOMEM); 114440024Sgibbs 114540024Sgibbs /* 114640024Sgibbs * Construct our SIM entry. 114740024Sgibbs */ 1148241588Sjhb adw->sim = cam_sim_alloc(adw_action, adw_poll, "adw", adw, 1149241588Sjhb device_get_unit(adw->device), &adw->lock, 1, adw->max_acbs, devq); 1150241588Sjhb if (adw->sim == NULL) 1151241588Sjhb return (ENOMEM); 115240024Sgibbs 115340024Sgibbs /* 115440024Sgibbs * Register the bus. 115540024Sgibbs */ 1156241588Sjhb mtx_lock(&adw->lock); 1157170872Sscottl if (xpt_bus_register(adw->sim, adw->device, 0) != CAM_SUCCESS) { 115840024Sgibbs cam_sim_free(adw->sim, /*free devq*/TRUE); 115956979Sgibbs error = ENOMEM; 116056979Sgibbs goto fail; 116140024Sgibbs } 116240024Sgibbs 116340024Sgibbs if (xpt_create_path(&adw->path, /*periph*/NULL, cam_sim_path(adw->sim), 116440024Sgibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) 116540024Sgibbs == CAM_REQ_CMP) { 116640024Sgibbs xpt_setup_ccb(&csa.ccb_h, adw->path, /*priority*/5); 116740024Sgibbs csa.ccb_h.func_code = XPT_SASYNC_CB; 116840024Sgibbs csa.event_enable = AC_LOST_DEVICE; 116940024Sgibbs csa.callback = adw_async; 117040024Sgibbs csa.callback_arg = adw; 117140024Sgibbs xpt_action((union ccb *)&csa); 117240024Sgibbs } 117340024Sgibbs 117456979Sgibbsfail: 1175241588Sjhb mtx_unlock(&adw->lock); 117656979Sgibbs return (error); 117740024Sgibbs} 117840024Sgibbs 117940024Sgibbsvoid 118040024Sgibbsadw_intr(void *arg) 118140024Sgibbs{ 118240024Sgibbs struct adw_softc *adw; 1183241588Sjhb 1184241588Sjhb adw = arg; 1185241588Sjhb mtx_lock(&adw->lock); 1186241588Sjhb adw_intr_locked(adw); 1187241588Sjhb mtx_unlock(&adw->lock); 1188241588Sjhb} 1189241588Sjhb 1190241588Sjhbvoid 1191241588Sjhbadw_intr_locked(struct adw_softc *adw) 1192241588Sjhb{ 119340024Sgibbs u_int int_stat; 119440024Sgibbs 119540024Sgibbs if ((adw_inw(adw, ADW_CTRL_REG) & ADW_CTRL_REG_HOST_INTR) == 0) 119640024Sgibbs return; 119740024Sgibbs 119840024Sgibbs /* Reading the register clears the interrupt. */ 119940024Sgibbs int_stat = adw_inb(adw, ADW_INTR_STATUS_REG); 120040024Sgibbs 120140024Sgibbs if ((int_stat & ADW_INTR_STATUS_INTRB) != 0) { 120256979Sgibbs u_int intrb_code; 120356979Sgibbs 120456979Sgibbs /* Async Microcode Event */ 120556979Sgibbs intrb_code = adw_lram_read_8(adw, ADW_MC_INTRB_CODE); 120656979Sgibbs switch (intrb_code) { 120756979Sgibbs case ADW_ASYNC_CARRIER_READY_FAILURE: 120856979Sgibbs /* 120956979Sgibbs * The RISC missed our update of 121056979Sgibbs * the commandq. 121156979Sgibbs */ 121256979Sgibbs if (LIST_FIRST(&adw->pending_ccbs) != NULL) 121356979Sgibbs adw_tickle_risc(adw, ADW_TICKLE_A); 121440024Sgibbs break; 121556979Sgibbs case ADW_ASYNC_SCSI_BUS_RESET_DET: 121656979Sgibbs /* 121756979Sgibbs * The firmware detected a SCSI Bus reset. 121856979Sgibbs */ 1219241588Sjhb device_printf(adw->device, "Someone Reset the Bus\n"); 122056979Sgibbs adw_handle_bus_reset(adw, /*initiated*/FALSE); 122156979Sgibbs break; 122256979Sgibbs case ADW_ASYNC_RDMA_FAILURE: 122356979Sgibbs /* 122456979Sgibbs * Handle RDMA failure by resetting the 122556979Sgibbs * SCSI Bus and chip. 122656979Sgibbs */ 1227153072Sru#if 0 /* XXX */ 122856979Sgibbs AdvResetChipAndSB(adv_dvc_varp); 122956979Sgibbs#endif 123056979Sgibbs break; 123156979Sgibbs 123256979Sgibbs case ADW_ASYNC_HOST_SCSI_BUS_RESET: 123356979Sgibbs /* 123456979Sgibbs * Host generated SCSI bus reset occurred. 123556979Sgibbs */ 123640024Sgibbs adw_handle_bus_reset(adw, /*initiated*/TRUE); 123756979Sgibbs break; 123856979Sgibbs default: 123956979Sgibbs printf("adw_intr: unknown async code 0x%x\n", 124056979Sgibbs intrb_code); 124140024Sgibbs break; 124240024Sgibbs } 124340024Sgibbs } 124440024Sgibbs 124540024Sgibbs /* 124656979Sgibbs * Run down the RequestQ. 124740024Sgibbs */ 124856979Sgibbs while ((adw->responseq->next_ba & ADW_RQ_DONE) != 0) { 124956979Sgibbs struct adw_carrier *free_carrier; 125056979Sgibbs struct acb *acb; 125156979Sgibbs union ccb *ccb; 125240024Sgibbs 125356979Sgibbs#if 0 125456979Sgibbs printf("0x%x, 0x%x, 0x%x, 0x%x\n", 125556979Sgibbs adw->responseq->carr_offset, 125656979Sgibbs adw->responseq->carr_ba, 125756979Sgibbs adw->responseq->areq_ba, 125856979Sgibbs adw->responseq->next_ba); 125956979Sgibbs#endif 126056979Sgibbs /* 126156979Sgibbs * The firmware copies the adw_scsi_req_q.acb_baddr 126256979Sgibbs * field into the areq_ba field of the carrier. 126356979Sgibbs */ 126456979Sgibbs acb = acbbotov(adw, adw->responseq->areq_ba); 126540024Sgibbs 126640024Sgibbs /* 126756979Sgibbs * The least significant four bits of the next_ba 126856979Sgibbs * field are used as flags. Mask them out and then 126956979Sgibbs * advance through the list. 127040024Sgibbs */ 127156979Sgibbs free_carrier = adw->responseq; 127256979Sgibbs adw->responseq = 127356979Sgibbs carrierbotov(adw, free_carrier->next_ba & ADW_NEXT_BA_MASK); 127456979Sgibbs free_carrier->next_ba = adw->free_carriers->carr_offset; 127556979Sgibbs adw->free_carriers = free_carrier; 127640024Sgibbs 127740024Sgibbs /* Process CCB */ 127840024Sgibbs ccb = acb->ccb; 1279241588Sjhb callout_stop(&acb->timer); 128040024Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 1281115343Sscottl bus_dmasync_op_t op; 128240024Sgibbs 128340024Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 128440024Sgibbs op = BUS_DMASYNC_POSTREAD; 128540024Sgibbs else 128640024Sgibbs op = BUS_DMASYNC_POSTWRITE; 128740024Sgibbs bus_dmamap_sync(adw->buffer_dmat, acb->dmamap, op); 128840024Sgibbs bus_dmamap_unload(adw->buffer_dmat, acb->dmamap); 128940024Sgibbs ccb->csio.resid = acb->queue.data_cnt; 129040024Sgibbs } else 129140024Sgibbs ccb->csio.resid = 0; 129240024Sgibbs 129340024Sgibbs /* Common Cases inline... */ 129440024Sgibbs if (acb->queue.host_status == QHSTA_NO_ERROR 129540024Sgibbs && (acb->queue.done_status == QD_NO_ERROR 129640024Sgibbs || acb->queue.done_status == QD_WITH_ERROR)) { 129740024Sgibbs ccb->csio.scsi_status = acb->queue.scsi_status; 129840024Sgibbs ccb->ccb_h.status = 0; 129940024Sgibbs switch (ccb->csio.scsi_status) { 130040024Sgibbs case SCSI_STATUS_OK: 130140024Sgibbs ccb->ccb_h.status |= CAM_REQ_CMP; 130240024Sgibbs break; 130340024Sgibbs case SCSI_STATUS_CHECK_COND: 130440024Sgibbs case SCSI_STATUS_CMD_TERMINATED: 130540024Sgibbs bcopy(&acb->sense_data, &ccb->csio.sense_data, 130640024Sgibbs ccb->csio.sense_len); 130740024Sgibbs ccb->ccb_h.status |= CAM_AUTOSNS_VALID; 130840024Sgibbs ccb->csio.sense_resid = acb->queue.sense_len; 130940024Sgibbs /* FALLTHROUGH */ 131040024Sgibbs default: 131140024Sgibbs ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR 131240024Sgibbs | CAM_DEV_QFRZN; 131340024Sgibbs xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 131440024Sgibbs break; 131540024Sgibbs } 131640024Sgibbs adwfreeacb(adw, acb); 131740024Sgibbs xpt_done(ccb); 131840024Sgibbs } else { 131940024Sgibbs adwprocesserror(adw, acb); 132040024Sgibbs } 132140024Sgibbs } 132240024Sgibbs} 132340024Sgibbs 132440024Sgibbsstatic void 132540024Sgibbsadwprocesserror(struct adw_softc *adw, struct acb *acb) 132640024Sgibbs{ 132740024Sgibbs union ccb *ccb; 132840024Sgibbs 132940024Sgibbs ccb = acb->ccb; 133040024Sgibbs if (acb->queue.done_status == QD_ABORTED_BY_HOST) { 133140024Sgibbs ccb->ccb_h.status = CAM_REQ_ABORTED; 133240024Sgibbs } else { 133340024Sgibbs 133440024Sgibbs switch (acb->queue.host_status) { 133540024Sgibbs case QHSTA_M_SEL_TIMEOUT: 133640024Sgibbs ccb->ccb_h.status = CAM_SEL_TIMEOUT; 133740024Sgibbs break; 133840024Sgibbs case QHSTA_M_SXFR_OFF_UFLW: 133940024Sgibbs case QHSTA_M_SXFR_OFF_OFLW: 134040024Sgibbs case QHSTA_M_DATA_OVER_RUN: 134140024Sgibbs ccb->ccb_h.status = CAM_DATA_RUN_ERR; 134240024Sgibbs break; 134340024Sgibbs case QHSTA_M_SXFR_DESELECTED: 134440024Sgibbs case QHSTA_M_UNEXPECTED_BUS_FREE: 134540024Sgibbs ccb->ccb_h.status = CAM_UNEXP_BUSFREE; 134640024Sgibbs break; 134757679Sgibbs case QHSTA_M_SCSI_BUS_RESET: 134857679Sgibbs case QHSTA_M_SCSI_BUS_RESET_UNSOL: 134957679Sgibbs ccb->ccb_h.status = CAM_SCSI_BUS_RESET; 135057679Sgibbs break; 135157679Sgibbs case QHSTA_M_BUS_DEVICE_RESET: 135257679Sgibbs ccb->ccb_h.status = CAM_BDR_SENT; 135357679Sgibbs break; 135440024Sgibbs case QHSTA_M_QUEUE_ABORTED: 135540024Sgibbs /* BDR or Bus Reset */ 1356241588Sjhb xpt_print_path(adw->path); 135757679Sgibbs printf("Saw Queue Aborted\n"); 135840024Sgibbs ccb->ccb_h.status = adw->last_reset; 135940024Sgibbs break; 136040024Sgibbs case QHSTA_M_SXFR_SDMA_ERR: 136140024Sgibbs case QHSTA_M_SXFR_SXFR_PERR: 136240024Sgibbs case QHSTA_M_RDMA_PERR: 136340024Sgibbs ccb->ccb_h.status = CAM_UNCOR_PARITY; 136440024Sgibbs break; 136540024Sgibbs case QHSTA_M_WTM_TIMEOUT: 136640024Sgibbs case QHSTA_M_SXFR_WD_TMO: 136756979Sgibbs { 136840024Sgibbs /* The SCSI bus hung in a phase */ 136957679Sgibbs xpt_print_path(adw->path); 1370241588Sjhb printf("Watch Dog timer expired. Resetting bus\n"); 137157679Sgibbs adw_reset_bus(adw); 137240024Sgibbs break; 137356979Sgibbs } 137440024Sgibbs case QHSTA_M_SXFR_XFR_PH_ERR: 137540024Sgibbs ccb->ccb_h.status = CAM_SEQUENCE_FAIL; 137640024Sgibbs break; 137740024Sgibbs case QHSTA_M_SXFR_UNKNOWN_ERROR: 137840024Sgibbs break; 137940024Sgibbs case QHSTA_M_BAD_CMPL_STATUS_IN: 138040024Sgibbs /* No command complete after a status message */ 138140024Sgibbs ccb->ccb_h.status = CAM_SEQUENCE_FAIL; 138240024Sgibbs break; 138340024Sgibbs case QHSTA_M_AUTO_REQ_SENSE_FAIL: 138440024Sgibbs ccb->ccb_h.status = CAM_AUTOSENSE_FAIL; 138540024Sgibbs break; 138640024Sgibbs case QHSTA_M_INVALID_DEVICE: 138740024Sgibbs ccb->ccb_h.status = CAM_PATH_INVALID; 138840024Sgibbs break; 138940024Sgibbs case QHSTA_M_NO_AUTO_REQ_SENSE: 139040024Sgibbs /* 139140024Sgibbs * User didn't request sense, but we got a 139240024Sgibbs * check condition. 139340024Sgibbs */ 139440024Sgibbs ccb->csio.scsi_status = acb->queue.scsi_status; 139540024Sgibbs ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; 139640024Sgibbs break; 139740024Sgibbs default: 139840024Sgibbs panic("%s: Unhandled Host status error %x", 1399241588Sjhb device_get_nameunit(adw->device), 1400241588Sjhb acb->queue.host_status); 140140024Sgibbs /* NOTREACHED */ 140240024Sgibbs } 140340024Sgibbs } 140457679Sgibbs if ((acb->state & ACB_RECOVERY_ACB) != 0) { 140557679Sgibbs if (ccb->ccb_h.status == CAM_SCSI_BUS_RESET 140657679Sgibbs || ccb->ccb_h.status == CAM_BDR_SENT) 140757679Sgibbs ccb->ccb_h.status = CAM_CMD_TIMEOUT; 140857679Sgibbs } 140940024Sgibbs if (ccb->ccb_h.status != CAM_REQ_CMP) { 141040024Sgibbs xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 141140024Sgibbs ccb->ccb_h.status |= CAM_DEV_QFRZN; 141240024Sgibbs } 141340024Sgibbs adwfreeacb(adw, acb); 141440024Sgibbs xpt_done(ccb); 141540024Sgibbs} 141640024Sgibbs 141740024Sgibbsstatic void 141840024Sgibbsadwtimeout(void *arg) 141940024Sgibbs{ 142040024Sgibbs struct acb *acb; 142140024Sgibbs union ccb *ccb; 142240024Sgibbs struct adw_softc *adw; 142340024Sgibbs adw_idle_cmd_status_t status; 142457679Sgibbs int target_id; 142540024Sgibbs 142640024Sgibbs acb = (struct acb *)arg; 142740024Sgibbs ccb = acb->ccb; 142840024Sgibbs adw = (struct adw_softc *)ccb->ccb_h.ccb_adw_ptr; 142940024Sgibbs xpt_print_path(ccb->ccb_h.path); 143040024Sgibbs printf("ACB %p - timed out\n", (void *)acb); 143140024Sgibbs 1432241588Sjhb mtx_assert(&adw->lock, MA_OWNED); 143340024Sgibbs 143440024Sgibbs if ((acb->state & ACB_ACTIVE) == 0) { 143540024Sgibbs xpt_print_path(ccb->ccb_h.path); 143640024Sgibbs printf("ACB %p - timed out CCB already completed\n", 143740024Sgibbs (void *)acb); 143840024Sgibbs return; 143940024Sgibbs } 144040024Sgibbs 144157679Sgibbs acb->state |= ACB_RECOVERY_ACB; 144257679Sgibbs target_id = ccb->ccb_h.target_id; 144357679Sgibbs 144440024Sgibbs /* Attempt a BDR first */ 144557679Sgibbs status = adw_idle_cmd_send(adw, ADW_IDLE_CMD_DEVICE_RESET, 144657679Sgibbs ccb->ccb_h.target_id); 144740024Sgibbs if (status == ADW_IDLE_CMD_SUCCESS) { 1448241588Sjhb device_printf(adw->device, 1449241588Sjhb "BDR Delivered. No longer in timeout\n"); 145057679Sgibbs adw_handle_device_reset(adw, target_id); 145140024Sgibbs } else { 145257679Sgibbs adw_reset_bus(adw); 145357679Sgibbs xpt_print_path(adw->path); 145457679Sgibbs printf("Bus Reset Delivered. No longer in timeout\n"); 145540024Sgibbs } 145640024Sgibbs} 145740024Sgibbs 145840024Sgibbsstatic void 145940024Sgibbsadw_handle_device_reset(struct adw_softc *adw, u_int target) 146040024Sgibbs{ 146140024Sgibbs struct cam_path *path; 146240024Sgibbs cam_status error; 146340024Sgibbs 146440024Sgibbs error = xpt_create_path(&path, /*periph*/NULL, cam_sim_path(adw->sim), 146540024Sgibbs target, CAM_LUN_WILDCARD); 146640024Sgibbs 146740024Sgibbs if (error == CAM_REQ_CMP) { 146840024Sgibbs xpt_async(AC_SENT_BDR, path, NULL); 146940024Sgibbs xpt_free_path(path); 147040024Sgibbs } 147140024Sgibbs adw->last_reset = CAM_BDR_SENT; 147240024Sgibbs} 147340024Sgibbs 147440024Sgibbsstatic void 147540024Sgibbsadw_handle_bus_reset(struct adw_softc *adw, int initiated) 147640024Sgibbs{ 147740024Sgibbs if (initiated) { 147840024Sgibbs /* 147940024Sgibbs * The microcode currently sets the SCSI Bus Reset signal 148040024Sgibbs * while handling the AscSendIdleCmd() IDLE_CMD_SCSI_RESET 148140024Sgibbs * command above. But the SCSI Bus Reset Hold Time in the 148240024Sgibbs * microcode is not deterministic (it may in fact be for less 148340024Sgibbs * than the SCSI Spec. minimum of 25 us). Therefore on return 148440024Sgibbs * the Adv Library sets the SCSI Bus Reset signal for 148540024Sgibbs * ADW_SCSI_RESET_HOLD_TIME_US, which is defined to be greater 148640024Sgibbs * than 25 us. 148740024Sgibbs */ 148840024Sgibbs u_int scsi_ctrl; 148940024Sgibbs 149040024Sgibbs scsi_ctrl = adw_inw(adw, ADW_SCSI_CTRL) & ~ADW_SCSI_CTRL_RSTOUT; 149140024Sgibbs adw_outw(adw, ADW_SCSI_CTRL, scsi_ctrl | ADW_SCSI_CTRL_RSTOUT); 149240024Sgibbs DELAY(ADW_SCSI_RESET_HOLD_TIME_US); 149340024Sgibbs adw_outw(adw, ADW_SCSI_CTRL, scsi_ctrl); 149440024Sgibbs 149540024Sgibbs /* 149640024Sgibbs * We will perform the async notification when the 149740024Sgibbs * SCSI Reset interrupt occurs. 149840024Sgibbs */ 149940024Sgibbs } else 150040024Sgibbs xpt_async(AC_BUS_RESET, adw->path, NULL); 150140024Sgibbs adw->last_reset = CAM_SCSI_BUS_RESET; 150240024Sgibbs} 1503165102SmjacobMODULE_DEPEND(adw, cam, 1, 1, 1); 1504165102Smjacob 1505