Home | History | Annotate | Line # | Download | only in atactl
      1  1.86  jakllsch /*	$NetBSD: atactl.c,v 1.86 2025/02/23 15:00:53 jakllsch Exp $	*/
      2   1.1      kenh 
      3   1.1      kenh /*-
      4  1.82       mrg  * Copyright (c) 1998, 2019 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.82       mrg  * by Ken Hornstein and Matthew R. Green.
      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.86  jakllsch __RCSID("$NetBSD: atactl.c,v 1.86 2025/02/23 15:00:53 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.68  riastrad #include <pwd.h>
     48   1.1      kenh #include <stdio.h>
     49   1.1      kenh #include <stdlib.h>
     50   1.1      kenh #include <string.h>
     51   1.1      kenh #include <unistd.h>
     52   1.1      kenh #include <util.h>
     53   1.1      kenh 
     54   1.1      kenh #include <dev/ata/atareg.h>
     55   1.1      kenh #include <sys/ataio.h>
     56   1.1      kenh 
     57  1.83   mlelstv #include <dev/scsipi/scsi_spc.h>
     58  1.83   mlelstv #include <sys/scsiio.h>
     59  1.83   mlelstv 
     60  1.33   mycroft struct ata_smart_error {
     61  1.33   mycroft 	struct {
     62  1.63  jakllsch 		uint8_t device_control;
     63  1.63  jakllsch 		uint8_t features;
     64  1.63  jakllsch 		uint8_t sector_count;
     65  1.63  jakllsch 		uint8_t sector_number;
     66  1.63  jakllsch 		uint8_t cylinder_low;
     67  1.63  jakllsch 		uint8_t cylinder_high;
     68  1.63  jakllsch 		uint8_t device_head;
     69  1.63  jakllsch 		uint8_t command;
     70  1.63  jakllsch 		uint8_t timestamp[4];
     71  1.33   mycroft 	} command[5];
     72  1.33   mycroft 	struct {
     73  1.63  jakllsch 		uint8_t reserved;
     74  1.63  jakllsch 		uint8_t error;
     75  1.63  jakllsch 		uint8_t sector_count;
     76  1.63  jakllsch 		uint8_t sector_number;
     77  1.63  jakllsch 		uint8_t cylinder_low;
     78  1.63  jakllsch 		uint8_t cylinder_high;
     79  1.63  jakllsch 		uint8_t device_head;
     80  1.63  jakllsch 		uint8_t status;
     81  1.63  jakllsch 		uint8_t extended_error[19];
     82  1.63  jakllsch 		uint8_t state;
     83  1.63  jakllsch 		uint8_t lifetime[2];
     84  1.33   mycroft 	} error_data;
     85  1.49     perry } __packed;
     86  1.33   mycroft 
     87  1.33   mycroft struct ata_smart_errorlog {
     88  1.63  jakllsch 	uint8_t			data_structure_revision;
     89  1.63  jakllsch 	uint8_t			mostrecenterror;
     90  1.33   mycroft 	struct ata_smart_error	log_entries[5];
     91  1.63  jakllsch 	uint16_t		device_error_count;
     92  1.63  jakllsch 	uint8_t			reserved[57];
     93  1.63  jakllsch 	uint8_t			checksum;
     94  1.49     perry } __packed;
     95  1.33   mycroft 
     96  1.83   mlelstv #define SCSI_ATA_PASS_THROUGH_16	0x85
     97  1.83   mlelstv struct scsi_ata_pass_through_16 {
     98  1.83   mlelstv 	uint8_t			opcode;
     99  1.83   mlelstv 	uint8_t			byte2;
    100  1.83   mlelstv #define SATL_NODATA	0x06
    101  1.83   mlelstv #define SATL_PIO_IN	0x08
    102  1.83   mlelstv #define SATL_PIO_OUT	0x0a
    103  1.83   mlelstv #define	SATL_EXTEND	0x01
    104  1.83   mlelstv 	uint8_t			byte3;
    105  1.83   mlelstv #define SATL_CKCOND	0x20
    106  1.83   mlelstv #define SATL_READ	0x08
    107  1.83   mlelstv #define SATL_BLOCKS	0x04
    108  1.83   mlelstv #define SATL_LEN(x)	((x) & 0x03)
    109  1.83   mlelstv 	uint8_t			features[2];
    110  1.83   mlelstv 	uint8_t			sector_count[2];
    111  1.83   mlelstv 	uint8_t			lba[6];
    112  1.83   mlelstv 	uint8_t			device;
    113  1.83   mlelstv 	uint8_t			ata_cmd;
    114  1.83   mlelstv 	uint8_t			control;
    115  1.83   mlelstv } __packed;
    116  1.83   mlelstv 
    117  1.83   mlelstv #define SCSI_ATA_PASS_THROUGH_12	0xa1
    118  1.83   mlelstv struct scsi_ata_pass_through_12 {
    119  1.83   mlelstv 	uint8_t			opcode;
    120  1.83   mlelstv 	uint8_t			byte2;
    121  1.83   mlelstv 	uint8_t			byte3;
    122  1.83   mlelstv 	uint8_t			features[1];
    123  1.83   mlelstv 	uint8_t			sector_count[1];
    124  1.83   mlelstv 	uint8_t			lba[3];
    125  1.83   mlelstv 	uint8_t			device;
    126  1.83   mlelstv 	uint8_t			ata_cmd;
    127  1.83   mlelstv 	uint8_t			reserved;
    128  1.83   mlelstv 	uint8_t			control;
    129  1.83   mlelstv } __packed;
    130  1.83   mlelstv 
    131  1.83   mlelstv struct scsi_ata_return_descriptor {
    132  1.83   mlelstv 	uint8_t			descr;
    133  1.83   mlelstv #define SCSI_ATA_RETURN_DESCRIPTOR	9
    134  1.83   mlelstv 	uint8_t			additional_length;
    135  1.83   mlelstv 	uint8_t			extend;
    136  1.83   mlelstv 	uint8_t			error;
    137  1.83   mlelstv 	uint8_t			sector_count[2];
    138  1.83   mlelstv 	uint8_t			lba[6];
    139  1.83   mlelstv 	uint8_t			device;
    140  1.83   mlelstv 	uint8_t			status;
    141  1.83   mlelstv } __packed;
    142  1.83   mlelstv 
    143   1.1      kenh struct command {
    144   1.1      kenh 	const char *cmd_name;
    145   1.5     soren 	const char *arg_names;
    146  1.13    simonb 	void (*cmd_func)(int, char *[]);
    147   1.1      kenh };
    148   1.1      kenh 
    149   1.1      kenh struct bitinfo {
    150   1.1      kenh 	u_int bitmask;
    151   1.1      kenh 	const char *string;
    152   1.1      kenh };
    153   1.1      kenh 
    154  1.60     joerg __dead static void	usage(void);
    155  1.60     joerg static void	ata_command(struct atareq *);
    156  1.83   mlelstv static int	satl_command(struct atareq *, int);
    157  1.83   mlelstv static const uint8_t *satl_return_desc(const uint8_t *, size_t, uint8_t);
    158  1.64  jakllsch static void	print_bitinfo(const char *, const char *, u_int,
    159  1.64  jakllsch     const struct bitinfo *);
    160  1.64  jakllsch static void	print_bitinfo2(const char *, const char *, u_int, u_int,
    161  1.64  jakllsch     const struct bitinfo *);
    162  1.78       mrg static void	print_smart_status(void *, void *, const char *);
    163  1.62  jakllsch static void	print_error_entry(int, const struct ata_smart_error *);
    164  1.62  jakllsch static void	print_selftest_entry(int, const struct ata_smart_selftest *);
    165  1.60     joerg 
    166  1.62  jakllsch static void	print_error(const void *);
    167  1.62  jakllsch static void	print_selftest(const void *);
    168  1.60     joerg 
    169  1.79       mrg static void	fillataparams(void);
    170  1.60     joerg 
    171  1.60     joerg static int	is_smart(void);
    172  1.60     joerg 
    173  1.60     joerg static int	fd;				/* file descriptor for device */
    174  1.83   mlelstv static int	use_satl;			/* tunnel through SATL */
    175  1.60     joerg static const	char *dvname;			/* device name */
    176  1.60     joerg static char	dvname_store[MAXPATHLEN];	/* for opendisk(3) */
    177  1.60     joerg static const	char *cmdname;			/* command user issued */
    178  1.79       mrg static const	struct ataparams *inqbuf;	/* inquiry buffer */
    179  1.79       mrg static char	model[sizeof(inqbuf->atap_model)+1];
    180  1.79       mrg static char	revision[sizeof(inqbuf->atap_revision)+1];
    181  1.79       mrg static char	serial[sizeof(inqbuf->atap_serial)+1];
    182  1.60     joerg 
    183  1.60     joerg static void	device_identify(int, char *[]);
    184  1.60     joerg static void	device_setidle(int, char *[]);
    185  1.60     joerg static void	device_idle(int, char *[]);
    186  1.60     joerg static void	device_apm(int, char *[]);
    187  1.60     joerg static void	device_checkpower(int, char *[]);
    188  1.60     joerg static void	device_smart(int, char *[]);
    189  1.60     joerg static void	device_security(int, char *[]);
    190   1.1      kenh 
    191  1.62  jakllsch static void	device_smart_temp(const struct ata_smart_attr *, uint64_t);
    192  1.24       lha 
    193  1.62  jakllsch static const struct command device_commands[] = {
    194   1.5     soren 	{ "identify",	"",			device_identify },
    195   1.5     soren 	{ "setidle",	"idle-timer",		device_setidle },
    196  1.48  christos 	{ "apm",	"disable|set #",	device_apm },
    197   1.5     soren 	{ "setstandby",	"standby-timer",	device_setidle },
    198   1.5     soren 	{ "idle",	"",			device_idle },
    199   1.5     soren 	{ "standby",	"",			device_idle },
    200   1.5     soren 	{ "sleep",	"",			device_idle },
    201   1.5     soren 	{ "checkpower",	"",			device_checkpower },
    202  1.64  jakllsch 	{ "smart",
    203  1.78       mrg 		"enable|disable|status [vendor]|offline #|error-log|selftest-log",
    204  1.34     soren 						device_smart },
    205  1.68  riastrad 	{ "security",
    206  1.68  riastrad 		"status|freeze|[setpass|unlock|disable|erase] [user|master]",
    207  1.68  riastrad 						device_security },
    208   1.5     soren 	{ NULL,		NULL,			NULL },
    209   1.1      kenh };
    210   1.1      kenh 
    211  1.60     joerg static void	bus_reset(int, char *[]);
    212  1.30    bouyer 
    213  1.62  jakllsch static const struct command bus_commands[] = {
    214  1.30    bouyer 	{ "reset",	"",			bus_reset },
    215  1.30    bouyer 	{ NULL,		NULL,			NULL },
    216  1.30    bouyer };
    217  1.30    bouyer 
    218   1.1      kenh /*
    219   1.1      kenh  * Tables containing bitmasks used for error reporting and
    220   1.1      kenh  * device identification.
    221   1.1      kenh  */
    222   1.1      kenh 
    223  1.62  jakllsch static const struct bitinfo ata_caps[] = {
    224  1.23      yamt 	{ WDC_CAP_DMA, "DMA" },
    225  1.23      yamt 	{ WDC_CAP_LBA, "LBA" },
    226   1.1      kenh 	{ ATA_CAP_STBY, "ATA standby timer values" },
    227   1.1      kenh 	{ WDC_CAP_IORDY, "IORDY operation" },
    228   1.1      kenh 	{ WDC_CAP_IORDY_DSBL, "IORDY disabling" },
    229  1.22      fvdl 	{ 0, NULL },
    230   1.1      kenh };
    231   1.1      kenh 
    232  1.62  jakllsch static const struct bitinfo ata_vers[] = {
    233   1.1      kenh 	{ WDC_VER_ATA1,	"ATA-1" },
    234   1.1      kenh 	{ WDC_VER_ATA2,	"ATA-2" },
    235   1.1      kenh 	{ WDC_VER_ATA3,	"ATA-3" },
    236   1.1      kenh 	{ WDC_VER_ATA4,	"ATA-4" },
    237  1.23      yamt 	{ WDC_VER_ATA5,	"ATA-5" },
    238  1.23      yamt 	{ WDC_VER_ATA6,	"ATA-6" },
    239  1.23      yamt 	{ WDC_VER_ATA7,	"ATA-7" },
    240  1.67  drochner 	{ WDC_VER_ATA8, "ATA-8" },
    241  1.22      fvdl 	{ 0, NULL },
    242   1.1      kenh };
    243   1.1      kenh 
    244  1.62  jakllsch static const struct bitinfo ata_cmd_set1[] = {
    245   1.1      kenh 	{ WDC_CMD1_NOP, "NOP command" },
    246   1.1      kenh 	{ WDC_CMD1_RB, "READ BUFFER command" },
    247   1.1      kenh 	{ WDC_CMD1_WB, "WRITE BUFFER command" },
    248   1.1      kenh 	{ WDC_CMD1_HPA, "Host Protected Area feature set" },
    249   1.1      kenh 	{ WDC_CMD1_DVRST, "DEVICE RESET command" },
    250   1.1      kenh 	{ WDC_CMD1_SRV, "SERVICE interrupt" },
    251  1.70     soren 	{ WDC_CMD1_RLSE, "Release interrupt" },
    252  1.70     soren 	{ WDC_CMD1_AHEAD, "Look-ahead" },
    253  1.70     soren 	{ WDC_CMD1_CACHE, "Write cache" },
    254   1.1      kenh 	{ WDC_CMD1_PKT, "PACKET command feature set" },
    255   1.1      kenh 	{ WDC_CMD1_PM, "Power Management feature set" },
    256   1.1      kenh 	{ WDC_CMD1_REMOV, "Removable Media feature set" },
    257   1.1      kenh 	{ WDC_CMD1_SEC, "Security Mode feature set" },
    258   1.1      kenh 	{ WDC_CMD1_SMART, "SMART feature set" },
    259  1.22      fvdl 	{ 0, NULL },
    260   1.1      kenh };
    261   1.1      kenh 
    262  1.62  jakllsch static const struct bitinfo ata_cmd_set2[] = {
    263  1.23      yamt 	{ ATA_CMD2_FCE, "FLUSH CACHE EXT command" },
    264  1.23      yamt 	{ WDC_CMD2_FC, "FLUSH CACHE command" },
    265  1.23      yamt 	{ WDC_CMD2_DCO, "Device Configuration Overlay feature set" },
    266  1.23      yamt 	{ ATA_CMD2_LBA48, "48-bit Address feature set" },
    267  1.23      yamt 	{ WDC_CMD2_AAM, "Automatic Acoustic Management feature set" },
    268  1.28       wiz 	{ WDC_CMD2_SM, "SET MAX security extension" },
    269  1.23      yamt 	{ WDC_CMD2_SFREQ, "SET FEATURES required to spin-up after power-up" },
    270  1.23      yamt 	{ WDC_CMD2_PUIS, "Power-Up In Standby feature set" },
    271   1.1      kenh 	{ WDC_CMD2_RMSN, "Removable Media Status Notification feature set" },
    272   1.1      kenh 	{ ATA_CMD2_APM, "Advanced Power Management feature set" },
    273   1.1      kenh 	{ ATA_CMD2_CFA, "CFA feature set" },
    274   1.6     soren 	{ ATA_CMD2_RWQ, "READ/WRITE DMA QUEUED commands" },
    275   1.1      kenh 	{ WDC_CMD2_DM, "DOWNLOAD MICROCODE command" },
    276  1.22      fvdl 	{ 0, NULL },
    277   1.1      kenh };
    278   1.1      kenh 
    279  1.62  jakllsch static const struct bitinfo ata_cmd_ext[] = {
    280  1.23      yamt 	{ ATA_CMDE_TLCONT, "Time-limited R/W feature set R/W Continuous mode" },
    281  1.23      yamt 	{ ATA_CMDE_TL, "Time-limited Read/Write" },
    282  1.23      yamt 	{ ATA_CMDE_URGW, "URG bit for WRITE STREAM DMA/PIO" },
    283  1.23      yamt 	{ ATA_CMDE_URGR, "URG bit for READ STREAM DMA/PIO" },
    284  1.55  jakllsch 	{ ATA_CMDE_WWN, "World Wide Name" },
    285  1.23      yamt 	{ ATA_CMDE_WQFE, "WRITE DMA QUEUED FUA EXT command" },
    286  1.23      yamt 	{ ATA_CMDE_WFE, "WRITE DMA/MULTIPLE FUA EXT commands" },
    287  1.23      yamt 	{ ATA_CMDE_GPL, "General Purpose Logging feature set" },
    288  1.23      yamt 	{ ATA_CMDE_STREAM, "Streaming feature set" },
    289  1.23      yamt 	{ ATA_CMDE_MCPTC, "Media Card Pass Through Command feature set" },
    290  1.23      yamt 	{ ATA_CMDE_MS, "Media serial number" },
    291  1.23      yamt 	{ ATA_CMDE_SST, "SMART self-test" },
    292  1.23      yamt 	{ ATA_CMDE_SEL, "SMART error logging" },
    293  1.23      yamt 	{ 0, NULL },
    294  1.23      yamt };
    295  1.23      yamt 
    296  1.62  jakllsch static const struct bitinfo ata_sata_caps[] = {
    297  1.46    bouyer 	{ SATA_SIGNAL_GEN1, "1.5Gb/s signaling" },
    298  1.46    bouyer 	{ SATA_SIGNAL_GEN2, "3.0Gb/s signaling" },
    299  1.69  jakllsch 	{ SATA_SIGNAL_GEN3, "6.0Gb/s signaling" },
    300  1.46    bouyer 	{ SATA_NATIVE_CMDQ, "Native Command Queuing" },
    301  1.46    bouyer 	{ SATA_HOST_PWR_MGMT, "Host-Initiated Interface Power Management" },
    302  1.46    bouyer 	{ SATA_PHY_EVNT_CNT, "PHY Event Counters" },
    303  1.46    bouyer 	{ 0, NULL },
    304  1.46    bouyer };
    305  1.46    bouyer 
    306  1.62  jakllsch static const struct bitinfo ata_sata_feat[] = {
    307  1.46    bouyer 	{ SATA_NONZERO_OFFSETS, "Non-zero Offset DMA" },
    308  1.46    bouyer 	{ SATA_DMA_SETUP_AUTO, "DMA Setup Auto Activate" },
    309  1.85  jmcneill 	{ SATA_DRIVE_PWR_MGMT, "Device-Initiated Interface Power Management" },
    310  1.46    bouyer 	{ SATA_IN_ORDER_DATA, "In-order Data Delivery" },
    311  1.47   xtraeme 	{ SATA_SW_STTNGS_PRS, "Software Settings Preservation" },
    312  1.46    bouyer 	{ 0, NULL },
    313  1.46    bouyer };
    314  1.46    bouyer 
    315  1.78       mrg /*
    316  1.78       mrg  * Global SMART attribute table.  All known attributes should be defined
    317  1.78       mrg  * here with overrides outside of the standard in a vendor specific table.
    318  1.78       mrg  *
    319  1.78       mrg  * XXX Some of these should be duplicated to vendor-specific tables now that
    320  1.78       mrg  * XXX they exist and have non generic names.
    321  1.78       mrg  */
    322  1.78       mrg static const struct attr_table {
    323  1.78       mrg 	const unsigned	id;
    324  1.17     soren 	const char	*name;
    325  1.62  jakllsch 	void (*special)(const struct ata_smart_attr *, uint64_t);
    326  1.17     soren } smart_attrs[] = {
    327  1.45  christos 	{   1,		"Raw read error rate", NULL },
    328  1.45  christos 	{   2,		"Throughput performance", NULL },
    329  1.45  christos 	{   3,		"Spin-up time", NULL },
    330  1.45  christos 	{   4,		"Start/stop count", NULL },
    331  1.45  christos 	{   5,		"Reallocated sector count", NULL },
    332  1.45  christos 	{   6,		"Read channel margin", NULL },
    333  1.45  christos 	{   7,		"Seek error rate", NULL },
    334  1.45  christos 	{   8,		"Seek time performance", NULL },
    335  1.45  christos 	{   9,		"Power-on hours count", NULL },
    336  1.45  christos 	{  10,		"Spin retry count", NULL },
    337  1.45  christos 	{  11,		"Calibration retry count", NULL },
    338  1.45  christos 	{  12,		"Device power cycle count", NULL },
    339  1.52  dholland 	{  13,		"Soft read error rate", NULL },
    340  1.74       mrg 	{ 100,          "Erase/Program Cycles", NULL },
    341  1.74       mrg 	{ 103,          "Translation Table Rebuild", NULL },
    342  1.74       mrg 	{ 170,          "Reserved Block Count", NULL },
    343  1.74       mrg 	{ 171,          "Program Fail Count", NULL },
    344  1.74       mrg 	{ 172,          "Erase Fail Count", NULL },
    345  1.74       mrg 	{ 173,          "Wear Leveller Worst Case Erase Count", NULL },
    346  1.78       mrg 	{ 174,          "Unexpected Power Loss Count", NULL },
    347  1.74       mrg 	{ 175,          "Program Fail Count", NULL },
    348  1.74       mrg 	{ 176,          "Erase Fail Count", NULL },
    349  1.74       mrg 	{ 177,          "Wear Leveling Count", NULL },
    350  1.74       mrg 	{ 178,          "Used Reserved Block Count", NULL },
    351  1.74       mrg 	{ 179,          "Used Reserved Block Count", NULL },
    352  1.74       mrg 	{ 180,          "Unused Reserved Block Count", NULL },
    353  1.74       mrg 	{ 181,          "Program Fail Count", NULL },
    354  1.74       mrg 	{ 182,          "Erase Fail Count", NULL },
    355  1.80       mrg 	{ 183,          "Runtime Bad Block", NULL },
    356  1.70     soren 	{ 184,          "End-to-end error", NULL },
    357  1.74       mrg 	{ 185,          "Head Stability", NULL },
    358  1.74       mrg 	{ 186,          "Induced Op-Vibration Detection", NULL },
    359  1.78       mrg 	{ 187,          "Reported Uncorrectable Errors", NULL },
    360  1.74       mrg 	{ 188,          "Command Timeout", NULL },
    361  1.52  dholland 	{ 189,          "High Fly Writes", NULL },
    362  1.52  dholland 	{ 190,          "Airflow Temperature",		device_smart_temp },
    363  1.52  dholland 	{ 191,		"G-sense error rate", NULL },
    364  1.45  christos 	{ 192,		"Power-off retract count", NULL },
    365  1.45  christos 	{ 193,		"Load cycle count", NULL },
    366  1.30    bouyer 	{ 194,		"Temperature",			device_smart_temp},
    367  1.45  christos 	{ 195,		"Hardware ECC Recovered", NULL },
    368  1.45  christos 	{ 196,		"Reallocated event count", NULL },
    369  1.45  christos 	{ 197,		"Current pending sector", NULL },
    370  1.45  christos 	{ 198,		"Offline uncorrectable", NULL },
    371  1.45  christos 	{ 199,		"Ultra DMA CRC error count", NULL },
    372  1.45  christos 	{ 200,		"Write error rate", NULL },
    373  1.45  christos 	{ 201,		"Soft read error rate", NULL },
    374  1.45  christos 	{ 202,		"Data address mark errors", NULL },
    375  1.45  christos 	{ 203,		"Run out cancel", NULL },
    376  1.45  christos 	{ 204,		"Soft ECC correction", NULL },
    377  1.45  christos 	{ 205,		"Thermal asperity check", NULL },
    378  1.45  christos 	{ 206,		"Flying height", NULL },
    379  1.45  christos 	{ 207,		"Spin high current", NULL },
    380  1.45  christos 	{ 208,		"Spin buzz", NULL },
    381  1.45  christos 	{ 209,		"Offline seek performance", NULL },
    382  1.75       mrg 	{ 210,		"Successful RAIN Recovery Count", NULL },
    383  1.45  christos 	{ 220,		"Disk shift", NULL },
    384  1.45  christos 	{ 221,		"G-Sense error rate", NULL },
    385  1.45  christos 	{ 222,		"Loaded hours", NULL },
    386  1.45  christos 	{ 223,		"Load/unload retry count", NULL },
    387  1.45  christos 	{ 224,		"Load friction", NULL },
    388  1.45  christos 	{ 225,		"Load/unload cycle count", NULL },
    389  1.45  christos 	{ 226,		"Load-in time", NULL },
    390  1.45  christos 	{ 227,		"Torque amplification count", NULL },
    391  1.45  christos 	{ 228,		"Power-off retract count", NULL },
    392  1.45  christos 	{ 230,		"GMR head amplitude", NULL },
    393  1.32    atatat 	{ 231,		"Temperature",			device_smart_temp },
    394  1.70     soren 	{ 232,		"Available reserved space", NULL },
    395  1.70     soren 	{ 233,		"Media wearout indicator", NULL },
    396  1.45  christos 	{ 240,		"Head flying hours", NULL },
    397  1.74       mrg 	{ 241,		"Total LBAs Written", NULL },
    398  1.74       mrg 	{ 242,		"Total LBAs Read", NULL },
    399  1.75       mrg 	{ 246,		"Total Host Sector Writes", NULL },
    400  1.76       mrg 	{ 247,		"Host Program NAND Pages Count", NULL },
    401  1.78       mrg 	{ 248,		"FTL Program Pages Count", NULL },
    402  1.77       mrg 	{ 249,		"Total Raw NAND Writes (1GiB units)", NULL },
    403  1.45  christos 	{ 250,		"Read error retry rate", NULL },
    404  1.74       mrg 	{ 254,		"Free Fall Sensor", NULL },
    405  1.45  christos 	{   0,		"Unknown", NULL },
    406  1.17     soren };
    407  1.17     soren 
    408  1.78       mrg /*
    409  1.78       mrg  * Micron specific SMART attributes published by Micron in:
    410  1.78       mrg  * "TN-FD-22: Client SATA SSD SMART Attribute Reference"
    411  1.78       mrg  */
    412  1.78       mrg static const struct attr_table micron_smart_names[] = {
    413  1.78       mrg 	{   5,		"Reallocated NAND block count", NULL },
    414  1.78       mrg 	{ 173,          "Average block erase count", NULL },
    415  1.79       mrg 	{ 181,          "Non 4K aligned access count", NULL },
    416  1.80       mrg 	{ 183,          "SATA Downshift Error Count", NULL },
    417  1.78       mrg 	{ 184,          "Error correction count", NULL },
    418  1.79       mrg 	{ 189,          "Factory bad block count", NULL },
    419  1.78       mrg 	{ 197,		"Current pending ECC count", NULL },
    420  1.78       mrg 	{ 198,		"SMART offline scan uncorrectable error count", NULL },
    421  1.84       mrg 	{ 202,		"Percent lifetime used", NULL },
    422  1.78       mrg 	{ 206,		"Write error rate", NULL },
    423  1.78       mrg 	{ 247,		"Number of NAND pages of data written by the host", NULL },
    424  1.78       mrg 	{ 248,		"Number of NAND pages written by the FTL", NULL },
    425  1.78       mrg 	{   0,		"Unknown", NULL },
    426  1.78       mrg };
    427  1.78       mrg 
    428  1.78       mrg /*
    429  1.80       mrg  * Intel specific SMART attributes.  Fill me in with more.
    430  1.80       mrg  */
    431  1.80       mrg static const struct attr_table intel_smart_names[] = {
    432  1.80       mrg 	{ 183,          "SATA Downshift Error Count", NULL },
    433  1.80       mrg };
    434  1.80       mrg 
    435  1.80       mrg /*
    436  1.81       mrg  * Samsung specific SMART attributes.  Fill me in with more.
    437  1.81       mrg  */
    438  1.81       mrg static const struct attr_table samsung_smart_names[] = {
    439  1.81       mrg 	{ 235,          "POR Recovery Count", NULL },
    440  1.81       mrg 	{ 243,          "SATA Downshift Count", NULL },
    441  1.81       mrg 	{ 244,          "Thermal Throttle Status", NULL },
    442  1.81       mrg 	{ 245,          "Timed Workload Media Wear", NULL },
    443  1.81       mrg 	{ 251,          "NAND Writes", NULL },
    444  1.81       mrg };
    445  1.81       mrg 
    446  1.81       mrg 
    447  1.81       mrg /*
    448  1.78       mrg  * Vendor-specific SMART attribute table.  Can be used to override
    449  1.78       mrg  * a particular attribute name and special printer function, with the
    450  1.78       mrg  * default is the main table.
    451  1.78       mrg  */
    452  1.80       mrg static const struct vendor_name_table {
    453  1.78       mrg 	const char *name;
    454  1.78       mrg 	const struct attr_table *table;
    455  1.78       mrg } vendor_smart_names[] = {
    456  1.80       mrg 	{ "Micron",		micron_smart_names },
    457  1.80       mrg 	{ "Intel",		intel_smart_names },
    458  1.81       mrg 	{ "Samsung",		samsung_smart_names },
    459  1.80       mrg };
    460  1.80       mrg 
    461  1.80       mrg /*
    462  1.80       mrg  * Global model -> vendor table.  Extend this to regexp.
    463  1.80       mrg  */
    464  1.80       mrg static const struct model_to_vendor_table {
    465  1.80       mrg 	const char *model;
    466  1.80       mrg 	const char *vendor;
    467  1.80       mrg } model_to_vendor[] = {
    468  1.80       mrg 	{ "Crucial",		"Micron" },
    469  1.80       mrg 	{ "Micron",		"Micron" },
    470  1.80       mrg 	{ "C300-CT",		"Micron" },
    471  1.80       mrg 	{ "C400-MT",		"Micron" },
    472  1.80       mrg 	{ "M4-CT",		"Micron" },
    473  1.80       mrg 	{ "M500",		"Micron" },
    474  1.80       mrg 	{ "M510",		"Micron" },
    475  1.80       mrg 	{ "M550",		"Micron" },
    476  1.80       mrg 	{ "MTFDDA",		"Micron" },
    477  1.80       mrg 	{ "EEFDDA",		"Micron" },
    478  1.80       mrg 	{ "INTEL",		"Intel" },
    479  1.81       mrg 	{ "SAMSUNG",		"Samsung" },
    480  1.78       mrg };
    481  1.78       mrg 
    482  1.62  jakllsch static const struct bitinfo ata_sec_st[] = {
    483  1.38  drochner 	{ WDC_SEC_SUPP,		"supported" },
    484  1.38  drochner 	{ WDC_SEC_EN,		"enabled" },
    485  1.38  drochner 	{ WDC_SEC_LOCKED,	"locked" },
    486  1.38  drochner 	{ WDC_SEC_FROZEN,	"frozen" },
    487  1.38  drochner 	{ WDC_SEC_EXP,		"expired" },
    488  1.38  drochner 	{ WDC_SEC_ESE_SUPP,	"enhanced erase support" },
    489  1.38  drochner 	{ WDC_SEC_LEV_MAX,	"maximum level" },
    490  1.38  drochner 	{ 0,			NULL },
    491  1.38  drochner };
    492  1.38  drochner 
    493   1.1      kenh int
    494  1.13    simonb main(int argc, char *argv[])
    495   1.1      kenh {
    496   1.1      kenh 	int i;
    497  1.62  jakllsch 	const struct command *commands = NULL;
    498   1.1      kenh 
    499   1.1      kenh 	/* Must have at least: device command */
    500   1.1      kenh 	if (argc < 3)
    501   1.1      kenh 		usage();
    502   1.1      kenh 
    503   1.1      kenh 	/* Skip program name, get and skip device name and command. */
    504   1.1      kenh 	dvname = argv[1];
    505   1.1      kenh 	cmdname = argv[2];
    506   1.1      kenh 	argv += 3;
    507   1.1      kenh 	argc -= 3;
    508   1.1      kenh 
    509   1.1      kenh 	/*
    510   1.1      kenh 	 * Open the device
    511   1.1      kenh 	 */
    512   1.1      kenh 	fd = opendisk(dvname, O_RDWR, dvname_store, sizeof(dvname_store), 0);
    513   1.1      kenh 	if (fd == -1) {
    514   1.1      kenh 		if (errno == ENOENT) {
    515   1.1      kenh 			/*
    516   1.1      kenh 			 * Device doesn't exist.  Probably trying to open
    517   1.1      kenh 			 * a device which doesn't use disk semantics for
    518   1.1      kenh 			 * device name.  Try again, specifying "cooked",
    519   1.1      kenh 			 * which leaves off the "r" in front of the device's
    520   1.1      kenh 			 * name.
    521   1.1      kenh 			 */
    522   1.1      kenh 			fd = opendisk(dvname, O_RDWR, dvname_store,
    523   1.1      kenh 			    sizeof(dvname_store), 1);
    524   1.1      kenh 			if (fd == -1)
    525   1.1      kenh 				err(1, "%s", dvname);
    526   1.4     jwise 		} else
    527   1.4     jwise 			err(1, "%s", dvname);
    528   1.1      kenh 	}
    529   1.1      kenh 
    530   1.1      kenh 	/*
    531   1.1      kenh 	 * Point the dvname at the actual device name that opendisk() opened.
    532   1.1      kenh 	 */
    533   1.1      kenh 	dvname = dvname_store;
    534   1.1      kenh 
    535   1.1      kenh 	/* Look up and call the command. */
    536  1.30    bouyer 	for (i = 0; device_commands[i].cmd_name != NULL; i++) {
    537  1.30    bouyer 		if (strcmp(cmdname, device_commands[i].cmd_name) == 0) {
    538  1.30    bouyer 			commands = &device_commands[i];
    539   1.1      kenh 			break;
    540  1.30    bouyer 		}
    541  1.30    bouyer 	}
    542  1.30    bouyer 	if (commands == NULL) {
    543  1.30    bouyer 		for (i = 0; bus_commands[i].cmd_name != NULL; i++) {
    544  1.30    bouyer 			if (strcmp(cmdname, bus_commands[i].cmd_name) == 0) {
    545  1.30    bouyer 				commands = &bus_commands[i];
    546  1.30    bouyer 				break;
    547  1.30    bouyer 			}
    548  1.30    bouyer 		}
    549  1.30    bouyer 	}
    550  1.30    bouyer 	if (commands == NULL)
    551  1.12        ad 		errx(1, "unknown command: %s", cmdname);
    552   1.1      kenh 
    553  1.30    bouyer 	(*commands->cmd_func)(argc, argv);
    554   1.1      kenh 	exit(0);
    555   1.1      kenh }
    556   1.1      kenh 
    557  1.60     joerg static void
    558  1.13    simonb usage(void)
    559   1.1      kenh {
    560   1.5     soren 	int i;
    561   1.1      kenh 
    562  1.27      jmmv 	fprintf(stderr, "usage: %s device command [arg [...]]\n",
    563  1.11       cgd 	    getprogname());
    564   1.5     soren 
    565   1.5     soren 	fprintf(stderr, "   Available device commands:\n");
    566  1.30    bouyer 	for (i=0; device_commands[i].cmd_name != NULL; i++)
    567  1.30    bouyer 		fprintf(stderr, "\t%s %s\n", device_commands[i].cmd_name,
    568  1.30    bouyer 					    device_commands[i].arg_names);
    569  1.30    bouyer 
    570  1.30    bouyer 	fprintf(stderr, "   Available bus commands:\n");
    571  1.30    bouyer 	for (i=0; bus_commands[i].cmd_name != NULL; i++)
    572  1.30    bouyer 		fprintf(stderr, "\t%s %s\n", bus_commands[i].cmd_name,
    573  1.30    bouyer 					    bus_commands[i].arg_names);
    574   1.5     soren 
    575   1.1      kenh 	exit(1);
    576   1.1      kenh }
    577   1.1      kenh 
    578   1.1      kenh /*
    579   1.1      kenh  * Wrapper that calls ATAIOCCOMMAND and checks for errors
    580   1.1      kenh  */
    581   1.1      kenh 
    582  1.60     joerg static void
    583  1.13    simonb ata_command(struct atareq *req)
    584   1.1      kenh {
    585   1.1      kenh 	int error;
    586   1.1      kenh 
    587  1.83   mlelstv 	switch (use_satl) {
    588  1.83   mlelstv 	case 0:
    589  1.83   mlelstv 		error = ioctl(fd, ATAIOCCOMMAND, req);
    590  1.83   mlelstv 		if (error == 0)
    591  1.83   mlelstv 			break;
    592  1.83   mlelstv 		if (errno != ENOTTY)
    593  1.83   mlelstv 			err(1, "ATAIOCCOMMAND failed");
    594  1.83   mlelstv 		use_satl = 1;
    595  1.83   mlelstv 		/* FALLTHROUGH */
    596  1.83   mlelstv 	case 1:
    597  1.83   mlelstv 		error = satl_command(req, 16);
    598  1.83   mlelstv 		if (error == 0)
    599  1.83   mlelstv 			return;
    600  1.83   mlelstv 		use_satl = 2;
    601  1.83   mlelstv 		/* FALLTHROUGH */
    602  1.83   mlelstv 	case 2:
    603  1.83   mlelstv 		(void) satl_command(req, 12);
    604  1.83   mlelstv 		return;
    605  1.83   mlelstv 	}
    606   1.1      kenh 
    607   1.1      kenh 	switch (req->retsts) {
    608   1.1      kenh 
    609   1.1      kenh 	case ATACMD_OK:
    610   1.1      kenh 		return;
    611   1.1      kenh 	case ATACMD_TIMEOUT:
    612   1.1      kenh 		fprintf(stderr, "ATA command timed out\n");
    613   1.1      kenh 		exit(1);
    614   1.1      kenh 	case ATACMD_DF:
    615   1.1      kenh 		fprintf(stderr, "ATA device returned a Device Fault\n");
    616   1.1      kenh 		exit(1);
    617   1.1      kenh 	case ATACMD_ERROR:
    618   1.1      kenh 		if (req->error & WDCE_ABRT)
    619   1.1      kenh 			fprintf(stderr, "ATA device returned Aborted "
    620   1.1      kenh 				"Command\n");
    621   1.1      kenh 		else
    622   1.1      kenh 			fprintf(stderr, "ATA device returned error register "
    623   1.1      kenh 				"%0x\n", req->error);
    624   1.1      kenh 		exit(1);
    625   1.1      kenh 	default:
    626   1.1      kenh 		fprintf(stderr, "ATAIOCCOMMAND returned unknown result code "
    627   1.1      kenh 			"%d\n", req->retsts);
    628   1.1      kenh 		exit(1);
    629   1.1      kenh 	}
    630   1.1      kenh }
    631   1.1      kenh 
    632   1.1      kenh /*
    633  1.83   mlelstv  * Wrapper that calls SCIOCCOMMAND for a tunneled ATA command
    634  1.83   mlelstv  */
    635  1.83   mlelstv static int
    636  1.83   mlelstv satl_command(struct atareq *req, int cmdlen)
    637  1.83   mlelstv {
    638  1.83   mlelstv 	scsireq_t sreq;
    639  1.83   mlelstv 	int error;
    640  1.83   mlelstv 	union {
    641  1.83   mlelstv 		struct scsi_ata_pass_through_12 cmd12;
    642  1.83   mlelstv 		struct scsi_ata_pass_through_16 cmd16;
    643  1.83   mlelstv 	} c;
    644  1.83   mlelstv 	uint8_t b2, b3;
    645  1.83   mlelstv 	const uint8_t *desc;
    646  1.83   mlelstv 
    647  1.83   mlelstv 	b2 = SATL_NODATA;
    648  1.83   mlelstv 	if (req->datalen > 0) {
    649  1.83   mlelstv 		if (req->flags & ATACMD_READ)
    650  1.83   mlelstv 			b2 = SATL_PIO_IN;
    651  1.83   mlelstv 		else
    652  1.83   mlelstv 			b2 = SATL_PIO_OUT;
    653  1.83   mlelstv 	}
    654  1.83   mlelstv 
    655  1.83   mlelstv 	b3 = SATL_BLOCKS;
    656  1.83   mlelstv 	if (req->datalen > 0) {
    657  1.83   mlelstv 		b3 |= 2; /* sector count holds count */
    658  1.83   mlelstv 	} else {
    659  1.83   mlelstv 		b3 |= SATL_CKCOND;
    660  1.83   mlelstv 	}
    661  1.83   mlelstv 	if (req->datalen == 0 || req->flags & ATACMD_READ)
    662  1.83   mlelstv 		b3 |= SATL_READ;
    663  1.83   mlelstv 
    664  1.83   mlelstv 	switch (cmdlen) {
    665  1.83   mlelstv 	case 16:
    666  1.83   mlelstv 		c.cmd16.opcode = SCSI_ATA_PASS_THROUGH_16;
    667  1.83   mlelstv 		c.cmd16.byte2 = b2;
    668  1.83   mlelstv 		c.cmd16.byte3 = b3;
    669  1.83   mlelstv 		c.cmd16.features[0] = 0;
    670  1.83   mlelstv 		c.cmd16.features[1] = req->features;
    671  1.83   mlelstv 		c.cmd16.sector_count[0] = 0;
    672  1.83   mlelstv 		c.cmd16.sector_count[1] = req->sec_count;
    673  1.83   mlelstv 		c.cmd16.lba[0] = 0;
    674  1.83   mlelstv 		c.cmd16.lba[1] = req->sec_num;
    675  1.83   mlelstv 		c.cmd16.lba[2] = 0;
    676  1.83   mlelstv 		c.cmd16.lba[3] = req->cylinder;
    677  1.83   mlelstv 		c.cmd16.lba[4] = 0;
    678  1.83   mlelstv 		c.cmd16.lba[5] = req->cylinder >> 8;
    679  1.83   mlelstv 		c.cmd16.device = 0;
    680  1.83   mlelstv 		c.cmd16.ata_cmd = req->command;
    681  1.83   mlelstv 		c.cmd16.control = 0;
    682  1.83   mlelstv 		break;
    683  1.83   mlelstv 	case 12:
    684  1.83   mlelstv 		c.cmd12.opcode = SCSI_ATA_PASS_THROUGH_12;
    685  1.83   mlelstv 		c.cmd12.byte2 = b2;
    686  1.83   mlelstv 		c.cmd12.byte3 = b3;
    687  1.83   mlelstv 		c.cmd12.features[0] = req->features;
    688  1.83   mlelstv 		c.cmd12.sector_count[0] = req->sec_count;
    689  1.83   mlelstv 		c.cmd12.lba[0] = req->sec_num;
    690  1.83   mlelstv 		c.cmd12.lba[1] = req->cylinder;
    691  1.83   mlelstv 		c.cmd12.lba[2] = req->cylinder >> 8;
    692  1.83   mlelstv 		c.cmd12.device = 0;
    693  1.83   mlelstv 		c.cmd12.reserved = 0;
    694  1.83   mlelstv 		c.cmd12.ata_cmd = req->command;
    695  1.83   mlelstv 		c.cmd12.control = 0;
    696  1.83   mlelstv 		break;
    697  1.83   mlelstv 	default:
    698  1.83   mlelstv 		fprintf(stderr, "ATA command with bad length\n");
    699  1.83   mlelstv 		exit(1);
    700  1.83   mlelstv 	}
    701  1.83   mlelstv 
    702  1.83   mlelstv 	memset(&sreq, 0, sizeof(sreq));
    703  1.83   mlelstv 	memcpy(sreq.cmd, &c, cmdlen);
    704  1.83   mlelstv 	sreq.cmdlen = cmdlen;
    705  1.83   mlelstv 	sreq.databuf = req->databuf;
    706  1.83   mlelstv 	sreq.datalen = req->datalen;
    707  1.83   mlelstv 	sreq.senselen = sizeof(sreq.sense);
    708  1.83   mlelstv 	sreq.timeout = req->timeout;
    709  1.83   mlelstv 
    710  1.83   mlelstv 	if (sreq.datalen > 0) {
    711  1.83   mlelstv 		if (req->flags & ATACMD_READ)
    712  1.83   mlelstv 			sreq.flags |= SCCMD_READ;
    713  1.83   mlelstv 		if (req->flags & ATACMD_WRITE)
    714  1.83   mlelstv 			sreq.flags |= SCCMD_WRITE;
    715  1.83   mlelstv 	}
    716  1.83   mlelstv 
    717  1.83   mlelstv 	error = ioctl(fd, SCIOCCOMMAND, &sreq);
    718  1.83   mlelstv 	if (error == -1)
    719  1.83   mlelstv 		err(1, "SCIOCCOMMAND failed");
    720  1.83   mlelstv 
    721  1.83   mlelstv 	req->datalen = sreq.datalen_used;
    722  1.83   mlelstv 	req->retsts = ATACMD_OK;
    723  1.83   mlelstv 	req->error = 0;
    724  1.83   mlelstv 
    725  1.83   mlelstv 	switch (sreq.retsts) {
    726  1.83   mlelstv 	case SCCMD_OK:
    727  1.83   mlelstv 		return 0;
    728  1.83   mlelstv 	case SCCMD_TIMEOUT:
    729  1.83   mlelstv 		fprintf(stderr, "SATL command timed out\n");
    730  1.83   mlelstv 		exit(1);
    731  1.83   mlelstv 	case SCCMD_BUSY:
    732  1.83   mlelstv 		fprintf(stderr, "SATL command returned busy\n");
    733  1.83   mlelstv 		exit(1);
    734  1.83   mlelstv 	case SCCMD_SENSE:
    735  1.83   mlelstv 		desc = NULL;
    736  1.83   mlelstv 		switch (SSD_RCODE(sreq.sense[0])) {
    737  1.83   mlelstv 		case 0x00:
    738  1.83   mlelstv 			return 0;
    739  1.83   mlelstv 		case 0x70:
    740  1.83   mlelstv 			if (sreq.sense[2] == SKEY_NO_SENSE)
    741  1.83   mlelstv 				return 0;
    742  1.83   mlelstv 			if (sreq.sense[2] == SKEY_ILLEGAL_REQUEST)
    743  1.83   mlelstv 				return 1;
    744  1.83   mlelstv 			break;
    745  1.83   mlelstv 		case 0x72:
    746  1.83   mlelstv 		case 0x73:
    747  1.83   mlelstv 			desc = satl_return_desc(sreq.sense, sreq.senselen_used,
    748  1.83   mlelstv 				SCSI_ATA_RETURN_DESCRIPTOR);
    749  1.83   mlelstv 			break;
    750  1.83   mlelstv 		default:
    751  1.83   mlelstv 			break;
    752  1.83   mlelstv 		}
    753  1.83   mlelstv 
    754  1.83   mlelstv 		if (desc && desc[1] >= 12) {
    755  1.83   mlelstv 			req->sec_count = desc[5];
    756  1.83   mlelstv 			req->sec_num = desc[7];
    757  1.83   mlelstv 			req->head = (desc[12] & 0xf0) |
    758  1.83   mlelstv 			            ((desc[7] >> 24) & 0x0f);
    759  1.83   mlelstv 			req->cylinder = desc[11] << 8 | desc[9];
    760  1.83   mlelstv 			req->retsts = desc[13];
    761  1.83   mlelstv 			req->error = desc[3];
    762  1.83   mlelstv 			return 0;
    763  1.83   mlelstv 		}
    764  1.83   mlelstv 
    765  1.83   mlelstv 		fprintf(stderr, "SATL command error: rcode %02x key %u\n",
    766  1.83   mlelstv 			SSD_RCODE(sreq.sense[0]),
    767  1.83   mlelstv 			SSD_SENSE_KEY(sreq.sense[2]));
    768  1.83   mlelstv 		if (desc) {
    769  1.83   mlelstv 			int i, n;
    770  1.83   mlelstv 			n = desc[1]+2;
    771  1.83   mlelstv 			printf("ATA Return Descriptor:");
    772  1.83   mlelstv 			for (i=0; i<n; ++i)
    773  1.83   mlelstv 				printf(" %02x",desc[i]);
    774  1.83   mlelstv 			printf("\n");
    775  1.83   mlelstv 		}
    776  1.83   mlelstv 		exit(1);
    777  1.83   mlelstv 	default:
    778  1.83   mlelstv 		fprintf(stderr, "SCSIIOCCOMMAND returned unknown result code "
    779  1.83   mlelstv 			"%d\n", sreq.retsts);
    780  1.83   mlelstv 		exit(1);
    781  1.83   mlelstv 	}
    782  1.83   mlelstv }
    783  1.83   mlelstv 
    784  1.83   mlelstv static const uint8_t *
    785  1.83   mlelstv satl_return_desc(const uint8_t *sense, size_t len, uint8_t type)
    786  1.83   mlelstv {
    787  1.83   mlelstv 	const uint8_t *p, *endp;
    788  1.83   mlelstv 	size_t l, extra;
    789  1.83   mlelstv 
    790  1.83   mlelstv 	if (len < 8)
    791  1.83   mlelstv 		return NULL;
    792  1.83   mlelstv 	extra = sense[7];
    793  1.83   mlelstv 	len -= 8;
    794  1.83   mlelstv 	if (extra < len)
    795  1.83   mlelstv 		len = extra;
    796  1.83   mlelstv 	if (len < 2)
    797  1.83   mlelstv 		return NULL;
    798  1.83   mlelstv 
    799  1.83   mlelstv 	switch (sense[0]) {
    800  1.83   mlelstv 	case 0x72:
    801  1.83   mlelstv 	case 0x73:
    802  1.83   mlelstv 		p = &sense[8];
    803  1.83   mlelstv 		endp = &p[len-1];
    804  1.83   mlelstv 		while (p < endp) {
    805  1.83   mlelstv 			if (p[0] == type)
    806  1.83   mlelstv 				return p;
    807  1.83   mlelstv 			l = p[1];
    808  1.83   mlelstv 			p += l + 2;
    809  1.83   mlelstv 		}
    810  1.83   mlelstv 		break;
    811  1.83   mlelstv 	}
    812  1.83   mlelstv 
    813  1.83   mlelstv 	return NULL;
    814  1.83   mlelstv }
    815  1.83   mlelstv 
    816  1.83   mlelstv 
    817  1.83   mlelstv /*
    818   1.1      kenh  * Print out strings associated with particular bitmasks
    819   1.1      kenh  */
    820   1.1      kenh 
    821  1.60     joerg static void
    822  1.64  jakllsch print_bitinfo(const char *bf, const char *af, u_int bits,
    823  1.64  jakllsch     const struct bitinfo *binfo)
    824   1.1      kenh {
    825   1.1      kenh 
    826  1.22      fvdl 	for (; binfo->bitmask != 0; binfo++)
    827   1.1      kenh 		if (bits & binfo->bitmask)
    828  1.10        is 			printf("%s%s%s", bf, binfo->string, af);
    829   1.1      kenh }
    830   1.1      kenh 
    831  1.60     joerg static void
    832  1.64  jakllsch print_bitinfo2(const char *bf, const char *af, u_int bits, u_int enables,
    833  1.64  jakllsch     const struct bitinfo *binfo)
    834  1.33   mycroft {
    835  1.33   mycroft 
    836  1.33   mycroft 	for (; binfo->bitmask != 0; binfo++)
    837  1.33   mycroft 		if (bits & binfo->bitmask)
    838  1.33   mycroft 			printf("%s%s (%s)%s", bf, binfo->string,
    839  1.33   mycroft 			    (enables & binfo->bitmask) ? "enabled" : "disabled",
    840  1.33   mycroft 			    af);
    841  1.33   mycroft }
    842  1.33   mycroft 
    843  1.24       lha 
    844  1.24       lha /*
    845  1.24       lha  * Try to print SMART temperature field
    846  1.24       lha  */
    847  1.24       lha 
    848  1.60     joerg static void
    849  1.62  jakllsch device_smart_temp(const struct ata_smart_attr *attr, uint64_t raw_value)
    850  1.24       lha {
    851  1.29   mycroft 	printf("%" PRIu8, attr->raw[0]);
    852  1.24       lha 	if (attr->raw[0] != raw_value)
    853  1.61  jakllsch 		printf(" Lifetime min/max %" PRIu8 "/%" PRIu8,
    854  1.29   mycroft 		    attr->raw[2], attr->raw[4]);
    855  1.24       lha }
    856  1.24       lha 
    857   1.1      kenh /*
    858  1.15     soren  * Print out SMART attribute thresholds and values
    859  1.15     soren  */
    860  1.15     soren 
    861  1.60     joerg static void
    862  1.78       mrg print_smart_status(void *vbuf, void *tbuf, const char *vendor)
    863  1.15     soren {
    864  1.62  jakllsch 	const struct ata_smart_attributes *value_buf = vbuf;
    865  1.62  jakllsch 	const struct ata_smart_thresholds *threshold_buf = tbuf;
    866  1.62  jakllsch 	const struct ata_smart_attr *attr;
    867  1.29   mycroft 	uint64_t raw_value;
    868  1.24       lha 	int flags;
    869  1.78       mrg 	unsigned i, j;
    870  1.78       mrg 	unsigned aid, vid;
    871  1.63  jakllsch 	uint8_t checksum;
    872  1.78       mrg 	const struct attr_table *vendor_table = NULL;
    873  1.78       mrg 	void (*special)(const struct ata_smart_attr *, uint64_t);
    874  1.78       mrg 
    875  1.78       mrg 	if (vendor) {
    876  1.78       mrg 		for (i = 0; i < __arraycount(vendor_smart_names); i++) {
    877  1.78       mrg 			if (strcasecmp(vendor,
    878  1.78       mrg 			    vendor_smart_names[i].name) == 0) {
    879  1.78       mrg 				vendor_table = vendor_smart_names[i].table;
    880  1.78       mrg 				break;
    881  1.78       mrg 			}
    882  1.78       mrg 		}
    883  1.78       mrg 		if (vendor_table == NULL)
    884  1.78       mrg 			fprintf(stderr,
    885  1.78       mrg 			    "SMART vendor '%s' has no special table\n", vendor);
    886  1.78       mrg 	}
    887  1.15     soren 
    888  1.33   mycroft 	for (i = checksum = 0; i < 512; i++)
    889  1.63  jakllsch 		checksum += ((const uint8_t *) value_buf)[i];
    890  1.33   mycroft 	if (checksum != 0) {
    891  1.15     soren 		fprintf(stderr, "SMART attribute values checksum error\n");
    892  1.15     soren 		return;
    893  1.15     soren 	}
    894  1.15     soren 
    895  1.33   mycroft 	for (i = checksum = 0; i < 512; i++)
    896  1.63  jakllsch 		checksum += ((const uint8_t *) threshold_buf)[i];
    897  1.33   mycroft 	if (checksum != 0) {
    898  1.15     soren 		fprintf(stderr, "SMART attribute thresholds checksum error\n");
    899  1.15     soren 		return;
    900  1.15     soren 	}
    901  1.15     soren 
    902  1.64  jakllsch 	printf("id value thresh crit collect reliability description"
    903  1.70     soren 	    "                 raw\n");
    904  1.24       lha 	for (i = 0; i < 256; i++) {
    905  1.24       lha 		int thresh = 0;
    906  1.78       mrg 		const char *name = NULL;
    907  1.24       lha 
    908  1.24       lha 		attr = NULL;
    909  1.24       lha 
    910  1.24       lha 		for (j = 0; j < 30; j++) {
    911  1.24       lha 			if (value_buf->attributes[j].id == i)
    912  1.24       lha 				attr = &value_buf->attributes[j];
    913  1.24       lha 			if (threshold_buf->thresholds[j].id == i)
    914  1.24       lha 				thresh = threshold_buf->thresholds[j].value;
    915  1.31    atatat 		}
    916  1.15     soren 
    917  1.24       lha 		if (thresh && attr == NULL)
    918  1.24       lha 			errx(1, "threshold but not attr %d", i);
    919  1.24       lha 		if (attr == NULL)
    920  1.24       lha 			continue;
    921  1.24       lha 
    922  1.24       lha 		if (attr->value == 0||attr->value == 0xFE||attr->value == 0xFF)
    923  1.24       lha 			continue;
    924  1.24       lha 
    925  1.61  jakllsch 		for (aid = 0;
    926  1.61  jakllsch 		     smart_attrs[aid].id != i && smart_attrs[aid].id != 0;
    927  1.24       lha 		     aid++)
    928  1.24       lha 			;
    929  1.24       lha 
    930  1.78       mrg 		if (vendor_table) {
    931  1.78       mrg 			for (vid = 0;
    932  1.78       mrg 			     vendor_table[vid].id != i && vendor_table[vid].id != 0;
    933  1.78       mrg 			     vid++)
    934  1.78       mrg 				;
    935  1.78       mrg 			if (vendor_table[vid].id != 0) {
    936  1.78       mrg 				name = vendor_table[vid].name;
    937  1.78       mrg 				special = vendor_table[vid].special;
    938  1.78       mrg 			}
    939  1.78       mrg 		}
    940  1.78       mrg 		if (name == NULL) {
    941  1.78       mrg 			name = smart_attrs[aid].name;
    942  1.78       mrg 			special = smart_attrs[aid].special;
    943  1.78       mrg 		}
    944  1.78       mrg 
    945  1.35      fvdl 		flags = le16toh(attr->flags);
    946  1.24       lha 
    947  1.70     soren 		printf("%3d %3d  %3d     %-3s %-7s %stive    %-27s ",
    948  1.24       lha 		    i, attr->value, thresh,
    949  1.24       lha 		    flags & WDSM_ATTR_ADVISORY ? "yes" : "no",
    950  1.24       lha 		    flags & WDSM_ATTR_COLLECTIVE ? "online" : "offline",
    951  1.78       mrg 		    attr->value > thresh ? "posi" : "nega", name);
    952  1.24       lha 
    953  1.24       lha 		for (j = 0, raw_value = 0; j < 6; j++)
    954  1.29   mycroft 			raw_value += ((uint64_t)attr->raw[j]) << (8*j);
    955  1.24       lha 
    956  1.78       mrg 		if (special)
    957  1.78       mrg 			(*special)(attr, raw_value);
    958  1.29   mycroft 		else
    959  1.29   mycroft 			printf("%" PRIu64, raw_value);
    960  1.24       lha 		printf("\n");
    961  1.15     soren 	}
    962  1.58  nisimura }
    963  1.24       lha 
    964  1.62  jakllsch static const struct {
    965  1.24       lha 	int number;
    966  1.24       lha 	const char *name;
    967  1.24       lha } selftest_name[] = {
    968  1.24       lha 	{ 0, "Off-line" },
    969  1.24       lha 	{ 1, "Short off-line" },
    970  1.24       lha 	{ 2, "Extended off-line" },
    971  1.24       lha 	{ 127, "Abort off-line test" },
    972  1.24       lha 	{ 129, "Short captive" },
    973  1.24       lha 	{ 130, "Extended captive" },
    974  1.73       wiz 	{ 256, "Unknown test" }, /* larger than uint8_t */
    975  1.24       lha 	{ 0, NULL }
    976  1.24       lha };
    977  1.24       lha 
    978  1.60     joerg static const char *selftest_status[] = {
    979  1.24       lha 	"No error",
    980  1.24       lha 	"Aborted by the host",
    981  1.42       wiz 	"Interrupted by the host by reset",
    982  1.24       lha 	"Fatal error or unknown test error",
    983  1.24       lha 	"Unknown test element failed",
    984  1.24       lha 	"Electrical test element failed",
    985  1.24       lha 	"The Servo (and/or seek) test element failed",
    986  1.24       lha 	"Read element of test failed",
    987  1.24       lha 	"Reserved",
    988  1.24       lha 	"Reserved",
    989  1.24       lha 	"Reserved",
    990  1.24       lha 	"Reserved",
    991  1.24       lha 	"Reserved",
    992  1.24       lha 	"Reserved",
    993  1.24       lha 	"Reserved",
    994  1.24       lha 	"Self-test in progress"
    995  1.24       lha };
    996  1.24       lha 
    997  1.60     joerg static void
    998  1.62  jakllsch print_error_entry(int num, const struct ata_smart_error *le)
    999  1.33   mycroft {
   1000  1.33   mycroft 	int i;
   1001  1.33   mycroft 
   1002  1.33   mycroft 	printf("Log entry: %d\n", num);
   1003  1.33   mycroft 
   1004  1.33   mycroft 	for (i = 0; i < 5; i++)
   1005  1.64  jakllsch 		printf("\tCommand %d: dc=%02x sf=%02x sc=%02x sn=%02x cl=%02x "
   1006  1.64  jakllsch 		    "ch=%02x dh=%02x cmd=%02x time=%02x%02x%02x%02x\n", i,
   1007  1.33   mycroft 		    le->command[i].device_control,
   1008  1.33   mycroft 		    le->command[i].features,
   1009  1.33   mycroft 		    le->command[i].sector_count,
   1010  1.33   mycroft 		    le->command[i].sector_number,
   1011  1.33   mycroft 		    le->command[i].cylinder_low,
   1012  1.33   mycroft 		    le->command[i].cylinder_high,
   1013  1.33   mycroft 		    le->command[i].device_head,
   1014  1.33   mycroft 		    le->command[i].command,
   1015  1.33   mycroft 		    le->command[i].timestamp[3],
   1016  1.33   mycroft 		    le->command[i].timestamp[2],
   1017  1.33   mycroft 		    le->command[i].timestamp[1],
   1018  1.33   mycroft 		    le->command[i].timestamp[0]);
   1019  1.64  jakllsch 	printf("\tError: err=%02x sc=%02x sn=%02x cl=%02x ch=%02x dh=%02x "
   1020  1.64  jakllsch 	    "status=%02x state=%02x lifetime=%02x%02x\n",
   1021  1.33   mycroft 	    le->error_data.error,
   1022  1.33   mycroft 	    le->error_data.sector_count,
   1023  1.33   mycroft 	    le->error_data.sector_number,
   1024  1.33   mycroft 	    le->error_data.cylinder_low,
   1025  1.33   mycroft 	    le->error_data.cylinder_high,
   1026  1.33   mycroft 	    le->error_data.device_head,
   1027  1.33   mycroft 	    le->error_data.status,
   1028  1.33   mycroft 	    le->error_data.state,
   1029  1.33   mycroft 	    le->error_data.lifetime[1],
   1030  1.33   mycroft 	    le->error_data.lifetime[0]);
   1031  1.64  jakllsch 	printf("\tExtended: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x "
   1032  1.64  jakllsch 	    "%02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
   1033  1.33   mycroft 	    le->error_data.extended_error[0],
   1034  1.33   mycroft 	    le->error_data.extended_error[1],
   1035  1.33   mycroft 	    le->error_data.extended_error[2],
   1036  1.33   mycroft 	    le->error_data.extended_error[3],
   1037  1.33   mycroft 	    le->error_data.extended_error[4],
   1038  1.33   mycroft 	    le->error_data.extended_error[5],
   1039  1.33   mycroft 	    le->error_data.extended_error[6],
   1040  1.33   mycroft 	    le->error_data.extended_error[7],
   1041  1.33   mycroft 	    le->error_data.extended_error[8],
   1042  1.33   mycroft 	    le->error_data.extended_error[9],
   1043  1.33   mycroft 	    le->error_data.extended_error[10],
   1044  1.33   mycroft 	    le->error_data.extended_error[11],
   1045  1.33   mycroft 	    le->error_data.extended_error[12],
   1046  1.33   mycroft 	    le->error_data.extended_error[13],
   1047  1.33   mycroft 	    le->error_data.extended_error[14],
   1048  1.33   mycroft 	    le->error_data.extended_error[15],
   1049  1.33   mycroft 	    le->error_data.extended_error[15],
   1050  1.33   mycroft 	    le->error_data.extended_error[17],
   1051  1.33   mycroft 	    le->error_data.extended_error[18]);
   1052  1.33   mycroft }
   1053  1.33   mycroft 
   1054  1.60     joerg static void
   1055  1.62  jakllsch print_error(const void *buf)
   1056  1.33   mycroft {
   1057  1.62  jakllsch 	const struct ata_smart_errorlog *erlog = buf;
   1058  1.63  jakllsch 	uint8_t checksum;
   1059  1.33   mycroft 	int i;
   1060  1.33   mycroft 
   1061  1.33   mycroft 	for (i = checksum = 0; i < 512; i++)
   1062  1.63  jakllsch 		checksum += ((const uint8_t *) buf)[i];
   1063  1.33   mycroft 	if (checksum != 0) {
   1064  1.33   mycroft 		fprintf(stderr, "SMART error log checksum error\n");
   1065  1.33   mycroft 		return;
   1066  1.33   mycroft 	}
   1067  1.33   mycroft 
   1068  1.33   mycroft 	if (erlog->data_structure_revision != 1) {
   1069  1.41       dbj 		fprintf(stderr, "Error log revision not 1 (found 0x%04x)\n",
   1070  1.41       dbj 		    erlog->data_structure_revision);
   1071  1.33   mycroft 		return;
   1072  1.33   mycroft 	}
   1073  1.33   mycroft 
   1074  1.33   mycroft 	if (erlog->mostrecenterror == 0) {
   1075  1.33   mycroft 		printf("No errors have been logged\n");
   1076  1.33   mycroft 		return;
   1077  1.33   mycroft 	}
   1078  1.61  jakllsch 
   1079  1.33   mycroft 	if (erlog->mostrecenterror > 5) {
   1080  1.33   mycroft 		fprintf(stderr, "Most recent error is too large\n");
   1081  1.33   mycroft 		return;
   1082  1.33   mycroft 	}
   1083  1.61  jakllsch 
   1084  1.33   mycroft 	for (i = erlog->mostrecenterror; i < 5; i++)
   1085  1.33   mycroft 		print_error_entry(i, &erlog->log_entries[i]);
   1086  1.33   mycroft 	for (i = 0; i < erlog->mostrecenterror; i++)
   1087  1.33   mycroft 		print_error_entry(i, &erlog->log_entries[i]);
   1088  1.33   mycroft 	printf("device error count: %d\n", erlog->device_error_count);
   1089  1.33   mycroft }
   1090  1.33   mycroft 
   1091  1.60     joerg static void
   1092  1.62  jakllsch print_selftest_entry(int num, const struct ata_smart_selftest *le)
   1093  1.24       lha {
   1094  1.62  jakllsch 	const unsigned char *p;
   1095  1.53     lukem 	size_t i;
   1096  1.24       lha 
   1097  1.24       lha 	/* check if all zero */
   1098  1.62  jakllsch 	for (p = (const void *)le, i = 0; i < sizeof(*le); i++)
   1099  1.24       lha 		if (p[i] != 0)
   1100  1.24       lha 			break;
   1101  1.24       lha 	if (i == sizeof(*le))
   1102  1.24       lha 		return;
   1103  1.24       lha 
   1104  1.24       lha 	printf("Log entry: %d\n", num);
   1105  1.24       lha 
   1106  1.24       lha 	/* Get test name */
   1107  1.24       lha 	for (i = 0; selftest_name[i].name != NULL; i++)
   1108  1.24       lha 		if (selftest_name[i].number == le->number)
   1109  1.24       lha 			break;
   1110  1.24       lha 
   1111  1.33   mycroft 	if (selftest_name[i].name == NULL)
   1112  1.33   mycroft 		printf("\tName: (%d)\n", le->number);
   1113  1.33   mycroft 	else
   1114  1.33   mycroft 		printf("\tName: %s\n", selftest_name[i].name);
   1115  1.24       lha 	printf("\tStatus: %s\n", selftest_status[le->status >> 4]);
   1116  1.33   mycroft 	/* XXX This generally should not be set when a self-test is completed,
   1117  1.33   mycroft 	   and at any rate is useless.  - mycroft */
   1118  1.24       lha 	if (le->status >> 4 == 15)
   1119  1.33   mycroft 		printf("\tPercent of test remaining: %1d0\n", le->status & 0xf);
   1120  1.33   mycroft 	else if (le->status >> 4 != 0)
   1121  1.35      fvdl 		printf("\tLBA first error: %d\n", le32toh(le->lba_first_error));
   1122  1.24       lha }
   1123  1.24       lha 
   1124  1.60     joerg static void
   1125  1.62  jakllsch print_selftest(const void *buf)
   1126  1.24       lha {
   1127  1.62  jakllsch 	const struct ata_smart_selftestlog *stlog = buf;
   1128  1.63  jakllsch 	uint8_t checksum;
   1129  1.24       lha 	int i;
   1130  1.24       lha 
   1131  1.33   mycroft 	for (i = checksum = 0; i < 512; i++)
   1132  1.63  jakllsch 		checksum += ((const uint8_t *) buf)[i];
   1133  1.33   mycroft 	if (checksum != 0) {
   1134  1.24       lha 		fprintf(stderr, "SMART selftest log checksum error\n");
   1135  1.24       lha 		return;
   1136  1.24       lha 	}
   1137  1.24       lha 
   1138  1.41       dbj 	if (le16toh(stlog->data_structure_revision) != 1) {
   1139  1.41       dbj 		fprintf(stderr, "Self-test log revision not 1 (found 0x%04x)\n",
   1140  1.41       dbj 		    le16toh(stlog->data_structure_revision));
   1141  1.24       lha 		return;
   1142  1.24       lha 	}
   1143  1.24       lha 
   1144  1.24       lha 	if (stlog->mostrecenttest == 0) {
   1145  1.24       lha 		printf("No self-tests have been logged\n");
   1146  1.24       lha 		return;
   1147  1.24       lha 	}
   1148  1.61  jakllsch 
   1149  1.24       lha 	if (stlog->mostrecenttest > 22) {
   1150  1.24       lha 		fprintf(stderr, "Most recent test is too large\n");
   1151  1.24       lha 		return;
   1152  1.24       lha 	}
   1153  1.61  jakllsch 
   1154  1.24       lha 	for (i = stlog->mostrecenttest; i < 22; i++)
   1155  1.24       lha 		print_selftest_entry(i, &stlog->log_entries[i]);
   1156  1.24       lha 	for (i = 0; i < stlog->mostrecenttest; i++)
   1157  1.24       lha 		print_selftest_entry(i, &stlog->log_entries[i]);
   1158  1.15     soren }
   1159  1.15     soren 
   1160  1.79       mrg static void
   1161  1.79       mrg fillataparams(void)
   1162  1.38  drochner {
   1163  1.38  drochner 	struct atareq req;
   1164  1.38  drochner 	static union {
   1165  1.38  drochner 		unsigned char inbuf[DEV_BSIZE];
   1166  1.38  drochner 		struct ataparams inqbuf;
   1167  1.38  drochner 	} inbuf;
   1168  1.79       mrg 	static int first = 1;
   1169  1.79       mrg 
   1170  1.79       mrg 	if (!first)
   1171  1.79       mrg 		return;
   1172  1.79       mrg 	first = 0;
   1173  1.38  drochner 
   1174  1.38  drochner 	memset(&inbuf, 0, sizeof(inbuf));
   1175  1.38  drochner 	memset(&req, 0, sizeof(req));
   1176  1.38  drochner 
   1177  1.38  drochner 	req.flags = ATACMD_READ;
   1178  1.38  drochner 	req.command = WDCC_IDENTIFY;
   1179  1.56  jakllsch 	req.databuf = &inbuf;
   1180  1.38  drochner 	req.datalen = sizeof(inbuf);
   1181  1.38  drochner 	req.timeout = 1000;
   1182  1.38  drochner 
   1183  1.38  drochner 	ata_command(&req);
   1184  1.38  drochner 
   1185  1.79       mrg 	inqbuf = &inbuf.inqbuf;
   1186  1.38  drochner }
   1187  1.38  drochner 
   1188  1.15     soren /*
   1189  1.15     soren  * is_smart:
   1190  1.15     soren  *
   1191  1.15     soren  *	Detect whether device supports SMART and SMART is enabled.
   1192  1.15     soren  */
   1193  1.15     soren 
   1194  1.60     joerg static int
   1195  1.20   mycroft is_smart(void)
   1196  1.15     soren {
   1197  1.15     soren 	int retval = 0;
   1198  1.39  christos 	const char *status;
   1199  1.15     soren 
   1200  1.79       mrg 	fillataparams();
   1201  1.15     soren 
   1202  1.15     soren 	if (inqbuf->atap_cmd_def != 0 && inqbuf->atap_cmd_def != 0xffff) {
   1203  1.15     soren 		if (!(inqbuf->atap_cmd_set1 & WDC_CMD1_SMART)) {
   1204  1.15     soren 			fprintf(stderr, "SMART unsupported\n");
   1205  1.15     soren 		} else {
   1206  1.15     soren 			if (inqbuf->atap_ata_major <= WDC_VER_ATA5 ||
   1207  1.15     soren 			    inqbuf->atap_cmd_set2 == 0xffff ||
   1208  1.15     soren 			    inqbuf->atap_cmd_set2 == 0x0000) {
   1209  1.15     soren 				status = "status unknown";
   1210  1.15     soren 				retval = 2;
   1211  1.15     soren 			} else {
   1212  1.18   mycroft 				if (inqbuf->atap_cmd1_en & WDC_CMD1_SMART) {
   1213  1.15     soren 					status = "enabled";
   1214  1.15     soren 					retval = 1;
   1215  1.15     soren 				} else {
   1216  1.15     soren 					status = "disabled";
   1217  1.43   xtraeme 					retval = 3;
   1218  1.15     soren 				}
   1219  1.15     soren 			}
   1220  1.20   mycroft 			printf("SMART supported, SMART %s\n", status);
   1221  1.15     soren 		}
   1222  1.15     soren 	}
   1223  1.15     soren 	return retval;
   1224  1.15     soren }
   1225  1.51  dholland 
   1226  1.51  dholland /*
   1227  1.51  dholland  * extract_string: copy a block of bytes out of ataparams and make
   1228  1.51  dholland  * a proper string out of it, truncating trailing spaces and preserving
   1229  1.51  dholland  * strict typing. And also, not doing unaligned accesses.
   1230  1.51  dholland  */
   1231  1.51  dholland static void
   1232  1.51  dholland extract_string(char *buf, size_t bufmax,
   1233  1.66  jakllsch 	       const uint8_t *bytes, size_t numbytes,
   1234  1.51  dholland 	       int needswap)
   1235  1.51  dholland {
   1236  1.51  dholland 	unsigned i;
   1237  1.51  dholland 	size_t j;
   1238  1.51  dholland 	unsigned char ch1, ch2;
   1239  1.51  dholland 
   1240  1.51  dholland 	for (i = 0, j = 0; i < numbytes; i += 2) {
   1241  1.51  dholland 		ch1 = bytes[i];
   1242  1.51  dholland 		ch2 = bytes[i+1];
   1243  1.51  dholland 		if (needswap && j < bufmax-1) {
   1244  1.51  dholland 			buf[j++] = ch2;
   1245  1.51  dholland 		}
   1246  1.51  dholland 		if (j < bufmax-1) {
   1247  1.51  dholland 			buf[j++] = ch1;
   1248  1.51  dholland 		}
   1249  1.51  dholland 		if (!needswap && j < bufmax-1) {
   1250  1.51  dholland 			buf[j++] = ch2;
   1251  1.51  dholland 		}
   1252  1.51  dholland 	}
   1253  1.51  dholland 	while (j > 0 && buf[j-1] == ' ') {
   1254  1.51  dholland 		j--;
   1255  1.51  dholland 	}
   1256  1.51  dholland 	buf[j] = '\0';
   1257  1.51  dholland }
   1258  1.51  dholland 
   1259  1.68  riastrad static void
   1260  1.79       mrg compute_capacity(uint64_t *capacityp, uint64_t *sectorsp, uint32_t *secsizep)
   1261  1.68  riastrad {
   1262  1.68  riastrad 	uint64_t capacity;
   1263  1.68  riastrad 	uint64_t sectors;
   1264  1.68  riastrad 	uint32_t secsize;
   1265  1.68  riastrad 
   1266  1.68  riastrad 	if (inqbuf->atap_cmd2_en != 0 && inqbuf->atap_cmd2_en != 0xffff &&
   1267  1.68  riastrad 	    inqbuf->atap_cmd2_en & ATA_CMD2_LBA48) {
   1268  1.68  riastrad 		sectors =
   1269  1.68  riastrad 		    ((uint64_t)inqbuf->atap_max_lba[3] << 48) |
   1270  1.68  riastrad 		    ((uint64_t)inqbuf->atap_max_lba[2] << 32) |
   1271  1.68  riastrad 		    ((uint64_t)inqbuf->atap_max_lba[1] << 16) |
   1272  1.68  riastrad 		    ((uint64_t)inqbuf->atap_max_lba[0] <<  0);
   1273  1.68  riastrad 	} else if (inqbuf->atap_capabilities1 & WDC_CAP_LBA) {
   1274  1.68  riastrad 		sectors = (inqbuf->atap_capacity[1] << 16) |
   1275  1.68  riastrad 		    inqbuf->atap_capacity[0];
   1276  1.68  riastrad 	} else {
   1277  1.68  riastrad 		sectors = inqbuf->atap_cylinders *
   1278  1.68  riastrad 		    inqbuf->atap_heads * inqbuf->atap_sectors;
   1279  1.68  riastrad 	}
   1280  1.68  riastrad 
   1281  1.68  riastrad 	secsize = 512;
   1282  1.68  riastrad 
   1283  1.68  riastrad 	if ((inqbuf->atap_secsz & ATA_SECSZ_VALID_MASK) == ATA_SECSZ_VALID) {
   1284  1.68  riastrad 		if (inqbuf->atap_secsz & ATA_SECSZ_LLS) {
   1285  1.68  riastrad 			secsize = 2 *		/* words to bytes */
   1286  1.68  riastrad 			    (inqbuf->atap_lls_secsz[1] << 16 |
   1287  1.68  riastrad 			    inqbuf->atap_lls_secsz[0] <<  0);
   1288  1.68  riastrad 		}
   1289  1.68  riastrad 	}
   1290  1.68  riastrad 
   1291  1.68  riastrad 	capacity = sectors * secsize;
   1292  1.68  riastrad 
   1293  1.68  riastrad 	if (capacityp)
   1294  1.68  riastrad 		*capacityp = capacity;
   1295  1.68  riastrad 	if (sectorsp)
   1296  1.68  riastrad 		*sectorsp = sectors;
   1297  1.68  riastrad 	if (secsizep)
   1298  1.68  riastrad 		*secsizep = secsize;
   1299  1.68  riastrad }
   1300  1.68  riastrad 
   1301  1.15     soren /*
   1302  1.79       mrg  * Inspect the inqbuf and guess what vendor to use.  This list is fairly
   1303  1.79       mrg  * basic, and probably should be converted into a regexp scheme.
   1304   1.1      kenh  */
   1305  1.79       mrg static const char *
   1306  1.79       mrg guess_vendor(void)
   1307  1.79       mrg {
   1308  1.80       mrg 
   1309  1.79       mrg 	unsigned i;
   1310  1.79       mrg 
   1311  1.79       mrg 	for (i = 0; i < __arraycount(model_to_vendor); i++)
   1312  1.79       mrg 		if (strncasecmp(model, model_to_vendor[i].model,
   1313  1.79       mrg 				strlen(model_to_vendor[i].model)) == 0)
   1314  1.79       mrg 			return model_to_vendor[i].vendor;
   1315  1.79       mrg 
   1316  1.79       mrg 	return NULL;
   1317  1.79       mrg }
   1318   1.1      kenh 
   1319   1.1      kenh /*
   1320  1.79       mrg  * identify_fixup() - Given an obtained ataparams, fix up the endian and
   1321  1.79       mrg  * other issues before using them.
   1322   1.1      kenh  */
   1323  1.60     joerg static void
   1324  1.79       mrg identify_fixup(void)
   1325   1.1      kenh {
   1326  1.51  dholland 	int needswap = 0;
   1327   1.1      kenh 
   1328  1.56  jakllsch 	if ((inqbuf->atap_integrity & WDC_INTEGRITY_MAGIC_MASK) ==
   1329  1.56  jakllsch 	    WDC_INTEGRITY_MAGIC) {
   1330  1.79       mrg 		int i;
   1331  1.79       mrg 		uint8_t checksum;
   1332  1.79       mrg 
   1333  1.56  jakllsch 		for (i = checksum = 0; i < 512; i++)
   1334  1.66  jakllsch 			checksum += ((const uint8_t *)inqbuf)[i];
   1335  1.56  jakllsch 		if (checksum != 0)
   1336  1.56  jakllsch 			puts("IDENTIFY DEVICE data checksum invalid\n");
   1337  1.56  jakllsch 	}
   1338  1.56  jakllsch 
   1339   1.1      kenh #if BYTE_ORDER == LITTLE_ENDIAN
   1340   1.1      kenh 	/*
   1341   1.1      kenh 	 * On little endian machines, we need to shuffle the string
   1342   1.1      kenh 	 * byte order.  However, we don't have to do this for NEC or
   1343   1.1      kenh 	 * Mitsumi ATAPI devices
   1344   1.1      kenh 	 */
   1345   1.1      kenh 
   1346  1.72  drochner 	if (!(inqbuf->atap_config != WDC_CFG_CFA_MAGIC &&
   1347  1.72  drochner 	      (inqbuf->atap_config & WDC_CFG_ATAPI) &&
   1348   1.1      kenh 	      ((inqbuf->atap_model[0] == 'N' &&
   1349   1.1      kenh 		  inqbuf->atap_model[1] == 'E') ||
   1350   1.1      kenh 	       (inqbuf->atap_model[0] == 'F' &&
   1351   1.1      kenh 		  inqbuf->atap_model[1] == 'X')))) {
   1352  1.51  dholland 		needswap = 1;
   1353   1.1      kenh 	}
   1354   1.1      kenh #endif
   1355   1.1      kenh 
   1356   1.1      kenh 	/*
   1357  1.51  dholland 	 * Copy the info strings out, stripping off blanks.
   1358   1.1      kenh 	 */
   1359  1.51  dholland 	extract_string(model, sizeof(model),
   1360  1.51  dholland 		inqbuf->atap_model, sizeof(inqbuf->atap_model),
   1361  1.51  dholland 		needswap);
   1362  1.51  dholland 	extract_string(revision, sizeof(revision),
   1363  1.51  dholland 		inqbuf->atap_revision, sizeof(inqbuf->atap_revision),
   1364  1.51  dholland 		needswap);
   1365  1.51  dholland 	extract_string(serial, sizeof(serial),
   1366  1.51  dholland 		inqbuf->atap_serial, sizeof(inqbuf->atap_serial),
   1367  1.51  dholland 		needswap);
   1368   1.1      kenh 
   1369  1.79       mrg }
   1370  1.79       mrg 
   1371  1.79       mrg /*
   1372  1.79       mrg  * DEVICE COMMANDS
   1373  1.79       mrg  */
   1374  1.79       mrg 
   1375  1.79       mrg /*
   1376  1.79       mrg  * device_identify:
   1377  1.79       mrg  *
   1378  1.79       mrg  *	Display the identity of the device
   1379  1.79       mrg  */
   1380  1.79       mrg static void
   1381  1.79       mrg device_identify(int argc, char *argv[])
   1382  1.79       mrg {
   1383  1.79       mrg 	char hnum[12];
   1384  1.79       mrg 	uint64_t capacity;
   1385  1.79       mrg 	uint64_t sectors;
   1386  1.79       mrg 	uint32_t secsize;
   1387  1.79       mrg 	int lb_per_pb;
   1388  1.79       mrg 
   1389  1.79       mrg 	/* No arguments. */
   1390  1.79       mrg 	if (argc != 0)
   1391  1.79       mrg 		usage();
   1392  1.79       mrg 
   1393  1.79       mrg 	fillataparams();
   1394  1.79       mrg 	identify_fixup();
   1395  1.79       mrg 
   1396  1.51  dholland 	printf("Model: %s, Rev: %s, Serial #: %s\n",
   1397  1.51  dholland 		model, revision, serial);
   1398   1.1      kenh 
   1399  1.55  jakllsch 	if (inqbuf->atap_cmd_ext != 0 && inqbuf->atap_cmd_ext != 0xffff &&
   1400  1.55  jakllsch 	    inqbuf->atap_cmd_ext & ATA_CMDE_WWN)
   1401  1.55  jakllsch 		printf("World Wide Name: %016" PRIX64 "\n",
   1402  1.55  jakllsch 		    ((uint64_t)inqbuf->atap_wwn[0] << 48) |
   1403  1.55  jakllsch 		    ((uint64_t)inqbuf->atap_wwn[1] << 32) |
   1404  1.55  jakllsch 		    ((uint64_t)inqbuf->atap_wwn[2] << 16) |
   1405  1.55  jakllsch 		    ((uint64_t)inqbuf->atap_wwn[3] <<  0));
   1406  1.55  jakllsch 
   1407  1.72  drochner 	printf("Device type: %s",
   1408  1.72  drochner 		inqbuf->atap_config == WDC_CFG_CFA_MAGIC ? "CF-ATA" :
   1409  1.72  drochner 		 (inqbuf->atap_config & WDC_CFG_ATAPI ? "ATAPI" : "ATA"));
   1410  1.72  drochner 	if (inqbuf->atap_config != WDC_CFG_CFA_MAGIC)
   1411  1.72  drochner 		printf(", %s",
   1412  1.72  drochner 		 inqbuf->atap_config & ATA_CFG_FIXED ? "fixed" : "removable");
   1413  1.72  drochner 	printf("\n");
   1414   1.1      kenh 
   1415  1.79       mrg 	compute_capacity(&capacity, &sectors, &secsize);
   1416  1.56  jakllsch 
   1417  1.56  jakllsch 	humanize_number(hnum, sizeof(hnum), capacity, "bytes",
   1418  1.56  jakllsch 		HN_AUTOSCALE, HN_DIVISOR_1000);
   1419  1.56  jakllsch 
   1420  1.61  jakllsch 	printf("Capacity %s, %" PRIu64 " sectors, %" PRIu32 " bytes/sector\n",
   1421  1.56  jakllsch 		       hnum, sectors, secsize);
   1422  1.56  jakllsch 
   1423  1.56  jakllsch 	printf("Cylinders: %d, heads: %d, sec/track: %d\n",
   1424  1.56  jakllsch 		inqbuf->atap_cylinders, inqbuf->atap_heads,
   1425  1.56  jakllsch 		inqbuf->atap_sectors);
   1426  1.61  jakllsch 
   1427  1.56  jakllsch 	lb_per_pb = 1;
   1428  1.56  jakllsch 
   1429  1.56  jakllsch 	if ((inqbuf->atap_secsz & ATA_SECSZ_VALID_MASK) == ATA_SECSZ_VALID) {
   1430  1.56  jakllsch 		if (inqbuf->atap_secsz & ATA_SECSZ_LPS) {
   1431  1.56  jakllsch 			lb_per_pb <<= inqbuf->atap_secsz & ATA_SECSZ_LPS_SZMSK;
   1432  1.56  jakllsch 			printf("Physical sector size: %d bytes\n",
   1433  1.56  jakllsch 			    lb_per_pb * secsize);
   1434  1.56  jakllsch 			if ((inqbuf->atap_logical_align &
   1435  1.56  jakllsch 			    ATA_LA_VALID_MASK) == ATA_LA_VALID) {
   1436  1.56  jakllsch 				printf("First physically aligned sector: %d\n",
   1437  1.86  jakllsch 				    inqbuf->atap_logical_align & ATA_LA_MASK);
   1438  1.56  jakllsch 			}
   1439  1.56  jakllsch 		}
   1440  1.55  jakllsch 	}
   1441   1.1      kenh 
   1442  1.55  jakllsch 	if (((inqbuf->atap_sata_caps & SATA_NATIVE_CMDQ) ||
   1443  1.55  jakllsch 	    (inqbuf->atap_cmd_set2 & ATA_CMD2_RWQ)) &&
   1444  1.55  jakllsch 	    (inqbuf->atap_queuedepth & WDC_QUEUE_DEPTH_MASK))
   1445  1.56  jakllsch 		printf("Command queue depth: %d\n",
   1446  1.55  jakllsch 		    (inqbuf->atap_queuedepth & WDC_QUEUE_DEPTH_MASK) + 1);
   1447   1.1      kenh 
   1448   1.1      kenh 	printf("Device capabilities:\n");
   1449  1.10        is 	print_bitinfo("\t", "\n", inqbuf->atap_capabilities1, ata_caps);
   1450   1.1      kenh 
   1451   1.1      kenh 	if (inqbuf->atap_ata_major != 0 && inqbuf->atap_ata_major != 0xffff) {
   1452   1.1      kenh 		printf("Device supports following standards:\n");
   1453  1.10        is 		print_bitinfo("", " ", inqbuf->atap_ata_major, ata_vers);
   1454   1.1      kenh 		printf("\n");
   1455   1.1      kenh 	}
   1456   1.1      kenh 
   1457   1.1      kenh 	if (inqbuf->atap_cmd_set1 != 0 && inqbuf->atap_cmd_set1 != 0xffff &&
   1458   1.1      kenh 	    inqbuf->atap_cmd_set2 != 0 && inqbuf->atap_cmd_set2 != 0xffff) {
   1459   1.1      kenh 		printf("Command set support:\n");
   1460  1.33   mycroft 		if (inqbuf->atap_cmd1_en != 0 && inqbuf->atap_cmd1_en != 0xffff)
   1461  1.33   mycroft 			print_bitinfo2("\t", "\n", inqbuf->atap_cmd_set1,
   1462  1.33   mycroft 			    inqbuf->atap_cmd1_en, ata_cmd_set1);
   1463  1.33   mycroft 		else
   1464  1.33   mycroft 			print_bitinfo("\t", "\n", inqbuf->atap_cmd_set1,
   1465  1.33   mycroft 			    ata_cmd_set1);
   1466  1.33   mycroft 		if (inqbuf->atap_cmd2_en != 0 && inqbuf->atap_cmd2_en != 0xffff)
   1467  1.33   mycroft 			print_bitinfo2("\t", "\n", inqbuf->atap_cmd_set2,
   1468  1.33   mycroft 			    inqbuf->atap_cmd2_en, ata_cmd_set2);
   1469  1.33   mycroft 		else
   1470  1.33   mycroft 			print_bitinfo("\t", "\n", inqbuf->atap_cmd_set2,
   1471  1.33   mycroft 			    ata_cmd_set2);
   1472  1.23      yamt 		if (inqbuf->atap_cmd_ext != 0 && inqbuf->atap_cmd_ext != 0xffff)
   1473  1.23      yamt 			print_bitinfo("\t", "\n", inqbuf->atap_cmd_ext,
   1474  1.23      yamt 			    ata_cmd_ext);
   1475   1.1      kenh 	}
   1476   1.1      kenh 
   1477  1.46    bouyer 	if (inqbuf->atap_sata_caps != 0 && inqbuf->atap_sata_caps != 0xffff) {
   1478  1.46    bouyer 		printf("Serial ATA capabilities:\n");
   1479  1.55  jakllsch 		print_bitinfo("\t", "\n",
   1480  1.55  jakllsch 		    inqbuf->atap_sata_caps, ata_sata_caps);
   1481  1.55  jakllsch 
   1482  1.46    bouyer 	}
   1483  1.46    bouyer 
   1484  1.55  jakllsch 	if (inqbuf->atap_sata_features_supp != 0 &&
   1485  1.55  jakllsch 	    inqbuf->atap_sata_features_supp != 0xffff) {
   1486  1.46    bouyer 		printf("Serial ATA features:\n");
   1487  1.55  jakllsch 		if (inqbuf->atap_sata_features_en != 0 &&
   1488  1.55  jakllsch 		    inqbuf->atap_sata_features_en != 0xffff)
   1489  1.55  jakllsch 			print_bitinfo2("\t", "\n",
   1490  1.55  jakllsch 			    inqbuf->atap_sata_features_supp,
   1491  1.55  jakllsch 			    inqbuf->atap_sata_features_en, ata_sata_feat);
   1492  1.46    bouyer 		else
   1493  1.55  jakllsch 			print_bitinfo("\t", "\n",
   1494  1.55  jakllsch 			    inqbuf->atap_sata_features_supp, ata_sata_feat);
   1495  1.46    bouyer 	}
   1496  1.46    bouyer 
   1497  1.71     soren 	if ((inqbuf->atap_ata_major & WDC_VER_ATA7) &&
   1498  1.67  drochner 	    (inqbuf->support_dsm & ATA_SUPPORT_DSM_TRIM))
   1499  1.67  drochner 		printf("TRIM supported\n");
   1500  1.67  drochner 
   1501   1.1      kenh 	return;
   1502   1.1      kenh }
   1503   1.1      kenh 
   1504   1.1      kenh /*
   1505   1.1      kenh  * device idle:
   1506   1.1      kenh  *
   1507   1.1      kenh  * issue the IDLE IMMEDIATE command to the drive
   1508   1.1      kenh  */
   1509  1.60     joerg static void
   1510  1.13    simonb device_idle(int argc, char *argv[])
   1511   1.1      kenh {
   1512   1.1      kenh 	struct atareq req;
   1513   1.1      kenh 
   1514   1.1      kenh 	/* No arguments. */
   1515   1.1      kenh 	if (argc != 0)
   1516   1.5     soren 		usage();
   1517   1.1      kenh 
   1518   1.1      kenh 	memset(&req, 0, sizeof(req));
   1519   1.1      kenh 
   1520   1.1      kenh 	if (strcmp(cmdname, "idle") == 0)
   1521   1.1      kenh 		req.command = WDCC_IDLE_IMMED;
   1522   1.1      kenh 	else if (strcmp(cmdname, "standby") == 0)
   1523   1.1      kenh 		req.command = WDCC_STANDBY_IMMED;
   1524   1.1      kenh 	else
   1525   1.1      kenh 		req.command = WDCC_SLEEP;
   1526   1.1      kenh 
   1527   1.1      kenh 	req.timeout = 1000;
   1528   1.1      kenh 
   1529   1.1      kenh 	ata_command(&req);
   1530   1.1      kenh 
   1531   1.1      kenh 	return;
   1532   1.1      kenh }
   1533   1.1      kenh 
   1534   1.1      kenh /*
   1535  1.48  christos  * device apm:
   1536  1.48  christos  *
   1537  1.48  christos  * enable/disable/control the APM feature of the drive
   1538  1.48  christos  */
   1539  1.60     joerg static void
   1540  1.48  christos device_apm(int argc, char *argv[])
   1541  1.48  christos {
   1542  1.48  christos 	struct atareq req;
   1543  1.48  christos 	long l;
   1544  1.48  christos 
   1545  1.48  christos 	memset(&req, 0, sizeof(req));
   1546  1.48  christos 	if (argc >= 1) {
   1547  1.48  christos 		req.command = SET_FEATURES;
   1548  1.48  christos 		req.timeout = 1000;
   1549  1.61  jakllsch 
   1550  1.48  christos 		if (strcmp(argv[0], "disable") == 0)
   1551  1.48  christos 			req.features = WDSF_APM_DS;
   1552  1.48  christos 		else if (strcmp(argv[0], "set") == 0 && argc >= 2 &&
   1553  1.48  christos 		         (l = strtol(argv[1], NULL, 0)) >= 0 && l <= 253) {
   1554  1.61  jakllsch 
   1555  1.48  christos 			req.features = WDSF_APM_EN;
   1556  1.48  christos 			req.sec_count = l + 1;
   1557  1.48  christos 		} else
   1558  1.48  christos 			usage();
   1559  1.48  christos 	} else
   1560  1.48  christos 		usage();
   1561  1.61  jakllsch 
   1562  1.48  christos 	ata_command(&req);
   1563  1.48  christos }
   1564  1.61  jakllsch 
   1565  1.48  christos 
   1566  1.48  christos /*
   1567   1.1      kenh  * Set the idle timer on the disk.  Set it for either idle mode or
   1568   1.1      kenh  * standby mode, depending on how we were invoked.
   1569   1.1      kenh  */
   1570   1.1      kenh 
   1571  1.60     joerg static void
   1572  1.13    simonb device_setidle(int argc, char *argv[])
   1573   1.1      kenh {
   1574   1.1      kenh 	unsigned long idle;
   1575   1.1      kenh 	struct atareq req;
   1576   1.1      kenh 	char *end;
   1577   1.1      kenh 
   1578   1.1      kenh 	/* Only one argument */
   1579   1.1      kenh 	if (argc != 1)
   1580   1.5     soren 		usage();
   1581   1.1      kenh 
   1582   1.1      kenh 	idle = strtoul(argv[0], &end, 0);
   1583   1.1      kenh 
   1584   1.1      kenh 	if (*end != '\0') {
   1585   1.1      kenh 		fprintf(stderr, "Invalid idle time: \"%s\"\n", argv[0]);
   1586   1.1      kenh 		exit(1);
   1587   1.1      kenh 	}
   1588   1.1      kenh 
   1589   1.1      kenh 	if (idle > 19800) {
   1590   1.1      kenh 		fprintf(stderr, "Idle time has a maximum value of 5.5 "
   1591   1.1      kenh 			"hours\n");
   1592   1.1      kenh 		exit(1);
   1593   1.1      kenh 	}
   1594   1.1      kenh 
   1595   1.1      kenh 	if (idle != 0 && idle < 5) {
   1596   1.1      kenh 		fprintf(stderr, "Idle timer must be at least 5 seconds\n");
   1597   1.1      kenh 		exit(1);
   1598   1.1      kenh 	}
   1599   1.1      kenh 
   1600   1.1      kenh 	memset(&req, 0, sizeof(req));
   1601   1.1      kenh 
   1602   1.1      kenh 	if (idle <= 240*5)
   1603   1.1      kenh 		req.sec_count = idle / 5;
   1604   1.1      kenh 	else
   1605   1.1      kenh 		req.sec_count = idle / (30*60) + 240;
   1606   1.1      kenh 
   1607   1.1      kenh 	req.command = cmdname[3] == 's' ? WDCC_STANDBY : WDCC_IDLE;
   1608   1.1      kenh 	req.timeout = 1000;
   1609   1.1      kenh 
   1610   1.1      kenh 	ata_command(&req);
   1611   1.1      kenh 
   1612   1.1      kenh 	return;
   1613   1.3      kenh }
   1614   1.3      kenh 
   1615   1.3      kenh /*
   1616   1.3      kenh  * Query the device for the current power mode
   1617   1.3      kenh  */
   1618   1.3      kenh 
   1619  1.60     joerg static void
   1620  1.13    simonb device_checkpower(int argc, char *argv[])
   1621   1.3      kenh {
   1622   1.3      kenh 	struct atareq req;
   1623   1.3      kenh 
   1624   1.3      kenh 	/* No arguments. */
   1625   1.3      kenh 	if (argc != 0)
   1626   1.5     soren 		usage();
   1627   1.3      kenh 
   1628   1.3      kenh 	memset(&req, 0, sizeof(req));
   1629   1.3      kenh 
   1630   1.3      kenh 	req.command = WDCC_CHECK_PWR;
   1631   1.3      kenh 	req.timeout = 1000;
   1632   1.3      kenh 	req.flags = ATACMD_READREG;
   1633   1.3      kenh 
   1634   1.3      kenh 	ata_command(&req);
   1635   1.3      kenh 
   1636   1.3      kenh 	printf("Current power status: ");
   1637   1.3      kenh 
   1638   1.3      kenh 	switch (req.sec_count) {
   1639   1.3      kenh 	case 0x00:
   1640   1.3      kenh 		printf("Standby mode\n");
   1641   1.3      kenh 		break;
   1642   1.3      kenh 	case 0x80:
   1643   1.3      kenh 		printf("Idle mode\n");
   1644   1.3      kenh 		break;
   1645   1.3      kenh 	case 0xff:
   1646   1.3      kenh 		printf("Active mode\n");
   1647   1.3      kenh 		break;
   1648   1.3      kenh 	default:
   1649   1.3      kenh 		printf("Unknown power code (%02x)\n", req.sec_count);
   1650   1.3      kenh 	}
   1651   1.3      kenh 
   1652  1.15     soren 	return;
   1653  1.15     soren }
   1654  1.15     soren 
   1655  1.15     soren /*
   1656  1.15     soren  * device_smart:
   1657  1.15     soren  *
   1658  1.15     soren  *	Display SMART status
   1659  1.15     soren  */
   1660  1.60     joerg static void
   1661  1.15     soren device_smart(int argc, char *argv[])
   1662  1.15     soren {
   1663  1.15     soren 	struct atareq req;
   1664  1.15     soren 	unsigned char inbuf[DEV_BSIZE];
   1665  1.15     soren 	unsigned char inbuf2[DEV_BSIZE];
   1666  1.15     soren 
   1667  1.33   mycroft 	if (argc < 1)
   1668  1.15     soren 		usage();
   1669  1.15     soren 
   1670  1.15     soren 	if (strcmp(argv[0], "enable") == 0) {
   1671  1.20   mycroft 		memset(&req, 0, sizeof(req));
   1672  1.15     soren 
   1673  1.20   mycroft 		req.features = WDSM_ENABLE_OPS;
   1674  1.20   mycroft 		req.command = WDCC_SMART;
   1675  1.35      fvdl 		req.cylinder = WDSMART_CYL;
   1676  1.20   mycroft 		req.timeout = 1000;
   1677  1.15     soren 
   1678  1.20   mycroft 		ata_command(&req);
   1679  1.15     soren 
   1680  1.20   mycroft 		is_smart();
   1681  1.15     soren 	} else if (strcmp(argv[0], "disable") == 0) {
   1682  1.20   mycroft 		memset(&req, 0, sizeof(req));
   1683  1.15     soren 
   1684  1.20   mycroft 		req.features = WDSM_DISABLE_OPS;
   1685  1.20   mycroft 		req.command = WDCC_SMART;
   1686  1.35      fvdl 		req.cylinder = WDSMART_CYL;
   1687  1.20   mycroft 		req.timeout = 1000;
   1688  1.15     soren 
   1689  1.20   mycroft 		ata_command(&req);
   1690  1.15     soren 
   1691  1.20   mycroft 		is_smart();
   1692  1.16     soren 	} else if (strcmp(argv[0], "status") == 0) {
   1693  1.43   xtraeme 		int rv;
   1694  1.79       mrg 		const char *vendor = argc > 1 ? argv[1] : NULL;
   1695  1.43   xtraeme 
   1696  1.43   xtraeme 		rv = is_smart();
   1697  1.43   xtraeme 
   1698  1.43   xtraeme 		if (!rv) {
   1699  1.24       lha 			fprintf(stderr, "SMART not supported\n");
   1700  1.24       lha 			return;
   1701  1.43   xtraeme 		} else if (rv == 3)
   1702  1.43   xtraeme 			return;
   1703  1.24       lha 
   1704  1.43   xtraeme 		memset(&inbuf, 0, sizeof(inbuf));
   1705  1.43   xtraeme 		memset(&req, 0, sizeof(req));
   1706  1.15     soren 
   1707  1.43   xtraeme 		req.features = WDSM_STATUS;
   1708  1.43   xtraeme 		req.command = WDCC_SMART;
   1709  1.43   xtraeme 		req.cylinder = WDSMART_CYL;
   1710  1.43   xtraeme 		req.timeout = 1000;
   1711  1.61  jakllsch 
   1712  1.43   xtraeme 		ata_command(&req);
   1713  1.15     soren 
   1714  1.43   xtraeme 		if (req.cylinder != WDSMART_CYL) {
   1715  1.43   xtraeme 			fprintf(stderr, "Threshold exceeds condition\n");
   1716  1.43   xtraeme 		}
   1717  1.15     soren 
   1718  1.43   xtraeme 		/* WDSM_RD_DATA and WDSM_RD_THRESHOLDS are optional
   1719  1.43   xtraeme 		 * features, the following ata_command()'s may error
   1720  1.43   xtraeme 		 * and exit().
   1721  1.43   xtraeme 		 */
   1722  1.15     soren 
   1723  1.43   xtraeme 		memset(&inbuf, 0, sizeof(inbuf));
   1724  1.43   xtraeme 		memset(&req, 0, sizeof(req));
   1725  1.15     soren 
   1726  1.43   xtraeme 		req.flags = ATACMD_READ;
   1727  1.43   xtraeme 		req.features = WDSM_RD_DATA;
   1728  1.43   xtraeme 		req.command = WDCC_SMART;
   1729  1.43   xtraeme 		req.databuf = (caddr_t) inbuf;
   1730  1.43   xtraeme 		req.datalen = sizeof(inbuf);
   1731  1.43   xtraeme 		req.cylinder = WDSMART_CYL;
   1732  1.43   xtraeme 		req.timeout = 1000;
   1733  1.61  jakllsch 
   1734  1.43   xtraeme 		ata_command(&req);
   1735  1.15     soren 
   1736  1.43   xtraeme 		memset(&inbuf2, 0, sizeof(inbuf2));
   1737  1.43   xtraeme 		memset(&req, 0, sizeof(req));
   1738  1.15     soren 
   1739  1.43   xtraeme 		req.flags = ATACMD_READ;
   1740  1.43   xtraeme 		req.features = WDSM_RD_THRESHOLDS;
   1741  1.43   xtraeme 		req.command = WDCC_SMART;
   1742  1.43   xtraeme 		req.databuf = (caddr_t) inbuf2;
   1743  1.43   xtraeme 		req.datalen = sizeof(inbuf2);
   1744  1.43   xtraeme 		req.cylinder = WDSMART_CYL;
   1745  1.43   xtraeme 		req.timeout = 1000;
   1746  1.15     soren 
   1747  1.43   xtraeme 		ata_command(&req);
   1748  1.15     soren 
   1749  1.79       mrg 		if (!vendor || strcmp(vendor, "noauto") == 0) {
   1750  1.79       mrg 			fillataparams();
   1751  1.79       mrg 			identify_fixup();
   1752  1.79       mrg 			vendor = guess_vendor();
   1753  1.79       mrg 		}
   1754  1.78       mrg 		print_smart_status(inbuf, inbuf2, vendor);
   1755  1.24       lha 
   1756  1.33   mycroft 	} else if (strcmp(argv[0], "offline") == 0) {
   1757  1.34     soren 		if (argc != 2)
   1758  1.34     soren 			usage();
   1759  1.33   mycroft 		if (!is_smart()) {
   1760  1.33   mycroft 			fprintf(stderr, "SMART not supported\n");
   1761  1.33   mycroft 			return;
   1762  1.33   mycroft 		}
   1763  1.33   mycroft 
   1764  1.33   mycroft 		memset(&req, 0, sizeof(req));
   1765  1.33   mycroft 
   1766  1.33   mycroft 		req.features = WDSM_EXEC_OFFL_IMM;
   1767  1.33   mycroft 		req.command = WDCC_SMART;
   1768  1.35      fvdl 		req.cylinder = WDSMART_CYL;
   1769  1.33   mycroft 		req.sec_num = atol(argv[1]);
   1770  1.33   mycroft 		req.timeout = 10000;
   1771  1.33   mycroft 
   1772  1.33   mycroft 		ata_command(&req);
   1773  1.33   mycroft 	} else if (strcmp(argv[0], "error-log") == 0) {
   1774  1.33   mycroft 		if (!is_smart()) {
   1775  1.33   mycroft 			fprintf(stderr, "SMART not supported\n");
   1776  1.33   mycroft 			return;
   1777  1.33   mycroft 		}
   1778  1.33   mycroft 
   1779  1.33   mycroft 		memset(&inbuf, 0, sizeof(inbuf));
   1780  1.33   mycroft 		memset(&req, 0, sizeof(req));
   1781  1.61  jakllsch 
   1782  1.33   mycroft 		req.flags = ATACMD_READ;
   1783  1.33   mycroft 		req.features = WDSM_RD_LOG;
   1784  1.33   mycroft 		req.sec_count = 1;
   1785  1.33   mycroft 		req.sec_num = 1;
   1786  1.33   mycroft 		req.command = WDCC_SMART;
   1787  1.33   mycroft 		req.databuf = (caddr_t) inbuf;
   1788  1.33   mycroft 		req.datalen = sizeof(inbuf);
   1789  1.35      fvdl 		req.cylinder = WDSMART_CYL;
   1790  1.33   mycroft 		req.timeout = 1000;
   1791  1.61  jakllsch 
   1792  1.33   mycroft 		ata_command(&req);
   1793  1.61  jakllsch 
   1794  1.33   mycroft 		print_error(inbuf);
   1795  1.24       lha 	} else if (strcmp(argv[0], "selftest-log") == 0) {
   1796  1.24       lha 		if (!is_smart()) {
   1797  1.15     soren 			fprintf(stderr, "SMART not supported\n");
   1798  1.24       lha 			return;
   1799  1.15     soren 		}
   1800  1.24       lha 
   1801  1.24       lha 		memset(&inbuf, 0, sizeof(inbuf));
   1802  1.24       lha 		memset(&req, 0, sizeof(req));
   1803  1.61  jakllsch 
   1804  1.24       lha 		req.flags = ATACMD_READ;
   1805  1.24       lha 		req.features = WDSM_RD_LOG;
   1806  1.24       lha 		req.sec_count = 1;
   1807  1.24       lha 		req.sec_num = 6;
   1808  1.24       lha 		req.command = WDCC_SMART;
   1809  1.24       lha 		req.databuf = (caddr_t) inbuf;
   1810  1.24       lha 		req.datalen = sizeof(inbuf);
   1811  1.35      fvdl 		req.cylinder = WDSMART_CYL;
   1812  1.24       lha 		req.timeout = 1000;
   1813  1.61  jakllsch 
   1814  1.24       lha 		ata_command(&req);
   1815  1.61  jakllsch 
   1816  1.24       lha 		print_selftest(inbuf);
   1817  1.24       lha 
   1818  1.15     soren 	} else {
   1819  1.15     soren 		usage();
   1820  1.15     soren 	}
   1821   1.3      kenh 	return;
   1822   1.1      kenh }
   1823  1.30    bouyer 
   1824  1.60     joerg static void
   1825  1.38  drochner device_security(int argc, char *argv[])
   1826  1.38  drochner {
   1827  1.38  drochner 	struct atareq req;
   1828  1.68  riastrad 	unsigned char data[DEV_BSIZE];
   1829  1.68  riastrad 	char *pass;
   1830  1.38  drochner 
   1831  1.38  drochner 	/* need subcommand */
   1832  1.38  drochner 	if (argc < 1)
   1833  1.38  drochner 		usage();
   1834  1.38  drochner 
   1835  1.68  riastrad 	memset(&req, 0, sizeof(req));
   1836  1.68  riastrad 	if (strcmp(argv[0], "status") == 0) {
   1837  1.79       mrg 		fillataparams();
   1838  1.68  riastrad 		print_bitinfo("\t", "\n", inqbuf->atap_sec_st, ata_sec_st);
   1839  1.68  riastrad 	} else if (strcmp(argv[0], "freeze") == 0) {
   1840  1.44   xtraeme 		req.command = WDCC_SECURITY_FREEZE;
   1841  1.38  drochner 		req.timeout = 1000;
   1842  1.38  drochner 		ata_command(&req);
   1843  1.68  riastrad 	} else if ((strcmp(argv[0], "setpass") == 0) ||
   1844  1.68  riastrad 	    (strcmp(argv[0], "unlock") == 0) ||
   1845  1.68  riastrad 	    (strcmp(argv[0], "disable") == 0) ||
   1846  1.68  riastrad 	    (strcmp(argv[0], "erase") == 0)) {
   1847  1.68  riastrad 		if (argc != 2)
   1848  1.68  riastrad 			usage();
   1849  1.68  riastrad 		if (strcmp(argv[1], "user") != 0) {
   1850  1.68  riastrad 			if (strcmp(argv[1], "master") == 0) {
   1851  1.68  riastrad 				fprintf(stderr,
   1852  1.68  riastrad 				    "Master passwords not supported\n");
   1853  1.68  riastrad 				exit(1);
   1854  1.68  riastrad 			} else {
   1855  1.68  riastrad 				usage();
   1856  1.68  riastrad 			}
   1857  1.68  riastrad 		}
   1858  1.68  riastrad 
   1859  1.68  riastrad 		pass = getpass("Password:");
   1860  1.68  riastrad 		if (strlen(pass) > 32) {
   1861  1.68  riastrad 			fprintf(stderr, "Password must be <=32 characters\n");
   1862  1.68  riastrad 			exit(1);
   1863  1.68  riastrad 		}
   1864  1.68  riastrad 
   1865  1.68  riastrad 		req.flags |= ATACMD_WRITE;
   1866  1.68  riastrad 		req.timeout = 1000;
   1867  1.68  riastrad 		req.databuf = data;
   1868  1.68  riastrad 		req.datalen = sizeof(data);
   1869  1.68  riastrad 		memset(data, 0, sizeof(data));
   1870  1.68  riastrad 		strlcpy((void *)&data[2], pass, 32 + 1);
   1871  1.68  riastrad 
   1872  1.68  riastrad 		if (strcmp(argv[0], "setpass") == 0) {
   1873  1.68  riastrad 			char orig[32 + 1];
   1874  1.68  riastrad 			strlcpy(orig, pass, 32 + 1);
   1875  1.68  riastrad 			pass = getpass("Confirm password:");
   1876  1.68  riastrad 			if (0 != strcmp(orig, pass)) {
   1877  1.68  riastrad 				fprintf(stderr, "Passwords do not match\n");
   1878  1.68  riastrad 				exit(1);
   1879  1.68  riastrad 			}
   1880  1.68  riastrad 			req.command = WDCC_SECURITY_SET_PASSWORD;
   1881  1.68  riastrad 		} else if (strcmp(argv[0], "unlock") == 0) {
   1882  1.68  riastrad 			req.command = WDCC_SECURITY_UNLOCK;
   1883  1.68  riastrad 		} else if (strcmp(argv[0], "disable") == 0) {
   1884  1.68  riastrad 			req.command = WDCC_SECURITY_DISABLE_PASSWORD;
   1885  1.68  riastrad 		} else if (strcmp(argv[0], "erase") == 0) {
   1886  1.68  riastrad 			struct atareq prepare;
   1887  1.68  riastrad 
   1888  1.79       mrg 			fillataparams();
   1889  1.68  riastrad 
   1890  1.68  riastrad 			/*
   1891  1.68  riastrad 			 * XXX Any way to lock the device to make sure
   1892  1.68  riastrad 			 * this really is the command preceding the
   1893  1.68  riastrad 			 * SECURITY ERASE UNIT command?  This would
   1894  1.68  riastrad 			 * probably have to be moved into the kernel to
   1895  1.68  riastrad 			 * do that.
   1896  1.68  riastrad 			 */
   1897  1.68  riastrad 			memset(&prepare, 0, sizeof(prepare));
   1898  1.68  riastrad 			prepare.command = WDCC_SECURITY_ERASE_PREPARE;
   1899  1.68  riastrad 			prepare.timeout = 1000;
   1900  1.68  riastrad 			ata_command(&prepare);
   1901  1.68  riastrad 
   1902  1.68  riastrad 			req.command = WDCC_SECURITY_ERASE_UNIT;
   1903  1.68  riastrad 
   1904  1.68  riastrad 			/*
   1905  1.68  riastrad 			 * Enable enhanced erase if it's supported.
   1906  1.68  riastrad 			 *
   1907  1.68  riastrad 			 * XXX should be a command-line option
   1908  1.68  riastrad 			 */
   1909  1.68  riastrad 			if (inqbuf->atap_sec_st & WDC_SEC_ESE_SUPP) {
   1910  1.68  riastrad 				data[0] |= 0x2;
   1911  1.68  riastrad 				req.timeout = (inqbuf->atap_eseu_time & 0xff)
   1912  1.68  riastrad 				    * 2 * 60 * 1000;
   1913  1.68  riastrad 			} else {
   1914  1.68  riastrad 				req.timeout = (inqbuf->atap_seu_time & 0xff)
   1915  1.68  riastrad 				    * 2 * 60 * 1000;
   1916  1.68  riastrad 			}
   1917  1.68  riastrad 
   1918  1.68  riastrad 			/*
   1919  1.68  riastrad 			 * If the estimated time was 0xff (* 2 * 60 *
   1920  1.68  riastrad 			 * 1000 = 30600000), that means `>508 minutes'.
   1921  1.68  riastrad 			 * Estimate that we can handle 16 MB/sec, a
   1922  1.68  riastrad 			 * rate I just pulled out of my arse.
   1923  1.68  riastrad 			 */
   1924  1.68  riastrad 			if (req.timeout == 30600000) {
   1925  1.68  riastrad 				uint64_t bytes, timeout;
   1926  1.79       mrg 				compute_capacity(&bytes, NULL, NULL);
   1927  1.68  riastrad 				timeout = (bytes / (16 * 1024 * 1024)) * 1000;
   1928  1.68  riastrad 				if (timeout > (uint64_t)INT_MAX)
   1929  1.68  riastrad 					req.timeout = INT_MAX;
   1930  1.68  riastrad 				else
   1931  1.68  riastrad 					req.timeout = timeout;
   1932  1.68  riastrad 			}
   1933  1.68  riastrad 
   1934  1.68  riastrad 			printf("Erasing may take up to %dh %dm %ds...\n",
   1935  1.68  riastrad 			    (req.timeout / 1000 / 60) / 60,
   1936  1.68  riastrad 			    (req.timeout / 1000 / 60) % 60,
   1937  1.68  riastrad 			    req.timeout % 60);
   1938  1.68  riastrad 		} else {
   1939  1.68  riastrad 			abort();
   1940  1.68  riastrad 		}
   1941  1.68  riastrad 
   1942  1.68  riastrad 		ata_command(&req);
   1943  1.68  riastrad 	} else {
   1944  1.38  drochner 		usage();
   1945  1.68  riastrad 	}
   1946  1.38  drochner }
   1947  1.38  drochner 
   1948  1.30    bouyer /*
   1949  1.30    bouyer  * bus_reset:
   1950  1.30    bouyer  *	Reset an ATA bus (will reset all devices on the bus)
   1951  1.30    bouyer  */
   1952  1.60     joerg static void
   1953  1.30    bouyer bus_reset(int argc, char *argv[])
   1954  1.30    bouyer {
   1955  1.30    bouyer 	int error;
   1956  1.30    bouyer 
   1957  1.30    bouyer 	/* no args */
   1958  1.30    bouyer 	if (argc != 0)
   1959  1.30    bouyer 		usage();
   1960  1.30    bouyer 
   1961  1.30    bouyer 	error = ioctl(fd, ATABUSIORESET, NULL);
   1962  1.30    bouyer 
   1963  1.30    bouyer 	if (error == -1)
   1964  1.30    bouyer 		err(1, "ATABUSIORESET failed");
   1965  1.30    bouyer }
   1966