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