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