merge sd changes from 9atom
This commit is contained in:
parent
ae00ac7465
commit
c2fc2fad13
163
sys/include/fis.h
Normal file
163
sys/include/fis.h
Normal 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*);
|
|
@ -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;
|
||||||
|
|
|
@ -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'}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
@ -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
2841
sys/src/9/pc/sdodin.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -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
|
@ -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
62
sys/src/9/port/led.c
Normal 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
26
sys/src/9/port/led.h
Normal 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);
|
|
@ -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
|
||||||
|
|
|
@ -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*);
|
|
||||||
|
|
|
@ -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
415
sys/src/9/port/sdloop.c
Normal 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,
|
||||||
|
};
|
|
@ -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
545
sys/src/libfis/fis.c
Normal 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
15
sys/src/libfis/mkfile
Normal 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
|
Loading…
Reference in a new issue