aoe.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. // aoe.c: the ATA over Ethernet virtual EtherDrive (R) blade
  2. #include "config.h"
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <stdlib.h>
  6. #include <unistd.h>
  7. #include <sys/types.h>
  8. #include <sys/stat.h>
  9. #include <fcntl.h>
  10. #include <netinet/in.h>
  11. #include "dat.h"
  12. #include "fns.h"
  13. enum {
  14. Nmasks= 32,
  15. Alen= 6,
  16. };
  17. uchar masks[Nmasks*Alen];
  18. int nmasks;
  19. char config[Nconfig];
  20. int nconfig = 0;
  21. int maxscnt = 2;
  22. char *ifname;
  23. void
  24. aoead(int fd) // advertise the virtual blade
  25. {
  26. uchar buf[2000];
  27. Conf *p;
  28. int i;
  29. p = (Conf *)buf;
  30. memset(p, 0, sizeof *p);
  31. memset(p->h.dst, 0xff, 6);
  32. memmove(p->h.src, mac, 6);
  33. p->h.type = htons(0x88a2);
  34. p->h.flags = Resp;
  35. p->h.maj = htons(shelf);
  36. p->h.min = slot;
  37. p->h.cmd = Config;
  38. p->bufcnt = htons(Bufcount);
  39. p->scnt = maxscnt = (getmtu(sfd, ifname) - sizeof (Ata)) / 512;
  40. p->firmware = htons(FWV);
  41. p->vercmd = 0x10 | Qread;
  42. memcpy(p->data, config, nconfig);
  43. p->len = htons(nconfig);
  44. if (nmasks == 0)
  45. if (putpkt(fd, buf, sizeof *p - sizeof p->data + nconfig) == -1) {
  46. perror("putpkt aoe id");
  47. return;
  48. }
  49. for (i=0; i<nmasks; i++) {
  50. memcpy(p->h.dst, &masks[i*Alen], Alen);
  51. if (putpkt(fd, buf, sizeof *p - sizeof p->data + nconfig) == -1)
  52. perror("putpkt aoe id");
  53. }
  54. }
  55. int
  56. isbcast(uchar *ea) // replace with assembler routine
  57. {
  58. uchar *b = (uchar *)"\377\377\377\377\377\377";
  59. return memcmp(ea, b, 6) == 0;
  60. }
  61. long long
  62. getlba(uchar *p)
  63. {
  64. vlong v;
  65. int i;
  66. v = 0;
  67. for (i = 0; i < 6; i++)
  68. v |= (vlong)(*p++) << i * 8;
  69. return v;
  70. }
  71. int
  72. aoeata(Ata *p, int pktlen) // do ATA reqeust
  73. {
  74. Ataregs r;
  75. int len = 60;
  76. int n;
  77. r.lba = getlba(p->lba);
  78. r.sectors = p->sectors;
  79. r.feature = p->err;
  80. r.cmd = p->cmd;
  81. if (atacmd(&r, (uchar *)(p+1), maxscnt*512, pktlen - sizeof(*p)) < 0) {
  82. p->h.flags |= Error;
  83. p->h.error = BadArg;
  84. return len;
  85. }
  86. if (!(p->aflag & Write))
  87. if ((n = p->sectors)) {
  88. n -= r.sectors;
  89. len = sizeof (Ata) + (n*512);
  90. }
  91. p->sectors = r.sectors;
  92. p->err = r.err;
  93. p->cmd = r.status;
  94. return len;
  95. }
  96. #define QCMD(x) ((x)->vercmd & 0xf)
  97. // yes, this makes unnecessary copies.
  98. int
  99. confcmd(Conf *p, int payload) // process conf request
  100. {
  101. int len;
  102. len = ntohs(p->len);
  103. if (QCMD(p) != Qread)
  104. if (len > Nconfig || len > payload)
  105. return 0; // if you can't play nice ...
  106. switch (QCMD(p)) {
  107. case Qtest:
  108. if (len != nconfig)
  109. return 0;
  110. // fall thru
  111. case Qprefix:
  112. if (len > nconfig)
  113. return 0;
  114. if (memcmp(config, p->data, len))
  115. return 0;
  116. // fall thru
  117. case Qread:
  118. break;
  119. case Qset:
  120. if (nconfig)
  121. if (nconfig != len || memcmp(config, p->data, len)) {
  122. p->h.flags |= Error;
  123. p->h.error = ConfigErr;
  124. break;
  125. }
  126. // fall thru
  127. case Qfset:
  128. nconfig = len;
  129. memcpy(config, p->data, nconfig);
  130. break;
  131. default:
  132. p->h.flags |= Error;
  133. p->h.error = BadArg;
  134. }
  135. memmove(p->data, config, nconfig);
  136. p->len = htons(nconfig);
  137. p->bufcnt = htons(Bufcount);
  138. p->scnt = maxscnt = (getmtu(sfd, ifname) - sizeof (Ata)) / 512;
  139. p->firmware = htons(FWV);
  140. p->vercmd = 0x10 | QCMD(p); // aoe v.1
  141. return nconfig + sizeof *p - sizeof p->data;
  142. }
  143. void
  144. doaoe(Aoehdr *p, int n)
  145. {
  146. int len;
  147. enum { // config query header size
  148. CHDR_SIZ = sizeof(Conf) - sizeof(((Conf *)0)->data),
  149. };
  150. switch (p->cmd) {
  151. case ATAcmd:
  152. if (n < sizeof(Ata))
  153. return;
  154. len = aoeata((Ata*)p, n);
  155. break;
  156. case Config:
  157. if (n < CHDR_SIZ)
  158. return;
  159. len = confcmd((Conf *)p, n - CHDR_SIZ);
  160. if (len == 0)
  161. return;
  162. break;
  163. default:
  164. p->error = BadCmd;
  165. len = 1024;
  166. break;
  167. }
  168. memmove(p->dst, p->src, 6);
  169. memmove(p->src, mac, 6);
  170. p->maj = htons(shelf);
  171. p->min = slot;
  172. p->flags |= Resp;
  173. if (putpkt(sfd, (uchar *) p, len) == -1) {
  174. perror("write to network");
  175. exit(1);
  176. }
  177. }
  178. void
  179. aoe(void)
  180. {
  181. Aoehdr *p;
  182. uchar *buf;
  183. int n, sh;
  184. enum { bufsz = 1<<16, };
  185. buf = malloc(bufsz);
  186. aoead(sfd);
  187. for (;;) {
  188. n = getpkt(sfd, buf, bufsz);
  189. if (n < 0) {
  190. perror("read network");
  191. exit(1);
  192. }
  193. if (n < sizeof(Aoehdr))
  194. continue;
  195. p = (Aoehdr *) buf;
  196. if (ntohs(p->type) != 0x88a2)
  197. continue;
  198. if (p->flags & Resp)
  199. continue;
  200. sh = ntohs(p->maj);
  201. if (sh != shelf && sh != (ushort)~0)
  202. continue;
  203. if (p->min != slot && p->min != (uchar)~0)
  204. continue;
  205. if (nmasks && !maskok(p->src))
  206. continue;
  207. doaoe(p, n);
  208. }
  209. free(buf);
  210. }
  211. void
  212. usage(void)
  213. {
  214. fprintf(stderr, "usage: %s [ -m mac[,mac...] ] shelf slot netif filename\n",
  215. progname);
  216. exit(1);
  217. }
  218. /* parseether from plan 9 */
  219. int
  220. parseether(uchar *to, char *from)
  221. {
  222. char nip[4];
  223. char *p;
  224. int i;
  225. p = from;
  226. for(i = 0; i < 6; i++){
  227. if(*p == 0)
  228. return -1;
  229. nip[0] = *p++;
  230. if(*p == 0)
  231. return -1;
  232. nip[1] = *p++;
  233. nip[2] = 0;
  234. to[i] = strtoul(nip, 0, 16);
  235. if(*p == ':')
  236. p++;
  237. }
  238. return 0;
  239. }
  240. void
  241. setmask(char *ml)
  242. {
  243. char *p;
  244. int n;
  245. for (; ml; ml=p) {
  246. p = strchr(ml, ',');
  247. if (p)
  248. *p++ = '\0';
  249. n = parseether(&masks[nmasks*Alen], ml);
  250. if (n < 0)
  251. fprintf(stderr, "ignoring mask %s, parseether failure\n", ml);
  252. else
  253. nmasks++;
  254. }
  255. }
  256. int
  257. maskok(uchar *ea)
  258. {
  259. int i, ok = 0;
  260. for (i=0; !ok && i<nmasks; i++)
  261. ok = memcmp(ea, &masks[i*Alen], Alen) == 0;
  262. return ok;
  263. }
  264. int
  265. main(int argc, char **argv)
  266. {
  267. int ch, omode = O_RDONLY;
  268. struct stat s;
  269. setbuf(stdin, NULL);
  270. atainit();
  271. progname = *argv;
  272. while ((ch = getopt(argc, argv, "m:")) != -1) {
  273. switch (ch) {
  274. case 'm':
  275. setmask(optarg);
  276. break;
  277. case '?':
  278. default:
  279. usage();
  280. }
  281. }
  282. argc -= optind;
  283. argv += optind;
  284. if (argc != 4)
  285. usage();
  286. if (stat(argv[3], &s) < 0) {
  287. perror("stat");
  288. exit(1);
  289. }
  290. if (s.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH))
  291. omode = O_RDWR;
  292. bfd = open(argv[3], omode);
  293. if (bfd == -1) {
  294. perror("open");
  295. exit(1);
  296. }
  297. shelf = atoi(argv[0]);
  298. slot = atoi(argv[1]);
  299. size = getsize(bfd);
  300. size /= 512;
  301. ifname = argv[2];
  302. sfd = dial(ifname);
  303. getea(sfd, ifname, mac);
  304. printf("pid %ld: e%d.%d, %lld sectors %s\n",
  305. (long) getpid(), shelf, slot, size,
  306. omode == O_RDWR ? "O_RDWR" : "O_RDONLY");
  307. fflush(stdout);
  308. aoe();
  309. return 0;
  310. }