666 lines · 10.0 KB · C
RawDownload
/* * 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.