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 */ 2750826Smdodd 28119418Sobrien#include <sys/cdefs.h> 29119418Sobrien__FBSDID("$FreeBSD: releng/11.0/sys/dev/buslogic/bt_mca.c 241592 2012-10-15 16:13:55Z jhb $"); 30119418Sobrien 3150826Smdodd/* 3250826Smdodd * Written using the bt_isa/bt_pci code as a reference. 3350826Smdodd * 3450826Smdodd * Thanks to Andy Farkas <andyf@speednet.com.au> for 3550826Smdodd * testing and feedback. 3650826Smdodd */ 3750826Smdodd 3850826Smdodd#include <sys/types.h> 3950826Smdodd#include <sys/param.h> 4050826Smdodd#include <sys/systm.h> 4150826Smdodd#include <sys/kernel.h> 42117126Sscottl#include <sys/lock.h> 43117126Sscottl#include <sys/mutex.h> 4450826Smdodd 4550826Smdodd#include <machine/cpufunc.h> 4650826Smdodd#include <machine/md_var.h> 4750826Smdodd 4850826Smdodd#include <sys/module.h> 4950826Smdodd#include <sys/bus.h> 5050826Smdodd 5150826Smdodd#include <machine/bus.h> 5250826Smdodd#include <machine/resource.h> 5350826Smdodd#include <sys/rman.h> 5450826Smdodd 5550826Smdodd#include <dev/mca/mca_busreg.h> 5650826Smdodd#include <dev/mca/mca_busvar.h> 5750826Smdodd 58135260Sphk#include <isa/isavar.h> 5950826Smdodd 6050826Smdodd#include <dev/buslogic/btreg.h> 6150826Smdodd 6250826Smdodd#include <cam/scsi/scsi_all.h> 6350826Smdodd 6450826Smdoddstatic struct mca_ident bt_mca_devs[] = { 6550826Smdodd { 0x0708, "BusLogic 32 Bit Bus Master MCA-to-SCSI Host Adapter" }, 6650826Smdodd { 0x0708, "BusTek BT-640A Micro Channel to SCSI Host Adapter" }, 6750826Smdodd { 0x0708, "Storage Dimensions SDC3211B 32-bit SCSI Host Adapter" }, 6850826Smdodd { 0x0709, "Storage Dimensions SDC3211F 32-bit FAST SCSI Host Adapter" }, 6950826Smdodd { 0, NULL }, 7050826Smdodd}; 7150826Smdodd 7250826Smdodd#define BT_MCA_IOPORT_POS1 MCA_ADP_POS(MCA_POS0) 7350826Smdodd#define BT_MCA_IOPORT_POS2 MCA_ADP_POS(MCA_POS1) 7450826Smdodd#define BT_MCA_IOPORT_MASK1 0x10 7550826Smdodd#define BT_MCA_IOPORT_MASK2 0x03 7650826Smdodd#define BT_MCA_IOPORT_SIZE 0x03 7750826Smdodd#define BT_MCA_IOPORT(pos) (0x30 + \ 7850826Smdodd (((u_int32_t)pos &\ 7950826Smdodd BT_MCA_IOPORT_MASK2) << 8) + \ 8050826Smdodd (((u_int32_t)pos &\ 8150826Smdodd BT_MCA_IOPORT_MASK1) >> 2)) 8250826Smdodd 8350826Smdodd#define BT_MCA_IRQ_POS MCA_ADP_POS(MCA_POS0) 8450826Smdodd#define BT_MCA_IRQ_MASK 0x0e 8550826Smdodd#define BT_MCA_IRQ(pos) (((pos & BT_MCA_IRQ_MASK) >> 1) + 8) 8650826Smdodd 8750826Smdodd#define BT_MCA_DRQ_POS MCA_ADP_POS(MCA_POS3) 8850826Smdodd#define BT_MCA_DRQ_MASK 0x0f 8950826Smdodd#define BT_MCA_DRQ(pos) (pos & BT_MCA_DRQ_MASK) 9050826Smdodd 9150826Smdodd#define BT_MCA_SCSIID_POS MCA_ADP_POS(MCA_POS2) 9250826Smdodd#define BT_MCA_SCSIID_MASK 0xe0 9350826Smdodd#define BT_MCA_SCSIID(pos) ((pos & BT_MCA_SCSIID_MASK) >> 5) 9450826Smdodd 9550826Smdoddstatic bus_dma_filter_t btvlbouncefilter; 9650826Smdoddstatic bus_dmamap_callback_t btmapsensebuffers; 9750826Smdodd 9850826Smdoddstatic void 9950826Smdoddbt_mca_release_resources (device_t dev) 10050826Smdodd{ 10150826Smdodd struct bt_softc * bt = device_get_softc(dev); 10250826Smdodd 10350826Smdodd if (bt->port) 10450826Smdodd bus_release_resource(dev, SYS_RES_IOPORT, 0, bt->port); 10550826Smdodd if (bt->irq) 10650826Smdodd bus_release_resource(dev, SYS_RES_IRQ, 0, bt->irq); 10750826Smdodd if (bt->drq) 10850826Smdodd bus_release_resource(dev, SYS_RES_DRQ, 0, bt->drq); 10950826Smdodd 11050826Smdodd bt_free_softc(dev); 11150826Smdodd} 11250826Smdodd 11352050Smdodd#define BT_MCA_PROBE 0 11452050Smdodd#define BT_MCA_ATTACH 1 11552050Smdodd 11650826Smdoddstatic int 11752050Smdoddbt_mca_alloc_resources(device_t dev, int mode) 11850826Smdodd{ 11950826Smdodd struct resource * io = NULL; 12050826Smdodd struct resource * irq = NULL; 12150826Smdodd struct resource * drq = NULL; 12250826Smdodd int rid; 12350826Smdodd 12450826Smdodd rid = 0; 125127135Snjl io = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE); 12652050Smdodd if (io == NULL) { 12752050Smdodd printf("bt_mca_alloc_resources() failed to allocate IOPORT\n"); 12850826Smdodd return (ENOMEM); 12952050Smdodd } 13050826Smdodd 13152050Smdodd if (mode == BT_MCA_ATTACH) { 13250826Smdodd 13352050Smdodd rid = 0; 134127135Snjl irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); 13552050Smdodd if (irq == NULL) { 13652050Smdodd printf("bt_mca_alloc_resources() failed to allocate IRQ\n"); 13752050Smdodd goto bad; 13852050Smdodd } 13952050Smdodd 14052050Smdodd rid = 0; 141127135Snjl drq = bus_alloc_resource_any(dev, SYS_RES_DRQ, &rid, RF_ACTIVE); 14252050Smdodd if (drq == NULL) { 14352050Smdodd printf("bt_mca_alloc_resources() failed to allocate DRQ\n"); 14452050Smdodd goto bad; 14552050Smdodd } 14652050Smdodd } 14752050Smdodd 14850826Smdodd bt_init_softc(dev, io, irq, drq); 14950826Smdodd 15050826Smdodd return (0); 15150826Smdoddbad: 15250826Smdodd bt_mca_release_resources(dev); 15350826Smdodd return (ENOMEM); 15450826Smdodd} 15550826Smdodd 15650826Smdoddstatic int 15750826Smdoddbt_mca_probe (device_t dev) 15850826Smdodd{ 15950826Smdodd const char * desc; 16050826Smdodd mca_id_t id = mca_get_id(dev); 16150826Smdodd struct bt_probe_info info; 16250826Smdodd u_int32_t iobase = 0; 16350826Smdodd u_int32_t iosize = 0; 16450826Smdodd u_int8_t drq = 0; 16550826Smdodd u_int8_t irq = 0; 16650826Smdodd u_int8_t pos; 16750826Smdodd int result; 16850826Smdodd 16950826Smdodd desc = mca_match_id(id, bt_mca_devs); 17050826Smdodd if (!desc) 17150826Smdodd return (ENXIO); 17250826Smdodd device_set_desc(dev, desc); 17350826Smdodd 17450826Smdodd pos = (mca_pos_read(dev, BT_MCA_IOPORT_POS1) & BT_MCA_IOPORT_MASK1) | 17550826Smdodd (mca_pos_read(dev, BT_MCA_IOPORT_POS2) & BT_MCA_IOPORT_MASK2); 17650826Smdodd iobase = BT_MCA_IOPORT(pos); 17750826Smdodd iosize = BT_MCA_IOPORT_SIZE; 17850826Smdodd 17950826Smdodd pos = mca_pos_read(dev, BT_MCA_DRQ_POS); 18050826Smdodd drq = BT_MCA_DRQ(pos); 18150826Smdodd 18250826Smdodd pos = mca_pos_read(dev, BT_MCA_IRQ_POS); 18350826Smdodd irq = BT_MCA_IRQ(pos); 18450826Smdodd 18550826Smdodd bt_mark_probed_iop(iobase); 18650826Smdodd 18751675Smdodd mca_add_iospace(dev, iobase, iosize); 18850826Smdodd 18950826Smdodd /* And allocate them */ 19052050Smdodd bt_mca_alloc_resources(dev, BT_MCA_PROBE); 19150826Smdodd 19250826Smdodd if (bt_port_probe(dev, &info) != 0) { 19350826Smdodd printf("bt_mca_probe: Probe failed for " 19450826Smdodd "card at slot %d\n", mca_get_slot(dev) + 1); 19550826Smdodd result = ENXIO; 19650826Smdodd } else { 19750826Smdodd mca_add_drq(dev, drq); 19850826Smdodd mca_add_irq(dev, irq); 199241592Sjhb result = BUS_PROBE_DEFAULT; 20050826Smdodd } 20150826Smdodd bt_mca_release_resources(dev); 20250826Smdodd 20350826Smdodd return (result); 20450826Smdodd} 20550826Smdodd 20650826Smdoddstatic int 20750826Smdoddbt_mca_attach (device_t dev) 20850826Smdodd{ 20950826Smdodd struct bt_softc * bt = device_get_softc(dev); 21050826Smdodd int error = 0; 21150826Smdodd 21250826Smdodd /* Allocate resources */ 21352050Smdodd if ((error = bt_mca_alloc_resources(dev, BT_MCA_ATTACH))) { 21450826Smdodd device_printf(dev, "Unable to allocate resources in bt_mca_attach()\n"); 21550826Smdodd return (error); 21650826Smdodd } 21750826Smdodd 21850826Smdodd isa_dmacascade(rman_get_start(bt->drq)); 21950826Smdodd 22050826Smdodd /* Allocate a dmatag for our CCB DMA maps */ 221112782Smdodd if (bus_dma_tag_create( /* parent */ NULL, 222112782Smdodd /* alignemnt */ 1, 223112782Smdodd /* boundary */ 0, 224112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR_24BIT, 225112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 226112782Smdodd /* filter */ btvlbouncefilter, 227112782Smdodd /* filterarg */ bt, 228112782Smdodd /* maxsize */ BUS_SPACE_MAXSIZE_32BIT, 229112782Smdodd /* nsegments */ ~0, 230112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT, 231112782Smdodd /* flags */ 0, 232241592Sjhb /* lockfunc */ NULL, 233241592Sjhb /* lockarg */ NULL, 234112782Smdodd &bt->parent_dmat) != 0) { 23550826Smdodd bt_mca_release_resources(dev); 23650826Smdodd return (ENOMEM); 23750826Smdodd } 23850826Smdodd 23950826Smdodd if (bt_init(dev)) { 24050826Smdodd bt_mca_release_resources(dev); 24150826Smdodd return (ENOMEM); 24250826Smdodd } 24350826Smdodd 24450826Smdodd /* DMA tag for our sense buffers */ 245112782Smdodd if (bus_dma_tag_create( /* parent */ bt->parent_dmat, 246112782Smdodd /* alignment */ 1, 247112782Smdodd /* boundary */ 0, 248112782Smdodd /* lowaddr */ BUS_SPACE_MAXADDR, 249112782Smdodd /* highaddr */ BUS_SPACE_MAXADDR, 250112782Smdodd /* filter */ NULL, 251112782Smdodd /* filterarg */ NULL, 252112782Smdodd /* maxsize */ bt->max_ccbs * 253112782Smdodd sizeof(struct scsi_sense_data), 254112782Smdodd /* nsegments */ 1, 255112782Smdodd /* maxsegsz */ BUS_SPACE_MAXSIZE_32BIT, 256112782Smdodd /* flags */ 0, 257241592Sjhb /* lockfunc */ NULL, 258241592Sjhb /* lockarg */ NULL, 259112782Smdodd &bt->sense_dmat) != 0) { 26050826Smdodd bt_mca_release_resources(dev); 26150826Smdodd return (ENOMEM); 26250826Smdodd } 26350826Smdodd 26450826Smdodd bt->init_level++; 26550826Smdodd 26650826Smdodd /* Allocation of sense buffers */ 26750826Smdodd if (bus_dmamem_alloc(bt->sense_dmat, 26850826Smdodd (void **)&bt->sense_buffers, 26950826Smdodd BUS_DMA_NOWAIT, &bt->sense_dmamap) != 0) { 27050826Smdodd bt_mca_release_resources(dev); 27150826Smdodd return (ENOMEM); 27250826Smdodd } 27350826Smdodd 27450826Smdodd bt->init_level++; 27550826Smdodd 27650826Smdodd /* And permanently map them */ 27750826Smdodd bus_dmamap_load(bt->sense_dmat, bt->sense_dmamap, 27850826Smdodd bt->sense_buffers, 27950826Smdodd bt->max_ccbs * sizeof(*bt->sense_buffers), 28050826Smdodd btmapsensebuffers, bt, /*flags*/0); 28150826Smdodd 28250826Smdodd bt->init_level++; 28350826Smdodd 28450826Smdodd if ((error = bt_attach(dev))) { 28550826Smdodd bt_mca_release_resources(dev); 28650826Smdodd return (error); 28750826Smdodd } 28850826Smdodd 28950826Smdodd return (0); 29050826Smdodd} 29150826Smdodd 29250826Smdodd/* 29350826Smdodd * This code should be shared with the ISA 29450826Smdodd * stubs as its exactly the same. 29550826Smdodd */ 29650826Smdodd 29750826Smdodd#define BIOS_MAP_SIZE (16 * 1024) 29850826Smdodd 29950826Smdoddstatic int 30050826Smdoddbtvlbouncefilter(void *arg, bus_addr_t addr) 30150826Smdodd{ 30250826Smdodd struct bt_softc *bt; 30350826Smdodd 30450826Smdodd bt = (struct bt_softc *)arg; 30550826Smdodd 30650826Smdodd addr &= BUS_SPACE_MAXADDR_24BIT; 30750826Smdodd 30850826Smdodd if (addr == 0 30950826Smdodd || (addr >= bt->bios_addr 31050826Smdodd && addr < (bt->bios_addr + BIOS_MAP_SIZE))) 31150826Smdodd return (1); 31250826Smdodd return (0); 31350826Smdodd} 31450826Smdodd 31550826Smdoddstatic void 31650826Smdoddbtmapsensebuffers(void *arg, bus_dma_segment_t *segs, int nseg, int error) 31750826Smdodd{ 31850826Smdodd struct bt_softc* bt; 31950826Smdodd 32050826Smdodd bt = (struct bt_softc*)arg; 32150826Smdodd bt->sense_buffers_physbase = segs->ds_addr; 32250826Smdodd} 32350826Smdodd 32450826Smdoddstatic device_method_t bt_mca_methods[] = { 32550826Smdodd /* Device interface */ 32650826Smdodd DEVMETHOD(device_probe, bt_mca_probe), 32750826Smdodd DEVMETHOD(device_attach, bt_mca_attach), 32850826Smdodd 32950826Smdodd { 0, 0 } 33050826Smdodd}; 33150826Smdodd 33250826Smdoddstatic driver_t bt_mca_driver = { 33350826Smdodd "bt", 33450826Smdodd bt_mca_methods, 33550826Smdodd sizeof(struct bt_softc), 33650826Smdodd}; 33750826Smdodd 33850826Smdoddstatic devclass_t bt_devclass; 33950826Smdodd 34050826SmdoddDRIVER_MODULE(bt, mca, bt_mca_driver, bt_devclass, 0, 0); 341165102SmjacobMODULE_DEPEND(bt, mca, 1, 1, 1); 342