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