/* * aoe device. © 2007 coraid */ #include "all.h"#include "../ip/ip.h"#include "io.h"#include "../pc/etherif.h"#include "mem.h"#include "aoe.h" #define Ms2tk(t) ((t*HZ)/1000)#define Tk2ms(t) ((t*1000)/HZ)#define Tfree XTfree#define UP(d) ((d)->flag&Dup)#define malloc(x) ialloc(x, 1); enum{ Maxframes = 40, Ndevlink = 6, Nea = 6, Nnetlink = 6,}; enum{ Fread = 0, Fwrite, Tfree = -1, Tmgmt, Ssize = 512, /* round trip bounds, timeouts, in ticks */ Rtmax = Ms2tk(300*8), Rtmin = Ms2tk(300), Srbtimeout = 45*HZ, Dbcnt = 1024, Crd = 0x20, Crdext = 0x24, Cwr = 0x30, Cwrext = 0x34, Cid = 0xec,}; /* * a Netlink + Aoedev most both be jumbo capable. * to send jumbograms to that interface. */enum{ /* sync with ahci.h */ Dllba = 1<<0, Dsmart = 1<<1, Dpower = 1<<2, Dnop = 1<<3, Datapi = 1<<4, Datapi16= 1<<5, /* aoe specific */ Dup = 1<<6, Djumbo = 1<<7,}; static char*flagname[] = { "llba", "smart", "power", "nop", "atapi", "atapi16", "up", "jumbo",}; typedef struct{ uchar flag; uchar lost; int datamtu; int index; Queue *dc; uchar ea[Easize];}Netlink; typedef struct{ Netlink *nl; uint nea; ulong eaidx; uchar eatab[Nea][Easize]; uchar lost[Nea]; uchar eaflag[Nea];uvlong ticks;uvlong pticks; ulong npkt; ulong resent; uchar flag; ulong rttavg; ulong mintimer;}Devlink; typedef struct Srb Srb;struct Srb{ Rendez; Msgbuf *msgbuf; /* hack: using msgbufs for srbs. */ Srb *next; ulong ticksent; ulong len; vlong sector; short write; short nout; char *error; void *dp; void *data;}; typedef struct{ ulong tag; ulong bcnt; ulong dlen; vlong lba; ulong ticksent; int nhdr; uchar hdr[ETHERMINTU]; void *dp; Devlink *dl; Netlink *nl; int eaidx; Srb *srb;}Frame; typedef struct Aoedev Aoedev;struct Aoedev{ QLock; Aoedev *next; ulong vers; // FIXME int ndl; ulong dlidx; Devlink *dl; Devlink dltab[Ndevlink]; uchar flag; int major; int minor; int unit; int lasttag; int nframes; Frame *frames; uvlong bsize; uint maxbcnt; ushort nout; ushort maxout;ushort devmaxout; ulong lastwadj; Lock srblock;// Srb *head;// Srb *tail;// Srb *inprocess; Queue *work; Rendez fframes; char serial[20+1]; char firmware[8+1]; char model[40+1]; uchar ident[512]; ulong nident; ulong identtk; Filter rate[2]; uchar fflag;uvlong frametime;};#pragma varargck type "æ" Aoedev* static struct{ RWlock; int nd; Aoedev *d;} devs; static struct{ Lock; int reader[Nnetlink]; /* reader is running. */ Netlink nl[Nnetlink];} netlinks; static int units;static int debug;static int autodiscover = 1;static int rediscover;static int debugflag;static int snoopyflag;static int rttflag;static Queue *aoeq[Nea]; char Enotup[] = "aoe device is down";char Echange[] = "media or partition has changed";char Etimedout[] = "aoe timeout";char Eio[] = "i/o error"; static intdprint(int f, char *fmt, ...){ int n; va_list arg; char buf[PRINTSIZE]; if((cons.flags & f) == 0) return 0; va_start(arg, fmt); n = vseprint(buf, buf+sizeof buf, fmt, arg) - buf; va_end(arg); putstrn(buf, n); return n;} static Srb*srbkalloc(void *db, ulong){ Msgbuf *b; Srb *srb; b = mballoc(sizeof *srb, 0, Mbaoesrb); srb = (Srb*)b->data; memset(srb, 0, sizeof *srb); srb->msgbuf = b; srb->dp = srb->data = db; srb->ticksent = Ticks; return srb;} static voidsrbfree(Srb *srb){ mbfree(srb->msgbuf);} static voidsrberror(Srb *srb, char *s){ srb->error = s; srb->nout--; wakeup(srb);} static voidframeerror(Aoedev *d, Frame *f, char *s){ Srb *srb; srb = f->srb; if(f->tag == Tfree) return; f->srb = nil; f->tag = Tfree; /* don't get fooled by way-slow responses */ if(!srb) return; srberror(srb, s); d->nout--;} static inttsince(int tag){ int n; n = Ticks&0xffff; n -= tag&0xffff; if(n < 0) n += 1<<16; return n;} static intnewtag(Aoedev *d){ int t;loop: t = ++d->lasttag<<16; t |= Ticks&0xffff; switch(t) { case Tfree: case Tmgmt: goto loop; default: return t; }} static voidfailio(Aoedev *d, char *err){ Frame *f, *e; f = d->frames; e = f + d->nframes; for(; f < e; f->tag = Tfree, f->srb = nil, f++) frameerror(d, f, err);} static voiddowndev(Aoedev *d, char *err){ d->flag &= ~Dup; failio(d, Enotup); print("%æ: removed; %s\n", d, err);} static Msgbuf*allocfb(Frame *f){ int len; Msgbuf *m; len = f->nhdr+f->dlen; if(len < ETHERMINTU) len = ETHERMINTU; m = mballoc(len, 0, Mbaoe); memmove(m->data, f->hdr, f->nhdr); if(f->dlen) memmove(m->data+f->nhdr, f->dp, f->dlen); m->count = len; return m;} static voidputlba(Aoeata *a, uvlong lba){ uchar *c; c = a->lba; c[0] = lba; c[1] = lba>>8; c[2] = lba>>16; c[3] = lba>>24; c[4] = lba>>32; c[5] = lba>>40;} static Devlink*pickdevlink(Aoedev *d){ ulong i, n; Devlink *l; for(i = 0; i < d->ndl; i++){ n = d->dlidx++%d->ndl; l = d->dl+n; if(l && (l->flag&Dup) && (l->nl->flag&Dup)) return l; } return 0;} Lock ealock; static intpickea(Devlink *l){ ulong e, t, m; if(l == 0) return -1; lock(&ealock); t = l->eaidx; for(e = t+l->nea; t <= e; ){ m = t++%l->nea; if(l->eaflag[m]&Dup){ l->eaidx = t; unlock(&ealock); return m; } } unlock(&ealock); return -1;} static inthset(Aoedev *d, Frame *f, Aoehdr *h, int cmd){ int i; Devlink *l; if(f->srb) if(Ticks-f->srb->ticksent > Srbtimeout){ print("%æ: %lld srb timeout\n", d, f->lba); if(cmd != ACata || f->srb == 0) frameerror(d, f, Etimedout); else f->srb->ticksent = Ticks; return -1; } l = pickdevlink(d); i = pickea(l); if(i == -1){ if(cmd != ACata || f->srb == 0) frameerror(d, f, Enotup); return -1; } memmove(h->dst, l->eatab[i], Easize); memmove(h->src, l->nl->ea, Easize); hnputs(h->type, Aoetype); h->verflag = Aoever<<4; h->error = 0; hnputs(h->major, d->major); h->minor = d->minor; h->cmd = cmd; hnputl(h->tag, f->tag = newtag(d)); f->dl = l; f->nl = l->nl; f->eaidx = i; f->ticksent = Ticks; return f->tag;} uvlonggetlba(uchar *u){ uvlong l; l = u[0]; l |= u[1]<<8; l |= u[2]<<16; l |= u[3]<<24; l |= (uvlong)u[4]<<32; l |= (uvlong)u[5]<<40; return l;} voidsnoopy(int idx, int dir, Enpkt *p, int n){ Aoeata *a; Aoeqc *q; if((cons.flags & snoopyflag) == 0) return; a = (Aoeata*)p; print("%d%s %uld\n", idx, "->\0<-"+3*dir, Ticks); print(" s %E d %E l %d\n", p->s, p->d, n); print(" e %d %d.%d %.2ux%.2ux%.2ux%.2ux\n", a->error, nhgets(a->major), a->minor, a->tag[0], a->tag[1], a->tag[2], a->tag[3]); if(a->cmd == ACata) print(" af %.2ux ef %.2ux sc %.2ux cs %.2ux lba %ulld\n", a->aflag, a->errfeat, a->scnt, a->cmdstat, getlba(a->lba)); if(a->cmd == ACconfig){ q = (Aoeqc*)a; print(" bc %ux fw %.2ux%.2ux scnt %d vcmd %ux cslen %d [%.*s]\n", nhgets(q->bufcnt), q->fwver[0], q->fwver[1], q->scnt, q->verccmd, nhgets(q->cslen), nhgets(q->cslen), (char*)(q+1)); }} voidfsend(Frame *f){ Msgbuf *m; m = allocfb(f); snoopy(f->nl->index, 0, (Enpkt*)m->data, m->count); send(f->nl->dc, m);} static intresend(Aoedev *d, Frame *f){ ulong n; Aoeata *a; a = (Aoeata*)f->hdr; if(hset(d, f, a, a->cmd) == -1) return -1; n = f->bcnt; if(n > d->maxbcnt){ n = d->maxbcnt; /* mtu mismatch (jumbo fail?) */ if(f->dlen > n) f->dlen = n; } a->scnt = n/Ssize; f->dl->resent++; f->dl->npkt++; fsend(f); return 0;} static Aoedev *getdev(int, int, int, int);static voiddiscover(int major, int minor){ Aoehdr *h; Msgbuf *m; Netlink *nl, *e; if(major != 0xffff && minor != 0xff) getdev(major, minor, 1, 1); nl = netlinks.nl;Lines 1–500 of 1890. Load more
/* * aoe device. © 2007 coraid */ #include "all.h" #include "../ip/ip.h" #include "io.h" #include "../pc/etherif.h" #include "mem.h" #include "aoe.h" #define Ms2tk(t) ((t*HZ)/1000) #define Tk2ms(t) ((t*1000)/HZ) #define Tfree XTfree #define UP(d) ((d)->flag&Dup) #define malloc(x) ialloc(x, 1); enum{ Maxframes = 40, Ndevlink = 6, Nea = 6, Nnetlink = 6, }; enum{ Fread = 0, Fwrite, Tfree = -1, Tmgmt, Ssize = 512, /* round trip bounds, timeouts, in ticks */ Rtmax = Ms2tk(300*8), Rtmin = Ms2tk(300), Srbtimeout = 45*HZ, Dbcnt = 1024, Crd = 0x20, Crdext = 0x24, Cwr = 0x30, Cwrext = 0x34, Cid = 0xec, }; /* * a Netlink + Aoedev most both be jumbo capable. * to send jumbograms to that interface. */ enum{ /* sync with ahci.h */ Dllba = 1<<0, Dsmart = 1<<1, Dpower = 1<<2, Dnop = 1<<3, Datapi = 1<<4, Datapi16= 1<<5, /* aoe specific */ Dup = 1<<6, Djumbo = 1<<7, }; static char*flagname[] = { "llba", "smart", "power", "nop", "atapi", "atapi16", "up", "jumbo", }; typedef struct{ uchar flag; uchar lost; int datamtu; int index; Queue *dc; uchar ea[Easize]; }Netlink; typedef struct{ Netlink *nl; uint nea; ulong eaidx; uchar eatab[Nea][Easize]; uchar lost[Nea]; uchar eaflag[Nea]; uvlong ticks; uvlong pticks; ulong npkt; ulong resent; uchar flag; ulong rttavg; ulong mintimer; }Devlink; typedef struct Srb Srb; struct Srb{ Rendez; Msgbuf *msgbuf; /* hack: using msgbufs for srbs. */ Srb *next; ulong ticksent; ulong len; vlong sector; short write; short nout; char *error; void *dp; void *data; }; typedef struct{ ulong tag; ulong bcnt; ulong dlen; vlong lba; ulong ticksent; int nhdr; uchar hdr[ETHERMINTU]; void *dp; Devlink *dl; Netlink *nl; int eaidx; Srb *srb; }Frame; typedef struct Aoedev Aoedev; struct Aoedev{ QLock; Aoedev *next; ulong vers; // FIXME int ndl; ulong dlidx; Devlink *dl; Devlink dltab[Ndevlink]; uchar flag; int major; int minor; int unit; int lasttag; int nframes; Frame *frames; uvlong bsize; uint maxbcnt; ushort nout; ushort maxout; ushort devmaxout; ulong lastwadj; Lock srblock; // Srb *head; // Srb *tail; // Srb *inprocess; Queue *work; Rendez fframes; char serial[20+1]; char firmware[8+1]; char model[40+1]; uchar ident[512]; ulong nident; ulong identtk; Filter rate[2]; uchar fflag; uvlong frametime; }; #pragma varargck type "æ" Aoedev* static struct{ RWlock; int nd; Aoedev *d; } devs; static struct{ Lock; int reader[Nnetlink]; /* reader is running. */ Netlink nl[Nnetlink]; } netlinks; static int units; static int debug; static int autodiscover = 1; static int rediscover; static int debugflag; static int snoopyflag; static int rttflag; static Queue *aoeq[Nea]; char Enotup[] = "aoe device is down"; char Echange[] = "media or partition has changed"; char Etimedout[] = "aoe timeout"; char Eio[] = "i/o error"; static int dprint(int f, char *fmt, ...) { int n; va_list arg; char buf[PRINTSIZE]; if((cons.flags & f) == 0) return 0; va_start(arg, fmt); n = vseprint(buf, buf+sizeof buf, fmt, arg) - buf; va_end(arg); putstrn(buf, n); return n; } static Srb* srbkalloc(void *db, ulong) { Msgbuf *b; Srb *srb; b = mballoc(sizeof *srb, 0, Mbaoesrb); srb = (Srb*)b->data; memset(srb, 0, sizeof *srb); srb->msgbuf = b; srb->dp = srb->data = db; srb->ticksent = Ticks; return srb; } static void srbfree(Srb *srb) { mbfree(srb->msgbuf); } static void srberror(Srb *srb, char *s) { srb->error = s; srb->nout--; wakeup(srb); } static void frameerror(Aoedev *d, Frame *f, char *s) { Srb *srb; srb = f->srb; if(f->tag == Tfree) return; f->srb = nil; f->tag = Tfree; /* don't get fooled by way-slow responses */ if(!srb) return; srberror(srb, s); d->nout--; } static int tsince(int tag) { int n; n = Ticks&0xffff; n -= tag&0xffff; if(n < 0) n += 1<<16; return n; } static int newtag(Aoedev *d) { int t; loop: t = ++d->lasttag<<16; t |= Ticks&0xffff; switch(t) { case Tfree: case Tmgmt: goto loop; default: return t; } } static void failio(Aoedev *d, char *err) { Frame *f, *e; f = d->frames; e = f + d->nframes; for(; f < e; f->tag = Tfree, f->srb = nil, f++) frameerror(d, f, err); } static void downdev(Aoedev *d, char *err) { d->flag &= ~Dup; failio(d, Enotup); print("%æ: removed; %s\n", d, err); } static Msgbuf* allocfb(Frame *f) { int len; Msgbuf *m; len = f->nhdr+f->dlen; if(len < ETHERMINTU) len = ETHERMINTU; m = mballoc(len, 0, Mbaoe); memmove(m->data, f->hdr, f->nhdr); if(f->dlen) memmove(m->data+f->nhdr, f->dp, f->dlen); m->count = len; return m; } static void putlba(Aoeata *a, uvlong lba) { uchar *c; c = a->lba; c[0] = lba; c[1] = lba>>8; c[2] = lba>>16; c[3] = lba>>24; c[4] = lba>>32; c[5] = lba>>40; } static Devlink* pickdevlink(Aoedev *d) { ulong i, n; Devlink *l; for(i = 0; i < d->ndl; i++){ n = d->dlidx++%d->ndl; l = d->dl+n; if(l && (l->flag&Dup) && (l->nl->flag&Dup)) return l; } return 0; } Lock ealock; static int pickea(Devlink *l) { ulong e, t, m; if(l == 0) return -1; lock(&ealock); t = l->eaidx; for(e = t+l->nea; t <= e; ){ m = t++%l->nea; if(l->eaflag[m]&Dup){ l->eaidx = t; unlock(&ealock); return m; } } unlock(&ealock); return -1; } static int hset(Aoedev *d, Frame *f, Aoehdr *h, int cmd) { int i; Devlink *l; if(f->srb) if(Ticks-f->srb->ticksent > Srbtimeout){ print("%æ: %lld srb timeout\n", d, f->lba); if(cmd != ACata || f->srb == 0) frameerror(d, f, Etimedout); else f->srb->ticksent = Ticks; return -1; } l = pickdevlink(d); i = pickea(l); if(i == -1){ if(cmd != ACata || f->srb == 0) frameerror(d, f, Enotup); return -1; } memmove(h->dst, l->eatab[i], Easize); memmove(h->src, l->nl->ea, Easize); hnputs(h->type, Aoetype); h->verflag = Aoever<<4; h->error = 0; hnputs(h->major, d->major); h->minor = d->minor; h->cmd = cmd; hnputl(h->tag, f->tag = newtag(d)); f->dl = l; f->nl = l->nl; f->eaidx = i; f->ticksent = Ticks; return f->tag; } uvlong getlba(uchar *u) { uvlong l; l = u[0]; l |= u[1]<<8; l |= u[2]<<16; l |= u[3]<<24; l |= (uvlong)u[4]<<32; l |= (uvlong)u[5]<<40; return l; } void snoopy(int idx, int dir, Enpkt *p, int n) { Aoeata *a; Aoeqc *q; if((cons.flags & snoopyflag) == 0) return; a = (Aoeata*)p; print("%d%s %uld\n", idx, "->\0<-"+3*dir, Ticks); print(" s %E d %E l %d\n", p->s, p->d, n); print(" e %d %d.%d %.2ux%.2ux%.2ux%.2ux\n", a->error, nhgets(a->major), a->minor, a->tag[0], a->tag[1], a->tag[2], a->tag[3]); if(a->cmd == ACata) print(" af %.2ux ef %.2ux sc %.2ux cs %.2ux lba %ulld\n", a->aflag, a->errfeat, a->scnt, a->cmdstat, getlba(a->lba)); if(a->cmd == ACconfig){ q = (Aoeqc*)a; print(" bc %ux fw %.2ux%.2ux scnt %d vcmd %ux cslen %d [%.*s]\n", nhgets(q->bufcnt), q->fwver[0], q->fwver[1], q->scnt, q->verccmd, nhgets(q->cslen), nhgets(q->cslen), (char*)(q+1)); } } void fsend(Frame *f) { Msgbuf *m; m = allocfb(f); snoopy(f->nl->index, 0, (Enpkt*)m->data, m->count); send(f->nl->dc, m); } static int resend(Aoedev *d, Frame *f) { ulong n; Aoeata *a; a = (Aoeata*)f->hdr; if(hset(d, f, a, a->cmd) == -1) return -1; n = f->bcnt; if(n > d->maxbcnt){ n = d->maxbcnt; /* mtu mismatch (jumbo fail?) */ if(f->dlen > n) f->dlen = n; } a->scnt = n/Ssize; f->dl->resent++; f->dl->npkt++; fsend(f); return 0; } static Aoedev *getdev(int, int, int, int); static void discover(int major, int minor) { Aoehdr *h; Msgbuf *m; Netlink *nl, *e; if(major != 0xffff && minor != 0xff) getdev(major, minor, 1, 1); nl = netlinks.nl;