shithub: riscv

Download patch

ref: fa7fb8b66b9ff50029532d09315f03896f2ac4c4
parent: 913afc39c9b4750e630c7f4ff3161a37602b006b
author: google <[email protected]>
date: Thu Sep 20 18:39:48 EDT 2012

Add Erik Quanstrom's atazz

(needed to disable power management/head unload on 2.5" drive)

--- /dev/null
+++ b/sys/src/cmd/atazz/atazz.h
@@ -1,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**
--- /dev/null
+++ b/sys/src/cmd/atazz/atazz.ms
@@ -1,0 +1,573 @@
+.FP lucidasans
+.TL
+ATA au Naturel
+.AU
+Erik Quanstrom
[email protected]
+.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" .
--- /dev/null
+++ b/sys/src/cmd/atazz/atazz.ps
@@ -1,0 +1,3414 @@
+%!PS-Adobe-2.0
+%%Version: 0.1
+%%Creator: troff, Plan 9 edition
+%%DocumentFonts: (atend)
+%%Pages: (atend)
+%%EndComments
+%
+% Version 3.3.2 prologue for troff files.
+%
+
+/#copies 1 store
+/aspectratio 1 def
+/formsperpage 1 def
+/landscape false def
+/linewidth .3 def
+/magnification 1 def
+/margin 0 def
+/orientation 0 def
+/resolution 720 def
+/rotation 1 def
+/xoffset 0 def
+/yoffset 0 def
+
+/roundpage true def
+/useclippath true def
+/pagebbox [0 0 612 792] def
+
+/R  /Times-Roman def
+/I  /Times-Italic def
+/B  /Times-Bold def
+/BI /Times-BoldItalic def
+/H  /Helvetica def
+/HI /Helvetica-Oblique def
+/HB /Helvetica-Bold def
+/HX /Helvetica-BoldOblique def
+/CW /Courier def
+/CO /Courier def
+/CI /Courier-Oblique def
+/CB /Courier-Bold def
+/CX /Courier-BoldOblique def
+/PA /Palatino-Roman def
+/PI /Palatino-Italic def
+/PB /Palatino-Bold def
+/PX /Palatino-BoldItalic def
+/Hr /Helvetica-Narrow def
+/Hi /Helvetica-Narrow-Oblique def
+/Hb /Helvetica-Narrow-Bold def
+/Hx /Helvetica-Narrow-BoldOblique def
+/KR /Bookman-Light def
+/KI /Bookman-LightItalic def
+/KB /Bookman-Demi def
+/KX /Bookman-DemiItalic def
+/AR /AvantGarde-Book def
+/AI /AvantGarde-BookOblique def
+/AB /AvantGarde-Demi def
+/AX /AvantGarde-DemiOblique def
+/NR /NewCenturySchlbk-Roman def
+/NI /NewCenturySchlbk-Italic def
+/NB /NewCenturySchlbk-Bold def
+/NX /NewCenturySchlbk-BoldItalic def
+/ZD /ZapfDingbats def
+/ZI /ZapfChancery-MediumItalic def
+/S  /S def
+/S1 /S1 def
+/GR /Symbol def
+
+/inch {72 mul} bind def
+/min {2 copy gt {exch} if pop} bind def
+
+/setup {
+	counttomark 2 idiv {def} repeat pop
+
+	landscape {/orientation 90 orientation add def} if
+	/scaling 72 resolution div def
+	linewidth setlinewidth
+	1 setlinecap
+
+	pagedimensions
+	xcenter ycenter translate
+	orientation rotation mul rotate
+	width 2 div neg height 2 div translate
+	xoffset inch yoffset inch neg translate
+	margin 2 div dup neg translate
+	magnification dup aspectratio mul scale
+	scaling scaling scale
+
+	addmetrics
+	0 0 moveto
+} def
+
+/pagedimensions {
+	useclippath userdict /gotpagebbox known not and {
+		/pagebbox [clippath pathbbox newpath] def
+		roundpage currentdict /roundpagebbox known and {roundpagebbox} if
+	} if
+	pagebbox aload pop
+	4 -1 roll exch 4 1 roll 4 copy
+	landscape {4 2 roll} if
+	sub /width exch def
+	sub /height exch def
+	add 2 div /xcenter exch def
+	add 2 div /ycenter exch def
+	userdict /gotpagebbox true put
+} def
+
+/addmetrics {
+	/Symbol /S null Sdefs cf
+	/Times-Roman /S1 StandardEncoding dup length array copy S1defs cf
+} def
+
+/pagesetup {
+	/page exch def
+	currentdict /pagedict known currentdict page known and {
+		page load pagedict exch get cvx exec
+	} if
+} def
+
+/decodingdefs [
+	{counttomark 2 idiv {y moveto show} repeat}
+	{neg /y exch def counttomark 2 idiv {y moveto show} repeat}
+	{neg moveto {2 index stringwidth pop sub exch div 0 32 4 -1 roll widthshow} repeat}
+	{neg moveto {spacewidth sub 0.0 32 4 -1 roll widthshow} repeat}
+	{counttomark 2 idiv {y moveto show} repeat}
+	{neg setfunnytext}
+] def
+
+/setdecoding {/t decodingdefs 3 -1 roll get bind def} bind def
+
+/w {neg moveto show} bind def
+/m {neg dup /y exch def moveto} bind def
+/done {/lastpage where {pop lastpage} if} def
+
+/f {
+	dup /font exch def findfont exch
+	dup /ptsize exch def scaling div dup /size exch def scalefont setfont
+	linewidth ptsize mul scaling 10 mul div setlinewidth
+	/spacewidth ( ) stringwidth pop def
+} bind def
+
+/changefont {
+	/fontheight exch def
+	/fontslant exch def
+	currentfont [
+		1 0
+		fontheight ptsize div fontslant sin mul fontslant cos div
+		fontheight ptsize div
+		0 0
+	] makefont setfont
+} bind def
+
+/sf {f} bind def
+
+/cf {
+	dup length 2 idiv
+	/entries exch def
+	/chtab exch def
+	/newencoding exch def
+	/newfont exch def
+
+	findfont dup length 1 add dict
+	/newdict exch def
+	{1 index /FID ne {newdict 3 1 roll put}{pop pop} ifelse} forall
+
+	newencoding type /arraytype eq {newdict /Encoding newencoding put} if
+
+	newdict /Metrics entries dict put
+	newdict /Metrics get
+	begin
+		chtab aload pop
+		1 1 entries {pop def} for
+		newfont newdict definefont pop
+	end
+} bind def
+
+%
+% A few arrays used to adjust reference points and character widths in some
+% of the printer resident fonts. If square roots are too high try changing
+% the lines describing /radical and /radicalex to,
+%
+%	/radical	[0 -75 550 0]
+%	/radicalex	[-50 -75 500 0]
+%
+% Move braceleftbt a bit - default PostScript character is off a bit.
+%
+
+/Sdefs [
+	/bracketlefttp		[201 500]
+	/bracketleftbt		[201 500]
+	/bracketrighttp		[-81 380]
+	/bracketrightbt		[-83 380]
+	/braceleftbt		[203 490]
+	/bracketrightex		[220 -125 500 0]
+	/radical		[0 0 550 0]
+	/radicalex		[-50 0 500 0]
+	/parenleftex		[-20 -170 0 0]
+	/integral		[100 -50 500 0]
+	/infinity		[10 -75 730 0]
+] def
+
+/S1defs [
+	/underscore		[0 80 500 0]
+	/endash			[7 90 650 0]
+] def
+%
+% Version 3.3.2 drawing procedures for dpost. Automatically pulled in when
+% needed.
+%
+
+/inpath false def
+/savematrix matrix def
+
+/Dl {
+	inpath
+		{neg lineto pop pop}
+		{newpath neg moveto neg lineto stroke}
+	ifelse
+} bind def
+
+/De {
+	/y1 exch 2 div def
+	/x1 exch 2 div def
+	/savematrix savematrix currentmatrix def
+	neg exch x1 add exch translate
+	x1 y1 scale
+	0 0 1 0 360
+	inpath
+		{1 0 moveto arc savematrix setmatrix}
+		{newpath arc savematrix setmatrix stroke}
+	ifelse
+} bind def
+
+/Da {
+	/dy2 exch def
+	/dx2 exch def
+	/dy1 exch def
+	/dx1 exch def
+	dy1 add neg exch dx1 add exch
+	dx1 dx1 mul dy1 dy1 mul add sqrt
+	dy1 dx1 neg atan
+	dy2 neg dx2 atan
+	inpath
+		{arc}
+		{newpath arc stroke}
+	ifelse
+} bind def
+
+/DA {
+	/dy2 exch def
+	/dx2 exch def
+	/dy1 exch def
+	/dx1 exch def
+	dy1 add neg exch dx1 add exch
+	dx1 dx1 mul dy1 dy1 mul add sqrt
+	dy1 dx1 neg atan
+	dy2 neg dx2 atan
+	inpath
+		{arcn}
+		{newpath arcn stroke}
+	ifelse
+} bind def
+
+/Ds {
+	/y2 exch def
+	/x2 exch def
+	/y1 exch def
+	/x1 exch def
+	/y0 exch def
+	/x0 exch def
+	x0 5 x1 mul add 6 div
+	y0 5 y1 mul add -6 div
+	x2 5 x1 mul add 6 div
+	y2 5 y1 mul add -6 div
+	x1 x2 add 2 div
+	y1 y2 add -2 div
+	inpath
+		{curveto}
+		{newpath x0 x1 add 2 div y0 y1 add -2 div moveto curveto stroke}
+	ifelse
+} bind def
+%
+% Tries to round clipping path dimensions, as stored in array pagebbox, so they
+% match one of the known sizes in the papersizes array. Lower left coordinates
+% are always set to 0.
+%
+
+/roundpagebbox {
+    7 dict begin
+	/papersizes [8.5 inch 11 inch 14 inch 17 inch] def
+
+	/mappapersize {
+		/val exch def
+		/slop .5 inch def
+		/diff slop def
+		/j 0 def
+		0 1 papersizes length 1 sub {
+			/i exch def
+			papersizes i get val sub abs
+			dup diff le {/diff exch def /j i def} {pop} ifelse
+		} for
+		diff slop lt {papersizes j get} {val} ifelse
+	} def
+
+	pagebbox 0 0 put
+	pagebbox 1 0 put
+	pagebbox dup 2 get mappapersize 2 exch put
+	pagebbox dup 3 get mappapersize 3 exch put
+    end
+} bind def
+
+%%EndProlog
+%%BeginSetup
+mark
+/magnification .9 def
+%
+% Encoding vector and redefinition of findfont for the ISO Latin1 standard.
+% The 18 characters missing from ROM based fonts on older printers are noted
+% below.
+%
+
+/ISOLatin1Encoding [
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/space
+	/exclam
+	/quotedbl
+	/numbersign
+	/dollar
+	/percent
+	/ampersand
+	/quoteright
+	/parenleft
+	/parenright
+	/asterisk
+	/plus
+	/comma
+	/minus
+	/period
+	/slash
+	/zero
+	/one
+	/two
+	/three
+	/four
+	/five
+	/six
+	/seven
+	/eight
+	/nine
+	/colon
+	/semicolon
+	/less
+	/equal
+	/greater
+	/question
+	/at
+	/A
+	/B
+	/C
+	/D
+	/E
+	/F
+	/G
+	/H
+	/I
+	/J
+	/K
+	/L
+	/M
+	/N
+	/O
+	/P
+	/Q
+	/R
+	/S
+	/T
+	/U
+	/V
+	/W
+	/X
+	/Y
+	/Z
+	/bracketleft
+	/backslash
+	/bracketright
+	/asciicircum
+	/underscore
+	/quoteleft
+	/a
+	/b
+	/c
+	/d
+	/e
+	/f
+	/g
+	/h
+	/i
+	/j
+	/k
+	/l
+	/m
+	/n
+	/o
+	/p
+	/q
+	/r
+	/s
+	/t
+	/u
+	/v
+	/w
+	/x
+	/y
+	/z
+	/braceleft
+	/bar
+	/braceright
+	/asciitilde
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/.notdef
+	/dotlessi
+	/grave
+	/acute
+	/circumflex
+	/tilde
+	/macron
+	/breve
+	/dotaccent
+	/dieresis
+	/.notdef
+	/ring
+	/cedilla
+	/.notdef
+	/hungarumlaut
+	/ogonek
+	/caron
+	/space
+	/exclamdown
+	/cent
+	/sterling
+	/currency
+	/yen
+	/brokenbar		% missing
+	/section
+	/dieresis
+	/copyright
+	/ordfeminine
+	/guillemotleft
+	/logicalnot
+	/hyphen
+	/registered
+	/macron
+	/degree			% missing
+	/plusminus		% missing
+	/twosuperior		% missing
+	/threesuperior		% missing
+	/acute
+	/mu			% missing
+	/paragraph
+	/periodcentered
+	/cedilla
+	/onesuperior		% missing
+	/ordmasculine
+	/guillemotright
+	/onequarter		% missing
+	/onehalf		% missing
+	/threequarters		% missing
+	/questiondown
+	/Agrave
+	/Aacute
+	/Acircumflex
+	/Atilde
+	/Adieresis
+	/Aring
+	/AE
+	/Ccedilla
+	/Egrave
+	/Eacute
+	/Ecircumflex
+	/Edieresis
+	/Igrave
+	/Iacute
+	/Icircumflex
+	/Idieresis
+	/Eth			% missing
+	/Ntilde
+	/Ograve
+	/Oacute
+	/Ocircumflex
+	/Otilde
+	/Odieresis
+	/multiply		% missing
+	/Oslash
+	/Ugrave
+	/Uacute
+	/Ucircumflex
+	/Udieresis
+	/Yacute			% missing
+	/Thorn			% missing
+	/germandbls
+	/agrave
+	/aacute
+	/acircumflex
+	/atilde
+	/adieresis
+	/aring
+	/ae
+	/ccedilla
+	/egrave
+	/eacute
+	/ecircumflex
+	/edieresis
+	/igrave
+	/iacute
+	/icircumflex
+	/idieresis
+	/eth			% missing
+	/ntilde
+	/ograve
+	/oacute
+	/ocircumflex
+	/otilde
+	/odieresis
+	/divide			% missing
+	/oslash
+	/ugrave
+	/uacute
+	/ucircumflex
+	/udieresis
+	/yacute			% missing
+	/thorn			% missing
+	/ydieresis
+] def
+
+/NewFontDirectory FontDirectory maxlength dict def
+
+%
+% Apparently no guarantee findfont is defined in systemdict so the obvious
+%
+%	systemdict /findfont get exec
+%
+% can generate an error. So far the only exception is a VT600 (version 48.0).
+%
+
+userdict /@RealFindfont known not {
+	userdict begin
+		/@RealFindfont systemdict begin /findfont load end def
+	end
+} if
+
+/findfont {
+	dup NewFontDirectory exch known not {
+		dup
+		%dup systemdict /findfont get exec	% not always in systemdict
+		dup userdict /@RealFindfont get exec
+		dup /Encoding get StandardEncoding eq {
+			dup length dict begin
+				{1 index /FID ne {def}{pop pop} ifelse} forall
+				/Encoding ISOLatin1Encoding def
+				currentdict
+			end
+			/DummyFontName exch definefont
+		} if
+		NewFontDirectory 3 1 roll put
+	} if
+	NewFontDirectory exch get
+} bind def
+
+%%Patch from lp
+%%EndPatch from lp
+
+setup
+%%EndSetup
+%%Page: 1 1
+/saveobj save def
+mark
+1 pagesetup
+13 /LucidaSans-Demi f
+(ATA) 2584 1230 w
+(au) 2908 1230 w
+(Naturel) 3113 1230 w
+11 /LucidaSans-Italic f
+(Erik) 2672 1490 w
+(Quanstrom) 2917 1490 w
+([email protected]) 2465 1620 w
+(ABSTRACT) 2817 2095 w
+11 /LucidaSansUnicode00 f
+(The) 1116 2375 w
+(Plan) 1351 2375 w
+(9) 1609 2375 w
+11 /LucidaSans-Italic f
+(sd) 1714 2375 w
+11 /LucidaSansUnicode00 f
+(\(3\)) 1835 2375 w
+(interface) 2012 2375 w
+(allows) 2516 2375 w
+(raw) 2885 2375 w
+(commands) 3112 2375 w
+(to) 3729 2375 w
+(be) 3873 2375 w
+(sent.) 4041 2375 w
+(Traditionally,) 4375 2375 w
+(only) 1116 2505 w
+(SCSI) 1378 2505 w
+(CDBs) 1642 2505 w
+(could) 1959 2505 w
+(be) 2289 2505 w
+(sent) 2458 2505 w
+(in) 2723 2505 w
+(this) 2861 2505 w
+(manner.) 3095 2505 w
+(For) 3608 2505 w
+(devices) 3816 2505 w
+(that) 4247 2505 w
+(respond) 4495 2505 w
+(to) 4968 2505 w
+(ATA/ATAPI) 1116 2635 w
+(commands,) 1768 2635 w
+(a) 2443 2635 w
+(small) 2563 2635 w
+(set) 2905 2635 w
+(of) 3123 2635 w
+(SCSI) 3290 2635 w
+(CDBs) 3575 2635 w
+(have) 3913 2635 w
+(been) 4220 2635 w
+(translated) 4540 2635 w
+(into) 1116 2765 w
+(an) 1371 2765 w
+(ATA) 1547 2765 w
+(equivalent.) 1815 2765 w
+(This) 2484 2765 w
+(approach) 2756 2765 w
+(works) 3299 2765 w
+(very) 3663 2765 w
+(well.) 3931 2765 w
+(However,) 4258 2765 w
+(there) 4798 2765 w
+(are) 1116 2895 w
+(ATA) 1322 2895 w
+(commands) 1581 2895 w
+(such) 2200 2895 w
+(as) 2486 2895 w
+(SMART) 2641 2895 w
+(which) 3047 2895 w
+(do) 3394 2895 w
+(not) 3568 2895 w
+(have) 3782 2895 w
+(direct) 4069 2895 w
+(translations.) 4413 2895 w
+(I) 1116 3025 w
+(describe) 1190 3025 w
+(how) 1683 3025 w
+(ATA/ATAPI) 1945 3025 w
+(commands) 2580 3025 w
+(were) 3203 3025 w
+(supported) 3498 3025 w
+(without) 4085 3025 w
+(disturbing) 4528 3025 w
+(existing functionality.) 1116 3155 w
+11 /LucidaSans-Demi f
+(Introduction) 720 3545 w
+11 /LucidaSansUnicode00 f
+(In) 720 3715 w
+(writing) 858 3715 w
+(new) 1267 3715 w
+11 /LucidaSans-Italic f
+(sd) 1520 3715 w
+11 /LucidaSansUnicode00 f
+(\(3\)) 1641 3715 w
+(drivers) 1821 3715 w
+(for) 2226 3715 w
+(plan) 2418 3715 w
+(9,) 2687 3715 w
+(it) 2830 3715 w
+(has) 2942 3715 w
+(been) 3166 3715 w
+(necessary) 3466 3715 w
+(to) 4028 3715 w
+(copy) 4175 3715 w
+(laundry) 4463 3715 w
+(list) 4902 3715 w
+(of) 5102 3715 w
+(spe\255) 5249 3715 w
+(cial) 720 3845 w
+(commands) 937 3845 w
+(that) 1554 3845 w
+(were) 1800 3845 w
+(needed with previous drivers.) 2089 3845 w
+(The) 3739 3845 w
+(set) 3973 3845 w
+(of) 4167 3845 w
+(commands supported) 4310 3845 w
+(by) 720 3975 w
+(each) 894 3975 w
+(device) 1189 3975 w
+(driver) 1575 3975 w
+(varies,) 1933 3975 w
+(and) 2329 3975 w
+(they) 2575 3975 w
+(are) 2851 3975 w
+(typically) 3067 3975 w
+(executed) 3553 3975 w
+(by) 4089 3975 w
+(writing) 4264 3975 w
+(a) 4684 3975 w
+(magic) 4794 3975 w
+(string) 5162 3975 w
+(into) 720 4105 w
+(the) 968 4105 w
+(driver) 1178 4105 w
+11 /LucidaSansUnicode20 f
+(\031) 1488 4105 w
+11 /LucidaSansUnicode00 f
+(s) 1523 4105 w
+11 /LucidaTypewriter f
+(ctl) 1618 4105 w
+11 /LucidaSansUnicode00 f
+(file.) 1894 4105 w
+(This) 2170 4105 w
+(requires) 2434 4105 w
+(code) 2912 4105 w
+(duplicated) 3205 4105 w
+(for) 3803 4105 w
+(each) 3995 4105 w
+(driver,) 4281 4105 w
+(and) 4665 4105 w
+(covers) 4902 4105 w
+(few) 5284 4105 w
+(commands.) 720 4235 w
+(Coverage) 1410 4235 w
+(depends) 1947 4235 w
+(on) 2441 4235 w
+(the) 2615 4235 w
+(driver.) 2825 4235 w
+(It) 3244 4235 w
+(is) 3357 4235 w
+(not) 3485 4235 w
+(possible) 3701 4235 w
+(for) 4184 4235 w
+(the) 4377 4235 w
+(control) 4588 4235 w
+(interface) 5004 4235 w
+(to) 720 4365 w
+(return) 895 4365 w
+(output,) 1290 4365 w
+(making) 1745 4365 w
+(some) 2206 4365 w
+(commands) 2559 4365 w
+(impossible) 3206 4365 w
+(to) 3849 4365 w
+(implement.) 4023 4365 w
+(While) 4729 4365 w
+(a) 5084 4365 w
+(work) 5211 4365 w
+(around) 720 4495 w
+(has) 1148 4495 w
+(been) 1383 4495 w
+(to) 1694 4495 w
+(change) 1852 4495 w
+(the) 2285 4495 w
+(contents) 2506 4495 w
+(of) 3015 4495 w
+(the) 3173 4495 w
+(control) 3394 4495 w
+(file,) 3820 4495 w
+(this) 4073 4495 w
+(solution) 4321 4495 w
+(is) 4803 4495 w
+(extremely) 4942 4495 w
+(unwieldy even for simple) 720 4625 w
+(commands such as) 2088 4625 w
+11 /LucidaTypewriter f
+(IDENTIFY DEVICE) 3139 4625 w
+11 /LucidaSansUnicode00 f
+(.) 4324 4625 w
+11 /LucidaSans-Demi f
+(Considerations) 720 4885 w
+11 /LucidaSansUnicode00 f
+(Currently,) 720 5055 w
+(all) 1294 5055 w
+11 /LucidaSans-Italic f
+(sd) 1464 5055 w
+11 /LucidaSansUnicode00 f
+(devices) 1630 5055 w
+(respond) 2070 5055 w
+(to) 2552 5055 w
+(a) 2706 5055 w
+(small) 2813 5055 w
+(subset) 3142 5055 w
+(of) 3540 5055 w
+(SCSI) 3694 5055 w
+(commands) 3966 5055 w
+(through) 4593 5055 w
+(the) 5064 5055 w
+(raw) 5281 5055 w
+(interface) 720 5185 w
+(and) 1229 5185 w
+(the) 1468 5185 w
+(normal) 1680 5185 w
+(read/write) 2096 5185 w
+(interface) 2697 5185 w
+(uses) 3206 5185 w
+(SCSI) 3489 5185 w
+(command) 3756 5185 w
+(blocks.) 4322 5185 w
+(SCSI) 4777 5185 w
+(devices,) 5043 5185 w
+(of) 720 5315 w
+(course,) 877 5315 w
+(respond) 1315 5315 w
+(natively) 1800 5315 w
+(while) 2259 5315 w
+(ATA) 2587 5315 w
+(devices) 2857 5315 w
+(emulate) 3300 5315 w
+(these) 3777 5315 w
+(commands) 4115 5315 w
+(with) 4745 5315 w
+(the) 5020 5315 w
+(help) 5241 5315 w
+11 /LucidaSans-Italic f
+(sd) 720 5445 w
+11 /LucidaSansUnicode00 f
+(.) 841 5445 w
+(This) 952 5445 w
+(means) 1218 5445 w
+(that) 1608 5445 w
+11 /LucidaSans-Italic f
+(scuzz) 1860 5445 w
+11 /LucidaSansUnicode00 f
+(\(8\)) 2155 5445 w
+(can) 2337 5445 w
+(get) 2563 5445 w
+(surprisingly) 2775 5445 w
+(far) 3444 5445 w
+(with) 3632 5445 w
+(ATA) 3899 5445 w
+(devices,) 4161 5445 w
+(and) 4631 5445 w
+(ATAPI) 4870 5445 w
+(\() 5224 5445 w
+11 /LucidaSans-Italic f
+(sic.) 5260 5445 w
+11 /LucidaSansUnicode00 f
+(\)) 5436 5445 w
+(devices) 720 5575 w
+(work) 1159 5575 w
+(quite) 1465 5575 w
+(well.) 1782 5575 w
+(Although) 2108 5575 w
+(a) 2641 5575 w
+(new) 2747 5575 w
+(implementation) 3007 5575 w
+(might) 3891 5575 w
+(not) 4247 5575 w
+(use) 4468 5575 w
+(this) 4699 5575 w
+(approach,) 4941 5575 w
+(replacing) 720 5705 w
+(the) 1251 5705 w
+(interface) 1460 5705 w
+(did) 1966 5705 w
+(not) 2174 5705 w
+(appear) 2388 5705 w
+(cost) 2793 5705 w
+(effective) 3050 5705 w
+(and) 3541 5705 w
+(would) 3776 5705 w
+(lead) 4134 5705 w
+(to) 4395 5705 w
+(maximum) 4540 5705 w
+(incom\255) 5111 5705 w
+(patibilities,) 720 5835 w
+(while) 1360 5835 w
+(this) 1685 5835 w
+(interface) 1928 5835 w
+(is) 2442 5835 w
+(experimental.) 2576 5835 w
+(This) 3395 5835 w
+(means) 3666 5835 w
+(that) 4062 5835 w
+(the) 4320 5835 w
+(raw) 4538 5835 w
+(interface) 4776 5835 w
+(will) 5291 5835 w
+(need a) 720 5965 w
+(method of) 1112 5965 w
+(signaling an ATA) 1699 5965 w
+(command rather than a) 2639 5965 w
+(SCSI) 3925 5965 w
+(CDB.) 4186 5965 w
+(An) 720 6135 w
+(unattractive) 901 6135 w
+(wart) 1571 6135 w
+(of) 1841 6135 w
+(the) 1987 6135 w
+(ATA) 2196 6135 w
+(command) 2455 6135 w
+(set) 3018 6135 w
+(is) 3215 6135 w
+(there) 3341 6135 w
+(are) 3657 6135 w
+(seven) 3863 6135 w
+(protocols) 4206 6135 w
+(and) 4744 6135 w
+(two) 4980 6135 w
+(com\255) 5211 6135 w
+(mand) 720 6265 w
+(sizes.) 1060 6265 w
+(While) 1439 6265 w
+(each) 1768 6265 w
+(command) 2055 6265 w
+(has) 2620 6265 w
+(a) 2845 6265 w
+(specific) 2946 6265 w
+(size) 3389 6265 w
+(\(either) 3641 6265 w
+(28-bit) 4026 6265 w
+(LBA) 4409 6265 w
+(or) 4646 6265 w
+(48-bit) 4797 6265 w
+(LLBA\)) 5180 6265 w
+(and) 720 6395 w
+(is) 956 6395 w
+(associated) 1082 6395 w
+(with) 1681 6395 w
+(a) 1945 6395 w
+(particular) 2045 6395 w
+(protocol) 2594 6395 w
+(\(PIO,) 3077 6395 w
+(DMA,) 3366 6395 w
+(PACKET,) 3694 6395 w
+(etc.\),) 4181 6395 w
+(this) 4485 6395 w
+(information) 4721 6395 w
+(is) 5384 6395 w
+(available) 720 6525 w
+(only) 1231 6525 w
+(by) 1499 6525 w
+(table) 1669 6525 w
+(lookup.) 1978 6525 w
+(While) 2459 6525 w
+(this) 2792 6525 w
+(information) 3033 6525 w
+(may) 3701 6525 w
+(not) 3965 6525 w
+(always) 4184 6525 w
+(be) 4579 6525 w
+(necessary) 4753 6525 w
+(for) 5319 6525 w
+(simple) 720 6655 w
+(SATA-based) 1126 6655 w
+(controllers,) 1840 6655 w
+(for) 2499 6655 w
+(the) 2705 6655 w
+(IDE) 2929 6655 w
+(controllers,) 3156 6655 w
+(it) 3815 6655 w
+(is) 3941 6655 w
+(required.) 4082 6655 w
+(PIO) 4658 6655 w
+(commands) 4891 6655 w
+(are) 720 6785 w
+(required) 941 6785 w
+(and) 1446 6785 w
+(use) 1697 6785 w
+(a) 1936 6785 w
+(different) 2049 6785 w
+(set) 2562 6785 w
+(of) 2773 6785 w
+(registers) 2933 6785 w
+(than) 3452 6785 w
+(DMA) 3742 6785 w
+(commands.) 4048 6785 w
+(Queued) 4751 6785 w
+(DMA) 5218 6785 w
+(commands) 720 6915 w
+(and) 1344 6915 w
+(ATAPI) 1585 6915 w
+(commands) 1942 6915 w
+(are) 2566 6915 w
+(submitted) 2777 6915 w
+(differently) 3360 6915 w
+(still.) 3954 6915 w
+(Finally,) 4261 6915 w
+(the) 4681 6915 w
+(data) 4896 6915 w
+(direc\255) 5172 6915 w
+(tion) 720 7045 w
+(is) 966 7045 w
+(implied) 1092 7045 w
+(by) 1527 7045 w
+(the) 1690 7045 w
+(command.) 1898 7045 w
+(Having) 2530 7045 w
+(these) 2934 7045 w
+(three) 3260 7045 w
+(extra) 3575 7045 w
+(pieces) 3888 7045 w
+(of) 4262 7045 w
+(information) 4407 7045 w
+(in) 5068 7045 w
+(addi\255) 5205 7045 w
+(tion to the) 720 7175 w
+(command seems necessary.) 1312 7175 w
+cleartomark
+showpage
+saveobj restore
+%%EndPage: 1 1
+%%Page: 2 2
+/saveobj save def
+mark
+2 pagesetup
+11 /LucidaSansUnicode00 f
+(A) 720 850 w
+(final) 864 850 w
+(bit) 1166 850 w
+(of) 1376 850 w
+(extra-command) 1552 850 w
+(information) 2486 850 w
+(that) 3179 850 w
+(may) 3459 850 w
+(be) 3748 850 w
+(useful) 3948 850 w
+(is) 4344 850 w
+(a) 4501 850 w
+(timeout.) 4631 850 w
+(While) 5183 850 w
+11 /LucidaSans-Italic f
+(alarm) 720 980 w
+11 /LucidaSansUnicode00 f
+(\(2\)) 1041 980 w
+(timeouts) 1221 980 w
+(work) 1729 980 w
+(with) 2029 980 w
+(many) 2294 980 w
+(drivers,) 2621 980 w
+(it) 3061 980 w
+(would) 3173 980 w
+(be) 3533 980 w
+(an) 3702 980 w
+(added) 3869 980 w
+(convenience) 4237 980 w
+(to) 4933 980 w
+(be) 5079 980 w
+(able) 5248 980 w
+(to) 720 1110 w
+(specify) 884 1110 w
+(a) 1313 1110 w
+(timeout) 1430 1110 w
+(along) 1899 1110 w
+(with) 2251 1110 w
+(the) 2533 1110 w
+(command.) 2760 1110 w
+(This) 3411 1110 w
+(seems) 3693 1110 w
+(a) 4088 1110 w
+(good) 4206 1110 w
+(idea) 4534 1110 w
+(in) 4815 1110 w
+(principle,) 4972 1110 w
+(since) 720 1240 w
+(some) 1052 1240 w
+(ATA) 1397 1240 w
+(commands) 1676 1240 w
+(should) 2315 1240 w
+(return) 2733 1240 w
+(within) 3120 1240 w
+(milli-) 3504 1240 w
+(or) 3856 1240 w
+(microseconds,) 4026 1240 w
+(others) 4855 1240 w
+(may) 5252 1240 w
+(take) 720 1370 w
+(hours) 984 1370 w
+(to) 1324 1370 w
+(complete.) 1468 1370 w
+(On) 2065 1370 w
+(the) 2255 1370 w
+(other) 2462 1370 w
+(hand,) 2781 1370 w
+(the) 3118 1370 w
+(existing) 3325 1370 w
+(SCSI) 3787 1370 w
+(interface) 4049 1370 w
+(does) 4553 1370 w
+(not) 4844 1370 w
+(support) 5057 1370 w
+(it) 720 1500 w
+(and) 829 1500 w
+(changing) 1063 1500 w
+(its) 1588 1500 w
+(kernel-to-user) 1753 1500 w
+(space) 2589 1500 w
+(format) 2929 1500 w
+(would) 3322 1500 w
+(be) 3679 1500 w
+(quite) 3846 1500 w
+(invasive.) 4154 1500 w
+(Timeouts) 4685 1500 w
+(were) 5218 1500 w
+(left) 720 1630 w
+(for a) 931 1630 w
+(later date.) 1215 1630 w
+11 /LucidaSans-Demi f
+(Protocol and) 720 1890 w
+(Data) 1467 1890 w
+(Format) 1764 1890 w
+11 /LucidaSansUnicode00 f
+(The) 720 2060 w
+(existing) 965 2060 w
+(protocol) 1437 2060 w
+(for) 1927 2060 w
+(SCSI) 2126 2060 w
+(commands) 2398 2060 w
+(suits) 3025 2060 w
+(ATA) 3324 2060 w
+(as) 3591 2060 w
+(well.) 3754 2060 w
+(We) 4082 2060 w
+(simply) 4286 2060 w
+(write) 4681 2060 w
+(the) 4993 2060 w
+(com\255) 5211 2060 w
+(mand) 720 2190 w
+(block) 1060 2190 w
+(to) 1388 2190 w
+(the) 1536 2190 w
+(raw) 1747 2190 w
+(device.) 1978 2190 w
+(Then) 2426 2190 w
+(we) 2733 2190 w
+(either) 2920 2190 w
+(write) 3270 2190 w
+(or) 3575 2190 w
+(read) 3727 2190 w
+(the) 4004 2190 w
+(data.) 4215 2190 w
+(Finally) 4557 2190 w
+(the) 4938 2190 w
+(status) 5149 2190 w
+(block) 720 2320 w
+(is read.) 1043 2320 w
+(What) 1508 2320 w
+(remains is choosing a) 1808 2320 w
+(data) 3005 2320 w
+(format) 3272 2320 w
+(for ATA) 3664 2320 w
+(commands.) 4108 2320 w
+(The) 720 2490 w
+(T10) 964 2490 w
+(Committee) 1216 2490 w
+(has) 1846 2490 w
+(defined) 2076 2490 w
+(a) 2524 2490 w
+(SCSI-to-ATA) 2630 2490 w
+(translation) 3358 2490 w
+(scheme) 3976 2490 w
+(called) 4428 2490 w
+(SAT[4].) 4786 2490 w
+(This) 5247 2490 w
+(provides) 720 2620 w
+(a) 1217 2620 w
+(standard) 1318 2620 w
+(set) 1828 2620 w
+(of) 2026 2620 w
+(translations) 2173 2620 w
+(between) 2840 2620 w
+(common) 3328 2620 w
+(SCSI) 3829 2620 w
+(commands) 4094 2620 w
+(and) 4714 2620 w
+(ATA) 4951 2620 w
+(com\255) 5211 2620 w
+(mands.) 720 2750 w
+(It) 1184 2750 w
+(specifies) 1295 2750 w
+(the) 1799 2750 w
+(ATA) 2008 2750 w
+(protocol) 2267 2750 w
+(and) 2750 2750 w
+(some) 2987 2750 w
+(other) 3313 2750 w
+(sideband) 3635 2750 w
+(information.) 4160 2750 w
+(It) 4893 2750 w
+(is) 5005 2750 w
+(partic\255) 5132 2750 w
+(ularly) 720 2880 w
+(useful) 1107 2880 w
+(for) 1526 2880 w
+(common) 1770 2880 w
+(commands) 2323 2880 w
+(such) 2995 2880 w
+(as) 3334 2880 w
+11 /LucidaTypewriter f
+(READ \(12\)) 3542 2880 w
+11 /LucidaSansUnicode00 f
+(or) 4344 2880 w
+11 /LucidaTypewriter f
+(READ) 4547 2880 w
+(CAPAC\255) 4998 2880 w
+(ITY \(12\)) 720 3010 w
+11 /LucidaSansUnicode00 f
+(.) 1352 3010 w
+(Unfortunately,) 1468 3010 w
+(our) 2276 3010 w
+(purpose) 2502 3010 w
+(is) 2985 3010 w
+(to) 3120 3010 w
+(address) 3275 3010 w
+(the) 3740 3010 w
+(uncommon) 3958 3010 w
+(commands.) 4603 3010 w
+(For) 5301 3010 w
+(those,) 720 3140 w
+(special) 1094 3140 w
+(commands) 1507 3140 w
+11 /LucidaTypewriter f
+(ATA) 2133 3140 w
+(PASSTHROUGH \(12\)) 2459 3140 w
+11 /LucidaSansUnicode00 f
+(and) 3768 3140 w
+11 /LucidaTypewriter f
+(\(16\)) 4011 3140 w
+11 /LucidaSansUnicode00 f
+(exist.) 4372 3140 w
+(Unfortunately) 4745 3140 w
+(several) 720 3270 w
+(commands) 1142 3270 w
+(we) 1770 3270 w
+(are) 1964 3270 w
+(interested) 2179 3270 w
+(in,) 2764 3270 w
+(such) 2946 3270 w
+(as) 3241 3270 w
+(those) 3405 3270 w
+(that) 3746 3270 w
+(set) 4004 3270 w
+(transfer) 4210 3270 w
+(modes) 4676 3270 w
+(are) 5080 3270 w
+(not) 5296 3270 w
+(allowed) 720 3400 w
+(by) 1166 3400 w
+(the) 1330 3400 w
+(standard.) 1539 3400 w
+(This) 2117 3400 w
+(is) 2380 3400 w
+(not) 2506 3400 w
+(a) 2720 3400 w
+(major) 2819 3400 w
+(obstacle.) 3164 3400 w
+(We) 3715 3400 w
+(could) 3909 3400 w
+(simply) 4238 3400 w
+(ignore) 4623 3400 w
+(the) 5002 3400 w
+(stan\255) 5210 3400 w
+(dard.) 720 3530 w
+(But) 1070 3530 w
+(this) 1279 3530 w
+(goes) 1512 3530 w
+(against) 1801 3530 w
+(the) 2224 3530 w
+(general) 2431 3530 w
+(reasons) 2865 3530 w
+(for) 3316 3530 w
+(using) 3506 3530 w
+(an) 3835 3530 w
+(established) 4001 3530 w
+(standard:) 4646 3530 w
+(inter\255) 5188 3530 w
+(operability.) 720 3660 w
+(Finally,) 1395 3660 w
+(it) 1809 3660 w
+(should) 1920 3660 w
+(be) 2318 3660 w
+(mentioned) 2487 3660 w
+(that) 3096 3660 w
+(SAT) 3345 3660 w
+(format) 3587 3660 w
+(adds) 3982 3660 w
+(yet) 4275 3660 w
+(another) 4473 3660 w
+(intermedi\255) 4923 3660 w
+(ate) 720 3790 w
+(format) 922 3790 w
+(of) 1317 3790 w
+(variable) 1464 3790 w
+(size) 1922 3790 w
+(which) 2174 3790 w
+(would) 2522 3790 w
+(require) 2882 3790 w
+(translation) 3304 3790 w
+(to) 3915 3790 w
+(a) 4062 3790 w
+(usable) 4162 3790 w
+(format) 4549 3790 w
+(for) 4945 3790 w
+(all) 5137 3790 w
+(the) 5301 3790 w
+(existing) 720 3920 w
+(Plan) 1183 3920 w
+(9) 1442 3920 w
+(drivers.) 1548 3920 w
+(If) 2021 3920 w
+(we) 2131 3920 w
+11 /LucidaSansUnicode20 f
+(\031) 2278 3920 w
+11 /LucidaSansUnicode00 f
+(re) 2313 3920 w
+(not) 2457 3920 w
+(hewing) 2670 3920 w
+(to) 3090 3920 w
+(a) 3235 3920 w
+(standard,) 3333 3920 w
+(we) 3874 3920 w
+(should) 4057 3920 w
+(build) 4453 3920 w
+(or) 4759 3920 w
+(choose) 4907 3920 w
+(for) 5319 3920 w
+(convenience.) 720 4050 w
+(ATA-8) 720 4220 w
+(and) 1126 4220 w
+(ACS-2) 1376 4220 w
+(also) 1772 4220 w
+(specify) 2040 4220 w
+(an) 2466 4220 w
+(abstract) 2648 4220 w
+(register) 3131 4220 w
+(layout.) 3595 4220 w
+(The) 4044 4220 w
+(size) 4296 4220 w
+(of) 4562 4220 w
+(the) 4723 4220 w
+(command) 4947 4220 w
+(block) 720 4350 w
+(varies) 1054 4350 w
+(based) 1413 4350 w
+(on) 1776 4350 w
+(the) 1957 4350 w
+11 /LucidaSansUnicode20 f
+(\034) 2174 4350 w
+11 /LucidaSansUnicode00 f
+(size) 2215 4350 w
+11 /LucidaSansUnicode20 f
+(\035) 2428 4350 w
+11 /LucidaSansUnicode00 f
+(\(either) 2515 4350 w
+(28-) 2907 4350 w
+(or) 3155 4350 w
+(48-bits\)) 3313 4350 w
+(of) 3794 4350 w
+(the) 3947 4350 w
+(command) 4163 4350 w
+(and) 4733 4350 w
+(only) 4976 4350 w
+(con\255) 5245 4350 w
+(text) 720 4480 w
+(differentiates) 979 4480 w
+(a) 1740 4480 w
+(command) 1849 4480 w
+(from) 2422 4480 w
+(a) 2725 4480 w
+(response.) 2834 4480 w
+(The) 3438 4480 w
+(SATA) 3686 4480 w
+(specification) 4015 4480 w
+(defines) 4737 4480 w
+(host-) 5176 4480 w
+(to-drive) 720 4610 w
+(communications.) 1220 4610 w
+(The) 2229 4610 w
+(formats) 2491 4610 w
+(of) 2967 4610 w
+(transactions) 3138 4610 w
+(are) 3853 4610 w
+(called) 4083 4610 w
+(Frame) 4457 4610 w
+(Information) 4848 4610 w
+(Structures) 720 4740 w
+(\(FISes\).) 1306 4740 w
+(Typically) 1761 4740 w
+(drivers) 2271 4740 w
+(fill) 2682 4740 w
+(out) 2865 4740 w
+(the) 3087 4740 w
+(command) 3304 4740 w
+(FISes) 3875 4740 w
+(directly) 4189 4740 w
+(and) 4629 4740 w
+(have) 4873 4740 w
+(direct) 5167 4740 w
+(access) 720 4870 w
+(to) 1107 4870 w
+(the) 1255 4870 w
+(Device-to-Host) 1465 4870 w
+(Register) 2337 4870 w
+(\(D2H\)) 2811 4870 w
+(FISes) 3155 4870 w
+(that) 3462 4870 w
+(return) 3712 4870 w
+(the) 4080 4870 w
+(resulting) 4290 4870 w
+(ATA) 4801 4870 w
+(register) 5061 4870 w
+(settings.) 720 5000 w
+(The) 1283 5000 w
+(command) 1551 5000 w
+(FISes) 2145 5000 w
+(are) 2482 5000 w
+(also) 2719 5000 w
+(called) 3004 5000 w
+(Host-to-Device) 3386 5000 w
+(\(H2D\)) 4289 5000 w
+(Register) 4664 5000 w
+(FISes.) 5169 5000 w
+(Using) 720 5130 w
+(this) 1057 5130 w
+(structure) 1291 5130 w
+(has) 1810 5130 w
+(several) 2032 5130 w
+(advantages.) 2444 5130 w
+(It) 3155 5130 w
+(is) 3265 5130 w
+(directly) 3390 5130 w
+(usable) 3821 5130 w
+(by) 4206 5130 w
+(many) 4369 5130 w
+(of) 4694 5130 w
+(the) 4839 5130 w
+(existing) 5046 5130 w
+(SATA) 720 5260 w
+(drivers.) 1056 5260 w
+(All) 1548 5260 w
+(SATA) 1744 5260 w
+(commands) 2080 5260 w
+(are) 2717 5260 w
+(the) 2941 5260 w
+(same) 3168 5260 w
+(size) 3506 5260 w
+(and) 3776 5260 w
+(are) 4031 5260 w
+(tagged) 4256 5260 w
+(as) 4682 5260 w
+(commands.) 4856 5260 w
+(Normal) 720 5390 w
+(responses) 1154 5390 w
+(are) 1741 5390 w
+(also) 1955 5390 w
+(all) 2217 5390 w
+(of) 2388 5390 w
+(the) 2542 5390 w
+(same) 2758 5390 w
+(size) 3084 5390 w
+(and) 3342 5390 w
+(are) 3585 5390 w
+(tagged) 3798 5390 w
+(as) 4212 5390 w
+(responses.) 4374 5390 w
+(Unfortu\255) 5030 5390 w
+(nately, the) 720 5520 w
+(ATA) 1317 5520 w
+(protocol) 1573 5520 w
+(is) 2052 5520 w
+(not) 2176 5520 w
+(specified.) 2388 5520 w
+(Nevertheless,) 2973 5520 w
+(SATA) 3728 5520 w
+(FISes) 4044 5520 w
+(seem) 4348 5520 w
+(to) 4666 5520 w
+(handle) 4810 5520 w
+(most) 5206 5520 w
+(of) 720 5650 w
+(our) 865 5650 w
+(needs) 1082 5650 w
+(and) 1436 5650 w
+(are) 1671 5650 w
+(quite) 1876 5650 w
+(convenient;) 2185 5650 w
+(they) 2838 5650 w
+(can) 3102 5650 w
+(be) 3323 5650 w
+(used) 3490 5650 w
+(directly) 3781 5650 w
+(by) 4211 5650 w
+(two) 4373 5650 w
+(of) 4602 5650 w
+(the) 4746 5650 w
+(three) 4953 5650 w
+(cur\255) 5267 5650 w
+(rent) 720 5780 w
+(SATA) 971 5780 w
+(drivers.) 1286 5780 w
+11 /LucidaSans-Demi f
+(Implementation) 720 6040 w
+11 /LucidaSansUnicode00 f
+(Raw) 720 6210 w
+(ATA) 993 6210 w
+(commands) 1272 6210 w
+(are) 1911 6210 w
+(formatted) 2137 6210 w
+(as) 2724 6210 w
+(a) 2900 6210 w
+(ATA) 3020 6210 w
+(escape) 3300 6210 w
+(byte,) 3725 6210 w
+(an) 4048 6210 w
+(encoded) 4236 6210 w
+(ATA) 4748 6210 w
+(protocol) 5028 6210 w
+11 /LucidaTypewriter f
+(proto) 720 6340 w
+11 /LucidaSansUnicode00 f
+(and) 1164 6340 w
+(the) 1411 6340 w
+(FIS.) 1631 6340 w
+(Typically) 1900 6340 w
+(this) 2414 6340 w
+(would) 2660 6340 w
+(be) 3030 6340 w
+(a) 3210 6340 w
+(H2D) 3320 6340 w
+(FIS,) 3602 6340 w
+(but) 3836 6340 w
+(this) 4063 6340 w
+(is) 4309 6340 w
+(not) 4446 6340 w
+(a) 4671 6340 w
+(requirement.) 4781 6340 w
+(The) 720 6470 w
+(escape) 956 6470 w
+(byte) 1359 6470 w
+(0xff,) 1626 6470 w
+(which) 1917 6470 w
+(is) 2264 6470 w
+(not) 2390 6470 w
+(and,) 2604 6470 w
+(according) 2875 6470 w
+(to) 3435 6470 w
+(the) 3581 6470 w
+(current) 3790 6470 w
+(specification,) 4213 6470 w
+(will) 4959 6470 w
+(never) 5178 6470 w
+(be) 720 6600 w
+(a) 906 6600 w
+(valid) 1022 6600 w
+(SCSI) 1328 6600 w
+(command,) 1609 6600 w
+(was) 2224 6600 w
+(chosen.) 2481 6600 w
+(The) 2983 6600 w
+(protocol) 3237 6600 w
+(encoding) 3736 6600 w
+11 /LucidaTypewriter f
+(proto) 4281 6600 w
+11 /LucidaSansUnicode00 f
+(and) 4731 6600 w
+(other) 4984 6600 w
+(FIS) 5322 6600 w
+(construction) 720 6730 w
+(details) 1442 6730 w
+(are) 1852 6730 w
+(specified) 2077 6730 w
+(in) 2614 6730 w
+11 /LucidaTypewriter f
+(/sys/include/fis.h) 2772 6730 w
+11 /LucidaSansUnicode00 f
+(.) 4194 6730 w
+(The) 4322 6730 w
+11 /LucidaTypewriter f
+(proto) 4579 6730 w
+11 /LucidaSansUnicode00 f
+(encodes) 5032 6730 w
+(the) 720 6860 w
+(ATA) 930 6860 w
+(protocol,) 1190 6860 w
+(the) 1708 6860 w
+(command) 1918 6860 w
+11 /LucidaSansUnicode20 f
+(\034) 2482 6860 w
+11 /LucidaSansUnicode00 f
+(size) 2523 6860 w
+11 /LucidaSansUnicode20 f
+(\035) 2736 6860 w
+11 /LucidaSansUnicode00 f
+(and) 2816 6860 w
+(data) 3053 6860 w
+(direction.) 3324 6860 w
+(The) 3905 6860 w
+11 /LucidaSansUnicode20 f
+(\034) 4143 6860 w
+11 /LucidaSansUnicode00 f
+(atazz) 4184 6860 w
+11 /LucidaSansUnicode20 f
+(\035) 4473 6860 w
+11 /LucidaSansUnicode00 f
+(command) 4552 6860 w
+(format) 5115 6860 w
+(is pictured in Figure 1.) 720 6990 w
+cleartomark
+showpage
+saveobj restore
+%%EndPage: 2 2
+%%Page: 3 3
+/saveobj save def
+mark
+3 pagesetup
+1224 1078 1224 934 Dl
+1224 934 1800 934 Dl
+1800 934 1800 1078 Dl
+1800 1078 1224 1078 Dl
+11 /LucidaSansUnicode00 f
+(0xff) 1403 1028 w
+1800 1078 1800 934 Dl
+1800 934 2376 934 Dl
+2376 934 2376 1078 Dl
+2376 1078 1800 1078 Dl
+(proto) 1944 1028 w
+2376 1078 2376 934 Dl
+2376 934 2952 934 Dl
+2952 934 2952 1078 Dl
+2952 1078 2376 1078 Dl
+(0x27) 2527 1028 w
+2952 1078 2952 934 Dl
+2952 934 3528 934 Dl
+3528 934 3528 1078 Dl
+3528 1078 2952 1078 Dl
+(flags) 3111 1028 w
+1224 1222 1224 1078 Dl
+1224 1078 1800 1078 Dl
+1800 1078 1800 1222 Dl
+1800 1222 1224 1222 Dl
+(cmd) 1399 1172 w
+1800 1222 1800 1078 Dl
+1800 1078 2376 1078 Dl
+2376 1078 2376 1222 Dl
+2376 1222 1800 1222 Dl
+(feat) 1986 1172 w
+2376 1222 2376 1078 Dl
+2376 1078 2952 1078 Dl
+2952 1078 2952 1222 Dl
+2952 1222 2376 1222 Dl
+(lba0) 2549 1172 w
+2952 1222 2952 1078 Dl
+2952 1078 3528 1078 Dl
+3528 1078 3528 1222 Dl
+3528 1222 2952 1222 Dl
+(lba8) 3125 1172 w
+1224 1366 1224 1222 Dl
+1224 1222 1800 1222 Dl
+1800 1222 1800 1366 Dl
+1800 1366 1224 1366 Dl
+(lba16) 1362 1316 w
+1800 1366 1800 1222 Dl
+1800 1222 2376 1222 Dl
+2376 1222 2376 1366 Dl
+2376 1366 1800 1366 Dl
+(dev) 1994 1316 w
+2376 1366 2376 1222 Dl
+2376 1222 2952 1222 Dl
+2952 1222 2952 1366 Dl
+2952 1366 2376 1366 Dl
+(lba24) 2514 1316 w
+2952 1366 2952 1222 Dl
+2952 1222 3528 1222 Dl
+3528 1222 3528 1366 Dl
+3528 1366 2952 1366 Dl
+(lba32) 3090 1316 w
+1224 1510 1224 1366 Dl
+1224 1366 1800 1366 Dl
+1800 1366 1800 1510 Dl
+1800 1510 1224 1510 Dl
+(lba40) 1362 1460 w
+1800 1510 1800 1366 Dl
+1800 1366 2376 1366 Dl
+2376 1366 2376 1510 Dl
+2376 1510 1800 1510 Dl
+(feat8) 1951 1460 w
+2376 1510 2376 1366 Dl
+2376 1366 2952 1366 Dl
+2952 1366 2952 1510 Dl
+2952 1510 2376 1510 Dl
+(cnt) 2582 1460 w
+2952 1510 2952 1366 Dl
+2952 1366 3528 1366 Dl
+3528 1366 3528 1510 Dl
+3528 1510 2952 1510 Dl
+(cnt8) 3123 1460 w
+1224 1654 1224 1510 Dl
+1224 1510 1800 1510 Dl
+1800 1510 1800 1654 Dl
+1800 1654 1224 1654 Dl
+(rsvd) 1399 1604 w
+1800 1654 1800 1510 Dl
+1800 1510 2376 1510 Dl
+2376 1510 2376 1654 Dl
+2376 1654 1800 1654 Dl
+(ctl) 2024 1604 w
+4392 1870 4392 1726 Dl
+4392 1726 4968 1726 Dl
+4968 1726 4968 1870 Dl
+4968 1870 4392 1870 Dl
+(sdXX/raw) 4424 1820 w
+3528 1294 4392 1798 Dl
+4320 1777 4391 1797 Dl
+4338 1746 4391 1797 Dl
+2952 2086 2952 1942 Dl
+2952 1942 3528 1942 Dl
+3528 1942 3528 2086 Dl
+3528 2086 2952 2086 Dl
+(data) 3124 2036 w
+4392 2302 4392 2158 Dl
+4392 2158 4968 2158 Dl
+4968 2158 4968 2302 Dl
+4968 2302 4392 2302 Dl
+(sdXX/raw) 4424 2252 w
+3528 2014 4392 2230 Dl
+4317 2230 4391 2230 Dl
+4326 2194 4391 2229 Dl
+4392 2590 4392 2446 Dl
+4392 2446 4968 2446 Dl
+4968 2446 4968 2590 Dl
+4968 2590 4392 2590 Dl
+(sdXX/raw) 4424 2540 w
+1224 2806 1224 2662 Dl
+1224 2662 1800 2662 Dl
+1800 2662 1800 2806 Dl
+1800 2806 1224 2806 Dl
+(0xff) 1403 2756 w
+1800 2806 1800 2662 Dl
+1800 2662 2376 2662 Dl
+2376 2662 2376 2806 Dl
+2376 2806 1800 2806 Dl
+(proto) 1944 2756 w
+2376 2806 2376 2662 Dl
+2376 2662 2952 2662 Dl
+2952 2662 2952 2806 Dl
+2952 2806 2376 2806 Dl
+(0x34) 2527 2756 w
+2952 2806 2952 2662 Dl
+2952 2662 3528 2662 Dl
+3528 2662 3528 2806 Dl
+3528 2806 2952 2806 Dl
+(port) 3129 2756 w
+1224 2950 1224 2806 Dl
+1224 2806 1800 2806 Dl
+1800 2806 1800 2950 Dl
+1800 2950 1224 2950 Dl
+(stat) 1413 2900 w
+1800 2950 1800 2806 Dl
+1800 2806 2376 2806 Dl
+2376 2806 2376 2950 Dl
+2376 2950 1800 2950 Dl
+(err) 2012 2900 w
+2376 2950 2376 2806 Dl
+2376 2806 2952 2806 Dl
+2952 2806 2952 2950 Dl
+2952 2950 2376 2950 Dl
+(lba0) 2549 2900 w
+2952 2950 2952 2806 Dl
+2952 2806 3528 2806 Dl
+3528 2806 3528 2950 Dl
+3528 2950 2952 2950 Dl
+(lba8) 3125 2900 w
+1224 3094 1224 2950 Dl
+1224 2950 1800 2950 Dl
+1800 2950 1800 3094 Dl
+1800 3094 1224 3094 Dl
+(lba16) 1362 3044 w
+1800 3094 1800 2950 Dl
+1800 2950 2376 2950 Dl
+2376 2950 2376 3094 Dl
+2376 3094 1800 3094 Dl
+(dev) 1994 3044 w
+2376 3094 2376 2950 Dl
+2376 2950 2952 2950 Dl
+2952 2950 2952 3094 Dl
+2952 3094 2376 3094 Dl
+(lba24) 2514 3044 w
+2952 3094 2952 2950 Dl
+2952 2950 3528 2950 Dl
+3528 2950 3528 3094 Dl
+3528 3094 2952 3094 Dl
+(lba32) 3090 3044 w
+1224 3238 1224 3094 Dl
+1224 3094 1800 3094 Dl
+1800 3094 1800 3238 Dl
+1800 3238 1224 3238 Dl
+(lba40) 1362 3188 w
+1800 3238 1800 3094 Dl
+1800 3094 2376 3094 Dl
+2376 3094 2376 3238 Dl
+2376 3238 1800 3238 Dl
+(feat8) 1951 3188 w
+2376 3238 2376 3094 Dl
+2376 3094 2952 3094 Dl
+2952 3094 2952 3238 Dl
+2952 3238 2376 3238 Dl
+(cnt) 2582 3188 w
+2952 3238 2952 3094 Dl
+2952 3094 3528 3094 Dl
+3528 3094 3528 3238 Dl
+3528 3238 2952 3238 Dl
+(cnt8) 3123 3188 w
+1224 3382 1224 3238 Dl
+1224 3238 1800 3238 Dl
+1800 3238 1800 3382 Dl
+1800 3382 1224 3382 Dl
+(rsvd) 1399 3332 w
+1800 3382 1800 3238 Dl
+1800 3238 2376 3238 Dl
+2376 3238 2376 3382 Dl
+2376 3382 1800 3382 Dl
+(ctl) 2024 3332 w
+4392 2518 3528 3022 Dl
+3581 2970 3528 3021 Dl
+3599 3001 3528 3021 Dl
+10 /LucidaSans-Demi f
+(Figure 1) 2853 3646 w
+11 /LucidaSansUnicode00 f
+(Raw) 720 3836 w
+(ATA) 980 3836 w
+(replies) 1247 3836 w
+(are) 1651 3836 w
+(formatted) 1865 3836 w
+(as) 2440 3836 w
+(a) 2603 3836 w
+(one-byte) 2710 3836 w
+(sd) 3246 3836 w
+(status) 3417 3836 w
+(code) 3786 3836 w
+(followed) 4086 3836 w
+(by) 4587 3836 w
+(the) 4759 3836 w
+(reply) 4976 3836 w
+(FIS.) 5287 3836 w
+(The) 720 3966 w
+(usual) 982 3966 w
+(read/write) 1330 3966 w
+(register) 1953 3966 w
+(substitutions) 2427 3966 w
+(are) 3185 3966 w
+(applied;) 3415 3966 w
+(ioport) 3906 3966 w
+(replaces) 4289 3966 w
+(flags,) 4794 3966 w
+(status) 5149 3966 w
+(replaces cmd, error replaces feature.) 720 4096 w
+(Important) 720 4266 w
+(commands) 1289 4266 w
+(such) 1913 4266 w
+(as) 2204 4266 w
+11 /LucidaTypewriter f
+(SMART) 2364 4266 w
+(RETURN) 2846 4266 w
+(STATUS) 3407 4266 w
+11 /LucidaSansUnicode00 f
+(return) 3924 4266 w
+(no) 4296 4266 w
+(data.) 4474 4266 w
+(In) 4819 4266 w
+(this) 4962 4266 w
+(case,) 5202 4266 w
+(the) 720 4396 w
+(protocol) 940 4396 w
+(is) 1433 4396 w
+(run) 1569 4396 w
+(as) 1798 4396 w
+(usual.) 1963 4396 w
+(The) 2366 4396 w
+(client) 2613 4396 w
+(performs) 2952 4396 w
+(a) 3487 4396 w
+(0-byte) 3596 4396 w
+(read) 4006 4396 w
+(to) 4291 4396 w
+(fulfill) 4447 4396 w
+(data) 4773 4396 w
+(transfer) 5053 4396 w
+(step.) 720 4526 w
+(The) 1067 4526 w
+(status) 1315 4526 w
+(is) 1687 4526 w
+(in) 1824 4526 w
+(the) 1973 4526 w
+(D2H) 2193 4526 w
+(FIS) 2475 4526 w
+(returned) 2674 4526 w
+(as) 3183 4526 w
+(the) 3349 4526 w
+(status.) 3569 4526 w
+(The) 4011 4526 w
+(vendor) 4259 4526 w
+(ATA) 4676 4526 w
+(command) 4947 4526 w
+(0xf0) 720 4656 w
+(is) 1012 4656 w
+(used) 1146 4656 w
+(to) 1447 4656 w
+(return) 1601 4656 w
+(the) 1976 4656 w
+(device) 2192 4656 w
+(signature) 2575 4656 w
+(FIS) 3121 4656 w
+(as) 3316 4656 w
+(there) 3478 4656 w
+(is) 3801 4656 w
+(no) 3934 4656 w
+(universal) 4114 4656 w
+(in-band) 4640 4656 w
+(way) 5116 4656 w
+(to) 5364 4656 w
+(do) 720 4786 w
+(this) 893 4786 w
+(without) 1127 4786 w
+(side) 1566 4786 w
+(effects.) 1822 4786 w
+(When) 2288 4786 w
+(talking) 2618 4786 w
+(only) 3021 4786 w
+(to) 3282 4786 w
+(ATA) 3428 4786 w
+(drives,) 3687 4786 w
+(it) 4081 4786 w
+(is) 4192 4786 w
+(possible) 4318 4786 w
+(to) 4799 4786 w
+(first) 4945 4786 w
+(issue) 5198 4786 w
+(a) 720 4916 w
+11 /LucidaTypewriter f
+(IDENTIFY) 817 4916 w
+(PACKET) 1529 4916 w
+(DEVICE) 2083 4916 w
+11 /LucidaSansUnicode00 f
+(and then a) 2593 4916 w
+11 /LucidaTypewriter f
+(IDENTIFY DEVICE) 3196 4916 w
+11 /LucidaSansUnicode00 f
+(command, inferring) 4416 4916 w
+(the) 720 5046 w
+(device) 944 5046 w
+(type) 1335 5046 w
+(from) 1617 5046 w
+(the) 1925 5046 w
+(successful) 2149 5046 w
+(command.) 2753 5046 w
+(However,) 3402 5046 w
+(it) 3950 5046 w
+(would) 4077 5046 w
+(not) 4452 5046 w
+(be) 4682 5046 w
+(possible) 4867 5046 w
+(to) 5364 5046 w
+(enumerate) 720 5176 w
+(the) 1326 5176 w
+(devices behind a) 1532 5176 w
+(port) 2460 5176 w
+(multiplier using this technique.) 2717 5176 w
+11 /LucidaSans-Demi f
+(Kernel changes) 720 5436 w
+(and) 1627 5436 w
+(Libfis) 1873 5436 w
+11 /LucidaSansUnicode00 f
+(Very) 720 5606 w
+(few) 1008 5606 w
+(changes) 1248 5606 w
+(were) 1739 5606 w
+(made) 2045 5606 w
+(to) 2391 5606 w
+(devsd) 2551 5606 w
+(to) 2917 5606 w
+(accommodate) 3078 5606 w
+(ATA) 3875 5606 w
+(commands.) 4149 5606 w
+(the) 4853 5606 w
+11 /LucidaTypewriter f
+(SDreq) 5077 5606 w
+11 /LucidaSansUnicode00 f
+(structure) 720 5736 w
+(adds) 1251 5736 w
+11 /LucidaTypewriter f
+(proto) 1555 5736 w
+11 /LucidaSansUnicode00 f
+(and) 1999 5736 w
+11 /LucidaTypewriter f
+(ataproto) 2246 5736 w
+11 /LucidaSansUnicode00 f
+(fields.) 2927 5736 w
+(To) 3338 5736 w
+(avoid) 3523 5736 w
+(disturbing) 3858 5736 w
+(existing) 4455 5736 w
+(SCSI) 4929 5736 w
+(func\255) 5203 5736 w
+(tionality and to allow) 720 5866 w
+(drivers which support) 1874 5866 w
+(SCSI) 3069 5866 w
+(and) 3331 5866 w
+(ATA) 3565 5866 w
+(commands) 3822 5866 w
+(in) 4439 5866 w
+(parallel,) 4575 5866 w
+(an) 5040 5866 w
+(addi\255) 5205 5866 w
+(tional) 720 5996 w
+11 /LucidaTypewriter f
+(ataio) 1075 5996 w
+11 /LucidaSansUnicode00 f
+(callback) 1524 5996 w
+(was) 2009 5996 w
+(added) 2265 5996 w
+(to) 2649 5996 w
+11 /LucidaTypewriter f
+(SDifc) 2811 5996 w
+11 /LucidaSansUnicode00 f
+(with) 3260 5996 w
+(the) 3540 5996 w
+(same) 3764 5996 w
+(signature) 4098 5996 w
+(as) 4652 5996 w
+(the) 4822 5996 w
+(existing) 5046 5996 w
+11 /LucidaTypewriter f
+(rio) 720 6126 w
+11 /LucidaSansUnicode00 f
+(callback.) 995 6126 w
+(About) 1534 6126 w
+(twenty) 1893 6126 w
+(lines) 2285 6126 w
+(of) 2573 6126 w
+(code) 2719 6126 w
+(were) 3011 6126 w
+(added) 3303 6126 w
+(to) 3671 6126 w
+11 /LucidaTypewriter f
+(port/devsd.c) 3817 6126 w
+11 /LucidaSansUnicode00 f
+(to) 4803 6126 w
+(recognize) 4949 6126 w
+(raw) 720 6256 w
+(ATA) 946 6256 w
+(commands and call) 1202 6256 w
+(the) 2267 6256 w
+(driver) 2473 6256 w
+11 /LucidaSansUnicode20 f
+(\031) 2783 6256 w
+11 /LucidaSansUnicode00 f
+(s) 2818 6256 w
+11 /LucidaTypewriter f
+(ataio) 2909 6256 w
+11 /LucidaSansUnicode00 f
+(function.) 3339 6256 w
+(To) 720 6426 w
+(assist) 896 6426 w
+(in) 1238 6426 w
+(generating) 1378 6426 w
+(the) 1993 6426 w
+(FISes) 2205 6426 w
+(to) 2514 6426 w
+(communicate) 2663 6426 w
+(with) 3419 6426 w
+(devices,) 3686 6426 w
+11 /LucidaTypewriter f
+(libfis) 4156 6426 w
+11 /LucidaSansUnicode00 f
+(was) 4671 6426 w
+(written.) 4914 6426 w
+(It) 5399 6426 w
+(contains) 720 6556 w
+(functions) 1205 6556 w
+(to) 1738 6556 w
+(identify) 1882 6556 w
+(and) 2320 6556 w
+(enumerate) 2554 6556 w
+(the) 3160 6556 w
+(important) 3366 6556 w
+(features of) 3927 6556 w
+(a) 4541 6556 w
+(drive, to format) 4637 6556 w
+(H2D) 720 6686 w
+(FISes And finally, functions) 988 6686 w
+(for) 2465 6686 w
+11 /LucidaSans-Italic f
+(sd) 2654 6686 w
+11 /LucidaSansUnicode00 f
+(and) 2811 6686 w
+11 /LucidaSans-Italic f
+(sd) 3045 6686 w
+11 /LucidaSansUnicode00 f
+(-devices) 3202 6686 w
+(to) 3696 6686 w
+(build) 3840 6686 w
+(D2H) 4146 6686 w
+(FISes) 4415 6686 w
+(to) 4719 6686 w
+(capture) 4863 6686 w
+(the) 5301 6686 w
+(device) 720 6816 w
+(signature.) 1093 6816 w
+(All) 720 6986 w
+(ATA) 907 6986 w
+(device) 1176 6986 w
+(drivers) 1562 6986 w
+(for) 1976 6986 w
+(the) 2177 6986 w
+(386) 2396 6986 w
+(architecture) 2651 6986 w
+(have) 3336 6986 w
+(been) 3632 6986 w
+(modified) 3941 6986 w
+(to) 4463 6986 w
+(accept) 4619 6986 w
+(raw) 5012 6986 w
+(ATA) 5251 6986 w
+(commands.) 720 7116 w
+(Due) 1408 7116 w
+(to) 1658 7116 w
+(consolidation) 1803 7116 w
+(of) 2556 7116 w
+(FIS) 2701 7116 w
+(handling,) 2887 7116 w
+(the) 3424 7116 w
+(AHCI) 3631 7116 w
+(driver) 3932 7116 w
+(lost) 4278 7116 w
+(175) 4510 7116 w
+(lines) 4753 7116 w
+(of) 5039 7116 w
+(code,) 5183 7116 w
+(additional) 720 7246 w
+(non-atazz-related) 1315 7246 w
+(functionality) 2370 7246 w
+(notwithstanding.) 3097 7246 w
+(The) 4096 7246 w
+(IDE) 4359 7246 w
+(driver) 4597 7246 w
+(remained) 4971 7246 w
+cleartomark
+showpage
+saveobj restore
+%%EndPage: 3 3
+%%Page: 4 4
+/saveobj save def
+mark
+4 pagesetup
+11 /LucidaSansUnicode00 f
+(exactly) 720 850 w
+(the) 1138 850 w
+(same) 1351 850 w
+(size.) 1674 850 w
+(Quite) 1999 850 w
+(a) 2330 850 w
+(bit) 2433 850 w
+(more) 2617 850 w
+(code) 2935 850 w
+(could) 3231 850 w
+(be) 3565 850 w
+(removed) 3738 850 w
+(if) 4244 850 w
+(the) 4359 850 w
+(driver) 4571 850 w
+(were) 4922 850 w
+(reor\255) 5217 850 w
+(ganized.) 720 980 w
+(The) 1266 980 w
+(mv50xx) 1518 980 w
+(driver) 2002 980 w
+(gained) 2365 980 w
+(153) 2778 980 w
+(lines) 3039 980 w
+(of) 3343 980 w
+(code.) 3505 980 w
+(Development) 3883 980 w
+(versions) 4642 980 w
+(of) 5139 980 w
+(the) 5301 980 w
+(Marvell) 720 1110 w
+(Orion) 1166 1110 w
+(driver) 1526 1110 w
+(lost) 1898 1110 w
+(over) 2156 1110 w
+(500) 2449 1110 w
+(lines) 2717 1110 w
+(while) 3028 1110 w
+11 /LucidaTypewriter f
+(libfis) 3368 1110 w
+11 /LucidaSansUnicode00 f
+(is) 3903 1110 w
+(only) 4052 1110 w
+(about) 4337 1110 w
+(the) 4704 1110 w
+(same) 4936 1110 w
+(line) 5278 1110 w
+(count.) 720 1240 w
+(Since) 720 1410 w
+(FIS) 1043 1410 w
+(formats) 1239 1410 w
+(were) 1698 1410 w
+(used) 1998 1410 w
+(to) 2299 1410 w
+(convey) 2453 1410 w
+(commands) 2866 1410 w
+(from) 3493 1410 w
+(user) 3794 1410 w
+(space,) 4072 1410 w
+11 /LucidaTypewriter f
+(libfis) 4458 1410 w
+11 /LucidaSansUnicode00 f
+(has) 4979 1410 w
+(been) 5211 1410 w
+(equally) 720 1540 w
+(useful) 1151 1540 w
+(for) 1528 1540 w
+(user) 1731 1540 w
+(space) 2012 1540 w
+(applications.) 2366 1540 w
+(This) 3130 1540 w
+(is) 3405 1540 w
+(because) 3543 1540 w
+(the) 4027 1540 w
+11 /LucidaSans-Italic f
+(atazz) 4247 1540 w
+11 /LucidaSansUnicode00 f
+(interface) 4590 1540 w
+(can) 5107 1540 w
+(be) 5341 1540 w
+(thought) 720 1670 w
+(of) 1178 1670 w
+(as) 1323 1670 w
+(an) 1477 1670 w
+(idealized) 1643 1670 w
+(HBA.) 2162 1670 w
+(Conversely,) 2491 1670 w
+(the) 3146 1670 w
+(hardware) 3355 1670 w
+(driver) 3889 1670 w
+(does) 4237 1670 w
+(not) 4529 1670 w
+(need) 4743 1670 w
+(to) 5042 1670 w
+(know) 5188 1670 w
+(anything about) 720 1800 w
+(the) 1559 1800 w
+(command it) 1765 1800 w
+(is issuing beyond the) 2433 1800 w
+(ATA) 3604 1800 w
+(protocol.) 3860 1800 w
+11 /LucidaSans-Demi f
+(Atazz) 720 2060 w
+11 /LucidaSansUnicode00 f
+(As an example) 720 2230 w
+(and) 1541 2230 w
+(debugging) 1775 2230 w
+(tool,) 2383 2230 w
+(the) 2661 2230 w
+11 /LucidaSans-Italic f
+(atazz) 2868 2230 w
+11 /LucidaSansUnicode00 f
+(\(8\)) 3162 2230 w
+(command) 3339 2230 w
+(was) 3900 2230 w
+(written.) 4138 2230 w
+11 /LucidaSans-Italic f
+(Atazz) 4618 2230 w
+11 /LucidaSansUnicode00 f
+(is) 4957 2230 w
+(an) 5081 2230 w
+(ana\255) 5246 2230 w
+(log) 720 2360 w
+(to) 929 2360 w
+11 /LucidaSans-Italic f
+(scuzz) 1079 2360 w
+11 /LucidaSansUnicode00 f
+(\(8\);) 1374 2360 w
+(they) 1592 2360 w
+(can) 1862 2360 w
+(be) 2089 2360 w
+(thought) 2262 2360 w
+(of) 2725 2360 w
+(as) 2875 2360 w
+(a) 3034 2360 w
+(driver) 3137 2360 w
+(for) 3489 2360 w
+(a) 3684 2360 w
+(virtual) 3787 2360 w
+(interface) 4164 2360 w
+(provided) 4673 2360 w
+(by) 5184 2360 w
+11 /LucidaSans-Italic f
+(sd) 5351 2360 w
+11 /LucidaSansUnicode00 f
+(combined) 720 2490 w
+(with) 1291 2490 w
+(a) 1564 2490 w
+(disk) 1672 2490 w
+(console.) 1940 2490 w
+(ATA) 2465 2490 w
+(commands) 2733 2490 w
+(are) 3361 2490 w
+(spelled) 3576 2490 w
+(out) 4005 2490 w
+(verbosely) 4228 2490 w
+(as) 4782 2490 w
+(in) 4946 2490 w
+(ACS-2.) 5093 2490 w
+(Arbitrary) 720 2620 w
+(ATA) 1227 2620 w
+(commands may be) 1483 2620 w
+(submitted, but) 2520 2620 w
+(the) 3343 2620 w
+(controller or driver may not) 3549 2620 w
+(support) 5057 2620 w
+(all) 720 2750 w
+(of) 880 2750 w
+(them.) 1023 2750 w
+(Here) 1401 2750 w
+(is a) 1686 2750 w
+(sample) 1905 2750 w
+(transcript:) 2322 2750 w
+9 /LucidaTypewriter f
+(az>) 940 2920 w
+(probe) 1200 2920 w
+(/dev/sda0) 940 3030 w
+(976773168;) 1720 3030 w
+(512) 2435 3030 w
+(50000f001b206489) 2760 3030 w
+(/dev/sdC1) 940 3140 w
+(0;) 1720 3140 w
+(0) 1915 3140 w
+(0) 2240 3140 w
+(/dev/sdD0) 940 3250 w
+(1023120;) 1720 3250 w
+(512) 2305 3250 w
+(0) 2760 3250 w
+(/dev/sdE0) 940 3360 w
+(976773168;) 1720 3360 w
+(512) 2435 3360 w
+(50014ee2014f5b5a) 2760 3360 w
+(/dev/sdF7) 940 3470 w
+(976773168;) 1720 3470 w
+(512) 2435 3470 w
+(5000cca214c3a6d3) 2760 3470 w
+(az>) 940 3580 w
+(open) 1200 3580 w
+(/dev/sdF0) 1525 3580 w
+(az>) 940 3690 w
+(smart) 1200 3690 w
+(enable) 1590 3690 w
+(operations) 2045 3690 w
+(az>) 940 3800 w
+(smart) 1200 3800 w
+(return) 1590 3800 w
+(status) 2045 3800 w
+(normal) 940 3910 w
+(az>) 940 4020 w
+(rfis) 1200 4020 w
+(00) 940 4130 w
+(34405000004fc2a00000000000000000) 940 4240 w
+11 /LucidaSansUnicode00 f
+(In) 720 4470 w
+(the) 871 4470 w
+(example,) 1093 4470 w
+(the) 1634 4470 w
+11 /LucidaTypewriter f
+(probe) 1856 4470 w
+11 /LucidaSansUnicode00 f
+(command) 2302 4470 w
+(is) 2878 4470 w
+(a) 3017 4470 w
+(special) 3129 4470 w
+(command) 3548 4470 w
+(that) 4124 4470 w
+(uses) 4386 4470 w
+11 /LucidaTypewriter f
+(#S/sdctl) 4680 4470 w
+11 /LucidaSansUnicode00 f
+(to) 5364 4470 w
+(enumerate) 720 4600 w
+(the) 1336 4600 w
+(controllers) 1552 4600 w
+(in) 2168 4600 w
+(the) 2313 4600 w
+(system.) 2529 4600 w
+(For) 3018 4600 w
+(each) 3233 4600 w
+(controller,) 3524 4600 w
+(the) 4118 4600 w
+11 /LucidaTypewriter f
+(sd) 4333 4600 w
+11 /LucidaSansUnicode00 f
+(vendor) 4535 4600 w
+(command) 4947 4600 w
+11 /LucidaTypewriter f
+(0xf0) 720 4730 w
+11 /LucidaSansUnicode00 f
+(\() 1077 4730 w
+11 /LucidaTypewriter f
+(GET) 1113 4730 w
+(SIGNATURE) 1391 4730 w
+11 /LucidaSansUnicode00 f
+(\)) 2102 4730 w
+(is) 2179 4730 w
+(issued.) 2309 4730 w
+(If) 2764 4730 w
+(this) 2879 4730 w
+(command) 3118 4730 w
+(is) 3685 4730 w
+(successful,) 3815 4730 w
+(the) 4443 4730 w
+(number) 4656 4730 w
+(of) 5112 4730 w
+(sec\255) 5262 4730 w
+(tors,) 720 4860 w
+(sector) 1000 4860 w
+(size) 1363 4860 w
+(and) 1612 4860 w
+(WWN) 1846 4860 w
+(are) 2153 4860 w
+(gathered) 2357 4860 w
+(and) 2869 4860 w
+(and) 3103 4860 w
+(listed.) 3337 4860 w
+(The) 3734 4860 w
+11 /LucidaTypewriter f
+(/dev/sdC1) 3968 4860 w
+11 /LucidaSansUnicode00 f
+(device) 4714 4860 w
+(reports) 5087 4860 w
+(0 sectors and) 720 4990 w
+(0) 1476 4990 w
+(sector) 1581 4990 w
+(size) 1944 4990 w
+(because) 2193 4990 w
+(it) 2663 4990 w
+(is) 2772 4990 w
+(a) 2896 4990 w
+(DVD-RW) 2993 4990 w
+(with) 3495 4990 w
+(no) 3757 4990 w
+(media.) 3928 4990 w
+(The) 4360 4990 w
+11 /LucidaTypewriter f
+(open) 4595 4990 w
+11 /LucidaSansUnicode00 f
+(command) 4947 4990 w
+(is) 720 5120 w
+(another) 850 5120 w
+(special) 1304 5120 w
+(command) 1714 5120 w
+(that) 2281 5120 w
+(issues) 2534 5120 w
+(the) 2906 5120 w
+(same) 3118 5120 w
+(commands) 3440 5120 w
+(a) 4062 5120 w
+(SATA) 4164 5120 w
+(driver) 4485 5120 w
+(would) 4836 5120 w
+(issue) 5198 5120 w
+(to) 720 5250 w
+(gather) 871 5250 w
+(the) 1259 5250 w
+(information) 1473 5250 w
+(about) 2140 5250 w
+(the) 2489 5250 w
+(drive.) 2703 5250 w
+(The) 3081 5250 w
+(final) 3324 5250 w
+(two) 3602 5250 w
+(commands) 3839 5250 w
+(enable) 4464 5250 w
+(SMART) 4862 5250 w
+(and) 5274 5250 w
+(return) 720 5380 w
+(the) 1108 5380 w
+(SMART) 1338 5380 w
+(status.) 1765 5380 w
+(The) 2217 5380 w
+(smart) 2475 5380 w
+(status) 2839 5380 w
+(is) 3221 5380 w
+(returned) 3368 5380 w
+(in) 3887 5380 w
+(a) 4046 5380 w
+(D2H) 4166 5380 w
+(FIS.) 4458 5380 w
+(This) 4737 5380 w
+(result) 5021 5380 w
+(is) 5384 5380 w
+(parsed) 720 5510 w
+(the) 1130 5510 w
+(result) 1349 5510 w
+(is) 1701 5510 w
+(printed) 1837 5510 w
+(as) 2271 5510 w
+(either) 2436 5510 w
+11 /LucidaSansUnicode20 f
+(\034) 2794 5510 w
+11 /LucidaSansUnicode00 f
+(normal,) 2835 5510 w
+11 /LucidaSansUnicode20 f
+(\035) 3245 5510 w
+11 /LucidaSansUnicode00 f
+(or) 3334 5510 w
+11 /LucidaSansUnicode20 f
+(\034) 3494 5510 w
+11 /LucidaSansUnicode00 f
+(threshold) 3535 5510 w
+(exceeded) 4091 5510 w
+11 /LucidaSansUnicode20 f
+(\035) 4600 5510 w
+11 /LucidaSansUnicode00 f
+(\(the) 4690 5510 w
+(drive) 4946 5510 w
+(pre\255) 5260 5510 w
+(dicts imminent) 720 5640 w
+(failure\).) 1551 5640 w
+(As) 720 5810 w
+(a) 889 5810 w
+(further) 987 5810 w
+(real-world) 1394 5810 w
+(example,) 1993 5810 w
+(a) 2520 5810 w
+(drive) 2619 5810 w
+(from) 2922 5810 w
+(my) 3215 5810 w
+(file) 3412 5810 w
+(server) 3617 5810 w
+(failed) 3982 5810 w
+(after) 4317 5810 w
+(a) 4605 5810 w
+(power) 4704 5810 w
+(outage.) 5070 5810 w
+(The) 720 5940 w
+(simple) 957 5940 w
+(diagnostic) 1348 5940 w
+11 /LucidaTypewriter f
+(SMART) 1936 5940 w
+(RETURN) 2413 5940 w
+(STATUS) 2968 5940 w
+11 /LucidaSansUnicode00 f
+(returned) 3479 5940 w
+(an) 3976 5940 w
+(uninformative) 4142 5940 w
+11 /LucidaSansUnicode20 f
+(\034) 4923 5940 w
+11 /LucidaSansUnicode00 f
+(threshold) 4964 5940 w
+(exceeded.) 720 6070 w
+11 /LucidaSansUnicode20 f
+(\035) 1264 6070 w
+11 /LucidaSansUnicode00 f
+(We) 1344 6070 w
+(can) 1540 6070 w
+(run) 1764 6070 w
+(some) 1984 6070 w
+(more) 2310 6070 w
+(in-depth) 2625 6070 w
+(tests.) 3137 6070 w
+(In) 3502 6070 w
+(this) 3641 6070 w
+(case) 3877 6070 w
+(we) 4151 6070 w
+(will) 4337 6070 w
+(need) 4557 6070 w
+(to) 4858 6070 w
+(make) 5006 6070 w
+(up) 5335 6070 w
+(for) 720 6200 w
+(the) 919 6200 w
+(fact) 1136 6200 w
+(that) 1381 6200 w
+11 /LucidaSans-Italic f
+(atazz) 1638 6200 w
+11 /LucidaSansUnicode00 f
+(does) 1978 6200 w
+(not) 2278 6200 w
+(know) 2500 6200 w
+(every) 2830 6200 w
+(option) 3159 6200 w
+(to) 3548 6200 w
+(every) 3701 6200 w
+(command.) 4029 6200 w
+(We) 4669 6200 w
+(will) 4871 6200 w
+(set) 5097 6200 w
+(the) 5301 6200 w
+11 /LucidaTypewriter f
+(lba0) 720 6330 w
+11 /LucidaSansUnicode00 f
+(register by hand:) 1071 6330 w
+cleartomark
+showpage
+saveobj restore
+%%EndPage: 4 4
+%%Page: 5 5
+/saveobj save def
+mark
+5 pagesetup
+9 /LucidaTypewriter f
+(az>) 940 830 w
+(smart) 1200 830 w
+(lba0) 1590 830 w
+(1) 1915 830 w
+(execute) 2045 830 w
+(off-line) 2565 830 w
+(immediate) 3150 830 w
+(#) 3800 830 w
+(short) 3930 830 w
+(data) 4320 830 w
+(collection) 4645 830 w
+(az>) 940 940 w
+(smart) 1200 940 w
+(read) 1590 940 w
+(data) 1915 940 w
+(col) 940 1050 w
+(status:) 1200 1050 w
+(00) 1720 1050 w
+(never) 1915 1050 w
+(started) 2305 1050 w
+(exe) 940 1160 w
+(status:) 1200 1160 w
+(89) 1720 1160 w
+(failed:) 1915 1160 w
+(shipping) 2435 1160 w
+(damage,) 3020 1160 w
+(90%) 3540 1160 w
+(left) 3800 1160 w
+(time) 940 1270 w
+(left:) 1265 1270 w
+(10507s) 1655 1270 w
+(shrt) 940 1380 w
+(poll:) 1265 1380 w
+(176m) 1655 1380 w
+(ext) 940 1490 w
+(poll:) 1200 1490 w
+(19m) 1590 1490 w
+(az>) 940 1600 w
+11 /LucidaSansUnicode00 f
+(Here) 720 1830 w
+(we) 1027 1830 w
+(see) 1231 1830 w
+(that) 1468 1830 w
+(the) 1736 1830 w
+(drive) 1964 1830 w
+(claims) 2286 1830 w
+(that) 2682 1830 w
+(it) 2950 1830 w
+(was) 3080 1830 w
+(damaged) 3339 1830 w
+(in) 3888 1830 w
+(shipping) 4045 1830 w
+(and) 4564 1830 w
+(the) 4820 1830 w
+(damage) 5049 1830 w
+(occurred) 720 1960 w
+(in) 1226 1960 w
+(the) 1364 1960 w
+(first) 1572 1960 w
+(10%) 1824 1960 w
+(of) 2073 1960 w
+(the) 2218 1960 w
+(drive.) 2426 1960 w
+(Since) 2798 1960 w
+(we) 3112 1960 w
+(know) 3296 1960 w
+(the) 3617 1960 w
+(drive) 3825 1960 w
+(had) 4127 1960 w
+(been) 4362 1960 w
+(working) 4660 1960 w
+(before) 5126 1960 w
+(the) 720 2090 w
+(power) 941 2090 w
+(outage,) 1319 2090 w
+(and) 1771 2090 w
+(the) 2019 2090 w
+(original) 2240 2090 w
+(symptom) 2695 2090 w
+(was) 3239 2090 w
+(excessive) 3491 2090 w
+(UREs) 4051 2090 w
+(\(Unrecoverable) 4362 2090 w
+(Read) 5211 2090 w
+(Errors\)) 720 2220 w
+(followed) 1121 2220 w
+(by) 1624 2220 w
+(write) 1798 2220 w
+(failures,) 2111 2220 w
+(and) 2591 2220 w
+(finally) 2837 2220 w
+(a) 3208 2220 w
+(threshold) 3317 2220 w
+(exceeded) 3873 2220 w
+(condition,) 4430 2220 w
+(it) 5013 2220 w
+(is) 5133 2220 w
+(rea\255) 5268 2220 w
+(sonable) 720 2350 w
+(to assume) 1170 2350 w
+(that) 1753 2350 w
+(the) 1999 2350 w
+(head may have) 2205 2350 w
+(crashed.) 3038 2350 w
+11 /LucidaSans-Demi f
+(Stand) 720 2610 w
+(Alone) 1074 2610 w
+(Applications) 1434 2610 w
+11 /LucidaSansUnicode00 f
+(There) 720 2780 w
+(are) 1107 2780 w
+(several) 1357 2780 w
+(obvious) 1814 2780 w
+(stand-alone) 2312 2780 w
+(applications) 3043 2780 w
+(for) 3769 2780 w
+(this) 4004 2780 w
+(functionality:) 4283 2780 w
+(a) 5064 2780 w
+(drive) 5207 2780 w
+(firmware) 720 2910 w
+(upgrade) 1243 2910 w
+(utility,) 1735 2910 w
+(a) 2123 2910 w
+(drive) 2233 2910 w
+(scrubber) 2547 2910 w
+(that) 3066 2910 w
+(bypasses) 3326 2910 w
+(the) 3861 2910 w
+(drive) 4081 2910 w
+(cache) 4395 2910 w
+(and) 4747 2910 w
+(a) 4994 2910 w
+(SMART) 5104 2910 w
+(monitor.) 720 3040 w
+(Since) 720 3210 w
+(SCSI) 1032 3210 w
+(also supports a) 1293 3210 w
+(basic) 2146 3210 w
+(SMART-like) 2456 3210 w
+(interface) 3114 3210 w
+(through) 3618 3210 w
+(the) 4079 3210 w
+11 /LucidaTypewriter f
+(SEND) 4286 3210 w
+(DIAGNOSTIC) 4682 3210 w
+11 /LucidaSansUnicode00 f
+(and) 720 3340 w
+11 /LucidaTypewriter f
+(RECEIVE) 964 3340 w
+(DIAGNOSTIC) 1607 3340 w
+(RESULTS) 2487 3340 w
+11 /LucidaSansUnicode00 f
+(commands,) 3086 3340 w
+11 /LucidaSans-Italic f
+(disk/smart) 3748 3340 w
+11 /LucidaSansUnicode00 f
+(\(8\)) 4336 3340 w
+(gives) 4522 3340 w
+(a) 4842 3340 w
+(chance) 4948 3340 w
+(to) 5364 3340 w
+(test) 720 3470 w
+(both raw) 955 3470 w
+(ATA) 1461 3470 w
+(and SCSI) 1717 3470 w
+(commands in the) 2211 3470 w
+(same) 3168 3470 w
+(application.) 3484 3470 w
+11 /LucidaSans-Italic f
+(Disk/smart) 720 3640 w
+11 /LucidaSansUnicode00 f
+(uses) 1362 3640 w
+(the) 1644 3640 w
+(usual) 1855 3640 w
+(techniques) 2180 3640 w
+(for) 2802 3640 w
+(gathering) 2995 3640 w
+(a) 3548 3640 w
+(list) 3649 3640 w
+(of) 3850 3640 w
+(devices) 3998 3640 w
+(or) 4432 3640 w
+(uses) 4584 3640 w
+(the) 4866 3640 w
+(devices) 5078 3640 w
+(given.) 720 3770 w
+(Then) 1135 3770 w
+(it) 1460 3770 w
+(issues) 1590 3770 w
+(a) 1977 3770 w
+(raw) 2095 3770 w
+(ATA) 2343 3770 w
+(request) 2621 3770 w
+(for) 3081 3770 w
+(the) 3291 3770 w
+(device) 3519 3770 w
+(signature.) 3914 3770 w
+(If) 4542 3770 w
+(that) 4672 3770 w
+(fails,) 4940 3770 w
+(it) 5254 3770 w
+(is) 5384 3770 w
+(assumed) 720 3900 w
+(that) 1262 3900 w
+(the) 1541 3900 w
+(drive) 1780 3900 w
+(is) 2113 3900 w
+(SCSI,) 2270 3900 w
+(and) 2600 3900 w
+(a) 2867 3900 w
+(raw) 2997 3900 w
+(SCSI) 3257 3900 w
+(request) 3552 3900 w
+(is) 4024 3900 w
+(issued.) 4181 3900 w
+(In) 4663 3900 w
+(both) 4832 3900 w
+(cases,) 5146 3900 w
+11 /LucidaSans-Italic f
+(disk/smart) 720 4030 w
+11 /LucidaSansUnicode00 f
+(is able) 1343 4030 w
+(to reliably determine) 1725 4030 w
+(if) 2871 4030 w
+(SMART is supported and can be) 2979 4030 w
+(enabled.) 4705 4030 w
+(If) 720 4200 w
+(successful,) 829 4200 w
+(each) 1452 4200 w
+(device) 1736 4200 w
+(is) 2111 4200 w
+(probed) 2236 4200 w
+(every) 2654 4200 w
+(5) 2974 4200 w
+(minutes) 3080 4200 w
+(and) 3546 4200 w
+(failures) 3781 4200 w
+(are) 4215 4200 w
+(logged.) 4420 4200 w
+(A) 4893 4200 w
+(one) 5006 4200 w
+(shot) 5240 4200 w
+(mode) 720 4330 w
+(is also available:) 1055 4330 w
+9 /LucidaTypewriter f
+(chula#) 940 4500 w
+(disk/smart) 1395 4500 w
+(-atv) 2110 4500 w
+(sda0:) 940 4610 w
+(normal) 1330 4610 w
+(sda1:) 940 4720 w
+(normal) 1330 4720 w
+(sda2:) 940 4830 w
+(normal) 1330 4830 w
+(sda3:) 940 4940 w
+(threshold) 1330 4940 w
+(exceeded) 1980 4940 w
+(sdE1:) 940 5050 w
+(normal) 1330 5050 w
+(sdF7:) 940 5160 w
+(normal) 1330 5160 w
+11 /LucidaSansUnicode00 f
+(Drives) 720 5390 w
+11 /LucidaTypewriter f
+(sda0) 1095 5390 w
+11 /LucidaSansUnicode00 f
+(,) 1411 5390 w
+11 /LucidaTypewriter f
+(sda1) 1486 5390 w
+11 /LucidaSansUnicode00 f
+(are) 1842 5390 w
+(SCSI) 2050 5390 w
+(and) 2316 5390 w
+(the) 2555 5390 w
+(remainder) 2767 5390 w
+(are) 3354 5390 w
+(ATA.) 3563 5390 w
+(Note) 3895 5390 w
+(that) 4187 5390 w
+(other) 4439 5390 w
+(drives) 4763 5390 w
+(on) 5125 5390 w
+(the) 5301 5390 w
+(same) 720 5520 w
+(controller are) 1036 5520 w
+(ATA.) 1789 5520 w
+(Recalling that) 2115 5520 w
+11 /LucidaTypewriter f
+(sdC0) 2876 5520 w
+11 /LucidaSansUnicode00 f
+(was previously listed, we) 3227 5520 w
+(can check) 4588 5520 w
+(to see) 5149 5520 w
+(why no results were) 720 5650 w
+(reported by) 1819 5650 w
+11 /LucidaTypewriter f
+(sdC0) 2475 5650 w
+11 /LucidaSansUnicode00 f
+(:) 2791 5650 w
+9 /LucidaTypewriter f
+(chula#) 940 5820 w
+(for\(i) 1395 5820 w
+(in) 1785 5820 w
+(a3) 1980 5820 w
+(C0\)) 2175 5820 w
+(echo) 1200 5930 w
+(identify) 1525 5930 w
+(device) 2110 5930 w
+(|) 2565 5930 w
+(atazz) 1460 6040 w
+(/dev/sd$i) 1850 6040 w
+(>[2]/dev/null) 2500 6040 w
+(|) 3410 6040 w
+(grep) 1460 6150 w
+('^flags') 1785 6150 w
+(flags) 940 6260 w
+(lba) 1460 6260 w
+(llba) 1720 6260 w
+(smart) 2045 6260 w
+(power) 2435 6260 w
+(nop) 2825 6260 w
+(sct) 3085 6260 w
+(flags) 940 6370 w
+(lba) 1460 6370 w
+11 /LucidaSansUnicode00 f
+(So we) 720 6560 w
+(see) 1063 6560 w
+(that) 1278 6560 w
+11 /LucidaTypewriter f
+(sdC0) 1524 6560 w
+11 /LucidaSansUnicode00 f
+(simply does not) 1875 6560 w
+(support) 2758 6560 w
+(the) 3208 6560 w
+(SMART feature) 3414 6560 w
+(set.) 4232 6560 w
+cleartomark
+showpage
+saveobj restore
+%%EndPage: 5 5
+%%Page: 6 6
+/saveobj save def
+mark
+6 pagesetup
+11 /LucidaSans-Demi f
+(Further) 720 850 w
+(Work) 1174 850 w
+11 /LucidaSansUnicode00 f
+(While) 720 1020 w
+(the) 1047 1020 w
+(raw) 1256 1020 w
+(ATA) 1485 1020 w
+(interface) 1744 1020 w
+(has) 2250 1020 w
+(been) 2473 1020 w
+(used) 2772 1020 w
+(extensively) 3065 1020 w
+(from) 3699 1020 w
+(user) 3992 1020 w
+(space) 4261 1020 w
+(and) 4603 1020 w
+(has) 4840 1020 w
+(allowed) 5064 1020 w
+(the) 720 1150 w
+(removal) 928 1150 w
+(of) 1391 1150 w
+(quirky) 1536 1150 w
+(functionality,) 1908 1150 w
+(device) 2644 1150 w
+(setup) 3019 1150 w
+(has) 3352 1150 w
+(not) 3574 1150 w
+(yet) 3787 1150 w
+(been) 3984 1150 w
+(addressed.) 4282 1150 w
+(For) 4937 1150 w
+(exam\255) 5144 1150 w
+(ple,) 720 1280 w
+(both) 960 1280 w
+(the) 1247 1280 w
+(Orion) 1460 1280 w
+(and) 1800 1280 w
+(AHCI) 2040 1280 w
+(drivers) 2347 1280 w
+(have) 2755 1280 w
+(an) 3045 1280 w
+(initialization) 3216 1280 w
+(routine) 3920 1280 w
+(similar) 4345 1280 w
+(to) 4747 1280 w
+(the) 4898 1280 w
+(follow\255) 5112 1280 w
+(ing) 720 1410 w
+9 /LucidaTypewriter f
+(newdrive\(Drive) 940 1580 w
+(*d\)) 1915 1580 w
+({) 940 1690 w
+(setfissig\(d,) 1200 1800 w
+(getsig\(d\)\);) 2045 1800 w
+(if\(identify\(d\)) 1200 1910 w
+(!=) 2175 1910 w
+(0\)) 2370 1910 w
+(return) 1460 2020 w
+(SDeio;) 1915 2020 w
+(setpowermode\(d\);) 1200 2130 w
+(if\(settxmode\(d,) 1200 2240 w
+(d->udma\)) 2240 2240 w
+(!=) 2825 2240 w
+(0\)) 3020 2240 w
+(return) 1460 2350 w
+(SDeio;) 1915 2350 w
+(return) 1200 2460 w
+(SDok;) 1655 2460 w
+(}) 940 2570 w
+11 /LucidaSansUnicode00 f
+(However) 720 2760 w
+(in) 1228 2760 w
+(preparing) 1377 2760 w
+(this) 1945 2760 w
+(document,) 2191 2760 w
+(it) 2808 2760 w
+(was) 2930 2760 w
+(discovered) 3181 2760 w
+(that) 3805 2760 w
+(one) 4065 2760 w
+(sets) 4311 2760 w
+(the) 4575 2760 w
+(power) 4795 2760 w
+(mode) 5172 2760 w
+(before) 720 2890 w
+(setting) 1115 2890 w
+(the) 1532 2890 w
+(transfer) 1752 2890 w
+(mode) 2220 2890 w
+(and) 2569 2890 w
+(the) 2816 2890 w
+(other) 3036 2890 w
+(does) 3368 2890 w
+(the) 3671 2890 w
+(opposite.) 3891 2890 w
+(It) 4473 2890 w
+(is) 4595 2890 w
+(not) 4732 2890 w
+(clear) 4957 2890 w
+(that) 5261 2890 w
+(this) 720 3020 w
+(particular) 953 3020 w
+(difference) 1500 3020 w
+(is) 2075 3020 w
+(a) 2200 3020 w
+(problem,) 2298 3020 w
+(but) 2816 3020 w
+(over) 3031 3020 w
+(time,) 3299 3020 w
+(such) 3608 3020 w
+(differences) 3893 3020 w
+(will) 4524 3020 w
+(be) 4742 3020 w
+(the) 4910 3020 w
+(source) 5118 3020 w
+(of) 720 3150 w
+(bugs.) 890 3150 w
+(Neither) 1283 3150 w
+(the) 1736 3150 w
+(IDE) 1969 3150 w
+(nor) 2205 3150 w
+(the) 2447 3150 w
+(Marvell) 2680 3150 w
+(50xx) 3126 3150 w
+(drivers) 3460 3150 w
+(sets) 3888 3150 w
+(the) 4165 3150 w
+(power) 4398 3150 w
+(mode) 4788 3150 w
+(at) 5149 3150 w
+(all.) 5312 3150 w
+(Worse,) 720 3280 w
+(none) 1122 3280 w
+(is) 1429 3280 w
+(capable) 1560 3280 w
+(of) 2013 3280 w
+(properly) 2164 3280 w
+(addressing) 2653 3280 w
+(drives) 3282 3280 w
+(with) 3646 3280 w
+(features) 3915 3280 w
+(such) 4394 3280 w
+(as) 4685 3280 w
+(PUIS) 4845 3280 w
+(\(Power) 5116 3280 w
+(Up) 720 3410 w
+(In) 916 3410 w
+(Standby\)) 1067 3410 w
+(enabled.) 1578 3410 w
+(To) 2122 3410 w
+(addresses) 2309 3410 w
+(this) 2896 3410 w
+(problem) 3143 3410 w
+(all) 3639 3410 w
+(four) 3814 3410 w
+(of) 4085 3410 w
+(the) 4243 3410 w
+(ATA) 4464 3410 w
+(drivers) 4735 3410 w
+(would) 5151 3410 w
+(need to be) 720 3540 w
+(changed.) 1325 3540 w
+(Rather) 720 3710 w
+(than) 1104 3710 w
+(maintaining) 1380 3710 w
+(a) 2052 3710 w
+(number) 2152 3710 w
+(of) 2605 3710 w
+(mutually) 2752 3710 w
+(out-of-date) 3252 3710 w
+(drivers,) 3936 3710 w
+(it) 4376 3710 w
+(would) 4488 3710 w
+(be) 4848 3710 w
+(advanta\255) 5018 3710 w
+(geous) 720 3840 w
+(to) 1081 3840 w
+(build) 1229 3840 w
+(an) 1539 3840 w
+(ATA) 1708 3840 w
+(analog) 1968 3840 w
+(of) 2364 3840 w
+11 /LucidaTypewriter f
+(pc/sdscsi.c) 2511 3840 w
+11 /LucidaSansUnicode00 f
+(using) 3419 3840 w
+(the) 3750 3840 w
+(raw) 3960 3840 w
+(ATA) 4190 3840 w
+(interface) 4450 3840 w
+(to) 4957 3840 w
+(submit) 5104 3840 w
+(ATA) 720 3970 w
+(commands.) 987 3970 w
+(There) 1684 3970 w
+(are) 2036 3970 w
+(some) 2250 3970 w
+(difficulties) 2583 3970 w
+(that) 3191 3970 w
+(make) 3448 3970 w
+(such) 3783 3970 w
+(a) 4077 3970 w
+(change) 4184 3970 w
+(a) 4614 3970 w
+(bit) 4722 3970 w
+(more) 4911 3970 w
+(than) 5234 3970 w
+(trivial.) 720 4100 w
+(Since) 1139 4100 w
+(current) 1465 4100 w
+(model) 1899 4100 w
+(for) 2279 4100 w
+(hot-pluggable) 2480 4100 w
+(devices) 3297 4100 w
+(is) 3739 4100 w
+(not) 3875 4100 w
+(compatible) 4099 4100 w
+(with) 4738 4100 w
+(the) 5012 4100 w
+(top-) 5231 4100 w
+(down approach currently taken by) 720 4230 w
+11 /LucidaSans-Italic f
+(sd) 2576 4230 w
+11 /LucidaSansUnicode00 f
+(this would need to be) 2732 4230 w
+(addressed.) 3925 4230 w
+(It) 4579 4230 w
+(does) 4688 4230 w
+(not) 4978 4230 w
+(seem) 5190 4230 w
+(that) 720 4360 w
+(this) 997 4360 w
+(would) 1260 4360 w
+(be) 1647 4360 w
+(difficult.) 1844 4360 w
+(Interface) 2392 4360 w
+(resets) 2925 4360 w
+(after) 3312 4360 w
+(failed) 3627 4360 w
+(commands) 3989 4360 w
+(should) 4635 4360 w
+(also) 5060 4360 w
+(be) 5341 4360 w
+(addressed.) 720 4490 w
+11 /LucidaSans-Demi f
+(Source) 720 4750 w
+11 /LucidaSansUnicode00 f
+(The) 720 4920 w
+(current) 962 4920 w
+(source) 1390 4920 w
+(including) 1787 4920 w
+(all) 2323 4920 w
+(the) 2491 4920 w
+(pc) 2705 4920 w
+(drivers) 2874 4920 w
+(and) 3284 4920 w
+(applications) 3526 4920 w
+(are) 4214 4920 w
+(available) 4426 4920 w
+(in) 4937 4920 w
+(the) 5081 4920 w
+(fol\255) 5296 4920 w
+(lowing) 720 5050 w
+11 /LucidaSans-Italic f
+(contrib) 1107 5050 w
+11 /LucidaSansUnicode00 f
+(\(1\) packages on) 1487 5050 w
+11 /LucidaSans-Italic f
+(sources) 2365 5050 w
+11 /LucidaSansUnicode00 f
+(:) 2770 5050 w
+11 /LucidaTypewriter f
+(quanstro/fis) 720 5180 w
+11 /LucidaSansUnicode00 f
+(,) 1668 5180 w
+11 /LucidaTypewriter f
+(quanstro/sd) 720 5310 w
+11 /LucidaSansUnicode00 f
+(,) 1589 5310 w
+11 /LucidaTypewriter f
+(quanstro/atazz) 720 5440 w
+11 /LucidaSansUnicode00 f
+(, and) 1826 5440 w
+11 /LucidaTypewriter f
+(quanstro/smart) 720 5570 w
+11 /LucidaSansUnicode00 f
+(.) 1826 5570 w
+(The) 720 5740 w
+(following manual) 954 5740 w
+(pages are) 1908 5740 w
+(included:) 2462 5740 w
+11 /LucidaSans-Italic f
+(fis) 720 5870 w
+11 /LucidaSansUnicode00 f
+(\(2\),) 848 5870 w
+11 /LucidaSans-Italic f
+(sd) 1059 5870 w
+11 /LucidaSansUnicode00 f
+(\(3\),) 1180 5870 w
+11 /LucidaSans-Italic f
+(sdahci) 1391 5870 w
+11 /LucidaSansUnicode00 f
+(\(3\),) 1734 5870 w
+11 /LucidaSans-Italic f
+(sdaoe) 1945 5870 w
+11 /LucidaSansUnicode00 f
+(\(3\),) 2254 5870 w
+11 /LucidaSans-Italic f
+(sdloop) 2465 5870 w
+11 /LucidaSansUnicode00 f
+(\(3\),) 2811 5870 w
+11 /LucidaSans-Italic f
+(sdorion) 3022 5870 w
+11 /LucidaSansUnicode00 f
+(\(3\),) 3422 5870 w
+11 /LucidaSans-Italic f
+(atazz) 3633 5870 w
+11 /LucidaSansUnicode00 f
+(\(8\), and) 3927 5870 w
+11 /LucidaSans-Italic f
+(smart) 4371 5870 w
+11 /LucidaSansUnicode00 f
+(\(8\).) 4689 5870 w
+11 /LucidaSans-Demi f
+(Abbreviated) 720 6130 w
+(References) 1446 6130 w
+11 /LucidaSansUnicode00 f
+([1]) 720 6300 w
+11 /LucidaSans-Italic f
+(sd) 995 6300 w
+11 /LucidaSansUnicode00 f
+(\(1\), published online) 1116 6300 w
+(at) 2251 6300 w
+11 /LucidaTypewriter f
+(http://plan9.bell-labs.com/magic/man2html/3/sd) 995 6430 w
+11 /LucidaSansUnicode00 f
+(.) 4629 6430 w
+([2]) 720 6600 w
+11 /LucidaSans-Italic f
+(scuzz) 995 6600 w
+11 /LucidaSansUnicode00 f
+(\(8\), published online) 1290 6600 w
+(at) 2425 6600 w
+11 /LucidaTypewriter f
+(http://plan9.bell-labs.com/magic/man2html/8/scuzz) 995 6730 w
+11 /LucidaSansUnicode00 f
+(.) 4866 6730 w
+([3]) 720 6900 w
+(T13) 995 6900 w
+11 /LucidaSans-Italic f
+(ATA/ATAPI) 1239 6900 w
+(Command) 1865 6900 w
+(Set ) 2446 6900 w
+11 /LucidaSansUnicode20 f
+(\023) 2642 6900 w
+11 /LucidaSans-Italic f
+(2) 2732 6900 w
+11 /LucidaSansUnicode00 f
+(,) 2801 6900 w
+(revision) 2873 6900 w
+(1,) 3329 6900 w
+(January) 3470 6900 w
+(21,) 3901 6900 w
+(2009,) 4111 6900 w
+(formerly) 4459 6900 w
+(published) 4947 6900 w
+(online) 995 7030 w
+(at) 1359 7030 w
+11 /LucidaTypewriter f
+(http://www.t13.org) 1496 7030 w
+11 /LucidaSansUnicode00 f
+(.) 2918 7030 w
+([4]) 720 7200 w
+(T10) 995 7200 w
+11 /LucidaSans-Italic f
+(SCSI/ATA) 1268 7200 w
+(Translation ) 1836 7200 w
+11 /LucidaSansUnicode20 f
+(\023) 2485 7200 w
+11 /LucidaSans-Italic f
+(2) 2575 7200 w
+(\(SAT) 2710 7200 w
+11 /LucidaSansUnicode20 f
+(\023) 2951 7200 w
+11 /LucidaSans-Italic f
+(2\)) 3006 7200 w
+11 /LucidaSansUnicode00 f
+(,) 3111 7200 w
+(revision) 3213 7200 w
+(7,) 3699 7200 w
+(February) 3870 7200 w
+(18,) 4403 7200 w
+(2007,) 4643 7200 w
+(formerly) 5021 7200 w
+cleartomark
+showpage
+saveobj restore
+%%EndPage: 6 6
+%%Page: 7 7
+/saveobj save def
+mark
+7 pagesetup
+11 /LucidaSansUnicode00 f
+(published online) 995 850 w
+(at) 1919 850 w
+11 /LucidaTypewriter f
+(http://www.t10.org) 2056 850 w
+11 /LucidaSansUnicode00 f
+(.) 3478 850 w
+cleartomark
+showpage
+saveobj restore
+%%EndPage: 7 7
+%%Trailer
+done
+%%DocumentFonts: LucidaSansUnicode20 LucidaSansUnicode00 LucidaSans-Demi LucidaSans-Italic LucidaTypewriter
+%%Pages: 7
--- /dev/null
+++ b/sys/src/cmd/atazz/bit.c
@@ -1,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;
+}
--- /dev/null
+++ b/sys/src/cmd/atazz/macros.ms
@@ -1,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
--- /dev/null
+++ b/sys/src/cmd/atazz/main.c
@@ -1,0 +1,1928 @@
+#include <u.h>
+#include <libc.h>
+#include <fis.h>
+#include "atazz.h"
+#include "tabs.h"
+
+#pragma	varargck	argpos	eprint	1
+#pragma	varargck	type	"π"	char**
+
+enum {
+	Dontread	= -2,
+};
+
+int	interrupted;
+int	rflag;
+int	squelch;
+int	scttrace;
+uchar	issuetr[0x100];
+
+Atatab	*idcmd;
+Atatab	*idpktcmd;
+Atatab	*sigcmd;
+Atatab	*sctread;
+Atatab	*sctissue;
+
+int
+πfmt(Fmt *f)
+{
+	char **p;
+
+	p = va_arg(f->args, char**);
+	if(p == nil)
+		return fmtstrcpy(f, "<nil**>");
+	for(; *p; p++){
+		fmtstrcpy(f, *p);
+		if(p[1] != nil)
+			fmtstrcpy(f, " ");
+	}
+	return 0;
+}
+
+int
+eprint(char *fmt, ...)
+{
+	int n;
+	va_list args;
+
+	if(squelch)
+		return 0;
+//	Bflush(&out);
+
+	va_start(args, fmt);
+	n = vfprint(2, fmt, args);
+	va_end(args);
+	return n;
+}
+
+void
+fisset(Req *r, uint i, uint v)
+{
+	if(r->fisbits & 1<<i)
+		return;
+	r->fisbits |= 1<<i;
+	r->cmd.fis[i] = v;
+}
+
+void
+prreq(Req *r)
+{
+	uchar *u;
+
+	print("%.2ux %.2ux\n", r->cmd.sdcmd, r->cmd.ataproto);
+	u = r->cmd.fis;
+	print("%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux ",
+		u[0], u[1], u[2], u[3], u[4], u[5], u[6], u[7]);
+	u += 8;
+	print("%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux\n",
+		u[0], u[1], u[2], u[3], u[4], u[5], u[6], u[7]);
+}
+
+char*
+protostr(char *p, char *e, int pr)
+{
+	char *s;
+
+	*p = 0;
+	if(pr & P28)
+		p = seprint(p, e, "28:");
+	else
+		p = seprint(p, e, "28:");
+	switch(pr & Pprotom){
+	default:
+		s = "unk";
+		break;
+	case Ppkt:
+		s = "pkt";
+		break;
+	case Pdiag:
+		s = "dig";
+		break;
+	case Preset:
+		s = "rst";
+		break;
+	case Pdmq:
+		s = "dmq";
+		break;
+	case Pdma:
+		s = "dma";
+		break;
+	case Ppio:
+		s = "pio";
+		break;
+	}
+	p = seprint(p, e, "%s:", s);
+	switch(pr & Pdatam){
+	default:
+		s = "nd";
+		break;
+	case Pin:
+		s = "in";
+		break;
+	case Pout:
+		s = "out";
+		break;
+	}
+	p = seprint(p, e, "%s", s);
+	return p;
+}
+
+void
+displaycmd(Req *r, Atatab *a)
+{
+	char buf[32];
+	int i;
+
+	if(a->cc > nelem(issuetr) || !issuetr[a->cc])
+		return;
+	protostr(buf, buf + sizeof buf, a->protocol);
+	fprint(2, "cmd %s:%2ux ", buf, a->cc);
+	for(i = 0; i < 16; i++)
+		fprint(2, "%.2ux", r->cmd.fis[i]);
+	fprint(2, "\n");
+}
+
+int
+issueata(Req *r, Atatab *a, Dev *d)
+{
+	uchar u;
+	int n, ok, pr, rv;
+
+	r->haverfis = 0;
+	pr = a->protocol & Pdatam;
+	r->data = realloc(r->data, r->count);
+	if(r->data == nil && r->count > 0)
+		sysfatal("realloc: %r");
+	if(r->data == nil && pr != Pnd)
+		sysfatal("no data for cmd %.2ux", a->cc);
+	if(0 && r->fisbits)
+		print("fisbits %.16b\n", r->fisbits);
+	r->cmd.sdcmd = 0xff;
+	r->cmd.ataproto = a->protocol;
+	if(a->cc & 0xff00)
+		fisset(r, 0, a->cc >> 8);
+	else
+		fisset(r, 0, H2dev);
+	fisset(r, 1, Fiscmd);
+	fisset(r, 2, a->cc);
+	switch(pr){
+	case Pout:
+		if(r->rfd != Dontread){
+			n = readn(r->rfd, r->data, r->count);
+			if(n != r->count){
+				if(n == -1)
+					eprint("!short src read %r\n");
+				else
+					eprint("!short src read %d wanted %lld\n", n, r->count);
+				return -1;
+			}
+		}
+	case Pnd:
+	case Pin:
+		if(0 && (d->feat & Dlba) == 0 && (d->c | d->h | d->s)){
+			int c, h, s;
+			c = r->lba / (d->s * d->h);
+			h = (r->lba / d->s) % d->h;
+			s = (r->lba % d->s) + 1;
+print("%d %d %d\n", c, h, s);
+			fisset(r, 4, s);
+			fisset(r, 5, c);
+			fisset(r, 6, c >> 8);
+			fisset(r, 7, Ataobs | h);
+		}else{
+			fisset(r, 4, r->lba);
+			fisset(r, 5, r->lba >> 8);
+			fisset(r, 6, r->lba >> 16);
+			u = Ataobs;
+			if(pr == Pin || pr == Pout)
+				u |= Atalba;
+			if((d->feat & Dllba) == 0)
+				u |= (r->lba >> 24) & 7;
+			fisset(r, 7, u);
+			fisset(r, 8, r->lba >> 24);
+			fisset(r, 9, r->lba >> 32);
+			fisset(r, 10, r->lba >> 48);
+		}
+		fisset(r, 12, r->nsect);
+		fisset(r, 13, r->nsect >> 8);
+		break;
+	}
+	fisset(r, 7, Ataobs);
+	displaycmd(r, a);
+	if(write(d->fd, &r->cmd, Cmdsz) != Cmdsz){
+		eprint("fis write error: %r\n");
+		return -1;
+	}
+
+	werrstr("");
+	switch(pr){
+	default:
+		ok = read(d->fd, "", 0) == 0;
+		break;
+	case Pin:
+		ok = read(d->fd, r->data, r->count) == r->count;
+		r->lba += r->nsect;
+		break;
+	case Pout:
+		ok = write(d->fd, r->data, r->count) == r->count;
+		r->lba += r->nsect;
+		break;
+	}
+	rv = 0;
+	if(ok == 0){
+		eprint("xfer error: %.2ux %r\n", a->cc);
+		rv = -1;
+	}
+	switch(n = read(d->fd, &r->reply, Replysz)){
+	case Replysz:
+		r->haverfis = 1;
+		return rv;
+	case -1:
+		eprint("status fis read error: %r\n");
+		return -1;
+	default:
+		eprint("status fis read error: short read: %d of %d\n", n, Replysz);
+		return -1;
+	}
+}
+
+/*
+ * cheezy code; just issue a inquiry.  use scuzz
+ * for real work with atapi devices
+ */
+int
+issuepkt(Req *r, Atatab *a, Dev *d)
+{
+	char *p;
+	uchar *u;
+	int n, rv;
+
+	r->haverfis = 0;
+	r->count = 128;
+	r->data = realloc(r->data, r->count);
+	if(r->data == nil && r->count > 0)
+		sysfatal("realloc: %r");
+	r->cmd.sdcmd = 0xff;
+	r->cmd.ataproto = a->protocol;
+	memset(r->cmd.fis, 0, Fissize);
+
+	u = r->cmd.fis;
+	u[0] = 0x12;
+	u[4] = 128-1;
+	displaycmd(r, a);
+
+	if(write(d->fd, &r->cmd, 6 + 2) != 6 + 2){
+		eprint("fis write error: %r\n");
+		return -1;
+	}
+	n = read(d->fd, r->data, r->count);
+	rv = 0;
+	if(n == -1){
+		eprint("xfer error: %.2ux %r\n", a->cc);
+		rv = -1;
+	}
+
+	print("n is %d (%lld)\n", n, r->count);
+	if(n > 32){
+		p = (char*)r->data;
+		print("%.8s %.16s\n", p + 8, p + 16);
+	}
+
+	u = (uchar*)&r->reply;
+	n = read(d->fd, u, Replysz);
+	if(n < 0){
+		eprint("status fis read error (%d): %r\n", n);
+		return -1;
+	}
+	
+	if(n < Replysz)
+		memset(u + n, 0, Replysz - n);
+	r->haverfis = 1;
+	return rv;
+}
+
+/*
+ * silly protocol:
+ * 1.  use write log ext 0xe0 to fill out the command
+ * 2.  use write log ext 0xe1 to write or data (if any)
+ * 3.  use read log ext 0xe0 to nab status.  polled
+ */
+void
+sctreq(Req *r)
+{
+	memset(r, 0, sizeof *r);
+	r->rfd = Dontread;
+}
+
+char*
+sctrsp(Req *r)
+{
+	uint i;
+	static char buf[32];
+
+	if(!r->haverfis)
+		return "no rfis";
+	if((r->reply.fis[Frerror] & (Eidnf | Eabrt)) == 0)
+		return nil;
+	i = r->reply.fis[Fsc] | r->reply.fis[Flba0]<<8;
+	if(i == 0xffff)
+		return "in progress";
+	else if(i == 0){
+		snprint(buf, sizeof buf, "unknown %.2ux", r->reply.fis[Frerror]);
+		return buf;
+	}else if(i < nelem(sctetab))
+		return sctetab[i];
+	else
+		return "<bad>";
+}
+
+char*
+sctready(Dev *d, int sec)
+{
+	char *s;
+	int i;
+	Req r;
+	static char e[ERRMAX];
+
+	for(;;){
+		if(interrupted){
+			s = "interrupted";
+			break;
+		}
+		sctreq(&r);
+		fisset(&r, Fsc, 1);
+		fisset(&r, Flba0, 0xe0);
+		r.count = 512;
+		i = issueata(&r, sctread, d);
+		free(r.data);
+		if(i == -1){
+			rerrstr(e, ERRMAX);
+			s = e;
+			break;
+		}
+		if((r.cmd.fis[Fsc] | r.cmd.fis[Fsc8]<<8) != 0xffff){
+			s = sctrsp(&r);
+			break;
+		}
+		if(sec == 0){
+			s = "timeout";
+			break;
+		}
+		sleep(1000);
+		sec--;
+	}
+	return s;
+}
+
+typedef struct Sttab Sttab;
+struct Sttab {
+	int	o;
+	int	sz;
+	char	*name;
+};
+
+Sttab sctt[] = {
+	0,	2,	"version",
+	2,	2,	"period",
+	4,	2,	"intval",
+	6,	1,	"max op",
+	7,	1,	"max",
+	8,	1,	"min op",
+	9,	1,	"min",
+};
+
+void
+sctttab(Req *r)
+{
+	char c, buf[10];
+	int i, n, l, d;
+	uchar *u;
+
+	u = r->data;
+	for(i = 0; i < nelem(sctt); i++){
+		switch(sctt[i].sz){
+		case 1:
+			c = u[sctt[i].o];
+			print("%s\t%d\n", sctt[i].name, c);
+			break;
+		case 2:
+			d = w(u + sctt[i].o);
+			print("%s\t%ud\n", sctt[i].name, d);
+			break;
+		}
+	}
+	n = w(u + 30);
+	l = w(u + 32);
+	for(i = 0; i < n; i++){
+		c = u[34 + (l + i) % n];
+		if((uchar)c == 0x80)
+			snprint(buf, sizeof buf, "xx");
+		else
+			snprint(buf, sizeof buf, "%d", c);
+		d = i%10;
+		if(d == 0)
+			print("\nt%d\t%d", i, c);
+		else
+			print("% .2d", c);
+	}
+	if(i%10)
+		print("\n");
+}
+
+static struct {
+	uint	code;
+	char	*s;
+	char	*ms;
+} fxtab[] = {
+	0x00010001,	"set features",	0,
+	0x00010002,	"enabled",	0,
+	0x00010003,	"disabled",	0,
+
+	0x00020001,	"enabled",	0,
+	0x00020002,	"disabled",	0,
+
+	0x0003ffff,	"minute",	"minutes",
+};
+
+void
+sctfcout(ushort *u, Req *r)
+{
+	uchar *f;
+	ushort v;
+	uint c, m, i;
+
+	f = r->reply.fis;
+	switch(u[1]){
+	case 1:
+	case 2:
+		v = f[Fsc] | f[Flba0]<<8;
+		c = u[2]<<16 | v;
+		m = u[2]<<16 | 0xffff;
+		for(i = 0; i < nelem(fxtab); i++)
+			if(fxtab[i].code == c)
+				print("%s\n", fxtab[i].s);
+			else if(fxtab[i].code == m)
+				print("%d %s\n", v, v>1? fxtab[i].ms: fxtab[i].s);
+		break;
+	case 3:
+		v = f[Fsc] | f[Flba0]<<8;
+		if(v & 1)
+			print("preserve\n");
+		else
+			print("volatile\n");
+		break;
+	}
+}
+
+void
+scterout(ushort *u, Req *r)
+{
+	uchar *f;
+	uint v;
+
+	f = r->reply.fis;
+	switch(u[1]){
+	case 2:
+		v = f[Fsc] | f[Flba0]<<8;
+		v *= 100;
+		print("%dms\n", v);
+	}
+}
+
+void
+sctout(ushort *u, Req *r)
+{
+	switch(u[0]){
+	case 5:
+		sctttab(r);
+		break;
+	case 4:
+		sctfcout(u, r);
+		break;
+	case 3:
+		scterout(u, r);
+		break;
+	}
+}
+
+int
+issuesct0(Req *r0, Atatab *a, Dev *d)
+{
+	char *s;
+	uchar proto;
+	Atatab *txa;
+	Req r;
+
+	if((d->feat & Dsct) == 0){
+		eprint("sct not supported\n");
+		return -1;
+	}
+
+	/* 1. issue command */
+	sctreq(&r);
+	r.data = malloc(r0->count);
+	memcpy(r.data, r0->data, r0->count);
+	r.count = r0->count;
+	fisset(&r, Fsc, 1);
+	fisset(&r, Flba0, 0xe0);
+	if(issueata(&r, sctissue, d) == -1)
+		return -1;
+	if(s = sctrsp(&r)){
+		eprint("sct error: %s\n", s);
+		return -1;
+	}
+
+	/* 1a. check response */
+	if((s = sctready(d, 1)) != nil){
+		eprint("sct cmd: %s\n", s);
+		return -1;
+	}
+	/* 2. transfer data */
+
+	proto = a->protocol;
+	if(r0->fisbits & 1 << 16){
+		proto &= ~Pdatam;
+		proto |= r0->cmd.ataproto;
+	}
+	switch(proto & Pdatam){
+	default:
+		txa = nil;
+		break;
+	case Pin:
+		txa = sctread;
+		break;
+/*	case Pout:
+		txa = sctout;
+		break;
+*/
+	}
+
+	if(txa != nil){
+		sctreq(&r);
+		r.count = 512;
+		fisset(&r, Fsc, 1);
+		fisset(&r, Flba0, 0xe1);
+		if(issueata(&r, txa, d) == -1)
+			return -1;
+
+		/* 2a. check response */
+		if((s = sctready(d, 1)) != nil){
+			eprint("sct cmd: %s\n", s);
+			return -1;
+		}
+	}
+
+	sctout((ushort*)r0->data, &r);
+	free(r.data);
+	return 0;
+}
+
+static void*
+pushtrace(int i)
+{
+	void *tr0;
+
+	tr0 = malloc(sizeof issuetr);
+	if(tr0 == 0)
+		return 0;
+	memcpy(tr0, issuetr, sizeof issuetr);
+	memset(issuetr, i, sizeof issuetr);
+	return tr0;
+}
+
+static void
+poptrace(void *tr0)
+{
+	if(tr0 == nil)
+		return;
+	memcpy(issuetr, tr0, sizeof issuetr);
+	free(tr0);
+}
+
+int
+issuesct(Req *r0, Atatab *a, Dev *d)
+{
+	int r;
+	void *t;
+
+	t = nil;
+	if(scttrace)
+		t = pushtrace(1);
+	r = issuesct0(r0, a, d);
+	if(scttrace)
+		poptrace(t);
+	return r;
+}
+
+int
+issue(Req *r, Atatab *a, Dev *d)
+{
+	int rv;
+	int (*f)(Req*, Atatab*, Dev*);
+
+	if(a->protocol & Psct)
+		f = issuesct;
+	else if((a->protocol & Pprotom) == Ppkt)
+		f = issuepkt;
+	else
+		f = issueata;
+	rv = f(r, a, d);
+	if(r->haverfis)
+	if(r->reply.fis[Fstatus] & ASerr){
+		werrstr("ata error");
+		rv = -1;
+	}
+	return rv;
+}
+
+void
+sigfmt(Req *r)
+{
+	print("%.8ux\n", fistosig(r->reply.fis));
+}
+
+int
+opendev(char *dev, Dev *d)
+{
+	char buf[128];
+	int rv;
+	ushort *u;
+	Req r;
+
+	if(d->fd != -1)
+		close(d->fd);
+	memset(d, 0, sizeof *d);
+	snprint(buf, sizeof buf, "%s/raw", dev);
+	d->fd = open(buf, ORDWR);
+	if(d->fd == -1)
+		return -1;
+	memset(&r, 0, sizeof r);
+	if(issue(&r, sigcmd, d) == -1){
+lose:
+		close(d->fd);
+		return -1;
+	}
+	setfissig(d, fistosig(r.reply.fis));
+	memset(&r, 0, sizeof r);
+	r.count = 512;
+	r.nsect = 1;
+	if(d->sig>>16 == 0xeb14)
+		rv = issue(&r, idpktcmd, d);
+	else
+		rv = issue(&r, idcmd, d);
+	if(rv == -1)
+		goto lose;
+	u = (ushort*)r.data;
+	d->nsect = idfeat(d, u);
+	d->secsize = idss(d, u);
+	d->wwn = idwwn(d, u);
+	return 0;
+}
+
+void
+rawout(Req *r)
+{
+	int n;
+
+	n = write(r->wfd, r->data, r->count);
+	if(n != r->count)
+		eprint("!short write %ud wanted %lld\n", n, r->count);
+}
+
+static ushort
+gbit16(void *a)
+{
+	ushort j;
+	uchar *i;
+
+	i = a;
+	j  = i[1] << 8;
+	j |= i[0];
+	return j;
+}
+
+static Btab extra[] = {
+	12,	"ncqpri",
+	11,	"ncqunload",
+	10,	"phyevent",
+	9,	"hpwrctl",
+	3,	"6.0gbit",
+	2,	"3.0gbit",
+	1,	"1.5gbit",
+};
+
+static Btab suptab[] = {
+	8,	"wwn",
+	5,	"mediaserial",
+	1,	"smartst",
+	0,	"smartlog"
+};
+
+char*
+pextraid(char *p, char *e, ushort *id, uint *medserial)
+{
+	char *p0;
+	ushort u;
+
+	*p = 0;
+	*medserial = 0;
+	p0 = p;
+	p = sebtab(p, e, extra, nelem(extra), gbit16(id + 76));
+	if(p != p0)
+		p = seprint(p, e, " ");
+	u = gbit16(id + 83);
+	if(u & 1<<5)
+		p = seprint(p, e, "gpl ");
+	p0 = p;
+	p = sebtab(p, e, suptab, nelem(suptab), gbit16(id + 84));
+	if(p != p0)
+		p = seprint(p, e, " ");
+	u = gbit16(id + 120);
+	if(u & 1<<2)
+		p = seprint(p, e, "wunc ");
+	return p;
+}
+
+static char *patatab[] = {
+	"ata8-apt",
+	"ata/atapi-7",
+};
+
+static char *satatab[] = {
+	"ata8-ast",
+	"sata1.0a",
+	"sataiiext",
+	"sata2.5",
+	"sata2.6",
+	"sata3.0",
+};
+
+char*
+ptransport(char *p, char *e, ushort *id)
+{
+	char *s;
+	ushort u, i;
+
+	u = gbit16(id + 222);
+	if(u == 0 || u == 0xffff)
+		return seprint(p, e, "unreported ");
+	i = (u>>5) & 0x7f;
+	switch(u & 7<<12){
+	default:
+		s = "unktransport";
+		break;
+	case 0:
+		s = "unkparallel";
+		if(i < nelem(patatab))
+			s = patatab[i];
+		break;
+	case 1<<12:
+		s = "unkserial";
+		if(i < nelem(satatab))
+			s = satatab[i];
+		break;
+	}
+	return seprint(p, e, "%s ", s);
+}
+
+Btab entab[] = {
+	10,	"hpa",
+	9,	"reset",
+	8,	"service",
+	7,	"release",
+	6,	"rdlookahd",
+	5,	"vwc",
+	4,	"packet",
+	3,	"pm",
+	2,	"security",
+	1,	"smart",
+};
+
+Btab addlen[] = {
+	15,	"cfast",
+//	14,	"trim",	/* check 169 */
+	13,	"lpsalignerr",
+	12,	"iddma",
+	11,	"rbufdma",
+	10,	"wbufdma",
+	9,	"pwddma",
+	8,	"dlmcdma",
+};
+
+char*
+penabled(char *p, char *e, ushort *id)
+{
+	char *p0;
+	ushort u;
+
+	p0 = p;
+	p = sebtab(p, e, addlen, nelem(addlen), gbit16(id + 69));
+	u = gbit16(id + 87);
+	if(u>>14 == 1){
+		if(p != p0)
+			p = seprint(p, e, " ");
+		p = sebtab(p, e, entab, nelem(entab), gbit16(id + 85));
+	}
+	return p;
+}
+
+static char *fftab[] = {
+	nil,
+	"5¼",
+	"3½",
+	"2½",
+	"1.8",
+	"<1.8",
+};
+
+char*
+pff(char *p, char *e, ushort *id)
+{
+	char *p0;
+	ushort u;
+
+	p0 = p;
+	u = gbit16(id + 168);
+	if(u < nelem(fftab) && fftab[u] != nil)
+		p = seprint(p, e, "%s ", fftab[u]);
+	u = gbit16(id + 217);
+	if(u == 1)
+		p = seprint(p, e, "solid-state ");
+	else if(u != 0 && u != 0xfffe)
+		p = seprint(p, e, "%udrpm ", u);
+	if(p != p0)
+		p--;
+	*p = 0;
+	return p;
+}
+
+Btab scttab[] = {
+	5,	"tables",
+	4,	"feactl",
+	3,	"errctl",
+	2,	"wsame",
+	1,	"rwlong",
+	0,	"sct",
+};
+
+char*
+psct(char *p, char *e, ushort *id)
+{
+	return sebtab(p, e, scttab, nelem(scttab), gbit16(id + 206));
+}
+
+void
+idfmt(Req *r)
+{
+	char buf[100];
+	uint ss, i;
+	ushort *id;
+	uvlong nsect;
+	Sfis f;
+
+	if(r->fmtrw == 0){
+		rawout(r);
+		return;
+	}
+	id = (ushort*)r->data;
+	nsect = idfeat(&f, id);
+	ss = idss(&f, id);
+
+	idmove(buf, id+10, 20);
+	print("serial\t%s\n", buf);
+	idmove(buf, id+23, 8);
+	print("firm\t%s\n", buf);
+	idmove(buf, id+27, 40);
+	print("model\t%s\n", buf);
+	print("wwn\t%ullx\n", idwwn(&f, id));
+	pflag(buf, buf + sizeof buf, &f);
+	print("flags\t%s", buf);
+	print("geometry %llud %ud", nsect, ss);
+	if(f.c | f.h | f.s)
+		print(" %ud %ud %ud", f.c, f.h, f.s);
+	print("\n");
+	penabled(buf, buf + sizeof buf, id);
+	print("enabled\t%s\n", buf);
+	pextraid(buf, buf + sizeof buf, id, &i);
+	print("extra\t%s\n", buf);
+	if(i){
+		idmove(buf, id + 176, 60);
+		if(buf[0] != 0)
+			print("medias\t%s\n", buf);
+	}
+	psct(buf, buf + sizeof buf, id);
+	if(buf[0])
+		print("sct\t%s\n", buf);
+	ptransport(buf, buf + sizeof buf, id);
+	print("trans\t%s\n", buf);
+	pff(buf, buf + sizeof buf, id);
+	if(buf[0])
+		print("ff\t%s\n", buf);
+}
+
+void
+smfmt(Req *r)
+{
+	uchar *fis;
+
+	if(r->cmd.fis[Ffeat] == 0xda){
+		fis = r->reply.fis;
+		if(fis[5] == 0x4f &&
+		   fis[6] == 0xc2)
+			eprint("normal\n");
+		else
+			eprint("threshold exceeded\n");
+		return;
+	}
+}
+
+void
+iofmt(Req *r)
+{
+	uchar *u;
+	int i;
+
+	if(r->fmtrw == 0){
+		rawout(r);
+		return;
+	}
+	u = r->data;
+	for(i = 0; i < r->count; i += 16)
+		fprint(2, "%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux"
+		"%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux%.2ux\n",
+		u[i + 0], u[i + 1], u[i + 2], u[i + 3], u[i + 4], u[i + 5], u[i + 6], u[i + 7],
+		u[i + 8], u[i + 9], u[i +10], u[i +11], u[i +12], u[i +13], u[i +14], u[i +15]);
+}
+
+static char *csbyte[] = {
+	"never started",
+	nil,
+	"competed without error",
+	"in progress",
+	"suspended by cmd from host",
+	"aborted by cmd from host",
+	"aborted by device with fatal error",
+};
+
+static char *exe[] = {
+	"no error or never run",
+	"aborted by host",
+	"interrupted by host",
+	"fatal error; unable to complete",
+	"failed",
+	"failed: electricial",
+	"failed: servo",
+	"failed: read",
+	"failed: shipping damage",
+[0xf]	"in progress",
+};
+
+char*
+tabtr(uint u, char **tab, int ntab)
+{
+	char *s;
+
+	if(u >= ntab || (s = tab[u]) == nil)
+		s = "reserved";
+	return s;
+}
+
+void
+sdfmt(Req *r)
+{
+	char *s;
+	uchar *b;
+	ushort u;
+
+	if(r->fmtrw == 0){
+		rawout(r);
+		return;
+	}
+	b = r->data;
+	u = b[362];
+	if((u & 0xf0) == 0x80 && u != 0x81 && u != 0x83)
+		u &= 0xf;
+	s = tabtr(u, csbyte, nelem(csbyte));
+	print("col status: %.2ux %s\n", b[362], s);
+	u = b[363];
+	s = tabtr(u>>4, exe, nelem(exe));
+	if(u & 0xf)
+		print("exe status: %.2ux %s, %d0%% left\n", u, s, u & 0xf);
+	else
+		print("exe status: %.2ux %s\n", u, s);
+	u = b[364] | b[365]<<8;
+	print("time left: %uds\n", u);
+	print("shrt poll: %udm\n", b[373]);
+	u = b[374];
+	if(u == 0xff)
+		u = b[375] | b[376]<<8;
+	print("ext poll: %udm\n", u);
+}
+
+void
+pagemapfmt(Req *r)
+{
+	int i;
+	ushort *u;
+
+	u = (ushort*)r->data;
+	if(u[0] != 1){
+		print("unsupported\n");
+		return;
+	}
+	for(i = 1; i < 128; i++)
+		if(u[i] > 0)
+			print("page %d: %d\n", i, u[i]);
+}
+
+void
+slfmt(Req *r)
+{
+	switch(r->cmd.fis[Flba0]){
+	default:
+		iofmt(r);
+		break;
+	case 0:
+		pagemapfmt(r);
+		break;
+	}
+}
+
+enum{
+	Physz	= 7<<12,
+};
+
+static char *phyec[] = {
+	"no event",
+	"icrc",
+	"err data",
+	"err d2h data",
+	"err h2d data",
+[0x05]	"err nd",
+	"err d2h nd",
+	"err h2d nd",
+	"retry d2h nd",
+	"nready",
+[0x0a]	"comreset",
+	"h2d crc",
+	nil,
+	"bad h2d",
+	nil,
+	"err h2d data crc",
+[0x10]	"err h2d data",
+	nil,
+	"err h2d nd crc",
+	"err h2d nd",
+};
+
+void
+phyfmt(Req *r)
+{
+	char *ec;
+	uchar *p;
+	ushort *u, *e, id, sz;
+
+	u = (ushort*)r->data;
+	e = u + 510/sizeof *u;
+	for(u += 2; u < e; u += sz){
+		id = w((uchar*)u);
+		sz = (id & Physz) >> 12;
+		id &= ~Physz;
+		if(sz == 0)
+			break;
+		ec = "unk";
+		if(id < nelem(phyec) && phyec[id] != nil)
+			ec = phyec[id];
+		print("%.4ux\t%-15s\t", id, ec);
+		p = (uchar*)u + 2;
+		switch(sz<<1){
+		default:
+			print("\n");
+			break;
+		case 2:
+			print("%.4ux\n", w(p));
+			break;
+		case 4:
+			print("%.8ux\n", dw(p));
+			break;
+		case 8:
+			print("%.16llux\n", qw(p));
+			break;
+		}
+		sz += 1;
+	}
+}
+
+typedef struct Gltab Gltab;
+struct Gltab{
+	int	offset;
+	char	*name;
+};
+
+Gltab page3[] = {
+	8,	"power-on hrs",
+	16,	"head flying hrs",
+	24,	"head loads",
+	32,	"realloc'd sec",
+	40,	"read recovery att",
+	48,	"start failures"
+};
+	
+void
+qpfmt(Req *r, Gltab *t, int ntab)
+{
+	uchar *u;
+	int i;
+	uvlong v;
+
+	u = r->data;
+	for(i = 0; i < ntab; i++){
+		v = qw(u + t[i].offset);
+		if((v & 3ll<<63) != 3ll<<63)
+			continue;
+		print("%lud\t%s\n", (ulong)v, t[i].name);
+	}
+}
+
+static char *sctsttab[] = {
+	"active waiting",
+	"standby",
+	"sleep",
+	"dst bgnd",
+	"smart bgnd",
+	"sct bgnd",
+};
+
+void
+sctstatfmt(Req *r)
+{
+	char *s;
+	uchar *id, c;
+
+	id = r->data;
+	print("version\t%d\n", gbit16(id + 0));
+	print("vnd ver\t%2ux\n", gbit16(id + 2));
+	print("flags\t%.8ux\n", dw(id + 6));
+	c = id[10];
+	s = "unk";
+	if(c < nelem(sctsttab))
+		s = sctsttab[c];
+	print("state\t%s\n", s);
+	print("ext stat\t%.4ux\n", gbit16(id + 14));
+	print("act code\t%.4ux\n", gbit16(id + 16));
+	print("fn code\t%.4ux\n", gbit16(id + 18));
+	print("lba\t%llud\n", qw(id + 40));
+	print("temp\t%d\n", id[200]);
+	print("min t\t%d %d\n", id[201], id[203]);
+	print("max t\t%d %d\n", id[202], id[204]);
+	print("ot\t%d\n", dw(id + 206));
+	print("ut\t%d\n", dw(id + 210));
+}
+
+
+void
+glfmt(Req *r)
+{
+	switch(r->cmd.fis[Flba0]){
+	case 0:
+		pagemapfmt(r);
+		break;
+	case 3:
+		qpfmt(r, page3, nelem(page3));
+		break;
+	case 17:
+		phyfmt(r);
+		break;
+	case 0xe0:
+		sctstatfmt(r);
+		break;
+	default:
+		iofmt(r);
+		break;
+	}
+}
+
+char*
+readline(char *prompt, char *line, int len)
+{
+	char *p, *e, *q;
+	int n, dump;
+
+	e = line + len;
+retry:
+	dump = 0;
+	if(interrupted)
+		eprint("\n%s", prompt);
+	else
+		eprint("%s", prompt);
+	interrupted = 0;
+	for(p = line;; p += n){
+		if(p == e){
+			dump = 1;
+			p = line;
+		}
+		n = read(0, p, e - p);
+		if(n < 0){
+			if(interrupted)
+				goto retry;
+			return nil;
+		}
+		if(n == 0)
+			return nil;
+		if(q = memchr(p, '\n', n)){
+			if(dump){
+				eprint("!line too long\n");
+				goto retry;
+			}
+			p = q;
+			break;
+		}
+	}
+	*p = 0;
+	return line;
+}
+
+void
+suggesttab(char *cmd, Atatab *a, int n)
+{
+	int i, l;
+
+	l = strlen(cmd);
+	for(i = 0; i < n; i++)
+		if(cistrncmp(cmd, a[i].name, l) == 0)
+			eprint("%s\n", a[i].name);
+}
+
+Atatab*
+findtab(char **cmd, Atatab *a, int n)
+{
+	char *p, *c;
+	int i, cc, max, l;
+
+	cc = strtoul(*cmd, &p, 0);
+	if(p != *cmd && (*p == 0 || *p == ' ')){
+		for(i = 0; i < n; i++)
+			if(a[i].cc == cc){
+				*cmd = p + 1;
+				return a + cc;
+			}
+		return 0;
+	}
+	max = 0;
+	cc = 0;
+	c = *cmd;
+	for(i = 0; i < n; i++){
+		l = strlen(a[i].name);
+		if(l > max && cistrncmp(*cmd, a[i].name, l) == 0)
+		if(c[l] == ' ' || c[l] == 0){
+			max = l + (c[l] == ' ');
+			cc = i;
+		}
+	}
+	if(max > 0){
+		*cmd = *cmd + max;
+		return a + cc;
+	}
+	return 0;
+}
+		
+int
+catch(void*, char *note)
+{
+	if(strstr(note, "interrupt") != nil)
+		return interrupted = 1;
+	return 0;
+}
+
+char**
+ndargs(Atatab*, Req *, char **p)
+{
+	return p;
+}
+
+char**
+ioargs(Atatab *, Req *r, char **p)
+{
+	if(r->nsect == 0)
+		r->nsect = 1;
+	if(p[0] == 0)
+		return p;
+	r->lba = strtoull(p[0], 0, 0);
+	p++;
+	if(p[0] == 0)
+		return p;
+	r->nsect = strtoul(p[0], 0, 0);
+	return p + 1;
+}
+
+char**
+stdargs(Atatab *, Req *r, char **p)
+{
+	char *s;
+	Rune x;
+
+	for(; p[0] && p[0][0] == '-' && p[0][1]; p++){
+		s = p[0] + 1;
+		if(*s == '-'){
+			p++;
+			break;
+		}
+		while(*s && (s += chartorune(&x, s)))
+		switch(x){
+		case 'r':
+			r->raw = 1;
+			break;
+		default:
+			return p;
+		}
+	}
+	return p;
+}
+
+static void
+chopoff(char *s, char *extra)
+{
+	char *p;
+	int l, ls;
+
+	l = strlen(extra);
+	ls = strlen(s);
+	if(l >= ls)
+		return;
+	p = s + ls - l;
+	if(strcmp(p, extra) == 0)
+		*p = 0;
+}
+
+char*
+trim(char *s)
+{
+	char *p;
+
+	while(*s && (*s == ' ' || *s == '\t'))
+		s++;
+	if(*s == 0)
+		return nil;
+	p = s + strlen(s) - 1;
+	while(*p == ' ' || *p == '\t')
+		p--;
+	p[1] = 0;
+	return s;
+}
+
+int
+doredir(Req *r, char **f, int nf, int mode, int *fd1, int *fd2)
+{
+	int fd;
+
+	if(nf != 1 && nf != 2){
+		eprint("!args\n");
+		return -1;
+	}
+	fd = -1;
+	if(nf == 2){
+		fd = open(f[1], mode);
+		if(mode != OREAD){
+			if(fd == -1)
+				fd = create(f[1], mode, 0660);
+			else
+				seek(fd, 0, 2);
+		}
+	}
+	if(fd1){
+		close(*fd1);
+		*fd1 = fd;
+	}
+	if(fd2){
+		r->fmtrw = fd == -1;
+		close(*fd2);
+		*fd2 = fd;
+	}
+	return fd;
+}
+
+int
+special(char *s, Dev *d, Req *r)
+{
+	char buf[512], path[128], *f[20], sbuf[512], s2[512], *p, *e, *t;
+	uchar *u;
+	int i, j, nf;
+	Atatab *a;
+
+	p = buf;
+	e = buf + sizeof buf;
+	if(!strcmp(s, "close")){
+		r->haverfis = 0;
+		close(d->fd);
+		d->fd = -1;
+		return 0;
+	}
+	if(!strcmp(s, "scttrace")){
+		scttrace = 1;
+		return 0;
+	}
+	if(!strcmp(s, "dev")){
+		if(d->fd == -1){
+			eprint("!bad cmd (device closed)\n");
+			return 0;
+		}
+		if(fd2path(d->fd, path, sizeof path) == -1)
+			sysfatal("fd2path: %r");
+		chopoff(path, "/raw");
+		p = seprint(p, e, "dev\t%s\n", path);
+		p = seprint(p, e, "flags\t");
+		p = pflag(p, e, d);
+		p = seprint(p, e, "lsectsz\t" "%ud ptol %ud\n", d->lsectsz, 1<<d->physshift);
+		p = seprint(p, e, "geometry %llud %ud\n", d->nsect, d->secsize);
+		if(d->c | d->h | d->s)
+			seprint(p, e, "chs\t%d %d %d\n", d->c, d->h, d->s);
+		print("%s", buf);
+		return 0;
+	}
+	if(!strcmp(s, "help")){
+		suggesttab(buf, atatab, nelem(atatab));
+		return 0;
+	}
+	if(!strcmp(s, "probe")){
+		probe();
+		return 0;
+	}
+	if(!strcmp(s, "rfis")){
+		if(r->haverfis == 0){
+			eprint("!no rfis\n");
+			return 0;
+		}
+		p = seprint(p, e, "%.2x\n", r->reply.sdcmd);
+		u = r->reply.fis;
+		for(i = 0; i < 16; i++)
+			p = seprint(p, e, "%.2ux", u[i]);
+		seprint(p, e, "\n");
+		print("%s", buf);
+		return 0;
+	}
+	for(t = s; *t == '<' || *t == '>'; t++)
+		;
+	if(t != s)
+		snprint(sbuf, sizeof buf, "%.*s %s", (int)(t - s), s, t);
+	else
+		snprint(sbuf, sizeof sbuf, "%s", s);
+	nf = tokenize(sbuf, f, nelem(f));
+	if(!strcmp(f[0], "issuetr")){
+		if(nf == 1)
+			for(i = 0; i < nelem(issuetr); i++)
+				issuetr[i] ^= 1;
+		else{
+			p = s2;
+			e = s2 + sizeof s2;
+			for(i = 1; i < nf - 1; i++)
+				p = seprint(p, e, "%s ", f[i]);
+			p = seprint(p, e, "%s", f[i]);
+			e = s2;
+			for(i = 1; i < nf; i++){
+				j = strtoul(f[i], &p, 0);
+				if(*p == 0 && j < nelem(issuetr))
+					issuetr[i] ^= 1;
+				else if(a = findtab(&e, atatab, nelem(atatab)))
+					issuetr[a->cc & 0xff] ^= 1;
+			}
+		}
+		return 0;
+	}
+	if(!strcmp(f[0], "open")){
+		r->lba = 0;
+		if(nf == 2)
+			opendev(f[1], d);
+		else
+			eprint("!bad args to open\n");
+		return 0;
+	}
+	if(!strcmp(f[0], ">")){
+		doredir(r, f, nf, OWRITE, 0, &r->wfd);
+		return 0;
+	}
+	if(!strcmp(f[0], "<")){
+		doredir(r, f, nf, OREAD, &r->rfd, 0);
+		return 0;
+	}
+	if(!strcmp(f[0], "<>")){
+		doredir(r, f, nf, OWRITE, &r->rfd, &r->wfd);
+		return 0;
+	}
+	return -1;
+}
+
+static char *regtab[] = {
+	"Ftype",
+	"Fflags",
+	"Fcmd",
+	"Ffeat",
+	"Flba0",
+	"Flba8",
+	"Flba16",
+	"Fdev",
+	"Flba24",
+	"Flba32",
+	"Flba40",
+	"Ffeat8",
+	"Fsc",
+	"Fsc8",
+	"Fr",
+	"Fcontrol",
+};
+
+void
+setreg(Req *r, uint reg, uvlong v)
+{
+	uchar *o;
+	int x;
+
+	switch(reg & (Sbase | Pbase)){
+	case 0:
+		r->fisbits |= 1 << reg;
+		r->cmd.fis[reg] = v;
+//	print("%s: %.2ux\n", regtab[reg], (uchar)v);
+		break;
+	case Sbase:
+	case Sbase | Pbase:
+		x = reg & ~(Sbase | Ssz);
+		o = r->data + x*2;
+		assert(x < r->count);
+		switch(reg & Ssz){
+		default:
+			print("reg & Ssz %ux\n", reg & Ssz);
+			_assert("bad table");
+		case Sw:
+			pw(o, v);
+			break;
+		case Sdw:
+			pdw(o, v);
+			break;
+		case Sqw:
+			pqw(o, v);
+			break;
+		}
+		break;
+	case Pbase:
+		/* fix me please: this is teh suck */
+		r->fisbits |= 1 << 16;
+		r->cmd.ataproto = v;
+		break;
+	}
+}
+
+int
+setfis0(Req *r, Txtab *t, char *p)
+{
+	char *e;
+	uvlong v;
+
+	v = strtoull(p, &e, 0);
+	setreg(r, t->val, v);
+	return *e != 0;
+}
+
+char**
+setfis(Atatab*, Req *r, char **p)
+{
+	char *s;
+	int i;
+
+loop:
+	if((s = p[0]) == 0)
+		return p;
+	for(i = 0; i < nelem(regtx); i++)
+		if(strcmp(s, regtx[i].name) == 0 && p[1] != nil){
+//			print("setfis0 %s %s\n", p[0], p[1]);
+			setfis0(r, regtx + i, p[1]);
+			p += 2;
+			goto loop;
+		}
+	return p;
+}
+
+char*
+rname(char *buf, int n, int r)
+{
+	int i;
+
+	for(i = 0; i < nelem(regtx); i++)
+		if(regtx[i].val == r){
+			snprint(buf, n, "%s", regtx[i].name);
+			return buf;
+		}
+	snprint(buf, n, "%.2ux", r);
+	return buf;
+}
+
+int
+mwcmp(char *a, char ***l)
+{
+	char buf[128], *f[20], **p;
+	int nf, i;
+
+	if(*a == 0)
+		return 0;
+	p = *l;
+	if(p[0] == 0)
+		return -1;
+	snprint(buf, sizeof buf, "%s", a);
+	nf = tokenize(buf, f, nelem(f));
+	for(i = 0; i < nf; i++)
+		if(p[i] == nil || cistrcmp(p[i], f[i]) != 0)
+			return -1;
+	*l = p + i - 1;
+	return 0;
+}
+
+char **dofetab(Fetab*, Req*, char**);
+
+static char hexdig[] = "ABCDEFabcdef0123456789";
+static char hexonly[] = "ABCDEFabcdef";
+static char Enum[] = "expecting number";
+
+int
+fenum(Fetab *, int v, char ***p)
+{
+	char *e, *s, *r;
+	int base;
+
+	if(v >= 0)
+		return v;
+	s = *(*p + 1);
+	e = nil;
+	if(s == nil || *s == 0)
+		e = Enum;
+	else{
+		base = 0;
+		if(strspn(s, hexdig) == strlen(s) &&
+		strpbrk(s, hexonly) != nil)
+			base = 0x10;
+		v = strtoul(s, &r, base);
+		if(*r)
+			e = Enum;
+	}
+	if(e == nil)
+		(*p)++;
+	else
+		print("error: %s [%s]\n", e, s);
+	return v;
+}
+
+char**
+dofetab0(Fetab *t, Req *r, char **p)
+{
+	int i, v;
+	Txtab *tab;
+
+	if(t == nil)
+		return p;
+	tab = t->tab;
+loop:
+	for(i = 0; i < t->ntab; i++)
+		if(mwcmp(tab[i].name, &p) == 0){
+			v = fenum(t, tab[i].val, &p);
+			setreg(r, t->reg, v);
+			if(tab[i].name[0] != 0){
+				p = dofetab(tab[i].fe, r, p + 1);
+				goto loop;
+			}
+		}
+	return p;
+
+}
+
+char**
+dofetab(Fetab *t, Req *r, char **p)
+{
+	for(; t != nil && t->ntab > 0; t++)
+		p = dofetab0(t, r, p);
+	return p;
+}
+
+char**
+dotab(Atatab *a, Req *r, char **p)
+{
+	if(a->tab == nil)
+		return p;
+	return dofetab(a->tab, r, p);
+}
+
+void
+initreq(Req *r)
+{
+	memset(r, 0, sizeof *r);
+//	r->wfd = open("/dev/null", OWRITE);
+	r->wfd = dup(1, -1);
+	if(rflag == 0)
+		r->fmtrw = 1;
+	r->rfd = open("/dev/zero", OREAD);
+}
+
+void
+setup(void)
+{
+	int i;
+
+	for(i = 0; i < nelem(atatab); i++)
+		if(atatab[i].cc == 0x2f){
+			sctread = atatab + i;
+			break;
+		}
+	for(; i < nelem(atatab); i++)
+		if(atatab[i].cc == 0x3f){
+			sctissue = atatab + i;
+			break;
+		}
+	for(; i < nelem(atatab); i++)
+		if(atatab[i].cc == 0xa1){
+			idpktcmd = atatab + i;
+			break;
+		}
+	for(; i < nelem(atatab); i++)
+		if(atatab[i].cc == 0xec){
+			idcmd = atatab + i;
+			break;
+		}
+	for(; i < nelem(atatab); i++)
+		if(atatab[i].cc == 0xf000){
+			sigcmd = atatab + i;
+			break;
+		}
+}
+
+typedef struct Htab Htab;
+struct Htab {
+	ulong	bit;
+	char	*name;
+};
+
+Htab ertab[] = {
+	Eicrc,	"icrc",
+	Ewp,	"wp",
+	Emc,	"mc",
+	Eidnf,	"idnf",
+	Emcr,	"mcr",
+	Eabrt,	"abrt",
+	Enm,	"nm",
+	Emed,	"med",
+	Eunc,	"unc",
+};
+
+Htab sttab[] = {
+	ASbsy,	"bsy",
+	ASdrdy,	"drdy",
+	ASdf,	"df",
+	ASdrq,	"drq",
+	ASerr,	"err",
+};
+
+static char*
+htabfmt(char *p, char *e, Htab *t, int n, ulong u)
+{
+	char *p0;
+	uint i;
+
+	p0 = p;
+	for(i = 0; i < n; i++)
+		if(u & t[i].bit)
+			p = seprint(p, e, "%s | ", t[i].name);
+	if(p - 3 >= p0)
+		p -= 3;
+	if(p < e)
+		p[0] = 0;
+	return p;
+}
+
+void
+prerror(Req *r)
+{
+	char st[64], er[64];
+	uchar *u;
+
+	u = r->reply.fis;
+	if(r->haverfis == 0 ||  (u[Fstatus] & ASerr) == 0)
+		return;
+	htabfmt(er, er + sizeof er, ertab, nelem(ertab), u[Frerror]);
+	htabfmt(st, st + sizeof st, sttab, nelem(sttab), u[Fstatus] & ~ASobs);
+	fprint(2, "err %.2ux %.2ux (%s, %s)\n", u[Frerror], u[Fstatus], er, st);
+}
+
+void
+usage(void)
+{
+	eprint("usage: atazz dev\n");
+	eprint(" or -c cmd\n");
+	exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+	char buf[1024], *p, *f[20], **fp;
+	int nf, cflag, i;
+	Atatab *a;
+	Req r;
+	Dev d;
+
+	cflag = 0;
+	ARGBEGIN{
+	case 'c':
+		cflag = atoi(EARGF(usage()));
+		break;
+	case 'r':
+		rflag = 1;
+		break;
+	default:
+		usage();
+	}ARGEND
+
+	if(cflag){
+		for(i = 0; i < nelem(atatab); i++)
+			if(atatab[i].cc == cflag)
+				print("%s\n", atatab[i].name);
+		exits("");
+	}
+
+	setup();
+	fmtinstall(L'π', πfmt);
+	if(argc > 1)
+		usage();
+	initreq(&r);
+	d.fd = -1;
+	if(argc == 1 && opendev(*argv, &d) == -1)
+		sysfatal("opendev: %r");
+	atnotify(catch, 1);
+	for(;;){
+		memset(&r.cmd, 0, sizeof r.cmd);
+		r.fisbits = 0;
+		if(readline("az> ", buf, sizeof buf-1) == nil)
+			break;
+		if((p = trim(buf)) == nil)
+			continue;
+		if(special(buf, &d, &r) == 0)
+			continue;
+		if(d.fd == -1){
+			eprint("!bad cmd (device closed)\n");
+			continue;
+		}
+		a = findtab(&p, atatab, nelem(atatab));
+		if(!a){
+			suggesttab(buf, atatab, nelem(atatab));
+			eprint("!unknown cmd\n");
+			continue;
+		}
+		nf = tokenize(p, f, nelem(f) - 1);
+		f[nf] = 0;
+		fp = stdargs(a, &r, f);
+		fp = setfis(a, &r, fp);
+		if(a->protocol & Psct){
+			r.count = 1 * 512;
+			r.data = realloc(r.data, r.count);
+			memset(r.data, 0, r.count);
+		}
+		fp = dotab(a, &r, fp);
+		switch(a->protocol & Pprotom){
+		default:
+			eprint("!bad proto1 %.2ux\n", a->protocol & Pprotom);
+			continue;
+		case Pnd:
+			fp = ndargs(a, &r, fp);
+		case Preset:
+		case Pdiag:
+			r.count = 0;
+			r.lba = 0;
+			r.nsect = 0;
+			break;
+		case Ppio:
+		case Pdma:
+		case Pdmq:
+		case Ppkt:
+			if(a->flags & Cmd5sc){
+				r.nsect = r.cmd.fis[Fsc];
+				if(r.nsect == 0)
+					r.nsect = 1;
+				r.cmd.fis[Fsc] = r.nsect;
+				r.count = r.nsect * 0x200;
+			}else if((a->protocol & Pssm) == P512){
+				r.lba = 0;
+				r.nsect = 0;
+				r.count = 512;
+			}else{
+				fp = ioargs(a, &r, fp);
+				r.count = d.secsize * r.nsect;
+			}
+			break;
+		}
+		if(fp[0]){
+			eprint("!extra args %π\n", fp);
+			continue;
+		}
+		if(issue(&r, a, &d) == -1){
+			prerror(&r);
+			continue;
+		}
+		if(a->fmt)
+			a->fmt(&r);
+	}
+	exits("");
+}
--- /dev/null
+++ b/sys/src/cmd/atazz/mkfile
@@ -1,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
--- /dev/null
+++ b/sys/src/cmd/atazz/probe.c
@@ -1,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;
+}
--- /dev/null
+++ b/sys/src/cmd/atazz/sctnotes
@@ -1,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
--- /dev/null
+++ b/sys/src/cmd/atazz/smartnotes
@@ -1,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 "
--- /dev/null
+++ b/sys/src/cmd/atazz/tabs.h
@@ -1,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",
+};