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__);
34 #define TYPE(q) ((ulong)(q).path & 0xf)
35 #define UNIT(q) (((ulong)(q).path>>4) & 0xff)
36 #define L(q) (((ulong)(q).path>>12) & 0xf)
37 #define QID(u, t) ((u)<<4 | (t))
38 #define Q3(l, u, t) ((l)<<8 | QID(u, t))
39 #define UP(d) ((d)->flag & Dup)
41 #define Ticks MACHP(0)->ticks
42 #define Ms2tk(t) (((t)*HZ)/1000)
43 #define Tk2ms(t) (((t)*1000)/HZ)
62 Qdevlink = Qdevlinkbase,
65 Qtopfiles = Qtopend-Qtopbase,
66 Qdevlinkfiles = Qdevlinkend-Qdevlinkbase,
76 /* round trip bounds, timeouts, in ticks */
99 * unified set of flags
100 * a Netlink + Aoedev most both be jumbo capable
101 * to send jumbograms to that interface.
109 static char *flagname[] = {
121 Chan *mtu; /* open early to prevent bind issues. */
130 uchar eatab[Nea][Eaddrlen];
140 typedef struct Srb Srb;
162 uchar hdr[ETHERMINTU];
170 typedef struct Aoedev Aoedev;
180 Devlink dltab[Ndevlink];
213 #pragma varargck type "æ" Aoedev*
219 char buf[Eventlen*Nevents];
232 int reader[Nnetlink]; /* reader is running. */
233 Rendez rendez[Nnetlink]; /* confirm exit. */
234 Netlink nl[Nnetlink];
237 extern Dev aoedevtab;
239 static Ref drivevers;
241 static int autodiscover = 1;
242 static int rediscover;
243 extern char Enotup[] = "aoe device is down";
244 extern char Echange[] = "media or partition has changed";
251 srb = malloc(sizeof *srb+sz);
253 srb->dp = srb->data = srb+1;
254 srb->ticksent = Ticks;
259 srbkalloc(void *db, ulong)
263 srb = malloc(sizeof *srb);
265 srb->dp = srb->data = db;
266 srb->ticksent = Ticks;
276 return s->nout == 0 && (s->len == 0 || s->error != nil);
284 for(n = 0; srb->state != Free; n++)
289 /* under Aoedev qlock() so setting of srb->state is safe */
294 assert(srb->state == Alloc);
301 srbcleanout(Aoedev *d, Srb *srb)
305 if(srb == d->inprocess)
308 for(ll = &d->head; x = *ll; ll = &x->next){
316 srberror(Aoedev *d, Srb *srb, char *s)
324 frameerror(Aoedev *d, Frame *f, char *s)
332 f->tag = Tfree; /* don't get fooled by way-slow responses */
343 uprint("%ud.%ud", d->major, d->minor);
348 eventlogread(void *a, long n)
353 buf = smalloc(Eventlen);
364 /* can't move directly into pageable space with events lock held */
365 memmove(buf, p+1, n);
367 events.rp = p += Eventlen;
368 if(p >= events.buf + sizeof events.buf)
369 events.rp = events.buf;
372 /* the concern here is page faults in memmove below */
387 eventlog(char *fmt, ...)
397 n = vsnprint(p, Eventlen-1, fmt, arg);
399 p = events.wp += Eventlen;
400 if(p >= events.buf + sizeof events.buf)
401 p = events.wp = events.buf;
418 n = events.wp - events.rp & Nevents - 1;
441 t = ++d->lasttag << 16;
443 } while (t == Tfree || t == Tmgmt);
448 downdev(Aoedev *d, char *err)
456 frameerror(d, f, Enotup);
458 eventlog("%æ: removed; %s\n", d, err);
467 len = f->nhdr + f->dlen;
471 memmove(b->wp, f->hdr, f->nhdr);
473 memmove(b->wp + f->nhdr, f->dp, f->dlen);
479 putlba(Aoeata *a, vlong lba)
493 pickdevlink(Aoedev *d)
498 for(i = 0; i < d->ndl; i++){
499 n = d->dlidx++ % d->ndl;
501 if(l && l->flag & Dup)
514 return l->eaidx++ % l->nea;
518 * would like this to depend on the chan (srb).
519 * not possible in the current structure.
521 #define Nofail(d, s) (((d)->flag&Dnofail) == Dnofail)
524 hset(Aoedev *d, Frame *f, Aoehdr *h, int cmd)
530 if((long)(Ticks-f->srb->ticksent) > Srbtimeout){
531 eventlog("%æ: srb timeout\n", d);
532 if(cmd == ACata && Nofail(d, s))
533 f->srb->ticksent = Ticks;
535 frameerror(d, f, Etimedout);
541 if(!(cmd == ACata && f->srb && Nofail(d, s)))
542 downdev(d, "resend fails; no netlink/ea");
545 memmove(h->dst, l->eatab[i], Eaddrlen);
546 memmove(h->src, l->nl->ea, sizeof h->src);
547 hnputs(h->type, Aoetype);
548 h->verflag = Aoever << 4;
550 hnputs(h->major, d->major);
554 hnputl(h->tag, f->tag = newtag(d));
564 resend(Aoedev *d, Frame *f)
571 if(hset(d, f, h, h->cmd) == -1)
573 a = (Aoeata*)(f->hdr + Aoehsz);
576 n = d->maxbcnt; /* mtu mismatch (jumbo fail?) */
580 a->scnt = n / Aoesectsz;
584 /* should remove the netlink */
586 devtab[f->nl->dc->type]->bwrite(f->nl->dc, allocfb(f), 0);
592 discover(uint major, uint minor)
599 e = nl + nelem(netlinks.nl);
603 b = allocb(ETHERMINTU);
608 b->wp = b->rp + ETHERMINTU;
609 memset(b->rp, 0, ETHERMINTU);
611 memset(h->dst, 0xff, sizeof h->dst);
612 memmove(h->src, nl->ea, sizeof h->src);
613 hnputs(h->type, Aoetype);
614 h->verflag = Aoever << 4;
615 hnputs(h->major, major);
619 devtab[nl->dc->type]->bwrite(nl->dc, b, 0);
624 * Check all frames on device and resend any frames that have been
625 * outstanding for 200% of the device round trip time average.
630 ulong i, tx, timeout, nbc;
632 enum { Nms = 100, Nbcms = 30*1000, };
642 if(rediscover && !waserror()){
643 discover(0xffff, 0xff);
650 for(d = devs.d; d; d = d->next){
664 timeout = l->rttavg << 1;
668 if(d->nout == d->maxout){
673 a = (Aoeata*)(f->hdr + Aoehsz);
674 if(a->scnt > Dbcnt / Aoesectsz &&
675 ++f->nl->lostjumbo > (d->nframes << 1)){
676 ea = f->dl->eatab[f->eaidx];
677 eventlog("%æ: jumbo failure on %s:%E; %llud\n",
678 d, f->nl->path, ea, f->lba);
684 if((l->rttavg <<= 1) > Rtmax)
686 eventlog("%æ: rtt %ldms\n", d, Tk2ms(l->rttavg));
689 if(d->nout == d->maxout && d->maxout < d->nframes &&
690 TK2MS(Ticks-d->lastwadj) > 10*1000){
697 i = Nms - TK2MS(Ticks - starttick);
699 tsleep(&up->sleep, return0, 0, i);
709 d = va_arg(f->args, Aoedev*);
710 snprint(buf, sizeof buf, "aoe%ud.%ud", d->major, d->minor);
711 return fmtstrcpy(f, buf);
714 static void netbind(char *path);
719 char *p, *f[32], buf[24], ifbuf[64];
722 if((p = getconf("aoeif")) == nil)
724 strncpy(ifbuf, p, sizeof buf);
725 if((n = tokenize(ifbuf, f, nelem(f))) < 1)
728 for(i = 0; i < n; i++){
730 if(strncmp(p, "ether", 5) == 0)
731 snprint(buf, sizeof buf, "#l%c/ether%c", p[5], p[5]);
732 else if(strncmp(p, "#l", 2) == 0)
733 snprint(buf, sizeof buf, "#l%c/ether%c", p[2], p[2]);
752 fmtinstall(L'æ', fmtæ);
753 events.rp = events.wp = events.buf;
754 kproc("aoesweep", aoesweepproc, nil);
762 aoeattach(char *spec)
769 c = devattach(L'æ', spec);
770 mkqid(&c->qid, Qzero, 0, QTDIR);
782 for(d = devs.d; d; d = d->next)
795 for(d = devs.d; d; d = d->next)
801 error("unit lookup failure");
806 unitgen(Chan *c, ulong type, Dir *dp)
815 d = unit2dev(UNIT(c->qid));
841 size = sizeof d->ident;
849 mkqid(&q, QID(UNIT(c->qid), type), vers, t);
850 devdir(c, q, p, size, eve, perm, dp);
855 topgen(Chan *c, ulong type, Dir *d)
876 mkqid(&q, type, 0, QTFILE);
877 devdir(c, q, p, size, eve, perm, d);
882 aoegen(Chan *c, char *, Dirtab *, int, int s, Dir *dp)
888 if(c->qid.path == 0){
893 devdir(c, q, "#æ", 0, eve, 0555, dp);
898 devdir(c, q, "aoe", 0, eve, 0555, dp);
906 switch(TYPE(c->qid)){
911 mkqid(&q, Qzero, 0, QTDIR);
912 devdir(c, q, "aoe", 0, eve, 0555, dp);
916 return topgen(c, Qtopbase + s, dp);
918 if((d = unitseq(s)) == 0)
920 mkqid(&q, QID(d->unit, Qunitdir), 0, QTDIR);
921 devdir(c, q, unitname(d), 0, eve, 0555, dp);
925 return topgen(c, TYPE(c->qid), dp);
928 mkqid(&q, QID(0, Qtopdir), 0, QTDIR);
929 uprint("%uld", UNIT(c->qid));
930 devdir(c, q, up->genbuf, 0, eve, 0555, dp);
933 return unitgen(c, Qunitbase+s, dp);
938 return unitgen(c, TYPE(c->qid), dp);
942 mkqid(&q, QID(i, Qunitdir), 0, QTDIR);
943 devdir(c, q, "devlink", 0, eve, 0555, dp);
952 mkqid(&q, Q3(s, i, Qdevlink), 0, QTFILE);
953 devdir(c, q, up->genbuf, 0, eve, 0755, dp);
957 mkqid(&q, Q3(s, UNIT(c->qid), Qdevlink), 0, QTFILE);
958 devdir(c, q, up->genbuf, 0, eve, 0755, dp);
964 aoewalk(Chan *c, Chan *nc, char **name, int nname)
966 return devwalk(c, nc, name, nname, nil, 0, aoegen);
970 aoestat(Chan *c, uchar *db, int n)
972 return devstat(c, db, n, nil, 0, aoegen);
976 aoeopen(Chan *c, int omode)
980 if(TYPE(c->qid) != Qdata)
981 return devopen(c, omode, 0, 0, aoegen);
983 d = unit2dev(UNIT(c->qid));
991 c = devopen(c, omode, 0, 0, aoegen);
1003 if(TYPE(c->qid) != Qdata || (c->flag&COPEN) == 0)
1006 d = unit2dev(UNIT(c->qid));
1008 if(--d->nopen == 0 && !waserror()){
1009 discover(d->major, d->minor);
1016 atarw(Aoedev *d, Frame *f)
1019 char extbit, writebit;
1031 f->nhdr = Aoehsz + Aoeatasz;
1032 memset(f->hdr, 0, f->nhdr);
1033 h = (Aoehdr*)f->hdr;
1034 if(hset(d, f, h, ACata) == -1){
1038 ah = (Aoeata*)(f->hdr + Aoehsz);
1041 f->lba = srb->sector;
1044 ah->scnt = bcnt / Aoesectsz;
1047 ah->aflag |= AAFext;
1051 ah->lba[3] |= 0xe0; /* LBA bit+obsolete 0xa0 */
1054 ah->aflag |= AAFwrite;
1060 ah->cmdstat = 0x20 | writebit | extbit;
1062 /* mark tracking fields and load out */
1064 srb->dp = (uchar*)srb->dp + bcnt;
1066 srb->sector += bcnt / Aoesectsz;
1072 frameerror(d, f, "write error");
1074 devtab[f->nl->dc->type]->bwrite(f->nl->dc, allocfb(f), 0);
1083 static char *errs[] = {
1084 "aoe protocol error: unknown",
1085 "aoe protocol error: bad command code",
1086 "aoe protocol error: bad argument param",
1087 "aoe protocol error: device unavailable",
1088 "aoe protocol error: config string present",
1089 "aoe protocol error: unsupported version",
1090 "aoe protocol error: target is reserved",
1093 if((h->verflag & AFerr) == 0)
1102 rtupdate(Devlink *l, int rtt)
1113 l->mintimer += (n - l->mintimer) >> 1;
1114 } else if(n < l->mintimer)
1119 /* g == .25; cf. Congestion Avoidance and Control, Jacobson&Karels; 1988 */
1121 l->rttavg += n >> 2;
1125 getframe(Aoedev *d, int tag)
1138 freeframe(Aoedev *d)
1140 if(d->nout < d->maxout)
1141 return getframe(d, Tfree);
1150 while(f = freeframe(d)) {
1151 if(d->inprocess == nil){
1154 d->inprocess = d->head;
1155 d->head = d->head->next;
1164 strategy(Aoedev *d, Srb *srb)
1175 d->tail->next = srb;
1185 srberror(d, srb, "interrupted");
1188 sleep(srb, srbready, srb);
1192 #define iskaddr(a) ((uintptr)(a) > KZERO)
1195 rw(Aoedev *d, int write, uchar *db, long len, uvlong off)
1198 enum { Srbsz = 1<<19, };
1201 if((off|len) & (Aoesectsz-1))
1202 error("offset and length must be sector multiple.\n");
1207 if(off + len > d->bsize)
1208 len = d->bsize - off;
1211 srb = srbkalloc(db, len);
1214 srb = srballoc(Srbsz <= len? Srbsz: len);
1220 for(nlen = len; nlen; nlen -= n){
1221 srb->sector = off / Aoesectsz;
1222 srb->dp = srb->data;
1228 memmove(srb->data, db, n);
1233 memmove(db, srb->data, n);
1243 readmem(ulong off, void *dst, long n, void *src, long size)
1249 memmove(dst, (uchar*)src + off, n);
1254 aoeflag(char *s, char *e, uchar f)
1258 for(i = 0; i < nelem(flagname); i++)
1260 s = seprint(s, e, "%s ", flagname[i]);
1261 return seprint(s, e, "\n");
1265 pstat(Aoedev *d, char *db, int len, int off)
1268 char *state, *s, *p, *e;
1270 s = p = malloc(READSTR);
1278 "state: %s\n" "nopen: %d\n" "nout: %d\n"
1279 "nmaxout: %d\n" "nframes: %d\n" "maxbcnt: %d [maxmtu %d]\n"
1281 "model: %s\n" "serial: %s\n" "firmware: %s\n",
1282 state, d->nopen, d->nout,
1283 d->maxout, d->nframes, d->maxbcnt, d->maxmtu,
1285 d->model, d->serial, d->firmware);
1286 p = seprint(p, e, "flag: ");
1288 p[-1] = ' '; /* horrid */
1289 p = aoeflag(p, e, d->flag);
1293 i = readstr(off, db, len, s);
1299 unitread(Chan *c, void *db, long len, vlong off)
1303 d = unit2dev(UNIT(c->qid));
1304 if(d->vers != c->qid.vers)
1306 switch(TYPE(c->qid)){
1310 return pstat(d, db, len, off);
1312 return rw(d, Read, db, len, off);
1316 return readmem(off, db, len, d->config, d->nconfig);
1320 return readmem(off, db, len, d->ident, sizeof d->ident);
1331 if(m == nil || waserror())
1333 n = devtab[m->type]->read(m, buf, sizeof buf - 1, 0);
1337 mtu = strtoul(buf + 12, 0, 0);
1343 devlinkread(Chan *c, void *db, int len, int off)
1350 d = unit2dev(UNIT(c->qid));
1356 s = p = malloc(READSTR);
1359 p = seprint(p, e, "addr: ");
1360 for(i = 0; i < l->nea; i++)
1361 p = seprint(p, e, "%E ", l->eatab[i]);
1362 p = seprint(p, e, "\n");
1363 p = seprint(p, e, "npkt: %uld\n", l->npkt);
1364 p = seprint(p, e, "resent: %uld\n", l->resent);
1365 p = seprint(p, e, "flag: ");
1366 p = aoeflag(p, e, l->flag);
1367 p = seprint(p, e, "rttavg: %uld\n", Tk2ms(l->rttavg));
1368 p = seprint(p, e, "mintimer: %uld\n", Tk2ms(l->mintimer));
1369 p = seprint(p, e, "datamtu: %d\n", l->datamtu);
1371 p = seprint(p, e, "nl path: %s\n", l->nl->path);
1372 p = seprint(p, e, "nl ea: %E\n", l->nl->ea);
1373 p = seprint(p, e, "nl flag: ");
1374 p = aoeflag(p, e, l->flag);
1375 p = seprint(p, e, "nl lostjumbo: %d\n", l->nl->lostjumbo);
1376 p = seprint(p, e, "nl datamtu: %d\n", getmtu(l->nl->mtu));
1380 i = readstr(off, db, len, s);
1386 topctlread(Chan *, void *db, int len, int off)
1392 s = p = malloc(READSTR);
1395 p = seprint(p, e, "debug: %d\n", debug);
1396 p = seprint(p, e, "autodiscover: %d\n", autodiscover);
1397 p = seprint(p, e, "rediscover: %d\n", rediscover);
1399 for(i = 0; i < Nnetlink; i++){
1403 p = seprint(p, e, "if%d path: %s\n", i, n->path);
1404 p = seprint(p, e, "if%d ea: %E\n", i, n->ea);
1405 p = seprint(p, e, "if%d flag: ", i);
1406 p = aoeflag(p, e, n->flag);
1407 p = seprint(p, e, "if%d lostjumbo: %d\n", i, n->lostjumbo);
1408 p = seprint(p, e, "if%d datamtu: %d\n", i, getmtu(n->mtu));
1413 i = readstr(off, db, len, s);
1419 aoeread(Chan *c, void *db, long n, vlong off)
1421 switch(TYPE(c->qid)){
1428 return devdirread(c, db, n, 0, 0, aoegen);
1430 return topctlread(c, db, n, off);
1432 return eventlogread(db, n);
1437 return unitread(c, db, n, off);
1439 return devlinkread(c, db, n, off);
1444 configwrite(Aoedev *d, void *db, long len)
1454 if(len > sizeof d->config)
1456 srb = srballoc(len);
1458 memmove(s, db, len);
1477 tsleep(&up->sleep, return0, 0, 100);
1480 f->nhdr = Aoehsz + Aoecfgsz;
1481 memset(f->hdr, 0, f->nhdr);
1482 h = (Aoehdr*)f->hdr;
1483 if(hset(d, f, h, ACconfig) == -1)
1485 ch = (Aoecfg*)(f->hdr + Aoehsz);
1488 ch->verccmd = AQCfset;
1489 hnputs(ch->cslen, len);
1495 * these refer to qlock & waserror in the above for loop.
1496 * there's still the first waserror outstanding.
1501 devtab[f->nl->dc->type]->bwrite(f->nl->dc, allocfb(f), 0);
1502 sleep(srb, srbready, srb);
1511 memmove(d->config, s, len);
1516 poperror(); /* pop first waserror */
1519 memmove(db, s, len);
1525 devmaxdata(Aoedev *d)
1527 int i, m, mtu, datamtu;
1533 for(i = 0; i < d->ndl; i++){
1536 if((l->flag & Dup) == 0 || (n->flag & Dup) == 0)
1539 if(l->datamtu < datamtu)
1540 datamtu = l->datamtu;
1546 mtu -= Aoehsz + Aoeatasz;
1547 mtu -= mtu % Aoesectsz;
1554 toggle(char *s, uint f, uint bit)
1558 else if(strcmp(s, "on") == 0)
1565 static void ataident(Aoedev*);
1568 unitctlwrite(Aoedev *d, void *db, long n)
1583 static Cmdtab cmds[] = {
1584 {Failio, "failio", 1 },
1585 {Ident, "identify", 1 },
1586 {Jumbo, "jumbo", 0 },
1587 {Maxbno, "maxbno", 0 },
1589 {Nofailf, "nofail", 0 },
1590 {Setsize, "setsize", 0 },
1593 cb = parsecmd(db, n);
1600 ct = lookupcmd(cb, cmds, nelem(cmds));
1603 downdev(d, "i/o failure");
1609 d->flag = toggle(cb->f[1], d->flag, Djumbo);
1613 maxbcnt = devmaxdata(d);
1617 m = strtoul(cb->f[1], 0, 0);
1618 if(ct->index == Maxbno)
1621 m -= Aoehsz + Aoeatasz;
1622 m &= ~(Aoesectsz-1);
1624 if(m == 0 || m > maxbcnt)
1625 cmderror(cb, "invalid mtu");
1630 d->maxbcnt = maxbcnt;
1633 d->flag = toggle(cb->f[1], d->flag, Dnofail);
1636 bsize = d->realbsize;
1640 bsize = strtoull(cb->f[1], 0, 0);
1641 if(bsize % Aoesectsz)
1642 cmderror(cb, "disk size must be sector aligned");
1654 unitwrite(Chan *c, void *db, long n, vlong off)
1660 d = unit2dev(UNIT(c->qid));
1661 switch(TYPE(c->qid)){
1665 return unitctlwrite(d, db, n);
1669 return rw(d, Write, db, n, off);
1671 if(off + n > sizeof d->config)
1673 buf = malloc(sizeof d->config);
1678 memmove(buf, d->config, d->nconfig);
1679 memmove(buf + off, db, n);
1680 rv = configwrite(d, buf, n + off);
1688 addnet(char *path, Chan *cc, Chan *dc, Chan *mtu, uchar *ea)
1698 e = nl + nelem(netlinks.nl);
1699 for(; nl < e && nl->cc; nl++)
1702 error("out of netlink structures");
1706 strncpy(nl->path, path, sizeof nl->path);
1707 memmove(nl->ea, ea, sizeof nl->ea);
1720 if(units.ref == Maxunits)
1740 * always allocate max frames. maxout may change.
1743 newdev(uint major, uint minor, int n)
1748 d = malloc(sizeof *d);
1749 f = malloc(sizeof *f*Maxframes);
1753 error("aoe device allocation failure");
1757 for (e = f + Maxframes; f < e; f++)
1765 d->unit = newunit(); /* bzzt. inaccurate if units removed */
1769 error("too many units");
1776 mm2dev(uint major, uint minor)
1781 for(d = devs.d; d; d = d->next)
1782 if(d->major == major && d->minor == minor){
1787 eventlog("mm2dev: %ud.%ud not found\n", major, minor);
1791 /* Find the device in our list. If not known, add it */
1793 getdev(uint major, uint minor, int n)
1797 if(major == 0xffff || minor == 0xff)
1804 for(d = devs.d; d; d = d->next)
1805 if(d->major == major && d->minor == minor)
1808 d = newdev(major, minor, n);
1827 f->nhdr = Aoehsz + Aoeatasz;
1828 memset(f->hdr, 0, f->nhdr);
1829 h = (Aoehdr*)f->hdr;
1830 if(hset(d, f, h, ACata) == -1)
1832 a = (Aoeata*)(f->hdr + Aoehsz);
1833 f->srb = srbkalloc(0, 0);
1834 a->cmdstat = Cid; /* ata 6, page 110 */
1846 devtab[f->nl->dc->type]->bwrite(f->nl->dc, allocfb(f), 0);
1852 newdlea(Devlink *l, uchar *ea)
1857 for(i = 0; i < Nea; i++){
1860 memmove(t, ea, Eaddrlen);
1863 if(memcmp(t, ea, Eaddrlen) == 0)
1870 newdevlink(Aoedev *d, Netlink *n, Aoehdr *h)
1876 c = (Aoecfg*)((uchar*)h + Aoehsz);
1877 for(i = 0; i < Ndevlink; i++){
1882 l->datamtu = c->scnt*Aoesectsz;
1885 l->mintimer = Rtmin;
1891 l->datamtu = c->scnt*Aoesectsz;
1896 eventlog("%æ: out of links: %s:%E to %E\n", d, n->path, n->ea, h->src);
1901 errrsp(Block *b, char *s)
1910 if(n == Tmgmt || n == Tfree)
1912 d = mm2dev(nhgets(h->major), h->minor);
1915 if(f = getframe(d, n))
1916 frameerror(d, f, s);
1920 qcfgrsp(Block *b, Netlink *nl)
1922 int cmd, cslen, blen;
1932 ch = (Aoecfg*)(b->rp + Aoehsz);
1933 major = nhgets(h->major);
1936 d = mm2dev(major, h->minor);
1943 eventlog("%æ: unknown response tag %ux\n", d, n);
1946 cslen = nhgets(ch->cslen);
1947 blen = BLEN(b) - (Aoehsz + Aoecfgsz);
1948 if(cslen < blen && BLEN(b) > 60)
1949 eventlog("%æ: cfgrsp: tag %.8ux oversized %d %d\n",
1952 eventlog("%æ: cfgrsp: tag %.8ux runt %d %d\n",
1956 memmove(f->dp, (uchar*)ch + Aoehsz + Aoecfgsz, cslen);
1970 cmd = ch->verccmd & 0xf;
1972 eventlog("aoe%ud.%ud: cfgrsp: bad command %d\n", major, h->minor, cmd);
1975 n = nhgets(ch->bufcnt);
1980 eventlog("getdev: %ud.%ud ignored: %s\n", major, h->minor, up->errstr);
1983 d = getdev(major, h->minor, n);
1992 eventlog("%æ: %s\n", d, up->errstr);
1996 l = newdevlink(d, nl, h); /* add this interface. */
1998 d->fwver = nhgets(ch->fwver);
1999 n = nhgets(ch->cslen);
2000 if(n > sizeof d->config)
2001 n = sizeof d->config;
2003 memmove(d->config, (uchar*)ch + Aoehsz + Aoecfgsz, n);
2005 /* manually set mtu may be reset lower if conditions warrant */
2008 if((d->flag & Djumbo) == 0)
2012 if(n != d->maxbcnt){
2013 eventlog("%æ: setting %d byte mtu on %s:%E\n",
2014 d, n, nl->path, nl->ea);
2025 aoeidentify(Aoedev *d, ushort *id)
2032 if((d->feat&Dlba) == 0){
2033 dprint("%æ: no lba support\n", d);
2037 memmove(d->ident, id, sizeof d->ident);
2045 d->vers = drivevers.ref++;
2050 identify(Aoedev *d, ushort *id)
2055 s = aoeidentify(d, id);
2058 osectors = d->realbsize;
2059 memmove(oserial, d->serial, sizeof d->serial);
2061 idmove(d->serial, id+10, 20);
2062 idmove(d->firmware, id+23, 8);
2063 idmove(d->model, id+27, 40);
2065 /* d->wwn = idwwn(d, id); */
2068 if(osectors != s || memcmp(oserial, d->serial, sizeof oserial)){
2071 // d->mediachange = 1;
2082 Aoeata *ahin, *ahout;
2089 major = nhgets(h->major);
2090 d = mm2dev(major, h->minor);
2093 ahin = (Aoeata*)(b->rp + Aoehsz);
2102 dprint("%æ: unexpected response; tag %ux\n", d, n);
2105 rtupdate(f->dl, tsince(f->tag));
2106 ahout = (Aoeata*)(f->hdr + Aoehsz);
2109 if(ahin->cmdstat & 0xa9){
2110 eventlog("%æ: ata error cmd %.2ux stat %.2ux\n",
2111 d, ahout->cmdstat, ahin->cmdstat);
2115 n = ahout->scnt * Aoesectsz;
2116 switch(ahout->cmdstat){
2119 if(BLEN(b) - (Aoehsz + Aoeatasz) != n){
2120 eventlog("%æ: misread blen %ld expect %d\n",
2124 memmove(f->dp, b->rp + Aoehsz + Aoeatasz, n);
2128 f->nl->lostjumbo = 0;
2130 f->lba += n / Aoesectsz;
2131 f->dp = (uchar*)f->dp + n;
2137 if(BLEN(b) - (Aoehsz + Aoeatasz) < 512){
2138 eventlog("%æ: runt identify blen %ld expect %d\n",
2139 d, BLEN(b), 512 + Aoehsz + Aoeatasz);
2142 identify(d, (ushort*)(b->rp + Aoehsz + Aoeatasz));
2143 free(srb); /* BOTCH */
2147 eventlog("%æ: unknown ata command %.2ux \n",
2167 netrdaoeproc(void *v)
2170 char name[Maxpath+1], *s;
2176 idx = nl - netlinks.nl;
2177 netlinks.reader[idx] = 1;
2178 kstrcpy(name, nl->path, Maxpath);
2181 eventlog("netrdaoe@%s: exiting: %s\n", name, up->errstr);
2182 netlinks.reader[idx] = 0;
2183 wakeup(netlinks.rendez + idx);
2184 pexit(up->errstr, 1);
2187 discover(0xffff, 0xff);
2189 if((nl->flag & Dup) == 0)
2190 error("netlink is down");
2192 panic("netrdaoe: nl->dc == nil");
2193 b = devtab[nl->dc->type]->bread(nl->dc, 1<<16, 0);
2195 error("network read");
2197 if(h->verflag & AFrsp)
2198 if(s = aoeerror(h)){
2199 eventlog("%s: %s\n", nl->path, s);
2201 }else if(h->cmd == ACata)
2203 else if(h->cmd == ACconfig)
2205 else if((h->cmd & 0xf0) == 0){
2206 eventlog("%s: unknown cmd %d\n",
2208 errrsp(b, "unknown command");
2215 getaddr(char *path, uchar *ea)
2218 char buf[2*Eaddrlen+1];
2221 uprint("%s/addr", path);
2222 c = namec(up->genbuf, Aopen, OREAD, 0);
2228 panic("æ: getaddr: c == nil");
2229 n = devtab[c->type]->read(c, buf, sizeof buf-1, 0);
2233 if(parseether(ea, buf) < 0)
2234 error("parseether failure");
2241 uchar ea[2*Eaddrlen+1];
2242 Chan *dc, *cc, *mtu;
2245 snprint(addr, sizeof addr, "%s!0x%x", path, Aoetype);
2246 dc = chandial(addr, nil, nil, &cc);
2247 snprint(addr, sizeof addr, "%s/mtu", path);
2251 mtu = namec(addr, Aopen, OREAD, 0);
2262 if(dc == nil || cc == nil)
2265 nl = addnet(path, cc, dc, mtu, ea);
2266 snprint(addr, sizeof addr, "netrdaoe@%s", path);
2267 kproc(addr, netrdaoeproc, nl);
2274 return *(int*)v != 0;
2278 netunbind(char *path)
2281 Aoedev *d, *p, *next;
2288 e = n + nelem(netlinks.nl);
2292 if(n->dc && strcmp(n->path, path) == 0)
2296 error("device not bound");
2299 * hunt down devices using this interface; disable
2300 * this also terminates the reader.
2302 idx = n - netlinks.nl;
2304 for(d = devs.d; d; d = d->next){
2306 for(i = 0; i < d->ndl; i++){
2316 /* confirm reader is down. */
2319 sleep(netlinks.rendez + idx, unbound, netlinks.reader + idx);
2322 /* reschedule packets. */
2324 for(d = devs.d; d; d = d->next){
2326 for(i = 0; i < d->nframes; i++){
2328 if(f->tag != Tfree && f->nl == n)
2335 /* squeeze devlink pool. (we assert nobody is using them now) */
2337 for(d = devs.d; d; d = d->next){
2339 for(i = 0; i < d->ndl; i++){
2342 memmove(l, l + 1, sizeof *l * (--d->ndl - i));
2348 /* close device link. */
2354 memset(n, 0, sizeof *n);
2360 /* squeeze orphan devices */
2362 for(p = d = devs.d; d; d = next){
2369 downdev(d, "orphan");
2385 strtoss(char *f, uint *shelf, uint *slot)
2393 *shelf = strtol(f, &s, 0);
2394 if(s == f || *shelf > 0xffff)
2398 *slot = strtol(f, &s, 0);
2399 if(s == f || *slot > 0xff)
2405 discoverstr(char *f)
2409 strtoss(f, &shelf, &slot);
2410 discover(shelf, slot);
2414 removedev(Aoedev *d)
2422 for(p = devs.d; p; p = p->next)
2430 for(i = 0; i < d->nframes; i++)
2431 frameerror(d, d->frames+i, Enotup);
2447 switch(TYPE(c->qid)){
2459 removedev(unit2dev(UNIT(c->qid)));
2470 strtoss(f, &shelf, &slot);
2472 for(d = devs.d; d; d = d->next)
2473 if(shelf == d->major && slot == d->minor){
2474 wunlock(&devs); /* BOTCH */
2479 error("device not bound");
2483 topctlwrite(void *db, long n)
2497 static Cmdtab cmds[] = {
2498 { Autodiscover, "autodiscover", 0 },
2499 { Bind, "bind", 2 },
2500 { Debug, "debug", 0 },
2501 { Discover, "discover", 0 },
2502 { Rediscover, "rediscover", 0 },
2503 { Remove, "remove", 2 },
2504 { Unbind, "unbind", 2 },
2507 cb = parsecmd(db, n);
2512 ct = lookupcmd(cb, cmds, nelem(cmds));
2516 autodiscover = toggle(f, autodiscover, 1);
2522 debug = toggle(f, debug, 1);
2528 rediscover = toggle(f, rediscover, 1);
2531 removestr(f); /* depricated */
2543 aoewrite(Chan *c, void *db, long n, vlong off)
2545 switch(TYPE(c->qid)){
2553 return topctlwrite(db, n);
2558 return unitwrite(c, db, n, off);