ida_pci.c revision 281826
161033Sdfr/*-
261033Sdfr * Copyright (c) 1999,2000 Jonathan Lemon
361033Sdfr * All rights reserved.
461033Sdfr *
561033Sdfr * Redistribution and use in source and binary forms, with or without
661033Sdfr * modification, are permitted provided that the following conditions
761033Sdfr * are met:
861033Sdfr * 1. Redistributions of source code must retain the above copyright
961033Sdfr *    notice, this list of conditions and the following disclaimer.
1061033Sdfr * 2. Redistributions in binary form must reproduce the above copyright
1161033Sdfr *    notice, this list of conditions and the following disclaimer in the
1261033Sdfr *    documentation and/or other materials provided with the distribution.
1361033Sdfr *
1461033Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1561033Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1661033Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1761033Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1861033Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1961033Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2061033Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2161033Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2261033Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2361033Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2461033Sdfr * SUCH DAMAGE.
2561033Sdfr */
2661033Sdfr
27116182Sobrien#include <sys/cdefs.h>
28116182Sobrien__FBSDID("$FreeBSD: stable/10/sys/dev/ida/ida_pci.c 281826 2015-04-21 11:27:50Z mav $");
29116182Sobrien
3061033Sdfr#include <sys/param.h>
3185521Sjhb#include <sys/systm.h>
3265822Sjhb#include <sys/kernel.h>
3385560Sjhb#include <sys/module.h>
3461033Sdfr
35123614Sjhb#include <sys/bio.h>
3685521Sjhb#include <sys/bus.h>
3761033Sdfr#include <sys/conf.h>
3885521Sjhb
39145729Ssam#include <machine/bus.h>
40154333Sscottl#include <machine/resource.h>
4185521Sjhb#include <sys/rman.h>
42119708Sken
43154333Sscottl#include <dev/pci/pcireg.h>
4461033Sdfr#include <dev/pci/pcivar.h>
4569774Sphk
46123614Sjhb#include <geom/geom_disk.h>
47123614Sjhb
4861033Sdfr#include <dev/ida/idavar.h>
4985521Sjhb#include <dev/ida/idareg.h>
5067551Sjhb
5161033Sdfr#define	IDA_PCI_MAX_DMA_ADDR	0xFFFFFFFF
5261033Sdfr#define	IDA_PCI_MAX_DMA_COUNT	0xFFFFFFFF
5361033Sdfr
5461033Sdfr#define	IDA_PCI_MEMADDR		PCIR_BAR(1)		/* Mem I/O Address */
5561033Sdfr
5661033Sdfr#define	IDA_DEVICEID_SMART		0xAE100E11
57145473Ssam#define	IDA_DEVICEID_DEC_SMART		0x00461011
5885521Sjhb#define	IDA_DEVICEID_NCR_53C1510	0x00101000
59178015Ssam
60178015Ssamstatic int
61180588Skmacyida_v3_fifo_full(struct ida_softc *ida)
62154333Sscottl{
6361033Sdfr	return (ida_inl(ida, R_CMD_FIFO) == 0);
6461033Sdfr}
65154333Sscottl
66177621Sscottlstatic void
67177621Sscottlida_v3_submit(struct ida_softc *ida, struct ida_qcb *qcb)
68154333Sscottl{
69180588Skmacy	ida_outl(ida, R_CMD_FIFO, qcb->hwqcb_busaddr);
70180588Skmacy}
71180588Skmacy
72180588Skmacystatic bus_addr_t
73180588Skmacyida_v3_done(struct ida_softc *ida)
74180588Skmacy{
75180588Skmacy	bus_addr_t completed;
76180588Skmacy
77154167Sscottl	completed = ida_inl(ida, R_DONE_FIFO);
78180588Skmacy	if (completed == -1) {
79180588Skmacy		return (0);			/* fifo is empty */
80180588Skmacy	}
81180588Skmacy	return (completed);
82180588Skmacy}
83180588Skmacy
84180588Skmacystatic int
85180588Skmacyida_v3_int_pending(struct ida_softc *ida)
86154167Sscottl{
8785521Sjhb	return (ida_inl(ida, R_INT_PENDING));
8885521Sjhb}
89154167Sscottl
90154167Sscottlstatic void
91154167Sscottlida_v3_int_enable(struct ida_softc *ida, int enable)
92154167Sscottl{
93180588Skmacy	if (enable)
94154167Sscottl		ida->flags |= IDA_INTERRUPTS;
95154167Sscottl	else
96154167Sscottl		ida->flags &= ~IDA_INTERRUPTS;
97154167Sscottl	ida_outl(ida, R_INT_MASK, enable ? INT_ENABLE : INT_DISABLE);
9885521Sjhb}
9985521Sjhb
10085521Sjhbstatic int
10185521Sjhbida_v4_fifo_full(struct ida_softc *ida)
10293818Sjhb{
10385521Sjhb	return (ida_inl(ida, R_42XX_REQUEST) != 0);
10485521Sjhb}
10585521Sjhb
10685521Sjhbstatic void
10785521Sjhbida_v4_submit(struct ida_softc *ida, struct ida_qcb *qcb)
108154167Sscottl{
109154167Sscottl	ida_outl(ida, R_42XX_REQUEST, qcb->hwqcb_busaddr);
110145729Ssam}
111154167Sscottl
11261033Sdfrstatic bus_addr_t
11361033Sdfrida_v4_done(struct ida_softc *ida)
114180588Skmacy{
11585521Sjhb	bus_addr_t completed;
11661033Sdfr
117188058Simp	completed = ida_inl(ida, R_42XX_REPLY);
118180588Skmacy	if (completed == -1)
11961033Sdfr		return (0);			/* fifo is empty */
12061033Sdfr	ida_outl(ida, R_42XX_REPLY, 0);		/* confirm read */
12161033Sdfr	return (completed);
12261033Sdfr}
123180588Skmacy
124180588Skmacystatic int
125154167Sscottlida_v4_int_pending(struct ida_softc *ida)
12661033Sdfr{
12785521Sjhb	return (ida_inl(ida, R_42XX_STATUS) & STATUS_42XX_INT_PENDING);
12861033Sdfr}
12985521Sjhb
13061033Sdfrstatic void
13161033Sdfrida_v4_int_enable(struct ida_softc *ida, int enable)
13261033Sdfr{
13361033Sdfr	if (enable)
134154167Sscottl		ida->flags |= IDA_INTERRUPTS;
135154167Sscottl	else
136154333Sscottl		ida->flags &= ~IDA_INTERRUPTS;
137154167Sscottl	ida_outl(ida, R_42XX_INT_MASK,
138154333Sscottl	    enable ? INT_ENABLE_42XX : INT_DISABLE_42XX);
139154167Sscottl}
140154167Sscottl
141154167Sscottlstatic struct ida_access ida_v3_access = {
142145729Ssam	ida_v3_fifo_full,
143145729Ssam	ida_v3_submit,
144145729Ssam	ida_v3_done,
145145729Ssam	ida_v3_int_pending,
146178015Ssam	ida_v3_int_enable,
147145729Ssam};
148145729Ssam
149178015Ssamstatic struct ida_access ida_v4_access = {
150154333Sscottl	ida_v4_fifo_full,
151154333Sscottl	ida_v4_submit,
152145729Ssam	ida_v4_done,
153145729Ssam	ida_v4_int_pending,
154145729Ssam	ida_v4_int_enable,
15561033Sdfr};
15661033Sdfr
15761033Sdfrstatic struct ida_board board_id[] = {
15885521Sjhb	{ 0x40300E11, "Compaq SMART-2/P array controller",
15985521Sjhb	    &ida_v3_access, 0 },
16061033Sdfr	{ 0x40310E11, "Compaq SMART-2SL array controller",
16185521Sjhb	    &ida_v3_access, 0 },
16261033Sdfr	{ 0x40320E11, "Compaq Smart Array 3200 controller",
163154167Sscottl	    &ida_v3_access, 0 },
164154333Sscottl	{ 0x40330E11, "Compaq Smart Array 3100ES controller",
165131246Sjhb	    &ida_v3_access, 0 },
166178015Ssam	{ 0x40340E11, "Compaq Smart Array 221 controller",
16785521Sjhb	    &ida_v3_access, 0 },
168178015Ssam
16961033Sdfr	{ 0x40400E11, "Compaq Integrated Array controller",
17061033Sdfr	    &ida_v4_access, IDA_FIRMWARE },
17161033Sdfr	{ 0x40480E11, "Compaq RAID LC2 controller",
17285521Sjhb	    &ida_v4_access, IDA_FIRMWARE },
17385521Sjhb	{ 0x40500E11, "Compaq Smart Array 4200 controller",
17485521Sjhb	    &ida_v4_access, 0 },
17561033Sdfr	{ 0x40510E11, "Compaq Smart Array 4250ES controller",
17661033Sdfr	    &ida_v4_access, 0 },
17761033Sdfr	{ 0x40580E11, "Compaq Smart Array 431 controller",
17861033Sdfr	    &ida_v4_access, 0 },
17961033Sdfr
18085521Sjhb	{ 0, "", 0, 0 },
18185521Sjhb};
182123614Sjhb
183154167Sscottlstatic int ida_pci_probe(device_t dev);
18485521Sjhbstatic int ida_pci_attach(device_t dev);
18561033Sdfr
18661033Sdfrstatic device_method_t ida_pci_methods[] = {
18785521Sjhb	DEVMETHOD(device_probe,		ida_pci_probe),
18885521Sjhb	DEVMETHOD(device_attach,	ida_pci_attach),
189123614Sjhb	DEVMETHOD(device_detach,	ida_detach),
19061033Sdfr
19161033Sdfr	DEVMETHOD_END
19261033Sdfr};
19361033Sdfr
19461033Sdfrstatic driver_t ida_pci_driver = {
19561033Sdfr	"ida",
19661033Sdfr	ida_pci_methods,
19761033Sdfr	sizeof(struct ida_softc)
198154167Sscottl};
19985560Sjhb
20061033Sdfrstatic devclass_t ida_devclass;
20161033Sdfr
20261033Sdfrstatic struct ida_board *
203180588Skmacyida_pci_match(device_t dev)
20461033Sdfr{
205154167Sscottl	int i;
20661033Sdfr	u_int32_t id, sub_id;
20761033Sdfr
20861033Sdfr	id = pci_get_devid(dev);
20961033Sdfr	sub_id = pci_get_subdevice(dev) << 16 | pci_get_subvendor(dev);
21061033Sdfr
21161033Sdfr	if (id == IDA_DEVICEID_SMART ||
21264199Shsu	    id == IDA_DEVICEID_DEC_SMART ||
21361033Sdfr	    id == IDA_DEVICEID_NCR_53C1510) {
21461033Sdfr		for (i = 0; board_id[i].board; i++)
21561033Sdfr			if (board_id[i].board == sub_id)
216188058Simp				return (&board_id[i]);
21761033Sdfr	}
21861033Sdfr	return (NULL);
21961033Sdfr}
22061033Sdfr
22161033Sdfrstatic int
22261033Sdfrida_pci_probe(device_t dev)
22361033Sdfr{
22461033Sdfr	struct ida_board *board = ida_pci_match(dev);
22561033Sdfr
22661033Sdfr	if (board != NULL) {
22761033Sdfr		device_set_desc(dev, board->desc);
22861033Sdfr		return (BUS_PROBE_DEFAULT);
229180588Skmacy	}
230177621Sscottl	return (ENXIO);
231180588Skmacy}
232177621Sscottl
23385560Sjhbstatic int
234154167Sscottlida_pci_attach(device_t dev)
23585560Sjhb{
23661033Sdfr	struct ida_board *board = ida_pci_match(dev);
23761033Sdfr	u_int32_t id = pci_get_devid(dev);
23861033Sdfr	struct ida_softc *ida;
23961033Sdfr	int error, rid;
240177621Sscottl
241177621Sscottl	ida = (struct ida_softc *)device_get_softc(dev);
242177621Sscottl	ida->dev = dev;
243177621Sscottl	ida->cmd = *board->accessor;
244177621Sscottl	ida->flags = board->flags;
245177621Sscottl	mtx_init(&ida->lock, "ida", NULL, MTX_DEF);
246177621Sscottl	callout_init_mtx(&ida->ch, &ida->lock, 0);
247177621Sscottl
248177621Sscottl	ida->regs_res_type = SYS_RES_MEMORY;
249177621Sscottl	ida->regs_res_id = IDA_PCI_MEMADDR;
250177621Sscottl	if (id == IDA_DEVICEID_DEC_SMART)
251177621Sscottl		ida->regs_res_id = PCIR_BAR(0);
252177621Sscottl
253177621Sscottl	ida->regs = bus_alloc_resource_any(dev, ida->regs_res_type,
254177621Sscottl	    &ida->regs_res_id, RF_ACTIVE);
255177621Sscottl	if (ida->regs == NULL) {
256177621Sscottl		device_printf(dev, "can't allocate memory resources\n");
257177621Sscottl		return (ENOMEM);
258177621Sscottl	}
259177621Sscottl
260177621Sscottl	error = bus_dma_tag_create(
261177621Sscottl		/* parent	*/ bus_get_dma_tag(dev),
26261033Sdfr		/* alignment	*/ 1,
26361033Sdfr		/* boundary	*/ 0,
26461033Sdfr		/* lowaddr	*/ BUS_SPACE_MAXADDR_32BIT,
265131246Sjhb		/* highaddr	*/ BUS_SPACE_MAXADDR,
26661033Sdfr		/* filter	*/ NULL,
267131246Sjhb		/* filterarg	*/ NULL,
268131246Sjhb		/* maxsize	*/ BUS_SPACE_MAXSIZE_32BIT,
269154167Sscottl		/* nsegments	*/ BUS_SPACE_UNRESTRICTED,
27061033Sdfr		/* maxsegsize	*/ BUS_SPACE_MAXSIZE_32BIT,
27161033Sdfr		/* flags	*/ BUS_DMA_ALLOCNOW,
27261033Sdfr		/* lockfunc	*/ NULL,
27361033Sdfr		/* lockarg	*/ NULL,
27461033Sdfr		&ida->parent_dmat);
27561033Sdfr	if (error != 0) {
27661033Sdfr		device_printf(dev, "can't allocate DMA tag\n");
27761033Sdfr		ida_free(ida);
27861033Sdfr		return (ENOMEM);
279145473Ssam	}
280154167Sscottl
28161033Sdfr	rid = 0;
28285560Sjhb	ida->irq_res_type = SYS_RES_IRQ;
28361033Sdfr	ida->irq = bus_alloc_resource_any(dev, ida->irq_res_type, &rid,
284154167Sscottl	    RF_ACTIVE | RF_SHAREABLE);
285145473Ssam	if (ida->irq == NULL) {
286136131Simp	        ida_free(ida);
28761033Sdfr	        return (ENOMEM);
288131246Sjhb	}
289131246Sjhb	error = bus_setup_intr(dev, ida->irq, INTR_TYPE_BIO | INTR_ENTROPY | INTR_MPSAFE,
290131246Sjhb	    NULL, ida_intr, ida, &ida->ih);
291131246Sjhb	if (error) {
292131246Sjhb		device_printf(dev, "can't setup interrupt\n");
293131246Sjhb		ida_free(ida);
294154167Sscottl		return (ENOMEM);
29561033Sdfr	}
29661033Sdfr
297136131Simp	error = ida_init(ida);
298136131Simp	if (error) {
299136131Simp	        ida_free(ida);
300180588Skmacy	        return (error);
301154167Sscottl	}
302154167Sscottl
303154167Sscottl	return (0);
304154167Sscottl}
305154167Sscottl
306154167SscottlDRIVER_MODULE(ida, pci, ida_pci_driver, ida_devclass, 0, 0);
307145729Ssam