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