123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423 |
- /* aoeping.c - userland aoe pinger
- *
- * run without arguments for usage
- */
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <stdint.h>
- #include <ctype.h>
- #include <netinet/in.h>
- #include <errno.h>
- #include "dat.h"
- #include "fns.h"
- struct progopts {
- int shelf;
- int slot;
- char *netif;
- int verbose;
- int timeout;
- u32 tag;
- char *smart;
- char ata_ident;
- };
- static struct progopts defaults = {
- .shelf = 0,
- .slot = 0,
- .netif = NULL,
- .verbose = 0,
- .timeout = 0,
- .tag = 0,
- .smart = NULL,
- .ata_ident = 0,
- };
- static struct progopts opts;
- struct smartcmd {
- char *name; /* subcommand name from ATA spec */
- int cmd; /* for features register */
- char data; /* does this subcommand xfer data? */
- };
- static struct smartcmd smarts[] = {
- { "read_data", 0xd0, SmartDataRet },
- // { "attr_autosave", 0xd2, 0 }, (unsupported b/c it overloads sector count)
- { "offline_immediate", 0xd4, 0 },
- { "read_log", 0xd5, SmartDataRet },
- { "write_log", 0xd6, SmartDataPut },
- { "enable", 0xd8, 0 },
- { "disable", 0xd9, 0 },
- { "return_status", 0xda, 0 },
- };
- static char *progname;
- static int sfd; /* raw socket file descriptor */
- static uchar mac[6];
- #if 0
- void
- show_opts(struct progopts *opts)
- {
- printf("shelf: %d\n", opts->shelf);
- printf("slot: %d\n", opts->slot);
- printf("netif: %s\n", opts->netif);
- printf("verbose: %d\n", opts->verbose);
- printf("timeout: %d\n", opts->timeout);
- printf("tag: %d\n", opts->tag);
- printf("ata_ident: %d\n", (int) opts->ata_ident);
- }
- #endif
- void
- usage(void)
- {
- fprintf(stderr,
- "usage:\t%s [options] {shelf} {slot} {netif}\n",
- progname);
- fprintf(stderr, "%s\n\t%s\n\t%s\n\t%s\n",
- "options:",
- "-i\tdo ATA device identify",
- "-v\tbe verbose",
- "-h\tshow this usage summary");
- fprintf(stderr, "%s\n\t%s\n\t%s\n\t%s\n",
- "options taking arguments:",
- "-s\ttimeout in seconds",
- "-S\tperform SMART command",
- "-t\tspecify number for starting AoE tag");
- }
- void
- hex_print(FILE *out, uchar *buf, int n, char *sep)
- {
- int i;
- int per_line = 16;
- for (i = 0; i < n;) {
- fprintf(out, "%02x%s", *buf++ & 0xff, sep);
- if (!(++i % per_line))
- putc('\n', out);
- }
- }
- void
- find_blade(Conf *c, int shelf, int slot)
- {
- int n;
- uchar buf[1400];
- Aoehdr *h = &c->h;
- memset(h, 0, sizeof *h);
- memset(h->dst, 0xff, sizeof h->dst);
- memmove(h->src, mac, sizeof h->src);
-
- h->type = htons(AOE_ETH_PROTO);
- h->flags = AoEver << 4;
- h->maj = htons(shelf);
- h->min = slot;
- h->cmd = Config;
- c->bufcnt = 3;
- c->vercmd = 0x10 | Qread;
- memset(c->data, 0xED, sizeof c->data);
- c->len = htons(1024);
- if (write(sfd, c, sizeof *c) == -1) {
- perror("send config query");
- exit(EXIT_FAILURE);
- }
- for (;;) {
- n = read(sfd, buf, sizeof buf);
- if (n < 0) {
- perror("read network");
- exit(EXIT_FAILURE);
- }
- if (n < 60)
- continue;
- h = (Aoehdr *) buf;
- if (ntohs(h->type) != AOE_ETH_PROTO
- || ntohs(h->maj) != shelf
- || h->min != slot)
- continue;
- break;
- }
- if (opts.verbose) {
- puts("config query response:");
- hex_print(stdout, buf, n, " ");
- putchar('\n');
- }
- memcpy(c, buf, sizeof *c);
- }
- /* read a packet that was sent by the device that returned *c earlier
- */
- int
- aoe_pkt_read(int fd, uchar *buf, size_t siz, Conf *c)
- {
- Aoehdr *h;
- int n;
- for (;;) {
- n = read(fd, buf, siz);
- if (n < 0) {
- perror("read network");
- exit(EXIT_FAILURE);
- }
- if (n < 60)
- continue;
- h = (Aoehdr *) buf;
- if (ntohs(h->type) != AOE_ETH_PROTO
- || h->maj != c->h.maj
- || h->min != c->h.min)
- continue;
- break;
- }
- return n;
- }
- /* prepare a packet for doing ATA to a device that gave us Conf *c
- */
- void
- ata_prep(Ata *a, Conf *c, u32 tag)
- {
- memset(a, 0, sizeof *a);
- memcpy(a->h.dst, c->h.src, sizeof a->h.dst);
- memcpy(a->h.src, mac, sizeof a->h.src);
- a->h.type = htons(AOE_ETH_PROTO);
- a->h.flags = AoEver << 4;
- a->h.maj = c->h.maj;
- a->h.min = c->h.min;
- a->h.cmd = ATAcmd;
- tag = htonl(tag);
- memmove(a->h.tag, &tag, sizeof a->h.tag);
- }
- void
- disk_identify(Conf *c, u32 tag)
- {
- int n;
- uchar buf[1400];
- Ata a;
- Ata *p;
- ata_prep(&a, c, tag);
- a.sectors = 1;
- a.cmd = ATAid_dev;
- a.lba[3] = 0xa0;
- if (write(sfd, &a, sizeof a) == -1) {
- perror("send ATA identify device");
- exit(EXIT_FAILURE);
- }
- n = aoe_pkt_read(sfd, buf, sizeof buf, c);
- p = (Ata *) buf;
- puts("device identify response:");
- hex_print(stdout, p->data, 512, " ");
- }
- struct smartcmd *
- smartcmd_lookup(char *nam)
- {
- int n = sizeof smarts / sizeof smarts[0];
- int i;
- for (i = 0; i < n; ++i) {
- char *p = strchr(nam, ':');
- if (p && !strncmp(smarts[i].name, nam, p - nam))
- return &smarts[i];
- else if (!strcmp(smarts[i].name, nam))
- return &smarts[i];
- }
- return nil;
- }
- void
- smart_registers(Ata *a, char *opts, struct smartcmd *s)
- {
- a->err = s->cmd;
- a->lba[1] = 0x4f;
- a->lba[2] = 0xc2;
- if (opts++)
- a->lba[0] = strtol(opts, NULL, 0);
- }
- void
- show_smart_regs(Ata *a)
- {
- puts("ATA registers:");
- char *names[] = {
- "Features", "Sector Count",
- "LBA Low", "LBA Mid", "LBA High",
- "Status",
- };
- int regs[] = {
- a->err, a->sectors,
- a->lba[0], a->lba[1], a->lba[2],
- a->cmd,
- };
- int i;
- for (i = 0; i < sizeof regs / sizeof regs[0]; ++i)
- printf("%20s: 0x%02x\n", names[i], regs[i]);
- }
- void
- smart(Conf *c, u32 tag, char *smart_cmd)
- {
- int n;
- uchar buf[1400];
- Ata a;
- Ata *p;
- struct smartcmd *s = smartcmd_lookup(smart_cmd);
- if (!s) {
- fprintf(stderr,
- "%s Error: no such SMART command: %s\n",
- progname, smart_cmd);
- exit(EXIT_FAILURE);
- }
- ata_prep(&a, c, tag);
- a.sectors = !!s->data; /* we only support one-sector data xfer */
- a.cmd = ATAsmart;
- smart_registers(&a, strchr(smart_cmd, ':'), s);
- if (s->data & SmartDataPut) {
- if (read(STDIN_FILENO, a.data, 512) == -1) {
- perror("reading smart data from stdin");
- exit(EXIT_FAILURE);
- }
- a.h.flags |= Write;
- }
- if (write(sfd, &a, sizeof a) == -1) {
- perror("send ATA identify device");
- exit(EXIT_FAILURE);
- }
- n = aoe_pkt_read(sfd, buf, sizeof buf, c);
- p = (Ata *) buf;
- show_smart_regs(p);
- if (s->data & SmartDataRet) {
- puts("SMART data:");
- hex_print(stdout, p->data, 512, " ");
- }
- }
- void
- bad_option(char c)
- {
- fprintf(stderr, "%s Error: unrecognized option: ", progname);
- if (isprint(c))
- fprintf(stderr, "%c\n", c);
- else
- fprintf(stderr, "0x%02x\n", c & 0xff);
- }
- void
- check_timeout(int secs)
- {
- if (secs < 1) {
- fprintf(stderr,
- "%s Error: timeout seconds must be one or more\n",
- progname);
- exit(EXIT_FAILURE);
- }
- }
- void
- init_opts(struct progopts *opts, int argc, char *argv[])
- {
- int c;
- while ( (c = getopt(argc, argv, "hvit:s:S:")) != -1) {
- switch (c) {
- case 'h':
- usage();
- exit(EXIT_SUCCESS);
- break;
- case 'v':
- ++opts->verbose;
- break;
- case 'i':
- opts->ata_ident = 1;
- break;
- case 't':
- opts->tag = atoi(optarg);
- break;
- case 's':
- opts->timeout = atoi(optarg);
- check_timeout(opts->timeout);
- break;
- case 'S':
- opts->smart = optarg;
- break;
- case '?':
- bad_option(optopt);
- usage();
- exit(EXIT_FAILURE);
- break;
- default:
- abort(); /* shouldn't happen */
- }
- }
- if (argc - optind != 3) {
- usage();
- exit(EXIT_FAILURE);
- }
- opts->shelf = atoi(argv[optind]);
- opts->slot = atoi(argv[optind+1]);
- opts->netif = argv[optind+2];
- }
- int
- main(int argc, char *argv[])
- {
- Conf c;
- opts = defaults;
- progname = strrchr(argv[0], '/');
- if (progname)
- progname += 1;
- else
- progname = argv[0];
- init_opts(&opts, argc, argv);
- opts.tag |= 1UL << 31; /* set high bit for userland AoE */
- if (opts.verbose) {
- printf("tag: %x\neth: %s\nshelf: %u\nslot: %u\n",
- opts.tag, opts.netif, opts.shelf, opts.slot);
- fflush(stdout);
- }
- sfd = dial(opts.netif);
- if (!getea(sfd, opts.netif, mac))
- exit(EXIT_FAILURE);
-
- alarm(opts.timeout);
- find_blade(&c, opts.shelf, opts.slot);
- alarm(0);
- if (opts.verbose) {
- printf("found e%d.%d with mac ",
- ntohs(c.h.maj), c.h.min);
- hex_print(stdout, c.h.src, sizeof c.h.src, "");
- putchar('\n');
- fflush(stdout);
- }
- if (opts.ata_ident) {
- alarm(opts.timeout);
- disk_identify(&c, opts.tag);
- alarm(0);
- opts.tag += 1;
- }
- if (opts.smart) {
- alarm(opts.timeout);
- smart(&c, opts.tag, opts.smart);
- alarm(0);
- opts.tag += 1;
- }
- return 0;
- }
|