ida_eisa.c revision 124471
1117395Skan/*
2169699Skan * Copyright (c) 2000 Jonathan Lemon
3169699Skan * Copyright (c) 1999 by Matthew N. Dodd <winter@jurai.net>
4117395Skan * All Rights Reserved.
5117395Skan *
6117395Skan * Redistribution and use in source and binary forms, with or without
7117395Skan * modification, are permitted provided that the following conditions
8117395Skan * are met:
9117395Skan * 1. Redistributions of source code must retain the above copyright
10117395Skan *    notice, this list of conditions, and the following disclaimer,
11117395Skan *    without modification, immediately at the beginning of the file.
12117395Skan * 2. The name of the author may not be used to endorse or promote products
13117395Skan *    derived from this software without specific prior written permission.
14117395Skan *
15117395Skan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16117395Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17117395Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18117395Skan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
19117395Skan * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20169699Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21169699Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22117395Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23132811Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24189824Sdas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25132811Skan * SUCH DAMAGE.
26117395Skan */
27117395Skan
28132718Skan#include <sys/cdefs.h>
29132718Skan__FBSDID("$FreeBSD: head/sys/dev/ida/ida_eisa.c 124471 2004-01-13 11:28:21Z mdodd $");
30117395Skan
31117395Skan#include <sys/param.h>
32117395Skan#include <sys/systm.h>
33117395Skan#include <sys/kernel.h>
34117395Skan#include <sys/bus.h>
35117395Skan
36117395Skan#include <sys/bio.h>
37117395Skan#include <sys/conf.h>
38117395Skan
39132718Skan#include <machine/bus_pio.h>
40132718Skan#include <machine/bus.h>
41132718Skan#include <machine/resource.h>
42132718Skan#include <sys/rman.h>
43132718Skan
44169699Skan#include <geom/geom_disk.h>
45117395Skan
46132718Skan#include <dev/ida/idavar.h>
47132718Skan#include <dev/ida/idareg.h>
48132718Skan
49132718Skan#include <dev/eisa/eisaconf.h>
50132718Skan
51132718Skan#define	IDA_EISA_IOPORT_START	0x0c88
52132718Skan#define	IDA_EISA_IOPORT_LEN	0x0017
53132718Skan
54169699Skan#define	IDA_EISA_IRQ_REG	0x0cc0
55169699Skan#define	IDA_EISA_IRQ_MASK	0xf0
56169699Skan#define	IDA_EISA_IRQ_15		0x80
57132718Skan#define	IDA_EISA_IRQ_14		0x40
58117395Skan#define	IDA_EISA_IRQ_11		0x10
59117395Skan#define	IDA_EISA_IRQ_10		0x20
60117395Skan
61117395Skanstatic int
62132718Skanida_v1_fifo_full(struct ida_softc *ida)
63117395Skan{
64117395Skan	u_int8_t status;
65117395Skan
66117395Skan	status = ida_inb(ida, R_EISA_SYSTEM_DOORBELL);
67117395Skan	return ((status & EISA_CHANNEL_CLEAR) == 0);
68117395Skan}
69117395Skan
70117395Skanstatic void
71117395Skanida_v1_submit(struct ida_softc *ida, struct ida_qcb *qcb)
72117395Skan{
73117395Skan	u_int16_t size;
74132718Skan
75132718Skan	/*
76132718Skan	 * On these cards, this location is actually for control flags.
77169699Skan	 * Set them to zero and pass in structure size via an I/O port.
78169699Skan	 */
79169699Skan	size = qcb->hwqcb->hdr.size << 2;
80117395Skan	qcb->hwqcb->hdr.size = 0;
81117395Skan
82117395Skan	ida_outb(ida, R_EISA_SYSTEM_DOORBELL, EISA_CHANNEL_CLEAR);
83132718Skan	ida_outl(ida, R_EISA_LIST_ADDR, qcb->hwqcb_busaddr);
84132718Skan	ida_outw(ida, R_EISA_LIST_LEN, size);
85117395Skan	ida_outb(ida, R_EISA_LOCAL_DOORBELL, EISA_CHANNEL_BUSY);
86169699Skan}
87169699Skan
88169699Skanstatic bus_addr_t
89132718Skanida_v1_done(struct ida_softc *ida)
90132718Skan{
91117395Skan	struct ida_hardware_qcb *hwqcb;
92132718Skan	bus_addr_t completed;
93132718Skan	u_int8_t status;
94117395Skan
95132718Skan	if ((ida_inb(ida, R_EISA_SYSTEM_DOORBELL) & EISA_CHANNEL_BUSY) == 0)
96132718Skan		return (0);
97117395Skan
98132718Skan	ida_outb(ida, R_EISA_SYSTEM_DOORBELL, EISA_CHANNEL_BUSY);
99132718Skan	completed = ida_inl(ida, R_EISA_COMPLETE_ADDR);
100117395Skan	status = ida_inb(ida, R_EISA_LIST_STATUS);
101132718Skan	ida_outb(ida, R_EISA_LOCAL_DOORBELL, EISA_CHANNEL_CLEAR);
102132718Skan
103117395Skan	if (completed != 0) {
104169699Skan        	hwqcb = (struct ida_hardware_qcb *)
105169699Skan		    ((bus_addr_t)ida->hwqcbs +
106169699Skan		    ((completed & ~3) - ida->hwqcb_busaddr));
107132718Skan		hwqcb->req.error = status;
108132718Skan	}
109117395Skan
110132718Skan	return (completed);
111132718Skan}
112117395Skan
113132718Skanstatic int
114132718Skanida_v1_int_pending(struct ida_softc *ida)
115132718Skan{
116132718Skan	return (ida_inb(ida, R_EISA_SYSTEM_DOORBELL) & EISA_CHANNEL_BUSY);
117132718Skan}
118132718Skan
119132718Skanstatic void
120132718Skanida_v1_int_enable(struct ida_softc *ida, int enable)
121132718Skan{
122132718Skan	if (enable) {
123132718Skan		ida_outb(ida, R_EISA_SYSTEM_DOORBELL, ~EISA_CHANNEL_CLEAR);
124132718Skan		ida_outb(ida, R_EISA_LOCAL_DOORBELL, EISA_CHANNEL_BUSY);
125132718Skan		ida_outb(ida, R_EISA_INT_MASK, INT_ENABLE);
126117395Skan		ida_outb(ida, R_EISA_SYSTEM_MASK, INT_ENABLE);
127132718Skan		ida->flags |= IDA_INTERRUPTS;
128132718Skan	} else {
129117395Skan		ida_outb(ida, R_EISA_SYSTEM_MASK, INT_DISABLE);
130117395Skan		ida->flags &= ~IDA_INTERRUPTS;
131132718Skan	}
132132718Skan}
133132718Skan
134117395Skanstatic int
135117395Skanida_v2_fifo_full(struct ida_softc *ida)
136117395Skan{
137117395Skan	return (ida_inl(ida, R_CMD_FIFO) == 0);
138117395Skan}
139117395Skan
140132718Skanstatic void
141132718Skanida_v2_submit(struct ida_softc *ida, struct ida_qcb *qcb)
142132718Skan{
143132718Skan	ida_outl(ida, R_CMD_FIFO, qcb->hwqcb_busaddr);
144132718Skan}
145132718Skan
146117395Skanstatic bus_addr_t
147132718Skanida_v2_done(struct ida_softc *ida)
148117395Skan{
149117395Skan	return (ida_inl(ida, R_DONE_FIFO));
150132718Skan}
151132718Skan
152132718Skanstatic int
153132718Skanida_v2_int_pending(struct ida_softc *ida)
154169699Skan{
155117395Skan	return (ida_inl(ida, R_INT_PENDING));
156117395Skan}
157132718Skan
158169699Skanstatic void
159117395Skanida_v2_int_enable(struct ida_softc *ida, int enable)
160117395Skan{
161132718Skan	if (enable)
162132718Skan		ida->flags |= IDA_INTERRUPTS;
163169699Skan	else
164132718Skan		ida->flags &= ~IDA_INTERRUPTS;
165132718Skan	ida_outl(ida, R_INT_MASK, enable ? INT_ENABLE : INT_DISABLE);
166169699Skan}
167132718Skan
168132718Skanstatic struct ida_access ida_v1_access = {
169132718Skan	ida_v1_fifo_full,
170132718Skan	ida_v1_submit,
171169699Skan	ida_v1_done,
172169699Skan	ida_v1_int_pending,
173132718Skan	ida_v1_int_enable,
174132718Skan};
175117395Skan
176117395Skanstatic struct ida_access ida_v2_access = {
177117395Skan	ida_v2_fifo_full,
178132718Skan	ida_v2_submit,
179132718Skan	ida_v2_done,
180117395Skan	ida_v2_int_pending,
181169699Skan	ida_v2_int_enable,
182117395Skan};
183117395Skan
184117395Skanstatic struct ida_board board_id[] = {
185117395Skan	{ 0x0e114001, "Compaq IDA controller",
186169699Skan	    &ida_v1_access, 0 },
187117395Skan	{ 0x0e114002, "Compaq IDA-2 controller",
188117395Skan	    &ida_v1_access, 0 },
189117395Skan	{ 0x0e114010, "Compaq IAES controller",
190132718Skan	    &ida_v1_access, 0 },
191117395Skan	{ 0x0e114020, "Compaq SMART array controller",
192117395Skan	    &ida_v1_access, 0 },
193117395Skan	{ 0x0e114030, "Compaq SMART-2/E array controller",
194117395Skan	    &ida_v2_access, 0 },
195132718Skan
196117395Skan	{ 0, "", 0, 0 }
197117395Skan};
198117395Skan
199117395Skanstatic struct 	ida_board *ida_eisa_match(eisa_id_t);
200117395Skanstatic int	ida_eisa_probe(device_t);
201117395Skanstatic int	ida_eisa_attach(device_t);
202117395Skan
203132718Skanstatic device_method_t ida_eisa_methods[] = {
204146908Skan	DEVMETHOD(device_probe,		ida_eisa_probe),
205117395Skan	DEVMETHOD(device_attach,	ida_eisa_attach),
206132718Skan	DEVMETHOD(device_detach,	ida_detach),
207146908Skan
208117395Skan	{ 0, 0 }
209132718Skan};
210132718Skan
211132718Skanstatic driver_t ida_eisa_driver = {
212132718Skan	"ida",
213132718Skan	ida_eisa_methods,
214132718Skan	sizeof(struct ida_softc)
215132718Skan};
216132718Skan
217132718Skanstatic devclass_t ida_devclass;
218132718Skan
219132718Skanstatic struct ida_board *
220117395Skanida_eisa_match(eisa_id_t id)
221132718Skan{
222169699Skan	int i;
223132718Skan
224117395Skan	for (i = 0; board_id[i].board; i++)
225132718Skan		if (board_id[i].board == id)
226132718Skan			return (&board_id[i]);
227117395Skan	return (NULL);
228132718Skan}
229132718Skan
230132718Skanstatic int
231117395Skanida_eisa_probe(device_t dev)
232132718Skan{
233132718Skan	struct ida_board	*board;
234169699Skan	u_int32_t		io_base;
235117395Skan	u_int			irq = 0;
236169699Skan
237117395Skan	board = ida_eisa_match(eisa_get_id(dev));
238132718Skan	if (board == NULL)
239117395Skan		return (ENXIO);
240146908Skan	device_set_desc(dev, board->desc);
241146908Skan
242169699Skan	io_base = (eisa_get_slot(dev) * EISA_SLOT_SIZE);
243169699Skan
244146908Skan	switch (IDA_EISA_IRQ_MASK & (inb(IDA_EISA_IRQ_REG + io_base))) {
245169699Skan	case IDA_EISA_IRQ_15:
246169699Skan		irq = 15;
247169699Skan		break;
248169699Skan	case IDA_EISA_IRQ_14:
249169699Skan		irq = 14;
250169699Skan		break;
251169699Skan	case IDA_EISA_IRQ_11:
252169699Skan		irq = 11;
253169699Skan		break;
254146908Skan	case IDA_EISA_IRQ_10:
255169699Skan		irq = 10;
256169699Skan		break;
257169699Skan	default:
258146908Skan		device_printf(dev, "slot %d, illegal irq setting.\n",
259117395Skan		    eisa_get_slot(dev));
260169699Skan		return (ENXIO);
261132718Skan	}
262132718Skan
263117395Skan	eisa_add_iospace(dev, (io_base + IDA_EISA_IOPORT_START),
264132718Skan			 IDA_EISA_IOPORT_LEN, RESVADDR_NONE);
265132718Skan
266132718Skan        eisa_add_intr(dev, irq, EISA_TRIGGER_LEVEL);		/* XXX ??? */
267132718Skan
268132718Skan	return (0);
269132718Skan}
270132718Skan
271132718Skanstatic int
272132718Skanida_eisa_attach(device_t dev)
273132718Skan{
274117395Skan	struct ida_softc	*ida;
275169699Skan	struct ida_board	*board;
276169699Skan	int			error;
277169699Skan	int			rid;
278169699Skan
279132718Skan	ida = device_get_softc(dev);
280117395Skan	ida->dev = dev;
281132718Skan
282169699Skan	board = ida_eisa_match(eisa_get_id(dev));
283169699Skan	ida->cmd = *board->accessor;
284169699Skan	ida->flags = board->flags;
285169699Skan
286169699Skan	ida->regs_res_type = SYS_RES_IOPORT;
287169699Skan	ida->regs_res_id = 0;
288169699Skan	ida->regs = bus_alloc_resource(dev, ida->regs_res_type,
289132718Skan	    &ida->regs_res_id, 0, ~0, 1, RF_ACTIVE);
290117395Skan	if (ida->regs == NULL) {
291132718Skan		device_printf(dev, "can't allocate register resources\n");
292132718Skan		return (ENOMEM);
293117395Skan	}
294117395Skan
295132718Skan	error = bus_dma_tag_create(
296132718Skan		/* parent	*/	NULL,
297117395Skan		/* alignment	*/	0,
298117395Skan		/* boundary	*/	0,
299117395Skan		/* lowaddr	*/	BUS_SPACE_MAXADDR_32BIT,
300117395Skan		/* highaddr	*/	BUS_SPACE_MAXADDR,
301117395Skan		/* filter	*/	NULL,
302117395Skan		/* filterarg	*/	NULL,
303117395Skan		/* maxsize	*/	MAXBSIZE,
304117395Skan		/* nsegments	*/	IDA_NSEG,
305117395Skan		/* maxsegsize	*/	BUS_SPACE_MAXSIZE_32BIT,
306117395Skan		/* flags	*/	BUS_DMA_ALLOCNOW,
307117395Skan		/* lockfunc	*/	NULL,
308132718Skan		/* lockarg	*/	NULL,
309132718Skan		&ida->parent_dmat);
310132718Skan
311132718Skan	if (error != 0) {
312117395Skan		device_printf(dev, "can't allocate DMA tag\n");
313117395Skan		ida_free(ida);
314117395Skan		return (ENOMEM);
315117395Skan	}
316117395Skan
317117395Skan	rid = 0;
318117395Skan	ida->irq_res_type = SYS_RES_IRQ;
319117395Skan	ida->irq = bus_alloc_resource(dev, ida->irq_res_type, &rid,
320169699Skan	    0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
321169699Skan	if (ida->irq == NULL) {
322169699Skan		ida_free(ida);
323169699Skan		return (ENOMEM);
324132718Skan	}
325132718Skan
326169699Skan	error = bus_setup_intr(dev, ida->irq, INTR_TYPE_BIO | INTR_ENTROPY,
327132718Skan	    ida_intr, ida, &ida->ih);
328132718Skan	if (error) {
329132718Skan		device_printf(dev, "can't setup interrupt\n");
330132718Skan		ida_free(ida);
331132718Skan		return (ENOMEM);
332132718Skan	}
333169699Skan
334132718Skan	error = ida_init(ida);
335132718Skan	if (error) {
336132718Skan		ida_free(ida);
337117395Skan		return (error);
338117395Skan	}
339117395Skan
340117395Skan	ida_attach(ida);
341117395Skan	ida->flags |= IDA_ATTACHED;
342117395Skan
343117395Skan	return (0);
344132718Skan}
345117395Skan
346117395SkanDRIVER_MODULE(ida, eisa, ida_eisa_driver, ida_devclass, 0, 0);
347117395Skan