/* * aoe (ata over ethernet) sd bootstrap driver, copyright © 2007 coraid */ #include "u.h"#include "mem.h"#include "lib.h"#include "dat.h"#include "fns.h"#include "io.h"#include "sd.h"#include "aoe.h" enum { NCtlr = 4, Ctlrlet = 'e', /* first sd controller letter */ Probeintvl = 100, /* ms. between probes */ Probemax = 8000, /* max ms. to wait */ Probetries = Probemax / Probeintvl, /* max tries */}; enum { /* sync with ahci.h */ Dllba = 1<<0, Dsmart = 1<<1, Dpower = 1<<2, Dnop = 1<<3, Datapi = 1<<4, Datapi16= 1<<5,}; enum { Tfree = -1, Tmgmt,}; typedef struct Ctlr Ctlr;struct Ctlr{ Ctlr *next; SDunit *unit; int major; int minor; uchar ea[Eaddrlen]; ushort lasttag; ulong vers; uchar mediachange; uchar flag; uchar smart; uchar smartrs; uchar feat; uvlong sectors; char serial[20+1]; char firmware[8+1]; char model[40+1]; char ident[0x100];}; static Ctlr *head;static Ctlr *tail;// static Ctlr aoectlr[NCtlr];// static SDev sdevs[NCtlr];// static int naoectlr; static int aoeether[10]; SDifc sdaoeifc; static voidhnputs(uchar *p, ushort i){ p[0] = i >> 8; p[1] = i;} static voidhnputl(uchar *p, ulong i){ p[0] = i >> 24; p[1] = i >> 16; p[2] = i >> 8; p[3] = i;} static ushortnhgets(uchar *p){ return *p<<8 | p[1];} static ulongnhgetl(uchar *p){ return p[0]<<24 | p[1]<<16 | p[2]<<8 | p[3];} static intnewtag(Ctlr *d){ int t; for(;;){ t = ++d->lasttag << 16; t |= m->ticks & 0xffff; switch(t) { case Tfree: case Tmgmt: break; default: return t; } }} static inthset(Ctlr *d, Aoehdr *h, int cmd){ int tag; memmove(h->dst, d->ea, Eaddrlen); hnputs(h->type, Aoetype); h->verflag = Aoever << 4; hnputs(h->major, d->major); h->minor = d->minor; h->cmd = cmd; hnputl(h->tag, tag = newtag(d)); return tag;} static voididmove(char *p, ushort *a, int n){ int i; char *op, *e; op = p; for(i = 0; i < n / 2; i++){ *p++ = a[i] >> 8; *p++ = a[i]; } *p = 0; while(p > op && *--p == ' ') *p = 0; e = p; p = op; while(*p == ' ') p++; memmove(op, p, n - (e - p));} static ushortgbit16(void *a){ uchar *i; i = a; return i[1]<<8 | i[0];} static ulonggbit32(void *a){ uchar *i; ulong j; i = a; j = i[3] << 24; j |= i[2] << 16; j |= i[1] << 8; j |= i[0]; return j;} static uvlonggbit64(void *a){ uchar *i; i = a; return (uvlong)gbit32(i+4) << 32 | gbit32(a);} static intataidentify(Ctlr *c, ushort *id){ vlong s; int i; i = gbit16(id+83) | gbit16(id+86); if(i & (1 << 10)){ c->feat |= Dllba; s = gbit64(id+100); }else s = gbit32(id+60); idmove(c->serial, id+10, 20); idmove(c->firmware, id+23, 8); idmove(c->model, id+27, 40); print("sdaoe: discovered %d.%d: %s %s\n", c->major, c->minor, c->model, c->serial); c->sectors = s; c->mediachange = 1; return 0;} static voididentifydump(Aoeata *a){ print("%E %E type=%.4ux verflag=%x error=%x %d.%d cmd=%d tag=%.8lux\n", a->dst, a->src, nhgets(a->type), a->verflag, a->error, nhgets(a->major), a->minor, a->cmd, nhgetl(a->tag)); print(" aflag=%x errfeat=%ux scnt=%d cmdstat=%ux, lba=%d? res=%.4ux\n", a->aflag, a->errfeat, a->scnt, a->cmdstat, 0, nhgets(a->res));} static intidpkt(Ctlr *c, Aoeata *a){ memset(a, 0, sizeof *a); a->cmdstat = Cid; a->scnt = 1; a->lba[3] = 0xa0; return hset(c, a, ACata);} static intchktag(int *out, int nout, int tag){ int j; for(j = 0; j <= nout; j++) if(out[j] == tag) return 0; print("sdaoe: chktag: wrong aoe tag: "); for(j = 0; j <= nout; j++) print("%.8ux != %.8ux\n", out[j], tag); return -1;} static intetherrxany(Etherpkt *p, int t){ int i, n; for(i = 0; i < nelem(aoeether); i++) if(aoeether[i]) while ((n = etherrxpkt(i, p, t)) != 0) if(nhgets(p->type) == Aoetype) return n; return 0;} static intethertxany(Etherpkt *p, int n){ int i; for(i = 0; i < nelem(aoeether); i++) if(aoeether[i]) ethertxpkt(i, p, n, 0); return 0;} /* * ignore the tag for identify. better than ignoring * a response to the wrong identify request */static intidentify(Ctlr *c){ int tag[5], i, n; Aoeata *a; Etherpkt p; memset(&p, 0, sizeof p); a = (Aoeata*)&p; i = 0; do { if(i == Probetries){ print("sdaoe: identify: timeout\n"); return -1; } tag[i] = idpkt(c, a); ethertxany(&p, sizeof *a); memset(&p, 0, sizeof p);next: n = etherrxany(&p, Probeintvl); if(n == 0){ i++; continue; } if(nhgets(a->type) != Aoetype) goto next; if(nhgets(a->major) != c->major || a->minor != c->minor){ print("wrong device %d.%d want %d.%d; %d\n", nhgets(a->major), a->minor, c->major, c->minor, n); goto next; } if(chktag(tag, i, nhgetl(a->tag)) == -1) goto next; if(a->cmdstat & 0xa9){ print("sdaoe: ata error on identify: %2ux\n", a->cmdstat); return -1; } } while (a->scnt != 1); c->feat = 0; ataidentify(c, (ushort*)(a+1)); return 0;} static Ctlr*ctlrlookup(int major, int minor){ Ctlr *c; for(c = head; c; c = c->next) if(c->major == major && c->minor == minor) break; return c;} static Ctlr*newctlr(Etherpkt *p){ int major, minor; Aoeqc *q; Ctlr *c; q = (Aoeqc*)p; if(nhgets(q->type) != Aoetype) return 0; major = nhgets(q->major); minor = q->minor; if(major == 0xffff || minor == 0xff) return 0; if(ctlrlookup(major, minor)){ print("duplicate shelf.slot\n"); return 0; } if((c = malloc(sizeof *c)) == 0) return 0; c->major = major; c->minor = minor; memmove(c->ea, q->src, Eaddrlen); if(head != 0) tail->next = c; else head = c; tail = c; return c;} static voiddiscover(int major, int minor){ int i; Aoehdr *h; Etherpkt p; for(i = 0; i < nelem(aoeether); i++){ if(aoeether[i] == 0) continue; memset(&p, 0, ETHERMINTU); h = (Aoehdr*)&p; memset(h->dst, 0xff, sizeof h->dst); hnputs(h->type, Aoetype); h->verflag = Aoever << 4; hnputs(h->major, major); h->minor = minor; h->cmd = ACconfig; ethertxpkt(i, &p, ETHERMINTU, 0); }} static intaoeprobe(int major, int minor, SDev *s){ Ctlr *ctlr; Etherpkt p; int n, i; n = -1; ctlr = nil; for(i = 0; n <= 0 || ctlr == nil; i += Probeintvl){ if(i > Probemax) return -1; discover(major, minor); while ((n = etherrxany(&p, Probeintvl)) > 0 && (ctlr = newctlr(&p)) == nil) ; } s->ctlr = ctlr; s->ifc = &sdaoeifc; s->nunit = 1; return 0;} static char *probef[32];static int nprobe; inttokenize(char *s, char **args, int maxargs){ int nargs; for(nargs = 0; nargs < maxargs; nargs++){ while(*s != '\0' && strchr("\t\n ", *s) != nil) s++; if(*s == '\0') break; args[nargs] = s; while(*s != '\0' && strchr("\t\n ", *s) == nil) s++; if(*s != '\0') *s++ = 0; } return nargs;} static intaoepnp0(void){ int i; char *p, c; if((p = getconf("aoeif")) == nil) return 0; nprobe = tokenize(p, probef, nelem(probef)); for(i = 0; i < nprobe; i++){ if(strncmp(probef[i], "ether", 5) != 0) continue; c = probef[i][5]; if(c > '9' || c < '0') continue; aoeether[c - '0'] = 1; } if((p = getconf("aoedev")) == nil) return 0; return tokenize(p, probef, nelem(probef));} static intprobeshelf(char *s, int *shelf, int *slot){ int a, b; char *r; for(r = s + strlen(s) - 1; r > s; r--) if((*r < '0' || *r > '9') && *r != '.'){ r++; break; } a = strtoul(r, &r, 10); if(*r++ != '.') return -1; b = strtoul(r, 0, 10); *shelf = a; *slot = b;// print("sdaoe: found shelf=%d.%d\n", a, b); return 0;} static Ctlr*pnpprobe(SDev *sd){ int shelf, slot; char *p; static int i; if(i >= nprobe) return nil; p = probef[i++]; if(strlen(p) < 2) return nil; if(p[1] == '!'){ sd->idno = p[0]; p += 2; } if(probeshelf(p, &shelf, &slot) == -1 || aoeprobe(shelf, slot, sd) == -1 || identify(sd->ctlr) == -1) return nil; return sd->ctlr;} /*Lines 1–500 of 760. Load more
/* * aoe (ata over ethernet) sd bootstrap driver, copyright © 2007 coraid */ #include "u.h" #include "mem.h" #include "lib.h" #include "dat.h" #include "fns.h" #include "io.h" #include "sd.h" #include "aoe.h" enum { NCtlr = 4, Ctlrlet = 'e', /* first sd controller letter */ Probeintvl = 100, /* ms. between probes */ Probemax = 8000, /* max ms. to wait */ Probetries = Probemax / Probeintvl, /* max tries */ }; enum { /* sync with ahci.h */ Dllba = 1<<0, Dsmart = 1<<1, Dpower = 1<<2, Dnop = 1<<3, Datapi = 1<<4, Datapi16= 1<<5, }; enum { Tfree = -1, Tmgmt, }; typedef struct Ctlr Ctlr; struct Ctlr{ Ctlr *next; SDunit *unit; int major; int minor; uchar ea[Eaddrlen]; ushort lasttag; ulong vers; uchar mediachange; uchar flag; uchar smart; uchar smartrs; uchar feat; uvlong sectors; char serial[20+1]; char firmware[8+1]; char model[40+1]; char ident[0x100]; }; static Ctlr *head; static Ctlr *tail; // static Ctlr aoectlr[NCtlr]; // static SDev sdevs[NCtlr]; // static int naoectlr; static int aoeether[10]; SDifc sdaoeifc; static void hnputs(uchar *p, ushort i) { p[0] = i >> 8; p[1] = i; } static void hnputl(uchar *p, ulong i) { p[0] = i >> 24; p[1] = i >> 16; p[2] = i >> 8; p[3] = i; } static ushort nhgets(uchar *p) { return *p<<8 | p[1]; } static ulong nhgetl(uchar *p) { return p[0]<<24 | p[1]<<16 | p[2]<<8 | p[3]; } static int newtag(Ctlr *d) { int t; for(;;){ t = ++d->lasttag << 16; t |= m->ticks & 0xffff; switch(t) { case Tfree: case Tmgmt: break; default: return t; } } } static int hset(Ctlr *d, Aoehdr *h, int cmd) { int tag; memmove(h->dst, d->ea, Eaddrlen); hnputs(h->type, Aoetype); h->verflag = Aoever << 4; hnputs(h->major, d->major); h->minor = d->minor; h->cmd = cmd; hnputl(h->tag, tag = newtag(d)); return tag; } static void idmove(char *p, ushort *a, int n) { int i; char *op, *e; op = p; for(i = 0; i < n / 2; i++){ *p++ = a[i] >> 8; *p++ = a[i]; } *p = 0; while(p > op && *--p == ' ') *p = 0; e = p; p = op; while(*p == ' ') p++; memmove(op, p, n - (e - p)); } static ushort gbit16(void *a) { uchar *i; i = a; return i[1]<<8 | i[0]; } static ulong gbit32(void *a) { uchar *i; ulong j; 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); } static int ataidentify(Ctlr *c, ushort *id) { vlong s; int i; i = gbit16(id+83) | gbit16(id+86); if(i & (1 << 10)){ c->feat |= Dllba; s = gbit64(id+100); }else s = gbit32(id+60); idmove(c->serial, id+10, 20); idmove(c->firmware, id+23, 8); idmove(c->model, id+27, 40); print("sdaoe: discovered %d.%d: %s %s\n", c->major, c->minor, c->model, c->serial); c->sectors = s; c->mediachange = 1; return 0; } static void identifydump(Aoeata *a) { print("%E %E type=%.4ux verflag=%x error=%x %d.%d cmd=%d tag=%.8lux\n", a->dst, a->src, nhgets(a->type), a->verflag, a->error, nhgets(a->major), a->minor, a->cmd, nhgetl(a->tag)); print(" aflag=%x errfeat=%ux scnt=%d cmdstat=%ux, lba=%d? res=%.4ux\n", a->aflag, a->errfeat, a->scnt, a->cmdstat, 0, nhgets(a->res)); } static int idpkt(Ctlr *c, Aoeata *a) { memset(a, 0, sizeof *a); a->cmdstat = Cid; a->scnt = 1; a->lba[3] = 0xa0; return hset(c, a, ACata); } static int chktag(int *out, int nout, int tag) { int j; for(j = 0; j <= nout; j++) if(out[j] == tag) return 0; print("sdaoe: chktag: wrong aoe tag: "); for(j = 0; j <= nout; j++) print("%.8ux != %.8ux\n", out[j], tag); return -1; } static int etherrxany(Etherpkt *p, int t) { int i, n; for(i = 0; i < nelem(aoeether); i++) if(aoeether[i]) while ((n = etherrxpkt(i, p, t)) != 0) if(nhgets(p->type) == Aoetype) return n; return 0; } static int ethertxany(Etherpkt *p, int n) { int i; for(i = 0; i < nelem(aoeether); i++) if(aoeether[i]) ethertxpkt(i, p, n, 0); return 0; } /* * ignore the tag for identify. better than ignoring * a response to the wrong identify request */ static int identify(Ctlr *c) { int tag[5], i, n; Aoeata *a; Etherpkt p; memset(&p, 0, sizeof p); a = (Aoeata*)&p; i = 0; do { if(i == Probetries){ print("sdaoe: identify: timeout\n"); return -1; } tag[i] = idpkt(c, a); ethertxany(&p, sizeof *a); memset(&p, 0, sizeof p); next: n = etherrxany(&p, Probeintvl); if(n == 0){ i++; continue; } if(nhgets(a->type) != Aoetype) goto next; if(nhgets(a->major) != c->major || a->minor != c->minor){ print("wrong device %d.%d want %d.%d; %d\n", nhgets(a->major), a->minor, c->major, c->minor, n); goto next; } if(chktag(tag, i, nhgetl(a->tag)) == -1) goto next; if(a->cmdstat & 0xa9){ print("sdaoe: ata error on identify: %2ux\n", a->cmdstat); return -1; } } while (a->scnt != 1); c->feat = 0; ataidentify(c, (ushort*)(a+1)); return 0; } static Ctlr* ctlrlookup(int major, int minor) { Ctlr *c; for(c = head; c; c = c->next) if(c->major == major && c->minor == minor) break; return c; } static Ctlr* newctlr(Etherpkt *p) { int major, minor; Aoeqc *q; Ctlr *c; q = (Aoeqc*)p; if(nhgets(q->type) != Aoetype) return 0; major = nhgets(q->major); minor = q->minor; if(major == 0xffff || minor == 0xff) return 0; if(ctlrlookup(major, minor)){ print("duplicate shelf.slot\n"); return 0; } if((c = malloc(sizeof *c)) == 0) return 0; c->major = major; c->minor = minor; memmove(c->ea, q->src, Eaddrlen); if(head != 0) tail->next = c; else head = c; tail = c; return c; } static void discover(int major, int minor) { int i; Aoehdr *h; Etherpkt p; for(i = 0; i < nelem(aoeether); i++){ if(aoeether[i] == 0) continue; memset(&p, 0, ETHERMINTU); h = (Aoehdr*)&p; memset(h->dst, 0xff, sizeof h->dst); hnputs(h->type, Aoetype); h->verflag = Aoever << 4; hnputs(h->major, major); h->minor = minor; h->cmd = ACconfig; ethertxpkt(i, &p, ETHERMINTU, 0); } } static int aoeprobe(int major, int minor, SDev *s) { Ctlr *ctlr; Etherpkt p; int n, i; n = -1; ctlr = nil; for(i = 0; n <= 0 || ctlr == nil; i += Probeintvl){ if(i > Probemax) return -1; discover(major, minor); while ((n = etherrxany(&p, Probeintvl)) > 0 && (ctlr = newctlr(&p)) == nil) ; } s->ctlr = ctlr; s->ifc = &sdaoeifc; s->nunit = 1; return 0; } static char *probef[32]; static int nprobe; int tokenize(char *s, char **args, int maxargs) { int nargs; for(nargs = 0; nargs < maxargs; nargs++){ while(*s != '\0' && strchr("\t\n ", *s) != nil) s++; if(*s == '\0') break; args[nargs] = s; while(*s != '\0' && strchr("\t\n ", *s) == nil) s++; if(*s != '\0') *s++ = 0; } return nargs; } static int aoepnp0(void) { int i; char *p, c; if((p = getconf("aoeif")) == nil) return 0; nprobe = tokenize(p, probef, nelem(probef)); for(i = 0; i < nprobe; i++){ if(strncmp(probef[i], "ether", 5) != 0) continue; c = probef[i][5]; if(c > '9' || c < '0') continue; aoeether[c - '0'] = 1; } if((p = getconf("aoedev")) == nil) return 0; return tokenize(p, probef, nelem(probef)); } static int probeshelf(char *s, int *shelf, int *slot) { int a, b; char *r; for(r = s + strlen(s) - 1; r > s; r--) if((*r < '0' || *r > '9') && *r != '.'){ r++; break; } a = strtoul(r, &r, 10); if(*r++ != '.') return -1; b = strtoul(r, 0, 10); *shelf = a; *slot = b; // print("sdaoe: found shelf=%d.%d\n", a, b); return 0; } static Ctlr* pnpprobe(SDev *sd) { int shelf, slot; char *p; static int i; if(i >= nprobe) return nil; p = probef[i++]; if(strlen(p) < 2) return nil; if(p[1] == '!'){ sd->idno = p[0]; p += 2; } if(probeshelf(p, &shelf, &slot) == -1 || aoeprobe(shelf, slot, sd) == -1 || identify(sd->ctlr) == -1) return nil; return sd->ctlr; } /*