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/ata/ata-cbus.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 /*-
    2  * Copyright (c) 2002 - 2008 Søren Schmidt <sos@FreeBSD.org>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer,
   10  *    without modification, immediately at the beginning of the file.
   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  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD$");
   29 
   30 #include "opt_ata.h"
   31 #include <sys/param.h>
   32 #include <sys/systm.h>
   33 #include <sys/kernel.h>
   34 #include <sys/ata.h>
   35 #include <sys/bus.h>
   36 #include <sys/malloc.h>
   37 #include <sys/module.h>
   38 #include <sys/conf.h>
   39 #include <sys/sema.h>
   40 #include <sys/taskqueue.h>
   41 #include <vm/uma.h>
   42 #include <machine/resource.h>
   43 #include <machine/bus.h>
   44 #include <sys/rman.h>
   45 #include <isa/isavar.h>
   46 #include <dev/ata/ata-all.h>
   47 #include <ata_if.h>
   48 
   49 /* local vars */
   50 struct ata_cbus_controller {
   51     struct resource *io;
   52     struct resource *ctlio;
   53     struct resource *bankio;
   54     struct resource *irq;
   55     void *ih;
   56 #ifndef ATA_CAM
   57     struct mtx bank_mtx;
   58     int locked_bank;
   59     int restart_bank;
   60     int hardware_bank;
   61 #endif
   62     int channels;
   63     struct {
   64         void (*function)(void *);
   65         void *argument;
   66     } interrupt[2];
   67 };
   68 
   69 /* local prototypes */
   70 static void ata_cbus_intr(void *);
   71 #ifndef ATA_CAM
   72 static int ata_cbuschannel_banking(device_t dev, int flags);
   73 #endif
   74 
   75 static int
   76 ata_cbus_probe(device_t dev)
   77 {
   78     struct resource *io;
   79     int rid;
   80     u_long tmp;
   81 
   82     /* dont probe PnP devices */
   83     if (isa_get_vendorid(dev))
   84         return (ENXIO);
   85 
   86     /* allocate the ioport range */
   87     rid = ATA_IOADDR_RID;
   88     if (!(io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0,
   89                                   ATA_PC98_IOSIZE, RF_ACTIVE)))
   90         return ENOMEM;
   91 
   92     /* calculate & set the altport range */
   93     rid = ATA_PC98_CTLADDR_RID;
   94     if (bus_get_resource(dev, SYS_RES_IOPORT, rid, &tmp, &tmp)) {
   95         bus_set_resource(dev, SYS_RES_IOPORT, rid,
   96                          rman_get_start(io)+ATA_PC98_CTLOFFSET, ATA_CTLIOSIZE);
   97     }
   98 
   99     /* calculate & set the bank range */
  100     rid = ATA_PC98_BANKADDR_RID;
  101     if (bus_get_resource(dev, SYS_RES_IOPORT, rid, &tmp, &tmp)) {
  102         bus_set_resource(dev, SYS_RES_IOPORT, rid,
  103                          ATA_PC98_BANK, ATA_PC98_BANKIOSIZE);
  104     }
  105 
  106     bus_release_resource(dev, SYS_RES_IOPORT, ATA_IOADDR_RID, io);
  107     return 0;
  108 }
  109 
  110 static int
  111 ata_cbus_attach(device_t dev)
  112 {
  113     struct ata_cbus_controller *ctlr = device_get_softc(dev);
  114     device_t child;
  115     int rid, unit;
  116 
  117     /* allocate resources */
  118     rid = ATA_IOADDR_RID;
  119     if (!(ctlr->io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0,
  120                                         ATA_PC98_IOSIZE, RF_ACTIVE)))
  121        return ENOMEM;
  122 
  123     rid = ATA_PC98_CTLADDR_RID;
  124     if (!(ctlr->ctlio = 
  125           bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
  126                              rman_get_start(ctlr->io) + ATA_PC98_CTLOFFSET, ~0,
  127                              ATA_CTLIOSIZE, RF_ACTIVE))) {
  128         bus_release_resource(dev, SYS_RES_IOPORT, ATA_IOADDR_RID, ctlr->io);
  129         return ENOMEM;
  130     }
  131 
  132     rid = ATA_PC98_BANKADDR_RID;
  133     if (!(ctlr->bankio = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
  134                                             ATA_PC98_BANK, ~0,
  135                                             ATA_PC98_BANKIOSIZE, RF_ACTIVE))) {
  136         bus_release_resource(dev, SYS_RES_IOPORT, ATA_IOADDR_RID, ctlr->io);
  137         bus_release_resource(dev, SYS_RES_IOPORT, ATA_CTLADDR_RID, ctlr->ctlio);
  138         return ENOMEM;
  139     }
  140 
  141     rid = ATA_IRQ_RID;
  142     if (!(ctlr->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
  143                                              RF_ACTIVE | RF_SHAREABLE))) {
  144         device_printf(dev, "unable to alloc interrupt\n");
  145         bus_release_resource(dev, SYS_RES_IOPORT, ATA_IOADDR_RID, ctlr->io);
  146         bus_release_resource(dev, SYS_RES_IOPORT, ATA_CTLADDR_RID, ctlr->ctlio);
  147         bus_release_resource(dev, SYS_RES_IOPORT, 
  148                              ATA_PC98_BANKADDR_RID, ctlr->bankio);
  149         return ENXIO;
  150     }
  151 
  152     if ((bus_setup_intr(dev, ctlr->irq, ATA_INTR_FLAGS,
  153                         NULL, ata_cbus_intr, ctlr, &ctlr->ih))) {
  154         device_printf(dev, "unable to setup interrupt\n");
  155         bus_release_resource(dev, SYS_RES_IOPORT, ATA_IOADDR_RID, ctlr->io);
  156         bus_release_resource(dev, SYS_RES_IOPORT, ATA_CTLADDR_RID, ctlr->ctlio);
  157         bus_release_resource(dev, SYS_RES_IOPORT, 
  158                              ATA_PC98_BANKADDR_RID, ctlr->bankio);
  159         bus_release_resource(dev, SYS_RES_IOPORT, ATA_IRQ_RID, ctlr->irq);
  160         return ENXIO;
  161     }
  162 
  163 #ifndef ATA_CAM
  164         ctlr->channels = 2;
  165     mtx_init(&ctlr->bank_mtx, "ATA cbus bank lock", NULL, MTX_DEF);
  166     ctlr->hardware_bank = -1;
  167     ctlr->locked_bank = -1;
  168     ctlr->restart_bank = -1;
  169 #else
  170         /* Work around the lack of channel serialization in ATA_CAM. */
  171         ctlr->channels = 1;
  172         device_printf(dev, "second channel ignored\n");
  173 #endif
  174 
  175     for (unit = 0; unit < ctlr->channels; unit++) {
  176         child = device_add_child(dev, "ata", unit);
  177         if (child == NULL)
  178             device_printf(dev, "failed to add ata child device\n");
  179         else
  180             device_set_ivars(child, (void *)(intptr_t)unit);
  181     }
  182 
  183     bus_generic_attach(dev);
  184     return (0);
  185 }
  186 
  187 static struct resource *
  188 ata_cbus_alloc_resource(device_t dev, device_t child, int type, int *rid,
  189                         u_long start, u_long end, u_long count, u_int flags)
  190 {
  191     struct ata_cbus_controller *ctlr = device_get_softc(dev);
  192 
  193     if (type == SYS_RES_IOPORT) {
  194         switch (*rid) {
  195         case ATA_IOADDR_RID:
  196             return ctlr->io;
  197         case ATA_CTLADDR_RID:
  198             return ctlr->ctlio;
  199         }
  200     }
  201     if (type == SYS_RES_IRQ)
  202         return ctlr->irq;
  203     return 0;
  204 }
  205 
  206 static int
  207 ata_cbus_setup_intr(device_t dev, device_t child, struct resource *irq,
  208                int flags, driver_filter_t *filter, driver_intr_t *intr, 
  209                void *arg, void **cookiep)
  210 {
  211     struct ata_cbus_controller *controller = device_get_softc(dev);
  212     int unit = ((struct ata_channel *)device_get_softc(child))->unit;
  213 
  214     if (filter != NULL) {
  215             printf("ata-cbus.c: we cannot use a filter here\n");
  216             return (EINVAL);
  217     }
  218     controller->interrupt[unit].function = intr;
  219     controller->interrupt[unit].argument = arg;
  220     *cookiep = controller;
  221 
  222     return 0;
  223 }
  224 
  225 static int
  226 ata_cbus_print_child(device_t dev, device_t child)
  227 {
  228     struct ata_channel *ch = device_get_softc(child);
  229     int retval = 0;
  230 
  231     retval += bus_print_child_header(dev, child);
  232     retval += printf(" at bank %d", ch->unit);
  233     retval += bus_print_child_footer(dev, child);
  234     return retval;
  235 }
  236 
  237 static void
  238 ata_cbus_intr(void *data)
  239 {  
  240     struct ata_cbus_controller *ctlr = data;
  241     struct ata_channel *ch;
  242     int unit;
  243 
  244     for (unit = 0; unit < ctlr->channels; unit++) {
  245         if (!(ch = ctlr->interrupt[unit].argument))
  246             continue;
  247 #ifndef ATA_CAM
  248         if (ata_cbuschannel_banking(ch->dev, ATA_LF_WHICH) == unit)
  249 #endif
  250             ctlr->interrupt[unit].function(ch);
  251     }
  252 }
  253 
  254 static device_method_t ata_cbus_methods[] = {
  255     /* device interface */
  256     DEVMETHOD(device_probe,             ata_cbus_probe),
  257     DEVMETHOD(device_attach,            ata_cbus_attach),
  258 //  DEVMETHOD(device_detach,            ata_cbus_detach),
  259 
  260     /* bus methods */
  261     DEVMETHOD(bus_alloc_resource,       ata_cbus_alloc_resource),
  262     DEVMETHOD(bus_setup_intr,           ata_cbus_setup_intr),
  263     DEVMETHOD(bus_print_child,          ata_cbus_print_child),
  264 
  265     DEVMETHOD_END
  266 };
  267 
  268 static driver_t ata_cbus_driver = {
  269     "atacbus",
  270     ata_cbus_methods,
  271     sizeof(struct ata_cbus_controller),
  272 };
  273 
  274 static devclass_t ata_cbus_devclass;
  275 
  276 DRIVER_MODULE(atacbus, isa, ata_cbus_driver, ata_cbus_devclass, NULL, NULL);
  277 
  278 static int
  279 ata_cbuschannel_probe(device_t dev)
  280 {
  281     char buffer[32];
  282 
  283     sprintf(buffer, "ATA channel %d", (int)(intptr_t)device_get_ivars(dev));
  284     device_set_desc_copy(dev, buffer);
  285 
  286     return ata_probe(dev);
  287 }
  288 
  289 static int
  290 ata_cbuschannel_attach(device_t dev)
  291 {
  292     struct ata_cbus_controller *ctlr = device_get_softc(device_get_parent(dev));
  293     struct ata_channel *ch = device_get_softc(dev);
  294     int i;
  295 
  296     if (ch->attached)
  297         return (0);
  298     ch->attached = 1;
  299 
  300     ch->unit = (intptr_t)device_get_ivars(dev);
  301     /* setup the resource vectors */
  302     for (i = ATA_DATA; i <= ATA_COMMAND; i ++) {
  303         ch->r_io[i].res = ctlr->io;
  304         ch->r_io[i].offset = i << 1;
  305     }
  306     ch->r_io[ATA_CONTROL].res = ctlr->ctlio;
  307     ch->r_io[ATA_CONTROL].offset = 0;
  308     ch->r_io[ATA_IDX_ADDR].res = ctlr->io;
  309     ata_default_registers(dev);
  310 
  311     /* initialize softc for this channel */
  312     ch->flags |= ATA_USE_16BIT;
  313     ata_generic_hw(dev);
  314 
  315     return ata_attach(dev);
  316 }
  317 
  318 static int
  319 ata_cbuschannel_detach(device_t dev)
  320 {
  321     struct ata_channel *ch = device_get_softc(dev);
  322 
  323     if (!ch->attached)
  324         return (0);
  325     ch->attached = 0;
  326 
  327     return ata_detach(dev);
  328 }
  329 
  330 static int
  331 ata_cbuschannel_suspend(device_t dev)
  332 {
  333     struct ata_channel *ch = device_get_softc(dev);
  334 
  335     if (!ch->attached)
  336         return (0);
  337 
  338     return ata_suspend(dev);
  339 }
  340 
  341 static int
  342 ata_cbuschannel_resume(device_t dev)
  343 {
  344     struct ata_channel *ch = device_get_softc(dev);
  345 
  346     if (!ch->attached)
  347         return (0);
  348 
  349     return ata_resume(dev);
  350 }
  351 
  352 #ifndef ATA_CAM
  353 static int
  354 ata_cbuschannel_banking(device_t dev, int flags)
  355 {
  356     struct ata_cbus_controller *ctlr = device_get_softc(device_get_parent(dev));
  357     struct ata_channel *ch = device_get_softc(dev);
  358     int res;
  359 
  360     mtx_lock(&ctlr->bank_mtx);
  361     switch (flags) {
  362     case ATA_LF_LOCK:
  363         if (ctlr->locked_bank == -1)
  364             ctlr->locked_bank = ch->unit;
  365         if (ctlr->locked_bank == ch->unit) {
  366             ctlr->hardware_bank = ch->unit;
  367             ATA_OUTB(ctlr->bankio, 0, ch->unit);
  368         }
  369         else
  370             ctlr->restart_bank = ch->unit;
  371         break;
  372 
  373     case ATA_LF_UNLOCK:
  374         if (ctlr->locked_bank == ch->unit) {
  375             ctlr->locked_bank = -1;
  376             if (ctlr->restart_bank != -1) {
  377                 if ((ch = ctlr->interrupt[ctlr->restart_bank].argument)) {
  378                     ctlr->restart_bank = -1;
  379                     mtx_unlock(&ctlr->bank_mtx);
  380                     ata_start(ch->dev);
  381                     return -1;
  382                 }
  383             }
  384         }
  385         break;
  386 
  387     case ATA_LF_WHICH:
  388         break;
  389     }
  390     res = ctlr->locked_bank;
  391     mtx_unlock(&ctlr->bank_mtx);
  392     return res;
  393 }
  394 #endif
  395 
  396 static device_method_t ata_cbuschannel_methods[] = {
  397     /* device interface */
  398     DEVMETHOD(device_probe,     ata_cbuschannel_probe),
  399     DEVMETHOD(device_attach,    ata_cbuschannel_attach),
  400     DEVMETHOD(device_detach,    ata_cbuschannel_detach),
  401     DEVMETHOD(device_suspend,   ata_cbuschannel_suspend),
  402     DEVMETHOD(device_resume,    ata_cbuschannel_resume),
  403 
  404 #ifndef ATA_CAM
  405     /* ATA methods */
  406     DEVMETHOD(ata_locking,      ata_cbuschannel_banking),
  407 #endif
  408     DEVMETHOD_END
  409 };
  410 
  411 static driver_t ata_cbuschannel_driver = {
  412     "ata",
  413     ata_cbuschannel_methods,
  414     sizeof(struct ata_channel),
  415 };
  416 
  417 DRIVER_MODULE(ata, atacbus, ata_cbuschannel_driver, ata_devclass, NULL, NULL);
  418 MODULE_DEPEND(ata, ata, 1, 1, 1);

Cache object: 4a26055410d5d89dd574a9b0d8447b83


[ 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.