2627 lines · 44.1 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* *	© 2005-2010 coraid *	ATA-over-Ethernet (AoE) storage initiator */ #include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "ureg.h"#include "../port/error.h"#include "../port/netif.h"#include "etherif.h"#include "../ip/ip.h"#include "../port/aoe.h" #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,	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)/* * would like this to depend on the chan (srb). * not possible in the current structure. */#define Nofail(d, s)	((d)->flag & Dnofail) #define	MS2TK(t)	((t)/MS2HZ) 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,			/* must be power of 2 */ 	Fread		= 0,	Fwrite,	Tfree		= -1,	Tmgmt, 	/*	 * round trip bounds, timeouts, in ticks.	 * timeouts should be long enough that rebooting	 * the coraid (which usually takes under two minutes)	 * doesn't trigger a timeout.	 */	Rtmax		= MS2TK(320),	Rtmin		= MS2TK(20),	Maxreqticks	= 4*60*HZ,		/* was 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,	Dnofail	= 1<<8,}; static char *flagname[] = {	"llba",	"smart",	"power",	"nop",	"atapi",	"atapi16", 	"up",	"jumbo",	"nofail",}; typedef struct {	ushort	flag;	uint	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];	ulong	npkt;	ulong	resent;	ushort	flag; 	ulong	rttavg;	ulong	mintimer;} Devlink; typedef struct Srb Srb;struct Srb {	Rendez;	Srb	*next;	int	shared;	/* Srb shared with kproc (don't free) */	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;	Aoedev	*next; 	ulong	vers; 	int	ndl;	ulong	dlidx;	Devlink	*dl;	Devlink	dltab[Ndevlink]; 	ushort	fwver;	ushort	flag;	int	nopen;	int	major;	int	minor;	int	unit;	int	lasttag;	int	nframes;	Frame	*frames;	vlong	bsize;	vlong	realbsize; 	uint	maxbcnt;	ushort	nout;	ushort	maxout;	ulong	lastwadj;	Srb	*head;	Srb	*tail;	Srb	*inprocess; 	/* magic numbers 'R' us */	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;	QLock;	Rendez;	char	buf[Eventlen*Nevents];	char	*rp;	char	*wp;} events; static struct {	RWlock;	int	nd;	Aoedev	*d;} devs; static struct {	Lock;	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; static Srb*srballoc(ulong sz){	Srb *srb; 	srb = malloc(sizeof *srb+sz);	if(srb == nil)		error(Enomem);	srb->dp = srb->data = srb+1;	srb->ticksent = MACHP(0)->ticks;	srb->shared = 0;	return srb;} static Srb*srbkalloc(void *db, ulong){	Srb *srb; 	srb = malloc(sizeof *srb);	if(srb == nil)		error(Enomem);	srb->dp = srb->data = db;	srb->ticksent = MACHP(0)->ticks;	srb->shared = 0;	return srb;} static voidsrbfree(Srb *srb){	while(srb->shared)		sched();	free(srb);} 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 || !srb)		return;	f->srb = nil;	f->tag = Tfree;		/* don't get fooled by way-slow responses */	srberror(srb, s);	d->nout--;} static char*unitname(Aoedev *d){	uprint("%d.%d", d->major, d->minor);	return up->genbuf;} static inteventlogready(void*){	return *events.rp;} 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		n = (events.wp - events.rp) & (Nevents - 1);	unlock(&events);	return n/Eventlen;} static inttsince(int tag){	int n; 	n = MACHP(0)->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 |= MACHP(0)->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, Eaoedown);	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;}

Lines 1–500 of 2627.