xref: /plan9-contrib/sys/src/9k/port/devaoe.c (revision 5ae61b61c8015e599b904d2af12b5be472f0d43e)
19ef1f84bSDavid du Colombier /*
29ef1f84bSDavid du Colombier  *	© 2005-2010 coraid
39ef1f84bSDavid du Colombier  *	ATA-over-Ethernet (AoE) storage initiator
49ef1f84bSDavid du Colombier  */
59ef1f84bSDavid du Colombier 
69ef1f84bSDavid du Colombier #include "u.h"
79ef1f84bSDavid du Colombier #include "../port/lib.h"
89ef1f84bSDavid du Colombier #include "mem.h"
99ef1f84bSDavid du Colombier #include "dat.h"
109ef1f84bSDavid du Colombier #include "fns.h"
119ef1f84bSDavid du Colombier #include "../port/error.h"
129ef1f84bSDavid du Colombier 
139ef1f84bSDavid du Colombier #include "../port/netif.h"
149ef1f84bSDavid du Colombier #include "../ip/ip.h"
159ef1f84bSDavid du Colombier 
169ef1f84bSDavid du Colombier #include "etherif.h"
179ef1f84bSDavid du Colombier #include "../port/aoe.h"
189ef1f84bSDavid du Colombier 
199ef1f84bSDavid du Colombier #pragma	varargck argpos	eventlog	1
209ef1f84bSDavid du Colombier 
219ef1f84bSDavid du Colombier #define dprint(...)	if(debug) eventlog(__VA_ARGS__); else USED(debug);
229ef1f84bSDavid du Colombier #define uprint(...)	snprint(up->genbuf, sizeof up->genbuf, __VA_ARGS__);
239ef1f84bSDavid du Colombier 
249ef1f84bSDavid du Colombier enum {
259ef1f84bSDavid du Colombier 	Maxunits	= 0xff,
269ef1f84bSDavid du Colombier 	Maxframes	= 128,
279ef1f84bSDavid du Colombier 	Ndevlink	= 6,
289ef1f84bSDavid du Colombier 	Nea		= 6,
299ef1f84bSDavid du Colombier 	Nnetlink	= 6,
309ef1f84bSDavid du Colombier };
319ef1f84bSDavid du Colombier 
329ef1f84bSDavid du Colombier #define TYPE(q)		((ulong)(q).path & 0xf)
339ef1f84bSDavid du Colombier #define UNIT(q)		(((ulong)(q).path>>4) & 0xff)
349ef1f84bSDavid du Colombier #define L(q)		(((ulong)(q).path>>12) & 0xf)
359ef1f84bSDavid du Colombier #define QID(u, t) 	((u)<<4 | (t))
369ef1f84bSDavid du Colombier #define Q3(l, u, t)	((l)<<8 | QID(u, t))
379ef1f84bSDavid du Colombier #define UP(d)		((d)->flag & Dup)
389ef1f84bSDavid du Colombier /*
399ef1f84bSDavid du Colombier  * would like this to depend on the chan (srb).
409ef1f84bSDavid du Colombier  * not possible in the current structure.
419ef1f84bSDavid du Colombier  */
429ef1f84bSDavid du Colombier #define Nofail(d, s)	((d)->flag & Dnofail)
439ef1f84bSDavid du Colombier 
449ef1f84bSDavid du Colombier #define	MS2TK(t)	((t)/MS2HZ)
459ef1f84bSDavid du Colombier 
469ef1f84bSDavid du Colombier enum {
479ef1f84bSDavid du Colombier 	Qzero,
489ef1f84bSDavid du Colombier 	Qtopdir		= 1,
499ef1f84bSDavid du Colombier 	Qtopbase,
509ef1f84bSDavid du Colombier 	Qtopctl		= Qtopbase,
519ef1f84bSDavid du Colombier 	Qtoplog,
529ef1f84bSDavid du Colombier 	Qtopend,
539ef1f84bSDavid du Colombier 
549ef1f84bSDavid du Colombier 	Qunitdir,
559ef1f84bSDavid du Colombier 	Qunitbase,
569ef1f84bSDavid du Colombier 	Qctl		= Qunitbase,
579ef1f84bSDavid du Colombier 	Qdata,
589ef1f84bSDavid du Colombier 	Qconfig,
599ef1f84bSDavid du Colombier 	Qident,
609ef1f84bSDavid du Colombier 
619ef1f84bSDavid du Colombier 	Qdevlinkdir,
629ef1f84bSDavid du Colombier 	Qdevlinkbase,
639ef1f84bSDavid du Colombier 	Qdevlink	= Qdevlinkbase,
649ef1f84bSDavid du Colombier 	Qdevlinkend,
659ef1f84bSDavid du Colombier 
669ef1f84bSDavid du Colombier 	Qtopfiles	= Qtopend-Qtopbase,
679ef1f84bSDavid du Colombier 	Qdevlinkfiles	= Qdevlinkend-Qdevlinkbase,
689ef1f84bSDavid du Colombier 
699ef1f84bSDavid du Colombier 	Eventlen 	= 256,
709ef1f84bSDavid du Colombier 	Nevents 	= 64,			/* must be power of 2 */
719ef1f84bSDavid du Colombier 
729ef1f84bSDavid du Colombier 	Fread		= 0,
739ef1f84bSDavid du Colombier 	Fwrite,
749ef1f84bSDavid du Colombier 	Tfree		= -1,
759ef1f84bSDavid du Colombier 	Tmgmt,
769ef1f84bSDavid du Colombier 
779ef1f84bSDavid du Colombier 	/*
789ef1f84bSDavid du Colombier 	 * round trip bounds, timeouts, in ticks.
799ef1f84bSDavid du Colombier 	 * timeouts should be long enough that rebooting
809ef1f84bSDavid du Colombier 	 * the coraid (which usually takes under two minutes)
819ef1f84bSDavid du Colombier 	 * doesn't trigger a timeout.
829ef1f84bSDavid du Colombier 	 */
839ef1f84bSDavid du Colombier 	Rtmax		= MS2TK(320),
849ef1f84bSDavid du Colombier 	Rtmin		= MS2TK(20),
859ef1f84bSDavid du Colombier 	Maxreqticks	= 4*60*HZ,		/* was 45*HZ */
869ef1f84bSDavid du Colombier 
879ef1f84bSDavid du Colombier 	Dbcnt		= 1024,
889ef1f84bSDavid du Colombier 
899ef1f84bSDavid du Colombier 	Crd		= 0x20,
909ef1f84bSDavid du Colombier 	Crdext		= 0x24,
919ef1f84bSDavid du Colombier 	Cwr		= 0x30,
929ef1f84bSDavid du Colombier 	Cwrext		= 0x34,
939ef1f84bSDavid du Colombier 	Cid		= 0xec,
949ef1f84bSDavid du Colombier };
959ef1f84bSDavid du Colombier 
969ef1f84bSDavid du Colombier enum {
979ef1f84bSDavid du Colombier 	Read,
989ef1f84bSDavid du Colombier 	Write,
999ef1f84bSDavid du Colombier };
1009ef1f84bSDavid du Colombier 
1019ef1f84bSDavid du Colombier /*
1029ef1f84bSDavid du Colombier  * unified set of flags
1039ef1f84bSDavid du Colombier  * a Netlink + Aoedev most both be jumbo capable
1049ef1f84bSDavid du Colombier  * to send jumbograms to that interface.
1059ef1f84bSDavid du Colombier  */
1069ef1f84bSDavid du Colombier enum {
1079ef1f84bSDavid du Colombier 	/* sync with ahci.h */
1089ef1f84bSDavid du Colombier 	Dllba 	= 1<<0,
1099ef1f84bSDavid du Colombier 	Dsmart	= 1<<1,
1109ef1f84bSDavid du Colombier 	Dpower	= 1<<2,
1119ef1f84bSDavid du Colombier 	Dnop	= 1<<3,
1129ef1f84bSDavid du Colombier 	Datapi	= 1<<4,
1139ef1f84bSDavid du Colombier 	Datapi16= 1<<5,
1149ef1f84bSDavid du Colombier 
1159ef1f84bSDavid du Colombier 	/* aoe specific */
1169ef1f84bSDavid du Colombier 	Dup	= 1<<6,
1179ef1f84bSDavid du Colombier 	Djumbo	= 1<<7,
1189ef1f84bSDavid du Colombier 	Dnofail	= 1<<8,
1199ef1f84bSDavid du Colombier };
1209ef1f84bSDavid du Colombier 
1219ef1f84bSDavid du Colombier static char *flagname[] = {
1229ef1f84bSDavid du Colombier 	"llba",
1239ef1f84bSDavid du Colombier 	"smart",
1249ef1f84bSDavid du Colombier 	"power",
1259ef1f84bSDavid du Colombier 	"nop",
1269ef1f84bSDavid du Colombier 	"atapi",
1279ef1f84bSDavid du Colombier 	"atapi16",
1289ef1f84bSDavid du Colombier 
1299ef1f84bSDavid du Colombier 	"up",
1309ef1f84bSDavid du Colombier 	"jumbo",
1319ef1f84bSDavid du Colombier 	"nofail",
1329ef1f84bSDavid du Colombier };
1339ef1f84bSDavid du Colombier 
1349ef1f84bSDavid du Colombier typedef struct {
1359ef1f84bSDavid du Colombier 	ushort	flag;
1369ef1f84bSDavid du Colombier 	uint	lostjumbo;
1379ef1f84bSDavid du Colombier 	int	datamtu;
1389ef1f84bSDavid du Colombier 
1399ef1f84bSDavid du Colombier 	Chan	*cc;
1409ef1f84bSDavid du Colombier 	Chan	*dc;
1419ef1f84bSDavid du Colombier 	Chan	*mtu;		/* open early to prevent bind issues. */
1429ef1f84bSDavid du Colombier 	char	path[Maxpath];
1439ef1f84bSDavid du Colombier 	uchar	ea[Eaddrlen];
1449ef1f84bSDavid du Colombier } Netlink;
1459ef1f84bSDavid du Colombier 
1469ef1f84bSDavid du Colombier typedef struct {
1479ef1f84bSDavid du Colombier 	Netlink	*nl;
1489ef1f84bSDavid du Colombier 	int	nea;
1499ef1f84bSDavid du Colombier 	ulong	eaidx;
1509ef1f84bSDavid du Colombier 	uchar	eatab[Nea][Eaddrlen];
1519ef1f84bSDavid du Colombier 	ulong	npkt;
1529ef1f84bSDavid du Colombier 	ulong	resent;
1539ef1f84bSDavid du Colombier 	ushort	flag;
1549ef1f84bSDavid du Colombier 
1559ef1f84bSDavid du Colombier 	ulong	rttavg;
1569ef1f84bSDavid du Colombier 	ulong	mintimer;
1579ef1f84bSDavid du Colombier } Devlink;
1589ef1f84bSDavid du Colombier 
1599ef1f84bSDavid du Colombier typedef struct Srb Srb;
1609ef1f84bSDavid du Colombier struct Srb {
1619ef1f84bSDavid du Colombier 	Rendez;
1629ef1f84bSDavid du Colombier 	Srb	*next;
163406c76faSDavid du Colombier 	int	shared;	/* Srb shared with kproc (don't free) */
1649ef1f84bSDavid du Colombier 	ulong	ticksent;
1659ef1f84bSDavid du Colombier 	ulong	len;
1669ef1f84bSDavid du Colombier 	vlong	sector;
1679ef1f84bSDavid du Colombier 	short	write;
1689ef1f84bSDavid du Colombier 	short	nout;
1699ef1f84bSDavid du Colombier 	char	*error;
1709ef1f84bSDavid du Colombier 	void	*dp;
1719ef1f84bSDavid du Colombier 	void	*data;
1729ef1f84bSDavid du Colombier };
1739ef1f84bSDavid du Colombier 
1749ef1f84bSDavid du Colombier typedef struct {
1759ef1f84bSDavid du Colombier 	int	tag;
1769ef1f84bSDavid du Colombier 	ulong	bcnt;
1779ef1f84bSDavid du Colombier 	ulong	dlen;
1789ef1f84bSDavid du Colombier 	vlong	lba;
1799ef1f84bSDavid du Colombier 	ulong	ticksent;
1809ef1f84bSDavid du Colombier 	int	nhdr;
1819ef1f84bSDavid du Colombier 	uchar	hdr[ETHERMINTU];
1829ef1f84bSDavid du Colombier 	void	*dp;
1839ef1f84bSDavid du Colombier 	Devlink	*dl;
1849ef1f84bSDavid du Colombier 	Netlink	*nl;
1859ef1f84bSDavid du Colombier 	int	eaidx;
1869ef1f84bSDavid du Colombier 	Srb	*srb;
1879ef1f84bSDavid du Colombier } Frame;
1889ef1f84bSDavid du Colombier 
1899ef1f84bSDavid du Colombier typedef struct Aoedev Aoedev;
1909ef1f84bSDavid du Colombier struct Aoedev {
1919ef1f84bSDavid du Colombier 	QLock;
1929ef1f84bSDavid du Colombier 	Aoedev	*next;
1939ef1f84bSDavid du Colombier 
1949ef1f84bSDavid du Colombier 	ulong	vers;
1959ef1f84bSDavid du Colombier 
1969ef1f84bSDavid du Colombier 	int	ndl;
1979ef1f84bSDavid du Colombier 	ulong	dlidx;
1989ef1f84bSDavid du Colombier 	Devlink	*dl;
1999ef1f84bSDavid du Colombier 	Devlink	dltab[Ndevlink];
2009ef1f84bSDavid du Colombier 
2019ef1f84bSDavid du Colombier 	ushort	fwver;
2029ef1f84bSDavid du Colombier 	ushort	flag;
2039ef1f84bSDavid du Colombier 	int	nopen;
2049ef1f84bSDavid du Colombier 	int	major;
2059ef1f84bSDavid du Colombier 	int	minor;
2069ef1f84bSDavid du Colombier 	int	unit;
2079ef1f84bSDavid du Colombier 	int	lasttag;
2089ef1f84bSDavid du Colombier 	int	nframes;
2099ef1f84bSDavid du Colombier 	Frame	*frames;
2109ef1f84bSDavid du Colombier 	vlong	bsize;
2119ef1f84bSDavid du Colombier 	vlong	realbsize;
2129ef1f84bSDavid du Colombier 
2139ef1f84bSDavid du Colombier 	uint	maxbcnt;
2149ef1f84bSDavid du Colombier 	ushort	nout;
2159ef1f84bSDavid du Colombier 	ushort	maxout;
2169ef1f84bSDavid du Colombier 	ulong	lastwadj;
2179ef1f84bSDavid du Colombier 	Srb	*head;
2189ef1f84bSDavid du Colombier 	Srb	*tail;
2199ef1f84bSDavid du Colombier 	Srb	*inprocess;
2209ef1f84bSDavid du Colombier 
2219ef1f84bSDavid du Colombier 	/* magic numbers 'R' us */
2229ef1f84bSDavid du Colombier 	char	serial[20+1];
2239ef1f84bSDavid du Colombier 	char	firmware[8+1];
2249ef1f84bSDavid du Colombier 	char	model[40+1];
2259ef1f84bSDavid du Colombier 	int	nconfig;
2269ef1f84bSDavid du Colombier 	uchar	config[1024];
2279ef1f84bSDavid du Colombier 	uchar	ident[512];
2289ef1f84bSDavid du Colombier };
2299ef1f84bSDavid du Colombier 
2309ef1f84bSDavid du Colombier #pragma	varargck type	"æ"	Aoedev*
2319ef1f84bSDavid du Colombier 
2329ef1f84bSDavid du Colombier static struct {
2339ef1f84bSDavid du Colombier 	Lock;
2349ef1f84bSDavid du Colombier 	QLock;
2359ef1f84bSDavid du Colombier 	Rendez;
2369ef1f84bSDavid du Colombier 	char	buf[Eventlen*Nevents];
2379ef1f84bSDavid du Colombier 	char	*rp;
2389ef1f84bSDavid du Colombier 	char	*wp;
2399ef1f84bSDavid du Colombier } events;
2409ef1f84bSDavid du Colombier 
2419ef1f84bSDavid du Colombier static struct {
2429ef1f84bSDavid du Colombier 	RWlock;
2439ef1f84bSDavid du Colombier 	int	nd;
2449ef1f84bSDavid du Colombier 	Aoedev	*d;
2459ef1f84bSDavid du Colombier } devs;
2469ef1f84bSDavid du Colombier 
2479ef1f84bSDavid du Colombier static struct {
2489ef1f84bSDavid du Colombier 	Lock;
2499ef1f84bSDavid du Colombier 	int	reader[Nnetlink];	/* reader is running. */
2509ef1f84bSDavid du Colombier 	Rendez	rendez[Nnetlink];	/* confirm exit. */
2519ef1f84bSDavid du Colombier 	Netlink	nl[Nnetlink];
2529ef1f84bSDavid du Colombier } netlinks;
2539ef1f84bSDavid du Colombier 
2549ef1f84bSDavid du Colombier extern Dev 	aoedevtab;
2559ef1f84bSDavid du Colombier static Ref 	units;
2569ef1f84bSDavid du Colombier static Ref	drivevers;
2579ef1f84bSDavid du Colombier static int	debug;
2589ef1f84bSDavid du Colombier static int	autodiscover	= 1;
2599ef1f84bSDavid du Colombier static int	rediscover;
2609ef1f84bSDavid du Colombier 
2619ef1f84bSDavid du Colombier static Srb*
srballoc(ulong sz)2629ef1f84bSDavid du Colombier srballoc(ulong sz)
2639ef1f84bSDavid du Colombier {
2649ef1f84bSDavid du Colombier 	Srb *srb;
2659ef1f84bSDavid du Colombier 
2669ef1f84bSDavid du Colombier 	srb = malloc(sizeof *srb+sz);
2679ef1f84bSDavid du Colombier 	if(srb == nil)
2689ef1f84bSDavid du Colombier 		error(Enomem);
2699ef1f84bSDavid du Colombier 	srb->dp = srb->data = srb+1;
2709ef1f84bSDavid du Colombier 	srb->ticksent = sys->ticks;
271406c76faSDavid du Colombier 	srb->shared = 0;
2729ef1f84bSDavid du Colombier 	return srb;
2739ef1f84bSDavid du Colombier }
2749ef1f84bSDavid du Colombier 
2759ef1f84bSDavid du Colombier static Srb*
srbkalloc(void * db,ulong)2769ef1f84bSDavid du Colombier srbkalloc(void *db, ulong)
2779ef1f84bSDavid du Colombier {
2789ef1f84bSDavid du Colombier 	Srb *srb;
2799ef1f84bSDavid du Colombier 
2809ef1f84bSDavid du Colombier 	srb = malloc(sizeof *srb);
2819ef1f84bSDavid du Colombier 	if(srb == nil)
2829ef1f84bSDavid du Colombier 		error(Enomem);
2839ef1f84bSDavid du Colombier 	srb->dp = srb->data = db;
2849ef1f84bSDavid du Colombier 	srb->ticksent = sys->ticks;
285406c76faSDavid du Colombier 	srb->shared = 0;
2869ef1f84bSDavid du Colombier 	return srb;
2879ef1f84bSDavid du Colombier }
2889ef1f84bSDavid du Colombier 
289406c76faSDavid du Colombier static void
srbfree(Srb * srb)290406c76faSDavid du Colombier srbfree(Srb *srb)
291406c76faSDavid du Colombier {
292406c76faSDavid du Colombier 	while(srb->shared)
293406c76faSDavid du Colombier 		sched();
294406c76faSDavid du Colombier 	free(srb);
295406c76faSDavid du Colombier }
2969ef1f84bSDavid du Colombier 
2979ef1f84bSDavid du Colombier static void
srberror(Srb * srb,char * s)2989ef1f84bSDavid du Colombier srberror(Srb *srb, char *s)
2999ef1f84bSDavid du Colombier {
3009ef1f84bSDavid du Colombier 	srb->error = s;
3019ef1f84bSDavid du Colombier 	srb->nout--;
3029ef1f84bSDavid du Colombier 	if(srb->nout == 0)
3039ef1f84bSDavid du Colombier 		wakeup(srb);
3049ef1f84bSDavid du Colombier }
3059ef1f84bSDavid du Colombier 
3069ef1f84bSDavid du Colombier static void
frameerror(Aoedev * d,Frame * f,char * s)3079ef1f84bSDavid du Colombier frameerror(Aoedev *d, Frame *f, char *s)
3089ef1f84bSDavid du Colombier {
3099ef1f84bSDavid du Colombier 	Srb *srb;
3109ef1f84bSDavid du Colombier 
3119ef1f84bSDavid du Colombier 	srb = f->srb;
3129ef1f84bSDavid du Colombier 	if(f->tag == Tfree || !srb)
3139ef1f84bSDavid du Colombier 		return;
3149ef1f84bSDavid du Colombier 	f->srb = nil;
3159ef1f84bSDavid du Colombier 	f->tag = Tfree;		/* don't get fooled by way-slow responses */
3169ef1f84bSDavid du Colombier 	srberror(srb, s);
3179ef1f84bSDavid du Colombier 	d->nout--;
3189ef1f84bSDavid du Colombier }
3199ef1f84bSDavid du Colombier 
3209ef1f84bSDavid du Colombier static char*
unitname(Aoedev * d)3219ef1f84bSDavid du Colombier unitname(Aoedev *d)
3229ef1f84bSDavid du Colombier {
3239ef1f84bSDavid du Colombier 	uprint("%d.%d", d->major, d->minor);
3249ef1f84bSDavid du Colombier 	return up->genbuf;
3259ef1f84bSDavid du Colombier }
3269ef1f84bSDavid du Colombier 
3279ef1f84bSDavid du Colombier static int
eventlogready(void *)3289ef1f84bSDavid du Colombier eventlogready(void*)
3299ef1f84bSDavid du Colombier {
3309ef1f84bSDavid du Colombier 	return *events.rp;
3319ef1f84bSDavid du Colombier }
3329ef1f84bSDavid du Colombier 
3339ef1f84bSDavid du Colombier static long
eventlogread(void * a,long n)3349ef1f84bSDavid du Colombier eventlogread(void *a, long n)
3359ef1f84bSDavid du Colombier {
3369ef1f84bSDavid du Colombier 	int len;
3379ef1f84bSDavid du Colombier 	char *p, *buf;
3389ef1f84bSDavid du Colombier 
3399ef1f84bSDavid du Colombier 	buf = smalloc(Eventlen);
3409ef1f84bSDavid du Colombier 	qlock(&events);
3419ef1f84bSDavid du Colombier 	lock(&events);
3429ef1f84bSDavid du Colombier 	p = events.rp;
3439ef1f84bSDavid du Colombier 	len = *p;
3449ef1f84bSDavid du Colombier 	if(len == 0){
3459ef1f84bSDavid du Colombier 		n = 0;
3469ef1f84bSDavid du Colombier 		unlock(&events);
3479ef1f84bSDavid du Colombier 	} else {
3489ef1f84bSDavid du Colombier 		if(n > len)
3499ef1f84bSDavid du Colombier 			n = len;
3509ef1f84bSDavid du Colombier 		/* can't move directly into pageable space with events lock held */
3519ef1f84bSDavid du Colombier 		memmove(buf, p+1, n);
3529ef1f84bSDavid du Colombier 		*p = 0;
3539ef1f84bSDavid du Colombier 		events.rp = p += Eventlen;
3549ef1f84bSDavid du Colombier 		if(p >= events.buf + sizeof events.buf)
3559ef1f84bSDavid du Colombier 			events.rp = events.buf;
3569ef1f84bSDavid du Colombier 		unlock(&events);
3579ef1f84bSDavid du Colombier 
3589ef1f84bSDavid du Colombier 		/* the concern here is page faults in memmove below */
3599ef1f84bSDavid du Colombier 		if(waserror()){
3609ef1f84bSDavid du Colombier 			free(buf);
3619ef1f84bSDavid du Colombier 			qunlock(&events);
3629ef1f84bSDavid du Colombier 			nexterror();
3639ef1f84bSDavid du Colombier 		}
3649ef1f84bSDavid du Colombier 		memmove(a, buf, n);
3659ef1f84bSDavid du Colombier 		poperror();
3669ef1f84bSDavid du Colombier 	}
3679ef1f84bSDavid du Colombier 	free(buf);
3689ef1f84bSDavid du Colombier 	qunlock(&events);
3699ef1f84bSDavid du Colombier 	return n;
3709ef1f84bSDavid du Colombier }
3719ef1f84bSDavid du Colombier 
3729ef1f84bSDavid du Colombier static int
eventlog(char * fmt,...)3739ef1f84bSDavid du Colombier eventlog(char *fmt, ...)
3749ef1f84bSDavid du Colombier {
3759ef1f84bSDavid du Colombier 	int dragrp, n;
3769ef1f84bSDavid du Colombier 	char *p;
3779ef1f84bSDavid du Colombier 	va_list arg;
3789ef1f84bSDavid du Colombier 
3799ef1f84bSDavid du Colombier 	lock(&events);
3809ef1f84bSDavid du Colombier 	p = events.wp;
3819ef1f84bSDavid du Colombier 	dragrp = *p++;
3829ef1f84bSDavid du Colombier 	va_start(arg, fmt);
3839ef1f84bSDavid du Colombier 	n = vsnprint(p, Eventlen-1, fmt, arg);
3849ef1f84bSDavid du Colombier 	*--p = n;
3859ef1f84bSDavid du Colombier 	p = events.wp += Eventlen;
3869ef1f84bSDavid du Colombier 	if(p >= events.buf + sizeof events.buf)
3879ef1f84bSDavid du Colombier 		p = events.wp = events.buf;
3889ef1f84bSDavid du Colombier 	if(dragrp)
3899ef1f84bSDavid du Colombier 		events.rp = p;
3909ef1f84bSDavid du Colombier 	unlock(&events);
3919ef1f84bSDavid du Colombier 	wakeup(&events);
3929ef1f84bSDavid du Colombier 	return n;
3939ef1f84bSDavid du Colombier }
3949ef1f84bSDavid du Colombier 
3959ef1f84bSDavid du Colombier static int
eventcount(void)3969ef1f84bSDavid du Colombier eventcount(void)
3979ef1f84bSDavid du Colombier {
3989ef1f84bSDavid du Colombier 	int n;
3999ef1f84bSDavid du Colombier 
4009ef1f84bSDavid du Colombier 	lock(&events);
4019ef1f84bSDavid du Colombier 	if(*events.rp == 0)
4029ef1f84bSDavid du Colombier 		n = 0;
4039ef1f84bSDavid du Colombier 	else
4049ef1f84bSDavid du Colombier 		n = (events.wp - events.rp) & (Nevents - 1);
4059ef1f84bSDavid du Colombier 	unlock(&events);
4069ef1f84bSDavid du Colombier 	return n/Eventlen;
4079ef1f84bSDavid du Colombier }
4089ef1f84bSDavid du Colombier 
4099ef1f84bSDavid du Colombier static int
tsince(int tag)4109ef1f84bSDavid du Colombier tsince(int tag)
4119ef1f84bSDavid du Colombier {
4129ef1f84bSDavid du Colombier 	int n;
4139ef1f84bSDavid du Colombier 
4149ef1f84bSDavid du Colombier 	n = sys->ticks & 0xffff;
4159ef1f84bSDavid du Colombier 	n -= tag & 0xffff;
4169ef1f84bSDavid du Colombier 	if(n < 0)
4179ef1f84bSDavid du Colombier 		n += 1<<16;
4189ef1f84bSDavid du Colombier 	return n;
4199ef1f84bSDavid du Colombier }
4209ef1f84bSDavid du Colombier 
4219ef1f84bSDavid du Colombier static int
newtag(Aoedev * d)4229ef1f84bSDavid du Colombier newtag(Aoedev *d)
4239ef1f84bSDavid du Colombier {
4249ef1f84bSDavid du Colombier 	int t;
4259ef1f84bSDavid du Colombier 
4269ef1f84bSDavid du Colombier 	do {
4279ef1f84bSDavid du Colombier 		t = ++d->lasttag << 16;
4289ef1f84bSDavid du Colombier 		t |= sys->ticks & 0xffff;
4299ef1f84bSDavid du Colombier 	} while (t == Tfree || t == Tmgmt);
4309ef1f84bSDavid du Colombier 	return t;
4319ef1f84bSDavid du Colombier }
4329ef1f84bSDavid du Colombier 
4339ef1f84bSDavid du Colombier static void
downdev(Aoedev * d,char * err)4349ef1f84bSDavid du Colombier downdev(Aoedev *d, char *err)
4359ef1f84bSDavid du Colombier {
4369ef1f84bSDavid du Colombier 	Frame *f, *e;
4379ef1f84bSDavid du Colombier 
4389ef1f84bSDavid du Colombier 	d->flag &= ~Dup;
4399ef1f84bSDavid du Colombier 	f = d->frames;
4409ef1f84bSDavid du Colombier 	e = f + d->nframes;
4419ef1f84bSDavid du Colombier 	for(; f < e; f->tag = Tfree, f->srb = nil, f++)
442406c76faSDavid du Colombier 		frameerror(d, f, Eaoedown);
4439ef1f84bSDavid du Colombier 	d->inprocess = nil;
4449ef1f84bSDavid du Colombier 	eventlog("%æ: removed; %s\n", d, err);
4459ef1f84bSDavid du Colombier }
4469ef1f84bSDavid du Colombier 
4479ef1f84bSDavid du Colombier static Block*
allocfb(Frame * f)4489ef1f84bSDavid du Colombier allocfb(Frame *f)
4499ef1f84bSDavid du Colombier {
4509ef1f84bSDavid du Colombier 	int len;
4519ef1f84bSDavid du Colombier 	Block *b;
4529ef1f84bSDavid du Colombier 
4539ef1f84bSDavid du Colombier 	len = f->nhdr + f->dlen;
4549ef1f84bSDavid du Colombier 	if(len < ETHERMINTU)
4559ef1f84bSDavid du Colombier 		len = ETHERMINTU;
4569ef1f84bSDavid du Colombier 	b = allocb(len);
4579ef1f84bSDavid du Colombier 	memmove(b->wp, f->hdr, f->nhdr);
4589ef1f84bSDavid du Colombier 	if(f->dlen)
4599ef1f84bSDavid du Colombier 		memmove(b->wp + f->nhdr, f->dp, f->dlen);
4609ef1f84bSDavid du Colombier 	b->wp += len;
4619ef1f84bSDavid du Colombier 	return b;
4629ef1f84bSDavid du Colombier }
4639ef1f84bSDavid du Colombier 
4649ef1f84bSDavid du Colombier static void
putlba(Aoeata * a,vlong lba)4659ef1f84bSDavid du Colombier putlba(Aoeata *a, vlong lba)
4669ef1f84bSDavid du Colombier {
4679ef1f84bSDavid du Colombier 	uchar *c;
4689ef1f84bSDavid du Colombier 
4699ef1f84bSDavid du Colombier 	c = a->lba;
4709ef1f84bSDavid du Colombier 	c[0] = lba;
4719ef1f84bSDavid du Colombier 	c[1] = lba >> 8;
4729ef1f84bSDavid du Colombier 	c[2] = lba >> 16;
4739ef1f84bSDavid du Colombier 	c[3] = lba >> 24;
4749ef1f84bSDavid du Colombier 	c[4] = lba >> 32;
4759ef1f84bSDavid du Colombier 	c[5] = lba >> 40;
4769ef1f84bSDavid du Colombier }
4779ef1f84bSDavid du Colombier 
4789ef1f84bSDavid du Colombier static Devlink*
pickdevlink(Aoedev * d)4799ef1f84bSDavid du Colombier pickdevlink(Aoedev *d)
4809ef1f84bSDavid du Colombier {
4819ef1f84bSDavid du Colombier 	ulong i, n;
4829ef1f84bSDavid du Colombier 	Devlink *l;
4839ef1f84bSDavid du Colombier 
4849ef1f84bSDavid du Colombier 	for(i = 0; i < d->ndl; i++){
4859ef1f84bSDavid du Colombier 		n = d->dlidx++ % d->ndl;
4869ef1f84bSDavid du Colombier 		l = d->dl + n;
4879ef1f84bSDavid du Colombier 		if(l && l->flag & Dup)
4889ef1f84bSDavid du Colombier 			return l;
4899ef1f84bSDavid du Colombier 	}
4909ef1f84bSDavid du Colombier 	return 0;
4919ef1f84bSDavid du Colombier }
4929ef1f84bSDavid du Colombier 
4939ef1f84bSDavid du Colombier static int
pickea(Devlink * l)4949ef1f84bSDavid du Colombier pickea(Devlink *l)
4959ef1f84bSDavid du Colombier {
4969ef1f84bSDavid du Colombier 	if(l == 0)
4979ef1f84bSDavid du Colombier 		return -1;
4989ef1f84bSDavid du Colombier 	if(l->nea == 0)
4999ef1f84bSDavid du Colombier 		return -1;
5009ef1f84bSDavid du Colombier 	return l->eaidx++ % l->nea;
5019ef1f84bSDavid du Colombier }
5029ef1f84bSDavid du Colombier 
5039ef1f84bSDavid du Colombier static int
hset(Aoedev * d,Frame * f,Aoehdr * h,int cmd)5049ef1f84bSDavid du Colombier hset(Aoedev *d, Frame *f, Aoehdr *h, int cmd)
5059ef1f84bSDavid du Colombier {
5069ef1f84bSDavid du Colombier 	int i;
5079ef1f84bSDavid du Colombier 	Devlink *l;
5089ef1f84bSDavid du Colombier 
5099ef1f84bSDavid du Colombier 	if(f->srb && sys->ticks - f->srb->ticksent > Maxreqticks){
5109ef1f84bSDavid du Colombier 		eventlog("%æ: srb timeout\n", d);
5119ef1f84bSDavid du Colombier 		if(cmd == ACata && f->srb && Nofail(d, s))
5129ef1f84bSDavid du Colombier 			f->srb->ticksent = sys->ticks;
5139ef1f84bSDavid du Colombier 		else
5149ef1f84bSDavid du Colombier 			frameerror(d, f, Etimedout);
5159ef1f84bSDavid du Colombier 		return -1;
5169ef1f84bSDavid du Colombier 	}
5179ef1f84bSDavid du Colombier 	l = pickdevlink(d);
5189ef1f84bSDavid du Colombier 	i = pickea(l);
5199ef1f84bSDavid du Colombier 	if(i == -1){
5209ef1f84bSDavid du Colombier 		if(cmd != ACata || f->srb == nil || !Nofail(d, s))
5219ef1f84bSDavid du Colombier 			downdev(d, "resend fails; no netlink/ea");
5229ef1f84bSDavid du Colombier 		return -1;
5239ef1f84bSDavid du Colombier 	}
5249ef1f84bSDavid du Colombier 	memmove(h->dst, l->eatab[i], Eaddrlen);
5259ef1f84bSDavid du Colombier 	memmove(h->src, l->nl->ea, sizeof h->src);
5269ef1f84bSDavid du Colombier 	hnputs(h->type, Aoetype);
5279ef1f84bSDavid du Colombier 	h->verflag = Aoever << 4;
5289ef1f84bSDavid du Colombier 	h->error = 0;
5299ef1f84bSDavid du Colombier 	hnputs(h->major, d->major);
5309ef1f84bSDavid du Colombier 	h->minor = d->minor;
5319ef1f84bSDavid du Colombier 	h->cmd = cmd;
5329ef1f84bSDavid du Colombier 
5339ef1f84bSDavid du Colombier 	hnputl(h->tag, f->tag = newtag(d));
5349ef1f84bSDavid du Colombier 	f->dl = l;
5359ef1f84bSDavid du Colombier 	f->nl = l->nl;
5369ef1f84bSDavid du Colombier 	f->eaidx = i;
5379ef1f84bSDavid du Colombier 	f->ticksent = sys->ticks;
5389ef1f84bSDavid du Colombier 
5399ef1f84bSDavid du Colombier 	return f->tag;
5409ef1f84bSDavid du Colombier }
5419ef1f84bSDavid du Colombier 
5429ef1f84bSDavid du Colombier static int
resend(Aoedev * d,Frame * f)5439ef1f84bSDavid du Colombier resend(Aoedev *d, Frame *f)
5449ef1f84bSDavid du Colombier {
5459ef1f84bSDavid du Colombier 	ulong n;
5469ef1f84bSDavid du Colombier 	Aoeata *a;
5479ef1f84bSDavid du Colombier 
5489ef1f84bSDavid du Colombier 	a = (Aoeata*)f->hdr;
5499ef1f84bSDavid du Colombier 	if(hset(d, f, a, a->cmd) == -1)
5509ef1f84bSDavid du Colombier 		return -1;
5519ef1f84bSDavid du Colombier 	n = f->bcnt;
5529ef1f84bSDavid du Colombier 	if(n > d->maxbcnt){
5539ef1f84bSDavid du Colombier 		n = d->maxbcnt;		/* mtu mismatch (jumbo fail?) */
5549ef1f84bSDavid du Colombier 		if(f->dlen > n)
5559ef1f84bSDavid du Colombier 			f->dlen = n;
5569ef1f84bSDavid du Colombier 	}
5579ef1f84bSDavid du Colombier 	a->scnt = n / Aoesectsz;
5589ef1f84bSDavid du Colombier 	f->dl->resent++;
5599ef1f84bSDavid du Colombier 	f->dl->npkt++;
5609ef1f84bSDavid du Colombier 	if(waserror())
5619ef1f84bSDavid du Colombier 		return -1;
5629ef1f84bSDavid du Colombier 	f->nl->dc->dev->bwrite(f->nl->dc, allocfb(f), 0);
5639ef1f84bSDavid du Colombier 	poperror();
5649ef1f84bSDavid du Colombier 	return 0;
5659ef1f84bSDavid du Colombier }
5669ef1f84bSDavid du Colombier 
5679ef1f84bSDavid du Colombier static void
discover(int major,int minor)5689ef1f84bSDavid du Colombier discover(int major, int minor)
5699ef1f84bSDavid du Colombier {
5709ef1f84bSDavid du Colombier 	Aoehdr *h;
5719ef1f84bSDavid du Colombier 	Block *b;
5729ef1f84bSDavid du Colombier 	Netlink *nl, *e;
5739ef1f84bSDavid du Colombier 
5749ef1f84bSDavid du Colombier 	nl = netlinks.nl;
5759ef1f84bSDavid du Colombier 	e = nl + nelem(netlinks.nl);
5769ef1f84bSDavid du Colombier 	for(; nl < e; nl++){
5779ef1f84bSDavid du Colombier 		if(nl->cc == nil)
5789ef1f84bSDavid du Colombier 			continue;
5799ef1f84bSDavid du Colombier 		b = allocb(ETHERMINTU);
5809ef1f84bSDavid du Colombier 		if(waserror()){
5819ef1f84bSDavid du Colombier 			freeb(b);
5829ef1f84bSDavid du Colombier 			nexterror();
5839ef1f84bSDavid du Colombier 		}
5849ef1f84bSDavid du Colombier 		b->wp = b->rp + ETHERMINTU;
5859ef1f84bSDavid du Colombier 		memset(b->rp, 0, ETHERMINTU);
5869ef1f84bSDavid du Colombier 		h = (Aoehdr*)b->rp;
5879ef1f84bSDavid du Colombier 		memset(h->dst, 0xff, sizeof h->dst);
5889ef1f84bSDavid du Colombier 		memmove(h->src, nl->ea, sizeof h->src);
5899ef1f84bSDavid du Colombier 		hnputs(h->type, Aoetype);
5909ef1f84bSDavid du Colombier 		h->verflag = Aoever << 4;
5919ef1f84bSDavid du Colombier 		hnputs(h->major, major);
5929ef1f84bSDavid du Colombier 		h->minor = minor;
5939ef1f84bSDavid du Colombier 		h->cmd = ACconfig;
5949ef1f84bSDavid du Colombier 		poperror();
5959ef1f84bSDavid du Colombier 		/* send b down the queue */
5969ef1f84bSDavid du Colombier 		nl->dc->dev->bwrite(nl->dc, b, 0);
5979ef1f84bSDavid du Colombier 	}
5989ef1f84bSDavid du Colombier }
5999ef1f84bSDavid du Colombier 
6009ef1f84bSDavid du Colombier /*
6019ef1f84bSDavid du Colombier  * Check all frames on device and resend any frames that have been
6029ef1f84bSDavid du Colombier  * outstanding for 200% of the device round trip time average.
6039ef1f84bSDavid du Colombier  */
6049ef1f84bSDavid du Colombier static void
aoesweepproc(void *)6059ef1f84bSDavid du Colombier aoesweepproc(void*)
6069ef1f84bSDavid du Colombier {
6079ef1f84bSDavid du Colombier 	ulong i, tx, timeout, nbc;
6089ef1f84bSDavid du Colombier 	vlong starttick;
6099ef1f84bSDavid du Colombier 	enum { Nms = 100, Nbcms = 30*1000, };		/* magic */
6109ef1f84bSDavid du Colombier 	uchar *ea;
6119ef1f84bSDavid du Colombier 	Aoeata *a;
6129ef1f84bSDavid du Colombier 	Aoedev *d;
6139ef1f84bSDavid du Colombier 	Devlink *l;
6149ef1f84bSDavid du Colombier 	Frame *f, *e;
6159ef1f84bSDavid du Colombier 
6169ef1f84bSDavid du Colombier 	nbc = Nbcms/Nms;
6179ef1f84bSDavid du Colombier loop:
6189ef1f84bSDavid du Colombier 	if(nbc-- == 0){
6199ef1f84bSDavid du Colombier 		if(rediscover && !waserror()){
6209ef1f84bSDavid du Colombier 			discover(0xffff, 0xff);
6219ef1f84bSDavid du Colombier 			poperror();
6229ef1f84bSDavid du Colombier 		}
6239ef1f84bSDavid du Colombier 		nbc = Nbcms/Nms;
6249ef1f84bSDavid du Colombier 	}
6259ef1f84bSDavid du Colombier 	starttick = sys->ticks;
6269ef1f84bSDavid du Colombier 	rlock(&devs);
6279ef1f84bSDavid du Colombier 	for(d = devs.d; d; d = d->next){
6289ef1f84bSDavid du Colombier 		if(!canqlock(d))
6299ef1f84bSDavid du Colombier 			continue;
6309ef1f84bSDavid du Colombier 		if(!UP(d)){
6319ef1f84bSDavid du Colombier 			qunlock(d);
6329ef1f84bSDavid du Colombier 			continue;
6339ef1f84bSDavid du Colombier 		}
6349ef1f84bSDavid du Colombier 		tx = 0;
6359ef1f84bSDavid du Colombier 		f = d->frames;
6369ef1f84bSDavid du Colombier 		e = f + d->nframes;
6379ef1f84bSDavid du Colombier 		for (; f < e; f++){
6389ef1f84bSDavid du Colombier 			if(f->tag == Tfree)
6399ef1f84bSDavid du Colombier 				continue;
6409ef1f84bSDavid du Colombier 			l = f->dl;
6419ef1f84bSDavid du Colombier 			timeout = l->rttavg << 1;
6429ef1f84bSDavid du Colombier 			i = tsince(f->tag);
6439ef1f84bSDavid du Colombier 			if(i < timeout)
6449ef1f84bSDavid du Colombier 				continue;
6459ef1f84bSDavid du Colombier 			if(d->nout == d->maxout){
6469ef1f84bSDavid du Colombier 				if(d->maxout > 1)
6479ef1f84bSDavid du Colombier 					d->maxout--;
6489ef1f84bSDavid du Colombier 				d->lastwadj = sys->ticks;
6499ef1f84bSDavid du Colombier 			}
6509ef1f84bSDavid du Colombier 			a = (Aoeata*)f->hdr;
6519ef1f84bSDavid du Colombier 			if(a->scnt > Dbcnt / Aoesectsz &&
6529ef1f84bSDavid du Colombier 			   ++f->nl->lostjumbo > (d->nframes << 1)){
6539ef1f84bSDavid du Colombier 				ea = f->dl->eatab[f->eaidx];
6549ef1f84bSDavid du Colombier 				eventlog("%æ: jumbo failure on %s:%E; lba%lld\n",
6559ef1f84bSDavid du Colombier 					d, f->nl->path, ea, f->lba);
6569ef1f84bSDavid du Colombier 				d->maxbcnt = Dbcnt;
6579ef1f84bSDavid du Colombier 				d->flag &= ~Djumbo;
6589ef1f84bSDavid du Colombier 			}
6599ef1f84bSDavid du Colombier 			resend(d, f);
6609ef1f84bSDavid du Colombier 			if(tx++ == 0){
6619ef1f84bSDavid du Colombier 				if((l->rttavg <<= 1) > Rtmax)
6629ef1f84bSDavid du Colombier 					l->rttavg = Rtmax;
6639ef1f84bSDavid du Colombier 				eventlog("%æ: rtt %ldms\n", d, TK2MS(l->rttavg));
6649ef1f84bSDavid du Colombier 			}
6659ef1f84bSDavid du Colombier 		}
6669ef1f84bSDavid du Colombier 		if(d->nout == d->maxout && d->maxout < d->nframes &&
6679ef1f84bSDavid du Colombier 		   TK2MS(sys->ticks - d->lastwadj) > 10*1000){ /* more magic */
6689ef1f84bSDavid du Colombier 			d->maxout++;
6699ef1f84bSDavid du Colombier 			d->lastwadj = sys->ticks;
6709ef1f84bSDavid du Colombier 		}
6719ef1f84bSDavid du Colombier 		qunlock(d);
6729ef1f84bSDavid du Colombier 	}
6739ef1f84bSDavid du Colombier 	runlock(&devs);
6749ef1f84bSDavid du Colombier 	i = Nms - TK2MS(sys->ticks - starttick);
6759ef1f84bSDavid du Colombier 	if(i > 0)
6769ef1f84bSDavid du Colombier 		tsleep(&up->sleep, return0, 0, i);
6779ef1f84bSDavid du Colombier 	goto loop;
6789ef1f84bSDavid du Colombier }
6799ef1f84bSDavid du Colombier 
6809ef1f84bSDavid du Colombier static int
6819ef1f84bSDavid du Colombier fmtæ(Fmt *f)
6829ef1f84bSDavid du Colombier {
6839ef1f84bSDavid du Colombier 	char buf[16];
6849ef1f84bSDavid du Colombier 	Aoedev *d;
6859ef1f84bSDavid du Colombier 
6869ef1f84bSDavid du Colombier 	d = va_arg(f->args, Aoedev*);
6879ef1f84bSDavid du Colombier 	snprint(buf, sizeof buf, "aoe%d.%d", d->major, d->minor);
6889ef1f84bSDavid du Colombier 	return fmtstrcpy(f, buf);
6899ef1f84bSDavid du Colombier }
6909ef1f84bSDavid du Colombier 
6919ef1f84bSDavid du Colombier static void netbind(char *path);
6929ef1f84bSDavid du Colombier 
6939ef1f84bSDavid du Colombier static void
aoecfg(void)6949ef1f84bSDavid du Colombier aoecfg(void)
6959ef1f84bSDavid du Colombier {
6969ef1f84bSDavid du Colombier 	int n, i;
6979ef1f84bSDavid du Colombier 	char *p, *f[32], buf[24];
6989ef1f84bSDavid du Colombier 
6999ef1f84bSDavid du Colombier 	if((p = getconf("aoeif")) == nil || (n = tokenize(p, f, nelem(f))) < 1)
7009ef1f84bSDavid du Colombier 		return;
7019ef1f84bSDavid du Colombier 	/* goo! */
7029ef1f84bSDavid du Colombier 	for(i = 0; i < n; i++){
7039ef1f84bSDavid du Colombier 		p = f[i];
7049ef1f84bSDavid du Colombier 		if(strncmp(p, "ether", 5) == 0)
7059ef1f84bSDavid du Colombier 			snprint(buf, sizeof buf, "#l%c/ether%c", p[5], p[5]);
7069ef1f84bSDavid du Colombier 		else if(strncmp(p, "#l", 2) == 0)
7079ef1f84bSDavid du Colombier 			snprint(buf, sizeof buf, "#l%c/ether%c", p[2], p[2]);
7089ef1f84bSDavid du Colombier 		else
7099ef1f84bSDavid du Colombier 			continue;
7109ef1f84bSDavid du Colombier 		if(!waserror()){
7119ef1f84bSDavid du Colombier 			netbind(buf);
7129ef1f84bSDavid du Colombier 			poperror();
7139ef1f84bSDavid du Colombier 		}
7149ef1f84bSDavid du Colombier 	}
7159ef1f84bSDavid du Colombier }
7169ef1f84bSDavid du Colombier 
7179ef1f84bSDavid du Colombier static void
aoeinit(void)7189ef1f84bSDavid du Colombier aoeinit(void)
7199ef1f84bSDavid du Colombier {
7209ef1f84bSDavid du Colombier 	static int init;
7219ef1f84bSDavid du Colombier 	static QLock l;
7229ef1f84bSDavid du Colombier 
7239ef1f84bSDavid du Colombier 	if(!canqlock(&l))
7249ef1f84bSDavid du Colombier 		return;
7259ef1f84bSDavid du Colombier 	if(init == 0){
7269ef1f84bSDavid du Colombier 		fmtinstall(L'æ', fmtæ);
7279ef1f84bSDavid du Colombier 		events.rp = events.wp = events.buf;
7289ef1f84bSDavid du Colombier 		kproc("aoesweep", aoesweepproc, nil);
7299ef1f84bSDavid du Colombier 		aoecfg();
7309ef1f84bSDavid du Colombier 		init = 1;
7319ef1f84bSDavid du Colombier 	}
7329ef1f84bSDavid du Colombier 	qunlock(&l);
7339ef1f84bSDavid du Colombier }
7349ef1f84bSDavid du Colombier 
7359ef1f84bSDavid du Colombier static Chan*
aoeattach(char * spec)7369ef1f84bSDavid du Colombier aoeattach(char *spec)
7379ef1f84bSDavid du Colombier {
7389ef1f84bSDavid du Colombier 	Chan *c;
7399ef1f84bSDavid du Colombier 
7409ef1f84bSDavid du Colombier 	if(*spec)
7419ef1f84bSDavid du Colombier 		error(Enonexist);
7429ef1f84bSDavid du Colombier 	aoeinit();
7439ef1f84bSDavid du Colombier 	c = devattach(L'æ', spec);
7449ef1f84bSDavid du Colombier 	mkqid(&c->qid, Qzero, 0, QTDIR);
7459ef1f84bSDavid du Colombier 	return c;
7469ef1f84bSDavid du Colombier }
7479ef1f84bSDavid du Colombier 
7489ef1f84bSDavid du Colombier static Aoedev*
unit2dev(ulong unit)7499ef1f84bSDavid du Colombier unit2dev(ulong unit)
7509ef1f84bSDavid du Colombier {
7519ef1f84bSDavid du Colombier 	int i;
7529ef1f84bSDavid du Colombier 	Aoedev *d;
7539ef1f84bSDavid du Colombier 
7549ef1f84bSDavid du Colombier 	rlock(&devs);
7559ef1f84bSDavid du Colombier 	i = 0;
7569ef1f84bSDavid du Colombier 	for(d = devs.d; d; d = d->next)
7579ef1f84bSDavid du Colombier 		if(i++ == unit){
7589ef1f84bSDavid du Colombier 			runlock(&devs);
7599ef1f84bSDavid du Colombier 			return d;
7609ef1f84bSDavid du Colombier 		}
7619ef1f84bSDavid du Colombier 	runlock(&devs);
7629ef1f84bSDavid du Colombier 	uprint("unit lookup failure: %#lux pc %#p", unit, getcallerpc(&unit));
7639ef1f84bSDavid du Colombier 	error(up->genbuf);
7649ef1f84bSDavid du Colombier 	return nil;
7659ef1f84bSDavid du Colombier }
7669ef1f84bSDavid du Colombier 
7679ef1f84bSDavid du Colombier static int
unitgen(Chan * c,ulong type,Dir * dp)7689ef1f84bSDavid du Colombier unitgen(Chan *c, ulong type, Dir *dp)
7699ef1f84bSDavid du Colombier {
7709ef1f84bSDavid du Colombier 	int perm, t;
7719ef1f84bSDavid du Colombier 	ulong vers;
7729ef1f84bSDavid du Colombier 	vlong size;
7739ef1f84bSDavid du Colombier 	char *p;
7749ef1f84bSDavid du Colombier 	Aoedev *d;
7759ef1f84bSDavid du Colombier 	Qid q;
7769ef1f84bSDavid du Colombier 
7779ef1f84bSDavid du Colombier 	d = unit2dev(UNIT(c->qid));
7789ef1f84bSDavid du Colombier 	perm = 0644;
7799ef1f84bSDavid du Colombier 	size = 0;
7809ef1f84bSDavid du Colombier 	vers = d->vers;
7819ef1f84bSDavid du Colombier 	t = QTFILE;
7829ef1f84bSDavid du Colombier 
7839ef1f84bSDavid du Colombier 	switch(type){
7849ef1f84bSDavid du Colombier 	default:
7859ef1f84bSDavid du Colombier 		return -1;
7869ef1f84bSDavid du Colombier 	case Qctl:
7879ef1f84bSDavid du Colombier 		p = "ctl";
7889ef1f84bSDavid du Colombier 		break;
7899ef1f84bSDavid du Colombier 	case Qdata:
7909ef1f84bSDavid du Colombier 		p = "data";
7919ef1f84bSDavid du Colombier 		perm = 0640;
7929ef1f84bSDavid du Colombier 		if(UP(d))
7939ef1f84bSDavid du Colombier 			size = d->bsize;
7949ef1f84bSDavid du Colombier 		break;
7959ef1f84bSDavid du Colombier 	case Qconfig:
7969ef1f84bSDavid du Colombier 		p = "config";
7979ef1f84bSDavid du Colombier 		if(UP(d))
7989ef1f84bSDavid du Colombier 			size = d->nconfig;
7999ef1f84bSDavid du Colombier 		break;
8009ef1f84bSDavid du Colombier 	case Qident:
8019ef1f84bSDavid du Colombier 		p = "ident";
8029ef1f84bSDavid du Colombier 		if(UP(d))
8039ef1f84bSDavid du Colombier 			size = sizeof d->ident;
8049ef1f84bSDavid du Colombier 		break;
8059ef1f84bSDavid du Colombier 	case Qdevlinkdir:
8069ef1f84bSDavid du Colombier 		p = "devlink";
8079ef1f84bSDavid du Colombier 		t = QTDIR;
8089ef1f84bSDavid du Colombier 		perm = 0555;
8099ef1f84bSDavid du Colombier 		break;
8109ef1f84bSDavid du Colombier 	}
8119ef1f84bSDavid du Colombier 	mkqid(&q, QID(UNIT(c->qid), type), vers, t);
8129ef1f84bSDavid du Colombier 	devdir(c, q, p, size, eve, perm, dp);
8139ef1f84bSDavid du Colombier 	return 1;
8149ef1f84bSDavid du Colombier }
8159ef1f84bSDavid du Colombier 
8169ef1f84bSDavid du Colombier static int
topgen(Chan * c,ulong type,Dir * d)8179ef1f84bSDavid du Colombier topgen(Chan *c, ulong type, Dir *d)
8189ef1f84bSDavid du Colombier {
8199ef1f84bSDavid du Colombier 	int perm;
8209ef1f84bSDavid du Colombier 	vlong size;
8219ef1f84bSDavid du Colombier 	char *p;
8229ef1f84bSDavid du Colombier 	Qid q;
8239ef1f84bSDavid du Colombier 
8249ef1f84bSDavid du Colombier 	perm = 0444;
8259ef1f84bSDavid du Colombier 	size = 0;
8269ef1f84bSDavid du Colombier 	switch(type){
8279ef1f84bSDavid du Colombier 	default:
8289ef1f84bSDavid du Colombier 		return -1;
8299ef1f84bSDavid du Colombier 	case Qtopctl:
8309ef1f84bSDavid du Colombier 		p = "ctl";
8319ef1f84bSDavid du Colombier 		perm = 0644;
8329ef1f84bSDavid du Colombier 		break;
8339ef1f84bSDavid du Colombier 	case Qtoplog:
8349ef1f84bSDavid du Colombier 		p = "log";
8359ef1f84bSDavid du Colombier 		size = eventcount();
8369ef1f84bSDavid du Colombier 		break;
8379ef1f84bSDavid du Colombier 	}
8389ef1f84bSDavid du Colombier 	mkqid(&q, type, 0, QTFILE);
8399ef1f84bSDavid du Colombier 	devdir(c, q, p, size, eve, perm, d);
8409ef1f84bSDavid du Colombier 	return 1;
8419ef1f84bSDavid du Colombier }
8429ef1f84bSDavid du Colombier 
8439ef1f84bSDavid du Colombier static int
aoegen(Chan * c,char *,Dirtab *,int,int s,Dir * dp)8449ef1f84bSDavid du Colombier aoegen(Chan *c, char *, Dirtab *, int, int s, Dir *dp)
8459ef1f84bSDavid du Colombier {
8469ef1f84bSDavid du Colombier 	int i;
8479ef1f84bSDavid du Colombier 	Aoedev *d;
8489ef1f84bSDavid du Colombier 	Qid q;
8499ef1f84bSDavid du Colombier 
8509ef1f84bSDavid du Colombier 	if(c->qid.path == 0){
8519ef1f84bSDavid du Colombier 		switch(s){
8529ef1f84bSDavid du Colombier 		case DEVDOTDOT:
8539ef1f84bSDavid du Colombier 			q.path = 0;
8549ef1f84bSDavid du Colombier 			q.type = QTDIR;
8559ef1f84bSDavid du Colombier 			devdir(c, q, "#æ", 0, eve, 0555, dp);
8569ef1f84bSDavid du Colombier 			break;
8579ef1f84bSDavid du Colombier 		case 0:
8589ef1f84bSDavid du Colombier 			q.path = Qtopdir;
8599ef1f84bSDavid du Colombier 			q.type = QTDIR;
8609ef1f84bSDavid du Colombier 			devdir(c, q, "aoe", 0, eve, 0555, dp);
8619ef1f84bSDavid du Colombier 			break;
8629ef1f84bSDavid du Colombier 		default:
8639ef1f84bSDavid du Colombier 			return -1;
8649ef1f84bSDavid du Colombier 		}
8659ef1f84bSDavid du Colombier 		return 1;
8669ef1f84bSDavid du Colombier 	}
8679ef1f84bSDavid du Colombier 
8689ef1f84bSDavid du Colombier 	switch(TYPE(c->qid)){
8699ef1f84bSDavid du Colombier 	default:
8709ef1f84bSDavid du Colombier 		return -1;
8719ef1f84bSDavid du Colombier 	case Qtopdir:
8729ef1f84bSDavid du Colombier 		if(s == DEVDOTDOT){
8739ef1f84bSDavid du Colombier 			mkqid(&q, Qzero, 0, QTDIR);
8749ef1f84bSDavid du Colombier 			devdir(c, q, "aoe", 0, eve, 0555, dp);
8759ef1f84bSDavid du Colombier 			return 1;
8769ef1f84bSDavid du Colombier 		}
8779ef1f84bSDavid du Colombier 		if(s < Qtopfiles)
8789ef1f84bSDavid du Colombier 			return topgen(c, Qtopbase + s, dp);
8799ef1f84bSDavid du Colombier 		s -= Qtopfiles;
8809ef1f84bSDavid du Colombier 		if(s >= units.ref)
8819ef1f84bSDavid du Colombier 			return -1;
8829ef1f84bSDavid du Colombier 		mkqid(&q, QID(s, Qunitdir), 0, QTDIR);
8839ef1f84bSDavid du Colombier 		d = unit2dev(s);
8849ef1f84bSDavid du Colombier 		assert(d != nil);
8859ef1f84bSDavid du Colombier 		devdir(c, q, unitname(d), 0, eve, 0555, dp);
8869ef1f84bSDavid du Colombier 		return 1;
8879ef1f84bSDavid du Colombier 	case Qtopctl:
8889ef1f84bSDavid du Colombier 	case Qtoplog:
8899ef1f84bSDavid du Colombier 		return topgen(c, TYPE(c->qid), dp);
8909ef1f84bSDavid du Colombier 	case Qunitdir:
8919ef1f84bSDavid du Colombier 		if(s == DEVDOTDOT){
8929ef1f84bSDavid du Colombier 			mkqid(&q, QID(0, Qtopdir), 0, QTDIR);
8939ef1f84bSDavid du Colombier 			uprint("%uld", UNIT(c->qid));
8949ef1f84bSDavid du Colombier 			devdir(c, q, up->genbuf, 0, eve, 0555, dp);
8959ef1f84bSDavid du Colombier 			return 1;
8969ef1f84bSDavid du Colombier 		}
8979ef1f84bSDavid du Colombier 		return unitgen(c, Qunitbase+s, dp);
8989ef1f84bSDavid du Colombier 	case Qctl:
8999ef1f84bSDavid du Colombier 	case Qdata:
9009ef1f84bSDavid du Colombier 	case Qconfig:
9019ef1f84bSDavid du Colombier 	case Qident:
9029ef1f84bSDavid du Colombier 		return unitgen(c, TYPE(c->qid), dp);
9039ef1f84bSDavid du Colombier 	case Qdevlinkdir:
9049ef1f84bSDavid du Colombier 		i = UNIT(c->qid);
9059ef1f84bSDavid du Colombier 		if(s == DEVDOTDOT){
9069ef1f84bSDavid du Colombier 			mkqid(&q, QID(i, Qunitdir), 0, QTDIR);
9079ef1f84bSDavid du Colombier 			devdir(c, q, "devlink", 0, eve, 0555, dp);
9089ef1f84bSDavid du Colombier 			return 1;
9099ef1f84bSDavid du Colombier 		}
9109ef1f84bSDavid du Colombier 		if(i >= units.ref)
9119ef1f84bSDavid du Colombier 			return -1;
9129ef1f84bSDavid du Colombier 		d = unit2dev(i);
9139ef1f84bSDavid du Colombier 		if(s >= d->ndl)
9149ef1f84bSDavid du Colombier 			return -1;
9159ef1f84bSDavid du Colombier 		uprint("%d", s);
9169ef1f84bSDavid du Colombier 		mkqid(&q, Q3(s, i, Qdevlink), 0, QTFILE);
9179ef1f84bSDavid du Colombier 		devdir(c, q, up->genbuf, 0, eve, 0755, dp);
9189ef1f84bSDavid du Colombier 		return 1;
9199ef1f84bSDavid du Colombier 	case Qdevlink:
9209ef1f84bSDavid du Colombier 		uprint("%d", s);
9219ef1f84bSDavid du Colombier 		mkqid(&q, Q3(s, UNIT(c->qid), Qdevlink), 0, QTFILE);
9229ef1f84bSDavid du Colombier 		devdir(c, q, up->genbuf, 0, eve, 0755, dp);
9239ef1f84bSDavid du Colombier 		return 1;
9249ef1f84bSDavid du Colombier 	}
9259ef1f84bSDavid du Colombier }
9269ef1f84bSDavid du Colombier 
9279ef1f84bSDavid du Colombier static Walkqid*
aoewalk(Chan * c,Chan * nc,char ** name,int nname)9289ef1f84bSDavid du Colombier aoewalk(Chan *c, Chan *nc, char **name, int nname)
9299ef1f84bSDavid du Colombier {
9309ef1f84bSDavid du Colombier 	return devwalk(c, nc, name, nname, nil, 0, aoegen);
9319ef1f84bSDavid du Colombier }
9329ef1f84bSDavid du Colombier 
9339ef1f84bSDavid du Colombier static long
aoestat(Chan * c,uchar * db,long n)9349ef1f84bSDavid du Colombier aoestat(Chan *c, uchar *db, long n)
9359ef1f84bSDavid du Colombier {
9369ef1f84bSDavid du Colombier 	return devstat(c, db, n, nil, 0, aoegen);
9379ef1f84bSDavid du Colombier }
9389ef1f84bSDavid du Colombier 
9399ef1f84bSDavid du Colombier static Chan*
aoeopen(Chan * c,int omode)9409ef1f84bSDavid du Colombier aoeopen(Chan *c, int omode)
9419ef1f84bSDavid du Colombier {
9429ef1f84bSDavid du Colombier 	Aoedev *d;
9439ef1f84bSDavid du Colombier 
9449ef1f84bSDavid du Colombier 	if(TYPE(c->qid) != Qdata)
9459ef1f84bSDavid du Colombier 		return devopen(c, omode, 0, 0, aoegen);
9469ef1f84bSDavid du Colombier 
9479ef1f84bSDavid du Colombier 	d = unit2dev(UNIT(c->qid));
9489ef1f84bSDavid du Colombier 	qlock(d);
9499ef1f84bSDavid du Colombier 	if(waserror()){
9509ef1f84bSDavid du Colombier 		qunlock(d);
9519ef1f84bSDavid du Colombier 		nexterror();
9529ef1f84bSDavid du Colombier 	}
9539ef1f84bSDavid du Colombier 	if(!UP(d))
954406c76faSDavid du Colombier 		error(Eaoedown);
9559ef1f84bSDavid du Colombier 	c = devopen(c, omode, 0, 0, aoegen);
9569ef1f84bSDavid du Colombier 	d->nopen++;
9579ef1f84bSDavid du Colombier 	poperror();
9589ef1f84bSDavid du Colombier 	qunlock(d);
9599ef1f84bSDavid du Colombier 	return c;
9609ef1f84bSDavid du Colombier }
9619ef1f84bSDavid du Colombier 
9629ef1f84bSDavid du Colombier static void
aoeclose(Chan * c)9639ef1f84bSDavid du Colombier aoeclose(Chan *c)
9649ef1f84bSDavid du Colombier {
9659ef1f84bSDavid du Colombier 	Aoedev *d;
9669ef1f84bSDavid du Colombier 
9679ef1f84bSDavid du Colombier 	if(TYPE(c->qid) != Qdata || (c->flag&COPEN) == 0)
9689ef1f84bSDavid du Colombier 		return;
9699ef1f84bSDavid du Colombier 
9709ef1f84bSDavid du Colombier 	d = unit2dev(UNIT(c->qid));
9719ef1f84bSDavid du Colombier 	qlock(d);
9729ef1f84bSDavid du Colombier 	if(--d->nopen == 0 && !waserror()){
9739ef1f84bSDavid du Colombier 		discover(d->major, d->minor);
9749ef1f84bSDavid du Colombier 		poperror();
9759ef1f84bSDavid du Colombier 	}
9769ef1f84bSDavid du Colombier 	qunlock(d);
9779ef1f84bSDavid du Colombier }
9789ef1f84bSDavid du Colombier 
9799ef1f84bSDavid du Colombier static void
atarw(Aoedev * d,Frame * f)9809ef1f84bSDavid du Colombier atarw(Aoedev *d, Frame *f)
9819ef1f84bSDavid du Colombier {
9829ef1f84bSDavid du Colombier 	ulong bcnt;
9839ef1f84bSDavid du Colombier 	char extbit, writebit;
9849ef1f84bSDavid du Colombier 	Aoeata *ah;
9859ef1f84bSDavid du Colombier 	Srb *srb;
9869ef1f84bSDavid du Colombier 
9879ef1f84bSDavid du Colombier 	extbit = 0x4;
9889ef1f84bSDavid du Colombier 	writebit = 0x10;
9899ef1f84bSDavid du Colombier 
9909ef1f84bSDavid du Colombier 	srb = d->inprocess;
9919ef1f84bSDavid du Colombier 	bcnt = d->maxbcnt;
9929ef1f84bSDavid du Colombier 	if(bcnt > srb->len)
9939ef1f84bSDavid du Colombier 		bcnt = srb->len;
9949ef1f84bSDavid du Colombier 	f->nhdr = AOEATASZ;
9959ef1f84bSDavid du Colombier 	memset(f->hdr, 0, f->nhdr);
9969ef1f84bSDavid du Colombier 	ah = (Aoeata*)f->hdr;
9979ef1f84bSDavid du Colombier 	if(hset(d, f, ah, ACata) == -1) {
9989ef1f84bSDavid du Colombier 		d->inprocess = nil;
9999ef1f84bSDavid du Colombier 		return;
10009ef1f84bSDavid du Colombier 	}
10019ef1f84bSDavid du Colombier 	f->dp = srb->dp;
10029ef1f84bSDavid du Colombier 	f->bcnt = bcnt;
10039ef1f84bSDavid du Colombier 	f->lba = srb->sector;
10049ef1f84bSDavid du Colombier 	f->srb = srb;
10059ef1f84bSDavid du Colombier 
10069ef1f84bSDavid du Colombier 	ah->scnt = bcnt / Aoesectsz;
10079ef1f84bSDavid du Colombier 	putlba(ah, f->lba);
10089ef1f84bSDavid du Colombier 	if(d->flag & Dllba)
10099ef1f84bSDavid du Colombier 		ah->aflag |= AAFext;
10109ef1f84bSDavid du Colombier 	else {
10119ef1f84bSDavid du Colombier 		extbit = 0;
10129ef1f84bSDavid du Colombier 		ah->lba[3] &= 0x0f;
10139ef1f84bSDavid du Colombier 		ah->lba[3] |= 0xe0;	/* LBA bit+obsolete 0xa0 */
10149ef1f84bSDavid du Colombier 	}
10159ef1f84bSDavid du Colombier 	if(srb->write){
10169ef1f84bSDavid du Colombier 		ah->aflag |= AAFwrite;
10179ef1f84bSDavid du Colombier 		f->dlen = bcnt;
10189ef1f84bSDavid du Colombier 	}else{
10199ef1f84bSDavid du Colombier 		writebit = 0;
10209ef1f84bSDavid du Colombier 		f->dlen = 0;
10219ef1f84bSDavid du Colombier 	}
10229ef1f84bSDavid du Colombier 	ah->cmdstat = 0x20 | writebit | extbit;
10239ef1f84bSDavid du Colombier 
10249ef1f84bSDavid du Colombier 	/* mark tracking fields and load out */
10259ef1f84bSDavid du Colombier 	srb->nout++;
10269ef1f84bSDavid du Colombier 	srb->dp = (uchar*)srb->dp + bcnt;
10279ef1f84bSDavid du Colombier 	srb->len -= bcnt;
10289ef1f84bSDavid du Colombier 	srb->sector += bcnt / Aoesectsz;
10299ef1f84bSDavid du Colombier 	if(srb->len == 0)
10309ef1f84bSDavid du Colombier 		d->inprocess = nil;
10319ef1f84bSDavid du Colombier 	d->nout++;
10329ef1f84bSDavid du Colombier 	f->dl->npkt++;
10339ef1f84bSDavid du Colombier 	if(waserror()){
10349ef1f84bSDavid du Colombier 		f->tag = Tfree;
10359ef1f84bSDavid du Colombier 		d->inprocess = nil;
10369ef1f84bSDavid du Colombier 		nexterror();
10379ef1f84bSDavid du Colombier 	}
10389ef1f84bSDavid du Colombier 	f->nl->dc->dev->bwrite(f->nl->dc, allocfb(f), 0);
10399ef1f84bSDavid du Colombier 	poperror();
10409ef1f84bSDavid du Colombier }
10419ef1f84bSDavid du Colombier 
10429ef1f84bSDavid du Colombier static char*
aoeerror(Aoehdr * h)10439ef1f84bSDavid du Colombier aoeerror(Aoehdr *h)
10449ef1f84bSDavid du Colombier {
10459ef1f84bSDavid du Colombier 	int n;
10469ef1f84bSDavid du Colombier 	static char *errs[] = {
10479ef1f84bSDavid du Colombier 		"aoe protocol error: unknown",
10489ef1f84bSDavid du Colombier 		"aoe protocol error: bad command code",
10499ef1f84bSDavid du Colombier 		"aoe protocol error: bad argument param",
10509ef1f84bSDavid du Colombier 		"aoe protocol error: device unavailable",
10519ef1f84bSDavid du Colombier 		"aoe protocol error: config string present",
10529ef1f84bSDavid du Colombier 		"aoe protocol error: unsupported version",
10539ef1f84bSDavid du Colombier 		"aoe protocol error: target is reserved",
10549ef1f84bSDavid du Colombier 	};
10559ef1f84bSDavid du Colombier 
10569ef1f84bSDavid du Colombier 	if((h->verflag & AFerr) == 0)
10579ef1f84bSDavid du Colombier 		return 0;
10589ef1f84bSDavid du Colombier 	n = h->error;
10599ef1f84bSDavid du Colombier 	if(n > nelem(errs))
10609ef1f84bSDavid du Colombier 		n = 0;
10619ef1f84bSDavid du Colombier 	return errs[n];
10629ef1f84bSDavid du Colombier }
10639ef1f84bSDavid du Colombier 
10649ef1f84bSDavid du Colombier static void
rtupdate(Devlink * l,int rtt)10659ef1f84bSDavid du Colombier rtupdate(Devlink *l, int rtt)
10669ef1f84bSDavid du Colombier {
10679ef1f84bSDavid du Colombier 	int n;
10689ef1f84bSDavid du Colombier 
10699ef1f84bSDavid du Colombier 	n = rtt;
10709ef1f84bSDavid du Colombier 	if(rtt < 0){
10719ef1f84bSDavid du Colombier 		n = -rtt;
10729ef1f84bSDavid du Colombier 		if(n < Rtmin)
10739ef1f84bSDavid du Colombier 			n = Rtmin;
10749ef1f84bSDavid du Colombier 		else if(n > Rtmax)
10759ef1f84bSDavid du Colombier 			n = Rtmax;
10769ef1f84bSDavid du Colombier 		l->mintimer += (n - l->mintimer) >> 1;
10779ef1f84bSDavid du Colombier 	} else if(n < l->mintimer)
10789ef1f84bSDavid du Colombier 		n = l->mintimer;
10799ef1f84bSDavid du Colombier 	else if(n > Rtmax)
10809ef1f84bSDavid du Colombier 		n = Rtmax;
10819ef1f84bSDavid du Colombier 
10829ef1f84bSDavid du Colombier 	/* g == .25; cf. Congestion Avoidance and Control, Jacobson&Karels; 1988 */
10839ef1f84bSDavid du Colombier 	n -= l->rttavg;
10849ef1f84bSDavid du Colombier 	l->rttavg += n >> 2;
10859ef1f84bSDavid du Colombier }
10869ef1f84bSDavid du Colombier 
10879ef1f84bSDavid du Colombier static int
srbready(void * v)10889ef1f84bSDavid du Colombier srbready(void *v)
10899ef1f84bSDavid du Colombier {
10909ef1f84bSDavid du Colombier 	Srb *s;
10919ef1f84bSDavid du Colombier 
10929ef1f84bSDavid du Colombier 	s = v;
1093406c76faSDavid du Colombier 	return s->error || (s->nout == 0 && s->len == 0);
10949ef1f84bSDavid du Colombier }
10959ef1f84bSDavid du Colombier 
10969ef1f84bSDavid du Colombier static Frame*
getframe(Aoedev * d,int tag)10979ef1f84bSDavid du Colombier getframe(Aoedev *d, int tag)
10989ef1f84bSDavid du Colombier {
10999ef1f84bSDavid du Colombier 	Frame *f, *e;
11009ef1f84bSDavid du Colombier 
11019ef1f84bSDavid du Colombier 	f = d->frames;
11029ef1f84bSDavid du Colombier 	e = f + d->nframes;
11039ef1f84bSDavid du Colombier 	for(; f < e; f++)
11049ef1f84bSDavid du Colombier 		if(f->tag == tag)
11059ef1f84bSDavid du Colombier 			return f;
11069ef1f84bSDavid du Colombier 	return nil;
11079ef1f84bSDavid du Colombier }
11089ef1f84bSDavid du Colombier 
11099ef1f84bSDavid du Colombier static Frame*
freeframe(Aoedev * d)11109ef1f84bSDavid du Colombier freeframe(Aoedev *d)
11119ef1f84bSDavid du Colombier {
11129ef1f84bSDavid du Colombier 	if(d->nout < d->maxout)
11139ef1f84bSDavid du Colombier 		return getframe(d, Tfree);
11149ef1f84bSDavid du Colombier 	return nil;
11159ef1f84bSDavid du Colombier }
11169ef1f84bSDavid du Colombier 
11179ef1f84bSDavid du Colombier static void
work(Aoedev * d)11189ef1f84bSDavid du Colombier work(Aoedev *d)
11199ef1f84bSDavid du Colombier {
11209ef1f84bSDavid du Colombier 	Frame *f;
11219ef1f84bSDavid du Colombier 
11229ef1f84bSDavid du Colombier 	while ((f = freeframe(d)) != nil) {
11239ef1f84bSDavid du Colombier 		if(d->inprocess == nil){
11249ef1f84bSDavid du Colombier 			if(d->head == nil)
11259ef1f84bSDavid du Colombier 				return;
11269ef1f84bSDavid du Colombier 			d->inprocess = d->head;
11279ef1f84bSDavid du Colombier 			d->head = d->head->next;
11289ef1f84bSDavid du Colombier 			if(d->head == nil)
11299ef1f84bSDavid du Colombier 				d->tail = nil;
11309ef1f84bSDavid du Colombier 		}
11319ef1f84bSDavid du Colombier 		atarw(d, f);
11329ef1f84bSDavid du Colombier 	}
11339ef1f84bSDavid du Colombier }
11349ef1f84bSDavid du Colombier 
11359ef1f84bSDavid du Colombier static void
strategy(Aoedev * d,Srb * srb)11369ef1f84bSDavid du Colombier strategy(Aoedev *d, Srb *srb)
11379ef1f84bSDavid du Colombier {
11389ef1f84bSDavid du Colombier 	qlock(d);
11399ef1f84bSDavid du Colombier 	if(waserror()){
11409ef1f84bSDavid du Colombier 		qunlock(d);
11419ef1f84bSDavid du Colombier 		nexterror();
11429ef1f84bSDavid du Colombier 	}
11439ef1f84bSDavid du Colombier 	srb->next = nil;
11449ef1f84bSDavid du Colombier 	if(d->tail)
11459ef1f84bSDavid du Colombier 		d->tail->next = srb;
11469ef1f84bSDavid du Colombier 	d->tail = srb;
11479ef1f84bSDavid du Colombier 	if(d->head == nil)
11489ef1f84bSDavid du Colombier 		d->head = srb;
1149406c76faSDavid du Colombier 	srb->shared = 1;
11509ef1f84bSDavid du Colombier 	work(d);
11519ef1f84bSDavid du Colombier 	poperror();
11529ef1f84bSDavid du Colombier 	qunlock(d);
11539ef1f84bSDavid du Colombier 
11549ef1f84bSDavid du Colombier 	while(waserror())
11559ef1f84bSDavid du Colombier 		;
11569ef1f84bSDavid du Colombier 	sleep(srb, srbready, srb);
11579ef1f84bSDavid du Colombier 	poperror();
11589ef1f84bSDavid du Colombier }
11599ef1f84bSDavid du Colombier 
11609ef1f84bSDavid du Colombier static long
rw(Aoedev * d,int write,uchar * db,long len,uvlong off)11619ef1f84bSDavid du Colombier rw(Aoedev *d, int write, uchar *db, long len, uvlong off)
11629ef1f84bSDavid du Colombier {
11639ef1f84bSDavid du Colombier 	long n, nlen, copy;
11649ef1f84bSDavid du Colombier 	enum { Srbsz = 1<<19, };	/* magic allocation */
11659ef1f84bSDavid du Colombier 	Srb *srb;
11669ef1f84bSDavid du Colombier 
11679ef1f84bSDavid du Colombier 	if((off|len) & (Aoesectsz-1))
11689ef1f84bSDavid du Colombier 		error("offset and length must be sector multiple.\n");
11699ef1f84bSDavid du Colombier 	if(off > d->bsize || len == 0)
11709ef1f84bSDavid du Colombier 		return 0;
11719ef1f84bSDavid du Colombier 	if(off + len > d->bsize)
11729ef1f84bSDavid du Colombier 		len = d->bsize - off;
11739ef1f84bSDavid du Colombier 	copy = 0;
1174*5ae61b61SDavid du Colombier 	if(isdmaok(db, len, 32)){
11759ef1f84bSDavid du Colombier 		srb = srbkalloc(db, len);
11769ef1f84bSDavid du Colombier 		copy = 1;
11779ef1f84bSDavid du Colombier 	}else
11789ef1f84bSDavid du Colombier 		srb = srballoc(Srbsz <= len? Srbsz: len);
11799ef1f84bSDavid du Colombier 	if(waserror()){
11809ef1f84bSDavid du Colombier 		srbfree(srb);
11819ef1f84bSDavid du Colombier 		nexterror();
11829ef1f84bSDavid du Colombier 	}
11839ef1f84bSDavid du Colombier 	nlen = len;
11849ef1f84bSDavid du Colombier 	srb->write = write;
11859ef1f84bSDavid du Colombier 	do {
11869ef1f84bSDavid du Colombier 		if(!UP(d))
11879ef1f84bSDavid du Colombier 			error(Eio);
11889ef1f84bSDavid du Colombier 		srb->sector = off / Aoesectsz;
11899ef1f84bSDavid du Colombier 		srb->dp = srb->data;
11909ef1f84bSDavid du Colombier 		n = nlen;
11919ef1f84bSDavid du Colombier 		if(n > Srbsz)
11929ef1f84bSDavid du Colombier 			n = Srbsz;
11939ef1f84bSDavid du Colombier 		srb->len = n;
11949ef1f84bSDavid du Colombier 		if(write && !copy)
11959ef1f84bSDavid du Colombier 			memmove(srb->data, db, n);
11969ef1f84bSDavid du Colombier 		strategy(d, srb);
11979ef1f84bSDavid du Colombier 		if(srb->error)
11989ef1f84bSDavid du Colombier 			error(srb->error);
11999ef1f84bSDavid du Colombier 		if(!write && !copy)
12009ef1f84bSDavid du Colombier 			memmove(db, srb->data, n);
12019ef1f84bSDavid du Colombier 		nlen -= n;
12029ef1f84bSDavid du Colombier 		db += n;
12039ef1f84bSDavid du Colombier 		off += n;
12049ef1f84bSDavid du Colombier 	} while (nlen > 0);
12059ef1f84bSDavid du Colombier 	poperror();
12069ef1f84bSDavid du Colombier 	srbfree(srb);
12079ef1f84bSDavid du Colombier 	return len;
12089ef1f84bSDavid du Colombier }
12099ef1f84bSDavid du Colombier 
12109ef1f84bSDavid du Colombier static long
readmem(ulong off,void * dst,long n,void * src,long size)12119ef1f84bSDavid du Colombier readmem(ulong off, void *dst, long n, void *src, long size)
12129ef1f84bSDavid du Colombier {
12139ef1f84bSDavid du Colombier 	if(off >= size)
12149ef1f84bSDavid du Colombier 		return 0;
12159ef1f84bSDavid du Colombier 	if(off + n > size)
12169ef1f84bSDavid du Colombier 		n = size - off;
12179ef1f84bSDavid du Colombier 	memmove(dst, (uchar*)src + off, n);
12189ef1f84bSDavid du Colombier 	return n;
12199ef1f84bSDavid du Colombier }
12209ef1f84bSDavid du Colombier 
12219ef1f84bSDavid du Colombier static char *
pflag(char * s,char * e,uchar f)12229ef1f84bSDavid du Colombier pflag(char *s, char *e, uchar f)
12239ef1f84bSDavid du Colombier {
12249ef1f84bSDavid du Colombier 	uchar i;
12259ef1f84bSDavid du Colombier 
12269ef1f84bSDavid du Colombier 	for(i = 0; i < 8; i++)
12279ef1f84bSDavid du Colombier 		if(f & (1 << i))
12289ef1f84bSDavid du Colombier 			s = seprint(s, e, "%s ", flagname[i]? flagname[i]: "oops");
12299ef1f84bSDavid du Colombier 	return seprint(s, e, "\n");
12309ef1f84bSDavid du Colombier }
12319ef1f84bSDavid du Colombier 
12329ef1f84bSDavid du Colombier static int
pstat(Aoedev * d,char * db,int len,int off)12339ef1f84bSDavid du Colombier pstat(Aoedev *d, char *db, int len, int off)
12349ef1f84bSDavid du Colombier {
12359ef1f84bSDavid du Colombier 	int i;
12369ef1f84bSDavid du Colombier 	char *state, *s, *p, *e;
12379ef1f84bSDavid du Colombier 
12389ef1f84bSDavid du Colombier 	s = p = malloc(READSTR);
12399ef1f84bSDavid du Colombier 	if(s == nil)
12409ef1f84bSDavid du Colombier 		error(Enomem);
12419ef1f84bSDavid du Colombier 	e = p + READSTR;
12429ef1f84bSDavid du Colombier 
12439ef1f84bSDavid du Colombier 	state = "down";
12449ef1f84bSDavid du Colombier 	if(UP(d))
12459ef1f84bSDavid du Colombier 		state = "up";
12469ef1f84bSDavid du Colombier 
12479ef1f84bSDavid du Colombier 	p = seprint(p, e,
12489ef1f84bSDavid du Colombier 		"state: %s\n"	"nopen: %d\n"	"nout: %d\n"
12499ef1f84bSDavid du Colombier 		"nmaxout: %d\n"	"nframes: %d\n"	"maxbcnt: %d\n"
12509ef1f84bSDavid du Colombier 		"fw: %.4ux\n"
12519ef1f84bSDavid du Colombier 		"model: %s\n"	"serial: %s\n"	"firmware: %s\n",
12529ef1f84bSDavid du Colombier 		state,		d->nopen,	d->nout,
12539ef1f84bSDavid du Colombier 		d->maxout, 	d->nframes,	d->maxbcnt,
12549ef1f84bSDavid du Colombier 		d->fwver,
12559ef1f84bSDavid du Colombier 		d->model, 	d->serial, 	d->firmware);
12569ef1f84bSDavid du Colombier 	p = seprint(p, e, "flag: ");
12579ef1f84bSDavid du Colombier 	p = pflag(p, e, d->flag);
12589ef1f84bSDavid du Colombier 
12599ef1f84bSDavid du Colombier 	if(p - s < len)
12609ef1f84bSDavid du Colombier 		len = p - s;
12619ef1f84bSDavid du Colombier 	i = readstr(off, db, len, s);
12629ef1f84bSDavid du Colombier 	free(s);
12639ef1f84bSDavid du Colombier 	return i;
12649ef1f84bSDavid du Colombier }
12659ef1f84bSDavid du Colombier 
12669ef1f84bSDavid du Colombier static long
unitread(Chan * c,void * db,long len,vlong off)12679ef1f84bSDavid du Colombier unitread(Chan *c, void *db, long len, vlong off)
12689ef1f84bSDavid du Colombier {
12699ef1f84bSDavid du Colombier 	Aoedev *d;
12709ef1f84bSDavid du Colombier 
12719ef1f84bSDavid du Colombier 	d = unit2dev(UNIT(c->qid));
12729ef1f84bSDavid du Colombier 	if(d->vers != c->qid.vers)
12739ef1f84bSDavid du Colombier 		error(Echange);
12749ef1f84bSDavid du Colombier 	switch(TYPE(c->qid)){
12759ef1f84bSDavid du Colombier 	default:
12769ef1f84bSDavid du Colombier 		error(Ebadarg);
12779ef1f84bSDavid du Colombier 	case Qctl:
12789ef1f84bSDavid du Colombier 		return pstat(d, db, len, off);
12799ef1f84bSDavid du Colombier 	case Qdata:
12809ef1f84bSDavid du Colombier 		return rw(d, Read, db, len, off);
12819ef1f84bSDavid du Colombier 	case Qconfig:
12829ef1f84bSDavid du Colombier 		if (!UP(d))
1283406c76faSDavid du Colombier 			error(Eaoedown);
12849ef1f84bSDavid du Colombier 		return readmem(off, db, len, d->config, d->nconfig);
12859ef1f84bSDavid du Colombier 	case Qident:
12869ef1f84bSDavid du Colombier 		if (!UP(d))
1287406c76faSDavid du Colombier 			error(Eaoedown);
12889ef1f84bSDavid du Colombier 		return readmem(off, db, len, d->ident, sizeof d->ident);
12899ef1f84bSDavid du Colombier 	}
12909ef1f84bSDavid du Colombier }
12919ef1f84bSDavid du Colombier 
12929ef1f84bSDavid du Colombier static int
devlinkread(Chan * c,void * db,int len,int off)12939ef1f84bSDavid du Colombier devlinkread(Chan *c, void *db, int len, int off)
12949ef1f84bSDavid du Colombier {
12959ef1f84bSDavid du Colombier 	int i;
12969ef1f84bSDavid du Colombier 	char *s, *p, *e;
12979ef1f84bSDavid du Colombier 	Aoedev *d;
12989ef1f84bSDavid du Colombier 	Devlink *l;
12999ef1f84bSDavid du Colombier 
13009ef1f84bSDavid du Colombier 	d = unit2dev(UNIT(c->qid));
13019ef1f84bSDavid du Colombier 	i = L(c->qid);
13029ef1f84bSDavid du Colombier 	if(i >= d->ndl)
13039ef1f84bSDavid du Colombier 		return 0;
13049ef1f84bSDavid du Colombier 	l = d->dl + i;
13059ef1f84bSDavid du Colombier 
13069ef1f84bSDavid du Colombier 	s = p = malloc(READSTR);
13079ef1f84bSDavid du Colombier 	if(s == nil)
13089ef1f84bSDavid du Colombier 		error(Enomem);
13099ef1f84bSDavid du Colombier 	e = s + READSTR;
13109ef1f84bSDavid du Colombier 
13119ef1f84bSDavid du Colombier 	p = seprint(p, e, "addr: ");
13129ef1f84bSDavid du Colombier 	for(i = 0; i < l->nea; i++)
13139ef1f84bSDavid du Colombier 		p = seprint(p, e, "%E ", l->eatab[i]);
13149ef1f84bSDavid du Colombier 	p = seprint(p, e, "\n");
13159ef1f84bSDavid du Colombier 	p = seprint(p, e, "npkt: %uld\n", l->npkt);
13169ef1f84bSDavid du Colombier 	p = seprint(p, e, "resent: %uld\n", l->resent);
13179ef1f84bSDavid du Colombier 	p = seprint(p, e, "flag: "); p = pflag(p, e, l->flag);
13189ef1f84bSDavid du Colombier 	p = seprint(p, e, "rttavg: %uld\n", TK2MS(l->rttavg));
13199ef1f84bSDavid du Colombier 	p = seprint(p, e, "mintimer: %uld\n", TK2MS(l->mintimer));
13209ef1f84bSDavid du Colombier 
13219ef1f84bSDavid du Colombier 	p = seprint(p, e, "nl path: %s\n", l->nl->path);
13229ef1f84bSDavid du Colombier 	p = seprint(p, e, "nl ea: %E\n", l->nl->ea);
13239ef1f84bSDavid du Colombier 	p = seprint(p, e, "nl flag: "); p = pflag(p, e, l->flag);
13249ef1f84bSDavid du Colombier 	p = seprint(p, e, "nl lostjumbo: %d\n", l->nl->lostjumbo);
13259ef1f84bSDavid du Colombier 	p = seprint(p, e, "nl datamtu: %d\n", l->nl->datamtu);
13269ef1f84bSDavid du Colombier 
13279ef1f84bSDavid du Colombier 	if(p - s < len)
13289ef1f84bSDavid du Colombier 		len = p - s;
13299ef1f84bSDavid du Colombier 	i = readstr(off, db, len, s);
13309ef1f84bSDavid du Colombier 	free(s);
13319ef1f84bSDavid du Colombier 	return i;
13329ef1f84bSDavid du Colombier }
13339ef1f84bSDavid du Colombier 
13349ef1f84bSDavid du Colombier static long
topctlread(Chan *,void * db,int len,int off)13359ef1f84bSDavid du Colombier topctlread(Chan *, void *db, int len, int off)
13369ef1f84bSDavid du Colombier {
13379ef1f84bSDavid du Colombier 	int i;
13389ef1f84bSDavid du Colombier 	char *s, *p, *e;
13399ef1f84bSDavid du Colombier 	Netlink *n;
13409ef1f84bSDavid du Colombier 
13419ef1f84bSDavid du Colombier 	s = p = malloc(READSTR);
13429ef1f84bSDavid du Colombier 	if(s == nil)
13439ef1f84bSDavid du Colombier 		error(Enomem);
13449ef1f84bSDavid du Colombier 	e = s + READSTR;
13459ef1f84bSDavid du Colombier 
13469ef1f84bSDavid du Colombier 	p = seprint(p, e, "debug: %d\n", debug);
13479ef1f84bSDavid du Colombier 	p = seprint(p, e, "autodiscover: %d\n", autodiscover);
13489ef1f84bSDavid du Colombier 	p = seprint(p, e, "rediscover: %d\n", rediscover);
13499ef1f84bSDavid du Colombier 
13509ef1f84bSDavid du Colombier 	for(i = 0; i < Nnetlink; i++){
13519ef1f84bSDavid du Colombier 		n = netlinks.nl+i;
13529ef1f84bSDavid du Colombier 		if(n->cc == 0)
13539ef1f84bSDavid du Colombier 			continue;
13549ef1f84bSDavid du Colombier 		p = seprint(p, e, "if%d path: %s\n", i, n->path);
13559ef1f84bSDavid du Colombier 		p = seprint(p, e, "if%d ea: %E\n", i, n->ea);
13569ef1f84bSDavid du Colombier 		p = seprint(p, e, "if%d flag: ", i); p = pflag(p, e, n->flag);
13579ef1f84bSDavid du Colombier 		p = seprint(p, e, "if%d lostjumbo: %d\n", i, n->lostjumbo);
13589ef1f84bSDavid du Colombier 		p = seprint(p, e, "if%d datamtu: %d\n", i, n->datamtu);
13599ef1f84bSDavid du Colombier 	}
13609ef1f84bSDavid du Colombier 
13619ef1f84bSDavid du Colombier 	if(p - s < len)
13629ef1f84bSDavid du Colombier 		len = p - s;
13639ef1f84bSDavid du Colombier 	i = readstr(off, db, len, s);
13649ef1f84bSDavid du Colombier 	free(s);
13659ef1f84bSDavid du Colombier 	return i;
13669ef1f84bSDavid du Colombier }
13679ef1f84bSDavid du Colombier 
13689ef1f84bSDavid du Colombier static long
aoeread(Chan * c,void * db,long n,vlong off)13699ef1f84bSDavid du Colombier aoeread(Chan *c, void *db, long n, vlong off)
13709ef1f84bSDavid du Colombier {
13719ef1f84bSDavid du Colombier 	switch(TYPE(c->qid)){
13729ef1f84bSDavid du Colombier 	default:
13739ef1f84bSDavid du Colombier 		error(Eperm);
13749ef1f84bSDavid du Colombier 	case Qzero:
13759ef1f84bSDavid du Colombier 	case Qtopdir:
13769ef1f84bSDavid du Colombier 	case Qunitdir:
13779ef1f84bSDavid du Colombier 	case Qdevlinkdir:
13789ef1f84bSDavid du Colombier 		return devdirread(c, db, n, 0, 0, aoegen);
13799ef1f84bSDavid du Colombier 	case Qtopctl:
13809ef1f84bSDavid du Colombier 		return topctlread(c, db, n, off);
13819ef1f84bSDavid du Colombier 	case Qtoplog:
13829ef1f84bSDavid du Colombier 		return eventlogread(db, n);
13839ef1f84bSDavid du Colombier 	case Qctl:
13849ef1f84bSDavid du Colombier 	case Qdata:
13859ef1f84bSDavid du Colombier 	case Qconfig:
13869ef1f84bSDavid du Colombier 	case Qident:
13879ef1f84bSDavid du Colombier 		return unitread(c, db, n, off);
13889ef1f84bSDavid du Colombier 	case Qdevlink:
13899ef1f84bSDavid du Colombier 		return devlinkread(c, db, n, off);
13909ef1f84bSDavid du Colombier 	}
13919ef1f84bSDavid du Colombier }
13929ef1f84bSDavid du Colombier 
13939ef1f84bSDavid du Colombier static long
configwrite(Aoedev * d,void * db,long len)13949ef1f84bSDavid du Colombier configwrite(Aoedev *d, void *db, long len)
13959ef1f84bSDavid du Colombier {
13969ef1f84bSDavid du Colombier 	char *s;
13979ef1f84bSDavid du Colombier 	Aoeqc *ch;
13989ef1f84bSDavid du Colombier 	Frame *f;
13999ef1f84bSDavid du Colombier 	Srb *srb;
14009ef1f84bSDavid du Colombier 
14019ef1f84bSDavid du Colombier 	if(!UP(d))
1402406c76faSDavid du Colombier 		error(Eaoedown);
14039ef1f84bSDavid du Colombier 	if(len > ETHERMAXTU - AOEQCSZ)
14049ef1f84bSDavid du Colombier 		error(Etoobig);
14059ef1f84bSDavid du Colombier 	srb = srballoc(len);
14069ef1f84bSDavid du Colombier 	s = malloc(len);
14079ef1f84bSDavid du Colombier 	if(s == nil)
14089ef1f84bSDavid du Colombier 		error(Enomem);
14099ef1f84bSDavid du Colombier 	memmove(s, db, len);
1410406c76faSDavid du Colombier 
14119ef1f84bSDavid du Colombier 	if(waserror()){
14129ef1f84bSDavid du Colombier 		srbfree(srb);
14139ef1f84bSDavid du Colombier 		free(s);
14149ef1f84bSDavid du Colombier 		nexterror();
14159ef1f84bSDavid du Colombier 	}
14169ef1f84bSDavid du Colombier 	for (;;) {
14179ef1f84bSDavid du Colombier 		qlock(d);
14189ef1f84bSDavid du Colombier 		if(waserror()){
14199ef1f84bSDavid du Colombier 			qunlock(d);
14209ef1f84bSDavid du Colombier 			nexterror();
14219ef1f84bSDavid du Colombier 		}
14229ef1f84bSDavid du Colombier 		f = freeframe(d);
14239ef1f84bSDavid du Colombier 		if(f != nil)
14249ef1f84bSDavid du Colombier 			break;
14259ef1f84bSDavid du Colombier 		poperror();
14269ef1f84bSDavid du Colombier 		qunlock(d);
1427406c76faSDavid du Colombier 
14289ef1f84bSDavid du Colombier 		if(waserror())
14299ef1f84bSDavid du Colombier 			nexterror();
14309ef1f84bSDavid du Colombier 		tsleep(&up->sleep, return0, 0, 100);
14319ef1f84bSDavid du Colombier 		poperror();
14329ef1f84bSDavid du Colombier 	}
14339ef1f84bSDavid du Colombier 	f->nhdr = AOEQCSZ;
14349ef1f84bSDavid du Colombier 	memset(f->hdr, 0, f->nhdr);
14359ef1f84bSDavid du Colombier 	ch = (Aoeqc*)f->hdr;
1436406c76faSDavid du Colombier 	if(hset(d, f, ch, ACconfig) == -1) {
1437406c76faSDavid du Colombier 		/*
1438406c76faSDavid du Colombier 		 * these refer to qlock & waserror in the above for loop.
1439406c76faSDavid du Colombier 		 * there's still the first waserror outstanding.
1440406c76faSDavid du Colombier 		 */
1441406c76faSDavid du Colombier 		poperror();
1442406c76faSDavid du Colombier 		qunlock(d);
14439ef1f84bSDavid du Colombier 		return 0;
1444406c76faSDavid du Colombier 	}
1445406c76faSDavid du Colombier 	srb->shared = 1;
14469ef1f84bSDavid du Colombier 	f->srb = srb;
14479ef1f84bSDavid du Colombier 	f->dp = s;
14489ef1f84bSDavid du Colombier 	ch->verccmd = AQCfset;
14499ef1f84bSDavid du Colombier 	hnputs(ch->cslen, len);
14509ef1f84bSDavid du Colombier 	d->nout++;
14519ef1f84bSDavid du Colombier 	srb->nout++;
14529ef1f84bSDavid du Colombier 	f->dl->npkt++;
14539ef1f84bSDavid du Colombier 	f->dlen = len;
1454406c76faSDavid du Colombier 	/* these too */
14559ef1f84bSDavid du Colombier 	poperror();
14569ef1f84bSDavid du Colombier 	qunlock(d);
14579ef1f84bSDavid du Colombier 
14589ef1f84bSDavid du Colombier 	f->nl->dc->dev->bwrite(f->nl->dc, allocfb(f), 0);
14599ef1f84bSDavid du Colombier 	sleep(srb, srbready, srb);
14609ef1f84bSDavid du Colombier 	if(srb->error)
14619ef1f84bSDavid du Colombier 		error(srb->error);
14629ef1f84bSDavid du Colombier 
14639ef1f84bSDavid du Colombier 	qlock(d);
14649ef1f84bSDavid du Colombier 	if(waserror()){
14659ef1f84bSDavid du Colombier 		qunlock(d);
14669ef1f84bSDavid du Colombier 		nexterror();
14679ef1f84bSDavid du Colombier 	}
14689ef1f84bSDavid du Colombier 	memmove(d->config, s, len);
14699ef1f84bSDavid du Colombier 	d->nconfig = len;
14709ef1f84bSDavid du Colombier 	poperror();
14719ef1f84bSDavid du Colombier 	qunlock(d);
14729ef1f84bSDavid du Colombier 
14739ef1f84bSDavid du Colombier 	poperror();			/* pop first waserror */
14749ef1f84bSDavid du Colombier 
14759ef1f84bSDavid du Colombier 	srbfree(srb);
14769ef1f84bSDavid du Colombier 	memmove(db, s, len);
14779ef1f84bSDavid du Colombier 	free(s);
14789ef1f84bSDavid du Colombier 	return len;
14799ef1f84bSDavid du Colombier }
14809ef1f84bSDavid du Colombier 
14819ef1f84bSDavid du Colombier static int getmtu(Chan*);
14829ef1f84bSDavid du Colombier 
14839ef1f84bSDavid du Colombier static int
devmaxdata(Aoedev * d)14849ef1f84bSDavid du Colombier devmaxdata(Aoedev *d)		/* return aoe mtu (excluding headers) */
14859ef1f84bSDavid du Colombier {
14869ef1f84bSDavid du Colombier 	int i, nmtu, mtu;
14879ef1f84bSDavid du Colombier 	Devlink *l;
14889ef1f84bSDavid du Colombier 	Netlink *n;
14899ef1f84bSDavid du Colombier 
14909ef1f84bSDavid du Colombier 	mtu = 100000;
14919ef1f84bSDavid du Colombier 	for(i = 0; i < d->ndl; i++){
14929ef1f84bSDavid du Colombier 		l = d->dl + i;
14939ef1f84bSDavid du Colombier 		n = l->nl;
14949ef1f84bSDavid du Colombier 		if((l->flag & Dup) == 0 || (n->flag & Dup) == 0)
14959ef1f84bSDavid du Colombier 			continue;
14969ef1f84bSDavid du Colombier 		nmtu = getmtu(n->mtu);
14979ef1f84bSDavid du Colombier 		if(mtu > nmtu)
14989ef1f84bSDavid du Colombier 			mtu = nmtu;
14999ef1f84bSDavid du Colombier 	}
15009ef1f84bSDavid du Colombier 	if(mtu == 100000)
15019ef1f84bSDavid du Colombier 		mtu = ETHERMAXTU;		/* normal ethernet mtu */
15029ef1f84bSDavid du Colombier 	mtu -= AOEATASZ;
15039ef1f84bSDavid du Colombier 	mtu -= (uint)mtu % Aoesectsz;
15049ef1f84bSDavid du Colombier 	if(mtu < 2*Aoesectsz)			/* sanity */
15059ef1f84bSDavid du Colombier 		mtu = 2*Aoesectsz;
15069ef1f84bSDavid du Colombier 	return mtu;
15079ef1f84bSDavid du Colombier }
15089ef1f84bSDavid du Colombier 
15099ef1f84bSDavid du Colombier static int
toggle(char * s,int f,int bit)15109ef1f84bSDavid du Colombier toggle(char *s, int f, int bit)
15119ef1f84bSDavid du Colombier {
15129ef1f84bSDavid du Colombier 	if(s == nil)
15139ef1f84bSDavid du Colombier 		f ^= bit;
15149ef1f84bSDavid du Colombier 	else if(strcmp(s, "on") == 0)
15159ef1f84bSDavid du Colombier 		f |= bit;
15169ef1f84bSDavid du Colombier 	else
15179ef1f84bSDavid du Colombier 		f &= ~bit;
15189ef1f84bSDavid du Colombier 	return f;
15199ef1f84bSDavid du Colombier }
15209ef1f84bSDavid du Colombier 
15219ef1f84bSDavid du Colombier static void ataident(Aoedev*);
15229ef1f84bSDavid du Colombier 
15239ef1f84bSDavid du Colombier static long
unitctlwrite(Aoedev * d,void * db,long n)15249ef1f84bSDavid du Colombier unitctlwrite(Aoedev *d, void *db, long n)
15259ef1f84bSDavid du Colombier {
15269ef1f84bSDavid du Colombier 	uint maxbcnt, mtu;
15279ef1f84bSDavid du Colombier 	uvlong bsize;
15289ef1f84bSDavid du Colombier 	enum {
15299ef1f84bSDavid du Colombier 		Failio,
15309ef1f84bSDavid du Colombier 		Ident,
15319ef1f84bSDavid du Colombier 		Jumbo,
15329ef1f84bSDavid du Colombier 		Maxbno,
15339ef1f84bSDavid du Colombier 		Mtu,
15349ef1f84bSDavid du Colombier 		Nofailf,
15359ef1f84bSDavid du Colombier 		Setsize,
15369ef1f84bSDavid du Colombier 	};
15379ef1f84bSDavid du Colombier 	Cmdbuf *cb;
15389ef1f84bSDavid du Colombier 	Cmdtab *ct;
15399ef1f84bSDavid du Colombier 	static Cmdtab cmds[] = {
15409ef1f84bSDavid du Colombier 		{Failio, 	"failio", 	1 },
15419ef1f84bSDavid du Colombier 		{Ident, 	"identify", 	1 },
15429ef1f84bSDavid du Colombier 		{Jumbo, 	"jumbo", 	0 },
15439ef1f84bSDavid du Colombier 		{Maxbno,	"maxbno",	0 },
15449ef1f84bSDavid du Colombier 		{Mtu,		"mtu",		0 },
15459ef1f84bSDavid du Colombier 		{Nofailf,	"nofail",	0 },
15469ef1f84bSDavid du Colombier 		{Setsize, 	"setsize", 	0 },
15479ef1f84bSDavid du Colombier 	};
15489ef1f84bSDavid du Colombier 
15499ef1f84bSDavid du Colombier 	cb = parsecmd(db, n);
15509ef1f84bSDavid du Colombier 	qlock(d);
15519ef1f84bSDavid du Colombier 	if(waserror()){
15529ef1f84bSDavid du Colombier 		qunlock(d);
15539ef1f84bSDavid du Colombier 		free(cb);
15549ef1f84bSDavid du Colombier 		nexterror();
15559ef1f84bSDavid du Colombier 	}
15569ef1f84bSDavid du Colombier 	ct = lookupcmd(cb, cmds, nelem(cmds));
15579ef1f84bSDavid du Colombier 	switch(ct->index){
15589ef1f84bSDavid du Colombier 	case Failio:
15599ef1f84bSDavid du Colombier 		downdev(d, "i/o failure");
15609ef1f84bSDavid du Colombier 		break;
15619ef1f84bSDavid du Colombier 	case Ident:
15629ef1f84bSDavid du Colombier 		ataident(d);
15639ef1f84bSDavid du Colombier 		break;
15649ef1f84bSDavid du Colombier 	case Jumbo:
15659ef1f84bSDavid du Colombier 		d->flag = toggle(cb->f[1], d->flag, Djumbo);
15669ef1f84bSDavid du Colombier 		break;
15679ef1f84bSDavid du Colombier 	case Maxbno:
15689ef1f84bSDavid du Colombier 	case Mtu:
15699ef1f84bSDavid du Colombier 		maxbcnt = devmaxdata(d);
15709ef1f84bSDavid du Colombier 		if(cb->nf > 2)
15719ef1f84bSDavid du Colombier 			error(Ecmdargs);
15729ef1f84bSDavid du Colombier 		if(cb->nf == 2){
15739ef1f84bSDavid du Colombier 			mtu = strtoul(cb->f[1], 0, 0);
15749ef1f84bSDavid du Colombier 			if(ct->index == Maxbno)
15759ef1f84bSDavid du Colombier 				mtu *= Aoesectsz;
15769ef1f84bSDavid du Colombier 			else{
15779ef1f84bSDavid du Colombier 				mtu -= AOEATASZ;
15789ef1f84bSDavid du Colombier 				mtu &= ~(Aoesectsz-1);
15799ef1f84bSDavid du Colombier 			}
15809ef1f84bSDavid du Colombier 			if(mtu == 0 || mtu > maxbcnt)
15819ef1f84bSDavid du Colombier 				cmderror(cb, "mtu out of legal range");
15829ef1f84bSDavid du Colombier 			maxbcnt = mtu;
15839ef1f84bSDavid du Colombier 		}
15849ef1f84bSDavid du Colombier 		d->maxbcnt = maxbcnt;
15859ef1f84bSDavid du Colombier 		break;
15869ef1f84bSDavid du Colombier 	case Nofailf:
15879ef1f84bSDavid du Colombier 		d->flag = toggle(cb->f[1], d->flag, Dnofail);
15889ef1f84bSDavid du Colombier 		break;
15899ef1f84bSDavid du Colombier 	case Setsize:
15909ef1f84bSDavid du Colombier 		bsize = d->realbsize;
15919ef1f84bSDavid du Colombier 		if(cb->nf > 2)
15929ef1f84bSDavid du Colombier 			error(Ecmdargs);
15939ef1f84bSDavid du Colombier 		if(cb->nf == 2){
15949ef1f84bSDavid du Colombier 			bsize = strtoull(cb->f[1], 0, 0);
15959ef1f84bSDavid du Colombier 			if(bsize % Aoesectsz)
15969ef1f84bSDavid du Colombier 				cmderror(cb, "disk size must be sector aligned");
15979ef1f84bSDavid du Colombier 		}
15989ef1f84bSDavid du Colombier 		d->bsize = bsize;
15999ef1f84bSDavid du Colombier 		break;
16009ef1f84bSDavid du Colombier 	default:
16019ef1f84bSDavid du Colombier 		cmderror(cb, "unknown aoe control message");
16029ef1f84bSDavid du Colombier 	}
16039ef1f84bSDavid du Colombier 	poperror();
16049ef1f84bSDavid du Colombier 	qunlock(d);
16059ef1f84bSDavid du Colombier 	free(cb);
16069ef1f84bSDavid du Colombier 	return n;
16079ef1f84bSDavid du Colombier }
16089ef1f84bSDavid du Colombier 
16099ef1f84bSDavid du Colombier static long
unitwrite(Chan * c,void * db,long n,vlong off)16109ef1f84bSDavid du Colombier unitwrite(Chan *c, void *db, long n, vlong off)
16119ef1f84bSDavid du Colombier {
16129ef1f84bSDavid du Colombier 	long rv;
16139ef1f84bSDavid du Colombier 	char *buf;
16149ef1f84bSDavid du Colombier 	Aoedev *d;
16159ef1f84bSDavid du Colombier 
16169ef1f84bSDavid du Colombier 	d = unit2dev(UNIT(c->qid));
16179ef1f84bSDavid du Colombier 	switch(TYPE(c->qid)){
16189ef1f84bSDavid du Colombier 	default:
16199ef1f84bSDavid du Colombier 		error(Ebadarg);
16209ef1f84bSDavid du Colombier 	case Qctl:
16219ef1f84bSDavid du Colombier 		return unitctlwrite(d, db, n);
16229ef1f84bSDavid du Colombier 	case Qident:
16239ef1f84bSDavid du Colombier 		error(Eperm);
16249ef1f84bSDavid du Colombier 	case Qdata:
16259ef1f84bSDavid du Colombier 		return rw(d, Write, db, n, off);
16269ef1f84bSDavid du Colombier 	case Qconfig:
16279ef1f84bSDavid du Colombier 		if(off + n > sizeof d->config)
16289ef1f84bSDavid du Colombier 			error(Etoobig);
16299ef1f84bSDavid du Colombier 		buf = malloc(sizeof d->config);
16309ef1f84bSDavid du Colombier 		if(buf == nil)
16319ef1f84bSDavid du Colombier 			error(Enomem);
16329ef1f84bSDavid du Colombier 		if(waserror()){
16339ef1f84bSDavid du Colombier 			free(buf);
16349ef1f84bSDavid du Colombier 			nexterror();
16359ef1f84bSDavid du Colombier 		}
16369ef1f84bSDavid du Colombier 		memmove(buf, d->config, d->nconfig);
16379ef1f84bSDavid du Colombier 		memmove(buf + off, db, n);
16389ef1f84bSDavid du Colombier 		rv = configwrite(d, buf, n + off);
16399ef1f84bSDavid du Colombier 		poperror();
16409ef1f84bSDavid du Colombier 		free(buf);
16419ef1f84bSDavid du Colombier 		return rv;
16429ef1f84bSDavid du Colombier 	}
16439ef1f84bSDavid du Colombier }
16449ef1f84bSDavid du Colombier 
16459ef1f84bSDavid du Colombier static Netlink*
addnet(char * path,Chan * cc,Chan * dc,Chan * mtu,uchar * ea)16469ef1f84bSDavid du Colombier addnet(char *path, Chan *cc, Chan *dc, Chan *mtu, uchar *ea)
16479ef1f84bSDavid du Colombier {
16489ef1f84bSDavid du Colombier 	Netlink *nl, *e;
16499ef1f84bSDavid du Colombier 
16509ef1f84bSDavid du Colombier 	lock(&netlinks);
16519ef1f84bSDavid du Colombier 	if(waserror()){
16529ef1f84bSDavid du Colombier 		unlock(&netlinks);
16539ef1f84bSDavid du Colombier 		nexterror();
16549ef1f84bSDavid du Colombier 	}
16559ef1f84bSDavid du Colombier 	nl = netlinks.nl;
16569ef1f84bSDavid du Colombier 	e = nl + nelem(netlinks.nl);
16579ef1f84bSDavid du Colombier 	for(; nl < e && nl->cc; nl++)
16589ef1f84bSDavid du Colombier 		continue;
16599ef1f84bSDavid du Colombier 	if (nl >= e)
16609ef1f84bSDavid du Colombier 		error("out of netlink structures");
16619ef1f84bSDavid du Colombier 	nl->cc = cc;
16629ef1f84bSDavid du Colombier 	nl->dc = dc;
16639ef1f84bSDavid du Colombier 	nl->mtu = mtu;
16649ef1f84bSDavid du Colombier 	strncpy(nl->path, path, sizeof nl->path);
16659ef1f84bSDavid du Colombier 	memmove(nl->ea, ea, sizeof nl->ea);
16669ef1f84bSDavid du Colombier 	poperror();
16679ef1f84bSDavid du Colombier 	nl->flag |= Dup;
16689ef1f84bSDavid du Colombier 	unlock(&netlinks);
16699ef1f84bSDavid du Colombier 	return nl;
16709ef1f84bSDavid du Colombier }
16719ef1f84bSDavid du Colombier 
16729ef1f84bSDavid du Colombier static int
newunit(void)16739ef1f84bSDavid du Colombier newunit(void)
16749ef1f84bSDavid du Colombier {
16759ef1f84bSDavid du Colombier 	int x;
16769ef1f84bSDavid du Colombier 
16779ef1f84bSDavid du Colombier 	lock(&units);
16789ef1f84bSDavid du Colombier 	if(units.ref == Maxunits)
16799ef1f84bSDavid du Colombier 		x = -1;
16809ef1f84bSDavid du Colombier 	else
16819ef1f84bSDavid du Colombier 		x = units.ref++;
16829ef1f84bSDavid du Colombier 	unlock(&units);
16839ef1f84bSDavid du Colombier 	return x;
16849ef1f84bSDavid du Colombier }
16859ef1f84bSDavid du Colombier 
16869ef1f84bSDavid du Colombier static int
dropunit(void)16879ef1f84bSDavid du Colombier dropunit(void)
16889ef1f84bSDavid du Colombier {
16899ef1f84bSDavid du Colombier 	int x;
16909ef1f84bSDavid du Colombier 
16919ef1f84bSDavid du Colombier 	lock(&units);
16929ef1f84bSDavid du Colombier 	x = --units.ref;
16939ef1f84bSDavid du Colombier 	unlock(&units);
16949ef1f84bSDavid du Colombier 	return x;
16959ef1f84bSDavid du Colombier }
16969ef1f84bSDavid du Colombier 
16979ef1f84bSDavid du Colombier /*
16989ef1f84bSDavid du Colombier  * always allocate max frames.  maxout may change.
16999ef1f84bSDavid du Colombier  */
17009ef1f84bSDavid du Colombier static Aoedev*
newdev(long major,long minor,int n)17019ef1f84bSDavid du Colombier newdev(long major, long minor, int n)
17029ef1f84bSDavid du Colombier {
17039ef1f84bSDavid du Colombier 	Aoedev *d;
17049ef1f84bSDavid du Colombier 	Frame *f, *e;
17059ef1f84bSDavid du Colombier 
17069ef1f84bSDavid du Colombier 	d = mallocz(sizeof *d, 1);
17079ef1f84bSDavid du Colombier 	f = mallocz(sizeof *f * Maxframes, 1);
17089ef1f84bSDavid du Colombier 	if (!d || !f) {
17099ef1f84bSDavid du Colombier 		free(d);
17109ef1f84bSDavid du Colombier 		free(f);
17119ef1f84bSDavid du Colombier 		error("aoe device allocation failure");
17129ef1f84bSDavid du Colombier 	}
17139ef1f84bSDavid du Colombier 	d->nframes = n;
17149ef1f84bSDavid du Colombier 	d->frames = f;
17159ef1f84bSDavid du Colombier 	for (e = f + n; f < e; f++)
17169ef1f84bSDavid du Colombier 		f->tag = Tfree;
17179ef1f84bSDavid du Colombier 	d->maxout = n;
17189ef1f84bSDavid du Colombier 	d->major = major;
17199ef1f84bSDavid du Colombier 	d->minor = minor;
17209ef1f84bSDavid du Colombier 	d->maxbcnt = Dbcnt;
17219ef1f84bSDavid du Colombier 	d->flag = Djumbo;
17229ef1f84bSDavid du Colombier 	d->unit = newunit();		/* bzzt.  inaccurate if units removed */
17239ef1f84bSDavid du Colombier 	if(d->unit == -1){
17249ef1f84bSDavid du Colombier 		free(d->frames);
1725406c76faSDavid du Colombier 		free(d);
17269ef1f84bSDavid du Colombier 		error("too many units");
17279ef1f84bSDavid du Colombier 	}
17289ef1f84bSDavid du Colombier 	d->dl = d->dltab;
17299ef1f84bSDavid du Colombier 	return d;
17309ef1f84bSDavid du Colombier }
17319ef1f84bSDavid du Colombier 
17329ef1f84bSDavid du Colombier static Aoedev*
mm2dev(int major,int minor)17339ef1f84bSDavid du Colombier mm2dev(int major, int minor)
17349ef1f84bSDavid du Colombier {
17359ef1f84bSDavid du Colombier 	Aoedev *d;
17369ef1f84bSDavid du Colombier 
17379ef1f84bSDavid du Colombier 	rlock(&devs);
17389ef1f84bSDavid du Colombier 	for(d = devs.d; d; d = d->next)
17399ef1f84bSDavid du Colombier 		if(d->major == major && d->minor == minor){
17409ef1f84bSDavid du Colombier 			runlock(&devs);
17419ef1f84bSDavid du Colombier 			return d;
17429ef1f84bSDavid du Colombier 		}
17439ef1f84bSDavid du Colombier 	runlock(&devs);
17449ef1f84bSDavid du Colombier 	eventlog("mm2dev: %d.%d not found\n", major, minor);
17459ef1f84bSDavid du Colombier 	return nil;
17469ef1f84bSDavid du Colombier }
17479ef1f84bSDavid du Colombier 
17489ef1f84bSDavid du Colombier /* Find the device in our list.  If not known, add it */
17499ef1f84bSDavid du Colombier static Aoedev*
getdev(long major,long minor,int n)17509ef1f84bSDavid du Colombier getdev(long major, long minor, int n)
17519ef1f84bSDavid du Colombier {
17529ef1f84bSDavid du Colombier 	Aoedev *d;
17539ef1f84bSDavid du Colombier 
17549ef1f84bSDavid du Colombier 	if(major == 0xffff || minor == 0xff)
17559ef1f84bSDavid du Colombier 		return 0;
17569ef1f84bSDavid du Colombier 	wlock(&devs);
17579ef1f84bSDavid du Colombier 	if(waserror()){
17589ef1f84bSDavid du Colombier 		wunlock(&devs);
17599ef1f84bSDavid du Colombier 		nexterror();
17609ef1f84bSDavid du Colombier 	}
17619ef1f84bSDavid du Colombier 	for(d = devs.d; d; d = d->next)
17629ef1f84bSDavid du Colombier 		if(d->major == major && d->minor == minor)
17639ef1f84bSDavid du Colombier 			break;
17649ef1f84bSDavid du Colombier 	if (d == nil) {
17659ef1f84bSDavid du Colombier 		d = newdev(major, minor, n);
17669ef1f84bSDavid du Colombier 		d->next = devs.d;
17679ef1f84bSDavid du Colombier 		devs.d = d;
17689ef1f84bSDavid du Colombier 	}
17699ef1f84bSDavid du Colombier 	poperror();
17709ef1f84bSDavid du Colombier 	wunlock(&devs);
17719ef1f84bSDavid du Colombier 	return d;
17729ef1f84bSDavid du Colombier }
17739ef1f84bSDavid du Colombier 
17749ef1f84bSDavid du Colombier static ushort
gbit16(void * a)17759ef1f84bSDavid du Colombier gbit16(void *a)
17769ef1f84bSDavid du Colombier {
17779ef1f84bSDavid du Colombier 	uchar *i;
17789ef1f84bSDavid du Colombier 
17799ef1f84bSDavid du Colombier 	i = a;
17809ef1f84bSDavid du Colombier 	return i[1] << 8 | i[0];
17819ef1f84bSDavid du Colombier }
17829ef1f84bSDavid du Colombier 
17839ef1f84bSDavid du Colombier static ulong
gbit32(void * a)17849ef1f84bSDavid du Colombier gbit32(void *a)
17859ef1f84bSDavid du Colombier {
17869ef1f84bSDavid du Colombier 	ulong j;
17879ef1f84bSDavid du Colombier 	uchar *i;
17889ef1f84bSDavid du Colombier 
17899ef1f84bSDavid du Colombier 	i = a;
17909ef1f84bSDavid du Colombier 	j  = i[3] << 24;
17919ef1f84bSDavid du Colombier 	j |= i[2] << 16;
17929ef1f84bSDavid du Colombier 	j |= i[1] << 8;
17939ef1f84bSDavid du Colombier 	j |= i[0];
17949ef1f84bSDavid du Colombier 	return j;
17959ef1f84bSDavid du Colombier }
17969ef1f84bSDavid du Colombier 
17979ef1f84bSDavid du Colombier static uvlong
gbit64(void * a)17989ef1f84bSDavid du Colombier gbit64(void *a)
17999ef1f84bSDavid du Colombier {
18009ef1f84bSDavid du Colombier 	uchar *i;
18019ef1f84bSDavid du Colombier 
18029ef1f84bSDavid du Colombier 	i = a;
18039ef1f84bSDavid du Colombier 	return (uvlong)gbit32(i+4) << 32 | gbit32(a);
18049ef1f84bSDavid du Colombier }
18059ef1f84bSDavid du Colombier 
18069ef1f84bSDavid du Colombier static void
ataident(Aoedev * d)18079ef1f84bSDavid du Colombier ataident(Aoedev *d)
18089ef1f84bSDavid du Colombier {
18099ef1f84bSDavid du Colombier 	Aoeata *a;
18109ef1f84bSDavid du Colombier 	Block *b;
18119ef1f84bSDavid du Colombier 	Frame *f;
18129ef1f84bSDavid du Colombier 
18139ef1f84bSDavid du Colombier 	f = freeframe(d);
18149ef1f84bSDavid du Colombier 	if(f == nil)
18159ef1f84bSDavid du Colombier 		return;
18169ef1f84bSDavid du Colombier 	f->nhdr = AOEATASZ;
18179ef1f84bSDavid du Colombier 	memset(f->hdr, 0, f->nhdr);
18189ef1f84bSDavid du Colombier 	a = (Aoeata*)f->hdr;
18199ef1f84bSDavid du Colombier 	if(hset(d, f, a, ACata) == -1)
18209ef1f84bSDavid du Colombier 		return;
18219ef1f84bSDavid du Colombier 	a->cmdstat = Cid;	/* ata 6, page 110 */
18229ef1f84bSDavid du Colombier 	a->scnt = 1;
18239ef1f84bSDavid du Colombier 	a->lba[3] = 0xa0;
18249ef1f84bSDavid du Colombier 	d->nout++;
18259ef1f84bSDavid du Colombier 	f->dl->npkt++;
18269ef1f84bSDavid du Colombier 	f->bcnt = 512;
18279ef1f84bSDavid du Colombier 	f->dlen = 0;
18289ef1f84bSDavid du Colombier 	b = allocfb(f);
18299ef1f84bSDavid du Colombier 	f->nl->dc->dev->bwrite(f->nl->dc, b, 0);
18309ef1f84bSDavid du Colombier }
18319ef1f84bSDavid du Colombier 
18329ef1f84bSDavid du Colombier static int
getmtu(Chan * mtuch)18339ef1f84bSDavid du Colombier getmtu(Chan *mtuch)
18349ef1f84bSDavid du Colombier {
18359ef1f84bSDavid du Colombier 	int n, mtu;
18369ef1f84bSDavid du Colombier 	char buf[36];
18379ef1f84bSDavid du Colombier 
18389ef1f84bSDavid du Colombier 	mtu = ETHERMAXTU;
18399ef1f84bSDavid du Colombier 	if(mtuch == nil || waserror())
18409ef1f84bSDavid du Colombier 		return mtu;
18419ef1f84bSDavid du Colombier 	n = mtuch->dev->read(mtuch, buf, sizeof buf - 1, 0);
18429ef1f84bSDavid du Colombier 	if(n > 12){
18439ef1f84bSDavid du Colombier 		buf[n] = 0;
18449ef1f84bSDavid du Colombier 		mtu = strtoul(buf + 12, 0, 0);
18459ef1f84bSDavid du Colombier 	}
18469ef1f84bSDavid du Colombier 	poperror();
18479ef1f84bSDavid du Colombier 	return mtu;
18489ef1f84bSDavid du Colombier }
18499ef1f84bSDavid du Colombier 
18509ef1f84bSDavid du Colombier static int
newdlea(Devlink * l,uchar * ea)18519ef1f84bSDavid du Colombier newdlea(Devlink *l, uchar *ea)
18529ef1f84bSDavid du Colombier {
18539ef1f84bSDavid du Colombier 	int i;
18549ef1f84bSDavid du Colombier 	uchar *t;
18559ef1f84bSDavid du Colombier 
18569ef1f84bSDavid du Colombier 	for(i = 0; i < Nea; i++){
18579ef1f84bSDavid du Colombier 		t = l->eatab[i];
18589ef1f84bSDavid du Colombier 		if(i == l->nea){
18599ef1f84bSDavid du Colombier 			memmove(t, ea, Eaddrlen);
18609ef1f84bSDavid du Colombier 			return l->nea++;
18619ef1f84bSDavid du Colombier 		}
18629ef1f84bSDavid du Colombier 		if(memcmp(t, ea, Eaddrlen) == 0)
18639ef1f84bSDavid du Colombier 			return i;
18649ef1f84bSDavid du Colombier 	}
18659ef1f84bSDavid du Colombier 	return -1;
18669ef1f84bSDavid du Colombier }
18679ef1f84bSDavid du Colombier 
18689ef1f84bSDavid du Colombier static Devlink*
newdevlink(Aoedev * d,Netlink * n,Aoeqc * c)18699ef1f84bSDavid du Colombier newdevlink(Aoedev *d, Netlink *n, Aoeqc *c)
18709ef1f84bSDavid du Colombier {
18719ef1f84bSDavid du Colombier 	int i;
18729ef1f84bSDavid du Colombier 	Devlink *l;
18739ef1f84bSDavid du Colombier 
18749ef1f84bSDavid du Colombier 	for(i = 0; i < Ndevlink; i++){
18759ef1f84bSDavid du Colombier 		l = d->dl + i;
18769ef1f84bSDavid du Colombier 		if(i == d->ndl){
18779ef1f84bSDavid du Colombier 			d->ndl++;
18789ef1f84bSDavid du Colombier 			newdlea(l, c->src);
18799ef1f84bSDavid du Colombier 			l->nl = n;
18809ef1f84bSDavid du Colombier 			l->flag |= Dup;
18819ef1f84bSDavid du Colombier 			l->mintimer = Rtmin;
18829ef1f84bSDavid du Colombier 			l->rttavg = Rtmax;
18839ef1f84bSDavid du Colombier 			return l;
18849ef1f84bSDavid du Colombier 		}
18859ef1f84bSDavid du Colombier 		if(l->nl == n) {
18869ef1f84bSDavid du Colombier 			newdlea(l, c->src);
18879ef1f84bSDavid du Colombier 			l->flag |= Dup;
18889ef1f84bSDavid du Colombier 			return l;
18899ef1f84bSDavid du Colombier 		}
18909ef1f84bSDavid du Colombier 	}
18919ef1f84bSDavid du Colombier 	eventlog("%æ: out of links: %s:%E to %E\n", d, n->path, n->ea, c->src);
18929ef1f84bSDavid du Colombier 	return 0;
18939ef1f84bSDavid du Colombier }
18949ef1f84bSDavid du Colombier 
18959ef1f84bSDavid du Colombier static void
errrsp(Block * b,char * s)18969ef1f84bSDavid du Colombier errrsp(Block *b, char *s)
18979ef1f84bSDavid du Colombier {
18989ef1f84bSDavid du Colombier 	int n;
18999ef1f84bSDavid du Colombier 	Aoedev *d;
19009ef1f84bSDavid du Colombier 	Aoehdr *h;
19019ef1f84bSDavid du Colombier 	Frame *f;
19029ef1f84bSDavid du Colombier 
19039ef1f84bSDavid du Colombier 	h = (Aoehdr*)b->rp;
19049ef1f84bSDavid du Colombier 	n = nhgetl(h->tag);
19059ef1f84bSDavid du Colombier 	if(n == Tmgmt || n == Tfree)
19069ef1f84bSDavid du Colombier 		return;
19079ef1f84bSDavid du Colombier 	d = mm2dev(nhgets(h->major), h->minor);
19089ef1f84bSDavid du Colombier 	if(d == 0)
19099ef1f84bSDavid du Colombier 		return;
19109ef1f84bSDavid du Colombier 	if(f = getframe(d, n))
19119ef1f84bSDavid du Colombier 		frameerror(d, f, s);
19129ef1f84bSDavid du Colombier }
19139ef1f84bSDavid du Colombier 
19149ef1f84bSDavid du Colombier static void
qcfgrsp(Block * b,Netlink * nl)19159ef1f84bSDavid du Colombier qcfgrsp(Block *b, Netlink *nl)
19169ef1f84bSDavid du Colombier {
19179ef1f84bSDavid du Colombier 	int major, cmd, cslen, blen;
19189ef1f84bSDavid du Colombier 	unsigned n;
19199ef1f84bSDavid du Colombier 	Aoedev *d;
19209ef1f84bSDavid du Colombier 	Aoeqc *ch;
19219ef1f84bSDavid du Colombier 	Devlink *l;
19229ef1f84bSDavid du Colombier 	Frame *f;
19239ef1f84bSDavid du Colombier 
19249ef1f84bSDavid du Colombier 	ch = (Aoeqc*)b->rp;
19259ef1f84bSDavid du Colombier 	major = nhgets(ch->major);
19269ef1f84bSDavid du Colombier 	n = nhgetl(ch->tag);
19279ef1f84bSDavid du Colombier 	if(n != Tmgmt){
19289ef1f84bSDavid du Colombier 		d = mm2dev(major, ch->minor);
19299ef1f84bSDavid du Colombier 		if(d == nil)
19309ef1f84bSDavid du Colombier 			return;
19319ef1f84bSDavid du Colombier 		qlock(d);
19329ef1f84bSDavid du Colombier 		f = getframe(d, n);
19339ef1f84bSDavid du Colombier 		if(f == nil){
19349ef1f84bSDavid du Colombier 			qunlock(d);
19359ef1f84bSDavid du Colombier 			eventlog("%æ: unknown response tag %#ux\n", d, n);
19369ef1f84bSDavid du Colombier 			return;
19379ef1f84bSDavid du Colombier 		}
19389ef1f84bSDavid du Colombier 		cslen = nhgets(ch->cslen);
19399ef1f84bSDavid du Colombier 		blen = BLEN(b) - AOEQCSZ;
19409ef1f84bSDavid du Colombier 		if(cslen < blen && BLEN(b) > 60)
19419ef1f84bSDavid du Colombier 			eventlog("%æ: cfgrsp: tag %.8ux oversized %d %d\n",
19429ef1f84bSDavid du Colombier 				d, n, cslen, blen);
19439ef1f84bSDavid du Colombier 		if(cslen > blen){
19449ef1f84bSDavid du Colombier 			eventlog("%æ: cfgrsp: tag %.8ux runt %d %d\n",
19459ef1f84bSDavid du Colombier 				d, n, cslen, blen);
19469ef1f84bSDavid du Colombier 			cslen = blen;
19479ef1f84bSDavid du Colombier 		}
19489ef1f84bSDavid du Colombier 		memmove(f->dp, ch + 1, cslen);
19499ef1f84bSDavid du Colombier 		f->srb->nout--;
19509ef1f84bSDavid du Colombier 		wakeup(f->srb);
1951406c76faSDavid du Colombier 		f->srb->shared = 0;
19529ef1f84bSDavid du Colombier 		d->nout--;
19539ef1f84bSDavid du Colombier 		f->srb = nil;
19549ef1f84bSDavid du Colombier 		f->tag = Tfree;
19559ef1f84bSDavid du Colombier 		qunlock(d);
19569ef1f84bSDavid du Colombier 		return;
19579ef1f84bSDavid du Colombier 	}
19589ef1f84bSDavid du Colombier 
19599ef1f84bSDavid du Colombier 	cmd = ch->verccmd & 0xf;
19609ef1f84bSDavid du Colombier 	if(cmd != 0){
19619ef1f84bSDavid du Colombier 		eventlog("aoe%d.%d: cfgrsp: bad command %d\n", major, ch->minor, cmd);
19629ef1f84bSDavid du Colombier 		return;
19639ef1f84bSDavid du Colombier 	}
19649ef1f84bSDavid du Colombier 	n = nhgets(ch->bufcnt);
19659ef1f84bSDavid du Colombier 	if(n > Maxframes)
19669ef1f84bSDavid du Colombier 		n = Maxframes;
19679ef1f84bSDavid du Colombier 
19689ef1f84bSDavid du Colombier 	if(waserror()){
19699ef1f84bSDavid du Colombier 		eventlog("getdev: %d.%d ignored: %s\n", major, ch->minor, up->errstr);
19709ef1f84bSDavid du Colombier 		return;
19719ef1f84bSDavid du Colombier 	}
19729ef1f84bSDavid du Colombier 	d = getdev(major, ch->minor, n);
19739ef1f84bSDavid du Colombier 	poperror();
19749ef1f84bSDavid du Colombier 	if(d == 0)
19759ef1f84bSDavid du Colombier 		return;
19769ef1f84bSDavid du Colombier 
19779ef1f84bSDavid du Colombier 	qlock(d);
19789ef1f84bSDavid du Colombier 	*up->errstr = 0;
19799ef1f84bSDavid du Colombier 	if(waserror()){
19809ef1f84bSDavid du Colombier 		qunlock(d);
19819ef1f84bSDavid du Colombier 		eventlog("%æ: %s\n", d, up->errstr);
19829ef1f84bSDavid du Colombier 		nexterror();
19839ef1f84bSDavid du Colombier 	}
19849ef1f84bSDavid du Colombier 
19859ef1f84bSDavid du Colombier 	l = newdevlink(d, nl, ch);		/* add this interface. */
19869ef1f84bSDavid du Colombier 
19879ef1f84bSDavid du Colombier 	d->fwver = nhgets(ch->fwver);
19889ef1f84bSDavid du Colombier 	n = nhgets(ch->cslen);
19899ef1f84bSDavid du Colombier 	if(n > sizeof d->config)
19909ef1f84bSDavid du Colombier 		n = sizeof d->config;
19919ef1f84bSDavid du Colombier 	d->nconfig = n;
19929ef1f84bSDavid du Colombier 	memmove(d->config, ch + 1, n);
19939ef1f84bSDavid du Colombier 	if(l != 0 && d->flag & Djumbo){
19949ef1f84bSDavid du Colombier 		n = getmtu(nl->mtu) - AOEATASZ;
19959ef1f84bSDavid du Colombier 		n /= Aoesectsz;
19969ef1f84bSDavid du Colombier 		if(n > ch->scnt)
19979ef1f84bSDavid du Colombier 			n = ch->scnt;
19989ef1f84bSDavid du Colombier 		n = n? n * Aoesectsz: Dbcnt;
19999ef1f84bSDavid du Colombier 		if(n != d->maxbcnt){
20009ef1f84bSDavid du Colombier 			eventlog("%æ: setting %d byte data frames on %s:%E\n",
20019ef1f84bSDavid du Colombier 				d, n, nl->path, nl->ea);
20029ef1f84bSDavid du Colombier 			d->maxbcnt = n;
20039ef1f84bSDavid du Colombier 		}
20049ef1f84bSDavid du Colombier 	}
20059ef1f84bSDavid du Colombier 	if(d->nopen == 0)
20069ef1f84bSDavid du Colombier 		ataident(d);
20079ef1f84bSDavid du Colombier 	poperror();
20089ef1f84bSDavid du Colombier 	qunlock(d);
20099ef1f84bSDavid du Colombier }
20109ef1f84bSDavid du Colombier 
20119ef1f84bSDavid du Colombier void
aoeidmove(char * p,ushort * u,unsigned n)20129ef1f84bSDavid du Colombier aoeidmove(char *p, ushort *u, unsigned n)
20139ef1f84bSDavid du Colombier {
20149ef1f84bSDavid du Colombier 	int i;
20159ef1f84bSDavid du Colombier 	char *op, *e, *s;
20169ef1f84bSDavid du Colombier 
20179ef1f84bSDavid du Colombier 	op = p;
20189ef1f84bSDavid du Colombier 	/*
20199ef1f84bSDavid du Colombier 	 * the ushort `*u' is sometimes not aligned on a short boundary,
20209ef1f84bSDavid du Colombier 	 * so dereferencing u[i] causes an alignment exception on
20219ef1f84bSDavid du Colombier 	 * some machines.
20229ef1f84bSDavid du Colombier 	 */
20239ef1f84bSDavid du Colombier 	s = (char *)u;
20249ef1f84bSDavid du Colombier 	for(i = 0; i < n; i += 2){
20259ef1f84bSDavid du Colombier 		*p++ = s[i + 1];
20269ef1f84bSDavid du Colombier 		*p++ = s[i];
20279ef1f84bSDavid du Colombier 	}
20289ef1f84bSDavid du Colombier 	*p = 0;
20299ef1f84bSDavid du Colombier 	while(p > op && *--p == ' ')
20309ef1f84bSDavid du Colombier 		*p = 0;
20319ef1f84bSDavid du Colombier 	e = p;
20329ef1f84bSDavid du Colombier 	p = op;
20339ef1f84bSDavid du Colombier 	while(*p == ' ')
20349ef1f84bSDavid du Colombier 		p++;
20359ef1f84bSDavid du Colombier 	memmove(op, p, n - (e - p));
20369ef1f84bSDavid du Colombier }
20379ef1f84bSDavid du Colombier 
20389ef1f84bSDavid du Colombier static vlong
aoeidentify(Aoedev * d,ushort * id)20399ef1f84bSDavid du Colombier aoeidentify(Aoedev *d, ushort *id)
20409ef1f84bSDavid du Colombier {
20419ef1f84bSDavid du Colombier 	int i;
20429ef1f84bSDavid du Colombier 	vlong s;
20439ef1f84bSDavid du Colombier 
20449ef1f84bSDavid du Colombier 	d->flag &= ~(Dllba|Dpower|Dsmart|Dnop|Dup);
20459ef1f84bSDavid du Colombier 
20469ef1f84bSDavid du Colombier 	i = gbit16(id+83) | gbit16(id+86);
20479ef1f84bSDavid du Colombier 	if(i & (1<<10)){
20489ef1f84bSDavid du Colombier 		d->flag |= Dllba;
20499ef1f84bSDavid du Colombier 		s = gbit64(id+100);
20509ef1f84bSDavid du Colombier 	}else
20519ef1f84bSDavid du Colombier 		s = gbit32(id+60);
20529ef1f84bSDavid du Colombier 
20539ef1f84bSDavid du Colombier 	i = gbit16(id+83);
20549ef1f84bSDavid du Colombier 	if((i>>14) == 1) {
20559ef1f84bSDavid du Colombier 		if(i & (1<<3))
20569ef1f84bSDavid du Colombier 			d->flag  |= Dpower;
20579ef1f84bSDavid du Colombier 		i = gbit16(id+82);
20589ef1f84bSDavid du Colombier 		if(i & 1)
20599ef1f84bSDavid du Colombier 			d->flag  |= Dsmart;
20609ef1f84bSDavid du Colombier 		if(i & (1<<14))
20619ef1f84bSDavid du Colombier 			d->flag  |= Dnop;
20629ef1f84bSDavid du Colombier 	}
20639ef1f84bSDavid du Colombier //	eventlog("%æ up\n", d);
20649ef1f84bSDavid du Colombier 	d->flag |= Dup;
20659ef1f84bSDavid du Colombier 	memmove(d->ident, id, sizeof d->ident);
20669ef1f84bSDavid du Colombier 	return s;
20679ef1f84bSDavid du Colombier }
20689ef1f84bSDavid du Colombier 
20699ef1f84bSDavid du Colombier static void
newvers(Aoedev * d)20709ef1f84bSDavid du Colombier newvers(Aoedev *d)
20719ef1f84bSDavid du Colombier {
20729ef1f84bSDavid du Colombier 	lock(&drivevers);
20739ef1f84bSDavid du Colombier 	d->vers = drivevers.ref++;
20749ef1f84bSDavid du Colombier 	unlock(&drivevers);
20759ef1f84bSDavid du Colombier }
20769ef1f84bSDavid du Colombier 
20779ef1f84bSDavid du Colombier static int
identify(Aoedev * d,ushort * id)20789ef1f84bSDavid du Colombier identify(Aoedev *d, ushort *id)
20799ef1f84bSDavid du Colombier {
20809ef1f84bSDavid du Colombier 	vlong osectors, s;
20819ef1f84bSDavid du Colombier 	uchar oserial[21];
20829ef1f84bSDavid du Colombier 
20839ef1f84bSDavid du Colombier 	s = aoeidentify(d, id);
20849ef1f84bSDavid du Colombier 	if(s == -1)
20859ef1f84bSDavid du Colombier 		return -1;
20869ef1f84bSDavid du Colombier 	osectors = d->realbsize;
20879ef1f84bSDavid du Colombier 	memmove(oserial, d->serial, sizeof d->serial);
20889ef1f84bSDavid du Colombier 
20899ef1f84bSDavid du Colombier 	aoeidmove(d->serial, id+10, 20);
20909ef1f84bSDavid du Colombier 	aoeidmove(d->firmware, id+23, 8);
20919ef1f84bSDavid du Colombier 	aoeidmove(d->model, id+27, 40);
20929ef1f84bSDavid du Colombier 
20939ef1f84bSDavid du Colombier 	s *= Aoesectsz;
20949ef1f84bSDavid du Colombier 	if((osectors == 0 || osectors != s) &&
20959ef1f84bSDavid du Colombier 	    memcmp(oserial, d->serial, sizeof oserial) != 0){
20969ef1f84bSDavid du Colombier 		d->bsize = s;
20979ef1f84bSDavid du Colombier 		d->realbsize = s;
20989ef1f84bSDavid du Colombier //		d->mediachange = 1;
20999ef1f84bSDavid du Colombier 		newvers(d);
21009ef1f84bSDavid du Colombier 	}
21019ef1f84bSDavid du Colombier 	return 0;
21029ef1f84bSDavid du Colombier }
21039ef1f84bSDavid du Colombier 
21049ef1f84bSDavid du Colombier static void
atarsp(Block * b)21059ef1f84bSDavid du Colombier atarsp(Block *b)
21069ef1f84bSDavid du Colombier {
21079ef1f84bSDavid du Colombier 	unsigned n;
21089ef1f84bSDavid du Colombier 	short major;
21099ef1f84bSDavid du Colombier 	Aoeata *ahin, *ahout;
21109ef1f84bSDavid du Colombier 	Aoedev *d;
21119ef1f84bSDavid du Colombier 	Frame *f;
21129ef1f84bSDavid du Colombier 	Srb *srb;
21139ef1f84bSDavid du Colombier 
21149ef1f84bSDavid du Colombier 	ahin = (Aoeata*)b->rp;
21159ef1f84bSDavid du Colombier 	major = nhgets(ahin->major);
21169ef1f84bSDavid du Colombier 	d = mm2dev(major, ahin->minor);
21179ef1f84bSDavid du Colombier 	if(d == nil)
21189ef1f84bSDavid du Colombier 		return;
21199ef1f84bSDavid du Colombier 	qlock(d);
21209ef1f84bSDavid du Colombier 	if(waserror()){
21219ef1f84bSDavid du Colombier 		qunlock(d);
21229ef1f84bSDavid du Colombier 		nexterror();
21239ef1f84bSDavid du Colombier 	}
21249ef1f84bSDavid du Colombier 	n = nhgetl(ahin->tag);
21259ef1f84bSDavid du Colombier 	f = getframe(d, n);
21269ef1f84bSDavid du Colombier 	if(f == nil){
21279ef1f84bSDavid du Colombier 		dprint("%æ: unexpected response; tag %#ux\n", d, n);
21289ef1f84bSDavid du Colombier 		goto bail;
21299ef1f84bSDavid du Colombier 	}
21309ef1f84bSDavid du Colombier 	rtupdate(f->dl, tsince(f->tag));
21319ef1f84bSDavid du Colombier 	ahout = (Aoeata*)f->hdr;
21329ef1f84bSDavid du Colombier 	srb = f->srb;
21339ef1f84bSDavid du Colombier 
21349ef1f84bSDavid du Colombier 	if(ahin->cmdstat & 0xa9){
21359ef1f84bSDavid du Colombier 		eventlog("%æ: ata error cmd %.2ux stat %.2ux\n",
21369ef1f84bSDavid du Colombier 			d, ahout->cmdstat, ahin->cmdstat);
21379ef1f84bSDavid du Colombier 		if(srb)
21389ef1f84bSDavid du Colombier 			srb->error = Eio;
21399ef1f84bSDavid du Colombier 	} else {
21409ef1f84bSDavid du Colombier 		n = ahout->scnt * Aoesectsz;
21419ef1f84bSDavid du Colombier 		switch(ahout->cmdstat){
21429ef1f84bSDavid du Colombier 		case Crd:
21439ef1f84bSDavid du Colombier 		case Crdext:
21449ef1f84bSDavid du Colombier 			if(BLEN(b) - AOEATASZ < n){
21459ef1f84bSDavid du Colombier 				eventlog("%æ: runt read blen %ld expect %d\n",
21469ef1f84bSDavid du Colombier 					d, BLEN(b), n);
21479ef1f84bSDavid du Colombier 				goto bail;
21489ef1f84bSDavid du Colombier 			}
21499ef1f84bSDavid du Colombier 			memmove(f->dp, (uchar *)ahin + AOEATASZ, n);
21509ef1f84bSDavid du Colombier 		case Cwr:
21519ef1f84bSDavid du Colombier 		case Cwrext:
21529ef1f84bSDavid du Colombier 			if(n > Dbcnt)
21539ef1f84bSDavid du Colombier 				f->nl->lostjumbo = 0;
21549ef1f84bSDavid du Colombier 			if(f->bcnt -= n){
21559ef1f84bSDavid du Colombier 				f->lba += n / Aoesectsz;
21569ef1f84bSDavid du Colombier 				f->dp = (uchar*)f->dp + n;
21579ef1f84bSDavid du Colombier 				resend(d, f);
21589ef1f84bSDavid du Colombier 				goto bail;
21599ef1f84bSDavid du Colombier 			}
21609ef1f84bSDavid du Colombier 			break;
21619ef1f84bSDavid du Colombier 		case Cid:
21629ef1f84bSDavid du Colombier 			if(BLEN(b) - AOEATASZ < 512){
21639ef1f84bSDavid du Colombier 				eventlog("%æ: runt identify blen %ld expect %d\n",
21649ef1f84bSDavid du Colombier 					d, BLEN(b), n);
21659ef1f84bSDavid du Colombier 				goto bail;
21669ef1f84bSDavid du Colombier 			}
21679ef1f84bSDavid du Colombier 			identify(d, (ushort*)((uchar *)ahin + AOEATASZ));
21689ef1f84bSDavid du Colombier 			break;
21699ef1f84bSDavid du Colombier 		default:
21709ef1f84bSDavid du Colombier 			eventlog("%æ: unknown ata command %.2ux \n",
21719ef1f84bSDavid du Colombier 				d, ahout->cmdstat);
21729ef1f84bSDavid du Colombier 		}
21739ef1f84bSDavid du Colombier 	}
21749ef1f84bSDavid du Colombier 
2175406c76faSDavid du Colombier 	if(srb && --srb->nout == 0 && srb->len == 0){
21769ef1f84bSDavid du Colombier 		wakeup(srb);
2177406c76faSDavid du Colombier 		srb->shared = 0;
2178406c76faSDavid du Colombier 	}
21799ef1f84bSDavid du Colombier 	f->srb = nil;
21809ef1f84bSDavid du Colombier 	f->tag = Tfree;
21819ef1f84bSDavid du Colombier 	d->nout--;
21829ef1f84bSDavid du Colombier 
21839ef1f84bSDavid du Colombier 	work(d);
21849ef1f84bSDavid du Colombier bail:
21859ef1f84bSDavid du Colombier 	poperror();
21869ef1f84bSDavid du Colombier 	qunlock(d);
21879ef1f84bSDavid du Colombier }
21889ef1f84bSDavid du Colombier 
21899ef1f84bSDavid du Colombier static void
netrdaoeproc(void * v)21909ef1f84bSDavid du Colombier netrdaoeproc(void *v)
21919ef1f84bSDavid du Colombier {
21929ef1f84bSDavid du Colombier 	int idx;
21939ef1f84bSDavid du Colombier 	char name[Maxpath+1], *s;
21949ef1f84bSDavid du Colombier 	Aoehdr *h;
21959ef1f84bSDavid du Colombier 	Block *b;
21969ef1f84bSDavid du Colombier 	Netlink *nl;
21979ef1f84bSDavid du Colombier 
21989ef1f84bSDavid du Colombier 	nl = (Netlink*)v;
21999ef1f84bSDavid du Colombier 	idx = nl - netlinks.nl;
22009ef1f84bSDavid du Colombier 	netlinks.reader[idx] = 1;
22019ef1f84bSDavid du Colombier 	kstrcpy(name, nl->path, Maxpath);
22029ef1f84bSDavid du Colombier 
22039ef1f84bSDavid du Colombier 	if(waserror()){
22049ef1f84bSDavid du Colombier 		eventlog("netrdaoe exiting: %s\n", up->errstr);
22059ef1f84bSDavid du Colombier 		netlinks.reader[idx] = 0;
22069ef1f84bSDavid du Colombier 		wakeup(netlinks.rendez + idx);
22079ef1f84bSDavid du Colombier 		pexit(up->errstr, 1);
22089ef1f84bSDavid du Colombier 	}
22099ef1f84bSDavid du Colombier 	if(autodiscover)
22109ef1f84bSDavid du Colombier 		discover(0xffff, 0xff);
22119ef1f84bSDavid du Colombier 	for (;;) {
22129ef1f84bSDavid du Colombier 		if(!(nl->flag & Dup)) {
22139ef1f84bSDavid du Colombier 			uprint("%s: netlink is down", name);
22149ef1f84bSDavid du Colombier 			error(up->genbuf);
22159ef1f84bSDavid du Colombier 		}
22169ef1f84bSDavid du Colombier 		if (nl->dc == nil)
22179ef1f84bSDavid du Colombier 			panic("netrdaoe: nl->dc == nil");
22189ef1f84bSDavid du Colombier 		b = nl->dc->dev->bread(nl->dc, 1<<16, 0);
22199ef1f84bSDavid du Colombier 		if(b == nil) {
22209ef1f84bSDavid du Colombier 			uprint("%s: nil read from network", name);
22219ef1f84bSDavid du Colombier 			error(up->genbuf);
22229ef1f84bSDavid du Colombier 		}
22239ef1f84bSDavid du Colombier 		h = (Aoehdr*)b->rp;
22249ef1f84bSDavid du Colombier 		if(h->verflag & AFrsp)
22259ef1f84bSDavid du Colombier 			if(s = aoeerror(h)){
22269ef1f84bSDavid du Colombier 				eventlog("%s: %s\n", nl->path, up->errstr);
22279ef1f84bSDavid du Colombier 				errrsp(b, s);
22289ef1f84bSDavid du Colombier 			}else
22299ef1f84bSDavid du Colombier 				switch(h->cmd){
22309ef1f84bSDavid du Colombier 				case ACata:
22319ef1f84bSDavid du Colombier 					atarsp(b);
22329ef1f84bSDavid du Colombier 					break;
22339ef1f84bSDavid du Colombier 				case ACconfig:
22349ef1f84bSDavid du Colombier 					qcfgrsp(b, nl);
22359ef1f84bSDavid du Colombier 					break;
22369ef1f84bSDavid du Colombier 				default:
22379ef1f84bSDavid du Colombier 					if((h->cmd & 0xf0) == 0){
22389ef1f84bSDavid du Colombier 						eventlog("%s: unknown cmd %d\n",
22399ef1f84bSDavid du Colombier 							nl->path, h->cmd);
22409ef1f84bSDavid du Colombier 						errrsp(b, "unknown command");
22419ef1f84bSDavid du Colombier 					}
22429ef1f84bSDavid du Colombier 					break;
22439ef1f84bSDavid du Colombier 				}
22449ef1f84bSDavid du Colombier 		freeb(b);
22459ef1f84bSDavid du Colombier 	}
22469ef1f84bSDavid du Colombier }
22479ef1f84bSDavid du Colombier 
22489ef1f84bSDavid du Colombier static void
getaddr(char * path,uchar * ea)22499ef1f84bSDavid du Colombier getaddr(char *path, uchar *ea)
22509ef1f84bSDavid du Colombier {
22519ef1f84bSDavid du Colombier 	int n;
22529ef1f84bSDavid du Colombier 	char buf[2*Eaddrlen+1];
22539ef1f84bSDavid du Colombier 	Chan *c;
22549ef1f84bSDavid du Colombier 
22559ef1f84bSDavid du Colombier 	uprint("%s/addr", path);
22569ef1f84bSDavid du Colombier 	c = namec(up->genbuf, Aopen, OREAD, 0);
22579ef1f84bSDavid du Colombier 	if(waserror()) {
22589ef1f84bSDavid du Colombier 		cclose(c);
22599ef1f84bSDavid du Colombier 		nexterror();
22609ef1f84bSDavid du Colombier 	}
22619ef1f84bSDavid du Colombier 	if (c == nil)
22629ef1f84bSDavid du Colombier 		panic("æ: getaddr: c == nil");
22639ef1f84bSDavid du Colombier 	n = c->dev->read(c, buf, sizeof buf-1, 0);
22649ef1f84bSDavid du Colombier 	poperror();
22659ef1f84bSDavid du Colombier 	cclose(c);
22669ef1f84bSDavid du Colombier 	buf[n] = 0;
22679ef1f84bSDavid du Colombier 	if(parseether(ea, buf) < 0)
22689ef1f84bSDavid du Colombier 		error("parseether failure");
22699ef1f84bSDavid du Colombier }
22709ef1f84bSDavid du Colombier 
22719ef1f84bSDavid du Colombier static void
netbind(char * path)22729ef1f84bSDavid du Colombier netbind(char *path)
22739ef1f84bSDavid du Colombier {
22749ef1f84bSDavid du Colombier 	char addr[Maxpath];
22759ef1f84bSDavid du Colombier 	uchar ea[2*Eaddrlen+1];
22769ef1f84bSDavid du Colombier 	Chan *dc, *cc, *mtu;
22779ef1f84bSDavid du Colombier 	Netlink *nl;
22789ef1f84bSDavid du Colombier 
22799ef1f84bSDavid du Colombier 	snprint(addr, sizeof addr, "%s!%#x", path, Aoetype);
22809ef1f84bSDavid du Colombier 	dc = chandial(addr, nil, nil, &cc);
22819ef1f84bSDavid du Colombier 	snprint(addr, sizeof addr, "%s/mtu", path);
22829ef1f84bSDavid du Colombier 	if(waserror())
22839ef1f84bSDavid du Colombier 		mtu = nil;
22849ef1f84bSDavid du Colombier 	else {
22859ef1f84bSDavid du Colombier 		mtu = namec(addr, Aopen, OREAD, 0);
22869ef1f84bSDavid du Colombier 		poperror();
22879ef1f84bSDavid du Colombier 	}
22889ef1f84bSDavid du Colombier 
22899ef1f84bSDavid du Colombier 	if(waserror()){
22909ef1f84bSDavid du Colombier 		cclose(dc);
22919ef1f84bSDavid du Colombier 		cclose(cc);
22929ef1f84bSDavid du Colombier 		if(mtu)
22939ef1f84bSDavid du Colombier 			cclose(mtu);
22949ef1f84bSDavid du Colombier 		nexterror();
22959ef1f84bSDavid du Colombier 	}
22969ef1f84bSDavid du Colombier 	if(dc == nil  || cc == nil)
22979ef1f84bSDavid du Colombier 		error(Enonexist);
22989ef1f84bSDavid du Colombier 	getaddr(path, ea);
22999ef1f84bSDavid du Colombier 	nl = addnet(path, cc, dc, mtu, ea);
23009ef1f84bSDavid du Colombier 	snprint(addr, sizeof addr, "netrdaoe@%s", path);
23019ef1f84bSDavid du Colombier 	kproc(addr, netrdaoeproc, nl);
23029ef1f84bSDavid du Colombier 	poperror();
23039ef1f84bSDavid du Colombier }
23049ef1f84bSDavid du Colombier 
23059ef1f84bSDavid du Colombier static int
unbound(void * v)23069ef1f84bSDavid du Colombier unbound(void *v)
23079ef1f84bSDavid du Colombier {
23089ef1f84bSDavid du Colombier 	return *(int*)v != 0;
23099ef1f84bSDavid du Colombier }
23109ef1f84bSDavid du Colombier 
23119ef1f84bSDavid du Colombier static void
netunbind(char * path)23129ef1f84bSDavid du Colombier netunbind(char *path)
23139ef1f84bSDavid du Colombier {
23149ef1f84bSDavid du Colombier 	int i, idx;
23159ef1f84bSDavid du Colombier 	Aoedev *d, *p, *next;
23169ef1f84bSDavid du Colombier 	Chan *dc, *cc;
23179ef1f84bSDavid du Colombier 	Devlink *l;
23189ef1f84bSDavid du Colombier 	Frame *f;
23199ef1f84bSDavid du Colombier 	Netlink *n, *e;
23209ef1f84bSDavid du Colombier 
23219ef1f84bSDavid du Colombier 	n = netlinks.nl;
23229ef1f84bSDavid du Colombier 	e = n + nelem(netlinks.nl);
23239ef1f84bSDavid du Colombier 
23249ef1f84bSDavid du Colombier 	lock(&netlinks);
23259ef1f84bSDavid du Colombier 	for(; n < e; n++)
23269ef1f84bSDavid du Colombier 		if(n->dc && strcmp(n->path, path) == 0)
23279ef1f84bSDavid du Colombier 			break;
23289ef1f84bSDavid du Colombier 	unlock(&netlinks);
23299ef1f84bSDavid du Colombier 	if (n >= e)
23309ef1f84bSDavid du Colombier 		error("device not bound");
23319ef1f84bSDavid du Colombier 
23329ef1f84bSDavid du Colombier 	/*
23339ef1f84bSDavid du Colombier 	 * hunt down devices using this interface; disable
23349ef1f84bSDavid du Colombier 	 * this also terminates the reader.
23359ef1f84bSDavid du Colombier 	 */
23369ef1f84bSDavid du Colombier 	idx = n - netlinks.nl;
23379ef1f84bSDavid du Colombier 	wlock(&devs);
23389ef1f84bSDavid du Colombier 	for(d = devs.d; d; d = d->next){
23399ef1f84bSDavid du Colombier 		qlock(d);
23409ef1f84bSDavid du Colombier 		for(i = 0; i < d->ndl; i++){
23419ef1f84bSDavid du Colombier 			l = d->dl + i;
23429ef1f84bSDavid du Colombier 			if(l->nl == n)
23439ef1f84bSDavid du Colombier 				l->flag &= ~Dup;
23449ef1f84bSDavid du Colombier 		}
23459ef1f84bSDavid du Colombier 		qunlock(d);
23469ef1f84bSDavid du Colombier 	}
23479ef1f84bSDavid du Colombier 	n->flag &= ~Dup;
23489ef1f84bSDavid du Colombier 	wunlock(&devs);
23499ef1f84bSDavid du Colombier 
23509ef1f84bSDavid du Colombier 	/* confirm reader is down. */
23519ef1f84bSDavid du Colombier 	while(waserror())
23529ef1f84bSDavid du Colombier 		;
23539ef1f84bSDavid du Colombier 	sleep(netlinks.rendez + idx, unbound, netlinks.reader + idx);
23549ef1f84bSDavid du Colombier 	poperror();
23559ef1f84bSDavid du Colombier 
23569ef1f84bSDavid du Colombier 	/* reschedule packets. */
23579ef1f84bSDavid du Colombier 	wlock(&devs);
23589ef1f84bSDavid du Colombier 	for(d = devs.d; d; d = d->next){
23599ef1f84bSDavid du Colombier 		qlock(d);
23609ef1f84bSDavid du Colombier 		for(i = 0; i < d->nframes; i++){
23619ef1f84bSDavid du Colombier 			f = d->frames + i;
23629ef1f84bSDavid du Colombier 			if(f->tag != Tfree && f->nl == n)
23639ef1f84bSDavid du Colombier 				resend(d, f);
23649ef1f84bSDavid du Colombier 		}
23659ef1f84bSDavid du Colombier 		qunlock(d);
23669ef1f84bSDavid du Colombier 	}
23679ef1f84bSDavid du Colombier 	wunlock(&devs);
23689ef1f84bSDavid du Colombier 
23699ef1f84bSDavid du Colombier 	/* squeeze devlink pool.  (we assert nobody is using them now) */
23709ef1f84bSDavid du Colombier 	wlock(&devs);
23719ef1f84bSDavid du Colombier 	for(d = devs.d; d; d = d->next){
23729ef1f84bSDavid du Colombier 		qlock(d);
23739ef1f84bSDavid du Colombier 		for(i = 0; i < d->ndl; i++){
23749ef1f84bSDavid du Colombier 			l = d->dl + i;
23759ef1f84bSDavid du Colombier 			if(l->nl == n)
23769ef1f84bSDavid du Colombier 				memmove(l, l + 1, sizeof *l * (--d->ndl - i));
23779ef1f84bSDavid du Colombier 		}
23789ef1f84bSDavid du Colombier 		qunlock(d);
23799ef1f84bSDavid du Colombier 	}
23809ef1f84bSDavid du Colombier 	wunlock(&devs);
23819ef1f84bSDavid du Colombier 
23829ef1f84bSDavid du Colombier 	/* close device link. */
23839ef1f84bSDavid du Colombier 	lock(&netlinks);
23849ef1f84bSDavid du Colombier 	dc = n->dc;
23859ef1f84bSDavid du Colombier 	cc = n->cc;
23869ef1f84bSDavid du Colombier 	if(n->mtu)
23879ef1f84bSDavid du Colombier 		cclose(n->mtu);
23889ef1f84bSDavid du Colombier 	memset(n, 0, sizeof *n);
23899ef1f84bSDavid du Colombier 	unlock(&netlinks);
23909ef1f84bSDavid du Colombier 
23919ef1f84bSDavid du Colombier 	cclose(dc);
23929ef1f84bSDavid du Colombier 	cclose(cc);
23939ef1f84bSDavid du Colombier 
23949ef1f84bSDavid du Colombier 	/* squeeze orphan devices */
23959ef1f84bSDavid du Colombier 	wlock(&devs);
23969ef1f84bSDavid du Colombier 	for(p = d = devs.d; d; d = next){
23979ef1f84bSDavid du Colombier 		next = d->next;
23989ef1f84bSDavid du Colombier 		if(d->ndl > 0) {
23999ef1f84bSDavid du Colombier 			p = d;
24009ef1f84bSDavid du Colombier 			continue;
24019ef1f84bSDavid du Colombier 		}
24029ef1f84bSDavid du Colombier 		qlock(d);
24039ef1f84bSDavid du Colombier 		downdev(d, "orphan");
24049ef1f84bSDavid du Colombier 		qunlock(d);
24059ef1f84bSDavid du Colombier 		if(p != devs.d)
24069ef1f84bSDavid du Colombier 			p->next = next;
24079ef1f84bSDavid du Colombier 		else{
24089ef1f84bSDavid du Colombier 			devs.d = next;
24099ef1f84bSDavid du Colombier 			p = devs.d;
24109ef1f84bSDavid du Colombier 		}
24119ef1f84bSDavid du Colombier 		free(d->frames);
24129ef1f84bSDavid du Colombier 		free(d);
24139ef1f84bSDavid du Colombier 		dropunit();
24149ef1f84bSDavid du Colombier 	}
24159ef1f84bSDavid du Colombier 	wunlock(&devs);
24169ef1f84bSDavid du Colombier }
24179ef1f84bSDavid du Colombier 
24189ef1f84bSDavid du Colombier static void
removeaoedev(Aoedev * d)24199ef1f84bSDavid du Colombier removeaoedev(Aoedev *d)
24209ef1f84bSDavid du Colombier {
24219ef1f84bSDavid du Colombier 	int i;
24229ef1f84bSDavid du Colombier 	Aoedev *p;
24239ef1f84bSDavid du Colombier 
24249ef1f84bSDavid du Colombier 	wlock(&devs);
24259ef1f84bSDavid du Colombier 	p = 0;
24269ef1f84bSDavid du Colombier 	if(d != devs.d)
24279ef1f84bSDavid du Colombier 		for(p = devs.d; p; p = p->next)
24289ef1f84bSDavid du Colombier 			if(p->next == d)
24299ef1f84bSDavid du Colombier 				break;
24309ef1f84bSDavid du Colombier 	qlock(d);
24319ef1f84bSDavid du Colombier 	d->flag &= ~Dup;
2432406c76faSDavid du Colombier 
2433406c76faSDavid du Colombier 	/*
2434406c76faSDavid du Colombier 	 * Changing the version number is, strictly speaking, correct,
2435406c76faSDavid du Colombier  	 * but doing so means that deleting a LUN that is not in use
2436406c76faSDavid du Colombier 	 * invalidates all other LUNs too.  If your file server has
2437406c76faSDavid du Colombier 	 * venti arenas or fossil file systems on 1.0, and you delete 1.1,
2438406c76faSDavid du Colombier 	 * since you no longer need it, 1.0 will become inaccessible to your
2439406c76faSDavid du Colombier 	 * file server, which will eventually panic.  Note that newdev()
2440406c76faSDavid du Colombier 	 * does not change the version number.
2441406c76faSDavid du Colombier 	 */
2442406c76faSDavid du Colombier 	// newvers(d);
2443406c76faSDavid du Colombier 
24449ef1f84bSDavid du Colombier 	d->ndl = 0;
24459ef1f84bSDavid du Colombier 	qunlock(d);
24469ef1f84bSDavid du Colombier 	for(i = 0; i < d->nframes; i++)
2447406c76faSDavid du Colombier 		frameerror(d, d->frames+i, Eaoedown);
24489ef1f84bSDavid du Colombier 
24499ef1f84bSDavid du Colombier 	if(p)
24509ef1f84bSDavid du Colombier 		p->next = d->next;
24519ef1f84bSDavid du Colombier 	else
24529ef1f84bSDavid du Colombier 		devs.d = d->next;
24539ef1f84bSDavid du Colombier 	free(d->frames);
24549ef1f84bSDavid du Colombier 	free(d);
24559ef1f84bSDavid du Colombier 	dropunit();
24569ef1f84bSDavid du Colombier 	wunlock(&devs);
24579ef1f84bSDavid du Colombier }
24589ef1f84bSDavid du Colombier 
24599ef1f84bSDavid du Colombier static void
removedev(char * name)24609ef1f84bSDavid du Colombier removedev(char *name)
24619ef1f84bSDavid du Colombier {
24629ef1f84bSDavid du Colombier 	Aoedev *d, *p;
24639ef1f84bSDavid du Colombier 
24649ef1f84bSDavid du Colombier 	wlock(&devs);
24659ef1f84bSDavid du Colombier 	for(p = d = devs.d; d; p = d, d = d->next)
24669ef1f84bSDavid du Colombier 		if(strcmp(name, unitname(d)) == 0) {
24679ef1f84bSDavid du Colombier 			wunlock(&devs);
24689ef1f84bSDavid du Colombier 			removeaoedev(p);
24699ef1f84bSDavid du Colombier 			return;
24709ef1f84bSDavid du Colombier 		}
24719ef1f84bSDavid du Colombier 	wunlock(&devs);
24729ef1f84bSDavid du Colombier 	error("device not bound");
24739ef1f84bSDavid du Colombier }
24749ef1f84bSDavid du Colombier 
24759ef1f84bSDavid du Colombier static void
discoverstr(char * f)24769ef1f84bSDavid du Colombier discoverstr(char *f)
24779ef1f84bSDavid du Colombier {
24789ef1f84bSDavid du Colombier 	ushort shelf, slot;
24799ef1f84bSDavid du Colombier 	ulong sh;
24809ef1f84bSDavid du Colombier 	char *s;
24819ef1f84bSDavid du Colombier 
24829ef1f84bSDavid du Colombier 	if(f == 0){
24839ef1f84bSDavid du Colombier 		discover(0xffff, 0xff);
24849ef1f84bSDavid du Colombier 		return;
24859ef1f84bSDavid du Colombier 	}
24869ef1f84bSDavid du Colombier 
24879ef1f84bSDavid du Colombier 	shelf = sh = strtol(f, &s, 0);
24889ef1f84bSDavid du Colombier 	if(s == f || sh > 0xffff)
24899ef1f84bSDavid du Colombier 		error("bad shelf");
24909ef1f84bSDavid du Colombier 	f = s;
24919ef1f84bSDavid du Colombier 	if(*f++ == '.'){
24929ef1f84bSDavid du Colombier 		slot = strtol(f, &s, 0);
24939ef1f84bSDavid du Colombier 		if(s == f || slot > 0xff)
24949ef1f84bSDavid du Colombier 			error("bad shelf");
24959ef1f84bSDavid du Colombier 	}else
24969ef1f84bSDavid du Colombier 		slot = 0xff;
24979ef1f84bSDavid du Colombier 	discover(shelf, slot);
24989ef1f84bSDavid du Colombier }
24999ef1f84bSDavid du Colombier 
25009ef1f84bSDavid du Colombier 
25019ef1f84bSDavid du Colombier static void
aoeremove(Chan * c)25029ef1f84bSDavid du Colombier aoeremove(Chan *c)
25039ef1f84bSDavid du Colombier {
25049ef1f84bSDavid du Colombier 	switch(TYPE(c->qid)){
25059ef1f84bSDavid du Colombier 	default:
25069ef1f84bSDavid du Colombier 		error(Eperm);
25079ef1f84bSDavid du Colombier 	case Qunitdir:
25089ef1f84bSDavid du Colombier 		removeaoedev(unit2dev(UNIT(c->qid)));
25099ef1f84bSDavid du Colombier 		break;
25109ef1f84bSDavid du Colombier 	}
25119ef1f84bSDavid du Colombier }
25129ef1f84bSDavid du Colombier 
25139ef1f84bSDavid du Colombier static long
topctlwrite(void * db,long n)25149ef1f84bSDavid du Colombier topctlwrite(void *db, long n)
25159ef1f84bSDavid du Colombier {
25169ef1f84bSDavid du Colombier 	enum {
25179ef1f84bSDavid du Colombier 		Autodiscover,
25189ef1f84bSDavid du Colombier 		Bind,
25199ef1f84bSDavid du Colombier 		Debug,
25209ef1f84bSDavid du Colombier 		Discover,
25219ef1f84bSDavid du Colombier 		Rediscover,
25229ef1f84bSDavid du Colombier 		Remove,
25239ef1f84bSDavid du Colombier 		Unbind,
25249ef1f84bSDavid du Colombier 	};
25259ef1f84bSDavid du Colombier 	char *f;
25269ef1f84bSDavid du Colombier 	Cmdbuf *cb;
25279ef1f84bSDavid du Colombier 	Cmdtab *ct;
25289ef1f84bSDavid du Colombier 	static Cmdtab cmds[] = {
25299ef1f84bSDavid du Colombier 		{ Autodiscover,	"autodiscover",	0	},
25309ef1f84bSDavid du Colombier 		{ Bind, 	"bind", 	2	},
25319ef1f84bSDavid du Colombier 		{ Debug, 	"debug", 	0	},
25329ef1f84bSDavid du Colombier 		{ Discover, 	"discover", 	0	},
25339ef1f84bSDavid du Colombier 		{ Rediscover,	"rediscover",	0	},
25349ef1f84bSDavid du Colombier 		{ Remove,	"remove",	2	},
25359ef1f84bSDavid du Colombier 		{ Unbind,	"unbind",	2	},
25369ef1f84bSDavid du Colombier 	};
25379ef1f84bSDavid du Colombier 
25389ef1f84bSDavid du Colombier 	cb = parsecmd(db, n);
25399ef1f84bSDavid du Colombier 	if(waserror()){
25409ef1f84bSDavid du Colombier 		free(cb);
25419ef1f84bSDavid du Colombier 		nexterror();
25429ef1f84bSDavid du Colombier 	}
25439ef1f84bSDavid du Colombier 	ct = lookupcmd(cb, cmds, nelem(cmds));
25449ef1f84bSDavid du Colombier 	f = cb->f[1];
25459ef1f84bSDavid du Colombier 	switch(ct->index){
25469ef1f84bSDavid du Colombier 	case Autodiscover:
25479ef1f84bSDavid du Colombier 		autodiscover = toggle(f, autodiscover, 1);
25489ef1f84bSDavid du Colombier 		break;
25499ef1f84bSDavid du Colombier 	case Bind:
25509ef1f84bSDavid du Colombier 		netbind(f);
25519ef1f84bSDavid du Colombier 		break;
25529ef1f84bSDavid du Colombier 	case Debug:
25539ef1f84bSDavid du Colombier 		debug = toggle(f, debug, 1);
25549ef1f84bSDavid du Colombier 		break;
25559ef1f84bSDavid du Colombier 	case Discover:
25569ef1f84bSDavid du Colombier 		discoverstr(f);
25579ef1f84bSDavid du Colombier 		break;
25589ef1f84bSDavid du Colombier 	case Rediscover:
25599ef1f84bSDavid du Colombier 		rediscover = toggle(f, rediscover, 1);
25609ef1f84bSDavid du Colombier 		break;
25619ef1f84bSDavid du Colombier 	case Remove:
25629ef1f84bSDavid du Colombier 		removedev(f);
25639ef1f84bSDavid du Colombier 		break;
25649ef1f84bSDavid du Colombier 	case Unbind:
25659ef1f84bSDavid du Colombier 		netunbind(f);
25669ef1f84bSDavid du Colombier 		break;
25679ef1f84bSDavid du Colombier 	default:
25689ef1f84bSDavid du Colombier 		cmderror(cb, "unknown aoe control message");
25699ef1f84bSDavid du Colombier 	}
25709ef1f84bSDavid du Colombier 	poperror();
25719ef1f84bSDavid du Colombier 	free(cb);
25729ef1f84bSDavid du Colombier 	return n;
25739ef1f84bSDavid du Colombier }
25749ef1f84bSDavid du Colombier 
25759ef1f84bSDavid du Colombier static long
aoewrite(Chan * c,void * db,long n,vlong off)25769ef1f84bSDavid du Colombier aoewrite(Chan *c, void *db, long n, vlong off)
25779ef1f84bSDavid du Colombier {
25789ef1f84bSDavid du Colombier 	switch(TYPE(c->qid)){
25799ef1f84bSDavid du Colombier 	default:
25809ef1f84bSDavid du Colombier 	case Qzero:
25819ef1f84bSDavid du Colombier 	case Qtopdir:
25829ef1f84bSDavid du Colombier 	case Qunitdir:
25839ef1f84bSDavid du Colombier 	case Qtoplog:
25849ef1f84bSDavid du Colombier 		error(Eperm);
25859ef1f84bSDavid du Colombier 	case Qtopctl:
25869ef1f84bSDavid du Colombier 		return topctlwrite(db, n);
25879ef1f84bSDavid du Colombier 	case Qctl:
25889ef1f84bSDavid du Colombier 	case Qdata:
25899ef1f84bSDavid du Colombier 	case Qconfig:
25909ef1f84bSDavid du Colombier 	case Qident:
25919ef1f84bSDavid du Colombier 		return unitwrite(c, db, n, off);
25929ef1f84bSDavid du Colombier 	}
25939ef1f84bSDavid du Colombier }
25949ef1f84bSDavid du Colombier 
25959ef1f84bSDavid du Colombier Dev aoedevtab = {
25969ef1f84bSDavid du Colombier 	L'æ',
25979ef1f84bSDavid du Colombier 	"aoe",
25989ef1f84bSDavid du Colombier 
25999ef1f84bSDavid du Colombier 	devreset,
26009ef1f84bSDavid du Colombier 	devinit,
26019ef1f84bSDavid du Colombier 	devshutdown,
26029ef1f84bSDavid du Colombier 	aoeattach,
26039ef1f84bSDavid du Colombier 	aoewalk,
26049ef1f84bSDavid du Colombier 	aoestat,
26059ef1f84bSDavid du Colombier 	aoeopen,
26069ef1f84bSDavid du Colombier 	devcreate,
26079ef1f84bSDavid du Colombier 	aoeclose,
26089ef1f84bSDavid du Colombier 	aoeread,
26099ef1f84bSDavid du Colombier 	devbread,
26109ef1f84bSDavid du Colombier 	aoewrite,
26119ef1f84bSDavid du Colombier 	devbwrite,
26129ef1f84bSDavid du Colombier 	aoeremove,
26139ef1f84bSDavid du Colombier 	devwstat,
26149ef1f84bSDavid du Colombier 	devpower,
26159ef1f84bSDavid du Colombier 	devconfig,
26169ef1f84bSDavid du Colombier };
2617