merge sd changes from 9atom

cinap_lenrek 2011-07-10 14:14:23 +02:00
parent ae00ac7465
commit c2fc2fad13
22 changed files with 7886 additions and 3050 deletions

163
sys/include/fis.h Normal file
View File

@ -0,0 +1,163 @@
#pragma lib "libfis.a"
#pragma src "/sys/src/libfis"
/* ata errors */
enum {
Emed = 1<<0, /* media error */
Enm = 1<<1, /* no media */
Eabrt = 1<<2, /* abort */
Emcr = 1<<3, /* media change request */
Eidnf = 1<<4, /* no user-accessible address */
Emc = 1<<5, /* media change */
Eunc = 1<<6, /* data error */
Ewp = 1<<6, /* write protect */
Eicrc = 1<<7, /* interface crc error */
Efatal = Eidnf|Eicrc, /* must sw reset */
};
/* ata status */
enum {
ASerr = 1<<0, /* error */
ASdrq = 1<<3, /* request */
ASdf = 1<<5, /* fault */
ASdrdy = 1<<6, /* ready */
ASbsy = 1<<7, /* busy */
ASobs = 1<<1|1<<2|1<<4,
};
enum {
/* fis types */
H2dev = 0x27,
D2host = 0x34,
/* fis flags bits */
Fiscmd = 0x80,
/* ata bits */
Ataobs = 0xa0,
Atalba = 0x40,
/* nominal fis size (fits any fis) */
Fissize = 0x20,
};
/* sata device-to-host (0x27) fis layout */
enum {
Ftype,
Fflags,
Fcmd,
Ffeat,
Flba0,
Flba8,
Flba16,
Fdev,
Flba24,
Flba32,
Flba40,
Ffeat8,
Fsc,
Fsc8,
Ficc, /* isochronous cmd completion */
Fcontrol,
};
/* sata host-to-device fis (0x34) differences */
enum{
Fioport = 1,
Fstatus,
Frerror,
};
/* ata protcol type */
enum{
Pnd = 0<<0, /* data direction */
Pin = 1<<0,
Pout = 2<<0,
Pdatam = 3<<0,
Ppio = 1<<2, /* ata protocol */
Pdma = 2<<2,
Pdmq = 3<<2,
Preset = 4<<2,
Pdiag = 5<<2,
Ppkt = 6<<2,
Pprotom = 7<<2,
P48 = 0<<5, /* command “size” */
P28 = 1<<5,
Pcmdszm = 1<<5,
Pssn = 0<<6, /* sector size */
P512 = 1<<6,
Pssm = 1<<6,
};
typedef struct Sfis Sfis;
struct Sfis {
ushort feat;
uchar udma;
uchar speeds;
uint sig;
uint lsectsz;
uint physshift; /* log2(log/phys) */
uint c; /* disgusting, no? */
uint h;
uint s;
};
enum {
Dlba = 1<<0, /* required for sata */
Dllba = 1<<1,
Dsmart = 1<<2,
Dpower = 1<<3,
Dnop = 1<<4,
Datapi = 1<<5,
Datapi16= 1<<6,
Data8 = 1<<7,
Dsct = 1<<8,
Dnflag = 9,
};
enum {
Pspinup = 1<<0,
Pidready = 1<<1,
};
void setfissig(Sfis*, uint);
int txmodefis(Sfis*, uchar*, uchar);
int atapirwfis(Sfis*, uchar*, uchar*, int, int);
int featfis(Sfis*, uchar*, uchar);
int flushcachefis(Sfis*, uchar*);
int identifyfis(Sfis*, uchar*);
int nopfis(Sfis*, uchar*, int);
int rwfis(Sfis*, uchar*, int, int, uvlong);
void skelfis(uchar*);
void sigtofis(Sfis*, uchar*);
uvlong fisrw(Sfis*, uchar*, int*);
void idmove(char*, ushort*, int);
vlong idfeat(Sfis*, ushort*);
uvlong idwwn(Sfis*, ushort*);
int idss(Sfis*, ushort*);
int idpuis(ushort*);
ushort id16(ushort*, int);
uint id32(ushort*, int);
uvlong id64(ushort*, int);
char *pflag(char*, char*, Sfis*);
uint fistosig(uchar*);
/* scsi */
typedef struct Cfis Cfis;
struct Cfis {
uchar phyid;
uchar encid[8];
uchar tsasaddr[8];
uchar ssasaddr[8];
uchar ict[2];
};
void smpskelframe(Cfis*, uchar*, int);
uint sashash(uvlong);
uchar *sasbhash(uchar*, uchar*);

View File

@ -1,34 +1,8 @@
/*
* advanced host controller interface (sata)
* © 2007 coraid, inc
* © 2007-9 coraid, inc
*/
/* ata errors */
enum {
Emed = 1<<0, /* media error */
Enm = 1<<1, /* no media */
Eabrt = 1<<2, /* abort */
Emcr = 1<<3, /* media change request */
Eidnf = 1<<4, /* no user-accessible address */
Emc = 1<<5, /* media change */
Eunc = 1<<6, /* data error */
Ewp = 1<<6, /* write protect */
Eicrc = 1<<7, /* interface crc error */
Efatal = Eidnf|Eicrc, /* must sw reset */
};
/* ata status */
enum {
ASerr = 1<<0, /* error */
ASdrq = 1<<3, /* request */
ASdf = 1<<5, /* fault */
ASdrdy = 1<<6, /* ready */
ASbsy = 1<<7, /* busy */
ASobs = 1<<1|1<<2|1<<4,
};
/* pci configuration */
enum {
Abar = 5,
@ -47,26 +21,25 @@ enum {
/* cap bits: supported features */
enum {
Hs64a = 1<<31, /* 64-bit addressing */
Hsncq = 1<<30, /* ncq */
Hssntf = 1<<29, /* snotification reg. */
Hsmps = 1<<28, /* mech pres switch */
Hsss = 1<<27, /* staggered spinup */
Hsalp = 1<<26, /* aggressive link pm */
Hsal = 1<<25, /* activity led */
Hsclo = 1<<24, /* command-list override */
H64a = 1<<31, /* 64-bit addressing */
Hncq = 1<<30, /* ncq */
Hsntf = 1<<29, /* snotification reg. */
Hmps = 1<<28, /* mech pres switch */
Hss = 1<<27, /* staggered spinup */
Halp = 1<<26, /* aggressive link pm */
Hal = 1<<25, /* activity led */
Hclo = 1<<24, /* command-list override */
Hiss = 1<<20, /* for interface speed */
// Hsnzo = 1<<19,
Hsam = 1<<18, /* ahci-mode only */
Hspm = 1<<17, /* port multiplier */
// Hfbss = 1<<16,
Ham = 1<<18, /* ahci-mode only */
Hpm = 1<<17, /* port multiplier */
Hfbs = 1<<16, /* fis-based switching */
Hpmb = 1<<15, /* multiple-block pio */
Hssc = 1<<14, /* slumber state */
Hpsc = 1<<13, /* partial-slumber state */
Hncs = 1<<8, /* n command slots */
Hcccs = 1<<7, /* coal */
Hems = 1<<6, /* enclosure mgmt. */
Hsxs = 1<<5, /* external sata */
Hxs = 1<<5, /* external sata */
Hnp = 1<<0, /* n ports */
};
@ -77,6 +50,29 @@ enum {
Hhr = 1<<0, /* hba reset */
};
/* cap2 bits */
enum {
Apts = 1<<2, /* automatic partial to slumber */
Nvmp = 1<<1, /* nvmhci present; nvram */
Boh = 1<<0, /* bios/os handoff supported */
};
/* emctl bits */
enum {
Pm = 1<<27, /* port multiplier support */
Alhd = 1<<26, /* activity led hardware driven */
Xonly = 1<<25, /* rx messages not supported */
Smb = 1<<24, /* single msg buffer; rx limited */
Esgpio = 1<<19, /* sgpio messages supported */
Eses2 = 1<<18, /* ses-2 supported */
Esafte = 1<<17, /* saf-te supported */
Elmt = 1<<16, /* led msg types support */
Emrst = 1<<9, /* reset all em logic */
Tmsg = 1<<8, /* transmit message */
Mr = 1<<0, /* message rx'd */
Emtype = Esgpio | Eses2 | Esafte | Elmt,
};
typedef struct {
ulong cap;
ulong ghc;
@ -87,6 +83,8 @@ typedef struct {
ulong cccports;
ulong emloc;
ulong emctl;
ulong cap2;
ulong bios;
} Ahba;
enum {
@ -147,6 +145,8 @@ enum {
Aalpe = 1<<26, /* aggressive link pm enable */
Adlae = 1<<25, /* drive led on atapi */
Aatapi = 1<<24, /* device is atapi */
Apste = 1<<23, /* automatic slumber to partial cap */
Afbsc = 1<<22, /* fis-based switching capable */
Aesp = 1<<21, /* external sata port */
Acpd = 1<<20, /* cold presence detect */
Ampsp = 1<<19, /* mechanical pres. */
@ -164,6 +164,7 @@ enum {
Ast = 1<<0, /* start */
Arun = Ast|Acr|Afre|Afr,
Apwr = Apod|Asud,
};
/* ctl register bits */
@ -173,13 +174,41 @@ enum {
Adet = 1<<0, /* device detection */
};
/* sstatus register bits */
enum{
/* sstatus det */
Smissing = 0<<0,
Spresent = 1<<0,
Sphylink = 3<<0,
Sbist = 4<<0,
Smask = 7<<0,
/* sstatus speed */
Gmissing = 0<<4,
Gi = 1<<4,
Gii = 2<<4,
Giii = 3<<4,
Gmask = 7<<4,
/* sstatus ipm */
Imissing = 0<<8,
Iactive = 1<<8,
Isleepy = 2<<8,
Islumber = 6<<8,
Imask = 7<<8,
SImask = Smask | Imask,
SSmask = Smask | Isleepy,
};
#define sstatus scr0
#define sctl scr2
#define serror scr1
#define sactive scr3
#define ntf scr4
typedef struct {
ulong list; /* PxCLB must be 1kb aligned. */
ulong list; /* PxCLB must be 1kb aligned */
ulong listhi;
ulong fis; /* 256-byte aligned */
ulong fishi;
@ -194,9 +223,10 @@ typedef struct {
ulong scr1;
ulong scr3;
ulong ci; /* command issue */
ulong ntf;
uchar res2[8];
ulong vendor;
ulong scr4;
ulong fbs;
ulong res2[11];
ulong vendor[4];
} Aport;
/* in host's memory; not memory mapped */
@ -244,26 +274,49 @@ typedef struct {
Aprdt prdt;
} Actab;
/* enclosure message header */
enum {
Mled = 0,
Msafte = 1,
Mses2 = 2,
Msgpio = 3,
};
typedef struct {
uchar dummy;
uchar msize;
uchar dsize;
uchar type;
uchar hba; /* bits 0:4 are the port */
uchar pm;
uchar led[2];
} Aledmsg;
enum {
Aled = 1<<0,
Locled = 1<<3,
Errled = 1<<6,
Ledoff = 0,
Ledon = 1,
};
typedef struct {
uint encsz;
ulong *enctx;
ulong *encrx;
} Aenc;
enum {
Ferror = 1,
Fdone = 2,
};
enum {
Dllba = 1,
Dsmart = 1<<1,
Dpower = 1<<2,
Dnop = 1<<3,
Datapi = 1<<4,
Datapi16= 1<<5,
};
typedef struct {
QLock;
Rendez;
uchar flag;
uchar feat;
uchar smart;
Sfis;
Afis fis;
Alist *list;
Actab *ctab;

View File

@ -67,6 +67,7 @@ LIB=\
/$objtype/lib/libc.a\
/$objtype/lib/libsec.a\
/$objtype/lib/libmp.a\
/$objtype/lib/libfis.a\
ETHER=`{echo devether.c ether*.c | sed 's/\.c/.'$O'/g'}
VGA=`{echo devvga.c screen.c vga*.c | sed 's/\.c/.'$O'/g'}

View File

@ -75,11 +75,13 @@ misc
uarti8250
uartpci pci
sdata pci sdscsi
sdaoe
sdide pci sdscsi
sd53c8xx pci sdscsi
sdmylex pci sdscsi
sdiahci pci sdscsi
sdaoe
sdiahci pci sdscsi led
sdodin pci sdscsi led
sdloop
vga3dfx +cur
vgaark2000pv +cur

View File

@ -81,11 +81,13 @@ misc
archmp mp apic
mtrr
sdata pci sdscsi
sdaoe
sdide pci sdscsi
sd53c8xx pci sdscsi
sdmylex pci sdscsi
sdiahci pci sdscsi
sdaoe
sdiahci pci sdscsi led
sdodin pci sdscsi led
sdloop
uarti8250
uartpci pci

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -840,7 +840,6 @@ mylexprobe(int port, int irq)
Ctlr *ctlr;
uchar cmd[6], data[256];
int clen, dlen, timeo;
static int count;
if(ioalloc(port, 0x3, 0, "mylex") < 0)
return nil;
@ -894,18 +893,13 @@ buggery:
if(issue(ctlr, cmd, clen, data, dlen)){
if(data[0] == 'E')
ctlr->bus = 32;
print("mylex ctlr @ port 0x%ux: 32-bit ", ctlr->port);
ctlr->wide = data[0x0D] & 0x01;
/*
* devsd doesn't pass us the `spec' argument, so
* we'll assume that sd0 goes to the first scsi host
* adapter found, etc.
*/
print("#S/sd%d: mylex SCSI: port 0x%ux: %d-bit, ",
count++, ctlr->port, ctlr->bus);
if (ctlr->wide)
print("wide\n");
print("wide ");
else
print("narrow\n");
print("narrow ");
print("SCSI host adapter\n");
}
else{
/*
@ -1187,8 +1181,9 @@ mylex32enable(Ctlr* ctlr)
cmd[1] = 1;
if(!issue(ctlr, cmd, 2, 0, 0)) {
ctlr->wide = 0;
print("mylex32enable: port 0x%ux: scsi wide-mode setup "
"failed on wide host adapter", ctlr->port);
print(
"mylex32enable: ctlr @ port 0x%ux: scsi wide-mode setup failed on wide host adapter",
ctlr->port);
}
}

2841
sys/src/9/pc/sdodin.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,8 @@
/*
* ATA-over-Ethernet (AoE) protocol
*/
enum {
ACata,
ACconfig,
ACmask,
ACres,
};
enum {
@ -15,23 +14,55 @@ enum {
};
enum {
AEcmd = 1,
AEarg,
AEdev,
AEcfg,
AEver,
AEunk,
AEcmd, /* bad command */
AEarg, /* bad argument */
AEoff, /* device offline */
AEcfg, /* config string already set */
AEver, /* unsupported version */
AEres, /* target reserved */
};
enum {
Aoetype = 0x88a2,
Aoesectsz = 512, /* standard sector size */
Aoever = 1,
/* mask commands */
Mread = 0,
Medit,
AFerr = 1<<2,
AFrsp = 1<<3,
/* mask directives */
MDnop = 0,
MDadd,
MDdel,
AAFwrite= 1,
AAFext = 1<<6,
/* mask errors */
MEunk = 1,
MEbad,
MEfull,
/* reserve / release */
Rrread = 0,
Rrset,
Rrforce,
};
enum {
Aoetype = 0x88a2,
Aoesectsz = 512,
Aoemaxcfg = 1024,
Aoehsz = 24,
Aoeatasz = 12,
Aoecfgsz = 8,
Aoerrsz = 2,
Aoemsz = 4,
Aoemdsz = 8,
Aoever = 1,
AFerr = 1<<2,
AFrsp = 1<<3,
AAFwrite = 1,
AAFext = 1<<6,
};
typedef struct {
@ -44,35 +75,43 @@ typedef struct {
uchar minor;
uchar cmd;
uchar tag[4];
uchar payload[];
} Aoehdr;
#define AOEHDRSZ offsetof(Aoehdr, payload[0])
typedef struct {
Aoehdr;
uchar aflag;
uchar errfeat;
uchar scnt;
uchar cmdstat;
uchar lba[6];
uchar res[2];
uchar payload[];
} Aoeata;
#define AOEATASZ offsetof(Aoeata, payload[0])
typedef struct {
Aoehdr;
uchar bufcnt[2];
uchar fwver[2];
uchar scnt;
uchar verccmd;
uchar cslen[2];
uchar payload[];
} Aoeqc;
} Aoecfg;
#define AOEQCSZ offsetof(Aoeqc, payload[0])
typedef struct {
uchar dres;
uchar dcmd;
uchar ea[Eaddrlen];
} Aoemd;
typedef struct {
uchar mres;
uchar mcmd;
uchar merr;
uchar mcnt;
} Aoem;
typedef struct {
uchar rcmd;
uchar nea;
uchar ea0[];
} Aoerr;
extern char Echange[];
extern char Enotup[];

File diff suppressed because it is too large Load Diff

View File

@ -15,7 +15,9 @@
extern Dev sddevtab;
extern SDifc* sdifc[];
static char Echange[] = "media or partition has changed";
static char Echange[] = "media or partition has changed";
static char Enoata[] = "raw ata commands not supported";
static char Enoscsi[] = "raw scsi commands not supported";
static char devletters[] = "0123456789"
"abcdefghijklmnopqrstuvwxyz"
@ -23,6 +25,11 @@ static char devletters[] = "0123456789"
static SDev *devs[sizeof devletters-1];
static QLock devslock;
static SDunit topctlunit;
enum {
Ahdrsz = 2,
};
enum {
Rawcmd,
@ -40,6 +47,7 @@ enum {
Qctl = Qunitbase,
Qraw,
Qpart,
Qextra,
TypeLOG = 4,
NType = (1<<TypeLOG),
@ -292,7 +300,7 @@ sdgetunit(SDev* sdev, int subno)
}
sdev->unitflg[subno] = 1;
snprint(buf, sizeof(buf), "%s%d", sdev->name, subno);
snprint(buf, sizeof buf, "%s%x", sdev->name, subno);
kstrdup(&unit->name, buf);
kstrdup(&unit->user, eve);
unit->perm = 0555;
@ -323,15 +331,14 @@ static void
sdreset(void)
{
int i;
SDev *sdev;
/*
* Probe all known controller types and register any devices found.
*/
for(i = 0; sdifc[i] != nil; i++){
if(sdifc[i]->pnp == nil || (sdev = sdifc[i]->pnp()) == nil)
if(sdifc[i]->pnp == nil)
continue;
sdadddevs(sdev);
sdadddevs(sdifc[i]->pnp());
}
}
@ -344,8 +351,8 @@ sdadddevs(SDev *sdev)
for(; sdev; sdev=next){
next = sdev->next;
sdev->unit = (SDunit**)malloc(sdev->nunit * sizeof(SDunit*));
sdev->unitflg = (int*)malloc(sdev->nunit * sizeof(int));
sdev->unit = malloc(sdev->nunit * sizeof(SDunit*));
sdev->unitflg = malloc(sdev->nunit * sizeof(int));
if(sdev->unit == nil || sdev->unitflg == nil){
print("sdadddevs: out of memory\n");
giveup:
@ -392,11 +399,12 @@ sd2gen(Chan* c, int i, Dir* dp)
{
Qid q;
uvlong l;
SDfile *e;
SDpart *pp;
SDperm *perm;
SDunit *unit;
SDev *sdev;
int rv;
int rv, t;
sdev = sdgetdev(DEV(c->qid));
assert(sdev);
@ -438,6 +446,18 @@ sd2gen(Chan* c, int i, Dir* dp)
devdir(c, q, pp->name, l, pp->user, pp->perm, dp);
rv = 1;
break;
case Qextra:
t = PART(c->qid);
if(t >= unit->nefile)
break;
mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qextra),
unit->vers, QTFILE);
e = unit->efile + t;
if(emptystr(e->user))
kstrdup(&e->user, eve);
devdir(c, q, e->name, 0, e->user, e->perm, dp);
rv = 1;
break;
}
decref(&sdev->r);
@ -448,16 +468,45 @@ static int
sd1gen(Chan* c, int i, Dir* dp)
{
Qid q;
SDperm *p;
switch(i){
case Qtopctl:
mkqid(&q, QID(0, 0, 0, Qtopctl), 0, QTFILE);
devdir(c, q, "sdctl", 0, eve, 0640, dp);
qlock(&topctlunit.ctl);
p = &topctlunit.ctlperm;
if(p->user == nil || p->user[0] == 0){
kstrdup(&p->name, "sdctl");
kstrdup(&p->user, eve);
p->perm = 0640;
}
devdir(c, q, p->name, 0, p->user, p->perm, dp);
qunlock(&topctlunit.ctl);
return 1;
}
return -1;
}
static int
efilegen(Chan *c, SDunit *unit, int i, Dir *dp)
{
Qid q;
SDfile *e;
i -= SDnpart;
if(unit->nefile == 0 || i >= unit->nefile)
return -1;
if(i < 0)
return 0;
e = unit->efile + i;
if(emptystr(e->user))
kstrdup(&e->user, eve);
mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), i, Qextra),
unit->vers, QTFILE);
devdir(c, q, e->name, 0, e->user, e->perm, dp);
return 1;
}
static int
sdgen(Chan* c, char*, Dirtab*, int, int s, Dir* dp)
{
@ -553,17 +602,18 @@ sdgen(Chan* c, char*, Dirtab*, int, int s, Dir* dp)
}
i -= Qpart;
if(unit->part == nil || i >= unit->npart){
r = efilegen(c, unit, i, dp);
qunlock(&unit->ctl);
decref(&sdev->r);
break;
return r;
}
pp = &unit->part[i];
if(!pp->valid){
if(!pp->valid || unit->sectors == 0){
qunlock(&unit->ctl);
decref(&sdev->r);
return 0;
}
l = (pp->end - pp->start) * unit->secsize;
l = (pp->end - pp->start) * (uvlong)unit->secsize;
mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), i, Qpart),
unit->vers+pp->vers, QTFILE);
if(emptystr(pp->user))
@ -575,6 +625,7 @@ sdgen(Chan* c, char*, Dirtab*, int, int s, Dir* dp)
case Qraw:
case Qctl:
case Qpart:
case Qextra:
if((sdev = sdgetdev(DEV(c->qid))) == nil){
devdir(c, q, "unavailable", 0, eve, 0, dp);
return 1;
@ -715,10 +766,12 @@ sdclose(Chan* c)
}
}
#define iskaddr(a) ((uintptr)(a) > KZERO)
static long
sdbio(Chan* c, int write, char* a, long len, uvlong off)
{
int nchange;
int nchange, hard, allocd;
long l;
uchar *b;
SDpart *pp;
@ -785,21 +838,30 @@ sdbio(Chan* c, int write, char* a, long len, uvlong off)
poperror();
}
b = sdmalloc(nb*unit->secsize);
if(b == nil)
error(Enomem);
offset = off%unit->secsize;
if(offset+len > nb*unit->secsize)
len = nb*unit->secsize - offset;
hard = offset || write && len%unit->secsize;
if(iskaddr(a) && !hard) {
b = (uchar*)a;
allocd = 0;
}else{
b = sdmalloc(nb*unit->secsize);
if(b == nil)
error(Enomem);
allocd = 1;
}
if(waserror()){
sdfree(b);
if(allocd)
sdfree(b);
if(!(unit->inquiry[1] & 0x80))
decref(&sdev->r); /* gadverdamme! */
nexterror();
}
offset = off%unit->secsize;
if(offset+len > nb*unit->secsize)
len = nb*unit->secsize - offset;
if(write){
if(offset || (len%unit->secsize)){
if(hard){
l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno);
if(l < 0)
error(Eio);
@ -810,7 +872,8 @@ sdbio(Chan* c, int write, char* a, long len, uvlong off)
len = l;
}
}
memmove(b+offset, a, len);
if(allocd)
memmove(b+offset, a, len);
l = unit->dev->ifc->bio(unit, 0, 1, b, nb, bno);
if(l < 0)
error(Eio);
@ -827,9 +890,11 @@ sdbio(Chan* c, int write, char* a, long len, uvlong off)
len = 0;
else if(len > l - offset)
len = l - offset;
memmove(a, b+offset, len);
if(allocd)
memmove(a, b+offset, len);
}
sdfree(b);
if(allocd)
sdfree(b);
poperror();
if(unit->inquiry[1] & 0x80){
@ -844,41 +909,69 @@ sdbio(Chan* c, int write, char* a, long len, uvlong off)
static long
sdrio(SDreq* r, void* a, long n)
{
char *errstr;
int rv;
void *data;
SDunit *u;
int (*f)(SDreq*);
if(n >= SDmaxio || n < 0)
error(Etoobig);
u = r->unit;
if(u->haversense && r->cmd[0] == 0x03){
u->haversense = 0;
r->rlen = sizeof u->rsense;
if(r->rlen > n)
r->rlen = n;
memmove(a, u->rsense, r->rlen);
r->status = SDok;
return r->rlen;
}
data = nil;
if(n){
if((data = sdmalloc(n)) == nil)
error(Enomem);
if(r->write)
memmove(data, a, n);
}
r->data = data;
r->dlen = n;
if(n > 0 && (data = sdmalloc(n)) == nil)
error(Enomem);
if(waserror()){
sdfree(data);
r->data = nil;
nexterror();
}
if(r->write && n > 0)
memmove(data, a, n);
r->data = data;
r->dlen = n;
if(r->unit->dev->ifc->rio(r) != SDok)
if(r->proto == SData){
f = u->dev->ifc->ataio;
errstr = Enoata;
}else{
f = u->dev->ifc->rio;
errstr = Enoscsi;
}
if(f == nil)
error(errstr);
rv = f(r);
if(r->flags & SDvalidsense){
memmove(u->rsense, r->sense, sizeof u->rsense);
u->haversense = 1;
}
if(rv != SDok)
error(Eio);
if(!r->write && r->rlen > 0)
memmove(a, data, r->rlen);
poperror();
sdfree(data);
r->data = nil;
poperror();
return r->rlen;
}
/*
* SCSI simulation for non-SCSI devices
*
* see /sys/src/cmd/scuzz/sense.c for information on key.
* see /sys/lib/scsicodes for asc:ascq codes
*/
int
sdsetsense(SDreq *r, int status, int key, int asc, int ascq)
@ -908,36 +1001,7 @@ sdsetsense(SDreq *r, int status, int key, int asc, int ascq)
}
int
sdmodesense(SDreq *r, uchar *cmd, void *info, int ilen)
{
int len;
uchar *data;
/*
* Fake a vendor-specific request with page code 0,
* return the drive info.
*/
if((cmd[2] & 0x3F) != 0 && (cmd[2] & 0x3F) != 0x3F)
return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
len = (cmd[7]<<8)|cmd[8];
if(len == 0)
return SDok;
if(len < 8+ilen)
return sdsetsense(r, SDcheck, 0x05, 0x1A, 0);
if(r->data == nil || r->dlen < len)
return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
data = r->data;
memset(data, 0, 8);
data[0] = ilen>>8;
data[1] = ilen;
if(ilen)
memmove(data+8, info, ilen);
r->rlen = 8+ilen;
return sdsetsense(r, SDok, 0, 0, 0);
}
int
sdfakescsi(SDreq *r, void *info, int ilen)
sdfakescsi(SDreq *r)
{
uchar *cmd, *p;
uvlong len;
@ -947,25 +1011,6 @@ sdfakescsi(SDreq *r, void *info, int ilen)
r->rlen = 0;
unit = r->unit;
/*
* Rewrite read(6)/write(6) into read(10)/write(10).
*/
switch(cmd[0]){
case 0x08: /* read */
case 0x0A: /* write */
cmd[9] = 0;
cmd[8] = cmd[4];
cmd[7] = 0;
cmd[6] = 0;
cmd[5] = cmd[3];
cmd[4] = cmd[2];
cmd[3] = cmd[1] & 0x0F;
cmd[2] = 0;
cmd[1] &= 0xE0;
cmd[0] |= 0x20;
break;
}
/*
* Map SCSI commands into ATA commands for discs.
* Fail any command with a LUN except INQUIRY which
@ -1018,13 +1063,15 @@ sdfakescsi(SDreq *r, void *info, int ilen)
/*
* Read capacity returns the LBA of the last sector.
*/
len = unit->sectors - 1;
len = unit->sectors;
if(len > 0)
len--;
p = r->data;
*p++ = len>>24;
*p++ = len>>16;
*p++ = len>>8;
*p++ = len;
len = 512;
len = unit->secsize;
*p++ = len>>24;
*p++ = len>>16;
*p++ = len>>8;
@ -1040,7 +1087,9 @@ sdfakescsi(SDreq *r, void *info, int ilen)
/*
* Read capcity returns the LBA of the last sector.
*/
len = unit->sectors - 1;
len = unit->sectors;
if(len > 0)
len--;
p = r->data;
*p++ = len>>56;
*p++ = len>>48;
@ -1050,32 +1099,124 @@ sdfakescsi(SDreq *r, void *info, int ilen)
*p++ = len>>16;
*p++ = len>>8;
*p++ = len;
len = 512;
len = unit->secsize;
*p++ = len>>24;
*p++ = len>>16;
*p++ = len>>8;
*p++ = len;
r->rlen = p - (uchar*)r->data;
return sdsetsense(r, SDok, 0, 0, 0);
case 0x5A: /* mode sense */
return sdmodesense(r, cmd, info, ilen);
case 0x28: /* read */
case 0x2A: /* write */
case 0x08: /* read6 */
case 0x0a: /* write6 */
case 0x28: /* read10 */
case 0x2a: /* write10 */
case 0xa8: /* read12 */
case 0xaa: /* write12 */
case 0x88: /* read16 */
case 0x8a: /* write16 */
return SDnostatus;
}
}
int
sdfakescsirw(SDreq *r, uvlong *llba, int *nsec, int *rwp)
{
uchar *c;
int rw, count;
uvlong lba;
c = r->cmd;
rw = SDread;
if((c[0] & 0xf) == 0xa)
rw = SDwrite;
switch(c[0]){
case 0x08: /* read6 */
case 0x0a:
lba = (c[1] & 0xf)<<16 | c[2]<<8 | c[3];
count = c[4];
break;
case 0x28: /* read10 */
case 0x2a:
lba = c[2]<<24 | c[3]<<16 | c[4]<<8 | c[5];
count = c[7]<<8 | c[8];
break;
case 0xa8: /* read12 */
case 0xaa:
lba = c[2]<<24 | c[3]<<16 | c[4]<<8 | c[5];
count = c[6]<<24 | c[7]<<16 | c[8]<<8 | c[9];
break;
case 0x88: /* read16 */
case 0x8a:
/* ata commands only go to 48-bit lba */
if(c[2] || c[3])
return sdsetsense(r, SDcheck, 3, 0xc, 2);
lba = (uvlong)c[4]<<40 | (uvlong)c[5]<<32;
lba |= c[6]<<24 | c[7]<<16 | c[8]<<8 | c[9];
count = c[10]<<24 | c[11]<<16 | c[12]<<8 | c[13];
break;
default:
print("%s: bad cmd 0x%.2ux\n", r->unit->name, c[0]);
r->status = sdsetsense(r, SDcheck, 0x05, 0x20, 0);
return SDcheck;
}
if(r->data == nil)
return SDok;
if(r->dlen < count * r->unit->secsize)
count = r->dlen/r->unit->secsize;
if(rwp)
*rwp = rw;
*llba = lba;
*nsec = count;
return SDnostatus;
}
static long
extrarw(int write, Chan *c, void *a, long n, vlong off)
{
int i;
SDrw *f;
SDev *sdev;
SDunit *unit;
sdev = sdgetdev(DEV(c->qid));
if(sdev == nil)
error(Enonexist);
if(waserror()){
decref(&sdev->r);
nexterror();
}
unit = sdev->unit[UNIT(c->qid)];
if(unit->vers != c->qid.vers)
error(Echange);
unit = sdev->unit[UNIT(c->qid)];
i = PART(c->qid);
if(i >= unit->nefile)
error(Enonexist);
f = unit->efile[i].r;
if(write)
f = unit->efile[i].w;
if(i >= unit->nefile || f == nil)
error(Eperm);
n = f(unit, c, a, n, off);
poperror();
decref(&sdev->r);
return n;
}
static char*
deftopctl(SDev *s, char *p, char *e)
{
return seprint(p, e, "sd%c %s %d units\n", s->idno, s->ifc->name, s->nunit);
}
static long
sdread(Chan *c, void *a, long n, vlong off)
{
char *p, *e, *buf;
SDpart *pp;
SDunit *unit;
SDev *sdev;
SDpart *pp;
SDreq *r;
SDunit *unit;
ulong offset;
int i, l, m, status;
@ -1093,6 +1234,8 @@ sdread(Chan *c, void *a, long n, vlong off)
sdev = devs[i];
if(sdev && sdev->ifc->rtopctl)
p = sdev->ifc->rtopctl(sdev, p, e);
else if(sdev)
p = deftopctl(sdev, p, e);
}
qunlock(&devslock);
n = readstr(off, a, n, buf);
@ -1157,23 +1300,38 @@ sdread(Chan *c, void *a, long n, vlong off)
}
if(unit->state == Rawdata){
unit->state = Rawstatus;
i = sdrio(unit->req, a, n);
r = unit->req;
r->timeout = 0;
i = sdrio(r, a, n);
}
else if(unit->state == Rawstatus){
status = unit->req->status;
unit->state = Rawcmd;
free(unit->req);
r = unit->req;
unit->req = nil;
i = readnum(0, a, n, status, NUMSIZE);
unit->state = Rawcmd;
status = r->status;
if(r->proto == SData){
p = a;
i = 16 + Ahdrsz;
if(n < i)
i = n;
if(i > 0)
p[0] = status;
if(i > Ahdrsz)
memmove(p + Ahdrsz, r->cmd, i - Ahdrsz);
}else
i = readnum(0, a, n, status, NUMSIZE);
free(r);
} else
i = 0;
poperror();
qunlock(&unit->raw);
decref(&sdev->r);
poperror();
return i;
case Qpart:
return sdbio(c, 0, a, n, off);
case Qextra:
return extrarw(0, c, a, n, off);
}
}
@ -1183,7 +1341,8 @@ static long
sdwrite(Chan* c, void* a, long n, vlong off)
{
char *f0;
int i;
int i, atacdb, proto, ataproto;
uchar *u;
uvlong end, start;
Cmdbuf *cb;
SDifc *ifc;
@ -1250,7 +1409,7 @@ sdwrite(Chan* c, void* a, long n, vlong off)
error(Ebadctl);
poperror();
poperror();
if (sdev)
if(sdev)
decref(&sdev->r);
free(cb);
break;
@ -1299,6 +1458,9 @@ sdwrite(Chan* c, void* a, long n, vlong off)
break;
case Qraw:
proto = SDcdb;
ataproto = 0;
atacdb = 0;
sdev = sdgetdev(DEV(c->qid));
if(sdev == nil)
error(Enonexist);
@ -1311,18 +1473,34 @@ sdwrite(Chan* c, void* a, long n, vlong off)
}
switch(unit->state){
case Rawcmd:
/* sneaky ata commands */
u = a;
if(n > 1 && *u == 0xff){
proto = SData;
ataproto = u[1];
a = u + 2;
atacdb = Ahdrsz;
n -= Ahdrsz;
}
if(n < 6 || n > sizeof(req->cmd))
error(Ebadarg);
if((req = malloc(sizeof(SDreq))) == nil)
error(Enomem);
req->unit = unit;
if(waserror()){
free(req);
nexterror();
}
memmove(req->cmd, a, n);
poperror();
req->clen = n;
req->flags = SDnosense;
/* req->flags = SDnosense; */
req->status = ~0;
req->proto = proto;
req->ataproto = ataproto;
unit->req = req;
unit->state = Rawdata;
n += atacdb;
break;
case Rawstatus:
@ -1333,15 +1511,18 @@ sdwrite(Chan* c, void* a, long n, vlong off)
case Rawdata:
unit->state = Rawstatus;
unit->req->write = 1;
n = sdrio(unit->req, a, n);
req = unit->req;
req->write = 1;
n = sdrio(req, a, n);
}
poperror();
qunlock(&unit->raw);
decref(&sdev->r);
poperror();
break;
case Qpart:
return sdbio(c, 1, a, n, off);
case Qextra:
return extrarw(1, c, a, n, off);
}
return n;
@ -1358,23 +1539,30 @@ sdwstat(Chan* c, uchar* dp, int n)
if(c->qid.type & QTDIR)
error(Eperm);
sdev = sdgetdev(DEV(c->qid));
if(sdev == nil)
error(Enonexist);
unit = sdev->unit[UNIT(c->qid)];
if(TYPE(c->qid) == Qtopctl){
unit = &topctlunit;
sdev = nil;
}else{
sdev = sdgetdev(DEV(c->qid));
if(sdev == nil)
error(Enonexist);
unit = sdev->unit[UNIT(c->qid)];
}
qlock(&unit->ctl);
d = nil;
if(waserror()){
free(d);
qunlock(&unit->ctl);
decref(&sdev->r);
if(sdev != nil)
decref(&sdev->r);
nexterror();
}
switch(TYPE(c->qid)){
default:
error(Eperm);
case Qtopctl:
case Qctl:
perm = &unit->ctlperm;
break;
@ -1396,14 +1584,22 @@ sdwstat(Chan* c, uchar* dp, int n)
n = convM2D(dp, n, &d[0], (char*)&d[1]);
if(n == 0)
error(Eshortstat);
if(d->atime != ~0 || d->mtime != ~0 || d->length != ~0)
error(Eperm);
if(!emptystr(d[0].muid) || !emptystr(d[0].name))
error(Eperm);
if(!emptystr(d[0].uid))
kstrdup(&perm->user, d[0].uid);
if(!emptystr(d[0].gid) && strcmp(d[0].gid, eve) != 0)
error(Eperm);
if(d[0].mode != ~0UL)
perm->perm = (perm->perm & ~0777) | (d[0].mode & 0777);
free(d);
d = nil; USED(d);
qunlock(&unit->ctl);
decref(&sdev->r);
if(sdev != nil)
decref(&sdev->r);
poperror();
return n;
}
@ -1487,13 +1683,62 @@ sdconfig(int on, char* spec, DevConf* cf)
return unconfigure(spec);
}
int
sdaddfile(SDunit *unit, char *s, int perm, char *u, SDrw *r, SDrw *w)
{
int i;
SDfile *e;
static Lock lk;
if(unit == nil)
return -1;
lock(&lk);
for(i = 0; i < unit->nefile; i++)
if(strcmp(unit->efile[i].name, s) == 0)
break;
if(i >= nelem(unit->efile)){
unlock(&lk);
return -1;
}
if(i >= unit->nefile)
unit->nefile = i + 1;
e = unit->efile + i;
if(e->name == nil)
kstrdup(&e->name, s);
if(e->user == nil)
kstrdup(&e->user, u);
e->perm = perm;
e->r = r;
e->w = w;
unlock(&lk);
return 0;
}
static void
sdshutdown(void)
{
int i;
SDev *sd;
for(i = 0; i < nelem(devs); i++){
sd = devs[i];
if(sd == nil)
continue;
if(sd->ifc->disable == nil){
print("#S/sd%c: no disable function\n", devletters[i]);
continue;
}
sd->ifc->disable(sd);
}
}
Dev sddevtab = {
'S',
"sd",
sdreset,
devinit,
devshutdown,
sdshutdown,
sdattach,
sdwalk,
sdstat,
@ -1544,7 +1789,7 @@ getnewport(DevConf* dc)
{
Devport *p;
p = (Devport *)malloc((dc->nports + 1) * sizeof(Devport));
p = malloc((dc->nports + 1) * sizeof(Devport));
if(dc->nports > 0){
memmove(p, dc->ports, dc->nports * sizeof(Devport));
free(dc->ports);
@ -1635,7 +1880,6 @@ legacytopctl(Cmdbuf *cb)
if(j == nelem(options))
error(Ebadarg);
}
/* this has been rewritten to accomodate sdaoe */
if(cd.on < 0 || cd.spec == 0)
error(Ebadarg);
if(cd.on && cd.cf.type == nil)

62
sys/src/9/port/led.c Normal file
View File

@ -0,0 +1,62 @@
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "../port/error.h"
#include "fns.h"
#include "led.h"
static char *ibpinames[Ibpilast] = {
[Ibpinone] "none",
[Ibpinormal] "normal",
[Ibpilocate] "locate",
[Ibpifail] "fail",
[Ibpirebuild] "rebuild",
[Ibpipfa] "pfa",
[Ibpispare] "spare",
[Ibpicritarray] "critarray",
[Ibpifailarray] "failarray",
};
char*
ledname(int c)
{
if(c >= 0 && c < Ibpilast)
return ibpinames[c];
return "bad index";
}
int
name2led(char *s)
{
int i;
for(i = 0; i < nelem(ibpinames); i++)
if(strcmp(ibpinames[i], s) == 0)
return i;
return -1;
}
long
ledr(Ledport *p, Chan*, void *a, long n, vlong off)
{
char buf[64];
snprint(buf, sizeof buf, "%s\n", ledname(p->led));
return readstr(off, a, n, buf);
}
long
ledw(Ledport *p, Chan*, void *a, long n, vlong)
{
int i;
Cmdbuf *cb;
cb = parsecmd(a, n);
i = name2led(cb->f[0]);
free(cb);
if(i == -1)
error(Ebadarg);
p->led = i;
return n;
}

26
sys/src/9/port/led.h Normal file
View File

@ -0,0 +1,26 @@
typedef struct Ledport Ledport;
struct Ledport {
uchar nled;
uchar led;
ushort ledbits; /* implementation dependent */
};
/* http://en.wikipedia.org/wiki/IBPI */
enum {
Ibpinone,
Ibpinormal,
Ibpilocate,
Ibpifail,
Ibpirebuild,
Ibpipfa,
Ibpispare,
Ibpicritarray,
Ibpifailarray,
Ibpilast,
};
char *ledname(int);
int name2led(char*);
long ledr(Ledport*, Chan*, void*, long, vlong);
long ledw(Ledport*, Chan*, void*, long, vlong);

View File

@ -85,18 +85,24 @@ extern int sprint(char*, char*, ...);
#pragma varargck argpos snprint 3
#pragma varargck argpos sprint 2
#pragma varargck type "llb" vlong
#pragma varargck type "lld" vlong
#pragma varargck type "llx" vlong
#pragma varargck type "llb" uvlong
#pragma varargck type "lld" uvlong
#pragma varargck type "llx" uvlong
#pragma varargck type "lb" long
#pragma varargck type "ld" long
#pragma varargck type "lx" long
#pragma varargck type "lb" ulong
#pragma varargck type "ld" ulong
#pragma varargck type "lx" ulong
#pragma varargck type "b" int
#pragma varargck type "d" int
#pragma varargck type "x" int
#pragma varargck type "c" int
#pragma varargck type "C" int
#pragma varargck type "b" uint
#pragma varargck type "d" uint
#pragma varargck type "x" uint
#pragma varargck type "c" uint

View File

@ -2,6 +2,7 @@
* Storage Device.
*/
typedef struct SDev SDev;
typedef struct SDfile SDfile;
typedef struct SDifc SDifc;
typedef struct SDpart SDpart;
typedef struct SDperm SDperm;
@ -22,11 +23,20 @@ struct SDpart {
ulong vers;
};
typedef long SDrw(SDunit*, Chan*, void*, long, vlong);
struct SDfile {
SDperm;
SDrw *r;
SDrw *w;
};
struct SDunit {
SDev* dev;
int subno;
uchar inquiry[255]; /* format follows SCSI spec */
uchar sense[18]; /* format follows SCSI spec */
uchar rsense[18]; /* support seperate rq sense and inline return */
uchar haversense;
SDperm;
QLock ctl;
@ -42,6 +52,8 @@ struct SDunit {
int state;
SDreq* req;
SDperm rawperm;
SDfile efile[5];
int nefile;
};
/*
@ -67,7 +79,7 @@ struct SDifc {
char* name;
SDev* (*pnp)(void);
SDev* (*legacy)(int, int);
SDev* (*xxlegacy)(int, int); /* unused. remove me */
int (*enable)(SDev*);
int (*disable)(SDev*);
@ -82,22 +94,26 @@ struct SDifc {
void (*clear)(SDev*);
char* (*rtopctl)(SDev*, char*, char*);
int (*wtopctl)(SDev*, Cmdbuf*);
int (*ataio)(SDreq*);
};
struct SDreq {
SDunit* unit;
int lun;
int write;
uchar cmd[16];
char write;
char proto;
char ataproto;
uchar cmd[0x20];
int clen;
void* data;
int dlen;
int flags;
ulong timeout; /* in ticks */
int status;
long rlen;
uchar sense[256];
uchar sense[32];
};
enum {
@ -119,6 +135,12 @@ enum {
SDmaxio = 2048*1024,
SDnpart = 16,
SDread = 0,
SDwrite,
SData = 1,
SDcdb = 2,
};
#define sdmalloc(n) malloc(n)
@ -127,11 +149,11 @@ enum {
/* devsd.c */
extern void sdadddevs(SDev*);
extern int sdsetsense(SDreq*, int, int, int, int);
extern int sdmodesense(SDreq*, uchar*, void*, int);
extern int sdfakescsi(SDreq*, void*, int);
extern int sdfakescsi(SDreq*);
extern int sdfakescsirw(SDreq*, uvlong*, int*, int*);
extern int sdaddfile(SDunit*, char*, int, char*, SDrw*, SDrw*);
/* sdscsi.c */
extern int scsiverify(SDunit*);
extern int scsionline(SDunit*);
extern long scsibio(SDunit*, int, int, void*, long, uvlong);
extern SDev* scsiid(SDev*, SDifc*);

View File

@ -1,5 +1,5 @@
/*
* aoe sd driver, copyright © 2007 coraid
* aoe sd driver, copyright © 2007-9 coraid
*/
#include "u.h"
@ -12,6 +12,7 @@
#include "../port/sd.h"
#include "../port/netif.h"
#include "../port/aoe.h"
#include <fis.h>
extern char Echange[];
extern char Enotup[];
@ -19,34 +20,14 @@ extern char Enotup[];
#define uprint(...) snprint(up->genbuf, sizeof up->genbuf, __VA_ARGS__);
enum {
Nctlr = 32,
Maxpath = 128,
Maxpath = 128,
Probeintvl = 100, /* ms. between probes */
Probemax = 20, /* max probes */
};
enum {
/* sync with ahci.h */
Dllba = 1<<0,
Dsmart = 1<<1,
Dpower = 1<<2,
Dnop = 1<<3,
Datapi = 1<<4,
Datapi16= 1<<5,
};
static char *flagname[] = {
"llba",
"smart",
"power",
"nop",
"atapi",
"atapi16",
Probemax = 10*1000, /* max ms. to wait */
};
typedef struct Ctlr Ctlr;
struct Ctlr{
struct Ctlr {
QLock;
Ctlr *next;
@ -56,11 +37,8 @@ struct Ctlr{
Chan *c;
ulong vers;
uchar mediachange;
uchar flag;
uchar smart;
uchar smartrs;
uchar feat;
uchar drivechange;
Sfis;
uvlong sectors;
char serial[20+1];
@ -69,88 +47,60 @@ struct Ctlr{
char ident[0x100];
};
void aoeidmove(char *p, ushort *a, unsigned n);
static Lock ctlrlock;
static Ctlr *head;
static Ctlr *tail;
SDifc sdaoeifc;
static ushort
gbit16(void *a)
{
uchar *i;
i = a;
return i[1] << 8 | i[0];
}
static ulong
gbit32(void *a)
{
ulong j;
uchar *i;
i = a;
j = i[3] << 24;
j |= i[2] << 16;
j |= i[1] << 8;
j |= i[0];
return j;
}
static uvlong
gbit64(void *a)
{
uchar *i;
i = a;
return (uvlong)gbit32(i+4)<<32 | gbit32(i);
}
static int
identify(Ctlr *c, ushort *id)
{
int i;
uchar oserial[21];
uvlong osectors, s;
vlong osectors, s;
osectors = c->sectors;
memmove(oserial, c->serial, sizeof c->serial);
c->feat &= ~(Dllba|Dpower|Dsmart|Dnop);
i = gbit16(id+83) | gbit16(id+86);
if(i & (1<<10)){
c->feat |= Dllba;
s = gbit64(id+100);
}else
s = gbit32(id+60);
i = gbit16(id+83);
if((i>>14) == 1) {
if(i & (1<<3))
c->feat |= Dpower;
i = gbit16(id+82);
if(i & 1)
c->feat |= Dsmart;
if(i & (1<<14))
c->feat |= Dnop;
s = idfeat(c, id);
if(s == -1){
uprint("%s: identify fails", c->unit->name);
print("%s\n", up->genbuf);
error(up->genbuf);
}
aoeidmove(c->serial, id+10, 20);
aoeidmove(c->firmware, id+23, 8);
aoeidmove(c->model, id+27, 40);
idmove(c->serial, id+10, 20);
idmove(c->firmware, id+23, 8);
idmove(c->model, id+27, 40);
if((osectors == 0 || osectors != s) &&
memcmp(oserial, c->serial, sizeof oserial) != 0){
c->sectors = s;
c->mediachange = 1;
c->drivechange = 1;
c->vers++;
}
return 0;
}
static void
aoectl(Ctlr *d, char *s)
{
Chan *c;
c = nil;
if(waserror()){
if(c)
cclose(c);
print("sdaoectl: %s\n", up->errstr);
nexterror();
}
uprint("%s/ctl", d->path);
c = namec(up->genbuf, Aopen, OWRITE, 0);
devtab[c->type]->write(c, s, strlen(s), 0);
poperror();
cclose(c);
}
/* must call with d qlocked */
static int
aoeidentify(Ctlr *d, SDunit *u)
@ -173,7 +123,6 @@ aoeidentify(Ctlr *d, SDunit *u)
cclose(c);
d->feat = 0;
d->smart = 0;
identify(d, (ushort*)d->ident);
memset(u->inquiry, 0, sizeof u->inquiry);
@ -203,7 +152,6 @@ newctlr(char *path)
{
Ctlr *c;
/* race? */
if(ctlrlookup(path))
error(Eexist);
@ -248,7 +196,6 @@ delctlr(Ctlr *c)
free(x);
}
/* don't call aoeprobe from within a loop; it loops internally retrying open. */
static SDev*
aoeprobe(char *path, SDev *s)
{
@ -273,21 +220,24 @@ aoeprobe(char *path, SDev *s)
poperror();
cclose(c);
for(i = 0; i < Probemax; i++){
for(i = 0;; i += Probeintvl){
if(i > Probemax || waserror())
error(Etimedout);
tsleep(&up->sleep, return0, 0, Probeintvl);
poperror();
uprint("%s/ident", path);
if(!waserror()) {
c = namec(up->genbuf, Aopen, OREAD, 0);
poperror();
cclose(c);
break;
}
if(waserror())
continue;
c = namec(up->genbuf, Aopen, OREAD, 0);
poperror();
cclose(c);
ctlr = newctlr(path);
break;
}
if(i >= Probemax)
error(Etimedout);
uprint("%s/ident", path);
ctlr = newctlr(path);
if(ctlr == nil || s == nil && (s = malloc(sizeof *s)) == nil)
if(s == nil && (s = malloc(sizeof *s)) == nil)
return nil;
s->ctlr = ctlr;
s->ifc = &sdaoeifc;
@ -296,14 +246,20 @@ aoeprobe(char *path, SDev *s)
}
static char *probef[32];
static char *probebuf;
static int nprobe;
static int
pnpprobeid(char *s)
{
int id;
if(strlen(s) < 2)
return 0;
return s[1] == '!'? s[0]: 'e';
id = 'e';
if(s[1] == '!')
id = s[0];
return id;
}
static SDev*
@ -315,7 +271,8 @@ aoepnp(void)
if((p = getconf("aoedev")) == 0)
return 0;
nprobe = tokenize(p, probef, nelem(probef));
kstrdup(&probebuf, p);
nprobe = tokenize(probebuf, probef, nelem(probef));
h = t = 0;
for(i = 0; i < nprobe; i++){
id = pnpprobeid(probef[i]);
@ -341,7 +298,7 @@ aoepnp(void)
static Ctlr*
pnpprobe(SDev *sd)
{
ulong start;
int j;
char *p;
static int i;
@ -353,17 +310,21 @@ pnpprobe(SDev *sd)
if(p[1] == '!')
p += 2;
start = TK2MS(MACHP(0)->ticks);
if(waserror()){
print("#æ: pnpprobe failed in %lud ms: %s: %s\n",
TK2MS(MACHP(0)->ticks) - start, probef[i-1],
up->errstr);
return nil;
for(j = 0;; j += Probeintvl){
if(j > Probemax){
print("#æ: pnpprobe: %s: %s\n", probef[i-1], up->errstr);
return 0;
}
if(waserror()){
tsleep(&up->sleep, return0, 0, Probeintvl);
continue;
}
sd = aoeprobe(p, sd);
poperror();
break;
}
sd = aoeprobe(p, sd); /* does a round of probing */
poperror();
print("#æ: pnpprobe established %s in %lud ms\n",
probef[i-1], TK2MS(MACHP(0)->ticks) - start);
print("#æ: pnpprobe establishes %s in %dms\n", probef[i-1], j);
aoectl(sd->ctlr, "nofail on");
return sd->ctlr;
}
@ -378,7 +339,7 @@ aoeverify(SDunit *u)
c = s->ctlr;
if(c == nil && (s->ctlr = c = pnpprobe(s)) == nil)
return 0;
c->mediachange = 1;
c->drivechange = 1;
return 1;
}
@ -412,17 +373,17 @@ aoeonline(SDunit *u)
c = u->dev->ctlr;
r = 0;
if((c->feat&Datapi) && c->mediachange){
if((c->feat&Datapi) && c->drivechange){
if(aoeconnect(u, c) == 0 && (r = scsionline(u)) > 0)
c->mediachange = 0;
c->drivechange = 0;
return r;
}
if(c->mediachange){
if(c->drivechange){
if(aoeconnect(u, c) == -1)
return 0;
r = 2;
c->mediachange = 0;
c->drivechange = 0;
u->sectors = c->sectors;
u->secsize = Aoesectsz;
} else
@ -431,103 +392,70 @@ aoeonline(SDunit *u)
return r;
}
static int
aoerio(SDreq *r)
static long
aoebio(SDunit *u, int, int write, void *a, long count, uvlong lba)
{
int i, count;
uvlong lba;
char *name;
uchar *cmd;
uchar *data;
int n;
long (*rio)(Chan*, void*, long, vlong);
Ctlr *c;
SDunit *unit;
unit = r->unit;
c = unit->dev->ctlr;
c = u->dev->ctlr;
// if(c->feat & Datapi)
// return aoeriopkt(r, d);
cmd = r->cmd;
name = unit->name;
if(r->cmd[0] == 0x35 || r->cmd[0] == 0x91){
// qlock(c);
// i = flushcache();
// qunlock(c);
// if(i == 0)
// return sdsetsense(r, SDok, 0, 0, 0);
return sdsetsense(r, SDcheck, 3, 0xc, 2);
}
if((i = sdfakescsi(r, c->ident, sizeof c->ident)) != SDnostatus){
r->status = i;
return i;
}
switch(*cmd){
case 0x88:
case 0x28:
rio = devtab[c->c->type]->read;
break;
case 0x8a:
case 0x2a:
// return scsibio(u, lun, write, a, count, lba);
data = a;
if(write)
rio = devtab[c->c->type]->write;
break;
default:
print("%s: bad cmd %#.2ux\n", name, cmd[0]);
r->status = SDcheck;
return SDcheck;
}
if(r->data == nil)
return SDok;
if(r->clen == 16){
if(cmd[2] || cmd[3])
return sdsetsense(r, SDcheck, 3, 0xc, 2);
lba = (uvlong)cmd[4]<<40 | (uvlong)cmd[5]<<32;
lba |= cmd[6]<<24 | cmd[7]<<16 | cmd[8]<<8 | cmd[9];
count = cmd[10]<<24 | cmd[11]<<16 | cmd[12]<<8 | cmd[13];
}else{
lba = cmd[2]<<24 | cmd[3]<<16 | cmd[4]<<8 | cmd[5];
count = cmd[7]<<8 | cmd[8];
}
count *= Aoesectsz;
if(r->dlen < count)
count = r->dlen & ~0x1ff;
else
rio = devtab[c->c->type]->read;
if(waserror()){
if(strcmp(up->errstr, Echange) == 0 ||
strcmp(up->errstr, Enotup) == 0)
unit->sectors = 0;
u->sectors = 0;
nexterror();
}
r->rlen = rio(c->c, r->data, count, Aoesectsz * lba);
n = rio(c->c, data, Aoesectsz * count, Aoesectsz * lba);
poperror();
r->status = SDok;
return SDok;
return n;
}
static char *smarttab[] = {
"unset",
"error",
"threshold exceeded",
"normal"
};
static char *
pflag(char *s, char *e, uchar f)
static int
flushcache(Ctlr *)
{
uchar i, m;
return -1;
}
for(i = 0; i < 8; i++){
m = 1 << i;
if(f & m)
s = seprint(s, e, "%s ", flagname[i]);
static int
aoerio(SDreq *r)
{
int i, count, rw;
uvlong lba;
Ctlr *c;
SDunit *u;
u = r->unit;
c = u->dev->ctlr;
// if(c->feat & Datapi)
// return aoeriopkt(r, d);
if(r->cmd[0] == 0x35 || r->cmd[0] == 0x91){
qlock(c);
i = flushcache(c);
qunlock(c);
if(i == 0)
return sdsetsense(r, SDok, 0, 0, 0);
return sdsetsense(r, SDcheck, 3, 0xc, 2);
}
return seprint(s, e, "\n");
if((i = sdfakescsi(r)) != SDnostatus){
r->status = i;
return i;
}
if((i = sdfakescsirw(r, &lba, &count, &rw)) != SDnostatus)
return i;
r->rlen = aoebio(u, r->lun, rw == SDwrite, r->data, count, lba);
return r->status = SDok;
}
static int
@ -544,14 +472,8 @@ aoerctl(SDunit *u, char *p, int l)
p = seprint(p, e, "model\t%s\n", c->model);
p = seprint(p, e, "serial\t%s\n", c->serial);
p = seprint(p, e, "firm %s\n", c->firmware);
if(c->smartrs == 0xff)
p = seprint(p, e, "smart\tenable error\n");
else if(c->smartrs == 0)
p = seprint(p, e, "smart\tdisabled\n");
else
p = seprint(p, e, "smart\t%s\n", smarttab[c->smart]);
p = seprint(p, e, "flag ");
p = pflag(p, e, c->feat);
p = pflag(p, e, c);
p = seprint(p, e, "geometry %llud %d\n", c->sectors, Aoesectsz);
return p-op;
}
@ -590,7 +512,7 @@ aoertopctl(SDev *s, char *p, char *e)
Ctlr *c;
c = s->ctlr;
return seprint(p, e, "%s aoe %s\n", s->name, c->path);
return seprint(p, e, "%s aoe %s\n", s->name, c? c->path: "");
}
static int
@ -617,7 +539,7 @@ SDifc sdaoeifc = {
aoerctl,
aoewctl,
scsibio,
aoebio,
aoeprobew, /* probe */
aoeclear, /* clear */
aoertopctl,

415
sys/src/9/port/sdloop.c Normal file
View File

@ -0,0 +1,415 @@
/*
* sd loopback driver,
* copyright © 2009-10 erik quanstrom
*/
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "../port/error.h"
#include "../port/sd.h"
#include "../port/netif.h"
extern char Echange[];
extern char Enotup[];
#define uprint(...) snprint(up->genbuf, sizeof up->genbuf, __VA_ARGS__);
enum {
Maxpath = 256,
Devsectsize = 512,
};
typedef struct Ctlr Ctlr;
struct Ctlr {
QLock;
Ctlr *next;
SDunit *unit;
char path[Maxpath];
Chan *c;
uint vers;
uchar drivechange;
uvlong sectors;
uint sectsize;
};
static Lock ctlrlock;
static Ctlr *head;
static Ctlr *tail;
SDifc sdloopifc;
/* must call with c qlocked */
static void
identify(Ctlr *c, SDunit *u)
{
int n;
uvlong s, osectors;
uchar buf[sizeof(Dir) + 100];
Dir dir;
if(waserror()){
iprint("sdloop: identify: %s\n", up->errstr);
nexterror();
}
osectors = c->sectors;
n = devtab[c->c->type]->stat(c->c, buf, sizeof buf);
if(convM2D(buf, n, &dir, nil) == 0)
error("internal error: stat error in seek");
s = dir.length / c->sectsize;
poperror();
memset(u->inquiry, 0, sizeof u->inquiry);
u->inquiry[2] = 2;
u->inquiry[3] = 2;
u->inquiry[4] = sizeof u->inquiry - 4;
memmove(u->inquiry+8, c->path, 40);
if(osectors == 0 || osectors != s){
c->sectors = s;
c->drivechange = 1;
c->vers++;
}
}
static Ctlr*
ctlrlookup(char *path)
{
Ctlr *c;
lock(&ctlrlock);
for(c = head; c; c = c->next)
if(strcmp(c->path, path) == 0)
break;
unlock(&ctlrlock);
return c;
}
static Ctlr*
newctlr(char *path)
{
Ctlr *c;
if(ctlrlookup(path))
error(Eexist);
if((c = malloc(sizeof *c)) == nil)
error(Enomem);
if(waserror()){
free(c);
nexterror();
}
c->c = namec(path, Aopen, ORDWR, 0);
poperror();
kstrcpy(c->path, path, sizeof c->path);
lock(&ctlrlock);
if(head != nil)
tail->next = c;
else
head = c;
tail = c;
unlock(&ctlrlock);
return c;
}
static void
delctlr(Ctlr *c)
{
Ctlr *x, *prev;
lock(&ctlrlock);
for(prev = 0, x = head; x; prev = x, x = c->next)
if(strcmp(c->path, x->path) == 0)
break;
if(x == 0){
unlock(&ctlrlock);
error(Enonexist);
}
if(prev)
prev->next = x->next;
else
head = x->next;
if(x->next == nil)
tail = prev;
unlock(&ctlrlock);
if(x->c)
cclose(x->c);
free(x);
}
static SDev*
probe(char *path, SDev *s)
{
char *p;
uint sectsize;
Ctlr *c;
sectsize = 0;
if(p = strchr(path, '!')){
*p = 0;
sectsize = strtoul(p + 1, 0, 0);
}
c = newctlr(path);
c->sectsize = sectsize? sectsize: Devsectsize;
if(s == nil && (s = malloc(sizeof *s)) == nil)
return nil;
s->ctlr = c;
s->ifc = &sdloopifc;
s->nunit = 1;
return s;
}
static char *probef[32];
static int nprobe;
static int
pnpprobeid(char *s)
{
int id;
if(strlen(s) < 2)
return 0;
id = 'l';
if(s[1] == '!')
id = s[0];
return id;
}
static SDev*
pnp(void)
{
int i, id;
char *p;
SDev *h, *t, *s;
if((p = getconf("loopdev")) == 0)
return 0;
nprobe = tokenize(p, probef, nelem(probef));
h = t = 0;
for(i = 0; i < nprobe; i++){
id = pnpprobeid(probef[i]);
if(id == 0)
continue;
s = malloc(sizeof *s);
if(s == nil)
break;
s->ctlr = 0;
s->idno = id;
s->ifc = &sdloopifc;
s->nunit = 1;
if(h)
t->next = s;
else
h = s;
t = s;
}
return h;
}
static Ctlr*
pnpprobe(SDev *s)
{
char *p;
static int i;
if(i > nprobe)
return 0;
p = probef[i++];
if(strlen(p) < 2)
return 0;
if(p[1] == '!')
p += 2;
s = probe(p, s);
return s->ctlr;
}
static int
loopverify(SDunit *u)
{
SDev *s;
Ctlr *c;
s = u->dev;
c = s->ctlr;
if(c == nil){
if(waserror())
return 0;
s->ctlr = c = pnpprobe(s);
poperror();
}
c->drivechange = 1;
return 1;
}
static int
connect(SDunit *u, Ctlr *c)
{
qlock(c);
if(waserror()){
qunlock(c);
return -1;
}
identify(u->dev->ctlr, u);
qunlock(c);
poperror();
return 0;
}
static int
looponline(SDunit *u)
{
Ctlr *c;
int r;
c = u->dev->ctlr;
if(c->drivechange){
if(connect(u, c) == -1)
return 0;
r = 2;
c->drivechange = 0;
u->sectors = c->sectors;
u->secsize = c->sectsize;
} else
r = 1;
return r;
}
static long
loopbio(SDunit *u, int, int write, void *a, long count, uvlong lba)
{
uchar *data;
int n;
long (*rio)(Chan*, void*, long, vlong);
Ctlr *c;
c = u->dev->ctlr;
data = a;
if(write)
rio = devtab[c->c->type]->write;
else
rio = devtab[c->c->type]->read;
if(waserror()){
if(strcmp(up->errstr, Echange) == 0 ||
strcmp(up->errstr, Enotup) == 0)
u->sectors = 0;
nexterror();
}
n = rio(c->c, data, c->sectsize * count, c->sectsize * lba);
poperror();
return n;
}
static int
looprio(SDreq *r)
{
int i, count, rw;
uvlong lba;
SDunit *u;
u = r->unit;
if(r->cmd[0] == 0x35 || r->cmd[0] == 0x91)
return sdsetsense(r, SDok, 0, 0, 0);
if((i = sdfakescsi(r)) != SDnostatus)
return r->status = i;
if((i = sdfakescsirw(r, &lba, &count, &rw)) != SDnostatus)
return i;
r->rlen = loopbio(u, r->lun, rw == SDwrite, r->data, count, lba);
return r->status = SDok;
}
static int
looprctl(SDunit *u, char *p, int l)
{
Ctlr *c;
char *e, *op;
if((c = u->dev->ctlr) == nil)
return 0;
e = p+l;
op = p;
p = seprint(p, e, "path\t%s\n", c->path);
p = seprint(p, e, "geometry %llud %d\n", c->sectors, c->sectsize);
return p - op;
}
static int
loopwctl(SDunit *, Cmdbuf *cmd)
{
cmderror(cmd, Ebadarg);
return 0;
}
static SDev*
loopprobew(DevConf *c)
{
char *p;
p = strchr(c->type, '/');
if(p == nil || strlen(p) > Maxpath - 1)
error(Ebadarg);
p++;
if(ctlrlookup(p))
error(Einuse);
return probe(p, 0);
}
static void
loopclear(SDev *s)
{
delctlr((Ctlr *)s->ctlr);
}
static char*
looprtopctl(SDev *s, char *p, char *e)
{
Ctlr *c;
c = s->ctlr;
return seprint(p, e, "%s loop %s\n", s->name, c? c->path: "");
}
static int
loopwtopctl(SDev *, Cmdbuf *cmd)
{
switch(cmd->nf){
default:
cmderror(cmd, Ebadarg);
}
return 0;
}
SDifc sdloopifc = {
"loop",
pnp,
nil, /* legacy */
nil, /* enable */
nil, /* disable */
loopverify,
looponline,
looprio,
looprctl,
loopwctl,
loopbio,
loopprobew, /* probe */
loopclear, /* clear */
looprtopctl,
loopwtopctl,
};

View File

@ -153,7 +153,8 @@ scsirio(SDreq* r)
/*
* If no medium present, bail out.
* If unit is becoming ready, rather than not
* not ready, wait a little then poke it again. */
* not ready, wait a little then poke it again.
*/
if(r->sense[12] == 0x3A)
break;
if(r->sense[12] != 0x04 || r->sense[13] != 0x01)
@ -175,22 +176,91 @@ scsirio(SDreq* r)
return -1;
}
static void
cap10(SDreq *r)
{
r->cmd[0] = 0x25;
r->cmd[1] = r->lun<<5;
r->clen = 10;
r->dlen = 8;
}
static void
cap16(SDreq *r)
{
uint i;
i = 32;
r->cmd[0] = 0x9e;
r->cmd[1] = 0x10;
r->cmd[10] = i>>24;
r->cmd[11] = i>>16;
r->cmd[12] = i>>8;
r->cmd[13] = i;
r->clen = 16;
r->dlen = i;
}
static uint
belong(uchar *u)
{
return u[0]<<24 | u[1]<<16 | u[2]<<8 | u[3];
}
static uvlong
capreply(SDreq *r, ulong *secsize)
{
uchar *u;
ulong ss;
uvlong s;
*secsize = 0;
u = r->data;
if(r->clen == 16){
s = (uvlong)belong(u)<<32 | belong(u + 4);
ss = belong(u + 8);
}else{
s = belong(u);
ss = belong(u + 4);
}
/*
* Some ATAPI CD readers lie about the block size.
* Since we don't read audio via this interface
* it's okay to always fudge this.
*/
if(ss == 2352)
ss = 2048;
/*
* Devices with removable media may return 0 sectors
* when they have empty media (e.g. sata dvd writers);
* if so, keep the count zero.
*
* Read-capacity returns the LBA of the last sector,
* therefore the number of sectors must be incremented.
*/
if(s != 0)
s++;
*secsize = ss;
return s;
}
int
scsionline(SDunit* unit)
{
SDreq *r;
uchar *p;
int ok, retries;
void (*cap)(SDreq*);
if((r = malloc(sizeof(SDreq))) == nil)
if((r = malloc(sizeof *r)) == nil)
return 0;
if((p = sdmalloc(8)) == nil){
if((p = sdmalloc(32)) == nil){
free(r);
return 0;
}
ok = 0;
cap = cap10;
r->unit = unit;
r->lun = 0; /* ??? */
for(retries = 0; retries < 10; retries++){
@ -201,39 +271,21 @@ scsionline(SDunit* unit)
* plain slow getting their act together after a reset.
*/
r->write = 0;
memset(r->cmd, 0, sizeof(r->cmd));
r->cmd[0] = 0x25;
r->cmd[1] = r->lun<<5;
r->clen = 10;
r->data = p;
r->dlen = 8;
r->flags = 0;
memset(r->cmd, 0, sizeof r->cmd);
cap(r);
r->status = ~0;
switch(scsirio(r)){
default:
break;
case 0:
unit->sectors = (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3];
unit->secsize = (p[4]<<24)|(p[5]<<16)|(p[6]<<8)|p[7];
/*
* Some ATAPI CD readers lie about the block size.
* Since we don't read audio via this interface
* it's okay to always fudge this.
*/
if(unit->secsize == 2352)
unit->secsize = 2048;
/*
* Devices with removable media may return 0 sectors
* when they have empty media (e.g. sata dvd writers);
* if so, keep the count zero.
*
* Read-capacity returns the LBA of the last sector,
* therefore the number of sectors must be incremented.
*/
if(unit->sectors != 0)
unit->sectors++;
unit->sectors = capreply(r, &unit->secsize);
if(unit->sectors == 0xffffffff && cap == cap10){
cap = cap16;
continue;
}
ok = 1;
break;
case 1:
@ -253,56 +305,6 @@ scsionline(SDunit* unit)
return 0;
}
int
scsiexec(SDunit* unit, int write, uchar* cmd, int clen, void* data, int* dlen)
{
SDreq *r;
int status;
if((r = malloc(sizeof(SDreq))) == nil)
return SDmalloc;
r->unit = unit;
r->lun = cmd[1]>>5; /* ??? */
r->write = write;
memmove(r->cmd, cmd, clen);
r->clen = clen;
r->data = data;
if(dlen)
r->dlen = *dlen;
r->flags = 0;
r->status = ~0;
/*
* Call the device-specific I/O routine.
* There should be no calls to 'error()' below this
* which percolate back up.
*/
switch(status = unit->dev->ifc->rio(r)){
case SDok:
if(dlen)
*dlen = r->rlen;
/*FALLTHROUGH*/
case SDcheck:
/*FALLTHROUGH*/
default:
/*
* It's more complicated than this. There are conditions
* which are 'ok' but for which the returned status code
* is not 'SDok'.
* Also, not all conditions require a reqsense, might
* need to do a reqsense here and make it available to the
* caller somehow.
*
* Mañana.
*/
break;
}
sdfree(r);
return status;
}
static void
scsifmt10(SDreq *r, int write, int lun, ulong nb, uvlong bno)
{
@ -367,7 +369,7 @@ scsibio(SDunit* unit, int lun, int write, void* data, long nb, uvlong bno)
r->lun = lun;
again:
r->write = write;
if(bno >= (1ULL<<32))
if(bno > 0xffffffff)
scsifmt16(r, write, lun, nb, bno);
else
scsifmt10(r, write, lun, nb, bno);
@ -381,8 +383,19 @@ again:
rlen = -1;
break;
case 0:
rlen = r->rlen;
break;
/*
* scsi allows commands to return successfully
* but return sense data, indicating that the
* operation didn't proceed as expected.
* (confusing, no). this allows the raw commands
* to successfully return errors. but any sense
* data bio sees must be an error. bomb out.
*/
if(r->status == SDok && r->rlen > 0
&& ((r->flags & SDvalidsense) == 0 || r->sense[2] == 0)){
rlen = r->rlen;
break;
}
case 2:
rlen = -1;
if(!(r->flags & SDvalidsense))
@ -415,6 +428,10 @@ again:
goto again;
break;
}
snprint(up->genbuf, sizeof up->genbuf, "%s %.2ux%.2ux%.2ux %lld",
Eio, r->sense[2], r->sense[12], r->sense[13], bno);
free(r);
error(up->genbuf);
break;
}
free(r);

545
sys/src/libfis/fis.c Normal file
View File

@ -0,0 +1,545 @@
/*
* sata fises and sas frames
* copyright © 2009-2010 erik quanstrom
*/
#include <u.h>
#include <libc.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, uint sig)
{
x->sig = sig;
}
void
skelfis(uchar *c)
{
memset(c, 0, Fissize);
c[Ftype] = H2dev;
c[Fflags] = Fiscmd;
c[Fdev] = Ataobs;
}
int
nopfis(Sfis*, uchar *c, int srst)
{
skelfis(c);
if(srst){
c[Fflags] &= ~Fiscmd;
c[Fcontrol] = 1<<2;
return Preset|P28;
}
return Pnd|P28;
}
int
txmodefis(Sfis *f, uchar *c, uchar 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*, uchar *c, uchar f)
{
skelfis(c);
c[Fcmd] = 0xef;
c[Ffeat] = f;
return Pnd|P28;
}
int
identifyfis(Sfis *f, uchar *c)
{
static uchar tab[] = { 0xec, 0xa1, };
skelfis(c);
c[Fcmd] = tab[f->sig>>16 == 0xeb14];
return Pin|Ppio|P28|P512;
}
int
flushcachefis(Sfis *f, uchar *c)
{
static uchar tab[2] = {0xe7, 0xea};
static uchar ptab[2] = {Pnd|P28, Pnd|P48};
int llba;
llba = (f->feat & Dllba) != 0;
skelfis(c);
c[Fcmd] = tab[llba];
return ptab[llba];
}
static ushort
gbit16(void *a)
{
ushort j;
uchar *i;
i = a;
j = i[1] << 8;
j |= i[0];
return j;
}
static uint
gbit32(void *a)
{
uint j;
uchar *i;
i = a;
j = i[3] << 24;
j |= i[2] << 16;
j |= i[1] << 8;
j |= i[0];
return j;
}
static uvlong
gbit64(void *a)
{
uchar *i;
i = a;
return (uvlong)gbit32(i+4) << 32 | gbit32(a);
}
ushort
id16(ushort *id, int i)
{
return gbit16(id+i);
}
uint
id32(ushort *id, int i)
{
return gbit32(id+i);
}
uvlong
id64(ushort *id, int i)
{
return gbit64(id+i);
}
/* acs-2 §7.18.7.4 */
static ushort puistab[] = {
0x37c8, Pspinup,
0x738c, Pspinup | Pidready,
0x8c73, 0,
0xc837, Pidready,
};
int
idpuis(ushort *id)
{
ushort 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 ushort
onesc(ushort *id)
{
ushort u;
u = gbit16(id);
if(u == 0xffff)
u = 0;
return u;
}
enum{
Idmasp = 1<<8,
Ilbasp = 1<<9,
Illba = 1<<10,
};
vlong
idfeat(Sfis *f, ushort *id)
{
int i, j;
vlong s;
f->feat = 0;
if(f->sig>>16 == 0xeb14)
f->feat |= Datapi;
i = gbit16(id + 49);
if((i & Ilbasp) == 0){
if(gbit16(id + 53) & 1){
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, ushort *id)
{
uint 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);
}
uvlong
idwwn(Sfis*, ushort *id)
{
uvlong u;
u = 0;
if(id[108]>>12 == 5){
u |= (uvlong)gbit16(id + 108) << 48;
u |= (uvlong)gbit16(id + 109) << 32;
u |= gbit16(id + 110) << 16;
u |= gbit16(id + 111) << 0;
}
return u;
}
void
idmove(char *p, ushort *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++;
memmove(op, p, n - (e - p));
}
char*
pflag(char *s, char *e, Sfis *f)
{
ushort i, u;
u = f->feat;
for(i = 0; i < Dnflag; i++)
if(u & (1 << i))
s = seprint(s, e, "%s ", flagname[i]);
return seprint(s, e, "\n");
}
int
atapirwfis(Sfis *f, uchar *c, uchar *cdb, int cdblen, int ndata)
{
int fill, len;
fill = f->feat&Datapi16? 16: 12;
if((len = cdblen) > fill)
len = fill;
memmove(c + 0x40, cdb, len);
memset(c + 0x40 + len, 0, fill - len);
c[Ftype] = H2dev;
c[Fflags] = Fiscmd;
c[Fcmd] = Ataobs;
if(ndata != 0)
c[Ffeat] = 1; /* dma */
else
c[Ffeat] = 0; /* features (exp); */
c[Flba0] = 0;
c[Flba8] = ndata;
c[Flba16] = ndata >> 8;
c[Fdev] = Ataobs;
memset(c + 8, 0, Fissize - 8);
return P28|Ppkt;
}
int
rwfis(Sfis *f, uchar *c, int rw, int nsect, uvlong lba)
{
uchar acmd, llba, udma;
static uchar tab[2][2][2] = { 0x20, 0x24, 0x30, 0x34, 0xc8, 0x25, 0xca, 0x35, };
static uchar 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;
memset(c + 16, 0, Fissize - 16);
return ptab[udma][rw][llba];
}
uvlong
fisrw(Sfis *f, uchar *c, int *n)
{
uvlong lba;
lba = c[Flba0];
lba |= c[Flba8] << 8;
lba |= c[Flba16] << 16;
lba |= c[Flba24] << 24;
lba |= (uvlong)(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, uchar *c)
{
uint u;
u = f->sig;
memset(c, 0, Fissize);
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;
}
uint
fistosig(uchar *u)
{
return u[Fsc] | u[Flba0]<<8 | u[Flba8]<<16 | u[Flba16]<<24;
}
/* sas smp */
void
smpskelframe(Cfis *f, uchar *c, int m)
{
memset(c, 0, Fissize);
c[Ftype] = 0x40;
c[Fflags] = m;
if(f->phyid)
c[Flba32] = f->phyid;
}
uint
sashash(uvlong u)
{
uint poly, msb, l, r;
uvlong 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;
}
uchar*
sasbhash(uchar *t, uchar *s)
{
uint 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;
}

15
sys/src/libfis/mkfile Normal file
View File

@ -0,0 +1,15 @@
</$objtype/mkfile
LIB=/$objtype/lib/libfis.a
OFILES=\
fis.$O\
HFILES=/sys/include/fis.h
UPDATE=\
mkfile\
$HFILES\
${OFILES:%.$O=%.c}\
${LIB:/$objtype/%=/386/%}\
</sys/src/cmd/mksyslib