ida_eisa.c revision 112946
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 112946 2003-04-01 15:06:26Z 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>
36111337Sphk#include <sys/conf.h>
3757828Sjlemon
3857828Sjlemon#include <machine/bus_pio.h>
3957828Sjlemon#include <machine/bus.h>
4057828Sjlemon#include <machine/resource.h>
4157828Sjlemon#include <sys/rman.h>
4257828Sjlemon
43112946Sphk#include <geom/geom_disk.h>
44112946Sphk
4557828Sjlemon#include <dev/ida/idavar.h>
4657828Sjlemon#include <dev/ida/idareg.h>
4757828Sjlemon
4857828Sjlemon#include <dev/eisa/eisaconf.h>
4957828Sjlemon
5057828Sjlemon#define IDA_EISA_IOPORT_START	0x0c88
5157828Sjlemon#define IDA_EISA_IOPORT_LEN	0x0017
5257828Sjlemon
5357828Sjlemon#define IDA_EISA_IRQ_REG	0x0cc0
5457828Sjlemon#define IDA_EISA_IRQ_MASK	0xf0
5557828Sjlemon#define IDA_EISA_IRQ_15		0x80
5657828Sjlemon#define IDA_EISA_IRQ_14		0x40
5757828Sjlemon#define IDA_EISA_IRQ_11		0x10
5857828Sjlemon#define IDA_EISA_IRQ_10		0x20
5957828Sjlemon
6057828Sjlemonstatic int
6157828Sjlemonida_v1_fifo_full(struct ida_softc *ida)
6257828Sjlemon{
6357828Sjlemon	u_int8_t status;
6457828Sjlemon
6557828Sjlemon	status = ida_inb(ida, R_EISA_SYSTEM_DOORBELL);
6657828Sjlemon	return ((status & EISA_CHANNEL_CLEAR) == 0);
6757828Sjlemon}
6857828Sjlemon
6957828Sjlemonstatic void
7057828Sjlemonida_v1_submit(struct ida_softc *ida, struct ida_qcb *qcb)
7157828Sjlemon{
7257828Sjlemon	u_int16_t size;
7357828Sjlemon
7457828Sjlemon	/*
7557828Sjlemon	 * On these cards, this location is actually for control flags.
7657828Sjlemon	 * Set them to zero and pass in structure size via an I/O port.
7757828Sjlemon	 */
7857828Sjlemon	size = qcb->hwqcb->hdr.size << 2;
7957828Sjlemon	qcb->hwqcb->hdr.size = 0;
8057828Sjlemon
8157828Sjlemon	ida_outb(ida, R_EISA_SYSTEM_DOORBELL, EISA_CHANNEL_CLEAR);
8257828Sjlemon	ida_outl(ida, R_EISA_LIST_ADDR, qcb->hwqcb_busaddr);
8357828Sjlemon	ida_outw(ida, R_EISA_LIST_LEN, size);
8459209Smdodd	ida_outb(ida, R_EISA_LOCAL_DOORBELL, EISA_CHANNEL_BUSY);
8557828Sjlemon}
8657828Sjlemon
8757828Sjlemonstatic bus_addr_t
8857828Sjlemonida_v1_done(struct ida_softc *ida)
8957828Sjlemon{
9057828Sjlemon	struct ida_hardware_qcb *hwqcb;
9157828Sjlemon	bus_addr_t completed;
9257828Sjlemon	u_int8_t status;
9357828Sjlemon
9457828Sjlemon	if ((ida_inb(ida, R_EISA_SYSTEM_DOORBELL) & EISA_CHANNEL_BUSY) == 0)
9557828Sjlemon		return (0);
9657828Sjlemon
9757828Sjlemon	ida_outb(ida, R_EISA_SYSTEM_DOORBELL, EISA_CHANNEL_BUSY);
9857828Sjlemon	completed = ida_inl(ida, R_EISA_COMPLETE_ADDR);
9957828Sjlemon	status = ida_inb(ida, R_EISA_LIST_STATUS);
10057828Sjlemon	ida_outb(ida, R_EISA_LOCAL_DOORBELL, EISA_CHANNEL_CLEAR);
10157828Sjlemon
10257828Sjlemon	if (completed != 0) {
10357828Sjlemon        	hwqcb = (struct ida_hardware_qcb *)
10457828Sjlemon		    ((bus_addr_t)ida->hwqcbs +
10557828Sjlemon		    ((completed & ~3) - ida->hwqcb_busaddr));
10657828Sjlemon		hwqcb->req.error = status;
10757828Sjlemon	}
10857828Sjlemon
10957828Sjlemon	return (completed);
11057828Sjlemon}
11157828Sjlemon
11257828Sjlemonstatic int
11357828Sjlemonida_v1_int_pending(struct ida_softc *ida)
11457828Sjlemon{
11557828Sjlemon	return (ida_inb(ida, R_EISA_SYSTEM_DOORBELL) & EISA_CHANNEL_BUSY);
11657828Sjlemon}
11757828Sjlemon
11857828Sjlemonstatic void
11957828Sjlemonida_v1_int_enable(struct ida_softc *ida, int enable)
12057828Sjlemon{
12157828Sjlemon	if (enable) {
12257828Sjlemon		ida_outb(ida, R_EISA_SYSTEM_DOORBELL, ~EISA_CHANNEL_CLEAR);
12357828Sjlemon		ida_outb(ida, R_EISA_LOCAL_DOORBELL, EISA_CHANNEL_BUSY);
12457828Sjlemon		ida_outb(ida, R_EISA_INT_MASK, INT_ENABLE);
12557828Sjlemon		ida_outb(ida, R_EISA_SYSTEM_MASK, INT_ENABLE);
12673113Sjlemon		ida->flags |= IDA_INTERRUPTS;
12757828Sjlemon	} else {
12857828Sjlemon		ida_outb(ida, R_EISA_SYSTEM_MASK, INT_DISABLE);
12973113Sjlemon		ida->flags &= ~IDA_INTERRUPTS;
13057828Sjlemon	}
13157828Sjlemon}
13257828Sjlemon
13357828Sjlemonstatic int
13457828Sjlemonida_v2_fifo_full(struct ida_softc *ida)
13557828Sjlemon{
13657828Sjlemon	return (ida_inl(ida, R_CMD_FIFO) == 0);
13757828Sjlemon}
13857828Sjlemon
13957828Sjlemonstatic void
14057828Sjlemonida_v2_submit(struct ida_softc *ida, struct ida_qcb *qcb)
14157828Sjlemon{
14257828Sjlemon	ida_outl(ida, R_CMD_FIFO, qcb->hwqcb_busaddr);
14357828Sjlemon}
14457828Sjlemon
14557828Sjlemonstatic bus_addr_t
14657828Sjlemonida_v2_done(struct ida_softc *ida)
14757828Sjlemon{
14857828Sjlemon	return (ida_inl(ida, R_DONE_FIFO));
14957828Sjlemon}
15057828Sjlemon
15157828Sjlemonstatic int
15257828Sjlemonida_v2_int_pending(struct ida_softc *ida)
15357828Sjlemon{
15457828Sjlemon	return (ida_inl(ida, R_INT_PENDING));
15557828Sjlemon}
15657828Sjlemon
15757828Sjlemonstatic void
15857828Sjlemonida_v2_int_enable(struct ida_softc *ida, int enable)
15957828Sjlemon{
16073113Sjlemon	if (enable)
16173113Sjlemon		ida->flags |= IDA_INTERRUPTS;
16273113Sjlemon	else
16373113Sjlemon		ida->flags &= ~IDA_INTERRUPTS;
16457828Sjlemon	ida_outl(ida, R_INT_MASK, enable ? INT_ENABLE : INT_DISABLE);
16557828Sjlemon}
16657828Sjlemon
16757828Sjlemonstatic struct ida_access ida_v1_access = {
16857828Sjlemon	ida_v1_fifo_full,
16957828Sjlemon	ida_v1_submit,
17057828Sjlemon	ida_v1_done,
17157828Sjlemon	ida_v1_int_pending,
17257828Sjlemon	ida_v1_int_enable,
17357828Sjlemon};
17457828Sjlemon
17557828Sjlemonstatic struct ida_access ida_v2_access = {
17657828Sjlemon	ida_v2_fifo_full,
17757828Sjlemon	ida_v2_submit,
17857828Sjlemon	ida_v2_done,
17957828Sjlemon	ida_v2_int_pending,
18057828Sjlemon	ida_v2_int_enable,
18157828Sjlemon};
18257828Sjlemon
18357828Sjlemonstatic struct ida_board board_id[] = {
18470845Sjlemon	{ 0x0e114001, "Compaq IDA controller",
18570845Sjlemon	    &ida_v1_access, 0 },
18670845Sjlemon	{ 0x0e114002, "Compaq IDA-2 controller",
18770845Sjlemon	    &ida_v1_access, 0 },
18870845Sjlemon	{ 0x0e114010, "Compaq IAES controller",
18970845Sjlemon	    &ida_v1_access, 0 },
19070845Sjlemon	{ 0x0e114020, "Compaq SMART array controller",
19170845Sjlemon	    &ida_v1_access, 0 },
19270845Sjlemon	{ 0x0e114030, "Compaq SMART-2/E array controller",
19370845Sjlemon	    &ida_v2_access, 0 },
19457828Sjlemon
19570845Sjlemon	{ 0, "", 0, 0 }
19657828Sjlemon};
19757828Sjlemon
19857828Sjlemonstatic struct 	ida_board *ida_eisa_match(eisa_id_t);
19957828Sjlemonstatic int	ida_eisa_probe(device_t);
20057828Sjlemonstatic int	ida_eisa_attach(device_t);
20157828Sjlemon
20257828Sjlemonstatic device_method_t ida_eisa_methods[] = {
20357828Sjlemon	DEVMETHOD(device_probe,		ida_eisa_probe),
20457828Sjlemon	DEVMETHOD(device_attach,	ida_eisa_attach),
20557828Sjlemon	DEVMETHOD(device_detach,	ida_detach),
20657828Sjlemon
20757828Sjlemon	{ 0, 0 }
20857828Sjlemon};
20957828Sjlemon
21057828Sjlemonstatic driver_t ida_eisa_driver = {
21157828Sjlemon	"ida",
21257828Sjlemon	ida_eisa_methods,
21357828Sjlemon	sizeof(struct ida_softc)
21457828Sjlemon};
21557828Sjlemon
21657828Sjlemonstatic devclass_t ida_devclass;
21757828Sjlemon
21857828Sjlemonstatic struct ida_board *
21957828Sjlemonida_eisa_match(eisa_id_t id)
22057828Sjlemon{
22157828Sjlemon	int i;
22257828Sjlemon
22357828Sjlemon	for (i = 0; board_id[i].board; i++)
22457828Sjlemon		if (board_id[i].board == id)
22557828Sjlemon			return (&board_id[i]);
22657828Sjlemon	return (NULL);
22757828Sjlemon}
22857828Sjlemon
22957828Sjlemonstatic int
23057828Sjlemonida_eisa_probe(device_t dev)
23157828Sjlemon{
23257828Sjlemon	struct ida_board	*board;
23357828Sjlemon	u_int32_t		io_base;
23457828Sjlemon	u_int			irq = 0;
23557828Sjlemon
23657828Sjlemon	board = ida_eisa_match(eisa_get_id(dev));
23757828Sjlemon	if (board == NULL)
23857828Sjlemon		return (ENXIO);
23957828Sjlemon	device_set_desc(dev, board->desc);
24057828Sjlemon
24157828Sjlemon	io_base = (eisa_get_slot(dev) * EISA_SLOT_SIZE);
24257828Sjlemon
24357828Sjlemon	switch (IDA_EISA_IRQ_MASK & (inb(IDA_EISA_IRQ_REG + io_base))) {
24457828Sjlemon	case IDA_EISA_IRQ_15:
24557828Sjlemon		irq = 15;
24657828Sjlemon		break;
24757828Sjlemon	case IDA_EISA_IRQ_14:
24857828Sjlemon		irq = 14;
24957828Sjlemon		break;
25057828Sjlemon	case IDA_EISA_IRQ_11:
25157828Sjlemon		irq = 11;
25257828Sjlemon		break;
25357828Sjlemon	case IDA_EISA_IRQ_10:
25457828Sjlemon		irq = 10;
25557828Sjlemon		break;
25657828Sjlemon	default:
25757828Sjlemon		device_printf(dev, "slot %d, illegal irq setting.\n",
25857828Sjlemon		    eisa_get_slot(dev));
25957828Sjlemon		return (ENXIO);
26057828Sjlemon	}
26157828Sjlemon
26257828Sjlemon	eisa_add_iospace(dev, (io_base + IDA_EISA_IOPORT_START),
26357828Sjlemon			 IDA_EISA_IOPORT_LEN, RESVADDR_NONE);
26457828Sjlemon
26557828Sjlemon        eisa_add_intr(dev, irq, EISA_TRIGGER_LEVEL);		/* XXX ??? */
26657828Sjlemon
26757828Sjlemon	return (0);
26857828Sjlemon}
26957828Sjlemon
27057828Sjlemonstatic int
27157828Sjlemonida_eisa_attach(device_t dev)
27257828Sjlemon{
27357828Sjlemon	struct ida_softc	*ida;
27457828Sjlemon	struct ida_board	*board;
27557828Sjlemon	int			error;
27657828Sjlemon	int			rid;
27757828Sjlemon
27857828Sjlemon	ida = device_get_softc(dev);
27957828Sjlemon	ida->dev = dev;
28057828Sjlemon
28157828Sjlemon	board = ida_eisa_match(eisa_get_id(dev));
28257828Sjlemon	ida->cmd = *board->accessor;
28370845Sjlemon	ida->flags = board->flags;
28457828Sjlemon
28557828Sjlemon	ida->regs_res_type = SYS_RES_IOPORT;
28657828Sjlemon	ida->regs_res_id = 0;
28757828Sjlemon	ida->regs = bus_alloc_resource(dev, ida->regs_res_type,
28857828Sjlemon	    &ida->regs_res_id, 0, ~0, 1, RF_ACTIVE);
28957828Sjlemon	if (ida->regs == NULL) {
29057828Sjlemon		device_printf(dev, "can't allocate register resources\n");
29157828Sjlemon		return (ENOMEM);
29257828Sjlemon	}
29357828Sjlemon
29457828Sjlemon	error = bus_dma_tag_create(
29557828Sjlemon		/* parent	*/	NULL,
29657828Sjlemon		/* alignment	*/	0,
29757828Sjlemon		/* boundary	*/	0,
29857828Sjlemon		/* lowaddr	*/	BUS_SPACE_MAXADDR_32BIT,
29957828Sjlemon		/* highaddr	*/	BUS_SPACE_MAXADDR,
30057828Sjlemon		/* filter	*/	NULL,
30157828Sjlemon		/* filterarg	*/	NULL,
30257828Sjlemon		/* maxsize	*/	MAXBSIZE,
30357828Sjlemon		/* nsegments	*/	IDA_NSEG,
30457828Sjlemon		/* maxsegsize	*/	BUS_SPACE_MAXSIZE_32BIT,
30557828Sjlemon		/* flags	*/	BUS_DMA_ALLOCNOW,
30657828Sjlemon		&ida->parent_dmat);
30757828Sjlemon
30857828Sjlemon	if (error != 0) {
30957828Sjlemon		device_printf(dev, "can't allocate DMA tag\n");
31057828Sjlemon		ida_free(ida);
31157828Sjlemon		return (ENOMEM);
31257828Sjlemon	}
31357828Sjlemon
31457828Sjlemon	rid = 0;
31557828Sjlemon	ida->irq_res_type = SYS_RES_IRQ;
31657828Sjlemon	ida->irq = bus_alloc_resource(dev, ida->irq_res_type, &rid,
31757828Sjlemon	    0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
31857828Sjlemon	if (ida->irq == NULL) {
31957828Sjlemon		ida_free(ida);
32057828Sjlemon		return (ENOMEM);
32157828Sjlemon	}
32257828Sjlemon
32373280Smarkm	error = bus_setup_intr(dev, ida->irq, INTR_TYPE_BIO | INTR_ENTROPY,
32457828Sjlemon	    ida_intr, ida, &ida->ih);
32557828Sjlemon	if (error) {
32657828Sjlemon		device_printf(dev, "can't setup interrupt\n");
32757828Sjlemon		ida_free(ida);
32857828Sjlemon		return (ENOMEM);
32957828Sjlemon	}
33057828Sjlemon
33157828Sjlemon	error = ida_init(ida);
33257828Sjlemon	if (error) {
33357828Sjlemon		ida_free(ida);
33457828Sjlemon		return (error);
33557828Sjlemon	}
33657828Sjlemon
33757828Sjlemon	ida_attach(ida);
33873113Sjlemon	ida->flags |= IDA_ATTACHED;
33957828Sjlemon
34057828Sjlemon	return (0);
34157828Sjlemon}
34257828Sjlemon
34357828SjlemonDRIVER_MODULE(ida, eisa, ida_eisa_driver, ida_devclass, 0, 0);
344