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