aha.c revision 170872
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: head/sys/dev/aha/aha.c 170872 2007-06-17 05:55:54Z scottl $"); 62119418Sobrien 6339225Sgibbs#include <sys/param.h> 64122597Simp#include <sys/bus.h> 65122363Simp#include <sys/systm.h> 6639225Sgibbs#include <sys/malloc.h> 6739225Sgibbs#include <sys/kernel.h> 68117126Sscottl#include <sys/lock.h> 69165102Smjacob#include <sys/module.h> 70117126Sscottl#include <sys/mutex.h> 71122363Simp 7239225Sgibbs#include <machine/bus.h> 7339225Sgibbs 7439225Sgibbs#include <cam/cam.h> 7539225Sgibbs#include <cam/cam_ccb.h> 7639225Sgibbs#include <cam/cam_sim.h> 7739225Sgibbs#include <cam/cam_xpt_sim.h> 7839225Sgibbs#include <cam/cam_debug.h> 7939225Sgibbs 8039225Sgibbs#include <cam/scsi/scsi_message.h> 8139225Sgibbs 8239225Sgibbs#include <dev/aha/ahareg.h> 8339225Sgibbs 84122597Simp#define PRVERB(x) do { if (bootverbose) device_printf x; } while (0) 8539225Sgibbs 8639751Simp/* Macro to determine that a rev is potentially a new valid one 8739751Simp * so that the driver doesn't keep breaking on new revs as it 8839751Simp * did for the CF and CP. 8939751Simp */ 9039751Simp#define PROBABLY_NEW_BOARD(REV) (REV > 0x43 && REV < 0x56) 9139751Simp 9239225Sgibbs/* MailBox Management functions */ 9339225Sgibbsstatic __inline void ahanextinbox(struct aha_softc *aha); 9439225Sgibbsstatic __inline void ahanextoutbox(struct aha_softc *aha); 9539225Sgibbs 96122597Simp#define aha_name(aha) device_get_nameunit(aha->dev) 97122597Simp 9839225Sgibbsstatic __inline void 9939225Sgibbsahanextinbox(struct aha_softc *aha) 10039225Sgibbs{ 10139225Sgibbs if (aha->cur_inbox == aha->last_inbox) 10239225Sgibbs aha->cur_inbox = aha->in_boxes; 10339225Sgibbs else 10439225Sgibbs aha->cur_inbox++; 10539225Sgibbs} 10639225Sgibbs 10739225Sgibbsstatic __inline void 10839225Sgibbsahanextoutbox(struct aha_softc *aha) 10939225Sgibbs{ 11039225Sgibbs if (aha->cur_outbox == aha->last_outbox) 11139225Sgibbs aha->cur_outbox = aha->out_boxes; 11239225Sgibbs else 11339225Sgibbs aha->cur_outbox++; 11439225Sgibbs} 11539225Sgibbs 11639225Sgibbs#define ahautoa24(u,s3) \ 11739225Sgibbs (s3)[0] = ((u) >> 16) & 0xff; \ 11839225Sgibbs (s3)[1] = ((u) >> 8) & 0xff; \ 11939225Sgibbs (s3)[2] = (u) & 0xff; 12039225Sgibbs 12139225Sgibbs#define aha_a24tou(s3) \ 12239225Sgibbs (((s3)[0] << 16) | ((s3)[1] << 8) | (s3)[2]) 12339225Sgibbs 12439225Sgibbs/* CCB Mangement functions */ 125122340Simpstatic __inline uint32_t ahaccbvtop(struct aha_softc *aha, 12641047Sgibbs struct aha_ccb *accb); 12739225Sgibbsstatic __inline struct aha_ccb* ahaccbptov(struct aha_softc *aha, 128122340Simp uint32_t ccb_addr); 12939225Sgibbs 130122340Simpstatic __inline uint32_t 13141047Sgibbsahaccbvtop(struct aha_softc *aha, struct aha_ccb *accb) 13239225Sgibbs{ 13339225Sgibbs return (aha->aha_ccb_physbase 134122340Simp + (uint32_t)((caddr_t)accb - (caddr_t)aha->aha_ccb_array)); 13539225Sgibbs} 13639225Sgibbsstatic __inline struct aha_ccb * 137122340Simpahaccbptov(struct aha_softc *aha, uint32_t ccb_addr) 13839225Sgibbs{ 13939225Sgibbs return (aha->aha_ccb_array + 140104713Speter + ((struct aha_ccb*)(uintptr_t)ccb_addr - 141104713Speter (struct aha_ccb*)(uintptr_t)aha->aha_ccb_physbase)); 14239225Sgibbs} 14339225Sgibbs 14439225Sgibbsstatic struct aha_ccb* ahagetccb(struct aha_softc *aha); 14541047Sgibbsstatic __inline void ahafreeccb(struct aha_softc *aha, struct aha_ccb *accb); 14639225Sgibbsstatic void ahaallocccbs(struct aha_softc *aha); 14739225Sgibbsstatic bus_dmamap_callback_t ahaexecuteccb; 14841047Sgibbsstatic void ahadone(struct aha_softc *aha, struct aha_ccb *accb, 14939225Sgibbs aha_mbi_comp_code_t comp_code); 15039225Sgibbs 15139225Sgibbs/* Host adapter command functions */ 15239225Sgibbsstatic int ahareset(struct aha_softc* aha, int hard_reset); 15339225Sgibbs 15439225Sgibbs/* Initialization functions */ 15539225Sgibbsstatic int ahainitmboxes(struct aha_softc *aha); 15639225Sgibbsstatic bus_dmamap_callback_t ahamapmboxes; 15739225Sgibbsstatic bus_dmamap_callback_t ahamapccbs; 15839225Sgibbsstatic bus_dmamap_callback_t ahamapsgs; 15939225Sgibbs 16039225Sgibbs/* Transfer Negotiation Functions */ 16139225Sgibbsstatic void ahafetchtransinfo(struct aha_softc *aha, 16239225Sgibbs struct ccb_trans_settings *cts); 16339225Sgibbs 16439225Sgibbs/* CAM SIM entry points */ 16541047Sgibbs#define ccb_accb_ptr spriv_ptr0 16639225Sgibbs#define ccb_aha_ptr spriv_ptr1 16739225Sgibbsstatic void ahaaction(struct cam_sim *sim, union ccb *ccb); 16839225Sgibbsstatic void ahapoll(struct cam_sim *sim); 16939225Sgibbs 17039225Sgibbs/* Our timeout handler */ 17146602Speterstatic timeout_t ahatimeout; 17239225Sgibbs 17339225Sgibbs/* Exported functions */ 174122361Simpvoid 175122361Simpaha_alloc(struct aha_softc *aha, int unit, bus_space_tag_t tag, 176122361Simp bus_space_handle_t bsh) 17739225Sgibbs{ 17839225Sgibbs 17939225Sgibbs SLIST_INIT(&aha->free_aha_ccbs); 18039225Sgibbs LIST_INIT(&aha->pending_ccbs); 18139225Sgibbs SLIST_INIT(&aha->sg_maps); 18239225Sgibbs aha->unit = unit; 18339225Sgibbs aha->tag = tag; 18439225Sgibbs aha->bsh = bsh; 18542887Simp aha->ccb_sg_opcode = INITIATOR_SG_CCB_WRESID; 18642887Simp aha->ccb_ccb_opcode = INITIATOR_CCB_WRESID; 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_dmamap_destroy(aha->ccb_dmat, aha->ccb_dmamap); 21139225Sgibbs bus_dmamem_free(aha->ccb_dmat, aha->aha_ccb_array, 212122340Simp 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 } 22839225Sgibbs} 22939225Sgibbs 23039225Sgibbs/* 23139225Sgibbs * Probe the adapter and verify that the card is an Adaptec. 23239225Sgibbs */ 23339225Sgibbsint 23439225Sgibbsaha_probe(struct aha_softc* aha) 23539225Sgibbs{ 23639225Sgibbs u_int status; 23739225Sgibbs u_int intstat; 23839225Sgibbs int error; 23939852Simp board_id_data_t board_id; 24039225Sgibbs 24139225Sgibbs /* 24239225Sgibbs * See if the three I/O ports look reasonable. 24339225Sgibbs * Touch the minimal number of registers in the 24439225Sgibbs * failure case. 24539225Sgibbs */ 24639225Sgibbs status = aha_inb(aha, STATUS_REG); 247122340Simp if ((status == 0) || 248122340Simp (status & (DIAG_ACTIVE|CMD_REG_BUSY | STATUS_REG_RSVD)) != 0) { 249122597Simp PRVERB((aha->dev, "status reg test failed %x\n", status)); 25039225Sgibbs return (ENXIO); 25139225Sgibbs } 25239225Sgibbs 25339225Sgibbs intstat = aha_inb(aha, INTSTAT_REG); 25439225Sgibbs if ((intstat & INTSTAT_REG_RSVD) != 0) { 255122597Simp PRVERB((aha->dev, "Failed Intstat Reg Test\n")); 25639225Sgibbs return (ENXIO); 25739225Sgibbs } 25839225Sgibbs 25939225Sgibbs /* 26041047Sgibbs * Looking good so far. Final test is to reset the 26141047Sgibbs * adapter and fetch the board ID and ensure we aren't 26241047Sgibbs * looking at a BusLogic. 26341047Sgibbs */ 26441047Sgibbs if ((error = ahareset(aha, /*hard_reset*/TRUE)) != 0) { 265122597Simp PRVERB((aha->dev, "Failed Reset\n")); 26641047Sgibbs return (ENXIO); 26741047Sgibbs } 26841047Sgibbs 26941047Sgibbs /* 27039852Simp * Get the board ID. We use this to see if we're dealing with 271108533Sschweikh * a buslogic card or an aha card (or clone). 27239225Sgibbs */ 27341047Sgibbs error = aha_cmd(aha, AOP_INQUIRE_BOARD_ID, NULL, /*parmlen*/0, 274122340Simp (uint8_t*)&board_id, sizeof(board_id), DEFAULT_CMD_TIMEOUT); 27539852Simp if (error != 0) { 276122597Simp PRVERB((aha->dev, "INQUIRE failed %x\n", error)); 27739225Sgibbs return (ENXIO); 27839225Sgibbs } 27939852Simp aha->fw_major = board_id.firmware_rev_major; 28039852Simp aha->fw_minor = board_id.firmware_rev_minor; 28139852Simp aha->boardid = board_id.board_type; 28239852Simp 28339225Sgibbs /* 28439852Simp * The Buslogic cards have an id of either 0x41 or 0x42. So 28539852Simp * if those come up in the probe, we test the geometry register 28639852Simp * of the board. Adaptec boards that are this old will not have 28739852Simp * this register, and return 0xff, while buslogic cards will return 28839852Simp * something different. 28939852Simp * 29041335Simp * It appears that for reasons unknow, for the for the 29141335Simp * aha-1542B cards, we need to wait a little bit before trying 29241335Simp * to read the geometry register. I picked 10ms since we have 29341335Simp * reports that a for loop to 1000 did the trick, and this 29441335Simp * errs on the side of conservatism. Besides, no one will 29541335Simp * notice a 10mS delay here, even the 1542B card users :-) 29641335Simp * 29746997Simp * Some compatible cards return 0 here. Some cards also 29846997Simp * seem to return 0x7f. 29941807Simp * 300122363Simp * XXX I'm not sure how this will impact other cloned cards 30141807Simp * 30241807Simp * This really should be replaced with the esetup command, since 30346997Simp * that appears to be more reliable. This becomes more and more 30446997Simp * true over time as we discover more cards that don't read the 30546997Simp * geometry register consistantly. 30639225Sgibbs */ 30739852Simp if (aha->boardid <= 0x42) { 30841335Simp /* Wait 10ms before reading */ 30941335Simp DELAY(10000); 31039852Simp status = aha_inb(aha, GEOMETRY_REG); 31146997Simp if (status != 0xff && status != 0x00 && status != 0x7f) { 312122597Simp PRVERB((aha->dev, "Geometry Register test failed %#x\n", 313122597Simp status)); 31439852Simp return (ENXIO); 31541047Sgibbs } 31639751Simp } 317122363Simp 31839225Sgibbs return (0); 31939225Sgibbs} 32039225Sgibbs 32139225Sgibbs/* 32239225Sgibbs * Pull the boards setup information and record it in our softc. 32339225Sgibbs */ 32439225Sgibbsint 32539225Sgibbsaha_fetch_adapter_info(struct aha_softc *aha) 32639225Sgibbs{ 32739225Sgibbs setup_data_t setup_info; 32839225Sgibbs config_data_t config_data; 329122340Simp uint8_t length_param; 33039225Sgibbs int error; 33139751Simp struct aha_extbios extbios; 332122363Simp 33339852Simp switch (aha->boardid) { 33439225Sgibbs case BOARD_1540_16HEAD_BIOS: 33541514Sarchie snprintf(aha->model, sizeof(aha->model), "1540 16 head BIOS"); 33639225Sgibbs break; 33739225Sgibbs case BOARD_1540_64HEAD_BIOS: 33841514Sarchie snprintf(aha->model, sizeof(aha->model), "1540 64 head BIOS"); 33939225Sgibbs break; 34039225Sgibbs case BOARD_1542: 34141514Sarchie snprintf(aha->model, sizeof(aha->model), "1540/1542 64 head BIOS"); 34239225Sgibbs break; 34339225Sgibbs case BOARD_1640: 34441514Sarchie snprintf(aha->model, sizeof(aha->model), "1640"); 34539225Sgibbs break; 34639225Sgibbs case BOARD_1740: 34741514Sarchie snprintf(aha->model, sizeof(aha->model), "1740A/1742A/1744"); 34839225Sgibbs break; 34939225Sgibbs case BOARD_1542C: 35041514Sarchie snprintf(aha->model, sizeof(aha->model), "1542C"); 35139225Sgibbs break; 35239225Sgibbs case BOARD_1542CF: 35341514Sarchie snprintf(aha->model, sizeof(aha->model), "1542CF"); 35439225Sgibbs break; 35539225Sgibbs case BOARD_1542CP: 35641514Sarchie snprintf(aha->model, sizeof(aha->model), "1542CP"); 35739225Sgibbs break; 35839225Sgibbs default: 35941514Sarchie snprintf(aha->model, sizeof(aha->model), "Unknown"); 36039225Sgibbs break; 36139225Sgibbs } 36239751Simp /* 36339751Simp * If we are a new type of 1542 board (anything newer than a 1542C) 36439751Simp * then disable the extended bios so that the 36539751Simp * mailbox interface is unlocked. 36639751Simp * This is also true for the 1542B Version 3.20. First Adaptec 36739751Simp * board that supports >1Gb drives. 36839751Simp * No need to check the extended bios flags as some of the 36939751Simp * extensions that cause us problems are not flagged in that byte. 37039751Simp */ 37139751Simp if (PROBABLY_NEW_BOARD(aha->boardid) || 37239751Simp (aha->boardid == 0x41 373122363Simp && aha->fw_major == 0x31 && 37439852Simp aha->fw_minor >= 0x34)) { 37541047Sgibbs error = aha_cmd(aha, AOP_RETURN_EXT_BIOS_INFO, NULL, 376122340Simp /*paramlen*/0, (u_char *)&extbios, sizeof(extbios), 377122340Simp DEFAULT_CMD_TIMEOUT); 378122360Simp if (error != 0) { 379122597Simp device_printf(aha->dev, 380122597Simp "AOP_RETURN_EXT_BIOS_INFO - Failed."); 381122360Simp return (error); 382122360Simp } 383122340Simp error = aha_cmd(aha, AOP_MBOX_IF_ENABLE, (uint8_t *)&extbios, 384122340Simp /*paramlen*/2, NULL, 0, DEFAULT_CMD_TIMEOUT); 385122360Simp if (error != 0) { 386122597Simp device_printf(aha->dev, "AOP_MBOX_IF_ENABLE - Failed."); 387122360Simp return (error); 388122360Simp } 38939751Simp } 39039751Simp if (aha->boardid < 0x41) 391122597Simp device_printf(aha->dev, "Warning: aha-1542A won't work.\n"); 39239751Simp 39341335Simp aha->max_sg = 17; /* Need >= 17 to do 64k I/O */ 39439225Sgibbs aha->diff_bus = 0; 39539225Sgibbs aha->extended_lun = 0; 39639751Simp aha->extended_trans = 0; 39740403Simp aha->max_ccbs = 16; 39839225Sgibbs /* Determine Sync/Wide/Disc settings */ 39939225Sgibbs length_param = sizeof(setup_info); 40041047Sgibbs error = aha_cmd(aha, AOP_INQUIRE_SETUP_INFO, &length_param, 401122340Simp /*paramlen*/1, (uint8_t*)&setup_info, sizeof(setup_info), 402122340Simp DEFAULT_CMD_TIMEOUT); 40339225Sgibbs if (error != 0) { 404122597Simp device_printf(aha->dev, "aha_fetch_adapter_info - Failed " 405122597Simp "Get Setup Info\n"); 40639225Sgibbs return (error); 40739225Sgibbs } 40839225Sgibbs if (setup_info.initiate_sync != 0) { 40939225Sgibbs aha->sync_permitted = ALL_TARGETS; 41039225Sgibbs } 41139225Sgibbs aha->disc_permitted = ALL_TARGETS; 41239225Sgibbs 41339225Sgibbs /* We need as many mailboxes as we can have ccbs */ 41439225Sgibbs aha->num_boxes = aha->max_ccbs; 41539225Sgibbs 41639225Sgibbs /* Determine our SCSI ID */ 41741047Sgibbs error = aha_cmd(aha, AOP_INQUIRE_CONFIG, NULL, /*parmlen*/0, 418122340Simp (uint8_t*)&config_data, sizeof(config_data), DEFAULT_CMD_TIMEOUT); 41939225Sgibbs if (error != 0) { 420122597Simp device_printf(aha->dev, 421122597Simp "aha_fetch_adapter_info - Failed Get Config\n"); 42239225Sgibbs return (error); 42339225Sgibbs } 42439225Sgibbs aha->scsi_id = config_data.scsi_id; 42539225Sgibbs return (0); 42639225Sgibbs} 42739225Sgibbs 42839225Sgibbs/* 42939225Sgibbs * Start the board, ready for normal operation 43039225Sgibbs */ 43139225Sgibbsint 43239225Sgibbsaha_init(struct aha_softc* aha) 43339225Sgibbs{ 43439225Sgibbs /* Announce the Adapter */ 435122597Simp device_printf(aha->dev, "AHA-%s FW Rev. %c.%c (ID=%x) ", 436122340Simp aha->model, aha->fw_major, aha->fw_minor, aha->boardid); 43739225Sgibbs 43839225Sgibbs if (aha->diff_bus != 0) 43939225Sgibbs printf("Diff "); 44039225Sgibbs 44139225Sgibbs printf("SCSI Host Adapter, SCSI ID %d, %d CCBs\n", aha->scsi_id, 442122340Simp aha->max_ccbs); 44339225Sgibbs 44439225Sgibbs /* 44539225Sgibbs * Create our DMA tags. These tags define the kinds of device 446122363Simp * accessible memory allocations and memory mappings we will 44739225Sgibbs * need to perform during normal operation. 44839225Sgibbs * 44939225Sgibbs * Unless we need to further restrict the allocation, we rely 45039225Sgibbs * on the restrictions of the parent dmat, hence the common 45139225Sgibbs * use of MAXADDR and MAXSIZE. 45239225Sgibbs */ 45339225Sgibbs 45439225Sgibbs /* DMA tag for mapping buffers into device visible space. */ 455122340Simp if (bus_dma_tag_create( /* parent */ aha->parent_dmat, 456112782Smdodd /* alignment */ 1, 457112782Smdodd /* boundary */ 0, 458112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR, 459112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 460112782Smdodd /* filter */ NULL, 461112782Smdodd /* filterarg */ NULL, 462112782Smdodd /* maxsize */ MAXBSIZE, 463112782Smdodd /* nsegments */ AHA_NSEG, 464112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_24BIT, 465112782Smdodd /* flags */ BUS_DMA_ALLOCNOW, 466117126Sscottl /* lockfunc */ busdma_lock_mutex, 467117126Sscottl /* lockarg */ &Giant, 468112782Smdodd &aha->buffer_dmat) != 0) { 46939225Sgibbs goto error_exit; 47039225Sgibbs } 47139225Sgibbs 47239225Sgibbs aha->init_level++; 47339225Sgibbs /* DMA tag for our mailboxes */ 474112782Smdodd if (bus_dma_tag_create( /* parent */ aha->parent_dmat, 475112782Smdodd /* alignment */ 1, 476112782Smdodd /* boundary */ 0, 477112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR, 478112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 479112782Smdodd /* filter */ NULL, 480112782Smdodd /* filterarg */ NULL, 481112782Smdodd /* maxsize */ aha->num_boxes * 482112782Smdodd (sizeof(aha_mbox_in_t) + 483112782Smdodd sizeof(aha_mbox_out_t)), 484112782Smdodd /* nsegments */ 1, 485112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_24BIT, 486112782Smdodd /* flags */ 0, 487117126Sscottl /* lockfunc */ busdma_lock_mutex, 488117126Sscottl /* lockarg */ &Giant, 489112782Smdodd &aha->mailbox_dmat) != 0) { 49039225Sgibbs goto error_exit; 49139225Sgibbs } 49239225Sgibbs 49339225Sgibbs aha->init_level++; 49439225Sgibbs 49539225Sgibbs /* Allocation for our mailboxes */ 49639225Sgibbs if (bus_dmamem_alloc(aha->mailbox_dmat, (void **)&aha->out_boxes, 497122340Simp BUS_DMA_NOWAIT, &aha->mailbox_dmamap) != 0) 49839225Sgibbs goto error_exit; 49939225Sgibbs 50039225Sgibbs aha->init_level++; 50139225Sgibbs 50239225Sgibbs /* And permanently map them */ 50339225Sgibbs bus_dmamap_load(aha->mailbox_dmat, aha->mailbox_dmamap, 504122340Simp aha->out_boxes, aha->num_boxes * (sizeof(aha_mbox_in_t) + 505122340Simp sizeof(aha_mbox_out_t)), ahamapmboxes, aha, /*flags*/0); 50639225Sgibbs 50739225Sgibbs aha->init_level++; 50839225Sgibbs 50939225Sgibbs aha->in_boxes = (aha_mbox_in_t *)&aha->out_boxes[aha->num_boxes]; 51039225Sgibbs 51139225Sgibbs ahainitmboxes(aha); 51239225Sgibbs 51339225Sgibbs /* DMA tag for our ccb structures */ 514112782Smdodd if (bus_dma_tag_create( /* parent */ aha->parent_dmat, 515112782Smdodd /* alignment */ 1, 516112782Smdodd /* boundary */ 0, 517112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR, 518112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 519112782Smdodd /* filter */ NULL, 520112782Smdodd /* filterarg */ NULL, 521112782Smdodd /* maxsize */ aha->max_ccbs * 522112782Smdodd sizeof(struct aha_ccb), 523112782Smdodd /* nsegments */ 1, 524112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_24BIT, 525112782Smdodd /* flags */ 0, 526117126Sscottl /* lockfunc */ busdma_lock_mutex, 527117126Sscottl /* lockarg */ &Giant, 528112782Smdodd &aha->ccb_dmat) != 0) { 52939225Sgibbs goto error_exit; 53039225Sgibbs } 53139225Sgibbs 53239225Sgibbs aha->init_level++; 53339225Sgibbs 53439225Sgibbs /* Allocation for our ccbs */ 53539225Sgibbs if (bus_dmamem_alloc(aha->ccb_dmat, (void **)&aha->aha_ccb_array, 536122340Simp BUS_DMA_NOWAIT, &aha->ccb_dmamap) != 0) 53739225Sgibbs goto error_exit; 53839225Sgibbs 53939225Sgibbs aha->init_level++; 54039225Sgibbs 54139225Sgibbs /* And permanently map them */ 542122340Simp bus_dmamap_load(aha->ccb_dmat, aha->ccb_dmamap, aha->aha_ccb_array, 543122340Simp aha->max_ccbs * sizeof(struct aha_ccb), ahamapccbs, aha, /*flags*/0); 54439225Sgibbs 54539225Sgibbs aha->init_level++; 54639225Sgibbs 54739225Sgibbs /* DMA tag for our S/G structures. We allocate in page sized chunks */ 548112782Smdodd if (bus_dma_tag_create( /* parent */ aha->parent_dmat, 549112782Smdodd /* alignment */ 1, 550112782Smdodd /* boundary */ 0, 551112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR, 552112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 553112782Smdodd /* filter */ NULL, 554112782Smdodd /* filterarg */ NULL, 555112782Smdodd /* maxsize */ PAGE_SIZE, 556112782Smdodd /* nsegments */ 1, 557112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_24BIT, 558112782Smdodd /* flags */ 0, 559117126Sscottl /* lockfunc */ busdma_lock_mutex, 560117126Sscottl /* lockarg */ &Giant, 561122340Simp &aha->sg_dmat) != 0) 56239225Sgibbs goto error_exit; 56339225Sgibbs 56439225Sgibbs aha->init_level++; 56539225Sgibbs 56639225Sgibbs /* Perform initial CCB allocation */ 56739225Sgibbs bzero(aha->aha_ccb_array, aha->max_ccbs * sizeof(struct aha_ccb)); 56839225Sgibbs ahaallocccbs(aha); 56939225Sgibbs 57039225Sgibbs if (aha->num_ccbs == 0) { 571122597Simp device_printf(aha->dev, 572122597Simp "aha_init - Unable to allocate initial ccbs\n"); 57339225Sgibbs goto error_exit; 57439225Sgibbs } 57539225Sgibbs 57639225Sgibbs /* 57739225Sgibbs * Note that we are going and return (to probe) 57839225Sgibbs */ 579122340Simp return (0); 58039225Sgibbs 58139225Sgibbserror_exit: 58239225Sgibbs 58339225Sgibbs return (ENXIO); 58439225Sgibbs} 58539225Sgibbs 58639225Sgibbsint 58739225Sgibbsaha_attach(struct aha_softc *aha) 58839225Sgibbs{ 58939225Sgibbs int tagged_dev_openings; 59039225Sgibbs struct cam_devq *devq; 59139225Sgibbs 59239225Sgibbs /* 59341335Simp * We don't do tagged queueing, since the aha cards don't 59441335Simp * support it. 59539225Sgibbs */ 59639225Sgibbs tagged_dev_openings = 0; 59739225Sgibbs 59839225Sgibbs /* 59939225Sgibbs * Create the device queue for our SIM. 60039225Sgibbs */ 60139225Sgibbs devq = cam_simq_alloc(aha->max_ccbs - 1); 60239225Sgibbs if (devq == NULL) 60339225Sgibbs return (ENOMEM); 60439225Sgibbs 60539225Sgibbs /* 60639225Sgibbs * Construct our SIM entry 60739225Sgibbs */ 608168752Sscottl aha->sim = cam_sim_alloc(ahaaction, ahapoll, "aha", aha, aha->unit, 609168752Sscottl &Giant, 2, tagged_dev_openings, devq); 61039225Sgibbs if (aha->sim == NULL) { 61139225Sgibbs cam_simq_free(devq); 61239225Sgibbs return (ENOMEM); 61339225Sgibbs } 614170872Sscottl if (xpt_bus_register(aha->sim, aha->dev, 0) != CAM_SUCCESS) { 61539225Sgibbs cam_sim_free(aha->sim, /*free_devq*/TRUE); 61639225Sgibbs return (ENXIO); 61739225Sgibbs } 618122340Simp if (xpt_create_path(&aha->path, /*periph*/NULL, cam_sim_path(aha->sim), 619122340Simp CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 62039225Sgibbs xpt_bus_deregister(cam_sim_path(aha->sim)); 62139225Sgibbs cam_sim_free(aha->sim, /*free_devq*/TRUE); 62239225Sgibbs return (ENXIO); 62339225Sgibbs } 624122363Simp 62539225Sgibbs return (0); 62639225Sgibbs} 62739225Sgibbs 62839225Sgibbsstatic void 62939225Sgibbsahaallocccbs(struct aha_softc *aha) 63039225Sgibbs{ 63139225Sgibbs struct aha_ccb *next_ccb; 63239225Sgibbs struct sg_map_node *sg_map; 63339225Sgibbs bus_addr_t physaddr; 63439225Sgibbs aha_sg_t *segs; 63539225Sgibbs int newcount; 63639225Sgibbs int i; 63739225Sgibbs 63839225Sgibbs next_ccb = &aha->aha_ccb_array[aha->num_ccbs]; 63939225Sgibbs 64039225Sgibbs sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT); 64139225Sgibbs 64239225Sgibbs if (sg_map == NULL) 64339225Sgibbs return; 64439225Sgibbs 64539225Sgibbs /* Allocate S/G space for the next batch of CCBS */ 64639225Sgibbs if (bus_dmamem_alloc(aha->sg_dmat, (void **)&sg_map->sg_vaddr, 647122340Simp BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) { 64839225Sgibbs free(sg_map, M_DEVBUF); 64939225Sgibbs return; 65039225Sgibbs } 65139225Sgibbs 65239225Sgibbs SLIST_INSERT_HEAD(&aha->sg_maps, sg_map, links); 65339225Sgibbs 65439225Sgibbs bus_dmamap_load(aha->sg_dmat, sg_map->sg_dmamap, sg_map->sg_vaddr, 655122340Simp PAGE_SIZE, ahamapsgs, aha, /*flags*/0); 656122363Simp 65739225Sgibbs segs = sg_map->sg_vaddr; 65839225Sgibbs physaddr = sg_map->sg_physaddr; 65939225Sgibbs 66039225Sgibbs newcount = (PAGE_SIZE / (AHA_NSEG * sizeof(aha_sg_t))); 66139225Sgibbs for (i = 0; aha->num_ccbs < aha->max_ccbs && i < newcount; i++) { 66239225Sgibbs int error; 66339225Sgibbs 66439225Sgibbs next_ccb->sg_list = segs; 66539225Sgibbs next_ccb->sg_list_phys = physaddr; 66641047Sgibbs next_ccb->flags = ACCB_FREE; 66739225Sgibbs error = bus_dmamap_create(aha->buffer_dmat, /*flags*/0, 668122340Simp &next_ccb->dmamap); 66939225Sgibbs if (error != 0) 67039225Sgibbs break; 67139225Sgibbs SLIST_INSERT_HEAD(&aha->free_aha_ccbs, next_ccb, links); 67239225Sgibbs segs += AHA_NSEG; 67339225Sgibbs physaddr += (AHA_NSEG * sizeof(aha_sg_t)); 67439225Sgibbs next_ccb++; 67539225Sgibbs aha->num_ccbs++; 67639225Sgibbs } 67739225Sgibbs 67839225Sgibbs /* Reserve a CCB for error recovery */ 67941047Sgibbs if (aha->recovery_accb == NULL) { 68041047Sgibbs aha->recovery_accb = SLIST_FIRST(&aha->free_aha_ccbs); 68139225Sgibbs SLIST_REMOVE_HEAD(&aha->free_aha_ccbs, links); 68239225Sgibbs } 68339225Sgibbs} 68439225Sgibbs 68539225Sgibbsstatic __inline void 68641047Sgibbsahafreeccb(struct aha_softc *aha, struct aha_ccb *accb) 68739225Sgibbs{ 68839225Sgibbs int s; 68939225Sgibbs 69039225Sgibbs s = splcam(); 69141047Sgibbs if ((accb->flags & ACCB_ACTIVE) != 0) 69241047Sgibbs LIST_REMOVE(&accb->ccb->ccb_h, sim_links.le); 69339225Sgibbs if (aha->resource_shortage != 0 694122340Simp && (accb->ccb->ccb_h.status & CAM_RELEASE_SIMQ) == 0) { 69541047Sgibbs accb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 69639225Sgibbs aha->resource_shortage = FALSE; 69739225Sgibbs } 69841047Sgibbs accb->flags = ACCB_FREE; 69941047Sgibbs SLIST_INSERT_HEAD(&aha->free_aha_ccbs, accb, links); 70041047Sgibbs aha->active_ccbs--; 70139225Sgibbs splx(s); 70239225Sgibbs} 70339225Sgibbs 70439225Sgibbsstatic struct aha_ccb* 70539225Sgibbsahagetccb(struct aha_softc *aha) 70639225Sgibbs{ 70741047Sgibbs struct aha_ccb* accb; 70839225Sgibbs int s; 70939225Sgibbs 71039225Sgibbs s = splcam(); 71141047Sgibbs if ((accb = SLIST_FIRST(&aha->free_aha_ccbs)) != NULL) { 71239225Sgibbs SLIST_REMOVE_HEAD(&aha->free_aha_ccbs, links); 71341047Sgibbs aha->active_ccbs++; 71439225Sgibbs } else if (aha->num_ccbs < aha->max_ccbs) { 71539225Sgibbs ahaallocccbs(aha); 71641047Sgibbs accb = SLIST_FIRST(&aha->free_aha_ccbs); 71741047Sgibbs if (accb == NULL) 718122597Simp device_printf(aha->dev, "Can't malloc ACCB\n"); 71941047Sgibbs else { 72039225Sgibbs SLIST_REMOVE_HEAD(&aha->free_aha_ccbs, links); 72141047Sgibbs aha->active_ccbs++; 72241047Sgibbs } 72339225Sgibbs } 72439225Sgibbs splx(s); 72539225Sgibbs 72641047Sgibbs return (accb); 72739225Sgibbs} 72839225Sgibbs 72939225Sgibbsstatic void 73039225Sgibbsahaaction(struct cam_sim *sim, union ccb *ccb) 73139225Sgibbs{ 73239225Sgibbs struct aha_softc *aha; 733122340Simp int s; 73439225Sgibbs 73539225Sgibbs CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("ahaaction\n")); 736122363Simp 73739225Sgibbs aha = (struct aha_softc *)cam_sim_softc(sim); 738122363Simp 73939225Sgibbs switch (ccb->ccb_h.func_code) { 74039225Sgibbs /* Common cases first */ 74139225Sgibbs case XPT_SCSI_IO: /* Execute the requested I/O operation */ 742122340Simp case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ { 74341047Sgibbs struct aha_ccb *accb; 74439225Sgibbs struct aha_hccb *hccb; 74539225Sgibbs 74639225Sgibbs /* 747108533Sschweikh * Get an accb to use. 74839225Sgibbs */ 74941047Sgibbs if ((accb = ahagetccb(aha)) == NULL) { 75039225Sgibbs s = splcam(); 75139225Sgibbs aha->resource_shortage = TRUE; 75239225Sgibbs splx(s); 75339225Sgibbs xpt_freeze_simq(aha->sim, /*count*/1); 75439225Sgibbs ccb->ccb_h.status = CAM_REQUEUE_REQ; 75539225Sgibbs xpt_done(ccb); 75639225Sgibbs return; 75739225Sgibbs } 75841047Sgibbs hccb = &accb->hccb; 75939225Sgibbs 76039225Sgibbs /* 76141047Sgibbs * So we can find the ACCB when an abort is requested 76239225Sgibbs */ 76341047Sgibbs accb->ccb = ccb; 76441047Sgibbs ccb->ccb_h.ccb_accb_ptr = accb; 76539225Sgibbs ccb->ccb_h.ccb_aha_ptr = aha; 76639225Sgibbs 76739225Sgibbs /* 76841047Sgibbs * Put all the arguments for the xfer in the accb 76939225Sgibbs */ 77039225Sgibbs hccb->target = ccb->ccb_h.target_id; 77139225Sgibbs hccb->lun = ccb->ccb_h.target_lun; 77239225Sgibbs hccb->ahastat = 0; 77339225Sgibbs hccb->sdstat = 0; 77439225Sgibbs 77539225Sgibbs if (ccb->ccb_h.func_code == XPT_SCSI_IO) { 77639225Sgibbs struct ccb_scsiio *csio; 77739225Sgibbs struct ccb_hdr *ccbh; 77839225Sgibbs 77939225Sgibbs csio = &ccb->csio; 78039225Sgibbs ccbh = &csio->ccb_h; 78142887Simp hccb->opcode = aha->ccb_ccb_opcode; 78239225Sgibbs hccb->datain = (ccb->ccb_h.flags & CAM_DIR_IN) != 0; 78339225Sgibbs hccb->dataout = (ccb->ccb_h.flags & CAM_DIR_OUT) != 0; 78439225Sgibbs hccb->cmd_len = csio->cdb_len; 78539225Sgibbs if (hccb->cmd_len > sizeof(hccb->scsi_cdb)) { 78639225Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 78741047Sgibbs ahafreeccb(aha, accb); 78839225Sgibbs xpt_done(ccb); 78939225Sgibbs return; 79039225Sgibbs } 79139225Sgibbs hccb->sense_len = csio->sense_len; 79239225Sgibbs if ((ccbh->flags & CAM_CDB_POINTER) != 0) { 79339225Sgibbs if ((ccbh->flags & CAM_CDB_PHYS) == 0) { 79439225Sgibbs bcopy(csio->cdb_io.cdb_ptr, 79539225Sgibbs hccb->scsi_cdb, hccb->cmd_len); 79639225Sgibbs } else { 79739225Sgibbs /* I guess I could map it in... */ 79839225Sgibbs ccbh->status = CAM_REQ_INVALID; 79941047Sgibbs ahafreeccb(aha, accb); 80039225Sgibbs xpt_done(ccb); 80139225Sgibbs return; 80239225Sgibbs } 80339225Sgibbs } else { 80439225Sgibbs bcopy(csio->cdb_io.cdb_bytes, 80539225Sgibbs hccb->scsi_cdb, hccb->cmd_len); 80639225Sgibbs } 80739225Sgibbs /* 80839225Sgibbs * If we have any data to send with this command, 80939225Sgibbs * map it into bus space. 81039225Sgibbs */ 81139225Sgibbs /* Only use S/G if there is a transfer */ 81239225Sgibbs if ((ccbh->flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 81339225Sgibbs if ((ccbh->flags & CAM_SCATTER_VALID) == 0) { 81439225Sgibbs /* 81539225Sgibbs * We've been given a pointer 81639225Sgibbs * to a single buffer. 81739225Sgibbs */ 81839225Sgibbs if ((ccbh->flags & CAM_DATA_PHYS)==0) { 81939225Sgibbs int error; 82039225Sgibbs 82139225Sgibbs s = splsoftvm(); 82239225Sgibbs error = bus_dmamap_load( 82339225Sgibbs aha->buffer_dmat, 82441047Sgibbs accb->dmamap, 82539225Sgibbs csio->data_ptr, 82639225Sgibbs csio->dxfer_len, 82739225Sgibbs ahaexecuteccb, 82841047Sgibbs accb, 82939225Sgibbs /*flags*/0); 83039225Sgibbs if (error == EINPROGRESS) { 83139225Sgibbs /* 83239225Sgibbs * So as to maintain 83339225Sgibbs * ordering, freeze the 83439225Sgibbs * controller queue 83539225Sgibbs * until our mapping is 83639225Sgibbs * returned. 83739225Sgibbs */ 83839225Sgibbs xpt_freeze_simq(aha->sim, 83939225Sgibbs 1); 84039225Sgibbs csio->ccb_h.status |= 84139225Sgibbs CAM_RELEASE_SIMQ; 84239225Sgibbs } 84339225Sgibbs splx(s); 84439225Sgibbs } else { 845122363Simp struct bus_dma_segment seg; 84639225Sgibbs 84739225Sgibbs /* Pointer to physical buffer */ 84839225Sgibbs seg.ds_addr = 84939225Sgibbs (bus_addr_t)csio->data_ptr; 85039225Sgibbs seg.ds_len = csio->dxfer_len; 85141047Sgibbs ahaexecuteccb(accb, &seg, 1, 0); 85239225Sgibbs } 85339225Sgibbs } else { 85439225Sgibbs struct bus_dma_segment *segs; 85539225Sgibbs 85639225Sgibbs if ((ccbh->flags & CAM_DATA_PHYS) != 0) 85739225Sgibbs panic("ahaaction - Physical " 85839225Sgibbs "segment pointers " 85939225Sgibbs "unsupported"); 86039225Sgibbs 86139225Sgibbs if ((ccbh->flags&CAM_SG_LIST_PHYS)==0) 86239225Sgibbs panic("ahaaction - Virtual " 86339225Sgibbs "segment addresses " 86439225Sgibbs "unsupported"); 86539225Sgibbs 86639225Sgibbs /* Just use the segments provided */ 86739225Sgibbs segs = (struct bus_dma_segment *) 86839225Sgibbs csio->data_ptr; 86941047Sgibbs ahaexecuteccb(accb, segs, 87039225Sgibbs csio->sglist_cnt, 0); 87139225Sgibbs } 87239225Sgibbs } else { 87341047Sgibbs ahaexecuteccb(accb, NULL, 0, 0); 87439225Sgibbs } 87539225Sgibbs } else { 87639225Sgibbs hccb->opcode = INITIATOR_BUS_DEV_RESET; 87739225Sgibbs /* No data transfer */ 87839225Sgibbs hccb->datain = TRUE; 87939225Sgibbs hccb->dataout = TRUE; 88039225Sgibbs hccb->cmd_len = 0; 88139225Sgibbs hccb->sense_len = 0; 88241047Sgibbs ahaexecuteccb(accb, NULL, 0, 0); 88339225Sgibbs } 88439225Sgibbs break; 88539225Sgibbs } 88639225Sgibbs case XPT_EN_LUN: /* Enable LUN as a target */ 88739225Sgibbs case XPT_TARGET_IO: /* Execute target I/O request */ 88839225Sgibbs case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */ 88939225Sgibbs case XPT_CONT_TARGET_IO: /* Continue Host Target I/O Connection*/ 89039225Sgibbs case XPT_ABORT: /* Abort the specified CCB */ 89139225Sgibbs /* XXX Implement */ 89239225Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 89339225Sgibbs xpt_done(ccb); 89439225Sgibbs break; 89539225Sgibbs case XPT_SET_TRAN_SETTINGS: 89639225Sgibbs /* XXX Implement */ 89746581Sken ccb->ccb_h.status = CAM_PROVIDE_FAIL; 89839225Sgibbs xpt_done(ccb); 89939225Sgibbs break; 90039225Sgibbs case XPT_GET_TRAN_SETTINGS: 90139225Sgibbs /* Get default/user set transfer settings for the target */ 90239225Sgibbs { 903163816Smjacob struct ccb_trans_settings *cts = &ccb->cts; 904163816Smjacob u_int target_mask = 0x01 << ccb->ccb_h.target_id; 905163816Smjacob struct ccb_trans_settings_scsi *scsi = 906163816Smjacob &cts->proto_specific.scsi; 907163816Smjacob struct ccb_trans_settings_spi *spi = 908163816Smjacob &cts->xport_specific.spi; 90939225Sgibbs 910163816Smjacob cts->protocol = PROTO_SCSI; 911163816Smjacob cts->protocol_version = SCSI_REV_2; 912163816Smjacob cts->transport = XPORT_SPI; 913163816Smjacob cts->transport_version = 2; 914163816Smjacob if (cts->type == CTS_TYPE_USER_SETTINGS) { 915163816Smjacob spi->flags = 0; 916163816Smjacob if ((aha->disc_permitted & target_mask) != 0) 917163816Smjacob spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 918163816Smjacob spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 919163816Smjacob if ((aha->sync_permitted & target_mask) != 0) { 920163816Smjacob if (aha->boardid >= BOARD_1542CF) 921163816Smjacob spi->sync_period = 25; 922163816Smjacob else 923163816Smjacob spi->sync_period = 50; 924163816Smjacob } else { 925163816Smjacob spi->sync_period = 0; 926163816Smjacob } 927163816Smjacob 928163816Smjacob if (spi->sync_period != 0) 929163816Smjacob spi->sync_offset = 15; 930163816Smjacob 931163816Smjacob spi->valid = CTS_SPI_VALID_SYNC_RATE 932163816Smjacob | CTS_SPI_VALID_SYNC_OFFSET 933163816Smjacob | CTS_SPI_VALID_BUS_WIDTH 934163816Smjacob | CTS_SPI_VALID_DISC; 935163816Smjacob scsi->valid = CTS_SCSI_VALID_TQ; 936163816Smjacob } else { 937163816Smjacob ahafetchtransinfo(aha, cts); 938163816Smjacob } 93939225Sgibbs 94039225Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 94139225Sgibbs xpt_done(ccb); 94239225Sgibbs break; 94339225Sgibbs } 94439225Sgibbs case XPT_CALC_GEOMETRY: 94539225Sgibbs { 94639225Sgibbs struct ccb_calc_geometry *ccg; 947122340Simp uint32_t size_mb; 948122340Simp uint32_t secs_per_cylinder; 94939225Sgibbs 95039225Sgibbs ccg = &ccb->ccg; 95139225Sgibbs size_mb = ccg->volume_size 95239225Sgibbs / ((1024L * 1024L) / ccg->block_size); 95339225Sgibbs if (size_mb >= 1024 && (aha->extended_trans != 0)) { 95439225Sgibbs if (size_mb >= 2048) { 95539225Sgibbs ccg->heads = 255; 95639225Sgibbs ccg->secs_per_track = 63; 95739225Sgibbs } else { 95839225Sgibbs ccg->heads = 128; 95939225Sgibbs ccg->secs_per_track = 32; 96039225Sgibbs } 96139225Sgibbs } else { 96239225Sgibbs ccg->heads = 64; 96339225Sgibbs ccg->secs_per_track = 32; 96439225Sgibbs } 96539225Sgibbs secs_per_cylinder = ccg->heads * ccg->secs_per_track; 96639225Sgibbs ccg->cylinders = ccg->volume_size / secs_per_cylinder; 96739225Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 96839225Sgibbs xpt_done(ccb); 96939225Sgibbs break; 97039225Sgibbs } 97139225Sgibbs case XPT_RESET_BUS: /* Reset the specified SCSI bus */ 97239225Sgibbs ahareset(aha, /*hardreset*/TRUE); 97339225Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 97439225Sgibbs xpt_done(ccb); 97539225Sgibbs break; 97639225Sgibbs case XPT_TERM_IO: /* Terminate the I/O process */ 97739225Sgibbs /* XXX Implement */ 97839225Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 97939225Sgibbs xpt_done(ccb); 98039225Sgibbs break; 98139225Sgibbs case XPT_PATH_INQ: /* Path routing inquiry */ 98239225Sgibbs { 98339225Sgibbs struct ccb_pathinq *cpi = &ccb->cpi; 984122363Simp 98539225Sgibbs cpi->version_num = 1; /* XXX??? */ 98639225Sgibbs cpi->hba_inquiry = PI_SDTR_ABLE; 98739225Sgibbs cpi->target_sprt = 0; 98839225Sgibbs cpi->hba_misc = 0; 98939225Sgibbs cpi->hba_eng_cnt = 0; 99039852Simp cpi->max_target = 7; 99139225Sgibbs cpi->max_lun = 7; 99239225Sgibbs cpi->initiator_id = aha->scsi_id; 99339225Sgibbs cpi->bus_id = cam_sim_bus(sim); 99446581Sken cpi->base_transfer_speed = 3300; 99539225Sgibbs strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 99639225Sgibbs strncpy(cpi->hba_vid, "Adaptec", HBA_IDLEN); 99739225Sgibbs strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 99839225Sgibbs cpi->unit_number = cam_sim_unit(sim); 999163816Smjacob cpi->transport = XPORT_SPI; 1000163816Smjacob cpi->transport_version = 2; 1001163816Smjacob cpi->protocol = PROTO_SCSI; 1002163816Smjacob cpi->protocol_version = SCSI_REV_2; 100339225Sgibbs cpi->ccb_h.status = CAM_REQ_CMP; 100439225Sgibbs xpt_done(ccb); 100539225Sgibbs break; 100639225Sgibbs } 100739225Sgibbs default: 100839225Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 100939225Sgibbs xpt_done(ccb); 101039225Sgibbs break; 101139225Sgibbs } 101239225Sgibbs} 101339225Sgibbs 101439225Sgibbsstatic void 101539225Sgibbsahaexecuteccb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 101639225Sgibbs{ 101741047Sgibbs struct aha_ccb *accb; 101839225Sgibbs union ccb *ccb; 101939225Sgibbs struct aha_softc *aha; 102040419Sgibbs int s; 1021122340Simp uint32_t paddr; 102239225Sgibbs 102341047Sgibbs accb = (struct aha_ccb *)arg; 102441047Sgibbs ccb = accb->ccb; 102539225Sgibbs aha = (struct aha_softc *)ccb->ccb_h.ccb_aha_ptr; 102639225Sgibbs 102739225Sgibbs if (error != 0) { 102839225Sgibbs if (error != EFBIG) 1029122597Simp device_printf(aha->dev, 1030122597Simp "Unexepected error 0x%x returned from " 1031122597Simp "bus_dmamap_load\n", error); 103239225Sgibbs if (ccb->ccb_h.status == CAM_REQ_INPROG) { 103339225Sgibbs xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 103439225Sgibbs ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN; 103539225Sgibbs } 103641047Sgibbs ahafreeccb(aha, accb); 103739225Sgibbs xpt_done(ccb); 103839225Sgibbs return; 103939225Sgibbs } 1040122363Simp 104139225Sgibbs if (nseg != 0) { 104239225Sgibbs aha_sg_t *sg; 104339225Sgibbs bus_dma_segment_t *end_seg; 1044115343Sscottl bus_dmasync_op_t op; 104539225Sgibbs 104639225Sgibbs end_seg = dm_segs + nseg; 104739225Sgibbs 104839225Sgibbs /* Copy the segments into our SG list */ 104941047Sgibbs sg = accb->sg_list; 105039225Sgibbs while (dm_segs < end_seg) { 105139225Sgibbs ahautoa24(dm_segs->ds_len, sg->len); 105239225Sgibbs ahautoa24(dm_segs->ds_addr, sg->addr); 105339225Sgibbs sg++; 105439225Sgibbs dm_segs++; 105539225Sgibbs } 105639225Sgibbs 105739225Sgibbs if (nseg > 1) { 105842887Simp accb->hccb.opcode = aha->ccb_sg_opcode; 105939225Sgibbs ahautoa24((sizeof(aha_sg_t) * nseg), 1060122340Simp accb->hccb.data_len); 106141047Sgibbs ahautoa24(accb->sg_list_phys, accb->hccb.data_addr); 106239225Sgibbs } else { 106341047Sgibbs bcopy(accb->sg_list->len, accb->hccb.data_len, 3); 106441047Sgibbs bcopy(accb->sg_list->addr, accb->hccb.data_addr, 3); 106539225Sgibbs } 106639225Sgibbs 106739225Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 106839225Sgibbs op = BUS_DMASYNC_PREREAD; 106939225Sgibbs else 107039225Sgibbs op = BUS_DMASYNC_PREWRITE; 107139225Sgibbs 107241047Sgibbs bus_dmamap_sync(aha->buffer_dmat, accb->dmamap, op); 107339225Sgibbs 107439225Sgibbs } else { 107541709Sgibbs accb->hccb.opcode = INITIATOR_CCB; 107641047Sgibbs ahautoa24(0, accb->hccb.data_len); 107741047Sgibbs ahautoa24(0, accb->hccb.data_addr); 107839225Sgibbs } 107939225Sgibbs 108039225Sgibbs s = splcam(); 108139225Sgibbs 108239225Sgibbs /* 108339225Sgibbs * Last time we need to check if this CCB needs to 108439225Sgibbs * be aborted. 108539225Sgibbs */ 108639225Sgibbs if (ccb->ccb_h.status != CAM_REQ_INPROG) { 108739225Sgibbs if (nseg != 0) 108841047Sgibbs bus_dmamap_unload(aha->buffer_dmat, accb->dmamap); 108941047Sgibbs ahafreeccb(aha, accb); 109039225Sgibbs xpt_done(ccb); 109139225Sgibbs splx(s); 109239225Sgibbs return; 109339225Sgibbs } 1094122363Simp 109541047Sgibbs accb->flags = ACCB_ACTIVE; 109639225Sgibbs ccb->ccb_h.status |= CAM_SIM_QUEUED; 109739225Sgibbs LIST_INSERT_HEAD(&aha->pending_ccbs, &ccb->ccb_h, sim_links.le); 109839225Sgibbs 1099122340Simp ccb->ccb_h.timeout_ch = timeout(ahatimeout, (caddr_t)accb, 1100122340Simp (ccb->ccb_h.timeout * hz) / 1000); 110139225Sgibbs 110239225Sgibbs /* Tell the adapter about this command */ 110341047Sgibbs if (aha->cur_outbox->action_code != AMBO_FREE) { 110441047Sgibbs /* 110541047Sgibbs * We should never encounter a busy mailbox. 110641047Sgibbs * If we do, warn the user, and treat it as 110741047Sgibbs * a resource shortage. If the controller is 110841047Sgibbs * hung, one of the pending transactions will 110941047Sgibbs * timeout causing us to start recovery operations. 111041047Sgibbs */ 1111122597Simp device_printf(aha->dev, 1112122597Simp "Encountered busy mailbox with %d out of %d " 1113122597Simp "commands active!!!", aha->active_ccbs, aha->max_ccbs); 111441047Sgibbs untimeout(ahatimeout, accb, ccb->ccb_h.timeout_ch); 111541047Sgibbs if (nseg != 0) 111641047Sgibbs bus_dmamap_unload(aha->buffer_dmat, accb->dmamap); 111741047Sgibbs ahafreeccb(aha, accb); 111841047Sgibbs aha->resource_shortage = TRUE; 111941047Sgibbs xpt_freeze_simq(aha->sim, /*count*/1); 112041047Sgibbs ccb->ccb_h.status = CAM_REQUEUE_REQ; 112141047Sgibbs xpt_done(ccb); 112241047Sgibbs return; 112341047Sgibbs } 112441047Sgibbs paddr = ahaccbvtop(aha, accb); 112539225Sgibbs ahautoa24(paddr, aha->cur_outbox->ccb_addr); 1126122363Simp aha->cur_outbox->action_code = AMBO_START; 112741047Sgibbs aha_outb(aha, COMMAND_REG, AOP_START_MBOX); 112839225Sgibbs 112939225Sgibbs ahanextoutbox(aha); 113039225Sgibbs splx(s); 113139225Sgibbs} 113239225Sgibbs 113339225Sgibbsvoid 113439225Sgibbsaha_intr(void *arg) 113539225Sgibbs{ 113639225Sgibbs struct aha_softc *aha; 113739225Sgibbs u_int intstat; 1138122340Simp uint32_t paddr; 113939225Sgibbs 114039225Sgibbs aha = (struct aha_softc *)arg; 114139225Sgibbs while (((intstat = aha_inb(aha, INTSTAT_REG)) & INTR_PENDING) != 0) { 114239225Sgibbs if ((intstat & CMD_COMPLETE) != 0) { 114339225Sgibbs aha->latched_status = aha_inb(aha, STATUS_REG); 114439225Sgibbs aha->command_cmp = TRUE; 114539225Sgibbs } 114639225Sgibbs 114739225Sgibbs aha_outb(aha, CONTROL_REG, RESET_INTR); 114839225Sgibbs 114939225Sgibbs if ((intstat & IMB_LOADED) != 0) { 115041047Sgibbs while (aha->cur_inbox->comp_code != AMBI_FREE) { 115139225Sgibbs paddr = aha_a24tou(aha->cur_inbox->ccb_addr); 1152122340Simp ahadone(aha, ahaccbptov(aha, paddr), 1153122340Simp aha->cur_inbox->comp_code); 115441047Sgibbs aha->cur_inbox->comp_code = AMBI_FREE; 115539225Sgibbs ahanextinbox(aha); 115639225Sgibbs } 115739225Sgibbs } 115839225Sgibbs 115939225Sgibbs if ((intstat & SCSI_BUS_RESET) != 0) { 116039225Sgibbs ahareset(aha, /*hardreset*/FALSE); 116139225Sgibbs } 116239225Sgibbs } 116339225Sgibbs} 116439225Sgibbs 116539225Sgibbsstatic void 116641047Sgibbsahadone(struct aha_softc *aha, struct aha_ccb *accb, aha_mbi_comp_code_t comp_code) 116739225Sgibbs{ 116839225Sgibbs union ccb *ccb; 116939225Sgibbs struct ccb_scsiio *csio; 117039225Sgibbs 117141047Sgibbs ccb = accb->ccb; 117241047Sgibbs csio = &accb->ccb->csio; 117339225Sgibbs 117441047Sgibbs if ((accb->flags & ACCB_ACTIVE) == 0) { 1175122597Simp device_printf(aha->dev, 1176122597Simp "ahadone - Attempt to free non-active ACCB %p\n", 1177122597Simp (void *)accb); 117839225Sgibbs return; 117939225Sgibbs } 118039225Sgibbs 118139225Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 1182115343Sscottl bus_dmasync_op_t op; 118339225Sgibbs 118439225Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 118539225Sgibbs op = BUS_DMASYNC_POSTREAD; 118639225Sgibbs else 118739225Sgibbs op = BUS_DMASYNC_POSTWRITE; 118841047Sgibbs bus_dmamap_sync(aha->buffer_dmat, accb->dmamap, op); 118941047Sgibbs bus_dmamap_unload(aha->buffer_dmat, accb->dmamap); 119039225Sgibbs } 119139225Sgibbs 119241047Sgibbs if (accb == aha->recovery_accb) { 119339225Sgibbs /* 119441047Sgibbs * The recovery ACCB does not have a CCB associated 119539225Sgibbs * with it, so short circuit the normal error handling. 119639225Sgibbs * We now traverse our list of pending CCBs and process 119739225Sgibbs * any that were terminated by the recovery CCBs action. 119839225Sgibbs * We also reinstate timeouts for all remaining, pending, 119939225Sgibbs * CCBs. 120039225Sgibbs */ 120139225Sgibbs struct cam_path *path; 120239225Sgibbs struct ccb_hdr *ccb_h; 120339225Sgibbs cam_status error; 120439225Sgibbs 120539225Sgibbs /* Notify all clients that a BDR occured */ 120639225Sgibbs error = xpt_create_path(&path, /*periph*/NULL, 1207122340Simp cam_sim_path(aha->sim), accb->hccb.target, 1208122340Simp CAM_LUN_WILDCARD); 1209122363Simp 121039225Sgibbs if (error == CAM_REQ_CMP) 121139225Sgibbs xpt_async(AC_SENT_BDR, path, NULL); 121239225Sgibbs 121339225Sgibbs ccb_h = LIST_FIRST(&aha->pending_ccbs); 121439225Sgibbs while (ccb_h != NULL) { 121541047Sgibbs struct aha_ccb *pending_accb; 121639225Sgibbs 121741047Sgibbs pending_accb = (struct aha_ccb *)ccb_h->ccb_accb_ptr; 121841047Sgibbs if (pending_accb->hccb.target == accb->hccb.target) { 121941047Sgibbs pending_accb->hccb.ahastat = AHASTAT_HA_BDR; 122039225Sgibbs ccb_h = LIST_NEXT(ccb_h, sim_links.le); 122141047Sgibbs ahadone(aha, pending_accb, AMBI_ERROR); 122239225Sgibbs } else { 1223122340Simp ccb_h->timeout_ch = timeout(ahatimeout, 1224122340Simp (caddr_t)pending_accb, 1225122340Simp (ccb_h->timeout * hz) / 1000); 122639225Sgibbs ccb_h = LIST_NEXT(ccb_h, sim_links.le); 122739225Sgibbs } 122839225Sgibbs } 1229122597Simp device_printf(aha->dev, "No longer in timeout\n"); 123039225Sgibbs return; 123139225Sgibbs } 123239225Sgibbs 123341047Sgibbs untimeout(ahatimeout, accb, ccb->ccb_h.timeout_ch); 123439225Sgibbs 123539225Sgibbs switch (comp_code) { 123641047Sgibbs case AMBI_FREE: 1237122597Simp device_printf(aha->dev, 1238122597Simp "ahadone - CCB completed with free status!\n"); 123939225Sgibbs break; 124041047Sgibbs case AMBI_NOT_FOUND: 1241122597Simp device_printf(aha->dev, 1242122597Simp "ahadone - CCB Abort failed to find CCB\n"); 124339225Sgibbs break; 124441047Sgibbs case AMBI_ABORT: 124541047Sgibbs case AMBI_ERROR: 124639225Sgibbs /* An error occured */ 124742887Simp if (accb->hccb.opcode < INITIATOR_CCB_WRESID) 124842887Simp csio->resid = 0; 124942887Simp else 125042887Simp csio->resid = aha_a24tou(accb->hccb.data_len); 125141047Sgibbs switch(accb->hccb.ahastat) { 125239225Sgibbs case AHASTAT_DATARUN_ERROR: 125342013Sgibbs { 125442013Sgibbs if (csio->resid <= 0) { 125539225Sgibbs csio->ccb_h.status = CAM_DATA_RUN_ERR; 125639225Sgibbs break; 125739225Sgibbs } 125839225Sgibbs /* FALLTHROUGH */ 125942013Sgibbs } 126039225Sgibbs case AHASTAT_NOERROR: 126141047Sgibbs csio->scsi_status = accb->hccb.sdstat; 126239225Sgibbs csio->ccb_h.status |= CAM_SCSI_STATUS_ERROR; 126339225Sgibbs switch(csio->scsi_status) { 126439225Sgibbs case SCSI_STATUS_CHECK_COND: 126539225Sgibbs case SCSI_STATUS_CMD_TERMINATED: 126639225Sgibbs csio->ccb_h.status |= CAM_AUTOSNS_VALID; 126739225Sgibbs /* 126839225Sgibbs * The aha writes the sense data at different 126939225Sgibbs * offsets based on the scsi cmd len 127039225Sgibbs */ 127141047Sgibbs bcopy((caddr_t) &accb->hccb.scsi_cdb + 1272122363Simp accb->hccb.cmd_len, 1273122340Simp (caddr_t) &csio->sense_data, 1274122340Simp accb->hccb.sense_len); 127539225Sgibbs break; 127639225Sgibbs default: 127739225Sgibbs break; 127839225Sgibbs case SCSI_STATUS_OK: 127939225Sgibbs csio->ccb_h.status = CAM_REQ_CMP; 128039225Sgibbs break; 128139225Sgibbs } 128239225Sgibbs break; 128339225Sgibbs case AHASTAT_SELTIMEOUT: 128439225Sgibbs csio->ccb_h.status = CAM_SEL_TIMEOUT; 128539225Sgibbs break; 128639225Sgibbs case AHASTAT_UNEXPECTED_BUSFREE: 128739225Sgibbs csio->ccb_h.status = CAM_UNEXP_BUSFREE; 128839225Sgibbs break; 128939225Sgibbs case AHASTAT_INVALID_PHASE: 129039225Sgibbs csio->ccb_h.status = CAM_SEQUENCE_FAIL; 129139225Sgibbs break; 129239225Sgibbs case AHASTAT_INVALID_ACTION_CODE: 129339225Sgibbs panic("%s: Inavlid Action code", aha_name(aha)); 129439225Sgibbs break; 129539225Sgibbs case AHASTAT_INVALID_OPCODE: 129642887Simp if (accb->hccb.opcode < INITIATOR_CCB_WRESID) 129742887Simp panic("%s: Invalid CCB Opcode %x hccb = %p", 1298122340Simp aha_name(aha), accb->hccb.opcode, 1299122340Simp &accb->hccb); 1300122597Simp device_printf(aha->dev, 1301140025Simp "AHA-1540A compensation failed\n"); 130242887Simp xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 130342887Simp csio->ccb_h.status = CAM_REQUEUE_REQ; 130439225Sgibbs break; 130539225Sgibbs case AHASTAT_LINKED_CCB_LUN_MISMATCH: 130639225Sgibbs /* We don't even support linked commands... */ 130739225Sgibbs panic("%s: Linked CCB Lun Mismatch", aha_name(aha)); 130839225Sgibbs break; 130939225Sgibbs case AHASTAT_INVALID_CCB_OR_SG_PARAM: 131039225Sgibbs panic("%s: Invalid CCB or SG list", aha_name(aha)); 131139225Sgibbs break; 131239225Sgibbs case AHASTAT_HA_SCSI_BUS_RESET: 131339225Sgibbs if ((csio->ccb_h.status & CAM_STATUS_MASK) 131442887Simp != CAM_CMD_TIMEOUT) 131539225Sgibbs csio->ccb_h.status = CAM_SCSI_BUS_RESET; 131639225Sgibbs break; 131739225Sgibbs case AHASTAT_HA_BDR: 131841047Sgibbs if ((accb->flags & ACCB_DEVICE_RESET) == 0) 131939225Sgibbs csio->ccb_h.status = CAM_BDR_SENT; 132039225Sgibbs else 132139225Sgibbs csio->ccb_h.status = CAM_CMD_TIMEOUT; 132239225Sgibbs break; 132339225Sgibbs } 132439225Sgibbs if (csio->ccb_h.status != CAM_REQ_CMP) { 132539225Sgibbs xpt_freeze_devq(csio->ccb_h.path, /*count*/1); 132639225Sgibbs csio->ccb_h.status |= CAM_DEV_QFRZN; 132739225Sgibbs } 132841047Sgibbs if ((accb->flags & ACCB_RELEASE_SIMQ) != 0) 132939225Sgibbs ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 133041047Sgibbs ahafreeccb(aha, accb); 133139225Sgibbs xpt_done(ccb); 133239225Sgibbs break; 133341047Sgibbs case AMBI_OK: 133439225Sgibbs /* All completed without incident */ 133539225Sgibbs /* XXX DO WE NEED TO COPY SENSE BYTES HERE???? XXX */ 133642887Simp /* I don't think so since it works???? */ 133739225Sgibbs ccb->ccb_h.status |= CAM_REQ_CMP; 133841047Sgibbs if ((accb->flags & ACCB_RELEASE_SIMQ) != 0) 133939225Sgibbs ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 134041047Sgibbs ahafreeccb(aha, accb); 134139225Sgibbs xpt_done(ccb); 134239225Sgibbs break; 134339225Sgibbs } 134439225Sgibbs} 134539225Sgibbs 134639225Sgibbsstatic int 134739225Sgibbsahareset(struct aha_softc* aha, int hard_reset) 134839225Sgibbs{ 134939225Sgibbs struct ccb_hdr *ccb_h; 135039225Sgibbs u_int status; 135139225Sgibbs u_int timeout; 1352122340Simp uint8_t reset_type; 135339225Sgibbs 135439225Sgibbs if (hard_reset != 0) 135539225Sgibbs reset_type = HARD_RESET; 135639225Sgibbs else 135739225Sgibbs reset_type = SOFT_RESET; 135839225Sgibbs aha_outb(aha, CONTROL_REG, reset_type); 135939225Sgibbs 136039225Sgibbs /* Wait 5sec. for Diagnostic start */ 136139225Sgibbs timeout = 5 * 10000; 136239225Sgibbs while (--timeout) { 136339225Sgibbs status = aha_inb(aha, STATUS_REG); 136439225Sgibbs if ((status & DIAG_ACTIVE) != 0) 136539225Sgibbs break; 136639225Sgibbs DELAY(100); 136739225Sgibbs } 136839225Sgibbs if (timeout == 0) { 1369122597Simp PRVERB((aha->dev, "ahareset - Diagnostic Active failed to " 1370122597Simp "assert. status = %#x\n", status)); 137139225Sgibbs return (ETIMEDOUT); 137239225Sgibbs } 137339225Sgibbs 137439225Sgibbs /* Wait 10sec. for Diagnostic end */ 137539225Sgibbs timeout = 10 * 10000; 137639225Sgibbs while (--timeout) { 137739225Sgibbs status = aha_inb(aha, STATUS_REG); 137839225Sgibbs if ((status & DIAG_ACTIVE) == 0) 137939225Sgibbs break; 138039225Sgibbs DELAY(100); 138139225Sgibbs } 138239225Sgibbs if (timeout == 0) { 138339225Sgibbs panic("%s: ahareset - Diagnostic Active failed to drop. " 1384122340Simp "status = 0x%x\n", aha_name(aha), status); 138539225Sgibbs return (ETIMEDOUT); 138639225Sgibbs } 138739225Sgibbs 138839225Sgibbs /* Wait for the host adapter to become ready or report a failure */ 138939225Sgibbs timeout = 10000; 139039225Sgibbs while (--timeout) { 139139225Sgibbs status = aha_inb(aha, STATUS_REG); 139239225Sgibbs if ((status & (DIAG_FAIL|HA_READY|DATAIN_REG_READY)) != 0) 139339225Sgibbs break; 139439225Sgibbs DELAY(100); 139539225Sgibbs } 139639225Sgibbs if (timeout == 0) { 1397122597Simp device_printf(aha->dev, "ahareset - Host adapter failed to " 1398122597Simp "come ready. status = 0x%x\n", status); 139939225Sgibbs return (ETIMEDOUT); 140039225Sgibbs } 140139225Sgibbs 140239225Sgibbs /* If the diagnostics failed, tell the user */ 140339225Sgibbs if ((status & DIAG_FAIL) != 0 140439225Sgibbs || (status & HA_READY) == 0) { 1405122597Simp device_printf(aha->dev, "ahareset - Adapter failed diag\n"); 140639225Sgibbs 140739225Sgibbs if ((status & DATAIN_REG_READY) != 0) 1408122597Simp device_printf(aha->dev, "ahareset - Host Adapter " 1409122597Simp "Error code = 0x%x\n", aha_inb(aha, DATAIN_REG)); 141039225Sgibbs return (ENXIO); 141139225Sgibbs } 141239225Sgibbs 141339225Sgibbs /* If we've attached to the XPT, tell it about the event */ 141439225Sgibbs if (aha->path != NULL) 141539225Sgibbs xpt_async(AC_BUS_RESET, aha->path, NULL); 141639225Sgibbs 141739225Sgibbs /* 141839225Sgibbs * Perform completion processing for all outstanding CCBs. 141939225Sgibbs */ 142039225Sgibbs while ((ccb_h = LIST_FIRST(&aha->pending_ccbs)) != NULL) { 142141047Sgibbs struct aha_ccb *pending_accb; 142239225Sgibbs 142341047Sgibbs pending_accb = (struct aha_ccb *)ccb_h->ccb_accb_ptr; 142441047Sgibbs pending_accb->hccb.ahastat = AHASTAT_HA_SCSI_BUS_RESET; 142541047Sgibbs ahadone(aha, pending_accb, AMBI_ERROR); 142639225Sgibbs } 142739225Sgibbs 1428122360Simp /* If we've allocated mailboxes, initialize them */ 1429122360Simp /* Must be done after we've aborted our queue, or aha_cmd fails */ 1430122360Simp if (aha->init_level > 4) 1431122360Simp ahainitmboxes(aha); 1432122360Simp 143339225Sgibbs return (0); 143439225Sgibbs} 143539225Sgibbs 143639225Sgibbs/* 143739225Sgibbs * Send a command to the adapter. 143839225Sgibbs */ 143939225Sgibbsint 1440122363Simpaha_cmd(struct aha_softc *aha, aha_op_t opcode, uint8_t *params, 1441122363Simp u_int param_len, uint8_t *reply_data, u_int reply_len, 144247506Sgibbs u_int cmd_timeout) 144339225Sgibbs{ 144439225Sgibbs u_int timeout; 144539225Sgibbs u_int status; 144647506Sgibbs u_int saved_status; 144739225Sgibbs u_int intstat; 144839225Sgibbs u_int reply_buf_size; 144939225Sgibbs int s; 145041709Sgibbs int cmd_complete; 145147506Sgibbs int error; 145239225Sgibbs 145339225Sgibbs /* No data returned to start */ 145439225Sgibbs reply_buf_size = reply_len; 145539225Sgibbs reply_len = 0; 145639225Sgibbs intstat = 0; 145741709Sgibbs cmd_complete = 0; 145847506Sgibbs saved_status = 0; 145947506Sgibbs error = 0; 146039225Sgibbs 146147506Sgibbs /* 146247506Sgibbs * All commands except for the "start mailbox" and the "enable 146347506Sgibbs * outgoing mailbox read interrupt" commands cannot be issued 146447506Sgibbs * while there are pending transactions. Freeze our SIMQ 146547506Sgibbs * and wait for all completions to occur if necessary. 146647506Sgibbs */ 1467122360Simp timeout = 10000; 146847506Sgibbs s = splcam(); 146947506Sgibbs while (LIST_FIRST(&aha->pending_ccbs) != NULL && --timeout) { 147047506Sgibbs /* Fire the interrupt handler in case interrupts are blocked */ 147147506Sgibbs aha_intr(aha); 147247506Sgibbs splx(s); 1473122360Simp DELAY(10); 147447506Sgibbs s = splcam(); 147547506Sgibbs } 147647506Sgibbs splx(s); 147747506Sgibbs 147847506Sgibbs if (timeout == 0) { 1479122597Simp device_printf(aha->dev, 1480122597Simp "aha_cmd: Timeout waiting for adapter idle\n"); 148147506Sgibbs return (ETIMEDOUT); 148247506Sgibbs } 148339225Sgibbs aha->command_cmp = 0; 148439225Sgibbs /* 148547506Sgibbs * Wait up to 10 sec. for the adapter to become 148639225Sgibbs * ready to accept commands. 148739225Sgibbs */ 148847506Sgibbs timeout = 100000; 148939225Sgibbs while (--timeout) { 149039225Sgibbs status = aha_inb(aha, STATUS_REG); 1491122340Simp if ((status & HA_READY) != 0 && (status & CMD_REG_BUSY) == 0) 149239225Sgibbs break; 149347506Sgibbs /* 149447506Sgibbs * Throw away any pending data which may be 149547506Sgibbs * left over from earlier commands that we 149647506Sgibbs * timedout on. 149747506Sgibbs */ 149847506Sgibbs if ((status & DATAIN_REG_READY) != 0) 149947506Sgibbs (void)aha_inb(aha, DATAIN_REG); 150039225Sgibbs DELAY(100); 150139225Sgibbs } 150239225Sgibbs if (timeout == 0) { 1503122597Simp device_printf(aha->dev, "aha_cmd: Timeout waiting for adapter" 1504122597Simp " ready, status = 0x%x\n", status); 150539225Sgibbs return (ETIMEDOUT); 150639225Sgibbs } 150739225Sgibbs 150839225Sgibbs /* 150939225Sgibbs * Send the opcode followed by any necessary parameter bytes. 151039225Sgibbs */ 151139225Sgibbs aha_outb(aha, COMMAND_REG, opcode); 151239225Sgibbs 151339225Sgibbs /* 151439225Sgibbs * Wait for up to 1sec to get the parameter list sent 151539225Sgibbs */ 151639225Sgibbs timeout = 10000; 151739225Sgibbs while (param_len && --timeout) { 151839225Sgibbs DELAY(100); 151947506Sgibbs s = splcam(); 152039225Sgibbs status = aha_inb(aha, STATUS_REG); 152139225Sgibbs intstat = aha_inb(aha, INTSTAT_REG); 152247506Sgibbs splx(s); 152347506Sgibbs 152439225Sgibbs if ((intstat & (INTR_PENDING|CMD_COMPLETE)) 152541709Sgibbs == (INTR_PENDING|CMD_COMPLETE)) { 152647506Sgibbs saved_status = status; 152741709Sgibbs cmd_complete = 1; 152839225Sgibbs break; 152941709Sgibbs } 153047506Sgibbs 153139225Sgibbs if (aha->command_cmp != 0) { 153247506Sgibbs saved_status = aha->latched_status; 153341709Sgibbs cmd_complete = 1; 153439225Sgibbs break; 153539225Sgibbs } 153639225Sgibbs if ((status & DATAIN_REG_READY) != 0) 153739225Sgibbs break; 153839225Sgibbs if ((status & CMD_REG_BUSY) == 0) { 153939225Sgibbs aha_outb(aha, COMMAND_REG, *params++); 154039225Sgibbs param_len--; 154147506Sgibbs timeout = 10000; 154239225Sgibbs } 154339225Sgibbs } 154439225Sgibbs if (timeout == 0) { 1545122597Simp device_printf(aha->dev, "aha_cmd: Timeout sending parameters, " 1546122597Simp "status = 0x%x\n", status); 154747506Sgibbs error = ETIMEDOUT; 154839225Sgibbs } 154939225Sgibbs 155039225Sgibbs /* 155139225Sgibbs * For all other commands, we wait for any output data 155239225Sgibbs * and the final comand completion interrupt. 155339225Sgibbs */ 155441709Sgibbs while (cmd_complete == 0 && --cmd_timeout) { 155539225Sgibbs 155647506Sgibbs s = splcam(); 155739225Sgibbs status = aha_inb(aha, STATUS_REG); 155839225Sgibbs intstat = aha_inb(aha, INTSTAT_REG); 155947506Sgibbs splx(s); 156039225Sgibbs 156139225Sgibbs if (aha->command_cmp != 0) { 156247506Sgibbs cmd_complete = 1; 156347506Sgibbs saved_status = aha->latched_status; 156447506Sgibbs } else if ((intstat & (INTR_PENDING|CMD_COMPLETE)) 156547506Sgibbs == (INTR_PENDING|CMD_COMPLETE)) { 156647506Sgibbs /* 156747506Sgibbs * Our poll (in case interrupts are blocked) 156847506Sgibbs * saw the CMD_COMPLETE interrupt. 156947506Sgibbs */ 157047506Sgibbs cmd_complete = 1; 157147506Sgibbs saved_status = status; 157251869Smdodd } 157351869Smdodd if ((status & DATAIN_REG_READY) != 0) { 1574122340Simp uint8_t data; 157539225Sgibbs 157639225Sgibbs data = aha_inb(aha, DATAIN_REG); 157739225Sgibbs if (reply_len < reply_buf_size) { 157839225Sgibbs *reply_data++ = data; 157939225Sgibbs } else { 1580122597Simp device_printf(aha->dev, 1581122597Simp "aha_cmd - Discarded reply data " 1582122597Simp "byte for opcode 0x%x\n", opcode); 158339225Sgibbs } 158447506Sgibbs /* 158547506Sgibbs * Reset timeout to ensure at least a second 158647506Sgibbs * between response bytes. 158747506Sgibbs */ 158847506Sgibbs cmd_timeout = MAX(cmd_timeout, 10000); 158939225Sgibbs reply_len++; 159039225Sgibbs } 159139225Sgibbs DELAY(100); 159239225Sgibbs } 159347506Sgibbs if (cmd_timeout == 0) { 1594122597Simp device_printf(aha->dev, "aha_cmd: Timeout: status = 0x%x, " 1595122597Simp "intstat = 0x%x, reply_len = %d\n", status, intstat, 1596122597Simp reply_len); 159739225Sgibbs return (ETIMEDOUT); 159839225Sgibbs } 159939225Sgibbs 160039225Sgibbs /* 160139225Sgibbs * Clear any pending interrupts. Block interrupts so our 160239225Sgibbs * interrupt handler is not re-entered. 160339225Sgibbs */ 160439225Sgibbs s = splcam(); 160539225Sgibbs aha_intr(aha); 160639225Sgibbs splx(s); 1607122363Simp 160847506Sgibbs if (error != 0) 160947506Sgibbs return (error); 161047506Sgibbs 161139225Sgibbs /* 161239225Sgibbs * If the command was rejected by the controller, tell the caller. 161339225Sgibbs */ 161447506Sgibbs if ((saved_status & CMD_INVALID) != 0) { 1615122597Simp PRVERB((aha->dev, "Invalid Command 0x%x\n", opcode)); 161639225Sgibbs /* 161739225Sgibbs * Some early adapters may not recover properly from 161839225Sgibbs * an invalid command. If it appears that the controller 161939225Sgibbs * has wedged (i.e. status was not cleared by our interrupt 162039225Sgibbs * reset above), perform a soft reset. 162139225Sgibbs */ 162239225Sgibbs DELAY(1000); 162339225Sgibbs status = aha_inb(aha, STATUS_REG); 162439225Sgibbs if ((status & (CMD_INVALID|STATUS_REG_RSVD|DATAIN_REG_READY| 162539225Sgibbs CMD_REG_BUSY|DIAG_FAIL|DIAG_ACTIVE)) != 0 162639225Sgibbs || (status & (HA_READY|INIT_REQUIRED)) 1627122340Simp != (HA_READY|INIT_REQUIRED)) 162839852Simp ahareset(aha, /*hard_reset*/FALSE); 162939225Sgibbs return (EINVAL); 163039225Sgibbs } 163139225Sgibbs 163239225Sgibbs if (param_len > 0) { 163339225Sgibbs /* The controller did not accept the full argument list */ 1634122597Simp PRVERB((aha->dev, "Controller did not accept full argument " 1635122597Simp "list (%d > 0)\n", param_len)); 163639225Sgibbs return (E2BIG); 163739225Sgibbs } 163839225Sgibbs 163939225Sgibbs if (reply_len != reply_buf_size) { 164039225Sgibbs /* Too much or too little data received */ 1641122597Simp PRVERB((aha->dev, "data received mismatch (%d != %d)\n", 1642122597Simp reply_len, reply_buf_size)); 164339225Sgibbs return (EMSGSIZE); 164439225Sgibbs } 164539225Sgibbs 164639225Sgibbs /* We were successful */ 164739225Sgibbs return (0); 164839225Sgibbs} 164939225Sgibbs 165039225Sgibbsstatic int 1651122363Simpahainitmboxes(struct aha_softc *aha) 165239225Sgibbs{ 165339225Sgibbs int error; 165439225Sgibbs init_24b_mbox_params_t init_mbox; 165539225Sgibbs 165639225Sgibbs bzero(aha->in_boxes, sizeof(aha_mbox_in_t) * aha->num_boxes); 165739225Sgibbs bzero(aha->out_boxes, sizeof(aha_mbox_out_t) * aha->num_boxes); 165839225Sgibbs aha->cur_inbox = aha->in_boxes; 165939225Sgibbs aha->last_inbox = aha->in_boxes + aha->num_boxes - 1; 166039225Sgibbs aha->cur_outbox = aha->out_boxes; 166139225Sgibbs aha->last_outbox = aha->out_boxes + aha->num_boxes - 1; 166239225Sgibbs 166339225Sgibbs /* Tell the adapter about them */ 166439225Sgibbs init_mbox.num_mboxes = aha->num_boxes; 166539225Sgibbs ahautoa24(aha->mailbox_physbase, init_mbox.base_addr); 1666122340Simp error = aha_cmd(aha, AOP_INITIALIZE_MBOX, (uint8_t *)&init_mbox, 1667122340Simp /*parmlen*/sizeof(init_mbox), /*reply_buf*/NULL, 1668122340Simp /*reply_len*/0, DEFAULT_CMD_TIMEOUT); 166939225Sgibbs 167039225Sgibbs if (error != 0) 167139225Sgibbs printf("ahainitmboxes: Initialization command failed\n"); 167239225Sgibbs return (error); 167339225Sgibbs} 167439225Sgibbs 167539225Sgibbs/* 167639225Sgibbs * Update the XPT's idea of the negotiated transfer 167739225Sgibbs * parameters for a particular target. 167839225Sgibbs */ 167939225Sgibbsstatic void 168039225Sgibbsahafetchtransinfo(struct aha_softc *aha, struct ccb_trans_settings* cts) 168139225Sgibbs{ 168239225Sgibbs setup_data_t setup_info; 168339225Sgibbs u_int target; 168439225Sgibbs u_int targ_offset; 168539225Sgibbs u_int sync_period; 168639225Sgibbs int error; 1687122340Simp uint8_t param; 168839225Sgibbs targ_syncinfo_t sync_info; 1689163816Smjacob struct ccb_trans_settings_spi *spi = &cts->xport_specific.spi; 169039225Sgibbs 169139225Sgibbs target = cts->ccb_h.target_id; 169239225Sgibbs targ_offset = (target & 0x7); 169339225Sgibbs 169439225Sgibbs /* 169547208Simp * Inquire Setup Information. This command retreives 169647506Sgibbs * the sync info for older models. 169739225Sgibbs */ 169839225Sgibbs param = sizeof(setup_info); 169941047Sgibbs error = aha_cmd(aha, AOP_INQUIRE_SETUP_INFO, ¶m, /*paramlen*/1, 1700122340Simp (uint8_t*)&setup_info, sizeof(setup_info), DEFAULT_CMD_TIMEOUT); 170139225Sgibbs 170239225Sgibbs if (error != 0) { 1703122597Simp device_printf(aha->dev, 1704122597Simp "ahafetchtransinfo - Inquire Setup Info Failed %d\n", 1705122597Simp error); 170639225Sgibbs return; 170739225Sgibbs } 170839225Sgibbs 170939225Sgibbs sync_info = setup_info.syncinfo[targ_offset]; 171039225Sgibbs 171139225Sgibbs if (sync_info.sync == 0) 1712163816Smjacob spi->sync_offset = 0; 1713163816Smjacob else 1714163816Smjacob spi->sync_offset = sync_info.offset; 1715163816Smjacob 1716163816Smjacob spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 1717163816Smjacob 1718163816Smjacob if (aha->boardid >= BOARD_1542CF) 1719163816Smjacob sync_period = 1000; 1720163816Smjacob else 1721163816Smjacob sync_period = 2000; 1722163816Smjacob sync_period += 500 * sync_info.period; 1723163816Smjacob 1724163816Smjacob /* Convert ns value to standard SCSI sync rate */ 1725163816Smjacob if (spi->sync_offset != 0) 1726163816Smjacob spi->sync_period = scsi_calc_syncparam(sync_period); 1727163816Smjacob else 1728163816Smjacob spi->sync_period = 0; 1729163816Smjacob 1730163816Smjacob spi->valid = CTS_SPI_VALID_SYNC_RATE 1731163816Smjacob | CTS_SPI_VALID_SYNC_OFFSET 1732163816Smjacob | CTS_SPI_VALID_BUS_WIDTH; 173339225Sgibbs xpt_async(AC_TRANSFER_NEG, cts->ccb_h.path, cts); 173439225Sgibbs} 173539225Sgibbs 173639225Sgibbsstatic void 173739225Sgibbsahamapmboxes(void *arg, bus_dma_segment_t *segs, int nseg, int error) 173839225Sgibbs{ 173939225Sgibbs struct aha_softc* aha; 174039225Sgibbs 174139225Sgibbs aha = (struct aha_softc*)arg; 174239225Sgibbs aha->mailbox_physbase = segs->ds_addr; 174339225Sgibbs} 174439225Sgibbs 174539225Sgibbsstatic void 174639225Sgibbsahamapccbs(void *arg, bus_dma_segment_t *segs, int nseg, int error) 174739225Sgibbs{ 174839225Sgibbs struct aha_softc* aha; 174939225Sgibbs 175039225Sgibbs aha = (struct aha_softc*)arg; 175139225Sgibbs aha->aha_ccb_physbase = segs->ds_addr; 175239225Sgibbs} 175339225Sgibbs 175439225Sgibbsstatic void 175539225Sgibbsahamapsgs(void *arg, bus_dma_segment_t *segs, int nseg, int error) 175639225Sgibbs{ 175739225Sgibbs 175839225Sgibbs struct aha_softc* aha; 175939225Sgibbs 176039225Sgibbs aha = (struct aha_softc*)arg; 176139225Sgibbs SLIST_FIRST(&aha->sg_maps)->sg_physaddr = segs->ds_addr; 176239225Sgibbs} 176339225Sgibbs 176439225Sgibbsstatic void 176539225Sgibbsahapoll(struct cam_sim *sim) 176639225Sgibbs{ 176740132Sgibbs aha_intr(cam_sim_softc(sim)); 176839225Sgibbs} 176939225Sgibbs 177045575Seivindstatic void 177139225Sgibbsahatimeout(void *arg) 177239225Sgibbs{ 177341047Sgibbs struct aha_ccb *accb; 177439225Sgibbs union ccb *ccb; 177539225Sgibbs struct aha_softc *aha; 177639225Sgibbs int s; 1777122340Simp uint32_t paddr; 1778122360Simp struct ccb_hdr *ccb_h; 177939225Sgibbs 178041047Sgibbs accb = (struct aha_ccb *)arg; 178141047Sgibbs ccb = accb->ccb; 178239225Sgibbs aha = (struct aha_softc *)ccb->ccb_h.ccb_aha_ptr; 178339225Sgibbs xpt_print_path(ccb->ccb_h.path); 178441047Sgibbs printf("CCB %p - timed out\n", (void *)accb); 178539225Sgibbs 178639225Sgibbs s = splcam(); 178739225Sgibbs 178841047Sgibbs if ((accb->flags & ACCB_ACTIVE) == 0) { 178939225Sgibbs xpt_print_path(ccb->ccb_h.path); 179039390Sgibbs printf("CCB %p - timed out CCB already completed\n", 1791122340Simp (void *)accb); 179239225Sgibbs splx(s); 179339225Sgibbs return; 179439225Sgibbs } 179539225Sgibbs 179639225Sgibbs /* 179739225Sgibbs * In order to simplify the recovery process, we ask the XPT 179839225Sgibbs * layer to halt the queue of new transactions and we traverse 179939225Sgibbs * the list of pending CCBs and remove their timeouts. This 180039225Sgibbs * means that the driver attempts to clear only one error 180139225Sgibbs * condition at a time. In general, timeouts that occur 180239225Sgibbs * close together are related anyway, so there is no benefit 180339225Sgibbs * in attempting to handle errors in parrallel. Timeouts will 180439225Sgibbs * be reinstated when the recovery process ends. 180539225Sgibbs */ 180641047Sgibbs if ((accb->flags & ACCB_DEVICE_RESET) == 0) { 180741047Sgibbs if ((accb->flags & ACCB_RELEASE_SIMQ) == 0) { 180839225Sgibbs xpt_freeze_simq(aha->sim, /*count*/1); 180941047Sgibbs accb->flags |= ACCB_RELEASE_SIMQ; 181039225Sgibbs } 181139225Sgibbs 181239225Sgibbs ccb_h = LIST_FIRST(&aha->pending_ccbs); 181339225Sgibbs while (ccb_h != NULL) { 181441047Sgibbs struct aha_ccb *pending_accb; 181539225Sgibbs 181641047Sgibbs pending_accb = (struct aha_ccb *)ccb_h->ccb_accb_ptr; 181741047Sgibbs untimeout(ahatimeout, pending_accb, ccb_h->timeout_ch); 181839225Sgibbs ccb_h = LIST_NEXT(ccb_h, sim_links.le); 181939225Sgibbs } 182039225Sgibbs } 182139225Sgibbs 182241047Sgibbs if ((accb->flags & ACCB_DEVICE_RESET) != 0 182341047Sgibbs || aha->cur_outbox->action_code != AMBO_FREE) { 182439225Sgibbs /* 182539225Sgibbs * Try a full host adapter/SCSI bus reset. 182639225Sgibbs * We do this only if we have already attempted 182739225Sgibbs * to clear the condition with a BDR, or we cannot 182839225Sgibbs * attempt a BDR for lack of mailbox resources. 182939225Sgibbs */ 183039225Sgibbs ccb->ccb_h.status = CAM_CMD_TIMEOUT; 183139225Sgibbs ahareset(aha, /*hardreset*/TRUE); 1832122597Simp device_printf(aha->dev, "No longer in timeout\n"); 183339225Sgibbs } else { 1834122363Simp /* 183539225Sgibbs * Send a Bus Device Reset message: 183639225Sgibbs * The target that is holding up the bus may not 183739225Sgibbs * be the same as the one that triggered this timeout 183839225Sgibbs * (different commands have different timeout lengths), 183939225Sgibbs * but we have no way of determining this from our 184039225Sgibbs * timeout handler. Our strategy here is to queue a 184139225Sgibbs * BDR message to the target of the timed out command. 184239225Sgibbs * If this fails, we'll get another timeout 2 seconds 184339225Sgibbs * later which will attempt a bus reset. 184439225Sgibbs */ 184541047Sgibbs accb->flags |= ACCB_DEVICE_RESET; 184641047Sgibbs ccb->ccb_h.timeout_ch = timeout(ahatimeout, (caddr_t)accb, 2 * hz); 184741047Sgibbs aha->recovery_accb->hccb.opcode = INITIATOR_BUS_DEV_RESET; 184839225Sgibbs 184939225Sgibbs /* No Data Transfer */ 185041047Sgibbs aha->recovery_accb->hccb.datain = TRUE; 185141047Sgibbs aha->recovery_accb->hccb.dataout = TRUE; 185241047Sgibbs aha->recovery_accb->hccb.ahastat = 0; 185341047Sgibbs aha->recovery_accb->hccb.sdstat = 0; 185441047Sgibbs aha->recovery_accb->hccb.target = ccb->ccb_h.target_id; 185539225Sgibbs 185639225Sgibbs /* Tell the adapter about this command */ 185741047Sgibbs paddr = ahaccbvtop(aha, aha->recovery_accb); 185839225Sgibbs ahautoa24(paddr, aha->cur_outbox->ccb_addr); 185941047Sgibbs aha->cur_outbox->action_code = AMBO_START; 186041047Sgibbs aha_outb(aha, COMMAND_REG, AOP_START_MBOX); 186139225Sgibbs ahanextoutbox(aha); 186239225Sgibbs } 186339225Sgibbs 186439225Sgibbs splx(s); 186539225Sgibbs} 186656504Simp 186756504Simpint 186856504Simpaha_detach(struct aha_softc *aha) 186956504Simp{ 187056504Simp xpt_async(AC_LOST_DEVICE, aha->path, NULL); 187156504Simp xpt_free_path(aha->path); 187256504Simp xpt_bus_deregister(cam_sim_path(aha->sim)); 187356504Simp cam_sim_free(aha->sim, /*free_devq*/TRUE); 187456504Simp return (0); 187556504Simp} 1876165102SmjacobMODULE_DEPEND(aha, cam, 1, 1, 1); 1877