root/dev/ata/ata.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ata_get_params
  2. ata_set_mode
  3. ata_dmaerr
  4. ata_perror

    1 /*      $OpenBSD: ata.c,v 1.28 2007/04/08 14:20:26 pedro Exp $      */
    2 /*      $NetBSD: ata.c,v 1.9 1999/04/15 09:41:09 bouyer Exp $      */
    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/param.h>
   33 #include <sys/systm.h>
   34 #include <sys/kernel.h>
   35 #include <sys/file.h>
   36 #include <sys/stat.h>
   37 #include <sys/malloc.h>
   38 #include <sys/device.h>
   39 #include <sys/syslog.h>
   40 
   41 #include <machine/bus.h>
   42 
   43 #include <dev/ata/atareg.h>
   44 #include <dev/ata/atavar.h>
   45 #include <dev/ic/wdcreg.h>
   46 #include <dev/ic/wdcvar.h>
   47 
   48 #define DEBUG_FUNCS  0x08
   49 #define DEBUG_PROBE  0x10
   50 #ifdef WDCDEBUG
   51 extern int wdcdebug_mask; /* init'ed in wdc.c */
   52 #define WDCDEBUG_PRINT(args, level) do {        \
   53         if ((wdcdebug_mask & (level)) != 0)     \
   54                 printf args;                    \
   55 } while (0)
   56 #else
   57 #define WDCDEBUG_PRINT(args, level)
   58 #endif
   59 
   60 #define ATAPARAMS_SIZE 512
   61 
   62 /* Get the disk's parameters */
   63 int
   64 ata_get_params(struct ata_drive_datas *drvp, u_int8_t flags,
   65     struct ataparams *prms)
   66 {
   67         char tb[ATAPARAMS_SIZE];
   68         struct wdc_command wdc_c;
   69         int i;
   70         u_int16_t *p;
   71         int ret;
   72 
   73         WDCDEBUG_PRINT(("ata_get_parms\n"), DEBUG_FUNCS);
   74 
   75         bzero(tb, sizeof(tb));
   76         bzero(&wdc_c, sizeof(struct wdc_command));
   77 
   78         if (drvp->drive_flags & DRIVE_ATA) {
   79                 wdc_c.r_command = WDCC_IDENTIFY;
   80                 wdc_c.r_st_bmask = WDCS_DRDY;
   81                 wdc_c.r_st_pmask = 0;
   82                 wdc_c.timeout = 3000; /* 3s */
   83         } else if (drvp->drive_flags & DRIVE_ATAPI) {
   84                 wdc_c.r_command = ATAPI_IDENTIFY_DEVICE;
   85                 wdc_c.r_st_bmask = 0;
   86                 wdc_c.r_st_pmask = 0;
   87                 wdc_c.timeout = 10000; /* 10s */
   88         } else {
   89                 WDCDEBUG_PRINT(("wdc_ata_get_parms: no disks\n"),
   90                     DEBUG_FUNCS|DEBUG_PROBE);
   91                 return CMD_ERR;
   92         }
   93         wdc_c.flags = AT_READ | flags;
   94         wdc_c.data = tb;
   95         wdc_c.bcount = ATAPARAMS_SIZE;
   96 
   97         if ((ret = wdc_exec_command(drvp, &wdc_c)) != WDC_COMPLETE) {
   98                 WDCDEBUG_PRINT(("%s: wdc_exec_command failed: %d\n",
   99                     __func__, ret), DEBUG_PROBE);
  100                 return CMD_AGAIN;
  101         }
  102 
  103         if (wdc_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {
  104                 WDCDEBUG_PRINT(("%s: IDENTIFY failed: 0x%x\n", __func__,
  105                     wdc_c.flags), DEBUG_PROBE);
  106 
  107                 return CMD_ERR;
  108         } else {
  109 #if BYTE_ORDER == BIG_ENDIAN
  110                 /* All the fields in the params structure are 16-bit
  111                    integers except for the ID strings which are char
  112                    strings.  The 16-bit integers are currently in
  113                    memory in little-endian, regardless of architecture.
  114                    So, they need to be swapped on big-endian architectures
  115                    before they are accessed through the ataparams structure.
  116 
  117                    The swaps below avoid touching the char strings.
  118                 */
  119 
  120                 swap16_multi((u_int16_t *)tb, 10);
  121                 swap16_multi((u_int16_t *)tb + 20, 3);
  122                 swap16_multi((u_int16_t *)tb + 47, ATAPARAMS_SIZE / 2 - 47);
  123 #endif
  124                 /* Read in parameter block. */
  125                 bcopy(tb, prms, sizeof(struct ataparams));
  126 
  127                 /*
  128                  * Shuffle string byte order.
  129                  * ATAPI Mitsumi and NEC drives don't need this.
  130                  */
  131                 if ((prms->atap_config & WDC_CFG_ATAPI_MASK) ==
  132                     WDC_CFG_ATAPI &&
  133                     ((prms->atap_model[0] == 'N' &&
  134                         prms->atap_model[1] == 'E') ||
  135                      (prms->atap_model[0] == 'F' &&
  136                          prms->atap_model[1] == 'X')))
  137                         return CMD_OK;
  138                 for (i = 0; i < sizeof(prms->atap_model); i += 2) {
  139                         p = (u_short *)(prms->atap_model + i);
  140                         *p = swap16(*p);
  141                 }
  142                 for (i = 0; i < sizeof(prms->atap_serial); i += 2) {
  143                         p = (u_short *)(prms->atap_serial + i);
  144                         *p = swap16(*p);
  145                 }
  146                 for (i = 0; i < sizeof(prms->atap_revision); i += 2) {
  147                         p = (u_short *)(prms->atap_revision + i);
  148                         *p = swap16(*p);
  149                 }
  150 
  151                 return CMD_OK;
  152         }
  153 }
  154 
  155 int
  156 ata_set_mode(struct ata_drive_datas *drvp, u_int8_t mode, u_int8_t flags)
  157 {
  158         struct wdc_command wdc_c;
  159 
  160         WDCDEBUG_PRINT(("%s: mode=0x%x, flags=0x%x\n", __func__,
  161             mode, flags), DEBUG_PROBE);
  162 
  163         bzero(&wdc_c, sizeof(struct wdc_command));
  164 
  165         wdc_c.r_command = SET_FEATURES;
  166         wdc_c.r_st_bmask = 0;
  167         wdc_c.r_st_pmask = 0;
  168         wdc_c.r_precomp = WDSF_SET_MODE;
  169         wdc_c.r_count = mode;
  170         wdc_c.flags = flags;
  171         wdc_c.timeout = 1000; /* 1s */
  172         if (wdc_exec_command(drvp, &wdc_c) != WDC_COMPLETE)
  173                 return CMD_AGAIN;
  174 
  175         WDCDEBUG_PRINT(("%s: after wdc_exec_command() wdc_c.flags=0x%x\n",
  176             __func__, wdc_c.flags), DEBUG_PROBE);
  177 
  178         if (wdc_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {
  179                 return CMD_ERR;
  180         }
  181         return CMD_OK;
  182 }
  183 
  184 void
  185 ata_dmaerr(struct ata_drive_datas *drvp)
  186 {
  187         /*
  188          * Downgrade decision: if we get NERRS_MAX in NXFER.
  189          * We start with n_dmaerrs set to NERRS_MAX-1 so that the
  190          * first error within the first NXFER ops will immediately trigger
  191          * a downgrade.
  192          * If we got an error and n_xfers is bigger than NXFER reset counters.
  193          */
  194         drvp->n_dmaerrs++;
  195         if (drvp->n_dmaerrs >= NERRS_MAX && drvp->n_xfers <= NXFER) {
  196                 wdc_downgrade_mode(drvp);
  197                 drvp->n_dmaerrs = NERRS_MAX-1;
  198                 drvp->n_xfers = 0;
  199                 return;
  200         }
  201         if (drvp->n_xfers > NXFER) {
  202                 drvp->n_dmaerrs = 1; /* just got an error */
  203                 drvp->n_xfers = 1; /* restart counting from this error */
  204         }
  205 }
  206 
  207 void
  208 ata_perror(struct ata_drive_datas *drvp, int errno, char *buf, size_t buf_len)
  209 {
  210         static char *errstr0_3[] = {"address mark not found",
  211             "track 0 not found", "aborted command", "media change requested",
  212             "id not found", "media changed", "uncorrectable data error",
  213             "bad block detected"};
  214         static char *errstr4_5[] = {"",
  215             "no media/write protected", "aborted command",
  216             "media change requested", "id not found", "media changed",
  217             "uncorrectable data error", "interface CRC error"};
  218         char **errstr;
  219         int i;
  220         char *sep = "";
  221         size_t len = 0;
  222 
  223         if (drvp->ata_vers >= 4)
  224                 errstr = errstr4_5;
  225         else
  226                 errstr = errstr0_3;
  227 
  228         if (errno == 0) {
  229                 snprintf(buf, buf_len, "error not notified");
  230         }
  231 
  232         for (i = 0; i < 8; i++) {
  233                 if (errno & (1 << i)) {
  234                         snprintf(buf + len, buf_len - len, "%s%s", sep,
  235                             errstr[i]);
  236                         len = strlen(buf);
  237                         sep = ", ";
  238                 }
  239         }
  240 }

/* [<][>][^][v][top][bottom][index][help] */