2016-11-25 17:18:40 +01:00
|
|
|
/*
|
|
|
|
* sata fises and sas frames
|
|
|
|
* copyright © 2009-2010 erik quanstrom
|
|
|
|
*/
|
|
|
|
#include "u.h"
|
|
|
|
#include "../port/lib.h"
|
|
|
|
#include "fis.h"
|
|
|
|
|
|
|
|
static char *flagname[9] = {
|
|
|
|
"lba",
|
|
|
|
"llba",
|
|
|
|
"smart",
|
|
|
|
"power",
|
|
|
|
"nop",
|
|
|
|
"atapi",
|
|
|
|
"atapi16",
|
|
|
|
"ata8",
|
|
|
|
"sct",
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ata8 standard (llba) cmd layout
|
|
|
|
*
|
|
|
|
* feature 16 bits
|
|
|
|
* count 16 bits
|
|
|
|
* lba 48 bits
|
|
|
|
* device 8 bits
|
|
|
|
* command 8 bits
|
|
|
|
*
|
|
|
|
* response:
|
|
|
|
*
|
|
|
|
* status 8 bits
|
|
|
|
* error 8 bits
|
|
|
|
* reason 8 bits
|
|
|
|
* count 8 bits
|
|
|
|
* sstatus 8 bits
|
|
|
|
* sactive 8 bits
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* sata fis layout for fistype 0x27: host-to-device:
|
|
|
|
*
|
|
|
|
* 0 fistype
|
|
|
|
* 1 fis flags
|
|
|
|
* 2 ata command
|
|
|
|
* 3 features
|
|
|
|
* 4 sector lba low 7:0
|
|
|
|
* 5 cyl low lba mid 15:8
|
|
|
|
* 6 cyl hi lba hi 23:16
|
|
|
|
* 7 device / head
|
|
|
|
* 8 sec exp lba 31:24
|
|
|
|
* 9 cy low e lba 39:32
|
|
|
|
* 10 cy hi e lba 48:40
|
|
|
|
* 11 features (exp)
|
|
|
|
* 12 sector count
|
|
|
|
* 13 sector count (exp)
|
|
|
|
* 14 r
|
|
|
|
* 15 control
|
|
|
|
*/
|
|
|
|
|
|
|
|
void
|
|
|
|
setfissig(Sfis *x, uint32_t sig)
|
|
|
|
{
|
|
|
|
x->sig = sig;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
skelfis(uint8_t *c)
|
|
|
|
{
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_memset(c, 0, Fissize);
|
2016-11-25 17:18:40 +01:00
|
|
|
c[Ftype] = H2dev;
|
|
|
|
c[Fflags] = Fiscmd;
|
|
|
|
c[Fdev] = Ataobs;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
nopfis(Sfis*, uint8_t *c, int srst)
|
|
|
|
{
|
|
|
|
skelfis(c);
|
|
|
|
if(srst){
|
|
|
|
c[Fflags] &= ~Fiscmd;
|
|
|
|
c[Fcontrol] = 1<<2;
|
|
|
|
return Preset|P28;
|
|
|
|
}
|
|
|
|
return Pnd|P28;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
txmodefis(Sfis *f, uint8_t *c, uint8_t d)
|
|
|
|
{
|
|
|
|
int m;
|
|
|
|
|
|
|
|
/* hack */
|
|
|
|
if((f->sig >> 16) == 0xeb14)
|
|
|
|
return -1;
|
|
|
|
m = 0x40;
|
|
|
|
if(d == 0xff){
|
|
|
|
d = 0;
|
|
|
|
m = 0;
|
|
|
|
}
|
|
|
|
skelfis(c);
|
|
|
|
c[Fcmd] = 0xef;
|
|
|
|
c[Ffeat] = 3; /* set transfer mode */
|
|
|
|
c[Fsc] = m | d; /* sector count */
|
|
|
|
return Pnd|P28;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
featfis(Sfis*, uint8_t *c, uint8_t f)
|
|
|
|
{
|
|
|
|
skelfis(c);
|
|
|
|
c[Fcmd] = 0xef;
|
|
|
|
c[Ffeat] = f;
|
|
|
|
return Pnd|P28;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
identifyfis(Sfis *f, uint8_t *c)
|
|
|
|
{
|
|
|
|
static uint8_t tab[] = { 0xec, 0xa1, };
|
|
|
|
|
|
|
|
skelfis(c);
|
|
|
|
c[Fcmd] = tab[f->sig>>16 == 0xeb14];
|
|
|
|
return Pin|Ppio|P28|P512;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
flushcachefis(Sfis *f, uint8_t *c)
|
|
|
|
{
|
|
|
|
static uint8_t tab[2] = {0xe7, 0xea};
|
|
|
|
static uint8_t ptab[2] = {Pnd|P28, Pnd|P48};
|
|
|
|
int llba;
|
|
|
|
|
|
|
|
llba = (f->feat & Dllba) != 0;
|
|
|
|
skelfis(c);
|
|
|
|
c[Fcmd] = tab[llba];
|
|
|
|
return ptab[llba];
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint16_t
|
|
|
|
gbit16(void *a)
|
|
|
|
{
|
|
|
|
uint16_t j;
|
|
|
|
uint8_t *i;
|
|
|
|
|
|
|
|
i = a;
|
|
|
|
j = i[1] << 8;
|
|
|
|
j |= i[0];
|
|
|
|
return j;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
gbit32(void *a)
|
|
|
|
{
|
|
|
|
uint32_t j;
|
|
|
|
uint8_t *i;
|
|
|
|
|
|
|
|
i = a;
|
|
|
|
j = i[3] << 24;
|
|
|
|
j |= i[2] << 16;
|
|
|
|
j |= i[1] << 8;
|
|
|
|
j |= i[0];
|
|
|
|
return j;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint64_t
|
|
|
|
gbit64(void *a)
|
|
|
|
{
|
|
|
|
uint8_t *i;
|
|
|
|
|
|
|
|
i = a;
|
|
|
|
return (uint64_t)gbit32(i+4) << 32 | gbit32(a);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint16_t
|
|
|
|
id16(uint16_t *id, int i)
|
|
|
|
{
|
|
|
|
return gbit16(id+i);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t
|
|
|
|
id32(uint16_t *id, int i)
|
|
|
|
{
|
|
|
|
return gbit32(id+i);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t
|
|
|
|
id64(uint16_t *id, int i)
|
|
|
|
{
|
|
|
|
return gbit64(id+i);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* acs-2 §7.18.7.4 */
|
|
|
|
static uint16_t puistab[] = {
|
|
|
|
0x37c8, Pspinup,
|
|
|
|
0x738c, Pspinup | Pidready,
|
|
|
|
0x8c73, 0,
|
|
|
|
0xc837, Pidready,
|
|
|
|
};
|
|
|
|
|
|
|
|
int
|
|
|
|
idpuis(uint16_t *id)
|
|
|
|
{
|
|
|
|
uint16_t u, i;
|
|
|
|
|
|
|
|
u = gbit16(id + 2);
|
|
|
|
for(i = 0; i < nelem(puistab); i += 2)
|
|
|
|
if(u == puistab[i])
|
|
|
|
return puistab[i + 1];
|
|
|
|
return Pidready; /* annoying cdroms */
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint16_t
|
|
|
|
onesc(uint16_t *id)
|
|
|
|
{
|
|
|
|
uint16_t u;
|
|
|
|
|
|
|
|
u = gbit16(id);
|
|
|
|
if(u == 0xffff)
|
|
|
|
u = 0;
|
|
|
|
return u;
|
|
|
|
}
|
|
|
|
|
|
|
|
enum{
|
|
|
|
Idmasp = 1<<8,
|
|
|
|
Ilbasp = 1<<9,
|
|
|
|
Illba = 1<<10,
|
|
|
|
};
|
|
|
|
|
|
|
|
int64_t
|
|
|
|
idfeat(Sfis *f, uint16_t *id)
|
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
int64_t s;
|
|
|
|
|
|
|
|
f->feat = 0;
|
|
|
|
if(f->sig>>16 == 0xeb14)
|
|
|
|
f->feat |= Datapi;
|
|
|
|
i = gbit16(id + 49);
|
|
|
|
if((i & Ilbasp) == 0){
|
2017-08-11 06:12:44 +02:00
|
|
|
if((gbit16(id + 53) & 1) == 0){
|
2016-11-25 17:18:40 +01:00
|
|
|
f->c = gbit16(id + 1);
|
|
|
|
f->h = gbit16(id + 3);
|
|
|
|
f->s = gbit16(id + 6);
|
|
|
|
}else{
|
|
|
|
f->c = gbit16(id + 54);
|
|
|
|
f->h = gbit16(id + 55);
|
|
|
|
f->s = gbit16(id + 56);
|
|
|
|
}
|
|
|
|
s = f->c*f->h*f->s;
|
|
|
|
}else{
|
|
|
|
f->c = f->h = f->s = 0;
|
|
|
|
f->feat |= Dlba;
|
|
|
|
j = gbit16(id + 83) | gbit16(id + 86);
|
|
|
|
if(j & Illba){
|
|
|
|
f->feat |= Dllba;
|
|
|
|
s = gbit64(id + 100);
|
|
|
|
}else
|
|
|
|
s = gbit32(id + 60);
|
|
|
|
}
|
|
|
|
f->udma = 0xff;
|
|
|
|
if(i & Idmasp)
|
|
|
|
if(gbit16(id + 53) & 4)
|
|
|
|
for(i = gbit16(id + 88) & 0x7f; i; i >>= 1)
|
|
|
|
f->udma++;
|
|
|
|
|
|
|
|
if(f->feat & Datapi){
|
|
|
|
i = gbit16(id + 0);
|
|
|
|
if(i & 1)
|
|
|
|
f->feat |= Datapi16;
|
|
|
|
}
|
|
|
|
|
|
|
|
i = gbit16(id+83);
|
|
|
|
if((i>>14) == 1){
|
|
|
|
if(i & (1<<3))
|
|
|
|
f->feat |= Dpower;
|
|
|
|
i = gbit16(id + 82);
|
|
|
|
if(i & 1)
|
|
|
|
f->feat |= Dsmart;
|
|
|
|
if(i & (1<<14))
|
|
|
|
f->feat |= Dnop;
|
|
|
|
}
|
|
|
|
i = onesc(id + 80);
|
|
|
|
if(i & 1<<8){
|
|
|
|
f->feat |= Data8;
|
|
|
|
i = onesc(id + 222); /* sata? */
|
|
|
|
j = onesc(id + 76);
|
|
|
|
if(i != 0 && i >> 12 == 1 && j != 0){
|
|
|
|
j >>= 1;
|
|
|
|
f->speeds = j & 7;
|
|
|
|
i = gbit16(id + 78) & gbit16(id + 79);
|
|
|
|
/*
|
|
|
|
* not acceptable for comreset to
|
|
|
|
* wipe out device configuration.
|
|
|
|
* reject drive.
|
|
|
|
*/
|
|
|
|
if((i & 1<<6) == 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(gbit16(id + 206) & 1)
|
|
|
|
f->feat |= Dsct;
|
|
|
|
idss(f, id);
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
idss(Sfis *f, uint16_t *id)
|
|
|
|
{
|
|
|
|
uint32_t sw, i;
|
|
|
|
|
|
|
|
if(f->sig>>16 == 0xeb14)
|
|
|
|
return 0;
|
|
|
|
f->lsectsz = 512;
|
|
|
|
f->physshift = 0;
|
|
|
|
i = gbit16(id + 106);
|
|
|
|
if(i >> 14 != 1)
|
|
|
|
return f->lsectsz;
|
|
|
|
if((sw = gbit32(id + 117)) >= 256)
|
|
|
|
f->lsectsz = sw * 2;
|
|
|
|
if(i & 1<<13)
|
|
|
|
f->physshift = i & 7;
|
|
|
|
return f->lsectsz * (1<<f->physshift);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t
|
|
|
|
idwwn(Sfis*, uint16_t *id)
|
|
|
|
{
|
|
|
|
uint64_t u;
|
|
|
|
|
|
|
|
u = 0;
|
|
|
|
if(id[108]>>12 == 5){
|
|
|
|
u |= (uint64_t)gbit16(id + 108) << 48;
|
|
|
|
u |= (uint64_t)gbit16(id + 109) << 32;
|
|
|
|
u |= gbit16(id + 110) << 16;
|
|
|
|
u |= gbit16(id + 111) << 0;
|
|
|
|
}
|
|
|
|
return u;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
idmove(char *p, uint16_t *u, int n)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
char *op, *e, *s;
|
|
|
|
|
|
|
|
op = p;
|
|
|
|
s = (char*)u;
|
|
|
|
for(i = 0; i < n; i += 2){
|
|
|
|
*p++ = s[i + 1];
|
|
|
|
*p++ = s[i + 0];
|
|
|
|
}
|
|
|
|
*p = 0;
|
|
|
|
while(p > op && *--p == ' ')
|
|
|
|
*p = 0;
|
|
|
|
e = p;
|
|
|
|
p = op;
|
|
|
|
while(*p == ' ')
|
|
|
|
p++;
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_memmove(op, p, n - (e - p));
|
2016-11-25 17:18:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
char*
|
|
|
|
pflag(char *s, char *e, Sfis *f)
|
|
|
|
{
|
|
|
|
uint16_t i, u;
|
|
|
|
|
|
|
|
u = f->feat;
|
|
|
|
for(i = 0; i < Dnflag; i++)
|
|
|
|
if(u & (1 << i))
|
2017-04-19 23:33:14 +02:00
|
|
|
s = jehanne_seprint(s, e, "%s ", flagname[i]);
|
|
|
|
return jehanne_seprint(s, e, "\n");
|
2016-11-25 17:18:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
atapirwfis(Sfis *f, uint8_t *c, uint8_t *cdb, int cdblen, int ndata)
|
|
|
|
{
|
|
|
|
int fill, len;
|
|
|
|
|
|
|
|
fill = f->feat&Datapi16? 16: 12;
|
|
|
|
if((len = cdblen) > fill)
|
|
|
|
len = fill;
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_memmove(c + 0x40, cdb, len);
|
|
|
|
jehanne_memset(c + 0x40 + len, 0, fill - len);
|
2016-11-25 17:18:40 +01:00
|
|
|
|
|
|
|
c[Ftype] = H2dev;
|
|
|
|
c[Fflags] = Fiscmd;
|
|
|
|
c[Fcmd] = Ataobs;
|
|
|
|
if(ndata != 0)
|
|
|
|
c[Ffeat] = 1; /* dma */
|
|
|
|
else
|
|
|
|
c[Ffeat] = 0; /* features (exp); */
|
2017-08-11 01:47:15 +02:00
|
|
|
c[Flba0] = 0;
|
2016-11-25 17:18:40 +01:00
|
|
|
c[Flba8] = ndata;
|
|
|
|
c[Flba16] = ndata >> 8;
|
|
|
|
c[Fdev] = Ataobs;
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_memset(c + 8, 0, Fissize - 8);
|
2016-11-25 17:18:40 +01:00
|
|
|
return P28|Ppkt;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
rwfis(Sfis *f, uint8_t *c, int rw, int nsect, uint64_t lba)
|
|
|
|
{
|
|
|
|
uint8_t acmd, llba, udma;
|
|
|
|
static uint8_t tab[2][2][2] = { 0x20, 0x24, 0x30, 0x34, 0xc8, 0x25, 0xca, 0x35, };
|
|
|
|
static uint8_t ptab[2][2][2] = {
|
|
|
|
Pin|Ppio|P28, Pin|Ppio|P48,
|
|
|
|
Pout|Ppio|P28, Pout|Ppio|P48,
|
|
|
|
Pin|Pdma|P28, Pin|Pdma|P48,
|
|
|
|
Pout|Pdma|P28, Pout|Pdma|P48,
|
|
|
|
};
|
|
|
|
|
|
|
|
nsect >>= f->physshift;
|
|
|
|
lba >>= f->physshift;
|
|
|
|
|
|
|
|
udma = f->udma != 0xff;
|
|
|
|
llba = (f->feat & Dllba) != 0;
|
|
|
|
acmd = tab[udma][rw][llba];
|
|
|
|
|
|
|
|
c[Ftype] = 0x27;
|
|
|
|
c[Fflags] = 0x80;
|
|
|
|
c[Fcmd] = acmd;
|
|
|
|
c[Ffeat] = 0;
|
|
|
|
|
|
|
|
c[Flba0] = lba;
|
|
|
|
c[Flba8] = lba >> 8;
|
|
|
|
c[Flba16] = lba >> 16;
|
|
|
|
c[Fdev] = Ataobs | Atalba;
|
|
|
|
if(llba == 0)
|
|
|
|
c[Fdev] |= (lba>>24) & 0xf;
|
|
|
|
|
|
|
|
c[Flba24] = lba >> 24;
|
|
|
|
c[Flba32] = lba >> 32;
|
|
|
|
c[Flba40] = lba >> 48;
|
|
|
|
c[Ffeat8] = 0;
|
|
|
|
|
|
|
|
c[Fsc] = nsect;
|
|
|
|
c[Fsc8] = nsect >> 8;
|
|
|
|
c[Ficc] = 0;
|
|
|
|
c[Fcontrol] = 0;
|
|
|
|
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_memset(c + 16, 0, Fissize - 16);
|
2016-11-25 17:18:40 +01:00
|
|
|
return ptab[udma][rw][llba];
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t
|
|
|
|
fisrw(Sfis *f, uint8_t *c, int *n)
|
|
|
|
{
|
|
|
|
uint64_t lba;
|
|
|
|
|
|
|
|
lba = c[Flba0];
|
|
|
|
lba |= c[Flba8] << 8;
|
|
|
|
lba |= c[Flba16] << 16;
|
|
|
|
lba |= c[Flba24] << 24;
|
|
|
|
lba |= (uint64_t)(c[Flba32] | c[Flba40]<<8) << 32;
|
|
|
|
|
|
|
|
*n = c[Fsc];
|
|
|
|
*n |= c[Fsc8] << 8;
|
|
|
|
|
|
|
|
*n >>= f->physshift;
|
|
|
|
lba >>= f->physshift;
|
|
|
|
|
|
|
|
return lba;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
sigtofis(Sfis *f, uint8_t *c)
|
|
|
|
{
|
|
|
|
uint32_t u;
|
|
|
|
|
|
|
|
u = f->sig;
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_memset(c, 0, Fissize);
|
2016-11-25 17:18:40 +01:00
|
|
|
c[Ftype] = 0x34;
|
|
|
|
c[Fflags] = 0x00;
|
|
|
|
c[Fcmd] = 0x50;
|
|
|
|
c[Ffeat] = 0x01;
|
|
|
|
c[Flba0] = u >> 8;
|
|
|
|
c[Flba8] = u >> 16;
|
|
|
|
c[Flba16] = u >> 24;
|
|
|
|
c[Fdev] = Ataobs;
|
|
|
|
c[Fsc] = u;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t
|
|
|
|
fistosig(uint8_t *u)
|
|
|
|
{
|
|
|
|
return u[Fsc] | u[Flba0]<<8 | u[Flba8]<<16 | u[Flba16]<<24;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* sas smp */
|
|
|
|
void
|
|
|
|
smpskelframe(Cfis *f, uint8_t *c, int m)
|
|
|
|
{
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_memset(c, 0, Fissize);
|
2016-11-25 17:18:40 +01:00
|
|
|
c[Ftype] = 0x40;
|
|
|
|
c[Fflags] = m;
|
|
|
|
if(f->phyid)
|
|
|
|
c[Flba32] = f->phyid;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t
|
|
|
|
sashash(uint64_t u)
|
|
|
|
{
|
|
|
|
uint32_t poly, msb, l, r;
|
|
|
|
uint64_t m;
|
|
|
|
|
|
|
|
r = 0;
|
|
|
|
poly = 0x01db2777;
|
|
|
|
msb = 0x01000000;
|
|
|
|
for(m = 1ull<<63; m > 0; m >>= 1){
|
|
|
|
l = 0;
|
|
|
|
if(m & u)
|
|
|
|
l = msb;
|
|
|
|
r <<= 1;
|
|
|
|
r ^= l;
|
|
|
|
if(r & msb)
|
|
|
|
r ^= poly;
|
|
|
|
}
|
|
|
|
return r & 0xffffff;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t*
|
|
|
|
sasbhash(uint8_t *t, uint8_t *s)
|
|
|
|
{
|
|
|
|
uint32_t poly, msb, l, r, i, j;
|
|
|
|
|
|
|
|
r = 0;
|
|
|
|
poly = 0x01db2777;
|
|
|
|
msb = 0x01000000;
|
|
|
|
for(i = 0; i < 8; i++)
|
|
|
|
for(j = 0x80; j != 0; j >>= 1){
|
|
|
|
l = 0;
|
|
|
|
if(s[i] & j)
|
|
|
|
l = msb;
|
|
|
|
r <<= 1;
|
|
|
|
r ^= l;
|
|
|
|
if(r & msb)
|
|
|
|
r ^= poly;
|
|
|
|
}
|
|
|
|
t[0] = r>>16;
|
|
|
|
t[1] = r>>8;
|
|
|
|
t[2] = r;
|
|
|
|
return t;
|
|
|
|
}
|