1763fae79SScott Long /*- 21de7b4b8SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 31de7b4b8SPedro F. Giffuni * 4763fae79SScott Long * Copyright (c) 2008, 2009 Yahoo!, Inc. 5763fae79SScott Long * All rights reserved. 6763fae79SScott Long * 7763fae79SScott Long * Redistribution and use in source and binary forms, with or without 8763fae79SScott Long * modification, are permitted provided that the following conditions 9763fae79SScott Long * are met: 10763fae79SScott Long * 1. Redistributions of source code must retain the above copyright 11763fae79SScott Long * notice, this list of conditions and the following disclaimer. 12763fae79SScott Long * 2. Redistributions in binary form must reproduce the above copyright 13763fae79SScott Long * notice, this list of conditions and the following disclaimer in the 14763fae79SScott Long * documentation and/or other materials provided with the distribution. 15763fae79SScott Long * 3. The names of the authors may not be used to endorse or promote 16763fae79SScott Long * products derived from this software without specific prior written 17763fae79SScott Long * permission. 18763fae79SScott Long * 19763fae79SScott Long * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20763fae79SScott Long * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21763fae79SScott Long * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22763fae79SScott Long * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23763fae79SScott Long * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24763fae79SScott Long * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25763fae79SScott Long * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26763fae79SScott Long * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27763fae79SScott Long * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28763fae79SScott Long * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29763fae79SScott Long * SUCH DAMAGE. 30763fae79SScott Long */ 31763fae79SScott Long 32763fae79SScott Long #include <sys/types.h> 33763fae79SScott Long #include <sys/errno.h> 34763fae79SScott Long #include <err.h> 35bf4ec4dfSEitan Adler #include <fcntl.h> 36186ddf96SJohn Baldwin #include <stdbool.h> 37763fae79SScott Long #include <stdio.h> 38763fae79SScott Long #include <stdlib.h> 39763fae79SScott Long #include <strings.h> 40763fae79SScott Long #include <time.h> 41763fae79SScott Long #include <unistd.h> 42763fae79SScott Long #include "mfiutil.h" 43763fae79SScott Long 44763fae79SScott Long static int 45763fae79SScott Long mfi_event_get_info(int fd, struct mfi_evt_log_state *info, uint8_t *statusp) 46763fae79SScott Long { 47763fae79SScott Long 48763fae79SScott Long return (mfi_dcmd_command(fd, MFI_DCMD_CTRL_EVENT_GETINFO, info, 49763fae79SScott Long sizeof(struct mfi_evt_log_state), NULL, 0, statusp)); 50763fae79SScott Long } 51763fae79SScott Long 52763fae79SScott Long static int 53763fae79SScott Long mfi_get_events(int fd, struct mfi_evt_list *list, int num_events, 54763fae79SScott Long union mfi_evt filter, uint32_t start_seq, uint8_t *statusp) 55763fae79SScott Long { 56763fae79SScott Long uint32_t mbox[2]; 57763fae79SScott Long size_t size; 58763fae79SScott Long 59763fae79SScott Long mbox[0] = start_seq; 60763fae79SScott Long mbox[1] = filter.word; 61763fae79SScott Long size = sizeof(struct mfi_evt_list) + sizeof(struct mfi_evt_detail) * 62763fae79SScott Long (num_events - 1); 63763fae79SScott Long return (mfi_dcmd_command(fd, MFI_DCMD_CTRL_EVENT_GET, list, size, 64763fae79SScott Long (uint8_t *)&mbox, sizeof(mbox), statusp)); 65763fae79SScott Long } 66763fae79SScott Long 67763fae79SScott Long static int 6841b8cbdaSEitan Adler show_logstate(int ac, char **av __unused) 69763fae79SScott Long { 70763fae79SScott Long struct mfi_evt_log_state info; 71c02999d9SJohn Baldwin int error, fd; 72763fae79SScott Long 73763fae79SScott Long if (ac != 1) { 74763fae79SScott Long warnx("show logstate: extra arguments"); 75763fae79SScott Long return (EINVAL); 76763fae79SScott Long } 77763fae79SScott Long 787e0f8b79SDoug Ambrisko fd = mfi_open(mfi_device, O_RDWR); 79763fae79SScott Long if (fd < 0) { 80c02999d9SJohn Baldwin error = errno; 81763fae79SScott Long warn("mfi_open"); 82c02999d9SJohn Baldwin return (error); 83763fae79SScott Long } 84763fae79SScott Long 85763fae79SScott Long if (mfi_event_get_info(fd, &info, NULL) < 0) { 86c02999d9SJohn Baldwin error = errno; 87763fae79SScott Long warn("Failed to get event log info"); 88375c4656SBjoern A. Zeeb close(fd); 89c02999d9SJohn Baldwin return (error); 90763fae79SScott Long } 91763fae79SScott Long 927e0f8b79SDoug Ambrisko printf("%s Event Log Sequence Numbers:\n", mfi_device); 93763fae79SScott Long printf(" Newest Seq #: %u\n", info.newest_seq_num); 94763fae79SScott Long printf(" Oldest Seq #: %u\n", info.oldest_seq_num); 95763fae79SScott Long printf(" Clear Seq #: %u\n", info.clear_seq_num); 96763fae79SScott Long printf("Shutdown Seq #: %u\n", info.shutdown_seq_num); 97763fae79SScott Long printf(" Boot Seq #: %u\n", info.boot_seq_num); 98763fae79SScott Long 99763fae79SScott Long close(fd); 100763fae79SScott Long 101763fae79SScott Long return (0); 102763fae79SScott Long } 103763fae79SScott Long MFI_COMMAND(show, logstate, show_logstate); 104763fae79SScott Long 105763fae79SScott Long static int 106763fae79SScott Long parse_seq(struct mfi_evt_log_state *info, char *arg, uint32_t *seq) 107763fae79SScott Long { 108763fae79SScott Long char *cp; 109763fae79SScott Long long val; 110763fae79SScott Long 111763fae79SScott Long if (strcasecmp(arg, "newest") == 0) { 112763fae79SScott Long *seq = info->newest_seq_num; 113763fae79SScott Long return (0); 114763fae79SScott Long } 115763fae79SScott Long if (strcasecmp(arg, "oldest") == 0) { 116763fae79SScott Long *seq = info->oldest_seq_num; 117763fae79SScott Long return (0); 118763fae79SScott Long } 119763fae79SScott Long if (strcasecmp(arg, "clear") == 0) { 120763fae79SScott Long *seq = info->clear_seq_num; 121763fae79SScott Long return (0); 122763fae79SScott Long } 123763fae79SScott Long if (strcasecmp(arg, "shutdown") == 0) { 124763fae79SScott Long *seq = info->shutdown_seq_num; 125763fae79SScott Long return (0); 126763fae79SScott Long } 127763fae79SScott Long if (strcasecmp(arg, "boot") == 0) { 128763fae79SScott Long *seq = info->boot_seq_num; 129763fae79SScott Long return (0); 130763fae79SScott Long } 131763fae79SScott Long val = strtol(arg, &cp, 0); 132763fae79SScott Long if (*cp != '\0' || val < 0) { 133763fae79SScott Long errno = EINVAL; 134763fae79SScott Long return (-1); 135763fae79SScott Long } 136763fae79SScott Long *seq = val; 137763fae79SScott Long return (0); 138763fae79SScott Long } 139763fae79SScott Long 140763fae79SScott Long static int 141763fae79SScott Long parse_locale(char *arg, uint16_t *locale) 142763fae79SScott Long { 143763fae79SScott Long char *cp; 144763fae79SScott Long long val; 145763fae79SScott Long 146763fae79SScott Long if (strncasecmp(arg, "vol", 3) == 0 || strcasecmp(arg, "ld") == 0) { 147763fae79SScott Long *locale = MFI_EVT_LOCALE_LD; 148763fae79SScott Long return (0); 149763fae79SScott Long } 150763fae79SScott Long if (strncasecmp(arg, "drive", 5) == 0 || strcasecmp(arg, "pd") == 0) { 151763fae79SScott Long *locale = MFI_EVT_LOCALE_PD; 152763fae79SScott Long return (0); 153763fae79SScott Long } 154763fae79SScott Long if (strncasecmp(arg, "encl", 4) == 0) { 155763fae79SScott Long *locale = MFI_EVT_LOCALE_ENCL; 156763fae79SScott Long return (0); 157763fae79SScott Long } 158763fae79SScott Long if (strncasecmp(arg, "batt", 4) == 0 || 159763fae79SScott Long strncasecmp(arg, "bbu", 3) == 0) { 160763fae79SScott Long *locale = MFI_EVT_LOCALE_BBU; 161763fae79SScott Long return (0); 162763fae79SScott Long } 163763fae79SScott Long if (strcasecmp(arg, "sas") == 0) { 164763fae79SScott Long *locale = MFI_EVT_LOCALE_SAS; 165763fae79SScott Long return (0); 166763fae79SScott Long } 167763fae79SScott Long if (strcasecmp(arg, "ctrl") == 0 || strncasecmp(arg, "cont", 4) == 0) { 168763fae79SScott Long *locale = MFI_EVT_LOCALE_CTRL; 169763fae79SScott Long return (0); 170763fae79SScott Long } 171763fae79SScott Long if (strcasecmp(arg, "config") == 0) { 172763fae79SScott Long *locale = MFI_EVT_LOCALE_CONFIG; 173763fae79SScott Long return (0); 174763fae79SScott Long } 175763fae79SScott Long if (strcasecmp(arg, "cluster") == 0) { 176763fae79SScott Long *locale = MFI_EVT_LOCALE_CLUSTER; 177763fae79SScott Long return (0); 178763fae79SScott Long } 179763fae79SScott Long if (strcasecmp(arg, "all") == 0) { 180763fae79SScott Long *locale = MFI_EVT_LOCALE_ALL; 181763fae79SScott Long return (0); 182763fae79SScott Long } 183763fae79SScott Long val = strtol(arg, &cp, 0); 184763fae79SScott Long if (*cp != '\0' || val < 0 || val > 0xffff) { 185763fae79SScott Long errno = EINVAL; 186763fae79SScott Long return (-1); 187763fae79SScott Long } 188763fae79SScott Long *locale = val; 189763fae79SScott Long return (0); 190763fae79SScott Long } 191763fae79SScott Long 192763fae79SScott Long static int 193763fae79SScott Long parse_class(char *arg, int8_t *class) 194763fae79SScott Long { 195763fae79SScott Long char *cp; 196763fae79SScott Long long val; 197763fae79SScott Long 198763fae79SScott Long if (strcasecmp(arg, "debug") == 0) { 199763fae79SScott Long *class = MFI_EVT_CLASS_DEBUG; 200763fae79SScott Long return (0); 201763fae79SScott Long } 202763fae79SScott Long if (strncasecmp(arg, "prog", 4) == 0) { 203763fae79SScott Long *class = MFI_EVT_CLASS_PROGRESS; 204763fae79SScott Long return (0); 205763fae79SScott Long } 206763fae79SScott Long if (strncasecmp(arg, "info", 4) == 0) { 207763fae79SScott Long *class = MFI_EVT_CLASS_INFO; 208763fae79SScott Long return (0); 209763fae79SScott Long } 210763fae79SScott Long if (strncasecmp(arg, "warn", 4) == 0) { 211763fae79SScott Long *class = MFI_EVT_CLASS_WARNING; 212763fae79SScott Long return (0); 213763fae79SScott Long } 214763fae79SScott Long if (strncasecmp(arg, "crit", 4) == 0) { 215763fae79SScott Long *class = MFI_EVT_CLASS_CRITICAL; 216763fae79SScott Long return (0); 217763fae79SScott Long } 218763fae79SScott Long if (strcasecmp(arg, "fatal") == 0) { 219763fae79SScott Long *class = MFI_EVT_CLASS_FATAL; 220763fae79SScott Long return (0); 221763fae79SScott Long } 222763fae79SScott Long if (strcasecmp(arg, "dead") == 0) { 223763fae79SScott Long *class = MFI_EVT_CLASS_DEAD; 224763fae79SScott Long return (0); 225763fae79SScott Long } 226763fae79SScott Long val = strtol(arg, &cp, 0); 227763fae79SScott Long if (*cp != '\0' || val < -128 || val > 127) { 228763fae79SScott Long errno = EINVAL; 229763fae79SScott Long return (-1); 230763fae79SScott Long } 231763fae79SScott Long *class = val; 232763fae79SScott Long return (0); 233763fae79SScott Long } 234763fae79SScott Long 235763fae79SScott Long /* 236763fae79SScott Long * The timestamp is the number of seconds since 00:00 Jan 1, 2000. If 237763fae79SScott Long * the bits in 24-31 are all set, then it is the number of seconds since 238763fae79SScott Long * boot. 239763fae79SScott Long */ 240763fae79SScott Long static const char * 241763fae79SScott Long format_timestamp(uint32_t timestamp) 242763fae79SScott Long { 243763fae79SScott Long static char buffer[32]; 244763fae79SScott Long static time_t base; 245763fae79SScott Long time_t t; 246763fae79SScott Long struct tm tm; 247763fae79SScott Long 248763fae79SScott Long if ((timestamp & 0xff000000) == 0xff000000) { 249763fae79SScott Long snprintf(buffer, sizeof(buffer), "boot + %us", timestamp & 250763fae79SScott Long 0x00ffffff); 251763fae79SScott Long return (buffer); 252763fae79SScott Long } 253763fae79SScott Long 254763fae79SScott Long if (base == 0) { 255763fae79SScott Long /* Compute 00:00 Jan 1, 2000 offset. */ 256763fae79SScott Long bzero(&tm, sizeof(tm)); 257763fae79SScott Long tm.tm_mday = 1; 258763fae79SScott Long tm.tm_year = (2000 - 1900); 259763fae79SScott Long base = mktime(&tm); 260763fae79SScott Long } 261763fae79SScott Long if (base == -1) { 262763fae79SScott Long snprintf(buffer, sizeof(buffer), "%us", timestamp); 263763fae79SScott Long return (buffer); 264763fae79SScott Long } 265763fae79SScott Long t = base + timestamp; 266763fae79SScott Long strftime(buffer, sizeof(buffer), "%+", localtime(&t)); 267763fae79SScott Long return (buffer); 268763fae79SScott Long } 269763fae79SScott Long 270763fae79SScott Long static const char * 271763fae79SScott Long format_locale(uint16_t locale) 272763fae79SScott Long { 273763fae79SScott Long static char buffer[8]; 274763fae79SScott Long 275763fae79SScott Long switch (locale) { 276763fae79SScott Long case MFI_EVT_LOCALE_LD: 277763fae79SScott Long return ("VOLUME"); 278763fae79SScott Long case MFI_EVT_LOCALE_PD: 279763fae79SScott Long return ("DRIVE"); 280763fae79SScott Long case MFI_EVT_LOCALE_ENCL: 281763fae79SScott Long return ("ENCL"); 282763fae79SScott Long case MFI_EVT_LOCALE_BBU: 283763fae79SScott Long return ("BATTERY"); 284763fae79SScott Long case MFI_EVT_LOCALE_SAS: 285763fae79SScott Long return ("SAS"); 286763fae79SScott Long case MFI_EVT_LOCALE_CTRL: 287763fae79SScott Long return ("CTRL"); 288763fae79SScott Long case MFI_EVT_LOCALE_CONFIG: 289763fae79SScott Long return ("CONFIG"); 290763fae79SScott Long case MFI_EVT_LOCALE_CLUSTER: 291763fae79SScott Long return ("CLUSTER"); 292763fae79SScott Long case MFI_EVT_LOCALE_ALL: 293763fae79SScott Long return ("ALL"); 294763fae79SScott Long default: 295763fae79SScott Long snprintf(buffer, sizeof(buffer), "0x%04x", locale); 296763fae79SScott Long return (buffer); 297763fae79SScott Long } 298763fae79SScott Long } 299763fae79SScott Long 300763fae79SScott Long static const char * 301763fae79SScott Long format_class(int8_t class) 302763fae79SScott Long { 303763fae79SScott Long static char buffer[6]; 304763fae79SScott Long 305763fae79SScott Long switch (class) { 306763fae79SScott Long case MFI_EVT_CLASS_DEBUG: 307763fae79SScott Long return ("debug"); 308763fae79SScott Long case MFI_EVT_CLASS_PROGRESS: 309763fae79SScott Long return ("progress"); 310763fae79SScott Long case MFI_EVT_CLASS_INFO: 311763fae79SScott Long return ("info"); 312763fae79SScott Long case MFI_EVT_CLASS_WARNING: 313763fae79SScott Long return ("WARN"); 314763fae79SScott Long case MFI_EVT_CLASS_CRITICAL: 315763fae79SScott Long return ("CRIT"); 316763fae79SScott Long case MFI_EVT_CLASS_FATAL: 317763fae79SScott Long return ("FATAL"); 318763fae79SScott Long case MFI_EVT_CLASS_DEAD: 319763fae79SScott Long return ("DEAD"); 320763fae79SScott Long default: 321763fae79SScott Long snprintf(buffer, sizeof(buffer), "%d", class); 322763fae79SScott Long return (buffer); 323763fae79SScott Long } 324763fae79SScott Long } 325763fae79SScott Long 326763fae79SScott Long /* Simulates %D from kernel printf(9). */ 327763fae79SScott Long static void 328763fae79SScott Long simple_hex(void *ptr, size_t length, const char *separator) 329763fae79SScott Long { 330763fae79SScott Long unsigned char *cp; 331763fae79SScott Long u_int i; 332763fae79SScott Long 333763fae79SScott Long if (length == 0) 334763fae79SScott Long return; 335763fae79SScott Long cp = ptr; 336763fae79SScott Long printf("%02x", cp[0]); 337763fae79SScott Long for (i = 1; i < length; i++) 338763fae79SScott Long printf("%s%02x", separator, cp[i]); 339763fae79SScott Long } 340763fae79SScott Long 341763fae79SScott Long static const char * 342763fae79SScott Long pdrive_location(struct mfi_evt_pd *pd) 343763fae79SScott Long { 344763fae79SScott Long static char buffer[16]; 345763fae79SScott Long 346763fae79SScott Long if (pd->enclosure_index == 0) 347763fae79SScott Long snprintf(buffer, sizeof(buffer), "%02d(s%d)", pd->device_id, 348763fae79SScott Long pd->slot_number); 349763fae79SScott Long else 350763fae79SScott Long snprintf(buffer, sizeof(buffer), "%02d(e%d/s%d)", pd->device_id, 351763fae79SScott Long pd->enclosure_index, pd->slot_number); 352763fae79SScott Long return (buffer); 353763fae79SScott Long } 354763fae79SScott Long 355763fae79SScott Long static const char * 356763fae79SScott Long volume_name(int fd, struct mfi_evt_ld *ld) 357763fae79SScott Long { 358763fae79SScott Long 359763fae79SScott Long return (mfi_volume_name(fd, ld->target_id)); 360763fae79SScott Long } 361763fae79SScott Long 362763fae79SScott Long /* Ripped from sys/dev/mfi/mfi.c. */ 363763fae79SScott Long static void 364763fae79SScott Long mfi_decode_evt(int fd, struct mfi_evt_detail *detail, int verbose) 365763fae79SScott Long { 366763fae79SScott Long 367763fae79SScott Long printf("%5d (%s/%s/%s) - ", detail->seq, format_timestamp(detail->time), 368aacea6e2SEd Maste format_locale(detail->evt_class.members.locale), 369aacea6e2SEd Maste format_class(detail->evt_class.members.evt_class)); 370763fae79SScott Long switch (detail->arg_type) { 371763fae79SScott Long case MR_EVT_ARGS_NONE: 372763fae79SScott Long break; 373763fae79SScott Long case MR_EVT_ARGS_CDB_SENSE: 374763fae79SScott Long if (verbose) { 375763fae79SScott Long printf("PD %s CDB ", 376763fae79SScott Long pdrive_location(&detail->args.cdb_sense.pd) 377763fae79SScott Long ); 378763fae79SScott Long simple_hex(detail->args.cdb_sense.cdb, 379763fae79SScott Long detail->args.cdb_sense.cdb_len, ":"); 380763fae79SScott Long printf(" Sense "); 381763fae79SScott Long simple_hex(detail->args.cdb_sense.sense, 382763fae79SScott Long detail->args.cdb_sense.sense_len, ":"); 383763fae79SScott Long printf(":\n "); 384763fae79SScott Long } 385763fae79SScott Long break; 386763fae79SScott Long case MR_EVT_ARGS_LD: 387763fae79SScott Long printf("VOL %s event: ", volume_name(fd, &detail->args.ld)); 388763fae79SScott Long break; 389763fae79SScott Long case MR_EVT_ARGS_LD_COUNT: 390763fae79SScott Long printf("VOL %s", volume_name(fd, &detail->args.ld_count.ld)); 391763fae79SScott Long if (verbose) { 392763fae79SScott Long printf(" count %lld: ", 393763fae79SScott Long (long long)detail->args.ld_count.count); 394763fae79SScott Long } 395763fae79SScott Long printf(": "); 396763fae79SScott Long break; 397763fae79SScott Long case MR_EVT_ARGS_LD_LBA: 398*c6ad7dcdSWHR printf("VOL %s", volume_name(fd, &detail->args.ld_lba.ld)); 399763fae79SScott Long if (verbose) { 400763fae79SScott Long printf(" lba %lld", 401763fae79SScott Long (long long)detail->args.ld_lba.lba); 402763fae79SScott Long } 403763fae79SScott Long printf(": "); 404763fae79SScott Long break; 405763fae79SScott Long case MR_EVT_ARGS_LD_OWNER: 406*c6ad7dcdSWHR printf("VOL %s", volume_name(fd, &detail->args.ld_owner.ld)); 407763fae79SScott Long if (verbose) { 408763fae79SScott Long printf(" owner changed: prior %d, new %d", 409763fae79SScott Long detail->args.ld_owner.pre_owner, 410763fae79SScott Long detail->args.ld_owner.new_owner); 411763fae79SScott Long } 412763fae79SScott Long printf(": "); 413763fae79SScott Long break; 414763fae79SScott Long case MR_EVT_ARGS_LD_LBA_PD_LBA: 415*c6ad7dcdSWHR printf("VOL %s", volume_name(fd, &detail->args.ld_lba_pd_lba.ld)); 416763fae79SScott Long if (verbose) { 417763fae79SScott Long printf(" lba %lld, physical drive PD %s lba %lld", 418763fae79SScott Long (long long)detail->args.ld_lba_pd_lba.ld_lba, 419763fae79SScott Long pdrive_location(&detail->args.ld_lba_pd_lba.pd), 420763fae79SScott Long (long long)detail->args.ld_lba_pd_lba.pd_lba); 421763fae79SScott Long } 422763fae79SScott Long printf(": "); 423763fae79SScott Long break; 424763fae79SScott Long case MR_EVT_ARGS_LD_PROG: 425763fae79SScott Long printf("VOL %s", volume_name(fd, &detail->args.ld_prog.ld)); 426763fae79SScott Long if (verbose) { 427763fae79SScott Long printf(" progress %d%% in %ds", 428763fae79SScott Long detail->args.ld_prog.prog.progress/655, 429763fae79SScott Long detail->args.ld_prog.prog.elapsed_seconds); 430763fae79SScott Long } 431763fae79SScott Long printf(": "); 432763fae79SScott Long break; 433763fae79SScott Long case MR_EVT_ARGS_LD_STATE: 434*c6ad7dcdSWHR printf("VOL %s", volume_name(fd, &detail->args.ld_state.ld)); 435763fae79SScott Long if (verbose) { 436763fae79SScott Long printf(" state prior %s new %s", 437763fae79SScott Long mfi_ldstate(detail->args.ld_state.prev_state), 438763fae79SScott Long mfi_ldstate(detail->args.ld_state.new_state)); 439763fae79SScott Long } 440763fae79SScott Long printf(": "); 441763fae79SScott Long break; 442763fae79SScott Long case MR_EVT_ARGS_LD_STRIP: 4431b202316SJohn Baldwin printf("VOL %s", volume_name(fd, &detail->args.ld_strip.ld)); 444763fae79SScott Long if (verbose) { 445763fae79SScott Long printf(" strip %lld", 446763fae79SScott Long (long long)detail->args.ld_strip.strip); 447763fae79SScott Long } 448763fae79SScott Long printf(": "); 449763fae79SScott Long break; 450763fae79SScott Long case MR_EVT_ARGS_PD: 451763fae79SScott Long if (verbose) { 452763fae79SScott Long printf("PD %s event: ", 453763fae79SScott Long pdrive_location(&detail->args.pd)); 454763fae79SScott Long } 455763fae79SScott Long break; 456763fae79SScott Long case MR_EVT_ARGS_PD_ERR: 457763fae79SScott Long if (verbose) { 458763fae79SScott Long printf("PD %s err %d: ", 459763fae79SScott Long pdrive_location(&detail->args.pd_err.pd), 460763fae79SScott Long detail->args.pd_err.err); 461763fae79SScott Long } 462763fae79SScott Long break; 463763fae79SScott Long case MR_EVT_ARGS_PD_LBA: 464763fae79SScott Long if (verbose) { 465763fae79SScott Long printf("PD %s lba %lld: ", 466763fae79SScott Long pdrive_location(&detail->args.pd_lba.pd), 467763fae79SScott Long (long long)detail->args.pd_lba.lba); 468763fae79SScott Long } 469763fae79SScott Long break; 470763fae79SScott Long case MR_EVT_ARGS_PD_LBA_LD: 471763fae79SScott Long if (verbose) { 472763fae79SScott Long printf("PD %s lba %lld VOL %s: ", 473763fae79SScott Long pdrive_location(&detail->args.pd_lba_ld.pd), 474763fae79SScott Long (long long)detail->args.pd_lba.lba, 475763fae79SScott Long volume_name(fd, &detail->args.pd_lba_ld.ld)); 476763fae79SScott Long } 477763fae79SScott Long break; 478763fae79SScott Long case MR_EVT_ARGS_PD_PROG: 479763fae79SScott Long if (verbose) { 480763fae79SScott Long printf("PD %s progress %d%% seconds %ds: ", 481763fae79SScott Long pdrive_location(&detail->args.pd_prog.pd), 482763fae79SScott Long detail->args.pd_prog.prog.progress/655, 483763fae79SScott Long detail->args.pd_prog.prog.elapsed_seconds); 484763fae79SScott Long } 485763fae79SScott Long break; 486763fae79SScott Long case MR_EVT_ARGS_PD_STATE: 487763fae79SScott Long if (verbose) { 488763fae79SScott Long printf("PD %s state prior %s new %s: ", 489*c6ad7dcdSWHR pdrive_location(&detail->args.pd_state.pd), 490763fae79SScott Long mfi_pdstate(detail->args.pd_state.prev_state), 491763fae79SScott Long mfi_pdstate(detail->args.pd_state.new_state)); 492763fae79SScott Long } 493763fae79SScott Long break; 494763fae79SScott Long case MR_EVT_ARGS_PCI: 495763fae79SScott Long if (verbose) { 496763fae79SScott Long printf("PCI 0x%04x 0x%04x 0x%04x 0x%04x: ", 497763fae79SScott Long detail->args.pci.venderId, 498763fae79SScott Long detail->args.pci.deviceId, 499763fae79SScott Long detail->args.pci.subVenderId, 500763fae79SScott Long detail->args.pci.subDeviceId); 501763fae79SScott Long } 502763fae79SScott Long break; 503763fae79SScott Long case MR_EVT_ARGS_RATE: 504763fae79SScott Long if (verbose) { 505763fae79SScott Long printf("Rebuild rate %d: ", detail->args.rate); 506763fae79SScott Long } 507763fae79SScott Long break; 508763fae79SScott Long case MR_EVT_ARGS_TIME: 509763fae79SScott Long if (verbose) { 510763fae79SScott Long printf("Adapter time %s; %d seconds since power on: ", 511763fae79SScott Long format_timestamp(detail->args.time.rtc), 512763fae79SScott Long detail->args.time.elapsedSeconds); 513763fae79SScott Long } 514763fae79SScott Long break; 515763fae79SScott Long case MR_EVT_ARGS_ECC: 516763fae79SScott Long if (verbose) { 517763fae79SScott Long printf("Adapter ECC %x,%x: %s: ", 518763fae79SScott Long detail->args.ecc.ecar, 519763fae79SScott Long detail->args.ecc.elog, 520763fae79SScott Long detail->args.ecc.str); 521763fae79SScott Long } 522763fae79SScott Long break; 523763fae79SScott Long default: 524763fae79SScott Long if (verbose) { 525763fae79SScott Long printf("Type %d: ", detail->arg_type); 526763fae79SScott Long } 527763fae79SScott Long break; 528763fae79SScott Long } 529763fae79SScott Long printf("%s\n", detail->description); 530763fae79SScott Long } 531763fae79SScott Long 532763fae79SScott Long static int 533763fae79SScott Long show_events(int ac, char **av) 534763fae79SScott Long { 535763fae79SScott Long struct mfi_evt_log_state info; 536763fae79SScott Long struct mfi_evt_list *list; 537763fae79SScott Long union mfi_evt filter; 538186ddf96SJohn Baldwin bool first; 539763fae79SScott Long long val; 540763fae79SScott Long char *cp; 541763fae79SScott Long ssize_t size; 542763fae79SScott Long uint32_t seq, start, stop; 5433ac0e476SDimitry Andric uint16_t locale; 544763fae79SScott Long uint8_t status; 545c02999d9SJohn Baldwin int ch, error, fd, num_events, verbose; 546763fae79SScott Long u_int i; 547763fae79SScott Long 5487e0f8b79SDoug Ambrisko fd = mfi_open(mfi_device, O_RDWR); 549763fae79SScott Long if (fd < 0) { 550c02999d9SJohn Baldwin error = errno; 551763fae79SScott Long warn("mfi_open"); 552c02999d9SJohn Baldwin return (error); 553763fae79SScott Long } 554763fae79SScott Long 555763fae79SScott Long if (mfi_event_get_info(fd, &info, NULL) < 0) { 556c02999d9SJohn Baldwin error = errno; 557763fae79SScott Long warn("Failed to get event log info"); 558375c4656SBjoern A. Zeeb close(fd); 559c02999d9SJohn Baldwin return (error); 560763fae79SScott Long } 561763fae79SScott Long 562763fae79SScott Long /* Default settings. */ 563763fae79SScott Long num_events = 15; 564763fae79SScott Long filter.members.reserved = 0; 565763fae79SScott Long filter.members.locale = MFI_EVT_LOCALE_ALL; 566aacea6e2SEd Maste filter.members.evt_class = MFI_EVT_CLASS_WARNING; 567763fae79SScott Long start = info.boot_seq_num; 568763fae79SScott Long stop = info.newest_seq_num; 569763fae79SScott Long verbose = 0; 570763fae79SScott Long 571763fae79SScott Long /* Parse any options. */ 572763fae79SScott Long optind = 1; 573763fae79SScott Long while ((ch = getopt(ac, av, "c:l:n:v")) != -1) { 574763fae79SScott Long switch (ch) { 575763fae79SScott Long case 'c': 576aacea6e2SEd Maste if (parse_class(optarg, &filter.members.evt_class) < 0) { 577c02999d9SJohn Baldwin error = errno; 578763fae79SScott Long warn("Error parsing event class"); 579375c4656SBjoern A. Zeeb close(fd); 580c02999d9SJohn Baldwin return (error); 581763fae79SScott Long } 582763fae79SScott Long break; 583763fae79SScott Long case 'l': 5843ac0e476SDimitry Andric if (parse_locale(optarg, &locale) < 0) { 585c02999d9SJohn Baldwin error = errno; 586763fae79SScott Long warn("Error parsing event locale"); 587375c4656SBjoern A. Zeeb close(fd); 588c02999d9SJohn Baldwin return (error); 589763fae79SScott Long } 5903ac0e476SDimitry Andric filter.members.locale = locale; 591763fae79SScott Long break; 592763fae79SScott Long case 'n': 593763fae79SScott Long val = strtol(optarg, &cp, 0); 594763fae79SScott Long if (*cp != '\0' || val <= 0) { 595763fae79SScott Long warnx("Invalid event count"); 596375c4656SBjoern A. Zeeb close(fd); 597763fae79SScott Long return (EINVAL); 598763fae79SScott Long } 599763fae79SScott Long num_events = val; 600763fae79SScott Long break; 601763fae79SScott Long case 'v': 602763fae79SScott Long verbose = 1; 603763fae79SScott Long break; 604763fae79SScott Long case '?': 605763fae79SScott Long default: 606375c4656SBjoern A. Zeeb close(fd); 607763fae79SScott Long return (EINVAL); 608763fae79SScott Long } 609763fae79SScott Long } 610763fae79SScott Long ac -= optind; 611763fae79SScott Long av += optind; 612763fae79SScott Long 613763fae79SScott Long /* Determine buffer size and validate it. */ 614763fae79SScott Long size = sizeof(struct mfi_evt_list) + sizeof(struct mfi_evt_detail) * 615763fae79SScott Long (num_events - 1); 616763fae79SScott Long if (size > getpagesize()) { 617763fae79SScott Long warnx("Event count is too high"); 618375c4656SBjoern A. Zeeb close(fd); 619763fae79SScott Long return (EINVAL); 620763fae79SScott Long } 621763fae79SScott Long 622763fae79SScott Long /* Handle optional start and stop sequence numbers. */ 623763fae79SScott Long if (ac > 2) { 624763fae79SScott Long warnx("show events: extra arguments"); 625375c4656SBjoern A. Zeeb close(fd); 626763fae79SScott Long return (EINVAL); 627763fae79SScott Long } 628763fae79SScott Long if (ac > 0 && parse_seq(&info, av[0], &start) < 0) { 629c02999d9SJohn Baldwin error = errno; 630763fae79SScott Long warn("Error parsing starting sequence number"); 631375c4656SBjoern A. Zeeb close(fd); 632c02999d9SJohn Baldwin return (error); 633763fae79SScott Long } 634763fae79SScott Long if (ac > 1 && parse_seq(&info, av[1], &stop) < 0) { 635c02999d9SJohn Baldwin error = errno; 636763fae79SScott Long warn("Error parsing ending sequence number"); 637375c4656SBjoern A. Zeeb close(fd); 638c02999d9SJohn Baldwin return (error); 639763fae79SScott Long } 640763fae79SScott Long 641763fae79SScott Long list = malloc(size); 6423c22a809SJohn Baldwin if (list == NULL) { 6433c22a809SJohn Baldwin warnx("malloc failed"); 644375c4656SBjoern A. Zeeb close(fd); 6453c22a809SJohn Baldwin return (ENOMEM); 6463c22a809SJohn Baldwin } 647186ddf96SJohn Baldwin first = true; 648186ddf96SJohn Baldwin seq = start; 649186ddf96SJohn Baldwin for (;;) { 650763fae79SScott Long if (mfi_get_events(fd, list, num_events, filter, seq, 651763fae79SScott Long &status) < 0) { 652c02999d9SJohn Baldwin error = errno; 653763fae79SScott Long warn("Failed to fetch events"); 654375c4656SBjoern A. Zeeb free(list); 655375c4656SBjoern A. Zeeb close(fd); 656c02999d9SJohn Baldwin return (error); 657763fae79SScott Long } 658763fae79SScott Long if (status == MFI_STAT_NOT_FOUND) { 659763fae79SScott Long break; 660763fae79SScott Long } 661763fae79SScott Long if (status != MFI_STAT_OK) { 662763fae79SScott Long warnx("Error fetching events: %s", mfi_status(status)); 663375c4656SBjoern A. Zeeb free(list); 664375c4656SBjoern A. Zeeb close(fd); 665763fae79SScott Long return (EIO); 666763fae79SScott Long } 667763fae79SScott Long 668763fae79SScott Long for (i = 0; i < list->count; i++) { 669763fae79SScott Long /* 670763fae79SScott Long * If this event is newer than 'stop_seq' then 671763fae79SScott Long * break out of the loop. Note that the log 672763fae79SScott Long * is a circular buffer so we have to handle 673763fae79SScott Long * the case that our stop point is earlier in 674763fae79SScott Long * the buffer than our start point. 675763fae79SScott Long */ 676186ddf96SJohn Baldwin if (list->event[i].seq > stop) { 677763fae79SScott Long if (start <= stop) 678186ddf96SJohn Baldwin goto finish; 679763fae79SScott Long else if (list->event[i].seq < start) 680186ddf96SJohn Baldwin goto finish; 681763fae79SScott Long } 682763fae79SScott Long mfi_decode_evt(fd, &list->event[i], verbose); 683186ddf96SJohn Baldwin first = false; 684763fae79SScott Long } 685763fae79SScott Long 686763fae79SScott Long /* 687763fae79SScott Long * XXX: If the event's seq # is the end of the buffer 688763fae79SScott Long * then this probably won't do the right thing. We 689763fae79SScott Long * need to know the size of the buffer somehow. 690763fae79SScott Long */ 691763fae79SScott Long seq = list->event[list->count - 1].seq + 1; 692763fae79SScott Long 693763fae79SScott Long } 694186ddf96SJohn Baldwin finish: 695186ddf96SJohn Baldwin if (first) 696186ddf96SJohn Baldwin warnx("No matching events found"); 697763fae79SScott Long 698763fae79SScott Long free(list); 699763fae79SScott Long close(fd); 700763fae79SScott Long 701763fae79SScott Long return (0); 702763fae79SScott Long } 703763fae79SScott Long MFI_COMMAND(show, events, show_events); 704