1888 lines · 31.1 KB · C
RawDownload
/* * aoe device.  © 2007 coraid */ #include "all.h"#include "../ip/ip.h"#include "io.h"#include "../pc/etherif.h"#include "mem.h"#include "aoe.h" #define	Ms2tk(t)		((t*HZ)/1000)#define	Tk2ms(t)		((t*1000)/HZ)#define	Tfree		XTfree#define UP(d)		((d)->flag&Dup)#define	malloc(x)	ialloc(x, 1); enum{	Maxframes	= 40,	Ndevlink		= 6,	Nea		= 6,	Nnetlink		= 6,}; enum{	Fread		= 0,	Fwrite,	Tfree		= -1,	Tmgmt, 	Ssize		= 512, 	/* round trip bounds, timeouts, in ticks */	Rtmax		= Ms2tk(300*8),	Rtmin		= Ms2tk(300),	Srbtimeout	= 45*HZ, 	Dbcnt		= 1024, 	Crd		= 0x20,	Crdext		= 0x24,	Cwr		= 0x30,	Cwrext		= 0x34,	Cid		= 0xec,}; /*  * a Netlink + Aoedev most both be jumbo capable. * to send jumbograms to that interface. */enum{	/* sync with ahci.h */	Dllba 	= 1<<0,	Dsmart	= 1<<1,	Dpower	= 1<<2,	Dnop	= 1<<3,	Datapi	= 1<<4,	Datapi16= 1<<5, 	/* aoe specific */	Dup	= 1<<6,	Djumbo	= 1<<7,}; static char*flagname[] = {	"llba",	"smart",	"power",	"nop",	"atapi",	"atapi16", 	"up",	"jumbo",}; typedef struct{	uchar	flag;	uchar	lost;	int	datamtu; 	int	index;	Queue	*dc;	uchar	ea[Easize];}Netlink; typedef struct{	Netlink	*nl;	uint	nea;	ulong	eaidx;	uchar	eatab[Nea][Easize];	uchar	lost[Nea];	uchar	eaflag[Nea];uvlong	ticks;uvlong	pticks;	ulong	npkt;	ulong	resent;	uchar	flag; 	ulong	rttavg;	ulong	mintimer;}Devlink; typedef struct Srb Srb;struct Srb{	Rendez;	Msgbuf	*msgbuf;		/* hack: using msgbufs for srbs. */	Srb	*next;	ulong	ticksent;	ulong	len;	vlong	sector;	short	write;	short	nout;	char	*error;	void	*dp;	void	*data;}; typedef struct{	ulong	tag;	ulong	bcnt;	ulong	dlen;	vlong	lba;	ulong	ticksent;	int	nhdr;	uchar	hdr[ETHERMINTU];	void	*dp;	Devlink	*dl;	Netlink	*nl;	int	eaidx;	Srb	*srb;}Frame; typedef struct Aoedev Aoedev;struct Aoedev{	QLock;	Aoedev	*next;	ulong	vers;			// FIXME 	int	ndl;	ulong	dlidx;	Devlink	*dl;	Devlink	dltab[Ndevlink]; 	uchar	flag;	int	major;	int	minor;	int	unit;	int	lasttag;	int	nframes;	Frame	*frames;	uvlong	bsize; 	uint	maxbcnt;	ushort	nout;	ushort	maxout;ushort	devmaxout;	ulong	lastwadj;	Lock	srblock;//	Srb	*head;//	Srb	*tail;//	Srb	*inprocess;	Queue	*work;	Rendez	fframes; 	char	serial[20+1];	char	firmware[8+1];	char	model[40+1];	uchar	ident[512]; 	ulong	nident;	ulong	identtk; 	Filter	rate[2];	uchar	fflag;uvlong frametime;};#pragma	varargck	type	"æ"	Aoedev* static struct{	RWlock;	int	nd;	Aoedev	*d;} devs; static struct{	Lock;	int	reader[Nnetlink];		/* reader is running. */	Netlink	nl[Nnetlink];} netlinks; static int 	units;static int		debug;static int		autodiscover	= 1;static int		rediscover;static int		debugflag;static int		snoopyflag;static int		rttflag;static Queue	*aoeq[Nea]; char 	Enotup[] 	= "aoe device is down";char	Echange[]	= "media or partition has changed";char	Etimedout[]	= "aoe timeout";char	Eio[]		= "i/o error"; static intdprint(int f, char *fmt, ...){	int n;	va_list arg;	char buf[PRINTSIZE]; 	if((cons.flags & f) == 0)		return 0;	va_start(arg, fmt);	n = vseprint(buf, buf+sizeof buf, fmt, arg) - buf;	va_end(arg);	putstrn(buf, n); 	return n;} static Srb*srbkalloc(void *db, ulong){	Msgbuf *b;	Srb *srb; 	b = mballoc(sizeof *srb, 0, Mbaoesrb);	srb = (Srb*)b->data;	memset(srb, 0, sizeof *srb);	srb->msgbuf = b;	srb->dp = srb->data = db;	srb->ticksent = Ticks;	return srb;} static voidsrbfree(Srb *srb){	mbfree(srb->msgbuf);} static voidsrberror(Srb *srb, char *s){	srb->error = s;	srb->nout--;	if(srb->nout == 0)		wakeup(srb);} static voidframeerror(Aoedev *d, Frame *f, char *s){	Srb *srb; 	srb = f->srb;	if(f->tag == Tfree)		return;	f->srb = nil;	f->tag = Tfree;		/* don't get fooled by way-slow responses */	if(!srb)		return;	srberror(srb, s);	d->nout--;} static inttsince(int tag){	int n; 	n = Ticks&0xffff;	n -= tag&0xffff;	if(n < 0)		n += 1<<16;	return n;} static intnewtag(Aoedev *d){	int t;loop:	t = ++d->lasttag<<16;	t |= Ticks&0xffff;	switch(t) {	case Tfree:	case Tmgmt:		goto loop;	default:		return t;	}} static voidfailio(Aoedev *d, char *err){	Frame *f, *e; 	f = d->frames;	e = f + d->nframes;	for(; f < e; f->tag = Tfree, f->srb = nil, f++)		frameerror(d, f, err);} static voiddowndev(Aoedev *d, char *err){	d->flag &= ~Dup;	failio(d, Enotup);	print("%æ: removed; %s\n", d, err);} static Msgbuf*allocfb(Frame *f){	int len;	Msgbuf *m; 	len = f->nhdr+f->dlen;	if(len < ETHERMINTU)		len = ETHERMINTU;	m = mballoc(len, 0, Mbaoe);	memmove(m->data, f->hdr, f->nhdr);	if(f->dlen)		memmove(m->data+f->nhdr, f->dp, f->dlen);	m->count = len;	return m;} static voidputlba(Aoeata *a, uvlong 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;} static Devlink*pickdevlink(Aoedev *d){	ulong i, n;	Devlink *l; 	for(i = 0; i < d->ndl; i++){		n = d->dlidx++%d->ndl;		l = d->dl+n;		if(l && (l->flag&Dup) && (l->nl->flag&Dup))			return l;	}	return 0;} Lock ealock; static intpickea(Devlink *l){	ulong e, t, m; 	if(l == 0)		return -1;	lock(&ealock);	t = l->eaidx;	for(e = t+l->nea; t <= e; ){		m = t++%l->nea;		if(l->eaflag[m]&Dup){			l->eaidx = t;			unlock(&ealock);			return m;		}	}	unlock(&ealock);	return -1;} static inthset(Aoedev *d, Frame *f, Aoehdr *h, int cmd){	int i;	Devlink *l; 	if(f->srb)	if(Ticks-f->srb->ticksent > Srbtimeout){		print("%æ: %lld srb timeout\n", d, f->lba);		if(cmd != ACata || f->srb == 0)			frameerror(d, f, Etimedout);		else			f->srb->ticksent = Ticks;		return -1;	}	l = pickdevlink(d);	i = pickea(l);	if(i == -1){		if(cmd != ACata || f->srb == 0)			frameerror(d, f, Enotup);		return -1;	}	memmove(h->dst, l->eatab[i], Easize);	memmove(h->src, l->nl->ea, Easize);	hnputs(h->type, Aoetype);	h->verflag = Aoever<<4;	h->error = 0;	hnputs(h->major, d->major);	h->minor = d->minor;	h->cmd = cmd; 	hnputl(h->tag, f->tag = newtag(d));	f->dl = l;	f->nl = l->nl;	f->eaidx = i;	f->ticksent = Ticks; 	return f->tag;} uvlonggetlba(uchar *u){	uvlong l; 	l = u[0];	l |= u[1]<<8;	l |= u[2]<<16;	l |= u[3]<<24;	l |= (uvlong)u[4]<<32;	l |= (uvlong)u[5]<<40;	return l;} voidsnoopy(int idx, int dir, Enpkt *p, int n){	Aoeata *a;	Aoeqc *q; 	if((cons.flags & snoopyflag) == 0)		return;	a = (Aoeata*)p;	print("%d%s  %uld\n", idx, "->\0<-"+3*dir, Ticks);	print("    s %E d %E l %d\n", p->s, p->d, n);	print("    e %d %d.%d %.2ux%.2ux%.2ux%.2ux\n", a->error, nhgets(a->major), a->minor, a->tag[0], a->tag[1], a->tag[2], a->tag[3]);	if(a->cmd == ACata)		print("    af %.2ux ef %.2ux sc %.2ux cs %.2ux lba %ulld\n", a->aflag, a->errfeat, a->scnt, a->cmdstat, getlba(a->lba));	if(a->cmd == ACconfig){		q = (Aoeqc*)a;		print("	bc %ux fw %.2ux%.2ux scnt %d vcmd %ux cslen %d [%.*s]\n", nhgets(q->bufcnt), q->fwver[0], q->fwver[1], q->scnt, q->verccmd, nhgets(q->cslen), nhgets(q->cslen), (char*)(q+1));	}} voidfsend(Frame *f){	Msgbuf *m; 	m = allocfb(f);	snoopy(f->nl->index, 0, (Enpkt*)m->data, m->count);	send(f->nl->dc, m);} static intresend(Aoedev *d, Frame *f){	ulong n;	Aoeata *a; 	a = (Aoeata*)f->hdr;	if(hset(d, f, a, a->cmd) == -1)		return -1;	n = f->bcnt;	if(n > d->maxbcnt){		n = d->maxbcnt;		/* mtu mismatch (jumbo fail?) */		if(f->dlen > n)			f->dlen = n;	}	a->scnt = n/Ssize;	f->dl->resent++;	f->dl->npkt++;	fsend(f);	return 0;} static Aoedev *getdev(int, int, int, int);static voiddiscover(int major, int minor){	Aoehdr *h;	Msgbuf *m;	Netlink *nl, *e; 	if(major != 0xffff && minor != 0xff)		getdev(major, minor, 1, 1);

Lines 1–500 of 1888.