aha.c revision 47208
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 * 5847208Simp * $Id: aha.c,v 1.24 1999/05/11 08:12:11 imp Exp $ 5939225Sgibbs */ 6039225Sgibbs 6142887Simp#include "pnp.h" 6242887Simp 6339225Sgibbs#include <sys/param.h> 6439225Sgibbs#include <sys/systm.h> 6539225Sgibbs#include <sys/malloc.h> 6639225Sgibbs#include <sys/buf.h> 6739225Sgibbs#include <sys/kernel.h> 6839225Sgibbs#include <sys/sysctl.h> 6939225Sgibbs 7039225Sgibbs#include <machine/bus_pio.h> 7139225Sgibbs#include <machine/bus.h> 7239225Sgibbs#include <machine/clock.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 <vm/vm.h> 8339225Sgibbs#include <vm/pmap.h> 8442887Simp 8542887Simp#if NPNP > 0 8642887Simp#include <i386/isa/isa_device.h> 8742887Simp#include <i386/isa/pnp.h> /* XXX pnp isn't x86 only */ 8842887Simp#endif 8939225Sgibbs 9039225Sgibbs#include <dev/aha/ahareg.h> 9139225Sgibbs 9242887Simpstruct aha_softc *aha_softcs[NAHATOT]; 9339225Sgibbs 9439225Sgibbs#define MIN(a, b) ((a) < (b) ? (a) : (b)) 9539881Simp#define PRVERB(x) if (bootverbose) printf x 9639225Sgibbs 9739751Simp/* Macro to determine that a rev is potentially a new valid one 9839751Simp * so that the driver doesn't keep breaking on new revs as it 9939751Simp * did for the CF and CP. 10039751Simp */ 10139751Simp#define PROBABLY_NEW_BOARD(REV) (REV > 0x43 && REV < 0x56) 10239751Simp 10339225Sgibbs/* MailBox Management functions */ 10439225Sgibbsstatic __inline void ahanextinbox(struct aha_softc *aha); 10539225Sgibbsstatic __inline void ahanextoutbox(struct aha_softc *aha); 10639225Sgibbs 10739225Sgibbsstatic __inline void 10839225Sgibbsahanextinbox(struct aha_softc *aha) 10939225Sgibbs{ 11039225Sgibbs if (aha->cur_inbox == aha->last_inbox) 11139225Sgibbs aha->cur_inbox = aha->in_boxes; 11239225Sgibbs else 11339225Sgibbs aha->cur_inbox++; 11439225Sgibbs} 11539225Sgibbs 11639225Sgibbsstatic __inline void 11739225Sgibbsahanextoutbox(struct aha_softc *aha) 11839225Sgibbs{ 11939225Sgibbs if (aha->cur_outbox == aha->last_outbox) 12039225Sgibbs aha->cur_outbox = aha->out_boxes; 12139225Sgibbs else 12239225Sgibbs aha->cur_outbox++; 12339225Sgibbs} 12439225Sgibbs 12539225Sgibbs#define ahautoa24(u,s3) \ 12639225Sgibbs (s3)[0] = ((u) >> 16) & 0xff; \ 12739225Sgibbs (s3)[1] = ((u) >> 8) & 0xff; \ 12839225Sgibbs (s3)[2] = (u) & 0xff; 12939225Sgibbs 13039225Sgibbs#define aha_a24tou(s3) \ 13139225Sgibbs (((s3)[0] << 16) | ((s3)[1] << 8) | (s3)[2]) 13239225Sgibbs 13339225Sgibbs/* CCB Mangement functions */ 13439225Sgibbsstatic __inline u_int32_t ahaccbvtop(struct aha_softc *aha, 13541047Sgibbs struct aha_ccb *accb); 13639225Sgibbsstatic __inline struct aha_ccb* ahaccbptov(struct aha_softc *aha, 13739225Sgibbs u_int32_t ccb_addr); 13839225Sgibbs 13939225Sgibbsstatic __inline u_int32_t 14041047Sgibbsahaccbvtop(struct aha_softc *aha, struct aha_ccb *accb) 14139225Sgibbs{ 14239225Sgibbs return (aha->aha_ccb_physbase 14341047Sgibbs + (u_int32_t)((caddr_t)accb - (caddr_t)aha->aha_ccb_array)); 14439225Sgibbs} 14539225Sgibbsstatic __inline struct aha_ccb * 14639225Sgibbsahaccbptov(struct aha_softc *aha, u_int32_t ccb_addr) 14739225Sgibbs{ 14839225Sgibbs return (aha->aha_ccb_array + 14939225Sgibbs + ((struct aha_ccb*)ccb_addr-(struct aha_ccb*)aha->aha_ccb_physbase)); 15039225Sgibbs} 15139225Sgibbs 15239225Sgibbsstatic struct aha_ccb* ahagetccb(struct aha_softc *aha); 15341047Sgibbsstatic __inline void ahafreeccb(struct aha_softc *aha, struct aha_ccb *accb); 15439225Sgibbsstatic void ahaallocccbs(struct aha_softc *aha); 15539225Sgibbsstatic bus_dmamap_callback_t ahaexecuteccb; 15641047Sgibbsstatic void ahadone(struct aha_softc *aha, struct aha_ccb *accb, 15739225Sgibbs aha_mbi_comp_code_t comp_code); 15839225Sgibbs 15939225Sgibbs/* Host adapter command functions */ 16039225Sgibbsstatic int ahareset(struct aha_softc* aha, int hard_reset); 16139225Sgibbs 16239225Sgibbs/* Initialization functions */ 16339225Sgibbsstatic int ahainitmboxes(struct aha_softc *aha); 16439225Sgibbsstatic bus_dmamap_callback_t ahamapmboxes; 16539225Sgibbsstatic bus_dmamap_callback_t ahamapccbs; 16639225Sgibbsstatic bus_dmamap_callback_t ahamapsgs; 16739225Sgibbs 16839225Sgibbs/* Transfer Negotiation Functions */ 16939225Sgibbsstatic void ahafetchtransinfo(struct aha_softc *aha, 17039225Sgibbs struct ccb_trans_settings *cts); 17139225Sgibbs 17239225Sgibbs/* CAM SIM entry points */ 17341047Sgibbs#define ccb_accb_ptr spriv_ptr0 17439225Sgibbs#define ccb_aha_ptr spriv_ptr1 17539225Sgibbsstatic void ahaaction(struct cam_sim *sim, union ccb *ccb); 17639225Sgibbsstatic void ahapoll(struct cam_sim *sim); 17739225Sgibbs 17839225Sgibbs/* Our timeout handler */ 17946602Speterstatic timeout_t ahatimeout; 18039225Sgibbs 18139225Sgibbsu_long aha_unit = 0; 18239225Sgibbs 18339225Sgibbs/* 18439225Sgibbs * Do our own re-probe protection until a configuration 18539225Sgibbs * manager can do it for us. This ensures that we don't 18639225Sgibbs * reprobe a card already found by the EISA or PCI probes. 18739225Sgibbs */ 18845575Seivindstatic struct aha_isa_port aha_isa_ports[] = 18939225Sgibbs{ 19041047Sgibbs { 0x130, 0, 4 }, 19141047Sgibbs { 0x134, 0, 5 }, 19241047Sgibbs { 0x230, 0, 2 }, 19341047Sgibbs { 0x234, 0, 3 }, 19441047Sgibbs { 0x330, 0, 0 }, 19541047Sgibbs { 0x334, 0, 1 } 19639225Sgibbs}; 19739225Sgibbs 19841047Sgibbs/* 19941047Sgibbs * I/O ports listed in the order enumerated by the 20041047Sgibbs * card for certain op codes. 20141047Sgibbs */ 20245575Seivindstatic u_int16_t aha_board_ports[] = 20341047Sgibbs{ 20441047Sgibbs 0x330, 20541047Sgibbs 0x334, 20641047Sgibbs 0x230, 20741047Sgibbs 0x234, 20841047Sgibbs 0x130, 20941047Sgibbs 0x134 21041047Sgibbs}; 21141047Sgibbs 21239225Sgibbs/* Exported functions */ 21339225Sgibbsstruct aha_softc * 21439225Sgibbsaha_alloc(int unit, bus_space_tag_t tag, bus_space_handle_t bsh) 21539225Sgibbs{ 21639225Sgibbs struct aha_softc *aha; 21739225Sgibbs 21839225Sgibbs if (unit != AHA_TEMP_UNIT) { 21942887Simp if (unit >= NAHATOT) { 22039225Sgibbs printf("aha: unit number (%d) too high\n", unit); 22139225Sgibbs return NULL; 22239225Sgibbs } 22339225Sgibbs 22439225Sgibbs /* 22539225Sgibbs * Allocate a storage area for us 22639225Sgibbs */ 22739225Sgibbs if (aha_softcs[unit]) { 22839225Sgibbs printf("aha%d: memory already allocated\n", unit); 22939225Sgibbs return NULL; 23039225Sgibbs } 23139225Sgibbs } 23239225Sgibbs 23339225Sgibbs aha = malloc(sizeof(struct aha_softc), M_DEVBUF, M_NOWAIT); 23439225Sgibbs if (!aha) { 23539225Sgibbs printf("aha%d: cannot malloc!\n", unit); 23639225Sgibbs return NULL; 23739225Sgibbs } 23839225Sgibbs bzero(aha, sizeof(struct aha_softc)); 23939225Sgibbs SLIST_INIT(&aha->free_aha_ccbs); 24039225Sgibbs LIST_INIT(&aha->pending_ccbs); 24139225Sgibbs SLIST_INIT(&aha->sg_maps); 24239225Sgibbs aha->unit = unit; 24339225Sgibbs aha->tag = tag; 24439225Sgibbs aha->bsh = bsh; 24542887Simp aha->ccb_sg_opcode = INITIATOR_SG_CCB_WRESID; 24642887Simp aha->ccb_ccb_opcode = INITIATOR_CCB_WRESID; 24739225Sgibbs 24839225Sgibbs if (aha->unit != AHA_TEMP_UNIT) { 24939225Sgibbs aha_softcs[unit] = aha; 25039225Sgibbs } 25139225Sgibbs return (aha); 25239225Sgibbs} 25339225Sgibbs 25439225Sgibbsvoid 25539225Sgibbsaha_free(struct aha_softc *aha) 25639225Sgibbs{ 25739225Sgibbs switch (aha->init_level) { 25839225Sgibbs default: 25939225Sgibbs case 8: 26039225Sgibbs { 26139225Sgibbs struct sg_map_node *sg_map; 26239225Sgibbs 26339225Sgibbs while ((sg_map = SLIST_FIRST(&aha->sg_maps))!= NULL) { 26439225Sgibbs SLIST_REMOVE_HEAD(&aha->sg_maps, links); 26539225Sgibbs bus_dmamap_unload(aha->sg_dmat, 26639225Sgibbs sg_map->sg_dmamap); 26739225Sgibbs bus_dmamem_free(aha->sg_dmat, sg_map->sg_vaddr, 26839225Sgibbs sg_map->sg_dmamap); 26939225Sgibbs free(sg_map, M_DEVBUF); 27039225Sgibbs } 27139225Sgibbs bus_dma_tag_destroy(aha->sg_dmat); 27239225Sgibbs } 27339225Sgibbs case 7: 27439225Sgibbs bus_dmamap_unload(aha->ccb_dmat, aha->ccb_dmamap); 27539225Sgibbs case 6: 27639225Sgibbs bus_dmamap_destroy(aha->ccb_dmat, aha->ccb_dmamap); 27739225Sgibbs bus_dmamem_free(aha->ccb_dmat, aha->aha_ccb_array, 27839225Sgibbs aha->ccb_dmamap); 27939225Sgibbs case 5: 28039225Sgibbs bus_dma_tag_destroy(aha->ccb_dmat); 28139225Sgibbs case 4: 28239225Sgibbs bus_dmamap_unload(aha->mailbox_dmat, aha->mailbox_dmamap); 28339225Sgibbs case 3: 28439225Sgibbs bus_dmamem_free(aha->mailbox_dmat, aha->in_boxes, 28539225Sgibbs aha->mailbox_dmamap); 28639225Sgibbs bus_dmamap_destroy(aha->mailbox_dmat, aha->mailbox_dmamap); 28739225Sgibbs case 2: 28839225Sgibbs bus_dma_tag_destroy(aha->buffer_dmat); 28939225Sgibbs case 1: 29039225Sgibbs bus_dma_tag_destroy(aha->mailbox_dmat); 29139225Sgibbs case 0: 29239225Sgibbs } 29339225Sgibbs if (aha->unit != AHA_TEMP_UNIT) { 29439225Sgibbs aha_softcs[aha->unit] = NULL; 29539225Sgibbs } 29639225Sgibbs free(aha, M_DEVBUF); 29739225Sgibbs} 29839225Sgibbs 29939225Sgibbs/* 30039225Sgibbs * Probe the adapter and verify that the card is an Adaptec. 30139225Sgibbs */ 30239225Sgibbsint 30339225Sgibbsaha_probe(struct aha_softc* aha) 30439225Sgibbs{ 30539225Sgibbs u_int status; 30639225Sgibbs u_int intstat; 30739225Sgibbs int error; 30839852Simp board_id_data_t board_id; 30939225Sgibbs 31039225Sgibbs /* 31139225Sgibbs * See if the three I/O ports look reasonable. 31239225Sgibbs * Touch the minimal number of registers in the 31339225Sgibbs * failure case. 31439225Sgibbs */ 31539225Sgibbs status = aha_inb(aha, STATUS_REG); 31639225Sgibbs if ((status == 0) 31739225Sgibbs || (status & (DIAG_ACTIVE|CMD_REG_BUSY| 31841047Sgibbs STATUS_REG_RSVD)) != 0) { 31941047Sgibbs PRVERB(("%s: status reg test failed %x\n", aha_name(aha), 32041047Sgibbs status)); 32139225Sgibbs return (ENXIO); 32239225Sgibbs } 32339225Sgibbs 32439225Sgibbs intstat = aha_inb(aha, INTSTAT_REG); 32539225Sgibbs if ((intstat & INTSTAT_REG_RSVD) != 0) { 32641047Sgibbs PRVERB(("%s: Failed Intstat Reg Test\n", aha_name(aha))); 32739225Sgibbs return (ENXIO); 32839225Sgibbs } 32939225Sgibbs 33039225Sgibbs /* 33141047Sgibbs * Looking good so far. Final test is to reset the 33241047Sgibbs * adapter and fetch the board ID and ensure we aren't 33341047Sgibbs * looking at a BusLogic. 33441047Sgibbs */ 33541047Sgibbs if ((error = ahareset(aha, /*hard_reset*/TRUE)) != 0) { 33641047Sgibbs if (bootverbose) 33741047Sgibbs printf("%s: Failed Reset\n", aha_name(aha)); 33841047Sgibbs return (ENXIO); 33941047Sgibbs } 34041047Sgibbs 34141047Sgibbs /* 34239852Simp * Get the board ID. We use this to see if we're dealing with 34339852Simp * a buslogic card or a aha card (or clone). 34439225Sgibbs */ 34541047Sgibbs error = aha_cmd(aha, AOP_INQUIRE_BOARD_ID, NULL, /*parmlen*/0, 34639852Simp (u_int8_t*)&board_id, sizeof(board_id), 34739852Simp DEFAULT_CMD_TIMEOUT); 34839852Simp if (error != 0) { 34939881Simp PRVERB(("%s: INQUIRE failed %x\n", aha_name(aha), error)); 35039225Sgibbs return (ENXIO); 35139225Sgibbs } 35239852Simp aha->fw_major = board_id.firmware_rev_major; 35339852Simp aha->fw_minor = board_id.firmware_rev_minor; 35439852Simp aha->boardid = board_id.board_type; 35539852Simp 35639225Sgibbs /* 35739852Simp * The Buslogic cards have an id of either 0x41 or 0x42. So 35839852Simp * if those come up in the probe, we test the geometry register 35939852Simp * of the board. Adaptec boards that are this old will not have 36039852Simp * this register, and return 0xff, while buslogic cards will return 36139852Simp * something different. 36239852Simp * 36341335Simp * It appears that for reasons unknow, for the for the 36441335Simp * aha-1542B cards, we need to wait a little bit before trying 36541335Simp * to read the geometry register. I picked 10ms since we have 36641335Simp * reports that a for loop to 1000 did the trick, and this 36741335Simp * errs on the side of conservatism. Besides, no one will 36841335Simp * notice a 10mS delay here, even the 1542B card users :-) 36941335Simp * 37046997Simp * Some compatible cards return 0 here. Some cards also 37146997Simp * seem to return 0x7f. 37241807Simp * 37341335Simp * XXX I'm not sure how this will impact other cloned cards 37441807Simp * 37541807Simp * This really should be replaced with the esetup command, since 37646997Simp * that appears to be more reliable. This becomes more and more 37746997Simp * true over time as we discover more cards that don't read the 37846997Simp * geometry register consistantly. 37939225Sgibbs */ 38039852Simp if (aha->boardid <= 0x42) { 38141335Simp /* Wait 10ms before reading */ 38241335Simp DELAY(10000); 38339852Simp status = aha_inb(aha, GEOMETRY_REG); 38446997Simp if (status != 0xff && status != 0x00 && status != 0x7f) { 38544434Simp PRVERB(("%s: Geometry Register test failed 0x%x\n", 38644434Simp aha_name(aha), status)); 38739852Simp return (ENXIO); 38841047Sgibbs } 38939751Simp } 39039852Simp 39139225Sgibbs return (0); 39239225Sgibbs} 39339225Sgibbs 39439225Sgibbs/* 39539225Sgibbs * Pull the boards setup information and record it in our softc. 39639225Sgibbs */ 39739225Sgibbsint 39839225Sgibbsaha_fetch_adapter_info(struct aha_softc *aha) 39939225Sgibbs{ 40039225Sgibbs setup_data_t setup_info; 40139225Sgibbs config_data_t config_data; 40239225Sgibbs u_int8_t length_param; 40339225Sgibbs int error; 40439751Simp struct aha_extbios extbios; 40539225Sgibbs 40639852Simp switch (aha->boardid) { 40739225Sgibbs case BOARD_1540_16HEAD_BIOS: 40841514Sarchie snprintf(aha->model, sizeof(aha->model), "1540 16 head BIOS"); 40939225Sgibbs break; 41039225Sgibbs case BOARD_1540_64HEAD_BIOS: 41141514Sarchie snprintf(aha->model, sizeof(aha->model), "1540 64 head BIOS"); 41239225Sgibbs break; 41339225Sgibbs case BOARD_1542: 41441514Sarchie snprintf(aha->model, sizeof(aha->model), "1540/1542 64 head BIOS"); 41539225Sgibbs break; 41639225Sgibbs case BOARD_1640: 41741514Sarchie snprintf(aha->model, sizeof(aha->model), "1640"); 41839225Sgibbs break; 41939225Sgibbs case BOARD_1740: 42041514Sarchie snprintf(aha->model, sizeof(aha->model), "1740A/1742A/1744"); 42139225Sgibbs break; 42239225Sgibbs case BOARD_1542C: 42341514Sarchie snprintf(aha->model, sizeof(aha->model), "1542C"); 42439225Sgibbs break; 42539225Sgibbs case BOARD_1542CF: 42641514Sarchie snprintf(aha->model, sizeof(aha->model), "1542CF"); 42739225Sgibbs break; 42839225Sgibbs case BOARD_1542CP: 42941514Sarchie snprintf(aha->model, sizeof(aha->model), "1542CP"); 43039225Sgibbs break; 43139225Sgibbs default: 43241514Sarchie snprintf(aha->model, sizeof(aha->model), "Unknown"); 43339225Sgibbs break; 43439225Sgibbs } 43539751Simp /* 43639751Simp * If we are a new type of 1542 board (anything newer than a 1542C) 43739751Simp * then disable the extended bios so that the 43839751Simp * mailbox interface is unlocked. 43939751Simp * This is also true for the 1542B Version 3.20. First Adaptec 44039751Simp * board that supports >1Gb drives. 44139751Simp * No need to check the extended bios flags as some of the 44239751Simp * extensions that cause us problems are not flagged in that byte. 44339751Simp */ 44439751Simp if (PROBABLY_NEW_BOARD(aha->boardid) || 44539751Simp (aha->boardid == 0x41 44639852Simp && aha->fw_major == 0x31 && 44739852Simp aha->fw_minor >= 0x34)) { 44841047Sgibbs error = aha_cmd(aha, AOP_RETURN_EXT_BIOS_INFO, NULL, 44939751Simp /*paramlen*/0, (u_char *)&extbios, sizeof(extbios), 45039751Simp DEFAULT_CMD_TIMEOUT); 45141047Sgibbs error = aha_cmd(aha, AOP_MBOX_IF_ENABLE, (u_int8_t *)&extbios, 45239751Simp /*paramlen*/2, NULL, 0, DEFAULT_CMD_TIMEOUT); 45339751Simp } 45439751Simp if (aha->boardid < 0x41) 45541335Simp printf("%s: Warning: aha-1542A won't likely work.\n", 45639751Simp aha_name(aha)); 45739751Simp 45841335Simp aha->max_sg = 17; /* Need >= 17 to do 64k I/O */ 45939225Sgibbs aha->diff_bus = 0; 46039225Sgibbs aha->extended_lun = 0; 46139751Simp aha->extended_trans = 0; 46240403Simp aha->max_ccbs = 16; 46339225Sgibbs /* Determine Sync/Wide/Disc settings */ 46439225Sgibbs length_param = sizeof(setup_info); 46541047Sgibbs error = aha_cmd(aha, AOP_INQUIRE_SETUP_INFO, &length_param, 46639225Sgibbs /*paramlen*/1, (u_int8_t*)&setup_info, 46739225Sgibbs sizeof(setup_info), DEFAULT_CMD_TIMEOUT); 46839225Sgibbs if (error != 0) { 46939225Sgibbs printf("%s: aha_fetch_adapter_info - Failed " 47039225Sgibbs "Get Setup Info\n", aha_name(aha)); 47139225Sgibbs return (error); 47239225Sgibbs } 47339225Sgibbs if (setup_info.initiate_sync != 0) { 47439225Sgibbs aha->sync_permitted = ALL_TARGETS; 47539225Sgibbs } 47639225Sgibbs aha->disc_permitted = ALL_TARGETS; 47739225Sgibbs 47839225Sgibbs /* We need as many mailboxes as we can have ccbs */ 47939225Sgibbs aha->num_boxes = aha->max_ccbs; 48039225Sgibbs 48139225Sgibbs /* Determine our SCSI ID */ 48239225Sgibbs 48341047Sgibbs error = aha_cmd(aha, AOP_INQUIRE_CONFIG, NULL, /*parmlen*/0, 48439225Sgibbs (u_int8_t*)&config_data, sizeof(config_data), 48539225Sgibbs DEFAULT_CMD_TIMEOUT); 48639225Sgibbs if (error != 0) { 48739225Sgibbs printf("%s: aha_fetch_adapter_info - Failed Get Config\n", 48839225Sgibbs aha_name(aha)); 48939225Sgibbs return (error); 49039225Sgibbs } 49139225Sgibbs aha->scsi_id = config_data.scsi_id; 49239225Sgibbs return (0); 49339225Sgibbs} 49439225Sgibbs 49539225Sgibbs/* 49639225Sgibbs * Start the board, ready for normal operation 49739225Sgibbs */ 49839225Sgibbsint 49939225Sgibbsaha_init(struct aha_softc* aha) 50039225Sgibbs{ 50139225Sgibbs /* Announce the Adapter */ 50239852Simp printf("%s: AHA-%s FW Rev. %c.%c (ID=%x) ", aha_name(aha), 50339852Simp aha->model, aha->fw_major, aha->fw_minor, aha->boardid); 50439225Sgibbs 50539225Sgibbs if (aha->diff_bus != 0) 50639225Sgibbs printf("Diff "); 50739225Sgibbs 50839225Sgibbs printf("SCSI Host Adapter, SCSI ID %d, %d CCBs\n", aha->scsi_id, 50939225Sgibbs aha->max_ccbs); 51039225Sgibbs 51139225Sgibbs /* 51239225Sgibbs * Create our DMA tags. These tags define the kinds of device 51339225Sgibbs * accessable memory allocations and memory mappings we will 51439225Sgibbs * need to perform during normal operation. 51539225Sgibbs * 51639225Sgibbs * Unless we need to further restrict the allocation, we rely 51739225Sgibbs * on the restrictions of the parent dmat, hence the common 51839225Sgibbs * use of MAXADDR and MAXSIZE. 51939225Sgibbs */ 52039225Sgibbs 52139225Sgibbs /* DMA tag for mapping buffers into device visible space. */ 52239225Sgibbs if (bus_dma_tag_create(aha->parent_dmat, /*alignment*/0, /*boundary*/0, 52339225Sgibbs /*lowaddr*/BUS_SPACE_MAXADDR, 52439225Sgibbs /*highaddr*/BUS_SPACE_MAXADDR, 52539225Sgibbs /*filter*/NULL, /*filterarg*/NULL, 52639225Sgibbs /*maxsize*/MAXBSIZE, /*nsegments*/AHA_NSEG, 52739225Sgibbs /*maxsegsz*/BUS_SPACE_MAXSIZE_24BIT, 52839225Sgibbs /*flags*/BUS_DMA_ALLOCNOW, 52939225Sgibbs &aha->buffer_dmat) != 0) { 53039225Sgibbs goto error_exit; 53139225Sgibbs } 53239225Sgibbs 53339225Sgibbs aha->init_level++; 53439225Sgibbs /* DMA tag for our mailboxes */ 53539225Sgibbs if (bus_dma_tag_create(aha->parent_dmat, /*alignment*/0, /*boundary*/0, 53639225Sgibbs /*lowaddr*/BUS_SPACE_MAXADDR, 53739225Sgibbs /*highaddr*/BUS_SPACE_MAXADDR, 53839225Sgibbs /*filter*/NULL, /*filterarg*/NULL, 53939225Sgibbs aha->num_boxes * (sizeof(aha_mbox_in_t) 54039225Sgibbs + sizeof(aha_mbox_out_t)), 54139225Sgibbs /*nsegments*/1, 54239225Sgibbs /*maxsegsz*/BUS_SPACE_MAXSIZE_24BIT, 54339225Sgibbs /*flags*/0, &aha->mailbox_dmat) != 0) { 54439225Sgibbs goto error_exit; 54539225Sgibbs } 54639225Sgibbs 54739225Sgibbs aha->init_level++; 54839225Sgibbs 54939225Sgibbs /* Allocation for our mailboxes */ 55039225Sgibbs if (bus_dmamem_alloc(aha->mailbox_dmat, (void **)&aha->out_boxes, 55139225Sgibbs BUS_DMA_NOWAIT, &aha->mailbox_dmamap) != 0) { 55239225Sgibbs goto error_exit; 55339225Sgibbs } 55439225Sgibbs 55539225Sgibbs aha->init_level++; 55639225Sgibbs 55739225Sgibbs /* And permanently map them */ 55839225Sgibbs bus_dmamap_load(aha->mailbox_dmat, aha->mailbox_dmamap, 55939225Sgibbs aha->out_boxes, 56039225Sgibbs aha->num_boxes * (sizeof(aha_mbox_in_t) 56139225Sgibbs + sizeof(aha_mbox_out_t)), 56239225Sgibbs ahamapmboxes, aha, /*flags*/0); 56339225Sgibbs 56439225Sgibbs aha->init_level++; 56539225Sgibbs 56639225Sgibbs aha->in_boxes = (aha_mbox_in_t *)&aha->out_boxes[aha->num_boxes]; 56739225Sgibbs 56839225Sgibbs ahainitmboxes(aha); 56939225Sgibbs 57039225Sgibbs /* DMA tag for our ccb structures */ 57139225Sgibbs if (bus_dma_tag_create(aha->parent_dmat, /*alignment*/0, /*boundary*/0, 57239225Sgibbs /*lowaddr*/BUS_SPACE_MAXADDR, 57339225Sgibbs /*highaddr*/BUS_SPACE_MAXADDR, 57439225Sgibbs /*filter*/NULL, /*filterarg*/NULL, 57539225Sgibbs aha->max_ccbs * sizeof(struct aha_ccb), 57639225Sgibbs /*nsegments*/1, 57739225Sgibbs /*maxsegsz*/BUS_SPACE_MAXSIZE_24BIT, 57839225Sgibbs /*flags*/0, &aha->ccb_dmat) != 0) { 57939225Sgibbs goto error_exit; 58039225Sgibbs } 58139225Sgibbs 58239225Sgibbs aha->init_level++; 58339225Sgibbs 58439225Sgibbs /* Allocation for our ccbs */ 58539225Sgibbs if (bus_dmamem_alloc(aha->ccb_dmat, (void **)&aha->aha_ccb_array, 58639225Sgibbs BUS_DMA_NOWAIT, &aha->ccb_dmamap) != 0) { 58739225Sgibbs goto error_exit; 58839225Sgibbs } 58939225Sgibbs 59039225Sgibbs aha->init_level++; 59139225Sgibbs 59239225Sgibbs /* And permanently map them */ 59339225Sgibbs bus_dmamap_load(aha->ccb_dmat, aha->ccb_dmamap, 59439225Sgibbs aha->aha_ccb_array, 59539225Sgibbs aha->max_ccbs * sizeof(struct aha_ccb), 59639225Sgibbs ahamapccbs, aha, /*flags*/0); 59739225Sgibbs 59839225Sgibbs aha->init_level++; 59939225Sgibbs 60039225Sgibbs /* DMA tag for our S/G structures. We allocate in page sized chunks */ 60139225Sgibbs if (bus_dma_tag_create(aha->parent_dmat, /*alignment*/0, /*boundary*/0, 60239225Sgibbs /*lowaddr*/BUS_SPACE_MAXADDR, 60339225Sgibbs /*highaddr*/BUS_SPACE_MAXADDR, 60439225Sgibbs /*filter*/NULL, /*filterarg*/NULL, 60539225Sgibbs PAGE_SIZE, /*nsegments*/1, 60639225Sgibbs /*maxsegsz*/BUS_SPACE_MAXSIZE_24BIT, 60739225Sgibbs /*flags*/0, &aha->sg_dmat) != 0) { 60839225Sgibbs goto error_exit; 60939225Sgibbs } 61039225Sgibbs 61139225Sgibbs aha->init_level++; 61239225Sgibbs 61339225Sgibbs /* Perform initial CCB allocation */ 61439225Sgibbs bzero(aha->aha_ccb_array, aha->max_ccbs * sizeof(struct aha_ccb)); 61539225Sgibbs ahaallocccbs(aha); 61639225Sgibbs 61739225Sgibbs if (aha->num_ccbs == 0) { 61839324Sgibbs printf("%s: aha_init - Unable to allocate initial ccbs\n", 61939324Sgibbs aha_name(aha)); 62039225Sgibbs goto error_exit; 62139225Sgibbs } 62239225Sgibbs 62339225Sgibbs /* 62439225Sgibbs * Note that we are going and return (to probe) 62539225Sgibbs */ 62639225Sgibbs return 0; 62739225Sgibbs 62839225Sgibbserror_exit: 62939225Sgibbs 63039225Sgibbs return (ENXIO); 63139225Sgibbs} 63239225Sgibbs 63339225Sgibbsint 63439225Sgibbsaha_attach(struct aha_softc *aha) 63539225Sgibbs{ 63639225Sgibbs int tagged_dev_openings; 63739225Sgibbs struct cam_devq *devq; 63839225Sgibbs 63939225Sgibbs /* 64041335Simp * We don't do tagged queueing, since the aha cards don't 64141335Simp * support it. 64239225Sgibbs */ 64339225Sgibbs tagged_dev_openings = 0; 64439225Sgibbs 64539225Sgibbs /* 64639225Sgibbs * Create the device queue for our SIM. 64739225Sgibbs */ 64839225Sgibbs devq = cam_simq_alloc(aha->max_ccbs - 1); 64939225Sgibbs if (devq == NULL) 65039225Sgibbs return (ENOMEM); 65139225Sgibbs 65239225Sgibbs /* 65339225Sgibbs * Construct our SIM entry 65439225Sgibbs */ 65539225Sgibbs aha->sim = cam_sim_alloc(ahaaction, ahapoll, "aha", aha, aha->unit, 65639225Sgibbs 2, tagged_dev_openings, devq); 65739225Sgibbs if (aha->sim == NULL) { 65839225Sgibbs cam_simq_free(devq); 65939225Sgibbs return (ENOMEM); 66039225Sgibbs } 66139225Sgibbs 66239225Sgibbs if (xpt_bus_register(aha->sim, 0) != CAM_SUCCESS) { 66339225Sgibbs cam_sim_free(aha->sim, /*free_devq*/TRUE); 66439225Sgibbs return (ENXIO); 66539225Sgibbs } 66639225Sgibbs 66739225Sgibbs if (xpt_create_path(&aha->path, /*periph*/NULL, 66839225Sgibbs cam_sim_path(aha->sim), CAM_TARGET_WILDCARD, 66939225Sgibbs CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 67039225Sgibbs xpt_bus_deregister(cam_sim_path(aha->sim)); 67139225Sgibbs cam_sim_free(aha->sim, /*free_devq*/TRUE); 67239225Sgibbs return (ENXIO); 67339225Sgibbs } 67439225Sgibbs 67539225Sgibbs return (0); 67639225Sgibbs} 67739225Sgibbs 67839225Sgibbschar * 67939225Sgibbsaha_name(struct aha_softc *aha) 68039225Sgibbs{ 68139225Sgibbs static char name[10]; 68239225Sgibbs 68341514Sarchie snprintf(name, sizeof(name), "aha%d", aha->unit); 68439225Sgibbs return (name); 68539225Sgibbs} 68639225Sgibbs 68739225Sgibbsint 68839225Sgibbsaha_check_probed_iop(u_int ioport) 68939225Sgibbs{ 69039225Sgibbs u_int i; 69139225Sgibbs 69239225Sgibbs for (i=0; i < AHA_NUM_ISAPORTS; i++) { 69339225Sgibbs if (aha_isa_ports[i].addr == ioport) { 69439225Sgibbs if (aha_isa_ports[i].probed != 0) 69539225Sgibbs return (1); 69639225Sgibbs else { 69739225Sgibbs return (0); 69839225Sgibbs } 69939225Sgibbs } 70039225Sgibbs } 70139225Sgibbs return (1); 70239225Sgibbs} 70339225Sgibbs 70439225Sgibbsvoid 70539225Sgibbsaha_mark_probed_bio(isa_compat_io_t port) 70639225Sgibbs{ 70739225Sgibbs if (port < BIO_DISABLED) 70841047Sgibbs aha_mark_probed_iop(aha_board_ports[port]); 70939225Sgibbs} 71039225Sgibbs 71139225Sgibbsvoid 71239225Sgibbsaha_mark_probed_iop(u_int ioport) 71339225Sgibbs{ 71439225Sgibbs u_int i; 71539225Sgibbs 71639225Sgibbs for (i = 0; i < AHA_NUM_ISAPORTS; i++) { 71739225Sgibbs if (ioport == aha_isa_ports[i].addr) { 71839225Sgibbs aha_isa_ports[i].probed = 1; 71939225Sgibbs break; 72039225Sgibbs } 72139225Sgibbs } 72239225Sgibbs} 72339225Sgibbs 72441047Sgibbsvoid 72541047Sgibbsaha_find_probe_range(int ioport, int *port_index, int *max_port_index) 72641047Sgibbs{ 72741047Sgibbs if (ioport > 0) { 72841047Sgibbs int i; 72941047Sgibbs 73041047Sgibbs for (i = 0;i < AHA_NUM_ISAPORTS; i++) 73141047Sgibbs if (ioport <= aha_isa_ports[i].addr) 73241047Sgibbs break; 73341047Sgibbs if ((i >= AHA_NUM_ISAPORTS) 73441047Sgibbs || (ioport != aha_isa_ports[i].addr)) { 73542013Sgibbs printf("\n" 73642013Sgibbs"aha_isa_probe: Invalid baseport of 0x%x specified.\n" 73742013Sgibbs"aha_isa_probe: Nearest valid baseport is 0x%x.\n" 73842013Sgibbs"aha_isa_probe: Failing probe.\n", 73941047Sgibbs ioport, 74041047Sgibbs (i < AHA_NUM_ISAPORTS) 74141047Sgibbs ? aha_isa_ports[i].addr 74241047Sgibbs : aha_isa_ports[AHA_NUM_ISAPORTS - 1].addr); 74341047Sgibbs *port_index = *max_port_index = -1; 74441047Sgibbs return; 74541047Sgibbs } 74641047Sgibbs *port_index = *max_port_index = aha_isa_ports[i].bio; 74741047Sgibbs } else { 74841047Sgibbs *port_index = 0; 74941047Sgibbs *max_port_index = AHA_NUM_ISAPORTS - 1; 75041047Sgibbs } 75141047Sgibbs} 75241047Sgibbs 75341047Sgibbsint 75441047Sgibbsaha_iop_from_bio(isa_compat_io_t bio_index) 75541047Sgibbs{ 75641047Sgibbs if (bio_index >= 0 && bio_index < AHA_NUM_ISAPORTS) 75741047Sgibbs return (aha_board_ports[bio_index]); 75841047Sgibbs return (-1); 75941047Sgibbs} 76041047Sgibbs 76139225Sgibbsstatic void 76239225Sgibbsahaallocccbs(struct aha_softc *aha) 76339225Sgibbs{ 76439225Sgibbs struct aha_ccb *next_ccb; 76539225Sgibbs struct sg_map_node *sg_map; 76639225Sgibbs bus_addr_t physaddr; 76739225Sgibbs aha_sg_t *segs; 76839225Sgibbs int newcount; 76939225Sgibbs int i; 77039225Sgibbs 77139225Sgibbs next_ccb = &aha->aha_ccb_array[aha->num_ccbs]; 77239225Sgibbs 77339225Sgibbs sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT); 77439225Sgibbs 77539225Sgibbs if (sg_map == NULL) 77639225Sgibbs return; 77739225Sgibbs 77839225Sgibbs /* Allocate S/G space for the next batch of CCBS */ 77939225Sgibbs if (bus_dmamem_alloc(aha->sg_dmat, (void **)&sg_map->sg_vaddr, 78039225Sgibbs BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) { 78139225Sgibbs free(sg_map, M_DEVBUF); 78239225Sgibbs return; 78339225Sgibbs } 78439225Sgibbs 78539225Sgibbs SLIST_INSERT_HEAD(&aha->sg_maps, sg_map, links); 78639225Sgibbs 78739225Sgibbs bus_dmamap_load(aha->sg_dmat, sg_map->sg_dmamap, sg_map->sg_vaddr, 78839225Sgibbs PAGE_SIZE, ahamapsgs, aha, /*flags*/0); 78939225Sgibbs 79039225Sgibbs segs = sg_map->sg_vaddr; 79139225Sgibbs physaddr = sg_map->sg_physaddr; 79239225Sgibbs 79339225Sgibbs newcount = (PAGE_SIZE / (AHA_NSEG * sizeof(aha_sg_t))); 79439225Sgibbs for (i = 0; aha->num_ccbs < aha->max_ccbs && i < newcount; i++) { 79539225Sgibbs int error; 79639225Sgibbs 79739225Sgibbs next_ccb->sg_list = segs; 79839225Sgibbs next_ccb->sg_list_phys = physaddr; 79941047Sgibbs next_ccb->flags = ACCB_FREE; 80039225Sgibbs error = bus_dmamap_create(aha->buffer_dmat, /*flags*/0, 80139225Sgibbs &next_ccb->dmamap); 80239225Sgibbs if (error != 0) 80339225Sgibbs break; 80439225Sgibbs SLIST_INSERT_HEAD(&aha->free_aha_ccbs, next_ccb, links); 80539225Sgibbs segs += AHA_NSEG; 80639225Sgibbs physaddr += (AHA_NSEG * sizeof(aha_sg_t)); 80739225Sgibbs next_ccb++; 80839225Sgibbs aha->num_ccbs++; 80939225Sgibbs } 81039225Sgibbs 81139225Sgibbs /* Reserve a CCB for error recovery */ 81241047Sgibbs if (aha->recovery_accb == NULL) { 81341047Sgibbs aha->recovery_accb = SLIST_FIRST(&aha->free_aha_ccbs); 81439225Sgibbs SLIST_REMOVE_HEAD(&aha->free_aha_ccbs, links); 81539225Sgibbs } 81639225Sgibbs} 81739225Sgibbs 81839225Sgibbsstatic __inline void 81941047Sgibbsahafreeccb(struct aha_softc *aha, struct aha_ccb *accb) 82039225Sgibbs{ 82139225Sgibbs int s; 82239225Sgibbs 82339225Sgibbs s = splcam(); 82441047Sgibbs if ((accb->flags & ACCB_ACTIVE) != 0) 82541047Sgibbs LIST_REMOVE(&accb->ccb->ccb_h, sim_links.le); 82639225Sgibbs if (aha->resource_shortage != 0 82741047Sgibbs && (accb->ccb->ccb_h.status & CAM_RELEASE_SIMQ) == 0) { 82841047Sgibbs accb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 82939225Sgibbs aha->resource_shortage = FALSE; 83039225Sgibbs } 83141047Sgibbs accb->flags = ACCB_FREE; 83241047Sgibbs SLIST_INSERT_HEAD(&aha->free_aha_ccbs, accb, links); 83341047Sgibbs aha->active_ccbs--; 83439225Sgibbs splx(s); 83539225Sgibbs} 83639225Sgibbs 83739225Sgibbsstatic struct aha_ccb* 83839225Sgibbsahagetccb(struct aha_softc *aha) 83939225Sgibbs{ 84041047Sgibbs struct aha_ccb* accb; 84139225Sgibbs int s; 84239225Sgibbs 84339225Sgibbs s = splcam(); 84441047Sgibbs if ((accb = SLIST_FIRST(&aha->free_aha_ccbs)) != NULL) { 84539225Sgibbs SLIST_REMOVE_HEAD(&aha->free_aha_ccbs, links); 84641047Sgibbs aha->active_ccbs++; 84739225Sgibbs } else if (aha->num_ccbs < aha->max_ccbs) { 84839225Sgibbs ahaallocccbs(aha); 84941047Sgibbs accb = SLIST_FIRST(&aha->free_aha_ccbs); 85041047Sgibbs if (accb == NULL) 85141047Sgibbs printf("%s: Can't malloc ACCB\n", aha_name(aha)); 85241047Sgibbs else { 85339225Sgibbs SLIST_REMOVE_HEAD(&aha->free_aha_ccbs, links); 85441047Sgibbs aha->active_ccbs++; 85541047Sgibbs } 85639225Sgibbs } 85739225Sgibbs splx(s); 85839225Sgibbs 85941047Sgibbs return (accb); 86039225Sgibbs} 86139225Sgibbs 86239225Sgibbsstatic void 86339225Sgibbsahaaction(struct cam_sim *sim, union ccb *ccb) 86439225Sgibbs{ 86539225Sgibbs struct aha_softc *aha; 86639225Sgibbs 86739225Sgibbs CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("ahaaction\n")); 86839225Sgibbs 86939225Sgibbs aha = (struct aha_softc *)cam_sim_softc(sim); 87039225Sgibbs 87139225Sgibbs switch (ccb->ccb_h.func_code) { 87239225Sgibbs /* Common cases first */ 87339225Sgibbs case XPT_SCSI_IO: /* Execute the requested I/O operation */ 87439225Sgibbs case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ 87539225Sgibbs { 87641047Sgibbs struct aha_ccb *accb; 87739225Sgibbs struct aha_hccb *hccb; 87839225Sgibbs 87939225Sgibbs /* 88041047Sgibbs * get a accb to use. 88139225Sgibbs */ 88241047Sgibbs if ((accb = ahagetccb(aha)) == NULL) { 88339225Sgibbs int s; 88439225Sgibbs 88539225Sgibbs s = splcam(); 88639225Sgibbs aha->resource_shortage = TRUE; 88739225Sgibbs splx(s); 88839225Sgibbs xpt_freeze_simq(aha->sim, /*count*/1); 88939225Sgibbs ccb->ccb_h.status = CAM_REQUEUE_REQ; 89039225Sgibbs xpt_done(ccb); 89139225Sgibbs return; 89239225Sgibbs } 89339225Sgibbs 89441047Sgibbs hccb = &accb->hccb; 89539225Sgibbs 89639225Sgibbs /* 89741047Sgibbs * So we can find the ACCB when an abort is requested 89839225Sgibbs */ 89941047Sgibbs accb->ccb = ccb; 90041047Sgibbs ccb->ccb_h.ccb_accb_ptr = accb; 90139225Sgibbs ccb->ccb_h.ccb_aha_ptr = aha; 90239225Sgibbs 90339225Sgibbs /* 90441047Sgibbs * Put all the arguments for the xfer in the accb 90539225Sgibbs */ 90639225Sgibbs hccb->target = ccb->ccb_h.target_id; 90739225Sgibbs hccb->lun = ccb->ccb_h.target_lun; 90839225Sgibbs hccb->ahastat = 0; 90939225Sgibbs hccb->sdstat = 0; 91039225Sgibbs 91139225Sgibbs if (ccb->ccb_h.func_code == XPT_SCSI_IO) { 91239225Sgibbs struct ccb_scsiio *csio; 91339225Sgibbs struct ccb_hdr *ccbh; 91439225Sgibbs 91539225Sgibbs csio = &ccb->csio; 91639225Sgibbs ccbh = &csio->ccb_h; 91742887Simp hccb->opcode = aha->ccb_ccb_opcode; 91839225Sgibbs hccb->datain = (ccb->ccb_h.flags & CAM_DIR_IN) != 0; 91939225Sgibbs hccb->dataout = (ccb->ccb_h.flags & CAM_DIR_OUT) != 0; 92039225Sgibbs hccb->cmd_len = csio->cdb_len; 92139225Sgibbs if (hccb->cmd_len > sizeof(hccb->scsi_cdb)) { 92239225Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 92341047Sgibbs ahafreeccb(aha, accb); 92439225Sgibbs xpt_done(ccb); 92539225Sgibbs return; 92639225Sgibbs } 92739225Sgibbs hccb->sense_len = csio->sense_len; 92839225Sgibbs if ((ccbh->flags & CAM_CDB_POINTER) != 0) { 92939225Sgibbs if ((ccbh->flags & CAM_CDB_PHYS) == 0) { 93039225Sgibbs bcopy(csio->cdb_io.cdb_ptr, 93139225Sgibbs hccb->scsi_cdb, hccb->cmd_len); 93239225Sgibbs } else { 93339225Sgibbs /* I guess I could map it in... */ 93439225Sgibbs ccbh->status = CAM_REQ_INVALID; 93541047Sgibbs ahafreeccb(aha, accb); 93639225Sgibbs xpt_done(ccb); 93739225Sgibbs return; 93839225Sgibbs } 93939225Sgibbs } else { 94039225Sgibbs bcopy(csio->cdb_io.cdb_bytes, 94139225Sgibbs hccb->scsi_cdb, hccb->cmd_len); 94239225Sgibbs } 94339225Sgibbs /* 94439225Sgibbs * If we have any data to send with this command, 94539225Sgibbs * map it into bus space. 94639225Sgibbs */ 94739225Sgibbs /* Only use S/G if there is a transfer */ 94839225Sgibbs if ((ccbh->flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 94939225Sgibbs if ((ccbh->flags & CAM_SCATTER_VALID) == 0) { 95039225Sgibbs /* 95139225Sgibbs * We've been given a pointer 95239225Sgibbs * to a single buffer. 95339225Sgibbs */ 95439225Sgibbs if ((ccbh->flags & CAM_DATA_PHYS)==0) { 95539225Sgibbs int s; 95639225Sgibbs int error; 95739225Sgibbs 95839225Sgibbs s = splsoftvm(); 95939225Sgibbs error = bus_dmamap_load( 96039225Sgibbs aha->buffer_dmat, 96141047Sgibbs accb->dmamap, 96239225Sgibbs csio->data_ptr, 96339225Sgibbs csio->dxfer_len, 96439225Sgibbs ahaexecuteccb, 96541047Sgibbs accb, 96639225Sgibbs /*flags*/0); 96739225Sgibbs if (error == EINPROGRESS) { 96839225Sgibbs /* 96939225Sgibbs * So as to maintain 97039225Sgibbs * ordering, freeze the 97139225Sgibbs * controller queue 97239225Sgibbs * until our mapping is 97339225Sgibbs * returned. 97439225Sgibbs */ 97539225Sgibbs xpt_freeze_simq(aha->sim, 97639225Sgibbs 1); 97739225Sgibbs csio->ccb_h.status |= 97839225Sgibbs CAM_RELEASE_SIMQ; 97939225Sgibbs } 98039225Sgibbs splx(s); 98139225Sgibbs } else { 98239225Sgibbs struct bus_dma_segment seg; 98339225Sgibbs 98439225Sgibbs /* Pointer to physical buffer */ 98539225Sgibbs seg.ds_addr = 98639225Sgibbs (bus_addr_t)csio->data_ptr; 98739225Sgibbs seg.ds_len = csio->dxfer_len; 98841047Sgibbs ahaexecuteccb(accb, &seg, 1, 0); 98939225Sgibbs } 99039225Sgibbs } else { 99139225Sgibbs struct bus_dma_segment *segs; 99239225Sgibbs 99339225Sgibbs if ((ccbh->flags & CAM_DATA_PHYS) != 0) 99439225Sgibbs panic("ahaaction - Physical " 99539225Sgibbs "segment pointers " 99639225Sgibbs "unsupported"); 99739225Sgibbs 99839225Sgibbs if ((ccbh->flags&CAM_SG_LIST_PHYS)==0) 99939225Sgibbs panic("ahaaction - Virtual " 100039225Sgibbs "segment addresses " 100139225Sgibbs "unsupported"); 100239225Sgibbs 100339225Sgibbs /* Just use the segments provided */ 100439225Sgibbs segs = (struct bus_dma_segment *) 100539225Sgibbs csio->data_ptr; 100641047Sgibbs ahaexecuteccb(accb, segs, 100739225Sgibbs csio->sglist_cnt, 0); 100839225Sgibbs } 100939225Sgibbs } else { 101041047Sgibbs ahaexecuteccb(accb, NULL, 0, 0); 101139225Sgibbs } 101239225Sgibbs } else { 101339225Sgibbs hccb->opcode = INITIATOR_BUS_DEV_RESET; 101439225Sgibbs /* No data transfer */ 101539225Sgibbs hccb->datain = TRUE; 101639225Sgibbs hccb->dataout = TRUE; 101739225Sgibbs hccb->cmd_len = 0; 101839225Sgibbs hccb->sense_len = 0; 101941047Sgibbs ahaexecuteccb(accb, NULL, 0, 0); 102039225Sgibbs } 102139225Sgibbs break; 102239225Sgibbs } 102339225Sgibbs case XPT_EN_LUN: /* Enable LUN as a target */ 102439225Sgibbs case XPT_TARGET_IO: /* Execute target I/O request */ 102539225Sgibbs case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */ 102639225Sgibbs case XPT_CONT_TARGET_IO: /* Continue Host Target I/O Connection*/ 102739225Sgibbs case XPT_ABORT: /* Abort the specified CCB */ 102839225Sgibbs /* XXX Implement */ 102939225Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 103039225Sgibbs xpt_done(ccb); 103139225Sgibbs break; 103239225Sgibbs case XPT_SET_TRAN_SETTINGS: 103339225Sgibbs { 103439225Sgibbs /* XXX Implement */ 103546581Sken ccb->ccb_h.status = CAM_PROVIDE_FAIL; 103639225Sgibbs xpt_done(ccb); 103739225Sgibbs break; 103839225Sgibbs } 103939225Sgibbs case XPT_GET_TRAN_SETTINGS: 104039225Sgibbs /* Get default/user set transfer settings for the target */ 104139225Sgibbs { 104239225Sgibbs struct ccb_trans_settings *cts; 104339225Sgibbs u_int target_mask; 104439225Sgibbs 104539225Sgibbs cts = &ccb->cts; 104639225Sgibbs target_mask = 0x01 << ccb->ccb_h.target_id; 104739225Sgibbs if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) { 104839225Sgibbs cts->flags = 0; 104939225Sgibbs if ((aha->disc_permitted & target_mask) != 0) 105039225Sgibbs cts->flags |= CCB_TRANS_DISC_ENB; 105139225Sgibbs cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 105239225Sgibbs if ((aha->sync_permitted & target_mask) != 0) 105339225Sgibbs cts->sync_period = 50; 105439225Sgibbs else 105539225Sgibbs cts->sync_period = 0; 105639225Sgibbs 105739225Sgibbs if (cts->sync_period != 0) 105839225Sgibbs cts->sync_offset = 15; 105939225Sgibbs 106039225Sgibbs cts->valid = CCB_TRANS_SYNC_RATE_VALID 106139225Sgibbs | CCB_TRANS_SYNC_OFFSET_VALID 106239225Sgibbs | CCB_TRANS_BUS_WIDTH_VALID 106339225Sgibbs | CCB_TRANS_DISC_VALID 106439225Sgibbs | CCB_TRANS_TQ_VALID; 106539225Sgibbs } else { 106639225Sgibbs ahafetchtransinfo(aha, cts); 106739225Sgibbs } 106839225Sgibbs 106939225Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 107039225Sgibbs xpt_done(ccb); 107139225Sgibbs break; 107239225Sgibbs } 107339225Sgibbs case XPT_CALC_GEOMETRY: 107439225Sgibbs { 107539225Sgibbs struct ccb_calc_geometry *ccg; 107639225Sgibbs u_int32_t size_mb; 107739225Sgibbs u_int32_t secs_per_cylinder; 107839225Sgibbs 107939225Sgibbs ccg = &ccb->ccg; 108039225Sgibbs size_mb = ccg->volume_size 108139225Sgibbs / ((1024L * 1024L) / ccg->block_size); 108239225Sgibbs 108339225Sgibbs if (size_mb >= 1024 && (aha->extended_trans != 0)) { 108439225Sgibbs if (size_mb >= 2048) { 108539225Sgibbs ccg->heads = 255; 108639225Sgibbs ccg->secs_per_track = 63; 108739225Sgibbs } else { 108839225Sgibbs ccg->heads = 128; 108939225Sgibbs ccg->secs_per_track = 32; 109039225Sgibbs } 109139225Sgibbs } else { 109239225Sgibbs ccg->heads = 64; 109339225Sgibbs ccg->secs_per_track = 32; 109439225Sgibbs } 109539225Sgibbs secs_per_cylinder = ccg->heads * ccg->secs_per_track; 109639225Sgibbs ccg->cylinders = ccg->volume_size / secs_per_cylinder; 109739225Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 109839225Sgibbs xpt_done(ccb); 109939225Sgibbs break; 110039225Sgibbs } 110139225Sgibbs case XPT_RESET_BUS: /* Reset the specified SCSI bus */ 110239225Sgibbs { 110339225Sgibbs ahareset(aha, /*hardreset*/TRUE); 110439225Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 110539225Sgibbs xpt_done(ccb); 110639225Sgibbs break; 110739225Sgibbs } 110839225Sgibbs case XPT_TERM_IO: /* Terminate the I/O process */ 110939225Sgibbs /* XXX Implement */ 111039225Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 111139225Sgibbs xpt_done(ccb); 111239225Sgibbs break; 111339225Sgibbs case XPT_PATH_INQ: /* Path routing inquiry */ 111439225Sgibbs { 111539225Sgibbs struct ccb_pathinq *cpi = &ccb->cpi; 111639225Sgibbs 111739225Sgibbs cpi->version_num = 1; /* XXX??? */ 111839225Sgibbs cpi->hba_inquiry = PI_SDTR_ABLE; 111939225Sgibbs cpi->target_sprt = 0; 112039225Sgibbs cpi->hba_misc = 0; 112139225Sgibbs cpi->hba_eng_cnt = 0; 112239852Simp cpi->max_target = 7; 112339225Sgibbs cpi->max_lun = 7; 112439225Sgibbs cpi->initiator_id = aha->scsi_id; 112539225Sgibbs cpi->bus_id = cam_sim_bus(sim); 112646581Sken cpi->base_transfer_speed = 3300; 112739225Sgibbs strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 112839225Sgibbs strncpy(cpi->hba_vid, "Adaptec", HBA_IDLEN); 112939225Sgibbs strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 113039225Sgibbs cpi->unit_number = cam_sim_unit(sim); 113139225Sgibbs cpi->ccb_h.status = CAM_REQ_CMP; 113239225Sgibbs xpt_done(ccb); 113339225Sgibbs break; 113439225Sgibbs } 113539225Sgibbs default: 113639225Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 113739225Sgibbs xpt_done(ccb); 113839225Sgibbs break; 113939225Sgibbs } 114039225Sgibbs} 114139225Sgibbs 114239225Sgibbsstatic void 114339225Sgibbsahaexecuteccb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 114439225Sgibbs{ 114541047Sgibbs struct aha_ccb *accb; 114639225Sgibbs union ccb *ccb; 114739225Sgibbs struct aha_softc *aha; 114840419Sgibbs int s; 114939225Sgibbs u_int32_t paddr; 115039225Sgibbs 115141047Sgibbs accb = (struct aha_ccb *)arg; 115241047Sgibbs ccb = accb->ccb; 115339225Sgibbs aha = (struct aha_softc *)ccb->ccb_h.ccb_aha_ptr; 115439225Sgibbs 115539225Sgibbs if (error != 0) { 115639225Sgibbs if (error != EFBIG) 115739225Sgibbs printf("%s: Unexepected error 0x%x returned from " 115839324Sgibbs "bus_dmamap_load\n", aha_name(aha), error); 115939225Sgibbs if (ccb->ccb_h.status == CAM_REQ_INPROG) { 116039225Sgibbs xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 116139225Sgibbs ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN; 116239225Sgibbs } 116341047Sgibbs ahafreeccb(aha, accb); 116439225Sgibbs xpt_done(ccb); 116539225Sgibbs return; 116639225Sgibbs } 116739225Sgibbs 116839225Sgibbs if (nseg != 0) { 116939225Sgibbs aha_sg_t *sg; 117039225Sgibbs bus_dma_segment_t *end_seg; 117139225Sgibbs bus_dmasync_op_t op; 117239225Sgibbs 117339225Sgibbs end_seg = dm_segs + nseg; 117439225Sgibbs 117539225Sgibbs /* Copy the segments into our SG list */ 117641047Sgibbs sg = accb->sg_list; 117739225Sgibbs while (dm_segs < end_seg) { 117839225Sgibbs ahautoa24(dm_segs->ds_len, sg->len); 117939225Sgibbs ahautoa24(dm_segs->ds_addr, sg->addr); 118039225Sgibbs sg++; 118139225Sgibbs dm_segs++; 118239225Sgibbs } 118339225Sgibbs 118439225Sgibbs if (nseg > 1) { 118542887Simp accb->hccb.opcode = aha->ccb_sg_opcode; 118639225Sgibbs ahautoa24((sizeof(aha_sg_t) * nseg), 118741047Sgibbs accb->hccb.data_len); 118841047Sgibbs ahautoa24(accb->sg_list_phys, accb->hccb.data_addr); 118939225Sgibbs } else { 119041047Sgibbs bcopy(accb->sg_list->len, accb->hccb.data_len, 3); 119141047Sgibbs bcopy(accb->sg_list->addr, accb->hccb.data_addr, 3); 119239225Sgibbs } 119339225Sgibbs 119439225Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 119539225Sgibbs op = BUS_DMASYNC_PREREAD; 119639225Sgibbs else 119739225Sgibbs op = BUS_DMASYNC_PREWRITE; 119839225Sgibbs 119941047Sgibbs bus_dmamap_sync(aha->buffer_dmat, accb->dmamap, op); 120039225Sgibbs 120139225Sgibbs } else { 120241709Sgibbs accb->hccb.opcode = INITIATOR_CCB; 120341047Sgibbs ahautoa24(0, accb->hccb.data_len); 120441047Sgibbs ahautoa24(0, accb->hccb.data_addr); 120539225Sgibbs } 120639225Sgibbs 120739225Sgibbs s = splcam(); 120839225Sgibbs 120939225Sgibbs /* 121039225Sgibbs * Last time we need to check if this CCB needs to 121139225Sgibbs * be aborted. 121239225Sgibbs */ 121339225Sgibbs if (ccb->ccb_h.status != CAM_REQ_INPROG) { 121439225Sgibbs if (nseg != 0) 121541047Sgibbs bus_dmamap_unload(aha->buffer_dmat, accb->dmamap); 121641047Sgibbs ahafreeccb(aha, accb); 121739225Sgibbs xpt_done(ccb); 121839225Sgibbs splx(s); 121939225Sgibbs return; 122039225Sgibbs } 122139225Sgibbs 122241047Sgibbs accb->flags = ACCB_ACTIVE; 122339225Sgibbs ccb->ccb_h.status |= CAM_SIM_QUEUED; 122439225Sgibbs LIST_INSERT_HEAD(&aha->pending_ccbs, &ccb->ccb_h, sim_links.le); 122539225Sgibbs 122639225Sgibbs ccb->ccb_h.timeout_ch = 122741047Sgibbs timeout(ahatimeout, (caddr_t)accb, 122839225Sgibbs (ccb->ccb_h.timeout * hz) / 1000); 122939225Sgibbs 123039225Sgibbs /* Tell the adapter about this command */ 123141047Sgibbs if (aha->cur_outbox->action_code != AMBO_FREE) { 123241047Sgibbs /* 123341047Sgibbs * We should never encounter a busy mailbox. 123441047Sgibbs * If we do, warn the user, and treat it as 123541047Sgibbs * a resource shortage. If the controller is 123641047Sgibbs * hung, one of the pending transactions will 123741047Sgibbs * timeout causing us to start recovery operations. 123841047Sgibbs */ 123941047Sgibbs printf("%s: Encountered busy mailbox with %d out of %d " 124041047Sgibbs "commands active!!!", aha_name(aha), aha->active_ccbs, 124141047Sgibbs aha->max_ccbs); 124241047Sgibbs untimeout(ahatimeout, accb, ccb->ccb_h.timeout_ch); 124341047Sgibbs if (nseg != 0) 124441047Sgibbs bus_dmamap_unload(aha->buffer_dmat, accb->dmamap); 124541047Sgibbs ahafreeccb(aha, accb); 124641047Sgibbs aha->resource_shortage = TRUE; 124741047Sgibbs xpt_freeze_simq(aha->sim, /*count*/1); 124841047Sgibbs ccb->ccb_h.status = CAM_REQUEUE_REQ; 124941047Sgibbs xpt_done(ccb); 125041047Sgibbs return; 125141047Sgibbs } 125241047Sgibbs paddr = ahaccbvtop(aha, accb); 125339225Sgibbs ahautoa24(paddr, aha->cur_outbox->ccb_addr); 125441047Sgibbs aha->cur_outbox->action_code = AMBO_START; 125541047Sgibbs aha_outb(aha, COMMAND_REG, AOP_START_MBOX); 125639225Sgibbs 125739225Sgibbs ahanextoutbox(aha); 125839225Sgibbs splx(s); 125939225Sgibbs} 126039225Sgibbs 126139225Sgibbsvoid 126239225Sgibbsaha_intr(void *arg) 126339225Sgibbs{ 126439225Sgibbs struct aha_softc *aha; 126539225Sgibbs u_int intstat; 126639225Sgibbs 126739225Sgibbs aha = (struct aha_softc *)arg; 126839225Sgibbs while (((intstat = aha_inb(aha, INTSTAT_REG)) & INTR_PENDING) != 0) { 126939225Sgibbs if ((intstat & CMD_COMPLETE) != 0) { 127039225Sgibbs aha->latched_status = aha_inb(aha, STATUS_REG); 127139225Sgibbs aha->command_cmp = TRUE; 127239225Sgibbs } 127339225Sgibbs 127439225Sgibbs aha_outb(aha, CONTROL_REG, RESET_INTR); 127539225Sgibbs 127639225Sgibbs if ((intstat & IMB_LOADED) != 0) { 127741047Sgibbs while (aha->cur_inbox->comp_code != AMBI_FREE) { 127839225Sgibbs u_int32_t paddr; 127939225Sgibbs paddr = aha_a24tou(aha->cur_inbox->ccb_addr); 128039225Sgibbs ahadone(aha, 128139225Sgibbs ahaccbptov(aha, paddr), 128239225Sgibbs aha->cur_inbox->comp_code); 128341047Sgibbs aha->cur_inbox->comp_code = AMBI_FREE; 128439225Sgibbs ahanextinbox(aha); 128539225Sgibbs } 128639225Sgibbs } 128739225Sgibbs 128839225Sgibbs if ((intstat & SCSI_BUS_RESET) != 0) { 128939225Sgibbs ahareset(aha, /*hardreset*/FALSE); 129039225Sgibbs } 129139225Sgibbs } 129239225Sgibbs} 129339225Sgibbs 129439225Sgibbsstatic void 129541047Sgibbsahadone(struct aha_softc *aha, struct aha_ccb *accb, aha_mbi_comp_code_t comp_code) 129639225Sgibbs{ 129739225Sgibbs union ccb *ccb; 129839225Sgibbs struct ccb_scsiio *csio; 129939225Sgibbs 130041047Sgibbs ccb = accb->ccb; 130141047Sgibbs csio = &accb->ccb->csio; 130239225Sgibbs 130341047Sgibbs if ((accb->flags & ACCB_ACTIVE) == 0) { 130441047Sgibbs printf("%s: ahadone - Attempt to free non-active ACCB %p\n", 130541047Sgibbs aha_name(aha), (void *)accb); 130639225Sgibbs return; 130739225Sgibbs } 130839225Sgibbs 130939225Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 131039225Sgibbs bus_dmasync_op_t op; 131139225Sgibbs 131239225Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 131339225Sgibbs op = BUS_DMASYNC_POSTREAD; 131439225Sgibbs else 131539225Sgibbs op = BUS_DMASYNC_POSTWRITE; 131641047Sgibbs bus_dmamap_sync(aha->buffer_dmat, accb->dmamap, op); 131741047Sgibbs bus_dmamap_unload(aha->buffer_dmat, accb->dmamap); 131839225Sgibbs } 131939225Sgibbs 132041047Sgibbs if (accb == aha->recovery_accb) { 132139225Sgibbs /* 132241047Sgibbs * The recovery ACCB does not have a CCB associated 132339225Sgibbs * with it, so short circuit the normal error handling. 132439225Sgibbs * We now traverse our list of pending CCBs and process 132539225Sgibbs * any that were terminated by the recovery CCBs action. 132639225Sgibbs * We also reinstate timeouts for all remaining, pending, 132739225Sgibbs * CCBs. 132839225Sgibbs */ 132939225Sgibbs struct cam_path *path; 133039225Sgibbs struct ccb_hdr *ccb_h; 133139225Sgibbs cam_status error; 133239225Sgibbs 133339225Sgibbs /* Notify all clients that a BDR occured */ 133439225Sgibbs error = xpt_create_path(&path, /*periph*/NULL, 133539225Sgibbs cam_sim_path(aha->sim), 133641047Sgibbs accb->hccb.target, 133739225Sgibbs CAM_LUN_WILDCARD); 133839225Sgibbs 133939225Sgibbs if (error == CAM_REQ_CMP) 134039225Sgibbs xpt_async(AC_SENT_BDR, path, NULL); 134139225Sgibbs 134239225Sgibbs ccb_h = LIST_FIRST(&aha->pending_ccbs); 134339225Sgibbs while (ccb_h != NULL) { 134441047Sgibbs struct aha_ccb *pending_accb; 134539225Sgibbs 134641047Sgibbs pending_accb = (struct aha_ccb *)ccb_h->ccb_accb_ptr; 134741047Sgibbs if (pending_accb->hccb.target == accb->hccb.target) { 134841047Sgibbs pending_accb->hccb.ahastat = AHASTAT_HA_BDR; 134939225Sgibbs ccb_h = LIST_NEXT(ccb_h, sim_links.le); 135041047Sgibbs ahadone(aha, pending_accb, AMBI_ERROR); 135139225Sgibbs } else { 135239225Sgibbs ccb_h->timeout_ch = 135341047Sgibbs timeout(ahatimeout, (caddr_t)pending_accb, 135439225Sgibbs (ccb_h->timeout * hz) / 1000); 135539225Sgibbs ccb_h = LIST_NEXT(ccb_h, sim_links.le); 135639225Sgibbs } 135739225Sgibbs } 135839225Sgibbs printf("%s: No longer in timeout\n", aha_name(aha)); 135939225Sgibbs return; 136039225Sgibbs } 136139225Sgibbs 136241047Sgibbs untimeout(ahatimeout, accb, ccb->ccb_h.timeout_ch); 136339225Sgibbs 136439225Sgibbs switch (comp_code) { 136541047Sgibbs case AMBI_FREE: 136639225Sgibbs printf("%s: ahadone - CCB completed with free status!\n", 136739225Sgibbs aha_name(aha)); 136839225Sgibbs break; 136941047Sgibbs case AMBI_NOT_FOUND: 137039225Sgibbs printf("%s: ahadone - CCB Abort failed to find CCB\n", 137139225Sgibbs aha_name(aha)); 137239225Sgibbs break; 137341047Sgibbs case AMBI_ABORT: 137441047Sgibbs case AMBI_ERROR: 137539225Sgibbs /* An error occured */ 137642887Simp if (accb->hccb.opcode < INITIATOR_CCB_WRESID) 137742887Simp csio->resid = 0; 137842887Simp else 137942887Simp csio->resid = aha_a24tou(accb->hccb.data_len); 138041047Sgibbs switch(accb->hccb.ahastat) { 138139225Sgibbs case AHASTAT_DATARUN_ERROR: 138242013Sgibbs { 138342013Sgibbs if (csio->resid <= 0) { 138439225Sgibbs csio->ccb_h.status = CAM_DATA_RUN_ERR; 138539225Sgibbs break; 138639225Sgibbs } 138739225Sgibbs /* FALLTHROUGH */ 138842013Sgibbs } 138939225Sgibbs case AHASTAT_NOERROR: 139041047Sgibbs csio->scsi_status = accb->hccb.sdstat; 139139225Sgibbs csio->ccb_h.status |= CAM_SCSI_STATUS_ERROR; 139239225Sgibbs switch(csio->scsi_status) { 139339225Sgibbs case SCSI_STATUS_CHECK_COND: 139439225Sgibbs case SCSI_STATUS_CMD_TERMINATED: 139539225Sgibbs csio->ccb_h.status |= CAM_AUTOSNS_VALID; 139639225Sgibbs /* 139739225Sgibbs * The aha writes the sense data at different 139839225Sgibbs * offsets based on the scsi cmd len 139939225Sgibbs */ 140041047Sgibbs bcopy((caddr_t) &accb->hccb.scsi_cdb + 140141047Sgibbs accb->hccb.cmd_len, 140239225Sgibbs (caddr_t) &csio->sense_data, 140341047Sgibbs accb->hccb.sense_len); 140439225Sgibbs break; 140539225Sgibbs default: 140639225Sgibbs break; 140739225Sgibbs case SCSI_STATUS_OK: 140839225Sgibbs csio->ccb_h.status = CAM_REQ_CMP; 140939225Sgibbs break; 141039225Sgibbs } 141139225Sgibbs break; 141239225Sgibbs case AHASTAT_SELTIMEOUT: 141339225Sgibbs csio->ccb_h.status = CAM_SEL_TIMEOUT; 141439225Sgibbs break; 141539225Sgibbs case AHASTAT_UNEXPECTED_BUSFREE: 141639225Sgibbs csio->ccb_h.status = CAM_UNEXP_BUSFREE; 141739225Sgibbs break; 141839225Sgibbs case AHASTAT_INVALID_PHASE: 141939225Sgibbs csio->ccb_h.status = CAM_SEQUENCE_FAIL; 142039225Sgibbs break; 142139225Sgibbs case AHASTAT_INVALID_ACTION_CODE: 142239225Sgibbs panic("%s: Inavlid Action code", aha_name(aha)); 142339225Sgibbs break; 142439225Sgibbs case AHASTAT_INVALID_OPCODE: 142542887Simp if (accb->hccb.opcode < INITIATOR_CCB_WRESID) 142642887Simp panic("%s: Invalid CCB Opcode %x hccb = %p", 142742887Simp aha_name(aha), accb->hccb.opcode, 142842887Simp &accb->hccb); 142942887Simp printf("%s: AHA-1540A detected, compensating\n", 143042887Simp aha_name(aha)); 143142887Simp aha->ccb_sg_opcode = INITIATOR_SG_CCB; 143242887Simp aha->ccb_ccb_opcode = INITIATOR_CCB; 143342887Simp xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 143442887Simp csio->ccb_h.status = CAM_REQUEUE_REQ; 143539225Sgibbs break; 143639225Sgibbs case AHASTAT_LINKED_CCB_LUN_MISMATCH: 143739225Sgibbs /* We don't even support linked commands... */ 143839225Sgibbs panic("%s: Linked CCB Lun Mismatch", aha_name(aha)); 143939225Sgibbs break; 144039225Sgibbs case AHASTAT_INVALID_CCB_OR_SG_PARAM: 144139225Sgibbs panic("%s: Invalid CCB or SG list", aha_name(aha)); 144239225Sgibbs break; 144339225Sgibbs case AHASTAT_HA_SCSI_BUS_RESET: 144439225Sgibbs if ((csio->ccb_h.status & CAM_STATUS_MASK) 144542887Simp != CAM_CMD_TIMEOUT) 144639225Sgibbs csio->ccb_h.status = CAM_SCSI_BUS_RESET; 144739225Sgibbs break; 144839225Sgibbs case AHASTAT_HA_BDR: 144941047Sgibbs if ((accb->flags & ACCB_DEVICE_RESET) == 0) 145039225Sgibbs csio->ccb_h.status = CAM_BDR_SENT; 145139225Sgibbs else 145239225Sgibbs csio->ccb_h.status = CAM_CMD_TIMEOUT; 145339225Sgibbs break; 145439225Sgibbs } 145539225Sgibbs if (csio->ccb_h.status != CAM_REQ_CMP) { 145639225Sgibbs xpt_freeze_devq(csio->ccb_h.path, /*count*/1); 145739225Sgibbs csio->ccb_h.status |= CAM_DEV_QFRZN; 145839225Sgibbs } 145941047Sgibbs if ((accb->flags & ACCB_RELEASE_SIMQ) != 0) 146039225Sgibbs ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 146141047Sgibbs ahafreeccb(aha, accb); 146239225Sgibbs xpt_done(ccb); 146339225Sgibbs break; 146441047Sgibbs case AMBI_OK: 146539225Sgibbs /* All completed without incident */ 146639225Sgibbs /* XXX DO WE NEED TO COPY SENSE BYTES HERE???? XXX */ 146742887Simp /* I don't think so since it works???? */ 146839225Sgibbs ccb->ccb_h.status |= CAM_REQ_CMP; 146941047Sgibbs if ((accb->flags & ACCB_RELEASE_SIMQ) != 0) 147039225Sgibbs ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 147141047Sgibbs ahafreeccb(aha, accb); 147239225Sgibbs xpt_done(ccb); 147339225Sgibbs break; 147439225Sgibbs } 147539225Sgibbs} 147639225Sgibbs 147739225Sgibbsstatic int 147839225Sgibbsahareset(struct aha_softc* aha, int hard_reset) 147939225Sgibbs{ 148039225Sgibbs struct ccb_hdr *ccb_h; 148139225Sgibbs u_int status; 148239225Sgibbs u_int timeout; 148339225Sgibbs u_int8_t reset_type; 148439225Sgibbs 148539225Sgibbs if (hard_reset != 0) 148639225Sgibbs reset_type = HARD_RESET; 148739225Sgibbs else 148839225Sgibbs reset_type = SOFT_RESET; 148939225Sgibbs aha_outb(aha, CONTROL_REG, reset_type); 149039225Sgibbs 149139225Sgibbs /* Wait 5sec. for Diagnostic start */ 149239225Sgibbs timeout = 5 * 10000; 149339225Sgibbs while (--timeout) { 149439225Sgibbs status = aha_inb(aha, STATUS_REG); 149539225Sgibbs if ((status & DIAG_ACTIVE) != 0) 149639225Sgibbs break; 149739225Sgibbs DELAY(100); 149839225Sgibbs } 149939225Sgibbs if (timeout == 0) { 150039881Simp PRVERB(("%s: ahareset - Diagnostic Active failed to " 150139881Simp "assert. status = 0x%x\n", aha_name(aha), 150239881Simp status)); 150339225Sgibbs return (ETIMEDOUT); 150439225Sgibbs } 150539225Sgibbs 150639225Sgibbs /* Wait 10sec. for Diagnostic end */ 150739225Sgibbs timeout = 10 * 10000; 150839225Sgibbs while (--timeout) { 150939225Sgibbs status = aha_inb(aha, STATUS_REG); 151039225Sgibbs if ((status & DIAG_ACTIVE) == 0) 151139225Sgibbs break; 151239225Sgibbs DELAY(100); 151339225Sgibbs } 151439225Sgibbs if (timeout == 0) { 151539225Sgibbs panic("%s: ahareset - Diagnostic Active failed to drop. " 151639225Sgibbs "status = 0x%x\n", aha_name(aha), status); 151739225Sgibbs return (ETIMEDOUT); 151839225Sgibbs } 151939225Sgibbs 152039225Sgibbs /* Wait for the host adapter to become ready or report a failure */ 152139225Sgibbs timeout = 10000; 152239225Sgibbs while (--timeout) { 152339225Sgibbs status = aha_inb(aha, STATUS_REG); 152439225Sgibbs if ((status & (DIAG_FAIL|HA_READY|DATAIN_REG_READY)) != 0) 152539225Sgibbs break; 152639225Sgibbs DELAY(100); 152739225Sgibbs } 152839225Sgibbs if (timeout == 0) { 152939225Sgibbs printf("%s: ahareset - Host adapter failed to come ready. " 153039225Sgibbs "status = 0x%x\n", aha_name(aha), status); 153139225Sgibbs return (ETIMEDOUT); 153239225Sgibbs } 153339225Sgibbs 153439225Sgibbs /* If the diagnostics failed, tell the user */ 153539225Sgibbs if ((status & DIAG_FAIL) != 0 153639225Sgibbs || (status & HA_READY) == 0) { 153739225Sgibbs printf("%s: ahareset - Adapter failed diagnostics\n", 153839225Sgibbs aha_name(aha)); 153939225Sgibbs 154039225Sgibbs if ((status & DATAIN_REG_READY) != 0) 154139324Sgibbs printf("%s: ahareset - Host Adapter Error " 154239324Sgibbs "code = 0x%x\n", aha_name(aha), 154339225Sgibbs aha_inb(aha, DATAIN_REG)); 154439225Sgibbs return (ENXIO); 154539225Sgibbs } 154639225Sgibbs 154739225Sgibbs /* If we've allocated mailboxes, initialize them */ 154839225Sgibbs if (aha->init_level > 4) 154939225Sgibbs ahainitmboxes(aha); 155039225Sgibbs 155139225Sgibbs /* If we've attached to the XPT, tell it about the event */ 155239225Sgibbs if (aha->path != NULL) 155339225Sgibbs xpt_async(AC_BUS_RESET, aha->path, NULL); 155439225Sgibbs 155539225Sgibbs /* 155639225Sgibbs * Perform completion processing for all outstanding CCBs. 155739225Sgibbs */ 155839225Sgibbs while ((ccb_h = LIST_FIRST(&aha->pending_ccbs)) != NULL) { 155941047Sgibbs struct aha_ccb *pending_accb; 156039225Sgibbs 156141047Sgibbs pending_accb = (struct aha_ccb *)ccb_h->ccb_accb_ptr; 156241047Sgibbs pending_accb->hccb.ahastat = AHASTAT_HA_SCSI_BUS_RESET; 156341047Sgibbs ahadone(aha, pending_accb, AMBI_ERROR); 156439225Sgibbs } 156539225Sgibbs 156639225Sgibbs return (0); 156739225Sgibbs} 156839225Sgibbs 156939225Sgibbs/* 157039225Sgibbs * Send a command to the adapter. 157139225Sgibbs */ 157239225Sgibbsint 157339225Sgibbsaha_cmd(struct aha_softc *aha, aha_op_t opcode, u_int8_t *params, 157439225Sgibbs u_int param_len, u_int8_t *reply_data, u_int reply_len, 157539225Sgibbs u_int cmd_timeout) 157639225Sgibbs{ 157739225Sgibbs u_int timeout; 157839225Sgibbs u_int status; 157939225Sgibbs u_int intstat; 158039225Sgibbs u_int reply_buf_size; 158139225Sgibbs int s; 158241709Sgibbs int cmd_complete; 158339225Sgibbs 158439225Sgibbs /* No data returned to start */ 158539225Sgibbs reply_buf_size = reply_len; 158639225Sgibbs reply_len = 0; 158739225Sgibbs intstat = 0; 158841709Sgibbs cmd_complete = 0; 158939225Sgibbs 159039225Sgibbs aha->command_cmp = 0; 159139225Sgibbs /* 159239225Sgibbs * Wait up to 1 sec. for the adapter to become 159339225Sgibbs * ready to accept commands. 159439225Sgibbs */ 159539225Sgibbs timeout = 10000; 159639225Sgibbs while (--timeout) { 159739225Sgibbs 159839225Sgibbs status = aha_inb(aha, STATUS_REG); 159939225Sgibbs if ((status & HA_READY) != 0 160039225Sgibbs && (status & CMD_REG_BUSY) == 0) 160139225Sgibbs break; 160239225Sgibbs DELAY(100); 160339225Sgibbs } 160439225Sgibbs if (timeout == 0) { 160539225Sgibbs printf("%s: aha_cmd: Timeout waiting for adapter ready, " 160639225Sgibbs "status = 0x%x\n", aha_name(aha), status); 160739225Sgibbs return (ETIMEDOUT); 160839225Sgibbs } 160939225Sgibbs 161039225Sgibbs /* 161139225Sgibbs * Send the opcode followed by any necessary parameter bytes. 161239225Sgibbs */ 161339225Sgibbs aha_outb(aha, COMMAND_REG, opcode); 161439225Sgibbs 161539225Sgibbs /* 161639225Sgibbs * Wait for up to 1sec to get the parameter list sent 161739225Sgibbs */ 161839225Sgibbs timeout = 10000; 161939225Sgibbs while (param_len && --timeout) { 162039225Sgibbs DELAY(100); 162139225Sgibbs status = aha_inb(aha, STATUS_REG); 162239225Sgibbs intstat = aha_inb(aha, INTSTAT_REG); 162339225Sgibbs if ((intstat & (INTR_PENDING|CMD_COMPLETE)) 162441709Sgibbs == (INTR_PENDING|CMD_COMPLETE)) { 162541709Sgibbs cmd_complete = 1; 162639225Sgibbs break; 162741709Sgibbs } 162839225Sgibbs if (aha->command_cmp != 0) { 162939225Sgibbs status = aha->latched_status; 163041709Sgibbs cmd_complete = 1; 163139225Sgibbs break; 163239225Sgibbs } 163339225Sgibbs if ((status & DATAIN_REG_READY) != 0) 163439225Sgibbs break; 163539225Sgibbs if ((status & CMD_REG_BUSY) == 0) { 163639225Sgibbs aha_outb(aha, COMMAND_REG, *params++); 163739225Sgibbs param_len--; 163839225Sgibbs } 163939225Sgibbs } 164039225Sgibbs if (timeout == 0) { 164139225Sgibbs printf("%s: aha_cmd: Timeout sending parameters, " 164239225Sgibbs "status = 0x%x\n", aha_name(aha), status); 164339225Sgibbs return (ETIMEDOUT); 164439225Sgibbs } 164539225Sgibbs 164639225Sgibbs /* 164739225Sgibbs * For all other commands, we wait for any output data 164839225Sgibbs * and the final comand completion interrupt. 164939225Sgibbs */ 165041709Sgibbs while (cmd_complete == 0 && --cmd_timeout) { 165139225Sgibbs 165239225Sgibbs status = aha_inb(aha, STATUS_REG); 165339225Sgibbs intstat = aha_inb(aha, INTSTAT_REG); 165439225Sgibbs if ((intstat & (INTR_PENDING|CMD_COMPLETE)) 165539225Sgibbs == (INTR_PENDING|CMD_COMPLETE)) 165639225Sgibbs break; 165739225Sgibbs 165839225Sgibbs if (aha->command_cmp != 0) { 165939225Sgibbs status = aha->latched_status; 166039225Sgibbs break; 166139225Sgibbs } 166239225Sgibbs 166339225Sgibbs if ((status & DATAIN_REG_READY) != 0) { 166439225Sgibbs u_int8_t data; 166539225Sgibbs 166639225Sgibbs data = aha_inb(aha, DATAIN_REG); 166739225Sgibbs if (reply_len < reply_buf_size) { 166839225Sgibbs *reply_data++ = data; 166939225Sgibbs } else { 167039225Sgibbs printf("%s: aha_cmd - Discarded reply data byte " 167139225Sgibbs "for opcode 0x%x\n", aha_name(aha), 167239225Sgibbs opcode); 167339225Sgibbs } 167439225Sgibbs reply_len++; 167539225Sgibbs } 167639225Sgibbs 167739225Sgibbs DELAY(100); 167839225Sgibbs } 167939225Sgibbs if (timeout == 0) { 168039225Sgibbs printf("%s: aha_cmd: Timeout waiting for reply data and " 168139225Sgibbs "command complete.\n%s: status = 0x%x, intstat = 0x%x, " 168239225Sgibbs "reply_len = %d\n", aha_name(aha), aha_name(aha), status, 168339225Sgibbs intstat, reply_len); 168439225Sgibbs return (ETIMEDOUT); 168539225Sgibbs } 168639225Sgibbs 168739225Sgibbs /* 168839225Sgibbs * Clear any pending interrupts. Block interrupts so our 168939225Sgibbs * interrupt handler is not re-entered. 169039225Sgibbs */ 169139225Sgibbs s = splcam(); 169239225Sgibbs aha_intr(aha); 169339225Sgibbs splx(s); 169439225Sgibbs 169539225Sgibbs /* 169639225Sgibbs * If the command was rejected by the controller, tell the caller. 169739225Sgibbs */ 169839225Sgibbs if ((status & CMD_INVALID) != 0) { 169939881Simp PRVERB(("%s: Invalid Command 0x%x\n", aha_name(aha), opcode)); 170039225Sgibbs /* 170139225Sgibbs * Some early adapters may not recover properly from 170239225Sgibbs * an invalid command. If it appears that the controller 170339225Sgibbs * has wedged (i.e. status was not cleared by our interrupt 170439225Sgibbs * reset above), perform a soft reset. 170539225Sgibbs */ 170639225Sgibbs DELAY(1000); 170739225Sgibbs status = aha_inb(aha, STATUS_REG); 170839225Sgibbs if ((status & (CMD_INVALID|STATUS_REG_RSVD|DATAIN_REG_READY| 170939225Sgibbs CMD_REG_BUSY|DIAG_FAIL|DIAG_ACTIVE)) != 0 171039225Sgibbs || (status & (HA_READY|INIT_REQUIRED)) 171139225Sgibbs != (HA_READY|INIT_REQUIRED)) { 171239852Simp ahareset(aha, /*hard_reset*/FALSE); 171339225Sgibbs } 171439225Sgibbs return (EINVAL); 171539225Sgibbs } 171639225Sgibbs 171739225Sgibbs 171839225Sgibbs if (param_len > 0) { 171939225Sgibbs /* The controller did not accept the full argument list */ 172039225Sgibbs return (E2BIG); 172139225Sgibbs } 172239225Sgibbs 172339225Sgibbs if (reply_len != reply_buf_size) { 172439225Sgibbs /* Too much or too little data received */ 172539225Sgibbs return (EMSGSIZE); 172639225Sgibbs } 172739225Sgibbs 172839225Sgibbs /* We were successful */ 172939225Sgibbs return (0); 173039225Sgibbs} 173139225Sgibbs 173239225Sgibbsstatic int 173339225Sgibbsahainitmboxes(struct aha_softc *aha) 173439225Sgibbs{ 173539225Sgibbs int error; 173639225Sgibbs init_24b_mbox_params_t init_mbox; 173739225Sgibbs 173839225Sgibbs bzero(aha->in_boxes, sizeof(aha_mbox_in_t) * aha->num_boxes); 173939225Sgibbs bzero(aha->out_boxes, sizeof(aha_mbox_out_t) * aha->num_boxes); 174039225Sgibbs aha->cur_inbox = aha->in_boxes; 174139225Sgibbs aha->last_inbox = aha->in_boxes + aha->num_boxes - 1; 174239225Sgibbs aha->cur_outbox = aha->out_boxes; 174339225Sgibbs aha->last_outbox = aha->out_boxes + aha->num_boxes - 1; 174439225Sgibbs 174539225Sgibbs /* Tell the adapter about them */ 174639225Sgibbs init_mbox.num_mboxes = aha->num_boxes; 174739225Sgibbs ahautoa24(aha->mailbox_physbase, init_mbox.base_addr); 174841047Sgibbs error = aha_cmd(aha, AOP_INITIALIZE_MBOX, (u_int8_t *)&init_mbox, 174939225Sgibbs /*parmlen*/sizeof(init_mbox), /*reply_buf*/NULL, 175039225Sgibbs /*reply_len*/0, DEFAULT_CMD_TIMEOUT); 175139225Sgibbs 175239225Sgibbs if (error != 0) 175339225Sgibbs printf("ahainitmboxes: Initialization command failed\n"); 175439225Sgibbs return (error); 175539225Sgibbs} 175639225Sgibbs 175739225Sgibbs/* 175839225Sgibbs * Update the XPT's idea of the negotiated transfer 175939225Sgibbs * parameters for a particular target. 176039225Sgibbs */ 176139225Sgibbsstatic void 176239225Sgibbsahafetchtransinfo(struct aha_softc *aha, struct ccb_trans_settings* cts) 176339225Sgibbs{ 176439225Sgibbs setup_data_t setup_info; 176539225Sgibbs u_int target; 176639225Sgibbs u_int targ_offset; 176739225Sgibbs u_int sync_period; 176839225Sgibbs int error; 176939225Sgibbs u_int8_t param; 177039225Sgibbs targ_syncinfo_t sync_info; 177139225Sgibbs 177239225Sgibbs target = cts->ccb_h.target_id; 177339225Sgibbs targ_offset = (target & 0x7); 177439225Sgibbs 177539225Sgibbs /* 177647208Simp * Inquire Setup Information. This command retreives 177747208Simp * the sync info for older models. We put a small delay here 177847208Simp * because that seems to help the stability. 10mS is known 177947208Simp * to work, but other values might also work. 178039225Sgibbs */ 178147208Simp DELAY(10000); 178239225Sgibbs param = sizeof(setup_info); 178341047Sgibbs error = aha_cmd(aha, AOP_INQUIRE_SETUP_INFO, ¶m, /*paramlen*/1, 178439225Sgibbs (u_int8_t*)&setup_info, sizeof(setup_info), 178539225Sgibbs DEFAULT_CMD_TIMEOUT); 178639225Sgibbs 178739225Sgibbs if (error != 0) { 178839225Sgibbs printf("%s: ahafetchtransinfo - Inquire Setup Info Failed\n", 178939225Sgibbs aha_name(aha)); 179039225Sgibbs return; 179139225Sgibbs } 179239225Sgibbs 179339225Sgibbs sync_info = setup_info.syncinfo[targ_offset]; 179439225Sgibbs 179539225Sgibbs if (sync_info.sync == 0) 179639225Sgibbs cts->sync_offset = 0; 179739225Sgibbs else 179839225Sgibbs cts->sync_offset = sync_info.offset; 179939225Sgibbs 180039225Sgibbs cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 180139225Sgibbs 180239225Sgibbs sync_period = 2000 + (500 * sync_info.period); 180339225Sgibbs 180439225Sgibbs /* Convert ns value to standard SCSI sync rate */ 180539225Sgibbs if (cts->sync_offset != 0) 180639225Sgibbs cts->sync_period = scsi_calc_syncparam(sync_period); 180739225Sgibbs else 180839225Sgibbs cts->sync_period = 0; 180939225Sgibbs 181039225Sgibbs cts->valid = CCB_TRANS_SYNC_RATE_VALID 181139225Sgibbs | CCB_TRANS_SYNC_OFFSET_VALID 181239225Sgibbs | CCB_TRANS_BUS_WIDTH_VALID; 181339225Sgibbs xpt_async(AC_TRANSFER_NEG, cts->ccb_h.path, cts); 181439225Sgibbs} 181539225Sgibbs 181639225Sgibbsstatic void 181739225Sgibbsahamapmboxes(void *arg, bus_dma_segment_t *segs, int nseg, int error) 181839225Sgibbs{ 181939225Sgibbs struct aha_softc* aha; 182039225Sgibbs 182139225Sgibbs aha = (struct aha_softc*)arg; 182239225Sgibbs aha->mailbox_physbase = segs->ds_addr; 182339225Sgibbs} 182439225Sgibbs 182539225Sgibbsstatic void 182639225Sgibbsahamapccbs(void *arg, bus_dma_segment_t *segs, int nseg, int error) 182739225Sgibbs{ 182839225Sgibbs struct aha_softc* aha; 182939225Sgibbs 183039225Sgibbs aha = (struct aha_softc*)arg; 183139225Sgibbs aha->aha_ccb_physbase = segs->ds_addr; 183239225Sgibbs} 183339225Sgibbs 183439225Sgibbsstatic void 183539225Sgibbsahamapsgs(void *arg, bus_dma_segment_t *segs, int nseg, int error) 183639225Sgibbs{ 183739225Sgibbs 183839225Sgibbs struct aha_softc* aha; 183939225Sgibbs 184039225Sgibbs aha = (struct aha_softc*)arg; 184139225Sgibbs SLIST_FIRST(&aha->sg_maps)->sg_physaddr = segs->ds_addr; 184239225Sgibbs} 184339225Sgibbs 184439225Sgibbsstatic void 184539225Sgibbsahapoll(struct cam_sim *sim) 184639225Sgibbs{ 184740132Sgibbs aha_intr(cam_sim_softc(sim)); 184839225Sgibbs} 184939225Sgibbs 185045575Seivindstatic void 185139225Sgibbsahatimeout(void *arg) 185239225Sgibbs{ 185341047Sgibbs struct aha_ccb *accb; 185439225Sgibbs union ccb *ccb; 185539225Sgibbs struct aha_softc *aha; 185639225Sgibbs int s; 185739225Sgibbs u_int32_t paddr; 185839225Sgibbs 185941047Sgibbs accb = (struct aha_ccb *)arg; 186041047Sgibbs ccb = accb->ccb; 186139225Sgibbs aha = (struct aha_softc *)ccb->ccb_h.ccb_aha_ptr; 186239225Sgibbs xpt_print_path(ccb->ccb_h.path); 186341047Sgibbs printf("CCB %p - timed out\n", (void *)accb); 186439225Sgibbs 186539225Sgibbs s = splcam(); 186639225Sgibbs 186741047Sgibbs if ((accb->flags & ACCB_ACTIVE) == 0) { 186839225Sgibbs xpt_print_path(ccb->ccb_h.path); 186939390Sgibbs printf("CCB %p - timed out CCB already completed\n", 187041047Sgibbs (void *)accb); 187139225Sgibbs splx(s); 187239225Sgibbs return; 187339225Sgibbs } 187439225Sgibbs 187539225Sgibbs /* 187639225Sgibbs * In order to simplify the recovery process, we ask the XPT 187739225Sgibbs * layer to halt the queue of new transactions and we traverse 187839225Sgibbs * the list of pending CCBs and remove their timeouts. This 187939225Sgibbs * means that the driver attempts to clear only one error 188039225Sgibbs * condition at a time. In general, timeouts that occur 188139225Sgibbs * close together are related anyway, so there is no benefit 188239225Sgibbs * in attempting to handle errors in parrallel. Timeouts will 188339225Sgibbs * be reinstated when the recovery process ends. 188439225Sgibbs */ 188541047Sgibbs if ((accb->flags & ACCB_DEVICE_RESET) == 0) { 188639225Sgibbs struct ccb_hdr *ccb_h; 188739225Sgibbs 188841047Sgibbs if ((accb->flags & ACCB_RELEASE_SIMQ) == 0) { 188939225Sgibbs xpt_freeze_simq(aha->sim, /*count*/1); 189041047Sgibbs accb->flags |= ACCB_RELEASE_SIMQ; 189139225Sgibbs } 189239225Sgibbs 189339225Sgibbs ccb_h = LIST_FIRST(&aha->pending_ccbs); 189439225Sgibbs while (ccb_h != NULL) { 189541047Sgibbs struct aha_ccb *pending_accb; 189639225Sgibbs 189741047Sgibbs pending_accb = (struct aha_ccb *)ccb_h->ccb_accb_ptr; 189841047Sgibbs untimeout(ahatimeout, pending_accb, ccb_h->timeout_ch); 189939225Sgibbs ccb_h = LIST_NEXT(ccb_h, sim_links.le); 190039225Sgibbs } 190139225Sgibbs } 190239225Sgibbs 190341047Sgibbs if ((accb->flags & ACCB_DEVICE_RESET) != 0 190441047Sgibbs || aha->cur_outbox->action_code != AMBO_FREE) { 190539225Sgibbs /* 190639225Sgibbs * Try a full host adapter/SCSI bus reset. 190739225Sgibbs * We do this only if we have already attempted 190839225Sgibbs * to clear the condition with a BDR, or we cannot 190939225Sgibbs * attempt a BDR for lack of mailbox resources. 191039225Sgibbs */ 191139225Sgibbs ccb->ccb_h.status = CAM_CMD_TIMEOUT; 191239225Sgibbs ahareset(aha, /*hardreset*/TRUE); 191339225Sgibbs printf("%s: No longer in timeout\n", aha_name(aha)); 191439225Sgibbs } else { 191539225Sgibbs /* 191639225Sgibbs * Send a Bus Device Reset message: 191739225Sgibbs * The target that is holding up the bus may not 191839225Sgibbs * be the same as the one that triggered this timeout 191939225Sgibbs * (different commands have different timeout lengths), 192039225Sgibbs * but we have no way of determining this from our 192139225Sgibbs * timeout handler. Our strategy here is to queue a 192239225Sgibbs * BDR message to the target of the timed out command. 192339225Sgibbs * If this fails, we'll get another timeout 2 seconds 192439225Sgibbs * later which will attempt a bus reset. 192539225Sgibbs */ 192641047Sgibbs accb->flags |= ACCB_DEVICE_RESET; 192741047Sgibbs ccb->ccb_h.timeout_ch = timeout(ahatimeout, (caddr_t)accb, 2 * hz); 192841047Sgibbs aha->recovery_accb->hccb.opcode = INITIATOR_BUS_DEV_RESET; 192939225Sgibbs 193039225Sgibbs /* No Data Transfer */ 193141047Sgibbs aha->recovery_accb->hccb.datain = TRUE; 193241047Sgibbs aha->recovery_accb->hccb.dataout = TRUE; 193341047Sgibbs aha->recovery_accb->hccb.ahastat = 0; 193441047Sgibbs aha->recovery_accb->hccb.sdstat = 0; 193541047Sgibbs aha->recovery_accb->hccb.target = ccb->ccb_h.target_id; 193639225Sgibbs 193739225Sgibbs /* Tell the adapter about this command */ 193841047Sgibbs paddr = ahaccbvtop(aha, aha->recovery_accb); 193939225Sgibbs ahautoa24(paddr, aha->cur_outbox->ccb_addr); 194041047Sgibbs aha->cur_outbox->action_code = AMBO_START; 194141047Sgibbs aha_outb(aha, COMMAND_REG, AOP_START_MBOX); 194239225Sgibbs ahanextoutbox(aha); 194339225Sgibbs } 194439225Sgibbs 194539225Sgibbs splx(s); 194639225Sgibbs} 1947