xref: /plan9/sys/src/9/port/devaoe.c (revision f7c114af05ae4d498891de07f5a043835bd540ab)
1 /*
2  *	© 2005-2010 coraid
3  *	ATA-over-Ethernet (AoE) storage initiator
4  */
5 
6 #include "u.h"
7 #include "../port/lib.h"
8 #include "mem.h"
9 #include "dat.h"
10 #include "fns.h"
11 #include "io.h"
12 #include "ureg.h"
13 #include "../port/error.h"
14 #include "../port/netif.h"
15 #include "etherif.h"
16 #include "../ip/ip.h"
17 #include "../port/aoe.h"
18 
19 #pragma	varargck argpos	eventlog	1
20 
21 #define dprint(...)	if(debug) eventlog(__VA_ARGS__); else USED(debug);
22 #define uprint(...)	snprint(up->genbuf, sizeof up->genbuf, __VA_ARGS__);
23 
24 enum {
25 	Maxunits	= 0xff,
26 	Maxframes	= 128,
27 	Ndevlink	= 6,
28 	Nea		= 6,
29 	Nnetlink	= 6,
30 };
31 
32 #define TYPE(q)		((ulong)(q).path & 0xf)
33 #define UNIT(q)		(((ulong)(q).path>>4) & 0xff)
34 #define L(q)		(((ulong)(q).path>>12) & 0xf)
35 #define QID(u, t) 	((u)<<4 | (t))
36 #define Q3(l, u, t)	((l)<<8 | QID(u, t))
37 #define UP(d)		((d)->flag & Dup)
38 /*
39  * would like this to depend on the chan (srb).
40  * not possible in the current structure.
41  */
42 #define Nofail(d, s)	((d)->flag & Dnofail)
43 
44 #define	MS2TK(t)	((t)/MS2HZ)
45 
46 enum {
47 	Qzero,
48 	Qtopdir		= 1,
49 	Qtopbase,
50 	Qtopctl		= Qtopbase,
51 	Qtoplog,
52 	Qtopend,
53 
54 	Qunitdir,
55 	Qunitbase,
56 	Qctl		= Qunitbase,
57 	Qdata,
58 	Qconfig,
59 	Qident,
60 
61 	Qdevlinkdir,
62 	Qdevlinkbase,
63 	Qdevlink	= Qdevlinkbase,
64 	Qdevlinkend,
65 
66 	Qtopfiles	= Qtopend-Qtopbase,
67 	Qdevlinkfiles	= Qdevlinkend-Qdevlinkbase,
68 
69 	Eventlen 	= 256,
70 	Nevents 	= 64,			/* must be power of 2 */
71 
72 	Fread		= 0,
73 	Fwrite,
74 	Tfree		= -1,
75 	Tmgmt,
76 
77 	/*
78 	 * round trip bounds, timeouts, in ticks.
79 	 * timeouts should be long enough that rebooting
80 	 * the coraid (which usually takes under two minutes)
81 	 * doesn't trigger a timeout.
82 	 */
83 	Rtmax		= MS2TK(320),
84 	Rtmin		= MS2TK(20),
85 	Maxreqticks	= 4*60*HZ,		/* was 45*HZ */
86 
87 	Dbcnt		= 1024,
88 
89 	Crd		= 0x20,
90 	Crdext		= 0x24,
91 	Cwr		= 0x30,
92 	Cwrext		= 0x34,
93 	Cid		= 0xec,
94 };
95 
96 enum {
97 	Read,
98 	Write,
99 };
100 
101 /*
102  * unified set of flags
103  * a Netlink + Aoedev most both be jumbo capable
104  * to send jumbograms to that interface.
105  */
106 enum {
107 	/* sync with ahci.h */
108 	Dllba 	= 1<<0,
109 	Dsmart	= 1<<1,
110 	Dpower	= 1<<2,
111 	Dnop	= 1<<3,
112 	Datapi	= 1<<4,
113 	Datapi16= 1<<5,
114 
115 	/* aoe specific */
116 	Dup	= 1<<6,
117 	Djumbo	= 1<<7,
118 	Dnofail	= 1<<8,
119 };
120 
121 static char *flagname[] = {
122 	"llba",
123 	"smart",
124 	"power",
125 	"nop",
126 	"atapi",
127 	"atapi16",
128 
129 	"up",
130 	"jumbo",
131 	"nofail",
132 };
133 
134 typedef struct {
135 	ushort	flag;
136 	uint	lostjumbo;
137 	int	datamtu;
138 
139 	Chan	*cc;
140 	Chan	*dc;
141 	Chan	*mtu;		/* open early to prevent bind issues. */
142 	char	path[Maxpath];
143 	uchar	ea[Eaddrlen];
144 } Netlink;
145 
146 typedef struct {
147 	Netlink	*nl;
148 	int	nea;
149 	ulong	eaidx;
150 	uchar	eatab[Nea][Eaddrlen];
151 	ulong	npkt;
152 	ulong	resent;
153 	ushort	flag;
154 
155 	ulong	rttavg;
156 	ulong	mintimer;
157 } Devlink;
158 
159 typedef struct Srb Srb;
160 struct Srb {
161 	Rendez;
162 	Srb	*next;
163 	int	shared;	/* Srb shared with kproc (don't free) */
164 	ulong	ticksent;
165 	ulong	len;
166 	vlong	sector;
167 	short	write;
168 	short	nout;
169 	char	*error;
170 	void	*dp;
171 	void	*data;
172 };
173 
174 typedef struct {
175 	int	tag;
176 	ulong	bcnt;
177 	ulong	dlen;
178 	vlong	lba;
179 	ulong	ticksent;
180 	int	nhdr;
181 	uchar	hdr[ETHERMINTU];
182 	void	*dp;
183 	Devlink	*dl;
184 	Netlink	*nl;
185 	int	eaidx;
186 	Srb	*srb;
187 } Frame;
188 
189 typedef struct Aoedev Aoedev;
190 struct Aoedev {
191 	QLock;
192 	Aoedev	*next;
193 
194 	ulong	vers;
195 
196 	int	ndl;
197 	ulong	dlidx;
198 	Devlink	*dl;
199 	Devlink	dltab[Ndevlink];
200 
201 	ushort	fwver;
202 	ushort	flag;
203 	int	nopen;
204 	int	major;
205 	int	minor;
206 	int	unit;
207 	int	lasttag;
208 	int	nframes;
209 	Frame	*frames;
210 	vlong	bsize;
211 	vlong	realbsize;
212 
213 	uint	maxbcnt;
214 	ushort	nout;
215 	ushort	maxout;
216 	ulong	lastwadj;
217 	Srb	*head;
218 	Srb	*tail;
219 	Srb	*inprocess;
220 
221 	/* magic numbers 'R' us */
222 	char	serial[20+1];
223 	char	firmware[8+1];
224 	char	model[40+1];
225 	int	nconfig;
226 	uchar	config[1024];
227 	uchar	ident[512];
228 };
229 
230 #pragma	varargck type	"æ"	Aoedev*
231 
232 static struct {
233 	Lock;
234 	QLock;
235 	Rendez;
236 	char	buf[Eventlen*Nevents];
237 	char	*rp;
238 	char	*wp;
239 } events;
240 
241 static struct {
242 	RWlock;
243 	int	nd;
244 	Aoedev	*d;
245 } devs;
246 
247 static struct {
248 	Lock;
249 	int	reader[Nnetlink];	/* reader is running. */
250 	Rendez	rendez[Nnetlink];	/* confirm exit. */
251 	Netlink	nl[Nnetlink];
252 } netlinks;
253 
254 extern Dev 	aoedevtab;
255 static Ref 	units;
256 static Ref	drivevers;
257 static int	debug;
258 static int	autodiscover	= 1;
259 static int	rediscover;
260 
261 static Srb*
srballoc(ulong sz)262 srballoc(ulong sz)
263 {
264 	Srb *srb;
265 
266 	srb = malloc(sizeof *srb+sz);
267 	if(srb == nil)
268 		error(Enomem);
269 	srb->dp = srb->data = srb+1;
270 	srb->ticksent = MACHP(0)->ticks;
271 	srb->shared = 0;
272 	return srb;
273 }
274 
275 static Srb*
srbkalloc(void * db,ulong)276 srbkalloc(void *db, ulong)
277 {
278 	Srb *srb;
279 
280 	srb = malloc(sizeof *srb);
281 	if(srb == nil)
282 		error(Enomem);
283 	srb->dp = srb->data = db;
284 	srb->ticksent = MACHP(0)->ticks;
285 	srb->shared = 0;
286 	return srb;
287 }
288 
289 static void
srbfree(Srb * srb)290 srbfree(Srb *srb)
291 {
292 	while(srb->shared)
293 		sched();
294 	free(srb);
295 }
296 
297 static void
srberror(Srb * srb,char * s)298 srberror(Srb *srb, char *s)
299 {
300 	srb->error = s;
301 	srb->nout--;
302 	if(srb->nout == 0)
303 		wakeup(srb);
304 }
305 
306 static void
frameerror(Aoedev * d,Frame * f,char * s)307 frameerror(Aoedev *d, Frame *f, char *s)
308 {
309 	Srb *srb;
310 
311 	srb = f->srb;
312 	if(f->tag == Tfree || !srb)
313 		return;
314 	f->srb = nil;
315 	f->tag = Tfree;		/* don't get fooled by way-slow responses */
316 	srberror(srb, s);
317 	d->nout--;
318 }
319 
320 static char*
unitname(Aoedev * d)321 unitname(Aoedev *d)
322 {
323 	uprint("%d.%d", d->major, d->minor);
324 	return up->genbuf;
325 }
326 
327 static int
eventlogready(void *)328 eventlogready(void*)
329 {
330 	return *events.rp;
331 }
332 
333 static long
eventlogread(void * a,long n)334 eventlogread(void *a, long n)
335 {
336 	int len;
337 	char *p, *buf;
338 
339 	buf = smalloc(Eventlen);
340 	qlock(&events);
341 	lock(&events);
342 	p = events.rp;
343 	len = *p;
344 	if(len == 0){
345 		n = 0;
346 		unlock(&events);
347 	} else {
348 		if(n > len)
349 			n = len;
350 		/* can't move directly into pageable space with events lock held */
351 		memmove(buf, p+1, n);
352 		*p = 0;
353 		events.rp = p += Eventlen;
354 		if(p >= events.buf + sizeof events.buf)
355 			events.rp = events.buf;
356 		unlock(&events);
357 
358 		/* the concern here is page faults in memmove below */
359 		if(waserror()){
360 			free(buf);
361 			qunlock(&events);
362 			nexterror();
363 		}
364 		memmove(a, buf, n);
365 		poperror();
366 	}
367 	free(buf);
368 	qunlock(&events);
369 	return n;
370 }
371 
372 static int
eventlog(char * fmt,...)373 eventlog(char *fmt, ...)
374 {
375 	int dragrp, n;
376 	char *p;
377 	va_list arg;
378 
379 	lock(&events);
380 	p = events.wp;
381 	dragrp = *p++;
382 	va_start(arg, fmt);
383 	n = vsnprint(p, Eventlen-1, fmt, arg);
384 	*--p = n;
385 	p = events.wp += Eventlen;
386 	if(p >= events.buf + sizeof events.buf)
387 		p = events.wp = events.buf;
388 	if(dragrp)
389 		events.rp = p;
390 	unlock(&events);
391 	wakeup(&events);
392 	return n;
393 }
394 
395 static int
eventcount(void)396 eventcount(void)
397 {
398 	int n;
399 
400 	lock(&events);
401 	if(*events.rp == 0)
402 		n = 0;
403 	else
404 		n = (events.wp - events.rp) & (Nevents - 1);
405 	unlock(&events);
406 	return n/Eventlen;
407 }
408 
409 static int
tsince(int tag)410 tsince(int tag)
411 {
412 	int n;
413 
414 	n = MACHP(0)->ticks & 0xffff;
415 	n -= tag & 0xffff;
416 	if(n < 0)
417 		n += 1<<16;
418 	return n;
419 }
420 
421 static int
newtag(Aoedev * d)422 newtag(Aoedev *d)
423 {
424 	int t;
425 
426 	do {
427 		t = ++d->lasttag << 16;
428 		t |= MACHP(0)->ticks & 0xffff;
429 	} while (t == Tfree || t == Tmgmt);
430 	return t;
431 }
432 
433 static void
downdev(Aoedev * d,char * err)434 downdev(Aoedev *d, char *err)
435 {
436 	Frame *f, *e;
437 
438 	d->flag &= ~Dup;
439 	f = d->frames;
440 	e = f + d->nframes;
441 	for(; f < e; f->tag = Tfree, f->srb = nil, f++)
442 		frameerror(d, f, Eaoedown);
443 	d->inprocess = nil;
444 	eventlog("%æ: removed; %s\n", d, err);
445 }
446 
447 static Block*
allocfb(Frame * f)448 allocfb(Frame *f)
449 {
450 	int len;
451 	Block *b;
452 
453 	len = f->nhdr + f->dlen;
454 	if(len < ETHERMINTU)
455 		len = ETHERMINTU;
456 	b = allocb(len);
457 	memmove(b->wp, f->hdr, f->nhdr);
458 	if(f->dlen)
459 		memmove(b->wp + f->nhdr, f->dp, f->dlen);
460 	b->wp += len;
461 	return b;
462 }
463 
464 static void
putlba(Aoeata * a,vlong lba)465 putlba(Aoeata *a, vlong lba)
466 {
467 	uchar *c;
468 
469 	c = a->lba;
470 	c[0] = lba;
471 	c[1] = lba >> 8;
472 	c[2] = lba >> 16;
473 	c[3] = lba >> 24;
474 	c[4] = lba >> 32;
475 	c[5] = lba >> 40;
476 }
477 
478 static Devlink*
pickdevlink(Aoedev * d)479 pickdevlink(Aoedev *d)
480 {
481 	ulong i, n;
482 	Devlink *l;
483 
484 	for(i = 0; i < d->ndl; i++){
485 		n = d->dlidx++ % d->ndl;
486 		l = d->dl + n;
487 		if(l && l->flag & Dup)
488 			return l;
489 	}
490 	return 0;
491 }
492 
493 static int
pickea(Devlink * l)494 pickea(Devlink *l)
495 {
496 	if(l == 0)
497 		return -1;
498 	if(l->nea == 0)
499 		return -1;
500 	return l->eaidx++ % l->nea;
501 }
502 
503 static int
hset(Aoedev * d,Frame * f,Aoehdr * h,int cmd)504 hset(Aoedev *d, Frame *f, Aoehdr *h, int cmd)
505 {
506 	int i;
507 	Devlink *l;
508 
509 	if(f->srb && MACHP(0)->ticks - f->srb->ticksent > Maxreqticks){
510 		eventlog("%æ: srb timeout\n", d);
511 		if(cmd == ACata && f->srb && Nofail(d, s))
512 			f->srb->ticksent = MACHP(0)->ticks;
513 		else
514 			frameerror(d, f, Etimedout);
515 		return -1;
516 	}
517 	l = pickdevlink(d);
518 	i = pickea(l);
519 	if(i == -1){
520 		if(cmd != ACata || f->srb == nil || !Nofail(d, s))
521 			downdev(d, "resend fails; no netlink/ea");
522 		return -1;
523 	}
524 	memmove(h->dst, l->eatab[i], Eaddrlen);
525 	memmove(h->src, l->nl->ea, sizeof h->src);
526 	hnputs(h->type, Aoetype);
527 	h->verflag = Aoever << 4;
528 	h->error = 0;
529 	hnputs(h->major, d->major);
530 	h->minor = d->minor;
531 	h->cmd = cmd;
532 
533 	hnputl(h->tag, f->tag = newtag(d));
534 	f->dl = l;
535 	f->nl = l->nl;
536 	f->eaidx = i;
537 	f->ticksent = MACHP(0)->ticks;
538 
539 	return f->tag;
540 }
541 
542 static int
resend(Aoedev * d,Frame * f)543 resend(Aoedev *d, Frame *f)
544 {
545 	ulong n;
546 	Aoeata *a;
547 
548 	a = (Aoeata*)f->hdr;
549 	if(hset(d, f, a, a->cmd) == -1)
550 		return -1;
551 	n = f->bcnt;
552 	if(n > d->maxbcnt){
553 		n = d->maxbcnt;		/* mtu mismatch (jumbo fail?) */
554 		if(f->dlen > n)
555 			f->dlen = n;
556 	}
557 	a->scnt = n / Aoesectsz;
558 	f->dl->resent++;
559 	f->dl->npkt++;
560 	if(waserror())
561 		return -1;
562 	devtab[f->nl->dc->type]->bwrite(f->nl->dc, allocfb(f), 0);
563 	poperror();
564 	return 0;
565 }
566 
567 static void
discover(int major,int minor)568 discover(int major, int minor)
569 {
570 	Aoehdr *h;
571 	Block *b;
572 	Netlink *nl, *e;
573 
574 	nl = netlinks.nl;
575 	e = nl + nelem(netlinks.nl);
576 	for(; nl < e; nl++){
577 		if(nl->cc == nil)
578 			continue;
579 		b = allocb(ETHERMINTU);
580 		if(waserror()){
581 			freeb(b);
582 			nexterror();
583 		}
584 		b->wp = b->rp + ETHERMINTU;
585 		memset(b->rp, 0, ETHERMINTU);
586 		h = (Aoehdr*)b->rp;
587 		memset(h->dst, 0xff, sizeof h->dst);
588 		memmove(h->src, nl->ea, sizeof h->src);
589 		hnputs(h->type, Aoetype);
590 		h->verflag = Aoever << 4;
591 		hnputs(h->major, major);
592 		h->minor = minor;
593 		h->cmd = ACconfig;
594 		poperror();
595 		/* send b down the queue */
596 		devtab[nl->dc->type]->bwrite(nl->dc, b, 0);
597 	}
598 }
599 
600 /*
601  * Check all frames on device and resend any frames that have been
602  * outstanding for 200% of the device round trip time average.
603  */
604 static void
aoesweepproc(void *)605 aoesweepproc(void*)
606 {
607 	ulong i, tx, timeout, nbc;
608 	vlong starttick;
609 	enum { Nms = 100, Nbcms = 30*1000, };		/* magic */
610 	uchar *ea;
611 	Aoeata *a;
612 	Aoedev *d;
613 	Devlink *l;
614 	Frame *f, *e;
615 
616 	nbc = Nbcms/Nms;
617 loop:
618 	if(nbc-- == 0){
619 		if(rediscover && !waserror()){
620 			discover(0xffff, 0xff);
621 			poperror();
622 		}
623 		nbc = Nbcms/Nms;
624 	}
625 	starttick = MACHP(0)->ticks;
626 	rlock(&devs);
627 	for(d = devs.d; d; d = d->next){
628 		if(!canqlock(d))
629 			continue;
630 		if(!UP(d)){
631 			qunlock(d);
632 			continue;
633 		}
634 		tx = 0;
635 		f = d->frames;
636 		e = f + d->nframes;
637 		for (; f < e; f++){
638 			if(f->tag == Tfree)
639 				continue;
640 			l = f->dl;
641 			timeout = l->rttavg << 1;
642 			i = tsince(f->tag);
643 			if(i < timeout)
644 				continue;
645 			if(d->nout == d->maxout){
646 				if(d->maxout > 1)
647 					d->maxout--;
648 				d->lastwadj = MACHP(0)->ticks;
649 			}
650 			a = (Aoeata*)f->hdr;
651 			if(a->scnt > Dbcnt / Aoesectsz &&
652 			   ++f->nl->lostjumbo > (d->nframes << 1)){
653 				ea = f->dl->eatab[f->eaidx];
654 				eventlog("%æ: jumbo failure on %s:%E; lba%lld\n",
655 					d, f->nl->path, ea, f->lba);
656 				d->maxbcnt = Dbcnt;
657 				d->flag &= ~Djumbo;
658 			}
659 			resend(d, f);
660 			if(tx++ == 0){
661 				if((l->rttavg <<= 1) > Rtmax)
662 					l->rttavg = Rtmax;
663 				eventlog("%æ: rtt %ldms\n", d, TK2MS(l->rttavg));
664 			}
665 		}
666 		if(d->nout == d->maxout && d->maxout < d->nframes &&
667 		   TK2MS(MACHP(0)->ticks - d->lastwadj) > 10*1000){ /* more magic */
668 			d->maxout++;
669 			d->lastwadj = MACHP(0)->ticks;
670 		}
671 		qunlock(d);
672 	}
673 	runlock(&devs);
674 	i = Nms - TK2MS(MACHP(0)->ticks - starttick);
675 	if(i > 0)
676 		tsleep(&up->sleep, return0, 0, i);
677 	goto loop;
678 }
679 
680 static int
681 fmtæ(Fmt *f)
682 {
683 	char buf[16];
684 	Aoedev *d;
685 
686 	d = va_arg(f->args, Aoedev*);
687 	snprint(buf, sizeof buf, "aoe%d.%d", d->major, d->minor);
688 	return fmtstrcpy(f, buf);
689 }
690 
691 static void netbind(char *path);
692 
693 static void
aoecfg(void)694 aoecfg(void)
695 {
696 	int n, i;
697 	char *p, *f[32], buf[24];
698 
699 	if((p = getconf("aoeif")) == nil || (n = tokenize(p, f, nelem(f))) < 1)
700 		return;
701 	/* goo! */
702 	for(i = 0; i < n; i++){
703 		p = f[i];
704 		if(strncmp(p, "ether", 5) == 0)
705 			snprint(buf, sizeof buf, "#l%c/ether%c", p[5], p[5]);
706 		else if(strncmp(p, "#l", 2) == 0)
707 			snprint(buf, sizeof buf, "#l%c/ether%c", p[2], p[2]);
708 		else
709 			continue;
710 		if(!waserror()){
711 			netbind(buf);
712 			poperror();
713 		}
714 	}
715 }
716 
717 static void
aoeinit(void)718 aoeinit(void)
719 {
720 	static int init;
721 	static QLock l;
722 
723 	if(!canqlock(&l))
724 		return;
725 	if(init == 0){
726 		fmtinstall(L'æ', fmtæ);
727 		events.rp = events.wp = events.buf;
728 		kproc("aoesweep", aoesweepproc, nil);
729 		aoecfg();
730 		init = 1;
731 	}
732 	qunlock(&l);
733 }
734 
735 static Chan*
aoeattach(char * spec)736 aoeattach(char *spec)
737 {
738 	Chan *c;
739 
740 	if(*spec)
741 		error(Enonexist);
742 	aoeinit();
743 	c = devattach(L'æ', spec);
744 	mkqid(&c->qid, Qzero, 0, QTDIR);
745 	return c;
746 }
747 
748 static Aoedev*
unit2dev(ulong unit)749 unit2dev(ulong unit)
750 {
751 	int i;
752 	Aoedev *d;
753 
754 	rlock(&devs);
755 	i = 0;
756 	for(d = devs.d; d; d = d->next)
757 		if(i++ == unit){
758 			runlock(&devs);
759 			return d;
760 		}
761 	runlock(&devs);
762 	uprint("unit lookup failure: %lux pc %#p", unit, getcallerpc(&unit));
763 	error(up->genbuf);
764 	return nil;
765 }
766 
767 static int
unitgen(Chan * c,ulong type,Dir * dp)768 unitgen(Chan *c, ulong type, Dir *dp)
769 {
770 	int perm, t;
771 	ulong vers;
772 	vlong size;
773 	char *p;
774 	Aoedev *d;
775 	Qid q;
776 
777 	d = unit2dev(UNIT(c->qid));
778 	perm = 0644;
779 	size = 0;
780 	vers = d->vers;
781 	t = QTFILE;
782 
783 	switch(type){
784 	default:
785 		return -1;
786 	case Qctl:
787 		p = "ctl";
788 		break;
789 	case Qdata:
790 		p = "data";
791 		perm = 0640;
792 		if(UP(d))
793 			size = d->bsize;
794 		break;
795 	case Qconfig:
796 		p = "config";
797 		if(UP(d))
798 			size = d->nconfig;
799 		break;
800 	case Qident:
801 		p = "ident";
802 		if(UP(d))
803 			size = sizeof d->ident;
804 		break;
805 	case Qdevlinkdir:
806 		p = "devlink";
807 		t = QTDIR;
808 		perm = 0555;
809 		break;
810 	}
811 	mkqid(&q, QID(UNIT(c->qid), type), vers, t);
812 	devdir(c, q, p, size, eve, perm, dp);
813 	return 1;
814 }
815 
816 static int
topgen(Chan * c,ulong type,Dir * d)817 topgen(Chan *c, ulong type, Dir *d)
818 {
819 	int perm;
820 	vlong size;
821 	char *p;
822 	Qid q;
823 
824 	perm = 0444;
825 	size = 0;
826 	switch(type){
827 	default:
828 		return -1;
829 	case Qtopctl:
830 		p = "ctl";
831 		perm = 0644;
832 		break;
833 	case Qtoplog:
834 		p = "log";
835 		size = eventcount();
836 		break;
837 	}
838 	mkqid(&q, type, 0, QTFILE);
839 	devdir(c, q, p, size, eve, perm, d);
840 	return 1;
841 }
842 
843 static int
aoegen(Chan * c,char *,Dirtab *,int,int s,Dir * dp)844 aoegen(Chan *c, char *, Dirtab *, int, int s, Dir *dp)
845 {
846 	int i;
847 	Aoedev *d;
848 	Qid q;
849 
850 	if(c->qid.path == 0){
851 		switch(s){
852 		case DEVDOTDOT:
853 			q.path = 0;
854 			q.type = QTDIR;
855 			devdir(c, q, "#æ", 0, eve, 0555, dp);
856 			break;
857 		case 0:
858 			q.path = Qtopdir;
859 			q.type = QTDIR;
860 			devdir(c, q, "aoe", 0, eve, 0555, dp);
861 			break;
862 		default:
863 			return -1;
864 		}
865 		return 1;
866 	}
867 
868 	switch(TYPE(c->qid)){
869 	default:
870 		return -1;
871 	case Qtopdir:
872 		if(s == DEVDOTDOT){
873 			mkqid(&q, Qzero, 0, QTDIR);
874 			devdir(c, q, "aoe", 0, eve, 0555, dp);
875 			return 1;
876 		}
877 		if(s < Qtopfiles)
878 			return topgen(c, Qtopbase + s, dp);
879 		s -= Qtopfiles;
880 		if(s >= units.ref)
881 			return -1;
882 		mkqid(&q, QID(s, Qunitdir), 0, QTDIR);
883 		d = unit2dev(s);
884 		assert(d != nil);
885 		devdir(c, q, unitname(d), 0, eve, 0555, dp);
886 		return 1;
887 	case Qtopctl:
888 	case Qtoplog:
889 		return topgen(c, TYPE(c->qid), dp);
890 	case Qunitdir:
891 		if(s == DEVDOTDOT){
892 			mkqid(&q, QID(0, Qtopdir), 0, QTDIR);
893 			uprint("%uld", UNIT(c->qid));
894 			devdir(c, q, up->genbuf, 0, eve, 0555, dp);
895 			return 1;
896 		}
897 		return unitgen(c, Qunitbase+s, dp);
898 	case Qctl:
899 	case Qdata:
900 	case Qconfig:
901 	case Qident:
902 		return unitgen(c, TYPE(c->qid), dp);
903 	case Qdevlinkdir:
904 		i = UNIT(c->qid);
905 		if(s == DEVDOTDOT){
906 			mkqid(&q, QID(i, Qunitdir), 0, QTDIR);
907 			devdir(c, q, "devlink", 0, eve, 0555, dp);
908 			return 1;
909 		}
910 		if(i >= units.ref)
911 			return -1;
912 		d = unit2dev(i);
913 		if(s >= d->ndl)
914 			return -1;
915 		uprint("%d", s);
916 		mkqid(&q, Q3(s, i, Qdevlink), 0, QTFILE);
917 		devdir(c, q, up->genbuf, 0, eve, 0755, dp);
918 		return 1;
919 	case Qdevlink:
920 		uprint("%d", s);
921 		mkqid(&q, Q3(s, UNIT(c->qid), Qdevlink), 0, QTFILE);
922 		devdir(c, q, up->genbuf, 0, eve, 0755, dp);
923 		return 1;
924 	}
925 }
926 
927 static Walkqid*
aoewalk(Chan * c,Chan * nc,char ** name,int nname)928 aoewalk(Chan *c, Chan *nc, char **name, int nname)
929 {
930 	return devwalk(c, nc, name, nname, nil, 0, aoegen);
931 }
932 
933 static int
aoestat(Chan * c,uchar * db,int n)934 aoestat(Chan *c, uchar *db, int n)
935 {
936 	return devstat(c, db, n, nil, 0, aoegen);
937 }
938 
939 static Chan*
aoeopen(Chan * c,int omode)940 aoeopen(Chan *c, int omode)
941 {
942 	Aoedev *d;
943 
944 	if(TYPE(c->qid) != Qdata)
945 		return devopen(c, omode, 0, 0, aoegen);
946 
947 	d = unit2dev(UNIT(c->qid));
948 	qlock(d);
949 	if(waserror()){
950 		qunlock(d);
951 		nexterror();
952 	}
953 	if(!UP(d))
954 		error(Eaoedown);
955 	c = devopen(c, omode, 0, 0, aoegen);
956 	d->nopen++;
957 	poperror();
958 	qunlock(d);
959 	return c;
960 }
961 
962 static void
aoeclose(Chan * c)963 aoeclose(Chan *c)
964 {
965 	Aoedev *d;
966 
967 	if(TYPE(c->qid) != Qdata || (c->flag&COPEN) == 0)
968 		return;
969 
970 	d = unit2dev(UNIT(c->qid));
971 	qlock(d);
972 	if(--d->nopen == 0 && !waserror()){
973 		discover(d->major, d->minor);
974 		poperror();
975 	}
976 	qunlock(d);
977 }
978 
979 static void
atarw(Aoedev * d,Frame * f)980 atarw(Aoedev *d, Frame *f)
981 {
982 	ulong bcnt;
983 	char extbit, writebit;
984 	Aoeata *ah;
985 	Srb *srb;
986 
987 	extbit = 0x4;
988 	writebit = 0x10;
989 
990 	srb = d->inprocess;
991 	bcnt = d->maxbcnt;
992 	if(bcnt > srb->len)
993 		bcnt = srb->len;
994 	f->nhdr = AOEATASZ;
995 	memset(f->hdr, 0, f->nhdr);
996 	ah = (Aoeata*)f->hdr;
997 	if(hset(d, f, ah, ACata) == -1) {
998 		d->inprocess = nil;
999 		return;
1000 	}
1001 	f->dp = srb->dp;
1002 	f->bcnt = bcnt;
1003 	f->lba = srb->sector;
1004 	f->srb = srb;
1005 
1006 	ah->scnt = bcnt / Aoesectsz;
1007 	putlba(ah, f->lba);
1008 	if(d->flag & Dllba)
1009 		ah->aflag |= AAFext;
1010 	else {
1011 		extbit = 0;
1012 		ah->lba[3] &= 0x0f;
1013 		ah->lba[3] |= 0xe0;	/* LBA bit+obsolete 0xa0 */
1014 	}
1015 	if(srb->write){
1016 		ah->aflag |= AAFwrite;
1017 		f->dlen = bcnt;
1018 	}else{
1019 		writebit = 0;
1020 		f->dlen = 0;
1021 	}
1022 	ah->cmdstat = 0x20 | writebit | extbit;
1023 
1024 	/* mark tracking fields and load out */
1025 	srb->nout++;
1026 	srb->dp = (uchar*)srb->dp + bcnt;
1027 	srb->len -= bcnt;
1028 	srb->sector += bcnt / Aoesectsz;
1029 	if(srb->len == 0)
1030 		d->inprocess = nil;
1031 	d->nout++;
1032 	f->dl->npkt++;
1033 	if(waserror()){
1034 		f->tag = Tfree;
1035 		d->inprocess = nil;
1036 		nexterror();
1037 	}
1038 	devtab[f->nl->dc->type]->bwrite(f->nl->dc, allocfb(f), 0);
1039 	poperror();
1040 }
1041 
1042 static char*
aoeerror(Aoehdr * h)1043 aoeerror(Aoehdr *h)
1044 {
1045 	int n;
1046 	static char *errs[] = {
1047 		"aoe protocol error: unknown",
1048 		"aoe protocol error: bad command code",
1049 		"aoe protocol error: bad argument param",
1050 		"aoe protocol error: device unavailable",
1051 		"aoe protocol error: config string present",
1052 		"aoe protocol error: unsupported version",
1053 		"aoe protocol error: target is reserved",
1054 	};
1055 
1056 	if((h->verflag & AFerr) == 0)
1057 		return 0;
1058 	n = h->error;
1059 	if(n > nelem(errs))
1060 		n = 0;
1061 	return errs[n];
1062 }
1063 
1064 static void
rtupdate(Devlink * l,int rtt)1065 rtupdate(Devlink *l, int rtt)
1066 {
1067 	int n;
1068 
1069 	n = rtt;
1070 	if(rtt < 0){
1071 		n = -rtt;
1072 		if(n < Rtmin)
1073 			n = Rtmin;
1074 		else if(n > Rtmax)
1075 			n = Rtmax;
1076 		l->mintimer += (n - l->mintimer) >> 1;
1077 	} else if(n < l->mintimer)
1078 		n = l->mintimer;
1079 	else if(n > Rtmax)
1080 		n = Rtmax;
1081 
1082 	/* g == .25; cf. Congestion Avoidance and Control, Jacobson&Karels; 1988 */
1083 	n -= l->rttavg;
1084 	l->rttavg += n >> 2;
1085 }
1086 
1087 static int
srbready(void * v)1088 srbready(void *v)
1089 {
1090 	Srb *s;
1091 
1092 	s = v;
1093 	return s->error || (s->nout == 0 && s->len == 0);
1094 }
1095 
1096 static Frame*
getframe(Aoedev * d,int tag)1097 getframe(Aoedev *d, int tag)
1098 {
1099 	Frame *f, *e;
1100 
1101 	f = d->frames;
1102 	e = f + d->nframes;
1103 	for(; f < e; f++)
1104 		if(f->tag == tag)
1105 			return f;
1106 	return nil;
1107 }
1108 
1109 static Frame*
freeframe(Aoedev * d)1110 freeframe(Aoedev *d)
1111 {
1112 	if(d->nout < d->maxout)
1113 		return getframe(d, Tfree);
1114 	return nil;
1115 }
1116 
1117 static void
work(Aoedev * d)1118 work(Aoedev *d)
1119 {
1120 	Frame *f;
1121 
1122 	while ((f = freeframe(d)) != nil) {
1123 		if(d->inprocess == nil){
1124 			if(d->head == nil)
1125 				return;
1126 			d->inprocess = d->head;
1127 			d->head = d->head->next;
1128 			if(d->head == nil)
1129 				d->tail = nil;
1130 		}
1131 		atarw(d, f);
1132 	}
1133 }
1134 
1135 static void
strategy(Aoedev * d,Srb * srb)1136 strategy(Aoedev *d, Srb *srb)
1137 {
1138 	qlock(d);
1139 	if(waserror()){
1140 		qunlock(d);
1141 		nexterror();
1142 	}
1143 	srb->next = nil;
1144 	if(d->tail)
1145 		d->tail->next = srb;
1146 	d->tail = srb;
1147 	if(d->head == nil)
1148 		d->head = srb;
1149 	srb->shared = 1;
1150 	work(d);
1151 	poperror();
1152 	qunlock(d);
1153 
1154 	while(waserror())
1155 		;
1156 	sleep(srb, srbready, srb);
1157 	poperror();
1158 }
1159 
1160 #define iskaddr(a)	((uintptr)(a) > KZERO)
1161 
1162 static long
rw(Aoedev * d,int write,uchar * db,long len,uvlong off)1163 rw(Aoedev *d, int write, uchar *db, long len, uvlong off)
1164 {
1165 	long n, nlen, copy;
1166 	enum { Srbsz = 1<<19, };	/* magic allocation */
1167 	Srb *srb;
1168 
1169 	if((off|len) & (Aoesectsz-1))
1170 		error("offset and length must be sector multiple.\n");
1171 	if(off > d->bsize || len == 0)
1172 		return 0;
1173 	if(off + len > d->bsize)
1174 		len = d->bsize - off;
1175 	copy = 0;
1176 	if(iskaddr(db)){
1177 		srb = srbkalloc(db, len);
1178 		copy = 1;
1179 	}else
1180 		srb = srballoc(Srbsz <= len? Srbsz: len);
1181 	if(waserror()){
1182 		srbfree(srb);
1183 		nexterror();
1184 	}
1185 	nlen = len;
1186 	srb->write = write;
1187 	do {
1188 		if(!UP(d))
1189 			error(Eio);
1190 		srb->sector = off / Aoesectsz;
1191 		srb->dp = srb->data;
1192 		n = nlen;
1193 		if(n > Srbsz)
1194 			n = Srbsz;
1195 		srb->len = n;
1196 		if(write && !copy)
1197 			memmove(srb->data, db, n);
1198 		strategy(d, srb);
1199 		if(srb->error)
1200 			error(srb->error);
1201 		if(!write && !copy)
1202 			memmove(db, srb->data, n);
1203 		nlen -= n;
1204 		db += n;
1205 		off += n;
1206 	} while (nlen > 0);
1207 	poperror();
1208 	srbfree(srb);
1209 	return len;
1210 }
1211 
1212 static long
readmem(ulong off,void * dst,long n,void * src,long size)1213 readmem(ulong off, void *dst, long n, void *src, long size)
1214 {
1215 	if(off >= size)
1216 		return 0;
1217 	if(off + n > size)
1218 		n = size - off;
1219 	memmove(dst, (uchar*)src + off, n);
1220 	return n;
1221 }
1222 
1223 static char *
pflag(char * s,char * e,uchar f)1224 pflag(char *s, char *e, uchar f)
1225 {
1226 	uchar i;
1227 
1228 	for(i = 0; i < 8; i++)
1229 		if(f & (1 << i))
1230 			s = seprint(s, e, "%s ", flagname[i]? flagname[i]: "oops");
1231 	return seprint(s, e, "\n");
1232 }
1233 
1234 static int
pstat(Aoedev * d,char * db,int len,int off)1235 pstat(Aoedev *d, char *db, int len, int off)
1236 {
1237 	int i;
1238 	char *state, *s, *p, *e;
1239 
1240 	s = p = malloc(READSTR);
1241 	if(s == nil)
1242 		error(Enomem);
1243 	e = p + READSTR;
1244 
1245 	state = "down";
1246 	if(UP(d))
1247 		state = "up";
1248 
1249 	p = seprint(p, e,
1250 		"state: %s\n"	"nopen: %d\n"	"nout: %d\n"
1251 		"nmaxout: %d\n"	"nframes: %d\n"	"maxbcnt: %d\n"
1252 		"fw: %.4ux\n"
1253 		"model: %s\n"	"serial: %s\n"	"firmware: %s\n",
1254 		state,		d->nopen,	d->nout,
1255 		d->maxout, 	d->nframes,	d->maxbcnt,
1256 		d->fwver,
1257 		d->model, 	d->serial, 	d->firmware);
1258 	p = seprint(p, e, "flag: ");
1259 	p = pflag(p, e, d->flag);
1260 
1261 	if(p - s < len)
1262 		len = p - s;
1263 	i = readstr(off, db, len, s);
1264 	free(s);
1265 	return i;
1266 }
1267 
1268 static long
unitread(Chan * c,void * db,long len,vlong off)1269 unitread(Chan *c, void *db, long len, vlong off)
1270 {
1271 	Aoedev *d;
1272 
1273 	d = unit2dev(UNIT(c->qid));
1274 	if(d->vers != c->qid.vers)
1275 		error(Echange);
1276 	switch(TYPE(c->qid)){
1277 	default:
1278 		error(Ebadarg);
1279 	case Qctl:
1280 		return pstat(d, db, len, off);
1281 	case Qdata:
1282 		return rw(d, Read, db, len, off);
1283 	case Qconfig:
1284 		if (!UP(d))
1285 			error(Eaoedown);
1286 		return readmem(off, db, len, d->config, d->nconfig);
1287 	case Qident:
1288 		if (!UP(d))
1289 			error(Eaoedown);
1290 		return readmem(off, db, len, d->ident, sizeof d->ident);
1291 	}
1292 }
1293 
1294 static int
devlinkread(Chan * c,void * db,int len,int off)1295 devlinkread(Chan *c, void *db, int len, int off)
1296 {
1297 	int i;
1298 	char *s, *p, *e;
1299 	Aoedev *d;
1300 	Devlink *l;
1301 
1302 	d = unit2dev(UNIT(c->qid));
1303 	i = L(c->qid);
1304 	if(i >= d->ndl)
1305 		return 0;
1306 	l = d->dl + i;
1307 
1308 	s = p = malloc(READSTR);
1309 	if(s == nil)
1310 		error(Enomem);
1311 	e = s + READSTR;
1312 
1313 	p = seprint(p, e, "addr: ");
1314 	for(i = 0; i < l->nea; i++)
1315 		p = seprint(p, e, "%E ", l->eatab[i]);
1316 	p = seprint(p, e, "\n");
1317 	p = seprint(p, e, "npkt: %uld\n", l->npkt);
1318 	p = seprint(p, e, "resent: %uld\n", l->resent);
1319 	p = seprint(p, e, "flag: "); p = pflag(p, e, l->flag);
1320 	p = seprint(p, e, "rttavg: %uld\n", TK2MS(l->rttavg));
1321 	p = seprint(p, e, "mintimer: %uld\n", TK2MS(l->mintimer));
1322 
1323 	p = seprint(p, e, "nl path: %s\n", l->nl->path);
1324 	p = seprint(p, e, "nl ea: %E\n", l->nl->ea);
1325 	p = seprint(p, e, "nl flag: "); p = pflag(p, e, l->flag);
1326 	p = seprint(p, e, "nl lostjumbo: %d\n", l->nl->lostjumbo);
1327 	p = seprint(p, e, "nl datamtu: %d\n", l->nl->datamtu);
1328 
1329 	if(p - s < len)
1330 		len = p - s;
1331 	i = readstr(off, db, len, s);
1332 	free(s);
1333 	return i;
1334 }
1335 
1336 static long
topctlread(Chan *,void * db,int len,int off)1337 topctlread(Chan *, void *db, int len, int off)
1338 {
1339 	int i;
1340 	char *s, *p, *e;
1341 	Netlink *n;
1342 
1343 	s = p = malloc(READSTR);
1344 	if(s == nil)
1345 		error(Enomem);
1346 	e = s + READSTR;
1347 
1348 	p = seprint(p, e, "debug: %d\n", debug);
1349 	p = seprint(p, e, "autodiscover: %d\n", autodiscover);
1350 	p = seprint(p, e, "rediscover: %d\n", rediscover);
1351 
1352 	for(i = 0; i < Nnetlink; i++){
1353 		n = netlinks.nl+i;
1354 		if(n->cc == 0)
1355 			continue;
1356 		p = seprint(p, e, "if%d path: %s\n", i, n->path);
1357 		p = seprint(p, e, "if%d ea: %E\n", i, n->ea);
1358 		p = seprint(p, e, "if%d flag: ", i); p = pflag(p, e, n->flag);
1359 		p = seprint(p, e, "if%d lostjumbo: %d\n", i, n->lostjumbo);
1360 		p = seprint(p, e, "if%d datamtu: %d\n", i, n->datamtu);
1361 	}
1362 
1363 	if(p - s < len)
1364 		len = p - s;
1365 	i = readstr(off, db, len, s);
1366 	free(s);
1367 	return i;
1368 }
1369 
1370 static long
aoeread(Chan * c,void * db,long n,vlong off)1371 aoeread(Chan *c, void *db, long n, vlong off)
1372 {
1373 	switch(TYPE(c->qid)){
1374 	default:
1375 		error(Eperm);
1376 	case Qzero:
1377 	case Qtopdir:
1378 	case Qunitdir:
1379 	case Qdevlinkdir:
1380 		return devdirread(c, db, n, 0, 0, aoegen);
1381 	case Qtopctl:
1382 		return topctlread(c, db, n, off);
1383 	case Qtoplog:
1384 		return eventlogread(db, n);
1385 	case Qctl:
1386 	case Qdata:
1387 	case Qconfig:
1388 	case Qident:
1389 		return unitread(c, db, n, off);
1390 	case Qdevlink:
1391 		return devlinkread(c, db, n, off);
1392 	}
1393 }
1394 
1395 static long
configwrite(Aoedev * d,void * db,long len)1396 configwrite(Aoedev *d, void *db, long len)
1397 {
1398 	char *s;
1399 	Aoeqc *ch;
1400 	Frame *f;
1401 	Srb *srb;
1402 
1403 	if(!UP(d))
1404 		error(Eaoedown);
1405 	if(len > ETHERMAXTU - AOEQCSZ)
1406 		error(Etoobig);
1407 	srb = srballoc(len);
1408 	s = malloc(len);
1409 	if(s == nil)
1410 		error(Enomem);
1411 	memmove(s, db, len);
1412 
1413 	if(waserror()){
1414 		srbfree(srb);
1415 		free(s);
1416 		nexterror();
1417 	}
1418 	for (;;) {
1419 		qlock(d);
1420 		if(waserror()){
1421 			qunlock(d);
1422 			nexterror();
1423 		}
1424 		f = freeframe(d);
1425 		if(f != nil)
1426 			break;
1427 		poperror();
1428 		qunlock(d);
1429 
1430 		if(waserror())
1431 			nexterror();
1432 		tsleep(&up->sleep, return0, 0, 100);
1433 		poperror();
1434 	}
1435 	f->nhdr = AOEQCSZ;
1436 	memset(f->hdr, 0, f->nhdr);
1437 	ch = (Aoeqc*)f->hdr;
1438 	if(hset(d, f, ch, ACconfig) == -1) {
1439 		/*
1440 		 * these refer to qlock & waserror in the above for loop.
1441 		 * there's still the first waserror outstanding.
1442 		 */
1443 		poperror();
1444 		qunlock(d);
1445 		return 0;
1446 	}
1447 	srb->shared = 1;
1448 	f->srb = srb;
1449 	f->dp = s;
1450 	ch->verccmd = AQCfset;
1451 	hnputs(ch->cslen, len);
1452 	d->nout++;
1453 	srb->nout++;
1454 	f->dl->npkt++;
1455 	f->dlen = len;
1456 	/* these too */
1457 	poperror();
1458 	qunlock(d);
1459 
1460 	devtab[f->nl->dc->type]->bwrite(f->nl->dc, allocfb(f), 0);
1461 	sleep(srb, srbready, srb);
1462 	if(srb->error)
1463 		error(srb->error);
1464 
1465 	qlock(d);
1466 	if(waserror()){
1467 		qunlock(d);
1468 		nexterror();
1469 	}
1470 	memmove(d->config, s, len);
1471 	d->nconfig = len;
1472 	poperror();
1473 	qunlock(d);
1474 
1475 	poperror();			/* pop first waserror */
1476 
1477 	srbfree(srb);
1478 	memmove(db, s, len);
1479 	free(s);
1480 	return len;
1481 }
1482 
1483 static int getmtu(Chan*);
1484 
1485 static int
devmaxdata(Aoedev * d)1486 devmaxdata(Aoedev *d)		/* return aoe mtu (excluding headers) */
1487 {
1488 	int i, nmtu, mtu;
1489 	Devlink *l;
1490 	Netlink *n;
1491 
1492 	mtu = 100000;
1493 	for(i = 0; i < d->ndl; i++){
1494 		l = d->dl + i;
1495 		n = l->nl;
1496 		if((l->flag & Dup) == 0 || (n->flag & Dup) == 0)
1497 			continue;
1498 		nmtu = getmtu(n->mtu);
1499 		if(mtu > nmtu)
1500 			mtu = nmtu;
1501 	}
1502 	if(mtu == 100000)
1503 		mtu = ETHERMAXTU;		/* normal ethernet mtu */
1504 	mtu -= AOEATASZ;
1505 	mtu -= (uint)mtu % Aoesectsz;
1506 	if(mtu < 2*Aoesectsz)			/* sanity */
1507 		mtu = 2*Aoesectsz;
1508 	return mtu;
1509 }
1510 
1511 static int
toggle(char * s,int f,int bit)1512 toggle(char *s, int f, int bit)
1513 {
1514 	if(s == nil)
1515 		f ^= bit;
1516 	else if(strcmp(s, "on") == 0)
1517 		f |= bit;
1518 	else
1519 		f &= ~bit;
1520 	return f;
1521 }
1522 
1523 static void ataident(Aoedev*);
1524 
1525 static long
unitctlwrite(Aoedev * d,void * db,long n)1526 unitctlwrite(Aoedev *d, void *db, long n)
1527 {
1528 	uint maxbcnt, mtu;
1529 	uvlong bsize;
1530 	enum {
1531 		Failio,
1532 		Ident,
1533 		Jumbo,
1534 		Maxbno,
1535 		Mtu,
1536 		Nofailf,
1537 		Setsize,
1538 	};
1539 	Cmdbuf *cb;
1540 	Cmdtab *ct;
1541 	static Cmdtab cmds[] = {
1542 		{Failio, 	"failio", 	1 },
1543 		{Ident, 	"identify", 	1 },
1544 		{Jumbo, 	"jumbo", 	0 },
1545 		{Maxbno,	"maxbno",	0 },
1546 		{Mtu,		"mtu",		0 },
1547 		{Nofailf,	"nofail",	0 },
1548 		{Setsize, 	"setsize", 	0 },
1549 	};
1550 
1551 	cb = parsecmd(db, n);
1552 	qlock(d);
1553 	if(waserror()){
1554 		qunlock(d);
1555 		free(cb);
1556 		nexterror();
1557 	}
1558 	ct = lookupcmd(cb, cmds, nelem(cmds));
1559 	switch(ct->index){
1560 	case Failio:
1561 		downdev(d, "i/o failure");
1562 		break;
1563 	case Ident:
1564 		ataident(d);
1565 		break;
1566 	case Jumbo:
1567 		d->flag = toggle(cb->f[1], d->flag, Djumbo);
1568 		break;
1569 	case Maxbno:
1570 	case Mtu:
1571 		maxbcnt = devmaxdata(d);
1572 		if(cb->nf > 2)
1573 			error(Ecmdargs);
1574 		if(cb->nf == 2){
1575 			mtu = strtoul(cb->f[1], 0, 0);
1576 			if(ct->index == Maxbno)
1577 				mtu *= Aoesectsz;
1578 			else{
1579 				mtu -= AOEATASZ;
1580 				mtu &= ~(Aoesectsz-1);
1581 			}
1582 			if(mtu == 0 || mtu > maxbcnt)
1583 				cmderror(cb, "mtu out of legal range");
1584 			maxbcnt = mtu;
1585 		}
1586 		d->maxbcnt = maxbcnt;
1587 		break;
1588 	case Nofailf:
1589 		d->flag = toggle(cb->f[1], d->flag, Dnofail);
1590 		break;
1591 	case Setsize:
1592 		bsize = d->realbsize;
1593 		if(cb->nf > 2)
1594 			error(Ecmdargs);
1595 		if(cb->nf == 2){
1596 			bsize = strtoull(cb->f[1], 0, 0);
1597 			if(bsize % Aoesectsz)
1598 				cmderror(cb, "disk size must be sector aligned");
1599 		}
1600 		d->bsize = bsize;
1601 		break;
1602 	default:
1603 		cmderror(cb, "unknown aoe control message");
1604 	}
1605 	poperror();
1606 	qunlock(d);
1607 	free(cb);
1608 	return n;
1609 }
1610 
1611 static long
unitwrite(Chan * c,void * db,long n,vlong off)1612 unitwrite(Chan *c, void *db, long n, vlong off)
1613 {
1614 	long rv;
1615 	char *buf;
1616 	Aoedev *d;
1617 
1618 	d = unit2dev(UNIT(c->qid));
1619 	switch(TYPE(c->qid)){
1620 	default:
1621 		error(Ebadarg);
1622 	case Qctl:
1623 		return unitctlwrite(d, db, n);
1624 	case Qident:
1625 		error(Eperm);
1626 	case Qdata:
1627 		return rw(d, Write, db, n, off);
1628 	case Qconfig:
1629 		if(off + n > sizeof d->config)
1630 			error(Etoobig);
1631 		buf = malloc(sizeof d->config);
1632 		if(buf == nil)
1633 			error(Enomem);
1634 		if(waserror()){
1635 			free(buf);
1636 			nexterror();
1637 		}
1638 		memmove(buf, d->config, d->nconfig);
1639 		memmove(buf + off, db, n);
1640 		rv = configwrite(d, buf, n + off);
1641 		poperror();
1642 		free(buf);
1643 		return rv;
1644 	}
1645 }
1646 
1647 static Netlink*
addnet(char * path,Chan * cc,Chan * dc,Chan * mtu,uchar * ea)1648 addnet(char *path, Chan *cc, Chan *dc, Chan *mtu, uchar *ea)
1649 {
1650 	Netlink *nl, *e;
1651 
1652 	lock(&netlinks);
1653 	if(waserror()){
1654 		unlock(&netlinks);
1655 		nexterror();
1656 	}
1657 	nl = netlinks.nl;
1658 	e = nl + nelem(netlinks.nl);
1659 	for(; nl < e && nl->cc; nl++)
1660 		continue;
1661 	if (nl >= e)
1662 		error("out of netlink structures");
1663 	nl->cc = cc;
1664 	nl->dc = dc;
1665 	nl->mtu = mtu;
1666 	strncpy(nl->path, path, sizeof nl->path);
1667 	memmove(nl->ea, ea, sizeof nl->ea);
1668 	poperror();
1669 	nl->flag |= Dup;
1670 	unlock(&netlinks);
1671 	return nl;
1672 }
1673 
1674 static int
newunit(void)1675 newunit(void)
1676 {
1677 	int x;
1678 
1679 	lock(&units);
1680 	if(units.ref == Maxunits)
1681 		x = -1;
1682 	else
1683 		x = units.ref++;
1684 	unlock(&units);
1685 	return x;
1686 }
1687 
1688 static int
dropunit(void)1689 dropunit(void)
1690 {
1691 	int x;
1692 
1693 	lock(&units);
1694 	x = --units.ref;
1695 	unlock(&units);
1696 	return x;
1697 }
1698 
1699 /*
1700  * always allocate max frames.  maxout may change.
1701  */
1702 static Aoedev*
newdev(long major,long minor,int n)1703 newdev(long major, long minor, int n)
1704 {
1705 	Aoedev *d;
1706 	Frame *f, *e;
1707 
1708 	d = mallocz(sizeof *d, 1);
1709 	f = mallocz(sizeof *f * Maxframes, 1);
1710 	if (!d || !f) {
1711 		free(d);
1712 		free(f);
1713 		error("aoe device allocation failure");
1714 	}
1715 	d->nframes = n;
1716 	d->frames = f;
1717 	for (e = f + n; f < e; f++)
1718 		f->tag = Tfree;
1719 	d->maxout = n;
1720 	d->major = major;
1721 	d->minor = minor;
1722 	d->maxbcnt = Dbcnt;
1723 	d->flag = Djumbo;
1724 	d->unit = newunit();		/* bzzt.  inaccurate if units removed */
1725 	if(d->unit == -1){
1726 		free(d->frames);
1727 		free(d);
1728 		error("too many units");
1729 	}
1730 	d->dl = d->dltab;
1731 	return d;
1732 }
1733 
1734 static Aoedev*
mm2dev(int major,int minor)1735 mm2dev(int major, int minor)
1736 {
1737 	Aoedev *d;
1738 
1739 	rlock(&devs);
1740 	for(d = devs.d; d; d = d->next)
1741 		if(d->major == major && d->minor == minor){
1742 			runlock(&devs);
1743 			return d;
1744 		}
1745 	runlock(&devs);
1746 	eventlog("mm2dev: %d.%d not found\n", major, minor);
1747 	return nil;
1748 }
1749 
1750 /* Find the device in our list.  If not known, add it */
1751 static Aoedev*
getdev(long major,long minor,int n)1752 getdev(long major, long minor, int n)
1753 {
1754 	Aoedev *d;
1755 
1756 	if(major == 0xffff || minor == 0xff)
1757 		return 0;
1758 	wlock(&devs);
1759 	if(waserror()){
1760 		wunlock(&devs);
1761 		nexterror();
1762 	}
1763 	for(d = devs.d; d; d = d->next)
1764 		if(d->major == major && d->minor == minor)
1765 			break;
1766 	if (d == nil) {
1767 		d = newdev(major, minor, n);
1768 		d->next = devs.d;
1769 		devs.d = d;
1770 	}
1771 	poperror();
1772 	wunlock(&devs);
1773 	return d;
1774 }
1775 
1776 static ushort
gbit16(void * a)1777 gbit16(void *a)
1778 {
1779 	uchar *i;
1780 
1781 	i = a;
1782 	return i[1] << 8 | i[0];
1783 }
1784 
1785 static ulong
gbit32(void * a)1786 gbit32(void *a)
1787 {
1788 	ulong j;
1789 	uchar *i;
1790 
1791 	i = a;
1792 	j  = i[3] << 24;
1793 	j |= i[2] << 16;
1794 	j |= i[1] << 8;
1795 	j |= i[0];
1796 	return j;
1797 }
1798 
1799 static uvlong
gbit64(void * a)1800 gbit64(void *a)
1801 {
1802 	uchar *i;
1803 
1804 	i = a;
1805 	return (uvlong)gbit32(i+4) << 32 | gbit32(a);
1806 }
1807 
1808 static void
ataident(Aoedev * d)1809 ataident(Aoedev *d)
1810 {
1811 	Aoeata *a;
1812 	Block *b;
1813 	Frame *f;
1814 
1815 	f = freeframe(d);
1816 	if(f == nil)
1817 		return;
1818 	f->nhdr = AOEATASZ;
1819 	memset(f->hdr, 0, f->nhdr);
1820 	a = (Aoeata*)f->hdr;
1821 	if(hset(d, f, a, ACata) == -1)
1822 		return;
1823 	a->cmdstat = Cid;	/* ata 6, page 110 */
1824 	a->scnt = 1;
1825 	a->lba[3] = 0xa0;
1826 	d->nout++;
1827 	f->dl->npkt++;
1828 	f->bcnt = 512;
1829 	f->dlen = 0;
1830 	b = allocfb(f);
1831 	devtab[f->nl->dc->type]->bwrite(f->nl->dc, b, 0);
1832 }
1833 
1834 static int
getmtu(Chan * mtuch)1835 getmtu(Chan *mtuch)
1836 {
1837 	int n, mtu;
1838 	char buf[36];
1839 
1840 	mtu = ETHERMAXTU;
1841 	if(mtuch == nil || waserror())
1842 		return mtu;
1843 	n = devtab[mtuch->type]->read(mtuch, buf, sizeof buf - 1, 0);
1844 	if(n > 12){
1845 		buf[n] = 0;
1846 		mtu = strtoul(buf + 12, 0, 0);
1847 	}
1848 	poperror();
1849 	return mtu;
1850 }
1851 
1852 static int
newdlea(Devlink * l,uchar * ea)1853 newdlea(Devlink *l, uchar *ea)
1854 {
1855 	int i;
1856 	uchar *t;
1857 
1858 	for(i = 0; i < Nea; i++){
1859 		t = l->eatab[i];
1860 		if(i == l->nea){
1861 			memmove(t, ea, Eaddrlen);
1862 			return l->nea++;
1863 		}
1864 		if(memcmp(t, ea, Eaddrlen) == 0)
1865 			return i;
1866 	}
1867 	return -1;
1868 }
1869 
1870 static Devlink*
newdevlink(Aoedev * d,Netlink * n,Aoeqc * c)1871 newdevlink(Aoedev *d, Netlink *n, Aoeqc *c)
1872 {
1873 	int i;
1874 	Devlink *l;
1875 
1876 	for(i = 0; i < Ndevlink; i++){
1877 		l = d->dl + i;
1878 		if(i == d->ndl){
1879 			d->ndl++;
1880 			newdlea(l, c->src);
1881 			l->nl = n;
1882 			l->flag |= Dup;
1883 			l->mintimer = Rtmin;
1884 			l->rttavg = Rtmax;
1885 			return l;
1886 		}
1887 		if(l->nl == n) {
1888 			newdlea(l, c->src);
1889 			l->flag |= Dup;
1890 			return l;
1891 		}
1892 	}
1893 	eventlog("%æ: out of links: %s:%E to %E\n", d, n->path, n->ea, c->src);
1894 	return 0;
1895 }
1896 
1897 static void
errrsp(Block * b,char * s)1898 errrsp(Block *b, char *s)
1899 {
1900 	int n;
1901 	Aoedev *d;
1902 	Aoehdr *h;
1903 	Frame *f;
1904 
1905 	h = (Aoehdr*)b->rp;
1906 	n = nhgetl(h->tag);
1907 	if(n == Tmgmt || n == Tfree)
1908 		return;
1909 	d = mm2dev(nhgets(h->major), h->minor);
1910 	if(d == 0)
1911 		return;
1912 	if(f = getframe(d, n))
1913 		frameerror(d, f, s);
1914 }
1915 
1916 static void
qcfgrsp(Block * b,Netlink * nl)1917 qcfgrsp(Block *b, Netlink *nl)
1918 {
1919 	int major, cmd, cslen, blen;
1920 	unsigned n;
1921 	Aoedev *d;
1922 	Aoeqc *ch;
1923 	Devlink *l;
1924 	Frame *f;
1925 
1926 	ch = (Aoeqc*)b->rp;
1927 	major = nhgets(ch->major);
1928 	n = nhgetl(ch->tag);
1929 	if(n != Tmgmt){
1930 		d = mm2dev(major, ch->minor);
1931 		if(d == nil)
1932 			return;
1933 		qlock(d);
1934 		f = getframe(d, n);
1935 		if(f == nil){
1936 			qunlock(d);
1937 			eventlog("%æ: unknown response tag %ux\n", d, n);
1938 			return;
1939 		}
1940 		cslen = nhgets(ch->cslen);
1941 		blen = BLEN(b) - AOEQCSZ;
1942 		if(cslen < blen && BLEN(b) > 60)
1943 			eventlog("%æ: cfgrsp: tag %.8ux oversized %d %d\n",
1944 				d, n, cslen, blen);
1945 		if(cslen > blen){
1946 			eventlog("%æ: cfgrsp: tag %.8ux runt %d %d\n",
1947 				d, n, cslen, blen);
1948 			cslen = blen;
1949 		}
1950 		memmove(f->dp, ch + 1, cslen);
1951 		f->srb->nout--;
1952 		wakeup(f->srb);
1953 		f->srb->shared = 0;
1954 		d->nout--;
1955 		f->srb = nil;
1956 		f->tag = Tfree;
1957 		qunlock(d);
1958 		return;
1959 	}
1960 
1961 	cmd = ch->verccmd & 0xf;
1962 	if(cmd != 0){
1963 		eventlog("aoe%d.%d: cfgrsp: bad command %d\n", major, ch->minor, cmd);
1964 		return;
1965 	}
1966 	n = nhgets(ch->bufcnt);
1967 	if(n > Maxframes)
1968 		n = Maxframes;
1969 
1970 	if(waserror()){
1971 		eventlog("getdev: %d.%d ignored: %s\n", major, ch->minor, up->errstr);
1972 		return;
1973 	}
1974 	d = getdev(major, ch->minor, n);
1975 	poperror();
1976 	if(d == 0)
1977 		return;
1978 
1979 	qlock(d);
1980 	*up->errstr = 0;
1981 	if(waserror()){
1982 		qunlock(d);
1983 		eventlog("%æ: %s\n", d, up->errstr);
1984 		nexterror();
1985 	}
1986 
1987 	l = newdevlink(d, nl, ch);		/* add this interface. */
1988 
1989 	d->fwver = nhgets(ch->fwver);
1990 	n = nhgets(ch->cslen);
1991 	if(n > sizeof d->config)
1992 		n = sizeof d->config;
1993 	d->nconfig = n;
1994 	memmove(d->config, ch + 1, n);
1995 	if(l != 0 && d->flag & Djumbo){
1996 		n = getmtu(nl->mtu) - AOEATASZ;
1997 		n /= Aoesectsz;
1998 		if(n > ch->scnt)
1999 			n = ch->scnt;
2000 		n = n? n * Aoesectsz: Dbcnt;
2001 		if(n != d->maxbcnt){
2002 			eventlog("%æ: setting %d byte data frames on %s:%E\n",
2003 				d, n, nl->path, nl->ea);
2004 			d->maxbcnt = n;
2005 		}
2006 	}
2007 	if(d->nopen == 0)
2008 		ataident(d);
2009 	poperror();
2010 	qunlock(d);
2011 }
2012 
2013 void
aoeidmove(char * p,ushort * u,unsigned n)2014 aoeidmove(char *p, ushort *u, unsigned n)
2015 {
2016 	int i;
2017 	char *op, *e, *s;
2018 
2019 	op = p;
2020 	/*
2021 	 * the ushort `*u' is sometimes not aligned on a short boundary,
2022 	 * so dereferencing u[i] causes an alignment exception on
2023 	 * some machines.
2024 	 */
2025 	s = (char *)u;
2026 	for(i = 0; i < n; i += 2){
2027 		*p++ = s[i + 1];
2028 		*p++ = s[i];
2029 	}
2030 	*p = 0;
2031 	while(p > op && *--p == ' ')
2032 		*p = 0;
2033 	e = p;
2034 	p = op;
2035 	while(*p == ' ')
2036 		p++;
2037 	memmove(op, p, n - (e - p));
2038 }
2039 
2040 static vlong
aoeidentify(Aoedev * d,ushort * id)2041 aoeidentify(Aoedev *d, ushort *id)
2042 {
2043 	int i;
2044 	vlong s;
2045 
2046 	d->flag &= ~(Dllba|Dpower|Dsmart|Dnop|Dup);
2047 
2048 	i = gbit16(id+83) | gbit16(id+86);
2049 	if(i & (1<<10)){
2050 		d->flag |= Dllba;
2051 		s = gbit64(id+100);
2052 	}else
2053 		s = gbit32(id+60);
2054 
2055 	i = gbit16(id+83);
2056 	if((i>>14) == 1) {
2057 		if(i & (1<<3))
2058 			d->flag  |= Dpower;
2059 		i = gbit16(id+82);
2060 		if(i & 1)
2061 			d->flag  |= Dsmart;
2062 		if(i & (1<<14))
2063 			d->flag  |= Dnop;
2064 	}
2065 //	eventlog("%æ up\n", d);
2066 	d->flag |= Dup;
2067 	memmove(d->ident, id, sizeof d->ident);
2068 	return s;
2069 }
2070 
2071 static void
newvers(Aoedev * d)2072 newvers(Aoedev *d)
2073 {
2074 	lock(&drivevers);
2075 	d->vers = drivevers.ref++;
2076 	unlock(&drivevers);
2077 }
2078 
2079 static int
identify(Aoedev * d,ushort * id)2080 identify(Aoedev *d, ushort *id)
2081 {
2082 	vlong osectors, s;
2083 	uchar oserial[21];
2084 
2085 	s = aoeidentify(d, id);
2086 	if(s == -1)
2087 		return -1;
2088 	osectors = d->realbsize;
2089 	memmove(oserial, d->serial, sizeof d->serial);
2090 
2091 	aoeidmove(d->serial, id+10, 20);
2092 	aoeidmove(d->firmware, id+23, 8);
2093 	aoeidmove(d->model, id+27, 40);
2094 
2095 	s *= Aoesectsz;
2096 	if((osectors == 0 || osectors != s) &&
2097 	    memcmp(oserial, d->serial, sizeof oserial) != 0){
2098 		d->bsize = s;
2099 		d->realbsize = s;
2100 //		d->mediachange = 1;
2101 		newvers(d);
2102 	}
2103 	return 0;
2104 }
2105 
2106 static void
atarsp(Block * b)2107 atarsp(Block *b)
2108 {
2109 	unsigned n;
2110 	short major;
2111 	Aoeata *ahin, *ahout;
2112 	Aoedev *d;
2113 	Frame *f;
2114 	Srb *srb;
2115 
2116 	ahin = (Aoeata*)b->rp;
2117 	major = nhgets(ahin->major);
2118 	d = mm2dev(major, ahin->minor);
2119 	if(d == nil)
2120 		return;
2121 	qlock(d);
2122 	if(waserror()){
2123 		qunlock(d);
2124 		nexterror();
2125 	}
2126 	n = nhgetl(ahin->tag);
2127 	f = getframe(d, n);
2128 	if(f == nil){
2129 		dprint("%æ: unexpected response; tag %ux\n", d, n);
2130 		goto bail;
2131 	}
2132 	rtupdate(f->dl, tsince(f->tag));
2133 	ahout = (Aoeata*)f->hdr;
2134 	srb = f->srb;
2135 
2136 	if(ahin->cmdstat & 0xa9){
2137 		eventlog("%æ: ata error cmd %.2ux stat %.2ux\n",
2138 			d, ahout->cmdstat, ahin->cmdstat);
2139 		if(srb)
2140 			srb->error = Eio;
2141 	} else {
2142 		n = ahout->scnt * Aoesectsz;
2143 		switch(ahout->cmdstat){
2144 		case Crd:
2145 		case Crdext:
2146 			if(BLEN(b) - AOEATASZ < n){
2147 				eventlog("%æ: runt read blen %ld expect %d\n",
2148 					d, BLEN(b), n);
2149 				goto bail;
2150 			}
2151 			memmove(f->dp, (uchar *)ahin + AOEATASZ, n);
2152 		case Cwr:
2153 		case Cwrext:
2154 			if(n > Dbcnt)
2155 				f->nl->lostjumbo = 0;
2156 			if(f->bcnt -= n){
2157 				f->lba += n / Aoesectsz;
2158 				f->dp = (uchar*)f->dp + n;
2159 				resend(d, f);
2160 				goto bail;
2161 			}
2162 			break;
2163 		case Cid:
2164 			if(BLEN(b) - AOEATASZ < 512){
2165 				eventlog("%æ: runt identify blen %ld expect %d\n",
2166 					d, BLEN(b), n);
2167 				goto bail;
2168 			}
2169 			identify(d, (ushort*)((uchar *)ahin + AOEATASZ));
2170 			break;
2171 		default:
2172 			eventlog("%æ: unknown ata command %.2ux \n",
2173 				d, ahout->cmdstat);
2174 		}
2175 	}
2176 
2177 	if(srb && --srb->nout == 0 && srb->len == 0){
2178 		wakeup(srb);
2179 		srb->shared = 0;
2180 	}
2181 	f->srb = nil;
2182 	f->tag = Tfree;
2183 	d->nout--;
2184 
2185 	work(d);
2186 bail:
2187 	poperror();
2188 	qunlock(d);
2189 }
2190 
2191 static void
netrdaoeproc(void * v)2192 netrdaoeproc(void *v)
2193 {
2194 	int idx;
2195 	char name[Maxpath+1], *s;
2196 	Aoehdr *h;
2197 	Block *b;
2198 	Netlink *nl;
2199 
2200 	nl = (Netlink*)v;
2201 	idx = nl - netlinks.nl;
2202 	netlinks.reader[idx] = 1;
2203 	kstrcpy(name, nl->path, Maxpath);
2204 
2205 	if(waserror()){
2206 		eventlog("netrdaoe exiting: %s\n", up->errstr);
2207 		netlinks.reader[idx] = 0;
2208 		wakeup(netlinks.rendez + idx);
2209 		pexit(up->errstr, 1);
2210 	}
2211 	if(autodiscover)
2212 		discover(0xffff, 0xff);
2213 	for (;;) {
2214 		if(!(nl->flag & Dup)) {
2215 			uprint("%s: netlink is down", name);
2216 			error(up->genbuf);
2217 		}
2218 		if (nl->dc == nil)
2219 			panic("netrdaoe: nl->dc == nil");
2220 		b = devtab[nl->dc->type]->bread(nl->dc, 1<<16, 0);
2221 		if(b == nil) {
2222 			uprint("%s: nil read from network", name);
2223 			error(up->genbuf);
2224 		}
2225 		h = (Aoehdr*)b->rp;
2226 		if(h->verflag & AFrsp)
2227 			if(s = aoeerror(h)){
2228 				eventlog("%s: %s\n", nl->path, up->errstr);
2229 				errrsp(b, s);
2230 			}else
2231 				switch(h->cmd){
2232 				case ACata:
2233 					atarsp(b);
2234 					break;
2235 				case ACconfig:
2236 					qcfgrsp(b, nl);
2237 					break;
2238 				default:
2239 					if((h->cmd & 0xf0) == 0){
2240 						eventlog("%s: unknown cmd %d\n",
2241 							nl->path, h->cmd);
2242 						errrsp(b, "unknown command");
2243 					}
2244 					break;
2245 				}
2246 		freeb(b);
2247 	}
2248 }
2249 
2250 static void
getaddr(char * path,uchar * ea)2251 getaddr(char *path, uchar *ea)
2252 {
2253 	int n;
2254 	char buf[2*Eaddrlen+1];
2255 	Chan *c;
2256 
2257 	uprint("%s/addr", path);
2258 	c = namec(up->genbuf, Aopen, OREAD, 0);
2259 	if(waserror()) {
2260 		cclose(c);
2261 		nexterror();
2262 	}
2263 	if (c == nil)
2264 		panic("æ: getaddr: c == nil");
2265 	n = devtab[c->type]->read(c, buf, sizeof buf-1, 0);
2266 	poperror();
2267 	cclose(c);
2268 	buf[n] = 0;
2269 	if(parseether(ea, buf) < 0)
2270 		error("parseether failure");
2271 }
2272 
2273 static void
netbind(char * path)2274 netbind(char *path)
2275 {
2276 	char addr[Maxpath];
2277 	uchar ea[2*Eaddrlen+1];
2278 	Chan *dc, *cc, *mtu;
2279 	Netlink *nl;
2280 
2281 	snprint(addr, sizeof addr, "%s!%#x", path, Aoetype);
2282 	dc = chandial(addr, nil, nil, &cc);
2283 	snprint(addr, sizeof addr, "%s/mtu", path);
2284 	if(waserror())
2285 		mtu = nil;
2286 	else {
2287 		mtu = namec(addr, Aopen, OREAD, 0);
2288 		poperror();
2289 	}
2290 
2291 	if(waserror()){
2292 		cclose(dc);
2293 		cclose(cc);
2294 		if(mtu)
2295 			cclose(mtu);
2296 		nexterror();
2297 	}
2298 	if(dc == nil  || cc == nil)
2299 		error(Enonexist);
2300 	getaddr(path, ea);
2301 	nl = addnet(path, cc, dc, mtu, ea);
2302 	snprint(addr, sizeof addr, "netrdaoe@%s", path);
2303 	kproc(addr, netrdaoeproc, nl);
2304 	poperror();
2305 }
2306 
2307 static int
unbound(void * v)2308 unbound(void *v)
2309 {
2310 	return *(int*)v != 0;
2311 }
2312 
2313 static void
netunbind(char * path)2314 netunbind(char *path)
2315 {
2316 	int i, idx;
2317 	Aoedev *d, *p, *next;
2318 	Chan *dc, *cc;
2319 	Devlink *l;
2320 	Frame *f;
2321 	Netlink *n, *e;
2322 
2323 	n = netlinks.nl;
2324 	e = n + nelem(netlinks.nl);
2325 
2326 	lock(&netlinks);
2327 	for(; n < e; n++)
2328 		if(n->dc && strcmp(n->path, path) == 0)
2329 			break;
2330 	unlock(&netlinks);
2331 	if (n >= e)
2332 		error("device not bound");
2333 
2334 	/*
2335 	 * hunt down devices using this interface; disable
2336 	 * this also terminates the reader.
2337 	 */
2338 	idx = n - netlinks.nl;
2339 	wlock(&devs);
2340 	for(d = devs.d; d; d = d->next){
2341 		qlock(d);
2342 		for(i = 0; i < d->ndl; i++){
2343 			l = d->dl + i;
2344 			if(l->nl == n)
2345 				l->flag &= ~Dup;
2346 		}
2347 		qunlock(d);
2348 	}
2349 	n->flag &= ~Dup;
2350 	wunlock(&devs);
2351 
2352 	/* confirm reader is down. */
2353 	while(waserror())
2354 		;
2355 	sleep(netlinks.rendez + idx, unbound, netlinks.reader + idx);
2356 	poperror();
2357 
2358 	/* reschedule packets. */
2359 	wlock(&devs);
2360 	for(d = devs.d; d; d = d->next){
2361 		qlock(d);
2362 		for(i = 0; i < d->nframes; i++){
2363 			f = d->frames + i;
2364 			if(f->tag != Tfree && f->nl == n)
2365 				resend(d, f);
2366 		}
2367 		qunlock(d);
2368 	}
2369 	wunlock(&devs);
2370 
2371 	/* squeeze devlink pool.  (we assert nobody is using them now) */
2372 	wlock(&devs);
2373 	for(d = devs.d; d; d = d->next){
2374 		qlock(d);
2375 		for(i = 0; i < d->ndl; i++){
2376 			l = d->dl + i;
2377 			if(l->nl == n)
2378 				memmove(l, l + 1, sizeof *l * (--d->ndl - i));
2379 		}
2380 		qunlock(d);
2381 	}
2382 	wunlock(&devs);
2383 
2384 	/* close device link. */
2385 	lock(&netlinks);
2386 	dc = n->dc;
2387 	cc = n->cc;
2388 	if(n->mtu)
2389 		cclose(n->mtu);
2390 	memset(n, 0, sizeof *n);
2391 	unlock(&netlinks);
2392 
2393 	cclose(dc);
2394 	cclose(cc);
2395 
2396 	/* squeeze orphan devices */
2397 	wlock(&devs);
2398 	for(p = d = devs.d; d; d = next){
2399 		next = d->next;
2400 		if(d->ndl > 0) {
2401 			p = d;
2402 			continue;
2403 		}
2404 		qlock(d);
2405 		downdev(d, "orphan");
2406 		qunlock(d);
2407 		if(p != devs.d)
2408 			p->next = next;
2409 		else{
2410 			devs.d = next;
2411 			p = devs.d;
2412 		}
2413 		free(d->frames);
2414 		free(d);
2415 		dropunit();
2416 	}
2417 	wunlock(&devs);
2418 }
2419 
2420 static void
removeaoedev(Aoedev * d)2421 removeaoedev(Aoedev *d)
2422 {
2423 	int i;
2424 	Aoedev *p;
2425 
2426 	wlock(&devs);
2427 	p = 0;
2428 	if(d != devs.d)
2429 		for(p = devs.d; p; p = p->next)
2430 			if(p->next == d)
2431 				break;
2432 	qlock(d);
2433 	d->flag &= ~Dup;
2434 
2435 	/*
2436 	 * Changing the version number is, strictly speaking, correct,
2437  	 * but doing so means that deleting a LUN that is not in use
2438 	 * invalidates all other LUNs too.  If your file server has
2439 	 * venti arenas or fossil file systems on 1.0, and you delete 1.1,
2440 	 * since you no longer need it, 1.0 will become inaccessible to your
2441 	 * file server, which will eventually panic.  Note that newdev()
2442 	 * does not change the version number.
2443 	 */
2444 	// newvers(d);
2445 
2446 	d->ndl = 0;
2447 	qunlock(d);
2448 	for(i = 0; i < d->nframes; i++)
2449 		frameerror(d, d->frames+i, Eaoedown);
2450 
2451 	if(p)
2452 		p->next = d->next;
2453 	else
2454 		devs.d = d->next;
2455 	free(d->frames);
2456 	free(d);
2457 	dropunit();
2458 	wunlock(&devs);
2459 }
2460 
2461 static void
removedev(char * name)2462 removedev(char *name)
2463 {
2464 	Aoedev *d, *p;
2465 
2466 	wlock(&devs);
2467 	for(p = d = devs.d; d; p = d, d = d->next)
2468 		if(strcmp(name, unitname(d)) == 0) {
2469 			wunlock(&devs);
2470 			removeaoedev(p);
2471 			return;
2472 		}
2473 	wunlock(&devs);
2474 	error("device not bound");
2475 }
2476 
2477 static void
discoverstr(char * f)2478 discoverstr(char *f)
2479 {
2480 	ushort shelf, slot;
2481 	ulong sh;
2482 	char *s;
2483 
2484 	if(f == 0){
2485 		discover(0xffff, 0xff);
2486 		return;
2487 	}
2488 
2489 	shelf = sh = strtol(f, &s, 0);
2490 	if(s == f || sh > 0xffff)
2491 		error("bad shelf");
2492 	f = s;
2493 	if(*f++ == '.'){
2494 		slot = strtol(f, &s, 0);
2495 		if(s == f || slot > 0xff)
2496 			error("bad shelf");
2497 	}else
2498 		slot = 0xff;
2499 	discover(shelf, slot);
2500 }
2501 
2502 
2503 static void
aoeremove(Chan * c)2504 aoeremove(Chan *c)
2505 {
2506 	switch(TYPE(c->qid)){
2507 	default:
2508 		error(Eperm);
2509 	case Qunitdir:
2510 		removeaoedev(unit2dev(UNIT(c->qid)));
2511 		break;
2512 	}
2513 }
2514 
2515 static long
topctlwrite(void * db,long n)2516 topctlwrite(void *db, long n)
2517 {
2518 	enum {
2519 		Autodiscover,
2520 		Bind,
2521 		Debug,
2522 		Discover,
2523 		Rediscover,
2524 		Remove,
2525 		Unbind,
2526 	};
2527 	char *f;
2528 	Cmdbuf *cb;
2529 	Cmdtab *ct;
2530 	static Cmdtab cmds[] = {
2531 		{ Autodiscover,	"autodiscover",	0	},
2532 		{ Bind, 	"bind", 	2	},
2533 		{ Debug, 	"debug", 	0	},
2534 		{ Discover, 	"discover", 	0	},
2535 		{ Rediscover,	"rediscover",	0	},
2536 		{ Remove,	"remove",	2	},
2537 		{ Unbind,	"unbind",	2	},
2538 	};
2539 
2540 	cb = parsecmd(db, n);
2541 	if(waserror()){
2542 		free(cb);
2543 		nexterror();
2544 	}
2545 	ct = lookupcmd(cb, cmds, nelem(cmds));
2546 	f = cb->f[1];
2547 	switch(ct->index){
2548 	case Autodiscover:
2549 		autodiscover = toggle(f, autodiscover, 1);
2550 		break;
2551 	case Bind:
2552 		netbind(f);
2553 		break;
2554 	case Debug:
2555 		debug = toggle(f, debug, 1);
2556 		break;
2557 	case Discover:
2558 		discoverstr(f);
2559 		break;
2560 	case Rediscover:
2561 		rediscover = toggle(f, rediscover, 1);
2562 		break;
2563 	case Remove:
2564 		removedev(f);
2565 		break;
2566 	case Unbind:
2567 		netunbind(f);
2568 		break;
2569 	default:
2570 		cmderror(cb, "unknown aoe control message");
2571 	}
2572 	poperror();
2573 	free(cb);
2574 	return n;
2575 }
2576 
2577 static long
aoewrite(Chan * c,void * db,long n,vlong off)2578 aoewrite(Chan *c, void *db, long n, vlong off)
2579 {
2580 	switch(TYPE(c->qid)){
2581 	default:
2582 	case Qzero:
2583 	case Qtopdir:
2584 	case Qunitdir:
2585 	case Qtoplog:
2586 		error(Eperm);
2587 	case Qtopctl:
2588 		return topctlwrite(db, n);
2589 	case Qctl:
2590 	case Qdata:
2591 	case Qconfig:
2592 	case Qident:
2593 		return unitwrite(c, db, n, off);
2594 	}
2595 }
2596 
2597 Dev aoedevtab = {
2598 	L'æ',
2599 	"aoe",
2600 
2601 	devreset,
2602 	devinit,
2603 	devshutdown,
2604 	aoeattach,
2605 	aoewalk,
2606 	aoestat,
2607 	aoeopen,
2608 	devcreate,
2609 	aoeclose,
2610 	aoeread,
2611 	devbread,
2612 	aoewrite,
2613 	devbwrite,
2614 	aoeremove,
2615 	devwstat,
2616 	devpower,
2617 	devconfig,
2618 };
2619