mfi_evt.c revision 215526
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: head/usr.sbin/mfiutil/mfi_evt.c 215526 2010-11-19 15:39:59Z jhb $ 30196200Sscottl */ 31196200Sscottl 32196200Sscottl#include <sys/types.h> 33196200Sscottl#include <sys/errno.h> 34196200Sscottl#include <err.h> 35196200Sscottl#include <stdio.h> 36196200Sscottl#include <stdlib.h> 37196200Sscottl#include <strings.h> 38196200Sscottl#include <time.h> 39196200Sscottl#include <unistd.h> 40196200Sscottl#include "mfiutil.h" 41196200Sscottl 42196200Sscottlstatic int 43196200Sscottlmfi_event_get_info(int fd, struct mfi_evt_log_state *info, uint8_t *statusp) 44196200Sscottl{ 45196200Sscottl 46196200Sscottl return (mfi_dcmd_command(fd, MFI_DCMD_CTRL_EVENT_GETINFO, info, 47196200Sscottl sizeof(struct mfi_evt_log_state), NULL, 0, statusp)); 48196200Sscottl} 49196200Sscottl 50196200Sscottlstatic int 51196200Sscottlmfi_get_events(int fd, struct mfi_evt_list *list, int num_events, 52196200Sscottl union mfi_evt filter, uint32_t start_seq, uint8_t *statusp) 53196200Sscottl{ 54196200Sscottl uint32_t mbox[2]; 55196200Sscottl size_t size; 56196200Sscottl 57196200Sscottl mbox[0] = start_seq; 58196200Sscottl mbox[1] = filter.word; 59196200Sscottl size = sizeof(struct mfi_evt_list) + sizeof(struct mfi_evt_detail) * 60196200Sscottl (num_events - 1); 61196200Sscottl return (mfi_dcmd_command(fd, MFI_DCMD_CTRL_EVENT_GET, list, size, 62196200Sscottl (uint8_t *)&mbox, sizeof(mbox), statusp)); 63196200Sscottl} 64196200Sscottl 65196200Sscottlstatic int 66196200Sscottlshow_logstate(int ac, char **av) 67196200Sscottl{ 68196200Sscottl struct mfi_evt_log_state info; 69214396Sjhb int error, fd; 70196200Sscottl 71196200Sscottl if (ac != 1) { 72196200Sscottl warnx("show logstate: extra arguments"); 73196200Sscottl return (EINVAL); 74196200Sscottl } 75196200Sscottl 76196200Sscottl fd = mfi_open(mfi_unit); 77196200Sscottl if (fd < 0) { 78214396Sjhb error = errno; 79196200Sscottl warn("mfi_open"); 80214396Sjhb return (error); 81196200Sscottl } 82196200Sscottl 83196200Sscottl if (mfi_event_get_info(fd, &info, NULL) < 0) { 84214396Sjhb error = errno; 85196200Sscottl warn("Failed to get event log info"); 86214396Sjhb return (error); 87196200Sscottl } 88196200Sscottl 89196200Sscottl printf("mfi%d Event Log Sequence Numbers:\n", mfi_unit); 90196200Sscottl printf(" Newest Seq #: %u\n", info.newest_seq_num); 91196200Sscottl printf(" Oldest Seq #: %u\n", info.oldest_seq_num); 92196200Sscottl printf(" Clear Seq #: %u\n", info.clear_seq_num); 93196200Sscottl printf("Shutdown Seq #: %u\n", info.shutdown_seq_num); 94196200Sscottl printf(" Boot Seq #: %u\n", info.boot_seq_num); 95196200Sscottl 96196200Sscottl close(fd); 97196200Sscottl 98196200Sscottl return (0); 99196200Sscottl} 100196200SscottlMFI_COMMAND(show, logstate, show_logstate); 101196200Sscottl 102196200Sscottlstatic int 103196200Sscottlparse_seq(struct mfi_evt_log_state *info, char *arg, uint32_t *seq) 104196200Sscottl{ 105196200Sscottl char *cp; 106196200Sscottl long val; 107196200Sscottl 108196200Sscottl if (strcasecmp(arg, "newest") == 0) { 109196200Sscottl *seq = info->newest_seq_num; 110196200Sscottl return (0); 111196200Sscottl } 112196200Sscottl if (strcasecmp(arg, "oldest") == 0) { 113196200Sscottl *seq = info->oldest_seq_num; 114196200Sscottl return (0); 115196200Sscottl } 116196200Sscottl if (strcasecmp(arg, "clear") == 0) { 117196200Sscottl *seq = info->clear_seq_num; 118196200Sscottl return (0); 119196200Sscottl } 120196200Sscottl if (strcasecmp(arg, "shutdown") == 0) { 121196200Sscottl *seq = info->shutdown_seq_num; 122196200Sscottl return (0); 123196200Sscottl } 124196200Sscottl if (strcasecmp(arg, "boot") == 0) { 125196200Sscottl *seq = info->boot_seq_num; 126196200Sscottl return (0); 127196200Sscottl } 128196200Sscottl val = strtol(arg, &cp, 0); 129196200Sscottl if (*cp != '\0' || val < 0) { 130196200Sscottl errno = EINVAL; 131196200Sscottl return (-1); 132196200Sscottl } 133196200Sscottl *seq = val; 134196200Sscottl return (0); 135196200Sscottl} 136196200Sscottl 137196200Sscottlstatic int 138196200Sscottlparse_locale(char *arg, uint16_t *locale) 139196200Sscottl{ 140196200Sscottl char *cp; 141196200Sscottl long val; 142196200Sscottl 143196200Sscottl if (strncasecmp(arg, "vol", 3) == 0 || strcasecmp(arg, "ld") == 0) { 144196200Sscottl *locale = MFI_EVT_LOCALE_LD; 145196200Sscottl return (0); 146196200Sscottl } 147196200Sscottl if (strncasecmp(arg, "drive", 5) == 0 || strcasecmp(arg, "pd") == 0) { 148196200Sscottl *locale = MFI_EVT_LOCALE_PD; 149196200Sscottl return (0); 150196200Sscottl } 151196200Sscottl if (strncasecmp(arg, "encl", 4) == 0) { 152196200Sscottl *locale = MFI_EVT_LOCALE_ENCL; 153196200Sscottl return (0); 154196200Sscottl } 155196200Sscottl if (strncasecmp(arg, "batt", 4) == 0 || 156196200Sscottl strncasecmp(arg, "bbu", 3) == 0) { 157196200Sscottl *locale = MFI_EVT_LOCALE_BBU; 158196200Sscottl return (0); 159196200Sscottl } 160196200Sscottl if (strcasecmp(arg, "sas") == 0) { 161196200Sscottl *locale = MFI_EVT_LOCALE_SAS; 162196200Sscottl return (0); 163196200Sscottl } 164196200Sscottl if (strcasecmp(arg, "ctrl") == 0 || strncasecmp(arg, "cont", 4) == 0) { 165196200Sscottl *locale = MFI_EVT_LOCALE_CTRL; 166196200Sscottl return (0); 167196200Sscottl } 168196200Sscottl if (strcasecmp(arg, "config") == 0) { 169196200Sscottl *locale = MFI_EVT_LOCALE_CONFIG; 170196200Sscottl return (0); 171196200Sscottl } 172196200Sscottl if (strcasecmp(arg, "cluster") == 0) { 173196200Sscottl *locale = MFI_EVT_LOCALE_CLUSTER; 174196200Sscottl return (0); 175196200Sscottl } 176196200Sscottl if (strcasecmp(arg, "all") == 0) { 177196200Sscottl *locale = MFI_EVT_LOCALE_ALL; 178196200Sscottl return (0); 179196200Sscottl } 180196200Sscottl val = strtol(arg, &cp, 0); 181196200Sscottl if (*cp != '\0' || val < 0 || val > 0xffff) { 182196200Sscottl errno = EINVAL; 183196200Sscottl return (-1); 184196200Sscottl } 185196200Sscottl *locale = val; 186196200Sscottl return (0); 187196200Sscottl} 188196200Sscottl 189196200Sscottlstatic int 190196200Sscottlparse_class(char *arg, int8_t *class) 191196200Sscottl{ 192196200Sscottl char *cp; 193196200Sscottl long val; 194196200Sscottl 195196200Sscottl if (strcasecmp(arg, "debug") == 0) { 196196200Sscottl *class = MFI_EVT_CLASS_DEBUG; 197196200Sscottl return (0); 198196200Sscottl } 199196200Sscottl if (strncasecmp(arg, "prog", 4) == 0) { 200196200Sscottl *class = MFI_EVT_CLASS_PROGRESS; 201196200Sscottl return (0); 202196200Sscottl } 203196200Sscottl if (strncasecmp(arg, "info", 4) == 0) { 204196200Sscottl *class = MFI_EVT_CLASS_INFO; 205196200Sscottl return (0); 206196200Sscottl } 207196200Sscottl if (strncasecmp(arg, "warn", 4) == 0) { 208196200Sscottl *class = MFI_EVT_CLASS_WARNING; 209196200Sscottl return (0); 210196200Sscottl } 211196200Sscottl if (strncasecmp(arg, "crit", 4) == 0) { 212196200Sscottl *class = MFI_EVT_CLASS_CRITICAL; 213196200Sscottl return (0); 214196200Sscottl } 215196200Sscottl if (strcasecmp(arg, "fatal") == 0) { 216196200Sscottl *class = MFI_EVT_CLASS_FATAL; 217196200Sscottl return (0); 218196200Sscottl } 219196200Sscottl if (strcasecmp(arg, "dead") == 0) { 220196200Sscottl *class = MFI_EVT_CLASS_DEAD; 221196200Sscottl return (0); 222196200Sscottl } 223196200Sscottl val = strtol(arg, &cp, 0); 224196200Sscottl if (*cp != '\0' || val < -128 || val > 127) { 225196200Sscottl errno = EINVAL; 226196200Sscottl return (-1); 227196200Sscottl } 228196200Sscottl *class = val; 229196200Sscottl return (0); 230196200Sscottl} 231196200Sscottl 232196200Sscottl/* 233196200Sscottl * The timestamp is the number of seconds since 00:00 Jan 1, 2000. If 234196200Sscottl * the bits in 24-31 are all set, then it is the number of seconds since 235196200Sscottl * boot. 236196200Sscottl */ 237196200Sscottlstatic const char * 238196200Sscottlformat_timestamp(uint32_t timestamp) 239196200Sscottl{ 240196200Sscottl static char buffer[32]; 241196200Sscottl static time_t base; 242196200Sscottl time_t t; 243196200Sscottl struct tm tm; 244196200Sscottl 245196200Sscottl if ((timestamp & 0xff000000) == 0xff000000) { 246196200Sscottl snprintf(buffer, sizeof(buffer), "boot + %us", timestamp & 247196200Sscottl 0x00ffffff); 248196200Sscottl return (buffer); 249196200Sscottl } 250196200Sscottl 251196200Sscottl if (base == 0) { 252196200Sscottl /* Compute 00:00 Jan 1, 2000 offset. */ 253196200Sscottl bzero(&tm, sizeof(tm)); 254196200Sscottl tm.tm_mday = 1; 255196200Sscottl tm.tm_year = (2000 - 1900); 256196200Sscottl base = mktime(&tm); 257196200Sscottl } 258196200Sscottl if (base == -1) { 259196200Sscottl snprintf(buffer, sizeof(buffer), "%us", timestamp); 260196200Sscottl return (buffer); 261196200Sscottl } 262196200Sscottl t = base + timestamp; 263196200Sscottl strftime(buffer, sizeof(buffer), "%+", localtime(&t)); 264196200Sscottl return (buffer); 265196200Sscottl} 266196200Sscottl 267196200Sscottlstatic const char * 268196200Sscottlformat_locale(uint16_t locale) 269196200Sscottl{ 270196200Sscottl static char buffer[8]; 271196200Sscottl 272196200Sscottl switch (locale) { 273196200Sscottl case MFI_EVT_LOCALE_LD: 274196200Sscottl return ("VOLUME"); 275196200Sscottl case MFI_EVT_LOCALE_PD: 276196200Sscottl return ("DRIVE"); 277196200Sscottl case MFI_EVT_LOCALE_ENCL: 278196200Sscottl return ("ENCL"); 279196200Sscottl case MFI_EVT_LOCALE_BBU: 280196200Sscottl return ("BATTERY"); 281196200Sscottl case MFI_EVT_LOCALE_SAS: 282196200Sscottl return ("SAS"); 283196200Sscottl case MFI_EVT_LOCALE_CTRL: 284196200Sscottl return ("CTRL"); 285196200Sscottl case MFI_EVT_LOCALE_CONFIG: 286196200Sscottl return ("CONFIG"); 287196200Sscottl case MFI_EVT_LOCALE_CLUSTER: 288196200Sscottl return ("CLUSTER"); 289196200Sscottl case MFI_EVT_LOCALE_ALL: 290196200Sscottl return ("ALL"); 291196200Sscottl default: 292196200Sscottl snprintf(buffer, sizeof(buffer), "0x%04x", locale); 293196200Sscottl return (buffer); 294196200Sscottl } 295196200Sscottl} 296196200Sscottl 297196200Sscottlstatic const char * 298196200Sscottlformat_class(int8_t class) 299196200Sscottl{ 300196200Sscottl static char buffer[6]; 301196200Sscottl 302196200Sscottl switch (class) { 303196200Sscottl case MFI_EVT_CLASS_DEBUG: 304196200Sscottl return ("debug"); 305196200Sscottl case MFI_EVT_CLASS_PROGRESS: 306196200Sscottl return ("progress"); 307196200Sscottl case MFI_EVT_CLASS_INFO: 308196200Sscottl return ("info"); 309196200Sscottl case MFI_EVT_CLASS_WARNING: 310196200Sscottl return ("WARN"); 311196200Sscottl case MFI_EVT_CLASS_CRITICAL: 312196200Sscottl return ("CRIT"); 313196200Sscottl case MFI_EVT_CLASS_FATAL: 314196200Sscottl return ("FATAL"); 315196200Sscottl case MFI_EVT_CLASS_DEAD: 316196200Sscottl return ("DEAD"); 317196200Sscottl default: 318196200Sscottl snprintf(buffer, sizeof(buffer), "%d", class); 319196200Sscottl return (buffer); 320196200Sscottl } 321196200Sscottl} 322196200Sscottl 323196200Sscottl/* Simulates %D from kernel printf(9). */ 324196200Sscottlstatic void 325196200Sscottlsimple_hex(void *ptr, size_t length, const char *separator) 326196200Sscottl{ 327196200Sscottl unsigned char *cp; 328196200Sscottl u_int i; 329196200Sscottl 330196200Sscottl if (length == 0) 331196200Sscottl return; 332196200Sscottl cp = ptr; 333196200Sscottl printf("%02x", cp[0]); 334196200Sscottl for (i = 1; i < length; i++) 335196200Sscottl printf("%s%02x", separator, cp[i]); 336196200Sscottl} 337196200Sscottl 338196200Sscottlstatic const char * 339196200Sscottlpdrive_location(struct mfi_evt_pd *pd) 340196200Sscottl{ 341196200Sscottl static char buffer[16]; 342196200Sscottl 343196200Sscottl if (pd->enclosure_index == 0) 344196200Sscottl snprintf(buffer, sizeof(buffer), "%02d(s%d)", pd->device_id, 345196200Sscottl pd->slot_number); 346196200Sscottl else 347196200Sscottl snprintf(buffer, sizeof(buffer), "%02d(e%d/s%d)", pd->device_id, 348196200Sscottl pd->enclosure_index, pd->slot_number); 349196200Sscottl return (buffer); 350196200Sscottl} 351196200Sscottl 352196200Sscottlstatic const char * 353196200Sscottlvolume_name(int fd, struct mfi_evt_ld *ld) 354196200Sscottl{ 355196200Sscottl 356196200Sscottl return (mfi_volume_name(fd, ld->target_id)); 357196200Sscottl} 358196200Sscottl 359196200Sscottl/* Ripped from sys/dev/mfi/mfi.c. */ 360196200Sscottlstatic void 361196200Sscottlmfi_decode_evt(int fd, struct mfi_evt_detail *detail, int verbose) 362196200Sscottl{ 363196200Sscottl 364196200Sscottl printf("%5d (%s/%s/%s) - ", detail->seq, format_timestamp(detail->time), 365196200Sscottl format_locale(detail->class.members.locale), 366196200Sscottl format_class(detail->class.members.class)); 367196200Sscottl switch (detail->arg_type) { 368196200Sscottl case MR_EVT_ARGS_NONE: 369196200Sscottl break; 370196200Sscottl case MR_EVT_ARGS_CDB_SENSE: 371196200Sscottl if (verbose) { 372196200Sscottl printf("PD %s CDB ", 373196200Sscottl pdrive_location(&detail->args.cdb_sense.pd) 374196200Sscottl ); 375196200Sscottl simple_hex(detail->args.cdb_sense.cdb, 376196200Sscottl detail->args.cdb_sense.cdb_len, ":"); 377196200Sscottl printf(" Sense "); 378196200Sscottl simple_hex(detail->args.cdb_sense.sense, 379196200Sscottl detail->args.cdb_sense.sense_len, ":"); 380196200Sscottl printf(":\n "); 381196200Sscottl } 382196200Sscottl break; 383196200Sscottl case MR_EVT_ARGS_LD: 384196200Sscottl printf("VOL %s event: ", volume_name(fd, &detail->args.ld)); 385196200Sscottl break; 386196200Sscottl case MR_EVT_ARGS_LD_COUNT: 387196200Sscottl printf("VOL %s", volume_name(fd, &detail->args.ld_count.ld)); 388196200Sscottl if (verbose) { 389196200Sscottl printf(" count %lld: ", 390196200Sscottl (long long)detail->args.ld_count.count); 391196200Sscottl } 392196200Sscottl printf(": "); 393196200Sscottl break; 394196200Sscottl case MR_EVT_ARGS_LD_LBA: 395196200Sscottl printf("VOL %s", volume_name(fd, &detail->args.ld_count.ld)); 396196200Sscottl if (verbose) { 397196200Sscottl printf(" lba %lld", 398196200Sscottl (long long)detail->args.ld_lba.lba); 399196200Sscottl } 400196200Sscottl printf(": "); 401196200Sscottl break; 402196200Sscottl case MR_EVT_ARGS_LD_OWNER: 403196200Sscottl printf("VOL %s", volume_name(fd, &detail->args.ld_count.ld)); 404196200Sscottl if (verbose) { 405196200Sscottl printf(" owner changed: prior %d, new %d", 406196200Sscottl detail->args.ld_owner.pre_owner, 407196200Sscottl detail->args.ld_owner.new_owner); 408196200Sscottl } 409196200Sscottl printf(": "); 410196200Sscottl break; 411196200Sscottl case MR_EVT_ARGS_LD_LBA_PD_LBA: 412196200Sscottl printf("VOL %s", volume_name(fd, &detail->args.ld_count.ld)); 413196200Sscottl if (verbose) { 414196200Sscottl printf(" lba %lld, physical drive PD %s lba %lld", 415196200Sscottl (long long)detail->args.ld_lba_pd_lba.ld_lba, 416196200Sscottl pdrive_location(&detail->args.ld_lba_pd_lba.pd), 417196200Sscottl (long long)detail->args.ld_lba_pd_lba.pd_lba); 418196200Sscottl } 419196200Sscottl printf(": "); 420196200Sscottl break; 421196200Sscottl case MR_EVT_ARGS_LD_PROG: 422196200Sscottl printf("VOL %s", volume_name(fd, &detail->args.ld_prog.ld)); 423196200Sscottl if (verbose) { 424196200Sscottl printf(" progress %d%% in %ds", 425196200Sscottl detail->args.ld_prog.prog.progress/655, 426196200Sscottl detail->args.ld_prog.prog.elapsed_seconds); 427196200Sscottl } 428196200Sscottl printf(": "); 429196200Sscottl break; 430196200Sscottl case MR_EVT_ARGS_LD_STATE: 431196200Sscottl printf("VOL %s", volume_name(fd, &detail->args.ld_prog.ld)); 432196200Sscottl if (verbose) { 433196200Sscottl printf(" state prior %s new %s", 434196200Sscottl mfi_ldstate(detail->args.ld_state.prev_state), 435196200Sscottl mfi_ldstate(detail->args.ld_state.new_state)); 436196200Sscottl } 437196200Sscottl printf(": "); 438196200Sscottl break; 439196200Sscottl case MR_EVT_ARGS_LD_STRIP: 440196200Sscottl printf("VOL %s", volume_name(fd, &detail->args.ld_prog.ld)); 441196200Sscottl if (verbose) { 442196200Sscottl printf(" strip %lld", 443196200Sscottl (long long)detail->args.ld_strip.strip); 444196200Sscottl } 445196200Sscottl printf(": "); 446196200Sscottl break; 447196200Sscottl case MR_EVT_ARGS_PD: 448196200Sscottl if (verbose) { 449196200Sscottl printf("PD %s event: ", 450196200Sscottl pdrive_location(&detail->args.pd)); 451196200Sscottl } 452196200Sscottl break; 453196200Sscottl case MR_EVT_ARGS_PD_ERR: 454196200Sscottl if (verbose) { 455196200Sscottl printf("PD %s err %d: ", 456196200Sscottl pdrive_location(&detail->args.pd_err.pd), 457196200Sscottl detail->args.pd_err.err); 458196200Sscottl } 459196200Sscottl break; 460196200Sscottl case MR_EVT_ARGS_PD_LBA: 461196200Sscottl if (verbose) { 462196200Sscottl printf("PD %s lba %lld: ", 463196200Sscottl pdrive_location(&detail->args.pd_lba.pd), 464196200Sscottl (long long)detail->args.pd_lba.lba); 465196200Sscottl } 466196200Sscottl break; 467196200Sscottl case MR_EVT_ARGS_PD_LBA_LD: 468196200Sscottl if (verbose) { 469196200Sscottl printf("PD %s lba %lld VOL %s: ", 470196200Sscottl pdrive_location(&detail->args.pd_lba_ld.pd), 471196200Sscottl (long long)detail->args.pd_lba.lba, 472196200Sscottl volume_name(fd, &detail->args.pd_lba_ld.ld)); 473196200Sscottl } 474196200Sscottl break; 475196200Sscottl case MR_EVT_ARGS_PD_PROG: 476196200Sscottl if (verbose) { 477196200Sscottl printf("PD %s progress %d%% seconds %ds: ", 478196200Sscottl pdrive_location(&detail->args.pd_prog.pd), 479196200Sscottl detail->args.pd_prog.prog.progress/655, 480196200Sscottl detail->args.pd_prog.prog.elapsed_seconds); 481196200Sscottl } 482196200Sscottl break; 483196200Sscottl case MR_EVT_ARGS_PD_STATE: 484196200Sscottl if (verbose) { 485196200Sscottl printf("PD %s state prior %s new %s: ", 486196200Sscottl pdrive_location(&detail->args.pd_prog.pd), 487196200Sscottl mfi_pdstate(detail->args.pd_state.prev_state), 488196200Sscottl mfi_pdstate(detail->args.pd_state.new_state)); 489196200Sscottl } 490196200Sscottl break; 491196200Sscottl case MR_EVT_ARGS_PCI: 492196200Sscottl if (verbose) { 493196200Sscottl printf("PCI 0x%04x 0x%04x 0x%04x 0x%04x: ", 494196200Sscottl detail->args.pci.venderId, 495196200Sscottl detail->args.pci.deviceId, 496196200Sscottl detail->args.pci.subVenderId, 497196200Sscottl detail->args.pci.subDeviceId); 498196200Sscottl } 499196200Sscottl break; 500196200Sscottl case MR_EVT_ARGS_RATE: 501196200Sscottl if (verbose) { 502196200Sscottl printf("Rebuild rate %d: ", detail->args.rate); 503196200Sscottl } 504196200Sscottl break; 505196200Sscottl case MR_EVT_ARGS_TIME: 506196200Sscottl if (verbose) { 507196200Sscottl printf("Adapter time %s; %d seconds since power on: ", 508196200Sscottl format_timestamp(detail->args.time.rtc), 509196200Sscottl detail->args.time.elapsedSeconds); 510196200Sscottl } 511196200Sscottl break; 512196200Sscottl case MR_EVT_ARGS_ECC: 513196200Sscottl if (verbose) { 514196200Sscottl printf("Adapter ECC %x,%x: %s: ", 515196200Sscottl detail->args.ecc.ecar, 516196200Sscottl detail->args.ecc.elog, 517196200Sscottl detail->args.ecc.str); 518196200Sscottl } 519196200Sscottl break; 520196200Sscottl default: 521196200Sscottl if (verbose) { 522196200Sscottl printf("Type %d: ", detail->arg_type); 523196200Sscottl } 524196200Sscottl break; 525196200Sscottl } 526196200Sscottl printf("%s\n", detail->description); 527196200Sscottl} 528196200Sscottl 529196200Sscottlstatic int 530196200Sscottlshow_events(int ac, char **av) 531196200Sscottl{ 532196200Sscottl struct mfi_evt_log_state info; 533196200Sscottl struct mfi_evt_list *list; 534196200Sscottl union mfi_evt filter; 535196200Sscottl long val; 536196200Sscottl char *cp; 537196200Sscottl ssize_t size; 538196200Sscottl uint32_t seq, start, stop; 539196200Sscottl uint8_t status; 540214396Sjhb int ch, error, fd, num_events, verbose; 541196200Sscottl u_int i; 542196200Sscottl 543196200Sscottl fd = mfi_open(mfi_unit); 544196200Sscottl if (fd < 0) { 545214396Sjhb error = errno; 546196200Sscottl warn("mfi_open"); 547214396Sjhb return (error); 548196200Sscottl } 549196200Sscottl 550196200Sscottl if (mfi_event_get_info(fd, &info, NULL) < 0) { 551214396Sjhb error = errno; 552196200Sscottl warn("Failed to get event log info"); 553214396Sjhb return (error); 554196200Sscottl } 555196200Sscottl 556196200Sscottl /* Default settings. */ 557196200Sscottl num_events = 15; 558196200Sscottl filter.members.reserved = 0; 559196200Sscottl filter.members.locale = MFI_EVT_LOCALE_ALL; 560196200Sscottl filter.members.class = MFI_EVT_CLASS_WARNING; 561196200Sscottl start = info.boot_seq_num; 562196200Sscottl stop = info.newest_seq_num; 563196200Sscottl verbose = 0; 564196200Sscottl 565196200Sscottl /* Parse any options. */ 566196200Sscottl optind = 1; 567196200Sscottl while ((ch = getopt(ac, av, "c:l:n:v")) != -1) { 568196200Sscottl switch (ch) { 569196200Sscottl case 'c': 570196200Sscottl if (parse_class(optarg, &filter.members.class) < 0) { 571214396Sjhb error = errno; 572196200Sscottl warn("Error parsing event class"); 573214396Sjhb return (error); 574196200Sscottl } 575196200Sscottl break; 576196200Sscottl case 'l': 577196200Sscottl if (parse_locale(optarg, &filter.members.locale) < 0) { 578214396Sjhb error = errno; 579196200Sscottl warn("Error parsing event locale"); 580214396Sjhb return (error); 581196200Sscottl } 582196200Sscottl break; 583196200Sscottl case 'n': 584196200Sscottl val = strtol(optarg, &cp, 0); 585196200Sscottl if (*cp != '\0' || val <= 0) { 586196200Sscottl warnx("Invalid event count"); 587196200Sscottl return (EINVAL); 588196200Sscottl } 589196200Sscottl num_events = val; 590196200Sscottl break; 591196200Sscottl case 'v': 592196200Sscottl verbose = 1; 593196200Sscottl break; 594196200Sscottl case '?': 595196200Sscottl default: 596196200Sscottl return (EINVAL); 597196200Sscottl } 598196200Sscottl } 599196200Sscottl ac -= optind; 600196200Sscottl av += optind; 601196200Sscottl 602196200Sscottl /* Determine buffer size and validate it. */ 603196200Sscottl size = sizeof(struct mfi_evt_list) + sizeof(struct mfi_evt_detail) * 604196200Sscottl (num_events - 1); 605196200Sscottl if (size > getpagesize()) { 606196200Sscottl warnx("Event count is too high"); 607196200Sscottl return (EINVAL); 608196200Sscottl } 609196200Sscottl 610196200Sscottl /* Handle optional start and stop sequence numbers. */ 611196200Sscottl if (ac > 2) { 612196200Sscottl warnx("show events: extra arguments"); 613196200Sscottl return (EINVAL); 614196200Sscottl } 615196200Sscottl if (ac > 0 && parse_seq(&info, av[0], &start) < 0) { 616214396Sjhb error = errno; 617196200Sscottl warn("Error parsing starting sequence number"); 618214396Sjhb return (error); 619196200Sscottl } 620196200Sscottl if (ac > 1 && parse_seq(&info, av[1], &stop) < 0) { 621214396Sjhb error = errno; 622196200Sscottl warn("Error parsing ending sequence number"); 623214396Sjhb return (error); 624196200Sscottl } 625196200Sscottl 626196200Sscottl list = malloc(size); 627215526Sjhb if (list == NULL) { 628215526Sjhb warnx("malloc failed"); 629215526Sjhb return (ENOMEM); 630215526Sjhb } 631196200Sscottl for (seq = start;;) { 632196200Sscottl if (mfi_get_events(fd, list, num_events, filter, seq, 633196200Sscottl &status) < 0) { 634214396Sjhb error = errno; 635196200Sscottl warn("Failed to fetch events"); 636214396Sjhb return (error); 637196200Sscottl } 638196200Sscottl if (status == MFI_STAT_NOT_FOUND) { 639196200Sscottl if (seq == start) 640196200Sscottl warnx("No matching events found"); 641196200Sscottl break; 642196200Sscottl } 643196200Sscottl if (status != MFI_STAT_OK) { 644196200Sscottl warnx("Error fetching events: %s", mfi_status(status)); 645196200Sscottl return (EIO); 646196200Sscottl } 647196200Sscottl 648196200Sscottl for (i = 0; i < list->count; i++) { 649196200Sscottl /* 650196200Sscottl * If this event is newer than 'stop_seq' then 651196200Sscottl * break out of the loop. Note that the log 652196200Sscottl * is a circular buffer so we have to handle 653196200Sscottl * the case that our stop point is earlier in 654196200Sscottl * the buffer than our start point. 655196200Sscottl */ 656196200Sscottl if (list->event[i].seq >= stop) { 657196200Sscottl if (start <= stop) 658196200Sscottl break; 659196200Sscottl else if (list->event[i].seq < start) 660196200Sscottl break; 661196200Sscottl } 662196200Sscottl mfi_decode_evt(fd, &list->event[i], verbose); 663196200Sscottl } 664196200Sscottl 665196200Sscottl /* 666196200Sscottl * XXX: If the event's seq # is the end of the buffer 667196200Sscottl * then this probably won't do the right thing. We 668196200Sscottl * need to know the size of the buffer somehow. 669196200Sscottl */ 670196200Sscottl seq = list->event[list->count - 1].seq + 1; 671196200Sscottl 672196200Sscottl } 673196200Sscottl 674196200Sscottl free(list); 675196200Sscottl close(fd); 676196200Sscottl 677196200Sscottl return (0); 678196200Sscottl} 679196200SscottlMFI_COMMAND(show, events, show_events); 680