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$"); 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); 212266089Sian bus_dmamap_destroy(aha->ccb_dmat, aha->ccb_dmamap); 21339225Sgibbs case 5: 21439225Sgibbs bus_dma_tag_destroy(aha->ccb_dmat); 21539225Sgibbs case 4: 21639225Sgibbs bus_dmamap_unload(aha->mailbox_dmat, aha->mailbox_dmamap); 21739225Sgibbs case 3: 21839225Sgibbs bus_dmamem_free(aha->mailbox_dmat, aha->in_boxes, 219122340Simp aha->mailbox_dmamap); 22039225Sgibbs bus_dmamap_destroy(aha->mailbox_dmat, aha->mailbox_dmamap); 22139225Sgibbs case 2: 22239225Sgibbs bus_dma_tag_destroy(aha->buffer_dmat); 22339225Sgibbs case 1: 22439225Sgibbs bus_dma_tag_destroy(aha->mailbox_dmat); 22539225Sgibbs case 0: 22697208Speter break; 22739225Sgibbs } 228241589Sjhb mtx_destroy(&aha->lock); 22939225Sgibbs} 23039225Sgibbs 23139225Sgibbs/* 23239225Sgibbs * Probe the adapter and verify that the card is an Adaptec. 23339225Sgibbs */ 23439225Sgibbsint 23539225Sgibbsaha_probe(struct aha_softc* aha) 23639225Sgibbs{ 23739225Sgibbs u_int status; 23839225Sgibbs u_int intstat; 23939225Sgibbs int error; 24039852Simp board_id_data_t board_id; 24139225Sgibbs 24239225Sgibbs /* 24339225Sgibbs * See if the three I/O ports look reasonable. 24439225Sgibbs * Touch the minimal number of registers in the 24539225Sgibbs * failure case. 24639225Sgibbs */ 24739225Sgibbs status = aha_inb(aha, STATUS_REG); 248122340Simp if ((status == 0) || 249122340Simp (status & (DIAG_ACTIVE|CMD_REG_BUSY | STATUS_REG_RSVD)) != 0) { 250122597Simp PRVERB((aha->dev, "status reg test failed %x\n", status)); 25139225Sgibbs return (ENXIO); 25239225Sgibbs } 25339225Sgibbs 25439225Sgibbs intstat = aha_inb(aha, INTSTAT_REG); 25539225Sgibbs if ((intstat & INTSTAT_REG_RSVD) != 0) { 256122597Simp PRVERB((aha->dev, "Failed Intstat Reg Test\n")); 25739225Sgibbs return (ENXIO); 25839225Sgibbs } 25939225Sgibbs 26039225Sgibbs /* 26141047Sgibbs * Looking good so far. Final test is to reset the 26241047Sgibbs * adapter and fetch the board ID and ensure we aren't 26341047Sgibbs * looking at a BusLogic. 26441047Sgibbs */ 26541047Sgibbs if ((error = ahareset(aha, /*hard_reset*/TRUE)) != 0) { 266122597Simp PRVERB((aha->dev, "Failed Reset\n")); 26741047Sgibbs return (ENXIO); 26841047Sgibbs } 26941047Sgibbs 27041047Sgibbs /* 27139852Simp * Get the board ID. We use this to see if we're dealing with 272108533Sschweikh * a buslogic card or an aha card (or clone). 27339225Sgibbs */ 27441047Sgibbs error = aha_cmd(aha, AOP_INQUIRE_BOARD_ID, NULL, /*parmlen*/0, 275122340Simp (uint8_t*)&board_id, sizeof(board_id), DEFAULT_CMD_TIMEOUT); 27639852Simp if (error != 0) { 277122597Simp PRVERB((aha->dev, "INQUIRE failed %x\n", error)); 27839225Sgibbs return (ENXIO); 27939225Sgibbs } 28039852Simp aha->fw_major = board_id.firmware_rev_major; 28139852Simp aha->fw_minor = board_id.firmware_rev_minor; 28239852Simp aha->boardid = board_id.board_type; 28339852Simp 28439225Sgibbs /* 28539852Simp * The Buslogic cards have an id of either 0x41 or 0x42. So 28639852Simp * if those come up in the probe, we test the geometry register 28739852Simp * of the board. Adaptec boards that are this old will not have 28839852Simp * this register, and return 0xff, while buslogic cards will return 28939852Simp * something different. 29039852Simp * 29141335Simp * It appears that for reasons unknow, for the for the 29241335Simp * aha-1542B cards, we need to wait a little bit before trying 29341335Simp * to read the geometry register. I picked 10ms since we have 29441335Simp * reports that a for loop to 1000 did the trick, and this 29541335Simp * errs on the side of conservatism. Besides, no one will 29641335Simp * notice a 10mS delay here, even the 1542B card users :-) 29741335Simp * 29846997Simp * Some compatible cards return 0 here. Some cards also 29946997Simp * seem to return 0x7f. 30041807Simp * 301122363Simp * XXX I'm not sure how this will impact other cloned cards 30241807Simp * 30341807Simp * This really should be replaced with the esetup command, since 30446997Simp * that appears to be more reliable. This becomes more and more 30546997Simp * true over time as we discover more cards that don't read the 30646997Simp * geometry register consistantly. 30739225Sgibbs */ 30839852Simp if (aha->boardid <= 0x42) { 30941335Simp /* Wait 10ms before reading */ 31041335Simp DELAY(10000); 31139852Simp status = aha_inb(aha, GEOMETRY_REG); 31246997Simp if (status != 0xff && status != 0x00 && status != 0x7f) { 313122597Simp PRVERB((aha->dev, "Geometry Register test failed %#x\n", 314122597Simp status)); 31539852Simp return (ENXIO); 31641047Sgibbs } 31739751Simp } 318122363Simp 31939225Sgibbs return (0); 32039225Sgibbs} 32139225Sgibbs 32239225Sgibbs/* 32339225Sgibbs * Pull the boards setup information and record it in our softc. 32439225Sgibbs */ 32539225Sgibbsint 32639225Sgibbsaha_fetch_adapter_info(struct aha_softc *aha) 32739225Sgibbs{ 32839225Sgibbs setup_data_t setup_info; 32939225Sgibbs config_data_t config_data; 330122340Simp uint8_t length_param; 33139225Sgibbs int error; 33239751Simp struct aha_extbios extbios; 333122363Simp 33439852Simp switch (aha->boardid) { 33539225Sgibbs case BOARD_1540_16HEAD_BIOS: 33641514Sarchie snprintf(aha->model, sizeof(aha->model), "1540 16 head BIOS"); 33739225Sgibbs break; 33839225Sgibbs case BOARD_1540_64HEAD_BIOS: 33941514Sarchie snprintf(aha->model, sizeof(aha->model), "1540 64 head BIOS"); 34039225Sgibbs break; 34139225Sgibbs case BOARD_1542: 34241514Sarchie snprintf(aha->model, sizeof(aha->model), "1540/1542 64 head BIOS"); 34339225Sgibbs break; 34439225Sgibbs case BOARD_1640: 34541514Sarchie snprintf(aha->model, sizeof(aha->model), "1640"); 34639225Sgibbs break; 34739225Sgibbs case BOARD_1740: 34841514Sarchie snprintf(aha->model, sizeof(aha->model), "1740A/1742A/1744"); 34939225Sgibbs break; 35039225Sgibbs case BOARD_1542C: 35141514Sarchie snprintf(aha->model, sizeof(aha->model), "1542C"); 35239225Sgibbs break; 35339225Sgibbs case BOARD_1542CF: 35441514Sarchie snprintf(aha->model, sizeof(aha->model), "1542CF"); 35539225Sgibbs break; 35639225Sgibbs case BOARD_1542CP: 35741514Sarchie snprintf(aha->model, sizeof(aha->model), "1542CP"); 35839225Sgibbs break; 35939225Sgibbs default: 36041514Sarchie snprintf(aha->model, sizeof(aha->model), "Unknown"); 36139225Sgibbs break; 36239225Sgibbs } 36339751Simp /* 36439751Simp * If we are a new type of 1542 board (anything newer than a 1542C) 36539751Simp * then disable the extended bios so that the 36639751Simp * mailbox interface is unlocked. 36739751Simp * This is also true for the 1542B Version 3.20. First Adaptec 36839751Simp * board that supports >1Gb drives. 36939751Simp * No need to check the extended bios flags as some of the 37039751Simp * extensions that cause us problems are not flagged in that byte. 37139751Simp */ 37239751Simp if (PROBABLY_NEW_BOARD(aha->boardid) || 37339751Simp (aha->boardid == 0x41 374122363Simp && aha->fw_major == 0x31 && 37539852Simp aha->fw_minor >= 0x34)) { 37641047Sgibbs error = aha_cmd(aha, AOP_RETURN_EXT_BIOS_INFO, NULL, 377122340Simp /*paramlen*/0, (u_char *)&extbios, sizeof(extbios), 378122340Simp DEFAULT_CMD_TIMEOUT); 379122360Simp if (error != 0) { 380122597Simp device_printf(aha->dev, 381122597Simp "AOP_RETURN_EXT_BIOS_INFO - Failed."); 382122360Simp return (error); 383122360Simp } 384122340Simp error = aha_cmd(aha, AOP_MBOX_IF_ENABLE, (uint8_t *)&extbios, 385122340Simp /*paramlen*/2, NULL, 0, DEFAULT_CMD_TIMEOUT); 386122360Simp if (error != 0) { 387122597Simp device_printf(aha->dev, "AOP_MBOX_IF_ENABLE - Failed."); 388122360Simp return (error); 389122360Simp } 39039751Simp } 39139751Simp if (aha->boardid < 0x41) 392122597Simp device_printf(aha->dev, "Warning: aha-1542A won't work.\n"); 39339751Simp 39441335Simp aha->max_sg = 17; /* Need >= 17 to do 64k I/O */ 39539225Sgibbs aha->diff_bus = 0; 39639225Sgibbs aha->extended_lun = 0; 39739751Simp aha->extended_trans = 0; 39840403Simp aha->max_ccbs = 16; 39939225Sgibbs /* Determine Sync/Wide/Disc settings */ 40039225Sgibbs length_param = sizeof(setup_info); 40141047Sgibbs error = aha_cmd(aha, AOP_INQUIRE_SETUP_INFO, &length_param, 402122340Simp /*paramlen*/1, (uint8_t*)&setup_info, sizeof(setup_info), 403122340Simp DEFAULT_CMD_TIMEOUT); 40439225Sgibbs if (error != 0) { 405122597Simp device_printf(aha->dev, "aha_fetch_adapter_info - Failed " 406122597Simp "Get Setup Info\n"); 40739225Sgibbs return (error); 40839225Sgibbs } 40939225Sgibbs if (setup_info.initiate_sync != 0) { 41039225Sgibbs aha->sync_permitted = ALL_TARGETS; 41139225Sgibbs } 41239225Sgibbs aha->disc_permitted = ALL_TARGETS; 41339225Sgibbs 41439225Sgibbs /* We need as many mailboxes as we can have ccbs */ 41539225Sgibbs aha->num_boxes = aha->max_ccbs; 41639225Sgibbs 41739225Sgibbs /* Determine our SCSI ID */ 41841047Sgibbs error = aha_cmd(aha, AOP_INQUIRE_CONFIG, NULL, /*parmlen*/0, 419122340Simp (uint8_t*)&config_data, sizeof(config_data), DEFAULT_CMD_TIMEOUT); 42039225Sgibbs if (error != 0) { 421122597Simp device_printf(aha->dev, 422122597Simp "aha_fetch_adapter_info - Failed Get Config\n"); 42339225Sgibbs return (error); 42439225Sgibbs } 42539225Sgibbs aha->scsi_id = config_data.scsi_id; 42639225Sgibbs return (0); 42739225Sgibbs} 42839225Sgibbs 42939225Sgibbs/* 43039225Sgibbs * Start the board, ready for normal operation 43139225Sgibbs */ 43239225Sgibbsint 43339225Sgibbsaha_init(struct aha_softc* aha) 43439225Sgibbs{ 43539225Sgibbs /* Announce the Adapter */ 436122597Simp device_printf(aha->dev, "AHA-%s FW Rev. %c.%c (ID=%x) ", 437122340Simp aha->model, aha->fw_major, aha->fw_minor, aha->boardid); 43839225Sgibbs 43939225Sgibbs if (aha->diff_bus != 0) 44039225Sgibbs printf("Diff "); 44139225Sgibbs 44239225Sgibbs printf("SCSI Host Adapter, SCSI ID %d, %d CCBs\n", aha->scsi_id, 443122340Simp aha->max_ccbs); 44439225Sgibbs 44539225Sgibbs /* 44639225Sgibbs * Create our DMA tags. These tags define the kinds of device 447122363Simp * accessible memory allocations and memory mappings we will 44839225Sgibbs * need to perform during normal operation. 44939225Sgibbs * 45039225Sgibbs * Unless we need to further restrict the allocation, we rely 45139225Sgibbs * on the restrictions of the parent dmat, hence the common 45239225Sgibbs * use of MAXADDR and MAXSIZE. 45339225Sgibbs */ 45439225Sgibbs 45539225Sgibbs /* DMA tag for mapping buffers into device visible space. */ 456122340Simp if (bus_dma_tag_create( /* parent */ aha->parent_dmat, 457112782Smdodd /* alignment */ 1, 458112782Smdodd /* boundary */ 0, 459112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR, 460112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 461112782Smdodd /* filter */ NULL, 462112782Smdodd /* filterarg */ NULL, 463112782Smdodd /* maxsize */ MAXBSIZE, 464112782Smdodd /* nsegments */ AHA_NSEG, 465112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_24BIT, 466112782Smdodd /* flags */ BUS_DMA_ALLOCNOW, 467117126Sscottl /* lockfunc */ busdma_lock_mutex, 468241589Sjhb /* lockarg */ &aha->lock, 469112782Smdodd &aha->buffer_dmat) != 0) { 47039225Sgibbs goto error_exit; 47139225Sgibbs } 47239225Sgibbs 47339225Sgibbs aha->init_level++; 47439225Sgibbs /* DMA tag for our mailboxes */ 475112782Smdodd if (bus_dma_tag_create( /* parent */ aha->parent_dmat, 476112782Smdodd /* alignment */ 1, 477112782Smdodd /* boundary */ 0, 478112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR, 479112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 480112782Smdodd /* filter */ NULL, 481112782Smdodd /* filterarg */ NULL, 482112782Smdodd /* maxsize */ aha->num_boxes * 483112782Smdodd (sizeof(aha_mbox_in_t) + 484112782Smdodd sizeof(aha_mbox_out_t)), 485112782Smdodd /* nsegments */ 1, 486112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_24BIT, 487112782Smdodd /* flags */ 0, 488241589Sjhb /* lockfunc */ NULL, 489241589Sjhb /* lockarg */ NULL, 490112782Smdodd &aha->mailbox_dmat) != 0) { 49139225Sgibbs goto error_exit; 49239225Sgibbs } 49339225Sgibbs 49439225Sgibbs aha->init_level++; 49539225Sgibbs 49639225Sgibbs /* Allocation for our mailboxes */ 49739225Sgibbs if (bus_dmamem_alloc(aha->mailbox_dmat, (void **)&aha->out_boxes, 498122340Simp BUS_DMA_NOWAIT, &aha->mailbox_dmamap) != 0) 49939225Sgibbs goto error_exit; 50039225Sgibbs 50139225Sgibbs aha->init_level++; 50239225Sgibbs 50339225Sgibbs /* And permanently map them */ 50439225Sgibbs bus_dmamap_load(aha->mailbox_dmat, aha->mailbox_dmamap, 505122340Simp aha->out_boxes, aha->num_boxes * (sizeof(aha_mbox_in_t) + 506122340Simp sizeof(aha_mbox_out_t)), ahamapmboxes, aha, /*flags*/0); 50739225Sgibbs 50839225Sgibbs aha->init_level++; 50939225Sgibbs 51039225Sgibbs aha->in_boxes = (aha_mbox_in_t *)&aha->out_boxes[aha->num_boxes]; 51139225Sgibbs 51239225Sgibbs ahainitmboxes(aha); 51339225Sgibbs 51439225Sgibbs /* DMA tag for our ccb structures */ 515112782Smdodd if (bus_dma_tag_create( /* parent */ aha->parent_dmat, 516112782Smdodd /* alignment */ 1, 517112782Smdodd /* boundary */ 0, 518112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR, 519112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 520112782Smdodd /* filter */ NULL, 521112782Smdodd /* filterarg */ NULL, 522112782Smdodd /* maxsize */ aha->max_ccbs * 523112782Smdodd sizeof(struct aha_ccb), 524112782Smdodd /* nsegments */ 1, 525112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_24BIT, 526112782Smdodd /* flags */ 0, 527241589Sjhb /* lockfunc */ NULL, 528241589Sjhb /* lockarg */ NULL, 529112782Smdodd &aha->ccb_dmat) != 0) { 53039225Sgibbs goto error_exit; 53139225Sgibbs } 53239225Sgibbs 53339225Sgibbs aha->init_level++; 53439225Sgibbs 53539225Sgibbs /* Allocation for our ccbs */ 53639225Sgibbs if (bus_dmamem_alloc(aha->ccb_dmat, (void **)&aha->aha_ccb_array, 537122340Simp BUS_DMA_NOWAIT, &aha->ccb_dmamap) != 0) 53839225Sgibbs goto error_exit; 53939225Sgibbs 54039225Sgibbs aha->init_level++; 54139225Sgibbs 54239225Sgibbs /* And permanently map them */ 543122340Simp bus_dmamap_load(aha->ccb_dmat, aha->ccb_dmamap, aha->aha_ccb_array, 544122340Simp aha->max_ccbs * sizeof(struct aha_ccb), ahamapccbs, aha, /*flags*/0); 54539225Sgibbs 54639225Sgibbs aha->init_level++; 54739225Sgibbs 54839225Sgibbs /* DMA tag for our S/G structures. We allocate in page sized chunks */ 549112782Smdodd if (bus_dma_tag_create( /* parent */ aha->parent_dmat, 550112782Smdodd /* alignment */ 1, 551112782Smdodd /* boundary */ 0, 552112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR, 553112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 554112782Smdodd /* filter */ NULL, 555112782Smdodd /* filterarg */ NULL, 556112782Smdodd /* maxsize */ PAGE_SIZE, 557112782Smdodd /* nsegments */ 1, 558112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_24BIT, 559112782Smdodd /* flags */ 0, 560241589Sjhb /* lockfunc */ NULL, 561241589Sjhb /* lockarg */ NULL, 562122340Simp &aha->sg_dmat) != 0) 56339225Sgibbs goto error_exit; 56439225Sgibbs 56539225Sgibbs aha->init_level++; 56639225Sgibbs 56739225Sgibbs /* Perform initial CCB allocation */ 56839225Sgibbs bzero(aha->aha_ccb_array, aha->max_ccbs * sizeof(struct aha_ccb)); 56939225Sgibbs ahaallocccbs(aha); 57039225Sgibbs 57139225Sgibbs if (aha->num_ccbs == 0) { 572122597Simp device_printf(aha->dev, 573122597Simp "aha_init - Unable to allocate initial ccbs\n"); 57439225Sgibbs goto error_exit; 57539225Sgibbs } 57639225Sgibbs 57739225Sgibbs /* 57839225Sgibbs * Note that we are going and return (to probe) 57939225Sgibbs */ 580122340Simp return (0); 58139225Sgibbs 58239225Sgibbserror_exit: 58339225Sgibbs 58439225Sgibbs return (ENXIO); 58539225Sgibbs} 58639225Sgibbs 58739225Sgibbsint 58839225Sgibbsaha_attach(struct aha_softc *aha) 58939225Sgibbs{ 59039225Sgibbs int tagged_dev_openings; 59139225Sgibbs struct cam_devq *devq; 59239225Sgibbs 59339225Sgibbs /* 59441335Simp * We don't do tagged queueing, since the aha cards don't 59541335Simp * support it. 59639225Sgibbs */ 59739225Sgibbs tagged_dev_openings = 0; 59839225Sgibbs 59939225Sgibbs /* 60039225Sgibbs * Create the device queue for our SIM. 60139225Sgibbs */ 60239225Sgibbs devq = cam_simq_alloc(aha->max_ccbs - 1); 60339225Sgibbs if (devq == NULL) 60439225Sgibbs return (ENOMEM); 60539225Sgibbs 60639225Sgibbs /* 60739225Sgibbs * Construct our SIM entry 60839225Sgibbs */ 609241589Sjhb aha->sim = cam_sim_alloc(ahaaction, ahapoll, "aha", aha, 610241589Sjhb device_get_unit(aha->dev), &aha->lock, 2, tagged_dev_openings, 611241589Sjhb devq); 61239225Sgibbs if (aha->sim == NULL) { 61339225Sgibbs cam_simq_free(devq); 61439225Sgibbs return (ENOMEM); 61539225Sgibbs } 616241589Sjhb mtx_lock(&aha->lock); 617170872Sscottl if (xpt_bus_register(aha->sim, aha->dev, 0) != CAM_SUCCESS) { 61839225Sgibbs cam_sim_free(aha->sim, /*free_devq*/TRUE); 619241589Sjhb mtx_unlock(&aha->lock); 62039225Sgibbs return (ENXIO); 62139225Sgibbs } 622122340Simp if (xpt_create_path(&aha->path, /*periph*/NULL, cam_sim_path(aha->sim), 623122340Simp CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 62439225Sgibbs xpt_bus_deregister(cam_sim_path(aha->sim)); 62539225Sgibbs cam_sim_free(aha->sim, /*free_devq*/TRUE); 626241589Sjhb mtx_unlock(&aha->lock); 62739225Sgibbs return (ENXIO); 62839225Sgibbs } 629241589Sjhb mtx_unlock(&aha->lock); 630122363Simp 63139225Sgibbs return (0); 63239225Sgibbs} 63339225Sgibbs 63439225Sgibbsstatic void 63539225Sgibbsahaallocccbs(struct aha_softc *aha) 63639225Sgibbs{ 63739225Sgibbs struct aha_ccb *next_ccb; 63839225Sgibbs struct sg_map_node *sg_map; 63939225Sgibbs bus_addr_t physaddr; 64039225Sgibbs aha_sg_t *segs; 64139225Sgibbs int newcount; 64239225Sgibbs int i; 64339225Sgibbs 64439225Sgibbs next_ccb = &aha->aha_ccb_array[aha->num_ccbs]; 64539225Sgibbs 64639225Sgibbs sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT); 64739225Sgibbs 64839225Sgibbs if (sg_map == NULL) 64939225Sgibbs return; 65039225Sgibbs 65139225Sgibbs /* Allocate S/G space for the next batch of CCBS */ 65239225Sgibbs if (bus_dmamem_alloc(aha->sg_dmat, (void **)&sg_map->sg_vaddr, 653122340Simp BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) { 65439225Sgibbs free(sg_map, M_DEVBUF); 65539225Sgibbs return; 65639225Sgibbs } 65739225Sgibbs 65839225Sgibbs SLIST_INSERT_HEAD(&aha->sg_maps, sg_map, links); 65939225Sgibbs 66039225Sgibbs bus_dmamap_load(aha->sg_dmat, sg_map->sg_dmamap, sg_map->sg_vaddr, 661122340Simp PAGE_SIZE, ahamapsgs, aha, /*flags*/0); 662122363Simp 66339225Sgibbs segs = sg_map->sg_vaddr; 66439225Sgibbs physaddr = sg_map->sg_physaddr; 66539225Sgibbs 66639225Sgibbs newcount = (PAGE_SIZE / (AHA_NSEG * sizeof(aha_sg_t))); 66739225Sgibbs for (i = 0; aha->num_ccbs < aha->max_ccbs && i < newcount; i++) { 66839225Sgibbs int error; 66939225Sgibbs 67039225Sgibbs next_ccb->sg_list = segs; 67139225Sgibbs next_ccb->sg_list_phys = physaddr; 67241047Sgibbs next_ccb->flags = ACCB_FREE; 673241589Sjhb callout_init_mtx(&next_ccb->timer, &aha->lock, 0); 67439225Sgibbs error = bus_dmamap_create(aha->buffer_dmat, /*flags*/0, 675122340Simp &next_ccb->dmamap); 67639225Sgibbs if (error != 0) 67739225Sgibbs break; 67839225Sgibbs SLIST_INSERT_HEAD(&aha->free_aha_ccbs, next_ccb, links); 67939225Sgibbs segs += AHA_NSEG; 68039225Sgibbs physaddr += (AHA_NSEG * sizeof(aha_sg_t)); 68139225Sgibbs next_ccb++; 68239225Sgibbs aha->num_ccbs++; 68339225Sgibbs } 68439225Sgibbs 68539225Sgibbs /* Reserve a CCB for error recovery */ 68641047Sgibbs if (aha->recovery_accb == NULL) { 68741047Sgibbs aha->recovery_accb = SLIST_FIRST(&aha->free_aha_ccbs); 68839225Sgibbs SLIST_REMOVE_HEAD(&aha->free_aha_ccbs, links); 68939225Sgibbs } 69039225Sgibbs} 69139225Sgibbs 69239225Sgibbsstatic __inline void 69341047Sgibbsahafreeccb(struct aha_softc *aha, struct aha_ccb *accb) 69439225Sgibbs{ 69539225Sgibbs 696241589Sjhb if (!dumping) 697241589Sjhb mtx_assert(&aha->lock, MA_OWNED); 69841047Sgibbs if ((accb->flags & ACCB_ACTIVE) != 0) 69941047Sgibbs LIST_REMOVE(&accb->ccb->ccb_h, sim_links.le); 70039225Sgibbs if (aha->resource_shortage != 0 701122340Simp && (accb->ccb->ccb_h.status & CAM_RELEASE_SIMQ) == 0) { 70241047Sgibbs accb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 70339225Sgibbs aha->resource_shortage = FALSE; 70439225Sgibbs } 70541047Sgibbs accb->flags = ACCB_FREE; 70641047Sgibbs SLIST_INSERT_HEAD(&aha->free_aha_ccbs, accb, links); 70741047Sgibbs aha->active_ccbs--; 70839225Sgibbs} 70939225Sgibbs 71039225Sgibbsstatic struct aha_ccb* 71139225Sgibbsahagetccb(struct aha_softc *aha) 71239225Sgibbs{ 71341047Sgibbs struct aha_ccb* accb; 71439225Sgibbs 715241589Sjhb if (!dumping) 716241589Sjhb mtx_assert(&aha->lock, MA_OWNED); 71741047Sgibbs if ((accb = SLIST_FIRST(&aha->free_aha_ccbs)) != NULL) { 71839225Sgibbs SLIST_REMOVE_HEAD(&aha->free_aha_ccbs, links); 71941047Sgibbs aha->active_ccbs++; 72039225Sgibbs } else if (aha->num_ccbs < aha->max_ccbs) { 72139225Sgibbs ahaallocccbs(aha); 72241047Sgibbs accb = SLIST_FIRST(&aha->free_aha_ccbs); 72341047Sgibbs if (accb == NULL) 724122597Simp device_printf(aha->dev, "Can't malloc ACCB\n"); 72541047Sgibbs else { 72639225Sgibbs SLIST_REMOVE_HEAD(&aha->free_aha_ccbs, links); 72741047Sgibbs aha->active_ccbs++; 72841047Sgibbs } 72939225Sgibbs } 73039225Sgibbs 73141047Sgibbs return (accb); 73239225Sgibbs} 73339225Sgibbs 73439225Sgibbsstatic void 73539225Sgibbsahaaction(struct cam_sim *sim, union ccb *ccb) 73639225Sgibbs{ 73739225Sgibbs struct aha_softc *aha; 73839225Sgibbs 73939225Sgibbs CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("ahaaction\n")); 740122363Simp 74139225Sgibbs aha = (struct aha_softc *)cam_sim_softc(sim); 742241589Sjhb mtx_assert(&aha->lock, MA_OWNED); 743122363Simp 74439225Sgibbs switch (ccb->ccb_h.func_code) { 74539225Sgibbs /* Common cases first */ 74639225Sgibbs case XPT_SCSI_IO: /* Execute the requested I/O operation */ 747122340Simp case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ { 74841047Sgibbs struct aha_ccb *accb; 74939225Sgibbs struct aha_hccb *hccb; 75039225Sgibbs 75139225Sgibbs /* 752108533Sschweikh * Get an accb to use. 75339225Sgibbs */ 75441047Sgibbs if ((accb = ahagetccb(aha)) == NULL) { 75539225Sgibbs aha->resource_shortage = TRUE; 75639225Sgibbs xpt_freeze_simq(aha->sim, /*count*/1); 75739225Sgibbs ccb->ccb_h.status = CAM_REQUEUE_REQ; 75839225Sgibbs xpt_done(ccb); 75939225Sgibbs return; 76039225Sgibbs } 76141047Sgibbs hccb = &accb->hccb; 76239225Sgibbs 76339225Sgibbs /* 76441047Sgibbs * So we can find the ACCB when an abort is requested 76539225Sgibbs */ 76641047Sgibbs accb->ccb = ccb; 76741047Sgibbs ccb->ccb_h.ccb_accb_ptr = accb; 76839225Sgibbs ccb->ccb_h.ccb_aha_ptr = aha; 76939225Sgibbs 77039225Sgibbs /* 77141047Sgibbs * Put all the arguments for the xfer in the accb 77239225Sgibbs */ 77339225Sgibbs hccb->target = ccb->ccb_h.target_id; 77439225Sgibbs hccb->lun = ccb->ccb_h.target_lun; 77539225Sgibbs hccb->ahastat = 0; 77639225Sgibbs hccb->sdstat = 0; 77739225Sgibbs 77839225Sgibbs if (ccb->ccb_h.func_code == XPT_SCSI_IO) { 77939225Sgibbs struct ccb_scsiio *csio; 78039225Sgibbs struct ccb_hdr *ccbh; 781246713Skib int error; 78239225Sgibbs 78339225Sgibbs csio = &ccb->csio; 78439225Sgibbs ccbh = &csio->ccb_h; 78542887Simp hccb->opcode = aha->ccb_ccb_opcode; 78639225Sgibbs hccb->datain = (ccb->ccb_h.flags & CAM_DIR_IN) != 0; 78739225Sgibbs hccb->dataout = (ccb->ccb_h.flags & CAM_DIR_OUT) != 0; 78839225Sgibbs hccb->cmd_len = csio->cdb_len; 78939225Sgibbs if (hccb->cmd_len > sizeof(hccb->scsi_cdb)) { 79039225Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 79141047Sgibbs ahafreeccb(aha, accb); 79239225Sgibbs xpt_done(ccb); 79339225Sgibbs return; 79439225Sgibbs } 79539225Sgibbs hccb->sense_len = csio->sense_len; 79639225Sgibbs if ((ccbh->flags & CAM_CDB_POINTER) != 0) { 79739225Sgibbs if ((ccbh->flags & CAM_CDB_PHYS) == 0) { 79839225Sgibbs bcopy(csio->cdb_io.cdb_ptr, 79939225Sgibbs hccb->scsi_cdb, hccb->cmd_len); 80039225Sgibbs } else { 80139225Sgibbs /* I guess I could map it in... */ 80239225Sgibbs ccbh->status = CAM_REQ_INVALID; 80341047Sgibbs ahafreeccb(aha, accb); 80439225Sgibbs xpt_done(ccb); 80539225Sgibbs return; 80639225Sgibbs } 80739225Sgibbs } else { 80839225Sgibbs bcopy(csio->cdb_io.cdb_bytes, 80939225Sgibbs hccb->scsi_cdb, hccb->cmd_len); 81039225Sgibbs } 81139225Sgibbs /* 81239225Sgibbs * If we have any data to send with this command, 81339225Sgibbs * map it into bus space. 81439225Sgibbs */ 81539225Sgibbs 816246713Skib error = bus_dmamap_load_ccb( 817246713Skib aha->buffer_dmat, 818246713Skib accb->dmamap, 819246713Skib ccb, 820246713Skib ahaexecuteccb, 821246713Skib accb, 822246713Skib /*flags*/0); 823246713Skib if (error == EINPROGRESS) { 824246713Skib /* 825246713Skib * So as to maintain ordering, freeze the 826246713Skib * controller queue until our mapping is 827246713Skib * returned. 828246713Skib */ 829246713Skib xpt_freeze_simq(aha->sim, 1); 830246713Skib csio->ccb_h.status |= CAM_RELEASE_SIMQ; 83139225Sgibbs } 83239225Sgibbs } else { 83339225Sgibbs hccb->opcode = INITIATOR_BUS_DEV_RESET; 83439225Sgibbs /* No data transfer */ 83539225Sgibbs hccb->datain = TRUE; 83639225Sgibbs hccb->dataout = TRUE; 83739225Sgibbs hccb->cmd_len = 0; 83839225Sgibbs hccb->sense_len = 0; 83941047Sgibbs ahaexecuteccb(accb, NULL, 0, 0); 84039225Sgibbs } 84139225Sgibbs break; 84239225Sgibbs } 84339225Sgibbs case XPT_EN_LUN: /* Enable LUN as a target */ 84439225Sgibbs case XPT_TARGET_IO: /* Execute target I/O request */ 84539225Sgibbs case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */ 84639225Sgibbs case XPT_CONT_TARGET_IO: /* Continue Host Target I/O Connection*/ 84739225Sgibbs case XPT_ABORT: /* Abort the specified CCB */ 84839225Sgibbs /* XXX Implement */ 84939225Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 85039225Sgibbs xpt_done(ccb); 85139225Sgibbs break; 85239225Sgibbs case XPT_SET_TRAN_SETTINGS: 85339225Sgibbs /* XXX Implement */ 85446581Sken ccb->ccb_h.status = CAM_PROVIDE_FAIL; 85539225Sgibbs xpt_done(ccb); 85639225Sgibbs break; 85739225Sgibbs case XPT_GET_TRAN_SETTINGS: 85839225Sgibbs /* Get default/user set transfer settings for the target */ 85939225Sgibbs { 860163816Smjacob struct ccb_trans_settings *cts = &ccb->cts; 861163816Smjacob u_int target_mask = 0x01 << ccb->ccb_h.target_id; 862163816Smjacob struct ccb_trans_settings_scsi *scsi = 863163816Smjacob &cts->proto_specific.scsi; 864163816Smjacob struct ccb_trans_settings_spi *spi = 865163816Smjacob &cts->xport_specific.spi; 86639225Sgibbs 867163816Smjacob cts->protocol = PROTO_SCSI; 868163816Smjacob cts->protocol_version = SCSI_REV_2; 869163816Smjacob cts->transport = XPORT_SPI; 870163816Smjacob cts->transport_version = 2; 871163816Smjacob if (cts->type == CTS_TYPE_USER_SETTINGS) { 872163816Smjacob spi->flags = 0; 873163816Smjacob if ((aha->disc_permitted & target_mask) != 0) 874163816Smjacob spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 875163816Smjacob spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 876163816Smjacob if ((aha->sync_permitted & target_mask) != 0) { 877163816Smjacob if (aha->boardid >= BOARD_1542CF) 878163816Smjacob spi->sync_period = 25; 879163816Smjacob else 880163816Smjacob spi->sync_period = 50; 881163816Smjacob } else { 882163816Smjacob spi->sync_period = 0; 883163816Smjacob } 884163816Smjacob 885163816Smjacob if (spi->sync_period != 0) 886163816Smjacob spi->sync_offset = 15; 887163816Smjacob 888163816Smjacob spi->valid = CTS_SPI_VALID_SYNC_RATE 889163816Smjacob | CTS_SPI_VALID_SYNC_OFFSET 890163816Smjacob | CTS_SPI_VALID_BUS_WIDTH 891163816Smjacob | CTS_SPI_VALID_DISC; 892163816Smjacob scsi->valid = CTS_SCSI_VALID_TQ; 893163816Smjacob } else { 894163816Smjacob ahafetchtransinfo(aha, cts); 895163816Smjacob } 89639225Sgibbs 89739225Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 89839225Sgibbs xpt_done(ccb); 89939225Sgibbs break; 90039225Sgibbs } 90139225Sgibbs case XPT_CALC_GEOMETRY: 90239225Sgibbs { 90339225Sgibbs struct ccb_calc_geometry *ccg; 904122340Simp uint32_t size_mb; 905122340Simp uint32_t secs_per_cylinder; 90639225Sgibbs 90739225Sgibbs ccg = &ccb->ccg; 90839225Sgibbs size_mb = ccg->volume_size 90939225Sgibbs / ((1024L * 1024L) / ccg->block_size); 91039225Sgibbs if (size_mb >= 1024 && (aha->extended_trans != 0)) { 91139225Sgibbs if (size_mb >= 2048) { 91239225Sgibbs ccg->heads = 255; 91339225Sgibbs ccg->secs_per_track = 63; 91439225Sgibbs } else { 91539225Sgibbs ccg->heads = 128; 91639225Sgibbs ccg->secs_per_track = 32; 91739225Sgibbs } 91839225Sgibbs } else { 91939225Sgibbs ccg->heads = 64; 92039225Sgibbs ccg->secs_per_track = 32; 92139225Sgibbs } 92239225Sgibbs secs_per_cylinder = ccg->heads * ccg->secs_per_track; 92339225Sgibbs ccg->cylinders = ccg->volume_size / secs_per_cylinder; 92439225Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 92539225Sgibbs xpt_done(ccb); 92639225Sgibbs break; 92739225Sgibbs } 92839225Sgibbs case XPT_RESET_BUS: /* Reset the specified SCSI bus */ 92939225Sgibbs ahareset(aha, /*hardreset*/TRUE); 93039225Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 93139225Sgibbs xpt_done(ccb); 93239225Sgibbs break; 93339225Sgibbs case XPT_TERM_IO: /* Terminate the I/O process */ 93439225Sgibbs /* XXX Implement */ 93539225Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 93639225Sgibbs xpt_done(ccb); 93739225Sgibbs break; 93839225Sgibbs case XPT_PATH_INQ: /* Path routing inquiry */ 93939225Sgibbs { 94039225Sgibbs struct ccb_pathinq *cpi = &ccb->cpi; 941122363Simp 94239225Sgibbs cpi->version_num = 1; /* XXX??? */ 94339225Sgibbs cpi->hba_inquiry = PI_SDTR_ABLE; 94439225Sgibbs cpi->target_sprt = 0; 94539225Sgibbs cpi->hba_misc = 0; 94639225Sgibbs cpi->hba_eng_cnt = 0; 94739852Simp cpi->max_target = 7; 94839225Sgibbs cpi->max_lun = 7; 94939225Sgibbs cpi->initiator_id = aha->scsi_id; 95039225Sgibbs cpi->bus_id = cam_sim_bus(sim); 95146581Sken cpi->base_transfer_speed = 3300; 95239225Sgibbs strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 95339225Sgibbs strncpy(cpi->hba_vid, "Adaptec", HBA_IDLEN); 95439225Sgibbs strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 95539225Sgibbs cpi->unit_number = cam_sim_unit(sim); 956163816Smjacob cpi->transport = XPORT_SPI; 957163816Smjacob cpi->transport_version = 2; 958163816Smjacob cpi->protocol = PROTO_SCSI; 959163816Smjacob cpi->protocol_version = SCSI_REV_2; 96039225Sgibbs cpi->ccb_h.status = CAM_REQ_CMP; 96139225Sgibbs xpt_done(ccb); 96239225Sgibbs break; 96339225Sgibbs } 96439225Sgibbs default: 96539225Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 96639225Sgibbs xpt_done(ccb); 96739225Sgibbs break; 96839225Sgibbs } 96939225Sgibbs} 97039225Sgibbs 97139225Sgibbsstatic void 97239225Sgibbsahaexecuteccb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 97339225Sgibbs{ 97441047Sgibbs struct aha_ccb *accb; 97539225Sgibbs union ccb *ccb; 97639225Sgibbs struct aha_softc *aha; 977122340Simp uint32_t paddr; 97839225Sgibbs 97941047Sgibbs accb = (struct aha_ccb *)arg; 98041047Sgibbs ccb = accb->ccb; 98139225Sgibbs aha = (struct aha_softc *)ccb->ccb_h.ccb_aha_ptr; 98239225Sgibbs 98339225Sgibbs if (error != 0) { 98439225Sgibbs if (error != EFBIG) 985122597Simp device_printf(aha->dev, 986122597Simp "Unexepected error 0x%x returned from " 987122597Simp "bus_dmamap_load\n", error); 98839225Sgibbs if (ccb->ccb_h.status == CAM_REQ_INPROG) { 98939225Sgibbs xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 99039225Sgibbs ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN; 99139225Sgibbs } 99241047Sgibbs ahafreeccb(aha, accb); 99339225Sgibbs xpt_done(ccb); 99439225Sgibbs return; 99539225Sgibbs } 996122363Simp 99739225Sgibbs if (nseg != 0) { 99839225Sgibbs aha_sg_t *sg; 99939225Sgibbs bus_dma_segment_t *end_seg; 1000115343Sscottl bus_dmasync_op_t op; 100139225Sgibbs 100239225Sgibbs end_seg = dm_segs + nseg; 100339225Sgibbs 100439225Sgibbs /* Copy the segments into our SG list */ 100541047Sgibbs sg = accb->sg_list; 100639225Sgibbs while (dm_segs < end_seg) { 100739225Sgibbs ahautoa24(dm_segs->ds_len, sg->len); 100839225Sgibbs ahautoa24(dm_segs->ds_addr, sg->addr); 100939225Sgibbs sg++; 101039225Sgibbs dm_segs++; 101139225Sgibbs } 101239225Sgibbs 101339225Sgibbs if (nseg > 1) { 101442887Simp accb->hccb.opcode = aha->ccb_sg_opcode; 101539225Sgibbs ahautoa24((sizeof(aha_sg_t) * nseg), 1016122340Simp accb->hccb.data_len); 101741047Sgibbs ahautoa24(accb->sg_list_phys, accb->hccb.data_addr); 101839225Sgibbs } else { 101941047Sgibbs bcopy(accb->sg_list->len, accb->hccb.data_len, 3); 102041047Sgibbs bcopy(accb->sg_list->addr, accb->hccb.data_addr, 3); 102139225Sgibbs } 102239225Sgibbs 102339225Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 102439225Sgibbs op = BUS_DMASYNC_PREREAD; 102539225Sgibbs else 102639225Sgibbs op = BUS_DMASYNC_PREWRITE; 102739225Sgibbs 102841047Sgibbs bus_dmamap_sync(aha->buffer_dmat, accb->dmamap, op); 102939225Sgibbs 103039225Sgibbs } else { 103141709Sgibbs accb->hccb.opcode = INITIATOR_CCB; 103241047Sgibbs ahautoa24(0, accb->hccb.data_len); 103341047Sgibbs ahautoa24(0, accb->hccb.data_addr); 103439225Sgibbs } 103539225Sgibbs 103639225Sgibbs /* 103739225Sgibbs * Last time we need to check if this CCB needs to 103839225Sgibbs * be aborted. 103939225Sgibbs */ 104039225Sgibbs if (ccb->ccb_h.status != CAM_REQ_INPROG) { 104139225Sgibbs if (nseg != 0) 104241047Sgibbs bus_dmamap_unload(aha->buffer_dmat, accb->dmamap); 104341047Sgibbs ahafreeccb(aha, accb); 104439225Sgibbs xpt_done(ccb); 104539225Sgibbs return; 104639225Sgibbs } 1047122363Simp 104841047Sgibbs accb->flags = ACCB_ACTIVE; 104939225Sgibbs ccb->ccb_h.status |= CAM_SIM_QUEUED; 105039225Sgibbs LIST_INSERT_HEAD(&aha->pending_ccbs, &ccb->ccb_h, sim_links.le); 105139225Sgibbs 1052241589Sjhb callout_reset(&accb->timer, (ccb->ccb_h.timeout * hz) / 1000, 1053241589Sjhb ahatimeout, accb); 105439225Sgibbs 105539225Sgibbs /* Tell the adapter about this command */ 105641047Sgibbs if (aha->cur_outbox->action_code != AMBO_FREE) { 105741047Sgibbs /* 105841047Sgibbs * We should never encounter a busy mailbox. 105941047Sgibbs * If we do, warn the user, and treat it as 106041047Sgibbs * a resource shortage. If the controller is 106141047Sgibbs * hung, one of the pending transactions will 106241047Sgibbs * timeout causing us to start recovery operations. 106341047Sgibbs */ 1064122597Simp device_printf(aha->dev, 1065122597Simp "Encountered busy mailbox with %d out of %d " 1066122597Simp "commands active!!!", aha->active_ccbs, aha->max_ccbs); 1067241603Sglebius callout_stop(&accb->timer); 106841047Sgibbs if (nseg != 0) 106941047Sgibbs bus_dmamap_unload(aha->buffer_dmat, accb->dmamap); 107041047Sgibbs ahafreeccb(aha, accb); 107141047Sgibbs aha->resource_shortage = TRUE; 107241047Sgibbs xpt_freeze_simq(aha->sim, /*count*/1); 107341047Sgibbs ccb->ccb_h.status = CAM_REQUEUE_REQ; 107441047Sgibbs xpt_done(ccb); 107541047Sgibbs return; 107641047Sgibbs } 107741047Sgibbs paddr = ahaccbvtop(aha, accb); 107839225Sgibbs ahautoa24(paddr, aha->cur_outbox->ccb_addr); 1079122363Simp aha->cur_outbox->action_code = AMBO_START; 108041047Sgibbs aha_outb(aha, COMMAND_REG, AOP_START_MBOX); 108139225Sgibbs 108239225Sgibbs ahanextoutbox(aha); 108339225Sgibbs} 108439225Sgibbs 108539225Sgibbsvoid 108639225Sgibbsaha_intr(void *arg) 108739225Sgibbs{ 108839225Sgibbs struct aha_softc *aha; 1089241589Sjhb 1090241589Sjhb aha = arg; 1091241589Sjhb mtx_lock(&aha->lock); 1092241589Sjhb aha_intr_locked(aha); 1093241589Sjhb mtx_unlock(&aha->lock); 1094241589Sjhb} 1095241589Sjhb 1096241589Sjhbvoid 1097241589Sjhbaha_intr_locked(struct aha_softc *aha) 1098241589Sjhb{ 109939225Sgibbs u_int intstat; 1100122340Simp uint32_t paddr; 110139225Sgibbs 110239225Sgibbs while (((intstat = aha_inb(aha, INTSTAT_REG)) & INTR_PENDING) != 0) { 110339225Sgibbs if ((intstat & CMD_COMPLETE) != 0) { 110439225Sgibbs aha->latched_status = aha_inb(aha, STATUS_REG); 110539225Sgibbs aha->command_cmp = TRUE; 110639225Sgibbs } 110739225Sgibbs 110839225Sgibbs aha_outb(aha, CONTROL_REG, RESET_INTR); 110939225Sgibbs 111039225Sgibbs if ((intstat & IMB_LOADED) != 0) { 111141047Sgibbs while (aha->cur_inbox->comp_code != AMBI_FREE) { 111239225Sgibbs paddr = aha_a24tou(aha->cur_inbox->ccb_addr); 1113122340Simp ahadone(aha, ahaccbptov(aha, paddr), 1114122340Simp aha->cur_inbox->comp_code); 111541047Sgibbs aha->cur_inbox->comp_code = AMBI_FREE; 111639225Sgibbs ahanextinbox(aha); 111739225Sgibbs } 111839225Sgibbs } 111939225Sgibbs 112039225Sgibbs if ((intstat & SCSI_BUS_RESET) != 0) { 112139225Sgibbs ahareset(aha, /*hardreset*/FALSE); 112239225Sgibbs } 112339225Sgibbs } 112439225Sgibbs} 112539225Sgibbs 112639225Sgibbsstatic void 112741047Sgibbsahadone(struct aha_softc *aha, struct aha_ccb *accb, aha_mbi_comp_code_t comp_code) 112839225Sgibbs{ 112939225Sgibbs union ccb *ccb; 113039225Sgibbs struct ccb_scsiio *csio; 113139225Sgibbs 113241047Sgibbs ccb = accb->ccb; 113341047Sgibbs csio = &accb->ccb->csio; 113439225Sgibbs 113541047Sgibbs if ((accb->flags & ACCB_ACTIVE) == 0) { 1136122597Simp device_printf(aha->dev, 1137122597Simp "ahadone - Attempt to free non-active ACCB %p\n", 1138122597Simp (void *)accb); 113939225Sgibbs return; 114039225Sgibbs } 114139225Sgibbs 114239225Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 1143115343Sscottl bus_dmasync_op_t op; 114439225Sgibbs 114539225Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 114639225Sgibbs op = BUS_DMASYNC_POSTREAD; 114739225Sgibbs else 114839225Sgibbs op = BUS_DMASYNC_POSTWRITE; 114941047Sgibbs bus_dmamap_sync(aha->buffer_dmat, accb->dmamap, op); 115041047Sgibbs bus_dmamap_unload(aha->buffer_dmat, accb->dmamap); 115139225Sgibbs } 115239225Sgibbs 115341047Sgibbs if (accb == aha->recovery_accb) { 115439225Sgibbs /* 115541047Sgibbs * The recovery ACCB does not have a CCB associated 115639225Sgibbs * with it, so short circuit the normal error handling. 115739225Sgibbs * We now traverse our list of pending CCBs and process 115839225Sgibbs * any that were terminated by the recovery CCBs action. 115939225Sgibbs * We also reinstate timeouts for all remaining, pending, 116039225Sgibbs * CCBs. 116139225Sgibbs */ 116239225Sgibbs struct cam_path *path; 116339225Sgibbs struct ccb_hdr *ccb_h; 116439225Sgibbs cam_status error; 116539225Sgibbs 116639225Sgibbs /* Notify all clients that a BDR occured */ 116739225Sgibbs error = xpt_create_path(&path, /*periph*/NULL, 1168122340Simp cam_sim_path(aha->sim), accb->hccb.target, 1169122340Simp CAM_LUN_WILDCARD); 1170122363Simp 1171260343Smav if (error == CAM_REQ_CMP) { 117239225Sgibbs xpt_async(AC_SENT_BDR, path, NULL); 1173260343Smav xpt_free_path(path); 1174260343Smav } 117539225Sgibbs 117639225Sgibbs ccb_h = LIST_FIRST(&aha->pending_ccbs); 117739225Sgibbs while (ccb_h != NULL) { 117841047Sgibbs struct aha_ccb *pending_accb; 117939225Sgibbs 118041047Sgibbs pending_accb = (struct aha_ccb *)ccb_h->ccb_accb_ptr; 118141047Sgibbs if (pending_accb->hccb.target == accb->hccb.target) { 118241047Sgibbs pending_accb->hccb.ahastat = AHASTAT_HA_BDR; 118339225Sgibbs ccb_h = LIST_NEXT(ccb_h, sim_links.le); 118441047Sgibbs ahadone(aha, pending_accb, AMBI_ERROR); 118539225Sgibbs } else { 1186241589Sjhb callout_reset(&pending_accb->timer, 1187241589Sjhb (ccb_h->timeout * hz) / 1000, 1188241589Sjhb ahatimeout, pending_accb); 118939225Sgibbs ccb_h = LIST_NEXT(ccb_h, sim_links.le); 119039225Sgibbs } 119139225Sgibbs } 1192122597Simp device_printf(aha->dev, "No longer in timeout\n"); 119339225Sgibbs return; 119439225Sgibbs } 119539225Sgibbs 1196241589Sjhb callout_stop(&accb->timer); 119739225Sgibbs 119839225Sgibbs switch (comp_code) { 119941047Sgibbs case AMBI_FREE: 1200122597Simp device_printf(aha->dev, 1201122597Simp "ahadone - CCB completed with free status!\n"); 120239225Sgibbs break; 120341047Sgibbs case AMBI_NOT_FOUND: 1204122597Simp device_printf(aha->dev, 1205122597Simp "ahadone - CCB Abort failed to find CCB\n"); 120639225Sgibbs break; 120741047Sgibbs case AMBI_ABORT: 120841047Sgibbs case AMBI_ERROR: 120939225Sgibbs /* An error occured */ 121042887Simp if (accb->hccb.opcode < INITIATOR_CCB_WRESID) 121142887Simp csio->resid = 0; 121242887Simp else 121342887Simp csio->resid = aha_a24tou(accb->hccb.data_len); 121441047Sgibbs switch(accb->hccb.ahastat) { 121539225Sgibbs case AHASTAT_DATARUN_ERROR: 121642013Sgibbs { 121742013Sgibbs if (csio->resid <= 0) { 121839225Sgibbs csio->ccb_h.status = CAM_DATA_RUN_ERR; 121939225Sgibbs break; 122039225Sgibbs } 122139225Sgibbs /* FALLTHROUGH */ 122242013Sgibbs } 122339225Sgibbs case AHASTAT_NOERROR: 122441047Sgibbs csio->scsi_status = accb->hccb.sdstat; 122539225Sgibbs csio->ccb_h.status |= CAM_SCSI_STATUS_ERROR; 122639225Sgibbs switch(csio->scsi_status) { 122739225Sgibbs case SCSI_STATUS_CHECK_COND: 122839225Sgibbs case SCSI_STATUS_CMD_TERMINATED: 122939225Sgibbs csio->ccb_h.status |= CAM_AUTOSNS_VALID; 123039225Sgibbs /* 123139225Sgibbs * The aha writes the sense data at different 123239225Sgibbs * offsets based on the scsi cmd len 123339225Sgibbs */ 123441047Sgibbs bcopy((caddr_t) &accb->hccb.scsi_cdb + 1235122363Simp accb->hccb.cmd_len, 1236122340Simp (caddr_t) &csio->sense_data, 1237122340Simp accb->hccb.sense_len); 123839225Sgibbs break; 123939225Sgibbs default: 124039225Sgibbs break; 124139225Sgibbs case SCSI_STATUS_OK: 124239225Sgibbs csio->ccb_h.status = CAM_REQ_CMP; 124339225Sgibbs break; 124439225Sgibbs } 124539225Sgibbs break; 124639225Sgibbs case AHASTAT_SELTIMEOUT: 124739225Sgibbs csio->ccb_h.status = CAM_SEL_TIMEOUT; 124839225Sgibbs break; 124939225Sgibbs case AHASTAT_UNEXPECTED_BUSFREE: 125039225Sgibbs csio->ccb_h.status = CAM_UNEXP_BUSFREE; 125139225Sgibbs break; 125239225Sgibbs case AHASTAT_INVALID_PHASE: 125339225Sgibbs csio->ccb_h.status = CAM_SEQUENCE_FAIL; 125439225Sgibbs break; 125539225Sgibbs case AHASTAT_INVALID_ACTION_CODE: 125639225Sgibbs panic("%s: Inavlid Action code", aha_name(aha)); 125739225Sgibbs break; 125839225Sgibbs case AHASTAT_INVALID_OPCODE: 125942887Simp if (accb->hccb.opcode < INITIATOR_CCB_WRESID) 126042887Simp panic("%s: Invalid CCB Opcode %x hccb = %p", 1261122340Simp aha_name(aha), accb->hccb.opcode, 1262122340Simp &accb->hccb); 1263122597Simp device_printf(aha->dev, 1264140025Simp "AHA-1540A compensation failed\n"); 126542887Simp xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 126642887Simp csio->ccb_h.status = CAM_REQUEUE_REQ; 126739225Sgibbs break; 126839225Sgibbs case AHASTAT_LINKED_CCB_LUN_MISMATCH: 126939225Sgibbs /* We don't even support linked commands... */ 127039225Sgibbs panic("%s: Linked CCB Lun Mismatch", aha_name(aha)); 127139225Sgibbs break; 127239225Sgibbs case AHASTAT_INVALID_CCB_OR_SG_PARAM: 127339225Sgibbs panic("%s: Invalid CCB or SG list", aha_name(aha)); 127439225Sgibbs break; 127539225Sgibbs case AHASTAT_HA_SCSI_BUS_RESET: 127639225Sgibbs if ((csio->ccb_h.status & CAM_STATUS_MASK) 127742887Simp != CAM_CMD_TIMEOUT) 127839225Sgibbs csio->ccb_h.status = CAM_SCSI_BUS_RESET; 127939225Sgibbs break; 128039225Sgibbs case AHASTAT_HA_BDR: 128141047Sgibbs if ((accb->flags & ACCB_DEVICE_RESET) == 0) 128239225Sgibbs csio->ccb_h.status = CAM_BDR_SENT; 128339225Sgibbs else 128439225Sgibbs csio->ccb_h.status = CAM_CMD_TIMEOUT; 128539225Sgibbs break; 128639225Sgibbs } 128739225Sgibbs if (csio->ccb_h.status != CAM_REQ_CMP) { 128839225Sgibbs xpt_freeze_devq(csio->ccb_h.path, /*count*/1); 128939225Sgibbs csio->ccb_h.status |= CAM_DEV_QFRZN; 129039225Sgibbs } 129141047Sgibbs if ((accb->flags & ACCB_RELEASE_SIMQ) != 0) 129239225Sgibbs ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 129341047Sgibbs ahafreeccb(aha, accb); 129439225Sgibbs xpt_done(ccb); 129539225Sgibbs break; 129641047Sgibbs case AMBI_OK: 129739225Sgibbs /* All completed without incident */ 129839225Sgibbs /* XXX DO WE NEED TO COPY SENSE BYTES HERE???? XXX */ 129942887Simp /* I don't think so since it works???? */ 130039225Sgibbs ccb->ccb_h.status |= CAM_REQ_CMP; 130141047Sgibbs if ((accb->flags & ACCB_RELEASE_SIMQ) != 0) 130239225Sgibbs ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 130341047Sgibbs ahafreeccb(aha, accb); 130439225Sgibbs xpt_done(ccb); 130539225Sgibbs break; 130639225Sgibbs } 130739225Sgibbs} 130839225Sgibbs 130939225Sgibbsstatic int 131039225Sgibbsahareset(struct aha_softc* aha, int hard_reset) 131139225Sgibbs{ 131239225Sgibbs struct ccb_hdr *ccb_h; 131339225Sgibbs u_int status; 131439225Sgibbs u_int timeout; 1315122340Simp uint8_t reset_type; 131639225Sgibbs 131739225Sgibbs if (hard_reset != 0) 131839225Sgibbs reset_type = HARD_RESET; 131939225Sgibbs else 132039225Sgibbs reset_type = SOFT_RESET; 132139225Sgibbs aha_outb(aha, CONTROL_REG, reset_type); 132239225Sgibbs 132339225Sgibbs /* Wait 5sec. for Diagnostic start */ 132439225Sgibbs timeout = 5 * 10000; 132539225Sgibbs while (--timeout) { 132639225Sgibbs status = aha_inb(aha, STATUS_REG); 132739225Sgibbs if ((status & DIAG_ACTIVE) != 0) 132839225Sgibbs break; 132939225Sgibbs DELAY(100); 133039225Sgibbs } 133139225Sgibbs if (timeout == 0) { 1332122597Simp PRVERB((aha->dev, "ahareset - Diagnostic Active failed to " 1333122597Simp "assert. status = %#x\n", status)); 133439225Sgibbs return (ETIMEDOUT); 133539225Sgibbs } 133639225Sgibbs 133739225Sgibbs /* Wait 10sec. for Diagnostic end */ 133839225Sgibbs timeout = 10 * 10000; 133939225Sgibbs while (--timeout) { 134039225Sgibbs status = aha_inb(aha, STATUS_REG); 134139225Sgibbs if ((status & DIAG_ACTIVE) == 0) 134239225Sgibbs break; 134339225Sgibbs DELAY(100); 134439225Sgibbs } 134539225Sgibbs if (timeout == 0) { 134639225Sgibbs panic("%s: ahareset - Diagnostic Active failed to drop. " 1347122340Simp "status = 0x%x\n", aha_name(aha), status); 134839225Sgibbs return (ETIMEDOUT); 134939225Sgibbs } 135039225Sgibbs 135139225Sgibbs /* Wait for the host adapter to become ready or report a failure */ 135239225Sgibbs timeout = 10000; 135339225Sgibbs while (--timeout) { 135439225Sgibbs status = aha_inb(aha, STATUS_REG); 135539225Sgibbs if ((status & (DIAG_FAIL|HA_READY|DATAIN_REG_READY)) != 0) 135639225Sgibbs break; 135739225Sgibbs DELAY(100); 135839225Sgibbs } 135939225Sgibbs if (timeout == 0) { 1360122597Simp device_printf(aha->dev, "ahareset - Host adapter failed to " 1361122597Simp "come ready. status = 0x%x\n", status); 136239225Sgibbs return (ETIMEDOUT); 136339225Sgibbs } 136439225Sgibbs 136539225Sgibbs /* If the diagnostics failed, tell the user */ 136639225Sgibbs if ((status & DIAG_FAIL) != 0 136739225Sgibbs || (status & HA_READY) == 0) { 1368122597Simp device_printf(aha->dev, "ahareset - Adapter failed diag\n"); 136939225Sgibbs 137039225Sgibbs if ((status & DATAIN_REG_READY) != 0) 1371122597Simp device_printf(aha->dev, "ahareset - Host Adapter " 1372122597Simp "Error code = 0x%x\n", aha_inb(aha, DATAIN_REG)); 137339225Sgibbs return (ENXIO); 137439225Sgibbs } 137539225Sgibbs 137639225Sgibbs /* If we've attached to the XPT, tell it about the event */ 137739225Sgibbs if (aha->path != NULL) 137839225Sgibbs xpt_async(AC_BUS_RESET, aha->path, NULL); 137939225Sgibbs 138039225Sgibbs /* 138139225Sgibbs * Perform completion processing for all outstanding CCBs. 138239225Sgibbs */ 138339225Sgibbs while ((ccb_h = LIST_FIRST(&aha->pending_ccbs)) != NULL) { 138441047Sgibbs struct aha_ccb *pending_accb; 138539225Sgibbs 138641047Sgibbs pending_accb = (struct aha_ccb *)ccb_h->ccb_accb_ptr; 138741047Sgibbs pending_accb->hccb.ahastat = AHASTAT_HA_SCSI_BUS_RESET; 138841047Sgibbs ahadone(aha, pending_accb, AMBI_ERROR); 138939225Sgibbs } 139039225Sgibbs 1391122360Simp /* If we've allocated mailboxes, initialize them */ 1392122360Simp /* Must be done after we've aborted our queue, or aha_cmd fails */ 1393122360Simp if (aha->init_level > 4) 1394122360Simp ahainitmboxes(aha); 1395122360Simp 139639225Sgibbs return (0); 139739225Sgibbs} 139839225Sgibbs 139939225Sgibbs/* 140039225Sgibbs * Send a command to the adapter. 140139225Sgibbs */ 140239225Sgibbsint 1403122363Simpaha_cmd(struct aha_softc *aha, aha_op_t opcode, uint8_t *params, 1404122363Simp u_int param_len, uint8_t *reply_data, u_int reply_len, 140547506Sgibbs u_int cmd_timeout) 140639225Sgibbs{ 140739225Sgibbs u_int timeout; 140839225Sgibbs u_int status; 140947506Sgibbs u_int saved_status; 141039225Sgibbs u_int intstat; 141139225Sgibbs u_int reply_buf_size; 141241709Sgibbs int cmd_complete; 141347506Sgibbs int error; 141439225Sgibbs 141539225Sgibbs /* No data returned to start */ 141639225Sgibbs reply_buf_size = reply_len; 141739225Sgibbs reply_len = 0; 141839225Sgibbs intstat = 0; 141941709Sgibbs cmd_complete = 0; 142047506Sgibbs saved_status = 0; 142147506Sgibbs error = 0; 142239225Sgibbs 142347506Sgibbs /* 142447506Sgibbs * All commands except for the "start mailbox" and the "enable 142547506Sgibbs * outgoing mailbox read interrupt" commands cannot be issued 142647506Sgibbs * while there are pending transactions. Freeze our SIMQ 142747506Sgibbs * and wait for all completions to occur if necessary. 142847506Sgibbs */ 1429122360Simp timeout = 10000; 143047506Sgibbs while (LIST_FIRST(&aha->pending_ccbs) != NULL && --timeout) { 143147506Sgibbs /* Fire the interrupt handler in case interrupts are blocked */ 143247506Sgibbs aha_intr(aha); 1433122360Simp DELAY(10); 143447506Sgibbs } 143547506Sgibbs 143647506Sgibbs if (timeout == 0) { 1437122597Simp device_printf(aha->dev, 1438122597Simp "aha_cmd: Timeout waiting for adapter idle\n"); 143947506Sgibbs return (ETIMEDOUT); 144047506Sgibbs } 144139225Sgibbs aha->command_cmp = 0; 144239225Sgibbs /* 144347506Sgibbs * Wait up to 10 sec. for the adapter to become 144439225Sgibbs * ready to accept commands. 144539225Sgibbs */ 144647506Sgibbs timeout = 100000; 144739225Sgibbs while (--timeout) { 144839225Sgibbs status = aha_inb(aha, STATUS_REG); 1449122340Simp if ((status & HA_READY) != 0 && (status & CMD_REG_BUSY) == 0) 145039225Sgibbs break; 145147506Sgibbs /* 145247506Sgibbs * Throw away any pending data which may be 145347506Sgibbs * left over from earlier commands that we 145447506Sgibbs * timedout on. 145547506Sgibbs */ 145647506Sgibbs if ((status & DATAIN_REG_READY) != 0) 145747506Sgibbs (void)aha_inb(aha, DATAIN_REG); 145839225Sgibbs DELAY(100); 145939225Sgibbs } 146039225Sgibbs if (timeout == 0) { 1461122597Simp device_printf(aha->dev, "aha_cmd: Timeout waiting for adapter" 1462122597Simp " ready, status = 0x%x\n", status); 146339225Sgibbs return (ETIMEDOUT); 146439225Sgibbs } 146539225Sgibbs 146639225Sgibbs /* 146739225Sgibbs * Send the opcode followed by any necessary parameter bytes. 146839225Sgibbs */ 146939225Sgibbs aha_outb(aha, COMMAND_REG, opcode); 147039225Sgibbs 147139225Sgibbs /* 147239225Sgibbs * Wait for up to 1sec to get the parameter list sent 147339225Sgibbs */ 147439225Sgibbs timeout = 10000; 147539225Sgibbs while (param_len && --timeout) { 147639225Sgibbs DELAY(100); 147739225Sgibbs status = aha_inb(aha, STATUS_REG); 147839225Sgibbs intstat = aha_inb(aha, INTSTAT_REG); 147947506Sgibbs 148039225Sgibbs if ((intstat & (INTR_PENDING|CMD_COMPLETE)) 148141709Sgibbs == (INTR_PENDING|CMD_COMPLETE)) { 148247506Sgibbs saved_status = status; 148341709Sgibbs cmd_complete = 1; 148439225Sgibbs break; 148541709Sgibbs } 148647506Sgibbs 148739225Sgibbs if (aha->command_cmp != 0) { 148847506Sgibbs saved_status = aha->latched_status; 148941709Sgibbs cmd_complete = 1; 149039225Sgibbs break; 149139225Sgibbs } 149239225Sgibbs if ((status & DATAIN_REG_READY) != 0) 149339225Sgibbs break; 149439225Sgibbs if ((status & CMD_REG_BUSY) == 0) { 149539225Sgibbs aha_outb(aha, COMMAND_REG, *params++); 149639225Sgibbs param_len--; 149747506Sgibbs timeout = 10000; 149839225Sgibbs } 149939225Sgibbs } 150039225Sgibbs if (timeout == 0) { 1501122597Simp device_printf(aha->dev, "aha_cmd: Timeout sending parameters, " 1502122597Simp "status = 0x%x\n", status); 150347506Sgibbs error = ETIMEDOUT; 150439225Sgibbs } 150539225Sgibbs 150639225Sgibbs /* 150739225Sgibbs * For all other commands, we wait for any output data 150839225Sgibbs * and the final comand completion interrupt. 150939225Sgibbs */ 151041709Sgibbs while (cmd_complete == 0 && --cmd_timeout) { 151139225Sgibbs 151239225Sgibbs status = aha_inb(aha, STATUS_REG); 151339225Sgibbs intstat = aha_inb(aha, INTSTAT_REG); 151439225Sgibbs 151539225Sgibbs if (aha->command_cmp != 0) { 151647506Sgibbs cmd_complete = 1; 151747506Sgibbs saved_status = aha->latched_status; 151847506Sgibbs } else if ((intstat & (INTR_PENDING|CMD_COMPLETE)) 151947506Sgibbs == (INTR_PENDING|CMD_COMPLETE)) { 152047506Sgibbs /* 152147506Sgibbs * Our poll (in case interrupts are blocked) 152247506Sgibbs * saw the CMD_COMPLETE interrupt. 152347506Sgibbs */ 152447506Sgibbs cmd_complete = 1; 152547506Sgibbs saved_status = status; 152651869Smdodd } 152751869Smdodd if ((status & DATAIN_REG_READY) != 0) { 1528122340Simp uint8_t data; 152939225Sgibbs 153039225Sgibbs data = aha_inb(aha, DATAIN_REG); 153139225Sgibbs if (reply_len < reply_buf_size) { 153239225Sgibbs *reply_data++ = data; 153339225Sgibbs } else { 1534122597Simp device_printf(aha->dev, 1535122597Simp "aha_cmd - Discarded reply data " 1536122597Simp "byte for opcode 0x%x\n", opcode); 153739225Sgibbs } 153847506Sgibbs /* 153947506Sgibbs * Reset timeout to ensure at least a second 154047506Sgibbs * between response bytes. 154147506Sgibbs */ 154247506Sgibbs cmd_timeout = MAX(cmd_timeout, 10000); 154339225Sgibbs reply_len++; 154439225Sgibbs } 154539225Sgibbs DELAY(100); 154639225Sgibbs } 154747506Sgibbs if (cmd_timeout == 0) { 1548122597Simp device_printf(aha->dev, "aha_cmd: Timeout: status = 0x%x, " 1549122597Simp "intstat = 0x%x, reply_len = %d\n", status, intstat, 1550122597Simp reply_len); 155139225Sgibbs return (ETIMEDOUT); 155239225Sgibbs } 155339225Sgibbs 155439225Sgibbs /* 155539225Sgibbs * Clear any pending interrupts. Block interrupts so our 155639225Sgibbs * interrupt handler is not re-entered. 155739225Sgibbs */ 155839225Sgibbs aha_intr(aha); 1559122363Simp 156047506Sgibbs if (error != 0) 156147506Sgibbs return (error); 156247506Sgibbs 156339225Sgibbs /* 156439225Sgibbs * If the command was rejected by the controller, tell the caller. 156539225Sgibbs */ 156647506Sgibbs if ((saved_status & CMD_INVALID) != 0) { 1567122597Simp PRVERB((aha->dev, "Invalid Command 0x%x\n", opcode)); 156839225Sgibbs /* 156939225Sgibbs * Some early adapters may not recover properly from 157039225Sgibbs * an invalid command. If it appears that the controller 157139225Sgibbs * has wedged (i.e. status was not cleared by our interrupt 157239225Sgibbs * reset above), perform a soft reset. 157339225Sgibbs */ 157439225Sgibbs DELAY(1000); 157539225Sgibbs status = aha_inb(aha, STATUS_REG); 157639225Sgibbs if ((status & (CMD_INVALID|STATUS_REG_RSVD|DATAIN_REG_READY| 157739225Sgibbs CMD_REG_BUSY|DIAG_FAIL|DIAG_ACTIVE)) != 0 157839225Sgibbs || (status & (HA_READY|INIT_REQUIRED)) 1579122340Simp != (HA_READY|INIT_REQUIRED)) 158039852Simp ahareset(aha, /*hard_reset*/FALSE); 158139225Sgibbs return (EINVAL); 158239225Sgibbs } 158339225Sgibbs 158439225Sgibbs if (param_len > 0) { 158539225Sgibbs /* The controller did not accept the full argument list */ 1586122597Simp PRVERB((aha->dev, "Controller did not accept full argument " 1587122597Simp "list (%d > 0)\n", param_len)); 158839225Sgibbs return (E2BIG); 158939225Sgibbs } 159039225Sgibbs 159139225Sgibbs if (reply_len != reply_buf_size) { 159239225Sgibbs /* Too much or too little data received */ 1593122597Simp PRVERB((aha->dev, "data received mismatch (%d != %d)\n", 1594122597Simp reply_len, reply_buf_size)); 159539225Sgibbs return (EMSGSIZE); 159639225Sgibbs } 159739225Sgibbs 159839225Sgibbs /* We were successful */ 159939225Sgibbs return (0); 160039225Sgibbs} 160139225Sgibbs 160239225Sgibbsstatic int 1603122363Simpahainitmboxes(struct aha_softc *aha) 160439225Sgibbs{ 160539225Sgibbs int error; 160639225Sgibbs init_24b_mbox_params_t init_mbox; 160739225Sgibbs 160839225Sgibbs bzero(aha->in_boxes, sizeof(aha_mbox_in_t) * aha->num_boxes); 160939225Sgibbs bzero(aha->out_boxes, sizeof(aha_mbox_out_t) * aha->num_boxes); 161039225Sgibbs aha->cur_inbox = aha->in_boxes; 161139225Sgibbs aha->last_inbox = aha->in_boxes + aha->num_boxes - 1; 161239225Sgibbs aha->cur_outbox = aha->out_boxes; 161339225Sgibbs aha->last_outbox = aha->out_boxes + aha->num_boxes - 1; 161439225Sgibbs 161539225Sgibbs /* Tell the adapter about them */ 161639225Sgibbs init_mbox.num_mboxes = aha->num_boxes; 161739225Sgibbs ahautoa24(aha->mailbox_physbase, init_mbox.base_addr); 1618122340Simp error = aha_cmd(aha, AOP_INITIALIZE_MBOX, (uint8_t *)&init_mbox, 1619122340Simp /*parmlen*/sizeof(init_mbox), /*reply_buf*/NULL, 1620122340Simp /*reply_len*/0, DEFAULT_CMD_TIMEOUT); 162139225Sgibbs 162239225Sgibbs if (error != 0) 162339225Sgibbs printf("ahainitmboxes: Initialization command failed\n"); 162439225Sgibbs return (error); 162539225Sgibbs} 162639225Sgibbs 162739225Sgibbs/* 162839225Sgibbs * Update the XPT's idea of the negotiated transfer 162939225Sgibbs * parameters for a particular target. 163039225Sgibbs */ 163139225Sgibbsstatic void 163239225Sgibbsahafetchtransinfo(struct aha_softc *aha, struct ccb_trans_settings* cts) 163339225Sgibbs{ 163439225Sgibbs setup_data_t setup_info; 163539225Sgibbs u_int target; 163639225Sgibbs u_int targ_offset; 163739225Sgibbs u_int sync_period; 163839225Sgibbs int error; 1639122340Simp uint8_t param; 164039225Sgibbs targ_syncinfo_t sync_info; 1641163816Smjacob struct ccb_trans_settings_spi *spi = &cts->xport_specific.spi; 164239225Sgibbs 164339225Sgibbs target = cts->ccb_h.target_id; 164439225Sgibbs targ_offset = (target & 0x7); 164539225Sgibbs 164639225Sgibbs /* 164747208Simp * Inquire Setup Information. This command retreives 164847506Sgibbs * the sync info for older models. 164939225Sgibbs */ 165039225Sgibbs param = sizeof(setup_info); 165141047Sgibbs error = aha_cmd(aha, AOP_INQUIRE_SETUP_INFO, ¶m, /*paramlen*/1, 1652122340Simp (uint8_t*)&setup_info, sizeof(setup_info), DEFAULT_CMD_TIMEOUT); 165339225Sgibbs 165439225Sgibbs if (error != 0) { 1655122597Simp device_printf(aha->dev, 1656122597Simp "ahafetchtransinfo - Inquire Setup Info Failed %d\n", 1657122597Simp error); 165839225Sgibbs return; 165939225Sgibbs } 166039225Sgibbs 166139225Sgibbs sync_info = setup_info.syncinfo[targ_offset]; 166239225Sgibbs 166339225Sgibbs if (sync_info.sync == 0) 1664163816Smjacob spi->sync_offset = 0; 1665163816Smjacob else 1666163816Smjacob spi->sync_offset = sync_info.offset; 1667163816Smjacob 1668163816Smjacob spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 1669163816Smjacob 1670163816Smjacob if (aha->boardid >= BOARD_1542CF) 1671163816Smjacob sync_period = 1000; 1672163816Smjacob else 1673163816Smjacob sync_period = 2000; 1674163816Smjacob sync_period += 500 * sync_info.period; 1675163816Smjacob 1676163816Smjacob /* Convert ns value to standard SCSI sync rate */ 1677163816Smjacob if (spi->sync_offset != 0) 1678163816Smjacob spi->sync_period = scsi_calc_syncparam(sync_period); 1679163816Smjacob else 1680163816Smjacob spi->sync_period = 0; 1681163816Smjacob 1682163816Smjacob spi->valid = CTS_SPI_VALID_SYNC_RATE 1683163816Smjacob | CTS_SPI_VALID_SYNC_OFFSET 1684163816Smjacob | CTS_SPI_VALID_BUS_WIDTH; 168539225Sgibbs xpt_async(AC_TRANSFER_NEG, cts->ccb_h.path, cts); 168639225Sgibbs} 168739225Sgibbs 168839225Sgibbsstatic void 168939225Sgibbsahamapmboxes(void *arg, bus_dma_segment_t *segs, int nseg, int error) 169039225Sgibbs{ 169139225Sgibbs struct aha_softc* aha; 169239225Sgibbs 169339225Sgibbs aha = (struct aha_softc*)arg; 169439225Sgibbs aha->mailbox_physbase = segs->ds_addr; 169539225Sgibbs} 169639225Sgibbs 169739225Sgibbsstatic void 169839225Sgibbsahamapccbs(void *arg, bus_dma_segment_t *segs, int nseg, int error) 169939225Sgibbs{ 170039225Sgibbs struct aha_softc* aha; 170139225Sgibbs 170239225Sgibbs aha = (struct aha_softc*)arg; 170339225Sgibbs aha->aha_ccb_physbase = segs->ds_addr; 170439225Sgibbs} 170539225Sgibbs 170639225Sgibbsstatic void 170739225Sgibbsahamapsgs(void *arg, bus_dma_segment_t *segs, int nseg, int error) 170839225Sgibbs{ 170939225Sgibbs 171039225Sgibbs struct aha_softc* aha; 171139225Sgibbs 171239225Sgibbs aha = (struct aha_softc*)arg; 171339225Sgibbs SLIST_FIRST(&aha->sg_maps)->sg_physaddr = segs->ds_addr; 171439225Sgibbs} 171539225Sgibbs 171639225Sgibbsstatic void 171739225Sgibbsahapoll(struct cam_sim *sim) 171839225Sgibbs{ 1719241589Sjhb aha_intr_locked(cam_sim_softc(sim)); 172039225Sgibbs} 172139225Sgibbs 172245575Seivindstatic void 172339225Sgibbsahatimeout(void *arg) 172439225Sgibbs{ 172541047Sgibbs struct aha_ccb *accb; 172639225Sgibbs union ccb *ccb; 172739225Sgibbs struct aha_softc *aha; 1728122340Simp uint32_t paddr; 1729122360Simp struct ccb_hdr *ccb_h; 173039225Sgibbs 173141047Sgibbs accb = (struct aha_ccb *)arg; 173241047Sgibbs ccb = accb->ccb; 173339225Sgibbs aha = (struct aha_softc *)ccb->ccb_h.ccb_aha_ptr; 1734241589Sjhb mtx_assert(&aha->lock, MA_OWNED); 173539225Sgibbs xpt_print_path(ccb->ccb_h.path); 173641047Sgibbs printf("CCB %p - timed out\n", (void *)accb); 173739225Sgibbs 173841047Sgibbs if ((accb->flags & ACCB_ACTIVE) == 0) { 173939225Sgibbs xpt_print_path(ccb->ccb_h.path); 174039390Sgibbs printf("CCB %p - timed out CCB already completed\n", 1741122340Simp (void *)accb); 174239225Sgibbs return; 174339225Sgibbs } 174439225Sgibbs 174539225Sgibbs /* 174639225Sgibbs * In order to simplify the recovery process, we ask the XPT 174739225Sgibbs * layer to halt the queue of new transactions and we traverse 174839225Sgibbs * the list of pending CCBs and remove their timeouts. This 174939225Sgibbs * means that the driver attempts to clear only one error 175039225Sgibbs * condition at a time. In general, timeouts that occur 175139225Sgibbs * close together are related anyway, so there is no benefit 175239225Sgibbs * in attempting to handle errors in parrallel. Timeouts will 175339225Sgibbs * be reinstated when the recovery process ends. 175439225Sgibbs */ 175541047Sgibbs if ((accb->flags & ACCB_DEVICE_RESET) == 0) { 175641047Sgibbs if ((accb->flags & ACCB_RELEASE_SIMQ) == 0) { 175739225Sgibbs xpt_freeze_simq(aha->sim, /*count*/1); 175841047Sgibbs accb->flags |= ACCB_RELEASE_SIMQ; 175939225Sgibbs } 176039225Sgibbs 176139225Sgibbs ccb_h = LIST_FIRST(&aha->pending_ccbs); 176239225Sgibbs while (ccb_h != NULL) { 176341047Sgibbs struct aha_ccb *pending_accb; 176439225Sgibbs 176541047Sgibbs pending_accb = (struct aha_ccb *)ccb_h->ccb_accb_ptr; 1766241589Sjhb callout_stop(&pending_accb->timer); 176739225Sgibbs ccb_h = LIST_NEXT(ccb_h, sim_links.le); 176839225Sgibbs } 176939225Sgibbs } 177039225Sgibbs 177141047Sgibbs if ((accb->flags & ACCB_DEVICE_RESET) != 0 177241047Sgibbs || aha->cur_outbox->action_code != AMBO_FREE) { 177339225Sgibbs /* 177439225Sgibbs * Try a full host adapter/SCSI bus reset. 177539225Sgibbs * We do this only if we have already attempted 177639225Sgibbs * to clear the condition with a BDR, or we cannot 177739225Sgibbs * attempt a BDR for lack of mailbox resources. 177839225Sgibbs */ 177939225Sgibbs ccb->ccb_h.status = CAM_CMD_TIMEOUT; 178039225Sgibbs ahareset(aha, /*hardreset*/TRUE); 1781122597Simp device_printf(aha->dev, "No longer in timeout\n"); 178239225Sgibbs } else { 1783122363Simp /* 178439225Sgibbs * Send a Bus Device Reset message: 178539225Sgibbs * The target that is holding up the bus may not 178639225Sgibbs * be the same as the one that triggered this timeout 178739225Sgibbs * (different commands have different timeout lengths), 178839225Sgibbs * but we have no way of determining this from our 178939225Sgibbs * timeout handler. Our strategy here is to queue a 179039225Sgibbs * BDR message to the target of the timed out command. 179139225Sgibbs * If this fails, we'll get another timeout 2 seconds 179239225Sgibbs * later which will attempt a bus reset. 179339225Sgibbs */ 179441047Sgibbs accb->flags |= ACCB_DEVICE_RESET; 1795241603Sglebius callout_reset(&accb->timer, 2 * hz, ahatimeout, accb); 179641047Sgibbs aha->recovery_accb->hccb.opcode = INITIATOR_BUS_DEV_RESET; 179739225Sgibbs 179839225Sgibbs /* No Data Transfer */ 179941047Sgibbs aha->recovery_accb->hccb.datain = TRUE; 180041047Sgibbs aha->recovery_accb->hccb.dataout = TRUE; 180141047Sgibbs aha->recovery_accb->hccb.ahastat = 0; 180241047Sgibbs aha->recovery_accb->hccb.sdstat = 0; 180341047Sgibbs aha->recovery_accb->hccb.target = ccb->ccb_h.target_id; 180439225Sgibbs 180539225Sgibbs /* Tell the adapter about this command */ 180641047Sgibbs paddr = ahaccbvtop(aha, aha->recovery_accb); 180739225Sgibbs ahautoa24(paddr, aha->cur_outbox->ccb_addr); 180841047Sgibbs aha->cur_outbox->action_code = AMBO_START; 180941047Sgibbs aha_outb(aha, COMMAND_REG, AOP_START_MBOX); 181039225Sgibbs ahanextoutbox(aha); 181139225Sgibbs } 181239225Sgibbs} 181356504Simp 181456504Simpint 181556504Simpaha_detach(struct aha_softc *aha) 181656504Simp{ 1817241589Sjhb mtx_lock(&aha->lock); 181856504Simp xpt_async(AC_LOST_DEVICE, aha->path, NULL); 181956504Simp xpt_free_path(aha->path); 182056504Simp xpt_bus_deregister(cam_sim_path(aha->sim)); 182156504Simp cam_sim_free(aha->sim, /*free_devq*/TRUE); 1822241589Sjhb mtx_unlock(&aha->lock); 1823241589Sjhb /* XXX: Drain all timers? */ 182456504Simp return (0); 182556504Simp} 1826165102SmjacobMODULE_DEPEND(aha, cam, 1, 1, 1); 1827