mfi_show.c revision 330449
1/*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 2008, 2009 Yahoo!, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. The names of the authors may not be used to endorse or promote
16 *    products derived from this software without specific prior written
17 *    permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 * $FreeBSD: stable/11/usr.sbin/mfiutil/mfi_show.c 330449 2018-03-05 07:26:05Z eadler $
32 */
33
34#include <sys/types.h>
35#include <sys/errno.h>
36#include <err.h>
37#include <fcntl.h>
38#include <libutil.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42#include <unistd.h>
43#include "mfiutil.h"
44
45static const char* foreign_state = " (FOREIGN)";
46
47MFI_TABLE(top, show);
48
49void
50format_stripe(char *buf, size_t buflen, uint8_t stripe)
51{
52
53	humanize_number(buf, buflen, (1 << stripe) * 512, "", HN_AUTOSCALE,
54	    HN_B | HN_NOSPACE);
55}
56
57static int
58show_adapter(int ac, char **av __unused)
59{
60	struct mfi_ctrl_info info;
61	char stripe[5];
62	int error, fd, comma;
63
64	if (ac != 1) {
65		warnx("show adapter: extra arguments");
66		return (EINVAL);
67	}
68
69	fd = mfi_open(mfi_unit, O_RDONLY);
70	if (fd < 0) {
71		error = errno;
72		warn("mfi_open");
73		return (error);
74	}
75
76	if (mfi_ctrl_get_info(fd, &info, NULL) < 0) {
77		error = errno;
78		warn("Failed to get controller info");
79		close(fd);
80		return (error);
81	}
82	printf("mfi%d Adapter:\n", mfi_unit);
83	printf("    Product Name: %.80s\n", info.product_name);
84	printf("   Serial Number: %.32s\n", info.serial_number);
85	if (info.package_version[0] != '\0')
86		printf("        Firmware: %s\n", info.package_version);
87	printf("     RAID Levels:");
88#ifdef DEBUG
89	printf(" (%#x)", info.raid_levels);
90#endif
91	comma = 0;
92	if (info.raid_levels & MFI_INFO_RAID_0) {
93		printf(" JBOD, RAID0");
94		comma = 1;
95	}
96	if (info.raid_levels & MFI_INFO_RAID_1) {
97		printf("%s RAID1", comma ? "," : "");
98		comma = 1;
99	}
100	if (info.raid_levels & MFI_INFO_RAID_5) {
101		printf("%s RAID5", comma ? "," : "");
102		comma = 1;
103	}
104	if (info.raid_levels & MFI_INFO_RAID_1E) {
105		printf("%s RAID1E", comma ? "," : "");
106		comma = 1;
107	}
108	if (info.raid_levels & MFI_INFO_RAID_6) {
109		printf("%s RAID6", comma ? "," : "");
110		comma = 1;
111	}
112	if ((info.raid_levels & (MFI_INFO_RAID_0 | MFI_INFO_RAID_1)) ==
113	    (MFI_INFO_RAID_0 | MFI_INFO_RAID_1)) {
114		printf("%s RAID10", comma ? "," : "");
115		comma = 1;
116	}
117	if ((info.raid_levels & (MFI_INFO_RAID_0 | MFI_INFO_RAID_5)) ==
118	    (MFI_INFO_RAID_0 | MFI_INFO_RAID_5)) {
119		printf("%s RAID50", comma ? "," : "");
120		comma = 1;
121	}
122	printf("\n");
123	printf("  Battery Backup: ");
124	if (info.hw_present & MFI_INFO_HW_BBU)
125		printf("present\n");
126	else
127		printf("not present\n");
128	if (info.hw_present & MFI_INFO_HW_NVRAM)
129		printf("           NVRAM: %uK\n", info.nvram_size);
130	printf("  Onboard Memory: %uM\n", info.memory_size);
131	format_stripe(stripe, sizeof(stripe), info.stripe_sz_ops.min);
132	printf("  Minimum Stripe: %s\n", stripe);
133	format_stripe(stripe, sizeof(stripe), info.stripe_sz_ops.max);
134	printf("  Maximum Stripe: %s\n", stripe);
135
136	close(fd);
137
138	return (0);
139}
140MFI_COMMAND(show, adapter, show_adapter);
141
142static int
143show_battery(int ac, char **av __unused)
144{
145	struct mfi_bbu_capacity_info cap;
146	struct mfi_bbu_design_info design;
147	struct mfi_bbu_properties props;
148	struct mfi_bbu_status stat;
149	uint8_t status;
150	int comma, error, fd, show_capacity, show_props;
151	char buf[32];
152
153	if (ac != 1) {
154		warnx("show battery: extra arguments");
155		return (EINVAL);
156	}
157
158	fd = mfi_open(mfi_unit, O_RDONLY);
159	if (fd < 0) {
160		error = errno;
161		warn("mfi_open");
162		return (error);
163	}
164
165	if (mfi_dcmd_command(fd, MFI_DCMD_BBU_GET_CAPACITY_INFO, &cap,
166	    sizeof(cap), NULL, 0, &status) < 0) {
167		error = errno;
168		warn("Failed to get capacity info");
169		close(fd);
170		return (error);
171	}
172	if (status == MFI_STAT_NO_HW_PRESENT) {
173		printf("mfi%d: No battery present\n", mfi_unit);
174		close(fd);
175		return (0);
176	}
177	show_capacity = (status == MFI_STAT_OK);
178
179	if (mfi_dcmd_command(fd, MFI_DCMD_BBU_GET_DESIGN_INFO, &design,
180	    sizeof(design), NULL, 0, NULL) < 0) {
181		error = errno;
182		warn("Failed to get design info");
183		close(fd);
184		return (error);
185	}
186
187	if (mfi_dcmd_command(fd, MFI_DCMD_BBU_GET_STATUS, &stat, sizeof(stat),
188	    NULL, 0, NULL) < 0) {
189		error = errno;
190		warn("Failed to get status");
191		close(fd);
192		return (error);
193	}
194
195	if (mfi_bbu_get_props(fd, &props, &status) < 0) {
196		error = errno;
197		warn("Failed to get properties");
198		close(fd);
199		return (error);
200	}
201	show_props = (status == MFI_STAT_OK);
202
203	printf("mfi%d: Battery State:\n", mfi_unit);
204	printf("     Manufacture Date: %d/%d/%d\n", design.mfg_date >> 5 & 0x0f,
205	    design.mfg_date & 0x1f, design.mfg_date >> 9 & 0xffff);
206	printf("        Serial Number: %d\n", design.serial_number);
207	printf("         Manufacturer: %s\n", design.mfg_name);
208	printf("                Model: %s\n", design.device_name);
209	printf("            Chemistry: %s\n", design.device_chemistry);
210	printf("      Design Capacity: %d mAh\n", design.design_capacity);
211	if (show_capacity) {
212		printf(" Full Charge Capacity: %d mAh\n",
213		    cap.full_charge_capacity);
214		printf("     Current Capacity: %d mAh\n",
215		    cap.remaining_capacity);
216		printf("        Charge Cycles: %d\n", cap.cycle_count);
217		printf("       Current Charge: %d%%\n", cap.relative_charge);
218	}
219	printf("       Design Voltage: %d mV\n", design.design_voltage);
220	printf("      Current Voltage: %d mV\n", stat.voltage);
221	printf("          Temperature: %d C\n", stat.temperature);
222	if (show_props) {
223		mfi_autolearn_period(props.auto_learn_period, buf, sizeof(buf));
224		printf("     Autolearn period: %s\n", buf);
225		if (props.auto_learn_mode != 0)
226			snprintf(buf, sizeof(buf), "never");
227		else
228			mfi_next_learn_time(props.next_learn_time, buf,
229			    sizeof(buf));
230		printf("      Next learn time: %s\n", buf);
231		printf(" Learn delay interval: %u hour%s\n",
232		    props.learn_delay_interval,
233		    props.learn_delay_interval != 1 ? "s" : "");
234		mfi_autolearn_mode(props.auto_learn_mode, buf, sizeof(buf));
235		printf("       Autolearn mode: %s\n", buf);
236		if (props.bbu_mode != 0)
237			printf("             BBU Mode: %d\n", props.bbu_mode);
238	}
239	printf("               Status:");
240	comma = 0;
241	if (stat.fw_status & MFI_BBU_STATE_PACK_MISSING) {
242		printf(" PACK_MISSING");
243		comma = 1;
244	}
245	if (stat.fw_status & MFI_BBU_STATE_VOLTAGE_LOW) {
246		printf("%s VOLTAGE_LOW", comma ? "," : "");
247		comma = 1;
248	}
249	if (stat.fw_status & MFI_BBU_STATE_TEMPERATURE_HIGH) {
250		printf("%s TEMPERATURE_HIGH", comma ? "," : "");
251		comma = 1;
252	}
253	if (stat.fw_status & MFI_BBU_STATE_CHARGE_ACTIVE) {
254		printf("%s CHARGING", comma ? "," : "");
255		comma = 1;
256	}
257	if (stat.fw_status & MFI_BBU_STATE_DISCHARGE_ACTIVE) {
258		printf("%s DISCHARGING", comma ? "," : "");
259		comma = 1;
260	}
261	if (stat.fw_status & MFI_BBU_STATE_LEARN_CYC_REQ) {
262		printf("%s LEARN_CYCLE_REQUESTED", comma ? "," : "");
263		comma = 1;
264	}
265	if (stat.fw_status & MFI_BBU_STATE_LEARN_CYC_ACTIVE) {
266		printf("%s LEARN_CYCLE_ACTIVE", comma ? "," : "");
267		comma = 1;
268	}
269	if (stat.fw_status & MFI_BBU_STATE_LEARN_CYC_FAIL) {
270		printf("%s LEARN_CYCLE_FAIL", comma ? "," : "");
271		comma = 1;
272	}
273	if (stat.fw_status & MFI_BBU_STATE_LEARN_CYC_TIMEOUT) {
274		printf("%s LEARN_CYCLE_TIMEOUT", comma ? "," : "");
275		comma = 1;
276	}
277	if (stat.fw_status & MFI_BBU_STATE_I2C_ERR_DETECT) {
278		printf("%s I2C_ERROR_DETECT", comma ? "," : "");
279		comma = 1;
280	}
281
282	if (!comma)
283		printf(" normal");
284	printf("\n");
285	switch (stat.battery_type) {
286	case MFI_BBU_TYPE_BBU:
287		printf("      State of Health: %s\n",
288		    stat.detail.bbu.is_SOH_good ? "good" : "bad");
289		break;
290	}
291
292	close(fd);
293
294	return (0);
295}
296MFI_COMMAND(show, battery, show_battery);
297
298void
299print_ld(struct mfi_ld_info *info, int state_len)
300{
301	struct mfi_ld_params *params = &info->ld_config.params;
302	const char *level;
303	char size[6], stripe[5];
304
305	humanize_number(size, sizeof(size), info->size * 512,
306	    "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
307	format_stripe(stripe, sizeof(stripe),
308	    info->ld_config.params.stripe_size);
309	level = mfi_raid_level(params->primary_raid_level,
310	    params->secondary_raid_level);
311	if (state_len > 0)
312		printf("(%6s) %-8s %6s %-*s", size, level, stripe, state_len,
313		    mfi_ldstate(params->state));
314	else
315		printf("(%s) %s %s %s", size, level, stripe,
316		    mfi_ldstate(params->state));
317}
318
319void
320print_pd(struct mfi_pd_info *info, int state_len)
321{
322	const char *s;
323	char buf[256];
324
325	humanize_number(buf, 6, info->raw_size * 512, "",
326	    HN_AUTOSCALE, HN_B | HN_NOSPACE |HN_DECIMAL);
327	printf("(%6s) ", buf);
328	if (info->state.ddf.v.pd_type.is_foreign) {
329		sprintf(buf, "%s%s", mfi_pdstate(info->fw_state), foreign_state);
330		s = buf;
331	} else
332		s = mfi_pdstate(info->fw_state);
333	if (state_len > 0)
334		printf("%-*s", state_len, s);
335	else
336		printf("%s",s);
337	s = mfi_pd_inq_string(info);
338	if (s != NULL)
339		printf(" %s", s);
340}
341
342static int
343show_config(int ac, char **av __unused)
344{
345	struct mfi_config_data *config;
346	struct mfi_array *ar;
347	struct mfi_ld_config *ld;
348	struct mfi_spare *sp;
349	struct mfi_ld_info linfo;
350	struct mfi_pd_info pinfo;
351	uint16_t device_id;
352	char *p;
353	int error, fd, i, j;
354
355	if (ac != 1) {
356		warnx("show config: extra arguments");
357		return (EINVAL);
358	}
359
360	fd = mfi_open(mfi_unit, O_RDONLY);
361	if (fd < 0) {
362		error = errno;
363		warn("mfi_open");
364		return (error);
365	}
366
367	/* Get the config from the controller. */
368	if (mfi_config_read(fd, &config) < 0) {
369		error = errno;
370		warn("Failed to get config");
371		close(fd);
372		return (error);
373	}
374
375	/* Dump out the configuration. */
376	printf("mfi%d Configuration: %d arrays, %d volumes, %d spares\n",
377	    mfi_unit, config->array_count, config->log_drv_count,
378	    config->spares_count);
379	p = (char *)config->array;
380
381	for (i = 0; i < config->array_count; i++) {
382		ar = (struct mfi_array *)p;
383		printf("    array %u of %u drives:\n", ar->array_ref,
384		    ar->num_drives);
385		for (j = 0; j < ar->num_drives; j++) {
386			device_id = ar->pd[j].ref.v.device_id;
387			printf("        drive %s ", mfi_drive_name(NULL,
388			    device_id,
389			    MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS));
390			if (device_id != 0xffff) {
391				if (mfi_pd_get_info(fd, device_id, &pinfo,
392				    NULL) < 0)
393					printf("%s",
394					    mfi_pdstate(ar->pd[j].fw_state));
395				else
396					print_pd(&pinfo, -1);
397			}
398			printf("\n");
399		}
400		p += config->array_size;
401	}
402
403	for (i = 0; i < config->log_drv_count; i++) {
404		ld = (struct mfi_ld_config *)p;
405		printf("    volume %s ",
406		    mfi_volume_name(fd, ld->properties.ld.v.target_id));
407		if (mfi_ld_get_info(fd, ld->properties.ld.v.target_id, &linfo,
408		    NULL) < 0) {
409			printf("%s %s",
410			    mfi_raid_level(ld->params.primary_raid_level,
411				ld->params.secondary_raid_level),
412			    mfi_ldstate(ld->params.state));
413		} else
414			print_ld(&linfo, -1);
415		if (ld->properties.name[0] != '\0')
416			printf(" <%s>", ld->properties.name);
417		printf(" spans:\n");
418		for (j = 0; j < ld->params.span_depth; j++)
419			printf("        array %u\n", ld->span[j].array_ref);
420		p += config->log_drv_size;
421	}
422
423	for (i = 0; i < config->spares_count; i++) {
424		sp = (struct mfi_spare *)p;
425		printf("    %s spare %s ",
426		    sp->spare_type & MFI_SPARE_DEDICATED ? "dedicated" :
427		    "global", mfi_drive_name(NULL, sp->ref.v.device_id,
428		    MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS));
429		if (mfi_pd_get_info(fd, sp->ref.v.device_id, &pinfo, NULL) < 0)
430			printf("%s", mfi_pdstate(MFI_PD_STATE_HOT_SPARE));
431		else
432			print_pd(&pinfo, -1);
433		if (sp->spare_type & MFI_SPARE_DEDICATED) {
434			printf(" backs:\n");
435			for (j = 0; j < sp->array_count; j++)
436				printf("        array %u\n", sp->array_ref[j]);
437		} else
438			printf("\n");
439		p += config->spares_size;
440	}
441	free(config);
442	close(fd);
443
444	return (0);
445}
446MFI_COMMAND(show, config, show_config);
447
448static int
449show_volumes(int ac, char **av __unused)
450{
451	struct mfi_ld_list list;
452	struct mfi_ld_info info;
453	int error, fd;
454	u_int i, len, state_len;
455
456	if (ac != 1) {
457		warnx("show volumes: extra arguments");
458		return (EINVAL);
459	}
460
461	fd = mfi_open(mfi_unit, O_RDONLY);
462	if (fd < 0) {
463		error = errno;
464		warn("mfi_open");
465		return (error);
466	}
467
468	/* Get the logical drive list from the controller. */
469	if (mfi_ld_get_list(fd, &list, NULL) < 0) {
470		error = errno;
471		warn("Failed to get volume list");
472		close(fd);
473		return (error);
474	}
475
476	/* List the volumes. */
477	printf("mfi%d Volumes:\n", mfi_unit);
478	state_len = strlen("State");
479	for (i = 0; i < list.ld_count; i++) {
480		len = strlen(mfi_ldstate(list.ld_list[i].state));
481		if (len > state_len)
482			state_len = len;
483	}
484	printf("  Id     Size    Level   Stripe ");
485	len = state_len - strlen("State");
486	for (i = 0; i < (len + 1) / 2; i++)
487		printf(" ");
488	printf("State");
489	for (i = 0; i < len / 2; i++)
490		printf(" ");
491	printf("  Cache   Name\n");
492	for (i = 0; i < list.ld_count; i++) {
493		if (mfi_ld_get_info(fd, list.ld_list[i].ld.v.target_id, &info,
494		    NULL) < 0) {
495			error = errno;
496			warn("Failed to get info for volume %d",
497			    list.ld_list[i].ld.v.target_id);
498			close(fd);
499			return (error);
500		}
501		printf("%6s ",
502		    mfi_volume_name(fd, list.ld_list[i].ld.v.target_id));
503		print_ld(&info, state_len);
504		switch (info.ld_config.properties.current_cache_policy &
505		    (MR_LD_CACHE_ALLOW_WRITE_CACHE |
506		    MR_LD_CACHE_ALLOW_READ_CACHE)) {
507		case 0:
508			printf(" Disabled");
509			break;
510		case MR_LD_CACHE_ALLOW_READ_CACHE:
511			printf(" Reads   ");
512			break;
513		case MR_LD_CACHE_ALLOW_WRITE_CACHE:
514			printf(" Writes  ");
515			break;
516		case MR_LD_CACHE_ALLOW_WRITE_CACHE |
517		    MR_LD_CACHE_ALLOW_READ_CACHE:
518			printf(" Enabled ");
519			break;
520		}
521		if (info.ld_config.properties.name[0] != '\0')
522			printf(" <%s>", info.ld_config.properties.name);
523		printf("\n");
524	}
525	close(fd);
526
527	return (0);
528}
529MFI_COMMAND(show, volumes, show_volumes);
530
531static int
532show_drives(int ac, char **av __unused)
533{
534	struct mfi_pd_list *list;
535	struct mfi_pd_info info;
536	u_int i, len, state_len;
537	int error, fd;
538
539	if (ac != 1) {
540		warnx("show drives: extra arguments");
541		return (EINVAL);
542	}
543
544	fd = mfi_open(mfi_unit, O_RDONLY);
545	if (fd < 0) {
546		error = errno;
547		warn("mfi_open");
548		return (error);
549	}
550
551	list = NULL;
552	if (mfi_pd_get_list(fd, &list, NULL) < 0) {
553		error = errno;
554		warn("Failed to get drive list");
555		goto error;
556	}
557
558	/* Walk the list of drives to determine width of state column. */
559	state_len = 0;
560	for (i = 0; i < list->count; i++) {
561		if (list->addr[i].scsi_dev_type != 0)
562			continue;
563
564		if (mfi_pd_get_info(fd, list->addr[i].device_id, &info,
565		    NULL) < 0) {
566			error = errno;
567			warn("Failed to fetch info for drive %u",
568			    list->addr[i].device_id);
569			goto error;
570		}
571		len = strlen(mfi_pdstate(info.fw_state));
572		if (info.state.ddf.v.pd_type.is_foreign)
573			len += strlen(foreign_state);
574		if (len > state_len)
575			state_len = len;
576	}
577
578	/* List the drives. */
579	printf("mfi%d Physical Drives:\n", mfi_unit);
580	for (i = 0; i < list->count; i++) {
581
582		/* Skip non-hard disks. */
583		if (list->addr[i].scsi_dev_type != 0)
584			continue;
585
586		/* Fetch details for this drive. */
587		if (mfi_pd_get_info(fd, list->addr[i].device_id, &info,
588		    NULL) < 0) {
589			error = errno;
590			warn("Failed to fetch info for drive %u",
591			    list->addr[i].device_id);
592			goto error;
593		}
594
595		printf("%s ", mfi_drive_name(&info, list->addr[i].device_id,
596		    MFI_DNAME_DEVICE_ID));
597		print_pd(&info, state_len);
598		printf(" %s", mfi_drive_name(&info, list->addr[i].device_id,
599		    MFI_DNAME_ES));
600		printf("\n");
601	}
602	error = 0;
603error:
604	free(list);
605	close(fd);
606
607	return (error);
608}
609MFI_COMMAND(show, drives, show_drives);
610
611static int
612show_firmware(int ac, char **av __unused)
613{
614	struct mfi_ctrl_info info;
615	struct mfi_info_component header;
616	int error, fd;
617	u_int i;
618
619	if (ac != 1) {
620		warnx("show firmware: extra arguments");
621		return (EINVAL);
622	}
623
624	fd = mfi_open(mfi_unit, O_RDONLY);
625	if (fd < 0) {
626		error = errno;
627		warn("mfi_open");
628		return (error);
629	}
630
631	if (mfi_ctrl_get_info(fd, &info, NULL) < 0) {
632		error = errno;
633		warn("Failed to get controller info");
634		close(fd);
635		return (error);
636	}
637
638	if (info.package_version[0] != '\0')
639		printf("mfi%d Firmware Package Version: %s\n", mfi_unit,
640		    info.package_version);
641	printf("mfi%d Firmware Images:\n", mfi_unit);
642	strcpy(header.name, "Name");
643	strcpy(header.version, "Version");
644	strcpy(header.build_date, "Date");
645	strcpy(header.build_time, "Time");
646	scan_firmware(&header);
647	if (info.image_component_count > 8)
648		info.image_component_count = 8;
649	for (i = 0; i < info.image_component_count; i++)
650		scan_firmware(&info.image_component[i]);
651	if (info.pending_image_component_count > 8)
652		info.pending_image_component_count = 8;
653	for (i = 0; i < info.pending_image_component_count; i++)
654		scan_firmware(&info.pending_image_component[i]);
655	display_firmware(&header, "Status");
656	for (i = 0; i < info.image_component_count; i++)
657		display_firmware(&info.image_component[i], "active");
658	for (i = 0; i < info.pending_image_component_count; i++)
659		display_firmware(&info.pending_image_component[i], "pending");
660
661	close(fd);
662
663	return (0);
664}
665MFI_COMMAND(show, firmware, show_firmware);
666
667static int
668show_progress(int ac, char **av __unused)
669{
670	struct mfi_ld_list llist;
671	struct mfi_pd_list *plist;
672	struct mfi_ld_info linfo;
673	struct mfi_pd_info pinfo;
674	int busy, error, fd;
675	u_int i;
676	uint16_t device_id;
677	uint8_t target_id;
678
679	if (ac != 1) {
680		warnx("show progress: extra arguments");
681		return (EINVAL);
682	}
683
684	fd = mfi_open(mfi_unit, O_RDONLY);
685	if (fd < 0) {
686		error = errno;
687		warn("mfi_open");
688		return (error);
689	}
690
691	if (mfi_ld_get_list(fd, &llist, NULL) < 0) {
692		error = errno;
693		warn("Failed to get volume list");
694		close(fd);
695		return (error);
696	}
697	if (mfi_pd_get_list(fd, &plist, NULL) < 0) {
698		error = errno;
699		warn("Failed to get drive list");
700		close(fd);
701		return (error);
702	}
703
704	busy = 0;
705	for (i = 0; i < llist.ld_count; i++) {
706		target_id = llist.ld_list[i].ld.v.target_id;
707		if (mfi_ld_get_info(fd, target_id, &linfo, NULL) < 0) {
708			error = errno;
709			warn("Failed to get info for volume %s",
710			    mfi_volume_name(fd, target_id));
711			free(plist);
712			close(fd);
713			return (error);
714		}
715		if (linfo.progress.active & MFI_LD_PROGRESS_CC) {
716			printf("volume %s ", mfi_volume_name(fd, target_id));
717			mfi_display_progress("Consistency Check",
718			    &linfo.progress.cc);
719			busy = 1;
720		}
721		if (linfo.progress.active & MFI_LD_PROGRESS_BGI) {
722			printf("volume %s ", mfi_volume_name(fd, target_id));
723			mfi_display_progress("Background Init",
724			    &linfo.progress.bgi);
725			busy = 1;
726		}
727		if (linfo.progress.active & MFI_LD_PROGRESS_FGI) {
728			printf("volume %s ", mfi_volume_name(fd, target_id));
729			mfi_display_progress("Foreground Init",
730			    &linfo.progress.fgi);
731			busy = 1;
732		}
733		if (linfo.progress.active & MFI_LD_PROGRESS_RECON) {
734			printf("volume %s ", mfi_volume_name(fd, target_id));
735			mfi_display_progress("Reconstruction",
736			    &linfo.progress.recon);
737			busy = 1;
738		}
739	}
740
741	for (i = 0; i < plist->count; i++) {
742		if (plist->addr[i].scsi_dev_type != 0)
743			continue;
744
745		device_id = plist->addr[i].device_id;
746		if (mfi_pd_get_info(fd, device_id, &pinfo, NULL) < 0) {
747			error = errno;
748			warn("Failed to fetch info for drive %u", device_id);
749			free(plist);
750			close(fd);
751			return (error);
752		}
753
754		if (pinfo.prog_info.active & MFI_PD_PROGRESS_REBUILD) {
755			printf("drive %s ", mfi_drive_name(NULL, device_id,
756			    MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS));
757			mfi_display_progress("Rebuild", &pinfo.prog_info.rbld);
758			busy = 1;
759		}
760		if (pinfo.prog_info.active & MFI_PD_PROGRESS_PATROL) {
761			printf("drive %s ", mfi_drive_name(NULL, device_id,
762			    MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS));
763			mfi_display_progress("Patrol Read",
764			    &pinfo.prog_info.patrol);
765			busy = 1;
766		}
767		if (pinfo.prog_info.active & MFI_PD_PROGRESS_CLEAR) {
768			printf("drive %s ", mfi_drive_name(NULL, device_id,
769			    MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS));
770			mfi_display_progress("Clear", &pinfo.prog_info.clear);
771			busy = 1;
772		}
773	}
774
775	free(plist);
776	close(fd);
777
778	if (!busy)
779		printf("No activity in progress for adapter mfi%d\n", mfi_unit);
780
781	return (0);
782}
783MFI_COMMAND(show, progress, show_progress);
784
785static int
786show_foreign(int ac, char **av)
787{
788	return(display_format(ac, av, 0/*normal display*/, MFI_DCMD_CFG_FOREIGN_DISPLAY));
789}
790MFI_COMMAND(show, foreign, show_foreign);
791