aha.c revision 39324
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 * <fill in list here> XXX 61592Srgrimes * 71592Srgrimes * Derived from bt.c written by: 81592Srgrimes * 91592Srgrimes * Copyright (c) 1998 Justin T. Gibbs. 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 * without modification, immediately at the beginning of the file. 181592Srgrimes * 2. The name of the author may not be used to endorse or promote products 191592Srgrimes * derived from this software without specific prior written permission. 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 FOR 251592Srgrimes * 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 * $Id: aha.c,v 1.1 1998/09/15 07:39:52 gibbs Exp $ 3417478Smarkm */ 351592Srgrimes 361592Srgrimes#include <sys/param.h> 371592Srgrimes#include <sys/systm.h> 381592Srgrimes#include <sys/malloc.h> 391592Srgrimes#include <sys/buf.h> 4017478Smarkm#include <sys/kernel.h> 411592Srgrimes#include <sys/sysctl.h> 4231329Scharnier 4317478Smarkm#include <machine/bus_pio.h> 441592Srgrimes#include <machine/bus.h> 4531329Scharnier#include <machine/clock.h> 4631329Scharnier 4750476Speter#include <cam/cam.h> 481592Srgrimes#include <cam/cam_ccb.h> 491592Srgrimes#include <cam/cam_sim.h> 501592Srgrimes#include <cam/cam_xpt_sim.h> 511592Srgrimes#include <cam/cam_debug.h> 521592Srgrimes 531592Srgrimes#include <cam/scsi/scsi_message.h> 541592Srgrimes 5566907Swollman#include <vm/vm.h> 561592Srgrimes#include <vm/pmap.h> 5766907Swollman 5866907Swollman#include <dev/aha/ahareg.h> 591592Srgrimes 601592Srgrimesstruct aha_softc *aha_softcs[NAHA]; 611592Srgrimes 621592Srgrimes#define MIN(a, b) ((a) < (b) ? (a) : (b)) 631592Srgrimes 648240Swollman/* MailBox Management functions */ 651592Srgrimesstatic __inline void ahanextinbox(struct aha_softc *aha); 661592Srgrimesstatic __inline void ahanextoutbox(struct aha_softc *aha); 671592Srgrimes 681592Srgrimesstatic __inline void 691592Srgrimesahanextinbox(struct aha_softc *aha) 701592Srgrimes{ 711592Srgrimes if (aha->cur_inbox == aha->last_inbox) 721592Srgrimes aha->cur_inbox = aha->in_boxes; 731592Srgrimes else 741592Srgrimes aha->cur_inbox++; 751592Srgrimes} 761592Srgrimes 771592Srgrimesstatic __inline void 781592Srgrimesahanextoutbox(struct aha_softc *aha) 791592Srgrimes{ 8025187Sdavidn if (aha->cur_outbox == aha->last_outbox) 8179469Smarkm aha->cur_outbox = aha->out_boxes; 8279469Smarkm else 8379469Smarkm aha->cur_outbox++; 841592Srgrimes} 851592Srgrimes 861592Srgrimes#define ahautoa24(u,s3) \ 871592Srgrimes (s3)[0] = ((u) >> 16) & 0xff; \ 881592Srgrimes (s3)[1] = ((u) >> 8) & 0xff; \ 891592Srgrimes (s3)[2] = (u) & 0xff; 901592Srgrimes 911592Srgrimes#define aha_a24tou(s3) \ 9213139Speter (((s3)[0] << 16) | ((s3)[1] << 8) | (s3)[2]) 9325101Sdavidn 9425101Sdavidn/* CCB Mangement functions */ 9525101Sdavidnstatic __inline u_int32_t ahaccbvtop(struct aha_softc *aha, 961592Srgrimes struct aha_ccb *bccb); 9774874Smarkmstatic __inline struct aha_ccb* ahaccbptov(struct aha_softc *aha, 9851433Smarkm u_int32_t ccb_addr); 9951433Smarkm 10051433Smarkmstatic __inline u_int32_t 1011592Srgrimesahaccbvtop(struct aha_softc *aha, struct aha_ccb *bccb) 1021592Srgrimes{ 1031592Srgrimes return (aha->aha_ccb_physbase 1041592Srgrimes + (u_int32_t)((caddr_t)bccb - (caddr_t)aha->aha_ccb_array)); 1051592Srgrimes} 1061592Srgrimesstatic __inline struct aha_ccb * 1071592Srgrimesahaccbptov(struct aha_softc *aha, u_int32_t ccb_addr) 1081592Srgrimes{ 1091592Srgrimes return (aha->aha_ccb_array + 11025165Sdavidn + ((struct aha_ccb*)ccb_addr-(struct aha_ccb*)aha->aha_ccb_physbase)); 11125165Sdavidn} 1121592Srgrimes 11356668Sshinstatic struct aha_ccb* ahagetccb(struct aha_softc *aha); 11456668Sshinstatic __inline void ahafreeccb(struct aha_softc *aha, struct aha_ccb *bccb); 11556668Sshinstatic void ahaallocccbs(struct aha_softc *aha); 11656668Sshinstatic bus_dmamap_callback_t ahaexecuteccb; 11756668Sshinstatic void ahadone(struct aha_softc *aha, struct aha_ccb *bccb, 1181592Srgrimes aha_mbi_comp_code_t comp_code); 1191592Srgrimes 1201592Srgrimes/* Host adapter command functions */ 12156668Sshinstatic int ahareset(struct aha_softc* aha, int hard_reset); 12256668Sshin 12356668Sshin/* Initialization functions */ 12456668Sshinstatic int ahainitmboxes(struct aha_softc *aha); 12556668Sshinstatic bus_dmamap_callback_t ahamapmboxes; 12656668Sshinstatic bus_dmamap_callback_t ahamapccbs; 1271592Srgrimesstatic bus_dmamap_callback_t ahamapsgs; 12815196Sdg 1291592Srgrimes/* Transfer Negotiation Functions */ 1301592Srgrimesstatic void ahafetchtransinfo(struct aha_softc *aha, 1311592Srgrimes struct ccb_trans_settings *cts); 1321592Srgrimes 13376096Smarkm/* CAM SIM entry points */ 1341592Srgrimes#define ccb_bccb_ptr spriv_ptr0 1351592Srgrimes#define ccb_aha_ptr spriv_ptr1 1361592Srgrimesstatic void ahaaction(struct cam_sim *sim, union ccb *ccb); 1379933Spststatic void ahapoll(struct cam_sim *sim); 13817435Spst 13920042Storstenb/* Our timeout handler */ 1401592Srgrimestimeout_t ahatimeout; 14117435Spst 1426740Sguidou_long aha_unit = 0; 1436740Sguido 1441592Srgrimes/* 1451592Srgrimes * Do our own re-probe protection until a configuration 1461592Srgrimes * manager can do it for us. This ensures that we don't 1471592Srgrimes * reprobe a card already found by the EISA or PCI probes. 1481592Srgrimes */ 1491592Srgrimesstruct aha_isa_port aha_isa_ports[] = 15070102Sphk{ 15170102Sphk { 0x330, 0 }, 15282460Snik { 0x334, 0 }, 15382796Ssheldonh { 0x230, 0 }, 15482460Snik { 0x234, 0 }, 1551592Srgrimes { 0x130, 0 }, 1561592Srgrimes { 0x134, 0 } 1571592Srgrimes}; 1581592Srgrimes 1591592Srgrimes/* Exported functions */ 1601592Srgrimesstruct aha_softc * 1611592Srgrimesaha_alloc(int unit, bus_space_tag_t tag, bus_space_handle_t bsh) 1621592Srgrimes{ 1631592Srgrimes struct aha_softc *aha; 16427650Sdavidn int i; 16578153Sdd 16678153Sdd if (unit != AHA_TEMP_UNIT) { 16725283Sdavidn if (unit >= NAHA) { 16825283Sdavidn printf("aha: unit number (%d) too high\n", unit); 16925283Sdavidn return NULL; 17025283Sdavidn } 17125283Sdavidn 17257124Sshin /* 17325283Sdavidn * Allocate a storage area for us 17425283Sdavidn */ 17525283Sdavidn if (aha_softcs[unit]) { 17625283Sdavidn printf("aha%d: memory already allocated\n", unit); 17725283Sdavidn return NULL; 17825283Sdavidn } 17925283Sdavidn } 18025283Sdavidn 18145422Sbrian aha = malloc(sizeof(struct aha_softc), M_DEVBUF, M_NOWAIT); 1826740Sguido if (!aha) { 18317435Spst printf("aha%d: cannot malloc!\n", unit); 18417435Spst return NULL; 18517435Spst } 18617435Spst bzero(aha, sizeof(struct aha_softc)); 18774874Smarkm SLIST_INIT(&aha->free_aha_ccbs); 18851433Smarkm LIST_INIT(&aha->pending_ccbs); 18974874Smarkm SLIST_INIT(&aha->sg_maps); 19079469Smarkm aha->unit = unit; 19179469Smarkm aha->tag = tag; 19279469Smarkm aha->bsh = bsh; 19379469Smarkm 19417478Smarkm if (aha->unit != AHA_TEMP_UNIT) { 19517478Smarkm aha_softcs[unit] = aha; 19617483Sjulian } 19717483Sjulian return (aha); 1981592Srgrimes} 19974470Sjlemon 20074470Sjlemonvoid 20174470Sjlemonaha_free(struct aha_softc *aha) 20274470Sjlemon{ 20374470Sjlemon switch (aha->init_level) { 20474470Sjlemon default: 20574470Sjlemon case 8: 2061592Srgrimes { 2071592Srgrimes struct sg_map_node *sg_map; 2081592Srgrimes 2091592Srgrimes while ((sg_map = SLIST_FIRST(&aha->sg_maps))!= NULL) { 2101592Srgrimes SLIST_REMOVE_HEAD(&aha->sg_maps, links); 2111592Srgrimes bus_dmamap_unload(aha->sg_dmat, 2121592Srgrimes sg_map->sg_dmamap); 2131592Srgrimes bus_dmamem_free(aha->sg_dmat, sg_map->sg_vaddr, 2141592Srgrimes sg_map->sg_dmamap); 2151592Srgrimes free(sg_map, M_DEVBUF); 2161592Srgrimes } 21713139Speter bus_dma_tag_destroy(aha->sg_dmat); 2181592Srgrimes } 2191592Srgrimes case 7: 22013139Speter bus_dmamap_unload(aha->ccb_dmat, aha->ccb_dmamap); 2211592Srgrimes case 6: 2221592Srgrimes bus_dmamap_destroy(aha->ccb_dmat, aha->ccb_dmamap); 2231592Srgrimes bus_dmamem_free(aha->ccb_dmat, aha->aha_ccb_array, 2241592Srgrimes aha->ccb_dmamap); 2251592Srgrimes case 5: 2261592Srgrimes bus_dma_tag_destroy(aha->ccb_dmat); 2271592Srgrimes case 4: 2281592Srgrimes bus_dmamap_unload(aha->mailbox_dmat, aha->mailbox_dmamap); 2291592Srgrimes case 3: 2301592Srgrimes bus_dmamem_free(aha->mailbox_dmat, aha->in_boxes, 2311592Srgrimes aha->mailbox_dmamap); 2321592Srgrimes bus_dmamap_destroy(aha->mailbox_dmat, aha->mailbox_dmamap); 2331592Srgrimes case 2: 2341592Srgrimes bus_dma_tag_destroy(aha->buffer_dmat); 2351592Srgrimes case 1: 2361592Srgrimes bus_dma_tag_destroy(aha->mailbox_dmat); 2371592Srgrimes case 0: 2381592Srgrimes } 2391592Srgrimes if (aha->unit != AHA_TEMP_UNIT) { 2401592Srgrimes aha_softcs[aha->unit] = NULL; 2411592Srgrimes } 2421592Srgrimes free(aha, M_DEVBUF); 24325283Sdavidn} 24425283Sdavidn 24556668Sshin/* 24625283Sdavidn * Probe the adapter and verify that the card is an Adaptec. 2471592Srgrimes */ 2481592Srgrimesint 24936349Ssteveaha_probe(struct aha_softc* aha) 2501592Srgrimes{ 25156668Sshin u_int status; 2521592Srgrimes u_int intstat; 2531592Srgrimes int error; 2541592Srgrimes u_int8_t param; 2551592Srgrimes esetup_info_data_t esetup_info; 2561592Srgrimes 2571592Srgrimes /* 2588240Swollman * See if the three I/O ports look reasonable. 2591592Srgrimes * Touch the minimal number of registers in the 2601592Srgrimes * failure case. 2611592Srgrimes */ 26215196Sdg status = aha_inb(aha, STATUS_REG); 26382792Sache if ((status == 0) 2641592Srgrimes || (status & (DIAG_ACTIVE|CMD_REG_BUSY| 2651592Srgrimes STATUS_REG_RSVD|CMD_INVALID)) != 0) { 2661592Srgrimes return (ENXIO); 2671592Srgrimes } 2681592Srgrimes 2691592Srgrimes intstat = aha_inb(aha, INTSTAT_REG); 2701592Srgrimes if ((intstat & INTSTAT_REG_RSVD) != 0) { 2711592Srgrimes printf("%s: Failed Intstat Reg Test\n", aha_name(aha)); 2721592Srgrimes return (ENXIO); 2731592Srgrimes } 2741592Srgrimes 2751592Srgrimes /* 2761592Srgrimes * Looking good so far. Final test is to reset the 2771592Srgrimes * adapter. 2781592Srgrimes */ 2791592Srgrimes if ((error = ahareset(aha, /*hard_reset*/TRUE)) != 0) { 2801592Srgrimes if (bootverbose) 2811592Srgrimes printf("%s: Failed Reset\n", aha_name(aha)); 2821592Srgrimes return (ENXIO); 2831592Srgrimes } 2841592Srgrimes 2851592Srgrimes /* 2861592Srgrimes * Issue a buslogic command that will fail, and reject the board 28756668Sshin * if it doesn't. 28856668Sshin */ 28956668Sshin param = sizeof(esetup_info); 29056668Sshin error = aha_cmd(aha, BOP_INQUIRE_ESETUP_INFO, ¶m, /*parmlen*/1, 2911592Srgrimes (u_int8_t*)&esetup_info, sizeof(esetup_info), 29236105Sache DEFAULT_CMD_TIMEOUT); 29336105Sache if (error == 0) 29413139Speter return ENXIO; 2951592Srgrimes 2961592Srgrimes return (0); 2971592Srgrimes} 2981592Srgrimes 2991592Srgrimes/* 3001592Srgrimes * Pull the boards setup information and record it in our softc. 3011592Srgrimes */ 30213139Speterint 3031592Srgrimesaha_fetch_adapter_info(struct aha_softc *aha) 3046740Sguido{ 30582796Ssheldonh board_id_data_t board_id; 3061592Srgrimes setup_data_t setup_info; 30715196Sdg config_data_t config_data; 30815196Sdg u_int8_t length_param; 30915196Sdg int error; 31015196Sdg 3111592Srgrimes /* First record the firmware version */ 31276096Smarkm error = aha_cmd(aha, BOP_INQUIRE_BOARD_ID, NULL, /*parmlen*/0, 3131592Srgrimes (u_int8_t*)&board_id, sizeof(board_id), 3141592Srgrimes DEFAULT_CMD_TIMEOUT); 31570102Sphk if (error != 0) { 31670102Sphk printf("%s: aha_fetch_adapter_info - Failed Get Board Info\n", 31770102Sphk aha_name(aha)); 31870102Sphk return (error); 3191592Srgrimes } 3201592Srgrimes aha->firmware_ver[0] = board_id.firmware_rev_major; 3211592Srgrimes aha->firmware_ver[1] = '.'; 3221592Srgrimes aha->firmware_ver[2] = board_id.firmware_rev_minor; 32370102Sphk aha->firmware_ver[3] = '\0'; 32470102Sphk 32570102Sphk aha->boardid = board_id.board_type; 32670102Sphk 32717435Spst switch (board_id.board_type) { 32817435Spst case BOARD_1540_16HEAD_BIOS: 3299933Spst strcpy(aha->model, "1540 16 head BIOS"); 3309933Spst break; 3316740Sguido case BOARD_1540_64HEAD_BIOS: 33217435Spst strcpy(aha->model, "1540 64 head BIOS"); 3336740Sguido break; 33417435Spst case BOARD_1542: 3351592Srgrimes strcpy(aha->model, "1540/1542 64 head BIOS"); 3361592Srgrimes break; 3371592Srgrimes case BOARD_1640: 3381592Srgrimes strcpy(aha->model, "1640"); 3391592Srgrimes break; 3401592Srgrimes case BOARD_1740: 34117435Spst strcpy(aha->model, "1740A/1742A/1744"); 34217435Spst break; 34317435Spst case BOARD_1542C: 34417435Spst strcpy(aha->model, "1542C"); 34517435Spst break; 34617435Spst case BOARD_1542CF: 34717435Spst strcpy(aha->model, "1542CF"); 34817435Spst break; 34917435Spst case BOARD_1542CP: 35017435Spst strcpy(aha->model, "1542CP"); 35117483Sjulian break; 35256668Sshin default: 35317483Sjulian strcpy(aha->model, "Unknown"); 35417483Sjulian break; 35517483Sjulian } 35617483Sjulian aha->max_sg = 16; 35717483Sjulian aha->diff_bus = 0; 35817483Sjulian aha->extended_lun = 0; 3591592Srgrimes aha->extended_trans = 0; /* XXX ???? XXX */ 3601592Srgrimes aha->max_ccbs = 16; /* XXX ???? XXX */ 3611592Srgrimes /* Determine Sync/Wide/Disc settings */ 3621592Srgrimes length_param = sizeof(setup_info); 3631592Srgrimes error = aha_cmd(aha, BOP_INQUIRE_SETUP_INFO, &length_param, 3641592Srgrimes /*paramlen*/1, (u_int8_t*)&setup_info, 3651592Srgrimes sizeof(setup_info), DEFAULT_CMD_TIMEOUT); 3661592Srgrimes if (error != 0) { 3671592Srgrimes printf("%s: aha_fetch_adapter_info - Failed " 3681592Srgrimes "Get Setup Info\n", aha_name(aha)); 3691592Srgrimes return (error); 37020042Storstenb } 37120042Storstenb if (setup_info.initiate_sync != 0) { 37220042Storstenb aha->sync_permitted = ALL_TARGETS; 3731592Srgrimes } 3741592Srgrimes aha->disc_permitted = ALL_TARGETS; 37576096Smarkm 3761592Srgrimes /* We need as many mailboxes as we can have ccbs */ 3771592Srgrimes aha->num_boxes = aha->max_ccbs; 37856668Sshin 37956668Sshin /* Determine our SCSI ID */ 38056668Sshin 38156668Sshin error = aha_cmd(aha, BOP_INQUIRE_CONFIG, NULL, /*parmlen*/0, 38256668Sshin (u_int8_t*)&config_data, sizeof(config_data), 38356668Sshin DEFAULT_CMD_TIMEOUT); 38456668Sshin if (error != 0) { 38556668Sshin printf("%s: aha_fetch_adapter_info - Failed Get Config\n", 38656668Sshin aha_name(aha)); 38756668Sshin return (error); 38882796Ssheldonh } 38982796Ssheldonh aha->scsi_id = config_data.scsi_id; 39082796Ssheldonh return (0); 39182796Ssheldonh} 39282460Snik 39382460Snik/* 39482460Snik * Start the board, ready for normal operation 39582460Snik */ 3961592Srgrimesint 3971592Srgrimesaha_init(struct aha_softc* aha) 3981592Srgrimes{ 3991592Srgrimes /* Announce the Adapter */ 4001592Srgrimes printf("%s: AHA-%s FW Rev. %s (ID=%x)", aha_name(aha), 40115196Sdg aha->model, aha->firmware_ver, aha->boardid); 40225283Sdavidn 40325283Sdavidn if (aha->diff_bus != 0) 40425283Sdavidn printf("Diff "); 4051592Srgrimes 40615196Sdg printf("SCSI Host Adapter, SCSI ID %d, %d CCBs\n", aha->scsi_id, 40715196Sdg aha->max_ccbs); 40815196Sdg 40915196Sdg /* 41015196Sdg * Create our DMA tags. These tags define the kinds of device 41115196Sdg * accessable memory allocations and memory mappings we will 41215196Sdg * need to perform during normal operation. 41315196Sdg * 41415196Sdg * Unless we need to further restrict the allocation, we rely 41556668Sshin * on the restrictions of the parent dmat, hence the common 41615196Sdg * use of MAXADDR and MAXSIZE. 41715196Sdg */ 41815196Sdg 41915196Sdg /* DMA tag for mapping buffers into device visible space. */ 42015196Sdg if (bus_dma_tag_create(aha->parent_dmat, /*alignment*/0, /*boundary*/0, 42115196Sdg /*lowaddr*/BUS_SPACE_MAXADDR, 42215196Sdg /*highaddr*/BUS_SPACE_MAXADDR, 42315196Sdg /*filter*/NULL, /*filterarg*/NULL, 42415196Sdg /*maxsize*/MAXBSIZE, /*nsegments*/AHA_NSEG, 42556668Sshin /*maxsegsz*/BUS_SPACE_MAXSIZE_24BIT, 42656668Sshin /*flags*/BUS_DMA_ALLOCNOW, 42756668Sshin &aha->buffer_dmat) != 0) { 42856668Sshin goto error_exit; 42956668Sshin } 43056668Sshin 43156668Sshin aha->init_level++; 43256668Sshin /* DMA tag for our mailboxes */ 43356668Sshin if (bus_dma_tag_create(aha->parent_dmat, /*alignment*/0, /*boundary*/0, 43456668Sshin /*lowaddr*/BUS_SPACE_MAXADDR, 43556668Sshin /*highaddr*/BUS_SPACE_MAXADDR, 43656668Sshin /*filter*/NULL, /*filterarg*/NULL, 43756668Sshin aha->num_boxes * (sizeof(aha_mbox_in_t) 43856668Sshin + sizeof(aha_mbox_out_t)), 43956668Sshin /*nsegments*/1, 44056668Sshin /*maxsegsz*/BUS_SPACE_MAXSIZE_24BIT, 44168901Skris /*flags*/0, &aha->mailbox_dmat) != 0) { 44256668Sshin goto error_exit; 44368901Skris } 44415196Sdg 44515196Sdg aha->init_level++; 44656668Sshin 44756668Sshin /* Allocation for our mailboxes */ 44856668Sshin if (bus_dmamem_alloc(aha->mailbox_dmat, (void **)&aha->out_boxes, 44964699Sru BUS_DMA_NOWAIT, &aha->mailbox_dmamap) != 0) { 45064699Sru goto error_exit; 45115196Sdg } 45215196Sdg 45315196Sdg aha->init_level++; 45415196Sdg 45556668Sshin /* And permanently map them */ 45615196Sdg bus_dmamap_load(aha->mailbox_dmat, aha->mailbox_dmamap, 45715196Sdg aha->out_boxes, 45815196Sdg aha->num_boxes * (sizeof(aha_mbox_in_t) 45915196Sdg + sizeof(aha_mbox_out_t)), 46015196Sdg ahamapmboxes, aha, /*flags*/0); 46115196Sdg 46256668Sshin aha->init_level++; 46356668Sshin 46456668Sshin aha->in_boxes = (aha_mbox_in_t *)&aha->out_boxes[aha->num_boxes]; 46556668Sshin 46656668Sshin ahainitmboxes(aha); 46756668Sshin 46856668Sshin /* DMA tag for our ccb structures */ 46956668Sshin if (bus_dma_tag_create(aha->parent_dmat, /*alignment*/0, /*boundary*/0, 47056668Sshin /*lowaddr*/BUS_SPACE_MAXADDR, 47156668Sshin /*highaddr*/BUS_SPACE_MAXADDR, 47256668Sshin /*filter*/NULL, /*filterarg*/NULL, 47356668Sshin aha->max_ccbs * sizeof(struct aha_ccb), 47415196Sdg /*nsegments*/1, 47515196Sdg /*maxsegsz*/BUS_SPACE_MAXSIZE_24BIT, 47615196Sdg /*flags*/0, &aha->ccb_dmat) != 0) { 47715196Sdg goto error_exit; 47815196Sdg } 47915196Sdg 48015196Sdg aha->init_level++; 48115196Sdg 48217483Sjulian /* Allocation for our ccbs */ 48317483Sjulian if (bus_dmamem_alloc(aha->ccb_dmat, (void **)&aha->aha_ccb_array, 48417483Sjulian BUS_DMA_NOWAIT, &aha->ccb_dmamap) != 0) { 48517483Sjulian goto error_exit; 48617483Sjulian } 48717483Sjulian 48817483Sjulian aha->init_level++; 48917483Sjulian 49017483Sjulian /* And permanently map them */ 49146078Simp bus_dmamap_load(aha->ccb_dmat, aha->ccb_dmamap, 49217483Sjulian aha->aha_ccb_array, 49317483Sjulian aha->max_ccbs * sizeof(struct aha_ccb), 49417483Sjulian ahamapccbs, aha, /*flags*/0); 49517483Sjulian 49646078Simp aha->init_level++; 49717483Sjulian 49817483Sjulian /* DMA tag for our S/G structures. We allocate in page sized chunks */ 49917483Sjulian if (bus_dma_tag_create(aha->parent_dmat, /*alignment*/0, /*boundary*/0, 50017483Sjulian /*lowaddr*/BUS_SPACE_MAXADDR, 50117483Sjulian /*highaddr*/BUS_SPACE_MAXADDR, 50217483Sjulian /*filter*/NULL, /*filterarg*/NULL, 50317483Sjulian PAGE_SIZE, /*nsegments*/1, 50415196Sdg /*maxsegsz*/BUS_SPACE_MAXSIZE_24BIT, 50515196Sdg /*flags*/0, &aha->sg_dmat) != 0) { 50615196Sdg goto error_exit; 50715196Sdg } 50856668Sshin 50915196Sdg aha->init_level++; 51015196Sdg 51115196Sdg /* Perform initial CCB allocation */ 51215196Sdg bzero(aha->aha_ccb_array, aha->max_ccbs * sizeof(struct aha_ccb)); 51315196Sdg ahaallocccbs(aha); 51415196Sdg 51515196Sdg if (aha->num_ccbs == 0) { 51615196Sdg printf("%s: aha_init - Unable to allocate initial ccbs\n", 51715196Sdg aha_name(aha)); 51815196Sdg goto error_exit; 51915196Sdg } 52015196Sdg 52115196Sdg /* 52215196Sdg * Note that we are going and return (to probe) 52315196Sdg */ 52415196Sdg return 0; 52515196Sdg 52615196Sdgerror_exit: 52715196Sdg 5281592Srgrimes return (ENXIO); 52936612Sjb} 5301592Srgrimes 5311592Srgrimesint 53215196Sdgaha_attach(struct aha_softc *aha) 53315196Sdg{ 53415196Sdg int tagged_dev_openings; 53515196Sdg struct cam_devq *devq; 53615196Sdg 53725283Sdavidn /* 53825283Sdavidn * We reserve 1 ccb for error recovery, so don't 53956668Sshin * tell the XPT about it. 54025283Sdavidn */ 54115196Sdg tagged_dev_openings = 0; 54256668Sshin 54356668Sshin /* 54415196Sdg * Create the device queue for our SIM. 54515196Sdg */ 54615196Sdg devq = cam_simq_alloc(aha->max_ccbs - 1); 54756668Sshin if (devq == NULL) 54815196Sdg return (ENOMEM); 54935482Sdg 55035482Sdg /* 55135482Sdg * Construct our SIM entry 55235482Sdg */ 55335482Sdg aha->sim = cam_sim_alloc(ahaaction, ahapoll, "aha", aha, aha->unit, 55435482Sdg 2, tagged_dev_openings, devq); 55535482Sdg if (aha->sim == NULL) { 55656668Sshin cam_simq_free(devq); 55715196Sdg return (ENOMEM); 55817435Spst } 55931973Simp 56017435Spst if (xpt_bus_register(aha->sim, 0) != CAM_SUCCESS) { 5611592Srgrimes cam_sim_free(aha->sim, /*free_devq*/TRUE); 5621592Srgrimes return (ENXIO); 5631592Srgrimes } 5641592Srgrimes 5651592Srgrimes if (xpt_create_path(&aha->path, /*periph*/NULL, 5661592Srgrimes cam_sim_path(aha->sim), CAM_TARGET_WILDCARD, 5671592Srgrimes CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 5681592Srgrimes xpt_bus_deregister(cam_sim_path(aha->sim)); 5691592Srgrimes cam_sim_free(aha->sim, /*free_devq*/TRUE); 5701592Srgrimes return (ENXIO); 57156668Sshin } 5721592Srgrimes 5731592Srgrimes return (0); 5741592Srgrimes} 5751592Srgrimes 5761592Srgrimeschar * 5771592Srgrimesaha_name(struct aha_softc *aha) 5781592Srgrimes{ 5791592Srgrimes static char name[10]; 5801592Srgrimes 5811592Srgrimes sprintf(name, "aha%d", aha->unit); 5821592Srgrimes return (name); 5831592Srgrimes} 5841592Srgrimes 5851592Srgrimesint 5861592Srgrimesaha_check_probed_iop(u_int ioport) 5871592Srgrimes{ 5881592Srgrimes u_int i; 5891592Srgrimes 5901592Srgrimes for (i=0; i < AHA_NUM_ISAPORTS; i++) { 5911592Srgrimes if (aha_isa_ports[i].addr == ioport) { 5921592Srgrimes if (aha_isa_ports[i].probed != 0) 5931592Srgrimes return (1); 59425283Sdavidn else { 59525283Sdavidn return (0); 59625283Sdavidn } 5971592Srgrimes } 59825283Sdavidn } 5991592Srgrimes return (1); 6001592Srgrimes} 6011592Srgrimes 6021592Srgrimesvoid 6031592Srgrimesaha_mark_probed_bio(isa_compat_io_t port) 6041592Srgrimes{ 6051592Srgrimes if (port < BIO_DISABLED) 6061592Srgrimes aha_isa_ports[port].probed = 1; 6071592Srgrimes} 60825283Sdavidn 60927650Sdavidnvoid 61076096Smarkmaha_mark_probed_iop(u_int ioport) 61145422Sbrian{ 61245422Sbrian u_int i; 61325283Sdavidn 6141592Srgrimes for (i = 0; i < AHA_NUM_ISAPORTS; i++) { 6151592Srgrimes if (ioport == aha_isa_ports[i].addr) { 6161592Srgrimes aha_isa_ports[i].probed = 1; 6171592Srgrimes break; 6181592Srgrimes } 6191592Srgrimes } 6201592Srgrimes} 6211592Srgrimes 6221592Srgrimesstatic void 6231592Srgrimesahaallocccbs(struct aha_softc *aha) 6241592Srgrimes{ 6251592Srgrimes struct aha_ccb *next_ccb; 62676096Smarkm struct sg_map_node *sg_map; 6271592Srgrimes bus_addr_t physaddr; 62831329Scharnier aha_sg_t *segs; 6291592Srgrimes int newcount; 6301592Srgrimes int i; 63125283Sdavidn 6321592Srgrimes next_ccb = &aha->aha_ccb_array[aha->num_ccbs]; 63325283Sdavidn 63425283Sdavidn sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT); 63525283Sdavidn 63625283Sdavidn if (sg_map == NULL) 63725283Sdavidn return; 63825283Sdavidn 63925283Sdavidn /* Allocate S/G space for the next batch of CCBS */ 64025283Sdavidn if (bus_dmamem_alloc(aha->sg_dmat, (void **)&sg_map->sg_vaddr, 64125283Sdavidn BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) { 64225283Sdavidn free(sg_map, M_DEVBUF); 64356668Sshin return; 64425283Sdavidn } 64525283Sdavidn 64625283Sdavidn SLIST_INSERT_HEAD(&aha->sg_maps, sg_map, links); 64725283Sdavidn 64825283Sdavidn bus_dmamap_load(aha->sg_dmat, sg_map->sg_dmamap, sg_map->sg_vaddr, 64925283Sdavidn PAGE_SIZE, ahamapsgs, aha, /*flags*/0); 65025283Sdavidn 65125283Sdavidn segs = sg_map->sg_vaddr; 65276096Smarkm physaddr = sg_map->sg_physaddr; 65357124Sshin 65456668Sshin newcount = (PAGE_SIZE / (AHA_NSEG * sizeof(aha_sg_t))); 65556668Sshin for (i = 0; aha->num_ccbs < aha->max_ccbs && i < newcount; i++) { 65656668Sshin int error; 65756668Sshin 65856668Sshin next_ccb->sg_list = segs; 65956668Sshin next_ccb->sg_list_phys = physaddr; 66057124Sshin next_ccb->flags = BCCB_FREE; 66125283Sdavidn error = bus_dmamap_create(aha->buffer_dmat, /*flags*/0, 66225283Sdavidn &next_ccb->dmamap); 66325283Sdavidn if (error != 0) 66425283Sdavidn break; 66525283Sdavidn SLIST_INSERT_HEAD(&aha->free_aha_ccbs, next_ccb, links); 66625283Sdavidn segs += AHA_NSEG; 66725283Sdavidn physaddr += (AHA_NSEG * sizeof(aha_sg_t)); 66862100Sdavidn next_ccb++; 66956668Sshin aha->num_ccbs++; 67056668Sshin } 67156668Sshin 67225283Sdavidn /* Reserve a CCB for error recovery */ 67356668Sshin if (aha->recovery_bccb == NULL) { 67425283Sdavidn aha->recovery_bccb = SLIST_FIRST(&aha->free_aha_ccbs); 67525283Sdavidn SLIST_REMOVE_HEAD(&aha->free_aha_ccbs, links); 67625283Sdavidn } 67725283Sdavidn} 67825283Sdavidn 67925283Sdavidnstatic __inline void 68025283Sdavidnahafreeccb(struct aha_softc *aha, struct aha_ccb *bccb) 68125283Sdavidn{ 68225283Sdavidn int s; 68325283Sdavidn 68425283Sdavidn s = splcam(); 68525283Sdavidn if ((bccb->flags & BCCB_ACTIVE) != 0) 68625283Sdavidn LIST_REMOVE(&bccb->ccb->ccb_h, sim_links.le); 68756668Sshin if (aha->resource_shortage != 0 68856668Sshin && (bccb->ccb->ccb_h.status & CAM_RELEASE_SIMQ) == 0) { 68956668Sshin bccb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 69056668Sshin aha->resource_shortage = FALSE; 69156668Sshin } 69256668Sshin bccb->flags = BCCB_FREE; 69325283Sdavidn SLIST_INSERT_HEAD(&aha->free_aha_ccbs, bccb, links); 69456668Sshin splx(s); 69562100Sdavidn} 69656668Sshin 69762100Sdavidnstatic struct aha_ccb* 69825283Sdavidnahagetccb(struct aha_softc *aha) 69957124Sshin{ 70057124Sshin struct aha_ccb* bccb; 70157124Sshin int s; 70257124Sshin 70357124Sshin s = splcam(); 70457124Sshin if ((bccb = SLIST_FIRST(&aha->free_aha_ccbs)) != NULL) { 70557124Sshin SLIST_REMOVE_HEAD(&aha->free_aha_ccbs, links); 70662100Sdavidn } else if (aha->num_ccbs < aha->max_ccbs) { 70762100Sdavidn ahaallocccbs(aha); 70857124Sshin bccb = SLIST_FIRST(&aha->free_aha_ccbs); 70962100Sdavidn if (bccb == NULL) 71062100Sdavidn printf("%s: Can't malloc BCCB\n", aha_name(aha)); 71162100Sdavidn else 71225283Sdavidn SLIST_REMOVE_HEAD(&aha->free_aha_ccbs, links); 71325283Sdavidn } 71425283Sdavidn splx(s); 71525283Sdavidn 71625283Sdavidn return (bccb); 71725283Sdavidn} 71825283Sdavidn 71925283Sdavidnstatic void 72025283Sdavidnahaaction(struct cam_sim *sim, union ccb *ccb) 72125283Sdavidn{ 72225283Sdavidn struct aha_softc *aha; 72325283Sdavidn int s; 72425283Sdavidn 72557124Sshin CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("ahaaction\n")); 72657124Sshin 72725283Sdavidn aha = (struct aha_softc *)cam_sim_softc(sim); 72825283Sdavidn 72956668Sshin switch (ccb->ccb_h.func_code) { 73025283Sdavidn /* Common cases first */ 73125283Sdavidn case XPT_SCSI_IO: /* Execute the requested I/O operation */ 73256668Sshin case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ 73357124Sshin { 73456668Sshin struct aha_ccb *bccb; 73557124Sshin struct aha_hccb *hccb; 73656668Sshin 73756668Sshin /* 73856668Sshin * get a bccb to use. 73957124Sshin */ 74056668Sshin if ((bccb = ahagetccb(aha)) == NULL) { 74156668Sshin int s; 74256668Sshin 74356668Sshin s = splcam(); 74457124Sshin aha->resource_shortage = TRUE; 74557124Sshin splx(s); 74656668Sshin xpt_freeze_simq(aha->sim, /*count*/1); 74756668Sshin ccb->ccb_h.status = CAM_REQUEUE_REQ; 74856668Sshin xpt_done(ccb); 74956668Sshin return; 75056668Sshin } 75157124Sshin 75256668Sshin hccb = &bccb->hccb; 75325283Sdavidn 75425283Sdavidn /* 75525283Sdavidn * So we can find the BCCB when an abort is requested 75625283Sdavidn */ 75725283Sdavidn bccb->ccb = ccb; 75825283Sdavidn ccb->ccb_h.ccb_bccb_ptr = bccb; 75925283Sdavidn ccb->ccb_h.ccb_aha_ptr = aha; 76025283Sdavidn 76125283Sdavidn /* 76225283Sdavidn * Put all the arguments for the xfer in the bccb 76325283Sdavidn */ 76425283Sdavidn hccb->target = ccb->ccb_h.target_id; 76525283Sdavidn hccb->lun = ccb->ccb_h.target_lun; 76625283Sdavidn hccb->ahastat = 0; 76756668Sshin hccb->sdstat = 0; 76825283Sdavidn 76925283Sdavidn if (ccb->ccb_h.func_code == XPT_SCSI_IO) { 77025283Sdavidn struct ccb_scsiio *csio; 77125283Sdavidn struct ccb_hdr *ccbh; 77225283Sdavidn 77325283Sdavidn csio = &ccb->csio; 77425283Sdavidn ccbh = &csio->ccb_h; 77525283Sdavidn hccb->opcode = INITIATOR_CCB_WRESID; 77625283Sdavidn hccb->datain = (ccb->ccb_h.flags & CAM_DIR_IN) != 0; 77725283Sdavidn hccb->dataout = (ccb->ccb_h.flags & CAM_DIR_OUT) != 0; 77825283Sdavidn hccb->cmd_len = csio->cdb_len; 77925283Sdavidn if (hccb->cmd_len > sizeof(hccb->scsi_cdb)) { 78025283Sdavidn ccb->ccb_h.status = CAM_REQ_INVALID; 78125283Sdavidn ahafreeccb(aha, bccb); 78225283Sdavidn xpt_done(ccb); 78325283Sdavidn return; 78425283Sdavidn } 78525283Sdavidn hccb->sense_len = csio->sense_len; 78625283Sdavidn if ((ccbh->flags & CAM_CDB_POINTER) != 0) { 78725283Sdavidn if ((ccbh->flags & CAM_CDB_PHYS) == 0) { 78825283Sdavidn bcopy(csio->cdb_io.cdb_ptr, 78956668Sshin hccb->scsi_cdb, hccb->cmd_len); 79056668Sshin } else { 79156668Sshin /* I guess I could map it in... */ 79225283Sdavidn ccbh->status = CAM_REQ_INVALID; 79325283Sdavidn ahafreeccb(aha, bccb); 79425283Sdavidn xpt_done(ccb); 79525283Sdavidn return; 79625283Sdavidn } 79725283Sdavidn } else { 79856668Sshin bcopy(csio->cdb_io.cdb_bytes, 79956668Sshin hccb->scsi_cdb, hccb->cmd_len); 80025283Sdavidn } 80125283Sdavidn /* 80256668Sshin * If we have any data to send with this command, 80356668Sshin * map it into bus space. 80456668Sshin */ 80556668Sshin /* Only use S/G if there is a transfer */ 80657124Sshin if ((ccbh->flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 80725283Sdavidn if ((ccbh->flags & CAM_SCATTER_VALID) == 0) { 80856668Sshin /* 80956668Sshin * We've been given a pointer 81056668Sshin * to a single buffer. 81156668Sshin */ 81256668Sshin if ((ccbh->flags & CAM_DATA_PHYS)==0) { 81356668Sshin int s; 81456668Sshin int error; 81556668Sshin 81656668Sshin s = splsoftvm(); 81756668Sshin error = bus_dmamap_load( 81825283Sdavidn aha->buffer_dmat, 81956668Sshin bccb->dmamap, 82056668Sshin csio->data_ptr, 82125283Sdavidn csio->dxfer_len, 82262100Sdavidn ahaexecuteccb, 82357124Sshin bccb, 82425283Sdavidn /*flags*/0); 82525283Sdavidn if (error == EINPROGRESS) { 82625283Sdavidn /* 82756668Sshin * So as to maintain 82856668Sshin * ordering, freeze the 82957124Sshin * controller queue 83056668Sshin * until our mapping is 83157124Sshin * returned. 83256668Sshin */ 83356668Sshin xpt_freeze_simq(aha->sim, 83456668Sshin 1); 83556668Sshin csio->ccb_h.status |= 83656668Sshin CAM_RELEASE_SIMQ; 83762100Sdavidn } 83862100Sdavidn splx(s); 83925283Sdavidn } else { 84056668Sshin struct bus_dma_segment seg; 84125283Sdavidn 84225283Sdavidn /* Pointer to physical buffer */ 84325283Sdavidn seg.ds_addr = 84425283Sdavidn (bus_addr_t)csio->data_ptr; 84525283Sdavidn seg.ds_len = csio->dxfer_len; 84625283Sdavidn ahaexecuteccb(bccb, &seg, 1, 0); 84725283Sdavidn } 8481592Srgrimes } else { 8491592Srgrimes struct bus_dma_segment *segs; 8501592Srgrimes 8511592Srgrimes if ((ccbh->flags & CAM_DATA_PHYS) != 0) 8521592Srgrimes panic("ahaaction - Physical " 8531592Srgrimes "segment pointers " 8541592Srgrimes "unsupported"); 8551592Srgrimes 8561592Srgrimes if ((ccbh->flags&CAM_SG_LIST_PHYS)==0) 8571592Srgrimes panic("ahaaction - Virtual " 8581592Srgrimes "segment addresses " 8591592Srgrimes "unsupported"); 8601592Srgrimes 8611592Srgrimes /* Just use the segments provided */ 8621592Srgrimes segs = (struct bus_dma_segment *) 8631592Srgrimes csio->data_ptr; 8641592Srgrimes ahaexecuteccb(bccb, segs, 8651592Srgrimes csio->sglist_cnt, 0); 8661592Srgrimes } 8671592Srgrimes } else { 8681592Srgrimes ahaexecuteccb(bccb, NULL, 0, 0); 8691592Srgrimes } 8701592Srgrimes } else { 8711592Srgrimes hccb->opcode = INITIATOR_BUS_DEV_RESET; 8721592Srgrimes /* No data transfer */ 8731592Srgrimes hccb->datain = TRUE; 8741592Srgrimes hccb->dataout = TRUE; 8751592Srgrimes hccb->cmd_len = 0; 8761592Srgrimes hccb->sense_len = 0; 8771592Srgrimes ahaexecuteccb(bccb, NULL, 0, 0); 8781592Srgrimes } 8791592Srgrimes break; 8801592Srgrimes } 8811592Srgrimes case XPT_EN_LUN: /* Enable LUN as a target */ 8821592Srgrimes case XPT_TARGET_IO: /* Execute target I/O request */ 8831592Srgrimes case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */ 8841592Srgrimes case XPT_CONT_TARGET_IO: /* Continue Host Target I/O Connection*/ 8851592Srgrimes case XPT_ABORT: /* Abort the specified CCB */ 8861592Srgrimes /* XXX Implement */ 8871592Srgrimes ccb->ccb_h.status = CAM_REQ_INVALID; 8881592Srgrimes xpt_done(ccb); 8891592Srgrimes break; 8901592Srgrimes case XPT_SET_TRAN_SETTINGS: 8911592Srgrimes { 8921592Srgrimes /* XXX Implement */ 8931592Srgrimes ccb->ccb_h.status = CAM_REQ_CMP; 8941592Srgrimes xpt_done(ccb); 8951592Srgrimes break; 8961592Srgrimes } 89764778Ssheldonh case XPT_GET_TRAN_SETTINGS: 8981592Srgrimes /* Get default/user set transfer settings for the target */ 8991592Srgrimes { 9001592Srgrimes struct ccb_trans_settings *cts; 9011592Srgrimes u_int target_mask; 9021592Srgrimes 9031592Srgrimes cts = &ccb->cts; 9041592Srgrimes target_mask = 0x01 << ccb->ccb_h.target_id; 9051592Srgrimes if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) { 9061592Srgrimes cts->flags = 0; 9071592Srgrimes if ((aha->disc_permitted & target_mask) != 0) 9081592Srgrimes cts->flags |= CCB_TRANS_DISC_ENB; 9091592Srgrimes cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 9101592Srgrimes if ((aha->sync_permitted & target_mask) != 0) 9111592Srgrimes cts->sync_period = 50; 9121592Srgrimes else 9131592Srgrimes cts->sync_period = 0; 9141592Srgrimes 9151592Srgrimes if (cts->sync_period != 0) 9161592Srgrimes cts->sync_offset = 15; 9171592Srgrimes 9181592Srgrimes cts->valid = CCB_TRANS_SYNC_RATE_VALID 9191592Srgrimes | CCB_TRANS_SYNC_OFFSET_VALID 92017435Spst | CCB_TRANS_BUS_WIDTH_VALID 92117435Spst | CCB_TRANS_DISC_VALID 92217435Spst | CCB_TRANS_TQ_VALID; 9231592Srgrimes } else { 9241592Srgrimes ahafetchtransinfo(aha, cts); 9251592Srgrimes } 9261592Srgrimes 9271592Srgrimes ccb->ccb_h.status = CAM_REQ_CMP; 9281592Srgrimes xpt_done(ccb); 92936349Ssteve break; 93036349Ssteve } 9311592Srgrimes case XPT_CALC_GEOMETRY: 93225283Sdavidn { 93325283Sdavidn struct ccb_calc_geometry *ccg; 93425283Sdavidn u_int32_t size_mb; 9351592Srgrimes u_int32_t secs_per_cylinder; 93625283Sdavidn 9371592Srgrimes ccg = &ccb->ccg; 9381592Srgrimes size_mb = ccg->volume_size 9391592Srgrimes / ((1024L * 1024L) / ccg->block_size); 9403938Spst 9411592Srgrimes if (size_mb >= 1024 && (aha->extended_trans != 0)) { 9421592Srgrimes if (size_mb >= 2048) { 9431592Srgrimes ccg->heads = 255; 9441592Srgrimes ccg->secs_per_track = 63; 9451592Srgrimes } else { 9461592Srgrimes ccg->heads = 128; 9471592Srgrimes ccg->secs_per_track = 32; 94820042Storstenb } 94920042Storstenb } else { 95020042Storstenb ccg->heads = 64; 95120042Storstenb ccg->secs_per_track = 32; 95220042Storstenb } 95317478Smarkm secs_per_cylinder = ccg->heads * ccg->secs_per_track; 9541592Srgrimes ccg->cylinders = ccg->volume_size / secs_per_cylinder; 9551592Srgrimes ccb->ccb_h.status = CAM_REQ_CMP; 9561592Srgrimes xpt_done(ccb); 9571592Srgrimes break; 9581592Srgrimes } 9591592Srgrimes case XPT_RESET_BUS: /* Reset the specified SCSI bus */ 9601592Srgrimes { 96136349Ssteve ahareset(aha, /*hardreset*/TRUE); 9621592Srgrimes ccb->ccb_h.status = CAM_REQ_CMP; 9631592Srgrimes xpt_done(ccb); 9641592Srgrimes break; 9651592Srgrimes } 9661592Srgrimes case XPT_TERM_IO: /* Terminate the I/O process */ 9671592Srgrimes /* XXX Implement */ 9681592Srgrimes ccb->ccb_h.status = CAM_REQ_INVALID; 9691592Srgrimes xpt_done(ccb); 9701592Srgrimes break; 9711592Srgrimes case XPT_PATH_INQ: /* Path routing inquiry */ 9721592Srgrimes { 97379469Smarkm struct ccb_pathinq *cpi = &ccb->cpi; 97479469Smarkm 97584146Sache cpi->version_num = 1; /* XXX??? */ 97684146Sache cpi->hba_inquiry = PI_SDTR_ABLE; 97784146Sache cpi->target_sprt = 0; 97884146Sache cpi->hba_misc = 0; 97984146Sache cpi->hba_eng_cnt = 0; 9802193Sguido cpi->max_target = aha->wide_bus ? 15 : 7; 9811592Srgrimes cpi->max_lun = 7; 9822193Sguido cpi->initiator_id = aha->scsi_id; 9831592Srgrimes cpi->bus_id = cam_sim_bus(sim); 9841592Srgrimes strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 9851592Srgrimes strncpy(cpi->hba_vid, "Adaptec", HBA_IDLEN); 9861592Srgrimes strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 9871592Srgrimes cpi->unit_number = cam_sim_unit(sim); 9881592Srgrimes cpi->ccb_h.status = CAM_REQ_CMP; 9891592Srgrimes xpt_done(ccb); 9901592Srgrimes break; 9911592Srgrimes } 9921592Srgrimes default: 99317435Spst ccb->ccb_h.status = CAM_REQ_INVALID; 9941592Srgrimes xpt_done(ccb); 9951592Srgrimes break; 99636349Ssteve } 99717435Spst} 9981592Srgrimes 99936349Sstevestatic void 10001592Srgrimesahaexecuteccb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 10011592Srgrimes{ 10021592Srgrimes struct aha_ccb *bccb; 10031592Srgrimes union ccb *ccb; 10041592Srgrimes struct aha_softc *aha; 100517435Spst int s, i; 100625187Sdavidn u_int32_t paddr; 10071592Srgrimes 10081592Srgrimes bccb = (struct aha_ccb *)arg; 10091592Srgrimes ccb = bccb->ccb; 10101592Srgrimes aha = (struct aha_softc *)ccb->ccb_h.ccb_aha_ptr; 101125187Sdavidn 101225187Sdavidn if (error != 0) { 101325187Sdavidn if (error != EFBIG) 101425187Sdavidn printf("%s: Unexepected error 0x%x returned from " 101525187Sdavidn "bus_dmamap_load\n", aha_name(aha), error); 101625187Sdavidn if (ccb->ccb_h.status == CAM_REQ_INPROG) { 101725187Sdavidn xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 101825187Sdavidn ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN; 101925187Sdavidn } 102036349Ssteve ahafreeccb(aha, bccb); 102136349Ssteve xpt_done(ccb); 102236349Ssteve return; 102336349Ssteve } 102436349Ssteve 102536349Ssteve if (nseg != 0) { 102636349Ssteve aha_sg_t *sg; 102736349Ssteve bus_dma_segment_t *end_seg; 102825187Sdavidn bus_dmasync_op_t op; 102925187Sdavidn 103025187Sdavidn end_seg = dm_segs + nseg; 103125187Sdavidn 10321592Srgrimes /* Copy the segments into our SG list */ 103325187Sdavidn sg = bccb->sg_list; 103425187Sdavidn while (dm_segs < end_seg) { 103525187Sdavidn ahautoa24(dm_segs->ds_len, sg->len); 103625187Sdavidn ahautoa24(dm_segs->ds_addr, sg->addr); 103725187Sdavidn sg++; 10381592Srgrimes dm_segs++; 10391592Srgrimes } 10401592Srgrimes 10411592Srgrimes if (nseg > 1) { 10421592Srgrimes bccb->hccb.opcode = INITIATOR_SG_CCB_WRESID; 10431592Srgrimes ahautoa24((sizeof(aha_sg_t) * nseg), 10441592Srgrimes bccb->hccb.data_len); 10451592Srgrimes ahautoa24(bccb->sg_list_phys, bccb->hccb.data_addr); 10461592Srgrimes } else { 10471592Srgrimes bcopy(bccb->sg_list->len, bccb->hccb.data_len, 3); 10481592Srgrimes bcopy(bccb->sg_list->addr, bccb->hccb.data_addr, 3); 10491592Srgrimes } 10501592Srgrimes 105174874Smarkm if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 105274874Smarkm op = BUS_DMASYNC_PREREAD; 105374874Smarkm else 10541592Srgrimes op = BUS_DMASYNC_PREWRITE; 10551592Srgrimes 10561592Srgrimes bus_dmamap_sync(aha->buffer_dmat, bccb->dmamap, op); 105729140Stg 10581592Srgrimes } else { 105925101Sdavidn bccb->hccb.opcode = INITIATOR_CCB_WRESID; 106025101Sdavidn ahautoa24(0, bccb->hccb.data_len); 106125101Sdavidn ahautoa24(0, bccb->hccb.data_addr); 106225101Sdavidn } 106374874Smarkm 106474874Smarkm s = splcam(); 106574874Smarkm 106674874Smarkm /* 106774874Smarkm * Last time we need to check if this CCB needs to 106874874Smarkm * be aborted. 106974874Smarkm */ 107074874Smarkm if (ccb->ccb_h.status != CAM_REQ_INPROG) { 107174874Smarkm if (nseg != 0) 10721592Srgrimes bus_dmamap_unload(aha->buffer_dmat, bccb->dmamap); 10731592Srgrimes ahafreeccb(aha, bccb); 107417435Spst xpt_done(ccb); 10751592Srgrimes splx(s); 10761592Srgrimes return; 107774874Smarkm } 107851433Smarkm 107951433Smarkm bccb->flags = BCCB_ACTIVE; 108051433Smarkm ccb->ccb_h.status |= CAM_SIM_QUEUED; 108151433Smarkm LIST_INSERT_HEAD(&aha->pending_ccbs, &ccb->ccb_h, sim_links.le); 108251433Smarkm 108351433Smarkm ccb->ccb_h.timeout_ch = 108451433Smarkm timeout(ahatimeout, (caddr_t)bccb, 108551433Smarkm (ccb->ccb_h.timeout * hz) / 1000); 108651433Smarkm 108751433Smarkm /* Tell the adapter about this command */ 108851433Smarkm paddr = ahaccbvtop(aha, bccb); 108951433Smarkm ahautoa24(paddr, aha->cur_outbox->ccb_addr); 109051433Smarkm if (aha->cur_outbox->action_code != BMBO_FREE) 109151433Smarkm panic("%s: Too few mailboxes or to many ccbs???", aha_name(aha)); 109251433Smarkm aha->cur_outbox->action_code = BMBO_START; 109351433Smarkm aha_outb(aha, COMMAND_REG, BOP_START_MBOX); 109451433Smarkm 109551433Smarkm ahanextoutbox(aha); 109651433Smarkm splx(s); 109751433Smarkm} 109851433Smarkm 109951433Smarkmvoid 110051433Smarkmaha_intr(void *arg) 110151433Smarkm{ 110251433Smarkm struct aha_softc *aha; 110351433Smarkm u_int intstat; 110451433Smarkm 110551433Smarkm aha = (struct aha_softc *)arg; 110651433Smarkm while (((intstat = aha_inb(aha, INTSTAT_REG)) & INTR_PENDING) != 0) { 110751433Smarkm if ((intstat & CMD_COMPLETE) != 0) { 110851433Smarkm aha->latched_status = aha_inb(aha, STATUS_REG); 110951433Smarkm aha->command_cmp = TRUE; 111051433Smarkm } 111151433Smarkm 111251433Smarkm aha_outb(aha, CONTROL_REG, RESET_INTR); 111351433Smarkm 111451433Smarkm if ((intstat & IMB_LOADED) != 0) { 111551433Smarkm while (aha->cur_inbox->comp_code != BMBI_FREE) { 111651433Smarkm u_int32_t paddr; 111751433Smarkm paddr = aha_a24tou(aha->cur_inbox->ccb_addr); 111851433Smarkm ahadone(aha, 111951433Smarkm ahaccbptov(aha, paddr), 112051433Smarkm aha->cur_inbox->comp_code); 112151433Smarkm aha->cur_inbox->comp_code = BMBI_FREE; 112251433Smarkm ahanextinbox(aha); 112351433Smarkm } 112451433Smarkm } 112551433Smarkm 112651433Smarkm if ((intstat & SCSI_BUS_RESET) != 0) { 112751433Smarkm ahareset(aha, /*hardreset*/FALSE); 112851433Smarkm } 112951433Smarkm } 113051433Smarkm} 113151433Smarkm 113251433Smarkmstatic void 113351433Smarkmahadone(struct aha_softc *aha, struct aha_ccb *bccb, aha_mbi_comp_code_t comp_code) 113451433Smarkm{ 113551433Smarkm union ccb *ccb; 113651433Smarkm struct ccb_scsiio *csio; 113751433Smarkm 113851433Smarkm ccb = bccb->ccb; 113951433Smarkm csio = &bccb->ccb->csio; 114051433Smarkm 114151433Smarkm if ((bccb->flags & BCCB_ACTIVE) == 0) { 114251433Smarkm printf("%s: ahadone - Attempt to free non-active BCCB 0x%x\n", 114351433Smarkm aha_name(aha), (intptr_t)bccb); 114451433Smarkm return; 114551433Smarkm } 114651433Smarkm 114751433Smarkm if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 114851433Smarkm bus_dmasync_op_t op; 114951433Smarkm 115051433Smarkm if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 115167007Sguido op = BUS_DMASYNC_POSTREAD; 115267007Sguido else 115367007Sguido op = BUS_DMASYNC_POSTWRITE; 115467007Sguido bus_dmamap_sync(aha->buffer_dmat, bccb->dmamap, op); 115567007Sguido bus_dmamap_unload(aha->buffer_dmat, bccb->dmamap); 115667007Sguido } 115767007Sguido 115851433Smarkm if (bccb == aha->recovery_bccb) { 115951433Smarkm /* 116051433Smarkm * The recovery BCCB does not have a CCB associated 116151433Smarkm * with it, so short circuit the normal error handling. 116251433Smarkm * We now traverse our list of pending CCBs and process 116351433Smarkm * any that were terminated by the recovery CCBs action. 116451433Smarkm * We also reinstate timeouts for all remaining, pending, 116551433Smarkm * CCBs. 116651433Smarkm */ 116751433Smarkm struct cam_path *path; 116851433Smarkm struct ccb_hdr *ccb_h; 116951433Smarkm cam_status error; 117051433Smarkm 117151433Smarkm /* Notify all clients that a BDR occured */ 117251433Smarkm error = xpt_create_path(&path, /*periph*/NULL, 117351433Smarkm cam_sim_path(aha->sim), 117451433Smarkm bccb->hccb.target, 117551433Smarkm CAM_LUN_WILDCARD); 117651433Smarkm 117751433Smarkm if (error == CAM_REQ_CMP) 117851433Smarkm xpt_async(AC_SENT_BDR, path, NULL); 117951433Smarkm 118051433Smarkm ccb_h = LIST_FIRST(&aha->pending_ccbs); 118151433Smarkm while (ccb_h != NULL) { 118251433Smarkm struct aha_ccb *pending_bccb; 118351433Smarkm 118451433Smarkm pending_bccb = (struct aha_ccb *)ccb_h->ccb_bccb_ptr; 118551433Smarkm if (pending_bccb->hccb.target == bccb->hccb.target) { 118651433Smarkm pending_bccb->hccb.ahastat = AHASTAT_HA_BDR; 118751433Smarkm ccb_h = LIST_NEXT(ccb_h, sim_links.le); 118851433Smarkm ahadone(aha, pending_bccb, BMBI_ERROR); 118951433Smarkm } else { 119051433Smarkm ccb_h->timeout_ch = 119151433Smarkm timeout(ahatimeout, (caddr_t)pending_bccb, 119251433Smarkm (ccb_h->timeout * hz) / 1000); 119351433Smarkm ccb_h = LIST_NEXT(ccb_h, sim_links.le); 119451433Smarkm } 119551433Smarkm } 119674874Smarkm printf("%s: No longer in timeout\n", aha_name(aha)); 119751433Smarkm return; 119851433Smarkm } 119951433Smarkm 120051433Smarkm untimeout(ahatimeout, bccb, ccb->ccb_h.timeout_ch); 120174874Smarkm 120274874Smarkm switch (comp_code) { 120374874Smarkm case BMBI_FREE: 120474874Smarkm printf("%s: ahadone - CCB completed with free status!\n", 120574874Smarkm aha_name(aha)); 120674874Smarkm break; 120774874Smarkm case BMBI_NOT_FOUND: 120874874Smarkm printf("%s: ahadone - CCB Abort failed to find CCB\n", 120974874Smarkm aha_name(aha)); 121074874Smarkm break; 121174874Smarkm case BMBI_ABORT: 121251433Smarkm case BMBI_ERROR: 121374874Smarkm /* An error occured */ 121474874Smarkm switch(bccb->hccb.ahastat) { 121574874Smarkm case AHASTAT_DATARUN_ERROR: 121674874Smarkm if (bccb->hccb.data_len <= 0) { 121774874Smarkm csio->ccb_h.status = CAM_DATA_RUN_ERR; 121874874Smarkm break; 121974874Smarkm } 122051433Smarkm /* FALLTHROUGH */ 122151433Smarkm case AHASTAT_NOERROR: 122251433Smarkm csio->scsi_status = bccb->hccb.sdstat; 122374874Smarkm csio->ccb_h.status |= CAM_SCSI_STATUS_ERROR; 122451433Smarkm switch(csio->scsi_status) { 12251592Srgrimes case SCSI_STATUS_CHECK_COND: 12261592Srgrimes case SCSI_STATUS_CMD_TERMINATED: 12271592Srgrimes csio->ccb_h.status |= CAM_AUTOSNS_VALID; 12281592Srgrimes /* 122917435Spst * The aha writes the sense data at different 12301592Srgrimes * offsets based on the scsi cmd len 123125101Sdavidn */ 123225101Sdavidn bcopy((caddr_t) &bccb->hccb.scsi_cdb + 123325101Sdavidn bccb->hccb.cmd_len, 123474874Smarkm (caddr_t) &csio->sense_data, 123574874Smarkm bccb->hccb.sense_len); 123674874Smarkm break; 12371592Srgrimes default: 12381592Srgrimes break; 12391592Srgrimes case SCSI_STATUS_OK: 12401592Srgrimes csio->ccb_h.status = CAM_REQ_CMP; 12411592Srgrimes break; 12421592Srgrimes } 12431592Srgrimes csio->resid = aha_a24tou(bccb->hccb.data_len); 124417435Spst break; 124517435Spst case AHASTAT_SELTIMEOUT: 124617435Spst csio->ccb_h.status = CAM_SEL_TIMEOUT; 124717435Spst break; 124874874Smarkm case AHASTAT_UNEXPECTED_BUSFREE: 124951433Smarkm csio->ccb_h.status = CAM_UNEXP_BUSFREE; 125051433Smarkm break; 125117435Spst case AHASTAT_INVALID_PHASE: 125217435Spst csio->ccb_h.status = CAM_SEQUENCE_FAIL; 125364103Ssheldonh break; 12541592Srgrimes case AHASTAT_INVALID_ACTION_CODE: 125517435Spst panic("%s: Inavlid Action code", aha_name(aha)); 125617435Spst break; 125717435Spst case AHASTAT_INVALID_OPCODE: 125817435Spst panic("%s: Inavlid CCB Opcode code %x hccb = %p", 125917435Spst aha_name(aha), bccb->hccb.opcode, &bccb->hccb); 126017435Spst break; 126151433Smarkm case AHASTAT_LINKED_CCB_LUN_MISMATCH: 126217435Spst /* We don't even support linked commands... */ 126317435Spst panic("%s: Linked CCB Lun Mismatch", aha_name(aha)); 126417435Spst break; 12651592Srgrimes case AHASTAT_INVALID_CCB_OR_SG_PARAM: 12661592Srgrimes panic("%s: Invalid CCB or SG list", aha_name(aha)); 12671592Srgrimes break; 12681592Srgrimes case AHASTAT_HA_SCSI_BUS_RESET: 12691592Srgrimes if ((csio->ccb_h.status & CAM_STATUS_MASK) 12701592Srgrimes != CAM_CMD_TIMEOUT) 12711592Srgrimes csio->ccb_h.status = CAM_SCSI_BUS_RESET; 12721592Srgrimes break; 12731592Srgrimes case AHASTAT_HA_BDR: 12741592Srgrimes if ((bccb->flags & BCCB_DEVICE_RESET) == 0) 12751592Srgrimes csio->ccb_h.status = CAM_BDR_SENT; 12761592Srgrimes else 12771592Srgrimes csio->ccb_h.status = CAM_CMD_TIMEOUT; 12781592Srgrimes break; 12791592Srgrimes } 12801592Srgrimes if (csio->ccb_h.status != CAM_REQ_CMP) { 12811592Srgrimes xpt_freeze_devq(csio->ccb_h.path, /*count*/1); 12821592Srgrimes csio->ccb_h.status |= CAM_DEV_QFRZN; 12831592Srgrimes } 12841592Srgrimes if ((bccb->flags & BCCB_RELEASE_SIMQ) != 0) 128525101Sdavidn ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 128625101Sdavidn ahafreeccb(aha, bccb); 128725101Sdavidn xpt_done(ccb); 128825674Sdavidn break; 128925101Sdavidn case BMBI_OK: 129025101Sdavidn /* All completed without incident */ 129156668Sshin /* XXX DO WE NEED TO COPY SENSE BYTES HERE???? XXX */ 129256668Sshin ccb->ccb_h.status |= CAM_REQ_CMP; 129356668Sshin if ((bccb->flags & BCCB_RELEASE_SIMQ) != 0) 129425101Sdavidn ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 129525101Sdavidn ahafreeccb(aha, bccb); 129625101Sdavidn xpt_done(ccb); 129725101Sdavidn break; 129825101Sdavidn } 129925101Sdavidn} 130025101Sdavidn 130125101Sdavidnstatic int 130225101Sdavidnahareset(struct aha_softc* aha, int hard_reset) 130325101Sdavidn{ 130425101Sdavidn struct ccb_hdr *ccb_h; 130525101Sdavidn u_int status; 130625101Sdavidn u_int timeout; 130725101Sdavidn u_int8_t reset_type; 130825101Sdavidn 130925101Sdavidn if (hard_reset != 0) 131040310Sdes reset_type = HARD_RESET; 131140310Sdes else 131225101Sdavidn reset_type = SOFT_RESET; 131340310Sdes aha_outb(aha, CONTROL_REG, reset_type); 13141592Srgrimes 131525101Sdavidn /* Wait 5sec. for Diagnostic start */ 13161592Srgrimes timeout = 5 * 10000; 131774874Smarkm while (--timeout) { 131874874Smarkm status = aha_inb(aha, STATUS_REG); 131974874Smarkm if ((status & DIAG_ACTIVE) != 0) 132074874Smarkm break; 132174874Smarkm DELAY(100); 132274874Smarkm } 132374874Smarkm if (timeout == 0) { 132474874Smarkm if (bootverbose) 132574874Smarkm printf("%s: ahareset - Diagnostic Active failed to " 132674874Smarkm "assert. status = 0x%x\n", aha_name(aha), 13271592Srgrimes status); 132829140Stg return (ETIMEDOUT); 13291592Srgrimes } 13301592Srgrimes 133117435Spst /* Wait 10sec. for Diagnostic end */ 133225283Sdavidn timeout = 10 * 10000; 133325283Sdavidn while (--timeout) { 133425283Sdavidn status = aha_inb(aha, STATUS_REG); 13356740Sguido if ((status & DIAG_ACTIVE) == 0) 133625283Sdavidn break; 13376740Sguido DELAY(100); 13386740Sguido } 133925101Sdavidn if (timeout == 0) { 134025101Sdavidn panic("%s: ahareset - Diagnostic Active failed to drop. " 134125101Sdavidn "status = 0x%x\n", aha_name(aha), status); 134225101Sdavidn return (ETIMEDOUT); 134336349Ssteve } 13441592Srgrimes 13451592Srgrimes /* Wait for the host adapter to become ready or report a failure */ 13461592Srgrimes timeout = 10000; 13471592Srgrimes while (--timeout) { 13481592Srgrimes status = aha_inb(aha, STATUS_REG); 13491592Srgrimes if ((status & (DIAG_FAIL|HA_READY|DATAIN_REG_READY)) != 0) 13501592Srgrimes break; 13511592Srgrimes DELAY(100); 13521592Srgrimes } 13531592Srgrimes if (timeout == 0) { 135417435Spst printf("%s: ahareset - Host adapter failed to come ready. " 135517435Spst "status = 0x%x\n", aha_name(aha), status); 135617435Spst return (ETIMEDOUT); 135717435Spst } 135817435Spst 13591592Srgrimes /* If the diagnostics failed, tell the user */ 13601592Srgrimes if ((status & DIAG_FAIL) != 0 13611592Srgrimes || (status & HA_READY) == 0) { 13621592Srgrimes printf("%s: ahareset - Adapter failed diagnostics\n", 13631592Srgrimes aha_name(aha)); 13641592Srgrimes 13651592Srgrimes if ((status & DATAIN_REG_READY) != 0) 13661592Srgrimes printf("%s: ahareset - Host Adapter Error " 13671592Srgrimes "code = 0x%x\n", aha_name(aha), 13681592Srgrimes aha_inb(aha, DATAIN_REG)); 13691592Srgrimes return (ENXIO); 13701592Srgrimes } 13718696Sdg 13721592Srgrimes /* If we've allocated mailboxes, initialize them */ 13731592Srgrimes if (aha->init_level > 4) 13741592Srgrimes ahainitmboxes(aha); 13751592Srgrimes 137625283Sdavidn /* If we've attached to the XPT, tell it about the event */ 137725283Sdavidn if (aha->path != NULL) 137825283Sdavidn xpt_async(AC_BUS_RESET, aha->path, NULL); 13791592Srgrimes 138025283Sdavidn /* 13811592Srgrimes * Perform completion processing for all outstanding CCBs. 13821592Srgrimes */ 13831592Srgrimes while ((ccb_h = LIST_FIRST(&aha->pending_ccbs)) != NULL) { 13841592Srgrimes struct aha_ccb *pending_bccb; 13851592Srgrimes 13861592Srgrimes pending_bccb = (struct aha_ccb *)ccb_h->ccb_bccb_ptr; 13871592Srgrimes pending_bccb->hccb.ahastat = AHASTAT_HA_SCSI_BUS_RESET; 13881592Srgrimes ahadone(aha, pending_bccb, BMBI_ERROR); 13891592Srgrimes } 13901592Srgrimes 13911592Srgrimes return (0); 13926740Sguido} 13936740Sguido 139417433Spst/* 139517433Spst * Send a command to the adapter. 139676096Smarkm */ 139717433Spstint 13981592Srgrimesaha_cmd(struct aha_softc *aha, aha_op_t opcode, u_int8_t *params, 13991592Srgrimes u_int param_len, u_int8_t *reply_data, u_int reply_len, 140025283Sdavidn u_int cmd_timeout) 140125283Sdavidn{ 140225283Sdavidn u_int timeout; 140383308Smikeh u_int status; 140483308Smikeh u_int intstat; 140525283Sdavidn u_int reply_buf_size; 140625283Sdavidn int s; 140725283Sdavidn 140883308Smikeh /* No data returned to start */ 140913139Speter reply_buf_size = reply_len; 14101592Srgrimes reply_len = 0; 14111592Srgrimes intstat = 0; 14121592Srgrimes 14131592Srgrimes aha->command_cmp = 0; 14141592Srgrimes /* 141525986Sdanny * Wait up to 1 sec. for the adapter to become 141625986Sdanny * ready to accept commands. 141725986Sdanny */ 141825986Sdanny timeout = 10000; 14191592Srgrimes while (--timeout) { 142025986Sdanny 14211592Srgrimes status = aha_inb(aha, STATUS_REG); 14221592Srgrimes if ((status & HA_READY) != 0 142325283Sdavidn && (status & CMD_REG_BUSY) == 0) 142413139Speter break; 14251592Srgrimes DELAY(100); 14261592Srgrimes } 14271592Srgrimes if (timeout == 0) { 14281592Srgrimes printf("%s: aha_cmd: Timeout waiting for adapter ready, " 14291592Srgrimes "status = 0x%x\n", aha_name(aha), status); 143025101Sdavidn return (ETIMEDOUT); 143125101Sdavidn } 143225101Sdavidn 14331592Srgrimes /* 14341592Srgrimes * Send the opcode followed by any necessary parameter bytes. 14351592Srgrimes */ 143625101Sdavidn aha_outb(aha, COMMAND_REG, opcode); 143725101Sdavidn 143825101Sdavidn /* 14391592Srgrimes * Wait for up to 1sec to get the parameter list sent 14401592Srgrimes */ 14411592Srgrimes timeout = 10000; 14421592Srgrimes while (param_len && --timeout) { 14431592Srgrimes DELAY(100); 14441592Srgrimes status = aha_inb(aha, STATUS_REG); 14451592Srgrimes intstat = aha_inb(aha, INTSTAT_REG); 14461592Srgrimes if ((intstat & (INTR_PENDING|CMD_COMPLETE)) 14471592Srgrimes == (INTR_PENDING|CMD_COMPLETE)) 14481592Srgrimes break; 144936612Sjb if (aha->command_cmp != 0) { 14501592Srgrimes status = aha->latched_status; 14511592Srgrimes break; 14521592Srgrimes } 14531592Srgrimes if ((status & DATAIN_REG_READY) != 0) 14541592Srgrimes break; 14551592Srgrimes if ((status & CMD_REG_BUSY) == 0) { 14561592Srgrimes aha_outb(aha, COMMAND_REG, *params++); 145731973Simp param_len--; 14581592Srgrimes } 14591592Srgrimes } 14601592Srgrimes if (timeout == 0) { 14611592Srgrimes printf("%s: aha_cmd: Timeout sending parameters, " 14621592Srgrimes "status = 0x%x\n", aha_name(aha), status); 14631592Srgrimes return (ETIMEDOUT); 14641592Srgrimes } 14651592Srgrimes 14661592Srgrimes /* 14671592Srgrimes * For all other commands, we wait for any output data 14681592Srgrimes * and the final comand completion interrupt. 14691592Srgrimes */ 14701592Srgrimes while (--cmd_timeout) { 14711592Srgrimes 14721592Srgrimes status = aha_inb(aha, STATUS_REG); 14731592Srgrimes intstat = aha_inb(aha, INTSTAT_REG); 14741592Srgrimes if ((intstat & (INTR_PENDING|CMD_COMPLETE)) 14751592Srgrimes == (INTR_PENDING|CMD_COMPLETE)) 14761592Srgrimes break; 14771592Srgrimes 14781592Srgrimes if (aha->command_cmp != 0) { 14791592Srgrimes status = aha->latched_status; 14801592Srgrimes break; 14811592Srgrimes } 14821592Srgrimes 14831592Srgrimes if ((status & DATAIN_REG_READY) != 0) { 14841592Srgrimes u_int8_t data; 14851592Srgrimes 14861592Srgrimes data = aha_inb(aha, DATAIN_REG); 14871592Srgrimes if (reply_len < reply_buf_size) { 14881592Srgrimes *reply_data++ = data; 14891592Srgrimes } else { 14901592Srgrimes printf("%s: aha_cmd - Discarded reply data byte " 14911592Srgrimes "for opcode 0x%x\n", aha_name(aha), 14921592Srgrimes opcode); 14931592Srgrimes } 14941592Srgrimes reply_len++; 14951592Srgrimes } 14961592Srgrimes 14971592Srgrimes DELAY(100); 14981592Srgrimes } 14996740Sguido if (timeout == 0) { 15008240Swollman printf("%s: aha_cmd: Timeout waiting for reply data and " 15018240Swollman "command complete.\n%s: status = 0x%x, intstat = 0x%x, " 15026740Sguido "reply_len = %d\n", aha_name(aha), aha_name(aha), status, 150317433Spst intstat, reply_len); 15041592Srgrimes return (ETIMEDOUT); 15051592Srgrimes } 15061592Srgrimes 15071592Srgrimes /* 15081592Srgrimes * Clear any pending interrupts. Block interrupts so our 15091592Srgrimes * interrupt handler is not re-entered. 15101592Srgrimes */ 15111592Srgrimes s = splcam(); 15121592Srgrimes aha_intr(aha); 15131592Srgrimes splx(s); 15141592Srgrimes 15151592Srgrimes /* 15161592Srgrimes * If the command was rejected by the controller, tell the caller. 15171592Srgrimes */ 15181592Srgrimes if ((status & CMD_INVALID) != 0) { 15191592Srgrimes if (bootverbose) 15201592Srgrimes printf("%s: Invalid Command 0x%x\n", aha_name(aha), 15211592Srgrimes opcode); 152217433Spst /* 15231592Srgrimes * Some early adapters may not recover properly from 15241592Srgrimes * an invalid command. If it appears that the controller 15251592Srgrimes * has wedged (i.e. status was not cleared by our interrupt 15261592Srgrimes * reset above), perform a soft reset. 15271592Srgrimes */ 15281592Srgrimes DELAY(1000); 15291592Srgrimes status = aha_inb(aha, STATUS_REG); 15301592Srgrimes if ((status & (CMD_INVALID|STATUS_REG_RSVD|DATAIN_REG_READY| 15311592Srgrimes CMD_REG_BUSY|DIAG_FAIL|DIAG_ACTIVE)) != 0 15321592Srgrimes || (status & (HA_READY|INIT_REQUIRED)) 15331592Srgrimes != (HA_READY|INIT_REQUIRED)) { 15341592Srgrimes ahareset(aha, /*hard_reset*/FALSE); 15351592Srgrimes } 15361592Srgrimes return (EINVAL); 15371592Srgrimes } 15381592Srgrimes 15391592Srgrimes 15401592Srgrimes if (param_len > 0) { 15411592Srgrimes /* The controller did not accept the full argument list */ 15421592Srgrimes return (E2BIG); 15431592Srgrimes } 15441592Srgrimes 15451592Srgrimes if (reply_len != reply_buf_size) { 15461592Srgrimes /* Too much or too little data received */ 15471592Srgrimes return (EMSGSIZE); 15481592Srgrimes } 15491592Srgrimes 15501592Srgrimes /* We were successful */ 15511592Srgrimes return (0); 15521592Srgrimes} 15531592Srgrimes 15541592Srgrimesstatic int 15551592Srgrimesahainitmboxes(struct aha_softc *aha) 15561592Srgrimes{ 15571592Srgrimes int error; 155882792Sache init_24b_mbox_params_t init_mbox; 15591592Srgrimes 15601592Srgrimes bzero(aha->in_boxes, sizeof(aha_mbox_in_t) * aha->num_boxes); 15611592Srgrimes bzero(aha->out_boxes, sizeof(aha_mbox_out_t) * aha->num_boxes); 15621592Srgrimes aha->cur_inbox = aha->in_boxes; 15631592Srgrimes aha->last_inbox = aha->in_boxes + aha->num_boxes - 1; 15641592Srgrimes aha->cur_outbox = aha->out_boxes; 15651592Srgrimes aha->last_outbox = aha->out_boxes + aha->num_boxes - 1; 15661592Srgrimes 15671592Srgrimes /* Tell the adapter about them */ 15681592Srgrimes init_mbox.num_mboxes = aha->num_boxes; 15691592Srgrimes ahautoa24(aha->mailbox_physbase, init_mbox.base_addr); 15701592Srgrimes error = aha_cmd(aha, BOP_INITIALIZE_MBOX, (u_int8_t *)&init_mbox, 15711592Srgrimes /*parmlen*/sizeof(init_mbox), /*reply_buf*/NULL, 15721592Srgrimes /*reply_len*/0, DEFAULT_CMD_TIMEOUT); 15731592Srgrimes 15741592Srgrimes if (error != 0) 15751592Srgrimes printf("ahainitmboxes: Initialization command failed\n"); 15761592Srgrimes return (error); 15771592Srgrimes} 15781592Srgrimes 15791592Srgrimes/* 15801592Srgrimes * Update the XPT's idea of the negotiated transfer 15811592Srgrimes * parameters for a particular target. 15821592Srgrimes */ 15831592Srgrimesstatic void 15841592Srgrimesahafetchtransinfo(struct aha_softc *aha, struct ccb_trans_settings* cts) 15851592Srgrimes{ 15861592Srgrimes setup_data_t setup_info; 15871592Srgrimes u_int target; 15881592Srgrimes u_int targ_offset; 15891592Srgrimes u_int sync_period; 15901592Srgrimes int error; 15911592Srgrimes u_int8_t param; 15921592Srgrimes targ_syncinfo_t sync_info; 15931592Srgrimes 159456668Sshin target = cts->ccb_h.target_id; 159556668Sshin targ_offset = (target & 0x7); 15961592Srgrimes 15971592Srgrimes /* 15981592Srgrimes * Inquire Setup Information. This command retreives the 15991592Srgrimes * Wide negotiation status for recent adapters as well as 16001592Srgrimes * the sync info for older models. 16011592Srgrimes */ 160256668Sshin param = sizeof(setup_info); 160356668Sshin error = aha_cmd(aha, BOP_INQUIRE_SETUP_INFO, ¶m, /*paramlen*/1, 16041592Srgrimes (u_int8_t*)&setup_info, sizeof(setup_info), 16051592Srgrimes DEFAULT_CMD_TIMEOUT); 160656668Sshin 16071592Srgrimes if (error != 0) { 16081592Srgrimes printf("%s: ahafetchtransinfo - Inquire Setup Info Failed\n", 16091592Srgrimes aha_name(aha)); 16101592Srgrimes return; 16111592Srgrimes } 16121592Srgrimes 16131592Srgrimes sync_info = setup_info.syncinfo[targ_offset]; 161456668Sshin 161556668Sshin if (sync_info.sync == 0) 16161592Srgrimes cts->sync_offset = 0; 16171592Srgrimes else 16181592Srgrimes cts->sync_offset = sync_info.offset; 161956668Sshin 16201592Srgrimes cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 16218240Swollman 16228240Swollman sync_period = 2000 + (500 * sync_info.period); 16238240Swollman 16248240Swollman /* Convert ns value to standard SCSI sync rate */ 16258240Swollman if (cts->sync_offset != 0) 16268240Swollman cts->sync_period = scsi_calc_syncparam(sync_period); 16278240Swollman else 16288240Swollman cts->sync_period = 0; 16298240Swollman 16308240Swollman cts->valid = CCB_TRANS_SYNC_RATE_VALID 16318240Swollman | CCB_TRANS_SYNC_OFFSET_VALID 16328240Swollman | CCB_TRANS_BUS_WIDTH_VALID; 16338240Swollman xpt_async(AC_TRANSFER_NEG, cts->ccb_h.path, cts); 16348240Swollman} 16358240Swollman 16368240Swollmanstatic void 16378240Swollmanahamapmboxes(void *arg, bus_dma_segment_t *segs, int nseg, int error) 16381592Srgrimes{ 16391592Srgrimes struct aha_softc* aha; 16401592Srgrimes 16411592Srgrimes aha = (struct aha_softc*)arg; 16421592Srgrimes aha->mailbox_physbase = segs->ds_addr; 16431592Srgrimes} 16441592Srgrimes 16451592Srgrimesstatic void 16461592Srgrimesahamapccbs(void *arg, bus_dma_segment_t *segs, int nseg, int error) 16471592Srgrimes{ 16481592Srgrimes struct aha_softc* aha; 16491592Srgrimes 16501592Srgrimes aha = (struct aha_softc*)arg; 16511592Srgrimes aha->aha_ccb_physbase = segs->ds_addr; 16521592Srgrimes} 16531592Srgrimes 16541592Srgrimesstatic void 16551592Srgrimesahamapsgs(void *arg, bus_dma_segment_t *segs, int nseg, int error) 16561592Srgrimes{ 16571592Srgrimes 16581592Srgrimes struct aha_softc* aha; 16591592Srgrimes 16601592Srgrimes aha = (struct aha_softc*)arg; 166131973Simp SLIST_FIRST(&aha->sg_maps)->sg_physaddr = segs->ds_addr; 16621592Srgrimes} 166331973Simp 16641592Srgrimesstatic void 166556668Sshinahapoll(struct cam_sim *sim) 166656668Sshin{ 166712532Sguido} 166812532Sguido 16691592Srgrimesvoid 167012532Sguidoahatimeout(void *arg) 167112532Sguido{ 167212532Sguido struct aha_ccb *bccb; 167312532Sguido union ccb *ccb; 167412532Sguido struct aha_softc *aha; 167512532Sguido int s; 167612532Sguido u_int32_t paddr; 167712532Sguido 16781592Srgrimes bccb = (struct aha_ccb *)arg; 16791592Srgrimes ccb = bccb->ccb; 16801592Srgrimes aha = (struct aha_softc *)ccb->ccb_h.ccb_aha_ptr; 16811592Srgrimes xpt_print_path(ccb->ccb_h.path); 16821592Srgrimes printf("CCB 0x%x - timed out\n", (intptr_t)bccb); 16831592Srgrimes 16841592Srgrimes s = splcam(); 16851592Srgrimes 168656668Sshin if ((bccb->flags & BCCB_ACTIVE) == 0) { 168756668Sshin xpt_print_path(ccb->ccb_h.path); 168817435Spst printf("CCB 0x%x - timed out CCB already completed\n", 16891592Srgrimes (intptr_t)bccb); 16901592Srgrimes splx(s); 169156668Sshin return; 16921592Srgrimes } 16931592Srgrimes 16941592Srgrimes /* 16951592Srgrimes * In order to simplify the recovery process, we ask the XPT 16961592Srgrimes * layer to halt the queue of new transactions and we traverse 16971592Srgrimes * the list of pending CCBs and remove their timeouts. This 16981592Srgrimes * means that the driver attempts to clear only one error 16991592Srgrimes * condition at a time. In general, timeouts that occur 17001592Srgrimes * close together are related anyway, so there is no benefit 17011592Srgrimes * in attempting to handle errors in parrallel. Timeouts will 17021592Srgrimes * be reinstated when the recovery process ends. 17031592Srgrimes */ 17041592Srgrimes if ((bccb->flags & BCCB_DEVICE_RESET) == 0) { 17051592Srgrimes struct ccb_hdr *ccb_h; 17061592Srgrimes 17071592Srgrimes if ((bccb->flags & BCCB_RELEASE_SIMQ) == 0) { 170856668Sshin xpt_freeze_simq(aha->sim, /*count*/1); 170956668Sshin bccb->flags |= BCCB_RELEASE_SIMQ; 171056668Sshin } 171156668Sshin 171256668Sshin ccb_h = LIST_FIRST(&aha->pending_ccbs); 171356668Sshin while (ccb_h != NULL) { 171456668Sshin struct aha_ccb *pending_bccb; 17151592Srgrimes 17161592Srgrimes pending_bccb = (struct aha_ccb *)ccb_h->ccb_bccb_ptr; 17171592Srgrimes untimeout(ahatimeout, pending_bccb, ccb_h->timeout_ch); 17181592Srgrimes ccb_h = LIST_NEXT(ccb_h, sim_links.le); 171956668Sshin } 17201592Srgrimes } 17211592Srgrimes 17221592Srgrimes if ((bccb->flags & BCCB_DEVICE_RESET) != 0 17231592Srgrimes || aha->cur_outbox->action_code != BMBO_FREE) { 17241592Srgrimes /* 17251592Srgrimes * Try a full host adapter/SCSI bus reset. 17261592Srgrimes * We do this only if we have already attempted 17271592Srgrimes * to clear the condition with a BDR, or we cannot 17281592Srgrimes * attempt a BDR for lack of mailbox resources. 17291592Srgrimes */ 17301592Srgrimes ccb->ccb_h.status = CAM_CMD_TIMEOUT; 17311592Srgrimes ahareset(aha, /*hardreset*/TRUE); 17321592Srgrimes printf("%s: No longer in timeout\n", aha_name(aha)); 17331592Srgrimes } else { 17341592Srgrimes /* 17351592Srgrimes * Send a Bus Device Reset message: 17361592Srgrimes * The target that is holding up the bus may not 17378240Swollman * be the same as the one that triggered this timeout 17381592Srgrimes * (different commands have different timeout lengths), 17391592Srgrimes * but we have no way of determining this from our 17401592Srgrimes * timeout handler. Our strategy here is to queue a 17411592Srgrimes * BDR message to the target of the timed out command. 17428240Swollman * If this fails, we'll get another timeout 2 seconds 17431592Srgrimes * later which will attempt a bus reset. 17441592Srgrimes */ 17458240Swollman bccb->flags |= BCCB_DEVICE_RESET; 17468240Swollman ccb->ccb_h.timeout_ch = timeout(ahatimeout, (caddr_t)bccb, 2 * hz); 17471592Srgrimes aha->recovery_bccb->hccb.opcode = INITIATOR_BUS_DEV_RESET; 174870205Sdan 174970205Sdan /* No Data Transfer */ 17508240Swollman aha->recovery_bccb->hccb.datain = TRUE; 175170205Sdan aha->recovery_bccb->hccb.dataout = TRUE; 17521592Srgrimes aha->recovery_bccb->hccb.ahastat = 0; 17531592Srgrimes aha->recovery_bccb->hccb.sdstat = 0; 17541592Srgrimes aha->recovery_bccb->hccb.target = ccb->ccb_h.target_id; 17551592Srgrimes 17561592Srgrimes /* Tell the adapter about this command */ 17571592Srgrimes paddr = ahaccbvtop(aha, aha->recovery_bccb); 17581592Srgrimes ahautoa24(paddr, aha->cur_outbox->ccb_addr); 17591592Srgrimes aha->cur_outbox->action_code = BMBO_START; 17601592Srgrimes aha_outb(aha, COMMAND_REG, BOP_START_MBOX); 17611592Srgrimes ahanextoutbox(aha); 17621592Srgrimes } 17631592Srgrimes 17641592Srgrimes splx(s); 17651592Srgrimes} 17661592Srgrimes