📄 bt.c
字号:
/* * Generic driver for the BusLogic MultiMaster SCSI host adapters * Product specific probe and attach routines can be found in: * i386/isa/bt_isa.c BT-54X, BT-445 cards * i386/eisa/bt_eisa.c BT-74x, BT-75x cards * pci/bt_pci.c BT-946, BT-948, BT-956, BT-958 cards * * Copyright (c) 1998, 1999 Justin T. Gibbs. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: bt.c,v 1.13.2.3 1999/05/07 00:43:31 ken Exp $ */ /* * Special thanks to Leonard N. Zubkoff for writing such a complete and * well documented Mylex/BusLogic MultiMaster driver for Linux. Support * in this driver for the wide range of MultiMaster controllers and * firmware revisions, with their otherwise undocumented quirks, would not * have been possible without his efforts. */#include <sys/param.h>#include <sys/systm.h> #include <sys/malloc.h>#include <sys/buf.h>#include <sys/kernel.h>#include <sys/sysctl.h> /* * XXX It appears that BusLogic PCI adapters go out to lunch if you * attempt to perform memory mapped I/O. */#if 0#include "pci.h"#if NPCI > 0#include <machine/bus_memio.h>#endif#endif#include <machine/bus_pio.h>#include <machine/bus.h>#include <machine/clock.h>#include <cam/cam.h>#include <cam/cam_ccb.h>#include <cam/cam_sim.h>#include <cam/cam_xpt_sim.h>#include <cam/cam_debug.h>#include <cam/scsi/scsi_message.h>#include <vm/vm.h>#include <vm/pmap.h> #include <dev/buslogic/btreg.h>#ifndef MAX#define MAX(a, b) ((a) > (b) ? (a) : (b))#endifstruct bt_softc *bt_softcs[NBT];/* MailBox Management functions */static __inline void btnextinbox(struct bt_softc *bt);static __inline void btnextoutbox(struct bt_softc *bt);static __inline voidbtnextinbox(struct bt_softc *bt){ if (bt->cur_inbox == bt->last_inbox) bt->cur_inbox = bt->in_boxes; else bt->cur_inbox++;}static __inline voidbtnextoutbox(struct bt_softc *bt){ if (bt->cur_outbox == bt->last_outbox) bt->cur_outbox = bt->out_boxes; else bt->cur_outbox++;}/* CCB Mangement functions */static __inline u_int32_t btccbvtop(struct bt_softc *bt, struct bt_ccb *bccb);static __inline struct bt_ccb* btccbptov(struct bt_softc *bt, u_int32_t ccb_addr);static __inline u_int32_t btsensepaddr(struct bt_softc *bt, struct bt_ccb *bccb);static __inline struct scsi_sense_data* btsensevaddr(struct bt_softc *bt, struct bt_ccb *bccb);static __inline u_int32_tbtccbvtop(struct bt_softc *bt, struct bt_ccb *bccb){ return (bt->bt_ccb_physbase + (u_int32_t)((caddr_t)bccb - (caddr_t)bt->bt_ccb_array));}static __inline struct bt_ccb *btccbptov(struct bt_softc *bt, u_int32_t ccb_addr){ return (bt->bt_ccb_array + ((struct bt_ccb*)ccb_addr-(struct bt_ccb*)bt->bt_ccb_physbase));}static __inline u_int32_tbtsensepaddr(struct bt_softc *bt, struct bt_ccb *bccb){ u_int index; index = (u_int)(bccb - bt->bt_ccb_array); return (bt->sense_buffers_physbase + (index * sizeof(struct scsi_sense_data)));}static __inline struct scsi_sense_data *btsensevaddr(struct bt_softc *bt, struct bt_ccb *bccb){ u_int index; index = (u_int)(bccb - bt->bt_ccb_array); return (bt->sense_buffers + index);}static __inline struct bt_ccb* btgetccb(struct bt_softc *bt);static __inline void btfreeccb(struct bt_softc *bt, struct bt_ccb *bccb);static void btallocccbs(struct bt_softc *bt);static bus_dmamap_callback_t btexecuteccb;static void btdone(struct bt_softc *bt, struct bt_ccb *bccb, bt_mbi_comp_code_t comp_code);/* Host adapter command functions */static int btreset(struct bt_softc* bt, int hard_reset);/* Initialization functions */static int btinitmboxes(struct bt_softc *bt);static bus_dmamap_callback_t btmapmboxes;static bus_dmamap_callback_t btmapccbs;static bus_dmamap_callback_t btmapsgs;/* Transfer Negotiation Functions */static void btfetchtransinfo(struct bt_softc *bt, struct ccb_trans_settings *cts);/* CAM SIM entry points */#define ccb_bccb_ptr spriv_ptr0#define ccb_bt_ptr spriv_ptr1static void btaction(struct cam_sim *sim, union ccb *ccb);static void btpoll(struct cam_sim *sim);/* Our timeout handler */timeout_t bttimeout;u_long bt_unit = 0;/* * XXX * Do our own re-probe protection until a configuration * manager can do it for us. This ensures that we don't * reprobe a card already found by the EISA or PCI probes. */struct bt_isa_port bt_isa_ports[] ={ { 0x130, 0, 4 }, { 0x134, 0, 5 }, { 0x230, 0, 2 }, { 0x234, 0, 3 }, { 0x330, 0, 0 }, { 0x334, 0, 1 }};/* * I/O ports listed in the order enumerated by the * card for certain op codes. */u_int16_t bt_board_ports[] ={ 0x330, 0x334, 0x230, 0x234, 0x130, 0x134};/* Exported functions */struct bt_softc *bt_alloc(int unit, bus_space_tag_t tag, bus_space_handle_t bsh){ struct bt_softc *bt; if (unit != BT_TEMP_UNIT) { if (unit >= NBT) { printf("bt: unit number (%d) too high\n", unit); return NULL; } /* * Allocate a storage area for us */ if (bt_softcs[unit]) { printf("bt%d: memory already allocated\n", unit); return NULL; } } bt = malloc(sizeof(struct bt_softc), M_DEVBUF, M_NOWAIT); if (!bt) { printf("bt%d: cannot malloc!\n", unit); return NULL; } bzero(bt, sizeof(struct bt_softc)); SLIST_INIT(&bt->free_bt_ccbs); LIST_INIT(&bt->pending_ccbs); SLIST_INIT(&bt->sg_maps); bt->unit = unit; bt->tag = tag; bt->bsh = bsh; if (bt->unit != BT_TEMP_UNIT) { bt_softcs[unit] = bt; } return (bt);}voidbt_free(struct bt_softc *bt){ switch (bt->init_level) { default: case 11: bus_dmamap_unload(bt->sense_dmat, bt->sense_dmamap); case 10: bus_dmamem_free(bt->sense_dmat, bt->sense_buffers, bt->sense_dmamap); case 9: bus_dma_tag_destroy(bt->sense_dmat); case 8: { struct sg_map_node *sg_map; while ((sg_map = SLIST_FIRST(&bt->sg_maps))!= NULL) { SLIST_REMOVE_HEAD(&bt->sg_maps, links); bus_dmamap_unload(bt->sg_dmat, sg_map->sg_dmamap); bus_dmamem_free(bt->sg_dmat, sg_map->sg_vaddr, sg_map->sg_dmamap); free(sg_map, M_DEVBUF); } bus_dma_tag_destroy(bt->sg_dmat); } case 7: bus_dmamap_unload(bt->ccb_dmat, bt->ccb_dmamap); case 6: bus_dmamem_free(bt->ccb_dmat, bt->bt_ccb_array, bt->ccb_dmamap); bus_dmamap_destroy(bt->ccb_dmat, bt->ccb_dmamap); case 5: bus_dma_tag_destroy(bt->ccb_dmat); case 4: bus_dmamap_unload(bt->mailbox_dmat, bt->mailbox_dmamap); case 3: bus_dmamem_free(bt->mailbox_dmat, bt->in_boxes, bt->mailbox_dmamap); bus_dmamap_destroy(bt->mailbox_dmat, bt->mailbox_dmamap); case 2: bus_dma_tag_destroy(bt->buffer_dmat); case 1: bus_dma_tag_destroy(bt->mailbox_dmat); case 0: break; } if (bt->unit != BT_TEMP_UNIT) { bt_softcs[bt->unit] = NULL; } free(bt, M_DEVBUF);}intbt_port_probe(struct bt_softc *bt, struct bt_probe_info *info){ config_data_t config_data; int error; /* See if there is really a card present */ if (bt_probe(bt) || bt_fetch_adapter_info(bt)) return(1); /* * Determine our IRQ, and DMA settings and * export them to the configuration system. */ error = bt_cmd(bt, BOP_INQUIRE_CONFIG, NULL, /*parmlen*/0, (u_int8_t*)&config_data, sizeof(config_data), DEFAULT_CMD_TIMEOUT); if (error != 0) { printf("bt_port_probe: Could not determine IRQ or DMA " "settings for adapter.\n"); return (1); } if (bt->model[0] == '5') { /* DMA settings only make sense for ISA cards */ switch (config_data.dma_chan) { case DMA_CHAN_5: info->drq = 5; break; case DMA_CHAN_6: info->drq = 6; break; case DMA_CHAN_7: info->drq = 7; break; default: printf("bt_port_probe: Invalid DMA setting " "detected for adapter.\n"); return (1); } } else { /* VL/EISA/PCI DMA */ info->drq = -1; } switch (config_data.irq) { case IRQ_9: case IRQ_10: case IRQ_11: case IRQ_12: case IRQ_14: case IRQ_15: info->irq = ffs(config_data.irq) + 8; break; default: printf("bt_port_probe: Invalid IRQ setting %x" "detected for adapter.\n", config_data.irq); return (1); } return (0);}/* * Probe the adapter and verify that the card is a BusLogic. */intbt_probe(struct bt_softc* bt){ esetup_info_data_t esetup_info; u_int status; u_int intstat; u_int geometry; int error; u_int8_t param; /* * See if the three I/O ports look reasonable. * Touch the minimal number of registers in the * failure case. */ status = bt_inb(bt, STATUS_REG); if ((status == 0) || (status & (DIAG_ACTIVE|CMD_REG_BUSY| STATUS_REG_RSVD|CMD_INVALID)) != 0) { if (bootverbose) printf("%s: Failed Status Reg Test - %x\n", bt_name(bt), status); return (ENXIO); } intstat = bt_inb(bt, INTSTAT_REG); if ((intstat & INTSTAT_REG_RSVD) != 0) { printf("%s: Failed Intstat Reg Test\n", bt_name(bt)); return (ENXIO); } geometry = bt_inb(bt, GEOMETRY_REG); if (geometry == 0xFF) { if (bootverbose) printf("%s: Failed Geometry Reg Test\n", bt_name(bt)); return (ENXIO); } /* * Looking good so far. Final test is to reset the * adapter and attempt to fetch the extended setup * information. This should filter out all 1542 cards. */ if ((error = btreset(bt, /*hard_reset*/TRUE)) != 0) { if (bootverbose) printf("%s: Failed Reset\n", bt_name(bt)); return (ENXIO); } param = sizeof(esetup_info); error = bt_cmd(bt, BOP_INQUIRE_ESETUP_INFO, ¶m, /*parmlen*/1, (u_int8_t*)&esetup_info, sizeof(esetup_info), DEFAULT_CMD_TIMEOUT); if (error != 0) { return (ENXIO); } return (0);}/* * Pull the boards setup information and record it in our softc. */intbt_fetch_adapter_info(struct bt_softc *bt){ board_id_data_t board_id; esetup_info_data_t esetup_info; config_data_t config_data; int error; u_int8_t length_param; /* First record the firmware version */ error = bt_cmd(bt, BOP_INQUIRE_BOARD_ID, NULL, /*parmlen*/0, (u_int8_t*)&board_id, sizeof(board_id), DEFAULT_CMD_TIMEOUT); if (error != 0) { printf("%s: bt_fetch_adapter_info - Failed Get Board Info\n", bt_name(bt)); return (error); } bt->firmware_ver[0] = board_id.firmware_rev_major; bt->firmware_ver[1] = '.'; bt->firmware_ver[2] = board_id.firmware_rev_minor; bt->firmware_ver[3] = '\0'; /* * Depending on the firmware major and minor version, * we may be able to fetch additional minor version info. */ if (bt->firmware_ver[0] > '0') { error = bt_cmd(bt, BOP_INQUIRE_FW_VER_3DIG, NULL, /*parmlen*/0, (u_int8_t*)&bt->firmware_ver[3], 1, DEFAULT_CMD_TIMEOUT); if (error != 0) { printf("%s: bt_fetch_adapter_info - Failed Get " "Firmware 3rd Digit\n", bt_name(bt)); return (error); } if (bt->firmware_ver[3] == ' ') bt->firmware_ver[3] = '\0'; bt->firmware_ver[4] = '\0'; } if (strcmp(bt->firmware_ver, "3.3") >= 0) { error = bt_cmd(bt, BOP_INQUIRE_FW_VER_4DIG, NULL, /*parmlen*/0, (u_int8_t*)&bt->firmware_ver[4], 1, DEFAULT_CMD_TIMEOUT); if (error != 0) { printf("%s: bt_fetch_adapter_info - Failed Get " "Firmware 4th Digit\n", bt_name(bt)); return (error); } if (bt->firmware_ver[4] == ' ') bt->firmware_ver[4] = '\0'; bt->firmware_ver[5] = '\0'; } /* * Some boards do not handle the "recently documented" * Inquire Board Model Number command correctly or do not give * exact information. Use the Firmware and Extended Setup * information in these cases to come up with the right answer. * The major firmware revision number indicates: * * 5.xx BusLogic "W" Series Host Adapters: * BT-948/958/958D * 4.xx BusLogic "C" Series Host Adapters: * BT-946C/956C/956CD/747C/757C/757CD/445C/545C/540CF * 3.xx BusLogic "S" Series Host Adapters: * BT-747S/747D/757S/757D/445S/545S/542D * BT-542B/742A (revision H) * 2.xx BusLogic "A" Series Host Adapters: * BT-542B/742A (revision G and below) * 0.xx AMI FastDisk VLB/EISA BusLogic Clone Host Adapter */ length_param = sizeof(esetup_info); error = bt_cmd(bt, BOP_INQUIRE_ESETUP_INFO, &length_param, /*parmlen*/1, (u_int8_t*)&esetup_info, sizeof(esetup_info), DEFAULT_CMD_TIMEOUT); if (error != 0) { return (error); } bt->bios_addr = esetup_info.bios_addr << 12; if (esetup_info.bus_type == 'A' && bt->firmware_ver[0] == '2') { snprintf(bt->model, sizeof(bt->model), "542B"); } else if (esetup_info.bus_type == 'E' && (strncmp(bt->firmware_ver, "2.1", 3) == 0 || strncmp(bt->firmware_ver, "2.20", 4) == 0)) { snprintf(bt->model, sizeof(bt->model), "742A"); } else if (esetup_info.bus_type == 'E' && bt->firmware_ver[0] == '0') { /* AMI FastDisk EISA Series 441 0.x */ snprintf(bt->model, sizeof(bt->model), "747A"); } else { ha_model_data_t model_data; int i; length_param = sizeof(model_data); error = bt_cmd(bt, BOP_INQUIRE_MODEL, &length_param, 1, (u_int8_t*)&model_data, sizeof(model_data), DEFAULT_CMD_TIMEOUT); if (error != 0) { printf("%s: bt_fetch_adapter_info - Failed Inquire " "Model Number\n", bt_name(bt)); return (error); } for (i = 0; i < sizeof(model_data.ascii_model); i++) { bt->model[i] = model_data.ascii_model[i]; if (bt->model[i] == ' ') break; } bt->model[i] = '\0'; } bt->level_trigger_ints = esetup_info.level_trigger_ints ? 1 : 0; /* SG element limits */ bt->max_sg = esetup_info.max_sg; /* Set feature flags */ bt->wide_bus = esetup_info.wide_bus; bt->diff_bus = esetup_info.diff_bus; bt->ultra_scsi = esetup_info.ultra_scsi; if ((bt->firmware_ver[0] == '5') || (bt->firmware_ver[0] == '4' && bt->wide_bus)) bt->extended_lun = TRUE; bt->strict_rr = (strcmp(bt->firmware_ver, "3.31") >= 0); bt->extended_trans = ((bt_inb(bt, GEOMETRY_REG) & EXTENDED_TRANSLATION) != 0); /* * Determine max CCB count and whether tagged queuing is * available based on controller type. Tagged queuing * only works on 'W' series adapters, 'C' series adapters * with firmware of rev 4.42 and higher, and 'S' series * adapters with firmware of rev 3.35 and higher. The * maximum CCB counts are as follows: * * 192 BT-948/958/958D * 100 BT-946C/956C/956CD/747C/757C/757CD/445C * 50 BT-545C/540CF * 30 BT-747S/747D/757S/757D/445S/545S/542D/542B/742A */ if (bt->firmware_ver[0] == '5') { bt->max_ccbs = 192; bt->tag_capable = TRUE; } else if (bt->firmware_ver[0] == '4') { if (bt->model[0] == '5') bt->max_ccbs = 50; else bt->max_ccbs = 100; bt->tag_capable = (strcmp(bt->firmware_ver, "4.22") >= 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -