Annotation of sys/dev/ata/ata.c, Revision 1.1
1.1 ! nbrk 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: }
CVSweb