19ef1f84bSDavid du Colombier /*
29ef1f84bSDavid du Colombier * © 2005-2010 coraid
39ef1f84bSDavid du Colombier * ATA-over-Ethernet (AoE) storage initiator
49ef1f84bSDavid du Colombier */
59ef1f84bSDavid du Colombier
69ef1f84bSDavid du Colombier #include "u.h"
79ef1f84bSDavid du Colombier #include "../port/lib.h"
89ef1f84bSDavid du Colombier #include "mem.h"
99ef1f84bSDavid du Colombier #include "dat.h"
109ef1f84bSDavid du Colombier #include "fns.h"
119ef1f84bSDavid du Colombier #include "../port/error.h"
129ef1f84bSDavid du Colombier
139ef1f84bSDavid du Colombier #include "../port/netif.h"
149ef1f84bSDavid du Colombier #include "../ip/ip.h"
159ef1f84bSDavid du Colombier
169ef1f84bSDavid du Colombier #include "etherif.h"
179ef1f84bSDavid du Colombier #include "../port/aoe.h"
189ef1f84bSDavid du Colombier
199ef1f84bSDavid du Colombier #pragma varargck argpos eventlog 1
209ef1f84bSDavid du Colombier
219ef1f84bSDavid du Colombier #define dprint(...) if(debug) eventlog(__VA_ARGS__); else USED(debug);
229ef1f84bSDavid du Colombier #define uprint(...) snprint(up->genbuf, sizeof up->genbuf, __VA_ARGS__);
239ef1f84bSDavid du Colombier
249ef1f84bSDavid du Colombier enum {
259ef1f84bSDavid du Colombier Maxunits = 0xff,
269ef1f84bSDavid du Colombier Maxframes = 128,
279ef1f84bSDavid du Colombier Ndevlink = 6,
289ef1f84bSDavid du Colombier Nea = 6,
299ef1f84bSDavid du Colombier Nnetlink = 6,
309ef1f84bSDavid du Colombier };
319ef1f84bSDavid du Colombier
329ef1f84bSDavid du Colombier #define TYPE(q) ((ulong)(q).path & 0xf)
339ef1f84bSDavid du Colombier #define UNIT(q) (((ulong)(q).path>>4) & 0xff)
349ef1f84bSDavid du Colombier #define L(q) (((ulong)(q).path>>12) & 0xf)
359ef1f84bSDavid du Colombier #define QID(u, t) ((u)<<4 | (t))
369ef1f84bSDavid du Colombier #define Q3(l, u, t) ((l)<<8 | QID(u, t))
379ef1f84bSDavid du Colombier #define UP(d) ((d)->flag & Dup)
389ef1f84bSDavid du Colombier /*
399ef1f84bSDavid du Colombier * would like this to depend on the chan (srb).
409ef1f84bSDavid du Colombier * not possible in the current structure.
419ef1f84bSDavid du Colombier */
429ef1f84bSDavid du Colombier #define Nofail(d, s) ((d)->flag & Dnofail)
439ef1f84bSDavid du Colombier
449ef1f84bSDavid du Colombier #define MS2TK(t) ((t)/MS2HZ)
459ef1f84bSDavid du Colombier
469ef1f84bSDavid du Colombier enum {
479ef1f84bSDavid du Colombier Qzero,
489ef1f84bSDavid du Colombier Qtopdir = 1,
499ef1f84bSDavid du Colombier Qtopbase,
509ef1f84bSDavid du Colombier Qtopctl = Qtopbase,
519ef1f84bSDavid du Colombier Qtoplog,
529ef1f84bSDavid du Colombier Qtopend,
539ef1f84bSDavid du Colombier
549ef1f84bSDavid du Colombier Qunitdir,
559ef1f84bSDavid du Colombier Qunitbase,
569ef1f84bSDavid du Colombier Qctl = Qunitbase,
579ef1f84bSDavid du Colombier Qdata,
589ef1f84bSDavid du Colombier Qconfig,
599ef1f84bSDavid du Colombier Qident,
609ef1f84bSDavid du Colombier
619ef1f84bSDavid du Colombier Qdevlinkdir,
629ef1f84bSDavid du Colombier Qdevlinkbase,
639ef1f84bSDavid du Colombier Qdevlink = Qdevlinkbase,
649ef1f84bSDavid du Colombier Qdevlinkend,
659ef1f84bSDavid du Colombier
669ef1f84bSDavid du Colombier Qtopfiles = Qtopend-Qtopbase,
679ef1f84bSDavid du Colombier Qdevlinkfiles = Qdevlinkend-Qdevlinkbase,
689ef1f84bSDavid du Colombier
699ef1f84bSDavid du Colombier Eventlen = 256,
709ef1f84bSDavid du Colombier Nevents = 64, /* must be power of 2 */
719ef1f84bSDavid du Colombier
729ef1f84bSDavid du Colombier Fread = 0,
739ef1f84bSDavid du Colombier Fwrite,
749ef1f84bSDavid du Colombier Tfree = -1,
759ef1f84bSDavid du Colombier Tmgmt,
769ef1f84bSDavid du Colombier
779ef1f84bSDavid du Colombier /*
789ef1f84bSDavid du Colombier * round trip bounds, timeouts, in ticks.
799ef1f84bSDavid du Colombier * timeouts should be long enough that rebooting
809ef1f84bSDavid du Colombier * the coraid (which usually takes under two minutes)
819ef1f84bSDavid du Colombier * doesn't trigger a timeout.
829ef1f84bSDavid du Colombier */
839ef1f84bSDavid du Colombier Rtmax = MS2TK(320),
849ef1f84bSDavid du Colombier Rtmin = MS2TK(20),
859ef1f84bSDavid du Colombier Maxreqticks = 4*60*HZ, /* was 45*HZ */
869ef1f84bSDavid du Colombier
879ef1f84bSDavid du Colombier Dbcnt = 1024,
889ef1f84bSDavid du Colombier
899ef1f84bSDavid du Colombier Crd = 0x20,
909ef1f84bSDavid du Colombier Crdext = 0x24,
919ef1f84bSDavid du Colombier Cwr = 0x30,
929ef1f84bSDavid du Colombier Cwrext = 0x34,
939ef1f84bSDavid du Colombier Cid = 0xec,
949ef1f84bSDavid du Colombier };
959ef1f84bSDavid du Colombier
969ef1f84bSDavid du Colombier enum {
979ef1f84bSDavid du Colombier Read,
989ef1f84bSDavid du Colombier Write,
999ef1f84bSDavid du Colombier };
1009ef1f84bSDavid du Colombier
1019ef1f84bSDavid du Colombier /*
1029ef1f84bSDavid du Colombier * unified set of flags
1039ef1f84bSDavid du Colombier * a Netlink + Aoedev most both be jumbo capable
1049ef1f84bSDavid du Colombier * to send jumbograms to that interface.
1059ef1f84bSDavid du Colombier */
1069ef1f84bSDavid du Colombier enum {
1079ef1f84bSDavid du Colombier /* sync with ahci.h */
1089ef1f84bSDavid du Colombier Dllba = 1<<0,
1099ef1f84bSDavid du Colombier Dsmart = 1<<1,
1109ef1f84bSDavid du Colombier Dpower = 1<<2,
1119ef1f84bSDavid du Colombier Dnop = 1<<3,
1129ef1f84bSDavid du Colombier Datapi = 1<<4,
1139ef1f84bSDavid du Colombier Datapi16= 1<<5,
1149ef1f84bSDavid du Colombier
1159ef1f84bSDavid du Colombier /* aoe specific */
1169ef1f84bSDavid du Colombier Dup = 1<<6,
1179ef1f84bSDavid du Colombier Djumbo = 1<<7,
1189ef1f84bSDavid du Colombier Dnofail = 1<<8,
1199ef1f84bSDavid du Colombier };
1209ef1f84bSDavid du Colombier
1219ef1f84bSDavid du Colombier static char *flagname[] = {
1229ef1f84bSDavid du Colombier "llba",
1239ef1f84bSDavid du Colombier "smart",
1249ef1f84bSDavid du Colombier "power",
1259ef1f84bSDavid du Colombier "nop",
1269ef1f84bSDavid du Colombier "atapi",
1279ef1f84bSDavid du Colombier "atapi16",
1289ef1f84bSDavid du Colombier
1299ef1f84bSDavid du Colombier "up",
1309ef1f84bSDavid du Colombier "jumbo",
1319ef1f84bSDavid du Colombier "nofail",
1329ef1f84bSDavid du Colombier };
1339ef1f84bSDavid du Colombier
1349ef1f84bSDavid du Colombier typedef struct {
1359ef1f84bSDavid du Colombier ushort flag;
1369ef1f84bSDavid du Colombier uint lostjumbo;
1379ef1f84bSDavid du Colombier int datamtu;
1389ef1f84bSDavid du Colombier
1399ef1f84bSDavid du Colombier Chan *cc;
1409ef1f84bSDavid du Colombier Chan *dc;
1419ef1f84bSDavid du Colombier Chan *mtu; /* open early to prevent bind issues. */
1429ef1f84bSDavid du Colombier char path[Maxpath];
1439ef1f84bSDavid du Colombier uchar ea[Eaddrlen];
1449ef1f84bSDavid du Colombier } Netlink;
1459ef1f84bSDavid du Colombier
1469ef1f84bSDavid du Colombier typedef struct {
1479ef1f84bSDavid du Colombier Netlink *nl;
1489ef1f84bSDavid du Colombier int nea;
1499ef1f84bSDavid du Colombier ulong eaidx;
1509ef1f84bSDavid du Colombier uchar eatab[Nea][Eaddrlen];
1519ef1f84bSDavid du Colombier ulong npkt;
1529ef1f84bSDavid du Colombier ulong resent;
1539ef1f84bSDavid du Colombier ushort flag;
1549ef1f84bSDavid du Colombier
1559ef1f84bSDavid du Colombier ulong rttavg;
1569ef1f84bSDavid du Colombier ulong mintimer;
1579ef1f84bSDavid du Colombier } Devlink;
1589ef1f84bSDavid du Colombier
1599ef1f84bSDavid du Colombier typedef struct Srb Srb;
1609ef1f84bSDavid du Colombier struct Srb {
1619ef1f84bSDavid du Colombier Rendez;
1629ef1f84bSDavid du Colombier Srb *next;
163406c76faSDavid du Colombier int shared; /* Srb shared with kproc (don't free) */
1649ef1f84bSDavid du Colombier ulong ticksent;
1659ef1f84bSDavid du Colombier ulong len;
1669ef1f84bSDavid du Colombier vlong sector;
1679ef1f84bSDavid du Colombier short write;
1689ef1f84bSDavid du Colombier short nout;
1699ef1f84bSDavid du Colombier char *error;
1709ef1f84bSDavid du Colombier void *dp;
1719ef1f84bSDavid du Colombier void *data;
1729ef1f84bSDavid du Colombier };
1739ef1f84bSDavid du Colombier
1749ef1f84bSDavid du Colombier typedef struct {
1759ef1f84bSDavid du Colombier int tag;
1769ef1f84bSDavid du Colombier ulong bcnt;
1779ef1f84bSDavid du Colombier ulong dlen;
1789ef1f84bSDavid du Colombier vlong lba;
1799ef1f84bSDavid du Colombier ulong ticksent;
1809ef1f84bSDavid du Colombier int nhdr;
1819ef1f84bSDavid du Colombier uchar hdr[ETHERMINTU];
1829ef1f84bSDavid du Colombier void *dp;
1839ef1f84bSDavid du Colombier Devlink *dl;
1849ef1f84bSDavid du Colombier Netlink *nl;
1859ef1f84bSDavid du Colombier int eaidx;
1869ef1f84bSDavid du Colombier Srb *srb;
1879ef1f84bSDavid du Colombier } Frame;
1889ef1f84bSDavid du Colombier
1899ef1f84bSDavid du Colombier typedef struct Aoedev Aoedev;
1909ef1f84bSDavid du Colombier struct Aoedev {
1919ef1f84bSDavid du Colombier QLock;
1929ef1f84bSDavid du Colombier Aoedev *next;
1939ef1f84bSDavid du Colombier
1949ef1f84bSDavid du Colombier ulong vers;
1959ef1f84bSDavid du Colombier
1969ef1f84bSDavid du Colombier int ndl;
1979ef1f84bSDavid du Colombier ulong dlidx;
1989ef1f84bSDavid du Colombier Devlink *dl;
1999ef1f84bSDavid du Colombier Devlink dltab[Ndevlink];
2009ef1f84bSDavid du Colombier
2019ef1f84bSDavid du Colombier ushort fwver;
2029ef1f84bSDavid du Colombier ushort flag;
2039ef1f84bSDavid du Colombier int nopen;
2049ef1f84bSDavid du Colombier int major;
2059ef1f84bSDavid du Colombier int minor;
2069ef1f84bSDavid du Colombier int unit;
2079ef1f84bSDavid du Colombier int lasttag;
2089ef1f84bSDavid du Colombier int nframes;
2099ef1f84bSDavid du Colombier Frame *frames;
2109ef1f84bSDavid du Colombier vlong bsize;
2119ef1f84bSDavid du Colombier vlong realbsize;
2129ef1f84bSDavid du Colombier
2139ef1f84bSDavid du Colombier uint maxbcnt;
2149ef1f84bSDavid du Colombier ushort nout;
2159ef1f84bSDavid du Colombier ushort maxout;
2169ef1f84bSDavid du Colombier ulong lastwadj;
2179ef1f84bSDavid du Colombier Srb *head;
2189ef1f84bSDavid du Colombier Srb *tail;
2199ef1f84bSDavid du Colombier Srb *inprocess;
2209ef1f84bSDavid du Colombier
2219ef1f84bSDavid du Colombier /* magic numbers 'R' us */
2229ef1f84bSDavid du Colombier char serial[20+1];
2239ef1f84bSDavid du Colombier char firmware[8+1];
2249ef1f84bSDavid du Colombier char model[40+1];
2259ef1f84bSDavid du Colombier int nconfig;
2269ef1f84bSDavid du Colombier uchar config[1024];
2279ef1f84bSDavid du Colombier uchar ident[512];
2289ef1f84bSDavid du Colombier };
2299ef1f84bSDavid du Colombier
2309ef1f84bSDavid du Colombier #pragma varargck type "æ" Aoedev*
2319ef1f84bSDavid du Colombier
2329ef1f84bSDavid du Colombier static struct {
2339ef1f84bSDavid du Colombier Lock;
2349ef1f84bSDavid du Colombier QLock;
2359ef1f84bSDavid du Colombier Rendez;
2369ef1f84bSDavid du Colombier char buf[Eventlen*Nevents];
2379ef1f84bSDavid du Colombier char *rp;
2389ef1f84bSDavid du Colombier char *wp;
2399ef1f84bSDavid du Colombier } events;
2409ef1f84bSDavid du Colombier
2419ef1f84bSDavid du Colombier static struct {
2429ef1f84bSDavid du Colombier RWlock;
2439ef1f84bSDavid du Colombier int nd;
2449ef1f84bSDavid du Colombier Aoedev *d;
2459ef1f84bSDavid du Colombier } devs;
2469ef1f84bSDavid du Colombier
2479ef1f84bSDavid du Colombier static struct {
2489ef1f84bSDavid du Colombier Lock;
2499ef1f84bSDavid du Colombier int reader[Nnetlink]; /* reader is running. */
2509ef1f84bSDavid du Colombier Rendez rendez[Nnetlink]; /* confirm exit. */
2519ef1f84bSDavid du Colombier Netlink nl[Nnetlink];
2529ef1f84bSDavid du Colombier } netlinks;
2539ef1f84bSDavid du Colombier
2549ef1f84bSDavid du Colombier extern Dev aoedevtab;
2559ef1f84bSDavid du Colombier static Ref units;
2569ef1f84bSDavid du Colombier static Ref drivevers;
2579ef1f84bSDavid du Colombier static int debug;
2589ef1f84bSDavid du Colombier static int autodiscover = 1;
2599ef1f84bSDavid du Colombier static int rediscover;
2609ef1f84bSDavid du Colombier
2619ef1f84bSDavid du Colombier static Srb*
srballoc(ulong sz)2629ef1f84bSDavid du Colombier srballoc(ulong sz)
2639ef1f84bSDavid du Colombier {
2649ef1f84bSDavid du Colombier Srb *srb;
2659ef1f84bSDavid du Colombier
2669ef1f84bSDavid du Colombier srb = malloc(sizeof *srb+sz);
2679ef1f84bSDavid du Colombier if(srb == nil)
2689ef1f84bSDavid du Colombier error(Enomem);
2699ef1f84bSDavid du Colombier srb->dp = srb->data = srb+1;
2709ef1f84bSDavid du Colombier srb->ticksent = sys->ticks;
271406c76faSDavid du Colombier srb->shared = 0;
2729ef1f84bSDavid du Colombier return srb;
2739ef1f84bSDavid du Colombier }
2749ef1f84bSDavid du Colombier
2759ef1f84bSDavid du Colombier static Srb*
srbkalloc(void * db,ulong)2769ef1f84bSDavid du Colombier srbkalloc(void *db, ulong)
2779ef1f84bSDavid du Colombier {
2789ef1f84bSDavid du Colombier Srb *srb;
2799ef1f84bSDavid du Colombier
2809ef1f84bSDavid du Colombier srb = malloc(sizeof *srb);
2819ef1f84bSDavid du Colombier if(srb == nil)
2829ef1f84bSDavid du Colombier error(Enomem);
2839ef1f84bSDavid du Colombier srb->dp = srb->data = db;
2849ef1f84bSDavid du Colombier srb->ticksent = sys->ticks;
285406c76faSDavid du Colombier srb->shared = 0;
2869ef1f84bSDavid du Colombier return srb;
2879ef1f84bSDavid du Colombier }
2889ef1f84bSDavid du Colombier
289406c76faSDavid du Colombier static void
srbfree(Srb * srb)290406c76faSDavid du Colombier srbfree(Srb *srb)
291406c76faSDavid du Colombier {
292406c76faSDavid du Colombier while(srb->shared)
293406c76faSDavid du Colombier sched();
294406c76faSDavid du Colombier free(srb);
295406c76faSDavid du Colombier }
2969ef1f84bSDavid du Colombier
2979ef1f84bSDavid du Colombier static void
srberror(Srb * srb,char * s)2989ef1f84bSDavid du Colombier srberror(Srb *srb, char *s)
2999ef1f84bSDavid du Colombier {
3009ef1f84bSDavid du Colombier srb->error = s;
3019ef1f84bSDavid du Colombier srb->nout--;
3029ef1f84bSDavid du Colombier if(srb->nout == 0)
3039ef1f84bSDavid du Colombier wakeup(srb);
3049ef1f84bSDavid du Colombier }
3059ef1f84bSDavid du Colombier
3069ef1f84bSDavid du Colombier static void
frameerror(Aoedev * d,Frame * f,char * s)3079ef1f84bSDavid du Colombier frameerror(Aoedev *d, Frame *f, char *s)
3089ef1f84bSDavid du Colombier {
3099ef1f84bSDavid du Colombier Srb *srb;
3109ef1f84bSDavid du Colombier
3119ef1f84bSDavid du Colombier srb = f->srb;
3129ef1f84bSDavid du Colombier if(f->tag == Tfree || !srb)
3139ef1f84bSDavid du Colombier return;
3149ef1f84bSDavid du Colombier f->srb = nil;
3159ef1f84bSDavid du Colombier f->tag = Tfree; /* don't get fooled by way-slow responses */
3169ef1f84bSDavid du Colombier srberror(srb, s);
3179ef1f84bSDavid du Colombier d->nout--;
3189ef1f84bSDavid du Colombier }
3199ef1f84bSDavid du Colombier
3209ef1f84bSDavid du Colombier static char*
unitname(Aoedev * d)3219ef1f84bSDavid du Colombier unitname(Aoedev *d)
3229ef1f84bSDavid du Colombier {
3239ef1f84bSDavid du Colombier uprint("%d.%d", d->major, d->minor);
3249ef1f84bSDavid du Colombier return up->genbuf;
3259ef1f84bSDavid du Colombier }
3269ef1f84bSDavid du Colombier
3279ef1f84bSDavid du Colombier static int
eventlogready(void *)3289ef1f84bSDavid du Colombier eventlogready(void*)
3299ef1f84bSDavid du Colombier {
3309ef1f84bSDavid du Colombier return *events.rp;
3319ef1f84bSDavid du Colombier }
3329ef1f84bSDavid du Colombier
3339ef1f84bSDavid du Colombier static long
eventlogread(void * a,long n)3349ef1f84bSDavid du Colombier eventlogread(void *a, long n)
3359ef1f84bSDavid du Colombier {
3369ef1f84bSDavid du Colombier int len;
3379ef1f84bSDavid du Colombier char *p, *buf;
3389ef1f84bSDavid du Colombier
3399ef1f84bSDavid du Colombier buf = smalloc(Eventlen);
3409ef1f84bSDavid du Colombier qlock(&events);
3419ef1f84bSDavid du Colombier lock(&events);
3429ef1f84bSDavid du Colombier p = events.rp;
3439ef1f84bSDavid du Colombier len = *p;
3449ef1f84bSDavid du Colombier if(len == 0){
3459ef1f84bSDavid du Colombier n = 0;
3469ef1f84bSDavid du Colombier unlock(&events);
3479ef1f84bSDavid du Colombier } else {
3489ef1f84bSDavid du Colombier if(n > len)
3499ef1f84bSDavid du Colombier n = len;
3509ef1f84bSDavid du Colombier /* can't move directly into pageable space with events lock held */
3519ef1f84bSDavid du Colombier memmove(buf, p+1, n);
3529ef1f84bSDavid du Colombier *p = 0;
3539ef1f84bSDavid du Colombier events.rp = p += Eventlen;
3549ef1f84bSDavid du Colombier if(p >= events.buf + sizeof events.buf)
3559ef1f84bSDavid du Colombier events.rp = events.buf;
3569ef1f84bSDavid du Colombier unlock(&events);
3579ef1f84bSDavid du Colombier
3589ef1f84bSDavid du Colombier /* the concern here is page faults in memmove below */
3599ef1f84bSDavid du Colombier if(waserror()){
3609ef1f84bSDavid du Colombier free(buf);
3619ef1f84bSDavid du Colombier qunlock(&events);
3629ef1f84bSDavid du Colombier nexterror();
3639ef1f84bSDavid du Colombier }
3649ef1f84bSDavid du Colombier memmove(a, buf, n);
3659ef1f84bSDavid du Colombier poperror();
3669ef1f84bSDavid du Colombier }
3679ef1f84bSDavid du Colombier free(buf);
3689ef1f84bSDavid du Colombier qunlock(&events);
3699ef1f84bSDavid du Colombier return n;
3709ef1f84bSDavid du Colombier }
3719ef1f84bSDavid du Colombier
3729ef1f84bSDavid du Colombier static int
eventlog(char * fmt,...)3739ef1f84bSDavid du Colombier eventlog(char *fmt, ...)
3749ef1f84bSDavid du Colombier {
3759ef1f84bSDavid du Colombier int dragrp, n;
3769ef1f84bSDavid du Colombier char *p;
3779ef1f84bSDavid du Colombier va_list arg;
3789ef1f84bSDavid du Colombier
3799ef1f84bSDavid du Colombier lock(&events);
3809ef1f84bSDavid du Colombier p = events.wp;
3819ef1f84bSDavid du Colombier dragrp = *p++;
3829ef1f84bSDavid du Colombier va_start(arg, fmt);
3839ef1f84bSDavid du Colombier n = vsnprint(p, Eventlen-1, fmt, arg);
3849ef1f84bSDavid du Colombier *--p = n;
3859ef1f84bSDavid du Colombier p = events.wp += Eventlen;
3869ef1f84bSDavid du Colombier if(p >= events.buf + sizeof events.buf)
3879ef1f84bSDavid du Colombier p = events.wp = events.buf;
3889ef1f84bSDavid du Colombier if(dragrp)
3899ef1f84bSDavid du Colombier events.rp = p;
3909ef1f84bSDavid du Colombier unlock(&events);
3919ef1f84bSDavid du Colombier wakeup(&events);
3929ef1f84bSDavid du Colombier return n;
3939ef1f84bSDavid du Colombier }
3949ef1f84bSDavid du Colombier
3959ef1f84bSDavid du Colombier static int
eventcount(void)3969ef1f84bSDavid du Colombier eventcount(void)
3979ef1f84bSDavid du Colombier {
3989ef1f84bSDavid du Colombier int n;
3999ef1f84bSDavid du Colombier
4009ef1f84bSDavid du Colombier lock(&events);
4019ef1f84bSDavid du Colombier if(*events.rp == 0)
4029ef1f84bSDavid du Colombier n = 0;
4039ef1f84bSDavid du Colombier else
4049ef1f84bSDavid du Colombier n = (events.wp - events.rp) & (Nevents - 1);
4059ef1f84bSDavid du Colombier unlock(&events);
4069ef1f84bSDavid du Colombier return n/Eventlen;
4079ef1f84bSDavid du Colombier }
4089ef1f84bSDavid du Colombier
4099ef1f84bSDavid du Colombier static int
tsince(int tag)4109ef1f84bSDavid du Colombier tsince(int tag)
4119ef1f84bSDavid du Colombier {
4129ef1f84bSDavid du Colombier int n;
4139ef1f84bSDavid du Colombier
4149ef1f84bSDavid du Colombier n = sys->ticks & 0xffff;
4159ef1f84bSDavid du Colombier n -= tag & 0xffff;
4169ef1f84bSDavid du Colombier if(n < 0)
4179ef1f84bSDavid du Colombier n += 1<<16;
4189ef1f84bSDavid du Colombier return n;
4199ef1f84bSDavid du Colombier }
4209ef1f84bSDavid du Colombier
4219ef1f84bSDavid du Colombier static int
newtag(Aoedev * d)4229ef1f84bSDavid du Colombier newtag(Aoedev *d)
4239ef1f84bSDavid du Colombier {
4249ef1f84bSDavid du Colombier int t;
4259ef1f84bSDavid du Colombier
4269ef1f84bSDavid du Colombier do {
4279ef1f84bSDavid du Colombier t = ++d->lasttag << 16;
4289ef1f84bSDavid du Colombier t |= sys->ticks & 0xffff;
4299ef1f84bSDavid du Colombier } while (t == Tfree || t == Tmgmt);
4309ef1f84bSDavid du Colombier return t;
4319ef1f84bSDavid du Colombier }
4329ef1f84bSDavid du Colombier
4339ef1f84bSDavid du Colombier static void
downdev(Aoedev * d,char * err)4349ef1f84bSDavid du Colombier downdev(Aoedev *d, char *err)
4359ef1f84bSDavid du Colombier {
4369ef1f84bSDavid du Colombier Frame *f, *e;
4379ef1f84bSDavid du Colombier
4389ef1f84bSDavid du Colombier d->flag &= ~Dup;
4399ef1f84bSDavid du Colombier f = d->frames;
4409ef1f84bSDavid du Colombier e = f + d->nframes;
4419ef1f84bSDavid du Colombier for(; f < e; f->tag = Tfree, f->srb = nil, f++)
442406c76faSDavid du Colombier frameerror(d, f, Eaoedown);
4439ef1f84bSDavid du Colombier d->inprocess = nil;
4449ef1f84bSDavid du Colombier eventlog("%æ: removed; %s\n", d, err);
4459ef1f84bSDavid du Colombier }
4469ef1f84bSDavid du Colombier
4479ef1f84bSDavid du Colombier static Block*
allocfb(Frame * f)4489ef1f84bSDavid du Colombier allocfb(Frame *f)
4499ef1f84bSDavid du Colombier {
4509ef1f84bSDavid du Colombier int len;
4519ef1f84bSDavid du Colombier Block *b;
4529ef1f84bSDavid du Colombier
4539ef1f84bSDavid du Colombier len = f->nhdr + f->dlen;
4549ef1f84bSDavid du Colombier if(len < ETHERMINTU)
4559ef1f84bSDavid du Colombier len = ETHERMINTU;
4569ef1f84bSDavid du Colombier b = allocb(len);
4579ef1f84bSDavid du Colombier memmove(b->wp, f->hdr, f->nhdr);
4589ef1f84bSDavid du Colombier if(f->dlen)
4599ef1f84bSDavid du Colombier memmove(b->wp + f->nhdr, f->dp, f->dlen);
4609ef1f84bSDavid du Colombier b->wp += len;
4619ef1f84bSDavid du Colombier return b;
4629ef1f84bSDavid du Colombier }
4639ef1f84bSDavid du Colombier
4649ef1f84bSDavid du Colombier static void
putlba(Aoeata * a,vlong lba)4659ef1f84bSDavid du Colombier putlba(Aoeata *a, vlong lba)
4669ef1f84bSDavid du Colombier {
4679ef1f84bSDavid du Colombier uchar *c;
4689ef1f84bSDavid du Colombier
4699ef1f84bSDavid du Colombier c = a->lba;
4709ef1f84bSDavid du Colombier c[0] = lba;
4719ef1f84bSDavid du Colombier c[1] = lba >> 8;
4729ef1f84bSDavid du Colombier c[2] = lba >> 16;
4739ef1f84bSDavid du Colombier c[3] = lba >> 24;
4749ef1f84bSDavid du Colombier c[4] = lba >> 32;
4759ef1f84bSDavid du Colombier c[5] = lba >> 40;
4769ef1f84bSDavid du Colombier }
4779ef1f84bSDavid du Colombier
4789ef1f84bSDavid du Colombier static Devlink*
pickdevlink(Aoedev * d)4799ef1f84bSDavid du Colombier pickdevlink(Aoedev *d)
4809ef1f84bSDavid du Colombier {
4819ef1f84bSDavid du Colombier ulong i, n;
4829ef1f84bSDavid du Colombier Devlink *l;
4839ef1f84bSDavid du Colombier
4849ef1f84bSDavid du Colombier for(i = 0; i < d->ndl; i++){
4859ef1f84bSDavid du Colombier n = d->dlidx++ % d->ndl;
4869ef1f84bSDavid du Colombier l = d->dl + n;
4879ef1f84bSDavid du Colombier if(l && l->flag & Dup)
4889ef1f84bSDavid du Colombier return l;
4899ef1f84bSDavid du Colombier }
4909ef1f84bSDavid du Colombier return 0;
4919ef1f84bSDavid du Colombier }
4929ef1f84bSDavid du Colombier
4939ef1f84bSDavid du Colombier static int
pickea(Devlink * l)4949ef1f84bSDavid du Colombier pickea(Devlink *l)
4959ef1f84bSDavid du Colombier {
4969ef1f84bSDavid du Colombier if(l == 0)
4979ef1f84bSDavid du Colombier return -1;
4989ef1f84bSDavid du Colombier if(l->nea == 0)
4999ef1f84bSDavid du Colombier return -1;
5009ef1f84bSDavid du Colombier return l->eaidx++ % l->nea;
5019ef1f84bSDavid du Colombier }
5029ef1f84bSDavid du Colombier
5039ef1f84bSDavid du Colombier static int
hset(Aoedev * d,Frame * f,Aoehdr * h,int cmd)5049ef1f84bSDavid du Colombier hset(Aoedev *d, Frame *f, Aoehdr *h, int cmd)
5059ef1f84bSDavid du Colombier {
5069ef1f84bSDavid du Colombier int i;
5079ef1f84bSDavid du Colombier Devlink *l;
5089ef1f84bSDavid du Colombier
5099ef1f84bSDavid du Colombier if(f->srb && sys->ticks - f->srb->ticksent > Maxreqticks){
5109ef1f84bSDavid du Colombier eventlog("%æ: srb timeout\n", d);
5119ef1f84bSDavid du Colombier if(cmd == ACata && f->srb && Nofail(d, s))
5129ef1f84bSDavid du Colombier f->srb->ticksent = sys->ticks;
5139ef1f84bSDavid du Colombier else
5149ef1f84bSDavid du Colombier frameerror(d, f, Etimedout);
5159ef1f84bSDavid du Colombier return -1;
5169ef1f84bSDavid du Colombier }
5179ef1f84bSDavid du Colombier l = pickdevlink(d);
5189ef1f84bSDavid du Colombier i = pickea(l);
5199ef1f84bSDavid du Colombier if(i == -1){
5209ef1f84bSDavid du Colombier if(cmd != ACata || f->srb == nil || !Nofail(d, s))
5219ef1f84bSDavid du Colombier downdev(d, "resend fails; no netlink/ea");
5229ef1f84bSDavid du Colombier return -1;
5239ef1f84bSDavid du Colombier }
5249ef1f84bSDavid du Colombier memmove(h->dst, l->eatab[i], Eaddrlen);
5259ef1f84bSDavid du Colombier memmove(h->src, l->nl->ea, sizeof h->src);
5269ef1f84bSDavid du Colombier hnputs(h->type, Aoetype);
5279ef1f84bSDavid du Colombier h->verflag = Aoever << 4;
5289ef1f84bSDavid du Colombier h->error = 0;
5299ef1f84bSDavid du Colombier hnputs(h->major, d->major);
5309ef1f84bSDavid du Colombier h->minor = d->minor;
5319ef1f84bSDavid du Colombier h->cmd = cmd;
5329ef1f84bSDavid du Colombier
5339ef1f84bSDavid du Colombier hnputl(h->tag, f->tag = newtag(d));
5349ef1f84bSDavid du Colombier f->dl = l;
5359ef1f84bSDavid du Colombier f->nl = l->nl;
5369ef1f84bSDavid du Colombier f->eaidx = i;
5379ef1f84bSDavid du Colombier f->ticksent = sys->ticks;
5389ef1f84bSDavid du Colombier
5399ef1f84bSDavid du Colombier return f->tag;
5409ef1f84bSDavid du Colombier }
5419ef1f84bSDavid du Colombier
5429ef1f84bSDavid du Colombier static int
resend(Aoedev * d,Frame * f)5439ef1f84bSDavid du Colombier resend(Aoedev *d, Frame *f)
5449ef1f84bSDavid du Colombier {
5459ef1f84bSDavid du Colombier ulong n;
5469ef1f84bSDavid du Colombier Aoeata *a;
5479ef1f84bSDavid du Colombier
5489ef1f84bSDavid du Colombier a = (Aoeata*)f->hdr;
5499ef1f84bSDavid du Colombier if(hset(d, f, a, a->cmd) == -1)
5509ef1f84bSDavid du Colombier return -1;
5519ef1f84bSDavid du Colombier n = f->bcnt;
5529ef1f84bSDavid du Colombier if(n > d->maxbcnt){
5539ef1f84bSDavid du Colombier n = d->maxbcnt; /* mtu mismatch (jumbo fail?) */
5549ef1f84bSDavid du Colombier if(f->dlen > n)
5559ef1f84bSDavid du Colombier f->dlen = n;
5569ef1f84bSDavid du Colombier }
5579ef1f84bSDavid du Colombier a->scnt = n / Aoesectsz;
5589ef1f84bSDavid du Colombier f->dl->resent++;
5599ef1f84bSDavid du Colombier f->dl->npkt++;
5609ef1f84bSDavid du Colombier if(waserror())
5619ef1f84bSDavid du Colombier return -1;
5629ef1f84bSDavid du Colombier f->nl->dc->dev->bwrite(f->nl->dc, allocfb(f), 0);
5639ef1f84bSDavid du Colombier poperror();
5649ef1f84bSDavid du Colombier return 0;
5659ef1f84bSDavid du Colombier }
5669ef1f84bSDavid du Colombier
5679ef1f84bSDavid du Colombier static void
discover(int major,int minor)5689ef1f84bSDavid du Colombier discover(int major, int minor)
5699ef1f84bSDavid du Colombier {
5709ef1f84bSDavid du Colombier Aoehdr *h;
5719ef1f84bSDavid du Colombier Block *b;
5729ef1f84bSDavid du Colombier Netlink *nl, *e;
5739ef1f84bSDavid du Colombier
5749ef1f84bSDavid du Colombier nl = netlinks.nl;
5759ef1f84bSDavid du Colombier e = nl + nelem(netlinks.nl);
5769ef1f84bSDavid du Colombier for(; nl < e; nl++){
5779ef1f84bSDavid du Colombier if(nl->cc == nil)
5789ef1f84bSDavid du Colombier continue;
5799ef1f84bSDavid du Colombier b = allocb(ETHERMINTU);
5809ef1f84bSDavid du Colombier if(waserror()){
5819ef1f84bSDavid du Colombier freeb(b);
5829ef1f84bSDavid du Colombier nexterror();
5839ef1f84bSDavid du Colombier }
5849ef1f84bSDavid du Colombier b->wp = b->rp + ETHERMINTU;
5859ef1f84bSDavid du Colombier memset(b->rp, 0, ETHERMINTU);
5869ef1f84bSDavid du Colombier h = (Aoehdr*)b->rp;
5879ef1f84bSDavid du Colombier memset(h->dst, 0xff, sizeof h->dst);
5889ef1f84bSDavid du Colombier memmove(h->src, nl->ea, sizeof h->src);
5899ef1f84bSDavid du Colombier hnputs(h->type, Aoetype);
5909ef1f84bSDavid du Colombier h->verflag = Aoever << 4;
5919ef1f84bSDavid du Colombier hnputs(h->major, major);
5929ef1f84bSDavid du Colombier h->minor = minor;
5939ef1f84bSDavid du Colombier h->cmd = ACconfig;
5949ef1f84bSDavid du Colombier poperror();
5959ef1f84bSDavid du Colombier /* send b down the queue */
5969ef1f84bSDavid du Colombier nl->dc->dev->bwrite(nl->dc, b, 0);
5979ef1f84bSDavid du Colombier }
5989ef1f84bSDavid du Colombier }
5999ef1f84bSDavid du Colombier
6009ef1f84bSDavid du Colombier /*
6019ef1f84bSDavid du Colombier * Check all frames on device and resend any frames that have been
6029ef1f84bSDavid du Colombier * outstanding for 200% of the device round trip time average.
6039ef1f84bSDavid du Colombier */
6049ef1f84bSDavid du Colombier static void
aoesweepproc(void *)6059ef1f84bSDavid du Colombier aoesweepproc(void*)
6069ef1f84bSDavid du Colombier {
6079ef1f84bSDavid du Colombier ulong i, tx, timeout, nbc;
6089ef1f84bSDavid du Colombier vlong starttick;
6099ef1f84bSDavid du Colombier enum { Nms = 100, Nbcms = 30*1000, }; /* magic */
6109ef1f84bSDavid du Colombier uchar *ea;
6119ef1f84bSDavid du Colombier Aoeata *a;
6129ef1f84bSDavid du Colombier Aoedev *d;
6139ef1f84bSDavid du Colombier Devlink *l;
6149ef1f84bSDavid du Colombier Frame *f, *e;
6159ef1f84bSDavid du Colombier
6169ef1f84bSDavid du Colombier nbc = Nbcms/Nms;
6179ef1f84bSDavid du Colombier loop:
6189ef1f84bSDavid du Colombier if(nbc-- == 0){
6199ef1f84bSDavid du Colombier if(rediscover && !waserror()){
6209ef1f84bSDavid du Colombier discover(0xffff, 0xff);
6219ef1f84bSDavid du Colombier poperror();
6229ef1f84bSDavid du Colombier }
6239ef1f84bSDavid du Colombier nbc = Nbcms/Nms;
6249ef1f84bSDavid du Colombier }
6259ef1f84bSDavid du Colombier starttick = sys->ticks;
6269ef1f84bSDavid du Colombier rlock(&devs);
6279ef1f84bSDavid du Colombier for(d = devs.d; d; d = d->next){
6289ef1f84bSDavid du Colombier if(!canqlock(d))
6299ef1f84bSDavid du Colombier continue;
6309ef1f84bSDavid du Colombier if(!UP(d)){
6319ef1f84bSDavid du Colombier qunlock(d);
6329ef1f84bSDavid du Colombier continue;
6339ef1f84bSDavid du Colombier }
6349ef1f84bSDavid du Colombier tx = 0;
6359ef1f84bSDavid du Colombier f = d->frames;
6369ef1f84bSDavid du Colombier e = f + d->nframes;
6379ef1f84bSDavid du Colombier for (; f < e; f++){
6389ef1f84bSDavid du Colombier if(f->tag == Tfree)
6399ef1f84bSDavid du Colombier continue;
6409ef1f84bSDavid du Colombier l = f->dl;
6419ef1f84bSDavid du Colombier timeout = l->rttavg << 1;
6429ef1f84bSDavid du Colombier i = tsince(f->tag);
6439ef1f84bSDavid du Colombier if(i < timeout)
6449ef1f84bSDavid du Colombier continue;
6459ef1f84bSDavid du Colombier if(d->nout == d->maxout){
6469ef1f84bSDavid du Colombier if(d->maxout > 1)
6479ef1f84bSDavid du Colombier d->maxout--;
6489ef1f84bSDavid du Colombier d->lastwadj = sys->ticks;
6499ef1f84bSDavid du Colombier }
6509ef1f84bSDavid du Colombier a = (Aoeata*)f->hdr;
6519ef1f84bSDavid du Colombier if(a->scnt > Dbcnt / Aoesectsz &&
6529ef1f84bSDavid du Colombier ++f->nl->lostjumbo > (d->nframes << 1)){
6539ef1f84bSDavid du Colombier ea = f->dl->eatab[f->eaidx];
6549ef1f84bSDavid du Colombier eventlog("%æ: jumbo failure on %s:%E; lba%lld\n",
6559ef1f84bSDavid du Colombier d, f->nl->path, ea, f->lba);
6569ef1f84bSDavid du Colombier d->maxbcnt = Dbcnt;
6579ef1f84bSDavid du Colombier d->flag &= ~Djumbo;
6589ef1f84bSDavid du Colombier }
6599ef1f84bSDavid du Colombier resend(d, f);
6609ef1f84bSDavid du Colombier if(tx++ == 0){
6619ef1f84bSDavid du Colombier if((l->rttavg <<= 1) > Rtmax)
6629ef1f84bSDavid du Colombier l->rttavg = Rtmax;
6639ef1f84bSDavid du Colombier eventlog("%æ: rtt %ldms\n", d, TK2MS(l->rttavg));
6649ef1f84bSDavid du Colombier }
6659ef1f84bSDavid du Colombier }
6669ef1f84bSDavid du Colombier if(d->nout == d->maxout && d->maxout < d->nframes &&
6679ef1f84bSDavid du Colombier TK2MS(sys->ticks - d->lastwadj) > 10*1000){ /* more magic */
6689ef1f84bSDavid du Colombier d->maxout++;
6699ef1f84bSDavid du Colombier d->lastwadj = sys->ticks;
6709ef1f84bSDavid du Colombier }
6719ef1f84bSDavid du Colombier qunlock(d);
6729ef1f84bSDavid du Colombier }
6739ef1f84bSDavid du Colombier runlock(&devs);
6749ef1f84bSDavid du Colombier i = Nms - TK2MS(sys->ticks - starttick);
6759ef1f84bSDavid du Colombier if(i > 0)
6769ef1f84bSDavid du Colombier tsleep(&up->sleep, return0, 0, i);
6779ef1f84bSDavid du Colombier goto loop;
6789ef1f84bSDavid du Colombier }
6799ef1f84bSDavid du Colombier
6809ef1f84bSDavid du Colombier static int
6819ef1f84bSDavid du Colombier fmtæ(Fmt *f)
6829ef1f84bSDavid du Colombier {
6839ef1f84bSDavid du Colombier char buf[16];
6849ef1f84bSDavid du Colombier Aoedev *d;
6859ef1f84bSDavid du Colombier
6869ef1f84bSDavid du Colombier d = va_arg(f->args, Aoedev*);
6879ef1f84bSDavid du Colombier snprint(buf, sizeof buf, "aoe%d.%d", d->major, d->minor);
6889ef1f84bSDavid du Colombier return fmtstrcpy(f, buf);
6899ef1f84bSDavid du Colombier }
6909ef1f84bSDavid du Colombier
6919ef1f84bSDavid du Colombier static void netbind(char *path);
6929ef1f84bSDavid du Colombier
6939ef1f84bSDavid du Colombier static void
aoecfg(void)6949ef1f84bSDavid du Colombier aoecfg(void)
6959ef1f84bSDavid du Colombier {
6969ef1f84bSDavid du Colombier int n, i;
6979ef1f84bSDavid du Colombier char *p, *f[32], buf[24];
6989ef1f84bSDavid du Colombier
6999ef1f84bSDavid du Colombier if((p = getconf("aoeif")) == nil || (n = tokenize(p, f, nelem(f))) < 1)
7009ef1f84bSDavid du Colombier return;
7019ef1f84bSDavid du Colombier /* goo! */
7029ef1f84bSDavid du Colombier for(i = 0; i < n; i++){
7039ef1f84bSDavid du Colombier p = f[i];
7049ef1f84bSDavid du Colombier if(strncmp(p, "ether", 5) == 0)
7059ef1f84bSDavid du Colombier snprint(buf, sizeof buf, "#l%c/ether%c", p[5], p[5]);
7069ef1f84bSDavid du Colombier else if(strncmp(p, "#l", 2) == 0)
7079ef1f84bSDavid du Colombier snprint(buf, sizeof buf, "#l%c/ether%c", p[2], p[2]);
7089ef1f84bSDavid du Colombier else
7099ef1f84bSDavid du Colombier continue;
7109ef1f84bSDavid du Colombier if(!waserror()){
7119ef1f84bSDavid du Colombier netbind(buf);
7129ef1f84bSDavid du Colombier poperror();
7139ef1f84bSDavid du Colombier }
7149ef1f84bSDavid du Colombier }
7159ef1f84bSDavid du Colombier }
7169ef1f84bSDavid du Colombier
7179ef1f84bSDavid du Colombier static void
aoeinit(void)7189ef1f84bSDavid du Colombier aoeinit(void)
7199ef1f84bSDavid du Colombier {
7209ef1f84bSDavid du Colombier static int init;
7219ef1f84bSDavid du Colombier static QLock l;
7229ef1f84bSDavid du Colombier
7239ef1f84bSDavid du Colombier if(!canqlock(&l))
7249ef1f84bSDavid du Colombier return;
7259ef1f84bSDavid du Colombier if(init == 0){
7269ef1f84bSDavid du Colombier fmtinstall(L'æ', fmtæ);
7279ef1f84bSDavid du Colombier events.rp = events.wp = events.buf;
7289ef1f84bSDavid du Colombier kproc("aoesweep", aoesweepproc, nil);
7299ef1f84bSDavid du Colombier aoecfg();
7309ef1f84bSDavid du Colombier init = 1;
7319ef1f84bSDavid du Colombier }
7329ef1f84bSDavid du Colombier qunlock(&l);
7339ef1f84bSDavid du Colombier }
7349ef1f84bSDavid du Colombier
7359ef1f84bSDavid du Colombier static Chan*
aoeattach(char * spec)7369ef1f84bSDavid du Colombier aoeattach(char *spec)
7379ef1f84bSDavid du Colombier {
7389ef1f84bSDavid du Colombier Chan *c;
7399ef1f84bSDavid du Colombier
7409ef1f84bSDavid du Colombier if(*spec)
7419ef1f84bSDavid du Colombier error(Enonexist);
7429ef1f84bSDavid du Colombier aoeinit();
7439ef1f84bSDavid du Colombier c = devattach(L'æ', spec);
7449ef1f84bSDavid du Colombier mkqid(&c->qid, Qzero, 0, QTDIR);
7459ef1f84bSDavid du Colombier return c;
7469ef1f84bSDavid du Colombier }
7479ef1f84bSDavid du Colombier
7489ef1f84bSDavid du Colombier static Aoedev*
unit2dev(ulong unit)7499ef1f84bSDavid du Colombier unit2dev(ulong unit)
7509ef1f84bSDavid du Colombier {
7519ef1f84bSDavid du Colombier int i;
7529ef1f84bSDavid du Colombier Aoedev *d;
7539ef1f84bSDavid du Colombier
7549ef1f84bSDavid du Colombier rlock(&devs);
7559ef1f84bSDavid du Colombier i = 0;
7569ef1f84bSDavid du Colombier for(d = devs.d; d; d = d->next)
7579ef1f84bSDavid du Colombier if(i++ == unit){
7589ef1f84bSDavid du Colombier runlock(&devs);
7599ef1f84bSDavid du Colombier return d;
7609ef1f84bSDavid du Colombier }
7619ef1f84bSDavid du Colombier runlock(&devs);
7629ef1f84bSDavid du Colombier uprint("unit lookup failure: %#lux pc %#p", unit, getcallerpc(&unit));
7639ef1f84bSDavid du Colombier error(up->genbuf);
7649ef1f84bSDavid du Colombier return nil;
7659ef1f84bSDavid du Colombier }
7669ef1f84bSDavid du Colombier
7679ef1f84bSDavid du Colombier static int
unitgen(Chan * c,ulong type,Dir * dp)7689ef1f84bSDavid du Colombier unitgen(Chan *c, ulong type, Dir *dp)
7699ef1f84bSDavid du Colombier {
7709ef1f84bSDavid du Colombier int perm, t;
7719ef1f84bSDavid du Colombier ulong vers;
7729ef1f84bSDavid du Colombier vlong size;
7739ef1f84bSDavid du Colombier char *p;
7749ef1f84bSDavid du Colombier Aoedev *d;
7759ef1f84bSDavid du Colombier Qid q;
7769ef1f84bSDavid du Colombier
7779ef1f84bSDavid du Colombier d = unit2dev(UNIT(c->qid));
7789ef1f84bSDavid du Colombier perm = 0644;
7799ef1f84bSDavid du Colombier size = 0;
7809ef1f84bSDavid du Colombier vers = d->vers;
7819ef1f84bSDavid du Colombier t = QTFILE;
7829ef1f84bSDavid du Colombier
7839ef1f84bSDavid du Colombier switch(type){
7849ef1f84bSDavid du Colombier default:
7859ef1f84bSDavid du Colombier return -1;
7869ef1f84bSDavid du Colombier case Qctl:
7879ef1f84bSDavid du Colombier p = "ctl";
7889ef1f84bSDavid du Colombier break;
7899ef1f84bSDavid du Colombier case Qdata:
7909ef1f84bSDavid du Colombier p = "data";
7919ef1f84bSDavid du Colombier perm = 0640;
7929ef1f84bSDavid du Colombier if(UP(d))
7939ef1f84bSDavid du Colombier size = d->bsize;
7949ef1f84bSDavid du Colombier break;
7959ef1f84bSDavid du Colombier case Qconfig:
7969ef1f84bSDavid du Colombier p = "config";
7979ef1f84bSDavid du Colombier if(UP(d))
7989ef1f84bSDavid du Colombier size = d->nconfig;
7999ef1f84bSDavid du Colombier break;
8009ef1f84bSDavid du Colombier case Qident:
8019ef1f84bSDavid du Colombier p = "ident";
8029ef1f84bSDavid du Colombier if(UP(d))
8039ef1f84bSDavid du Colombier size = sizeof d->ident;
8049ef1f84bSDavid du Colombier break;
8059ef1f84bSDavid du Colombier case Qdevlinkdir:
8069ef1f84bSDavid du Colombier p = "devlink";
8079ef1f84bSDavid du Colombier t = QTDIR;
8089ef1f84bSDavid du Colombier perm = 0555;
8099ef1f84bSDavid du Colombier break;
8109ef1f84bSDavid du Colombier }
8119ef1f84bSDavid du Colombier mkqid(&q, QID(UNIT(c->qid), type), vers, t);
8129ef1f84bSDavid du Colombier devdir(c, q, p, size, eve, perm, dp);
8139ef1f84bSDavid du Colombier return 1;
8149ef1f84bSDavid du Colombier }
8159ef1f84bSDavid du Colombier
8169ef1f84bSDavid du Colombier static int
topgen(Chan * c,ulong type,Dir * d)8179ef1f84bSDavid du Colombier topgen(Chan *c, ulong type, Dir *d)
8189ef1f84bSDavid du Colombier {
8199ef1f84bSDavid du Colombier int perm;
8209ef1f84bSDavid du Colombier vlong size;
8219ef1f84bSDavid du Colombier char *p;
8229ef1f84bSDavid du Colombier Qid q;
8239ef1f84bSDavid du Colombier
8249ef1f84bSDavid du Colombier perm = 0444;
8259ef1f84bSDavid du Colombier size = 0;
8269ef1f84bSDavid du Colombier switch(type){
8279ef1f84bSDavid du Colombier default:
8289ef1f84bSDavid du Colombier return -1;
8299ef1f84bSDavid du Colombier case Qtopctl:
8309ef1f84bSDavid du Colombier p = "ctl";
8319ef1f84bSDavid du Colombier perm = 0644;
8329ef1f84bSDavid du Colombier break;
8339ef1f84bSDavid du Colombier case Qtoplog:
8349ef1f84bSDavid du Colombier p = "log";
8359ef1f84bSDavid du Colombier size = eventcount();
8369ef1f84bSDavid du Colombier break;
8379ef1f84bSDavid du Colombier }
8389ef1f84bSDavid du Colombier mkqid(&q, type, 0, QTFILE);
8399ef1f84bSDavid du Colombier devdir(c, q, p, size, eve, perm, d);
8409ef1f84bSDavid du Colombier return 1;
8419ef1f84bSDavid du Colombier }
8429ef1f84bSDavid du Colombier
8439ef1f84bSDavid du Colombier static int
aoegen(Chan * c,char *,Dirtab *,int,int s,Dir * dp)8449ef1f84bSDavid du Colombier aoegen(Chan *c, char *, Dirtab *, int, int s, Dir *dp)
8459ef1f84bSDavid du Colombier {
8469ef1f84bSDavid du Colombier int i;
8479ef1f84bSDavid du Colombier Aoedev *d;
8489ef1f84bSDavid du Colombier Qid q;
8499ef1f84bSDavid du Colombier
8509ef1f84bSDavid du Colombier if(c->qid.path == 0){
8519ef1f84bSDavid du Colombier switch(s){
8529ef1f84bSDavid du Colombier case DEVDOTDOT:
8539ef1f84bSDavid du Colombier q.path = 0;
8549ef1f84bSDavid du Colombier q.type = QTDIR;
8559ef1f84bSDavid du Colombier devdir(c, q, "#æ", 0, eve, 0555, dp);
8569ef1f84bSDavid du Colombier break;
8579ef1f84bSDavid du Colombier case 0:
8589ef1f84bSDavid du Colombier q.path = Qtopdir;
8599ef1f84bSDavid du Colombier q.type = QTDIR;
8609ef1f84bSDavid du Colombier devdir(c, q, "aoe", 0, eve, 0555, dp);
8619ef1f84bSDavid du Colombier break;
8629ef1f84bSDavid du Colombier default:
8639ef1f84bSDavid du Colombier return -1;
8649ef1f84bSDavid du Colombier }
8659ef1f84bSDavid du Colombier return 1;
8669ef1f84bSDavid du Colombier }
8679ef1f84bSDavid du Colombier
8689ef1f84bSDavid du Colombier switch(TYPE(c->qid)){
8699ef1f84bSDavid du Colombier default:
8709ef1f84bSDavid du Colombier return -1;
8719ef1f84bSDavid du Colombier case Qtopdir:
8729ef1f84bSDavid du Colombier if(s == DEVDOTDOT){
8739ef1f84bSDavid du Colombier mkqid(&q, Qzero, 0, QTDIR);
8749ef1f84bSDavid du Colombier devdir(c, q, "aoe", 0, eve, 0555, dp);
8759ef1f84bSDavid du Colombier return 1;
8769ef1f84bSDavid du Colombier }
8779ef1f84bSDavid du Colombier if(s < Qtopfiles)
8789ef1f84bSDavid du Colombier return topgen(c, Qtopbase + s, dp);
8799ef1f84bSDavid du Colombier s -= Qtopfiles;
8809ef1f84bSDavid du Colombier if(s >= units.ref)
8819ef1f84bSDavid du Colombier return -1;
8829ef1f84bSDavid du Colombier mkqid(&q, QID(s, Qunitdir), 0, QTDIR);
8839ef1f84bSDavid du Colombier d = unit2dev(s);
8849ef1f84bSDavid du Colombier assert(d != nil);
8859ef1f84bSDavid du Colombier devdir(c, q, unitname(d), 0, eve, 0555, dp);
8869ef1f84bSDavid du Colombier return 1;
8879ef1f84bSDavid du Colombier case Qtopctl:
8889ef1f84bSDavid du Colombier case Qtoplog:
8899ef1f84bSDavid du Colombier return topgen(c, TYPE(c->qid), dp);
8909ef1f84bSDavid du Colombier case Qunitdir:
8919ef1f84bSDavid du Colombier if(s == DEVDOTDOT){
8929ef1f84bSDavid du Colombier mkqid(&q, QID(0, Qtopdir), 0, QTDIR);
8939ef1f84bSDavid du Colombier uprint("%uld", UNIT(c->qid));
8949ef1f84bSDavid du Colombier devdir(c, q, up->genbuf, 0, eve, 0555, dp);
8959ef1f84bSDavid du Colombier return 1;
8969ef1f84bSDavid du Colombier }
8979ef1f84bSDavid du Colombier return unitgen(c, Qunitbase+s, dp);
8989ef1f84bSDavid du Colombier case Qctl:
8999ef1f84bSDavid du Colombier case Qdata:
9009ef1f84bSDavid du Colombier case Qconfig:
9019ef1f84bSDavid du Colombier case Qident:
9029ef1f84bSDavid du Colombier return unitgen(c, TYPE(c->qid), dp);
9039ef1f84bSDavid du Colombier case Qdevlinkdir:
9049ef1f84bSDavid du Colombier i = UNIT(c->qid);
9059ef1f84bSDavid du Colombier if(s == DEVDOTDOT){
9069ef1f84bSDavid du Colombier mkqid(&q, QID(i, Qunitdir), 0, QTDIR);
9079ef1f84bSDavid du Colombier devdir(c, q, "devlink", 0, eve, 0555, dp);
9089ef1f84bSDavid du Colombier return 1;
9099ef1f84bSDavid du Colombier }
9109ef1f84bSDavid du Colombier if(i >= units.ref)
9119ef1f84bSDavid du Colombier return -1;
9129ef1f84bSDavid du Colombier d = unit2dev(i);
9139ef1f84bSDavid du Colombier if(s >= d->ndl)
9149ef1f84bSDavid du Colombier return -1;
9159ef1f84bSDavid du Colombier uprint("%d", s);
9169ef1f84bSDavid du Colombier mkqid(&q, Q3(s, i, Qdevlink), 0, QTFILE);
9179ef1f84bSDavid du Colombier devdir(c, q, up->genbuf, 0, eve, 0755, dp);
9189ef1f84bSDavid du Colombier return 1;
9199ef1f84bSDavid du Colombier case Qdevlink:
9209ef1f84bSDavid du Colombier uprint("%d", s);
9219ef1f84bSDavid du Colombier mkqid(&q, Q3(s, UNIT(c->qid), Qdevlink), 0, QTFILE);
9229ef1f84bSDavid du Colombier devdir(c, q, up->genbuf, 0, eve, 0755, dp);
9239ef1f84bSDavid du Colombier return 1;
9249ef1f84bSDavid du Colombier }
9259ef1f84bSDavid du Colombier }
9269ef1f84bSDavid du Colombier
9279ef1f84bSDavid du Colombier static Walkqid*
aoewalk(Chan * c,Chan * nc,char ** name,int nname)9289ef1f84bSDavid du Colombier aoewalk(Chan *c, Chan *nc, char **name, int nname)
9299ef1f84bSDavid du Colombier {
9309ef1f84bSDavid du Colombier return devwalk(c, nc, name, nname, nil, 0, aoegen);
9319ef1f84bSDavid du Colombier }
9329ef1f84bSDavid du Colombier
9339ef1f84bSDavid du Colombier static long
aoestat(Chan * c,uchar * db,long n)9349ef1f84bSDavid du Colombier aoestat(Chan *c, uchar *db, long n)
9359ef1f84bSDavid du Colombier {
9369ef1f84bSDavid du Colombier return devstat(c, db, n, nil, 0, aoegen);
9379ef1f84bSDavid du Colombier }
9389ef1f84bSDavid du Colombier
9399ef1f84bSDavid du Colombier static Chan*
aoeopen(Chan * c,int omode)9409ef1f84bSDavid du Colombier aoeopen(Chan *c, int omode)
9419ef1f84bSDavid du Colombier {
9429ef1f84bSDavid du Colombier Aoedev *d;
9439ef1f84bSDavid du Colombier
9449ef1f84bSDavid du Colombier if(TYPE(c->qid) != Qdata)
9459ef1f84bSDavid du Colombier return devopen(c, omode, 0, 0, aoegen);
9469ef1f84bSDavid du Colombier
9479ef1f84bSDavid du Colombier d = unit2dev(UNIT(c->qid));
9489ef1f84bSDavid du Colombier qlock(d);
9499ef1f84bSDavid du Colombier if(waserror()){
9509ef1f84bSDavid du Colombier qunlock(d);
9519ef1f84bSDavid du Colombier nexterror();
9529ef1f84bSDavid du Colombier }
9539ef1f84bSDavid du Colombier if(!UP(d))
954406c76faSDavid du Colombier error(Eaoedown);
9559ef1f84bSDavid du Colombier c = devopen(c, omode, 0, 0, aoegen);
9569ef1f84bSDavid du Colombier d->nopen++;
9579ef1f84bSDavid du Colombier poperror();
9589ef1f84bSDavid du Colombier qunlock(d);
9599ef1f84bSDavid du Colombier return c;
9609ef1f84bSDavid du Colombier }
9619ef1f84bSDavid du Colombier
9629ef1f84bSDavid du Colombier static void
aoeclose(Chan * c)9639ef1f84bSDavid du Colombier aoeclose(Chan *c)
9649ef1f84bSDavid du Colombier {
9659ef1f84bSDavid du Colombier Aoedev *d;
9669ef1f84bSDavid du Colombier
9679ef1f84bSDavid du Colombier if(TYPE(c->qid) != Qdata || (c->flag&COPEN) == 0)
9689ef1f84bSDavid du Colombier return;
9699ef1f84bSDavid du Colombier
9709ef1f84bSDavid du Colombier d = unit2dev(UNIT(c->qid));
9719ef1f84bSDavid du Colombier qlock(d);
9729ef1f84bSDavid du Colombier if(--d->nopen == 0 && !waserror()){
9739ef1f84bSDavid du Colombier discover(d->major, d->minor);
9749ef1f84bSDavid du Colombier poperror();
9759ef1f84bSDavid du Colombier }
9769ef1f84bSDavid du Colombier qunlock(d);
9779ef1f84bSDavid du Colombier }
9789ef1f84bSDavid du Colombier
9799ef1f84bSDavid du Colombier static void
atarw(Aoedev * d,Frame * f)9809ef1f84bSDavid du Colombier atarw(Aoedev *d, Frame *f)
9819ef1f84bSDavid du Colombier {
9829ef1f84bSDavid du Colombier ulong bcnt;
9839ef1f84bSDavid du Colombier char extbit, writebit;
9849ef1f84bSDavid du Colombier Aoeata *ah;
9859ef1f84bSDavid du Colombier Srb *srb;
9869ef1f84bSDavid du Colombier
9879ef1f84bSDavid du Colombier extbit = 0x4;
9889ef1f84bSDavid du Colombier writebit = 0x10;
9899ef1f84bSDavid du Colombier
9909ef1f84bSDavid du Colombier srb = d->inprocess;
9919ef1f84bSDavid du Colombier bcnt = d->maxbcnt;
9929ef1f84bSDavid du Colombier if(bcnt > srb->len)
9939ef1f84bSDavid du Colombier bcnt = srb->len;
9949ef1f84bSDavid du Colombier f->nhdr = AOEATASZ;
9959ef1f84bSDavid du Colombier memset(f->hdr, 0, f->nhdr);
9969ef1f84bSDavid du Colombier ah = (Aoeata*)f->hdr;
9979ef1f84bSDavid du Colombier if(hset(d, f, ah, ACata) == -1) {
9989ef1f84bSDavid du Colombier d->inprocess = nil;
9999ef1f84bSDavid du Colombier return;
10009ef1f84bSDavid du Colombier }
10019ef1f84bSDavid du Colombier f->dp = srb->dp;
10029ef1f84bSDavid du Colombier f->bcnt = bcnt;
10039ef1f84bSDavid du Colombier f->lba = srb->sector;
10049ef1f84bSDavid du Colombier f->srb = srb;
10059ef1f84bSDavid du Colombier
10069ef1f84bSDavid du Colombier ah->scnt = bcnt / Aoesectsz;
10079ef1f84bSDavid du Colombier putlba(ah, f->lba);
10089ef1f84bSDavid du Colombier if(d->flag & Dllba)
10099ef1f84bSDavid du Colombier ah->aflag |= AAFext;
10109ef1f84bSDavid du Colombier else {
10119ef1f84bSDavid du Colombier extbit = 0;
10129ef1f84bSDavid du Colombier ah->lba[3] &= 0x0f;
10139ef1f84bSDavid du Colombier ah->lba[3] |= 0xe0; /* LBA bit+obsolete 0xa0 */
10149ef1f84bSDavid du Colombier }
10159ef1f84bSDavid du Colombier if(srb->write){
10169ef1f84bSDavid du Colombier ah->aflag |= AAFwrite;
10179ef1f84bSDavid du Colombier f->dlen = bcnt;
10189ef1f84bSDavid du Colombier }else{
10199ef1f84bSDavid du Colombier writebit = 0;
10209ef1f84bSDavid du Colombier f->dlen = 0;
10219ef1f84bSDavid du Colombier }
10229ef1f84bSDavid du Colombier ah->cmdstat = 0x20 | writebit | extbit;
10239ef1f84bSDavid du Colombier
10249ef1f84bSDavid du Colombier /* mark tracking fields and load out */
10259ef1f84bSDavid du Colombier srb->nout++;
10269ef1f84bSDavid du Colombier srb->dp = (uchar*)srb->dp + bcnt;
10279ef1f84bSDavid du Colombier srb->len -= bcnt;
10289ef1f84bSDavid du Colombier srb->sector += bcnt / Aoesectsz;
10299ef1f84bSDavid du Colombier if(srb->len == 0)
10309ef1f84bSDavid du Colombier d->inprocess = nil;
10319ef1f84bSDavid du Colombier d->nout++;
10329ef1f84bSDavid du Colombier f->dl->npkt++;
10339ef1f84bSDavid du Colombier if(waserror()){
10349ef1f84bSDavid du Colombier f->tag = Tfree;
10359ef1f84bSDavid du Colombier d->inprocess = nil;
10369ef1f84bSDavid du Colombier nexterror();
10379ef1f84bSDavid du Colombier }
10389ef1f84bSDavid du Colombier f->nl->dc->dev->bwrite(f->nl->dc, allocfb(f), 0);
10399ef1f84bSDavid du Colombier poperror();
10409ef1f84bSDavid du Colombier }
10419ef1f84bSDavid du Colombier
10429ef1f84bSDavid du Colombier static char*
aoeerror(Aoehdr * h)10439ef1f84bSDavid du Colombier aoeerror(Aoehdr *h)
10449ef1f84bSDavid du Colombier {
10459ef1f84bSDavid du Colombier int n;
10469ef1f84bSDavid du Colombier static char *errs[] = {
10479ef1f84bSDavid du Colombier "aoe protocol error: unknown",
10489ef1f84bSDavid du Colombier "aoe protocol error: bad command code",
10499ef1f84bSDavid du Colombier "aoe protocol error: bad argument param",
10509ef1f84bSDavid du Colombier "aoe protocol error: device unavailable",
10519ef1f84bSDavid du Colombier "aoe protocol error: config string present",
10529ef1f84bSDavid du Colombier "aoe protocol error: unsupported version",
10539ef1f84bSDavid du Colombier "aoe protocol error: target is reserved",
10549ef1f84bSDavid du Colombier };
10559ef1f84bSDavid du Colombier
10569ef1f84bSDavid du Colombier if((h->verflag & AFerr) == 0)
10579ef1f84bSDavid du Colombier return 0;
10589ef1f84bSDavid du Colombier n = h->error;
10599ef1f84bSDavid du Colombier if(n > nelem(errs))
10609ef1f84bSDavid du Colombier n = 0;
10619ef1f84bSDavid du Colombier return errs[n];
10629ef1f84bSDavid du Colombier }
10639ef1f84bSDavid du Colombier
10649ef1f84bSDavid du Colombier static void
rtupdate(Devlink * l,int rtt)10659ef1f84bSDavid du Colombier rtupdate(Devlink *l, int rtt)
10669ef1f84bSDavid du Colombier {
10679ef1f84bSDavid du Colombier int n;
10689ef1f84bSDavid du Colombier
10699ef1f84bSDavid du Colombier n = rtt;
10709ef1f84bSDavid du Colombier if(rtt < 0){
10719ef1f84bSDavid du Colombier n = -rtt;
10729ef1f84bSDavid du Colombier if(n < Rtmin)
10739ef1f84bSDavid du Colombier n = Rtmin;
10749ef1f84bSDavid du Colombier else if(n > Rtmax)
10759ef1f84bSDavid du Colombier n = Rtmax;
10769ef1f84bSDavid du Colombier l->mintimer += (n - l->mintimer) >> 1;
10779ef1f84bSDavid du Colombier } else if(n < l->mintimer)
10789ef1f84bSDavid du Colombier n = l->mintimer;
10799ef1f84bSDavid du Colombier else if(n > Rtmax)
10809ef1f84bSDavid du Colombier n = Rtmax;
10819ef1f84bSDavid du Colombier
10829ef1f84bSDavid du Colombier /* g == .25; cf. Congestion Avoidance and Control, Jacobson&Karels; 1988 */
10839ef1f84bSDavid du Colombier n -= l->rttavg;
10849ef1f84bSDavid du Colombier l->rttavg += n >> 2;
10859ef1f84bSDavid du Colombier }
10869ef1f84bSDavid du Colombier
10879ef1f84bSDavid du Colombier static int
srbready(void * v)10889ef1f84bSDavid du Colombier srbready(void *v)
10899ef1f84bSDavid du Colombier {
10909ef1f84bSDavid du Colombier Srb *s;
10919ef1f84bSDavid du Colombier
10929ef1f84bSDavid du Colombier s = v;
1093406c76faSDavid du Colombier return s->error || (s->nout == 0 && s->len == 0);
10949ef1f84bSDavid du Colombier }
10959ef1f84bSDavid du Colombier
10969ef1f84bSDavid du Colombier static Frame*
getframe(Aoedev * d,int tag)10979ef1f84bSDavid du Colombier getframe(Aoedev *d, int tag)
10989ef1f84bSDavid du Colombier {
10999ef1f84bSDavid du Colombier Frame *f, *e;
11009ef1f84bSDavid du Colombier
11019ef1f84bSDavid du Colombier f = d->frames;
11029ef1f84bSDavid du Colombier e = f + d->nframes;
11039ef1f84bSDavid du Colombier for(; f < e; f++)
11049ef1f84bSDavid du Colombier if(f->tag == tag)
11059ef1f84bSDavid du Colombier return f;
11069ef1f84bSDavid du Colombier return nil;
11079ef1f84bSDavid du Colombier }
11089ef1f84bSDavid du Colombier
11099ef1f84bSDavid du Colombier static Frame*
freeframe(Aoedev * d)11109ef1f84bSDavid du Colombier freeframe(Aoedev *d)
11119ef1f84bSDavid du Colombier {
11129ef1f84bSDavid du Colombier if(d->nout < d->maxout)
11139ef1f84bSDavid du Colombier return getframe(d, Tfree);
11149ef1f84bSDavid du Colombier return nil;
11159ef1f84bSDavid du Colombier }
11169ef1f84bSDavid du Colombier
11179ef1f84bSDavid du Colombier static void
work(Aoedev * d)11189ef1f84bSDavid du Colombier work(Aoedev *d)
11199ef1f84bSDavid du Colombier {
11209ef1f84bSDavid du Colombier Frame *f;
11219ef1f84bSDavid du Colombier
11229ef1f84bSDavid du Colombier while ((f = freeframe(d)) != nil) {
11239ef1f84bSDavid du Colombier if(d->inprocess == nil){
11249ef1f84bSDavid du Colombier if(d->head == nil)
11259ef1f84bSDavid du Colombier return;
11269ef1f84bSDavid du Colombier d->inprocess = d->head;
11279ef1f84bSDavid du Colombier d->head = d->head->next;
11289ef1f84bSDavid du Colombier if(d->head == nil)
11299ef1f84bSDavid du Colombier d->tail = nil;
11309ef1f84bSDavid du Colombier }
11319ef1f84bSDavid du Colombier atarw(d, f);
11329ef1f84bSDavid du Colombier }
11339ef1f84bSDavid du Colombier }
11349ef1f84bSDavid du Colombier
11359ef1f84bSDavid du Colombier static void
strategy(Aoedev * d,Srb * srb)11369ef1f84bSDavid du Colombier strategy(Aoedev *d, Srb *srb)
11379ef1f84bSDavid du Colombier {
11389ef1f84bSDavid du Colombier qlock(d);
11399ef1f84bSDavid du Colombier if(waserror()){
11409ef1f84bSDavid du Colombier qunlock(d);
11419ef1f84bSDavid du Colombier nexterror();
11429ef1f84bSDavid du Colombier }
11439ef1f84bSDavid du Colombier srb->next = nil;
11449ef1f84bSDavid du Colombier if(d->tail)
11459ef1f84bSDavid du Colombier d->tail->next = srb;
11469ef1f84bSDavid du Colombier d->tail = srb;
11479ef1f84bSDavid du Colombier if(d->head == nil)
11489ef1f84bSDavid du Colombier d->head = srb;
1149406c76faSDavid du Colombier srb->shared = 1;
11509ef1f84bSDavid du Colombier work(d);
11519ef1f84bSDavid du Colombier poperror();
11529ef1f84bSDavid du Colombier qunlock(d);
11539ef1f84bSDavid du Colombier
11549ef1f84bSDavid du Colombier while(waserror())
11559ef1f84bSDavid du Colombier ;
11569ef1f84bSDavid du Colombier sleep(srb, srbready, srb);
11579ef1f84bSDavid du Colombier poperror();
11589ef1f84bSDavid du Colombier }
11599ef1f84bSDavid du Colombier
11609ef1f84bSDavid du Colombier static long
rw(Aoedev * d,int write,uchar * db,long len,uvlong off)11619ef1f84bSDavid du Colombier rw(Aoedev *d, int write, uchar *db, long len, uvlong off)
11629ef1f84bSDavid du Colombier {
11639ef1f84bSDavid du Colombier long n, nlen, copy;
11649ef1f84bSDavid du Colombier enum { Srbsz = 1<<19, }; /* magic allocation */
11659ef1f84bSDavid du Colombier Srb *srb;
11669ef1f84bSDavid du Colombier
11679ef1f84bSDavid du Colombier if((off|len) & (Aoesectsz-1))
11689ef1f84bSDavid du Colombier error("offset and length must be sector multiple.\n");
11699ef1f84bSDavid du Colombier if(off > d->bsize || len == 0)
11709ef1f84bSDavid du Colombier return 0;
11719ef1f84bSDavid du Colombier if(off + len > d->bsize)
11729ef1f84bSDavid du Colombier len = d->bsize - off;
11739ef1f84bSDavid du Colombier copy = 0;
1174*5ae61b61SDavid du Colombier if(isdmaok(db, len, 32)){
11759ef1f84bSDavid du Colombier srb = srbkalloc(db, len);
11769ef1f84bSDavid du Colombier copy = 1;
11779ef1f84bSDavid du Colombier }else
11789ef1f84bSDavid du Colombier srb = srballoc(Srbsz <= len? Srbsz: len);
11799ef1f84bSDavid du Colombier if(waserror()){
11809ef1f84bSDavid du Colombier srbfree(srb);
11819ef1f84bSDavid du Colombier nexterror();
11829ef1f84bSDavid du Colombier }
11839ef1f84bSDavid du Colombier nlen = len;
11849ef1f84bSDavid du Colombier srb->write = write;
11859ef1f84bSDavid du Colombier do {
11869ef1f84bSDavid du Colombier if(!UP(d))
11879ef1f84bSDavid du Colombier error(Eio);
11889ef1f84bSDavid du Colombier srb->sector = off / Aoesectsz;
11899ef1f84bSDavid du Colombier srb->dp = srb->data;
11909ef1f84bSDavid du Colombier n = nlen;
11919ef1f84bSDavid du Colombier if(n > Srbsz)
11929ef1f84bSDavid du Colombier n = Srbsz;
11939ef1f84bSDavid du Colombier srb->len = n;
11949ef1f84bSDavid du Colombier if(write && !copy)
11959ef1f84bSDavid du Colombier memmove(srb->data, db, n);
11969ef1f84bSDavid du Colombier strategy(d, srb);
11979ef1f84bSDavid du Colombier if(srb->error)
11989ef1f84bSDavid du Colombier error(srb->error);
11999ef1f84bSDavid du Colombier if(!write && !copy)
12009ef1f84bSDavid du Colombier memmove(db, srb->data, n);
12019ef1f84bSDavid du Colombier nlen -= n;
12029ef1f84bSDavid du Colombier db += n;
12039ef1f84bSDavid du Colombier off += n;
12049ef1f84bSDavid du Colombier } while (nlen > 0);
12059ef1f84bSDavid du Colombier poperror();
12069ef1f84bSDavid du Colombier srbfree(srb);
12079ef1f84bSDavid du Colombier return len;
12089ef1f84bSDavid du Colombier }
12099ef1f84bSDavid du Colombier
12109ef1f84bSDavid du Colombier static long
readmem(ulong off,void * dst,long n,void * src,long size)12119ef1f84bSDavid du Colombier readmem(ulong off, void *dst, long n, void *src, long size)
12129ef1f84bSDavid du Colombier {
12139ef1f84bSDavid du Colombier if(off >= size)
12149ef1f84bSDavid du Colombier return 0;
12159ef1f84bSDavid du Colombier if(off + n > size)
12169ef1f84bSDavid du Colombier n = size - off;
12179ef1f84bSDavid du Colombier memmove(dst, (uchar*)src + off, n);
12189ef1f84bSDavid du Colombier return n;
12199ef1f84bSDavid du Colombier }
12209ef1f84bSDavid du Colombier
12219ef1f84bSDavid du Colombier static char *
pflag(char * s,char * e,uchar f)12229ef1f84bSDavid du Colombier pflag(char *s, char *e, uchar f)
12239ef1f84bSDavid du Colombier {
12249ef1f84bSDavid du Colombier uchar i;
12259ef1f84bSDavid du Colombier
12269ef1f84bSDavid du Colombier for(i = 0; i < 8; i++)
12279ef1f84bSDavid du Colombier if(f & (1 << i))
12289ef1f84bSDavid du Colombier s = seprint(s, e, "%s ", flagname[i]? flagname[i]: "oops");
12299ef1f84bSDavid du Colombier return seprint(s, e, "\n");
12309ef1f84bSDavid du Colombier }
12319ef1f84bSDavid du Colombier
12329ef1f84bSDavid du Colombier static int
pstat(Aoedev * d,char * db,int len,int off)12339ef1f84bSDavid du Colombier pstat(Aoedev *d, char *db, int len, int off)
12349ef1f84bSDavid du Colombier {
12359ef1f84bSDavid du Colombier int i;
12369ef1f84bSDavid du Colombier char *state, *s, *p, *e;
12379ef1f84bSDavid du Colombier
12389ef1f84bSDavid du Colombier s = p = malloc(READSTR);
12399ef1f84bSDavid du Colombier if(s == nil)
12409ef1f84bSDavid du Colombier error(Enomem);
12419ef1f84bSDavid du Colombier e = p + READSTR;
12429ef1f84bSDavid du Colombier
12439ef1f84bSDavid du Colombier state = "down";
12449ef1f84bSDavid du Colombier if(UP(d))
12459ef1f84bSDavid du Colombier state = "up";
12469ef1f84bSDavid du Colombier
12479ef1f84bSDavid du Colombier p = seprint(p, e,
12489ef1f84bSDavid du Colombier "state: %s\n" "nopen: %d\n" "nout: %d\n"
12499ef1f84bSDavid du Colombier "nmaxout: %d\n" "nframes: %d\n" "maxbcnt: %d\n"
12509ef1f84bSDavid du Colombier "fw: %.4ux\n"
12519ef1f84bSDavid du Colombier "model: %s\n" "serial: %s\n" "firmware: %s\n",
12529ef1f84bSDavid du Colombier state, d->nopen, d->nout,
12539ef1f84bSDavid du Colombier d->maxout, d->nframes, d->maxbcnt,
12549ef1f84bSDavid du Colombier d->fwver,
12559ef1f84bSDavid du Colombier d->model, d->serial, d->firmware);
12569ef1f84bSDavid du Colombier p = seprint(p, e, "flag: ");
12579ef1f84bSDavid du Colombier p = pflag(p, e, d->flag);
12589ef1f84bSDavid du Colombier
12599ef1f84bSDavid du Colombier if(p - s < len)
12609ef1f84bSDavid du Colombier len = p - s;
12619ef1f84bSDavid du Colombier i = readstr(off, db, len, s);
12629ef1f84bSDavid du Colombier free(s);
12639ef1f84bSDavid du Colombier return i;
12649ef1f84bSDavid du Colombier }
12659ef1f84bSDavid du Colombier
12669ef1f84bSDavid du Colombier static long
unitread(Chan * c,void * db,long len,vlong off)12679ef1f84bSDavid du Colombier unitread(Chan *c, void *db, long len, vlong off)
12689ef1f84bSDavid du Colombier {
12699ef1f84bSDavid du Colombier Aoedev *d;
12709ef1f84bSDavid du Colombier
12719ef1f84bSDavid du Colombier d = unit2dev(UNIT(c->qid));
12729ef1f84bSDavid du Colombier if(d->vers != c->qid.vers)
12739ef1f84bSDavid du Colombier error(Echange);
12749ef1f84bSDavid du Colombier switch(TYPE(c->qid)){
12759ef1f84bSDavid du Colombier default:
12769ef1f84bSDavid du Colombier error(Ebadarg);
12779ef1f84bSDavid du Colombier case Qctl:
12789ef1f84bSDavid du Colombier return pstat(d, db, len, off);
12799ef1f84bSDavid du Colombier case Qdata:
12809ef1f84bSDavid du Colombier return rw(d, Read, db, len, off);
12819ef1f84bSDavid du Colombier case Qconfig:
12829ef1f84bSDavid du Colombier if (!UP(d))
1283406c76faSDavid du Colombier error(Eaoedown);
12849ef1f84bSDavid du Colombier return readmem(off, db, len, d->config, d->nconfig);
12859ef1f84bSDavid du Colombier case Qident:
12869ef1f84bSDavid du Colombier if (!UP(d))
1287406c76faSDavid du Colombier error(Eaoedown);
12889ef1f84bSDavid du Colombier return readmem(off, db, len, d->ident, sizeof d->ident);
12899ef1f84bSDavid du Colombier }
12909ef1f84bSDavid du Colombier }
12919ef1f84bSDavid du Colombier
12929ef1f84bSDavid du Colombier static int
devlinkread(Chan * c,void * db,int len,int off)12939ef1f84bSDavid du Colombier devlinkread(Chan *c, void *db, int len, int off)
12949ef1f84bSDavid du Colombier {
12959ef1f84bSDavid du Colombier int i;
12969ef1f84bSDavid du Colombier char *s, *p, *e;
12979ef1f84bSDavid du Colombier Aoedev *d;
12989ef1f84bSDavid du Colombier Devlink *l;
12999ef1f84bSDavid du Colombier
13009ef1f84bSDavid du Colombier d = unit2dev(UNIT(c->qid));
13019ef1f84bSDavid du Colombier i = L(c->qid);
13029ef1f84bSDavid du Colombier if(i >= d->ndl)
13039ef1f84bSDavid du Colombier return 0;
13049ef1f84bSDavid du Colombier l = d->dl + i;
13059ef1f84bSDavid du Colombier
13069ef1f84bSDavid du Colombier s = p = malloc(READSTR);
13079ef1f84bSDavid du Colombier if(s == nil)
13089ef1f84bSDavid du Colombier error(Enomem);
13099ef1f84bSDavid du Colombier e = s + READSTR;
13109ef1f84bSDavid du Colombier
13119ef1f84bSDavid du Colombier p = seprint(p, e, "addr: ");
13129ef1f84bSDavid du Colombier for(i = 0; i < l->nea; i++)
13139ef1f84bSDavid du Colombier p = seprint(p, e, "%E ", l->eatab[i]);
13149ef1f84bSDavid du Colombier p = seprint(p, e, "\n");
13159ef1f84bSDavid du Colombier p = seprint(p, e, "npkt: %uld\n", l->npkt);
13169ef1f84bSDavid du Colombier p = seprint(p, e, "resent: %uld\n", l->resent);
13179ef1f84bSDavid du Colombier p = seprint(p, e, "flag: "); p = pflag(p, e, l->flag);
13189ef1f84bSDavid du Colombier p = seprint(p, e, "rttavg: %uld\n", TK2MS(l->rttavg));
13199ef1f84bSDavid du Colombier p = seprint(p, e, "mintimer: %uld\n", TK2MS(l->mintimer));
13209ef1f84bSDavid du Colombier
13219ef1f84bSDavid du Colombier p = seprint(p, e, "nl path: %s\n", l->nl->path);
13229ef1f84bSDavid du Colombier p = seprint(p, e, "nl ea: %E\n", l->nl->ea);
13239ef1f84bSDavid du Colombier p = seprint(p, e, "nl flag: "); p = pflag(p, e, l->flag);
13249ef1f84bSDavid du Colombier p = seprint(p, e, "nl lostjumbo: %d\n", l->nl->lostjumbo);
13259ef1f84bSDavid du Colombier p = seprint(p, e, "nl datamtu: %d\n", l->nl->datamtu);
13269ef1f84bSDavid du Colombier
13279ef1f84bSDavid du Colombier if(p - s < len)
13289ef1f84bSDavid du Colombier len = p - s;
13299ef1f84bSDavid du Colombier i = readstr(off, db, len, s);
13309ef1f84bSDavid du Colombier free(s);
13319ef1f84bSDavid du Colombier return i;
13329ef1f84bSDavid du Colombier }
13339ef1f84bSDavid du Colombier
13349ef1f84bSDavid du Colombier static long
topctlread(Chan *,void * db,int len,int off)13359ef1f84bSDavid du Colombier topctlread(Chan *, void *db, int len, int off)
13369ef1f84bSDavid du Colombier {
13379ef1f84bSDavid du Colombier int i;
13389ef1f84bSDavid du Colombier char *s, *p, *e;
13399ef1f84bSDavid du Colombier Netlink *n;
13409ef1f84bSDavid du Colombier
13419ef1f84bSDavid du Colombier s = p = malloc(READSTR);
13429ef1f84bSDavid du Colombier if(s == nil)
13439ef1f84bSDavid du Colombier error(Enomem);
13449ef1f84bSDavid du Colombier e = s + READSTR;
13459ef1f84bSDavid du Colombier
13469ef1f84bSDavid du Colombier p = seprint(p, e, "debug: %d\n", debug);
13479ef1f84bSDavid du Colombier p = seprint(p, e, "autodiscover: %d\n", autodiscover);
13489ef1f84bSDavid du Colombier p = seprint(p, e, "rediscover: %d\n", rediscover);
13499ef1f84bSDavid du Colombier
13509ef1f84bSDavid du Colombier for(i = 0; i < Nnetlink; i++){
13519ef1f84bSDavid du Colombier n = netlinks.nl+i;
13529ef1f84bSDavid du Colombier if(n->cc == 0)
13539ef1f84bSDavid du Colombier continue;
13549ef1f84bSDavid du Colombier p = seprint(p, e, "if%d path: %s\n", i, n->path);
13559ef1f84bSDavid du Colombier p = seprint(p, e, "if%d ea: %E\n", i, n->ea);
13569ef1f84bSDavid du Colombier p = seprint(p, e, "if%d flag: ", i); p = pflag(p, e, n->flag);
13579ef1f84bSDavid du Colombier p = seprint(p, e, "if%d lostjumbo: %d\n", i, n->lostjumbo);
13589ef1f84bSDavid du Colombier p = seprint(p, e, "if%d datamtu: %d\n", i, n->datamtu);
13599ef1f84bSDavid du Colombier }
13609ef1f84bSDavid du Colombier
13619ef1f84bSDavid du Colombier if(p - s < len)
13629ef1f84bSDavid du Colombier len = p - s;
13639ef1f84bSDavid du Colombier i = readstr(off, db, len, s);
13649ef1f84bSDavid du Colombier free(s);
13659ef1f84bSDavid du Colombier return i;
13669ef1f84bSDavid du Colombier }
13679ef1f84bSDavid du Colombier
13689ef1f84bSDavid du Colombier static long
aoeread(Chan * c,void * db,long n,vlong off)13699ef1f84bSDavid du Colombier aoeread(Chan *c, void *db, long n, vlong off)
13709ef1f84bSDavid du Colombier {
13719ef1f84bSDavid du Colombier switch(TYPE(c->qid)){
13729ef1f84bSDavid du Colombier default:
13739ef1f84bSDavid du Colombier error(Eperm);
13749ef1f84bSDavid du Colombier case Qzero:
13759ef1f84bSDavid du Colombier case Qtopdir:
13769ef1f84bSDavid du Colombier case Qunitdir:
13779ef1f84bSDavid du Colombier case Qdevlinkdir:
13789ef1f84bSDavid du Colombier return devdirread(c, db, n, 0, 0, aoegen);
13799ef1f84bSDavid du Colombier case Qtopctl:
13809ef1f84bSDavid du Colombier return topctlread(c, db, n, off);
13819ef1f84bSDavid du Colombier case Qtoplog:
13829ef1f84bSDavid du Colombier return eventlogread(db, n);
13839ef1f84bSDavid du Colombier case Qctl:
13849ef1f84bSDavid du Colombier case Qdata:
13859ef1f84bSDavid du Colombier case Qconfig:
13869ef1f84bSDavid du Colombier case Qident:
13879ef1f84bSDavid du Colombier return unitread(c, db, n, off);
13889ef1f84bSDavid du Colombier case Qdevlink:
13899ef1f84bSDavid du Colombier return devlinkread(c, db, n, off);
13909ef1f84bSDavid du Colombier }
13919ef1f84bSDavid du Colombier }
13929ef1f84bSDavid du Colombier
13939ef1f84bSDavid du Colombier static long
configwrite(Aoedev * d,void * db,long len)13949ef1f84bSDavid du Colombier configwrite(Aoedev *d, void *db, long len)
13959ef1f84bSDavid du Colombier {
13969ef1f84bSDavid du Colombier char *s;
13979ef1f84bSDavid du Colombier Aoeqc *ch;
13989ef1f84bSDavid du Colombier Frame *f;
13999ef1f84bSDavid du Colombier Srb *srb;
14009ef1f84bSDavid du Colombier
14019ef1f84bSDavid du Colombier if(!UP(d))
1402406c76faSDavid du Colombier error(Eaoedown);
14039ef1f84bSDavid du Colombier if(len > ETHERMAXTU - AOEQCSZ)
14049ef1f84bSDavid du Colombier error(Etoobig);
14059ef1f84bSDavid du Colombier srb = srballoc(len);
14069ef1f84bSDavid du Colombier s = malloc(len);
14079ef1f84bSDavid du Colombier if(s == nil)
14089ef1f84bSDavid du Colombier error(Enomem);
14099ef1f84bSDavid du Colombier memmove(s, db, len);
1410406c76faSDavid du Colombier
14119ef1f84bSDavid du Colombier if(waserror()){
14129ef1f84bSDavid du Colombier srbfree(srb);
14139ef1f84bSDavid du Colombier free(s);
14149ef1f84bSDavid du Colombier nexterror();
14159ef1f84bSDavid du Colombier }
14169ef1f84bSDavid du Colombier for (;;) {
14179ef1f84bSDavid du Colombier qlock(d);
14189ef1f84bSDavid du Colombier if(waserror()){
14199ef1f84bSDavid du Colombier qunlock(d);
14209ef1f84bSDavid du Colombier nexterror();
14219ef1f84bSDavid du Colombier }
14229ef1f84bSDavid du Colombier f = freeframe(d);
14239ef1f84bSDavid du Colombier if(f != nil)
14249ef1f84bSDavid du Colombier break;
14259ef1f84bSDavid du Colombier poperror();
14269ef1f84bSDavid du Colombier qunlock(d);
1427406c76faSDavid du Colombier
14289ef1f84bSDavid du Colombier if(waserror())
14299ef1f84bSDavid du Colombier nexterror();
14309ef1f84bSDavid du Colombier tsleep(&up->sleep, return0, 0, 100);
14319ef1f84bSDavid du Colombier poperror();
14329ef1f84bSDavid du Colombier }
14339ef1f84bSDavid du Colombier f->nhdr = AOEQCSZ;
14349ef1f84bSDavid du Colombier memset(f->hdr, 0, f->nhdr);
14359ef1f84bSDavid du Colombier ch = (Aoeqc*)f->hdr;
1436406c76faSDavid du Colombier if(hset(d, f, ch, ACconfig) == -1) {
1437406c76faSDavid du Colombier /*
1438406c76faSDavid du Colombier * these refer to qlock & waserror in the above for loop.
1439406c76faSDavid du Colombier * there's still the first waserror outstanding.
1440406c76faSDavid du Colombier */
1441406c76faSDavid du Colombier poperror();
1442406c76faSDavid du Colombier qunlock(d);
14439ef1f84bSDavid du Colombier return 0;
1444406c76faSDavid du Colombier }
1445406c76faSDavid du Colombier srb->shared = 1;
14469ef1f84bSDavid du Colombier f->srb = srb;
14479ef1f84bSDavid du Colombier f->dp = s;
14489ef1f84bSDavid du Colombier ch->verccmd = AQCfset;
14499ef1f84bSDavid du Colombier hnputs(ch->cslen, len);
14509ef1f84bSDavid du Colombier d->nout++;
14519ef1f84bSDavid du Colombier srb->nout++;
14529ef1f84bSDavid du Colombier f->dl->npkt++;
14539ef1f84bSDavid du Colombier f->dlen = len;
1454406c76faSDavid du Colombier /* these too */
14559ef1f84bSDavid du Colombier poperror();
14569ef1f84bSDavid du Colombier qunlock(d);
14579ef1f84bSDavid du Colombier
14589ef1f84bSDavid du Colombier f->nl->dc->dev->bwrite(f->nl->dc, allocfb(f), 0);
14599ef1f84bSDavid du Colombier sleep(srb, srbready, srb);
14609ef1f84bSDavid du Colombier if(srb->error)
14619ef1f84bSDavid du Colombier error(srb->error);
14629ef1f84bSDavid du Colombier
14639ef1f84bSDavid du Colombier qlock(d);
14649ef1f84bSDavid du Colombier if(waserror()){
14659ef1f84bSDavid du Colombier qunlock(d);
14669ef1f84bSDavid du Colombier nexterror();
14679ef1f84bSDavid du Colombier }
14689ef1f84bSDavid du Colombier memmove(d->config, s, len);
14699ef1f84bSDavid du Colombier d->nconfig = len;
14709ef1f84bSDavid du Colombier poperror();
14719ef1f84bSDavid du Colombier qunlock(d);
14729ef1f84bSDavid du Colombier
14739ef1f84bSDavid du Colombier poperror(); /* pop first waserror */
14749ef1f84bSDavid du Colombier
14759ef1f84bSDavid du Colombier srbfree(srb);
14769ef1f84bSDavid du Colombier memmove(db, s, len);
14779ef1f84bSDavid du Colombier free(s);
14789ef1f84bSDavid du Colombier return len;
14799ef1f84bSDavid du Colombier }
14809ef1f84bSDavid du Colombier
14819ef1f84bSDavid du Colombier static int getmtu(Chan*);
14829ef1f84bSDavid du Colombier
14839ef1f84bSDavid du Colombier static int
devmaxdata(Aoedev * d)14849ef1f84bSDavid du Colombier devmaxdata(Aoedev *d) /* return aoe mtu (excluding headers) */
14859ef1f84bSDavid du Colombier {
14869ef1f84bSDavid du Colombier int i, nmtu, mtu;
14879ef1f84bSDavid du Colombier Devlink *l;
14889ef1f84bSDavid du Colombier Netlink *n;
14899ef1f84bSDavid du Colombier
14909ef1f84bSDavid du Colombier mtu = 100000;
14919ef1f84bSDavid du Colombier for(i = 0; i < d->ndl; i++){
14929ef1f84bSDavid du Colombier l = d->dl + i;
14939ef1f84bSDavid du Colombier n = l->nl;
14949ef1f84bSDavid du Colombier if((l->flag & Dup) == 0 || (n->flag & Dup) == 0)
14959ef1f84bSDavid du Colombier continue;
14969ef1f84bSDavid du Colombier nmtu = getmtu(n->mtu);
14979ef1f84bSDavid du Colombier if(mtu > nmtu)
14989ef1f84bSDavid du Colombier mtu = nmtu;
14999ef1f84bSDavid du Colombier }
15009ef1f84bSDavid du Colombier if(mtu == 100000)
15019ef1f84bSDavid du Colombier mtu = ETHERMAXTU; /* normal ethernet mtu */
15029ef1f84bSDavid du Colombier mtu -= AOEATASZ;
15039ef1f84bSDavid du Colombier mtu -= (uint)mtu % Aoesectsz;
15049ef1f84bSDavid du Colombier if(mtu < 2*Aoesectsz) /* sanity */
15059ef1f84bSDavid du Colombier mtu = 2*Aoesectsz;
15069ef1f84bSDavid du Colombier return mtu;
15079ef1f84bSDavid du Colombier }
15089ef1f84bSDavid du Colombier
15099ef1f84bSDavid du Colombier static int
toggle(char * s,int f,int bit)15109ef1f84bSDavid du Colombier toggle(char *s, int f, int bit)
15119ef1f84bSDavid du Colombier {
15129ef1f84bSDavid du Colombier if(s == nil)
15139ef1f84bSDavid du Colombier f ^= bit;
15149ef1f84bSDavid du Colombier else if(strcmp(s, "on") == 0)
15159ef1f84bSDavid du Colombier f |= bit;
15169ef1f84bSDavid du Colombier else
15179ef1f84bSDavid du Colombier f &= ~bit;
15189ef1f84bSDavid du Colombier return f;
15199ef1f84bSDavid du Colombier }
15209ef1f84bSDavid du Colombier
15219ef1f84bSDavid du Colombier static void ataident(Aoedev*);
15229ef1f84bSDavid du Colombier
15239ef1f84bSDavid du Colombier static long
unitctlwrite(Aoedev * d,void * db,long n)15249ef1f84bSDavid du Colombier unitctlwrite(Aoedev *d, void *db, long n)
15259ef1f84bSDavid du Colombier {
15269ef1f84bSDavid du Colombier uint maxbcnt, mtu;
15279ef1f84bSDavid du Colombier uvlong bsize;
15289ef1f84bSDavid du Colombier enum {
15299ef1f84bSDavid du Colombier Failio,
15309ef1f84bSDavid du Colombier Ident,
15319ef1f84bSDavid du Colombier Jumbo,
15329ef1f84bSDavid du Colombier Maxbno,
15339ef1f84bSDavid du Colombier Mtu,
15349ef1f84bSDavid du Colombier Nofailf,
15359ef1f84bSDavid du Colombier Setsize,
15369ef1f84bSDavid du Colombier };
15379ef1f84bSDavid du Colombier Cmdbuf *cb;
15389ef1f84bSDavid du Colombier Cmdtab *ct;
15399ef1f84bSDavid du Colombier static Cmdtab cmds[] = {
15409ef1f84bSDavid du Colombier {Failio, "failio", 1 },
15419ef1f84bSDavid du Colombier {Ident, "identify", 1 },
15429ef1f84bSDavid du Colombier {Jumbo, "jumbo", 0 },
15439ef1f84bSDavid du Colombier {Maxbno, "maxbno", 0 },
15449ef1f84bSDavid du Colombier {Mtu, "mtu", 0 },
15459ef1f84bSDavid du Colombier {Nofailf, "nofail", 0 },
15469ef1f84bSDavid du Colombier {Setsize, "setsize", 0 },
15479ef1f84bSDavid du Colombier };
15489ef1f84bSDavid du Colombier
15499ef1f84bSDavid du Colombier cb = parsecmd(db, n);
15509ef1f84bSDavid du Colombier qlock(d);
15519ef1f84bSDavid du Colombier if(waserror()){
15529ef1f84bSDavid du Colombier qunlock(d);
15539ef1f84bSDavid du Colombier free(cb);
15549ef1f84bSDavid du Colombier nexterror();
15559ef1f84bSDavid du Colombier }
15569ef1f84bSDavid du Colombier ct = lookupcmd(cb, cmds, nelem(cmds));
15579ef1f84bSDavid du Colombier switch(ct->index){
15589ef1f84bSDavid du Colombier case Failio:
15599ef1f84bSDavid du Colombier downdev(d, "i/o failure");
15609ef1f84bSDavid du Colombier break;
15619ef1f84bSDavid du Colombier case Ident:
15629ef1f84bSDavid du Colombier ataident(d);
15639ef1f84bSDavid du Colombier break;
15649ef1f84bSDavid du Colombier case Jumbo:
15659ef1f84bSDavid du Colombier d->flag = toggle(cb->f[1], d->flag, Djumbo);
15669ef1f84bSDavid du Colombier break;
15679ef1f84bSDavid du Colombier case Maxbno:
15689ef1f84bSDavid du Colombier case Mtu:
15699ef1f84bSDavid du Colombier maxbcnt = devmaxdata(d);
15709ef1f84bSDavid du Colombier if(cb->nf > 2)
15719ef1f84bSDavid du Colombier error(Ecmdargs);
15729ef1f84bSDavid du Colombier if(cb->nf == 2){
15739ef1f84bSDavid du Colombier mtu = strtoul(cb->f[1], 0, 0);
15749ef1f84bSDavid du Colombier if(ct->index == Maxbno)
15759ef1f84bSDavid du Colombier mtu *= Aoesectsz;
15769ef1f84bSDavid du Colombier else{
15779ef1f84bSDavid du Colombier mtu -= AOEATASZ;
15789ef1f84bSDavid du Colombier mtu &= ~(Aoesectsz-1);
15799ef1f84bSDavid du Colombier }
15809ef1f84bSDavid du Colombier if(mtu == 0 || mtu > maxbcnt)
15819ef1f84bSDavid du Colombier cmderror(cb, "mtu out of legal range");
15829ef1f84bSDavid du Colombier maxbcnt = mtu;
15839ef1f84bSDavid du Colombier }
15849ef1f84bSDavid du Colombier d->maxbcnt = maxbcnt;
15859ef1f84bSDavid du Colombier break;
15869ef1f84bSDavid du Colombier case Nofailf:
15879ef1f84bSDavid du Colombier d->flag = toggle(cb->f[1], d->flag, Dnofail);
15889ef1f84bSDavid du Colombier break;
15899ef1f84bSDavid du Colombier case Setsize:
15909ef1f84bSDavid du Colombier bsize = d->realbsize;
15919ef1f84bSDavid du Colombier if(cb->nf > 2)
15929ef1f84bSDavid du Colombier error(Ecmdargs);
15939ef1f84bSDavid du Colombier if(cb->nf == 2){
15949ef1f84bSDavid du Colombier bsize = strtoull(cb->f[1], 0, 0);
15959ef1f84bSDavid du Colombier if(bsize % Aoesectsz)
15969ef1f84bSDavid du Colombier cmderror(cb, "disk size must be sector aligned");
15979ef1f84bSDavid du Colombier }
15989ef1f84bSDavid du Colombier d->bsize = bsize;
15999ef1f84bSDavid du Colombier break;
16009ef1f84bSDavid du Colombier default:
16019ef1f84bSDavid du Colombier cmderror(cb, "unknown aoe control message");
16029ef1f84bSDavid du Colombier }
16039ef1f84bSDavid du Colombier poperror();
16049ef1f84bSDavid du Colombier qunlock(d);
16059ef1f84bSDavid du Colombier free(cb);
16069ef1f84bSDavid du Colombier return n;
16079ef1f84bSDavid du Colombier }
16089ef1f84bSDavid du Colombier
16099ef1f84bSDavid du Colombier static long
unitwrite(Chan * c,void * db,long n,vlong off)16109ef1f84bSDavid du Colombier unitwrite(Chan *c, void *db, long n, vlong off)
16119ef1f84bSDavid du Colombier {
16129ef1f84bSDavid du Colombier long rv;
16139ef1f84bSDavid du Colombier char *buf;
16149ef1f84bSDavid du Colombier Aoedev *d;
16159ef1f84bSDavid du Colombier
16169ef1f84bSDavid du Colombier d = unit2dev(UNIT(c->qid));
16179ef1f84bSDavid du Colombier switch(TYPE(c->qid)){
16189ef1f84bSDavid du Colombier default:
16199ef1f84bSDavid du Colombier error(Ebadarg);
16209ef1f84bSDavid du Colombier case Qctl:
16219ef1f84bSDavid du Colombier return unitctlwrite(d, db, n);
16229ef1f84bSDavid du Colombier case Qident:
16239ef1f84bSDavid du Colombier error(Eperm);
16249ef1f84bSDavid du Colombier case Qdata:
16259ef1f84bSDavid du Colombier return rw(d, Write, db, n, off);
16269ef1f84bSDavid du Colombier case Qconfig:
16279ef1f84bSDavid du Colombier if(off + n > sizeof d->config)
16289ef1f84bSDavid du Colombier error(Etoobig);
16299ef1f84bSDavid du Colombier buf = malloc(sizeof d->config);
16309ef1f84bSDavid du Colombier if(buf == nil)
16319ef1f84bSDavid du Colombier error(Enomem);
16329ef1f84bSDavid du Colombier if(waserror()){
16339ef1f84bSDavid du Colombier free(buf);
16349ef1f84bSDavid du Colombier nexterror();
16359ef1f84bSDavid du Colombier }
16369ef1f84bSDavid du Colombier memmove(buf, d->config, d->nconfig);
16379ef1f84bSDavid du Colombier memmove(buf + off, db, n);
16389ef1f84bSDavid du Colombier rv = configwrite(d, buf, n + off);
16399ef1f84bSDavid du Colombier poperror();
16409ef1f84bSDavid du Colombier free(buf);
16419ef1f84bSDavid du Colombier return rv;
16429ef1f84bSDavid du Colombier }
16439ef1f84bSDavid du Colombier }
16449ef1f84bSDavid du Colombier
16459ef1f84bSDavid du Colombier static Netlink*
addnet(char * path,Chan * cc,Chan * dc,Chan * mtu,uchar * ea)16469ef1f84bSDavid du Colombier addnet(char *path, Chan *cc, Chan *dc, Chan *mtu, uchar *ea)
16479ef1f84bSDavid du Colombier {
16489ef1f84bSDavid du Colombier Netlink *nl, *e;
16499ef1f84bSDavid du Colombier
16509ef1f84bSDavid du Colombier lock(&netlinks);
16519ef1f84bSDavid du Colombier if(waserror()){
16529ef1f84bSDavid du Colombier unlock(&netlinks);
16539ef1f84bSDavid du Colombier nexterror();
16549ef1f84bSDavid du Colombier }
16559ef1f84bSDavid du Colombier nl = netlinks.nl;
16569ef1f84bSDavid du Colombier e = nl + nelem(netlinks.nl);
16579ef1f84bSDavid du Colombier for(; nl < e && nl->cc; nl++)
16589ef1f84bSDavid du Colombier continue;
16599ef1f84bSDavid du Colombier if (nl >= e)
16609ef1f84bSDavid du Colombier error("out of netlink structures");
16619ef1f84bSDavid du Colombier nl->cc = cc;
16629ef1f84bSDavid du Colombier nl->dc = dc;
16639ef1f84bSDavid du Colombier nl->mtu = mtu;
16649ef1f84bSDavid du Colombier strncpy(nl->path, path, sizeof nl->path);
16659ef1f84bSDavid du Colombier memmove(nl->ea, ea, sizeof nl->ea);
16669ef1f84bSDavid du Colombier poperror();
16679ef1f84bSDavid du Colombier nl->flag |= Dup;
16689ef1f84bSDavid du Colombier unlock(&netlinks);
16699ef1f84bSDavid du Colombier return nl;
16709ef1f84bSDavid du Colombier }
16719ef1f84bSDavid du Colombier
16729ef1f84bSDavid du Colombier static int
newunit(void)16739ef1f84bSDavid du Colombier newunit(void)
16749ef1f84bSDavid du Colombier {
16759ef1f84bSDavid du Colombier int x;
16769ef1f84bSDavid du Colombier
16779ef1f84bSDavid du Colombier lock(&units);
16789ef1f84bSDavid du Colombier if(units.ref == Maxunits)
16799ef1f84bSDavid du Colombier x = -1;
16809ef1f84bSDavid du Colombier else
16819ef1f84bSDavid du Colombier x = units.ref++;
16829ef1f84bSDavid du Colombier unlock(&units);
16839ef1f84bSDavid du Colombier return x;
16849ef1f84bSDavid du Colombier }
16859ef1f84bSDavid du Colombier
16869ef1f84bSDavid du Colombier static int
dropunit(void)16879ef1f84bSDavid du Colombier dropunit(void)
16889ef1f84bSDavid du Colombier {
16899ef1f84bSDavid du Colombier int x;
16909ef1f84bSDavid du Colombier
16919ef1f84bSDavid du Colombier lock(&units);
16929ef1f84bSDavid du Colombier x = --units.ref;
16939ef1f84bSDavid du Colombier unlock(&units);
16949ef1f84bSDavid du Colombier return x;
16959ef1f84bSDavid du Colombier }
16969ef1f84bSDavid du Colombier
16979ef1f84bSDavid du Colombier /*
16989ef1f84bSDavid du Colombier * always allocate max frames. maxout may change.
16999ef1f84bSDavid du Colombier */
17009ef1f84bSDavid du Colombier static Aoedev*
newdev(long major,long minor,int n)17019ef1f84bSDavid du Colombier newdev(long major, long minor, int n)
17029ef1f84bSDavid du Colombier {
17039ef1f84bSDavid du Colombier Aoedev *d;
17049ef1f84bSDavid du Colombier Frame *f, *e;
17059ef1f84bSDavid du Colombier
17069ef1f84bSDavid du Colombier d = mallocz(sizeof *d, 1);
17079ef1f84bSDavid du Colombier f = mallocz(sizeof *f * Maxframes, 1);
17089ef1f84bSDavid du Colombier if (!d || !f) {
17099ef1f84bSDavid du Colombier free(d);
17109ef1f84bSDavid du Colombier free(f);
17119ef1f84bSDavid du Colombier error("aoe device allocation failure");
17129ef1f84bSDavid du Colombier }
17139ef1f84bSDavid du Colombier d->nframes = n;
17149ef1f84bSDavid du Colombier d->frames = f;
17159ef1f84bSDavid du Colombier for (e = f + n; f < e; f++)
17169ef1f84bSDavid du Colombier f->tag = Tfree;
17179ef1f84bSDavid du Colombier d->maxout = n;
17189ef1f84bSDavid du Colombier d->major = major;
17199ef1f84bSDavid du Colombier d->minor = minor;
17209ef1f84bSDavid du Colombier d->maxbcnt = Dbcnt;
17219ef1f84bSDavid du Colombier d->flag = Djumbo;
17229ef1f84bSDavid du Colombier d->unit = newunit(); /* bzzt. inaccurate if units removed */
17239ef1f84bSDavid du Colombier if(d->unit == -1){
17249ef1f84bSDavid du Colombier free(d->frames);
1725406c76faSDavid du Colombier free(d);
17269ef1f84bSDavid du Colombier error("too many units");
17279ef1f84bSDavid du Colombier }
17289ef1f84bSDavid du Colombier d->dl = d->dltab;
17299ef1f84bSDavid du Colombier return d;
17309ef1f84bSDavid du Colombier }
17319ef1f84bSDavid du Colombier
17329ef1f84bSDavid du Colombier static Aoedev*
mm2dev(int major,int minor)17339ef1f84bSDavid du Colombier mm2dev(int major, int minor)
17349ef1f84bSDavid du Colombier {
17359ef1f84bSDavid du Colombier Aoedev *d;
17369ef1f84bSDavid du Colombier
17379ef1f84bSDavid du Colombier rlock(&devs);
17389ef1f84bSDavid du Colombier for(d = devs.d; d; d = d->next)
17399ef1f84bSDavid du Colombier if(d->major == major && d->minor == minor){
17409ef1f84bSDavid du Colombier runlock(&devs);
17419ef1f84bSDavid du Colombier return d;
17429ef1f84bSDavid du Colombier }
17439ef1f84bSDavid du Colombier runlock(&devs);
17449ef1f84bSDavid du Colombier eventlog("mm2dev: %d.%d not found\n", major, minor);
17459ef1f84bSDavid du Colombier return nil;
17469ef1f84bSDavid du Colombier }
17479ef1f84bSDavid du Colombier
17489ef1f84bSDavid du Colombier /* Find the device in our list. If not known, add it */
17499ef1f84bSDavid du Colombier static Aoedev*
getdev(long major,long minor,int n)17509ef1f84bSDavid du Colombier getdev(long major, long minor, int n)
17519ef1f84bSDavid du Colombier {
17529ef1f84bSDavid du Colombier Aoedev *d;
17539ef1f84bSDavid du Colombier
17549ef1f84bSDavid du Colombier if(major == 0xffff || minor == 0xff)
17559ef1f84bSDavid du Colombier return 0;
17569ef1f84bSDavid du Colombier wlock(&devs);
17579ef1f84bSDavid du Colombier if(waserror()){
17589ef1f84bSDavid du Colombier wunlock(&devs);
17599ef1f84bSDavid du Colombier nexterror();
17609ef1f84bSDavid du Colombier }
17619ef1f84bSDavid du Colombier for(d = devs.d; d; d = d->next)
17629ef1f84bSDavid du Colombier if(d->major == major && d->minor == minor)
17639ef1f84bSDavid du Colombier break;
17649ef1f84bSDavid du Colombier if (d == nil) {
17659ef1f84bSDavid du Colombier d = newdev(major, minor, n);
17669ef1f84bSDavid du Colombier d->next = devs.d;
17679ef1f84bSDavid du Colombier devs.d = d;
17689ef1f84bSDavid du Colombier }
17699ef1f84bSDavid du Colombier poperror();
17709ef1f84bSDavid du Colombier wunlock(&devs);
17719ef1f84bSDavid du Colombier return d;
17729ef1f84bSDavid du Colombier }
17739ef1f84bSDavid du Colombier
17749ef1f84bSDavid du Colombier static ushort
gbit16(void * a)17759ef1f84bSDavid du Colombier gbit16(void *a)
17769ef1f84bSDavid du Colombier {
17779ef1f84bSDavid du Colombier uchar *i;
17789ef1f84bSDavid du Colombier
17799ef1f84bSDavid du Colombier i = a;
17809ef1f84bSDavid du Colombier return i[1] << 8 | i[0];
17819ef1f84bSDavid du Colombier }
17829ef1f84bSDavid du Colombier
17839ef1f84bSDavid du Colombier static ulong
gbit32(void * a)17849ef1f84bSDavid du Colombier gbit32(void *a)
17859ef1f84bSDavid du Colombier {
17869ef1f84bSDavid du Colombier ulong j;
17879ef1f84bSDavid du Colombier uchar *i;
17889ef1f84bSDavid du Colombier
17899ef1f84bSDavid du Colombier i = a;
17909ef1f84bSDavid du Colombier j = i[3] << 24;
17919ef1f84bSDavid du Colombier j |= i[2] << 16;
17929ef1f84bSDavid du Colombier j |= i[1] << 8;
17939ef1f84bSDavid du Colombier j |= i[0];
17949ef1f84bSDavid du Colombier return j;
17959ef1f84bSDavid du Colombier }
17969ef1f84bSDavid du Colombier
17979ef1f84bSDavid du Colombier static uvlong
gbit64(void * a)17989ef1f84bSDavid du Colombier gbit64(void *a)
17999ef1f84bSDavid du Colombier {
18009ef1f84bSDavid du Colombier uchar *i;
18019ef1f84bSDavid du Colombier
18029ef1f84bSDavid du Colombier i = a;
18039ef1f84bSDavid du Colombier return (uvlong)gbit32(i+4) << 32 | gbit32(a);
18049ef1f84bSDavid du Colombier }
18059ef1f84bSDavid du Colombier
18069ef1f84bSDavid du Colombier static void
ataident(Aoedev * d)18079ef1f84bSDavid du Colombier ataident(Aoedev *d)
18089ef1f84bSDavid du Colombier {
18099ef1f84bSDavid du Colombier Aoeata *a;
18109ef1f84bSDavid du Colombier Block *b;
18119ef1f84bSDavid du Colombier Frame *f;
18129ef1f84bSDavid du Colombier
18139ef1f84bSDavid du Colombier f = freeframe(d);
18149ef1f84bSDavid du Colombier if(f == nil)
18159ef1f84bSDavid du Colombier return;
18169ef1f84bSDavid du Colombier f->nhdr = AOEATASZ;
18179ef1f84bSDavid du Colombier memset(f->hdr, 0, f->nhdr);
18189ef1f84bSDavid du Colombier a = (Aoeata*)f->hdr;
18199ef1f84bSDavid du Colombier if(hset(d, f, a, ACata) == -1)
18209ef1f84bSDavid du Colombier return;
18219ef1f84bSDavid du Colombier a->cmdstat = Cid; /* ata 6, page 110 */
18229ef1f84bSDavid du Colombier a->scnt = 1;
18239ef1f84bSDavid du Colombier a->lba[3] = 0xa0;
18249ef1f84bSDavid du Colombier d->nout++;
18259ef1f84bSDavid du Colombier f->dl->npkt++;
18269ef1f84bSDavid du Colombier f->bcnt = 512;
18279ef1f84bSDavid du Colombier f->dlen = 0;
18289ef1f84bSDavid du Colombier b = allocfb(f);
18299ef1f84bSDavid du Colombier f->nl->dc->dev->bwrite(f->nl->dc, b, 0);
18309ef1f84bSDavid du Colombier }
18319ef1f84bSDavid du Colombier
18329ef1f84bSDavid du Colombier static int
getmtu(Chan * mtuch)18339ef1f84bSDavid du Colombier getmtu(Chan *mtuch)
18349ef1f84bSDavid du Colombier {
18359ef1f84bSDavid du Colombier int n, mtu;
18369ef1f84bSDavid du Colombier char buf[36];
18379ef1f84bSDavid du Colombier
18389ef1f84bSDavid du Colombier mtu = ETHERMAXTU;
18399ef1f84bSDavid du Colombier if(mtuch == nil || waserror())
18409ef1f84bSDavid du Colombier return mtu;
18419ef1f84bSDavid du Colombier n = mtuch->dev->read(mtuch, buf, sizeof buf - 1, 0);
18429ef1f84bSDavid du Colombier if(n > 12){
18439ef1f84bSDavid du Colombier buf[n] = 0;
18449ef1f84bSDavid du Colombier mtu = strtoul(buf + 12, 0, 0);
18459ef1f84bSDavid du Colombier }
18469ef1f84bSDavid du Colombier poperror();
18479ef1f84bSDavid du Colombier return mtu;
18489ef1f84bSDavid du Colombier }
18499ef1f84bSDavid du Colombier
18509ef1f84bSDavid du Colombier static int
newdlea(Devlink * l,uchar * ea)18519ef1f84bSDavid du Colombier newdlea(Devlink *l, uchar *ea)
18529ef1f84bSDavid du Colombier {
18539ef1f84bSDavid du Colombier int i;
18549ef1f84bSDavid du Colombier uchar *t;
18559ef1f84bSDavid du Colombier
18569ef1f84bSDavid du Colombier for(i = 0; i < Nea; i++){
18579ef1f84bSDavid du Colombier t = l->eatab[i];
18589ef1f84bSDavid du Colombier if(i == l->nea){
18599ef1f84bSDavid du Colombier memmove(t, ea, Eaddrlen);
18609ef1f84bSDavid du Colombier return l->nea++;
18619ef1f84bSDavid du Colombier }
18629ef1f84bSDavid du Colombier if(memcmp(t, ea, Eaddrlen) == 0)
18639ef1f84bSDavid du Colombier return i;
18649ef1f84bSDavid du Colombier }
18659ef1f84bSDavid du Colombier return -1;
18669ef1f84bSDavid du Colombier }
18679ef1f84bSDavid du Colombier
18689ef1f84bSDavid du Colombier static Devlink*
newdevlink(Aoedev * d,Netlink * n,Aoeqc * c)18699ef1f84bSDavid du Colombier newdevlink(Aoedev *d, Netlink *n, Aoeqc *c)
18709ef1f84bSDavid du Colombier {
18719ef1f84bSDavid du Colombier int i;
18729ef1f84bSDavid du Colombier Devlink *l;
18739ef1f84bSDavid du Colombier
18749ef1f84bSDavid du Colombier for(i = 0; i < Ndevlink; i++){
18759ef1f84bSDavid du Colombier l = d->dl + i;
18769ef1f84bSDavid du Colombier if(i == d->ndl){
18779ef1f84bSDavid du Colombier d->ndl++;
18789ef1f84bSDavid du Colombier newdlea(l, c->src);
18799ef1f84bSDavid du Colombier l->nl = n;
18809ef1f84bSDavid du Colombier l->flag |= Dup;
18819ef1f84bSDavid du Colombier l->mintimer = Rtmin;
18829ef1f84bSDavid du Colombier l->rttavg = Rtmax;
18839ef1f84bSDavid du Colombier return l;
18849ef1f84bSDavid du Colombier }
18859ef1f84bSDavid du Colombier if(l->nl == n) {
18869ef1f84bSDavid du Colombier newdlea(l, c->src);
18879ef1f84bSDavid du Colombier l->flag |= Dup;
18889ef1f84bSDavid du Colombier return l;
18899ef1f84bSDavid du Colombier }
18909ef1f84bSDavid du Colombier }
18919ef1f84bSDavid du Colombier eventlog("%æ: out of links: %s:%E to %E\n", d, n->path, n->ea, c->src);
18929ef1f84bSDavid du Colombier return 0;
18939ef1f84bSDavid du Colombier }
18949ef1f84bSDavid du Colombier
18959ef1f84bSDavid du Colombier static void
errrsp(Block * b,char * s)18969ef1f84bSDavid du Colombier errrsp(Block *b, char *s)
18979ef1f84bSDavid du Colombier {
18989ef1f84bSDavid du Colombier int n;
18999ef1f84bSDavid du Colombier Aoedev *d;
19009ef1f84bSDavid du Colombier Aoehdr *h;
19019ef1f84bSDavid du Colombier Frame *f;
19029ef1f84bSDavid du Colombier
19039ef1f84bSDavid du Colombier h = (Aoehdr*)b->rp;
19049ef1f84bSDavid du Colombier n = nhgetl(h->tag);
19059ef1f84bSDavid du Colombier if(n == Tmgmt || n == Tfree)
19069ef1f84bSDavid du Colombier return;
19079ef1f84bSDavid du Colombier d = mm2dev(nhgets(h->major), h->minor);
19089ef1f84bSDavid du Colombier if(d == 0)
19099ef1f84bSDavid du Colombier return;
19109ef1f84bSDavid du Colombier if(f = getframe(d, n))
19119ef1f84bSDavid du Colombier frameerror(d, f, s);
19129ef1f84bSDavid du Colombier }
19139ef1f84bSDavid du Colombier
19149ef1f84bSDavid du Colombier static void
qcfgrsp(Block * b,Netlink * nl)19159ef1f84bSDavid du Colombier qcfgrsp(Block *b, Netlink *nl)
19169ef1f84bSDavid du Colombier {
19179ef1f84bSDavid du Colombier int major, cmd, cslen, blen;
19189ef1f84bSDavid du Colombier unsigned n;
19199ef1f84bSDavid du Colombier Aoedev *d;
19209ef1f84bSDavid du Colombier Aoeqc *ch;
19219ef1f84bSDavid du Colombier Devlink *l;
19229ef1f84bSDavid du Colombier Frame *f;
19239ef1f84bSDavid du Colombier
19249ef1f84bSDavid du Colombier ch = (Aoeqc*)b->rp;
19259ef1f84bSDavid du Colombier major = nhgets(ch->major);
19269ef1f84bSDavid du Colombier n = nhgetl(ch->tag);
19279ef1f84bSDavid du Colombier if(n != Tmgmt){
19289ef1f84bSDavid du Colombier d = mm2dev(major, ch->minor);
19299ef1f84bSDavid du Colombier if(d == nil)
19309ef1f84bSDavid du Colombier return;
19319ef1f84bSDavid du Colombier qlock(d);
19329ef1f84bSDavid du Colombier f = getframe(d, n);
19339ef1f84bSDavid du Colombier if(f == nil){
19349ef1f84bSDavid du Colombier qunlock(d);
19359ef1f84bSDavid du Colombier eventlog("%æ: unknown response tag %#ux\n", d, n);
19369ef1f84bSDavid du Colombier return;
19379ef1f84bSDavid du Colombier }
19389ef1f84bSDavid du Colombier cslen = nhgets(ch->cslen);
19399ef1f84bSDavid du Colombier blen = BLEN(b) - AOEQCSZ;
19409ef1f84bSDavid du Colombier if(cslen < blen && BLEN(b) > 60)
19419ef1f84bSDavid du Colombier eventlog("%æ: cfgrsp: tag %.8ux oversized %d %d\n",
19429ef1f84bSDavid du Colombier d, n, cslen, blen);
19439ef1f84bSDavid du Colombier if(cslen > blen){
19449ef1f84bSDavid du Colombier eventlog("%æ: cfgrsp: tag %.8ux runt %d %d\n",
19459ef1f84bSDavid du Colombier d, n, cslen, blen);
19469ef1f84bSDavid du Colombier cslen = blen;
19479ef1f84bSDavid du Colombier }
19489ef1f84bSDavid du Colombier memmove(f->dp, ch + 1, cslen);
19499ef1f84bSDavid du Colombier f->srb->nout--;
19509ef1f84bSDavid du Colombier wakeup(f->srb);
1951406c76faSDavid du Colombier f->srb->shared = 0;
19529ef1f84bSDavid du Colombier d->nout--;
19539ef1f84bSDavid du Colombier f->srb = nil;
19549ef1f84bSDavid du Colombier f->tag = Tfree;
19559ef1f84bSDavid du Colombier qunlock(d);
19569ef1f84bSDavid du Colombier return;
19579ef1f84bSDavid du Colombier }
19589ef1f84bSDavid du Colombier
19599ef1f84bSDavid du Colombier cmd = ch->verccmd & 0xf;
19609ef1f84bSDavid du Colombier if(cmd != 0){
19619ef1f84bSDavid du Colombier eventlog("aoe%d.%d: cfgrsp: bad command %d\n", major, ch->minor, cmd);
19629ef1f84bSDavid du Colombier return;
19639ef1f84bSDavid du Colombier }
19649ef1f84bSDavid du Colombier n = nhgets(ch->bufcnt);
19659ef1f84bSDavid du Colombier if(n > Maxframes)
19669ef1f84bSDavid du Colombier n = Maxframes;
19679ef1f84bSDavid du Colombier
19689ef1f84bSDavid du Colombier if(waserror()){
19699ef1f84bSDavid du Colombier eventlog("getdev: %d.%d ignored: %s\n", major, ch->minor, up->errstr);
19709ef1f84bSDavid du Colombier return;
19719ef1f84bSDavid du Colombier }
19729ef1f84bSDavid du Colombier d = getdev(major, ch->minor, n);
19739ef1f84bSDavid du Colombier poperror();
19749ef1f84bSDavid du Colombier if(d == 0)
19759ef1f84bSDavid du Colombier return;
19769ef1f84bSDavid du Colombier
19779ef1f84bSDavid du Colombier qlock(d);
19789ef1f84bSDavid du Colombier *up->errstr = 0;
19799ef1f84bSDavid du Colombier if(waserror()){
19809ef1f84bSDavid du Colombier qunlock(d);
19819ef1f84bSDavid du Colombier eventlog("%æ: %s\n", d, up->errstr);
19829ef1f84bSDavid du Colombier nexterror();
19839ef1f84bSDavid du Colombier }
19849ef1f84bSDavid du Colombier
19859ef1f84bSDavid du Colombier l = newdevlink(d, nl, ch); /* add this interface. */
19869ef1f84bSDavid du Colombier
19879ef1f84bSDavid du Colombier d->fwver = nhgets(ch->fwver);
19889ef1f84bSDavid du Colombier n = nhgets(ch->cslen);
19899ef1f84bSDavid du Colombier if(n > sizeof d->config)
19909ef1f84bSDavid du Colombier n = sizeof d->config;
19919ef1f84bSDavid du Colombier d->nconfig = n;
19929ef1f84bSDavid du Colombier memmove(d->config, ch + 1, n);
19939ef1f84bSDavid du Colombier if(l != 0 && d->flag & Djumbo){
19949ef1f84bSDavid du Colombier n = getmtu(nl->mtu) - AOEATASZ;
19959ef1f84bSDavid du Colombier n /= Aoesectsz;
19969ef1f84bSDavid du Colombier if(n > ch->scnt)
19979ef1f84bSDavid du Colombier n = ch->scnt;
19989ef1f84bSDavid du Colombier n = n? n * Aoesectsz: Dbcnt;
19999ef1f84bSDavid du Colombier if(n != d->maxbcnt){
20009ef1f84bSDavid du Colombier eventlog("%æ: setting %d byte data frames on %s:%E\n",
20019ef1f84bSDavid du Colombier d, n, nl->path, nl->ea);
20029ef1f84bSDavid du Colombier d->maxbcnt = n;
20039ef1f84bSDavid du Colombier }
20049ef1f84bSDavid du Colombier }
20059ef1f84bSDavid du Colombier if(d->nopen == 0)
20069ef1f84bSDavid du Colombier ataident(d);
20079ef1f84bSDavid du Colombier poperror();
20089ef1f84bSDavid du Colombier qunlock(d);
20099ef1f84bSDavid du Colombier }
20109ef1f84bSDavid du Colombier
20119ef1f84bSDavid du Colombier void
aoeidmove(char * p,ushort * u,unsigned n)20129ef1f84bSDavid du Colombier aoeidmove(char *p, ushort *u, unsigned n)
20139ef1f84bSDavid du Colombier {
20149ef1f84bSDavid du Colombier int i;
20159ef1f84bSDavid du Colombier char *op, *e, *s;
20169ef1f84bSDavid du Colombier
20179ef1f84bSDavid du Colombier op = p;
20189ef1f84bSDavid du Colombier /*
20199ef1f84bSDavid du Colombier * the ushort `*u' is sometimes not aligned on a short boundary,
20209ef1f84bSDavid du Colombier * so dereferencing u[i] causes an alignment exception on
20219ef1f84bSDavid du Colombier * some machines.
20229ef1f84bSDavid du Colombier */
20239ef1f84bSDavid du Colombier s = (char *)u;
20249ef1f84bSDavid du Colombier for(i = 0; i < n; i += 2){
20259ef1f84bSDavid du Colombier *p++ = s[i + 1];
20269ef1f84bSDavid du Colombier *p++ = s[i];
20279ef1f84bSDavid du Colombier }
20289ef1f84bSDavid du Colombier *p = 0;
20299ef1f84bSDavid du Colombier while(p > op && *--p == ' ')
20309ef1f84bSDavid du Colombier *p = 0;
20319ef1f84bSDavid du Colombier e = p;
20329ef1f84bSDavid du Colombier p = op;
20339ef1f84bSDavid du Colombier while(*p == ' ')
20349ef1f84bSDavid du Colombier p++;
20359ef1f84bSDavid du Colombier memmove(op, p, n - (e - p));
20369ef1f84bSDavid du Colombier }
20379ef1f84bSDavid du Colombier
20389ef1f84bSDavid du Colombier static vlong
aoeidentify(Aoedev * d,ushort * id)20399ef1f84bSDavid du Colombier aoeidentify(Aoedev *d, ushort *id)
20409ef1f84bSDavid du Colombier {
20419ef1f84bSDavid du Colombier int i;
20429ef1f84bSDavid du Colombier vlong s;
20439ef1f84bSDavid du Colombier
20449ef1f84bSDavid du Colombier d->flag &= ~(Dllba|Dpower|Dsmart|Dnop|Dup);
20459ef1f84bSDavid du Colombier
20469ef1f84bSDavid du Colombier i = gbit16(id+83) | gbit16(id+86);
20479ef1f84bSDavid du Colombier if(i & (1<<10)){
20489ef1f84bSDavid du Colombier d->flag |= Dllba;
20499ef1f84bSDavid du Colombier s = gbit64(id+100);
20509ef1f84bSDavid du Colombier }else
20519ef1f84bSDavid du Colombier s = gbit32(id+60);
20529ef1f84bSDavid du Colombier
20539ef1f84bSDavid du Colombier i = gbit16(id+83);
20549ef1f84bSDavid du Colombier if((i>>14) == 1) {
20559ef1f84bSDavid du Colombier if(i & (1<<3))
20569ef1f84bSDavid du Colombier d->flag |= Dpower;
20579ef1f84bSDavid du Colombier i = gbit16(id+82);
20589ef1f84bSDavid du Colombier if(i & 1)
20599ef1f84bSDavid du Colombier d->flag |= Dsmart;
20609ef1f84bSDavid du Colombier if(i & (1<<14))
20619ef1f84bSDavid du Colombier d->flag |= Dnop;
20629ef1f84bSDavid du Colombier }
20639ef1f84bSDavid du Colombier // eventlog("%æ up\n", d);
20649ef1f84bSDavid du Colombier d->flag |= Dup;
20659ef1f84bSDavid du Colombier memmove(d->ident, id, sizeof d->ident);
20669ef1f84bSDavid du Colombier return s;
20679ef1f84bSDavid du Colombier }
20689ef1f84bSDavid du Colombier
20699ef1f84bSDavid du Colombier static void
newvers(Aoedev * d)20709ef1f84bSDavid du Colombier newvers(Aoedev *d)
20719ef1f84bSDavid du Colombier {
20729ef1f84bSDavid du Colombier lock(&drivevers);
20739ef1f84bSDavid du Colombier d->vers = drivevers.ref++;
20749ef1f84bSDavid du Colombier unlock(&drivevers);
20759ef1f84bSDavid du Colombier }
20769ef1f84bSDavid du Colombier
20779ef1f84bSDavid du Colombier static int
identify(Aoedev * d,ushort * id)20789ef1f84bSDavid du Colombier identify(Aoedev *d, ushort *id)
20799ef1f84bSDavid du Colombier {
20809ef1f84bSDavid du Colombier vlong osectors, s;
20819ef1f84bSDavid du Colombier uchar oserial[21];
20829ef1f84bSDavid du Colombier
20839ef1f84bSDavid du Colombier s = aoeidentify(d, id);
20849ef1f84bSDavid du Colombier if(s == -1)
20859ef1f84bSDavid du Colombier return -1;
20869ef1f84bSDavid du Colombier osectors = d->realbsize;
20879ef1f84bSDavid du Colombier memmove(oserial, d->serial, sizeof d->serial);
20889ef1f84bSDavid du Colombier
20899ef1f84bSDavid du Colombier aoeidmove(d->serial, id+10, 20);
20909ef1f84bSDavid du Colombier aoeidmove(d->firmware, id+23, 8);
20919ef1f84bSDavid du Colombier aoeidmove(d->model, id+27, 40);
20929ef1f84bSDavid du Colombier
20939ef1f84bSDavid du Colombier s *= Aoesectsz;
20949ef1f84bSDavid du Colombier if((osectors == 0 || osectors != s) &&
20959ef1f84bSDavid du Colombier memcmp(oserial, d->serial, sizeof oserial) != 0){
20969ef1f84bSDavid du Colombier d->bsize = s;
20979ef1f84bSDavid du Colombier d->realbsize = s;
20989ef1f84bSDavid du Colombier // d->mediachange = 1;
20999ef1f84bSDavid du Colombier newvers(d);
21009ef1f84bSDavid du Colombier }
21019ef1f84bSDavid du Colombier return 0;
21029ef1f84bSDavid du Colombier }
21039ef1f84bSDavid du Colombier
21049ef1f84bSDavid du Colombier static void
atarsp(Block * b)21059ef1f84bSDavid du Colombier atarsp(Block *b)
21069ef1f84bSDavid du Colombier {
21079ef1f84bSDavid du Colombier unsigned n;
21089ef1f84bSDavid du Colombier short major;
21099ef1f84bSDavid du Colombier Aoeata *ahin, *ahout;
21109ef1f84bSDavid du Colombier Aoedev *d;
21119ef1f84bSDavid du Colombier Frame *f;
21129ef1f84bSDavid du Colombier Srb *srb;
21139ef1f84bSDavid du Colombier
21149ef1f84bSDavid du Colombier ahin = (Aoeata*)b->rp;
21159ef1f84bSDavid du Colombier major = nhgets(ahin->major);
21169ef1f84bSDavid du Colombier d = mm2dev(major, ahin->minor);
21179ef1f84bSDavid du Colombier if(d == nil)
21189ef1f84bSDavid du Colombier return;
21199ef1f84bSDavid du Colombier qlock(d);
21209ef1f84bSDavid du Colombier if(waserror()){
21219ef1f84bSDavid du Colombier qunlock(d);
21229ef1f84bSDavid du Colombier nexterror();
21239ef1f84bSDavid du Colombier }
21249ef1f84bSDavid du Colombier n = nhgetl(ahin->tag);
21259ef1f84bSDavid du Colombier f = getframe(d, n);
21269ef1f84bSDavid du Colombier if(f == nil){
21279ef1f84bSDavid du Colombier dprint("%æ: unexpected response; tag %#ux\n", d, n);
21289ef1f84bSDavid du Colombier goto bail;
21299ef1f84bSDavid du Colombier }
21309ef1f84bSDavid du Colombier rtupdate(f->dl, tsince(f->tag));
21319ef1f84bSDavid du Colombier ahout = (Aoeata*)f->hdr;
21329ef1f84bSDavid du Colombier srb = f->srb;
21339ef1f84bSDavid du Colombier
21349ef1f84bSDavid du Colombier if(ahin->cmdstat & 0xa9){
21359ef1f84bSDavid du Colombier eventlog("%æ: ata error cmd %.2ux stat %.2ux\n",
21369ef1f84bSDavid du Colombier d, ahout->cmdstat, ahin->cmdstat);
21379ef1f84bSDavid du Colombier if(srb)
21389ef1f84bSDavid du Colombier srb->error = Eio;
21399ef1f84bSDavid du Colombier } else {
21409ef1f84bSDavid du Colombier n = ahout->scnt * Aoesectsz;
21419ef1f84bSDavid du Colombier switch(ahout->cmdstat){
21429ef1f84bSDavid du Colombier case Crd:
21439ef1f84bSDavid du Colombier case Crdext:
21449ef1f84bSDavid du Colombier if(BLEN(b) - AOEATASZ < n){
21459ef1f84bSDavid du Colombier eventlog("%æ: runt read blen %ld expect %d\n",
21469ef1f84bSDavid du Colombier d, BLEN(b), n);
21479ef1f84bSDavid du Colombier goto bail;
21489ef1f84bSDavid du Colombier }
21499ef1f84bSDavid du Colombier memmove(f->dp, (uchar *)ahin + AOEATASZ, n);
21509ef1f84bSDavid du Colombier case Cwr:
21519ef1f84bSDavid du Colombier case Cwrext:
21529ef1f84bSDavid du Colombier if(n > Dbcnt)
21539ef1f84bSDavid du Colombier f->nl->lostjumbo = 0;
21549ef1f84bSDavid du Colombier if(f->bcnt -= n){
21559ef1f84bSDavid du Colombier f->lba += n / Aoesectsz;
21569ef1f84bSDavid du Colombier f->dp = (uchar*)f->dp + n;
21579ef1f84bSDavid du Colombier resend(d, f);
21589ef1f84bSDavid du Colombier goto bail;
21599ef1f84bSDavid du Colombier }
21609ef1f84bSDavid du Colombier break;
21619ef1f84bSDavid du Colombier case Cid:
21629ef1f84bSDavid du Colombier if(BLEN(b) - AOEATASZ < 512){
21639ef1f84bSDavid du Colombier eventlog("%æ: runt identify blen %ld expect %d\n",
21649ef1f84bSDavid du Colombier d, BLEN(b), n);
21659ef1f84bSDavid du Colombier goto bail;
21669ef1f84bSDavid du Colombier }
21679ef1f84bSDavid du Colombier identify(d, (ushort*)((uchar *)ahin + AOEATASZ));
21689ef1f84bSDavid du Colombier break;
21699ef1f84bSDavid du Colombier default:
21709ef1f84bSDavid du Colombier eventlog("%æ: unknown ata command %.2ux \n",
21719ef1f84bSDavid du Colombier d, ahout->cmdstat);
21729ef1f84bSDavid du Colombier }
21739ef1f84bSDavid du Colombier }
21749ef1f84bSDavid du Colombier
2175406c76faSDavid du Colombier if(srb && --srb->nout == 0 && srb->len == 0){
21769ef1f84bSDavid du Colombier wakeup(srb);
2177406c76faSDavid du Colombier srb->shared = 0;
2178406c76faSDavid du Colombier }
21799ef1f84bSDavid du Colombier f->srb = nil;
21809ef1f84bSDavid du Colombier f->tag = Tfree;
21819ef1f84bSDavid du Colombier d->nout--;
21829ef1f84bSDavid du Colombier
21839ef1f84bSDavid du Colombier work(d);
21849ef1f84bSDavid du Colombier bail:
21859ef1f84bSDavid du Colombier poperror();
21869ef1f84bSDavid du Colombier qunlock(d);
21879ef1f84bSDavid du Colombier }
21889ef1f84bSDavid du Colombier
21899ef1f84bSDavid du Colombier static void
netrdaoeproc(void * v)21909ef1f84bSDavid du Colombier netrdaoeproc(void *v)
21919ef1f84bSDavid du Colombier {
21929ef1f84bSDavid du Colombier int idx;
21939ef1f84bSDavid du Colombier char name[Maxpath+1], *s;
21949ef1f84bSDavid du Colombier Aoehdr *h;
21959ef1f84bSDavid du Colombier Block *b;
21969ef1f84bSDavid du Colombier Netlink *nl;
21979ef1f84bSDavid du Colombier
21989ef1f84bSDavid du Colombier nl = (Netlink*)v;
21999ef1f84bSDavid du Colombier idx = nl - netlinks.nl;
22009ef1f84bSDavid du Colombier netlinks.reader[idx] = 1;
22019ef1f84bSDavid du Colombier kstrcpy(name, nl->path, Maxpath);
22029ef1f84bSDavid du Colombier
22039ef1f84bSDavid du Colombier if(waserror()){
22049ef1f84bSDavid du Colombier eventlog("netrdaoe exiting: %s\n", up->errstr);
22059ef1f84bSDavid du Colombier netlinks.reader[idx] = 0;
22069ef1f84bSDavid du Colombier wakeup(netlinks.rendez + idx);
22079ef1f84bSDavid du Colombier pexit(up->errstr, 1);
22089ef1f84bSDavid du Colombier }
22099ef1f84bSDavid du Colombier if(autodiscover)
22109ef1f84bSDavid du Colombier discover(0xffff, 0xff);
22119ef1f84bSDavid du Colombier for (;;) {
22129ef1f84bSDavid du Colombier if(!(nl->flag & Dup)) {
22139ef1f84bSDavid du Colombier uprint("%s: netlink is down", name);
22149ef1f84bSDavid du Colombier error(up->genbuf);
22159ef1f84bSDavid du Colombier }
22169ef1f84bSDavid du Colombier if (nl->dc == nil)
22179ef1f84bSDavid du Colombier panic("netrdaoe: nl->dc == nil");
22189ef1f84bSDavid du Colombier b = nl->dc->dev->bread(nl->dc, 1<<16, 0);
22199ef1f84bSDavid du Colombier if(b == nil) {
22209ef1f84bSDavid du Colombier uprint("%s: nil read from network", name);
22219ef1f84bSDavid du Colombier error(up->genbuf);
22229ef1f84bSDavid du Colombier }
22239ef1f84bSDavid du Colombier h = (Aoehdr*)b->rp;
22249ef1f84bSDavid du Colombier if(h->verflag & AFrsp)
22259ef1f84bSDavid du Colombier if(s = aoeerror(h)){
22269ef1f84bSDavid du Colombier eventlog("%s: %s\n", nl->path, up->errstr);
22279ef1f84bSDavid du Colombier errrsp(b, s);
22289ef1f84bSDavid du Colombier }else
22299ef1f84bSDavid du Colombier switch(h->cmd){
22309ef1f84bSDavid du Colombier case ACata:
22319ef1f84bSDavid du Colombier atarsp(b);
22329ef1f84bSDavid du Colombier break;
22339ef1f84bSDavid du Colombier case ACconfig:
22349ef1f84bSDavid du Colombier qcfgrsp(b, nl);
22359ef1f84bSDavid du Colombier break;
22369ef1f84bSDavid du Colombier default:
22379ef1f84bSDavid du Colombier if((h->cmd & 0xf0) == 0){
22389ef1f84bSDavid du Colombier eventlog("%s: unknown cmd %d\n",
22399ef1f84bSDavid du Colombier nl->path, h->cmd);
22409ef1f84bSDavid du Colombier errrsp(b, "unknown command");
22419ef1f84bSDavid du Colombier }
22429ef1f84bSDavid du Colombier break;
22439ef1f84bSDavid du Colombier }
22449ef1f84bSDavid du Colombier freeb(b);
22459ef1f84bSDavid du Colombier }
22469ef1f84bSDavid du Colombier }
22479ef1f84bSDavid du Colombier
22489ef1f84bSDavid du Colombier static void
getaddr(char * path,uchar * ea)22499ef1f84bSDavid du Colombier getaddr(char *path, uchar *ea)
22509ef1f84bSDavid du Colombier {
22519ef1f84bSDavid du Colombier int n;
22529ef1f84bSDavid du Colombier char buf[2*Eaddrlen+1];
22539ef1f84bSDavid du Colombier Chan *c;
22549ef1f84bSDavid du Colombier
22559ef1f84bSDavid du Colombier uprint("%s/addr", path);
22569ef1f84bSDavid du Colombier c = namec(up->genbuf, Aopen, OREAD, 0);
22579ef1f84bSDavid du Colombier if(waserror()) {
22589ef1f84bSDavid du Colombier cclose(c);
22599ef1f84bSDavid du Colombier nexterror();
22609ef1f84bSDavid du Colombier }
22619ef1f84bSDavid du Colombier if (c == nil)
22629ef1f84bSDavid du Colombier panic("æ: getaddr: c == nil");
22639ef1f84bSDavid du Colombier n = c->dev->read(c, buf, sizeof buf-1, 0);
22649ef1f84bSDavid du Colombier poperror();
22659ef1f84bSDavid du Colombier cclose(c);
22669ef1f84bSDavid du Colombier buf[n] = 0;
22679ef1f84bSDavid du Colombier if(parseether(ea, buf) < 0)
22689ef1f84bSDavid du Colombier error("parseether failure");
22699ef1f84bSDavid du Colombier }
22709ef1f84bSDavid du Colombier
22719ef1f84bSDavid du Colombier static void
netbind(char * path)22729ef1f84bSDavid du Colombier netbind(char *path)
22739ef1f84bSDavid du Colombier {
22749ef1f84bSDavid du Colombier char addr[Maxpath];
22759ef1f84bSDavid du Colombier uchar ea[2*Eaddrlen+1];
22769ef1f84bSDavid du Colombier Chan *dc, *cc, *mtu;
22779ef1f84bSDavid du Colombier Netlink *nl;
22789ef1f84bSDavid du Colombier
22799ef1f84bSDavid du Colombier snprint(addr, sizeof addr, "%s!%#x", path, Aoetype);
22809ef1f84bSDavid du Colombier dc = chandial(addr, nil, nil, &cc);
22819ef1f84bSDavid du Colombier snprint(addr, sizeof addr, "%s/mtu", path);
22829ef1f84bSDavid du Colombier if(waserror())
22839ef1f84bSDavid du Colombier mtu = nil;
22849ef1f84bSDavid du Colombier else {
22859ef1f84bSDavid du Colombier mtu = namec(addr, Aopen, OREAD, 0);
22869ef1f84bSDavid du Colombier poperror();
22879ef1f84bSDavid du Colombier }
22889ef1f84bSDavid du Colombier
22899ef1f84bSDavid du Colombier if(waserror()){
22909ef1f84bSDavid du Colombier cclose(dc);
22919ef1f84bSDavid du Colombier cclose(cc);
22929ef1f84bSDavid du Colombier if(mtu)
22939ef1f84bSDavid du Colombier cclose(mtu);
22949ef1f84bSDavid du Colombier nexterror();
22959ef1f84bSDavid du Colombier }
22969ef1f84bSDavid du Colombier if(dc == nil || cc == nil)
22979ef1f84bSDavid du Colombier error(Enonexist);
22989ef1f84bSDavid du Colombier getaddr(path, ea);
22999ef1f84bSDavid du Colombier nl = addnet(path, cc, dc, mtu, ea);
23009ef1f84bSDavid du Colombier snprint(addr, sizeof addr, "netrdaoe@%s", path);
23019ef1f84bSDavid du Colombier kproc(addr, netrdaoeproc, nl);
23029ef1f84bSDavid du Colombier poperror();
23039ef1f84bSDavid du Colombier }
23049ef1f84bSDavid du Colombier
23059ef1f84bSDavid du Colombier static int
unbound(void * v)23069ef1f84bSDavid du Colombier unbound(void *v)
23079ef1f84bSDavid du Colombier {
23089ef1f84bSDavid du Colombier return *(int*)v != 0;
23099ef1f84bSDavid du Colombier }
23109ef1f84bSDavid du Colombier
23119ef1f84bSDavid du Colombier static void
netunbind(char * path)23129ef1f84bSDavid du Colombier netunbind(char *path)
23139ef1f84bSDavid du Colombier {
23149ef1f84bSDavid du Colombier int i, idx;
23159ef1f84bSDavid du Colombier Aoedev *d, *p, *next;
23169ef1f84bSDavid du Colombier Chan *dc, *cc;
23179ef1f84bSDavid du Colombier Devlink *l;
23189ef1f84bSDavid du Colombier Frame *f;
23199ef1f84bSDavid du Colombier Netlink *n, *e;
23209ef1f84bSDavid du Colombier
23219ef1f84bSDavid du Colombier n = netlinks.nl;
23229ef1f84bSDavid du Colombier e = n + nelem(netlinks.nl);
23239ef1f84bSDavid du Colombier
23249ef1f84bSDavid du Colombier lock(&netlinks);
23259ef1f84bSDavid du Colombier for(; n < e; n++)
23269ef1f84bSDavid du Colombier if(n->dc && strcmp(n->path, path) == 0)
23279ef1f84bSDavid du Colombier break;
23289ef1f84bSDavid du Colombier unlock(&netlinks);
23299ef1f84bSDavid du Colombier if (n >= e)
23309ef1f84bSDavid du Colombier error("device not bound");
23319ef1f84bSDavid du Colombier
23329ef1f84bSDavid du Colombier /*
23339ef1f84bSDavid du Colombier * hunt down devices using this interface; disable
23349ef1f84bSDavid du Colombier * this also terminates the reader.
23359ef1f84bSDavid du Colombier */
23369ef1f84bSDavid du Colombier idx = n - netlinks.nl;
23379ef1f84bSDavid du Colombier wlock(&devs);
23389ef1f84bSDavid du Colombier for(d = devs.d; d; d = d->next){
23399ef1f84bSDavid du Colombier qlock(d);
23409ef1f84bSDavid du Colombier for(i = 0; i < d->ndl; i++){
23419ef1f84bSDavid du Colombier l = d->dl + i;
23429ef1f84bSDavid du Colombier if(l->nl == n)
23439ef1f84bSDavid du Colombier l->flag &= ~Dup;
23449ef1f84bSDavid du Colombier }
23459ef1f84bSDavid du Colombier qunlock(d);
23469ef1f84bSDavid du Colombier }
23479ef1f84bSDavid du Colombier n->flag &= ~Dup;
23489ef1f84bSDavid du Colombier wunlock(&devs);
23499ef1f84bSDavid du Colombier
23509ef1f84bSDavid du Colombier /* confirm reader is down. */
23519ef1f84bSDavid du Colombier while(waserror())
23529ef1f84bSDavid du Colombier ;
23539ef1f84bSDavid du Colombier sleep(netlinks.rendez + idx, unbound, netlinks.reader + idx);
23549ef1f84bSDavid du Colombier poperror();
23559ef1f84bSDavid du Colombier
23569ef1f84bSDavid du Colombier /* reschedule packets. */
23579ef1f84bSDavid du Colombier wlock(&devs);
23589ef1f84bSDavid du Colombier for(d = devs.d; d; d = d->next){
23599ef1f84bSDavid du Colombier qlock(d);
23609ef1f84bSDavid du Colombier for(i = 0; i < d->nframes; i++){
23619ef1f84bSDavid du Colombier f = d->frames + i;
23629ef1f84bSDavid du Colombier if(f->tag != Tfree && f->nl == n)
23639ef1f84bSDavid du Colombier resend(d, f);
23649ef1f84bSDavid du Colombier }
23659ef1f84bSDavid du Colombier qunlock(d);
23669ef1f84bSDavid du Colombier }
23679ef1f84bSDavid du Colombier wunlock(&devs);
23689ef1f84bSDavid du Colombier
23699ef1f84bSDavid du Colombier /* squeeze devlink pool. (we assert nobody is using them now) */
23709ef1f84bSDavid du Colombier wlock(&devs);
23719ef1f84bSDavid du Colombier for(d = devs.d; d; d = d->next){
23729ef1f84bSDavid du Colombier qlock(d);
23739ef1f84bSDavid du Colombier for(i = 0; i < d->ndl; i++){
23749ef1f84bSDavid du Colombier l = d->dl + i;
23759ef1f84bSDavid du Colombier if(l->nl == n)
23769ef1f84bSDavid du Colombier memmove(l, l + 1, sizeof *l * (--d->ndl - i));
23779ef1f84bSDavid du Colombier }
23789ef1f84bSDavid du Colombier qunlock(d);
23799ef1f84bSDavid du Colombier }
23809ef1f84bSDavid du Colombier wunlock(&devs);
23819ef1f84bSDavid du Colombier
23829ef1f84bSDavid du Colombier /* close device link. */
23839ef1f84bSDavid du Colombier lock(&netlinks);
23849ef1f84bSDavid du Colombier dc = n->dc;
23859ef1f84bSDavid du Colombier cc = n->cc;
23869ef1f84bSDavid du Colombier if(n->mtu)
23879ef1f84bSDavid du Colombier cclose(n->mtu);
23889ef1f84bSDavid du Colombier memset(n, 0, sizeof *n);
23899ef1f84bSDavid du Colombier unlock(&netlinks);
23909ef1f84bSDavid du Colombier
23919ef1f84bSDavid du Colombier cclose(dc);
23929ef1f84bSDavid du Colombier cclose(cc);
23939ef1f84bSDavid du Colombier
23949ef1f84bSDavid du Colombier /* squeeze orphan devices */
23959ef1f84bSDavid du Colombier wlock(&devs);
23969ef1f84bSDavid du Colombier for(p = d = devs.d; d; d = next){
23979ef1f84bSDavid du Colombier next = d->next;
23989ef1f84bSDavid du Colombier if(d->ndl > 0) {
23999ef1f84bSDavid du Colombier p = d;
24009ef1f84bSDavid du Colombier continue;
24019ef1f84bSDavid du Colombier }
24029ef1f84bSDavid du Colombier qlock(d);
24039ef1f84bSDavid du Colombier downdev(d, "orphan");
24049ef1f84bSDavid du Colombier qunlock(d);
24059ef1f84bSDavid du Colombier if(p != devs.d)
24069ef1f84bSDavid du Colombier p->next = next;
24079ef1f84bSDavid du Colombier else{
24089ef1f84bSDavid du Colombier devs.d = next;
24099ef1f84bSDavid du Colombier p = devs.d;
24109ef1f84bSDavid du Colombier }
24119ef1f84bSDavid du Colombier free(d->frames);
24129ef1f84bSDavid du Colombier free(d);
24139ef1f84bSDavid du Colombier dropunit();
24149ef1f84bSDavid du Colombier }
24159ef1f84bSDavid du Colombier wunlock(&devs);
24169ef1f84bSDavid du Colombier }
24179ef1f84bSDavid du Colombier
24189ef1f84bSDavid du Colombier static void
removeaoedev(Aoedev * d)24199ef1f84bSDavid du Colombier removeaoedev(Aoedev *d)
24209ef1f84bSDavid du Colombier {
24219ef1f84bSDavid du Colombier int i;
24229ef1f84bSDavid du Colombier Aoedev *p;
24239ef1f84bSDavid du Colombier
24249ef1f84bSDavid du Colombier wlock(&devs);
24259ef1f84bSDavid du Colombier p = 0;
24269ef1f84bSDavid du Colombier if(d != devs.d)
24279ef1f84bSDavid du Colombier for(p = devs.d; p; p = p->next)
24289ef1f84bSDavid du Colombier if(p->next == d)
24299ef1f84bSDavid du Colombier break;
24309ef1f84bSDavid du Colombier qlock(d);
24319ef1f84bSDavid du Colombier d->flag &= ~Dup;
2432406c76faSDavid du Colombier
2433406c76faSDavid du Colombier /*
2434406c76faSDavid du Colombier * Changing the version number is, strictly speaking, correct,
2435406c76faSDavid du Colombier * but doing so means that deleting a LUN that is not in use
2436406c76faSDavid du Colombier * invalidates all other LUNs too. If your file server has
2437406c76faSDavid du Colombier * venti arenas or fossil file systems on 1.0, and you delete 1.1,
2438406c76faSDavid du Colombier * since you no longer need it, 1.0 will become inaccessible to your
2439406c76faSDavid du Colombier * file server, which will eventually panic. Note that newdev()
2440406c76faSDavid du Colombier * does not change the version number.
2441406c76faSDavid du Colombier */
2442406c76faSDavid du Colombier // newvers(d);
2443406c76faSDavid du Colombier
24449ef1f84bSDavid du Colombier d->ndl = 0;
24459ef1f84bSDavid du Colombier qunlock(d);
24469ef1f84bSDavid du Colombier for(i = 0; i < d->nframes; i++)
2447406c76faSDavid du Colombier frameerror(d, d->frames+i, Eaoedown);
24489ef1f84bSDavid du Colombier
24499ef1f84bSDavid du Colombier if(p)
24509ef1f84bSDavid du Colombier p->next = d->next;
24519ef1f84bSDavid du Colombier else
24529ef1f84bSDavid du Colombier devs.d = d->next;
24539ef1f84bSDavid du Colombier free(d->frames);
24549ef1f84bSDavid du Colombier free(d);
24559ef1f84bSDavid du Colombier dropunit();
24569ef1f84bSDavid du Colombier wunlock(&devs);
24579ef1f84bSDavid du Colombier }
24589ef1f84bSDavid du Colombier
24599ef1f84bSDavid du Colombier static void
removedev(char * name)24609ef1f84bSDavid du Colombier removedev(char *name)
24619ef1f84bSDavid du Colombier {
24629ef1f84bSDavid du Colombier Aoedev *d, *p;
24639ef1f84bSDavid du Colombier
24649ef1f84bSDavid du Colombier wlock(&devs);
24659ef1f84bSDavid du Colombier for(p = d = devs.d; d; p = d, d = d->next)
24669ef1f84bSDavid du Colombier if(strcmp(name, unitname(d)) == 0) {
24679ef1f84bSDavid du Colombier wunlock(&devs);
24689ef1f84bSDavid du Colombier removeaoedev(p);
24699ef1f84bSDavid du Colombier return;
24709ef1f84bSDavid du Colombier }
24719ef1f84bSDavid du Colombier wunlock(&devs);
24729ef1f84bSDavid du Colombier error("device not bound");
24739ef1f84bSDavid du Colombier }
24749ef1f84bSDavid du Colombier
24759ef1f84bSDavid du Colombier static void
discoverstr(char * f)24769ef1f84bSDavid du Colombier discoverstr(char *f)
24779ef1f84bSDavid du Colombier {
24789ef1f84bSDavid du Colombier ushort shelf, slot;
24799ef1f84bSDavid du Colombier ulong sh;
24809ef1f84bSDavid du Colombier char *s;
24819ef1f84bSDavid du Colombier
24829ef1f84bSDavid du Colombier if(f == 0){
24839ef1f84bSDavid du Colombier discover(0xffff, 0xff);
24849ef1f84bSDavid du Colombier return;
24859ef1f84bSDavid du Colombier }
24869ef1f84bSDavid du Colombier
24879ef1f84bSDavid du Colombier shelf = sh = strtol(f, &s, 0);
24889ef1f84bSDavid du Colombier if(s == f || sh > 0xffff)
24899ef1f84bSDavid du Colombier error("bad shelf");
24909ef1f84bSDavid du Colombier f = s;
24919ef1f84bSDavid du Colombier if(*f++ == '.'){
24929ef1f84bSDavid du Colombier slot = strtol(f, &s, 0);
24939ef1f84bSDavid du Colombier if(s == f || slot > 0xff)
24949ef1f84bSDavid du Colombier error("bad shelf");
24959ef1f84bSDavid du Colombier }else
24969ef1f84bSDavid du Colombier slot = 0xff;
24979ef1f84bSDavid du Colombier discover(shelf, slot);
24989ef1f84bSDavid du Colombier }
24999ef1f84bSDavid du Colombier
25009ef1f84bSDavid du Colombier
25019ef1f84bSDavid du Colombier static void
aoeremove(Chan * c)25029ef1f84bSDavid du Colombier aoeremove(Chan *c)
25039ef1f84bSDavid du Colombier {
25049ef1f84bSDavid du Colombier switch(TYPE(c->qid)){
25059ef1f84bSDavid du Colombier default:
25069ef1f84bSDavid du Colombier error(Eperm);
25079ef1f84bSDavid du Colombier case Qunitdir:
25089ef1f84bSDavid du Colombier removeaoedev(unit2dev(UNIT(c->qid)));
25099ef1f84bSDavid du Colombier break;
25109ef1f84bSDavid du Colombier }
25119ef1f84bSDavid du Colombier }
25129ef1f84bSDavid du Colombier
25139ef1f84bSDavid du Colombier static long
topctlwrite(void * db,long n)25149ef1f84bSDavid du Colombier topctlwrite(void *db, long n)
25159ef1f84bSDavid du Colombier {
25169ef1f84bSDavid du Colombier enum {
25179ef1f84bSDavid du Colombier Autodiscover,
25189ef1f84bSDavid du Colombier Bind,
25199ef1f84bSDavid du Colombier Debug,
25209ef1f84bSDavid du Colombier Discover,
25219ef1f84bSDavid du Colombier Rediscover,
25229ef1f84bSDavid du Colombier Remove,
25239ef1f84bSDavid du Colombier Unbind,
25249ef1f84bSDavid du Colombier };
25259ef1f84bSDavid du Colombier char *f;
25269ef1f84bSDavid du Colombier Cmdbuf *cb;
25279ef1f84bSDavid du Colombier Cmdtab *ct;
25289ef1f84bSDavid du Colombier static Cmdtab cmds[] = {
25299ef1f84bSDavid du Colombier { Autodiscover, "autodiscover", 0 },
25309ef1f84bSDavid du Colombier { Bind, "bind", 2 },
25319ef1f84bSDavid du Colombier { Debug, "debug", 0 },
25329ef1f84bSDavid du Colombier { Discover, "discover", 0 },
25339ef1f84bSDavid du Colombier { Rediscover, "rediscover", 0 },
25349ef1f84bSDavid du Colombier { Remove, "remove", 2 },
25359ef1f84bSDavid du Colombier { Unbind, "unbind", 2 },
25369ef1f84bSDavid du Colombier };
25379ef1f84bSDavid du Colombier
25389ef1f84bSDavid du Colombier cb = parsecmd(db, n);
25399ef1f84bSDavid du Colombier if(waserror()){
25409ef1f84bSDavid du Colombier free(cb);
25419ef1f84bSDavid du Colombier nexterror();
25429ef1f84bSDavid du Colombier }
25439ef1f84bSDavid du Colombier ct = lookupcmd(cb, cmds, nelem(cmds));
25449ef1f84bSDavid du Colombier f = cb->f[1];
25459ef1f84bSDavid du Colombier switch(ct->index){
25469ef1f84bSDavid du Colombier case Autodiscover:
25479ef1f84bSDavid du Colombier autodiscover = toggle(f, autodiscover, 1);
25489ef1f84bSDavid du Colombier break;
25499ef1f84bSDavid du Colombier case Bind:
25509ef1f84bSDavid du Colombier netbind(f);
25519ef1f84bSDavid du Colombier break;
25529ef1f84bSDavid du Colombier case Debug:
25539ef1f84bSDavid du Colombier debug = toggle(f, debug, 1);
25549ef1f84bSDavid du Colombier break;
25559ef1f84bSDavid du Colombier case Discover:
25569ef1f84bSDavid du Colombier discoverstr(f);
25579ef1f84bSDavid du Colombier break;
25589ef1f84bSDavid du Colombier case Rediscover:
25599ef1f84bSDavid du Colombier rediscover = toggle(f, rediscover, 1);
25609ef1f84bSDavid du Colombier break;
25619ef1f84bSDavid du Colombier case Remove:
25629ef1f84bSDavid du Colombier removedev(f);
25639ef1f84bSDavid du Colombier break;
25649ef1f84bSDavid du Colombier case Unbind:
25659ef1f84bSDavid du Colombier netunbind(f);
25669ef1f84bSDavid du Colombier break;
25679ef1f84bSDavid du Colombier default:
25689ef1f84bSDavid du Colombier cmderror(cb, "unknown aoe control message");
25699ef1f84bSDavid du Colombier }
25709ef1f84bSDavid du Colombier poperror();
25719ef1f84bSDavid du Colombier free(cb);
25729ef1f84bSDavid du Colombier return n;
25739ef1f84bSDavid du Colombier }
25749ef1f84bSDavid du Colombier
25759ef1f84bSDavid du Colombier static long
aoewrite(Chan * c,void * db,long n,vlong off)25769ef1f84bSDavid du Colombier aoewrite(Chan *c, void *db, long n, vlong off)
25779ef1f84bSDavid du Colombier {
25789ef1f84bSDavid du Colombier switch(TYPE(c->qid)){
25799ef1f84bSDavid du Colombier default:
25809ef1f84bSDavid du Colombier case Qzero:
25819ef1f84bSDavid du Colombier case Qtopdir:
25829ef1f84bSDavid du Colombier case Qunitdir:
25839ef1f84bSDavid du Colombier case Qtoplog:
25849ef1f84bSDavid du Colombier error(Eperm);
25859ef1f84bSDavid du Colombier case Qtopctl:
25869ef1f84bSDavid du Colombier return topctlwrite(db, n);
25879ef1f84bSDavid du Colombier case Qctl:
25889ef1f84bSDavid du Colombier case Qdata:
25899ef1f84bSDavid du Colombier case Qconfig:
25909ef1f84bSDavid du Colombier case Qident:
25919ef1f84bSDavid du Colombier return unitwrite(c, db, n, off);
25929ef1f84bSDavid du Colombier }
25939ef1f84bSDavid du Colombier }
25949ef1f84bSDavid du Colombier
25959ef1f84bSDavid du Colombier Dev aoedevtab = {
25969ef1f84bSDavid du Colombier L'æ',
25979ef1f84bSDavid du Colombier "aoe",
25989ef1f84bSDavid du Colombier
25999ef1f84bSDavid du Colombier devreset,
26009ef1f84bSDavid du Colombier devinit,
26019ef1f84bSDavid du Colombier devshutdown,
26029ef1f84bSDavid du Colombier aoeattach,
26039ef1f84bSDavid du Colombier aoewalk,
26049ef1f84bSDavid du Colombier aoestat,
26059ef1f84bSDavid du Colombier aoeopen,
26069ef1f84bSDavid du Colombier devcreate,
26079ef1f84bSDavid du Colombier aoeclose,
26089ef1f84bSDavid du Colombier aoeread,
26099ef1f84bSDavid du Colombier devbread,
26109ef1f84bSDavid du Colombier aoewrite,
26119ef1f84bSDavid du Colombier devbwrite,
26129ef1f84bSDavid du Colombier aoeremove,
26139ef1f84bSDavid du Colombier devwstat,
26149ef1f84bSDavid du Colombier devpower,
26159ef1f84bSDavid du Colombier devconfig,
26169ef1f84bSDavid du Colombier };
2617