mfi_evt.c revision 237589
1196200Sscottl/*- 2196200Sscottl * Copyright (c) 2008, 2009 Yahoo!, Inc. 3196200Sscottl * All rights reserved. 4196200Sscottl * 5196200Sscottl * Redistribution and use in source and binary forms, with or without 6196200Sscottl * modification, are permitted provided that the following conditions 7196200Sscottl * are met: 8196200Sscottl * 1. Redistributions of source code must retain the above copyright 9196200Sscottl * notice, this list of conditions and the following disclaimer. 10196200Sscottl * 2. Redistributions in binary form must reproduce the above copyright 11196200Sscottl * notice, this list of conditions and the following disclaimer in the 12196200Sscottl * documentation and/or other materials provided with the distribution. 13196200Sscottl * 3. The names of the authors may not be used to endorse or promote 14196200Sscottl * products derived from this software without specific prior written 15196200Sscottl * permission. 16196200Sscottl * 17196200Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18196200Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19196200Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20196200Sscottl * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21196200Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22196200Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23196200Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24196200Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25196200Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26196200Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27196200Sscottl * SUCH DAMAGE. 28196200Sscottl * 29196200Sscottl * $FreeBSD: stable/9/usr.sbin/mfiutil/mfi_evt.c 237589 2012-06-26 03:05:17Z eadler $ 30196200Sscottl */ 31196200Sscottl 32196200Sscottl#include <sys/types.h> 33196200Sscottl#include <sys/errno.h> 34196200Sscottl#include <err.h> 35237589Seadler#include <fcntl.h> 36196200Sscottl#include <stdio.h> 37196200Sscottl#include <stdlib.h> 38196200Sscottl#include <strings.h> 39196200Sscottl#include <time.h> 40196200Sscottl#include <unistd.h> 41196200Sscottl#include "mfiutil.h" 42196200Sscottl 43196200Sscottlstatic int 44196200Sscottlmfi_event_get_info(int fd, struct mfi_evt_log_state *info, uint8_t *statusp) 45196200Sscottl{ 46196200Sscottl 47196200Sscottl return (mfi_dcmd_command(fd, MFI_DCMD_CTRL_EVENT_GETINFO, info, 48196200Sscottl sizeof(struct mfi_evt_log_state), NULL, 0, statusp)); 49196200Sscottl} 50196200Sscottl 51196200Sscottlstatic int 52196200Sscottlmfi_get_events(int fd, struct mfi_evt_list *list, int num_events, 53196200Sscottl union mfi_evt filter, uint32_t start_seq, uint8_t *statusp) 54196200Sscottl{ 55196200Sscottl uint32_t mbox[2]; 56196200Sscottl size_t size; 57196200Sscottl 58196200Sscottl mbox[0] = start_seq; 59196200Sscottl mbox[1] = filter.word; 60196200Sscottl size = sizeof(struct mfi_evt_list) + sizeof(struct mfi_evt_detail) * 61196200Sscottl (num_events - 1); 62196200Sscottl return (mfi_dcmd_command(fd, MFI_DCMD_CTRL_EVENT_GET, list, size, 63196200Sscottl (uint8_t *)&mbox, sizeof(mbox), statusp)); 64196200Sscottl} 65196200Sscottl 66196200Sscottlstatic int 67237589Seadlershow_logstate(int ac, char **av __unused) 68196200Sscottl{ 69196200Sscottl struct mfi_evt_log_state info; 70214396Sjhb int error, fd; 71196200Sscottl 72196200Sscottl if (ac != 1) { 73196200Sscottl warnx("show logstate: extra arguments"); 74196200Sscottl return (EINVAL); 75196200Sscottl } 76196200Sscottl 77237589Seadler fd = mfi_open(mfi_unit, O_RDWR); 78196200Sscottl if (fd < 0) { 79214396Sjhb error = errno; 80196200Sscottl warn("mfi_open"); 81214396Sjhb return (error); 82196200Sscottl } 83196200Sscottl 84196200Sscottl if (mfi_event_get_info(fd, &info, NULL) < 0) { 85214396Sjhb error = errno; 86196200Sscottl warn("Failed to get event log info"); 87222899Sbz close(fd); 88214396Sjhb return (error); 89196200Sscottl } 90196200Sscottl 91196200Sscottl printf("mfi%d Event Log Sequence Numbers:\n", mfi_unit); 92196200Sscottl printf(" Newest Seq #: %u\n", info.newest_seq_num); 93196200Sscottl printf(" Oldest Seq #: %u\n", info.oldest_seq_num); 94196200Sscottl printf(" Clear Seq #: %u\n", info.clear_seq_num); 95196200Sscottl printf("Shutdown Seq #: %u\n", info.shutdown_seq_num); 96196200Sscottl printf(" Boot Seq #: %u\n", info.boot_seq_num); 97196200Sscottl 98196200Sscottl close(fd); 99196200Sscottl 100196200Sscottl return (0); 101196200Sscottl} 102196200SscottlMFI_COMMAND(show, logstate, show_logstate); 103196200Sscottl 104196200Sscottlstatic int 105196200Sscottlparse_seq(struct mfi_evt_log_state *info, char *arg, uint32_t *seq) 106196200Sscottl{ 107196200Sscottl char *cp; 108196200Sscottl long val; 109196200Sscottl 110196200Sscottl if (strcasecmp(arg, "newest") == 0) { 111196200Sscottl *seq = info->newest_seq_num; 112196200Sscottl return (0); 113196200Sscottl } 114196200Sscottl if (strcasecmp(arg, "oldest") == 0) { 115196200Sscottl *seq = info->oldest_seq_num; 116196200Sscottl return (0); 117196200Sscottl } 118196200Sscottl if (strcasecmp(arg, "clear") == 0) { 119196200Sscottl *seq = info->clear_seq_num; 120196200Sscottl return (0); 121196200Sscottl } 122196200Sscottl if (strcasecmp(arg, "shutdown") == 0) { 123196200Sscottl *seq = info->shutdown_seq_num; 124196200Sscottl return (0); 125196200Sscottl } 126196200Sscottl if (strcasecmp(arg, "boot") == 0) { 127196200Sscottl *seq = info->boot_seq_num; 128196200Sscottl return (0); 129196200Sscottl } 130196200Sscottl val = strtol(arg, &cp, 0); 131196200Sscottl if (*cp != '\0' || val < 0) { 132196200Sscottl errno = EINVAL; 133196200Sscottl return (-1); 134196200Sscottl } 135196200Sscottl *seq = val; 136196200Sscottl return (0); 137196200Sscottl} 138196200Sscottl 139196200Sscottlstatic int 140196200Sscottlparse_locale(char *arg, uint16_t *locale) 141196200Sscottl{ 142196200Sscottl char *cp; 143196200Sscottl long val; 144196200Sscottl 145196200Sscottl if (strncasecmp(arg, "vol", 3) == 0 || strcasecmp(arg, "ld") == 0) { 146196200Sscottl *locale = MFI_EVT_LOCALE_LD; 147196200Sscottl return (0); 148196200Sscottl } 149196200Sscottl if (strncasecmp(arg, "drive", 5) == 0 || strcasecmp(arg, "pd") == 0) { 150196200Sscottl *locale = MFI_EVT_LOCALE_PD; 151196200Sscottl return (0); 152196200Sscottl } 153196200Sscottl if (strncasecmp(arg, "encl", 4) == 0) { 154196200Sscottl *locale = MFI_EVT_LOCALE_ENCL; 155196200Sscottl return (0); 156196200Sscottl } 157196200Sscottl if (strncasecmp(arg, "batt", 4) == 0 || 158196200Sscottl strncasecmp(arg, "bbu", 3) == 0) { 159196200Sscottl *locale = MFI_EVT_LOCALE_BBU; 160196200Sscottl return (0); 161196200Sscottl } 162196200Sscottl if (strcasecmp(arg, "sas") == 0) { 163196200Sscottl *locale = MFI_EVT_LOCALE_SAS; 164196200Sscottl return (0); 165196200Sscottl } 166196200Sscottl if (strcasecmp(arg, "ctrl") == 0 || strncasecmp(arg, "cont", 4) == 0) { 167196200Sscottl *locale = MFI_EVT_LOCALE_CTRL; 168196200Sscottl return (0); 169196200Sscottl } 170196200Sscottl if (strcasecmp(arg, "config") == 0) { 171196200Sscottl *locale = MFI_EVT_LOCALE_CONFIG; 172196200Sscottl return (0); 173196200Sscottl } 174196200Sscottl if (strcasecmp(arg, "cluster") == 0) { 175196200Sscottl *locale = MFI_EVT_LOCALE_CLUSTER; 176196200Sscottl return (0); 177196200Sscottl } 178196200Sscottl if (strcasecmp(arg, "all") == 0) { 179196200Sscottl *locale = MFI_EVT_LOCALE_ALL; 180196200Sscottl return (0); 181196200Sscottl } 182196200Sscottl val = strtol(arg, &cp, 0); 183196200Sscottl if (*cp != '\0' || val < 0 || val > 0xffff) { 184196200Sscottl errno = EINVAL; 185196200Sscottl return (-1); 186196200Sscottl } 187196200Sscottl *locale = val; 188196200Sscottl return (0); 189196200Sscottl} 190196200Sscottl 191196200Sscottlstatic int 192196200Sscottlparse_class(char *arg, int8_t *class) 193196200Sscottl{ 194196200Sscottl char *cp; 195196200Sscottl long val; 196196200Sscottl 197196200Sscottl if (strcasecmp(arg, "debug") == 0) { 198196200Sscottl *class = MFI_EVT_CLASS_DEBUG; 199196200Sscottl return (0); 200196200Sscottl } 201196200Sscottl if (strncasecmp(arg, "prog", 4) == 0) { 202196200Sscottl *class = MFI_EVT_CLASS_PROGRESS; 203196200Sscottl return (0); 204196200Sscottl } 205196200Sscottl if (strncasecmp(arg, "info", 4) == 0) { 206196200Sscottl *class = MFI_EVT_CLASS_INFO; 207196200Sscottl return (0); 208196200Sscottl } 209196200Sscottl if (strncasecmp(arg, "warn", 4) == 0) { 210196200Sscottl *class = MFI_EVT_CLASS_WARNING; 211196200Sscottl return (0); 212196200Sscottl } 213196200Sscottl if (strncasecmp(arg, "crit", 4) == 0) { 214196200Sscottl *class = MFI_EVT_CLASS_CRITICAL; 215196200Sscottl return (0); 216196200Sscottl } 217196200Sscottl if (strcasecmp(arg, "fatal") == 0) { 218196200Sscottl *class = MFI_EVT_CLASS_FATAL; 219196200Sscottl return (0); 220196200Sscottl } 221196200Sscottl if (strcasecmp(arg, "dead") == 0) { 222196200Sscottl *class = MFI_EVT_CLASS_DEAD; 223196200Sscottl return (0); 224196200Sscottl } 225196200Sscottl val = strtol(arg, &cp, 0); 226196200Sscottl if (*cp != '\0' || val < -128 || val > 127) { 227196200Sscottl errno = EINVAL; 228196200Sscottl return (-1); 229196200Sscottl } 230196200Sscottl *class = val; 231196200Sscottl return (0); 232196200Sscottl} 233196200Sscottl 234196200Sscottl/* 235196200Sscottl * The timestamp is the number of seconds since 00:00 Jan 1, 2000. If 236196200Sscottl * the bits in 24-31 are all set, then it is the number of seconds since 237196200Sscottl * boot. 238196200Sscottl */ 239196200Sscottlstatic const char * 240196200Sscottlformat_timestamp(uint32_t timestamp) 241196200Sscottl{ 242196200Sscottl static char buffer[32]; 243196200Sscottl static time_t base; 244196200Sscottl time_t t; 245196200Sscottl struct tm tm; 246196200Sscottl 247196200Sscottl if ((timestamp & 0xff000000) == 0xff000000) { 248196200Sscottl snprintf(buffer, sizeof(buffer), "boot + %us", timestamp & 249196200Sscottl 0x00ffffff); 250196200Sscottl return (buffer); 251196200Sscottl } 252196200Sscottl 253196200Sscottl if (base == 0) { 254196200Sscottl /* Compute 00:00 Jan 1, 2000 offset. */ 255196200Sscottl bzero(&tm, sizeof(tm)); 256196200Sscottl tm.tm_mday = 1; 257196200Sscottl tm.tm_year = (2000 - 1900); 258196200Sscottl base = mktime(&tm); 259196200Sscottl } 260196200Sscottl if (base == -1) { 261196200Sscottl snprintf(buffer, sizeof(buffer), "%us", timestamp); 262196200Sscottl return (buffer); 263196200Sscottl } 264196200Sscottl t = base + timestamp; 265196200Sscottl strftime(buffer, sizeof(buffer), "%+", localtime(&t)); 266196200Sscottl return (buffer); 267196200Sscottl} 268196200Sscottl 269196200Sscottlstatic const char * 270196200Sscottlformat_locale(uint16_t locale) 271196200Sscottl{ 272196200Sscottl static char buffer[8]; 273196200Sscottl 274196200Sscottl switch (locale) { 275196200Sscottl case MFI_EVT_LOCALE_LD: 276196200Sscottl return ("VOLUME"); 277196200Sscottl case MFI_EVT_LOCALE_PD: 278196200Sscottl return ("DRIVE"); 279196200Sscottl case MFI_EVT_LOCALE_ENCL: 280196200Sscottl return ("ENCL"); 281196200Sscottl case MFI_EVT_LOCALE_BBU: 282196200Sscottl return ("BATTERY"); 283196200Sscottl case MFI_EVT_LOCALE_SAS: 284196200Sscottl return ("SAS"); 285196200Sscottl case MFI_EVT_LOCALE_CTRL: 286196200Sscottl return ("CTRL"); 287196200Sscottl case MFI_EVT_LOCALE_CONFIG: 288196200Sscottl return ("CONFIG"); 289196200Sscottl case MFI_EVT_LOCALE_CLUSTER: 290196200Sscottl return ("CLUSTER"); 291196200Sscottl case MFI_EVT_LOCALE_ALL: 292196200Sscottl return ("ALL"); 293196200Sscottl default: 294196200Sscottl snprintf(buffer, sizeof(buffer), "0x%04x", locale); 295196200Sscottl return (buffer); 296196200Sscottl } 297196200Sscottl} 298196200Sscottl 299196200Sscottlstatic const char * 300196200Sscottlformat_class(int8_t class) 301196200Sscottl{ 302196200Sscottl static char buffer[6]; 303196200Sscottl 304196200Sscottl switch (class) { 305196200Sscottl case MFI_EVT_CLASS_DEBUG: 306196200Sscottl return ("debug"); 307196200Sscottl case MFI_EVT_CLASS_PROGRESS: 308196200Sscottl return ("progress"); 309196200Sscottl case MFI_EVT_CLASS_INFO: 310196200Sscottl return ("info"); 311196200Sscottl case MFI_EVT_CLASS_WARNING: 312196200Sscottl return ("WARN"); 313196200Sscottl case MFI_EVT_CLASS_CRITICAL: 314196200Sscottl return ("CRIT"); 315196200Sscottl case MFI_EVT_CLASS_FATAL: 316196200Sscottl return ("FATAL"); 317196200Sscottl case MFI_EVT_CLASS_DEAD: 318196200Sscottl return ("DEAD"); 319196200Sscottl default: 320196200Sscottl snprintf(buffer, sizeof(buffer), "%d", class); 321196200Sscottl return (buffer); 322196200Sscottl } 323196200Sscottl} 324196200Sscottl 325196200Sscottl/* Simulates %D from kernel printf(9). */ 326196200Sscottlstatic void 327196200Sscottlsimple_hex(void *ptr, size_t length, const char *separator) 328196200Sscottl{ 329196200Sscottl unsigned char *cp; 330196200Sscottl u_int i; 331196200Sscottl 332196200Sscottl if (length == 0) 333196200Sscottl return; 334196200Sscottl cp = ptr; 335196200Sscottl printf("%02x", cp[0]); 336196200Sscottl for (i = 1; i < length; i++) 337196200Sscottl printf("%s%02x", separator, cp[i]); 338196200Sscottl} 339196200Sscottl 340196200Sscottlstatic const char * 341196200Sscottlpdrive_location(struct mfi_evt_pd *pd) 342196200Sscottl{ 343196200Sscottl static char buffer[16]; 344196200Sscottl 345196200Sscottl if (pd->enclosure_index == 0) 346196200Sscottl snprintf(buffer, sizeof(buffer), "%02d(s%d)", pd->device_id, 347196200Sscottl pd->slot_number); 348196200Sscottl else 349196200Sscottl snprintf(buffer, sizeof(buffer), "%02d(e%d/s%d)", pd->device_id, 350196200Sscottl pd->enclosure_index, pd->slot_number); 351196200Sscottl return (buffer); 352196200Sscottl} 353196200Sscottl 354196200Sscottlstatic const char * 355196200Sscottlvolume_name(int fd, struct mfi_evt_ld *ld) 356196200Sscottl{ 357196200Sscottl 358196200Sscottl return (mfi_volume_name(fd, ld->target_id)); 359196200Sscottl} 360196200Sscottl 361196200Sscottl/* Ripped from sys/dev/mfi/mfi.c. */ 362196200Sscottlstatic void 363196200Sscottlmfi_decode_evt(int fd, struct mfi_evt_detail *detail, int verbose) 364196200Sscottl{ 365196200Sscottl 366196200Sscottl printf("%5d (%s/%s/%s) - ", detail->seq, format_timestamp(detail->time), 367222589Semaste format_locale(detail->evt_class.members.locale), 368222589Semaste format_class(detail->evt_class.members.evt_class)); 369196200Sscottl switch (detail->arg_type) { 370196200Sscottl case MR_EVT_ARGS_NONE: 371196200Sscottl break; 372196200Sscottl case MR_EVT_ARGS_CDB_SENSE: 373196200Sscottl if (verbose) { 374196200Sscottl printf("PD %s CDB ", 375196200Sscottl pdrive_location(&detail->args.cdb_sense.pd) 376196200Sscottl ); 377196200Sscottl simple_hex(detail->args.cdb_sense.cdb, 378196200Sscottl detail->args.cdb_sense.cdb_len, ":"); 379196200Sscottl printf(" Sense "); 380196200Sscottl simple_hex(detail->args.cdb_sense.sense, 381196200Sscottl detail->args.cdb_sense.sense_len, ":"); 382196200Sscottl printf(":\n "); 383196200Sscottl } 384196200Sscottl break; 385196200Sscottl case MR_EVT_ARGS_LD: 386196200Sscottl printf("VOL %s event: ", volume_name(fd, &detail->args.ld)); 387196200Sscottl break; 388196200Sscottl case MR_EVT_ARGS_LD_COUNT: 389196200Sscottl printf("VOL %s", volume_name(fd, &detail->args.ld_count.ld)); 390196200Sscottl if (verbose) { 391196200Sscottl printf(" count %lld: ", 392196200Sscottl (long long)detail->args.ld_count.count); 393196200Sscottl } 394196200Sscottl printf(": "); 395196200Sscottl break; 396196200Sscottl case MR_EVT_ARGS_LD_LBA: 397196200Sscottl printf("VOL %s", volume_name(fd, &detail->args.ld_count.ld)); 398196200Sscottl if (verbose) { 399196200Sscottl printf(" lba %lld", 400196200Sscottl (long long)detail->args.ld_lba.lba); 401196200Sscottl } 402196200Sscottl printf(": "); 403196200Sscottl break; 404196200Sscottl case MR_EVT_ARGS_LD_OWNER: 405196200Sscottl printf("VOL %s", volume_name(fd, &detail->args.ld_count.ld)); 406196200Sscottl if (verbose) { 407196200Sscottl printf(" owner changed: prior %d, new %d", 408196200Sscottl detail->args.ld_owner.pre_owner, 409196200Sscottl detail->args.ld_owner.new_owner); 410196200Sscottl } 411196200Sscottl printf(": "); 412196200Sscottl break; 413196200Sscottl case MR_EVT_ARGS_LD_LBA_PD_LBA: 414196200Sscottl printf("VOL %s", volume_name(fd, &detail->args.ld_count.ld)); 415196200Sscottl if (verbose) { 416196200Sscottl printf(" lba %lld, physical drive PD %s lba %lld", 417196200Sscottl (long long)detail->args.ld_lba_pd_lba.ld_lba, 418196200Sscottl pdrive_location(&detail->args.ld_lba_pd_lba.pd), 419196200Sscottl (long long)detail->args.ld_lba_pd_lba.pd_lba); 420196200Sscottl } 421196200Sscottl printf(": "); 422196200Sscottl break; 423196200Sscottl case MR_EVT_ARGS_LD_PROG: 424196200Sscottl printf("VOL %s", volume_name(fd, &detail->args.ld_prog.ld)); 425196200Sscottl if (verbose) { 426196200Sscottl printf(" progress %d%% in %ds", 427196200Sscottl detail->args.ld_prog.prog.progress/655, 428196200Sscottl detail->args.ld_prog.prog.elapsed_seconds); 429196200Sscottl } 430196200Sscottl printf(": "); 431196200Sscottl break; 432196200Sscottl case MR_EVT_ARGS_LD_STATE: 433196200Sscottl printf("VOL %s", volume_name(fd, &detail->args.ld_prog.ld)); 434196200Sscottl if (verbose) { 435196200Sscottl printf(" state prior %s new %s", 436196200Sscottl mfi_ldstate(detail->args.ld_state.prev_state), 437196200Sscottl mfi_ldstate(detail->args.ld_state.new_state)); 438196200Sscottl } 439196200Sscottl printf(": "); 440196200Sscottl break; 441196200Sscottl case MR_EVT_ARGS_LD_STRIP: 442229623Sjhb printf("VOL %s", volume_name(fd, &detail->args.ld_strip.ld)); 443196200Sscottl if (verbose) { 444196200Sscottl printf(" strip %lld", 445196200Sscottl (long long)detail->args.ld_strip.strip); 446196200Sscottl } 447196200Sscottl printf(": "); 448196200Sscottl break; 449196200Sscottl case MR_EVT_ARGS_PD: 450196200Sscottl if (verbose) { 451196200Sscottl printf("PD %s event: ", 452196200Sscottl pdrive_location(&detail->args.pd)); 453196200Sscottl } 454196200Sscottl break; 455196200Sscottl case MR_EVT_ARGS_PD_ERR: 456196200Sscottl if (verbose) { 457196200Sscottl printf("PD %s err %d: ", 458196200Sscottl pdrive_location(&detail->args.pd_err.pd), 459196200Sscottl detail->args.pd_err.err); 460196200Sscottl } 461196200Sscottl break; 462196200Sscottl case MR_EVT_ARGS_PD_LBA: 463196200Sscottl if (verbose) { 464196200Sscottl printf("PD %s lba %lld: ", 465196200Sscottl pdrive_location(&detail->args.pd_lba.pd), 466196200Sscottl (long long)detail->args.pd_lba.lba); 467196200Sscottl } 468196200Sscottl break; 469196200Sscottl case MR_EVT_ARGS_PD_LBA_LD: 470196200Sscottl if (verbose) { 471196200Sscottl printf("PD %s lba %lld VOL %s: ", 472196200Sscottl pdrive_location(&detail->args.pd_lba_ld.pd), 473196200Sscottl (long long)detail->args.pd_lba.lba, 474196200Sscottl volume_name(fd, &detail->args.pd_lba_ld.ld)); 475196200Sscottl } 476196200Sscottl break; 477196200Sscottl case MR_EVT_ARGS_PD_PROG: 478196200Sscottl if (verbose) { 479196200Sscottl printf("PD %s progress %d%% seconds %ds: ", 480196200Sscottl pdrive_location(&detail->args.pd_prog.pd), 481196200Sscottl detail->args.pd_prog.prog.progress/655, 482196200Sscottl detail->args.pd_prog.prog.elapsed_seconds); 483196200Sscottl } 484196200Sscottl break; 485196200Sscottl case MR_EVT_ARGS_PD_STATE: 486196200Sscottl if (verbose) { 487196200Sscottl printf("PD %s state prior %s new %s: ", 488196200Sscottl pdrive_location(&detail->args.pd_prog.pd), 489196200Sscottl mfi_pdstate(detail->args.pd_state.prev_state), 490196200Sscottl mfi_pdstate(detail->args.pd_state.new_state)); 491196200Sscottl } 492196200Sscottl break; 493196200Sscottl case MR_EVT_ARGS_PCI: 494196200Sscottl if (verbose) { 495196200Sscottl printf("PCI 0x%04x 0x%04x 0x%04x 0x%04x: ", 496196200Sscottl detail->args.pci.venderId, 497196200Sscottl detail->args.pci.deviceId, 498196200Sscottl detail->args.pci.subVenderId, 499196200Sscottl detail->args.pci.subDeviceId); 500196200Sscottl } 501196200Sscottl break; 502196200Sscottl case MR_EVT_ARGS_RATE: 503196200Sscottl if (verbose) { 504196200Sscottl printf("Rebuild rate %d: ", detail->args.rate); 505196200Sscottl } 506196200Sscottl break; 507196200Sscottl case MR_EVT_ARGS_TIME: 508196200Sscottl if (verbose) { 509196200Sscottl printf("Adapter time %s; %d seconds since power on: ", 510196200Sscottl format_timestamp(detail->args.time.rtc), 511196200Sscottl detail->args.time.elapsedSeconds); 512196200Sscottl } 513196200Sscottl break; 514196200Sscottl case MR_EVT_ARGS_ECC: 515196200Sscottl if (verbose) { 516196200Sscottl printf("Adapter ECC %x,%x: %s: ", 517196200Sscottl detail->args.ecc.ecar, 518196200Sscottl detail->args.ecc.elog, 519196200Sscottl detail->args.ecc.str); 520196200Sscottl } 521196200Sscottl break; 522196200Sscottl default: 523196200Sscottl if (verbose) { 524196200Sscottl printf("Type %d: ", detail->arg_type); 525196200Sscottl } 526196200Sscottl break; 527196200Sscottl } 528196200Sscottl printf("%s\n", detail->description); 529196200Sscottl} 530196200Sscottl 531196200Sscottlstatic int 532196200Sscottlshow_events(int ac, char **av) 533196200Sscottl{ 534196200Sscottl struct mfi_evt_log_state info; 535196200Sscottl struct mfi_evt_list *list; 536196200Sscottl union mfi_evt filter; 537196200Sscottl long val; 538196200Sscottl char *cp; 539196200Sscottl ssize_t size; 540196200Sscottl uint32_t seq, start, stop; 541196200Sscottl uint8_t status; 542214396Sjhb int ch, error, fd, num_events, verbose; 543196200Sscottl u_int i; 544196200Sscottl 545237589Seadler fd = mfi_open(mfi_unit, O_RDWR); 546196200Sscottl if (fd < 0) { 547214396Sjhb error = errno; 548196200Sscottl warn("mfi_open"); 549214396Sjhb return (error); 550196200Sscottl } 551196200Sscottl 552196200Sscottl if (mfi_event_get_info(fd, &info, NULL) < 0) { 553214396Sjhb error = errno; 554196200Sscottl warn("Failed to get event log info"); 555222899Sbz close(fd); 556214396Sjhb return (error); 557196200Sscottl } 558196200Sscottl 559196200Sscottl /* Default settings. */ 560196200Sscottl num_events = 15; 561196200Sscottl filter.members.reserved = 0; 562196200Sscottl filter.members.locale = MFI_EVT_LOCALE_ALL; 563222589Semaste filter.members.evt_class = MFI_EVT_CLASS_WARNING; 564196200Sscottl start = info.boot_seq_num; 565196200Sscottl stop = info.newest_seq_num; 566196200Sscottl verbose = 0; 567196200Sscottl 568196200Sscottl /* Parse any options. */ 569196200Sscottl optind = 1; 570196200Sscottl while ((ch = getopt(ac, av, "c:l:n:v")) != -1) { 571196200Sscottl switch (ch) { 572196200Sscottl case 'c': 573222589Semaste if (parse_class(optarg, &filter.members.evt_class) < 0) { 574214396Sjhb error = errno; 575196200Sscottl warn("Error parsing event class"); 576222899Sbz close(fd); 577214396Sjhb return (error); 578196200Sscottl } 579196200Sscottl break; 580196200Sscottl case 'l': 581196200Sscottl if (parse_locale(optarg, &filter.members.locale) < 0) { 582214396Sjhb error = errno; 583196200Sscottl warn("Error parsing event locale"); 584222899Sbz close(fd); 585214396Sjhb return (error); 586196200Sscottl } 587196200Sscottl break; 588196200Sscottl case 'n': 589196200Sscottl val = strtol(optarg, &cp, 0); 590196200Sscottl if (*cp != '\0' || val <= 0) { 591196200Sscottl warnx("Invalid event count"); 592222899Sbz close(fd); 593196200Sscottl return (EINVAL); 594196200Sscottl } 595196200Sscottl num_events = val; 596196200Sscottl break; 597196200Sscottl case 'v': 598196200Sscottl verbose = 1; 599196200Sscottl break; 600196200Sscottl case '?': 601196200Sscottl default: 602222899Sbz close(fd); 603196200Sscottl return (EINVAL); 604196200Sscottl } 605196200Sscottl } 606196200Sscottl ac -= optind; 607196200Sscottl av += optind; 608196200Sscottl 609196200Sscottl /* Determine buffer size and validate it. */ 610196200Sscottl size = sizeof(struct mfi_evt_list) + sizeof(struct mfi_evt_detail) * 611196200Sscottl (num_events - 1); 612196200Sscottl if (size > getpagesize()) { 613196200Sscottl warnx("Event count is too high"); 614222899Sbz close(fd); 615196200Sscottl return (EINVAL); 616196200Sscottl } 617196200Sscottl 618196200Sscottl /* Handle optional start and stop sequence numbers. */ 619196200Sscottl if (ac > 2) { 620196200Sscottl warnx("show events: extra arguments"); 621222899Sbz close(fd); 622196200Sscottl return (EINVAL); 623196200Sscottl } 624196200Sscottl if (ac > 0 && parse_seq(&info, av[0], &start) < 0) { 625214396Sjhb error = errno; 626196200Sscottl warn("Error parsing starting sequence number"); 627222899Sbz close(fd); 628214396Sjhb return (error); 629196200Sscottl } 630196200Sscottl if (ac > 1 && parse_seq(&info, av[1], &stop) < 0) { 631214396Sjhb error = errno; 632196200Sscottl warn("Error parsing ending sequence number"); 633222899Sbz close(fd); 634214396Sjhb return (error); 635196200Sscottl } 636196200Sscottl 637196200Sscottl list = malloc(size); 638215526Sjhb if (list == NULL) { 639215526Sjhb warnx("malloc failed"); 640222899Sbz close(fd); 641215526Sjhb return (ENOMEM); 642215526Sjhb } 643196200Sscottl for (seq = start;;) { 644196200Sscottl if (mfi_get_events(fd, list, num_events, filter, seq, 645196200Sscottl &status) < 0) { 646214396Sjhb error = errno; 647196200Sscottl warn("Failed to fetch events"); 648222899Sbz free(list); 649222899Sbz close(fd); 650214396Sjhb return (error); 651196200Sscottl } 652196200Sscottl if (status == MFI_STAT_NOT_FOUND) { 653196200Sscottl if (seq == start) 654196200Sscottl warnx("No matching events found"); 655196200Sscottl break; 656196200Sscottl } 657196200Sscottl if (status != MFI_STAT_OK) { 658196200Sscottl warnx("Error fetching events: %s", mfi_status(status)); 659222899Sbz free(list); 660222899Sbz close(fd); 661196200Sscottl return (EIO); 662196200Sscottl } 663196200Sscottl 664196200Sscottl for (i = 0; i < list->count; i++) { 665196200Sscottl /* 666196200Sscottl * If this event is newer than 'stop_seq' then 667196200Sscottl * break out of the loop. Note that the log 668196200Sscottl * is a circular buffer so we have to handle 669196200Sscottl * the case that our stop point is earlier in 670196200Sscottl * the buffer than our start point. 671196200Sscottl */ 672196200Sscottl if (list->event[i].seq >= stop) { 673196200Sscottl if (start <= stop) 674196200Sscottl break; 675196200Sscottl else if (list->event[i].seq < start) 676196200Sscottl break; 677196200Sscottl } 678196200Sscottl mfi_decode_evt(fd, &list->event[i], verbose); 679196200Sscottl } 680196200Sscottl 681196200Sscottl /* 682196200Sscottl * XXX: If the event's seq # is the end of the buffer 683196200Sscottl * then this probably won't do the right thing. We 684196200Sscottl * need to know the size of the buffer somehow. 685196200Sscottl */ 686196200Sscottl seq = list->event[list->count - 1].seq + 1; 687196200Sscottl 688196200Sscottl } 689196200Sscottl 690196200Sscottl free(list); 691196200Sscottl close(fd); 692196200Sscottl 693196200Sscottl return (0); 694196200Sscottl} 695196200SscottlMFI_COMMAND(show, events, show_events); 696