bt_mca.c revision 50826
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 50826 1999-09-03 03:50:55Z mdodd $ 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 41#include <machine/cpufunc.h> 42#include <machine/md_var.h> 43 44#include <sys/module.h> 45#include <sys/bus.h> 46 47#include <machine/bus.h> 48#include <machine/resource.h> 49#include <sys/rman.h> 50 51#include <dev/mca/mca_busreg.h> 52#include <dev/mca/mca_busvar.h> 53 54#include <i386/isa/isa_dma.h> 55 56#include <dev/buslogic/btreg.h> 57 58#include <cam/scsi/scsi_all.h> 59 60static struct mca_ident bt_mca_devs[] = { 61 { 0x0708, "BusLogic 32 Bit Bus Master MCA-to-SCSI Host Adapter" }, 62 { 0x0708, "BusTek BT-640A Micro Channel to SCSI Host Adapter" }, 63 { 0x0708, "Storage Dimensions SDC3211B 32-bit SCSI Host Adapter" }, 64 { 0x0709, "Storage Dimensions SDC3211F 32-bit FAST SCSI Host Adapter" }, 65 { 0, NULL }, 66}; 67 68#define BT_MCA_IOPORT_POS1 MCA_ADP_POS(MCA_POS0) 69#define BT_MCA_IOPORT_POS2 MCA_ADP_POS(MCA_POS1) 70#define BT_MCA_IOPORT_MASK1 0x10 71#define BT_MCA_IOPORT_MASK2 0x03 72#define BT_MCA_IOPORT_SIZE 0x03 73#define BT_MCA_IOPORT(pos) (0x30 + \ 74 (((u_int32_t)pos &\ 75 BT_MCA_IOPORT_MASK2) << 8) + \ 76 (((u_int32_t)pos &\ 77 BT_MCA_IOPORT_MASK1) >> 2)) 78 79#define BT_MCA_IRQ_POS MCA_ADP_POS(MCA_POS0) 80#define BT_MCA_IRQ_MASK 0x0e 81#define BT_MCA_IRQ(pos) (((pos & BT_MCA_IRQ_MASK) >> 1) + 8) 82 83#define BT_MCA_DRQ_POS MCA_ADP_POS(MCA_POS3) 84#define BT_MCA_DRQ_MASK 0x0f 85#define BT_MCA_DRQ(pos) (pos & BT_MCA_DRQ_MASK) 86 87#define BT_MCA_SCSIID_POS MCA_ADP_POS(MCA_POS2) 88#define BT_MCA_SCSIID_MASK 0xe0 89#define BT_MCA_SCSIID(pos) ((pos & BT_MCA_SCSIID_MASK) >> 5) 90 91static bus_dma_filter_t btvlbouncefilter; 92static bus_dmamap_callback_t btmapsensebuffers; 93 94static void 95bt_mca_release_resources (device_t dev) 96{ 97 struct bt_softc * bt = device_get_softc(dev); 98 99 if (bt->port) 100 bus_release_resource(dev, SYS_RES_IOPORT, 0, bt->port); 101 if (bt->irq) 102 bus_release_resource(dev, SYS_RES_IRQ, 0, bt->irq); 103 if (bt->drq) 104 bus_release_resource(dev, SYS_RES_DRQ, 0, bt->drq); 105 106 bt_free_softc(dev); 107} 108 109static int 110bt_mca_alloc_resources(device_t dev) 111{ 112 struct resource * io = NULL; 113 struct resource * irq = NULL; 114 struct resource * drq = NULL; 115 int rid; 116 117 rid = 0; 118 io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 119 0, ~0, 1, RF_ACTIVE); 120 if (io == NULL) 121 return (ENOMEM); 122 123 if (mca_get_irq(dev) != -1) { 124 rid = 0; 125 irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 126 0, ~0, 1, RF_ACTIVE); 127 if (irq == NULL) 128 goto bad; 129 } else { 130 irq = 0; 131 } 132 133 if (mca_get_drq(dev) != -1) { 134 rid = 0; 135 drq = bus_alloc_resource(dev, SYS_RES_DRQ, &rid, 136 0, ~0, 1, RF_ACTIVE); 137 if (drq == NULL) 138 goto bad; 139 } else { 140 drq = 0; 141 } 142 143 bt_init_softc(dev, io, irq, drq); 144 145 return (0); 146bad: 147 bt_mca_release_resources(dev); 148 return (ENOMEM); 149} 150 151static int 152bt_mca_probe (device_t dev) 153{ 154 const char * desc; 155 mca_id_t id = mca_get_id(dev); 156 struct bt_probe_info info; 157 u_int32_t iobase = 0; 158 u_int32_t iosize = 0; 159 u_int8_t drq = 0; 160 u_int8_t irq = 0; 161 u_int8_t pos; 162 int result; 163 164 desc = mca_match_id(id, bt_mca_devs); 165 if (!desc) 166 return (ENXIO); 167 device_set_desc(dev, desc); 168 169 pos = (mca_pos_read(dev, BT_MCA_IOPORT_POS1) & BT_MCA_IOPORT_MASK1) | 170 (mca_pos_read(dev, BT_MCA_IOPORT_POS2) & BT_MCA_IOPORT_MASK2); 171 iobase = BT_MCA_IOPORT(pos); 172 iosize = BT_MCA_IOPORT_SIZE; 173 174 pos = mca_pos_read(dev, BT_MCA_DRQ_POS); 175 drq = BT_MCA_DRQ(pos); 176 177 pos = mca_pos_read(dev, BT_MCA_IRQ_POS); 178 irq = BT_MCA_IRQ(pos); 179 180 bt_mark_probed_iop(iobase); 181 182 mca_add_iospace(dev, iobase, iosize, RF_ALLOCATED); 183 184 /* And allocate them */ 185 bt_mca_alloc_resources(dev); 186 187 if (bt_port_probe(dev, &info) != 0) { 188 printf("bt_mca_probe: Probe failed for " 189 "card at slot %d\n", mca_get_slot(dev) + 1); 190 result = ENXIO; 191 } else { 192 mca_add_drq(dev, drq); 193 mca_add_irq(dev, irq); 194 result = 0; 195 } 196 bt_mca_release_resources(dev); 197 198 return (result); 199} 200 201static int 202bt_mca_attach (device_t dev) 203{ 204 struct bt_softc * bt = device_get_softc(dev); 205 int error = 0; 206 207 /* Allocate resources */ 208 if ((error = bt_mca_alloc_resources(dev))) { 209 device_printf(dev, "Unable to allocate resources in bt_mca_attach()\n"); 210 return (error); 211 } 212 213 isa_dmacascade(rman_get_start(bt->drq)); 214 215 /* Allocate a dmatag for our CCB DMA maps */ 216 if (bus_dma_tag_create(/*parent*/NULL, /*alignemnt*/1, /*boundary*/0, 217 /*lowaddr*/BUS_SPACE_MAXADDR_24BIT, 218 /*highaddr*/BUS_SPACE_MAXADDR, 219 /*filter*/btvlbouncefilter, 220 /*filterarg*/bt, 221 /*maxsize*/BUS_SPACE_MAXSIZE_32BIT, 222 /*nsegments*/BUS_SPACE_UNRESTRICTED, 223 /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, 224 /*flags*/0, &bt->parent_dmat) != 0) { 225 bt_mca_release_resources(dev); 226 return (ENOMEM); 227 } 228 229 if (bt_init(dev)) { 230 bt_mca_release_resources(dev); 231 return (ENOMEM); 232 } 233 234 /* DMA tag for our sense buffers */ 235 if (bus_dma_tag_create(bt->parent_dmat, /*alignment*/1, 236 /*boundary*/0, 237 /*lowaddr*/BUS_SPACE_MAXADDR, 238 /*highaddr*/BUS_SPACE_MAXADDR, 239 /*filter*/NULL, /*filterarg*/NULL, 240 bt->max_ccbs * sizeof(struct scsi_sense_data), 241 /*nsegments*/1, 242 /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, 243 /*flags*/0, &bt->sense_dmat) != 0) { 244 bt_mca_release_resources(dev); 245 return (ENOMEM); 246 } 247 248 bt->init_level++; 249 250 /* Allocation of sense buffers */ 251 if (bus_dmamem_alloc(bt->sense_dmat, 252 (void **)&bt->sense_buffers, 253 BUS_DMA_NOWAIT, &bt->sense_dmamap) != 0) { 254 bt_mca_release_resources(dev); 255 return (ENOMEM); 256 } 257 258 bt->init_level++; 259 260 /* And permanently map them */ 261 bus_dmamap_load(bt->sense_dmat, bt->sense_dmamap, 262 bt->sense_buffers, 263 bt->max_ccbs * sizeof(*bt->sense_buffers), 264 btmapsensebuffers, bt, /*flags*/0); 265 266 bt->init_level++; 267 268 if ((error = bt_attach(dev))) { 269 bt_mca_release_resources(dev); 270 return (error); 271 } 272 273 return (0); 274} 275 276/* 277 * This code should be shared with the ISA 278 * stubs as its exactly the same. 279 */ 280 281#define BIOS_MAP_SIZE (16 * 1024) 282 283static int 284btvlbouncefilter(void *arg, bus_addr_t addr) 285{ 286 struct bt_softc *bt; 287 288 bt = (struct bt_softc *)arg; 289 290 addr &= BUS_SPACE_MAXADDR_24BIT; 291 292 if (addr == 0 293 || (addr >= bt->bios_addr 294 && addr < (bt->bios_addr + BIOS_MAP_SIZE))) 295 return (1); 296 return (0); 297} 298 299static void 300btmapsensebuffers(void *arg, bus_dma_segment_t *segs, int nseg, int error) 301{ 302 struct bt_softc* bt; 303 304 bt = (struct bt_softc*)arg; 305 bt->sense_buffers_physbase = segs->ds_addr; 306} 307 308static device_method_t bt_mca_methods[] = { 309 /* Device interface */ 310 DEVMETHOD(device_probe, bt_mca_probe), 311 DEVMETHOD(device_attach, bt_mca_attach), 312 313 { 0, 0 } 314}; 315 316static driver_t bt_mca_driver = { 317 "bt", 318 bt_mca_methods, 319 sizeof(struct bt_softc), 320}; 321 322static devclass_t bt_devclass; 323 324DRIVER_MODULE(bt, mca, bt_mca_driver, bt_devclass, 0, 0); 325