121abd8f2SDavid du Colombier /*
22f205b96SDavid du Colombier * © 2005-2010 coraid
3060a30c6SDavid du Colombier * ATA-over-Ethernet (AoE) storage initiator
421abd8f2SDavid du Colombier */
521abd8f2SDavid du Colombier
621abd8f2SDavid du Colombier #include "u.h"
721abd8f2SDavid du Colombier #include "../port/lib.h"
821abd8f2SDavid du Colombier #include "mem.h"
921abd8f2SDavid du Colombier #include "dat.h"
1021abd8f2SDavid du Colombier #include "fns.h"
1121abd8f2SDavid du Colombier #include "io.h"
1221abd8f2SDavid du Colombier #include "ureg.h"
1321abd8f2SDavid du Colombier #include "../port/error.h"
1421abd8f2SDavid du Colombier #include "../port/netif.h"
1521abd8f2SDavid du Colombier #include "etherif.h"
1621abd8f2SDavid du Colombier #include "../ip/ip.h"
1721abd8f2SDavid du Colombier #include "../port/aoe.h"
1821abd8f2SDavid du Colombier
1921abd8f2SDavid du Colombier #pragma varargck argpos eventlog 1
2021abd8f2SDavid du Colombier
2121abd8f2SDavid du Colombier #define dprint(...) if(debug) eventlog(__VA_ARGS__); else USED(debug);
2221abd8f2SDavid du Colombier #define uprint(...) snprint(up->genbuf, sizeof up->genbuf, __VA_ARGS__);
2321abd8f2SDavid du Colombier
2421abd8f2SDavid du Colombier enum {
25c675ee80SDavid du Colombier Maxunits = 0xff,
2641ac1ab6SDavid du Colombier Maxframes = 128,
2721abd8f2SDavid du Colombier Ndevlink = 6,
2821abd8f2SDavid du Colombier Nea = 6,
2921abd8f2SDavid du Colombier Nnetlink = 6,
3021abd8f2SDavid du Colombier };
3121abd8f2SDavid du Colombier
3221abd8f2SDavid du Colombier #define TYPE(q) ((ulong)(q).path & 0xf)
33c675ee80SDavid du Colombier #define UNIT(q) (((ulong)(q).path>>4) & 0xff)
34c675ee80SDavid du Colombier #define L(q) (((ulong)(q).path>>12) & 0xf)
3521abd8f2SDavid du Colombier #define QID(u, t) ((u)<<4 | (t))
3621abd8f2SDavid du Colombier #define Q3(l, u, t) ((l)<<8 | QID(u, t))
3721abd8f2SDavid du Colombier #define UP(d) ((d)->flag & Dup)
382f205b96SDavid du Colombier /*
392f205b96SDavid du Colombier * would like this to depend on the chan (srb).
402f205b96SDavid du Colombier * not possible in the current structure.
412f205b96SDavid du Colombier */
422f205b96SDavid du Colombier #define Nofail(d, s) ((d)->flag & Dnofail)
4321abd8f2SDavid du Colombier
44552c49cfSDavid du Colombier #define MS2TK(t) ((t)/MS2HZ)
4521abd8f2SDavid du Colombier
4621abd8f2SDavid du Colombier enum {
4721abd8f2SDavid du Colombier Qzero,
4821abd8f2SDavid du Colombier Qtopdir = 1,
4921abd8f2SDavid du Colombier Qtopbase,
5021abd8f2SDavid du Colombier Qtopctl = Qtopbase,
5121abd8f2SDavid du Colombier Qtoplog,
5221abd8f2SDavid du Colombier Qtopend,
5321abd8f2SDavid du Colombier
5421abd8f2SDavid du Colombier Qunitdir,
5521abd8f2SDavid du Colombier Qunitbase,
5621abd8f2SDavid du Colombier Qctl = Qunitbase,
5721abd8f2SDavid du Colombier Qdata,
5821abd8f2SDavid du Colombier Qconfig,
5921abd8f2SDavid du Colombier Qident,
6021abd8f2SDavid du Colombier
6121abd8f2SDavid du Colombier Qdevlinkdir,
6221abd8f2SDavid du Colombier Qdevlinkbase,
6321abd8f2SDavid du Colombier Qdevlink = Qdevlinkbase,
6421abd8f2SDavid du Colombier Qdevlinkend,
6521abd8f2SDavid du Colombier
6621abd8f2SDavid du Colombier Qtopfiles = Qtopend-Qtopbase,
6721abd8f2SDavid du Colombier Qdevlinkfiles = Qdevlinkend-Qdevlinkbase,
6821abd8f2SDavid du Colombier
6921abd8f2SDavid du Colombier Eventlen = 256,
702f205b96SDavid du Colombier Nevents = 64, /* must be power of 2 */
7121abd8f2SDavid du Colombier
7221abd8f2SDavid du Colombier Fread = 0,
7321abd8f2SDavid du Colombier Fwrite,
7421abd8f2SDavid du Colombier Tfree = -1,
7521abd8f2SDavid du Colombier Tmgmt,
7621abd8f2SDavid du Colombier
77bc8903feSDavid du Colombier /*
78bc8903feSDavid du Colombier * round trip bounds, timeouts, in ticks.
79bc8903feSDavid du Colombier * timeouts should be long enough that rebooting
80552c49cfSDavid du Colombier * the coraid (which usually takes under two minutes)
81bc8903feSDavid du Colombier * doesn't trigger a timeout.
82bc8903feSDavid du Colombier */
83552c49cfSDavid du Colombier Rtmax = MS2TK(320),
84552c49cfSDavid du Colombier Rtmin = MS2TK(20),
85552c49cfSDavid du Colombier Maxreqticks = 4*60*HZ, /* was 45*HZ */
8621abd8f2SDavid du Colombier
8721abd8f2SDavid du Colombier Dbcnt = 1024,
8821abd8f2SDavid du Colombier
8921abd8f2SDavid du Colombier Crd = 0x20,
9021abd8f2SDavid du Colombier Crdext = 0x24,
9121abd8f2SDavid du Colombier Cwr = 0x30,
9221abd8f2SDavid du Colombier Cwrext = 0x34,
9321abd8f2SDavid du Colombier Cid = 0xec,
9421abd8f2SDavid du Colombier };
9521abd8f2SDavid du Colombier
9699c72adcSDavid du Colombier enum {
9799c72adcSDavid du Colombier Read,
9899c72adcSDavid du Colombier Write,
9999c72adcSDavid du Colombier };
10099c72adcSDavid du Colombier
10121abd8f2SDavid du Colombier /*
10221abd8f2SDavid du Colombier * unified set of flags
10321abd8f2SDavid du Colombier * a Netlink + Aoedev most both be jumbo capable
10421abd8f2SDavid du Colombier * to send jumbograms to that interface.
10521abd8f2SDavid du Colombier */
10621abd8f2SDavid du Colombier enum {
10721abd8f2SDavid du Colombier /* sync with ahci.h */
10821abd8f2SDavid du Colombier Dllba = 1<<0,
10921abd8f2SDavid du Colombier Dsmart = 1<<1,
11021abd8f2SDavid du Colombier Dpower = 1<<2,
11121abd8f2SDavid du Colombier Dnop = 1<<3,
11221abd8f2SDavid du Colombier Datapi = 1<<4,
11321abd8f2SDavid du Colombier Datapi16= 1<<5,
11421abd8f2SDavid du Colombier
11521abd8f2SDavid du Colombier /* aoe specific */
11621abd8f2SDavid du Colombier Dup = 1<<6,
11721abd8f2SDavid du Colombier Djumbo = 1<<7,
1182f205b96SDavid du Colombier Dnofail = 1<<8,
11921abd8f2SDavid du Colombier };
12021abd8f2SDavid du Colombier
12121abd8f2SDavid du Colombier static char *flagname[] = {
12221abd8f2SDavid du Colombier "llba",
12321abd8f2SDavid du Colombier "smart",
12421abd8f2SDavid du Colombier "power",
12521abd8f2SDavid du Colombier "nop",
12621abd8f2SDavid du Colombier "atapi",
12721abd8f2SDavid du Colombier "atapi16",
12821abd8f2SDavid du Colombier
12921abd8f2SDavid du Colombier "up",
13021abd8f2SDavid du Colombier "jumbo",
1312f205b96SDavid du Colombier "nofail",
13221abd8f2SDavid du Colombier };
13321abd8f2SDavid du Colombier
13421abd8f2SDavid du Colombier typedef struct {
1352f205b96SDavid du Colombier ushort flag;
1362f205b96SDavid du Colombier uint lostjumbo;
13721abd8f2SDavid du Colombier int datamtu;
13821abd8f2SDavid du Colombier
13921abd8f2SDavid du Colombier Chan *cc;
14021abd8f2SDavid du Colombier Chan *dc;
14121abd8f2SDavid du Colombier Chan *mtu; /* open early to prevent bind issues. */
14221abd8f2SDavid du Colombier char path[Maxpath];
14321abd8f2SDavid du Colombier uchar ea[Eaddrlen];
14421abd8f2SDavid du Colombier } Netlink;
14521abd8f2SDavid du Colombier
14621abd8f2SDavid du Colombier typedef struct {
14721abd8f2SDavid du Colombier Netlink *nl;
14821abd8f2SDavid du Colombier int nea;
14921abd8f2SDavid du Colombier ulong eaidx;
15021abd8f2SDavid du Colombier uchar eatab[Nea][Eaddrlen];
15121abd8f2SDavid du Colombier ulong npkt;
15221abd8f2SDavid du Colombier ulong resent;
1532f205b96SDavid du Colombier ushort flag;
15421abd8f2SDavid du Colombier
15521abd8f2SDavid du Colombier ulong rttavg;
15621abd8f2SDavid du Colombier ulong mintimer;
15721abd8f2SDavid du Colombier } Devlink;
15821abd8f2SDavid du Colombier
15921abd8f2SDavid du Colombier typedef struct Srb Srb;
16021abd8f2SDavid du Colombier struct Srb {
16121abd8f2SDavid du Colombier Rendez;
16221abd8f2SDavid du Colombier Srb *next;
163*f7c114afSDavid du Colombier int shared; /* Srb shared with kproc (don't free) */
16421abd8f2SDavid du Colombier ulong ticksent;
16521abd8f2SDavid du Colombier ulong len;
16621abd8f2SDavid du Colombier vlong sector;
16721abd8f2SDavid du Colombier short write;
16821abd8f2SDavid du Colombier short nout;
16921abd8f2SDavid du Colombier char *error;
17021abd8f2SDavid du Colombier void *dp;
17121abd8f2SDavid du Colombier void *data;
17221abd8f2SDavid du Colombier };
17321abd8f2SDavid du Colombier
17421abd8f2SDavid du Colombier typedef struct {
17521abd8f2SDavid du Colombier int tag;
17621abd8f2SDavid du Colombier ulong bcnt;
177c675ee80SDavid du Colombier ulong dlen;
17821abd8f2SDavid du Colombier vlong lba;
17921abd8f2SDavid du Colombier ulong ticksent;
18021abd8f2SDavid du Colombier int nhdr;
18121abd8f2SDavid du Colombier uchar hdr[ETHERMINTU];
18221abd8f2SDavid du Colombier void *dp;
18321abd8f2SDavid du Colombier Devlink *dl;
18421abd8f2SDavid du Colombier Netlink *nl;
18521abd8f2SDavid du Colombier int eaidx;
18621abd8f2SDavid du Colombier Srb *srb;
18721abd8f2SDavid du Colombier } Frame;
18821abd8f2SDavid du Colombier
18921abd8f2SDavid du Colombier typedef struct Aoedev Aoedev;
19021abd8f2SDavid du Colombier struct Aoedev {
19121abd8f2SDavid du Colombier QLock;
19221abd8f2SDavid du Colombier Aoedev *next;
19321abd8f2SDavid du Colombier
19421abd8f2SDavid du Colombier ulong vers;
19521abd8f2SDavid du Colombier
19621abd8f2SDavid du Colombier int ndl;
19721abd8f2SDavid du Colombier ulong dlidx;
19821abd8f2SDavid du Colombier Devlink *dl;
19921abd8f2SDavid du Colombier Devlink dltab[Ndevlink];
20021abd8f2SDavid du Colombier
20121abd8f2SDavid du Colombier ushort fwver;
2022f205b96SDavid du Colombier ushort flag;
20321abd8f2SDavid du Colombier int nopen;
20421abd8f2SDavid du Colombier int major;
20521abd8f2SDavid du Colombier int minor;
20621abd8f2SDavid du Colombier int unit;
20721abd8f2SDavid du Colombier int lasttag;
20821abd8f2SDavid du Colombier int nframes;
20921abd8f2SDavid du Colombier Frame *frames;
21021abd8f2SDavid du Colombier vlong bsize;
21121abd8f2SDavid du Colombier vlong realbsize;
21221abd8f2SDavid du Colombier
21321abd8f2SDavid du Colombier uint maxbcnt;
21421abd8f2SDavid du Colombier ushort nout;
21521abd8f2SDavid du Colombier ushort maxout;
21621abd8f2SDavid du Colombier ulong lastwadj;
21721abd8f2SDavid du Colombier Srb *head;
21821abd8f2SDavid du Colombier Srb *tail;
21921abd8f2SDavid du Colombier Srb *inprocess;
22021abd8f2SDavid du Colombier
22121abd8f2SDavid du Colombier /* magic numbers 'R' us */
22221abd8f2SDavid du Colombier char serial[20+1];
22321abd8f2SDavid du Colombier char firmware[8+1];
22421abd8f2SDavid du Colombier char model[40+1];
22521abd8f2SDavid du Colombier int nconfig;
22621abd8f2SDavid du Colombier uchar config[1024];
22721abd8f2SDavid du Colombier uchar ident[512];
22821abd8f2SDavid du Colombier };
22921abd8f2SDavid du Colombier
23021abd8f2SDavid du Colombier #pragma varargck type "æ" Aoedev*
23121abd8f2SDavid du Colombier
23221abd8f2SDavid du Colombier static struct {
23321abd8f2SDavid du Colombier Lock;
23421abd8f2SDavid du Colombier QLock;
23521abd8f2SDavid du Colombier Rendez;
23621abd8f2SDavid du Colombier char buf[Eventlen*Nevents];
23721abd8f2SDavid du Colombier char *rp;
23821abd8f2SDavid du Colombier char *wp;
23921abd8f2SDavid du Colombier } events;
24021abd8f2SDavid du Colombier
24121abd8f2SDavid du Colombier static struct {
24221abd8f2SDavid du Colombier RWlock;
24321abd8f2SDavid du Colombier int nd;
24421abd8f2SDavid du Colombier Aoedev *d;
24521abd8f2SDavid du Colombier } devs;
24621abd8f2SDavid du Colombier
24721abd8f2SDavid du Colombier static struct {
24821abd8f2SDavid du Colombier Lock;
24921abd8f2SDavid du Colombier int reader[Nnetlink]; /* reader is running. */
25021abd8f2SDavid du Colombier Rendez rendez[Nnetlink]; /* confirm exit. */
25121abd8f2SDavid du Colombier Netlink nl[Nnetlink];
25221abd8f2SDavid du Colombier } netlinks;
25321abd8f2SDavid du Colombier
25421abd8f2SDavid du Colombier extern Dev aoedevtab;
25521abd8f2SDavid du Colombier static Ref units;
256c675ee80SDavid du Colombier static Ref drivevers;
25721abd8f2SDavid du Colombier static int debug;
25821abd8f2SDavid du Colombier static int autodiscover = 1;
25921abd8f2SDavid du Colombier static int rediscover;
26021abd8f2SDavid du Colombier
26121abd8f2SDavid du Colombier static Srb*
srballoc(ulong sz)26221abd8f2SDavid du Colombier srballoc(ulong sz)
26321abd8f2SDavid du Colombier {
26421abd8f2SDavid du Colombier Srb *srb;
26521abd8f2SDavid du Colombier
26621abd8f2SDavid du Colombier srb = malloc(sizeof *srb+sz);
267aa72973aSDavid du Colombier if(srb == nil)
268aa72973aSDavid du Colombier error(Enomem);
26921abd8f2SDavid du Colombier srb->dp = srb->data = srb+1;
27099c72adcSDavid du Colombier srb->ticksent = MACHP(0)->ticks;
271*f7c114afSDavid du Colombier srb->shared = 0;
27221abd8f2SDavid du Colombier return srb;
27321abd8f2SDavid du Colombier }
27421abd8f2SDavid du Colombier
27521abd8f2SDavid du Colombier static Srb*
srbkalloc(void * db,ulong)27621abd8f2SDavid du Colombier srbkalloc(void *db, ulong)
27721abd8f2SDavid du Colombier {
27821abd8f2SDavid du Colombier Srb *srb;
27921abd8f2SDavid du Colombier
28021abd8f2SDavid du Colombier srb = malloc(sizeof *srb);
281aa72973aSDavid du Colombier if(srb == nil)
282aa72973aSDavid du Colombier error(Enomem);
28321abd8f2SDavid du Colombier srb->dp = srb->data = db;
28499c72adcSDavid du Colombier srb->ticksent = MACHP(0)->ticks;
285*f7c114afSDavid du Colombier srb->shared = 0;
28621abd8f2SDavid du Colombier return srb;
28721abd8f2SDavid du Colombier }
28821abd8f2SDavid du Colombier
289*f7c114afSDavid du Colombier static void
srbfree(Srb * srb)290*f7c114afSDavid du Colombier srbfree(Srb *srb)
291*f7c114afSDavid du Colombier {
292*f7c114afSDavid du Colombier while(srb->shared)
293*f7c114afSDavid du Colombier sched();
294*f7c114afSDavid du Colombier free(srb);
295*f7c114afSDavid du Colombier }
29621abd8f2SDavid du Colombier
29721abd8f2SDavid du Colombier static void
srberror(Srb * srb,char * s)29821abd8f2SDavid du Colombier srberror(Srb *srb, char *s)
29921abd8f2SDavid du Colombier {
30021abd8f2SDavid du Colombier srb->error = s;
30121abd8f2SDavid du Colombier srb->nout--;
30245dfec46SDavid du Colombier if(srb->nout == 0)
30321abd8f2SDavid du Colombier wakeup(srb);
30421abd8f2SDavid du Colombier }
30521abd8f2SDavid du Colombier
30621abd8f2SDavid du Colombier static void
frameerror(Aoedev * d,Frame * f,char * s)30721abd8f2SDavid du Colombier frameerror(Aoedev *d, Frame *f, char *s)
30821abd8f2SDavid du Colombier {
30921abd8f2SDavid du Colombier Srb *srb;
31021abd8f2SDavid du Colombier
31121abd8f2SDavid du Colombier srb = f->srb;
31221abd8f2SDavid du Colombier if(f->tag == Tfree || !srb)
31321abd8f2SDavid du Colombier return;
31421abd8f2SDavid du Colombier f->srb = nil;
31521abd8f2SDavid du Colombier f->tag = Tfree; /* don't get fooled by way-slow responses */
31621abd8f2SDavid du Colombier srberror(srb, s);
31721abd8f2SDavid du Colombier d->nout--;
31821abd8f2SDavid du Colombier }
31921abd8f2SDavid du Colombier
32021abd8f2SDavid du Colombier static char*
unitname(Aoedev * d)32121abd8f2SDavid du Colombier unitname(Aoedev *d)
32221abd8f2SDavid du Colombier {
32321abd8f2SDavid du Colombier uprint("%d.%d", d->major, d->minor);
32421abd8f2SDavid du Colombier return up->genbuf;
32521abd8f2SDavid du Colombier }
32621abd8f2SDavid du Colombier
32721abd8f2SDavid du Colombier static int
eventlogready(void *)32821abd8f2SDavid du Colombier eventlogready(void*)
32921abd8f2SDavid du Colombier {
33021abd8f2SDavid du Colombier return *events.rp;
33121abd8f2SDavid du Colombier }
33221abd8f2SDavid du Colombier
33321abd8f2SDavid du Colombier static long
eventlogread(void * a,long n)33421abd8f2SDavid du Colombier eventlogread(void *a, long n)
33521abd8f2SDavid du Colombier {
33621abd8f2SDavid du Colombier int len;
33721abd8f2SDavid du Colombier char *p, *buf;
33821abd8f2SDavid du Colombier
33921abd8f2SDavid du Colombier buf = smalloc(Eventlen);
34021abd8f2SDavid du Colombier qlock(&events);
34121abd8f2SDavid du Colombier lock(&events);
34221abd8f2SDavid du Colombier p = events.rp;
34321abd8f2SDavid du Colombier len = *p;
34421abd8f2SDavid du Colombier if(len == 0){
34521abd8f2SDavid du Colombier n = 0;
34621abd8f2SDavid du Colombier unlock(&events);
34721abd8f2SDavid du Colombier } else {
34821abd8f2SDavid du Colombier if(n > len)
34921abd8f2SDavid du Colombier n = len;
35021abd8f2SDavid du Colombier /* can't move directly into pageable space with events lock held */
35121abd8f2SDavid du Colombier memmove(buf, p+1, n);
35221abd8f2SDavid du Colombier *p = 0;
35321abd8f2SDavid du Colombier events.rp = p += Eventlen;
35421abd8f2SDavid du Colombier if(p >= events.buf + sizeof events.buf)
35521abd8f2SDavid du Colombier events.rp = events.buf;
35621abd8f2SDavid du Colombier unlock(&events);
35721abd8f2SDavid du Colombier
35821abd8f2SDavid du Colombier /* the concern here is page faults in memmove below */
35921abd8f2SDavid du Colombier if(waserror()){
36021abd8f2SDavid du Colombier free(buf);
36121abd8f2SDavid du Colombier qunlock(&events);
36221abd8f2SDavid du Colombier nexterror();
36321abd8f2SDavid du Colombier }
36421abd8f2SDavid du Colombier memmove(a, buf, n);
36521abd8f2SDavid du Colombier poperror();
36621abd8f2SDavid du Colombier }
36721abd8f2SDavid du Colombier free(buf);
36821abd8f2SDavid du Colombier qunlock(&events);
36921abd8f2SDavid du Colombier return n;
37021abd8f2SDavid du Colombier }
37121abd8f2SDavid du Colombier
37221abd8f2SDavid du Colombier static int
eventlog(char * fmt,...)37321abd8f2SDavid du Colombier eventlog(char *fmt, ...)
37421abd8f2SDavid du Colombier {
37521abd8f2SDavid du Colombier int dragrp, n;
37621abd8f2SDavid du Colombier char *p;
37721abd8f2SDavid du Colombier va_list arg;
37821abd8f2SDavid du Colombier
37921abd8f2SDavid du Colombier lock(&events);
38021abd8f2SDavid du Colombier p = events.wp;
38121abd8f2SDavid du Colombier dragrp = *p++;
38221abd8f2SDavid du Colombier va_start(arg, fmt);
38321abd8f2SDavid du Colombier n = vsnprint(p, Eventlen-1, fmt, arg);
38421abd8f2SDavid du Colombier *--p = n;
38521abd8f2SDavid du Colombier p = events.wp += Eventlen;
38621abd8f2SDavid du Colombier if(p >= events.buf + sizeof events.buf)
38721abd8f2SDavid du Colombier p = events.wp = events.buf;
38821abd8f2SDavid du Colombier if(dragrp)
38921abd8f2SDavid du Colombier events.rp = p;
39021abd8f2SDavid du Colombier unlock(&events);
39121abd8f2SDavid du Colombier wakeup(&events);
39221abd8f2SDavid du Colombier return n;
39321abd8f2SDavid du Colombier }
39421abd8f2SDavid du Colombier
39521abd8f2SDavid du Colombier static int
eventcount(void)39621abd8f2SDavid du Colombier eventcount(void)
39721abd8f2SDavid du Colombier {
39821abd8f2SDavid du Colombier int n;
39921abd8f2SDavid du Colombier
40021abd8f2SDavid du Colombier lock(&events);
40121abd8f2SDavid du Colombier if(*events.rp == 0)
40221abd8f2SDavid du Colombier n = 0;
40321abd8f2SDavid du Colombier else
4042f205b96SDavid du Colombier n = (events.wp - events.rp) & (Nevents - 1);
40521abd8f2SDavid du Colombier unlock(&events);
40621abd8f2SDavid du Colombier return n/Eventlen;
40721abd8f2SDavid du Colombier }
40821abd8f2SDavid du Colombier
40921abd8f2SDavid du Colombier static int
tsince(int tag)41021abd8f2SDavid du Colombier tsince(int tag)
41121abd8f2SDavid du Colombier {
41221abd8f2SDavid du Colombier int n;
41321abd8f2SDavid du Colombier
41499c72adcSDavid du Colombier n = MACHP(0)->ticks & 0xffff;
41521abd8f2SDavid du Colombier n -= tag & 0xffff;
41621abd8f2SDavid du Colombier if(n < 0)
41721abd8f2SDavid du Colombier n += 1<<16;
41821abd8f2SDavid du Colombier return n;
41921abd8f2SDavid du Colombier }
42021abd8f2SDavid du Colombier
42121abd8f2SDavid du Colombier static int
newtag(Aoedev * d)42221abd8f2SDavid du Colombier newtag(Aoedev *d)
42321abd8f2SDavid du Colombier {
42421abd8f2SDavid du Colombier int t;
42521abd8f2SDavid du Colombier
42621abd8f2SDavid du Colombier do {
42721abd8f2SDavid du Colombier t = ++d->lasttag << 16;
42899c72adcSDavid du Colombier t |= MACHP(0)->ticks & 0xffff;
42921abd8f2SDavid du Colombier } while (t == Tfree || t == Tmgmt);
43021abd8f2SDavid du Colombier return t;
43121abd8f2SDavid du Colombier }
43221abd8f2SDavid du Colombier
43321abd8f2SDavid du Colombier static void
downdev(Aoedev * d,char * err)43421abd8f2SDavid du Colombier downdev(Aoedev *d, char *err)
43521abd8f2SDavid du Colombier {
43621abd8f2SDavid du Colombier Frame *f, *e;
43721abd8f2SDavid du Colombier
43821abd8f2SDavid du Colombier d->flag &= ~Dup;
43921abd8f2SDavid du Colombier f = d->frames;
44021abd8f2SDavid du Colombier e = f + d->nframes;
44121abd8f2SDavid du Colombier for(; f < e; f->tag = Tfree, f->srb = nil, f++)
442a587111cSDavid du Colombier frameerror(d, f, Eaoedown);
44321abd8f2SDavid du Colombier d->inprocess = nil;
44421abd8f2SDavid du Colombier eventlog("%æ: removed; %s\n", d, err);
44521abd8f2SDavid du Colombier }
44621abd8f2SDavid du Colombier
44721abd8f2SDavid du Colombier static Block*
allocfb(Frame * f)448c675ee80SDavid du Colombier allocfb(Frame *f)
44921abd8f2SDavid du Colombier {
45021abd8f2SDavid du Colombier int len;
45121abd8f2SDavid du Colombier Block *b;
45221abd8f2SDavid du Colombier
453c675ee80SDavid du Colombier len = f->nhdr + f->dlen;
45421abd8f2SDavid du Colombier if(len < ETHERMINTU)
45521abd8f2SDavid du Colombier len = ETHERMINTU;
45621abd8f2SDavid du Colombier b = allocb(len);
45721abd8f2SDavid du Colombier memmove(b->wp, f->hdr, f->nhdr);
458c675ee80SDavid du Colombier if(f->dlen)
459c675ee80SDavid du Colombier memmove(b->wp + f->nhdr, f->dp, f->dlen);
46021abd8f2SDavid du Colombier b->wp += len;
46121abd8f2SDavid du Colombier return b;
46221abd8f2SDavid du Colombier }
46321abd8f2SDavid du Colombier
46421abd8f2SDavid du Colombier static void
putlba(Aoeata * a,vlong lba)46521abd8f2SDavid du Colombier putlba(Aoeata *a, vlong lba)
46621abd8f2SDavid du Colombier {
46721abd8f2SDavid du Colombier uchar *c;
46821abd8f2SDavid du Colombier
46921abd8f2SDavid du Colombier c = a->lba;
47021abd8f2SDavid du Colombier c[0] = lba;
47121abd8f2SDavid du Colombier c[1] = lba >> 8;
47221abd8f2SDavid du Colombier c[2] = lba >> 16;
47321abd8f2SDavid du Colombier c[3] = lba >> 24;
47421abd8f2SDavid du Colombier c[4] = lba >> 32;
47521abd8f2SDavid du Colombier c[5] = lba >> 40;
47621abd8f2SDavid du Colombier }
47721abd8f2SDavid du Colombier
47821abd8f2SDavid du Colombier static Devlink*
pickdevlink(Aoedev * d)47921abd8f2SDavid du Colombier pickdevlink(Aoedev *d)
48021abd8f2SDavid du Colombier {
48121abd8f2SDavid du Colombier ulong i, n;
48221abd8f2SDavid du Colombier Devlink *l;
48321abd8f2SDavid du Colombier
48421abd8f2SDavid du Colombier for(i = 0; i < d->ndl; i++){
48521abd8f2SDavid du Colombier n = d->dlidx++ % d->ndl;
48621abd8f2SDavid du Colombier l = d->dl + n;
48721abd8f2SDavid du Colombier if(l && l->flag & Dup)
48821abd8f2SDavid du Colombier return l;
48921abd8f2SDavid du Colombier }
49021abd8f2SDavid du Colombier return 0;
49121abd8f2SDavid du Colombier }
49221abd8f2SDavid du Colombier
49321abd8f2SDavid du Colombier static int
pickea(Devlink * l)49421abd8f2SDavid du Colombier pickea(Devlink *l)
49521abd8f2SDavid du Colombier {
496421195e0SDavid du Colombier if(l == 0)
497421195e0SDavid du Colombier return -1;
49821abd8f2SDavid du Colombier if(l->nea == 0)
49921abd8f2SDavid du Colombier return -1;
50021abd8f2SDavid du Colombier return l->eaidx++ % l->nea;
50121abd8f2SDavid du Colombier }
50221abd8f2SDavid du Colombier
50321abd8f2SDavid du Colombier static int
hset(Aoedev * d,Frame * f,Aoehdr * h,int cmd)50421abd8f2SDavid du Colombier hset(Aoedev *d, Frame *f, Aoehdr *h, int cmd)
50521abd8f2SDavid du Colombier {
50621abd8f2SDavid du Colombier int i;
50721abd8f2SDavid du Colombier Devlink *l;
50821abd8f2SDavid du Colombier
5092f205b96SDavid du Colombier if(f->srb && MACHP(0)->ticks - f->srb->ticksent > Maxreqticks){
5102f205b96SDavid du Colombier eventlog("%æ: srb timeout\n", d);
5112f205b96SDavid du Colombier if(cmd == ACata && f->srb && Nofail(d, s))
5122f205b96SDavid du Colombier f->srb->ticksent = MACHP(0)->ticks;
5132f205b96SDavid du Colombier else
5142f205b96SDavid du Colombier frameerror(d, f, Etimedout);
5152f205b96SDavid du Colombier return -1;
5162f205b96SDavid du Colombier }
51721abd8f2SDavid du Colombier l = pickdevlink(d);
51821abd8f2SDavid du Colombier i = pickea(l);
519421195e0SDavid du Colombier if(i == -1){
5202f205b96SDavid du Colombier if(cmd != ACata || f->srb == nil || !Nofail(d, s))
521421195e0SDavid du Colombier downdev(d, "resend fails; no netlink/ea");
52221abd8f2SDavid du Colombier return -1;
52321abd8f2SDavid du Colombier }
524544cf74fSDavid du Colombier memmove(h->dst, l->eatab[i], Eaddrlen);
52521abd8f2SDavid du Colombier memmove(h->src, l->nl->ea, sizeof h->src);
52621abd8f2SDavid du Colombier hnputs(h->type, Aoetype);
52721abd8f2SDavid du Colombier h->verflag = Aoever << 4;
52821abd8f2SDavid du Colombier h->error = 0;
52921abd8f2SDavid du Colombier hnputs(h->major, d->major);
53021abd8f2SDavid du Colombier h->minor = d->minor;
53121abd8f2SDavid du Colombier h->cmd = cmd;
53221abd8f2SDavid du Colombier
53321abd8f2SDavid du Colombier hnputl(h->tag, f->tag = newtag(d));
53421abd8f2SDavid du Colombier f->dl = l;
53521abd8f2SDavid du Colombier f->nl = l->nl;
53621abd8f2SDavid du Colombier f->eaidx = i;
53799c72adcSDavid du Colombier f->ticksent = MACHP(0)->ticks;
53821abd8f2SDavid du Colombier
53921abd8f2SDavid du Colombier return f->tag;
54021abd8f2SDavid du Colombier }
54121abd8f2SDavid du Colombier
54221abd8f2SDavid du Colombier static int
resend(Aoedev * d,Frame * f)54321abd8f2SDavid du Colombier resend(Aoedev *d, Frame *f)
54421abd8f2SDavid du Colombier {
545c675ee80SDavid du Colombier ulong n;
54621abd8f2SDavid du Colombier Aoeata *a;
54721abd8f2SDavid du Colombier
54821abd8f2SDavid du Colombier a = (Aoeata*)f->hdr;
54921abd8f2SDavid du Colombier if(hset(d, f, a, a->cmd) == -1)
55021abd8f2SDavid du Colombier return -1;
55121abd8f2SDavid du Colombier n = f->bcnt;
552c675ee80SDavid du Colombier if(n > d->maxbcnt){
55321abd8f2SDavid du Colombier n = d->maxbcnt; /* mtu mismatch (jumbo fail?) */
554c675ee80SDavid du Colombier if(f->dlen > n)
555c675ee80SDavid du Colombier f->dlen = n;
556c675ee80SDavid du Colombier }
55721abd8f2SDavid du Colombier a->scnt = n / Aoesectsz;
55821abd8f2SDavid du Colombier f->dl->resent++;
55921abd8f2SDavid du Colombier f->dl->npkt++;
560421195e0SDavid du Colombier if(waserror())
561421195e0SDavid du Colombier return -1;
562c675ee80SDavid du Colombier devtab[f->nl->dc->type]->bwrite(f->nl->dc, allocfb(f), 0);
563421195e0SDavid du Colombier poperror();
56421abd8f2SDavid du Colombier return 0;
56521abd8f2SDavid du Colombier }
56621abd8f2SDavid du Colombier
56721abd8f2SDavid du Colombier static void
discover(int major,int minor)56821abd8f2SDavid du Colombier discover(int major, int minor)
56921abd8f2SDavid du Colombier {
57021abd8f2SDavid du Colombier Aoehdr *h;
57121abd8f2SDavid du Colombier Block *b;
57221abd8f2SDavid du Colombier Netlink *nl, *e;
57321abd8f2SDavid du Colombier
57421abd8f2SDavid du Colombier nl = netlinks.nl;
57521abd8f2SDavid du Colombier e = nl + nelem(netlinks.nl);
57621abd8f2SDavid du Colombier for(; nl < e; nl++){
57721abd8f2SDavid du Colombier if(nl->cc == nil)
57821abd8f2SDavid du Colombier continue;
57921abd8f2SDavid du Colombier b = allocb(ETHERMINTU);
58021abd8f2SDavid du Colombier if(waserror()){
58121abd8f2SDavid du Colombier freeb(b);
58221abd8f2SDavid du Colombier nexterror();
58321abd8f2SDavid du Colombier }
58421abd8f2SDavid du Colombier b->wp = b->rp + ETHERMINTU;
58521abd8f2SDavid du Colombier memset(b->rp, 0, ETHERMINTU);
58621abd8f2SDavid du Colombier h = (Aoehdr*)b->rp;
58721abd8f2SDavid du Colombier memset(h->dst, 0xff, sizeof h->dst);
58821abd8f2SDavid du Colombier memmove(h->src, nl->ea, sizeof h->src);
58921abd8f2SDavid du Colombier hnputs(h->type, Aoetype);
59021abd8f2SDavid du Colombier h->verflag = Aoever << 4;
59121abd8f2SDavid du Colombier hnputs(h->major, major);
59221abd8f2SDavid du Colombier h->minor = minor;
59321abd8f2SDavid du Colombier h->cmd = ACconfig;
59421abd8f2SDavid du Colombier poperror();
59599c72adcSDavid du Colombier /* send b down the queue */
59621abd8f2SDavid du Colombier devtab[nl->dc->type]->bwrite(nl->dc, b, 0);
59721abd8f2SDavid du Colombier }
59821abd8f2SDavid du Colombier }
59921abd8f2SDavid du Colombier
60021abd8f2SDavid du Colombier /*
60121abd8f2SDavid du Colombier * Check all frames on device and resend any frames that have been
60221abd8f2SDavid du Colombier * outstanding for 200% of the device round trip time average.
60321abd8f2SDavid du Colombier */
60421abd8f2SDavid du Colombier static void
aoesweepproc(void *)60599c72adcSDavid du Colombier aoesweepproc(void*)
60621abd8f2SDavid du Colombier {
60721abd8f2SDavid du Colombier ulong i, tx, timeout, nbc;
60821abd8f2SDavid du Colombier vlong starttick;
609bc8903feSDavid du Colombier enum { Nms = 100, Nbcms = 30*1000, }; /* magic */
61021abd8f2SDavid du Colombier uchar *ea;
61121abd8f2SDavid du Colombier Aoeata *a;
61221abd8f2SDavid du Colombier Aoedev *d;
61321abd8f2SDavid du Colombier Devlink *l;
61421abd8f2SDavid du Colombier Frame *f, *e;
61521abd8f2SDavid du Colombier
61621abd8f2SDavid du Colombier nbc = Nbcms/Nms;
61721abd8f2SDavid du Colombier loop:
61821abd8f2SDavid du Colombier if(nbc-- == 0){
619c675ee80SDavid du Colombier if(rediscover && !waserror()){
62021abd8f2SDavid du Colombier discover(0xffff, 0xff);
621c675ee80SDavid du Colombier poperror();
622c675ee80SDavid du Colombier }
62321abd8f2SDavid du Colombier nbc = Nbcms/Nms;
62421abd8f2SDavid du Colombier }
62599c72adcSDavid du Colombier starttick = MACHP(0)->ticks;
62621abd8f2SDavid du Colombier rlock(&devs);
62721abd8f2SDavid du Colombier for(d = devs.d; d; d = d->next){
62821abd8f2SDavid du Colombier if(!canqlock(d))
62921abd8f2SDavid du Colombier continue;
63021abd8f2SDavid du Colombier if(!UP(d)){
63121abd8f2SDavid du Colombier qunlock(d);
63221abd8f2SDavid du Colombier continue;
63321abd8f2SDavid du Colombier }
63421abd8f2SDavid du Colombier tx = 0;
63521abd8f2SDavid du Colombier f = d->frames;
63621abd8f2SDavid du Colombier e = f + d->nframes;
63721abd8f2SDavid du Colombier for (; f < e; f++){
63821abd8f2SDavid du Colombier if(f->tag == Tfree)
63921abd8f2SDavid du Colombier continue;
64021abd8f2SDavid du Colombier l = f->dl;
64121abd8f2SDavid du Colombier timeout = l->rttavg << 1;
64221abd8f2SDavid du Colombier i = tsince(f->tag);
64321abd8f2SDavid du Colombier if(i < timeout)
64421abd8f2SDavid du Colombier continue;
64521abd8f2SDavid du Colombier if(d->nout == d->maxout){
64621abd8f2SDavid du Colombier if(d->maxout > 1)
64721abd8f2SDavid du Colombier d->maxout--;
64899c72adcSDavid du Colombier d->lastwadj = MACHP(0)->ticks;
64921abd8f2SDavid du Colombier }
65021abd8f2SDavid du Colombier a = (Aoeata*)f->hdr;
65121abd8f2SDavid du Colombier if(a->scnt > Dbcnt / Aoesectsz &&
65221abd8f2SDavid du Colombier ++f->nl->lostjumbo > (d->nframes << 1)){
6530343ea0dSDavid du Colombier ea = f->dl->eatab[f->eaidx];
65421abd8f2SDavid du Colombier eventlog("%æ: jumbo failure on %s:%E; lba%lld\n",
65521abd8f2SDavid du Colombier d, f->nl->path, ea, f->lba);
65621abd8f2SDavid du Colombier d->maxbcnt = Dbcnt;
65721abd8f2SDavid du Colombier d->flag &= ~Djumbo;
65821abd8f2SDavid du Colombier }
65921abd8f2SDavid du Colombier resend(d, f);
66021abd8f2SDavid du Colombier if(tx++ == 0){
66121abd8f2SDavid du Colombier if((l->rttavg <<= 1) > Rtmax)
66221abd8f2SDavid du Colombier l->rttavg = Rtmax;
663552c49cfSDavid du Colombier eventlog("%æ: rtt %ldms\n", d, TK2MS(l->rttavg));
66421abd8f2SDavid du Colombier }
66521abd8f2SDavid du Colombier }
66621abd8f2SDavid du Colombier if(d->nout == d->maxout && d->maxout < d->nframes &&
667bc8903feSDavid du Colombier TK2MS(MACHP(0)->ticks - d->lastwadj) > 10*1000){ /* more magic */
66821abd8f2SDavid du Colombier d->maxout++;
66999c72adcSDavid du Colombier d->lastwadj = MACHP(0)->ticks;
67021abd8f2SDavid du Colombier }
67121abd8f2SDavid du Colombier qunlock(d);
67221abd8f2SDavid du Colombier }
67321abd8f2SDavid du Colombier runlock(&devs);
67499c72adcSDavid du Colombier i = Nms - TK2MS(MACHP(0)->ticks - starttick);
67521abd8f2SDavid du Colombier if(i > 0)
67621abd8f2SDavid du Colombier tsleep(&up->sleep, return0, 0, i);
67721abd8f2SDavid du Colombier goto loop;
67821abd8f2SDavid du Colombier }
67921abd8f2SDavid du Colombier
68021abd8f2SDavid du Colombier static int
68121abd8f2SDavid du Colombier fmtæ(Fmt *f)
68221abd8f2SDavid du Colombier {
683b8a11165SDavid du Colombier char buf[16];
68421abd8f2SDavid du Colombier Aoedev *d;
68521abd8f2SDavid du Colombier
68621abd8f2SDavid du Colombier d = va_arg(f->args, Aoedev*);
68721abd8f2SDavid du Colombier snprint(buf, sizeof buf, "aoe%d.%d", d->major, d->minor);
68821abd8f2SDavid du Colombier return fmtstrcpy(f, buf);
68921abd8f2SDavid du Colombier }
69021abd8f2SDavid du Colombier
69121abd8f2SDavid du Colombier static void netbind(char *path);
69221abd8f2SDavid du Colombier
69321abd8f2SDavid du Colombier static void
aoecfg(void)69421abd8f2SDavid du Colombier aoecfg(void)
69521abd8f2SDavid du Colombier {
69621abd8f2SDavid du Colombier int n, i;
69721abd8f2SDavid du Colombier char *p, *f[32], buf[24];
69821abd8f2SDavid du Colombier
69921abd8f2SDavid du Colombier if((p = getconf("aoeif")) == nil || (n = tokenize(p, f, nelem(f))) < 1)
70021abd8f2SDavid du Colombier return;
70121abd8f2SDavid du Colombier /* goo! */
70221abd8f2SDavid du Colombier for(i = 0; i < n; i++){
70321abd8f2SDavid du Colombier p = f[i];
70421abd8f2SDavid du Colombier if(strncmp(p, "ether", 5) == 0)
70521abd8f2SDavid du Colombier snprint(buf, sizeof buf, "#l%c/ether%c", p[5], p[5]);
70621abd8f2SDavid du Colombier else if(strncmp(p, "#l", 2) == 0)
70721abd8f2SDavid du Colombier snprint(buf, sizeof buf, "#l%c/ether%c", p[2], p[2]);
70821abd8f2SDavid du Colombier else
70921abd8f2SDavid du Colombier continue;
710c675ee80SDavid du Colombier if(!waserror()){
71121abd8f2SDavid du Colombier netbind(buf);
712c675ee80SDavid du Colombier poperror();
713c675ee80SDavid du Colombier }
71421abd8f2SDavid du Colombier }
71521abd8f2SDavid du Colombier }
71621abd8f2SDavid du Colombier
71721abd8f2SDavid du Colombier static void
aoeinit(void)71821abd8f2SDavid du Colombier aoeinit(void)
71921abd8f2SDavid du Colombier {
72021abd8f2SDavid du Colombier static int init;
72121abd8f2SDavid du Colombier static QLock l;
72221abd8f2SDavid du Colombier
72321abd8f2SDavid du Colombier if(!canqlock(&l))
72421abd8f2SDavid du Colombier return;
72599c72adcSDavid du Colombier if(init == 0){
72621abd8f2SDavid du Colombier fmtinstall(L'æ', fmtæ);
72721abd8f2SDavid du Colombier events.rp = events.wp = events.buf;
72899c72adcSDavid du Colombier kproc("aoesweep", aoesweepproc, nil);
72921abd8f2SDavid du Colombier aoecfg();
73099c72adcSDavid du Colombier init = 1;
73199c72adcSDavid du Colombier }
73221abd8f2SDavid du Colombier qunlock(&l);
73321abd8f2SDavid du Colombier }
73421abd8f2SDavid du Colombier
73521abd8f2SDavid du Colombier static Chan*
aoeattach(char * spec)73621abd8f2SDavid du Colombier aoeattach(char *spec)
73721abd8f2SDavid du Colombier {
73821abd8f2SDavid du Colombier Chan *c;
73921abd8f2SDavid du Colombier
74021abd8f2SDavid du Colombier if(*spec)
74121abd8f2SDavid du Colombier error(Enonexist);
74221abd8f2SDavid du Colombier aoeinit();
74321abd8f2SDavid du Colombier c = devattach(L'æ', spec);
74421abd8f2SDavid du Colombier mkqid(&c->qid, Qzero, 0, QTDIR);
74521abd8f2SDavid du Colombier return c;
74621abd8f2SDavid du Colombier }
74721abd8f2SDavid du Colombier
74821abd8f2SDavid du Colombier static Aoedev*
unit2dev(ulong unit)74921abd8f2SDavid du Colombier unit2dev(ulong unit)
75021abd8f2SDavid du Colombier {
75121abd8f2SDavid du Colombier int i;
75221abd8f2SDavid du Colombier Aoedev *d;
75321abd8f2SDavid du Colombier
75421abd8f2SDavid du Colombier rlock(&devs);
75521abd8f2SDavid du Colombier i = 0;
75621abd8f2SDavid du Colombier for(d = devs.d; d; d = d->next)
75721abd8f2SDavid du Colombier if(i++ == unit){
75821abd8f2SDavid du Colombier runlock(&devs);
75921abd8f2SDavid du Colombier return d;
76021abd8f2SDavid du Colombier }
76121abd8f2SDavid du Colombier runlock(&devs);
762567483c8SDavid du Colombier uprint("unit lookup failure: %lux pc %#p", unit, getcallerpc(&unit));
76321abd8f2SDavid du Colombier error(up->genbuf);
76421abd8f2SDavid du Colombier return nil;
76521abd8f2SDavid du Colombier }
76621abd8f2SDavid du Colombier
76721abd8f2SDavid du Colombier static int
unitgen(Chan * c,ulong type,Dir * dp)76821abd8f2SDavid du Colombier unitgen(Chan *c, ulong type, Dir *dp)
76921abd8f2SDavid du Colombier {
77021abd8f2SDavid du Colombier int perm, t;
77121abd8f2SDavid du Colombier ulong vers;
77221abd8f2SDavid du Colombier vlong size;
77321abd8f2SDavid du Colombier char *p;
77421abd8f2SDavid du Colombier Aoedev *d;
77521abd8f2SDavid du Colombier Qid q;
77621abd8f2SDavid du Colombier
77721abd8f2SDavid du Colombier d = unit2dev(UNIT(c->qid));
7780774058cSDavid du Colombier perm = 0644;
77921abd8f2SDavid du Colombier size = 0;
78021abd8f2SDavid du Colombier vers = d->vers;
78121abd8f2SDavid du Colombier t = QTFILE;
78221abd8f2SDavid du Colombier
78321abd8f2SDavid du Colombier switch(type){
78421abd8f2SDavid du Colombier default:
78521abd8f2SDavid du Colombier return -1;
78621abd8f2SDavid du Colombier case Qctl:
78721abd8f2SDavid du Colombier p = "ctl";
78821abd8f2SDavid du Colombier break;
78921abd8f2SDavid du Colombier case Qdata:
79021abd8f2SDavid du Colombier p = "data";
7910774058cSDavid du Colombier perm = 0640;
79221abd8f2SDavid du Colombier if(UP(d))
79321abd8f2SDavid du Colombier size = d->bsize;
79421abd8f2SDavid du Colombier break;
79521abd8f2SDavid du Colombier case Qconfig:
79621abd8f2SDavid du Colombier p = "config";
79721abd8f2SDavid du Colombier if(UP(d))
79821abd8f2SDavid du Colombier size = d->nconfig;
79921abd8f2SDavid du Colombier break;
80021abd8f2SDavid du Colombier case Qident:
80121abd8f2SDavid du Colombier p = "ident";
80221abd8f2SDavid du Colombier if(UP(d))
80321abd8f2SDavid du Colombier size = sizeof d->ident;
80421abd8f2SDavid du Colombier break;
80521abd8f2SDavid du Colombier case Qdevlinkdir:
80621abd8f2SDavid du Colombier p = "devlink";
80721abd8f2SDavid du Colombier t = QTDIR;
80821abd8f2SDavid du Colombier perm = 0555;
80921abd8f2SDavid du Colombier break;
81021abd8f2SDavid du Colombier }
81121abd8f2SDavid du Colombier mkqid(&q, QID(UNIT(c->qid), type), vers, t);
81221abd8f2SDavid du Colombier devdir(c, q, p, size, eve, perm, dp);
81321abd8f2SDavid du Colombier return 1;
81421abd8f2SDavid du Colombier }
81521abd8f2SDavid du Colombier
81621abd8f2SDavid du Colombier static int
topgen(Chan * c,ulong type,Dir * d)81721abd8f2SDavid du Colombier topgen(Chan *c, ulong type, Dir *d)
81821abd8f2SDavid du Colombier {
81921abd8f2SDavid du Colombier int perm;
82021abd8f2SDavid du Colombier vlong size;
82121abd8f2SDavid du Colombier char *p;
82221abd8f2SDavid du Colombier Qid q;
82321abd8f2SDavid du Colombier
82421abd8f2SDavid du Colombier perm = 0444;
82521abd8f2SDavid du Colombier size = 0;
82621abd8f2SDavid du Colombier switch(type){
82721abd8f2SDavid du Colombier default:
82821abd8f2SDavid du Colombier return -1;
82921abd8f2SDavid du Colombier case Qtopctl:
83021abd8f2SDavid du Colombier p = "ctl";
83121abd8f2SDavid du Colombier perm = 0644;
83221abd8f2SDavid du Colombier break;
83321abd8f2SDavid du Colombier case Qtoplog:
83421abd8f2SDavid du Colombier p = "log";
83521abd8f2SDavid du Colombier size = eventcount();
83621abd8f2SDavid du Colombier break;
83721abd8f2SDavid du Colombier }
83821abd8f2SDavid du Colombier mkqid(&q, type, 0, QTFILE);
83921abd8f2SDavid du Colombier devdir(c, q, p, size, eve, perm, d);
84021abd8f2SDavid du Colombier return 1;
84121abd8f2SDavid du Colombier }
84221abd8f2SDavid du Colombier
84321abd8f2SDavid du Colombier static int
aoegen(Chan * c,char *,Dirtab *,int,int s,Dir * dp)84421abd8f2SDavid du Colombier aoegen(Chan *c, char *, Dirtab *, int, int s, Dir *dp)
84521abd8f2SDavid du Colombier {
84621abd8f2SDavid du Colombier int i;
84721abd8f2SDavid du Colombier Aoedev *d;
84821abd8f2SDavid du Colombier Qid q;
84921abd8f2SDavid du Colombier
85021abd8f2SDavid du Colombier if(c->qid.path == 0){
85121abd8f2SDavid du Colombier switch(s){
85221abd8f2SDavid du Colombier case DEVDOTDOT:
85321abd8f2SDavid du Colombier q.path = 0;
85421abd8f2SDavid du Colombier q.type = QTDIR;
85521abd8f2SDavid du Colombier devdir(c, q, "#æ", 0, eve, 0555, dp);
85621abd8f2SDavid du Colombier break;
85721abd8f2SDavid du Colombier case 0:
85821abd8f2SDavid du Colombier q.path = Qtopdir;
85921abd8f2SDavid du Colombier q.type = QTDIR;
86021abd8f2SDavid du Colombier devdir(c, q, "aoe", 0, eve, 0555, dp);
86121abd8f2SDavid du Colombier break;
86221abd8f2SDavid du Colombier default:
86321abd8f2SDavid du Colombier return -1;
86421abd8f2SDavid du Colombier }
86521abd8f2SDavid du Colombier return 1;
86621abd8f2SDavid du Colombier }
86721abd8f2SDavid du Colombier
86821abd8f2SDavid du Colombier switch(TYPE(c->qid)){
86921abd8f2SDavid du Colombier default:
87021abd8f2SDavid du Colombier return -1;
87121abd8f2SDavid du Colombier case Qtopdir:
87221abd8f2SDavid du Colombier if(s == DEVDOTDOT){
87321abd8f2SDavid du Colombier mkqid(&q, Qzero, 0, QTDIR);
87421abd8f2SDavid du Colombier devdir(c, q, "aoe", 0, eve, 0555, dp);
87521abd8f2SDavid du Colombier return 1;
87621abd8f2SDavid du Colombier }
87721abd8f2SDavid du Colombier if(s < Qtopfiles)
87821abd8f2SDavid du Colombier return topgen(c, Qtopbase + s, dp);
87921abd8f2SDavid du Colombier s -= Qtopfiles;
88021abd8f2SDavid du Colombier if(s >= units.ref)
88121abd8f2SDavid du Colombier return -1;
88221abd8f2SDavid du Colombier mkqid(&q, QID(s, Qunitdir), 0, QTDIR);
88321abd8f2SDavid du Colombier d = unit2dev(s);
8842f205b96SDavid du Colombier assert(d != nil);
88521abd8f2SDavid du Colombier devdir(c, q, unitname(d), 0, eve, 0555, dp);
88621abd8f2SDavid du Colombier return 1;
88721abd8f2SDavid du Colombier case Qtopctl:
88821abd8f2SDavid du Colombier case Qtoplog:
88921abd8f2SDavid du Colombier return topgen(c, TYPE(c->qid), dp);
89021abd8f2SDavid du Colombier case Qunitdir:
89121abd8f2SDavid du Colombier if(s == DEVDOTDOT){
89221abd8f2SDavid du Colombier mkqid(&q, QID(0, Qtopdir), 0, QTDIR);
89321abd8f2SDavid du Colombier uprint("%uld", UNIT(c->qid));
89421abd8f2SDavid du Colombier devdir(c, q, up->genbuf, 0, eve, 0555, dp);
89521abd8f2SDavid du Colombier return 1;
89621abd8f2SDavid du Colombier }
89721abd8f2SDavid du Colombier return unitgen(c, Qunitbase+s, dp);
89821abd8f2SDavid du Colombier case Qctl:
89921abd8f2SDavid du Colombier case Qdata:
90021abd8f2SDavid du Colombier case Qconfig:
9011e18b896SDavid du Colombier case Qident:
90221abd8f2SDavid du Colombier return unitgen(c, TYPE(c->qid), dp);
90321abd8f2SDavid du Colombier case Qdevlinkdir:
90421abd8f2SDavid du Colombier i = UNIT(c->qid);
90521abd8f2SDavid du Colombier if(s == DEVDOTDOT){
90621abd8f2SDavid du Colombier mkqid(&q, QID(i, Qunitdir), 0, QTDIR);
90721abd8f2SDavid du Colombier devdir(c, q, "devlink", 0, eve, 0555, dp);
90821abd8f2SDavid du Colombier return 1;
90921abd8f2SDavid du Colombier }
91021abd8f2SDavid du Colombier if(i >= units.ref)
91121abd8f2SDavid du Colombier return -1;
91221abd8f2SDavid du Colombier d = unit2dev(i);
91321abd8f2SDavid du Colombier if(s >= d->ndl)
91421abd8f2SDavid du Colombier return -1;
91521abd8f2SDavid du Colombier uprint("%d", s);
91621abd8f2SDavid du Colombier mkqid(&q, Q3(s, i, Qdevlink), 0, QTFILE);
91721abd8f2SDavid du Colombier devdir(c, q, up->genbuf, 0, eve, 0755, dp);
91821abd8f2SDavid du Colombier return 1;
91921abd8f2SDavid du Colombier case Qdevlink:
92021abd8f2SDavid du Colombier uprint("%d", s);
92121abd8f2SDavid du Colombier mkqid(&q, Q3(s, UNIT(c->qid), Qdevlink), 0, QTFILE);
92221abd8f2SDavid du Colombier devdir(c, q, up->genbuf, 0, eve, 0755, dp);
92321abd8f2SDavid du Colombier return 1;
92421abd8f2SDavid du Colombier }
92521abd8f2SDavid du Colombier }
92621abd8f2SDavid du Colombier
92721abd8f2SDavid du Colombier static Walkqid*
aoewalk(Chan * c,Chan * nc,char ** name,int nname)92821abd8f2SDavid du Colombier aoewalk(Chan *c, Chan *nc, char **name, int nname)
92921abd8f2SDavid du Colombier {
93021abd8f2SDavid du Colombier return devwalk(c, nc, name, nname, nil, 0, aoegen);
93121abd8f2SDavid du Colombier }
93221abd8f2SDavid du Colombier
93321abd8f2SDavid du Colombier static int
aoestat(Chan * c,uchar * db,int n)93421abd8f2SDavid du Colombier aoestat(Chan *c, uchar *db, int n)
93521abd8f2SDavid du Colombier {
93621abd8f2SDavid du Colombier return devstat(c, db, n, nil, 0, aoegen);
93721abd8f2SDavid du Colombier }
93821abd8f2SDavid du Colombier
93921abd8f2SDavid du Colombier static Chan*
aoeopen(Chan * c,int omode)94021abd8f2SDavid du Colombier aoeopen(Chan *c, int omode)
94121abd8f2SDavid du Colombier {
94221abd8f2SDavid du Colombier Aoedev *d;
94321abd8f2SDavid du Colombier
94421abd8f2SDavid du Colombier if(TYPE(c->qid) != Qdata)
94521abd8f2SDavid du Colombier return devopen(c, omode, 0, 0, aoegen);
94621abd8f2SDavid du Colombier
94721abd8f2SDavid du Colombier d = unit2dev(UNIT(c->qid));
94821abd8f2SDavid du Colombier qlock(d);
94921abd8f2SDavid du Colombier if(waserror()){
95021abd8f2SDavid du Colombier qunlock(d);
95121abd8f2SDavid du Colombier nexterror();
95221abd8f2SDavid du Colombier }
95321abd8f2SDavid du Colombier if(!UP(d))
954a587111cSDavid du Colombier error(Eaoedown);
95521abd8f2SDavid du Colombier c = devopen(c, omode, 0, 0, aoegen);
95621abd8f2SDavid du Colombier d->nopen++;
95721abd8f2SDavid du Colombier poperror();
95821abd8f2SDavid du Colombier qunlock(d);
95921abd8f2SDavid du Colombier return c;
96021abd8f2SDavid du Colombier }
96121abd8f2SDavid du Colombier
96221abd8f2SDavid du Colombier static void
aoeclose(Chan * c)96321abd8f2SDavid du Colombier aoeclose(Chan *c)
96421abd8f2SDavid du Colombier {
96521abd8f2SDavid du Colombier Aoedev *d;
96621abd8f2SDavid du Colombier
96721abd8f2SDavid du Colombier if(TYPE(c->qid) != Qdata || (c->flag&COPEN) == 0)
96821abd8f2SDavid du Colombier return;
96921abd8f2SDavid du Colombier
97021abd8f2SDavid du Colombier d = unit2dev(UNIT(c->qid));
97121abd8f2SDavid du Colombier qlock(d);
97221abd8f2SDavid du Colombier if(--d->nopen == 0 && !waserror()){
97321abd8f2SDavid du Colombier discover(d->major, d->minor);
97421abd8f2SDavid du Colombier poperror();
97521abd8f2SDavid du Colombier }
97621abd8f2SDavid du Colombier qunlock(d);
97721abd8f2SDavid du Colombier }
97821abd8f2SDavid du Colombier
97921abd8f2SDavid du Colombier static void
atarw(Aoedev * d,Frame * f)98021abd8f2SDavid du Colombier atarw(Aoedev *d, Frame *f)
98121abd8f2SDavid du Colombier {
98221abd8f2SDavid du Colombier ulong bcnt;
98321abd8f2SDavid du Colombier char extbit, writebit;
98421abd8f2SDavid du Colombier Aoeata *ah;
98521abd8f2SDavid du Colombier Srb *srb;
98621abd8f2SDavid du Colombier
98721abd8f2SDavid du Colombier extbit = 0x4;
98821abd8f2SDavid du Colombier writebit = 0x10;
98921abd8f2SDavid du Colombier
99021abd8f2SDavid du Colombier srb = d->inprocess;
99121abd8f2SDavid du Colombier bcnt = d->maxbcnt;
99221abd8f2SDavid du Colombier if(bcnt > srb->len)
99321abd8f2SDavid du Colombier bcnt = srb->len;
99441ac1ab6SDavid du Colombier f->nhdr = AOEATASZ;
99521abd8f2SDavid du Colombier memset(f->hdr, 0, f->nhdr);
99621abd8f2SDavid du Colombier ah = (Aoeata*)f->hdr;
9972f205b96SDavid du Colombier if(hset(d, f, ah, ACata) == -1) {
9982f205b96SDavid du Colombier d->inprocess = nil;
99921abd8f2SDavid du Colombier return;
10002f205b96SDavid du Colombier }
100121abd8f2SDavid du Colombier f->dp = srb->dp;
100221abd8f2SDavid du Colombier f->bcnt = bcnt;
100321abd8f2SDavid du Colombier f->lba = srb->sector;
100421abd8f2SDavid du Colombier f->srb = srb;
100521abd8f2SDavid du Colombier
100621abd8f2SDavid du Colombier ah->scnt = bcnt / Aoesectsz;
100721abd8f2SDavid du Colombier putlba(ah, f->lba);
100821abd8f2SDavid du Colombier if(d->flag & Dllba)
100921abd8f2SDavid du Colombier ah->aflag |= AAFext;
101021abd8f2SDavid du Colombier else {
101121abd8f2SDavid du Colombier extbit = 0;
101221abd8f2SDavid du Colombier ah->lba[3] &= 0x0f;
101321abd8f2SDavid du Colombier ah->lba[3] |= 0xe0; /* LBA bit+obsolete 0xa0 */
101421abd8f2SDavid du Colombier }
101521abd8f2SDavid du Colombier if(srb->write){
101621abd8f2SDavid du Colombier ah->aflag |= AAFwrite;
1017c675ee80SDavid du Colombier f->dlen = bcnt;
101821abd8f2SDavid du Colombier }else{
101921abd8f2SDavid du Colombier writebit = 0;
1020c675ee80SDavid du Colombier f->dlen = 0;
102121abd8f2SDavid du Colombier }
102221abd8f2SDavid du Colombier ah->cmdstat = 0x20 | writebit | extbit;
102321abd8f2SDavid du Colombier
102421abd8f2SDavid du Colombier /* mark tracking fields and load out */
102521abd8f2SDavid du Colombier srb->nout++;
102621abd8f2SDavid du Colombier srb->dp = (uchar*)srb->dp + bcnt;
102721abd8f2SDavid du Colombier srb->len -= bcnt;
102821abd8f2SDavid du Colombier srb->sector += bcnt / Aoesectsz;
102921abd8f2SDavid du Colombier if(srb->len == 0)
103021abd8f2SDavid du Colombier d->inprocess = nil;
103121abd8f2SDavid du Colombier d->nout++;
103221abd8f2SDavid du Colombier f->dl->npkt++;
103321abd8f2SDavid du Colombier if(waserror()){
103421abd8f2SDavid du Colombier f->tag = Tfree;
103521abd8f2SDavid du Colombier d->inprocess = nil;
103621abd8f2SDavid du Colombier nexterror();
103721abd8f2SDavid du Colombier }
1038c675ee80SDavid du Colombier devtab[f->nl->dc->type]->bwrite(f->nl->dc, allocfb(f), 0);
103921abd8f2SDavid du Colombier poperror();
104021abd8f2SDavid du Colombier }
104121abd8f2SDavid du Colombier
104221abd8f2SDavid du Colombier static char*
aoeerror(Aoehdr * h)104321abd8f2SDavid du Colombier aoeerror(Aoehdr *h)
104421abd8f2SDavid du Colombier {
104521abd8f2SDavid du Colombier int n;
104621abd8f2SDavid du Colombier static char *errs[] = {
104721abd8f2SDavid du Colombier "aoe protocol error: unknown",
104821abd8f2SDavid du Colombier "aoe protocol error: bad command code",
104921abd8f2SDavid du Colombier "aoe protocol error: bad argument param",
105021abd8f2SDavid du Colombier "aoe protocol error: device unavailable",
105121abd8f2SDavid du Colombier "aoe protocol error: config string present",
105221abd8f2SDavid du Colombier "aoe protocol error: unsupported version",
10532f205b96SDavid du Colombier "aoe protocol error: target is reserved",
105421abd8f2SDavid du Colombier };
105521abd8f2SDavid du Colombier
105621abd8f2SDavid du Colombier if((h->verflag & AFerr) == 0)
105721abd8f2SDavid du Colombier return 0;
105821abd8f2SDavid du Colombier n = h->error;
105921abd8f2SDavid du Colombier if(n > nelem(errs))
106021abd8f2SDavid du Colombier n = 0;
106121abd8f2SDavid du Colombier return errs[n];
106221abd8f2SDavid du Colombier }
106321abd8f2SDavid du Colombier
106421abd8f2SDavid du Colombier static void
rtupdate(Devlink * l,int rtt)106521abd8f2SDavid du Colombier rtupdate(Devlink *l, int rtt)
106621abd8f2SDavid du Colombier {
106721abd8f2SDavid du Colombier int n;
106821abd8f2SDavid du Colombier
106921abd8f2SDavid du Colombier n = rtt;
107021abd8f2SDavid du Colombier if(rtt < 0){
107121abd8f2SDavid du Colombier n = -rtt;
107221abd8f2SDavid du Colombier if(n < Rtmin)
107321abd8f2SDavid du Colombier n = Rtmin;
107421abd8f2SDavid du Colombier else if(n > Rtmax)
107521abd8f2SDavid du Colombier n = Rtmax;
107621abd8f2SDavid du Colombier l->mintimer += (n - l->mintimer) >> 1;
107721abd8f2SDavid du Colombier } else if(n < l->mintimer)
107821abd8f2SDavid du Colombier n = l->mintimer;
107921abd8f2SDavid du Colombier else if(n > Rtmax)
108021abd8f2SDavid du Colombier n = Rtmax;
108121abd8f2SDavid du Colombier
108221abd8f2SDavid du Colombier /* g == .25; cf. Congestion Avoidance and Control, Jacobson&Karels; 1988 */
108321abd8f2SDavid du Colombier n -= l->rttavg;
108421abd8f2SDavid du Colombier l->rttavg += n >> 2;
108521abd8f2SDavid du Colombier }
108621abd8f2SDavid du Colombier
108721abd8f2SDavid du Colombier static int
srbready(void * v)108821abd8f2SDavid du Colombier srbready(void *v)
108921abd8f2SDavid du Colombier {
109021abd8f2SDavid du Colombier Srb *s;
109121abd8f2SDavid du Colombier
109221abd8f2SDavid du Colombier s = v;
1093*f7c114afSDavid du Colombier return s->error || (s->nout == 0 && s->len == 0);
109421abd8f2SDavid du Colombier }
109521abd8f2SDavid du Colombier
109621abd8f2SDavid du Colombier static Frame*
getframe(Aoedev * d,int tag)109721abd8f2SDavid du Colombier getframe(Aoedev *d, int tag)
109821abd8f2SDavid du Colombier {
109921abd8f2SDavid du Colombier Frame *f, *e;
110021abd8f2SDavid du Colombier
110121abd8f2SDavid du Colombier f = d->frames;
110221abd8f2SDavid du Colombier e = f + d->nframes;
110321abd8f2SDavid du Colombier for(; f < e; f++)
110421abd8f2SDavid du Colombier if(f->tag == tag)
110521abd8f2SDavid du Colombier return f;
110621abd8f2SDavid du Colombier return nil;
110721abd8f2SDavid du Colombier }
110821abd8f2SDavid du Colombier
110921abd8f2SDavid du Colombier static Frame*
freeframe(Aoedev * d)111021abd8f2SDavid du Colombier freeframe(Aoedev *d)
111121abd8f2SDavid du Colombier {
111221abd8f2SDavid du Colombier if(d->nout < d->maxout)
111321abd8f2SDavid du Colombier return getframe(d, Tfree);
111421abd8f2SDavid du Colombier return nil;
111521abd8f2SDavid du Colombier }
111621abd8f2SDavid du Colombier
111721abd8f2SDavid du Colombier static void
work(Aoedev * d)111821abd8f2SDavid du Colombier work(Aoedev *d)
111921abd8f2SDavid du Colombier {
112021abd8f2SDavid du Colombier Frame *f;
112121abd8f2SDavid du Colombier
112221abd8f2SDavid du Colombier while ((f = freeframe(d)) != nil) {
112321abd8f2SDavid du Colombier if(d->inprocess == nil){
112421abd8f2SDavid du Colombier if(d->head == nil)
112521abd8f2SDavid du Colombier return;
112621abd8f2SDavid du Colombier d->inprocess = d->head;
112721abd8f2SDavid du Colombier d->head = d->head->next;
112821abd8f2SDavid du Colombier if(d->head == nil)
112921abd8f2SDavid du Colombier d->tail = nil;
113021abd8f2SDavid du Colombier }
113121abd8f2SDavid du Colombier atarw(d, f);
113221abd8f2SDavid du Colombier }
113321abd8f2SDavid du Colombier }
113421abd8f2SDavid du Colombier
113521abd8f2SDavid du Colombier static void
strategy(Aoedev * d,Srb * srb)113621abd8f2SDavid du Colombier strategy(Aoedev *d, Srb *srb)
113721abd8f2SDavid du Colombier {
113821abd8f2SDavid du Colombier qlock(d);
113921abd8f2SDavid du Colombier if(waserror()){
114021abd8f2SDavid du Colombier qunlock(d);
114121abd8f2SDavid du Colombier nexterror();
114221abd8f2SDavid du Colombier }
114321abd8f2SDavid du Colombier srb->next = nil;
114421abd8f2SDavid du Colombier if(d->tail)
114521abd8f2SDavid du Colombier d->tail->next = srb;
114621abd8f2SDavid du Colombier d->tail = srb;
114721abd8f2SDavid du Colombier if(d->head == nil)
114821abd8f2SDavid du Colombier d->head = srb;
1149*f7c114afSDavid du Colombier srb->shared = 1;
115021abd8f2SDavid du Colombier work(d);
115121abd8f2SDavid du Colombier poperror();
115221abd8f2SDavid du Colombier qunlock(d);
115321abd8f2SDavid du Colombier
115421abd8f2SDavid du Colombier while(waserror())
115521abd8f2SDavid du Colombier ;
115621abd8f2SDavid du Colombier sleep(srb, srbready, srb);
115721abd8f2SDavid du Colombier poperror();
115821abd8f2SDavid du Colombier }
115921abd8f2SDavid du Colombier
116021abd8f2SDavid du Colombier #define iskaddr(a) ((uintptr)(a) > KZERO)
116121abd8f2SDavid du Colombier
116221abd8f2SDavid du Colombier static long
rw(Aoedev * d,int write,uchar * db,long len,uvlong off)116321abd8f2SDavid du Colombier rw(Aoedev *d, int write, uchar *db, long len, uvlong off)
116421abd8f2SDavid du Colombier {
116521abd8f2SDavid du Colombier long n, nlen, copy;
11662f205b96SDavid du Colombier enum { Srbsz = 1<<19, }; /* magic allocation */
116721abd8f2SDavid du Colombier Srb *srb;
116821abd8f2SDavid du Colombier
116921abd8f2SDavid du Colombier if((off|len) & (Aoesectsz-1))
117021abd8f2SDavid du Colombier error("offset and length must be sector multiple.\n");
11710774058cSDavid du Colombier if(off > d->bsize || len == 0)
117221abd8f2SDavid du Colombier return 0;
117321abd8f2SDavid du Colombier if(off + len > d->bsize)
117421abd8f2SDavid du Colombier len = d->bsize - off;
117521abd8f2SDavid du Colombier copy = 0;
117621abd8f2SDavid du Colombier if(iskaddr(db)){
117721abd8f2SDavid du Colombier srb = srbkalloc(db, len);
117821abd8f2SDavid du Colombier copy = 1;
117921abd8f2SDavid du Colombier }else
118021abd8f2SDavid du Colombier srb = srballoc(Srbsz <= len? Srbsz: len);
118121abd8f2SDavid du Colombier if(waserror()){
118221abd8f2SDavid du Colombier srbfree(srb);
118321abd8f2SDavid du Colombier nexterror();
118421abd8f2SDavid du Colombier }
118521abd8f2SDavid du Colombier nlen = len;
118621abd8f2SDavid du Colombier srb->write = write;
118799c72adcSDavid du Colombier do {
118821abd8f2SDavid du Colombier if(!UP(d))
118921abd8f2SDavid du Colombier error(Eio);
119021abd8f2SDavid du Colombier srb->sector = off / Aoesectsz;
119121abd8f2SDavid du Colombier srb->dp = srb->data;
119221abd8f2SDavid du Colombier n = nlen;
119321abd8f2SDavid du Colombier if(n > Srbsz)
119421abd8f2SDavid du Colombier n = Srbsz;
119521abd8f2SDavid du Colombier srb->len = n;
119699c72adcSDavid du Colombier if(write && !copy)
119721abd8f2SDavid du Colombier memmove(srb->data, db, n);
119821abd8f2SDavid du Colombier strategy(d, srb);
119921abd8f2SDavid du Colombier if(srb->error)
120021abd8f2SDavid du Colombier error(srb->error);
120199c72adcSDavid du Colombier if(!write && !copy)
120221abd8f2SDavid du Colombier memmove(db, srb->data, n);
120321abd8f2SDavid du Colombier nlen -= n;
120421abd8f2SDavid du Colombier db += n;
120521abd8f2SDavid du Colombier off += n;
120699c72adcSDavid du Colombier } while (nlen > 0);
120721abd8f2SDavid du Colombier poperror();
120821abd8f2SDavid du Colombier srbfree(srb);
120921abd8f2SDavid du Colombier return len;
121021abd8f2SDavid du Colombier }
121121abd8f2SDavid du Colombier
121221abd8f2SDavid du Colombier static long
readmem(ulong off,void * dst,long n,void * src,long size)121321abd8f2SDavid du Colombier readmem(ulong off, void *dst, long n, void *src, long size)
121421abd8f2SDavid du Colombier {
121521abd8f2SDavid du Colombier if(off >= size)
121621abd8f2SDavid du Colombier return 0;
121721abd8f2SDavid du Colombier if(off + n > size)
121821abd8f2SDavid du Colombier n = size - off;
121921abd8f2SDavid du Colombier memmove(dst, (uchar*)src + off, n);
122021abd8f2SDavid du Colombier return n;
122121abd8f2SDavid du Colombier }
122221abd8f2SDavid du Colombier
122321abd8f2SDavid du Colombier static char *
pflag(char * s,char * e,uchar f)122421abd8f2SDavid du Colombier pflag(char *s, char *e, uchar f)
122521abd8f2SDavid du Colombier {
1226060a30c6SDavid du Colombier uchar i;
122721abd8f2SDavid du Colombier
1228060a30c6SDavid du Colombier for(i = 0; i < 8; i++)
1229060a30c6SDavid du Colombier if(f & (1 << i))
123021abd8f2SDavid du Colombier s = seprint(s, e, "%s ", flagname[i]? flagname[i]: "oops");
123121abd8f2SDavid du Colombier return seprint(s, e, "\n");
123221abd8f2SDavid du Colombier }
123321abd8f2SDavid du Colombier
123421abd8f2SDavid du Colombier static int
pstat(Aoedev * d,char * db,int len,int off)123521abd8f2SDavid du Colombier pstat(Aoedev *d, char *db, int len, int off)
123621abd8f2SDavid du Colombier {
123721abd8f2SDavid du Colombier int i;
123821abd8f2SDavid du Colombier char *state, *s, *p, *e;
123921abd8f2SDavid du Colombier
1240c9b6d007SDavid du Colombier s = p = malloc(READSTR);
1241aa72973aSDavid du Colombier if(s == nil)
1242aa72973aSDavid du Colombier error(Enomem);
1243c9b6d007SDavid du Colombier e = p + READSTR;
124421abd8f2SDavid du Colombier
124521abd8f2SDavid du Colombier state = "down";
124621abd8f2SDavid du Colombier if(UP(d))
124721abd8f2SDavid du Colombier state = "up";
124821abd8f2SDavid du Colombier
124921abd8f2SDavid du Colombier p = seprint(p, e,
125021abd8f2SDavid du Colombier "state: %s\n" "nopen: %d\n" "nout: %d\n"
125121abd8f2SDavid du Colombier "nmaxout: %d\n" "nframes: %d\n" "maxbcnt: %d\n"
12520774058cSDavid du Colombier "fw: %.4ux\n"
125321abd8f2SDavid du Colombier "model: %s\n" "serial: %s\n" "firmware: %s\n",
125421abd8f2SDavid du Colombier state, d->nopen, d->nout,
125521abd8f2SDavid du Colombier d->maxout, d->nframes, d->maxbcnt,
125621abd8f2SDavid du Colombier d->fwver,
125721abd8f2SDavid du Colombier d->model, d->serial, d->firmware);
125821abd8f2SDavid du Colombier p = seprint(p, e, "flag: ");
125921abd8f2SDavid du Colombier p = pflag(p, e, d->flag);
126021abd8f2SDavid du Colombier
126121abd8f2SDavid du Colombier if(p - s < len)
126221abd8f2SDavid du Colombier len = p - s;
126321abd8f2SDavid du Colombier i = readstr(off, db, len, s);
126421abd8f2SDavid du Colombier free(s);
126521abd8f2SDavid du Colombier return i;
126621abd8f2SDavid du Colombier }
126721abd8f2SDavid du Colombier
126821abd8f2SDavid du Colombier static long
unitread(Chan * c,void * db,long len,vlong off)126921abd8f2SDavid du Colombier unitread(Chan *c, void *db, long len, vlong off)
127021abd8f2SDavid du Colombier {
127121abd8f2SDavid du Colombier Aoedev *d;
127221abd8f2SDavid du Colombier
127321abd8f2SDavid du Colombier d = unit2dev(UNIT(c->qid));
127421abd8f2SDavid du Colombier if(d->vers != c->qid.vers)
127521abd8f2SDavid du Colombier error(Echange);
127621abd8f2SDavid du Colombier switch(TYPE(c->qid)){
127721abd8f2SDavid du Colombier default:
127821abd8f2SDavid du Colombier error(Ebadarg);
127921abd8f2SDavid du Colombier case Qctl:
128021abd8f2SDavid du Colombier return pstat(d, db, len, off);
128121abd8f2SDavid du Colombier case Qdata:
128299c72adcSDavid du Colombier return rw(d, Read, db, len, off);
128321abd8f2SDavid du Colombier case Qconfig:
128421abd8f2SDavid du Colombier if (!UP(d))
1285a587111cSDavid du Colombier error(Eaoedown);
128621abd8f2SDavid du Colombier return readmem(off, db, len, d->config, d->nconfig);
128721abd8f2SDavid du Colombier case Qident:
128821abd8f2SDavid du Colombier if (!UP(d))
1289a587111cSDavid du Colombier error(Eaoedown);
129021abd8f2SDavid du Colombier return readmem(off, db, len, d->ident, sizeof d->ident);
129121abd8f2SDavid du Colombier }
129221abd8f2SDavid du Colombier }
129321abd8f2SDavid du Colombier
129421abd8f2SDavid du Colombier static int
devlinkread(Chan * c,void * db,int len,int off)129521abd8f2SDavid du Colombier devlinkread(Chan *c, void *db, int len, int off)
129621abd8f2SDavid du Colombier {
129721abd8f2SDavid du Colombier int i;
129821abd8f2SDavid du Colombier char *s, *p, *e;
129921abd8f2SDavid du Colombier Aoedev *d;
130021abd8f2SDavid du Colombier Devlink *l;
130121abd8f2SDavid du Colombier
130221abd8f2SDavid du Colombier d = unit2dev(UNIT(c->qid));
130321abd8f2SDavid du Colombier i = L(c->qid);
130421abd8f2SDavid du Colombier if(i >= d->ndl)
130521abd8f2SDavid du Colombier return 0;
130621abd8f2SDavid du Colombier l = d->dl + i;
130721abd8f2SDavid du Colombier
1308c9b6d007SDavid du Colombier s = p = malloc(READSTR);
1309aa72973aSDavid du Colombier if(s == nil)
1310aa72973aSDavid du Colombier error(Enomem);
1311c9b6d007SDavid du Colombier e = s + READSTR;
131221abd8f2SDavid du Colombier
131321abd8f2SDavid du Colombier p = seprint(p, e, "addr: ");
131421abd8f2SDavid du Colombier for(i = 0; i < l->nea; i++)
131521abd8f2SDavid du Colombier p = seprint(p, e, "%E ", l->eatab[i]);
131621abd8f2SDavid du Colombier p = seprint(p, e, "\n");
131721abd8f2SDavid du Colombier p = seprint(p, e, "npkt: %uld\n", l->npkt);
131821abd8f2SDavid du Colombier p = seprint(p, e, "resent: %uld\n", l->resent);
131921abd8f2SDavid du Colombier p = seprint(p, e, "flag: "); p = pflag(p, e, l->flag);
1320552c49cfSDavid du Colombier p = seprint(p, e, "rttavg: %uld\n", TK2MS(l->rttavg));
1321552c49cfSDavid du Colombier p = seprint(p, e, "mintimer: %uld\n", TK2MS(l->mintimer));
132221abd8f2SDavid du Colombier
132321abd8f2SDavid du Colombier p = seprint(p, e, "nl path: %s\n", l->nl->path);
132421abd8f2SDavid du Colombier p = seprint(p, e, "nl ea: %E\n", l->nl->ea);
132521abd8f2SDavid du Colombier p = seprint(p, e, "nl flag: "); p = pflag(p, e, l->flag);
132621abd8f2SDavid du Colombier p = seprint(p, e, "nl lostjumbo: %d\n", l->nl->lostjumbo);
132721abd8f2SDavid du Colombier p = seprint(p, e, "nl datamtu: %d\n", l->nl->datamtu);
132821abd8f2SDavid du Colombier
132921abd8f2SDavid du Colombier if(p - s < len)
133021abd8f2SDavid du Colombier len = p - s;
133121abd8f2SDavid du Colombier i = readstr(off, db, len, s);
133221abd8f2SDavid du Colombier free(s);
133321abd8f2SDavid du Colombier return i;
133421abd8f2SDavid du Colombier }
133521abd8f2SDavid du Colombier
133621abd8f2SDavid du Colombier static long
topctlread(Chan *,void * db,int len,int off)133721abd8f2SDavid du Colombier topctlread(Chan *, void *db, int len, int off)
133821abd8f2SDavid du Colombier {
133921abd8f2SDavid du Colombier int i;
134021abd8f2SDavid du Colombier char *s, *p, *e;
134121abd8f2SDavid du Colombier Netlink *n;
134221abd8f2SDavid du Colombier
1343c9b6d007SDavid du Colombier s = p = malloc(READSTR);
1344aa72973aSDavid du Colombier if(s == nil)
1345aa72973aSDavid du Colombier error(Enomem);
1346c9b6d007SDavid du Colombier e = s + READSTR;
134721abd8f2SDavid du Colombier
134821abd8f2SDavid du Colombier p = seprint(p, e, "debug: %d\n", debug);
134921abd8f2SDavid du Colombier p = seprint(p, e, "autodiscover: %d\n", autodiscover);
135021abd8f2SDavid du Colombier p = seprint(p, e, "rediscover: %d\n", rediscover);
135121abd8f2SDavid du Colombier
135221abd8f2SDavid du Colombier for(i = 0; i < Nnetlink; i++){
135321abd8f2SDavid du Colombier n = netlinks.nl+i;
135421abd8f2SDavid du Colombier if(n->cc == 0)
135521abd8f2SDavid du Colombier continue;
135621abd8f2SDavid du Colombier p = seprint(p, e, "if%d path: %s\n", i, n->path);
135721abd8f2SDavid du Colombier p = seprint(p, e, "if%d ea: %E\n", i, n->ea);
135821abd8f2SDavid du Colombier p = seprint(p, e, "if%d flag: ", i); p = pflag(p, e, n->flag);
13590343ea0dSDavid du Colombier p = seprint(p, e, "if%d lostjumbo: %d\n", i, n->lostjumbo);
13600343ea0dSDavid du Colombier p = seprint(p, e, "if%d datamtu: %d\n", i, n->datamtu);
136121abd8f2SDavid du Colombier }
136221abd8f2SDavid du Colombier
136321abd8f2SDavid du Colombier if(p - s < len)
136421abd8f2SDavid du Colombier len = p - s;
136521abd8f2SDavid du Colombier i = readstr(off, db, len, s);
136621abd8f2SDavid du Colombier free(s);
136721abd8f2SDavid du Colombier return i;
136821abd8f2SDavid du Colombier }
136921abd8f2SDavid du Colombier
137021abd8f2SDavid du Colombier static long
aoeread(Chan * c,void * db,long n,vlong off)137121abd8f2SDavid du Colombier aoeread(Chan *c, void *db, long n, vlong off)
137221abd8f2SDavid du Colombier {
137321abd8f2SDavid du Colombier switch(TYPE(c->qid)){
137421abd8f2SDavid du Colombier default:
137521abd8f2SDavid du Colombier error(Eperm);
137621abd8f2SDavid du Colombier case Qzero:
137721abd8f2SDavid du Colombier case Qtopdir:
137821abd8f2SDavid du Colombier case Qunitdir:
137921abd8f2SDavid du Colombier case Qdevlinkdir:
138021abd8f2SDavid du Colombier return devdirread(c, db, n, 0, 0, aoegen);
138121abd8f2SDavid du Colombier case Qtopctl:
138221abd8f2SDavid du Colombier return topctlread(c, db, n, off);
138321abd8f2SDavid du Colombier case Qtoplog:
138421abd8f2SDavid du Colombier return eventlogread(db, n);
138521abd8f2SDavid du Colombier case Qctl:
138621abd8f2SDavid du Colombier case Qdata:
138721abd8f2SDavid du Colombier case Qconfig:
138821abd8f2SDavid du Colombier case Qident:
138921abd8f2SDavid du Colombier return unitread(c, db, n, off);
139021abd8f2SDavid du Colombier case Qdevlink:
139121abd8f2SDavid du Colombier return devlinkread(c, db, n, off);
139221abd8f2SDavid du Colombier }
139321abd8f2SDavid du Colombier }
139421abd8f2SDavid du Colombier
139521abd8f2SDavid du Colombier static long
configwrite(Aoedev * d,void * db,long len)139621abd8f2SDavid du Colombier configwrite(Aoedev *d, void *db, long len)
139721abd8f2SDavid du Colombier {
139821abd8f2SDavid du Colombier char *s;
139921abd8f2SDavid du Colombier Aoeqc *ch;
140021abd8f2SDavid du Colombier Frame *f;
140121abd8f2SDavid du Colombier Srb *srb;
140221abd8f2SDavid du Colombier
140321abd8f2SDavid du Colombier if(!UP(d))
1404a587111cSDavid du Colombier error(Eaoedown);
140541ac1ab6SDavid du Colombier if(len > ETHERMAXTU - AOEQCSZ)
140621abd8f2SDavid du Colombier error(Etoobig);
140721abd8f2SDavid du Colombier srb = srballoc(len);
140821abd8f2SDavid du Colombier s = malloc(len);
1409aa72973aSDavid du Colombier if(s == nil)
1410aa72973aSDavid du Colombier error(Enomem);
141121abd8f2SDavid du Colombier memmove(s, db, len);
1412*f7c114afSDavid du Colombier
141321abd8f2SDavid du Colombier if(waserror()){
141421abd8f2SDavid du Colombier srbfree(srb);
141521abd8f2SDavid du Colombier free(s);
141621abd8f2SDavid du Colombier nexterror();
141721abd8f2SDavid du Colombier }
141821abd8f2SDavid du Colombier for (;;) {
141921abd8f2SDavid du Colombier qlock(d);
14200343ea0dSDavid du Colombier if(waserror()){
14210343ea0dSDavid du Colombier qunlock(d);
14220343ea0dSDavid du Colombier nexterror();
14230343ea0dSDavid du Colombier }
142421abd8f2SDavid du Colombier f = freeframe(d);
142521abd8f2SDavid du Colombier if(f != nil)
142621abd8f2SDavid du Colombier break;
14270343ea0dSDavid du Colombier poperror();
142821abd8f2SDavid du Colombier qunlock(d);
1429*f7c114afSDavid du Colombier
1430c675ee80SDavid du Colombier if(waserror())
1431c675ee80SDavid du Colombier nexterror();
143221abd8f2SDavid du Colombier tsleep(&up->sleep, return0, 0, 100);
1433c675ee80SDavid du Colombier poperror();
143421abd8f2SDavid du Colombier }
143541ac1ab6SDavid du Colombier f->nhdr = AOEQCSZ;
143621abd8f2SDavid du Colombier memset(f->hdr, 0, f->nhdr);
143721abd8f2SDavid du Colombier ch = (Aoeqc*)f->hdr;
1438*f7c114afSDavid du Colombier if(hset(d, f, ch, ACconfig) == -1) {
1439*f7c114afSDavid du Colombier /*
1440*f7c114afSDavid du Colombier * these refer to qlock & waserror in the above for loop.
1441*f7c114afSDavid du Colombier * there's still the first waserror outstanding.
1442*f7c114afSDavid du Colombier */
1443*f7c114afSDavid du Colombier poperror();
1444*f7c114afSDavid du Colombier qunlock(d);
144521abd8f2SDavid du Colombier return 0;
1446*f7c114afSDavid du Colombier }
1447*f7c114afSDavid du Colombier srb->shared = 1;
144821abd8f2SDavid du Colombier f->srb = srb;
144921abd8f2SDavid du Colombier f->dp = s;
145021abd8f2SDavid du Colombier ch->verccmd = AQCfset;
145121abd8f2SDavid du Colombier hnputs(ch->cslen, len);
145221abd8f2SDavid du Colombier d->nout++;
145321abd8f2SDavid du Colombier srb->nout++;
145421abd8f2SDavid du Colombier f->dl->npkt++;
1455c675ee80SDavid du Colombier f->dlen = len;
1456*f7c114afSDavid du Colombier /* these too */
145721abd8f2SDavid du Colombier poperror();
145821abd8f2SDavid du Colombier qunlock(d);
145921abd8f2SDavid du Colombier
1460c675ee80SDavid du Colombier devtab[f->nl->dc->type]->bwrite(f->nl->dc, allocfb(f), 0);
146121abd8f2SDavid du Colombier sleep(srb, srbready, srb);
146221abd8f2SDavid du Colombier if(srb->error)
146321abd8f2SDavid du Colombier error(srb->error);
146421abd8f2SDavid du Colombier
146521abd8f2SDavid du Colombier qlock(d);
146621abd8f2SDavid du Colombier if(waserror()){
146721abd8f2SDavid du Colombier qunlock(d);
146821abd8f2SDavid du Colombier nexterror();
146921abd8f2SDavid du Colombier }
147021abd8f2SDavid du Colombier memmove(d->config, s, len);
147121abd8f2SDavid du Colombier d->nconfig = len;
147221abd8f2SDavid du Colombier poperror();
147321abd8f2SDavid du Colombier qunlock(d);
147421abd8f2SDavid du Colombier
147521abd8f2SDavid du Colombier poperror(); /* pop first waserror */
147621abd8f2SDavid du Colombier
147721abd8f2SDavid du Colombier srbfree(srb);
147821abd8f2SDavid du Colombier memmove(db, s, len);
147921abd8f2SDavid du Colombier free(s);
148021abd8f2SDavid du Colombier return len;
148121abd8f2SDavid du Colombier }
148221abd8f2SDavid du Colombier
148321abd8f2SDavid du Colombier static int getmtu(Chan*);
148421abd8f2SDavid du Colombier
148521abd8f2SDavid du Colombier static int
devmaxdata(Aoedev * d)1486060a30c6SDavid du Colombier devmaxdata(Aoedev *d) /* return aoe mtu (excluding headers) */
148721abd8f2SDavid du Colombier {
1488060a30c6SDavid du Colombier int i, nmtu, mtu;
148921abd8f2SDavid du Colombier Devlink *l;
149021abd8f2SDavid du Colombier Netlink *n;
149121abd8f2SDavid du Colombier
149221abd8f2SDavid du Colombier mtu = 100000;
149321abd8f2SDavid du Colombier for(i = 0; i < d->ndl; i++){
149421abd8f2SDavid du Colombier l = d->dl + i;
149521abd8f2SDavid du Colombier n = l->nl;
149621abd8f2SDavid du Colombier if((l->flag & Dup) == 0 || (n->flag & Dup) == 0)
149721abd8f2SDavid du Colombier continue;
1498060a30c6SDavid du Colombier nmtu = getmtu(n->mtu);
1499060a30c6SDavid du Colombier if(mtu > nmtu)
1500060a30c6SDavid du Colombier mtu = nmtu;
150121abd8f2SDavid du Colombier }
150221abd8f2SDavid du Colombier if(mtu == 100000)
1503060a30c6SDavid du Colombier mtu = ETHERMAXTU; /* normal ethernet mtu */
150441ac1ab6SDavid du Colombier mtu -= AOEATASZ;
1505060a30c6SDavid du Colombier mtu -= (uint)mtu % Aoesectsz;
1506060a30c6SDavid du Colombier if(mtu < 2*Aoesectsz) /* sanity */
1507060a30c6SDavid du Colombier mtu = 2*Aoesectsz;
150821abd8f2SDavid du Colombier return mtu;
150921abd8f2SDavid du Colombier }
151021abd8f2SDavid du Colombier
151121abd8f2SDavid du Colombier static int
toggle(char * s,int f,int bit)1512060a30c6SDavid du Colombier toggle(char *s, int f, int bit)
151321abd8f2SDavid du Colombier {
151421abd8f2SDavid du Colombier if(s == nil)
1515060a30c6SDavid du Colombier f ^= bit;
1516060a30c6SDavid du Colombier else if(strcmp(s, "on") == 0)
1517060a30c6SDavid du Colombier f |= bit;
1518060a30c6SDavid du Colombier else
1519060a30c6SDavid du Colombier f &= ~bit;
1520060a30c6SDavid du Colombier return f;
152121abd8f2SDavid du Colombier }
152221abd8f2SDavid du Colombier
152321abd8f2SDavid du Colombier static void ataident(Aoedev*);
152421abd8f2SDavid du Colombier
152521abd8f2SDavid du Colombier static long
unitctlwrite(Aoedev * d,void * db,long n)152621abd8f2SDavid du Colombier unitctlwrite(Aoedev *d, void *db, long n)
152721abd8f2SDavid du Colombier {
1528060a30c6SDavid du Colombier uint maxbcnt, mtu;
152921abd8f2SDavid du Colombier uvlong bsize;
153021abd8f2SDavid du Colombier enum {
153121abd8f2SDavid du Colombier Failio,
153221abd8f2SDavid du Colombier Ident,
153321abd8f2SDavid du Colombier Jumbo,
153421abd8f2SDavid du Colombier Maxbno,
153521abd8f2SDavid du Colombier Mtu,
15362f205b96SDavid du Colombier Nofailf,
153721abd8f2SDavid du Colombier Setsize,
153821abd8f2SDavid du Colombier };
153921abd8f2SDavid du Colombier Cmdbuf *cb;
154099c72adcSDavid du Colombier Cmdtab *ct;
154199c72adcSDavid du Colombier static Cmdtab cmds[] = {
154221abd8f2SDavid du Colombier {Failio, "failio", 1 },
154321abd8f2SDavid du Colombier {Ident, "identify", 1 },
154421abd8f2SDavid du Colombier {Jumbo, "jumbo", 0 },
154521abd8f2SDavid du Colombier {Maxbno, "maxbno", 0 },
154621abd8f2SDavid du Colombier {Mtu, "mtu", 0 },
15472f205b96SDavid du Colombier {Nofailf, "nofail", 0 },
154821abd8f2SDavid du Colombier {Setsize, "setsize", 0 },
154921abd8f2SDavid du Colombier };
155021abd8f2SDavid du Colombier
155121abd8f2SDavid du Colombier cb = parsecmd(db, n);
155221abd8f2SDavid du Colombier qlock(d);
155321abd8f2SDavid du Colombier if(waserror()){
155421abd8f2SDavid du Colombier qunlock(d);
155521abd8f2SDavid du Colombier free(cb);
155621abd8f2SDavid du Colombier nexterror();
155721abd8f2SDavid du Colombier }
155821abd8f2SDavid du Colombier ct = lookupcmd(cb, cmds, nelem(cmds));
155921abd8f2SDavid du Colombier switch(ct->index){
156021abd8f2SDavid du Colombier case Failio:
156121abd8f2SDavid du Colombier downdev(d, "i/o failure");
156221abd8f2SDavid du Colombier break;
156321abd8f2SDavid du Colombier case Ident:
156421abd8f2SDavid du Colombier ataident(d);
156521abd8f2SDavid du Colombier break;
156621abd8f2SDavid du Colombier case Jumbo:
1567060a30c6SDavid du Colombier d->flag = toggle(cb->f[1], d->flag, Djumbo);
156821abd8f2SDavid du Colombier break;
156921abd8f2SDavid du Colombier case Maxbno:
157021abd8f2SDavid du Colombier case Mtu:
157121abd8f2SDavid du Colombier maxbcnt = devmaxdata(d);
157221abd8f2SDavid du Colombier if(cb->nf > 2)
157321abd8f2SDavid du Colombier error(Ecmdargs);
157421abd8f2SDavid du Colombier if(cb->nf == 2){
1575060a30c6SDavid du Colombier mtu = strtoul(cb->f[1], 0, 0);
157621abd8f2SDavid du Colombier if(ct->index == Maxbno)
1577060a30c6SDavid du Colombier mtu *= Aoesectsz;
157821abd8f2SDavid du Colombier else{
1579060a30c6SDavid du Colombier mtu -= AOEATASZ;
1580060a30c6SDavid du Colombier mtu &= ~(Aoesectsz-1);
158121abd8f2SDavid du Colombier }
1582060a30c6SDavid du Colombier if(mtu == 0 || mtu > maxbcnt)
15832f205b96SDavid du Colombier cmderror(cb, "mtu out of legal range");
1584060a30c6SDavid du Colombier maxbcnt = mtu;
158521abd8f2SDavid du Colombier }
158621abd8f2SDavid du Colombier d->maxbcnt = maxbcnt;
158721abd8f2SDavid du Colombier break;
15882f205b96SDavid du Colombier case Nofailf:
1589060a30c6SDavid du Colombier d->flag = toggle(cb->f[1], d->flag, Dnofail);
15902f205b96SDavid du Colombier break;
159121abd8f2SDavid du Colombier case Setsize:
159221abd8f2SDavid du Colombier bsize = d->realbsize;
159321abd8f2SDavid du Colombier if(cb->nf > 2)
159421abd8f2SDavid du Colombier error(Ecmdargs);
159521abd8f2SDavid du Colombier if(cb->nf == 2){
159621abd8f2SDavid du Colombier bsize = strtoull(cb->f[1], 0, 0);
159721abd8f2SDavid du Colombier if(bsize % Aoesectsz)
159821abd8f2SDavid du Colombier cmderror(cb, "disk size must be sector aligned");
159921abd8f2SDavid du Colombier }
160021abd8f2SDavid du Colombier d->bsize = bsize;
160121abd8f2SDavid du Colombier break;
160221abd8f2SDavid du Colombier default:
160321abd8f2SDavid du Colombier cmderror(cb, "unknown aoe control message");
160421abd8f2SDavid du Colombier }
160521abd8f2SDavid du Colombier poperror();
160621abd8f2SDavid du Colombier qunlock(d);
160721abd8f2SDavid du Colombier free(cb);
160821abd8f2SDavid du Colombier return n;
160921abd8f2SDavid du Colombier }
161021abd8f2SDavid du Colombier
161121abd8f2SDavid du Colombier static long
unitwrite(Chan * c,void * db,long n,vlong off)161221abd8f2SDavid du Colombier unitwrite(Chan *c, void *db, long n, vlong off)
161321abd8f2SDavid du Colombier {
161421abd8f2SDavid du Colombier long rv;
161521abd8f2SDavid du Colombier char *buf;
161621abd8f2SDavid du Colombier Aoedev *d;
161721abd8f2SDavid du Colombier
161821abd8f2SDavid du Colombier d = unit2dev(UNIT(c->qid));
161921abd8f2SDavid du Colombier switch(TYPE(c->qid)){
162021abd8f2SDavid du Colombier default:
162121abd8f2SDavid du Colombier error(Ebadarg);
162221abd8f2SDavid du Colombier case Qctl:
162321abd8f2SDavid du Colombier return unitctlwrite(d, db, n);
162421abd8f2SDavid du Colombier case Qident:
162521abd8f2SDavid du Colombier error(Eperm);
162621abd8f2SDavid du Colombier case Qdata:
162799c72adcSDavid du Colombier return rw(d, Write, db, n, off);
162821abd8f2SDavid du Colombier case Qconfig:
162921abd8f2SDavid du Colombier if(off + n > sizeof d->config)
163021abd8f2SDavid du Colombier error(Etoobig);
163121abd8f2SDavid du Colombier buf = malloc(sizeof d->config);
1632aa72973aSDavid du Colombier if(buf == nil)
1633aa72973aSDavid du Colombier error(Enomem);
16342f205b96SDavid du Colombier if(waserror()){
16352f205b96SDavid du Colombier free(buf);
16362f205b96SDavid du Colombier nexterror();
16372f205b96SDavid du Colombier }
163821abd8f2SDavid du Colombier memmove(buf, d->config, d->nconfig);
163921abd8f2SDavid du Colombier memmove(buf + off, db, n);
164021abd8f2SDavid du Colombier rv = configwrite(d, buf, n + off);
16412f205b96SDavid du Colombier poperror();
164221abd8f2SDavid du Colombier free(buf);
164321abd8f2SDavid du Colombier return rv;
164421abd8f2SDavid du Colombier }
164521abd8f2SDavid du Colombier }
164621abd8f2SDavid du Colombier
164721abd8f2SDavid du Colombier static Netlink*
addnet(char * path,Chan * cc,Chan * dc,Chan * mtu,uchar * ea)164821abd8f2SDavid du Colombier addnet(char *path, Chan *cc, Chan *dc, Chan *mtu, uchar *ea)
164921abd8f2SDavid du Colombier {
165021abd8f2SDavid du Colombier Netlink *nl, *e;
165121abd8f2SDavid du Colombier
165221abd8f2SDavid du Colombier lock(&netlinks);
165321abd8f2SDavid du Colombier if(waserror()){
165421abd8f2SDavid du Colombier unlock(&netlinks);
165521abd8f2SDavid du Colombier nexterror();
165621abd8f2SDavid du Colombier }
165721abd8f2SDavid du Colombier nl = netlinks.nl;
165821abd8f2SDavid du Colombier e = nl + nelem(netlinks.nl);
165999c72adcSDavid du Colombier for(; nl < e && nl->cc; nl++)
166021abd8f2SDavid du Colombier continue;
166199c72adcSDavid du Colombier if (nl >= e)
166299c72adcSDavid du Colombier error("out of netlink structures");
166321abd8f2SDavid du Colombier nl->cc = cc;
166421abd8f2SDavid du Colombier nl->dc = dc;
166521abd8f2SDavid du Colombier nl->mtu = mtu;
166621abd8f2SDavid du Colombier strncpy(nl->path, path, sizeof nl->path);
166721abd8f2SDavid du Colombier memmove(nl->ea, ea, sizeof nl->ea);
166821abd8f2SDavid du Colombier poperror();
166921abd8f2SDavid du Colombier nl->flag |= Dup;
167021abd8f2SDavid du Colombier unlock(&netlinks);
167121abd8f2SDavid du Colombier return nl;
167221abd8f2SDavid du Colombier }
167321abd8f2SDavid du Colombier
167421abd8f2SDavid du Colombier static int
newunit(void)167521abd8f2SDavid du Colombier newunit(void)
167621abd8f2SDavid du Colombier {
167721abd8f2SDavid du Colombier int x;
167821abd8f2SDavid du Colombier
167921abd8f2SDavid du Colombier lock(&units);
1680c675ee80SDavid du Colombier if(units.ref == Maxunits)
1681c675ee80SDavid du Colombier x = -1;
1682c675ee80SDavid du Colombier else
168321abd8f2SDavid du Colombier x = units.ref++;
168421abd8f2SDavid du Colombier unlock(&units);
168521abd8f2SDavid du Colombier return x;
168621abd8f2SDavid du Colombier }
168721abd8f2SDavid du Colombier
168821abd8f2SDavid du Colombier static int
dropunit(void)168921abd8f2SDavid du Colombier dropunit(void)
169021abd8f2SDavid du Colombier {
169121abd8f2SDavid du Colombier int x;
169221abd8f2SDavid du Colombier
169321abd8f2SDavid du Colombier lock(&units);
169421abd8f2SDavid du Colombier x = --units.ref;
169521abd8f2SDavid du Colombier unlock(&units);
169621abd8f2SDavid du Colombier return x;
169721abd8f2SDavid du Colombier }
169821abd8f2SDavid du Colombier
16992f205b96SDavid du Colombier /*
17002f205b96SDavid du Colombier * always allocate max frames. maxout may change.
17012f205b96SDavid du Colombier */
170221abd8f2SDavid du Colombier static Aoedev*
newdev(long major,long minor,int n)170321abd8f2SDavid du Colombier newdev(long major, long minor, int n)
170421abd8f2SDavid du Colombier {
170521abd8f2SDavid du Colombier Aoedev *d;
170621abd8f2SDavid du Colombier Frame *f, *e;
170721abd8f2SDavid du Colombier
170821abd8f2SDavid du Colombier d = mallocz(sizeof *d, 1);
17092f205b96SDavid du Colombier f = mallocz(sizeof *f * Maxframes, 1);
171021abd8f2SDavid du Colombier if (!d || !f) {
171121abd8f2SDavid du Colombier free(d);
171221abd8f2SDavid du Colombier free(f);
171321abd8f2SDavid du Colombier error("aoe device allocation failure");
171421abd8f2SDavid du Colombier }
171521abd8f2SDavid du Colombier d->nframes = n;
171621abd8f2SDavid du Colombier d->frames = f;
171721abd8f2SDavid du Colombier for (e = f + n; f < e; f++)
171821abd8f2SDavid du Colombier f->tag = Tfree;
171921abd8f2SDavid du Colombier d->maxout = n;
172021abd8f2SDavid du Colombier d->major = major;
172121abd8f2SDavid du Colombier d->minor = minor;
172221abd8f2SDavid du Colombier d->maxbcnt = Dbcnt;
172321abd8f2SDavid du Colombier d->flag = Djumbo;
172421abd8f2SDavid du Colombier d->unit = newunit(); /* bzzt. inaccurate if units removed */
1725c675ee80SDavid du Colombier if(d->unit == -1){
1726c675ee80SDavid du Colombier free(d->frames);
1727*f7c114afSDavid du Colombier free(d);
1728c675ee80SDavid du Colombier error("too many units");
1729c675ee80SDavid du Colombier }
173021abd8f2SDavid du Colombier d->dl = d->dltab;
173121abd8f2SDavid du Colombier return d;
173221abd8f2SDavid du Colombier }
173321abd8f2SDavid du Colombier
173421abd8f2SDavid du Colombier static Aoedev*
mm2dev(int major,int minor)1735c675ee80SDavid du Colombier mm2dev(int major, int minor)
173621abd8f2SDavid du Colombier {
173721abd8f2SDavid du Colombier Aoedev *d;
173821abd8f2SDavid du Colombier
173921abd8f2SDavid du Colombier rlock(&devs);
174021abd8f2SDavid du Colombier for(d = devs.d; d; d = d->next)
174121abd8f2SDavid du Colombier if(d->major == major && d->minor == minor){
174221abd8f2SDavid du Colombier runlock(&devs);
174321abd8f2SDavid du Colombier return d;
174421abd8f2SDavid du Colombier }
174521abd8f2SDavid du Colombier runlock(&devs);
1746c675ee80SDavid du Colombier eventlog("mm2dev: %d.%d not found\n", major, minor);
174721abd8f2SDavid du Colombier return nil;
174821abd8f2SDavid du Colombier }
174921abd8f2SDavid du Colombier
175021abd8f2SDavid du Colombier /* Find the device in our list. If not known, add it */
175121abd8f2SDavid du Colombier static Aoedev*
getdev(long major,long minor,int n)175221abd8f2SDavid du Colombier getdev(long major, long minor, int n)
175321abd8f2SDavid du Colombier {
175421abd8f2SDavid du Colombier Aoedev *d;
175521abd8f2SDavid du Colombier
17562f205b96SDavid du Colombier if(major == 0xffff || minor == 0xff)
17572f205b96SDavid du Colombier return 0;
175821abd8f2SDavid du Colombier wlock(&devs);
175921abd8f2SDavid du Colombier if(waserror()){
176021abd8f2SDavid du Colombier wunlock(&devs);
176121abd8f2SDavid du Colombier nexterror();
176221abd8f2SDavid du Colombier }
176321abd8f2SDavid du Colombier for(d = devs.d; d; d = d->next)
176421abd8f2SDavid du Colombier if(d->major == major && d->minor == minor)
176521abd8f2SDavid du Colombier break;
17661e18b896SDavid du Colombier if (d == nil) {
176721abd8f2SDavid du Colombier d = newdev(major, minor, n);
176821abd8f2SDavid du Colombier d->next = devs.d;
176921abd8f2SDavid du Colombier devs.d = d;
177021abd8f2SDavid du Colombier }
177121abd8f2SDavid du Colombier poperror();
177221abd8f2SDavid du Colombier wunlock(&devs);
177321abd8f2SDavid du Colombier return d;
177421abd8f2SDavid du Colombier }
177521abd8f2SDavid du Colombier
177621abd8f2SDavid du Colombier static ushort
gbit16(void * a)177721abd8f2SDavid du Colombier gbit16(void *a)
177821abd8f2SDavid du Colombier {
177921abd8f2SDavid du Colombier uchar *i;
178021abd8f2SDavid du Colombier
178121abd8f2SDavid du Colombier i = a;
178221abd8f2SDavid du Colombier return i[1] << 8 | i[0];
178321abd8f2SDavid du Colombier }
178421abd8f2SDavid du Colombier
178591b330d9SDavid du Colombier static ulong
gbit32(void * a)178621abd8f2SDavid du Colombier gbit32(void *a)
178721abd8f2SDavid du Colombier {
178891b330d9SDavid du Colombier ulong j;
178921abd8f2SDavid du Colombier uchar *i;
179021abd8f2SDavid du Colombier
179121abd8f2SDavid du Colombier i = a;
179221abd8f2SDavid du Colombier j = i[3] << 24;
179321abd8f2SDavid du Colombier j |= i[2] << 16;
179421abd8f2SDavid du Colombier j |= i[1] << 8;
179521abd8f2SDavid du Colombier j |= i[0];
179621abd8f2SDavid du Colombier return j;
179721abd8f2SDavid du Colombier }
179821abd8f2SDavid du Colombier
179921abd8f2SDavid du Colombier static uvlong
gbit64(void * a)180021abd8f2SDavid du Colombier gbit64(void *a)
180121abd8f2SDavid du Colombier {
180221abd8f2SDavid du Colombier uchar *i;
180321abd8f2SDavid du Colombier
180421abd8f2SDavid du Colombier i = a;
180521abd8f2SDavid du Colombier return (uvlong)gbit32(i+4) << 32 | gbit32(a);
180621abd8f2SDavid du Colombier }
180721abd8f2SDavid du Colombier
180821abd8f2SDavid du Colombier static void
ataident(Aoedev * d)180921abd8f2SDavid du Colombier ataident(Aoedev *d)
181021abd8f2SDavid du Colombier {
181121abd8f2SDavid du Colombier Aoeata *a;
181221abd8f2SDavid du Colombier Block *b;
181321abd8f2SDavid du Colombier Frame *f;
181421abd8f2SDavid du Colombier
181521abd8f2SDavid du Colombier f = freeframe(d);
181621abd8f2SDavid du Colombier if(f == nil)
181721abd8f2SDavid du Colombier return;
181841ac1ab6SDavid du Colombier f->nhdr = AOEATASZ;
181921abd8f2SDavid du Colombier memset(f->hdr, 0, f->nhdr);
182021abd8f2SDavid du Colombier a = (Aoeata*)f->hdr;
182121abd8f2SDavid du Colombier if(hset(d, f, a, ACata) == -1)
182221abd8f2SDavid du Colombier return;
182321abd8f2SDavid du Colombier a->cmdstat = Cid; /* ata 6, page 110 */
182421abd8f2SDavid du Colombier a->scnt = 1;
182521abd8f2SDavid du Colombier a->lba[3] = 0xa0;
182621abd8f2SDavid du Colombier d->nout++;
182721abd8f2SDavid du Colombier f->dl->npkt++;
1828c675ee80SDavid du Colombier f->bcnt = 512;
1829c675ee80SDavid du Colombier f->dlen = 0;
1830c675ee80SDavid du Colombier b = allocfb(f);
183121abd8f2SDavid du Colombier devtab[f->nl->dc->type]->bwrite(f->nl->dc, b, 0);
183221abd8f2SDavid du Colombier }
183321abd8f2SDavid du Colombier
183421abd8f2SDavid du Colombier static int
getmtu(Chan * mtuch)1835060a30c6SDavid du Colombier getmtu(Chan *mtuch)
183621abd8f2SDavid du Colombier {
183721abd8f2SDavid du Colombier int n, mtu;
183821abd8f2SDavid du Colombier char buf[36];
183921abd8f2SDavid du Colombier
1840060a30c6SDavid du Colombier mtu = ETHERMAXTU;
1841060a30c6SDavid du Colombier if(mtuch == nil || waserror())
184221abd8f2SDavid du Colombier return mtu;
1843060a30c6SDavid du Colombier n = devtab[mtuch->type]->read(mtuch, buf, sizeof buf - 1, 0);
184421abd8f2SDavid du Colombier if(n > 12){
184521abd8f2SDavid du Colombier buf[n] = 0;
184621abd8f2SDavid du Colombier mtu = strtoul(buf + 12, 0, 0);
184721abd8f2SDavid du Colombier }
184821abd8f2SDavid du Colombier poperror();
184921abd8f2SDavid du Colombier return mtu;
185021abd8f2SDavid du Colombier }
185121abd8f2SDavid du Colombier
185221abd8f2SDavid du Colombier static int
newdlea(Devlink * l,uchar * ea)185321abd8f2SDavid du Colombier newdlea(Devlink *l, uchar *ea)
185421abd8f2SDavid du Colombier {
185521abd8f2SDavid du Colombier int i;
185621abd8f2SDavid du Colombier uchar *t;
185721abd8f2SDavid du Colombier
185821abd8f2SDavid du Colombier for(i = 0; i < Nea; i++){
185921abd8f2SDavid du Colombier t = l->eatab[i];
186021abd8f2SDavid du Colombier if(i == l->nea){
186121abd8f2SDavid du Colombier memmove(t, ea, Eaddrlen);
186221abd8f2SDavid du Colombier return l->nea++;
186321abd8f2SDavid du Colombier }
186421abd8f2SDavid du Colombier if(memcmp(t, ea, Eaddrlen) == 0)
186521abd8f2SDavid du Colombier return i;
186621abd8f2SDavid du Colombier }
186721abd8f2SDavid du Colombier return -1;
186821abd8f2SDavid du Colombier }
186921abd8f2SDavid du Colombier
187021abd8f2SDavid du Colombier static Devlink*
newdevlink(Aoedev * d,Netlink * n,Aoeqc * c)187121abd8f2SDavid du Colombier newdevlink(Aoedev *d, Netlink *n, Aoeqc *c)
187221abd8f2SDavid du Colombier {
187321abd8f2SDavid du Colombier int i;
187421abd8f2SDavid du Colombier Devlink *l;
187521abd8f2SDavid du Colombier
187621abd8f2SDavid du Colombier for(i = 0; i < Ndevlink; i++){
187721abd8f2SDavid du Colombier l = d->dl + i;
187821abd8f2SDavid du Colombier if(i == d->ndl){
187921abd8f2SDavid du Colombier d->ndl++;
188021abd8f2SDavid du Colombier newdlea(l, c->src);
188121abd8f2SDavid du Colombier l->nl = n;
188221abd8f2SDavid du Colombier l->flag |= Dup;
188321abd8f2SDavid du Colombier l->mintimer = Rtmin;
188421abd8f2SDavid du Colombier l->rttavg = Rtmax;
188521abd8f2SDavid du Colombier return l;
188621abd8f2SDavid du Colombier }
18872f205b96SDavid du Colombier if(l->nl == n) {
18882f205b96SDavid du Colombier newdlea(l, c->src);
18892f205b96SDavid du Colombier l->flag |= Dup;
189021abd8f2SDavid du Colombier return l;
189121abd8f2SDavid du Colombier }
18922f205b96SDavid du Colombier }
1893c675ee80SDavid du Colombier eventlog("%æ: out of links: %s:%E to %E\n", d, n->path, n->ea, c->src);
189421abd8f2SDavid du Colombier return 0;
189521abd8f2SDavid du Colombier }
189621abd8f2SDavid du Colombier
189721abd8f2SDavid du Colombier static void
errrsp(Block * b,char * s)189821abd8f2SDavid du Colombier errrsp(Block *b, char *s)
189921abd8f2SDavid du Colombier {
190021abd8f2SDavid du Colombier int n;
190121abd8f2SDavid du Colombier Aoedev *d;
190221abd8f2SDavid du Colombier Aoehdr *h;
190321abd8f2SDavid du Colombier Frame *f;
190421abd8f2SDavid du Colombier
190521abd8f2SDavid du Colombier h = (Aoehdr*)b->rp;
190621abd8f2SDavid du Colombier n = nhgetl(h->tag);
190721abd8f2SDavid du Colombier if(n == Tmgmt || n == Tfree)
190821abd8f2SDavid du Colombier return;
190921abd8f2SDavid du Colombier d = mm2dev(nhgets(h->major), h->minor);
191021abd8f2SDavid du Colombier if(d == 0)
191121abd8f2SDavid du Colombier return;
191221abd8f2SDavid du Colombier if(f = getframe(d, n))
191321abd8f2SDavid du Colombier frameerror(d, f, s);
191421abd8f2SDavid du Colombier }
191521abd8f2SDavid du Colombier
191621abd8f2SDavid du Colombier static void
qcfgrsp(Block * b,Netlink * nl)191721abd8f2SDavid du Colombier qcfgrsp(Block *b, Netlink *nl)
191821abd8f2SDavid du Colombier {
191921abd8f2SDavid du Colombier int major, cmd, cslen, blen;
192021abd8f2SDavid du Colombier unsigned n;
192121abd8f2SDavid du Colombier Aoedev *d;
192221abd8f2SDavid du Colombier Aoeqc *ch;
192321abd8f2SDavid du Colombier Devlink *l;
192421abd8f2SDavid du Colombier Frame *f;
192521abd8f2SDavid du Colombier
192621abd8f2SDavid du Colombier ch = (Aoeqc*)b->rp;
192721abd8f2SDavid du Colombier major = nhgets(ch->major);
192821abd8f2SDavid du Colombier n = nhgetl(ch->tag);
192921abd8f2SDavid du Colombier if(n != Tmgmt){
193021abd8f2SDavid du Colombier d = mm2dev(major, ch->minor);
1931c675ee80SDavid du Colombier if(d == nil)
1932c675ee80SDavid du Colombier return;
193321abd8f2SDavid du Colombier qlock(d);
193421abd8f2SDavid du Colombier f = getframe(d, n);
193521abd8f2SDavid du Colombier if(f == nil){
193621abd8f2SDavid du Colombier qunlock(d);
193721abd8f2SDavid du Colombier eventlog("%æ: unknown response tag %ux\n", d, n);
193821abd8f2SDavid du Colombier return;
193921abd8f2SDavid du Colombier }
194021abd8f2SDavid du Colombier cslen = nhgets(ch->cslen);
194141ac1ab6SDavid du Colombier blen = BLEN(b) - AOEQCSZ;
19422f205b96SDavid du Colombier if(cslen < blen && BLEN(b) > 60)
194321abd8f2SDavid du Colombier eventlog("%æ: cfgrsp: tag %.8ux oversized %d %d\n",
194421abd8f2SDavid du Colombier d, n, cslen, blen);
194521abd8f2SDavid du Colombier if(cslen > blen){
194621abd8f2SDavid du Colombier eventlog("%æ: cfgrsp: tag %.8ux runt %d %d\n",
194721abd8f2SDavid du Colombier d, n, cslen, blen);
194821abd8f2SDavid du Colombier cslen = blen;
194921abd8f2SDavid du Colombier }
195021abd8f2SDavid du Colombier memmove(f->dp, ch + 1, cslen);
195121abd8f2SDavid du Colombier f->srb->nout--;
195221abd8f2SDavid du Colombier wakeup(f->srb);
1953*f7c114afSDavid du Colombier f->srb->shared = 0;
195421abd8f2SDavid du Colombier d->nout--;
195521abd8f2SDavid du Colombier f->srb = nil;
195621abd8f2SDavid du Colombier f->tag = Tfree;
195721abd8f2SDavid du Colombier qunlock(d);
195821abd8f2SDavid du Colombier return;
195921abd8f2SDavid du Colombier }
196021abd8f2SDavid du Colombier
196121abd8f2SDavid du Colombier cmd = ch->verccmd & 0xf;
196221abd8f2SDavid du Colombier if(cmd != 0){
1963421195e0SDavid du Colombier eventlog("aoe%d.%d: cfgrsp: bad command %d\n", major, ch->minor, cmd);
196421abd8f2SDavid du Colombier return;
196521abd8f2SDavid du Colombier }
196621abd8f2SDavid du Colombier n = nhgets(ch->bufcnt);
196721abd8f2SDavid du Colombier if(n > Maxframes)
196821abd8f2SDavid du Colombier n = Maxframes;
1969c675ee80SDavid du Colombier
1970c675ee80SDavid du Colombier if(waserror()){
1971c675ee80SDavid du Colombier eventlog("getdev: %d.%d ignored: %s\n", major, ch->minor, up->errstr);
1972c675ee80SDavid du Colombier return;
1973c675ee80SDavid du Colombier }
197421abd8f2SDavid du Colombier d = getdev(major, ch->minor, n);
1975c675ee80SDavid du Colombier poperror();
19762f205b96SDavid du Colombier if(d == 0)
19772f205b96SDavid du Colombier return;
1978c675ee80SDavid du Colombier
197921abd8f2SDavid du Colombier qlock(d);
19802f205b96SDavid du Colombier *up->errstr = 0;
198121abd8f2SDavid du Colombier if(waserror()){
198221abd8f2SDavid du Colombier qunlock(d);
1983c675ee80SDavid du Colombier eventlog("%æ: %s\n", d, up->errstr);
1984421195e0SDavid du Colombier nexterror();
198521abd8f2SDavid du Colombier }
198621abd8f2SDavid du Colombier
198721abd8f2SDavid du Colombier l = newdevlink(d, nl, ch); /* add this interface. */
198821abd8f2SDavid du Colombier
198921abd8f2SDavid du Colombier d->fwver = nhgets(ch->fwver);
199021abd8f2SDavid du Colombier n = nhgets(ch->cslen);
199121abd8f2SDavid du Colombier if(n > sizeof d->config)
199221abd8f2SDavid du Colombier n = sizeof d->config;
199321abd8f2SDavid du Colombier d->nconfig = n;
199421abd8f2SDavid du Colombier memmove(d->config, ch + 1, n);
199521abd8f2SDavid du Colombier if(l != 0 && d->flag & Djumbo){
199641ac1ab6SDavid du Colombier n = getmtu(nl->mtu) - AOEATASZ;
199721abd8f2SDavid du Colombier n /= Aoesectsz;
199821abd8f2SDavid du Colombier if(n > ch->scnt)
199921abd8f2SDavid du Colombier n = ch->scnt;
200021abd8f2SDavid du Colombier n = n? n * Aoesectsz: Dbcnt;
200121abd8f2SDavid du Colombier if(n != d->maxbcnt){
200221abd8f2SDavid du Colombier eventlog("%æ: setting %d byte data frames on %s:%E\n",
200321abd8f2SDavid du Colombier d, n, nl->path, nl->ea);
200421abd8f2SDavid du Colombier d->maxbcnt = n;
200521abd8f2SDavid du Colombier }
200621abd8f2SDavid du Colombier }
200721abd8f2SDavid du Colombier if(d->nopen == 0)
200821abd8f2SDavid du Colombier ataident(d);
200921abd8f2SDavid du Colombier poperror();
201021abd8f2SDavid du Colombier qunlock(d);
201121abd8f2SDavid du Colombier }
201221abd8f2SDavid du Colombier
201345dfec46SDavid du Colombier void
aoeidmove(char * p,ushort * u,unsigned n)201445dfec46SDavid du Colombier aoeidmove(char *p, ushort *u, unsigned n)
201521abd8f2SDavid du Colombier {
201621abd8f2SDavid du Colombier int i;
201745dfec46SDavid du Colombier char *op, *e, *s;
201821abd8f2SDavid du Colombier
201921abd8f2SDavid du Colombier op = p;
202045dfec46SDavid du Colombier /*
20212f205b96SDavid du Colombier * the ushort `*u' is sometimes not aligned on a short boundary,
20222f205b96SDavid du Colombier * so dereferencing u[i] causes an alignment exception on
202345dfec46SDavid du Colombier * some machines.
202445dfec46SDavid du Colombier */
202545dfec46SDavid du Colombier s = (char *)u;
202645dfec46SDavid du Colombier for(i = 0; i < n; i += 2){
202745dfec46SDavid du Colombier *p++ = s[i + 1];
202845dfec46SDavid du Colombier *p++ = s[i];
202921abd8f2SDavid du Colombier }
203021abd8f2SDavid du Colombier *p = 0;
203121abd8f2SDavid du Colombier while(p > op && *--p == ' ')
203221abd8f2SDavid du Colombier *p = 0;
203321abd8f2SDavid du Colombier e = p;
203421abd8f2SDavid du Colombier p = op;
203521abd8f2SDavid du Colombier while(*p == ' ')
203621abd8f2SDavid du Colombier p++;
203721abd8f2SDavid du Colombier memmove(op, p, n - (e - p));
203821abd8f2SDavid du Colombier }
203921abd8f2SDavid du Colombier
204021abd8f2SDavid du Colombier static vlong
aoeidentify(Aoedev * d,ushort * id)204121abd8f2SDavid du Colombier aoeidentify(Aoedev *d, ushort *id)
204221abd8f2SDavid du Colombier {
204321abd8f2SDavid du Colombier int i;
204421abd8f2SDavid du Colombier vlong s;
204521abd8f2SDavid du Colombier
204621abd8f2SDavid du Colombier d->flag &= ~(Dllba|Dpower|Dsmart|Dnop|Dup);
204721abd8f2SDavid du Colombier
204821abd8f2SDavid du Colombier i = gbit16(id+83) | gbit16(id+86);
204921abd8f2SDavid du Colombier if(i & (1<<10)){
205021abd8f2SDavid du Colombier d->flag |= Dllba;
205121abd8f2SDavid du Colombier s = gbit64(id+100);
205221abd8f2SDavid du Colombier }else
205321abd8f2SDavid du Colombier s = gbit32(id+60);
205421abd8f2SDavid du Colombier
205521abd8f2SDavid du Colombier i = gbit16(id+83);
205621abd8f2SDavid du Colombier if((i>>14) == 1) {
205721abd8f2SDavid du Colombier if(i & (1<<3))
205821abd8f2SDavid du Colombier d->flag |= Dpower;
205921abd8f2SDavid du Colombier i = gbit16(id+82);
206021abd8f2SDavid du Colombier if(i & 1)
206121abd8f2SDavid du Colombier d->flag |= Dsmart;
206221abd8f2SDavid du Colombier if(i & (1<<14))
206321abd8f2SDavid du Colombier d->flag |= Dnop;
206421abd8f2SDavid du Colombier }
206521abd8f2SDavid du Colombier // eventlog("%æ up\n", d);
206621abd8f2SDavid du Colombier d->flag |= Dup;
206721abd8f2SDavid du Colombier memmove(d->ident, id, sizeof d->ident);
206821abd8f2SDavid du Colombier return s;
206921abd8f2SDavid du Colombier }
207021abd8f2SDavid du Colombier
2071c675ee80SDavid du Colombier static void
newvers(Aoedev * d)2072c675ee80SDavid du Colombier newvers(Aoedev *d)
2073c675ee80SDavid du Colombier {
2074c675ee80SDavid du Colombier lock(&drivevers);
2075c675ee80SDavid du Colombier d->vers = drivevers.ref++;
2076c675ee80SDavid du Colombier unlock(&drivevers);
2077c675ee80SDavid du Colombier }
2078c675ee80SDavid du Colombier
207921abd8f2SDavid du Colombier static int
identify(Aoedev * d,ushort * id)208021abd8f2SDavid du Colombier identify(Aoedev *d, ushort *id)
208121abd8f2SDavid du Colombier {
208221abd8f2SDavid du Colombier vlong osectors, s;
208321abd8f2SDavid du Colombier uchar oserial[21];
208421abd8f2SDavid du Colombier
208521abd8f2SDavid du Colombier s = aoeidentify(d, id);
208621abd8f2SDavid du Colombier if(s == -1)
208721abd8f2SDavid du Colombier return -1;
208821abd8f2SDavid du Colombier osectors = d->realbsize;
208921abd8f2SDavid du Colombier memmove(oserial, d->serial, sizeof d->serial);
209021abd8f2SDavid du Colombier
209145dfec46SDavid du Colombier aoeidmove(d->serial, id+10, 20);
209245dfec46SDavid du Colombier aoeidmove(d->firmware, id+23, 8);
209345dfec46SDavid du Colombier aoeidmove(d->model, id+27, 40);
209421abd8f2SDavid du Colombier
209521abd8f2SDavid du Colombier s *= Aoesectsz;
209621abd8f2SDavid du Colombier if((osectors == 0 || osectors != s) &&
209721abd8f2SDavid du Colombier memcmp(oserial, d->serial, sizeof oserial) != 0){
209821abd8f2SDavid du Colombier d->bsize = s;
209921abd8f2SDavid du Colombier d->realbsize = s;
210021abd8f2SDavid du Colombier // d->mediachange = 1;
2101c675ee80SDavid du Colombier newvers(d);
210221abd8f2SDavid du Colombier }
210321abd8f2SDavid du Colombier return 0;
210421abd8f2SDavid du Colombier }
210521abd8f2SDavid du Colombier
210621abd8f2SDavid du Colombier static void
atarsp(Block * b)210721abd8f2SDavid du Colombier atarsp(Block *b)
210821abd8f2SDavid du Colombier {
210921abd8f2SDavid du Colombier unsigned n;
211021abd8f2SDavid du Colombier short major;
211121abd8f2SDavid du Colombier Aoeata *ahin, *ahout;
211221abd8f2SDavid du Colombier Aoedev *d;
211321abd8f2SDavid du Colombier Frame *f;
211421abd8f2SDavid du Colombier Srb *srb;
211521abd8f2SDavid du Colombier
211621abd8f2SDavid du Colombier ahin = (Aoeata*)b->rp;
211721abd8f2SDavid du Colombier major = nhgets(ahin->major);
211821abd8f2SDavid du Colombier d = mm2dev(major, ahin->minor);
2119c675ee80SDavid du Colombier if(d == nil)
2120c675ee80SDavid du Colombier return;
212121abd8f2SDavid du Colombier qlock(d);
212221abd8f2SDavid du Colombier if(waserror()){
212321abd8f2SDavid du Colombier qunlock(d);
212421abd8f2SDavid du Colombier nexterror();
212521abd8f2SDavid du Colombier }
212621abd8f2SDavid du Colombier n = nhgetl(ahin->tag);
212721abd8f2SDavid du Colombier f = getframe(d, n);
212821abd8f2SDavid du Colombier if(f == nil){
212921abd8f2SDavid du Colombier dprint("%æ: unexpected response; tag %ux\n", d, n);
213021abd8f2SDavid du Colombier goto bail;
213121abd8f2SDavid du Colombier }
213221abd8f2SDavid du Colombier rtupdate(f->dl, tsince(f->tag));
213321abd8f2SDavid du Colombier ahout = (Aoeata*)f->hdr;
213421abd8f2SDavid du Colombier srb = f->srb;
213521abd8f2SDavid du Colombier
213621abd8f2SDavid du Colombier if(ahin->cmdstat & 0xa9){
213721abd8f2SDavid du Colombier eventlog("%æ: ata error cmd %.2ux stat %.2ux\n",
213821abd8f2SDavid du Colombier d, ahout->cmdstat, ahin->cmdstat);
213921abd8f2SDavid du Colombier if(srb)
214021abd8f2SDavid du Colombier srb->error = Eio;
214121abd8f2SDavid du Colombier } else {
214221abd8f2SDavid du Colombier n = ahout->scnt * Aoesectsz;
214321abd8f2SDavid du Colombier switch(ahout->cmdstat){
214421abd8f2SDavid du Colombier case Crd:
214521abd8f2SDavid du Colombier case Crdext:
214641ac1ab6SDavid du Colombier if(BLEN(b) - AOEATASZ < n){
214721abd8f2SDavid du Colombier eventlog("%æ: runt read blen %ld expect %d\n",
214821abd8f2SDavid du Colombier d, BLEN(b), n);
214921abd8f2SDavid du Colombier goto bail;
215021abd8f2SDavid du Colombier }
215141ac1ab6SDavid du Colombier memmove(f->dp, (uchar *)ahin + AOEATASZ, n);
215221abd8f2SDavid du Colombier case Cwr:
215321abd8f2SDavid du Colombier case Cwrext:
215421abd8f2SDavid du Colombier if(n > Dbcnt)
215521abd8f2SDavid du Colombier f->nl->lostjumbo = 0;
215621abd8f2SDavid du Colombier if(f->bcnt -= n){
215721abd8f2SDavid du Colombier f->lba += n / Aoesectsz;
215821abd8f2SDavid du Colombier f->dp = (uchar*)f->dp + n;
215921abd8f2SDavid du Colombier resend(d, f);
216021abd8f2SDavid du Colombier goto bail;
216121abd8f2SDavid du Colombier }
216221abd8f2SDavid du Colombier break;
216321abd8f2SDavid du Colombier case Cid:
216441ac1ab6SDavid du Colombier if(BLEN(b) - AOEATASZ < 512){
216521abd8f2SDavid du Colombier eventlog("%æ: runt identify blen %ld expect %d\n",
216621abd8f2SDavid du Colombier d, BLEN(b), n);
216721abd8f2SDavid du Colombier goto bail;
216821abd8f2SDavid du Colombier }
216941ac1ab6SDavid du Colombier identify(d, (ushort*)((uchar *)ahin + AOEATASZ));
217021abd8f2SDavid du Colombier break;
217121abd8f2SDavid du Colombier default:
217221abd8f2SDavid du Colombier eventlog("%æ: unknown ata command %.2ux \n",
217321abd8f2SDavid du Colombier d, ahout->cmdstat);
217421abd8f2SDavid du Colombier }
217521abd8f2SDavid du Colombier }
217621abd8f2SDavid du Colombier
2177*f7c114afSDavid du Colombier if(srb && --srb->nout == 0 && srb->len == 0){
217821abd8f2SDavid du Colombier wakeup(srb);
2179*f7c114afSDavid du Colombier srb->shared = 0;
2180*f7c114afSDavid du Colombier }
218121abd8f2SDavid du Colombier f->srb = nil;
218221abd8f2SDavid du Colombier f->tag = Tfree;
218321abd8f2SDavid du Colombier d->nout--;
218421abd8f2SDavid du Colombier
218521abd8f2SDavid du Colombier work(d);
218621abd8f2SDavid du Colombier bail:
218721abd8f2SDavid du Colombier poperror();
218821abd8f2SDavid du Colombier qunlock(d);
218921abd8f2SDavid du Colombier }
219021abd8f2SDavid du Colombier
219121abd8f2SDavid du Colombier static void
netrdaoeproc(void * v)219299c72adcSDavid du Colombier netrdaoeproc(void *v)
219321abd8f2SDavid du Colombier {
219421abd8f2SDavid du Colombier int idx;
219521abd8f2SDavid du Colombier char name[Maxpath+1], *s;
219621abd8f2SDavid du Colombier Aoehdr *h;
219721abd8f2SDavid du Colombier Block *b;
219821abd8f2SDavid du Colombier Netlink *nl;
219921abd8f2SDavid du Colombier
220021abd8f2SDavid du Colombier nl = (Netlink*)v;
220121abd8f2SDavid du Colombier idx = nl - netlinks.nl;
220221abd8f2SDavid du Colombier netlinks.reader[idx] = 1;
220321abd8f2SDavid du Colombier kstrcpy(name, nl->path, Maxpath);
220421abd8f2SDavid du Colombier
220521abd8f2SDavid du Colombier if(waserror()){
220621abd8f2SDavid du Colombier eventlog("netrdaoe exiting: %s\n", up->errstr);
220721abd8f2SDavid du Colombier netlinks.reader[idx] = 0;
220821abd8f2SDavid du Colombier wakeup(netlinks.rendez + idx);
220921abd8f2SDavid du Colombier pexit(up->errstr, 1);
221021abd8f2SDavid du Colombier }
221121abd8f2SDavid du Colombier if(autodiscover)
221221abd8f2SDavid du Colombier discover(0xffff, 0xff);
221321abd8f2SDavid du Colombier for (;;) {
221499c72adcSDavid du Colombier if(!(nl->flag & Dup)) {
221599c72adcSDavid du Colombier uprint("%s: netlink is down", name);
221699c72adcSDavid du Colombier error(up->genbuf);
221799c72adcSDavid du Colombier }
22181e18b896SDavid du Colombier if (nl->dc == nil)
22191e18b896SDavid du Colombier panic("netrdaoe: nl->dc == nil");
222021abd8f2SDavid du Colombier b = devtab[nl->dc->type]->bread(nl->dc, 1<<16, 0);
222199c72adcSDavid du Colombier if(b == nil) {
222299c72adcSDavid du Colombier uprint("%s: nil read from network", name);
222399c72adcSDavid du Colombier error(up->genbuf);
222499c72adcSDavid du Colombier }
222521abd8f2SDavid du Colombier h = (Aoehdr*)b->rp;
222621abd8f2SDavid du Colombier if(h->verflag & AFrsp)
222721abd8f2SDavid du Colombier if(s = aoeerror(h)){
222821abd8f2SDavid du Colombier eventlog("%s: %s\n", nl->path, up->errstr);
222921abd8f2SDavid du Colombier errrsp(b, s);
223021abd8f2SDavid du Colombier }else
223121abd8f2SDavid du Colombier switch(h->cmd){
223221abd8f2SDavid du Colombier case ACata:
223321abd8f2SDavid du Colombier atarsp(b);
223421abd8f2SDavid du Colombier break;
223521abd8f2SDavid du Colombier case ACconfig:
223621abd8f2SDavid du Colombier qcfgrsp(b, nl);
223721abd8f2SDavid du Colombier break;
223821abd8f2SDavid du Colombier default:
22392f205b96SDavid du Colombier if((h->cmd & 0xf0) == 0){
224021abd8f2SDavid du Colombier eventlog("%s: unknown cmd %d\n",
224121abd8f2SDavid du Colombier nl->path, h->cmd);
224221abd8f2SDavid du Colombier errrsp(b, "unknown command");
224321abd8f2SDavid du Colombier }
22442f205b96SDavid du Colombier break;
22452f205b96SDavid du Colombier }
224621abd8f2SDavid du Colombier freeb(b);
224721abd8f2SDavid du Colombier }
224821abd8f2SDavid du Colombier }
224921abd8f2SDavid du Colombier
225021abd8f2SDavid du Colombier static void
getaddr(char * path,uchar * ea)225121abd8f2SDavid du Colombier getaddr(char *path, uchar *ea)
225221abd8f2SDavid du Colombier {
225321abd8f2SDavid du Colombier int n;
225421abd8f2SDavid du Colombier char buf[2*Eaddrlen+1];
225521abd8f2SDavid du Colombier Chan *c;
225621abd8f2SDavid du Colombier
225721abd8f2SDavid du Colombier uprint("%s/addr", path);
225821abd8f2SDavid du Colombier c = namec(up->genbuf, Aopen, OREAD, 0);
225921abd8f2SDavid du Colombier if(waserror()) {
226021abd8f2SDavid du Colombier cclose(c);
226121abd8f2SDavid du Colombier nexterror();
226221abd8f2SDavid du Colombier }
22631e18b896SDavid du Colombier if (c == nil)
22641e18b896SDavid du Colombier panic("æ: getaddr: c == nil");
226521abd8f2SDavid du Colombier n = devtab[c->type]->read(c, buf, sizeof buf-1, 0);
226621abd8f2SDavid du Colombier poperror();
226721abd8f2SDavid du Colombier cclose(c);
226821abd8f2SDavid du Colombier buf[n] = 0;
226921abd8f2SDavid du Colombier if(parseether(ea, buf) < 0)
227021abd8f2SDavid du Colombier error("parseether failure");
227121abd8f2SDavid du Colombier }
227221abd8f2SDavid du Colombier
227321abd8f2SDavid du Colombier static void
netbind(char * path)227421abd8f2SDavid du Colombier netbind(char *path)
227521abd8f2SDavid du Colombier {
227621abd8f2SDavid du Colombier char addr[Maxpath];
227721abd8f2SDavid du Colombier uchar ea[2*Eaddrlen+1];
227821abd8f2SDavid du Colombier Chan *dc, *cc, *mtu;
227921abd8f2SDavid du Colombier Netlink *nl;
228021abd8f2SDavid du Colombier
2281567483c8SDavid du Colombier snprint(addr, sizeof addr, "%s!%#x", path, Aoetype);
228221abd8f2SDavid du Colombier dc = chandial(addr, nil, nil, &cc);
228321abd8f2SDavid du Colombier snprint(addr, sizeof addr, "%s/mtu", path);
22841e18b896SDavid du Colombier if(waserror())
22851e18b896SDavid du Colombier mtu = nil;
22861e18b896SDavid du Colombier else {
228721abd8f2SDavid du Colombier mtu = namec(addr, Aopen, OREAD, 0);
22881e18b896SDavid du Colombier poperror();
22891e18b896SDavid du Colombier }
229021abd8f2SDavid du Colombier
229121abd8f2SDavid du Colombier if(waserror()){
229221abd8f2SDavid du Colombier cclose(dc);
229321abd8f2SDavid du Colombier cclose(cc);
229421abd8f2SDavid du Colombier if(mtu)
229521abd8f2SDavid du Colombier cclose(mtu);
229621abd8f2SDavid du Colombier nexterror();
229721abd8f2SDavid du Colombier }
229821abd8f2SDavid du Colombier if(dc == nil || cc == nil)
229921abd8f2SDavid du Colombier error(Enonexist);
230021abd8f2SDavid du Colombier getaddr(path, ea);
230121abd8f2SDavid du Colombier nl = addnet(path, cc, dc, mtu, ea);
230221abd8f2SDavid du Colombier snprint(addr, sizeof addr, "netrdaoe@%s", path);
230399c72adcSDavid du Colombier kproc(addr, netrdaoeproc, nl);
230421abd8f2SDavid du Colombier poperror();
230521abd8f2SDavid du Colombier }
230621abd8f2SDavid du Colombier
230721abd8f2SDavid du Colombier static int
unbound(void * v)230821abd8f2SDavid du Colombier unbound(void *v)
230921abd8f2SDavid du Colombier {
231021abd8f2SDavid du Colombier return *(int*)v != 0;
231121abd8f2SDavid du Colombier }
231221abd8f2SDavid du Colombier
231321abd8f2SDavid du Colombier static void
netunbind(char * path)231421abd8f2SDavid du Colombier netunbind(char *path)
231521abd8f2SDavid du Colombier {
231621abd8f2SDavid du Colombier int i, idx;
231721abd8f2SDavid du Colombier Aoedev *d, *p, *next;
231821abd8f2SDavid du Colombier Chan *dc, *cc;
231921abd8f2SDavid du Colombier Devlink *l;
232021abd8f2SDavid du Colombier Frame *f;
232121abd8f2SDavid du Colombier Netlink *n, *e;
232221abd8f2SDavid du Colombier
232321abd8f2SDavid du Colombier n = netlinks.nl;
232421abd8f2SDavid du Colombier e = n + nelem(netlinks.nl);
232521abd8f2SDavid du Colombier
232621abd8f2SDavid du Colombier lock(&netlinks);
232721abd8f2SDavid du Colombier for(; n < e; n++)
232821abd8f2SDavid du Colombier if(n->dc && strcmp(n->path, path) == 0)
232921abd8f2SDavid du Colombier break;
233021abd8f2SDavid du Colombier unlock(&netlinks);
233121abd8f2SDavid du Colombier if (n >= e)
233221abd8f2SDavid du Colombier error("device not bound");
233321abd8f2SDavid du Colombier
233421abd8f2SDavid du Colombier /*
233521abd8f2SDavid du Colombier * hunt down devices using this interface; disable
233621abd8f2SDavid du Colombier * this also terminates the reader.
233721abd8f2SDavid du Colombier */
233821abd8f2SDavid du Colombier idx = n - netlinks.nl;
233921abd8f2SDavid du Colombier wlock(&devs);
234021abd8f2SDavid du Colombier for(d = devs.d; d; d = d->next){
234121abd8f2SDavid du Colombier qlock(d);
234221abd8f2SDavid du Colombier for(i = 0; i < d->ndl; i++){
234321abd8f2SDavid du Colombier l = d->dl + i;
234421abd8f2SDavid du Colombier if(l->nl == n)
234521abd8f2SDavid du Colombier l->flag &= ~Dup;
234621abd8f2SDavid du Colombier }
234721abd8f2SDavid du Colombier qunlock(d);
234821abd8f2SDavid du Colombier }
234921abd8f2SDavid du Colombier n->flag &= ~Dup;
235021abd8f2SDavid du Colombier wunlock(&devs);
235121abd8f2SDavid du Colombier
235221abd8f2SDavid du Colombier /* confirm reader is down. */
235321abd8f2SDavid du Colombier while(waserror())
235421abd8f2SDavid du Colombier ;
235521abd8f2SDavid du Colombier sleep(netlinks.rendez + idx, unbound, netlinks.reader + idx);
235621abd8f2SDavid du Colombier poperror();
235721abd8f2SDavid du Colombier
235821abd8f2SDavid du Colombier /* reschedule packets. */
235921abd8f2SDavid du Colombier wlock(&devs);
236021abd8f2SDavid du Colombier for(d = devs.d; d; d = d->next){
236121abd8f2SDavid du Colombier qlock(d);
236221abd8f2SDavid du Colombier for(i = 0; i < d->nframes; i++){
236321abd8f2SDavid du Colombier f = d->frames + i;
236421abd8f2SDavid du Colombier if(f->tag != Tfree && f->nl == n)
236521abd8f2SDavid du Colombier resend(d, f);
236621abd8f2SDavid du Colombier }
236721abd8f2SDavid du Colombier qunlock(d);
236821abd8f2SDavid du Colombier }
236921abd8f2SDavid du Colombier wunlock(&devs);
237021abd8f2SDavid du Colombier
237121abd8f2SDavid du Colombier /* squeeze devlink pool. (we assert nobody is using them now) */
237221abd8f2SDavid du Colombier wlock(&devs);
237321abd8f2SDavid du Colombier for(d = devs.d; d; d = d->next){
237421abd8f2SDavid du Colombier qlock(d);
237521abd8f2SDavid du Colombier for(i = 0; i < d->ndl; i++){
237621abd8f2SDavid du Colombier l = d->dl + i;
237721abd8f2SDavid du Colombier if(l->nl == n)
237821abd8f2SDavid du Colombier memmove(l, l + 1, sizeof *l * (--d->ndl - i));
237921abd8f2SDavid du Colombier }
238021abd8f2SDavid du Colombier qunlock(d);
238121abd8f2SDavid du Colombier }
238221abd8f2SDavid du Colombier wunlock(&devs);
238321abd8f2SDavid du Colombier
238421abd8f2SDavid du Colombier /* close device link. */
238521abd8f2SDavid du Colombier lock(&netlinks);
238621abd8f2SDavid du Colombier dc = n->dc;
238721abd8f2SDavid du Colombier cc = n->cc;
238821abd8f2SDavid du Colombier if(n->mtu)
238921abd8f2SDavid du Colombier cclose(n->mtu);
239021abd8f2SDavid du Colombier memset(n, 0, sizeof *n);
239121abd8f2SDavid du Colombier unlock(&netlinks);
239221abd8f2SDavid du Colombier
239321abd8f2SDavid du Colombier cclose(dc);
239421abd8f2SDavid du Colombier cclose(cc);
239521abd8f2SDavid du Colombier
239621abd8f2SDavid du Colombier /* squeeze orphan devices */
239721abd8f2SDavid du Colombier wlock(&devs);
23982f205b96SDavid du Colombier for(p = d = devs.d; d; d = next){
239921abd8f2SDavid du Colombier next = d->next;
24002f205b96SDavid du Colombier if(d->ndl > 0) {
24012f205b96SDavid du Colombier p = d;
240221abd8f2SDavid du Colombier continue;
24032f205b96SDavid du Colombier }
24042f205b96SDavid du Colombier qlock(d);
24052f205b96SDavid du Colombier downdev(d, "orphan");
24062f205b96SDavid du Colombier qunlock(d);
240721abd8f2SDavid du Colombier if(p != devs.d)
240821abd8f2SDavid du Colombier p->next = next;
24092f205b96SDavid du Colombier else{
241021abd8f2SDavid du Colombier devs.d = next;
24112f205b96SDavid du Colombier p = devs.d;
24122f205b96SDavid du Colombier }
241321abd8f2SDavid du Colombier free(d->frames);
241421abd8f2SDavid du Colombier free(d);
241521abd8f2SDavid du Colombier dropunit();
241621abd8f2SDavid du Colombier }
241721abd8f2SDavid du Colombier wunlock(&devs);
241821abd8f2SDavid du Colombier }
241921abd8f2SDavid du Colombier
242021abd8f2SDavid du Colombier static void
removeaoedev(Aoedev * d)24212f205b96SDavid du Colombier removeaoedev(Aoedev *d)
242221abd8f2SDavid du Colombier {
242321abd8f2SDavid du Colombier int i;
24242f205b96SDavid du Colombier Aoedev *p;
242521abd8f2SDavid du Colombier
242621abd8f2SDavid du Colombier wlock(&devs);
24272f205b96SDavid du Colombier p = 0;
24282f205b96SDavid du Colombier if(d != devs.d)
24292f205b96SDavid du Colombier for(p = devs.d; p; p = p->next)
24302f205b96SDavid du Colombier if(p->next == d)
24312f205b96SDavid du Colombier break;
24322f205b96SDavid du Colombier qlock(d);
243321abd8f2SDavid du Colombier d->flag &= ~Dup;
2434b65f1be6SDavid du Colombier
2435b65f1be6SDavid du Colombier /*
2436b65f1be6SDavid du Colombier * Changing the version number is, strictly speaking, correct,
2437b65f1be6SDavid du Colombier * but doing so means that deleting a LUN that is not in use
2438b65f1be6SDavid du Colombier * invalidates all other LUNs too. If your file server has
2439b65f1be6SDavid du Colombier * venti arenas or fossil file systems on 1.0, and you delete 1.1,
2440b65f1be6SDavid du Colombier * since you no longer need it, 1.0 will become inaccessible to your
2441b65f1be6SDavid du Colombier * file server, which will eventually panic. Note that newdev()
2442b65f1be6SDavid du Colombier * does not change the version number.
2443b65f1be6SDavid du Colombier */
2444b65f1be6SDavid du Colombier // newvers(d);
2445b65f1be6SDavid du Colombier
244621abd8f2SDavid du Colombier d->ndl = 0;
24472f205b96SDavid du Colombier qunlock(d);
244821abd8f2SDavid du Colombier for(i = 0; i < d->nframes; i++)
2449a587111cSDavid du Colombier frameerror(d, d->frames+i, Eaoedown);
245021abd8f2SDavid du Colombier
24512f205b96SDavid du Colombier if(p)
245221abd8f2SDavid du Colombier p->next = d->next;
245321abd8f2SDavid du Colombier else
245421abd8f2SDavid du Colombier devs.d = d->next;
245521abd8f2SDavid du Colombier free(d->frames);
245621abd8f2SDavid du Colombier free(d);
245721abd8f2SDavid du Colombier dropunit();
245821abd8f2SDavid du Colombier wunlock(&devs);
245921abd8f2SDavid du Colombier }
246021abd8f2SDavid du Colombier
246121abd8f2SDavid du Colombier static void
removedev(char * name)24622f205b96SDavid du Colombier removedev(char *name)
24632f205b96SDavid du Colombier {
24642f205b96SDavid du Colombier Aoedev *d, *p;
24652f205b96SDavid du Colombier
24662f205b96SDavid du Colombier wlock(&devs);
24672f205b96SDavid du Colombier for(p = d = devs.d; d; p = d, d = d->next)
24682f205b96SDavid du Colombier if(strcmp(name, unitname(d)) == 0) {
24692f205b96SDavid du Colombier wunlock(&devs);
24702f205b96SDavid du Colombier removeaoedev(p);
24712f205b96SDavid du Colombier return;
24722f205b96SDavid du Colombier }
24732f205b96SDavid du Colombier wunlock(&devs);
24742f205b96SDavid du Colombier error("device not bound");
24752f205b96SDavid du Colombier }
24762f205b96SDavid du Colombier
24772f205b96SDavid du Colombier static void
discoverstr(char * f)247821abd8f2SDavid du Colombier discoverstr(char *f)
247921abd8f2SDavid du Colombier {
248021abd8f2SDavid du Colombier ushort shelf, slot;
248121abd8f2SDavid du Colombier ulong sh;
248221abd8f2SDavid du Colombier char *s;
248321abd8f2SDavid du Colombier
248421abd8f2SDavid du Colombier if(f == 0){
248521abd8f2SDavid du Colombier discover(0xffff, 0xff);
248621abd8f2SDavid du Colombier return;
248721abd8f2SDavid du Colombier }
248821abd8f2SDavid du Colombier
248921abd8f2SDavid du Colombier shelf = sh = strtol(f, &s, 0);
249021abd8f2SDavid du Colombier if(s == f || sh > 0xffff)
249121abd8f2SDavid du Colombier error("bad shelf");
249221abd8f2SDavid du Colombier f = s;
249321abd8f2SDavid du Colombier if(*f++ == '.'){
249421abd8f2SDavid du Colombier slot = strtol(f, &s, 0);
249521abd8f2SDavid du Colombier if(s == f || slot > 0xff)
249621abd8f2SDavid du Colombier error("bad shelf");
249721abd8f2SDavid du Colombier }else
249821abd8f2SDavid du Colombier slot = 0xff;
249921abd8f2SDavid du Colombier discover(shelf, slot);
250021abd8f2SDavid du Colombier }
250121abd8f2SDavid du Colombier
250221abd8f2SDavid du Colombier
25032f205b96SDavid du Colombier static void
aoeremove(Chan * c)25042f205b96SDavid du Colombier aoeremove(Chan *c)
25052f205b96SDavid du Colombier {
25062f205b96SDavid du Colombier switch(TYPE(c->qid)){
25072f205b96SDavid du Colombier default:
25082f205b96SDavid du Colombier error(Eperm);
25092f205b96SDavid du Colombier case Qunitdir:
25102f205b96SDavid du Colombier removeaoedev(unit2dev(UNIT(c->qid)));
25112f205b96SDavid du Colombier break;
25122f205b96SDavid du Colombier }
25132f205b96SDavid du Colombier }
25142f205b96SDavid du Colombier
251521abd8f2SDavid du Colombier static long
topctlwrite(void * db,long n)251621abd8f2SDavid du Colombier topctlwrite(void *db, long n)
251721abd8f2SDavid du Colombier {
251821abd8f2SDavid du Colombier enum {
251921abd8f2SDavid du Colombier Autodiscover,
252021abd8f2SDavid du Colombier Bind,
252121abd8f2SDavid du Colombier Debug,
252221abd8f2SDavid du Colombier Discover,
252321abd8f2SDavid du Colombier Rediscover,
252421abd8f2SDavid du Colombier Remove,
252521abd8f2SDavid du Colombier Unbind,
252621abd8f2SDavid du Colombier };
252799c72adcSDavid du Colombier char *f;
252821abd8f2SDavid du Colombier Cmdbuf *cb;
252999c72adcSDavid du Colombier Cmdtab *ct;
253099c72adcSDavid du Colombier static Cmdtab cmds[] = {
253121abd8f2SDavid du Colombier { Autodiscover, "autodiscover", 0 },
253221abd8f2SDavid du Colombier { Bind, "bind", 2 },
253321abd8f2SDavid du Colombier { Debug, "debug", 0 },
253421abd8f2SDavid du Colombier { Discover, "discover", 0 },
253521abd8f2SDavid du Colombier { Rediscover, "rediscover", 0 },
253621abd8f2SDavid du Colombier { Remove, "remove", 2 },
253721abd8f2SDavid du Colombier { Unbind, "unbind", 2 },
253821abd8f2SDavid du Colombier };
253921abd8f2SDavid du Colombier
254021abd8f2SDavid du Colombier cb = parsecmd(db, n);
254121abd8f2SDavid du Colombier if(waserror()){
254221abd8f2SDavid du Colombier free(cb);
254321abd8f2SDavid du Colombier nexterror();
254421abd8f2SDavid du Colombier }
254521abd8f2SDavid du Colombier ct = lookupcmd(cb, cmds, nelem(cmds));
254621abd8f2SDavid du Colombier f = cb->f[1];
254721abd8f2SDavid du Colombier switch(ct->index){
254821abd8f2SDavid du Colombier case Autodiscover:
2549060a30c6SDavid du Colombier autodiscover = toggle(f, autodiscover, 1);
255021abd8f2SDavid du Colombier break;
255121abd8f2SDavid du Colombier case Bind:
255221abd8f2SDavid du Colombier netbind(f);
255321abd8f2SDavid du Colombier break;
255421abd8f2SDavid du Colombier case Debug:
2555060a30c6SDavid du Colombier debug = toggle(f, debug, 1);
255621abd8f2SDavid du Colombier break;
255721abd8f2SDavid du Colombier case Discover:
255821abd8f2SDavid du Colombier discoverstr(f);
255921abd8f2SDavid du Colombier break;
256021abd8f2SDavid du Colombier case Rediscover:
2561060a30c6SDavid du Colombier rediscover = toggle(f, rediscover, 1);
256221abd8f2SDavid du Colombier break;
256321abd8f2SDavid du Colombier case Remove:
256421abd8f2SDavid du Colombier removedev(f);
256521abd8f2SDavid du Colombier break;
256621abd8f2SDavid du Colombier case Unbind:
256721abd8f2SDavid du Colombier netunbind(f);
256821abd8f2SDavid du Colombier break;
256921abd8f2SDavid du Colombier default:
257021abd8f2SDavid du Colombier cmderror(cb, "unknown aoe control message");
257121abd8f2SDavid du Colombier }
257221abd8f2SDavid du Colombier poperror();
257321abd8f2SDavid du Colombier free(cb);
257421abd8f2SDavid du Colombier return n;
257521abd8f2SDavid du Colombier }
257621abd8f2SDavid du Colombier
257721abd8f2SDavid du Colombier static long
aoewrite(Chan * c,void * db,long n,vlong off)257821abd8f2SDavid du Colombier aoewrite(Chan *c, void *db, long n, vlong off)
257921abd8f2SDavid du Colombier {
258021abd8f2SDavid du Colombier switch(TYPE(c->qid)){
258121abd8f2SDavid du Colombier default:
258221abd8f2SDavid du Colombier case Qzero:
258321abd8f2SDavid du Colombier case Qtopdir:
258421abd8f2SDavid du Colombier case Qunitdir:
258521abd8f2SDavid du Colombier case Qtoplog:
258621abd8f2SDavid du Colombier error(Eperm);
258721abd8f2SDavid du Colombier case Qtopctl:
258821abd8f2SDavid du Colombier return topctlwrite(db, n);
258921abd8f2SDavid du Colombier case Qctl:
259021abd8f2SDavid du Colombier case Qdata:
259121abd8f2SDavid du Colombier case Qconfig:
259221abd8f2SDavid du Colombier case Qident:
259321abd8f2SDavid du Colombier return unitwrite(c, db, n, off);
259421abd8f2SDavid du Colombier }
259521abd8f2SDavid du Colombier }
259621abd8f2SDavid du Colombier
259721abd8f2SDavid du Colombier Dev aoedevtab = {
259821abd8f2SDavid du Colombier L'æ',
259921abd8f2SDavid du Colombier "aoe",
260021abd8f2SDavid du Colombier
260121abd8f2SDavid du Colombier devreset,
260221abd8f2SDavid du Colombier devinit,
260321abd8f2SDavid du Colombier devshutdown,
260421abd8f2SDavid du Colombier aoeattach,
260521abd8f2SDavid du Colombier aoewalk,
260621abd8f2SDavid du Colombier aoestat,
260721abd8f2SDavid du Colombier aoeopen,
260821abd8f2SDavid du Colombier devcreate,
260921abd8f2SDavid du Colombier aoeclose,
261021abd8f2SDavid du Colombier aoeread,
261121abd8f2SDavid du Colombier devbread,
261221abd8f2SDavid du Colombier aoewrite,
261321abd8f2SDavid du Colombier devbwrite,
26142f205b96SDavid du Colombier aoeremove,
261521abd8f2SDavid du Colombier devwstat,
261621abd8f2SDavid du Colombier devpower,
261721abd8f2SDavid du Colombier devconfig,
261821abd8f2SDavid du Colombier };
2619