ida_eisa.c revision 70845
1/* 2 * Copyright (c) 2000 Jonathan Lemon 3 * Copyright (c) 1999 by Matthew N. Dodd <winter@jurai.net> 4 * All Rights Reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions, and the following disclaimer, 11 * without modification, immediately at the beginning of the file. 12 * 2. The name of the author may not be used to endorse or promote products 13 * derived from this software without specific prior written permission. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 19 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD: head/sys/dev/ida/ida_eisa.c 70845 2001-01-09 14:49:41Z jlemon $ 28 */ 29 30#include <sys/param.h> 31#include <sys/systm.h> 32#include <sys/kernel.h> 33#include <sys/bus.h> 34 35#include <sys/bio.h> 36#include <sys/devicestat.h> 37#include <sys/disk.h> 38 39#include <machine/bus_pio.h> 40#include <machine/bus.h> 41#include <machine/resource.h> 42#include <sys/rman.h> 43 44#include <dev/ida/idavar.h> 45#include <dev/ida/idareg.h> 46 47#include <dev/eisa/eisaconf.h> 48 49#define IDA_EISA_IOPORT_START 0x0c88 50#define IDA_EISA_IOPORT_LEN 0x0017 51 52#define IDA_EISA_IRQ_REG 0x0cc0 53#define IDA_EISA_IRQ_MASK 0xf0 54#define IDA_EISA_IRQ_15 0x80 55#define IDA_EISA_IRQ_14 0x40 56#define IDA_EISA_IRQ_11 0x10 57#define IDA_EISA_IRQ_10 0x20 58 59static int 60ida_v1_fifo_full(struct ida_softc *ida) 61{ 62 u_int8_t status; 63 64 status = ida_inb(ida, R_EISA_SYSTEM_DOORBELL); 65 return ((status & EISA_CHANNEL_CLEAR) == 0); 66} 67 68static void 69ida_v1_submit(struct ida_softc *ida, struct ida_qcb *qcb) 70{ 71 u_int16_t size; 72 73 /* 74 * On these cards, this location is actually for control flags. 75 * Set them to zero and pass in structure size via an I/O port. 76 */ 77 size = qcb->hwqcb->hdr.size << 2; 78 qcb->hwqcb->hdr.size = 0; 79 80 ida_outb(ida, R_EISA_SYSTEM_DOORBELL, EISA_CHANNEL_CLEAR); 81 ida_outl(ida, R_EISA_LIST_ADDR, qcb->hwqcb_busaddr); 82 ida_outw(ida, R_EISA_LIST_LEN, size); 83 ida_outb(ida, R_EISA_LOCAL_DOORBELL, EISA_CHANNEL_BUSY); 84} 85 86static bus_addr_t 87ida_v1_done(struct ida_softc *ida) 88{ 89 struct ida_hardware_qcb *hwqcb; 90 bus_addr_t completed; 91 u_int8_t status; 92 93 if ((ida_inb(ida, R_EISA_SYSTEM_DOORBELL) & EISA_CHANNEL_BUSY) == 0) 94 return (0); 95 96 ida_outb(ida, R_EISA_SYSTEM_DOORBELL, EISA_CHANNEL_BUSY); 97 completed = ida_inl(ida, R_EISA_COMPLETE_ADDR); 98 status = ida_inb(ida, R_EISA_LIST_STATUS); 99 ida_outb(ida, R_EISA_LOCAL_DOORBELL, EISA_CHANNEL_CLEAR); 100 101 if (completed != 0) { 102 hwqcb = (struct ida_hardware_qcb *) 103 ((bus_addr_t)ida->hwqcbs + 104 ((completed & ~3) - ida->hwqcb_busaddr)); 105 hwqcb->req.error = status; 106 } 107 108 return (completed); 109} 110 111static int 112ida_v1_int_pending(struct ida_softc *ida) 113{ 114 return (ida_inb(ida, R_EISA_SYSTEM_DOORBELL) & EISA_CHANNEL_BUSY); 115} 116 117static void 118ida_v1_int_enable(struct ida_softc *ida, int enable) 119{ 120 if (enable) { 121 ida_outb(ida, R_EISA_SYSTEM_DOORBELL, ~EISA_CHANNEL_CLEAR); 122 ida_outb(ida, R_EISA_LOCAL_DOORBELL, EISA_CHANNEL_BUSY); 123 ida_outb(ida, R_EISA_INT_MASK, INT_ENABLE); 124 ida_outb(ida, R_EISA_SYSTEM_MASK, INT_ENABLE); 125 } else { 126 ida_outb(ida, R_EISA_SYSTEM_MASK, INT_DISABLE); 127 } 128} 129 130static int 131ida_v2_fifo_full(struct ida_softc *ida) 132{ 133 return (ida_inl(ida, R_CMD_FIFO) == 0); 134} 135 136static void 137ida_v2_submit(struct ida_softc *ida, struct ida_qcb *qcb) 138{ 139 ida_outl(ida, R_CMD_FIFO, qcb->hwqcb_busaddr); 140} 141 142static bus_addr_t 143ida_v2_done(struct ida_softc *ida) 144{ 145 return (ida_inl(ida, R_DONE_FIFO)); 146} 147 148static int 149ida_v2_int_pending(struct ida_softc *ida) 150{ 151 return (ida_inl(ida, R_INT_PENDING)); 152} 153 154static void 155ida_v2_int_enable(struct ida_softc *ida, int enable) 156{ 157 ida_outl(ida, R_INT_MASK, enable ? INT_ENABLE : INT_DISABLE); 158} 159 160static struct ida_access ida_v1_access = { 161 ida_v1_fifo_full, 162 ida_v1_submit, 163 ida_v1_done, 164 ida_v1_int_pending, 165 ida_v1_int_enable, 166}; 167 168static struct ida_access ida_v2_access = { 169 ida_v2_fifo_full, 170 ida_v2_submit, 171 ida_v2_done, 172 ida_v2_int_pending, 173 ida_v2_int_enable, 174}; 175 176static struct ida_board board_id[] = { 177 { 0x0e114001, "Compaq IDA controller", 178 &ida_v1_access, 0 }, 179 { 0x0e114002, "Compaq IDA-2 controller", 180 &ida_v1_access, 0 }, 181 { 0x0e114010, "Compaq IAES controller", 182 &ida_v1_access, 0 }, 183 { 0x0e114020, "Compaq SMART array controller", 184 &ida_v1_access, 0 }, 185 { 0x0e114030, "Compaq SMART-2/E array controller", 186 &ida_v2_access, 0 }, 187 188 { 0, "", 0, 0 } 189}; 190 191static struct ida_board *ida_eisa_match(eisa_id_t); 192static int ida_eisa_probe(device_t); 193static int ida_eisa_attach(device_t); 194 195static device_method_t ida_eisa_methods[] = { 196 DEVMETHOD(device_probe, ida_eisa_probe), 197 DEVMETHOD(device_attach, ida_eisa_attach), 198 DEVMETHOD(device_detach, ida_detach), 199 200 { 0, 0 } 201}; 202 203static driver_t ida_eisa_driver = { 204 "ida", 205 ida_eisa_methods, 206 sizeof(struct ida_softc) 207}; 208 209static devclass_t ida_devclass; 210 211static struct ida_board * 212ida_eisa_match(eisa_id_t id) 213{ 214 int i; 215 216 for (i = 0; board_id[i].board; i++) 217 if (board_id[i].board == id) 218 return (&board_id[i]); 219 return (NULL); 220} 221 222static int 223ida_eisa_probe(device_t dev) 224{ 225 struct ida_board *board; 226 u_int32_t io_base; 227 u_int irq = 0; 228 229 board = ida_eisa_match(eisa_get_id(dev)); 230 if (board == NULL) 231 return (ENXIO); 232 device_set_desc(dev, board->desc); 233 234 io_base = (eisa_get_slot(dev) * EISA_SLOT_SIZE); 235 236 switch (IDA_EISA_IRQ_MASK & (inb(IDA_EISA_IRQ_REG + io_base))) { 237 case IDA_EISA_IRQ_15: 238 irq = 15; 239 break; 240 case IDA_EISA_IRQ_14: 241 irq = 14; 242 break; 243 case IDA_EISA_IRQ_11: 244 irq = 11; 245 break; 246 case IDA_EISA_IRQ_10: 247 irq = 10; 248 break; 249 default: 250 device_printf(dev, "slot %d, illegal irq setting.\n", 251 eisa_get_slot(dev)); 252 return (ENXIO); 253 } 254 255 eisa_add_iospace(dev, (io_base + IDA_EISA_IOPORT_START), 256 IDA_EISA_IOPORT_LEN, RESVADDR_NONE); 257 258 eisa_add_intr(dev, irq, EISA_TRIGGER_LEVEL); /* XXX ??? */ 259 260 return (0); 261} 262 263static int 264ida_eisa_attach(device_t dev) 265{ 266 struct ida_softc *ida; 267 struct ida_board *board; 268 int error; 269 int rid; 270 271 ida = device_get_softc(dev); 272 ida->dev = dev; 273 274 board = ida_eisa_match(eisa_get_id(dev)); 275 ida->cmd = *board->accessor; 276 ida->flags = board->flags; 277 278 ida->regs_res_type = SYS_RES_IOPORT; 279 ida->regs_res_id = 0; 280 ida->regs = bus_alloc_resource(dev, ida->regs_res_type, 281 &ida->regs_res_id, 0, ~0, 1, RF_ACTIVE); 282 if (ida->regs == NULL) { 283 device_printf(dev, "can't allocate register resources\n"); 284 return (ENOMEM); 285 } 286 287 error = bus_dma_tag_create( 288 /* parent */ NULL, 289 /* alignment */ 0, 290 /* boundary */ 0, 291 /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, 292 /* highaddr */ BUS_SPACE_MAXADDR, 293 /* filter */ NULL, 294 /* filterarg */ NULL, 295 /* maxsize */ MAXBSIZE, 296 /* nsegments */ IDA_NSEG, 297 /* maxsegsize */ BUS_SPACE_MAXSIZE_32BIT, 298 /* flags */ BUS_DMA_ALLOCNOW, 299 &ida->parent_dmat); 300 301 if (error != 0) { 302 device_printf(dev, "can't allocate DMA tag\n"); 303 ida_free(ida); 304 return (ENOMEM); 305 } 306 307 rid = 0; 308 ida->irq_res_type = SYS_RES_IRQ; 309 ida->irq = bus_alloc_resource(dev, ida->irq_res_type, &rid, 310 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); 311 if (ida->irq == NULL) { 312 ida_free(ida); 313 return (ENOMEM); 314 } 315 316 error = bus_setup_intr(dev, ida->irq, INTR_TYPE_BIO, 317 ida_intr, ida, &ida->ih); 318 if (error) { 319 device_printf(dev, "can't setup interrupt\n"); 320 ida_free(ida); 321 return (ENOMEM); 322 } 323 324 error = ida_init(ida); 325 if (error) { 326 ida_free(ida); 327 return (error); 328 } 329 330 ida_attach(ida); 331 ida->flags |= IDA_ATTACHED; 332 333 return (0); 334} 335 336DRIVER_MODULE(ida, eisa, ida_eisa_driver, ida_devclass, 0, 0); 337