1250963Sachim/*- 2250963Sachim * Copyright (c) 2000 Michael Smith 3250963Sachim * Copyright (c) 2001 Scott Long 4250963Sachim * Copyright (c) 2000 BSDi 5250963Sachim * Copyright (c) 2001-2010 Adaptec, Inc. 6250963Sachim * Copyright (c) 2010-2012 PMC-Sierra, Inc. 7250963Sachim * All rights reserved. 8250963Sachim * 9250963Sachim * Redistribution and use in source and binary forms, with or without 10250963Sachim * modification, are permitted provided that the following conditions 11250963Sachim * are met: 12250963Sachim * 1. Redistributions of source code must retain the above copyright 13250963Sachim * notice, this list of conditions and the following disclaimer. 14250963Sachim * 2. Redistributions in binary form must reproduce the above copyright 15250963Sachim * notice, this list of conditions and the following disclaimer in the 16250963Sachim * documentation and/or other materials provided with the distribution. 17250963Sachim * 18250963Sachim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19250963Sachim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20250963Sachim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21250963Sachim * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22250963Sachim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23250963Sachim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24250963Sachim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25250963Sachim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26250963Sachim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27250963Sachim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28250963Sachim * SUCH DAMAGE. 29250963Sachim */ 30250963Sachim 31250963Sachim#include <sys/cdefs.h> 32250963Sachim__FBSDID("$FreeBSD$"); 33250963Sachim 34250963Sachim/* 35250963Sachim * PCI bus interface and resource allocation. 36250963Sachim */ 37250963Sachim 38250963Sachim#include "opt_aacraid.h" 39250963Sachim 40250963Sachim#include <sys/param.h> 41250963Sachim#include <sys/systm.h> 42250963Sachim#include <sys/kernel.h> 43250963Sachim#include <sys/module.h> 44250963Sachim 45250963Sachim#include <sys/bio.h> 46250963Sachim#include <sys/bus.h> 47250963Sachim#include <sys/conf.h> 48250963Sachim#include <sys/disk.h> 49250963Sachim 50250963Sachim#include <machine/bus.h> 51250963Sachim#include <machine/resource.h> 52250963Sachim#include <sys/rman.h> 53250963Sachim 54250963Sachim#include <dev/pci/pcireg.h> 55250963Sachim#include <dev/pci/pcivar.h> 56250963Sachim 57250963Sachim#include <dev/aacraid/aacraid_reg.h> 58250963Sachim#include <sys/aac_ioctl.h> 59250963Sachim#include <dev/aacraid/aacraid_debug.h> 60250963Sachim#include <dev/aacraid/aacraid_var.h> 61250963Sachim 62250963Sachimstatic int aacraid_pci_probe(device_t dev); 63250963Sachimstatic int aacraid_pci_attach(device_t dev); 64250963Sachim 65250963Sachimstatic device_method_t aacraid_methods[] = { 66250963Sachim /* Device interface */ 67250963Sachim DEVMETHOD(device_probe, aacraid_pci_probe), 68250963Sachim DEVMETHOD(device_attach, aacraid_pci_attach), 69250963Sachim DEVMETHOD(device_detach, aacraid_detach), 70250963Sachim DEVMETHOD(device_suspend, aacraid_suspend), 71250963Sachim DEVMETHOD(device_resume, aacraid_resume), 72250963Sachim 73250963Sachim DEVMETHOD(bus_print_child, bus_generic_print_child), 74250963Sachim DEVMETHOD(bus_driver_added, bus_generic_driver_added), 75250963Sachim { 0, 0 } 76250963Sachim}; 77250963Sachim 78250963Sachimstatic driver_t aacraid_pci_driver = { 79250963Sachim "aacraid", 80250963Sachim aacraid_methods, 81250963Sachim sizeof(struct aac_softc) 82250963Sachim}; 83250963Sachim 84250963Sachimstatic devclass_t aacraid_devclass; 85250963Sachim 86250963SachimDRIVER_MODULE(aacraid, pci, aacraid_pci_driver, aacraid_devclass, 0, 0); 87250963SachimMODULE_DEPEND(aacraid, pci, 1, 1, 1); 88250963Sachim 89250963Sachimstruct aac_ident 90250963Sachim{ 91250963Sachim u_int16_t vendor; 92250963Sachim u_int16_t device; 93250963Sachim u_int16_t subvendor; 94250963Sachim u_int16_t subdevice; 95250963Sachim int hwif; 96250963Sachim int quirks; 97250963Sachim char *desc; 98250963Sachim} aacraid_family_identifiers[] = { 99250963Sachim {0x9005, 0x028b, 0, 0, AAC_HWIF_SRC, 0, 100250963Sachim "Adaptec RAID Controller"}, 101250963Sachim {0x9005, 0x028c, 0, 0, AAC_HWIF_SRCV, 0, 102250963Sachim "Adaptec RAID Controller"}, 103250963Sachim {0x9005, 0x028d, 0, 0, AAC_HWIF_SRCV, 0, 104250963Sachim "Adaptec RAID Controller"}, 105250963Sachim {0x9005, 0x028f, 0, 0, AAC_HWIF_SRCV, 0, 106250963Sachim "Adaptec RAID Controller"}, 107250963Sachim {0, 0, 0, 0, 0, 0, 0} 108250963Sachim}; 109250963Sachim 110250963Sachimstatic struct aac_ident * 111250963Sachimaac_find_ident(device_t dev) 112250963Sachim{ 113250963Sachim struct aac_ident *m; 114250963Sachim u_int16_t vendid, devid, sub_vendid, sub_devid; 115250963Sachim 116250963Sachim vendid = pci_get_vendor(dev); 117250963Sachim devid = pci_get_device(dev); 118250963Sachim sub_vendid = pci_get_subvendor(dev); 119250963Sachim sub_devid = pci_get_subdevice(dev); 120250963Sachim 121250963Sachim for (m = aacraid_family_identifiers; m->vendor != 0; m++) { 122250963Sachim if ((m->vendor == vendid) && (m->device == devid)) 123250963Sachim return (m); 124250963Sachim } 125250963Sachim 126250963Sachim return (NULL); 127250963Sachim} 128250963Sachim 129250963Sachim/* 130250963Sachim * Determine whether this is one of our supported adapters. 131250963Sachim */ 132250963Sachimstatic int 133250963Sachimaacraid_pci_probe(device_t dev) 134250963Sachim{ 135250963Sachim struct aac_ident *id; 136250963Sachim 137250963Sachim fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 138250963Sachim 139250963Sachim if ((id = aac_find_ident(dev)) != NULL) { 140250963Sachim device_set_desc(dev, id->desc); 141250963Sachim return(BUS_PROBE_DEFAULT); 142250963Sachim } 143250963Sachim return(ENXIO); 144250963Sachim} 145250963Sachim 146250963Sachim/* 147250963Sachim * Allocate resources for our device, set up the bus interface. 148250963Sachim */ 149250963Sachimstatic int 150250963Sachimaacraid_pci_attach(device_t dev) 151250963Sachim{ 152250963Sachim struct aac_softc *sc; 153250963Sachim struct aac_ident *id; 154250963Sachim int error; 155250963Sachim u_int32_t command; 156250963Sachim 157250963Sachim fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 158250963Sachim 159250963Sachim /* 160250963Sachim * Initialise softc. 161250963Sachim */ 162250963Sachim sc = device_get_softc(dev); 163250963Sachim bzero(sc, sizeof(*sc)); 164250963Sachim sc->aac_dev = dev; 165250963Sachim 166250963Sachim /* assume failure is 'not configured' */ 167250963Sachim error = ENXIO; 168250963Sachim 169250963Sachim /* 170250963Sachim * Verify that the adapter is correctly set up in PCI space. 171250963Sachim */ 172254263Sscottl pci_enable_busmaster(dev); 173250963Sachim command = pci_read_config(sc->aac_dev, PCIR_COMMAND, 2); 174250963Sachim if (!(command & PCIM_CMD_BUSMASTEREN)) { 175250963Sachim device_printf(sc->aac_dev, "can't enable bus-master feature\n"); 176250963Sachim goto out; 177250963Sachim } 178250963Sachim 179250963Sachim /* 180250963Sachim * Detect the hardware interface version, set up the bus interface 181250963Sachim * indirection. 182250963Sachim */ 183250963Sachim id = aac_find_ident(dev); 184250963Sachim sc->aac_hwif = id->hwif; 185250963Sachim switch(sc->aac_hwif) { 186250963Sachim case AAC_HWIF_SRC: 187250963Sachim fwprintf(sc, HBA_FLAGS_DBG_INIT_B, "set hardware up for PMC SRC"); 188250963Sachim sc->aac_if = aacraid_src_interface; 189250963Sachim break; 190250963Sachim case AAC_HWIF_SRCV: 191250963Sachim fwprintf(sc, HBA_FLAGS_DBG_INIT_B, "set hardware up for PMC SRCv"); 192250963Sachim sc->aac_if = aacraid_srcv_interface; 193250963Sachim break; 194250963Sachim default: 195250963Sachim sc->aac_hwif = AAC_HWIF_UNKNOWN; 196250963Sachim device_printf(sc->aac_dev, "unknown hardware type\n"); 197250963Sachim error = ENXIO; 198250963Sachim goto out; 199250963Sachim } 200250963Sachim 201250963Sachim /* assume failure is 'out of memory' */ 202250963Sachim error = ENOMEM; 203250963Sachim 204250963Sachim /* 205250963Sachim * Allocate the PCI register window. 206250963Sachim */ 207250963Sachim sc->aac_regs_rid0 = PCIR_BAR(0); 208250963Sachim if ((sc->aac_regs_res0 = bus_alloc_resource_any(sc->aac_dev, 209250963Sachim SYS_RES_MEMORY, &sc->aac_regs_rid0, RF_ACTIVE)) == NULL) { 210250963Sachim device_printf(sc->aac_dev, 211250963Sachim "couldn't allocate register window 0\n"); 212250963Sachim goto out; 213250963Sachim } 214250963Sachim sc->aac_btag0 = rman_get_bustag(sc->aac_regs_res0); 215250963Sachim sc->aac_bhandle0 = rman_get_bushandle(sc->aac_regs_res0); 216250963Sachim 217250963Sachim sc->aac_regs_rid1 = PCIR_BAR(2); 218250963Sachim if ((sc->aac_regs_res1 = bus_alloc_resource_any(sc->aac_dev, 219250963Sachim SYS_RES_MEMORY, &sc->aac_regs_rid1, RF_ACTIVE)) == NULL) { 220250963Sachim device_printf(sc->aac_dev, 221250963Sachim "couldn't allocate register window 1\n"); 222250963Sachim goto out; 223250963Sachim } 224250963Sachim sc->aac_btag1 = rman_get_bustag(sc->aac_regs_res1); 225250963Sachim sc->aac_bhandle1 = rman_get_bushandle(sc->aac_regs_res1); 226250963Sachim 227250963Sachim /* 228250963Sachim * Allocate the parent bus DMA tag appropriate for our PCI interface. 229250963Sachim * 230250963Sachim * Note that some of these controllers are 64-bit capable. 231250963Sachim */ 232250963Sachim if (bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */ 233250963Sachim PAGE_SIZE, 0, /* algnmnt, boundary */ 234250963Sachim BUS_SPACE_MAXADDR, /* lowaddr */ 235250963Sachim BUS_SPACE_MAXADDR, /* highaddr */ 236250963Sachim NULL, NULL, /* filter, filterarg */ 237250963Sachim BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ 238250963Sachim BUS_SPACE_UNRESTRICTED, /* nsegments */ 239250963Sachim BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 240250963Sachim 0, /* flags */ 241250963Sachim NULL, NULL, /* No locking needed */ 242250963Sachim &sc->aac_parent_dmat)) { 243250963Sachim device_printf(sc->aac_dev, "can't allocate parent DMA tag\n"); 244250963Sachim goto out; 245250963Sachim } 246250963Sachim 247250963Sachim /* Set up quirks */ 248250963Sachim sc->flags = id->quirks; 249250963Sachim 250250963Sachim /* 251250963Sachim * Do bus-independent initialisation. 252250963Sachim */ 253250963Sachim error = aacraid_attach(sc); 254250963Sachim 255250963Sachimout: 256250963Sachim if (error) 257250963Sachim aacraid_free(sc); 258250963Sachim return(error); 259250963Sachim} 260