aoe.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  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) // 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) < 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) // process conf request
  100. {
  101. int len;
  102. len = ntohs(p->len);
  103. if (QCMD(p) != Qread)
  104. if (len > Nconfig)
  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)
  145. {
  146. int len;
  147. switch (p->cmd) {
  148. case ATAcmd:
  149. len = aoeata((Ata*)p);
  150. break;
  151. case Config:
  152. len = confcmd((Conf *)p);
  153. if (len == 0)
  154. return;
  155. break;
  156. default:
  157. p->error = BadCmd;
  158. len = 1024;
  159. break;
  160. }
  161. memmove(p->dst, p->src, 6);
  162. memmove(p->src, mac, 6);
  163. p->maj = htons(shelf);
  164. p->min = slot;
  165. p->flags |= Resp;
  166. if (putpkt(sfd, (uchar *) p, len) == -1) {
  167. perror("write to network");
  168. exit(1);
  169. }
  170. }
  171. void
  172. aoe(void)
  173. {
  174. Aoehdr *p;
  175. uchar *buf;
  176. int n, sh;
  177. enum { bufsz = 1<<16, };
  178. buf = malloc(bufsz);
  179. aoead(sfd);
  180. for (;;) {
  181. n = getpkt(sfd, buf, bufsz);
  182. if (n < 0) {
  183. perror("read network");
  184. exit(1);
  185. }
  186. if (n < 60)
  187. continue;
  188. p = (Aoehdr *) buf;
  189. if (ntohs(p->type) != 0x88a2)
  190. continue;
  191. if (p->flags & Resp)
  192. continue;
  193. sh = ntohs(p->maj);
  194. if (sh != shelf && sh != (ushort)~0)
  195. continue;
  196. if (p->min != slot && p->min != (uchar)~0)
  197. continue;
  198. if (nmasks && !maskok(p->src))
  199. continue;
  200. doaoe(p);
  201. }
  202. free(buf);
  203. }
  204. void
  205. usage(void)
  206. {
  207. fprintf(stderr, "usage: %s [ -m mac[,mac...] ] shelf slot netif filename\n",
  208. progname);
  209. exit(1);
  210. }
  211. /* parseether from plan 9 */
  212. int
  213. parseether(uchar *to, char *from)
  214. {
  215. char nip[4];
  216. char *p;
  217. int i;
  218. p = from;
  219. for(i = 0; i < 6; i++){
  220. if(*p == 0)
  221. return -1;
  222. nip[0] = *p++;
  223. if(*p == 0)
  224. return -1;
  225. nip[1] = *p++;
  226. nip[2] = 0;
  227. to[i] = strtoul(nip, 0, 16);
  228. if(*p == ':')
  229. p++;
  230. }
  231. return 0;
  232. }
  233. void
  234. setmask(char *ml)
  235. {
  236. char *p;
  237. int n;
  238. for (; ml; ml=p) {
  239. p = strchr(ml, ',');
  240. if (p)
  241. *p++ = '\0';
  242. n = parseether(&masks[nmasks*Alen], ml);
  243. if (n < 0)
  244. fprintf(stderr, "ignoring mask %s, parseether failure\n", ml);
  245. else
  246. nmasks++;
  247. }
  248. }
  249. int
  250. maskok(uchar *ea)
  251. {
  252. int i, ok = 0;
  253. for (i=0; !ok && i<nmasks; i++)
  254. ok = memcmp(ea, &masks[i*Alen], Alen) == 0;
  255. return ok;
  256. }
  257. int
  258. main(int argc, char **argv)
  259. {
  260. int ch, omode = O_RDONLY;
  261. struct stat s;
  262. setbuf(stdin, NULL);
  263. atainit();
  264. progname = *argv;
  265. while ((ch = getopt(argc, argv, "m:")) != -1) {
  266. switch (ch) {
  267. case 'm':
  268. setmask(optarg);
  269. break;
  270. case '?':
  271. default:
  272. usage();
  273. }
  274. }
  275. argc -= optind;
  276. argv += optind;
  277. if (argc != 4)
  278. usage();
  279. if (stat(argv[3], &s) < 0) {
  280. perror("stat");
  281. exit(1);
  282. }
  283. if (s.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH))
  284. omode = O_RDWR;
  285. bfd = open(argv[3], omode);
  286. if (bfd == -1) {
  287. perror("open");
  288. exit(1);
  289. }
  290. shelf = atoi(argv[0]);
  291. slot = atoi(argv[1]);
  292. size = getsize(bfd);
  293. size /= 512;
  294. ifname = argv[2];
  295. sfd = dial(ifname);
  296. getea(sfd, ifname, mac);
  297. printf("pid %ld: e%d.%d, %lld sectors %s\n",
  298. (long) getpid(), shelf, slot, size,
  299. omode == O_RDWR ? "O_RDWR" : "O_RDONLY");
  300. fflush(stdout);
  301. aoe();
  302. return 0;
  303. }