aha.c revision 47506
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 * 5847506Sgibbs * $Id: aha.c,v 1.25 1999/05/14 23:10:25 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 10347506Sgibbs#ifndef MAX 10447506Sgibbs#define MAX(a, b) ((a) > (b) ? (a) : (b)) 10547506Sgibbs#endif 10647506Sgibbs 10739225Sgibbs/* MailBox Management functions */ 10839225Sgibbsstatic __inline void ahanextinbox(struct aha_softc *aha); 10939225Sgibbsstatic __inline void ahanextoutbox(struct aha_softc *aha); 11039225Sgibbs 11139225Sgibbsstatic __inline void 11239225Sgibbsahanextinbox(struct aha_softc *aha) 11339225Sgibbs{ 11439225Sgibbs if (aha->cur_inbox == aha->last_inbox) 11539225Sgibbs aha->cur_inbox = aha->in_boxes; 11639225Sgibbs else 11739225Sgibbs aha->cur_inbox++; 11839225Sgibbs} 11939225Sgibbs 12039225Sgibbsstatic __inline void 12139225Sgibbsahanextoutbox(struct aha_softc *aha) 12239225Sgibbs{ 12339225Sgibbs if (aha->cur_outbox == aha->last_outbox) 12439225Sgibbs aha->cur_outbox = aha->out_boxes; 12539225Sgibbs else 12639225Sgibbs aha->cur_outbox++; 12739225Sgibbs} 12839225Sgibbs 12939225Sgibbs#define ahautoa24(u,s3) \ 13039225Sgibbs (s3)[0] = ((u) >> 16) & 0xff; \ 13139225Sgibbs (s3)[1] = ((u) >> 8) & 0xff; \ 13239225Sgibbs (s3)[2] = (u) & 0xff; 13339225Sgibbs 13439225Sgibbs#define aha_a24tou(s3) \ 13539225Sgibbs (((s3)[0] << 16) | ((s3)[1] << 8) | (s3)[2]) 13639225Sgibbs 13739225Sgibbs/* CCB Mangement functions */ 13839225Sgibbsstatic __inline u_int32_t ahaccbvtop(struct aha_softc *aha, 13941047Sgibbs struct aha_ccb *accb); 14039225Sgibbsstatic __inline struct aha_ccb* ahaccbptov(struct aha_softc *aha, 14139225Sgibbs u_int32_t ccb_addr); 14239225Sgibbs 14339225Sgibbsstatic __inline u_int32_t 14441047Sgibbsahaccbvtop(struct aha_softc *aha, struct aha_ccb *accb) 14539225Sgibbs{ 14639225Sgibbs return (aha->aha_ccb_physbase 14741047Sgibbs + (u_int32_t)((caddr_t)accb - (caddr_t)aha->aha_ccb_array)); 14839225Sgibbs} 14939225Sgibbsstatic __inline struct aha_ccb * 15039225Sgibbsahaccbptov(struct aha_softc *aha, u_int32_t ccb_addr) 15139225Sgibbs{ 15239225Sgibbs return (aha->aha_ccb_array + 15339225Sgibbs + ((struct aha_ccb*)ccb_addr-(struct aha_ccb*)aha->aha_ccb_physbase)); 15439225Sgibbs} 15539225Sgibbs 15639225Sgibbsstatic struct aha_ccb* ahagetccb(struct aha_softc *aha); 15741047Sgibbsstatic __inline void ahafreeccb(struct aha_softc *aha, struct aha_ccb *accb); 15839225Sgibbsstatic void ahaallocccbs(struct aha_softc *aha); 15939225Sgibbsstatic bus_dmamap_callback_t ahaexecuteccb; 16041047Sgibbsstatic void ahadone(struct aha_softc *aha, struct aha_ccb *accb, 16139225Sgibbs aha_mbi_comp_code_t comp_code); 16239225Sgibbs 16339225Sgibbs/* Host adapter command functions */ 16439225Sgibbsstatic int ahareset(struct aha_softc* aha, int hard_reset); 16539225Sgibbs 16639225Sgibbs/* Initialization functions */ 16739225Sgibbsstatic int ahainitmboxes(struct aha_softc *aha); 16839225Sgibbsstatic bus_dmamap_callback_t ahamapmboxes; 16939225Sgibbsstatic bus_dmamap_callback_t ahamapccbs; 17039225Sgibbsstatic bus_dmamap_callback_t ahamapsgs; 17139225Sgibbs 17239225Sgibbs/* Transfer Negotiation Functions */ 17339225Sgibbsstatic void ahafetchtransinfo(struct aha_softc *aha, 17439225Sgibbs struct ccb_trans_settings *cts); 17539225Sgibbs 17639225Sgibbs/* CAM SIM entry points */ 17741047Sgibbs#define ccb_accb_ptr spriv_ptr0 17839225Sgibbs#define ccb_aha_ptr spriv_ptr1 17939225Sgibbsstatic void ahaaction(struct cam_sim *sim, union ccb *ccb); 18039225Sgibbsstatic void ahapoll(struct cam_sim *sim); 18139225Sgibbs 18239225Sgibbs/* Our timeout handler */ 18346602Speterstatic timeout_t ahatimeout; 18439225Sgibbs 18539225Sgibbsu_long aha_unit = 0; 18639225Sgibbs 18739225Sgibbs/* 18839225Sgibbs * Do our own re-probe protection until a configuration 18939225Sgibbs * manager can do it for us. This ensures that we don't 19039225Sgibbs * reprobe a card already found by the EISA or PCI probes. 19139225Sgibbs */ 19245575Seivindstatic struct aha_isa_port aha_isa_ports[] = 19339225Sgibbs{ 19441047Sgibbs { 0x130, 0, 4 }, 19541047Sgibbs { 0x134, 0, 5 }, 19641047Sgibbs { 0x230, 0, 2 }, 19741047Sgibbs { 0x234, 0, 3 }, 19841047Sgibbs { 0x330, 0, 0 }, 19941047Sgibbs { 0x334, 0, 1 } 20039225Sgibbs}; 20139225Sgibbs 20241047Sgibbs/* 20341047Sgibbs * I/O ports listed in the order enumerated by the 20441047Sgibbs * card for certain op codes. 20541047Sgibbs */ 20645575Seivindstatic u_int16_t aha_board_ports[] = 20741047Sgibbs{ 20841047Sgibbs 0x330, 20941047Sgibbs 0x334, 21041047Sgibbs 0x230, 21141047Sgibbs 0x234, 21241047Sgibbs 0x130, 21341047Sgibbs 0x134 21441047Sgibbs}; 21541047Sgibbs 21639225Sgibbs/* Exported functions */ 21739225Sgibbsstruct aha_softc * 21839225Sgibbsaha_alloc(int unit, bus_space_tag_t tag, bus_space_handle_t bsh) 21939225Sgibbs{ 22039225Sgibbs struct aha_softc *aha; 22139225Sgibbs 22239225Sgibbs if (unit != AHA_TEMP_UNIT) { 22342887Simp if (unit >= NAHATOT) { 22439225Sgibbs printf("aha: unit number (%d) too high\n", unit); 22539225Sgibbs return NULL; 22639225Sgibbs } 22739225Sgibbs 22839225Sgibbs /* 22939225Sgibbs * Allocate a storage area for us 23039225Sgibbs */ 23139225Sgibbs if (aha_softcs[unit]) { 23239225Sgibbs printf("aha%d: memory already allocated\n", unit); 23339225Sgibbs return NULL; 23439225Sgibbs } 23539225Sgibbs } 23639225Sgibbs 23739225Sgibbs aha = malloc(sizeof(struct aha_softc), M_DEVBUF, M_NOWAIT); 23839225Sgibbs if (!aha) { 23939225Sgibbs printf("aha%d: cannot malloc!\n", unit); 24039225Sgibbs return NULL; 24139225Sgibbs } 24239225Sgibbs bzero(aha, sizeof(struct aha_softc)); 24339225Sgibbs SLIST_INIT(&aha->free_aha_ccbs); 24439225Sgibbs LIST_INIT(&aha->pending_ccbs); 24539225Sgibbs SLIST_INIT(&aha->sg_maps); 24639225Sgibbs aha->unit = unit; 24739225Sgibbs aha->tag = tag; 24839225Sgibbs aha->bsh = bsh; 24942887Simp aha->ccb_sg_opcode = INITIATOR_SG_CCB_WRESID; 25042887Simp aha->ccb_ccb_opcode = INITIATOR_CCB_WRESID; 25139225Sgibbs 25239225Sgibbs if (aha->unit != AHA_TEMP_UNIT) { 25339225Sgibbs aha_softcs[unit] = aha; 25439225Sgibbs } 25539225Sgibbs return (aha); 25639225Sgibbs} 25739225Sgibbs 25839225Sgibbsvoid 25939225Sgibbsaha_free(struct aha_softc *aha) 26039225Sgibbs{ 26139225Sgibbs switch (aha->init_level) { 26239225Sgibbs default: 26339225Sgibbs case 8: 26439225Sgibbs { 26539225Sgibbs struct sg_map_node *sg_map; 26639225Sgibbs 26739225Sgibbs while ((sg_map = SLIST_FIRST(&aha->sg_maps))!= NULL) { 26839225Sgibbs SLIST_REMOVE_HEAD(&aha->sg_maps, links); 26939225Sgibbs bus_dmamap_unload(aha->sg_dmat, 27039225Sgibbs sg_map->sg_dmamap); 27139225Sgibbs bus_dmamem_free(aha->sg_dmat, sg_map->sg_vaddr, 27239225Sgibbs sg_map->sg_dmamap); 27339225Sgibbs free(sg_map, M_DEVBUF); 27439225Sgibbs } 27539225Sgibbs bus_dma_tag_destroy(aha->sg_dmat); 27639225Sgibbs } 27739225Sgibbs case 7: 27839225Sgibbs bus_dmamap_unload(aha->ccb_dmat, aha->ccb_dmamap); 27939225Sgibbs case 6: 28039225Sgibbs bus_dmamap_destroy(aha->ccb_dmat, aha->ccb_dmamap); 28139225Sgibbs bus_dmamem_free(aha->ccb_dmat, aha->aha_ccb_array, 28239225Sgibbs aha->ccb_dmamap); 28339225Sgibbs case 5: 28439225Sgibbs bus_dma_tag_destroy(aha->ccb_dmat); 28539225Sgibbs case 4: 28639225Sgibbs bus_dmamap_unload(aha->mailbox_dmat, aha->mailbox_dmamap); 28739225Sgibbs case 3: 28839225Sgibbs bus_dmamem_free(aha->mailbox_dmat, aha->in_boxes, 28939225Sgibbs aha->mailbox_dmamap); 29039225Sgibbs bus_dmamap_destroy(aha->mailbox_dmat, aha->mailbox_dmamap); 29139225Sgibbs case 2: 29239225Sgibbs bus_dma_tag_destroy(aha->buffer_dmat); 29339225Sgibbs case 1: 29439225Sgibbs bus_dma_tag_destroy(aha->mailbox_dmat); 29539225Sgibbs case 0: 29639225Sgibbs } 29739225Sgibbs if (aha->unit != AHA_TEMP_UNIT) { 29839225Sgibbs aha_softcs[aha->unit] = NULL; 29939225Sgibbs } 30039225Sgibbs free(aha, M_DEVBUF); 30139225Sgibbs} 30239225Sgibbs 30339225Sgibbs/* 30439225Sgibbs * Probe the adapter and verify that the card is an Adaptec. 30539225Sgibbs */ 30639225Sgibbsint 30739225Sgibbsaha_probe(struct aha_softc* aha) 30839225Sgibbs{ 30939225Sgibbs u_int status; 31039225Sgibbs u_int intstat; 31139225Sgibbs int error; 31239852Simp board_id_data_t board_id; 31339225Sgibbs 31439225Sgibbs /* 31539225Sgibbs * See if the three I/O ports look reasonable. 31639225Sgibbs * Touch the minimal number of registers in the 31739225Sgibbs * failure case. 31839225Sgibbs */ 31939225Sgibbs status = aha_inb(aha, STATUS_REG); 32039225Sgibbs if ((status == 0) 32139225Sgibbs || (status & (DIAG_ACTIVE|CMD_REG_BUSY| 32241047Sgibbs STATUS_REG_RSVD)) != 0) { 32341047Sgibbs PRVERB(("%s: status reg test failed %x\n", aha_name(aha), 32441047Sgibbs status)); 32539225Sgibbs return (ENXIO); 32639225Sgibbs } 32739225Sgibbs 32839225Sgibbs intstat = aha_inb(aha, INTSTAT_REG); 32939225Sgibbs if ((intstat & INTSTAT_REG_RSVD) != 0) { 33041047Sgibbs PRVERB(("%s: Failed Intstat Reg Test\n", aha_name(aha))); 33139225Sgibbs return (ENXIO); 33239225Sgibbs } 33339225Sgibbs 33439225Sgibbs /* 33541047Sgibbs * Looking good so far. Final test is to reset the 33641047Sgibbs * adapter and fetch the board ID and ensure we aren't 33741047Sgibbs * looking at a BusLogic. 33841047Sgibbs */ 33941047Sgibbs if ((error = ahareset(aha, /*hard_reset*/TRUE)) != 0) { 34041047Sgibbs if (bootverbose) 34141047Sgibbs printf("%s: Failed Reset\n", aha_name(aha)); 34241047Sgibbs return (ENXIO); 34341047Sgibbs } 34441047Sgibbs 34541047Sgibbs /* 34639852Simp * Get the board ID. We use this to see if we're dealing with 34739852Simp * a buslogic card or a aha card (or clone). 34839225Sgibbs */ 34941047Sgibbs error = aha_cmd(aha, AOP_INQUIRE_BOARD_ID, NULL, /*parmlen*/0, 35039852Simp (u_int8_t*)&board_id, sizeof(board_id), 35139852Simp DEFAULT_CMD_TIMEOUT); 35239852Simp if (error != 0) { 35339881Simp PRVERB(("%s: INQUIRE failed %x\n", aha_name(aha), error)); 35439225Sgibbs return (ENXIO); 35539225Sgibbs } 35639852Simp aha->fw_major = board_id.firmware_rev_major; 35739852Simp aha->fw_minor = board_id.firmware_rev_minor; 35839852Simp aha->boardid = board_id.board_type; 35939852Simp 36039225Sgibbs /* 36139852Simp * The Buslogic cards have an id of either 0x41 or 0x42. So 36239852Simp * if those come up in the probe, we test the geometry register 36339852Simp * of the board. Adaptec boards that are this old will not have 36439852Simp * this register, and return 0xff, while buslogic cards will return 36539852Simp * something different. 36639852Simp * 36741335Simp * It appears that for reasons unknow, for the for the 36841335Simp * aha-1542B cards, we need to wait a little bit before trying 36941335Simp * to read the geometry register. I picked 10ms since we have 37041335Simp * reports that a for loop to 1000 did the trick, and this 37141335Simp * errs on the side of conservatism. Besides, no one will 37241335Simp * notice a 10mS delay here, even the 1542B card users :-) 37341335Simp * 37446997Simp * Some compatible cards return 0 here. Some cards also 37546997Simp * seem to return 0x7f. 37641807Simp * 37741335Simp * XXX I'm not sure how this will impact other cloned cards 37841807Simp * 37941807Simp * This really should be replaced with the esetup command, since 38046997Simp * that appears to be more reliable. This becomes more and more 38146997Simp * true over time as we discover more cards that don't read the 38246997Simp * geometry register consistantly. 38339225Sgibbs */ 38439852Simp if (aha->boardid <= 0x42) { 38541335Simp /* Wait 10ms before reading */ 38641335Simp DELAY(10000); 38739852Simp status = aha_inb(aha, GEOMETRY_REG); 38846997Simp if (status != 0xff && status != 0x00 && status != 0x7f) { 38944434Simp PRVERB(("%s: Geometry Register test failed 0x%x\n", 39044434Simp aha_name(aha), status)); 39139852Simp return (ENXIO); 39241047Sgibbs } 39339751Simp } 39439852Simp 39539225Sgibbs return (0); 39639225Sgibbs} 39739225Sgibbs 39839225Sgibbs/* 39939225Sgibbs * Pull the boards setup information and record it in our softc. 40039225Sgibbs */ 40139225Sgibbsint 40239225Sgibbsaha_fetch_adapter_info(struct aha_softc *aha) 40339225Sgibbs{ 40439225Sgibbs setup_data_t setup_info; 40539225Sgibbs config_data_t config_data; 40639225Sgibbs u_int8_t length_param; 40739225Sgibbs int error; 40839751Simp struct aha_extbios extbios; 40939225Sgibbs 41039852Simp switch (aha->boardid) { 41139225Sgibbs case BOARD_1540_16HEAD_BIOS: 41241514Sarchie snprintf(aha->model, sizeof(aha->model), "1540 16 head BIOS"); 41339225Sgibbs break; 41439225Sgibbs case BOARD_1540_64HEAD_BIOS: 41541514Sarchie snprintf(aha->model, sizeof(aha->model), "1540 64 head BIOS"); 41639225Sgibbs break; 41739225Sgibbs case BOARD_1542: 41841514Sarchie snprintf(aha->model, sizeof(aha->model), "1540/1542 64 head BIOS"); 41939225Sgibbs break; 42039225Sgibbs case BOARD_1640: 42141514Sarchie snprintf(aha->model, sizeof(aha->model), "1640"); 42239225Sgibbs break; 42339225Sgibbs case BOARD_1740: 42441514Sarchie snprintf(aha->model, sizeof(aha->model), "1740A/1742A/1744"); 42539225Sgibbs break; 42639225Sgibbs case BOARD_1542C: 42741514Sarchie snprintf(aha->model, sizeof(aha->model), "1542C"); 42839225Sgibbs break; 42939225Sgibbs case BOARD_1542CF: 43041514Sarchie snprintf(aha->model, sizeof(aha->model), "1542CF"); 43139225Sgibbs break; 43239225Sgibbs case BOARD_1542CP: 43341514Sarchie snprintf(aha->model, sizeof(aha->model), "1542CP"); 43439225Sgibbs break; 43539225Sgibbs default: 43641514Sarchie snprintf(aha->model, sizeof(aha->model), "Unknown"); 43739225Sgibbs break; 43839225Sgibbs } 43939751Simp /* 44039751Simp * If we are a new type of 1542 board (anything newer than a 1542C) 44139751Simp * then disable the extended bios so that the 44239751Simp * mailbox interface is unlocked. 44339751Simp * This is also true for the 1542B Version 3.20. First Adaptec 44439751Simp * board that supports >1Gb drives. 44539751Simp * No need to check the extended bios flags as some of the 44639751Simp * extensions that cause us problems are not flagged in that byte. 44739751Simp */ 44839751Simp if (PROBABLY_NEW_BOARD(aha->boardid) || 44939751Simp (aha->boardid == 0x41 45039852Simp && aha->fw_major == 0x31 && 45139852Simp aha->fw_minor >= 0x34)) { 45241047Sgibbs error = aha_cmd(aha, AOP_RETURN_EXT_BIOS_INFO, NULL, 45339751Simp /*paramlen*/0, (u_char *)&extbios, sizeof(extbios), 45439751Simp DEFAULT_CMD_TIMEOUT); 45541047Sgibbs error = aha_cmd(aha, AOP_MBOX_IF_ENABLE, (u_int8_t *)&extbios, 45639751Simp /*paramlen*/2, NULL, 0, DEFAULT_CMD_TIMEOUT); 45739751Simp } 45839751Simp if (aha->boardid < 0x41) 45941335Simp printf("%s: Warning: aha-1542A won't likely work.\n", 46039751Simp aha_name(aha)); 46139751Simp 46241335Simp aha->max_sg = 17; /* Need >= 17 to do 64k I/O */ 46339225Sgibbs aha->diff_bus = 0; 46439225Sgibbs aha->extended_lun = 0; 46539751Simp aha->extended_trans = 0; 46640403Simp aha->max_ccbs = 16; 46739225Sgibbs /* Determine Sync/Wide/Disc settings */ 46839225Sgibbs length_param = sizeof(setup_info); 46941047Sgibbs error = aha_cmd(aha, AOP_INQUIRE_SETUP_INFO, &length_param, 47039225Sgibbs /*paramlen*/1, (u_int8_t*)&setup_info, 47139225Sgibbs sizeof(setup_info), DEFAULT_CMD_TIMEOUT); 47239225Sgibbs if (error != 0) { 47339225Sgibbs printf("%s: aha_fetch_adapter_info - Failed " 47439225Sgibbs "Get Setup Info\n", aha_name(aha)); 47539225Sgibbs return (error); 47639225Sgibbs } 47739225Sgibbs if (setup_info.initiate_sync != 0) { 47839225Sgibbs aha->sync_permitted = ALL_TARGETS; 47939225Sgibbs } 48039225Sgibbs aha->disc_permitted = ALL_TARGETS; 48139225Sgibbs 48239225Sgibbs /* We need as many mailboxes as we can have ccbs */ 48339225Sgibbs aha->num_boxes = aha->max_ccbs; 48439225Sgibbs 48539225Sgibbs /* Determine our SCSI ID */ 48639225Sgibbs 48741047Sgibbs error = aha_cmd(aha, AOP_INQUIRE_CONFIG, NULL, /*parmlen*/0, 48839225Sgibbs (u_int8_t*)&config_data, sizeof(config_data), 48939225Sgibbs DEFAULT_CMD_TIMEOUT); 49039225Sgibbs if (error != 0) { 49139225Sgibbs printf("%s: aha_fetch_adapter_info - Failed Get Config\n", 49239225Sgibbs aha_name(aha)); 49339225Sgibbs return (error); 49439225Sgibbs } 49539225Sgibbs aha->scsi_id = config_data.scsi_id; 49639225Sgibbs return (0); 49739225Sgibbs} 49839225Sgibbs 49939225Sgibbs/* 50039225Sgibbs * Start the board, ready for normal operation 50139225Sgibbs */ 50239225Sgibbsint 50339225Sgibbsaha_init(struct aha_softc* aha) 50439225Sgibbs{ 50539225Sgibbs /* Announce the Adapter */ 50639852Simp printf("%s: AHA-%s FW Rev. %c.%c (ID=%x) ", aha_name(aha), 50739852Simp aha->model, aha->fw_major, aha->fw_minor, aha->boardid); 50839225Sgibbs 50939225Sgibbs if (aha->diff_bus != 0) 51039225Sgibbs printf("Diff "); 51139225Sgibbs 51239225Sgibbs printf("SCSI Host Adapter, SCSI ID %d, %d CCBs\n", aha->scsi_id, 51339225Sgibbs aha->max_ccbs); 51439225Sgibbs 51539225Sgibbs /* 51639225Sgibbs * Create our DMA tags. These tags define the kinds of device 51739225Sgibbs * accessable memory allocations and memory mappings we will 51839225Sgibbs * need to perform during normal operation. 51939225Sgibbs * 52039225Sgibbs * Unless we need to further restrict the allocation, we rely 52139225Sgibbs * on the restrictions of the parent dmat, hence the common 52239225Sgibbs * use of MAXADDR and MAXSIZE. 52339225Sgibbs */ 52439225Sgibbs 52539225Sgibbs /* DMA tag for mapping buffers into device visible space. */ 52639225Sgibbs if (bus_dma_tag_create(aha->parent_dmat, /*alignment*/0, /*boundary*/0, 52739225Sgibbs /*lowaddr*/BUS_SPACE_MAXADDR, 52839225Sgibbs /*highaddr*/BUS_SPACE_MAXADDR, 52939225Sgibbs /*filter*/NULL, /*filterarg*/NULL, 53039225Sgibbs /*maxsize*/MAXBSIZE, /*nsegments*/AHA_NSEG, 53139225Sgibbs /*maxsegsz*/BUS_SPACE_MAXSIZE_24BIT, 53239225Sgibbs /*flags*/BUS_DMA_ALLOCNOW, 53339225Sgibbs &aha->buffer_dmat) != 0) { 53439225Sgibbs goto error_exit; 53539225Sgibbs } 53639225Sgibbs 53739225Sgibbs aha->init_level++; 53839225Sgibbs /* DMA tag for our mailboxes */ 53939225Sgibbs if (bus_dma_tag_create(aha->parent_dmat, /*alignment*/0, /*boundary*/0, 54039225Sgibbs /*lowaddr*/BUS_SPACE_MAXADDR, 54139225Sgibbs /*highaddr*/BUS_SPACE_MAXADDR, 54239225Sgibbs /*filter*/NULL, /*filterarg*/NULL, 54339225Sgibbs aha->num_boxes * (sizeof(aha_mbox_in_t) 54439225Sgibbs + sizeof(aha_mbox_out_t)), 54539225Sgibbs /*nsegments*/1, 54639225Sgibbs /*maxsegsz*/BUS_SPACE_MAXSIZE_24BIT, 54739225Sgibbs /*flags*/0, &aha->mailbox_dmat) != 0) { 54839225Sgibbs goto error_exit; 54939225Sgibbs } 55039225Sgibbs 55139225Sgibbs aha->init_level++; 55239225Sgibbs 55339225Sgibbs /* Allocation for our mailboxes */ 55439225Sgibbs if (bus_dmamem_alloc(aha->mailbox_dmat, (void **)&aha->out_boxes, 55539225Sgibbs BUS_DMA_NOWAIT, &aha->mailbox_dmamap) != 0) { 55639225Sgibbs goto error_exit; 55739225Sgibbs } 55839225Sgibbs 55939225Sgibbs aha->init_level++; 56039225Sgibbs 56139225Sgibbs /* And permanently map them */ 56239225Sgibbs bus_dmamap_load(aha->mailbox_dmat, aha->mailbox_dmamap, 56339225Sgibbs aha->out_boxes, 56439225Sgibbs aha->num_boxes * (sizeof(aha_mbox_in_t) 56539225Sgibbs + sizeof(aha_mbox_out_t)), 56639225Sgibbs ahamapmboxes, aha, /*flags*/0); 56739225Sgibbs 56839225Sgibbs aha->init_level++; 56939225Sgibbs 57039225Sgibbs aha->in_boxes = (aha_mbox_in_t *)&aha->out_boxes[aha->num_boxes]; 57139225Sgibbs 57239225Sgibbs ahainitmboxes(aha); 57339225Sgibbs 57439225Sgibbs /* DMA tag for our ccb structures */ 57539225Sgibbs if (bus_dma_tag_create(aha->parent_dmat, /*alignment*/0, /*boundary*/0, 57639225Sgibbs /*lowaddr*/BUS_SPACE_MAXADDR, 57739225Sgibbs /*highaddr*/BUS_SPACE_MAXADDR, 57839225Sgibbs /*filter*/NULL, /*filterarg*/NULL, 57939225Sgibbs aha->max_ccbs * sizeof(struct aha_ccb), 58039225Sgibbs /*nsegments*/1, 58139225Sgibbs /*maxsegsz*/BUS_SPACE_MAXSIZE_24BIT, 58239225Sgibbs /*flags*/0, &aha->ccb_dmat) != 0) { 58339225Sgibbs goto error_exit; 58439225Sgibbs } 58539225Sgibbs 58639225Sgibbs aha->init_level++; 58739225Sgibbs 58839225Sgibbs /* Allocation for our ccbs */ 58939225Sgibbs if (bus_dmamem_alloc(aha->ccb_dmat, (void **)&aha->aha_ccb_array, 59039225Sgibbs BUS_DMA_NOWAIT, &aha->ccb_dmamap) != 0) { 59139225Sgibbs goto error_exit; 59239225Sgibbs } 59339225Sgibbs 59439225Sgibbs aha->init_level++; 59539225Sgibbs 59639225Sgibbs /* And permanently map them */ 59739225Sgibbs bus_dmamap_load(aha->ccb_dmat, aha->ccb_dmamap, 59839225Sgibbs aha->aha_ccb_array, 59939225Sgibbs aha->max_ccbs * sizeof(struct aha_ccb), 60039225Sgibbs ahamapccbs, aha, /*flags*/0); 60139225Sgibbs 60239225Sgibbs aha->init_level++; 60339225Sgibbs 60439225Sgibbs /* DMA tag for our S/G structures. We allocate in page sized chunks */ 60539225Sgibbs if (bus_dma_tag_create(aha->parent_dmat, /*alignment*/0, /*boundary*/0, 60639225Sgibbs /*lowaddr*/BUS_SPACE_MAXADDR, 60739225Sgibbs /*highaddr*/BUS_SPACE_MAXADDR, 60839225Sgibbs /*filter*/NULL, /*filterarg*/NULL, 60939225Sgibbs PAGE_SIZE, /*nsegments*/1, 61039225Sgibbs /*maxsegsz*/BUS_SPACE_MAXSIZE_24BIT, 61139225Sgibbs /*flags*/0, &aha->sg_dmat) != 0) { 61239225Sgibbs goto error_exit; 61339225Sgibbs } 61439225Sgibbs 61539225Sgibbs aha->init_level++; 61639225Sgibbs 61739225Sgibbs /* Perform initial CCB allocation */ 61839225Sgibbs bzero(aha->aha_ccb_array, aha->max_ccbs * sizeof(struct aha_ccb)); 61939225Sgibbs ahaallocccbs(aha); 62039225Sgibbs 62139225Sgibbs if (aha->num_ccbs == 0) { 62239324Sgibbs printf("%s: aha_init - Unable to allocate initial ccbs\n", 62339324Sgibbs aha_name(aha)); 62439225Sgibbs goto error_exit; 62539225Sgibbs } 62639225Sgibbs 62739225Sgibbs /* 62839225Sgibbs * Note that we are going and return (to probe) 62939225Sgibbs */ 63039225Sgibbs return 0; 63139225Sgibbs 63239225Sgibbserror_exit: 63339225Sgibbs 63439225Sgibbs return (ENXIO); 63539225Sgibbs} 63639225Sgibbs 63739225Sgibbsint 63839225Sgibbsaha_attach(struct aha_softc *aha) 63939225Sgibbs{ 64039225Sgibbs int tagged_dev_openings; 64139225Sgibbs struct cam_devq *devq; 64239225Sgibbs 64339225Sgibbs /* 64441335Simp * We don't do tagged queueing, since the aha cards don't 64541335Simp * support it. 64639225Sgibbs */ 64739225Sgibbs tagged_dev_openings = 0; 64839225Sgibbs 64939225Sgibbs /* 65039225Sgibbs * Create the device queue for our SIM. 65139225Sgibbs */ 65239225Sgibbs devq = cam_simq_alloc(aha->max_ccbs - 1); 65339225Sgibbs if (devq == NULL) 65439225Sgibbs return (ENOMEM); 65539225Sgibbs 65639225Sgibbs /* 65739225Sgibbs * Construct our SIM entry 65839225Sgibbs */ 65939225Sgibbs aha->sim = cam_sim_alloc(ahaaction, ahapoll, "aha", aha, aha->unit, 66039225Sgibbs 2, tagged_dev_openings, devq); 66139225Sgibbs if (aha->sim == NULL) { 66239225Sgibbs cam_simq_free(devq); 66339225Sgibbs return (ENOMEM); 66439225Sgibbs } 66539225Sgibbs 66639225Sgibbs if (xpt_bus_register(aha->sim, 0) != CAM_SUCCESS) { 66739225Sgibbs cam_sim_free(aha->sim, /*free_devq*/TRUE); 66839225Sgibbs return (ENXIO); 66939225Sgibbs } 67039225Sgibbs 67139225Sgibbs if (xpt_create_path(&aha->path, /*periph*/NULL, 67239225Sgibbs cam_sim_path(aha->sim), CAM_TARGET_WILDCARD, 67339225Sgibbs CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 67439225Sgibbs xpt_bus_deregister(cam_sim_path(aha->sim)); 67539225Sgibbs cam_sim_free(aha->sim, /*free_devq*/TRUE); 67639225Sgibbs return (ENXIO); 67739225Sgibbs } 67839225Sgibbs 67939225Sgibbs return (0); 68039225Sgibbs} 68139225Sgibbs 68239225Sgibbschar * 68339225Sgibbsaha_name(struct aha_softc *aha) 68439225Sgibbs{ 68539225Sgibbs static char name[10]; 68639225Sgibbs 68741514Sarchie snprintf(name, sizeof(name), "aha%d", aha->unit); 68839225Sgibbs return (name); 68939225Sgibbs} 69039225Sgibbs 69139225Sgibbsint 69239225Sgibbsaha_check_probed_iop(u_int ioport) 69339225Sgibbs{ 69439225Sgibbs u_int i; 69539225Sgibbs 69639225Sgibbs for (i=0; i < AHA_NUM_ISAPORTS; i++) { 69739225Sgibbs if (aha_isa_ports[i].addr == ioport) { 69839225Sgibbs if (aha_isa_ports[i].probed != 0) 69939225Sgibbs return (1); 70039225Sgibbs else { 70139225Sgibbs return (0); 70239225Sgibbs } 70339225Sgibbs } 70439225Sgibbs } 70539225Sgibbs return (1); 70639225Sgibbs} 70739225Sgibbs 70839225Sgibbsvoid 70939225Sgibbsaha_mark_probed_bio(isa_compat_io_t port) 71039225Sgibbs{ 71139225Sgibbs if (port < BIO_DISABLED) 71241047Sgibbs aha_mark_probed_iop(aha_board_ports[port]); 71339225Sgibbs} 71439225Sgibbs 71539225Sgibbsvoid 71639225Sgibbsaha_mark_probed_iop(u_int ioport) 71739225Sgibbs{ 71839225Sgibbs u_int i; 71939225Sgibbs 72039225Sgibbs for (i = 0; i < AHA_NUM_ISAPORTS; i++) { 72139225Sgibbs if (ioport == aha_isa_ports[i].addr) { 72239225Sgibbs aha_isa_ports[i].probed = 1; 72339225Sgibbs break; 72439225Sgibbs } 72539225Sgibbs } 72639225Sgibbs} 72739225Sgibbs 72841047Sgibbsvoid 72941047Sgibbsaha_find_probe_range(int ioport, int *port_index, int *max_port_index) 73041047Sgibbs{ 73141047Sgibbs if (ioport > 0) { 73241047Sgibbs int i; 73341047Sgibbs 73441047Sgibbs for (i = 0;i < AHA_NUM_ISAPORTS; i++) 73541047Sgibbs if (ioport <= aha_isa_ports[i].addr) 73641047Sgibbs break; 73741047Sgibbs if ((i >= AHA_NUM_ISAPORTS) 73841047Sgibbs || (ioport != aha_isa_ports[i].addr)) { 73942013Sgibbs printf("\n" 74042013Sgibbs"aha_isa_probe: Invalid baseport of 0x%x specified.\n" 74142013Sgibbs"aha_isa_probe: Nearest valid baseport is 0x%x.\n" 74242013Sgibbs"aha_isa_probe: Failing probe.\n", 74341047Sgibbs ioport, 74441047Sgibbs (i < AHA_NUM_ISAPORTS) 74541047Sgibbs ? aha_isa_ports[i].addr 74641047Sgibbs : aha_isa_ports[AHA_NUM_ISAPORTS - 1].addr); 74741047Sgibbs *port_index = *max_port_index = -1; 74841047Sgibbs return; 74941047Sgibbs } 75041047Sgibbs *port_index = *max_port_index = aha_isa_ports[i].bio; 75141047Sgibbs } else { 75241047Sgibbs *port_index = 0; 75341047Sgibbs *max_port_index = AHA_NUM_ISAPORTS - 1; 75441047Sgibbs } 75541047Sgibbs} 75641047Sgibbs 75741047Sgibbsint 75841047Sgibbsaha_iop_from_bio(isa_compat_io_t bio_index) 75941047Sgibbs{ 76041047Sgibbs if (bio_index >= 0 && bio_index < AHA_NUM_ISAPORTS) 76141047Sgibbs return (aha_board_ports[bio_index]); 76241047Sgibbs return (-1); 76341047Sgibbs} 76441047Sgibbs 76539225Sgibbsstatic void 76639225Sgibbsahaallocccbs(struct aha_softc *aha) 76739225Sgibbs{ 76839225Sgibbs struct aha_ccb *next_ccb; 76939225Sgibbs struct sg_map_node *sg_map; 77039225Sgibbs bus_addr_t physaddr; 77139225Sgibbs aha_sg_t *segs; 77239225Sgibbs int newcount; 77339225Sgibbs int i; 77439225Sgibbs 77539225Sgibbs next_ccb = &aha->aha_ccb_array[aha->num_ccbs]; 77639225Sgibbs 77739225Sgibbs sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT); 77839225Sgibbs 77939225Sgibbs if (sg_map == NULL) 78039225Sgibbs return; 78139225Sgibbs 78239225Sgibbs /* Allocate S/G space for the next batch of CCBS */ 78339225Sgibbs if (bus_dmamem_alloc(aha->sg_dmat, (void **)&sg_map->sg_vaddr, 78439225Sgibbs BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) { 78539225Sgibbs free(sg_map, M_DEVBUF); 78639225Sgibbs return; 78739225Sgibbs } 78839225Sgibbs 78939225Sgibbs SLIST_INSERT_HEAD(&aha->sg_maps, sg_map, links); 79039225Sgibbs 79139225Sgibbs bus_dmamap_load(aha->sg_dmat, sg_map->sg_dmamap, sg_map->sg_vaddr, 79239225Sgibbs PAGE_SIZE, ahamapsgs, aha, /*flags*/0); 79339225Sgibbs 79439225Sgibbs segs = sg_map->sg_vaddr; 79539225Sgibbs physaddr = sg_map->sg_physaddr; 79639225Sgibbs 79739225Sgibbs newcount = (PAGE_SIZE / (AHA_NSEG * sizeof(aha_sg_t))); 79839225Sgibbs for (i = 0; aha->num_ccbs < aha->max_ccbs && i < newcount; i++) { 79939225Sgibbs int error; 80039225Sgibbs 80139225Sgibbs next_ccb->sg_list = segs; 80239225Sgibbs next_ccb->sg_list_phys = physaddr; 80341047Sgibbs next_ccb->flags = ACCB_FREE; 80439225Sgibbs error = bus_dmamap_create(aha->buffer_dmat, /*flags*/0, 80539225Sgibbs &next_ccb->dmamap); 80639225Sgibbs if (error != 0) 80739225Sgibbs break; 80839225Sgibbs SLIST_INSERT_HEAD(&aha->free_aha_ccbs, next_ccb, links); 80939225Sgibbs segs += AHA_NSEG; 81039225Sgibbs physaddr += (AHA_NSEG * sizeof(aha_sg_t)); 81139225Sgibbs next_ccb++; 81239225Sgibbs aha->num_ccbs++; 81339225Sgibbs } 81439225Sgibbs 81539225Sgibbs /* Reserve a CCB for error recovery */ 81641047Sgibbs if (aha->recovery_accb == NULL) { 81741047Sgibbs aha->recovery_accb = SLIST_FIRST(&aha->free_aha_ccbs); 81839225Sgibbs SLIST_REMOVE_HEAD(&aha->free_aha_ccbs, links); 81939225Sgibbs } 82039225Sgibbs} 82139225Sgibbs 82239225Sgibbsstatic __inline void 82341047Sgibbsahafreeccb(struct aha_softc *aha, struct aha_ccb *accb) 82439225Sgibbs{ 82539225Sgibbs int s; 82639225Sgibbs 82739225Sgibbs s = splcam(); 82841047Sgibbs if ((accb->flags & ACCB_ACTIVE) != 0) 82941047Sgibbs LIST_REMOVE(&accb->ccb->ccb_h, sim_links.le); 83039225Sgibbs if (aha->resource_shortage != 0 83141047Sgibbs && (accb->ccb->ccb_h.status & CAM_RELEASE_SIMQ) == 0) { 83241047Sgibbs accb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 83339225Sgibbs aha->resource_shortage = FALSE; 83439225Sgibbs } 83541047Sgibbs accb->flags = ACCB_FREE; 83641047Sgibbs SLIST_INSERT_HEAD(&aha->free_aha_ccbs, accb, links); 83741047Sgibbs aha->active_ccbs--; 83839225Sgibbs splx(s); 83939225Sgibbs} 84039225Sgibbs 84139225Sgibbsstatic struct aha_ccb* 84239225Sgibbsahagetccb(struct aha_softc *aha) 84339225Sgibbs{ 84441047Sgibbs struct aha_ccb* accb; 84539225Sgibbs int s; 84639225Sgibbs 84739225Sgibbs s = splcam(); 84841047Sgibbs if ((accb = SLIST_FIRST(&aha->free_aha_ccbs)) != NULL) { 84939225Sgibbs SLIST_REMOVE_HEAD(&aha->free_aha_ccbs, links); 85041047Sgibbs aha->active_ccbs++; 85139225Sgibbs } else if (aha->num_ccbs < aha->max_ccbs) { 85239225Sgibbs ahaallocccbs(aha); 85341047Sgibbs accb = SLIST_FIRST(&aha->free_aha_ccbs); 85441047Sgibbs if (accb == NULL) 85541047Sgibbs printf("%s: Can't malloc ACCB\n", aha_name(aha)); 85641047Sgibbs else { 85739225Sgibbs SLIST_REMOVE_HEAD(&aha->free_aha_ccbs, links); 85841047Sgibbs aha->active_ccbs++; 85941047Sgibbs } 86039225Sgibbs } 86139225Sgibbs splx(s); 86239225Sgibbs 86341047Sgibbs return (accb); 86439225Sgibbs} 86539225Sgibbs 86639225Sgibbsstatic void 86739225Sgibbsahaaction(struct cam_sim *sim, union ccb *ccb) 86839225Sgibbs{ 86939225Sgibbs struct aha_softc *aha; 87039225Sgibbs 87139225Sgibbs CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("ahaaction\n")); 87239225Sgibbs 87339225Sgibbs aha = (struct aha_softc *)cam_sim_softc(sim); 87439225Sgibbs 87539225Sgibbs switch (ccb->ccb_h.func_code) { 87639225Sgibbs /* Common cases first */ 87739225Sgibbs case XPT_SCSI_IO: /* Execute the requested I/O operation */ 87839225Sgibbs case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ 87939225Sgibbs { 88041047Sgibbs struct aha_ccb *accb; 88139225Sgibbs struct aha_hccb *hccb; 88239225Sgibbs 88339225Sgibbs /* 88441047Sgibbs * get a accb to use. 88539225Sgibbs */ 88641047Sgibbs if ((accb = ahagetccb(aha)) == NULL) { 88739225Sgibbs int s; 88839225Sgibbs 88939225Sgibbs s = splcam(); 89039225Sgibbs aha->resource_shortage = TRUE; 89139225Sgibbs splx(s); 89239225Sgibbs xpt_freeze_simq(aha->sim, /*count*/1); 89339225Sgibbs ccb->ccb_h.status = CAM_REQUEUE_REQ; 89439225Sgibbs xpt_done(ccb); 89539225Sgibbs return; 89639225Sgibbs } 89739225Sgibbs 89841047Sgibbs hccb = &accb->hccb; 89939225Sgibbs 90039225Sgibbs /* 90141047Sgibbs * So we can find the ACCB when an abort is requested 90239225Sgibbs */ 90341047Sgibbs accb->ccb = ccb; 90441047Sgibbs ccb->ccb_h.ccb_accb_ptr = accb; 90539225Sgibbs ccb->ccb_h.ccb_aha_ptr = aha; 90639225Sgibbs 90739225Sgibbs /* 90841047Sgibbs * Put all the arguments for the xfer in the accb 90939225Sgibbs */ 91039225Sgibbs hccb->target = ccb->ccb_h.target_id; 91139225Sgibbs hccb->lun = ccb->ccb_h.target_lun; 91239225Sgibbs hccb->ahastat = 0; 91339225Sgibbs hccb->sdstat = 0; 91439225Sgibbs 91539225Sgibbs if (ccb->ccb_h.func_code == XPT_SCSI_IO) { 91639225Sgibbs struct ccb_scsiio *csio; 91739225Sgibbs struct ccb_hdr *ccbh; 91839225Sgibbs 91939225Sgibbs csio = &ccb->csio; 92039225Sgibbs ccbh = &csio->ccb_h; 92142887Simp hccb->opcode = aha->ccb_ccb_opcode; 92239225Sgibbs hccb->datain = (ccb->ccb_h.flags & CAM_DIR_IN) != 0; 92339225Sgibbs hccb->dataout = (ccb->ccb_h.flags & CAM_DIR_OUT) != 0; 92439225Sgibbs hccb->cmd_len = csio->cdb_len; 92539225Sgibbs if (hccb->cmd_len > sizeof(hccb->scsi_cdb)) { 92639225Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 92741047Sgibbs ahafreeccb(aha, accb); 92839225Sgibbs xpt_done(ccb); 92939225Sgibbs return; 93039225Sgibbs } 93139225Sgibbs hccb->sense_len = csio->sense_len; 93239225Sgibbs if ((ccbh->flags & CAM_CDB_POINTER) != 0) { 93339225Sgibbs if ((ccbh->flags & CAM_CDB_PHYS) == 0) { 93439225Sgibbs bcopy(csio->cdb_io.cdb_ptr, 93539225Sgibbs hccb->scsi_cdb, hccb->cmd_len); 93639225Sgibbs } else { 93739225Sgibbs /* I guess I could map it in... */ 93839225Sgibbs ccbh->status = CAM_REQ_INVALID; 93941047Sgibbs ahafreeccb(aha, accb); 94039225Sgibbs xpt_done(ccb); 94139225Sgibbs return; 94239225Sgibbs } 94339225Sgibbs } else { 94439225Sgibbs bcopy(csio->cdb_io.cdb_bytes, 94539225Sgibbs hccb->scsi_cdb, hccb->cmd_len); 94639225Sgibbs } 94739225Sgibbs /* 94839225Sgibbs * If we have any data to send with this command, 94939225Sgibbs * map it into bus space. 95039225Sgibbs */ 95139225Sgibbs /* Only use S/G if there is a transfer */ 95239225Sgibbs if ((ccbh->flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 95339225Sgibbs if ((ccbh->flags & CAM_SCATTER_VALID) == 0) { 95439225Sgibbs /* 95539225Sgibbs * We've been given a pointer 95639225Sgibbs * to a single buffer. 95739225Sgibbs */ 95839225Sgibbs if ((ccbh->flags & CAM_DATA_PHYS)==0) { 95939225Sgibbs int s; 96039225Sgibbs int error; 96139225Sgibbs 96239225Sgibbs s = splsoftvm(); 96339225Sgibbs error = bus_dmamap_load( 96439225Sgibbs aha->buffer_dmat, 96541047Sgibbs accb->dmamap, 96639225Sgibbs csio->data_ptr, 96739225Sgibbs csio->dxfer_len, 96839225Sgibbs ahaexecuteccb, 96941047Sgibbs accb, 97039225Sgibbs /*flags*/0); 97139225Sgibbs if (error == EINPROGRESS) { 97239225Sgibbs /* 97339225Sgibbs * So as to maintain 97439225Sgibbs * ordering, freeze the 97539225Sgibbs * controller queue 97639225Sgibbs * until our mapping is 97739225Sgibbs * returned. 97839225Sgibbs */ 97939225Sgibbs xpt_freeze_simq(aha->sim, 98039225Sgibbs 1); 98139225Sgibbs csio->ccb_h.status |= 98239225Sgibbs CAM_RELEASE_SIMQ; 98339225Sgibbs } 98439225Sgibbs splx(s); 98539225Sgibbs } else { 98639225Sgibbs struct bus_dma_segment seg; 98739225Sgibbs 98839225Sgibbs /* Pointer to physical buffer */ 98939225Sgibbs seg.ds_addr = 99039225Sgibbs (bus_addr_t)csio->data_ptr; 99139225Sgibbs seg.ds_len = csio->dxfer_len; 99241047Sgibbs ahaexecuteccb(accb, &seg, 1, 0); 99339225Sgibbs } 99439225Sgibbs } else { 99539225Sgibbs struct bus_dma_segment *segs; 99639225Sgibbs 99739225Sgibbs if ((ccbh->flags & CAM_DATA_PHYS) != 0) 99839225Sgibbs panic("ahaaction - Physical " 99939225Sgibbs "segment pointers " 100039225Sgibbs "unsupported"); 100139225Sgibbs 100239225Sgibbs if ((ccbh->flags&CAM_SG_LIST_PHYS)==0) 100339225Sgibbs panic("ahaaction - Virtual " 100439225Sgibbs "segment addresses " 100539225Sgibbs "unsupported"); 100639225Sgibbs 100739225Sgibbs /* Just use the segments provided */ 100839225Sgibbs segs = (struct bus_dma_segment *) 100939225Sgibbs csio->data_ptr; 101041047Sgibbs ahaexecuteccb(accb, segs, 101139225Sgibbs csio->sglist_cnt, 0); 101239225Sgibbs } 101339225Sgibbs } else { 101441047Sgibbs ahaexecuteccb(accb, NULL, 0, 0); 101539225Sgibbs } 101639225Sgibbs } else { 101739225Sgibbs hccb->opcode = INITIATOR_BUS_DEV_RESET; 101839225Sgibbs /* No data transfer */ 101939225Sgibbs hccb->datain = TRUE; 102039225Sgibbs hccb->dataout = TRUE; 102139225Sgibbs hccb->cmd_len = 0; 102239225Sgibbs hccb->sense_len = 0; 102341047Sgibbs ahaexecuteccb(accb, NULL, 0, 0); 102439225Sgibbs } 102539225Sgibbs break; 102639225Sgibbs } 102739225Sgibbs case XPT_EN_LUN: /* Enable LUN as a target */ 102839225Sgibbs case XPT_TARGET_IO: /* Execute target I/O request */ 102939225Sgibbs case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */ 103039225Sgibbs case XPT_CONT_TARGET_IO: /* Continue Host Target I/O Connection*/ 103139225Sgibbs case XPT_ABORT: /* Abort the specified CCB */ 103239225Sgibbs /* XXX Implement */ 103339225Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 103439225Sgibbs xpt_done(ccb); 103539225Sgibbs break; 103639225Sgibbs case XPT_SET_TRAN_SETTINGS: 103739225Sgibbs { 103839225Sgibbs /* XXX Implement */ 103946581Sken ccb->ccb_h.status = CAM_PROVIDE_FAIL; 104039225Sgibbs xpt_done(ccb); 104139225Sgibbs break; 104239225Sgibbs } 104339225Sgibbs case XPT_GET_TRAN_SETTINGS: 104439225Sgibbs /* Get default/user set transfer settings for the target */ 104539225Sgibbs { 104639225Sgibbs struct ccb_trans_settings *cts; 104739225Sgibbs u_int target_mask; 104839225Sgibbs 104939225Sgibbs cts = &ccb->cts; 105039225Sgibbs target_mask = 0x01 << ccb->ccb_h.target_id; 105139225Sgibbs if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) { 105239225Sgibbs cts->flags = 0; 105339225Sgibbs if ((aha->disc_permitted & target_mask) != 0) 105439225Sgibbs cts->flags |= CCB_TRANS_DISC_ENB; 105539225Sgibbs cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 105647506Sgibbs if ((aha->sync_permitted & target_mask) != 0) { 105747506Sgibbs if (aha->boardid >= BOARD_1542CF) 105847506Sgibbs cts->sync_period = 25; 105947506Sgibbs else 106047506Sgibbs cts->sync_period = 50; 106147506Sgibbs } else 106239225Sgibbs cts->sync_period = 0; 106339225Sgibbs 106439225Sgibbs if (cts->sync_period != 0) 106539225Sgibbs cts->sync_offset = 15; 106639225Sgibbs 106739225Sgibbs cts->valid = CCB_TRANS_SYNC_RATE_VALID 106839225Sgibbs | CCB_TRANS_SYNC_OFFSET_VALID 106939225Sgibbs | CCB_TRANS_BUS_WIDTH_VALID 107039225Sgibbs | CCB_TRANS_DISC_VALID 107139225Sgibbs | CCB_TRANS_TQ_VALID; 107239225Sgibbs } else { 107339225Sgibbs ahafetchtransinfo(aha, cts); 107439225Sgibbs } 107539225Sgibbs 107639225Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 107739225Sgibbs xpt_done(ccb); 107839225Sgibbs break; 107939225Sgibbs } 108039225Sgibbs case XPT_CALC_GEOMETRY: 108139225Sgibbs { 108239225Sgibbs struct ccb_calc_geometry *ccg; 108339225Sgibbs u_int32_t size_mb; 108439225Sgibbs u_int32_t secs_per_cylinder; 108539225Sgibbs 108639225Sgibbs ccg = &ccb->ccg; 108739225Sgibbs size_mb = ccg->volume_size 108839225Sgibbs / ((1024L * 1024L) / ccg->block_size); 108939225Sgibbs 109039225Sgibbs if (size_mb >= 1024 && (aha->extended_trans != 0)) { 109139225Sgibbs if (size_mb >= 2048) { 109239225Sgibbs ccg->heads = 255; 109339225Sgibbs ccg->secs_per_track = 63; 109439225Sgibbs } else { 109539225Sgibbs ccg->heads = 128; 109639225Sgibbs ccg->secs_per_track = 32; 109739225Sgibbs } 109839225Sgibbs } else { 109939225Sgibbs ccg->heads = 64; 110039225Sgibbs ccg->secs_per_track = 32; 110139225Sgibbs } 110239225Sgibbs secs_per_cylinder = ccg->heads * ccg->secs_per_track; 110339225Sgibbs ccg->cylinders = ccg->volume_size / secs_per_cylinder; 110439225Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 110539225Sgibbs xpt_done(ccb); 110639225Sgibbs break; 110739225Sgibbs } 110839225Sgibbs case XPT_RESET_BUS: /* Reset the specified SCSI bus */ 110939225Sgibbs { 111039225Sgibbs ahareset(aha, /*hardreset*/TRUE); 111139225Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 111239225Sgibbs xpt_done(ccb); 111339225Sgibbs break; 111439225Sgibbs } 111539225Sgibbs case XPT_TERM_IO: /* Terminate the I/O process */ 111639225Sgibbs /* XXX Implement */ 111739225Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 111839225Sgibbs xpt_done(ccb); 111939225Sgibbs break; 112039225Sgibbs case XPT_PATH_INQ: /* Path routing inquiry */ 112139225Sgibbs { 112239225Sgibbs struct ccb_pathinq *cpi = &ccb->cpi; 112339225Sgibbs 112439225Sgibbs cpi->version_num = 1; /* XXX??? */ 112539225Sgibbs cpi->hba_inquiry = PI_SDTR_ABLE; 112639225Sgibbs cpi->target_sprt = 0; 112739225Sgibbs cpi->hba_misc = 0; 112839225Sgibbs cpi->hba_eng_cnt = 0; 112939852Simp cpi->max_target = 7; 113039225Sgibbs cpi->max_lun = 7; 113139225Sgibbs cpi->initiator_id = aha->scsi_id; 113239225Sgibbs cpi->bus_id = cam_sim_bus(sim); 113346581Sken cpi->base_transfer_speed = 3300; 113439225Sgibbs strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 113539225Sgibbs strncpy(cpi->hba_vid, "Adaptec", HBA_IDLEN); 113639225Sgibbs strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 113739225Sgibbs cpi->unit_number = cam_sim_unit(sim); 113839225Sgibbs cpi->ccb_h.status = CAM_REQ_CMP; 113939225Sgibbs xpt_done(ccb); 114039225Sgibbs break; 114139225Sgibbs } 114239225Sgibbs default: 114339225Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 114439225Sgibbs xpt_done(ccb); 114539225Sgibbs break; 114639225Sgibbs } 114739225Sgibbs} 114839225Sgibbs 114939225Sgibbsstatic void 115039225Sgibbsahaexecuteccb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 115139225Sgibbs{ 115241047Sgibbs struct aha_ccb *accb; 115339225Sgibbs union ccb *ccb; 115439225Sgibbs struct aha_softc *aha; 115540419Sgibbs int s; 115639225Sgibbs u_int32_t paddr; 115739225Sgibbs 115841047Sgibbs accb = (struct aha_ccb *)arg; 115941047Sgibbs ccb = accb->ccb; 116039225Sgibbs aha = (struct aha_softc *)ccb->ccb_h.ccb_aha_ptr; 116139225Sgibbs 116239225Sgibbs if (error != 0) { 116339225Sgibbs if (error != EFBIG) 116439225Sgibbs printf("%s: Unexepected error 0x%x returned from " 116539324Sgibbs "bus_dmamap_load\n", aha_name(aha), error); 116639225Sgibbs if (ccb->ccb_h.status == CAM_REQ_INPROG) { 116739225Sgibbs xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 116839225Sgibbs ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN; 116939225Sgibbs } 117041047Sgibbs ahafreeccb(aha, accb); 117139225Sgibbs xpt_done(ccb); 117239225Sgibbs return; 117339225Sgibbs } 117439225Sgibbs 117539225Sgibbs if (nseg != 0) { 117639225Sgibbs aha_sg_t *sg; 117739225Sgibbs bus_dma_segment_t *end_seg; 117839225Sgibbs bus_dmasync_op_t op; 117939225Sgibbs 118039225Sgibbs end_seg = dm_segs + nseg; 118139225Sgibbs 118239225Sgibbs /* Copy the segments into our SG list */ 118341047Sgibbs sg = accb->sg_list; 118439225Sgibbs while (dm_segs < end_seg) { 118539225Sgibbs ahautoa24(dm_segs->ds_len, sg->len); 118639225Sgibbs ahautoa24(dm_segs->ds_addr, sg->addr); 118739225Sgibbs sg++; 118839225Sgibbs dm_segs++; 118939225Sgibbs } 119039225Sgibbs 119139225Sgibbs if (nseg > 1) { 119242887Simp accb->hccb.opcode = aha->ccb_sg_opcode; 119339225Sgibbs ahautoa24((sizeof(aha_sg_t) * nseg), 119441047Sgibbs accb->hccb.data_len); 119541047Sgibbs ahautoa24(accb->sg_list_phys, accb->hccb.data_addr); 119639225Sgibbs } else { 119741047Sgibbs bcopy(accb->sg_list->len, accb->hccb.data_len, 3); 119841047Sgibbs bcopy(accb->sg_list->addr, accb->hccb.data_addr, 3); 119939225Sgibbs } 120039225Sgibbs 120139225Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 120239225Sgibbs op = BUS_DMASYNC_PREREAD; 120339225Sgibbs else 120439225Sgibbs op = BUS_DMASYNC_PREWRITE; 120539225Sgibbs 120641047Sgibbs bus_dmamap_sync(aha->buffer_dmat, accb->dmamap, op); 120739225Sgibbs 120839225Sgibbs } else { 120941709Sgibbs accb->hccb.opcode = INITIATOR_CCB; 121041047Sgibbs ahautoa24(0, accb->hccb.data_len); 121141047Sgibbs ahautoa24(0, accb->hccb.data_addr); 121239225Sgibbs } 121339225Sgibbs 121439225Sgibbs s = splcam(); 121539225Sgibbs 121639225Sgibbs /* 121739225Sgibbs * Last time we need to check if this CCB needs to 121839225Sgibbs * be aborted. 121939225Sgibbs */ 122039225Sgibbs if (ccb->ccb_h.status != CAM_REQ_INPROG) { 122139225Sgibbs if (nseg != 0) 122241047Sgibbs bus_dmamap_unload(aha->buffer_dmat, accb->dmamap); 122341047Sgibbs ahafreeccb(aha, accb); 122439225Sgibbs xpt_done(ccb); 122539225Sgibbs splx(s); 122639225Sgibbs return; 122739225Sgibbs } 122839225Sgibbs 122941047Sgibbs accb->flags = ACCB_ACTIVE; 123039225Sgibbs ccb->ccb_h.status |= CAM_SIM_QUEUED; 123139225Sgibbs LIST_INSERT_HEAD(&aha->pending_ccbs, &ccb->ccb_h, sim_links.le); 123239225Sgibbs 123339225Sgibbs ccb->ccb_h.timeout_ch = 123441047Sgibbs timeout(ahatimeout, (caddr_t)accb, 123539225Sgibbs (ccb->ccb_h.timeout * hz) / 1000); 123639225Sgibbs 123739225Sgibbs /* Tell the adapter about this command */ 123841047Sgibbs if (aha->cur_outbox->action_code != AMBO_FREE) { 123941047Sgibbs /* 124041047Sgibbs * We should never encounter a busy mailbox. 124141047Sgibbs * If we do, warn the user, and treat it as 124241047Sgibbs * a resource shortage. If the controller is 124341047Sgibbs * hung, one of the pending transactions will 124441047Sgibbs * timeout causing us to start recovery operations. 124541047Sgibbs */ 124641047Sgibbs printf("%s: Encountered busy mailbox with %d out of %d " 124741047Sgibbs "commands active!!!", aha_name(aha), aha->active_ccbs, 124841047Sgibbs aha->max_ccbs); 124941047Sgibbs untimeout(ahatimeout, accb, ccb->ccb_h.timeout_ch); 125041047Sgibbs if (nseg != 0) 125141047Sgibbs bus_dmamap_unload(aha->buffer_dmat, accb->dmamap); 125241047Sgibbs ahafreeccb(aha, accb); 125341047Sgibbs aha->resource_shortage = TRUE; 125441047Sgibbs xpt_freeze_simq(aha->sim, /*count*/1); 125541047Sgibbs ccb->ccb_h.status = CAM_REQUEUE_REQ; 125641047Sgibbs xpt_done(ccb); 125741047Sgibbs return; 125841047Sgibbs } 125941047Sgibbs paddr = ahaccbvtop(aha, accb); 126039225Sgibbs ahautoa24(paddr, aha->cur_outbox->ccb_addr); 126141047Sgibbs aha->cur_outbox->action_code = AMBO_START; 126241047Sgibbs aha_outb(aha, COMMAND_REG, AOP_START_MBOX); 126339225Sgibbs 126439225Sgibbs ahanextoutbox(aha); 126539225Sgibbs splx(s); 126639225Sgibbs} 126739225Sgibbs 126839225Sgibbsvoid 126939225Sgibbsaha_intr(void *arg) 127039225Sgibbs{ 127139225Sgibbs struct aha_softc *aha; 127239225Sgibbs u_int intstat; 127339225Sgibbs 127439225Sgibbs aha = (struct aha_softc *)arg; 127539225Sgibbs while (((intstat = aha_inb(aha, INTSTAT_REG)) & INTR_PENDING) != 0) { 127639225Sgibbs if ((intstat & CMD_COMPLETE) != 0) { 127739225Sgibbs aha->latched_status = aha_inb(aha, STATUS_REG); 127839225Sgibbs aha->command_cmp = TRUE; 127939225Sgibbs } 128039225Sgibbs 128139225Sgibbs aha_outb(aha, CONTROL_REG, RESET_INTR); 128239225Sgibbs 128339225Sgibbs if ((intstat & IMB_LOADED) != 0) { 128441047Sgibbs while (aha->cur_inbox->comp_code != AMBI_FREE) { 128539225Sgibbs u_int32_t paddr; 128639225Sgibbs paddr = aha_a24tou(aha->cur_inbox->ccb_addr); 128739225Sgibbs ahadone(aha, 128839225Sgibbs ahaccbptov(aha, paddr), 128939225Sgibbs aha->cur_inbox->comp_code); 129041047Sgibbs aha->cur_inbox->comp_code = AMBI_FREE; 129139225Sgibbs ahanextinbox(aha); 129239225Sgibbs } 129339225Sgibbs } 129439225Sgibbs 129539225Sgibbs if ((intstat & SCSI_BUS_RESET) != 0) { 129639225Sgibbs ahareset(aha, /*hardreset*/FALSE); 129739225Sgibbs } 129839225Sgibbs } 129939225Sgibbs} 130039225Sgibbs 130139225Sgibbsstatic void 130241047Sgibbsahadone(struct aha_softc *aha, struct aha_ccb *accb, aha_mbi_comp_code_t comp_code) 130339225Sgibbs{ 130439225Sgibbs union ccb *ccb; 130539225Sgibbs struct ccb_scsiio *csio; 130639225Sgibbs 130741047Sgibbs ccb = accb->ccb; 130841047Sgibbs csio = &accb->ccb->csio; 130939225Sgibbs 131041047Sgibbs if ((accb->flags & ACCB_ACTIVE) == 0) { 131141047Sgibbs printf("%s: ahadone - Attempt to free non-active ACCB %p\n", 131241047Sgibbs aha_name(aha), (void *)accb); 131339225Sgibbs return; 131439225Sgibbs } 131539225Sgibbs 131639225Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 131739225Sgibbs bus_dmasync_op_t op; 131839225Sgibbs 131939225Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 132039225Sgibbs op = BUS_DMASYNC_POSTREAD; 132139225Sgibbs else 132239225Sgibbs op = BUS_DMASYNC_POSTWRITE; 132341047Sgibbs bus_dmamap_sync(aha->buffer_dmat, accb->dmamap, op); 132441047Sgibbs bus_dmamap_unload(aha->buffer_dmat, accb->dmamap); 132539225Sgibbs } 132639225Sgibbs 132741047Sgibbs if (accb == aha->recovery_accb) { 132839225Sgibbs /* 132941047Sgibbs * The recovery ACCB does not have a CCB associated 133039225Sgibbs * with it, so short circuit the normal error handling. 133139225Sgibbs * We now traverse our list of pending CCBs and process 133239225Sgibbs * any that were terminated by the recovery CCBs action. 133339225Sgibbs * We also reinstate timeouts for all remaining, pending, 133439225Sgibbs * CCBs. 133539225Sgibbs */ 133639225Sgibbs struct cam_path *path; 133739225Sgibbs struct ccb_hdr *ccb_h; 133839225Sgibbs cam_status error; 133939225Sgibbs 134039225Sgibbs /* Notify all clients that a BDR occured */ 134139225Sgibbs error = xpt_create_path(&path, /*periph*/NULL, 134239225Sgibbs cam_sim_path(aha->sim), 134341047Sgibbs accb->hccb.target, 134439225Sgibbs CAM_LUN_WILDCARD); 134539225Sgibbs 134639225Sgibbs if (error == CAM_REQ_CMP) 134739225Sgibbs xpt_async(AC_SENT_BDR, path, NULL); 134839225Sgibbs 134939225Sgibbs ccb_h = LIST_FIRST(&aha->pending_ccbs); 135039225Sgibbs while (ccb_h != NULL) { 135141047Sgibbs struct aha_ccb *pending_accb; 135239225Sgibbs 135341047Sgibbs pending_accb = (struct aha_ccb *)ccb_h->ccb_accb_ptr; 135441047Sgibbs if (pending_accb->hccb.target == accb->hccb.target) { 135541047Sgibbs pending_accb->hccb.ahastat = AHASTAT_HA_BDR; 135639225Sgibbs ccb_h = LIST_NEXT(ccb_h, sim_links.le); 135741047Sgibbs ahadone(aha, pending_accb, AMBI_ERROR); 135839225Sgibbs } else { 135939225Sgibbs ccb_h->timeout_ch = 136041047Sgibbs timeout(ahatimeout, (caddr_t)pending_accb, 136139225Sgibbs (ccb_h->timeout * hz) / 1000); 136239225Sgibbs ccb_h = LIST_NEXT(ccb_h, sim_links.le); 136339225Sgibbs } 136439225Sgibbs } 136539225Sgibbs printf("%s: No longer in timeout\n", aha_name(aha)); 136639225Sgibbs return; 136739225Sgibbs } 136839225Sgibbs 136941047Sgibbs untimeout(ahatimeout, accb, ccb->ccb_h.timeout_ch); 137039225Sgibbs 137139225Sgibbs switch (comp_code) { 137241047Sgibbs case AMBI_FREE: 137339225Sgibbs printf("%s: ahadone - CCB completed with free status!\n", 137439225Sgibbs aha_name(aha)); 137539225Sgibbs break; 137641047Sgibbs case AMBI_NOT_FOUND: 137739225Sgibbs printf("%s: ahadone - CCB Abort failed to find CCB\n", 137839225Sgibbs aha_name(aha)); 137939225Sgibbs break; 138041047Sgibbs case AMBI_ABORT: 138141047Sgibbs case AMBI_ERROR: 138239225Sgibbs /* An error occured */ 138342887Simp if (accb->hccb.opcode < INITIATOR_CCB_WRESID) 138442887Simp csio->resid = 0; 138542887Simp else 138642887Simp csio->resid = aha_a24tou(accb->hccb.data_len); 138741047Sgibbs switch(accb->hccb.ahastat) { 138839225Sgibbs case AHASTAT_DATARUN_ERROR: 138942013Sgibbs { 139042013Sgibbs if (csio->resid <= 0) { 139139225Sgibbs csio->ccb_h.status = CAM_DATA_RUN_ERR; 139239225Sgibbs break; 139339225Sgibbs } 139439225Sgibbs /* FALLTHROUGH */ 139542013Sgibbs } 139639225Sgibbs case AHASTAT_NOERROR: 139741047Sgibbs csio->scsi_status = accb->hccb.sdstat; 139839225Sgibbs csio->ccb_h.status |= CAM_SCSI_STATUS_ERROR; 139939225Sgibbs switch(csio->scsi_status) { 140039225Sgibbs case SCSI_STATUS_CHECK_COND: 140139225Sgibbs case SCSI_STATUS_CMD_TERMINATED: 140239225Sgibbs csio->ccb_h.status |= CAM_AUTOSNS_VALID; 140339225Sgibbs /* 140439225Sgibbs * The aha writes the sense data at different 140539225Sgibbs * offsets based on the scsi cmd len 140639225Sgibbs */ 140741047Sgibbs bcopy((caddr_t) &accb->hccb.scsi_cdb + 140841047Sgibbs accb->hccb.cmd_len, 140939225Sgibbs (caddr_t) &csio->sense_data, 141041047Sgibbs accb->hccb.sense_len); 141139225Sgibbs break; 141239225Sgibbs default: 141339225Sgibbs break; 141439225Sgibbs case SCSI_STATUS_OK: 141539225Sgibbs csio->ccb_h.status = CAM_REQ_CMP; 141639225Sgibbs break; 141739225Sgibbs } 141839225Sgibbs break; 141939225Sgibbs case AHASTAT_SELTIMEOUT: 142039225Sgibbs csio->ccb_h.status = CAM_SEL_TIMEOUT; 142139225Sgibbs break; 142239225Sgibbs case AHASTAT_UNEXPECTED_BUSFREE: 142339225Sgibbs csio->ccb_h.status = CAM_UNEXP_BUSFREE; 142439225Sgibbs break; 142539225Sgibbs case AHASTAT_INVALID_PHASE: 142639225Sgibbs csio->ccb_h.status = CAM_SEQUENCE_FAIL; 142739225Sgibbs break; 142839225Sgibbs case AHASTAT_INVALID_ACTION_CODE: 142939225Sgibbs panic("%s: Inavlid Action code", aha_name(aha)); 143039225Sgibbs break; 143139225Sgibbs case AHASTAT_INVALID_OPCODE: 143242887Simp if (accb->hccb.opcode < INITIATOR_CCB_WRESID) 143342887Simp panic("%s: Invalid CCB Opcode %x hccb = %p", 143442887Simp aha_name(aha), accb->hccb.opcode, 143542887Simp &accb->hccb); 143642887Simp printf("%s: AHA-1540A detected, compensating\n", 143742887Simp aha_name(aha)); 143842887Simp aha->ccb_sg_opcode = INITIATOR_SG_CCB; 143942887Simp aha->ccb_ccb_opcode = INITIATOR_CCB; 144042887Simp xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 144142887Simp csio->ccb_h.status = CAM_REQUEUE_REQ; 144239225Sgibbs break; 144339225Sgibbs case AHASTAT_LINKED_CCB_LUN_MISMATCH: 144439225Sgibbs /* We don't even support linked commands... */ 144539225Sgibbs panic("%s: Linked CCB Lun Mismatch", aha_name(aha)); 144639225Sgibbs break; 144739225Sgibbs case AHASTAT_INVALID_CCB_OR_SG_PARAM: 144839225Sgibbs panic("%s: Invalid CCB or SG list", aha_name(aha)); 144939225Sgibbs break; 145039225Sgibbs case AHASTAT_HA_SCSI_BUS_RESET: 145139225Sgibbs if ((csio->ccb_h.status & CAM_STATUS_MASK) 145242887Simp != CAM_CMD_TIMEOUT) 145339225Sgibbs csio->ccb_h.status = CAM_SCSI_BUS_RESET; 145439225Sgibbs break; 145539225Sgibbs case AHASTAT_HA_BDR: 145641047Sgibbs if ((accb->flags & ACCB_DEVICE_RESET) == 0) 145739225Sgibbs csio->ccb_h.status = CAM_BDR_SENT; 145839225Sgibbs else 145939225Sgibbs csio->ccb_h.status = CAM_CMD_TIMEOUT; 146039225Sgibbs break; 146139225Sgibbs } 146239225Sgibbs if (csio->ccb_h.status != CAM_REQ_CMP) { 146339225Sgibbs xpt_freeze_devq(csio->ccb_h.path, /*count*/1); 146439225Sgibbs csio->ccb_h.status |= CAM_DEV_QFRZN; 146539225Sgibbs } 146641047Sgibbs if ((accb->flags & ACCB_RELEASE_SIMQ) != 0) 146739225Sgibbs ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 146841047Sgibbs ahafreeccb(aha, accb); 146939225Sgibbs xpt_done(ccb); 147039225Sgibbs break; 147141047Sgibbs case AMBI_OK: 147239225Sgibbs /* All completed without incident */ 147339225Sgibbs /* XXX DO WE NEED TO COPY SENSE BYTES HERE???? XXX */ 147442887Simp /* I don't think so since it works???? */ 147539225Sgibbs ccb->ccb_h.status |= CAM_REQ_CMP; 147641047Sgibbs if ((accb->flags & ACCB_RELEASE_SIMQ) != 0) 147739225Sgibbs ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 147841047Sgibbs ahafreeccb(aha, accb); 147939225Sgibbs xpt_done(ccb); 148039225Sgibbs break; 148139225Sgibbs } 148239225Sgibbs} 148339225Sgibbs 148439225Sgibbsstatic int 148539225Sgibbsahareset(struct aha_softc* aha, int hard_reset) 148639225Sgibbs{ 148739225Sgibbs struct ccb_hdr *ccb_h; 148839225Sgibbs u_int status; 148939225Sgibbs u_int timeout; 149039225Sgibbs u_int8_t reset_type; 149139225Sgibbs 149239225Sgibbs if (hard_reset != 0) 149339225Sgibbs reset_type = HARD_RESET; 149439225Sgibbs else 149539225Sgibbs reset_type = SOFT_RESET; 149639225Sgibbs aha_outb(aha, CONTROL_REG, reset_type); 149739225Sgibbs 149839225Sgibbs /* Wait 5sec. for Diagnostic start */ 149939225Sgibbs timeout = 5 * 10000; 150039225Sgibbs while (--timeout) { 150139225Sgibbs status = aha_inb(aha, STATUS_REG); 150239225Sgibbs if ((status & DIAG_ACTIVE) != 0) 150339225Sgibbs break; 150439225Sgibbs DELAY(100); 150539225Sgibbs } 150639225Sgibbs if (timeout == 0) { 150739881Simp PRVERB(("%s: ahareset - Diagnostic Active failed to " 150839881Simp "assert. status = 0x%x\n", aha_name(aha), 150939881Simp status)); 151039225Sgibbs return (ETIMEDOUT); 151139225Sgibbs } 151239225Sgibbs 151339225Sgibbs /* Wait 10sec. for Diagnostic end */ 151439225Sgibbs timeout = 10 * 10000; 151539225Sgibbs while (--timeout) { 151639225Sgibbs status = aha_inb(aha, STATUS_REG); 151739225Sgibbs if ((status & DIAG_ACTIVE) == 0) 151839225Sgibbs break; 151939225Sgibbs DELAY(100); 152039225Sgibbs } 152139225Sgibbs if (timeout == 0) { 152239225Sgibbs panic("%s: ahareset - Diagnostic Active failed to drop. " 152339225Sgibbs "status = 0x%x\n", aha_name(aha), status); 152439225Sgibbs return (ETIMEDOUT); 152539225Sgibbs } 152639225Sgibbs 152739225Sgibbs /* Wait for the host adapter to become ready or report a failure */ 152839225Sgibbs timeout = 10000; 152939225Sgibbs while (--timeout) { 153039225Sgibbs status = aha_inb(aha, STATUS_REG); 153139225Sgibbs if ((status & (DIAG_FAIL|HA_READY|DATAIN_REG_READY)) != 0) 153239225Sgibbs break; 153339225Sgibbs DELAY(100); 153439225Sgibbs } 153539225Sgibbs if (timeout == 0) { 153639225Sgibbs printf("%s: ahareset - Host adapter failed to come ready. " 153739225Sgibbs "status = 0x%x\n", aha_name(aha), status); 153839225Sgibbs return (ETIMEDOUT); 153939225Sgibbs } 154039225Sgibbs 154139225Sgibbs /* If the diagnostics failed, tell the user */ 154239225Sgibbs if ((status & DIAG_FAIL) != 0 154339225Sgibbs || (status & HA_READY) == 0) { 154439225Sgibbs printf("%s: ahareset - Adapter failed diagnostics\n", 154539225Sgibbs aha_name(aha)); 154639225Sgibbs 154739225Sgibbs if ((status & DATAIN_REG_READY) != 0) 154839324Sgibbs printf("%s: ahareset - Host Adapter Error " 154939324Sgibbs "code = 0x%x\n", aha_name(aha), 155039225Sgibbs aha_inb(aha, DATAIN_REG)); 155139225Sgibbs return (ENXIO); 155239225Sgibbs } 155339225Sgibbs 155439225Sgibbs /* If we've allocated mailboxes, initialize them */ 155539225Sgibbs if (aha->init_level > 4) 155639225Sgibbs ahainitmboxes(aha); 155739225Sgibbs 155839225Sgibbs /* If we've attached to the XPT, tell it about the event */ 155939225Sgibbs if (aha->path != NULL) 156039225Sgibbs xpt_async(AC_BUS_RESET, aha->path, NULL); 156139225Sgibbs 156239225Sgibbs /* 156339225Sgibbs * Perform completion processing for all outstanding CCBs. 156439225Sgibbs */ 156539225Sgibbs while ((ccb_h = LIST_FIRST(&aha->pending_ccbs)) != NULL) { 156641047Sgibbs struct aha_ccb *pending_accb; 156739225Sgibbs 156841047Sgibbs pending_accb = (struct aha_ccb *)ccb_h->ccb_accb_ptr; 156941047Sgibbs pending_accb->hccb.ahastat = AHASTAT_HA_SCSI_BUS_RESET; 157041047Sgibbs ahadone(aha, pending_accb, AMBI_ERROR); 157139225Sgibbs } 157239225Sgibbs 157339225Sgibbs return (0); 157439225Sgibbs} 157539225Sgibbs 157639225Sgibbs/* 157739225Sgibbs * Send a command to the adapter. 157839225Sgibbs */ 157939225Sgibbsint 158039225Sgibbsaha_cmd(struct aha_softc *aha, aha_op_t opcode, u_int8_t *params, 158147506Sgibbs u_int param_len, u_int8_t *reply_data, u_int reply_len, 158247506Sgibbs u_int cmd_timeout) 158339225Sgibbs{ 158439225Sgibbs u_int timeout; 158539225Sgibbs u_int status; 158647506Sgibbs u_int saved_status; 158739225Sgibbs u_int intstat; 158839225Sgibbs u_int reply_buf_size; 158939225Sgibbs int s; 159041709Sgibbs int cmd_complete; 159147506Sgibbs int error; 159239225Sgibbs 159339225Sgibbs /* No data returned to start */ 159439225Sgibbs reply_buf_size = reply_len; 159539225Sgibbs reply_len = 0; 159639225Sgibbs intstat = 0; 159741709Sgibbs cmd_complete = 0; 159847506Sgibbs saved_status = 0; 159947506Sgibbs error = 0; 160039225Sgibbs 160147506Sgibbs /* 160247506Sgibbs * All commands except for the "start mailbox" and the "enable 160347506Sgibbs * outgoing mailbox read interrupt" commands cannot be issued 160447506Sgibbs * while there are pending transactions. Freeze our SIMQ 160547506Sgibbs * and wait for all completions to occur if necessary. 160647506Sgibbs */ 160747506Sgibbs timeout = 100000; 160847506Sgibbs s = splcam(); 160947506Sgibbs while (LIST_FIRST(&aha->pending_ccbs) != NULL && --timeout) { 161047506Sgibbs /* Fire the interrupt handler in case interrupts are blocked */ 161147506Sgibbs aha_intr(aha); 161247506Sgibbs splx(s); 161347506Sgibbs DELAY(100); 161447506Sgibbs s = splcam(); 161547506Sgibbs } 161647506Sgibbs splx(s); 161747506Sgibbs 161847506Sgibbs if (timeout == 0) { 161947506Sgibbs printf("%s: aha_cmd: Timeout waiting for adapter idle\n", 162047506Sgibbs aha_name(aha)); 162147506Sgibbs return (ETIMEDOUT); 162247506Sgibbs } 162339225Sgibbs aha->command_cmp = 0; 162439225Sgibbs /* 162547506Sgibbs * Wait up to 10 sec. for the adapter to become 162639225Sgibbs * ready to accept commands. 162739225Sgibbs */ 162847506Sgibbs timeout = 100000; 162939225Sgibbs while (--timeout) { 163039225Sgibbs 163139225Sgibbs status = aha_inb(aha, STATUS_REG); 163239225Sgibbs if ((status & HA_READY) != 0 163339225Sgibbs && (status & CMD_REG_BUSY) == 0) 163439225Sgibbs break; 163547506Sgibbs /* 163647506Sgibbs * Throw away any pending data which may be 163747506Sgibbs * left over from earlier commands that we 163847506Sgibbs * timedout on. 163947506Sgibbs */ 164047506Sgibbs if ((status & DATAIN_REG_READY) != 0) 164147506Sgibbs (void)aha_inb(aha, DATAIN_REG); 164239225Sgibbs DELAY(100); 164339225Sgibbs } 164439225Sgibbs if (timeout == 0) { 164539225Sgibbs printf("%s: aha_cmd: Timeout waiting for adapter ready, " 164639225Sgibbs "status = 0x%x\n", aha_name(aha), status); 164739225Sgibbs return (ETIMEDOUT); 164839225Sgibbs } 164939225Sgibbs 165039225Sgibbs /* 165139225Sgibbs * Send the opcode followed by any necessary parameter bytes. 165239225Sgibbs */ 165339225Sgibbs aha_outb(aha, COMMAND_REG, opcode); 165439225Sgibbs 165539225Sgibbs /* 165639225Sgibbs * Wait for up to 1sec to get the parameter list sent 165739225Sgibbs */ 165839225Sgibbs timeout = 10000; 165939225Sgibbs while (param_len && --timeout) { 166039225Sgibbs DELAY(100); 166147506Sgibbs s = splcam(); 166239225Sgibbs status = aha_inb(aha, STATUS_REG); 166339225Sgibbs intstat = aha_inb(aha, INTSTAT_REG); 166447506Sgibbs splx(s); 166547506Sgibbs 166639225Sgibbs if ((intstat & (INTR_PENDING|CMD_COMPLETE)) 166741709Sgibbs == (INTR_PENDING|CMD_COMPLETE)) { 166847506Sgibbs saved_status = status; 166941709Sgibbs cmd_complete = 1; 167039225Sgibbs break; 167141709Sgibbs } 167247506Sgibbs 167339225Sgibbs if (aha->command_cmp != 0) { 167447506Sgibbs saved_status = aha->latched_status; 167541709Sgibbs cmd_complete = 1; 167639225Sgibbs break; 167739225Sgibbs } 167839225Sgibbs if ((status & DATAIN_REG_READY) != 0) 167939225Sgibbs break; 168039225Sgibbs if ((status & CMD_REG_BUSY) == 0) { 168139225Sgibbs aha_outb(aha, COMMAND_REG, *params++); 168239225Sgibbs param_len--; 168347506Sgibbs timeout = 10000; 168439225Sgibbs } 168539225Sgibbs } 168639225Sgibbs if (timeout == 0) { 168739225Sgibbs printf("%s: aha_cmd: Timeout sending parameters, " 168839225Sgibbs "status = 0x%x\n", aha_name(aha), status); 168947506Sgibbs error = ETIMEDOUT; 169039225Sgibbs } 169139225Sgibbs 169239225Sgibbs /* 169339225Sgibbs * For all other commands, we wait for any output data 169439225Sgibbs * and the final comand completion interrupt. 169539225Sgibbs */ 169641709Sgibbs while (cmd_complete == 0 && --cmd_timeout) { 169739225Sgibbs 169847506Sgibbs s = splcam(); 169939225Sgibbs status = aha_inb(aha, STATUS_REG); 170039225Sgibbs intstat = aha_inb(aha, INTSTAT_REG); 170147506Sgibbs splx(s); 170239225Sgibbs 170339225Sgibbs if (aha->command_cmp != 0) { 170447506Sgibbs cmd_complete = 1; 170547506Sgibbs saved_status = aha->latched_status; 170647506Sgibbs } else if ((intstat & (INTR_PENDING|CMD_COMPLETE)) 170747506Sgibbs == (INTR_PENDING|CMD_COMPLETE)) { 170847506Sgibbs /* 170947506Sgibbs * Our poll (in case interrupts are blocked) 171047506Sgibbs * saw the CMD_COMPLETE interrupt. 171147506Sgibbs */ 171247506Sgibbs cmd_complete = 1; 171347506Sgibbs saved_status = status; 171447506Sgibbs } else if ((status & DATAIN_REG_READY) != 0) { 171539225Sgibbs u_int8_t data; 171639225Sgibbs 171739225Sgibbs data = aha_inb(aha, DATAIN_REG); 171839225Sgibbs if (reply_len < reply_buf_size) { 171939225Sgibbs *reply_data++ = data; 172039225Sgibbs } else { 172147506Sgibbs printf("%s: aha_cmd - Discarded reply data " 172247506Sgibbs "byte for opcode 0x%x\n", aha_name(aha), 172339225Sgibbs opcode); 172439225Sgibbs } 172547506Sgibbs /* 172647506Sgibbs * Reset timeout to ensure at least a second 172747506Sgibbs * between response bytes. 172847506Sgibbs */ 172947506Sgibbs cmd_timeout = MAX(cmd_timeout, 10000); 173039225Sgibbs reply_len++; 173139225Sgibbs } 173239225Sgibbs DELAY(100); 173339225Sgibbs } 173447506Sgibbs if (cmd_timeout == 0) { 173539225Sgibbs printf("%s: aha_cmd: Timeout waiting for reply data and " 173639225Sgibbs "command complete.\n%s: status = 0x%x, intstat = 0x%x, " 173739225Sgibbs "reply_len = %d\n", aha_name(aha), aha_name(aha), status, 173839225Sgibbs intstat, reply_len); 173939225Sgibbs return (ETIMEDOUT); 174039225Sgibbs } 174139225Sgibbs 174239225Sgibbs /* 174339225Sgibbs * Clear any pending interrupts. Block interrupts so our 174439225Sgibbs * interrupt handler is not re-entered. 174539225Sgibbs */ 174639225Sgibbs s = splcam(); 174739225Sgibbs aha_intr(aha); 174839225Sgibbs splx(s); 174939225Sgibbs 175047506Sgibbs if (error != 0) 175147506Sgibbs return (error); 175247506Sgibbs 175339225Sgibbs /* 175439225Sgibbs * If the command was rejected by the controller, tell the caller. 175539225Sgibbs */ 175647506Sgibbs if ((saved_status & CMD_INVALID) != 0) { 175739881Simp PRVERB(("%s: Invalid Command 0x%x\n", aha_name(aha), opcode)); 175839225Sgibbs /* 175939225Sgibbs * Some early adapters may not recover properly from 176039225Sgibbs * an invalid command. If it appears that the controller 176139225Sgibbs * has wedged (i.e. status was not cleared by our interrupt 176239225Sgibbs * reset above), perform a soft reset. 176339225Sgibbs */ 176439225Sgibbs DELAY(1000); 176539225Sgibbs status = aha_inb(aha, STATUS_REG); 176639225Sgibbs if ((status & (CMD_INVALID|STATUS_REG_RSVD|DATAIN_REG_READY| 176739225Sgibbs CMD_REG_BUSY|DIAG_FAIL|DIAG_ACTIVE)) != 0 176839225Sgibbs || (status & (HA_READY|INIT_REQUIRED)) 176939225Sgibbs != (HA_READY|INIT_REQUIRED)) { 177039852Simp ahareset(aha, /*hard_reset*/FALSE); 177139225Sgibbs } 177239225Sgibbs return (EINVAL); 177339225Sgibbs } 177439225Sgibbs 177539225Sgibbs if (param_len > 0) { 177639225Sgibbs /* The controller did not accept the full argument list */ 177739225Sgibbs return (E2BIG); 177839225Sgibbs } 177939225Sgibbs 178039225Sgibbs if (reply_len != reply_buf_size) { 178139225Sgibbs /* Too much or too little data received */ 178239225Sgibbs return (EMSGSIZE); 178339225Sgibbs } 178439225Sgibbs 178539225Sgibbs /* We were successful */ 178639225Sgibbs return (0); 178739225Sgibbs} 178839225Sgibbs 178939225Sgibbsstatic int 179039225Sgibbsahainitmboxes(struct aha_softc *aha) 179139225Sgibbs{ 179239225Sgibbs int error; 179339225Sgibbs init_24b_mbox_params_t init_mbox; 179439225Sgibbs 179539225Sgibbs bzero(aha->in_boxes, sizeof(aha_mbox_in_t) * aha->num_boxes); 179639225Sgibbs bzero(aha->out_boxes, sizeof(aha_mbox_out_t) * aha->num_boxes); 179739225Sgibbs aha->cur_inbox = aha->in_boxes; 179839225Sgibbs aha->last_inbox = aha->in_boxes + aha->num_boxes - 1; 179939225Sgibbs aha->cur_outbox = aha->out_boxes; 180039225Sgibbs aha->last_outbox = aha->out_boxes + aha->num_boxes - 1; 180139225Sgibbs 180239225Sgibbs /* Tell the adapter about them */ 180339225Sgibbs init_mbox.num_mboxes = aha->num_boxes; 180439225Sgibbs ahautoa24(aha->mailbox_physbase, init_mbox.base_addr); 180541047Sgibbs error = aha_cmd(aha, AOP_INITIALIZE_MBOX, (u_int8_t *)&init_mbox, 180639225Sgibbs /*parmlen*/sizeof(init_mbox), /*reply_buf*/NULL, 180739225Sgibbs /*reply_len*/0, DEFAULT_CMD_TIMEOUT); 180839225Sgibbs 180939225Sgibbs if (error != 0) 181039225Sgibbs printf("ahainitmboxes: Initialization command failed\n"); 181139225Sgibbs return (error); 181239225Sgibbs} 181339225Sgibbs 181439225Sgibbs/* 181539225Sgibbs * Update the XPT's idea of the negotiated transfer 181639225Sgibbs * parameters for a particular target. 181739225Sgibbs */ 181839225Sgibbsstatic void 181939225Sgibbsahafetchtransinfo(struct aha_softc *aha, struct ccb_trans_settings* cts) 182039225Sgibbs{ 182139225Sgibbs setup_data_t setup_info; 182239225Sgibbs u_int target; 182339225Sgibbs u_int targ_offset; 182439225Sgibbs u_int sync_period; 182539225Sgibbs int error; 182639225Sgibbs u_int8_t param; 182739225Sgibbs targ_syncinfo_t sync_info; 182839225Sgibbs 182939225Sgibbs target = cts->ccb_h.target_id; 183039225Sgibbs targ_offset = (target & 0x7); 183139225Sgibbs 183239225Sgibbs /* 183347208Simp * Inquire Setup Information. This command retreives 183447506Sgibbs * the sync info for older models. 183539225Sgibbs */ 183639225Sgibbs param = sizeof(setup_info); 183741047Sgibbs error = aha_cmd(aha, AOP_INQUIRE_SETUP_INFO, ¶m, /*paramlen*/1, 183839225Sgibbs (u_int8_t*)&setup_info, sizeof(setup_info), 183939225Sgibbs DEFAULT_CMD_TIMEOUT); 184039225Sgibbs 184139225Sgibbs if (error != 0) { 184247506Sgibbs printf("%s: ahafetchtransinfo - Inquire Setup Info Failed %d\n", 184347506Sgibbs aha_name(aha), error); 184439225Sgibbs return; 184539225Sgibbs } 184639225Sgibbs 184739225Sgibbs sync_info = setup_info.syncinfo[targ_offset]; 184839225Sgibbs 184939225Sgibbs if (sync_info.sync == 0) 185039225Sgibbs cts->sync_offset = 0; 185139225Sgibbs else 185239225Sgibbs cts->sync_offset = sync_info.offset; 185339225Sgibbs 185439225Sgibbs cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 185539225Sgibbs 185647506Sgibbs if (aha->boardid >= BOARD_1542CF) 185747506Sgibbs sync_period = 1000; 185847506Sgibbs else 185947506Sgibbs sync_period = 2000; 186047506Sgibbs sync_period += 500 * sync_info.period; 186139225Sgibbs 186239225Sgibbs /* Convert ns value to standard SCSI sync rate */ 186339225Sgibbs if (cts->sync_offset != 0) 186439225Sgibbs cts->sync_period = scsi_calc_syncparam(sync_period); 186539225Sgibbs else 186639225Sgibbs cts->sync_period = 0; 186739225Sgibbs 186839225Sgibbs cts->valid = CCB_TRANS_SYNC_RATE_VALID 186939225Sgibbs | CCB_TRANS_SYNC_OFFSET_VALID 187039225Sgibbs | CCB_TRANS_BUS_WIDTH_VALID; 187139225Sgibbs xpt_async(AC_TRANSFER_NEG, cts->ccb_h.path, cts); 187239225Sgibbs} 187339225Sgibbs 187439225Sgibbsstatic void 187539225Sgibbsahamapmboxes(void *arg, bus_dma_segment_t *segs, int nseg, int error) 187639225Sgibbs{ 187739225Sgibbs struct aha_softc* aha; 187839225Sgibbs 187939225Sgibbs aha = (struct aha_softc*)arg; 188039225Sgibbs aha->mailbox_physbase = segs->ds_addr; 188139225Sgibbs} 188239225Sgibbs 188339225Sgibbsstatic void 188439225Sgibbsahamapccbs(void *arg, bus_dma_segment_t *segs, int nseg, int error) 188539225Sgibbs{ 188639225Sgibbs struct aha_softc* aha; 188739225Sgibbs 188839225Sgibbs aha = (struct aha_softc*)arg; 188939225Sgibbs aha->aha_ccb_physbase = segs->ds_addr; 189039225Sgibbs} 189139225Sgibbs 189239225Sgibbsstatic void 189339225Sgibbsahamapsgs(void *arg, bus_dma_segment_t *segs, int nseg, int error) 189439225Sgibbs{ 189539225Sgibbs 189639225Sgibbs struct aha_softc* aha; 189739225Sgibbs 189839225Sgibbs aha = (struct aha_softc*)arg; 189939225Sgibbs SLIST_FIRST(&aha->sg_maps)->sg_physaddr = segs->ds_addr; 190039225Sgibbs} 190139225Sgibbs 190239225Sgibbsstatic void 190339225Sgibbsahapoll(struct cam_sim *sim) 190439225Sgibbs{ 190540132Sgibbs aha_intr(cam_sim_softc(sim)); 190639225Sgibbs} 190739225Sgibbs 190845575Seivindstatic void 190939225Sgibbsahatimeout(void *arg) 191039225Sgibbs{ 191141047Sgibbs struct aha_ccb *accb; 191239225Sgibbs union ccb *ccb; 191339225Sgibbs struct aha_softc *aha; 191439225Sgibbs int s; 191539225Sgibbs u_int32_t paddr; 191639225Sgibbs 191741047Sgibbs accb = (struct aha_ccb *)arg; 191841047Sgibbs ccb = accb->ccb; 191939225Sgibbs aha = (struct aha_softc *)ccb->ccb_h.ccb_aha_ptr; 192039225Sgibbs xpt_print_path(ccb->ccb_h.path); 192141047Sgibbs printf("CCB %p - timed out\n", (void *)accb); 192239225Sgibbs 192339225Sgibbs s = splcam(); 192439225Sgibbs 192541047Sgibbs if ((accb->flags & ACCB_ACTIVE) == 0) { 192639225Sgibbs xpt_print_path(ccb->ccb_h.path); 192739390Sgibbs printf("CCB %p - timed out CCB already completed\n", 192841047Sgibbs (void *)accb); 192939225Sgibbs splx(s); 193039225Sgibbs return; 193139225Sgibbs } 193239225Sgibbs 193339225Sgibbs /* 193439225Sgibbs * In order to simplify the recovery process, we ask the XPT 193539225Sgibbs * layer to halt the queue of new transactions and we traverse 193639225Sgibbs * the list of pending CCBs and remove their timeouts. This 193739225Sgibbs * means that the driver attempts to clear only one error 193839225Sgibbs * condition at a time. In general, timeouts that occur 193939225Sgibbs * close together are related anyway, so there is no benefit 194039225Sgibbs * in attempting to handle errors in parrallel. Timeouts will 194139225Sgibbs * be reinstated when the recovery process ends. 194239225Sgibbs */ 194341047Sgibbs if ((accb->flags & ACCB_DEVICE_RESET) == 0) { 194439225Sgibbs struct ccb_hdr *ccb_h; 194539225Sgibbs 194641047Sgibbs if ((accb->flags & ACCB_RELEASE_SIMQ) == 0) { 194739225Sgibbs xpt_freeze_simq(aha->sim, /*count*/1); 194841047Sgibbs accb->flags |= ACCB_RELEASE_SIMQ; 194939225Sgibbs } 195039225Sgibbs 195139225Sgibbs ccb_h = LIST_FIRST(&aha->pending_ccbs); 195239225Sgibbs while (ccb_h != NULL) { 195341047Sgibbs struct aha_ccb *pending_accb; 195439225Sgibbs 195541047Sgibbs pending_accb = (struct aha_ccb *)ccb_h->ccb_accb_ptr; 195641047Sgibbs untimeout(ahatimeout, pending_accb, ccb_h->timeout_ch); 195739225Sgibbs ccb_h = LIST_NEXT(ccb_h, sim_links.le); 195839225Sgibbs } 195939225Sgibbs } 196039225Sgibbs 196141047Sgibbs if ((accb->flags & ACCB_DEVICE_RESET) != 0 196241047Sgibbs || aha->cur_outbox->action_code != AMBO_FREE) { 196339225Sgibbs /* 196439225Sgibbs * Try a full host adapter/SCSI bus reset. 196539225Sgibbs * We do this only if we have already attempted 196639225Sgibbs * to clear the condition with a BDR, or we cannot 196739225Sgibbs * attempt a BDR for lack of mailbox resources. 196839225Sgibbs */ 196939225Sgibbs ccb->ccb_h.status = CAM_CMD_TIMEOUT; 197039225Sgibbs ahareset(aha, /*hardreset*/TRUE); 197139225Sgibbs printf("%s: No longer in timeout\n", aha_name(aha)); 197239225Sgibbs } else { 197339225Sgibbs /* 197439225Sgibbs * Send a Bus Device Reset message: 197539225Sgibbs * The target that is holding up the bus may not 197639225Sgibbs * be the same as the one that triggered this timeout 197739225Sgibbs * (different commands have different timeout lengths), 197839225Sgibbs * but we have no way of determining this from our 197939225Sgibbs * timeout handler. Our strategy here is to queue a 198039225Sgibbs * BDR message to the target of the timed out command. 198139225Sgibbs * If this fails, we'll get another timeout 2 seconds 198239225Sgibbs * later which will attempt a bus reset. 198339225Sgibbs */ 198441047Sgibbs accb->flags |= ACCB_DEVICE_RESET; 198541047Sgibbs ccb->ccb_h.timeout_ch = timeout(ahatimeout, (caddr_t)accb, 2 * hz); 198641047Sgibbs aha->recovery_accb->hccb.opcode = INITIATOR_BUS_DEV_RESET; 198739225Sgibbs 198839225Sgibbs /* No Data Transfer */ 198941047Sgibbs aha->recovery_accb->hccb.datain = TRUE; 199041047Sgibbs aha->recovery_accb->hccb.dataout = TRUE; 199141047Sgibbs aha->recovery_accb->hccb.ahastat = 0; 199241047Sgibbs aha->recovery_accb->hccb.sdstat = 0; 199341047Sgibbs aha->recovery_accb->hccb.target = ccb->ccb_h.target_id; 199439225Sgibbs 199539225Sgibbs /* Tell the adapter about this command */ 199641047Sgibbs paddr = ahaccbvtop(aha, aha->recovery_accb); 199739225Sgibbs ahautoa24(paddr, aha->cur_outbox->ccb_addr); 199841047Sgibbs aha->cur_outbox->action_code = AMBO_START; 199941047Sgibbs aha_outb(aha, COMMAND_REG, AOP_START_MBOX); 200039225Sgibbs ahanextoutbox(aha); 200139225Sgibbs } 200239225Sgibbs 200339225Sgibbs splx(s); 200439225Sgibbs} 2005