ida_pci.c revision 281826
161033Sdfr/*- 261033Sdfr * Copyright (c) 1999,2000 Jonathan Lemon 361033Sdfr * All rights reserved. 461033Sdfr * 561033Sdfr * Redistribution and use in source and binary forms, with or without 661033Sdfr * modification, are permitted provided that the following conditions 761033Sdfr * are met: 861033Sdfr * 1. Redistributions of source code must retain the above copyright 961033Sdfr * notice, this list of conditions and the following disclaimer. 1061033Sdfr * 2. Redistributions in binary form must reproduce the above copyright 1161033Sdfr * notice, this list of conditions and the following disclaimer in the 1261033Sdfr * documentation and/or other materials provided with the distribution. 1361033Sdfr * 1461033Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1561033Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1661033Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1761033Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1861033Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1961033Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2061033Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2161033Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2261033Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2361033Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2461033Sdfr * SUCH DAMAGE. 2561033Sdfr */ 2661033Sdfr 27116182Sobrien#include <sys/cdefs.h> 28116182Sobrien__FBSDID("$FreeBSD: stable/10/sys/dev/ida/ida_pci.c 281826 2015-04-21 11:27:50Z mav $"); 29116182Sobrien 3061033Sdfr#include <sys/param.h> 3185521Sjhb#include <sys/systm.h> 3265822Sjhb#include <sys/kernel.h> 3385560Sjhb#include <sys/module.h> 3461033Sdfr 35123614Sjhb#include <sys/bio.h> 3685521Sjhb#include <sys/bus.h> 3761033Sdfr#include <sys/conf.h> 3885521Sjhb 39145729Ssam#include <machine/bus.h> 40154333Sscottl#include <machine/resource.h> 4185521Sjhb#include <sys/rman.h> 42119708Sken 43154333Sscottl#include <dev/pci/pcireg.h> 4461033Sdfr#include <dev/pci/pcivar.h> 4569774Sphk 46123614Sjhb#include <geom/geom_disk.h> 47123614Sjhb 4861033Sdfr#include <dev/ida/idavar.h> 4985521Sjhb#include <dev/ida/idareg.h> 5067551Sjhb 5161033Sdfr#define IDA_PCI_MAX_DMA_ADDR 0xFFFFFFFF 5261033Sdfr#define IDA_PCI_MAX_DMA_COUNT 0xFFFFFFFF 5361033Sdfr 5461033Sdfr#define IDA_PCI_MEMADDR PCIR_BAR(1) /* Mem I/O Address */ 5561033Sdfr 5661033Sdfr#define IDA_DEVICEID_SMART 0xAE100E11 57145473Ssam#define IDA_DEVICEID_DEC_SMART 0x00461011 5885521Sjhb#define IDA_DEVICEID_NCR_53C1510 0x00101000 59178015Ssam 60178015Ssamstatic int 61180588Skmacyida_v3_fifo_full(struct ida_softc *ida) 62154333Sscottl{ 6361033Sdfr return (ida_inl(ida, R_CMD_FIFO) == 0); 6461033Sdfr} 65154333Sscottl 66177621Sscottlstatic void 67177621Sscottlida_v3_submit(struct ida_softc *ida, struct ida_qcb *qcb) 68154333Sscottl{ 69180588Skmacy ida_outl(ida, R_CMD_FIFO, qcb->hwqcb_busaddr); 70180588Skmacy} 71180588Skmacy 72180588Skmacystatic bus_addr_t 73180588Skmacyida_v3_done(struct ida_softc *ida) 74180588Skmacy{ 75180588Skmacy bus_addr_t completed; 76180588Skmacy 77154167Sscottl completed = ida_inl(ida, R_DONE_FIFO); 78180588Skmacy if (completed == -1) { 79180588Skmacy return (0); /* fifo is empty */ 80180588Skmacy } 81180588Skmacy return (completed); 82180588Skmacy} 83180588Skmacy 84180588Skmacystatic int 85180588Skmacyida_v3_int_pending(struct ida_softc *ida) 86154167Sscottl{ 8785521Sjhb return (ida_inl(ida, R_INT_PENDING)); 8885521Sjhb} 89154167Sscottl 90154167Sscottlstatic void 91154167Sscottlida_v3_int_enable(struct ida_softc *ida, int enable) 92154167Sscottl{ 93180588Skmacy if (enable) 94154167Sscottl ida->flags |= IDA_INTERRUPTS; 95154167Sscottl else 96154167Sscottl ida->flags &= ~IDA_INTERRUPTS; 97154167Sscottl ida_outl(ida, R_INT_MASK, enable ? INT_ENABLE : INT_DISABLE); 9885521Sjhb} 9985521Sjhb 10085521Sjhbstatic int 10185521Sjhbida_v4_fifo_full(struct ida_softc *ida) 10293818Sjhb{ 10385521Sjhb return (ida_inl(ida, R_42XX_REQUEST) != 0); 10485521Sjhb} 10585521Sjhb 10685521Sjhbstatic void 10785521Sjhbida_v4_submit(struct ida_softc *ida, struct ida_qcb *qcb) 108154167Sscottl{ 109154167Sscottl ida_outl(ida, R_42XX_REQUEST, qcb->hwqcb_busaddr); 110145729Ssam} 111154167Sscottl 11261033Sdfrstatic bus_addr_t 11361033Sdfrida_v4_done(struct ida_softc *ida) 114180588Skmacy{ 11585521Sjhb bus_addr_t completed; 11661033Sdfr 117188058Simp completed = ida_inl(ida, R_42XX_REPLY); 118180588Skmacy if (completed == -1) 11961033Sdfr return (0); /* fifo is empty */ 12061033Sdfr ida_outl(ida, R_42XX_REPLY, 0); /* confirm read */ 12161033Sdfr return (completed); 12261033Sdfr} 123180588Skmacy 124180588Skmacystatic int 125154167Sscottlida_v4_int_pending(struct ida_softc *ida) 12661033Sdfr{ 12785521Sjhb return (ida_inl(ida, R_42XX_STATUS) & STATUS_42XX_INT_PENDING); 12861033Sdfr} 12985521Sjhb 13061033Sdfrstatic void 13161033Sdfrida_v4_int_enable(struct ida_softc *ida, int enable) 13261033Sdfr{ 13361033Sdfr if (enable) 134154167Sscottl ida->flags |= IDA_INTERRUPTS; 135154167Sscottl else 136154333Sscottl ida->flags &= ~IDA_INTERRUPTS; 137154167Sscottl ida_outl(ida, R_42XX_INT_MASK, 138154333Sscottl enable ? INT_ENABLE_42XX : INT_DISABLE_42XX); 139154167Sscottl} 140154167Sscottl 141154167Sscottlstatic struct ida_access ida_v3_access = { 142145729Ssam ida_v3_fifo_full, 143145729Ssam ida_v3_submit, 144145729Ssam ida_v3_done, 145145729Ssam ida_v3_int_pending, 146178015Ssam ida_v3_int_enable, 147145729Ssam}; 148145729Ssam 149178015Ssamstatic struct ida_access ida_v4_access = { 150154333Sscottl ida_v4_fifo_full, 151154333Sscottl ida_v4_submit, 152145729Ssam ida_v4_done, 153145729Ssam ida_v4_int_pending, 154145729Ssam ida_v4_int_enable, 15561033Sdfr}; 15661033Sdfr 15761033Sdfrstatic struct ida_board board_id[] = { 15885521Sjhb { 0x40300E11, "Compaq SMART-2/P array controller", 15985521Sjhb &ida_v3_access, 0 }, 16061033Sdfr { 0x40310E11, "Compaq SMART-2SL array controller", 16185521Sjhb &ida_v3_access, 0 }, 16261033Sdfr { 0x40320E11, "Compaq Smart Array 3200 controller", 163154167Sscottl &ida_v3_access, 0 }, 164154333Sscottl { 0x40330E11, "Compaq Smart Array 3100ES controller", 165131246Sjhb &ida_v3_access, 0 }, 166178015Ssam { 0x40340E11, "Compaq Smart Array 221 controller", 16785521Sjhb &ida_v3_access, 0 }, 168178015Ssam 16961033Sdfr { 0x40400E11, "Compaq Integrated Array controller", 17061033Sdfr &ida_v4_access, IDA_FIRMWARE }, 17161033Sdfr { 0x40480E11, "Compaq RAID LC2 controller", 17285521Sjhb &ida_v4_access, IDA_FIRMWARE }, 17385521Sjhb { 0x40500E11, "Compaq Smart Array 4200 controller", 17485521Sjhb &ida_v4_access, 0 }, 17561033Sdfr { 0x40510E11, "Compaq Smart Array 4250ES controller", 17661033Sdfr &ida_v4_access, 0 }, 17761033Sdfr { 0x40580E11, "Compaq Smart Array 431 controller", 17861033Sdfr &ida_v4_access, 0 }, 17961033Sdfr 18085521Sjhb { 0, "", 0, 0 }, 18185521Sjhb}; 182123614Sjhb 183154167Sscottlstatic int ida_pci_probe(device_t dev); 18485521Sjhbstatic int ida_pci_attach(device_t dev); 18561033Sdfr 18661033Sdfrstatic device_method_t ida_pci_methods[] = { 18785521Sjhb DEVMETHOD(device_probe, ida_pci_probe), 18885521Sjhb DEVMETHOD(device_attach, ida_pci_attach), 189123614Sjhb DEVMETHOD(device_detach, ida_detach), 19061033Sdfr 19161033Sdfr DEVMETHOD_END 19261033Sdfr}; 19361033Sdfr 19461033Sdfrstatic driver_t ida_pci_driver = { 19561033Sdfr "ida", 19661033Sdfr ida_pci_methods, 19761033Sdfr sizeof(struct ida_softc) 198154167Sscottl}; 19985560Sjhb 20061033Sdfrstatic devclass_t ida_devclass; 20161033Sdfr 20261033Sdfrstatic struct ida_board * 203180588Skmacyida_pci_match(device_t dev) 20461033Sdfr{ 205154167Sscottl int i; 20661033Sdfr u_int32_t id, sub_id; 20761033Sdfr 20861033Sdfr id = pci_get_devid(dev); 20961033Sdfr sub_id = pci_get_subdevice(dev) << 16 | pci_get_subvendor(dev); 21061033Sdfr 21161033Sdfr if (id == IDA_DEVICEID_SMART || 21264199Shsu id == IDA_DEVICEID_DEC_SMART || 21361033Sdfr id == IDA_DEVICEID_NCR_53C1510) { 21461033Sdfr for (i = 0; board_id[i].board; i++) 21561033Sdfr if (board_id[i].board == sub_id) 216188058Simp return (&board_id[i]); 21761033Sdfr } 21861033Sdfr return (NULL); 21961033Sdfr} 22061033Sdfr 22161033Sdfrstatic int 22261033Sdfrida_pci_probe(device_t dev) 22361033Sdfr{ 22461033Sdfr struct ida_board *board = ida_pci_match(dev); 22561033Sdfr 22661033Sdfr if (board != NULL) { 22761033Sdfr device_set_desc(dev, board->desc); 22861033Sdfr return (BUS_PROBE_DEFAULT); 229180588Skmacy } 230177621Sscottl return (ENXIO); 231180588Skmacy} 232177621Sscottl 23385560Sjhbstatic int 234154167Sscottlida_pci_attach(device_t dev) 23585560Sjhb{ 23661033Sdfr struct ida_board *board = ida_pci_match(dev); 23761033Sdfr u_int32_t id = pci_get_devid(dev); 23861033Sdfr struct ida_softc *ida; 23961033Sdfr int error, rid; 240177621Sscottl 241177621Sscottl ida = (struct ida_softc *)device_get_softc(dev); 242177621Sscottl ida->dev = dev; 243177621Sscottl ida->cmd = *board->accessor; 244177621Sscottl ida->flags = board->flags; 245177621Sscottl mtx_init(&ida->lock, "ida", NULL, MTX_DEF); 246177621Sscottl callout_init_mtx(&ida->ch, &ida->lock, 0); 247177621Sscottl 248177621Sscottl ida->regs_res_type = SYS_RES_MEMORY; 249177621Sscottl ida->regs_res_id = IDA_PCI_MEMADDR; 250177621Sscottl if (id == IDA_DEVICEID_DEC_SMART) 251177621Sscottl ida->regs_res_id = PCIR_BAR(0); 252177621Sscottl 253177621Sscottl ida->regs = bus_alloc_resource_any(dev, ida->regs_res_type, 254177621Sscottl &ida->regs_res_id, RF_ACTIVE); 255177621Sscottl if (ida->regs == NULL) { 256177621Sscottl device_printf(dev, "can't allocate memory resources\n"); 257177621Sscottl return (ENOMEM); 258177621Sscottl } 259177621Sscottl 260177621Sscottl error = bus_dma_tag_create( 261177621Sscottl /* parent */ bus_get_dma_tag(dev), 26261033Sdfr /* alignment */ 1, 26361033Sdfr /* boundary */ 0, 26461033Sdfr /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, 265131246Sjhb /* highaddr */ BUS_SPACE_MAXADDR, 26661033Sdfr /* filter */ NULL, 267131246Sjhb /* filterarg */ NULL, 268131246Sjhb /* maxsize */ BUS_SPACE_MAXSIZE_32BIT, 269154167Sscottl /* nsegments */ BUS_SPACE_UNRESTRICTED, 27061033Sdfr /* maxsegsize */ BUS_SPACE_MAXSIZE_32BIT, 27161033Sdfr /* flags */ BUS_DMA_ALLOCNOW, 27261033Sdfr /* lockfunc */ NULL, 27361033Sdfr /* lockarg */ NULL, 27461033Sdfr &ida->parent_dmat); 27561033Sdfr if (error != 0) { 27661033Sdfr device_printf(dev, "can't allocate DMA tag\n"); 27761033Sdfr ida_free(ida); 27861033Sdfr return (ENOMEM); 279145473Ssam } 280154167Sscottl 28161033Sdfr rid = 0; 28285560Sjhb ida->irq_res_type = SYS_RES_IRQ; 28361033Sdfr ida->irq = bus_alloc_resource_any(dev, ida->irq_res_type, &rid, 284154167Sscottl RF_ACTIVE | RF_SHAREABLE); 285145473Ssam if (ida->irq == NULL) { 286136131Simp ida_free(ida); 28761033Sdfr return (ENOMEM); 288131246Sjhb } 289131246Sjhb error = bus_setup_intr(dev, ida->irq, INTR_TYPE_BIO | INTR_ENTROPY | INTR_MPSAFE, 290131246Sjhb NULL, ida_intr, ida, &ida->ih); 291131246Sjhb if (error) { 292131246Sjhb device_printf(dev, "can't setup interrupt\n"); 293131246Sjhb ida_free(ida); 294154167Sscottl return (ENOMEM); 29561033Sdfr } 29661033Sdfr 297136131Simp error = ida_init(ida); 298136131Simp if (error) { 299136131Simp ida_free(ida); 300180588Skmacy return (error); 301154167Sscottl } 302154167Sscottl 303154167Sscottl return (0); 304154167Sscottl} 305154167Sscottl 306154167SscottlDRIVER_MODULE(ida, pci, ida_pci_driver, ida_devclass, 0, 0); 307145729Ssam