123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738 |
- /*
- * aoe 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"
- #define uprint(...) snprint(up->genbuf, sizeof up->genbuf, __VA_ARGS__);
- enum {
- Nctlr = 4,
- };
- 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 ctlrno;
- 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 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("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)
- {
- int tag[5], i, n;
- Aoeata *a;
- Etherpkt p;
- memset(&p, 0, sizeof p);
- a = (Aoeata*)&p;
- i = 0;
- do {
- 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;
- }
- } 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
- rxany(Etherpkt *p, int t)
- {
- int i, n;
- for(i = 0; i < nelem(aoeether); i++){
- if(aoeether[i] == 0)
- continue;
- while ((n = etherrxpkt(i, p, t)) != 0)
- if(nhgets(p->type) == Aoetype)
- 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)
- {
- int i;
- char *p, c;
- if((p = getconf("aoeif")) == nil)
- 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")) == nil)
- return 0;
- return nprobe = tokenize(p, probef, nelem(probef));
- }
- 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(" shelf=%d.%d\n", a, b);
- return 0;
- }
- Ctlr*
- pnpprobe(SDev *sd)
- {
- int shelf, slot;
- char *p;
- static int i;
- 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 ||
- aoeprobe(shelf, slot, sd) == -1 ||
- identify(sd->ctlr) == -1)
- return 0;
- return sd->ctlr;
- }
- /*
- * we may need to pretend we found something
- */
- SDev*
- aoepnp(void)
- {
- int n, i, id;
- char *p;
- SDev *h, *t, *s;
- p = getconf("aoeif");
- if (p)
- print("aoepnp: aoeif=%s\n", p);
- 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)
- {
- Ctlr *c;
- SDev *s;
- if (u == nil || u->dev == nil)
- return 0;
- s = u->dev;
- c = s->ctlr;
- if(c == nil){
- aoepnp0();
- if((s->ctlr = c = pnpprobe(s)) == nil)
- return 0;
- }
- c->mediachange = 1;
- return 1;
- }
- static int
- aoeonline(SDunit *u)
- {
- int r;
- Ctlr *c;
- if (u == nil || u->dev == nil || u->dev->ctlr == nil)
- return 0;
- c = u->dev->ctlr;
- if(c->mediachange){
- r = 2;
- c->mediachange = 0;
- u->sectors = c->sectors;
- u->secsize = 512;
- } else
- r = 1;
- return r;
- }
- static int
- rio(Ctlr *c, Aoeata *a, int n, int scnt)
- {
- int i, tag, cmd;
- for(i = 0; i < 5; i++){
- tag = hset(c, a, ACata);
- cmd = a->cmdstat;
- ethertxpkt(c->ctlrno, (Etherpkt*)a, n, 0);
- memset(a, 0, sizeof *a);
- again:
- n = etherrxpkt(c->ctlrno, (Etherpkt*)a, 125);
- if(n == 0)
- continue;
- if(nhgets(a->type) != Aoetype || nhgetl(a->tag) != tag ||
- nhgets(a->major) != c->major || a->minor != c->minor)
- goto again;
- if(a->cmdstat & 0xa9){
- print("aoe: ata rio error: %2ux\n", a->cmdstat);
- return 0;
- }
- switch(cmd){
- case Crd:
- case Crdext:
- if(n - sizeof *a < scnt * 512){
- print("aoe: runt expect %d got %d\n",
- scnt*512 + sizeof *a, n);
- return 0;
- }
- return n - sizeof *a;
- case Cwr:
- case Cwrext:
- return scnt * 512;
- default:
- print("unknown cmd %ux\n", cmd);
- break;
- }
- }
- print("aoe: rio timeout\n");
- return 0;
- }
- 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;
- }
- /*
- * you'll need to loop if you want to read more than 2 sectors. for now
- * i'm cheeting and not bothering with a loop.
- */
- static uchar pktbuf[1024 + sizeof(Aoeata)];
- static int
- aoebuild(Ctlr *c, uchar *cmd, char *data, vlong lba, int scnt)
- {
- int n;
- Aoeata *a;
- memset(pktbuf, 0, sizeof pktbuf);
- a = (Aoeata*)pktbuf;
- hset(c, a, ACata);
- putlba(a, lba);
- a->cmdstat = 0x20;
- if(c->flag & Dllba){
- a->aflag |= AAFext;
- a->cmdstat |= 4;
- }else{
- a->lba[3] &= 0xf;
- a->lba[3] |= 0xe0; /* LBA bit+obsolete 0xa0 */
- }
- n = scnt;
- if(n > 2)
- n = 2;
- a->scnt = n;
- switch(*cmd){
- case 0x2a:
- a->aflag |= AAFwrite;
- a->cmdstat |= 10;
- memmove(a+1, data, n*512);
- n = sizeof *a + n*512;
- break;
- case 0x28:
- n = sizeof *a;
- break;
- default:
- print("aoe: bad cmd 0x%.2ux\n", cmd[0]);
- return -1;
- }
- return n;
- }
- static int
- aoerio(SDreq *r)
- {
- int size, nsec, n;
- vlong lba;
- char *data;
- uchar *cmd;
- Aoeata *a;
- Ctlr *c;
- SDunit *unit;
- unit = r->unit;
- c = unit->dev->ctlr;
- if(r->data == nil)
- return SDok;
- cmd = r->cmd;
- lba = cmd[2]<<24 | cmd[3]<<16 | cmd[4]<<8 | cmd[5]; /* sic. */
- nsec = cmd[7]<<8 | cmd[8];
- a = (Aoeata*)pktbuf;
- data = r->data;
- r->rlen = 0;
- for(; nsec > 0; nsec -= n){
- // print("aoebuild(%2x, %p, %lld, %d)\n", *cmd, data, lba, nsec);
- size = aoebuild(c, cmd, data, lba, nsec);
- if(size < 0){
- r->status = SDcheck;
- return SDcheck;
- }
- n = a->scnt;
- r->rlen += rio(c, a, size, n);
- if(*cmd == 0x28)
- memmove(r->data, a + 1, n * 512);
- data += n * 512;
- lba += n;
- }
- r->status = SDok;
- return SDok;
- }
- SDifc sdaoeifc = {
- "aoe",
- aoepnp,
- nil, /* legacy */
- nil, /* id */
- nil, /* enable */
- nil, /* disable */
- aoeverify,
- aoeonline,
- aoerio,
- nil,
- nil,
- scsibio,
- };
|