148156Sjlemon/*-
257828Sjlemon * Copyright (c) 1999,2000 Jonathan Lemon
348156Sjlemon * All rights reserved.
448156Sjlemon *
548156Sjlemon * Redistribution and use in source and binary forms, with or without
648156Sjlemon * modification, are permitted provided that the following conditions
748156Sjlemon * are met:
848156Sjlemon * 1. Redistributions of source code must retain the above copyright
948156Sjlemon *    notice, this list of conditions and the following disclaimer.
1048156Sjlemon * 2. Redistributions in binary form must reproduce the above copyright
1148156Sjlemon *    notice, this list of conditions and the following disclaimer in the
1248156Sjlemon *    documentation and/or other materials provided with the distribution.
1348156Sjlemon *
1448156Sjlemon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1548156Sjlemon * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1648156Sjlemon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1748156Sjlemon * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1848156Sjlemon * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1948156Sjlemon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2048156Sjlemon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2148156Sjlemon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2248156Sjlemon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2348156Sjlemon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2448156Sjlemon * SUCH DAMAGE.
2548156Sjlemon */
2648156Sjlemon
27119418Sobrien#include <sys/cdefs.h>
28119418Sobrien__FBSDID("$FreeBSD$");
29119418Sobrien
3048156Sjlemon#include <sys/param.h>
3148156Sjlemon#include <sys/systm.h>
3248156Sjlemon#include <sys/kernel.h>
33129879Sphk#include <sys/module.h>
3448156Sjlemon
3560041Sphk#include <sys/bio.h>
3648156Sjlemon#include <sys/bus.h>
37111337Sphk#include <sys/conf.h>
3848156Sjlemon
3948156Sjlemon#include <machine/bus.h>
4048156Sjlemon#include <machine/resource.h>
4148156Sjlemon#include <sys/rman.h>
4248156Sjlemon
43119280Simp#include <dev/pci/pcireg.h>
44119280Simp#include <dev/pci/pcivar.h>
4548156Sjlemon
46112946Sphk#include <geom/geom_disk.h>
47112946Sphk
4848156Sjlemon#include <dev/ida/idavar.h>
4957828Sjlemon#include <dev/ida/idareg.h>
5048156Sjlemon
51124471Smdodd#define	IDA_PCI_MAX_DMA_ADDR	0xFFFFFFFF
52124471Smdodd#define	IDA_PCI_MAX_DMA_COUNT	0xFFFFFFFF
5348156Sjlemon
54124471Smdodd#define	IDA_PCI_MEMADDR		PCIR_BAR(1)		/* Mem I/O Address */
5548156Sjlemon
56124471Smdodd#define	IDA_DEVICEID_SMART		0xAE100E11
57124471Smdodd#define	IDA_DEVICEID_DEC_SMART		0x00461011
58124471Smdodd#define	IDA_DEVICEID_NCR_53C1510	0x00101000
5948156Sjlemon
6057828Sjlemonstatic int
6157828Sjlemonida_v3_fifo_full(struct ida_softc *ida)
6257828Sjlemon{
6357828Sjlemon	return (ida_inl(ida, R_CMD_FIFO) == 0);
6457828Sjlemon}
6548156Sjlemon
6657828Sjlemonstatic void
6757828Sjlemonida_v3_submit(struct ida_softc *ida, struct ida_qcb *qcb)
6857828Sjlemon{
6957828Sjlemon	ida_outl(ida, R_CMD_FIFO, qcb->hwqcb_busaddr);
7057828Sjlemon}
7157828Sjlemon
7257828Sjlemonstatic bus_addr_t
7357828Sjlemonida_v3_done(struct ida_softc *ida)
7457828Sjlemon{
75138852Smdodd	bus_addr_t completed;
76138852Smdodd
77138852Smdodd	completed = ida_inl(ida, R_DONE_FIFO);
78138852Smdodd	if (completed == -1) {
79138852Smdodd		return (0);			/* fifo is empty */
80138852Smdodd	}
81138852Smdodd	return (completed);
8257828Sjlemon}
8357828Sjlemon
8457828Sjlemonstatic int
8557828Sjlemonida_v3_int_pending(struct ida_softc *ida)
8657828Sjlemon{
8757828Sjlemon	return (ida_inl(ida, R_INT_PENDING));
8857828Sjlemon}
8957828Sjlemon
9057828Sjlemonstatic void
9157828Sjlemonida_v3_int_enable(struct ida_softc *ida, int enable)
9257828Sjlemon{
9373113Sjlemon	if (enable)
9473113Sjlemon		ida->flags |= IDA_INTERRUPTS;
9573113Sjlemon	else
9673113Sjlemon		ida->flags &= ~IDA_INTERRUPTS;
9757828Sjlemon	ida_outl(ida, R_INT_MASK, enable ? INT_ENABLE : INT_DISABLE);
9857828Sjlemon}
9957828Sjlemon
10057828Sjlemonstatic int
10157828Sjlemonida_v4_fifo_full(struct ida_softc *ida)
10257828Sjlemon{
10357828Sjlemon	return (ida_inl(ida, R_42XX_REQUEST) != 0);
10457828Sjlemon}
10557828Sjlemon
10657828Sjlemonstatic void
10757828Sjlemonida_v4_submit(struct ida_softc *ida, struct ida_qcb *qcb)
10857828Sjlemon{
10957828Sjlemon	ida_outl(ida, R_42XX_REQUEST, qcb->hwqcb_busaddr);
11057828Sjlemon}
11157828Sjlemon
11257828Sjlemonstatic bus_addr_t
11357828Sjlemonida_v4_done(struct ida_softc *ida)
11457828Sjlemon{
11557828Sjlemon	bus_addr_t completed;
11657828Sjlemon
11757828Sjlemon	completed = ida_inl(ida, R_42XX_REPLY);
11857828Sjlemon	if (completed == -1)
11957828Sjlemon		return (0);			/* fifo is empty */
12057828Sjlemon	ida_outl(ida, R_42XX_REPLY, 0);		/* confirm read */
12157828Sjlemon	return (completed);
12257828Sjlemon}
12357828Sjlemon
12457828Sjlemonstatic int
12557828Sjlemonida_v4_int_pending(struct ida_softc *ida)
12657828Sjlemon{
12757828Sjlemon	return (ida_inl(ida, R_42XX_STATUS) & STATUS_42XX_INT_PENDING);
12857828Sjlemon}
12957828Sjlemon
13057828Sjlemonstatic void
13157828Sjlemonida_v4_int_enable(struct ida_softc *ida, int enable)
13257828Sjlemon{
13373113Sjlemon	if (enable)
13473113Sjlemon		ida->flags |= IDA_INTERRUPTS;
13573113Sjlemon	else
13673113Sjlemon		ida->flags &= ~IDA_INTERRUPTS;
13757828Sjlemon	ida_outl(ida, R_42XX_INT_MASK,
13857828Sjlemon	    enable ? INT_ENABLE_42XX : INT_DISABLE_42XX);
13957828Sjlemon}
14057828Sjlemon
14157828Sjlemonstatic struct ida_access ida_v3_access = {
14257828Sjlemon	ida_v3_fifo_full,
14357828Sjlemon	ida_v3_submit,
14457828Sjlemon	ida_v3_done,
14557828Sjlemon	ida_v3_int_pending,
14657828Sjlemon	ida_v3_int_enable,
14748156Sjlemon};
14848156Sjlemon
14957828Sjlemonstatic struct ida_access ida_v4_access = {
15057828Sjlemon	ida_v4_fifo_full,
15157828Sjlemon	ida_v4_submit,
15257828Sjlemon	ida_v4_done,
15357828Sjlemon	ida_v4_int_pending,
15457828Sjlemon	ida_v4_int_enable,
15557828Sjlemon};
15657828Sjlemon
15757828Sjlemonstatic struct ida_board board_id[] = {
15870845Sjlemon	{ 0x40300E11, "Compaq SMART-2/P array controller",
15970845Sjlemon	    &ida_v3_access, 0 },
16070845Sjlemon	{ 0x40310E11, "Compaq SMART-2SL array controller",
16170845Sjlemon	    &ida_v3_access, 0 },
16270845Sjlemon	{ 0x40320E11, "Compaq Smart Array 3200 controller",
16370845Sjlemon	    &ida_v3_access, 0 },
16470845Sjlemon	{ 0x40330E11, "Compaq Smart Array 3100ES controller",
16570845Sjlemon	    &ida_v3_access, 0 },
16670845Sjlemon	{ 0x40340E11, "Compaq Smart Array 221 controller",
16770845Sjlemon	    &ida_v3_access, 0 },
16857828Sjlemon
16970845Sjlemon	{ 0x40400E11, "Compaq Integrated Array controller",
17070845Sjlemon	    &ida_v4_access, IDA_FIRMWARE },
17170845Sjlemon	{ 0x40480E11, "Compaq RAID LC2 controller",
17270845Sjlemon	    &ida_v4_access, IDA_FIRMWARE },
17370845Sjlemon	{ 0x40500E11, "Compaq Smart Array 4200 controller",
17470845Sjlemon	    &ida_v4_access, 0 },
17570845Sjlemon	{ 0x40510E11, "Compaq Smart Array 4250ES controller",
17670845Sjlemon	    &ida_v4_access, 0 },
17770845Sjlemon	{ 0x40580E11, "Compaq Smart Array 431 controller",
17870845Sjlemon	    &ida_v4_access, 0 },
17957828Sjlemon
18070845Sjlemon	{ 0, "", 0, 0 },
18157828Sjlemon};
18257828Sjlemon
18348156Sjlemonstatic int ida_pci_probe(device_t dev);
18448156Sjlemonstatic int ida_pci_attach(device_t dev);
18548156Sjlemon
18648156Sjlemonstatic device_method_t ida_pci_methods[] = {
18748156Sjlemon	DEVMETHOD(device_probe,		ida_pci_probe),
18848156Sjlemon	DEVMETHOD(device_attach,	ida_pci_attach),
18957828Sjlemon	DEVMETHOD(device_detach,	ida_detach),
19048156Sjlemon
191227843Smarius	DEVMETHOD_END
19248156Sjlemon};
19348156Sjlemon
19448156Sjlemonstatic driver_t ida_pci_driver = {
19548156Sjlemon	"ida",
19648156Sjlemon	ida_pci_methods,
19748156Sjlemon	sizeof(struct ida_softc)
19848156Sjlemon};
19948156Sjlemon
20048156Sjlemonstatic devclass_t ida_devclass;
20148156Sjlemon
20257828Sjlemonstatic struct ida_board *
20367101Sjlemonida_pci_match(device_t dev)
20457828Sjlemon{
20557828Sjlemon	int i;
20667101Sjlemon	u_int32_t id, sub_id;
20757828Sjlemon
20867101Sjlemon	id = pci_get_devid(dev);
20967101Sjlemon	sub_id = pci_get_subdevice(dev) << 16 | pci_get_subvendor(dev);
21067101Sjlemon
21167101Sjlemon	if (id == IDA_DEVICEID_SMART ||
21267101Sjlemon	    id == IDA_DEVICEID_DEC_SMART ||
21367101Sjlemon	    id == IDA_DEVICEID_NCR_53C1510) {
21467101Sjlemon		for (i = 0; board_id[i].board; i++)
21567101Sjlemon			if (board_id[i].board == sub_id)
21667101Sjlemon				return (&board_id[i]);
21767101Sjlemon	}
21857828Sjlemon	return (NULL);
21957828Sjlemon}
22057828Sjlemon
22148156Sjlemonstatic int
22248156Sjlemonida_pci_probe(device_t dev)
22348156Sjlemon{
22467101Sjlemon	struct ida_board *board = ida_pci_match(dev);
22548156Sjlemon
22659999Sjlemon	if (board != NULL) {
22759999Sjlemon		device_set_desc(dev, board->desc);
228143160Simp		return (BUS_PROBE_DEFAULT);
22948156Sjlemon	}
23048156Sjlemon	return (ENXIO);
23148156Sjlemon}
23248156Sjlemon
23348156Sjlemonstatic int
23448156Sjlemonida_pci_attach(device_t dev)
23548156Sjlemon{
23667101Sjlemon	struct ida_board *board = ida_pci_match(dev);
23769479Sjlemon	u_int32_t id = pci_get_devid(dev);
23848156Sjlemon	struct ida_softc *ida;
23948156Sjlemon	int error, rid;
24048156Sjlemon
24148156Sjlemon	ida = (struct ida_softc *)device_get_softc(dev);
24248156Sjlemon	ida->dev = dev;
24357828Sjlemon	ida->cmd = *board->accessor;
24470845Sjlemon	ida->flags = board->flags;
245239740Sjhb	mtx_init(&ida->lock, "ida", NULL, MTX_DEF);
246239740Sjhb	callout_init_mtx(&ida->ch, &ida->lock, 0);
24757828Sjlemon
24848156Sjlemon	ida->regs_res_type = SYS_RES_MEMORY;
24948156Sjlemon	ida->regs_res_id = IDA_PCI_MEMADDR;
25069479Sjlemon	if (id == IDA_DEVICEID_DEC_SMART)
251119690Sjhb		ida->regs_res_id = PCIR_BAR(0);
25263934Sjlemon
253127135Snjl	ida->regs = bus_alloc_resource_any(dev, ida->regs_res_type,
254127135Snjl	    &ida->regs_res_id, RF_ACTIVE);
25548156Sjlemon	if (ida->regs == NULL) {
25663934Sjlemon		device_printf(dev, "can't allocate memory resources\n");
25748156Sjlemon		return (ENOMEM);
25848156Sjlemon	}
25948156Sjlemon
260138851Smdodd	error = bus_dma_tag_create(
261232854Sscottl		/* parent	*/ bus_get_dma_tag(dev),
262138851Smdodd		/* alignment	*/ 1,
263138851Smdodd		/* boundary	*/ 0,
264138851Smdodd		/* lowaddr	*/ BUS_SPACE_MAXADDR_32BIT,
265138851Smdodd		/* highaddr	*/ BUS_SPACE_MAXADDR,
266138851Smdodd		/* filter	*/ NULL,
267138851Smdodd		/* filterarg	*/ NULL,
268138851Smdodd		/* maxsize	*/ MAXBSIZE,
269138851Smdodd		/* nsegments	*/ IDA_NSEG,
270138851Smdodd		/* maxsegsize	*/ BUS_SPACE_MAXSIZE_32BIT,
271138851Smdodd		/* flags	*/ BUS_DMA_ALLOCNOW,
272138851Smdodd		/* lockfunc	*/ NULL,
273138851Smdodd		/* lockarg	*/ NULL,
274138851Smdodd		&ida->parent_dmat);
27548156Sjlemon	if (error != 0) {
27648156Sjlemon		device_printf(dev, "can't allocate DMA tag\n");
27748156Sjlemon		ida_free(ida);
27848156Sjlemon		return (ENOMEM);
27948156Sjlemon	}
28048156Sjlemon
28148156Sjlemon	rid = 0;
282144991Smdodd	ida->irq_res_type = SYS_RES_IRQ;
283127135Snjl	ida->irq = bus_alloc_resource_any(dev, ida->irq_res_type, &rid,
284127135Snjl	    RF_ACTIVE | RF_SHAREABLE);
285144991Smdodd	if (ida->irq == NULL) {
286144991Smdodd	        ida_free(ida);
287144991Smdodd	        return (ENOMEM);
288144991Smdodd	}
289239740Sjhb	error = bus_setup_intr(dev, ida->irq, INTR_TYPE_BIO | INTR_ENTROPY | INTR_MPSAFE,
290166901Spiso	    NULL, ida_intr, ida, &ida->ih);
29148156Sjlemon	if (error) {
29248156Sjlemon		device_printf(dev, "can't setup interrupt\n");
29348156Sjlemon		ida_free(ida);
29448156Sjlemon		return (ENOMEM);
29548156Sjlemon	}
29648156Sjlemon
29748156Sjlemon	error = ida_init(ida);
29848156Sjlemon	if (error) {
299144991Smdodd	        ida_free(ida);
300144991Smdodd	        return (error);
301144991Smdodd	}
30248156Sjlemon
30348156Sjlemon	return (0);
30448156Sjlemon}
30548156Sjlemon
30648156SjlemonDRIVER_MODULE(ida, pci, ida_pci_driver, ida_devclass, 0, 0);
307