aoeping.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. /* aoeping.c - userland aoe pinger
  2. *
  3. * run without arguments for usage
  4. */
  5. #include <stdio.h>
  6. #include <string.h>
  7. #include <stdlib.h>
  8. #include <unistd.h>
  9. #include <stdint.h>
  10. #include <ctype.h>
  11. #include <netinet/in.h>
  12. #include <errno.h>
  13. #include "dat.h"
  14. #include "fns.h"
  15. struct progopts {
  16. int shelf;
  17. int slot;
  18. char *netif;
  19. int verbose;
  20. int timeout;
  21. u32 tag;
  22. char *smart;
  23. char ata_ident;
  24. };
  25. static struct progopts defaults = {
  26. .shelf = 0,
  27. .slot = 0,
  28. .netif = NULL,
  29. .verbose = 0,
  30. .timeout = 0,
  31. .tag = 0,
  32. .smart = NULL,
  33. .ata_ident = 0,
  34. };
  35. static struct progopts opts;
  36. struct smartcmd {
  37. char *name; /* subcommand name from ATA spec */
  38. int cmd; /* for features register */
  39. char data; /* does this subcommand xfer data? */
  40. };
  41. static struct smartcmd smarts[] = {
  42. { "read_data", 0xd0, SmartDataRet },
  43. // { "attr_autosave", 0xd2, 0 }, (unsupported b/c it overloads sector count)
  44. { "offline_immediate", 0xd4, 0 },
  45. { "read_log", 0xd5, SmartDataRet },
  46. { "write_log", 0xd6, SmartDataPut },
  47. { "enable", 0xd8, 0 },
  48. { "disable", 0xd9, 0 },
  49. { "return_status", 0xda, 0 },
  50. };
  51. static char *progname;
  52. static int sfd; /* raw socket file descriptor */
  53. static uchar mac[6];
  54. #if 0
  55. void
  56. show_opts(struct progopts *opts)
  57. {
  58. printf("shelf: %d\n", opts->shelf);
  59. printf("slot: %d\n", opts->slot);
  60. printf("netif: %s\n", opts->netif);
  61. printf("verbose: %d\n", opts->verbose);
  62. printf("timeout: %d\n", opts->timeout);
  63. printf("tag: %d\n", opts->tag);
  64. printf("ata_ident: %d\n", (int) opts->ata_ident);
  65. }
  66. #endif
  67. void
  68. usage(void)
  69. {
  70. fprintf(stderr,
  71. "usage:\t%s [options] {shelf} {slot} {netif}\n",
  72. progname);
  73. fprintf(stderr, "%s\n\t%s\n\t%s\n\t%s\n",
  74. "options:",
  75. "-i\tdo ATA device identify",
  76. "-v\tbe verbose",
  77. "-h\tshow this usage summary");
  78. fprintf(stderr, "%s\n\t%s\n\t%s\n\t%s\n",
  79. "options taking arguments:",
  80. "-s\ttimeout in seconds",
  81. "-S\tperform SMART command",
  82. "-t\tspecify number for starting AoE tag");
  83. }
  84. void
  85. hex_print(FILE *out, char *buf, int n, char *sep)
  86. {
  87. int i;
  88. int per_line = 16;
  89. for (i = 0; i < n;) {
  90. fprintf(out, "%02x%s", *buf++ & 0xff, sep);
  91. if (!(++i % per_line))
  92. putc('\n', out);
  93. }
  94. }
  95. void
  96. find_blade(Conf *c, int shelf, int slot)
  97. {
  98. int n;
  99. uchar buf[1400];
  100. Aoehdr *h = &c->h;
  101. memset(h, 0, sizeof *h);
  102. memset(h->dst, 0xff, sizeof h->dst);
  103. memmove(h->src, mac, sizeof h->src);
  104. h->type = htons(AOE_ETH_PROTO);
  105. h->flags = AoEver << 4;
  106. h->maj = htons(shelf);
  107. h->min = slot;
  108. h->cmd = Config;
  109. c->bufcnt = 3;
  110. c->vercmd = 0x10 | Qread;
  111. memset(c->data, 0xED, sizeof c->data);
  112. c->len = htons(1024);
  113. if (write(sfd, c, sizeof *c) == -1) {
  114. perror("send config query");
  115. exit(EXIT_FAILURE);
  116. }
  117. for (;;) {
  118. n = read(sfd, buf, sizeof buf);
  119. if (n < 0) {
  120. perror("read network");
  121. exit(EXIT_FAILURE);
  122. }
  123. if (n < 60)
  124. continue;
  125. h = (Aoehdr *) buf;
  126. if (ntohs(h->type) != AOE_ETH_PROTO
  127. || ntohs(h->maj) != shelf
  128. || h->min != slot)
  129. continue;
  130. break;
  131. }
  132. if (opts.verbose) {
  133. puts("config query response:");
  134. hex_print(stdout, buf, n, " ");
  135. putchar('\n');
  136. }
  137. memcpy(c, buf, sizeof *c);
  138. }
  139. /* read a packet that was sent by the device that returned *c earlier
  140. */
  141. int
  142. aoe_pkt_read(int fd, char *buf, size_t siz, Conf *c)
  143. {
  144. Aoehdr *h;
  145. int n;
  146. for (;;) {
  147. n = read(fd, buf, siz);
  148. if (n < 0) {
  149. perror("read network");
  150. exit(EXIT_FAILURE);
  151. }
  152. if (n < 60)
  153. continue;
  154. h = (Aoehdr *) buf;
  155. if (ntohs(h->type) != AOE_ETH_PROTO
  156. || h->maj != c->h.maj
  157. || h->min != c->h.min)
  158. continue;
  159. break;
  160. }
  161. return n;
  162. }
  163. /* prepare a packet for doing ATA to a device that gave us Conf *c
  164. */
  165. void
  166. ata_prep(Ata *a, Conf *c, u32 tag)
  167. {
  168. memset(a, 0, sizeof *a);
  169. memcpy(a->h.dst, c->h.src, sizeof a->h.dst);
  170. memcpy(a->h.src, mac, sizeof a->h.src);
  171. a->h.type = htons(AOE_ETH_PROTO);
  172. a->h.flags = AoEver << 4;
  173. a->h.maj = c->h.maj;
  174. a->h.min = c->h.min;
  175. a->h.cmd = ATAcmd;
  176. tag = htonl(tag);
  177. memmove(a->h.tag, &tag, sizeof a->h.tag);
  178. }
  179. void
  180. disk_identify(Conf *c, u32 tag)
  181. {
  182. int n;
  183. uchar buf[1400];
  184. Ata a;
  185. Ata *p;
  186. ata_prep(&a, c, tag);
  187. a.sectors = 1;
  188. a.cmd = ATAid_dev;
  189. a.lba[3] = 0xa0;
  190. if (write(sfd, &a, sizeof a) == -1) {
  191. perror("send ATA identify device");
  192. exit(EXIT_FAILURE);
  193. }
  194. n = aoe_pkt_read(sfd, buf, sizeof buf, c);
  195. p = (Ata *) buf;
  196. puts("device identify response:");
  197. hex_print(stdout, p->data, 512, " ");
  198. }
  199. struct smartcmd *
  200. smartcmd_lookup(char *nam)
  201. {
  202. int n = sizeof smarts / sizeof smarts[0];
  203. int i;
  204. for (i = 0; i < n; ++i) {
  205. char *p = strchr(nam, ':');
  206. if (p && !strncmp(smarts[i].name, nam, p - nam))
  207. return &smarts[i];
  208. else if (!strcmp(smarts[i].name, nam))
  209. return &smarts[i];
  210. }
  211. return nil;
  212. }
  213. void
  214. smart_registers(Ata *a, char *opts, struct smartcmd *s)
  215. {
  216. a->err = s->cmd;
  217. a->lba[1] = 0x4f;
  218. a->lba[2] = 0xc2;
  219. if (opts++)
  220. a->lba[0] = strtol(opts, NULL, 0);
  221. }
  222. void
  223. show_smart_regs(Ata *a)
  224. {
  225. puts("ATA registers:");
  226. char *names[] = {
  227. "Features", "Sector Count",
  228. "LBA Low", "LBA Mid", "LBA High",
  229. "Status",
  230. };
  231. int regs[] = {
  232. a->err, a->sectors,
  233. a->lba[0], a->lba[1], a->lba[2],
  234. a->cmd,
  235. };
  236. int i;
  237. for (i = 0; i < sizeof regs / sizeof regs[0]; ++i)
  238. printf("%20s: 0x%02x\n", names[i], regs[i]);
  239. }
  240. void
  241. smart(Conf *c, u32 tag, char *smart_cmd)
  242. {
  243. int n;
  244. uchar buf[1400];
  245. Ata a;
  246. Ata *p;
  247. struct smartcmd *s = smartcmd_lookup(smart_cmd);
  248. if (!s) {
  249. fprintf(stderr,
  250. "%s Error: no such SMART command: %s\n",
  251. progname, smart_cmd);
  252. exit(EXIT_FAILURE);
  253. }
  254. ata_prep(&a, c, tag);
  255. a.sectors = !!s->data; /* we only support one-sector data xfer */
  256. a.cmd = ATAsmart;
  257. smart_registers(&a, strchr(smart_cmd, ':'), s);
  258. if (s->data & SmartDataPut) {
  259. if (read(STDIN_FILENO, a.data, 512) == -1) {
  260. perror("reading smart data from stdin");
  261. exit(EXIT_FAILURE);
  262. }
  263. a.h.flags |= Write;
  264. }
  265. if (write(sfd, &a, sizeof a) == -1) {
  266. perror("send ATA identify device");
  267. exit(EXIT_FAILURE);
  268. }
  269. n = aoe_pkt_read(sfd, buf, sizeof buf, c);
  270. p = (Ata *) buf;
  271. show_smart_regs(p);
  272. if (s->data & SmartDataRet) {
  273. puts("SMART data:");
  274. hex_print(stdout, p->data, 512, " ");
  275. }
  276. }
  277. void
  278. bad_option(char c)
  279. {
  280. fprintf(stderr, "%s Error: unrecognized option: ", progname);
  281. if (isprint(c))
  282. fprintf(stderr, "%c\n", c);
  283. else
  284. fprintf(stderr, "0x%02x\n", c & 0xff);
  285. }
  286. void
  287. check_timeout(int secs)
  288. {
  289. if (secs < 1) {
  290. fprintf(stderr,
  291. "%s Error: timeout seconds must be one or more\n",
  292. progname);
  293. exit(EXIT_FAILURE);
  294. }
  295. }
  296. void
  297. init_opts(struct progopts *opts, int argc, char *argv[])
  298. {
  299. int c;
  300. while ( (c = getopt(argc, argv, "hvit:s:S:")) != -1) {
  301. switch (c) {
  302. case 'h':
  303. usage();
  304. exit(EXIT_SUCCESS);
  305. break;
  306. case 'v':
  307. ++opts->verbose;
  308. break;
  309. case 'i':
  310. opts->ata_ident = 1;
  311. break;
  312. case 't':
  313. opts->tag = atoi(optarg);
  314. break;
  315. case 's':
  316. opts->timeout = atoi(optarg);
  317. check_timeout(opts->timeout);
  318. break;
  319. case 'S':
  320. opts->smart = optarg;
  321. break;
  322. case '?':
  323. bad_option(optopt);
  324. usage();
  325. exit(EXIT_FAILURE);
  326. break;
  327. default:
  328. abort(); /* shouldn't happen */
  329. }
  330. }
  331. if (argc - optind != 3) {
  332. usage();
  333. exit(EXIT_FAILURE);
  334. }
  335. opts->shelf = atoi(argv[optind]);
  336. opts->slot = atoi(argv[optind+1]);
  337. opts->netif = argv[optind+2];
  338. }
  339. int
  340. main(int argc, char *argv[])
  341. {
  342. Conf c;
  343. opts = defaults;
  344. progname = strrchr(argv[0], '/');
  345. if (progname)
  346. progname += 1;
  347. else
  348. progname = argv[0];
  349. init_opts(&opts, argc, argv);
  350. opts.tag |= 1UL << 31; /* set high bit for userland AoE */
  351. if (opts.verbose) {
  352. printf("tag: %x\neth: %s\nshelf: %u\nslot: %u\n",
  353. opts.tag, opts.netif, opts.shelf, opts.slot);
  354. fflush(stdout);
  355. }
  356. sfd = dial(opts.netif);
  357. if (!getea(sfd, opts.netif, mac))
  358. exit(EXIT_FAILURE);
  359. alarm(opts.timeout);
  360. find_blade(&c, opts.shelf, opts.slot);
  361. alarm(0);
  362. if (opts.verbose) {
  363. printf("found e%d.%d with mac ",
  364. ntohs(c.h.maj), c.h.min);
  365. hex_print(stdout, c.h.src, sizeof c.h.src, "");
  366. putchar('\n');
  367. fflush(stdout);
  368. }
  369. if (opts.ata_ident) {
  370. alarm(opts.timeout);
  371. disk_identify(&c, opts.tag);
  372. alarm(0);
  373. opts.tag += 1;
  374. }
  375. if (opts.smart) {
  376. alarm(opts.timeout);
  377. smart(&c, opts.tag, opts.smart);
  378. alarm(0);
  379. opts.tag += 1;
  380. }
  381. return 0;
  382. }