bt_mca.c revision 112782
150826Smdodd/*- 250826Smdodd * Copyright (c) 1999 Matthew N. Dodd <winter@jurai.net> 350826Smdodd * All rights reserved. 450826Smdodd * 550826Smdodd * Redistribution and use in source and binary forms, with or without 650826Smdodd * modification, are permitted provided that the following conditions 750826Smdodd * are met: 850826Smdodd * 1. Redistributions of source code must retain the above copyright 950826Smdodd * notice, this list of conditions and the following disclaimer. 1050826Smdodd * 2. Redistributions in binary form must reproduce the above copyright 1150826Smdodd * notice, this list of conditions and the following disclaimer in the 1250826Smdodd * documentation and/or other materials provided with the distribution. 1350826Smdodd * 1450826Smdodd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1550826Smdodd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1650826Smdodd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1750826Smdodd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1850826Smdodd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1950826Smdodd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2050826Smdodd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2150826Smdodd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2250826Smdodd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2350826Smdodd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2450826Smdodd * SUCH DAMAGE. 2550826Smdodd * 2650826Smdodd * $FreeBSD: head/sys/dev/buslogic/bt_mca.c 112782 2003-03-29 09:46:10Z mdodd $ 2750826Smdodd */ 2850826Smdodd 2950826Smdodd/* 3050826Smdodd * Written using the bt_isa/bt_pci code as a reference. 3150826Smdodd * 3250826Smdodd * Thanks to Andy Farkas <andyf@speednet.com.au> for 3350826Smdodd * testing and feedback. 3450826Smdodd */ 3550826Smdodd 3650826Smdodd#include <sys/types.h> 3750826Smdodd#include <sys/param.h> 3850826Smdodd#include <sys/systm.h> 3950826Smdodd#include <sys/kernel.h> 4050826Smdodd 4150826Smdodd#include <machine/cpufunc.h> 4250826Smdodd#include <machine/md_var.h> 4350826Smdodd 4450826Smdodd#include <sys/module.h> 4550826Smdodd#include <sys/bus.h> 4650826Smdodd 4750826Smdodd#include <machine/bus.h> 4850826Smdodd#include <machine/resource.h> 4950826Smdodd#include <sys/rman.h> 5050826Smdodd 5150826Smdodd#include <dev/mca/mca_busreg.h> 5250826Smdodd#include <dev/mca/mca_busvar.h> 5350826Smdodd 5450826Smdodd#include <i386/isa/isa_dma.h> 5550826Smdodd 5650826Smdodd#include <dev/buslogic/btreg.h> 5750826Smdodd 5850826Smdodd#include <cam/scsi/scsi_all.h> 5950826Smdodd 6050826Smdoddstatic struct mca_ident bt_mca_devs[] = { 6150826Smdodd { 0x0708, "BusLogic 32 Bit Bus Master MCA-to-SCSI Host Adapter" }, 6250826Smdodd { 0x0708, "BusTek BT-640A Micro Channel to SCSI Host Adapter" }, 6350826Smdodd { 0x0708, "Storage Dimensions SDC3211B 32-bit SCSI Host Adapter" }, 6450826Smdodd { 0x0709, "Storage Dimensions SDC3211F 32-bit FAST SCSI Host Adapter" }, 6550826Smdodd { 0, NULL }, 6650826Smdodd}; 6750826Smdodd 6850826Smdodd#define BT_MCA_IOPORT_POS1 MCA_ADP_POS(MCA_POS0) 6950826Smdodd#define BT_MCA_IOPORT_POS2 MCA_ADP_POS(MCA_POS1) 7050826Smdodd#define BT_MCA_IOPORT_MASK1 0x10 7150826Smdodd#define BT_MCA_IOPORT_MASK2 0x03 7250826Smdodd#define BT_MCA_IOPORT_SIZE 0x03 7350826Smdodd#define BT_MCA_IOPORT(pos) (0x30 + \ 7450826Smdodd (((u_int32_t)pos &\ 7550826Smdodd BT_MCA_IOPORT_MASK2) << 8) + \ 7650826Smdodd (((u_int32_t)pos &\ 7750826Smdodd BT_MCA_IOPORT_MASK1) >> 2)) 7850826Smdodd 7950826Smdodd#define BT_MCA_IRQ_POS MCA_ADP_POS(MCA_POS0) 8050826Smdodd#define BT_MCA_IRQ_MASK 0x0e 8150826Smdodd#define BT_MCA_IRQ(pos) (((pos & BT_MCA_IRQ_MASK) >> 1) + 8) 8250826Smdodd 8350826Smdodd#define BT_MCA_DRQ_POS MCA_ADP_POS(MCA_POS3) 8450826Smdodd#define BT_MCA_DRQ_MASK 0x0f 8550826Smdodd#define BT_MCA_DRQ(pos) (pos & BT_MCA_DRQ_MASK) 8650826Smdodd 8750826Smdodd#define BT_MCA_SCSIID_POS MCA_ADP_POS(MCA_POS2) 8850826Smdodd#define BT_MCA_SCSIID_MASK 0xe0 8950826Smdodd#define BT_MCA_SCSIID(pos) ((pos & BT_MCA_SCSIID_MASK) >> 5) 9050826Smdodd 9150826Smdoddstatic bus_dma_filter_t btvlbouncefilter; 9250826Smdoddstatic bus_dmamap_callback_t btmapsensebuffers; 9350826Smdodd 9450826Smdoddstatic void 9550826Smdoddbt_mca_release_resources (device_t dev) 9650826Smdodd{ 9750826Smdodd struct bt_softc * bt = device_get_softc(dev); 9850826Smdodd 9950826Smdodd if (bt->port) 10050826Smdodd bus_release_resource(dev, SYS_RES_IOPORT, 0, bt->port); 10150826Smdodd if (bt->irq) 10250826Smdodd bus_release_resource(dev, SYS_RES_IRQ, 0, bt->irq); 10350826Smdodd if (bt->drq) 10450826Smdodd bus_release_resource(dev, SYS_RES_DRQ, 0, bt->drq); 10550826Smdodd 10650826Smdodd bt_free_softc(dev); 10750826Smdodd} 10850826Smdodd 10952050Smdodd#define BT_MCA_PROBE 0 11052050Smdodd#define BT_MCA_ATTACH 1 11152050Smdodd 11250826Smdoddstatic int 11352050Smdoddbt_mca_alloc_resources(device_t dev, int mode) 11450826Smdodd{ 11550826Smdodd struct resource * io = NULL; 11650826Smdodd struct resource * irq = NULL; 11750826Smdodd struct resource * drq = NULL; 11850826Smdodd int rid; 11950826Smdodd 12050826Smdodd rid = 0; 12150826Smdodd io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 12250826Smdodd 0, ~0, 1, RF_ACTIVE); 12352050Smdodd if (io == NULL) { 12452050Smdodd printf("bt_mca_alloc_resources() failed to allocate IOPORT\n"); 12550826Smdodd return (ENOMEM); 12652050Smdodd } 12750826Smdodd 12852050Smdodd if (mode == BT_MCA_ATTACH) { 12950826Smdodd 13052050Smdodd rid = 0; 13152050Smdodd irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 13250826Smdodd 0, ~0, 1, RF_ACTIVE); 13352050Smdodd if (irq == NULL) { 13452050Smdodd printf("bt_mca_alloc_resources() failed to allocate IRQ\n"); 13552050Smdodd goto bad; 13652050Smdodd } 13752050Smdodd 13852050Smdodd rid = 0; 13952050Smdodd drq = bus_alloc_resource(dev, SYS_RES_DRQ, &rid, 14052050Smdodd 0, ~0, 1, RF_ACTIVE); 14152050Smdodd if (drq == NULL) { 14252050Smdodd printf("bt_mca_alloc_resources() failed to allocate DRQ\n"); 14352050Smdodd goto bad; 14452050Smdodd } 14552050Smdodd } 14652050Smdodd 14750826Smdodd bt_init_softc(dev, io, irq, drq); 14850826Smdodd 14950826Smdodd return (0); 15050826Smdoddbad: 15150826Smdodd bt_mca_release_resources(dev); 15250826Smdodd return (ENOMEM); 15350826Smdodd} 15450826Smdodd 15550826Smdoddstatic int 15650826Smdoddbt_mca_probe (device_t dev) 15750826Smdodd{ 15850826Smdodd const char * desc; 15950826Smdodd mca_id_t id = mca_get_id(dev); 16050826Smdodd struct bt_probe_info info; 16150826Smdodd u_int32_t iobase = 0; 16250826Smdodd u_int32_t iosize = 0; 16350826Smdodd u_int8_t drq = 0; 16450826Smdodd u_int8_t irq = 0; 16550826Smdodd u_int8_t pos; 16650826Smdodd int result; 16750826Smdodd 16850826Smdodd desc = mca_match_id(id, bt_mca_devs); 16950826Smdodd if (!desc) 17050826Smdodd return (ENXIO); 17150826Smdodd device_set_desc(dev, desc); 17250826Smdodd 17350826Smdodd pos = (mca_pos_read(dev, BT_MCA_IOPORT_POS1) & BT_MCA_IOPORT_MASK1) | 17450826Smdodd (mca_pos_read(dev, BT_MCA_IOPORT_POS2) & BT_MCA_IOPORT_MASK2); 17550826Smdodd iobase = BT_MCA_IOPORT(pos); 17650826Smdodd iosize = BT_MCA_IOPORT_SIZE; 17750826Smdodd 17850826Smdodd pos = mca_pos_read(dev, BT_MCA_DRQ_POS); 17950826Smdodd drq = BT_MCA_DRQ(pos); 18050826Smdodd 18150826Smdodd pos = mca_pos_read(dev, BT_MCA_IRQ_POS); 18250826Smdodd irq = BT_MCA_IRQ(pos); 18350826Smdodd 18450826Smdodd bt_mark_probed_iop(iobase); 18550826Smdodd 18651675Smdodd mca_add_iospace(dev, iobase, iosize); 18750826Smdodd 18850826Smdodd /* And allocate them */ 18952050Smdodd bt_mca_alloc_resources(dev, BT_MCA_PROBE); 19050826Smdodd 19150826Smdodd if (bt_port_probe(dev, &info) != 0) { 19250826Smdodd printf("bt_mca_probe: Probe failed for " 19350826Smdodd "card at slot %d\n", mca_get_slot(dev) + 1); 19450826Smdodd result = ENXIO; 19550826Smdodd } else { 19650826Smdodd mca_add_drq(dev, drq); 19750826Smdodd mca_add_irq(dev, irq); 19850826Smdodd result = 0; 19950826Smdodd } 20050826Smdodd bt_mca_release_resources(dev); 20150826Smdodd 20250826Smdodd return (result); 20350826Smdodd} 20450826Smdodd 20550826Smdoddstatic int 20650826Smdoddbt_mca_attach (device_t dev) 20750826Smdodd{ 20850826Smdodd struct bt_softc * bt = device_get_softc(dev); 20950826Smdodd int error = 0; 21050826Smdodd 21150826Smdodd /* Allocate resources */ 21252050Smdodd if ((error = bt_mca_alloc_resources(dev, BT_MCA_ATTACH))) { 21350826Smdodd device_printf(dev, "Unable to allocate resources in bt_mca_attach()\n"); 21450826Smdodd return (error); 21550826Smdodd } 21650826Smdodd 21750826Smdodd isa_dmacascade(rman_get_start(bt->drq)); 21850826Smdodd 21950826Smdodd /* Allocate a dmatag for our CCB DMA maps */ 220112782Smdodd if (bus_dma_tag_create( /* parent */ NULL, 221112782Smdodd /* alignemnt */ 1, 222112782Smdodd /* boundary */ 0, 223112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR_24BIT, 224112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 225112782Smdodd /* filter */ btvlbouncefilter, 226112782Smdodd /* filterarg */ bt, 227112782Smdodd /* maxsize */ BUS_SPACE_MAXSIZE_32BIT, 228112782Smdodd /* nsegments */ ~0, 229112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT, 230112782Smdodd /* flags */ 0, 231112782Smdodd &bt->parent_dmat) != 0) { 23250826Smdodd bt_mca_release_resources(dev); 23350826Smdodd return (ENOMEM); 23450826Smdodd } 23550826Smdodd 23650826Smdodd if (bt_init(dev)) { 23750826Smdodd bt_mca_release_resources(dev); 23850826Smdodd return (ENOMEM); 23950826Smdodd } 24050826Smdodd 24150826Smdodd /* DMA tag for our sense buffers */ 242112782Smdodd if (bus_dma_tag_create( /* parent */ bt->parent_dmat, 243112782Smdodd /* alignment */ 1, 244112782Smdodd /* boundary */ 0, 245112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR, 246112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 247112782Smdodd /* filter */ NULL, 248112782Smdodd /* filterarg */ NULL, 249112782Smdodd /* maxsize */ bt->max_ccbs * 250112782Smdodd sizeof(struct scsi_sense_data), 251112782Smdodd /* nsegments */ 1, 252112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT, 253112782Smdodd /* flags */ 0, 254112782Smdodd &bt->sense_dmat) != 0) { 25550826Smdodd bt_mca_release_resources(dev); 25650826Smdodd return (ENOMEM); 25750826Smdodd } 25850826Smdodd 25950826Smdodd bt->init_level++; 26050826Smdodd 26150826Smdodd /* Allocation of sense buffers */ 26250826Smdodd if (bus_dmamem_alloc(bt->sense_dmat, 26350826Smdodd (void **)&bt->sense_buffers, 26450826Smdodd BUS_DMA_NOWAIT, &bt->sense_dmamap) != 0) { 26550826Smdodd bt_mca_release_resources(dev); 26650826Smdodd return (ENOMEM); 26750826Smdodd } 26850826Smdodd 26950826Smdodd bt->init_level++; 27050826Smdodd 27150826Smdodd /* And permanently map them */ 27250826Smdodd bus_dmamap_load(bt->sense_dmat, bt->sense_dmamap, 27350826Smdodd bt->sense_buffers, 27450826Smdodd bt->max_ccbs * sizeof(*bt->sense_buffers), 27550826Smdodd btmapsensebuffers, bt, /*flags*/0); 27650826Smdodd 27750826Smdodd bt->init_level++; 27850826Smdodd 27950826Smdodd if ((error = bt_attach(dev))) { 28050826Smdodd bt_mca_release_resources(dev); 28150826Smdodd return (error); 28250826Smdodd } 28350826Smdodd 28450826Smdodd return (0); 28550826Smdodd} 28650826Smdodd 28750826Smdodd/* 28850826Smdodd * This code should be shared with the ISA 28950826Smdodd * stubs as its exactly the same. 29050826Smdodd */ 29150826Smdodd 29250826Smdodd#define BIOS_MAP_SIZE (16 * 1024) 29350826Smdodd 29450826Smdoddstatic int 29550826Smdoddbtvlbouncefilter(void *arg, bus_addr_t addr) 29650826Smdodd{ 29750826Smdodd struct bt_softc *bt; 29850826Smdodd 29950826Smdodd bt = (struct bt_softc *)arg; 30050826Smdodd 30150826Smdodd addr &= BUS_SPACE_MAXADDR_24BIT; 30250826Smdodd 30350826Smdodd if (addr == 0 30450826Smdodd || (addr >= bt->bios_addr 30550826Smdodd && addr < (bt->bios_addr + BIOS_MAP_SIZE))) 30650826Smdodd return (1); 30750826Smdodd return (0); 30850826Smdodd} 30950826Smdodd 31050826Smdoddstatic void 31150826Smdoddbtmapsensebuffers(void *arg, bus_dma_segment_t *segs, int nseg, int error) 31250826Smdodd{ 31350826Smdodd struct bt_softc* bt; 31450826Smdodd 31550826Smdodd bt = (struct bt_softc*)arg; 31650826Smdodd bt->sense_buffers_physbase = segs->ds_addr; 31750826Smdodd} 31850826Smdodd 31950826Smdoddstatic device_method_t bt_mca_methods[] = { 32050826Smdodd /* Device interface */ 32150826Smdodd DEVMETHOD(device_probe, bt_mca_probe), 32250826Smdodd DEVMETHOD(device_attach, bt_mca_attach), 32350826Smdodd 32450826Smdodd { 0, 0 } 32550826Smdodd}; 32650826Smdodd 32750826Smdoddstatic driver_t bt_mca_driver = { 32850826Smdodd "bt", 32950826Smdodd bt_mca_methods, 33050826Smdodd sizeof(struct bt_softc), 33150826Smdodd}; 33250826Smdodd 33350826Smdoddstatic devclass_t bt_devclass; 33450826Smdodd 33550826SmdoddDRIVER_MODULE(bt, mca, bt_mca_driver, bt_devclass, 0, 0); 336