diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2014-12-19 02:50:22 +0100 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2014-12-19 02:50:22 +0100 |
commit | 63799396422447f3d19640abc6a3d5374f9977b0 (patch) | |
tree | e65843955c545100ebffb368b3dfd6bd8a054df0 /sys/src/cmd/disk | |
parent | e93cd703a2e7a98d178206c8a066f248aece76e9 (diff) |
add erik quanstros vblade utility
Diffstat (limited to 'sys/src/cmd/disk')
-rw-r--r-- | sys/src/cmd/disk/mkfile | 1 | ||||
-rw-r--r-- | sys/src/cmd/disk/vblade/aoe.h | 74 | ||||
-rw-r--r-- | sys/src/cmd/disk/vblade/mkfile | 12 | ||||
-rw-r--r-- | sys/src/cmd/disk/vblade/vblade.c | 663 |
4 files changed, 750 insertions, 0 deletions
diff --git a/sys/src/cmd/disk/mkfile b/sys/src/cmd/disk/mkfile index c762df038..7acb0fcef 100644 --- a/sys/src/cmd/disk/mkfile +++ b/sys/src/cmd/disk/mkfile @@ -14,6 +14,7 @@ DIRS=\ prep\ smart\ # sacfs\ + vblade\ OFILES= diff --git a/sys/src/cmd/disk/vblade/aoe.h b/sys/src/cmd/disk/vblade/aoe.h new file mode 100644 index 000000000..6981db643 --- /dev/null +++ b/sys/src/cmd/disk/vblade/aoe.h @@ -0,0 +1,74 @@ +enum{ + ACata, + ACconfig, +}; + +enum{ + AQCread, + AQCtest, + AQCprefix, + AQCset, + AQCfset, +}; + +enum{ + AEcmd = 1, + AEarg, + AEdev, + AEcfg, + AEver, +}; + +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, +}; + +#pragma pack on + +typedef struct{ + uchar dst[Eaddrlen]; + uchar src[Eaddrlen]; + uchar type[2]; + uchar verflag; + uchar error; + uchar major[2]; + uchar minor; + uchar cmd; + uchar tag[4]; +}Aoehdr; + +typedef struct{ + Aoehdr; + uchar aflag; + uchar errfeat; + uchar scnt; + uchar cmdstat; + uchar lba[6]; + uchar res[2]; +}Aoeata; + +typedef struct{ + Aoehdr; + uchar bufcnt[2]; + uchar fwver[2]; + uchar scnt; + uchar verccmd; + uchar cslen[2]; +}Aoeqc; diff --git a/sys/src/cmd/disk/vblade/mkfile b/sys/src/cmd/disk/vblade/mkfile new file mode 100644 index 000000000..a03a7d0ef --- /dev/null +++ b/sys/src/cmd/disk/vblade/mkfile @@ -0,0 +1,12 @@ +</$objtype/mkfile + +TARG=vblade + +OFILES=\ + vblade.$O\ + +HFILES=aoe.h + +BIN=/$objtype/bin/disk + +</sys/src/cmd/mkone diff --git a/sys/src/cmd/disk/vblade/vblade.c b/sys/src/cmd/disk/vblade/vblade.c new file mode 100644 index 000000000..7ad4acc1c --- /dev/null +++ b/sys/src/cmd/disk/vblade/vblade.c @@ -0,0 +1,663 @@ +/* + * vblade -- virtual aoe target + * copyright © 2007 erik quanstrom + */ + +#include <u.h> +#include <libc.h> +#include <thread.h> +#include <ip.h> /* irony */ +#include <fis.h> + +enum { + Eaddrlen = 6, /* only defined in kernel */ +}; +#include "aoe.h" + +enum { + Fclone, + Fdata, + Flast, + + Fraw = 1<<0, + + Nether = 8, + Nvblade = 8, + Maxpkt = 10000, + Hdrlba = 128, + Conflen = 1024, +}; + +typedef struct { + int iflag; + int flag; + int shelf; + int slot; + uvlong maxlba; + char *config; +} Conf; + +typedef struct { + char magic[32]; + char size[32]; + char address[16]; + char configlen[6]; + char pad[512-32-32-16-6]; + char config[Conflen]; +} Vbhdr; + +typedef struct { + Vbhdr hdr; + vlong maxlba; + vlong hdrsz; + int shelf; + int slot; + int clen; + int flag; + int fd; +} Vblade; + +static Vblade vblade[Nvblade]; +static int nblade; + +static char *ethertab[Nether] = { + "/net/ether0", +}; +static int etheridx = 1; +static int efdtab[Nether*Flast]; +static char pkttab[Nether][Maxpkt]; +static char bctab[Nether][Maxpkt]; +static int mtutab[Nether]; +static char Magic[] = "aoe vblade\n"; + +static int +getmtu(char *p) +{ + char buf[50]; + int fd, mtu; + + snprint(buf, sizeof buf, "%s/mtu", p); + if((fd = open(buf, OREAD)) == -1) + return 2; + if(read(fd, buf, 36) < 0) + return 2; + close(fd); + buf[36] = 0; + mtu = strtoul(buf+12, 0, 0)-sizeof(Aoehdr); + return mtu>>9; +} + +int +parseshelf(char *s, int *shelf, int *slot) +{ + int a, b; + + a = strtoul(s, &s, 0); + if(*s++ != '.') + return -1; + b = strtoul(s, &s, 0); + if(*s != 0) + return -1; + *shelf = a; + *slot = b; + return 0; +} + +static vlong +getsize(char *s) +{ + static char tab[] = "ptgmk"; + char *p; + vlong v; + + v = strtoull(s, &s, 0); + while((p = strchr(tab, *s++)) && *p) + while(*p++) + v *= 1024; + if(s[-1]) + return -1; + return v; +} + +vlong +sizetolba(vlong size) +{ + if(size < 512 || size & 0x1ff){ + fprint(2, "invalid size %lld\n", size); + exits("size"); + } + return size>>9; +} + +static int +savevblade(int fd, Vblade *vb) +{ + int n, r; + char *p; + + sprint(vb->hdr.size, "%lld", vb->maxlba<<9); + sprint(vb->hdr.address, "%d.%d", vb->shelf, vb->slot); + sprint(vb->hdr.configlen, "%d", vb->clen); + + if(vb->flag & Fraw) + return 0; + p = (char*)vb; + for(n = 0; n < sizeof *vb; n += r) + if((r = pwrite(fd, p+n, sizeof *vb-n, n)) <= 0) + break; + if(n != sizeof *vb) + return -1; + return 0; +} + +static char* +chkvblade(int fd, Vblade *vb) +{ + Vbhdr *h; + + h = &vb->hdr; + if(readn(fd, (char*)h, sizeof *h) != sizeof *h) + return "bad read"; + if(memcmp(h->magic, Magic, sizeof Magic)) + return "bad magic"; + h->size[sizeof h->size-1] = 0; + vb->maxlba = sizetolba(strtoull(h->size, 0, 0)); + if(parseshelf(h->address, &vb->shelf, &vb->slot) == -1) + return "bad shelf"; + h->configlen[sizeof h->configlen-1] = 0; + vb->clen = strtoul(h->configlen, 0, 0); + return 0; +} + +void +checkfile(char *s, Vblade *vb, int iflag) +{ + char *e; + + vb->fd = open(s, ORDWR); + if(vb->fd == -1) + sysfatal("can't open backing store: %r"); + if(iflag == 0 && (e = chkvblade(vb->fd, vb))) + sysfatal("invalid vblade %s", e); +} + +void +recheck(int fd, Vblade *vb) +{ + Dir *d; + vlong v; + + d = dirfstat(fd); + if(d == 0) + sysfatal("can't stat: %r"); + if((vb->flag & Fraw) == 0) + vb->hdrsz = Hdrlba; + v = sizetolba(d->length & ~0x1ff) - vb->hdrsz; + free(d); + if(vb->maxlba > v) + sysfatal("cmdline size too large (%lld sector overhead)", vb->hdrsz); + if(vb->maxlba == 0) + vb->maxlba = v; + + savevblade(fd, vb); +} + +int +aoeopen(char *e, int fds[]) +{ + char buf[128], ctl[13]; + int n; + + snprint(buf, sizeof buf, "%s/clone", e); + if((fds[Fclone] = open(buf, ORDWR)) == -1) + return -1; + memset(ctl, 0, sizeof ctl); + if(read(fds[Fclone], ctl, sizeof ctl - 1) < 0) + return -1; + n = atoi(ctl); + snprint(buf, sizeof buf, "connect %d", Aoetype); + if(write(fds[Fclone], buf, strlen(buf)) != strlen(buf)) + return -1; + snprint(buf, sizeof buf, "%s/%d/data", e, n); + fds[Fdata] = open(buf, ORDWR); + return fds[Fdata]; +} + +void +replyhdr(Aoehdr *h, Vblade *vblade) +{ + uchar ea[Eaddrlen]; + + memmove(ea, h->dst, Eaddrlen); + memmove(h->dst, h->src, Eaddrlen); + memmove(h->src, ea, Eaddrlen); + + hnputs(h->major, vblade->shelf); + h->minor = vblade->slot; + h->verflag |= AFrsp; +} + +static int +serveconfig(Aoeqc *q, Vblade *vb, int mtu) +{ + int cmd, reqlen, len; + char *cfg; + + if(memcmp(q->src, q->dst, Eaddrlen) == 0) + return -1; + + reqlen = nhgets(q->cslen); + len = vb->clen; + cmd = q->verccmd&0xf; + cfg = (char*)(q+1); + + switch(cmd){ + case AQCtest: + if(reqlen != len) + return -1; + case AQCprefix: + if(reqlen > len) + return -1; + if(memcmp(vb->hdr.config, cfg, reqlen) != 0) + return -1; + case AQCread: + break; + case AQCset: + if(len && len != reqlen || memcmp(vb->hdr.config, cfg, reqlen) != 0){ + q->verflag |= AFerr; + q->error = AEcfg; + break; + } + case AQCfset: + if(reqlen > Conflen){ + q->verflag |= AFerr; + q->error = AEarg; + break; + } + memset(vb->hdr.config, 0, sizeof vb->hdr.config); + memmove(vb->hdr.config, cfg, reqlen); + vb->clen = len = reqlen; + savevblade(vb->fd, vb); + break; + default: + q->verflag |= AFerr; + q->error = AEarg; + } + + memmove(cfg, vb->hdr.config, len); + hnputs(q->cslen, len); + hnputs(q->bufcnt, 24); + q->scnt = mtu; + hnputs(q->fwver, 2323); + q->verccmd = Aoever<<4 | cmd; + + return len+sizeof *q; +} + +static ushort ident[256] = { + [47] 0x8000, + [49] 0x0200, + [50] 0x4000, + [83] 0x5400, + [84] 0x4000, + [86] 0x1400, + [87] 0x4000, + [93] 0x400b, +}; + +static void +idmoveto(char *a, int idx, int len, char *s) +{ + char *p; + + p = a+idx*2; + for(; len > 0; len -= 2) { + if(*s == 0) + p[1] = ' '; + else + p[1] = *s++; + if (*s == 0) + p[0] = ' '; + else + p[0] = *s++; + p += 2; + } +} + +static void +lbamoveto(char *p, int idx, int n, vlong lba) +{ + int i; + + p += idx*2; + for(i = 0; i < n; i++) + *p++ = lba>>i*8; +} + +enum { + Crd = 0x20, + Crdext = 0x24, + Cwr = 0x30, + Cwrext = 0x34, + Cid = 0xec, +}; + +static uvlong +getlba(uchar *p) +{ + uvlong v; + + v = p[0]; + v |= p[1]<<8; + v |= p[2]<<16; + v |= p[3]<<24; + v |= (uvlong)p[4]<<32; + v |= (uvlong)p[5]<<40; + return v; +} + +static void +putlba(uchar *p, vlong lba) +{ + p[0] = lba; + p[1] = lba>>8; + p[2] = lba>>16; + p[3] = lba>>24; + p[5] = lba>>32; + p[6] = lba>>40; +} + +static int +serveata(Aoeata *a, Vblade *vb, int mtu) +{ + char *buf; + int rbytes, bytes, len; + vlong lba, off; + + buf = (char*)(a+1); + lba = getlba(a->lba); + len = a->scnt<<9; + off = lba+vb->hdrsz<<9; + + if(a->scnt > mtu || a->scnt == 0){ + a->verflag |= AFerr; + a->cmdstat = ASdrdy|ASerr; + a->error = AEarg; + return 0; + } + + if(a->cmdstat != Cid) + if(lba+a->scnt > vb->maxlba){ + a->errfeat = Eidnf; + a->cmdstat = ASdrdy|ASerr; + return 0; + } + + if(a->cmdstat&0xf0 == 0x20) + lba &= 0xfffffff; + switch(a->cmdstat){ + default: + a->errfeat = Eabrt; + a->cmdstat = ASdrdy|ASerr; + return 0; + case Cid: + memmove(buf, ident, sizeof ident); + idmoveto(buf, 27, 40, "Plan 9 Vblade"); + idmoveto(buf, 10, 20, "serial#"); + idmoveto(buf, 23, 8, "2"); + lbamoveto(buf, 60, 4, vb->maxlba); + lbamoveto(buf, 100, 8, vb->maxlba); + a->cmdstat = ASdrdy; + return 512; + break; + case Crd: + case Crdext: + bytes = pread(vb->fd, buf, len, off); + rbytes = bytes; + break; + case Cwr: + case Cwrext: + bytes = pwrite(vb->fd, buf, len, off); + rbytes = 0; + break; + } + if(bytes != len){ + a->errfeat = Eabrt; + a->cmdstat = ASdf|ASerr; + putlba(a->lba, lba+(len-bytes)>>9); + return 0; + } + + putlba(a->lba, lba+a->scnt); + a->scnt = 0; + a->errfeat = 0; + a->cmdstat = ASdrdy; + + return rbytes; +} + +static int +myea(uchar ea[6], char *p) +{ + char buf[50]; + int fd; + + snprint(buf, sizeof buf, "%s/addr", p); + if((fd = open(buf, OREAD)) == -1) + return -1; + if(read(fd, buf, 12) < 12) + return -1; + close(fd); + return parseether(ea, buf); +} + +static int +bcastpkt(Aoeqc *h, uint shelf, uint slot, int i) +{ + myea(h->dst, ethertab[i]); + memset(h->src, 0xff, Eaddrlen); + hnputs(h->type, Aoetype); + hnputs(h->major, shelf); + h->minor = slot; + h->cmd = ACconfig; + *(u32int*)h->tag = 0; + return Aoehsz + Aoecfgsz; +} + +int +bladereply(Vblade *v, int i, int fd, char *pkt) +{ + int n; + Aoehdr *h; + + h = (Aoehdr*)pkt; + switch(h->cmd){ + case ACata: + n = serveata((Aoeata*)h, v, mtutab[i]); + n += sizeof(Aoeata); + break; + case ACconfig: + n = serveconfig((Aoeqc*)h, v, mtutab[i]); + break; + default: + n = -1; + break; + } + if(n == -1) + return -1; + replyhdr(h, v); + if(n < 60){ + memset(pkt+n, 0, 60-n); + n = 60; + } + if(write(fd, h, n) != n){ + fprint(2, "write to %s failed: %r\n", ethertab[i]); + return -1; + } + return 0; +} + +void +serve(void *v) +{ + int i, j, popcnt, vec, n, s, efd; + char *pkt, *bcpkt; + Aoehdr *h; + +fmtinstall('E', eipfmt); + i = (int)(uintptr)v; + + efd = efdtab[i*Flast+Fdata]; + pkt = pkttab[i]; + bcpkt = bctab[i]; + + n = 60; + h = (Aoehdr*)pkt; + bcastpkt((Aoeqc*)pkt, 0xffff, 0xff, i); + goto start; + + for(;;){ + n = read(efd, pkt, Maxpkt); + start: + if(n < 60 || h->verflag & AFrsp) + continue; + s = nhgets(h->major); + popcnt = 0; + vec = 0; + for(j = 0; j < nblade; j++){ + if((vblade[j].shelf == s || s == 0xffff) + && (vblade[j].slot == h->minor || h->minor == 0xff)){ + popcnt++; + vec |= 1<<j; + } + } + for(j = 0; popcnt>0 && j < nblade; j++){ + if((vec & 1<<j) == 0) + continue; + if(popcnt>0){ + memcpy(bcpkt, pkt, n); + bladereply(vblade + j, i, efd, bcpkt); + }else + bladereply(vblade + j, i, efd, pkt); + popcnt--; + } + } +} + +void +launch(char *tab[], int fdtab[]) +{ + int i; + + for(i = 0; tab[i]; i++){ + if(aoeopen(tab[i], fdtab+Flast*i) < 0) + sysfatal("network open: %r"); + /* + * use proc not threads. otherwise we will block on read/write. + */ + proccreate(serve, (void*)i, 32*1024); + } +} + +void +usage(void) +{ + fprint(2, "vblade [-ir] [-s size] [-a shelf.slot] [-c config] [-e ether] file\n"); + exits("usage"); +} + +void +goblade(Vblade *vblade, char *file, Conf *c) +{ + char *anal; + + if(c->iflag == 1) + memcpy(vblade->hdr.magic, Magic, sizeof Magic); + checkfile(file, vblade, c->iflag); + + vblade->flag = c->flag; + if(c->shelf != -1){ + vblade->shelf = c->shelf; + vblade->slot = c->slot; + } + if(c->maxlba > 0) + vblade->maxlba = c->maxlba; + if(c->config != nil) + memmove(vblade->hdr.config, c->config, vblade->clen = strlen(c->config)); + + recheck(vblade->fd, vblade); + + anal = ""; + if(vblade->maxlba > 1) + anal = "s"; + fprint(2, "lblade %d.%d %lld sector%s\n", vblade->shelf, vblade->slot, vblade->maxlba, anal); +} + +void +threadmain(int argc, char **argv) +{ + int i, lastc, anye; + Conf c; + + anye = 0; + for(;;){ + if(nblade == nelem(vblade)) + sysfatal("too many blades"); + c = (Conf){0, 0, -1, -1, 0, nil}; + lastc = 0; + ARGBEGIN{ + case 'a': + lastc = 'a'; + if(parseshelf(EARGF(usage()), &c.shelf, &c.slot) == -1) + sysfatal("bad vblade address"); + break; + case 'c': + lastc = 'c'; + c.config = EARGF(usage()); + break; + case 'e': + lastc = 'e'; + if(anye++ == 0) + etheridx = 0; + if(etheridx == nelem(ethertab)) + sysfatal("too many interfaces"); + ethertab[etheridx++] = EARGF(usage()); + break; + case 'i': + lastc = 'i'; + c.iflag = 1; + break; + case 'r': + lastc = 'r'; + c.flag |= Fraw; + c.iflag = 1; + break; + case 's': + lastc = 's'; + c.maxlba = sizetolba(getsize(EARGF(usage()))); + break; + default: + lastc = '?'; + usage(); + }ARGEND; + + if(argc == 0 && lastc == 'e') + break; + if(argc == 0) + usage(); + goblade(vblade + nblade++, *argv, &c); + if(argc == 1) + break; + } + + if(nblade == 0) + usage(); + for(i = 0; i < etheridx; i++) + mtutab[i] = getmtu(ethertab[i]); + + launch(ethertab, efdtab); + + for(; sleep(1*1000) != -1;) + ; + threadexitsall("interrupted"); +} |