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