aha.c revision 122340
139225Sgibbs/* 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: 539751Simp * aha 1540/1542B/1542C/1542CF/1542CP aha_isa.c 639225Sgibbs * 739751Simp * Copyright (c) 1998 M. Warner Losh. 839751Simp * All Rights Reserved. 939751Simp * 1039751Simp * 1139751Simp * Redistribution and use in source and binary forms, with or without 1239751Simp * modification, are permitted provided that the following conditions 1339751Simp * are met: 1439751Simp * 1. Redistributions of source code must retain the above copyright 1539751Simp * notice, this list of conditions, and the following disclaimer, 1639751Simp * without modification, immediately at the beginning of the file. 1739751Simp * 2. The name of the author may not be used to endorse or promote products 1839751Simp * derived from this software without specific prior written permission. 1939751Simp * 2039751Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2139751Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2239751Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2339751Simp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2439751Simp * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2539751Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2639751Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2739751Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2839751Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2939751Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3039751Simp * SUCH DAMAGE. 3139751Simp * 3239225Sgibbs * Derived from bt.c written by: 3339225Sgibbs * 3439225Sgibbs * Copyright (c) 1998 Justin T. Gibbs. 3539225Sgibbs * All rights reserved. 3639225Sgibbs * 3739225Sgibbs * Redistribution and use in source and binary forms, with or without 3839225Sgibbs * modification, are permitted provided that the following conditions 3939225Sgibbs * are met: 4039225Sgibbs * 1. Redistributions of source code must retain the above copyright 4139225Sgibbs * notice, this list of conditions, and the following disclaimer, 4239225Sgibbs * without modification, immediately at the beginning of the file. 4339225Sgibbs * 2. The name of the author may not be used to endorse or promote products 4439225Sgibbs * derived from this software without specific prior written permission. 4539225Sgibbs * 4639225Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 4739225Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4839225Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4939225Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 5039225Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 5139225Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 5239225Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 5339225Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 5439225Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5539225Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5639225Sgibbs * SUCH DAMAGE. 5739225Sgibbs */ 5839225Sgibbs 59119418Sobrien#include <sys/cdefs.h> 60119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/aha/aha.c 122340 2003-11-09 00:51:52Z imp $"); 61119418Sobrien 6239225Sgibbs#include <sys/param.h> 6339225Sgibbs#include <sys/systm.h> 6439225Sgibbs#include <sys/malloc.h> 6539225Sgibbs#include <sys/kernel.h> 66117126Sscottl#include <sys/lock.h> 67117126Sscottl#include <sys/mutex.h> 6839225Sgibbs 6939225Sgibbs#include <machine/bus_pio.h> 7039225Sgibbs#include <machine/bus.h> 7139225Sgibbs 7239225Sgibbs#include <cam/cam.h> 7339225Sgibbs#include <cam/cam_ccb.h> 7439225Sgibbs#include <cam/cam_sim.h> 7539225Sgibbs#include <cam/cam_xpt_sim.h> 7639225Sgibbs#include <cam/cam_debug.h> 7739225Sgibbs 7839225Sgibbs#include <cam/scsi/scsi_message.h> 7939225Sgibbs 8039225Sgibbs#include <dev/aha/ahareg.h> 8139225Sgibbs 8239881Simp#define PRVERB(x) if (bootverbose) printf x 8339225Sgibbs 8439751Simp/* Macro to determine that a rev is potentially a new valid one 8539751Simp * so that the driver doesn't keep breaking on new revs as it 8639751Simp * did for the CF and CP. 8739751Simp */ 8839751Simp#define PROBABLY_NEW_BOARD(REV) (REV > 0x43 && REV < 0x56) 8939751Simp 9039225Sgibbs/* MailBox Management functions */ 9139225Sgibbsstatic __inline void ahanextinbox(struct aha_softc *aha); 9239225Sgibbsstatic __inline void ahanextoutbox(struct aha_softc *aha); 9339225Sgibbs 9439225Sgibbsstatic __inline void 9539225Sgibbsahanextinbox(struct aha_softc *aha) 9639225Sgibbs{ 9739225Sgibbs if (aha->cur_inbox == aha->last_inbox) 9839225Sgibbs aha->cur_inbox = aha->in_boxes; 9939225Sgibbs else 10039225Sgibbs aha->cur_inbox++; 10139225Sgibbs} 10239225Sgibbs 10339225Sgibbsstatic __inline void 10439225Sgibbsahanextoutbox(struct aha_softc *aha) 10539225Sgibbs{ 10639225Sgibbs if (aha->cur_outbox == aha->last_outbox) 10739225Sgibbs aha->cur_outbox = aha->out_boxes; 10839225Sgibbs else 10939225Sgibbs aha->cur_outbox++; 11039225Sgibbs} 11139225Sgibbs 11239225Sgibbs#define ahautoa24(u,s3) \ 11339225Sgibbs (s3)[0] = ((u) >> 16) & 0xff; \ 11439225Sgibbs (s3)[1] = ((u) >> 8) & 0xff; \ 11539225Sgibbs (s3)[2] = (u) & 0xff; 11639225Sgibbs 11739225Sgibbs#define aha_a24tou(s3) \ 11839225Sgibbs (((s3)[0] << 16) | ((s3)[1] << 8) | (s3)[2]) 11939225Sgibbs 12039225Sgibbs/* CCB Mangement functions */ 121122340Simpstatic __inline uint32_t ahaccbvtop(struct aha_softc *aha, 12241047Sgibbs struct aha_ccb *accb); 12339225Sgibbsstatic __inline struct aha_ccb* ahaccbptov(struct aha_softc *aha, 124122340Simp uint32_t ccb_addr); 12539225Sgibbs 126122340Simpstatic __inline uint32_t 12741047Sgibbsahaccbvtop(struct aha_softc *aha, struct aha_ccb *accb) 12839225Sgibbs{ 12939225Sgibbs return (aha->aha_ccb_physbase 130122340Simp + (uint32_t)((caddr_t)accb - (caddr_t)aha->aha_ccb_array)); 13139225Sgibbs} 13239225Sgibbsstatic __inline struct aha_ccb * 133122340Simpahaccbptov(struct aha_softc *aha, uint32_t ccb_addr) 13439225Sgibbs{ 13539225Sgibbs return (aha->aha_ccb_array + 136104713Speter + ((struct aha_ccb*)(uintptr_t)ccb_addr - 137104713Speter (struct aha_ccb*)(uintptr_t)aha->aha_ccb_physbase)); 13839225Sgibbs} 13939225Sgibbs 14039225Sgibbsstatic struct aha_ccb* ahagetccb(struct aha_softc *aha); 14141047Sgibbsstatic __inline void ahafreeccb(struct aha_softc *aha, struct aha_ccb *accb); 14239225Sgibbsstatic void ahaallocccbs(struct aha_softc *aha); 14339225Sgibbsstatic bus_dmamap_callback_t ahaexecuteccb; 14441047Sgibbsstatic void ahadone(struct aha_softc *aha, struct aha_ccb *accb, 14539225Sgibbs aha_mbi_comp_code_t comp_code); 14639225Sgibbs 14739225Sgibbs/* Host adapter command functions */ 14839225Sgibbsstatic int ahareset(struct aha_softc* aha, int hard_reset); 14939225Sgibbs 15039225Sgibbs/* Initialization functions */ 15139225Sgibbsstatic int ahainitmboxes(struct aha_softc *aha); 15239225Sgibbsstatic bus_dmamap_callback_t ahamapmboxes; 15339225Sgibbsstatic bus_dmamap_callback_t ahamapccbs; 15439225Sgibbsstatic bus_dmamap_callback_t ahamapsgs; 15539225Sgibbs 15639225Sgibbs/* Transfer Negotiation Functions */ 15739225Sgibbsstatic void ahafetchtransinfo(struct aha_softc *aha, 15839225Sgibbs struct ccb_trans_settings *cts); 15939225Sgibbs 16039225Sgibbs/* CAM SIM entry points */ 16141047Sgibbs#define ccb_accb_ptr spriv_ptr0 16239225Sgibbs#define ccb_aha_ptr spriv_ptr1 16339225Sgibbsstatic void ahaaction(struct cam_sim *sim, union ccb *ccb); 16439225Sgibbsstatic void ahapoll(struct cam_sim *sim); 16539225Sgibbs 16639225Sgibbs/* Our timeout handler */ 16746602Speterstatic timeout_t ahatimeout; 16839225Sgibbs 16939225Sgibbsu_long aha_unit = 0; 17039225Sgibbs 17139225Sgibbs/* 17239225Sgibbs * Do our own re-probe protection until a configuration 17339225Sgibbs * manager can do it for us. This ensures that we don't 17439225Sgibbs * reprobe a card already found by the EISA or PCI probes. 17539225Sgibbs */ 17645575Seivindstatic struct aha_isa_port aha_isa_ports[] = 17739225Sgibbs{ 17856504Simp { 0x130, 4 }, 17956504Simp { 0x134, 5 }, 18056504Simp { 0x230, 2 }, 18156504Simp { 0x234, 3 }, 18256504Simp { 0x330, 0 }, 18356504Simp { 0x334, 1 } 18439225Sgibbs}; 18539225Sgibbs 18641047Sgibbs/* 18741047Sgibbs * I/O ports listed in the order enumerated by the 18841047Sgibbs * card for certain op codes. 18941047Sgibbs */ 190122340Simpstatic uint16_t aha_board_ports[] = 19141047Sgibbs{ 19241047Sgibbs 0x330, 19341047Sgibbs 0x334, 19441047Sgibbs 0x230, 19541047Sgibbs 0x234, 19641047Sgibbs 0x130, 19741047Sgibbs 0x134 19841047Sgibbs}; 19941047Sgibbs 20039225Sgibbs/* Exported functions */ 20139225Sgibbsstruct aha_softc * 20239225Sgibbsaha_alloc(int unit, bus_space_tag_t tag, bus_space_handle_t bsh) 20339225Sgibbs{ 20439225Sgibbs struct aha_softc *aha; 20539225Sgibbs 20667897Sdwmalone aha = malloc(sizeof(struct aha_softc), M_DEVBUF, M_NOWAIT | M_ZERO); 20739225Sgibbs if (!aha) { 20839225Sgibbs printf("aha%d: cannot malloc!\n", unit); 20939225Sgibbs return NULL; 21039225Sgibbs } 21139225Sgibbs SLIST_INIT(&aha->free_aha_ccbs); 21239225Sgibbs LIST_INIT(&aha->pending_ccbs); 21339225Sgibbs SLIST_INIT(&aha->sg_maps); 21439225Sgibbs aha->unit = unit; 21539225Sgibbs aha->tag = tag; 21639225Sgibbs aha->bsh = bsh; 21742887Simp aha->ccb_sg_opcode = INITIATOR_SG_CCB_WRESID; 21842887Simp aha->ccb_ccb_opcode = INITIATOR_CCB_WRESID; 21939225Sgibbs return (aha); 22039225Sgibbs} 22139225Sgibbs 22239225Sgibbsvoid 22339225Sgibbsaha_free(struct aha_softc *aha) 22439225Sgibbs{ 22539225Sgibbs switch (aha->init_level) { 22639225Sgibbs default: 22739225Sgibbs case 8: 22839225Sgibbs { 22939225Sgibbs struct sg_map_node *sg_map; 23039225Sgibbs 23139225Sgibbs while ((sg_map = SLIST_FIRST(&aha->sg_maps))!= NULL) { 23239225Sgibbs SLIST_REMOVE_HEAD(&aha->sg_maps, links); 233122340Simp bus_dmamap_unload(aha->sg_dmat, sg_map->sg_dmamap); 23439225Sgibbs bus_dmamem_free(aha->sg_dmat, sg_map->sg_vaddr, 235122340Simp sg_map->sg_dmamap); 23639225Sgibbs free(sg_map, M_DEVBUF); 23739225Sgibbs } 23839225Sgibbs bus_dma_tag_destroy(aha->sg_dmat); 23939225Sgibbs } 24039225Sgibbs case 7: 24139225Sgibbs bus_dmamap_unload(aha->ccb_dmat, aha->ccb_dmamap); 24239225Sgibbs case 6: 24339225Sgibbs bus_dmamap_destroy(aha->ccb_dmat, aha->ccb_dmamap); 24439225Sgibbs bus_dmamem_free(aha->ccb_dmat, aha->aha_ccb_array, 245122340Simp aha->ccb_dmamap); 24639225Sgibbs case 5: 24739225Sgibbs bus_dma_tag_destroy(aha->ccb_dmat); 24839225Sgibbs case 4: 24939225Sgibbs bus_dmamap_unload(aha->mailbox_dmat, aha->mailbox_dmamap); 25039225Sgibbs case 3: 25139225Sgibbs bus_dmamem_free(aha->mailbox_dmat, aha->in_boxes, 252122340Simp aha->mailbox_dmamap); 25339225Sgibbs bus_dmamap_destroy(aha->mailbox_dmat, aha->mailbox_dmamap); 25439225Sgibbs case 2: 25539225Sgibbs bus_dma_tag_destroy(aha->buffer_dmat); 25639225Sgibbs case 1: 25739225Sgibbs bus_dma_tag_destroy(aha->mailbox_dmat); 25839225Sgibbs case 0: 25997208Speter break; 26039225Sgibbs } 26139225Sgibbs free(aha, M_DEVBUF); 26239225Sgibbs} 26339225Sgibbs 26439225Sgibbs/* 26539225Sgibbs * Probe the adapter and verify that the card is an Adaptec. 26639225Sgibbs */ 26739225Sgibbsint 26839225Sgibbsaha_probe(struct aha_softc* aha) 26939225Sgibbs{ 27039225Sgibbs u_int status; 27139225Sgibbs u_int intstat; 27239225Sgibbs int error; 27339852Simp board_id_data_t board_id; 27439225Sgibbs 27539225Sgibbs /* 27639225Sgibbs * See if the three I/O ports look reasonable. 27739225Sgibbs * Touch the minimal number of registers in the 27839225Sgibbs * failure case. 27939225Sgibbs */ 28039225Sgibbs status = aha_inb(aha, STATUS_REG); 281122340Simp if ((status == 0) || 282122340Simp (status & (DIAG_ACTIVE|CMD_REG_BUSY | STATUS_REG_RSVD)) != 0) { 28341047Sgibbs PRVERB(("%s: status reg test failed %x\n", aha_name(aha), 284122340Simp status)); 28539225Sgibbs return (ENXIO); 28639225Sgibbs } 28739225Sgibbs 28839225Sgibbs intstat = aha_inb(aha, INTSTAT_REG); 28939225Sgibbs if ((intstat & INTSTAT_REG_RSVD) != 0) { 29041047Sgibbs PRVERB(("%s: Failed Intstat Reg Test\n", aha_name(aha))); 29139225Sgibbs return (ENXIO); 29239225Sgibbs } 29339225Sgibbs 29439225Sgibbs /* 29541047Sgibbs * Looking good so far. Final test is to reset the 29641047Sgibbs * adapter and fetch the board ID and ensure we aren't 29741047Sgibbs * looking at a BusLogic. 29841047Sgibbs */ 29941047Sgibbs if ((error = ahareset(aha, /*hard_reset*/TRUE)) != 0) { 30051869Smdodd PRVERB(("%s: Failed Reset\n", aha_name(aha))); 30141047Sgibbs return (ENXIO); 30241047Sgibbs } 30341047Sgibbs 30441047Sgibbs /* 30539852Simp * Get the board ID. We use this to see if we're dealing with 306108533Sschweikh * a buslogic card or an aha card (or clone). 30739225Sgibbs */ 30841047Sgibbs error = aha_cmd(aha, AOP_INQUIRE_BOARD_ID, NULL, /*parmlen*/0, 309122340Simp (uint8_t*)&board_id, sizeof(board_id), DEFAULT_CMD_TIMEOUT); 31039852Simp if (error != 0) { 31139881Simp PRVERB(("%s: INQUIRE failed %x\n", aha_name(aha), error)); 31239225Sgibbs return (ENXIO); 31339225Sgibbs } 31439852Simp aha->fw_major = board_id.firmware_rev_major; 31539852Simp aha->fw_minor = board_id.firmware_rev_minor; 31639852Simp aha->boardid = board_id.board_type; 31739852Simp 31839225Sgibbs /* 31939852Simp * The Buslogic cards have an id of either 0x41 or 0x42. So 32039852Simp * if those come up in the probe, we test the geometry register 32139852Simp * of the board. Adaptec boards that are this old will not have 32239852Simp * this register, and return 0xff, while buslogic cards will return 32339852Simp * something different. 32439852Simp * 32541335Simp * It appears that for reasons unknow, for the for the 32641335Simp * aha-1542B cards, we need to wait a little bit before trying 32741335Simp * to read the geometry register. I picked 10ms since we have 32841335Simp * reports that a for loop to 1000 did the trick, and this 32941335Simp * errs on the side of conservatism. Besides, no one will 33041335Simp * notice a 10mS delay here, even the 1542B card users :-) 33141335Simp * 33246997Simp * Some compatible cards return 0 here. Some cards also 33346997Simp * seem to return 0x7f. 33441807Simp * 33541335Simp * XXX I'm not sure how this will impact other cloned cards 33641807Simp * 33741807Simp * This really should be replaced with the esetup command, since 33846997Simp * that appears to be more reliable. This becomes more and more 33946997Simp * true over time as we discover more cards that don't read the 34046997Simp * geometry register consistantly. 34139225Sgibbs */ 34239852Simp if (aha->boardid <= 0x42) { 34341335Simp /* Wait 10ms before reading */ 34441335Simp DELAY(10000); 34539852Simp status = aha_inb(aha, GEOMETRY_REG); 34646997Simp if (status != 0xff && status != 0x00 && status != 0x7f) { 34744434Simp PRVERB(("%s: Geometry Register test failed 0x%x\n", 34844434Simp aha_name(aha), status)); 34939852Simp return (ENXIO); 35041047Sgibbs } 35139751Simp } 35239852Simp 35339225Sgibbs return (0); 35439225Sgibbs} 35539225Sgibbs 35639225Sgibbs/* 35739225Sgibbs * Pull the boards setup information and record it in our softc. 35839225Sgibbs */ 35939225Sgibbsint 36039225Sgibbsaha_fetch_adapter_info(struct aha_softc *aha) 36139225Sgibbs{ 36239225Sgibbs setup_data_t setup_info; 36339225Sgibbs config_data_t config_data; 364122340Simp uint8_t length_param; 36539225Sgibbs int error; 36639751Simp struct aha_extbios extbios; 36739225Sgibbs 36839852Simp switch (aha->boardid) { 36939225Sgibbs case BOARD_1540_16HEAD_BIOS: 37041514Sarchie snprintf(aha->model, sizeof(aha->model), "1540 16 head BIOS"); 37139225Sgibbs break; 37239225Sgibbs case BOARD_1540_64HEAD_BIOS: 37341514Sarchie snprintf(aha->model, sizeof(aha->model), "1540 64 head BIOS"); 37439225Sgibbs break; 37539225Sgibbs case BOARD_1542: 37641514Sarchie snprintf(aha->model, sizeof(aha->model), "1540/1542 64 head BIOS"); 37739225Sgibbs break; 37839225Sgibbs case BOARD_1640: 37941514Sarchie snprintf(aha->model, sizeof(aha->model), "1640"); 38039225Sgibbs break; 38139225Sgibbs case BOARD_1740: 38241514Sarchie snprintf(aha->model, sizeof(aha->model), "1740A/1742A/1744"); 38339225Sgibbs break; 38439225Sgibbs case BOARD_1542C: 38541514Sarchie snprintf(aha->model, sizeof(aha->model), "1542C"); 38639225Sgibbs break; 38739225Sgibbs case BOARD_1542CF: 38841514Sarchie snprintf(aha->model, sizeof(aha->model), "1542CF"); 38939225Sgibbs break; 39039225Sgibbs case BOARD_1542CP: 39141514Sarchie snprintf(aha->model, sizeof(aha->model), "1542CP"); 39239225Sgibbs break; 39339225Sgibbs default: 39441514Sarchie snprintf(aha->model, sizeof(aha->model), "Unknown"); 39539225Sgibbs break; 39639225Sgibbs } 39739751Simp /* 39839751Simp * If we are a new type of 1542 board (anything newer than a 1542C) 39939751Simp * then disable the extended bios so that the 40039751Simp * mailbox interface is unlocked. 40139751Simp * This is also true for the 1542B Version 3.20. First Adaptec 40239751Simp * board that supports >1Gb drives. 40339751Simp * No need to check the extended bios flags as some of the 40439751Simp * extensions that cause us problems are not flagged in that byte. 40539751Simp */ 40639751Simp if (PROBABLY_NEW_BOARD(aha->boardid) || 40739751Simp (aha->boardid == 0x41 40839852Simp && aha->fw_major == 0x31 && 40939852Simp aha->fw_minor >= 0x34)) { 41041047Sgibbs error = aha_cmd(aha, AOP_RETURN_EXT_BIOS_INFO, NULL, 411122340Simp /*paramlen*/0, (u_char *)&extbios, sizeof(extbios), 412122340Simp DEFAULT_CMD_TIMEOUT); 413122340Simp error = aha_cmd(aha, AOP_MBOX_IF_ENABLE, (uint8_t *)&extbios, 414122340Simp /*paramlen*/2, NULL, 0, DEFAULT_CMD_TIMEOUT); 41539751Simp } 41639751Simp if (aha->boardid < 0x41) 41741335Simp printf("%s: Warning: aha-1542A won't likely work.\n", 418122340Simp aha_name(aha)); 41939751Simp 42041335Simp aha->max_sg = 17; /* Need >= 17 to do 64k I/O */ 42139225Sgibbs aha->diff_bus = 0; 42239225Sgibbs aha->extended_lun = 0; 42339751Simp aha->extended_trans = 0; 42440403Simp aha->max_ccbs = 16; 42539225Sgibbs /* Determine Sync/Wide/Disc settings */ 42639225Sgibbs length_param = sizeof(setup_info); 42741047Sgibbs error = aha_cmd(aha, AOP_INQUIRE_SETUP_INFO, &length_param, 428122340Simp /*paramlen*/1, (uint8_t*)&setup_info, sizeof(setup_info), 429122340Simp DEFAULT_CMD_TIMEOUT); 43039225Sgibbs if (error != 0) { 43139225Sgibbs printf("%s: aha_fetch_adapter_info - Failed " 432122340Simp "Get Setup Info\n", aha_name(aha)); 43339225Sgibbs return (error); 43439225Sgibbs } 43539225Sgibbs if (setup_info.initiate_sync != 0) { 43639225Sgibbs aha->sync_permitted = ALL_TARGETS; 43739225Sgibbs } 43839225Sgibbs aha->disc_permitted = ALL_TARGETS; 43939225Sgibbs 44039225Sgibbs /* We need as many mailboxes as we can have ccbs */ 44139225Sgibbs aha->num_boxes = aha->max_ccbs; 44239225Sgibbs 44339225Sgibbs /* Determine our SCSI ID */ 44439225Sgibbs 44541047Sgibbs error = aha_cmd(aha, AOP_INQUIRE_CONFIG, NULL, /*parmlen*/0, 446122340Simp (uint8_t*)&config_data, sizeof(config_data), DEFAULT_CMD_TIMEOUT); 44739225Sgibbs if (error != 0) { 44839225Sgibbs printf("%s: aha_fetch_adapter_info - Failed Get Config\n", 449122340Simp aha_name(aha)); 45039225Sgibbs return (error); 45139225Sgibbs } 45239225Sgibbs aha->scsi_id = config_data.scsi_id; 45339225Sgibbs return (0); 45439225Sgibbs} 45539225Sgibbs 45639225Sgibbs/* 45739225Sgibbs * Start the board, ready for normal operation 45839225Sgibbs */ 45939225Sgibbsint 46039225Sgibbsaha_init(struct aha_softc* aha) 46139225Sgibbs{ 46239225Sgibbs /* Announce the Adapter */ 46339852Simp printf("%s: AHA-%s FW Rev. %c.%c (ID=%x) ", aha_name(aha), 464122340Simp aha->model, aha->fw_major, aha->fw_minor, aha->boardid); 46539225Sgibbs 46639225Sgibbs if (aha->diff_bus != 0) 46739225Sgibbs printf("Diff "); 46839225Sgibbs 46939225Sgibbs printf("SCSI Host Adapter, SCSI ID %d, %d CCBs\n", aha->scsi_id, 470122340Simp aha->max_ccbs); 47139225Sgibbs 47239225Sgibbs /* 47339225Sgibbs * Create our DMA tags. These tags define the kinds of device 47461686Salex * accessible memory allocations and memory mappings we will 47539225Sgibbs * need to perform during normal operation. 47639225Sgibbs * 47739225Sgibbs * Unless we need to further restrict the allocation, we rely 47839225Sgibbs * on the restrictions of the parent dmat, hence the common 47939225Sgibbs * use of MAXADDR and MAXSIZE. 48039225Sgibbs */ 48139225Sgibbs 48239225Sgibbs /* DMA tag for mapping buffers into device visible space. */ 483122340Simp if (bus_dma_tag_create( /* parent */ aha->parent_dmat, 484112782Smdodd /* alignment */ 1, 485112782Smdodd /* boundary */ 0, 486112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR, 487112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 488112782Smdodd /* filter */ NULL, 489112782Smdodd /* filterarg */ NULL, 490112782Smdodd /* maxsize */ MAXBSIZE, 491112782Smdodd /* nsegments */ AHA_NSEG, 492112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_24BIT, 493112782Smdodd /* flags */ BUS_DMA_ALLOCNOW, 494117126Sscottl /* lockfunc */ busdma_lock_mutex, 495117126Sscottl /* lockarg */ &Giant, 496112782Smdodd &aha->buffer_dmat) != 0) { 49739225Sgibbs goto error_exit; 49839225Sgibbs } 49939225Sgibbs 50039225Sgibbs aha->init_level++; 50139225Sgibbs /* DMA tag for our mailboxes */ 502112782Smdodd if (bus_dma_tag_create( /* parent */ aha->parent_dmat, 503112782Smdodd /* alignment */ 1, 504112782Smdodd /* boundary */ 0, 505112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR, 506112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 507112782Smdodd /* filter */ NULL, 508112782Smdodd /* filterarg */ NULL, 509112782Smdodd /* maxsize */ aha->num_boxes * 510112782Smdodd (sizeof(aha_mbox_in_t) + 511112782Smdodd sizeof(aha_mbox_out_t)), 512112782Smdodd /* nsegments */ 1, 513112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_24BIT, 514112782Smdodd /* flags */ 0, 515117126Sscottl /* lockfunc */ busdma_lock_mutex, 516117126Sscottl /* lockarg */ &Giant, 517112782Smdodd &aha->mailbox_dmat) != 0) { 51839225Sgibbs goto error_exit; 51939225Sgibbs } 52039225Sgibbs 52139225Sgibbs aha->init_level++; 52239225Sgibbs 52339225Sgibbs /* Allocation for our mailboxes */ 52439225Sgibbs if (bus_dmamem_alloc(aha->mailbox_dmat, (void **)&aha->out_boxes, 525122340Simp BUS_DMA_NOWAIT, &aha->mailbox_dmamap) != 0) 52639225Sgibbs goto error_exit; 52739225Sgibbs 52839225Sgibbs aha->init_level++; 52939225Sgibbs 53039225Sgibbs /* And permanently map them */ 53139225Sgibbs bus_dmamap_load(aha->mailbox_dmat, aha->mailbox_dmamap, 532122340Simp aha->out_boxes, aha->num_boxes * (sizeof(aha_mbox_in_t) + 533122340Simp sizeof(aha_mbox_out_t)), ahamapmboxes, aha, /*flags*/0); 53439225Sgibbs 53539225Sgibbs aha->init_level++; 53639225Sgibbs 53739225Sgibbs aha->in_boxes = (aha_mbox_in_t *)&aha->out_boxes[aha->num_boxes]; 53839225Sgibbs 53939225Sgibbs ahainitmboxes(aha); 54039225Sgibbs 54139225Sgibbs /* DMA tag for our ccb structures */ 542112782Smdodd if (bus_dma_tag_create( /* parent */ aha->parent_dmat, 543112782Smdodd /* alignment */ 1, 544112782Smdodd /* boundary */ 0, 545112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR, 546112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 547112782Smdodd /* filter */ NULL, 548112782Smdodd /* filterarg */ NULL, 549112782Smdodd /* maxsize */ aha->max_ccbs * 550112782Smdodd sizeof(struct aha_ccb), 551112782Smdodd /* nsegments */ 1, 552112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_24BIT, 553112782Smdodd /* flags */ 0, 554117126Sscottl /* lockfunc */ busdma_lock_mutex, 555117126Sscottl /* lockarg */ &Giant, 556112782Smdodd &aha->ccb_dmat) != 0) { 55739225Sgibbs goto error_exit; 55839225Sgibbs } 55939225Sgibbs 56039225Sgibbs aha->init_level++; 56139225Sgibbs 56239225Sgibbs /* Allocation for our ccbs */ 56339225Sgibbs if (bus_dmamem_alloc(aha->ccb_dmat, (void **)&aha->aha_ccb_array, 564122340Simp BUS_DMA_NOWAIT, &aha->ccb_dmamap) != 0) 56539225Sgibbs goto error_exit; 56639225Sgibbs 56739225Sgibbs aha->init_level++; 56839225Sgibbs 56939225Sgibbs /* And permanently map them */ 570122340Simp bus_dmamap_load(aha->ccb_dmat, aha->ccb_dmamap, aha->aha_ccb_array, 571122340Simp aha->max_ccbs * sizeof(struct aha_ccb), ahamapccbs, aha, /*flags*/0); 57239225Sgibbs 57339225Sgibbs aha->init_level++; 57439225Sgibbs 57539225Sgibbs /* DMA tag for our S/G structures. We allocate in page sized chunks */ 576112782Smdodd if (bus_dma_tag_create( /* parent */ aha->parent_dmat, 577112782Smdodd /* alignment */ 1, 578112782Smdodd /* boundary */ 0, 579112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR, 580112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 581112782Smdodd /* filter */ NULL, 582112782Smdodd /* filterarg */ NULL, 583112782Smdodd /* maxsize */ PAGE_SIZE, 584112782Smdodd /* nsegments */ 1, 585112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_24BIT, 586112782Smdodd /* flags */ 0, 587117126Sscottl /* lockfunc */ busdma_lock_mutex, 588117126Sscottl /* lockarg */ &Giant, 589122340Simp &aha->sg_dmat) != 0) 59039225Sgibbs goto error_exit; 59139225Sgibbs 59239225Sgibbs aha->init_level++; 59339225Sgibbs 59439225Sgibbs /* Perform initial CCB allocation */ 59539225Sgibbs bzero(aha->aha_ccb_array, aha->max_ccbs * sizeof(struct aha_ccb)); 59639225Sgibbs ahaallocccbs(aha); 59739225Sgibbs 59839225Sgibbs if (aha->num_ccbs == 0) { 59939324Sgibbs printf("%s: aha_init - Unable to allocate initial ccbs\n", 600122340Simp aha_name(aha)); 60139225Sgibbs goto error_exit; 60239225Sgibbs } 60339225Sgibbs 60439225Sgibbs /* 60539225Sgibbs * Note that we are going and return (to probe) 60639225Sgibbs */ 607122340Simp return (0); 60839225Sgibbs 60939225Sgibbserror_exit: 61039225Sgibbs 61139225Sgibbs return (ENXIO); 61239225Sgibbs} 61339225Sgibbs 61439225Sgibbsint 61539225Sgibbsaha_attach(struct aha_softc *aha) 61639225Sgibbs{ 61739225Sgibbs int tagged_dev_openings; 61839225Sgibbs struct cam_devq *devq; 61939225Sgibbs 62039225Sgibbs /* 62141335Simp * We don't do tagged queueing, since the aha cards don't 62241335Simp * support it. 62339225Sgibbs */ 62439225Sgibbs tagged_dev_openings = 0; 62539225Sgibbs 62639225Sgibbs /* 62739225Sgibbs * Create the device queue for our SIM. 62839225Sgibbs */ 62939225Sgibbs devq = cam_simq_alloc(aha->max_ccbs - 1); 63039225Sgibbs if (devq == NULL) 63139225Sgibbs return (ENOMEM); 63239225Sgibbs 63339225Sgibbs /* 63439225Sgibbs * Construct our SIM entry 63539225Sgibbs */ 636122340Simp aha->sim = cam_sim_alloc(ahaaction, ahapoll, "aha", aha, aha->unit, 2, 637122340Simp tagged_dev_openings, devq); 63839225Sgibbs if (aha->sim == NULL) { 63939225Sgibbs cam_simq_free(devq); 64039225Sgibbs return (ENOMEM); 64139225Sgibbs } 64239225Sgibbs 64339225Sgibbs if (xpt_bus_register(aha->sim, 0) != CAM_SUCCESS) { 64439225Sgibbs cam_sim_free(aha->sim, /*free_devq*/TRUE); 64539225Sgibbs return (ENXIO); 64639225Sgibbs } 64739225Sgibbs 648122340Simp if (xpt_create_path(&aha->path, /*periph*/NULL, cam_sim_path(aha->sim), 649122340Simp CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 65039225Sgibbs xpt_bus_deregister(cam_sim_path(aha->sim)); 65139225Sgibbs cam_sim_free(aha->sim, /*free_devq*/TRUE); 65239225Sgibbs return (ENXIO); 65339225Sgibbs } 65439225Sgibbs 65539225Sgibbs return (0); 65639225Sgibbs} 65739225Sgibbs 65839225Sgibbschar * 65939225Sgibbsaha_name(struct aha_softc *aha) 66039225Sgibbs{ 66139225Sgibbs static char name[10]; 66239225Sgibbs 66341514Sarchie snprintf(name, sizeof(name), "aha%d", aha->unit); 66439225Sgibbs return (name); 66539225Sgibbs} 66639225Sgibbs 66739225Sgibbsvoid 66841047Sgibbsaha_find_probe_range(int ioport, int *port_index, int *max_port_index) 66941047Sgibbs{ 67041047Sgibbs if (ioport > 0) { 67141047Sgibbs int i; 67241047Sgibbs 67341047Sgibbs for (i = 0;i < AHA_NUM_ISAPORTS; i++) 67441047Sgibbs if (ioport <= aha_isa_ports[i].addr) 67541047Sgibbs break; 676122340Simp if (i >= AHA_NUM_ISAPORTS || ioport != aha_isa_ports[i].addr) { 67742013Sgibbs printf("\n" 67842013Sgibbs"aha_isa_probe: Invalid baseport of 0x%x specified.\n" 67942013Sgibbs"aha_isa_probe: Nearest valid baseport is 0x%x.\n" 68042013Sgibbs"aha_isa_probe: Failing probe.\n", 681122340Simp ioport, 682122340Simp i < AHA_NUM_ISAPORTS ? aha_isa_ports[i].addr 683122340Simp : aha_isa_ports[AHA_NUM_ISAPORTS - 1].addr); 68441047Sgibbs *port_index = *max_port_index = -1; 68541047Sgibbs return; 68641047Sgibbs } 68741047Sgibbs *port_index = *max_port_index = aha_isa_ports[i].bio; 68841047Sgibbs } else { 68941047Sgibbs *port_index = 0; 69041047Sgibbs *max_port_index = AHA_NUM_ISAPORTS - 1; 69141047Sgibbs } 69241047Sgibbs} 69341047Sgibbs 69441047Sgibbsint 69541047Sgibbsaha_iop_from_bio(isa_compat_io_t bio_index) 69641047Sgibbs{ 69741047Sgibbs if (bio_index >= 0 && bio_index < AHA_NUM_ISAPORTS) 69841047Sgibbs return (aha_board_ports[bio_index]); 69941047Sgibbs return (-1); 70041047Sgibbs} 70141047Sgibbs 70239225Sgibbsstatic void 70339225Sgibbsahaallocccbs(struct aha_softc *aha) 70439225Sgibbs{ 70539225Sgibbs struct aha_ccb *next_ccb; 70639225Sgibbs struct sg_map_node *sg_map; 70739225Sgibbs bus_addr_t physaddr; 70839225Sgibbs aha_sg_t *segs; 70939225Sgibbs int newcount; 71039225Sgibbs int i; 71139225Sgibbs 71239225Sgibbs next_ccb = &aha->aha_ccb_array[aha->num_ccbs]; 71339225Sgibbs 71439225Sgibbs sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT); 71539225Sgibbs 71639225Sgibbs if (sg_map == NULL) 71739225Sgibbs return; 71839225Sgibbs 71939225Sgibbs /* Allocate S/G space for the next batch of CCBS */ 72039225Sgibbs if (bus_dmamem_alloc(aha->sg_dmat, (void **)&sg_map->sg_vaddr, 721122340Simp BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) { 72239225Sgibbs free(sg_map, M_DEVBUF); 72339225Sgibbs return; 72439225Sgibbs } 72539225Sgibbs 72639225Sgibbs SLIST_INSERT_HEAD(&aha->sg_maps, sg_map, links); 72739225Sgibbs 72839225Sgibbs bus_dmamap_load(aha->sg_dmat, sg_map->sg_dmamap, sg_map->sg_vaddr, 729122340Simp PAGE_SIZE, ahamapsgs, aha, /*flags*/0); 73039225Sgibbs 73139225Sgibbs segs = sg_map->sg_vaddr; 73239225Sgibbs physaddr = sg_map->sg_physaddr; 73339225Sgibbs 73439225Sgibbs newcount = (PAGE_SIZE / (AHA_NSEG * sizeof(aha_sg_t))); 73539225Sgibbs for (i = 0; aha->num_ccbs < aha->max_ccbs && i < newcount; i++) { 73639225Sgibbs int error; 73739225Sgibbs 73839225Sgibbs next_ccb->sg_list = segs; 73939225Sgibbs next_ccb->sg_list_phys = physaddr; 74041047Sgibbs next_ccb->flags = ACCB_FREE; 74139225Sgibbs error = bus_dmamap_create(aha->buffer_dmat, /*flags*/0, 742122340Simp &next_ccb->dmamap); 74339225Sgibbs if (error != 0) 74439225Sgibbs break; 74539225Sgibbs SLIST_INSERT_HEAD(&aha->free_aha_ccbs, next_ccb, links); 74639225Sgibbs segs += AHA_NSEG; 74739225Sgibbs physaddr += (AHA_NSEG * sizeof(aha_sg_t)); 74839225Sgibbs next_ccb++; 74939225Sgibbs aha->num_ccbs++; 75039225Sgibbs } 75139225Sgibbs 75239225Sgibbs /* Reserve a CCB for error recovery */ 75341047Sgibbs if (aha->recovery_accb == NULL) { 75441047Sgibbs aha->recovery_accb = SLIST_FIRST(&aha->free_aha_ccbs); 75539225Sgibbs SLIST_REMOVE_HEAD(&aha->free_aha_ccbs, links); 75639225Sgibbs } 75739225Sgibbs} 75839225Sgibbs 75939225Sgibbsstatic __inline void 76041047Sgibbsahafreeccb(struct aha_softc *aha, struct aha_ccb *accb) 76139225Sgibbs{ 76239225Sgibbs int s; 76339225Sgibbs 76439225Sgibbs s = splcam(); 76541047Sgibbs if ((accb->flags & ACCB_ACTIVE) != 0) 76641047Sgibbs LIST_REMOVE(&accb->ccb->ccb_h, sim_links.le); 76739225Sgibbs if (aha->resource_shortage != 0 768122340Simp && (accb->ccb->ccb_h.status & CAM_RELEASE_SIMQ) == 0) { 76941047Sgibbs accb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 77039225Sgibbs aha->resource_shortage = FALSE; 77139225Sgibbs } 77241047Sgibbs accb->flags = ACCB_FREE; 77341047Sgibbs SLIST_INSERT_HEAD(&aha->free_aha_ccbs, accb, links); 77441047Sgibbs aha->active_ccbs--; 77539225Sgibbs splx(s); 77639225Sgibbs} 77739225Sgibbs 77839225Sgibbsstatic struct aha_ccb* 77939225Sgibbsahagetccb(struct aha_softc *aha) 78039225Sgibbs{ 78141047Sgibbs struct aha_ccb* accb; 78239225Sgibbs int s; 78339225Sgibbs 78439225Sgibbs s = splcam(); 78541047Sgibbs if ((accb = SLIST_FIRST(&aha->free_aha_ccbs)) != NULL) { 78639225Sgibbs SLIST_REMOVE_HEAD(&aha->free_aha_ccbs, links); 78741047Sgibbs aha->active_ccbs++; 78839225Sgibbs } else if (aha->num_ccbs < aha->max_ccbs) { 78939225Sgibbs ahaallocccbs(aha); 79041047Sgibbs accb = SLIST_FIRST(&aha->free_aha_ccbs); 79141047Sgibbs if (accb == NULL) 79241047Sgibbs printf("%s: Can't malloc ACCB\n", aha_name(aha)); 79341047Sgibbs else { 79439225Sgibbs SLIST_REMOVE_HEAD(&aha->free_aha_ccbs, links); 79541047Sgibbs aha->active_ccbs++; 79641047Sgibbs } 79739225Sgibbs } 79839225Sgibbs splx(s); 79939225Sgibbs 80041047Sgibbs return (accb); 80139225Sgibbs} 80239225Sgibbs 80339225Sgibbsstatic void 80439225Sgibbsahaaction(struct cam_sim *sim, union ccb *ccb) 80539225Sgibbs{ 80639225Sgibbs struct aha_softc *aha; 807122340Simp int s; 80839225Sgibbs 80939225Sgibbs CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("ahaaction\n")); 81039225Sgibbs 81139225Sgibbs aha = (struct aha_softc *)cam_sim_softc(sim); 81239225Sgibbs 81339225Sgibbs switch (ccb->ccb_h.func_code) { 81439225Sgibbs /* Common cases first */ 81539225Sgibbs case XPT_SCSI_IO: /* Execute the requested I/O operation */ 816122340Simp case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ { 81741047Sgibbs struct aha_ccb *accb; 81839225Sgibbs struct aha_hccb *hccb; 81939225Sgibbs 82039225Sgibbs /* 821108533Sschweikh * Get an accb to use. 82239225Sgibbs */ 82341047Sgibbs if ((accb = ahagetccb(aha)) == NULL) { 82439225Sgibbs s = splcam(); 82539225Sgibbs aha->resource_shortage = TRUE; 82639225Sgibbs splx(s); 82739225Sgibbs xpt_freeze_simq(aha->sim, /*count*/1); 82839225Sgibbs ccb->ccb_h.status = CAM_REQUEUE_REQ; 82939225Sgibbs xpt_done(ccb); 83039225Sgibbs return; 83139225Sgibbs } 83239225Sgibbs 83341047Sgibbs hccb = &accb->hccb; 83439225Sgibbs 83539225Sgibbs /* 83641047Sgibbs * So we can find the ACCB when an abort is requested 83739225Sgibbs */ 83841047Sgibbs accb->ccb = ccb; 83941047Sgibbs ccb->ccb_h.ccb_accb_ptr = accb; 84039225Sgibbs ccb->ccb_h.ccb_aha_ptr = aha; 84139225Sgibbs 84239225Sgibbs /* 84341047Sgibbs * Put all the arguments for the xfer in the accb 84439225Sgibbs */ 84539225Sgibbs hccb->target = ccb->ccb_h.target_id; 84639225Sgibbs hccb->lun = ccb->ccb_h.target_lun; 84739225Sgibbs hccb->ahastat = 0; 84839225Sgibbs hccb->sdstat = 0; 84939225Sgibbs 85039225Sgibbs if (ccb->ccb_h.func_code == XPT_SCSI_IO) { 85139225Sgibbs struct ccb_scsiio *csio; 85239225Sgibbs struct ccb_hdr *ccbh; 85339225Sgibbs 85439225Sgibbs csio = &ccb->csio; 85539225Sgibbs ccbh = &csio->ccb_h; 85642887Simp hccb->opcode = aha->ccb_ccb_opcode; 85739225Sgibbs hccb->datain = (ccb->ccb_h.flags & CAM_DIR_IN) != 0; 85839225Sgibbs hccb->dataout = (ccb->ccb_h.flags & CAM_DIR_OUT) != 0; 85939225Sgibbs hccb->cmd_len = csio->cdb_len; 86039225Sgibbs if (hccb->cmd_len > sizeof(hccb->scsi_cdb)) { 86139225Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 86241047Sgibbs ahafreeccb(aha, accb); 86339225Sgibbs xpt_done(ccb); 86439225Sgibbs return; 86539225Sgibbs } 86639225Sgibbs hccb->sense_len = csio->sense_len; 86739225Sgibbs if ((ccbh->flags & CAM_CDB_POINTER) != 0) { 86839225Sgibbs if ((ccbh->flags & CAM_CDB_PHYS) == 0) { 86939225Sgibbs bcopy(csio->cdb_io.cdb_ptr, 87039225Sgibbs hccb->scsi_cdb, hccb->cmd_len); 87139225Sgibbs } else { 87239225Sgibbs /* I guess I could map it in... */ 87339225Sgibbs ccbh->status = CAM_REQ_INVALID; 87441047Sgibbs ahafreeccb(aha, accb); 87539225Sgibbs xpt_done(ccb); 87639225Sgibbs return; 87739225Sgibbs } 87839225Sgibbs } else { 87939225Sgibbs bcopy(csio->cdb_io.cdb_bytes, 88039225Sgibbs hccb->scsi_cdb, hccb->cmd_len); 88139225Sgibbs } 88239225Sgibbs /* 88339225Sgibbs * If we have any data to send with this command, 88439225Sgibbs * map it into bus space. 88539225Sgibbs */ 88639225Sgibbs /* Only use S/G if there is a transfer */ 88739225Sgibbs if ((ccbh->flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 88839225Sgibbs if ((ccbh->flags & CAM_SCATTER_VALID) == 0) { 88939225Sgibbs /* 89039225Sgibbs * We've been given a pointer 89139225Sgibbs * to a single buffer. 89239225Sgibbs */ 89339225Sgibbs if ((ccbh->flags & CAM_DATA_PHYS)==0) { 89439225Sgibbs int error; 89539225Sgibbs 89639225Sgibbs s = splsoftvm(); 89739225Sgibbs error = bus_dmamap_load( 89839225Sgibbs aha->buffer_dmat, 89941047Sgibbs accb->dmamap, 90039225Sgibbs csio->data_ptr, 90139225Sgibbs csio->dxfer_len, 90239225Sgibbs ahaexecuteccb, 90341047Sgibbs accb, 90439225Sgibbs /*flags*/0); 90539225Sgibbs if (error == EINPROGRESS) { 90639225Sgibbs /* 90739225Sgibbs * So as to maintain 90839225Sgibbs * ordering, freeze the 90939225Sgibbs * controller queue 91039225Sgibbs * until our mapping is 91139225Sgibbs * returned. 91239225Sgibbs */ 91339225Sgibbs xpt_freeze_simq(aha->sim, 91439225Sgibbs 1); 91539225Sgibbs csio->ccb_h.status |= 91639225Sgibbs CAM_RELEASE_SIMQ; 91739225Sgibbs } 91839225Sgibbs splx(s); 91939225Sgibbs } else { 92039225Sgibbs struct bus_dma_segment seg; 92139225Sgibbs 92239225Sgibbs /* Pointer to physical buffer */ 92339225Sgibbs seg.ds_addr = 92439225Sgibbs (bus_addr_t)csio->data_ptr; 92539225Sgibbs seg.ds_len = csio->dxfer_len; 92641047Sgibbs ahaexecuteccb(accb, &seg, 1, 0); 92739225Sgibbs } 92839225Sgibbs } else { 92939225Sgibbs struct bus_dma_segment *segs; 93039225Sgibbs 93139225Sgibbs if ((ccbh->flags & CAM_DATA_PHYS) != 0) 93239225Sgibbs panic("ahaaction - Physical " 93339225Sgibbs "segment pointers " 93439225Sgibbs "unsupported"); 93539225Sgibbs 93639225Sgibbs if ((ccbh->flags&CAM_SG_LIST_PHYS)==0) 93739225Sgibbs panic("ahaaction - Virtual " 93839225Sgibbs "segment addresses " 93939225Sgibbs "unsupported"); 94039225Sgibbs 94139225Sgibbs /* Just use the segments provided */ 94239225Sgibbs segs = (struct bus_dma_segment *) 94339225Sgibbs csio->data_ptr; 94441047Sgibbs ahaexecuteccb(accb, segs, 94539225Sgibbs csio->sglist_cnt, 0); 94639225Sgibbs } 94739225Sgibbs } else { 94841047Sgibbs ahaexecuteccb(accb, NULL, 0, 0); 94939225Sgibbs } 95039225Sgibbs } else { 95139225Sgibbs hccb->opcode = INITIATOR_BUS_DEV_RESET; 95239225Sgibbs /* No data transfer */ 95339225Sgibbs hccb->datain = TRUE; 95439225Sgibbs hccb->dataout = TRUE; 95539225Sgibbs hccb->cmd_len = 0; 95639225Sgibbs hccb->sense_len = 0; 95741047Sgibbs ahaexecuteccb(accb, NULL, 0, 0); 95839225Sgibbs } 95939225Sgibbs break; 96039225Sgibbs } 96139225Sgibbs case XPT_EN_LUN: /* Enable LUN as a target */ 96239225Sgibbs case XPT_TARGET_IO: /* Execute target I/O request */ 96339225Sgibbs case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */ 96439225Sgibbs case XPT_CONT_TARGET_IO: /* Continue Host Target I/O Connection*/ 96539225Sgibbs case XPT_ABORT: /* Abort the specified CCB */ 96639225Sgibbs /* XXX Implement */ 96739225Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 96839225Sgibbs xpt_done(ccb); 96939225Sgibbs break; 97039225Sgibbs case XPT_SET_TRAN_SETTINGS: 97139225Sgibbs /* XXX Implement */ 97246581Sken ccb->ccb_h.status = CAM_PROVIDE_FAIL; 97339225Sgibbs xpt_done(ccb); 97439225Sgibbs break; 97539225Sgibbs case XPT_GET_TRAN_SETTINGS: 97639225Sgibbs /* Get default/user set transfer settings for the target */ 97739225Sgibbs { 97839225Sgibbs struct ccb_trans_settings *cts; 97939225Sgibbs u_int target_mask; 98039225Sgibbs 98139225Sgibbs cts = &ccb->cts; 98239225Sgibbs target_mask = 0x01 << ccb->ccb_h.target_id; 98339225Sgibbs if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) { 98439225Sgibbs cts->flags = 0; 98539225Sgibbs if ((aha->disc_permitted & target_mask) != 0) 98639225Sgibbs cts->flags |= CCB_TRANS_DISC_ENB; 98739225Sgibbs cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 98847506Sgibbs if ((aha->sync_permitted & target_mask) != 0) { 98947506Sgibbs if (aha->boardid >= BOARD_1542CF) 99047506Sgibbs cts->sync_period = 25; 99147506Sgibbs else 99247506Sgibbs cts->sync_period = 50; 99347506Sgibbs } else 99439225Sgibbs cts->sync_period = 0; 99539225Sgibbs 99639225Sgibbs if (cts->sync_period != 0) 99739225Sgibbs cts->sync_offset = 15; 99839225Sgibbs 99939225Sgibbs cts->valid = CCB_TRANS_SYNC_RATE_VALID 100039225Sgibbs | CCB_TRANS_SYNC_OFFSET_VALID 100139225Sgibbs | CCB_TRANS_BUS_WIDTH_VALID 100239225Sgibbs | CCB_TRANS_DISC_VALID 100339225Sgibbs | CCB_TRANS_TQ_VALID; 100439225Sgibbs } else { 100539225Sgibbs ahafetchtransinfo(aha, cts); 100639225Sgibbs } 100739225Sgibbs 100839225Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 100939225Sgibbs xpt_done(ccb); 101039225Sgibbs break; 101139225Sgibbs } 101239225Sgibbs case XPT_CALC_GEOMETRY: 101339225Sgibbs { 101439225Sgibbs struct ccb_calc_geometry *ccg; 1015122340Simp uint32_t size_mb; 1016122340Simp uint32_t secs_per_cylinder; 101739225Sgibbs 101839225Sgibbs ccg = &ccb->ccg; 101939225Sgibbs size_mb = ccg->volume_size 102039225Sgibbs / ((1024L * 1024L) / ccg->block_size); 102139225Sgibbs 102239225Sgibbs if (size_mb >= 1024 && (aha->extended_trans != 0)) { 102339225Sgibbs if (size_mb >= 2048) { 102439225Sgibbs ccg->heads = 255; 102539225Sgibbs ccg->secs_per_track = 63; 102639225Sgibbs } else { 102739225Sgibbs ccg->heads = 128; 102839225Sgibbs ccg->secs_per_track = 32; 102939225Sgibbs } 103039225Sgibbs } else { 103139225Sgibbs ccg->heads = 64; 103239225Sgibbs ccg->secs_per_track = 32; 103339225Sgibbs } 103439225Sgibbs secs_per_cylinder = ccg->heads * ccg->secs_per_track; 103539225Sgibbs ccg->cylinders = ccg->volume_size / secs_per_cylinder; 103639225Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 103739225Sgibbs xpt_done(ccb); 103839225Sgibbs break; 103939225Sgibbs } 104039225Sgibbs case XPT_RESET_BUS: /* Reset the specified SCSI bus */ 104139225Sgibbs ahareset(aha, /*hardreset*/TRUE); 104239225Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 104339225Sgibbs xpt_done(ccb); 104439225Sgibbs break; 104539225Sgibbs case XPT_TERM_IO: /* Terminate the I/O process */ 104639225Sgibbs /* XXX Implement */ 104739225Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 104839225Sgibbs xpt_done(ccb); 104939225Sgibbs break; 105039225Sgibbs case XPT_PATH_INQ: /* Path routing inquiry */ 105139225Sgibbs { 105239225Sgibbs struct ccb_pathinq *cpi = &ccb->cpi; 105339225Sgibbs 105439225Sgibbs cpi->version_num = 1; /* XXX??? */ 105539225Sgibbs cpi->hba_inquiry = PI_SDTR_ABLE; 105639225Sgibbs cpi->target_sprt = 0; 105739225Sgibbs cpi->hba_misc = 0; 105839225Sgibbs cpi->hba_eng_cnt = 0; 105939852Simp cpi->max_target = 7; 106039225Sgibbs cpi->max_lun = 7; 106139225Sgibbs cpi->initiator_id = aha->scsi_id; 106239225Sgibbs cpi->bus_id = cam_sim_bus(sim); 106346581Sken cpi->base_transfer_speed = 3300; 106439225Sgibbs strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 106539225Sgibbs strncpy(cpi->hba_vid, "Adaptec", HBA_IDLEN); 106639225Sgibbs strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 106739225Sgibbs cpi->unit_number = cam_sim_unit(sim); 106839225Sgibbs cpi->ccb_h.status = CAM_REQ_CMP; 106939225Sgibbs xpt_done(ccb); 107039225Sgibbs break; 107139225Sgibbs } 107239225Sgibbs default: 107339225Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 107439225Sgibbs xpt_done(ccb); 107539225Sgibbs break; 107639225Sgibbs } 107739225Sgibbs} 107839225Sgibbs 107939225Sgibbsstatic void 108039225Sgibbsahaexecuteccb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 108139225Sgibbs{ 108241047Sgibbs struct aha_ccb *accb; 108339225Sgibbs union ccb *ccb; 108439225Sgibbs struct aha_softc *aha; 108540419Sgibbs int s; 1086122340Simp uint32_t paddr; 108739225Sgibbs 108841047Sgibbs accb = (struct aha_ccb *)arg; 108941047Sgibbs ccb = accb->ccb; 109039225Sgibbs aha = (struct aha_softc *)ccb->ccb_h.ccb_aha_ptr; 109139225Sgibbs 109239225Sgibbs if (error != 0) { 109339225Sgibbs if (error != EFBIG) 109439225Sgibbs printf("%s: Unexepected error 0x%x returned from " 1095122340Simp "bus_dmamap_load\n", aha_name(aha), error); 109639225Sgibbs if (ccb->ccb_h.status == CAM_REQ_INPROG) { 109739225Sgibbs xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 109839225Sgibbs ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN; 109939225Sgibbs } 110041047Sgibbs ahafreeccb(aha, accb); 110139225Sgibbs xpt_done(ccb); 110239225Sgibbs return; 110339225Sgibbs } 110439225Sgibbs 110539225Sgibbs if (nseg != 0) { 110639225Sgibbs aha_sg_t *sg; 110739225Sgibbs bus_dma_segment_t *end_seg; 1108115343Sscottl bus_dmasync_op_t op; 110939225Sgibbs 111039225Sgibbs end_seg = dm_segs + nseg; 111139225Sgibbs 111239225Sgibbs /* Copy the segments into our SG list */ 111341047Sgibbs sg = accb->sg_list; 111439225Sgibbs while (dm_segs < end_seg) { 111539225Sgibbs ahautoa24(dm_segs->ds_len, sg->len); 111639225Sgibbs ahautoa24(dm_segs->ds_addr, sg->addr); 111739225Sgibbs sg++; 111839225Sgibbs dm_segs++; 111939225Sgibbs } 112039225Sgibbs 112139225Sgibbs if (nseg > 1) { 112242887Simp accb->hccb.opcode = aha->ccb_sg_opcode; 112339225Sgibbs ahautoa24((sizeof(aha_sg_t) * nseg), 1124122340Simp accb->hccb.data_len); 112541047Sgibbs ahautoa24(accb->sg_list_phys, accb->hccb.data_addr); 112639225Sgibbs } else { 112741047Sgibbs bcopy(accb->sg_list->len, accb->hccb.data_len, 3); 112841047Sgibbs bcopy(accb->sg_list->addr, accb->hccb.data_addr, 3); 112939225Sgibbs } 113039225Sgibbs 113139225Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 113239225Sgibbs op = BUS_DMASYNC_PREREAD; 113339225Sgibbs else 113439225Sgibbs op = BUS_DMASYNC_PREWRITE; 113539225Sgibbs 113641047Sgibbs bus_dmamap_sync(aha->buffer_dmat, accb->dmamap, op); 113739225Sgibbs 113839225Sgibbs } else { 113941709Sgibbs accb->hccb.opcode = INITIATOR_CCB; 114041047Sgibbs ahautoa24(0, accb->hccb.data_len); 114141047Sgibbs ahautoa24(0, accb->hccb.data_addr); 114239225Sgibbs } 114339225Sgibbs 114439225Sgibbs s = splcam(); 114539225Sgibbs 114639225Sgibbs /* 114739225Sgibbs * Last time we need to check if this CCB needs to 114839225Sgibbs * be aborted. 114939225Sgibbs */ 115039225Sgibbs if (ccb->ccb_h.status != CAM_REQ_INPROG) { 115139225Sgibbs if (nseg != 0) 115241047Sgibbs bus_dmamap_unload(aha->buffer_dmat, accb->dmamap); 115341047Sgibbs ahafreeccb(aha, accb); 115439225Sgibbs xpt_done(ccb); 115539225Sgibbs splx(s); 115639225Sgibbs return; 115739225Sgibbs } 115839225Sgibbs 115941047Sgibbs accb->flags = ACCB_ACTIVE; 116039225Sgibbs ccb->ccb_h.status |= CAM_SIM_QUEUED; 116139225Sgibbs LIST_INSERT_HEAD(&aha->pending_ccbs, &ccb->ccb_h, sim_links.le); 116239225Sgibbs 1163122340Simp ccb->ccb_h.timeout_ch = timeout(ahatimeout, (caddr_t)accb, 1164122340Simp (ccb->ccb_h.timeout * hz) / 1000); 116539225Sgibbs 116639225Sgibbs /* Tell the adapter about this command */ 116741047Sgibbs if (aha->cur_outbox->action_code != AMBO_FREE) { 116841047Sgibbs /* 116941047Sgibbs * We should never encounter a busy mailbox. 117041047Sgibbs * If we do, warn the user, and treat it as 117141047Sgibbs * a resource shortage. If the controller is 117241047Sgibbs * hung, one of the pending transactions will 117341047Sgibbs * timeout causing us to start recovery operations. 117441047Sgibbs */ 117541047Sgibbs printf("%s: Encountered busy mailbox with %d out of %d " 1176122340Simp "commands active!!!", aha_name(aha), aha->active_ccbs, 1177122340Simp aha->max_ccbs); 117841047Sgibbs untimeout(ahatimeout, accb, ccb->ccb_h.timeout_ch); 117941047Sgibbs if (nseg != 0) 118041047Sgibbs bus_dmamap_unload(aha->buffer_dmat, accb->dmamap); 118141047Sgibbs ahafreeccb(aha, accb); 118241047Sgibbs aha->resource_shortage = TRUE; 118341047Sgibbs xpt_freeze_simq(aha->sim, /*count*/1); 118441047Sgibbs ccb->ccb_h.status = CAM_REQUEUE_REQ; 118541047Sgibbs xpt_done(ccb); 118641047Sgibbs return; 118741047Sgibbs } 118841047Sgibbs paddr = ahaccbvtop(aha, accb); 118939225Sgibbs ahautoa24(paddr, aha->cur_outbox->ccb_addr); 119041047Sgibbs aha->cur_outbox->action_code = AMBO_START; 119141047Sgibbs aha_outb(aha, COMMAND_REG, AOP_START_MBOX); 119239225Sgibbs 119339225Sgibbs ahanextoutbox(aha); 119439225Sgibbs splx(s); 119539225Sgibbs} 119639225Sgibbs 119739225Sgibbsvoid 119839225Sgibbsaha_intr(void *arg) 119939225Sgibbs{ 120039225Sgibbs struct aha_softc *aha; 120139225Sgibbs u_int intstat; 1202122340Simp uint32_t paddr; 120339225Sgibbs 120439225Sgibbs aha = (struct aha_softc *)arg; 120539225Sgibbs while (((intstat = aha_inb(aha, INTSTAT_REG)) & INTR_PENDING) != 0) { 120639225Sgibbs if ((intstat & CMD_COMPLETE) != 0) { 120739225Sgibbs aha->latched_status = aha_inb(aha, STATUS_REG); 120839225Sgibbs aha->command_cmp = TRUE; 120939225Sgibbs } 121039225Sgibbs 121139225Sgibbs aha_outb(aha, CONTROL_REG, RESET_INTR); 121239225Sgibbs 121339225Sgibbs if ((intstat & IMB_LOADED) != 0) { 121441047Sgibbs while (aha->cur_inbox->comp_code != AMBI_FREE) { 121539225Sgibbs paddr = aha_a24tou(aha->cur_inbox->ccb_addr); 1216122340Simp ahadone(aha, ahaccbptov(aha, paddr), 1217122340Simp aha->cur_inbox->comp_code); 121841047Sgibbs aha->cur_inbox->comp_code = AMBI_FREE; 121939225Sgibbs ahanextinbox(aha); 122039225Sgibbs } 122139225Sgibbs } 122239225Sgibbs 122339225Sgibbs if ((intstat & SCSI_BUS_RESET) != 0) { 122439225Sgibbs ahareset(aha, /*hardreset*/FALSE); 122539225Sgibbs } 122639225Sgibbs } 122739225Sgibbs} 122839225Sgibbs 122939225Sgibbsstatic void 123041047Sgibbsahadone(struct aha_softc *aha, struct aha_ccb *accb, aha_mbi_comp_code_t comp_code) 123139225Sgibbs{ 123239225Sgibbs union ccb *ccb; 123339225Sgibbs struct ccb_scsiio *csio; 123439225Sgibbs 123541047Sgibbs ccb = accb->ccb; 123641047Sgibbs csio = &accb->ccb->csio; 123739225Sgibbs 123841047Sgibbs if ((accb->flags & ACCB_ACTIVE) == 0) { 123941047Sgibbs printf("%s: ahadone - Attempt to free non-active ACCB %p\n", 1240122340Simp aha_name(aha), (void *)accb); 124139225Sgibbs return; 124239225Sgibbs } 124339225Sgibbs 124439225Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 1245115343Sscottl bus_dmasync_op_t op; 124639225Sgibbs 124739225Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 124839225Sgibbs op = BUS_DMASYNC_POSTREAD; 124939225Sgibbs else 125039225Sgibbs op = BUS_DMASYNC_POSTWRITE; 125141047Sgibbs bus_dmamap_sync(aha->buffer_dmat, accb->dmamap, op); 125241047Sgibbs bus_dmamap_unload(aha->buffer_dmat, accb->dmamap); 125339225Sgibbs } 125439225Sgibbs 125541047Sgibbs if (accb == aha->recovery_accb) { 125639225Sgibbs /* 125741047Sgibbs * The recovery ACCB does not have a CCB associated 125839225Sgibbs * with it, so short circuit the normal error handling. 125939225Sgibbs * We now traverse our list of pending CCBs and process 126039225Sgibbs * any that were terminated by the recovery CCBs action. 126139225Sgibbs * We also reinstate timeouts for all remaining, pending, 126239225Sgibbs * CCBs. 126339225Sgibbs */ 126439225Sgibbs struct cam_path *path; 126539225Sgibbs struct ccb_hdr *ccb_h; 126639225Sgibbs cam_status error; 126739225Sgibbs 126839225Sgibbs /* Notify all clients that a BDR occured */ 126939225Sgibbs error = xpt_create_path(&path, /*periph*/NULL, 1270122340Simp cam_sim_path(aha->sim), accb->hccb.target, 1271122340Simp CAM_LUN_WILDCARD); 127239225Sgibbs 127339225Sgibbs if (error == CAM_REQ_CMP) 127439225Sgibbs xpt_async(AC_SENT_BDR, path, NULL); 127539225Sgibbs 127639225Sgibbs ccb_h = LIST_FIRST(&aha->pending_ccbs); 127739225Sgibbs while (ccb_h != NULL) { 127841047Sgibbs struct aha_ccb *pending_accb; 127939225Sgibbs 128041047Sgibbs pending_accb = (struct aha_ccb *)ccb_h->ccb_accb_ptr; 128141047Sgibbs if (pending_accb->hccb.target == accb->hccb.target) { 128241047Sgibbs pending_accb->hccb.ahastat = AHASTAT_HA_BDR; 128339225Sgibbs ccb_h = LIST_NEXT(ccb_h, sim_links.le); 128441047Sgibbs ahadone(aha, pending_accb, AMBI_ERROR); 128539225Sgibbs } else { 1286122340Simp ccb_h->timeout_ch = timeout(ahatimeout, 1287122340Simp (caddr_t)pending_accb, 1288122340Simp (ccb_h->timeout * hz) / 1000); 128939225Sgibbs ccb_h = LIST_NEXT(ccb_h, sim_links.le); 129039225Sgibbs } 129139225Sgibbs } 129239225Sgibbs printf("%s: No longer in timeout\n", aha_name(aha)); 129339225Sgibbs return; 129439225Sgibbs } 129539225Sgibbs 129641047Sgibbs untimeout(ahatimeout, accb, ccb->ccb_h.timeout_ch); 129739225Sgibbs 129839225Sgibbs switch (comp_code) { 129941047Sgibbs case AMBI_FREE: 130039225Sgibbs printf("%s: ahadone - CCB completed with free status!\n", 130139225Sgibbs aha_name(aha)); 130239225Sgibbs break; 130341047Sgibbs case AMBI_NOT_FOUND: 130439225Sgibbs printf("%s: ahadone - CCB Abort failed to find CCB\n", 130539225Sgibbs aha_name(aha)); 130639225Sgibbs break; 130741047Sgibbs case AMBI_ABORT: 130841047Sgibbs case AMBI_ERROR: 130939225Sgibbs /* An error occured */ 131042887Simp if (accb->hccb.opcode < INITIATOR_CCB_WRESID) 131142887Simp csio->resid = 0; 131242887Simp else 131342887Simp csio->resid = aha_a24tou(accb->hccb.data_len); 131441047Sgibbs switch(accb->hccb.ahastat) { 131539225Sgibbs case AHASTAT_DATARUN_ERROR: 131642013Sgibbs { 131742013Sgibbs if (csio->resid <= 0) { 131839225Sgibbs csio->ccb_h.status = CAM_DATA_RUN_ERR; 131939225Sgibbs break; 132039225Sgibbs } 132139225Sgibbs /* FALLTHROUGH */ 132242013Sgibbs } 132339225Sgibbs case AHASTAT_NOERROR: 132441047Sgibbs csio->scsi_status = accb->hccb.sdstat; 132539225Sgibbs csio->ccb_h.status |= CAM_SCSI_STATUS_ERROR; 132639225Sgibbs switch(csio->scsi_status) { 132739225Sgibbs case SCSI_STATUS_CHECK_COND: 132839225Sgibbs case SCSI_STATUS_CMD_TERMINATED: 132939225Sgibbs csio->ccb_h.status |= CAM_AUTOSNS_VALID; 133039225Sgibbs /* 133139225Sgibbs * The aha writes the sense data at different 133239225Sgibbs * offsets based on the scsi cmd len 133339225Sgibbs */ 133441047Sgibbs bcopy((caddr_t) &accb->hccb.scsi_cdb + 1335122340Simp accb->hccb.cmd_len, 1336122340Simp (caddr_t) &csio->sense_data, 1337122340Simp accb->hccb.sense_len); 133839225Sgibbs break; 133939225Sgibbs default: 134039225Sgibbs break; 134139225Sgibbs case SCSI_STATUS_OK: 134239225Sgibbs csio->ccb_h.status = CAM_REQ_CMP; 134339225Sgibbs break; 134439225Sgibbs } 134539225Sgibbs break; 134639225Sgibbs case AHASTAT_SELTIMEOUT: 134739225Sgibbs csio->ccb_h.status = CAM_SEL_TIMEOUT; 134839225Sgibbs break; 134939225Sgibbs case AHASTAT_UNEXPECTED_BUSFREE: 135039225Sgibbs csio->ccb_h.status = CAM_UNEXP_BUSFREE; 135139225Sgibbs break; 135239225Sgibbs case AHASTAT_INVALID_PHASE: 135339225Sgibbs csio->ccb_h.status = CAM_SEQUENCE_FAIL; 135439225Sgibbs break; 135539225Sgibbs case AHASTAT_INVALID_ACTION_CODE: 135639225Sgibbs panic("%s: Inavlid Action code", aha_name(aha)); 135739225Sgibbs break; 135839225Sgibbs case AHASTAT_INVALID_OPCODE: 135942887Simp if (accb->hccb.opcode < INITIATOR_CCB_WRESID) 136042887Simp panic("%s: Invalid CCB Opcode %x hccb = %p", 1361122340Simp aha_name(aha), accb->hccb.opcode, 1362122340Simp &accb->hccb); 136342887Simp printf("%s: AHA-1540A detected, compensating\n", 1364122340Simp aha_name(aha)); 136542887Simp aha->ccb_sg_opcode = INITIATOR_SG_CCB; 136642887Simp aha->ccb_ccb_opcode = INITIATOR_CCB; 136742887Simp xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 136842887Simp csio->ccb_h.status = CAM_REQUEUE_REQ; 136939225Sgibbs break; 137039225Sgibbs case AHASTAT_LINKED_CCB_LUN_MISMATCH: 137139225Sgibbs /* We don't even support linked commands... */ 137239225Sgibbs panic("%s: Linked CCB Lun Mismatch", aha_name(aha)); 137339225Sgibbs break; 137439225Sgibbs case AHASTAT_INVALID_CCB_OR_SG_PARAM: 137539225Sgibbs panic("%s: Invalid CCB or SG list", aha_name(aha)); 137639225Sgibbs break; 137739225Sgibbs case AHASTAT_HA_SCSI_BUS_RESET: 137839225Sgibbs if ((csio->ccb_h.status & CAM_STATUS_MASK) 137942887Simp != CAM_CMD_TIMEOUT) 138039225Sgibbs csio->ccb_h.status = CAM_SCSI_BUS_RESET; 138139225Sgibbs break; 138239225Sgibbs case AHASTAT_HA_BDR: 138341047Sgibbs if ((accb->flags & ACCB_DEVICE_RESET) == 0) 138439225Sgibbs csio->ccb_h.status = CAM_BDR_SENT; 138539225Sgibbs else 138639225Sgibbs csio->ccb_h.status = CAM_CMD_TIMEOUT; 138739225Sgibbs break; 138839225Sgibbs } 138939225Sgibbs if (csio->ccb_h.status != CAM_REQ_CMP) { 139039225Sgibbs xpt_freeze_devq(csio->ccb_h.path, /*count*/1); 139139225Sgibbs csio->ccb_h.status |= CAM_DEV_QFRZN; 139239225Sgibbs } 139341047Sgibbs if ((accb->flags & ACCB_RELEASE_SIMQ) != 0) 139439225Sgibbs ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 139541047Sgibbs ahafreeccb(aha, accb); 139639225Sgibbs xpt_done(ccb); 139739225Sgibbs break; 139841047Sgibbs case AMBI_OK: 139939225Sgibbs /* All completed without incident */ 140039225Sgibbs /* XXX DO WE NEED TO COPY SENSE BYTES HERE???? XXX */ 140142887Simp /* I don't think so since it works???? */ 140239225Sgibbs ccb->ccb_h.status |= CAM_REQ_CMP; 140341047Sgibbs if ((accb->flags & ACCB_RELEASE_SIMQ) != 0) 140439225Sgibbs ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 140541047Sgibbs ahafreeccb(aha, accb); 140639225Sgibbs xpt_done(ccb); 140739225Sgibbs break; 140839225Sgibbs } 140939225Sgibbs} 141039225Sgibbs 141139225Sgibbsstatic int 141239225Sgibbsahareset(struct aha_softc* aha, int hard_reset) 141339225Sgibbs{ 141439225Sgibbs struct ccb_hdr *ccb_h; 141539225Sgibbs u_int status; 141639225Sgibbs u_int timeout; 1417122340Simp uint8_t reset_type; 141839225Sgibbs 141939225Sgibbs if (hard_reset != 0) 142039225Sgibbs reset_type = HARD_RESET; 142139225Sgibbs else 142239225Sgibbs reset_type = SOFT_RESET; 142339225Sgibbs aha_outb(aha, CONTROL_REG, reset_type); 142439225Sgibbs 142539225Sgibbs /* Wait 5sec. for Diagnostic start */ 142639225Sgibbs timeout = 5 * 10000; 142739225Sgibbs while (--timeout) { 142839225Sgibbs status = aha_inb(aha, STATUS_REG); 142939225Sgibbs if ((status & DIAG_ACTIVE) != 0) 143039225Sgibbs break; 143139225Sgibbs DELAY(100); 143239225Sgibbs } 143339225Sgibbs if (timeout == 0) { 143439881Simp PRVERB(("%s: ahareset - Diagnostic Active failed to " 1435122340Simp "assert. status = 0x%x\n", aha_name(aha), status)); 143639225Sgibbs return (ETIMEDOUT); 143739225Sgibbs } 143839225Sgibbs 143939225Sgibbs /* Wait 10sec. for Diagnostic end */ 144039225Sgibbs timeout = 10 * 10000; 144139225Sgibbs while (--timeout) { 144239225Sgibbs status = aha_inb(aha, STATUS_REG); 144339225Sgibbs if ((status & DIAG_ACTIVE) == 0) 144439225Sgibbs break; 144539225Sgibbs DELAY(100); 144639225Sgibbs } 144739225Sgibbs if (timeout == 0) { 144839225Sgibbs panic("%s: ahareset - Diagnostic Active failed to drop. " 1449122340Simp "status = 0x%x\n", aha_name(aha), status); 145039225Sgibbs return (ETIMEDOUT); 145139225Sgibbs } 145239225Sgibbs 145339225Sgibbs /* Wait for the host adapter to become ready or report a failure */ 145439225Sgibbs timeout = 10000; 145539225Sgibbs while (--timeout) { 145639225Sgibbs status = aha_inb(aha, STATUS_REG); 145739225Sgibbs if ((status & (DIAG_FAIL|HA_READY|DATAIN_REG_READY)) != 0) 145839225Sgibbs break; 145939225Sgibbs DELAY(100); 146039225Sgibbs } 146139225Sgibbs if (timeout == 0) { 146239225Sgibbs printf("%s: ahareset - Host adapter failed to come ready. " 1463122340Simp "status = 0x%x\n", aha_name(aha), status); 146439225Sgibbs return (ETIMEDOUT); 146539225Sgibbs } 146639225Sgibbs 146739225Sgibbs /* If the diagnostics failed, tell the user */ 146839225Sgibbs if ((status & DIAG_FAIL) != 0 146939225Sgibbs || (status & HA_READY) == 0) { 147039225Sgibbs printf("%s: ahareset - Adapter failed diagnostics\n", 1471122340Simp aha_name(aha)); 147239225Sgibbs 147339225Sgibbs if ((status & DATAIN_REG_READY) != 0) 147439324Sgibbs printf("%s: ahareset - Host Adapter Error " 1475122340Simp "code = 0x%x\n", aha_name(aha), 1476122340Simp aha_inb(aha, DATAIN_REG)); 147739225Sgibbs return (ENXIO); 147839225Sgibbs } 147939225Sgibbs 148039225Sgibbs /* If we've allocated mailboxes, initialize them */ 148139225Sgibbs if (aha->init_level > 4) 148239225Sgibbs ahainitmboxes(aha); 148339225Sgibbs 148439225Sgibbs /* If we've attached to the XPT, tell it about the event */ 148539225Sgibbs if (aha->path != NULL) 148639225Sgibbs xpt_async(AC_BUS_RESET, aha->path, NULL); 148739225Sgibbs 148839225Sgibbs /* 148939225Sgibbs * Perform completion processing for all outstanding CCBs. 149039225Sgibbs */ 149139225Sgibbs while ((ccb_h = LIST_FIRST(&aha->pending_ccbs)) != NULL) { 149241047Sgibbs struct aha_ccb *pending_accb; 149339225Sgibbs 149441047Sgibbs pending_accb = (struct aha_ccb *)ccb_h->ccb_accb_ptr; 149541047Sgibbs pending_accb->hccb.ahastat = AHASTAT_HA_SCSI_BUS_RESET; 149641047Sgibbs ahadone(aha, pending_accb, AMBI_ERROR); 149739225Sgibbs } 149839225Sgibbs 149939225Sgibbs return (0); 150039225Sgibbs} 150139225Sgibbs 150239225Sgibbs/* 150339225Sgibbs * Send a command to the adapter. 150439225Sgibbs */ 150539225Sgibbsint 1506122340Simpaha_cmd(struct aha_softc *aha, aha_op_t opcode, uint8_t *params, 1507122340Simp u_int param_len, uint8_t *reply_data, u_int reply_len, 150847506Sgibbs u_int cmd_timeout) 150939225Sgibbs{ 151039225Sgibbs u_int timeout; 151139225Sgibbs u_int status; 151247506Sgibbs u_int saved_status; 151339225Sgibbs u_int intstat; 151439225Sgibbs u_int reply_buf_size; 151539225Sgibbs int s; 151641709Sgibbs int cmd_complete; 151747506Sgibbs int error; 151839225Sgibbs 151939225Sgibbs /* No data returned to start */ 152039225Sgibbs reply_buf_size = reply_len; 152139225Sgibbs reply_len = 0; 152239225Sgibbs intstat = 0; 152341709Sgibbs cmd_complete = 0; 152447506Sgibbs saved_status = 0; 152547506Sgibbs error = 0; 152639225Sgibbs 152747506Sgibbs /* 152847506Sgibbs * All commands except for the "start mailbox" and the "enable 152947506Sgibbs * outgoing mailbox read interrupt" commands cannot be issued 153047506Sgibbs * while there are pending transactions. Freeze our SIMQ 153147506Sgibbs * and wait for all completions to occur if necessary. 153247506Sgibbs */ 153347506Sgibbs timeout = 100000; 153447506Sgibbs s = splcam(); 153547506Sgibbs while (LIST_FIRST(&aha->pending_ccbs) != NULL && --timeout) { 153647506Sgibbs /* Fire the interrupt handler in case interrupts are blocked */ 153747506Sgibbs aha_intr(aha); 153847506Sgibbs splx(s); 153947506Sgibbs DELAY(100); 154047506Sgibbs s = splcam(); 154147506Sgibbs } 154247506Sgibbs splx(s); 154347506Sgibbs 154447506Sgibbs if (timeout == 0) { 154547506Sgibbs printf("%s: aha_cmd: Timeout waiting for adapter idle\n", 1546122340Simp aha_name(aha)); 154747506Sgibbs return (ETIMEDOUT); 154847506Sgibbs } 154939225Sgibbs aha->command_cmp = 0; 155039225Sgibbs /* 155147506Sgibbs * Wait up to 10 sec. for the adapter to become 155239225Sgibbs * ready to accept commands. 155339225Sgibbs */ 155447506Sgibbs timeout = 100000; 155539225Sgibbs while (--timeout) { 155639225Sgibbs status = aha_inb(aha, STATUS_REG); 1557122340Simp if ((status & HA_READY) != 0 && (status & CMD_REG_BUSY) == 0) 155839225Sgibbs break; 155947506Sgibbs /* 156047506Sgibbs * Throw away any pending data which may be 156147506Sgibbs * left over from earlier commands that we 156247506Sgibbs * timedout on. 156347506Sgibbs */ 156447506Sgibbs if ((status & DATAIN_REG_READY) != 0) 156547506Sgibbs (void)aha_inb(aha, DATAIN_REG); 156639225Sgibbs DELAY(100); 156739225Sgibbs } 156839225Sgibbs if (timeout == 0) { 156939225Sgibbs printf("%s: aha_cmd: Timeout waiting for adapter ready, " 1570122340Simp "status = 0x%x\n", aha_name(aha), status); 157139225Sgibbs return (ETIMEDOUT); 157239225Sgibbs } 157339225Sgibbs 157439225Sgibbs /* 157539225Sgibbs * Send the opcode followed by any necessary parameter bytes. 157639225Sgibbs */ 157739225Sgibbs aha_outb(aha, COMMAND_REG, opcode); 157839225Sgibbs 157939225Sgibbs /* 158039225Sgibbs * Wait for up to 1sec to get the parameter list sent 158139225Sgibbs */ 158239225Sgibbs timeout = 10000; 158339225Sgibbs while (param_len && --timeout) { 158439225Sgibbs DELAY(100); 158547506Sgibbs s = splcam(); 158639225Sgibbs status = aha_inb(aha, STATUS_REG); 158739225Sgibbs intstat = aha_inb(aha, INTSTAT_REG); 158847506Sgibbs splx(s); 158947506Sgibbs 159039225Sgibbs if ((intstat & (INTR_PENDING|CMD_COMPLETE)) 159141709Sgibbs == (INTR_PENDING|CMD_COMPLETE)) { 159247506Sgibbs saved_status = status; 159341709Sgibbs cmd_complete = 1; 159439225Sgibbs break; 159541709Sgibbs } 159647506Sgibbs 159739225Sgibbs if (aha->command_cmp != 0) { 159847506Sgibbs saved_status = aha->latched_status; 159941709Sgibbs cmd_complete = 1; 160039225Sgibbs break; 160139225Sgibbs } 160239225Sgibbs if ((status & DATAIN_REG_READY) != 0) 160339225Sgibbs break; 160439225Sgibbs if ((status & CMD_REG_BUSY) == 0) { 160539225Sgibbs aha_outb(aha, COMMAND_REG, *params++); 160639225Sgibbs param_len--; 160747506Sgibbs timeout = 10000; 160839225Sgibbs } 160939225Sgibbs } 161039225Sgibbs if (timeout == 0) { 161139225Sgibbs printf("%s: aha_cmd: Timeout sending parameters, " 161239225Sgibbs "status = 0x%x\n", aha_name(aha), status); 161347506Sgibbs error = ETIMEDOUT; 161439225Sgibbs } 161539225Sgibbs 161639225Sgibbs /* 161739225Sgibbs * For all other commands, we wait for any output data 161839225Sgibbs * and the final comand completion interrupt. 161939225Sgibbs */ 162041709Sgibbs while (cmd_complete == 0 && --cmd_timeout) { 162139225Sgibbs 162247506Sgibbs s = splcam(); 162339225Sgibbs status = aha_inb(aha, STATUS_REG); 162439225Sgibbs intstat = aha_inb(aha, INTSTAT_REG); 162547506Sgibbs splx(s); 162639225Sgibbs 162739225Sgibbs if (aha->command_cmp != 0) { 162847506Sgibbs cmd_complete = 1; 162947506Sgibbs saved_status = aha->latched_status; 163047506Sgibbs } else if ((intstat & (INTR_PENDING|CMD_COMPLETE)) 163147506Sgibbs == (INTR_PENDING|CMD_COMPLETE)) { 163247506Sgibbs /* 163347506Sgibbs * Our poll (in case interrupts are blocked) 163447506Sgibbs * saw the CMD_COMPLETE interrupt. 163547506Sgibbs */ 163647506Sgibbs cmd_complete = 1; 163747506Sgibbs saved_status = status; 163851869Smdodd } 163951869Smdodd if ((status & DATAIN_REG_READY) != 0) { 1640122340Simp uint8_t data; 164139225Sgibbs 164239225Sgibbs data = aha_inb(aha, DATAIN_REG); 164339225Sgibbs if (reply_len < reply_buf_size) { 164439225Sgibbs *reply_data++ = data; 164539225Sgibbs } else { 164647506Sgibbs printf("%s: aha_cmd - Discarded reply data " 1647122340Simp "byte for opcode 0x%x\n", aha_name(aha), 1648122340Simp opcode); 164939225Sgibbs } 165047506Sgibbs /* 165147506Sgibbs * Reset timeout to ensure at least a second 165247506Sgibbs * between response bytes. 165347506Sgibbs */ 165447506Sgibbs cmd_timeout = MAX(cmd_timeout, 10000); 165539225Sgibbs reply_len++; 165639225Sgibbs } 165739225Sgibbs DELAY(100); 165839225Sgibbs } 165947506Sgibbs if (cmd_timeout == 0) { 166039225Sgibbs printf("%s: aha_cmd: Timeout waiting for reply data and " 1661122340Simp "command complete.\n%s: status = 0x%x, intstat = 0x%x, " 1662122340Simp "reply_len = %d\n", aha_name(aha), aha_name(aha), status, 1663122340Simp intstat, reply_len); 166439225Sgibbs return (ETIMEDOUT); 166539225Sgibbs } 166639225Sgibbs 166739225Sgibbs /* 166839225Sgibbs * Clear any pending interrupts. Block interrupts so our 166939225Sgibbs * interrupt handler is not re-entered. 167039225Sgibbs */ 167139225Sgibbs s = splcam(); 167239225Sgibbs aha_intr(aha); 167339225Sgibbs splx(s); 167439225Sgibbs 167547506Sgibbs if (error != 0) 167647506Sgibbs return (error); 167747506Sgibbs 167839225Sgibbs /* 167939225Sgibbs * If the command was rejected by the controller, tell the caller. 168039225Sgibbs */ 168147506Sgibbs if ((saved_status & CMD_INVALID) != 0) { 168239881Simp PRVERB(("%s: Invalid Command 0x%x\n", aha_name(aha), opcode)); 168339225Sgibbs /* 168439225Sgibbs * Some early adapters may not recover properly from 168539225Sgibbs * an invalid command. If it appears that the controller 168639225Sgibbs * has wedged (i.e. status was not cleared by our interrupt 168739225Sgibbs * reset above), perform a soft reset. 168839225Sgibbs */ 168939225Sgibbs DELAY(1000); 169039225Sgibbs status = aha_inb(aha, STATUS_REG); 169139225Sgibbs if ((status & (CMD_INVALID|STATUS_REG_RSVD|DATAIN_REG_READY| 169239225Sgibbs CMD_REG_BUSY|DIAG_FAIL|DIAG_ACTIVE)) != 0 169339225Sgibbs || (status & (HA_READY|INIT_REQUIRED)) 1694122340Simp != (HA_READY|INIT_REQUIRED)) 169539852Simp ahareset(aha, /*hard_reset*/FALSE); 169639225Sgibbs return (EINVAL); 169739225Sgibbs } 169839225Sgibbs 169939225Sgibbs if (param_len > 0) { 170039225Sgibbs /* The controller did not accept the full argument list */ 170151869Smdodd PRVERB(("%s: Controller did not accept full argument list " 1702122340Simp "(%d > 0)\n", aha_name(aha), param_len)); 170339225Sgibbs return (E2BIG); 170439225Sgibbs } 170539225Sgibbs 170639225Sgibbs if (reply_len != reply_buf_size) { 170739225Sgibbs /* Too much or too little data received */ 170851869Smdodd PRVERB(("%s: Too much or too little data received (%d != %d)\n", 1709122340Simp aha_name(aha), reply_len, reply_buf_size)); 171039225Sgibbs return (EMSGSIZE); 171139225Sgibbs } 171239225Sgibbs 171339225Sgibbs /* We were successful */ 171439225Sgibbs return (0); 171539225Sgibbs} 171639225Sgibbs 171739225Sgibbsstatic int 171839225Sgibbsahainitmboxes(struct aha_softc *aha) 171939225Sgibbs{ 172039225Sgibbs int error; 172139225Sgibbs init_24b_mbox_params_t init_mbox; 172239225Sgibbs 172339225Sgibbs bzero(aha->in_boxes, sizeof(aha_mbox_in_t) * aha->num_boxes); 172439225Sgibbs bzero(aha->out_boxes, sizeof(aha_mbox_out_t) * aha->num_boxes); 172539225Sgibbs aha->cur_inbox = aha->in_boxes; 172639225Sgibbs aha->last_inbox = aha->in_boxes + aha->num_boxes - 1; 172739225Sgibbs aha->cur_outbox = aha->out_boxes; 172839225Sgibbs aha->last_outbox = aha->out_boxes + aha->num_boxes - 1; 172939225Sgibbs 173039225Sgibbs /* Tell the adapter about them */ 173139225Sgibbs init_mbox.num_mboxes = aha->num_boxes; 173239225Sgibbs ahautoa24(aha->mailbox_physbase, init_mbox.base_addr); 1733122340Simp error = aha_cmd(aha, AOP_INITIALIZE_MBOX, (uint8_t *)&init_mbox, 1734122340Simp /*parmlen*/sizeof(init_mbox), /*reply_buf*/NULL, 1735122340Simp /*reply_len*/0, DEFAULT_CMD_TIMEOUT); 173639225Sgibbs 173739225Sgibbs if (error != 0) 173839225Sgibbs printf("ahainitmboxes: Initialization command failed\n"); 173939225Sgibbs return (error); 174039225Sgibbs} 174139225Sgibbs 174239225Sgibbs/* 174339225Sgibbs * Update the XPT's idea of the negotiated transfer 174439225Sgibbs * parameters for a particular target. 174539225Sgibbs */ 174639225Sgibbsstatic void 174739225Sgibbsahafetchtransinfo(struct aha_softc *aha, struct ccb_trans_settings* cts) 174839225Sgibbs{ 174939225Sgibbs setup_data_t setup_info; 175039225Sgibbs u_int target; 175139225Sgibbs u_int targ_offset; 175239225Sgibbs u_int sync_period; 175339225Sgibbs int error; 1754122340Simp uint8_t param; 175539225Sgibbs targ_syncinfo_t sync_info; 175639225Sgibbs 175739225Sgibbs target = cts->ccb_h.target_id; 175839225Sgibbs targ_offset = (target & 0x7); 175939225Sgibbs 176039225Sgibbs /* 176147208Simp * Inquire Setup Information. This command retreives 176247506Sgibbs * the sync info for older models. 176339225Sgibbs */ 176439225Sgibbs param = sizeof(setup_info); 176541047Sgibbs error = aha_cmd(aha, AOP_INQUIRE_SETUP_INFO, ¶m, /*paramlen*/1, 1766122340Simp (uint8_t*)&setup_info, sizeof(setup_info), DEFAULT_CMD_TIMEOUT); 176739225Sgibbs 176839225Sgibbs if (error != 0) { 176947506Sgibbs printf("%s: ahafetchtransinfo - Inquire Setup Info Failed %d\n", 1770122340Simp aha_name(aha), error); 177139225Sgibbs return; 177239225Sgibbs } 177339225Sgibbs 177439225Sgibbs sync_info = setup_info.syncinfo[targ_offset]; 177539225Sgibbs 177639225Sgibbs if (sync_info.sync == 0) 177739225Sgibbs cts->sync_offset = 0; 177839225Sgibbs else 177939225Sgibbs cts->sync_offset = sync_info.offset; 178039225Sgibbs 178139225Sgibbs cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 178239225Sgibbs 178347506Sgibbs if (aha->boardid >= BOARD_1542CF) 178447506Sgibbs sync_period = 1000; 178547506Sgibbs else 178647506Sgibbs sync_period = 2000; 178747506Sgibbs sync_period += 500 * sync_info.period; 178839225Sgibbs 178939225Sgibbs /* Convert ns value to standard SCSI sync rate */ 179039225Sgibbs if (cts->sync_offset != 0) 179139225Sgibbs cts->sync_period = scsi_calc_syncparam(sync_period); 179239225Sgibbs else 179339225Sgibbs cts->sync_period = 0; 179439225Sgibbs 179539225Sgibbs cts->valid = CCB_TRANS_SYNC_RATE_VALID 179639225Sgibbs | CCB_TRANS_SYNC_OFFSET_VALID 179739225Sgibbs | CCB_TRANS_BUS_WIDTH_VALID; 179839225Sgibbs xpt_async(AC_TRANSFER_NEG, cts->ccb_h.path, cts); 179939225Sgibbs} 180039225Sgibbs 180139225Sgibbsstatic void 180239225Sgibbsahamapmboxes(void *arg, bus_dma_segment_t *segs, int nseg, int error) 180339225Sgibbs{ 180439225Sgibbs struct aha_softc* aha; 180539225Sgibbs 180639225Sgibbs aha = (struct aha_softc*)arg; 180739225Sgibbs aha->mailbox_physbase = segs->ds_addr; 180839225Sgibbs} 180939225Sgibbs 181039225Sgibbsstatic void 181139225Sgibbsahamapccbs(void *arg, bus_dma_segment_t *segs, int nseg, int error) 181239225Sgibbs{ 181339225Sgibbs struct aha_softc* aha; 181439225Sgibbs 181539225Sgibbs aha = (struct aha_softc*)arg; 181639225Sgibbs aha->aha_ccb_physbase = segs->ds_addr; 181739225Sgibbs} 181839225Sgibbs 181939225Sgibbsstatic void 182039225Sgibbsahamapsgs(void *arg, bus_dma_segment_t *segs, int nseg, int error) 182139225Sgibbs{ 182239225Sgibbs 182339225Sgibbs struct aha_softc* aha; 182439225Sgibbs 182539225Sgibbs aha = (struct aha_softc*)arg; 182639225Sgibbs SLIST_FIRST(&aha->sg_maps)->sg_physaddr = segs->ds_addr; 182739225Sgibbs} 182839225Sgibbs 182939225Sgibbsstatic void 183039225Sgibbsahapoll(struct cam_sim *sim) 183139225Sgibbs{ 183240132Sgibbs aha_intr(cam_sim_softc(sim)); 183339225Sgibbs} 183439225Sgibbs 183545575Seivindstatic void 183639225Sgibbsahatimeout(void *arg) 183739225Sgibbs{ 183841047Sgibbs struct aha_ccb *accb; 183939225Sgibbs union ccb *ccb; 184039225Sgibbs struct aha_softc *aha; 184139225Sgibbs int s; 1842122340Simp uint32_t paddr; 184339225Sgibbs 184441047Sgibbs accb = (struct aha_ccb *)arg; 184541047Sgibbs ccb = accb->ccb; 184639225Sgibbs aha = (struct aha_softc *)ccb->ccb_h.ccb_aha_ptr; 184739225Sgibbs xpt_print_path(ccb->ccb_h.path); 184841047Sgibbs printf("CCB %p - timed out\n", (void *)accb); 184939225Sgibbs 185039225Sgibbs s = splcam(); 185139225Sgibbs 185241047Sgibbs if ((accb->flags & ACCB_ACTIVE) == 0) { 185339225Sgibbs xpt_print_path(ccb->ccb_h.path); 185439390Sgibbs printf("CCB %p - timed out CCB already completed\n", 1855122340Simp (void *)accb); 185639225Sgibbs splx(s); 185739225Sgibbs return; 185839225Sgibbs } 185939225Sgibbs 186039225Sgibbs /* 186139225Sgibbs * In order to simplify the recovery process, we ask the XPT 186239225Sgibbs * layer to halt the queue of new transactions and we traverse 186339225Sgibbs * the list of pending CCBs and remove their timeouts. This 186439225Sgibbs * means that the driver attempts to clear only one error 186539225Sgibbs * condition at a time. In general, timeouts that occur 186639225Sgibbs * close together are related anyway, so there is no benefit 186739225Sgibbs * in attempting to handle errors in parrallel. Timeouts will 186839225Sgibbs * be reinstated when the recovery process ends. 186939225Sgibbs */ 187041047Sgibbs if ((accb->flags & ACCB_DEVICE_RESET) == 0) { 187139225Sgibbs struct ccb_hdr *ccb_h; 187239225Sgibbs 187341047Sgibbs if ((accb->flags & ACCB_RELEASE_SIMQ) == 0) { 187439225Sgibbs xpt_freeze_simq(aha->sim, /*count*/1); 187541047Sgibbs accb->flags |= ACCB_RELEASE_SIMQ; 187639225Sgibbs } 187739225Sgibbs 187839225Sgibbs ccb_h = LIST_FIRST(&aha->pending_ccbs); 187939225Sgibbs while (ccb_h != NULL) { 188041047Sgibbs struct aha_ccb *pending_accb; 188139225Sgibbs 188241047Sgibbs pending_accb = (struct aha_ccb *)ccb_h->ccb_accb_ptr; 188341047Sgibbs untimeout(ahatimeout, pending_accb, ccb_h->timeout_ch); 188439225Sgibbs ccb_h = LIST_NEXT(ccb_h, sim_links.le); 188539225Sgibbs } 188639225Sgibbs } 188739225Sgibbs 188841047Sgibbs if ((accb->flags & ACCB_DEVICE_RESET) != 0 188941047Sgibbs || aha->cur_outbox->action_code != AMBO_FREE) { 189039225Sgibbs /* 189139225Sgibbs * Try a full host adapter/SCSI bus reset. 189239225Sgibbs * We do this only if we have already attempted 189339225Sgibbs * to clear the condition with a BDR, or we cannot 189439225Sgibbs * attempt a BDR for lack of mailbox resources. 189539225Sgibbs */ 189639225Sgibbs ccb->ccb_h.status = CAM_CMD_TIMEOUT; 189739225Sgibbs ahareset(aha, /*hardreset*/TRUE); 189839225Sgibbs printf("%s: No longer in timeout\n", aha_name(aha)); 189939225Sgibbs } else { 190039225Sgibbs /* 190139225Sgibbs * Send a Bus Device Reset message: 190239225Sgibbs * The target that is holding up the bus may not 190339225Sgibbs * be the same as the one that triggered this timeout 190439225Sgibbs * (different commands have different timeout lengths), 190539225Sgibbs * but we have no way of determining this from our 190639225Sgibbs * timeout handler. Our strategy here is to queue a 190739225Sgibbs * BDR message to the target of the timed out command. 190839225Sgibbs * If this fails, we'll get another timeout 2 seconds 190939225Sgibbs * later which will attempt a bus reset. 191039225Sgibbs */ 191141047Sgibbs accb->flags |= ACCB_DEVICE_RESET; 191241047Sgibbs ccb->ccb_h.timeout_ch = timeout(ahatimeout, (caddr_t)accb, 2 * hz); 191341047Sgibbs aha->recovery_accb->hccb.opcode = INITIATOR_BUS_DEV_RESET; 191439225Sgibbs 191539225Sgibbs /* No Data Transfer */ 191641047Sgibbs aha->recovery_accb->hccb.datain = TRUE; 191741047Sgibbs aha->recovery_accb->hccb.dataout = TRUE; 191841047Sgibbs aha->recovery_accb->hccb.ahastat = 0; 191941047Sgibbs aha->recovery_accb->hccb.sdstat = 0; 192041047Sgibbs aha->recovery_accb->hccb.target = ccb->ccb_h.target_id; 192139225Sgibbs 192239225Sgibbs /* Tell the adapter about this command */ 192341047Sgibbs paddr = ahaccbvtop(aha, aha->recovery_accb); 192439225Sgibbs ahautoa24(paddr, aha->cur_outbox->ccb_addr); 192541047Sgibbs aha->cur_outbox->action_code = AMBO_START; 192641047Sgibbs aha_outb(aha, COMMAND_REG, AOP_START_MBOX); 192739225Sgibbs ahanextoutbox(aha); 192839225Sgibbs } 192939225Sgibbs 193039225Sgibbs splx(s); 193139225Sgibbs} 193256504Simp 193356504Simpint 193456504Simpaha_detach(struct aha_softc *aha) 193556504Simp{ 193656504Simp xpt_async(AC_LOST_DEVICE, aha->path, NULL); 193756504Simp xpt_free_path(aha->path); 193856504Simp xpt_bus_deregister(cam_sim_path(aha->sim)); 193956504Simp cam_sim_free(aha->sim, /*free_devq*/TRUE); 194056504Simp return (0); 194156504Simp} 1942