adwcam.c revision 246713
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: head/sys/dev/advansys/adwcam.c 246713 2013-02-12 16:57:20Z kib $"); 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 7857679Sgibbsstatic __inline cam_status adwccbstatus(union ccb*); 7940024Sgibbsstatic __inline struct acb* adwgetacb(struct adw_softc *adw); 8040024Sgibbsstatic __inline void adwfreeacb(struct adw_softc *adw, 8140024Sgibbs struct acb *acb); 8240024Sgibbs 8340024Sgibbsstatic void adwmapmem(void *arg, bus_dma_segment_t *segs, 8440024Sgibbs int nseg, int error); 8540024Sgibbsstatic struct sg_map_node* 8640024Sgibbs adwallocsgmap(struct adw_softc *adw); 8740024Sgibbsstatic int adwallocacbs(struct adw_softc *adw); 8840024Sgibbs 8940024Sgibbsstatic void adwexecuteacb(void *arg, bus_dma_segment_t *dm_segs, 9040024Sgibbs int nseg, int error); 9140024Sgibbsstatic void adw_action(struct cam_sim *sim, union ccb *ccb); 92241588Sjhbstatic void adw_intr_locked(struct adw_softc *adw); 9340024Sgibbsstatic void adw_poll(struct cam_sim *sim); 9440024Sgibbsstatic void adw_async(void *callback_arg, u_int32_t code, 9540024Sgibbs struct cam_path *path, void *arg); 9640024Sgibbsstatic void adwprocesserror(struct adw_softc *adw, struct acb *acb); 9740024Sgibbsstatic void adwtimeout(void *arg); 9840024Sgibbsstatic void adw_handle_device_reset(struct adw_softc *adw, 9940024Sgibbs u_int target); 10040024Sgibbsstatic void adw_handle_bus_reset(struct adw_softc *adw, 10140024Sgibbs int initiated); 10240024Sgibbs 10357679Sgibbsstatic __inline cam_status 10457679Sgibbsadwccbstatus(union ccb* ccb) 10557679Sgibbs{ 10657679Sgibbs return (ccb->ccb_h.status & CAM_STATUS_MASK); 10757679Sgibbs} 10857679Sgibbs 10940024Sgibbsstatic __inline struct acb* 11040024Sgibbsadwgetacb(struct adw_softc *adw) 11140024Sgibbs{ 11240024Sgibbs struct acb* acb; 11340024Sgibbs 114241588Sjhb if (!dumping) 115241588Sjhb mtx_assert(&adw->lock, MA_OWNED); 11640024Sgibbs if ((acb = SLIST_FIRST(&adw->free_acb_list)) != NULL) { 11740024Sgibbs SLIST_REMOVE_HEAD(&adw->free_acb_list, links); 11840024Sgibbs } else if (adw->num_acbs < adw->max_acbs) { 11940024Sgibbs adwallocacbs(adw); 12040024Sgibbs acb = SLIST_FIRST(&adw->free_acb_list); 12140024Sgibbs if (acb == NULL) 122241588Sjhb device_printf(adw->device, "Can't malloc ACB\n"); 12340024Sgibbs else { 12440024Sgibbs SLIST_REMOVE_HEAD(&adw->free_acb_list, links); 12540024Sgibbs } 12640024Sgibbs } 12740024Sgibbs 12840024Sgibbs return (acb); 12940024Sgibbs} 13040024Sgibbs 13140024Sgibbsstatic __inline void 13240024Sgibbsadwfreeacb(struct adw_softc *adw, struct acb *acb) 13340024Sgibbs{ 13440024Sgibbs 135241588Sjhb if (!dumping) 136241588Sjhb mtx_assert(&adw->lock, MA_OWNED); 13740024Sgibbs if ((acb->state & ACB_ACTIVE) != 0) 13840024Sgibbs LIST_REMOVE(&acb->ccb->ccb_h, sim_links.le); 13940024Sgibbs if ((acb->state & ACB_RELEASE_SIMQ) != 0) 14040024Sgibbs acb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 14140024Sgibbs else if ((adw->state & ADW_RESOURCE_SHORTAGE) != 0 14240024Sgibbs && (acb->ccb->ccb_h.status & CAM_RELEASE_SIMQ) == 0) { 14340024Sgibbs acb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 14440024Sgibbs adw->state &= ~ADW_RESOURCE_SHORTAGE; 14540024Sgibbs } 14640024Sgibbs acb->state = ACB_FREE; 14740024Sgibbs SLIST_INSERT_HEAD(&adw->free_acb_list, acb, links); 14840024Sgibbs} 14940024Sgibbs 15040024Sgibbsstatic void 15140024Sgibbsadwmapmem(void *arg, bus_dma_segment_t *segs, int nseg, int error) 15240024Sgibbs{ 15340024Sgibbs bus_addr_t *busaddrp; 15440024Sgibbs 15540024Sgibbs busaddrp = (bus_addr_t *)arg; 15640024Sgibbs *busaddrp = segs->ds_addr; 15740024Sgibbs} 15840024Sgibbs 15940024Sgibbsstatic struct sg_map_node * 16040024Sgibbsadwallocsgmap(struct adw_softc *adw) 16140024Sgibbs{ 16240024Sgibbs struct sg_map_node *sg_map; 16340024Sgibbs 16440024Sgibbs sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT); 16540024Sgibbs 16640024Sgibbs if (sg_map == NULL) 16740024Sgibbs return (NULL); 16840024Sgibbs 16940024Sgibbs /* Allocate S/G space for the next batch of ACBS */ 17040024Sgibbs if (bus_dmamem_alloc(adw->sg_dmat, (void **)&sg_map->sg_vaddr, 17140024Sgibbs BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) { 17240024Sgibbs free(sg_map, M_DEVBUF); 17340024Sgibbs return (NULL); 17440024Sgibbs } 17540024Sgibbs 17640024Sgibbs SLIST_INSERT_HEAD(&adw->sg_maps, sg_map, links); 17740024Sgibbs 17840024Sgibbs bus_dmamap_load(adw->sg_dmat, sg_map->sg_dmamap, sg_map->sg_vaddr, 17940024Sgibbs PAGE_SIZE, adwmapmem, &sg_map->sg_physaddr, /*flags*/0); 18040024Sgibbs 18140024Sgibbs bzero(sg_map->sg_vaddr, PAGE_SIZE); 18240024Sgibbs return (sg_map); 18340024Sgibbs} 18440024Sgibbs 18540024Sgibbs/* 18640024Sgibbs * Allocate another chunk of CCB's. Return count of entries added. 18740024Sgibbs */ 18840024Sgibbsstatic int 18940024Sgibbsadwallocacbs(struct adw_softc *adw) 19040024Sgibbs{ 19140024Sgibbs struct acb *next_acb; 19240024Sgibbs struct sg_map_node *sg_map; 19340024Sgibbs bus_addr_t busaddr; 19440024Sgibbs struct adw_sg_block *blocks; 19540024Sgibbs int newcount; 19640024Sgibbs int i; 19740024Sgibbs 19840024Sgibbs next_acb = &adw->acbs[adw->num_acbs]; 19940024Sgibbs sg_map = adwallocsgmap(adw); 20040024Sgibbs 20140024Sgibbs if (sg_map == NULL) 20240024Sgibbs return (0); 20340024Sgibbs 20440024Sgibbs blocks = sg_map->sg_vaddr; 20540024Sgibbs busaddr = sg_map->sg_physaddr; 20640024Sgibbs 20740024Sgibbs newcount = (PAGE_SIZE / (ADW_SG_BLOCKCNT * sizeof(*blocks))); 20840024Sgibbs for (i = 0; adw->num_acbs < adw->max_acbs && i < newcount; i++) { 20940024Sgibbs int error; 21040024Sgibbs 21140024Sgibbs error = bus_dmamap_create(adw->buffer_dmat, /*flags*/0, 21240024Sgibbs &next_acb->dmamap); 21340024Sgibbs if (error != 0) 21440024Sgibbs break; 21556979Sgibbs next_acb->queue.scsi_req_baddr = acbvtob(adw, next_acb); 21656979Sgibbs next_acb->queue.scsi_req_bo = acbvtobo(adw, next_acb); 21756979Sgibbs next_acb->queue.sense_baddr = 21856979Sgibbs acbvtob(adw, next_acb) + offsetof(struct acb, sense_data); 21940024Sgibbs next_acb->sg_blocks = blocks; 22040024Sgibbs next_acb->sg_busaddr = busaddr; 22140024Sgibbs next_acb->state = ACB_FREE; 222241588Sjhb callout_init_mtx(&next_acb->timer, &adw->lock, 0); 22340024Sgibbs SLIST_INSERT_HEAD(&adw->free_acb_list, next_acb, links); 22440024Sgibbs blocks += ADW_SG_BLOCKCNT; 22540024Sgibbs busaddr += ADW_SG_BLOCKCNT * sizeof(*blocks); 22640024Sgibbs next_acb++; 22740024Sgibbs adw->num_acbs++; 22840024Sgibbs } 22940024Sgibbs return (i); 23040024Sgibbs} 23140024Sgibbs 23240024Sgibbsstatic void 23340024Sgibbsadwexecuteacb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 23440024Sgibbs{ 23540024Sgibbs struct acb *acb; 23640024Sgibbs union ccb *ccb; 23740024Sgibbs struct adw_softc *adw; 23840024Sgibbs 23940024Sgibbs acb = (struct acb *)arg; 24040024Sgibbs ccb = acb->ccb; 24140024Sgibbs adw = (struct adw_softc *)ccb->ccb_h.ccb_adw_ptr; 24240024Sgibbs 243241588Sjhb if (!dumping) 244241588Sjhb mtx_assert(&adw->lock, MA_OWNED); 24540024Sgibbs if (error != 0) { 24640024Sgibbs if (error != EFBIG) 247241588Sjhb device_printf(adw->device, "Unexepected error 0x%x " 248241588Sjhb "returned from bus_dmamap_load\n", error); 24940024Sgibbs if (ccb->ccb_h.status == CAM_REQ_INPROG) { 25040024Sgibbs xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 25140024Sgibbs ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN; 25240024Sgibbs } 25340024Sgibbs adwfreeacb(adw, acb); 25440024Sgibbs xpt_done(ccb); 25540024Sgibbs return; 25640024Sgibbs } 25740024Sgibbs 25840024Sgibbs if (nseg != 0) { 259115343Sscottl bus_dmasync_op_t op; 26040024Sgibbs 26140024Sgibbs acb->queue.data_addr = dm_segs[0].ds_addr; 26240024Sgibbs acb->queue.data_cnt = ccb->csio.dxfer_len; 26340024Sgibbs if (nseg > 1) { 26440024Sgibbs struct adw_sg_block *sg_block; 26540024Sgibbs struct adw_sg_elm *sg; 26640024Sgibbs bus_addr_t sg_busaddr; 26740024Sgibbs u_int sg_index; 26840024Sgibbs bus_dma_segment_t *end_seg; 26940024Sgibbs 27040024Sgibbs end_seg = dm_segs + nseg; 27140024Sgibbs 27240024Sgibbs sg_busaddr = acb->sg_busaddr; 27340024Sgibbs sg_index = 0; 27440024Sgibbs /* Copy the segments into our SG list */ 27540024Sgibbs for (sg_block = acb->sg_blocks;; sg_block++) { 27656979Sgibbs u_int i; 27740024Sgibbs 27840024Sgibbs sg = sg_block->sg_list; 27956979Sgibbs for (i = 0; i < ADW_NO_OF_SG_PER_BLOCK; i++) { 28056979Sgibbs if (dm_segs >= end_seg) 28156979Sgibbs break; 28256979Sgibbs 28340024Sgibbs sg->sg_addr = dm_segs->ds_addr; 28440024Sgibbs sg->sg_count = dm_segs->ds_len; 28540024Sgibbs sg++; 28640024Sgibbs dm_segs++; 28740024Sgibbs } 28856979Sgibbs sg_block->sg_cnt = i; 28956979Sgibbs sg_index += i; 29040024Sgibbs if (dm_segs == end_seg) { 29140024Sgibbs sg_block->sg_busaddr_next = 0; 29240024Sgibbs break; 29340024Sgibbs } else { 29440024Sgibbs sg_busaddr += 29540024Sgibbs sizeof(struct adw_sg_block); 29640024Sgibbs sg_block->sg_busaddr_next = sg_busaddr; 29740024Sgibbs } 29840024Sgibbs } 29940024Sgibbs acb->queue.sg_real_addr = acb->sg_busaddr; 30040024Sgibbs } else { 30140024Sgibbs acb->queue.sg_real_addr = 0; 30240024Sgibbs } 30340024Sgibbs 30440024Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 30540024Sgibbs op = BUS_DMASYNC_PREREAD; 30640024Sgibbs else 30740024Sgibbs op = BUS_DMASYNC_PREWRITE; 30840024Sgibbs 30940024Sgibbs bus_dmamap_sync(adw->buffer_dmat, acb->dmamap, op); 31040024Sgibbs 31140024Sgibbs } else { 31240024Sgibbs acb->queue.data_addr = 0; 31340024Sgibbs acb->queue.data_cnt = 0; 31440024Sgibbs acb->queue.sg_real_addr = 0; 31540024Sgibbs } 31640024Sgibbs 31740024Sgibbs /* 31840024Sgibbs * Last time we need to check if this CCB needs to 31940024Sgibbs * be aborted. 32040024Sgibbs */ 32140024Sgibbs if (ccb->ccb_h.status != CAM_REQ_INPROG) { 32240024Sgibbs if (nseg != 0) 32340024Sgibbs bus_dmamap_unload(adw->buffer_dmat, acb->dmamap); 32440024Sgibbs adwfreeacb(adw, acb); 32540024Sgibbs xpt_done(ccb); 32640024Sgibbs return; 32740024Sgibbs } 32857679Sgibbs 32940024Sgibbs acb->state |= ACB_ACTIVE; 33040024Sgibbs ccb->ccb_h.status |= CAM_SIM_QUEUED; 33140024Sgibbs LIST_INSERT_HEAD(&adw->pending_ccbs, &ccb->ccb_h, sim_links.le); 332241588Sjhb callout_reset(&acb->timer, (ccb->ccb_h.timeout * hz) / 1000, 333241588Sjhb adwtimeout, acb); 33440024Sgibbs 33556979Sgibbs adw_send_acb(adw, acb, acbvtob(adw, acb)); 33640024Sgibbs} 33740024Sgibbs 33840024Sgibbsstatic void 33940024Sgibbsadw_action(struct cam_sim *sim, union ccb *ccb) 34040024Sgibbs{ 34140024Sgibbs struct adw_softc *adw; 34240024Sgibbs 34340024Sgibbs CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("adw_action\n")); 34440024Sgibbs 34540024Sgibbs adw = (struct adw_softc *)cam_sim_softc(sim); 346241588Sjhb if (!dumping) 347241588Sjhb mtx_assert(&adw->lock, MA_OWNED); 34840024Sgibbs 34940024Sgibbs switch (ccb->ccb_h.func_code) { 35040024Sgibbs /* Common cases first */ 35140024Sgibbs case XPT_SCSI_IO: /* Execute the requested I/O operation */ 35240024Sgibbs { 35340024Sgibbs struct ccb_scsiio *csio; 35440024Sgibbs struct ccb_hdr *ccbh; 35540024Sgibbs struct acb *acb; 356246713Skib int error; 35740024Sgibbs 35840024Sgibbs csio = &ccb->csio; 35940024Sgibbs ccbh = &ccb->ccb_h; 36056979Sgibbs 36140024Sgibbs /* Max supported CDB length is 12 bytes */ 36240024Sgibbs if (csio->cdb_len > 12) { 36340024Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 36440024Sgibbs xpt_done(ccb); 36540024Sgibbs return; 36640024Sgibbs } 36740024Sgibbs 36840024Sgibbs if ((acb = adwgetacb(adw)) == NULL) { 36940024Sgibbs adw->state |= ADW_RESOURCE_SHORTAGE; 37040024Sgibbs xpt_freeze_simq(sim, /*count*/1); 37140024Sgibbs ccb->ccb_h.status = CAM_REQUEUE_REQ; 37240024Sgibbs xpt_done(ccb); 37340024Sgibbs return; 37440024Sgibbs } 37540024Sgibbs 37656979Sgibbs /* Link acb and ccb so we can find one from the other */ 37740024Sgibbs acb->ccb = ccb; 37840024Sgibbs ccb->ccb_h.ccb_acb_ptr = acb; 37940024Sgibbs ccb->ccb_h.ccb_adw_ptr = adw; 38040024Sgibbs 38140024Sgibbs acb->queue.cntl = 0; 38256979Sgibbs acb->queue.target_cmd = 0; 38340024Sgibbs acb->queue.target_id = ccb->ccb_h.target_id; 38440024Sgibbs acb->queue.target_lun = ccb->ccb_h.target_lun; 38540024Sgibbs 38656979Sgibbs acb->queue.mflag = 0; 38740024Sgibbs acb->queue.sense_len = 38840024Sgibbs MIN(csio->sense_len, sizeof(acb->sense_data)); 38940024Sgibbs acb->queue.cdb_len = csio->cdb_len; 39056979Sgibbs if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0) { 39156979Sgibbs switch (csio->tag_action) { 39256979Sgibbs case MSG_SIMPLE_Q_TAG: 39357679Sgibbs acb->queue.scsi_cntl = ADW_QSC_SIMPLE_Q_TAG; 39456979Sgibbs break; 39556979Sgibbs case MSG_HEAD_OF_Q_TAG: 39656979Sgibbs acb->queue.scsi_cntl = ADW_QSC_HEAD_OF_Q_TAG; 39756979Sgibbs break; 39856979Sgibbs case MSG_ORDERED_Q_TAG: 39956979Sgibbs acb->queue.scsi_cntl = ADW_QSC_ORDERED_Q_TAG; 40056979Sgibbs break; 40157679Sgibbs default: 40257679Sgibbs acb->queue.scsi_cntl = ADW_QSC_NO_TAGMSG; 40357679Sgibbs break; 40456979Sgibbs } 40556979Sgibbs } else 40656979Sgibbs acb->queue.scsi_cntl = ADW_QSC_NO_TAGMSG; 40740024Sgibbs 40856979Sgibbs if ((ccb->ccb_h.flags & CAM_DIS_DISCONNECT) != 0) 40956979Sgibbs acb->queue.scsi_cntl |= ADW_QSC_NO_DISC; 41040024Sgibbs 41140024Sgibbs acb->queue.done_status = 0; 41240024Sgibbs acb->queue.scsi_status = 0; 41340024Sgibbs acb->queue.host_status = 0; 41456979Sgibbs acb->queue.sg_wk_ix = 0; 41540024Sgibbs if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) { 41640024Sgibbs if ((ccb->ccb_h.flags & CAM_CDB_PHYS) == 0) { 41740024Sgibbs bcopy(csio->cdb_io.cdb_ptr, 41840024Sgibbs acb->queue.cdb, csio->cdb_len); 41940024Sgibbs } else { 42040024Sgibbs /* I guess I could map it in... */ 42140024Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 42240024Sgibbs adwfreeacb(adw, acb); 42340024Sgibbs xpt_done(ccb); 42440024Sgibbs return; 42540024Sgibbs } 42640024Sgibbs } else { 42740024Sgibbs bcopy(csio->cdb_io.cdb_bytes, 42840024Sgibbs acb->queue.cdb, csio->cdb_len); 42940024Sgibbs } 43040024Sgibbs 431246713Skib error = bus_dmamap_load_ccb(adw->buffer_dmat, 432246713Skib acb->dmamap, 433246713Skib ccb, 434246713Skib adwexecuteacb, 435246713Skib acb, /*flags*/0); 436246713Skib if (error == EINPROGRESS) { 437246713Skib /* 438246713Skib * So as to maintain ordering, freeze the controller 439246713Skib * queue until our mapping is returned. 440246713Skib */ 441246713Skib xpt_freeze_simq(sim, 1); 442246713Skib acb->state |= CAM_RELEASE_SIMQ; 44340024Sgibbs } 44440024Sgibbs break; 44540024Sgibbs } 44640024Sgibbs case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ 44740024Sgibbs { 44840024Sgibbs adw_idle_cmd_status_t status; 44940024Sgibbs 45057679Sgibbs status = adw_idle_cmd_send(adw, ADW_IDLE_CMD_DEVICE_RESET, 45157679Sgibbs ccb->ccb_h.target_id); 45240024Sgibbs if (status == ADW_IDLE_CMD_SUCCESS) { 45340024Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 45440024Sgibbs if (bootverbose) { 45540024Sgibbs xpt_print_path(ccb->ccb_h.path); 45640024Sgibbs printf("BDR Delivered\n"); 45740024Sgibbs } 45840024Sgibbs } else 45940024Sgibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 46040024Sgibbs xpt_done(ccb); 46140024Sgibbs break; 46240024Sgibbs } 46340024Sgibbs case XPT_ABORT: /* Abort the specified CCB */ 46440024Sgibbs /* XXX Implement */ 46540024Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 46640024Sgibbs xpt_done(ccb); 46740024Sgibbs break; 46840024Sgibbs case XPT_SET_TRAN_SETTINGS: 46940024Sgibbs { 470163816Smjacob struct ccb_trans_settings_scsi *scsi; 471163816Smjacob struct ccb_trans_settings_spi *spi; 47240024Sgibbs struct ccb_trans_settings *cts; 47340024Sgibbs u_int target_mask; 47440024Sgibbs 47540024Sgibbs cts = &ccb->cts; 47640024Sgibbs target_mask = 0x01 << ccb->ccb_h.target_id; 47740024Sgibbs 478163816Smjacob scsi = &cts->proto_specific.scsi; 479163816Smjacob spi = &cts->xport_specific.spi; 480163816Smjacob if (cts->type == CTS_TYPE_CURRENT_SETTINGS) { 481163816Smjacob u_int sdtrdone; 482163816Smjacob 483163816Smjacob sdtrdone = adw_lram_read_16(adw, ADW_MC_SDTR_DONE); 484163816Smjacob if ((spi->valid & CTS_SPI_VALID_DISC) != 0) { 485163816Smjacob u_int discenb; 486163816Smjacob 487163816Smjacob discenb = 488163816Smjacob adw_lram_read_16(adw, ADW_MC_DISC_ENABLE); 489163816Smjacob 490163816Smjacob if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0) 491163816Smjacob discenb |= target_mask; 492163816Smjacob else 493163816Smjacob discenb &= ~target_mask; 494163816Smjacob 495163816Smjacob adw_lram_write_16(adw, ADW_MC_DISC_ENABLE, 496163816Smjacob discenb); 497163816Smjacob } 498163816Smjacob 499163816Smjacob if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) { 500163816Smjacob 501163816Smjacob if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) 502163816Smjacob adw->tagenb |= target_mask; 503163816Smjacob else 504163816Smjacob adw->tagenb &= ~target_mask; 505163816Smjacob } 506163816Smjacob 507163816Smjacob if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) { 508163816Smjacob u_int wdtrenb_orig; 509163816Smjacob u_int wdtrenb; 510163816Smjacob u_int wdtrdone; 511163816Smjacob 512163816Smjacob wdtrenb_orig = 513163816Smjacob adw_lram_read_16(adw, ADW_MC_WDTR_ABLE); 514163816Smjacob wdtrenb = wdtrenb_orig; 515163816Smjacob wdtrdone = adw_lram_read_16(adw, 516163816Smjacob ADW_MC_WDTR_DONE); 517163816Smjacob switch (spi->bus_width) { 518163816Smjacob case MSG_EXT_WDTR_BUS_32_BIT: 519163816Smjacob case MSG_EXT_WDTR_BUS_16_BIT: 520163816Smjacob wdtrenb |= target_mask; 521163816Smjacob break; 522163816Smjacob case MSG_EXT_WDTR_BUS_8_BIT: 523163816Smjacob default: 524163816Smjacob wdtrenb &= ~target_mask; 525163816Smjacob break; 526163816Smjacob } 527163816Smjacob if (wdtrenb != wdtrenb_orig) { 528163816Smjacob adw_lram_write_16(adw, 529163816Smjacob ADW_MC_WDTR_ABLE, 530163816Smjacob wdtrenb); 531163816Smjacob wdtrdone &= ~target_mask; 532163816Smjacob adw_lram_write_16(adw, 533163816Smjacob ADW_MC_WDTR_DONE, 534163816Smjacob wdtrdone); 535163816Smjacob /* Wide negotiation forces async */ 536163816Smjacob sdtrdone &= ~target_mask; 537163816Smjacob adw_lram_write_16(adw, 538163816Smjacob ADW_MC_SDTR_DONE, 539163816Smjacob sdtrdone); 540163816Smjacob } 541163816Smjacob } 542163816Smjacob 543163816Smjacob if (((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0) 544163816Smjacob || ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0)) { 545163816Smjacob u_int sdtr_orig; 546163816Smjacob u_int sdtr; 547163816Smjacob u_int sdtrable_orig; 548163816Smjacob u_int sdtrable; 549163816Smjacob 550163816Smjacob sdtr = adw_get_chip_sdtr(adw, 551163816Smjacob ccb->ccb_h.target_id); 552163816Smjacob sdtr_orig = sdtr; 553163816Smjacob sdtrable = adw_lram_read_16(adw, 554163816Smjacob ADW_MC_SDTR_ABLE); 555163816Smjacob sdtrable_orig = sdtrable; 556163816Smjacob 557163816Smjacob if ((spi->valid 558163816Smjacob & CTS_SPI_VALID_SYNC_RATE) != 0) { 559163816Smjacob 560163816Smjacob sdtr = 561163816Smjacob adw_find_sdtr(adw, 562163816Smjacob spi->sync_period); 563163816Smjacob } 564163816Smjacob 565163816Smjacob if ((spi->valid 566163816Smjacob & CTS_SPI_VALID_SYNC_OFFSET) != 0) { 567163816Smjacob if (spi->sync_offset == 0) 568163816Smjacob sdtr = ADW_MC_SDTR_ASYNC; 569163816Smjacob } 570163816Smjacob 571163816Smjacob if (sdtr == ADW_MC_SDTR_ASYNC) 572163816Smjacob sdtrable &= ~target_mask; 573163816Smjacob else 574163816Smjacob sdtrable |= target_mask; 575163816Smjacob if (sdtr != sdtr_orig 576163816Smjacob || sdtrable != sdtrable_orig) { 577163816Smjacob adw_set_chip_sdtr(adw, 578163816Smjacob ccb->ccb_h.target_id, 579163816Smjacob sdtr); 580163816Smjacob sdtrdone &= ~target_mask; 581163816Smjacob adw_lram_write_16(adw, ADW_MC_SDTR_ABLE, 582163816Smjacob sdtrable); 583163816Smjacob adw_lram_write_16(adw, ADW_MC_SDTR_DONE, 584163816Smjacob sdtrdone); 585163816Smjacob 586163816Smjacob } 587163816Smjacob } 588163816Smjacob } 58940024Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 59040024Sgibbs xpt_done(ccb); 59140024Sgibbs break; 59240024Sgibbs } 59340024Sgibbs case XPT_GET_TRAN_SETTINGS: 59440024Sgibbs /* Get default/user set transfer settings for the target */ 59540024Sgibbs { 596163816Smjacob struct ccb_trans_settings_scsi *scsi; 597163816Smjacob struct ccb_trans_settings_spi *spi; 59840024Sgibbs struct ccb_trans_settings *cts; 59940024Sgibbs u_int target_mask; 60040024Sgibbs 60140024Sgibbs cts = &ccb->cts; 60240024Sgibbs target_mask = 0x01 << ccb->ccb_h.target_id; 603163816Smjacob cts->protocol = PROTO_SCSI; 604163816Smjacob cts->protocol_version = SCSI_REV_2; 605163816Smjacob cts->transport = XPORT_SPI; 606163816Smjacob cts->transport_version = 2; 607163816Smjacob 608163816Smjacob scsi = &cts->proto_specific.scsi; 609163816Smjacob spi = &cts->xport_specific.spi; 610163816Smjacob if (cts->type == CTS_TYPE_CURRENT_SETTINGS) { 61156979Sgibbs u_int mc_sdtr; 61256979Sgibbs 613163816Smjacob spi->flags = 0; 614163816Smjacob if ((adw->user_discenb & target_mask) != 0) 615163816Smjacob spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 616163816Smjacob 617163816Smjacob if ((adw->user_tagenb & target_mask) != 0) 618163816Smjacob scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 619163816Smjacob 620163816Smjacob if ((adw->user_wdtr & target_mask) != 0) 621163816Smjacob spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 622163816Smjacob else 623163816Smjacob spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 624163816Smjacob 625163816Smjacob mc_sdtr = adw_get_user_sdtr(adw, ccb->ccb_h.target_id); 626163816Smjacob spi->sync_period = adw_find_period(adw, mc_sdtr); 627163816Smjacob if (spi->sync_period != 0) 628163816Smjacob spi->sync_offset = 15; /* XXX ??? */ 629163816Smjacob else 630163816Smjacob spi->sync_offset = 0; 631163816Smjacob 632163816Smjacob 633163816Smjacob } else { 634163816Smjacob u_int targ_tinfo; 635163816Smjacob 636163816Smjacob spi->flags = 0; 637163816Smjacob if ((adw_lram_read_16(adw, ADW_MC_DISC_ENABLE) 638163816Smjacob & target_mask) != 0) 639163816Smjacob spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 640163816Smjacob 641163816Smjacob if ((adw->tagenb & target_mask) != 0) 642163816Smjacob scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 643163816Smjacob 644163816Smjacob targ_tinfo = 645163816Smjacob adw_lram_read_16(adw, 646163816Smjacob ADW_MC_DEVICE_HSHK_CFG_TABLE 647163816Smjacob + (2 * ccb->ccb_h.target_id)); 648163816Smjacob 649163816Smjacob if ((targ_tinfo & ADW_HSHK_CFG_WIDE_XFR) != 0) 650163816Smjacob spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 651163816Smjacob else 652163816Smjacob spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 653163816Smjacob 654163816Smjacob spi->sync_period = 655163816Smjacob adw_hshk_cfg_period_factor(targ_tinfo); 656163816Smjacob 657163816Smjacob spi->sync_offset = targ_tinfo & ADW_HSHK_CFG_OFFSET; 658163816Smjacob if (spi->sync_period == 0) 659163816Smjacob spi->sync_offset = 0; 660163816Smjacob 661163816Smjacob if (spi->sync_offset == 0) 662163816Smjacob spi->sync_period = 0; 663163816Smjacob } 664163816Smjacob 665163816Smjacob spi->valid = CTS_SPI_VALID_SYNC_RATE 666163816Smjacob | CTS_SPI_VALID_SYNC_OFFSET 667163816Smjacob | CTS_SPI_VALID_BUS_WIDTH 668163816Smjacob | CTS_SPI_VALID_DISC; 669163816Smjacob scsi->valid = CTS_SCSI_VALID_TQ; 67040024Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 67140024Sgibbs xpt_done(ccb); 67240024Sgibbs break; 67340024Sgibbs } 67440024Sgibbs case XPT_CALC_GEOMETRY: 67540024Sgibbs { 67640024Sgibbs /* 67740024Sgibbs * XXX Use Adaptec translation until I find out how to 67840024Sgibbs * get this information from the card. 67940024Sgibbs */ 680116351Snjl cam_calc_geometry(&ccb->ccg, /*extended*/1); 68140024Sgibbs xpt_done(ccb); 68240024Sgibbs break; 68340024Sgibbs } 68440024Sgibbs case XPT_RESET_BUS: /* Reset the specified SCSI bus */ 68540024Sgibbs { 68657679Sgibbs int failure; 68740024Sgibbs 68857679Sgibbs failure = adw_reset_bus(adw); 68957679Sgibbs if (failure != 0) { 69040024Sgibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 69157679Sgibbs } else { 69257679Sgibbs if (bootverbose) { 69357679Sgibbs xpt_print_path(adw->path); 69457679Sgibbs printf("Bus Reset Delivered\n"); 69557679Sgibbs } 69657679Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 69756979Sgibbs } 69840024Sgibbs xpt_done(ccb); 69940024Sgibbs break; 70040024Sgibbs } 70140024Sgibbs case XPT_TERM_IO: /* Terminate the I/O process */ 70240024Sgibbs /* XXX Implement */ 70340024Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 70440024Sgibbs xpt_done(ccb); 70540024Sgibbs break; 70640024Sgibbs case XPT_PATH_INQ: /* Path routing inquiry */ 70740024Sgibbs { 70840024Sgibbs struct ccb_pathinq *cpi = &ccb->cpi; 70940024Sgibbs 71040024Sgibbs cpi->version_num = 1; 71140024Sgibbs cpi->hba_inquiry = PI_WIDE_16|PI_SDTR_ABLE|PI_TAG_ABLE; 71240024Sgibbs cpi->target_sprt = 0; 71340024Sgibbs cpi->hba_misc = 0; 71440024Sgibbs cpi->hba_eng_cnt = 0; 71540024Sgibbs cpi->max_target = ADW_MAX_TID; 71640024Sgibbs cpi->max_lun = ADW_MAX_LUN; 71740024Sgibbs cpi->initiator_id = adw->initiator_id; 71840024Sgibbs cpi->bus_id = cam_sim_bus(sim); 71946581Sken cpi->base_transfer_speed = 3300; 72040024Sgibbs strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 72140024Sgibbs strncpy(cpi->hba_vid, "AdvanSys", HBA_IDLEN); 72240024Sgibbs strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 72340024Sgibbs cpi->unit_number = cam_sim_unit(sim); 724163816Smjacob cpi->transport = XPORT_SPI; 725163816Smjacob cpi->transport_version = 2; 726163816Smjacob cpi->protocol = PROTO_SCSI; 727163816Smjacob cpi->protocol_version = SCSI_REV_2; 72840024Sgibbs cpi->ccb_h.status = CAM_REQ_CMP; 72940024Sgibbs xpt_done(ccb); 73040024Sgibbs break; 73140024Sgibbs } 73240024Sgibbs default: 73340024Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 73440024Sgibbs xpt_done(ccb); 73540024Sgibbs break; 73640024Sgibbs } 73740024Sgibbs} 73840024Sgibbs 73940024Sgibbsstatic void 74040024Sgibbsadw_poll(struct cam_sim *sim) 74140024Sgibbs{ 742241588Sjhb adw_intr_locked(cam_sim_softc(sim)); 74340024Sgibbs} 74440024Sgibbs 74540024Sgibbsstatic void 74640024Sgibbsadw_async(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg) 74740024Sgibbs{ 74840024Sgibbs} 74940024Sgibbs 75040024Sgibbsstruct adw_softc * 75156979Sgibbsadw_alloc(device_t dev, struct resource *regs, int regs_type, int regs_id) 75240024Sgibbs{ 75340024Sgibbs struct adw_softc *adw; 754241588Sjhb 755241588Sjhb adw = device_get_softc(dev); 75640024Sgibbs LIST_INIT(&adw->pending_ccbs); 75740024Sgibbs SLIST_INIT(&adw->sg_maps); 758241588Sjhb mtx_init(&adw->lock, "adw", NULL, MTX_DEF); 75956979Sgibbs adw->device = dev; 76056979Sgibbs adw->regs_res_type = regs_type; 76156979Sgibbs adw->regs_res_id = regs_id; 76256979Sgibbs adw->regs = regs; 76340024Sgibbs return(adw); 76440024Sgibbs} 76540024Sgibbs 76640024Sgibbsvoid 76740024Sgibbsadw_free(struct adw_softc *adw) 76840024Sgibbs{ 76940024Sgibbs switch (adw->init_level) { 77056979Sgibbs case 9: 77140024Sgibbs { 77240024Sgibbs struct sg_map_node *sg_map; 77340024Sgibbs 77440024Sgibbs while ((sg_map = SLIST_FIRST(&adw->sg_maps)) != NULL) { 77540024Sgibbs SLIST_REMOVE_HEAD(&adw->sg_maps, links); 77640024Sgibbs bus_dmamap_unload(adw->sg_dmat, 77740024Sgibbs sg_map->sg_dmamap); 77840024Sgibbs bus_dmamem_free(adw->sg_dmat, sg_map->sg_vaddr, 77940024Sgibbs sg_map->sg_dmamap); 78040024Sgibbs free(sg_map, M_DEVBUF); 78140024Sgibbs } 78240024Sgibbs bus_dma_tag_destroy(adw->sg_dmat); 78340024Sgibbs } 78456979Sgibbs case 8: 78540024Sgibbs bus_dmamap_unload(adw->acb_dmat, adw->acb_dmamap); 78656979Sgibbs case 7: 78740024Sgibbs bus_dmamem_free(adw->acb_dmat, adw->acbs, 78840024Sgibbs adw->acb_dmamap); 78940024Sgibbs bus_dmamap_destroy(adw->acb_dmat, adw->acb_dmamap); 79056979Sgibbs case 6: 79156979Sgibbs bus_dma_tag_destroy(adw->acb_dmat); 79256979Sgibbs case 5: 79356979Sgibbs bus_dmamap_unload(adw->carrier_dmat, adw->carrier_dmamap); 79456979Sgibbs case 4: 79556979Sgibbs bus_dmamem_free(adw->carrier_dmat, adw->carriers, 79656979Sgibbs adw->carrier_dmamap); 79756979Sgibbs bus_dmamap_destroy(adw->carrier_dmat, adw->carrier_dmamap); 79840024Sgibbs case 3: 79956979Sgibbs bus_dma_tag_destroy(adw->carrier_dmat); 80040024Sgibbs case 2: 80140024Sgibbs bus_dma_tag_destroy(adw->buffer_dmat); 80240024Sgibbs case 1: 80340024Sgibbs bus_dma_tag_destroy(adw->parent_dmat); 80440024Sgibbs case 0: 80540024Sgibbs break; 80640024Sgibbs } 807138502Srsm 808138502Srsm if (adw->regs != NULL) 809138502Srsm bus_release_resource(adw->device, 810138502Srsm adw->regs_res_type, 811138502Srsm adw->regs_res_id, 812138502Srsm adw->regs); 813138502Srsm 814138502Srsm if (adw->irq != NULL) 815138502Srsm bus_release_resource(adw->device, 816138502Srsm adw->irq_res_type, 817138502Srsm 0, adw->irq); 818138502Srsm 819138502Srsm if (adw->sim != NULL) { 820138502Srsm if (adw->path != NULL) { 821138502Srsm xpt_async(AC_LOST_DEVICE, adw->path, NULL); 822138502Srsm xpt_free_path(adw->path); 823138502Srsm } 824138502Srsm xpt_bus_deregister(cam_sim_path(adw->sim)); 825138502Srsm cam_sim_free(adw->sim, /*free_devq*/TRUE); 826138502Srsm } 827241588Sjhb mtx_destroy(&adw->lock); 82840024Sgibbs} 82940024Sgibbs 83040024Sgibbsint 83140024Sgibbsadw_init(struct adw_softc *adw) 83240024Sgibbs{ 83340024Sgibbs struct adw_eeprom eep_config; 83456979Sgibbs u_int tid; 83556979Sgibbs u_int i; 83640024Sgibbs u_int16_t checksum; 83740024Sgibbs u_int16_t scsicfg1; 83840024Sgibbs 83940024Sgibbs checksum = adw_eeprom_read(adw, &eep_config); 84040024Sgibbs bcopy(eep_config.serial_number, adw->serial_number, 84140024Sgibbs sizeof(adw->serial_number)); 84240024Sgibbs if (checksum != eep_config.checksum) { 84340024Sgibbs u_int16_t serial_number[3]; 84440024Sgibbs 84556979Sgibbs adw->flags |= ADW_EEPROM_FAILED; 846241588Sjhb device_printf(adw->device, 847241588Sjhb "EEPROM checksum failed. Restoring Defaults\n"); 84840024Sgibbs 84940024Sgibbs /* 85040024Sgibbs * Restore the default EEPROM settings. 85140024Sgibbs * Assume the 6 byte board serial number that was read 85240024Sgibbs * from EEPROM is correct even if the EEPROM checksum 85340024Sgibbs * failed. 85440024Sgibbs */ 85556979Sgibbs bcopy(adw->default_eeprom, &eep_config, sizeof(eep_config)); 85640024Sgibbs bcopy(adw->serial_number, eep_config.serial_number, 85740024Sgibbs sizeof(serial_number)); 85840024Sgibbs adw_eeprom_write(adw, &eep_config); 85940024Sgibbs } 86040024Sgibbs 86140024Sgibbs /* Pull eeprom information into our softc. */ 86240024Sgibbs adw->bios_ctrl = eep_config.bios_ctrl; 86340024Sgibbs adw->user_wdtr = eep_config.wdtr_able; 86456979Sgibbs for (tid = 0; tid < ADW_MAX_TID; tid++) { 86556979Sgibbs u_int mc_sdtr; 86656979Sgibbs u_int16_t tid_mask; 86756979Sgibbs 86856979Sgibbs tid_mask = 0x1 << tid; 86956979Sgibbs if ((adw->features & ADW_ULTRA) != 0) { 87056979Sgibbs /* 87156979Sgibbs * Ultra chips store sdtr and ultraenb 87256979Sgibbs * bits in their seeprom, so we must 87356979Sgibbs * construct valid mc_sdtr entries for 87456979Sgibbs * indirectly. 87556979Sgibbs */ 87656979Sgibbs if (eep_config.sync1.sync_enable & tid_mask) { 87756979Sgibbs if (eep_config.sync2.ultra_enable & tid_mask) 87856979Sgibbs mc_sdtr = ADW_MC_SDTR_20; 87956979Sgibbs else 88056979Sgibbs mc_sdtr = ADW_MC_SDTR_10; 88156979Sgibbs } else 88256979Sgibbs mc_sdtr = ADW_MC_SDTR_ASYNC; 88356979Sgibbs } else { 88456979Sgibbs switch (ADW_TARGET_GROUP(tid)) { 88556979Sgibbs case 3: 88656979Sgibbs mc_sdtr = eep_config.sync4.sdtr4; 88756979Sgibbs break; 88856979Sgibbs case 2: 88956979Sgibbs mc_sdtr = eep_config.sync3.sdtr3; 89056979Sgibbs break; 89156979Sgibbs case 1: 89256979Sgibbs mc_sdtr = eep_config.sync2.sdtr2; 89356979Sgibbs break; 89456979Sgibbs default: /* Shut up compiler */ 89556979Sgibbs case 0: 89656979Sgibbs mc_sdtr = eep_config.sync1.sdtr1; 89756979Sgibbs break; 89856979Sgibbs } 89956979Sgibbs mc_sdtr >>= ADW_TARGET_GROUP_SHIFT(tid); 90056979Sgibbs mc_sdtr &= 0xFF; 90156979Sgibbs } 90256979Sgibbs adw_set_user_sdtr(adw, tid, mc_sdtr); 90356979Sgibbs } 90440024Sgibbs adw->user_tagenb = eep_config.tagqng_able; 90540024Sgibbs adw->user_discenb = eep_config.disc_enable; 90640024Sgibbs adw->max_acbs = eep_config.max_host_qng; 90740024Sgibbs adw->initiator_id = (eep_config.adapter_scsi_id & ADW_MAX_TID); 90840024Sgibbs 90940024Sgibbs /* 91040024Sgibbs * Sanity check the number of host openings. 91140024Sgibbs */ 91240024Sgibbs if (adw->max_acbs > ADW_DEF_MAX_HOST_QNG) 91340024Sgibbs adw->max_acbs = ADW_DEF_MAX_HOST_QNG; 91440024Sgibbs else if (adw->max_acbs < ADW_DEF_MIN_HOST_QNG) { 91540024Sgibbs /* If the value is zero, assume it is uninitialized. */ 91640024Sgibbs if (adw->max_acbs == 0) 91740024Sgibbs adw->max_acbs = ADW_DEF_MAX_HOST_QNG; 91840024Sgibbs else 91940024Sgibbs adw->max_acbs = ADW_DEF_MIN_HOST_QNG; 92040024Sgibbs } 92140024Sgibbs 92240024Sgibbs scsicfg1 = 0; 92356979Sgibbs if ((adw->features & ADW_ULTRA2) != 0) { 92456979Sgibbs switch (eep_config.termination_lvd) { 92556979Sgibbs default: 926241588Sjhb device_printf(adw->device, 927241588Sjhb "Invalid EEPROM LVD Termination Settings.\n"); 928241588Sjhb device_printf(adw->device, 929241588Sjhb "Reverting to Automatic LVD Termination\n"); 93056979Sgibbs /* FALLTHROUGH */ 93156979Sgibbs case ADW_EEPROM_TERM_AUTO: 93256979Sgibbs break; 93356979Sgibbs case ADW_EEPROM_TERM_BOTH_ON: 93456979Sgibbs scsicfg1 |= ADW2_SCSI_CFG1_TERM_LVD_LO; 93556979Sgibbs /* FALLTHROUGH */ 93656979Sgibbs case ADW_EEPROM_TERM_HIGH_ON: 93756979Sgibbs scsicfg1 |= ADW2_SCSI_CFG1_TERM_LVD_HI; 93856979Sgibbs /* FALLTHROUGH */ 93956979Sgibbs case ADW_EEPROM_TERM_OFF: 94056979Sgibbs scsicfg1 |= ADW2_SCSI_CFG1_DIS_TERM_DRV; 94156979Sgibbs break; 94256979Sgibbs } 94356979Sgibbs } 94456979Sgibbs 94556979Sgibbs switch (eep_config.termination_se) { 94640024Sgibbs default: 947241588Sjhb device_printf(adw->device, 948241588Sjhb "Invalid SE EEPROM Termination Settings.\n"); 949241588Sjhb device_printf(adw->device, 950241588Sjhb "Reverting to Automatic SE Termination\n"); 95140024Sgibbs /* FALLTHROUGH */ 95240024Sgibbs case ADW_EEPROM_TERM_AUTO: 95340024Sgibbs break; 95440024Sgibbs case ADW_EEPROM_TERM_BOTH_ON: 95540024Sgibbs scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_L; 95640024Sgibbs /* FALLTHROUGH */ 95740024Sgibbs case ADW_EEPROM_TERM_HIGH_ON: 95840024Sgibbs scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_H; 95940024Sgibbs /* FALLTHROUGH */ 96040024Sgibbs case ADW_EEPROM_TERM_OFF: 96140024Sgibbs scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_MANUAL; 96240024Sgibbs break; 96340024Sgibbs } 964241588Sjhb device_printf(adw->device, "SCSI ID %d, ", adw->initiator_id); 96540024Sgibbs 96640024Sgibbs /* DMA tag for mapping buffers into device visible space. */ 967112782Smdodd if (bus_dma_tag_create( 968112782Smdodd /* parent */ adw->parent_dmat, 969112782Smdodd /* alignment */ 1, 970112782Smdodd /* boundary */ 0, 971112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, 972112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 973112782Smdodd /* filter */ NULL, 974112782Smdodd /* filterarg */ NULL, 975112782Smdodd /* maxsize */ MAXBSIZE, 976112782Smdodd /* nsegments */ ADW_SGSIZE, 977112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT, 978112782Smdodd /* flags */ BUS_DMA_ALLOCNOW, 979117126Sscottl /* lockfunc */ busdma_lock_mutex, 980241588Sjhb /* lockarg */ &adw->lock, 981112782Smdodd &adw->buffer_dmat) != 0) { 98256979Sgibbs return (ENOMEM); 98340024Sgibbs } 98440024Sgibbs 98540024Sgibbs adw->init_level++; 98640024Sgibbs 98756979Sgibbs /* DMA tag for our ccb carrier structures */ 988112782Smdodd if (bus_dma_tag_create( 989112782Smdodd /* parent */ adw->parent_dmat, 990112782Smdodd /* alignment */ 0x10, 991112782Smdodd /* boundary */ 0, 992112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, 993112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 994112782Smdodd /* filter */ NULL, 995112782Smdodd /* filterarg */ NULL, 996112782Smdodd /* maxsize */ (adw->max_acbs + 997112782Smdodd ADW_NUM_CARRIER_QUEUES + 1) * 998112782Smdodd sizeof(struct adw_carrier), 999112782Smdodd /* nsegments */ 1, 1000112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT, 1001112782Smdodd /* flags */ 0, 1002241588Sjhb /* lockfunc */ NULL, 1003241588Sjhb /* lockarg */ NULL, 1004112782Smdodd &adw->carrier_dmat) != 0) { 100556979Sgibbs return (ENOMEM); 100656979Sgibbs } 100756979Sgibbs 100856979Sgibbs adw->init_level++; 100956979Sgibbs 101056979Sgibbs /* Allocation for our ccb carrier structures */ 101156979Sgibbs if (bus_dmamem_alloc(adw->carrier_dmat, (void **)&adw->carriers, 101256979Sgibbs BUS_DMA_NOWAIT, &adw->carrier_dmamap) != 0) { 101356979Sgibbs return (ENOMEM); 101456979Sgibbs } 101556979Sgibbs 101656979Sgibbs adw->init_level++; 101756979Sgibbs 101856979Sgibbs /* And permanently map them */ 101956979Sgibbs bus_dmamap_load(adw->carrier_dmat, adw->carrier_dmamap, 102056979Sgibbs adw->carriers, 102156979Sgibbs (adw->max_acbs + ADW_NUM_CARRIER_QUEUES + 1) 102256979Sgibbs * sizeof(struct adw_carrier), 102356979Sgibbs adwmapmem, &adw->carrier_busbase, /*flags*/0); 102456979Sgibbs 102556979Sgibbs /* Clear them out. */ 102656979Sgibbs bzero(adw->carriers, (adw->max_acbs + ADW_NUM_CARRIER_QUEUES + 1) 102756979Sgibbs * sizeof(struct adw_carrier)); 102856979Sgibbs 102956979Sgibbs /* Setup our free carrier list */ 103056979Sgibbs adw->free_carriers = adw->carriers; 103156979Sgibbs for (i = 0; i < adw->max_acbs + ADW_NUM_CARRIER_QUEUES; i++) { 103256979Sgibbs adw->carriers[i].carr_offset = 103356979Sgibbs carriervtobo(adw, &adw->carriers[i]); 103456979Sgibbs adw->carriers[i].carr_ba = 103556979Sgibbs carriervtob(adw, &adw->carriers[i]); 103656979Sgibbs adw->carriers[i].areq_ba = 0; 103756979Sgibbs adw->carriers[i].next_ba = 103856979Sgibbs carriervtobo(adw, &adw->carriers[i+1]); 103956979Sgibbs } 104056979Sgibbs /* Terminal carrier. Never leaves the freelist */ 104156979Sgibbs adw->carriers[i].carr_offset = 104256979Sgibbs carriervtobo(adw, &adw->carriers[i]); 104356979Sgibbs adw->carriers[i].carr_ba = 104456979Sgibbs carriervtob(adw, &adw->carriers[i]); 104556979Sgibbs adw->carriers[i].areq_ba = 0; 104656979Sgibbs adw->carriers[i].next_ba = ~0; 104756979Sgibbs 104856979Sgibbs adw->init_level++; 104956979Sgibbs 105056979Sgibbs /* DMA tag for our acb structures */ 1051112782Smdodd if (bus_dma_tag_create( 1052112782Smdodd /* parent */ adw->parent_dmat, 1053112782Smdodd /* alignment */ 1, 1054112782Smdodd /* boundary */ 0, 1055112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR, 1056112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 1057112782Smdodd /* filter */ NULL, 1058112782Smdodd /* filterarg */ NULL, 1059112782Smdodd /* maxsize */ adw->max_acbs * sizeof(struct acb), 1060112782Smdodd /* nsegments */ 1, 1061112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT, 1062112782Smdodd /* flags */ 0, 1063241588Sjhb /* lockfunc */ NULL, 1064241588Sjhb /* lockarg */ NULL, 1065112782Smdodd &adw->acb_dmat) != 0) { 106656979Sgibbs return (ENOMEM); 106740024Sgibbs } 106840024Sgibbs 106940024Sgibbs adw->init_level++; 107040024Sgibbs 107140024Sgibbs /* Allocation for our ccbs */ 107240024Sgibbs if (bus_dmamem_alloc(adw->acb_dmat, (void **)&adw->acbs, 107356979Sgibbs BUS_DMA_NOWAIT, &adw->acb_dmamap) != 0) 107456979Sgibbs return (ENOMEM); 107540024Sgibbs 107640024Sgibbs adw->init_level++; 107740024Sgibbs 107840024Sgibbs /* And permanently map them */ 107940024Sgibbs bus_dmamap_load(adw->acb_dmat, adw->acb_dmamap, 108040024Sgibbs adw->acbs, 108140024Sgibbs adw->max_acbs * sizeof(struct acb), 108240024Sgibbs adwmapmem, &adw->acb_busbase, /*flags*/0); 108340024Sgibbs 108440024Sgibbs /* Clear them out. */ 108540024Sgibbs bzero(adw->acbs, adw->max_acbs * sizeof(struct acb)); 108640024Sgibbs 108740024Sgibbs /* DMA tag for our S/G structures. We allocate in page sized chunks */ 1088112782Smdodd if (bus_dma_tag_create( 1089112782Smdodd /* parent */ adw->parent_dmat, 1090112782Smdodd /* alignment */ 1, 1091112782Smdodd /* boundary */ 0, 1092112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR, 1093112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 1094112782Smdodd /* filter */ NULL, 1095112782Smdodd /* filterarg */ NULL, 1096112782Smdodd /* maxsize */ PAGE_SIZE, 1097112782Smdodd /* nsegments */ 1, 1098112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT, 1099112782Smdodd /* flags */ 0, 1100241588Sjhb /* lockfunc */ NULL, 1101241588Sjhb /* lockarg */ NULL, 1102112782Smdodd &adw->sg_dmat) != 0) { 110356979Sgibbs return (ENOMEM); 110440024Sgibbs } 110540024Sgibbs 110640024Sgibbs adw->init_level++; 110740024Sgibbs 110840024Sgibbs /* Allocate our first batch of ccbs */ 1109241588Sjhb mtx_lock(&adw->lock); 1110241588Sjhb if (adwallocacbs(adw) == 0) { 1111241588Sjhb mtx_unlock(&adw->lock); 111256979Sgibbs return (ENOMEM); 1113241588Sjhb } 111440024Sgibbs 1115241588Sjhb if (adw_init_chip(adw, scsicfg1) != 0) { 1116241588Sjhb mtx_unlock(&adw->lock); 111756979Sgibbs return (ENXIO); 1118241588Sjhb } 111956979Sgibbs 112056979Sgibbs printf("Queue Depth %d\n", adw->max_acbs); 1121241588Sjhb mtx_unlock(&adw->lock); 112256979Sgibbs 112340024Sgibbs return (0); 112440024Sgibbs} 112540024Sgibbs 112640024Sgibbs/* 112740024Sgibbs * Attach all the sub-devices we can find 112840024Sgibbs */ 112940024Sgibbsint 113040024Sgibbsadw_attach(struct adw_softc *adw) 113140024Sgibbs{ 113240024Sgibbs struct ccb_setasync csa; 113340024Sgibbs struct cam_devq *devq; 113456979Sgibbs int error; 113540024Sgibbs 113656979Sgibbs /* Hook up our interrupt handler */ 1137241588Sjhb error = bus_setup_intr(adw->device, adw->irq, 1138241588Sjhb INTR_TYPE_CAM | INTR_ENTROPY | INTR_MPSAFE, NULL, adw_intr, adw, 1139241588Sjhb &adw->ih); 1140241588Sjhb if (error != 0) { 114156979Sgibbs device_printf(adw->device, "bus_setup_intr() failed: %d\n", 114256979Sgibbs error); 1143241588Sjhb return (error); 114456979Sgibbs } 114556979Sgibbs 114640024Sgibbs /* Start the Risc processor now that we are fully configured. */ 114740024Sgibbs adw_outw(adw, ADW_RISC_CSR, ADW_RISC_CSR_RUN); 114840024Sgibbs 114940024Sgibbs /* 115040024Sgibbs * Create the device queue for our SIM. 115140024Sgibbs */ 115240024Sgibbs devq = cam_simq_alloc(adw->max_acbs); 115340024Sgibbs if (devq == NULL) 115456979Sgibbs return (ENOMEM); 115540024Sgibbs 115640024Sgibbs /* 115740024Sgibbs * Construct our SIM entry. 115840024Sgibbs */ 1159241588Sjhb adw->sim = cam_sim_alloc(adw_action, adw_poll, "adw", adw, 1160241588Sjhb device_get_unit(adw->device), &adw->lock, 1, adw->max_acbs, devq); 1161241588Sjhb if (adw->sim == NULL) 1162241588Sjhb return (ENOMEM); 116340024Sgibbs 116440024Sgibbs /* 116540024Sgibbs * Register the bus. 116640024Sgibbs */ 1167241588Sjhb mtx_lock(&adw->lock); 1168170872Sscottl if (xpt_bus_register(adw->sim, adw->device, 0) != CAM_SUCCESS) { 116940024Sgibbs cam_sim_free(adw->sim, /*free devq*/TRUE); 117056979Sgibbs error = ENOMEM; 117156979Sgibbs goto fail; 117240024Sgibbs } 117340024Sgibbs 117440024Sgibbs if (xpt_create_path(&adw->path, /*periph*/NULL, cam_sim_path(adw->sim), 117540024Sgibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) 117640024Sgibbs == CAM_REQ_CMP) { 117740024Sgibbs xpt_setup_ccb(&csa.ccb_h, adw->path, /*priority*/5); 117840024Sgibbs csa.ccb_h.func_code = XPT_SASYNC_CB; 117940024Sgibbs csa.event_enable = AC_LOST_DEVICE; 118040024Sgibbs csa.callback = adw_async; 118140024Sgibbs csa.callback_arg = adw; 118240024Sgibbs xpt_action((union ccb *)&csa); 118340024Sgibbs } 118440024Sgibbs 118556979Sgibbsfail: 1186241588Sjhb mtx_unlock(&adw->lock); 118756979Sgibbs return (error); 118840024Sgibbs} 118940024Sgibbs 119040024Sgibbsvoid 119140024Sgibbsadw_intr(void *arg) 119240024Sgibbs{ 119340024Sgibbs struct adw_softc *adw; 1194241588Sjhb 1195241588Sjhb adw = arg; 1196241588Sjhb mtx_lock(&adw->lock); 1197241588Sjhb adw_intr_locked(adw); 1198241588Sjhb mtx_unlock(&adw->lock); 1199241588Sjhb} 1200241588Sjhb 1201241588Sjhbvoid 1202241588Sjhbadw_intr_locked(struct adw_softc *adw) 1203241588Sjhb{ 120440024Sgibbs u_int int_stat; 120540024Sgibbs 120640024Sgibbs if ((adw_inw(adw, ADW_CTRL_REG) & ADW_CTRL_REG_HOST_INTR) == 0) 120740024Sgibbs return; 120840024Sgibbs 120940024Sgibbs /* Reading the register clears the interrupt. */ 121040024Sgibbs int_stat = adw_inb(adw, ADW_INTR_STATUS_REG); 121140024Sgibbs 121240024Sgibbs if ((int_stat & ADW_INTR_STATUS_INTRB) != 0) { 121356979Sgibbs u_int intrb_code; 121456979Sgibbs 121556979Sgibbs /* Async Microcode Event */ 121656979Sgibbs intrb_code = adw_lram_read_8(adw, ADW_MC_INTRB_CODE); 121756979Sgibbs switch (intrb_code) { 121856979Sgibbs case ADW_ASYNC_CARRIER_READY_FAILURE: 121956979Sgibbs /* 122056979Sgibbs * The RISC missed our update of 122156979Sgibbs * the commandq. 122256979Sgibbs */ 122356979Sgibbs if (LIST_FIRST(&adw->pending_ccbs) != NULL) 122456979Sgibbs adw_tickle_risc(adw, ADW_TICKLE_A); 122540024Sgibbs break; 122656979Sgibbs case ADW_ASYNC_SCSI_BUS_RESET_DET: 122756979Sgibbs /* 122856979Sgibbs * The firmware detected a SCSI Bus reset. 122956979Sgibbs */ 1230241588Sjhb device_printf(adw->device, "Someone Reset the Bus\n"); 123156979Sgibbs adw_handle_bus_reset(adw, /*initiated*/FALSE); 123256979Sgibbs break; 123356979Sgibbs case ADW_ASYNC_RDMA_FAILURE: 123456979Sgibbs /* 123556979Sgibbs * Handle RDMA failure by resetting the 123656979Sgibbs * SCSI Bus and chip. 123756979Sgibbs */ 1238153072Sru#if 0 /* XXX */ 123956979Sgibbs AdvResetChipAndSB(adv_dvc_varp); 124056979Sgibbs#endif 124156979Sgibbs break; 124256979Sgibbs 124356979Sgibbs case ADW_ASYNC_HOST_SCSI_BUS_RESET: 124456979Sgibbs /* 124556979Sgibbs * Host generated SCSI bus reset occurred. 124656979Sgibbs */ 124740024Sgibbs adw_handle_bus_reset(adw, /*initiated*/TRUE); 124856979Sgibbs break; 124956979Sgibbs default: 125056979Sgibbs printf("adw_intr: unknown async code 0x%x\n", 125156979Sgibbs intrb_code); 125240024Sgibbs break; 125340024Sgibbs } 125440024Sgibbs } 125540024Sgibbs 125640024Sgibbs /* 125756979Sgibbs * Run down the RequestQ. 125840024Sgibbs */ 125956979Sgibbs while ((adw->responseq->next_ba & ADW_RQ_DONE) != 0) { 126056979Sgibbs struct adw_carrier *free_carrier; 126156979Sgibbs struct acb *acb; 126256979Sgibbs union ccb *ccb; 126340024Sgibbs 126456979Sgibbs#if 0 126556979Sgibbs printf("0x%x, 0x%x, 0x%x, 0x%x\n", 126656979Sgibbs adw->responseq->carr_offset, 126756979Sgibbs adw->responseq->carr_ba, 126856979Sgibbs adw->responseq->areq_ba, 126956979Sgibbs adw->responseq->next_ba); 127056979Sgibbs#endif 127156979Sgibbs /* 127256979Sgibbs * The firmware copies the adw_scsi_req_q.acb_baddr 127356979Sgibbs * field into the areq_ba field of the carrier. 127456979Sgibbs */ 127556979Sgibbs acb = acbbotov(adw, adw->responseq->areq_ba); 127640024Sgibbs 127740024Sgibbs /* 127856979Sgibbs * The least significant four bits of the next_ba 127956979Sgibbs * field are used as flags. Mask them out and then 128056979Sgibbs * advance through the list. 128140024Sgibbs */ 128256979Sgibbs free_carrier = adw->responseq; 128356979Sgibbs adw->responseq = 128456979Sgibbs carrierbotov(adw, free_carrier->next_ba & ADW_NEXT_BA_MASK); 128556979Sgibbs free_carrier->next_ba = adw->free_carriers->carr_offset; 128656979Sgibbs adw->free_carriers = free_carrier; 128740024Sgibbs 128840024Sgibbs /* Process CCB */ 128940024Sgibbs ccb = acb->ccb; 1290241588Sjhb callout_stop(&acb->timer); 129140024Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 1292115343Sscottl bus_dmasync_op_t op; 129340024Sgibbs 129440024Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 129540024Sgibbs op = BUS_DMASYNC_POSTREAD; 129640024Sgibbs else 129740024Sgibbs op = BUS_DMASYNC_POSTWRITE; 129840024Sgibbs bus_dmamap_sync(adw->buffer_dmat, acb->dmamap, op); 129940024Sgibbs bus_dmamap_unload(adw->buffer_dmat, acb->dmamap); 130040024Sgibbs ccb->csio.resid = acb->queue.data_cnt; 130140024Sgibbs } else 130240024Sgibbs ccb->csio.resid = 0; 130340024Sgibbs 130440024Sgibbs /* Common Cases inline... */ 130540024Sgibbs if (acb->queue.host_status == QHSTA_NO_ERROR 130640024Sgibbs && (acb->queue.done_status == QD_NO_ERROR 130740024Sgibbs || acb->queue.done_status == QD_WITH_ERROR)) { 130840024Sgibbs ccb->csio.scsi_status = acb->queue.scsi_status; 130940024Sgibbs ccb->ccb_h.status = 0; 131040024Sgibbs switch (ccb->csio.scsi_status) { 131140024Sgibbs case SCSI_STATUS_OK: 131240024Sgibbs ccb->ccb_h.status |= CAM_REQ_CMP; 131340024Sgibbs break; 131440024Sgibbs case SCSI_STATUS_CHECK_COND: 131540024Sgibbs case SCSI_STATUS_CMD_TERMINATED: 131640024Sgibbs bcopy(&acb->sense_data, &ccb->csio.sense_data, 131740024Sgibbs ccb->csio.sense_len); 131840024Sgibbs ccb->ccb_h.status |= CAM_AUTOSNS_VALID; 131940024Sgibbs ccb->csio.sense_resid = acb->queue.sense_len; 132040024Sgibbs /* FALLTHROUGH */ 132140024Sgibbs default: 132240024Sgibbs ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR 132340024Sgibbs | CAM_DEV_QFRZN; 132440024Sgibbs xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 132540024Sgibbs break; 132640024Sgibbs } 132740024Sgibbs adwfreeacb(adw, acb); 132840024Sgibbs xpt_done(ccb); 132940024Sgibbs } else { 133040024Sgibbs adwprocesserror(adw, acb); 133140024Sgibbs } 133240024Sgibbs } 133340024Sgibbs} 133440024Sgibbs 133540024Sgibbsstatic void 133640024Sgibbsadwprocesserror(struct adw_softc *adw, struct acb *acb) 133740024Sgibbs{ 133840024Sgibbs union ccb *ccb; 133940024Sgibbs 134040024Sgibbs ccb = acb->ccb; 134140024Sgibbs if (acb->queue.done_status == QD_ABORTED_BY_HOST) { 134240024Sgibbs ccb->ccb_h.status = CAM_REQ_ABORTED; 134340024Sgibbs } else { 134440024Sgibbs 134540024Sgibbs switch (acb->queue.host_status) { 134640024Sgibbs case QHSTA_M_SEL_TIMEOUT: 134740024Sgibbs ccb->ccb_h.status = CAM_SEL_TIMEOUT; 134840024Sgibbs break; 134940024Sgibbs case QHSTA_M_SXFR_OFF_UFLW: 135040024Sgibbs case QHSTA_M_SXFR_OFF_OFLW: 135140024Sgibbs case QHSTA_M_DATA_OVER_RUN: 135240024Sgibbs ccb->ccb_h.status = CAM_DATA_RUN_ERR; 135340024Sgibbs break; 135440024Sgibbs case QHSTA_M_SXFR_DESELECTED: 135540024Sgibbs case QHSTA_M_UNEXPECTED_BUS_FREE: 135640024Sgibbs ccb->ccb_h.status = CAM_UNEXP_BUSFREE; 135740024Sgibbs break; 135857679Sgibbs case QHSTA_M_SCSI_BUS_RESET: 135957679Sgibbs case QHSTA_M_SCSI_BUS_RESET_UNSOL: 136057679Sgibbs ccb->ccb_h.status = CAM_SCSI_BUS_RESET; 136157679Sgibbs break; 136257679Sgibbs case QHSTA_M_BUS_DEVICE_RESET: 136357679Sgibbs ccb->ccb_h.status = CAM_BDR_SENT; 136457679Sgibbs break; 136540024Sgibbs case QHSTA_M_QUEUE_ABORTED: 136640024Sgibbs /* BDR or Bus Reset */ 1367241588Sjhb xpt_print_path(adw->path); 136857679Sgibbs printf("Saw Queue Aborted\n"); 136940024Sgibbs ccb->ccb_h.status = adw->last_reset; 137040024Sgibbs break; 137140024Sgibbs case QHSTA_M_SXFR_SDMA_ERR: 137240024Sgibbs case QHSTA_M_SXFR_SXFR_PERR: 137340024Sgibbs case QHSTA_M_RDMA_PERR: 137440024Sgibbs ccb->ccb_h.status = CAM_UNCOR_PARITY; 137540024Sgibbs break; 137640024Sgibbs case QHSTA_M_WTM_TIMEOUT: 137740024Sgibbs case QHSTA_M_SXFR_WD_TMO: 137856979Sgibbs { 137940024Sgibbs /* The SCSI bus hung in a phase */ 138057679Sgibbs xpt_print_path(adw->path); 1381241588Sjhb printf("Watch Dog timer expired. Resetting bus\n"); 138257679Sgibbs adw_reset_bus(adw); 138340024Sgibbs break; 138456979Sgibbs } 138540024Sgibbs case QHSTA_M_SXFR_XFR_PH_ERR: 138640024Sgibbs ccb->ccb_h.status = CAM_SEQUENCE_FAIL; 138740024Sgibbs break; 138840024Sgibbs case QHSTA_M_SXFR_UNKNOWN_ERROR: 138940024Sgibbs break; 139040024Sgibbs case QHSTA_M_BAD_CMPL_STATUS_IN: 139140024Sgibbs /* No command complete after a status message */ 139240024Sgibbs ccb->ccb_h.status = CAM_SEQUENCE_FAIL; 139340024Sgibbs break; 139440024Sgibbs case QHSTA_M_AUTO_REQ_SENSE_FAIL: 139540024Sgibbs ccb->ccb_h.status = CAM_AUTOSENSE_FAIL; 139640024Sgibbs break; 139740024Sgibbs case QHSTA_M_INVALID_DEVICE: 139840024Sgibbs ccb->ccb_h.status = CAM_PATH_INVALID; 139940024Sgibbs break; 140040024Sgibbs case QHSTA_M_NO_AUTO_REQ_SENSE: 140140024Sgibbs /* 140240024Sgibbs * User didn't request sense, but we got a 140340024Sgibbs * check condition. 140440024Sgibbs */ 140540024Sgibbs ccb->csio.scsi_status = acb->queue.scsi_status; 140640024Sgibbs ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; 140740024Sgibbs break; 140840024Sgibbs default: 140940024Sgibbs panic("%s: Unhandled Host status error %x", 1410241588Sjhb device_get_nameunit(adw->device), 1411241588Sjhb acb->queue.host_status); 141240024Sgibbs /* NOTREACHED */ 141340024Sgibbs } 141440024Sgibbs } 141557679Sgibbs if ((acb->state & ACB_RECOVERY_ACB) != 0) { 141657679Sgibbs if (ccb->ccb_h.status == CAM_SCSI_BUS_RESET 141757679Sgibbs || ccb->ccb_h.status == CAM_BDR_SENT) 141857679Sgibbs ccb->ccb_h.status = CAM_CMD_TIMEOUT; 141957679Sgibbs } 142040024Sgibbs if (ccb->ccb_h.status != CAM_REQ_CMP) { 142140024Sgibbs xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 142240024Sgibbs ccb->ccb_h.status |= CAM_DEV_QFRZN; 142340024Sgibbs } 142440024Sgibbs adwfreeacb(adw, acb); 142540024Sgibbs xpt_done(ccb); 142640024Sgibbs} 142740024Sgibbs 142840024Sgibbsstatic void 142940024Sgibbsadwtimeout(void *arg) 143040024Sgibbs{ 143140024Sgibbs struct acb *acb; 143240024Sgibbs union ccb *ccb; 143340024Sgibbs struct adw_softc *adw; 143440024Sgibbs adw_idle_cmd_status_t status; 143557679Sgibbs int target_id; 143640024Sgibbs 143740024Sgibbs acb = (struct acb *)arg; 143840024Sgibbs ccb = acb->ccb; 143940024Sgibbs adw = (struct adw_softc *)ccb->ccb_h.ccb_adw_ptr; 144040024Sgibbs xpt_print_path(ccb->ccb_h.path); 144140024Sgibbs printf("ACB %p - timed out\n", (void *)acb); 144240024Sgibbs 1443241588Sjhb mtx_assert(&adw->lock, MA_OWNED); 144440024Sgibbs 144540024Sgibbs if ((acb->state & ACB_ACTIVE) == 0) { 144640024Sgibbs xpt_print_path(ccb->ccb_h.path); 144740024Sgibbs printf("ACB %p - timed out CCB already completed\n", 144840024Sgibbs (void *)acb); 144940024Sgibbs return; 145040024Sgibbs } 145140024Sgibbs 145257679Sgibbs acb->state |= ACB_RECOVERY_ACB; 145357679Sgibbs target_id = ccb->ccb_h.target_id; 145457679Sgibbs 145540024Sgibbs /* Attempt a BDR first */ 145657679Sgibbs status = adw_idle_cmd_send(adw, ADW_IDLE_CMD_DEVICE_RESET, 145757679Sgibbs ccb->ccb_h.target_id); 145840024Sgibbs if (status == ADW_IDLE_CMD_SUCCESS) { 1459241588Sjhb device_printf(adw->device, 1460241588Sjhb "BDR Delivered. No longer in timeout\n"); 146157679Sgibbs adw_handle_device_reset(adw, target_id); 146240024Sgibbs } else { 146357679Sgibbs adw_reset_bus(adw); 146457679Sgibbs xpt_print_path(adw->path); 146557679Sgibbs printf("Bus Reset Delivered. No longer in timeout\n"); 146640024Sgibbs } 146740024Sgibbs} 146840024Sgibbs 146940024Sgibbsstatic void 147040024Sgibbsadw_handle_device_reset(struct adw_softc *adw, u_int target) 147140024Sgibbs{ 147240024Sgibbs struct cam_path *path; 147340024Sgibbs cam_status error; 147440024Sgibbs 147540024Sgibbs error = xpt_create_path(&path, /*periph*/NULL, cam_sim_path(adw->sim), 147640024Sgibbs target, CAM_LUN_WILDCARD); 147740024Sgibbs 147840024Sgibbs if (error == CAM_REQ_CMP) { 147940024Sgibbs xpt_async(AC_SENT_BDR, path, NULL); 148040024Sgibbs xpt_free_path(path); 148140024Sgibbs } 148240024Sgibbs adw->last_reset = CAM_BDR_SENT; 148340024Sgibbs} 148440024Sgibbs 148540024Sgibbsstatic void 148640024Sgibbsadw_handle_bus_reset(struct adw_softc *adw, int initiated) 148740024Sgibbs{ 148840024Sgibbs if (initiated) { 148940024Sgibbs /* 149040024Sgibbs * The microcode currently sets the SCSI Bus Reset signal 149140024Sgibbs * while handling the AscSendIdleCmd() IDLE_CMD_SCSI_RESET 149240024Sgibbs * command above. But the SCSI Bus Reset Hold Time in the 149340024Sgibbs * microcode is not deterministic (it may in fact be for less 149440024Sgibbs * than the SCSI Spec. minimum of 25 us). Therefore on return 149540024Sgibbs * the Adv Library sets the SCSI Bus Reset signal for 149640024Sgibbs * ADW_SCSI_RESET_HOLD_TIME_US, which is defined to be greater 149740024Sgibbs * than 25 us. 149840024Sgibbs */ 149940024Sgibbs u_int scsi_ctrl; 150040024Sgibbs 150140024Sgibbs scsi_ctrl = adw_inw(adw, ADW_SCSI_CTRL) & ~ADW_SCSI_CTRL_RSTOUT; 150240024Sgibbs adw_outw(adw, ADW_SCSI_CTRL, scsi_ctrl | ADW_SCSI_CTRL_RSTOUT); 150340024Sgibbs DELAY(ADW_SCSI_RESET_HOLD_TIME_US); 150440024Sgibbs adw_outw(adw, ADW_SCSI_CTRL, scsi_ctrl); 150540024Sgibbs 150640024Sgibbs /* 150740024Sgibbs * We will perform the async notification when the 150840024Sgibbs * SCSI Reset interrupt occurs. 150940024Sgibbs */ 151040024Sgibbs } else 151140024Sgibbs xpt_async(AC_BUS_RESET, adw->path, NULL); 151240024Sgibbs adw->last_reset = CAM_SCSI_BUS_RESET; 151340024Sgibbs} 1514165102SmjacobMODULE_DEPEND(adw, cam, 1, 1, 1); 1515165102Smjacob 1516