"smart status" already obtains the ata parameters to check if smart
is actually supported, so we can attempt to guess a vendor smart table from the model name. add basic support for all the micron / crucial disk names i could find, and add a couple more micron specific values. XXX: probably should add regex support for matching, and probably should be more restrictive with the current matches.
This commit is contained in:
parent
568f3ff655
commit
3d07a0370e
|
@ -1,4 +1,4 @@
|
|||
.\" $NetBSD: atactl.8,v 1.26 2018/11/03 10:51:14 wiz Exp $
|
||||
.\" $NetBSD: atactl.8,v 1.27 2018/12/05 06:49:54 mrg Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
.\" All rights reserved.
|
||||
|
@ -27,7 +27,7 @@
|
|||
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
.\" POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd October 4, 2018
|
||||
.Dd December 5, 2018
|
||||
.Dt ATACTL 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
@ -162,6 +162,8 @@ information if known to
|
|||
Currently, only
|
||||
.Dq micron
|
||||
has a vendor-specific table.
|
||||
If the vendor is not supplied, it may be guessed from devices' model
|
||||
or other data available.
|
||||
.It Ar offline #
|
||||
Runs the numbered offline self-test on the drive.
|
||||
.It Ar error-log
|
||||
|
@ -273,6 +275,10 @@ It was based heavily on the
|
|||
.Xr scsictl 8
|
||||
command written by
|
||||
.An Jason R. Thorpe .
|
||||
.An Matthew R. Green
|
||||
significantly enhanced the
|
||||
.Cm smart status
|
||||
support.
|
||||
.Sh BUGS
|
||||
The output from the
|
||||
.Cm identify
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: atactl.c,v 1.78 2018/10/31 20:00:56 mrg Exp $ */
|
||||
/* $NetBSD: atactl.c,v 1.79 2018/12/05 06:49:54 mrg Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
|
@ -35,7 +35,7 @@
|
|||
#include <sys/cdefs.h>
|
||||
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: atactl.c,v 1.78 2018/10/31 20:00:56 mrg Exp $");
|
||||
__RCSID("$NetBSD: atactl.c,v 1.79 2018/12/05 06:49:54 mrg Exp $");
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -114,7 +114,7 @@ static void print_selftest_entry(int, const struct ata_smart_selftest *);
|
|||
static void print_error(const void *);
|
||||
static void print_selftest(const void *);
|
||||
|
||||
static const struct ataparams *getataparams(void);
|
||||
static void fillataparams(void);
|
||||
|
||||
static int is_smart(void);
|
||||
|
||||
|
@ -122,6 +122,10 @@ static int fd; /* file descriptor for device */
|
|||
static const char *dvname; /* device name */
|
||||
static char dvname_store[MAXPATHLEN]; /* for opendisk(3) */
|
||||
static const char *cmdname; /* command user issued */
|
||||
static const struct ataparams *inqbuf; /* inquiry buffer */
|
||||
static char model[sizeof(inqbuf->atap_model)+1];
|
||||
static char revision[sizeof(inqbuf->atap_revision)+1];
|
||||
static char serial[sizeof(inqbuf->atap_serial)+1];
|
||||
|
||||
static void device_identify(int, char *[]);
|
||||
static void device_setidle(int, char *[]);
|
||||
|
@ -355,7 +359,9 @@ static const struct attr_table {
|
|||
static const struct attr_table micron_smart_names[] = {
|
||||
{ 5, "Reallocated NAND block count", NULL },
|
||||
{ 173, "Average block erase count", NULL },
|
||||
{ 181, "Non 4K aligned access count", NULL },
|
||||
{ 184, "Error correction count", NULL },
|
||||
{ 189, "Factory bad block count", NULL },
|
||||
{ 197, "Current pending ECC count", NULL },
|
||||
{ 198, "SMART offline scan uncorrectable error count", NULL },
|
||||
{ 202, "Percent lifetime remaining", NULL },
|
||||
|
@ -855,14 +861,19 @@ print_selftest(const void *buf)
|
|||
print_selftest_entry(i, &stlog->log_entries[i]);
|
||||
}
|
||||
|
||||
static const struct ataparams *
|
||||
getataparams(void)
|
||||
static void
|
||||
fillataparams(void)
|
||||
{
|
||||
struct atareq req;
|
||||
static union {
|
||||
unsigned char inbuf[DEV_BSIZE];
|
||||
struct ataparams inqbuf;
|
||||
} inbuf;
|
||||
static int first = 1;
|
||||
|
||||
if (!first)
|
||||
return;
|
||||
first = 0;
|
||||
|
||||
memset(&inbuf, 0, sizeof(inbuf));
|
||||
memset(&req, 0, sizeof(req));
|
||||
|
@ -875,7 +886,7 @@ getataparams(void)
|
|||
|
||||
ata_command(&req);
|
||||
|
||||
return (&inbuf.inqbuf);
|
||||
inqbuf = &inbuf.inqbuf;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -888,10 +899,9 @@ static int
|
|||
is_smart(void)
|
||||
{
|
||||
int retval = 0;
|
||||
const struct ataparams *inqbuf;
|
||||
const char *status;
|
||||
|
||||
inqbuf = getataparams();
|
||||
fillataparams();
|
||||
|
||||
if (inqbuf->atap_cmd_def != 0 && inqbuf->atap_cmd_def != 0xffff) {
|
||||
if (!(inqbuf->atap_cmd_set1 & WDC_CMD1_SMART)) {
|
||||
|
@ -951,8 +961,7 @@ extract_string(char *buf, size_t bufmax,
|
|||
}
|
||||
|
||||
static void
|
||||
compute_capacity(const struct ataparams *inqbuf, uint64_t *capacityp,
|
||||
uint64_t *sectorsp, uint32_t *secsizep)
|
||||
compute_capacity(uint64_t *capacityp, uint64_t *sectorsp, uint32_t *secsizep)
|
||||
{
|
||||
uint64_t capacity;
|
||||
uint64_t sectors;
|
||||
|
@ -994,38 +1003,51 @@ compute_capacity(const struct ataparams *inqbuf, uint64_t *capacityp,
|
|||
}
|
||||
|
||||
/*
|
||||
* DEVICE COMMANDS
|
||||
* Inspect the inqbuf and guess what vendor to use. This list is fairly
|
||||
* basic, and probably should be converted into a regexp scheme.
|
||||
*/
|
||||
static const char *
|
||||
guess_vendor(void)
|
||||
{
|
||||
struct {
|
||||
const char *model;
|
||||
const char *vendor;
|
||||
} model_to_vendor[] = {
|
||||
{ "Crucial", "Micron" },
|
||||
{ "Micron", "Micron" },
|
||||
{ "C300-CT", "Micron" },
|
||||
{ "C400-MT", "Micron" },
|
||||
{ "M4-CT", "Micron" },
|
||||
{ "M500", "Micron" },
|
||||
{ "M510", "Micron" },
|
||||
{ "M550", "Micron" },
|
||||
{ "MTFDDA", "Micron" },
|
||||
{ "EEFDDA", "Micron" },
|
||||
};
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < __arraycount(model_to_vendor); i++)
|
||||
if (strncasecmp(model, model_to_vendor[i].model,
|
||||
strlen(model_to_vendor[i].model)) == 0)
|
||||
return model_to_vendor[i].vendor;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* device_identify:
|
||||
*
|
||||
* Display the identity of the device
|
||||
* identify_fixup() - Given an obtained ataparams, fix up the endian and
|
||||
* other issues before using them.
|
||||
*/
|
||||
static void
|
||||
device_identify(int argc, char *argv[])
|
||||
identify_fixup(void)
|
||||
{
|
||||
const struct ataparams *inqbuf;
|
||||
char model[sizeof(inqbuf->atap_model)+1];
|
||||
char revision[sizeof(inqbuf->atap_revision)+1];
|
||||
char serial[sizeof(inqbuf->atap_serial)+1];
|
||||
char hnum[12];
|
||||
uint64_t capacity;
|
||||
uint64_t sectors;
|
||||
uint32_t secsize;
|
||||
int lb_per_pb;
|
||||
int needswap = 0;
|
||||
int i;
|
||||
uint8_t checksum;
|
||||
|
||||
/* No arguments. */
|
||||
if (argc != 0)
|
||||
usage();
|
||||
|
||||
inqbuf = getataparams();
|
||||
|
||||
if ((inqbuf->atap_integrity & WDC_INTEGRITY_MAGIC_MASK) ==
|
||||
WDC_INTEGRITY_MAGIC) {
|
||||
int i;
|
||||
uint8_t checksum;
|
||||
|
||||
for (i = checksum = 0; i < 512; i++)
|
||||
checksum += ((const uint8_t *)inqbuf)[i];
|
||||
if (checksum != 0)
|
||||
|
@ -1062,6 +1084,33 @@ device_identify(int argc, char *argv[])
|
|||
inqbuf->atap_serial, sizeof(inqbuf->atap_serial),
|
||||
needswap);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* DEVICE COMMANDS
|
||||
*/
|
||||
|
||||
/*
|
||||
* device_identify:
|
||||
*
|
||||
* Display the identity of the device
|
||||
*/
|
||||
static void
|
||||
device_identify(int argc, char *argv[])
|
||||
{
|
||||
char hnum[12];
|
||||
uint64_t capacity;
|
||||
uint64_t sectors;
|
||||
uint32_t secsize;
|
||||
int lb_per_pb;
|
||||
|
||||
/* No arguments. */
|
||||
if (argc != 0)
|
||||
usage();
|
||||
|
||||
fillataparams();
|
||||
identify_fixup();
|
||||
|
||||
printf("Model: %s, Rev: %s, Serial #: %s\n",
|
||||
model, revision, serial);
|
||||
|
||||
|
@ -1081,7 +1130,7 @@ device_identify(int argc, char *argv[])
|
|||
inqbuf->atap_config & ATA_CFG_FIXED ? "fixed" : "removable");
|
||||
printf("\n");
|
||||
|
||||
compute_capacity(inqbuf, &capacity, §ors, &secsize);
|
||||
compute_capacity(&capacity, §ors, &secsize);
|
||||
|
||||
humanize_number(hnum, sizeof(hnum), capacity, "bytes",
|
||||
HN_AUTOSCALE, HN_DIVISOR_1000);
|
||||
|
@ -1361,7 +1410,7 @@ device_smart(int argc, char *argv[])
|
|||
is_smart();
|
||||
} else if (strcmp(argv[0], "status") == 0) {
|
||||
int rv;
|
||||
char *vendor = argc > 1 ? argv[1] : NULL;
|
||||
const char *vendor = argc > 1 ? argv[1] : NULL;
|
||||
|
||||
rv = is_smart();
|
||||
|
||||
|
@ -1416,6 +1465,11 @@ device_smart(int argc, char *argv[])
|
|||
|
||||
ata_command(&req);
|
||||
|
||||
if (!vendor || strcmp(vendor, "noauto") == 0) {
|
||||
fillataparams();
|
||||
identify_fixup();
|
||||
vendor = guess_vendor();
|
||||
}
|
||||
print_smart_status(inbuf, inbuf2, vendor);
|
||||
|
||||
} else if (strcmp(argv[0], "offline") == 0) {
|
||||
|
@ -1490,7 +1544,6 @@ static void
|
|||
device_security(int argc, char *argv[])
|
||||
{
|
||||
struct atareq req;
|
||||
const struct ataparams *inqbuf;
|
||||
unsigned char data[DEV_BSIZE];
|
||||
char *pass;
|
||||
|
||||
|
@ -1500,7 +1553,7 @@ device_security(int argc, char *argv[])
|
|||
|
||||
memset(&req, 0, sizeof(req));
|
||||
if (strcmp(argv[0], "status") == 0) {
|
||||
inqbuf = getataparams();
|
||||
fillataparams();
|
||||
print_bitinfo("\t", "\n", inqbuf->atap_sec_st, ata_sec_st);
|
||||
} else if (strcmp(argv[0], "freeze") == 0) {
|
||||
req.command = WDCC_SECURITY_FREEZE;
|
||||
|
@ -1551,7 +1604,7 @@ device_security(int argc, char *argv[])
|
|||
} else if (strcmp(argv[0], "erase") == 0) {
|
||||
struct atareq prepare;
|
||||
|
||||
inqbuf = getataparams();
|
||||
fillataparams();
|
||||
|
||||
/*
|
||||
* XXX Any way to lock the device to make sure
|
||||
|
@ -1589,7 +1642,7 @@ device_security(int argc, char *argv[])
|
|||
*/
|
||||
if (req.timeout == 30600000) {
|
||||
uint64_t bytes, timeout;
|
||||
compute_capacity(inqbuf, &bytes, NULL, NULL);
|
||||
compute_capacity(&bytes, NULL, NULL);
|
||||
timeout = (bytes / (16 * 1024 * 1024)) * 1000;
|
||||
if (timeout > (uint64_t)INT_MAX)
|
||||
req.timeout = INT_MAX;
|
||||
|
|
Loading…
Reference in New Issue