summaryrefslogtreecommitdiffstats
path: root/atacmds.h
blob: 6bdf0b6110fa87abcd10343693832b60654c9874 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
/*
 * atacmds.h
 *
 * Home page of code is: https://www.smartmontools.org
 *
 * Copyright (C) 2002-11 Bruce Allen
 * Copyright (C) 2008-19 Christian Franke
 * Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org>
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */

#ifndef ATACMDS_H_
#define ATACMDS_H_

#define ATACMDS_H_CVSID "$Id: atacmds.h 5166 2021-01-15 18:02:19Z chrfranke $"

#include "dev_interface.h" // ata_device
#include "static_assert.h"

// Add __attribute__((packed)) if compiler supports it
// because some gcc versions (at least ARM) lack support of #pragma pack()
#ifdef HAVE_ATTR_PACKED
#define ATTR_PACKED __attribute__((packed))
#else
#define ATTR_PACKED
#endif

typedef enum {
  // returns no data, just succeeds or fails
  ENABLE,
  DISABLE,
  AUTOSAVE,
  IMMEDIATE_OFFLINE,
  AUTO_OFFLINE,
  STATUS,       // just says if SMART is working or not
  STATUS_CHECK, // says if disk's SMART status is healthy, or failing
  // return 512 bytes of data:
  READ_VALUES,
  READ_THRESHOLDS,
  READ_LOG,
  IDENTIFY,
  PIDENTIFY,
  // returns 1 byte of data
  CHECK_POWER_MODE,
  // writes 512 bytes of data:
  WRITE_LOG
} smart_command_set;


// ATA Specification Command Register Values (Commands)
#define ATA_CHECK_POWER_MODE            0xe5
#define ATA_IDENTIFY_DEVICE             0xec
#define ATA_IDENTIFY_PACKET_DEVICE      0xa1
#define ATA_IDLE                        0xe3
#define ATA_SMART_CMD                   0xb0
#define ATA_SECURITY_FREEZE_LOCK        0xf5
#ifndef ATA_SET_FEATURES
#define ATA_SET_FEATURES                0xef
#endif
#define ATA_STANDBY                     0xe2
#define ATA_STANDBY_IMMEDIATE           0xe0

// SET_FEATURES subcommands
#define ATA_DISABLE_AAM                 0xc2
#define ATA_DISABLE_APM                 0x85
#define ATA_DISABLE_WRITE_CACHE         0x82
#define ATA_DISABLE_READ_LOOK_AHEAD     0x55
#define ATA_ENABLE_AAM                  0x42
#define ATA_ENABLE_APM                  0x05
#define ATA_ENABLE_WRITE_CACHE          0x02
#define ATA_ENABLE_READ_LOOK_AHEAD      0xaa
#define ATA_ENABLE_DISABLE_DSN          0x63

// 48-bit commands
#define ATA_READ_LOG_EXT                0x2F
#define ATA_WRITE_LOG_EXT               0x3f

// ATA Specification Feature Register Values (SMART Subcommands).
// Note that some are obsolete as of ATA-7.
#define ATA_SMART_READ_VALUES           0xd0
#define ATA_SMART_READ_THRESHOLDS       0xd1
#define ATA_SMART_AUTOSAVE              0xd2
#define ATA_SMART_SAVE                  0xd3
#define ATA_SMART_IMMEDIATE_OFFLINE     0xd4
#define ATA_SMART_READ_LOG_SECTOR       0xd5
#define ATA_SMART_WRITE_LOG_SECTOR      0xd6
#define ATA_SMART_WRITE_THRESHOLDS      0xd7
#define ATA_SMART_ENABLE                0xd8
#define ATA_SMART_DISABLE               0xd9
#define ATA_SMART_STATUS                0xda
// SFF 8035i Revision 2 Specification Feature Register Value (SMART
// Subcommand)
#define ATA_SMART_AUTO_OFFLINE          0xdb

// Sector Number values for ATA_SMART_IMMEDIATE_OFFLINE Subcommand
#define OFFLINE_FULL_SCAN               0
#define SHORT_SELF_TEST                 1
#define EXTEND_SELF_TEST                2
#define CONVEYANCE_SELF_TEST            3
#define SELECTIVE_SELF_TEST             4
#define ABORT_SELF_TEST                 127
#define SHORT_CAPTIVE_SELF_TEST         129
#define EXTEND_CAPTIVE_SELF_TEST        130
#define CONVEYANCE_CAPTIVE_SELF_TEST    131
#define SELECTIVE_CAPTIVE_SELF_TEST     132
#define CAPTIVE_MASK                    (0x01<<7)

// Maximum allowed number of SMART Attributes
#define NUMBER_ATA_SMART_ATTRIBUTES     30

// Needed parts of the ATA DRIVE IDENTIFY Structure. Those labeled
// word* are NOT used.
#pragma pack(1)
struct ata_identify_device {
  unsigned short words000_009[10];
  unsigned char  serial_no[20];
  unsigned short words020_022[3];
  unsigned char  fw_rev[8];
  unsigned char  model[40];
  unsigned short words047_079[33];
  unsigned short major_rev_num;
  unsigned short minor_rev_num;
  unsigned short command_set_1;
  unsigned short command_set_2;
  unsigned short command_set_extension;
  unsigned short cfs_enable_1;
  unsigned short word086;
  unsigned short csf_default;
  unsigned short words088_255[168];
} ATTR_PACKED;
#pragma pack()
STATIC_ASSERT(sizeof(ata_identify_device) == 512);

/* ata_smart_attribute is the vendor specific in SFF-8035 spec */ 
#pragma pack(1)
struct ata_smart_attribute {
  unsigned char id;
  // meaning of flag bits: see MACROS just below
  // WARNING: MISALIGNED!
  unsigned short flags; 
  unsigned char current;
  unsigned char worst;
  unsigned char raw[6];
  unsigned char reserv;
} ATTR_PACKED;
#pragma pack()
STATIC_ASSERT(sizeof(ata_smart_attribute) == 12);

// MACROS to interpret the flags bits in the previous structure.
// These have not been implemented using bitflags and a union, to make
// it portable across bit/little endian and different platforms.

// 0: Prefailure bit

// From SFF 8035i Revision 2 page 19: Bit 0 (pre-failure/advisory bit)
// - If the value of this bit equals zero, an attribute value less
// than or equal to its corresponding attribute threshold indicates an
// advisory condition where the usage or age of the device has
// exceeded its intended design life period. If the value of this bit
// equals one, an attribute value less than or equal to its
// corresponding attribute threshold indicates a prefailure condition
// where imminent loss of data is being predicted.
#define ATTRIBUTE_FLAGS_PREFAILURE(x) (x & 0x01)

// 1: Online bit 

//  From SFF 8035i Revision 2 page 19: Bit 1 (on-line data collection
// bit) - If the value of this bit equals zero, then the attribute
// value is updated only during off-line data collection
// activities. If the value of this bit equals one, then the attribute
// value is updated during normal operation of the device or during
// both normal operation and off-line testing.
#define ATTRIBUTE_FLAGS_ONLINE(x) (x & 0x02)


// The following are (probably) IBM's, Maxtors and  Quantum's definitions for the
// vendor-specific bits:
// 2: Performance type bit
#define ATTRIBUTE_FLAGS_PERFORMANCE(x) (x & 0x04)

// 3: Errorrate type bit
#define ATTRIBUTE_FLAGS_ERRORRATE(x) (x & 0x08)

// 4: Eventcount bit
#define ATTRIBUTE_FLAGS_EVENTCOUNT(x) (x & 0x10)

// 5: Selfpereserving bit
#define ATTRIBUTE_FLAGS_SELFPRESERVING(x) (x & 0x20)

// 6-15: Reserved for future use
#define ATTRIBUTE_FLAGS_OTHER(x) ((x) & 0xffc0)


// Format of data returned by SMART READ DATA
// Table 62 of T13/1699-D (ATA8-ACS) Revision 6a, September 2008
#pragma pack(1)
struct ata_smart_values {
  unsigned short int revnumber;
  struct ata_smart_attribute vendor_attributes [NUMBER_ATA_SMART_ATTRIBUTES];
  unsigned char offline_data_collection_status;
  unsigned char self_test_exec_status;  //IBM # segments for offline collection
  unsigned short int total_time_to_complete_off_line; // IBM different
  unsigned char vendor_specific_366; // Maxtor & IBM current segment pointer
  unsigned char offline_data_collection_capability;
  unsigned short int smart_capability;
  unsigned char errorlog_capability;
  unsigned char vendor_specific_371;  // Maxtor, IBM: self-test failure checkpoint see below!
  unsigned char short_test_completion_time;
  unsigned char extend_test_completion_time_b; // If 0xff, use 16-bit value below
  unsigned char conveyance_test_completion_time;
  unsigned short extend_test_completion_time_w; // e04130r2, added to T13/1699-D Revision 1c, April 2005
  unsigned char reserved_377_385[9];
  unsigned char vendor_specific_386_510[125]; // Maxtor bytes 508-509 Attribute/Threshold Revision #
  unsigned char chksum;
} ATTR_PACKED;
#pragma pack()
STATIC_ASSERT(sizeof(ata_smart_values) == 512);

/* Maxtor, IBM: self-test failure checkpoint byte meaning:
 00 - write test
 01 - servo basic
 02 - servo random
 03 - G-list scan
 04 - Handling damage
 05 - Read scan
*/

/* Vendor attribute of SMART Threshold (compare to ata_smart_attribute above) */
#pragma pack(1)
struct ata_smart_threshold_entry {
  unsigned char id;
  unsigned char threshold;
  unsigned char reserved[10];
} ATTR_PACKED;
#pragma pack()
STATIC_ASSERT(sizeof(ata_smart_threshold_entry) == 12);

/* Format of Read SMART THreshold Command */
/* Compare to ata_smart_values above */
#pragma pack(1)
struct ata_smart_thresholds_pvt {
  unsigned short int revnumber;
  struct ata_smart_threshold_entry thres_entries[NUMBER_ATA_SMART_ATTRIBUTES];
  unsigned char reserved[149];
  unsigned char chksum;
} ATTR_PACKED;
#pragma pack()
STATIC_ASSERT(sizeof(ata_smart_thresholds_pvt) == 512);


// Table 42 of T13/1321D Rev 1 spec (Error Data Structure)
#pragma pack(1)
struct ata_smart_errorlog_error_struct {
  unsigned char reserved;
  unsigned char error_register;
  unsigned char sector_count;
  unsigned char sector_number;
  unsigned char cylinder_low;
  unsigned char cylinder_high;
  unsigned char drive_head;
  unsigned char status;
  unsigned char extended_error[19];
  unsigned char state;
  unsigned short timestamp;
} ATTR_PACKED;
#pragma pack()
STATIC_ASSERT(sizeof(ata_smart_errorlog_error_struct) == 30);


// Table 41 of T13/1321D Rev 1 spec (Command Data Structure)
#pragma pack(1)
struct ata_smart_errorlog_command_struct {
  unsigned char devicecontrolreg;
  unsigned char featuresreg;
  unsigned char sector_count;
  unsigned char sector_number;
  unsigned char cylinder_low;
  unsigned char cylinder_high;
  unsigned char drive_head;
  unsigned char commandreg;
  unsigned int timestamp;
} ATTR_PACKED;
#pragma pack()
STATIC_ASSERT(sizeof(ata_smart_errorlog_command_struct) == 12);

// Table 40 of T13/1321D Rev 1 spec (Error log data structure)
#pragma pack(1)
struct ata_smart_errorlog_struct {
  struct ata_smart_errorlog_command_struct commands[5];
  struct ata_smart_errorlog_error_struct error_struct;
} ATTR_PACKED;
#pragma pack()
STATIC_ASSERT(sizeof(ata_smart_errorlog_struct) == 90);

// Table 39 of T13/1321D Rev 1 spec (SMART error log sector)
#pragma pack(1)
struct ata_smart_errorlog {
  unsigned char revnumber;
  unsigned char error_log_pointer;
  struct ata_smart_errorlog_struct errorlog_struct[5];
  unsigned short int ata_error_count;
  unsigned char reserved[57];
  unsigned char checksum;
} ATTR_PACKED;
#pragma pack()
STATIC_ASSERT(sizeof(ata_smart_errorlog) == 512);


// Extended Comprehensive SMART Error Log data structures
// See Section A.7 of
//   AT Attachment 8 - ATA/ATAPI Command Set (ATA8-ACS)
//   T13/1699-D Revision 6a (Working Draft), September 6, 2008.

// Command data structure
// Table A.9 of T13/1699-D Revision 6a
#pragma pack(1)
struct ata_smart_exterrlog_command
{
  unsigned char device_control_register;
  unsigned char features_register;
  unsigned char features_register_hi;
  unsigned char count_register;
  unsigned char count_register_hi;
  unsigned char lba_low_register;
  unsigned char lba_low_register_hi;
  unsigned char lba_mid_register;
  unsigned char lba_mid_register_hi;
  unsigned char lba_high_register;
  unsigned char lba_high_register_hi;
  unsigned char device_register;
  unsigned char command_register;

  unsigned char reserved;
  unsigned int timestamp;
} ATTR_PACKED;
#pragma pack()
STATIC_ASSERT(sizeof(ata_smart_exterrlog_command) == 18);

// Error data structure
// Table A.10 T13/1699-D Revision 6a
#pragma pack(1)
struct ata_smart_exterrlog_error
{
  unsigned char device_control_register;
  unsigned char error_register;
  unsigned char count_register;
  unsigned char count_register_hi;
  unsigned char lba_low_register;
  unsigned char lba_low_register_hi;
  unsigned char lba_mid_register;
  unsigned char lba_mid_register_hi;
  unsigned char lba_high_register;
  unsigned char lba_high_register_hi;
  unsigned char device_register;
  unsigned char status_register;

  unsigned char extended_error[19];
  unsigned char state;
  unsigned short timestamp;
} ATTR_PACKED;
#pragma pack()
STATIC_ASSERT(sizeof(ata_smart_exterrlog_error) == 34);

// Error log data structure
// Table A.8 of T13/1699-D Revision 6a
#pragma pack(1)
struct ata_smart_exterrlog_error_log
{
  ata_smart_exterrlog_command commands[5];
  ata_smart_exterrlog_error error;
} ATTR_PACKED;
#pragma pack()
STATIC_ASSERT(sizeof(ata_smart_exterrlog_error_log) == 124);

// Ext. Comprehensive SMART error log
// Table A.7 of T13/1699-D Revision 6a
#pragma pack(1)
struct ata_smart_exterrlog
{
  unsigned char version;
  unsigned char reserved1;
  unsigned short error_log_index;
  ata_smart_exterrlog_error_log error_logs[4];
  unsigned short device_error_count;
  unsigned char reserved2[9];
  unsigned char checksum;
} ATTR_PACKED;
#pragma pack()
STATIC_ASSERT(sizeof(ata_smart_exterrlog) == 512);


// Table 45 of T13/1321D Rev 1 spec (Self-test log descriptor entry)
#pragma pack(1)
struct ata_smart_selftestlog_struct {
  unsigned char selftestnumber; // Sector number register
  unsigned char selfteststatus;
  unsigned short int timestamp;
  unsigned char selftestfailurecheckpoint;
  unsigned int lbafirstfailure;
  unsigned char vendorspecific[15];
} ATTR_PACKED;
#pragma pack()
STATIC_ASSERT(sizeof(ata_smart_selftestlog_struct) == 24);

// Table 44 of T13/1321D Rev 1 spec (Self-test log data structure)
#pragma pack(1)
struct ata_smart_selftestlog {
  unsigned short int revnumber;
  struct ata_smart_selftestlog_struct selftest_struct[21];
  unsigned char vendorspecific[2];
  unsigned char mostrecenttest;
  unsigned char reserved[2];
  unsigned char chksum;
} ATTR_PACKED;
#pragma pack()
STATIC_ASSERT(sizeof(ata_smart_selftestlog) == 512);

// Extended SMART Self-test log data structures
// See Section A.8 of
//   AT Attachment 8 - ATA/ATAPI Command Set (ATA8-ACS)
//   T13/1699-D Revision 6a (Working Draft), September 6, 2008.

// Extended Self-test log descriptor entry
// Table A.13 of T13/1699-D Revision 6a
#pragma pack(1)
struct ata_smart_extselftestlog_desc
{
  unsigned char self_test_type;
  unsigned char self_test_status;
  unsigned short timestamp;
  unsigned char checkpoint;
  unsigned char failing_lba[6];
  unsigned char vendorspecific[15];
} ATTR_PACKED;
#pragma pack()
STATIC_ASSERT(sizeof(ata_smart_extselftestlog_desc) == 26);

// Extended Self-test log data structure
// Table A.12 of T13/1699-D Revision 6a
#pragma pack(1)
struct ata_smart_extselftestlog
{
  unsigned char version;
  unsigned char reserved1;
  unsigned short log_desc_index;
  struct ata_smart_extselftestlog_desc log_descs[19];
  unsigned char vendor_specifc[2];
  unsigned char reserved2[11];
  unsigned char chksum;
} ATTR_PACKED;
#pragma pack()
STATIC_ASSERT(sizeof(ata_smart_extselftestlog) == 512);

// SMART LOG DIRECTORY Table 52 of T13/1532D Vol 1 Rev 1a
#pragma pack(1)
struct ata_smart_log_entry {
  unsigned char numsectors;
  unsigned char reserved;
} ATTR_PACKED;
#pragma pack()
STATIC_ASSERT(sizeof(ata_smart_log_entry) == 2);

#pragma pack(1)
struct ata_smart_log_directory {
  unsigned short int logversion;
  struct ata_smart_log_entry entry[255];
} ATTR_PACKED;
#pragma pack()
STATIC_ASSERT(sizeof(ata_smart_log_directory) == 512);

// SMART SELECTIVE SELF-TEST LOG Table 61 of T13/1532D Volume 1
// Revision 3
#pragma pack(1)
struct test_span {
  uint64_t start;
  uint64_t end;
} ATTR_PACKED;
#pragma pack()
STATIC_ASSERT(sizeof(test_span) == 16);

#pragma pack(1)
struct ata_selective_self_test_log {
  unsigned short     logversion;
  struct test_span   span[5];
  unsigned char      reserved1[337-82+1];
  unsigned char      vendor_specific1[491-338+1];
  uint64_t           currentlba;
  unsigned short     currentspan;
  unsigned short     flags;
  unsigned char      vendor_specific2[507-504+1];
  unsigned short     pendingtime;
  unsigned char      reserved2;
  unsigned char      checksum;
} ATTR_PACKED;
#pragma pack()
STATIC_ASSERT(sizeof(ata_selective_self_test_log) == 512);

#define SELECTIVE_FLAG_DOSCAN  (0x0002)
#define SELECTIVE_FLAG_PENDING (0x0008)
#define SELECTIVE_FLAG_ACTIVE  (0x0010)


// SCT (SMART Command Transport) data structures
// See Sections 8.2 and 8.3 of:
//   AT Attachment 8 - ATA/ATAPI Command Set (ATA8-ACS)
//   T13/1699-D Revision 3f (Working Draft), December 11, 2006.

// SCT Status response (read with SMART_READ_LOG page 0xe0)
// Table 194 of T13/BSR INCITS 529 (ACS-4) Revision 20, October 26, 2017
#pragma pack(1)
struct ata_sct_status_response
{
  unsigned short format_version;    // 0-1: Status response format version number (2, 3)
  unsigned short sct_version;       // 2-3: Vendor specific version number
  unsigned short sct_spec;          // 4-5: SCT level supported (1)
  unsigned int status_flags;        // 6-9: Status flags (Bit 0: Segment initialized, Bits 1-31: reserved)
  unsigned char device_state;       // 10: Device State (0-5)
  unsigned char bytes011_013[3];    // 11-13: reserved
  unsigned short ext_status_code;   // 14-15: Status of last SCT command (0xffff if executing)
  unsigned short action_code;       // 16-17: Action code of last SCT command
  unsigned short function_code;     // 18-19: Function code of last SCT command
  unsigned char bytes020_039[20];   // 20-39: reserved
  uint64_t lba_current;             // 40-47: LBA of SCT command executing in background
  unsigned char bytes048_199[152];  // 48-199: reserved
  signed char hda_temp;             // 200: Current temperature in Celsius (0x80 = invalid)
  signed char min_temp;             // 201: Minimum temperature this power cycle
  signed char max_temp;             // 202: Maximum temperature this power cycle
  signed char life_min_temp;        // 203: Minimum lifetime temperature
  signed char life_max_temp;        // 204: Maximum lifetime temperature
  signed char max_op_limit;         // 205: Specified maximum operating temperature (ACS-4)
  unsigned int over_limit_count;    // 206-209: # intervals since last reset with temperature > Max Op Limit
  unsigned int under_limit_count;   // 210-213: # intervals since last reset with temperature < Min Op Limit
  unsigned short smart_status;      // 214-215: LBA(32:8) of SMART RETURN STATUS (0, 0x2cf4, 0xc24f) (ACS-4)
  unsigned short min_erc_time;      // 216-217: Minimum supported value for ERC (ACS-4)
  unsigned char bytes216_479[479-218+1]; // 218-479: reserved
  unsigned char vendor_specific[32];// 480-511: vendor specific
} ATTR_PACKED;
#pragma pack()
STATIC_ASSERT(sizeof(ata_sct_status_response) == 512);

// SCT Error Recovery Control command (send with SMART_WRITE_LOG page 0xe0)
// Table 88 of T13/1699-D Revision 6a
#pragma pack(1)
struct ata_sct_error_recovery_control_command
{
  unsigned short action_code;       // 3 = Error Recovery Control
  unsigned short function_code;     // 1 = Set Current, 2 = Return Current, 3 = Set Power-on, 4 = Return Power-on, 5 = Restore Default
  unsigned short selection_code;    // 1 = Read Timer, 2 = Write Timer
  unsigned short time_limit;        // If set: Recovery time limit in 100ms units
  unsigned short words004_255[252]; // reserved
} ATTR_PACKED;
#pragma pack()
STATIC_ASSERT(sizeof(ata_sct_error_recovery_control_command) == 512);

// SCT Feature Control command (send with SMART_WRITE_LOG page 0xe0)
// Table 72 of T13/1699-D Revision 3f
#pragma pack(1)
struct ata_sct_feature_control_command
{
  unsigned short action_code;       // 4 = Feature Control
  unsigned short function_code;     // 1 = Set, 2 = Return, 3 = Return options
  unsigned short feature_code;      // 3 = Temperature logging interval
  unsigned short state;             // Interval
  unsigned short option_flags;      // Bit 0: persistent, Bits 1-15: reserved
  unsigned short words005_255[251]; // reserved
} ATTR_PACKED;
#pragma pack()
STATIC_ASSERT(sizeof(ata_sct_feature_control_command) == 512);

// SCT Data Table command (send with SMART_WRITE_LOG page 0xe0)
// Table 73 of T13/1699-D Revision 3f 
#pragma pack(1)
struct ata_sct_data_table_command
{
  unsigned short action_code;       // 5 = Data Table
  unsigned short function_code;     // 1 = Read Table
  unsigned short table_id;          // 2 = Temperature History
  unsigned short words003_255[253]; // reserved
} ATTR_PACKED;
#pragma pack()
STATIC_ASSERT(sizeof(ata_sct_data_table_command) == 512);

// SCT Temperature History Table (read with SMART_READ_LOG page 0xe1)
// Table 75 of T13/1699-D Revision 3f 
#pragma pack(1)
struct ata_sct_temperature_history_table
{
  unsigned short format_version;    // 0-1: Data table format version number (2)
  unsigned short sampling_period;   // 2-3: Temperature sampling period in minutes
  unsigned short interval;          // 4-5: Timer interval between history entries
  signed char max_op_limit;         // 6: Maximum recommended continuous operating temperature
  signed char over_limit;           // 7: Maximum temperature limit
  signed char min_op_limit;         // 8: Minimum recommended continuous operating limit
  signed char under_limit;          // 9: Minimum temperature limit
  unsigned char bytes010_029[20];   // 10-29: reserved
  unsigned short cb_size;           // 30-31: Number of history entries (range 128-478)
  unsigned short cb_index;          // 32-33: Index of last updated entry (zero-based)
  signed char cb[478];              // 34-(34+cb_size-1): Circular buffer of temperature values
} ATTR_PACKED;
#pragma pack()
STATIC_ASSERT(sizeof(ata_sct_temperature_history_table) == 512);

// Possible values for span_args.mode
enum {
  SEL_RANGE, // MIN-MAX
  SEL_REDO,  // redo this
  SEL_NEXT,  // do next range
  SEL_CONT   // redo or next depending of last test status
};

// Arguments for selective self-test
struct ata_selective_selftest_args
{
  // Arguments for each span
  struct span_args
  {
    uint64_t start;   // First block
    uint64_t end;     // Last block
    int mode;         // SEL_*, see above

    span_args()
      : start(0), end(0), mode(SEL_RANGE) { }
  };

  span_args span[5];  // Range and mode for 5 spans
  int num_spans;      // Number of spans
  int pending_time;   // One plus time in minutes to wait after powerup before restarting
                      // interrupted offline scan after selective self-test.
  int scan_after_select; // Run offline scan after selective self-test:
                      // 0: don't change,
                      // 1: turn off scan after selective self-test,
                      // 2: turn on scan after selective self-test.

  ata_selective_selftest_args()
    : num_spans(0), pending_time(0), scan_after_select(0) { }
};

// Priority for vendor attribute defs
enum ata_vendor_def_prior
{
  PRIOR_DEFAULT,
  PRIOR_DATABASE,
  PRIOR_USER
};

// Raw attribute value print formats
enum ata_attr_raw_format
{
  RAWFMT_DEFAULT,
  RAWFMT_RAW8,
  RAWFMT_RAW16,
  RAWFMT_RAW48,
  RAWFMT_HEX48,
  RAWFMT_RAW56,
  RAWFMT_HEX56,
  RAWFMT_RAW64,
  RAWFMT_HEX64,
  RAWFMT_RAW16_OPT_RAW16,
  RAWFMT_RAW16_OPT_AVG16,
  RAWFMT_RAW24_OPT_RAW8,
  RAWFMT_RAW24_DIV_RAW24,
  RAWFMT_RAW24_DIV_RAW32,
  RAWFMT_SEC2HOUR,
  RAWFMT_MIN2HOUR,
  RAWFMT_HALFMIN2HOUR,
  RAWFMT_MSEC24_HOUR32,
  RAWFMT_TEMPMINMAX,
  RAWFMT_TEMP10X,
};

// Attribute flags
enum {
  ATTRFLAG_INCREASING  = 0x01, // Value not reset (for reallocated/pending counts)
  ATTRFLAG_NO_NORMVAL  = 0x02, // Normalized value not valid
  ATTRFLAG_NO_WORSTVAL = 0x04, // Worst value not valid
  ATTRFLAG_HDD_ONLY    = 0x08, // DEFAULT setting for HDD only
  ATTRFLAG_SSD_ONLY    = 0x10, // DEFAULT setting for SSD only
};

// Vendor attribute display defs for all attribute ids
class ata_vendor_attr_defs
{
public:
  struct entry
  {
    std::string name; // Attribute name, empty for default
    ata_attr_raw_format raw_format; // Raw value print format
    ata_vendor_def_prior priority; // Setting priority
    unsigned flags; // ATTRFLAG_*
    char byteorder[8+1]; // String [012345rvwz] to define byte order

    entry()
      : raw_format(RAWFMT_DEFAULT),
        priority(PRIOR_DEFAULT),
        flags(0)
      { byteorder[0] = 0; }
  };

  entry & operator[](unsigned char id)
    { return m_defs[id]; }

  const entry & operator[](unsigned char id) const
    { return m_defs[id]; }

private:
  entry m_defs[256];
};


// Possible values for firmwarebugs
enum firmwarebug_t {
  BUG_NONE = 0,
  BUG_NOLOGDIR,
  BUG_SAMSUNG,
  BUG_SAMSUNG2,
  BUG_SAMSUNG3,
  BUG_XERRORLBA
};

// Set of firmware bugs
class firmwarebug_defs
{
public:
  firmwarebug_defs()
    : m_bugs(0) { }

  bool is_set(firmwarebug_t bug) const
    { return !!(m_bugs & (1 << bug)); }

  void set(firmwarebug_t bug)
    { m_bugs |= (1 << bug); }

  void set(firmwarebug_defs bugs)
    { m_bugs |= bugs.m_bugs; }

private:
  unsigned m_bugs;
};


// Print ATA debug messages?
extern unsigned char ata_debugmode;

// Suppress serial number?
extern bool dont_print_serial_number;

// Get information from drive
int ata_read_identity(ata_device * device, ata_identify_device * buf, bool fix_swapped_id,
                      unsigned char * raw_buf = 0);
int ataCheckPowerMode(ata_device * device);

// Issue a no-data ATA command with optional sector count register value
bool ata_nodata_command(ata_device * device, unsigned char command, int sector_count = -1);

// Issue SET FEATURES command with optional sector count register value
bool ata_set_features(ata_device * device, unsigned char features, int sector_count = -1);

/* Read S.M.A.R.T information from drive */
int ataReadSmartValues(ata_device * device,struct ata_smart_values *);
int ataReadSmartThresholds(ata_device * device, struct ata_smart_thresholds_pvt *);
int ataReadErrorLog (ata_device * device, ata_smart_errorlog *data,
                     firmwarebug_defs firmwarebugs);
int ataReadSelfTestLog(ata_device * device, ata_smart_selftestlog * data,
                       firmwarebug_defs firmwarebugs);
int ataReadSelectiveSelfTestLog(ata_device * device, struct ata_selective_self_test_log *data);
int ataReadLogDirectory(ata_device * device, ata_smart_log_directory *, bool gpl);

// Write GP Log page(s)
bool ataWriteLogExt(ata_device * device, unsigned char logaddr,
                    unsigned page, void * data, unsigned nsectors);

// Read GP Log page(s)
bool ataReadLogExt(ata_device * device, unsigned char logaddr,
                   unsigned char features, unsigned page,
                   void * data, unsigned nsectors);
// Read SMART Log page(s)
bool ataReadSmartLog(ata_device * device, unsigned char logaddr,
                     void * data, unsigned nsectors);
// Read SMART Extended Comprehensive Error Log
bool ataReadExtErrorLog(ata_device * device, ata_smart_exterrlog * log,
                        unsigned page, unsigned nsectors, firmwarebug_defs firmwarebugs);
// Read SMART Extended Self-test Log
bool ataReadExtSelfTestLog(ata_device * device, ata_smart_extselftestlog * log,
                           unsigned nsectors);

// Read SCT information
int ataReadSCTStatus(ata_device * device, ata_sct_status_response * sts);
int ataReadSCTTempHist(ata_device * device, ata_sct_temperature_history_table * tmh,
                       ata_sct_status_response * sts);
// Set SCT temperature logging interval
int ataSetSCTTempInterval(ata_device * device, unsigned interval, bool persistent);

// Get/Set SCT Error Recovery Control
int ataGetSCTErrorRecoveryControltime(ata_device * device, unsigned type, unsigned short & time_limit, bool power_on);
int ataSetSCTErrorRecoveryControltime(ata_device * device, unsigned type, unsigned short time_limit, bool power_on, bool mfg_default);


/* Enable/Disable SMART on device */
int ataEnableSmart (ata_device * device);
int ataDisableSmart (ata_device * device);
int ataEnableAutoSave(ata_device * device);
int ataDisableAutoSave(ata_device * device);

/* Automatic Offline Testing */
int ataEnableAutoOffline (ata_device * device);
int ataDisableAutoOffline (ata_device * device);

/* S.M.A.R.T. test commands */
int ataSmartTest(ata_device * device, int testtype, bool force,
                 const ata_selective_selftest_args & args,
                 const ata_smart_values * sv, uint64_t num_sectors);

int ataWriteSelectiveSelfTestLog(ata_device * device, ata_selective_selftest_args & args,
                                 const ata_smart_values * sv, uint64_t num_sectors,
                                 const ata_selective_selftest_args * prev_spans = 0);

// Get World Wide Name (WWN) fields.
// Return NAA field or -1 if WWN is unsupported.
int ata_get_wwn(const ata_identify_device * id, unsigned & oui, uint64_t & unique_id);

// Get nominal media rotation rate.
// Returns: 0 = not reported, 1 = SSD, >1 = HDD rpm, < 0 = -(Unknown value)
int ata_get_rotation_rate(const ata_identify_device * id);

// If SMART supported, this is guaranteed to return 1 if SMART is enabled, else 0.
int ataDoesSmartWork(ata_device * device);

// returns 1 if SMART supported, 0 if not supported or can't tell
int ataSmartSupport(const ata_identify_device * drive);

// Return values:
//  1: Write Cache Reordering enabled
//  2: Write Cache Reordering disabled
// -1: error
int ataGetSetSCTWriteCacheReordering(ata_device * device, bool enable, bool persistent, bool set);

// Return values:
// 1: Write cache controlled by ATA Set Features command
// 2: Force enable write cache
// 3: Force disable write cache
int ataGetSetSCTWriteCache(ata_device * device, unsigned short state, bool persistent, bool set);

// Return values:
//  1: SMART enabled
//  0: SMART disabled
// -1: can't tell if SMART is enabled -- try issuing ataDoesSmartWork command to see
int ataIsSmartEnabled(const ata_identify_device * drive);

int ataSmartStatus2(ata_device * device);

bool isSmartErrorLogCapable(const ata_smart_values * data, const ata_identify_device * identity);

bool isSmartTestLogCapable(const ata_smart_values * data, const ata_identify_device * identity);

bool isGeneralPurposeLoggingCapable(const ata_identify_device * identity);

// SMART self-test capability is also indicated in bit 1 of DEVICE
// IDENTIFY word 87 (if top two bits of word 87 match pattern 01).
// However this was only introduced in ATA-6 (but self-test log was in
// ATA-5).
inline bool isSupportExecuteOfflineImmediate(const ata_smart_values *data)
  { return !!(data->offline_data_collection_capability & 0x01); }

// TODO: Remove uses of this check.  Bit 1 is vendor specific since ATA-4.
// Automatic timer support was only documented for very old IBM drives
// (for example IBM Travelstar 40GNX).
inline bool isSupportAutomaticTimer(const ata_smart_values * data)
  { return !!(data->offline_data_collection_capability & 0x02); }

inline bool isSupportOfflineAbort(const ata_smart_values *data)
  { return !!(data->offline_data_collection_capability & 0x04); }

inline bool isSupportOfflineSurfaceScan(const ata_smart_values * data)
  { return !!(data->offline_data_collection_capability & 0x08); }

inline bool isSupportSelfTest(const ata_smart_values * data)
  { return !!(data->offline_data_collection_capability & 0x10); }

inline bool isSupportConveyanceSelfTest(const ata_smart_values * data)
  { return !!(data->offline_data_collection_capability & 0x20); }

inline bool isSupportSelectiveSelfTest(const ata_smart_values * data)
  { return !!(data->offline_data_collection_capability & 0x40); }

inline bool isSCTCapable(const ata_identify_device *drive)
  { return !!(drive->words088_255[206-88] & 0x01); } // 0x01 = SCT support

inline bool isSCTErrorRecoveryControlCapable(const ata_identify_device *drive)
  { return ((drive->words088_255[206-88] & 0x09) == 0x09); } // 0x08 = SCT Error Recovery Control support

inline bool isSCTFeatureControlCapable(const ata_identify_device *drive)
  { return ((drive->words088_255[206-88] & 0x11) == 0x11); } // 0x10 = SCT Feature Control support

inline bool isSCTDataTableCapable(const ata_identify_device *drive)
  { return ((drive->words088_255[206-88] & 0x21) == 0x21); } // 0x20 = SCT Data Table support

int TestTime(const ata_smart_values * data, int testtype);

// Attribute state
enum ata_attr_state
{
  ATTRSTATE_NON_EXISTING,   // No such Attribute
  ATTRSTATE_NO_NORMVAL,     // Normalized value not valid
  ATTRSTATE_NO_THRESHOLD,   // Unknown or no threshold
  ATTRSTATE_OK,             // Never failed
  ATTRSTATE_FAILED_PAST,    // Failed in the past
  ATTRSTATE_FAILED_NOW      // Failed now
};

// Get attribute state
ata_attr_state ata_get_attr_state(const ata_smart_attribute & attr,
                                  int attridx,
                                  const ata_smart_threshold_entry * thresholds,
                                  const ata_vendor_attr_defs & defs,
                                  unsigned char * threshval = 0);

// Get attribute raw value.
uint64_t ata_get_attr_raw_value(const ata_smart_attribute & attr,
                                const ata_vendor_attr_defs & defs);

// Format attribute raw value.
std::string ata_format_attr_raw_value(const ata_smart_attribute & attr,
                                      const ata_vendor_attr_defs & defs);

// Get attribute name
std::string ata_get_smart_attr_name(unsigned char id,
                                    const ata_vendor_attr_defs & defs,
                                    int rpm = 0);

// External handler function, for when a checksum is not correct.  Can
// simply return if no action is desired, or can print error messages
// as needed, or exit.  Is passed a string with the name of the Data
// Structure with the incorrect checksum.
void checksumwarning(const char *string);

// Find attribute index for attribute id, -1 if not found.
int ata_find_attr_index(unsigned char id, const ata_smart_values & smartval);

// Return Temperature Attribute raw value selected according to possible
// non-default interpretations. If the Attribute does not exist, return 0
unsigned char ata_return_temperature_value(const ata_smart_values * data, const ata_vendor_attr_defs & defs);


#define MAX_ATTRIBUTE_NUM 256

// Parse vendor attribute display def (-v option).
// Return false on error.
bool parse_attribute_def(const char * opt, ata_vendor_attr_defs & defs,
                         ata_vendor_def_prior priority);

// Get ID and increase flag of current pending or offline
// uncorrectable attribute.
unsigned char get_unc_attr_id(bool offline, const ata_vendor_attr_defs & defs,
                              bool & increase);

// Return a multiline string containing a list of valid arguments for
// parse_attribute_def().
std::string create_vendor_attribute_arg_list();

// Parse firmwarebug def (-F option).
// Return false on error.
bool parse_firmwarebug_def(const char * opt, firmwarebug_defs & firmwarebugs);

// Return a string of valid argument words for parse_firmwarebug_def()
const char * get_valid_firmwarebug_args();


// These are two of the functions that are defined in os_*.c and need
// to be ported to get smartmontools onto another OS.
// Moved to C++ interface
//int ata_command_interface(int device, smart_command_set command, int select, char *data);
//int escalade_command_interface(int fd, int escalade_port, int escalade_type, smart_command_set command, int select, char *data);
//int marvell_command_interface(int device, smart_command_set command, int select, char *data);
//int highpoint_command_interface(int device, smart_command_set command, int select, char *data);
//int areca_command_interface(int fd, int disknum, smart_command_set command, int select, char *data);


// This function is exported to give low-level capability
int smartcommandhandler(ata_device * device, smart_command_set command, int select, char *data);

// Get capacity and sector sizes from IDENTIFY data
struct ata_size_info
{
  uint64_t sectors;
  uint64_t capacity;
  unsigned log_sector_size;
  unsigned phy_sector_size;
  unsigned log_sector_offset;
};

void ata_get_size_info(const ata_identify_device * id, ata_size_info & sizes);

// Convenience function for formatting strings from ata_identify_device.
void ata_format_id_string(char * out, const unsigned char * in, int n);

// Utility routines.
unsigned char checksum(const void * data);

// Return pseudo-device to parse "smartctl -r ataioctl,2 ..." output
// and simulate an ATA device with same behaviour
ata_device * get_parsed_ata_device(smart_interface * intf, const char * dev_name);

#endif /* ATACMDS_H_ */