36#include <stdio.h> 37#include <stdlib.h> 38#include <strings.h> 39#include <time.h> 40#include <unistd.h> 41#include "mfiutil.h" 42 43static int 44mfi_event_get_info(int fd, struct mfi_evt_log_state *info, uint8_t *statusp) 45{ 46 47 return (mfi_dcmd_command(fd, MFI_DCMD_CTRL_EVENT_GETINFO, info, 48 sizeof(struct mfi_evt_log_state), NULL, 0, statusp)); 49} 50 51static int 52mfi_get_events(int fd, struct mfi_evt_list *list, int num_events, 53 union mfi_evt filter, uint32_t start_seq, uint8_t *statusp) 54{ 55 uint32_t mbox[2]; 56 size_t size; 57 58 mbox[0] = start_seq; 59 mbox[1] = filter.word; 60 size = sizeof(struct mfi_evt_list) + sizeof(struct mfi_evt_detail) * 61 (num_events - 1); 62 return (mfi_dcmd_command(fd, MFI_DCMD_CTRL_EVENT_GET, list, size, 63 (uint8_t *)&mbox, sizeof(mbox), statusp)); 64} 65 66static int 67show_logstate(int ac, char **av __unused) 68{ 69 struct mfi_evt_log_state info; 70 int error, fd; 71 72 if (ac != 1) { 73 warnx("show logstate: extra arguments"); 74 return (EINVAL); 75 } 76 77 fd = mfi_open(mfi_unit, O_RDWR); 78 if (fd < 0) { 79 error = errno; 80 warn("mfi_open"); 81 return (error); 82 } 83 84 if (mfi_event_get_info(fd, &info, NULL) < 0) { 85 error = errno; 86 warn("Failed to get event log info"); 87 close(fd); 88 return (error); 89 } 90 91 printf("mfi%d Event Log Sequence Numbers:\n", mfi_unit); 92 printf(" Newest Seq #: %u\n", info.newest_seq_num); 93 printf(" Oldest Seq #: %u\n", info.oldest_seq_num); 94 printf(" Clear Seq #: %u\n", info.clear_seq_num); 95 printf("Shutdown Seq #: %u\n", info.shutdown_seq_num); 96 printf(" Boot Seq #: %u\n", info.boot_seq_num); 97 98 close(fd); 99 100 return (0); 101} 102MFI_COMMAND(show, logstate, show_logstate); 103 104static int 105parse_seq(struct mfi_evt_log_state *info, char *arg, uint32_t *seq) 106{ 107 char *cp; 108 long val; 109 110 if (strcasecmp(arg, "newest") == 0) { 111 *seq = info->newest_seq_num; 112 return (0); 113 } 114 if (strcasecmp(arg, "oldest") == 0) { 115 *seq = info->oldest_seq_num; 116 return (0); 117 } 118 if (strcasecmp(arg, "clear") == 0) { 119 *seq = info->clear_seq_num; 120 return (0); 121 } 122 if (strcasecmp(arg, "shutdown") == 0) { 123 *seq = info->shutdown_seq_num; 124 return (0); 125 } 126 if (strcasecmp(arg, "boot") == 0) { 127 *seq = info->boot_seq_num; 128 return (0); 129 } 130 val = strtol(arg, &cp, 0); 131 if (*cp != '\0' || val < 0) { 132 errno = EINVAL; 133 return (-1); 134 } 135 *seq = val; 136 return (0); 137} 138 139static int 140parse_locale(char *arg, uint16_t *locale) 141{ 142 char *cp; 143 long val; 144 145 if (strncasecmp(arg, "vol", 3) == 0 || strcasecmp(arg, "ld") == 0) { 146 *locale = MFI_EVT_LOCALE_LD; 147 return (0); 148 } 149 if (strncasecmp(arg, "drive", 5) == 0 || strcasecmp(arg, "pd") == 0) { 150 *locale = MFI_EVT_LOCALE_PD; 151 return (0); 152 } 153 if (strncasecmp(arg, "encl", 4) == 0) { 154 *locale = MFI_EVT_LOCALE_ENCL; 155 return (0); 156 } 157 if (strncasecmp(arg, "batt", 4) == 0 || 158 strncasecmp(arg, "bbu", 3) == 0) { 159 *locale = MFI_EVT_LOCALE_BBU; 160 return (0); 161 } 162 if (strcasecmp(arg, "sas") == 0) { 163 *locale = MFI_EVT_LOCALE_SAS; 164 return (0); 165 } 166 if (strcasecmp(arg, "ctrl") == 0 || strncasecmp(arg, "cont", 4) == 0) { 167 *locale = MFI_EVT_LOCALE_CTRL; 168 return (0); 169 } 170 if (strcasecmp(arg, "config") == 0) { 171 *locale = MFI_EVT_LOCALE_CONFIG; 172 return (0); 173 } 174 if (strcasecmp(arg, "cluster") == 0) { 175 *locale = MFI_EVT_LOCALE_CLUSTER; 176 return (0); 177 } 178 if (strcasecmp(arg, "all") == 0) { 179 *locale = MFI_EVT_LOCALE_ALL; 180 return (0); 181 } 182 val = strtol(arg, &cp, 0); 183 if (*cp != '\0' || val < 0 || val > 0xffff) { 184 errno = EINVAL; 185 return (-1); 186 } 187 *locale = val; 188 return (0); 189} 190 191static int 192parse_class(char *arg, int8_t *class) 193{ 194 char *cp; 195 long val; 196 197 if (strcasecmp(arg, "debug") == 0) { 198 *class = MFI_EVT_CLASS_DEBUG; 199 return (0); 200 } 201 if (strncasecmp(arg, "prog", 4) == 0) { 202 *class = MFI_EVT_CLASS_PROGRESS; 203 return (0); 204 } 205 if (strncasecmp(arg, "info", 4) == 0) { 206 *class = MFI_EVT_CLASS_INFO; 207 return (0); 208 } 209 if (strncasecmp(arg, "warn", 4) == 0) { 210 *class = MFI_EVT_CLASS_WARNING; 211 return (0); 212 } 213 if (strncasecmp(arg, "crit", 4) == 0) { 214 *class = MFI_EVT_CLASS_CRITICAL; 215 return (0); 216 } 217 if (strcasecmp(arg, "fatal") == 0) { 218 *class = MFI_EVT_CLASS_FATAL; 219 return (0); 220 } 221 if (strcasecmp(arg, "dead") == 0) { 222 *class = MFI_EVT_CLASS_DEAD; 223 return (0); 224 } 225 val = strtol(arg, &cp, 0); 226 if (*cp != '\0' || val < -128 || val > 127) { 227 errno = EINVAL; 228 return (-1); 229 } 230 *class = val; 231 return (0); 232} 233 234/* 235 * The timestamp is the number of seconds since 00:00 Jan 1, 2000. If 236 * the bits in 24-31 are all set, then it is the number of seconds since 237 * boot. 238 */ 239static const char * 240format_timestamp(uint32_t timestamp) 241{ 242 static char buffer[32]; 243 static time_t base; 244 time_t t; 245 struct tm tm; 246 247 if ((timestamp & 0xff000000) == 0xff000000) { 248 snprintf(buffer, sizeof(buffer), "boot + %us", timestamp & 249 0x00ffffff); 250 return (buffer); 251 } 252 253 if (base == 0) { 254 /* Compute 00:00 Jan 1, 2000 offset. */ 255 bzero(&tm, sizeof(tm)); 256 tm.tm_mday = 1; 257 tm.tm_year = (2000 - 1900); 258 base = mktime(&tm); 259 } 260 if (base == -1) { 261 snprintf(buffer, sizeof(buffer), "%us", timestamp); 262 return (buffer); 263 } 264 t = base + timestamp; 265 strftime(buffer, sizeof(buffer), "%+", localtime(&t)); 266 return (buffer); 267} 268 269static const char * 270format_locale(uint16_t locale) 271{ 272 static char buffer[8]; 273 274 switch (locale) { 275 case MFI_EVT_LOCALE_LD: 276 return ("VOLUME"); 277 case MFI_EVT_LOCALE_PD: 278 return ("DRIVE"); 279 case MFI_EVT_LOCALE_ENCL: 280 return ("ENCL"); 281 case MFI_EVT_LOCALE_BBU: 282 return ("BATTERY"); 283 case MFI_EVT_LOCALE_SAS: 284 return ("SAS"); 285 case MFI_EVT_LOCALE_CTRL: 286 return ("CTRL"); 287 case MFI_EVT_LOCALE_CONFIG: 288 return ("CONFIG"); 289 case MFI_EVT_LOCALE_CLUSTER: 290 return ("CLUSTER"); 291 case MFI_EVT_LOCALE_ALL: 292 return ("ALL"); 293 default: 294 snprintf(buffer, sizeof(buffer), "0x%04x", locale); 295 return (buffer); 296 } 297} 298 299static const char * 300format_class(int8_t class) 301{ 302 static char buffer[6]; 303 304 switch (class) { 305 case MFI_EVT_CLASS_DEBUG: 306 return ("debug"); 307 case MFI_EVT_CLASS_PROGRESS: 308 return ("progress"); 309 case MFI_EVT_CLASS_INFO: 310 return ("info"); 311 case MFI_EVT_CLASS_WARNING: 312 return ("WARN"); 313 case MFI_EVT_CLASS_CRITICAL: 314 return ("CRIT"); 315 case MFI_EVT_CLASS_FATAL: 316 return ("FATAL"); 317 case MFI_EVT_CLASS_DEAD: 318 return ("DEAD"); 319 default: 320 snprintf(buffer, sizeof(buffer), "%d", class); 321 return (buffer); 322 } 323} 324 325/* Simulates %D from kernel printf(9). */ 326static void 327simple_hex(void *ptr, size_t length, const char *separator) 328{ 329 unsigned char *cp; 330 u_int i; 331 332 if (length == 0) 333 return; 334 cp = ptr; 335 printf("%02x", cp[0]); 336 for (i = 1; i < length; i++) 337 printf("%s%02x", separator, cp[i]); 338} 339 340static const char * 341pdrive_location(struct mfi_evt_pd *pd) 342{ 343 static char buffer[16]; 344 345 if (pd->enclosure_index == 0) 346 snprintf(buffer, sizeof(buffer), "%02d(s%d)", pd->device_id, 347 pd->slot_number); 348 else 349 snprintf(buffer, sizeof(buffer), "%02d(e%d/s%d)", pd->device_id, 350 pd->enclosure_index, pd->slot_number); 351 return (buffer); 352} 353 354static const char * 355volume_name(int fd, struct mfi_evt_ld *ld) 356{ 357 358 return (mfi_volume_name(fd, ld->target_id)); 359} 360 361/* Ripped from sys/dev/mfi/mfi.c. */ 362static void 363mfi_decode_evt(int fd, struct mfi_evt_detail *detail, int verbose) 364{ 365 366 printf("%5d (%s/%s/%s) - ", detail->seq, format_timestamp(detail->time), 367 format_locale(detail->evt_class.members.locale), 368 format_class(detail->evt_class.members.evt_class)); 369 switch (detail->arg_type) { 370 case MR_EVT_ARGS_NONE: 371 break; 372 case MR_EVT_ARGS_CDB_SENSE: 373 if (verbose) { 374 printf("PD %s CDB ", 375 pdrive_location(&detail->args.cdb_sense.pd) 376 ); 377 simple_hex(detail->args.cdb_sense.cdb, 378 detail->args.cdb_sense.cdb_len, ":"); 379 printf(" Sense "); 380 simple_hex(detail->args.cdb_sense.sense, 381 detail->args.cdb_sense.sense_len, ":"); 382 printf(":\n "); 383 } 384 break; 385 case MR_EVT_ARGS_LD: 386 printf("VOL %s event: ", volume_name(fd, &detail->args.ld)); 387 break; 388 case MR_EVT_ARGS_LD_COUNT: 389 printf("VOL %s", volume_name(fd, &detail->args.ld_count.ld)); 390 if (verbose) { 391 printf(" count %lld: ", 392 (long long)detail->args.ld_count.count); 393 } 394 printf(": "); 395 break; 396 case MR_EVT_ARGS_LD_LBA: 397 printf("VOL %s", volume_name(fd, &detail->args.ld_count.ld)); 398 if (verbose) { 399 printf(" lba %lld", 400 (long long)detail->args.ld_lba.lba); 401 } 402 printf(": "); 403 break; 404 case MR_EVT_ARGS_LD_OWNER: 405 printf("VOL %s", volume_name(fd, &detail->args.ld_count.ld)); 406 if (verbose) { 407 printf(" owner changed: prior %d, new %d", 408 detail->args.ld_owner.pre_owner, 409 detail->args.ld_owner.new_owner); 410 } 411 printf(": "); 412 break; 413 case MR_EVT_ARGS_LD_LBA_PD_LBA: 414 printf("VOL %s", volume_name(fd, &detail->args.ld_count.ld)); 415 if (verbose) { 416 printf(" lba %lld, physical drive PD %s lba %lld", 417 (long long)detail->args.ld_lba_pd_lba.ld_lba, 418 pdrive_location(&detail->args.ld_lba_pd_lba.pd), 419 (long long)detail->args.ld_lba_pd_lba.pd_lba); 420 } 421 printf(": "); 422 break; 423 case MR_EVT_ARGS_LD_PROG: 424 printf("VOL %s", volume_name(fd, &detail->args.ld_prog.ld)); 425 if (verbose) { 426 printf(" progress %d%% in %ds", 427 detail->args.ld_prog.prog.progress/655, 428 detail->args.ld_prog.prog.elapsed_seconds); 429 } 430 printf(": "); 431 break; 432 case MR_EVT_ARGS_LD_STATE: 433 printf("VOL %s", volume_name(fd, &detail->args.ld_prog.ld)); 434 if (verbose) { 435 printf(" state prior %s new %s", 436 mfi_ldstate(detail->args.ld_state.prev_state), 437 mfi_ldstate(detail->args.ld_state.new_state)); 438 } 439 printf(": "); 440 break; 441 case MR_EVT_ARGS_LD_STRIP: 442 printf("VOL %s", volume_name(fd, &detail->args.ld_strip.ld)); 443 if (verbose) { 444 printf(" strip %lld", 445 (long long)detail->args.ld_strip.strip); 446 } 447 printf(": "); 448 break; 449 case MR_EVT_ARGS_PD: 450 if (verbose) { 451 printf("PD %s event: ", 452 pdrive_location(&detail->args.pd)); 453 } 454 break; 455 case MR_EVT_ARGS_PD_ERR: 456 if (verbose) { 457 printf("PD %s err %d: ", 458 pdrive_location(&detail->args.pd_err.pd), 459 detail->args.pd_err.err); 460 } 461 break; 462 case MR_EVT_ARGS_PD_LBA: 463 if (verbose) { 464 printf("PD %s lba %lld: ", 465 pdrive_location(&detail->args.pd_lba.pd), 466 (long long)detail->args.pd_lba.lba); 467 } 468 break; 469 case MR_EVT_ARGS_PD_LBA_LD: 470 if (verbose) { 471 printf("PD %s lba %lld VOL %s: ", 472 pdrive_location(&detail->args.pd_lba_ld.pd), 473 (long long)detail->args.pd_lba.lba, 474 volume_name(fd, &detail->args.pd_lba_ld.ld)); 475 } 476 break; 477 case MR_EVT_ARGS_PD_PROG: 478 if (verbose) { 479 printf("PD %s progress %d%% seconds %ds: ", 480 pdrive_location(&detail->args.pd_prog.pd), 481 detail->args.pd_prog.prog.progress/655, 482 detail->args.pd_prog.prog.elapsed_seconds); 483 } 484 break; 485 case MR_EVT_ARGS_PD_STATE: 486 if (verbose) { 487 printf("PD %s state prior %s new %s: ", 488 pdrive_location(&detail->args.pd_prog.pd), 489 mfi_pdstate(detail->args.pd_state.prev_state), 490 mfi_pdstate(detail->args.pd_state.new_state)); 491 } 492 break; 493 case MR_EVT_ARGS_PCI: 494 if (verbose) { 495 printf("PCI 0x%04x 0x%04x 0x%04x 0x%04x: ", 496 detail->args.pci.venderId, 497 detail->args.pci.deviceId, 498 detail->args.pci.subVenderId, 499 detail->args.pci.subDeviceId); 500 } 501 break; 502 case MR_EVT_ARGS_RATE: 503 if (verbose) { 504 printf("Rebuild rate %d: ", detail->args.rate); 505 } 506 break; 507 case MR_EVT_ARGS_TIME: 508 if (verbose) { 509 printf("Adapter time %s; %d seconds since power on: ", 510 format_timestamp(detail->args.time.rtc), 511 detail->args.time.elapsedSeconds); 512 } 513 break; 514 case MR_EVT_ARGS_ECC: 515 if (verbose) { 516 printf("Adapter ECC %x,%x: %s: ", 517 detail->args.ecc.ecar, 518 detail->args.ecc.elog, 519 detail->args.ecc.str); 520 } 521 break; 522 default: 523 if (verbose) { 524 printf("Type %d: ", detail->arg_type); 525 } 526 break; 527 } 528 printf("%s\n", detail->description); 529} 530 531static int 532show_events(int ac, char **av) 533{ 534 struct mfi_evt_log_state info; 535 struct mfi_evt_list *list; 536 union mfi_evt filter;
| 37#include <stdio.h> 38#include <stdlib.h> 39#include <strings.h> 40#include <time.h> 41#include <unistd.h> 42#include "mfiutil.h" 43 44static int 45mfi_event_get_info(int fd, struct mfi_evt_log_state *info, uint8_t *statusp) 46{ 47 48 return (mfi_dcmd_command(fd, MFI_DCMD_CTRL_EVENT_GETINFO, info, 49 sizeof(struct mfi_evt_log_state), NULL, 0, statusp)); 50} 51 52static int 53mfi_get_events(int fd, struct mfi_evt_list *list, int num_events, 54 union mfi_evt filter, uint32_t start_seq, uint8_t *statusp) 55{ 56 uint32_t mbox[2]; 57 size_t size; 58 59 mbox[0] = start_seq; 60 mbox[1] = filter.word; 61 size = sizeof(struct mfi_evt_list) + sizeof(struct mfi_evt_detail) * 62 (num_events - 1); 63 return (mfi_dcmd_command(fd, MFI_DCMD_CTRL_EVENT_GET, list, size, 64 (uint8_t *)&mbox, sizeof(mbox), statusp)); 65} 66 67static int 68show_logstate(int ac, char **av __unused) 69{ 70 struct mfi_evt_log_state info; 71 int error, fd; 72 73 if (ac != 1) { 74 warnx("show logstate: extra arguments"); 75 return (EINVAL); 76 } 77 78 fd = mfi_open(mfi_unit, O_RDWR); 79 if (fd < 0) { 80 error = errno; 81 warn("mfi_open"); 82 return (error); 83 } 84 85 if (mfi_event_get_info(fd, &info, NULL) < 0) { 86 error = errno; 87 warn("Failed to get event log info"); 88 close(fd); 89 return (error); 90 } 91 92 printf("mfi%d Event Log Sequence Numbers:\n", mfi_unit); 93 printf(" Newest Seq #: %u\n", info.newest_seq_num); 94 printf(" Oldest Seq #: %u\n", info.oldest_seq_num); 95 printf(" Clear Seq #: %u\n", info.clear_seq_num); 96 printf("Shutdown Seq #: %u\n", info.shutdown_seq_num); 97 printf(" Boot Seq #: %u\n", info.boot_seq_num); 98 99 close(fd); 100 101 return (0); 102} 103MFI_COMMAND(show, logstate, show_logstate); 104 105static int 106parse_seq(struct mfi_evt_log_state *info, char *arg, uint32_t *seq) 107{ 108 char *cp; 109 long val; 110 111 if (strcasecmp(arg, "newest") == 0) { 112 *seq = info->newest_seq_num; 113 return (0); 114 } 115 if (strcasecmp(arg, "oldest") == 0) { 116 *seq = info->oldest_seq_num; 117 return (0); 118 } 119 if (strcasecmp(arg, "clear") == 0) { 120 *seq = info->clear_seq_num; 121 return (0); 122 } 123 if (strcasecmp(arg, "shutdown") == 0) { 124 *seq = info->shutdown_seq_num; 125 return (0); 126 } 127 if (strcasecmp(arg, "boot") == 0) { 128 *seq = info->boot_seq_num; 129 return (0); 130 } 131 val = strtol(arg, &cp, 0); 132 if (*cp != '\0' || val < 0) { 133 errno = EINVAL; 134 return (-1); 135 } 136 *seq = val; 137 return (0); 138} 139 140static int 141parse_locale(char *arg, uint16_t *locale) 142{ 143 char *cp; 144 long val; 145 146 if (strncasecmp(arg, "vol", 3) == 0 || strcasecmp(arg, "ld") == 0) { 147 *locale = MFI_EVT_LOCALE_LD; 148 return (0); 149 } 150 if (strncasecmp(arg, "drive", 5) == 0 || strcasecmp(arg, "pd") == 0) { 151 *locale = MFI_EVT_LOCALE_PD; 152 return (0); 153 } 154 if (strncasecmp(arg, "encl", 4) == 0) { 155 *locale = MFI_EVT_LOCALE_ENCL; 156 return (0); 157 } 158 if (strncasecmp(arg, "batt", 4) == 0 || 159 strncasecmp(arg, "bbu", 3) == 0) { 160 *locale = MFI_EVT_LOCALE_BBU; 161 return (0); 162 } 163 if (strcasecmp(arg, "sas") == 0) { 164 *locale = MFI_EVT_LOCALE_SAS; 165 return (0); 166 } 167 if (strcasecmp(arg, "ctrl") == 0 || strncasecmp(arg, "cont", 4) == 0) { 168 *locale = MFI_EVT_LOCALE_CTRL; 169 return (0); 170 } 171 if (strcasecmp(arg, "config") == 0) { 172 *locale = MFI_EVT_LOCALE_CONFIG; 173 return (0); 174 } 175 if (strcasecmp(arg, "cluster") == 0) { 176 *locale = MFI_EVT_LOCALE_CLUSTER; 177 return (0); 178 } 179 if (strcasecmp(arg, "all") == 0) { 180 *locale = MFI_EVT_LOCALE_ALL; 181 return (0); 182 } 183 val = strtol(arg, &cp, 0); 184 if (*cp != '\0' || val < 0 || val > 0xffff) { 185 errno = EINVAL; 186 return (-1); 187 } 188 *locale = val; 189 return (0); 190} 191 192static int 193parse_class(char *arg, int8_t *class) 194{ 195 char *cp; 196 long val; 197 198 if (strcasecmp(arg, "debug") == 0) { 199 *class = MFI_EVT_CLASS_DEBUG; 200 return (0); 201 } 202 if (strncasecmp(arg, "prog", 4) == 0) { 203 *class = MFI_EVT_CLASS_PROGRESS; 204 return (0); 205 } 206 if (strncasecmp(arg, "info", 4) == 0) { 207 *class = MFI_EVT_CLASS_INFO; 208 return (0); 209 } 210 if (strncasecmp(arg, "warn", 4) == 0) { 211 *class = MFI_EVT_CLASS_WARNING; 212 return (0); 213 } 214 if (strncasecmp(arg, "crit", 4) == 0) { 215 *class = MFI_EVT_CLASS_CRITICAL; 216 return (0); 217 } 218 if (strcasecmp(arg, "fatal") == 0) { 219 *class = MFI_EVT_CLASS_FATAL; 220 return (0); 221 } 222 if (strcasecmp(arg, "dead") == 0) { 223 *class = MFI_EVT_CLASS_DEAD; 224 return (0); 225 } 226 val = strtol(arg, &cp, 0); 227 if (*cp != '\0' || val < -128 || val > 127) { 228 errno = EINVAL; 229 return (-1); 230 } 231 *class = val; 232 return (0); 233} 234 235/* 236 * The timestamp is the number of seconds since 00:00 Jan 1, 2000. If 237 * the bits in 24-31 are all set, then it is the number of seconds since 238 * boot. 239 */ 240static const char * 241format_timestamp(uint32_t timestamp) 242{ 243 static char buffer[32]; 244 static time_t base; 245 time_t t; 246 struct tm tm; 247 248 if ((timestamp & 0xff000000) == 0xff000000) { 249 snprintf(buffer, sizeof(buffer), "boot + %us", timestamp & 250 0x00ffffff); 251 return (buffer); 252 } 253 254 if (base == 0) { 255 /* Compute 00:00 Jan 1, 2000 offset. */ 256 bzero(&tm, sizeof(tm)); 257 tm.tm_mday = 1; 258 tm.tm_year = (2000 - 1900); 259 base = mktime(&tm); 260 } 261 if (base == -1) { 262 snprintf(buffer, sizeof(buffer), "%us", timestamp); 263 return (buffer); 264 } 265 t = base + timestamp; 266 strftime(buffer, sizeof(buffer), "%+", localtime(&t)); 267 return (buffer); 268} 269 270static const char * 271format_locale(uint16_t locale) 272{ 273 static char buffer[8]; 274 275 switch (locale) { 276 case MFI_EVT_LOCALE_LD: 277 return ("VOLUME"); 278 case MFI_EVT_LOCALE_PD: 279 return ("DRIVE"); 280 case MFI_EVT_LOCALE_ENCL: 281 return ("ENCL"); 282 case MFI_EVT_LOCALE_BBU: 283 return ("BATTERY"); 284 case MFI_EVT_LOCALE_SAS: 285 return ("SAS"); 286 case MFI_EVT_LOCALE_CTRL: 287 return ("CTRL"); 288 case MFI_EVT_LOCALE_CONFIG: 289 return ("CONFIG"); 290 case MFI_EVT_LOCALE_CLUSTER: 291 return ("CLUSTER"); 292 case MFI_EVT_LOCALE_ALL: 293 return ("ALL"); 294 default: 295 snprintf(buffer, sizeof(buffer), "0x%04x", locale); 296 return (buffer); 297 } 298} 299 300static const char * 301format_class(int8_t class) 302{ 303 static char buffer[6]; 304 305 switch (class) { 306 case MFI_EVT_CLASS_DEBUG: 307 return ("debug"); 308 case MFI_EVT_CLASS_PROGRESS: 309 return ("progress"); 310 case MFI_EVT_CLASS_INFO: 311 return ("info"); 312 case MFI_EVT_CLASS_WARNING: 313 return ("WARN"); 314 case MFI_EVT_CLASS_CRITICAL: 315 return ("CRIT"); 316 case MFI_EVT_CLASS_FATAL: 317 return ("FATAL"); 318 case MFI_EVT_CLASS_DEAD: 319 return ("DEAD"); 320 default: 321 snprintf(buffer, sizeof(buffer), "%d", class); 322 return (buffer); 323 } 324} 325 326/* Simulates %D from kernel printf(9). */ 327static void 328simple_hex(void *ptr, size_t length, const char *separator) 329{ 330 unsigned char *cp; 331 u_int i; 332 333 if (length == 0) 334 return; 335 cp = ptr; 336 printf("%02x", cp[0]); 337 for (i = 1; i < length; i++) 338 printf("%s%02x", separator, cp[i]); 339} 340 341static const char * 342pdrive_location(struct mfi_evt_pd *pd) 343{ 344 static char buffer[16]; 345 346 if (pd->enclosure_index == 0) 347 snprintf(buffer, sizeof(buffer), "%02d(s%d)", pd->device_id, 348 pd->slot_number); 349 else 350 snprintf(buffer, sizeof(buffer), "%02d(e%d/s%d)", pd->device_id, 351 pd->enclosure_index, pd->slot_number); 352 return (buffer); 353} 354 355static const char * 356volume_name(int fd, struct mfi_evt_ld *ld) 357{ 358 359 return (mfi_volume_name(fd, ld->target_id)); 360} 361 362/* Ripped from sys/dev/mfi/mfi.c. */ 363static void 364mfi_decode_evt(int fd, struct mfi_evt_detail *detail, int verbose) 365{ 366 367 printf("%5d (%s/%s/%s) - ", detail->seq, format_timestamp(detail->time), 368 format_locale(detail->evt_class.members.locale), 369 format_class(detail->evt_class.members.evt_class)); 370 switch (detail->arg_type) { 371 case MR_EVT_ARGS_NONE: 372 break; 373 case MR_EVT_ARGS_CDB_SENSE: 374 if (verbose) { 375 printf("PD %s CDB ", 376 pdrive_location(&detail->args.cdb_sense.pd) 377 ); 378 simple_hex(detail->args.cdb_sense.cdb, 379 detail->args.cdb_sense.cdb_len, ":"); 380 printf(" Sense "); 381 simple_hex(detail->args.cdb_sense.sense, 382 detail->args.cdb_sense.sense_len, ":"); 383 printf(":\n "); 384 } 385 break; 386 case MR_EVT_ARGS_LD: 387 printf("VOL %s event: ", volume_name(fd, &detail->args.ld)); 388 break; 389 case MR_EVT_ARGS_LD_COUNT: 390 printf("VOL %s", volume_name(fd, &detail->args.ld_count.ld)); 391 if (verbose) { 392 printf(" count %lld: ", 393 (long long)detail->args.ld_count.count); 394 } 395 printf(": "); 396 break; 397 case MR_EVT_ARGS_LD_LBA: 398 printf("VOL %s", volume_name(fd, &detail->args.ld_count.ld)); 399 if (verbose) { 400 printf(" lba %lld", 401 (long long)detail->args.ld_lba.lba); 402 } 403 printf(": "); 404 break; 405 case MR_EVT_ARGS_LD_OWNER: 406 printf("VOL %s", volume_name(fd, &detail->args.ld_count.ld)); 407 if (verbose) { 408 printf(" owner changed: prior %d, new %d", 409 detail->args.ld_owner.pre_owner, 410 detail->args.ld_owner.new_owner); 411 } 412 printf(": "); 413 break; 414 case MR_EVT_ARGS_LD_LBA_PD_LBA: 415 printf("VOL %s", volume_name(fd, &detail->args.ld_count.ld)); 416 if (verbose) { 417 printf(" lba %lld, physical drive PD %s lba %lld", 418 (long long)detail->args.ld_lba_pd_lba.ld_lba, 419 pdrive_location(&detail->args.ld_lba_pd_lba.pd), 420 (long long)detail->args.ld_lba_pd_lba.pd_lba); 421 } 422 printf(": "); 423 break; 424 case MR_EVT_ARGS_LD_PROG: 425 printf("VOL %s", volume_name(fd, &detail->args.ld_prog.ld)); 426 if (verbose) { 427 printf(" progress %d%% in %ds", 428 detail->args.ld_prog.prog.progress/655, 429 detail->args.ld_prog.prog.elapsed_seconds); 430 } 431 printf(": "); 432 break; 433 case MR_EVT_ARGS_LD_STATE: 434 printf("VOL %s", volume_name(fd, &detail->args.ld_prog.ld)); 435 if (verbose) { 436 printf(" state prior %s new %s", 437 mfi_ldstate(detail->args.ld_state.prev_state), 438 mfi_ldstate(detail->args.ld_state.new_state)); 439 } 440 printf(": "); 441 break; 442 case MR_EVT_ARGS_LD_STRIP: 443 printf("VOL %s", volume_name(fd, &detail->args.ld_strip.ld)); 444 if (verbose) { 445 printf(" strip %lld", 446 (long long)detail->args.ld_strip.strip); 447 } 448 printf(": "); 449 break; 450 case MR_EVT_ARGS_PD: 451 if (verbose) { 452 printf("PD %s event: ", 453 pdrive_location(&detail->args.pd)); 454 } 455 break; 456 case MR_EVT_ARGS_PD_ERR: 457 if (verbose) { 458 printf("PD %s err %d: ", 459 pdrive_location(&detail->args.pd_err.pd), 460 detail->args.pd_err.err); 461 } 462 break; 463 case MR_EVT_ARGS_PD_LBA: 464 if (verbose) { 465 printf("PD %s lba %lld: ", 466 pdrive_location(&detail->args.pd_lba.pd), 467 (long long)detail->args.pd_lba.lba); 468 } 469 break; 470 case MR_EVT_ARGS_PD_LBA_LD: 471 if (verbose) { 472 printf("PD %s lba %lld VOL %s: ", 473 pdrive_location(&detail->args.pd_lba_ld.pd), 474 (long long)detail->args.pd_lba.lba, 475 volume_name(fd, &detail->args.pd_lba_ld.ld)); 476 } 477 break; 478 case MR_EVT_ARGS_PD_PROG: 479 if (verbose) { 480 printf("PD %s progress %d%% seconds %ds: ", 481 pdrive_location(&detail->args.pd_prog.pd), 482 detail->args.pd_prog.prog.progress/655, 483 detail->args.pd_prog.prog.elapsed_seconds); 484 } 485 break; 486 case MR_EVT_ARGS_PD_STATE: 487 if (verbose) { 488 printf("PD %s state prior %s new %s: ", 489 pdrive_location(&detail->args.pd_prog.pd), 490 mfi_pdstate(detail->args.pd_state.prev_state), 491 mfi_pdstate(detail->args.pd_state.new_state)); 492 } 493 break; 494 case MR_EVT_ARGS_PCI: 495 if (verbose) { 496 printf("PCI 0x%04x 0x%04x 0x%04x 0x%04x: ", 497 detail->args.pci.venderId, 498 detail->args.pci.deviceId, 499 detail->args.pci.subVenderId, 500 detail->args.pci.subDeviceId); 501 } 502 break; 503 case MR_EVT_ARGS_RATE: 504 if (verbose) { 505 printf("Rebuild rate %d: ", detail->args.rate); 506 } 507 break; 508 case MR_EVT_ARGS_TIME: 509 if (verbose) { 510 printf("Adapter time %s; %d seconds since power on: ", 511 format_timestamp(detail->args.time.rtc), 512 detail->args.time.elapsedSeconds); 513 } 514 break; 515 case MR_EVT_ARGS_ECC: 516 if (verbose) { 517 printf("Adapter ECC %x,%x: %s: ", 518 detail->args.ecc.ecar, 519 detail->args.ecc.elog, 520 detail->args.ecc.str); 521 } 522 break; 523 default: 524 if (verbose) { 525 printf("Type %d: ", detail->arg_type); 526 } 527 break; 528 } 529 printf("%s\n", detail->description); 530} 531 532static int 533show_events(int ac, char **av) 534{ 535 struct mfi_evt_log_state info; 536 struct mfi_evt_list *list; 537 union mfi_evt filter;
|