bt_mca.c revision 117126
1/*- 2 * Copyright (c) 1999 Matthew N. Dodd <winter@jurai.net> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: head/sys/dev/buslogic/bt_mca.c 117126 2003-07-01 15:52:06Z scottl $ 27 */ 28 29/* 30 * Written using the bt_isa/bt_pci code as a reference. 31 * 32 * Thanks to Andy Farkas <andyf@speednet.com.au> for 33 * testing and feedback. 34 */ 35 36#include <sys/types.h> 37#include <sys/param.h> 38#include <sys/systm.h> 39#include <sys/kernel.h> 40#include <sys/lock.h> 41#include <sys/mutex.h> 42 43#include <machine/cpufunc.h> 44#include <machine/md_var.h> 45 46#include <sys/module.h> 47#include <sys/bus.h> 48 49#include <machine/bus.h> 50#include <machine/resource.h> 51#include <sys/rman.h> 52 53#include <dev/mca/mca_busreg.h> 54#include <dev/mca/mca_busvar.h> 55 56#include <i386/isa/isa_dma.h> 57 58#include <dev/buslogic/btreg.h> 59 60#include <cam/scsi/scsi_all.h> 61 62static struct mca_ident bt_mca_devs[] = { 63 { 0x0708, "BusLogic 32 Bit Bus Master MCA-to-SCSI Host Adapter" }, 64 { 0x0708, "BusTek BT-640A Micro Channel to SCSI Host Adapter" }, 65 { 0x0708, "Storage Dimensions SDC3211B 32-bit SCSI Host Adapter" }, 66 { 0x0709, "Storage Dimensions SDC3211F 32-bit FAST SCSI Host Adapter" }, 67 { 0, NULL }, 68}; 69 70#define BT_MCA_IOPORT_POS1 MCA_ADP_POS(MCA_POS0) 71#define BT_MCA_IOPORT_POS2 MCA_ADP_POS(MCA_POS1) 72#define BT_MCA_IOPORT_MASK1 0x10 73#define BT_MCA_IOPORT_MASK2 0x03 74#define BT_MCA_IOPORT_SIZE 0x03 75#define BT_MCA_IOPORT(pos) (0x30 + \ 76 (((u_int32_t)pos &\ 77 BT_MCA_IOPORT_MASK2) << 8) + \ 78 (((u_int32_t)pos &\ 79 BT_MCA_IOPORT_MASK1) >> 2)) 80 81#define BT_MCA_IRQ_POS MCA_ADP_POS(MCA_POS0) 82#define BT_MCA_IRQ_MASK 0x0e 83#define BT_MCA_IRQ(pos) (((pos & BT_MCA_IRQ_MASK) >> 1) + 8) 84 85#define BT_MCA_DRQ_POS MCA_ADP_POS(MCA_POS3) 86#define BT_MCA_DRQ_MASK 0x0f 87#define BT_MCA_DRQ(pos) (pos & BT_MCA_DRQ_MASK) 88 89#define BT_MCA_SCSIID_POS MCA_ADP_POS(MCA_POS2) 90#define BT_MCA_SCSIID_MASK 0xe0 91#define BT_MCA_SCSIID(pos) ((pos & BT_MCA_SCSIID_MASK) >> 5) 92 93static bus_dma_filter_t btvlbouncefilter; 94static bus_dmamap_callback_t btmapsensebuffers; 95 96static void 97bt_mca_release_resources (device_t dev) 98{ 99 struct bt_softc * bt = device_get_softc(dev); 100 101 if (bt->port) 102 bus_release_resource(dev, SYS_RES_IOPORT, 0, bt->port); 103 if (bt->irq) 104 bus_release_resource(dev, SYS_RES_IRQ, 0, bt->irq); 105 if (bt->drq) 106 bus_release_resource(dev, SYS_RES_DRQ, 0, bt->drq); 107 108 bt_free_softc(dev); 109} 110 111#define BT_MCA_PROBE 0 112#define BT_MCA_ATTACH 1 113 114static int 115bt_mca_alloc_resources(device_t dev, int mode) 116{ 117 struct resource * io = NULL; 118 struct resource * irq = NULL; 119 struct resource * drq = NULL; 120 int rid; 121 122 rid = 0; 123 io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 124 0, ~0, 1, RF_ACTIVE); 125 if (io == NULL) { 126 printf("bt_mca_alloc_resources() failed to allocate IOPORT\n"); 127 return (ENOMEM); 128 } 129 130 if (mode == BT_MCA_ATTACH) { 131 132 rid = 0; 133 irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 134 0, ~0, 1, RF_ACTIVE); 135 if (irq == NULL) { 136 printf("bt_mca_alloc_resources() failed to allocate IRQ\n"); 137 goto bad; 138 } 139 140 rid = 0; 141 drq = bus_alloc_resource(dev, SYS_RES_DRQ, &rid, 142 0, ~0, 1, RF_ACTIVE); 143 if (drq == NULL) { 144 printf("bt_mca_alloc_resources() failed to allocate DRQ\n"); 145 goto bad; 146 } 147 } 148 149 bt_init_softc(dev, io, irq, drq); 150 151 return (0); 152bad: 153 bt_mca_release_resources(dev); 154 return (ENOMEM); 155} 156 157static int 158bt_mca_probe (device_t dev) 159{ 160 const char * desc; 161 mca_id_t id = mca_get_id(dev); 162 struct bt_probe_info info; 163 u_int32_t iobase = 0; 164 u_int32_t iosize = 0; 165 u_int8_t drq = 0; 166 u_int8_t irq = 0; 167 u_int8_t pos; 168 int result; 169 170 desc = mca_match_id(id, bt_mca_devs); 171 if (!desc) 172 return (ENXIO); 173 device_set_desc(dev, desc); 174 175 pos = (mca_pos_read(dev, BT_MCA_IOPORT_POS1) & BT_MCA_IOPORT_MASK1) | 176 (mca_pos_read(dev, BT_MCA_IOPORT_POS2) & BT_MCA_IOPORT_MASK2); 177 iobase = BT_MCA_IOPORT(pos); 178 iosize = BT_MCA_IOPORT_SIZE; 179 180 pos = mca_pos_read(dev, BT_MCA_DRQ_POS); 181 drq = BT_MCA_DRQ(pos); 182 183 pos = mca_pos_read(dev, BT_MCA_IRQ_POS); 184 irq = BT_MCA_IRQ(pos); 185 186 bt_mark_probed_iop(iobase); 187 188 mca_add_iospace(dev, iobase, iosize); 189 190 /* And allocate them */ 191 bt_mca_alloc_resources(dev, BT_MCA_PROBE); 192 193 if (bt_port_probe(dev, &info) != 0) { 194 printf("bt_mca_probe: Probe failed for " 195 "card at slot %d\n", mca_get_slot(dev) + 1); 196 result = ENXIO; 197 } else { 198 mca_add_drq(dev, drq); 199 mca_add_irq(dev, irq); 200 result = 0; 201 } 202 bt_mca_release_resources(dev); 203 204 return (result); 205} 206 207static int 208bt_mca_attach (device_t dev) 209{ 210 struct bt_softc * bt = device_get_softc(dev); 211 int error = 0; 212 213 /* Allocate resources */ 214 if ((error = bt_mca_alloc_resources(dev, BT_MCA_ATTACH))) { 215 device_printf(dev, "Unable to allocate resources in bt_mca_attach()\n"); 216 return (error); 217 } 218 219 isa_dmacascade(rman_get_start(bt->drq)); 220 221 /* Allocate a dmatag for our CCB DMA maps */ 222 if (bus_dma_tag_create( /* parent */ NULL, 223 /* alignemnt */ 1, 224 /* boundary */ 0, 225 /* lowaddr */ BUS_SPACE_MAXADDR_24BIT, 226 /* highaddr */ BUS_SPACE_MAXADDR, 227 /* filter */ btvlbouncefilter, 228 /* filterarg */ bt, 229 /* maxsize */ BUS_SPACE_MAXSIZE_32BIT, 230 /* nsegments */ ~0, 231 /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT, 232 /* flags */ 0, 233 /* lockfunc */ busdma_lock_mutex, 234 /* lockarg */ &Giant, 235 &bt->parent_dmat) != 0) { 236 bt_mca_release_resources(dev); 237 return (ENOMEM); 238 } 239 240 if (bt_init(dev)) { 241 bt_mca_release_resources(dev); 242 return (ENOMEM); 243 } 244 245 /* DMA tag for our sense buffers */ 246 if (bus_dma_tag_create( /* parent */ bt->parent_dmat, 247 /* alignment */ 1, 248 /* boundary */ 0, 249 /* lowaddr */ BUS_SPACE_MAXADDR, 250 /* highaddr */ BUS_SPACE_MAXADDR, 251 /* filter */ NULL, 252 /* filterarg */ NULL, 253 /* maxsize */ bt->max_ccbs * 254 sizeof(struct scsi_sense_data), 255 /* nsegments */ 1, 256 /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT, 257 /* flags */ 0, 258 /* lockfunc */ busdma_lock_mutex, 259 /* lockarg */ &Giant, 260 &bt->sense_dmat) != 0) { 261 bt_mca_release_resources(dev); 262 return (ENOMEM); 263 } 264 265 bt->init_level++; 266 267 /* Allocation of sense buffers */ 268 if (bus_dmamem_alloc(bt->sense_dmat, 269 (void **)&bt->sense_buffers, 270 BUS_DMA_NOWAIT, &bt->sense_dmamap) != 0) { 271 bt_mca_release_resources(dev); 272 return (ENOMEM); 273 } 274 275 bt->init_level++; 276 277 /* And permanently map them */ 278 bus_dmamap_load(bt->sense_dmat, bt->sense_dmamap, 279 bt->sense_buffers, 280 bt->max_ccbs * sizeof(*bt->sense_buffers), 281 btmapsensebuffers, bt, /*flags*/0); 282 283 bt->init_level++; 284 285 if ((error = bt_attach(dev))) { 286 bt_mca_release_resources(dev); 287 return (error); 288 } 289 290 return (0); 291} 292 293/* 294 * This code should be shared with the ISA 295 * stubs as its exactly the same. 296 */ 297 298#define BIOS_MAP_SIZE (16 * 1024) 299 300static int 301btvlbouncefilter(void *arg, bus_addr_t addr) 302{ 303 struct bt_softc *bt; 304 305 bt = (struct bt_softc *)arg; 306 307 addr &= BUS_SPACE_MAXADDR_24BIT; 308 309 if (addr == 0 310 || (addr >= bt->bios_addr 311 && addr < (bt->bios_addr + BIOS_MAP_SIZE))) 312 return (1); 313 return (0); 314} 315 316static void 317btmapsensebuffers(void *arg, bus_dma_segment_t *segs, int nseg, int error) 318{ 319 struct bt_softc* bt; 320 321 bt = (struct bt_softc*)arg; 322 bt->sense_buffers_physbase = segs->ds_addr; 323} 324 325static device_method_t bt_mca_methods[] = { 326 /* Device interface */ 327 DEVMETHOD(device_probe, bt_mca_probe), 328 DEVMETHOD(device_attach, bt_mca_attach), 329 330 { 0, 0 } 331}; 332 333static driver_t bt_mca_driver = { 334 "bt", 335 bt_mca_methods, 336 sizeof(struct bt_softc), 337}; 338 339static devclass_t bt_devclass; 340 341DRIVER_MODULE(bt, mca, bt_mca_driver, bt_devclass, 0, 0); 342