From 22321ac3562706b859fd16b824ca1c73264a902b Mon Sep 17 00:00:00 2001
From: Song Liu <songliubraving@fb.com>
Date: Thu, 11 Aug 2016 09:00:44 -0700
Subject: [PATCH] Add wcache-sct option for -g -s to control wcache in SCT
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The option is described as following in man page:
wcache-sct[,ata|on|off[,p]] - [ATA only] Gets/sets the write
cache feature through SCT Feature Control (if supported). The
state of write cache in SCT Feature Control could be
"Controlled by ATA", "Force Enabled", or "Force Disabled". SCT
Feature control overwrites the setting by ATA Set Features
command (wcache[,on|off] option). If SCT Feature Control sets
write cache as "Force Enabled" or "Force Disabled", the setting
of wcache[,on|off] is ignored by the drive. SCT Feature Control
usually sets write cache as "Controlled by ATA" by default.
If ´,p´ is specified, the setting is preserved across power cycles.
We reuse code for wcreorder, so there isn't much change in the
backend. Persistent flag is added to trigger persistent flag in
SCT command.
---
trunk/smartmontools/atacmds.cpp | 25 ++++++++++++++++-----
trunk/smartmontools/atacmds.h | 6 +++++
trunk/smartmontools/ataprint.cpp | 46 +++++++++++++++++++++++++++++++++++++-
trunk/smartmontools/ataprint.h | 7 +++++-
trunk/smartmontools/smartctl.8.in | 10 +++++++++
trunk/smartmontools/smartctl.cpp | 47 ++++++++++++++++++++++++++++++++++-----
6 files changed, 128 insertions(+), 13 deletions(-)
diff --git a/trunk/smartmontools/atacmds.cpp b/trunk/smartmontools/atacmds.cpp
index c470b1c..f2eb092 100644
a
|
b
|
int ataReadSCTTempHist(ata_device * device, ata_sct_temperature_history_table *
|
2307 | 2307 | return 0; |
2308 | 2308 | } |
2309 | 2309 | |
2310 | | // Get/Set Write Cache Reordering |
2311 | | int ataGetSetSCTWriteCacheReordering(ata_device * device, bool enable, bool persistent, bool set) |
| 2310 | // Common function for Get/Set SCT Feature Control: |
| 2311 | // Write Cache, Write Cache Reordering, etc. |
| 2312 | static int ataGetSetSCTFeatureControl(ata_device * device, unsigned short feature_code, |
| 2313 | unsigned short state, bool persistent, bool set) |
2312 | 2314 | { |
2313 | 2315 | // Check initial status |
2314 | 2316 | ata_sct_status_response sts; |
… |
… |
int ataGetSetSCTWriteCacheReordering(ata_device * device, bool enable, bool pers
|
2327 | 2329 | // CAUTION: DO NOT CHANGE THIS VALUE (SOME ACTION CODES MAY ERASE DISK) |
2328 | 2330 | cmd.action_code = 4; // Feature Control command |
2329 | 2331 | cmd.function_code = (set ? 1 : 2); // 1=Set, 2=Get |
2330 | | cmd.feature_code = 2; // Enable/Disable Write Cache Reordering |
2331 | | cmd.state = (enable ? 1 : 2); // 1 enable, 2 disable |
| 2332 | cmd.feature_code = feature_code; |
| 2333 | cmd.state = state; |
2332 | 2334 | cmd.option_flags = (persistent ? 0x01 : 0x00); |
2333 | 2335 | |
2334 | 2336 | // swap endian order if needed |
… |
… |
int ataGetSetSCTWriteCacheReordering(ata_device * device, bool enable, bool pers
|
2359 | 2361 | (!set ? 'G' : 'S'), device->get_errmsg()); |
2360 | 2362 | return -1; |
2361 | 2363 | } |
2362 | | int state = out.out_regs.sector_count | (out.out_regs.lba_low << 8); |
| 2364 | state = out.out_regs.sector_count | (out.out_regs.lba_low << 8); |
2363 | 2365 | |
2364 | 2366 | // re-read and check SCT status |
2365 | 2367 | if (ataReadSCTStatus(device, &sts)) |
… |
… |
int ataGetSetSCTWriteCacheReordering(ata_device * device, bool enable, bool pers
|
2373 | 2375 | return state; |
2374 | 2376 | } |
2375 | 2377 | |
| 2378 | // Get/Set Write Cache Reordering |
| 2379 | int ataGetSetSCTWriteCacheReordering(ata_device * device, bool enable, bool persistent, bool set) |
| 2380 | { |
| 2381 | return ataGetSetSCTFeatureControl(device, 2 /* Enable/Disable Write Cache Reordering */, |
| 2382 | (enable ? 1 : 2), persistent, set); |
| 2383 | } |
| 2384 | |
| 2385 | // Get/Set Write Cache (force enable, force disable, |
| 2386 | int ataGetSetSCTWriteCache(ata_device * device, unsigned short state, bool persistent, bool set) |
| 2387 | { |
| 2388 | return ataGetSetSCTFeatureControl(device, 1 /* Enable/Disable Write Cache */, |
| 2389 | state, persistent, set); |
| 2390 | } |
2376 | 2391 | |
2377 | 2392 | // Set SCT Temperature Logging Interval |
2378 | 2393 | int ataSetSCTTempInterval(ata_device * device, unsigned interval, bool persistent) |
diff --git a/trunk/smartmontools/atacmds.h b/trunk/smartmontools/atacmds.h
index 4cd768a..d172a02 100644
a
|
b
|
int ataSmartSupport(const ata_identify_device * drive);
|
845 | 845 | int ataGetSetSCTWriteCacheReordering(ata_device * device, bool enable, bool persistent, bool set); |
846 | 846 | |
847 | 847 | // Return values: |
| 848 | // 1: Write cache controled by ATA Set Features command |
| 849 | // 2: Force enable write cache |
| 850 | // 3: Force disable write cache |
| 851 | int ataGetSetSCTWriteCache(ata_device * device, unsigned short state, bool persistent, bool set); |
| 852 | |
| 853 | // Return values: |
848 | 854 | // 1: SMART enabled |
849 | 855 | // 0: SMART disabled |
850 | 856 | // -1: can't tell if SMART is enabled -- try issuing ataDoesSmartWork command to see |
diff --git a/trunk/smartmontools/ataprint.cpp b/trunk/smartmontools/ataprint.cpp
index 593e2cb..aa81cf0 100644
a
|
b
|
int ataPrintMain (ata_device * device, const ata_print_options & options)
|
2638 | 2638 | || options.sct_erc_set |
2639 | 2639 | || options.sct_wcache_reorder_get |
2640 | 2640 | || options.sct_wcache_reorder_set |
| 2641 | || options.sct_wcache_sct_get |
| 2642 | || options.sct_wcache_sct_set |
2641 | 2643 | ); |
2642 | 2644 | |
2643 | 2645 | // Exit if no further options specified |
… |
… |
int ataPrintMain (ata_device * device, const ata_print_options & options)
|
2821 | 2823 | } |
2822 | 2824 | } |
2823 | 2825 | |
| 2826 | const char * sct_write_cache_state_desc[4] = { |
| 2827 | "Unknown", // 0: not defined in standard but returned on some drives if not set |
| 2828 | "Controlled by ATA", // 1: controlled ATA Set Features command |
| 2829 | "Force Enabled", // 2 |
| 2830 | "Force Disabled" // 3 |
| 2831 | }; |
| 2832 | |
| 2833 | // Print SCT feature control of write cache |
| 2834 | if (options.sct_wcache_sct_get) { |
| 2835 | if (!isSCTFeatureControlCapable(&drive)) |
| 2836 | pout("SCT Write Cache Control: Unavailable\n"); |
| 2837 | else if (locked) |
| 2838 | pout("SCT Write Cache Control: Unknown (SCT not supported if ATA Security is LOCKED)\n"); |
| 2839 | else { |
| 2840 | int state = ataGetSetSCTWriteCache(device, 1, false /*persistent*/, false /*set*/); |
| 2841 | if (-1 <= state && state <= 3) |
| 2842 | pout("SCT Write Cache Control: %s\n", |
| 2843 | (state == -1 ? "Unknown (SCT Feature Control command failed)" : |
| 2844 | sct_write_cache_state_desc[state])); |
| 2845 | else |
| 2846 | pout("SCT Write Cache Control: Unknown (0x%02x)\n", state); |
| 2847 | } |
| 2848 | } |
| 2849 | |
| 2850 | |
2824 | 2851 | // Print remaining drive info |
2825 | 2852 | if (options.drive_info) { |
2826 | 2853 | // Print the (now possibly changed) power mode if available |
… |
… |
int ataPrintMain (ata_device * device, const ata_print_options & options)
|
2839 | 2866 | || options.smart_auto_offl_disable || options.smart_auto_offl_enable |
2840 | 2867 | || options.set_aam || options.set_apm || options.set_lookahead |
2841 | 2868 | || options.set_wcache || options.set_security_freeze || options.set_standby |
2842 | | || options.sct_wcache_reorder_set) |
| 2869 | || options.sct_wcache_reorder_set || options.sct_wcache_sct_set) |
2843 | 2870 | pout("=== START OF ENABLE/DISABLE COMMANDS SECTION ===\n"); |
2844 | 2871 | |
2845 | 2872 | // Enable/Disable AAM |
… |
… |
int ataPrintMain (ata_device * device, const ata_print_options & options)
|
2922 | 2949 | pout("Write cache reordering %sabled\n", (enable ? "en" : "dis")); |
2923 | 2950 | } |
2924 | 2951 | |
| 2952 | // Enable/Disable write cache in SCT |
| 2953 | if (options.sct_wcache_sct_set) { |
| 2954 | if (!isSCTFeatureControlCapable(&drive)) |
| 2955 | pout("SCT Feature Control of write cache failed: SCT Feature Control command not supported\n"); |
| 2956 | else if (locked) |
| 2957 | pout("SCT Feature Control of write cache failed: SCT not supported if ATA Security is LOCKED\n"); |
| 2958 | else if (ataGetSetSCTWriteCache(device, |
| 2959 | options.sct_wcache_sct_set, options.sct_wcache_sct_set_pers, true /*set*/) < 0) { |
| 2960 | pout("SCT Feature Control of write cache failed: %s\n", device->get_errmsg()); |
| 2961 | returnval |= FAILSMART; |
| 2962 | } |
| 2963 | else |
| 2964 | pout("Write cache SCT Feature Control is set to: %s (%s)\n", |
| 2965 | sct_write_cache_state_desc[options.sct_wcache_sct_set], |
| 2966 | (options.sct_wcache_sct_set_pers ? "persistent" : "volatile")); |
| 2967 | } |
| 2968 | |
2925 | 2969 | // Freeze ATA security |
2926 | 2970 | if (options.set_security_freeze) { |
2927 | 2971 | if (!ata_nodata_command(device, ATA_SECURITY_FREEZE_LOCK)) { |
diff --git a/trunk/smartmontools/ataprint.h b/trunk/smartmontools/ataprint.h
index 74e28b9..230ce22 100644
a
|
b
|
struct ata_print_options
|
108 | 108 | int set_wcache; // disable(-1), enable(1) write cache |
109 | 109 | bool sct_wcache_reorder_get; // print write cache reordering status |
110 | 110 | int sct_wcache_reorder_set; // disable(-1), enable(1) write cache reordering |
| 111 | bool sct_wcache_sct_get; // print SCT Feature Control of write cache status |
| 112 | int sct_wcache_sct_set; // determined by ata set features command(1), force enable(2), force disable(3) |
| 113 | bool sct_wcache_sct_set_pers; // persistent or volatile |
111 | 114 | |
112 | 115 | ata_print_options() |
113 | 116 | : drive_info(false), |
… |
… |
struct ata_print_options
|
145 | 148 | set_standby(0), set_standby_now(false), |
146 | 149 | get_security(false), set_security_freeze(false), |
147 | 150 | get_wcache(false), set_wcache(0), |
148 | | sct_wcache_reorder_get(false), sct_wcache_reorder_set(0) |
| 151 | sct_wcache_reorder_get(false), sct_wcache_reorder_set(0), |
| 152 | sct_wcache_sct_get(false), sct_wcache_sct_set(0), |
| 153 | sct_wcache_sct_set_pers(false) |
149 | 154 | { } |
150 | 155 | }; |
151 | 156 | |
diff --git a/trunk/smartmontools/smartctl.8.in b/trunk/smartmontools/smartctl.8.in
index 765e8d3..372f331 100644
a
|
b
|
The write cache is usually enabled by default.
|
947 | 947 | \- [SCSI] Gets/sets the \'Write Cache Enable\' (WCE) bit (if supported). |
948 | 948 | The write cache is usually enabled by default. |
949 | 949 | |
| 950 | .I wcache-sct[,ata|on|off[,p]] |
| 951 | \- [ATA only] Gets/sets the write cache feature through SCT Feature Control |
| 952 | (if supported). The state of write cache in SCT Feature Control could be |
| 953 | "Controlled by ATA", "Force Enabled", or "Force Disabled". SCT Feature control |
| 954 | overwrites the setting by ATA Set Features command (wcache[,on|off] option). |
| 955 | If SCT Feature Control sets write cache as "Force Enabled" or "Force Disabled", |
| 956 | the setting of wcache[,on|off] is ignored by the drive. SCT Feature Control |
| 957 | usually sets write cache as "Controlled by ATA" by default. If ´,p´ is |
| 958 | specified, the setting is preserved across power cycles. |
| 959 | |
950 | 960 | .I wcreorder[,on|off] |
951 | 961 | \- [ATA only] Gets/sets Write Cache Reordering. |
952 | 962 | If it is disabled (off), disk write scheduling is executed on a |
diff --git a/trunk/smartmontools/smartctl.cpp b/trunk/smartmontools/smartctl.cpp
index aee253c..7660b9c 100644
a
|
b
|
static void Usage()
|
87 | 87 | " --identify[=[w][nvb]]\n" |
88 | 88 | " Show words and bits from IDENTIFY DEVICE data (ATA)\n\n" |
89 | 89 | " -g NAME, --get=NAME\n" |
90 | | " Get device setting: all, aam, apm, lookahead, security, wcache, rcache, wcreorder\n\n" |
| 90 | " Get device setting: all, aam, apm, lookahead, security, wcache, rcache, wcreorder, wcache-sct\n\n" |
91 | 91 | " -a, --all\n" |
92 | 92 | " Show all SMART information for device\n\n" |
93 | 93 | " -x, --xall\n" |
… |
… |
static void Usage()
|
123 | 123 | " -s NAME[,VALUE], --set=NAME[,VALUE]\n" |
124 | 124 | " Enable/disable/change device setting: aam,[N|off], apm,[N|off],\n" |
125 | 125 | " lookahead,[on|off], security-freeze, standby,[N|off|now],\n" |
126 | | " wcache,[on|off], rcache,[on|off], wcreorder,[on|off]\n\n" |
| 126 | " wcache,[on|off], rcache,[on|off], wcreorder,[on|off]\n" |
| 127 | " wcache-sct,[ata|on|off[,p]]\n\n" |
127 | 128 | ); |
128 | 129 | printf( |
129 | 130 | "======================================= READ AND DISPLAY DATA OPTIONS =====\n\n" |
… |
… |
static std::string getvalidarglist(int opt)
|
221 | 222 | case 'f': |
222 | 223 | return "old, brief, hex[,id|val]"; |
223 | 224 | case 'g': |
224 | | return "aam, apm, lookahead, security, wcache, rcache, wcreorder"; |
| 225 | return "aam, apm, lookahead, security, wcache, rcache, wcreorder, wcache-sct"; |
225 | 226 | case opt_set: |
226 | 227 | return "aam,[N|off], apm,[N|off], lookahead,[on|off], security-freeze, " |
227 | | "standby,[N|off|now], wcache,[on|off], rcache,[on|off], wcreorder,[on|off]"; |
| 228 | "standby,[N|off|now], wcache,[on|off], rcache,[on|off], wcreorder,[on|off], " |
| 229 | "wcache-sct,[ata|on|off[,p]]"; |
228 | 230 | case 's': |
229 | 231 | return getvalidarglist(opt_smart)+", "+getvalidarglist(opt_set); |
230 | 232 | case opt_identify: |
… |
… |
static const char * parse_options(int argc, char** argv,
|
854 | 856 | bool get = (optchar == 'g'); |
855 | 857 | char name[16+1]; unsigned val; |
856 | 858 | int n1 = -1, n2 = -1, n3 = -1, len = strlen(optarg); |
| 859 | bool persistent = false; |
857 | 860 | if (sscanf(optarg, "%16[^,=]%n%*[,=]%n%u%n", name, &n1, &n2, &val, &n3) >= 1 |
858 | 861 | && (n1 == len || (!get && n2 > 0))) { |
859 | | bool on = (n2 > 0 && !strcmp(optarg+n2, "on")); |
860 | | bool off = (n2 > 0 && !strcmp(optarg+n2, "off")); |
| 862 | bool on = false; |
| 863 | bool off = false; |
| 864 | bool ata = false; |
| 865 | |
| 866 | if (n2 > 0) { |
| 867 | int len2 = strlen(optarg + n2); |
| 868 | char * tmp = strstr(optarg+n2, ",p"); |
| 869 | // handle ",p" in persistent options like: wcache-sct,[ata|on|off],p |
| 870 | if (tmp && (strlen(tmp) == 2)) { |
| 871 | persistent = true; |
| 872 | len2 = strlen(optarg+n2) - 2; |
| 873 | |
| 874 | // the ,p option only works for set of SCT Feature Control command |
| 875 | if (strcmp(name, "wcache-sct") != 0) |
| 876 | badarg = true; |
| 877 | } |
| 878 | on = !strncmp(optarg+n2, "on", len2); |
| 879 | off = !strncmp(optarg+n2, "off", len2); |
| 880 | ata = !strncmp(optarg+n2, "ata", len2); |
| 881 | } |
861 | 882 | if (n3 != len) |
862 | 883 | val = ~0U; |
863 | 884 | |
… |
… |
static const char * parse_options(int argc, char** argv,
|
913 | 934 | else |
914 | 935 | badarg = true; |
915 | 936 | } |
| 937 | else if (!strcmp(name, "wcache-sct")) { |
| 938 | ataopts.sct_wcache_sct_set_pers = persistent; |
| 939 | if (get) { |
| 940 | ataopts.sct_wcache_sct_get = true; |
| 941 | } |
| 942 | else if (off) |
| 943 | ataopts.sct_wcache_sct_set = 3; |
| 944 | else if (on) |
| 945 | ataopts.sct_wcache_sct_set = 2; |
| 946 | else if (ata) |
| 947 | ataopts.sct_wcache_sct_set = 1; |
| 948 | else |
| 949 | badarg = true; |
| 950 | } |
916 | 951 | else if (!strcmp(name, "rcache")) { |
917 | 952 | if (get) |
918 | 953 | scsiopts.get_rcd = true; |