Add Erik Quanstrom's atazz

(needed to disable power management/head unload on 2.5" drive)
This commit is contained in:
google 2012-09-20 22:39:48 +12:00
parent 913afc39c9
commit fa7fb8b66b
11 changed files with 6820 additions and 0 deletions

131
sys/src/cmd/atazz/atazz.h Normal file
View file

@ -0,0 +1,131 @@
enum {
Cmdn = 1,
Cmdf, /* cfa only */
Cmdp, /* packet */
Cmd5sc, /* 512-byte sector size, set sector count */
};
typedef struct Dev Dev;
struct Dev {
Sfis;
int fd;
uint secsize;
uvlong nsect;
uvlong wwn;
};
enum {
Cmdsz = 18,
Replysz = 18,
};
typedef struct Rcmd Rcmd;
struct Rcmd {
uchar sdcmd; /* sd command; 0xff means ata passthrough */
uchar ataproto; /* ata protocol. non-data, pio, reset, dd, etc. */
uchar fis[Fissize];
};
typedef struct Req Req;
struct Req {
int rfd;
int wfd;
uchar fmtrw;
uvlong lba;
uvlong count; /* bytes; allow long sectors to work */
uint nsect;
char haverfis;
uint fisbits; /* bitmask of manually set fields */
Rcmd cmd;
Rcmd reply;
uchar *data;
uchar raw;
};
void sigfmt(Req*);
void idfmt(Req*);
void iofmt(Req*);
void sdfmt(Req*);
void smfmt(Req*);
void slfmt(Req*);
void glfmt(Req*);
typedef struct Btab Btab;
struct Btab {
int bit;
char *name;
};
char *sebtab(char*, char*, Btab*, int, uint);
typedef struct Txtab Txtab;
typedef struct Fetab Fetab;
struct Txtab {
int val;
char *name;
Fetab *fe;
};
struct Fetab {
int reg;
Txtab *tab;
int ntab;
};
/* sct “registers” */
enum {
Sbase = 1<<5,
Sbyte = 0<<6,
Sw = 1<<6,
Sdw = 2<<6,
Sqw = 3<<6,
Ssz = 3<<6,
Saction = 0 | Sbase | Sw,
Sfn = 1 | Sbase | Sw,
Slba = 2 | Sbase | Sqw,
Scnt = 6 | Sbase | Sqw,
Spat = 10 | Sbase | Sdw,
Ssc = 2 | Sbase | Sw,
Stimer = 3 | Sbase | Sw,
Sfe = 2 | Sbase | Sw,
Sstate = 3 | Sbase | Sw,
Soptf = 4 | Sbase | Sw,
Stabid = 2 | Sbase | Sw,
Pbase = 1<<6,
};
void pw(uchar*, ushort);
void pdw(uchar*, uint);
void pqw(uchar*, uvlong);
ushort w(uchar*);
uint dw(uchar*);
uvlong qw(uchar*);
/*
* botch. integrate with fis.h?
*/
enum {
Psct = 1<<6 + 8,
};
typedef struct Atatab Atatab;
struct Atatab {
ushort cc;
uchar flags;
uchar pktflags;
ushort protocol;
Fetab *tab;
void (*fmt)(Req*);
char *name;
};
int eprint(char *, ...);
int opendev(char*, Dev*);
int probe(void);
extern int squelch;
#pragma varargck argpos eprint 1
#pragma varargck type "π" char**

573
sys/src/cmd/atazz/atazz.ms Normal file
View file

@ -0,0 +1,573 @@
.FP lucidasans
.TL
ATA au Naturel
.AU
Erik Quanstrom
quanstro@quanstro.net
.AB
The Plan 9
.I sd (3)
interface allows raw commands to be sent. Traditionally,
only SCSI CDBs could be sent in this manner. For devices
that respond to ATA/ATAPI commands, a small set of SCSI CDBs
have been translated into an ATA equivalent. This approach
works very well. However, there are ATA commands such as
SMART which do not have direct translations. I describe how
ATA/ATAPI commands were supported without disturbing
existing functionality.
.AE
.SH
Introduction
.PP
In writing new
.I sd (3)
drivers for plan 9, it has been necessary to copy laundry
list of special commands that were needed with previous
drivers. The set of commands supported by each device
driver varies, and they are typically executed by writing a
magic string into the driver's
.CW ctl
file. This requires code duplicated for each driver, and
covers few commands. Coverage depends on the driver. It is
not possible for the control interface to return output,
making some commands impossible to implement. While a
work around has been to change the contents of the control
file, this solution is extremely unwieldy even for simple
commands such as
.CW "IDENTIFY DEVICE" .
.SH
Considerations
.PP
Currently, all
.I sd
devices respond to a small subset of SCSI commands
through the raw interface and the normal read/write interface uses
SCSI command blocks. SCSI devices, of course, respond natively
while ATA devices emulate these commands with the help
.I sd .
This means that
.I scuzz (8)
can get surprisingly far with ATA devices, and ATAPI
.I \fP(\fPsic. )
devices
work quite well. Although a new implementation might not
use this approach, replacing the interface did not appear
cost effective and would lead to maximum incompatibilities,
while this interface is experimental. This means that the raw interface will need
a method of signaling an ATA command rather than a SCSI CDB.
.PP
An unattractive wart of the ATA command set is there are seven
protocols and two command sizes. While each command has a
specific size (either 28-bit LBA or 48-bit LLBA) and is
associated with a particular protocol (PIO, DMA, PACKET,
etc.), this information is available only by table lookup.
While this information may not always be necessary for simple
SATA-based controllers, for the IDE controllers, it is required.
PIO commands are required and use a different set of registers
than DMA commands. Queued DMA commands and ATAPI
commands are submitted differently still. Finally,
the data direction is implied by the command. Having these
three extra pieces of information in addition to the command
seems necessary.
.PP
A final bit of extra-command information that may be useful
is a timeout. While
.I alarm (2)
timeouts work with many drivers, it would be an added
convenience to be able to specify a timeout along with the
command. This seems a good idea in principle, since some
ATA commands should return within milli- or microseconds,
others may take hours to complete. On the other hand, the
existing SCSI interface does not support it and changing its
kernel-to-user space format would be quite invasive. Timeouts
were left for a later date.
.SH
Protocol and Data Format
.PP
The existing protocol for SCSI commands suits ATA as well.
We simply write the command block to the raw device. Then
we either write or read the data. Finally the status block
is read. What remains is choosing a data format for ATA
commands.
.PP
The T10 Committee has defined a SCSI-to-ATA translation
scheme called SAT[4]. This provides a standard set of
translations between common SCSI commands and ATA commands.
It specifies the ATA protocol and some other sideband
information. It is particularly useful for common commands
such as
.CW "READ\ (12)"
or
.CW "READ CAPACITY\ (12)" .
Unfortunately, our purpose is to address the uncommon commands.
For those, special commands
.CW "ATA PASSTHROUGH\ (12)"
and
.CW "(16)"
exist. Unfortunately several commands we are interested in,
such as those that set transfer modes are not allowed by the
standard. This is not a major obstacle. We could simply
ignore the standard. But this goes against the general
reasons for using an established standard: interoperability.
Finally, it should be mentioned that SAT format adds yet
another intermediate format of variable size which would
require translation to a usable format for all the existing
Plan 9 drivers. If we're not hewing to a standard, we should
build or choose for convenience.
.PP
ATA-8 and ACS-2 also specify an abstract register layout.
The size of the command block varies based on the “size”
(either 28- or 48-bits) of the command and only context
differentiates a command from a response. The SATA
specification defines host-to-drive communications. The
formats of transactions are called Frame Information
Structures (FISes). Typically drivers fill out the command
FISes directly and have direct access to the Device-to-Host
Register (D2H) FISes that return the resulting ATA register
settings. The command FISes are also called Host-to-Device
(H2D) Register FISes. Using this structure has several advantages. It
is directly usable by many of the existing SATA drivers.
All SATA commands are the same size and are tagged as
commands. Normal responses are also all of the same size
and are tagged as responses. Unfortunately, the ATA
protocol is not specified. Nevertheless, SATA FISes seem to
handle most of our needs and are quite convenient; they can
be used directly by two of the three current SATA drivers.
.SH
Implementation
.PP
Raw ATA commands are formatted as a ATA escape byte, an
encoded ATA protocol
.CW proto
and the FIS. Typically this would be a
H2D FIS, but this is not a requirement. The escape byte
.R 0xff ,
which is not and, according to the current specification,
will never be a valid SCSI command, was chosen. The
protocol encoding
.CW proto
and other FIS construction details are specified in
.CW "/sys/include/fis.h" .
The
.CW proto
encodes the ATA protocol, the command “size” and data
direction. The “atazz” command format is pictured in \*(Fn.
.F1
.PS
scale=10
w=8
h=2
define hdr |
[
box $1 ht h wid w
] |
define fis |
[
box $1 ht h wid w
] |
F: [
A: hdr("0xff")
hdr("proto")
hdr("0x27")
hdr("flags")
B: hdr("cmd") at A+(0, -h)
hdr("feat")
hdr("lba0")
hdr("lba8")
C: hdr("lba16") at B+(0, -h)
hdr("dev")
hdr("lba24")
hdr("lba32")
D: hdr("lba40") at C+(0, -h)
hdr("feat8")
hdr("cnt")
hdr("cnt8")
E: hdr("rsvd") at D+(0, -h)
hdr("ctl")
]
G: [
fis("sdXX/raw")
] at F.se +(w*2, -h)
arrow from F.e to G.w
H: [
fis("data")
] at G.sw +(-w*2, -h)
HH: [
fis("sdXX/raw")
] at H.se +(w*2, -h)
arrow from H.e to HH.w
Q: [
fis("sdXX/raw")
] at HH +(0, -2*h)
I: [
K: hdr("0xff")
hdr("proto")
hdr("0x34")
hdr("port");
L: hdr("stat") at K+(0, -h)
hdr("err")
hdr("lba0")
hdr("lba8")
M: hdr("lba16") at L+(0, -h)
hdr("dev")
hdr("lba24")
hdr("lba32")
O: hdr("lba40") at M+(0, -h)
hdr("feat8")
hdr("cnt")
hdr("cnt8")
P: hdr("rsvd") at O+(0, -h)
hdr("ctl")
] at Q.sw +(-w*3.5, -3*h)
arrow from Q.w to I.e
.PE
.F2
.F3
.PP
Raw ATA replies are formatted as a one-byte
.R sd
status code followed by the reply FIS.
The usual read/write register substitutions are
applied; ioport replaces flags, status replaces cmd, error
replaces feature.
.PP
Important commands such as
.CW "SMART RETURN STATUS"
return no data. In this case, the protocol is run as usual.
The client performs a 0-byte read to fulfill data transfer
step. The status is in the D2H FIS returned as the status.
The vendor ATA command
.R 0xf0
is used to return the device signature FIS as there is no
universal in-band way to do this without side effects.
When talking only to ATA drives, it is possible to first
issue a
.CW "IDENTIFY PACKET DEVICE"
and then a
.CW "IDENTIFY DEVICE"
command, inferring the device type from the successful
command. However, it would not be possible to enumerate the
devices behind a port multiplier using this technique.
.SH
Kernel changes and Libfis
.PP
Very few changes were made to devsd to accommodate ATA
commands. the
.CW SDreq
structure adds
.CW proto
and
.CW ataproto
fields. To avoid disturbing existing SCSI functionality and
to allow drivers which support SCSI and ATA commands in
parallel, an additional
.CW ataio
callback was added to
.CW SDifc
with the same signature as
the existing
.CW rio
callback. About twenty lines of code were
added to
.CW port/devsd.c
to recognize raw ATA commands and call the
driver's
.CW ataio
function.
.PP
To assist in generating the FISes to communicate with devices,
.CW libfis
was written. It contains functions to identify and
enumerate the important features of a drive, to format
H2D FISes And finally, functions for
.I sd
and
.I sd
-devices to build D2H FISes to
capture the device signature.
.PP
All ATA device drivers for the 386 architecture have been
modified to accept raw ATA commands. Due to consolidation
of FIS handling, the AHCI driver lost
175 lines of code, additional non-atazz-related functionality
notwithstanding. The IDE driver remained exactly the same
size. Quite a bit more code could be removed if the driver
were reorganized. The mv50xx driver gained 153 lines of
code. Development versions of the Marvell Orion driver
lost over 500 lines while
.CW libfis
is only about the same line count.
.PP
Since FIS formats were used to convey
commands from user space,
.CW libfis
has been equally useful for user space applications. This is
because the
.I atazz
interface can be thought of as an idealized HBA. Conversely,
the hardware driver does not need to know anything about
the command it is issuing beyond the ATA protocol.
.SH
Atazz
.PP
As an example and debugging tool, the
.I atazz (8)
command was written.
.I Atazz
is an analog to
.I scuzz (8);
they can be thought of as a driver for a virtual interface provided
by
.I sd
combined with a disk console.
ATA commands are spelled out verbosely as in ACS-2. Arbitrary ATA
commands may be submitted, but the controller or driver may
not support all of them. Here is a sample transcript:
.P1
az> probe
/dev/sda0 976773168; 512 50000f001b206489
/dev/sdC1 0; 0 0
/dev/sdD0 1023120; 512 0
/dev/sdE0 976773168; 512 50014ee2014f5b5a
/dev/sdF7 976773168; 512 5000cca214c3a6d3
az> open /dev/sdF0
az> smart enable operations
az> smart return status
normal
az> rfis
00
34405000004fc2a00000000000000000
.P2
.PP
In the example, the
.CW probe
command is a special command that uses
.CW #S/sdctl
to enumerate the controllers in the system.
For each controller, the
.CW sd
vendor command
.CW 0xf0
.CW \fP(\fPGET
.CW SIGNATURE )
is issued. If this command is successful, the
number of sectors, sector size and WWN are gathered
and and listed. The
.CW /dev/sdC1
device reports 0 sectors and 0 sector size because it is
a DVD-RW with no media. The
.CW open
command is another special command that issues the
same commands a SATA driver would issue to gather
the information about the drive. The final two commands
enable SMART
and return the SMART status. The smart status is
returned in a D2H FIS. This result is parsed the result
is printed as either “normal,” or “threshold exceeded”
(the drive predicts imminent failure).
.PP
As a further real-world example, a drive from my file server
failed after a power outage. The simple diagnostic
.CW "SMART RETURN STATUS"
returned an uninformative “threshold exceeded.”
We can run some more in-depth tests. In this case we
will need to make up for the fact that
.I atazz
does not know every option to every command. We
will set the
.CW lba0
register by hand:
.P1
az> smart lba0 1 execute off-line immediate # short data collection
az> smart read data
col status: 00 never started
exe status: 89 failed: shipping damage, 90% left
time left: 10507s
shrt poll: 176m
ext poll: 19m
az>
.P2
.PP
Here we see that the drive claims that it was damaged in
shipping and the damage occurred in the first 10% of the
drive. Since we know the drive had been working before
the power outage, and the original symptom was excessive
UREs (Unrecoverable Read Errors) followed by write
failures, and finally a threshold exceeded condition, it is
reasonable to assume that the head may have crashed.
.SH
Stand Alone Applications
.PP
There are several obvious stand-alone applications for
this functionality: a drive firmware upgrade utility,
a drive scrubber that bypasses the drive cache and a
SMART monitor.
.PP
Since SCSI also supports a basic SMART-like
interface through the
.CW "SEND DIAGNOSTIC"
and
.CW "RECEIVE DIAGNOSTIC RESULTS"
commands,
.I disk/smart (8)
gives a chance to test both raw ATA and SCSI
commands in the same application.
.PP
.I Disk/smart
uses the usual techniques for gathering a list of
devices or uses the devices given. Then it issues a raw ATA request for
the device signature. If that fails, it is assumed
that the drive is SCSI, and a raw SCSI request is issued.
In both cases,
.I disk/smart
is able to reliably determine if SMART is supported
and can be enabled.
.PP
If successful, each device is probed every 5 minutes
and failures are logged. A one shot mode is also
available:
.P1
chula# disk/smart -atv
sda0: normal
sda1: normal
sda2: normal
sda3: threshold exceeded
sdE1: normal
sdF7: normal
.P2
.PP
Drives
.CW sda0 ,
.CW sda1
are SCSI
and the remainder are ATA. Note that other drives
on the same controller are ATA.
Recalling that
.CW sdC0
was previously listed, we can check to see why no
results were reported by
.CW sdC0 :
.P1
chula# for(i in a3 C0)
echo identify device |
atazz /dev/sd$i >[2]/dev/null |
grep '^flags'
flags lba llba smart power nop sct
flags lba
.P2
So we see that
.CW sdC0
simply does not support the SMART feature set.
.SH
Further Work
.PP
While the raw ATA interface has been used extensively
from user space and has allowed the removal of quirky
functionality, device setup has not yet been addressed.
For example, both the Orion and AHCI drivers have
an initialization routine similar to the following
.P1
newdrive(Drive *d)
{
setfissig(d, getsig(d));
if(identify(d) != 0)
return SDeio;
setpowermode(d);
if(settxmode(d, d->udma) != 0)
return SDeio;
return SDok;
}
.P2
However in preparing this document, it was discovered
that one sets the power mode before setting the
transfer mode and the other does the opposite. It is
not clear that this particular difference is a problem,
but over time, such differences will be the source of bugs.
Neither the IDE nor the Marvell 50xx drivers sets the
power mode at all. Worse,
none is capable of properly addressing drives with
features such as PUIS (Power Up In Standby) enabled.
To addresses this problem all four of the ATA drivers would
need to be changed.
.PP
Rather than maintaining a number of mutually out-of-date
drivers, it would be advantageous to build an ATA analog
of
.CW pc/sdscsi.c
using the raw ATA interface to submit ATA commands.
There are some difficulties that make such a change a bit
more than trivial. Since current model for hot-pluggable
devices is not compatible with the top-down
approach currently taken by
.I sd
this would need to be addressed. It does not seem that
this would be difficult. Interface resets after failed commands
should also be addressed.
.SH
Source
.PP
The current source including all the pc drivers and applications
are available
in the following
.I contrib (1)
packages on
.I sources :
.br
.CW "quanstro/fis" ,
.br
.CW "quanstro/sd" ,
.br
.CW "quanstro/atazz" ,
and
.br
.CW "quanstro/smart" .
.PP
The following manual pages are included:
.br
.I fis (2),
.I sd (3),
.I sdahci (3),
.I sdaoe (3),
.I sdloop (3),
.I sdorion (3),
.I atazz (8),
and
.I smart (8).
.SH
Abbreviated References
.nr PI 5n
.IP [1]
.I sd (1),
published online at
.br
.CW "http://plan9.bell-labs.com/magic/man2html/3/sd" .
.IP [2]
.I scuzz (8),
published online at
.br
.CW "http://plan9.bell-labs.com/magic/man2html/8/scuzz" .
.IP [3]
T13
.I "ATA/ATAPI Command Set\ \-\ 2" ,
revision 1, January 21, 2009,
formerly published online at
.CW "http://www.t13.org" .
.IP [4]
T10
.I "SCSI/ATA Translation\ \-\ 2 (SAT\-2)" ,
revision 7, February 18, 2007,
formerly published online at
.CW "http://www.t10.org" .

3414
sys/src/cmd/atazz/atazz.ps Normal file

File diff suppressed because it is too large Load diff

71
sys/src/cmd/atazz/bit.c Normal file
View file

@ -0,0 +1,71 @@
#include <u.h>
#include <libc.h>
#include <fis.h>
#include "atazz.h"
char*
sebtab(char *p, char *e, Btab *t, int nt, uint u)
{
char *p0;
int i;
p0 = p;
for(i = 0; i < nt; i++)
if(u & 1<< t[i].bit)
p = seprint(p, e, "%s ", t[i].name);
if(p > p0)
p--;
*p = 0;
return p;
}
void
pw(uchar *p, ushort i)
{
p[0] = i >> 0;
p[1] = i >> 8;
}
void
pdw(uchar *p, uint i)
{
p[0] = i >> 0;
p[1] = i >> 8;
p[2] = i >> 16;
p[3] = i >> 24;
}
void
pqw(uchar *p, uvlong i)
{
pdw(p, i);
pdw(p + 4, i >> 32);
}
ushort
w(uchar *u)
{
ushort r;
r = u[0] << 0;
r |= u[1] << 8;
return r;
}
uint
dw(uchar *u)
{
ulong r;
r = u[0] << 0;
r |= u[1] << 8;
r |= u[2] << 16;
r |= u[3] << 24;
return r;
}
uvlong
qw(uchar *u)
{
return dw(u) | (uvlong)dw(u + 4)<<32;
}

View file

@ -0,0 +1,92 @@
.de F1
.nr OI \\n(.iu
.nr PW 1v
.KF
.sp 0.3v
..
.de T1
.F1
..
.de F2
.ds Fp Figure\ \\n(Fi
.ds Fn Figure\ \\n+(Fi
.ds Fq \\*(Fp
.F0
..
.de T2
.ds Tp Table\ \\n(Ti
.ds Tn Table\ \\n+(Ti
.ds Tq \\*(Tp
.T0
..
.de F0
.nr BD 1
.if t .ps \\n(PS-1
.ie \\n(VS>=41 .vs \\n(VSu-1p
.el .vs \\n(VSp-1p
.ft 1
.di DD
.ll \\n(.lu*3u/4u
.in 0
.fi
.ad b
.sp 0.5v
\f3\\*(Fq\f1\ \ \c
..
.de T0
.nr BD 1
.if t .ps \\n(PS-1
.ie \\n(VS>=41 .vs \\n(VSu-1p
.el .vs \\n(VSp-1p
.ft 1
.di DD
.ll \\n(.lu*3u/4u
.in 0
.fi
.ad b
.sp 0.5v
\f3\\*(Tq\f1\ \ \c
..
.de F3
.sp 0.5v
.di
.br
.ll \\n(.lu*4u/3u
.if \\n(dl>\\n(BD .nr BD \\n(dl
.if \\n(BD<\\n(.l .in (\\n(.lu-\\n(BDu)/2u
.nf
.DD
.in \\n(OIu
.nr BD 0
.fi
.KE
.ie \\n(VS>=41 .vs \\n(VSu
.el .vs \\n(VSp
..
.de T3
.F3
..
.de EX
.P1
\s-4
..
.de EE
\s+4
.P2
..
.nr Fi 1 +1
.nr Ti 1 +1
.ds Fn Figure\ \\n(Fi
.ds Tn Table\ \\n(Ti
.nr XP 2 \" delta point size for program
.nr XV 2p \" delta vertical for programs
.nr XT 4 \" delta tab stop for programs
.nr DV .5v \" space before start of program
.FP lucidasans
.nr PS 11
.nr VS 13
.nr LL 6.6i
.nr PI 0 \" paragraph indent
.nr PD 4p \" extra space between paragraphs
.pl 11i
.rm CH

1928
sys/src/cmd/atazz/main.c Normal file

File diff suppressed because it is too large Load diff

23
sys/src/cmd/atazz/mkfile Normal file
View file

@ -0,0 +1,23 @@
</$objtype/mkfile
TARG = atazz
HFILES = atazz.h tabs.h
OFILES = bit.$O main.$O probe.$O
BIN=/$objtype/bin
UPDATE=\
mkfile\
$HFILES\
${OFILES:%.$O=%.c}\
${TARG:%=/386/bin/%}\
%.ps:DQ: %.ms
eval `{doctype macros.ms $stem.ms} | \
lp -m.9 -dstdout >$target
%.pdf:DQ: %.ps
cat /sys/doc/docfonts $stem.ps >_$stem.ps
ps2pdf _$stem.ps $stem.pdf && rm -f _$stem.ps
</sys/src/cmd/mkone

75
sys/src/cmd/atazz/probe.c Normal file
View file

@ -0,0 +1,75 @@
#include <u.h>
#include <libc.h>
#include <fis.h>
#include "atazz.h"
static int
ckprint(char *s)
{
char buf[ERRMAX];
int st;
Dev d;
squelch = 1;
d.fd = -1;
st = opendev(s, &d);
squelch = 0;
if(st == -1){
rerrstr(buf, sizeof buf);
if(strstr(buf, "ata command") != nil)
return 0;
return 0 /* -1 */;
}
close(d.fd);
print("%s\t%llud; %ud\t%llux\n", s, d.nsect, d.secsize, d.wwn);
return 1;
}
static int
probe0(char *s, int l)
{
char *p, *f[3], buf[16];
int i, r;
s[l] = 0;
r = 0;
for(; p = strchr(s, '\n'); s = p + 1){
if(tokenize(s, f, nelem(f)) < 1)
continue;
for(i = 0; i < 10; i++){
snprint(buf, sizeof buf, "/dev/%s%d", f[0], i);
switch(ckprint(buf)){
case -1:
eprint("!device error %s: %r\n", buf);
break;
case 0:
goto nextdev;
case 1:
r++;
break;
}
nextdev:
;
}
}
return r;
}
int
probe(void)
{
char *s;
int fd, l, r;
fd = open("/dev/sdctl", OREAD);
if(fd == -1)
return -1;
r = -1;
l = 1024; /* #S/sdctl has 0 size; guess */
if(s = malloc(l + 1))
if((l = read(fd, s, l)) > 0)
r = probe0(s, l);
free(s);
close(fd);
return r;
}

View file

@ -0,0 +1,25 @@
read log ext page 17
- phy error log
read log ext sctstat
- current temperature
sct read data table hda temperature history
- temperature history
sct feature control
set state [preserve]
write cache
write cache reordering
enable
disable
set features
temperature logging interval
minutes
return state
return feature option flags
write cache
write cache reordering
temperature logging interval
az> sct error recovery time set read timer = 5
az> sct error recovery time return read timer
sct cmd: Invalid Function code in SCT Feature Control command

View file

@ -0,0 +1,22 @@
this currently needs some more work
az> smart lba0 1 execute off-line immediate # short data collection
az> smart read data
col status: 06 aborted by device with fatal error
exe status: 89 failed: shipping damage, 90% left
time left: 11924s
shrt poll: 200m
ext poll: 21m
options are:
lba0
0x00 normal
0x01 short self-test
0x02 extended self-test
0x03 conveyance self-test
0x04 selective self-test
0x7f abort off-line mode self-test routine
0x81 short self-test in captive mode
0x82 extended "
0x83 conveyance "
0x85 selective "

466
sys/src/cmd/atazz/tabs.h Normal file
View file

@ -0,0 +1,466 @@
Txtab regtx[] = {
Ftype, "type", 0,
Fflags, "flags", 0,
Fcmd, "cmd", 0,
Ffeat, "feat", 0,
Flba0, "lba0", 0,
Flba8, "lba8", 0,
Flba16, "lba16", 0,
Fdev, "dev", 0,
Flba24, "lba24", 0,
Flba32, "lba32", 0,
Flba40, "lba40", 0,
Ffeat8, "feat8", 0,
Fsc, "sc", 0,
Fsc8, "sc8", 0,
Ficc, "icc", 0,
Fcontrol,"control", 0,
/* aliases */
Ffeat, "features", 0,
Flba0, "sector", 0,
Flba8, "cyl0", 0,
Flba8, "byte0", 0,
Flba16, "cyl8", 0,
Flba24, "dh", 0,
Flba24, "byte8", 0,
Flba32, "cyl24", 0,
Flba40, "cyl32", 0,
};
Txtab smautosave[] = {
0, "disable", 0,
0xf1, "enable", 0,
};
Fetab _b0d2[] = {
Fsc, smautosave, nelem(smautosave),
0, 0, 0,
};
Txtab smlba8[] = {
0x4f, "", 0,
};
Txtab smlba16[] = {
0xc2, "", 0,
};
Txtab smartfeat[] = {
// 0xd0, "read data", 0,
0xd2, "attribute autosave", _b0d2,
0xd2, "aa", 0,
0xd4, "execute off-line immediate", 0,
// 0xd5, "read log", 0,
// 0xd6, "write log", 0,
0xd8, "enable operations", 0,
0xd9, "disable operations", 0,
0xda, "return status", 0,
};
Fetab _b0[] = {
Ffeat, smartfeat, nelem(smartfeat),
Flba8, smlba8, 1,
Flba16, smlba16, 1,
0, 0, 0,
};
Txtab _b0d0feat[] = {
0xd0, "", 0,
};
Fetab _b0d0[] = {
Ffeat, _b0d0feat, nelem(_b0d0feat),
Flba8, smlba8, 1,
Flba16, smlba16, 1,
0, 0, 0,
};
Txtab _b0d5feat[] = {
0xd5, "", 0,
};
Txtab _b0d5count[] = {
0x01, "", 0,
};
Txtab smpage[] = {
0x00, "page 0", 0,
0x01, "page 1", 0,
0x02, "page 2", 0,
0x03, "page 3", 0,
0x04, "page 4", 0,
0x05, "page 5", 0,
0x06, "page 6", 0,
0x07, "page 7", 0,
0x08, "page 8", 0,
0x09, "page 9", 0,
0x11, "page 17", 0,
0xe0, "sctstat", 0,
0xe1, "sctdata", 0,
};
Fetab _b0d5[] = {
Ffeat, _b0d5feat, nelem(_b0d5feat),
// Fsc, _b0d5count, nelem(_b0d5count),
Flba0, smpage, nelem(smpage),
Flba8, smlba8, 1,
Flba16, smlba16, 1,
0, 0, 0,
};
Fetab _2f[] = {
Flba0, smpage, nelem(smpage),
0, 0, 0,
};
Txtab nvfeat[] = {
0x00, "set power mode", 0,
0x01, "return from power mode", 0,
0x10, "add lbas", 0,
0x11, "remove lbas", 0,
0x13, "query pinned set", 0,
0x13, "query misses", 0,
0x14, "flush", 0,
0x15, "disable", 0,
0x16, "disable", 0,
};
Fetab _b6[] = {
Ffeat, nvfeat, nelem(nvfeat),
0, 0, 0,
};
Txtab umodes[] = {
0x40, "0", 0,
0x41, "1", 0,
0x42, "2", 0,
0x43, "3", 0,
0x44, "4", 0,
0x45, "5", 0,
0x46, "6", 0,
};
Fetab _ef0340[] = {
Fsc, umodes, nelem(umodes),
0, 0, 0,
};
Txtab txmode[] = {
0x00, "pio", 0,
0x01, "pio-iordy", 0,
0x08, "piofc", 0,
0x20, "mwdma", 0,
0x40, "udma", _ef0340,
};
Fetab _ef03[] = {
Fsc, txmode, nelem(txmode),
0, 0, 0,
};
Txtab apmmode[] = {
0xfe, "maximum", 0,
0x80, "minimum without standby", 0,
0x02, "intermediate", 0,
0x01, "standby", 0,
};
Fetab _ef05[] = {
Fsc, apmmode, nelem(apmmode),
0, 0, 0,
};
Txtab scisone[] = {
1, "", 0,
};
Fetab _scis1[] = {
Fsc, scisone, nelem(scisone),
0, 0, 0,
};
Txtab feat[] = {
0x01, "enable 8-bit pio", 0,
0x02, "enable write cache", 0,
0x03, "set transfer mode", _ef03,
0x05, "enable apm", _ef05,
0x06, "enable power-up in standby", 0,
0x07, "power-up in standby device spin-up", 0,
0x10, "enable sata features", 0,
0x0a, "enable cfa power mode 1", 0,
0x31, "disable media status notification", 0,
0x42, "enable aam", 0,
0x43, "set maximum host interface sector times", 0,
0x55, "disable read look-ahead", 0,
0x5d, "enable release interrupt", 0,
0x5e, "enable service interrupt", 0,
0x66, "disable reverting to power-on defaults", 0,
0x81, "disable 8-bit pio", 0,
0x82, "disable write cache", 0,
0x85, "disable apm", 0,
0x86, "disable power-up in standby", 0,
0x8a, "disable cfa power mode 1", 0,
0x10, "disable sata features", 0,
0x95, "enable media status notification", 0,
0xaa, "enable read look-ahead", 0,
0xc1, "disable free-fall control", 0,
0xc2, "disable aam", 0,
0xc3, "sense data", 0, /* incomplete; enable/disable */
0xcc, "enable reverting to power-on defaults", 0,
0xdd, "disable release interrupt", 0,
0xde, "disable service interrupt", 0,
};
Fetab _ef[] = {
Ffeat, feat, nelem(feat),
0, 0, 0,
};
/* 0xffff — sct command executing in background */
char *sctetab[] = {
"Command complete without error",
"Invalid Function Code",
"Input LBA out of range"
"Request 512-byte data block count overflow.", /* sic */
"Invalid Function code in Error Recovery command",
"Invalid Selection code in Error Recovery command",
"Host read command timer is less than minimum value",
"Host write command timer is less than minimum value",
"Background SCT command was aborted because of an interrupting host command",
"Background SCT command was terminated because of unrecoverable error",
"Invalid Function code in SCT Read/Write Long command",
"SCT data transfer command was issued without first issuing an SCT command",
"Invalid Function code in SCT Feature Control command",
"Invalid Feature code in SCT Feature Control command",
"Invalid New State value in SCT Feature Control command",
"Invalid Option Flags value in SCT Feature Control command",
"Invalid SCT Action code",
"Invalid Table ID (table not supported)",
"Command wa saborted due to device security being locked",
"Invalid revision code in SCT data",
"Foreground SCT operation was terminated because of unrecoverable error",
"Error Recovery Timer expired", /* sic */
};
Txtab fcfewcrt[] = {
1, "enable", 0,
2, "disable", 0,
};
Fetab fcfewcr[] = {
Sstate, fcfewcrt, nelem(fcfewcrt),
0, 0, 0,
};
Txtab fcfewct[] = {
1, "set features", 0,
2, "enable", 0,
3, "disable", 0,
};
Fetab fcfewc[] = {
Sstate, fcfewct, nelem(fcfewct),
0, 0, 0,
};
Txtab fcfn[] = {
1, "set state", 0,
2, "return state", 0,
3, "return feature option flags", 0,
};
Txtab fcfe[] = {
2, "write cache reordering", fcfewcr,
1, "write cache", fcfewc,
3, "temperature logging interval", 0,
};
Txtab fcoptf[] = {
1, "preserve", 0,
};
Txtab fcproto[] = {
Pnd, "", 0,
};
Fetab sctfc[] = {
Sfn, fcfn, nelem(fcfn),
Sfe, fcfe, nelem(fcfe),
Soptf, fcoptf, nelem(fcoptf),
Pbase, fcproto, nelem(fcproto),
0, 0, 0,
};
Txtab sctdt[] = {
Stabid, "tableid", 0,
};
Txtab tabnam[] = {
2, "hda temperature history", 0,
};
Txtab tablefc[] = {
1, "", 0,
};
Fetab tables[] = {
Sfn, tablefc, nelem(tablefc),
Stabid, tabnam, nelem(tabnam),
0, 0, 0,
};
Txtab ersc[] = {
1, "read timer", 0,
2, "write timer", 0,
};
Txtab erfc[] = {
1, "set", 0,
2, "return", 0,
};
Txtab erti[] = {
-1, "=", 0,
};
Fetab scter[] = {
Sfn, erfc, nelem(erfc),
Ssc, ersc, nelem(ersc),
Stimer, erti, nelem(erti),
Pbase, fcproto, nelem(fcproto),
0, 0, 0,
};
Fetab patfe[] = {
Pbase, fcproto, nelem(fcproto),
0, 0, 0,
};
Txtab wsfc[] = {
1, "repeat write pattern", patfe,
2, "repeat write data block", 0,
0x101, "repeat write pattern foreground", patfe,
0x102, "repeat write data block foreground", 0,
};
Txtab wslba[] = {
-1, "lba", 0,
};
Txtab wscnt[] = {
-1, "count", 0,
};
Txtab wspat[] = {
-1, "pattern", 0,
};
Fetab wsame[] = {
Sfn, wsfc, nelem(wsfc),
Slba, wslba, nelem(wslba),
Scnt, wscnt, nelem(wscnt),
Spat, wspat, nelem(wspat),
0, 0, 0,
};
Txtab action[] = {
5, "read data table", tables,
4, "feature control", sctfc,
3, "error recovery time", scter,
2, "write same", wsame,
};
Fetab scta[] = {
Saction, action, nelem(action),
0, 0, 0,
};
Atatab atatab[] = {
0x00, 0, 0, Pnd|P28, 0, 0, "nop",
0x03, 0, Cmdn, Pnd|P28, 0, 0, "cfa request extended error",
0x08, Cmdn, 0, Preset|P28, 0, 0, "device reset",
0x0b, 0, Cmdp, Pnd|P48, 0, 0, "request sense data ext",
0x20, 0, 0, Pin|Ppio|P28, 0, iofmt, "read sector",
0x24, 0, Cmdn, Pin|Ppio|P48, 0, iofmt, "read sector ext",
0x25, 0, Cmdn, Pin|Pdma|P48, 0, iofmt, "read dma ext",
0x26, 0, Cmdn, Pin|Pdmq|P48, 0, iofmt, "read dma queued ext",
0x27, 0, Cmdn, Pnd|P48, 0, 0, "read native max address ext",
0x29, 0, Cmdn, Pin|Ppio|P48, 0, iofmt, "read multiple ext",
0x2a, 0, Cmdn, Pin|Pdma|P48, 0, iofmt, "read stream dma ext",
0x2b, 0, Cmdn, Pin|Ppio|P48, 0, iofmt, "read stream ext",
0x2f, Cmd5sc, 0, Pin|Ppio|P48|P512, _2f, glfmt, "read log ext",
0x2f, Cmd5sc, 0, Psct|Pin|Ppio|P48|P512, scta, 0, "sct",
0x30, 0, Cmdn, Pout|Ppio|P28, 0, 0, "write sector",
0x34, 0, Cmdn, Pout|Ppio|P48, 0, 0, "write sector ext",
0x35, 0, Cmdn, Pout|Pdma|P48, 0, 0, "write dma ext",
0x36, 0, Cmdn, Pout|Pdmq|P48, 0, 0, "write dma queued ext",
0x37, 0, Cmdn, Pnd|P48, 0, 0, "set max address ext",
0x38, 0, Cmdn, Pout|Ppio|P28, 0, 0, "cfa write sectors without erase",
0x39, 0, Cmdn, Pout|Ppio|P48, 0, 0, "write multiple ext",
0x3a, 0, Cmdn, Pout|Pdma|P48, 0, 0, "write stream dma ext",
0x3b, 0, Cmdn, Pout|Ppio|P48, 0, 0, "write stream ext",
0x3d, 0, Cmdn, Pout|Pdma|P48, 0, 0, "write dma fua ext",
0x3e, 0, Cmdn, Pout|Pdmq|P48, 0, 0, "write dma queued fua ext",
0x3f, 0, 0, Pout|Ppio|P48, 0, 0, "write log ext",
0x40, 0, Cmdn, Pnd|P28, 0, 0, "read verify sector",
0x42, 0, Cmdn, Pnd|P48, 0, 0, "read verify sector ext",
0x45, 0, Cmdn, Pnd|P48, 0, 0, "write uncorrectable ext",
0x47, Cmd5sc, 0, Pin|Pdma|P48|P512, _2f, glfmt, "read log dma ext",
0x51, 0, 0, Pnd|P48, 0, 0, "configure stream",
0x57, 0, 0, Pout|Pdma|P48, 0, 0, "write log dma ext",
0x5b, 0, Cmdp, Pnd|P28, 0, 0, "trusted non-data",
0x5c, 0, Cmdp, Pin|Ppio|P28, 0, iofmt, "trusted receive",
0x5d, 0, Cmdp, Pin|Pdma|P28, 0, iofmt, "trusted receive dma",
0x5e, 0, Cmdp, Pout|Ppio|P28, 0, 0, "trusted send",
0x5f, 0, Cmdp, Pout|Pdma|P28, 0, 0, "trusted send dma",
0x60, 0, Cmdn, Pin|Pdmq|P48, 0, iofmt, "read fpdma queued",
0x61, 0, Cmdn, Pout|Pdmq|P48, 0, 0, "write fpdma queued",
0x87, 0, Cmdn, Pin|Ppio|P28, 0, iofmt, "cfa translate sector",
0x90, 0, 0, Pdiag|P28, 0, 0, "execute device diagnostic",
0x92, 0, Cmdn, Pout|Ppio|P28, 0, 0, "download microcode",
0x93, 0, Cmdn, Pout|Pdma|P28, 0, 0, "download microcode dma",
0xa0, Cmdn, 0, Ppkt, 0, 0, "packet",
0xa1, Cmdn, 0, Pin|Ppio|P28|P512, _scis1, idfmt, "identify packet device",
0xb0, Cmd5sc, Cmdn, Pin|Ppio|P28|P512, _b0d0, sdfmt, "smart read data",
0xb0, Cmd5sc, Cmdn, Pin|Ppio|P28|P512, _b0d5, slfmt, "smart read log",
0xb0, 0, Cmdn, Pnd|P28, _b0, smfmt, "smart",
0xb1, 0, 0, Pnd|P28, 0, 0, "device configuration overlay",
0xb6, 0, Cmdn, Pnd|P48, 0, 0, "nv cache",
0xc0, Cmdf, Cmdn, Pnd|P28, 0, 0, "cfa erase sectors",
0xc4, 0, Cmdn, Pin|Ppio|P28, 0, iofmt, "read multiple",
0xc5, 0, Cmdn, Pout|Ppio|P28, 0, 0, "write multiple",
0xc6, 0, Cmdn, Pnd|P28, 0, 0, "set multiple mode",
0xc7, 0, Cmdn, Pin|Pdmq|P28, 0, iofmt, "read dma queued",
0xc8, 0, Cmdn, Pin|Pdma|P28, 0, iofmt, "read dma",
0xca, 0, Cmdn, Pout|Pdma|P28, 0, 0, "write dma",
0xcc, 0, Cmdn, Pout|Pdmq|P28, 0, 0, "write dma queued",
0xcd, 0, Cmdn, Pout|Ppio|P28, 0, 0, "cfa write multiple without erase",
0xce, 0, Cmdn, Pout|Ppio|P48, 0, 0, "write multiple fua ext",
0xd1, 0, Cmdn, Pnd|P28, 0, 0, "check media card type",
0xda, 0, Cmdn, Pnd|P28, 0, 0, "get media status",
0xe0, 0, 0, Pnd|P28, 0, 0, "standby immediate",
0xe1, 0, 0, Pnd|P28, 0, 0, "idle immediate",
0xe2, 0, 0, Pnd|P28, 0, 0, "standby",
0xe3, 0, 0, Pnd|P28, 0, 0, "idle",
0xe4, 0, Cmdn, Pin|Ppio|P28, 0, iofmt, "read buffer",
0xe5, 0, 0, Pnd|P28, 0, 0, "check power mode",
0xe6, 0, 0, Pnd|P28, 0, 0, "sleep",
0xe7, 0, 0, Pnd|P28, 0, 0, "flush cache",
0xe8, 0, Cmdn, Pout|Ppio|P28, 0, 0, "write buffer",
0xe9, 0, Cmdn, Pin|Pdma|P28, 0, iofmt, "read buffer dma",
0xea, 0, Cmdn, Pnd|P28, 0, 0, "flush cache ext",
0xeb, 0, Cmdn, Pdma|P28, 0, 0, "write buffer dma",
0xec, 0, 0, Pin|Ppio|P28|P512, _scis1, idfmt, "identify device",
0xef, 0, 0, Pnd|P28, _ef, 0, "set features",
0xf1, 0, 0, Pout|Ppio|P28, 0, 0, "security set password",
0xf2, 0, 0, Pout|Ppio|P28, 0, 0, "security unlock",
0xf3, 0, 0, Pnd|P28, 0, 0, "security erase prepare",
0xf4, 0, 0, Pout|Ppio|P28, 0, 0, "security erase unit",
0xf5, 0, 0, Pnd|P28, 0, 0, "security freeze lock",
0xf6, 0, 0, Pout|Ppio|P28, 0, 0, "security disable password",
0xf8, 0, 0, Pnd|P28, 0, 0, "read native max address",
0xf9, 0, 0, Pnd|P28, 0, 0, "set max address",
0xf000, 0, 0, Pnd|P28, 0, sigfmt, "signature",
0xf100, 0, 0, Pnd|P28, 0, 0, "oobreset",
};