The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/port/devaoe.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.