setfissig, txmodefis, atapirwfis, featfis, flushcachefis, identifyfis, nopfis, rwfis, skelfis, sigtofis, fiswr, fisrw, id16, id32, id64, idmove, idfeat, idwwn, idss, idpuis, pflag, fistosig, sasbhash, sashash – SATA/SAS FIS and drive feature functions


#include <u.h>
#include <libc.h>
#include <fis.h>
enum {
Fissize    = 0x20,      /* nominal (fits all) fis size */
Dlba       = 1<<0,
Dllba      = 1<<1,
Dsmart     = 1<<2,
Dpower     = 1<<3,
Dnop       = 1<<4,
Datapi     = 1<<5,
Datapi16 = 1<<6,
Data8      = 1<<7,
Dsct       = 1<<8,
enum {
Pspinup    = 1<<0,
Pidready = 1<<1,
struct Sfis {
ushort     feat;        /* features supportd */
uchar      udma;        /* modes supported */
uchar      speeds;      /* sata: allowed speeds */
uint       sectsz;      /* sector size */
uint       phystol;     /* log2(logical/physical) */
uint       sig;         /* signature */
uint       c;           /* cylinder */
uint       h;           /* head */
uint       s;           /* sector */
void     setfissig(Sfis *sfis, uint sig)
int      txmodefis(Sfis *sfis, uchar *fis, uchar mode)
int      featfis(Sfis *sfis, uchar *fis, uchar feat)
int      flushcachefis(Sfis *sfis, uchar *fis)
int      identifyfis(Sfis *sfis, uchar *fis)
int      nopfis(Sfis *sfis, uchar *fis, int srst)
int      fisrw(Sfis *f, uchar *fis, int *count)
int      rwfis(Sfis *sfis, uchar *fis, int rw, int nsect, uvlong lba)
int      atapirwfis(Sfis *sfis, uchar *fis, uchar *cdb, int cdblen, int ndata)
void     skelfis(uchar *fis)
void     sigtofis(Sfis *sfis, uchar *d2hfis)
uvlong fisrw(Sfis *sfis, uchar *fis, int *nsect)
ushort id16(ushort *id, int idx)
uint     id32(ushort *id, int idx)
uvlong id64(ushort *id, int idx)
void     idmove(char *buf, ushort *ididx, int n)
vlong    idfeat(Sfis *sfis, ushort *id)
uvlong idwwn(Sfis*, ushort *id)
int      idss(Sfis *sfis, ushort *id)
int      idpuis(ushort *id)
char     *pflag(char *p, char *e, Sfis *sbis)
uint     fistosig(uchar *fis)
uint     sashash(uvlong u)
uchar* sasbhash(uchar *t, uchar *s)


The Sfis type describes the connection between an ATA drive and a Host Bus Adaptor (HBA). The details of this connection, such as DMA and LBA support, and the logcal sectors per physical sector are used to construct the proper SATA FISes.
Since ATA uses a seperate sector size for addressing (the logical sector size) and for ECC calculations (the physical sector size), the library returns values based on the physical sector size. This allows clients to make intelligent decisions about IO size without worrying about this implementation botch.
feat    selected features supported by the drive. Set by idfeat.
udma    the UDMA modes supported by the drive. Set by idfeat.
speedsbitmaped signaling speeds supported by the device. SATA drives may support 1.5gbit/s, 3.0gbit/s and 6.0gbit/s signaling.
sig     this field contains the drive's “signature.” Drives that support the packet command set have a signature of 0xeb140000, while conventional drives have a signature of 0x0101. The signature is set by setfissig. See sd(3) for more information.
c, h, s   the number of physical or logical cylinders, heads and sectors claimed by the drive. CHS addressing is not allowed by SATA drivers. Set by idfeat.
Typically, a client starts by filling out sfis–>sig. Device drivers typically have an ideosyncratic method of obtaining a signature. Clients of sd(3) can use special commands to obtain a signature. Given a signature the client can use identifyfis to identify the device and finally idfeat, idss and idwwn to fill out the structure and extract the maximum LBA+1 and the sector size.
The xtofis functions create FISes to be sent from the host to the device. These are called H2D or Host to Device Register FISes. All require a fis buffer of at least Fislen bytes. The return value is the ATA protocol of the returned command. For example, identifyfis returns Pin|Ppio|P28|P512. setfissig(sfis, sig)
sets the device's ATA signature.
identifyfis(sfis, fis)
builds an ATA IDENTIFY DEVICE or IDENTIFY PACKET DEVICE FIS, based on sfis–>sig.
id16(id, idx), id32, id64
return id word, double–world or quad–word at position idx.
idss(sfis, id)
return the physical sector size of the disk. The physical sector size is the quanta protected by ECC and is never smaller than the logical sector size, which is used in LBA calcuations.
checks for PUIS (power up in standby) modes. Invalid id blocks return –1. Otherwise Pspinup is set if the drive needs SET FEATURES subcommand 7 to return complete data and Pidready bit set if the id block is complete. Both or neither bits may be set.
idfeat(sfis, id)
parses the 512–byte data block returned by the identify commands. On success, the last LBA+1 is returned. Unparseable or unsupportable data blocks return –1. Flags may be converted to a descriptive string with pflag. Idss and idwwn return the sector size and World Wide Name from the same data.
idmove(buf, ididx, n)
converts an ATA string of length n into a null–terminated string. Trailing spaces are deleted.
converts a D2H FIS into a device signature.
txmodefis(sfis, fis, mode)
featfis(sfis, fis, feat)
flushcachefis(sfis, fis)
nopfis(sfis, fis, srst)
builds a NOP FIS. If srst is set, then out–of–band signaling is used to request a soft reset. It is not expected that srst will be useful outside of device drivers.
rwfis(sfis, fis, rw, nsect, lba)
generates a FIS requesting an nsect i/o at lba. If rw is non–zero, then a write is requested otherwise a read is requested. The correct command to issue is determined by sfis . DMA and 48–bit (LLBA) commands are preferred. The inverse is fisrw which returns the lba and nsect given a FIS generated by rwfis.
atapirwfis(sfis, fis, cdb, cdlen, ndata)
generates an ATAPI read or write FIS. The cdb contains a cdblen–byte SCSI Command Data Block describing an nbyte–byte i/o operation.
builds a skeleton Host–to–Device (H2D) Register FIS. Fis must be a buffer of at least Fislen bytes.
The fistox functions create FISes to be sent from the device to the host. These are called D2H or Device to Host Register FISes and are used to generate faux responses where actual communication with a device would be desirable. All require a fis buffer of at least Fislen bytes.
sigtofis(sfis, d2hfis)
builds a device signature fis from based on a device's sfis.
generates a 4–byte hashed SAS address from an 8 byte WWN.
sasbhash(sasaddr, wwn)
fills the buffer sasaddr with the hashed SAS addresse from the 8 byte buffer wwn.
sigtofis(sfis, d2hfis)




atazz(8), sd(3), sdahci(3), sdodin(3), smart(8)


Support for CHS–style addressing is somewhat weak. In particular, rwfis does not do the usual LBA–to–CHS transations. This is done by drivers that support CHS addressing. Currently this is only the IDE driver.
The Sfis structure arguably could contain the LBA size, it is required for the correct construction of FISes.