/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * © 2005-2010 coraid * ATA-over-Ethernet (AoE) storage initiator */ #include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "ureg.h"#include "../port/error.h"#include "../port/netif.h"#include "etherif.h"#include "../ip/ip.h"#include "../port/aoe.h" #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, 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)/* * would like this to depend on the chan (srb). * not possible in the current structure. */#define Nofail(d, s) ((d)->flag & Dnofail) #define MS2TK(t) ((t)/MS2HZ) 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, /* must be power of 2 */ Fread = 0, Fwrite, Tfree = -1, Tmgmt, /* * round trip bounds, timeouts, in ticks. * timeouts should be long enough that rebooting * the coraid (which usually takes under two minutes) * doesn't trigger a timeout. */ Rtmax = MS2TK(320), Rtmin = MS2TK(20), Maxreqticks = 4*60*HZ, /* was 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, Dnofail = 1<<8,}; static char *flagname[] = { "llba", "smart", "power", "nop", "atapi", "atapi16", "up", "jumbo", "nofail",}; typedef struct { ushort flag; uint 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]; ulong npkt; ulong resent; ushort flag; ulong rttavg; ulong mintimer;} Devlink; typedef struct Srb Srb;struct Srb { Rendez; Srb *next; int shared; /* Srb shared with kproc (don't free) */ 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; Aoedev *next; ulong vers; int ndl; ulong dlidx; Devlink *dl; Devlink dltab[Ndevlink]; ushort fwver; ushort flag; int nopen; int major; int minor; int unit; int lasttag; int nframes; Frame *frames; vlong bsize; vlong realbsize; uint maxbcnt; ushort nout; ushort maxout; ulong lastwadj; Srb *head; Srb *tail; Srb *inprocess; /* magic numbers 'R' us */ 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; QLock; Rendez; char buf[Eventlen*Nevents]; char *rp; char *wp;} events; static struct { RWlock; int nd; Aoedev *d;} devs; static struct { Lock; 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; static Srb*srballoc(ulong sz){ Srb *srb; srb = malloc(sizeof *srb+sz); if(srb == nil) error(Enomem); srb->dp = srb->data = srb+1; srb->ticksent = MACHP(0)->ticks; srb->shared = 0; return srb;} static Srb*srbkalloc(void *db, ulong){ Srb *srb; srb = malloc(sizeof *srb); if(srb == nil) error(Enomem); srb->dp = srb->data = db; srb->ticksent = MACHP(0)->ticks; srb->shared = 0; return srb;} static voidsrbfree(Srb *srb){ while(srb->shared) sched(); free(srb);} static voidsrberror(Srb *srb, char *s){ srb->error = s; srb->nout--; if(srb->nout == 0) wakeup(srb);} static voidframeerror(Aoedev *d, Frame *f, char *s){ Srb *srb; srb = f->srb; if(f->tag == Tfree || !srb) return; f->srb = nil; f->tag = Tfree; /* don't get fooled by way-slow responses */ srberror(srb, s); d->nout--;} static char*unitname(Aoedev *d){ uprint("%d.%d", d->major, d->minor); return up->genbuf;} static inteventlogready(void*){ return *events.rp;} 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 n = (events.wp - events.rp) & (Nevents - 1); unlock(&events); return n/Eventlen;} static inttsince(int tag){ int n; n = MACHP(0)->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 |= MACHP(0)->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, Eaoedown); 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;}Lines 1–500 of 2627. Load more
/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * © 2005-2010 coraid * ATA-over-Ethernet (AoE) storage initiator */ #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "ureg.h" #include "../port/error.h" #include "../port/netif.h" #include "etherif.h" #include "../ip/ip.h" #include "../port/aoe.h" #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, 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) /* * would like this to depend on the chan (srb). * not possible in the current structure. */ #define Nofail(d, s) ((d)->flag & Dnofail) #define MS2TK(t) ((t)/MS2HZ) 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, /* must be power of 2 */ Fread = 0, Fwrite, Tfree = -1, Tmgmt, /* * round trip bounds, timeouts, in ticks. * timeouts should be long enough that rebooting * the coraid (which usually takes under two minutes) * doesn't trigger a timeout. */ Rtmax = MS2TK(320), Rtmin = MS2TK(20), Maxreqticks = 4*60*HZ, /* was 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, Dnofail = 1<<8, }; static char *flagname[] = { "llba", "smart", "power", "nop", "atapi", "atapi16", "up", "jumbo", "nofail", }; typedef struct { ushort flag; uint 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]; ulong npkt; ulong resent; ushort flag; ulong rttavg; ulong mintimer; } Devlink; typedef struct Srb Srb; struct Srb { Rendez; Srb *next; int shared; /* Srb shared with kproc (don't free) */ 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; Aoedev *next; ulong vers; int ndl; ulong dlidx; Devlink *dl; Devlink dltab[Ndevlink]; ushort fwver; ushort flag; int nopen; int major; int minor; int unit; int lasttag; int nframes; Frame *frames; vlong bsize; vlong realbsize; uint maxbcnt; ushort nout; ushort maxout; ulong lastwadj; Srb *head; Srb *tail; Srb *inprocess; /* magic numbers 'R' us */ 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; QLock; Rendez; char buf[Eventlen*Nevents]; char *rp; char *wp; } events; static struct { RWlock; int nd; Aoedev *d; } devs; static struct { Lock; 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; static Srb* srballoc(ulong sz) { Srb *srb; srb = malloc(sizeof *srb+sz); if(srb == nil) error(Enomem); srb->dp = srb->data = srb+1; srb->ticksent = MACHP(0)->ticks; srb->shared = 0; return srb; } static Srb* srbkalloc(void *db, ulong) { Srb *srb; srb = malloc(sizeof *srb); if(srb == nil) error(Enomem); srb->dp = srb->data = db; srb->ticksent = MACHP(0)->ticks; srb->shared = 0; return srb; } static void srbfree(Srb *srb) { while(srb->shared) sched(); free(srb); } static void srberror(Srb *srb, char *s) { srb->error = s; srb->nout--; if(srb->nout == 0) wakeup(srb); } static void frameerror(Aoedev *d, Frame *f, char *s) { Srb *srb; srb = f->srb; if(f->tag == Tfree || !srb) return; f->srb = nil; f->tag = Tfree; /* don't get fooled by way-slow responses */ srberror(srb, s); d->nout--; } static char* unitname(Aoedev *d) { uprint("%d.%d", d->major, d->minor); return up->genbuf; } static int eventlogready(void*) { return *events.rp; } 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 n = (events.wp - events.rp) & (Nevents - 1); unlock(&events); return n/Eventlen; } static int tsince(int tag) { int n; n = MACHP(0)->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 |= MACHP(0)->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, Eaoedown); 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; }