bt_mca.c revision 52050
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 52050 1999-10-09 04:02:02Z 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 */ 22050826Smdodd if (bus_dma_tag_create(/*parent*/NULL, /*alignemnt*/1, /*boundary*/0, 22150826Smdodd /*lowaddr*/BUS_SPACE_MAXADDR_24BIT, 22250826Smdodd /*highaddr*/BUS_SPACE_MAXADDR, 22350826Smdodd /*filter*/btvlbouncefilter, 22450826Smdodd /*filterarg*/bt, 22550826Smdodd /*maxsize*/BUS_SPACE_MAXSIZE_32BIT, 22650826Smdodd /*nsegments*/BUS_SPACE_UNRESTRICTED, 22750826Smdodd /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, 22850826Smdodd /*flags*/0, &bt->parent_dmat) != 0) { 22950826Smdodd bt_mca_release_resources(dev); 23050826Smdodd return (ENOMEM); 23150826Smdodd } 23250826Smdodd 23350826Smdodd if (bt_init(dev)) { 23450826Smdodd bt_mca_release_resources(dev); 23550826Smdodd return (ENOMEM); 23650826Smdodd } 23750826Smdodd 23850826Smdodd /* DMA tag for our sense buffers */ 23950826Smdodd if (bus_dma_tag_create(bt->parent_dmat, /*alignment*/1, 24050826Smdodd /*boundary*/0, 24150826Smdodd /*lowaddr*/BUS_SPACE_MAXADDR, 24250826Smdodd /*highaddr*/BUS_SPACE_MAXADDR, 24350826Smdodd /*filter*/NULL, /*filterarg*/NULL, 24450826Smdodd bt->max_ccbs * sizeof(struct scsi_sense_data), 24550826Smdodd /*nsegments*/1, 24650826Smdodd /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, 24750826Smdodd /*flags*/0, &bt->sense_dmat) != 0) { 24850826Smdodd bt_mca_release_resources(dev); 24950826Smdodd return (ENOMEM); 25050826Smdodd } 25150826Smdodd 25250826Smdodd bt->init_level++; 25350826Smdodd 25450826Smdodd /* Allocation of sense buffers */ 25550826Smdodd if (bus_dmamem_alloc(bt->sense_dmat, 25650826Smdodd (void **)&bt->sense_buffers, 25750826Smdodd BUS_DMA_NOWAIT, &bt->sense_dmamap) != 0) { 25850826Smdodd bt_mca_release_resources(dev); 25950826Smdodd return (ENOMEM); 26050826Smdodd } 26150826Smdodd 26250826Smdodd bt->init_level++; 26350826Smdodd 26450826Smdodd /* And permanently map them */ 26550826Smdodd bus_dmamap_load(bt->sense_dmat, bt->sense_dmamap, 26650826Smdodd bt->sense_buffers, 26750826Smdodd bt->max_ccbs * sizeof(*bt->sense_buffers), 26850826Smdodd btmapsensebuffers, bt, /*flags*/0); 26950826Smdodd 27050826Smdodd bt->init_level++; 27150826Smdodd 27250826Smdodd if ((error = bt_attach(dev))) { 27350826Smdodd bt_mca_release_resources(dev); 27450826Smdodd return (error); 27550826Smdodd } 27650826Smdodd 27750826Smdodd return (0); 27850826Smdodd} 27950826Smdodd 28050826Smdodd/* 28150826Smdodd * This code should be shared with the ISA 28250826Smdodd * stubs as its exactly the same. 28350826Smdodd */ 28450826Smdodd 28550826Smdodd#define BIOS_MAP_SIZE (16 * 1024) 28650826Smdodd 28750826Smdoddstatic int 28850826Smdoddbtvlbouncefilter(void *arg, bus_addr_t addr) 28950826Smdodd{ 29050826Smdodd struct bt_softc *bt; 29150826Smdodd 29250826Smdodd bt = (struct bt_softc *)arg; 29350826Smdodd 29450826Smdodd addr &= BUS_SPACE_MAXADDR_24BIT; 29550826Smdodd 29650826Smdodd if (addr == 0 29750826Smdodd || (addr >= bt->bios_addr 29850826Smdodd && addr < (bt->bios_addr + BIOS_MAP_SIZE))) 29950826Smdodd return (1); 30050826Smdodd return (0); 30150826Smdodd} 30250826Smdodd 30350826Smdoddstatic void 30450826Smdoddbtmapsensebuffers(void *arg, bus_dma_segment_t *segs, int nseg, int error) 30550826Smdodd{ 30650826Smdodd struct bt_softc* bt; 30750826Smdodd 30850826Smdodd bt = (struct bt_softc*)arg; 30950826Smdodd bt->sense_buffers_physbase = segs->ds_addr; 31050826Smdodd} 31150826Smdodd 31250826Smdoddstatic device_method_t bt_mca_methods[] = { 31350826Smdodd /* Device interface */ 31450826Smdodd DEVMETHOD(device_probe, bt_mca_probe), 31550826Smdodd DEVMETHOD(device_attach, bt_mca_attach), 31650826Smdodd 31750826Smdodd { 0, 0 } 31850826Smdodd}; 31950826Smdodd 32050826Smdoddstatic driver_t bt_mca_driver = { 32150826Smdodd "bt", 32250826Smdodd bt_mca_methods, 32350826Smdodd sizeof(struct bt_softc), 32450826Smdodd}; 32550826Smdodd 32650826Smdoddstatic devclass_t bt_devclass; 32750826Smdodd 32850826SmdoddDRIVER_MODULE(bt, mca, bt_mca_driver, bt_devclass, 0, 0); 329