[BACK]Return to atactl.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sbin / atactl

Annotation of src/sbin/atactl/atactl.c, Revision 1.76

1.76    ! mrg         1: /*     $NetBSD: atactl.c,v 1.75 2015/09/21 06:05:00 mrg Exp $  */
1.1       kenh        2:
                      3: /*-
                      4:  * Copyright (c) 1998 The NetBSD Foundation, Inc.
                      5:  * All rights reserved.
                      6:  *
                      7:  * This code is derived from software contributed to The NetBSD Foundation
                      8:  * by Ken Hornstein.
                      9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
                     18:  *
                     19:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     20:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     21:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     22:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     23:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     24:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     25:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     26:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     27:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     28:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     29:  * POSSIBILITY OF SUCH DAMAGE.
                     30:  */
                     31:
                     32: /*
1.4       jwise      33:  * atactl(8) - a program to control ATA devices.
1.1       kenh       34:  */
1.21      agc        35: #include <sys/cdefs.h>
                     36:
                     37: #ifndef lint
1.76    ! mrg        38: __RCSID("$NetBSD: atactl.c,v 1.75 2015/09/21 06:05:00 mrg Exp $");
1.21      agc        39: #endif
                     40:
1.1       kenh       41:
                     42: #include <sys/param.h>
                     43: #include <sys/ioctl.h>
                     44: #include <err.h>
                     45: #include <errno.h>
                     46: #include <fcntl.h>
1.68      riastrad   47: #include <pwd.h>
1.1       kenh       48: #include <stdio.h>
                     49: #include <stdlib.h>
                     50: #include <string.h>
                     51: #include <unistd.h>
                     52: #include <util.h>
                     53:
                     54: #include <dev/ata/atareg.h>
                     55: #include <sys/ataio.h>
                     56:
1.33      mycroft    57: struct ata_smart_error {
                     58:        struct {
1.63      jakllsch   59:                uint8_t device_control;
                     60:                uint8_t features;
                     61:                uint8_t sector_count;
                     62:                uint8_t sector_number;
                     63:                uint8_t cylinder_low;
                     64:                uint8_t cylinder_high;
                     65:                uint8_t device_head;
                     66:                uint8_t command;
                     67:                uint8_t timestamp[4];
1.33      mycroft    68:        } command[5];
                     69:        struct {
1.63      jakllsch   70:                uint8_t reserved;
                     71:                uint8_t error;
                     72:                uint8_t sector_count;
                     73:                uint8_t sector_number;
                     74:                uint8_t cylinder_low;
                     75:                uint8_t cylinder_high;
                     76:                uint8_t device_head;
                     77:                uint8_t status;
                     78:                uint8_t extended_error[19];
                     79:                uint8_t state;
                     80:                uint8_t lifetime[2];
1.33      mycroft    81:        } error_data;
1.49      perry      82: } __packed;
1.33      mycroft    83:
                     84: struct ata_smart_errorlog {
1.63      jakllsch   85:        uint8_t                 data_structure_revision;
                     86:        uint8_t                 mostrecenterror;
1.33      mycroft    87:        struct ata_smart_error  log_entries[5];
1.63      jakllsch   88:        uint16_t                device_error_count;
                     89:        uint8_t                 reserved[57];
                     90:        uint8_t                 checksum;
1.49      perry      91: } __packed;
1.33      mycroft    92:
1.1       kenh       93: struct command {
                     94:        const char *cmd_name;
1.5       soren      95:        const char *arg_names;
1.13      simonb     96:        void (*cmd_func)(int, char *[]);
1.1       kenh       97: };
                     98:
                     99: struct bitinfo {
                    100:        u_int bitmask;
                    101:        const char *string;
                    102: };
                    103:
1.60      joerg     104: __dead static void     usage(void);
                    105: static void    ata_command(struct atareq *);
1.64      jakllsch  106: static void    print_bitinfo(const char *, const char *, u_int,
                    107:     const struct bitinfo *);
                    108: static void    print_bitinfo2(const char *, const char *, u_int, u_int,
                    109:     const struct bitinfo *);
1.60      joerg     110: static void    print_smart_status(void *, void *);
1.62      jakllsch  111: static void    print_error_entry(int, const struct ata_smart_error *);
                    112: static void    print_selftest_entry(int, const struct ata_smart_selftest *);
1.60      joerg     113:
1.62      jakllsch  114: static void    print_error(const void *);
                    115: static void    print_selftest(const void *);
1.60      joerg     116:
1.66      jakllsch  117: static const struct ataparams *getataparams(void);
1.60      joerg     118:
                    119: static int     is_smart(void);
                    120:
                    121: static int     fd;                             /* file descriptor for device */
                    122: static const   char *dvname;                   /* device name */
                    123: static char    dvname_store[MAXPATHLEN];       /* for opendisk(3) */
                    124: static const   char *cmdname;                  /* command user issued */
                    125:
                    126: static void    device_identify(int, char *[]);
                    127: static void    device_setidle(int, char *[]);
                    128: static void    device_idle(int, char *[]);
                    129: static void    device_apm(int, char *[]);
                    130: static void    device_checkpower(int, char *[]);
                    131: static void    device_smart(int, char *[]);
                    132: static void    device_security(int, char *[]);
1.1       kenh      133:
1.62      jakllsch  134: static void    device_smart_temp(const struct ata_smart_attr *, uint64_t);
1.24      lha       135:
1.62      jakllsch  136: static const struct command device_commands[] = {
1.5       soren     137:        { "identify",   "",                     device_identify },
                    138:        { "setidle",    "idle-timer",           device_setidle },
1.48      christos  139:        { "apm",        "disable|set #",        device_apm },
1.5       soren     140:        { "setstandby", "standby-timer",        device_setidle },
                    141:        { "idle",       "",                     device_idle },
                    142:        { "standby",    "",                     device_idle },
                    143:        { "sleep",      "",                     device_idle },
                    144:        { "checkpower", "",                     device_checkpower },
1.64      jakllsch  145:        { "smart",
                    146:                "enable|disable|status|offline #|error-log|selftest-log",
1.34      soren     147:                                                device_smart },
1.68      riastrad  148:        { "security",
                    149:                "status|freeze|[setpass|unlock|disable|erase] [user|master]",
                    150:                                                device_security },
1.5       soren     151:        { NULL,         NULL,                   NULL },
1.1       kenh      152: };
                    153:
1.60      joerg     154: static void    bus_reset(int, char *[]);
1.30      bouyer    155:
1.62      jakllsch  156: static const struct command bus_commands[] = {
1.30      bouyer    157:        { "reset",      "",                     bus_reset },
                    158:        { NULL,         NULL,                   NULL },
                    159: };
                    160:
1.1       kenh      161: /*
                    162:  * Tables containing bitmasks used for error reporting and
                    163:  * device identification.
                    164:  */
                    165:
1.62      jakllsch  166: static const struct bitinfo ata_caps[] = {
1.23      yamt      167:        { WDC_CAP_DMA, "DMA" },
                    168:        { WDC_CAP_LBA, "LBA" },
1.1       kenh      169:        { ATA_CAP_STBY, "ATA standby timer values" },
                    170:        { WDC_CAP_IORDY, "IORDY operation" },
                    171:        { WDC_CAP_IORDY_DSBL, "IORDY disabling" },
1.22      fvdl      172:        { 0, NULL },
1.1       kenh      173: };
                    174:
1.62      jakllsch  175: static const struct bitinfo ata_vers[] = {
1.1       kenh      176:        { WDC_VER_ATA1, "ATA-1" },
                    177:        { WDC_VER_ATA2, "ATA-2" },
                    178:        { WDC_VER_ATA3, "ATA-3" },
                    179:        { WDC_VER_ATA4, "ATA-4" },
1.23      yamt      180:        { WDC_VER_ATA5, "ATA-5" },
                    181:        { WDC_VER_ATA6, "ATA-6" },
                    182:        { WDC_VER_ATA7, "ATA-7" },
1.67      drochner  183:        { WDC_VER_ATA8, "ATA-8" },
1.22      fvdl      184:        { 0, NULL },
1.1       kenh      185: };
                    186:
1.62      jakllsch  187: static const struct bitinfo ata_cmd_set1[] = {
1.1       kenh      188:        { WDC_CMD1_NOP, "NOP command" },
                    189:        { WDC_CMD1_RB, "READ BUFFER command" },
                    190:        { WDC_CMD1_WB, "WRITE BUFFER command" },
                    191:        { WDC_CMD1_HPA, "Host Protected Area feature set" },
                    192:        { WDC_CMD1_DVRST, "DEVICE RESET command" },
                    193:        { WDC_CMD1_SRV, "SERVICE interrupt" },
1.70      soren     194:        { WDC_CMD1_RLSE, "Release interrupt" },
                    195:        { WDC_CMD1_AHEAD, "Look-ahead" },
                    196:        { WDC_CMD1_CACHE, "Write cache" },
1.1       kenh      197:        { WDC_CMD1_PKT, "PACKET command feature set" },
                    198:        { WDC_CMD1_PM, "Power Management feature set" },
                    199:        { WDC_CMD1_REMOV, "Removable Media feature set" },
                    200:        { WDC_CMD1_SEC, "Security Mode feature set" },
                    201:        { WDC_CMD1_SMART, "SMART feature set" },
1.22      fvdl      202:        { 0, NULL },
1.1       kenh      203: };
                    204:
1.62      jakllsch  205: static const struct bitinfo ata_cmd_set2[] = {
1.23      yamt      206:        { ATA_CMD2_FCE, "FLUSH CACHE EXT command" },
                    207:        { WDC_CMD2_FC, "FLUSH CACHE command" },
                    208:        { WDC_CMD2_DCO, "Device Configuration Overlay feature set" },
                    209:        { ATA_CMD2_LBA48, "48-bit Address feature set" },
                    210:        { WDC_CMD2_AAM, "Automatic Acoustic Management feature set" },
1.28      wiz       211:        { WDC_CMD2_SM, "SET MAX security extension" },
1.23      yamt      212:        { WDC_CMD2_SFREQ, "SET FEATURES required to spin-up after power-up" },
                    213:        { WDC_CMD2_PUIS, "Power-Up In Standby feature set" },
1.1       kenh      214:        { WDC_CMD2_RMSN, "Removable Media Status Notification feature set" },
                    215:        { ATA_CMD2_APM, "Advanced Power Management feature set" },
                    216:        { ATA_CMD2_CFA, "CFA feature set" },
1.6       soren     217:        { ATA_CMD2_RWQ, "READ/WRITE DMA QUEUED commands" },
1.1       kenh      218:        { WDC_CMD2_DM, "DOWNLOAD MICROCODE command" },
1.22      fvdl      219:        { 0, NULL },
1.1       kenh      220: };
                    221:
1.62      jakllsch  222: static const struct bitinfo ata_cmd_ext[] = {
1.23      yamt      223:        { ATA_CMDE_TLCONT, "Time-limited R/W feature set R/W Continuous mode" },
                    224:        { ATA_CMDE_TL, "Time-limited Read/Write" },
                    225:        { ATA_CMDE_URGW, "URG bit for WRITE STREAM DMA/PIO" },
                    226:        { ATA_CMDE_URGR, "URG bit for READ STREAM DMA/PIO" },
1.55      jakllsch  227:        { ATA_CMDE_WWN, "World Wide Name" },
1.23      yamt      228:        { ATA_CMDE_WQFE, "WRITE DMA QUEUED FUA EXT command" },
                    229:        { ATA_CMDE_WFE, "WRITE DMA/MULTIPLE FUA EXT commands" },
                    230:        { ATA_CMDE_GPL, "General Purpose Logging feature set" },
                    231:        { ATA_CMDE_STREAM, "Streaming feature set" },
                    232:        { ATA_CMDE_MCPTC, "Media Card Pass Through Command feature set" },
                    233:        { ATA_CMDE_MS, "Media serial number" },
                    234:        { ATA_CMDE_SST, "SMART self-test" },
                    235:        { ATA_CMDE_SEL, "SMART error logging" },
                    236:        { 0, NULL },
                    237: };
                    238:
1.62      jakllsch  239: static const struct bitinfo ata_sata_caps[] = {
1.46      bouyer    240:        { SATA_SIGNAL_GEN1, "1.5Gb/s signaling" },
                    241:        { SATA_SIGNAL_GEN2, "3.0Gb/s signaling" },
1.69      jakllsch  242:        { SATA_SIGNAL_GEN3, "6.0Gb/s signaling" },
1.46      bouyer    243:        { SATA_NATIVE_CMDQ, "Native Command Queuing" },
                    244:        { SATA_HOST_PWR_MGMT, "Host-Initiated Interface Power Management" },
                    245:        { SATA_PHY_EVNT_CNT, "PHY Event Counters" },
                    246:        { 0, NULL },
                    247: };
                    248:
1.62      jakllsch  249: static const struct bitinfo ata_sata_feat[] = {
1.46      bouyer    250:        { SATA_NONZERO_OFFSETS, "Non-zero Offset DMA" },
                    251:        { SATA_DMA_SETUP_AUTO, "DMA Setup Auto Activate" },
                    252:        { SATA_DRIVE_PWR_MGMT, "Device-Initiated Interface Power Managment" },
                    253:        { SATA_IN_ORDER_DATA, "In-order Data Delivery" },
1.47      xtraeme   254:        { SATA_SW_STTNGS_PRS, "Software Settings Preservation" },
1.46      bouyer    255:        { 0, NULL },
                    256: };
                    257:
1.17      soren     258: static const struct {
                    259:        const int       id;
                    260:        const char      *name;
1.62      jakllsch  261:        void (*special)(const struct ata_smart_attr *, uint64_t);
1.17      soren     262: } smart_attrs[] = {
1.45      christos  263:        {   1,          "Raw read error rate", NULL },
                    264:        {   2,          "Throughput performance", NULL },
                    265:        {   3,          "Spin-up time", NULL },
                    266:        {   4,          "Start/stop count", NULL },
                    267:        {   5,          "Reallocated sector count", NULL },
                    268:        {   6,          "Read channel margin", NULL },
                    269:        {   7,          "Seek error rate", NULL },
                    270:        {   8,          "Seek time performance", NULL },
                    271:        {   9,          "Power-on hours count", NULL },
                    272:        {  10,          "Spin retry count", NULL },
                    273:        {  11,          "Calibration retry count", NULL },
                    274:        {  12,          "Device power cycle count", NULL },
1.52      dholland  275:        {  13,          "Soft read error rate", NULL },
1.74      mrg       276:        { 100,          "Erase/Program Cycles", NULL },
                    277:        { 103,          "Translation Table Rebuild", NULL },
                    278:        { 170,          "Reserved Block Count", NULL },
                    279:        { 171,          "Program Fail Count", NULL },
                    280:        { 172,          "Erase Fail Count", NULL },
                    281:        { 173,          "Wear Leveller Worst Case Erase Count", NULL },
                    282:        { 174,          "Unexpected Power Loss", NULL },
                    283:        { 175,          "Program Fail Count", NULL },
                    284:        { 176,          "Erase Fail Count", NULL },
                    285:        { 177,          "Wear Leveling Count", NULL },
                    286:        { 178,          "Used Reserved Block Count", NULL },
                    287:        { 179,          "Used Reserved Block Count", NULL },
                    288:        { 180,          "Unused Reserved Block Count", NULL },
                    289:        { 181,          "Program Fail Count", NULL },
                    290:        { 182,          "Erase Fail Count", NULL },
                    291:        { 183,          "SATA Downshift Error Count", NULL },
1.70      soren     292:        { 184,          "End-to-end error", NULL },
1.74      mrg       293:        { 185,          "Head Stability", NULL },
                    294:        { 186,          "Induced Op-Vibration Detection", NULL },
1.57      mrg       295:        { 187,          "Reported uncorrect", NULL },
1.74      mrg       296:        { 188,          "Command Timeout", NULL },
1.52      dholland  297:        { 189,          "High Fly Writes", NULL },
                    298:        { 190,          "Airflow Temperature",          device_smart_temp },
                    299:        { 191,          "G-sense error rate", NULL },
1.45      christos  300:        { 192,          "Power-off retract count", NULL },
                    301:        { 193,          "Load cycle count", NULL },
1.30      bouyer    302:        { 194,          "Temperature",                  device_smart_temp},
1.45      christos  303:        { 195,          "Hardware ECC Recovered", NULL },
                    304:        { 196,          "Reallocated event count", NULL },
                    305:        { 197,          "Current pending sector", NULL },
                    306:        { 198,          "Offline uncorrectable", NULL },
                    307:        { 199,          "Ultra DMA CRC error count", NULL },
                    308:        { 200,          "Write error rate", NULL },
                    309:        { 201,          "Soft read error rate", NULL },
                    310:        { 202,          "Data address mark errors", NULL },
                    311:        { 203,          "Run out cancel", NULL },
                    312:        { 204,          "Soft ECC correction", NULL },
                    313:        { 205,          "Thermal asperity check", NULL },
                    314:        { 206,          "Flying height", NULL },
                    315:        { 207,          "Spin high current", NULL },
                    316:        { 208,          "Spin buzz", NULL },
                    317:        { 209,          "Offline seek performance", NULL },
1.75      mrg       318:        { 210,          "Successful RAIN Recovery Count", NULL },
1.45      christos  319:        { 220,          "Disk shift", NULL },
                    320:        { 221,          "G-Sense error rate", NULL },
                    321:        { 222,          "Loaded hours", NULL },
                    322:        { 223,          "Load/unload retry count", NULL },
                    323:        { 224,          "Load friction", NULL },
                    324:        { 225,          "Load/unload cycle count", NULL },
                    325:        { 226,          "Load-in time", NULL },
                    326:        { 227,          "Torque amplification count", NULL },
                    327:        { 228,          "Power-off retract count", NULL },
                    328:        { 230,          "GMR head amplitude", NULL },
1.32      atatat    329:        { 231,          "Temperature",                  device_smart_temp },
1.70      soren     330:        { 232,          "Available reserved space", NULL },
                    331:        { 233,          "Media wearout indicator", NULL },
1.45      christos  332:        { 240,          "Head flying hours", NULL },
1.74      mrg       333:        { 241,          "Total LBAs Written", NULL },
                    334:        { 242,          "Total LBAs Read", NULL },
1.75      mrg       335:        { 246,          "Total Host Sector Writes", NULL },
1.76    ! mrg       336:        { 247,          "Host Program NAND Pages Count", NULL },
        !           337:        { 248,          "FTL Program Pages Count ", NULL },
1.45      christos  338:        { 250,          "Read error retry rate", NULL },
1.74      mrg       339:        { 254,          "Free Fall Sensor", NULL },
1.45      christos  340:        {   0,          "Unknown", NULL },
1.17      soren     341: };
                    342:
1.62      jakllsch  343: static const struct bitinfo ata_sec_st[] = {
1.38      drochner  344:        { WDC_SEC_SUPP,         "supported" },
                    345:        { WDC_SEC_EN,           "enabled" },
                    346:        { WDC_SEC_LOCKED,       "locked" },
                    347:        { WDC_SEC_FROZEN,       "frozen" },
                    348:        { WDC_SEC_EXP,          "expired" },
                    349:        { WDC_SEC_ESE_SUPP,     "enhanced erase support" },
                    350:        { WDC_SEC_LEV_MAX,      "maximum level" },
                    351:        { 0,                    NULL },
                    352: };
                    353:
1.1       kenh      354: int
1.13      simonb    355: main(int argc, char *argv[])
1.1       kenh      356: {
                    357:        int i;
1.62      jakllsch  358:        const struct command *commands = NULL;
1.1       kenh      359:
                    360:        /* Must have at least: device command */
                    361:        if (argc < 3)
                    362:                usage();
                    363:
                    364:        /* Skip program name, get and skip device name and command. */
                    365:        dvname = argv[1];
                    366:        cmdname = argv[2];
                    367:        argv += 3;
                    368:        argc -= 3;
                    369:
                    370:        /*
                    371:         * Open the device
                    372:         */
                    373:        fd = opendisk(dvname, O_RDWR, dvname_store, sizeof(dvname_store), 0);
                    374:        if (fd == -1) {
                    375:                if (errno == ENOENT) {
                    376:                        /*
                    377:                         * Device doesn't exist.  Probably trying to open
                    378:                         * a device which doesn't use disk semantics for
                    379:                         * device name.  Try again, specifying "cooked",
                    380:                         * which leaves off the "r" in front of the device's
                    381:                         * name.
                    382:                         */
                    383:                        fd = opendisk(dvname, O_RDWR, dvname_store,
                    384:                            sizeof(dvname_store), 1);
                    385:                        if (fd == -1)
                    386:                                err(1, "%s", dvname);
1.4       jwise     387:                } else
                    388:                        err(1, "%s", dvname);
1.1       kenh      389:        }
                    390:
                    391:        /*
                    392:         * Point the dvname at the actual device name that opendisk() opened.
                    393:         */
                    394:        dvname = dvname_store;
                    395:
                    396:        /* Look up and call the command. */
1.30      bouyer    397:        for (i = 0; device_commands[i].cmd_name != NULL; i++) {
                    398:                if (strcmp(cmdname, device_commands[i].cmd_name) == 0) {
                    399:                        commands = &device_commands[i];
1.1       kenh      400:                        break;
1.30      bouyer    401:                }
                    402:        }
                    403:        if (commands == NULL) {
                    404:                for (i = 0; bus_commands[i].cmd_name != NULL; i++) {
                    405:                        if (strcmp(cmdname, bus_commands[i].cmd_name) == 0) {
                    406:                                commands = &bus_commands[i];
                    407:                                break;
                    408:                        }
                    409:                }
                    410:        }
                    411:        if (commands == NULL)
1.12      ad        412:                errx(1, "unknown command: %s", cmdname);
1.1       kenh      413:
1.30      bouyer    414:        (*commands->cmd_func)(argc, argv);
1.1       kenh      415:        exit(0);
                    416: }
                    417:
1.60      joerg     418: static void
1.13      simonb    419: usage(void)
1.1       kenh      420: {
1.5       soren     421:        int i;
1.1       kenh      422:
1.27      jmmv      423:        fprintf(stderr, "usage: %s device command [arg [...]]\n",
1.11      cgd       424:            getprogname());
1.5       soren     425:
                    426:        fprintf(stderr, "   Available device commands:\n");
1.30      bouyer    427:        for (i=0; device_commands[i].cmd_name != NULL; i++)
                    428:                fprintf(stderr, "\t%s %s\n", device_commands[i].cmd_name,
                    429:                                            device_commands[i].arg_names);
                    430:
                    431:        fprintf(stderr, "   Available bus commands:\n");
                    432:        for (i=0; bus_commands[i].cmd_name != NULL; i++)
                    433:                fprintf(stderr, "\t%s %s\n", bus_commands[i].cmd_name,
                    434:                                            bus_commands[i].arg_names);
1.5       soren     435:
1.1       kenh      436:        exit(1);
                    437: }
                    438:
                    439: /*
                    440:  * Wrapper that calls ATAIOCCOMMAND and checks for errors
                    441:  */
                    442:
1.60      joerg     443: static void
1.13      simonb    444: ata_command(struct atareq *req)
1.1       kenh      445: {
                    446:        int error;
                    447:
                    448:        error = ioctl(fd, ATAIOCCOMMAND, req);
                    449:
                    450:        if (error == -1)
                    451:                err(1, "ATAIOCCOMMAND failed");
                    452:
                    453:        switch (req->retsts) {
                    454:
                    455:        case ATACMD_OK:
                    456:                return;
                    457:        case ATACMD_TIMEOUT:
                    458:                fprintf(stderr, "ATA command timed out\n");
                    459:                exit(1);
                    460:        case ATACMD_DF:
                    461:                fprintf(stderr, "ATA device returned a Device Fault\n");
                    462:                exit(1);
                    463:        case ATACMD_ERROR:
                    464:                if (req->error & WDCE_ABRT)
                    465:                        fprintf(stderr, "ATA device returned Aborted "
                    466:                                "Command\n");
                    467:                else
                    468:                        fprintf(stderr, "ATA device returned error register "
                    469:                                "%0x\n", req->error);
                    470:                exit(1);
                    471:        default:
                    472:                fprintf(stderr, "ATAIOCCOMMAND returned unknown result code "
                    473:                        "%d\n", req->retsts);
                    474:                exit(1);
                    475:        }
                    476: }
                    477:
                    478: /*
                    479:  * Print out strings associated with particular bitmasks
                    480:  */
                    481:
1.60      joerg     482: static void
1.64      jakllsch  483: print_bitinfo(const char *bf, const char *af, u_int bits,
                    484:     const struct bitinfo *binfo)
1.1       kenh      485: {
                    486:
1.22      fvdl      487:        for (; binfo->bitmask != 0; binfo++)
1.1       kenh      488:                if (bits & binfo->bitmask)
1.10      is        489:                        printf("%s%s%s", bf, binfo->string, af);
1.1       kenh      490: }
                    491:
1.60      joerg     492: static void
1.64      jakllsch  493: print_bitinfo2(const char *bf, const char *af, u_int bits, u_int enables,
                    494:     const struct bitinfo *binfo)
1.33      mycroft   495: {
                    496:
                    497:        for (; binfo->bitmask != 0; binfo++)
                    498:                if (bits & binfo->bitmask)
                    499:                        printf("%s%s (%s)%s", bf, binfo->string,
                    500:                            (enables & binfo->bitmask) ? "enabled" : "disabled",
                    501:                            af);
                    502: }
                    503:
1.24      lha       504:
                    505: /*
                    506:  * Try to print SMART temperature field
                    507:  */
                    508:
1.60      joerg     509: static void
1.62      jakllsch  510: device_smart_temp(const struct ata_smart_attr *attr, uint64_t raw_value)
1.24      lha       511: {
1.29      mycroft   512:        printf("%" PRIu8, attr->raw[0]);
1.24      lha       513:        if (attr->raw[0] != raw_value)
1.61      jakllsch  514:                printf(" Lifetime min/max %" PRIu8 "/%" PRIu8,
1.29      mycroft   515:                    attr->raw[2], attr->raw[4]);
1.24      lha       516: }
                    517:
                    518:
1.1       kenh      519: /*
1.15      soren     520:  * Print out SMART attribute thresholds and values
                    521:  */
                    522:
1.60      joerg     523: static void
1.15      soren     524: print_smart_status(void *vbuf, void *tbuf)
                    525: {
1.62      jakllsch  526:        const struct ata_smart_attributes *value_buf = vbuf;
                    527:        const struct ata_smart_thresholds *threshold_buf = tbuf;
                    528:        const struct ata_smart_attr *attr;
1.29      mycroft   529:        uint64_t raw_value;
1.24      lha       530:        int flags;
1.17      soren     531:        int i, j;
1.24      lha       532:        int aid;
1.63      jakllsch  533:        uint8_t checksum;
1.15      soren     534:
1.33      mycroft   535:        for (i = checksum = 0; i < 512; i++)
1.63      jakllsch  536:                checksum += ((const uint8_t *) value_buf)[i];
1.33      mycroft   537:        if (checksum != 0) {
1.15      soren     538:                fprintf(stderr, "SMART attribute values checksum error\n");
                    539:                return;
                    540:        }
                    541:
1.33      mycroft   542:        for (i = checksum = 0; i < 512; i++)
1.63      jakllsch  543:                checksum += ((const uint8_t *) threshold_buf)[i];
1.33      mycroft   544:        if (checksum != 0) {
1.15      soren     545:                fprintf(stderr, "SMART attribute thresholds checksum error\n");
                    546:                return;
                    547:        }
                    548:
1.64      jakllsch  549:        printf("id value thresh crit collect reliability description"
1.70      soren     550:            "                 raw\n");
1.24      lha       551:        for (i = 0; i < 256; i++) {
                    552:                int thresh = 0;
                    553:
                    554:                attr = NULL;
                    555:
                    556:                for (j = 0; j < 30; j++) {
                    557:                        if (value_buf->attributes[j].id == i)
                    558:                                attr = &value_buf->attributes[j];
                    559:                        if (threshold_buf->thresholds[j].id == i)
                    560:                                thresh = threshold_buf->thresholds[j].value;
1.31      atatat    561:                }
1.15      soren     562:
1.24      lha       563:                if (thresh && attr == NULL)
                    564:                        errx(1, "threshold but not attr %d", i);
                    565:                if (attr == NULL)
                    566:                        continue;
                    567:
                    568:                if (attr->value == 0||attr->value == 0xFE||attr->value == 0xFF)
                    569:                        continue;
                    570:
1.61      jakllsch  571:                for (aid = 0;
                    572:                     smart_attrs[aid].id != i && smart_attrs[aid].id != 0;
1.24      lha       573:                     aid++)
                    574:                        ;
                    575:
1.35      fvdl      576:                flags = le16toh(attr->flags);
1.24      lha       577:
1.70      soren     578:                printf("%3d %3d  %3d     %-3s %-7s %stive    %-27s ",
1.24      lha       579:                    i, attr->value, thresh,
                    580:                    flags & WDSM_ATTR_ADVISORY ? "yes" : "no",
                    581:                    flags & WDSM_ATTR_COLLECTIVE ? "online" : "offline",
                    582:                    attr->value > thresh ? "posi" : "nega",
                    583:                    smart_attrs[aid].name);
                    584:
                    585:                for (j = 0, raw_value = 0; j < 6; j++)
1.29      mycroft   586:                        raw_value += ((uint64_t)attr->raw[j]) << (8*j);
1.24      lha       587:
                    588:                if (smart_attrs[aid].special)
                    589:                        (*smart_attrs[aid].special)(attr, raw_value);
1.29      mycroft   590:                else
                    591:                        printf("%" PRIu64, raw_value);
1.24      lha       592:                printf("\n");
1.15      soren     593:        }
1.58      nisimura  594: }
1.24      lha       595:
1.62      jakllsch  596: static const struct {
1.24      lha       597:        int number;
                    598:        const char *name;
                    599: } selftest_name[] = {
                    600:        { 0, "Off-line" },
                    601:        { 1, "Short off-line" },
                    602:        { 2, "Extended off-line" },
                    603:        { 127, "Abort off-line test" },
                    604:        { 129, "Short captive" },
                    605:        { 130, "Extended captive" },
1.73      wiz       606:        { 256, "Unknown test" }, /* larger than uint8_t */
1.24      lha       607:        { 0, NULL }
                    608: };
                    609:
1.60      joerg     610: static const char *selftest_status[] = {
1.24      lha       611:        "No error",
                    612:        "Aborted by the host",
1.42      wiz       613:        "Interrupted by the host by reset",
1.24      lha       614:        "Fatal error or unknown test error",
                    615:        "Unknown test element failed",
                    616:        "Electrical test element failed",
                    617:        "The Servo (and/or seek) test element failed",
                    618:        "Read element of test failed",
                    619:        "Reserved",
                    620:        "Reserved",
                    621:        "Reserved",
                    622:        "Reserved",
                    623:        "Reserved",
                    624:        "Reserved",
                    625:        "Reserved",
                    626:        "Self-test in progress"
                    627: };
                    628:
1.60      joerg     629: static void
1.62      jakllsch  630: print_error_entry(int num, const struct ata_smart_error *le)
1.33      mycroft   631: {
                    632:        int i;
                    633:
                    634:        printf("Log entry: %d\n", num);
                    635:
                    636:        for (i = 0; i < 5; i++)
1.64      jakllsch  637:                printf("\tCommand %d: dc=%02x sf=%02x sc=%02x sn=%02x cl=%02x "
                    638:                    "ch=%02x dh=%02x cmd=%02x time=%02x%02x%02x%02x\n", i,
1.33      mycroft   639:                    le->command[i].device_control,
                    640:                    le->command[i].features,
                    641:                    le->command[i].sector_count,
                    642:                    le->command[i].sector_number,
                    643:                    le->command[i].cylinder_low,
                    644:                    le->command[i].cylinder_high,
                    645:                    le->command[i].device_head,
                    646:                    le->command[i].command,
                    647:                    le->command[i].timestamp[3],
                    648:                    le->command[i].timestamp[2],
                    649:                    le->command[i].timestamp[1],
                    650:                    le->command[i].timestamp[0]);
1.64      jakllsch  651:        printf("\tError: err=%02x sc=%02x sn=%02x cl=%02x ch=%02x dh=%02x "
                    652:            "status=%02x state=%02x lifetime=%02x%02x\n",
1.33      mycroft   653:            le->error_data.error,
                    654:            le->error_data.sector_count,
                    655:            le->error_data.sector_number,
                    656:            le->error_data.cylinder_low,
                    657:            le->error_data.cylinder_high,
                    658:            le->error_data.device_head,
                    659:            le->error_data.status,
                    660:            le->error_data.state,
                    661:            le->error_data.lifetime[1],
                    662:            le->error_data.lifetime[0]);
1.64      jakllsch  663:        printf("\tExtended: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x "
                    664:            "%02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
1.33      mycroft   665:            le->error_data.extended_error[0],
                    666:            le->error_data.extended_error[1],
                    667:            le->error_data.extended_error[2],
                    668:            le->error_data.extended_error[3],
                    669:            le->error_data.extended_error[4],
                    670:            le->error_data.extended_error[5],
                    671:            le->error_data.extended_error[6],
                    672:            le->error_data.extended_error[7],
                    673:            le->error_data.extended_error[8],
                    674:            le->error_data.extended_error[9],
                    675:            le->error_data.extended_error[10],
                    676:            le->error_data.extended_error[11],
                    677:            le->error_data.extended_error[12],
                    678:            le->error_data.extended_error[13],
                    679:            le->error_data.extended_error[14],
                    680:            le->error_data.extended_error[15],
                    681:            le->error_data.extended_error[15],
                    682:            le->error_data.extended_error[17],
                    683:            le->error_data.extended_error[18]);
                    684: }
                    685:
1.60      joerg     686: static void
1.62      jakllsch  687: print_error(const void *buf)
1.33      mycroft   688: {
1.62      jakllsch  689:        const struct ata_smart_errorlog *erlog = buf;
1.63      jakllsch  690:        uint8_t checksum;
1.33      mycroft   691:        int i;
                    692:
                    693:        for (i = checksum = 0; i < 512; i++)
1.63      jakllsch  694:                checksum += ((const uint8_t *) buf)[i];
1.33      mycroft   695:        if (checksum != 0) {
                    696:                fprintf(stderr, "SMART error log checksum error\n");
                    697:                return;
                    698:        }
                    699:
                    700:        if (erlog->data_structure_revision != 1) {
1.41      dbj       701:                fprintf(stderr, "Error log revision not 1 (found 0x%04x)\n",
                    702:                    erlog->data_structure_revision);
1.33      mycroft   703:                return;
                    704:        }
                    705:
                    706:        if (erlog->mostrecenterror == 0) {
                    707:                printf("No errors have been logged\n");
                    708:                return;
                    709:        }
1.61      jakllsch  710:
1.33      mycroft   711:        if (erlog->mostrecenterror > 5) {
                    712:                fprintf(stderr, "Most recent error is too large\n");
                    713:                return;
                    714:        }
1.61      jakllsch  715:
1.33      mycroft   716:        for (i = erlog->mostrecenterror; i < 5; i++)
                    717:                print_error_entry(i, &erlog->log_entries[i]);
                    718:        for (i = 0; i < erlog->mostrecenterror; i++)
                    719:                print_error_entry(i, &erlog->log_entries[i]);
                    720:        printf("device error count: %d\n", erlog->device_error_count);
                    721: }
                    722:
1.60      joerg     723: static void
1.62      jakllsch  724: print_selftest_entry(int num, const struct ata_smart_selftest *le)
1.24      lha       725: {
1.62      jakllsch  726:        const unsigned char *p;
1.53      lukem     727:        size_t i;
1.24      lha       728:
                    729:        /* check if all zero */
1.62      jakllsch  730:        for (p = (const void *)le, i = 0; i < sizeof(*le); i++)
1.24      lha       731:                if (p[i] != 0)
                    732:                        break;
                    733:        if (i == sizeof(*le))
                    734:                return;
                    735:
                    736:        printf("Log entry: %d\n", num);
                    737:
                    738:        /* Get test name */
                    739:        for (i = 0; selftest_name[i].name != NULL; i++)
                    740:                if (selftest_name[i].number == le->number)
                    741:                        break;
                    742:
1.33      mycroft   743:        if (selftest_name[i].name == NULL)
                    744:                printf("\tName: (%d)\n", le->number);
                    745:        else
                    746:                printf("\tName: %s\n", selftest_name[i].name);
1.24      lha       747:        printf("\tStatus: %s\n", selftest_status[le->status >> 4]);
1.33      mycroft   748:        /* XXX This generally should not be set when a self-test is completed,
                    749:           and at any rate is useless.  - mycroft */
1.24      lha       750:        if (le->status >> 4 == 15)
1.33      mycroft   751:                printf("\tPercent of test remaining: %1d0\n", le->status & 0xf);
                    752:        else if (le->status >> 4 != 0)
1.35      fvdl      753:                printf("\tLBA first error: %d\n", le32toh(le->lba_first_error));
1.24      lha       754: }
                    755:
1.60      joerg     756: static void
1.62      jakllsch  757: print_selftest(const void *buf)
1.24      lha       758: {
1.62      jakllsch  759:        const struct ata_smart_selftestlog *stlog = buf;
1.63      jakllsch  760:        uint8_t checksum;
1.24      lha       761:        int i;
                    762:
1.33      mycroft   763:        for (i = checksum = 0; i < 512; i++)
1.63      jakllsch  764:                checksum += ((const uint8_t *) buf)[i];
1.33      mycroft   765:        if (checksum != 0) {
1.24      lha       766:                fprintf(stderr, "SMART selftest log checksum error\n");
                    767:                return;
                    768:        }
                    769:
1.41      dbj       770:        if (le16toh(stlog->data_structure_revision) != 1) {
                    771:                fprintf(stderr, "Self-test log revision not 1 (found 0x%04x)\n",
                    772:                    le16toh(stlog->data_structure_revision));
1.24      lha       773:                return;
                    774:        }
                    775:
                    776:        if (stlog->mostrecenttest == 0) {
                    777:                printf("No self-tests have been logged\n");
                    778:                return;
                    779:        }
1.61      jakllsch  780:
1.24      lha       781:        if (stlog->mostrecenttest > 22) {
                    782:                fprintf(stderr, "Most recent test is too large\n");
                    783:                return;
                    784:        }
1.61      jakllsch  785:
1.24      lha       786:        for (i = stlog->mostrecenttest; i < 22; i++)
                    787:                print_selftest_entry(i, &stlog->log_entries[i]);
                    788:        for (i = 0; i < stlog->mostrecenttest; i++)
                    789:                print_selftest_entry(i, &stlog->log_entries[i]);
1.15      soren     790: }
                    791:
1.66      jakllsch  792: static const struct ataparams *
1.60      joerg     793: getataparams(void)
1.38      drochner  794: {
                    795:        struct atareq req;
                    796:        static union {
                    797:                unsigned char inbuf[DEV_BSIZE];
                    798:                struct ataparams inqbuf;
                    799:        } inbuf;
                    800:
                    801:        memset(&inbuf, 0, sizeof(inbuf));
                    802:        memset(&req, 0, sizeof(req));
                    803:
                    804:        req.flags = ATACMD_READ;
                    805:        req.command = WDCC_IDENTIFY;
1.56      jakllsch  806:        req.databuf = &inbuf;
1.38      drochner  807:        req.datalen = sizeof(inbuf);
                    808:        req.timeout = 1000;
                    809:
                    810:        ata_command(&req);
                    811:
                    812:        return (&inbuf.inqbuf);
                    813: }
                    814:
1.15      soren     815: /*
                    816:  * is_smart:
                    817:  *
                    818:  *     Detect whether device supports SMART and SMART is enabled.
                    819:  */
                    820:
1.60      joerg     821: static int
1.20      mycroft   822: is_smart(void)
1.15      soren     823: {
                    824:        int retval = 0;
1.66      jakllsch  825:        const struct ataparams *inqbuf;
1.39      christos  826:        const char *status;
1.15      soren     827:
1.38      drochner  828:        inqbuf = getataparams();
1.15      soren     829:
                    830:        if (inqbuf->atap_cmd_def != 0 && inqbuf->atap_cmd_def != 0xffff) {
                    831:                if (!(inqbuf->atap_cmd_set1 & WDC_CMD1_SMART)) {
                    832:                        fprintf(stderr, "SMART unsupported\n");
                    833:                } else {
                    834:                        if (inqbuf->atap_ata_major <= WDC_VER_ATA5 ||
                    835:                            inqbuf->atap_cmd_set2 == 0xffff ||
                    836:                            inqbuf->atap_cmd_set2 == 0x0000) {
                    837:                                status = "status unknown";
                    838:                                retval = 2;
                    839:                        } else {
1.18      mycroft   840:                                if (inqbuf->atap_cmd1_en & WDC_CMD1_SMART) {
1.15      soren     841:                                        status = "enabled";
                    842:                                        retval = 1;
                    843:                                } else {
                    844:                                        status = "disabled";
1.43      xtraeme   845:                                        retval = 3;
1.15      soren     846:                                }
                    847:                        }
1.20      mycroft   848:                        printf("SMART supported, SMART %s\n", status);
1.15      soren     849:                }
                    850:        }
                    851:        return retval;
                    852: }
1.51      dholland  853:
                    854: /*
                    855:  * extract_string: copy a block of bytes out of ataparams and make
                    856:  * a proper string out of it, truncating trailing spaces and preserving
                    857:  * strict typing. And also, not doing unaligned accesses.
                    858:  */
                    859: static void
                    860: extract_string(char *buf, size_t bufmax,
1.66      jakllsch  861:               const uint8_t *bytes, size_t numbytes,
1.51      dholland  862:               int needswap)
                    863: {
                    864:        unsigned i;
                    865:        size_t j;
                    866:        unsigned char ch1, ch2;
                    867:
                    868:        for (i = 0, j = 0; i < numbytes; i += 2) {
                    869:                ch1 = bytes[i];
                    870:                ch2 = bytes[i+1];
                    871:                if (needswap && j < bufmax-1) {
                    872:                        buf[j++] = ch2;
                    873:                }
                    874:                if (j < bufmax-1) {
                    875:                        buf[j++] = ch1;
                    876:                }
                    877:                if (!needswap && j < bufmax-1) {
                    878:                        buf[j++] = ch2;
                    879:                }
                    880:        }
                    881:        while (j > 0 && buf[j-1] == ' ') {
                    882:                j--;
                    883:        }
                    884:        buf[j] = '\0';
                    885: }
                    886:
1.68      riastrad  887: static void
                    888: compute_capacity(const struct ataparams *inqbuf, uint64_t *capacityp,
                    889:     uint64_t *sectorsp, uint32_t *secsizep)
                    890: {
                    891:        uint64_t capacity;
                    892:        uint64_t sectors;
                    893:        uint32_t secsize;
                    894:
                    895:        if (inqbuf->atap_cmd2_en != 0 && inqbuf->atap_cmd2_en != 0xffff &&
                    896:            inqbuf->atap_cmd2_en & ATA_CMD2_LBA48) {
                    897:                sectors =
                    898:                    ((uint64_t)inqbuf->atap_max_lba[3] << 48) |
                    899:                    ((uint64_t)inqbuf->atap_max_lba[2] << 32) |
                    900:                    ((uint64_t)inqbuf->atap_max_lba[1] << 16) |
                    901:                    ((uint64_t)inqbuf->atap_max_lba[0] <<  0);
                    902:        } else if (inqbuf->atap_capabilities1 & WDC_CAP_LBA) {
                    903:                sectors = (inqbuf->atap_capacity[1] << 16) |
                    904:                    inqbuf->atap_capacity[0];
                    905:        } else {
                    906:                sectors = inqbuf->atap_cylinders *
                    907:                    inqbuf->atap_heads * inqbuf->atap_sectors;
                    908:        }
                    909:
                    910:        secsize = 512;
                    911:
                    912:        if ((inqbuf->atap_secsz & ATA_SECSZ_VALID_MASK) == ATA_SECSZ_VALID) {
                    913:                if (inqbuf->atap_secsz & ATA_SECSZ_LLS) {
                    914:                        secsize = 2 *           /* words to bytes */
                    915:                            (inqbuf->atap_lls_secsz[1] << 16 |
                    916:                            inqbuf->atap_lls_secsz[0] <<  0);
                    917:                }
                    918:        }
                    919:
                    920:        capacity = sectors * secsize;
                    921:
                    922:        if (capacityp)
                    923:                *capacityp = capacity;
                    924:        if (sectorsp)
                    925:                *sectorsp = sectors;
                    926:        if (secsizep)
                    927:                *secsizep = secsize;
                    928: }
                    929:
1.15      soren     930: /*
1.1       kenh      931:  * DEVICE COMMANDS
                    932:  */
                    933:
                    934: /*
                    935:  * device_identify:
                    936:  *
                    937:  *     Display the identity of the device
                    938:  */
1.60      joerg     939: static void
1.13      simonb    940: device_identify(int argc, char *argv[])
1.1       kenh      941: {
1.66      jakllsch  942:        const struct ataparams *inqbuf;
1.54      mlelstv   943:        char model[sizeof(inqbuf->atap_model)+1];
                    944:        char revision[sizeof(inqbuf->atap_revision)+1];
                    945:        char serial[sizeof(inqbuf->atap_serial)+1];
1.56      jakllsch  946:        char hnum[12];
1.55      jakllsch  947:        uint64_t capacity;
1.56      jakllsch  948:        uint64_t sectors;
                    949:        uint32_t secsize;
                    950:        int lb_per_pb;
1.51      dholland  951:        int needswap = 0;
1.56      jakllsch  952:        int i;
                    953:        uint8_t checksum;
1.1       kenh      954:
                    955:        /* No arguments. */
                    956:        if (argc != 0)
1.5       soren     957:                usage();
1.1       kenh      958:
1.38      drochner  959:        inqbuf = getataparams();
1.1       kenh      960:
1.56      jakllsch  961:        if ((inqbuf->atap_integrity & WDC_INTEGRITY_MAGIC_MASK) ==
                    962:            WDC_INTEGRITY_MAGIC) {
                    963:                for (i = checksum = 0; i < 512; i++)
1.66      jakllsch  964:                        checksum += ((const uint8_t *)inqbuf)[i];
1.56      jakllsch  965:                if (checksum != 0)
                    966:                        puts("IDENTIFY DEVICE data checksum invalid\n");
                    967:        }
                    968:
1.1       kenh      969: #if BYTE_ORDER == LITTLE_ENDIAN
                    970:        /*
                    971:         * On little endian machines, we need to shuffle the string
                    972:         * byte order.  However, we don't have to do this for NEC or
                    973:         * Mitsumi ATAPI devices
                    974:         */
                    975:
1.72      drochner  976:        if (!(inqbuf->atap_config != WDC_CFG_CFA_MAGIC &&
                    977:              (inqbuf->atap_config & WDC_CFG_ATAPI) &&
1.1       kenh      978:              ((inqbuf->atap_model[0] == 'N' &&
                    979:                  inqbuf->atap_model[1] == 'E') ||
                    980:               (inqbuf->atap_model[0] == 'F' &&
                    981:                  inqbuf->atap_model[1] == 'X')))) {
1.51      dholland  982:                needswap = 1;
1.1       kenh      983:        }
                    984: #endif
                    985:
                    986:        /*
1.51      dholland  987:         * Copy the info strings out, stripping off blanks.
1.1       kenh      988:         */
1.51      dholland  989:        extract_string(model, sizeof(model),
                    990:                inqbuf->atap_model, sizeof(inqbuf->atap_model),
                    991:                needswap);
                    992:        extract_string(revision, sizeof(revision),
                    993:                inqbuf->atap_revision, sizeof(inqbuf->atap_revision),
                    994:                needswap);
                    995:        extract_string(serial, sizeof(serial),
                    996:                inqbuf->atap_serial, sizeof(inqbuf->atap_serial),
                    997:                needswap);
1.1       kenh      998:
1.51      dholland  999:        printf("Model: %s, Rev: %s, Serial #: %s\n",
                   1000:                model, revision, serial);
1.1       kenh     1001:
1.55      jakllsch 1002:        if (inqbuf->atap_cmd_ext != 0 && inqbuf->atap_cmd_ext != 0xffff &&
                   1003:            inqbuf->atap_cmd_ext & ATA_CMDE_WWN)
                   1004:                printf("World Wide Name: %016" PRIX64 "\n",
                   1005:                    ((uint64_t)inqbuf->atap_wwn[0] << 48) |
                   1006:                    ((uint64_t)inqbuf->atap_wwn[1] << 32) |
                   1007:                    ((uint64_t)inqbuf->atap_wwn[2] << 16) |
                   1008:                    ((uint64_t)inqbuf->atap_wwn[3] <<  0));
                   1009:
1.72      drochner 1010:        printf("Device type: %s",
                   1011:                inqbuf->atap_config == WDC_CFG_CFA_MAGIC ? "CF-ATA" :
                   1012:                 (inqbuf->atap_config & WDC_CFG_ATAPI ? "ATAPI" : "ATA"));
                   1013:        if (inqbuf->atap_config != WDC_CFG_CFA_MAGIC)
                   1014:                printf(", %s",
                   1015:                 inqbuf->atap_config & ATA_CFG_FIXED ? "fixed" : "removable");
                   1016:        printf("\n");
1.1       kenh     1017:
1.68      riastrad 1018:        compute_capacity(inqbuf, &capacity, &sectors, &secsize);
1.56      jakllsch 1019:
                   1020:        humanize_number(hnum, sizeof(hnum), capacity, "bytes",
                   1021:                HN_AUTOSCALE, HN_DIVISOR_1000);
                   1022:
1.61      jakllsch 1023:        printf("Capacity %s, %" PRIu64 " sectors, %" PRIu32 " bytes/sector\n",
1.56      jakllsch 1024:                       hnum, sectors, secsize);
                   1025:
                   1026:        printf("Cylinders: %d, heads: %d, sec/track: %d\n",
                   1027:                inqbuf->atap_cylinders, inqbuf->atap_heads,
                   1028:                inqbuf->atap_sectors);
1.61      jakllsch 1029:
1.56      jakllsch 1030:        lb_per_pb = 1;
                   1031:
                   1032:        if ((inqbuf->atap_secsz & ATA_SECSZ_VALID_MASK) == ATA_SECSZ_VALID) {
                   1033:                if (inqbuf->atap_secsz & ATA_SECSZ_LPS) {
                   1034:                        lb_per_pb <<= inqbuf->atap_secsz & ATA_SECSZ_LPS_SZMSK;
                   1035:                        printf("Physical sector size: %d bytes\n",
                   1036:                            lb_per_pb * secsize);
                   1037:                        if ((inqbuf->atap_logical_align &
                   1038:                            ATA_LA_VALID_MASK) == ATA_LA_VALID) {
                   1039:                                printf("First physically aligned sector: %d\n",
                   1040:                                    lb_per_pb - (inqbuf->atap_logical_align &
                   1041:                                        ATA_LA_MASK));
                   1042:                        }
                   1043:                }
1.55      jakllsch 1044:        }
1.1       kenh     1045:
1.55      jakllsch 1046:        if (((inqbuf->atap_sata_caps & SATA_NATIVE_CMDQ) ||
                   1047:            (inqbuf->atap_cmd_set2 & ATA_CMD2_RWQ)) &&
                   1048:            (inqbuf->atap_queuedepth & WDC_QUEUE_DEPTH_MASK))
1.56      jakllsch 1049:                printf("Command queue depth: %d\n",
1.55      jakllsch 1050:                    (inqbuf->atap_queuedepth & WDC_QUEUE_DEPTH_MASK) + 1);
1.1       kenh     1051:
                   1052:        printf("Device capabilities:\n");
1.10      is       1053:        print_bitinfo("\t", "\n", inqbuf->atap_capabilities1, ata_caps);
1.1       kenh     1054:
                   1055:        if (inqbuf->atap_ata_major != 0 && inqbuf->atap_ata_major != 0xffff) {
                   1056:                printf("Device supports following standards:\n");
1.10      is       1057:                print_bitinfo("", " ", inqbuf->atap_ata_major, ata_vers);
1.1       kenh     1058:                printf("\n");
                   1059:        }
                   1060:
                   1061:        if (inqbuf->atap_cmd_set1 != 0 && inqbuf->atap_cmd_set1 != 0xffff &&
                   1062:            inqbuf->atap_cmd_set2 != 0 && inqbuf->atap_cmd_set2 != 0xffff) {
                   1063:                printf("Command set support:\n");
1.33      mycroft  1064:                if (inqbuf->atap_cmd1_en != 0 && inqbuf->atap_cmd1_en != 0xffff)
                   1065:                        print_bitinfo2("\t", "\n", inqbuf->atap_cmd_set1,
                   1066:                            inqbuf->atap_cmd1_en, ata_cmd_set1);
                   1067:                else
                   1068:                        print_bitinfo("\t", "\n", inqbuf->atap_cmd_set1,
                   1069:                            ata_cmd_set1);
                   1070:                if (inqbuf->atap_cmd2_en != 0 && inqbuf->atap_cmd2_en != 0xffff)
                   1071:                        print_bitinfo2("\t", "\n", inqbuf->atap_cmd_set2,
                   1072:                            inqbuf->atap_cmd2_en, ata_cmd_set2);
                   1073:                else
                   1074:                        print_bitinfo("\t", "\n", inqbuf->atap_cmd_set2,
                   1075:                            ata_cmd_set2);
1.23      yamt     1076:                if (inqbuf->atap_cmd_ext != 0 && inqbuf->atap_cmd_ext != 0xffff)
                   1077:                        print_bitinfo("\t", "\n", inqbuf->atap_cmd_ext,
                   1078:                            ata_cmd_ext);
1.1       kenh     1079:        }
                   1080:
1.46      bouyer   1081:        if (inqbuf->atap_sata_caps != 0 && inqbuf->atap_sata_caps != 0xffff) {
                   1082:                printf("Serial ATA capabilities:\n");
1.55      jakllsch 1083:                print_bitinfo("\t", "\n",
                   1084:                    inqbuf->atap_sata_caps, ata_sata_caps);
                   1085:
1.46      bouyer   1086:        }
                   1087:
1.55      jakllsch 1088:        if (inqbuf->atap_sata_features_supp != 0 &&
                   1089:            inqbuf->atap_sata_features_supp != 0xffff) {
1.46      bouyer   1090:                printf("Serial ATA features:\n");
1.55      jakllsch 1091:                if (inqbuf->atap_sata_features_en != 0 &&
                   1092:                    inqbuf->atap_sata_features_en != 0xffff)
                   1093:                        print_bitinfo2("\t", "\n",
                   1094:                            inqbuf->atap_sata_features_supp,
                   1095:                            inqbuf->atap_sata_features_en, ata_sata_feat);
1.46      bouyer   1096:                else
1.55      jakllsch 1097:                        print_bitinfo("\t", "\n",
                   1098:                            inqbuf->atap_sata_features_supp, ata_sata_feat);
1.46      bouyer   1099:        }
                   1100:
1.71      soren    1101:        if ((inqbuf->atap_ata_major & WDC_VER_ATA7) &&
1.67      drochner 1102:            (inqbuf->support_dsm & ATA_SUPPORT_DSM_TRIM))
                   1103:                printf("TRIM supported\n");
                   1104:
1.1       kenh     1105:        return;
                   1106: }
                   1107:
                   1108: /*
                   1109:  * device idle:
                   1110:  *
                   1111:  * issue the IDLE IMMEDIATE command to the drive
                   1112:  */
1.60      joerg    1113: static void
1.13      simonb   1114: device_idle(int argc, char *argv[])
1.1       kenh     1115: {
                   1116:        struct atareq req;
                   1117:
                   1118:        /* No arguments. */
                   1119:        if (argc != 0)
1.5       soren    1120:                usage();
1.1       kenh     1121:
                   1122:        memset(&req, 0, sizeof(req));
                   1123:
                   1124:        if (strcmp(cmdname, "idle") == 0)
                   1125:                req.command = WDCC_IDLE_IMMED;
                   1126:        else if (strcmp(cmdname, "standby") == 0)
                   1127:                req.command = WDCC_STANDBY_IMMED;
                   1128:        else
                   1129:                req.command = WDCC_SLEEP;
                   1130:
                   1131:        req.timeout = 1000;
                   1132:
                   1133:        ata_command(&req);
                   1134:
                   1135:        return;
                   1136: }
                   1137:
                   1138: /*
1.48      christos 1139:  * device apm:
                   1140:  *
                   1141:  * enable/disable/control the APM feature of the drive
                   1142:  */
1.60      joerg    1143: static void
1.48      christos 1144: device_apm(int argc, char *argv[])
                   1145: {
                   1146:        struct atareq req;
                   1147:        long l;
                   1148:
                   1149:        memset(&req, 0, sizeof(req));
                   1150:        if (argc >= 1) {
                   1151:                req.command = SET_FEATURES;
                   1152:                req.timeout = 1000;
1.61      jakllsch 1153:
1.48      christos 1154:                if (strcmp(argv[0], "disable") == 0)
                   1155:                        req.features = WDSF_APM_DS;
                   1156:                else if (strcmp(argv[0], "set") == 0 && argc >= 2 &&
                   1157:                         (l = strtol(argv[1], NULL, 0)) >= 0 && l <= 253) {
1.61      jakllsch 1158:
1.48      christos 1159:                        req.features = WDSF_APM_EN;
                   1160:                        req.sec_count = l + 1;
                   1161:                } else
                   1162:                        usage();
                   1163:        } else
                   1164:                usage();
1.61      jakllsch 1165:
1.48      christos 1166:        ata_command(&req);
                   1167: }
1.61      jakllsch 1168:
1.48      christos 1169:
                   1170: /*
1.1       kenh     1171:  * Set the idle timer on the disk.  Set it for either idle mode or
                   1172:  * standby mode, depending on how we were invoked.
                   1173:  */
                   1174:
1.60      joerg    1175: static void
1.13      simonb   1176: device_setidle(int argc, char *argv[])
1.1       kenh     1177: {
                   1178:        unsigned long idle;
                   1179:        struct atareq req;
                   1180:        char *end;
                   1181:
                   1182:        /* Only one argument */
                   1183:        if (argc != 1)
1.5       soren    1184:                usage();
1.1       kenh     1185:
                   1186:        idle = strtoul(argv[0], &end, 0);
                   1187:
                   1188:        if (*end != '\0') {
                   1189:                fprintf(stderr, "Invalid idle time: \"%s\"\n", argv[0]);
                   1190:                exit(1);
                   1191:        }
                   1192:
                   1193:        if (idle > 19800) {
                   1194:                fprintf(stderr, "Idle time has a maximum value of 5.5 "
                   1195:                        "hours\n");
                   1196:                exit(1);
                   1197:        }
                   1198:
                   1199:        if (idle != 0 && idle < 5) {
                   1200:                fprintf(stderr, "Idle timer must be at least 5 seconds\n");
                   1201:                exit(1);
                   1202:        }
                   1203:
                   1204:        memset(&req, 0, sizeof(req));
                   1205:
                   1206:        if (idle <= 240*5)
                   1207:                req.sec_count = idle / 5;
                   1208:        else
                   1209:                req.sec_count = idle / (30*60) + 240;
                   1210:
                   1211:        req.command = cmdname[3] == 's' ? WDCC_STANDBY : WDCC_IDLE;
                   1212:        req.timeout = 1000;
                   1213:
                   1214:        ata_command(&req);
                   1215:
                   1216:        return;
1.3       kenh     1217: }
                   1218:
                   1219: /*
                   1220:  * Query the device for the current power mode
                   1221:  */
                   1222:
1.60      joerg    1223: static void
1.13      simonb   1224: device_checkpower(int argc, char *argv[])
1.3       kenh     1225: {
                   1226:        struct atareq req;
                   1227:
                   1228:        /* No arguments. */
                   1229:        if (argc != 0)
1.5       soren    1230:                usage();
1.3       kenh     1231:
                   1232:        memset(&req, 0, sizeof(req));
                   1233:
                   1234:        req.command = WDCC_CHECK_PWR;
                   1235:        req.timeout = 1000;
                   1236:        req.flags = ATACMD_READREG;
                   1237:
                   1238:        ata_command(&req);
                   1239:
                   1240:        printf("Current power status: ");
                   1241:
                   1242:        switch (req.sec_count) {
                   1243:        case 0x00:
                   1244:                printf("Standby mode\n");
                   1245:                break;
                   1246:        case 0x80:
                   1247:                printf("Idle mode\n");
                   1248:                break;
                   1249:        case 0xff:
                   1250:                printf("Active mode\n");
                   1251:                break;
                   1252:        default:
                   1253:                printf("Unknown power code (%02x)\n", req.sec_count);
                   1254:        }
                   1255:
1.15      soren    1256:        return;
                   1257: }
                   1258:
                   1259: /*
                   1260:  * device_smart:
                   1261:  *
                   1262:  *     Display SMART status
                   1263:  */
1.60      joerg    1264: static void
1.15      soren    1265: device_smart(int argc, char *argv[])
                   1266: {
                   1267:        struct atareq req;
                   1268:        unsigned char inbuf[DEV_BSIZE];
                   1269:        unsigned char inbuf2[DEV_BSIZE];
                   1270:
1.33      mycroft  1271:        if (argc < 1)
1.15      soren    1272:                usage();
                   1273:
                   1274:        if (strcmp(argv[0], "enable") == 0) {
1.20      mycroft  1275:                memset(&req, 0, sizeof(req));
1.15      soren    1276:
1.20      mycroft  1277:                req.features = WDSM_ENABLE_OPS;
                   1278:                req.command = WDCC_SMART;
1.35      fvdl     1279:                req.cylinder = WDSMART_CYL;
1.20      mycroft  1280:                req.timeout = 1000;
1.15      soren    1281:
1.20      mycroft  1282:                ata_command(&req);
1.15      soren    1283:
1.20      mycroft  1284:                is_smart();
1.15      soren    1285:        } else if (strcmp(argv[0], "disable") == 0) {
1.20      mycroft  1286:                memset(&req, 0, sizeof(req));
1.15      soren    1287:
1.20      mycroft  1288:                req.features = WDSM_DISABLE_OPS;
                   1289:                req.command = WDCC_SMART;
1.35      fvdl     1290:                req.cylinder = WDSMART_CYL;
1.20      mycroft  1291:                req.timeout = 1000;
1.15      soren    1292:
1.20      mycroft  1293:                ata_command(&req);
1.15      soren    1294:
1.20      mycroft  1295:                is_smart();
1.16      soren    1296:        } else if (strcmp(argv[0], "status") == 0) {
1.43      xtraeme  1297:                int rv;
                   1298:
                   1299:                rv = is_smart();
                   1300:
                   1301:                if (!rv) {
1.24      lha      1302:                        fprintf(stderr, "SMART not supported\n");
                   1303:                        return;
1.43      xtraeme  1304:                } else if (rv == 3)
                   1305:                        return;
1.24      lha      1306:
1.43      xtraeme  1307:                memset(&inbuf, 0, sizeof(inbuf));
                   1308:                memset(&req, 0, sizeof(req));
1.15      soren    1309:
1.43      xtraeme  1310:                req.features = WDSM_STATUS;
                   1311:                req.command = WDCC_SMART;
                   1312:                req.cylinder = WDSMART_CYL;
                   1313:                req.timeout = 1000;
1.61      jakllsch 1314:
1.43      xtraeme  1315:                ata_command(&req);
1.15      soren    1316:
1.43      xtraeme  1317:                if (req.cylinder != WDSMART_CYL) {
                   1318:                        fprintf(stderr, "Threshold exceeds condition\n");
                   1319:                }
1.15      soren    1320:
1.43      xtraeme  1321:                /* WDSM_RD_DATA and WDSM_RD_THRESHOLDS are optional
                   1322:                 * features, the following ata_command()'s may error
                   1323:                 * and exit().
                   1324:                 */
1.15      soren    1325:
1.43      xtraeme  1326:                memset(&inbuf, 0, sizeof(inbuf));
                   1327:                memset(&req, 0, sizeof(req));
1.15      soren    1328:
1.43      xtraeme  1329:                req.flags = ATACMD_READ;
                   1330:                req.features = WDSM_RD_DATA;
                   1331:                req.command = WDCC_SMART;
                   1332:                req.databuf = (caddr_t) inbuf;
                   1333:                req.datalen = sizeof(inbuf);
                   1334:                req.cylinder = WDSMART_CYL;
                   1335:                req.timeout = 1000;
1.61      jakllsch 1336:
1.43      xtraeme  1337:                ata_command(&req);
1.15      soren    1338:
1.43      xtraeme  1339:                memset(&inbuf2, 0, sizeof(inbuf2));
                   1340:                memset(&req, 0, sizeof(req));
1.15      soren    1341:
1.43      xtraeme  1342:                req.flags = ATACMD_READ;
                   1343:                req.features = WDSM_RD_THRESHOLDS;
                   1344:                req.command = WDCC_SMART;
                   1345:                req.databuf = (caddr_t) inbuf2;
                   1346:                req.datalen = sizeof(inbuf2);
                   1347:                req.cylinder = WDSMART_CYL;
                   1348:                req.timeout = 1000;
1.15      soren    1349:
1.43      xtraeme  1350:                ata_command(&req);
1.15      soren    1351:
1.43      xtraeme  1352:                print_smart_status(inbuf, inbuf2);
1.24      lha      1353:
1.33      mycroft  1354:        } else if (strcmp(argv[0], "offline") == 0) {
1.34      soren    1355:                if (argc != 2)
                   1356:                        usage();
1.33      mycroft  1357:                if (!is_smart()) {
                   1358:                        fprintf(stderr, "SMART not supported\n");
                   1359:                        return;
                   1360:                }
                   1361:
                   1362:                memset(&req, 0, sizeof(req));
                   1363:
                   1364:                req.features = WDSM_EXEC_OFFL_IMM;
                   1365:                req.command = WDCC_SMART;
1.35      fvdl     1366:                req.cylinder = WDSMART_CYL;
1.33      mycroft  1367:                req.sec_num = atol(argv[1]);
                   1368:                req.timeout = 10000;
                   1369:
                   1370:                ata_command(&req);
                   1371:        } else if (strcmp(argv[0], "error-log") == 0) {
                   1372:                if (!is_smart()) {
                   1373:                        fprintf(stderr, "SMART not supported\n");
                   1374:                        return;
                   1375:                }
                   1376:
                   1377:                memset(&inbuf, 0, sizeof(inbuf));
                   1378:                memset(&req, 0, sizeof(req));
1.61      jakllsch 1379:
1.33      mycroft  1380:                req.flags = ATACMD_READ;
                   1381:                req.features = WDSM_RD_LOG;
                   1382:                req.sec_count = 1;
                   1383:                req.sec_num = 1;
                   1384:                req.command = WDCC_SMART;
                   1385:                req.databuf = (caddr_t) inbuf;
                   1386:                req.datalen = sizeof(inbuf);
1.35      fvdl     1387:                req.cylinder = WDSMART_CYL;
1.33      mycroft  1388:                req.timeout = 1000;
1.61      jakllsch 1389:
1.33      mycroft  1390:                ata_command(&req);
1.61      jakllsch 1391:
1.33      mycroft  1392:                print_error(inbuf);
1.24      lha      1393:        } else if (strcmp(argv[0], "selftest-log") == 0) {
                   1394:                if (!is_smart()) {
1.15      soren    1395:                        fprintf(stderr, "SMART not supported\n");
1.24      lha      1396:                        return;
1.15      soren    1397:                }
1.24      lha      1398:
                   1399:                memset(&inbuf, 0, sizeof(inbuf));
                   1400:                memset(&req, 0, sizeof(req));
1.61      jakllsch 1401:
1.24      lha      1402:                req.flags = ATACMD_READ;
                   1403:                req.features = WDSM_RD_LOG;
                   1404:                req.sec_count = 1;
                   1405:                req.sec_num = 6;
                   1406:                req.command = WDCC_SMART;
                   1407:                req.databuf = (caddr_t) inbuf;
                   1408:                req.datalen = sizeof(inbuf);
1.35      fvdl     1409:                req.cylinder = WDSMART_CYL;
1.24      lha      1410:                req.timeout = 1000;
1.61      jakllsch 1411:
1.24      lha      1412:                ata_command(&req);
1.61      jakllsch 1413:
1.24      lha      1414:                print_selftest(inbuf);
                   1415:
1.15      soren    1416:        } else {
                   1417:                usage();
                   1418:        }
1.3       kenh     1419:        return;
1.1       kenh     1420: }
1.30      bouyer   1421:
1.60      joerg    1422: static void
1.38      drochner 1423: device_security(int argc, char *argv[])
                   1424: {
                   1425:        struct atareq req;
1.66      jakllsch 1426:        const struct ataparams *inqbuf;
1.68      riastrad 1427:        unsigned char data[DEV_BSIZE];
                   1428:        char *pass;
1.38      drochner 1429:
                   1430:        /* need subcommand */
                   1431:        if (argc < 1)
                   1432:                usage();
                   1433:
1.68      riastrad 1434:        memset(&req, 0, sizeof(req));
                   1435:        if (strcmp(argv[0], "status") == 0) {
                   1436:                inqbuf = getataparams();
                   1437:                print_bitinfo("\t", "\n", inqbuf->atap_sec_st, ata_sec_st);
                   1438:        } else if (strcmp(argv[0], "freeze") == 0) {
1.44      xtraeme  1439:                req.command = WDCC_SECURITY_FREEZE;
1.38      drochner 1440:                req.timeout = 1000;
                   1441:                ata_command(&req);
1.68      riastrad 1442:        } else if ((strcmp(argv[0], "setpass") == 0) ||
                   1443:            (strcmp(argv[0], "unlock") == 0) ||
                   1444:            (strcmp(argv[0], "disable") == 0) ||
                   1445:            (strcmp(argv[0], "erase") == 0)) {
                   1446:                if (argc != 2)
                   1447:                        usage();
                   1448:                if (strcmp(argv[1], "user") != 0) {
                   1449:                        if (strcmp(argv[1], "master") == 0) {
                   1450:                                fprintf(stderr,
                   1451:                                    "Master passwords not supported\n");
                   1452:                                exit(1);
                   1453:                        } else {
                   1454:                                usage();
                   1455:                        }
                   1456:                }
                   1457:
                   1458:                pass = getpass("Password:");
                   1459:                if (strlen(pass) > 32) {
                   1460:                        fprintf(stderr, "Password must be <=32 characters\n");
                   1461:                        exit(1);
                   1462:                }
                   1463:
                   1464:                req.flags |= ATACMD_WRITE;
                   1465:                req.timeout = 1000;
                   1466:                req.databuf = data;
                   1467:                req.datalen = sizeof(data);
                   1468:                memset(data, 0, sizeof(data));
                   1469:                strlcpy((void *)&data[2], pass, 32 + 1);
                   1470:
                   1471:                if (strcmp(argv[0], "setpass") == 0) {
                   1472:                        char orig[32 + 1];
                   1473:                        strlcpy(orig, pass, 32 + 1);
                   1474:                        pass = getpass("Confirm password:");
                   1475:                        if (0 != strcmp(orig, pass)) {
                   1476:                                fprintf(stderr, "Passwords do not match\n");
                   1477:                                exit(1);
                   1478:                        }
                   1479:                        req.command = WDCC_SECURITY_SET_PASSWORD;
                   1480:                } else if (strcmp(argv[0], "unlock") == 0) {
                   1481:                        req.command = WDCC_SECURITY_UNLOCK;
                   1482:                } else if (strcmp(argv[0], "disable") == 0) {
                   1483:                        req.command = WDCC_SECURITY_DISABLE_PASSWORD;
                   1484:                } else if (strcmp(argv[0], "erase") == 0) {
                   1485:                        struct atareq prepare;
                   1486:
                   1487:                        inqbuf = getataparams();
                   1488:
                   1489:                        /*
                   1490:                         * XXX Any way to lock the device to make sure
                   1491:                         * this really is the command preceding the
                   1492:                         * SECURITY ERASE UNIT command?  This would
                   1493:                         * probably have to be moved into the kernel to
                   1494:                         * do that.
                   1495:                         */
                   1496:                        memset(&prepare, 0, sizeof(prepare));
                   1497:                        prepare.command = WDCC_SECURITY_ERASE_PREPARE;
                   1498:                        prepare.timeout = 1000;
                   1499:                        ata_command(&prepare);
                   1500:
                   1501:                        req.command = WDCC_SECURITY_ERASE_UNIT;
                   1502:
                   1503:                        /*
                   1504:                         * Enable enhanced erase if it's supported.
                   1505:                         *
                   1506:                         * XXX should be a command-line option
                   1507:                         */
                   1508:                        if (inqbuf->atap_sec_st & WDC_SEC_ESE_SUPP) {
                   1509:                                data[0] |= 0x2;
                   1510:                                req.timeout = (inqbuf->atap_eseu_time & 0xff)
                   1511:                                    * 2 * 60 * 1000;
                   1512:                        } else {
                   1513:                                req.timeout = (inqbuf->atap_seu_time & 0xff)
                   1514:                                    * 2 * 60 * 1000;
                   1515:                        }
                   1516:
                   1517:                        /*
                   1518:                         * If the estimated time was 0xff (* 2 * 60 *
                   1519:                         * 1000 = 30600000), that means `>508 minutes'.
                   1520:                         * Estimate that we can handle 16 MB/sec, a
                   1521:                         * rate I just pulled out of my arse.
                   1522:                         */
                   1523:                        if (req.timeout == 30600000) {
                   1524:                                uint64_t bytes, timeout;
                   1525:                                compute_capacity(inqbuf, &bytes, NULL, NULL);
                   1526:                                timeout = (bytes / (16 * 1024 * 1024)) * 1000;
                   1527:                                if (timeout > (uint64_t)INT_MAX)
                   1528:                                        req.timeout = INT_MAX;
                   1529:                                else
                   1530:                                        req.timeout = timeout;
                   1531:                        }
                   1532:
                   1533:                        printf("Erasing may take up to %dh %dm %ds...\n",
                   1534:                            (req.timeout / 1000 / 60) / 60,
                   1535:                            (req.timeout / 1000 / 60) % 60,
                   1536:                            req.timeout % 60);
                   1537:                } else {
                   1538:                        abort();
                   1539:                }
                   1540:
                   1541:                ata_command(&req);
                   1542:        } else {
1.38      drochner 1543:                usage();
1.68      riastrad 1544:        }
1.38      drochner 1545: }
                   1546:
1.30      bouyer   1547: /*
                   1548:  * bus_reset:
                   1549:  *     Reset an ATA bus (will reset all devices on the bus)
                   1550:  */
1.60      joerg    1551: static void
1.30      bouyer   1552: bus_reset(int argc, char *argv[])
                   1553: {
                   1554:        int error;
                   1555:
                   1556:        /* no args */
                   1557:        if (argc != 0)
                   1558:                usage();
                   1559:
                   1560:        error = ioctl(fd, ATABUSIORESET, NULL);
                   1561:
                   1562:        if (error == -1)
                   1563:                err(1, "ATABUSIORESET failed");
                   1564: }

CVSweb <webmaster@jp.NetBSD.org>