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