2575 lines · 42.3 KB · C
RawDownload
/* *	© 2005-8 coraid *	aoe storage initiator */ #include "u.h"#include "lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "ureg.h"#include "error.h"#include "netif.h"#include "etherif.h"#include "ip/ip.h"#include "aoe.h" #define	WAKEUP(x)	wakeup(&((x)->rend))#define SLEEP(a,b,c)	sleep(&(a->rend), b, c) //#pragma	varargck argpos	eventlog	1 #define dprint(...)	if(debug) eventlog(__VA_ARGS__); else USED(debug);#define uprint(...)	snprint(up->genbuf, sizeof up->genbuf, __VA_ARGS__); enum {	Maxunits	= 0xff,	Maxframes	= 128,	Maxmtu		= 100000,	Ndevlink	= 6,	Nea		= 6,	Nnetlink	= 6,}; #define TYPE(q)		((ulong)(q).path & 0xf)#define UNIT(q)		(((ulong)(q).path>>4) & 0xff)#define L(q)		(((ulong)(q).path>>12) & 0xf)#define QID(u, t) 	((u)<<4 | (t))#define Q3(l, u, t)	((l)<<8 | QID(u, t))#define UP(d)		((d)->flag & Dup) #define	Ticks		msec()#define	Ms2tk(t)	(((t)*HZ)/1000)#define	Tk2ms(t)	(((t)*1000)/HZ) enum {	Qzero,	Qtopdir		= 1,	Qtopbase,	Qtopctl		= Qtopbase,	Qtoplog,	Qtopend, 	Qunitdir,	Qunitbase,	Qctl		= Qunitbase,	Qdata,	Qconfig,	Qident, 	Qdevlinkdir,	Qdevlinkbase,	Qdevlink	= Qdevlinkbase,	Qdevlinkend, 	Qtopfiles	= Qtopend-Qtopbase,	Qdevlinkfiles	= Qdevlinkend-Qdevlinkbase, 	Eventlen 	= 256,	Nevents 	= 64, 	Fread		= 0,	Fwrite,	Tfree		= -1,	Tmgmt, 	/* round trip bounds, timeouts, in ticks */	Rtmax		= Ms2tk(320),	Rtmin		= Ms2tk(20),	Srbtimeout	= 45*HZ, 	Dbcnt		= 1024, 	Crd		= 0x20,	Crdext		= 0x24,	Cwr		= 0x30,	Cwrext		= 0x34,	Cid		= 0xec,}; enum {	Read,	Write,}; /* * unified set of flags * 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	lostjumbo;	int	datamtu; 	Chan	*cc;	Chan	*dc;	Chan	*mtu;		/* open early to prevent bind issues. */	char	path[Maxpath];	uchar	ea[Eaddrlen];} Netlink; typedef struct {	Netlink	*nl;	int	nea;	ulong	eaidx;	uchar	eatab[Nea][Eaddrlen];	int	datamtu;	ulong	npkt;	ulong	resent;	uchar	flag; 	ulong	rttavg;	ulong	mintimer;} Devlink; typedef struct Srb Srb;struct Srb {	Rendez	rend;	Srb	*next;	ulong	ticksent;	ulong	len;	vlong	sector;	short	write;	short	nout;	char	*error;	void	*dp;	void	*data;}; typedef struct {	int	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	qlock;	Aoedev	*next; 	ulong	vers; 	int	ndl;	ulong	dlidx;	Devlink	*dl;	Devlink	dltab[Ndevlink]; 	ushort	fwver;	uchar	flag;	int	nopen;	int	major;	int	minor;	int	unit;	int	lasttag;	int	nframes;	Frame	*frames;	vlong	bsize;	vlong	realbsize; 	uint	maxbcnt;	uint	maxmtu;	ulong	lostjumbo;	ushort	nout;	ushort	maxout;	ulong	lastwadj;	Srb	*head;	Srb	*tail;	Srb	*inprocess; 	char	serial[20+1];	char	firmware[8+1];	char	model[40+1];	int	nconfig;	uchar	config[1024];	uchar	ident[512];}; //#pragma	varargck type	"æ"	Aoedev* static struct {	Lock	lk;	QLock	qlock;	Rendez	rend;	char	buf[Eventlen*Nevents];	char	*rp;	char	*wp;} events; static struct {	RWlock	rwlock;	int	nd;	Aoedev	*d;} devs; static struct {	Lock	lk;	int	reader[Nnetlink];	/* reader is running. */	Rendez	rendez[Nnetlink];	/* confirm exit. */	Netlink	nl[Nnetlink];} netlinks; extern	Dev 	aoedevtab;static	Ref 	units;static	Ref	drivevers;static	int	debug;static	int	autodiscover	= 1;static	int	rediscover;	char 	Enotup[] 	= "aoe device is down";	char	Echange[]	= "media or partition has changed"; static Srb*srballoc(ulong sz){	Srb *srb; 	srb = malloc(sizeof *srb+sz);	srb->dp = srb->data = srb+1;	srb->ticksent = Ticks;	return srb;} static Srb*srbkalloc(void *db, ulong dummy){	Srb *srb; 	srb = malloc(sizeof *srb);	srb->dp = srb->data = db;	srb->ticksent = Ticks;	return srb;} #define srbfree(srb) free(srb) static voidsrberror(Srb *srb, char *s){	srb->error = s;	srb->nout--;	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 char*unitname(Aoedev *d){	uprint("%d.%d", d->major, d->minor);	return up->genbuf;} static longeventlogread(void *a, long n){	int len;	char *p, *buf; 	buf = smalloc(Eventlen);	QLOCK(&events);	LOCK(&events);	p = events.rp;	len = *p;	if(len == 0){		n = 0;		UNLOCK(&events);	} else {		if(n > len)			n = len;		/* can't move directly into pageable space with events lock held */		memmove(buf, p+1, n);		*p = 0;		events.rp = p += Eventlen;		if(p >= events.buf + sizeof events.buf)			events.rp = events.buf;		UNLOCK(&events); 		/* the concern here is page faults in memmove below */		if(waserror()){			free(buf);			QUNLOCK(&events);			nexterror();		}		memmove(a, buf, n);		poperror();	}	free(buf);	QUNLOCK(&events);	return n;} static inteventlog(char *fmt, ...){	int dragrp, n;	char *p;	va_list arg; 	LOCK(&events);	p = events.wp;	dragrp = *p++;	va_start(arg, fmt);	n = vsnprint(p, Eventlen-1, fmt, arg);	*--p = n;	p = events.wp += Eventlen;	if(p >= events.buf + sizeof events.buf)		p = events.wp = events.buf;	if(dragrp)		events.rp = p;	UNLOCK(&events);	WAKEUP(&events);	return n;} static inteventcount(void){	int n; 	LOCK(&events);	if(*events.rp == 0)		n = 0;	else if(events.wp < events.rp)		n = Nevents - (events.rp - events.wp);	else		n = events.wp - events.rp;	UNLOCK(&events);	return n/Eventlen;} 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; 	do {		t = ++d->lasttag << 16;		t |= Ticks & 0xffff;	} while (t == Tfree || t == Tmgmt);	return t;} static voiddowndev(Aoedev *d, char *err){	Frame *f, *e; 	d->flag &= ~Dup;	f = d->frames;	e = f + d->nframes;	for(; f < e; f->tag = Tfree, f->srb = nil, f++)		frameerror(d, f, Enotup);	d->inprocess = nil;	eventlog("%æ: removed; %s\n", d, err);} static Block*allocfb(Frame *f){	int len;	Block *b; 	len = f->nhdr + f->dlen;	if(len < ETHERMINTU)		len = ETHERMINTU;	b = allocb(len);	memmove(b->wp, f->hdr, f->nhdr);	if(f->dlen)		memmove(b->wp + f->nhdr, f->dp, f->dlen);	b->wp += len;	return b;} static voidputlba(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;} 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)			return l;	}	return 0;} static intpickea(Devlink *l){	if(l == 0)		return -1;	if(l->nea == 0)		return -1;	return l->eaidx++ % l->nea;} static inthset(Aoedev *d, Frame *f, Aoehdr *h, int cmd){	int i;	Devlink *l; 	if(f->srb)	if((long)(Ticks-f->srb->ticksent) > Srbtimeout){		eventlog("%æ: srb timeout\n", d);		frameerror(d, f, Etimedout);		return -1;	}	l = pickdevlink(d);	i = pickea(l);	if(i == -1){		downdev(d, "resend fails; no netlink/ea");

Lines 1–500 of 2575.