aha.c revision 163816
11592Srgrimes/* 21592Srgrimes * Generic register and struct definitions for the Adaptech 154x/164x 31592Srgrimes * SCSI host adapters. Product specific probe and attach routines can 41592Srgrimes * be found in: 51592Srgrimes * aha 1542A/1542B/1542C/1542CF/1542CP aha_isa.c 61592Srgrimes * aha 1640 aha_mca.c 71592Srgrimes */ 81592Srgrimes/*- 91592Srgrimes * Copyright (c) 1998 M. Warner Losh. 101592Srgrimes * All Rights Reserved. 111592Srgrimes * 121592Srgrimes * Redistribution and use in source and binary forms, with or without 131592Srgrimes * modification, are permitted provided that the following conditions 141592Srgrimes * are met: 151592Srgrimes * 1. Redistributions of source code must retain the above copyright 161592Srgrimes * notice, this list of conditions and the following disclaimer. 171592Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 181592Srgrimes * notice, this list of conditions and the following disclaimer in the 191592Srgrimes * documentation and/or other materials provided with the distribution. 201592Srgrimes * 211592Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 221592Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231592Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241592Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 251592Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261592Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271592Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281592Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291592Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301592Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311592Srgrimes * SUCH DAMAGE. 321592Srgrimes * 331592Srgrimes * Derived from bt.c written by: 3417478Smarkm * 351592Srgrimes * Copyright (c) 1998 Justin T. Gibbs. 361592Srgrimes * All rights reserved. 371592Srgrimes * 381592Srgrimes * Redistribution and use in source and binary forms, with or without 391592Srgrimes * modification, are permitted provided that the following conditions 4017478Smarkm * are met: 411592Srgrimes * 1. Redistributions of source code must retain the above copyright 4231329Scharnier * notice, this list of conditions, and the following disclaimer, 4317478Smarkm * without modification, immediately at the beginning of the file. 441592Srgrimes * 2. The name of the author may not be used to endorse or promote products 4531329Scharnier * derived from this software without specific prior written permission. 4631329Scharnier * 4750476Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 481592Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 491592Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 501592Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 511592Srgrimes * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 521592Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 531592Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 541592Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 5566907Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 561592Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5766907Swollman * SUCH DAMAGE. 5866907Swollman */ 591592Srgrimes 601592Srgrimes#include <sys/cdefs.h> 611592Srgrimes__FBSDID("$FreeBSD: head/sys/dev/aha/aha.c 163816 2006-10-31 05:53:29Z mjacob $"); 621592Srgrimes 631592Srgrimes#include <sys/param.h> 648240Swollman#include <sys/bus.h> 651592Srgrimes#include <sys/systm.h> 661592Srgrimes#include <sys/malloc.h> 671592Srgrimes#include <sys/kernel.h> 681592Srgrimes#include <sys/lock.h> 691592Srgrimes#include <sys/mutex.h> 701592Srgrimes 711592Srgrimes#include <machine/bus.h> 721592Srgrimes 731592Srgrimes#include <cam/cam.h> 741592Srgrimes#include <cam/cam_ccb.h> 751592Srgrimes#include <cam/cam_sim.h> 761592Srgrimes#include <cam/cam_xpt_sim.h> 771592Srgrimes#include <cam/cam_debug.h> 781592Srgrimes 791592Srgrimes#include <cam/scsi/scsi_message.h> 8025187Sdavidn 8188763Sache#include <dev/aha/ahareg.h> 821592Srgrimes 831592Srgrimes#define PRVERB(x) do { if (bootverbose) device_printf x; } while (0) 841592Srgrimes 851592Srgrimes/* Macro to determine that a rev is potentially a new valid one 861592Srgrimes * so that the driver doesn't keep breaking on new revs as it 871592Srgrimes * did for the CF and CP. 881592Srgrimes */ 8913139Speter#define PROBABLY_NEW_BOARD(REV) (REV > 0x43 && REV < 0x56) 9025101Sdavidn 9125101Sdavidn/* MailBox Management functions */ 9225101Sdavidnstatic __inline void ahanextinbox(struct aha_softc *aha); 931592Srgrimesstatic __inline void ahanextoutbox(struct aha_softc *aha); 9474874Smarkm 9551433Smarkm#define aha_name(aha) device_get_nameunit(aha->dev) 9651433Smarkm 9751433Smarkmstatic __inline void 981592Srgrimesahanextinbox(struct aha_softc *aha) 991592Srgrimes{ 1001592Srgrimes if (aha->cur_inbox == aha->last_inbox) 1011592Srgrimes aha->cur_inbox = aha->in_boxes; 1021592Srgrimes else 10325165Sdavidn aha->cur_inbox++; 10425165Sdavidn} 1051592Srgrimes 1061592Srgrimesstatic __inline void 1071592Srgrimesahanextoutbox(struct aha_softc *aha) 1081592Srgrimes{ 10956668Sshin if (aha->cur_outbox == aha->last_outbox) 11056668Sshin aha->cur_outbox = aha->out_boxes; 11156668Sshin else 11256668Sshin aha->cur_outbox++; 11356668Sshin} 1141592Srgrimes 11515196Sdg#define ahautoa24(u,s3) \ 1161592Srgrimes (s3)[0] = ((u) >> 16) & 0xff; \ 117109742Syar (s3)[1] = ((u) >> 8) & 0xff; \ 118110037Syar (s3)[2] = (u) & 0xff; 1191592Srgrimes 1201592Srgrimes#define aha_a24tou(s3) \ 121110036Syar (((s3)[0] << 16) | ((s3)[1] << 8) | (s3)[2]) 12276096Smarkm 1231592Srgrimes/* CCB Mangement functions */ 1241592Srgrimesstatic __inline uint32_t ahaccbvtop(struct aha_softc *aha, 1251592Srgrimes struct aha_ccb *accb); 1269933Spststatic __inline struct aha_ccb* ahaccbptov(struct aha_softc *aha, 12717435Spst uint32_t ccb_addr); 12820042Storstenb 1291592Srgrimesstatic __inline uint32_t 13017435Spstahaccbvtop(struct aha_softc *aha, struct aha_ccb *accb) 131102311Syar{ 1326740Sguido return (aha->aha_ccb_physbase 1336740Sguido + (uint32_t)((caddr_t)accb - (caddr_t)aha->aha_ccb_array)); 1341592Srgrimes} 1351592Srgrimesstatic __inline struct aha_ccb * 1361592Srgrimesahaccbptov(struct aha_softc *aha, uint32_t ccb_addr) 1371592Srgrimes{ 1381592Srgrimes return (aha->aha_ccb_array + 1391592Srgrimes + ((struct aha_ccb*)(uintptr_t)ccb_addr - 14070102Sphk (struct aha_ccb*)(uintptr_t)aha->aha_ccb_physbase)); 14170102Sphk} 14282460Snik 14382796Ssheldonhstatic struct aha_ccb* ahagetccb(struct aha_softc *aha); 14499195Smdoddstatic __inline void ahafreeccb(struct aha_softc *aha, struct aha_ccb *accb); 145101537Syarstatic void ahaallocccbs(struct aha_softc *aha); 14682460Snikstatic bus_dmamap_callback_t ahaexecuteccb; 14789935Syarstatic void ahadone(struct aha_softc *aha, struct aha_ccb *accb, 1481592Srgrimes aha_mbi_comp_code_t comp_code); 1491592Srgrimes 1501592Srgrimes/* Host adapter command functions */ 1511592Srgrimesstatic int ahareset(struct aha_softc* aha, int hard_reset); 1521592Srgrimes 1531592Srgrimes/* Initialization functions */ 1541592Srgrimesstatic int ahainitmboxes(struct aha_softc *aha); 1551592Srgrimesstatic bus_dmamap_callback_t ahamapmboxes; 1561592Srgrimesstatic bus_dmamap_callback_t ahamapccbs; 15727650Sdavidnstatic bus_dmamap_callback_t ahamapsgs; 15878153Sdd 15978153Sdd/* Transfer Negotiation Functions */ 16025283Sdavidnstatic void ahafetchtransinfo(struct aha_softc *aha, 16125283Sdavidn struct ccb_trans_settings *cts); 16225283Sdavidn 16325283Sdavidn/* CAM SIM entry points */ 16425283Sdavidn#define ccb_accb_ptr spriv_ptr0 16557124Sshin#define ccb_aha_ptr spriv_ptr1 16625283Sdavidnstatic void ahaaction(struct cam_sim *sim, union ccb *ccb); 16725283Sdavidnstatic void ahapoll(struct cam_sim *sim); 16825283Sdavidn 16925283Sdavidn/* Our timeout handler */ 17025283Sdavidnstatic timeout_t ahatimeout; 17125283Sdavidn 17225283Sdavidn/* Exported functions */ 17325283Sdavidnvoid 17445422Sbrianaha_alloc(struct aha_softc *aha, int unit, bus_space_tag_t tag, 1756740Sguido bus_space_handle_t bsh) 17617435Spst{ 17717435Spst 17817435Spst SLIST_INIT(&aha->free_aha_ccbs); 17917435Spst LIST_INIT(&aha->pending_ccbs); 18074874Smarkm SLIST_INIT(&aha->sg_maps); 18190148Simp aha->unit = unit; 18274874Smarkm aha->tag = tag; 18388763Sache aha->bsh = bsh; 18479469Smarkm aha->ccb_sg_opcode = INITIATOR_SG_CCB_WRESID; 18579469Smarkm aha->ccb_ccb_opcode = INITIATOR_CCB_WRESID; 18679469Smarkm} 18788763Sache 18817478Smarkmvoid 18917483Sjulianaha_free(struct aha_softc *aha) 19017483Sjulian{ 1911592Srgrimes switch (aha->init_level) { 19274470Sjlemon default: 19374470Sjlemon case 8: 19474470Sjlemon { 19574470Sjlemon struct sg_map_node *sg_map; 19674470Sjlemon 19774470Sjlemon while ((sg_map = SLIST_FIRST(&aha->sg_maps))!= NULL) { 19874470Sjlemon SLIST_REMOVE_HEAD(&aha->sg_maps, links); 1991592Srgrimes bus_dmamap_unload(aha->sg_dmat, sg_map->sg_dmamap); 2001592Srgrimes bus_dmamem_free(aha->sg_dmat, sg_map->sg_vaddr, 2011592Srgrimes sg_map->sg_dmamap); 2021592Srgrimes free(sg_map, M_DEVBUF); 2031592Srgrimes } 2041592Srgrimes bus_dma_tag_destroy(aha->sg_dmat); 2051592Srgrimes } 2061592Srgrimes case 7: 2071592Srgrimes bus_dmamap_unload(aha->ccb_dmat, aha->ccb_dmamap); 2081592Srgrimes case 6: 2091592Srgrimes bus_dmamap_destroy(aha->ccb_dmat, aha->ccb_dmamap); 21013139Speter bus_dmamem_free(aha->ccb_dmat, aha->aha_ccb_array, 2111592Srgrimes aha->ccb_dmamap); 2121592Srgrimes case 5: 21313139Speter bus_dma_tag_destroy(aha->ccb_dmat); 2141592Srgrimes case 4: 2151592Srgrimes bus_dmamap_unload(aha->mailbox_dmat, aha->mailbox_dmamap); 2161592Srgrimes case 3: 2171592Srgrimes bus_dmamem_free(aha->mailbox_dmat, aha->in_boxes, 2181592Srgrimes aha->mailbox_dmamap); 2191592Srgrimes bus_dmamap_destroy(aha->mailbox_dmat, aha->mailbox_dmamap); 2201592Srgrimes case 2: 2211592Srgrimes bus_dma_tag_destroy(aha->buffer_dmat); 2221592Srgrimes case 1: 2231592Srgrimes bus_dma_tag_destroy(aha->mailbox_dmat); 2241592Srgrimes case 0: 2251592Srgrimes break; 2261592Srgrimes } 2271592Srgrimes} 2281592Srgrimes 2291592Srgrimes/* 2301592Srgrimes * Probe the adapter and verify that the card is an Adaptec. 2311592Srgrimes */ 2321592Srgrimesint 2331592Srgrimesaha_probe(struct aha_softc* aha) 2341592Srgrimes{ 2351592Srgrimes u_int status; 23625283Sdavidn u_int intstat; 23790148Simp int error; 23890148Simp board_id_data_t board_id; 23925283Sdavidn 24090148Simp /* 24190148Simp * See if the three I/O ports look reasonable. 24290148Simp * Touch the minimal number of registers in the 243109893Syar * failure case. 24490148Simp */ 24590148Simp status = aha_inb(aha, STATUS_REG); 24690148Simp if ((status == 0) || 24790148Simp (status & (DIAG_ACTIVE|CMD_REG_BUSY | STATUS_REG_RSVD)) != 0) { 24890148Simp PRVERB((aha->dev, "status reg test failed %x\n", status)); 249101537Syar return (ENXIO); 25090148Simp } 25190148Simp 25290148Simp intstat = aha_inb(aha, INTSTAT_REG); 25390148Simp if ((intstat & INTSTAT_REG_RSVD) != 0) { 2541592Srgrimes PRVERB((aha->dev, "Failed Intstat Reg Test\n")); 25590148Simp return (ENXIO); 25690148Simp } 25790148Simp 25890148Simp /* 259100486Syar * Looking good so far. Final test is to reset the 260120059Sume * adapter and fetch the board ID and ensure we aren't 2611592Srgrimes * looking at a BusLogic. 2621592Srgrimes */ 26390148Simp if ((error = ahareset(aha, /*hard_reset*/TRUE)) != 0) { 2641592Srgrimes PRVERB((aha->dev, "Failed Reset\n")); 2651592Srgrimes return (ENXIO); 2661592Srgrimes } 2671592Srgrimes 2681592Srgrimes /* 2691592Srgrimes * Get the board ID. We use this to see if we're dealing with 2701592Srgrimes * a buslogic card or an aha card (or clone). 2711592Srgrimes */ 2721592Srgrimes error = aha_cmd(aha, AOP_INQUIRE_BOARD_ID, NULL, /*parmlen*/0, 2731592Srgrimes (uint8_t*)&board_id, sizeof(board_id), DEFAULT_CMD_TIMEOUT); 2741592Srgrimes if (error != 0) { 2751592Srgrimes PRVERB((aha->dev, "INQUIRE failed %x\n", error)); 27690148Simp return (ENXIO); 2771592Srgrimes } 2781592Srgrimes aha->fw_major = board_id.firmware_rev_major; 2791592Srgrimes aha->fw_minor = board_id.firmware_rev_minor; 2801592Srgrimes aha->boardid = board_id.board_type; 28156668Sshin 28256668Sshin /* 283109742Syar * The Buslogic cards have an id of either 0x41 or 0x42. So 28456668Sshin * if those come up in the probe, we test the geometry register 28589935Syar * of the board. Adaptec boards that are this old will not have 2861592Srgrimes * this register, and return 0xff, while buslogic cards will return 28736105Sache * something different. 28889935Syar * 28989935Syar * It appears that for reasons unknow, for the for the 29036105Sache * aha-1542B cards, we need to wait a little bit before trying 29113139Speter * to read the geometry register. I picked 10ms since we have 2921592Srgrimes * reports that a for loop to 1000 did the trick, and this 2931592Srgrimes * errs on the side of conservatism. Besides, no one will 2941592Srgrimes * notice a 10mS delay here, even the 1542B card users :-) 2951592Srgrimes * 2961592Srgrimes * Some compatible cards return 0 here. Some cards also 2971592Srgrimes * seem to return 0x7f. 2981592Srgrimes * 29913139Speter * XXX I'm not sure how this will impact other cloned cards 3001592Srgrimes * 3016740Sguido * This really should be replaced with the esetup command, since 302110037Syar * that appears to be more reliable. This becomes more and more 303110037Syar * true over time as we discover more cards that don't read the 3041592Srgrimes * geometry register consistantly. 305100717Syar */ 306120059Sume if (aha->boardid <= 0x42) { 30715196Sdg /* Wait 10ms before reading */ 30815196Sdg DELAY(10000); 309100717Syar status = aha_inb(aha, GEOMETRY_REG); 310120059Sume if (status != 0xff && status != 0x00 && status != 0x7f) { 311100717Syar PRVERB((aha->dev, "Geometry Register test failed %#x\n", 312100717Syar status)); 313100717Syar return (ENXIO); 314100717Syar } 315100717Syar } 316100717Syar 317100717Syar return (0); 318100717Syar} 319100717Syar 320100717Syar/* 3211592Srgrimes * Pull the boards setup information and record it in our softc. 32276096Smarkm */ 3231592Srgrimesint 3241592Srgrimesaha_fetch_adapter_info(struct aha_softc *aha) 325100717Syar{ 326100717Syar setup_data_t setup_info; 327100717Syar config_data_t config_data; 328100717Syar uint8_t length_param; 32970102Sphk int error; 33070102Sphk struct aha_extbios extbios; 33170102Sphk 33270102Sphk switch (aha->boardid) { 333110037Syar case BOARD_1540_16HEAD_BIOS: 334110037Syar snprintf(aha->model, sizeof(aha->model), "1540 16 head BIOS"); 335110037Syar break; 336110037Syar case BOARD_1540_64HEAD_BIOS: 3371592Srgrimes snprintf(aha->model, sizeof(aha->model), "1540 64 head BIOS"); 3381592Srgrimes break; 3391592Srgrimes case BOARD_1542: 3401592Srgrimes snprintf(aha->model, sizeof(aha->model), "1540/1542 64 head BIOS"); 341101537Syar break; 342101537Syar case BOARD_1640: 343101537Syar snprintf(aha->model, sizeof(aha->model), "1640"); 344101537Syar break; 345100717Syar case BOARD_1740: 346100717Syar snprintf(aha->model, sizeof(aha->model), "1740A/1742A/1744"); 347100717Syar break; 348100717Syar case BOARD_1542C: 349100717Syar snprintf(aha->model, sizeof(aha->model), "1542C"); 350100717Syar break; 351100717Syar case BOARD_1542CF: 352100717Syar snprintf(aha->model, sizeof(aha->model), "1542CF"); 353100717Syar break; 354100717Syar case BOARD_1542CP: 355100717Syar snprintf(aha->model, sizeof(aha->model), "1542CP"); 356100717Syar break; 357100717Syar default: 358100717Syar snprintf(aha->model, sizeof(aha->model), "Unknown"); 359100717Syar break; 360100717Syar } 361109742Syar /* 362109742Syar * If we are a new type of 1542 board (anything newer than a 1542C) 363109742Syar * then disable the extended bios so that the 364109742Syar * mailbox interface is unlocked. 36570102Sphk * This is also true for the 1542B Version 3.20. First Adaptec 36670102Sphk * board that supports >1Gb drives. 36770102Sphk * No need to check the extended bios flags as some of the 36870102Sphk * extensions that cause us problems are not flagged in that byte. 36917435Spst */ 37017435Spst if (PROBABLY_NEW_BOARD(aha->boardid) || 3719933Spst (aha->boardid == 0x41 3729933Spst && aha->fw_major == 0x31 && 3736740Sguido aha->fw_minor >= 0x34)) { 37417435Spst error = aha_cmd(aha, AOP_RETURN_EXT_BIOS_INFO, NULL, 3756740Sguido /*paramlen*/0, (u_char *)&extbios, sizeof(extbios), 37617435Spst DEFAULT_CMD_TIMEOUT); 37717435Spst if (error != 0) { 37817435Spst device_printf(aha->dev, 37917435Spst "AOP_RETURN_EXT_BIOS_INFO - Failed."); 38017435Spst return (error); 38117435Spst } 38217435Spst error = aha_cmd(aha, AOP_MBOX_IF_ENABLE, (uint8_t *)&extbios, 383100717Syar /*paramlen*/2, NULL, 0, DEFAULT_CMD_TIMEOUT); 384100717Syar if (error != 0) { 385100717Syar device_printf(aha->dev, "AOP_MBOX_IF_ENABLE - Failed."); 386100717Syar return (error); 38717435Spst } 38817435Spst } 3891592Srgrimes if (aha->boardid < 0x41) 3901592Srgrimes device_printf(aha->dev, "Warning: aha-1542A won't work.\n"); 3911592Srgrimes 3921592Srgrimes aha->max_sg = 17; /* Need >= 17 to do 64k I/O */ 3931592Srgrimes aha->diff_bus = 0; 3941592Srgrimes aha->extended_lun = 0; 3951592Srgrimes aha->extended_trans = 0; 3961592Srgrimes aha->max_ccbs = 16; 3971592Srgrimes /* Determine Sync/Wide/Disc settings */ 3981592Srgrimes length_param = sizeof(setup_info); 3991592Srgrimes error = aha_cmd(aha, AOP_INQUIRE_SETUP_INFO, &length_param, 400100717Syar /*paramlen*/1, (uint8_t*)&setup_info, sizeof(setup_info), 401100717Syar DEFAULT_CMD_TIMEOUT); 40220042Storstenb if (error != 0) { 4031592Srgrimes device_printf(aha->dev, "aha_fetch_adapter_info - Failed " 4041592Srgrimes "Get Setup Info\n"); 405100720Syar return (error); 4061592Srgrimes } 4071592Srgrimes if (setup_info.initiate_sync != 0) { 408102311Syar aha->sync_permitted = ALL_TARGETS; 409102311Syar } 410102311Syar aha->disc_permitted = ALL_TARGETS; 411102311Syar 4121592Srgrimes /* We need as many mailboxes as we can have ccbs */ 4131592Srgrimes aha->num_boxes = aha->max_ccbs; 4141592Srgrimes 4151592Srgrimes /* Determine our SCSI ID */ 4161592Srgrimes error = aha_cmd(aha, AOP_INQUIRE_CONFIG, NULL, /*parmlen*/0, 41715196Sdg (uint8_t*)&config_data, sizeof(config_data), DEFAULT_CMD_TIMEOUT); 41825283Sdavidn if (error != 0) { 41925283Sdavidn device_printf(aha->dev, 42025283Sdavidn "aha_fetch_adapter_info - Failed Get Config\n"); 4211592Srgrimes return (error); 42215196Sdg } 42315196Sdg aha->scsi_id = config_data.scsi_id; 42415196Sdg return (0); 42515196Sdg} 42615196Sdg 42715196Sdg/* 42815196Sdg * Start the board, ready for normal operation 42915196Sdg */ 430120059Sumeint 431120059Sumeaha_init(struct aha_softc* aha) 432120059Sume{ 43315196Sdg /* Announce the Adapter */ 43415196Sdg device_printf(aha->dev, "AHA-%s FW Rev. %c.%c (ID=%x) ", 43515196Sdg aha->model, aha->fw_major, aha->fw_minor, aha->boardid); 43615196Sdg 43715196Sdg if (aha->diff_bus != 0) 43815196Sdg printf("Diff "); 43915196Sdg 44015196Sdg printf("SCSI Host Adapter, SCSI ID %d, %d CCBs\n", aha->scsi_id, 44189935Syar aha->max_ccbs); 44289935Syar 44356668Sshin /* 44415196Sdg * Create our DMA tags. These tags define the kinds of device 44515196Sdg * accessible memory allocations and memory mappings we will 44615196Sdg * need to perform during normal operation. 44715196Sdg * 448120059Sume * Unless we need to further restrict the allocation, we rely 449120059Sume * on the restrictions of the parent dmat, hence the common 45015196Sdg * use of MAXADDR and MAXSIZE. 451120059Sume */ 452120059Sume 453120059Sume /* DMA tag for mapping buffers into device visible space. */ 454120059Sume if (bus_dma_tag_create( /* parent */ aha->parent_dmat, 455120059Sume /* alignment */ 1, 456120059Sume /* boundary */ 0, 457120059Sume /* lowaddr */ BUS_SPACE_MAXADDR, 458120059Sume /* highaddr */ BUS_SPACE_MAXADDR, 459120059Sume /* filter */ NULL, 460120059Sume /* filterarg */ NULL, 46115196Sdg /* maxsize */ MAXBSIZE, 462120059Sume /* nsegments */ AHA_NSEG, 46315196Sdg /* maxsegsz */ BUS_SPACE_MAXSIZE_24BIT, 46417483Sjulian /* flags */ BUS_DMA_ALLOCNOW, 46517483Sjulian /* lockfunc */ busdma_lock_mutex, 46617483Sjulian /* lockarg */ &Giant, 46799213Smaxim &aha->buffer_dmat) != 0) { 46817483Sjulian goto error_exit; 46917483Sjulian } 47017483Sjulian 47117483Sjulian aha->init_level++; 47217483Sjulian /* DMA tag for our mailboxes */ 47346078Simp if (bus_dma_tag_create( /* parent */ aha->parent_dmat, 47417483Sjulian /* alignment */ 1, 47517483Sjulian /* boundary */ 0, 47617483Sjulian /* lowaddr */ BUS_SPACE_MAXADDR, 47717483Sjulian /* highaddr */ BUS_SPACE_MAXADDR, 47846078Simp /* filter */ NULL, 47917483Sjulian /* filterarg */ NULL, 48017483Sjulian /* maxsize */ aha->num_boxes * 48117483Sjulian (sizeof(aha_mbox_in_t) + 48217483Sjulian sizeof(aha_mbox_out_t)), 48317483Sjulian /* nsegments */ 1, 48417483Sjulian /* maxsegsz */ BUS_SPACE_MAXSIZE_24BIT, 48517483Sjulian /* flags */ 0, 48615196Sdg /* lockfunc */ busdma_lock_mutex, 48715196Sdg /* lockarg */ &Giant, 48815196Sdg &aha->mailbox_dmat) != 0) { 48915196Sdg goto error_exit; 490120059Sume } 491120059Sume 492120059Sume aha->init_level++; 493120059Sume 494120059Sume /* Allocation for our mailboxes */ 495120059Sume if (bus_dmamem_alloc(aha->mailbox_dmat, (void **)&aha->out_boxes, 496120059Sume BUS_DMA_NOWAIT, &aha->mailbox_dmamap) != 0) 497120059Sume goto error_exit; 498120059Sume 499120059Sume aha->init_level++; 500120059Sume 501120059Sume /* And permanently map them */ 502120059Sume bus_dmamap_load(aha->mailbox_dmat, aha->mailbox_dmamap, 503120059Sume aha->out_boxes, aha->num_boxes * (sizeof(aha_mbox_in_t) + 504120059Sume sizeof(aha_mbox_out_t)), ahamapmboxes, aha, /*flags*/0); 505120059Sume 506120059Sume aha->init_level++; 507120059Sume 508120059Sume aha->in_boxes = (aha_mbox_in_t *)&aha->out_boxes[aha->num_boxes]; 509120059Sume 510120059Sume ahainitmboxes(aha); 511120059Sume 512120059Sume /* DMA tag for our ccb structures */ 513120059Sume if (bus_dma_tag_create( /* parent */ aha->parent_dmat, 51415196Sdg /* alignment */ 1, 51515196Sdg /* boundary */ 0, 51615196Sdg /* lowaddr */ BUS_SPACE_MAXADDR, 51715196Sdg /* highaddr */ BUS_SPACE_MAXADDR, 51815196Sdg /* filter */ NULL, 51915196Sdg /* filterarg */ NULL, 52015196Sdg /* maxsize */ aha->max_ccbs * 52115196Sdg sizeof(struct aha_ccb), 52215196Sdg /* nsegments */ 1, 52315196Sdg /* maxsegsz */ BUS_SPACE_MAXSIZE_24BIT, 52489935Syar /* flags */ 0, 52589935Syar /* lockfunc */ busdma_lock_mutex, 5261592Srgrimes /* lockarg */ &Giant, 52789935Syar &aha->ccb_dmat) != 0) { 52889935Syar goto error_exit; 52989935Syar } 53089935Syar 53189935Syar aha->init_level++; 53289935Syar 53389935Syar /* Allocation for our ccbs */ 53489935Syar if (bus_dmamem_alloc(aha->ccb_dmat, (void **)&aha->aha_ccb_array, 53589935Syar BUS_DMA_NOWAIT, &aha->ccb_dmamap) != 0) 53689935Syar goto error_exit; 53789935Syar 53889935Syar aha->init_level++; 53989935Syar 54089935Syar /* And permanently map them */ 54189935Syar bus_dmamap_load(aha->ccb_dmat, aha->ccb_dmamap, aha->aha_ccb_array, 54215196Sdg aha->max_ccbs * sizeof(struct aha_ccb), ahamapccbs, aha, /*flags*/0); 54315196Sdg 54415196Sdg aha->init_level++; 54515196Sdg 54615196Sdg /* DMA tag for our S/G structures. We allocate in page sized chunks */ 547109742Syar if (bus_dma_tag_create( /* parent */ aha->parent_dmat, 54825283Sdavidn /* alignment */ 1, 54925283Sdavidn /* boundary */ 0, 55056668Sshin /* lowaddr */ BUS_SPACE_MAXADDR, 55125283Sdavidn /* highaddr */ BUS_SPACE_MAXADDR, 55215196Sdg /* filter */ NULL, 55356668Sshin /* filterarg */ NULL, 55456668Sshin /* maxsize */ PAGE_SIZE, 55515196Sdg /* nsegments */ 1, 556100612Syar /* maxsegsz */ BUS_SPACE_MAXSIZE_24BIT, 557100609Syar /* flags */ 0, 55856668Sshin /* lockfunc */ busdma_lock_mutex, 55915196Sdg /* lockarg */ &Giant, 56035482Sdg &aha->sg_dmat) != 0) 56135482Sdg goto error_exit; 56235482Sdg 56335482Sdg aha->init_level++; 56435482Sdg 565100609Syar /* Perform initial CCB allocation */ 56635482Sdg bzero(aha->aha_ccb_array, aha->max_ccbs * sizeof(struct aha_ccb)); 56756668Sshin ahaallocccbs(aha); 56815196Sdg 56917435Spst if (aha->num_ccbs == 0) { 57031973Simp device_printf(aha->dev, 57117435Spst "aha_init - Unable to allocate initial ccbs\n"); 5721592Srgrimes goto error_exit; 5731592Srgrimes } 574100612Syar 575100609Syar /* 5761592Srgrimes * Note that we are going and return (to probe) 5771592Srgrimes */ 5781592Srgrimes return (0); 5791592Srgrimes 5801592Srgrimeserror_exit: 5811592Srgrimes 58256668Sshin return (ENXIO); 5831592Srgrimes} 5841592Srgrimes 5851592Srgrimesint 5861592Srgrimesaha_attach(struct aha_softc *aha) 5871592Srgrimes{ 5881592Srgrimes int tagged_dev_openings; 5891592Srgrimes struct cam_devq *devq; 5901592Srgrimes 5911592Srgrimes /* 5921592Srgrimes * We don't do tagged queueing, since the aha cards don't 5931592Srgrimes * support it. 5941592Srgrimes */ 5951592Srgrimes tagged_dev_openings = 0; 5961592Srgrimes 5971592Srgrimes /* 5981592Srgrimes * Create the device queue for our SIM. 5991592Srgrimes */ 6001592Srgrimes devq = cam_simq_alloc(aha->max_ccbs - 1); 6011592Srgrimes if (devq == NULL) 6021592Srgrimes return (ENOMEM); 6031592Srgrimes 6041592Srgrimes /* 60525283Sdavidn * Construct our SIM entry 60625283Sdavidn */ 60725283Sdavidn aha->sim = cam_sim_alloc(ahaaction, ahapoll, "aha", aha, aha->unit, 2, 6081592Srgrimes tagged_dev_openings, devq); 60925283Sdavidn if (aha->sim == NULL) { 6101592Srgrimes cam_simq_free(devq); 6111592Srgrimes return (ENOMEM); 6121592Srgrimes } 6131592Srgrimes if (xpt_bus_register(aha->sim, 0) != CAM_SUCCESS) { 6141592Srgrimes cam_sim_free(aha->sim, /*free_devq*/TRUE); 6151592Srgrimes return (ENXIO); 6161592Srgrimes } 6171592Srgrimes if (xpt_create_path(&aha->path, /*periph*/NULL, cam_sim_path(aha->sim), 6181592Srgrimes CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 61925283Sdavidn xpt_bus_deregister(cam_sim_path(aha->sim)); 62027650Sdavidn cam_sim_free(aha->sim, /*free_devq*/TRUE); 62176096Smarkm return (ENXIO); 62245422Sbrian } 62345422Sbrian 62425283Sdavidn return (0); 625110037Syar} 626110037Syar 627110037Syarstatic void 628110037Syarahaallocccbs(struct aha_softc *aha) 6291592Srgrimes{ 6301592Srgrimes struct aha_ccb *next_ccb; 6311592Srgrimes struct sg_map_node *sg_map; 6321592Srgrimes bus_addr_t physaddr; 6331592Srgrimes aha_sg_t *segs; 6341592Srgrimes int newcount; 63590148Simp int i; 6361592Srgrimes 6371592Srgrimes next_ccb = &aha->aha_ccb_array[aha->num_ccbs]; 63876096Smarkm 6391592Srgrimes sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT); 64031329Scharnier 6411592Srgrimes if (sg_map == NULL) 6421592Srgrimes return; 64389935Syar 64490148Simp /* Allocate S/G space for the next batch of CCBS */ 64589935Syar if (bus_dmamem_alloc(aha->sg_dmat, (void **)&sg_map->sg_vaddr, 64689935Syar BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) { 64789935Syar free(sg_map, M_DEVBUF); 64889935Syar return; 64989935Syar } 65089935Syar 65125283Sdavidn SLIST_INSERT_HEAD(&aha->sg_maps, sg_map, links); 6521592Srgrimes 65325283Sdavidn bus_dmamap_load(aha->sg_dmat, sg_map->sg_dmamap, sg_map->sg_vaddr, 65425283Sdavidn PAGE_SIZE, ahamapsgs, aha, /*flags*/0); 65525283Sdavidn 65625283Sdavidn segs = sg_map->sg_vaddr; 65790148Simp physaddr = sg_map->sg_physaddr; 65825283Sdavidn 659100182Syar newcount = (PAGE_SIZE / (AHA_NSEG * sizeof(aha_sg_t))); 66099877Syar for (i = 0; aha->num_ccbs < aha->max_ccbs && i < newcount; i++) { 66125283Sdavidn int error; 66299877Syar 66399877Syar next_ccb->sg_list = segs; 664100182Syar next_ccb->sg_list_phys = physaddr; 66525283Sdavidn next_ccb->flags = ACCB_FREE; 66656668Sshin error = bus_dmamap_create(aha->buffer_dmat, /*flags*/0, 66725283Sdavidn &next_ccb->dmamap); 66825283Sdavidn if (error != 0) 66925283Sdavidn break; 67025283Sdavidn SLIST_INSERT_HEAD(&aha->free_aha_ccbs, next_ccb, links); 67199877Syar segs += AHA_NSEG; 67276096Smarkm physaddr += (AHA_NSEG * sizeof(aha_sg_t)); 67399877Syar next_ccb++; 67499877Syar aha->num_ccbs++; 67599877Syar } 67699877Syar 67799877Syar /* Reserve a CCB for error recovery */ 67899877Syar if (aha->recovery_accb == NULL) { 67957124Sshin aha->recovery_accb = SLIST_FIRST(&aha->free_aha_ccbs); 68056668Sshin SLIST_REMOVE_HEAD(&aha->free_aha_ccbs, links); 68156668Sshin } 68256668Sshin} 68356668Sshin 684102183Syarstatic __inline void 68557124Sshinahafreeccb(struct aha_softc *aha, struct aha_ccb *accb) 68625283Sdavidn{ 68725283Sdavidn int s; 68825283Sdavidn 68925283Sdavidn s = splcam(); 69025283Sdavidn if ((accb->flags & ACCB_ACTIVE) != 0) 69125283Sdavidn LIST_REMOVE(&accb->ccb->ccb_h, sim_links.le); 69225283Sdavidn if (aha->resource_shortage != 0 693102474Syar && (accb->ccb->ccb_h.status & CAM_RELEASE_SIMQ) == 0) { 69456668Sshin accb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 69556668Sshin aha->resource_shortage = FALSE; 69656668Sshin } 69799877Syar accb->flags = ACCB_FREE; 69856668Sshin SLIST_INSERT_HEAD(&aha->free_aha_ccbs, accb, links); 69925283Sdavidn aha->active_ccbs--; 70099877Syar splx(s); 70199877Syar} 70225283Sdavidn 70399877Syarstatic struct aha_ccb* 70499877Syarahagetccb(struct aha_softc *aha) 70599877Syar{ 70699877Syar struct aha_ccb* accb; 70799877Syar int s; 70899877Syar 70999877Syar s = splcam(); 71099877Syar if ((accb = SLIST_FIRST(&aha->free_aha_ccbs)) != NULL) { 71199877Syar SLIST_REMOVE_HEAD(&aha->free_aha_ccbs, links); 71225283Sdavidn aha->active_ccbs++; 71325283Sdavidn } else if (aha->num_ccbs < aha->max_ccbs) { 71499877Syar ahaallocccbs(aha); 71599877Syar accb = SLIST_FIRST(&aha->free_aha_ccbs); 71699877Syar if (accb == NULL) 717100182Syar device_printf(aha->dev, "Can't malloc ACCB\n"); 71856668Sshin else { 719100182Syar SLIST_REMOVE_HEAD(&aha->free_aha_ccbs, links); 720100182Syar aha->active_ccbs++; 721100182Syar } 722100182Syar } 723100182Syar splx(s); 724100182Syar 725100182Syar return (accb); 726100182Syar} 727100182Syar 728100182Syarstatic void 729100182Syarahaaction(struct cam_sim *sim, union ccb *ccb) 730100182Syar{ 731100182Syar struct aha_softc *aha; 732100182Syar int s; 733100182Syar 734100182Syar CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("ahaaction\n")); 735100182Syar 736100182Syar aha = (struct aha_softc *)cam_sim_softc(sim); 737100182Syar 738100182Syar switch (ccb->ccb_h.func_code) { 739100182Syar /* Common cases first */ 740100182Syar case XPT_SCSI_IO: /* Execute the requested I/O operation */ 741100182Syar case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ { 742100182Syar struct aha_ccb *accb; 743100182Syar struct aha_hccb *hccb; 744100182Syar 745100182Syar /* 746100182Syar * Get an accb to use. 747100182Syar */ 748100182Syar if ((accb = ahagetccb(aha)) == NULL) { 749100182Syar s = splcam(); 750100182Syar aha->resource_shortage = TRUE; 751100182Syar splx(s); 752100182Syar xpt_freeze_simq(aha->sim, /*count*/1); 75356668Sshin ccb->ccb_h.status = CAM_REQUEUE_REQ; 75456668Sshin xpt_done(ccb); 75556668Sshin return; 756102183Syar } 75799877Syar hccb = &accb->hccb; 75856668Sshin 75962100Sdavidn /* 76056668Sshin * So we can find the ACCB when an abort is requested 76162100Sdavidn */ 76225283Sdavidn accb->ccb = ccb; 76357124Sshin ccb->ccb_h.ccb_accb_ptr = accb; 76457124Sshin ccb->ccb_h.ccb_aha_ptr = aha; 76557124Sshin 76657124Sshin /* 76757124Sshin * Put all the arguments for the xfer in the accb 76857124Sshin */ 76957124Sshin hccb->target = ccb->ccb_h.target_id; 77062100Sdavidn hccb->lun = ccb->ccb_h.target_lun; 77162100Sdavidn hccb->ahastat = 0; 77257124Sshin hccb->sdstat = 0; 773100183Syar 77462100Sdavidn if (ccb->ccb_h.func_code == XPT_SCSI_IO) { 77562100Sdavidn struct ccb_scsiio *csio; 77625283Sdavidn struct ccb_hdr *ccbh; 77725283Sdavidn 77825283Sdavidn csio = &ccb->csio; 77999877Syar ccbh = &csio->ccb_h; 780102183Syar hccb->opcode = aha->ccb_ccb_opcode; 781100182Syar hccb->datain = (ccb->ccb_h.flags & CAM_DIR_IN) != 0; 782102473Syar hccb->dataout = (ccb->ccb_h.flags & CAM_DIR_OUT) != 0; 783106754Syar hccb->cmd_len = csio->cdb_len; 784102473Syar if (hccb->cmd_len > sizeof(hccb->scsi_cdb)) { 785100182Syar ccb->ccb_h.status = CAM_REQ_INVALID; 786102473Syar ahafreeccb(aha, accb); 78757124Sshin xpt_done(ccb); 78857124Sshin return; 78925283Sdavidn } 79025283Sdavidn hccb->sense_len = csio->sense_len; 79156668Sshin if ((ccbh->flags & CAM_CDB_POINTER) != 0) { 79225283Sdavidn if ((ccbh->flags & CAM_CDB_PHYS) == 0) { 79325283Sdavidn bcopy(csio->cdb_io.cdb_ptr, 79456668Sshin hccb->scsi_cdb, hccb->cmd_len); 79557124Sshin } else { 79656668Sshin /* I guess I could map it in... */ 797100259Syar ccbh->status = CAM_REQ_INVALID; 798100259Syar ahafreeccb(aha, accb); 79956668Sshin xpt_done(ccb); 80056668Sshin return; 801100259Syar } 802100259Syar } else { 80356668Sshin bcopy(csio->cdb_io.cdb_bytes, 80456668Sshin hccb->scsi_cdb, hccb->cmd_len); 80556668Sshin } 806102473Syar /* 807102473Syar * If we have any data to send with this command, 808102473Syar * map it into bus space. 809102473Syar */ 810102473Syar /* Only use S/G if there is a transfer */ 81199877Syar if ((ccbh->flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 81256668Sshin if ((ccbh->flags & CAM_SCATTER_VALID) == 0) { 81356668Sshin /* 814100612Syar * We've been given a pointer 81557124Sshin * to a single buffer. 81656668Sshin */ 817100182Syar if ((ccbh->flags & CAM_DATA_PHYS)==0) { 81825283Sdavidn int error; 819100182Syar 82025283Sdavidn s = splsoftvm(); 82125283Sdavidn error = bus_dmamap_load( 82225283Sdavidn aha->buffer_dmat, 823100182Syar accb->dmamap, 82425283Sdavidn csio->data_ptr, 82525283Sdavidn csio->dxfer_len, 826100182Syar ahaexecuteccb, 82725283Sdavidn accb, 82825283Sdavidn /*flags*/0); 82925283Sdavidn if (error == EINPROGRESS) { 830102183Syar /* 831102183Syar * So as to maintain 832102183Syar * ordering, freeze the 833102183Syar * controller queue 834102183Syar * until our mapping is 835102183Syar * returned. 836102473Syar */ 837102473Syar xpt_freeze_simq(aha->sim, 838102473Syar 1); 839102473Syar csio->ccb_h.status |= 840102473Syar CAM_RELEASE_SIMQ; 841100182Syar } 842102473Syar splx(s); 843100182Syar } else { 844100182Syar struct bus_dma_segment seg; 845100182Syar 846100182Syar /* Pointer to physical buffer */ 847100182Syar seg.ds_addr = 848100182Syar (bus_addr_t)csio->data_ptr; 849100182Syar seg.ds_len = csio->dxfer_len; 850100182Syar ahaexecuteccb(accb, &seg, 1, 0); 851100182Syar } 852100263Syar } else { 853100263Syar struct bus_dma_segment *segs; 85456668Sshin 85599877Syar if ((ccbh->flags & CAM_DATA_PHYS) != 0) 85699877Syar panic("ahaaction - Physical " 85799877Syar "segment pointers " 85825283Sdavidn "unsupported"); 85925283Sdavidn 86025283Sdavidn if ((ccbh->flags&CAM_SG_LIST_PHYS)==0) 86125283Sdavidn panic("ahaaction - Virtual " 86225283Sdavidn "segment addresses " 86325283Sdavidn "unsupported"); 86490148Simp 86525283Sdavidn /* Just use the segments provided */ 86625283Sdavidn segs = (struct bus_dma_segment *) 86756668Sshin csio->data_ptr; 86856668Sshin ahaexecuteccb(accb, segs, 86956668Sshin csio->sglist_cnt, 0); 87056668Sshin } 87157124Sshin } else { 87225283Sdavidn ahaexecuteccb(accb, NULL, 0, 0); 87356668Sshin } 87456668Sshin } else { 87556668Sshin hccb->opcode = INITIATOR_BUS_DEV_RESET; 87656668Sshin /* No data transfer */ 87756668Sshin hccb->datain = TRUE; 87856668Sshin hccb->dataout = TRUE; 87956668Sshin hccb->cmd_len = 0; 88056668Sshin hccb->sense_len = 0; 88156668Sshin ahaexecuteccb(accb, NULL, 0, 0); 88256668Sshin } 88325283Sdavidn break; 88456668Sshin } 88556668Sshin case XPT_EN_LUN: /* Enable LUN as a target */ 88625283Sdavidn case XPT_TARGET_IO: /* Execute target I/O request */ 88762100Sdavidn case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */ 88857124Sshin case XPT_CONT_TARGET_IO: /* Continue Host Target I/O Connection*/ 88925283Sdavidn case XPT_ABORT: /* Abort the specified CCB */ 89025283Sdavidn /* XXX Implement */ 89125283Sdavidn ccb->ccb_h.status = CAM_REQ_INVALID; 89256668Sshin xpt_done(ccb); 89356668Sshin break; 89457124Sshin case XPT_SET_TRAN_SETTINGS: 89556668Sshin /* XXX Implement */ 89657124Sshin ccb->ccb_h.status = CAM_PROVIDE_FAIL; 89756668Sshin xpt_done(ccb); 89856668Sshin break; 89956668Sshin case XPT_GET_TRAN_SETTINGS: 90056668Sshin /* Get default/user set transfer settings for the target */ 90156668Sshin { 90262100Sdavidn struct ccb_trans_settings *cts = &ccb->cts; 90362100Sdavidn u_int target_mask = 0x01 << ccb->ccb_h.target_id; 90425283Sdavidn#ifdef CAM_NEW_TRAN_CODE 90556668Sshin struct ccb_trans_settings_scsi *scsi = 90625283Sdavidn &cts->proto_specific.scsi; 90725283Sdavidn struct ccb_trans_settings_spi *spi = 90825283Sdavidn &cts->xport_specific.spi; 90925283Sdavidn 91025283Sdavidn cts->protocol = PROTO_SCSI; 91125283Sdavidn cts->protocol_version = SCSI_REV_2; 91225283Sdavidn cts->transport = XPORT_SPI; 9131592Srgrimes cts->transport_version = 2; 9141592Srgrimes if (cts->type == CTS_TYPE_USER_SETTINGS) { 9151592Srgrimes spi->flags = 0; 91690148Simp if ((aha->disc_permitted & target_mask) != 0) 9171592Srgrimes spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 9181592Srgrimes spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 9191592Srgrimes if ((aha->sync_permitted & target_mask) != 0) { 9201592Srgrimes if (aha->boardid >= BOARD_1542CF) 9211592Srgrimes spi->sync_period = 25; 9221592Srgrimes else 9231592Srgrimes spi->sync_period = 50; 9241592Srgrimes } else { 9251592Srgrimes spi->sync_period = 0; 9261592Srgrimes } 9271592Srgrimes 9281592Srgrimes if (spi->sync_period != 0) 9291592Srgrimes spi->sync_offset = 15; 9301592Srgrimes 9311592Srgrimes spi->valid = CTS_SPI_VALID_SYNC_RATE 9321592Srgrimes | CTS_SPI_VALID_SYNC_OFFSET 9331592Srgrimes | CTS_SPI_VALID_BUS_WIDTH 9341592Srgrimes | CTS_SPI_VALID_DISC; 93590148Simp scsi->valid = CTS_SCSI_VALID_TQ; 9361592Srgrimes } else { 9371592Srgrimes ahafetchtransinfo(aha, cts); 9381592Srgrimes } 9391592Srgrimes#else 9401592Srgrimes if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) { 9411592Srgrimes cts->flags = 0; 9421592Srgrimes if ((aha->disc_permitted & target_mask) != 0) 9431592Srgrimes cts->flags |= CCB_TRANS_DISC_ENB; 9441592Srgrimes cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 9451592Srgrimes if ((aha->sync_permitted & target_mask) != 0) { 9461592Srgrimes if (aha->boardid >= BOARD_1542CF) 9471592Srgrimes cts->sync_period = 25; 9481592Srgrimes else 9491592Srgrimes cts->sync_period = 50; 9501592Srgrimes } else 9511592Srgrimes cts->sync_period = 0; 9521592Srgrimes 9531592Srgrimes if (cts->sync_period != 0) 9541592Srgrimes cts->sync_offset = 15; 9551592Srgrimes 9561592Srgrimes cts->valid = CCB_TRANS_SYNC_RATE_VALID 9571592Srgrimes | CCB_TRANS_SYNC_OFFSET_VALID 9581592Srgrimes | CCB_TRANS_BUS_WIDTH_VALID 9591592Srgrimes | CCB_TRANS_DISC_VALID 96064778Ssheldonh | CCB_TRANS_TQ_VALID; 9611592Srgrimes } else { 9621592Srgrimes ahafetchtransinfo(aha, cts); 9631592Srgrimes } 9641592Srgrimes#endif 9651592Srgrimes 9661592Srgrimes ccb->ccb_h.status = CAM_REQ_CMP; 9671592Srgrimes xpt_done(ccb); 9681592Srgrimes break; 9691592Srgrimes } 9701592Srgrimes case XPT_CALC_GEOMETRY: 9711592Srgrimes { 9721592Srgrimes struct ccb_calc_geometry *ccg; 9731592Srgrimes uint32_t size_mb; 97490148Simp uint32_t secs_per_cylinder; 9751592Srgrimes 9761592Srgrimes ccg = &ccb->ccg; 9771592Srgrimes size_mb = ccg->volume_size 9781592Srgrimes / ((1024L * 1024L) / ccg->block_size); 9791592Srgrimes if (size_mb >= 1024 && (aha->extended_trans != 0)) { 9801592Srgrimes if (size_mb >= 2048) { 9811592Srgrimes ccg->heads = 255; 98217435Spst ccg->secs_per_track = 63; 98317435Spst } else { 98417435Spst ccg->heads = 128; 9851592Srgrimes ccg->secs_per_track = 32; 9861592Srgrimes } 9871592Srgrimes } else { 9881592Srgrimes ccg->heads = 64; 9891592Srgrimes ccg->secs_per_track = 32; 9901592Srgrimes } 991109893Syar secs_per_cylinder = ccg->heads * ccg->secs_per_track; 992109893Syar ccg->cylinders = ccg->volume_size / secs_per_cylinder; 9931592Srgrimes ccb->ccb_h.status = CAM_REQ_CMP; 99425283Sdavidn xpt_done(ccb); 99525283Sdavidn break; 99625283Sdavidn } 9971592Srgrimes case XPT_RESET_BUS: /* Reset the specified SCSI bus */ 99825283Sdavidn ahareset(aha, /*hardreset*/TRUE); 9991592Srgrimes ccb->ccb_h.status = CAM_REQ_CMP; 10001592Srgrimes xpt_done(ccb); 10011592Srgrimes break; 10023938Spst case XPT_TERM_IO: /* Terminate the I/O process */ 10031592Srgrimes /* XXX Implement */ 10041592Srgrimes ccb->ccb_h.status = CAM_REQ_INVALID; 10051592Srgrimes xpt_done(ccb); 10061592Srgrimes break; 10071592Srgrimes case XPT_PATH_INQ: /* Path routing inquiry */ 10081592Srgrimes { 10091592Srgrimes struct ccb_pathinq *cpi = &ccb->cpi; 101020042Storstenb 101120042Storstenb cpi->version_num = 1; /* XXX??? */ 101220042Storstenb cpi->hba_inquiry = PI_SDTR_ABLE; 101320042Storstenb cpi->target_sprt = 0; 101420042Storstenb cpi->hba_misc = 0; 101517478Smarkm cpi->hba_eng_cnt = 0; 10161592Srgrimes cpi->max_target = 7; 10171592Srgrimes cpi->max_lun = 7; 1018124687Scharnier cpi->initiator_id = aha->scsi_id; 10191592Srgrimes cpi->bus_id = cam_sim_bus(sim); 10201592Srgrimes cpi->base_transfer_speed = 3300; 10211592Srgrimes strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 10221592Srgrimes strncpy(cpi->hba_vid, "Adaptec", HBA_IDLEN); 10231592Srgrimes strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 1024109893Syar cpi->unit_number = cam_sim_unit(sim); 10251592Srgrimes#ifdef CAM_NEW_TRAN_CODE 10261592Srgrimes cpi->transport = XPORT_SPI; 10271592Srgrimes cpi->transport_version = 2; 10281592Srgrimes cpi->protocol = PROTO_SCSI; 10291592Srgrimes cpi->protocol_version = SCSI_REV_2; 10301592Srgrimes#endif 10311592Srgrimes cpi->ccb_h.status = CAM_REQ_CMP; 10321592Srgrimes xpt_done(ccb); 10331592Srgrimes break; 10341592Srgrimes } 10351592Srgrimes default: 103688763Sache ccb->ccb_h.status = CAM_REQ_INVALID; 103788763Sache xpt_done(ccb); 103879469Smarkm break; 103979469Smarkm } 104088763Sache} 104188763Sache 104288763Sachestatic void 104388763Sacheahaexecuteccb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 104488763Sache{ 104588763Sache struct aha_ccb *accb; 104688763Sache union ccb *ccb; 104788763Sache struct aha_softc *aha; 104888763Sache int s; 104984146Sache uint32_t paddr; 105088763Sache 10511592Srgrimes accb = (struct aha_ccb *)arg; 10521592Srgrimes ccb = accb->ccb; 10531592Srgrimes aha = (struct aha_softc *)ccb->ccb_h.ccb_aha_ptr; 10541592Srgrimes 10551592Srgrimes if (error != 0) { 10561592Srgrimes if (error != EFBIG) 10571592Srgrimes device_printf(aha->dev, 10581592Srgrimes "Unexepected error 0x%x returned from " 10591592Srgrimes "bus_dmamap_load\n", error); 10601592Srgrimes if (ccb->ccb_h.status == CAM_REQ_INPROG) { 1061109893Syar xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 1062109893Syar ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN; 1063109893Syar } 10641592Srgrimes ahafreeccb(aha, accb); 10651592Srgrimes xpt_done(ccb); 1066109893Syar return; 10671592Srgrimes } 10681592Srgrimes 10691592Srgrimes if (nseg != 0) { 107099877Syar aha_sg_t *sg; 107199877Syar bus_dma_segment_t *end_seg; 10721592Srgrimes bus_dmasync_op_t op; 107317435Spst 107499877Syar end_seg = dm_segs + nseg; 107599877Syar 107699877Syar /* Copy the segments into our SG list */ 107799877Syar sg = accb->sg_list; 107899877Syar while (dm_segs < end_seg) { 107999877Syar ahautoa24(dm_segs->ds_len, sg->len); 108099877Syar ahautoa24(dm_segs->ds_addr, sg->addr); 108199877Syar sg++; 108299877Syar dm_segs++; 108399877Syar } 108499877Syar 108599877Syar if (nseg > 1) { 108699877Syar accb->hccb.opcode = aha->ccb_sg_opcode; 108799877Syar ahautoa24((sizeof(aha_sg_t) * nseg), 108899877Syar accb->hccb.data_len); 108999877Syar ahautoa24(accb->sg_list_phys, accb->hccb.data_addr); 109099877Syar } else { 109199877Syar bcopy(accb->sg_list->len, accb->hccb.data_len, 3); 109299877Syar bcopy(accb->sg_list->addr, accb->hccb.data_addr, 3); 109399877Syar } 109499877Syar 109599877Syar if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 109699877Syar op = BUS_DMASYNC_PREREAD; 109799877Syar else 109899877Syar op = BUS_DMASYNC_PREWRITE; 109999877Syar 1100109893Syar bus_dmamap_sync(aha->buffer_dmat, accb->dmamap, op); 110199877Syar 1102109893Syar } else { 1103109893Syar accb->hccb.opcode = INITIATOR_CCB; 1104109893Syar ahautoa24(0, accb->hccb.data_len); 1105109893Syar ahautoa24(0, accb->hccb.data_addr); 1106109893Syar } 1107109893Syar 1108109893Syar s = splcam(); 1109109893Syar 1110109893Syar /* 1111109893Syar * Last time we need to check if this CCB needs to 1112109893Syar * be aborted. 1113109893Syar */ 1114109893Syar if (ccb->ccb_h.status != CAM_REQ_INPROG) { 1115109893Syar if (nseg != 0) 1116109893Syar bus_dmamap_unload(aha->buffer_dmat, accb->dmamap); 1117109893Syar ahafreeccb(aha, accb); 11181592Srgrimes xpt_done(ccb); 111999877Syar splx(s); 112099877Syar return; 112199877Syar } 112299877Syar 112399877Syar accb->flags = ACCB_ACTIVE; 1124109893Syar ccb->ccb_h.status |= CAM_SIM_QUEUED; 1125109893Syar LIST_INSERT_HEAD(&aha->pending_ccbs, &ccb->ccb_h, sim_links.le); 1126109893Syar 1127109893Syar ccb->ccb_h.timeout_ch = timeout(ahatimeout, (caddr_t)accb, 1128109938Syar (ccb->ccb_h.timeout * hz) / 1000); 1129109938Syar 1130109938Syar /* Tell the adapter about this command */ 1131109893Syar if (aha->cur_outbox->action_code != AMBO_FREE) { 1132109893Syar /* 1133109893Syar * We should never encounter a busy mailbox. 1134109893Syar * If we do, warn the user, and treat it as 1135109893Syar * a resource shortage. If the controller is 113699877Syar * hung, one of the pending transactions will 113799877Syar * timeout causing us to start recovery operations. 113899877Syar */ 113999877Syar device_printf(aha->dev, 11401592Srgrimes "Encountered busy mailbox with %d out of %d " 11411592Srgrimes "commands active!!!", aha->active_ccbs, aha->max_ccbs); 11421592Srgrimes untimeout(ahatimeout, accb, ccb->ccb_h.timeout_ch); 11431592Srgrimes if (nseg != 0) 11441592Srgrimes bus_dmamap_unload(aha->buffer_dmat, accb->dmamap); 11451592Srgrimes ahafreeccb(aha, accb); 11461592Srgrimes aha->resource_shortage = TRUE; 11471592Srgrimes xpt_freeze_simq(aha->sim, /*count*/1); 11481592Srgrimes ccb->ccb_h.status = CAM_REQUEUE_REQ; 11491592Srgrimes xpt_done(ccb); 115090148Simp return; 11511592Srgrimes } 115274874Smarkm paddr = ahaccbvtop(aha, accb); 115374874Smarkm ahautoa24(paddr, aha->cur_outbox->ccb_addr); 115474874Smarkm aha->cur_outbox->action_code = AMBO_START; 11551592Srgrimes aha_outb(aha, COMMAND_REG, AOP_START_MBOX); 11561592Srgrimes 1157102311Syar ahanextoutbox(aha); 115889920Sume splx(s); 11591592Srgrimes} 116025101Sdavidn 116125101Sdavidnvoid 1162105877Srwatsonaha_intr(void *arg) 1163105877Srwatson{ 116425101Sdavidn struct aha_softc *aha; 116574874Smarkm u_int intstat; 116674874Smarkm uint32_t paddr; 116774874Smarkm 116874874Smarkm aha = (struct aha_softc *)arg; 116974874Smarkm while (((intstat = aha_inb(aha, INTSTAT_REG)) & INTR_PENDING) != 0) { 117074874Smarkm if ((intstat & CMD_COMPLETE) != 0) { 117174874Smarkm aha->latched_status = aha_inb(aha, STATUS_REG); 117274874Smarkm aha->command_cmp = TRUE; 117374874Smarkm } 11741592Srgrimes 11751592Srgrimes aha_outb(aha, CONTROL_REG, RESET_INTR); 117617435Spst 11771592Srgrimes if ((intstat & IMB_LOADED) != 0) { 11781592Srgrimes while (aha->cur_inbox->comp_code != AMBI_FREE) { 117974874Smarkm paddr = aha_a24tou(aha->cur_inbox->ccb_addr); 118051433Smarkm ahadone(aha, ahaccbptov(aha, paddr), 118151433Smarkm aha->cur_inbox->comp_code); 118251433Smarkm aha->cur_inbox->comp_code = AMBI_FREE; 118351433Smarkm ahanextinbox(aha); 118451433Smarkm } 118551433Smarkm } 118651433Smarkm 118751433Smarkm if ((intstat & SCSI_BUS_RESET) != 0) { 118851433Smarkm ahareset(aha, /*hardreset*/FALSE); 118951433Smarkm } 119051433Smarkm } 119151433Smarkm} 119251433Smarkm 119351433Smarkmstatic void 119451433Smarkmahadone(struct aha_softc *aha, struct aha_ccb *accb, aha_mbi_comp_code_t comp_code) 119551433Smarkm{ 119651433Smarkm union ccb *ccb; 119751433Smarkm struct ccb_scsiio *csio; 119851433Smarkm 119991244Sdes ccb = accb->ccb; 120051433Smarkm csio = &accb->ccb->csio; 120191244Sdes 120291244Sdes if ((accb->flags & ACCB_ACTIVE) == 0) { 120391244Sdes device_printf(aha->dev, 120491244Sdes "ahadone - Attempt to free non-active ACCB %p\n", 120551433Smarkm (void *)accb); 120651433Smarkm return; 120751433Smarkm } 120851433Smarkm 120951433Smarkm if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 121051433Smarkm bus_dmasync_op_t op; 121151433Smarkm 121251433Smarkm if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 121351433Smarkm op = BUS_DMASYNC_POSTREAD; 121451433Smarkm else 121551433Smarkm op = BUS_DMASYNC_POSTWRITE; 121651433Smarkm bus_dmamap_sync(aha->buffer_dmat, accb->dmamap, op); 121751433Smarkm bus_dmamap_unload(aha->buffer_dmat, accb->dmamap); 121851433Smarkm } 121951433Smarkm 122051433Smarkm if (accb == aha->recovery_accb) { 122151433Smarkm /* 122251433Smarkm * The recovery ACCB does not have a CCB associated 122351433Smarkm * with it, so short circuit the normal error handling. 122451433Smarkm * We now traverse our list of pending CCBs and process 122551433Smarkm * any that were terminated by the recovery CCBs action. 122651433Smarkm * We also reinstate timeouts for all remaining, pending, 122751433Smarkm * CCBs. 122851433Smarkm */ 122951433Smarkm struct cam_path *path; 123051433Smarkm struct ccb_hdr *ccb_h; 123151433Smarkm cam_status error; 123251433Smarkm 123351433Smarkm /* Notify all clients that a BDR occured */ 123451433Smarkm error = xpt_create_path(&path, /*periph*/NULL, 123551433Smarkm cam_sim_path(aha->sim), accb->hccb.target, 123651433Smarkm CAM_LUN_WILDCARD); 123751433Smarkm 123851433Smarkm if (error == CAM_REQ_CMP) 123951433Smarkm xpt_async(AC_SENT_BDR, path, NULL); 124051433Smarkm 124151433Smarkm ccb_h = LIST_FIRST(&aha->pending_ccbs); 124251433Smarkm while (ccb_h != NULL) { 124351433Smarkm struct aha_ccb *pending_accb; 124451433Smarkm 124551433Smarkm pending_accb = (struct aha_ccb *)ccb_h->ccb_accb_ptr; 124651433Smarkm if (pending_accb->hccb.target == accb->hccb.target) { 124751433Smarkm pending_accb->hccb.ahastat = AHASTAT_HA_BDR; 124851433Smarkm ccb_h = LIST_NEXT(ccb_h, sim_links.le); 124951433Smarkm ahadone(aha, pending_accb, AMBI_ERROR); 125051433Smarkm } else { 125151433Smarkm ccb_h->timeout_ch = timeout(ahatimeout, 125251433Smarkm (caddr_t)pending_accb, 125351433Smarkm (ccb_h->timeout * hz) / 1000); 125451433Smarkm ccb_h = LIST_NEXT(ccb_h, sim_links.le); 125551433Smarkm } 125667007Sguido } 125767007Sguido device_printf(aha->dev, "No longer in timeout\n"); 125867007Sguido return; 125967007Sguido } 126067007Sguido 126167007Sguido untimeout(ahatimeout, accb, ccb->ccb_h.timeout_ch); 126267007Sguido 126351433Smarkm switch (comp_code) { 126451433Smarkm case AMBI_FREE: 126551433Smarkm device_printf(aha->dev, 126651433Smarkm "ahadone - CCB completed with free status!\n"); 126751433Smarkm break; 126851433Smarkm case AMBI_NOT_FOUND: 126951433Smarkm device_printf(aha->dev, 127051433Smarkm "ahadone - CCB Abort failed to find CCB\n"); 127151433Smarkm break; 127251433Smarkm case AMBI_ABORT: 127351433Smarkm case AMBI_ERROR: 127451433Smarkm /* An error occured */ 127551433Smarkm if (accb->hccb.opcode < INITIATOR_CCB_WRESID) 127651433Smarkm csio->resid = 0; 127751433Smarkm else 127851433Smarkm csio->resid = aha_a24tou(accb->hccb.data_len); 127951433Smarkm switch(accb->hccb.ahastat) { 128051433Smarkm case AHASTAT_DATARUN_ERROR: 128151433Smarkm { 128251433Smarkm if (csio->resid <= 0) { 128351433Smarkm csio->ccb_h.status = CAM_DATA_RUN_ERR; 128451433Smarkm break; 128551433Smarkm } 128651433Smarkm /* FALLTHROUGH */ 128751433Smarkm } 128851433Smarkm case AHASTAT_NOERROR: 128951433Smarkm csio->scsi_status = accb->hccb.sdstat; 129051433Smarkm csio->ccb_h.status |= CAM_SCSI_STATUS_ERROR; 129151433Smarkm switch(csio->scsi_status) { 129251433Smarkm case SCSI_STATUS_CHECK_COND: 129351433Smarkm case SCSI_STATUS_CMD_TERMINATED: 129451433Smarkm csio->ccb_h.status |= CAM_AUTOSNS_VALID; 129551433Smarkm /* 129651433Smarkm * The aha writes the sense data at different 129751433Smarkm * offsets based on the scsi cmd len 129851433Smarkm */ 129951433Smarkm bcopy((caddr_t) &accb->hccb.scsi_cdb + 130051433Smarkm accb->hccb.cmd_len, 130174874Smarkm (caddr_t) &csio->sense_data, 130251433Smarkm accb->hccb.sense_len); 130351433Smarkm break; 130451433Smarkm default: 130551433Smarkm break; 130674874Smarkm case SCSI_STATUS_OK: 130774874Smarkm csio->ccb_h.status = CAM_REQ_CMP; 130874874Smarkm break; 130974874Smarkm } 131074874Smarkm break; 131174874Smarkm case AHASTAT_SELTIMEOUT: 131274874Smarkm csio->ccb_h.status = CAM_SEL_TIMEOUT; 131374874Smarkm break; 131474874Smarkm case AHASTAT_UNEXPECTED_BUSFREE: 131574874Smarkm csio->ccb_h.status = CAM_UNEXP_BUSFREE; 131674874Smarkm break; 131751433Smarkm case AHASTAT_INVALID_PHASE: 131874874Smarkm csio->ccb_h.status = CAM_SEQUENCE_FAIL; 131974874Smarkm break; 132074874Smarkm case AHASTAT_INVALID_ACTION_CODE: 132174874Smarkm panic("%s: Inavlid Action code", aha_name(aha)); 132274874Smarkm break; 132374874Smarkm case AHASTAT_INVALID_OPCODE: 132474874Smarkm if (accb->hccb.opcode < INITIATOR_CCB_WRESID) 132551433Smarkm panic("%s: Invalid CCB Opcode %x hccb = %p", 132651433Smarkm aha_name(aha), accb->hccb.opcode, 132751433Smarkm &accb->hccb); 132874874Smarkm device_printf(aha->dev, 132951433Smarkm "AHA-1540A compensation failed\n"); 13301592Srgrimes xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 133190148Simp csio->ccb_h.status = CAM_REQUEUE_REQ; 13321592Srgrimes break; 133317435Spst case AHASTAT_LINKED_CCB_LUN_MISMATCH: 13341592Srgrimes /* We don't even support linked commands... */ 133525101Sdavidn panic("%s: Linked CCB Lun Mismatch", aha_name(aha)); 133625101Sdavidn break; 133725101Sdavidn case AHASTAT_INVALID_CCB_OR_SG_PARAM: 133874874Smarkm panic("%s: Invalid CCB or SG list", aha_name(aha)); 133974874Smarkm break; 134074874Smarkm case AHASTAT_HA_SCSI_BUS_RESET: 1341110036Syar if ((csio->ccb_h.status & CAM_STATUS_MASK) 1342109939Syar != CAM_CMD_TIMEOUT) 134388763Sache csio->ccb_h.status = CAM_SCSI_BUS_RESET; 13441592Srgrimes break; 13451592Srgrimes case AHASTAT_HA_BDR: 13461592Srgrimes if ((accb->flags & ACCB_DEVICE_RESET) == 0) 13471592Srgrimes csio->ccb_h.status = CAM_BDR_SENT; 13481592Srgrimes else 13491592Srgrimes csio->ccb_h.status = CAM_CMD_TIMEOUT; 13501592Srgrimes break; 135117435Spst } 135217435Spst if (csio->ccb_h.status != CAM_REQ_CMP) { 135317435Spst xpt_freeze_devq(csio->ccb_h.path, /*count*/1); 135417435Spst csio->ccb_h.status |= CAM_DEV_QFRZN; 135574874Smarkm } 135651433Smarkm if ((accb->flags & ACCB_RELEASE_SIMQ) != 0) 135789622Sache ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 135889622Sache ahafreeccb(aha, accb); 135917435Spst xpt_done(ccb); 136089622Sache break; 136189622Sache case AMBI_OK: 136288763Sache /* All completed without incident */ 136388763Sache /* XXX DO WE NEED TO COPY SENSE BYTES HERE???? XXX */ 136489622Sache /* I don't think so since it works???? */ 136588763Sache ccb->ccb_h.status |= CAM_REQ_CMP; 136689622Sache if ((accb->flags & ACCB_RELEASE_SIMQ) != 0) 136789622Sache ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 136889622Sache ahafreeccb(aha, accb); 136988763Sache xpt_done(ccb); 137088763Sache break; 137188763Sache } 137288763Sache} 137389622Sache 137417435Spststatic int 137517435Spstahareset(struct aha_softc* aha, int hard_reset) 137617435Spst{ 137717435Spst struct ccb_hdr *ccb_h; 137851433Smarkm u_int status; 137917435Spst u_int timeout; 138017435Spst uint8_t reset_type; 138117435Spst 13821592Srgrimes if (hard_reset != 0) 1383110691Syar reset_type = HARD_RESET; 13841592Srgrimes else 1385110691Syar reset_type = SOFT_RESET; 1386110691Syar aha_outb(aha, CONTROL_REG, reset_type); 1387110691Syar 13881592Srgrimes /* Wait 5sec. for Diagnostic start */ 13891592Srgrimes timeout = 5 * 10000; 1390110691Syar while (--timeout) { 13911592Srgrimes status = aha_inb(aha, STATUS_REG); 13921592Srgrimes if ((status & DIAG_ACTIVE) != 0) 13931592Srgrimes break; 13941592Srgrimes DELAY(100); 13951592Srgrimes } 13961592Srgrimes if (timeout == 0) { 13971592Srgrimes PRVERB((aha->dev, "ahareset - Diagnostic Active failed to " 13981592Srgrimes "assert. status = %#x\n", status)); 13991592Srgrimes return (ETIMEDOUT); 14001592Srgrimes } 14011592Srgrimes 14021592Srgrimes /* Wait 10sec. for Diagnostic end */ 14031592Srgrimes timeout = 10 * 10000; 14041592Srgrimes while (--timeout) { 14051592Srgrimes status = aha_inb(aha, STATUS_REG); 140625101Sdavidn if ((status & DIAG_ACTIVE) == 0) 140725101Sdavidn break; 140825101Sdavidn DELAY(100); 140925674Sdavidn } 141025101Sdavidn if (timeout == 0) { 141125101Sdavidn panic("%s: ahareset - Diagnostic Active failed to drop. " 141256668Sshin "status = 0x%x\n", aha_name(aha), status); 141356668Sshin return (ETIMEDOUT); 141499255Sume } 141525101Sdavidn 141625101Sdavidn /* Wait for the host adapter to become ready or report a failure */ 141725101Sdavidn timeout = 10000; 141825101Sdavidn while (--timeout) { 141925101Sdavidn status = aha_inb(aha, STATUS_REG); 142025101Sdavidn if ((status & (DIAG_FAIL|HA_READY|DATAIN_REG_READY)) != 0) 142125101Sdavidn break; 142225101Sdavidn DELAY(100); 142325101Sdavidn } 142425101Sdavidn if (timeout == 0) { 142525101Sdavidn device_printf(aha->dev, "ahareset - Host adapter failed to " 142625101Sdavidn "come ready. status = 0x%x\n", status); 142725101Sdavidn return (ETIMEDOUT); 142825101Sdavidn } 142925101Sdavidn 143025101Sdavidn /* If the diagnostics failed, tell the user */ 143140310Sdes if ((status & DIAG_FAIL) != 0 1432105877Srwatson || (status & HA_READY) == 0) { 143325101Sdavidn device_printf(aha->dev, "ahareset - Adapter failed diag\n"); 143440310Sdes 14351592Srgrimes if ((status & DATAIN_REG_READY) != 0) 143625101Sdavidn device_printf(aha->dev, "ahareset - Host Adapter " 14371592Srgrimes "Error code = 0x%x\n", aha_inb(aha, DATAIN_REG)); 143874874Smarkm return (ENXIO); 143974874Smarkm } 144074874Smarkm 144174874Smarkm /* If we've attached to the XPT, tell it about the event */ 144274874Smarkm if (aha->path != NULL) 144374874Smarkm xpt_async(AC_BUS_RESET, aha->path, NULL); 144474874Smarkm 144574874Smarkm /* 144674874Smarkm * Perform completion processing for all outstanding CCBs. 144774874Smarkm */ 14481592Srgrimes while ((ccb_h = LIST_FIRST(&aha->pending_ccbs)) != NULL) { 1449102311Syar struct aha_ccb *pending_accb; 1450102311Syar 1451102311Syar pending_accb = (struct aha_ccb *)ccb_h->ccb_accb_ptr; 14521592Srgrimes pending_accb->hccb.ahastat = AHASTAT_HA_SCSI_BUS_RESET; 14531592Srgrimes ahadone(aha, pending_accb, AMBI_ERROR); 145417435Spst } 145525283Sdavidn 145625283Sdavidn /* If we've allocated mailboxes, initialize them */ 145725283Sdavidn /* Must be done after we've aborted our queue, or aha_cmd fails */ 14586740Sguido if (aha->init_level > 4) 145925283Sdavidn ahainitmboxes(aha); 14606740Sguido 14616740Sguido return (0); 146225101Sdavidn} 1463109939Syar 146425101Sdavidn/* 1465109893Syar * Send a command to the adapter. 146625101Sdavidn */ 1467109893Syarint 1468110036Syaraha_cmd(struct aha_softc *aha, aha_op_t opcode, uint8_t *params, 1469110036Syar u_int param_len, uint8_t *reply_data, u_int reply_len, 1470110036Syar u_int cmd_timeout) 1471110036Syar{ 1472110036Syar u_int timeout; 1473110036Syar u_int status; 1474110036Syar u_int saved_status; 1475110036Syar u_int intstat; 1476117349Syar u_int reply_buf_size; 1477117349Syar int s; 1478117349Syar int cmd_complete; 1479117349Syar int error; 1480117349Syar 1481110036Syar /* No data returned to start */ 1482110036Syar reply_buf_size = reply_len; 1483110036Syar reply_len = 0; 1484110036Syar intstat = 0; 14851592Srgrimes cmd_complete = 0; 1486110036Syar saved_status = 0; 1487110036Syar error = 0; 14881592Srgrimes 1489110036Syar /* 1490110036Syar * All commands except for the "start mailbox" and the "enable 1491110036Syar * outgoing mailbox read interrupt" commands cannot be issued 1492110036Syar * while there are pending transactions. Freeze our SIMQ 1493110036Syar * and wait for all completions to occur if necessary. 1494110036Syar */ 1495110036Syar timeout = 10000; 1496110036Syar s = splcam(); 1497110036Syar while (LIST_FIRST(&aha->pending_ccbs) != NULL && --timeout) { 1498110036Syar /* Fire the interrupt handler in case interrupts are blocked */ 1499110036Syar aha_intr(aha); 1500110036Syar splx(s); 1501109893Syar DELAY(10); 1502110036Syar s = splcam(); 1503110036Syar } 1504110036Syar splx(s); 1505110036Syar 1506110036Syar if (timeout == 0) { 1507110036Syar device_printf(aha->dev, 1508110036Syar "aha_cmd: Timeout waiting for adapter idle\n"); 1509109939Syar return (ETIMEDOUT); 1510110036Syar } 1511110036Syar aha->command_cmp = 0; 1512110036Syar /* 1513110036Syar * Wait up to 10 sec. for the adapter to become 151417435Spst * ready to accept commands. 151517435Spst */ 151617435Spst timeout = 100000; 1517110036Syar while (--timeout) { 1518110036Syar status = aha_inb(aha, STATUS_REG); 1519110036Syar if ((status & HA_READY) != 0 && (status & CMD_REG_BUSY) == 0) 1520110036Syar break; 1521110036Syar /* 1522110036Syar * Throw away any pending data which may be 1523110036Syar * left over from earlier commands that we 1524110036Syar * timedout on. 1525110036Syar */ 15261592Srgrimes if ((status & DATAIN_REG_READY) != 0) 15271592Srgrimes (void)aha_inb(aha, DATAIN_REG); 15281592Srgrimes DELAY(100); 15291592Srgrimes } 1530110036Syar if (timeout == 0) { 1531110036Syar device_printf(aha->dev, "aha_cmd: Timeout waiting for adapter" 1532110036Syar " ready, status = 0x%x\n", status); 1533110036Syar return (ETIMEDOUT); 1534110036Syar } 1535110036Syar 1536110036Syar /* 1537110036Syar * Send the opcode followed by any necessary parameter bytes. 1538110036Syar */ 1539110036Syar aha_outb(aha, COMMAND_REG, opcode); 1540110036Syar 1541110036Syar /* 15428696Sdg * Wait for up to 1sec to get the parameter list sent 15431592Srgrimes */ 15441592Srgrimes timeout = 10000; 15451592Srgrimes while (param_len && --timeout) { 15461592Srgrimes DELAY(100); 154725283Sdavidn s = splcam(); 154825283Sdavidn status = aha_inb(aha, STATUS_REG); 154925283Sdavidn intstat = aha_inb(aha, INTSTAT_REG); 15501592Srgrimes splx(s); 155125283Sdavidn 15521592Srgrimes if ((intstat & (INTR_PENDING|CMD_COMPLETE)) 15531592Srgrimes == (INTR_PENDING|CMD_COMPLETE)) { 15541592Srgrimes saved_status = status; 15551592Srgrimes cmd_complete = 1; 15561592Srgrimes break; 15571592Srgrimes } 15581592Srgrimes 15591592Srgrimes if (aha->command_cmp != 0) { 15601592Srgrimes saved_status = aha->latched_status; 15611592Srgrimes cmd_complete = 1; 15621592Srgrimes break; 15636740Sguido } 15646740Sguido if ((status & DATAIN_REG_READY) != 0) 156517433Spst break; 156617433Spst if ((status & CMD_REG_BUSY) == 0) { 156776096Smarkm aha_outb(aha, COMMAND_REG, *params++); 156817433Spst param_len--; 15691592Srgrimes timeout = 10000; 15701592Srgrimes } 157125283Sdavidn } 157225283Sdavidn if (timeout == 0) { 157325283Sdavidn device_printf(aha->dev, "aha_cmd: Timeout sending parameters, " 157483308Smikeh "status = 0x%x\n", status); 157583308Smikeh error = ETIMEDOUT; 157625283Sdavidn } 157725283Sdavidn 157825283Sdavidn /* 157983308Smikeh * For all other commands, we wait for any output data 158013139Speter * and the final comand completion interrupt. 15811592Srgrimes */ 15821592Srgrimes while (cmd_complete == 0 && --cmd_timeout) { 15831592Srgrimes 15841592Srgrimes s = splcam(); 15851592Srgrimes status = aha_inb(aha, STATUS_REG); 158684841Syar intstat = aha_inb(aha, INTSTAT_REG); 158784841Syar splx(s); 158884841Syar 158984841Syar if (aha->command_cmp != 0) { 159084841Syar cmd_complete = 1; 159125986Sdanny saved_status = aha->latched_status; 15921592Srgrimes } else if ((intstat & (INTR_PENDING|CMD_COMPLETE)) 15931592Srgrimes == (INTR_PENDING|CMD_COMPLETE)) { 159484842Syar /* 159513139Speter * Our poll (in case interrupts are blocked) 15961592Srgrimes * saw the CMD_COMPLETE interrupt. 15971592Srgrimes */ 15981592Srgrimes cmd_complete = 1; 15991592Srgrimes saved_status = status; 16001592Srgrimes } 160125101Sdavidn if ((status & DATAIN_REG_READY) != 0) { 160225101Sdavidn uint8_t data; 160325101Sdavidn 1604110036Syar data = aha_inb(aha, DATAIN_REG); 1605110036Syar if (reply_len < reply_buf_size) { 1606110036Syar *reply_data++ = data; 1607110036Syar } else { 16081592Srgrimes device_printf(aha->dev, 16091592Srgrimes "aha_cmd - Discarded reply data " 16101592Srgrimes "byte for opcode 0x%x\n", opcode); 161125101Sdavidn } 161225101Sdavidn /* 161325101Sdavidn * Reset timeout to ensure at least a second 1614110036Syar * between response bytes. 1615110036Syar */ 1616110036Syar cmd_timeout = MAX(cmd_timeout, 10000); 1617110036Syar reply_len++; 16181592Srgrimes } 16191592Srgrimes DELAY(100); 16201592Srgrimes } 16211592Srgrimes if (cmd_timeout == 0) { 162290148Simp device_printf(aha->dev, "aha_cmd: Timeout: status = 0x%x, " 16231592Srgrimes "intstat = 0x%x, reply_len = %d\n", status, intstat, 16241592Srgrimes reply_len); 16251592Srgrimes return (ETIMEDOUT); 162690148Simp } 162736612Sjb 16281592Srgrimes /* 16291592Srgrimes * Clear any pending interrupts. Block interrupts so our 16301592Srgrimes * interrupt handler is not re-entered. 16311592Srgrimes */ 16321592Srgrimes s = splcam(); 16331592Srgrimes aha_intr(aha); 16341592Srgrimes splx(s); 163531973Simp 16361592Srgrimes if (error != 0) 16371592Srgrimes return (error); 16381592Srgrimes 16391592Srgrimes /* 16401592Srgrimes * If the command was rejected by the controller, tell the caller. 16411592Srgrimes */ 16421592Srgrimes if ((saved_status & CMD_INVALID) != 0) { 16431592Srgrimes PRVERB((aha->dev, "Invalid Command 0x%x\n", opcode)); 16441592Srgrimes /* 16451592Srgrimes * Some early adapters may not recover properly from 16461592Srgrimes * an invalid command. If it appears that the controller 16471592Srgrimes * has wedged (i.e. status was not cleared by our interrupt 16481592Srgrimes * reset above), perform a soft reset. 16491592Srgrimes */ 1650110144Syar DELAY(1000); 1651110144Syar status = aha_inb(aha, STATUS_REG); 1652110144Syar if ((status & (CMD_INVALID|STATUS_REG_RSVD|DATAIN_REG_READY| 1653110144Syar CMD_REG_BUSY|DIAG_FAIL|DIAG_ACTIVE)) != 0 1654110144Syar || (status & (HA_READY|INIT_REQUIRED)) 1655110144Syar != (HA_READY|INIT_REQUIRED)) 1656125565Syar ahareset(aha, /*hard_reset*/FALSE); 1657125565Syar return (EINVAL); 1658125565Syar } 1659125565Syar 1660125565Syar if (param_len > 0) { 1661125565Syar /* The controller did not accept the full argument list */ 1662125565Syar PRVERB((aha->dev, "Controller did not accept full argument " 1663125565Syar "list (%d > 0)\n", param_len)); 1664110144Syar return (E2BIG); 1665110144Syar } 1666110144Syar 1667110144Syar if (reply_len != reply_buf_size) { 1668110144Syar /* Too much or too little data received */ 1669110144Syar PRVERB((aha->dev, "data received mismatch (%d != %d)\n", 16701592Srgrimes reply_len, reply_buf_size)); 16711592Srgrimes return (EMSGSIZE); 16721592Srgrimes } 16731592Srgrimes 16741592Srgrimes /* We were successful */ 16751592Srgrimes return (0); 16761592Srgrimes} 16771592Srgrimes 16781592Srgrimesstatic int 16791592Srgrimesahainitmboxes(struct aha_softc *aha) 16801592Srgrimes{ 16811592Srgrimes int error; 16821592Srgrimes init_24b_mbox_params_t init_mbox; 16831592Srgrimes 16841592Srgrimes bzero(aha->in_boxes, sizeof(aha_mbox_in_t) * aha->num_boxes); 16851592Srgrimes bzero(aha->out_boxes, sizeof(aha_mbox_out_t) * aha->num_boxes); 16861592Srgrimes aha->cur_inbox = aha->in_boxes; 16871592Srgrimes aha->last_inbox = aha->in_boxes + aha->num_boxes - 1; 16881592Srgrimes aha->cur_outbox = aha->out_boxes; 16891592Srgrimes aha->last_outbox = aha->out_boxes + aha->num_boxes - 1; 16901592Srgrimes 16911592Srgrimes /* Tell the adapter about them */ 16921592Srgrimes init_mbox.num_mboxes = aha->num_boxes; 16931592Srgrimes ahautoa24(aha->mailbox_physbase, init_mbox.base_addr); 16946740Sguido error = aha_cmd(aha, AOP_INITIALIZE_MBOX, (uint8_t *)&init_mbox, 16958240Swollman /*parmlen*/sizeof(init_mbox), /*reply_buf*/NULL, 16968240Swollman /*reply_len*/0, DEFAULT_CMD_TIMEOUT); 16976740Sguido 169817433Spst if (error != 0) 16991592Srgrimes printf("ahainitmboxes: Initialization command failed\n"); 17001592Srgrimes return (error); 17011592Srgrimes} 17021592Srgrimes 17031592Srgrimes/* 17041592Srgrimes * Update the XPT's idea of the negotiated transfer 17051592Srgrimes * parameters for a particular target. 17061592Srgrimes */ 17071592Srgrimesstatic void 17081592Srgrimesahafetchtransinfo(struct aha_softc *aha, struct ccb_trans_settings* cts) 170990148Simp{ 17101592Srgrimes setup_data_t setup_info; 1711101537Syar u_int target; 17121592Srgrimes u_int targ_offset; 171390148Simp u_int sync_period; 17141592Srgrimes int error; 1715101537Syar uint8_t param; 1716101537Syar targ_syncinfo_t sync_info; 1717101537Syar#ifdef CAM_NEW_TRAN_CODE 1718101537Syar struct ccb_trans_settings_spi *spi = &cts->xport_specific.spi; 1719101537Syar#endif 1720101537Syar 1721101537Syar target = cts->ccb_h.target_id; 1722101537Syar targ_offset = (target & 0x7); 1723101537Syar 1724101537Syar /* 1725101537Syar * Inquire Setup Information. This command retreives 17261592Srgrimes * the sync info for older models. 1727101537Syar */ 1728101537Syar param = sizeof(setup_info); 1729101537Syar error = aha_cmd(aha, AOP_INQUIRE_SETUP_INFO, ¶m, /*paramlen*/1, 1730101537Syar (uint8_t*)&setup_info, sizeof(setup_info), DEFAULT_CMD_TIMEOUT); 1731101537Syar 1732101537Syar if (error != 0) { 1733101537Syar device_printf(aha->dev, 1734101537Syar "ahafetchtransinfo - Inquire Setup Info Failed %d\n", 1735101537Syar error); 17361592Srgrimes return; 17371592Srgrimes } 1738101537Syar 1739101537Syar sync_info = setup_info.syncinfo[targ_offset]; 1740101537Syar 1741101537Syar#ifdef CAM_NEW_TRAN_CODE 1742101537Syar if (sync_info.sync == 0) 1743101537Syar spi->sync_offset = 0; 1744101537Syar else 17451592Srgrimes spi->sync_offset = sync_info.offset; 17461592Srgrimes 17471592Srgrimes spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 1748101537Syar 17491592Srgrimes if (aha->boardid >= BOARD_1542CF) 17501592Srgrimes sync_period = 1000; 17511592Srgrimes else 17521592Srgrimes sync_period = 2000; 17531592Srgrimes sync_period += 500 * sync_info.period; 17541592Srgrimes 17551592Srgrimes /* Convert ns value to standard SCSI sync rate */ 17561592Srgrimes if (spi->sync_offset != 0) 17571592Srgrimes spi->sync_period = scsi_calc_syncparam(sync_period); 17581592Srgrimes else 17591592Srgrimes spi->sync_period = 0; 17601592Srgrimes 17611592Srgrimes spi->valid = CTS_SPI_VALID_SYNC_RATE 17621592Srgrimes | CTS_SPI_VALID_SYNC_OFFSET 17631592Srgrimes | CTS_SPI_VALID_BUS_WIDTH; 17641592Srgrimes#else 17651592Srgrimes if (sync_info.sync == 0) 17661592Srgrimes cts->sync_offset = 0; 17671592Srgrimes else 17681592Srgrimes cts->sync_offset = sync_info.offset; 17691592Srgrimes 17701592Srgrimes cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 177182792Sache 17721592Srgrimes if (aha->boardid >= BOARD_1542CF) 17731592Srgrimes sync_period = 1000; 17741592Srgrimes else 17751592Srgrimes sync_period = 2000; 17761592Srgrimes sync_period += 500 * sync_info.period; 17771592Srgrimes 17781592Srgrimes /* Convert ns value to standard SCSI sync rate */ 17791592Srgrimes if (cts->sync_offset != 0) 17801592Srgrimes cts->sync_period = scsi_calc_syncparam(sync_period); 17811592Srgrimes else 17821592Srgrimes cts->sync_period = 0; 17831592Srgrimes 17841592Srgrimes cts->valid = CCB_TRANS_SYNC_RATE_VALID 17851592Srgrimes | CCB_TRANS_SYNC_OFFSET_VALID 17861592Srgrimes | CCB_TRANS_BUS_WIDTH_VALID; 17871592Srgrimes#endif 17881592Srgrimes xpt_async(AC_TRANSFER_NEG, cts->ccb_h.path, cts); 17891592Srgrimes} 17901592Srgrimes 17911592Srgrimesstatic void 17921592Srgrimesahamapmboxes(void *arg, bus_dma_segment_t *segs, int nseg, int error) 17931592Srgrimes{ 1794102566Syar struct aha_softc* aha; 17951592Srgrimes 1796101537Syar aha = (struct aha_softc*)arg; 1797101537Syar aha->mailbox_physbase = segs->ds_addr; 1798101537Syar} 1799101537Syar 18001592Srgrimesstatic void 18011592Srgrimesahamapccbs(void *arg, bus_dma_segment_t *segs, int nseg, int error) 18021592Srgrimes{ 180390148Simp struct aha_softc* aha; 18041592Srgrimes 18051592Srgrimes aha = (struct aha_softc*)arg; 18061592Srgrimes aha->aha_ccb_physbase = segs->ds_addr; 18071592Srgrimes} 18081592Srgrimes 18091592Srgrimesstatic void 181056668Sshinahamapsgs(void *arg, bus_dma_segment_t *segs, int nseg, int error) 181156668Sshin{ 18121592Srgrimes 18131592Srgrimes struct aha_softc* aha; 1814100612Syar 1815100609Syar aha = (struct aha_softc*)arg; 18161592Srgrimes SLIST_FIRST(&aha->sg_maps)->sg_physaddr = segs->ds_addr; 181756668Sshin} 1818109742Syar 18191592Srgrimesstatic void 18201592Srgrimesahapoll(struct cam_sim *sim) 182156668Sshin{ 18221592Srgrimes aha_intr(cam_sim_softc(sim)); 18231592Srgrimes} 18241592Srgrimes 18251592Srgrimesstatic void 18261592Srgrimesahatimeout(void *arg) 18271592Srgrimes{ 18281592Srgrimes struct aha_ccb *accb; 182956668Sshin union ccb *ccb; 183056668Sshin struct aha_softc *aha; 18311592Srgrimes int s; 1832100612Syar uint32_t paddr; 1833100609Syar struct ccb_hdr *ccb_h; 183456668Sshin 18351592Srgrimes accb = (struct aha_ccb *)arg; 18368240Swollman ccb = accb->ccb; 18378240Swollman aha = (struct aha_softc *)ccb->ccb_h.ccb_aha_ptr; 18388240Swollman xpt_print_path(ccb->ccb_h.path); 18398240Swollman printf("CCB %p - timed out\n", (void *)accb); 18408240Swollman 18418240Swollman s = splcam(); 18428240Swollman 18438240Swollman if ((accb->flags & ACCB_ACTIVE) == 0) { 1844100612Syar xpt_print_path(ccb->ccb_h.path); 1845100609Syar printf("CCB %p - timed out CCB already completed\n", 18468240Swollman (void *)accb); 18478240Swollman splx(s); 18488240Swollman return; 1849100612Syar } 1850100609Syar 18518240Swollman /* 18528240Swollman * In order to simplify the recovery process, we ask the XPT 18531592Srgrimes * layer to halt the queue of new transactions and we traverse 18541592Srgrimes * the list of pending CCBs and remove their timeouts. This 18551592Srgrimes * means that the driver attempts to clear only one error 18561592Srgrimes * condition at a time. In general, timeouts that occur 18571592Srgrimes * close together are related anyway, so there is no benefit 18581592Srgrimes * in attempting to handle errors in parrallel. Timeouts will 18591592Srgrimes * be reinstated when the recovery process ends. 18601592Srgrimes */ 18611592Srgrimes if ((accb->flags & ACCB_DEVICE_RESET) == 0) { 18621592Srgrimes if ((accb->flags & ACCB_RELEASE_SIMQ) == 0) { 18631592Srgrimes xpt_freeze_simq(aha->sim, /*count*/1); 186490148Simp accb->flags |= ACCB_RELEASE_SIMQ; 18651592Srgrimes } 18661592Srgrimes 18671592Srgrimes ccb_h = LIST_FIRST(&aha->pending_ccbs); 1868109611Scjc while (ccb_h != NULL) { 18691592Srgrimes struct aha_ccb *pending_accb; 18701592Srgrimes 18711592Srgrimes pending_accb = (struct aha_ccb *)ccb_h->ccb_accb_ptr; 18721592Srgrimes untimeout(ahatimeout, pending_accb, ccb_h->timeout_ch); 187331973Simp ccb_h = LIST_NEXT(ccb_h, sim_links.le); 18741592Srgrimes } 187531973Simp } 18761592Srgrimes 187756668Sshin if ((accb->flags & ACCB_DEVICE_RESET) != 0 187886628Syar || aha->cur_outbox->action_code != AMBO_FREE) { 187956668Sshin /* 188012532Sguido * Try a full host adapter/SCSI bus reset. 188112532Sguido * We do this only if we have already attempted 18821592Srgrimes * to clear the condition with a BDR, or we cannot 188312532Sguido * attempt a BDR for lack of mailbox resources. 188412532Sguido */ 188512532Sguido ccb->ccb_h.status = CAM_CMD_TIMEOUT; 188612532Sguido ahareset(aha, /*hardreset*/TRUE); 188712532Sguido device_printf(aha->dev, "No longer in timeout\n"); 188812532Sguido } else { 188986628Syar /* 189086628Syar * Send a Bus Device Reset message: 189186628Syar * The target that is holding up the bus may not 189286628Syar * be the same as the one that triggered this timeout 189386628Syar * (different commands have different timeout lengths), 189486628Syar * but we have no way of determining this from our 189586628Syar * timeout handler. Our strategy here is to queue a 189686628Syar * BDR message to the target of the timed out command. 189786628Syar * If this fails, we'll get another timeout 2 seconds 189886628Syar * later which will attempt a bus reset. 189986628Syar */ 190086628Syar accb->flags |= ACCB_DEVICE_RESET; 19011592Srgrimes ccb->ccb_h.timeout_ch = timeout(ahatimeout, (caddr_t)accb, 2 * hz); 19021592Srgrimes aha->recovery_accb->hccb.opcode = INITIATOR_BUS_DEV_RESET; 190386628Syar 1904101809Syar /* No Data Transfer */ 1905101809Syar aha->recovery_accb->hccb.datain = TRUE; 190686628Syar aha->recovery_accb->hccb.dataout = TRUE; 190786628Syar aha->recovery_accb->hccb.ahastat = 0; 190886628Syar aha->recovery_accb->hccb.sdstat = 0; 190986628Syar aha->recovery_accb->hccb.target = ccb->ccb_h.target_id; 19101592Srgrimes 191156668Sshin /* Tell the adapter about this command */ 191256668Sshin paddr = ahaccbvtop(aha, aha->recovery_accb); 191317435Spst ahautoa24(paddr, aha->cur_outbox->ccb_addr); 1914100612Syar aha->cur_outbox->action_code = AMBO_START; 1915100609Syar aha_outb(aha, COMMAND_REG, AOP_START_MBOX); 191656668Sshin ahanextoutbox(aha); 19171592Srgrimes } 19181592Srgrimes 19191592Srgrimes splx(s); 19201592Srgrimes} 192186628Syar 192286628Syarint 192386628Syaraha_detach(struct aha_softc *aha) 192486628Syar{ 192586628Syar xpt_async(AC_LOST_DEVICE, aha->path, NULL); 19261592Srgrimes xpt_free_path(aha->path); 19271592Srgrimes xpt_bus_deregister(cam_sim_path(aha->sim)); 19281592Srgrimes cam_sim_free(aha->sim, /*free_devq*/TRUE); 19291592Srgrimes return (0); 19301592Srgrimes} 19311592Srgrimes