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