bt_isa.c revision 119418
1250008Sadrian/* 2250008Sadrian * Product specific probe and attach routines for: 3250008Sadrian * Buslogic BT-54X and BT-445 cards 4250008Sadrian * 5250008Sadrian * Copyright (c) 1998, 1999 Justin T. Gibbs 6250008Sadrian * All rights reserved. 7250008Sadrian * 8250008Sadrian * Redistribution and use in source and binary forms, with or without 9250008Sadrian * modification, are permitted provided that the following conditions 10250008Sadrian * are met: 11250008Sadrian * 1. Redistributions of source code must retain the above copyright 12250008Sadrian * notice, this list of conditions, and the following disclaimer, 13250008Sadrian * without modification, immediately at the beginning of the file. 14250008Sadrian * 2. The name of the author may not be used to endorse or promote products 15250008Sadrian * derived from this software without specific prior written permission. 16250008Sadrian * 17250008Sadrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18250008Sadrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19250008Sadrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20250008Sadrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 21250008Sadrian * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22250008Sadrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23250008Sadrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24250008Sadrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25250008Sadrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26250008Sadrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27250008Sadrian * SUCH DAMAGE. 28250008Sadrian * 29250008Sadrian */ 30250008Sadrian 31250008Sadrian#include <sys/cdefs.h> 32250008Sadrian__FBSDID("$FreeBSD: head/sys/dev/buslogic/bt_isa.c 119418 2003-08-24 17:55:58Z obrien $"); 33250008Sadrian 34250008Sadrian#include <sys/param.h> 35250008Sadrian#include <sys/systm.h> 36250008Sadrian#include <sys/kernel.h> 37250008Sadrian#include <sys/module.h> 38250008Sadrian#include <sys/lock.h> 39250008Sadrian#include <sys/mutex.h> 40250008Sadrian#include <sys/bus.h> 41250008Sadrian 42250008Sadrian#include <machine/bus_pio.h> 43250008Sadrian#include <machine/bus.h> 44250008Sadrian#include <machine/resource.h> 45250008Sadrian#include <sys/rman.h> 46250008Sadrian 47250008Sadrian#include <isa/isavar.h> 48250008Sadrian#include <dev/buslogic/btreg.h> 49250008Sadrian 50250008Sadrian#include <cam/scsi/scsi_all.h> 51250008Sadrian 52250008Sadrianstatic bus_dma_filter_t btvlbouncefilter; 53250008Sadrianstatic bus_dmamap_callback_t btmapsensebuffers; 54250008Sadrian 55250008Sadrianstatic int 56250008Sadrianbt_isa_alloc_resources(device_t dev, u_long portstart, u_long portend) 57250008Sadrian{ 58250008Sadrian int rid; 59250008Sadrian struct resource *port; 60250008Sadrian struct resource *irq; 61250008Sadrian struct resource *drq; 62250008Sadrian 63250008Sadrian rid = 0; 64250008Sadrian port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 65250008Sadrian portstart, portend, BT_NREGS, RF_ACTIVE); 66250008Sadrian if (!port) 67250008Sadrian return (ENOMEM); 68250008Sadrian 69250008Sadrian if (isa_get_irq(dev) != -1) { 70250008Sadrian rid = 0; 71250008Sadrian irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 72250008Sadrian 0, ~0, 1, RF_ACTIVE); 73250008Sadrian if (!irq) { 74250008Sadrian if (port) 75250008Sadrian bus_release_resource(dev, SYS_RES_IOPORT, 76250008Sadrian 0, port); 77250008Sadrian return (ENOMEM); 78250008Sadrian } 79250008Sadrian } else 80250008Sadrian irq = 0; 81250008Sadrian 82250008Sadrian if (isa_get_drq(dev) != -1) { 83250008Sadrian rid = 0; 84250008Sadrian drq = bus_alloc_resource(dev, SYS_RES_DRQ, &rid, 85250008Sadrian 0, ~0, 1, RF_ACTIVE); 86250008Sadrian if (!drq) { 87250008Sadrian if (port) 88250008Sadrian bus_release_resource(dev, SYS_RES_IOPORT, 89250008Sadrian 0, port); 90250008Sadrian if (irq) 91250008Sadrian bus_release_resource(dev, SYS_RES_IRQ, 92250008Sadrian 0, irq); 93250008Sadrian return (ENOMEM); 94250008Sadrian } 95250008Sadrian } else 96250008Sadrian drq = 0; 97250008Sadrian 98250008Sadrian bt_init_softc(dev, port, irq, drq); 99250008Sadrian 100250008Sadrian return (0); 101250008Sadrian} 102250008Sadrian 103250008Sadrianstatic void 104250008Sadrianbt_isa_release_resources(device_t dev) 105250008Sadrian{ 106250008Sadrian struct bt_softc *bt = device_get_softc(dev); 107250008Sadrian 108250008Sadrian if (bt->port) 109250008Sadrian bus_release_resource(dev, SYS_RES_IOPORT, 0, bt->port); 110250008Sadrian if (bt->irq) 111250008Sadrian bus_release_resource(dev, SYS_RES_IRQ, 0, bt->irq); 112250008Sadrian if (bt->drq) 113250008Sadrian bus_release_resource(dev, SYS_RES_DRQ, 0, bt->drq); 114250008Sadrian bt_free_softc(dev); 115250008Sadrian} 116250008Sadrian 117250008Sadrian/* 118250008Sadrian * Check if the device can be found at the port given 119250008Sadrian * and if so, set it up ready for further work 120250008Sadrian * as an argument, takes the isa_device structure from 121250008Sadrian * autoconf.c 122250008Sadrian */ 123250008Sadrianstatic int 124250008Sadrianbt_isa_probe(device_t dev) 125250008Sadrian{ 126250008Sadrian /* 127250008Sadrian * find unit and check we have that many defined 128250008Sadrian */ 129250008Sadrian int port_index; 130250008Sadrian int max_port_index; 131250008Sadrian 132250008Sadrian /* No pnp support */ 133250008Sadrian if (isa_get_vendorid(dev)) 134250008Sadrian return (ENXIO); 135250008Sadrian 136250008Sadrian port_index = 0; 137250008Sadrian max_port_index = BT_NUM_ISAPORTS - 1; 138250008Sadrian /* 139250008Sadrian * Bound our board search if the user has 140250008Sadrian * specified an exact port. 141250008Sadrian */ 142250008Sadrian bt_find_probe_range(isa_get_port(dev), &port_index, &max_port_index); 143250008Sadrian 144250008Sadrian if (port_index < 0) 145250008Sadrian return (ENXIO); 146250008Sadrian 147250008Sadrian /* Attempt to find an adapter */ 148250008Sadrian for (;port_index <= max_port_index; port_index++) { 149250008Sadrian struct bt_probe_info info; 150250008Sadrian u_int ioport; 151250008Sadrian 152250008Sadrian ioport = bt_iop_from_bio(port_index); 153250008Sadrian 154250008Sadrian /* 155250008Sadrian * Ensure this port has not already been claimed already 156250008Sadrian * by a PCI, EISA or ISA adapter. 157250008Sadrian */ 158250008Sadrian if (bt_check_probed_iop(ioport) != 0) 159250008Sadrian continue; 160250008Sadrian 161250008Sadrian /* Initialise the softc for use during probing */ 162250008Sadrian if (bt_isa_alloc_resources(dev, ioport, 163250008Sadrian ioport + BT_NREGS -1) != 0) 164250008Sadrian continue; 165250008Sadrian 166250008Sadrian /* We're going to attempt to probe it now, so mark it probed */ 167250008Sadrian bt_mark_probed_bio(port_index); 168250008Sadrian 169250008Sadrian if (bt_port_probe(dev, &info) != 0) { 170250008Sadrian if (bootverbose) 171250008Sadrian printf("bt_isa_probe: Probe failed at 0x%x\n", 172 ioport); 173 bt_isa_release_resources(dev); 174 continue; 175 } 176 177 bt_isa_release_resources(dev); 178 179 bus_set_resource(dev, SYS_RES_DRQ, 0, info.drq, 1); 180 bus_set_resource(dev, SYS_RES_IRQ, 0, info.irq, 1); 181 182 return (0); 183 } 184 185 return (ENXIO); 186} 187 188/* 189 * Attach all the sub-devices we can find 190 */ 191static int 192bt_isa_attach(device_t dev) 193{ 194 struct bt_softc *bt = device_get_softc(dev); 195 bus_dma_filter_t *filter; 196 void *filter_arg; 197 bus_addr_t lowaddr; 198 int error, drq; 199 200 /* Initialise softc */ 201 error = bt_isa_alloc_resources(dev, 0, ~0); 202 if (error) { 203 device_printf(dev, "can't allocate resources in bt_isa_attach\n"); 204 return error; 205 } 206 207 /* Program the DMA channel for external control */ 208 if ((drq = isa_get_drq(dev)) != -1) 209 isa_dmacascade(drq); 210 211 /* Allocate our parent dmatag */ 212 filter = NULL; 213 filter_arg = NULL; 214 lowaddr = BUS_SPACE_MAXADDR_24BIT; 215 if (bt->model[0] == '4') { 216 /* 217 * This is a VL adapter. Typically, VL devices have access 218 * to the full 32bit address space. On BT-445S adapters 219 * prior to revision E, there is a hardware bug that causes 220 * corruption of transfers to/from addresses in the range of 221 * the BIOS modulo 16MB. The only properly functioning 222 * BT-445S Host Adapters have firmware version 3.37. 223 * If we encounter one of these adapters and the BIOS is 224 * installed, install a filter function for our bus_dma_map 225 * that will catch these accesses and bounce them to a safe 226 * region of memory. 227 */ 228 if (bt->bios_addr != 0 229 && strcmp(bt->model, "445S") == 0 230 && strcmp(bt->firmware_ver, "3.37") < 0) { 231 filter = btvlbouncefilter; 232 filter_arg = bt; 233 } else { 234 lowaddr = BUS_SPACE_MAXADDR_32BIT; 235 } 236 } 237 238 /* XXX Should be a child of the ISA or VL bus dma tag */ 239 if (bus_dma_tag_create( /* parent */ NULL, 240 /* alignemnt */ 1, 241 /* boundary */ 0, 242 /* lowaddr */ lowaddr, 243 /* highaddr */ BUS_SPACE_MAXADDR, 244 /* filter */ filter, 245 /* filterarg */ filter_arg, 246 /* maxsize */ BUS_SPACE_MAXSIZE_32BIT, 247 /* nsegments */ ~0, 248 /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT, 249 /* flags */ 0, 250 /* lockfunc */ busdma_lock_mutex, 251 /* lockarg */ &Giant, 252 &bt->parent_dmat) != 0) { 253 bt_isa_release_resources(dev); 254 return (ENOMEM); 255 } 256 257 error = bt_init(dev); 258 if (error) { 259 bt_isa_release_resources(dev); 260 return (ENOMEM); 261 } 262 263 if (lowaddr != BUS_SPACE_MAXADDR_32BIT) { 264 /* DMA tag for our sense buffers */ 265 if (bus_dma_tag_create( 266 /* parent */ bt->parent_dmat, 267 /* alignment */ 1, 268 /* boundary */ 0, 269 /* lowaddr */ BUS_SPACE_MAXADDR, 270 /* highaddr */ BUS_SPACE_MAXADDR, 271 /* filter */ NULL, 272 /* filterarg */ NULL, 273 /* maxsize */ bt->max_ccbs * 274 sizeof(struct scsi_sense_data), 275 /* nsegments */ 1, 276 /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT, 277 /* flags */ 0, 278 /* lockfunc */ busdma_lock_mutex, 279 /* lockarg */ &Giant, 280 &bt->sense_dmat) != 0) { 281 bt_isa_release_resources(dev); 282 return (ENOMEM); 283 } 284 285 bt->init_level++; 286 287 /* Allocation of sense buffers */ 288 if (bus_dmamem_alloc(bt->sense_dmat, 289 (void **)&bt->sense_buffers, 290 BUS_DMA_NOWAIT, &bt->sense_dmamap) != 0) { 291 bt_isa_release_resources(dev); 292 return (ENOMEM); 293 } 294 295 bt->init_level++; 296 297 /* And permanently map them */ 298 bus_dmamap_load(bt->sense_dmat, bt->sense_dmamap, 299 bt->sense_buffers, 300 bt->max_ccbs * sizeof(*bt->sense_buffers), 301 btmapsensebuffers, bt, /*flags*/0); 302 303 bt->init_level++; 304 } 305 306 error = bt_attach(dev); 307 if (error) { 308 bt_isa_release_resources(dev); 309 return (error); 310 } 311 312 return (0); 313} 314 315#define BIOS_MAP_SIZE (16 * 1024) 316 317static int 318btvlbouncefilter(void *arg, bus_addr_t addr) 319{ 320 struct bt_softc *bt; 321 322 bt = (struct bt_softc *)arg; 323 324 addr &= BUS_SPACE_MAXADDR_24BIT; 325 326 if (addr == 0 327 || (addr >= bt->bios_addr 328 && addr < (bt->bios_addr + BIOS_MAP_SIZE))) 329 return (1); 330 return (0); 331} 332 333static void 334btmapsensebuffers(void *arg, bus_dma_segment_t *segs, int nseg, int error) 335{ 336 struct bt_softc* bt; 337 338 bt = (struct bt_softc*)arg; 339 bt->sense_buffers_physbase = segs->ds_addr; 340} 341 342static device_method_t bt_isa_methods[] = { 343 /* Device interface */ 344 DEVMETHOD(device_probe, bt_isa_probe), 345 DEVMETHOD(device_attach, bt_isa_attach), 346 347 { 0, 0 } 348}; 349 350static driver_t bt_isa_driver = { 351 "bt", 352 bt_isa_methods, 353 sizeof(struct bt_softc), 354}; 355 356static devclass_t bt_devclass; 357 358DRIVER_MODULE(bt, isa, bt_isa_driver, bt_devclass, 0, 0); 359