/* * aoe sd bootstrap driver, copyright © 2007-9 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"#include <fis.h> #define uprint(...) snprint(up->genbuf, sizeof up->genbuf, __VA_ARGS__); enum{ Tfree = -1, Tmgmt,}; typedef struct Ctlr Ctlr;struct Ctlr{ Ctlr *next; SDunit *unit; int ctlrno; int major; int minor; uchar ea[Eaddrlen]; ushort lasttag; ulong vers; uchar mediachange; Sfis; uvlong sectors; char serial[20+1]; char firmware[8+1]; char model[40+1]; char ident[0x100];}; static Ctlr *head;static Ctlr *tail; 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){ ushort i; i = *p<<8; return i|p[1];} static ulongnhgetl(uchar *p){ return p[0]<<24 | p[1]<<16 | p[2]<<8 | p[3];} static intnewtag(Ctlr *d){ int t;loop: t = ++d->lasttag<<16; t |= m->ticks&0xffff; switch(t) { case Tfree: case Tmgmt: goto loop; 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 intataidentify(Ctlr *c, ushort *id){ vlong s; s = idfeat(c, id); idmove(c->serial, id+10, 20); idmove(c->firmware, id+23, 8); idmove(c->model, id+27, 40); print("aoe discovers %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("wrong tag\n"); for(j = 0; j <= nout; j++) print("%.8ux != %.8ux\n", out[j], tag); return -1;} /* * ignore the tag for identify. better than ignoring * a response to the wrong identify request */static intidentify(Ctlr *c){ Etherpkt p; Aoeata *a; int tag[5], i, n; memset(&p, 0, sizeof p); a = (Aoeata*)&p; for(i = 0;;){ if(i == 5){ print("aoe: identify timeout\n"); return -1; } tag[i] = idpkt(c, a); ethertxpkt(c->ctlrno, &p, sizeof *a, 0); memset(&p, 0, sizeof p); next: n = etherrxpkt(c->ctlrno, &p, 125); 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("aoe: ata error on identify: %2ux\n", a->cmdstat); return -1; } if(a->scnt != 1) continue; break; } 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){ Ctlr *c; Aoeqc *q; int major, minor; 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 int aoeminor = -1;static int aoemajor = -1; intinterestingaoe(uchar *u, int l){ Aoehdr *h; if(l < 60) return 0; h = (Aoehdr*)u; if(h->minor != aoeminor || nhgets(h->major) != aoemajor) return 0; return 1;} static voiddiscover(int major, int minor){ Aoehdr *h; Etherpkt p; int i; aoemajor = major; aoeminor = minor; 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 intrxany(Etherpkt *p, int t){ int i, n; for(i = 0; i < nelem(aoeether); i++){ if(aoeether[i] == 0) continue; again: if(n = etherrxpkt(i, p, t)){ if(nhgets(p->type) != Aoetype) goto again; return n; } } return 0;} static intaoeprobe(int major, int minor, SDev *s){ Ctlr *ctlr; Etherpkt p; int n, i; for(i = 0;; i += 200){ if(i > 8000) return -1; discover(major, minor); again: n = rxany(&p, 100); if(n > 0 && (ctlr = newctlr(&p))) break; if(n > 0) goto again; } s->ctlr = ctlr; s->ifc = &sdaoeifc; s->nunit = 1; return 0;} static char *probef[32];static int nprobe; intpnpprobeid(char *s){ int id; if(strlen(s) < 2) return 0; id = 'e'; if(s[1] == '!') id = s[0]; return id;} 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;} intaoepnp0(void){ char *p, c; int i; if((p = getconf("aoeif")) == 0) return 0; print("aoeif = %s\n", p); 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")) == 0) return 0; return nprobe = tokenize(p, probef, nelem(probef));} intprobeshelf(char *s, int *shelf, int *slot){ char *r; int a, b; 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(" shelf=%d.%d\n", a, b); return 0;} Ctlr*pnpprobe(SDev *sd){ static int i; char *p; int shelf, slot; if(i >= nprobe) return 0; p = probef[i++]; if(strlen(p) < 2) return 0; if(p[1] == '!'){ sd->idno = p[0]; p += 2; } if(probeshelf(p, &shelf, &slot) == -1) return 0; if(aoeprobe(shelf, slot, sd) == -1) return 0; if(identify(sd->ctlr) == -1) return 0; return sd->ctlr;} /* * we may need to pretend we found something; */ SDev*aoepnp(void){ SDev *h, *t, *s; int n, i, id; print("aoepnp(%s)\n", getconf("aoeif")); if((n = aoepnp0()) == 0) n = 2; t = h = 0; for(i = 0; i < n; i++){ id = 'e'; s = malloc(sizeof *s); if(s == 0) break; s->ctlr = 0; s->idno = id; s->ifc = &sdaoeifc; s->nunit = 1; pnpprobe(s); if(h) t->next = s; else h = s; t = s; } return h;} static intaoeverify(SDunit *u){ SDev *s; Ctlr *c; s = u->dev; c = s->ctlr; if(c == 0){ aoepnp0(); if((c = s->ctlr = pnpprobe(s)) == 0) return 0; } c->mediachange = 1; return 1;} Lines 1–500 of 666. Load more
/* * aoe sd bootstrap driver, copyright © 2007-9 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" #include <fis.h> #define uprint(...) snprint(up->genbuf, sizeof up->genbuf, __VA_ARGS__); enum{ Tfree = -1, Tmgmt, }; typedef struct Ctlr Ctlr; struct Ctlr{ Ctlr *next; SDunit *unit; int ctlrno; int major; int minor; uchar ea[Eaddrlen]; ushort lasttag; ulong vers; uchar mediachange; Sfis; uvlong sectors; char serial[20+1]; char firmware[8+1]; char model[40+1]; char ident[0x100]; }; static Ctlr *head; static Ctlr *tail; 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) { ushort i; i = *p<<8; return i|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; loop: t = ++d->lasttag<<16; t |= m->ticks&0xffff; switch(t) { case Tfree: case Tmgmt: goto loop; 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 int ataidentify(Ctlr *c, ushort *id) { vlong s; s = idfeat(c, id); idmove(c->serial, id+10, 20); idmove(c->firmware, id+23, 8); idmove(c->model, id+27, 40); print("aoe discovers %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("wrong tag\n"); for(j = 0; j <= nout; j++) print("%.8ux != %.8ux\n", out[j], tag); return -1; } /* * ignore the tag for identify. better than ignoring * a response to the wrong identify request */ static int identify(Ctlr *c) { Etherpkt p; Aoeata *a; int tag[5], i, n; memset(&p, 0, sizeof p); a = (Aoeata*)&p; for(i = 0;;){ if(i == 5){ print("aoe: identify timeout\n"); return -1; } tag[i] = idpkt(c, a); ethertxpkt(c->ctlrno, &p, sizeof *a, 0); memset(&p, 0, sizeof p); next: n = etherrxpkt(c->ctlrno, &p, 125); 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("aoe: ata error on identify: %2ux\n", a->cmdstat); return -1; } if(a->scnt != 1) continue; break; } 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) { Ctlr *c; Aoeqc *q; int major, minor; 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 int aoeminor = -1; static int aoemajor = -1; int interestingaoe(uchar *u, int l) { Aoehdr *h; if(l < 60) return 0; h = (Aoehdr*)u; if(h->minor != aoeminor || nhgets(h->major) != aoemajor) return 0; return 1; } static void discover(int major, int minor) { Aoehdr *h; Etherpkt p; int i; aoemajor = major; aoeminor = minor; 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 rxany(Etherpkt *p, int t) { int i, n; for(i = 0; i < nelem(aoeether); i++){ if(aoeether[i] == 0) continue; again: if(n = etherrxpkt(i, p, t)){ if(nhgets(p->type) != Aoetype) goto again; return n; } } return 0; } static int aoeprobe(int major, int minor, SDev *s) { Ctlr *ctlr; Etherpkt p; int n, i; for(i = 0;; i += 200){ if(i > 8000) return -1; discover(major, minor); again: n = rxany(&p, 100); if(n > 0 && (ctlr = newctlr(&p))) break; if(n > 0) goto again; } s->ctlr = ctlr; s->ifc = &sdaoeifc; s->nunit = 1; return 0; } static char *probef[32]; static int nprobe; int pnpprobeid(char *s) { int id; if(strlen(s) < 2) return 0; id = 'e'; if(s[1] == '!') id = s[0]; return id; } 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; } int aoepnp0(void) { char *p, c; int i; if((p = getconf("aoeif")) == 0) return 0; print("aoeif = %s\n", p); 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")) == 0) return 0; return nprobe = tokenize(p, probef, nelem(probef)); } int probeshelf(char *s, int *shelf, int *slot) { char *r; int a, b; 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(" shelf=%d.%d\n", a, b); return 0; } Ctlr* pnpprobe(SDev *sd) { static int i; char *p; int shelf, slot; if(i >= nprobe) return 0; p = probef[i++]; if(strlen(p) < 2) return 0; if(p[1] == '!'){ sd->idno = p[0]; p += 2; } if(probeshelf(p, &shelf, &slot) == -1) return 0; if(aoeprobe(shelf, slot, sd) == -1) return 0; if(identify(sd->ctlr) == -1) return 0; return sd->ctlr; } /* * we may need to pretend we found something; */ SDev* aoepnp(void) { SDev *h, *t, *s; int n, i, id; print("aoepnp(%s)\n", getconf("aoeif")); if((n = aoepnp0()) == 0) n = 2; t = h = 0; for(i = 0; i < n; i++){ id = 'e'; s = malloc(sizeof *s); if(s == 0) break; s->ctlr = 0; s->idno = id; s->ifc = &sdaoeifc; s->nunit = 1; pnpprobe(s); if(h) t->next = s; else h = s; t = s; } return h; } static int aoeverify(SDunit *u) { SDev *s; Ctlr *c; s = u->dev; c = s->ctlr; if(c == 0){ aoepnp0(); if((c = s->ctlr = pnpprobe(s)) == 0) return 0; } c->mediachange = 1; return 1; }