1140025Simp/* 239225Sgibbs * Generic register and struct definitions for the Adaptech 154x/164x 339225Sgibbs * SCSI host adapters. Product specific probe and attach routines can 439225Sgibbs * be found in: 5140025Simp * aha 1542A/1542B/1542C/1542CF/1542CP aha_isa.c 6122363Simp * aha 1640 aha_mca.c 7140025Simp */ 8140025Simp/*- 939751Simp * Copyright (c) 1998 M. Warner Losh. 1039751Simp * All Rights Reserved. 1139751Simp * 1239751Simp * Redistribution and use in source and binary forms, with or without 1339751Simp * modification, are permitted provided that the following conditions 1439751Simp * are met: 1539751Simp * 1. Redistributions of source code must retain the above copyright 16140040Simp * notice, this list of conditions and the following disclaimer. 17140040Simp * 2. Redistributions in binary form must reproduce the above copyright 18140040Simp * notice, this list of conditions and the following disclaimer in the 19140040Simp * documentation and/or other materials provided with the distribution. 2039751Simp * 2139751Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2239751Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2339751Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24140040Simp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 25140040Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2639751Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2739751Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2839751Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2939751Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3039751Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3139751Simp * SUCH DAMAGE. 3239751Simp * 3339225Sgibbs * Derived from bt.c written by: 3439225Sgibbs * 3539225Sgibbs * Copyright (c) 1998 Justin T. Gibbs. 3639225Sgibbs * All rights reserved. 3739225Sgibbs * 3839225Sgibbs * Redistribution and use in source and binary forms, with or without 3939225Sgibbs * modification, are permitted provided that the following conditions 4039225Sgibbs * are met: 4139225Sgibbs * 1. Redistributions of source code must retain the above copyright 4239225Sgibbs * notice, this list of conditions, and the following disclaimer, 4339225Sgibbs * without modification, immediately at the beginning of the file. 4439225Sgibbs * 2. The name of the author may not be used to endorse or promote products 4539225Sgibbs * derived from this software without specific prior written permission. 4639225Sgibbs * 4739225Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 4839225Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4939225Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5039225Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 5139225Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 5239225Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 5339225Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 5439225Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 5539225Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5639225Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5739225Sgibbs * SUCH DAMAGE. 5839225Sgibbs */ 5939225Sgibbs 60119418Sobrien#include <sys/cdefs.h> 61119418Sobrien__FBSDID("$FreeBSD: releng/11.0/sys/dev/aha/aha.c 298955 2016-05-03 03:41:25Z pfg $"); 62119418Sobrien 6339225Sgibbs#include <sys/param.h> 64241603Sglebius#include <sys/conf.h> 65122597Simp#include <sys/bus.h> 66122363Simp#include <sys/systm.h> 6739225Sgibbs#include <sys/malloc.h> 6839225Sgibbs#include <sys/kernel.h> 69117126Sscottl#include <sys/lock.h> 70165102Smjacob#include <sys/module.h> 71117126Sscottl#include <sys/mutex.h> 72241603Sglebius#include <sys/rman.h> 73122363Simp 7439225Sgibbs#include <machine/bus.h> 7539225Sgibbs 7639225Sgibbs#include <cam/cam.h> 7739225Sgibbs#include <cam/cam_ccb.h> 7839225Sgibbs#include <cam/cam_sim.h> 7939225Sgibbs#include <cam/cam_xpt_sim.h> 8039225Sgibbs#include <cam/cam_debug.h> 8139225Sgibbs 8239225Sgibbs#include <cam/scsi/scsi_message.h> 8339225Sgibbs 8439225Sgibbs#include <dev/aha/ahareg.h> 8539225Sgibbs 86122597Simp#define PRVERB(x) do { if (bootverbose) device_printf x; } while (0) 8739225Sgibbs 8839751Simp/* Macro to determine that a rev is potentially a new valid one 8939751Simp * so that the driver doesn't keep breaking on new revs as it 9039751Simp * did for the CF and CP. 9139751Simp */ 9239751Simp#define PROBABLY_NEW_BOARD(REV) (REV > 0x43 && REV < 0x56) 9339751Simp 9439225Sgibbs/* MailBox Management functions */ 9539225Sgibbsstatic __inline void ahanextinbox(struct aha_softc *aha); 9639225Sgibbsstatic __inline void ahanextoutbox(struct aha_softc *aha); 9739225Sgibbs 98122597Simp#define aha_name(aha) device_get_nameunit(aha->dev) 99122597Simp 10039225Sgibbsstatic __inline void 10139225Sgibbsahanextinbox(struct aha_softc *aha) 10239225Sgibbs{ 10339225Sgibbs if (aha->cur_inbox == aha->last_inbox) 10439225Sgibbs aha->cur_inbox = aha->in_boxes; 10539225Sgibbs else 10639225Sgibbs aha->cur_inbox++; 10739225Sgibbs} 10839225Sgibbs 10939225Sgibbsstatic __inline void 11039225Sgibbsahanextoutbox(struct aha_softc *aha) 11139225Sgibbs{ 11239225Sgibbs if (aha->cur_outbox == aha->last_outbox) 11339225Sgibbs aha->cur_outbox = aha->out_boxes; 11439225Sgibbs else 11539225Sgibbs aha->cur_outbox++; 11639225Sgibbs} 11739225Sgibbs 11839225Sgibbs#define ahautoa24(u,s3) \ 11939225Sgibbs (s3)[0] = ((u) >> 16) & 0xff; \ 12039225Sgibbs (s3)[1] = ((u) >> 8) & 0xff; \ 12139225Sgibbs (s3)[2] = (u) & 0xff; 12239225Sgibbs 12339225Sgibbs#define aha_a24tou(s3) \ 12439225Sgibbs (((s3)[0] << 16) | ((s3)[1] << 8) | (s3)[2]) 12539225Sgibbs 126181530Skeramida/* CCB Management functions */ 127122340Simpstatic __inline uint32_t ahaccbvtop(struct aha_softc *aha, 12841047Sgibbs struct aha_ccb *accb); 12939225Sgibbsstatic __inline struct aha_ccb* ahaccbptov(struct aha_softc *aha, 130122340Simp uint32_t ccb_addr); 13139225Sgibbs 132122340Simpstatic __inline uint32_t 13341047Sgibbsahaccbvtop(struct aha_softc *aha, struct aha_ccb *accb) 13439225Sgibbs{ 13539225Sgibbs return (aha->aha_ccb_physbase 136122340Simp + (uint32_t)((caddr_t)accb - (caddr_t)aha->aha_ccb_array)); 13739225Sgibbs} 13839225Sgibbsstatic __inline struct aha_ccb * 139122340Simpahaccbptov(struct aha_softc *aha, uint32_t ccb_addr) 14039225Sgibbs{ 14139225Sgibbs return (aha->aha_ccb_array + 142104713Speter + ((struct aha_ccb*)(uintptr_t)ccb_addr - 143104713Speter (struct aha_ccb*)(uintptr_t)aha->aha_ccb_physbase)); 14439225Sgibbs} 14539225Sgibbs 14639225Sgibbsstatic struct aha_ccb* ahagetccb(struct aha_softc *aha); 14741047Sgibbsstatic __inline void ahafreeccb(struct aha_softc *aha, struct aha_ccb *accb); 14839225Sgibbsstatic void ahaallocccbs(struct aha_softc *aha); 14939225Sgibbsstatic bus_dmamap_callback_t ahaexecuteccb; 15041047Sgibbsstatic void ahadone(struct aha_softc *aha, struct aha_ccb *accb, 15139225Sgibbs aha_mbi_comp_code_t comp_code); 152241589Sjhbstatic void aha_intr_locked(struct aha_softc *aha); 15339225Sgibbs 15439225Sgibbs/* Host adapter command functions */ 15539225Sgibbsstatic int ahareset(struct aha_softc* aha, int hard_reset); 15639225Sgibbs 15739225Sgibbs/* Initialization functions */ 15839225Sgibbsstatic int ahainitmboxes(struct aha_softc *aha); 15939225Sgibbsstatic bus_dmamap_callback_t ahamapmboxes; 16039225Sgibbsstatic bus_dmamap_callback_t ahamapccbs; 16139225Sgibbsstatic bus_dmamap_callback_t ahamapsgs; 16239225Sgibbs 16339225Sgibbs/* Transfer Negotiation Functions */ 16439225Sgibbsstatic void ahafetchtransinfo(struct aha_softc *aha, 16539225Sgibbs struct ccb_trans_settings *cts); 16639225Sgibbs 16739225Sgibbs/* CAM SIM entry points */ 16841047Sgibbs#define ccb_accb_ptr spriv_ptr0 16939225Sgibbs#define ccb_aha_ptr spriv_ptr1 17039225Sgibbsstatic void ahaaction(struct cam_sim *sim, union ccb *ccb); 17139225Sgibbsstatic void ahapoll(struct cam_sim *sim); 17239225Sgibbs 17339225Sgibbs/* Our timeout handler */ 174241589Sjhbstatic void ahatimeout(void *arg); 17539225Sgibbs 17639225Sgibbs/* Exported functions */ 177122361Simpvoid 178241603Sglebiusaha_alloc(struct aha_softc *aha) 17939225Sgibbs{ 18039225Sgibbs 18139225Sgibbs SLIST_INIT(&aha->free_aha_ccbs); 18239225Sgibbs LIST_INIT(&aha->pending_ccbs); 18339225Sgibbs SLIST_INIT(&aha->sg_maps); 18442887Simp aha->ccb_sg_opcode = INITIATOR_SG_CCB_WRESID; 18542887Simp aha->ccb_ccb_opcode = INITIATOR_CCB_WRESID; 186241589Sjhb mtx_init(&aha->lock, "aha", NULL, MTX_DEF); 18739225Sgibbs} 18839225Sgibbs 18939225Sgibbsvoid 19039225Sgibbsaha_free(struct aha_softc *aha) 19139225Sgibbs{ 19239225Sgibbs switch (aha->init_level) { 19339225Sgibbs default: 19439225Sgibbs case 8: 19539225Sgibbs { 19639225Sgibbs struct sg_map_node *sg_map; 19739225Sgibbs 19839225Sgibbs while ((sg_map = SLIST_FIRST(&aha->sg_maps))!= NULL) { 19939225Sgibbs SLIST_REMOVE_HEAD(&aha->sg_maps, links); 200122340Simp bus_dmamap_unload(aha->sg_dmat, sg_map->sg_dmamap); 20139225Sgibbs bus_dmamem_free(aha->sg_dmat, sg_map->sg_vaddr, 202122340Simp sg_map->sg_dmamap); 20339225Sgibbs free(sg_map, M_DEVBUF); 20439225Sgibbs } 20539225Sgibbs bus_dma_tag_destroy(aha->sg_dmat); 20639225Sgibbs } 20739225Sgibbs case 7: 20839225Sgibbs bus_dmamap_unload(aha->ccb_dmat, aha->ccb_dmamap); 20939225Sgibbs case 6: 21039225Sgibbs bus_dmamem_free(aha->ccb_dmat, aha->aha_ccb_array, 211122340Simp aha->ccb_dmamap); 21239225Sgibbs case 5: 21339225Sgibbs bus_dma_tag_destroy(aha->ccb_dmat); 21439225Sgibbs case 4: 21539225Sgibbs bus_dmamap_unload(aha->mailbox_dmat, aha->mailbox_dmamap); 21639225Sgibbs case 3: 21739225Sgibbs bus_dmamem_free(aha->mailbox_dmat, aha->in_boxes, 218122340Simp aha->mailbox_dmamap); 21939225Sgibbs case 2: 22039225Sgibbs bus_dma_tag_destroy(aha->buffer_dmat); 22139225Sgibbs case 1: 22239225Sgibbs bus_dma_tag_destroy(aha->mailbox_dmat); 22339225Sgibbs case 0: 22497208Speter break; 22539225Sgibbs } 226241589Sjhb mtx_destroy(&aha->lock); 22739225Sgibbs} 22839225Sgibbs 22939225Sgibbs/* 23039225Sgibbs * Probe the adapter and verify that the card is an Adaptec. 23139225Sgibbs */ 23239225Sgibbsint 23339225Sgibbsaha_probe(struct aha_softc* aha) 23439225Sgibbs{ 23539225Sgibbs u_int status; 23639225Sgibbs u_int intstat; 23739225Sgibbs int error; 23839852Simp board_id_data_t board_id; 23939225Sgibbs 24039225Sgibbs /* 24139225Sgibbs * See if the three I/O ports look reasonable. 24239225Sgibbs * Touch the minimal number of registers in the 24339225Sgibbs * failure case. 24439225Sgibbs */ 24539225Sgibbs status = aha_inb(aha, STATUS_REG); 246122340Simp if ((status == 0) || 247122340Simp (status & (DIAG_ACTIVE|CMD_REG_BUSY | STATUS_REG_RSVD)) != 0) { 248122597Simp PRVERB((aha->dev, "status reg test failed %x\n", status)); 24939225Sgibbs return (ENXIO); 25039225Sgibbs } 25139225Sgibbs 25239225Sgibbs intstat = aha_inb(aha, INTSTAT_REG); 25339225Sgibbs if ((intstat & INTSTAT_REG_RSVD) != 0) { 254122597Simp PRVERB((aha->dev, "Failed Intstat Reg Test\n")); 25539225Sgibbs return (ENXIO); 25639225Sgibbs } 25739225Sgibbs 25839225Sgibbs /* 25941047Sgibbs * Looking good so far. Final test is to reset the 26041047Sgibbs * adapter and fetch the board ID and ensure we aren't 26141047Sgibbs * looking at a BusLogic. 26241047Sgibbs */ 26341047Sgibbs if ((error = ahareset(aha, /*hard_reset*/TRUE)) != 0) { 264122597Simp PRVERB((aha->dev, "Failed Reset\n")); 26541047Sgibbs return (ENXIO); 26641047Sgibbs } 26741047Sgibbs 26841047Sgibbs /* 26939852Simp * Get the board ID. We use this to see if we're dealing with 270108533Sschweikh * a buslogic card or an aha card (or clone). 27139225Sgibbs */ 27241047Sgibbs error = aha_cmd(aha, AOP_INQUIRE_BOARD_ID, NULL, /*parmlen*/0, 273122340Simp (uint8_t*)&board_id, sizeof(board_id), DEFAULT_CMD_TIMEOUT); 27439852Simp if (error != 0) { 275122597Simp PRVERB((aha->dev, "INQUIRE failed %x\n", error)); 27639225Sgibbs return (ENXIO); 27739225Sgibbs } 27839852Simp aha->fw_major = board_id.firmware_rev_major; 27939852Simp aha->fw_minor = board_id.firmware_rev_minor; 28039852Simp aha->boardid = board_id.board_type; 28139852Simp 28239225Sgibbs /* 28339852Simp * The Buslogic cards have an id of either 0x41 or 0x42. So 28439852Simp * if those come up in the probe, we test the geometry register 28539852Simp * of the board. Adaptec boards that are this old will not have 28639852Simp * this register, and return 0xff, while buslogic cards will return 28739852Simp * something different. 28839852Simp * 28941335Simp * It appears that for reasons unknow, for the for the 29041335Simp * aha-1542B cards, we need to wait a little bit before trying 29141335Simp * to read the geometry register. I picked 10ms since we have 29241335Simp * reports that a for loop to 1000 did the trick, and this 29341335Simp * errs on the side of conservatism. Besides, no one will 29441335Simp * notice a 10mS delay here, even the 1542B card users :-) 29541335Simp * 29646997Simp * Some compatible cards return 0 here. Some cards also 29746997Simp * seem to return 0x7f. 29841807Simp * 299122363Simp * XXX I'm not sure how this will impact other cloned cards 30041807Simp * 30141807Simp * This really should be replaced with the esetup command, since 30246997Simp * that appears to be more reliable. This becomes more and more 30346997Simp * true over time as we discover more cards that don't read the 304298955Spfg * geometry register consistently. 30539225Sgibbs */ 30639852Simp if (aha->boardid <= 0x42) { 30741335Simp /* Wait 10ms before reading */ 30841335Simp DELAY(10000); 30939852Simp status = aha_inb(aha, GEOMETRY_REG); 31046997Simp if (status != 0xff && status != 0x00 && status != 0x7f) { 311122597Simp PRVERB((aha->dev, "Geometry Register test failed %#x\n", 312122597Simp status)); 31339852Simp return (ENXIO); 31441047Sgibbs } 31539751Simp } 316122363Simp 31739225Sgibbs return (0); 31839225Sgibbs} 31939225Sgibbs 32039225Sgibbs/* 32139225Sgibbs * Pull the boards setup information and record it in our softc. 32239225Sgibbs */ 32339225Sgibbsint 32439225Sgibbsaha_fetch_adapter_info(struct aha_softc *aha) 32539225Sgibbs{ 32639225Sgibbs setup_data_t setup_info; 32739225Sgibbs config_data_t config_data; 328122340Simp uint8_t length_param; 32939225Sgibbs int error; 33039751Simp struct aha_extbios extbios; 331122363Simp 33239852Simp switch (aha->boardid) { 33339225Sgibbs case BOARD_1540_16HEAD_BIOS: 33441514Sarchie snprintf(aha->model, sizeof(aha->model), "1540 16 head BIOS"); 33539225Sgibbs break; 33639225Sgibbs case BOARD_1540_64HEAD_BIOS: 33741514Sarchie snprintf(aha->model, sizeof(aha->model), "1540 64 head BIOS"); 33839225Sgibbs break; 33939225Sgibbs case BOARD_1542: 34041514Sarchie snprintf(aha->model, sizeof(aha->model), "1540/1542 64 head BIOS"); 34139225Sgibbs break; 34239225Sgibbs case BOARD_1640: 34341514Sarchie snprintf(aha->model, sizeof(aha->model), "1640"); 34439225Sgibbs break; 34539225Sgibbs case BOARD_1740: 34641514Sarchie snprintf(aha->model, sizeof(aha->model), "1740A/1742A/1744"); 34739225Sgibbs break; 34839225Sgibbs case BOARD_1542C: 34941514Sarchie snprintf(aha->model, sizeof(aha->model), "1542C"); 35039225Sgibbs break; 35139225Sgibbs case BOARD_1542CF: 35241514Sarchie snprintf(aha->model, sizeof(aha->model), "1542CF"); 35339225Sgibbs break; 35439225Sgibbs case BOARD_1542CP: 35541514Sarchie snprintf(aha->model, sizeof(aha->model), "1542CP"); 35639225Sgibbs break; 35739225Sgibbs default: 35841514Sarchie snprintf(aha->model, sizeof(aha->model), "Unknown"); 35939225Sgibbs break; 36039225Sgibbs } 36139751Simp /* 36239751Simp * If we are a new type of 1542 board (anything newer than a 1542C) 36339751Simp * then disable the extended bios so that the 36439751Simp * mailbox interface is unlocked. 36539751Simp * This is also true for the 1542B Version 3.20. First Adaptec 36639751Simp * board that supports >1Gb drives. 36739751Simp * No need to check the extended bios flags as some of the 36839751Simp * extensions that cause us problems are not flagged in that byte. 36939751Simp */ 37039751Simp if (PROBABLY_NEW_BOARD(aha->boardid) || 37139751Simp (aha->boardid == 0x41 372122363Simp && aha->fw_major == 0x31 && 37339852Simp aha->fw_minor >= 0x34)) { 37441047Sgibbs error = aha_cmd(aha, AOP_RETURN_EXT_BIOS_INFO, NULL, 375122340Simp /*paramlen*/0, (u_char *)&extbios, sizeof(extbios), 376122340Simp DEFAULT_CMD_TIMEOUT); 377122360Simp if (error != 0) { 378122597Simp device_printf(aha->dev, 379122597Simp "AOP_RETURN_EXT_BIOS_INFO - Failed."); 380122360Simp return (error); 381122360Simp } 382122340Simp error = aha_cmd(aha, AOP_MBOX_IF_ENABLE, (uint8_t *)&extbios, 383122340Simp /*paramlen*/2, NULL, 0, DEFAULT_CMD_TIMEOUT); 384122360Simp if (error != 0) { 385122597Simp device_printf(aha->dev, "AOP_MBOX_IF_ENABLE - Failed."); 386122360Simp return (error); 387122360Simp } 38839751Simp } 38939751Simp if (aha->boardid < 0x41) 390122597Simp device_printf(aha->dev, "Warning: aha-1542A won't work.\n"); 39139751Simp 39241335Simp aha->max_sg = 17; /* Need >= 17 to do 64k I/O */ 39339225Sgibbs aha->diff_bus = 0; 39439225Sgibbs aha->extended_lun = 0; 39539751Simp aha->extended_trans = 0; 39640403Simp aha->max_ccbs = 16; 39739225Sgibbs /* Determine Sync/Wide/Disc settings */ 39839225Sgibbs length_param = sizeof(setup_info); 39941047Sgibbs error = aha_cmd(aha, AOP_INQUIRE_SETUP_INFO, &length_param, 400122340Simp /*paramlen*/1, (uint8_t*)&setup_info, sizeof(setup_info), 401122340Simp DEFAULT_CMD_TIMEOUT); 40239225Sgibbs if (error != 0) { 403122597Simp device_printf(aha->dev, "aha_fetch_adapter_info - Failed " 404122597Simp "Get Setup Info\n"); 40539225Sgibbs return (error); 40639225Sgibbs } 40739225Sgibbs if (setup_info.initiate_sync != 0) { 40839225Sgibbs aha->sync_permitted = ALL_TARGETS; 40939225Sgibbs } 41039225Sgibbs aha->disc_permitted = ALL_TARGETS; 41139225Sgibbs 41239225Sgibbs /* We need as many mailboxes as we can have ccbs */ 41339225Sgibbs aha->num_boxes = aha->max_ccbs; 41439225Sgibbs 41539225Sgibbs /* Determine our SCSI ID */ 41641047Sgibbs error = aha_cmd(aha, AOP_INQUIRE_CONFIG, NULL, /*parmlen*/0, 417122340Simp (uint8_t*)&config_data, sizeof(config_data), DEFAULT_CMD_TIMEOUT); 41839225Sgibbs if (error != 0) { 419122597Simp device_printf(aha->dev, 420122597Simp "aha_fetch_adapter_info - Failed Get Config\n"); 42139225Sgibbs return (error); 42239225Sgibbs } 42339225Sgibbs aha->scsi_id = config_data.scsi_id; 42439225Sgibbs return (0); 42539225Sgibbs} 42639225Sgibbs 42739225Sgibbs/* 42839225Sgibbs * Start the board, ready for normal operation 42939225Sgibbs */ 43039225Sgibbsint 43139225Sgibbsaha_init(struct aha_softc* aha) 43239225Sgibbs{ 43339225Sgibbs /* Announce the Adapter */ 434122597Simp device_printf(aha->dev, "AHA-%s FW Rev. %c.%c (ID=%x) ", 435122340Simp aha->model, aha->fw_major, aha->fw_minor, aha->boardid); 43639225Sgibbs 43739225Sgibbs if (aha->diff_bus != 0) 43839225Sgibbs printf("Diff "); 43939225Sgibbs 44039225Sgibbs printf("SCSI Host Adapter, SCSI ID %d, %d CCBs\n", aha->scsi_id, 441122340Simp aha->max_ccbs); 44239225Sgibbs 44339225Sgibbs /* 44439225Sgibbs * Create our DMA tags. These tags define the kinds of device 445122363Simp * accessible memory allocations and memory mappings we will 44639225Sgibbs * need to perform during normal operation. 44739225Sgibbs * 44839225Sgibbs * Unless we need to further restrict the allocation, we rely 44939225Sgibbs * on the restrictions of the parent dmat, hence the common 45039225Sgibbs * use of MAXADDR and MAXSIZE. 45139225Sgibbs */ 45239225Sgibbs 45339225Sgibbs /* DMA tag for mapping buffers into device visible space. */ 454122340Simp if (bus_dma_tag_create( /* parent */ aha->parent_dmat, 455112782Smdodd /* alignment */ 1, 456112782Smdodd /* boundary */ 0, 457112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR, 458112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 459112782Smdodd /* filter */ NULL, 460112782Smdodd /* filterarg */ NULL, 461280347Smav /* maxsize */ DFLTPHYS, 462112782Smdodd /* nsegments */ AHA_NSEG, 463112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_24BIT, 464112782Smdodd /* flags */ BUS_DMA_ALLOCNOW, 465117126Sscottl /* lockfunc */ busdma_lock_mutex, 466241589Sjhb /* lockarg */ &aha->lock, 467112782Smdodd &aha->buffer_dmat) != 0) { 46839225Sgibbs goto error_exit; 46939225Sgibbs } 47039225Sgibbs 47139225Sgibbs aha->init_level++; 47239225Sgibbs /* DMA tag for our mailboxes */ 473112782Smdodd if (bus_dma_tag_create( /* parent */ aha->parent_dmat, 474112782Smdodd /* alignment */ 1, 475112782Smdodd /* boundary */ 0, 476112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR, 477112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 478112782Smdodd /* filter */ NULL, 479112782Smdodd /* filterarg */ NULL, 480112782Smdodd /* maxsize */ aha->num_boxes * 481112782Smdodd (sizeof(aha_mbox_in_t) + 482112782Smdodd sizeof(aha_mbox_out_t)), 483112782Smdodd /* nsegments */ 1, 484112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_24BIT, 485112782Smdodd /* flags */ 0, 486241589Sjhb /* lockfunc */ NULL, 487241589Sjhb /* lockarg */ NULL, 488112782Smdodd &aha->mailbox_dmat) != 0) { 48939225Sgibbs goto error_exit; 49039225Sgibbs } 49139225Sgibbs 49239225Sgibbs aha->init_level++; 49339225Sgibbs 49439225Sgibbs /* Allocation for our mailboxes */ 49539225Sgibbs if (bus_dmamem_alloc(aha->mailbox_dmat, (void **)&aha->out_boxes, 496122340Simp BUS_DMA_NOWAIT, &aha->mailbox_dmamap) != 0) 49739225Sgibbs goto error_exit; 49839225Sgibbs 49939225Sgibbs aha->init_level++; 50039225Sgibbs 50139225Sgibbs /* And permanently map them */ 50239225Sgibbs bus_dmamap_load(aha->mailbox_dmat, aha->mailbox_dmamap, 503122340Simp aha->out_boxes, aha->num_boxes * (sizeof(aha_mbox_in_t) + 504122340Simp sizeof(aha_mbox_out_t)), ahamapmboxes, aha, /*flags*/0); 50539225Sgibbs 50639225Sgibbs aha->init_level++; 50739225Sgibbs 50839225Sgibbs aha->in_boxes = (aha_mbox_in_t *)&aha->out_boxes[aha->num_boxes]; 50939225Sgibbs 51039225Sgibbs ahainitmboxes(aha); 51139225Sgibbs 51239225Sgibbs /* DMA tag for our ccb structures */ 513112782Smdodd if (bus_dma_tag_create( /* parent */ aha->parent_dmat, 514112782Smdodd /* alignment */ 1, 515112782Smdodd /* boundary */ 0, 516112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR, 517112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 518112782Smdodd /* filter */ NULL, 519112782Smdodd /* filterarg */ NULL, 520112782Smdodd /* maxsize */ aha->max_ccbs * 521112782Smdodd sizeof(struct aha_ccb), 522112782Smdodd /* nsegments */ 1, 523112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_24BIT, 524112782Smdodd /* flags */ 0, 525241589Sjhb /* lockfunc */ NULL, 526241589Sjhb /* lockarg */ NULL, 527112782Smdodd &aha->ccb_dmat) != 0) { 52839225Sgibbs goto error_exit; 52939225Sgibbs } 53039225Sgibbs 53139225Sgibbs aha->init_level++; 53239225Sgibbs 53339225Sgibbs /* Allocation for our ccbs */ 53439225Sgibbs if (bus_dmamem_alloc(aha->ccb_dmat, (void **)&aha->aha_ccb_array, 535122340Simp BUS_DMA_NOWAIT, &aha->ccb_dmamap) != 0) 53639225Sgibbs goto error_exit; 53739225Sgibbs 53839225Sgibbs aha->init_level++; 53939225Sgibbs 54039225Sgibbs /* And permanently map them */ 541122340Simp bus_dmamap_load(aha->ccb_dmat, aha->ccb_dmamap, aha->aha_ccb_array, 542122340Simp aha->max_ccbs * sizeof(struct aha_ccb), ahamapccbs, aha, /*flags*/0); 54339225Sgibbs 54439225Sgibbs aha->init_level++; 54539225Sgibbs 54639225Sgibbs /* DMA tag for our S/G structures. We allocate in page sized chunks */ 547112782Smdodd if (bus_dma_tag_create( /* parent */ aha->parent_dmat, 548112782Smdodd /* alignment */ 1, 549112782Smdodd /* boundary */ 0, 550112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR, 551112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 552112782Smdodd /* filter */ NULL, 553112782Smdodd /* filterarg */ NULL, 554112782Smdodd /* maxsize */ PAGE_SIZE, 555112782Smdodd /* nsegments */ 1, 556112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_24BIT, 557112782Smdodd /* flags */ 0, 558241589Sjhb /* lockfunc */ NULL, 559241589Sjhb /* lockarg */ NULL, 560122340Simp &aha->sg_dmat) != 0) 56139225Sgibbs goto error_exit; 56239225Sgibbs 56339225Sgibbs aha->init_level++; 56439225Sgibbs 56539225Sgibbs /* Perform initial CCB allocation */ 56639225Sgibbs bzero(aha->aha_ccb_array, aha->max_ccbs * sizeof(struct aha_ccb)); 56739225Sgibbs ahaallocccbs(aha); 56839225Sgibbs 56939225Sgibbs if (aha->num_ccbs == 0) { 570122597Simp device_printf(aha->dev, 571122597Simp "aha_init - Unable to allocate initial ccbs\n"); 57239225Sgibbs goto error_exit; 57339225Sgibbs } 57439225Sgibbs 57539225Sgibbs /* 57639225Sgibbs * Note that we are going and return (to probe) 57739225Sgibbs */ 578122340Simp return (0); 57939225Sgibbs 58039225Sgibbserror_exit: 58139225Sgibbs 58239225Sgibbs return (ENXIO); 58339225Sgibbs} 58439225Sgibbs 58539225Sgibbsint 58639225Sgibbsaha_attach(struct aha_softc *aha) 58739225Sgibbs{ 58839225Sgibbs int tagged_dev_openings; 58939225Sgibbs struct cam_devq *devq; 59039225Sgibbs 59139225Sgibbs /* 59241335Simp * We don't do tagged queueing, since the aha cards don't 59341335Simp * support it. 59439225Sgibbs */ 59539225Sgibbs tagged_dev_openings = 0; 59639225Sgibbs 59739225Sgibbs /* 59839225Sgibbs * Create the device queue for our SIM. 59939225Sgibbs */ 60039225Sgibbs devq = cam_simq_alloc(aha->max_ccbs - 1); 60139225Sgibbs if (devq == NULL) 60239225Sgibbs return (ENOMEM); 60339225Sgibbs 60439225Sgibbs /* 60539225Sgibbs * Construct our SIM entry 60639225Sgibbs */ 607241589Sjhb aha->sim = cam_sim_alloc(ahaaction, ahapoll, "aha", aha, 608241589Sjhb device_get_unit(aha->dev), &aha->lock, 2, tagged_dev_openings, 609241589Sjhb devq); 61039225Sgibbs if (aha->sim == NULL) { 61139225Sgibbs cam_simq_free(devq); 61239225Sgibbs return (ENOMEM); 61339225Sgibbs } 614241589Sjhb mtx_lock(&aha->lock); 615170872Sscottl if (xpt_bus_register(aha->sim, aha->dev, 0) != CAM_SUCCESS) { 61639225Sgibbs cam_sim_free(aha->sim, /*free_devq*/TRUE); 617241589Sjhb mtx_unlock(&aha->lock); 61839225Sgibbs return (ENXIO); 61939225Sgibbs } 620122340Simp if (xpt_create_path(&aha->path, /*periph*/NULL, cam_sim_path(aha->sim), 621122340Simp CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 62239225Sgibbs xpt_bus_deregister(cam_sim_path(aha->sim)); 62339225Sgibbs cam_sim_free(aha->sim, /*free_devq*/TRUE); 624241589Sjhb mtx_unlock(&aha->lock); 62539225Sgibbs return (ENXIO); 62639225Sgibbs } 627241589Sjhb mtx_unlock(&aha->lock); 628122363Simp 62939225Sgibbs return (0); 63039225Sgibbs} 63139225Sgibbs 63239225Sgibbsstatic void 63339225Sgibbsahaallocccbs(struct aha_softc *aha) 63439225Sgibbs{ 63539225Sgibbs struct aha_ccb *next_ccb; 63639225Sgibbs struct sg_map_node *sg_map; 63739225Sgibbs bus_addr_t physaddr; 63839225Sgibbs aha_sg_t *segs; 63939225Sgibbs int newcount; 64039225Sgibbs int i; 64139225Sgibbs 64239225Sgibbs next_ccb = &aha->aha_ccb_array[aha->num_ccbs]; 64339225Sgibbs 64439225Sgibbs sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT); 64539225Sgibbs 64639225Sgibbs if (sg_map == NULL) 64739225Sgibbs return; 64839225Sgibbs 64939225Sgibbs /* Allocate S/G space for the next batch of CCBS */ 65039225Sgibbs if (bus_dmamem_alloc(aha->sg_dmat, (void **)&sg_map->sg_vaddr, 651122340Simp BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) { 65239225Sgibbs free(sg_map, M_DEVBUF); 65339225Sgibbs return; 65439225Sgibbs } 65539225Sgibbs 65639225Sgibbs SLIST_INSERT_HEAD(&aha->sg_maps, sg_map, links); 65739225Sgibbs 65839225Sgibbs bus_dmamap_load(aha->sg_dmat, sg_map->sg_dmamap, sg_map->sg_vaddr, 659122340Simp PAGE_SIZE, ahamapsgs, aha, /*flags*/0); 660122363Simp 66139225Sgibbs segs = sg_map->sg_vaddr; 66239225Sgibbs physaddr = sg_map->sg_physaddr; 66339225Sgibbs 66439225Sgibbs newcount = (PAGE_SIZE / (AHA_NSEG * sizeof(aha_sg_t))); 66539225Sgibbs for (i = 0; aha->num_ccbs < aha->max_ccbs && i < newcount; i++) { 66639225Sgibbs int error; 66739225Sgibbs 66839225Sgibbs next_ccb->sg_list = segs; 66939225Sgibbs next_ccb->sg_list_phys = physaddr; 67041047Sgibbs next_ccb->flags = ACCB_FREE; 671241589Sjhb callout_init_mtx(&next_ccb->timer, &aha->lock, 0); 67239225Sgibbs error = bus_dmamap_create(aha->buffer_dmat, /*flags*/0, 673122340Simp &next_ccb->dmamap); 67439225Sgibbs if (error != 0) 67539225Sgibbs break; 67639225Sgibbs SLIST_INSERT_HEAD(&aha->free_aha_ccbs, next_ccb, links); 67739225Sgibbs segs += AHA_NSEG; 67839225Sgibbs physaddr += (AHA_NSEG * sizeof(aha_sg_t)); 67939225Sgibbs next_ccb++; 68039225Sgibbs aha->num_ccbs++; 68139225Sgibbs } 68239225Sgibbs 68339225Sgibbs /* Reserve a CCB for error recovery */ 68441047Sgibbs if (aha->recovery_accb == NULL) { 68541047Sgibbs aha->recovery_accb = SLIST_FIRST(&aha->free_aha_ccbs); 68639225Sgibbs SLIST_REMOVE_HEAD(&aha->free_aha_ccbs, links); 68739225Sgibbs } 68839225Sgibbs} 68939225Sgibbs 69039225Sgibbsstatic __inline void 69141047Sgibbsahafreeccb(struct aha_softc *aha, struct aha_ccb *accb) 69239225Sgibbs{ 69339225Sgibbs 694241589Sjhb if (!dumping) 695241589Sjhb mtx_assert(&aha->lock, MA_OWNED); 69641047Sgibbs if ((accb->flags & ACCB_ACTIVE) != 0) 69741047Sgibbs LIST_REMOVE(&accb->ccb->ccb_h, sim_links.le); 69839225Sgibbs if (aha->resource_shortage != 0 699122340Simp && (accb->ccb->ccb_h.status & CAM_RELEASE_SIMQ) == 0) { 70041047Sgibbs accb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 70139225Sgibbs aha->resource_shortage = FALSE; 70239225Sgibbs } 70341047Sgibbs accb->flags = ACCB_FREE; 70441047Sgibbs SLIST_INSERT_HEAD(&aha->free_aha_ccbs, accb, links); 70541047Sgibbs aha->active_ccbs--; 70639225Sgibbs} 70739225Sgibbs 70839225Sgibbsstatic struct aha_ccb* 70939225Sgibbsahagetccb(struct aha_softc *aha) 71039225Sgibbs{ 71141047Sgibbs struct aha_ccb* accb; 71239225Sgibbs 713241589Sjhb if (!dumping) 714241589Sjhb mtx_assert(&aha->lock, MA_OWNED); 71541047Sgibbs if ((accb = SLIST_FIRST(&aha->free_aha_ccbs)) != NULL) { 71639225Sgibbs SLIST_REMOVE_HEAD(&aha->free_aha_ccbs, links); 71741047Sgibbs aha->active_ccbs++; 71839225Sgibbs } else if (aha->num_ccbs < aha->max_ccbs) { 71939225Sgibbs ahaallocccbs(aha); 72041047Sgibbs accb = SLIST_FIRST(&aha->free_aha_ccbs); 72141047Sgibbs if (accb == NULL) 722122597Simp device_printf(aha->dev, "Can't malloc ACCB\n"); 72341047Sgibbs else { 72439225Sgibbs SLIST_REMOVE_HEAD(&aha->free_aha_ccbs, links); 72541047Sgibbs aha->active_ccbs++; 72641047Sgibbs } 72739225Sgibbs } 72839225Sgibbs 72941047Sgibbs return (accb); 73039225Sgibbs} 73139225Sgibbs 73239225Sgibbsstatic void 73339225Sgibbsahaaction(struct cam_sim *sim, union ccb *ccb) 73439225Sgibbs{ 73539225Sgibbs struct aha_softc *aha; 73639225Sgibbs 73739225Sgibbs CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("ahaaction\n")); 738122363Simp 73939225Sgibbs aha = (struct aha_softc *)cam_sim_softc(sim); 740241589Sjhb mtx_assert(&aha->lock, MA_OWNED); 741122363Simp 74239225Sgibbs switch (ccb->ccb_h.func_code) { 74339225Sgibbs /* Common cases first */ 74439225Sgibbs case XPT_SCSI_IO: /* Execute the requested I/O operation */ 745122340Simp case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ { 74641047Sgibbs struct aha_ccb *accb; 74739225Sgibbs struct aha_hccb *hccb; 74839225Sgibbs 74939225Sgibbs /* 750108533Sschweikh * Get an accb to use. 75139225Sgibbs */ 75241047Sgibbs if ((accb = ahagetccb(aha)) == NULL) { 75339225Sgibbs aha->resource_shortage = TRUE; 75439225Sgibbs xpt_freeze_simq(aha->sim, /*count*/1); 75539225Sgibbs ccb->ccb_h.status = CAM_REQUEUE_REQ; 75639225Sgibbs xpt_done(ccb); 75739225Sgibbs return; 75839225Sgibbs } 75941047Sgibbs hccb = &accb->hccb; 76039225Sgibbs 76139225Sgibbs /* 76241047Sgibbs * So we can find the ACCB when an abort is requested 76339225Sgibbs */ 76441047Sgibbs accb->ccb = ccb; 76541047Sgibbs ccb->ccb_h.ccb_accb_ptr = accb; 76639225Sgibbs ccb->ccb_h.ccb_aha_ptr = aha; 76739225Sgibbs 76839225Sgibbs /* 76941047Sgibbs * Put all the arguments for the xfer in the accb 77039225Sgibbs */ 77139225Sgibbs hccb->target = ccb->ccb_h.target_id; 77239225Sgibbs hccb->lun = ccb->ccb_h.target_lun; 77339225Sgibbs hccb->ahastat = 0; 77439225Sgibbs hccb->sdstat = 0; 77539225Sgibbs 77639225Sgibbs if (ccb->ccb_h.func_code == XPT_SCSI_IO) { 77739225Sgibbs struct ccb_scsiio *csio; 77839225Sgibbs struct ccb_hdr *ccbh; 779246713Skib int error; 78039225Sgibbs 78139225Sgibbs csio = &ccb->csio; 78239225Sgibbs ccbh = &csio->ccb_h; 78342887Simp hccb->opcode = aha->ccb_ccb_opcode; 78439225Sgibbs hccb->datain = (ccb->ccb_h.flags & CAM_DIR_IN) != 0; 78539225Sgibbs hccb->dataout = (ccb->ccb_h.flags & CAM_DIR_OUT) != 0; 78639225Sgibbs hccb->cmd_len = csio->cdb_len; 78739225Sgibbs if (hccb->cmd_len > sizeof(hccb->scsi_cdb)) { 78839225Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 78941047Sgibbs ahafreeccb(aha, accb); 79039225Sgibbs xpt_done(ccb); 79139225Sgibbs return; 79239225Sgibbs } 79339225Sgibbs hccb->sense_len = csio->sense_len; 79439225Sgibbs if ((ccbh->flags & CAM_CDB_POINTER) != 0) { 79539225Sgibbs if ((ccbh->flags & CAM_CDB_PHYS) == 0) { 79639225Sgibbs bcopy(csio->cdb_io.cdb_ptr, 79739225Sgibbs hccb->scsi_cdb, hccb->cmd_len); 79839225Sgibbs } else { 79939225Sgibbs /* I guess I could map it in... */ 80039225Sgibbs ccbh->status = CAM_REQ_INVALID; 80141047Sgibbs ahafreeccb(aha, accb); 80239225Sgibbs xpt_done(ccb); 80339225Sgibbs return; 80439225Sgibbs } 80539225Sgibbs } else { 80639225Sgibbs bcopy(csio->cdb_io.cdb_bytes, 80739225Sgibbs hccb->scsi_cdb, hccb->cmd_len); 80839225Sgibbs } 80939225Sgibbs /* 81039225Sgibbs * If we have any data to send with this command, 81139225Sgibbs * map it into bus space. 81239225Sgibbs */ 81339225Sgibbs 814246713Skib error = bus_dmamap_load_ccb( 815246713Skib aha->buffer_dmat, 816246713Skib accb->dmamap, 817246713Skib ccb, 818246713Skib ahaexecuteccb, 819246713Skib accb, 820246713Skib /*flags*/0); 821246713Skib if (error == EINPROGRESS) { 822246713Skib /* 823246713Skib * So as to maintain ordering, freeze the 824246713Skib * controller queue until our mapping is 825246713Skib * returned. 826246713Skib */ 827246713Skib xpt_freeze_simq(aha->sim, 1); 828246713Skib csio->ccb_h.status |= CAM_RELEASE_SIMQ; 82939225Sgibbs } 83039225Sgibbs } else { 83139225Sgibbs hccb->opcode = INITIATOR_BUS_DEV_RESET; 83239225Sgibbs /* No data transfer */ 83339225Sgibbs hccb->datain = TRUE; 83439225Sgibbs hccb->dataout = TRUE; 83539225Sgibbs hccb->cmd_len = 0; 83639225Sgibbs hccb->sense_len = 0; 83741047Sgibbs ahaexecuteccb(accb, NULL, 0, 0); 83839225Sgibbs } 83939225Sgibbs break; 84039225Sgibbs } 84139225Sgibbs case XPT_EN_LUN: /* Enable LUN as a target */ 84239225Sgibbs case XPT_TARGET_IO: /* Execute target I/O request */ 84339225Sgibbs case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */ 84439225Sgibbs case XPT_CONT_TARGET_IO: /* Continue Host Target I/O Connection*/ 84539225Sgibbs case XPT_ABORT: /* Abort the specified CCB */ 84639225Sgibbs /* XXX Implement */ 84739225Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 84839225Sgibbs xpt_done(ccb); 84939225Sgibbs break; 85039225Sgibbs case XPT_SET_TRAN_SETTINGS: 85139225Sgibbs /* XXX Implement */ 85246581Sken ccb->ccb_h.status = CAM_PROVIDE_FAIL; 85339225Sgibbs xpt_done(ccb); 85439225Sgibbs break; 85539225Sgibbs case XPT_GET_TRAN_SETTINGS: 85639225Sgibbs /* Get default/user set transfer settings for the target */ 85739225Sgibbs { 858163816Smjacob struct ccb_trans_settings *cts = &ccb->cts; 859163816Smjacob u_int target_mask = 0x01 << ccb->ccb_h.target_id; 860163816Smjacob struct ccb_trans_settings_scsi *scsi = 861163816Smjacob &cts->proto_specific.scsi; 862163816Smjacob struct ccb_trans_settings_spi *spi = 863163816Smjacob &cts->xport_specific.spi; 86439225Sgibbs 865163816Smjacob cts->protocol = PROTO_SCSI; 866163816Smjacob cts->protocol_version = SCSI_REV_2; 867163816Smjacob cts->transport = XPORT_SPI; 868163816Smjacob cts->transport_version = 2; 869163816Smjacob if (cts->type == CTS_TYPE_USER_SETTINGS) { 870163816Smjacob spi->flags = 0; 871163816Smjacob if ((aha->disc_permitted & target_mask) != 0) 872163816Smjacob spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 873163816Smjacob spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 874163816Smjacob if ((aha->sync_permitted & target_mask) != 0) { 875163816Smjacob if (aha->boardid >= BOARD_1542CF) 876163816Smjacob spi->sync_period = 25; 877163816Smjacob else 878163816Smjacob spi->sync_period = 50; 879163816Smjacob } else { 880163816Smjacob spi->sync_period = 0; 881163816Smjacob } 882163816Smjacob 883163816Smjacob if (spi->sync_period != 0) 884163816Smjacob spi->sync_offset = 15; 885163816Smjacob 886163816Smjacob spi->valid = CTS_SPI_VALID_SYNC_RATE 887163816Smjacob | CTS_SPI_VALID_SYNC_OFFSET 888163816Smjacob | CTS_SPI_VALID_BUS_WIDTH 889163816Smjacob | CTS_SPI_VALID_DISC; 890163816Smjacob scsi->valid = CTS_SCSI_VALID_TQ; 891163816Smjacob } else { 892163816Smjacob ahafetchtransinfo(aha, cts); 893163816Smjacob } 89439225Sgibbs 89539225Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 89639225Sgibbs xpt_done(ccb); 89739225Sgibbs break; 89839225Sgibbs } 89939225Sgibbs case XPT_CALC_GEOMETRY: 90039225Sgibbs { 90139225Sgibbs struct ccb_calc_geometry *ccg; 902122340Simp uint32_t size_mb; 903122340Simp uint32_t secs_per_cylinder; 90439225Sgibbs 90539225Sgibbs ccg = &ccb->ccg; 90639225Sgibbs size_mb = ccg->volume_size 90739225Sgibbs / ((1024L * 1024L) / ccg->block_size); 90839225Sgibbs if (size_mb >= 1024 && (aha->extended_trans != 0)) { 90939225Sgibbs if (size_mb >= 2048) { 91039225Sgibbs ccg->heads = 255; 91139225Sgibbs ccg->secs_per_track = 63; 91239225Sgibbs } else { 91339225Sgibbs ccg->heads = 128; 91439225Sgibbs ccg->secs_per_track = 32; 91539225Sgibbs } 91639225Sgibbs } else { 91739225Sgibbs ccg->heads = 64; 91839225Sgibbs ccg->secs_per_track = 32; 91939225Sgibbs } 92039225Sgibbs secs_per_cylinder = ccg->heads * ccg->secs_per_track; 92139225Sgibbs ccg->cylinders = ccg->volume_size / secs_per_cylinder; 92239225Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 92339225Sgibbs xpt_done(ccb); 92439225Sgibbs break; 92539225Sgibbs } 92639225Sgibbs case XPT_RESET_BUS: /* Reset the specified SCSI bus */ 92739225Sgibbs ahareset(aha, /*hardreset*/TRUE); 92839225Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 92939225Sgibbs xpt_done(ccb); 93039225Sgibbs break; 93139225Sgibbs case XPT_TERM_IO: /* Terminate the I/O process */ 93239225Sgibbs /* XXX Implement */ 93339225Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 93439225Sgibbs xpt_done(ccb); 93539225Sgibbs break; 93639225Sgibbs case XPT_PATH_INQ: /* Path routing inquiry */ 93739225Sgibbs { 93839225Sgibbs struct ccb_pathinq *cpi = &ccb->cpi; 939122363Simp 94039225Sgibbs cpi->version_num = 1; /* XXX??? */ 94139225Sgibbs cpi->hba_inquiry = PI_SDTR_ABLE; 94239225Sgibbs cpi->target_sprt = 0; 94339225Sgibbs cpi->hba_misc = 0; 94439225Sgibbs cpi->hba_eng_cnt = 0; 94539852Simp cpi->max_target = 7; 94639225Sgibbs cpi->max_lun = 7; 94739225Sgibbs cpi->initiator_id = aha->scsi_id; 94839225Sgibbs cpi->bus_id = cam_sim_bus(sim); 94946581Sken cpi->base_transfer_speed = 3300; 95039225Sgibbs strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 95139225Sgibbs strncpy(cpi->hba_vid, "Adaptec", HBA_IDLEN); 95239225Sgibbs strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 95339225Sgibbs cpi->unit_number = cam_sim_unit(sim); 954163816Smjacob cpi->transport = XPORT_SPI; 955163816Smjacob cpi->transport_version = 2; 956163816Smjacob cpi->protocol = PROTO_SCSI; 957163816Smjacob cpi->protocol_version = SCSI_REV_2; 95839225Sgibbs cpi->ccb_h.status = CAM_REQ_CMP; 95939225Sgibbs xpt_done(ccb); 96039225Sgibbs break; 96139225Sgibbs } 96239225Sgibbs default: 96339225Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 96439225Sgibbs xpt_done(ccb); 96539225Sgibbs break; 96639225Sgibbs } 96739225Sgibbs} 96839225Sgibbs 96939225Sgibbsstatic void 97039225Sgibbsahaexecuteccb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 97139225Sgibbs{ 97241047Sgibbs struct aha_ccb *accb; 97339225Sgibbs union ccb *ccb; 97439225Sgibbs struct aha_softc *aha; 975122340Simp uint32_t paddr; 97639225Sgibbs 97741047Sgibbs accb = (struct aha_ccb *)arg; 97841047Sgibbs ccb = accb->ccb; 97939225Sgibbs aha = (struct aha_softc *)ccb->ccb_h.ccb_aha_ptr; 98039225Sgibbs 98139225Sgibbs if (error != 0) { 98239225Sgibbs if (error != EFBIG) 983122597Simp device_printf(aha->dev, 984122597Simp "Unexepected error 0x%x returned from " 985122597Simp "bus_dmamap_load\n", error); 98639225Sgibbs if (ccb->ccb_h.status == CAM_REQ_INPROG) { 98739225Sgibbs xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 98839225Sgibbs ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN; 98939225Sgibbs } 99041047Sgibbs ahafreeccb(aha, accb); 99139225Sgibbs xpt_done(ccb); 99239225Sgibbs return; 99339225Sgibbs } 994122363Simp 99539225Sgibbs if (nseg != 0) { 99639225Sgibbs aha_sg_t *sg; 99739225Sgibbs bus_dma_segment_t *end_seg; 998115343Sscottl bus_dmasync_op_t op; 99939225Sgibbs 100039225Sgibbs end_seg = dm_segs + nseg; 100139225Sgibbs 100239225Sgibbs /* Copy the segments into our SG list */ 100341047Sgibbs sg = accb->sg_list; 100439225Sgibbs while (dm_segs < end_seg) { 100539225Sgibbs ahautoa24(dm_segs->ds_len, sg->len); 100639225Sgibbs ahautoa24(dm_segs->ds_addr, sg->addr); 100739225Sgibbs sg++; 100839225Sgibbs dm_segs++; 100939225Sgibbs } 101039225Sgibbs 101139225Sgibbs if (nseg > 1) { 101242887Simp accb->hccb.opcode = aha->ccb_sg_opcode; 101339225Sgibbs ahautoa24((sizeof(aha_sg_t) * nseg), 1014122340Simp accb->hccb.data_len); 101541047Sgibbs ahautoa24(accb->sg_list_phys, accb->hccb.data_addr); 101639225Sgibbs } else { 101741047Sgibbs bcopy(accb->sg_list->len, accb->hccb.data_len, 3); 101841047Sgibbs bcopy(accb->sg_list->addr, accb->hccb.data_addr, 3); 101939225Sgibbs } 102039225Sgibbs 102139225Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 102239225Sgibbs op = BUS_DMASYNC_PREREAD; 102339225Sgibbs else 102439225Sgibbs op = BUS_DMASYNC_PREWRITE; 102539225Sgibbs 102641047Sgibbs bus_dmamap_sync(aha->buffer_dmat, accb->dmamap, op); 102739225Sgibbs 102839225Sgibbs } else { 102941709Sgibbs accb->hccb.opcode = INITIATOR_CCB; 103041047Sgibbs ahautoa24(0, accb->hccb.data_len); 103141047Sgibbs ahautoa24(0, accb->hccb.data_addr); 103239225Sgibbs } 103339225Sgibbs 103439225Sgibbs /* 103539225Sgibbs * Last time we need to check if this CCB needs to 103639225Sgibbs * be aborted. 103739225Sgibbs */ 103839225Sgibbs if (ccb->ccb_h.status != CAM_REQ_INPROG) { 103939225Sgibbs if (nseg != 0) 104041047Sgibbs bus_dmamap_unload(aha->buffer_dmat, accb->dmamap); 104141047Sgibbs ahafreeccb(aha, accb); 104239225Sgibbs xpt_done(ccb); 104339225Sgibbs return; 104439225Sgibbs } 1045122363Simp 104641047Sgibbs accb->flags = ACCB_ACTIVE; 104739225Sgibbs ccb->ccb_h.status |= CAM_SIM_QUEUED; 104839225Sgibbs LIST_INSERT_HEAD(&aha->pending_ccbs, &ccb->ccb_h, sim_links.le); 104939225Sgibbs 1050274819Ssmh callout_reset_sbt(&accb->timer, SBT_1MS * ccb->ccb_h.timeout, 0, 1051274819Ssmh ahatimeout, accb, 0); 105239225Sgibbs 105339225Sgibbs /* Tell the adapter about this command */ 105441047Sgibbs if (aha->cur_outbox->action_code != AMBO_FREE) { 105541047Sgibbs /* 105641047Sgibbs * We should never encounter a busy mailbox. 105741047Sgibbs * If we do, warn the user, and treat it as 105841047Sgibbs * a resource shortage. If the controller is 105941047Sgibbs * hung, one of the pending transactions will 106041047Sgibbs * timeout causing us to start recovery operations. 106141047Sgibbs */ 1062122597Simp device_printf(aha->dev, 1063122597Simp "Encountered busy mailbox with %d out of %d " 1064122597Simp "commands active!!!", aha->active_ccbs, aha->max_ccbs); 1065241603Sglebius callout_stop(&accb->timer); 106641047Sgibbs if (nseg != 0) 106741047Sgibbs bus_dmamap_unload(aha->buffer_dmat, accb->dmamap); 106841047Sgibbs ahafreeccb(aha, accb); 106941047Sgibbs aha->resource_shortage = TRUE; 107041047Sgibbs xpt_freeze_simq(aha->sim, /*count*/1); 107141047Sgibbs ccb->ccb_h.status = CAM_REQUEUE_REQ; 107241047Sgibbs xpt_done(ccb); 107341047Sgibbs return; 107441047Sgibbs } 107541047Sgibbs paddr = ahaccbvtop(aha, accb); 107639225Sgibbs ahautoa24(paddr, aha->cur_outbox->ccb_addr); 1077122363Simp aha->cur_outbox->action_code = AMBO_START; 107841047Sgibbs aha_outb(aha, COMMAND_REG, AOP_START_MBOX); 107939225Sgibbs 108039225Sgibbs ahanextoutbox(aha); 108139225Sgibbs} 108239225Sgibbs 108339225Sgibbsvoid 108439225Sgibbsaha_intr(void *arg) 108539225Sgibbs{ 108639225Sgibbs struct aha_softc *aha; 1087241589Sjhb 1088241589Sjhb aha = arg; 1089241589Sjhb mtx_lock(&aha->lock); 1090241589Sjhb aha_intr_locked(aha); 1091241589Sjhb mtx_unlock(&aha->lock); 1092241589Sjhb} 1093241589Sjhb 1094241589Sjhbvoid 1095241589Sjhbaha_intr_locked(struct aha_softc *aha) 1096241589Sjhb{ 109739225Sgibbs u_int intstat; 1098122340Simp uint32_t paddr; 109939225Sgibbs 110039225Sgibbs while (((intstat = aha_inb(aha, INTSTAT_REG)) & INTR_PENDING) != 0) { 110139225Sgibbs if ((intstat & CMD_COMPLETE) != 0) { 110239225Sgibbs aha->latched_status = aha_inb(aha, STATUS_REG); 110339225Sgibbs aha->command_cmp = TRUE; 110439225Sgibbs } 110539225Sgibbs 110639225Sgibbs aha_outb(aha, CONTROL_REG, RESET_INTR); 110739225Sgibbs 110839225Sgibbs if ((intstat & IMB_LOADED) != 0) { 110941047Sgibbs while (aha->cur_inbox->comp_code != AMBI_FREE) { 111039225Sgibbs paddr = aha_a24tou(aha->cur_inbox->ccb_addr); 1111122340Simp ahadone(aha, ahaccbptov(aha, paddr), 1112122340Simp aha->cur_inbox->comp_code); 111341047Sgibbs aha->cur_inbox->comp_code = AMBI_FREE; 111439225Sgibbs ahanextinbox(aha); 111539225Sgibbs } 111639225Sgibbs } 111739225Sgibbs 111839225Sgibbs if ((intstat & SCSI_BUS_RESET) != 0) { 111939225Sgibbs ahareset(aha, /*hardreset*/FALSE); 112039225Sgibbs } 112139225Sgibbs } 112239225Sgibbs} 112339225Sgibbs 112439225Sgibbsstatic void 112541047Sgibbsahadone(struct aha_softc *aha, struct aha_ccb *accb, aha_mbi_comp_code_t comp_code) 112639225Sgibbs{ 112739225Sgibbs union ccb *ccb; 112839225Sgibbs struct ccb_scsiio *csio; 112939225Sgibbs 113041047Sgibbs ccb = accb->ccb; 113141047Sgibbs csio = &accb->ccb->csio; 113239225Sgibbs 113341047Sgibbs if ((accb->flags & ACCB_ACTIVE) == 0) { 1134122597Simp device_printf(aha->dev, 1135122597Simp "ahadone - Attempt to free non-active ACCB %p\n", 1136122597Simp (void *)accb); 113739225Sgibbs return; 113839225Sgibbs } 113939225Sgibbs 114039225Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 1141115343Sscottl bus_dmasync_op_t op; 114239225Sgibbs 114339225Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 114439225Sgibbs op = BUS_DMASYNC_POSTREAD; 114539225Sgibbs else 114639225Sgibbs op = BUS_DMASYNC_POSTWRITE; 114741047Sgibbs bus_dmamap_sync(aha->buffer_dmat, accb->dmamap, op); 114841047Sgibbs bus_dmamap_unload(aha->buffer_dmat, accb->dmamap); 114939225Sgibbs } 115039225Sgibbs 115141047Sgibbs if (accb == aha->recovery_accb) { 115239225Sgibbs /* 115341047Sgibbs * The recovery ACCB does not have a CCB associated 115439225Sgibbs * with it, so short circuit the normal error handling. 115539225Sgibbs * We now traverse our list of pending CCBs and process 115639225Sgibbs * any that were terminated by the recovery CCBs action. 115739225Sgibbs * We also reinstate timeouts for all remaining, pending, 115839225Sgibbs * CCBs. 115939225Sgibbs */ 116039225Sgibbs struct cam_path *path; 116139225Sgibbs struct ccb_hdr *ccb_h; 116239225Sgibbs cam_status error; 116339225Sgibbs 1164298955Spfg /* Notify all clients that a BDR occurred */ 116539225Sgibbs error = xpt_create_path(&path, /*periph*/NULL, 1166122340Simp cam_sim_path(aha->sim), accb->hccb.target, 1167122340Simp CAM_LUN_WILDCARD); 1168122363Simp 1169256887Smav if (error == CAM_REQ_CMP) { 117039225Sgibbs xpt_async(AC_SENT_BDR, path, NULL); 1171256887Smav xpt_free_path(path); 1172256887Smav } 117339225Sgibbs 117439225Sgibbs ccb_h = LIST_FIRST(&aha->pending_ccbs); 117539225Sgibbs while (ccb_h != NULL) { 117641047Sgibbs struct aha_ccb *pending_accb; 117739225Sgibbs 117841047Sgibbs pending_accb = (struct aha_ccb *)ccb_h->ccb_accb_ptr; 117941047Sgibbs if (pending_accb->hccb.target == accb->hccb.target) { 118041047Sgibbs pending_accb->hccb.ahastat = AHASTAT_HA_BDR; 118139225Sgibbs ccb_h = LIST_NEXT(ccb_h, sim_links.le); 118241047Sgibbs ahadone(aha, pending_accb, AMBI_ERROR); 118339225Sgibbs } else { 1184274819Ssmh callout_reset_sbt(&pending_accb->timer, 1185274819Ssmh SBT_1MS * ccb_h->timeout, 0, ahatimeout, 1186274819Ssmh pending_accb, 0); 118739225Sgibbs ccb_h = LIST_NEXT(ccb_h, sim_links.le); 118839225Sgibbs } 118939225Sgibbs } 1190122597Simp device_printf(aha->dev, "No longer in timeout\n"); 119139225Sgibbs return; 119239225Sgibbs } 119339225Sgibbs 1194241589Sjhb callout_stop(&accb->timer); 119539225Sgibbs 119639225Sgibbs switch (comp_code) { 119741047Sgibbs case AMBI_FREE: 1198122597Simp device_printf(aha->dev, 1199122597Simp "ahadone - CCB completed with free status!\n"); 120039225Sgibbs break; 120141047Sgibbs case AMBI_NOT_FOUND: 1202122597Simp device_printf(aha->dev, 1203122597Simp "ahadone - CCB Abort failed to find CCB\n"); 120439225Sgibbs break; 120541047Sgibbs case AMBI_ABORT: 120641047Sgibbs case AMBI_ERROR: 1207298955Spfg /* An error occurred */ 120842887Simp if (accb->hccb.opcode < INITIATOR_CCB_WRESID) 120942887Simp csio->resid = 0; 121042887Simp else 121142887Simp csio->resid = aha_a24tou(accb->hccb.data_len); 121241047Sgibbs switch(accb->hccb.ahastat) { 121339225Sgibbs case AHASTAT_DATARUN_ERROR: 121442013Sgibbs { 121542013Sgibbs if (csio->resid <= 0) { 121639225Sgibbs csio->ccb_h.status = CAM_DATA_RUN_ERR; 121739225Sgibbs break; 121839225Sgibbs } 121939225Sgibbs /* FALLTHROUGH */ 122042013Sgibbs } 122139225Sgibbs case AHASTAT_NOERROR: 122241047Sgibbs csio->scsi_status = accb->hccb.sdstat; 122339225Sgibbs csio->ccb_h.status |= CAM_SCSI_STATUS_ERROR; 122439225Sgibbs switch(csio->scsi_status) { 122539225Sgibbs case SCSI_STATUS_CHECK_COND: 122639225Sgibbs case SCSI_STATUS_CMD_TERMINATED: 122739225Sgibbs csio->ccb_h.status |= CAM_AUTOSNS_VALID; 122839225Sgibbs /* 122939225Sgibbs * The aha writes the sense data at different 123039225Sgibbs * offsets based on the scsi cmd len 123139225Sgibbs */ 123241047Sgibbs bcopy((caddr_t) &accb->hccb.scsi_cdb + 1233122363Simp accb->hccb.cmd_len, 1234122340Simp (caddr_t) &csio->sense_data, 1235122340Simp accb->hccb.sense_len); 123639225Sgibbs break; 123739225Sgibbs default: 123839225Sgibbs break; 123939225Sgibbs case SCSI_STATUS_OK: 124039225Sgibbs csio->ccb_h.status = CAM_REQ_CMP; 124139225Sgibbs break; 124239225Sgibbs } 124339225Sgibbs break; 124439225Sgibbs case AHASTAT_SELTIMEOUT: 124539225Sgibbs csio->ccb_h.status = CAM_SEL_TIMEOUT; 124639225Sgibbs break; 124739225Sgibbs case AHASTAT_UNEXPECTED_BUSFREE: 124839225Sgibbs csio->ccb_h.status = CAM_UNEXP_BUSFREE; 124939225Sgibbs break; 125039225Sgibbs case AHASTAT_INVALID_PHASE: 125139225Sgibbs csio->ccb_h.status = CAM_SEQUENCE_FAIL; 125239225Sgibbs break; 125339225Sgibbs case AHASTAT_INVALID_ACTION_CODE: 125439225Sgibbs panic("%s: Inavlid Action code", aha_name(aha)); 125539225Sgibbs break; 125639225Sgibbs case AHASTAT_INVALID_OPCODE: 125742887Simp if (accb->hccb.opcode < INITIATOR_CCB_WRESID) 125842887Simp panic("%s: Invalid CCB Opcode %x hccb = %p", 1259122340Simp aha_name(aha), accb->hccb.opcode, 1260122340Simp &accb->hccb); 1261122597Simp device_printf(aha->dev, 1262140025Simp "AHA-1540A compensation failed\n"); 126342887Simp xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 126442887Simp csio->ccb_h.status = CAM_REQUEUE_REQ; 126539225Sgibbs break; 126639225Sgibbs case AHASTAT_LINKED_CCB_LUN_MISMATCH: 126739225Sgibbs /* We don't even support linked commands... */ 126839225Sgibbs panic("%s: Linked CCB Lun Mismatch", aha_name(aha)); 126939225Sgibbs break; 127039225Sgibbs case AHASTAT_INVALID_CCB_OR_SG_PARAM: 127139225Sgibbs panic("%s: Invalid CCB or SG list", aha_name(aha)); 127239225Sgibbs break; 127339225Sgibbs case AHASTAT_HA_SCSI_BUS_RESET: 127439225Sgibbs if ((csio->ccb_h.status & CAM_STATUS_MASK) 127542887Simp != CAM_CMD_TIMEOUT) 127639225Sgibbs csio->ccb_h.status = CAM_SCSI_BUS_RESET; 127739225Sgibbs break; 127839225Sgibbs case AHASTAT_HA_BDR: 127941047Sgibbs if ((accb->flags & ACCB_DEVICE_RESET) == 0) 128039225Sgibbs csio->ccb_h.status = CAM_BDR_SENT; 128139225Sgibbs else 128239225Sgibbs csio->ccb_h.status = CAM_CMD_TIMEOUT; 128339225Sgibbs break; 128439225Sgibbs } 128539225Sgibbs if (csio->ccb_h.status != CAM_REQ_CMP) { 128639225Sgibbs xpt_freeze_devq(csio->ccb_h.path, /*count*/1); 128739225Sgibbs csio->ccb_h.status |= CAM_DEV_QFRZN; 128839225Sgibbs } 128941047Sgibbs if ((accb->flags & ACCB_RELEASE_SIMQ) != 0) 129039225Sgibbs ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 129141047Sgibbs ahafreeccb(aha, accb); 129239225Sgibbs xpt_done(ccb); 129339225Sgibbs break; 129441047Sgibbs case AMBI_OK: 129539225Sgibbs /* All completed without incident */ 129639225Sgibbs /* XXX DO WE NEED TO COPY SENSE BYTES HERE???? XXX */ 129742887Simp /* I don't think so since it works???? */ 129839225Sgibbs ccb->ccb_h.status |= CAM_REQ_CMP; 129941047Sgibbs if ((accb->flags & ACCB_RELEASE_SIMQ) != 0) 130039225Sgibbs ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 130141047Sgibbs ahafreeccb(aha, accb); 130239225Sgibbs xpt_done(ccb); 130339225Sgibbs break; 130439225Sgibbs } 130539225Sgibbs} 130639225Sgibbs 130739225Sgibbsstatic int 130839225Sgibbsahareset(struct aha_softc* aha, int hard_reset) 130939225Sgibbs{ 131039225Sgibbs struct ccb_hdr *ccb_h; 131139225Sgibbs u_int status; 131239225Sgibbs u_int timeout; 1313122340Simp uint8_t reset_type; 131439225Sgibbs 131539225Sgibbs if (hard_reset != 0) 131639225Sgibbs reset_type = HARD_RESET; 131739225Sgibbs else 131839225Sgibbs reset_type = SOFT_RESET; 131939225Sgibbs aha_outb(aha, CONTROL_REG, reset_type); 132039225Sgibbs 132139225Sgibbs /* Wait 5sec. for Diagnostic start */ 132239225Sgibbs timeout = 5 * 10000; 132339225Sgibbs while (--timeout) { 132439225Sgibbs status = aha_inb(aha, STATUS_REG); 132539225Sgibbs if ((status & DIAG_ACTIVE) != 0) 132639225Sgibbs break; 132739225Sgibbs DELAY(100); 132839225Sgibbs } 132939225Sgibbs if (timeout == 0) { 1330122597Simp PRVERB((aha->dev, "ahareset - Diagnostic Active failed to " 1331122597Simp "assert. status = %#x\n", status)); 133239225Sgibbs return (ETIMEDOUT); 133339225Sgibbs } 133439225Sgibbs 133539225Sgibbs /* Wait 10sec. for Diagnostic end */ 133639225Sgibbs timeout = 10 * 10000; 133739225Sgibbs while (--timeout) { 133839225Sgibbs status = aha_inb(aha, STATUS_REG); 133939225Sgibbs if ((status & DIAG_ACTIVE) == 0) 134039225Sgibbs break; 134139225Sgibbs DELAY(100); 134239225Sgibbs } 134339225Sgibbs if (timeout == 0) { 134439225Sgibbs panic("%s: ahareset - Diagnostic Active failed to drop. " 1345122340Simp "status = 0x%x\n", aha_name(aha), status); 134639225Sgibbs return (ETIMEDOUT); 134739225Sgibbs } 134839225Sgibbs 134939225Sgibbs /* Wait for the host adapter to become ready or report a failure */ 135039225Sgibbs timeout = 10000; 135139225Sgibbs while (--timeout) { 135239225Sgibbs status = aha_inb(aha, STATUS_REG); 135339225Sgibbs if ((status & (DIAG_FAIL|HA_READY|DATAIN_REG_READY)) != 0) 135439225Sgibbs break; 135539225Sgibbs DELAY(100); 135639225Sgibbs } 135739225Sgibbs if (timeout == 0) { 1358122597Simp device_printf(aha->dev, "ahareset - Host adapter failed to " 1359122597Simp "come ready. status = 0x%x\n", status); 136039225Sgibbs return (ETIMEDOUT); 136139225Sgibbs } 136239225Sgibbs 136339225Sgibbs /* If the diagnostics failed, tell the user */ 136439225Sgibbs if ((status & DIAG_FAIL) != 0 136539225Sgibbs || (status & HA_READY) == 0) { 1366122597Simp device_printf(aha->dev, "ahareset - Adapter failed diag\n"); 136739225Sgibbs 136839225Sgibbs if ((status & DATAIN_REG_READY) != 0) 1369122597Simp device_printf(aha->dev, "ahareset - Host Adapter " 1370122597Simp "Error code = 0x%x\n", aha_inb(aha, DATAIN_REG)); 137139225Sgibbs return (ENXIO); 137239225Sgibbs } 137339225Sgibbs 137439225Sgibbs /* If we've attached to the XPT, tell it about the event */ 137539225Sgibbs if (aha->path != NULL) 137639225Sgibbs xpt_async(AC_BUS_RESET, aha->path, NULL); 137739225Sgibbs 137839225Sgibbs /* 137939225Sgibbs * Perform completion processing for all outstanding CCBs. 138039225Sgibbs */ 138139225Sgibbs while ((ccb_h = LIST_FIRST(&aha->pending_ccbs)) != NULL) { 138241047Sgibbs struct aha_ccb *pending_accb; 138339225Sgibbs 138441047Sgibbs pending_accb = (struct aha_ccb *)ccb_h->ccb_accb_ptr; 138541047Sgibbs pending_accb->hccb.ahastat = AHASTAT_HA_SCSI_BUS_RESET; 138641047Sgibbs ahadone(aha, pending_accb, AMBI_ERROR); 138739225Sgibbs } 138839225Sgibbs 1389122360Simp /* If we've allocated mailboxes, initialize them */ 1390122360Simp /* Must be done after we've aborted our queue, or aha_cmd fails */ 1391122360Simp if (aha->init_level > 4) 1392122360Simp ahainitmboxes(aha); 1393122360Simp 139439225Sgibbs return (0); 139539225Sgibbs} 139639225Sgibbs 139739225Sgibbs/* 139839225Sgibbs * Send a command to the adapter. 139939225Sgibbs */ 140039225Sgibbsint 1401122363Simpaha_cmd(struct aha_softc *aha, aha_op_t opcode, uint8_t *params, 1402122363Simp u_int param_len, uint8_t *reply_data, u_int reply_len, 140347506Sgibbs u_int cmd_timeout) 140439225Sgibbs{ 140539225Sgibbs u_int timeout; 140639225Sgibbs u_int status; 140747506Sgibbs u_int saved_status; 140839225Sgibbs u_int intstat; 140939225Sgibbs u_int reply_buf_size; 141041709Sgibbs int cmd_complete; 141147506Sgibbs int error; 141239225Sgibbs 141339225Sgibbs /* No data returned to start */ 141439225Sgibbs reply_buf_size = reply_len; 141539225Sgibbs reply_len = 0; 141639225Sgibbs intstat = 0; 141741709Sgibbs cmd_complete = 0; 141847506Sgibbs saved_status = 0; 141947506Sgibbs error = 0; 142039225Sgibbs 142147506Sgibbs /* 142247506Sgibbs * All commands except for the "start mailbox" and the "enable 142347506Sgibbs * outgoing mailbox read interrupt" commands cannot be issued 142447506Sgibbs * while there are pending transactions. Freeze our SIMQ 142547506Sgibbs * and wait for all completions to occur if necessary. 142647506Sgibbs */ 1427122360Simp timeout = 10000; 142847506Sgibbs while (LIST_FIRST(&aha->pending_ccbs) != NULL && --timeout) { 142947506Sgibbs /* Fire the interrupt handler in case interrupts are blocked */ 143047506Sgibbs aha_intr(aha); 1431122360Simp DELAY(10); 143247506Sgibbs } 143347506Sgibbs 143447506Sgibbs if (timeout == 0) { 1435122597Simp device_printf(aha->dev, 1436122597Simp "aha_cmd: Timeout waiting for adapter idle\n"); 143747506Sgibbs return (ETIMEDOUT); 143847506Sgibbs } 143939225Sgibbs aha->command_cmp = 0; 144039225Sgibbs /* 144147506Sgibbs * Wait up to 10 sec. for the adapter to become 144239225Sgibbs * ready to accept commands. 144339225Sgibbs */ 144447506Sgibbs timeout = 100000; 144539225Sgibbs while (--timeout) { 144639225Sgibbs status = aha_inb(aha, STATUS_REG); 1447122340Simp if ((status & HA_READY) != 0 && (status & CMD_REG_BUSY) == 0) 144839225Sgibbs break; 144947506Sgibbs /* 145047506Sgibbs * Throw away any pending data which may be 145147506Sgibbs * left over from earlier commands that we 145247506Sgibbs * timedout on. 145347506Sgibbs */ 145447506Sgibbs if ((status & DATAIN_REG_READY) != 0) 145547506Sgibbs (void)aha_inb(aha, DATAIN_REG); 145639225Sgibbs DELAY(100); 145739225Sgibbs } 145839225Sgibbs if (timeout == 0) { 1459122597Simp device_printf(aha->dev, "aha_cmd: Timeout waiting for adapter" 1460122597Simp " ready, status = 0x%x\n", status); 146139225Sgibbs return (ETIMEDOUT); 146239225Sgibbs } 146339225Sgibbs 146439225Sgibbs /* 146539225Sgibbs * Send the opcode followed by any necessary parameter bytes. 146639225Sgibbs */ 146739225Sgibbs aha_outb(aha, COMMAND_REG, opcode); 146839225Sgibbs 146939225Sgibbs /* 147039225Sgibbs * Wait for up to 1sec to get the parameter list sent 147139225Sgibbs */ 147239225Sgibbs timeout = 10000; 147339225Sgibbs while (param_len && --timeout) { 147439225Sgibbs DELAY(100); 147539225Sgibbs status = aha_inb(aha, STATUS_REG); 147639225Sgibbs intstat = aha_inb(aha, INTSTAT_REG); 147747506Sgibbs 147839225Sgibbs if ((intstat & (INTR_PENDING|CMD_COMPLETE)) 147941709Sgibbs == (INTR_PENDING|CMD_COMPLETE)) { 148047506Sgibbs saved_status = status; 148141709Sgibbs cmd_complete = 1; 148239225Sgibbs break; 148341709Sgibbs } 148447506Sgibbs 148539225Sgibbs if (aha->command_cmp != 0) { 148647506Sgibbs saved_status = aha->latched_status; 148741709Sgibbs cmd_complete = 1; 148839225Sgibbs break; 148939225Sgibbs } 149039225Sgibbs if ((status & DATAIN_REG_READY) != 0) 149139225Sgibbs break; 149239225Sgibbs if ((status & CMD_REG_BUSY) == 0) { 149339225Sgibbs aha_outb(aha, COMMAND_REG, *params++); 149439225Sgibbs param_len--; 149547506Sgibbs timeout = 10000; 149639225Sgibbs } 149739225Sgibbs } 149839225Sgibbs if (timeout == 0) { 1499122597Simp device_printf(aha->dev, "aha_cmd: Timeout sending parameters, " 1500122597Simp "status = 0x%x\n", status); 150147506Sgibbs error = ETIMEDOUT; 150239225Sgibbs } 150339225Sgibbs 150439225Sgibbs /* 150539225Sgibbs * For all other commands, we wait for any output data 150639225Sgibbs * and the final comand completion interrupt. 150739225Sgibbs */ 150841709Sgibbs while (cmd_complete == 0 && --cmd_timeout) { 150939225Sgibbs 151039225Sgibbs status = aha_inb(aha, STATUS_REG); 151139225Sgibbs intstat = aha_inb(aha, INTSTAT_REG); 151239225Sgibbs 151339225Sgibbs if (aha->command_cmp != 0) { 151447506Sgibbs cmd_complete = 1; 151547506Sgibbs saved_status = aha->latched_status; 151647506Sgibbs } else if ((intstat & (INTR_PENDING|CMD_COMPLETE)) 151747506Sgibbs == (INTR_PENDING|CMD_COMPLETE)) { 151847506Sgibbs /* 151947506Sgibbs * Our poll (in case interrupts are blocked) 152047506Sgibbs * saw the CMD_COMPLETE interrupt. 152147506Sgibbs */ 152247506Sgibbs cmd_complete = 1; 152347506Sgibbs saved_status = status; 152451869Smdodd } 152551869Smdodd if ((status & DATAIN_REG_READY) != 0) { 1526122340Simp uint8_t data; 152739225Sgibbs 152839225Sgibbs data = aha_inb(aha, DATAIN_REG); 152939225Sgibbs if (reply_len < reply_buf_size) { 153039225Sgibbs *reply_data++ = data; 153139225Sgibbs } else { 1532122597Simp device_printf(aha->dev, 1533122597Simp "aha_cmd - Discarded reply data " 1534122597Simp "byte for opcode 0x%x\n", opcode); 153539225Sgibbs } 153647506Sgibbs /* 153747506Sgibbs * Reset timeout to ensure at least a second 153847506Sgibbs * between response bytes. 153947506Sgibbs */ 154047506Sgibbs cmd_timeout = MAX(cmd_timeout, 10000); 154139225Sgibbs reply_len++; 154239225Sgibbs } 154339225Sgibbs DELAY(100); 154439225Sgibbs } 154547506Sgibbs if (cmd_timeout == 0) { 1546122597Simp device_printf(aha->dev, "aha_cmd: Timeout: status = 0x%x, " 1547122597Simp "intstat = 0x%x, reply_len = %d\n", status, intstat, 1548122597Simp reply_len); 154939225Sgibbs return (ETIMEDOUT); 155039225Sgibbs } 155139225Sgibbs 155239225Sgibbs /* 155339225Sgibbs * Clear any pending interrupts. Block interrupts so our 155439225Sgibbs * interrupt handler is not re-entered. 155539225Sgibbs */ 155639225Sgibbs aha_intr(aha); 1557122363Simp 155847506Sgibbs if (error != 0) 155947506Sgibbs return (error); 156047506Sgibbs 156139225Sgibbs /* 156239225Sgibbs * If the command was rejected by the controller, tell the caller. 156339225Sgibbs */ 156447506Sgibbs if ((saved_status & CMD_INVALID) != 0) { 1565122597Simp PRVERB((aha->dev, "Invalid Command 0x%x\n", opcode)); 156639225Sgibbs /* 156739225Sgibbs * Some early adapters may not recover properly from 156839225Sgibbs * an invalid command. If it appears that the controller 156939225Sgibbs * has wedged (i.e. status was not cleared by our interrupt 157039225Sgibbs * reset above), perform a soft reset. 157139225Sgibbs */ 157239225Sgibbs DELAY(1000); 157339225Sgibbs status = aha_inb(aha, STATUS_REG); 157439225Sgibbs if ((status & (CMD_INVALID|STATUS_REG_RSVD|DATAIN_REG_READY| 157539225Sgibbs CMD_REG_BUSY|DIAG_FAIL|DIAG_ACTIVE)) != 0 157639225Sgibbs || (status & (HA_READY|INIT_REQUIRED)) 1577122340Simp != (HA_READY|INIT_REQUIRED)) 157839852Simp ahareset(aha, /*hard_reset*/FALSE); 157939225Sgibbs return (EINVAL); 158039225Sgibbs } 158139225Sgibbs 158239225Sgibbs if (param_len > 0) { 158339225Sgibbs /* The controller did not accept the full argument list */ 1584122597Simp PRVERB((aha->dev, "Controller did not accept full argument " 1585122597Simp "list (%d > 0)\n", param_len)); 158639225Sgibbs return (E2BIG); 158739225Sgibbs } 158839225Sgibbs 158939225Sgibbs if (reply_len != reply_buf_size) { 159039225Sgibbs /* Too much or too little data received */ 1591122597Simp PRVERB((aha->dev, "data received mismatch (%d != %d)\n", 1592122597Simp reply_len, reply_buf_size)); 159339225Sgibbs return (EMSGSIZE); 159439225Sgibbs } 159539225Sgibbs 159639225Sgibbs /* We were successful */ 159739225Sgibbs return (0); 159839225Sgibbs} 159939225Sgibbs 160039225Sgibbsstatic int 1601122363Simpahainitmboxes(struct aha_softc *aha) 160239225Sgibbs{ 160339225Sgibbs int error; 160439225Sgibbs init_24b_mbox_params_t init_mbox; 160539225Sgibbs 160639225Sgibbs bzero(aha->in_boxes, sizeof(aha_mbox_in_t) * aha->num_boxes); 160739225Sgibbs bzero(aha->out_boxes, sizeof(aha_mbox_out_t) * aha->num_boxes); 160839225Sgibbs aha->cur_inbox = aha->in_boxes; 160939225Sgibbs aha->last_inbox = aha->in_boxes + aha->num_boxes - 1; 161039225Sgibbs aha->cur_outbox = aha->out_boxes; 161139225Sgibbs aha->last_outbox = aha->out_boxes + aha->num_boxes - 1; 161239225Sgibbs 161339225Sgibbs /* Tell the adapter about them */ 161439225Sgibbs init_mbox.num_mboxes = aha->num_boxes; 161539225Sgibbs ahautoa24(aha->mailbox_physbase, init_mbox.base_addr); 1616122340Simp error = aha_cmd(aha, AOP_INITIALIZE_MBOX, (uint8_t *)&init_mbox, 1617122340Simp /*parmlen*/sizeof(init_mbox), /*reply_buf*/NULL, 1618122340Simp /*reply_len*/0, DEFAULT_CMD_TIMEOUT); 161939225Sgibbs 162039225Sgibbs if (error != 0) 162139225Sgibbs printf("ahainitmboxes: Initialization command failed\n"); 162239225Sgibbs return (error); 162339225Sgibbs} 162439225Sgibbs 162539225Sgibbs/* 162639225Sgibbs * Update the XPT's idea of the negotiated transfer 162739225Sgibbs * parameters for a particular target. 162839225Sgibbs */ 162939225Sgibbsstatic void 163039225Sgibbsahafetchtransinfo(struct aha_softc *aha, struct ccb_trans_settings* cts) 163139225Sgibbs{ 163239225Sgibbs setup_data_t setup_info; 163339225Sgibbs u_int target; 163439225Sgibbs u_int targ_offset; 163539225Sgibbs u_int sync_period; 163639225Sgibbs int error; 1637122340Simp uint8_t param; 163839225Sgibbs targ_syncinfo_t sync_info; 1639163816Smjacob struct ccb_trans_settings_spi *spi = &cts->xport_specific.spi; 164039225Sgibbs 164139225Sgibbs target = cts->ccb_h.target_id; 164239225Sgibbs targ_offset = (target & 0x7); 164339225Sgibbs 164439225Sgibbs /* 164547208Simp * Inquire Setup Information. This command retreives 164647506Sgibbs * the sync info for older models. 164739225Sgibbs */ 164839225Sgibbs param = sizeof(setup_info); 164941047Sgibbs error = aha_cmd(aha, AOP_INQUIRE_SETUP_INFO, ¶m, /*paramlen*/1, 1650122340Simp (uint8_t*)&setup_info, sizeof(setup_info), DEFAULT_CMD_TIMEOUT); 165139225Sgibbs 165239225Sgibbs if (error != 0) { 1653122597Simp device_printf(aha->dev, 1654122597Simp "ahafetchtransinfo - Inquire Setup Info Failed %d\n", 1655122597Simp error); 165639225Sgibbs return; 165739225Sgibbs } 165839225Sgibbs 165939225Sgibbs sync_info = setup_info.syncinfo[targ_offset]; 166039225Sgibbs 166139225Sgibbs if (sync_info.sync == 0) 1662163816Smjacob spi->sync_offset = 0; 1663163816Smjacob else 1664163816Smjacob spi->sync_offset = sync_info.offset; 1665163816Smjacob 1666163816Smjacob spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 1667163816Smjacob 1668163816Smjacob if (aha->boardid >= BOARD_1542CF) 1669163816Smjacob sync_period = 1000; 1670163816Smjacob else 1671163816Smjacob sync_period = 2000; 1672163816Smjacob sync_period += 500 * sync_info.period; 1673163816Smjacob 1674163816Smjacob /* Convert ns value to standard SCSI sync rate */ 1675163816Smjacob if (spi->sync_offset != 0) 1676163816Smjacob spi->sync_period = scsi_calc_syncparam(sync_period); 1677163816Smjacob else 1678163816Smjacob spi->sync_period = 0; 1679163816Smjacob 1680163816Smjacob spi->valid = CTS_SPI_VALID_SYNC_RATE 1681163816Smjacob | CTS_SPI_VALID_SYNC_OFFSET 1682163816Smjacob | CTS_SPI_VALID_BUS_WIDTH; 168339225Sgibbs xpt_async(AC_TRANSFER_NEG, cts->ccb_h.path, cts); 168439225Sgibbs} 168539225Sgibbs 168639225Sgibbsstatic void 168739225Sgibbsahamapmboxes(void *arg, bus_dma_segment_t *segs, int nseg, int error) 168839225Sgibbs{ 168939225Sgibbs struct aha_softc* aha; 169039225Sgibbs 169139225Sgibbs aha = (struct aha_softc*)arg; 169239225Sgibbs aha->mailbox_physbase = segs->ds_addr; 169339225Sgibbs} 169439225Sgibbs 169539225Sgibbsstatic void 169639225Sgibbsahamapccbs(void *arg, bus_dma_segment_t *segs, int nseg, int error) 169739225Sgibbs{ 169839225Sgibbs struct aha_softc* aha; 169939225Sgibbs 170039225Sgibbs aha = (struct aha_softc*)arg; 170139225Sgibbs aha->aha_ccb_physbase = segs->ds_addr; 170239225Sgibbs} 170339225Sgibbs 170439225Sgibbsstatic void 170539225Sgibbsahamapsgs(void *arg, bus_dma_segment_t *segs, int nseg, int error) 170639225Sgibbs{ 170739225Sgibbs 170839225Sgibbs struct aha_softc* aha; 170939225Sgibbs 171039225Sgibbs aha = (struct aha_softc*)arg; 171139225Sgibbs SLIST_FIRST(&aha->sg_maps)->sg_physaddr = segs->ds_addr; 171239225Sgibbs} 171339225Sgibbs 171439225Sgibbsstatic void 171539225Sgibbsahapoll(struct cam_sim *sim) 171639225Sgibbs{ 1717241589Sjhb aha_intr_locked(cam_sim_softc(sim)); 171839225Sgibbs} 171939225Sgibbs 172045575Seivindstatic void 172139225Sgibbsahatimeout(void *arg) 172239225Sgibbs{ 172341047Sgibbs struct aha_ccb *accb; 172439225Sgibbs union ccb *ccb; 172539225Sgibbs struct aha_softc *aha; 1726122340Simp uint32_t paddr; 1727122360Simp struct ccb_hdr *ccb_h; 172839225Sgibbs 172941047Sgibbs accb = (struct aha_ccb *)arg; 173041047Sgibbs ccb = accb->ccb; 173139225Sgibbs aha = (struct aha_softc *)ccb->ccb_h.ccb_aha_ptr; 1732241589Sjhb mtx_assert(&aha->lock, MA_OWNED); 173339225Sgibbs xpt_print_path(ccb->ccb_h.path); 173441047Sgibbs printf("CCB %p - timed out\n", (void *)accb); 173539225Sgibbs 173641047Sgibbs if ((accb->flags & ACCB_ACTIVE) == 0) { 173739225Sgibbs xpt_print_path(ccb->ccb_h.path); 173839390Sgibbs printf("CCB %p - timed out CCB already completed\n", 1739122340Simp (void *)accb); 174039225Sgibbs return; 174139225Sgibbs } 174239225Sgibbs 174339225Sgibbs /* 174439225Sgibbs * In order to simplify the recovery process, we ask the XPT 174539225Sgibbs * layer to halt the queue of new transactions and we traverse 174639225Sgibbs * the list of pending CCBs and remove their timeouts. This 174739225Sgibbs * means that the driver attempts to clear only one error 174839225Sgibbs * condition at a time. In general, timeouts that occur 174939225Sgibbs * close together are related anyway, so there is no benefit 1750298955Spfg * in attempting to handle errors in parallel. Timeouts will 175139225Sgibbs * be reinstated when the recovery process ends. 175239225Sgibbs */ 175341047Sgibbs if ((accb->flags & ACCB_DEVICE_RESET) == 0) { 175441047Sgibbs if ((accb->flags & ACCB_RELEASE_SIMQ) == 0) { 175539225Sgibbs xpt_freeze_simq(aha->sim, /*count*/1); 175641047Sgibbs accb->flags |= ACCB_RELEASE_SIMQ; 175739225Sgibbs } 175839225Sgibbs 175939225Sgibbs ccb_h = LIST_FIRST(&aha->pending_ccbs); 176039225Sgibbs while (ccb_h != NULL) { 176141047Sgibbs struct aha_ccb *pending_accb; 176239225Sgibbs 176341047Sgibbs pending_accb = (struct aha_ccb *)ccb_h->ccb_accb_ptr; 1764241589Sjhb callout_stop(&pending_accb->timer); 176539225Sgibbs ccb_h = LIST_NEXT(ccb_h, sim_links.le); 176639225Sgibbs } 176739225Sgibbs } 176839225Sgibbs 176941047Sgibbs if ((accb->flags & ACCB_DEVICE_RESET) != 0 177041047Sgibbs || aha->cur_outbox->action_code != AMBO_FREE) { 177139225Sgibbs /* 177239225Sgibbs * Try a full host adapter/SCSI bus reset. 177339225Sgibbs * We do this only if we have already attempted 177439225Sgibbs * to clear the condition with a BDR, or we cannot 177539225Sgibbs * attempt a BDR for lack of mailbox resources. 177639225Sgibbs */ 177739225Sgibbs ccb->ccb_h.status = CAM_CMD_TIMEOUT; 177839225Sgibbs ahareset(aha, /*hardreset*/TRUE); 1779122597Simp device_printf(aha->dev, "No longer in timeout\n"); 178039225Sgibbs } else { 1781122363Simp /* 178239225Sgibbs * Send a Bus Device Reset message: 178339225Sgibbs * The target that is holding up the bus may not 178439225Sgibbs * be the same as the one that triggered this timeout 178539225Sgibbs * (different commands have different timeout lengths), 178639225Sgibbs * but we have no way of determining this from our 178739225Sgibbs * timeout handler. Our strategy here is to queue a 178839225Sgibbs * BDR message to the target of the timed out command. 178939225Sgibbs * If this fails, we'll get another timeout 2 seconds 179039225Sgibbs * later which will attempt a bus reset. 179139225Sgibbs */ 179241047Sgibbs accb->flags |= ACCB_DEVICE_RESET; 1793241603Sglebius callout_reset(&accb->timer, 2 * hz, ahatimeout, accb); 179441047Sgibbs aha->recovery_accb->hccb.opcode = INITIATOR_BUS_DEV_RESET; 179539225Sgibbs 179639225Sgibbs /* No Data Transfer */ 179741047Sgibbs aha->recovery_accb->hccb.datain = TRUE; 179841047Sgibbs aha->recovery_accb->hccb.dataout = TRUE; 179941047Sgibbs aha->recovery_accb->hccb.ahastat = 0; 180041047Sgibbs aha->recovery_accb->hccb.sdstat = 0; 180141047Sgibbs aha->recovery_accb->hccb.target = ccb->ccb_h.target_id; 180239225Sgibbs 180339225Sgibbs /* Tell the adapter about this command */ 180441047Sgibbs paddr = ahaccbvtop(aha, aha->recovery_accb); 180539225Sgibbs ahautoa24(paddr, aha->cur_outbox->ccb_addr); 180641047Sgibbs aha->cur_outbox->action_code = AMBO_START; 180741047Sgibbs aha_outb(aha, COMMAND_REG, AOP_START_MBOX); 180839225Sgibbs ahanextoutbox(aha); 180939225Sgibbs } 181039225Sgibbs} 181156504Simp 181256504Simpint 181356504Simpaha_detach(struct aha_softc *aha) 181456504Simp{ 1815241589Sjhb mtx_lock(&aha->lock); 181656504Simp xpt_async(AC_LOST_DEVICE, aha->path, NULL); 181756504Simp xpt_free_path(aha->path); 181856504Simp xpt_bus_deregister(cam_sim_path(aha->sim)); 181956504Simp cam_sim_free(aha->sim, /*free_devq*/TRUE); 1820241589Sjhb mtx_unlock(&aha->lock); 1821241589Sjhb /* XXX: Drain all timers? */ 182256504Simp return (0); 182356504Simp} 1824165102SmjacobMODULE_DEPEND(aha, cam, 1, 1, 1); 1825