bt_mca.c revision 51675
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 51675 1999-09-26 07:16:01Z 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 10950826Smdoddstatic int 11050826Smdoddbt_mca_alloc_resources(device_t dev) 11150826Smdodd{ 11250826Smdodd struct resource * io = NULL; 11350826Smdodd struct resource * irq = NULL; 11450826Smdodd struct resource * drq = NULL; 11550826Smdodd int rid; 11650826Smdodd 11750826Smdodd rid = 0; 11850826Smdodd io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 11950826Smdodd 0, ~0, 1, RF_ACTIVE); 12050826Smdodd if (io == NULL) 12150826Smdodd return (ENOMEM); 12250826Smdodd 12350826Smdodd if (mca_get_irq(dev) != -1) { 12450826Smdodd rid = 0; 12550826Smdodd irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 12650826Smdodd 0, ~0, 1, RF_ACTIVE); 12750826Smdodd if (irq == NULL) 12850826Smdodd goto bad; 12950826Smdodd } else { 13050826Smdodd irq = 0; 13150826Smdodd } 13250826Smdodd 13350826Smdodd if (mca_get_drq(dev) != -1) { 13450826Smdodd rid = 0; 13550826Smdodd drq = bus_alloc_resource(dev, SYS_RES_DRQ, &rid, 13650826Smdodd 0, ~0, 1, RF_ACTIVE); 13750826Smdodd if (drq == NULL) 13850826Smdodd goto bad; 13950826Smdodd } else { 14050826Smdodd drq = 0; 14150826Smdodd } 14250826Smdodd 14350826Smdodd bt_init_softc(dev, io, irq, drq); 14450826Smdodd 14550826Smdodd return (0); 14650826Smdoddbad: 14750826Smdodd bt_mca_release_resources(dev); 14850826Smdodd return (ENOMEM); 14950826Smdodd} 15050826Smdodd 15150826Smdoddstatic int 15250826Smdoddbt_mca_probe (device_t dev) 15350826Smdodd{ 15450826Smdodd const char * desc; 15550826Smdodd mca_id_t id = mca_get_id(dev); 15650826Smdodd struct bt_probe_info info; 15750826Smdodd u_int32_t iobase = 0; 15850826Smdodd u_int32_t iosize = 0; 15950826Smdodd u_int8_t drq = 0; 16050826Smdodd u_int8_t irq = 0; 16150826Smdodd u_int8_t pos; 16250826Smdodd int result; 16350826Smdodd 16450826Smdodd desc = mca_match_id(id, bt_mca_devs); 16550826Smdodd if (!desc) 16650826Smdodd return (ENXIO); 16750826Smdodd device_set_desc(dev, desc); 16850826Smdodd 16950826Smdodd pos = (mca_pos_read(dev, BT_MCA_IOPORT_POS1) & BT_MCA_IOPORT_MASK1) | 17050826Smdodd (mca_pos_read(dev, BT_MCA_IOPORT_POS2) & BT_MCA_IOPORT_MASK2); 17150826Smdodd iobase = BT_MCA_IOPORT(pos); 17250826Smdodd iosize = BT_MCA_IOPORT_SIZE; 17350826Smdodd 17450826Smdodd pos = mca_pos_read(dev, BT_MCA_DRQ_POS); 17550826Smdodd drq = BT_MCA_DRQ(pos); 17650826Smdodd 17750826Smdodd pos = mca_pos_read(dev, BT_MCA_IRQ_POS); 17850826Smdodd irq = BT_MCA_IRQ(pos); 17950826Smdodd 18050826Smdodd bt_mark_probed_iop(iobase); 18150826Smdodd 18251675Smdodd mca_add_iospace(dev, iobase, iosize); 18350826Smdodd 18450826Smdodd /* And allocate them */ 18550826Smdodd bt_mca_alloc_resources(dev); 18650826Smdodd 18750826Smdodd if (bt_port_probe(dev, &info) != 0) { 18850826Smdodd printf("bt_mca_probe: Probe failed for " 18950826Smdodd "card at slot %d\n", mca_get_slot(dev) + 1); 19050826Smdodd result = ENXIO; 19150826Smdodd } else { 19250826Smdodd mca_add_drq(dev, drq); 19350826Smdodd mca_add_irq(dev, irq); 19450826Smdodd result = 0; 19550826Smdodd } 19650826Smdodd bt_mca_release_resources(dev); 19750826Smdodd 19850826Smdodd return (result); 19950826Smdodd} 20050826Smdodd 20150826Smdoddstatic int 20250826Smdoddbt_mca_attach (device_t dev) 20350826Smdodd{ 20450826Smdodd struct bt_softc * bt = device_get_softc(dev); 20550826Smdodd int error = 0; 20650826Smdodd 20750826Smdodd /* Allocate resources */ 20850826Smdodd if ((error = bt_mca_alloc_resources(dev))) { 20950826Smdodd device_printf(dev, "Unable to allocate resources in bt_mca_attach()\n"); 21050826Smdodd return (error); 21150826Smdodd } 21250826Smdodd 21350826Smdodd isa_dmacascade(rman_get_start(bt->drq)); 21450826Smdodd 21550826Smdodd /* Allocate a dmatag for our CCB DMA maps */ 21650826Smdodd if (bus_dma_tag_create(/*parent*/NULL, /*alignemnt*/1, /*boundary*/0, 21750826Smdodd /*lowaddr*/BUS_SPACE_MAXADDR_24BIT, 21850826Smdodd /*highaddr*/BUS_SPACE_MAXADDR, 21950826Smdodd /*filter*/btvlbouncefilter, 22050826Smdodd /*filterarg*/bt, 22150826Smdodd /*maxsize*/BUS_SPACE_MAXSIZE_32BIT, 22250826Smdodd /*nsegments*/BUS_SPACE_UNRESTRICTED, 22350826Smdodd /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, 22450826Smdodd /*flags*/0, &bt->parent_dmat) != 0) { 22550826Smdodd bt_mca_release_resources(dev); 22650826Smdodd return (ENOMEM); 22750826Smdodd } 22850826Smdodd 22950826Smdodd if (bt_init(dev)) { 23050826Smdodd bt_mca_release_resources(dev); 23150826Smdodd return (ENOMEM); 23250826Smdodd } 23350826Smdodd 23450826Smdodd /* DMA tag for our sense buffers */ 23550826Smdodd if (bus_dma_tag_create(bt->parent_dmat, /*alignment*/1, 23650826Smdodd /*boundary*/0, 23750826Smdodd /*lowaddr*/BUS_SPACE_MAXADDR, 23850826Smdodd /*highaddr*/BUS_SPACE_MAXADDR, 23950826Smdodd /*filter*/NULL, /*filterarg*/NULL, 24050826Smdodd bt->max_ccbs * sizeof(struct scsi_sense_data), 24150826Smdodd /*nsegments*/1, 24250826Smdodd /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, 24350826Smdodd /*flags*/0, &bt->sense_dmat) != 0) { 24450826Smdodd bt_mca_release_resources(dev); 24550826Smdodd return (ENOMEM); 24650826Smdodd } 24750826Smdodd 24850826Smdodd bt->init_level++; 24950826Smdodd 25050826Smdodd /* Allocation of sense buffers */ 25150826Smdodd if (bus_dmamem_alloc(bt->sense_dmat, 25250826Smdodd (void **)&bt->sense_buffers, 25350826Smdodd BUS_DMA_NOWAIT, &bt->sense_dmamap) != 0) { 25450826Smdodd bt_mca_release_resources(dev); 25550826Smdodd return (ENOMEM); 25650826Smdodd } 25750826Smdodd 25850826Smdodd bt->init_level++; 25950826Smdodd 26050826Smdodd /* And permanently map them */ 26150826Smdodd bus_dmamap_load(bt->sense_dmat, bt->sense_dmamap, 26250826Smdodd bt->sense_buffers, 26350826Smdodd bt->max_ccbs * sizeof(*bt->sense_buffers), 26450826Smdodd btmapsensebuffers, bt, /*flags*/0); 26550826Smdodd 26650826Smdodd bt->init_level++; 26750826Smdodd 26850826Smdodd if ((error = bt_attach(dev))) { 26950826Smdodd bt_mca_release_resources(dev); 27050826Smdodd return (error); 27150826Smdodd } 27250826Smdodd 27350826Smdodd return (0); 27450826Smdodd} 27550826Smdodd 27650826Smdodd/* 27750826Smdodd * This code should be shared with the ISA 27850826Smdodd * stubs as its exactly the same. 27950826Smdodd */ 28050826Smdodd 28150826Smdodd#define BIOS_MAP_SIZE (16 * 1024) 28250826Smdodd 28350826Smdoddstatic int 28450826Smdoddbtvlbouncefilter(void *arg, bus_addr_t addr) 28550826Smdodd{ 28650826Smdodd struct bt_softc *bt; 28750826Smdodd 28850826Smdodd bt = (struct bt_softc *)arg; 28950826Smdodd 29050826Smdodd addr &= BUS_SPACE_MAXADDR_24BIT; 29150826Smdodd 29250826Smdodd if (addr == 0 29350826Smdodd || (addr >= bt->bios_addr 29450826Smdodd && addr < (bt->bios_addr + BIOS_MAP_SIZE))) 29550826Smdodd return (1); 29650826Smdodd return (0); 29750826Smdodd} 29850826Smdodd 29950826Smdoddstatic void 30050826Smdoddbtmapsensebuffers(void *arg, bus_dma_segment_t *segs, int nseg, int error) 30150826Smdodd{ 30250826Smdodd struct bt_softc* bt; 30350826Smdodd 30450826Smdodd bt = (struct bt_softc*)arg; 30550826Smdodd bt->sense_buffers_physbase = segs->ds_addr; 30650826Smdodd} 30750826Smdodd 30850826Smdoddstatic device_method_t bt_mca_methods[] = { 30950826Smdodd /* Device interface */ 31050826Smdodd DEVMETHOD(device_probe, bt_mca_probe), 31150826Smdodd DEVMETHOD(device_attach, bt_mca_attach), 31250826Smdodd 31350826Smdodd { 0, 0 } 31450826Smdodd}; 31550826Smdodd 31650826Smdoddstatic driver_t bt_mca_driver = { 31750826Smdodd "bt", 31850826Smdodd bt_mca_methods, 31950826Smdodd sizeof(struct bt_softc), 32050826Smdodd}; 32150826Smdodd 32250826Smdoddstatic devclass_t bt_devclass; 32350826Smdodd 32450826SmdoddDRIVER_MODULE(bt, mca, bt_mca_driver, bt_devclass, 0, 0); 325