adwcam.c revision 138502
140024Sgibbs/* 240024Sgibbs * CAM SCSI interface for the 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 138502 2004-12-06 23:17:04Z rsm $"); 48119418Sobrien 4940024Sgibbs#include <sys/param.h> 5040024Sgibbs#include <sys/systm.h> 5140024Sgibbs#include <sys/kernel.h> 5240024Sgibbs#include <sys/malloc.h> 53117126Sscottl#include <sys/lock.h> 54117126Sscottl#include <sys/mutex.h> 5556979Sgibbs#include <sys/bus.h> 5640024Sgibbs 5740024Sgibbs#include <machine/bus_pio.h> 5840024Sgibbs#include <machine/bus_memio.h> 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 7840024Sgibbsu_long adw_unit; 7940024Sgibbs 8057679Sgibbsstatic __inline cam_status adwccbstatus(union ccb*); 8140024Sgibbsstatic __inline struct acb* adwgetacb(struct adw_softc *adw); 8240024Sgibbsstatic __inline void adwfreeacb(struct adw_softc *adw, 8340024Sgibbs struct acb *acb); 8440024Sgibbs 8540024Sgibbsstatic void adwmapmem(void *arg, bus_dma_segment_t *segs, 8640024Sgibbs int nseg, int error); 8740024Sgibbsstatic struct sg_map_node* 8840024Sgibbs adwallocsgmap(struct adw_softc *adw); 8940024Sgibbsstatic int adwallocacbs(struct adw_softc *adw); 9040024Sgibbs 9140024Sgibbsstatic void adwexecuteacb(void *arg, bus_dma_segment_t *dm_segs, 9240024Sgibbs int nseg, int error); 9340024Sgibbsstatic void adw_action(struct cam_sim *sim, union ccb *ccb); 9440024Sgibbsstatic void adw_poll(struct cam_sim *sim); 9540024Sgibbsstatic void adw_async(void *callback_arg, u_int32_t code, 9640024Sgibbs struct cam_path *path, void *arg); 9740024Sgibbsstatic void adwprocesserror(struct adw_softc *adw, struct acb *acb); 9840024Sgibbsstatic void adwtimeout(void *arg); 9940024Sgibbsstatic void adw_handle_device_reset(struct adw_softc *adw, 10040024Sgibbs u_int target); 10140024Sgibbsstatic void adw_handle_bus_reset(struct adw_softc *adw, 10240024Sgibbs int initiated); 10340024Sgibbs 10457679Sgibbsstatic __inline cam_status 10557679Sgibbsadwccbstatus(union ccb* ccb) 10657679Sgibbs{ 10757679Sgibbs return (ccb->ccb_h.status & CAM_STATUS_MASK); 10857679Sgibbs} 10957679Sgibbs 11040024Sgibbsstatic __inline struct acb* 11140024Sgibbsadwgetacb(struct adw_softc *adw) 11240024Sgibbs{ 11340024Sgibbs struct acb* acb; 11440024Sgibbs int s; 11540024Sgibbs 11640024Sgibbs s = splcam(); 11740024Sgibbs if ((acb = SLIST_FIRST(&adw->free_acb_list)) != NULL) { 11840024Sgibbs SLIST_REMOVE_HEAD(&adw->free_acb_list, links); 11940024Sgibbs } else if (adw->num_acbs < adw->max_acbs) { 12040024Sgibbs adwallocacbs(adw); 12140024Sgibbs acb = SLIST_FIRST(&adw->free_acb_list); 12240024Sgibbs if (acb == NULL) 12340024Sgibbs printf("%s: Can't malloc ACB\n", adw_name(adw)); 12440024Sgibbs else { 12540024Sgibbs SLIST_REMOVE_HEAD(&adw->free_acb_list, links); 12640024Sgibbs } 12740024Sgibbs } 12840024Sgibbs splx(s); 12940024Sgibbs 13040024Sgibbs return (acb); 13140024Sgibbs} 13240024Sgibbs 13340024Sgibbsstatic __inline void 13440024Sgibbsadwfreeacb(struct adw_softc *adw, struct acb *acb) 13540024Sgibbs{ 13640024Sgibbs int s; 13740024Sgibbs 13840024Sgibbs s = splcam(); 13940024Sgibbs if ((acb->state & ACB_ACTIVE) != 0) 14040024Sgibbs LIST_REMOVE(&acb->ccb->ccb_h, sim_links.le); 14140024Sgibbs if ((acb->state & ACB_RELEASE_SIMQ) != 0) 14240024Sgibbs acb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 14340024Sgibbs else if ((adw->state & ADW_RESOURCE_SHORTAGE) != 0 14440024Sgibbs && (acb->ccb->ccb_h.status & CAM_RELEASE_SIMQ) == 0) { 14540024Sgibbs acb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 14640024Sgibbs adw->state &= ~ADW_RESOURCE_SHORTAGE; 14740024Sgibbs } 14840024Sgibbs acb->state = ACB_FREE; 14940024Sgibbs SLIST_INSERT_HEAD(&adw->free_acb_list, acb, links); 15040024Sgibbs splx(s); 15140024Sgibbs} 15240024Sgibbs 15340024Sgibbsstatic void 15440024Sgibbsadwmapmem(void *arg, bus_dma_segment_t *segs, int nseg, int error) 15540024Sgibbs{ 15640024Sgibbs bus_addr_t *busaddrp; 15740024Sgibbs 15840024Sgibbs busaddrp = (bus_addr_t *)arg; 15940024Sgibbs *busaddrp = segs->ds_addr; 16040024Sgibbs} 16140024Sgibbs 16240024Sgibbsstatic struct sg_map_node * 16340024Sgibbsadwallocsgmap(struct adw_softc *adw) 16440024Sgibbs{ 16540024Sgibbs struct sg_map_node *sg_map; 16640024Sgibbs 16740024Sgibbs sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT); 16840024Sgibbs 16940024Sgibbs if (sg_map == NULL) 17040024Sgibbs return (NULL); 17140024Sgibbs 17240024Sgibbs /* Allocate S/G space for the next batch of ACBS */ 17340024Sgibbs if (bus_dmamem_alloc(adw->sg_dmat, (void **)&sg_map->sg_vaddr, 17440024Sgibbs BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) { 17540024Sgibbs free(sg_map, M_DEVBUF); 17640024Sgibbs return (NULL); 17740024Sgibbs } 17840024Sgibbs 17940024Sgibbs SLIST_INSERT_HEAD(&adw->sg_maps, sg_map, links); 18040024Sgibbs 18140024Sgibbs bus_dmamap_load(adw->sg_dmat, sg_map->sg_dmamap, sg_map->sg_vaddr, 18240024Sgibbs PAGE_SIZE, adwmapmem, &sg_map->sg_physaddr, /*flags*/0); 18340024Sgibbs 18440024Sgibbs bzero(sg_map->sg_vaddr, PAGE_SIZE); 18540024Sgibbs return (sg_map); 18640024Sgibbs} 18740024Sgibbs 18840024Sgibbs/* 18940024Sgibbs * Allocate another chunk of CCB's. Return count of entries added. 19040024Sgibbs * Assumed to be called at splcam(). 19140024Sgibbs */ 19240024Sgibbsstatic int 19340024Sgibbsadwallocacbs(struct adw_softc *adw) 19440024Sgibbs{ 19540024Sgibbs struct acb *next_acb; 19640024Sgibbs struct sg_map_node *sg_map; 19740024Sgibbs bus_addr_t busaddr; 19840024Sgibbs struct adw_sg_block *blocks; 19940024Sgibbs int newcount; 20040024Sgibbs int i; 20140024Sgibbs 20240024Sgibbs next_acb = &adw->acbs[adw->num_acbs]; 20340024Sgibbs sg_map = adwallocsgmap(adw); 20440024Sgibbs 20540024Sgibbs if (sg_map == NULL) 20640024Sgibbs return (0); 20740024Sgibbs 20840024Sgibbs blocks = sg_map->sg_vaddr; 20940024Sgibbs busaddr = sg_map->sg_physaddr; 21040024Sgibbs 21140024Sgibbs newcount = (PAGE_SIZE / (ADW_SG_BLOCKCNT * sizeof(*blocks))); 21240024Sgibbs for (i = 0; adw->num_acbs < adw->max_acbs && i < newcount; i++) { 21340024Sgibbs int error; 21440024Sgibbs 21540024Sgibbs error = bus_dmamap_create(adw->buffer_dmat, /*flags*/0, 21640024Sgibbs &next_acb->dmamap); 21740024Sgibbs if (error != 0) 21840024Sgibbs break; 21956979Sgibbs next_acb->queue.scsi_req_baddr = acbvtob(adw, next_acb); 22056979Sgibbs next_acb->queue.scsi_req_bo = acbvtobo(adw, next_acb); 22156979Sgibbs next_acb->queue.sense_baddr = 22256979Sgibbs acbvtob(adw, next_acb) + offsetof(struct acb, sense_data); 22340024Sgibbs next_acb->sg_blocks = blocks; 22440024Sgibbs next_acb->sg_busaddr = busaddr; 22540024Sgibbs next_acb->state = ACB_FREE; 22640024Sgibbs SLIST_INSERT_HEAD(&adw->free_acb_list, next_acb, links); 22740024Sgibbs blocks += ADW_SG_BLOCKCNT; 22840024Sgibbs busaddr += ADW_SG_BLOCKCNT * sizeof(*blocks); 22940024Sgibbs next_acb++; 23040024Sgibbs adw->num_acbs++; 23140024Sgibbs } 23240024Sgibbs return (i); 23340024Sgibbs} 23440024Sgibbs 23540024Sgibbsstatic void 23640024Sgibbsadwexecuteacb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 23740024Sgibbs{ 23840024Sgibbs struct acb *acb; 23940024Sgibbs union ccb *ccb; 24040024Sgibbs struct adw_softc *adw; 24140420Sgibbs int s; 24240024Sgibbs 24340024Sgibbs acb = (struct acb *)arg; 24440024Sgibbs ccb = acb->ccb; 24540024Sgibbs adw = (struct adw_softc *)ccb->ccb_h.ccb_adw_ptr; 24640024Sgibbs 24740024Sgibbs if (error != 0) { 24840024Sgibbs if (error != EFBIG) 24940024Sgibbs printf("%s: Unexepected error 0x%x returned from " 25040024Sgibbs "bus_dmamap_load\n", adw_name(adw), error); 25140024Sgibbs if (ccb->ccb_h.status == CAM_REQ_INPROG) { 25240024Sgibbs xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 25340024Sgibbs ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN; 25440024Sgibbs } 25540024Sgibbs adwfreeacb(adw, acb); 25640024Sgibbs xpt_done(ccb); 25740024Sgibbs return; 25840024Sgibbs } 25940024Sgibbs 26040024Sgibbs if (nseg != 0) { 261115343Sscottl bus_dmasync_op_t op; 26240024Sgibbs 26340024Sgibbs acb->queue.data_addr = dm_segs[0].ds_addr; 26440024Sgibbs acb->queue.data_cnt = ccb->csio.dxfer_len; 26540024Sgibbs if (nseg > 1) { 26640024Sgibbs struct adw_sg_block *sg_block; 26740024Sgibbs struct adw_sg_elm *sg; 26840024Sgibbs bus_addr_t sg_busaddr; 26940024Sgibbs u_int sg_index; 27040024Sgibbs bus_dma_segment_t *end_seg; 27140024Sgibbs 27240024Sgibbs end_seg = dm_segs + nseg; 27340024Sgibbs 27440024Sgibbs sg_busaddr = acb->sg_busaddr; 27540024Sgibbs sg_index = 0; 27640024Sgibbs /* Copy the segments into our SG list */ 27740024Sgibbs for (sg_block = acb->sg_blocks;; sg_block++) { 27856979Sgibbs u_int i; 27940024Sgibbs 28040024Sgibbs sg = sg_block->sg_list; 28156979Sgibbs for (i = 0; i < ADW_NO_OF_SG_PER_BLOCK; i++) { 28256979Sgibbs if (dm_segs >= end_seg) 28356979Sgibbs break; 28456979Sgibbs 28540024Sgibbs sg->sg_addr = dm_segs->ds_addr; 28640024Sgibbs sg->sg_count = dm_segs->ds_len; 28740024Sgibbs sg++; 28840024Sgibbs dm_segs++; 28940024Sgibbs } 29056979Sgibbs sg_block->sg_cnt = i; 29156979Sgibbs sg_index += i; 29240024Sgibbs if (dm_segs == end_seg) { 29340024Sgibbs sg_block->sg_busaddr_next = 0; 29440024Sgibbs break; 29540024Sgibbs } else { 29640024Sgibbs sg_busaddr += 29740024Sgibbs sizeof(struct adw_sg_block); 29840024Sgibbs sg_block->sg_busaddr_next = sg_busaddr; 29940024Sgibbs } 30040024Sgibbs } 30140024Sgibbs acb->queue.sg_real_addr = acb->sg_busaddr; 30240024Sgibbs } else { 30340024Sgibbs acb->queue.sg_real_addr = 0; 30440024Sgibbs } 30540024Sgibbs 30640024Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 30740024Sgibbs op = BUS_DMASYNC_PREREAD; 30840024Sgibbs else 30940024Sgibbs op = BUS_DMASYNC_PREWRITE; 31040024Sgibbs 31140024Sgibbs bus_dmamap_sync(adw->buffer_dmat, acb->dmamap, op); 31240024Sgibbs 31340024Sgibbs } else { 31440024Sgibbs acb->queue.data_addr = 0; 31540024Sgibbs acb->queue.data_cnt = 0; 31640024Sgibbs acb->queue.sg_real_addr = 0; 31740024Sgibbs } 31840024Sgibbs 31940024Sgibbs s = splcam(); 32040024Sgibbs 32140024Sgibbs /* 32240024Sgibbs * Last time we need to check if this CCB needs to 32340024Sgibbs * be aborted. 32440024Sgibbs */ 32540024Sgibbs if (ccb->ccb_h.status != CAM_REQ_INPROG) { 32640024Sgibbs if (nseg != 0) 32740024Sgibbs bus_dmamap_unload(adw->buffer_dmat, acb->dmamap); 32840024Sgibbs adwfreeacb(adw, acb); 32940024Sgibbs xpt_done(ccb); 33040024Sgibbs splx(s); 33140024Sgibbs return; 33240024Sgibbs } 33357679Sgibbs 33440024Sgibbs acb->state |= ACB_ACTIVE; 33540024Sgibbs ccb->ccb_h.status |= CAM_SIM_QUEUED; 33640024Sgibbs LIST_INSERT_HEAD(&adw->pending_ccbs, &ccb->ccb_h, sim_links.le); 33740024Sgibbs ccb->ccb_h.timeout_ch = 33840024Sgibbs timeout(adwtimeout, (caddr_t)acb, 33940024Sgibbs (ccb->ccb_h.timeout * hz) / 1000); 34040024Sgibbs 34156979Sgibbs adw_send_acb(adw, acb, acbvtob(adw, acb)); 34240024Sgibbs 34340024Sgibbs splx(s); 34440024Sgibbs} 34540024Sgibbs 34640024Sgibbsstatic void 34740024Sgibbsadw_action(struct cam_sim *sim, union ccb *ccb) 34840024Sgibbs{ 34940024Sgibbs struct adw_softc *adw; 35040024Sgibbs 35140024Sgibbs CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("adw_action\n")); 35240024Sgibbs 35340024Sgibbs adw = (struct adw_softc *)cam_sim_softc(sim); 35440024Sgibbs 35540024Sgibbs switch (ccb->ccb_h.func_code) { 35640024Sgibbs /* Common cases first */ 35740024Sgibbs case XPT_SCSI_IO: /* Execute the requested I/O operation */ 35840024Sgibbs { 35940024Sgibbs struct ccb_scsiio *csio; 36040024Sgibbs struct ccb_hdr *ccbh; 36140024Sgibbs struct acb *acb; 36240024Sgibbs 36340024Sgibbs csio = &ccb->csio; 36440024Sgibbs ccbh = &ccb->ccb_h; 36556979Sgibbs 36640024Sgibbs /* Max supported CDB length is 12 bytes */ 36740024Sgibbs if (csio->cdb_len > 12) { 36840024Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 36940024Sgibbs xpt_done(ccb); 37040024Sgibbs return; 37140024Sgibbs } 37240024Sgibbs 37340024Sgibbs if ((acb = adwgetacb(adw)) == NULL) { 37440024Sgibbs int s; 37540024Sgibbs 37640024Sgibbs s = splcam(); 37740024Sgibbs adw->state |= ADW_RESOURCE_SHORTAGE; 37840024Sgibbs splx(s); 37940024Sgibbs xpt_freeze_simq(sim, /*count*/1); 38040024Sgibbs ccb->ccb_h.status = CAM_REQUEUE_REQ; 38140024Sgibbs xpt_done(ccb); 38240024Sgibbs return; 38340024Sgibbs } 38440024Sgibbs 38556979Sgibbs /* Link acb and ccb so we can find one from the other */ 38640024Sgibbs acb->ccb = ccb; 38740024Sgibbs ccb->ccb_h.ccb_acb_ptr = acb; 38840024Sgibbs ccb->ccb_h.ccb_adw_ptr = adw; 38940024Sgibbs 39040024Sgibbs acb->queue.cntl = 0; 39156979Sgibbs acb->queue.target_cmd = 0; 39240024Sgibbs acb->queue.target_id = ccb->ccb_h.target_id; 39340024Sgibbs acb->queue.target_lun = ccb->ccb_h.target_lun; 39440024Sgibbs 39556979Sgibbs acb->queue.mflag = 0; 39640024Sgibbs acb->queue.sense_len = 39740024Sgibbs MIN(csio->sense_len, sizeof(acb->sense_data)); 39840024Sgibbs acb->queue.cdb_len = csio->cdb_len; 39956979Sgibbs if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0) { 40056979Sgibbs switch (csio->tag_action) { 40156979Sgibbs case MSG_SIMPLE_Q_TAG: 40257679Sgibbs acb->queue.scsi_cntl = ADW_QSC_SIMPLE_Q_TAG; 40356979Sgibbs break; 40456979Sgibbs case MSG_HEAD_OF_Q_TAG: 40556979Sgibbs acb->queue.scsi_cntl = ADW_QSC_HEAD_OF_Q_TAG; 40656979Sgibbs break; 40756979Sgibbs case MSG_ORDERED_Q_TAG: 40856979Sgibbs acb->queue.scsi_cntl = ADW_QSC_ORDERED_Q_TAG; 40956979Sgibbs break; 41057679Sgibbs default: 41157679Sgibbs acb->queue.scsi_cntl = ADW_QSC_NO_TAGMSG; 41257679Sgibbs break; 41356979Sgibbs } 41456979Sgibbs } else 41556979Sgibbs acb->queue.scsi_cntl = ADW_QSC_NO_TAGMSG; 41640024Sgibbs 41756979Sgibbs if ((ccb->ccb_h.flags & CAM_DIS_DISCONNECT) != 0) 41856979Sgibbs acb->queue.scsi_cntl |= ADW_QSC_NO_DISC; 41940024Sgibbs 42040024Sgibbs acb->queue.done_status = 0; 42140024Sgibbs acb->queue.scsi_status = 0; 42240024Sgibbs acb->queue.host_status = 0; 42356979Sgibbs acb->queue.sg_wk_ix = 0; 42440024Sgibbs if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) { 42540024Sgibbs if ((ccb->ccb_h.flags & CAM_CDB_PHYS) == 0) { 42640024Sgibbs bcopy(csio->cdb_io.cdb_ptr, 42740024Sgibbs acb->queue.cdb, csio->cdb_len); 42840024Sgibbs } else { 42940024Sgibbs /* I guess I could map it in... */ 43040024Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 43140024Sgibbs adwfreeacb(adw, acb); 43240024Sgibbs xpt_done(ccb); 43340024Sgibbs return; 43440024Sgibbs } 43540024Sgibbs } else { 43640024Sgibbs bcopy(csio->cdb_io.cdb_bytes, 43740024Sgibbs acb->queue.cdb, csio->cdb_len); 43840024Sgibbs } 43940024Sgibbs 44040024Sgibbs /* 44140024Sgibbs * If we have any data to send with this command, 44240024Sgibbs * map it into bus space. 44340024Sgibbs */ 44440024Sgibbs if ((ccbh->flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 44540024Sgibbs if ((ccbh->flags & CAM_SCATTER_VALID) == 0) { 44640024Sgibbs /* 44740024Sgibbs * We've been given a pointer 44840024Sgibbs * to a single buffer. 44940024Sgibbs */ 45040024Sgibbs if ((ccbh->flags & CAM_DATA_PHYS) == 0) { 45140024Sgibbs int s; 45240024Sgibbs int error; 45340024Sgibbs 45440024Sgibbs s = splsoftvm(); 45540024Sgibbs error = 45640024Sgibbs bus_dmamap_load(adw->buffer_dmat, 45740024Sgibbs acb->dmamap, 45840024Sgibbs csio->data_ptr, 45940024Sgibbs csio->dxfer_len, 46040024Sgibbs adwexecuteacb, 46140024Sgibbs acb, /*flags*/0); 46240024Sgibbs if (error == EINPROGRESS) { 46340024Sgibbs /* 46440024Sgibbs * So as to maintain ordering, 46540024Sgibbs * freeze the controller queue 46640024Sgibbs * until our mapping is 46740024Sgibbs * returned. 46840024Sgibbs */ 46940024Sgibbs xpt_freeze_simq(sim, 1); 47040024Sgibbs acb->state |= CAM_RELEASE_SIMQ; 47140024Sgibbs } 47240024Sgibbs splx(s); 47340024Sgibbs } else { 47440024Sgibbs struct bus_dma_segment seg; 47540024Sgibbs 47640024Sgibbs /* Pointer to physical buffer */ 47740024Sgibbs seg.ds_addr = 47840024Sgibbs (bus_addr_t)csio->data_ptr; 47940024Sgibbs seg.ds_len = csio->dxfer_len; 48040024Sgibbs adwexecuteacb(acb, &seg, 1, 0); 48140024Sgibbs } 48240024Sgibbs } else { 48340024Sgibbs struct bus_dma_segment *segs; 48440024Sgibbs 48540024Sgibbs if ((ccbh->flags & CAM_DATA_PHYS) != 0) 48640024Sgibbs panic("adw_action - Physical " 48740024Sgibbs "segment pointers " 48840024Sgibbs "unsupported"); 48940024Sgibbs 49040024Sgibbs if ((ccbh->flags&CAM_SG_LIST_PHYS)==0) 49140024Sgibbs panic("adw_action - Virtual " 49240024Sgibbs "segment addresses " 49340024Sgibbs "unsupported"); 49440024Sgibbs 49540024Sgibbs /* Just use the segments provided */ 49640024Sgibbs segs = (struct bus_dma_segment *)csio->data_ptr; 49740024Sgibbs adwexecuteacb(acb, segs, csio->sglist_cnt, 49840024Sgibbs (csio->sglist_cnt < ADW_SGSIZE) 49940024Sgibbs ? 0 : EFBIG); 50040024Sgibbs } 50140024Sgibbs } else { 50240024Sgibbs adwexecuteacb(acb, NULL, 0, 0); 50340024Sgibbs } 50440024Sgibbs break; 50540024Sgibbs } 50640024Sgibbs case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ 50740024Sgibbs { 50840024Sgibbs adw_idle_cmd_status_t status; 50940024Sgibbs 51057679Sgibbs status = adw_idle_cmd_send(adw, ADW_IDLE_CMD_DEVICE_RESET, 51157679Sgibbs ccb->ccb_h.target_id); 51240024Sgibbs if (status == ADW_IDLE_CMD_SUCCESS) { 51340024Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 51440024Sgibbs if (bootverbose) { 51540024Sgibbs xpt_print_path(ccb->ccb_h.path); 51640024Sgibbs printf("BDR Delivered\n"); 51740024Sgibbs } 51840024Sgibbs } else 51940024Sgibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 52040024Sgibbs xpt_done(ccb); 52140024Sgibbs break; 52240024Sgibbs } 52340024Sgibbs case XPT_ABORT: /* Abort the specified CCB */ 52440024Sgibbs /* XXX Implement */ 52540024Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 52640024Sgibbs xpt_done(ccb); 52740024Sgibbs break; 52840024Sgibbs case XPT_SET_TRAN_SETTINGS: 52940024Sgibbs { 53040024Sgibbs struct ccb_trans_settings *cts; 53140024Sgibbs u_int target_mask; 53240024Sgibbs int s; 53340024Sgibbs 53440024Sgibbs cts = &ccb->cts; 53540024Sgibbs target_mask = 0x01 << ccb->ccb_h.target_id; 53640024Sgibbs 53740024Sgibbs s = splcam(); 53840024Sgibbs if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) { 53956979Sgibbs u_int sdtrdone; 54056979Sgibbs 54156979Sgibbs sdtrdone = adw_lram_read_16(adw, ADW_MC_SDTR_DONE); 54240024Sgibbs if ((cts->valid & CCB_TRANS_DISC_VALID) != 0) { 54340024Sgibbs u_int discenb; 54440024Sgibbs 54540024Sgibbs discenb = 54640024Sgibbs adw_lram_read_16(adw, ADW_MC_DISC_ENABLE); 54740024Sgibbs 54840024Sgibbs if ((cts->flags & CCB_TRANS_DISC_ENB) != 0) 54940024Sgibbs discenb |= target_mask; 55040024Sgibbs else 55140024Sgibbs discenb &= ~target_mask; 55240024Sgibbs 55340024Sgibbs adw_lram_write_16(adw, ADW_MC_DISC_ENABLE, 55440024Sgibbs discenb); 55540024Sgibbs } 55640024Sgibbs 55740024Sgibbs if ((cts->valid & CCB_TRANS_TQ_VALID) != 0) { 55840024Sgibbs 55940024Sgibbs if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) 56040024Sgibbs adw->tagenb |= target_mask; 56140024Sgibbs else 56240024Sgibbs adw->tagenb &= ~target_mask; 56340024Sgibbs } 56440024Sgibbs 56540024Sgibbs if ((cts->valid & CCB_TRANS_BUS_WIDTH_VALID) != 0) { 56640024Sgibbs u_int wdtrenb_orig; 56740024Sgibbs u_int wdtrenb; 56840024Sgibbs u_int wdtrdone; 56940024Sgibbs 57040024Sgibbs wdtrenb_orig = 57140024Sgibbs adw_lram_read_16(adw, ADW_MC_WDTR_ABLE); 57240024Sgibbs wdtrenb = wdtrenb_orig; 57340024Sgibbs wdtrdone = adw_lram_read_16(adw, 57440024Sgibbs ADW_MC_WDTR_DONE); 57540024Sgibbs switch (cts->bus_width) { 57640024Sgibbs case MSG_EXT_WDTR_BUS_32_BIT: 57740024Sgibbs case MSG_EXT_WDTR_BUS_16_BIT: 57840024Sgibbs wdtrenb |= target_mask; 57940024Sgibbs break; 58040024Sgibbs case MSG_EXT_WDTR_BUS_8_BIT: 58140024Sgibbs default: 58240024Sgibbs wdtrenb &= ~target_mask; 58340024Sgibbs break; 58440024Sgibbs } 58540024Sgibbs if (wdtrenb != wdtrenb_orig) { 58640024Sgibbs adw_lram_write_16(adw, 58740024Sgibbs ADW_MC_WDTR_ABLE, 58840024Sgibbs wdtrenb); 58940024Sgibbs wdtrdone &= ~target_mask; 59040024Sgibbs adw_lram_write_16(adw, 59140024Sgibbs ADW_MC_WDTR_DONE, 59240024Sgibbs wdtrdone); 59356979Sgibbs /* Wide negotiation forces async */ 59456979Sgibbs sdtrdone &= ~target_mask; 59556979Sgibbs adw_lram_write_16(adw, 59656979Sgibbs ADW_MC_SDTR_DONE, 59756979Sgibbs sdtrdone); 59840024Sgibbs } 59940024Sgibbs } 60040024Sgibbs 60146581Sken if (((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0) 60246581Sken || ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0)) { 60356979Sgibbs u_int sdtr_orig; 60456979Sgibbs u_int sdtr; 60556979Sgibbs u_int sdtrable_orig; 60656979Sgibbs u_int sdtrable; 60740024Sgibbs 60856979Sgibbs sdtr = adw_get_chip_sdtr(adw, 60956979Sgibbs ccb->ccb_h.target_id); 61056979Sgibbs sdtr_orig = sdtr; 61156979Sgibbs sdtrable = adw_lram_read_16(adw, 61256979Sgibbs ADW_MC_SDTR_ABLE); 61356979Sgibbs sdtrable_orig = sdtrable; 61440024Sgibbs 61546581Sken if ((cts->valid 61646581Sken & CCB_TRANS_SYNC_RATE_VALID) != 0) { 61746581Sken 61856979Sgibbs sdtr = 61956979Sgibbs adw_find_sdtr(adw, 62056979Sgibbs cts->sync_period); 62140024Sgibbs } 62240024Sgibbs 62340024Sgibbs if ((cts->valid 62440024Sgibbs & CCB_TRANS_SYNC_OFFSET_VALID) != 0) { 62540024Sgibbs if (cts->sync_offset == 0) 62656979Sgibbs sdtr = ADW_MC_SDTR_ASYNC; 62740024Sgibbs } 62840024Sgibbs 62956979Sgibbs if (sdtr == ADW_MC_SDTR_ASYNC) 63056979Sgibbs sdtrable &= ~target_mask; 63156979Sgibbs else 63256979Sgibbs sdtrable |= target_mask; 63356979Sgibbs if (sdtr != sdtr_orig 63456979Sgibbs || sdtrable != sdtrable_orig) { 63556979Sgibbs adw_set_chip_sdtr(adw, 63656979Sgibbs ccb->ccb_h.target_id, 63756979Sgibbs sdtr); 63856979Sgibbs sdtrdone &= ~target_mask; 63940024Sgibbs adw_lram_write_16(adw, ADW_MC_SDTR_ABLE, 64056979Sgibbs sdtrable); 64140024Sgibbs adw_lram_write_16(adw, ADW_MC_SDTR_DONE, 64240024Sgibbs sdtrdone); 64356979Sgibbs 64440024Sgibbs } 64540024Sgibbs } 64640024Sgibbs } 64740024Sgibbs splx(s); 64840024Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 64940024Sgibbs xpt_done(ccb); 65040024Sgibbs break; 65140024Sgibbs } 65240024Sgibbs case XPT_GET_TRAN_SETTINGS: 65340024Sgibbs /* Get default/user set transfer settings for the target */ 65440024Sgibbs { 65540024Sgibbs struct ccb_trans_settings *cts; 65640024Sgibbs u_int target_mask; 65740024Sgibbs 65840024Sgibbs cts = &ccb->cts; 65940024Sgibbs target_mask = 0x01 << ccb->ccb_h.target_id; 66040024Sgibbs if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) { 66156979Sgibbs u_int mc_sdtr; 66256979Sgibbs 66340024Sgibbs cts->flags = 0; 66440024Sgibbs if ((adw->user_discenb & target_mask) != 0) 66540024Sgibbs cts->flags |= CCB_TRANS_DISC_ENB; 66640024Sgibbs 66740024Sgibbs if ((adw->user_tagenb & target_mask) != 0) 66840024Sgibbs cts->flags |= CCB_TRANS_TAG_ENB; 66940024Sgibbs 67040024Sgibbs if ((adw->user_wdtr & target_mask) != 0) 67140024Sgibbs cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 67240024Sgibbs else 67340024Sgibbs cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 67440024Sgibbs 67556979Sgibbs mc_sdtr = adw_get_user_sdtr(adw, ccb->ccb_h.target_id); 67656979Sgibbs cts->sync_period = adw_find_period(adw, mc_sdtr); 67756979Sgibbs if (cts->sync_period != 0) 67840024Sgibbs cts->sync_offset = 15; /* XXX ??? */ 67956979Sgibbs else 68056979Sgibbs cts->sync_offset = 0; 68140024Sgibbs 68240024Sgibbs cts->valid = CCB_TRANS_SYNC_RATE_VALID 68340024Sgibbs | CCB_TRANS_SYNC_OFFSET_VALID 68440024Sgibbs | CCB_TRANS_BUS_WIDTH_VALID 68540024Sgibbs | CCB_TRANS_DISC_VALID 68640024Sgibbs | CCB_TRANS_TQ_VALID; 68740024Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 68840024Sgibbs } else { 68940024Sgibbs u_int targ_tinfo; 69040024Sgibbs 69140024Sgibbs cts->flags = 0; 69240024Sgibbs if ((adw_lram_read_16(adw, ADW_MC_DISC_ENABLE) 69340024Sgibbs & target_mask) != 0) 69440024Sgibbs cts->flags |= CCB_TRANS_DISC_ENB; 69540024Sgibbs 69640024Sgibbs if ((adw->tagenb & target_mask) != 0) 69740024Sgibbs cts->flags |= CCB_TRANS_TAG_ENB; 69840024Sgibbs 69940024Sgibbs targ_tinfo = 70040024Sgibbs adw_lram_read_16(adw, 70140024Sgibbs ADW_MC_DEVICE_HSHK_CFG_TABLE 70240024Sgibbs + (2 * ccb->ccb_h.target_id)); 70340024Sgibbs 70440024Sgibbs if ((targ_tinfo & ADW_HSHK_CFG_WIDE_XFR) != 0) 70540024Sgibbs cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 70640024Sgibbs else 70740024Sgibbs cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 70840024Sgibbs 70940024Sgibbs cts->sync_period = 71056979Sgibbs adw_hshk_cfg_period_factor(targ_tinfo); 71140024Sgibbs 71240024Sgibbs cts->sync_offset = targ_tinfo & ADW_HSHK_CFG_OFFSET; 71340024Sgibbs if (cts->sync_period == 0) 71440024Sgibbs cts->sync_offset = 0; 71540024Sgibbs 71640024Sgibbs if (cts->sync_offset == 0) 71740024Sgibbs cts->sync_period = 0; 71840024Sgibbs } 71940024Sgibbs cts->valid = CCB_TRANS_SYNC_RATE_VALID 72040024Sgibbs | CCB_TRANS_SYNC_OFFSET_VALID 72140024Sgibbs | CCB_TRANS_BUS_WIDTH_VALID 72240024Sgibbs | CCB_TRANS_DISC_VALID 72340024Sgibbs | CCB_TRANS_TQ_VALID; 72440024Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 72540024Sgibbs xpt_done(ccb); 72640024Sgibbs break; 72740024Sgibbs } 72840024Sgibbs case XPT_CALC_GEOMETRY: 72940024Sgibbs { 73040024Sgibbs /* 73140024Sgibbs * XXX Use Adaptec translation until I find out how to 73240024Sgibbs * get this information from the card. 73340024Sgibbs */ 734116351Snjl cam_calc_geometry(&ccb->ccg, /*extended*/1); 73540024Sgibbs xpt_done(ccb); 73640024Sgibbs break; 73740024Sgibbs } 73840024Sgibbs case XPT_RESET_BUS: /* Reset the specified SCSI bus */ 73940024Sgibbs { 74057679Sgibbs int failure; 74140024Sgibbs 74257679Sgibbs failure = adw_reset_bus(adw); 74357679Sgibbs if (failure != 0) { 74440024Sgibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 74557679Sgibbs } else { 74657679Sgibbs if (bootverbose) { 74757679Sgibbs xpt_print_path(adw->path); 74857679Sgibbs printf("Bus Reset Delivered\n"); 74957679Sgibbs } 75057679Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 75156979Sgibbs } 75240024Sgibbs xpt_done(ccb); 75340024Sgibbs break; 75440024Sgibbs } 75540024Sgibbs case XPT_TERM_IO: /* Terminate the I/O process */ 75640024Sgibbs /* XXX Implement */ 75740024Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 75840024Sgibbs xpt_done(ccb); 75940024Sgibbs break; 76040024Sgibbs case XPT_PATH_INQ: /* Path routing inquiry */ 76140024Sgibbs { 76240024Sgibbs struct ccb_pathinq *cpi = &ccb->cpi; 76340024Sgibbs 76440024Sgibbs cpi->version_num = 1; 76540024Sgibbs cpi->hba_inquiry = PI_WIDE_16|PI_SDTR_ABLE|PI_TAG_ABLE; 76640024Sgibbs cpi->target_sprt = 0; 76740024Sgibbs cpi->hba_misc = 0; 76840024Sgibbs cpi->hba_eng_cnt = 0; 76940024Sgibbs cpi->max_target = ADW_MAX_TID; 77040024Sgibbs cpi->max_lun = ADW_MAX_LUN; 77140024Sgibbs cpi->initiator_id = adw->initiator_id; 77240024Sgibbs cpi->bus_id = cam_sim_bus(sim); 77346581Sken cpi->base_transfer_speed = 3300; 77440024Sgibbs strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 77540024Sgibbs strncpy(cpi->hba_vid, "AdvanSys", HBA_IDLEN); 77640024Sgibbs strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 77740024Sgibbs cpi->unit_number = cam_sim_unit(sim); 77840024Sgibbs cpi->ccb_h.status = CAM_REQ_CMP; 77940024Sgibbs xpt_done(ccb); 78040024Sgibbs break; 78140024Sgibbs } 78240024Sgibbs default: 78340024Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 78440024Sgibbs xpt_done(ccb); 78540024Sgibbs break; 78640024Sgibbs } 78740024Sgibbs} 78840024Sgibbs 78940024Sgibbsstatic void 79040024Sgibbsadw_poll(struct cam_sim *sim) 79140024Sgibbs{ 79240024Sgibbs adw_intr(cam_sim_softc(sim)); 79340024Sgibbs} 79440024Sgibbs 79540024Sgibbsstatic void 79640024Sgibbsadw_async(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg) 79740024Sgibbs{ 79840024Sgibbs} 79940024Sgibbs 80040024Sgibbsstruct adw_softc * 80156979Sgibbsadw_alloc(device_t dev, struct resource *regs, int regs_type, int regs_id) 80240024Sgibbs{ 80340024Sgibbs struct adw_softc *adw; 80440024Sgibbs int i; 80540024Sgibbs 80640024Sgibbs /* 80740024Sgibbs * Allocate a storage area for us 80840024Sgibbs */ 80967888Sdwmalone adw = malloc(sizeof(struct adw_softc), M_DEVBUF, M_NOWAIT | M_ZERO); 81040024Sgibbs if (adw == NULL) { 81156979Sgibbs printf("adw%d: cannot malloc!\n", device_get_unit(dev)); 81240024Sgibbs return NULL; 81340024Sgibbs } 81440024Sgibbs LIST_INIT(&adw->pending_ccbs); 81540024Sgibbs SLIST_INIT(&adw->sg_maps); 81656979Sgibbs adw->device = dev; 81756979Sgibbs adw->unit = device_get_unit(dev); 81856979Sgibbs adw->regs_res_type = regs_type; 81956979Sgibbs adw->regs_res_id = regs_id; 82056979Sgibbs adw->regs = regs; 82156979Sgibbs adw->tag = rman_get_bustag(regs); 82256979Sgibbs adw->bsh = rman_get_bushandle(regs); 82340024Sgibbs i = adw->unit / 10; 82440024Sgibbs adw->name = malloc(sizeof("adw") + i + 1, M_DEVBUF, M_NOWAIT); 82540024Sgibbs if (adw->name == NULL) { 82656979Sgibbs printf("adw%d: cannot malloc name!\n", adw->unit); 82740024Sgibbs free(adw, M_DEVBUF); 82840024Sgibbs return NULL; 82940024Sgibbs } 83040024Sgibbs sprintf(adw->name, "adw%d", adw->unit); 83140024Sgibbs return(adw); 83240024Sgibbs} 83340024Sgibbs 83440024Sgibbsvoid 83540024Sgibbsadw_free(struct adw_softc *adw) 83640024Sgibbs{ 83740024Sgibbs switch (adw->init_level) { 83856979Sgibbs case 9: 83940024Sgibbs { 84040024Sgibbs struct sg_map_node *sg_map; 84140024Sgibbs 84240024Sgibbs while ((sg_map = SLIST_FIRST(&adw->sg_maps)) != NULL) { 84340024Sgibbs SLIST_REMOVE_HEAD(&adw->sg_maps, links); 84440024Sgibbs bus_dmamap_unload(adw->sg_dmat, 84540024Sgibbs sg_map->sg_dmamap); 84640024Sgibbs bus_dmamem_free(adw->sg_dmat, sg_map->sg_vaddr, 84740024Sgibbs sg_map->sg_dmamap); 84840024Sgibbs free(sg_map, M_DEVBUF); 84940024Sgibbs } 85040024Sgibbs bus_dma_tag_destroy(adw->sg_dmat); 85140024Sgibbs } 85256979Sgibbs case 8: 85340024Sgibbs bus_dmamap_unload(adw->acb_dmat, adw->acb_dmamap); 85456979Sgibbs case 7: 85540024Sgibbs bus_dmamem_free(adw->acb_dmat, adw->acbs, 85640024Sgibbs adw->acb_dmamap); 85740024Sgibbs bus_dmamap_destroy(adw->acb_dmat, adw->acb_dmamap); 85856979Sgibbs case 6: 85956979Sgibbs bus_dma_tag_destroy(adw->acb_dmat); 86056979Sgibbs case 5: 86156979Sgibbs bus_dmamap_unload(adw->carrier_dmat, adw->carrier_dmamap); 86256979Sgibbs case 4: 86356979Sgibbs bus_dmamem_free(adw->carrier_dmat, adw->carriers, 86456979Sgibbs adw->carrier_dmamap); 86556979Sgibbs bus_dmamap_destroy(adw->carrier_dmat, adw->carrier_dmamap); 86640024Sgibbs case 3: 86756979Sgibbs bus_dma_tag_destroy(adw->carrier_dmat); 86840024Sgibbs case 2: 86940024Sgibbs bus_dma_tag_destroy(adw->buffer_dmat); 87040024Sgibbs case 1: 87140024Sgibbs bus_dma_tag_destroy(adw->parent_dmat); 87240024Sgibbs case 0: 87340024Sgibbs break; 87440024Sgibbs } 875138502Srsm 876138502Srsm if (adw->regs != NULL) 877138502Srsm bus_release_resource(adw->device, 878138502Srsm adw->regs_res_type, 879138502Srsm adw->regs_res_id, 880138502Srsm adw->regs); 881138502Srsm 882138502Srsm if (adw->irq != NULL) 883138502Srsm bus_release_resource(adw->device, 884138502Srsm adw->irq_res_type, 885138502Srsm 0, adw->irq); 886138502Srsm 887138502Srsm if (adw->sim != NULL) { 888138502Srsm if (adw->path != NULL) { 889138502Srsm xpt_async(AC_LOST_DEVICE, adw->path, NULL); 890138502Srsm xpt_free_path(adw->path); 891138502Srsm } 892138502Srsm xpt_bus_deregister(cam_sim_path(adw->sim)); 893138502Srsm cam_sim_free(adw->sim, /*free_devq*/TRUE); 894138502Srsm } 89540024Sgibbs free(adw->name, M_DEVBUF); 89640024Sgibbs free(adw, M_DEVBUF); 89740024Sgibbs} 89840024Sgibbs 89940024Sgibbsint 90040024Sgibbsadw_init(struct adw_softc *adw) 90140024Sgibbs{ 90240024Sgibbs struct adw_eeprom eep_config; 90356979Sgibbs u_int tid; 90456979Sgibbs u_int i; 90540024Sgibbs u_int16_t checksum; 90640024Sgibbs u_int16_t scsicfg1; 90740024Sgibbs 90840024Sgibbs checksum = adw_eeprom_read(adw, &eep_config); 90940024Sgibbs bcopy(eep_config.serial_number, adw->serial_number, 91040024Sgibbs sizeof(adw->serial_number)); 91140024Sgibbs if (checksum != eep_config.checksum) { 91240024Sgibbs u_int16_t serial_number[3]; 91340024Sgibbs 91456979Sgibbs adw->flags |= ADW_EEPROM_FAILED; 91540024Sgibbs printf("%s: EEPROM checksum failed. Restoring Defaults\n", 91640024Sgibbs adw_name(adw)); 91740024Sgibbs 91840024Sgibbs /* 91940024Sgibbs * Restore the default EEPROM settings. 92040024Sgibbs * Assume the 6 byte board serial number that was read 92140024Sgibbs * from EEPROM is correct even if the EEPROM checksum 92240024Sgibbs * failed. 92340024Sgibbs */ 92456979Sgibbs bcopy(adw->default_eeprom, &eep_config, sizeof(eep_config)); 92540024Sgibbs bcopy(adw->serial_number, eep_config.serial_number, 92640024Sgibbs sizeof(serial_number)); 92740024Sgibbs adw_eeprom_write(adw, &eep_config); 92840024Sgibbs } 92940024Sgibbs 93040024Sgibbs /* Pull eeprom information into our softc. */ 93140024Sgibbs adw->bios_ctrl = eep_config.bios_ctrl; 93240024Sgibbs adw->user_wdtr = eep_config.wdtr_able; 93356979Sgibbs for (tid = 0; tid < ADW_MAX_TID; tid++) { 93456979Sgibbs u_int mc_sdtr; 93556979Sgibbs u_int16_t tid_mask; 93656979Sgibbs 93756979Sgibbs tid_mask = 0x1 << tid; 93856979Sgibbs if ((adw->features & ADW_ULTRA) != 0) { 93956979Sgibbs /* 94056979Sgibbs * Ultra chips store sdtr and ultraenb 94156979Sgibbs * bits in their seeprom, so we must 94256979Sgibbs * construct valid mc_sdtr entries for 94356979Sgibbs * indirectly. 94456979Sgibbs */ 94556979Sgibbs if (eep_config.sync1.sync_enable & tid_mask) { 94656979Sgibbs if (eep_config.sync2.ultra_enable & tid_mask) 94756979Sgibbs mc_sdtr = ADW_MC_SDTR_20; 94856979Sgibbs else 94956979Sgibbs mc_sdtr = ADW_MC_SDTR_10; 95056979Sgibbs } else 95156979Sgibbs mc_sdtr = ADW_MC_SDTR_ASYNC; 95256979Sgibbs } else { 95356979Sgibbs switch (ADW_TARGET_GROUP(tid)) { 95456979Sgibbs case 3: 95556979Sgibbs mc_sdtr = eep_config.sync4.sdtr4; 95656979Sgibbs break; 95756979Sgibbs case 2: 95856979Sgibbs mc_sdtr = eep_config.sync3.sdtr3; 95956979Sgibbs break; 96056979Sgibbs case 1: 96156979Sgibbs mc_sdtr = eep_config.sync2.sdtr2; 96256979Sgibbs break; 96356979Sgibbs default: /* Shut up compiler */ 96456979Sgibbs case 0: 96556979Sgibbs mc_sdtr = eep_config.sync1.sdtr1; 96656979Sgibbs break; 96756979Sgibbs } 96856979Sgibbs mc_sdtr >>= ADW_TARGET_GROUP_SHIFT(tid); 96956979Sgibbs mc_sdtr &= 0xFF; 97056979Sgibbs } 97156979Sgibbs adw_set_user_sdtr(adw, tid, mc_sdtr); 97256979Sgibbs } 97340024Sgibbs adw->user_tagenb = eep_config.tagqng_able; 97440024Sgibbs adw->user_discenb = eep_config.disc_enable; 97540024Sgibbs adw->max_acbs = eep_config.max_host_qng; 97640024Sgibbs adw->initiator_id = (eep_config.adapter_scsi_id & ADW_MAX_TID); 97740024Sgibbs 97840024Sgibbs /* 97940024Sgibbs * Sanity check the number of host openings. 98040024Sgibbs */ 98140024Sgibbs if (adw->max_acbs > ADW_DEF_MAX_HOST_QNG) 98240024Sgibbs adw->max_acbs = ADW_DEF_MAX_HOST_QNG; 98340024Sgibbs else if (adw->max_acbs < ADW_DEF_MIN_HOST_QNG) { 98440024Sgibbs /* If the value is zero, assume it is uninitialized. */ 98540024Sgibbs if (adw->max_acbs == 0) 98640024Sgibbs adw->max_acbs = ADW_DEF_MAX_HOST_QNG; 98740024Sgibbs else 98840024Sgibbs adw->max_acbs = ADW_DEF_MIN_HOST_QNG; 98940024Sgibbs } 99040024Sgibbs 99140024Sgibbs scsicfg1 = 0; 99256979Sgibbs if ((adw->features & ADW_ULTRA2) != 0) { 99356979Sgibbs switch (eep_config.termination_lvd) { 99456979Sgibbs default: 99556979Sgibbs printf("%s: Invalid EEPROM LVD Termination Settings.\n", 99656979Sgibbs adw_name(adw)); 99756979Sgibbs printf("%s: Reverting to Automatic LVD Termination\n", 99856979Sgibbs adw_name(adw)); 99956979Sgibbs /* FALLTHROUGH */ 100056979Sgibbs case ADW_EEPROM_TERM_AUTO: 100156979Sgibbs break; 100256979Sgibbs case ADW_EEPROM_TERM_BOTH_ON: 100356979Sgibbs scsicfg1 |= ADW2_SCSI_CFG1_TERM_LVD_LO; 100456979Sgibbs /* FALLTHROUGH */ 100556979Sgibbs case ADW_EEPROM_TERM_HIGH_ON: 100656979Sgibbs scsicfg1 |= ADW2_SCSI_CFG1_TERM_LVD_HI; 100756979Sgibbs /* FALLTHROUGH */ 100856979Sgibbs case ADW_EEPROM_TERM_OFF: 100956979Sgibbs scsicfg1 |= ADW2_SCSI_CFG1_DIS_TERM_DRV; 101056979Sgibbs break; 101156979Sgibbs } 101256979Sgibbs } 101356979Sgibbs 101456979Sgibbs switch (eep_config.termination_se) { 101540024Sgibbs default: 101656979Sgibbs printf("%s: Invalid SE EEPROM Termination Settings.\n", 101740024Sgibbs adw_name(adw)); 101856979Sgibbs printf("%s: Reverting to Automatic SE Termination\n", 101940024Sgibbs adw_name(adw)); 102040024Sgibbs /* FALLTHROUGH */ 102140024Sgibbs case ADW_EEPROM_TERM_AUTO: 102240024Sgibbs break; 102340024Sgibbs case ADW_EEPROM_TERM_BOTH_ON: 102440024Sgibbs scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_L; 102540024Sgibbs /* FALLTHROUGH */ 102640024Sgibbs case ADW_EEPROM_TERM_HIGH_ON: 102740024Sgibbs scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_H; 102840024Sgibbs /* FALLTHROUGH */ 102940024Sgibbs case ADW_EEPROM_TERM_OFF: 103040024Sgibbs scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_MANUAL; 103140024Sgibbs break; 103240024Sgibbs } 103340024Sgibbs printf("%s: SCSI ID %d, ", adw_name(adw), adw->initiator_id); 103440024Sgibbs 103540024Sgibbs /* DMA tag for mapping buffers into device visible space. */ 1036112782Smdodd if (bus_dma_tag_create( 1037112782Smdodd /* parent */ adw->parent_dmat, 1038112782Smdodd /* alignment */ 1, 1039112782Smdodd /* boundary */ 0, 1040112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, 1041112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 1042112782Smdodd /* filter */ NULL, 1043112782Smdodd /* filterarg */ NULL, 1044112782Smdodd /* maxsize */ MAXBSIZE, 1045112782Smdodd /* nsegments */ ADW_SGSIZE, 1046112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT, 1047112782Smdodd /* flags */ BUS_DMA_ALLOCNOW, 1048117126Sscottl /* lockfunc */ busdma_lock_mutex, 1049117126Sscottl /* lockarg */ &Giant, 1050112782Smdodd &adw->buffer_dmat) != 0) { 105156979Sgibbs return (ENOMEM); 105240024Sgibbs } 105340024Sgibbs 105440024Sgibbs adw->init_level++; 105540024Sgibbs 105656979Sgibbs /* DMA tag for our ccb carrier structures */ 1057112782Smdodd if (bus_dma_tag_create( 1058112782Smdodd /* parent */ adw->parent_dmat, 1059112782Smdodd /* alignment */ 0x10, 1060112782Smdodd /* boundary */ 0, 1061112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, 1062112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 1063112782Smdodd /* filter */ NULL, 1064112782Smdodd /* filterarg */ NULL, 1065112782Smdodd /* maxsize */ (adw->max_acbs + 1066112782Smdodd ADW_NUM_CARRIER_QUEUES + 1) * 1067112782Smdodd sizeof(struct adw_carrier), 1068112782Smdodd /* nsegments */ 1, 1069112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT, 1070112782Smdodd /* flags */ 0, 1071117126Sscottl /* lockfunc */ busdma_lock_mutex, 1072117126Sscottl /* lockarg */ &Giant, 1073112782Smdodd &adw->carrier_dmat) != 0) { 107456979Sgibbs return (ENOMEM); 107556979Sgibbs } 107656979Sgibbs 107756979Sgibbs adw->init_level++; 107856979Sgibbs 107956979Sgibbs /* Allocation for our ccb carrier structures */ 108056979Sgibbs if (bus_dmamem_alloc(adw->carrier_dmat, (void **)&adw->carriers, 108156979Sgibbs BUS_DMA_NOWAIT, &adw->carrier_dmamap) != 0) { 108256979Sgibbs return (ENOMEM); 108356979Sgibbs } 108456979Sgibbs 108556979Sgibbs adw->init_level++; 108656979Sgibbs 108756979Sgibbs /* And permanently map them */ 108856979Sgibbs bus_dmamap_load(adw->carrier_dmat, adw->carrier_dmamap, 108956979Sgibbs adw->carriers, 109056979Sgibbs (adw->max_acbs + ADW_NUM_CARRIER_QUEUES + 1) 109156979Sgibbs * sizeof(struct adw_carrier), 109256979Sgibbs adwmapmem, &adw->carrier_busbase, /*flags*/0); 109356979Sgibbs 109456979Sgibbs /* Clear them out. */ 109556979Sgibbs bzero(adw->carriers, (adw->max_acbs + ADW_NUM_CARRIER_QUEUES + 1) 109656979Sgibbs * sizeof(struct adw_carrier)); 109756979Sgibbs 109856979Sgibbs /* Setup our free carrier list */ 109956979Sgibbs adw->free_carriers = adw->carriers; 110056979Sgibbs for (i = 0; i < adw->max_acbs + ADW_NUM_CARRIER_QUEUES; i++) { 110156979Sgibbs adw->carriers[i].carr_offset = 110256979Sgibbs carriervtobo(adw, &adw->carriers[i]); 110356979Sgibbs adw->carriers[i].carr_ba = 110456979Sgibbs carriervtob(adw, &adw->carriers[i]); 110556979Sgibbs adw->carriers[i].areq_ba = 0; 110656979Sgibbs adw->carriers[i].next_ba = 110756979Sgibbs carriervtobo(adw, &adw->carriers[i+1]); 110856979Sgibbs } 110956979Sgibbs /* Terminal carrier. Never leaves the freelist */ 111056979Sgibbs adw->carriers[i].carr_offset = 111156979Sgibbs carriervtobo(adw, &adw->carriers[i]); 111256979Sgibbs adw->carriers[i].carr_ba = 111356979Sgibbs carriervtob(adw, &adw->carriers[i]); 111456979Sgibbs adw->carriers[i].areq_ba = 0; 111556979Sgibbs adw->carriers[i].next_ba = ~0; 111656979Sgibbs 111756979Sgibbs adw->init_level++; 111856979Sgibbs 111956979Sgibbs /* DMA tag for our acb structures */ 1120112782Smdodd if (bus_dma_tag_create( 1121112782Smdodd /* parent */ adw->parent_dmat, 1122112782Smdodd /* alignment */ 1, 1123112782Smdodd /* boundary */ 0, 1124112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR, 1125112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 1126112782Smdodd /* filter */ NULL, 1127112782Smdodd /* filterarg */ NULL, 1128112782Smdodd /* maxsize */ adw->max_acbs * sizeof(struct acb), 1129112782Smdodd /* nsegments */ 1, 1130112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT, 1131112782Smdodd /* flags */ 0, 1132117126Sscottl /* lockfunc */ busdma_lock_mutex, 1133117126Sscottl /* lockarg */ &Giant, 1134112782Smdodd &adw->acb_dmat) != 0) { 113556979Sgibbs return (ENOMEM); 113640024Sgibbs } 113740024Sgibbs 113840024Sgibbs adw->init_level++; 113940024Sgibbs 114040024Sgibbs /* Allocation for our ccbs */ 114140024Sgibbs if (bus_dmamem_alloc(adw->acb_dmat, (void **)&adw->acbs, 114256979Sgibbs BUS_DMA_NOWAIT, &adw->acb_dmamap) != 0) 114356979Sgibbs return (ENOMEM); 114440024Sgibbs 114540024Sgibbs adw->init_level++; 114640024Sgibbs 114740024Sgibbs /* And permanently map them */ 114840024Sgibbs bus_dmamap_load(adw->acb_dmat, adw->acb_dmamap, 114940024Sgibbs adw->acbs, 115040024Sgibbs adw->max_acbs * sizeof(struct acb), 115140024Sgibbs adwmapmem, &adw->acb_busbase, /*flags*/0); 115240024Sgibbs 115340024Sgibbs /* Clear them out. */ 115440024Sgibbs bzero(adw->acbs, adw->max_acbs * sizeof(struct acb)); 115540024Sgibbs 115640024Sgibbs /* DMA tag for our S/G structures. We allocate in page sized chunks */ 1157112782Smdodd if (bus_dma_tag_create( 1158112782Smdodd /* parent */ adw->parent_dmat, 1159112782Smdodd /* alignment */ 1, 1160112782Smdodd /* boundary */ 0, 1161112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR, 1162112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 1163112782Smdodd /* filter */ NULL, 1164112782Smdodd /* filterarg */ NULL, 1165112782Smdodd /* maxsize */ PAGE_SIZE, 1166112782Smdodd /* nsegments */ 1, 1167112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT, 1168112782Smdodd /* flags */ 0, 1169117126Sscottl /* lockfunc */ busdma_lock_mutex, 1170117126Sscottl /* lockarg */ &Giant, 1171112782Smdodd &adw->sg_dmat) != 0) { 117256979Sgibbs return (ENOMEM); 117340024Sgibbs } 117440024Sgibbs 117540024Sgibbs adw->init_level++; 117640024Sgibbs 117740024Sgibbs /* Allocate our first batch of ccbs */ 117840024Sgibbs if (adwallocacbs(adw) == 0) 117956979Sgibbs return (ENOMEM); 118040024Sgibbs 118156979Sgibbs if (adw_init_chip(adw, scsicfg1) != 0) 118256979Sgibbs return (ENXIO); 118356979Sgibbs 118456979Sgibbs printf("Queue Depth %d\n", adw->max_acbs); 118556979Sgibbs 118640024Sgibbs return (0); 118740024Sgibbs} 118840024Sgibbs 118940024Sgibbs/* 119040024Sgibbs * Attach all the sub-devices we can find 119140024Sgibbs */ 119240024Sgibbsint 119340024Sgibbsadw_attach(struct adw_softc *adw) 119440024Sgibbs{ 119540024Sgibbs struct ccb_setasync csa; 119640024Sgibbs struct cam_devq *devq; 119756979Sgibbs int s; 119856979Sgibbs int error; 119940024Sgibbs 120056979Sgibbs error = 0; 120156979Sgibbs s = splcam(); 120256979Sgibbs /* Hook up our interrupt handler */ 120373280Smarkm if ((error = bus_setup_intr(adw->device, adw->irq, 120473280Smarkm INTR_TYPE_CAM | INTR_ENTROPY, adw_intr, 120573280Smarkm adw, &adw->ih)) != 0) { 120656979Sgibbs device_printf(adw->device, "bus_setup_intr() failed: %d\n", 120756979Sgibbs error); 120856979Sgibbs goto fail; 120956979Sgibbs } 121056979Sgibbs 121140024Sgibbs /* Start the Risc processor now that we are fully configured. */ 121240024Sgibbs adw_outw(adw, ADW_RISC_CSR, ADW_RISC_CSR_RUN); 121340024Sgibbs 121440024Sgibbs /* 121540024Sgibbs * Create the device queue for our SIM. 121640024Sgibbs */ 121740024Sgibbs devq = cam_simq_alloc(adw->max_acbs); 121840024Sgibbs if (devq == NULL) 121956979Sgibbs return (ENOMEM); 122040024Sgibbs 122140024Sgibbs /* 122240024Sgibbs * Construct our SIM entry. 122340024Sgibbs */ 122440024Sgibbs adw->sim = cam_sim_alloc(adw_action, adw_poll, "adw", adw, adw->unit, 122540024Sgibbs 1, adw->max_acbs, devq); 122656979Sgibbs if (adw->sim == NULL) { 122756979Sgibbs error = ENOMEM; 122856979Sgibbs goto fail; 122956979Sgibbs } 123040024Sgibbs 123140024Sgibbs /* 123240024Sgibbs * Register the bus. 123340024Sgibbs */ 123440024Sgibbs if (xpt_bus_register(adw->sim, 0) != CAM_SUCCESS) { 123540024Sgibbs cam_sim_free(adw->sim, /*free devq*/TRUE); 123656979Sgibbs error = ENOMEM; 123756979Sgibbs goto fail; 123840024Sgibbs } 123940024Sgibbs 124040024Sgibbs if (xpt_create_path(&adw->path, /*periph*/NULL, cam_sim_path(adw->sim), 124140024Sgibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) 124240024Sgibbs == CAM_REQ_CMP) { 124340024Sgibbs xpt_setup_ccb(&csa.ccb_h, adw->path, /*priority*/5); 124440024Sgibbs csa.ccb_h.func_code = XPT_SASYNC_CB; 124540024Sgibbs csa.event_enable = AC_LOST_DEVICE; 124640024Sgibbs csa.callback = adw_async; 124740024Sgibbs csa.callback_arg = adw; 124840024Sgibbs xpt_action((union ccb *)&csa); 124940024Sgibbs } 125040024Sgibbs 125156979Sgibbsfail: 125256979Sgibbs splx(s); 125356979Sgibbs return (error); 125440024Sgibbs} 125540024Sgibbs 125640024Sgibbsvoid 125740024Sgibbsadw_intr(void *arg) 125840024Sgibbs{ 125940024Sgibbs struct adw_softc *adw; 126040024Sgibbs u_int int_stat; 126140024Sgibbs 126240024Sgibbs adw = (struct adw_softc *)arg; 126340024Sgibbs if ((adw_inw(adw, ADW_CTRL_REG) & ADW_CTRL_REG_HOST_INTR) == 0) 126440024Sgibbs return; 126540024Sgibbs 126640024Sgibbs /* Reading the register clears the interrupt. */ 126740024Sgibbs int_stat = adw_inb(adw, ADW_INTR_STATUS_REG); 126840024Sgibbs 126940024Sgibbs if ((int_stat & ADW_INTR_STATUS_INTRB) != 0) { 127056979Sgibbs u_int intrb_code; 127156979Sgibbs 127256979Sgibbs /* Async Microcode Event */ 127356979Sgibbs intrb_code = adw_lram_read_8(adw, ADW_MC_INTRB_CODE); 127456979Sgibbs switch (intrb_code) { 127556979Sgibbs case ADW_ASYNC_CARRIER_READY_FAILURE: 127656979Sgibbs /* 127756979Sgibbs * The RISC missed our update of 127856979Sgibbs * the commandq. 127956979Sgibbs */ 128056979Sgibbs if (LIST_FIRST(&adw->pending_ccbs) != NULL) 128156979Sgibbs adw_tickle_risc(adw, ADW_TICKLE_A); 128240024Sgibbs break; 128356979Sgibbs case ADW_ASYNC_SCSI_BUS_RESET_DET: 128456979Sgibbs /* 128556979Sgibbs * The firmware detected a SCSI Bus reset. 128656979Sgibbs */ 128756979Sgibbs printf("Someone Reset the Bus\n"); 128856979Sgibbs adw_handle_bus_reset(adw, /*initiated*/FALSE); 128956979Sgibbs break; 129056979Sgibbs case ADW_ASYNC_RDMA_FAILURE: 129156979Sgibbs /* 129256979Sgibbs * Handle RDMA failure by resetting the 129356979Sgibbs * SCSI Bus and chip. 129456979Sgibbs */ 129556979Sgibbs#if XXX 129656979Sgibbs AdvResetChipAndSB(adv_dvc_varp); 129756979Sgibbs#endif 129856979Sgibbs break; 129956979Sgibbs 130056979Sgibbs case ADW_ASYNC_HOST_SCSI_BUS_RESET: 130156979Sgibbs /* 130256979Sgibbs * Host generated SCSI bus reset occurred. 130356979Sgibbs */ 130440024Sgibbs adw_handle_bus_reset(adw, /*initiated*/TRUE); 130556979Sgibbs break; 130656979Sgibbs default: 130756979Sgibbs printf("adw_intr: unknown async code 0x%x\n", 130856979Sgibbs intrb_code); 130940024Sgibbs break; 131040024Sgibbs } 131140024Sgibbs } 131240024Sgibbs 131340024Sgibbs /* 131456979Sgibbs * Run down the RequestQ. 131540024Sgibbs */ 131656979Sgibbs while ((adw->responseq->next_ba & ADW_RQ_DONE) != 0) { 131756979Sgibbs struct adw_carrier *free_carrier; 131856979Sgibbs struct acb *acb; 131956979Sgibbs union ccb *ccb; 132040024Sgibbs 132156979Sgibbs#if 0 132256979Sgibbs printf("0x%x, 0x%x, 0x%x, 0x%x\n", 132356979Sgibbs adw->responseq->carr_offset, 132456979Sgibbs adw->responseq->carr_ba, 132556979Sgibbs adw->responseq->areq_ba, 132656979Sgibbs adw->responseq->next_ba); 132756979Sgibbs#endif 132856979Sgibbs /* 132956979Sgibbs * The firmware copies the adw_scsi_req_q.acb_baddr 133056979Sgibbs * field into the areq_ba field of the carrier. 133156979Sgibbs */ 133256979Sgibbs acb = acbbotov(adw, adw->responseq->areq_ba); 133340024Sgibbs 133440024Sgibbs /* 133556979Sgibbs * The least significant four bits of the next_ba 133656979Sgibbs * field are used as flags. Mask them out and then 133756979Sgibbs * advance through the list. 133840024Sgibbs */ 133956979Sgibbs free_carrier = adw->responseq; 134056979Sgibbs adw->responseq = 134156979Sgibbs carrierbotov(adw, free_carrier->next_ba & ADW_NEXT_BA_MASK); 134256979Sgibbs free_carrier->next_ba = adw->free_carriers->carr_offset; 134356979Sgibbs adw->free_carriers = free_carrier; 134440024Sgibbs 134540024Sgibbs /* Process CCB */ 134640024Sgibbs ccb = acb->ccb; 134740024Sgibbs untimeout(adwtimeout, acb, ccb->ccb_h.timeout_ch); 134840024Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 1349115343Sscottl bus_dmasync_op_t op; 135040024Sgibbs 135140024Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 135240024Sgibbs op = BUS_DMASYNC_POSTREAD; 135340024Sgibbs else 135440024Sgibbs op = BUS_DMASYNC_POSTWRITE; 135540024Sgibbs bus_dmamap_sync(adw->buffer_dmat, acb->dmamap, op); 135640024Sgibbs bus_dmamap_unload(adw->buffer_dmat, acb->dmamap); 135740024Sgibbs ccb->csio.resid = acb->queue.data_cnt; 135840024Sgibbs } else 135940024Sgibbs ccb->csio.resid = 0; 136040024Sgibbs 136140024Sgibbs /* Common Cases inline... */ 136240024Sgibbs if (acb->queue.host_status == QHSTA_NO_ERROR 136340024Sgibbs && (acb->queue.done_status == QD_NO_ERROR 136440024Sgibbs || acb->queue.done_status == QD_WITH_ERROR)) { 136540024Sgibbs ccb->csio.scsi_status = acb->queue.scsi_status; 136640024Sgibbs ccb->ccb_h.status = 0; 136740024Sgibbs switch (ccb->csio.scsi_status) { 136840024Sgibbs case SCSI_STATUS_OK: 136940024Sgibbs ccb->ccb_h.status |= CAM_REQ_CMP; 137040024Sgibbs break; 137140024Sgibbs case SCSI_STATUS_CHECK_COND: 137240024Sgibbs case SCSI_STATUS_CMD_TERMINATED: 137340024Sgibbs bcopy(&acb->sense_data, &ccb->csio.sense_data, 137440024Sgibbs ccb->csio.sense_len); 137540024Sgibbs ccb->ccb_h.status |= CAM_AUTOSNS_VALID; 137640024Sgibbs ccb->csio.sense_resid = acb->queue.sense_len; 137740024Sgibbs /* FALLTHROUGH */ 137840024Sgibbs default: 137940024Sgibbs ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR 138040024Sgibbs | CAM_DEV_QFRZN; 138140024Sgibbs xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 138240024Sgibbs break; 138340024Sgibbs } 138440024Sgibbs adwfreeacb(adw, acb); 138540024Sgibbs xpt_done(ccb); 138640024Sgibbs } else { 138740024Sgibbs adwprocesserror(adw, acb); 138840024Sgibbs } 138940024Sgibbs } 139040024Sgibbs} 139140024Sgibbs 139240024Sgibbsstatic void 139340024Sgibbsadwprocesserror(struct adw_softc *adw, struct acb *acb) 139440024Sgibbs{ 139540024Sgibbs union ccb *ccb; 139640024Sgibbs 139740024Sgibbs ccb = acb->ccb; 139840024Sgibbs if (acb->queue.done_status == QD_ABORTED_BY_HOST) { 139940024Sgibbs ccb->ccb_h.status = CAM_REQ_ABORTED; 140040024Sgibbs } else { 140140024Sgibbs 140240024Sgibbs switch (acb->queue.host_status) { 140340024Sgibbs case QHSTA_M_SEL_TIMEOUT: 140440024Sgibbs ccb->ccb_h.status = CAM_SEL_TIMEOUT; 140540024Sgibbs break; 140640024Sgibbs case QHSTA_M_SXFR_OFF_UFLW: 140740024Sgibbs case QHSTA_M_SXFR_OFF_OFLW: 140840024Sgibbs case QHSTA_M_DATA_OVER_RUN: 140940024Sgibbs ccb->ccb_h.status = CAM_DATA_RUN_ERR; 141040024Sgibbs break; 141140024Sgibbs case QHSTA_M_SXFR_DESELECTED: 141240024Sgibbs case QHSTA_M_UNEXPECTED_BUS_FREE: 141340024Sgibbs ccb->ccb_h.status = CAM_UNEXP_BUSFREE; 141440024Sgibbs break; 141557679Sgibbs case QHSTA_M_SCSI_BUS_RESET: 141657679Sgibbs case QHSTA_M_SCSI_BUS_RESET_UNSOL: 141757679Sgibbs ccb->ccb_h.status = CAM_SCSI_BUS_RESET; 141857679Sgibbs break; 141957679Sgibbs case QHSTA_M_BUS_DEVICE_RESET: 142057679Sgibbs ccb->ccb_h.status = CAM_BDR_SENT; 142157679Sgibbs break; 142240024Sgibbs case QHSTA_M_QUEUE_ABORTED: 142340024Sgibbs /* BDR or Bus Reset */ 142457679Sgibbs printf("Saw Queue Aborted\n"); 142540024Sgibbs ccb->ccb_h.status = adw->last_reset; 142640024Sgibbs break; 142740024Sgibbs case QHSTA_M_SXFR_SDMA_ERR: 142840024Sgibbs case QHSTA_M_SXFR_SXFR_PERR: 142940024Sgibbs case QHSTA_M_RDMA_PERR: 143040024Sgibbs ccb->ccb_h.status = CAM_UNCOR_PARITY; 143140024Sgibbs break; 143240024Sgibbs case QHSTA_M_WTM_TIMEOUT: 143340024Sgibbs case QHSTA_M_SXFR_WD_TMO: 143456979Sgibbs { 143540024Sgibbs /* The SCSI bus hung in a phase */ 143657679Sgibbs xpt_print_path(adw->path); 143757679Sgibbs printf("Watch Dog timer expired. Reseting bus\n"); 143857679Sgibbs adw_reset_bus(adw); 143940024Sgibbs break; 144056979Sgibbs } 144140024Sgibbs case QHSTA_M_SXFR_XFR_PH_ERR: 144240024Sgibbs ccb->ccb_h.status = CAM_SEQUENCE_FAIL; 144340024Sgibbs break; 144440024Sgibbs case QHSTA_M_SXFR_UNKNOWN_ERROR: 144540024Sgibbs break; 144640024Sgibbs case QHSTA_M_BAD_CMPL_STATUS_IN: 144740024Sgibbs /* No command complete after a status message */ 144840024Sgibbs ccb->ccb_h.status = CAM_SEQUENCE_FAIL; 144940024Sgibbs break; 145040024Sgibbs case QHSTA_M_AUTO_REQ_SENSE_FAIL: 145140024Sgibbs ccb->ccb_h.status = CAM_AUTOSENSE_FAIL; 145240024Sgibbs break; 145340024Sgibbs case QHSTA_M_INVALID_DEVICE: 145440024Sgibbs ccb->ccb_h.status = CAM_PATH_INVALID; 145540024Sgibbs break; 145640024Sgibbs case QHSTA_M_NO_AUTO_REQ_SENSE: 145740024Sgibbs /* 145840024Sgibbs * User didn't request sense, but we got a 145940024Sgibbs * check condition. 146040024Sgibbs */ 146140024Sgibbs ccb->csio.scsi_status = acb->queue.scsi_status; 146240024Sgibbs ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; 146340024Sgibbs break; 146440024Sgibbs default: 146540024Sgibbs panic("%s: Unhandled Host status error %x", 146640024Sgibbs adw_name(adw), acb->queue.host_status); 146740024Sgibbs /* NOTREACHED */ 146840024Sgibbs } 146940024Sgibbs } 147057679Sgibbs if ((acb->state & ACB_RECOVERY_ACB) != 0) { 147157679Sgibbs if (ccb->ccb_h.status == CAM_SCSI_BUS_RESET 147257679Sgibbs || ccb->ccb_h.status == CAM_BDR_SENT) 147357679Sgibbs ccb->ccb_h.status = CAM_CMD_TIMEOUT; 147457679Sgibbs } 147540024Sgibbs if (ccb->ccb_h.status != CAM_REQ_CMP) { 147640024Sgibbs xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 147740024Sgibbs ccb->ccb_h.status |= CAM_DEV_QFRZN; 147840024Sgibbs } 147940024Sgibbs adwfreeacb(adw, acb); 148040024Sgibbs xpt_done(ccb); 148140024Sgibbs} 148240024Sgibbs 148340024Sgibbsstatic void 148440024Sgibbsadwtimeout(void *arg) 148540024Sgibbs{ 148640024Sgibbs struct acb *acb; 148740024Sgibbs union ccb *ccb; 148840024Sgibbs struct adw_softc *adw; 148940024Sgibbs adw_idle_cmd_status_t status; 149057679Sgibbs int target_id; 149140024Sgibbs int s; 149240024Sgibbs 149340024Sgibbs acb = (struct acb *)arg; 149440024Sgibbs ccb = acb->ccb; 149540024Sgibbs adw = (struct adw_softc *)ccb->ccb_h.ccb_adw_ptr; 149640024Sgibbs xpt_print_path(ccb->ccb_h.path); 149740024Sgibbs printf("ACB %p - timed out\n", (void *)acb); 149840024Sgibbs 149940024Sgibbs s = splcam(); 150040024Sgibbs 150140024Sgibbs if ((acb->state & ACB_ACTIVE) == 0) { 150240024Sgibbs xpt_print_path(ccb->ccb_h.path); 150340024Sgibbs printf("ACB %p - timed out CCB already completed\n", 150440024Sgibbs (void *)acb); 150540024Sgibbs splx(s); 150640024Sgibbs return; 150740024Sgibbs } 150840024Sgibbs 150957679Sgibbs acb->state |= ACB_RECOVERY_ACB; 151057679Sgibbs target_id = ccb->ccb_h.target_id; 151157679Sgibbs 151240024Sgibbs /* Attempt a BDR first */ 151357679Sgibbs status = adw_idle_cmd_send(adw, ADW_IDLE_CMD_DEVICE_RESET, 151457679Sgibbs ccb->ccb_h.target_id); 151540024Sgibbs splx(s); 151640024Sgibbs if (status == ADW_IDLE_CMD_SUCCESS) { 151740024Sgibbs printf("%s: BDR Delivered. No longer in timeout\n", 151840024Sgibbs adw_name(adw)); 151957679Sgibbs adw_handle_device_reset(adw, target_id); 152040024Sgibbs } else { 152157679Sgibbs adw_reset_bus(adw); 152257679Sgibbs xpt_print_path(adw->path); 152357679Sgibbs printf("Bus Reset Delivered. No longer in timeout\n"); 152440024Sgibbs } 152540024Sgibbs} 152640024Sgibbs 152740024Sgibbsstatic void 152840024Sgibbsadw_handle_device_reset(struct adw_softc *adw, u_int target) 152940024Sgibbs{ 153040024Sgibbs struct cam_path *path; 153140024Sgibbs cam_status error; 153240024Sgibbs 153340024Sgibbs error = xpt_create_path(&path, /*periph*/NULL, cam_sim_path(adw->sim), 153440024Sgibbs target, CAM_LUN_WILDCARD); 153540024Sgibbs 153640024Sgibbs if (error == CAM_REQ_CMP) { 153740024Sgibbs xpt_async(AC_SENT_BDR, path, NULL); 153840024Sgibbs xpt_free_path(path); 153940024Sgibbs } 154040024Sgibbs adw->last_reset = CAM_BDR_SENT; 154140024Sgibbs} 154240024Sgibbs 154340024Sgibbsstatic void 154440024Sgibbsadw_handle_bus_reset(struct adw_softc *adw, int initiated) 154540024Sgibbs{ 154640024Sgibbs if (initiated) { 154740024Sgibbs /* 154840024Sgibbs * The microcode currently sets the SCSI Bus Reset signal 154940024Sgibbs * while handling the AscSendIdleCmd() IDLE_CMD_SCSI_RESET 155040024Sgibbs * command above. But the SCSI Bus Reset Hold Time in the 155140024Sgibbs * microcode is not deterministic (it may in fact be for less 155240024Sgibbs * than the SCSI Spec. minimum of 25 us). Therefore on return 155340024Sgibbs * the Adv Library sets the SCSI Bus Reset signal for 155440024Sgibbs * ADW_SCSI_RESET_HOLD_TIME_US, which is defined to be greater 155540024Sgibbs * than 25 us. 155640024Sgibbs */ 155740024Sgibbs u_int scsi_ctrl; 155840024Sgibbs 155940024Sgibbs scsi_ctrl = adw_inw(adw, ADW_SCSI_CTRL) & ~ADW_SCSI_CTRL_RSTOUT; 156040024Sgibbs adw_outw(adw, ADW_SCSI_CTRL, scsi_ctrl | ADW_SCSI_CTRL_RSTOUT); 156140024Sgibbs DELAY(ADW_SCSI_RESET_HOLD_TIME_US); 156240024Sgibbs adw_outw(adw, ADW_SCSI_CTRL, scsi_ctrl); 156340024Sgibbs 156440024Sgibbs /* 156540024Sgibbs * We will perform the async notification when the 156640024Sgibbs * SCSI Reset interrupt occurs. 156740024Sgibbs */ 156840024Sgibbs } else 156940024Sgibbs xpt_async(AC_BUS_RESET, adw->path, NULL); 157040024Sgibbs adw->last_reset = CAM_SCSI_BUS_RESET; 157140024Sgibbs} 1572