bt_isa.c revision 39223
1/* 2 * Product specific probe and attach routines for: 3 * Buslogic BT-54X and BT-445 cards 4 * 5 * Copyright (c) 1998 Justin T. Gibbs 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions, and the following disclaimer, 13 * without modification, immediately at the beginning of the file. 14 * 2. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 21 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $Id$ 30 */ 31 32#include <sys/param.h> 33#include <sys/systm.h> 34 35#include <machine/bus_pio.h> 36#include <machine/bus.h> 37 38#include <i386/isa/isa_device.h> 39#include <dev/buslogic/btreg.h> 40 41#include <cam/scsi/scsi_all.h> 42 43#include "ioconf.h" 44 45static int bt_isa_probe __P((struct isa_device *dev)); 46static int bt_isa_attach __P((struct isa_device *dev)); 47static void bt_isa_intr __P((void *unit)); 48 49static bus_dma_filter_t btvlbouncefilter; 50static bus_dmamap_callback_t btmapsensebuffers; 51 52struct isa_driver btdriver = 53{ 54 bt_isa_probe, 55 bt_isa_attach, 56 "bt" 57}; 58 59/* 60 * Check if the device can be found at the port given 61 * and if so, set it up ready for further work 62 * as an argument, takes the isa_device structure from 63 * autoconf.c 64 */ 65static int 66bt_isa_probe(dev) 67 struct isa_device *dev; 68{ 69 /* 70 * find unit and check we have that many defined 71 */ 72 struct bt_softc *bt; 73 int port_index; 74 int max_port_index; 75 76 /* 77 * We ignore the unit number assigned by config to allow 78 * consistant numbering between PCI/EISA/ISA devices. 79 * This is a total kludge until we have a configuration 80 * manager. 81 */ 82 dev->id_unit = bt_unit; 83 84 bt = NULL; 85 port_index = 0; 86 max_port_index = BT_NUM_ISAPORTS - 1; 87 /* 88 * Bound our board search if the user has 89 * specified an exact port. 90 */ 91 if (dev->id_iobase > 0) { 92 for (;port_index <= max_port_index; port_index++) 93 if (dev->id_iobase >= bt_isa_ports[port_index].addr) 94 break; 95 if ((port_index > max_port_index) 96 || (dev->id_iobase != bt_isa_ports[port_index].addr)) { 97 printf(" 98bt_isa_probe: Invalid baseport of 0x%x specified. 99bt_isa_probe: Nearest valid baseport is 0x%x. 100bt_isa_probe: Failing probe.\n", 101 dev->id_iobase, 102 (port_index <= max_port_index) 103 ? bt_isa_ports[port_index].addr 104 : bt_isa_ports[max_port_index].addr); 105 return 0; 106 } 107 } 108 109 /* Attempt to find an adapter */ 110 for (;port_index <= max_port_index; port_index++) { 111 config_data_t config_data; 112 u_int ioport; 113 int error; 114 115 ioport = bt_isa_ports[port_index].addr; 116 117 /* 118 * Ensure this port has not already been claimed already 119 * by a PCI or EISA adapter. 120 */ 121 if (bt_check_probed_iop(ioport) != 0) 122 continue; 123 124 /* Allocate a softc for use during probing */ 125 bt = bt_alloc(dev->id_unit, I386_BUS_SPACE_IO, ioport); 126 127 if (bt == NULL) 128 break; 129 130 /* We're going to attempt to probe it now, so mark it probed */ 131 bt_mark_probed_bio(port_index); 132 133 /* See if there is really a card present */ 134 if (bt_probe(bt) || bt_fetch_adapter_info(bt)) { 135 bt_free(bt); 136 continue; 137 } 138 139 /* 140 * Determine our IRQ, and DMA settings and 141 * export them to the configuration system. 142 */ 143 error = bt_cmd(bt, BOP_INQUIRE_CONFIG, NULL, /*parmlen*/0, 144 (u_int8_t*)&config_data, sizeof(config_data), 145 DEFAULT_CMD_TIMEOUT); 146 if (error != 0) { 147 printf("bt_isa_probe: Could not determine IRQ or DMA " 148 "settings for adapter at 0x%x. Failing probe\n", 149 ioport); 150 bt_free(bt); 151 continue; 152 } 153 154 if (bt->model[0] == '5') { 155 /* DMA settings only make sense for ISA cards */ 156 switch (config_data.dma_chan) { 157 case DMA_CHAN_5: 158 dev->id_drq = 5; 159 break; 160 case DMA_CHAN_6: 161 dev->id_drq = 6; 162 break; 163 case DMA_CHAN_7: 164 dev->id_drq = 7; 165 break; 166 default: 167 printf("bt_isa_probe: Invalid DMA setting " 168 "detected for adapter at 0x%x. " 169 "Failing probe\n", ioport); 170 } 171 } else { 172 /* VL DMA */ 173 dev->id_drq = -1; 174 } 175 dev->id_iobase = bt_isa_ports[port_index].addr; 176 dev->id_irq = (config_data.irq << 9); 177 dev->id_intr = bt_isa_intr; 178 bt_unit++; 179 return (BT_NREGS); 180 } 181 182 return (0); 183} 184 185/* 186 * Attach all the sub-devices we can find 187 */ 188static int 189bt_isa_attach(dev) 190 struct isa_device *dev; 191{ 192 struct bt_softc *bt; 193 bus_dma_filter_t *filter; 194 void *filter_arg; 195 bus_addr_t lowaddr; 196 197 bt = bt_softcs[dev->id_unit]; 198 if (dev->id_drq != -1) 199 isa_dmacascade(dev->id_drq); 200 201 /* Allocate our parent dmatag */ 202 filter = NULL; 203 filter_arg = NULL; 204 lowaddr = BUS_SPACE_MAXADDR_24BIT; 205 if (bt->model[0] == '4') { 206 /* 207 * This is a VL adapter. Typically, VL devices have access 208 * to the full 32bit address space. On BT-445S adapters 209 * prior to revision E, there is a hardware bug that causes 210 * corruption of transfers to/from addresses in the range of 211 * the BIOS modulo 16MB. The only properly functioning 212 * BT-445S Host Adapters have firmware version 3.37. 213 * If we encounter one of these adapters and the BIOS is 214 * installed, install a filter function for our bus_dma_map 215 * that will catch these accesses and bounce them to a safe 216 * region of memory. 217 */ 218 if (bt->bios_addr != 0 219 && strcmp(bt->model, "445S") == 0 220 && strcmp(bt->firmware_ver, "3.37") < 0) { 221 filter = btvlbouncefilter; 222 filter_arg = bt; 223 } else { 224 lowaddr = BUS_SPACE_MAXADDR_32BIT; 225 } 226 } 227 228 /* XXX Should be a child of the ISA or VL bus dma tag */ 229 if (bus_dma_tag_create(/*parent*/NULL, /*alignemnt*/0, /*boundary*/0, 230 lowaddr, /*highaddr*/BUS_SPACE_MAXADDR, 231 filter, filter_arg, 232 /*maxsize*/BUS_SPACE_MAXSIZE_32BIT, 233 /*nsegments*/BUS_SPACE_UNRESTRICTED, 234 /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, 235 /*flags*/0, &bt->parent_dmat) != 0) { 236 bt_free(bt); 237 return (-1); 238 } 239 240 if (bt_init(bt)) { 241 bt_free(bt); 242 return (-1); 243 } 244 245 if (lowaddr != BUS_SPACE_MAXADDR_32BIT) { 246 /* DMA tag for our sense buffers */ 247 if (bus_dma_tag_create(bt->parent_dmat, /*alignment*/0, 248 /*boundary*/0, 249 /*lowaddr*/BUS_SPACE_MAXADDR, 250 /*highaddr*/BUS_SPACE_MAXADDR, 251 /*filter*/NULL, /*filterarg*/NULL, 252 bt->max_ccbs 253 * sizeof(struct scsi_sense_data), 254 /*nsegments*/1, 255 /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, 256 /*flags*/0, &bt->sense_dmat) != 0) { 257 bt_free(bt); 258 return (-1); 259 } 260 261 bt->init_level++; 262 263 /* Allocation of sense buffers */ 264 if (bus_dmamem_alloc(bt->sense_dmat, 265 (void **)&bt->sense_buffers, 266 BUS_DMA_NOWAIT, &bt->sense_dmamap) != 0) { 267 bt_free(bt); 268 return (-1); 269 } 270 271 bt->init_level++; 272 273 /* And permanently map them */ 274 bus_dmamap_load(bt->sense_dmat, bt->sense_dmamap, 275 bt->sense_buffers, 276 bt->max_ccbs * sizeof(*bt->sense_buffers), 277 btmapsensebuffers, bt, /*flags*/0); 278 279 bt->init_level++; 280 } 281 282 return (bt_attach(bt)); 283} 284 285/* 286 * Handle an ISA interrupt. 287 * XXX should go away as soon as ISA interrupt handlers 288 * take a (void *) arg. 289 */ 290static void 291bt_isa_intr(void *unit) 292{ 293 struct bt_softc* arg = bt_softcs[(int)unit]; 294 bt_intr((void *)arg); 295} 296 297#define BIOS_MAP_SIZE (16 * 1024) 298 299static int 300btvlbouncefilter(void *arg, bus_addr_t addr) 301{ 302 struct bt_softc *bt; 303 304 bt = (struct bt_softc *)arg; 305 306 addr &= BUS_SPACE_MAXADDR_24BIT; 307 308 if (addr == 0 309 || (addr >= bt->bios_addr 310 && addr < (bt->bios_addr + BIOS_MAP_SIZE))) 311 return (1); 312 return (0); 313} 314 315static void 316btmapsensebuffers(void *arg, bus_dma_segment_t *segs, int nseg, int error) 317{ 318 struct bt_softc* bt; 319 320 bt = (struct bt_softc*)arg; 321 bt->sense_buffers_physbase = segs->ds_addr; 322} 323