ida_eisa.c revision 280347
1228063Sbapt/*- 295060Sjmallett * Copyright (c) 2000 Jonathan Lemon 395060Sjmallett * Copyright (c) 1999 by Matthew N. Dodd <winter@jurai.net> 41590Srgrimes * All Rights Reserved. 51590Srgrimes * 61590Srgrimes * Redistribution and use in source and binary forms, with or without 71590Srgrimes * modification, are permitted provided that the following conditions 81590Srgrimes * are met: 91590Srgrimes * 1. Redistributions of source code must retain the above copyright 101590Srgrimes * notice, this list of conditions, and the following disclaimer, 111590Srgrimes * without modification, immediately at the beginning of the file. 121590Srgrimes * 2. The name of the author may not be used to endorse or promote products 131590Srgrimes * derived from this software without specific prior written permission. 141590Srgrimes * 151590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 161590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 171590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 181590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 19228063Sbapt * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 201590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 211590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 221590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 231590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 241590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 251590Srgrimes * SUCH DAMAGE. 261590Srgrimes */ 271590Srgrimes 281590Srgrimes#include <sys/cdefs.h> 291590Srgrimes__FBSDID("$FreeBSD: head/sys/dev/ida/ida_eisa.c 280347 2015-03-22 16:10:28Z mav $"); 301590Srgrimes 311590Srgrimes#include <sys/param.h> 321590Srgrimes#include <sys/systm.h> 331590Srgrimes#include <sys/kernel.h> 341590Srgrimes#include <sys/module.h> 3595060Sjmallett#include <sys/bus.h> 3695060Sjmallett 371590Srgrimes#include <sys/bio.h> 381590Srgrimes#include <sys/conf.h> 3995060Sjmallett 4095060Sjmallett#include <machine/bus.h> 41228063Sbapt#include <machine/resource.h> 421590Srgrimes#include <sys/rman.h> 431590Srgrimes 4495060Sjmallett#include <geom/geom_disk.h> 451590Srgrimes 4695060Sjmallett#include <dev/ida/idavar.h> 471590Srgrimes#include <dev/ida/idareg.h> 481590Srgrimes 491590Srgrimes#include <dev/eisa/eisaconf.h> 501590Srgrimes 511590Srgrimes#define IDA_EISA_IOPORT_START 0x0c88 5295060Sjmallett#define IDA_EISA_IOPORT_LEN 0x0017 5395060Sjmallett 5495060Sjmallett#define IDA_EISA_IRQ_REG 0x0cc0 5595060Sjmallett#define IDA_EISA_IRQ_MASK 0xf0 5695060Sjmallett#define IDA_EISA_IRQ_15 0x80 5795060Sjmallett#define IDA_EISA_IRQ_14 0x40 5895060Sjmallett#define IDA_EISA_IRQ_11 0x10 59228063Sbapt#define IDA_EISA_IRQ_10 0x20 60228063Sbapt 61228063Sbaptstatic int 62228063Sbaptida_v1_fifo_full(struct ida_softc *ida) 63228063Sbapt{ 6495060Sjmallett u_int8_t status; 6595060Sjmallett 661590Srgrimes status = ida_inb(ida, R_EISA_SYSTEM_DOORBELL); 671590Srgrimes return ((status & EISA_CHANNEL_CLEAR) == 0); 681590Srgrimes} 6995060Sjmallett 7095887Sjmallettstatic void 711590Srgrimesida_v1_submit(struct ida_softc *ida, struct ida_qcb *qcb) 7295060Sjmallett{ 731590Srgrimes u_int16_t size; 7495060Sjmallett 7595060Sjmallett /* 7695060Sjmallett * On these cards, this location is actually for control flags. 7795060Sjmallett * Set them to zero and pass in structure size via an I/O port. 7895060Sjmallett */ 791590Srgrimes size = qcb->hwqcb->hdr.size << 2; 801590Srgrimes qcb->hwqcb->hdr.size = 0; 81228063Sbapt 821590Srgrimes ida_outb(ida, R_EISA_SYSTEM_DOORBELL, EISA_CHANNEL_CLEAR); 831590Srgrimes ida_outl(ida, R_EISA_LIST_ADDR, qcb->hwqcb_busaddr); 84228063Sbapt ida_outw(ida, R_EISA_LIST_LEN, size); 851590Srgrimes ida_outb(ida, R_EISA_LOCAL_DOORBELL, EISA_CHANNEL_BUSY); 865165Sache} 875167Sache 8895060Sjmallettstatic bus_addr_t 8995060Sjmallettida_v1_done(struct ida_softc *ida) 9095060Sjmallett{ 911590Srgrimes struct ida_hardware_qcb *hwqcb; 921590Srgrimes bus_addr_t completed; 931590Srgrimes u_int8_t status; 941590Srgrimes 95228063Sbapt if ((ida_inb(ida, R_EISA_SYSTEM_DOORBELL) & EISA_CHANNEL_BUSY) == 0) 961590Srgrimes return (0); 971590Srgrimes 981590Srgrimes ida_outb(ida, R_EISA_SYSTEM_DOORBELL, EISA_CHANNEL_BUSY); 9995887Sjmallett completed = ida_inl(ida, R_EISA_COMPLETE_ADDR); 1001590Srgrimes status = ida_inb(ida, R_EISA_LIST_STATUS); 10195060Sjmallett ida_outb(ida, R_EISA_LOCAL_DOORBELL, EISA_CHANNEL_CLEAR); 1021590Srgrimes 10395060Sjmallett if (completed != 0) { 104228063Sbapt hwqcb = (struct ida_hardware_qcb *) 10595060Sjmallett ((bus_addr_t)ida->hwqcbs + 10695060Sjmallett ((completed & ~3) - ida->hwqcb_busaddr)); 10795060Sjmallett hwqcb->req.error = status; 1081590Srgrimes } 1091590Srgrimes 1101590Srgrimes return (completed); 1111590Srgrimes} 1121590Srgrimes 1131590Srgrimesstatic int 11495887Sjmallettida_v1_int_pending(struct ida_softc *ida) 1151590Srgrimes{ 116228063Sbapt return (ida_inb(ida, R_EISA_SYSTEM_DOORBELL) & EISA_CHANNEL_BUSY); 117228063Sbapt} 118228063Sbapt 119228063Sbaptstatic void 120228063Sbaptida_v1_int_enable(struct ida_softc *ida, int enable) 121228063Sbapt{ 122228063Sbapt if (enable) { 12395060Sjmallett ida_outb(ida, R_EISA_SYSTEM_DOORBELL, ~EISA_CHANNEL_CLEAR); 124228063Sbapt ida_outb(ida, R_EISA_LOCAL_DOORBELL, EISA_CHANNEL_BUSY); 1251590Srgrimes ida_outb(ida, R_EISA_INT_MASK, INT_ENABLE); 126228063Sbapt ida_outb(ida, R_EISA_SYSTEM_MASK, INT_ENABLE); 127228063Sbapt ida->flags |= IDA_INTERRUPTS; 128228063Sbapt } else { 129228063Sbapt ida_outb(ida, R_EISA_SYSTEM_MASK, INT_DISABLE); 130228063Sbapt ida->flags &= ~IDA_INTERRUPTS; 131228063Sbapt } 1321590Srgrimes} 1331590Srgrimes 134228063Sbaptstatic int 135228063Sbaptida_v2_fifo_full(struct ida_softc *ida) 1361590Srgrimes{ 137228063Sbapt return (ida_inl(ida, R_CMD_FIFO) == 0); 1381590Srgrimes} 1391590Srgrimes 140228063Sbaptstatic void 141228063Sbaptida_v2_submit(struct ida_softc *ida, struct ida_qcb *qcb) 142228063Sbapt{ 143228063Sbapt ida_outl(ida, R_CMD_FIFO, qcb->hwqcb_busaddr); 144228063Sbapt} 145228063Sbapt 1461590Srgrimesstatic bus_addr_t 1471590Srgrimesida_v2_done(struct ida_softc *ida) 1481590Srgrimes{ 14995060Sjmallett return (ida_inl(ida, R_DONE_FIFO)); 15095060Sjmallett} 15195060Sjmallett 15295887Sjmallettstatic int 15395060Sjmallettida_v2_int_pending(struct ida_softc *ida) 15495060Sjmallett{ 155228063Sbapt return (ida_inl(ida, R_INT_PENDING)); 15695060Sjmallett} 15795060Sjmallett 15895060Sjmallettstatic void 15995060Sjmallettida_v2_int_enable(struct ida_softc *ida, int enable) 160100014Sjmallett{ 16199939Sjmallett if (enable) 16295060Sjmallett ida->flags |= IDA_INTERRUPTS; 16395060Sjmallett else 16495060Sjmallett ida->flags &= ~IDA_INTERRUPTS; 165228063Sbapt ida_outl(ida, R_INT_MASK, enable ? INT_ENABLE : INT_DISABLE); 16695060Sjmallett} 16795060Sjmallett 168228063Sbaptstatic struct ida_access ida_v1_access = { 16995060Sjmallett ida_v1_fifo_full, 17095060Sjmallett ida_v1_submit, 17195060Sjmallett ida_v1_done, 17295060Sjmallett ida_v1_int_pending, 17395060Sjmallett ida_v1_int_enable, 17495060Sjmallett}; 17595060Sjmallett 176100014Sjmallettstatic struct ida_access ida_v2_access = { 17799939Sjmallett ida_v2_fifo_full, 17895060Sjmallett ida_v2_submit, 17995060Sjmallett ida_v2_done, 18095060Sjmallett ida_v2_int_pending, 18195060Sjmallett ida_v2_int_enable, 18295060Sjmallett}; 18395060Sjmallett 18495060Sjmallettstatic struct ida_board board_id[] = { 18595060Sjmallett { 0x0e114001, "Compaq IDA controller", 18695060Sjmallett &ida_v1_access, 0 }, 187100014Sjmallett { 0x0e114002, "Compaq IDA-2 controller", 18895060Sjmallett &ida_v1_access, 0 }, 189100014Sjmallett { 0x0e114010, "Compaq IAES controller", 19095060Sjmallett &ida_v1_access, 0 }, 19195060Sjmallett { 0x0e114020, "Compaq SMART array controller", 19295060Sjmallett &ida_v1_access, 0 }, 19395060Sjmallett { 0x0e114030, "Compaq SMART-2/E array controller", 19495060Sjmallett &ida_v2_access, 0 }, 19595060Sjmallett 19695060Sjmallett { 0, "", 0, 0 } 19795060Sjmallett}; 19899939Sjmallett 19995060Sjmallettstatic struct ida_board *ida_eisa_match(eisa_id_t); 200228063Sbaptstatic int ida_eisa_probe(device_t); 20195060Sjmallettstatic int ida_eisa_attach(device_t); 20295060Sjmallett 203228063Sbaptstatic device_method_t ida_eisa_methods[] = { 204228063Sbapt DEVMETHOD(device_probe, ida_eisa_probe), 20595060Sjmallett DEVMETHOD(device_attach, ida_eisa_attach), 20695060Sjmallett DEVMETHOD(device_detach, ida_detach), 20795060Sjmallett 20895060Sjmallett { 0, 0 } 20995060Sjmallett}; 21095060Sjmallett 21195060Sjmallettstatic driver_t ida_eisa_driver = { 21295060Sjmallett "ida", 21395060Sjmallett ida_eisa_methods, 2141590Srgrimes sizeof(struct ida_softc) 2151590Srgrimes}; 2161590Srgrimes 21795887Sjmallettstatic devclass_t ida_devclass; 2181590Srgrimes 219100014Sjmallettstatic struct ida_board * 22095060Sjmallettida_eisa_match(eisa_id_t id) 22195060Sjmallett{ 2221590Srgrimes int i; 2231590Srgrimes 2241590Srgrimes for (i = 0; board_id[i].board; i++) 2251590Srgrimes if (board_id[i].board == id) 2261590Srgrimes return (&board_id[i]); 2271590Srgrimes return (NULL); 22895887Sjmallett} 2291590Srgrimes 23095060Sjmallettstatic int 2311590Srgrimesida_eisa_probe(device_t dev) 2321590Srgrimes{ 233228063Sbapt struct ida_board *board; 23495060Sjmallett u_int32_t io_base; 23595060Sjmallett u_int irq = 0; 23695060Sjmallett 2371590Srgrimes board = ida_eisa_match(eisa_get_id(dev)); 2381590Srgrimes if (board == NULL) 2391590Srgrimes return (ENXIO); 2401590Srgrimes device_set_desc(dev, board->desc); 2411590Srgrimes 242228063Sbapt io_base = (eisa_get_slot(dev) * EISA_SLOT_SIZE); 2431590Srgrimes 24495060Sjmallett switch (IDA_EISA_IRQ_MASK & (inb(IDA_EISA_IRQ_REG + io_base))) { 24595060Sjmallett case IDA_EISA_IRQ_15: 24695060Sjmallett irq = 15; 2471590Srgrimes break; 2481590Srgrimes case IDA_EISA_IRQ_14: 2491590Srgrimes irq = 14; 2501590Srgrimes break; 2511590Srgrimes case IDA_EISA_IRQ_11: 2521590Srgrimes irq = 11; 25399939Sjmallett break; 2541590Srgrimes case IDA_EISA_IRQ_10: 25595060Sjmallett irq = 10; 2561590Srgrimes break; 25795060Sjmallett default: 2581590Srgrimes device_printf(dev, "slot %d, illegal irq setting.\n", 2591590Srgrimes eisa_get_slot(dev)); 2601590Srgrimes return (ENXIO); 2611590Srgrimes } 2621590Srgrimes 263228063Sbapt eisa_add_iospace(dev, (io_base + IDA_EISA_IOPORT_START), 264228063Sbapt IDA_EISA_IOPORT_LEN, RESVADDR_NONE); 265228063Sbapt 266228063Sbapt eisa_add_intr(dev, irq, EISA_TRIGGER_LEVEL); /* XXX ??? */ 267228063Sbapt 268228063Sbapt return (0); 269228063Sbapt} 270228063Sbapt 271228063Sbaptstatic int 272228063Sbaptida_eisa_attach(device_t dev) 273228063Sbapt{ 274228063Sbapt struct ida_softc *ida; 275228063Sbapt struct ida_board *board; 276228063Sbapt int error; 277228063Sbapt int rid; 278228063Sbapt 279228063Sbapt ida = device_get_softc(dev); 280228063Sbapt ida->dev = dev; 28195060Sjmallett 28295060Sjmallett board = ida_eisa_match(eisa_get_id(dev)); 2831590Srgrimes ida->cmd = *board->accessor; 28495887Sjmallett ida->flags = board->flags; 28575551Sgshapiro mtx_init(&ida->lock, "ida", NULL, MTX_DEF); 28695060Sjmallett callout_init_mtx(&ida->ch, &ida->lock, 0); 28795060Sjmallett 288228063Sbapt ida->regs_res_type = SYS_RES_IOPORT; 289228063Sbapt ida->regs_res_id = 0; 29095060Sjmallett ida->regs = bus_alloc_resource_any(dev, ida->regs_res_type, 29195060Sjmallett &ida->regs_res_id, RF_ACTIVE); 29295060Sjmallett if (ida->regs == NULL) { 29375551Sgshapiro device_printf(dev, "can't allocate register resources\n"); 29475551Sgshapiro return (ENOMEM); 29595060Sjmallett } 296228063Sbapt 29795060Sjmallett error = bus_dma_tag_create( 298228063Sbapt /* parent */ bus_get_dma_tag(dev), 29995060Sjmallett /* alignment */ 1, 300228063Sbapt /* boundary */ 0, 301228063Sbapt /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, 302228063Sbapt /* highaddr */ BUS_SPACE_MAXADDR, 303228063Sbapt /* filter */ NULL, 304228063Sbapt /* filterarg */ NULL, 305228063Sbapt /* maxsize */ BUS_SPACE_MAXSIZE_32BIT, 306228063Sbapt /* nsegments */ BUS_SPACE_UNRESTRICTED, 307228063Sbapt /* maxsegsize */ BUS_SPACE_MAXSIZE_32BIT, 308228063Sbapt /* flags */ BUS_DMA_ALLOCNOW, 309228063Sbapt /* lockfunc */ NULL, 310228063Sbapt /* lockarg */ NULL, 31195060Sjmallett &ida->parent_dmat); 31295060Sjmallett 31395060Sjmallett if (error != 0) { 314228063Sbapt device_printf(dev, "can't allocate DMA tag\n"); 315228063Sbapt ida_free(ida); 316228063Sbapt return (ENOMEM); 317228063Sbapt } 318228063Sbapt 319228063Sbapt rid = 0; 320228063Sbapt ida->irq_res_type = SYS_RES_IRQ; 321228063Sbapt ida->irq = bus_alloc_resource_any(dev, ida->irq_res_type, &rid, 322228063Sbapt RF_ACTIVE | RF_SHAREABLE); 323228063Sbapt if (ida->irq == NULL) { 324228063Sbapt ida_free(ida); 325228063Sbapt return (ENOMEM); 326228063Sbapt } 327228063Sbapt 328228063Sbapt error = bus_setup_intr(dev, ida->irq, INTR_TYPE_BIO | INTR_ENTROPY | INTR_MPSAFE, 329228063Sbapt NULL, ida_intr, ida, &ida->ih); 330228063Sbapt if (error) { 331228063Sbapt device_printf(dev, "can't setup interrupt\n"); 332228063Sbapt ida_free(ida); 333228063Sbapt return (ENOMEM); 33495060Sjmallett } 33595887Sjmallett 33695060Sjmallett error = ida_init(ida); 33795060Sjmallett if (error) { 33895060Sjmallett ida_free(ida); 33995060Sjmallett return (error); 34095060Sjmallett } 34195060Sjmallett 34295060Sjmallett return (0); 34375551Sgshapiro} 34499939Sjmallett 3451590SrgrimesDRIVER_MODULE(ida, eisa, ida_eisa_driver, ida_devclass, 0, 0); 346228063Sbapt