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