bt.c revision 39507
139223Sgibbs/* 239223Sgibbs * Generic driver for the BusLogic MultiMaster SCSI host adapters 339223Sgibbs * Product specific probe and attach routines can be found in: 439223Sgibbs * i386/isa/bt_isa.c BT-54X, BT-445 cards 539223Sgibbs * i386/eisa/bt_eisa.c BT-74x, BT-75x cards 639223Sgibbs * pci/bt_pci.c BT-946, BT-948, BT-956, BT-958 cards 739223Sgibbs * 839223Sgibbs * Copyright (c) 1998 Justin T. Gibbs. 939223Sgibbs * All rights reserved. 1039223Sgibbs * 1139223Sgibbs * Redistribution and use in source and binary forms, with or without 1239223Sgibbs * modification, are permitted provided that the following conditions 1339223Sgibbs * are met: 1439223Sgibbs * 1. Redistributions of source code must retain the above copyright 1539223Sgibbs * notice, this list of conditions, and the following disclaimer, 1639223Sgibbs * without modification, immediately at the beginning of the file. 1739223Sgibbs * 2. The name of the author may not be used to endorse or promote products 1839223Sgibbs * derived from this software without specific prior written permission. 1939223Sgibbs * 2039223Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2139223Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2239223Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2339223Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2439223Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2539223Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2639223Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2739223Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2839223Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2939223Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3039223Sgibbs * SUCH DAMAGE. 3139223Sgibbs * 3239507Sgibbs * $Id: bt.c,v 1.3 1998/09/17 00:08:27 gibbs Exp $ 3339223Sgibbs */ 3439223Sgibbs 3539223Sgibbs /* 3639223Sgibbs * Special thanks to Leonard N. Zubkoff for writing such a complete and 3739223Sgibbs * well documented Mylex/BusLogic MultiMaster driver for Linux. Support 3839223Sgibbs * in this driver for the wide range of MultiMaster controllers and 3939223Sgibbs * firmware revisions, with their otherwise undocumented quirks, would not 4039223Sgibbs * have been possible without his efforts. 4139223Sgibbs */ 4239223Sgibbs 4339223Sgibbs#include <sys/param.h> 4439223Sgibbs#include <sys/systm.h> 4539223Sgibbs#include <sys/malloc.h> 4639223Sgibbs#include <sys/buf.h> 4739223Sgibbs#include <sys/kernel.h> 4839223Sgibbs#include <sys/sysctl.h> 4939223Sgibbs 5039223Sgibbs/* 5139223Sgibbs * XXX It appears that BusLogic PCI adapters go out to lunch if you 5239223Sgibbs * attempt to perform memory mapped I/O. 5339223Sgibbs */ 5439223Sgibbs#if 0 5539223Sgibbs#include "pci.h" 5639223Sgibbs#if NPCI > 0 5739223Sgibbs#include <machine/bus_memio.h> 5839223Sgibbs#endif 5939223Sgibbs#endif 6039223Sgibbs#include <machine/bus_pio.h> 6139223Sgibbs#include <machine/bus.h> 6239223Sgibbs#include <machine/clock.h> 6339223Sgibbs 6439223Sgibbs#include <cam/cam.h> 6539223Sgibbs#include <cam/cam_ccb.h> 6639223Sgibbs#include <cam/cam_sim.h> 6739223Sgibbs#include <cam/cam_xpt_sim.h> 6839223Sgibbs#include <cam/cam_debug.h> 6939223Sgibbs 7039223Sgibbs#include <cam/scsi/scsi_message.h> 7139223Sgibbs 7239223Sgibbs#include <vm/vm.h> 7339223Sgibbs#include <vm/pmap.h> 7439223Sgibbs 7539223Sgibbs#include <dev/buslogic/btreg.h> 7639223Sgibbs 7739223Sgibbsstruct bt_softc *bt_softcs[NBT]; 7839223Sgibbs 7939223Sgibbs/* MailBox Management functions */ 8039223Sgibbsstatic __inline void btnextinbox(struct bt_softc *bt); 8139223Sgibbsstatic __inline void btnextoutbox(struct bt_softc *bt); 8239223Sgibbs 8339223Sgibbsstatic __inline void 8439223Sgibbsbtnextinbox(struct bt_softc *bt) 8539223Sgibbs{ 8639223Sgibbs if (bt->cur_inbox == bt->last_inbox) 8739223Sgibbs bt->cur_inbox = bt->in_boxes; 8839223Sgibbs else 8939223Sgibbs bt->cur_inbox++; 9039223Sgibbs} 9139223Sgibbs 9239223Sgibbsstatic __inline void 9339223Sgibbsbtnextoutbox(struct bt_softc *bt) 9439223Sgibbs{ 9539223Sgibbs if (bt->cur_outbox == bt->last_outbox) 9639223Sgibbs bt->cur_outbox = bt->out_boxes; 9739223Sgibbs else 9839223Sgibbs bt->cur_outbox++; 9939223Sgibbs} 10039223Sgibbs 10139223Sgibbs/* CCB Mangement functions */ 10239223Sgibbsstatic __inline u_int32_t btccbvtop(struct bt_softc *bt, 10339223Sgibbs struct bt_ccb *bccb); 10439223Sgibbsstatic __inline struct bt_ccb* btccbptov(struct bt_softc *bt, 10539223Sgibbs u_int32_t ccb_addr); 10639223Sgibbsstatic __inline u_int32_t btsensepaddr(struct bt_softc *bt, 10739223Sgibbs struct bt_ccb *bccb); 10839223Sgibbsstatic __inline struct scsi_sense_data* btsensevaddr(struct bt_softc *bt, 10939223Sgibbs struct bt_ccb *bccb); 11039223Sgibbs 11139223Sgibbsstatic __inline u_int32_t 11239223Sgibbsbtccbvtop(struct bt_softc *bt, struct bt_ccb *bccb) 11339223Sgibbs{ 11439223Sgibbs return (bt->bt_ccb_physbase 11539223Sgibbs + (u_int32_t)((caddr_t)bccb - (caddr_t)bt->bt_ccb_array)); 11639223Sgibbs} 11739223Sgibbs 11839223Sgibbsstatic __inline struct bt_ccb * 11939223Sgibbsbtccbptov(struct bt_softc *bt, u_int32_t ccb_addr) 12039223Sgibbs{ 12139223Sgibbs return (bt->bt_ccb_array + 12239223Sgibbs ((struct bt_ccb*)ccb_addr-(struct bt_ccb*)bt->bt_ccb_physbase)); 12339223Sgibbs} 12439223Sgibbs 12539223Sgibbsstatic __inline u_int32_t 12639223Sgibbsbtsensepaddr(struct bt_softc *bt, struct bt_ccb *bccb) 12739223Sgibbs{ 12839223Sgibbs u_int index; 12939223Sgibbs 13039223Sgibbs index = (u_int)(bccb - bt->bt_ccb_array); 13139223Sgibbs return (bt->sense_buffers_physbase 13239223Sgibbs + (index * sizeof(struct scsi_sense_data))); 13339223Sgibbs} 13439223Sgibbs 13539223Sgibbsstatic __inline struct scsi_sense_data * 13639223Sgibbsbtsensevaddr(struct bt_softc *bt, struct bt_ccb *bccb) 13739223Sgibbs{ 13839223Sgibbs u_int index; 13939223Sgibbs 14039223Sgibbs index = (u_int)(bccb - bt->bt_ccb_array); 14139223Sgibbs return (bt->sense_buffers + index); 14239223Sgibbs} 14339223Sgibbs 14439223Sgibbsstatic __inline struct bt_ccb* btgetccb(struct bt_softc *bt); 14539223Sgibbsstatic __inline void btfreeccb(struct bt_softc *bt, 14639223Sgibbs struct bt_ccb *bccb); 14739223Sgibbsstatic void btallocccbs(struct bt_softc *bt); 14839223Sgibbsstatic bus_dmamap_callback_t btexecuteccb; 14939223Sgibbsstatic void btdone(struct bt_softc *bt, struct bt_ccb *bccb, 15039223Sgibbs bt_mbi_comp_code_t comp_code); 15139223Sgibbs 15239223Sgibbs/* Host adapter command functions */ 15339223Sgibbsstatic int btreset(struct bt_softc* bt, int hard_reset); 15439223Sgibbs 15539223Sgibbs/* Initialization functions */ 15639223Sgibbsstatic int btinitmboxes(struct bt_softc *bt); 15739223Sgibbsstatic bus_dmamap_callback_t btmapmboxes; 15839223Sgibbsstatic bus_dmamap_callback_t btmapccbs; 15939223Sgibbsstatic bus_dmamap_callback_t btmapsgs; 16039223Sgibbs 16139223Sgibbs/* Transfer Negotiation Functions */ 16239223Sgibbsstatic void btfetchtransinfo(struct bt_softc *bt, 16339223Sgibbs struct ccb_trans_settings *cts); 16439223Sgibbs 16539223Sgibbs/* CAM SIM entry points */ 16639223Sgibbs#define ccb_bccb_ptr spriv_ptr0 16739223Sgibbs#define ccb_bt_ptr spriv_ptr1 16839223Sgibbsstatic void btaction(struct cam_sim *sim, union ccb *ccb); 16939223Sgibbsstatic void btpoll(struct cam_sim *sim); 17039223Sgibbs 17139223Sgibbs/* Our timeout handler */ 17239223Sgibbstimeout_t bttimeout; 17339223Sgibbs 17439223Sgibbsu_long bt_unit = 0; 17539223Sgibbs 17639223Sgibbs/* 17739223Sgibbs * XXX 17839223Sgibbs * Do our own re-probe protection until a configuration 17939223Sgibbs * manager can do it for us. This ensures that we don't 18039223Sgibbs * reprobe a card already found by the EISA or PCI probes. 18139223Sgibbs */ 18239223Sgibbsstruct bt_isa_port bt_isa_ports[] = 18339223Sgibbs{ 18439223Sgibbs { 0x330, 0 }, 18539223Sgibbs { 0x334, 0 }, 18639223Sgibbs { 0x230, 0 }, 18739223Sgibbs { 0x234, 0 }, 18839223Sgibbs { 0x130, 0 }, 18939223Sgibbs { 0x134, 0 } 19039223Sgibbs}; 19139223Sgibbs 19239223Sgibbs/* Exported functions */ 19339223Sgibbsstruct bt_softc * 19439223Sgibbsbt_alloc(int unit, bus_space_tag_t tag, bus_space_handle_t bsh) 19539223Sgibbs{ 19639223Sgibbs struct bt_softc *bt; 19739223Sgibbs int i; 19839223Sgibbs 19939223Sgibbs if (unit != BT_TEMP_UNIT) { 20039223Sgibbs if (unit >= NBT) { 20139223Sgibbs printf("bt: unit number (%d) too high\n", unit); 20239223Sgibbs return NULL; 20339223Sgibbs } 20439223Sgibbs 20539223Sgibbs /* 20639223Sgibbs * Allocate a storage area for us 20739223Sgibbs */ 20839223Sgibbs if (bt_softcs[unit]) { 20939223Sgibbs printf("bt%d: memory already allocated\n", unit); 21039223Sgibbs return NULL; 21139223Sgibbs } 21239223Sgibbs } 21339223Sgibbs 21439223Sgibbs bt = malloc(sizeof(struct bt_softc), M_DEVBUF, M_NOWAIT); 21539223Sgibbs if (!bt) { 21639223Sgibbs printf("bt%d: cannot malloc!\n", unit); 21739223Sgibbs return NULL; 21839223Sgibbs } 21939223Sgibbs bzero(bt, sizeof(struct bt_softc)); 22039223Sgibbs SLIST_INIT(&bt->free_bt_ccbs); 22139223Sgibbs LIST_INIT(&bt->pending_ccbs); 22239223Sgibbs SLIST_INIT(&bt->sg_maps); 22339223Sgibbs bt->unit = unit; 22439223Sgibbs bt->tag = tag; 22539223Sgibbs bt->bsh = bsh; 22639223Sgibbs 22739223Sgibbs if (bt->unit != BT_TEMP_UNIT) { 22839223Sgibbs bt_softcs[unit] = bt; 22939223Sgibbs } 23039223Sgibbs return (bt); 23139223Sgibbs} 23239223Sgibbs 23339223Sgibbsvoid 23439223Sgibbsbt_free(struct bt_softc *bt) 23539223Sgibbs{ 23639223Sgibbs switch (bt->init_level) { 23739223Sgibbs default: 23839223Sgibbs case 11: 23939223Sgibbs bus_dmamap_unload(bt->sense_dmat, bt->sense_dmamap); 24039223Sgibbs case 10: 24139223Sgibbs bus_dmamem_free(bt->sense_dmat, bt->sense_buffers, 24239223Sgibbs bt->sense_dmamap); 24339223Sgibbs case 9: 24439223Sgibbs bus_dma_tag_destroy(bt->sense_dmat); 24539223Sgibbs case 8: 24639223Sgibbs { 24739223Sgibbs struct sg_map_node *sg_map; 24839223Sgibbs 24939223Sgibbs while ((sg_map = SLIST_FIRST(&bt->sg_maps))!= NULL) { 25039223Sgibbs SLIST_REMOVE_HEAD(&bt->sg_maps, links); 25139223Sgibbs bus_dmamap_unload(bt->sg_dmat, 25239223Sgibbs sg_map->sg_dmamap); 25339223Sgibbs bus_dmamem_free(bt->sg_dmat, sg_map->sg_vaddr, 25439223Sgibbs sg_map->sg_dmamap); 25539223Sgibbs free(sg_map, M_DEVBUF); 25639223Sgibbs } 25739223Sgibbs bus_dma_tag_destroy(bt->sg_dmat); 25839223Sgibbs } 25939223Sgibbs case 7: 26039223Sgibbs bus_dmamap_unload(bt->ccb_dmat, bt->ccb_dmamap); 26139223Sgibbs case 6: 26239223Sgibbs bus_dmamem_free(bt->ccb_dmat, bt->bt_ccb_array, 26339223Sgibbs bt->ccb_dmamap); 26439223Sgibbs bus_dmamap_destroy(bt->ccb_dmat, bt->ccb_dmamap); 26539223Sgibbs case 5: 26639223Sgibbs bus_dma_tag_destroy(bt->ccb_dmat); 26739223Sgibbs case 4: 26839223Sgibbs bus_dmamap_unload(bt->mailbox_dmat, bt->mailbox_dmamap); 26939223Sgibbs case 3: 27039223Sgibbs bus_dmamem_free(bt->mailbox_dmat, bt->in_boxes, 27139223Sgibbs bt->mailbox_dmamap); 27239223Sgibbs bus_dmamap_destroy(bt->mailbox_dmat, bt->mailbox_dmamap); 27339223Sgibbs case 2: 27439223Sgibbs bus_dma_tag_destroy(bt->buffer_dmat); 27539223Sgibbs case 1: 27639223Sgibbs bus_dma_tag_destroy(bt->mailbox_dmat); 27739223Sgibbs case 0: 27839223Sgibbs break; 27939223Sgibbs } 28039223Sgibbs if (bt->unit != BT_TEMP_UNIT) { 28139223Sgibbs bt_softcs[bt->unit] = NULL; 28239223Sgibbs } 28339223Sgibbs free(bt, M_DEVBUF); 28439223Sgibbs} 28539223Sgibbs 28639223Sgibbs/* 28739223Sgibbs * Probe the adapter and verify that the card is a BusLogic. 28839223Sgibbs */ 28939223Sgibbsint 29039223Sgibbsbt_probe(struct bt_softc* bt) 29139223Sgibbs{ 29239223Sgibbs esetup_info_data_t esetup_info; 29339223Sgibbs u_int status; 29439223Sgibbs u_int intstat; 29539223Sgibbs u_int geometry; 29639223Sgibbs int error; 29739223Sgibbs u_int8_t param; 29839223Sgibbs 29939223Sgibbs /* 30039223Sgibbs * See if the three I/O ports look reasonable. 30139223Sgibbs * Touch the minimal number of registers in the 30239223Sgibbs * failure case. 30339223Sgibbs */ 30439223Sgibbs status = bt_inb(bt, STATUS_REG); 30539223Sgibbs if ((status == 0) 30639223Sgibbs || (status & (DIAG_ACTIVE|CMD_REG_BUSY| 30739223Sgibbs STATUS_REG_RSVD|CMD_INVALID)) != 0) { 30839223Sgibbs if (bootverbose) 30939223Sgibbs printf("%s: Failed Status Reg Test - %x\n", bt_name(bt), 31039223Sgibbs status); 31139223Sgibbs return (ENXIO); 31239223Sgibbs } 31339223Sgibbs 31439223Sgibbs intstat = bt_inb(bt, INTSTAT_REG); 31539223Sgibbs if ((intstat & INTSTAT_REG_RSVD) != 0) { 31639223Sgibbs printf("%s: Failed Intstat Reg Test\n", bt_name(bt)); 31739223Sgibbs return (ENXIO); 31839223Sgibbs } 31939223Sgibbs 32039223Sgibbs geometry = bt_inb(bt, GEOMETRY_REG); 32139223Sgibbs if (geometry == 0xFF) { 32239223Sgibbs if (bootverbose) 32339223Sgibbs printf("%s: Failed Geometry Reg Test\n", bt_name(bt)); 32439223Sgibbs return (ENXIO); 32539223Sgibbs } 32639223Sgibbs 32739223Sgibbs /* 32839223Sgibbs * Looking good so far. Final test is to reset the 32939223Sgibbs * adapter and attempt to fetch the extended setup 33039223Sgibbs * information. This should filter out all 1542 cards. 33139223Sgibbs */ 33239223Sgibbs if ((error = btreset(bt, /*hard_reset*/TRUE)) != 0) { 33339223Sgibbs if (bootverbose) 33439223Sgibbs printf("%s: Failed Reset\n", bt_name(bt)); 33539223Sgibbs return (ENXIO); 33639223Sgibbs } 33739223Sgibbs 33839223Sgibbs param = sizeof(esetup_info); 33939223Sgibbs error = bt_cmd(bt, BOP_INQUIRE_ESETUP_INFO, ¶m, /*parmlen*/1, 34039223Sgibbs (u_int8_t*)&esetup_info, sizeof(esetup_info), 34139223Sgibbs DEFAULT_CMD_TIMEOUT); 34239223Sgibbs if (error != 0) { 34339223Sgibbs return (ENXIO); 34439223Sgibbs } 34539223Sgibbs 34639223Sgibbs return (0); 34739223Sgibbs} 34839223Sgibbs 34939223Sgibbs/* 35039223Sgibbs * Pull the boards setup information and record it in our softc. 35139223Sgibbs */ 35239223Sgibbsint 35339223Sgibbsbt_fetch_adapter_info(struct bt_softc *bt) 35439223Sgibbs{ 35539223Sgibbs board_id_data_t board_id; 35639223Sgibbs esetup_info_data_t esetup_info; 35739223Sgibbs config_data_t config_data; 35839223Sgibbs int error; 35939223Sgibbs u_int8_t length_param; 36039223Sgibbs 36139223Sgibbs /* First record the firmware version */ 36239223Sgibbs error = bt_cmd(bt, BOP_INQUIRE_BOARD_ID, NULL, /*parmlen*/0, 36339223Sgibbs (u_int8_t*)&board_id, sizeof(board_id), 36439223Sgibbs DEFAULT_CMD_TIMEOUT); 36539223Sgibbs if (error != 0) { 36639223Sgibbs printf("%s: bt_fetch_adapter_info - Failed Get Board Info\n", 36739223Sgibbs bt_name(bt)); 36839223Sgibbs return (error); 36939223Sgibbs } 37039223Sgibbs bt->firmware_ver[0] = board_id.firmware_rev_major; 37139223Sgibbs bt->firmware_ver[1] = '.'; 37239223Sgibbs bt->firmware_ver[2] = board_id.firmware_rev_minor; 37339223Sgibbs bt->firmware_ver[3] = '\0'; 37439223Sgibbs 37539223Sgibbs /* 37639223Sgibbs * Depending on the firmware major and minor version, 37739223Sgibbs * we may be able to fetch additional minor version info. 37839223Sgibbs */ 37939223Sgibbs if (bt->firmware_ver[0] > '0') { 38039223Sgibbs 38139223Sgibbs error = bt_cmd(bt, BOP_INQUIRE_FW_VER_3DIG, NULL, /*parmlen*/0, 38239223Sgibbs (u_int8_t*)&bt->firmware_ver[3], 1, 38339223Sgibbs DEFAULT_CMD_TIMEOUT); 38439223Sgibbs if (error != 0) { 38539223Sgibbs printf("%s: bt_fetch_adapter_info - Failed Get " 38639223Sgibbs "Firmware 3rd Digit\n", bt_name(bt)); 38739223Sgibbs return (error); 38839223Sgibbs } 38939223Sgibbs if (bt->firmware_ver[3] == ' ') 39039223Sgibbs bt->firmware_ver[3] = '\0'; 39139223Sgibbs bt->firmware_ver[4] = '\0'; 39239223Sgibbs } 39339223Sgibbs 39439223Sgibbs if (strcmp(bt->firmware_ver, "3.3") >= 0) { 39539223Sgibbs 39639223Sgibbs error = bt_cmd(bt, BOP_INQUIRE_FW_VER_4DIG, NULL, /*parmlen*/0, 39739223Sgibbs (u_int8_t*)&bt->firmware_ver[4], 1, 39839223Sgibbs DEFAULT_CMD_TIMEOUT); 39939223Sgibbs if (error != 0) { 40039223Sgibbs printf("%s: bt_fetch_adapter_info - Failed Get " 40139223Sgibbs "Firmware 4th Digit\n", bt_name(bt)); 40239223Sgibbs return (error); 40339223Sgibbs } 40439223Sgibbs if (bt->firmware_ver[4] == ' ') 40539223Sgibbs bt->firmware_ver[4] = '\0'; 40639223Sgibbs bt->firmware_ver[5] = '\0'; 40739223Sgibbs } 40839223Sgibbs 40939223Sgibbs /* 41039223Sgibbs * Some boards do not handle the "recently documented" 41139223Sgibbs * Inquire Board Model Number command correctly or do not give 41239223Sgibbs * exact information. Use the Firmware and Extended Setup 41339223Sgibbs * information in these cases to come up with the right answer. 41439223Sgibbs * The major firmware revision number indicates: 41539223Sgibbs * 41639223Sgibbs * 5.xx BusLogic "W" Series Host Adapters: 41739223Sgibbs * BT-948/958/958D 41839223Sgibbs * 4.xx BusLogic "C" Series Host Adapters: 41939223Sgibbs * BT-946C/956C/956CD/747C/757C/757CD/445C/545C/540CF 42039223Sgibbs * 3.xx BusLogic "S" Series Host Adapters: 42139223Sgibbs * BT-747S/747D/757S/757D/445S/545S/542D 42239223Sgibbs * BT-542B/742A (revision H) 42339223Sgibbs * 2.xx BusLogic "A" Series Host Adapters: 42439223Sgibbs * BT-542B/742A (revision G and below) 42539223Sgibbs * 0.xx AMI FastDisk VLB/EISA BusLogic Clone Host Adapter 42639223Sgibbs */ 42739223Sgibbs length_param = sizeof(esetup_info); 42839223Sgibbs error = bt_cmd(bt, BOP_INQUIRE_ESETUP_INFO, &length_param, /*parmlen*/1, 42939223Sgibbs (u_int8_t*)&esetup_info, sizeof(esetup_info), 43039223Sgibbs DEFAULT_CMD_TIMEOUT); 43139223Sgibbs if (error != 0) { 43239223Sgibbs return (error); 43339223Sgibbs } 43439223Sgibbs 43539223Sgibbs bt->bios_addr = esetup_info.bios_addr << 12; 43639223Sgibbs 43739223Sgibbs if (esetup_info.bus_type == 'A' 43839223Sgibbs && bt->firmware_ver[0] == '2') { 43939223Sgibbs strcpy(bt->model, "542B"); 44039223Sgibbs } else if (esetup_info.bus_type == 'E' 44139223Sgibbs && (strncmp(bt->firmware_ver, "2.1", 3) == 0 44239223Sgibbs || strncmp(bt->firmware_ver, "2.20", 4) == 0)) { 44339223Sgibbs strcpy(bt->model, "742A"); 44439223Sgibbs } else if (esetup_info.bus_type == 'E' 44539223Sgibbs && bt->firmware_ver[0] == '0') { 44639223Sgibbs /* AMI FastDisk EISA Series 441 0.x */ 44739223Sgibbs strcpy(bt->model, "747A"); 44839223Sgibbs } else { 44939223Sgibbs ha_model_data_t model_data; 45039223Sgibbs int i; 45139223Sgibbs 45239223Sgibbs length_param = sizeof(model_data); 45339223Sgibbs error = bt_cmd(bt, BOP_INQUIRE_MODEL, &length_param, 1, 45439223Sgibbs (u_int8_t*)&model_data, sizeof(model_data), 45539223Sgibbs DEFAULT_CMD_TIMEOUT); 45639223Sgibbs if (error != 0) { 45739223Sgibbs printf("%s: bt_fetch_adapter_info - Failed Inquire " 45839223Sgibbs "Model Number\n", bt_name(bt)); 45939223Sgibbs return (error); 46039223Sgibbs } 46139223Sgibbs for (i = 0; i < sizeof(model_data.ascii_model); i++) { 46239223Sgibbs bt->model[i] = model_data.ascii_model[i]; 46339223Sgibbs if (bt->model[i] == ' ') 46439223Sgibbs break; 46539223Sgibbs } 46639223Sgibbs bt->model[i] = '\0'; 46739223Sgibbs } 46839223Sgibbs 46939223Sgibbs /* SG element limits */ 47039223Sgibbs bt->max_sg = esetup_info.max_sg; 47139223Sgibbs 47239223Sgibbs /* Set feature flags */ 47339223Sgibbs bt->wide_bus = esetup_info.wide_bus; 47439223Sgibbs bt->diff_bus = esetup_info.diff_bus; 47539223Sgibbs bt->ultra_scsi = esetup_info.ultra_scsi; 47639223Sgibbs 47739223Sgibbs if ((bt->firmware_ver[0] == '5') 47839223Sgibbs || (bt->firmware_ver[0] == '4' && bt->wide_bus)) 47939223Sgibbs bt->extended_lun = TRUE; 48039223Sgibbs 48139223Sgibbs bt->strict_rr = (strcmp(bt->firmware_ver, "3.31") >= 0); 48239223Sgibbs 48339223Sgibbs bt->extended_trans = 48439223Sgibbs ((bt_inb(bt, GEOMETRY_REG) & EXTENDED_TRANSLATION) != 0); 48539223Sgibbs 48639223Sgibbs /* 48739223Sgibbs * Determine max CCB count and whether tagged queuing is 48839223Sgibbs * available based on controller type. Tagged queuing 48939223Sgibbs * only works on 'W' series adapters, 'C' series adapters 49039223Sgibbs * with firmware of rev 4.42 and higher, and 'S' series 49139223Sgibbs * adapters with firmware of rev 3.35 and higher. The 49239223Sgibbs * maximum CCB counts are as follows: 49339223Sgibbs * 49439223Sgibbs * 192 BT-948/958/958D 49539223Sgibbs * 100 BT-946C/956C/956CD/747C/757C/757CD/445C 49639223Sgibbs * 50 BT-545C/540CF 49739223Sgibbs * 30 BT-747S/747D/757S/757D/445S/545S/542D/542B/742A 49839223Sgibbs */ 49939223Sgibbs if (bt->firmware_ver[0] == '5') { 50039223Sgibbs bt->max_ccbs = 192; 50139223Sgibbs bt->tag_capable = TRUE; 50239223Sgibbs } else if (bt->firmware_ver[0] == '4') { 50339223Sgibbs if (bt->model[0] == '5') 50439223Sgibbs bt->max_ccbs = 50; 50539223Sgibbs else 50639223Sgibbs bt->max_ccbs = 100; 50739223Sgibbs bt->tag_capable = (strcmp(bt->firmware_ver, "4.22") >= 0); 50839223Sgibbs } else { 50939223Sgibbs bt->max_ccbs = 30; 51039223Sgibbs if (bt->firmware_ver[0] == '3' 51139223Sgibbs && (strcmp(bt->firmware_ver, "3.35") >= 0)) 51239223Sgibbs bt->tag_capable = TRUE; 51339223Sgibbs else 51439223Sgibbs bt->tag_capable = FALSE; 51539223Sgibbs } 51639223Sgibbs 51739223Sgibbs if (bt->tag_capable != FALSE) 51839223Sgibbs bt->tags_permitted = ALL_TARGETS; 51939223Sgibbs 52039223Sgibbs /* Determine Sync/Wide/Disc settings */ 52139223Sgibbs if (bt->firmware_ver[0] >= '4') { 52239223Sgibbs auto_scsi_data_t auto_scsi_data; 52339223Sgibbs fetch_lram_params_t fetch_lram_params; 52439223Sgibbs int error; 52539223Sgibbs 52639223Sgibbs /* 52739223Sgibbs * These settings are stored in the 52839223Sgibbs * AutoSCSI data in LRAM of 'W' and 'C' 52939223Sgibbs * adapters. 53039223Sgibbs */ 53139223Sgibbs fetch_lram_params.offset = AUTO_SCSI_BYTE_OFFSET; 53239223Sgibbs fetch_lram_params.response_len = sizeof(auto_scsi_data); 53339223Sgibbs error = bt_cmd(bt, BOP_FETCH_LRAM, 53439223Sgibbs (u_int8_t*)&fetch_lram_params, 53539223Sgibbs sizeof(fetch_lram_params), 53639223Sgibbs (u_int8_t*)&auto_scsi_data, 53739223Sgibbs sizeof(auto_scsi_data), DEFAULT_CMD_TIMEOUT); 53839223Sgibbs 53939223Sgibbs if (error != 0) { 54039223Sgibbs printf("%s: bt_fetch_adapter_info - Failed " 54139223Sgibbs "Get Auto SCSI Info\n", bt_name(bt)); 54239223Sgibbs return (error); 54339223Sgibbs } 54439223Sgibbs 54539223Sgibbs bt->disc_permitted = auto_scsi_data.low_disc_permitted 54639223Sgibbs | (auto_scsi_data.high_disc_permitted << 8); 54739223Sgibbs bt->sync_permitted = auto_scsi_data.low_sync_permitted 54839223Sgibbs | (auto_scsi_data.high_sync_permitted << 8); 54939223Sgibbs bt->fast_permitted = auto_scsi_data.low_fast_permitted 55039223Sgibbs | (auto_scsi_data.high_fast_permitted << 8); 55139223Sgibbs bt->ultra_permitted = auto_scsi_data.low_ultra_permitted 55239223Sgibbs | (auto_scsi_data.high_ultra_permitted << 8); 55339223Sgibbs bt->wide_permitted = auto_scsi_data.low_wide_permitted 55439223Sgibbs | (auto_scsi_data.high_wide_permitted << 8); 55539223Sgibbs 55639223Sgibbs if (bt->ultra_scsi == FALSE) 55739223Sgibbs bt->ultra_permitted = 0; 55839223Sgibbs 55939223Sgibbs if (bt->wide_bus == FALSE) 56039223Sgibbs bt->wide_permitted = 0; 56139223Sgibbs } else { 56239223Sgibbs /* 56339223Sgibbs * 'S' and 'A' series have this information in the setup 56439223Sgibbs * information structure. 56539223Sgibbs */ 56639223Sgibbs setup_data_t setup_info; 56739223Sgibbs 56839223Sgibbs length_param = sizeof(setup_info); 56939223Sgibbs error = bt_cmd(bt, BOP_INQUIRE_SETUP_INFO, &length_param, 57039223Sgibbs /*paramlen*/1, (u_int8_t*)&setup_info, 57139223Sgibbs sizeof(setup_info), DEFAULT_CMD_TIMEOUT); 57239223Sgibbs 57339223Sgibbs if (error != 0) { 57439223Sgibbs printf("%s: bt_fetch_adapter_info - Failed " 57539223Sgibbs "Get Setup Info\n", bt_name(bt)); 57639223Sgibbs return (error); 57739223Sgibbs } 57839223Sgibbs 57939223Sgibbs if (setup_info.initiate_sync != 0) { 58039223Sgibbs bt->sync_permitted = ALL_TARGETS; 58139223Sgibbs 58239223Sgibbs if (bt->model[0] == '7') { 58339223Sgibbs if (esetup_info.sync_neg10MB != 0) 58439223Sgibbs bt->fast_permitted = ALL_TARGETS; 58539223Sgibbs if (strcmp(bt->model, "757") == 0) 58639223Sgibbs bt->wide_permitted = ALL_TARGETS; 58739223Sgibbs } 58839223Sgibbs } 58939223Sgibbs bt->disc_permitted = ALL_TARGETS; 59039223Sgibbs } 59139223Sgibbs 59239223Sgibbs /* We need as many mailboxes as we can have ccbs */ 59339223Sgibbs bt->num_boxes = bt->max_ccbs; 59439223Sgibbs 59539223Sgibbs /* Determine our SCSI ID */ 59639223Sgibbs 59739223Sgibbs error = bt_cmd(bt, BOP_INQUIRE_CONFIG, NULL, /*parmlen*/0, 59839223Sgibbs (u_int8_t*)&config_data, sizeof(config_data), 59939223Sgibbs DEFAULT_CMD_TIMEOUT); 60039223Sgibbs if (error != 0) { 60139223Sgibbs printf("%s: bt_fetch_adapter_info - Failed Get Config\n", 60239223Sgibbs bt_name(bt)); 60339223Sgibbs return (error); 60439223Sgibbs } 60539223Sgibbs bt->scsi_id = config_data.scsi_id; 60639223Sgibbs 60739223Sgibbs return (0); 60839223Sgibbs} 60939223Sgibbs 61039223Sgibbs/* 61139223Sgibbs * Start the board, ready for normal operation 61239223Sgibbs */ 61339223Sgibbsint 61439223Sgibbsbt_init(struct bt_softc* bt) 61539223Sgibbs{ 61639223Sgibbs /* Announce the Adapter */ 61739223Sgibbs printf("%s: BT-%s FW Rev. %s ", bt_name(bt), 61839223Sgibbs bt->model, bt->firmware_ver); 61939223Sgibbs 62039223Sgibbs if (bt->ultra_scsi != 0) 62139223Sgibbs printf("Ultra "); 62239223Sgibbs 62339223Sgibbs if (bt->wide_bus != 0) 62439223Sgibbs printf("Wide "); 62539223Sgibbs else 62639223Sgibbs printf("Narrow "); 62739223Sgibbs 62839223Sgibbs if (bt->diff_bus != 0) 62939223Sgibbs printf("Diff "); 63039223Sgibbs 63139223Sgibbs printf("SCSI Host Adapter, SCSI ID %d, %d CCBs\n", bt->scsi_id, 63239223Sgibbs bt->max_ccbs); 63339223Sgibbs 63439223Sgibbs /* 63539223Sgibbs * Create our DMA tags. These tags define the kinds of device 63639223Sgibbs * accessable memory allocations and memory mappings we will 63739223Sgibbs * need to perform during normal operation. 63839223Sgibbs * 63939223Sgibbs * Unless we need to further restrict the allocation, we rely 64039223Sgibbs * on the restrictions of the parent dmat, hence the common 64139223Sgibbs * use of MAXADDR and MAXSIZE. 64239223Sgibbs */ 64339223Sgibbs 64439223Sgibbs /* DMA tag for mapping buffers into device visible space. */ 64539223Sgibbs if (bus_dma_tag_create(bt->parent_dmat, /*alignment*/0, /*boundary*/0, 64639223Sgibbs /*lowaddr*/BUS_SPACE_MAXADDR, 64739223Sgibbs /*highaddr*/BUS_SPACE_MAXADDR, 64839223Sgibbs /*filter*/NULL, /*filterarg*/NULL, 64939223Sgibbs /*maxsize*/MAXBSIZE, /*nsegments*/BT_NSEG, 65039223Sgibbs /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, 65139223Sgibbs /*flags*/BUS_DMA_ALLOCNOW, 65239223Sgibbs &bt->buffer_dmat) != 0) { 65339223Sgibbs goto error_exit; 65439223Sgibbs } 65539223Sgibbs 65639223Sgibbs bt->init_level++; 65739223Sgibbs /* DMA tag for our mailboxes */ 65839223Sgibbs if (bus_dma_tag_create(bt->parent_dmat, /*alignment*/0, /*boundary*/0, 65939223Sgibbs /*lowaddr*/BUS_SPACE_MAXADDR, 66039223Sgibbs /*highaddr*/BUS_SPACE_MAXADDR, 66139223Sgibbs /*filter*/NULL, /*filterarg*/NULL, 66239223Sgibbs bt->num_boxes * (sizeof(bt_mbox_in_t) 66339223Sgibbs + sizeof(bt_mbox_out_t)), 66439223Sgibbs /*nsegments*/1, 66539223Sgibbs /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, 66639223Sgibbs /*flags*/0, &bt->mailbox_dmat) != 0) { 66739223Sgibbs goto error_exit; 66839223Sgibbs } 66939223Sgibbs 67039223Sgibbs bt->init_level++; 67139223Sgibbs 67239223Sgibbs /* Allocation for our mailboxes */ 67339223Sgibbs if (bus_dmamem_alloc(bt->mailbox_dmat, (void **)&bt->out_boxes, 67439223Sgibbs BUS_DMA_NOWAIT, &bt->mailbox_dmamap) != 0) { 67539223Sgibbs goto error_exit; 67639223Sgibbs } 67739223Sgibbs 67839223Sgibbs bt->init_level++; 67939223Sgibbs 68039223Sgibbs /* And permanently map them */ 68139223Sgibbs bus_dmamap_load(bt->mailbox_dmat, bt->mailbox_dmamap, 68239223Sgibbs bt->out_boxes, 68339223Sgibbs bt->num_boxes * (sizeof(bt_mbox_in_t) 68439223Sgibbs + sizeof(bt_mbox_out_t)), 68539223Sgibbs btmapmboxes, bt, /*flags*/0); 68639223Sgibbs 68739223Sgibbs bt->init_level++; 68839223Sgibbs 68939223Sgibbs bt->in_boxes = (bt_mbox_in_t *)&bt->out_boxes[bt->num_boxes]; 69039223Sgibbs 69139223Sgibbs btinitmboxes(bt); 69239223Sgibbs 69339223Sgibbs /* DMA tag for our ccb structures */ 69439223Sgibbs if (bus_dma_tag_create(bt->parent_dmat, /*alignment*/0, /*boundary*/0, 69539223Sgibbs /*lowaddr*/BUS_SPACE_MAXADDR, 69639223Sgibbs /*highaddr*/BUS_SPACE_MAXADDR, 69739223Sgibbs /*filter*/NULL, /*filterarg*/NULL, 69839223Sgibbs bt->max_ccbs * sizeof(struct bt_ccb), 69939223Sgibbs /*nsegments*/1, 70039223Sgibbs /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, 70139223Sgibbs /*flags*/0, &bt->ccb_dmat) != 0) { 70239223Sgibbs goto error_exit; 70339223Sgibbs } 70439223Sgibbs 70539223Sgibbs bt->init_level++; 70639223Sgibbs 70739223Sgibbs /* Allocation for our ccbs */ 70839223Sgibbs if (bus_dmamem_alloc(bt->ccb_dmat, (void **)&bt->bt_ccb_array, 70939223Sgibbs BUS_DMA_NOWAIT, &bt->ccb_dmamap) != 0) { 71039223Sgibbs goto error_exit; 71139223Sgibbs } 71239223Sgibbs 71339223Sgibbs bt->init_level++; 71439223Sgibbs 71539223Sgibbs /* And permanently map them */ 71639223Sgibbs bus_dmamap_load(bt->ccb_dmat, bt->ccb_dmamap, 71739223Sgibbs bt->bt_ccb_array, 71839223Sgibbs bt->max_ccbs * sizeof(struct bt_ccb), 71939223Sgibbs btmapccbs, bt, /*flags*/0); 72039223Sgibbs 72139223Sgibbs bt->init_level++; 72239223Sgibbs 72339223Sgibbs /* DMA tag for our S/G structures. We allocate in page sized chunks */ 72439223Sgibbs if (bus_dma_tag_create(bt->parent_dmat, /*alignment*/0, /*boundary*/0, 72539223Sgibbs /*lowaddr*/BUS_SPACE_MAXADDR, 72639223Sgibbs /*highaddr*/BUS_SPACE_MAXADDR, 72739223Sgibbs /*filter*/NULL, /*filterarg*/NULL, 72839223Sgibbs PAGE_SIZE, /*nsegments*/1, 72939223Sgibbs /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, 73039223Sgibbs /*flags*/0, &bt->sg_dmat) != 0) { 73139223Sgibbs goto error_exit; 73239223Sgibbs } 73339223Sgibbs 73439223Sgibbs bt->init_level++; 73539223Sgibbs 73639223Sgibbs /* Perform initial CCB allocation */ 73739223Sgibbs bzero(bt->bt_ccb_array, bt->max_ccbs * sizeof(struct bt_ccb)); 73839223Sgibbs btallocccbs(bt); 73939223Sgibbs 74039223Sgibbs if (bt->num_ccbs == 0) { 74139324Sgibbs printf("%s: bt_init - Unable to allocate initial ccbs\n", 74239324Sgibbs bt_name(bt)); 74339223Sgibbs goto error_exit; 74439223Sgibbs } 74539223Sgibbs 74639223Sgibbs /* 74739223Sgibbs * Note that we are going and return (to probe) 74839223Sgibbs */ 74939223Sgibbs return 0; 75039223Sgibbs 75139223Sgibbserror_exit: 75239223Sgibbs 75339223Sgibbs return (ENXIO); 75439223Sgibbs} 75539223Sgibbs 75639223Sgibbsint 75739223Sgibbsbt_attach(struct bt_softc *bt) 75839223Sgibbs{ 75939223Sgibbs int tagged_dev_openings; 76039223Sgibbs struct cam_devq *devq; 76139223Sgibbs 76239223Sgibbs /* 76339223Sgibbs * We reserve 1 ccb for error recovery, so don't 76439223Sgibbs * tell the XPT about it. 76539223Sgibbs */ 76639223Sgibbs if (bt->tag_capable != 0) 76739223Sgibbs tagged_dev_openings = bt->max_ccbs - 1; 76839223Sgibbs else 76939223Sgibbs tagged_dev_openings = 0; 77039223Sgibbs 77139223Sgibbs /* 77239223Sgibbs * Create the device queue for our SIM. 77339223Sgibbs */ 77439223Sgibbs devq = cam_simq_alloc(bt->max_ccbs - 1); 77539223Sgibbs if (devq == NULL) 77639223Sgibbs return (ENOMEM); 77739223Sgibbs 77839223Sgibbs /* 77939223Sgibbs * Construct our SIM entry 78039223Sgibbs */ 78139223Sgibbs bt->sim = cam_sim_alloc(btaction, btpoll, "bt", bt, bt->unit, 78239223Sgibbs 2, tagged_dev_openings, devq); 78339223Sgibbs if (bt->sim == NULL) { 78439223Sgibbs cam_simq_free(devq); 78539223Sgibbs return (ENOMEM); 78639223Sgibbs } 78739223Sgibbs 78839223Sgibbs if (xpt_bus_register(bt->sim, 0) != CAM_SUCCESS) { 78939223Sgibbs cam_sim_free(bt->sim, /*free_devq*/TRUE); 79039223Sgibbs return (ENXIO); 79139223Sgibbs } 79239223Sgibbs 79339223Sgibbs if (xpt_create_path(&bt->path, /*periph*/NULL, 79439223Sgibbs cam_sim_path(bt->sim), CAM_TARGET_WILDCARD, 79539223Sgibbs CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 79639223Sgibbs xpt_bus_deregister(cam_sim_path(bt->sim)); 79739223Sgibbs cam_sim_free(bt->sim, /*free_devq*/TRUE); 79839223Sgibbs return (ENXIO); 79939223Sgibbs } 80039223Sgibbs 80139223Sgibbs return (0); 80239223Sgibbs} 80339223Sgibbs 80439223Sgibbschar * 80539223Sgibbsbt_name(struct bt_softc *bt) 80639223Sgibbs{ 80739223Sgibbs static char name[10]; 80839223Sgibbs 80939223Sgibbs sprintf(name, "bt%d", bt->unit); 81039223Sgibbs return (name); 81139223Sgibbs} 81239223Sgibbs 81339223Sgibbsint 81439223Sgibbsbt_check_probed_iop(u_int ioport) 81539223Sgibbs{ 81639223Sgibbs u_int i; 81739223Sgibbs 81839223Sgibbs for (i=0; i < BT_NUM_ISAPORTS; i++) { 81939223Sgibbs if (bt_isa_ports[i].addr == ioport) { 82039223Sgibbs if (bt_isa_ports[i].probed != 0) 82139223Sgibbs return (1); 82239223Sgibbs else { 82339223Sgibbs return (0); 82439223Sgibbs } 82539223Sgibbs } 82639223Sgibbs } 82739223Sgibbs return (1); 82839223Sgibbs} 82939223Sgibbs 83039223Sgibbsvoid 83139223Sgibbsbt_mark_probed_bio(isa_compat_io_t port) 83239223Sgibbs{ 83339223Sgibbs if (port < BIO_DISABLED) 83439223Sgibbs bt_isa_ports[port].probed = 1; 83539223Sgibbs} 83639223Sgibbs 83739223Sgibbsvoid 83839223Sgibbsbt_mark_probed_iop(u_int ioport) 83939223Sgibbs{ 84039223Sgibbs u_int i; 84139223Sgibbs 84239223Sgibbs for (i = 0; i < BT_NUM_ISAPORTS; i++) { 84339223Sgibbs if (ioport == bt_isa_ports[i].addr) { 84439223Sgibbs bt_isa_ports[i].probed = 1; 84539223Sgibbs break; 84639223Sgibbs } 84739223Sgibbs } 84839223Sgibbs} 84939223Sgibbs 85039223Sgibbsstatic void 85139223Sgibbsbtallocccbs(struct bt_softc *bt) 85239223Sgibbs{ 85339223Sgibbs struct bt_ccb *next_ccb; 85439223Sgibbs struct sg_map_node *sg_map; 85539223Sgibbs bus_addr_t physaddr; 85639223Sgibbs bt_sg_t *segs; 85739223Sgibbs int newcount; 85839223Sgibbs int i; 85939223Sgibbs 86039223Sgibbs next_ccb = &bt->bt_ccb_array[bt->num_ccbs]; 86139223Sgibbs 86239223Sgibbs sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT); 86339223Sgibbs 86439223Sgibbs if (sg_map == NULL) 86539223Sgibbs return; 86639223Sgibbs 86739223Sgibbs /* Allocate S/G space for the next batch of CCBS */ 86839223Sgibbs if (bus_dmamem_alloc(bt->sg_dmat, (void **)&sg_map->sg_vaddr, 86939223Sgibbs BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) { 87039223Sgibbs free(sg_map, M_DEVBUF); 87139223Sgibbs return; 87239223Sgibbs } 87339223Sgibbs 87439223Sgibbs SLIST_INSERT_HEAD(&bt->sg_maps, sg_map, links); 87539223Sgibbs 87639223Sgibbs bus_dmamap_load(bt->sg_dmat, sg_map->sg_dmamap, sg_map->sg_vaddr, 87739223Sgibbs PAGE_SIZE, btmapsgs, bt, /*flags*/0); 87839223Sgibbs 87939223Sgibbs segs = sg_map->sg_vaddr; 88039223Sgibbs physaddr = sg_map->sg_physaddr; 88139223Sgibbs 88239223Sgibbs newcount = (PAGE_SIZE / (BT_NSEG * sizeof(bt_sg_t))); 88339223Sgibbs for (i = 0; bt->num_ccbs < bt->max_ccbs && i < newcount; i++) { 88439223Sgibbs int error; 88539223Sgibbs 88639223Sgibbs next_ccb->sg_list = segs; 88739223Sgibbs next_ccb->sg_list_phys = physaddr; 88839223Sgibbs next_ccb->flags = BCCB_FREE; 88939223Sgibbs error = bus_dmamap_create(bt->buffer_dmat, /*flags*/0, 89039223Sgibbs &next_ccb->dmamap); 89139223Sgibbs if (error != 0) 89239223Sgibbs break; 89339223Sgibbs SLIST_INSERT_HEAD(&bt->free_bt_ccbs, next_ccb, links); 89439223Sgibbs segs += BT_NSEG; 89539223Sgibbs physaddr += (BT_NSEG * sizeof(bt_sg_t)); 89639223Sgibbs next_ccb++; 89739223Sgibbs bt->num_ccbs++; 89839223Sgibbs } 89939223Sgibbs 90039223Sgibbs /* Reserve a CCB for error recovery */ 90139223Sgibbs if (bt->recovery_bccb == NULL) { 90239223Sgibbs bt->recovery_bccb = SLIST_FIRST(&bt->free_bt_ccbs); 90339223Sgibbs SLIST_REMOVE_HEAD(&bt->free_bt_ccbs, links); 90439223Sgibbs } 90539223Sgibbs} 90639223Sgibbs 90739223Sgibbsstatic __inline void 90839223Sgibbsbtfreeccb(struct bt_softc *bt, struct bt_ccb *bccb) 90939223Sgibbs{ 91039223Sgibbs int s; 91139223Sgibbs 91239223Sgibbs s = splcam(); 91339223Sgibbs if ((bccb->flags & BCCB_ACTIVE) != 0) 91439223Sgibbs LIST_REMOVE(&bccb->ccb->ccb_h, sim_links.le); 91539223Sgibbs if (bt->resource_shortage != 0 91639223Sgibbs && (bccb->ccb->ccb_h.status & CAM_RELEASE_SIMQ) == 0) { 91739223Sgibbs bccb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 91839223Sgibbs bt->resource_shortage = FALSE; 91939223Sgibbs } 92039223Sgibbs bccb->flags = BCCB_FREE; 92139223Sgibbs SLIST_INSERT_HEAD(&bt->free_bt_ccbs, bccb, links); 92239223Sgibbs splx(s); 92339223Sgibbs} 92439223Sgibbs 92539223Sgibbsstatic __inline struct bt_ccb* 92639223Sgibbsbtgetccb(struct bt_softc *bt) 92739223Sgibbs{ 92839223Sgibbs struct bt_ccb* bccb; 92939223Sgibbs int s; 93039223Sgibbs 93139223Sgibbs s = splcam(); 93239223Sgibbs if ((bccb = SLIST_FIRST(&bt->free_bt_ccbs)) != NULL) { 93339223Sgibbs SLIST_REMOVE_HEAD(&bt->free_bt_ccbs, links); 93439223Sgibbs } else if (bt->num_ccbs < bt->max_ccbs) { 93539223Sgibbs btallocccbs(bt); 93639223Sgibbs bccb = SLIST_FIRST(&bt->free_bt_ccbs); 93739223Sgibbs if (bccb == NULL) 93839223Sgibbs printf("%s: Can't malloc BCCB\n", bt_name(bt)); 93939223Sgibbs else 94039223Sgibbs SLIST_REMOVE_HEAD(&bt->free_bt_ccbs, links); 94139223Sgibbs } 94239223Sgibbs splx(s); 94339223Sgibbs 94439223Sgibbs return (bccb); 94539223Sgibbs} 94639223Sgibbs 94739223Sgibbsstatic void 94839223Sgibbsbtaction(struct cam_sim *sim, union ccb *ccb) 94939223Sgibbs{ 95039223Sgibbs struct bt_softc *bt; 95139223Sgibbs int s; 95239223Sgibbs 95339223Sgibbs CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("btaction\n")); 95439223Sgibbs 95539223Sgibbs bt = (struct bt_softc *)cam_sim_softc(sim); 95639223Sgibbs 95739223Sgibbs switch (ccb->ccb_h.func_code) { 95839223Sgibbs /* Common cases first */ 95939223Sgibbs case XPT_SCSI_IO: /* Execute the requested I/O operation */ 96039223Sgibbs case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ 96139223Sgibbs { 96239223Sgibbs struct bt_ccb *bccb; 96339223Sgibbs struct bt_hccb *hccb; 96439223Sgibbs u_int16_t targ_mask; 96539223Sgibbs 96639223Sgibbs /* 96739223Sgibbs * get a bccb to use. 96839223Sgibbs */ 96939223Sgibbs if ((bccb = btgetccb(bt)) == NULL) { 97039223Sgibbs int s; 97139223Sgibbs 97239223Sgibbs s = splcam(); 97339223Sgibbs bt->resource_shortage = TRUE; 97439223Sgibbs splx(s); 97539223Sgibbs xpt_freeze_simq(bt->sim, /*count*/1); 97639223Sgibbs ccb->ccb_h.status = CAM_REQUEUE_REQ; 97739223Sgibbs xpt_done(ccb); 97839223Sgibbs return; 97939223Sgibbs } 98039223Sgibbs 98139223Sgibbs hccb = &bccb->hccb; 98239223Sgibbs 98339223Sgibbs /* 98439223Sgibbs * So we can find the BCCB when an abort is requested 98539223Sgibbs */ 98639223Sgibbs bccb->ccb = ccb; 98739223Sgibbs ccb->ccb_h.ccb_bccb_ptr = bccb; 98839223Sgibbs ccb->ccb_h.ccb_bt_ptr = bt; 98939223Sgibbs 99039223Sgibbs /* 99139223Sgibbs * Put all the arguments for the xfer in the bccb 99239223Sgibbs */ 99339223Sgibbs hccb->target_id = ccb->ccb_h.target_id; 99439223Sgibbs hccb->target_lun = ccb->ccb_h.target_lun; 99539223Sgibbs hccb->btstat = 0; 99639223Sgibbs hccb->sdstat = 0; 99739223Sgibbs targ_mask = (0x01 << hccb->target_id); 99839223Sgibbs 99939223Sgibbs if (ccb->ccb_h.func_code == XPT_SCSI_IO) { 100039223Sgibbs struct ccb_scsiio *csio; 100139223Sgibbs struct ccb_hdr *ccbh; 100239223Sgibbs 100339223Sgibbs csio = &ccb->csio; 100439223Sgibbs ccbh = &csio->ccb_h; 100539223Sgibbs hccb->opcode = INITIATOR_CCB_WRESID; 100639223Sgibbs hccb->datain = (ccb->ccb_h.flags & CAM_DIR_IN) != 0; 100739223Sgibbs hccb->dataout = (ccb->ccb_h.flags & CAM_DIR_OUT) != 0; 100839223Sgibbs hccb->cmd_len = csio->cdb_len; 100939223Sgibbs if (hccb->cmd_len > sizeof(hccb->scsi_cdb)) { 101039223Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 101139223Sgibbs btfreeccb(bt, bccb); 101239223Sgibbs xpt_done(ccb); 101339223Sgibbs return; 101439223Sgibbs } 101539223Sgibbs hccb->sense_len = csio->sense_len; 101639223Sgibbs if ((ccbh->flags & CAM_TAG_ACTION_VALID) != 0) { 101739223Sgibbs hccb->tag_enable = TRUE; 101839223Sgibbs hccb->tag_type = (ccb->csio.tag_action & 0x3); 101939223Sgibbs } else { 102039223Sgibbs hccb->tag_enable = FALSE; 102139223Sgibbs hccb->tag_type = 0; 102239223Sgibbs } 102339223Sgibbs if ((ccbh->flags & CAM_CDB_POINTER) != 0) { 102439223Sgibbs if ((ccbh->flags & CAM_CDB_PHYS) == 0) { 102539223Sgibbs bcopy(csio->cdb_io.cdb_ptr, 102639223Sgibbs hccb->scsi_cdb, hccb->cmd_len); 102739223Sgibbs } else { 102839223Sgibbs /* I guess I could map it in... */ 102939223Sgibbs ccbh->status = CAM_REQ_INVALID; 103039223Sgibbs btfreeccb(bt, bccb); 103139223Sgibbs xpt_done(ccb); 103239223Sgibbs return; 103339223Sgibbs } 103439223Sgibbs } else { 103539223Sgibbs bcopy(csio->cdb_io.cdb_bytes, 103639223Sgibbs hccb->scsi_cdb, hccb->cmd_len); 103739223Sgibbs } 103839223Sgibbs /* If need be, bounce our sense buffer */ 103939223Sgibbs if (bt->sense_buffers != NULL) { 104039223Sgibbs hccb->sense_addr = btsensepaddr(bt, bccb); 104139223Sgibbs } else { 104239223Sgibbs hccb->sense_addr = vtophys(&csio->sense_data); 104339223Sgibbs } 104439223Sgibbs /* 104539223Sgibbs * If we have any data to send with this command, 104639223Sgibbs * map it into bus space. 104739223Sgibbs */ 104839223Sgibbs /* Only use S/G if there is a transfer */ 104939223Sgibbs if ((ccbh->flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 105039223Sgibbs if ((ccbh->flags & CAM_SCATTER_VALID) == 0) { 105139223Sgibbs /* 105239223Sgibbs * We've been given a pointer 105339223Sgibbs * to a single buffer. 105439223Sgibbs */ 105539223Sgibbs if ((ccbh->flags & CAM_DATA_PHYS)==0) { 105639223Sgibbs int s; 105739223Sgibbs int error; 105839223Sgibbs 105939223Sgibbs s = splsoftvm(); 106039223Sgibbs error = bus_dmamap_load( 106139223Sgibbs bt->buffer_dmat, 106239223Sgibbs bccb->dmamap, 106339223Sgibbs csio->data_ptr, 106439223Sgibbs csio->dxfer_len, 106539223Sgibbs btexecuteccb, 106639223Sgibbs bccb, 106739223Sgibbs /*flags*/0); 106839223Sgibbs if (error == EINPROGRESS) { 106939223Sgibbs /* 107039223Sgibbs * So as to maintain 107139223Sgibbs * ordering, freeze the 107239223Sgibbs * controller queue 107339223Sgibbs * until our mapping is 107439223Sgibbs * returned. 107539223Sgibbs */ 107639223Sgibbs xpt_freeze_simq(bt->sim, 107739223Sgibbs 1); 107839223Sgibbs csio->ccb_h.status |= 107939223Sgibbs CAM_RELEASE_SIMQ; 108039223Sgibbs } 108139223Sgibbs splx(s); 108239223Sgibbs } else { 108339223Sgibbs struct bus_dma_segment seg; 108439223Sgibbs 108539223Sgibbs /* Pointer to physical buffer */ 108639223Sgibbs seg.ds_addr = 108739223Sgibbs (bus_addr_t)csio->data_ptr; 108839223Sgibbs seg.ds_len = csio->dxfer_len; 108939223Sgibbs btexecuteccb(bccb, &seg, 1, 0); 109039223Sgibbs } 109139223Sgibbs } else { 109239223Sgibbs struct bus_dma_segment *segs; 109339223Sgibbs 109439223Sgibbs if ((ccbh->flags & CAM_DATA_PHYS) != 0) 109539223Sgibbs panic("btaction - Physical " 109639223Sgibbs "segment pointers " 109739223Sgibbs "unsupported"); 109839223Sgibbs 109939223Sgibbs if ((ccbh->flags&CAM_SG_LIST_PHYS)==0) 110039223Sgibbs panic("btaction - Virtual " 110139223Sgibbs "segment addresses " 110239223Sgibbs "unsupported"); 110339223Sgibbs 110439223Sgibbs /* Just use the segments provided */ 110539223Sgibbs segs = (struct bus_dma_segment *) 110639223Sgibbs csio->data_ptr; 110739223Sgibbs btexecuteccb(bccb, segs, 110839223Sgibbs csio->sglist_cnt, 0); 110939223Sgibbs } 111039223Sgibbs } else { 111139223Sgibbs btexecuteccb(bccb, NULL, 0, 0); 111239223Sgibbs } 111339223Sgibbs } else { 111439223Sgibbs hccb->opcode = INITIATOR_BUS_DEV_RESET; 111539223Sgibbs /* No data transfer */ 111639223Sgibbs hccb->datain = TRUE; 111739223Sgibbs hccb->dataout = TRUE; 111839223Sgibbs hccb->cmd_len = 0; 111939223Sgibbs hccb->sense_len = 0; 112039223Sgibbs hccb->tag_enable = FALSE; 112139223Sgibbs hccb->tag_type = 0; 112239223Sgibbs btexecuteccb(bccb, NULL, 0, 0); 112339223Sgibbs } 112439223Sgibbs break; 112539223Sgibbs } 112639223Sgibbs case XPT_EN_LUN: /* Enable LUN as a target */ 112739223Sgibbs case XPT_TARGET_IO: /* Execute target I/O request */ 112839223Sgibbs case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */ 112939223Sgibbs case XPT_CONT_TARGET_IO: /* Continue Host Target I/O Connection*/ 113039223Sgibbs case XPT_ABORT: /* Abort the specified CCB */ 113139223Sgibbs /* XXX Implement */ 113239223Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 113339223Sgibbs xpt_done(ccb); 113439223Sgibbs break; 113539223Sgibbs case XPT_SET_TRAN_SETTINGS: 113639223Sgibbs { 113739223Sgibbs /* XXX Implement */ 113839223Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 113939223Sgibbs xpt_done(ccb); 114039223Sgibbs break; 114139223Sgibbs } 114239223Sgibbs case XPT_GET_TRAN_SETTINGS: 114339223Sgibbs /* Get default/user set transfer settings for the target */ 114439223Sgibbs { 114539223Sgibbs struct ccb_trans_settings *cts; 114639223Sgibbs u_int target_mask; 114739223Sgibbs 114839223Sgibbs cts = &ccb->cts; 114939223Sgibbs target_mask = 0x01 << ccb->ccb_h.target_id; 115039223Sgibbs if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) { 115139223Sgibbs cts->flags = 0; 115239223Sgibbs if ((bt->disc_permitted & target_mask) != 0) 115339223Sgibbs cts->flags |= CCB_TRANS_DISC_ENB; 115439223Sgibbs if ((bt->tags_permitted & target_mask) != 0) 115539223Sgibbs cts->flags |= CCB_TRANS_TAG_ENB; 115639223Sgibbs if ((bt->wide_permitted & target_mask) != 0) 115739223Sgibbs cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 115839223Sgibbs else 115939223Sgibbs cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 116039223Sgibbs if ((bt->ultra_permitted & target_mask) != 0) 116139223Sgibbs cts->sync_period = 12; 116239223Sgibbs else if ((bt->fast_permitted & target_mask) != 0) 116339223Sgibbs cts->sync_period = 25; 116439223Sgibbs else if ((bt->sync_permitted & target_mask) != 0) 116539223Sgibbs cts->sync_period = 50; 116639223Sgibbs else 116739223Sgibbs cts->sync_period = 0; 116839223Sgibbs 116939223Sgibbs if (cts->sync_period != 0) 117039223Sgibbs cts->sync_offset = 15; 117139223Sgibbs 117239223Sgibbs cts->valid = CCB_TRANS_SYNC_RATE_VALID 117339223Sgibbs | CCB_TRANS_SYNC_OFFSET_VALID 117439223Sgibbs | CCB_TRANS_BUS_WIDTH_VALID 117539223Sgibbs | CCB_TRANS_DISC_VALID 117639223Sgibbs | CCB_TRANS_TQ_VALID; 117739223Sgibbs } else { 117839223Sgibbs btfetchtransinfo(bt, cts); 117939223Sgibbs } 118039223Sgibbs 118139223Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 118239223Sgibbs xpt_done(ccb); 118339223Sgibbs break; 118439223Sgibbs } 118539223Sgibbs case XPT_CALC_GEOMETRY: 118639223Sgibbs { 118739223Sgibbs struct ccb_calc_geometry *ccg; 118839223Sgibbs u_int32_t size_mb; 118939223Sgibbs u_int32_t secs_per_cylinder; 119039223Sgibbs 119139223Sgibbs ccg = &ccb->ccg; 119239223Sgibbs size_mb = ccg->volume_size 119339223Sgibbs / ((1024L * 1024L) / ccg->block_size); 119439223Sgibbs 119539223Sgibbs if (size_mb >= 1024 && (bt->extended_trans != 0)) { 119639223Sgibbs if (size_mb >= 2048) { 119739223Sgibbs ccg->heads = 255; 119839223Sgibbs ccg->secs_per_track = 63; 119939223Sgibbs } else { 120039223Sgibbs ccg->heads = 128; 120139223Sgibbs ccg->secs_per_track = 32; 120239223Sgibbs } 120339223Sgibbs } else { 120439223Sgibbs ccg->heads = 64; 120539223Sgibbs ccg->secs_per_track = 32; 120639223Sgibbs } 120739223Sgibbs secs_per_cylinder = ccg->heads * ccg->secs_per_track; 120839223Sgibbs ccg->cylinders = ccg->volume_size / secs_per_cylinder; 120939223Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 121039223Sgibbs xpt_done(ccb); 121139223Sgibbs break; 121239223Sgibbs } 121339223Sgibbs case XPT_RESET_BUS: /* Reset the specified SCSI bus */ 121439223Sgibbs { 121539223Sgibbs btreset(bt, /*hardreset*/TRUE); 121639223Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 121739223Sgibbs xpt_done(ccb); 121839223Sgibbs break; 121939223Sgibbs } 122039223Sgibbs case XPT_TERM_IO: /* Terminate the I/O process */ 122139223Sgibbs /* XXX Implement */ 122239223Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 122339223Sgibbs xpt_done(ccb); 122439223Sgibbs break; 122539223Sgibbs case XPT_PATH_INQ: /* Path routing inquiry */ 122639223Sgibbs { 122739223Sgibbs struct ccb_pathinq *cpi = &ccb->cpi; 122839223Sgibbs 122939223Sgibbs cpi->version_num = 1; /* XXX??? */ 123039223Sgibbs cpi->hba_inquiry = PI_SDTR_ABLE; 123139223Sgibbs if (bt->tag_capable != 0) 123239223Sgibbs cpi->hba_inquiry |= PI_TAG_ABLE; 123339223Sgibbs if (bt->wide_bus != 0) 123439223Sgibbs cpi->hba_inquiry |= PI_WIDE_16; 123539223Sgibbs cpi->target_sprt = 0; 123639223Sgibbs cpi->hba_misc = 0; 123739223Sgibbs cpi->hba_eng_cnt = 0; 123839223Sgibbs cpi->max_target = bt->wide_bus ? 15 : 7; 123939223Sgibbs cpi->max_lun = 7; 124039223Sgibbs cpi->initiator_id = bt->scsi_id; 124139223Sgibbs cpi->bus_id = cam_sim_bus(sim); 124239223Sgibbs strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 124339223Sgibbs strncpy(cpi->hba_vid, "BusLogic", HBA_IDLEN); 124439223Sgibbs strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 124539223Sgibbs cpi->unit_number = cam_sim_unit(sim); 124639223Sgibbs cpi->ccb_h.status = CAM_REQ_CMP; 124739223Sgibbs xpt_done(ccb); 124839223Sgibbs break; 124939223Sgibbs } 125039223Sgibbs default: 125139223Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 125239223Sgibbs xpt_done(ccb); 125339223Sgibbs break; 125439223Sgibbs } 125539223Sgibbs} 125639223Sgibbs 125739223Sgibbsstatic void 125839223Sgibbsbtexecuteccb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 125939223Sgibbs{ 126039223Sgibbs struct bt_ccb *bccb; 126139223Sgibbs union ccb *ccb; 126239223Sgibbs struct bt_softc *bt; 126339223Sgibbs int s, i; 126439223Sgibbs 126539223Sgibbs bccb = (struct bt_ccb *)arg; 126639223Sgibbs ccb = bccb->ccb; 126739223Sgibbs bt = (struct bt_softc *)ccb->ccb_h.ccb_bt_ptr; 126839223Sgibbs 126939223Sgibbs if (error != 0) { 127039223Sgibbs if (error != EFBIG) 127139223Sgibbs printf("%s: Unexepected error 0x%x returned from " 127239324Sgibbs "bus_dmamap_load\n", bt_name(bt), error); 127339223Sgibbs if (ccb->ccb_h.status == CAM_REQ_INPROG) { 127439223Sgibbs xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 127539223Sgibbs ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN; 127639223Sgibbs } 127739223Sgibbs btfreeccb(bt, bccb); 127839223Sgibbs xpt_done(ccb); 127939223Sgibbs return; 128039223Sgibbs } 128139223Sgibbs 128239223Sgibbs if (nseg != 0) { 128339223Sgibbs bt_sg_t *sg; 128439223Sgibbs bus_dma_segment_t *end_seg; 128539223Sgibbs bus_dmasync_op_t op; 128639223Sgibbs 128739223Sgibbs end_seg = dm_segs + nseg; 128839223Sgibbs 128939223Sgibbs /* Copy the segments into our SG list */ 129039223Sgibbs sg = bccb->sg_list; 129139223Sgibbs while (dm_segs < end_seg) { 129239223Sgibbs sg->len = dm_segs->ds_len; 129339223Sgibbs sg->addr = dm_segs->ds_addr; 129439223Sgibbs sg++; 129539223Sgibbs dm_segs++; 129639223Sgibbs } 129739223Sgibbs 129839223Sgibbs if (nseg > 1) { 129939223Sgibbs bccb->hccb.opcode = INITIATOR_SG_CCB_WRESID; 130039223Sgibbs bccb->hccb.data_len = sizeof(bt_sg_t) * nseg; 130139223Sgibbs bccb->hccb.data_addr = bccb->sg_list_phys; 130239223Sgibbs } else { 130339223Sgibbs bccb->hccb.data_len = bccb->sg_list->len; 130439223Sgibbs bccb->hccb.data_addr = bccb->sg_list->addr; 130539223Sgibbs } 130639223Sgibbs 130739223Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 130839223Sgibbs op = BUS_DMASYNC_PREREAD; 130939223Sgibbs else 131039223Sgibbs op = BUS_DMASYNC_PREWRITE; 131139223Sgibbs 131239223Sgibbs bus_dmamap_sync(bt->buffer_dmat, bccb->dmamap, op); 131339223Sgibbs 131439223Sgibbs } else { 131539223Sgibbs bccb->hccb.opcode = INITIATOR_SG_CCB; 131639223Sgibbs bccb->hccb.data_len = 0; 131739223Sgibbs bccb->hccb.data_addr = 0; 131839223Sgibbs } 131939223Sgibbs 132039223Sgibbs s = splcam(); 132139223Sgibbs 132239223Sgibbs /* 132339223Sgibbs * Last time we need to check if this CCB needs to 132439223Sgibbs * be aborted. 132539223Sgibbs */ 132639223Sgibbs if (ccb->ccb_h.status != CAM_REQ_INPROG) { 132739223Sgibbs if (nseg != 0) 132839223Sgibbs bus_dmamap_unload(bt->buffer_dmat, bccb->dmamap); 132939223Sgibbs btfreeccb(bt, bccb); 133039223Sgibbs xpt_done(ccb); 133139223Sgibbs splx(s); 133239223Sgibbs return; 133339223Sgibbs } 133439223Sgibbs 133539223Sgibbs bccb->flags = BCCB_ACTIVE; 133639223Sgibbs ccb->ccb_h.status |= CAM_SIM_QUEUED; 133739223Sgibbs LIST_INSERT_HEAD(&bt->pending_ccbs, &ccb->ccb_h, sim_links.le); 133839223Sgibbs 133939223Sgibbs ccb->ccb_h.timeout_ch = 134039223Sgibbs timeout(bttimeout, (caddr_t)bccb, 134139223Sgibbs (ccb->ccb_h.timeout * hz) / 1000); 134239223Sgibbs 134339223Sgibbs /* Tell the adapter about this command */ 134439223Sgibbs bt->cur_outbox->ccb_addr = btccbvtop(bt, bccb); 134539223Sgibbs if (bt->cur_outbox->action_code != BMBO_FREE) 134639223Sgibbs panic("%s: Too few mailboxes or to many ccbs???", bt_name(bt)); 134739223Sgibbs bt->cur_outbox->action_code = BMBO_START; 134839223Sgibbs bt_outb(bt, COMMAND_REG, BOP_START_MBOX); 134939223Sgibbs btnextoutbox(bt); 135039223Sgibbs splx(s); 135139223Sgibbs} 135239223Sgibbs 135339223Sgibbsvoid 135439223Sgibbsbt_intr(void *arg) 135539223Sgibbs{ 135639223Sgibbs struct bt_softc *bt; 135739223Sgibbs u_int intstat; 135839223Sgibbs 135939223Sgibbs bt = (struct bt_softc *)arg; 136039223Sgibbs while (((intstat = bt_inb(bt, INTSTAT_REG)) & INTR_PENDING) != 0) { 136139223Sgibbs 136239223Sgibbs if ((intstat & CMD_COMPLETE) != 0) { 136339223Sgibbs bt->latched_status = bt_inb(bt, STATUS_REG); 136439223Sgibbs bt->command_cmp = TRUE; 136539223Sgibbs } 136639223Sgibbs 136739223Sgibbs bt_outb(bt, CONTROL_REG, RESET_INTR); 136839223Sgibbs 136939223Sgibbs if ((intstat & IMB_LOADED) != 0) { 137039223Sgibbs while (bt->cur_inbox->comp_code != BMBI_FREE) { 137139223Sgibbs btdone(bt, 137239223Sgibbs btccbptov(bt, bt->cur_inbox->ccb_addr), 137339223Sgibbs bt->cur_inbox->comp_code); 137439223Sgibbs bt->cur_inbox->comp_code = BMBI_FREE; 137539223Sgibbs btnextinbox(bt); 137639223Sgibbs } 137739223Sgibbs } 137839223Sgibbs 137939223Sgibbs if ((intstat & SCSI_BUS_RESET) != 0) { 138039223Sgibbs btreset(bt, /*hardreset*/FALSE); 138139223Sgibbs } 138239223Sgibbs } 138339223Sgibbs} 138439223Sgibbs 138539223Sgibbsstatic void 138639223Sgibbsbtdone(struct bt_softc *bt, struct bt_ccb *bccb, bt_mbi_comp_code_t comp_code) 138739223Sgibbs{ 138839223Sgibbs union ccb *ccb; 138939223Sgibbs struct ccb_scsiio *csio; 139039223Sgibbs 139139223Sgibbs ccb = bccb->ccb; 139239223Sgibbs csio = &bccb->ccb->csio; 139339223Sgibbs 139439223Sgibbs if ((bccb->flags & BCCB_ACTIVE) == 0) { 139539390Sgibbs printf("%s: btdone - Attempt to free non-active BCCB %p\n", 139639390Sgibbs bt_name(bt), (void *)bccb); 139739223Sgibbs return; 139839223Sgibbs } 139939223Sgibbs 140039223Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 140139223Sgibbs bus_dmasync_op_t op; 140239223Sgibbs 140339223Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 140439223Sgibbs op = BUS_DMASYNC_POSTREAD; 140539223Sgibbs else 140639223Sgibbs op = BUS_DMASYNC_POSTWRITE; 140739223Sgibbs bus_dmamap_sync(bt->buffer_dmat, bccb->dmamap, op); 140839223Sgibbs bus_dmamap_unload(bt->buffer_dmat, bccb->dmamap); 140939223Sgibbs } 141039223Sgibbs 141139223Sgibbs if (bccb == bt->recovery_bccb) { 141239223Sgibbs /* 141339223Sgibbs * The recovery BCCB does not have a CCB associated 141439223Sgibbs * with it, so short circuit the normal error handling. 141539223Sgibbs * We now traverse our list of pending CCBs and process 141639223Sgibbs * any that were terminated by the recovery CCBs action. 141739223Sgibbs * We also reinstate timeouts for all remaining, pending, 141839223Sgibbs * CCBs. 141939223Sgibbs */ 142039223Sgibbs struct cam_path *path; 142139223Sgibbs struct ccb_hdr *ccb_h; 142239223Sgibbs cam_status error; 142339223Sgibbs 142439223Sgibbs /* Notify all clients that a BDR occured */ 142539223Sgibbs error = xpt_create_path(&path, /*periph*/NULL, 142639223Sgibbs cam_sim_path(bt->sim), 142739223Sgibbs bccb->hccb.target_id, 142839223Sgibbs CAM_LUN_WILDCARD); 142939223Sgibbs 143039223Sgibbs if (error == CAM_REQ_CMP) 143139223Sgibbs xpt_async(AC_SENT_BDR, path, NULL); 143239223Sgibbs 143339223Sgibbs ccb_h = LIST_FIRST(&bt->pending_ccbs); 143439223Sgibbs while (ccb_h != NULL) { 143539223Sgibbs struct bt_ccb *pending_bccb; 143639223Sgibbs 143739223Sgibbs pending_bccb = (struct bt_ccb *)ccb_h->ccb_bccb_ptr; 143839223Sgibbs if (pending_bccb->hccb.target_id 143939223Sgibbs == bccb->hccb.target_id) { 144039223Sgibbs pending_bccb->hccb.btstat = BTSTAT_HA_BDR; 144139223Sgibbs ccb_h = LIST_NEXT(ccb_h, sim_links.le); 144239223Sgibbs btdone(bt, pending_bccb, BMBI_ERROR); 144339223Sgibbs } else { 144439223Sgibbs ccb_h->timeout_ch = 144539223Sgibbs timeout(bttimeout, (caddr_t)pending_bccb, 144639223Sgibbs (ccb_h->timeout * hz) / 1000); 144739223Sgibbs ccb_h = LIST_NEXT(ccb_h, sim_links.le); 144839223Sgibbs } 144939223Sgibbs } 145039223Sgibbs printf("%s: No longer in timeout\n", bt_name(bt)); 145139223Sgibbs return; 145239223Sgibbs } 145339223Sgibbs 145439223Sgibbs untimeout(bttimeout, bccb, ccb->ccb_h.timeout_ch); 145539223Sgibbs 145639223Sgibbs switch (comp_code) { 145739223Sgibbs case BMBI_FREE: 145839223Sgibbs printf("%s: btdone - CCB completed with free status!\n", 145939223Sgibbs bt_name(bt)); 146039223Sgibbs break; 146139223Sgibbs case BMBI_NOT_FOUND: 146239223Sgibbs printf("%s: btdone - CCB Abort failed to find CCB\n", 146339223Sgibbs bt_name(bt)); 146439223Sgibbs break; 146539223Sgibbs case BMBI_ABORT: 146639223Sgibbs case BMBI_ERROR: 146739223Sgibbs#if 0 146839223Sgibbs printf("bt: ccb %x - error %x occured. btstat = %x, sdstat = %x\n", 146939223Sgibbs bccb, comp_code, bccb->hccb.btstat, bccb->hccb.sdstat); 147039223Sgibbs#endif 147139223Sgibbs /* An error occured */ 147239223Sgibbs switch(bccb->hccb.btstat) { 147339223Sgibbs case BTSTAT_DATARUN_ERROR: 147439223Sgibbs if (bccb->hccb.data_len <= 0) { 147539223Sgibbs csio->ccb_h.status = CAM_DATA_RUN_ERR; 147639223Sgibbs break; 147739223Sgibbs } 147839223Sgibbs /* FALLTHROUGH */ 147939223Sgibbs case BTSTAT_NOERROR: 148039223Sgibbs case BTSTAT_LINKED_CMD_COMPLETE: 148139223Sgibbs case BTSTAT_LINKED_CMD_FLAG_COMPLETE: 148239223Sgibbs case BTSTAT_DATAUNDERUN_ERROR: 148339223Sgibbs 148439223Sgibbs csio->scsi_status = bccb->hccb.sdstat; 148539223Sgibbs csio->ccb_h.status |= CAM_SCSI_STATUS_ERROR; 148639223Sgibbs switch(csio->scsi_status) { 148739223Sgibbs case SCSI_STATUS_CHECK_COND: 148839223Sgibbs case SCSI_STATUS_CMD_TERMINATED: 148939223Sgibbs csio->ccb_h.status |= CAM_AUTOSNS_VALID; 149039223Sgibbs /* Bounce sense back if necessary */ 149139223Sgibbs if (bt->sense_buffers != NULL) { 149239223Sgibbs csio->sense_data = 149339223Sgibbs *btsensevaddr(bt, bccb); 149439223Sgibbs } 149539223Sgibbs break; 149639223Sgibbs default: 149739223Sgibbs break; 149839223Sgibbs case SCSI_STATUS_OK: 149939223Sgibbs csio->ccb_h.status = CAM_REQ_CMP; 150039223Sgibbs break; 150139223Sgibbs } 150239223Sgibbs csio->resid = bccb->hccb.data_len; 150339223Sgibbs break; 150439223Sgibbs case BTSTAT_SELTIMEOUT: 150539223Sgibbs csio->ccb_h.status = CAM_SEL_TIMEOUT; 150639223Sgibbs break; 150739223Sgibbs case BTSTAT_UNEXPECTED_BUSFREE: 150839223Sgibbs csio->ccb_h.status = CAM_UNEXP_BUSFREE; 150939223Sgibbs break; 151039223Sgibbs case BTSTAT_INVALID_PHASE: 151139223Sgibbs csio->ccb_h.status = CAM_SEQUENCE_FAIL; 151239223Sgibbs break; 151339223Sgibbs case BTSTAT_INVALID_ACTION_CODE: 151439223Sgibbs panic("%s: Inavlid Action code", bt_name(bt)); 151539223Sgibbs break; 151639223Sgibbs case BTSTAT_INVALID_OPCODE: 151739223Sgibbs panic("%s: Inavlid CCB Opcode code", bt_name(bt)); 151839223Sgibbs break; 151939223Sgibbs case BTSTAT_LINKED_CCB_LUN_MISMATCH: 152039223Sgibbs /* We don't even support linked commands... */ 152139223Sgibbs panic("%s: Linked CCB Lun Mismatch", bt_name(bt)); 152239223Sgibbs break; 152339223Sgibbs case BTSTAT_INVALID_CCB_OR_SG_PARAM: 152439223Sgibbs panic("%s: Invalid CCB or SG list", bt_name(bt)); 152539223Sgibbs break; 152639223Sgibbs case BTSTAT_AUTOSENSE_FAILED: 152739223Sgibbs csio->ccb_h.status = CAM_AUTOSENSE_FAIL; 152839223Sgibbs break; 152939223Sgibbs case BTSTAT_TAGGED_MSG_REJECTED: 153039223Sgibbs { 153139223Sgibbs struct ccb_trans_settings neg; 153239223Sgibbs 153339223Sgibbs xpt_print_path(csio->ccb_h.path); 153439223Sgibbs printf("refuses tagged commands. Performing " 153539223Sgibbs "non-tagged I/O\n"); 153639223Sgibbs neg.flags = 0; 153739223Sgibbs neg.valid = CCB_TRANS_TQ_VALID; 153839223Sgibbs xpt_setup_ccb(&neg.ccb_h, csio->ccb_h.path, 153939223Sgibbs /*priority*/1); 154039223Sgibbs xpt_async(AC_TRANSFER_NEG, csio->ccb_h.path, &neg); 154139223Sgibbs bt->tags_permitted &= ~(0x01 << csio->ccb_h.target_id); 154239223Sgibbs csio->ccb_h.status = CAM_MSG_REJECT_REC; 154339223Sgibbs break; 154439223Sgibbs } 154539223Sgibbs case BTSTAT_UNSUPPORTED_MSG_RECEIVED: 154639223Sgibbs /* 154739223Sgibbs * XXX You would think that this is 154839223Sgibbs * a recoverable error... Hmmm. 154939223Sgibbs */ 155039223Sgibbs csio->ccb_h.status = CAM_REQ_CMP_ERR; 155139223Sgibbs break; 155239223Sgibbs case BTSTAT_HA_SOFTWARE_ERROR: 155339223Sgibbs case BTSTAT_HA_WATCHDOG_ERROR: 155439223Sgibbs case BTSTAT_HARDWARE_FAILURE: 155539223Sgibbs /* Hardware reset ??? Can we recover ??? */ 155639223Sgibbs csio->ccb_h.status = CAM_NO_HBA; 155739223Sgibbs break; 155839223Sgibbs case BTSTAT_TARGET_IGNORED_ATN: 155939223Sgibbs case BTSTAT_OTHER_SCSI_BUS_RESET: 156039223Sgibbs case BTSTAT_HA_SCSI_BUS_RESET: 156139223Sgibbs if ((csio->ccb_h.status & CAM_STATUS_MASK) 156239223Sgibbs != CAM_CMD_TIMEOUT) 156339223Sgibbs csio->ccb_h.status = CAM_SCSI_BUS_RESET; 156439223Sgibbs break; 156539223Sgibbs case BTSTAT_HA_BDR: 156639223Sgibbs if ((bccb->flags & BCCB_DEVICE_RESET) == 0) 156739223Sgibbs csio->ccb_h.status = CAM_BDR_SENT; 156839223Sgibbs else 156939223Sgibbs csio->ccb_h.status = CAM_CMD_TIMEOUT; 157039223Sgibbs break; 157139223Sgibbs case BTSTAT_INVALID_RECONNECT: 157239223Sgibbs case BTSTAT_ABORT_QUEUE_GENERATED: 157339223Sgibbs csio->ccb_h.status = CAM_REQ_TERMIO; 157439223Sgibbs break; 157539223Sgibbs case BTSTAT_SCSI_PERROR_DETECTED: 157639223Sgibbs csio->ccb_h.status = CAM_UNCOR_PARITY; 157739223Sgibbs break; 157839223Sgibbs } 157939223Sgibbs if (csio->ccb_h.status != CAM_REQ_CMP) { 158039223Sgibbs xpt_freeze_devq(csio->ccb_h.path, /*count*/1); 158139223Sgibbs csio->ccb_h.status |= CAM_DEV_QFRZN; 158239223Sgibbs } 158339223Sgibbs if ((bccb->flags & BCCB_RELEASE_SIMQ) != 0) 158439223Sgibbs ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 158539223Sgibbs btfreeccb(bt, bccb); 158639223Sgibbs xpt_done(ccb); 158739223Sgibbs break; 158839223Sgibbs case BMBI_OK: 158939223Sgibbs /* All completed without incident */ 159039223Sgibbs ccb->ccb_h.status |= CAM_REQ_CMP; 159139223Sgibbs if ((bccb->flags & BCCB_RELEASE_SIMQ) != 0) 159239223Sgibbs ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 159339223Sgibbs btfreeccb(bt, bccb); 159439223Sgibbs xpt_done(ccb); 159539223Sgibbs break; 159639223Sgibbs } 159739223Sgibbs} 159839223Sgibbs 159939223Sgibbsstatic int 160039223Sgibbsbtreset(struct bt_softc* bt, int hard_reset) 160139223Sgibbs{ 160239223Sgibbs struct ccb_hdr *ccb_h; 160339223Sgibbs u_int status; 160439223Sgibbs u_int timeout; 160539223Sgibbs u_int8_t reset_type; 160639223Sgibbs 160739223Sgibbs if (hard_reset != 0) 160839223Sgibbs reset_type = HARD_RESET; 160939223Sgibbs else 161039223Sgibbs reset_type = SOFT_RESET; 161139223Sgibbs bt_outb(bt, CONTROL_REG, reset_type); 161239223Sgibbs 161339223Sgibbs /* Wait 5sec. for Diagnostic start */ 161439223Sgibbs timeout = 5 * 10000; 161539223Sgibbs while (--timeout) { 161639223Sgibbs status = bt_inb(bt, STATUS_REG); 161739223Sgibbs if ((status & DIAG_ACTIVE) != 0) 161839223Sgibbs break; 161939223Sgibbs DELAY(100); 162039223Sgibbs } 162139223Sgibbs if (timeout == 0) { 162239223Sgibbs if (bootverbose) 162339223Sgibbs printf("%s: btreset - Diagnostic Active failed to " 162439223Sgibbs "assert. status = 0x%x\n", bt_name(bt), status); 162539223Sgibbs return (ETIMEDOUT); 162639223Sgibbs } 162739223Sgibbs 162839223Sgibbs /* Wait 10sec. for Diagnostic end */ 162939223Sgibbs timeout = 10 * 10000; 163039223Sgibbs while (--timeout) { 163139223Sgibbs status = bt_inb(bt, STATUS_REG); 163239223Sgibbs if ((status & DIAG_ACTIVE) == 0) 163339223Sgibbs break; 163439223Sgibbs DELAY(100); 163539223Sgibbs } 163639223Sgibbs if (timeout == 0) { 163739223Sgibbs panic("%s: btreset - Diagnostic Active failed to drop. " 163839223Sgibbs "status = 0x%x\n", bt_name(bt), status); 163939223Sgibbs return (ETIMEDOUT); 164039223Sgibbs } 164139223Sgibbs 164239223Sgibbs /* Wait for the host adapter to become ready or report a failure */ 164339223Sgibbs timeout = 10000; 164439223Sgibbs while (--timeout) { 164539223Sgibbs status = bt_inb(bt, STATUS_REG); 164639223Sgibbs if ((status & (DIAG_FAIL|HA_READY|DATAIN_REG_READY)) != 0) 164739223Sgibbs break; 164839223Sgibbs DELAY(100); 164939223Sgibbs } 165039223Sgibbs if (timeout == 0) { 165139223Sgibbs printf("%s: btreset - Host adapter failed to come ready. " 165239223Sgibbs "status = 0x%x\n", bt_name(bt), status); 165339223Sgibbs return (ETIMEDOUT); 165439223Sgibbs } 165539223Sgibbs 165639223Sgibbs /* If the diagnostics failed, tell the user */ 165739223Sgibbs if ((status & DIAG_FAIL) != 0 165839223Sgibbs || (status & HA_READY) == 0) { 165939223Sgibbs printf("%s: btreset - Adapter failed diagnostics\n", 166039223Sgibbs bt_name(bt)); 166139223Sgibbs 166239223Sgibbs if ((status & DATAIN_REG_READY) != 0) 166339223Sgibbs printf("%s: btreset - Host Adapter Error code = 0x%x\n", 166439324Sgibbs bt_name(bt), bt_inb(bt, DATAIN_REG)); 166539223Sgibbs return (ENXIO); 166639223Sgibbs } 166739223Sgibbs 166839223Sgibbs /* If we've allocated mailboxes, initialize them */ 166939223Sgibbs if (bt->init_level > 4) 167039223Sgibbs btinitmboxes(bt); 167139223Sgibbs 167239223Sgibbs /* If we've attached to the XPT, tell it about the event */ 167339223Sgibbs if (bt->path != NULL) 167439223Sgibbs xpt_async(AC_BUS_RESET, bt->path, NULL); 167539223Sgibbs 167639223Sgibbs /* 167739223Sgibbs * Perform completion processing for all outstanding CCBs. 167839223Sgibbs */ 167939223Sgibbs while ((ccb_h = LIST_FIRST(&bt->pending_ccbs)) != NULL) { 168039223Sgibbs struct bt_ccb *pending_bccb; 168139223Sgibbs 168239223Sgibbs pending_bccb = (struct bt_ccb *)ccb_h->ccb_bccb_ptr; 168339223Sgibbs pending_bccb->hccb.btstat = BTSTAT_HA_SCSI_BUS_RESET; 168439223Sgibbs btdone(bt, pending_bccb, BMBI_ERROR); 168539223Sgibbs } 168639223Sgibbs 168739223Sgibbs return (0); 168839223Sgibbs} 168939223Sgibbs 169039223Sgibbs/* 169139223Sgibbs * Send a command to the adapter. 169239223Sgibbs */ 169339223Sgibbsint 169439223Sgibbsbt_cmd(struct bt_softc *bt, bt_op_t opcode, u_int8_t *params, u_int param_len, 169539223Sgibbs u_int8_t *reply_data, u_int reply_len, u_int cmd_timeout) 169639223Sgibbs{ 169739223Sgibbs u_int timeout; 169839223Sgibbs u_int status; 169939223Sgibbs u_int intstat; 170039223Sgibbs u_int reply_buf_size; 170139223Sgibbs int s; 170239223Sgibbs 170339223Sgibbs /* No data returned to start */ 170439223Sgibbs reply_buf_size = reply_len; 170539223Sgibbs reply_len = 0; 170639223Sgibbs intstat = 0; 170739223Sgibbs 170839223Sgibbs bt->command_cmp = 0; 170939223Sgibbs /* 171039223Sgibbs * Wait up to 1 sec. for the adapter to become 171139223Sgibbs * ready to accept commands. 171239223Sgibbs */ 171339223Sgibbs timeout = 10000; 171439223Sgibbs while (--timeout) { 171539223Sgibbs 171639223Sgibbs status = bt_inb(bt, STATUS_REG); 171739223Sgibbs if ((status & HA_READY) != 0 171839223Sgibbs && (status & CMD_REG_BUSY) == 0) 171939223Sgibbs break; 172039223Sgibbs DELAY(100); 172139223Sgibbs } 172239223Sgibbs if (timeout == 0) { 172339223Sgibbs printf("%s: bt_cmd: Timeout waiting for adapter ready, " 172439223Sgibbs "status = 0x%x\n", bt_name(bt), status); 172539223Sgibbs return (ETIMEDOUT); 172639223Sgibbs } 172739223Sgibbs 172839223Sgibbs /* 172939223Sgibbs * Send the opcode followed by any necessary parameter bytes. 173039223Sgibbs */ 173139223Sgibbs bt_outb(bt, COMMAND_REG, opcode); 173239223Sgibbs 173339223Sgibbs /* 173439223Sgibbs * Wait for up to 1sec to get the parameter list sent 173539223Sgibbs */ 173639223Sgibbs timeout = 10000; 173739223Sgibbs while (param_len && --timeout) { 173839223Sgibbs DELAY(100); 173939223Sgibbs status = bt_inb(bt, STATUS_REG); 174039223Sgibbs intstat = bt_inb(bt, INTSTAT_REG); 174139223Sgibbs if ((intstat & (INTR_PENDING|CMD_COMPLETE)) 174239223Sgibbs == (INTR_PENDING|CMD_COMPLETE)) 174339223Sgibbs break; 174439223Sgibbs if (bt->command_cmp != 0) { 174539223Sgibbs status = bt->latched_status; 174639223Sgibbs break; 174739223Sgibbs } 174839223Sgibbs if ((status & DATAIN_REG_READY) != 0) 174939223Sgibbs break; 175039223Sgibbs if ((status & CMD_REG_BUSY) == 0) { 175139223Sgibbs bt_outb(bt, COMMAND_REG, *params++); 175239223Sgibbs param_len--; 175339223Sgibbs } 175439223Sgibbs } 175539223Sgibbs if (timeout == 0) { 175639223Sgibbs printf("%s: bt_cmd: Timeout sending parameters, " 175739223Sgibbs "status = 0x%x\n", bt_name(bt), status); 175839223Sgibbs return (ETIMEDOUT); 175939223Sgibbs } 176039223Sgibbs 176139223Sgibbs /* 176239223Sgibbs * The BOP_MODIFY_IO_ADDR does not issue a CMD_COMPLETE, but 176339223Sgibbs * it should update the status register. So, we wait for 176439223Sgibbs * the CMD_REG_BUSY status to clear and check for a command 176539223Sgibbs * failure. 176639223Sgibbs */ 176739223Sgibbs if (opcode == BOP_MODIFY_IO_ADDR) { 176839223Sgibbs 176939223Sgibbs while (--cmd_timeout) { 177039223Sgibbs status = bt_inb(bt, STATUS_REG); 177139223Sgibbs if ((status & CMD_REG_BUSY) == 0) { 177239223Sgibbs if ((status & CMD_INVALID) != 0) { 177339223Sgibbs printf("%s: bt_cmd - Modify I/O Address" 177439223Sgibbs " invalid\n", bt_name(bt)); 177539223Sgibbs return (EINVAL); 177639223Sgibbs } 177739223Sgibbs return (0); 177839223Sgibbs } 177939223Sgibbs DELAY(100); 178039223Sgibbs } 178139223Sgibbs if (timeout == 0) { 178239223Sgibbs printf("%s: bt_cmd: Timeout on Modify I/O Address CMD, " 178339223Sgibbs "status = 0x%x\n", bt_name(bt), status); 178439223Sgibbs return (ETIMEDOUT); 178539223Sgibbs } 178639223Sgibbs } 178739223Sgibbs 178839223Sgibbs /* 178939223Sgibbs * For all other commands, we wait for any output data 179039223Sgibbs * and the final comand completion interrupt. 179139223Sgibbs */ 179239223Sgibbs while (--cmd_timeout) { 179339223Sgibbs 179439223Sgibbs status = bt_inb(bt, STATUS_REG); 179539223Sgibbs intstat = bt_inb(bt, INTSTAT_REG); 179639223Sgibbs if ((intstat & (INTR_PENDING|CMD_COMPLETE)) 179739223Sgibbs == (INTR_PENDING|CMD_COMPLETE)) 179839223Sgibbs break; 179939223Sgibbs 180039223Sgibbs if (bt->command_cmp != 0) { 180139223Sgibbs status = bt->latched_status; 180239223Sgibbs break; 180339223Sgibbs } 180439223Sgibbs 180539223Sgibbs if ((status & DATAIN_REG_READY) != 0) { 180639223Sgibbs u_int8_t data; 180739223Sgibbs 180839223Sgibbs data = bt_inb(bt, DATAIN_REG); 180939223Sgibbs if (reply_len < reply_buf_size) { 181039223Sgibbs *reply_data++ = data; 181139223Sgibbs } else { 181239223Sgibbs printf("%s: bt_cmd - Discarded reply data byte " 181339223Sgibbs "for opcode 0x%x\n", bt_name(bt), 181439223Sgibbs opcode); 181539223Sgibbs } 181639223Sgibbs reply_len++; 181739223Sgibbs } 181839223Sgibbs 181939223Sgibbs if ((opcode == BOP_FETCH_LRAM) 182039223Sgibbs && (status & HA_READY) != 0) 182139223Sgibbs break; 182239223Sgibbs DELAY(100); 182339223Sgibbs } 182439223Sgibbs if (timeout == 0) { 182539223Sgibbs printf("%s: bt_cmd: Timeout waiting for reply data and " 182639223Sgibbs "command complete.\n%s: status = 0x%x, intstat = 0x%x, " 182739223Sgibbs "reply_len = %d\n", bt_name(bt), bt_name(bt), status, 182839223Sgibbs intstat, reply_len); 182939223Sgibbs return (ETIMEDOUT); 183039223Sgibbs } 183139223Sgibbs 183239223Sgibbs /* 183339223Sgibbs * Clear any pending interrupts. Block interrupts so our 183439223Sgibbs * interrupt handler is not re-entered. 183539223Sgibbs */ 183639223Sgibbs s = splcam(); 183739223Sgibbs bt_intr(bt); 183839223Sgibbs splx(s); 183939223Sgibbs 184039223Sgibbs /* 184139223Sgibbs * If the command was rejected by the controller, tell the caller. 184239223Sgibbs */ 184339223Sgibbs if ((status & CMD_INVALID) != 0) { 184439223Sgibbs /* 184539223Sgibbs * Some early adapters may not recover properly from 184639223Sgibbs * an invalid command. If it appears that the controller 184739223Sgibbs * has wedged (i.e. status was not cleared by our interrupt 184839223Sgibbs * reset above), perform a soft reset. 184939223Sgibbs */ 185039223Sgibbs if (bootverbose) 185139223Sgibbs printf("%s: Invalid Command 0x%x\n", bt_name(bt), 185239223Sgibbs opcode); 185339223Sgibbs DELAY(1000); 185439223Sgibbs status = bt_inb(bt, STATUS_REG); 185539223Sgibbs if ((status & (CMD_INVALID|STATUS_REG_RSVD|DATAIN_REG_READY| 185639223Sgibbs CMD_REG_BUSY|DIAG_FAIL|DIAG_ACTIVE)) != 0 185739223Sgibbs || (status & (HA_READY|INIT_REQUIRED)) 185839223Sgibbs != (HA_READY|INIT_REQUIRED)) { 185939223Sgibbs btreset(bt, /*hard_reset*/FALSE); 186039223Sgibbs } 186139223Sgibbs return (EINVAL); 186239223Sgibbs } 186339223Sgibbs 186439223Sgibbs 186539223Sgibbs if (param_len > 0) { 186639223Sgibbs /* The controller did not accept the full argument list */ 186739223Sgibbs return (E2BIG); 186839223Sgibbs } 186939223Sgibbs 187039223Sgibbs if (reply_len != reply_buf_size) { 187139223Sgibbs /* Too much or too little data received */ 187239223Sgibbs return (EMSGSIZE); 187339223Sgibbs } 187439223Sgibbs 187539223Sgibbs /* We were successful */ 187639223Sgibbs return (0); 187739223Sgibbs} 187839223Sgibbs 187939223Sgibbsstatic int 188039223Sgibbsbtinitmboxes(struct bt_softc *bt) { 188139223Sgibbs init_32b_mbox_params_t init_mbox; 188239223Sgibbs int error; 188339223Sgibbs 188439223Sgibbs bzero(bt->in_boxes, sizeof(bt_mbox_in_t) * bt->num_boxes); 188539223Sgibbs bzero(bt->out_boxes, sizeof(bt_mbox_out_t) * bt->num_boxes); 188639223Sgibbs bt->cur_inbox = bt->in_boxes; 188739223Sgibbs bt->last_inbox = bt->in_boxes + bt->num_boxes - 1; 188839223Sgibbs bt->cur_outbox = bt->out_boxes; 188939223Sgibbs bt->last_outbox = bt->out_boxes + bt->num_boxes - 1; 189039223Sgibbs 189139223Sgibbs /* Tell the adapter about them */ 189239223Sgibbs init_mbox.num_boxes = bt->num_boxes; 189339223Sgibbs init_mbox.base_addr[0] = bt->mailbox_physbase & 0xFF; 189439223Sgibbs init_mbox.base_addr[1] = (bt->mailbox_physbase >> 8) & 0xFF; 189539223Sgibbs init_mbox.base_addr[2] = (bt->mailbox_physbase >> 16) & 0xFF; 189639223Sgibbs init_mbox.base_addr[3] = (bt->mailbox_physbase >> 24) & 0xFF; 189739223Sgibbs error = bt_cmd(bt, BOP_INITIALIZE_32BMBOX, (u_int8_t *)&init_mbox, 189839223Sgibbs /*parmlen*/sizeof(init_mbox), /*reply_buf*/NULL, 189939223Sgibbs /*reply_len*/0, DEFAULT_CMD_TIMEOUT); 190039223Sgibbs 190139223Sgibbs if (error != 0) 190239223Sgibbs printf("btinitmboxes: Initialization command failed\n"); 190339223Sgibbs else if (bt->strict_rr != 0) { 190439223Sgibbs /* 190539223Sgibbs * If the controller supports 190639223Sgibbs * strict round robin mode, 190739223Sgibbs * enable it 190839223Sgibbs */ 190939223Sgibbs u_int8_t param; 191039223Sgibbs 191139223Sgibbs param = 0; 191239223Sgibbs error = bt_cmd(bt, BOP_ENABLE_STRICT_RR, ¶m, 1, 191339223Sgibbs /*reply_buf*/NULL, /*reply_len*/0, 191439223Sgibbs DEFAULT_CMD_TIMEOUT); 191539223Sgibbs 191639223Sgibbs if (error != 0) { 191739223Sgibbs printf("btinitmboxes: Unable to enable strict RR\n"); 191839223Sgibbs error = 0; 191939223Sgibbs } else if (bootverbose) { 192039223Sgibbs printf("%s: Using Strict Round Robin Mailbox Mode\n", 192139223Sgibbs bt_name(bt)); 192239223Sgibbs } 192339223Sgibbs } 192439223Sgibbs 192539223Sgibbs return (error); 192639223Sgibbs} 192739223Sgibbs 192839223Sgibbs/* 192939223Sgibbs * Update the XPT's idea of the negotiated transfer 193039223Sgibbs * parameters for a particular target. 193139223Sgibbs */ 193239223Sgibbsstatic void 193339223Sgibbsbtfetchtransinfo(struct bt_softc *bt, struct ccb_trans_settings* cts) 193439223Sgibbs{ 193539223Sgibbs setup_data_t setup_info; 193639223Sgibbs u_int target; 193739223Sgibbs u_int targ_offset; 193839223Sgibbs u_int targ_mask; 193939223Sgibbs u_int sync_period; 194039223Sgibbs int error; 194139223Sgibbs u_int8_t param; 194239223Sgibbs targ_syncinfo_t sync_info; 194339223Sgibbs 194439223Sgibbs target = cts->ccb_h.target_id; 194539223Sgibbs targ_offset = (target & 0x7); 194639223Sgibbs targ_mask = (0x01 << targ_offset); 194739223Sgibbs 194839223Sgibbs /* 194939223Sgibbs * Inquire Setup Information. This command retreives the 195039223Sgibbs * Wide negotiation status for recent adapters as well as 195139223Sgibbs * the sync info for older models. 195239223Sgibbs */ 195339223Sgibbs param = sizeof(setup_info); 195439223Sgibbs error = bt_cmd(bt, BOP_INQUIRE_SETUP_INFO, ¶m, /*paramlen*/1, 195539223Sgibbs (u_int8_t*)&setup_info, sizeof(setup_info), 195639223Sgibbs DEFAULT_CMD_TIMEOUT); 195739223Sgibbs 195839223Sgibbs if (error != 0) { 195939223Sgibbs printf("%s: btfetchtransinfo - Inquire Setup Info Failed\n", 196039223Sgibbs bt_name(bt)); 196139223Sgibbs return; 196239223Sgibbs } 196339223Sgibbs 196439223Sgibbs sync_info = (target < 8) ? setup_info.low_syncinfo[targ_offset] 196539223Sgibbs : setup_info.high_syncinfo[targ_offset]; 196639223Sgibbs 196739223Sgibbs if (sync_info.sync == 0) 196839223Sgibbs cts->sync_offset = 0; 196939223Sgibbs else 197039223Sgibbs cts->sync_offset = sync_info.offset; 197139223Sgibbs 197239223Sgibbs cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 197339223Sgibbs if (strcmp(bt->firmware_ver, "5.06L") >= 0) { 197439223Sgibbs u_int wide_active; 197539223Sgibbs 197639223Sgibbs wide_active = 197739223Sgibbs (target < 8) ? (setup_info.low_wide_active & targ_mask) 197839223Sgibbs : (setup_info.high_wide_active & targ_mask); 197939223Sgibbs 198039223Sgibbs if (wide_active) 198139223Sgibbs cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 198239507Sgibbs } else if ((bt->wide_permitted & targ_mask) != 0) { 198339507Sgibbs struct ccb_getdev cgd; 198439507Sgibbs 198539507Sgibbs /* 198639507Sgibbs * Prior to rev 5.06L, wide status isn't provided, 198739507Sgibbs * so we "guess" that wide transfers are in effect 198839507Sgibbs * if the user settings allow for wide and the inquiry 198939507Sgibbs * data for the device indicates that it can handle 199039507Sgibbs * wide transfers. 199139507Sgibbs */ 199239507Sgibbs xpt_setup_ccb(&cgd.ccb_h, cts->ccb_h.path, /*priority*/1); 199339507Sgibbs cgd.ccb_h.func_code = XPT_GDEV_TYPE; 199439507Sgibbs xpt_action((union ccb *)&cgd); 199539507Sgibbs if ((cgd.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP 199639507Sgibbs && (cgd.inq_data.flags & SID_WBus16) != 0) 199739507Sgibbs cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 199839223Sgibbs } 199939223Sgibbs 200039223Sgibbs if (bt->firmware_ver[0] >= 3) { 200139223Sgibbs /* 200239223Sgibbs * For adapters that can do fast or ultra speeds, 200339223Sgibbs * use the more exact Target Sync Information command. 200439223Sgibbs */ 200539223Sgibbs target_sync_info_data_t sync_info; 200639223Sgibbs 200739223Sgibbs param = sizeof(sync_info); 200839223Sgibbs error = bt_cmd(bt, BOP_TARG_SYNC_INFO, ¶m, /*paramlen*/1, 200939223Sgibbs (u_int8_t*)&sync_info, sizeof(sync_info), 201039223Sgibbs DEFAULT_CMD_TIMEOUT); 201139223Sgibbs 201239223Sgibbs if (error != 0) { 201339223Sgibbs printf("%s: btfetchtransinfo - Inquire Sync " 201439223Sgibbs "Info Failed 0x%x\n", bt_name(bt), error); 201539223Sgibbs return; 201639223Sgibbs } 201739223Sgibbs sync_period = sync_info.sync_rate[target] * 100; 201839223Sgibbs } else { 201939223Sgibbs sync_period = 2000 + (500 * sync_info.period); 202039223Sgibbs } 202139223Sgibbs 202239223Sgibbs /* Convert ns value to standard SCSI sync rate */ 202339223Sgibbs if (cts->sync_offset != 0) 202439223Sgibbs cts->sync_period = scsi_calc_syncparam(sync_period); 202539223Sgibbs else 202639223Sgibbs cts->sync_period = 0; 202739223Sgibbs 202839223Sgibbs cts->valid = CCB_TRANS_SYNC_RATE_VALID 202939223Sgibbs | CCB_TRANS_SYNC_OFFSET_VALID 203039223Sgibbs | CCB_TRANS_BUS_WIDTH_VALID; 203139223Sgibbs xpt_async(AC_TRANSFER_NEG, cts->ccb_h.path, cts); 203239223Sgibbs} 203339223Sgibbs 203439223Sgibbsstatic void 203539223Sgibbsbtmapmboxes(void *arg, bus_dma_segment_t *segs, int nseg, int error) 203639223Sgibbs{ 203739223Sgibbs struct bt_softc* bt; 203839223Sgibbs 203939223Sgibbs bt = (struct bt_softc*)arg; 204039223Sgibbs bt->mailbox_physbase = segs->ds_addr; 204139223Sgibbs} 204239223Sgibbs 204339223Sgibbsstatic void 204439223Sgibbsbtmapccbs(void *arg, bus_dma_segment_t *segs, int nseg, int error) 204539223Sgibbs{ 204639223Sgibbs struct bt_softc* bt; 204739223Sgibbs 204839223Sgibbs bt = (struct bt_softc*)arg; 204939223Sgibbs bt->bt_ccb_physbase = segs->ds_addr; 205039223Sgibbs} 205139223Sgibbs 205239223Sgibbsstatic void 205339223Sgibbsbtmapsgs(void *arg, bus_dma_segment_t *segs, int nseg, int error) 205439223Sgibbs{ 205539223Sgibbs 205639223Sgibbs struct bt_softc* bt; 205739223Sgibbs 205839223Sgibbs bt = (struct bt_softc*)arg; 205939223Sgibbs SLIST_FIRST(&bt->sg_maps)->sg_physaddr = segs->ds_addr; 206039223Sgibbs} 206139223Sgibbs 206239223Sgibbsstatic void 206339223Sgibbsbtpoll(struct cam_sim *sim) 206439223Sgibbs{ 206539223Sgibbs} 206639223Sgibbs 206739223Sgibbsvoid 206839223Sgibbsbttimeout(void *arg) 206939223Sgibbs{ 207039223Sgibbs struct bt_ccb *bccb; 207139223Sgibbs union ccb *ccb; 207239223Sgibbs struct bt_softc *bt; 207339223Sgibbs int s; 207439223Sgibbs 207539223Sgibbs bccb = (struct bt_ccb *)arg; 207639223Sgibbs ccb = bccb->ccb; 207739223Sgibbs bt = (struct bt_softc *)ccb->ccb_h.ccb_bt_ptr; 207839223Sgibbs xpt_print_path(ccb->ccb_h.path); 207939390Sgibbs printf("CCB %p - timed out\n", (void *)bccb); 208039223Sgibbs 208139223Sgibbs s = splcam(); 208239223Sgibbs 208339223Sgibbs if ((bccb->flags & BCCB_ACTIVE) == 0) { 208439223Sgibbs xpt_print_path(ccb->ccb_h.path); 208539390Sgibbs printf("CCB %p - timed out CCB already completed\n", 208639390Sgibbs (void *)bccb); 208739223Sgibbs splx(s); 208839223Sgibbs return; 208939223Sgibbs } 209039223Sgibbs 209139223Sgibbs /* 209239223Sgibbs * In order to simplify the recovery process, we ask the XPT 209339223Sgibbs * layer to halt the queue of new transactions and we traverse 209439223Sgibbs * the list of pending CCBs and remove their timeouts. This 209539223Sgibbs * means that the driver attempts to clear only one error 209639223Sgibbs * condition at a time. In general, timeouts that occur 209739223Sgibbs * close together are related anyway, so there is no benefit 209839223Sgibbs * in attempting to handle errors in parrallel. Timeouts will 209939223Sgibbs * be reinstated when the recovery process ends. 210039223Sgibbs */ 210139223Sgibbs if ((bccb->flags & BCCB_DEVICE_RESET) == 0) { 210239223Sgibbs struct ccb_hdr *ccb_h; 210339223Sgibbs 210439223Sgibbs if ((bccb->flags & BCCB_RELEASE_SIMQ) == 0) { 210539223Sgibbs xpt_freeze_simq(bt->sim, /*count*/1); 210639223Sgibbs bccb->flags |= BCCB_RELEASE_SIMQ; 210739223Sgibbs } 210839223Sgibbs 210939223Sgibbs ccb_h = LIST_FIRST(&bt->pending_ccbs); 211039223Sgibbs while (ccb_h != NULL) { 211139223Sgibbs struct bt_ccb *pending_bccb; 211239223Sgibbs 211339223Sgibbs pending_bccb = (struct bt_ccb *)ccb_h->ccb_bccb_ptr; 211439223Sgibbs untimeout(bttimeout, pending_bccb, ccb_h->timeout_ch); 211539223Sgibbs ccb_h = LIST_NEXT(ccb_h, sim_links.le); 211639223Sgibbs } 211739223Sgibbs } 211839223Sgibbs 211939223Sgibbs if ((bccb->flags & BCCB_DEVICE_RESET) != 0 212039223Sgibbs || bt->cur_outbox->action_code != BMBO_FREE 212139223Sgibbs || ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0 212239223Sgibbs && (bt->firmware_ver[0] < '5'))) { 212339223Sgibbs /* 212439223Sgibbs * Try a full host adapter/SCSI bus reset. 212539223Sgibbs * We do this only if we have already attempted 212639223Sgibbs * to clear the condition with a BDR, or we cannot 212739223Sgibbs * attempt a BDR for lack of mailbox resources 212839223Sgibbs * or because of faulty firmware. It turns out 212939223Sgibbs * that firmware versions prior to 5.xx treat BDRs 213039223Sgibbs * as untagged commands that cannot be sent until 213139223Sgibbs * all outstanding tagged commands have been processed. 213239223Sgibbs * This makes it somewhat difficult to use a BDR to 213339223Sgibbs * clear up a problem with an uncompleted tagged command. 213439223Sgibbs */ 213539223Sgibbs ccb->ccb_h.status = CAM_CMD_TIMEOUT; 213639223Sgibbs btreset(bt, /*hardreset*/TRUE); 213739223Sgibbs printf("%s: No longer in timeout\n", bt_name(bt)); 213839223Sgibbs } else { 213939223Sgibbs /* 214039223Sgibbs * Send a Bus Device Reset message: 214139223Sgibbs * The target that is holding up the bus may not 214239223Sgibbs * be the same as the one that triggered this timeout 214339223Sgibbs * (different commands have different timeout lengths), 214439223Sgibbs * but we have no way of determining this from our 214539223Sgibbs * timeout handler. Our strategy here is to queue a 214639223Sgibbs * BDR message to the target of the timed out command. 214739223Sgibbs * If this fails, we'll get another timeout 2 seconds 214839223Sgibbs * later which will attempt a bus reset. 214939223Sgibbs */ 215039223Sgibbs bccb->flags |= BCCB_DEVICE_RESET; 215139223Sgibbs ccb->ccb_h.timeout_ch = 215239223Sgibbs timeout(bttimeout, (caddr_t)bccb, 2 * hz); 215339223Sgibbs 215439223Sgibbs bt->recovery_bccb->hccb.opcode = INITIATOR_BUS_DEV_RESET; 215539223Sgibbs 215639223Sgibbs /* No Data Transfer */ 215739223Sgibbs bt->recovery_bccb->hccb.datain = TRUE; 215839223Sgibbs bt->recovery_bccb->hccb.dataout = TRUE; 215939223Sgibbs bt->recovery_bccb->hccb.btstat = 0; 216039223Sgibbs bt->recovery_bccb->hccb.sdstat = 0; 216139223Sgibbs bt->recovery_bccb->hccb.target_id = ccb->ccb_h.target_id; 216239223Sgibbs 216339223Sgibbs /* Tell the adapter about this command */ 216439223Sgibbs bt->cur_outbox->ccb_addr = btccbvtop(bt, bt->recovery_bccb); 216539223Sgibbs bt->cur_outbox->action_code = BMBO_START; 216639223Sgibbs bt_outb(bt, COMMAND_REG, BOP_START_MBOX); 216739223Sgibbs btnextoutbox(bt); 216839223Sgibbs } 216939223Sgibbs 217039223Sgibbs splx(s); 217139223Sgibbs} 217239223Sgibbs 2173