version 1.66.8.3, 2014/08/20 00:02:24 |
version 1.67, 2012/10/19 17:09:07 |
Line 44 __RCSID("$NetBSD$"); |
|
Line 44 __RCSID("$NetBSD$"); |
|
#include <err.h> |
#include <err.h> |
#include <errno.h> |
#include <errno.h> |
#include <fcntl.h> |
#include <fcntl.h> |
#include <pwd.h> |
|
#include <stdio.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <stdlib.h> |
#include <string.h> |
#include <string.h> |
Line 145 static const struct command device_comma |
|
Line 144 static const struct command device_comma |
|
{ "smart", |
{ "smart", |
"enable|disable|status|offline #|error-log|selftest-log", |
"enable|disable|status|offline #|error-log|selftest-log", |
device_smart }, |
device_smart }, |
{ "security", |
{ "security", "freeze|status", device_security }, |
"status|freeze|[setpass|unlock|disable|erase] [user|master]", |
|
device_security }, |
|
{ NULL, NULL, NULL }, |
{ NULL, NULL, NULL }, |
}; |
}; |
|
|
Line 191 static const struct bitinfo ata_cmd_set1 |
|
Line 188 static const struct bitinfo ata_cmd_set1 |
|
{ WDC_CMD1_HPA, "Host Protected Area feature set" }, |
{ WDC_CMD1_HPA, "Host Protected Area feature set" }, |
{ WDC_CMD1_DVRST, "DEVICE RESET command" }, |
{ WDC_CMD1_DVRST, "DEVICE RESET command" }, |
{ WDC_CMD1_SRV, "SERVICE interrupt" }, |
{ WDC_CMD1_SRV, "SERVICE interrupt" }, |
{ WDC_CMD1_RLSE, "Release interrupt" }, |
{ WDC_CMD1_RLSE, "release interrupt" }, |
{ WDC_CMD1_AHEAD, "Look-ahead" }, |
{ WDC_CMD1_AHEAD, "look-ahead" }, |
{ WDC_CMD1_CACHE, "Write cache" }, |
{ WDC_CMD1_CACHE, "write cache" }, |
{ WDC_CMD1_PKT, "PACKET command feature set" }, |
{ WDC_CMD1_PKT, "PACKET command feature set" }, |
{ WDC_CMD1_PM, "Power Management feature set" }, |
{ WDC_CMD1_PM, "Power Management feature set" }, |
{ WDC_CMD1_REMOV, "Removable Media feature set" }, |
{ WDC_CMD1_REMOV, "Removable Media feature set" }, |
Line 239 static const struct bitinfo ata_cmd_ext[ |
|
Line 236 static const struct bitinfo ata_cmd_ext[ |
|
static const struct bitinfo ata_sata_caps[] = { |
static const struct bitinfo ata_sata_caps[] = { |
{ SATA_SIGNAL_GEN1, "1.5Gb/s signaling" }, |
{ SATA_SIGNAL_GEN1, "1.5Gb/s signaling" }, |
{ SATA_SIGNAL_GEN2, "3.0Gb/s signaling" }, |
{ SATA_SIGNAL_GEN2, "3.0Gb/s signaling" }, |
{ SATA_SIGNAL_GEN3, "6.0Gb/s signaling" }, |
|
{ SATA_NATIVE_CMDQ, "Native Command Queuing" }, |
{ SATA_NATIVE_CMDQ, "Native Command Queuing" }, |
{ SATA_HOST_PWR_MGMT, "Host-Initiated Interface Power Management" }, |
{ SATA_HOST_PWR_MGMT, "Host-Initiated Interface Power Management" }, |
{ SATA_PHY_EVNT_CNT, "PHY Event Counters" }, |
{ SATA_PHY_EVNT_CNT, "PHY Event Counters" }, |
Line 273 static const struct { |
|
Line 269 static const struct { |
|
{ 11, "Calibration retry count", NULL }, |
{ 11, "Calibration retry count", NULL }, |
{ 12, "Device power cycle count", NULL }, |
{ 12, "Device power cycle count", NULL }, |
{ 13, "Soft read error rate", NULL }, |
{ 13, "Soft read error rate", NULL }, |
{ 184, "End-to-end error", NULL }, |
|
{ 187, "Reported uncorrect", NULL }, |
{ 187, "Reported uncorrect", NULL }, |
{ 189, "High Fly Writes", NULL }, |
{ 189, "High Fly Writes", NULL }, |
{ 190, "Airflow Temperature", device_smart_temp }, |
{ 190, "Airflow Temperature", device_smart_temp }, |
Line 307 static const struct { |
|
Line 302 static const struct { |
|
{ 228, "Power-off retract count", NULL }, |
{ 228, "Power-off retract count", NULL }, |
{ 230, "GMR head amplitude", NULL }, |
{ 230, "GMR head amplitude", NULL }, |
{ 231, "Temperature", device_smart_temp }, |
{ 231, "Temperature", device_smart_temp }, |
{ 232, "Available reserved space", NULL }, |
|
{ 233, "Media wearout indicator", NULL }, |
|
{ 240, "Head flying hours", NULL }, |
{ 240, "Head flying hours", NULL }, |
{ 250, "Read error retry rate", NULL }, |
{ 250, "Read error retry rate", NULL }, |
{ 0, "Unknown", NULL }, |
{ 0, "Unknown", NULL }, |
Line 521 print_smart_status(void *vbuf, void *tbu |
|
Line 514 print_smart_status(void *vbuf, void *tbu |
|
} |
} |
|
|
printf("id value thresh crit collect reliability description" |
printf("id value thresh crit collect reliability description" |
" raw\n"); |
"\t\t\traw\n"); |
for (i = 0; i < 256; i++) { |
for (i = 0; i < 256; i++) { |
int thresh = 0; |
int thresh = 0; |
|
|
Line 549 print_smart_status(void *vbuf, void *tbu |
|
Line 542 print_smart_status(void *vbuf, void *tbu |
|
|
|
flags = le16toh(attr->flags); |
flags = le16toh(attr->flags); |
|
|
printf("%3d %3d %3d %-3s %-7s %stive %-27s ", |
printf("%3d %3d %3d %-3s %-7s %stive %-24s\t", |
i, attr->value, thresh, |
i, attr->value, thresh, |
flags & WDSM_ATTR_ADVISORY ? "yes" : "no", |
flags & WDSM_ATTR_ADVISORY ? "yes" : "no", |
flags & WDSM_ATTR_COLLECTIVE ? "online" : "offline", |
flags & WDSM_ATTR_COLLECTIVE ? "online" : "offline", |
Line 577 static const struct { |
|
Line 570 static const struct { |
|
{ 127, "Abort off-line test" }, |
{ 127, "Abort off-line test" }, |
{ 129, "Short captive" }, |
{ 129, "Short captive" }, |
{ 130, "Extended captive" }, |
{ 130, "Extended captive" }, |
{ 256, "Unknown test" }, /* larger than uint8_t */ |
{ 256, "Unknown test" }, /* larger then uint8_t */ |
{ 0, NULL } |
{ 0, NULL } |
}; |
}; |
|
|
Line 858 extract_string(char *buf, size_t bufmax, |
|
Line 851 extract_string(char *buf, size_t bufmax, |
|
buf[j] = '\0'; |
buf[j] = '\0'; |
} |
} |
|
|
static void |
|
compute_capacity(const struct ataparams *inqbuf, uint64_t *capacityp, |
|
uint64_t *sectorsp, uint32_t *secsizep) |
|
{ |
|
uint64_t capacity; |
|
uint64_t sectors; |
|
uint32_t secsize; |
|
|
|
if (inqbuf->atap_cmd2_en != 0 && inqbuf->atap_cmd2_en != 0xffff && |
|
inqbuf->atap_cmd2_en & ATA_CMD2_LBA48) { |
|
sectors = |
|
((uint64_t)inqbuf->atap_max_lba[3] << 48) | |
|
((uint64_t)inqbuf->atap_max_lba[2] << 32) | |
|
((uint64_t)inqbuf->atap_max_lba[1] << 16) | |
|
((uint64_t)inqbuf->atap_max_lba[0] << 0); |
|
} else if (inqbuf->atap_capabilities1 & WDC_CAP_LBA) { |
|
sectors = (inqbuf->atap_capacity[1] << 16) | |
|
inqbuf->atap_capacity[0]; |
|
} else { |
|
sectors = inqbuf->atap_cylinders * |
|
inqbuf->atap_heads * inqbuf->atap_sectors; |
|
} |
|
|
|
secsize = 512; |
|
|
|
if ((inqbuf->atap_secsz & ATA_SECSZ_VALID_MASK) == ATA_SECSZ_VALID) { |
|
if (inqbuf->atap_secsz & ATA_SECSZ_LLS) { |
|
secsize = 2 * /* words to bytes */ |
|
(inqbuf->atap_lls_secsz[1] << 16 | |
|
inqbuf->atap_lls_secsz[0] << 0); |
|
} |
|
} |
|
|
|
capacity = sectors * secsize; |
|
|
|
if (capacityp) |
|
*capacityp = capacity; |
|
if (sectorsp) |
|
*sectorsp = sectors; |
|
if (secsizep) |
|
*secsizep = secsize; |
|
} |
|
|
|
/* |
/* |
* DEVICE COMMANDS |
* DEVICE COMMANDS |
*/ |
*/ |
Line 947 device_identify(int argc, char *argv[]) |
|
Line 897 device_identify(int argc, char *argv[]) |
|
* Mitsumi ATAPI devices |
* Mitsumi ATAPI devices |
*/ |
*/ |
|
|
if (!(inqbuf->atap_config != WDC_CFG_CFA_MAGIC && |
if (!((inqbuf->atap_config & WDC_CFG_ATAPI_MASK) == WDC_CFG_ATAPI && |
(inqbuf->atap_config & WDC_CFG_ATAPI) && |
|
((inqbuf->atap_model[0] == 'N' && |
((inqbuf->atap_model[0] == 'N' && |
inqbuf->atap_model[1] == 'E') || |
inqbuf->atap_model[1] == 'E') || |
(inqbuf->atap_model[0] == 'F' && |
(inqbuf->atap_model[0] == 'F' && |
Line 981 device_identify(int argc, char *argv[]) |
|
Line 930 device_identify(int argc, char *argv[]) |
|
((uint64_t)inqbuf->atap_wwn[2] << 16) | |
((uint64_t)inqbuf->atap_wwn[2] << 16) | |
((uint64_t)inqbuf->atap_wwn[3] << 0)); |
((uint64_t)inqbuf->atap_wwn[3] << 0)); |
|
|
printf("Device type: %s", |
printf("Device type: %s, %s\n", inqbuf->atap_config & WDC_CFG_ATAPI ? |
inqbuf->atap_config == WDC_CFG_CFA_MAGIC ? "CF-ATA" : |
"ATAPI" : "ATA", inqbuf->atap_config & ATA_CFG_FIXED ? "fixed" : |
(inqbuf->atap_config & WDC_CFG_ATAPI ? "ATAPI" : "ATA")); |
"removable"); |
if (inqbuf->atap_config != WDC_CFG_CFA_MAGIC) |
|
printf(", %s", |
if (inqbuf->atap_cmd2_en != 0 && inqbuf->atap_cmd2_en != 0xffff && |
inqbuf->atap_config & ATA_CFG_FIXED ? "fixed" : "removable"); |
inqbuf->atap_cmd2_en & ATA_CMD2_LBA48) { |
printf("\n"); |
sectors = |
|
((uint64_t)inqbuf->atap_max_lba[3] << 48) | |
|
((uint64_t)inqbuf->atap_max_lba[2] << 32) | |
|
((uint64_t)inqbuf->atap_max_lba[1] << 16) | |
|
((uint64_t)inqbuf->atap_max_lba[0] << 0); |
|
} else if (inqbuf->atap_capabilities1 & WDC_CAP_LBA) { |
|
sectors = (inqbuf->atap_capacity[1] << 16) | |
|
inqbuf->atap_capacity[0]; |
|
} else { |
|
sectors = inqbuf->atap_cylinders * |
|
inqbuf->atap_heads * inqbuf->atap_sectors; |
|
} |
|
|
|
secsize = 512; |
|
|
compute_capacity(inqbuf, &capacity, §ors, &secsize); |
if ((inqbuf->atap_secsz & ATA_SECSZ_VALID_MASK) == ATA_SECSZ_VALID) { |
|
if (inqbuf->atap_secsz & ATA_SECSZ_LLS) { |
|
secsize = 2 * /* words to bytes */ |
|
(inqbuf->atap_lls_secsz[1] << 16 | |
|
inqbuf->atap_lls_secsz[0] << 0); |
|
} |
|
} |
|
|
|
capacity = sectors * secsize; |
|
|
humanize_number(hnum, sizeof(hnum), capacity, "bytes", |
humanize_number(hnum, sizeof(hnum), capacity, "bytes", |
HN_AUTOSCALE, HN_DIVISOR_1000); |
HN_AUTOSCALE, HN_DIVISOR_1000); |
Line 1072 device_identify(int argc, char *argv[]) |
|
Line 1042 device_identify(int argc, char *argv[]) |
|
inqbuf->atap_sata_features_supp, ata_sata_feat); |
inqbuf->atap_sata_features_supp, ata_sata_feat); |
} |
} |
|
|
if ((inqbuf->atap_ata_major & WDC_VER_ATA7) && |
if ((inqbuf->atap_ata_major & WDC_VER_ATA8) && |
(inqbuf->support_dsm & ATA_SUPPORT_DSM_TRIM)) |
(inqbuf->support_dsm & ATA_SUPPORT_DSM_TRIM)) |
printf("TRIM supported\n"); |
printf("TRIM supported\n"); |
|
|
Line 1398 device_security(int argc, char *argv[]) |
|
Line 1368 device_security(int argc, char *argv[]) |
|
{ |
{ |
struct atareq req; |
struct atareq req; |
const struct ataparams *inqbuf; |
const struct ataparams *inqbuf; |
unsigned char data[DEV_BSIZE]; |
|
char *pass; |
|
|
|
/* need subcommand */ |
/* need subcommand */ |
if (argc < 1) |
if (argc < 1) |
usage(); |
usage(); |
|
|
memset(&req, 0, sizeof(req)); |
if (strcmp(argv[0], "freeze") == 0) { |
if (strcmp(argv[0], "status") == 0) { |
memset(&req, 0, sizeof(req)); |
inqbuf = getataparams(); |
|
print_bitinfo("\t", "\n", inqbuf->atap_sec_st, ata_sec_st); |
|
} else if (strcmp(argv[0], "freeze") == 0) { |
|
req.command = WDCC_SECURITY_FREEZE; |
req.command = WDCC_SECURITY_FREEZE; |
req.timeout = 1000; |
req.timeout = 1000; |
ata_command(&req); |
ata_command(&req); |
} else if ((strcmp(argv[0], "setpass") == 0) || |
} else if (strcmp(argv[0], "status") == 0) { |
(strcmp(argv[0], "unlock") == 0) || |
inqbuf = getataparams(); |
(strcmp(argv[0], "disable") == 0) || |
print_bitinfo("\t", "\n", inqbuf->atap_sec_st, ata_sec_st); |
(strcmp(argv[0], "erase") == 0)) { |
} else |
if (argc != 2) |
|
usage(); |
|
if (strcmp(argv[1], "user") != 0) { |
|
if (strcmp(argv[1], "master") == 0) { |
|
fprintf(stderr, |
|
"Master passwords not supported\n"); |
|
exit(1); |
|
} else { |
|
usage(); |
|
} |
|
} |
|
|
|
pass = getpass("Password:"); |
|
if (strlen(pass) > 32) { |
|
fprintf(stderr, "Password must be <=32 characters\n"); |
|
exit(1); |
|
} |
|
|
|
req.flags |= ATACMD_WRITE; |
|
req.timeout = 1000; |
|
req.databuf = data; |
|
req.datalen = sizeof(data); |
|
memset(data, 0, sizeof(data)); |
|
strlcpy((void *)&data[2], pass, 32 + 1); |
|
|
|
if (strcmp(argv[0], "setpass") == 0) { |
|
char orig[32 + 1]; |
|
strlcpy(orig, pass, 32 + 1); |
|
pass = getpass("Confirm password:"); |
|
if (0 != strcmp(orig, pass)) { |
|
fprintf(stderr, "Passwords do not match\n"); |
|
exit(1); |
|
} |
|
req.command = WDCC_SECURITY_SET_PASSWORD; |
|
} else if (strcmp(argv[0], "unlock") == 0) { |
|
req.command = WDCC_SECURITY_UNLOCK; |
|
} else if (strcmp(argv[0], "disable") == 0) { |
|
req.command = WDCC_SECURITY_DISABLE_PASSWORD; |
|
} else if (strcmp(argv[0], "erase") == 0) { |
|
struct atareq prepare; |
|
|
|
inqbuf = getataparams(); |
|
|
|
/* |
|
* XXX Any way to lock the device to make sure |
|
* this really is the command preceding the |
|
* SECURITY ERASE UNIT command? This would |
|
* probably have to be moved into the kernel to |
|
* do that. |
|
*/ |
|
memset(&prepare, 0, sizeof(prepare)); |
|
prepare.command = WDCC_SECURITY_ERASE_PREPARE; |
|
prepare.timeout = 1000; |
|
ata_command(&prepare); |
|
|
|
req.command = WDCC_SECURITY_ERASE_UNIT; |
|
|
|
/* |
|
* Enable enhanced erase if it's supported. |
|
* |
|
* XXX should be a command-line option |
|
*/ |
|
if (inqbuf->atap_sec_st & WDC_SEC_ESE_SUPP) { |
|
data[0] |= 0x2; |
|
req.timeout = (inqbuf->atap_eseu_time & 0xff) |
|
* 2 * 60 * 1000; |
|
} else { |
|
req.timeout = (inqbuf->atap_seu_time & 0xff) |
|
* 2 * 60 * 1000; |
|
} |
|
|
|
/* |
|
* If the estimated time was 0xff (* 2 * 60 * |
|
* 1000 = 30600000), that means `>508 minutes'. |
|
* Estimate that we can handle 16 MB/sec, a |
|
* rate I just pulled out of my arse. |
|
*/ |
|
if (req.timeout == 30600000) { |
|
uint64_t bytes, timeout; |
|
compute_capacity(inqbuf, &bytes, NULL, NULL); |
|
timeout = (bytes / (16 * 1024 * 1024)) * 1000; |
|
if (timeout > (uint64_t)INT_MAX) |
|
req.timeout = INT_MAX; |
|
else |
|
req.timeout = timeout; |
|
} |
|
|
|
printf("Erasing may take up to %dh %dm %ds...\n", |
|
(req.timeout / 1000 / 60) / 60, |
|
(req.timeout / 1000 / 60) % 60, |
|
req.timeout % 60); |
|
} else { |
|
abort(); |
|
} |
|
|
|
ata_command(&req); |
|
} else { |
|
usage(); |
usage(); |
} |
|
|
return; |
} |
} |
|
|
/* |
/* |