1 /* $NetBSD: ata.c,v 1.14 2001/11/13 12:53:09 lukem Exp $ */ 2 /* 3 * Copyright (c) 1998 Manuel Bouyer. 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 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Manuel Bouyer. 16 * 4. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 __KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.14 2001/11/13 12:53:09 lukem Exp $"); 33 34 #ifndef WDCDEBUG 35 #define WDCDEBUG 36 #endif /* WDCDEBUG */ 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/kernel.h> 41 #include <sys/file.h> 42 #include <sys/stat.h> 43 #include <sys/malloc.h> 44 #include <sys/device.h> 45 #include <sys/syslog.h> 46 47 #include <dev/ic/wdcreg.h> 48 #include <dev/ata/atareg.h> 49 #include <dev/ata/atavar.h> 50 51 #define DEBUG_FUNCS 0x08 52 #define DEBUG_PROBE 0x10 53 #ifdef WDCDEBUG 54 extern int wdcdebug_mask; /* init'ed in wdc.c */ 55 #define WDCDEBUG_PRINT(args, level) \ 56 if (wdcdebug_mask & (level)) \ 57 printf args 58 #else 59 #define WDCDEBUG_PRINT(args, level) 60 #endif 61 62 /* Get the disk's parameters */ 63 int 64 ata_get_params(drvp, flags, prms) 65 struct ata_drive_datas *drvp; 66 u_int8_t flags; 67 struct ataparams *prms; 68 { 69 char tb[DEV_BSIZE]; 70 struct wdc_command wdc_c; 71 72 #if BYTE_ORDER == LITTLE_ENDIAN 73 int i; 74 u_int16_t *p; 75 #endif 76 77 WDCDEBUG_PRINT(("wdc_ata_get_parms\n"), DEBUG_FUNCS); 78 79 memset(tb, 0, DEV_BSIZE); 80 memset(prms, 0, sizeof(struct ataparams)); 81 memset(&wdc_c, 0, sizeof(struct wdc_command)); 82 83 if (drvp->drive_flags & DRIVE_ATA) { 84 wdc_c.r_command = WDCC_IDENTIFY; 85 wdc_c.r_st_bmask = WDCS_DRDY; 86 wdc_c.r_st_pmask = WDCS_DRQ; 87 wdc_c.timeout = 1000; /* 1s */ 88 } else if (drvp->drive_flags & DRIVE_ATAPI) { 89 wdc_c.r_command = ATAPI_IDENTIFY_DEVICE; 90 wdc_c.r_st_bmask = 0; 91 wdc_c.r_st_pmask = WDCS_DRQ; 92 wdc_c.timeout = 10000; /* 10s */ 93 } else { 94 WDCDEBUG_PRINT(("wdc_ata_get_parms: no disks\n"), 95 DEBUG_FUNCS|DEBUG_PROBE); 96 return CMD_ERR; 97 } 98 wdc_c.flags = AT_READ | flags; 99 wdc_c.data = tb; 100 wdc_c.bcount = DEV_BSIZE; 101 if (wdc_exec_command(drvp, &wdc_c) != WDC_COMPLETE) { 102 WDCDEBUG_PRINT(("wdc_ata_get_parms: wdc_exec_command failed\n"), 103 DEBUG_FUNCS|DEBUG_PROBE); 104 return CMD_AGAIN; 105 } 106 if (wdc_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) { 107 WDCDEBUG_PRINT(("wdc_ata_get_parms: wdc_c.flags=0x%x\n", 108 wdc_c.flags), DEBUG_FUNCS|DEBUG_PROBE); 109 return CMD_ERR; 110 } else { 111 /* Read in parameter block. */ 112 memcpy(prms, tb, sizeof(struct ataparams)); 113 #if BYTE_ORDER == LITTLE_ENDIAN 114 /* 115 * Shuffle string byte order. 116 * ATAPI Mitsumi and NEC drives don't need this. 117 */ 118 if ((prms->atap_config & WDC_CFG_ATAPI_MASK) == 119 WDC_CFG_ATAPI && 120 ((prms->atap_model[0] == 'N' && 121 prms->atap_model[1] == 'E') || 122 (prms->atap_model[0] == 'F' && 123 prms->atap_model[1] == 'X'))) 124 return 0; 125 for (i = 0; i < sizeof(prms->atap_model); i += 2) { 126 p = (u_short *)(prms->atap_model + i); 127 *p = ntohs(*p); 128 } 129 for (i = 0; i < sizeof(prms->atap_serial); i += 2) { 130 p = (u_short *)(prms->atap_serial + i); 131 *p = ntohs(*p); 132 } 133 for (i = 0; i < sizeof(prms->atap_revision); i += 2) { 134 p = (u_short *)(prms->atap_revision + i); 135 *p = ntohs(*p); 136 } 137 #endif 138 return CMD_OK; 139 } 140 } 141 142 int 143 ata_set_mode(drvp, mode, flags) 144 struct ata_drive_datas *drvp; 145 u_int8_t mode; 146 u_int8_t flags; 147 { 148 struct wdc_command wdc_c; 149 150 WDCDEBUG_PRINT(("wdc_ata_set_mode=0x%x\n", mode), DEBUG_FUNCS); 151 memset(&wdc_c, 0, sizeof(struct wdc_command)); 152 153 wdc_c.r_command = SET_FEATURES; 154 wdc_c.r_st_bmask = 0; 155 wdc_c.r_st_pmask = 0; 156 wdc_c.r_precomp = WDSF_SET_MODE; 157 wdc_c.r_count = mode; 158 wdc_c.flags = AT_READ | flags; 159 wdc_c.timeout = 1000; /* 1s */ 160 if (wdc_exec_command(drvp, &wdc_c) != WDC_COMPLETE) 161 return CMD_AGAIN; 162 if (wdc_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) { 163 return CMD_ERR; 164 } 165 return CMD_OK; 166 } 167 168 void 169 ata_dmaerr(drvp) 170 struct ata_drive_datas *drvp; 171 { 172 /* 173 * Downgrade decision: if we get NERRS_MAX in NXFER. 174 * We start with n_dmaerrs set to NERRS_MAX-1 so that the 175 * first error within the first NXFER ops will immediatly trigger 176 * a downgrade. 177 * If we got an error and n_xfers is bigger than NXFER reset counters. 178 */ 179 drvp->n_dmaerrs++; 180 if (drvp->n_dmaerrs >= NERRS_MAX && drvp->n_xfers <= NXFER) { 181 wdc_downgrade_mode(drvp); 182 drvp->n_dmaerrs = NERRS_MAX-1; 183 drvp->n_xfers = 0; 184 return; 185 } 186 if (drvp->n_xfers > NXFER) { 187 drvp->n_dmaerrs = 1; /* just got an error */ 188 drvp->n_xfers = 1; /* restart counting from this error */ 189 } 190 } 191 192 void 193 ata_perror(drvp, errno, buf) 194 struct ata_drive_datas *drvp; 195 int errno; 196 char *buf; 197 { 198 static char *errstr0_3[] = {"address mark not found", 199 "track 0 not found", "aborted command", "media change requested", 200 "id not found", "media changed", "uncorrectable data error", 201 "bad block detected"}; 202 static char *errstr4_5[] = {"obsolete (address mark not found)", 203 "no media/write protected", "aborted command", 204 "media change requested", "id not found", "media changed", 205 "uncorrectable data error", "interface CRC error"}; 206 char **errstr; 207 int i; 208 char *sep = ""; 209 210 if (drvp->ata_vers >= 4) 211 errstr = errstr4_5; 212 else 213 errstr = errstr0_3; 214 215 if (errno == 0) { 216 sprintf(buf, "error not notified"); 217 } 218 219 for (i = 0; i < 8; i++) { 220 if (errno & (1 << i)) { 221 buf += sprintf(buf, "%s%s", sep, errstr[i]); 222 sep = ", "; 223 } 224 } 225 } 226