2 * vblade -- virtual aoe target
3 * copyright © 2007 erik quanstrom
9 #include <ip.h> /* irony */
13 Eaddrlen = 6, /* only defined in kernel */
45 char pad[512-32-32-16-6];
60 static Vblade vblade[Nvblade];
63 static char *ethertab[Nether] = {
66 static int etheridx = 1;
67 static int efdtab[Nether*Flast];
68 static char pkttab[Nether][Maxpkt];
69 static char bctab[Nether][Maxpkt];
70 static int mtutab[Nether];
71 static char Magic[] = "aoe vblade\n";
79 snprint(buf, sizeof buf, "%s/mtu", p);
80 if((fd = open(buf, OREAD)) == -1)
82 if(read(fd, buf, 36) < 0)
86 mtu = strtoul(buf+12, 0, 0)-Aoehsz;
91 parseshelf(char *s, int *shelf, int *slot)
95 a = strtoul(s, &s, 0);
98 b = strtoul(s, &s, 0);
109 static char tab[] = "ptgmk";
113 v = strtoull(s, &s, 0);
114 while((p = strchr(tab, *s++)) && *p)
123 sizetolba(vlong size)
125 if(size < 512 || size & 0x1ff){
126 fprint(2, "invalid size %lld\n", size);
133 savevblade(int fd, Vblade *vb)
138 sprint(vb->hdr.size, "%lld", vb->maxlba<<9);
139 sprint(vb->hdr.address, "%d.%d", vb->shelf, vb->slot);
140 sprint(vb->hdr.configlen, "%d", vb->clen);
145 for(n = 0; n < sizeof *vb; n += r)
146 if((r = pwrite(fd, p+n, sizeof *vb-n, n)) <= 0)
154 chkvblade(int fd, Vblade *vb)
159 if(readn(fd, (char*)h, sizeof *h) != sizeof *h)
161 if(memcmp(h->magic, Magic, sizeof Magic))
163 h->size[sizeof h->size-1] = 0;
164 vb->maxlba = sizetolba(strtoull(h->size, 0, 0));
165 if(parseshelf(h->address, &vb->shelf, &vb->slot) == -1)
167 h->configlen[sizeof h->configlen-1] = 0;
168 vb->clen = strtoul(h->configlen, 0, 0);
173 checkfile(char *s, Vblade *vb, int iflag)
177 vb->fd = open(s, ORDWR);
179 sysfatal("can't open backing store: %r");
180 if(iflag == 0 && (e = chkvblade(vb->fd, vb)))
181 sysfatal("invalid vblade %s", e);
185 recheck(int fd, Vblade *vb)
192 sysfatal("can't stat: %r");
193 if((vb->flag & Fraw) == 0)
195 v = sizetolba(d->length & ~0x1ff) - vb->hdrsz;
198 sysfatal("cmdline size too large (%lld sector overhead)", vb->hdrsz);
206 aoeopen(char *e, int fds[])
208 char buf[128], ctl[13];
211 snprint(buf, sizeof buf, "%s/clone", e);
212 if((fds[Fclone] = open(buf, ORDWR)) == -1)
214 memset(ctl, 0, sizeof ctl);
215 if(read(fds[Fclone], ctl, sizeof ctl - 1) < 0)
218 snprint(buf, sizeof buf, "connect %d", Aoetype);
219 if(write(fds[Fclone], buf, strlen(buf)) != strlen(buf))
221 snprint(buf, sizeof buf, "%s/%d/data", e, n);
222 fds[Fdata] = open(buf, ORDWR);
227 replyhdr(Aoehdr *h, Vblade *vblade)
231 memmove(ea, h->dst, Eaddrlen);
232 memmove(h->dst, h->src, Eaddrlen);
233 memmove(h->src, ea, Eaddrlen);
235 hnputs(h->major, vblade->shelf);
236 h->minor = vblade->slot;
241 serveconfig(Aoehdr *h, Vblade *vb, int mtu)
243 int cmd, reqlen, len;
247 if(memcmp(h->src, h->dst, Eaddrlen) == 0)
250 q = (Aoeqc*)((char*)h + Aoehsz);
251 reqlen = nhgets(q->cslen);
253 cmd = q->verccmd&0xf;
254 cfg = (char*)q + Aoecfgsz;
263 if(memcmp(vb->hdr.config, cfg, reqlen) != 0)
268 if(len && len != reqlen || memcmp(vb->hdr.config, cfg, reqlen) != 0){
274 if(reqlen > Conflen){
279 memset(vb->hdr.config, 0, sizeof vb->hdr.config);
280 memmove(vb->hdr.config, cfg, reqlen);
281 vb->clen = len = reqlen;
282 savevblade(vb->fd, vb);
289 memmove(cfg, vb->hdr.config, len);
290 hnputs(q->cslen, len);
291 hnputs(q->bufcnt, 24);
293 hnputs(q->fwver, 2323);
294 q->verccmd = Aoever<<4 | cmd;
296 return Aoehsz+Aoecfgsz + len;
299 static ushort ident[256] = {
311 idmoveto(char *a, int idx, int len, char *s)
316 for(; len > 0; len -= 2) {
330 lbamoveto(char *p, int idx, int n, vlong lba)
335 for(i = 0; i < n; i++)
356 v |= (uvlong)p[4]<<32;
357 v |= (uvlong)p[5]<<40;
362 putlba(uchar *p, vlong lba)
373 serveata(Aoehdr *h, Vblade *vb, int mtu)
377 int rbytes, bytes, len;
380 a = (Aoeata*)((char*)h + Aoehsz);
381 buf = (char*)a + Aoeatasz;
382 lba = getlba(a->lba);
384 off = lba+vb->hdrsz<<9;
387 if(a->scnt > mtu || a->scnt == 0){
389 a->cmdstat = ASdrdy|ASerr;
394 if(a->cmdstat != Cid)
395 if(lba+a->scnt > vb->maxlba){
397 a->cmdstat = ASdrdy|ASerr;
401 if(a->cmdstat&0xf0 == 0x20)
406 a->cmdstat = ASdrdy|ASerr;
409 memmove(buf, ident, sizeof ident);
410 idmoveto(buf, 27, 40, "Plan 9 Vblade");
411 idmoveto(buf, 10, 20, "serial#");
412 idmoveto(buf, 23, 8, "2");
413 lbamoveto(buf, 60, 4, vb->maxlba);
414 lbamoveto(buf, 100, 8, vb->maxlba);
420 bytes = pread(vb->fd, buf, len, off);
425 bytes = pwrite(vb->fd, buf, len, off);
430 a->cmdstat = ASdf|ASerr;
431 putlba(a->lba, lba+(len-bytes)>>9);
436 putlba(a->lba, lba+a->scnt);
441 return Aoehsz+Aoeatasz + rbytes;
445 myea(uchar ea[6], char *p)
450 snprint(buf, sizeof buf, "%s/addr", p);
451 if((fd = open(buf, OREAD)) == -1)
453 if(read(fd, buf, 12) < 12)
456 return parseether(ea, buf);
460 bcastpkt(Aoehdr *h, uint shelf, uint slot, int i)
462 myea(h->dst, ethertab[i]);
463 memset(h->src, 0xff, Eaddrlen);
464 hnputs(h->type, Aoetype);
465 hnputs(h->major, shelf);
468 h->tag[0] = h->tag[1] = h->tag[2] = h->tag[3] = 0;
472 bladereply(Vblade *v, int i, int fd, char *pkt)
480 n = serveata(h, v, mtutab[i]);
483 n = serveconfig(h, v, mtutab[i]);
493 memset(pkt+n, 0, 60-n);
496 if(write(fd, h, n) != n){
497 fprint(2, "write to %s failed: %r\n", ethertab[i]);
506 int i, j, popcnt, vec, n, s, efd;
510 fmtinstall('E', eipfmt);
513 efd = efdtab[i*Flast+Fdata];
519 bcastpkt(h, 0xffff, 0xff, i);
523 n = read(efd, pkt, Maxpkt);
525 if(n < 60 || h->verflag & AFrsp)
527 s = nhgets(h->major);
530 for(j = 0; j < nblade; j++){
531 if((vblade[j].shelf == s || s == 0xffff)
532 && (vblade[j].slot == h->minor || h->minor == 0xff)){
537 for(j = 0; popcnt>0 && j < nblade; j++){
538 if((vec & 1<<j) == 0)
541 memcpy(bcpkt, pkt, n);
542 bladereply(vblade + j, i, efd, bcpkt);
544 bladereply(vblade + j, i, efd, pkt);
551 launch(char *tab[], int fdtab[])
555 for(i = 0; tab[i]; i++){
556 if(aoeopen(tab[i], fdtab+Flast*i) < 0)
557 sysfatal("network open: %r");
559 * use proc not threads. otherwise we will block on read/write.
561 proccreate(serve, (void*)i, 32*1024);
568 fprint(2, "vblade [-ir] [-s size] [-a shelf.slot] [-c config] [-e ether] file\n");
573 goblade(Vblade *vblade, char *file, Conf *c)
578 memcpy(vblade->hdr.magic, Magic, sizeof Magic);
579 checkfile(file, vblade, c->iflag);
581 vblade->flag = c->flag;
583 vblade->shelf = c->shelf;
584 vblade->slot = c->slot;
587 vblade->maxlba = c->maxlba;
589 memmove(vblade->hdr.config, c->config, vblade->clen = strlen(c->config));
591 recheck(vblade->fd, vblade);
594 if(vblade->maxlba > 1)
596 fprint(2, "lblade %d.%d %lld sector%s\n", vblade->shelf, vblade->slot, vblade->maxlba, anal);
600 threadmain(int argc, char **argv)
607 if(nblade == nelem(vblade))
608 sysfatal("too many blades");
609 c = (Conf){0, 0, -1, -1, 0, nil};
614 if(parseshelf(EARGF(usage()), &c.shelf, &c.slot) == -1)
615 sysfatal("bad vblade address");
619 c.config = EARGF(usage());
625 if(etheridx == nelem(ethertab))
626 sysfatal("too many interfaces");
627 ethertab[etheridx++] = EARGF(usage());
640 c.maxlba = sizetolba(getsize(EARGF(usage())));
647 if(argc == 0 && lastc == 'e')
651 goblade(vblade + nblade++, *argv, &c);
658 for(i = 0; i < etheridx; i++)
659 mtutab[i] = getmtu(ethertab[i]);
661 launch(ethertab, efdtab);
663 for(; sleep(1*1000) != -1;)
665 threadexitsall("interrupted");