ida_eisa.c revision 60041
157828Sjlemon/*
257828Sjlemon * Copyright (c) 2000 Jonathan Lemon
357828Sjlemon * Copyright (c) 1999 by Matthew N. Dodd <winter@jurai.net>
457828Sjlemon * All Rights Reserved.
557828Sjlemon *
657828Sjlemon * Redistribution and use in source and binary forms, with or without
757828Sjlemon * modification, are permitted provided that the following conditions
857828Sjlemon * are met:
957828Sjlemon * 1. Redistributions of source code must retain the above copyright
1057828Sjlemon *    notice, this list of conditions, and the following disclaimer,
1157828Sjlemon *    without modification, immediately at the beginning of the file.
1257828Sjlemon * 2. The name of the author may not be used to endorse or promote products
1357828Sjlemon *    derived from this software without specific prior written permission.
1457828Sjlemon *
1557828Sjlemon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1657828Sjlemon * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1757828Sjlemon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1857828Sjlemon * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
1957828Sjlemon * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2057828Sjlemon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2157828Sjlemon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2257828Sjlemon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2357828Sjlemon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2457828Sjlemon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2557828Sjlemon * SUCH DAMAGE.
2657828Sjlemon *
2757828Sjlemon * $FreeBSD: head/sys/dev/ida/ida_eisa.c 60041 2000-05-05 09:59:14Z phk $
2857828Sjlemon */
2957828Sjlemon
3057828Sjlemon#include <sys/param.h>
3157828Sjlemon#include <sys/systm.h>
3257828Sjlemon#include <sys/kernel.h>
3357828Sjlemon#include <sys/bus.h>
3457828Sjlemon
3560041Sphk#include <sys/bio.h>
3657828Sjlemon#include <sys/devicestat.h>
3757828Sjlemon#include <sys/disk.h>
3857828Sjlemon
3957828Sjlemon#include <machine/bus_pio.h>
4057828Sjlemon#include <machine/bus.h>
4157828Sjlemon#include <machine/resource.h>
4257828Sjlemon#include <sys/rman.h>
4357828Sjlemon
4457828Sjlemon#include <dev/ida/idavar.h>
4557828Sjlemon#include <dev/ida/idareg.h>
4657828Sjlemon
4757828Sjlemon#include <dev/eisa/eisaconf.h>
4857828Sjlemon
4957828Sjlemon#define IDA_EISA_IOPORT_START	0x0c88
5057828Sjlemon#define IDA_EISA_IOPORT_LEN	0x0017
5157828Sjlemon
5257828Sjlemon#define IDA_EISA_IRQ_REG	0x0cc0
5357828Sjlemon#define IDA_EISA_IRQ_MASK	0xf0
5457828Sjlemon#define IDA_EISA_IRQ_15		0x80
5557828Sjlemon#define IDA_EISA_IRQ_14		0x40
5657828Sjlemon#define IDA_EISA_IRQ_11		0x10
5757828Sjlemon#define IDA_EISA_IRQ_10		0x20
5857828Sjlemon
5957828Sjlemonstatic int
6057828Sjlemonida_v1_fifo_full(struct ida_softc *ida)
6157828Sjlemon{
6257828Sjlemon	u_int8_t status;
6357828Sjlemon
6457828Sjlemon	status = ida_inb(ida, R_EISA_SYSTEM_DOORBELL);
6557828Sjlemon	return ((status & EISA_CHANNEL_CLEAR) == 0);
6657828Sjlemon}
6757828Sjlemon
6857828Sjlemonstatic void
6957828Sjlemonida_v1_submit(struct ida_softc *ida, struct ida_qcb *qcb)
7057828Sjlemon{
7157828Sjlemon	u_int16_t size;
7257828Sjlemon
7357828Sjlemon	/*
7457828Sjlemon	 * On these cards, this location is actually for control flags.
7557828Sjlemon	 * Set them to zero and pass in structure size via an I/O port.
7657828Sjlemon	 */
7757828Sjlemon	size = qcb->hwqcb->hdr.size << 2;
7857828Sjlemon	qcb->hwqcb->hdr.size = 0;
7957828Sjlemon
8057828Sjlemon	ida_outb(ida, R_EISA_SYSTEM_DOORBELL, EISA_CHANNEL_CLEAR);
8157828Sjlemon	ida_outl(ida, R_EISA_LIST_ADDR, qcb->hwqcb_busaddr);
8257828Sjlemon	ida_outw(ida, R_EISA_LIST_LEN, size);
8359209Smdodd	ida_outb(ida, R_EISA_LOCAL_DOORBELL, EISA_CHANNEL_BUSY);
8457828Sjlemon}
8557828Sjlemon
8657828Sjlemonstatic bus_addr_t
8757828Sjlemonida_v1_done(struct ida_softc *ida)
8857828Sjlemon{
8957828Sjlemon	struct ida_hardware_qcb *hwqcb;
9057828Sjlemon	bus_addr_t completed;
9157828Sjlemon	u_int8_t status;
9257828Sjlemon
9357828Sjlemon	if ((ida_inb(ida, R_EISA_SYSTEM_DOORBELL) & EISA_CHANNEL_BUSY) == 0)
9457828Sjlemon		return (0);
9557828Sjlemon
9657828Sjlemon	ida_outb(ida, R_EISA_SYSTEM_DOORBELL, EISA_CHANNEL_BUSY);
9757828Sjlemon	completed = ida_inl(ida, R_EISA_COMPLETE_ADDR);
9857828Sjlemon	status = ida_inb(ida, R_EISA_LIST_STATUS);
9957828Sjlemon	ida_outb(ida, R_EISA_LOCAL_DOORBELL, EISA_CHANNEL_CLEAR);
10057828Sjlemon
10157828Sjlemon	if (completed != 0) {
10257828Sjlemon        	hwqcb = (struct ida_hardware_qcb *)
10357828Sjlemon		    ((bus_addr_t)ida->hwqcbs +
10457828Sjlemon		    ((completed & ~3) - ida->hwqcb_busaddr));
10557828Sjlemon		hwqcb->req.error = status;
10657828Sjlemon	}
10757828Sjlemon
10857828Sjlemon	return (completed);
10957828Sjlemon}
11057828Sjlemon
11157828Sjlemonstatic int
11257828Sjlemonida_v1_int_pending(struct ida_softc *ida)
11357828Sjlemon{
11457828Sjlemon	return (ida_inb(ida, R_EISA_SYSTEM_DOORBELL) & EISA_CHANNEL_BUSY);
11557828Sjlemon}
11657828Sjlemon
11757828Sjlemonstatic void
11857828Sjlemonida_v1_int_enable(struct ida_softc *ida, int enable)
11957828Sjlemon{
12057828Sjlemon	if (enable) {
12157828Sjlemon		ida_outb(ida, R_EISA_SYSTEM_DOORBELL, ~EISA_CHANNEL_CLEAR);
12257828Sjlemon		ida_outb(ida, R_EISA_LOCAL_DOORBELL, EISA_CHANNEL_BUSY);
12357828Sjlemon		ida_outb(ida, R_EISA_INT_MASK, INT_ENABLE);
12457828Sjlemon		ida_outb(ida, R_EISA_SYSTEM_MASK, INT_ENABLE);
12557828Sjlemon	} else {
12657828Sjlemon		ida_outb(ida, R_EISA_SYSTEM_MASK, INT_DISABLE);
12757828Sjlemon	}
12857828Sjlemon}
12957828Sjlemon
13057828Sjlemonstatic int
13157828Sjlemonida_v2_fifo_full(struct ida_softc *ida)
13257828Sjlemon{
13357828Sjlemon	return (ida_inl(ida, R_CMD_FIFO) == 0);
13457828Sjlemon}
13557828Sjlemon
13657828Sjlemonstatic void
13757828Sjlemonida_v2_submit(struct ida_softc *ida, struct ida_qcb *qcb)
13857828Sjlemon{
13957828Sjlemon	ida_outl(ida, R_CMD_FIFO, qcb->hwqcb_busaddr);
14057828Sjlemon}
14157828Sjlemon
14257828Sjlemonstatic bus_addr_t
14357828Sjlemonida_v2_done(struct ida_softc *ida)
14457828Sjlemon{
14557828Sjlemon	return (ida_inl(ida, R_DONE_FIFO));
14657828Sjlemon}
14757828Sjlemon
14857828Sjlemonstatic int
14957828Sjlemonida_v2_int_pending(struct ida_softc *ida)
15057828Sjlemon{
15157828Sjlemon	return (ida_inl(ida, R_INT_PENDING));
15257828Sjlemon}
15357828Sjlemon
15457828Sjlemonstatic void
15557828Sjlemonida_v2_int_enable(struct ida_softc *ida, int enable)
15657828Sjlemon{
15757828Sjlemon	ida_outl(ida, R_INT_MASK, enable ? INT_ENABLE : INT_DISABLE);
15857828Sjlemon}
15957828Sjlemon
16057828Sjlemonstatic struct ida_access ida_v1_access = {
16157828Sjlemon	ida_v1_fifo_full,
16257828Sjlemon	ida_v1_submit,
16357828Sjlemon	ida_v1_done,
16457828Sjlemon	ida_v1_int_pending,
16557828Sjlemon	ida_v1_int_enable,
16657828Sjlemon};
16757828Sjlemon
16857828Sjlemonstatic struct ida_access ida_v2_access = {
16957828Sjlemon	ida_v2_fifo_full,
17057828Sjlemon	ida_v2_submit,
17157828Sjlemon	ida_v2_done,
17257828Sjlemon	ida_v2_int_pending,
17357828Sjlemon	ida_v2_int_enable,
17457828Sjlemon};
17557828Sjlemon
17657828Sjlemonstatic struct ida_board board_id[] = {
17757828Sjlemon	{ 0x0e114001, "Compaq IDA controller",		    &ida_v1_access },
17857828Sjlemon	{ 0x0e114002, "Compaq IDA-2 controller",	    &ida_v1_access },
17957828Sjlemon	{ 0x0e114010, "Compaq IAES controller",		    &ida_v1_access },
18057828Sjlemon	{ 0x0e114020, "Compaq SMART array controller",	    &ida_v1_access },
18157828Sjlemon	{ 0x0e114030, "Compaq SMART-2/E array controller",  &ida_v2_access },
18257828Sjlemon
18357828Sjlemon	{ 0, "", 0 }
18457828Sjlemon};
18557828Sjlemon
18657828Sjlemonstatic struct 	ida_board *ida_eisa_match(eisa_id_t);
18757828Sjlemonstatic int	ida_eisa_probe(device_t);
18857828Sjlemonstatic int	ida_eisa_attach(device_t);
18957828Sjlemon
19057828Sjlemonstatic device_method_t ida_eisa_methods[] = {
19157828Sjlemon	DEVMETHOD(device_probe,		ida_eisa_probe),
19257828Sjlemon	DEVMETHOD(device_attach,	ida_eisa_attach),
19357828Sjlemon	DEVMETHOD(device_detach,	ida_detach),
19457828Sjlemon
19557828Sjlemon	{ 0, 0 }
19657828Sjlemon};
19757828Sjlemon
19857828Sjlemonstatic driver_t ida_eisa_driver = {
19957828Sjlemon	"ida",
20057828Sjlemon	ida_eisa_methods,
20157828Sjlemon	sizeof(struct ida_softc)
20257828Sjlemon};
20357828Sjlemon
20457828Sjlemonstatic devclass_t ida_devclass;
20557828Sjlemon
20657828Sjlemonstatic struct ida_board *
20757828Sjlemonida_eisa_match(eisa_id_t id)
20857828Sjlemon{
20957828Sjlemon	int i;
21057828Sjlemon
21157828Sjlemon	for (i = 0; board_id[i].board; i++)
21257828Sjlemon		if (board_id[i].board == id)
21357828Sjlemon			return (&board_id[i]);
21457828Sjlemon	return (NULL);
21557828Sjlemon}
21657828Sjlemon
21757828Sjlemonstatic int
21857828Sjlemonida_eisa_probe(device_t dev)
21957828Sjlemon{
22057828Sjlemon	struct ida_board	*board;
22157828Sjlemon	u_int32_t		io_base;
22257828Sjlemon	u_int			irq = 0;
22357828Sjlemon
22457828Sjlemon	board = ida_eisa_match(eisa_get_id(dev));
22557828Sjlemon	if (board == NULL)
22657828Sjlemon		return (ENXIO);
22757828Sjlemon	device_set_desc(dev, board->desc);
22857828Sjlemon
22957828Sjlemon	io_base = (eisa_get_slot(dev) * EISA_SLOT_SIZE);
23057828Sjlemon
23157828Sjlemon	switch (IDA_EISA_IRQ_MASK & (inb(IDA_EISA_IRQ_REG + io_base))) {
23257828Sjlemon	case IDA_EISA_IRQ_15:
23357828Sjlemon		irq = 15;
23457828Sjlemon		break;
23557828Sjlemon	case IDA_EISA_IRQ_14:
23657828Sjlemon		irq = 14;
23757828Sjlemon		break;
23857828Sjlemon	case IDA_EISA_IRQ_11:
23957828Sjlemon		irq = 11;
24057828Sjlemon		break;
24157828Sjlemon	case IDA_EISA_IRQ_10:
24257828Sjlemon		irq = 10;
24357828Sjlemon		break;
24457828Sjlemon	default:
24557828Sjlemon		device_printf(dev, "slot %d, illegal irq setting.\n",
24657828Sjlemon		    eisa_get_slot(dev));
24757828Sjlemon		return (ENXIO);
24857828Sjlemon	}
24957828Sjlemon
25057828Sjlemon	eisa_add_iospace(dev, (io_base + IDA_EISA_IOPORT_START),
25157828Sjlemon			 IDA_EISA_IOPORT_LEN, RESVADDR_NONE);
25257828Sjlemon
25357828Sjlemon        eisa_add_intr(dev, irq, EISA_TRIGGER_LEVEL);		/* XXX ??? */
25457828Sjlemon
25557828Sjlemon	return (0);
25657828Sjlemon}
25757828Sjlemon
25857828Sjlemonstatic int
25957828Sjlemonida_eisa_attach(device_t dev)
26057828Sjlemon{
26157828Sjlemon	struct ida_softc	*ida;
26257828Sjlemon	struct ida_board	*board;
26357828Sjlemon	int			error;
26457828Sjlemon	int			rid;
26557828Sjlemon
26657828Sjlemon	ida = device_get_softc(dev);
26757828Sjlemon	ida->dev = dev;
26857828Sjlemon
26957828Sjlemon	board = ida_eisa_match(eisa_get_id(dev));
27057828Sjlemon	ida->cmd = *board->accessor;
27157828Sjlemon
27257828Sjlemon	ida->regs_res_type = SYS_RES_IOPORT;
27357828Sjlemon	ida->regs_res_id = 0;
27457828Sjlemon	ida->regs = bus_alloc_resource(dev, ida->regs_res_type,
27557828Sjlemon	    &ida->regs_res_id, 0, ~0, 1, RF_ACTIVE);
27657828Sjlemon	if (ida->regs == NULL) {
27757828Sjlemon		device_printf(dev, "can't allocate register resources\n");
27857828Sjlemon		return (ENOMEM);
27957828Sjlemon	}
28057828Sjlemon
28157828Sjlemon	error = bus_dma_tag_create(
28257828Sjlemon		/* parent	*/	NULL,
28357828Sjlemon		/* alignment	*/	0,
28457828Sjlemon		/* boundary	*/	0,
28557828Sjlemon		/* lowaddr	*/	BUS_SPACE_MAXADDR_32BIT,
28657828Sjlemon		/* highaddr	*/	BUS_SPACE_MAXADDR,
28757828Sjlemon		/* filter	*/	NULL,
28857828Sjlemon		/* filterarg	*/	NULL,
28957828Sjlemon		/* maxsize	*/	MAXBSIZE,
29057828Sjlemon		/* nsegments	*/	IDA_NSEG,
29157828Sjlemon		/* maxsegsize	*/	BUS_SPACE_MAXSIZE_32BIT,
29257828Sjlemon		/* flags	*/	BUS_DMA_ALLOCNOW,
29357828Sjlemon		&ida->parent_dmat);
29457828Sjlemon
29557828Sjlemon	if (error != 0) {
29657828Sjlemon		device_printf(dev, "can't allocate DMA tag\n");
29757828Sjlemon		ida_free(ida);
29857828Sjlemon		return (ENOMEM);
29957828Sjlemon	}
30057828Sjlemon
30157828Sjlemon	rid = 0;
30257828Sjlemon	ida->irq_res_type = SYS_RES_IRQ;
30357828Sjlemon	ida->irq = bus_alloc_resource(dev, ida->irq_res_type, &rid,
30457828Sjlemon	    0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
30557828Sjlemon	if (ida->irq == NULL) {
30657828Sjlemon		ida_free(ida);
30757828Sjlemon		return (ENOMEM);
30857828Sjlemon	}
30957828Sjlemon
31057828Sjlemon	error = bus_setup_intr(dev, ida->irq, INTR_TYPE_BIO,
31157828Sjlemon	    ida_intr, ida, &ida->ih);
31257828Sjlemon	if (error) {
31357828Sjlemon		device_printf(dev, "can't setup interrupt\n");
31457828Sjlemon		ida_free(ida);
31557828Sjlemon		return (ENOMEM);
31657828Sjlemon	}
31757828Sjlemon
31857828Sjlemon	error = ida_init(ida);
31957828Sjlemon	if (error) {
32057828Sjlemon		ida_free(ida);
32157828Sjlemon		return (error);
32257828Sjlemon	}
32357828Sjlemon
32457828Sjlemon	ida_attach(ida);
32557828Sjlemon	ida->flags = IDA_ATTACHED;
32657828Sjlemon
32757828Sjlemon	return (0);
32857828Sjlemon}
32957828Sjlemon
33057828SjlemonDRIVER_MODULE(ida, eisa, ida_eisa_driver, ida_devclass, 0, 0);
331