bt.c revision 39223
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 * 3239223Sgibbs * $Id$ 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) { 74139223Sgibbs printf("%s: bt_init - Unable to allocate initial ccbs\n"); 74239223Sgibbs goto error_exit; 74339223Sgibbs } 74439223Sgibbs 74539223Sgibbs /* 74639223Sgibbs * Note that we are going and return (to probe) 74739223Sgibbs */ 74839223Sgibbs return 0; 74939223Sgibbs 75039223Sgibbserror_exit: 75139223Sgibbs 75239223Sgibbs return (ENXIO); 75339223Sgibbs} 75439223Sgibbs 75539223Sgibbsint 75639223Sgibbsbt_attach(struct bt_softc *bt) 75739223Sgibbs{ 75839223Sgibbs int tagged_dev_openings; 75939223Sgibbs struct cam_devq *devq; 76039223Sgibbs 76139223Sgibbs /* 76239223Sgibbs * We reserve 1 ccb for error recovery, so don't 76339223Sgibbs * tell the XPT about it. 76439223Sgibbs */ 76539223Sgibbs if (bt->tag_capable != 0) 76639223Sgibbs tagged_dev_openings = bt->max_ccbs - 1; 76739223Sgibbs else 76839223Sgibbs tagged_dev_openings = 0; 76939223Sgibbs 77039223Sgibbs /* 77139223Sgibbs * Create the device queue for our SIM. 77239223Sgibbs */ 77339223Sgibbs devq = cam_simq_alloc(bt->max_ccbs - 1); 77439223Sgibbs if (devq == NULL) 77539223Sgibbs return (ENOMEM); 77639223Sgibbs 77739223Sgibbs /* 77839223Sgibbs * Construct our SIM entry 77939223Sgibbs */ 78039223Sgibbs bt->sim = cam_sim_alloc(btaction, btpoll, "bt", bt, bt->unit, 78139223Sgibbs 2, tagged_dev_openings, devq); 78239223Sgibbs if (bt->sim == NULL) { 78339223Sgibbs cam_simq_free(devq); 78439223Sgibbs return (ENOMEM); 78539223Sgibbs } 78639223Sgibbs 78739223Sgibbs if (xpt_bus_register(bt->sim, 0) != CAM_SUCCESS) { 78839223Sgibbs cam_sim_free(bt->sim, /*free_devq*/TRUE); 78939223Sgibbs return (ENXIO); 79039223Sgibbs } 79139223Sgibbs 79239223Sgibbs if (xpt_create_path(&bt->path, /*periph*/NULL, 79339223Sgibbs cam_sim_path(bt->sim), CAM_TARGET_WILDCARD, 79439223Sgibbs CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 79539223Sgibbs xpt_bus_deregister(cam_sim_path(bt->sim)); 79639223Sgibbs cam_sim_free(bt->sim, /*free_devq*/TRUE); 79739223Sgibbs return (ENXIO); 79839223Sgibbs } 79939223Sgibbs 80039223Sgibbs return (0); 80139223Sgibbs} 80239223Sgibbs 80339223Sgibbschar * 80439223Sgibbsbt_name(struct bt_softc *bt) 80539223Sgibbs{ 80639223Sgibbs static char name[10]; 80739223Sgibbs 80839223Sgibbs sprintf(name, "bt%d", bt->unit); 80939223Sgibbs return (name); 81039223Sgibbs} 81139223Sgibbs 81239223Sgibbsint 81339223Sgibbsbt_check_probed_iop(u_int ioport) 81439223Sgibbs{ 81539223Sgibbs u_int i; 81639223Sgibbs 81739223Sgibbs for (i=0; i < BT_NUM_ISAPORTS; i++) { 81839223Sgibbs if (bt_isa_ports[i].addr == ioport) { 81939223Sgibbs if (bt_isa_ports[i].probed != 0) 82039223Sgibbs return (1); 82139223Sgibbs else { 82239223Sgibbs return (0); 82339223Sgibbs } 82439223Sgibbs } 82539223Sgibbs } 82639223Sgibbs return (1); 82739223Sgibbs} 82839223Sgibbs 82939223Sgibbsvoid 83039223Sgibbsbt_mark_probed_bio(isa_compat_io_t port) 83139223Sgibbs{ 83239223Sgibbs if (port < BIO_DISABLED) 83339223Sgibbs bt_isa_ports[port].probed = 1; 83439223Sgibbs} 83539223Sgibbs 83639223Sgibbsvoid 83739223Sgibbsbt_mark_probed_iop(u_int ioport) 83839223Sgibbs{ 83939223Sgibbs u_int i; 84039223Sgibbs 84139223Sgibbs for (i = 0; i < BT_NUM_ISAPORTS; i++) { 84239223Sgibbs if (ioport == bt_isa_ports[i].addr) { 84339223Sgibbs bt_isa_ports[i].probed = 1; 84439223Sgibbs break; 84539223Sgibbs } 84639223Sgibbs } 84739223Sgibbs} 84839223Sgibbs 84939223Sgibbsstatic void 85039223Sgibbsbtallocccbs(struct bt_softc *bt) 85139223Sgibbs{ 85239223Sgibbs struct bt_ccb *next_ccb; 85339223Sgibbs struct sg_map_node *sg_map; 85439223Sgibbs bus_addr_t physaddr; 85539223Sgibbs bt_sg_t *segs; 85639223Sgibbs int newcount; 85739223Sgibbs int i; 85839223Sgibbs 85939223Sgibbs next_ccb = &bt->bt_ccb_array[bt->num_ccbs]; 86039223Sgibbs 86139223Sgibbs sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT); 86239223Sgibbs 86339223Sgibbs if (sg_map == NULL) 86439223Sgibbs return; 86539223Sgibbs 86639223Sgibbs /* Allocate S/G space for the next batch of CCBS */ 86739223Sgibbs if (bus_dmamem_alloc(bt->sg_dmat, (void **)&sg_map->sg_vaddr, 86839223Sgibbs BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) { 86939223Sgibbs free(sg_map, M_DEVBUF); 87039223Sgibbs return; 87139223Sgibbs } 87239223Sgibbs 87339223Sgibbs SLIST_INSERT_HEAD(&bt->sg_maps, sg_map, links); 87439223Sgibbs 87539223Sgibbs bus_dmamap_load(bt->sg_dmat, sg_map->sg_dmamap, sg_map->sg_vaddr, 87639223Sgibbs PAGE_SIZE, btmapsgs, bt, /*flags*/0); 87739223Sgibbs 87839223Sgibbs segs = sg_map->sg_vaddr; 87939223Sgibbs physaddr = sg_map->sg_physaddr; 88039223Sgibbs 88139223Sgibbs newcount = (PAGE_SIZE / (BT_NSEG * sizeof(bt_sg_t))); 88239223Sgibbs for (i = 0; bt->num_ccbs < bt->max_ccbs && i < newcount; i++) { 88339223Sgibbs int error; 88439223Sgibbs 88539223Sgibbs next_ccb->sg_list = segs; 88639223Sgibbs next_ccb->sg_list_phys = physaddr; 88739223Sgibbs next_ccb->flags = BCCB_FREE; 88839223Sgibbs error = bus_dmamap_create(bt->buffer_dmat, /*flags*/0, 88939223Sgibbs &next_ccb->dmamap); 89039223Sgibbs if (error != 0) 89139223Sgibbs break; 89239223Sgibbs SLIST_INSERT_HEAD(&bt->free_bt_ccbs, next_ccb, links); 89339223Sgibbs segs += BT_NSEG; 89439223Sgibbs physaddr += (BT_NSEG * sizeof(bt_sg_t)); 89539223Sgibbs next_ccb++; 89639223Sgibbs bt->num_ccbs++; 89739223Sgibbs } 89839223Sgibbs 89939223Sgibbs /* Reserve a CCB for error recovery */ 90039223Sgibbs if (bt->recovery_bccb == NULL) { 90139223Sgibbs bt->recovery_bccb = SLIST_FIRST(&bt->free_bt_ccbs); 90239223Sgibbs SLIST_REMOVE_HEAD(&bt->free_bt_ccbs, links); 90339223Sgibbs } 90439223Sgibbs} 90539223Sgibbs 90639223Sgibbsstatic __inline void 90739223Sgibbsbtfreeccb(struct bt_softc *bt, struct bt_ccb *bccb) 90839223Sgibbs{ 90939223Sgibbs int s; 91039223Sgibbs 91139223Sgibbs s = splcam(); 91239223Sgibbs if ((bccb->flags & BCCB_ACTIVE) != 0) 91339223Sgibbs LIST_REMOVE(&bccb->ccb->ccb_h, sim_links.le); 91439223Sgibbs if (bt->resource_shortage != 0 91539223Sgibbs && (bccb->ccb->ccb_h.status & CAM_RELEASE_SIMQ) == 0) { 91639223Sgibbs bccb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 91739223Sgibbs bt->resource_shortage = FALSE; 91839223Sgibbs } 91939223Sgibbs bccb->flags = BCCB_FREE; 92039223Sgibbs SLIST_INSERT_HEAD(&bt->free_bt_ccbs, bccb, links); 92139223Sgibbs splx(s); 92239223Sgibbs} 92339223Sgibbs 92439223Sgibbsstatic __inline struct bt_ccb* 92539223Sgibbsbtgetccb(struct bt_softc *bt) 92639223Sgibbs{ 92739223Sgibbs struct bt_ccb* bccb; 92839223Sgibbs int s; 92939223Sgibbs 93039223Sgibbs s = splcam(); 93139223Sgibbs if ((bccb = SLIST_FIRST(&bt->free_bt_ccbs)) != NULL) { 93239223Sgibbs SLIST_REMOVE_HEAD(&bt->free_bt_ccbs, links); 93339223Sgibbs } else if (bt->num_ccbs < bt->max_ccbs) { 93439223Sgibbs btallocccbs(bt); 93539223Sgibbs bccb = SLIST_FIRST(&bt->free_bt_ccbs); 93639223Sgibbs if (bccb == NULL) 93739223Sgibbs printf("%s: Can't malloc BCCB\n", bt_name(bt)); 93839223Sgibbs else 93939223Sgibbs SLIST_REMOVE_HEAD(&bt->free_bt_ccbs, links); 94039223Sgibbs } 94139223Sgibbs splx(s); 94239223Sgibbs 94339223Sgibbs return (bccb); 94439223Sgibbs} 94539223Sgibbs 94639223Sgibbsstatic void 94739223Sgibbsbtaction(struct cam_sim *sim, union ccb *ccb) 94839223Sgibbs{ 94939223Sgibbs struct bt_softc *bt; 95039223Sgibbs int s; 95139223Sgibbs 95239223Sgibbs CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("btaction\n")); 95339223Sgibbs 95439223Sgibbs bt = (struct bt_softc *)cam_sim_softc(sim); 95539223Sgibbs 95639223Sgibbs switch (ccb->ccb_h.func_code) { 95739223Sgibbs /* Common cases first */ 95839223Sgibbs case XPT_SCSI_IO: /* Execute the requested I/O operation */ 95939223Sgibbs case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ 96039223Sgibbs { 96139223Sgibbs struct bt_ccb *bccb; 96239223Sgibbs struct bt_hccb *hccb; 96339223Sgibbs u_int16_t targ_mask; 96439223Sgibbs 96539223Sgibbs /* 96639223Sgibbs * get a bccb to use. 96739223Sgibbs */ 96839223Sgibbs if ((bccb = btgetccb(bt)) == NULL) { 96939223Sgibbs int s; 97039223Sgibbs 97139223Sgibbs s = splcam(); 97239223Sgibbs bt->resource_shortage = TRUE; 97339223Sgibbs splx(s); 97439223Sgibbs xpt_freeze_simq(bt->sim, /*count*/1); 97539223Sgibbs ccb->ccb_h.status = CAM_REQUEUE_REQ; 97639223Sgibbs xpt_done(ccb); 97739223Sgibbs return; 97839223Sgibbs } 97939223Sgibbs 98039223Sgibbs hccb = &bccb->hccb; 98139223Sgibbs 98239223Sgibbs /* 98339223Sgibbs * So we can find the BCCB when an abort is requested 98439223Sgibbs */ 98539223Sgibbs bccb->ccb = ccb; 98639223Sgibbs ccb->ccb_h.ccb_bccb_ptr = bccb; 98739223Sgibbs ccb->ccb_h.ccb_bt_ptr = bt; 98839223Sgibbs 98939223Sgibbs /* 99039223Sgibbs * Put all the arguments for the xfer in the bccb 99139223Sgibbs */ 99239223Sgibbs hccb->target_id = ccb->ccb_h.target_id; 99339223Sgibbs hccb->target_lun = ccb->ccb_h.target_lun; 99439223Sgibbs hccb->btstat = 0; 99539223Sgibbs hccb->sdstat = 0; 99639223Sgibbs targ_mask = (0x01 << hccb->target_id); 99739223Sgibbs 99839223Sgibbs if (ccb->ccb_h.func_code == XPT_SCSI_IO) { 99939223Sgibbs struct ccb_scsiio *csio; 100039223Sgibbs struct ccb_hdr *ccbh; 100139223Sgibbs 100239223Sgibbs csio = &ccb->csio; 100339223Sgibbs ccbh = &csio->ccb_h; 100439223Sgibbs hccb->opcode = INITIATOR_CCB_WRESID; 100539223Sgibbs hccb->datain = (ccb->ccb_h.flags & CAM_DIR_IN) != 0; 100639223Sgibbs hccb->dataout = (ccb->ccb_h.flags & CAM_DIR_OUT) != 0; 100739223Sgibbs hccb->cmd_len = csio->cdb_len; 100839223Sgibbs if (hccb->cmd_len > sizeof(hccb->scsi_cdb)) { 100939223Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 101039223Sgibbs btfreeccb(bt, bccb); 101139223Sgibbs xpt_done(ccb); 101239223Sgibbs return; 101339223Sgibbs } 101439223Sgibbs hccb->sense_len = csio->sense_len; 101539223Sgibbs if ((ccbh->flags & CAM_TAG_ACTION_VALID) != 0) { 101639223Sgibbs hccb->tag_enable = TRUE; 101739223Sgibbs hccb->tag_type = (ccb->csio.tag_action & 0x3); 101839223Sgibbs } else { 101939223Sgibbs hccb->tag_enable = FALSE; 102039223Sgibbs hccb->tag_type = 0; 102139223Sgibbs } 102239223Sgibbs if ((ccbh->flags & CAM_CDB_POINTER) != 0) { 102339223Sgibbs if ((ccbh->flags & CAM_CDB_PHYS) == 0) { 102439223Sgibbs bcopy(csio->cdb_io.cdb_ptr, 102539223Sgibbs hccb->scsi_cdb, hccb->cmd_len); 102639223Sgibbs } else { 102739223Sgibbs /* I guess I could map it in... */ 102839223Sgibbs ccbh->status = CAM_REQ_INVALID; 102939223Sgibbs btfreeccb(bt, bccb); 103039223Sgibbs xpt_done(ccb); 103139223Sgibbs return; 103239223Sgibbs } 103339223Sgibbs } else { 103439223Sgibbs bcopy(csio->cdb_io.cdb_bytes, 103539223Sgibbs hccb->scsi_cdb, hccb->cmd_len); 103639223Sgibbs } 103739223Sgibbs /* If need be, bounce our sense buffer */ 103839223Sgibbs if (bt->sense_buffers != NULL) { 103939223Sgibbs hccb->sense_addr = btsensepaddr(bt, bccb); 104039223Sgibbs } else { 104139223Sgibbs hccb->sense_addr = vtophys(&csio->sense_data); 104239223Sgibbs } 104339223Sgibbs /* 104439223Sgibbs * If we have any data to send with this command, 104539223Sgibbs * map it into bus space. 104639223Sgibbs */ 104739223Sgibbs /* Only use S/G if there is a transfer */ 104839223Sgibbs if ((ccbh->flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 104939223Sgibbs if ((ccbh->flags & CAM_SCATTER_VALID) == 0) { 105039223Sgibbs /* 105139223Sgibbs * We've been given a pointer 105239223Sgibbs * to a single buffer. 105339223Sgibbs */ 105439223Sgibbs if ((ccbh->flags & CAM_DATA_PHYS)==0) { 105539223Sgibbs int s; 105639223Sgibbs int error; 105739223Sgibbs 105839223Sgibbs s = splsoftvm(); 105939223Sgibbs error = bus_dmamap_load( 106039223Sgibbs bt->buffer_dmat, 106139223Sgibbs bccb->dmamap, 106239223Sgibbs csio->data_ptr, 106339223Sgibbs csio->dxfer_len, 106439223Sgibbs btexecuteccb, 106539223Sgibbs bccb, 106639223Sgibbs /*flags*/0); 106739223Sgibbs if (error == EINPROGRESS) { 106839223Sgibbs /* 106939223Sgibbs * So as to maintain 107039223Sgibbs * ordering, freeze the 107139223Sgibbs * controller queue 107239223Sgibbs * until our mapping is 107339223Sgibbs * returned. 107439223Sgibbs */ 107539223Sgibbs xpt_freeze_simq(bt->sim, 107639223Sgibbs 1); 107739223Sgibbs csio->ccb_h.status |= 107839223Sgibbs CAM_RELEASE_SIMQ; 107939223Sgibbs } 108039223Sgibbs splx(s); 108139223Sgibbs } else { 108239223Sgibbs struct bus_dma_segment seg; 108339223Sgibbs 108439223Sgibbs /* Pointer to physical buffer */ 108539223Sgibbs seg.ds_addr = 108639223Sgibbs (bus_addr_t)csio->data_ptr; 108739223Sgibbs seg.ds_len = csio->dxfer_len; 108839223Sgibbs btexecuteccb(bccb, &seg, 1, 0); 108939223Sgibbs } 109039223Sgibbs } else { 109139223Sgibbs struct bus_dma_segment *segs; 109239223Sgibbs 109339223Sgibbs if ((ccbh->flags & CAM_DATA_PHYS) != 0) 109439223Sgibbs panic("btaction - Physical " 109539223Sgibbs "segment pointers " 109639223Sgibbs "unsupported"); 109739223Sgibbs 109839223Sgibbs if ((ccbh->flags&CAM_SG_LIST_PHYS)==0) 109939223Sgibbs panic("btaction - Virtual " 110039223Sgibbs "segment addresses " 110139223Sgibbs "unsupported"); 110239223Sgibbs 110339223Sgibbs /* Just use the segments provided */ 110439223Sgibbs segs = (struct bus_dma_segment *) 110539223Sgibbs csio->data_ptr; 110639223Sgibbs btexecuteccb(bccb, segs, 110739223Sgibbs csio->sglist_cnt, 0); 110839223Sgibbs } 110939223Sgibbs } else { 111039223Sgibbs btexecuteccb(bccb, NULL, 0, 0); 111139223Sgibbs } 111239223Sgibbs } else { 111339223Sgibbs hccb->opcode = INITIATOR_BUS_DEV_RESET; 111439223Sgibbs /* No data transfer */ 111539223Sgibbs hccb->datain = TRUE; 111639223Sgibbs hccb->dataout = TRUE; 111739223Sgibbs hccb->cmd_len = 0; 111839223Sgibbs hccb->sense_len = 0; 111939223Sgibbs hccb->tag_enable = FALSE; 112039223Sgibbs hccb->tag_type = 0; 112139223Sgibbs btexecuteccb(bccb, NULL, 0, 0); 112239223Sgibbs } 112339223Sgibbs break; 112439223Sgibbs } 112539223Sgibbs case XPT_EN_LUN: /* Enable LUN as a target */ 112639223Sgibbs case XPT_TARGET_IO: /* Execute target I/O request */ 112739223Sgibbs case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */ 112839223Sgibbs case XPT_CONT_TARGET_IO: /* Continue Host Target I/O Connection*/ 112939223Sgibbs case XPT_ABORT: /* Abort the specified CCB */ 113039223Sgibbs /* XXX Implement */ 113139223Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 113239223Sgibbs xpt_done(ccb); 113339223Sgibbs break; 113439223Sgibbs case XPT_SET_TRAN_SETTINGS: 113539223Sgibbs { 113639223Sgibbs /* XXX Implement */ 113739223Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 113839223Sgibbs xpt_done(ccb); 113939223Sgibbs break; 114039223Sgibbs } 114139223Sgibbs case XPT_GET_TRAN_SETTINGS: 114239223Sgibbs /* Get default/user set transfer settings for the target */ 114339223Sgibbs { 114439223Sgibbs struct ccb_trans_settings *cts; 114539223Sgibbs u_int target_mask; 114639223Sgibbs 114739223Sgibbs cts = &ccb->cts; 114839223Sgibbs target_mask = 0x01 << ccb->ccb_h.target_id; 114939223Sgibbs if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) { 115039223Sgibbs cts->flags = 0; 115139223Sgibbs if ((bt->disc_permitted & target_mask) != 0) 115239223Sgibbs cts->flags |= CCB_TRANS_DISC_ENB; 115339223Sgibbs if ((bt->tags_permitted & target_mask) != 0) 115439223Sgibbs cts->flags |= CCB_TRANS_TAG_ENB; 115539223Sgibbs if ((bt->wide_permitted & target_mask) != 0) 115639223Sgibbs cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 115739223Sgibbs else 115839223Sgibbs cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 115939223Sgibbs if ((bt->ultra_permitted & target_mask) != 0) 116039223Sgibbs cts->sync_period = 12; 116139223Sgibbs else if ((bt->fast_permitted & target_mask) != 0) 116239223Sgibbs cts->sync_period = 25; 116339223Sgibbs else if ((bt->sync_permitted & target_mask) != 0) 116439223Sgibbs cts->sync_period = 50; 116539223Sgibbs else 116639223Sgibbs cts->sync_period = 0; 116739223Sgibbs 116839223Sgibbs if (cts->sync_period != 0) 116939223Sgibbs cts->sync_offset = 15; 117039223Sgibbs 117139223Sgibbs cts->valid = CCB_TRANS_SYNC_RATE_VALID 117239223Sgibbs | CCB_TRANS_SYNC_OFFSET_VALID 117339223Sgibbs | CCB_TRANS_BUS_WIDTH_VALID 117439223Sgibbs | CCB_TRANS_DISC_VALID 117539223Sgibbs | CCB_TRANS_TQ_VALID; 117639223Sgibbs } else { 117739223Sgibbs btfetchtransinfo(bt, cts); 117839223Sgibbs } 117939223Sgibbs 118039223Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 118139223Sgibbs xpt_done(ccb); 118239223Sgibbs break; 118339223Sgibbs } 118439223Sgibbs case XPT_CALC_GEOMETRY: 118539223Sgibbs { 118639223Sgibbs struct ccb_calc_geometry *ccg; 118739223Sgibbs u_int32_t size_mb; 118839223Sgibbs u_int32_t secs_per_cylinder; 118939223Sgibbs 119039223Sgibbs ccg = &ccb->ccg; 119139223Sgibbs size_mb = ccg->volume_size 119239223Sgibbs / ((1024L * 1024L) / ccg->block_size); 119339223Sgibbs 119439223Sgibbs if (size_mb >= 1024 && (bt->extended_trans != 0)) { 119539223Sgibbs if (size_mb >= 2048) { 119639223Sgibbs ccg->heads = 255; 119739223Sgibbs ccg->secs_per_track = 63; 119839223Sgibbs } else { 119939223Sgibbs ccg->heads = 128; 120039223Sgibbs ccg->secs_per_track = 32; 120139223Sgibbs } 120239223Sgibbs } else { 120339223Sgibbs ccg->heads = 64; 120439223Sgibbs ccg->secs_per_track = 32; 120539223Sgibbs } 120639223Sgibbs secs_per_cylinder = ccg->heads * ccg->secs_per_track; 120739223Sgibbs ccg->cylinders = ccg->volume_size / secs_per_cylinder; 120839223Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 120939223Sgibbs xpt_done(ccb); 121039223Sgibbs break; 121139223Sgibbs } 121239223Sgibbs case XPT_RESET_BUS: /* Reset the specified SCSI bus */ 121339223Sgibbs { 121439223Sgibbs btreset(bt, /*hardreset*/TRUE); 121539223Sgibbs ccb->ccb_h.status = CAM_REQ_CMP; 121639223Sgibbs xpt_done(ccb); 121739223Sgibbs break; 121839223Sgibbs } 121939223Sgibbs case XPT_TERM_IO: /* Terminate the I/O process */ 122039223Sgibbs /* XXX Implement */ 122139223Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 122239223Sgibbs xpt_done(ccb); 122339223Sgibbs break; 122439223Sgibbs case XPT_PATH_INQ: /* Path routing inquiry */ 122539223Sgibbs { 122639223Sgibbs struct ccb_pathinq *cpi = &ccb->cpi; 122739223Sgibbs 122839223Sgibbs cpi->version_num = 1; /* XXX??? */ 122939223Sgibbs cpi->hba_inquiry = PI_SDTR_ABLE; 123039223Sgibbs if (bt->tag_capable != 0) 123139223Sgibbs cpi->hba_inquiry |= PI_TAG_ABLE; 123239223Sgibbs if (bt->wide_bus != 0) 123339223Sgibbs cpi->hba_inquiry |= PI_WIDE_16; 123439223Sgibbs cpi->target_sprt = 0; 123539223Sgibbs cpi->hba_misc = 0; 123639223Sgibbs cpi->hba_eng_cnt = 0; 123739223Sgibbs cpi->max_target = bt->wide_bus ? 15 : 7; 123839223Sgibbs cpi->max_lun = 7; 123939223Sgibbs cpi->initiator_id = bt->scsi_id; 124039223Sgibbs cpi->bus_id = cam_sim_bus(sim); 124139223Sgibbs strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 124239223Sgibbs strncpy(cpi->hba_vid, "BusLogic", HBA_IDLEN); 124339223Sgibbs strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 124439223Sgibbs cpi->unit_number = cam_sim_unit(sim); 124539223Sgibbs cpi->ccb_h.status = CAM_REQ_CMP; 124639223Sgibbs xpt_done(ccb); 124739223Sgibbs break; 124839223Sgibbs } 124939223Sgibbs default: 125039223Sgibbs ccb->ccb_h.status = CAM_REQ_INVALID; 125139223Sgibbs xpt_done(ccb); 125239223Sgibbs break; 125339223Sgibbs } 125439223Sgibbs} 125539223Sgibbs 125639223Sgibbsstatic void 125739223Sgibbsbtexecuteccb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) 125839223Sgibbs{ 125939223Sgibbs struct bt_ccb *bccb; 126039223Sgibbs union ccb *ccb; 126139223Sgibbs struct bt_softc *bt; 126239223Sgibbs int s, i; 126339223Sgibbs 126439223Sgibbs bccb = (struct bt_ccb *)arg; 126539223Sgibbs ccb = bccb->ccb; 126639223Sgibbs bt = (struct bt_softc *)ccb->ccb_h.ccb_bt_ptr; 126739223Sgibbs 126839223Sgibbs if (error != 0) { 126939223Sgibbs if (error != EFBIG) 127039223Sgibbs printf("%s: Unexepected error 0x%x returned from " 127139223Sgibbs "bus_dmamap_load\n", bt_name(bt)); 127239223Sgibbs if (ccb->ccb_h.status == CAM_REQ_INPROG) { 127339223Sgibbs xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); 127439223Sgibbs ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN; 127539223Sgibbs } 127639223Sgibbs btfreeccb(bt, bccb); 127739223Sgibbs xpt_done(ccb); 127839223Sgibbs return; 127939223Sgibbs } 128039223Sgibbs 128139223Sgibbs if (nseg != 0) { 128239223Sgibbs bt_sg_t *sg; 128339223Sgibbs bus_dma_segment_t *end_seg; 128439223Sgibbs bus_dmasync_op_t op; 128539223Sgibbs 128639223Sgibbs end_seg = dm_segs + nseg; 128739223Sgibbs 128839223Sgibbs /* Copy the segments into our SG list */ 128939223Sgibbs sg = bccb->sg_list; 129039223Sgibbs while (dm_segs < end_seg) { 129139223Sgibbs sg->len = dm_segs->ds_len; 129239223Sgibbs sg->addr = dm_segs->ds_addr; 129339223Sgibbs sg++; 129439223Sgibbs dm_segs++; 129539223Sgibbs } 129639223Sgibbs 129739223Sgibbs if (nseg > 1) { 129839223Sgibbs bccb->hccb.opcode = INITIATOR_SG_CCB_WRESID; 129939223Sgibbs bccb->hccb.data_len = sizeof(bt_sg_t) * nseg; 130039223Sgibbs bccb->hccb.data_addr = bccb->sg_list_phys; 130139223Sgibbs } else { 130239223Sgibbs bccb->hccb.data_len = bccb->sg_list->len; 130339223Sgibbs bccb->hccb.data_addr = bccb->sg_list->addr; 130439223Sgibbs } 130539223Sgibbs 130639223Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 130739223Sgibbs op = BUS_DMASYNC_PREREAD; 130839223Sgibbs else 130939223Sgibbs op = BUS_DMASYNC_PREWRITE; 131039223Sgibbs 131139223Sgibbs bus_dmamap_sync(bt->buffer_dmat, bccb->dmamap, op); 131239223Sgibbs 131339223Sgibbs } else { 131439223Sgibbs bccb->hccb.opcode = INITIATOR_SG_CCB; 131539223Sgibbs bccb->hccb.data_len = 0; 131639223Sgibbs bccb->hccb.data_addr = 0; 131739223Sgibbs } 131839223Sgibbs 131939223Sgibbs s = splcam(); 132039223Sgibbs 132139223Sgibbs /* 132239223Sgibbs * Last time we need to check if this CCB needs to 132339223Sgibbs * be aborted. 132439223Sgibbs */ 132539223Sgibbs if (ccb->ccb_h.status != CAM_REQ_INPROG) { 132639223Sgibbs if (nseg != 0) 132739223Sgibbs bus_dmamap_unload(bt->buffer_dmat, bccb->dmamap); 132839223Sgibbs btfreeccb(bt, bccb); 132939223Sgibbs xpt_done(ccb); 133039223Sgibbs splx(s); 133139223Sgibbs return; 133239223Sgibbs } 133339223Sgibbs 133439223Sgibbs bccb->flags = BCCB_ACTIVE; 133539223Sgibbs ccb->ccb_h.status |= CAM_SIM_QUEUED; 133639223Sgibbs LIST_INSERT_HEAD(&bt->pending_ccbs, &ccb->ccb_h, sim_links.le); 133739223Sgibbs 133839223Sgibbs ccb->ccb_h.timeout_ch = 133939223Sgibbs timeout(bttimeout, (caddr_t)bccb, 134039223Sgibbs (ccb->ccb_h.timeout * hz) / 1000); 134139223Sgibbs 134239223Sgibbs /* Tell the adapter about this command */ 134339223Sgibbs bt->cur_outbox->ccb_addr = btccbvtop(bt, bccb); 134439223Sgibbs if (bt->cur_outbox->action_code != BMBO_FREE) 134539223Sgibbs panic("%s: Too few mailboxes or to many ccbs???", bt_name(bt)); 134639223Sgibbs bt->cur_outbox->action_code = BMBO_START; 134739223Sgibbs bt_outb(bt, COMMAND_REG, BOP_START_MBOX); 134839223Sgibbs btnextoutbox(bt); 134939223Sgibbs splx(s); 135039223Sgibbs} 135139223Sgibbs 135239223Sgibbsvoid 135339223Sgibbsbt_intr(void *arg) 135439223Sgibbs{ 135539223Sgibbs struct bt_softc *bt; 135639223Sgibbs u_int intstat; 135739223Sgibbs 135839223Sgibbs bt = (struct bt_softc *)arg; 135939223Sgibbs while (((intstat = bt_inb(bt, INTSTAT_REG)) & INTR_PENDING) != 0) { 136039223Sgibbs 136139223Sgibbs if ((intstat & CMD_COMPLETE) != 0) { 136239223Sgibbs bt->latched_status = bt_inb(bt, STATUS_REG); 136339223Sgibbs bt->command_cmp = TRUE; 136439223Sgibbs } 136539223Sgibbs 136639223Sgibbs bt_outb(bt, CONTROL_REG, RESET_INTR); 136739223Sgibbs 136839223Sgibbs if ((intstat & IMB_LOADED) != 0) { 136939223Sgibbs while (bt->cur_inbox->comp_code != BMBI_FREE) { 137039223Sgibbs btdone(bt, 137139223Sgibbs btccbptov(bt, bt->cur_inbox->ccb_addr), 137239223Sgibbs bt->cur_inbox->comp_code); 137339223Sgibbs bt->cur_inbox->comp_code = BMBI_FREE; 137439223Sgibbs btnextinbox(bt); 137539223Sgibbs } 137639223Sgibbs } 137739223Sgibbs 137839223Sgibbs if ((intstat & SCSI_BUS_RESET) != 0) { 137939223Sgibbs btreset(bt, /*hardreset*/FALSE); 138039223Sgibbs } 138139223Sgibbs } 138239223Sgibbs} 138339223Sgibbs 138439223Sgibbsstatic void 138539223Sgibbsbtdone(struct bt_softc *bt, struct bt_ccb *bccb, bt_mbi_comp_code_t comp_code) 138639223Sgibbs{ 138739223Sgibbs union ccb *ccb; 138839223Sgibbs struct ccb_scsiio *csio; 138939223Sgibbs 139039223Sgibbs ccb = bccb->ccb; 139139223Sgibbs csio = &bccb->ccb->csio; 139239223Sgibbs 139339223Sgibbs if ((bccb->flags & BCCB_ACTIVE) == 0) { 139439223Sgibbs printf("%s: btdone - Attempt to free non-active BCCB 0x%x\n", 139539223Sgibbs bt_name(bt), bccb); 139639223Sgibbs return; 139739223Sgibbs } 139839223Sgibbs 139939223Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 140039223Sgibbs bus_dmasync_op_t op; 140139223Sgibbs 140239223Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 140339223Sgibbs op = BUS_DMASYNC_POSTREAD; 140439223Sgibbs else 140539223Sgibbs op = BUS_DMASYNC_POSTWRITE; 140639223Sgibbs bus_dmamap_sync(bt->buffer_dmat, bccb->dmamap, op); 140739223Sgibbs bus_dmamap_unload(bt->buffer_dmat, bccb->dmamap); 140839223Sgibbs } 140939223Sgibbs 141039223Sgibbs if (bccb == bt->recovery_bccb) { 141139223Sgibbs /* 141239223Sgibbs * The recovery BCCB does not have a CCB associated 141339223Sgibbs * with it, so short circuit the normal error handling. 141439223Sgibbs * We now traverse our list of pending CCBs and process 141539223Sgibbs * any that were terminated by the recovery CCBs action. 141639223Sgibbs * We also reinstate timeouts for all remaining, pending, 141739223Sgibbs * CCBs. 141839223Sgibbs */ 141939223Sgibbs struct cam_path *path; 142039223Sgibbs struct ccb_hdr *ccb_h; 142139223Sgibbs cam_status error; 142239223Sgibbs 142339223Sgibbs /* Notify all clients that a BDR occured */ 142439223Sgibbs error = xpt_create_path(&path, /*periph*/NULL, 142539223Sgibbs cam_sim_path(bt->sim), 142639223Sgibbs bccb->hccb.target_id, 142739223Sgibbs CAM_LUN_WILDCARD); 142839223Sgibbs 142939223Sgibbs if (error == CAM_REQ_CMP) 143039223Sgibbs xpt_async(AC_SENT_BDR, path, NULL); 143139223Sgibbs 143239223Sgibbs ccb_h = LIST_FIRST(&bt->pending_ccbs); 143339223Sgibbs while (ccb_h != NULL) { 143439223Sgibbs struct bt_ccb *pending_bccb; 143539223Sgibbs 143639223Sgibbs pending_bccb = (struct bt_ccb *)ccb_h->ccb_bccb_ptr; 143739223Sgibbs if (pending_bccb->hccb.target_id 143839223Sgibbs == bccb->hccb.target_id) { 143939223Sgibbs pending_bccb->hccb.btstat = BTSTAT_HA_BDR; 144039223Sgibbs ccb_h = LIST_NEXT(ccb_h, sim_links.le); 144139223Sgibbs btdone(bt, pending_bccb, BMBI_ERROR); 144239223Sgibbs } else { 144339223Sgibbs ccb_h->timeout_ch = 144439223Sgibbs timeout(bttimeout, (caddr_t)pending_bccb, 144539223Sgibbs (ccb_h->timeout * hz) / 1000); 144639223Sgibbs ccb_h = LIST_NEXT(ccb_h, sim_links.le); 144739223Sgibbs } 144839223Sgibbs } 144939223Sgibbs printf("%s: No longer in timeout\n", bt_name(bt)); 145039223Sgibbs return; 145139223Sgibbs } 145239223Sgibbs 145339223Sgibbs untimeout(bttimeout, bccb, ccb->ccb_h.timeout_ch); 145439223Sgibbs 145539223Sgibbs switch (comp_code) { 145639223Sgibbs case BMBI_FREE: 145739223Sgibbs printf("%s: btdone - CCB completed with free status!\n", 145839223Sgibbs bt_name(bt)); 145939223Sgibbs break; 146039223Sgibbs case BMBI_NOT_FOUND: 146139223Sgibbs printf("%s: btdone - CCB Abort failed to find CCB\n", 146239223Sgibbs bt_name(bt)); 146339223Sgibbs break; 146439223Sgibbs case BMBI_ABORT: 146539223Sgibbs case BMBI_ERROR: 146639223Sgibbs#if 0 146739223Sgibbs printf("bt: ccb %x - error %x occured. btstat = %x, sdstat = %x\n", 146839223Sgibbs bccb, comp_code, bccb->hccb.btstat, bccb->hccb.sdstat); 146939223Sgibbs#endif 147039223Sgibbs /* An error occured */ 147139223Sgibbs switch(bccb->hccb.btstat) { 147239223Sgibbs case BTSTAT_DATARUN_ERROR: 147339223Sgibbs if (bccb->hccb.data_len <= 0) { 147439223Sgibbs csio->ccb_h.status = CAM_DATA_RUN_ERR; 147539223Sgibbs break; 147639223Sgibbs } 147739223Sgibbs /* FALLTHROUGH */ 147839223Sgibbs case BTSTAT_NOERROR: 147939223Sgibbs case BTSTAT_LINKED_CMD_COMPLETE: 148039223Sgibbs case BTSTAT_LINKED_CMD_FLAG_COMPLETE: 148139223Sgibbs case BTSTAT_DATAUNDERUN_ERROR: 148239223Sgibbs 148339223Sgibbs csio->scsi_status = bccb->hccb.sdstat; 148439223Sgibbs csio->ccb_h.status |= CAM_SCSI_STATUS_ERROR; 148539223Sgibbs switch(csio->scsi_status) { 148639223Sgibbs case SCSI_STATUS_CHECK_COND: 148739223Sgibbs case SCSI_STATUS_CMD_TERMINATED: 148839223Sgibbs csio->ccb_h.status |= CAM_AUTOSNS_VALID; 148939223Sgibbs /* Bounce sense back if necessary */ 149039223Sgibbs if (bt->sense_buffers != NULL) { 149139223Sgibbs csio->sense_data = 149239223Sgibbs *btsensevaddr(bt, bccb); 149339223Sgibbs } 149439223Sgibbs break; 149539223Sgibbs default: 149639223Sgibbs break; 149739223Sgibbs case SCSI_STATUS_OK: 149839223Sgibbs csio->ccb_h.status = CAM_REQ_CMP; 149939223Sgibbs break; 150039223Sgibbs } 150139223Sgibbs csio->resid = bccb->hccb.data_len; 150239223Sgibbs break; 150339223Sgibbs case BTSTAT_SELTIMEOUT: 150439223Sgibbs csio->ccb_h.status = CAM_SEL_TIMEOUT; 150539223Sgibbs break; 150639223Sgibbs case BTSTAT_UNEXPECTED_BUSFREE: 150739223Sgibbs csio->ccb_h.status = CAM_UNEXP_BUSFREE; 150839223Sgibbs break; 150939223Sgibbs case BTSTAT_INVALID_PHASE: 151039223Sgibbs csio->ccb_h.status = CAM_SEQUENCE_FAIL; 151139223Sgibbs break; 151239223Sgibbs case BTSTAT_INVALID_ACTION_CODE: 151339223Sgibbs panic("%s: Inavlid Action code", bt_name(bt)); 151439223Sgibbs break; 151539223Sgibbs case BTSTAT_INVALID_OPCODE: 151639223Sgibbs panic("%s: Inavlid CCB Opcode code", bt_name(bt)); 151739223Sgibbs break; 151839223Sgibbs case BTSTAT_LINKED_CCB_LUN_MISMATCH: 151939223Sgibbs /* We don't even support linked commands... */ 152039223Sgibbs panic("%s: Linked CCB Lun Mismatch", bt_name(bt)); 152139223Sgibbs break; 152239223Sgibbs case BTSTAT_INVALID_CCB_OR_SG_PARAM: 152339223Sgibbs panic("%s: Invalid CCB or SG list", bt_name(bt)); 152439223Sgibbs break; 152539223Sgibbs case BTSTAT_AUTOSENSE_FAILED: 152639223Sgibbs csio->ccb_h.status = CAM_AUTOSENSE_FAIL; 152739223Sgibbs break; 152839223Sgibbs case BTSTAT_TAGGED_MSG_REJECTED: 152939223Sgibbs { 153039223Sgibbs struct ccb_trans_settings neg; 153139223Sgibbs 153239223Sgibbs xpt_print_path(csio->ccb_h.path); 153339223Sgibbs printf("refuses tagged commands. Performing " 153439223Sgibbs "non-tagged I/O\n"); 153539223Sgibbs neg.flags = 0; 153639223Sgibbs neg.valid = CCB_TRANS_TQ_VALID; 153739223Sgibbs xpt_setup_ccb(&neg.ccb_h, csio->ccb_h.path, 153839223Sgibbs /*priority*/1); 153939223Sgibbs xpt_async(AC_TRANSFER_NEG, csio->ccb_h.path, &neg); 154039223Sgibbs bt->tags_permitted &= ~(0x01 << csio->ccb_h.target_id); 154139223Sgibbs csio->ccb_h.status = CAM_MSG_REJECT_REC; 154239223Sgibbs break; 154339223Sgibbs } 154439223Sgibbs case BTSTAT_UNSUPPORTED_MSG_RECEIVED: 154539223Sgibbs /* 154639223Sgibbs * XXX You would think that this is 154739223Sgibbs * a recoverable error... Hmmm. 154839223Sgibbs */ 154939223Sgibbs csio->ccb_h.status = CAM_REQ_CMP_ERR; 155039223Sgibbs break; 155139223Sgibbs case BTSTAT_HA_SOFTWARE_ERROR: 155239223Sgibbs case BTSTAT_HA_WATCHDOG_ERROR: 155339223Sgibbs case BTSTAT_HARDWARE_FAILURE: 155439223Sgibbs /* Hardware reset ??? Can we recover ??? */ 155539223Sgibbs csio->ccb_h.status = CAM_NO_HBA; 155639223Sgibbs break; 155739223Sgibbs case BTSTAT_TARGET_IGNORED_ATN: 155839223Sgibbs case BTSTAT_OTHER_SCSI_BUS_RESET: 155939223Sgibbs case BTSTAT_HA_SCSI_BUS_RESET: 156039223Sgibbs if ((csio->ccb_h.status & CAM_STATUS_MASK) 156139223Sgibbs != CAM_CMD_TIMEOUT) 156239223Sgibbs csio->ccb_h.status = CAM_SCSI_BUS_RESET; 156339223Sgibbs break; 156439223Sgibbs case BTSTAT_HA_BDR: 156539223Sgibbs if ((bccb->flags & BCCB_DEVICE_RESET) == 0) 156639223Sgibbs csio->ccb_h.status = CAM_BDR_SENT; 156739223Sgibbs else 156839223Sgibbs csio->ccb_h.status = CAM_CMD_TIMEOUT; 156939223Sgibbs break; 157039223Sgibbs case BTSTAT_INVALID_RECONNECT: 157139223Sgibbs case BTSTAT_ABORT_QUEUE_GENERATED: 157239223Sgibbs csio->ccb_h.status = CAM_REQ_TERMIO; 157339223Sgibbs break; 157439223Sgibbs case BTSTAT_SCSI_PERROR_DETECTED: 157539223Sgibbs csio->ccb_h.status = CAM_UNCOR_PARITY; 157639223Sgibbs break; 157739223Sgibbs } 157839223Sgibbs if (csio->ccb_h.status != CAM_REQ_CMP) { 157939223Sgibbs xpt_freeze_devq(csio->ccb_h.path, /*count*/1); 158039223Sgibbs csio->ccb_h.status |= CAM_DEV_QFRZN; 158139223Sgibbs } 158239223Sgibbs if ((bccb->flags & BCCB_RELEASE_SIMQ) != 0) 158339223Sgibbs ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 158439223Sgibbs btfreeccb(bt, bccb); 158539223Sgibbs xpt_done(ccb); 158639223Sgibbs break; 158739223Sgibbs case BMBI_OK: 158839223Sgibbs /* All completed without incident */ 158939223Sgibbs ccb->ccb_h.status |= CAM_REQ_CMP; 159039223Sgibbs if ((bccb->flags & BCCB_RELEASE_SIMQ) != 0) 159139223Sgibbs ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 159239223Sgibbs btfreeccb(bt, bccb); 159339223Sgibbs xpt_done(ccb); 159439223Sgibbs break; 159539223Sgibbs } 159639223Sgibbs} 159739223Sgibbs 159839223Sgibbsstatic int 159939223Sgibbsbtreset(struct bt_softc* bt, int hard_reset) 160039223Sgibbs{ 160139223Sgibbs struct ccb_hdr *ccb_h; 160239223Sgibbs u_int status; 160339223Sgibbs u_int timeout; 160439223Sgibbs u_int8_t reset_type; 160539223Sgibbs 160639223Sgibbs if (hard_reset != 0) 160739223Sgibbs reset_type = HARD_RESET; 160839223Sgibbs else 160939223Sgibbs reset_type = SOFT_RESET; 161039223Sgibbs bt_outb(bt, CONTROL_REG, reset_type); 161139223Sgibbs 161239223Sgibbs /* Wait 5sec. for Diagnostic start */ 161339223Sgibbs timeout = 5 * 10000; 161439223Sgibbs while (--timeout) { 161539223Sgibbs status = bt_inb(bt, STATUS_REG); 161639223Sgibbs if ((status & DIAG_ACTIVE) != 0) 161739223Sgibbs break; 161839223Sgibbs DELAY(100); 161939223Sgibbs } 162039223Sgibbs if (timeout == 0) { 162139223Sgibbs if (bootverbose) 162239223Sgibbs printf("%s: btreset - Diagnostic Active failed to " 162339223Sgibbs "assert. status = 0x%x\n", bt_name(bt), status); 162439223Sgibbs return (ETIMEDOUT); 162539223Sgibbs } 162639223Sgibbs 162739223Sgibbs /* Wait 10sec. for Diagnostic end */ 162839223Sgibbs timeout = 10 * 10000; 162939223Sgibbs while (--timeout) { 163039223Sgibbs status = bt_inb(bt, STATUS_REG); 163139223Sgibbs if ((status & DIAG_ACTIVE) == 0) 163239223Sgibbs break; 163339223Sgibbs DELAY(100); 163439223Sgibbs } 163539223Sgibbs if (timeout == 0) { 163639223Sgibbs panic("%s: btreset - Diagnostic Active failed to drop. " 163739223Sgibbs "status = 0x%x\n", bt_name(bt), status); 163839223Sgibbs return (ETIMEDOUT); 163939223Sgibbs } 164039223Sgibbs 164139223Sgibbs /* Wait for the host adapter to become ready or report a failure */ 164239223Sgibbs timeout = 10000; 164339223Sgibbs while (--timeout) { 164439223Sgibbs status = bt_inb(bt, STATUS_REG); 164539223Sgibbs if ((status & (DIAG_FAIL|HA_READY|DATAIN_REG_READY)) != 0) 164639223Sgibbs break; 164739223Sgibbs DELAY(100); 164839223Sgibbs } 164939223Sgibbs if (timeout == 0) { 165039223Sgibbs printf("%s: btreset - Host adapter failed to come ready. " 165139223Sgibbs "status = 0x%x\n", bt_name(bt), status); 165239223Sgibbs return (ETIMEDOUT); 165339223Sgibbs } 165439223Sgibbs 165539223Sgibbs /* If the diagnostics failed, tell the user */ 165639223Sgibbs if ((status & DIAG_FAIL) != 0 165739223Sgibbs || (status & HA_READY) == 0) { 165839223Sgibbs printf("%s: btreset - Adapter failed diagnostics\n", 165939223Sgibbs bt_name(bt)); 166039223Sgibbs 166139223Sgibbs if ((status & DATAIN_REG_READY) != 0) 166239223Sgibbs printf("%s: btreset - Host Adapter Error code = 0x%x\n", 166339223Sgibbs bt_inb(bt, DATAIN_REG)); 166439223Sgibbs return (ENXIO); 166539223Sgibbs } 166639223Sgibbs 166739223Sgibbs /* If we've allocated mailboxes, initialize them */ 166839223Sgibbs if (bt->init_level > 4) 166939223Sgibbs btinitmboxes(bt); 167039223Sgibbs 167139223Sgibbs /* If we've attached to the XPT, tell it about the event */ 167239223Sgibbs if (bt->path != NULL) 167339223Sgibbs xpt_async(AC_BUS_RESET, bt->path, NULL); 167439223Sgibbs 167539223Sgibbs /* 167639223Sgibbs * Perform completion processing for all outstanding CCBs. 167739223Sgibbs */ 167839223Sgibbs while ((ccb_h = LIST_FIRST(&bt->pending_ccbs)) != NULL) { 167939223Sgibbs struct bt_ccb *pending_bccb; 168039223Sgibbs 168139223Sgibbs pending_bccb = (struct bt_ccb *)ccb_h->ccb_bccb_ptr; 168239223Sgibbs pending_bccb->hccb.btstat = BTSTAT_HA_SCSI_BUS_RESET; 168339223Sgibbs btdone(bt, pending_bccb, BMBI_ERROR); 168439223Sgibbs } 168539223Sgibbs 168639223Sgibbs return (0); 168739223Sgibbs} 168839223Sgibbs 168939223Sgibbs/* 169039223Sgibbs * Send a command to the adapter. 169139223Sgibbs */ 169239223Sgibbsint 169339223Sgibbsbt_cmd(struct bt_softc *bt, bt_op_t opcode, u_int8_t *params, u_int param_len, 169439223Sgibbs u_int8_t *reply_data, u_int reply_len, u_int cmd_timeout) 169539223Sgibbs{ 169639223Sgibbs u_int timeout; 169739223Sgibbs u_int status; 169839223Sgibbs u_int intstat; 169939223Sgibbs u_int reply_buf_size; 170039223Sgibbs int s; 170139223Sgibbs 170239223Sgibbs /* No data returned to start */ 170339223Sgibbs reply_buf_size = reply_len; 170439223Sgibbs reply_len = 0; 170539223Sgibbs intstat = 0; 170639223Sgibbs 170739223Sgibbs bt->command_cmp = 0; 170839223Sgibbs /* 170939223Sgibbs * Wait up to 1 sec. for the adapter to become 171039223Sgibbs * ready to accept commands. 171139223Sgibbs */ 171239223Sgibbs timeout = 10000; 171339223Sgibbs while (--timeout) { 171439223Sgibbs 171539223Sgibbs status = bt_inb(bt, STATUS_REG); 171639223Sgibbs if ((status & HA_READY) != 0 171739223Sgibbs && (status & CMD_REG_BUSY) == 0) 171839223Sgibbs break; 171939223Sgibbs DELAY(100); 172039223Sgibbs } 172139223Sgibbs if (timeout == 0) { 172239223Sgibbs printf("%s: bt_cmd: Timeout waiting for adapter ready, " 172339223Sgibbs "status = 0x%x\n", bt_name(bt), status); 172439223Sgibbs return (ETIMEDOUT); 172539223Sgibbs } 172639223Sgibbs 172739223Sgibbs /* 172839223Sgibbs * Send the opcode followed by any necessary parameter bytes. 172939223Sgibbs */ 173039223Sgibbs bt_outb(bt, COMMAND_REG, opcode); 173139223Sgibbs 173239223Sgibbs /* 173339223Sgibbs * Wait for up to 1sec to get the parameter list sent 173439223Sgibbs */ 173539223Sgibbs timeout = 10000; 173639223Sgibbs while (param_len && --timeout) { 173739223Sgibbs DELAY(100); 173839223Sgibbs status = bt_inb(bt, STATUS_REG); 173939223Sgibbs intstat = bt_inb(bt, INTSTAT_REG); 174039223Sgibbs if ((intstat & (INTR_PENDING|CMD_COMPLETE)) 174139223Sgibbs == (INTR_PENDING|CMD_COMPLETE)) 174239223Sgibbs break; 174339223Sgibbs if (bt->command_cmp != 0) { 174439223Sgibbs status = bt->latched_status; 174539223Sgibbs break; 174639223Sgibbs } 174739223Sgibbs if ((status & DATAIN_REG_READY) != 0) 174839223Sgibbs break; 174939223Sgibbs if ((status & CMD_REG_BUSY) == 0) { 175039223Sgibbs bt_outb(bt, COMMAND_REG, *params++); 175139223Sgibbs param_len--; 175239223Sgibbs } 175339223Sgibbs } 175439223Sgibbs if (timeout == 0) { 175539223Sgibbs printf("%s: bt_cmd: Timeout sending parameters, " 175639223Sgibbs "status = 0x%x\n", bt_name(bt), status); 175739223Sgibbs return (ETIMEDOUT); 175839223Sgibbs } 175939223Sgibbs 176039223Sgibbs /* 176139223Sgibbs * The BOP_MODIFY_IO_ADDR does not issue a CMD_COMPLETE, but 176239223Sgibbs * it should update the status register. So, we wait for 176339223Sgibbs * the CMD_REG_BUSY status to clear and check for a command 176439223Sgibbs * failure. 176539223Sgibbs */ 176639223Sgibbs if (opcode == BOP_MODIFY_IO_ADDR) { 176739223Sgibbs 176839223Sgibbs while (--cmd_timeout) { 176939223Sgibbs status = bt_inb(bt, STATUS_REG); 177039223Sgibbs if ((status & CMD_REG_BUSY) == 0) { 177139223Sgibbs if ((status & CMD_INVALID) != 0) { 177239223Sgibbs printf("%s: bt_cmd - Modify I/O Address" 177339223Sgibbs " invalid\n", bt_name(bt)); 177439223Sgibbs return (EINVAL); 177539223Sgibbs } 177639223Sgibbs return (0); 177739223Sgibbs } 177839223Sgibbs DELAY(100); 177939223Sgibbs } 178039223Sgibbs if (timeout == 0) { 178139223Sgibbs printf("%s: bt_cmd: Timeout on Modify I/O Address CMD, " 178239223Sgibbs "status = 0x%x\n", bt_name(bt), status); 178339223Sgibbs return (ETIMEDOUT); 178439223Sgibbs } 178539223Sgibbs } 178639223Sgibbs 178739223Sgibbs /* 178839223Sgibbs * For all other commands, we wait for any output data 178939223Sgibbs * and the final comand completion interrupt. 179039223Sgibbs */ 179139223Sgibbs while (--cmd_timeout) { 179239223Sgibbs 179339223Sgibbs status = bt_inb(bt, STATUS_REG); 179439223Sgibbs intstat = bt_inb(bt, INTSTAT_REG); 179539223Sgibbs if ((intstat & (INTR_PENDING|CMD_COMPLETE)) 179639223Sgibbs == (INTR_PENDING|CMD_COMPLETE)) 179739223Sgibbs break; 179839223Sgibbs 179939223Sgibbs if (bt->command_cmp != 0) { 180039223Sgibbs status = bt->latched_status; 180139223Sgibbs break; 180239223Sgibbs } 180339223Sgibbs 180439223Sgibbs if ((status & DATAIN_REG_READY) != 0) { 180539223Sgibbs u_int8_t data; 180639223Sgibbs 180739223Sgibbs data = bt_inb(bt, DATAIN_REG); 180839223Sgibbs if (reply_len < reply_buf_size) { 180939223Sgibbs *reply_data++ = data; 181039223Sgibbs } else { 181139223Sgibbs printf("%s: bt_cmd - Discarded reply data byte " 181239223Sgibbs "for opcode 0x%x\n", bt_name(bt), 181339223Sgibbs opcode); 181439223Sgibbs } 181539223Sgibbs reply_len++; 181639223Sgibbs } 181739223Sgibbs 181839223Sgibbs if ((opcode == BOP_FETCH_LRAM) 181939223Sgibbs && (status & HA_READY) != 0) 182039223Sgibbs break; 182139223Sgibbs DELAY(100); 182239223Sgibbs } 182339223Sgibbs if (timeout == 0) { 182439223Sgibbs printf("%s: bt_cmd: Timeout waiting for reply data and " 182539223Sgibbs "command complete.\n%s: status = 0x%x, intstat = 0x%x, " 182639223Sgibbs "reply_len = %d\n", bt_name(bt), bt_name(bt), status, 182739223Sgibbs intstat, reply_len); 182839223Sgibbs return (ETIMEDOUT); 182939223Sgibbs } 183039223Sgibbs 183139223Sgibbs /* 183239223Sgibbs * Clear any pending interrupts. Block interrupts so our 183339223Sgibbs * interrupt handler is not re-entered. 183439223Sgibbs */ 183539223Sgibbs s = splcam(); 183639223Sgibbs bt_intr(bt); 183739223Sgibbs splx(s); 183839223Sgibbs 183939223Sgibbs /* 184039223Sgibbs * If the command was rejected by the controller, tell the caller. 184139223Sgibbs */ 184239223Sgibbs if ((status & CMD_INVALID) != 0) { 184339223Sgibbs /* 184439223Sgibbs * Some early adapters may not recover properly from 184539223Sgibbs * an invalid command. If it appears that the controller 184639223Sgibbs * has wedged (i.e. status was not cleared by our interrupt 184739223Sgibbs * reset above), perform a soft reset. 184839223Sgibbs */ 184939223Sgibbs if (bootverbose) 185039223Sgibbs printf("%s: Invalid Command 0x%x\n", bt_name(bt), 185139223Sgibbs opcode); 185239223Sgibbs DELAY(1000); 185339223Sgibbs status = bt_inb(bt, STATUS_REG); 185439223Sgibbs if ((status & (CMD_INVALID|STATUS_REG_RSVD|DATAIN_REG_READY| 185539223Sgibbs CMD_REG_BUSY|DIAG_FAIL|DIAG_ACTIVE)) != 0 185639223Sgibbs || (status & (HA_READY|INIT_REQUIRED)) 185739223Sgibbs != (HA_READY|INIT_REQUIRED)) { 185839223Sgibbs btreset(bt, /*hard_reset*/FALSE); 185939223Sgibbs } 186039223Sgibbs return (EINVAL); 186139223Sgibbs } 186239223Sgibbs 186339223Sgibbs 186439223Sgibbs if (param_len > 0) { 186539223Sgibbs /* The controller did not accept the full argument list */ 186639223Sgibbs return (E2BIG); 186739223Sgibbs } 186839223Sgibbs 186939223Sgibbs if (reply_len != reply_buf_size) { 187039223Sgibbs /* Too much or too little data received */ 187139223Sgibbs return (EMSGSIZE); 187239223Sgibbs } 187339223Sgibbs 187439223Sgibbs /* We were successful */ 187539223Sgibbs return (0); 187639223Sgibbs} 187739223Sgibbs 187839223Sgibbsstatic int 187939223Sgibbsbtinitmboxes(struct bt_softc *bt) { 188039223Sgibbs init_32b_mbox_params_t init_mbox; 188139223Sgibbs int error; 188239223Sgibbs 188339223Sgibbs bzero(bt->in_boxes, sizeof(bt_mbox_in_t) * bt->num_boxes); 188439223Sgibbs bzero(bt->out_boxes, sizeof(bt_mbox_out_t) * bt->num_boxes); 188539223Sgibbs bt->cur_inbox = bt->in_boxes; 188639223Sgibbs bt->last_inbox = bt->in_boxes + bt->num_boxes - 1; 188739223Sgibbs bt->cur_outbox = bt->out_boxes; 188839223Sgibbs bt->last_outbox = bt->out_boxes + bt->num_boxes - 1; 188939223Sgibbs 189039223Sgibbs /* Tell the adapter about them */ 189139223Sgibbs init_mbox.num_boxes = bt->num_boxes; 189239223Sgibbs init_mbox.base_addr[0] = bt->mailbox_physbase & 0xFF; 189339223Sgibbs init_mbox.base_addr[1] = (bt->mailbox_physbase >> 8) & 0xFF; 189439223Sgibbs init_mbox.base_addr[2] = (bt->mailbox_physbase >> 16) & 0xFF; 189539223Sgibbs init_mbox.base_addr[3] = (bt->mailbox_physbase >> 24) & 0xFF; 189639223Sgibbs error = bt_cmd(bt, BOP_INITIALIZE_32BMBOX, (u_int8_t *)&init_mbox, 189739223Sgibbs /*parmlen*/sizeof(init_mbox), /*reply_buf*/NULL, 189839223Sgibbs /*reply_len*/0, DEFAULT_CMD_TIMEOUT); 189939223Sgibbs 190039223Sgibbs if (error != 0) 190139223Sgibbs printf("btinitmboxes: Initialization command failed\n"); 190239223Sgibbs else if (bt->strict_rr != 0) { 190339223Sgibbs /* 190439223Sgibbs * If the controller supports 190539223Sgibbs * strict round robin mode, 190639223Sgibbs * enable it 190739223Sgibbs */ 190839223Sgibbs u_int8_t param; 190939223Sgibbs 191039223Sgibbs param = 0; 191139223Sgibbs error = bt_cmd(bt, BOP_ENABLE_STRICT_RR, ¶m, 1, 191239223Sgibbs /*reply_buf*/NULL, /*reply_len*/0, 191339223Sgibbs DEFAULT_CMD_TIMEOUT); 191439223Sgibbs 191539223Sgibbs if (error != 0) { 191639223Sgibbs printf("btinitmboxes: Unable to enable strict RR\n"); 191739223Sgibbs error = 0; 191839223Sgibbs } else if (bootverbose) { 191939223Sgibbs printf("%s: Using Strict Round Robin Mailbox Mode\n", 192039223Sgibbs bt_name(bt)); 192139223Sgibbs } 192239223Sgibbs } 192339223Sgibbs 192439223Sgibbs return (error); 192539223Sgibbs} 192639223Sgibbs 192739223Sgibbs/* 192839223Sgibbs * Update the XPT's idea of the negotiated transfer 192939223Sgibbs * parameters for a particular target. 193039223Sgibbs */ 193139223Sgibbsstatic void 193239223Sgibbsbtfetchtransinfo(struct bt_softc *bt, struct ccb_trans_settings* cts) 193339223Sgibbs{ 193439223Sgibbs setup_data_t setup_info; 193539223Sgibbs u_int target; 193639223Sgibbs u_int targ_offset; 193739223Sgibbs u_int targ_mask; 193839223Sgibbs u_int sync_period; 193939223Sgibbs int error; 194039223Sgibbs u_int8_t param; 194139223Sgibbs targ_syncinfo_t sync_info; 194239223Sgibbs 194339223Sgibbs target = cts->ccb_h.target_id; 194439223Sgibbs targ_offset = (target & 0x7); 194539223Sgibbs targ_mask = (0x01 << targ_offset); 194639223Sgibbs 194739223Sgibbs /* 194839223Sgibbs * Inquire Setup Information. This command retreives the 194939223Sgibbs * Wide negotiation status for recent adapters as well as 195039223Sgibbs * the sync info for older models. 195139223Sgibbs */ 195239223Sgibbs param = sizeof(setup_info); 195339223Sgibbs error = bt_cmd(bt, BOP_INQUIRE_SETUP_INFO, ¶m, /*paramlen*/1, 195439223Sgibbs (u_int8_t*)&setup_info, sizeof(setup_info), 195539223Sgibbs DEFAULT_CMD_TIMEOUT); 195639223Sgibbs 195739223Sgibbs if (error != 0) { 195839223Sgibbs printf("%s: btfetchtransinfo - Inquire Setup Info Failed\n", 195939223Sgibbs bt_name(bt)); 196039223Sgibbs return; 196139223Sgibbs } 196239223Sgibbs 196339223Sgibbs sync_info = (target < 8) ? setup_info.low_syncinfo[targ_offset] 196439223Sgibbs : setup_info.high_syncinfo[targ_offset]; 196539223Sgibbs 196639223Sgibbs if (sync_info.sync == 0) 196739223Sgibbs cts->sync_offset = 0; 196839223Sgibbs else 196939223Sgibbs cts->sync_offset = sync_info.offset; 197039223Sgibbs 197139223Sgibbs cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 197239223Sgibbs if (strcmp(bt->firmware_ver, "5.06L") >= 0) { 197339223Sgibbs u_int wide_active; 197439223Sgibbs 197539223Sgibbs wide_active = 197639223Sgibbs (target < 8) ? (setup_info.low_wide_active & targ_mask) 197739223Sgibbs : (setup_info.high_wide_active & targ_mask); 197839223Sgibbs 197939223Sgibbs if (wide_active) 198039223Sgibbs cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 198139223Sgibbs } 198239223Sgibbs 198339223Sgibbs if (bt->firmware_ver[0] >= 3) { 198439223Sgibbs /* 198539223Sgibbs * For adapters that can do fast or ultra speeds, 198639223Sgibbs * use the more exact Target Sync Information command. 198739223Sgibbs */ 198839223Sgibbs target_sync_info_data_t sync_info; 198939223Sgibbs 199039223Sgibbs param = sizeof(sync_info); 199139223Sgibbs error = bt_cmd(bt, BOP_TARG_SYNC_INFO, ¶m, /*paramlen*/1, 199239223Sgibbs (u_int8_t*)&sync_info, sizeof(sync_info), 199339223Sgibbs DEFAULT_CMD_TIMEOUT); 199439223Sgibbs 199539223Sgibbs if (error != 0) { 199639223Sgibbs printf("%s: btfetchtransinfo - Inquire Sync " 199739223Sgibbs "Info Failed 0x%x\n", bt_name(bt), error); 199839223Sgibbs return; 199939223Sgibbs } 200039223Sgibbs sync_period = sync_info.sync_rate[target] * 100; 200139223Sgibbs } else { 200239223Sgibbs sync_period = 2000 + (500 * sync_info.period); 200339223Sgibbs } 200439223Sgibbs 200539223Sgibbs /* Convert ns value to standard SCSI sync rate */ 200639223Sgibbs if (cts->sync_offset != 0) 200739223Sgibbs cts->sync_period = scsi_calc_syncparam(sync_period); 200839223Sgibbs else 200939223Sgibbs cts->sync_period = 0; 201039223Sgibbs 201139223Sgibbs cts->valid = CCB_TRANS_SYNC_RATE_VALID 201239223Sgibbs | CCB_TRANS_SYNC_OFFSET_VALID 201339223Sgibbs | CCB_TRANS_BUS_WIDTH_VALID; 201439223Sgibbs xpt_async(AC_TRANSFER_NEG, cts->ccb_h.path, cts); 201539223Sgibbs} 201639223Sgibbs 201739223Sgibbsstatic void 201839223Sgibbsbtmapmboxes(void *arg, bus_dma_segment_t *segs, int nseg, int error) 201939223Sgibbs{ 202039223Sgibbs struct bt_softc* bt; 202139223Sgibbs 202239223Sgibbs bt = (struct bt_softc*)arg; 202339223Sgibbs bt->mailbox_physbase = segs->ds_addr; 202439223Sgibbs} 202539223Sgibbs 202639223Sgibbsstatic void 202739223Sgibbsbtmapccbs(void *arg, bus_dma_segment_t *segs, int nseg, int error) 202839223Sgibbs{ 202939223Sgibbs struct bt_softc* bt; 203039223Sgibbs 203139223Sgibbs bt = (struct bt_softc*)arg; 203239223Sgibbs bt->bt_ccb_physbase = segs->ds_addr; 203339223Sgibbs} 203439223Sgibbs 203539223Sgibbsstatic void 203639223Sgibbsbtmapsgs(void *arg, bus_dma_segment_t *segs, int nseg, int error) 203739223Sgibbs{ 203839223Sgibbs 203939223Sgibbs struct bt_softc* bt; 204039223Sgibbs 204139223Sgibbs bt = (struct bt_softc*)arg; 204239223Sgibbs SLIST_FIRST(&bt->sg_maps)->sg_physaddr = segs->ds_addr; 204339223Sgibbs} 204439223Sgibbs 204539223Sgibbsstatic void 204639223Sgibbsbtpoll(struct cam_sim *sim) 204739223Sgibbs{ 204839223Sgibbs} 204939223Sgibbs 205039223Sgibbsvoid 205139223Sgibbsbttimeout(void *arg) 205239223Sgibbs{ 205339223Sgibbs struct bt_ccb *bccb; 205439223Sgibbs union ccb *ccb; 205539223Sgibbs struct bt_softc *bt; 205639223Sgibbs int s; 205739223Sgibbs 205839223Sgibbs bccb = (struct bt_ccb *)arg; 205939223Sgibbs ccb = bccb->ccb; 206039223Sgibbs bt = (struct bt_softc *)ccb->ccb_h.ccb_bt_ptr; 206139223Sgibbs xpt_print_path(ccb->ccb_h.path); 206239223Sgibbs printf("CCB 0x%x - timed out\n", bccb); 206339223Sgibbs 206439223Sgibbs s = splcam(); 206539223Sgibbs 206639223Sgibbs if ((bccb->flags & BCCB_ACTIVE) == 0) { 206739223Sgibbs xpt_print_path(ccb->ccb_h.path); 206839223Sgibbs printf("CCB 0x%x - timed out CCB already completed\n", bccb); 206939223Sgibbs splx(s); 207039223Sgibbs return; 207139223Sgibbs } 207239223Sgibbs 207339223Sgibbs /* 207439223Sgibbs * In order to simplify the recovery process, we ask the XPT 207539223Sgibbs * layer to halt the queue of new transactions and we traverse 207639223Sgibbs * the list of pending CCBs and remove their timeouts. This 207739223Sgibbs * means that the driver attempts to clear only one error 207839223Sgibbs * condition at a time. In general, timeouts that occur 207939223Sgibbs * close together are related anyway, so there is no benefit 208039223Sgibbs * in attempting to handle errors in parrallel. Timeouts will 208139223Sgibbs * be reinstated when the recovery process ends. 208239223Sgibbs */ 208339223Sgibbs if ((bccb->flags & BCCB_DEVICE_RESET) == 0) { 208439223Sgibbs struct ccb_hdr *ccb_h; 208539223Sgibbs 208639223Sgibbs if ((bccb->flags & BCCB_RELEASE_SIMQ) == 0) { 208739223Sgibbs xpt_freeze_simq(bt->sim, /*count*/1); 208839223Sgibbs bccb->flags |= BCCB_RELEASE_SIMQ; 208939223Sgibbs } 209039223Sgibbs 209139223Sgibbs ccb_h = LIST_FIRST(&bt->pending_ccbs); 209239223Sgibbs while (ccb_h != NULL) { 209339223Sgibbs struct bt_ccb *pending_bccb; 209439223Sgibbs 209539223Sgibbs pending_bccb = (struct bt_ccb *)ccb_h->ccb_bccb_ptr; 209639223Sgibbs untimeout(bttimeout, pending_bccb, ccb_h->timeout_ch); 209739223Sgibbs ccb_h = LIST_NEXT(ccb_h, sim_links.le); 209839223Sgibbs } 209939223Sgibbs } 210039223Sgibbs 210139223Sgibbs if ((bccb->flags & BCCB_DEVICE_RESET) != 0 210239223Sgibbs || bt->cur_outbox->action_code != BMBO_FREE 210339223Sgibbs || ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0 210439223Sgibbs && (bt->firmware_ver[0] < '5'))) { 210539223Sgibbs /* 210639223Sgibbs * Try a full host adapter/SCSI bus reset. 210739223Sgibbs * We do this only if we have already attempted 210839223Sgibbs * to clear the condition with a BDR, or we cannot 210939223Sgibbs * attempt a BDR for lack of mailbox resources 211039223Sgibbs * or because of faulty firmware. It turns out 211139223Sgibbs * that firmware versions prior to 5.xx treat BDRs 211239223Sgibbs * as untagged commands that cannot be sent until 211339223Sgibbs * all outstanding tagged commands have been processed. 211439223Sgibbs * This makes it somewhat difficult to use a BDR to 211539223Sgibbs * clear up a problem with an uncompleted tagged command. 211639223Sgibbs */ 211739223Sgibbs ccb->ccb_h.status = CAM_CMD_TIMEOUT; 211839223Sgibbs btreset(bt, /*hardreset*/TRUE); 211939223Sgibbs printf("%s: No longer in timeout\n", bt_name(bt)); 212039223Sgibbs } else { 212139223Sgibbs /* 212239223Sgibbs * Send a Bus Device Reset message: 212339223Sgibbs * The target that is holding up the bus may not 212439223Sgibbs * be the same as the one that triggered this timeout 212539223Sgibbs * (different commands have different timeout lengths), 212639223Sgibbs * but we have no way of determining this from our 212739223Sgibbs * timeout handler. Our strategy here is to queue a 212839223Sgibbs * BDR message to the target of the timed out command. 212939223Sgibbs * If this fails, we'll get another timeout 2 seconds 213039223Sgibbs * later which will attempt a bus reset. 213139223Sgibbs */ 213239223Sgibbs bccb->flags |= BCCB_DEVICE_RESET; 213339223Sgibbs ccb->ccb_h.timeout_ch = 213439223Sgibbs timeout(bttimeout, (caddr_t)bccb, 2 * hz); 213539223Sgibbs 213639223Sgibbs bt->recovery_bccb->hccb.opcode = INITIATOR_BUS_DEV_RESET; 213739223Sgibbs 213839223Sgibbs /* No Data Transfer */ 213939223Sgibbs bt->recovery_bccb->hccb.datain = TRUE; 214039223Sgibbs bt->recovery_bccb->hccb.dataout = TRUE; 214139223Sgibbs bt->recovery_bccb->hccb.btstat = 0; 214239223Sgibbs bt->recovery_bccb->hccb.sdstat = 0; 214339223Sgibbs bt->recovery_bccb->hccb.target_id = ccb->ccb_h.target_id; 214439223Sgibbs 214539223Sgibbs /* Tell the adapter about this command */ 214639223Sgibbs bt->cur_outbox->ccb_addr = btccbvtop(bt, bt->recovery_bccb); 214739223Sgibbs bt->cur_outbox->action_code = BMBO_START; 214839223Sgibbs bt_outb(bt, COMMAND_REG, BOP_START_MBOX); 214939223Sgibbs btnextoutbox(bt); 215039223Sgibbs } 215139223Sgibbs 215239223Sgibbs splx(s); 215339223Sgibbs} 215439223Sgibbs 2155