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 * Based on aha_isa.c 27 */ 28 29#include <sys/cdefs.h> 30__FBSDID("$FreeBSD$"); 31 32#include <sys/types.h> 33#include <sys/param.h> 34#include <sys/systm.h> 35#include <sys/kernel.h> 36#include <sys/lock.h> 37#include <sys/mutex.h> 38 39#include <sys/module.h> 40#include <sys/bus.h> 41#include <machine/bus.h> 42#include <machine/resource.h> 43#include <sys/rman.h> 44 45#include <isa/isavar.h> 46 47#include <dev/mca/mca_busreg.h> 48#include <dev/mca/mca_busvar.h> 49 50#include <dev/aha/ahareg.h> 51 52static struct mca_ident aha_mca_devs[] = { 53 { 0x0f1f, "Adaptec AHA-1640 SCSI Adapter" }, 54 { 0, NULL }, 55}; 56 57#define AHA_MCA_IOPORT_POS MCA_ADP_POS(MCA_POS1) 58# define AHA_MCA_IOPORT_MASK1 0x07 59# define AHA_MCA_IOPORT_MASK2 0xc0 60# define AHA_MCA_IOPORT_SIZE 0x03 61# define AHA_MCA_IOPORT(pos) (0x30 + \ 62 (((uint32_t)pos & \ 63 AHA_MCA_IOPORT_MASK1) << 8) + \ 64 (((uint32_t)pos & \ 65 AHA_MCA_IOPORT_MASK2) >> 4)) 66 67#define AHA_MCA_DRQ_POS MCA_ADP_POS(MCA_POS3) 68# define AHA_MCA_DRQ_MASK 0x0f 69# define AHA_MCA_DRQ(pos) (pos & AHA_MCA_DRQ_MASK) 70 71#define AHA_MCA_IRQ_POS MCA_ADP_POS(MCA_POS2) 72# define AHA_MCA_IRQ_MASK 0x07 73# define AHA_MCA_IRQ(pos) ((pos & AHA_MCA_IRQ_MASK) + 8) 74 75/* 76 * Not needed as the board knows its config 77 * internally and the ID will be fetched 78 * via AOP_INQUIRE_SETUP_INFO command. 79 */ 80#define AHA_MCA_SCSIID_POS MCA_ADP_POS(MCA_POS2) 81#define AHA_MCA_SCSIID_MASK 0xe0 82#define AHA_MCA_SCSIID(pos) ((pos & AHA_MCA_SCSIID_MASK) >> 5) 83 84static int 85aha_mca_probe (device_t dev) 86{ 87 const char * desc; 88 mca_id_t id = mca_get_id(dev); 89 uint32_t iobase = 0; 90 uint32_t iosize = 0; 91 uint8_t drq = 0; 92 uint8_t irq = 0; 93 uint8_t pos; 94 95 desc = mca_match_id(id, aha_mca_devs); 96 if (!desc) 97 return (ENXIO); 98 device_set_desc(dev, desc); 99 100 pos = mca_pos_read(dev, AHA_MCA_IOPORT_POS); 101 iobase = AHA_MCA_IOPORT(pos); 102 iosize = AHA_MCA_IOPORT_SIZE; 103 104 pos = mca_pos_read(dev, AHA_MCA_DRQ_POS); 105 drq = AHA_MCA_DRQ(pos); 106 107 pos = mca_pos_read(dev, AHA_MCA_IRQ_POS); 108 irq = AHA_MCA_IRQ(pos); 109 110 mca_add_iospace(dev, iobase, iosize); 111 mca_add_drq(dev, drq); 112 mca_add_irq(dev, irq); 113 114 return (0); 115} 116 117static int 118aha_mca_attach (device_t dev) 119{ 120 struct aha_softc * sc = device_get_softc(dev); 121 int error = ENOMEM; 122 123 sc->portrid = 0; 124 sc->port = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &sc->portrid, 125 RF_ACTIVE); 126 if (sc->port == NULL) { 127 device_printf(dev, "No I/O space?!\n"); 128 goto bad; 129 } 130 131 sc->irqrid = 0; 132 sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqrid, 133 RF_ACTIVE); 134 if (sc->irq == NULL) { 135 device_printf(dev, "No IRQ?!\n"); 136 goto bad; 137 } 138 139 sc->drqrid = 0; 140 sc->drq = bus_alloc_resource_any(dev, SYS_RES_DRQ, &sc->drqrid, 141 RF_ACTIVE); 142 if (sc->drq == NULL) { 143 device_printf(dev, "No DRQ?!\n"); 144 goto bad; 145 } 146 147 aha_alloc(sc); 148 error = aha_probe(sc); 149 if (error) { 150 device_printf(dev, "aha_probe() failed!\n"); 151 goto bad; 152 } 153 154 error = aha_fetch_adapter_info(sc); 155 if (error) { 156 device_printf(dev, "aha_fetch_adapter_info() failed!\n"); 157 goto bad; 158 } 159 160 isa_dmacascade(rman_get_start(sc->drq)); 161 162 error = bus_dma_tag_create( 163 /* parent */ bus_get_dma_tag(dev), 164 /* alignemnt */ 1, 165 /* boundary */ 0, 166 /* lowaddr */ BUS_SPACE_MAXADDR_24BIT, 167 /* highaddr */ BUS_SPACE_MAXADDR, 168 /* filter */ NULL, 169 /* filterarg */ NULL, 170 /* maxsize */ BUS_SPACE_MAXSIZE_24BIT, 171 /* nsegments */ ~0, 172 /* maxsegsz */ BUS_SPACE_MAXSIZE_24BIT, 173 /* flags */ 0, 174 /* lockfunc */ NULL, 175 /* lockarg */ NULL, 176 &sc->parent_dmat); 177 if (error) { 178 device_printf(dev, "bus_dma_tag_create() failed!\n"); 179 goto bad; 180 } 181 182 error = aha_init(sc); 183 if (error) { 184 device_printf(dev, "aha_init() failed\n"); 185 goto bad; 186 } 187 188 error = aha_attach(sc); 189 if (error) { 190 device_printf(dev, "aha_attach() failed\n"); 191 goto bad; 192 } 193 194 error = bus_setup_intr(dev, sc->irq, INTR_TYPE_CAM | INTR_ENTROPY | 195 INTR_MPSAFE, NULL, aha_intr, sc, &sc->ih); 196 if (error) { 197 device_printf(dev, "Unable to register interrupt handler\n"); 198 aha_detach(sc); 199 goto bad; 200 } 201 202 return (0); 203 204bad: 205 aha_free(sc); 206 bus_free_resource(dev, SYS_RES_IOPORT, sc->port); 207 bus_free_resource(dev, SYS_RES_IRQ, sc->irq); 208 bus_free_resource(dev, SYS_RES_DRQ, sc->drq); 209 return (error); 210} 211 212static device_method_t aha_mca_methods[] = { 213 DEVMETHOD(device_probe, aha_mca_probe), 214 DEVMETHOD(device_attach, aha_mca_attach), 215 216 { 0, 0 } 217}; 218 219static driver_t aha_mca_driver = { 220 "aha", 221 aha_mca_methods, 222 1, 223/* 224 sizeof(struct aha_softc *), 225 */ 226}; 227 228static devclass_t aha_devclass; 229 230DRIVER_MODULE(aha, mca, aha_mca_driver, aha_devclass, 0, 0); 231MODULE_DEPEND(aha, mca, 1, 1, 1); 232