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.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: ata.c,v 1.27.2.2 2005/05/24 19:54:47 riz Exp $      */
    2 
    3 /*
    4  * Copyright (c) 1998, 2001 Manuel Bouyer.  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. All advertising materials mentioning features or use of this software
   15  *    must display the following acknowledgement:
   16  *  This product includes software developed by Manuel Bouyer.
   17  * 4. The name of the author may not be used to endorse or promote products
   18  *    derived from this software without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,     
   24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   30  */
   31 
   32 #include <sys/cdefs.h>
   33 __KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.27.2.2 2005/05/24 19:54:47 riz Exp $");
   34 
   35 #ifndef WDCDEBUG
   36 #define WDCDEBUG
   37 #endif /* WDCDEBUG */
   38 
   39 #include <sys/param.h>
   40 #include <sys/systm.h>
   41 #include <sys/kernel.h>
   42 #include <sys/malloc.h>
   43 #include <sys/device.h>
   44 #include <sys/proc.h>
   45 #include <sys/kthread.h>
   46 #include <sys/errno.h>
   47 
   48 #include <machine/intr.h>
   49 #include <machine/bus.h>
   50 
   51 #include <dev/ata/atareg.h>
   52 #include <dev/ata/atavar.h>
   53 #include <dev/ic/wdcreg.h>
   54 #include <dev/ic/wdcvar.h>
   55 
   56 #include "locators.h"
   57 
   58 #define DEBUG_FUNCS  0x08
   59 #define DEBUG_PROBE  0x10
   60 #define DEBUG_DETACH 0x20
   61 #ifdef WDCDEBUG
   62 extern int wdcdebug_mask; /* init'ed in wdc.c */
   63 #define WDCDEBUG_PRINT(args, level) \
   64         if (wdcdebug_mask & (level)) \
   65                 printf args
   66 #else
   67 #define WDCDEBUG_PRINT(args, level)
   68 #endif
   69 
   70 /*****************************************************************************
   71  * ATA bus layer.
   72  *
   73  * ATA controllers attach an atabus instance, which handles probing the bus
   74  * for drives, etc.
   75  *****************************************************************************/
   76 
   77 /*
   78  * atabusprint:
   79  *
   80  *      Autoconfiguration print routine used by ATA controllers when
   81  *      attaching an atabus instance.
   82  */
   83 int
   84 atabusprint(void *aux, const char *pnp)
   85 {
   86         struct wdc_channel *chan = aux;
   87         
   88         if (pnp)
   89                 aprint_normal("atabus at %s", pnp);
   90         aprint_normal(" channel %d", chan->ch_channel);
   91 
   92         return (UNCONF);
   93 }
   94 
   95 /*
   96  * ataprint:
   97  *
   98  *      Autoconfiguration print routine.
   99  */
  100 int
  101 ataprint(void *aux, const char *pnp)
  102 {
  103         struct ata_device *adev = aux;
  104 
  105         if (pnp)
  106                 aprint_normal("wd at %s", pnp);
  107         aprint_normal(" drive %d", adev->adev_drv_data->drive);
  108 
  109         return (UNCONF);
  110 }
  111 
  112 /*
  113  * atabus_thread:
  114  *
  115  *      Worker thread for the ATA bus.
  116  */
  117 static void
  118 atabus_thread(void *arg)
  119 {
  120         struct atabus_softc *sc = arg;
  121         struct wdc_channel *chp = sc->sc_chan;
  122         struct ata_xfer *xfer;
  123         int s;
  124 
  125         s = splbio();
  126         chp->ch_flags |= WDCF_TH_RUN;
  127         splx(s);
  128 
  129         /* Configure the devices on the bus. */
  130         atabusconfig(sc);
  131 
  132         s = splbio();
  133         for (;;) {
  134                 if ((chp->ch_flags & (WDCF_TH_RESET | WDCF_SHUTDOWN)) == 0 &&
  135                     ((chp->ch_flags & WDCF_ACTIVE) == 0 ||
  136                      chp->ch_queue->queue_freeze == 0)) {
  137                         chp->ch_flags &= ~WDCF_TH_RUN;
  138                         (void) tsleep(&chp->ch_thread, PRIBIO, "atath", 0);
  139                         chp->ch_flags |= WDCF_TH_RUN;
  140                 }
  141                 if (chp->ch_flags & WDCF_SHUTDOWN)
  142                         break;
  143                 if (chp->ch_flags & WDCF_TH_RESET) {
  144                         int drive;
  145 
  146                         (void) wdcreset(chp, RESET_SLEEP);
  147                         for (drive = 0; drive < 2; drive++)
  148                                 chp->ch_drive[drive].state = 0;
  149                         chp->ch_flags &= ~WDCF_TH_RESET;
  150                         chp->ch_queue->queue_freeze--;
  151                         wdcstart(chp);
  152                 } else if ((chp->ch_flags & WDCF_ACTIVE) != 0 &&
  153                            chp->ch_queue->queue_freeze == 1) {
  154                         /*
  155                          * Caller has bumped queue_freeze, decrease it.
  156                          */
  157                         chp->ch_queue->queue_freeze--;
  158                         xfer = TAILQ_FIRST(&chp->ch_queue->queue_xfer);
  159                         KASSERT(xfer != NULL);
  160                         (*xfer->c_start)(chp, xfer);
  161                 } else if (chp->ch_queue->queue_freeze > 1)
  162                         panic("ata_thread: queue_freeze");
  163         }
  164         splx(s);
  165         chp->ch_thread = NULL;
  166         wakeup((void *)&chp->ch_flags);
  167         kthread_exit(0);
  168 }
  169 
  170 /*
  171  * atabus_create_thread:
  172  *
  173  *      Helper routine to create the ATA bus worker thread.
  174  */
  175 static void
  176 atabus_create_thread(void *arg)
  177 {
  178         struct atabus_softc *sc = arg;
  179         struct wdc_channel *chp = sc->sc_chan;
  180         int error;
  181 
  182         if ((error = kthread_create1(atabus_thread, sc, &chp->ch_thread,
  183                                      "%s", sc->sc_dev.dv_xname)) != 0)
  184                 aprint_error("%s: unable to create kernel thread: error %d\n",
  185                     sc->sc_dev.dv_xname, error);
  186 }
  187 
  188 /*
  189  * atabus_match:
  190  *
  191  *      Autoconfiguration match routine.
  192  */
  193 static int
  194 atabus_match(struct device *parent, struct cfdata *cf, void *aux)
  195 {
  196         struct wdc_channel *chp = aux;
  197 
  198         if (chp == NULL)
  199                 return (0);
  200         
  201         if (cf->cf_loc[ATACF_CHANNEL] != chp->ch_channel &&
  202             cf->cf_loc[ATACF_CHANNEL] != ATACF_CHANNEL_DEFAULT)
  203                 return (0);
  204         
  205         return (1);
  206 }
  207 
  208 /*
  209  * atabus_attach:
  210  *
  211  *      Autoconfiguration attach routine.
  212  */
  213 static void
  214 atabus_attach(struct device *parent, struct device *self, void *aux)
  215 {
  216         struct atabus_softc *sc = (void *) self;
  217         struct wdc_channel *chp = aux;
  218         struct atabus_initq *initq;
  219 
  220         sc->sc_chan = chp;
  221 
  222         aprint_normal("\n");
  223         aprint_naive("\n");
  224 
  225         initq = malloc(sizeof(*initq), M_DEVBUF, M_WAITOK);
  226         initq->atabus_sc = sc;
  227         TAILQ_INSERT_TAIL(&atabus_initq_head, initq, atabus_initq);
  228         config_pending_incr();
  229         kthread_create(atabus_create_thread, sc);
  230 }
  231 
  232 /*
  233  * atabus_activate:
  234  *
  235  *      Autoconfiguration activation routine.
  236  */
  237 static int
  238 atabus_activate(struct device *self, enum devact act)
  239 {
  240         struct atabus_softc *sc = (void *) self;
  241         struct wdc_channel *chp = sc->sc_chan;
  242         struct device *dev = NULL;
  243         int s, i, error = 0;
  244 
  245         s = splbio();
  246         switch (act) {
  247         case DVACT_ACTIVATE:
  248                 error = EOPNOTSUPP;
  249                 break;
  250         
  251         case DVACT_DEACTIVATE:
  252                 /*
  253                  * We might deactivate the children of atapibus twice
  254                  * (once bia atapibus, once directly), but since the
  255                  * generic autoconfiguration code maintains the DVF_ACTIVE
  256                  * flag, it's safe.
  257                  */
  258                 if ((dev = chp->atapibus) != NULL) {
  259                         error = config_deactivate(dev);
  260                         if (error)
  261                                 goto out;
  262                 }
  263 
  264                 for (i = 0; i < 2; i++) {
  265                         if ((dev = chp->ch_drive[i].drv_softc) != NULL) {
  266                                 WDCDEBUG_PRINT(("atabus_activate: %s: "
  267                                     "deactivating %s\n", sc->sc_dev.dv_xname,
  268                                     dev->dv_xname),
  269                                     DEBUG_DETACH);
  270                                 error = config_deactivate(dev);
  271                                 if (error)
  272                                         goto out;
  273                         }
  274                 }
  275                 break;
  276         }
  277  out:
  278         splx(s);
  279 
  280 #ifdef WDCDEBUG
  281         if (dev != NULL && error != 0)
  282                 WDCDEBUG_PRINT(("atabus_activate: %s: "
  283                     "error %d deactivating %s\n", sc->sc_dev.dv_xname,
  284                     error, dev->dv_xname), DEBUG_DETACH);
  285 #endif /* WDCDEBUG */
  286 
  287         return (error);
  288 }
  289 
  290 /*
  291  * atabus_detach:
  292  *
  293  *      Autoconfiguration detach routine.
  294  */
  295 static int
  296 atabus_detach(struct device *self, int flags)
  297 {
  298         struct atabus_softc *sc = (void *) self;
  299         struct wdc_channel *chp = sc->sc_chan;
  300         struct device *dev = NULL;
  301         int i, error = 0;
  302 
  303         /* Shutdown the channel. */
  304         /* XXX NEED AN INTERLOCK HERE. */
  305         chp->ch_flags |= WDCF_SHUTDOWN;
  306         wakeup(&chp->ch_thread);
  307         while (chp->ch_thread != NULL)
  308                 (void) tsleep((void *)&chp->ch_flags, PRIBIO, "atadown", 0);
  309         
  310         /*
  311          * Detach atapibus and its children.
  312          */
  313         if ((dev = chp->atapibus) != NULL) {
  314                 WDCDEBUG_PRINT(("atabus_detach: %s: detaching %s\n",
  315                     sc->sc_dev.dv_xname, dev->dv_xname), DEBUG_DETACH);
  316                 error = config_detach(dev, flags);
  317                 if (error)
  318                         goto out;
  319         }
  320 
  321         /*
  322          * Detach our other children.
  323          */
  324         for (i = 0; i < 2; i++) {
  325                 if (chp->ch_drive[i].drive_flags & DRIVE_ATAPI)
  326                         continue;
  327                 if ((dev = chp->ch_drive[i].drv_softc) != NULL) {
  328                         WDCDEBUG_PRINT(("atabus_detach: %s: detaching %s\n",
  329                             sc->sc_dev.dv_xname, dev->dv_xname),
  330                             DEBUG_DETACH);
  331                         error = config_detach(dev, flags);
  332                         if (error)
  333                                 goto out;
  334                 }
  335         }
  336 
  337         wdc_kill_pending(chp);
  338  out:
  339 #ifdef WDCDEBUG
  340         if (dev != NULL && error != 0)
  341                 WDCDEBUG_PRINT(("atabus_detach: %s: error %d detaching %s\n",
  342                     sc->sc_dev.dv_xname, error, dev->dv_xname),
  343                     DEBUG_DETACH);
  344 #endif /* WDCDEBUG */
  345 
  346         return (error);
  347 }
  348 
  349 CFATTACH_DECL(atabus, sizeof(struct atabus_softc),
  350     atabus_match, atabus_attach, atabus_detach, atabus_activate);
  351 
  352 /*****************************************************************************
  353  * Common ATA bus operations.
  354  *****************************************************************************/
  355 
  356 /* Get the disk's parameters */
  357 int
  358 ata_get_params(struct ata_drive_datas *drvp, u_int8_t flags,
  359     struct ataparams *prms)
  360 {
  361         char tb[DEV_BSIZE];
  362         struct wdc_command wdc_c;
  363 
  364 #if BYTE_ORDER == LITTLE_ENDIAN
  365         int i;
  366         u_int16_t *p;
  367 #endif
  368 
  369         WDCDEBUG_PRINT(("ata_get_parms\n"), DEBUG_FUNCS);
  370 
  371         memset(tb, 0, DEV_BSIZE);
  372         memset(prms, 0, sizeof(struct ataparams));
  373         memset(&wdc_c, 0, sizeof(struct wdc_command));
  374 
  375         if (drvp->drive_flags & DRIVE_ATA) {
  376                 wdc_c.r_command = WDCC_IDENTIFY;
  377                 wdc_c.r_st_bmask = WDCS_DRDY;
  378                 wdc_c.r_st_pmask = 0;
  379                 wdc_c.timeout = 3000; /* 3s */
  380         } else if (drvp->drive_flags & DRIVE_ATAPI) {
  381                 wdc_c.r_command = ATAPI_IDENTIFY_DEVICE;
  382                 wdc_c.r_st_bmask = 0;
  383                 wdc_c.r_st_pmask = 0;
  384                 wdc_c.timeout = 10000; /* 10s */
  385         } else {
  386                 WDCDEBUG_PRINT(("ata_get_parms: no disks\n"),
  387                     DEBUG_FUNCS|DEBUG_PROBE);
  388                 return CMD_ERR;
  389         }
  390         wdc_c.flags = AT_READ | flags;
  391         wdc_c.data = tb;
  392         wdc_c.bcount = DEV_BSIZE;
  393         if (wdc_exec_command(drvp, &wdc_c) != WDC_COMPLETE) {
  394                 WDCDEBUG_PRINT(("ata_get_parms: wdc_exec_command failed\n"),
  395                     DEBUG_FUNCS|DEBUG_PROBE);
  396                 return CMD_AGAIN;
  397         }
  398         if (wdc_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {
  399                 WDCDEBUG_PRINT(("ata_get_parms: wdc_c.flags=0x%x\n",
  400                     wdc_c.flags), DEBUG_FUNCS|DEBUG_PROBE);
  401                 return CMD_ERR;
  402         } else {
  403                 /* if we didn't read any data something is wrong */
  404                 if ((wdc_c.flags & AT_XFDONE) == 0)
  405                         return CMD_ERR;
  406                 /* Read in parameter block. */
  407                 memcpy(prms, tb, sizeof(struct ataparams));
  408 #if BYTE_ORDER == LITTLE_ENDIAN
  409                 /*
  410                  * Shuffle string byte order.
  411                  * ATAPI Mitsumi and NEC drives don't need this.
  412                  */
  413                 if ((prms->atap_config & WDC_CFG_ATAPI_MASK) ==
  414                     WDC_CFG_ATAPI &&
  415                     ((prms->atap_model[0] == 'N' &&
  416                         prms->atap_model[1] == 'E') ||
  417                      (prms->atap_model[0] == 'F' &&
  418                          prms->atap_model[1] == 'X')))
  419                         return 0;
  420                 for (i = 0; i < sizeof(prms->atap_model); i += 2) {
  421                         p = (u_short *)(prms->atap_model + i);
  422                         *p = ntohs(*p);
  423                 }
  424                 for (i = 0; i < sizeof(prms->atap_serial); i += 2) {
  425                         p = (u_short *)(prms->atap_serial + i);
  426                         *p = ntohs(*p);
  427                 }
  428                 for (i = 0; i < sizeof(prms->atap_revision); i += 2) {
  429                         p = (u_short *)(prms->atap_revision + i);
  430                         *p = ntohs(*p);
  431                 }
  432 #endif
  433                 return CMD_OK;
  434         }
  435 }
  436 
  437 int
  438 ata_set_mode(struct ata_drive_datas *drvp, u_int8_t mode, u_int8_t flags)
  439 {
  440         struct wdc_command wdc_c;
  441 
  442         WDCDEBUG_PRINT(("ata_set_mode=0x%x\n", mode), DEBUG_FUNCS);
  443         memset(&wdc_c, 0, sizeof(struct wdc_command));
  444 
  445         wdc_c.r_command = SET_FEATURES;
  446         wdc_c.r_st_bmask = 0;
  447         wdc_c.r_st_pmask = 0;
  448         wdc_c.r_precomp = WDSF_SET_MODE;
  449         wdc_c.r_count = mode;
  450         wdc_c.flags = flags;
  451         wdc_c.timeout = 1000; /* 1s */
  452         if (wdc_exec_command(drvp, &wdc_c) != WDC_COMPLETE)
  453                 return CMD_AGAIN;
  454         if (wdc_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {
  455                 return CMD_ERR;
  456         }
  457         return CMD_OK;
  458 }
  459 
  460 void
  461 ata_dmaerr(struct ata_drive_datas *drvp, int flags)
  462 {
  463         /*
  464          * Downgrade decision: if we get NERRS_MAX in NXFER.
  465          * We start with n_dmaerrs set to NERRS_MAX-1 so that the
  466          * first error within the first NXFER ops will immediatly trigger
  467          * a downgrade.
  468          * If we got an error and n_xfers is bigger than NXFER reset counters.
  469          */
  470         drvp->n_dmaerrs++;
  471         if (drvp->n_dmaerrs >= NERRS_MAX && drvp->n_xfers <= NXFER) {
  472                 wdc_downgrade_mode(drvp, flags);
  473                 drvp->n_dmaerrs = NERRS_MAX-1;
  474                 drvp->n_xfers = 0;
  475                 return;
  476         }
  477         if (drvp->n_xfers > NXFER) {
  478                 drvp->n_dmaerrs = 1; /* just got an error */
  479                 drvp->n_xfers = 1; /* restart counting from this error */
  480         }
  481 }

Cache object: c6dd7c16485b69a11085cf91135eae4f


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