2 * Copyright (c) 2008, 2009 Yahoo!, Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The names of the authors may not be used to endorse or promote
14 * products derived from this software without specific prior written
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * $FreeBSD: src/usr.sbin/mfiutil/mfi_evt.c,v 1.6 2011/12/05 15:11:35 jhb Exp $
32 #include <sys/types.h>
33 #include <sys/errno.h>
43 mfi_event_get_info(int fd
, struct mfi_evt_log_state
*info
, uint8_t *statusp
)
46 return (mfi_dcmd_command(fd
, MFI_DCMD_CTRL_EVENT_GETINFO
, info
,
47 sizeof(struct mfi_evt_log_state
), NULL
, 0, statusp
));
51 mfi_get_events(int fd
, struct mfi_evt_list
*list
, int num_events
,
52 union mfi_evt filter
, uint32_t start_seq
, uint8_t *statusp
)
58 mbox
[1] = filter
.word
;
59 size
= sizeof(struct mfi_evt_list
) + sizeof(struct mfi_evt_detail
) *
61 return (mfi_dcmd_command(fd
, MFI_DCMD_CTRL_EVENT_GET
, list
, size
,
62 (uint8_t *)&mbox
, sizeof(mbox
), statusp
));
66 show_logstate(int ac
, __unused
char **av
)
68 struct mfi_evt_log_state info
;
72 warnx("show logstate: extra arguments");
76 fd
= mfi_open(mfi_unit
);
83 if (mfi_event_get_info(fd
, &info
, NULL
) < 0) {
85 warn("Failed to get event log info");
90 printf("mfi%d Event Log Sequence Numbers:\n", mfi_unit
);
91 printf(" Newest Seq #: %u\n", info
.newest_seq_num
);
92 printf(" Oldest Seq #: %u\n", info
.oldest_seq_num
);
93 printf(" Clear Seq #: %u\n", info
.clear_seq_num
);
94 printf("Shutdown Seq #: %u\n", info
.shutdown_seq_num
);
95 printf(" Boot Seq #: %u\n", info
.boot_seq_num
);
101 MFI_COMMAND(show
, logstate
, show_logstate
);
104 parse_seq(struct mfi_evt_log_state
*info
, char *arg
, uint32_t *seq
)
109 if (strcasecmp(arg
, "newest") == 0) {
110 *seq
= info
->newest_seq_num
;
113 if (strcasecmp(arg
, "oldest") == 0) {
114 *seq
= info
->oldest_seq_num
;
117 if (strcasecmp(arg
, "clear") == 0) {
118 *seq
= info
->clear_seq_num
;
121 if (strcasecmp(arg
, "shutdown") == 0) {
122 *seq
= info
->shutdown_seq_num
;
125 if (strcasecmp(arg
, "boot") == 0) {
126 *seq
= info
->boot_seq_num
;
129 val
= strtol(arg
, &cp
, 0);
130 if (*cp
!= '\0' || val
< 0) {
139 parse_locale(char *arg
, uint16_t *locale
)
144 if (strncasecmp(arg
, "vol", 3) == 0 || strcasecmp(arg
, "ld") == 0) {
145 *locale
= MFI_EVT_LOCALE_LD
;
148 if (strncasecmp(arg
, "drive", 5) == 0 || strcasecmp(arg
, "pd") == 0) {
149 *locale
= MFI_EVT_LOCALE_PD
;
152 if (strncasecmp(arg
, "encl", 4) == 0) {
153 *locale
= MFI_EVT_LOCALE_ENCL
;
156 if (strncasecmp(arg
, "batt", 4) == 0 ||
157 strncasecmp(arg
, "bbu", 3) == 0) {
158 *locale
= MFI_EVT_LOCALE_BBU
;
161 if (strcasecmp(arg
, "sas") == 0) {
162 *locale
= MFI_EVT_LOCALE_SAS
;
165 if (strcasecmp(arg
, "ctrl") == 0 || strncasecmp(arg
, "cont", 4) == 0) {
166 *locale
= MFI_EVT_LOCALE_CTRL
;
169 if (strcasecmp(arg
, "config") == 0) {
170 *locale
= MFI_EVT_LOCALE_CONFIG
;
173 if (strcasecmp(arg
, "cluster") == 0) {
174 *locale
= MFI_EVT_LOCALE_CLUSTER
;
177 if (strcasecmp(arg
, "all") == 0) {
178 *locale
= MFI_EVT_LOCALE_ALL
;
181 val
= strtol(arg
, &cp
, 0);
182 if (*cp
!= '\0' || val
< 0 || val
> 0xffff) {
191 parse_class(char *arg
, int8_t *class)
196 if (strcasecmp(arg
, "debug") == 0) {
197 *class = MFI_EVT_CLASS_DEBUG
;
200 if (strncasecmp(arg
, "prog", 4) == 0) {
201 *class = MFI_EVT_CLASS_PROGRESS
;
204 if (strncasecmp(arg
, "info", 4) == 0) {
205 *class = MFI_EVT_CLASS_INFO
;
208 if (strncasecmp(arg
, "warn", 4) == 0) {
209 *class = MFI_EVT_CLASS_WARNING
;
212 if (strncasecmp(arg
, "crit", 4) == 0) {
213 *class = MFI_EVT_CLASS_CRITICAL
;
216 if (strcasecmp(arg
, "fatal") == 0) {
217 *class = MFI_EVT_CLASS_FATAL
;
220 if (strcasecmp(arg
, "dead") == 0) {
221 *class = MFI_EVT_CLASS_DEAD
;
224 val
= strtol(arg
, &cp
, 0);
225 if (*cp
!= '\0' || val
< -128 || val
> 127) {
234 * The timestamp is the number of seconds since 00:00 Jan 1, 2000. If
235 * the bits in 24-31 are all set, then it is the number of seconds since
239 format_timestamp(uint32_t timestamp
)
241 static char buffer
[32];
246 if ((timestamp
& 0xff000000) == 0xff000000) {
247 snprintf(buffer
, sizeof(buffer
), "boot + %us", timestamp
&
253 /* Compute 00:00 Jan 1, 2000 offset. */
254 bzero(&tm
, sizeof(tm
));
256 tm
.tm_year
= (2000 - 1900);
260 snprintf(buffer
, sizeof(buffer
), "%us", timestamp
);
263 t
= base
+ timestamp
;
264 strftime(buffer
, sizeof(buffer
), "%+", localtime(&t
));
269 format_locale(uint16_t locale
)
271 static char buffer
[8];
274 case MFI_EVT_LOCALE_LD
:
276 case MFI_EVT_LOCALE_PD
:
278 case MFI_EVT_LOCALE_ENCL
:
280 case MFI_EVT_LOCALE_BBU
:
282 case MFI_EVT_LOCALE_SAS
:
284 case MFI_EVT_LOCALE_CTRL
:
286 case MFI_EVT_LOCALE_CONFIG
:
288 case MFI_EVT_LOCALE_CLUSTER
:
290 case MFI_EVT_LOCALE_ALL
:
293 snprintf(buffer
, sizeof(buffer
), "0x%04x", locale
);
299 format_class(int8_t class)
301 static char buffer
[6];
304 case MFI_EVT_CLASS_DEBUG
:
306 case MFI_EVT_CLASS_PROGRESS
:
308 case MFI_EVT_CLASS_INFO
:
310 case MFI_EVT_CLASS_WARNING
:
312 case MFI_EVT_CLASS_CRITICAL
:
314 case MFI_EVT_CLASS_FATAL
:
316 case MFI_EVT_CLASS_DEAD
:
319 snprintf(buffer
, sizeof(buffer
), "%d", class);
325 simple_hex(void *ptr
, size_t length
, const char *separator
)
333 printf("%02x", cp
[0]);
334 for (i
= 1; i
< length
; i
++)
335 printf("%s%02x", separator
, cp
[i
]);
339 pdrive_location(struct mfi_evt_pd
*pd
)
341 static char buffer
[16];
343 if (pd
->enclosure_index
== 0)
344 snprintf(buffer
, sizeof(buffer
), "%02d(s%d)", pd
->device_id
,
347 snprintf(buffer
, sizeof(buffer
), "%02d(e%d/s%d)", pd
->device_id
,
348 pd
->enclosure_index
, pd
->slot_number
);
353 volume_name(int fd
, struct mfi_evt_ld
*ld
)
356 return (mfi_volume_name(fd
, ld
->target_id
));
359 /* Ripped from sys/dev/mfi/mfi.c. */
361 mfi_decode_evt(int fd
, struct mfi_evt_detail
*detail
, int verbose
)
364 printf("%5d (%s/%s/%s) - ", detail
->seq
, format_timestamp(detail
->time
),
365 format_locale(detail
->evt_class
.members
.locale
),
366 format_class(detail
->evt_class
.members
.evt_class
));
367 switch (detail
->arg_type
) {
368 case MR_EVT_ARGS_NONE
:
370 case MR_EVT_ARGS_CDB_SENSE
:
373 pdrive_location(&detail
->args
.cdb_sense
.pd
)
375 simple_hex(detail
->args
.cdb_sense
.cdb
,
376 detail
->args
.cdb_sense
.cdb_len
, ":");
378 simple_hex(detail
->args
.cdb_sense
.sense
,
379 detail
->args
.cdb_sense
.sense_len
, ":");
384 printf("VOL %s event: ", volume_name(fd
, &detail
->args
.ld
));
386 case MR_EVT_ARGS_LD_COUNT
:
387 printf("VOL %s", volume_name(fd
, &detail
->args
.ld_count
.ld
));
389 printf(" count %lld: ",
390 (long long)detail
->args
.ld_count
.count
);
394 case MR_EVT_ARGS_LD_LBA
:
395 printf("VOL %s", volume_name(fd
, &detail
->args
.ld_count
.ld
));
398 (long long)detail
->args
.ld_lba
.lba
);
402 case MR_EVT_ARGS_LD_OWNER
:
403 printf("VOL %s", volume_name(fd
, &detail
->args
.ld_count
.ld
));
405 printf(" owner changed: prior %d, new %d",
406 detail
->args
.ld_owner
.pre_owner
,
407 detail
->args
.ld_owner
.new_owner
);
411 case MR_EVT_ARGS_LD_LBA_PD_LBA
:
412 printf("VOL %s", volume_name(fd
, &detail
->args
.ld_count
.ld
));
414 printf(" lba %lld, physical drive PD %s lba %lld",
415 (long long)detail
->args
.ld_lba_pd_lba
.ld_lba
,
416 pdrive_location(&detail
->args
.ld_lba_pd_lba
.pd
),
417 (long long)detail
->args
.ld_lba_pd_lba
.pd_lba
);
421 case MR_EVT_ARGS_LD_PROG
:
422 printf("VOL %s", volume_name(fd
, &detail
->args
.ld_prog
.ld
));
424 printf(" progress %d%% in %ds",
425 detail
->args
.ld_prog
.prog
.progress
/655,
426 detail
->args
.ld_prog
.prog
.elapsed_seconds
);
430 case MR_EVT_ARGS_LD_STATE
:
431 printf("VOL %s", volume_name(fd
, &detail
->args
.ld_prog
.ld
));
433 printf(" state prior %s new %s",
434 mfi_ldstate(detail
->args
.ld_state
.prev_state
),
435 mfi_ldstate(detail
->args
.ld_state
.new_state
));
439 case MR_EVT_ARGS_LD_STRIP
:
440 printf("VOL %s", volume_name(fd
, &detail
->args
.ld_strip
.ld
));
442 printf(" strip %lld",
443 (long long)detail
->args
.ld_strip
.strip
);
449 printf("PD %s event: ",
450 pdrive_location(&detail
->args
.pd
));
453 case MR_EVT_ARGS_PD_ERR
:
455 printf("PD %s err %d: ",
456 pdrive_location(&detail
->args
.pd_err
.pd
),
457 detail
->args
.pd_err
.err
);
460 case MR_EVT_ARGS_PD_LBA
:
462 printf("PD %s lba %lld: ",
463 pdrive_location(&detail
->args
.pd_lba
.pd
),
464 (long long)detail
->args
.pd_lba
.lba
);
467 case MR_EVT_ARGS_PD_LBA_LD
:
469 printf("PD %s lba %lld VOL %s: ",
470 pdrive_location(&detail
->args
.pd_lba_ld
.pd
),
471 (long long)detail
->args
.pd_lba
.lba
,
472 volume_name(fd
, &detail
->args
.pd_lba_ld
.ld
));
475 case MR_EVT_ARGS_PD_PROG
:
477 printf("PD %s progress %d%% seconds %ds: ",
478 pdrive_location(&detail
->args
.pd_prog
.pd
),
479 detail
->args
.pd_prog
.prog
.progress
/655,
480 detail
->args
.pd_prog
.prog
.elapsed_seconds
);
483 case MR_EVT_ARGS_PD_STATE
:
485 printf("PD %s state prior %s new %s: ",
486 pdrive_location(&detail
->args
.pd_prog
.pd
),
487 mfi_pdstate(detail
->args
.pd_state
.prev_state
),
488 mfi_pdstate(detail
->args
.pd_state
.new_state
));
491 case MR_EVT_ARGS_PCI
:
493 printf("PCI 0x%04x 0x%04x 0x%04x 0x%04x: ",
494 detail
->args
.pci
.venderId
,
495 detail
->args
.pci
.deviceId
,
496 detail
->args
.pci
.subVenderId
,
497 detail
->args
.pci
.subDeviceId
);
500 case MR_EVT_ARGS_RATE
:
502 printf("Rebuild rate %d: ", detail
->args
.rate
);
505 case MR_EVT_ARGS_TIME
:
507 printf("Adapter time %s; %d seconds since power on: ",
508 format_timestamp(detail
->args
.time
.rtc
),
509 detail
->args
.time
.elapsedSeconds
);
512 case MR_EVT_ARGS_ECC
:
514 printf("Adapter ECC %x,%x: %s: ",
515 detail
->args
.ecc
.ecar
,
516 detail
->args
.ecc
.elog
,
517 detail
->args
.ecc
.str
);
522 printf("Type %d: ", detail
->arg_type
);
526 printf("%s\n", detail
->description
);
530 show_events(int ac
, char **av
)
532 struct mfi_evt_log_state info
;
533 struct mfi_evt_list
*list
;
534 union mfi_evt filter
;
538 uint32_t seq
, start
, stop
;
540 int ch
, error
, fd
, num_events
, verbose
;
543 fd
= mfi_open(mfi_unit
);
550 if (mfi_event_get_info(fd
, &info
, NULL
) < 0) {
552 warn("Failed to get event log info");
557 /* Default settings. */
559 filter
.members
.reserved
= 0;
560 filter
.members
.locale
= MFI_EVT_LOCALE_ALL
;
561 filter
.members
.evt_class
= MFI_EVT_CLASS_WARNING
;
562 start
= info
.boot_seq_num
;
563 stop
= info
.newest_seq_num
;
566 /* Parse any options. */
568 while ((ch
= getopt(ac
, av
, "c:l:n:v")) != -1) {
571 if (parse_class(optarg
, &filter
.members
.evt_class
) < 0) {
573 warn("Error parsing event class");
579 if (parse_locale(optarg
, &filter
.members
.locale
) < 0) {
581 warn("Error parsing event locale");
587 val
= strtol(optarg
, &cp
, 0);
588 if (*cp
!= '\0' || val
<= 0) {
589 warnx("Invalid event count");
607 /* Determine buffer size and validate it. */
608 size
= sizeof(struct mfi_evt_list
) + sizeof(struct mfi_evt_detail
) *
610 if (size
> getpagesize()) {
611 warnx("Event count is too high");
616 /* Handle optional start and stop sequence numbers. */
618 warnx("show events: extra arguments");
622 if (ac
> 0 && parse_seq(&info
, av
[0], &start
) < 0) {
624 warn("Error parsing starting sequence number");
628 if (ac
> 1 && parse_seq(&info
, av
[1], &stop
) < 0) {
630 warn("Error parsing ending sequence number");
637 warnx("malloc failed");
641 for (seq
= start
;;) {
642 if (mfi_get_events(fd
, list
, num_events
, filter
, seq
,
645 warn("Failed to fetch events");
650 if (status
== MFI_STAT_NOT_FOUND
) {
652 warnx("No matching events found");
655 if (status
!= MFI_STAT_OK
) {
656 warnx("Error fetching events: %s", mfi_status(status
));
662 for (i
= 0; i
< list
->count
; i
++) {
664 * If this event is newer than 'stop_seq' then
665 * break out of the loop. Note that the log
666 * is a circular buffer so we have to handle
667 * the case that our stop point is earlier in
668 * the buffer than our start point.
670 if (list
->event
[i
].seq
>= stop
) {
673 else if (list
->event
[i
].seq
< start
)
676 mfi_decode_evt(fd
, &list
->event
[i
], verbose
);
680 * XXX: If the event's seq # is the end of the buffer
681 * then this probably won't do the right thing. We
682 * need to know the size of the buffer somehow.
684 seq
= list
->event
[list
->count
- 1].seq
+ 1;
693 MFI_COMMAND(show
, events
, show_events
);