1*dce93cd0SAchim Leubner /*- 2*dce93cd0SAchim Leubner * Copyright (c) 2000 Michael Smith 3*dce93cd0SAchim Leubner * Copyright (c) 2001 Scott Long 4*dce93cd0SAchim Leubner * Copyright (c) 2000 BSDi 5*dce93cd0SAchim Leubner * Copyright (c) 2001-2010 Adaptec, Inc. 6*dce93cd0SAchim Leubner * Copyright (c) 2010-2012 PMC-Sierra, Inc. 7*dce93cd0SAchim Leubner * All rights reserved. 8*dce93cd0SAchim Leubner * 9*dce93cd0SAchim Leubner * Redistribution and use in source and binary forms, with or without 10*dce93cd0SAchim Leubner * modification, are permitted provided that the following conditions 11*dce93cd0SAchim Leubner * are met: 12*dce93cd0SAchim Leubner * 1. Redistributions of source code must retain the above copyright 13*dce93cd0SAchim Leubner * notice, this list of conditions and the following disclaimer. 14*dce93cd0SAchim Leubner * 2. Redistributions in binary form must reproduce the above copyright 15*dce93cd0SAchim Leubner * notice, this list of conditions and the following disclaimer in the 16*dce93cd0SAchim Leubner * documentation and/or other materials provided with the distribution. 17*dce93cd0SAchim Leubner * 18*dce93cd0SAchim Leubner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19*dce93cd0SAchim Leubner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20*dce93cd0SAchim Leubner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21*dce93cd0SAchim Leubner * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22*dce93cd0SAchim Leubner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23*dce93cd0SAchim Leubner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24*dce93cd0SAchim Leubner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25*dce93cd0SAchim Leubner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26*dce93cd0SAchim Leubner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27*dce93cd0SAchim Leubner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28*dce93cd0SAchim Leubner * SUCH DAMAGE. 29*dce93cd0SAchim Leubner */ 30*dce93cd0SAchim Leubner 31*dce93cd0SAchim Leubner #include <sys/cdefs.h> 32*dce93cd0SAchim Leubner __FBSDID("$FreeBSD$"); 33*dce93cd0SAchim Leubner 34*dce93cd0SAchim Leubner /* 35*dce93cd0SAchim Leubner * PCI bus interface and resource allocation. 36*dce93cd0SAchim Leubner */ 37*dce93cd0SAchim Leubner 38*dce93cd0SAchim Leubner #include "opt_aacraid.h" 39*dce93cd0SAchim Leubner 40*dce93cd0SAchim Leubner #include <sys/param.h> 41*dce93cd0SAchim Leubner #include <sys/systm.h> 42*dce93cd0SAchim Leubner #include <sys/kernel.h> 43*dce93cd0SAchim Leubner #include <sys/module.h> 44*dce93cd0SAchim Leubner 45*dce93cd0SAchim Leubner #include <sys/bio.h> 46*dce93cd0SAchim Leubner #include <sys/bus.h> 47*dce93cd0SAchim Leubner #include <sys/conf.h> 48*dce93cd0SAchim Leubner #include <sys/disk.h> 49*dce93cd0SAchim Leubner 50*dce93cd0SAchim Leubner #include <machine/bus.h> 51*dce93cd0SAchim Leubner #include <machine/resource.h> 52*dce93cd0SAchim Leubner #include <sys/rman.h> 53*dce93cd0SAchim Leubner 54*dce93cd0SAchim Leubner #include <dev/pci/pcireg.h> 55*dce93cd0SAchim Leubner #include <dev/pci/pcivar.h> 56*dce93cd0SAchim Leubner 57*dce93cd0SAchim Leubner #include <dev/aacraid/aacraid_reg.h> 58*dce93cd0SAchim Leubner #include <sys/aac_ioctl.h> 59*dce93cd0SAchim Leubner #include <dev/aacraid/aacraid_debug.h> 60*dce93cd0SAchim Leubner #include <dev/aacraid/aacraid_var.h> 61*dce93cd0SAchim Leubner 62*dce93cd0SAchim Leubner static int aacraid_pci_probe(device_t dev); 63*dce93cd0SAchim Leubner static int aacraid_pci_attach(device_t dev); 64*dce93cd0SAchim Leubner 65*dce93cd0SAchim Leubner static device_method_t aacraid_methods[] = { 66*dce93cd0SAchim Leubner /* Device interface */ 67*dce93cd0SAchim Leubner DEVMETHOD(device_probe, aacraid_pci_probe), 68*dce93cd0SAchim Leubner DEVMETHOD(device_attach, aacraid_pci_attach), 69*dce93cd0SAchim Leubner DEVMETHOD(device_detach, aacraid_detach), 70*dce93cd0SAchim Leubner DEVMETHOD(device_suspend, aacraid_suspend), 71*dce93cd0SAchim Leubner DEVMETHOD(device_resume, aacraid_resume), 72*dce93cd0SAchim Leubner 73*dce93cd0SAchim Leubner DEVMETHOD(bus_print_child, bus_generic_print_child), 74*dce93cd0SAchim Leubner DEVMETHOD(bus_driver_added, bus_generic_driver_added), 75*dce93cd0SAchim Leubner { 0, 0 } 76*dce93cd0SAchim Leubner }; 77*dce93cd0SAchim Leubner 78*dce93cd0SAchim Leubner static driver_t aacraid_pci_driver = { 79*dce93cd0SAchim Leubner "aacraid", 80*dce93cd0SAchim Leubner aacraid_methods, 81*dce93cd0SAchim Leubner sizeof(struct aac_softc) 82*dce93cd0SAchim Leubner }; 83*dce93cd0SAchim Leubner 84*dce93cd0SAchim Leubner static devclass_t aacraid_devclass; 85*dce93cd0SAchim Leubner 86*dce93cd0SAchim Leubner DRIVER_MODULE(aacraid, pci, aacraid_pci_driver, aacraid_devclass, 0, 0); 87*dce93cd0SAchim Leubner MODULE_DEPEND(aacraid, pci, 1, 1, 1); 88*dce93cd0SAchim Leubner 89*dce93cd0SAchim Leubner struct aac_ident 90*dce93cd0SAchim Leubner { 91*dce93cd0SAchim Leubner u_int16_t vendor; 92*dce93cd0SAchim Leubner u_int16_t device; 93*dce93cd0SAchim Leubner u_int16_t subvendor; 94*dce93cd0SAchim Leubner u_int16_t subdevice; 95*dce93cd0SAchim Leubner int hwif; 96*dce93cd0SAchim Leubner int quirks; 97*dce93cd0SAchim Leubner char *desc; 98*dce93cd0SAchim Leubner } aacraid_family_identifiers[] = { 99*dce93cd0SAchim Leubner {0x9005, 0x028b, 0, 0, AAC_HWIF_SRC, 0, 100*dce93cd0SAchim Leubner "Adaptec RAID Controller"}, 101*dce93cd0SAchim Leubner {0x9005, 0x028c, 0, 0, AAC_HWIF_SRCV, 0, 102*dce93cd0SAchim Leubner "Adaptec RAID Controller"}, 103*dce93cd0SAchim Leubner {0x9005, 0x028d, 0, 0, AAC_HWIF_SRCV, 0, 104*dce93cd0SAchim Leubner "Adaptec RAID Controller"}, 105*dce93cd0SAchim Leubner {0x9005, 0x028f, 0, 0, AAC_HWIF_SRCV, 0, 106*dce93cd0SAchim Leubner "Adaptec RAID Controller"}, 107*dce93cd0SAchim Leubner {0, 0, 0, 0, 0, 0, 0} 108*dce93cd0SAchim Leubner }; 109*dce93cd0SAchim Leubner 110*dce93cd0SAchim Leubner static struct aac_ident * 111*dce93cd0SAchim Leubner aac_find_ident(device_t dev) 112*dce93cd0SAchim Leubner { 113*dce93cd0SAchim Leubner struct aac_ident *m; 114*dce93cd0SAchim Leubner u_int16_t vendid, devid, sub_vendid, sub_devid; 115*dce93cd0SAchim Leubner 116*dce93cd0SAchim Leubner vendid = pci_get_vendor(dev); 117*dce93cd0SAchim Leubner devid = pci_get_device(dev); 118*dce93cd0SAchim Leubner sub_vendid = pci_get_subvendor(dev); 119*dce93cd0SAchim Leubner sub_devid = pci_get_subdevice(dev); 120*dce93cd0SAchim Leubner 121*dce93cd0SAchim Leubner for (m = aacraid_family_identifiers; m->vendor != 0; m++) { 122*dce93cd0SAchim Leubner if ((m->vendor == vendid) && (m->device == devid)) 123*dce93cd0SAchim Leubner return (m); 124*dce93cd0SAchim Leubner } 125*dce93cd0SAchim Leubner 126*dce93cd0SAchim Leubner return (NULL); 127*dce93cd0SAchim Leubner } 128*dce93cd0SAchim Leubner 129*dce93cd0SAchim Leubner /* 130*dce93cd0SAchim Leubner * Determine whether this is one of our supported adapters. 131*dce93cd0SAchim Leubner */ 132*dce93cd0SAchim Leubner static int 133*dce93cd0SAchim Leubner aacraid_pci_probe(device_t dev) 134*dce93cd0SAchim Leubner { 135*dce93cd0SAchim Leubner struct aac_ident *id; 136*dce93cd0SAchim Leubner 137*dce93cd0SAchim Leubner fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 138*dce93cd0SAchim Leubner 139*dce93cd0SAchim Leubner if ((id = aac_find_ident(dev)) != NULL) { 140*dce93cd0SAchim Leubner device_set_desc(dev, id->desc); 141*dce93cd0SAchim Leubner return(BUS_PROBE_DEFAULT); 142*dce93cd0SAchim Leubner } 143*dce93cd0SAchim Leubner return(ENXIO); 144*dce93cd0SAchim Leubner } 145*dce93cd0SAchim Leubner 146*dce93cd0SAchim Leubner /* 147*dce93cd0SAchim Leubner * Allocate resources for our device, set up the bus interface. 148*dce93cd0SAchim Leubner */ 149*dce93cd0SAchim Leubner static int 150*dce93cd0SAchim Leubner aacraid_pci_attach(device_t dev) 151*dce93cd0SAchim Leubner { 152*dce93cd0SAchim Leubner struct aac_softc *sc; 153*dce93cd0SAchim Leubner struct aac_ident *id; 154*dce93cd0SAchim Leubner int error; 155*dce93cd0SAchim Leubner u_int32_t command; 156*dce93cd0SAchim Leubner 157*dce93cd0SAchim Leubner fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 158*dce93cd0SAchim Leubner 159*dce93cd0SAchim Leubner /* 160*dce93cd0SAchim Leubner * Initialise softc. 161*dce93cd0SAchim Leubner */ 162*dce93cd0SAchim Leubner sc = device_get_softc(dev); 163*dce93cd0SAchim Leubner bzero(sc, sizeof(*sc)); 164*dce93cd0SAchim Leubner sc->aac_dev = dev; 165*dce93cd0SAchim Leubner 166*dce93cd0SAchim Leubner /* assume failure is 'not configured' */ 167*dce93cd0SAchim Leubner error = ENXIO; 168*dce93cd0SAchim Leubner 169*dce93cd0SAchim Leubner /* 170*dce93cd0SAchim Leubner * Verify that the adapter is correctly set up in PCI space. 171*dce93cd0SAchim Leubner */ 172*dce93cd0SAchim Leubner command = pci_read_config(sc->aac_dev, PCIR_COMMAND, 2); 173*dce93cd0SAchim Leubner command |= PCIM_CMD_BUSMASTEREN; 174*dce93cd0SAchim Leubner pci_write_config(dev, PCIR_COMMAND, command, 2); 175*dce93cd0SAchim Leubner command = pci_read_config(sc->aac_dev, PCIR_COMMAND, 2); 176*dce93cd0SAchim Leubner if (!(command & PCIM_CMD_BUSMASTEREN)) { 177*dce93cd0SAchim Leubner device_printf(sc->aac_dev, "can't enable bus-master feature\n"); 178*dce93cd0SAchim Leubner goto out; 179*dce93cd0SAchim Leubner } 180*dce93cd0SAchim Leubner if ((command & PCIM_CMD_MEMEN) == 0) { 181*dce93cd0SAchim Leubner device_printf(sc->aac_dev, "memory window not available\n"); 182*dce93cd0SAchim Leubner goto out; 183*dce93cd0SAchim Leubner } 184*dce93cd0SAchim Leubner 185*dce93cd0SAchim Leubner /* 186*dce93cd0SAchim Leubner * Detect the hardware interface version, set up the bus interface 187*dce93cd0SAchim Leubner * indirection. 188*dce93cd0SAchim Leubner */ 189*dce93cd0SAchim Leubner id = aac_find_ident(dev); 190*dce93cd0SAchim Leubner sc->aac_hwif = id->hwif; 191*dce93cd0SAchim Leubner switch(sc->aac_hwif) { 192*dce93cd0SAchim Leubner case AAC_HWIF_SRC: 193*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_INIT_B, "set hardware up for PMC SRC"); 194*dce93cd0SAchim Leubner sc->aac_if = aacraid_src_interface; 195*dce93cd0SAchim Leubner break; 196*dce93cd0SAchim Leubner case AAC_HWIF_SRCV: 197*dce93cd0SAchim Leubner fwprintf(sc, HBA_FLAGS_DBG_INIT_B, "set hardware up for PMC SRCv"); 198*dce93cd0SAchim Leubner sc->aac_if = aacraid_srcv_interface; 199*dce93cd0SAchim Leubner break; 200*dce93cd0SAchim Leubner default: 201*dce93cd0SAchim Leubner sc->aac_hwif = AAC_HWIF_UNKNOWN; 202*dce93cd0SAchim Leubner device_printf(sc->aac_dev, "unknown hardware type\n"); 203*dce93cd0SAchim Leubner error = ENXIO; 204*dce93cd0SAchim Leubner goto out; 205*dce93cd0SAchim Leubner } 206*dce93cd0SAchim Leubner 207*dce93cd0SAchim Leubner /* assume failure is 'out of memory' */ 208*dce93cd0SAchim Leubner error = ENOMEM; 209*dce93cd0SAchim Leubner 210*dce93cd0SAchim Leubner /* 211*dce93cd0SAchim Leubner * Allocate the PCI register window. 212*dce93cd0SAchim Leubner */ 213*dce93cd0SAchim Leubner sc->aac_regs_rid0 = PCIR_BAR(0); 214*dce93cd0SAchim Leubner if ((sc->aac_regs_res0 = bus_alloc_resource_any(sc->aac_dev, 215*dce93cd0SAchim Leubner SYS_RES_MEMORY, &sc->aac_regs_rid0, RF_ACTIVE)) == NULL) { 216*dce93cd0SAchim Leubner device_printf(sc->aac_dev, 217*dce93cd0SAchim Leubner "couldn't allocate register window 0\n"); 218*dce93cd0SAchim Leubner goto out; 219*dce93cd0SAchim Leubner } 220*dce93cd0SAchim Leubner sc->aac_btag0 = rman_get_bustag(sc->aac_regs_res0); 221*dce93cd0SAchim Leubner sc->aac_bhandle0 = rman_get_bushandle(sc->aac_regs_res0); 222*dce93cd0SAchim Leubner 223*dce93cd0SAchim Leubner sc->aac_regs_rid1 = PCIR_BAR(2); 224*dce93cd0SAchim Leubner if ((sc->aac_regs_res1 = bus_alloc_resource_any(sc->aac_dev, 225*dce93cd0SAchim Leubner SYS_RES_MEMORY, &sc->aac_regs_rid1, RF_ACTIVE)) == NULL) { 226*dce93cd0SAchim Leubner device_printf(sc->aac_dev, 227*dce93cd0SAchim Leubner "couldn't allocate register window 1\n"); 228*dce93cd0SAchim Leubner goto out; 229*dce93cd0SAchim Leubner } 230*dce93cd0SAchim Leubner sc->aac_btag1 = rman_get_bustag(sc->aac_regs_res1); 231*dce93cd0SAchim Leubner sc->aac_bhandle1 = rman_get_bushandle(sc->aac_regs_res1); 232*dce93cd0SAchim Leubner 233*dce93cd0SAchim Leubner /* 234*dce93cd0SAchim Leubner * Allocate the parent bus DMA tag appropriate for our PCI interface. 235*dce93cd0SAchim Leubner * 236*dce93cd0SAchim Leubner * Note that some of these controllers are 64-bit capable. 237*dce93cd0SAchim Leubner */ 238*dce93cd0SAchim Leubner if (bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */ 239*dce93cd0SAchim Leubner PAGE_SIZE, 0, /* algnmnt, boundary */ 240*dce93cd0SAchim Leubner BUS_SPACE_MAXADDR, /* lowaddr */ 241*dce93cd0SAchim Leubner BUS_SPACE_MAXADDR, /* highaddr */ 242*dce93cd0SAchim Leubner NULL, NULL, /* filter, filterarg */ 243*dce93cd0SAchim Leubner BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ 244*dce93cd0SAchim Leubner BUS_SPACE_UNRESTRICTED, /* nsegments */ 245*dce93cd0SAchim Leubner BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 246*dce93cd0SAchim Leubner 0, /* flags */ 247*dce93cd0SAchim Leubner NULL, NULL, /* No locking needed */ 248*dce93cd0SAchim Leubner &sc->aac_parent_dmat)) { 249*dce93cd0SAchim Leubner device_printf(sc->aac_dev, "can't allocate parent DMA tag\n"); 250*dce93cd0SAchim Leubner goto out; 251*dce93cd0SAchim Leubner } 252*dce93cd0SAchim Leubner 253*dce93cd0SAchim Leubner /* Set up quirks */ 254*dce93cd0SAchim Leubner sc->flags = id->quirks; 255*dce93cd0SAchim Leubner 256*dce93cd0SAchim Leubner /* 257*dce93cd0SAchim Leubner * Do bus-independent initialisation. 258*dce93cd0SAchim Leubner */ 259*dce93cd0SAchim Leubner error = aacraid_attach(sc); 260*dce93cd0SAchim Leubner 261*dce93cd0SAchim Leubner out: 262*dce93cd0SAchim Leubner if (error) 263*dce93cd0SAchim Leubner aacraid_free(sc); 264*dce93cd0SAchim Leubner return(error); 265*dce93cd0SAchim Leubner } 266