merge sd changes from 9atom

This commit is contained in:
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) * 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 */ /* pci configuration */
enum { enum {
Abar = 5, Abar = 5,
@ -47,26 +21,25 @@ enum {
/* cap bits: supported features */ /* cap bits: supported features */
enum { enum {
Hs64a = 1<<31, /* 64-bit addressing */ H64a = 1<<31, /* 64-bit addressing */
Hsncq = 1<<30, /* ncq */ Hncq = 1<<30, /* ncq */
Hssntf = 1<<29, /* snotification reg. */ Hsntf = 1<<29, /* snotification reg. */
Hsmps = 1<<28, /* mech pres switch */ Hmps = 1<<28, /* mech pres switch */
Hsss = 1<<27, /* staggered spinup */ Hss = 1<<27, /* staggered spinup */
Hsalp = 1<<26, /* aggressive link pm */ Halp = 1<<26, /* aggressive link pm */
Hsal = 1<<25, /* activity led */ Hal = 1<<25, /* activity led */
Hsclo = 1<<24, /* command-list override */ Hclo = 1<<24, /* command-list override */
Hiss = 1<<20, /* for interface speed */ Hiss = 1<<20, /* for interface speed */
// Hsnzo = 1<<19, Ham = 1<<18, /* ahci-mode only */
Hsam = 1<<18, /* ahci-mode only */ Hpm = 1<<17, /* port multiplier */
Hspm = 1<<17, /* port multiplier */ Hfbs = 1<<16, /* fis-based switching */
// Hfbss = 1<<16,
Hpmb = 1<<15, /* multiple-block pio */ Hpmb = 1<<15, /* multiple-block pio */
Hssc = 1<<14, /* slumber state */ Hssc = 1<<14, /* slumber state */
Hpsc = 1<<13, /* partial-slumber state */ Hpsc = 1<<13, /* partial-slumber state */
Hncs = 1<<8, /* n command slots */ Hncs = 1<<8, /* n command slots */
Hcccs = 1<<7, /* coal */ Hcccs = 1<<7, /* coal */
Hems = 1<<6, /* enclosure mgmt. */ Hems = 1<<6, /* enclosure mgmt. */
Hsxs = 1<<5, /* external sata */ Hxs = 1<<5, /* external sata */
Hnp = 1<<0, /* n ports */ Hnp = 1<<0, /* n ports */
}; };
@ -77,6 +50,29 @@ enum {
Hhr = 1<<0, /* hba reset */ 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 { typedef struct {
ulong cap; ulong cap;
ulong ghc; ulong ghc;
@ -87,6 +83,8 @@ typedef struct {
ulong cccports; ulong cccports;
ulong emloc; ulong emloc;
ulong emctl; ulong emctl;
ulong cap2;
ulong bios;
} Ahba; } Ahba;
enum { enum {
@ -147,6 +145,8 @@ enum {
Aalpe = 1<<26, /* aggressive link pm enable */ Aalpe = 1<<26, /* aggressive link pm enable */
Adlae = 1<<25, /* drive led on atapi */ Adlae = 1<<25, /* drive led on atapi */
Aatapi = 1<<24, /* device is 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 */ Aesp = 1<<21, /* external sata port */
Acpd = 1<<20, /* cold presence detect */ Acpd = 1<<20, /* cold presence detect */
Ampsp = 1<<19, /* mechanical pres. */ Ampsp = 1<<19, /* mechanical pres. */
@ -164,6 +164,7 @@ enum {
Ast = 1<<0, /* start */ Ast = 1<<0, /* start */
Arun = Ast|Acr|Afre|Afr, Arun = Ast|Acr|Afre|Afr,
Apwr = Apod|Asud,
}; };
/* ctl register bits */ /* ctl register bits */
@ -173,13 +174,41 @@ enum {
Adet = 1<<0, /* device detection */ 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 sstatus scr0
#define sctl scr2 #define sctl scr2
#define serror scr1 #define serror scr1
#define sactive scr3 #define sactive scr3
#define ntf scr4
typedef struct { typedef struct {
ulong list; /* PxCLB must be 1kb aligned. */ ulong list; /* PxCLB must be 1kb aligned */
ulong listhi; ulong listhi;
ulong fis; /* 256-byte aligned */ ulong fis; /* 256-byte aligned */
ulong fishi; ulong fishi;
@ -194,9 +223,10 @@ typedef struct {
ulong scr1; ulong scr1;
ulong scr3; ulong scr3;
ulong ci; /* command issue */ ulong ci; /* command issue */
ulong ntf; ulong scr4;
uchar res2[8]; ulong fbs;
ulong vendor; ulong res2[11];
ulong vendor[4];
} Aport; } Aport;
/* in host's memory; not memory mapped */ /* in host's memory; not memory mapped */
@ -244,26 +274,49 @@ typedef struct {
Aprdt prdt; Aprdt prdt;
} Actab; } 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 { enum {
Ferror = 1, Ferror = 1,
Fdone = 2, Fdone = 2,
}; };
enum {
Dllba = 1,
Dsmart = 1<<1,
Dpower = 1<<2,
Dnop = 1<<3,
Datapi = 1<<4,
Datapi16= 1<<5,
};
typedef struct { typedef struct {
QLock; QLock;
Rendez; Rendez;
uchar flag; uchar flag;
uchar feat; Sfis;
uchar smart;
Afis fis; Afis fis;
Alist *list; Alist *list;
Actab *ctab; Actab *ctab;

View file

@ -67,6 +67,7 @@ LIB=\
/$objtype/lib/libc.a\ /$objtype/lib/libc.a\
/$objtype/lib/libsec.a\ /$objtype/lib/libsec.a\
/$objtype/lib/libmp.a\ /$objtype/lib/libmp.a\
/$objtype/lib/libfis.a\
ETHER=`{echo devether.c ether*.c | sed 's/\.c/.'$O'/g'} ETHER=`{echo devether.c ether*.c | sed 's/\.c/.'$O'/g'}
VGA=`{echo devvga.c screen.c vga*.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 uarti8250
uartpci pci uartpci pci
sdata pci sdscsi sdaoe
sdide pci sdscsi
sd53c8xx pci sdscsi sd53c8xx pci sdscsi
sdmylex pci sdscsi sdmylex pci sdscsi
sdiahci pci sdscsi sdiahci pci sdscsi led
sdaoe sdodin pci sdscsi led
sdloop
vga3dfx +cur vga3dfx +cur
vgaark2000pv +cur vgaark2000pv +cur

View file

@ -81,11 +81,13 @@ misc
archmp mp apic archmp mp apic
mtrr mtrr
sdata pci sdscsi sdaoe
sdide pci sdscsi
sd53c8xx pci sdscsi sd53c8xx pci sdscsi
sdmylex pci sdscsi sdmylex pci sdscsi
sdiahci pci sdscsi sdiahci pci sdscsi led
sdaoe sdodin pci sdscsi led
sdloop
uarti8250 uarti8250
uartpci pci 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; Ctlr *ctlr;
uchar cmd[6], data[256]; uchar cmd[6], data[256];
int clen, dlen, timeo; int clen, dlen, timeo;
static int count;
if(ioalloc(port, 0x3, 0, "mylex") < 0) if(ioalloc(port, 0x3, 0, "mylex") < 0)
return nil; return nil;
@ -894,18 +893,13 @@ buggery:
if(issue(ctlr, cmd, clen, data, dlen)){ if(issue(ctlr, cmd, clen, data, dlen)){
if(data[0] == 'E') if(data[0] == 'E')
ctlr->bus = 32; ctlr->bus = 32;
print("mylex ctlr @ port 0x%ux: 32-bit ", ctlr->port);
ctlr->wide = data[0x0D] & 0x01; 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) if (ctlr->wide)
print("wide\n"); print("wide ");
else else
print("narrow\n"); print("narrow ");
print("SCSI host adapter\n");
} }
else{ else{
/* /*
@ -1187,8 +1181,9 @@ mylex32enable(Ctlr* ctlr)
cmd[1] = 1; cmd[1] = 1;
if(!issue(ctlr, cmd, 2, 0, 0)) { if(!issue(ctlr, cmd, 2, 0, 0)) {
ctlr->wide = 0; ctlr->wide = 0;
print("mylex32enable: port 0x%ux: scsi wide-mode setup " print(
"failed on wide host adapter", ctlr->port); "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 { enum {
ACata, ACata,
ACconfig, ACconfig,
ACmask,
ACres,
}; };
enum { enum {
@ -15,23 +14,55 @@ enum {
}; };
enum { enum {
AEcmd = 1, AEunk,
AEarg, AEcmd, /* bad command */
AEdev, AEarg, /* bad argument */
AEcfg, AEoff, /* device offline */
AEver, AEcfg, /* config string already set */
AEver, /* unsupported version */
AEres, /* target reserved */
}; };
enum { enum {
Aoetype = 0x88a2, /* mask commands */
Aoesectsz = 512, /* standard sector size */ Mread = 0,
Aoever = 1, Medit,
AFerr = 1<<2, /* mask directives */
AFrsp = 1<<3, MDnop = 0,
MDadd,
MDdel,
AAFwrite= 1, /* mask errors */
AAFext = 1<<6, 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 { typedef struct {
@ -44,35 +75,43 @@ typedef struct {
uchar minor; uchar minor;
uchar cmd; uchar cmd;
uchar tag[4]; uchar tag[4];
uchar payload[];
} Aoehdr; } Aoehdr;
#define AOEHDRSZ offsetof(Aoehdr, payload[0])
typedef struct { typedef struct {
Aoehdr;
uchar aflag; uchar aflag;
uchar errfeat; uchar errfeat;
uchar scnt; uchar scnt;
uchar cmdstat; uchar cmdstat;
uchar lba[6]; uchar lba[6];
uchar res[2]; uchar res[2];
uchar payload[];
} Aoeata; } Aoeata;
#define AOEATASZ offsetof(Aoeata, payload[0])
typedef struct { typedef struct {
Aoehdr;
uchar bufcnt[2]; uchar bufcnt[2];
uchar fwver[2]; uchar fwver[2];
uchar scnt; uchar scnt;
uchar verccmd; uchar verccmd;
uchar cslen[2]; uchar cslen[2];
uchar payload[]; } Aoecfg;
} Aoeqc;
#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 Echange[];
extern char Enotup[]; extern char Enotup[];

File diff suppressed because it is too large Load diff

View file

@ -15,7 +15,9 @@
extern Dev sddevtab; extern Dev sddevtab;
extern SDifc* sdifc[]; 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" static char devletters[] = "0123456789"
"abcdefghijklmnopqrstuvwxyz" "abcdefghijklmnopqrstuvwxyz"
@ -23,6 +25,11 @@ static char devletters[] = "0123456789"
static SDev *devs[sizeof devletters-1]; static SDev *devs[sizeof devletters-1];
static QLock devslock; static QLock devslock;
static SDunit topctlunit;
enum {
Ahdrsz = 2,
};
enum { enum {
Rawcmd, Rawcmd,
@ -40,6 +47,7 @@ enum {
Qctl = Qunitbase, Qctl = Qunitbase,
Qraw, Qraw,
Qpart, Qpart,
Qextra,
TypeLOG = 4, TypeLOG = 4,
NType = (1<<TypeLOG), NType = (1<<TypeLOG),
@ -292,7 +300,7 @@ sdgetunit(SDev* sdev, int subno)
} }
sdev->unitflg[subno] = 1; 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->name, buf);
kstrdup(&unit->user, eve); kstrdup(&unit->user, eve);
unit->perm = 0555; unit->perm = 0555;
@ -323,15 +331,14 @@ static void
sdreset(void) sdreset(void)
{ {
int i; int i;
SDev *sdev;
/* /*
* Probe all known controller types and register any devices found. * Probe all known controller types and register any devices found.
*/ */
for(i = 0; sdifc[i] != nil; i++){ for(i = 0; sdifc[i] != nil; i++){
if(sdifc[i]->pnp == nil || (sdev = sdifc[i]->pnp()) == nil) if(sdifc[i]->pnp == nil)
continue; continue;
sdadddevs(sdev); sdadddevs(sdifc[i]->pnp());
} }
} }
@ -344,8 +351,8 @@ sdadddevs(SDev *sdev)
for(; sdev; sdev=next){ for(; sdev; sdev=next){
next = sdev->next; next = sdev->next;
sdev->unit = (SDunit**)malloc(sdev->nunit * sizeof(SDunit*)); sdev->unit = malloc(sdev->nunit * sizeof(SDunit*));
sdev->unitflg = (int*)malloc(sdev->nunit * sizeof(int)); sdev->unitflg = malloc(sdev->nunit * sizeof(int));
if(sdev->unit == nil || sdev->unitflg == nil){ if(sdev->unit == nil || sdev->unitflg == nil){
print("sdadddevs: out of memory\n"); print("sdadddevs: out of memory\n");
giveup: giveup:
@ -392,11 +399,12 @@ sd2gen(Chan* c, int i, Dir* dp)
{ {
Qid q; Qid q;
uvlong l; uvlong l;
SDfile *e;
SDpart *pp; SDpart *pp;
SDperm *perm; SDperm *perm;
SDunit *unit; SDunit *unit;
SDev *sdev; SDev *sdev;
int rv; int rv, t;
sdev = sdgetdev(DEV(c->qid)); sdev = sdgetdev(DEV(c->qid));
assert(sdev); assert(sdev);
@ -438,6 +446,18 @@ sd2gen(Chan* c, int i, Dir* dp)
devdir(c, q, pp->name, l, pp->user, pp->perm, dp); devdir(c, q, pp->name, l, pp->user, pp->perm, dp);
rv = 1; rv = 1;
break; 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); decref(&sdev->r);
@ -448,16 +468,45 @@ static int
sd1gen(Chan* c, int i, Dir* dp) sd1gen(Chan* c, int i, Dir* dp)
{ {
Qid q; Qid q;
SDperm *p;
switch(i){ switch(i){
case Qtopctl: case Qtopctl:
mkqid(&q, QID(0, 0, 0, Qtopctl), 0, QTFILE); 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;
} }
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 static int
sdgen(Chan* c, char*, Dirtab*, int, int s, Dir* dp) 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; i -= Qpart;
if(unit->part == nil || i >= unit->npart){ if(unit->part == nil || i >= unit->npart){
r = efilegen(c, unit, i, dp);
qunlock(&unit->ctl); qunlock(&unit->ctl);
decref(&sdev->r); decref(&sdev->r);
break; return r;
} }
pp = &unit->part[i]; pp = &unit->part[i];
if(!pp->valid){ if(!pp->valid || unit->sectors == 0){
qunlock(&unit->ctl); qunlock(&unit->ctl);
decref(&sdev->r); decref(&sdev->r);
return 0; 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), mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), i, Qpart),
unit->vers+pp->vers, QTFILE); unit->vers+pp->vers, QTFILE);
if(emptystr(pp->user)) if(emptystr(pp->user))
@ -575,6 +625,7 @@ sdgen(Chan* c, char*, Dirtab*, int, int s, Dir* dp)
case Qraw: case Qraw:
case Qctl: case Qctl:
case Qpart: case Qpart:
case Qextra:
if((sdev = sdgetdev(DEV(c->qid))) == nil){ if((sdev = sdgetdev(DEV(c->qid))) == nil){
devdir(c, q, "unavailable", 0, eve, 0, dp); devdir(c, q, "unavailable", 0, eve, 0, dp);
return 1; return 1;
@ -715,10 +766,12 @@ sdclose(Chan* c)
} }
} }
#define iskaddr(a) ((uintptr)(a) > KZERO)
static long static long
sdbio(Chan* c, int write, char* a, long len, uvlong off) sdbio(Chan* c, int write, char* a, long len, uvlong off)
{ {
int nchange; int nchange, hard, allocd;
long l; long l;
uchar *b; uchar *b;
SDpart *pp; SDpart *pp;
@ -785,21 +838,30 @@ sdbio(Chan* c, int write, char* a, long len, uvlong off)
poperror(); poperror();
} }
b = sdmalloc(nb*unit->secsize); offset = off%unit->secsize;
if(b == nil) if(offset+len > nb*unit->secsize)
error(Enomem); 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()){ if(waserror()){
sdfree(b); if(allocd)
sdfree(b);
if(!(unit->inquiry[1] & 0x80)) if(!(unit->inquiry[1] & 0x80))
decref(&sdev->r); /* gadverdamme! */ decref(&sdev->r); /* gadverdamme! */
nexterror(); nexterror();
} }
offset = off%unit->secsize;
if(offset+len > nb*unit->secsize)
len = nb*unit->secsize - offset;
if(write){ if(write){
if(offset || (len%unit->secsize)){ if(hard){
l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno); l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno);
if(l < 0) if(l < 0)
error(Eio); error(Eio);
@ -810,7 +872,8 @@ sdbio(Chan* c, int write, char* a, long len, uvlong off)
len = l; 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); l = unit->dev->ifc->bio(unit, 0, 1, b, nb, bno);
if(l < 0) if(l < 0)
error(Eio); error(Eio);
@ -827,9 +890,11 @@ sdbio(Chan* c, int write, char* a, long len, uvlong off)
len = 0; len = 0;
else if(len > l - offset) else if(len > l - offset)
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(); poperror();
if(unit->inquiry[1] & 0x80){ if(unit->inquiry[1] & 0x80){
@ -844,41 +909,69 @@ sdbio(Chan* c, int write, char* a, long len, uvlong off)
static long static long
sdrio(SDreq* r, void* a, long n) sdrio(SDreq* r, void* a, long n)
{ {
char *errstr;
int rv;
void *data; void *data;
SDunit *u;
int (*f)(SDreq*);
if(n >= SDmaxio || n < 0) if(n >= SDmaxio || n < 0)
error(Etoobig); 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; data = nil;
if(n){ if(n > 0 && (data = sdmalloc(n)) == nil)
if((data = sdmalloc(n)) == nil) error(Enomem);
error(Enomem);
if(r->write)
memmove(data, a, n);
}
r->data = data;
r->dlen = n;
if(waserror()){ if(waserror()){
sdfree(data); sdfree(data);
r->data = nil; r->data = nil;
nexterror(); 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); error(Eio);
if(!r->write && r->rlen > 0) if(!r->write && r->rlen > 0)
memmove(a, data, r->rlen); memmove(a, data, r->rlen);
poperror();
sdfree(data); sdfree(data);
r->data = nil; r->data = nil;
poperror();
return r->rlen; return r->rlen;
} }
/* /*
* SCSI simulation for non-SCSI devices * 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 int
sdsetsense(SDreq *r, int status, int key, int asc, int ascq) 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 int
sdmodesense(SDreq *r, uchar *cmd, void *info, int ilen) sdfakescsi(SDreq *r)
{
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)
{ {
uchar *cmd, *p; uchar *cmd, *p;
uvlong len; uvlong len;
@ -947,25 +1011,6 @@ sdfakescsi(SDreq *r, void *info, int ilen)
r->rlen = 0; r->rlen = 0;
unit = r->unit; 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. * Map SCSI commands into ATA commands for discs.
* Fail any command with a LUN except INQUIRY which * 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. * Read capacity returns the LBA of the last sector.
*/ */
len = unit->sectors - 1; len = unit->sectors;
if(len > 0)
len--;
p = r->data; p = r->data;
*p++ = len>>24; *p++ = len>>24;
*p++ = len>>16; *p++ = len>>16;
*p++ = len>>8; *p++ = len>>8;
*p++ = len; *p++ = len;
len = 512; len = unit->secsize;
*p++ = len>>24; *p++ = len>>24;
*p++ = len>>16; *p++ = len>>16;
*p++ = len>>8; *p++ = len>>8;
@ -1040,7 +1087,9 @@ sdfakescsi(SDreq *r, void *info, int ilen)
/* /*
* Read capcity returns the LBA of the last sector. * Read capcity returns the LBA of the last sector.
*/ */
len = unit->sectors - 1; len = unit->sectors;
if(len > 0)
len--;
p = r->data; p = r->data;
*p++ = len>>56; *p++ = len>>56;
*p++ = len>>48; *p++ = len>>48;
@ -1050,32 +1099,124 @@ sdfakescsi(SDreq *r, void *info, int ilen)
*p++ = len>>16; *p++ = len>>16;
*p++ = len>>8; *p++ = len>>8;
*p++ = len; *p++ = len;
len = 512; len = unit->secsize;
*p++ = len>>24; *p++ = len>>24;
*p++ = len>>16; *p++ = len>>16;
*p++ = len>>8; *p++ = len>>8;
*p++ = len; *p++ = len;
r->rlen = p - (uchar*)r->data; r->rlen = p - (uchar*)r->data;
return sdsetsense(r, SDok, 0, 0, 0); return sdsetsense(r, SDok, 0, 0, 0);
case 0x08: /* read6 */
case 0x5A: /* mode sense */ case 0x0a: /* write6 */
return sdmodesense(r, cmd, info, ilen); case 0x28: /* read10 */
case 0x2a: /* write10 */
case 0x28: /* read */ case 0xa8: /* read12 */
case 0x2A: /* write */ case 0xaa: /* write12 */
case 0x88: /* read16 */ case 0x88: /* read16 */
case 0x8a: /* write16 */ case 0x8a: /* write16 */
return SDnostatus; 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 static long
sdread(Chan *c, void *a, long n, vlong off) sdread(Chan *c, void *a, long n, vlong off)
{ {
char *p, *e, *buf; char *p, *e, *buf;
SDpart *pp;
SDunit *unit;
SDev *sdev; SDev *sdev;
SDpart *pp;
SDreq *r;
SDunit *unit;
ulong offset; ulong offset;
int i, l, m, status; int i, l, m, status;
@ -1093,6 +1234,8 @@ sdread(Chan *c, void *a, long n, vlong off)
sdev = devs[i]; sdev = devs[i];
if(sdev && sdev->ifc->rtopctl) if(sdev && sdev->ifc->rtopctl)
p = sdev->ifc->rtopctl(sdev, p, e); p = sdev->ifc->rtopctl(sdev, p, e);
else if(sdev)
p = deftopctl(sdev, p, e);
} }
qunlock(&devslock); qunlock(&devslock);
n = readstr(off, a, n, buf); n = readstr(off, a, n, buf);
@ -1157,23 +1300,38 @@ sdread(Chan *c, void *a, long n, vlong off)
} }
if(unit->state == Rawdata){ if(unit->state == Rawdata){
unit->state = Rawstatus; 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){ else if(unit->state == Rawstatus){
status = unit->req->status; r = unit->req;
unit->state = Rawcmd;
free(unit->req);
unit->req = nil; 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 } else
i = 0; i = 0;
poperror();
qunlock(&unit->raw); qunlock(&unit->raw);
decref(&sdev->r); decref(&sdev->r);
poperror();
return i; return i;
case Qpart: case Qpart:
return sdbio(c, 0, a, n, off); 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) sdwrite(Chan* c, void* a, long n, vlong off)
{ {
char *f0; char *f0;
int i; int i, atacdb, proto, ataproto;
uchar *u;
uvlong end, start; uvlong end, start;
Cmdbuf *cb; Cmdbuf *cb;
SDifc *ifc; SDifc *ifc;
@ -1250,7 +1409,7 @@ sdwrite(Chan* c, void* a, long n, vlong off)
error(Ebadctl); error(Ebadctl);
poperror(); poperror();
poperror(); poperror();
if (sdev) if(sdev)
decref(&sdev->r); decref(&sdev->r);
free(cb); free(cb);
break; break;
@ -1299,6 +1458,9 @@ sdwrite(Chan* c, void* a, long n, vlong off)
break; break;
case Qraw: case Qraw:
proto = SDcdb;
ataproto = 0;
atacdb = 0;
sdev = sdgetdev(DEV(c->qid)); sdev = sdgetdev(DEV(c->qid));
if(sdev == nil) if(sdev == nil)
error(Enonexist); error(Enonexist);
@ -1311,18 +1473,34 @@ sdwrite(Chan* c, void* a, long n, vlong off)
} }
switch(unit->state){ switch(unit->state){
case Rawcmd: 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)) if(n < 6 || n > sizeof(req->cmd))
error(Ebadarg); error(Ebadarg);
if((req = malloc(sizeof(SDreq))) == nil) if((req = malloc(sizeof(SDreq))) == nil)
error(Enomem); error(Enomem);
req->unit = unit; req->unit = unit;
if(waserror()){
free(req);
nexterror();
}
memmove(req->cmd, a, n); memmove(req->cmd, a, n);
poperror();
req->clen = n; req->clen = n;
req->flags = SDnosense; /* req->flags = SDnosense; */
req->status = ~0; req->status = ~0;
req->proto = proto;
req->ataproto = ataproto;
unit->req = req; unit->req = req;
unit->state = Rawdata; unit->state = Rawdata;
n += atacdb;
break; break;
case Rawstatus: case Rawstatus:
@ -1333,15 +1511,18 @@ sdwrite(Chan* c, void* a, long n, vlong off)
case Rawdata: case Rawdata:
unit->state = Rawstatus; unit->state = Rawstatus;
unit->req->write = 1; req = unit->req;
n = sdrio(unit->req, a, n); req->write = 1;
n = sdrio(req, a, n);
} }
poperror();
qunlock(&unit->raw); qunlock(&unit->raw);
decref(&sdev->r); decref(&sdev->r);
poperror();
break; break;
case Qpart: case Qpart:
return sdbio(c, 1, a, n, off); return sdbio(c, 1, a, n, off);
case Qextra:
return extrarw(1, c, a, n, off);
} }
return n; return n;
@ -1358,23 +1539,30 @@ sdwstat(Chan* c, uchar* dp, int n)
if(c->qid.type & QTDIR) if(c->qid.type & QTDIR)
error(Eperm); error(Eperm);
if(TYPE(c->qid) == Qtopctl){
sdev = sdgetdev(DEV(c->qid)); unit = &topctlunit;
if(sdev == nil) sdev = nil;
error(Enonexist); }else{
unit = sdev->unit[UNIT(c->qid)]; sdev = sdgetdev(DEV(c->qid));
if(sdev == nil)
error(Enonexist);
unit = sdev->unit[UNIT(c->qid)];
}
qlock(&unit->ctl); qlock(&unit->ctl);
d = nil; d = nil;
if(waserror()){ if(waserror()){
free(d); free(d);
qunlock(&unit->ctl); qunlock(&unit->ctl);
decref(&sdev->r); if(sdev != nil)
decref(&sdev->r);
nexterror(); nexterror();
} }
switch(TYPE(c->qid)){ switch(TYPE(c->qid)){
default: default:
error(Eperm); error(Eperm);
case Qtopctl:
case Qctl: case Qctl:
perm = &unit->ctlperm; perm = &unit->ctlperm;
break; break;
@ -1396,14 +1584,22 @@ sdwstat(Chan* c, uchar* dp, int n)
n = convM2D(dp, n, &d[0], (char*)&d[1]); n = convM2D(dp, n, &d[0], (char*)&d[1]);
if(n == 0) if(n == 0)
error(Eshortstat); 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)) if(!emptystr(d[0].uid))
kstrdup(&perm->user, 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) if(d[0].mode != ~0UL)
perm->perm = (perm->perm & ~0777) | (d[0].mode & 0777); perm->perm = (perm->perm & ~0777) | (d[0].mode & 0777);
free(d); free(d);
d = nil; USED(d);
qunlock(&unit->ctl); qunlock(&unit->ctl);
decref(&sdev->r); if(sdev != nil)
decref(&sdev->r);
poperror(); poperror();
return n; return n;
} }
@ -1487,13 +1683,62 @@ sdconfig(int on, char* spec, DevConf* cf)
return unconfigure(spec); 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 = { Dev sddevtab = {
'S', 'S',
"sd", "sd",
sdreset, sdreset,
devinit, devinit,
devshutdown, sdshutdown,
sdattach, sdattach,
sdwalk, sdwalk,
sdstat, sdstat,
@ -1544,7 +1789,7 @@ getnewport(DevConf* dc)
{ {
Devport *p; Devport *p;
p = (Devport *)malloc((dc->nports + 1) * sizeof(Devport)); p = malloc((dc->nports + 1) * sizeof(Devport));
if(dc->nports > 0){ if(dc->nports > 0){
memmove(p, dc->ports, dc->nports * sizeof(Devport)); memmove(p, dc->ports, dc->nports * sizeof(Devport));
free(dc->ports); free(dc->ports);
@ -1635,7 +1880,6 @@ legacytopctl(Cmdbuf *cb)
if(j == nelem(options)) if(j == nelem(options))
error(Ebadarg); error(Ebadarg);
} }
/* this has been rewritten to accomodate sdaoe */
if(cd.on < 0 || cd.spec == 0) if(cd.on < 0 || cd.spec == 0)
error(Ebadarg); error(Ebadarg);
if(cd.on && cd.cf.type == nil) 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 snprint 3
#pragma varargck argpos sprint 2 #pragma varargck argpos sprint 2
#pragma varargck type "llb" vlong
#pragma varargck type "lld" vlong #pragma varargck type "lld" vlong
#pragma varargck type "llx" vlong #pragma varargck type "llx" vlong
#pragma varargck type "llb" uvlong
#pragma varargck type "lld" uvlong #pragma varargck type "lld" uvlong
#pragma varargck type "llx" uvlong #pragma varargck type "llx" uvlong
#pragma varargck type "lb" long
#pragma varargck type "ld" long #pragma varargck type "ld" long
#pragma varargck type "lx" long #pragma varargck type "lx" long
#pragma varargck type "lb" ulong
#pragma varargck type "ld" ulong #pragma varargck type "ld" ulong
#pragma varargck type "lx" ulong #pragma varargck type "lx" ulong
#pragma varargck type "b" int
#pragma varargck type "d" int #pragma varargck type "d" int
#pragma varargck type "x" int #pragma varargck type "x" int
#pragma varargck type "c" int #pragma varargck type "c" int
#pragma varargck type "C" int #pragma varargck type "C" int
#pragma varargck type "b" uint
#pragma varargck type "d" uint #pragma varargck type "d" uint
#pragma varargck type "x" uint #pragma varargck type "x" uint
#pragma varargck type "c" uint #pragma varargck type "c" uint

View file

@ -2,6 +2,7 @@
* Storage Device. * Storage Device.
*/ */
typedef struct SDev SDev; typedef struct SDev SDev;
typedef struct SDfile SDfile;
typedef struct SDifc SDifc; typedef struct SDifc SDifc;
typedef struct SDpart SDpart; typedef struct SDpart SDpart;
typedef struct SDperm SDperm; typedef struct SDperm SDperm;
@ -22,11 +23,20 @@ struct SDpart {
ulong vers; ulong vers;
}; };
typedef long SDrw(SDunit*, Chan*, void*, long, vlong);
struct SDfile {
SDperm;
SDrw *r;
SDrw *w;
};
struct SDunit { struct SDunit {
SDev* dev; SDev* dev;
int subno; int subno;
uchar inquiry[255]; /* format follows SCSI spec */ uchar inquiry[255]; /* format follows SCSI spec */
uchar sense[18]; /* format follows SCSI spec */ uchar sense[18]; /* format follows SCSI spec */
uchar rsense[18]; /* support seperate rq sense and inline return */
uchar haversense;
SDperm; SDperm;
QLock ctl; QLock ctl;
@ -42,6 +52,8 @@ struct SDunit {
int state; int state;
SDreq* req; SDreq* req;
SDperm rawperm; SDperm rawperm;
SDfile efile[5];
int nefile;
}; };
/* /*
@ -67,7 +79,7 @@ struct SDifc {
char* name; char* name;
SDev* (*pnp)(void); SDev* (*pnp)(void);
SDev* (*legacy)(int, int); SDev* (*xxlegacy)(int, int); /* unused. remove me */
int (*enable)(SDev*); int (*enable)(SDev*);
int (*disable)(SDev*); int (*disable)(SDev*);
@ -82,22 +94,26 @@ struct SDifc {
void (*clear)(SDev*); void (*clear)(SDev*);
char* (*rtopctl)(SDev*, char*, char*); char* (*rtopctl)(SDev*, char*, char*);
int (*wtopctl)(SDev*, Cmdbuf*); int (*wtopctl)(SDev*, Cmdbuf*);
int (*ataio)(SDreq*);
}; };
struct SDreq { struct SDreq {
SDunit* unit; SDunit* unit;
int lun; int lun;
int write; char write;
uchar cmd[16]; char proto;
char ataproto;
uchar cmd[0x20];
int clen; int clen;
void* data; void* data;
int dlen; int dlen;
int flags; int flags;
ulong timeout; /* in ticks */
int status; int status;
long rlen; long rlen;
uchar sense[256]; uchar sense[32];
}; };
enum { enum {
@ -119,6 +135,12 @@ enum {
SDmaxio = 2048*1024, SDmaxio = 2048*1024,
SDnpart = 16, SDnpart = 16,
SDread = 0,
SDwrite,
SData = 1,
SDcdb = 2,
}; };
#define sdmalloc(n) malloc(n) #define sdmalloc(n) malloc(n)
@ -127,11 +149,11 @@ enum {
/* devsd.c */ /* devsd.c */
extern void sdadddevs(SDev*); extern void sdadddevs(SDev*);
extern int sdsetsense(SDreq*, int, int, int, int); extern int sdsetsense(SDreq*, int, int, int, int);
extern int sdmodesense(SDreq*, uchar*, void*, int); extern int sdfakescsi(SDreq*);
extern int sdfakescsi(SDreq*, void*, int); extern int sdfakescsirw(SDreq*, uvlong*, int*, int*);
extern int sdaddfile(SDunit*, char*, int, char*, SDrw*, SDrw*);
/* sdscsi.c */ /* sdscsi.c */
extern int scsiverify(SDunit*); extern int scsiverify(SDunit*);
extern int scsionline(SDunit*); extern int scsionline(SDunit*);
extern long scsibio(SDunit*, int, int, void*, long, uvlong); 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" #include "u.h"
@ -12,6 +12,7 @@
#include "../port/sd.h" #include "../port/sd.h"
#include "../port/netif.h" #include "../port/netif.h"
#include "../port/aoe.h" #include "../port/aoe.h"
#include <fis.h>
extern char Echange[]; extern char Echange[];
extern char Enotup[]; extern char Enotup[];
@ -19,34 +20,14 @@ extern char Enotup[];
#define uprint(...) snprint(up->genbuf, sizeof up->genbuf, __VA_ARGS__); #define uprint(...) snprint(up->genbuf, sizeof up->genbuf, __VA_ARGS__);
enum { enum {
Nctlr = 32, Maxpath = 128,
Maxpath = 128,
Probeintvl = 100, /* ms. between probes */ Probeintvl = 100, /* ms. between probes */
Probemax = 20, /* max probes */ Probemax = 10*1000, /* max ms. to wait */
};
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",
}; };
typedef struct Ctlr Ctlr; typedef struct Ctlr Ctlr;
struct Ctlr{ struct Ctlr {
QLock; QLock;
Ctlr *next; Ctlr *next;
@ -56,11 +37,8 @@ struct Ctlr{
Chan *c; Chan *c;
ulong vers; ulong vers;
uchar mediachange; uchar drivechange;
uchar flag; Sfis;
uchar smart;
uchar smartrs;
uchar feat;
uvlong sectors; uvlong sectors;
char serial[20+1]; char serial[20+1];
@ -69,88 +47,60 @@ struct Ctlr{
char ident[0x100]; char ident[0x100];
}; };
void aoeidmove(char *p, ushort *a, unsigned n);
static Lock ctlrlock; static Lock ctlrlock;
static Ctlr *head; static Ctlr *head;
static Ctlr *tail; static Ctlr *tail;
SDifc sdaoeifc; 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 static int
identify(Ctlr *c, ushort *id) identify(Ctlr *c, ushort *id)
{ {
int i;
uchar oserial[21]; uchar oserial[21];
uvlong osectors, s; vlong osectors, s;
osectors = c->sectors; osectors = c->sectors;
memmove(oserial, c->serial, sizeof c->serial); memmove(oserial, c->serial, sizeof c->serial);
s = idfeat(c, id);
c->feat &= ~(Dllba|Dpower|Dsmart|Dnop); if(s == -1){
i = gbit16(id+83) | gbit16(id+86); uprint("%s: identify fails", c->unit->name);
if(i & (1<<10)){ print("%s\n", up->genbuf);
c->feat |= Dllba; error(up->genbuf);
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;
} }
idmove(c->serial, id+10, 20);
aoeidmove(c->serial, id+10, 20); idmove(c->firmware, id+23, 8);
aoeidmove(c->firmware, id+23, 8); idmove(c->model, id+27, 40);
aoeidmove(c->model, id+27, 40);
if((osectors == 0 || osectors != s) && if((osectors == 0 || osectors != s) &&
memcmp(oserial, c->serial, sizeof oserial) != 0){ memcmp(oserial, c->serial, sizeof oserial) != 0){
c->sectors = s; c->sectors = s;
c->mediachange = 1; c->drivechange = 1;
c->vers++; c->vers++;
} }
return 0; 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 */ /* must call with d qlocked */
static int static int
aoeidentify(Ctlr *d, SDunit *u) aoeidentify(Ctlr *d, SDunit *u)
@ -173,7 +123,6 @@ aoeidentify(Ctlr *d, SDunit *u)
cclose(c); cclose(c);
d->feat = 0; d->feat = 0;
d->smart = 0;
identify(d, (ushort*)d->ident); identify(d, (ushort*)d->ident);
memset(u->inquiry, 0, sizeof u->inquiry); memset(u->inquiry, 0, sizeof u->inquiry);
@ -203,7 +152,6 @@ newctlr(char *path)
{ {
Ctlr *c; Ctlr *c;
/* race? */
if(ctlrlookup(path)) if(ctlrlookup(path))
error(Eexist); error(Eexist);
@ -248,7 +196,6 @@ delctlr(Ctlr *c)
free(x); free(x);
} }
/* don't call aoeprobe from within a loop; it loops internally retrying open. */
static SDev* static SDev*
aoeprobe(char *path, SDev *s) aoeprobe(char *path, SDev *s)
{ {
@ -273,21 +220,24 @@ aoeprobe(char *path, SDev *s)
poperror(); poperror();
cclose(c); 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); tsleep(&up->sleep, return0, 0, Probeintvl);
poperror();
uprint("%s/ident", path); uprint("%s/ident", path);
if(!waserror()) { if(waserror())
c = namec(up->genbuf, Aopen, OREAD, 0); continue;
poperror(); c = namec(up->genbuf, Aopen, OREAD, 0);
cclose(c); poperror();
break; cclose(c);
}
ctlr = newctlr(path);
break;
} }
if(i >= Probemax)
error(Etimedout); if(s == nil && (s = malloc(sizeof *s)) == nil)
uprint("%s/ident", path);
ctlr = newctlr(path);
if(ctlr == nil || s == nil && (s = malloc(sizeof *s)) == nil)
return nil; return nil;
s->ctlr = ctlr; s->ctlr = ctlr;
s->ifc = &sdaoeifc; s->ifc = &sdaoeifc;
@ -296,14 +246,20 @@ aoeprobe(char *path, SDev *s)
} }
static char *probef[32]; static char *probef[32];
static char *probebuf;
static int nprobe; static int nprobe;
static int static int
pnpprobeid(char *s) pnpprobeid(char *s)
{ {
int id;
if(strlen(s) < 2) if(strlen(s) < 2)
return 0; return 0;
return s[1] == '!'? s[0]: 'e'; id = 'e';
if(s[1] == '!')
id = s[0];
return id;
} }
static SDev* static SDev*
@ -315,7 +271,8 @@ aoepnp(void)
if((p = getconf("aoedev")) == 0) if((p = getconf("aoedev")) == 0)
return 0; return 0;
nprobe = tokenize(p, probef, nelem(probef)); kstrdup(&probebuf, p);
nprobe = tokenize(probebuf, probef, nelem(probef));
h = t = 0; h = t = 0;
for(i = 0; i < nprobe; i++){ for(i = 0; i < nprobe; i++){
id = pnpprobeid(probef[i]); id = pnpprobeid(probef[i]);
@ -341,7 +298,7 @@ aoepnp(void)
static Ctlr* static Ctlr*
pnpprobe(SDev *sd) pnpprobe(SDev *sd)
{ {
ulong start; int j;
char *p; char *p;
static int i; static int i;
@ -353,17 +310,21 @@ pnpprobe(SDev *sd)
if(p[1] == '!') if(p[1] == '!')
p += 2; p += 2;
start = TK2MS(MACHP(0)->ticks); for(j = 0;; j += Probeintvl){
if(waserror()){ if(j > Probemax){
print("#æ: pnpprobe failed in %lud ms: %s: %s\n", print("#æ: pnpprobe: %s: %s\n", probef[i-1], up->errstr);
TK2MS(MACHP(0)->ticks) - start, probef[i-1], return 0;
up->errstr); }
return nil; if(waserror()){
tsleep(&up->sleep, return0, 0, Probeintvl);
continue;
}
sd = aoeprobe(p, sd);
poperror();
break;
} }
sd = aoeprobe(p, sd); /* does a round of probing */ print("#æ: pnpprobe establishes %s in %dms\n", probef[i-1], j);
poperror(); aoectl(sd->ctlr, "nofail on");
print("#æ: pnpprobe established %s in %lud ms\n",
probef[i-1], TK2MS(MACHP(0)->ticks) - start);
return sd->ctlr; return sd->ctlr;
} }
@ -378,7 +339,7 @@ aoeverify(SDunit *u)
c = s->ctlr; c = s->ctlr;
if(c == nil && (s->ctlr = c = pnpprobe(s)) == nil) if(c == nil && (s->ctlr = c = pnpprobe(s)) == nil)
return 0; return 0;
c->mediachange = 1; c->drivechange = 1;
return 1; return 1;
} }
@ -412,17 +373,17 @@ aoeonline(SDunit *u)
c = u->dev->ctlr; c = u->dev->ctlr;
r = 0; r = 0;
if((c->feat&Datapi) && c->mediachange){ if((c->feat&Datapi) && c->drivechange){
if(aoeconnect(u, c) == 0 && (r = scsionline(u)) > 0) if(aoeconnect(u, c) == 0 && (r = scsionline(u)) > 0)
c->mediachange = 0; c->drivechange = 0;
return r; return r;
} }
if(c->mediachange){ if(c->drivechange){
if(aoeconnect(u, c) == -1) if(aoeconnect(u, c) == -1)
return 0; return 0;
r = 2; r = 2;
c->mediachange = 0; c->drivechange = 0;
u->sectors = c->sectors; u->sectors = c->sectors;
u->secsize = Aoesectsz; u->secsize = Aoesectsz;
} else } else
@ -431,103 +392,70 @@ aoeonline(SDunit *u)
return r; return r;
} }
static int static long
aoerio(SDreq *r) aoebio(SDunit *u, int, int write, void *a, long count, uvlong lba)
{ {
int i, count; uchar *data;
uvlong lba; int n;
char *name;
uchar *cmd;
long (*rio)(Chan*, void*, long, vlong); long (*rio)(Chan*, void*, long, vlong);
Ctlr *c; Ctlr *c;
SDunit *unit;
unit = r->unit; c = u->dev->ctlr;
c = unit->dev->ctlr;
// if(c->feat & Datapi) // if(c->feat & Datapi)
// return aoeriopkt(r, d); // return scsibio(u, lun, write, a, count, lba);
data = a;
cmd = r->cmd; if(write)
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:
rio = devtab[c->c->type]->write; rio = devtab[c->c->type]->write;
break; else
default: rio = devtab[c->c->type]->read;
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;
if(waserror()){ if(waserror()){
if(strcmp(up->errstr, Echange) == 0 || if(strcmp(up->errstr, Echange) == 0 ||
strcmp(up->errstr, Enotup) == 0) strcmp(up->errstr, Enotup) == 0)
unit->sectors = 0; u->sectors = 0;
nexterror(); nexterror();
} }
r->rlen = rio(c->c, r->data, count, Aoesectsz * lba); n = rio(c->c, data, Aoesectsz * count, Aoesectsz * lba);
poperror(); poperror();
r->status = SDok; return n;
return SDok;
} }
static char *smarttab[] = { static int
"unset", flushcache(Ctlr *)
"error",
"threshold exceeded",
"normal"
};
static char *
pflag(char *s, char *e, uchar f)
{ {
uchar i, m; return -1;
}
for(i = 0; i < 8; i++){ static int
m = 1 << i; aoerio(SDreq *r)
if(f & m) {
s = seprint(s, e, "%s ", flagname[i]); 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 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, "model\t%s\n", c->model);
p = seprint(p, e, "serial\t%s\n", c->serial); p = seprint(p, e, "serial\t%s\n", c->serial);
p = seprint(p, e, "firm %s\n", c->firmware); 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 = 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); p = seprint(p, e, "geometry %llud %d\n", c->sectors, Aoesectsz);
return p-op; return p-op;
} }
@ -590,7 +512,7 @@ aoertopctl(SDev *s, char *p, char *e)
Ctlr *c; Ctlr *c;
c = s->ctlr; 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 static int
@ -617,7 +539,7 @@ SDifc sdaoeifc = {
aoerctl, aoerctl,
aoewctl, aoewctl,
scsibio, aoebio,
aoeprobew, /* probe */ aoeprobew, /* probe */
aoeclear, /* clear */ aoeclear, /* clear */
aoertopctl, 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 no medium present, bail out.
* If unit is becoming ready, rather than not * 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) if(r->sense[12] == 0x3A)
break; break;
if(r->sense[12] != 0x04 || r->sense[13] != 0x01) if(r->sense[12] != 0x04 || r->sense[13] != 0x01)
@ -175,22 +176,91 @@ scsirio(SDreq* r)
return -1; 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 int
scsionline(SDunit* unit) scsionline(SDunit* unit)
{ {
SDreq *r; SDreq *r;
uchar *p; uchar *p;
int ok, retries; int ok, retries;
void (*cap)(SDreq*);
if((r = malloc(sizeof(SDreq))) == nil) if((r = malloc(sizeof *r)) == nil)
return 0; return 0;
if((p = sdmalloc(8)) == nil){ if((p = sdmalloc(32)) == nil){
free(r); free(r);
return 0; return 0;
} }
ok = 0; ok = 0;
cap = cap10;
r->unit = unit; r->unit = unit;
r->lun = 0; /* ??? */ r->lun = 0; /* ??? */
for(retries = 0; retries < 10; retries++){ for(retries = 0; retries < 10; retries++){
@ -201,39 +271,21 @@ scsionline(SDunit* unit)
* plain slow getting their act together after a reset. * plain slow getting their act together after a reset.
*/ */
r->write = 0; 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->data = p;
r->dlen = 8;
r->flags = 0; r->flags = 0;
memset(r->cmd, 0, sizeof r->cmd);
cap(r);
r->status = ~0; r->status = ~0;
switch(scsirio(r)){ switch(scsirio(r)){
default: default:
break; break;
case 0: case 0:
unit->sectors = (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3]; unit->sectors = capreply(r, &unit->secsize);
unit->secsize = (p[4]<<24)|(p[5]<<16)|(p[6]<<8)|p[7]; if(unit->sectors == 0xffffffff && cap == cap10){
cap = cap16;
/* continue;
* 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++;
ok = 1; ok = 1;
break; break;
case 1: case 1:
@ -253,56 +305,6 @@ scsionline(SDunit* unit)
return 0; 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 static void
scsifmt10(SDreq *r, int write, int lun, ulong nb, uvlong bno) 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; r->lun = lun;
again: again:
r->write = write; r->write = write;
if(bno >= (1ULL<<32)) if(bno > 0xffffffff)
scsifmt16(r, write, lun, nb, bno); scsifmt16(r, write, lun, nb, bno);
else else
scsifmt10(r, write, lun, nb, bno); scsifmt10(r, write, lun, nb, bno);
@ -381,8 +383,19 @@ again:
rlen = -1; rlen = -1;
break; break;
case 0: 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: case 2:
rlen = -1; rlen = -1;
if(!(r->flags & SDvalidsense)) if(!(r->flags & SDvalidsense))
@ -415,6 +428,10 @@ again:
goto again; goto again;
break; 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; break;
} }
free(r); 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