merge sd changes from 9atom
This commit is contained in:
parent
ae00ac7465
commit
c2fc2fad13
22 changed files with 7886 additions and 3050 deletions
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)
|
||||
* © 2007 coraid, inc
|
||||
* © 2007-9 coraid, inc
|
||||
*/
|
||||
|
||||
/* ata errors */
|
||||
enum {
|
||||
Emed = 1<<0, /* media error */
|
||||
Enm = 1<<1, /* no media */
|
||||
Eabrt = 1<<2, /* abort */
|
||||
Emcr = 1<<3, /* media change request */
|
||||
Eidnf = 1<<4, /* no user-accessible address */
|
||||
Emc = 1<<5, /* media change */
|
||||
Eunc = 1<<6, /* data error */
|
||||
Ewp = 1<<6, /* write protect */
|
||||
Eicrc = 1<<7, /* interface crc error */
|
||||
|
||||
Efatal = Eidnf|Eicrc, /* must sw reset */
|
||||
};
|
||||
|
||||
/* ata status */
|
||||
enum {
|
||||
ASerr = 1<<0, /* error */
|
||||
ASdrq = 1<<3, /* request */
|
||||
ASdf = 1<<5, /* fault */
|
||||
ASdrdy = 1<<6, /* ready */
|
||||
ASbsy = 1<<7, /* busy */
|
||||
|
||||
ASobs = 1<<1|1<<2|1<<4,
|
||||
};
|
||||
|
||||
/* pci configuration */
|
||||
enum {
|
||||
Abar = 5,
|
||||
|
@ -47,26 +21,25 @@ enum {
|
|||
|
||||
/* cap bits: supported features */
|
||||
enum {
|
||||
Hs64a = 1<<31, /* 64-bit addressing */
|
||||
Hsncq = 1<<30, /* ncq */
|
||||
Hssntf = 1<<29, /* snotification reg. */
|
||||
Hsmps = 1<<28, /* mech pres switch */
|
||||
Hsss = 1<<27, /* staggered spinup */
|
||||
Hsalp = 1<<26, /* aggressive link pm */
|
||||
Hsal = 1<<25, /* activity led */
|
||||
Hsclo = 1<<24, /* command-list override */
|
||||
H64a = 1<<31, /* 64-bit addressing */
|
||||
Hncq = 1<<30, /* ncq */
|
||||
Hsntf = 1<<29, /* snotification reg. */
|
||||
Hmps = 1<<28, /* mech pres switch */
|
||||
Hss = 1<<27, /* staggered spinup */
|
||||
Halp = 1<<26, /* aggressive link pm */
|
||||
Hal = 1<<25, /* activity led */
|
||||
Hclo = 1<<24, /* command-list override */
|
||||
Hiss = 1<<20, /* for interface speed */
|
||||
// Hsnzo = 1<<19,
|
||||
Hsam = 1<<18, /* ahci-mode only */
|
||||
Hspm = 1<<17, /* port multiplier */
|
||||
// Hfbss = 1<<16,
|
||||
Ham = 1<<18, /* ahci-mode only */
|
||||
Hpm = 1<<17, /* port multiplier */
|
||||
Hfbs = 1<<16, /* fis-based switching */
|
||||
Hpmb = 1<<15, /* multiple-block pio */
|
||||
Hssc = 1<<14, /* slumber state */
|
||||
Hpsc = 1<<13, /* partial-slumber state */
|
||||
Hncs = 1<<8, /* n command slots */
|
||||
Hcccs = 1<<7, /* coal */
|
||||
Hems = 1<<6, /* enclosure mgmt. */
|
||||
Hsxs = 1<<5, /* external sata */
|
||||
Hxs = 1<<5, /* external sata */
|
||||
Hnp = 1<<0, /* n ports */
|
||||
};
|
||||
|
||||
|
@ -77,6 +50,29 @@ enum {
|
|||
Hhr = 1<<0, /* hba reset */
|
||||
};
|
||||
|
||||
/* cap2 bits */
|
||||
enum {
|
||||
Apts = 1<<2, /* automatic partial to slumber */
|
||||
Nvmp = 1<<1, /* nvmhci present; nvram */
|
||||
Boh = 1<<0, /* bios/os handoff supported */
|
||||
};
|
||||
|
||||
/* emctl bits */
|
||||
enum {
|
||||
Pm = 1<<27, /* port multiplier support */
|
||||
Alhd = 1<<26, /* activity led hardware driven */
|
||||
Xonly = 1<<25, /* rx messages not supported */
|
||||
Smb = 1<<24, /* single msg buffer; rx limited */
|
||||
Esgpio = 1<<19, /* sgpio messages supported */
|
||||
Eses2 = 1<<18, /* ses-2 supported */
|
||||
Esafte = 1<<17, /* saf-te supported */
|
||||
Elmt = 1<<16, /* led msg types support */
|
||||
Emrst = 1<<9, /* reset all em logic */
|
||||
Tmsg = 1<<8, /* transmit message */
|
||||
Mr = 1<<0, /* message rx'd */
|
||||
Emtype = Esgpio | Eses2 | Esafte | Elmt,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
ulong cap;
|
||||
ulong ghc;
|
||||
|
@ -87,6 +83,8 @@ typedef struct {
|
|||
ulong cccports;
|
||||
ulong emloc;
|
||||
ulong emctl;
|
||||
ulong cap2;
|
||||
ulong bios;
|
||||
} Ahba;
|
||||
|
||||
enum {
|
||||
|
@ -147,6 +145,8 @@ enum {
|
|||
Aalpe = 1<<26, /* aggressive link pm enable */
|
||||
Adlae = 1<<25, /* drive led on atapi */
|
||||
Aatapi = 1<<24, /* device is atapi */
|
||||
Apste = 1<<23, /* automatic slumber to partial cap */
|
||||
Afbsc = 1<<22, /* fis-based switching capable */
|
||||
Aesp = 1<<21, /* external sata port */
|
||||
Acpd = 1<<20, /* cold presence detect */
|
||||
Ampsp = 1<<19, /* mechanical pres. */
|
||||
|
@ -164,6 +164,7 @@ enum {
|
|||
Ast = 1<<0, /* start */
|
||||
|
||||
Arun = Ast|Acr|Afre|Afr,
|
||||
Apwr = Apod|Asud,
|
||||
};
|
||||
|
||||
/* ctl register bits */
|
||||
|
@ -173,13 +174,41 @@ enum {
|
|||
Adet = 1<<0, /* device detection */
|
||||
};
|
||||
|
||||
/* sstatus register bits */
|
||||
enum{
|
||||
/* sstatus det */
|
||||
Smissing = 0<<0,
|
||||
Spresent = 1<<0,
|
||||
Sphylink = 3<<0,
|
||||
Sbist = 4<<0,
|
||||
Smask = 7<<0,
|
||||
|
||||
/* sstatus speed */
|
||||
Gmissing = 0<<4,
|
||||
Gi = 1<<4,
|
||||
Gii = 2<<4,
|
||||
Giii = 3<<4,
|
||||
Gmask = 7<<4,
|
||||
|
||||
/* sstatus ipm */
|
||||
Imissing = 0<<8,
|
||||
Iactive = 1<<8,
|
||||
Isleepy = 2<<8,
|
||||
Islumber = 6<<8,
|
||||
Imask = 7<<8,
|
||||
|
||||
SImask = Smask | Imask,
|
||||
SSmask = Smask | Isleepy,
|
||||
};
|
||||
|
||||
#define sstatus scr0
|
||||
#define sctl scr2
|
||||
#define serror scr1
|
||||
#define sactive scr3
|
||||
#define ntf scr4
|
||||
|
||||
typedef struct {
|
||||
ulong list; /* PxCLB must be 1kb aligned. */
|
||||
ulong list; /* PxCLB must be 1kb aligned */
|
||||
ulong listhi;
|
||||
ulong fis; /* 256-byte aligned */
|
||||
ulong fishi;
|
||||
|
@ -194,9 +223,10 @@ typedef struct {
|
|||
ulong scr1;
|
||||
ulong scr3;
|
||||
ulong ci; /* command issue */
|
||||
ulong ntf;
|
||||
uchar res2[8];
|
||||
ulong vendor;
|
||||
ulong scr4;
|
||||
ulong fbs;
|
||||
ulong res2[11];
|
||||
ulong vendor[4];
|
||||
} Aport;
|
||||
|
||||
/* in host's memory; not memory mapped */
|
||||
|
@ -244,26 +274,49 @@ typedef struct {
|
|||
Aprdt prdt;
|
||||
} Actab;
|
||||
|
||||
/* enclosure message header */
|
||||
enum {
|
||||
Mled = 0,
|
||||
Msafte = 1,
|
||||
Mses2 = 2,
|
||||
Msgpio = 3,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uchar dummy;
|
||||
uchar msize;
|
||||
uchar dsize;
|
||||
uchar type;
|
||||
uchar hba; /* bits 0:4 are the port */
|
||||
uchar pm;
|
||||
uchar led[2];
|
||||
} Aledmsg;
|
||||
|
||||
enum {
|
||||
Aled = 1<<0,
|
||||
Locled = 1<<3,
|
||||
Errled = 1<<6,
|
||||
|
||||
Ledoff = 0,
|
||||
Ledon = 1,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint encsz;
|
||||
ulong *enctx;
|
||||
ulong *encrx;
|
||||
} Aenc;
|
||||
|
||||
enum {
|
||||
Ferror = 1,
|
||||
Fdone = 2,
|
||||
};
|
||||
|
||||
enum {
|
||||
Dllba = 1,
|
||||
Dsmart = 1<<1,
|
||||
Dpower = 1<<2,
|
||||
Dnop = 1<<3,
|
||||
Datapi = 1<<4,
|
||||
Datapi16= 1<<5,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
QLock;
|
||||
Rendez;
|
||||
uchar flag;
|
||||
uchar feat;
|
||||
uchar smart;
|
||||
Sfis;
|
||||
Afis fis;
|
||||
Alist *list;
|
||||
Actab *ctab;
|
||||
|
|
|
@ -67,6 +67,7 @@ LIB=\
|
|||
/$objtype/lib/libc.a\
|
||||
/$objtype/lib/libsec.a\
|
||||
/$objtype/lib/libmp.a\
|
||||
/$objtype/lib/libfis.a\
|
||||
|
||||
ETHER=`{echo devether.c ether*.c | sed 's/\.c/.'$O'/g'}
|
||||
VGA=`{echo devvga.c screen.c vga*.c | sed 's/\.c/.'$O'/g'}
|
||||
|
|
|
@ -75,11 +75,13 @@ misc
|
|||
uarti8250
|
||||
uartpci pci
|
||||
|
||||
sdata pci sdscsi
|
||||
sdaoe
|
||||
sdide pci sdscsi
|
||||
sd53c8xx pci sdscsi
|
||||
sdmylex pci sdscsi
|
||||
sdiahci pci sdscsi
|
||||
sdaoe
|
||||
sdiahci pci sdscsi led
|
||||
sdodin pci sdscsi led
|
||||
sdloop
|
||||
|
||||
vga3dfx +cur
|
||||
vgaark2000pv +cur
|
||||
|
|
|
@ -81,11 +81,13 @@ misc
|
|||
archmp mp apic
|
||||
mtrr
|
||||
|
||||
sdata pci sdscsi
|
||||
sdaoe
|
||||
sdide pci sdscsi
|
||||
sd53c8xx pci sdscsi
|
||||
sdmylex pci sdscsi
|
||||
sdiahci pci sdscsi
|
||||
sdaoe
|
||||
sdiahci pci sdscsi led
|
||||
sdodin pci sdscsi led
|
||||
sdloop
|
||||
|
||||
uarti8250
|
||||
uartpci pci
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -840,7 +840,6 @@ mylexprobe(int port, int irq)
|
|||
Ctlr *ctlr;
|
||||
uchar cmd[6], data[256];
|
||||
int clen, dlen, timeo;
|
||||
static int count;
|
||||
|
||||
if(ioalloc(port, 0x3, 0, "mylex") < 0)
|
||||
return nil;
|
||||
|
@ -894,18 +893,13 @@ buggery:
|
|||
if(issue(ctlr, cmd, clen, data, dlen)){
|
||||
if(data[0] == 'E')
|
||||
ctlr->bus = 32;
|
||||
print("mylex ctlr @ port 0x%ux: 32-bit ", ctlr->port);
|
||||
ctlr->wide = data[0x0D] & 0x01;
|
||||
/*
|
||||
* devsd doesn't pass us the `spec' argument, so
|
||||
* we'll assume that sd0 goes to the first scsi host
|
||||
* adapter found, etc.
|
||||
*/
|
||||
print("#S/sd%d: mylex SCSI: port 0x%ux: %d-bit, ",
|
||||
count++, ctlr->port, ctlr->bus);
|
||||
if (ctlr->wide)
|
||||
print("wide\n");
|
||||
print("wide ");
|
||||
else
|
||||
print("narrow\n");
|
||||
print("narrow ");
|
||||
print("SCSI host adapter\n");
|
||||
}
|
||||
else{
|
||||
/*
|
||||
|
@ -1187,8 +1181,9 @@ mylex32enable(Ctlr* ctlr)
|
|||
cmd[1] = 1;
|
||||
if(!issue(ctlr, cmd, 2, 0, 0)) {
|
||||
ctlr->wide = 0;
|
||||
print("mylex32enable: port 0x%ux: scsi wide-mode setup "
|
||||
"failed on wide host adapter", ctlr->port);
|
||||
print(
|
||||
"mylex32enable: ctlr @ port 0x%ux: scsi wide-mode setup failed on wide host adapter",
|
||||
ctlr->port);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
2841
sys/src/9/pc/sdodin.c
Normal file
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 {
|
||||
ACata,
|
||||
ACconfig,
|
||||
ACmask,
|
||||
ACres,
|
||||
};
|
||||
|
||||
enum {
|
||||
|
@ -15,23 +14,55 @@ enum {
|
|||
};
|
||||
|
||||
enum {
|
||||
AEcmd = 1,
|
||||
AEarg,
|
||||
AEdev,
|
||||
AEcfg,
|
||||
AEver,
|
||||
AEunk,
|
||||
AEcmd, /* bad command */
|
||||
AEarg, /* bad argument */
|
||||
AEoff, /* device offline */
|
||||
AEcfg, /* config string already set */
|
||||
AEver, /* unsupported version */
|
||||
AEres, /* target reserved */
|
||||
};
|
||||
|
||||
enum {
|
||||
Aoetype = 0x88a2,
|
||||
Aoesectsz = 512, /* standard sector size */
|
||||
Aoever = 1,
|
||||
/* mask commands */
|
||||
Mread = 0,
|
||||
Medit,
|
||||
|
||||
AFerr = 1<<2,
|
||||
AFrsp = 1<<3,
|
||||
/* mask directives */
|
||||
MDnop = 0,
|
||||
MDadd,
|
||||
MDdel,
|
||||
|
||||
AAFwrite= 1,
|
||||
AAFext = 1<<6,
|
||||
/* mask errors */
|
||||
MEunk = 1,
|
||||
MEbad,
|
||||
MEfull,
|
||||
|
||||
/* reserve / release */
|
||||
Rrread = 0,
|
||||
Rrset,
|
||||
Rrforce,
|
||||
};
|
||||
|
||||
enum {
|
||||
Aoetype = 0x88a2,
|
||||
Aoesectsz = 512,
|
||||
Aoemaxcfg = 1024,
|
||||
|
||||
Aoehsz = 24,
|
||||
Aoeatasz = 12,
|
||||
Aoecfgsz = 8,
|
||||
Aoerrsz = 2,
|
||||
Aoemsz = 4,
|
||||
Aoemdsz = 8,
|
||||
|
||||
Aoever = 1,
|
||||
|
||||
AFerr = 1<<2,
|
||||
AFrsp = 1<<3,
|
||||
|
||||
AAFwrite = 1,
|
||||
AAFext = 1<<6,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
|
@ -44,35 +75,43 @@ typedef struct {
|
|||
uchar minor;
|
||||
uchar cmd;
|
||||
uchar tag[4];
|
||||
uchar payload[];
|
||||
} Aoehdr;
|
||||
|
||||
#define AOEHDRSZ offsetof(Aoehdr, payload[0])
|
||||
|
||||
typedef struct {
|
||||
Aoehdr;
|
||||
uchar aflag;
|
||||
uchar errfeat;
|
||||
uchar scnt;
|
||||
uchar cmdstat;
|
||||
uchar lba[6];
|
||||
uchar res[2];
|
||||
uchar payload[];
|
||||
} Aoeata;
|
||||
|
||||
#define AOEATASZ offsetof(Aoeata, payload[0])
|
||||
|
||||
typedef struct {
|
||||
Aoehdr;
|
||||
uchar bufcnt[2];
|
||||
uchar fwver[2];
|
||||
uchar scnt;
|
||||
uchar verccmd;
|
||||
uchar cslen[2];
|
||||
uchar payload[];
|
||||
} Aoeqc;
|
||||
} Aoecfg;
|
||||
|
||||
#define AOEQCSZ offsetof(Aoeqc, payload[0])
|
||||
typedef struct {
|
||||
uchar dres;
|
||||
uchar dcmd;
|
||||
uchar ea[Eaddrlen];
|
||||
} Aoemd;
|
||||
|
||||
typedef struct {
|
||||
uchar mres;
|
||||
uchar mcmd;
|
||||
uchar merr;
|
||||
uchar mcnt;
|
||||
} Aoem;
|
||||
|
||||
typedef struct {
|
||||
uchar rcmd;
|
||||
uchar nea;
|
||||
uchar ea0[];
|
||||
} Aoerr;
|
||||
|
||||
extern char Echange[];
|
||||
extern char Enotup[];
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -15,7 +15,9 @@
|
|||
extern Dev sddevtab;
|
||||
extern SDifc* sdifc[];
|
||||
|
||||
static char Echange[] = "media or partition has changed";
|
||||
static char Echange[] = "media or partition has changed";
|
||||
static char Enoata[] = "raw ata commands not supported";
|
||||
static char Enoscsi[] = "raw scsi commands not supported";
|
||||
|
||||
static char devletters[] = "0123456789"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
|
@ -23,6 +25,11 @@ static char devletters[] = "0123456789"
|
|||
|
||||
static SDev *devs[sizeof devletters-1];
|
||||
static QLock devslock;
|
||||
static SDunit topctlunit;
|
||||
|
||||
enum {
|
||||
Ahdrsz = 2,
|
||||
};
|
||||
|
||||
enum {
|
||||
Rawcmd,
|
||||
|
@ -40,6 +47,7 @@ enum {
|
|||
Qctl = Qunitbase,
|
||||
Qraw,
|
||||
Qpart,
|
||||
Qextra,
|
||||
|
||||
TypeLOG = 4,
|
||||
NType = (1<<TypeLOG),
|
||||
|
@ -292,7 +300,7 @@ sdgetunit(SDev* sdev, int subno)
|
|||
}
|
||||
sdev->unitflg[subno] = 1;
|
||||
|
||||
snprint(buf, sizeof(buf), "%s%d", sdev->name, subno);
|
||||
snprint(buf, sizeof buf, "%s%x", sdev->name, subno);
|
||||
kstrdup(&unit->name, buf);
|
||||
kstrdup(&unit->user, eve);
|
||||
unit->perm = 0555;
|
||||
|
@ -323,15 +331,14 @@ static void
|
|||
sdreset(void)
|
||||
{
|
||||
int i;
|
||||
SDev *sdev;
|
||||
|
||||
/*
|
||||
* Probe all known controller types and register any devices found.
|
||||
*/
|
||||
for(i = 0; sdifc[i] != nil; i++){
|
||||
if(sdifc[i]->pnp == nil || (sdev = sdifc[i]->pnp()) == nil)
|
||||
if(sdifc[i]->pnp == nil)
|
||||
continue;
|
||||
sdadddevs(sdev);
|
||||
sdadddevs(sdifc[i]->pnp());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -344,8 +351,8 @@ sdadddevs(SDev *sdev)
|
|||
for(; sdev; sdev=next){
|
||||
next = sdev->next;
|
||||
|
||||
sdev->unit = (SDunit**)malloc(sdev->nunit * sizeof(SDunit*));
|
||||
sdev->unitflg = (int*)malloc(sdev->nunit * sizeof(int));
|
||||
sdev->unit = malloc(sdev->nunit * sizeof(SDunit*));
|
||||
sdev->unitflg = malloc(sdev->nunit * sizeof(int));
|
||||
if(sdev->unit == nil || sdev->unitflg == nil){
|
||||
print("sdadddevs: out of memory\n");
|
||||
giveup:
|
||||
|
@ -392,11 +399,12 @@ sd2gen(Chan* c, int i, Dir* dp)
|
|||
{
|
||||
Qid q;
|
||||
uvlong l;
|
||||
SDfile *e;
|
||||
SDpart *pp;
|
||||
SDperm *perm;
|
||||
SDunit *unit;
|
||||
SDev *sdev;
|
||||
int rv;
|
||||
int rv, t;
|
||||
|
||||
sdev = sdgetdev(DEV(c->qid));
|
||||
assert(sdev);
|
||||
|
@ -438,6 +446,18 @@ sd2gen(Chan* c, int i, Dir* dp)
|
|||
devdir(c, q, pp->name, l, pp->user, pp->perm, dp);
|
||||
rv = 1;
|
||||
break;
|
||||
case Qextra:
|
||||
t = PART(c->qid);
|
||||
if(t >= unit->nefile)
|
||||
break;
|
||||
mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qextra),
|
||||
unit->vers, QTFILE);
|
||||
e = unit->efile + t;
|
||||
if(emptystr(e->user))
|
||||
kstrdup(&e->user, eve);
|
||||
devdir(c, q, e->name, 0, e->user, e->perm, dp);
|
||||
rv = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
decref(&sdev->r);
|
||||
|
@ -448,16 +468,45 @@ static int
|
|||
sd1gen(Chan* c, int i, Dir* dp)
|
||||
{
|
||||
Qid q;
|
||||
SDperm *p;
|
||||
|
||||
switch(i){
|
||||
case Qtopctl:
|
||||
mkqid(&q, QID(0, 0, 0, Qtopctl), 0, QTFILE);
|
||||
devdir(c, q, "sdctl", 0, eve, 0640, dp);
|
||||
qlock(&topctlunit.ctl);
|
||||
p = &topctlunit.ctlperm;
|
||||
if(p->user == nil || p->user[0] == 0){
|
||||
kstrdup(&p->name, "sdctl");
|
||||
kstrdup(&p->user, eve);
|
||||
p->perm = 0640;
|
||||
}
|
||||
devdir(c, q, p->name, 0, p->user, p->perm, dp);
|
||||
qunlock(&topctlunit.ctl);
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
efilegen(Chan *c, SDunit *unit, int i, Dir *dp)
|
||||
{
|
||||
Qid q;
|
||||
SDfile *e;
|
||||
|
||||
i -= SDnpart;
|
||||
if(unit->nefile == 0 || i >= unit->nefile)
|
||||
return -1;
|
||||
if(i < 0)
|
||||
return 0;
|
||||
e = unit->efile + i;
|
||||
if(emptystr(e->user))
|
||||
kstrdup(&e->user, eve);
|
||||
mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), i, Qextra),
|
||||
unit->vers, QTFILE);
|
||||
devdir(c, q, e->name, 0, e->user, e->perm, dp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
sdgen(Chan* c, char*, Dirtab*, int, int s, Dir* dp)
|
||||
{
|
||||
|
@ -553,17 +602,18 @@ sdgen(Chan* c, char*, Dirtab*, int, int s, Dir* dp)
|
|||
}
|
||||
i -= Qpart;
|
||||
if(unit->part == nil || i >= unit->npart){
|
||||
r = efilegen(c, unit, i, dp);
|
||||
qunlock(&unit->ctl);
|
||||
decref(&sdev->r);
|
||||
break;
|
||||
return r;
|
||||
}
|
||||
pp = &unit->part[i];
|
||||
if(!pp->valid){
|
||||
if(!pp->valid || unit->sectors == 0){
|
||||
qunlock(&unit->ctl);
|
||||
decref(&sdev->r);
|
||||
return 0;
|
||||
}
|
||||
l = (pp->end - pp->start) * unit->secsize;
|
||||
l = (pp->end - pp->start) * (uvlong)unit->secsize;
|
||||
mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), i, Qpart),
|
||||
unit->vers+pp->vers, QTFILE);
|
||||
if(emptystr(pp->user))
|
||||
|
@ -575,6 +625,7 @@ sdgen(Chan* c, char*, Dirtab*, int, int s, Dir* dp)
|
|||
case Qraw:
|
||||
case Qctl:
|
||||
case Qpart:
|
||||
case Qextra:
|
||||
if((sdev = sdgetdev(DEV(c->qid))) == nil){
|
||||
devdir(c, q, "unavailable", 0, eve, 0, dp);
|
||||
return 1;
|
||||
|
@ -715,10 +766,12 @@ sdclose(Chan* c)
|
|||
}
|
||||
}
|
||||
|
||||
#define iskaddr(a) ((uintptr)(a) > KZERO)
|
||||
|
||||
static long
|
||||
sdbio(Chan* c, int write, char* a, long len, uvlong off)
|
||||
{
|
||||
int nchange;
|
||||
int nchange, hard, allocd;
|
||||
long l;
|
||||
uchar *b;
|
||||
SDpart *pp;
|
||||
|
@ -785,21 +838,30 @@ sdbio(Chan* c, int write, char* a, long len, uvlong off)
|
|||
poperror();
|
||||
}
|
||||
|
||||
b = sdmalloc(nb*unit->secsize);
|
||||
if(b == nil)
|
||||
error(Enomem);
|
||||
offset = off%unit->secsize;
|
||||
if(offset+len > nb*unit->secsize)
|
||||
len = nb*unit->secsize - offset;
|
||||
hard = offset || write && len%unit->secsize;
|
||||
|
||||
if(iskaddr(a) && !hard) {
|
||||
b = (uchar*)a;
|
||||
allocd = 0;
|
||||
}else{
|
||||
b = sdmalloc(nb*unit->secsize);
|
||||
if(b == nil)
|
||||
error(Enomem);
|
||||
allocd = 1;
|
||||
}
|
||||
if(waserror()){
|
||||
sdfree(b);
|
||||
if(allocd)
|
||||
sdfree(b);
|
||||
if(!(unit->inquiry[1] & 0x80))
|
||||
decref(&sdev->r); /* gadverdamme! */
|
||||
nexterror();
|
||||
}
|
||||
|
||||
offset = off%unit->secsize;
|
||||
if(offset+len > nb*unit->secsize)
|
||||
len = nb*unit->secsize - offset;
|
||||
if(write){
|
||||
if(offset || (len%unit->secsize)){
|
||||
if(hard){
|
||||
l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno);
|
||||
if(l < 0)
|
||||
error(Eio);
|
||||
|
@ -810,7 +872,8 @@ sdbio(Chan* c, int write, char* a, long len, uvlong off)
|
|||
len = l;
|
||||
}
|
||||
}
|
||||
memmove(b+offset, a, len);
|
||||
if(allocd)
|
||||
memmove(b+offset, a, len);
|
||||
l = unit->dev->ifc->bio(unit, 0, 1, b, nb, bno);
|
||||
if(l < 0)
|
||||
error(Eio);
|
||||
|
@ -827,9 +890,11 @@ sdbio(Chan* c, int write, char* a, long len, uvlong off)
|
|||
len = 0;
|
||||
else if(len > l - offset)
|
||||
len = l - offset;
|
||||
memmove(a, b+offset, len);
|
||||
if(allocd)
|
||||
memmove(a, b+offset, len);
|
||||
}
|
||||
sdfree(b);
|
||||
if(allocd)
|
||||
sdfree(b);
|
||||
poperror();
|
||||
|
||||
if(unit->inquiry[1] & 0x80){
|
||||
|
@ -844,41 +909,69 @@ sdbio(Chan* c, int write, char* a, long len, uvlong off)
|
|||
static long
|
||||
sdrio(SDreq* r, void* a, long n)
|
||||
{
|
||||
char *errstr;
|
||||
int rv;
|
||||
void *data;
|
||||
SDunit *u;
|
||||
int (*f)(SDreq*);
|
||||
|
||||
if(n >= SDmaxio || n < 0)
|
||||
error(Etoobig);
|
||||
u = r->unit;
|
||||
if(u->haversense && r->cmd[0] == 0x03){
|
||||
u->haversense = 0;
|
||||
r->rlen = sizeof u->rsense;
|
||||
if(r->rlen > n)
|
||||
r->rlen = n;
|
||||
memmove(a, u->rsense, r->rlen);
|
||||
r->status = SDok;
|
||||
return r->rlen;
|
||||
}
|
||||
|
||||
data = nil;
|
||||
if(n){
|
||||
if((data = sdmalloc(n)) == nil)
|
||||
error(Enomem);
|
||||
if(r->write)
|
||||
memmove(data, a, n);
|
||||
}
|
||||
r->data = data;
|
||||
r->dlen = n;
|
||||
|
||||
if(n > 0 && (data = sdmalloc(n)) == nil)
|
||||
error(Enomem);
|
||||
if(waserror()){
|
||||
sdfree(data);
|
||||
r->data = nil;
|
||||
nexterror();
|
||||
}
|
||||
if(r->write && n > 0)
|
||||
memmove(data, a, n);
|
||||
r->data = data;
|
||||
r->dlen = n;
|
||||
|
||||
if(r->unit->dev->ifc->rio(r) != SDok)
|
||||
if(r->proto == SData){
|
||||
f = u->dev->ifc->ataio;
|
||||
errstr = Enoata;
|
||||
}else{
|
||||
f = u->dev->ifc->rio;
|
||||
errstr = Enoscsi;
|
||||
}
|
||||
if(f == nil)
|
||||
error(errstr);
|
||||
rv = f(r);
|
||||
if(r->flags & SDvalidsense){
|
||||
memmove(u->rsense, r->sense, sizeof u->rsense);
|
||||
u->haversense = 1;
|
||||
}
|
||||
if(rv != SDok)
|
||||
error(Eio);
|
||||
|
||||
if(!r->write && r->rlen > 0)
|
||||
memmove(a, data, r->rlen);
|
||||
poperror();
|
||||
sdfree(data);
|
||||
r->data = nil;
|
||||
poperror();
|
||||
|
||||
return r->rlen;
|
||||
}
|
||||
|
||||
/*
|
||||
* SCSI simulation for non-SCSI devices
|
||||
*
|
||||
* see /sys/src/cmd/scuzz/sense.c for information on key.
|
||||
* see /sys/lib/scsicodes for asc:ascq codes
|
||||
*/
|
||||
int
|
||||
sdsetsense(SDreq *r, int status, int key, int asc, int ascq)
|
||||
|
@ -908,36 +1001,7 @@ sdsetsense(SDreq *r, int status, int key, int asc, int ascq)
|
|||
}
|
||||
|
||||
int
|
||||
sdmodesense(SDreq *r, uchar *cmd, void *info, int ilen)
|
||||
{
|
||||
int len;
|
||||
uchar *data;
|
||||
|
||||
/*
|
||||
* Fake a vendor-specific request with page code 0,
|
||||
* return the drive info.
|
||||
*/
|
||||
if((cmd[2] & 0x3F) != 0 && (cmd[2] & 0x3F) != 0x3F)
|
||||
return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
|
||||
len = (cmd[7]<<8)|cmd[8];
|
||||
if(len == 0)
|
||||
return SDok;
|
||||
if(len < 8+ilen)
|
||||
return sdsetsense(r, SDcheck, 0x05, 0x1A, 0);
|
||||
if(r->data == nil || r->dlen < len)
|
||||
return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
|
||||
data = r->data;
|
||||
memset(data, 0, 8);
|
||||
data[0] = ilen>>8;
|
||||
data[1] = ilen;
|
||||
if(ilen)
|
||||
memmove(data+8, info, ilen);
|
||||
r->rlen = 8+ilen;
|
||||
return sdsetsense(r, SDok, 0, 0, 0);
|
||||
}
|
||||
|
||||
int
|
||||
sdfakescsi(SDreq *r, void *info, int ilen)
|
||||
sdfakescsi(SDreq *r)
|
||||
{
|
||||
uchar *cmd, *p;
|
||||
uvlong len;
|
||||
|
@ -947,25 +1011,6 @@ sdfakescsi(SDreq *r, void *info, int ilen)
|
|||
r->rlen = 0;
|
||||
unit = r->unit;
|
||||
|
||||
/*
|
||||
* Rewrite read(6)/write(6) into read(10)/write(10).
|
||||
*/
|
||||
switch(cmd[0]){
|
||||
case 0x08: /* read */
|
||||
case 0x0A: /* write */
|
||||
cmd[9] = 0;
|
||||
cmd[8] = cmd[4];
|
||||
cmd[7] = 0;
|
||||
cmd[6] = 0;
|
||||
cmd[5] = cmd[3];
|
||||
cmd[4] = cmd[2];
|
||||
cmd[3] = cmd[1] & 0x0F;
|
||||
cmd[2] = 0;
|
||||
cmd[1] &= 0xE0;
|
||||
cmd[0] |= 0x20;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Map SCSI commands into ATA commands for discs.
|
||||
* Fail any command with a LUN except INQUIRY which
|
||||
|
@ -1018,13 +1063,15 @@ sdfakescsi(SDreq *r, void *info, int ilen)
|
|||
/*
|
||||
* Read capacity returns the LBA of the last sector.
|
||||
*/
|
||||
len = unit->sectors - 1;
|
||||
len = unit->sectors;
|
||||
if(len > 0)
|
||||
len--;
|
||||
p = r->data;
|
||||
*p++ = len>>24;
|
||||
*p++ = len>>16;
|
||||
*p++ = len>>8;
|
||||
*p++ = len;
|
||||
len = 512;
|
||||
len = unit->secsize;
|
||||
*p++ = len>>24;
|
||||
*p++ = len>>16;
|
||||
*p++ = len>>8;
|
||||
|
@ -1040,7 +1087,9 @@ sdfakescsi(SDreq *r, void *info, int ilen)
|
|||
/*
|
||||
* Read capcity returns the LBA of the last sector.
|
||||
*/
|
||||
len = unit->sectors - 1;
|
||||
len = unit->sectors;
|
||||
if(len > 0)
|
||||
len--;
|
||||
p = r->data;
|
||||
*p++ = len>>56;
|
||||
*p++ = len>>48;
|
||||
|
@ -1050,32 +1099,124 @@ sdfakescsi(SDreq *r, void *info, int ilen)
|
|||
*p++ = len>>16;
|
||||
*p++ = len>>8;
|
||||
*p++ = len;
|
||||
len = 512;
|
||||
len = unit->secsize;
|
||||
*p++ = len>>24;
|
||||
*p++ = len>>16;
|
||||
*p++ = len>>8;
|
||||
*p++ = len;
|
||||
r->rlen = p - (uchar*)r->data;
|
||||
return sdsetsense(r, SDok, 0, 0, 0);
|
||||
|
||||
case 0x5A: /* mode sense */
|
||||
return sdmodesense(r, cmd, info, ilen);
|
||||
|
||||
case 0x28: /* read */
|
||||
case 0x2A: /* write */
|
||||
case 0x08: /* read6 */
|
||||
case 0x0a: /* write6 */
|
||||
case 0x28: /* read10 */
|
||||
case 0x2a: /* write10 */
|
||||
case 0xa8: /* read12 */
|
||||
case 0xaa: /* write12 */
|
||||
case 0x88: /* read16 */
|
||||
case 0x8a: /* write16 */
|
||||
return SDnostatus;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
sdfakescsirw(SDreq *r, uvlong *llba, int *nsec, int *rwp)
|
||||
{
|
||||
uchar *c;
|
||||
int rw, count;
|
||||
uvlong lba;
|
||||
|
||||
c = r->cmd;
|
||||
rw = SDread;
|
||||
if((c[0] & 0xf) == 0xa)
|
||||
rw = SDwrite;
|
||||
switch(c[0]){
|
||||
case 0x08: /* read6 */
|
||||
case 0x0a:
|
||||
lba = (c[1] & 0xf)<<16 | c[2]<<8 | c[3];
|
||||
count = c[4];
|
||||
break;
|
||||
case 0x28: /* read10 */
|
||||
case 0x2a:
|
||||
lba = c[2]<<24 | c[3]<<16 | c[4]<<8 | c[5];
|
||||
count = c[7]<<8 | c[8];
|
||||
break;
|
||||
case 0xa8: /* read12 */
|
||||
case 0xaa:
|
||||
lba = c[2]<<24 | c[3]<<16 | c[4]<<8 | c[5];
|
||||
count = c[6]<<24 | c[7]<<16 | c[8]<<8 | c[9];
|
||||
break;
|
||||
case 0x88: /* read16 */
|
||||
case 0x8a:
|
||||
/* ata commands only go to 48-bit lba */
|
||||
if(c[2] || c[3])
|
||||
return sdsetsense(r, SDcheck, 3, 0xc, 2);
|
||||
lba = (uvlong)c[4]<<40 | (uvlong)c[5]<<32;
|
||||
lba |= c[6]<<24 | c[7]<<16 | c[8]<<8 | c[9];
|
||||
count = c[10]<<24 | c[11]<<16 | c[12]<<8 | c[13];
|
||||
break;
|
||||
default:
|
||||
print("%s: bad cmd 0x%.2ux\n", r->unit->name, c[0]);
|
||||
r->status = sdsetsense(r, SDcheck, 0x05, 0x20, 0);
|
||||
return SDcheck;
|
||||
}
|
||||
if(r->data == nil)
|
||||
return SDok;
|
||||
if(r->dlen < count * r->unit->secsize)
|
||||
count = r->dlen/r->unit->secsize;
|
||||
if(rwp)
|
||||
*rwp = rw;
|
||||
*llba = lba;
|
||||
*nsec = count;
|
||||
return SDnostatus;
|
||||
}
|
||||
|
||||
static long
|
||||
extrarw(int write, Chan *c, void *a, long n, vlong off)
|
||||
{
|
||||
int i;
|
||||
SDrw *f;
|
||||
SDev *sdev;
|
||||
SDunit *unit;
|
||||
|
||||
sdev = sdgetdev(DEV(c->qid));
|
||||
if(sdev == nil)
|
||||
error(Enonexist);
|
||||
if(waserror()){
|
||||
decref(&sdev->r);
|
||||
nexterror();
|
||||
}
|
||||
unit = sdev->unit[UNIT(c->qid)];
|
||||
if(unit->vers != c->qid.vers)
|
||||
error(Echange);
|
||||
unit = sdev->unit[UNIT(c->qid)];
|
||||
i = PART(c->qid);
|
||||
if(i >= unit->nefile)
|
||||
error(Enonexist);
|
||||
f = unit->efile[i].r;
|
||||
if(write)
|
||||
f = unit->efile[i].w;
|
||||
if(i >= unit->nefile || f == nil)
|
||||
error(Eperm);
|
||||
n = f(unit, c, a, n, off);
|
||||
poperror();
|
||||
decref(&sdev->r);
|
||||
return n;
|
||||
}
|
||||
|
||||
static char*
|
||||
deftopctl(SDev *s, char *p, char *e)
|
||||
{
|
||||
return seprint(p, e, "sd%c %s %d units\n", s->idno, s->ifc->name, s->nunit);
|
||||
}
|
||||
|
||||
static long
|
||||
sdread(Chan *c, void *a, long n, vlong off)
|
||||
{
|
||||
char *p, *e, *buf;
|
||||
SDpart *pp;
|
||||
SDunit *unit;
|
||||
SDev *sdev;
|
||||
SDpart *pp;
|
||||
SDreq *r;
|
||||
SDunit *unit;
|
||||
ulong offset;
|
||||
int i, l, m, status;
|
||||
|
||||
|
@ -1093,6 +1234,8 @@ sdread(Chan *c, void *a, long n, vlong off)
|
|||
sdev = devs[i];
|
||||
if(sdev && sdev->ifc->rtopctl)
|
||||
p = sdev->ifc->rtopctl(sdev, p, e);
|
||||
else if(sdev)
|
||||
p = deftopctl(sdev, p, e);
|
||||
}
|
||||
qunlock(&devslock);
|
||||
n = readstr(off, a, n, buf);
|
||||
|
@ -1157,23 +1300,38 @@ sdread(Chan *c, void *a, long n, vlong off)
|
|||
}
|
||||
if(unit->state == Rawdata){
|
||||
unit->state = Rawstatus;
|
||||
i = sdrio(unit->req, a, n);
|
||||
r = unit->req;
|
||||
r->timeout = 0;
|
||||
i = sdrio(r, a, n);
|
||||
}
|
||||
else if(unit->state == Rawstatus){
|
||||
status = unit->req->status;
|
||||
unit->state = Rawcmd;
|
||||
free(unit->req);
|
||||
r = unit->req;
|
||||
unit->req = nil;
|
||||
i = readnum(0, a, n, status, NUMSIZE);
|
||||
unit->state = Rawcmd;
|
||||
status = r->status;
|
||||
if(r->proto == SData){
|
||||
p = a;
|
||||
i = 16 + Ahdrsz;
|
||||
if(n < i)
|
||||
i = n;
|
||||
if(i > 0)
|
||||
p[0] = status;
|
||||
if(i > Ahdrsz)
|
||||
memmove(p + Ahdrsz, r->cmd, i - Ahdrsz);
|
||||
}else
|
||||
i = readnum(0, a, n, status, NUMSIZE);
|
||||
free(r);
|
||||
} else
|
||||
i = 0;
|
||||
poperror();
|
||||
qunlock(&unit->raw);
|
||||
decref(&sdev->r);
|
||||
poperror();
|
||||
return i;
|
||||
|
||||
case Qpart:
|
||||
return sdbio(c, 0, a, n, off);
|
||||
case Qextra:
|
||||
return extrarw(0, c, a, n, off);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1183,7 +1341,8 @@ static long
|
|||
sdwrite(Chan* c, void* a, long n, vlong off)
|
||||
{
|
||||
char *f0;
|
||||
int i;
|
||||
int i, atacdb, proto, ataproto;
|
||||
uchar *u;
|
||||
uvlong end, start;
|
||||
Cmdbuf *cb;
|
||||
SDifc *ifc;
|
||||
|
@ -1250,7 +1409,7 @@ sdwrite(Chan* c, void* a, long n, vlong off)
|
|||
error(Ebadctl);
|
||||
poperror();
|
||||
poperror();
|
||||
if (sdev)
|
||||
if(sdev)
|
||||
decref(&sdev->r);
|
||||
free(cb);
|
||||
break;
|
||||
|
@ -1299,6 +1458,9 @@ sdwrite(Chan* c, void* a, long n, vlong off)
|
|||
break;
|
||||
|
||||
case Qraw:
|
||||
proto = SDcdb;
|
||||
ataproto = 0;
|
||||
atacdb = 0;
|
||||
sdev = sdgetdev(DEV(c->qid));
|
||||
if(sdev == nil)
|
||||
error(Enonexist);
|
||||
|
@ -1311,18 +1473,34 @@ sdwrite(Chan* c, void* a, long n, vlong off)
|
|||
}
|
||||
switch(unit->state){
|
||||
case Rawcmd:
|
||||
/* sneaky ata commands */
|
||||
u = a;
|
||||
if(n > 1 && *u == 0xff){
|
||||
proto = SData;
|
||||
ataproto = u[1];
|
||||
a = u + 2;
|
||||
atacdb = Ahdrsz;
|
||||
n -= Ahdrsz;
|
||||
}
|
||||
if(n < 6 || n > sizeof(req->cmd))
|
||||
error(Ebadarg);
|
||||
if((req = malloc(sizeof(SDreq))) == nil)
|
||||
error(Enomem);
|
||||
req->unit = unit;
|
||||
if(waserror()){
|
||||
free(req);
|
||||
nexterror();
|
||||
}
|
||||
memmove(req->cmd, a, n);
|
||||
poperror();
|
||||
req->clen = n;
|
||||
req->flags = SDnosense;
|
||||
/* req->flags = SDnosense; */
|
||||
req->status = ~0;
|
||||
|
||||
req->proto = proto;
|
||||
req->ataproto = ataproto;
|
||||
unit->req = req;
|
||||
unit->state = Rawdata;
|
||||
n += atacdb;
|
||||
break;
|
||||
|
||||
case Rawstatus:
|
||||
|
@ -1333,15 +1511,18 @@ sdwrite(Chan* c, void* a, long n, vlong off)
|
|||
|
||||
case Rawdata:
|
||||
unit->state = Rawstatus;
|
||||
unit->req->write = 1;
|
||||
n = sdrio(unit->req, a, n);
|
||||
req = unit->req;
|
||||
req->write = 1;
|
||||
n = sdrio(req, a, n);
|
||||
}
|
||||
poperror();
|
||||
qunlock(&unit->raw);
|
||||
decref(&sdev->r);
|
||||
poperror();
|
||||
break;
|
||||
case Qpart:
|
||||
return sdbio(c, 1, a, n, off);
|
||||
case Qextra:
|
||||
return extrarw(1, c, a, n, off);
|
||||
}
|
||||
|
||||
return n;
|
||||
|
@ -1358,23 +1539,30 @@ sdwstat(Chan* c, uchar* dp, int n)
|
|||
|
||||
if(c->qid.type & QTDIR)
|
||||
error(Eperm);
|
||||
|
||||
sdev = sdgetdev(DEV(c->qid));
|
||||
if(sdev == nil)
|
||||
error(Enonexist);
|
||||
unit = sdev->unit[UNIT(c->qid)];
|
||||
if(TYPE(c->qid) == Qtopctl){
|
||||
unit = &topctlunit;
|
||||
sdev = nil;
|
||||
}else{
|
||||
sdev = sdgetdev(DEV(c->qid));
|
||||
if(sdev == nil)
|
||||
error(Enonexist);
|
||||
unit = sdev->unit[UNIT(c->qid)];
|
||||
}
|
||||
qlock(&unit->ctl);
|
||||
|
||||
d = nil;
|
||||
if(waserror()){
|
||||
free(d);
|
||||
qunlock(&unit->ctl);
|
||||
decref(&sdev->r);
|
||||
if(sdev != nil)
|
||||
decref(&sdev->r);
|
||||
nexterror();
|
||||
}
|
||||
|
||||
switch(TYPE(c->qid)){
|
||||
default:
|
||||
error(Eperm);
|
||||
case Qtopctl:
|
||||
case Qctl:
|
||||
perm = &unit->ctlperm;
|
||||
break;
|
||||
|
@ -1396,14 +1584,22 @@ sdwstat(Chan* c, uchar* dp, int n)
|
|||
n = convM2D(dp, n, &d[0], (char*)&d[1]);
|
||||
if(n == 0)
|
||||
error(Eshortstat);
|
||||
if(d->atime != ~0 || d->mtime != ~0 || d->length != ~0)
|
||||
error(Eperm);
|
||||
if(!emptystr(d[0].muid) || !emptystr(d[0].name))
|
||||
error(Eperm);
|
||||
if(!emptystr(d[0].uid))
|
||||
kstrdup(&perm->user, d[0].uid);
|
||||
if(!emptystr(d[0].gid) && strcmp(d[0].gid, eve) != 0)
|
||||
error(Eperm);
|
||||
if(d[0].mode != ~0UL)
|
||||
perm->perm = (perm->perm & ~0777) | (d[0].mode & 0777);
|
||||
|
||||
free(d);
|
||||
d = nil; USED(d);
|
||||
qunlock(&unit->ctl);
|
||||
decref(&sdev->r);
|
||||
if(sdev != nil)
|
||||
decref(&sdev->r);
|
||||
poperror();
|
||||
return n;
|
||||
}
|
||||
|
@ -1487,13 +1683,62 @@ sdconfig(int on, char* spec, DevConf* cf)
|
|||
return unconfigure(spec);
|
||||
}
|
||||
|
||||
int
|
||||
sdaddfile(SDunit *unit, char *s, int perm, char *u, SDrw *r, SDrw *w)
|
||||
{
|
||||
int i;
|
||||
SDfile *e;
|
||||
static Lock lk;
|
||||
|
||||
if(unit == nil)
|
||||
return -1;
|
||||
lock(&lk);
|
||||
for(i = 0; i < unit->nefile; i++)
|
||||
if(strcmp(unit->efile[i].name, s) == 0)
|
||||
break;
|
||||
if(i >= nelem(unit->efile)){
|
||||
unlock(&lk);
|
||||
return -1;
|
||||
}
|
||||
if(i >= unit->nefile)
|
||||
unit->nefile = i + 1;
|
||||
e = unit->efile + i;
|
||||
if(e->name == nil)
|
||||
kstrdup(&e->name, s);
|
||||
if(e->user == nil)
|
||||
kstrdup(&e->user, u);
|
||||
e->perm = perm;
|
||||
e->r = r;
|
||||
e->w = w;
|
||||
unlock(&lk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
sdshutdown(void)
|
||||
{
|
||||
int i;
|
||||
SDev *sd;
|
||||
|
||||
for(i = 0; i < nelem(devs); i++){
|
||||
sd = devs[i];
|
||||
if(sd == nil)
|
||||
continue;
|
||||
if(sd->ifc->disable == nil){
|
||||
print("#S/sd%c: no disable function\n", devletters[i]);
|
||||
continue;
|
||||
}
|
||||
sd->ifc->disable(sd);
|
||||
}
|
||||
}
|
||||
|
||||
Dev sddevtab = {
|
||||
'S',
|
||||
"sd",
|
||||
|
||||
sdreset,
|
||||
devinit,
|
||||
devshutdown,
|
||||
sdshutdown,
|
||||
sdattach,
|
||||
sdwalk,
|
||||
sdstat,
|
||||
|
@ -1544,7 +1789,7 @@ getnewport(DevConf* dc)
|
|||
{
|
||||
Devport *p;
|
||||
|
||||
p = (Devport *)malloc((dc->nports + 1) * sizeof(Devport));
|
||||
p = malloc((dc->nports + 1) * sizeof(Devport));
|
||||
if(dc->nports > 0){
|
||||
memmove(p, dc->ports, dc->nports * sizeof(Devport));
|
||||
free(dc->ports);
|
||||
|
@ -1635,7 +1880,6 @@ legacytopctl(Cmdbuf *cb)
|
|||
if(j == nelem(options))
|
||||
error(Ebadarg);
|
||||
}
|
||||
/* this has been rewritten to accomodate sdaoe */
|
||||
if(cd.on < 0 || cd.spec == 0)
|
||||
error(Ebadarg);
|
||||
if(cd.on && cd.cf.type == nil)
|
||||
|
|
62
sys/src/9/port/led.c
Normal file
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 sprint 2
|
||||
|
||||
#pragma varargck type "llb" vlong
|
||||
#pragma varargck type "lld" vlong
|
||||
#pragma varargck type "llx" vlong
|
||||
#pragma varargck type "llb" uvlong
|
||||
#pragma varargck type "lld" uvlong
|
||||
#pragma varargck type "llx" uvlong
|
||||
#pragma varargck type "lb" long
|
||||
#pragma varargck type "ld" long
|
||||
#pragma varargck type "lx" long
|
||||
#pragma varargck type "lb" ulong
|
||||
#pragma varargck type "ld" ulong
|
||||
#pragma varargck type "lx" ulong
|
||||
#pragma varargck type "b" int
|
||||
#pragma varargck type "d" int
|
||||
#pragma varargck type "x" int
|
||||
#pragma varargck type "c" int
|
||||
#pragma varargck type "C" int
|
||||
#pragma varargck type "b" uint
|
||||
#pragma varargck type "d" uint
|
||||
#pragma varargck type "x" uint
|
||||
#pragma varargck type "c" uint
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* Storage Device.
|
||||
*/
|
||||
typedef struct SDev SDev;
|
||||
typedef struct SDfile SDfile;
|
||||
typedef struct SDifc SDifc;
|
||||
typedef struct SDpart SDpart;
|
||||
typedef struct SDperm SDperm;
|
||||
|
@ -22,11 +23,20 @@ struct SDpart {
|
|||
ulong vers;
|
||||
};
|
||||
|
||||
typedef long SDrw(SDunit*, Chan*, void*, long, vlong);
|
||||
struct SDfile {
|
||||
SDperm;
|
||||
SDrw *r;
|
||||
SDrw *w;
|
||||
};
|
||||
|
||||
struct SDunit {
|
||||
SDev* dev;
|
||||
int subno;
|
||||
uchar inquiry[255]; /* format follows SCSI spec */
|
||||
uchar sense[18]; /* format follows SCSI spec */
|
||||
uchar rsense[18]; /* support seperate rq sense and inline return */
|
||||
uchar haversense;
|
||||
SDperm;
|
||||
|
||||
QLock ctl;
|
||||
|
@ -42,6 +52,8 @@ struct SDunit {
|
|||
int state;
|
||||
SDreq* req;
|
||||
SDperm rawperm;
|
||||
SDfile efile[5];
|
||||
int nefile;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -67,7 +79,7 @@ struct SDifc {
|
|||
char* name;
|
||||
|
||||
SDev* (*pnp)(void);
|
||||
SDev* (*legacy)(int, int);
|
||||
SDev* (*xxlegacy)(int, int); /* unused. remove me */
|
||||
int (*enable)(SDev*);
|
||||
int (*disable)(SDev*);
|
||||
|
||||
|
@ -82,22 +94,26 @@ struct SDifc {
|
|||
void (*clear)(SDev*);
|
||||
char* (*rtopctl)(SDev*, char*, char*);
|
||||
int (*wtopctl)(SDev*, Cmdbuf*);
|
||||
int (*ataio)(SDreq*);
|
||||
};
|
||||
|
||||
struct SDreq {
|
||||
SDunit* unit;
|
||||
int lun;
|
||||
int write;
|
||||
uchar cmd[16];
|
||||
char write;
|
||||
char proto;
|
||||
char ataproto;
|
||||
uchar cmd[0x20];
|
||||
int clen;
|
||||
void* data;
|
||||
int dlen;
|
||||
|
||||
int flags;
|
||||
ulong timeout; /* in ticks */
|
||||
|
||||
int status;
|
||||
long rlen;
|
||||
uchar sense[256];
|
||||
uchar sense[32];
|
||||
};
|
||||
|
||||
enum {
|
||||
|
@ -119,6 +135,12 @@ enum {
|
|||
|
||||
SDmaxio = 2048*1024,
|
||||
SDnpart = 16,
|
||||
|
||||
SDread = 0,
|
||||
SDwrite,
|
||||
|
||||
SData = 1,
|
||||
SDcdb = 2,
|
||||
};
|
||||
|
||||
#define sdmalloc(n) malloc(n)
|
||||
|
@ -127,11 +149,11 @@ enum {
|
|||
/* devsd.c */
|
||||
extern void sdadddevs(SDev*);
|
||||
extern int sdsetsense(SDreq*, int, int, int, int);
|
||||
extern int sdmodesense(SDreq*, uchar*, void*, int);
|
||||
extern int sdfakescsi(SDreq*, void*, int);
|
||||
extern int sdfakescsi(SDreq*);
|
||||
extern int sdfakescsirw(SDreq*, uvlong*, int*, int*);
|
||||
extern int sdaddfile(SDunit*, char*, int, char*, SDrw*, SDrw*);
|
||||
|
||||
/* sdscsi.c */
|
||||
extern int scsiverify(SDunit*);
|
||||
extern int scsionline(SDunit*);
|
||||
extern long scsibio(SDunit*, int, int, void*, long, uvlong);
|
||||
extern SDev* scsiid(SDev*, SDifc*);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* aoe sd driver, copyright © 2007 coraid
|
||||
* aoe sd driver, copyright © 2007-9 coraid
|
||||
*/
|
||||
|
||||
#include "u.h"
|
||||
|
@ -12,6 +12,7 @@
|
|||
#include "../port/sd.h"
|
||||
#include "../port/netif.h"
|
||||
#include "../port/aoe.h"
|
||||
#include <fis.h>
|
||||
|
||||
extern char Echange[];
|
||||
extern char Enotup[];
|
||||
|
@ -19,34 +20,14 @@ extern char Enotup[];
|
|||
#define uprint(...) snprint(up->genbuf, sizeof up->genbuf, __VA_ARGS__);
|
||||
|
||||
enum {
|
||||
Nctlr = 32,
|
||||
Maxpath = 128,
|
||||
Maxpath = 128,
|
||||
|
||||
Probeintvl = 100, /* ms. between probes */
|
||||
Probemax = 20, /* max probes */
|
||||
};
|
||||
|
||||
enum {
|
||||
/* sync with ahci.h */
|
||||
Dllba = 1<<0,
|
||||
Dsmart = 1<<1,
|
||||
Dpower = 1<<2,
|
||||
Dnop = 1<<3,
|
||||
Datapi = 1<<4,
|
||||
Datapi16= 1<<5,
|
||||
};
|
||||
|
||||
static char *flagname[] = {
|
||||
"llba",
|
||||
"smart",
|
||||
"power",
|
||||
"nop",
|
||||
"atapi",
|
||||
"atapi16",
|
||||
Probemax = 10*1000, /* max ms. to wait */
|
||||
};
|
||||
|
||||
typedef struct Ctlr Ctlr;
|
||||
struct Ctlr{
|
||||
struct Ctlr {
|
||||
QLock;
|
||||
|
||||
Ctlr *next;
|
||||
|
@ -56,11 +37,8 @@ struct Ctlr{
|
|||
Chan *c;
|
||||
|
||||
ulong vers;
|
||||
uchar mediachange;
|
||||
uchar flag;
|
||||
uchar smart;
|
||||
uchar smartrs;
|
||||
uchar feat;
|
||||
uchar drivechange;
|
||||
Sfis;
|
||||
|
||||
uvlong sectors;
|
||||
char serial[20+1];
|
||||
|
@ -69,88 +47,60 @@ struct Ctlr{
|
|||
char ident[0x100];
|
||||
};
|
||||
|
||||
void aoeidmove(char *p, ushort *a, unsigned n);
|
||||
|
||||
static Lock ctlrlock;
|
||||
static Ctlr *head;
|
||||
static Ctlr *tail;
|
||||
|
||||
SDifc sdaoeifc;
|
||||
|
||||
static ushort
|
||||
gbit16(void *a)
|
||||
{
|
||||
uchar *i;
|
||||
|
||||
i = a;
|
||||
return i[1] << 8 | i[0];
|
||||
}
|
||||
|
||||
static ulong
|
||||
gbit32(void *a)
|
||||
{
|
||||
ulong j;
|
||||
uchar *i;
|
||||
|
||||
i = a;
|
||||
j = i[3] << 24;
|
||||
j |= i[2] << 16;
|
||||
j |= i[1] << 8;
|
||||
j |= i[0];
|
||||
return j;
|
||||
}
|
||||
|
||||
static uvlong
|
||||
gbit64(void *a)
|
||||
{
|
||||
uchar *i;
|
||||
|
||||
i = a;
|
||||
return (uvlong)gbit32(i+4)<<32 | gbit32(i);
|
||||
}
|
||||
|
||||
static int
|
||||
identify(Ctlr *c, ushort *id)
|
||||
{
|
||||
int i;
|
||||
uchar oserial[21];
|
||||
uvlong osectors, s;
|
||||
vlong osectors, s;
|
||||
|
||||
osectors = c->sectors;
|
||||
memmove(oserial, c->serial, sizeof c->serial);
|
||||
|
||||
c->feat &= ~(Dllba|Dpower|Dsmart|Dnop);
|
||||
i = gbit16(id+83) | gbit16(id+86);
|
||||
if(i & (1<<10)){
|
||||
c->feat |= Dllba;
|
||||
s = gbit64(id+100);
|
||||
}else
|
||||
s = gbit32(id+60);
|
||||
|
||||
i = gbit16(id+83);
|
||||
if((i>>14) == 1) {
|
||||
if(i & (1<<3))
|
||||
c->feat |= Dpower;
|
||||
i = gbit16(id+82);
|
||||
if(i & 1)
|
||||
c->feat |= Dsmart;
|
||||
if(i & (1<<14))
|
||||
c->feat |= Dnop;
|
||||
s = idfeat(c, id);
|
||||
if(s == -1){
|
||||
uprint("%s: identify fails", c->unit->name);
|
||||
print("%s\n", up->genbuf);
|
||||
error(up->genbuf);
|
||||
}
|
||||
|
||||
aoeidmove(c->serial, id+10, 20);
|
||||
aoeidmove(c->firmware, id+23, 8);
|
||||
aoeidmove(c->model, id+27, 40);
|
||||
idmove(c->serial, id+10, 20);
|
||||
idmove(c->firmware, id+23, 8);
|
||||
idmove(c->model, id+27, 40);
|
||||
|
||||
if((osectors == 0 || osectors != s) &&
|
||||
memcmp(oserial, c->serial, sizeof oserial) != 0){
|
||||
c->sectors = s;
|
||||
c->mediachange = 1;
|
||||
c->drivechange = 1;
|
||||
c->vers++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
aoectl(Ctlr *d, char *s)
|
||||
{
|
||||
Chan *c;
|
||||
|
||||
c = nil;
|
||||
if(waserror()){
|
||||
if(c)
|
||||
cclose(c);
|
||||
print("sdaoectl: %s\n", up->errstr);
|
||||
nexterror();
|
||||
}
|
||||
|
||||
uprint("%s/ctl", d->path);
|
||||
c = namec(up->genbuf, Aopen, OWRITE, 0);
|
||||
devtab[c->type]->write(c, s, strlen(s), 0);
|
||||
|
||||
poperror();
|
||||
cclose(c);
|
||||
}
|
||||
|
||||
/* must call with d qlocked */
|
||||
static int
|
||||
aoeidentify(Ctlr *d, SDunit *u)
|
||||
|
@ -173,7 +123,6 @@ aoeidentify(Ctlr *d, SDunit *u)
|
|||
cclose(c);
|
||||
|
||||
d->feat = 0;
|
||||
d->smart = 0;
|
||||
identify(d, (ushort*)d->ident);
|
||||
|
||||
memset(u->inquiry, 0, sizeof u->inquiry);
|
||||
|
@ -203,7 +152,6 @@ newctlr(char *path)
|
|||
{
|
||||
Ctlr *c;
|
||||
|
||||
/* race? */
|
||||
if(ctlrlookup(path))
|
||||
error(Eexist);
|
||||
|
||||
|
@ -248,7 +196,6 @@ delctlr(Ctlr *c)
|
|||
free(x);
|
||||
}
|
||||
|
||||
/* don't call aoeprobe from within a loop; it loops internally retrying open. */
|
||||
static SDev*
|
||||
aoeprobe(char *path, SDev *s)
|
||||
{
|
||||
|
@ -273,21 +220,24 @@ aoeprobe(char *path, SDev *s)
|
|||
poperror();
|
||||
cclose(c);
|
||||
|
||||
for(i = 0; i < Probemax; i++){
|
||||
for(i = 0;; i += Probeintvl){
|
||||
if(i > Probemax || waserror())
|
||||
error(Etimedout);
|
||||
tsleep(&up->sleep, return0, 0, Probeintvl);
|
||||
poperror();
|
||||
|
||||
uprint("%s/ident", path);
|
||||
if(!waserror()) {
|
||||
c = namec(up->genbuf, Aopen, OREAD, 0);
|
||||
poperror();
|
||||
cclose(c);
|
||||
break;
|
||||
}
|
||||
if(waserror())
|
||||
continue;
|
||||
c = namec(up->genbuf, Aopen, OREAD, 0);
|
||||
poperror();
|
||||
cclose(c);
|
||||
|
||||
ctlr = newctlr(path);
|
||||
break;
|
||||
}
|
||||
if(i >= Probemax)
|
||||
error(Etimedout);
|
||||
uprint("%s/ident", path);
|
||||
ctlr = newctlr(path);
|
||||
if(ctlr == nil || s == nil && (s = malloc(sizeof *s)) == nil)
|
||||
|
||||
if(s == nil && (s = malloc(sizeof *s)) == nil)
|
||||
return nil;
|
||||
s->ctlr = ctlr;
|
||||
s->ifc = &sdaoeifc;
|
||||
|
@ -296,14 +246,20 @@ aoeprobe(char *path, SDev *s)
|
|||
}
|
||||
|
||||
static char *probef[32];
|
||||
static char *probebuf;
|
||||
static int nprobe;
|
||||
|
||||
static int
|
||||
pnpprobeid(char *s)
|
||||
{
|
||||
int id;
|
||||
|
||||
if(strlen(s) < 2)
|
||||
return 0;
|
||||
return s[1] == '!'? s[0]: 'e';
|
||||
id = 'e';
|
||||
if(s[1] == '!')
|
||||
id = s[0];
|
||||
return id;
|
||||
}
|
||||
|
||||
static SDev*
|
||||
|
@ -315,7 +271,8 @@ aoepnp(void)
|
|||
|
||||
if((p = getconf("aoedev")) == 0)
|
||||
return 0;
|
||||
nprobe = tokenize(p, probef, nelem(probef));
|
||||
kstrdup(&probebuf, p);
|
||||
nprobe = tokenize(probebuf, probef, nelem(probef));
|
||||
h = t = 0;
|
||||
for(i = 0; i < nprobe; i++){
|
||||
id = pnpprobeid(probef[i]);
|
||||
|
@ -341,7 +298,7 @@ aoepnp(void)
|
|||
static Ctlr*
|
||||
pnpprobe(SDev *sd)
|
||||
{
|
||||
ulong start;
|
||||
int j;
|
||||
char *p;
|
||||
static int i;
|
||||
|
||||
|
@ -353,17 +310,21 @@ pnpprobe(SDev *sd)
|
|||
if(p[1] == '!')
|
||||
p += 2;
|
||||
|
||||
start = TK2MS(MACHP(0)->ticks);
|
||||
if(waserror()){
|
||||
print("#æ: pnpprobe failed in %lud ms: %s: %s\n",
|
||||
TK2MS(MACHP(0)->ticks) - start, probef[i-1],
|
||||
up->errstr);
|
||||
return nil;
|
||||
for(j = 0;; j += Probeintvl){
|
||||
if(j > Probemax){
|
||||
print("#æ: pnpprobe: %s: %s\n", probef[i-1], up->errstr);
|
||||
return 0;
|
||||
}
|
||||
if(waserror()){
|
||||
tsleep(&up->sleep, return0, 0, Probeintvl);
|
||||
continue;
|
||||
}
|
||||
sd = aoeprobe(p, sd);
|
||||
poperror();
|
||||
break;
|
||||
}
|
||||
sd = aoeprobe(p, sd); /* does a round of probing */
|
||||
poperror();
|
||||
print("#æ: pnpprobe established %s in %lud ms\n",
|
||||
probef[i-1], TK2MS(MACHP(0)->ticks) - start);
|
||||
print("#æ: pnpprobe establishes %s in %dms\n", probef[i-1], j);
|
||||
aoectl(sd->ctlr, "nofail on");
|
||||
return sd->ctlr;
|
||||
}
|
||||
|
||||
|
@ -378,7 +339,7 @@ aoeverify(SDunit *u)
|
|||
c = s->ctlr;
|
||||
if(c == nil && (s->ctlr = c = pnpprobe(s)) == nil)
|
||||
return 0;
|
||||
c->mediachange = 1;
|
||||
c->drivechange = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -412,17 +373,17 @@ aoeonline(SDunit *u)
|
|||
c = u->dev->ctlr;
|
||||
r = 0;
|
||||
|
||||
if((c->feat&Datapi) && c->mediachange){
|
||||
if((c->feat&Datapi) && c->drivechange){
|
||||
if(aoeconnect(u, c) == 0 && (r = scsionline(u)) > 0)
|
||||
c->mediachange = 0;
|
||||
c->drivechange = 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
if(c->mediachange){
|
||||
if(c->drivechange){
|
||||
if(aoeconnect(u, c) == -1)
|
||||
return 0;
|
||||
r = 2;
|
||||
c->mediachange = 0;
|
||||
c->drivechange = 0;
|
||||
u->sectors = c->sectors;
|
||||
u->secsize = Aoesectsz;
|
||||
} else
|
||||
|
@ -431,103 +392,70 @@ aoeonline(SDunit *u)
|
|||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
aoerio(SDreq *r)
|
||||
static long
|
||||
aoebio(SDunit *u, int, int write, void *a, long count, uvlong lba)
|
||||
{
|
||||
int i, count;
|
||||
uvlong lba;
|
||||
char *name;
|
||||
uchar *cmd;
|
||||
uchar *data;
|
||||
int n;
|
||||
long (*rio)(Chan*, void*, long, vlong);
|
||||
Ctlr *c;
|
||||
SDunit *unit;
|
||||
|
||||
unit = r->unit;
|
||||
c = unit->dev->ctlr;
|
||||
c = u->dev->ctlr;
|
||||
// if(c->feat & Datapi)
|
||||
// return aoeriopkt(r, d);
|
||||
|
||||
cmd = r->cmd;
|
||||
name = unit->name;
|
||||
|
||||
if(r->cmd[0] == 0x35 || r->cmd[0] == 0x91){
|
||||
// qlock(c);
|
||||
// i = flushcache();
|
||||
// qunlock(c);
|
||||
// if(i == 0)
|
||||
// return sdsetsense(r, SDok, 0, 0, 0);
|
||||
return sdsetsense(r, SDcheck, 3, 0xc, 2);
|
||||
}
|
||||
|
||||
if((i = sdfakescsi(r, c->ident, sizeof c->ident)) != SDnostatus){
|
||||
r->status = i;
|
||||
return i;
|
||||
}
|
||||
|
||||
switch(*cmd){
|
||||
case 0x88:
|
||||
case 0x28:
|
||||
rio = devtab[c->c->type]->read;
|
||||
break;
|
||||
case 0x8a:
|
||||
case 0x2a:
|
||||
// return scsibio(u, lun, write, a, count, lba);
|
||||
data = a;
|
||||
if(write)
|
||||
rio = devtab[c->c->type]->write;
|
||||
break;
|
||||
default:
|
||||
print("%s: bad cmd %#.2ux\n", name, cmd[0]);
|
||||
r->status = SDcheck;
|
||||
return SDcheck;
|
||||
}
|
||||
|
||||
if(r->data == nil)
|
||||
return SDok;
|
||||
|
||||
if(r->clen == 16){
|
||||
if(cmd[2] || cmd[3])
|
||||
return sdsetsense(r, SDcheck, 3, 0xc, 2);
|
||||
lba = (uvlong)cmd[4]<<40 | (uvlong)cmd[5]<<32;
|
||||
lba |= cmd[6]<<24 | cmd[7]<<16 | cmd[8]<<8 | cmd[9];
|
||||
count = cmd[10]<<24 | cmd[11]<<16 | cmd[12]<<8 | cmd[13];
|
||||
}else{
|
||||
lba = cmd[2]<<24 | cmd[3]<<16 | cmd[4]<<8 | cmd[5];
|
||||
count = cmd[7]<<8 | cmd[8];
|
||||
}
|
||||
|
||||
count *= Aoesectsz;
|
||||
|
||||
if(r->dlen < count)
|
||||
count = r->dlen & ~0x1ff;
|
||||
else
|
||||
rio = devtab[c->c->type]->read;
|
||||
|
||||
if(waserror()){
|
||||
if(strcmp(up->errstr, Echange) == 0 ||
|
||||
strcmp(up->errstr, Enotup) == 0)
|
||||
unit->sectors = 0;
|
||||
u->sectors = 0;
|
||||
nexterror();
|
||||
}
|
||||
r->rlen = rio(c->c, r->data, count, Aoesectsz * lba);
|
||||
n = rio(c->c, data, Aoesectsz * count, Aoesectsz * lba);
|
||||
poperror();
|
||||
r->status = SDok;
|
||||
return SDok;
|
||||
return n;
|
||||
}
|
||||
|
||||
static char *smarttab[] = {
|
||||
"unset",
|
||||
"error",
|
||||
"threshold exceeded",
|
||||
"normal"
|
||||
};
|
||||
|
||||
static char *
|
||||
pflag(char *s, char *e, uchar f)
|
||||
static int
|
||||
flushcache(Ctlr *)
|
||||
{
|
||||
uchar i, m;
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(i = 0; i < 8; i++){
|
||||
m = 1 << i;
|
||||
if(f & m)
|
||||
s = seprint(s, e, "%s ", flagname[i]);
|
||||
static int
|
||||
aoerio(SDreq *r)
|
||||
{
|
||||
int i, count, rw;
|
||||
uvlong lba;
|
||||
Ctlr *c;
|
||||
SDunit *u;
|
||||
|
||||
u = r->unit;
|
||||
c = u->dev->ctlr;
|
||||
// if(c->feat & Datapi)
|
||||
// return aoeriopkt(r, d);
|
||||
|
||||
if(r->cmd[0] == 0x35 || r->cmd[0] == 0x91){
|
||||
qlock(c);
|
||||
i = flushcache(c);
|
||||
qunlock(c);
|
||||
if(i == 0)
|
||||
return sdsetsense(r, SDok, 0, 0, 0);
|
||||
return sdsetsense(r, SDcheck, 3, 0xc, 2);
|
||||
}
|
||||
return seprint(s, e, "\n");
|
||||
|
||||
if((i = sdfakescsi(r)) != SDnostatus){
|
||||
r->status = i;
|
||||
return i;
|
||||
}
|
||||
if((i = sdfakescsirw(r, &lba, &count, &rw)) != SDnostatus)
|
||||
return i;
|
||||
r->rlen = aoebio(u, r->lun, rw == SDwrite, r->data, count, lba);
|
||||
return r->status = SDok;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -544,14 +472,8 @@ aoerctl(SDunit *u, char *p, int l)
|
|||
p = seprint(p, e, "model\t%s\n", c->model);
|
||||
p = seprint(p, e, "serial\t%s\n", c->serial);
|
||||
p = seprint(p, e, "firm %s\n", c->firmware);
|
||||
if(c->smartrs == 0xff)
|
||||
p = seprint(p, e, "smart\tenable error\n");
|
||||
else if(c->smartrs == 0)
|
||||
p = seprint(p, e, "smart\tdisabled\n");
|
||||
else
|
||||
p = seprint(p, e, "smart\t%s\n", smarttab[c->smart]);
|
||||
p = seprint(p, e, "flag ");
|
||||
p = pflag(p, e, c->feat);
|
||||
p = pflag(p, e, c);
|
||||
p = seprint(p, e, "geometry %llud %d\n", c->sectors, Aoesectsz);
|
||||
return p-op;
|
||||
}
|
||||
|
@ -590,7 +512,7 @@ aoertopctl(SDev *s, char *p, char *e)
|
|||
Ctlr *c;
|
||||
|
||||
c = s->ctlr;
|
||||
return seprint(p, e, "%s aoe %s\n", s->name, c->path);
|
||||
return seprint(p, e, "%s aoe %s\n", s->name, c? c->path: "");
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -617,7 +539,7 @@ SDifc sdaoeifc = {
|
|||
aoerctl,
|
||||
aoewctl,
|
||||
|
||||
scsibio,
|
||||
aoebio,
|
||||
aoeprobew, /* probe */
|
||||
aoeclear, /* clear */
|
||||
aoertopctl,
|
||||
|
|
415
sys/src/9/port/sdloop.c
Normal file
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 unit is becoming ready, rather than not
|
||||
* not ready, wait a little then poke it again. */
|
||||
* not ready, wait a little then poke it again.
|
||||
*/
|
||||
if(r->sense[12] == 0x3A)
|
||||
break;
|
||||
if(r->sense[12] != 0x04 || r->sense[13] != 0x01)
|
||||
|
@ -175,22 +176,91 @@ scsirio(SDreq* r)
|
|||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
cap10(SDreq *r)
|
||||
{
|
||||
r->cmd[0] = 0x25;
|
||||
r->cmd[1] = r->lun<<5;
|
||||
r->clen = 10;
|
||||
r->dlen = 8;
|
||||
}
|
||||
|
||||
static void
|
||||
cap16(SDreq *r)
|
||||
{
|
||||
uint i;
|
||||
|
||||
i = 32;
|
||||
r->cmd[0] = 0x9e;
|
||||
r->cmd[1] = 0x10;
|
||||
r->cmd[10] = i>>24;
|
||||
r->cmd[11] = i>>16;
|
||||
r->cmd[12] = i>>8;
|
||||
r->cmd[13] = i;
|
||||
r->clen = 16;
|
||||
r->dlen = i;
|
||||
}
|
||||
|
||||
static uint
|
||||
belong(uchar *u)
|
||||
{
|
||||
return u[0]<<24 | u[1]<<16 | u[2]<<8 | u[3];
|
||||
}
|
||||
|
||||
static uvlong
|
||||
capreply(SDreq *r, ulong *secsize)
|
||||
{
|
||||
uchar *u;
|
||||
ulong ss;
|
||||
uvlong s;
|
||||
|
||||
*secsize = 0;
|
||||
u = r->data;
|
||||
if(r->clen == 16){
|
||||
s = (uvlong)belong(u)<<32 | belong(u + 4);
|
||||
ss = belong(u + 8);
|
||||
}else{
|
||||
s = belong(u);
|
||||
ss = belong(u + 4);
|
||||
}
|
||||
/*
|
||||
* Some ATAPI CD readers lie about the block size.
|
||||
* Since we don't read audio via this interface
|
||||
* it's okay to always fudge this.
|
||||
*/
|
||||
if(ss == 2352)
|
||||
ss = 2048;
|
||||
/*
|
||||
* Devices with removable media may return 0 sectors
|
||||
* when they have empty media (e.g. sata dvd writers);
|
||||
* if so, keep the count zero.
|
||||
*
|
||||
* Read-capacity returns the LBA of the last sector,
|
||||
* therefore the number of sectors must be incremented.
|
||||
*/
|
||||
if(s != 0)
|
||||
s++;
|
||||
*secsize = ss;
|
||||
return s;
|
||||
}
|
||||
|
||||
int
|
||||
scsionline(SDunit* unit)
|
||||
{
|
||||
SDreq *r;
|
||||
uchar *p;
|
||||
int ok, retries;
|
||||
void (*cap)(SDreq*);
|
||||
|
||||
if((r = malloc(sizeof(SDreq))) == nil)
|
||||
if((r = malloc(sizeof *r)) == nil)
|
||||
return 0;
|
||||
if((p = sdmalloc(8)) == nil){
|
||||
if((p = sdmalloc(32)) == nil){
|
||||
free(r);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ok = 0;
|
||||
|
||||
cap = cap10;
|
||||
r->unit = unit;
|
||||
r->lun = 0; /* ??? */
|
||||
for(retries = 0; retries < 10; retries++){
|
||||
|
@ -201,39 +271,21 @@ scsionline(SDunit* unit)
|
|||
* plain slow getting their act together after a reset.
|
||||
*/
|
||||
r->write = 0;
|
||||
memset(r->cmd, 0, sizeof(r->cmd));
|
||||
r->cmd[0] = 0x25;
|
||||
r->cmd[1] = r->lun<<5;
|
||||
r->clen = 10;
|
||||
r->data = p;
|
||||
r->dlen = 8;
|
||||
r->flags = 0;
|
||||
memset(r->cmd, 0, sizeof r->cmd);
|
||||
cap(r);
|
||||
|
||||
r->status = ~0;
|
||||
switch(scsirio(r)){
|
||||
default:
|
||||
break;
|
||||
case 0:
|
||||
unit->sectors = (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3];
|
||||
unit->secsize = (p[4]<<24)|(p[5]<<16)|(p[6]<<8)|p[7];
|
||||
|
||||
/*
|
||||
* Some ATAPI CD readers lie about the block size.
|
||||
* Since we don't read audio via this interface
|
||||
* it's okay to always fudge this.
|
||||
*/
|
||||
if(unit->secsize == 2352)
|
||||
unit->secsize = 2048;
|
||||
/*
|
||||
* Devices with removable media may return 0 sectors
|
||||
* when they have empty media (e.g. sata dvd writers);
|
||||
* if so, keep the count zero.
|
||||
*
|
||||
* Read-capacity returns the LBA of the last sector,
|
||||
* therefore the number of sectors must be incremented.
|
||||
*/
|
||||
if(unit->sectors != 0)
|
||||
unit->sectors++;
|
||||
unit->sectors = capreply(r, &unit->secsize);
|
||||
if(unit->sectors == 0xffffffff && cap == cap10){
|
||||
cap = cap16;
|
||||
continue;
|
||||
}
|
||||
ok = 1;
|
||||
break;
|
||||
case 1:
|
||||
|
@ -253,56 +305,6 @@ scsionline(SDunit* unit)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
scsiexec(SDunit* unit, int write, uchar* cmd, int clen, void* data, int* dlen)
|
||||
{
|
||||
SDreq *r;
|
||||
int status;
|
||||
|
||||
if((r = malloc(sizeof(SDreq))) == nil)
|
||||
return SDmalloc;
|
||||
r->unit = unit;
|
||||
r->lun = cmd[1]>>5; /* ??? */
|
||||
r->write = write;
|
||||
memmove(r->cmd, cmd, clen);
|
||||
r->clen = clen;
|
||||
r->data = data;
|
||||
if(dlen)
|
||||
r->dlen = *dlen;
|
||||
r->flags = 0;
|
||||
|
||||
r->status = ~0;
|
||||
|
||||
/*
|
||||
* Call the device-specific I/O routine.
|
||||
* There should be no calls to 'error()' below this
|
||||
* which percolate back up.
|
||||
*/
|
||||
switch(status = unit->dev->ifc->rio(r)){
|
||||
case SDok:
|
||||
if(dlen)
|
||||
*dlen = r->rlen;
|
||||
/*FALLTHROUGH*/
|
||||
case SDcheck:
|
||||
/*FALLTHROUGH*/
|
||||
default:
|
||||
/*
|
||||
* It's more complicated than this. There are conditions
|
||||
* which are 'ok' but for which the returned status code
|
||||
* is not 'SDok'.
|
||||
* Also, not all conditions require a reqsense, might
|
||||
* need to do a reqsense here and make it available to the
|
||||
* caller somehow.
|
||||
*
|
||||
* Mañana.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
sdfree(r);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void
|
||||
scsifmt10(SDreq *r, int write, int lun, ulong nb, uvlong bno)
|
||||
{
|
||||
|
@ -367,7 +369,7 @@ scsibio(SDunit* unit, int lun, int write, void* data, long nb, uvlong bno)
|
|||
r->lun = lun;
|
||||
again:
|
||||
r->write = write;
|
||||
if(bno >= (1ULL<<32))
|
||||
if(bno > 0xffffffff)
|
||||
scsifmt16(r, write, lun, nb, bno);
|
||||
else
|
||||
scsifmt10(r, write, lun, nb, bno);
|
||||
|
@ -381,8 +383,19 @@ again:
|
|||
rlen = -1;
|
||||
break;
|
||||
case 0:
|
||||
rlen = r->rlen;
|
||||
break;
|
||||
/*
|
||||
* scsi allows commands to return successfully
|
||||
* but return sense data, indicating that the
|
||||
* operation didn't proceed as expected.
|
||||
* (confusing, no). this allows the raw commands
|
||||
* to successfully return errors. but any sense
|
||||
* data bio sees must be an error. bomb out.
|
||||
*/
|
||||
if(r->status == SDok && r->rlen > 0
|
||||
&& ((r->flags & SDvalidsense) == 0 || r->sense[2] == 0)){
|
||||
rlen = r->rlen;
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
rlen = -1;
|
||||
if(!(r->flags & SDvalidsense))
|
||||
|
@ -415,6 +428,10 @@ again:
|
|||
goto again;
|
||||
break;
|
||||
}
|
||||
snprint(up->genbuf, sizeof up->genbuf, "%s %.2ux%.2ux%.2ux %lld",
|
||||
Eio, r->sense[2], r->sense[12], r->sense[13], bno);
|
||||
free(r);
|
||||
error(up->genbuf);
|
||||
break;
|
||||
}
|
||||
free(r);
|
||||
|
|
545
sys/src/libfis/fis.c
Normal file
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