/* * © 2005-8 coraid * aoe storage initiator */ #include "u.h"#include "lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "ureg.h"#include "error.h"#include "netif.h"#include "etherif.h"#include "ip/ip.h"#include "aoe.h" #define WAKEUP(x) wakeup(&((x)->rend))#define SLEEP(a,b,c) sleep(&(a->rend), b, c) //#pragma varargck argpos eventlog 1 #define dprint(...) if(debug) eventlog(__VA_ARGS__); else USED(debug);#define uprint(...) snprint(up->genbuf, sizeof up->genbuf, __VA_ARGS__); enum { Maxunits = 0xff, Maxframes = 128, Maxmtu = 100000, Ndevlink = 6, Nea = 6, Nnetlink = 6,}; #define TYPE(q) ((ulong)(q).path & 0xf)#define UNIT(q) (((ulong)(q).path>>4) & 0xff)#define L(q) (((ulong)(q).path>>12) & 0xf)#define QID(u, t) ((u)<<4 | (t))#define Q3(l, u, t) ((l)<<8 | QID(u, t))#define UP(d) ((d)->flag & Dup) #define Ticks msec()#define Ms2tk(t) (((t)*HZ)/1000)#define Tk2ms(t) (((t)*1000)/HZ) enum { Qzero, Qtopdir = 1, Qtopbase, Qtopctl = Qtopbase, Qtoplog, Qtopend, Qunitdir, Qunitbase, Qctl = Qunitbase, Qdata, Qconfig, Qident, Qdevlinkdir, Qdevlinkbase, Qdevlink = Qdevlinkbase, Qdevlinkend, Qtopfiles = Qtopend-Qtopbase, Qdevlinkfiles = Qdevlinkend-Qdevlinkbase, Eventlen = 256, Nevents = 64, Fread = 0, Fwrite, Tfree = -1, Tmgmt, /* round trip bounds, timeouts, in ticks */ Rtmax = Ms2tk(320), Rtmin = Ms2tk(20), Srbtimeout = 45*HZ, Dbcnt = 1024, Crd = 0x20, Crdext = 0x24, Cwr = 0x30, Cwrext = 0x34, Cid = 0xec,}; enum { Read, Write,}; /* * unified set of flags * 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 lostjumbo; int datamtu; Chan *cc; Chan *dc; Chan *mtu; /* open early to prevent bind issues. */ char path[Maxpath]; uchar ea[Eaddrlen];} Netlink; typedef struct { Netlink *nl; int nea; ulong eaidx; uchar eatab[Nea][Eaddrlen]; int datamtu; ulong npkt; ulong resent; uchar flag; ulong rttavg; ulong mintimer;} Devlink; typedef struct Srb Srb;struct Srb { Rendez rend; Srb *next; ulong ticksent; ulong len; vlong sector; short write; short nout; char *error; void *dp; void *data;}; typedef struct { int 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 qlock; Aoedev *next; ulong vers; int ndl; ulong dlidx; Devlink *dl; Devlink dltab[Ndevlink]; ushort fwver; uchar flag; int nopen; int major; int minor; int unit; int lasttag; int nframes; Frame *frames; vlong bsize; vlong realbsize; uint maxbcnt; uint maxmtu; ulong lostjumbo; ushort nout; ushort maxout; ulong lastwadj; Srb *head; Srb *tail; Srb *inprocess; char serial[20+1]; char firmware[8+1]; char model[40+1]; int nconfig; uchar config[1024]; uchar ident[512];}; //#pragma varargck type "æ" Aoedev* static struct { Lock lk; QLock qlock; Rendez rend; char buf[Eventlen*Nevents]; char *rp; char *wp;} events; static struct { RWlock rwlock; int nd; Aoedev *d;} devs; static struct { Lock lk; int reader[Nnetlink]; /* reader is running. */ Rendez rendez[Nnetlink]; /* confirm exit. */ Netlink nl[Nnetlink];} netlinks; extern Dev aoedevtab;static Ref units;static Ref drivevers;static int debug;static int autodiscover = 1;static int rediscover; char Enotup[] = "aoe device is down"; char Echange[] = "media or partition has changed"; static Srb*srballoc(ulong sz){ Srb *srb; srb = malloc(sizeof *srb+sz); srb->dp = srb->data = srb+1; srb->ticksent = Ticks; return srb;} static Srb*srbkalloc(void *db, ulong dummy){ Srb *srb; srb = malloc(sizeof *srb); srb->dp = srb->data = db; srb->ticksent = Ticks; return srb;} #define srbfree(srb) free(srb) 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 char*unitname(Aoedev *d){ uprint("%d.%d", d->major, d->minor); return up->genbuf;} static longeventlogread(void *a, long n){ int len; char *p, *buf; buf = smalloc(Eventlen); QLOCK(&events); LOCK(&events); p = events.rp; len = *p; if(len == 0){ n = 0; UNLOCK(&events); } else { if(n > len) n = len; /* can't move directly into pageable space with events lock held */ memmove(buf, p+1, n); *p = 0; events.rp = p += Eventlen; if(p >= events.buf + sizeof events.buf) events.rp = events.buf; UNLOCK(&events); /* the concern here is page faults in memmove below */ if(waserror()){ free(buf); QUNLOCK(&events); nexterror(); } memmove(a, buf, n); poperror(); } free(buf); QUNLOCK(&events); return n;} static inteventlog(char *fmt, ...){ int dragrp, n; char *p; va_list arg; LOCK(&events); p = events.wp; dragrp = *p++; va_start(arg, fmt); n = vsnprint(p, Eventlen-1, fmt, arg); *--p = n; p = events.wp += Eventlen; if(p >= events.buf + sizeof events.buf) p = events.wp = events.buf; if(dragrp) events.rp = p; UNLOCK(&events); WAKEUP(&events); return n;} static inteventcount(void){ int n; LOCK(&events); if(*events.rp == 0) n = 0; else if(events.wp < events.rp) n = Nevents - (events.rp - events.wp); else n = events.wp - events.rp; UNLOCK(&events); return n/Eventlen;} 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; do { t = ++d->lasttag << 16; t |= Ticks & 0xffff; } while (t == Tfree || t == Tmgmt); return t;} static voiddowndev(Aoedev *d, char *err){ Frame *f, *e; d->flag &= ~Dup; f = d->frames; e = f + d->nframes; for(; f < e; f->tag = Tfree, f->srb = nil, f++) frameerror(d, f, Enotup); d->inprocess = nil; eventlog("%æ: removed; %s\n", d, err);} static Block*allocfb(Frame *f){ int len; Block *b; len = f->nhdr + f->dlen; if(len < ETHERMINTU) len = ETHERMINTU; b = allocb(len); memmove(b->wp, f->hdr, f->nhdr); if(f->dlen) memmove(b->wp + f->nhdr, f->dp, f->dlen); b->wp += len; return b;} static voidputlba(Aoeata *a, vlong 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) return l; } return 0;} static intpickea(Devlink *l){ if(l == 0) return -1; if(l->nea == 0) return -1; return l->eaidx++ % l->nea;} static inthset(Aoedev *d, Frame *f, Aoehdr *h, int cmd){ int i; Devlink *l; if(f->srb) if((long)(Ticks-f->srb->ticksent) > Srbtimeout){ eventlog("%æ: srb timeout\n", d); frameerror(d, f, Etimedout); return -1; } l = pickdevlink(d); i = pickea(l); if(i == -1){ downdev(d, "resend fails; no netlink/ea");Lines 1–500 of 2575. Load more
/* * © 2005-8 coraid * aoe storage initiator */ #include "u.h" #include "lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "ureg.h" #include "error.h" #include "netif.h" #include "etherif.h" #include "ip/ip.h" #include "aoe.h" #define WAKEUP(x) wakeup(&((x)->rend)) #define SLEEP(a,b,c) sleep(&(a->rend), b, c) //#pragma varargck argpos eventlog 1 #define dprint(...) if(debug) eventlog(__VA_ARGS__); else USED(debug); #define uprint(...) snprint(up->genbuf, sizeof up->genbuf, __VA_ARGS__); enum { Maxunits = 0xff, Maxframes = 128, Maxmtu = 100000, Ndevlink = 6, Nea = 6, Nnetlink = 6, }; #define TYPE(q) ((ulong)(q).path & 0xf) #define UNIT(q) (((ulong)(q).path>>4) & 0xff) #define L(q) (((ulong)(q).path>>12) & 0xf) #define QID(u, t) ((u)<<4 | (t)) #define Q3(l, u, t) ((l)<<8 | QID(u, t)) #define UP(d) ((d)->flag & Dup) #define Ticks msec() #define Ms2tk(t) (((t)*HZ)/1000) #define Tk2ms(t) (((t)*1000)/HZ) enum { Qzero, Qtopdir = 1, Qtopbase, Qtopctl = Qtopbase, Qtoplog, Qtopend, Qunitdir, Qunitbase, Qctl = Qunitbase, Qdata, Qconfig, Qident, Qdevlinkdir, Qdevlinkbase, Qdevlink = Qdevlinkbase, Qdevlinkend, Qtopfiles = Qtopend-Qtopbase, Qdevlinkfiles = Qdevlinkend-Qdevlinkbase, Eventlen = 256, Nevents = 64, Fread = 0, Fwrite, Tfree = -1, Tmgmt, /* round trip bounds, timeouts, in ticks */ Rtmax = Ms2tk(320), Rtmin = Ms2tk(20), Srbtimeout = 45*HZ, Dbcnt = 1024, Crd = 0x20, Crdext = 0x24, Cwr = 0x30, Cwrext = 0x34, Cid = 0xec, }; enum { Read, Write, }; /* * unified set of flags * 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 lostjumbo; int datamtu; Chan *cc; Chan *dc; Chan *mtu; /* open early to prevent bind issues. */ char path[Maxpath]; uchar ea[Eaddrlen]; } Netlink; typedef struct { Netlink *nl; int nea; ulong eaidx; uchar eatab[Nea][Eaddrlen]; int datamtu; ulong npkt; ulong resent; uchar flag; ulong rttavg; ulong mintimer; } Devlink; typedef struct Srb Srb; struct Srb { Rendez rend; Srb *next; ulong ticksent; ulong len; vlong sector; short write; short nout; char *error; void *dp; void *data; }; typedef struct { int 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 qlock; Aoedev *next; ulong vers; int ndl; ulong dlidx; Devlink *dl; Devlink dltab[Ndevlink]; ushort fwver; uchar flag; int nopen; int major; int minor; int unit; int lasttag; int nframes; Frame *frames; vlong bsize; vlong realbsize; uint maxbcnt; uint maxmtu; ulong lostjumbo; ushort nout; ushort maxout; ulong lastwadj; Srb *head; Srb *tail; Srb *inprocess; char serial[20+1]; char firmware[8+1]; char model[40+1]; int nconfig; uchar config[1024]; uchar ident[512]; }; //#pragma varargck type "æ" Aoedev* static struct { Lock lk; QLock qlock; Rendez rend; char buf[Eventlen*Nevents]; char *rp; char *wp; } events; static struct { RWlock rwlock; int nd; Aoedev *d; } devs; static struct { Lock lk; int reader[Nnetlink]; /* reader is running. */ Rendez rendez[Nnetlink]; /* confirm exit. */ Netlink nl[Nnetlink]; } netlinks; extern Dev aoedevtab; static Ref units; static Ref drivevers; static int debug; static int autodiscover = 1; static int rediscover; char Enotup[] = "aoe device is down"; char Echange[] = "media or partition has changed"; static Srb* srballoc(ulong sz) { Srb *srb; srb = malloc(sizeof *srb+sz); srb->dp = srb->data = srb+1; srb->ticksent = Ticks; return srb; } static Srb* srbkalloc(void *db, ulong dummy) { Srb *srb; srb = malloc(sizeof *srb); srb->dp = srb->data = db; srb->ticksent = Ticks; return srb; } #define srbfree(srb) free(srb) 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 char* unitname(Aoedev *d) { uprint("%d.%d", d->major, d->minor); return up->genbuf; } static long eventlogread(void *a, long n) { int len; char *p, *buf; buf = smalloc(Eventlen); QLOCK(&events); LOCK(&events); p = events.rp; len = *p; if(len == 0){ n = 0; UNLOCK(&events); } else { if(n > len) n = len; /* can't move directly into pageable space with events lock held */ memmove(buf, p+1, n); *p = 0; events.rp = p += Eventlen; if(p >= events.buf + sizeof events.buf) events.rp = events.buf; UNLOCK(&events); /* the concern here is page faults in memmove below */ if(waserror()){ free(buf); QUNLOCK(&events); nexterror(); } memmove(a, buf, n); poperror(); } free(buf); QUNLOCK(&events); return n; } static int eventlog(char *fmt, ...) { int dragrp, n; char *p; va_list arg; LOCK(&events); p = events.wp; dragrp = *p++; va_start(arg, fmt); n = vsnprint(p, Eventlen-1, fmt, arg); *--p = n; p = events.wp += Eventlen; if(p >= events.buf + sizeof events.buf) p = events.wp = events.buf; if(dragrp) events.rp = p; UNLOCK(&events); WAKEUP(&events); return n; } static int eventcount(void) { int n; LOCK(&events); if(*events.rp == 0) n = 0; else if(events.wp < events.rp) n = Nevents - (events.rp - events.wp); else n = events.wp - events.rp; UNLOCK(&events); return n/Eventlen; } 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; do { t = ++d->lasttag << 16; t |= Ticks & 0xffff; } while (t == Tfree || t == Tmgmt); return t; } static void downdev(Aoedev *d, char *err) { Frame *f, *e; d->flag &= ~Dup; f = d->frames; e = f + d->nframes; for(; f < e; f->tag = Tfree, f->srb = nil, f++) frameerror(d, f, Enotup); d->inprocess = nil; eventlog("%æ: removed; %s\n", d, err); } static Block* allocfb(Frame *f) { int len; Block *b; len = f->nhdr + f->dlen; if(len < ETHERMINTU) len = ETHERMINTU; b = allocb(len); memmove(b->wp, f->hdr, f->nhdr); if(f->dlen) memmove(b->wp + f->nhdr, f->dp, f->dlen); b->wp += len; return b; } static void putlba(Aoeata *a, vlong 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) return l; } return 0; } static int pickea(Devlink *l) { if(l == 0) return -1; if(l->nea == 0) return -1; return l->eaidx++ % l->nea; } static int hset(Aoedev *d, Frame *f, Aoehdr *h, int cmd) { int i; Devlink *l; if(f->srb) if((long)(Ticks-f->srb->ticksent) > Srbtimeout){ eventlog("%æ: srb timeout\n", d); frameerror(d, f, Etimedout); return -1; } l = pickdevlink(d); i = pickea(l); if(i == -1){ downdev(d, "resend fails; no netlink/ea");