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