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