3 * aoe storage initiator
7 #include "../port/lib.h"
13 #include "../port/error.h"
14 #include "../port/netif.h"
17 #include "../port/aoe.h"
20 #pragma varargck argpos eventlog 1
22 #define dprint(...) if(debug) eventlog(__VA_ARGS__); else USED(debug);
23 #define uprint(...) snprint(up->genbuf, sizeof up->genbuf, __VA_ARGS__);
29 Maxtype = (1<<Typebits)-1,
30 Maxunits = (1<<Unitbits)-1,
31 Maxl3 = (1<<L3bits)-1,
39 #define TYPE(q) ((ulong)(q).path & Maxtype)
40 #define UNIT(q) (((ulong)(q).path>>Typebits) & Maxunits)
41 #define L(q) (((ulong)(q).path>>Typebits+Unitbits) & Maxl3)
42 #define QID(u, t) ((u)<<Typebits | (t))
43 #define Q3(l, u, t) ((l)<<Typebits+Unitbits | QID(u, t))
44 #define UP(d) ((d)->flag & Dup)
46 #define Ticks MACHP(0)->ticks
47 #define Ms2tk(t) (((t)*HZ)/1000)
48 #define Tk2ms(t) (((t)*1000)/HZ)
67 Qdevlink = Qdevlinkbase,
70 Qtopfiles = Qtopend-Qtopbase,
71 Qdevlinkfiles = Qdevlinkend-Qdevlinkbase,
81 /* round trip bounds, timeouts, in ticks */
104 * unified set of flags
105 * a Netlink + Aoedev most both be jumbo capable
106 * to send jumbograms to that interface.
114 static char *flagname[] = {
126 Chan *mtu; /* open early to prevent bind issues. */
135 uchar eatab[Nea][Eaddrlen];
145 typedef struct Srb Srb;
167 uchar hdr[ETHERMINTU];
175 typedef struct Aoedev Aoedev;
185 Devlink dltab[Ndevlink];
218 #pragma varargck type "æ" Aoedev*
224 char buf[Eventlen*Nevents];
237 int reader[Nnetlink]; /* reader is running. */
238 Rendez rendez[Nnetlink]; /* confirm exit. */
239 Netlink nl[Nnetlink];
242 extern Dev aoedevtab;
244 static Ref drivevers;
246 static int autodiscover = 1;
247 static int rediscover;
248 extern char Enotup[] = "aoe device is down";
255 srb = smalloc(sizeof *srb+sz);
257 srb->dp = srb->data = srb+1;
258 srb->ticksent = Ticks;
263 srbkalloc(void *db, ulong)
267 srb = smalloc(sizeof *srb);
269 srb->dp = srb->data = db;
270 srb->ticksent = Ticks;
280 return s->nout == 0 && (s->len == 0 || s->error != nil);
288 for(n = 0; srb->state != Free; n++)
293 /* under Aoedev qlock() so setting of srb->state is safe */
298 assert(srb->state == Alloc);
305 srbcleanout(Aoedev *d, Srb *srb)
309 if(srb == d->inprocess)
312 for(ll = &d->head; (x = *ll) != nil; ll = &x->next){
320 srberror(Aoedev *d, Srb *srb, char *s)
328 frameerror(Aoedev *d, Frame *f, char *s)
336 f->tag = Tfree; /* don't get fooled by way-slow responses */
347 uprint("%ud.%ud", d->major, d->minor);
352 eventlogread(void *a, long n)
357 buf = smalloc(Eventlen);
368 /* can't move directly into pageable space with events lock held */
369 memmove(buf, p+1, n);
371 events.rp = p += Eventlen;
372 if(p >= events.buf + sizeof events.buf)
373 events.rp = events.buf;
376 /* the concern here is page faults in memmove below */
391 eventlog(char *fmt, ...)
401 n = vsnprint(p, Eventlen-1, fmt, arg);
403 p = events.wp += Eventlen;
404 if(p >= events.buf + sizeof events.buf)
405 p = events.wp = events.buf;
422 n = events.wp - events.rp & Nevents - 1;
445 t = ++d->lasttag << 16;
447 } while (t == Tfree || t == Tmgmt);
452 downdev(Aoedev *d, char *err)
460 frameerror(d, f, Enotup);
462 eventlog("%æ: removed; %s\n", d, err);
471 len = f->nhdr + f->dlen;
475 memmove(b->wp, f->hdr, f->nhdr);
477 memmove(b->wp + f->nhdr, f->dp, f->dlen);
483 putlba(Aoeata *a, vlong lba)
497 pickdevlink(Aoedev *d)
502 for(i = 0; i < d->ndl; i++){
503 n = d->dlidx++ % d->ndl;
518 return l->eaidx++ % l->nea;
522 * would like this to depend on the chan (srb).
523 * not possible in the current structure.
525 #define Nofail(d, s) (((d)->flag&Dnofail) == Dnofail)
528 hset(Aoedev *d, Frame *f, Aoehdr *h, int cmd, int new)
534 if((long)(Ticks-f->srb->ticksent) > Srbtimeout){
535 eventlog("%æ: srb timeout\n", d);
536 if(cmd == ACata && Nofail(d, s))
537 f->srb->ticksent = Ticks;
539 frameerror(d, f, Etimedout);
545 if(!(cmd == ACata && f->srb != nil && Nofail(d, s)))
546 downdev(d, "resend fails; no netlink/ea");
549 memmove(h->dst, l->eatab[i], Eaddrlen);
550 memmove(h->src, l->nl->ea, sizeof h->src);
551 hnputs(h->type, Aoetype);
552 h->verflag = Aoever << 4;
554 hnputs(h->major, d->major);
560 hnputl(h->tag, f->tag);
570 resend(Aoedev *d, Frame *f)
577 if(hset(d, f, h, h->cmd, 0) == -1)
579 a = (Aoeata*)(f->hdr + Aoehsz);
582 n = d->maxbcnt; /* mtu mismatch (jumbo fail?) */
586 a->scnt = n / Aoesectsz;
590 /* should remove the netlink */
592 devtab[f->nl->dc->type]->bwrite(f->nl->dc, allocfb(f), 0);
598 discover(uint major, uint minor)
605 e = nl + nelem(netlinks.nl);
609 b = allocb(ETHERMINTU);
614 b->wp = b->rp + ETHERMINTU;
615 memset(b->rp, 0, ETHERMINTU);
617 memset(h->dst, 0xff, sizeof h->dst);
618 memmove(h->src, nl->ea, sizeof h->src);
619 hnputs(h->type, Aoetype);
620 h->verflag = Aoever << 4;
621 hnputs(h->major, major);
625 devtab[nl->dc->type]->bwrite(nl->dc, b, 0);
630 * Check all frames on device and resend any frames that have been
631 * outstanding for 200% of the device round trip time average.
636 ulong i, tx, timeout, nbc;
638 enum { Nms = 100, Nbcms = 30*1000, };
648 if(rediscover && !waserror()){
649 discover(0xffff, 0xff);
656 for(d = devs.d; d != nil; d = d->next){
670 timeout = l->rttavg << 1;
674 if(d->nout == d->maxout){
679 a = (Aoeata*)(f->hdr + Aoehsz);
680 if(a->scnt > Dbcnt / Aoesectsz &&
681 ++f->nl->lostjumbo > (d->nframes << 1)){
682 ea = f->dl->eatab[f->eaidx];
683 eventlog("%æ: jumbo failure on %s:%E; %llud\n",
684 d, f->nl->path, ea, f->lba);
690 if((l->rttavg <<= 1) > Rtmax)
692 eventlog("%æ: rtt %ldms\n", d, Tk2ms(l->rttavg));
695 if(d->nout == d->maxout && d->maxout < d->nframes &&
696 TK2MS(Ticks-d->lastwadj) > 10*1000){
703 i = Nms - TK2MS(Ticks - starttick);
704 if(i > 0 && !waserror()){
705 tsleep(&up->sleep, return0, 0, i);
717 d = va_arg(f->args, Aoedev*);
718 snprint(buf, sizeof buf, "aoe%ud.%ud", d->major, d->minor);
719 return fmtstrcpy(f, buf);
722 static void netbind(char *path);
727 char *p, *f[32], buf[24], ifbuf[64];
730 if((p = getconf("aoeif")) == nil)
732 strncpy(ifbuf, p, sizeof(ifbuf)-1);
733 ifbuf[sizeof(ifbuf)-1] = 0;
734 if((n = tokenize(ifbuf, f, nelem(f))) < 1)
737 for(i = 0; i < n; i++){
739 if(strncmp(p, "ether", 5) == 0)
740 snprint(buf, sizeof buf, "#l%c/ether%c", p[5], p[5]);
741 else if(strncmp(p, "#l", 2) == 0)
742 snprint(buf, sizeof buf, "#l%c/ether%c", p[2], p[2]);
761 fmtinstall(L'æ', fmtæ);
762 events.rp = events.wp = events.buf;
763 kproc("aoesweep", aoesweepproc, nil);
771 aoeattach(char *spec)
778 c = devattach(L'æ', spec);
779 mkqid(&c->qid, Qzero, 0, QTDIR);
784 unitseq(Chan *c, uint unit, Dir *dp)
793 for(d = devs.d; d != nil; d = d->next)
795 mkqid(&q, QID(d->unit, Qunitdir), 0, QTDIR);
796 devdir(c, q, unitname(d), 0, eve, 0555, dp);
810 for(d = devs.d; d != nil; d = d->next)
816 error("unit lookup failure");
821 unitgen(Chan *c, ulong type, Dir *dp)
830 d = unit2dev(UNIT(c->qid));
856 size = sizeof d->ident;
864 mkqid(&q, QID(UNIT(c->qid), type), vers, t);
865 devdir(c, q, p, size, eve, perm, dp);
870 topgen(Chan *c, ulong type, Dir *d)
891 mkqid(&q, type, 0, QTFILE);
892 devdir(c, q, p, size, eve, perm, d);
897 aoegen(Chan *c, char *, Dirtab *, int, int s, Dir *dp)
903 if(c->qid.path == 0){
908 devdir(c, q, "#æ", 0, eve, 0555, dp);
913 devdir(c, q, "aoe", 0, eve, 0555, dp);
921 switch(TYPE(c->qid)){
926 mkqid(&q, Qzero, 0, QTDIR);
927 devdir(c, q, "aoe", 0, eve, 0555, dp);
931 return topgen(c, Qtopbase + s, dp);
933 return unitseq(c, s, dp);
936 return topgen(c, TYPE(c->qid), dp);
939 mkqid(&q, QID(0, Qtopdir), 0, QTDIR);
940 uprint("%uld", UNIT(c->qid));
941 devdir(c, q, up->genbuf, 0, eve, 0555, dp);
944 return unitgen(c, Qunitbase+s, dp);
949 return unitgen(c, TYPE(c->qid), dp);
953 mkqid(&q, QID(i, Qunitdir), 0, QTDIR);
954 devdir(c, q, "devlink", 0, eve, 0555, dp);
957 if(i >= Maxunits || i >= units.ref)
963 mkqid(&q, Q3(s, i, Qdevlink), 0, QTFILE);
964 devdir(c, q, up->genbuf, 0, eve, 0755, dp);
968 mkqid(&q, Q3(s, UNIT(c->qid), Qdevlink), 0, QTFILE);
969 devdir(c, q, up->genbuf, 0, eve, 0755, dp);
975 aoewalk(Chan *c, Chan *nc, char **name, int nname)
977 return devwalk(c, nc, name, nname, nil, 0, aoegen);
981 aoestat(Chan *c, uchar *db, int n)
983 return devstat(c, db, n, nil, 0, aoegen);
987 aoeopen(Chan *c, int omode)
991 if(TYPE(c->qid) != Qdata)
992 return devopen(c, omode, 0, 0, aoegen);
994 d = unit2dev(UNIT(c->qid));
1002 c = devopen(c, omode, 0, 0, aoegen);
1014 if(TYPE(c->qid) != Qdata || (c->flag&COPEN) == 0)
1017 d = unit2dev(UNIT(c->qid));
1019 if(--d->nopen == 0 && !waserror()){
1020 discover(d->major, d->minor);
1027 atarw(Aoedev *d, Frame *f)
1030 char extbit, writebit;
1042 f->nhdr = Aoehsz + Aoeatasz;
1043 memset(f->hdr, 0, f->nhdr);
1044 h = (Aoehdr*)f->hdr;
1045 if(hset(d, f, h, ACata, 1) == -1){
1049 ah = (Aoeata*)(f->hdr + Aoehsz);
1052 f->lba = srb->sector;
1055 ah->scnt = bcnt / Aoesectsz;
1058 ah->aflag |= AAFext;
1062 ah->lba[3] |= 0xe0; /* LBA bit+obsolete 0xa0 */
1065 ah->aflag |= AAFwrite;
1071 ah->cmdstat = 0x20 | writebit | extbit;
1073 /* mark tracking fields and load out */
1075 srb->dp = (uchar*)srb->dp + bcnt;
1077 srb->sector += bcnt / Aoesectsz;
1083 frameerror(d, f, "write error");
1085 devtab[f->nl->dc->type]->bwrite(f->nl->dc, allocfb(f), 0);
1094 static char *errs[] = {
1095 "aoe protocol error: unknown",
1096 "aoe protocol error: bad command code",
1097 "aoe protocol error: bad argument param",
1098 "aoe protocol error: device unavailable",
1099 "aoe protocol error: config string present",
1100 "aoe protocol error: unsupported version",
1101 "aoe protocol error: target is reserved",
1104 if((h->verflag & AFerr) == 0)
1107 if(n >= nelem(errs))
1113 rtupdate(Devlink *l, int rtt)
1124 l->mintimer += (n - l->mintimer) >> 1;
1125 } else if(n < l->mintimer)
1130 /* g == .25; cf. Congestion Avoidance and Control, Jacobson&Karels; 1988 */
1132 l->rttavg += n >> 2;
1136 getframe(Aoedev *d, int tag)
1149 freeframe(Aoedev *d)
1151 if(d->nout < d->maxout)
1152 return getframe(d, Tfree);
1161 while(f = freeframe(d)) {
1162 if(d->inprocess == nil){
1165 d->inprocess = d->head;
1166 d->head = d->head->next;
1175 strategy(Aoedev *d, Srb *srb)
1186 d->tail->next = srb;
1196 srberror(d, srb, "interrupted");
1199 sleep(srb, srbready, srb);
1203 #define iskaddr(a) ((uintptr)(a) > KZERO)
1206 rw(Aoedev *d, int write, uchar *db, long len, uvlong off)
1209 enum { Srbsz = 1<<19, };
1212 if((off|len) & (Aoesectsz-1))
1213 error("offset and length must be sector multiple.\n");
1218 if(off + len > d->bsize)
1219 len = d->bsize - off;
1222 srb = srbkalloc(db, len);
1225 srb = srballoc(Srbsz <= len? Srbsz: len);
1231 for(nlen = len; nlen; nlen -= n){
1232 srb->sector = off / Aoesectsz;
1233 srb->dp = srb->data;
1239 memmove(srb->data, db, n);
1241 if(srb->error != nil)
1244 memmove(db, srb->data, n);
1254 readmem(ulong off, void *dst, long n, void *src, long size)
1260 memmove(dst, (uchar*)src + off, n);
1265 aoeflag(char *s, char *e, uchar f)
1269 for(i = 0; i < nelem(flagname); i++)
1271 s = seprint(s, e, "%s ", flagname[i]);
1272 return seprint(s, e, "\n");
1276 pstat(Aoedev *d, char *db, int len, int off)
1279 char *state, *s, *p, *e;
1281 s = p = smalloc(READSTR);
1289 "state: %s\n" "nopen: %d\n" "nout: %d\n"
1290 "nmaxout: %d\n" "nframes: %d\n" "maxbcnt: %d [maxmtu %d]\n"
1292 "model: %s\n" "serial: %s\n" "firmware: %s\n",
1293 state, d->nopen, d->nout,
1294 d->maxout, d->nframes, d->maxbcnt, d->maxmtu,
1296 d->model, d->serial, d->firmware);
1297 p = seprint(p, e, "flag: ");
1299 p[-1] = ' '; /* horrid */
1300 p = aoeflag(p, e, d->flag);
1304 i = readstr(off, db, len, s);
1310 unitread(Chan *c, void *db, long len, vlong off)
1314 d = unit2dev(UNIT(c->qid));
1315 if(d->vers != c->qid.vers)
1317 switch(TYPE(c->qid)){
1321 return pstat(d, db, len, off);
1323 return rw(d, Read, db, len, off);
1327 return readmem(off, db, len, d->config, d->nconfig);
1331 return readmem(off, db, len, d->ident, sizeof d->ident);
1342 if(m == nil || waserror())
1344 n = devtab[m->type]->read(m, buf, sizeof buf - 1, 0);
1348 mtu = strtoul(buf + 12, 0, 0);
1354 devlinkread(Chan *c, void *db, int len, int off)
1361 d = unit2dev(UNIT(c->qid));
1367 s = p = smalloc(READSTR);
1370 p = seprint(p, e, "addr: ");
1371 for(i = 0; i < l->nea; i++)
1372 p = seprint(p, e, "%E ", l->eatab[i]);
1373 p = seprint(p, e, "\n");
1374 p = seprint(p, e, "npkt: %uld\n", l->npkt);
1375 p = seprint(p, e, "resent: %uld\n", l->resent);
1376 p = seprint(p, e, "flag: ");
1377 p = aoeflag(p, e, l->flag);
1378 p = seprint(p, e, "rttavg: %uld\n", Tk2ms(l->rttavg));
1379 p = seprint(p, e, "mintimer: %uld\n", Tk2ms(l->mintimer));
1380 p = seprint(p, e, "datamtu: %d\n", l->datamtu);
1382 p = seprint(p, e, "nl path: %s\n", l->nl->path);
1383 p = seprint(p, e, "nl ea: %E\n", l->nl->ea);
1384 p = seprint(p, e, "nl flag: ");
1385 p = aoeflag(p, e, l->flag);
1386 p = seprint(p, e, "nl lostjumbo: %d\n", l->nl->lostjumbo);
1387 p = seprint(p, e, "nl datamtu: %d\n", getmtu(l->nl->mtu));
1391 i = readstr(off, db, len, s);
1397 topctlread(Chan *, void *db, int len, int off)
1403 s = p = smalloc(READSTR);
1406 p = seprint(p, e, "debug: %d\n", debug);
1407 p = seprint(p, e, "autodiscover: %d\n", autodiscover);
1408 p = seprint(p, e, "rediscover: %d\n", rediscover);
1410 for(i = 0; i < Nnetlink; i++){
1414 p = seprint(p, e, "if%d path: %s\n", i, n->path);
1415 p = seprint(p, e, "if%d ea: %E\n", i, n->ea);
1416 p = seprint(p, e, "if%d flag: ", i);
1417 p = aoeflag(p, e, n->flag);
1418 p = seprint(p, e, "if%d lostjumbo: %d\n", i, n->lostjumbo);
1419 p = seprint(p, e, "if%d datamtu: %d\n", i, getmtu(n->mtu));
1424 i = readstr(off, db, len, s);
1430 aoeread(Chan *c, void *db, long n, vlong off)
1432 switch(TYPE(c->qid)){
1439 return devdirread(c, db, n, 0, 0, aoegen);
1441 return topctlread(c, db, n, off);
1443 return eventlogread(db, n);
1448 return unitread(c, db, n, off);
1450 return devlinkread(c, db, n, off);
1455 configwrite(Aoedev *d, void *db, long len)
1465 if(len > sizeof d->config)
1467 srb = srballoc(len);
1469 memmove(s, db, len);
1488 tsleep(&up->sleep, return0, 0, 100);
1491 f->nhdr = Aoehsz + Aoecfgsz;
1492 memset(f->hdr, 0, f->nhdr);
1493 h = (Aoehdr*)f->hdr;
1494 if(hset(d, f, h, ACconfig, 1) == -1)
1496 ch = (Aoecfg*)(f->hdr + Aoehsz);
1499 ch->verccmd = AQCfset;
1500 hnputs(ch->cslen, len);
1506 * these refer to qlock & waserror in the above for loop.
1507 * there's still the first waserror outstanding.
1512 devtab[f->nl->dc->type]->bwrite(f->nl->dc, allocfb(f), 0);
1513 sleep(srb, srbready, srb);
1522 memmove(d->config, s, len);
1527 poperror(); /* pop first waserror */
1530 memmove(db, s, len);
1536 devmaxdata(Aoedev *d)
1538 int i, m, mtu, datamtu;
1544 for(i = 0; i < d->ndl; i++){
1547 if((l->flag & Dup) == 0 || (n->flag & Dup) == 0)
1550 if(l->datamtu < datamtu)
1551 datamtu = l->datamtu;
1557 mtu -= Aoehsz + Aoeatasz;
1558 mtu -= mtu % Aoesectsz;
1565 toggle(char *s, uint f, uint bit)
1569 else if(strcmp(s, "on") == 0)
1576 static void ataident(Aoedev*);
1579 unitctlwrite(Aoedev *d, void *db, long n)
1594 static Cmdtab cmds[] = {
1595 {Failio, "failio", 1 },
1596 {Ident, "identify", 1 },
1597 {Jumbo, "jumbo", 0 },
1598 {Maxbno, "maxbno", 0 },
1600 {Nofailf, "nofail", 0 },
1601 {Setsize, "setsize", 0 },
1604 cb = parsecmd(db, n);
1611 ct = lookupcmd(cb, cmds, nelem(cmds));
1614 downdev(d, "i/o failure");
1620 d->flag = toggle(cb->f[1], d->flag, Djumbo);
1624 maxbcnt = devmaxdata(d);
1628 m = strtoul(cb->f[1], 0, 0);
1629 if(ct->index == Maxbno)
1632 m -= Aoehsz + Aoeatasz;
1633 m &= ~(Aoesectsz-1);
1635 if(m == 0 || m > maxbcnt)
1636 cmderror(cb, "invalid mtu");
1641 d->maxbcnt = maxbcnt;
1644 d->flag = toggle(cb->f[1], d->flag, Dnofail);
1647 bsize = d->realbsize;
1651 bsize = strtoull(cb->f[1], 0, 0);
1652 if(bsize % Aoesectsz)
1653 cmderror(cb, "disk size must be sector aligned");
1665 unitwrite(Chan *c, void *db, long n, vlong off)
1671 d = unit2dev(UNIT(c->qid));
1672 switch(TYPE(c->qid)){
1676 return unitctlwrite(d, db, n);
1680 return rw(d, Write, db, n, off);
1682 if(off + n > sizeof d->config)
1684 buf = smalloc(sizeof d->config);
1689 memmove(buf, d->config, d->nconfig);
1690 memmove(buf + off, db, n);
1691 rv = configwrite(d, buf, n + off);
1699 addnet(char *path, Chan *cc, Chan *dc, Chan *mtu, uchar *ea)
1709 e = nl + nelem(netlinks.nl);
1710 for(; nl < e && nl->cc != nil; nl++)
1713 error("out of netlink structures");
1717 strncpy(nl->path, path, sizeof(nl->path)-1);
1718 nl->path[sizeof(nl->path)-1] = 0;
1719 memmove(nl->ea, ea, sizeof nl->ea);
1742 return decref(&units);
1746 * always allocate max frames. maxout may change.
1749 newdev(uint major, uint minor, int n)
1754 d = malloc(sizeof *d);
1755 f = malloc(sizeof *f*Maxframes);
1756 if(d == nil || f == nil) {
1759 error("aoe device allocation failure");
1763 for (e = f + Maxframes; f < e; f++)
1771 d->unit = newunit(); /* bzzt. inaccurate if units removed */
1775 error("too many units");
1782 mm2dev(uint major, uint minor)
1787 for(d = devs.d; d; d = d->next)
1788 if(d->major == major && d->minor == minor){
1793 eventlog("mm2dev: %ud.%ud not found\n", major, minor);
1797 /* Find the device in our list. If not known, add it */
1799 getdev(uint major, uint minor, int n)
1803 if(major == 0xffff || minor == 0xff)
1810 for(d = devs.d; d; d = d->next)
1811 if(d->major == major && d->minor == minor)
1814 d = newdev(major, minor, n);
1833 f->nhdr = Aoehsz + Aoeatasz;
1834 memset(f->hdr, 0, f->nhdr);
1835 h = (Aoehdr*)f->hdr;
1836 if(hset(d, f, h, ACata, 1) == -1)
1838 a = (Aoeata*)(f->hdr + Aoehsz);
1839 f->srb = srbkalloc(0, 0);
1840 a->cmdstat = Cid; /* ata 6, page 110 */
1852 devtab[f->nl->dc->type]->bwrite(f->nl->dc, allocfb(f), 0);
1858 newdlea(Devlink *l, uchar *ea)
1863 for(i = 0; i < Nea; i++){
1866 memmove(t, ea, Eaddrlen);
1869 if(memcmp(t, ea, Eaddrlen) == 0)
1876 newdevlink(Aoedev *d, Netlink *n, Aoehdr *h)
1882 c = (Aoecfg*)((uchar*)h + Aoehsz);
1883 for(i = 0; i < Ndevlink; i++){
1888 l->datamtu = c->scnt*Aoesectsz;
1891 l->mintimer = Rtmin;
1897 l->datamtu = c->scnt*Aoesectsz;
1902 eventlog("%æ: out of links: %s:%E to %E\n", d, n->path, n->ea, h->src);
1907 errrsp(Block *b, char *s)
1916 if(n == Tmgmt || n == Tfree)
1918 d = mm2dev(nhgets(h->major), h->minor);
1921 if(f = getframe(d, n))
1922 frameerror(d, f, s);
1926 qcfgrsp(Block *b, Netlink *nl)
1928 int cmd, cslen, blen;
1938 ch = (Aoecfg*)(b->rp + Aoehsz);
1939 major = nhgets(h->major);
1941 if(n != Tmgmt && n != Tfree){
1942 d = mm2dev(major, h->minor);
1949 eventlog("%æ: unknown response tag %ux\n", d, n);
1952 h0 = (Aoehdr*)f->hdr;
1954 if(cmd != ACconfig){
1956 eventlog("%æ: malicious server got ACconfig want %d; tag %ux\n", d, cmd, n);
1959 cslen = nhgets(ch->cslen);
1960 blen = BLEN(b) - (Aoehsz + Aoecfgsz);
1961 if(cslen < blen && BLEN(b) > 60)
1962 eventlog("%æ: cfgrsp: tag %.8ux oversized %d %d\n",
1965 eventlog("%æ: cfgrsp: tag %.8ux runt %d %d\n",
1969 memmove(f->dp, b->rp + Aoehsz + Aoecfgsz, cslen);
1983 cmd = ch->verccmd & 0xf;
1985 eventlog("aoe%ud.%ud: cfgrsp: bad command %d\n", major, h->minor, cmd);
1988 n = nhgets(ch->bufcnt);
1993 eventlog("getdev: %ud.%ud ignored: %s\n", major, h->minor, up->errstr);
1996 d = getdev(major, h->minor, n);
2005 eventlog("%æ: %s\n", d, up->errstr);
2009 l = newdevlink(d, nl, h); /* add this interface. */
2011 d->fwver = nhgets(ch->fwver);
2012 cslen = nhgets(ch->cslen);
2013 if(cslen > sizeof d->config)
2014 cslen = sizeof d->config;
2015 if(Aoehsz + Aoecfgsz + cslen > BLEN(b))
2016 cslen = BLEN(b) - (Aoehsz + Aoecfgsz);
2018 memmove(d->config, b->rp + Aoehsz + Aoecfgsz, cslen);
2020 /* manually set mtu may be reset lower if conditions warrant */
2023 if((d->flag & Djumbo) == 0)
2027 if(n != d->maxbcnt){
2028 eventlog("%æ: setting %d byte mtu on %s:%E\n",
2029 d, n, nl->path, nl->ea);
2040 aoeidentify(Aoedev *d, ushort *id)
2046 eventlog("%æ: idfeat returns -1\n", d);
2049 if((d->feat&Dlba) == 0){
2050 eventlog("%æ: no lba support\n", d);
2054 memmove(d->ident, id, sizeof d->ident);
2061 d->vers = incref(&drivevers);
2065 identify(Aoedev *d, ushort *id)
2070 s = aoeidentify(d, id);
2073 osectors = d->realbsize;
2074 memmove(oserial, d->serial, sizeof d->serial);
2076 idmove(d->serial, id+10, 20);
2077 idmove(d->firmware, id+23, 8);
2078 idmove(d->model, id+27, 40);
2080 /* d->wwn = idwwn(d, id); */
2083 if(osectors != s || memcmp(oserial, d->serial, sizeof oserial)){
2086 // d->mediachange = 1;
2097 Aoeata *ahin, *ahout;
2104 major = nhgets(h->major);
2105 d = mm2dev(major, h->minor);
2108 ahin = (Aoeata*)(b->rp + Aoehsz);
2115 if(n == Tfree || n == Tmgmt)
2119 eventlog("%æ: unexpected response; tag %ux\n", d, n);
2122 h0 = (Aoehdr*)f->hdr;
2125 eventlog("%æ: malicious server got ACata want %d; tag %ux\n", d, cmd, n);
2129 rtupdate(f->dl, tsince(f->tag));
2130 ahout = (Aoeata*)(f->hdr + Aoehsz);
2133 if(ahin->cmdstat & 0xa9){
2134 eventlog("%æ: ata error cmd %.2ux stat %.2ux\n",
2135 d, ahout->cmdstat, ahin->cmdstat);
2139 n = ahout->scnt * Aoesectsz;
2140 switch(ahout->cmdstat){
2143 if(BLEN(b) - (Aoehsz + Aoeatasz) != n){
2144 eventlog("%æ: misread blen %zd expect %d\n",
2148 memmove(f->dp, b->rp + Aoehsz + Aoeatasz, n);
2152 f->nl->lostjumbo = 0;
2154 f->lba += n / Aoesectsz;
2155 f->dp = (uchar*)f->dp + n;
2161 if(BLEN(b) - (Aoehsz + Aoeatasz) < 512){
2162 eventlog("%æ: runt identify blen %zd expect %d\n",
2163 d, BLEN(b), 512 + Aoehsz + Aoeatasz);
2166 identify(d, (ushort*)(b->rp + Aoehsz + Aoeatasz));
2167 free(srb); /* BOTCH */
2171 eventlog("%æ: unknown ata command %.2ux \n",
2191 netrdaoeproc(void *v)
2194 char name[Maxpath+1], *s;
2200 idx = nl - netlinks.nl;
2201 netlinks.reader[idx] = 1;
2202 kstrcpy(name, nl->path, Maxpath);
2205 eventlog("netrdaoe@%s: exiting: %s\n", name, up->errstr);
2206 netlinks.reader[idx] = 0;
2207 wakeup(netlinks.rendez + idx);
2208 pexit(up->errstr, 1);
2211 discover(0xffff, 0xff);
2213 if((nl->flag & Dup) == 0)
2214 error("netlink is down");
2216 panic("netrdaoe: nl->dc == nil");
2217 b = devtab[nl->dc->type]->bread(nl->dc, 1<<16, 0);
2219 error("network read");
2221 if(h->verflag & AFrsp)
2222 if(s = aoeerror(h)){
2223 eventlog("%s: %d.%d %s\n", nl->path,
2224 h->major[0]<<8 | h->major[1], h->minor, s);
2226 }else if(h->cmd == ACata)
2228 else if(h->cmd == ACconfig)
2230 else if((h->cmd & 0xf0) != 0xf0){
2231 eventlog("%s: unknown cmd %d\n",
2233 errrsp(b, "unknown command");
2240 getaddr(char *path, uchar *ea)
2243 char buf[2*Eaddrlen+1];
2246 uprint("%s/addr", path);
2247 c = namec(up->genbuf, Aopen, OREAD, 0);
2252 n = devtab[c->type]->read(c, buf, sizeof buf-1, 0);
2256 if(parseether(ea, buf) < 0)
2257 error("parseether failure");
2264 uchar ea[2*Eaddrlen+1];
2265 Chan *dc, *cc, *mtu;
2268 snprint(addr, sizeof addr, "%s!0x%x", path, Aoetype);
2269 dc = chandial(addr, nil, nil, &cc);
2270 snprint(addr, sizeof addr, "%s/mtu", path);
2273 mtu = namec(addr, Aopen, OREAD, 0);
2283 if(dc == nil || cc == nil)
2286 nl = addnet(path, cc, dc, mtu, ea);
2287 snprint(addr, sizeof addr, "netrdaoe@%s", path);
2288 kproc(addr, netrdaoeproc, nl);
2295 return *(int*)v != 0;
2299 netunbind(char *path)
2302 Aoedev *d, *p, *next;
2309 e = n + nelem(netlinks.nl);
2313 if(n->dc && strcmp(n->path, path) == 0)
2317 error("device not bound");
2320 * hunt down devices using this interface; disable
2321 * this also terminates the reader.
2323 idx = n - netlinks.nl;
2325 for(d = devs.d; d; d = d->next){
2327 for(i = 0; i < d->ndl; i++){
2337 /* confirm reader is down. */
2340 sleep(netlinks.rendez + idx, unbound, netlinks.reader + idx);
2343 /* reschedule packets. */
2345 for(d = devs.d; d != nil; d = d->next){
2347 for(i = 0; i < d->nframes; i++){
2349 if(f->tag != Tfree && f->nl == n)
2356 /* squeeze devlink pool. (we assert nobody is using them now) */
2358 for(d = devs.d; d != nil; d = d->next){
2360 for(i = 0; i < d->ndl; i++){
2363 memmove(l, l + 1, sizeof *l * (--d->ndl - i));
2369 /* close device link. */
2375 memset(n, 0, sizeof *n);
2381 /* squeeze orphan devices */
2383 for(p = d = devs.d; d != nil; d = next){
2390 downdev(d, "orphan");
2406 strtoss(char *f, uint *shelf, uint *slot)
2414 *shelf = strtol(f, &s, 0);
2415 if(s == f || *shelf > 0xffff)
2419 *slot = strtol(f, &s, 0);
2420 if(s == f || *slot > 0xff)
2426 discoverstr(char *f)
2430 strtoss(f, &shelf, &slot);
2431 discover(shelf, slot);
2435 removedev(Aoedev *d)
2443 for(p = devs.d; p != nil; p = p->next)
2451 for(i = 0; i < d->nframes; i++)
2452 frameerror(d, d->frames+i, Enotup);
2468 switch(TYPE(c->qid)){
2480 removedev(unit2dev(UNIT(c->qid)));
2491 strtoss(f, &shelf, &slot);
2493 for(d = devs.d; d != nil; d = d->next)
2494 if(shelf == d->major && slot == d->minor){
2495 wunlock(&devs); /* BOTCH */
2500 error("device not bound");
2504 topctlwrite(void *db, long n)
2518 static Cmdtab cmds[] = {
2519 { Autodiscover, "autodiscover", 0 },
2520 { Bind, "bind", 2 },
2521 { Debug, "debug", 0 },
2522 { Discover, "discover", 0 },
2523 { Rediscover, "rediscover", 0 },
2524 { Remove, "remove", 2 },
2525 { Unbind, "unbind", 2 },
2528 cb = parsecmd(db, n);
2533 ct = lookupcmd(cb, cmds, nelem(cmds));
2537 autodiscover = toggle(f, autodiscover, 1);
2543 debug = toggle(f, debug, 1);
2549 rediscover = toggle(f, rediscover, 1);
2552 removestr(f); /* depricated */
2564 aoewrite(Chan *c, void *db, long n, vlong off)
2566 switch(TYPE(c->qid)){
2574 return topctlwrite(db, n);
2579 return unitwrite(c, db, n, off);