1/*-
2 * Copyright (c) 1999 Matthew N. Dodd <winter@jurai.net>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * Based on aha_isa.c
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD$");
31
32#include <sys/types.h>
33#include <sys/param.h>
34#include <sys/systm.h>
35#include <sys/kernel.h>
36#include <sys/lock.h>
37#include <sys/mutex.h>
38
39#include <sys/module.h>
40#include <sys/bus.h>
41#include <machine/bus.h>
42#include <machine/resource.h>
43#include <sys/rman.h>
44
45#include <isa/isavar.h>
46
47#include <dev/mca/mca_busreg.h>
48#include <dev/mca/mca_busvar.h>
49
50#include <dev/aha/ahareg.h>
51
52static struct mca_ident aha_mca_devs[] = {
53	{ 0x0f1f, "Adaptec AHA-1640 SCSI Adapter" },
54	{ 0, NULL },
55};
56
57#define AHA_MCA_IOPORT_POS		MCA_ADP_POS(MCA_POS1)
58# define AHA_MCA_IOPORT_MASK1		0x07
59# define AHA_MCA_IOPORT_MASK2		0xc0
60# define AHA_MCA_IOPORT_SIZE		0x03
61# define AHA_MCA_IOPORT(pos)		(0x30 + \
62					(((uint32_t)pos & \
63						AHA_MCA_IOPORT_MASK1) << 8) + \
64					(((uint32_t)pos & \
65						AHA_MCA_IOPORT_MASK2) >> 4))
66
67#define AHA_MCA_DRQ_POS			MCA_ADP_POS(MCA_POS3)
68# define AHA_MCA_DRQ_MASK		0x0f
69# define AHA_MCA_DRQ(pos)		(pos & AHA_MCA_DRQ_MASK)
70
71#define AHA_MCA_IRQ_POS			MCA_ADP_POS(MCA_POS2)
72# define AHA_MCA_IRQ_MASK		0x07
73# define AHA_MCA_IRQ(pos)		((pos & AHA_MCA_IRQ_MASK) + 8)
74
75/*
76 * Not needed as the board knows its config
77 * internally and the ID will be fetched
78 * via AOP_INQUIRE_SETUP_INFO command.
79 */
80#define AHA_MCA_SCSIID_POS		MCA_ADP_POS(MCA_POS2)
81#define AHA_MCA_SCSIID_MASK		0xe0
82#define AHA_MCA_SCSIID(pos)		((pos & AHA_MCA_SCSIID_MASK) >> 5)
83
84static int
85aha_mca_probe (device_t dev)
86{
87	const char *	desc;
88	mca_id_t	id = mca_get_id(dev);
89	uint32_t	iobase = 0;
90	uint32_t	iosize = 0;
91	uint8_t		drq = 0;
92	uint8_t		irq = 0;
93	uint8_t		pos;
94
95	desc = mca_match_id(id, aha_mca_devs);
96	if (!desc)
97		return (ENXIO);
98	device_set_desc(dev, desc);
99
100	pos = mca_pos_read(dev, AHA_MCA_IOPORT_POS);
101	iobase = AHA_MCA_IOPORT(pos);
102	iosize = AHA_MCA_IOPORT_SIZE;
103
104	pos = mca_pos_read(dev, AHA_MCA_DRQ_POS);
105	drq = AHA_MCA_DRQ(pos);
106
107	pos = mca_pos_read(dev, AHA_MCA_IRQ_POS);
108	irq = AHA_MCA_IRQ(pos);
109
110	mca_add_iospace(dev, iobase, iosize);
111	mca_add_drq(dev, drq);
112	mca_add_irq(dev, irq);
113
114	return (0);
115}
116
117static int
118aha_mca_attach (device_t dev)
119{
120	struct aha_softc *	sc = device_get_softc(dev);
121	int			error = ENOMEM;
122
123	sc->portrid = 0;
124	sc->port = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &sc->portrid,
125	    RF_ACTIVE);
126	if (sc->port == NULL) {
127		device_printf(dev, "No I/O space?!\n");
128		goto bad;
129	}
130
131	sc->irqrid = 0;
132	sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqrid,
133	    RF_ACTIVE);
134	if (sc->irq == NULL) {
135		device_printf(dev, "No IRQ?!\n");
136		goto bad;
137	}
138
139	sc->drqrid = 0;
140	sc->drq = bus_alloc_resource_any(dev, SYS_RES_DRQ, &sc->drqrid,
141	    RF_ACTIVE);
142	if (sc->drq == NULL) {
143		device_printf(dev, "No DRQ?!\n");
144		goto bad;
145	}
146
147	aha_alloc(sc);
148	error = aha_probe(sc);
149	if (error) {
150		device_printf(dev, "aha_probe() failed!\n");
151		goto bad;
152	}
153
154	error = aha_fetch_adapter_info(sc);
155	if (error) {
156		device_printf(dev, "aha_fetch_adapter_info() failed!\n");
157		goto bad;
158	}
159
160	isa_dmacascade(rman_get_start(sc->drq));
161
162	error = bus_dma_tag_create(
163				/* parent	*/ bus_get_dma_tag(dev),
164				/* alignemnt	*/ 1,
165				/* boundary	*/ 0,
166				/* lowaddr	*/ BUS_SPACE_MAXADDR_24BIT,
167				/* highaddr	*/ BUS_SPACE_MAXADDR,
168				/* filter	*/ NULL,
169				/* filterarg	*/ NULL,
170				/* maxsize	*/ BUS_SPACE_MAXSIZE_24BIT,
171				/* nsegments	*/ ~0,
172				/* maxsegsz	*/ BUS_SPACE_MAXSIZE_24BIT,
173				/* flags	*/ 0,
174				/* lockfunc	*/ NULL,
175				/* lockarg	*/ NULL,
176				&sc->parent_dmat);
177	if (error) {
178		device_printf(dev, "bus_dma_tag_create() failed!\n");
179		goto bad;
180	}
181
182	error = aha_init(sc);
183	if (error) {
184		device_printf(dev, "aha_init() failed\n");
185		goto bad;
186	}
187
188	error = aha_attach(sc);
189	if (error) {
190		device_printf(dev, "aha_attach() failed\n");
191		goto bad;
192	}
193
194	error = bus_setup_intr(dev, sc->irq, INTR_TYPE_CAM | INTR_ENTROPY |
195	    INTR_MPSAFE, NULL, aha_intr, sc, &sc->ih);
196	if (error) {
197		device_printf(dev, "Unable to register interrupt handler\n");
198		aha_detach(sc);
199		goto bad;
200	}
201
202	return (0);
203
204bad:
205	aha_free(sc);
206	bus_free_resource(dev, SYS_RES_IOPORT, sc->port);
207	bus_free_resource(dev, SYS_RES_IRQ, sc->irq);
208	bus_free_resource(dev, SYS_RES_DRQ, sc->drq);
209	return (error);
210}
211
212static device_method_t aha_mca_methods[] = {
213	DEVMETHOD(device_probe,         aha_mca_probe),
214	DEVMETHOD(device_attach,        aha_mca_attach),
215
216	{ 0, 0 }
217};
218
219static driver_t aha_mca_driver = {
220	"aha",
221	aha_mca_methods,
222	1,
223/*
224	sizeof(struct aha_softc *),
225 */
226};
227
228static devclass_t aha_devclass;
229
230DRIVER_MODULE(aha, mca, aha_mca_driver, aha_devclass, 0, 0);
231MODULE_DEPEND(aha, mca, 1, 1, 1);
232