// aoe.c: the ATA over Ethernet virtual EtherDrive (R) blade #include "config.h" #include #include #include #include #include #include #include #include "dat.h" #include "fns.h" // dummy for testing int qcget(uchar *p, int len) { memset(p, 0xff, len); return len; } int qcset(uchar *p, int len) { return len; } void aoead(int fd) // advertise the virtual blade { int len; uchar buf[2000]; Conf *p; p = (Conf *)buf; memset(p, 0, sizeof *p); memset(p->h.dst, 0xff, 6); memmove(p->h.src, mac, 6); p->h.type = htons(0x88a2); p->h.flags = Resp; p->h.maj = htons(shelf); p->h.min = slot; p->h.cmd = Config; p->bufcnt = htons(Bufcount); p->firmware = htons(FWV); p->vercmd = 0x10 | Qread; len = qcget(p->data, 1024); p->len = htons(len); if (write(fd, buf, len) == -1) perror("write aoe id"); } int isbcast(uchar *ea) // replace with assembler routine { uchar *b = (uchar *)"\377\377\377\377\377\377"; return memcmp(ea, b, 6) == 0; } long long getlba(uchar *p) { vlong v; int i; v = 0; for (i = 0; i < 6; i++) v |= (vlong)(*p++) << i * 8; return v; } int aoeata(Ata *p) // do ATA reqeust { Ataregs r; int len = 60; if (p->sectors && (p->aflag & Write) == 0) len = sizeof (Ata); r.lba = getlba(p->lba); r.sectors = p->sectors; r.feature = p->err; r.cmd = p->cmd; atacmd(&r, p->data); p->sectors = r.sectors; p->err = r.err; p->cmd = r.status; return len; } int confcmd(Conf *p) // process conf request { uchar buf[1024]; int len = 0, len2; switch (p->vercmd & 0xf) { case Qread: len = qcget(p->data, 1024); p->len = htons(len); break; case Qtest: len = qcget(buf, 1024); if (len != ntohs(p->len)) return 0; if (memcmp(buf, p->data, len) != 0) return 0; memmove(p->data, buf, len); break; case Qprefix: len = qcget(buf, 1024); len2 = ntohs(p->len); if (len2 > len) return 0; if (memcmp(buf, p->data, len2) != 0) return 0; memmove(p->data, buf, len); p->len = htons(len); break; case Qset: if (qcget(buf, 1024) > 0) { p->h.flags |= Error; p->h.error = ConfigErr; break; } len = 1024; // fall thru case Qfset: len = ntohs(p->len); qcset(p->data, len); break; default: p->h.flags |= BadArg; } p->bufcnt = htons(Bufcount); p->firmware = htons(FWV); p->vercmd |= 0x10; return len; } void doaoe(Aoehdr *p) { int len; switch (p->cmd) { case ATAcmd: len = aoeata((Ata*)p); break; case Config: if ((len = confcmd((Conf *)p)) == 0) return; break; default: p->error = BadCmd; len = 1024; break; } memmove(p->dst, p->src, 6); memmove(p->src, mac, 6); p->maj = htons(shelf); p->min = slot; p->flags |= Resp; if (write(sfd, p, len) == -1) { perror("write to network"); exit(1); } } void aoe(void) { Aoehdr *p; uchar buf[1400]; int n, sh; aoead(sfd); for (;;) { n = read(sfd, buf, sizeof buf); if (n < 0) { perror("read network"); exit(1); } if (n < 60) continue; p = (Aoehdr *)buf; if (ntohs(p->type) != 0x88a2) continue; if (p->flags & Resp) continue; sh = ntohs(p->maj); if (sh != shelf && sh != (ushort)~0) continue; if (p->min != slot && p->min != (uchar)~0) continue; doaoe(p); } } void usage(void) { fprintf(stderr, "usage: %s \n", progname); exit(1); } int main(int argc, char **argv) { setbuf(stdin, NULL); progname = *argv; if (argc != 5) usage(); bfd = open(argv[4], O_RDWR); if (bfd == -1) { perror("open"); exit(1); } shelf = atoi(argv[1]); slot = atoi(argv[2]); size = getsize(bfd); size /= 512; sfd = dial(argv[3]); getea(sfd, argv[3], mac); printf("pid %ld: e%d.%d, %lld sectors\n", (long) getpid(), shelf, slot, size); fflush(stdout); aoe(); return 0; }