The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/pci/rccide.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: rccide.c,v 1.7 2004/01/03 22:56:53 thorpej Exp $       */
    2 
    3 /*
    4  * Copyright (c) 2003 By Noon Software, Inc.  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  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  * 3. The names of the authors may not be used to endorse or promote products
   15  *    derived from this software without specific prior written permission.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
   18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   20  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __KERNEL_RCSID(0, "$NetBSD: rccide.c,v 1.7 2004/01/03 22:56:53 thorpej Exp $");
   31 
   32 #include <sys/param.h>
   33 #include <sys/systm.h>
   34 
   35 #include <dev/pci/pcivar.h>
   36 #include <dev/pci/pcidevs.h>
   37 #include <dev/pci/pciidereg.h>
   38 #include <dev/pci/pciidevar.h>
   39 
   40 static void serverworks_chip_map(struct pciide_softc *,
   41                                  struct pci_attach_args *);
   42 static void serverworks_setup_channel(struct wdc_channel *);
   43 static int  serverworks_pci_intr(void *);
   44 static int  serverworkscsb6_pci_intr(void *);
   45 
   46 static int  rccide_match(struct device *, struct cfdata *, void *);
   47 static void rccide_attach(struct device *, struct device *, void *);
   48 
   49 CFATTACH_DECL(rccide, sizeof(struct pciide_softc),
   50     rccide_match, rccide_attach, NULL, NULL);
   51 
   52 static const struct pciide_product_desc pciide_serverworks_products[] =  {
   53         { PCI_PRODUCT_SERVERWORKS_OSB4_IDE,
   54           0,
   55           "ServerWorks OSB4 IDE Controller",
   56           serverworks_chip_map,
   57         },
   58         { PCI_PRODUCT_SERVERWORKS_CSB5_IDE,
   59           0,
   60           "ServerWorks CSB5 IDE Controller",
   61           serverworks_chip_map,
   62         },
   63         { PCI_PRODUCT_SERVERWORKS_CSB6_IDE,
   64           0,
   65           "ServerWorks CSB6 RAID/IDE Controller",
   66           serverworks_chip_map,
   67         },
   68         { PCI_PRODUCT_SERVERWORKS_CSB6_RAID,
   69           0,
   70           "ServerWorks CSB6 RAID/IDE Controller",
   71           serverworks_chip_map,
   72         },
   73         { 0,
   74           0,
   75           NULL,
   76           NULL,
   77         }
   78 };
   79 
   80 static int
   81 rccide_match(struct device *parent, struct cfdata *match, void *aux)
   82 {
   83         struct pci_attach_args *pa = aux;
   84 
   85         if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_SERVERWORKS &&
   86             PCI_CLASS(pa->pa_class) == PCI_CLASS_MASS_STORAGE &&
   87             PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_MASS_STORAGE_IDE) {
   88                 if (pciide_lookup_product(pa->pa_id,
   89                     pciide_serverworks_products))
   90                         return (2);
   91         }
   92         return (0);
   93 }
   94 
   95 static void
   96 rccide_attach(struct device *parent, struct device *self, void *aux)
   97 {
   98         struct pci_attach_args *pa = aux;
   99         struct pciide_softc *sc = (void *)self;
  100 
  101         pciide_common_attach(sc, pa,
  102             pciide_lookup_product(pa->pa_id, pciide_serverworks_products));
  103 }
  104 
  105 static void
  106 serverworks_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
  107 {
  108         struct pciide_channel *cp;
  109         pcireg_t interface = PCI_INTERFACE(pa->pa_class);
  110         pcitag_t pcib_tag;
  111         int channel;
  112         bus_size_t cmdsize, ctlsize;
  113 
  114         if (pciide_chipen(sc, pa) == 0)
  115                 return;
  116 
  117         aprint_normal("%s: bus-master DMA support present",
  118             sc->sc_wdcdev.sc_dev.dv_xname);
  119         pciide_mapreg_dma(sc, pa);
  120         aprint_normal("\n");
  121         sc->sc_wdcdev.cap = WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 |
  122             WDC_CAPABILITY_MODE;
  123 
  124         if (sc->sc_dma_ok) {
  125                 sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA | WDC_CAPABILITY_UDMA;
  126                 sc->sc_wdcdev.cap |= WDC_CAPABILITY_IRQACK;
  127                 sc->sc_wdcdev.irqack = pciide_irqack;
  128         }
  129         sc->sc_wdcdev.PIO_cap = 4;
  130         sc->sc_wdcdev.DMA_cap = 2;
  131         switch (sc->sc_pp->ide_product) {
  132         case PCI_PRODUCT_SERVERWORKS_OSB4_IDE:
  133                 sc->sc_wdcdev.UDMA_cap = 2;
  134                 break;
  135         case PCI_PRODUCT_SERVERWORKS_CSB5_IDE:
  136                 if (PCI_REVISION(pa->pa_class) < 0x92)
  137                         sc->sc_wdcdev.UDMA_cap = 4;
  138                 else
  139                         sc->sc_wdcdev.UDMA_cap = 5;
  140                 break;
  141         case PCI_PRODUCT_SERVERWORKS_CSB6_IDE:
  142         case PCI_PRODUCT_SERVERWORKS_CSB6_RAID:
  143                 sc->sc_wdcdev.UDMA_cap = 5;
  144                 break;
  145         }
  146 
  147         sc->sc_wdcdev.set_modes = serverworks_setup_channel;
  148         sc->sc_wdcdev.channels = sc->wdc_chanarray;
  149         sc->sc_wdcdev.nchannels = 2;
  150 
  151         for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
  152                 cp = &sc->pciide_channels[channel];
  153                 if (pciide_chansetup(sc, channel, interface) == 0)
  154                         continue;
  155                 switch (sc->sc_pp->ide_product) {
  156                 case PCI_PRODUCT_SERVERWORKS_CSB6_IDE:
  157                 case PCI_PRODUCT_SERVERWORKS_CSB6_RAID:
  158                         pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize,
  159                             serverworkscsb6_pci_intr);
  160                         break;
  161                 default:
  162                         pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize,
  163                             serverworks_pci_intr);
  164                 }
  165         }
  166 
  167         pcib_tag = pci_make_tag(pa->pa_pc, pa->pa_bus, pa->pa_device, 0);
  168         pci_conf_write(pa->pa_pc, pcib_tag, 0x64,
  169             (pci_conf_read(pa->pa_pc, pcib_tag, 0x64) & ~0x2000) | 0x4000);
  170 }
  171 
  172 static void
  173 serverworks_setup_channel(struct wdc_channel *chp)
  174 {
  175         struct ata_drive_datas *drvp;
  176         struct pciide_channel *cp = (struct pciide_channel*)chp;
  177         struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.ch_wdc;
  178         struct wdc_softc *wdc = &sc->sc_wdcdev;
  179         int channel = chp->ch_channel;
  180         int drive, unit;
  181         u_int32_t pio_time, dma_time, pio_mode, udma_mode;
  182         u_int32_t idedma_ctl;
  183         static const u_int8_t pio_modes[5] = {0x5d, 0x47, 0x34, 0x22, 0x20};
  184         static const u_int8_t dma_modes[3] = {0x77, 0x21, 0x20};
  185 
  186         /* setup DMA if needed */
  187         pciide_channel_dma_setup(cp);
  188 
  189         pio_time = pci_conf_read(sc->sc_pc, sc->sc_tag, 0x40);
  190         dma_time = pci_conf_read(sc->sc_pc, sc->sc_tag, 0x44);
  191         pio_mode = pci_conf_read(sc->sc_pc, sc->sc_tag, 0x48);
  192         udma_mode = pci_conf_read(sc->sc_pc, sc->sc_tag, 0x54);
  193 
  194         pio_time &= ~(0xffff << (16 * channel));
  195         dma_time &= ~(0xffff << (16 * channel));
  196         pio_mode &= ~(0xff << (8 * channel + 16));
  197         udma_mode &= ~(0xff << (8 * channel + 16));
  198         udma_mode &= ~(3 << (2 * channel));
  199 
  200         idedma_ctl = 0;
  201 
  202         /* Per drive settings */
  203         for (drive = 0; drive < 2; drive++) {
  204                 drvp = &chp->ch_drive[drive];
  205                 /* If no drive, skip */
  206                 if ((drvp->drive_flags & DRIVE) == 0)
  207                         continue;
  208                 unit = drive + 2 * channel;
  209                 /* add timing values, setup DMA if needed */
  210                 pio_time |= pio_modes[drvp->PIO_mode] << (8 * (unit^1));
  211                 pio_mode |= drvp->PIO_mode << (4 * unit + 16);
  212                 if ((wdc->cap & WDC_CAPABILITY_UDMA) &&
  213                     (drvp->drive_flags & DRIVE_UDMA)) {
  214                         /* use Ultra/DMA, check for 80-pin cable */
  215                         if (drvp->UDMA_mode > 2 &&
  216                             (PCI_PRODUCT(pci_conf_read(sc->sc_pc, sc->sc_tag,
  217                                                        PCI_SUBSYS_ID_REG))
  218                              & (1 << (14 + channel))) == 0)
  219                                 drvp->UDMA_mode = 2;
  220                         dma_time |= dma_modes[drvp->DMA_mode] << (8 * (unit^1));
  221                         udma_mode |= drvp->UDMA_mode << (4 * unit + 16);
  222                         udma_mode |= 1 << unit;
  223                         idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
  224                 } else if ((wdc->cap & WDC_CAPABILITY_DMA) &&
  225                     (drvp->drive_flags & DRIVE_DMA)) {
  226                         /* use Multiword DMA */
  227                         drvp->drive_flags &= ~DRIVE_UDMA;
  228                         dma_time |= dma_modes[drvp->DMA_mode] << (8 * (unit^1));
  229                         idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
  230                 } else {
  231                         /* PIO only */
  232                         drvp->drive_flags &= ~(DRIVE_UDMA | DRIVE_DMA);
  233                 }
  234         }
  235 
  236         pci_conf_write(sc->sc_pc, sc->sc_tag, 0x40, pio_time);
  237         pci_conf_write(sc->sc_pc, sc->sc_tag, 0x44, dma_time);
  238         if (sc->sc_pp->ide_product != PCI_PRODUCT_SERVERWORKS_OSB4_IDE)
  239                 pci_conf_write(sc->sc_pc, sc->sc_tag, 0x48, pio_mode);
  240         pci_conf_write(sc->sc_pc, sc->sc_tag, 0x54, udma_mode);
  241 
  242         if (idedma_ctl != 0) {
  243                 /* Add software bits in status register */
  244                 bus_space_write_1(sc->sc_dma_iot, cp->dma_iohs[IDEDMA_CTL], 0,
  245                     idedma_ctl);
  246         }
  247 }
  248 
  249 static int
  250 serverworks_pci_intr(arg)
  251         void *arg;
  252 {
  253         struct pciide_softc *sc = arg;
  254         struct pciide_channel *cp;
  255         struct wdc_channel *wdc_cp;
  256         int rv = 0;
  257         int dmastat, i, crv;
  258 
  259         for (i = 0; i < sc->sc_wdcdev.nchannels; i++) {
  260                 cp = &sc->pciide_channels[i];
  261                 dmastat = bus_space_read_1(sc->sc_dma_iot,
  262                     cp->dma_iohs[IDEDMA_CTL], 0);
  263                 if ((dmastat & (IDEDMA_CTL_ACT | IDEDMA_CTL_INTR)) !=
  264                     IDEDMA_CTL_INTR)
  265                         continue;
  266                 wdc_cp = &cp->wdc_channel;
  267                 crv = wdcintr(wdc_cp);
  268                 if (crv == 0) {
  269                         printf("%s:%d: bogus intr\n",
  270                             sc->sc_wdcdev.sc_dev.dv_xname, i);
  271                         bus_space_write_1(sc->sc_dma_iot,
  272                             cp->dma_iohs[IDEDMA_CTL], 0, dmastat);
  273                 } else
  274                         rv = 1;
  275         }
  276         return rv;
  277 }
  278 
  279 static int
  280 serverworkscsb6_pci_intr(arg)
  281         void *arg;
  282 {
  283         struct pciide_softc *sc = arg;
  284         struct pciide_channel *cp;
  285         struct wdc_channel *wdc_cp;
  286         int rv = 0;
  287         int i, crv;
  288 
  289         for (i = 0; i < sc->sc_wdcdev.nchannels; i++) {
  290                 cp = &sc->pciide_channels[i];
  291                 wdc_cp = &cp->wdc_channel;
  292                 /*
  293                  * The CSB6 doesn't assert IDEDMA_CTL_INTR for non-DMA commands.
  294                  * Until we find a way to know if the controller posted an
  295                  * interrupt, always call wdcintr(), which will try to guess
  296                  * if the interrupt was for us or not (and checks
  297                  * IDEDMA_CTL_INTR for DMA commands only).
  298                  */
  299                 crv = wdcintr(wdc_cp);
  300                 if (crv != 0)
  301                         rv = 1;
  302         }
  303         return rv;
  304 }

Cache object: c1296348a8dd9c0eddb3a53d4da1aca4


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.