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