1196212Sscottl/*-
2196212Sscottl * Copyright (c) 2008 Yahoo!, Inc.
3196212Sscottl * All rights reserved.
4196212Sscottl * Written by: John Baldwin <jhb@FreeBSD.org>
5196212Sscottl *
6196212Sscottl * Redistribution and use in source and binary forms, with or without
7196212Sscottl * modification, are permitted provided that the following conditions
8196212Sscottl * are met:
9196212Sscottl * 1. Redistributions of source code must retain the above copyright
10196212Sscottl *    notice, this list of conditions and the following disclaimer.
11196212Sscottl * 2. Redistributions in binary form must reproduce the above copyright
12196212Sscottl *    notice, this list of conditions and the following disclaimer in the
13196212Sscottl *    documentation and/or other materials provided with the distribution.
14196212Sscottl * 3. Neither the name of the author nor the names of any co-contributors
15196212Sscottl *    may be used to endorse or promote products derived from this software
16196212Sscottl *    without specific prior written permission.
17196212Sscottl *
18196212Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19196212Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20196212Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21196212Sscottl * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22196212Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23196212Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24196212Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25196212Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26196212Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27196212Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28196212Sscottl * SUCH DAMAGE.
29196212Sscottl */
30196212Sscottl
31196212Sscottl#include <sys/cdefs.h>
32196212Sscottl__RCSID("$FreeBSD$");
33196212Sscottl
34196212Sscottl#include <sys/param.h>
35196212Sscottl#include <sys/errno.h>
36196212Sscottl#include <err.h>
37196212Sscottl#include <libutil.h>
38196212Sscottl#include <stdio.h>
39196212Sscottl#include <stdlib.h>
40196212Sscottl#include <string.h>
41196212Sscottl#include <unistd.h>
42196212Sscottl#include "mptutil.h"
43196212Sscottl
44196212SscottlMPT_TABLE(top, show);
45196212Sscottl
46196212Sscottl#define	STANDALONE_STATE	"ONLINE"
47196212Sscottl
48196212Sscottlstatic void
49196212Sscottlformat_stripe(char *buf, size_t buflen, U32 stripe)
50196212Sscottl{
51196212Sscottl
52196212Sscottl	humanize_number(buf, buflen, stripe * 512, "", HN_AUTOSCALE,
53196212Sscottl	    HN_B | HN_NOSPACE);
54196212Sscottl}
55196212Sscottl
56196212Sscottlstatic void
57196212Sscottldisplay_stripe_map(const char *label, U32 StripeMap)
58196212Sscottl{
59196212Sscottl	char stripe[5];
60196212Sscottl	int comma, i;
61196212Sscottl
62196212Sscottl	comma = 0;
63196212Sscottl	printf("%s: ", label);
64196212Sscottl	for (i = 0; StripeMap != 0; i++, StripeMap >>= 1)
65196212Sscottl		if (StripeMap & 1) {
66196212Sscottl			format_stripe(stripe, sizeof(stripe), 1 << i);
67196212Sscottl			if (comma)
68196212Sscottl				printf(", ");
69196212Sscottl			printf("%s", stripe);
70196212Sscottl			comma = 1;
71196212Sscottl		}
72196212Sscottl	printf("\n");
73196212Sscottl}
74196212Sscottl
75196212Sscottlstatic int
76196212Sscottlshow_adapter(int ac, char **av)
77196212Sscottl{
78196212Sscottl	CONFIG_PAGE_MANUFACTURING_0 *man0;
79196212Sscottl	CONFIG_PAGE_IOC_2 *ioc2;
80196212Sscottl	CONFIG_PAGE_IOC_6 *ioc6;
81204086Sjhb	U16 IOCStatus;
82215046Sjhb	int comma, error, fd;
83196212Sscottl
84196212Sscottl	if (ac != 1) {
85196212Sscottl		warnx("show adapter: extra arguments");
86196212Sscottl		return (EINVAL);
87196212Sscottl	}
88196212Sscottl
89196212Sscottl	fd = mpt_open(mpt_unit);
90196212Sscottl	if (fd < 0) {
91215046Sjhb		error = errno;
92196212Sscottl		warn("mpt_open");
93215046Sjhb		return (error);
94196212Sscottl	}
95196212Sscottl
96196212Sscottl	man0 = mpt_read_man_page(fd, 0, NULL);
97196212Sscottl	if (man0 == NULL) {
98215046Sjhb		error = errno;
99196212Sscottl		warn("Failed to get controller info");
100215046Sjhb		return (error);
101196212Sscottl	}
102196212Sscottl	if (man0->Header.PageLength < sizeof(*man0) / 4) {
103215046Sjhb		warnx("Invalid controller info");
104196212Sscottl		return (EINVAL);
105196212Sscottl	}
106196212Sscottl	printf("mpt%d Adapter:\n", mpt_unit);
107196212Sscottl	printf("       Board Name: %.16s\n", man0->BoardName);
108196212Sscottl	printf("   Board Assembly: %.16s\n", man0->BoardAssembly);
109196212Sscottl	printf("        Chip Name: %.16s\n", man0->ChipName);
110196212Sscottl	printf("    Chip Revision: %.16s\n", man0->ChipRevision);
111196212Sscottl
112196212Sscottl	free(man0);
113196212Sscottl
114204086Sjhb	ioc2 = mpt_read_ioc_page(fd, 2, &IOCStatus);
115196212Sscottl	if (ioc2 != NULL) {
116196212Sscottl		printf("      RAID Levels:");
117196212Sscottl		comma = 0;
118196212Sscottl		if (ioc2->CapabilitiesFlags &
119196212Sscottl		    MPI_IOCPAGE2_CAP_FLAGS_IS_SUPPORT) {
120196212Sscottl			printf(" RAID0");
121196212Sscottl			comma = 1;
122196212Sscottl		}
123196212Sscottl		if (ioc2->CapabilitiesFlags &
124196212Sscottl		    MPI_IOCPAGE2_CAP_FLAGS_IM_SUPPORT) {
125196212Sscottl			printf("%s RAID1", comma ? "," : "");
126196212Sscottl			comma = 1;
127196212Sscottl		}
128196212Sscottl		if (ioc2->CapabilitiesFlags &
129196212Sscottl		    MPI_IOCPAGE2_CAP_FLAGS_IME_SUPPORT) {
130196212Sscottl			printf("%s RAID1E", comma ? "," : "");
131196212Sscottl			comma = 1;
132196212Sscottl		}
133196212Sscottl		if (ioc2->CapabilitiesFlags &
134196212Sscottl		    MPI_IOCPAGE2_CAP_FLAGS_RAID_5_SUPPORT) {
135196212Sscottl			printf("%s RAID5", comma ? "," : "");
136196212Sscottl			comma = 1;
137196212Sscottl		}
138196212Sscottl		if (ioc2->CapabilitiesFlags &
139196212Sscottl		    MPI_IOCPAGE2_CAP_FLAGS_RAID_6_SUPPORT) {
140196212Sscottl			printf("%s RAID6", comma ? "," : "");
141196212Sscottl			comma = 1;
142196212Sscottl		}
143196212Sscottl		if (ioc2->CapabilitiesFlags &
144196212Sscottl		    MPI_IOCPAGE2_CAP_FLAGS_RAID_10_SUPPORT) {
145196212Sscottl			printf("%s RAID10", comma ? "," : "");
146196212Sscottl			comma = 1;
147196212Sscottl		}
148196212Sscottl		if (ioc2->CapabilitiesFlags &
149196212Sscottl		    MPI_IOCPAGE2_CAP_FLAGS_RAID_50_SUPPORT) {
150196212Sscottl			printf("%s RAID50", comma ? "," : "");
151196212Sscottl			comma = 1;
152196212Sscottl		}
153196212Sscottl		if (!comma)
154196212Sscottl			printf(" none");
155196212Sscottl		printf("\n");
156196212Sscottl		free(ioc2);
157204086Sjhb	} else if ((IOCStatus & MPI_IOCSTATUS_MASK) !=
158204086Sjhb	    MPI_IOCSTATUS_CONFIG_INVALID_PAGE)
159204086Sjhb		warnx("mpt_read_ioc_page(2): %s", mpt_ioc_status(IOCStatus));
160196212Sscottl
161204086Sjhb	ioc6 = mpt_read_ioc_page(fd, 6, &IOCStatus);
162196212Sscottl	if (ioc6 != NULL) {
163196212Sscottl		display_stripe_map("    RAID0 Stripes",
164196212Sscottl		    ioc6->SupportedStripeSizeMapIS);
165196212Sscottl		display_stripe_map("   RAID1E Stripes",
166196212Sscottl		    ioc6->SupportedStripeSizeMapIME);
167196212Sscottl		printf(" RAID0 Drives/Vol: %u", ioc6->MinDrivesIS);
168196212Sscottl		if (ioc6->MinDrivesIS != ioc6->MaxDrivesIS)
169196212Sscottl			printf("-%u", ioc6->MaxDrivesIS);
170196212Sscottl		printf("\n");
171196212Sscottl		printf(" RAID1 Drives/Vol: %u", ioc6->MinDrivesIM);
172196212Sscottl		if (ioc6->MinDrivesIM != ioc6->MaxDrivesIM)
173196212Sscottl			printf("-%u", ioc6->MaxDrivesIM);
174196212Sscottl		printf("\n");
175196212Sscottl		printf("RAID1E Drives/Vol: %u", ioc6->MinDrivesIME);
176196212Sscottl		if (ioc6->MinDrivesIME != ioc6->MaxDrivesIME)
177196212Sscottl			printf("-%u", ioc6->MaxDrivesIME);
178196212Sscottl		printf("\n");
179196212Sscottl		free(ioc6);
180204086Sjhb	} else if ((IOCStatus & MPI_IOCSTATUS_MASK) !=
181204086Sjhb	    MPI_IOCSTATUS_CONFIG_INVALID_PAGE)
182204086Sjhb		warnx("mpt_read_ioc_page(6): %s", mpt_ioc_status(IOCStatus));
183196212Sscottl
184196212Sscottl	/* TODO: Add an ioctl to fetch IOC_FACTS and print firmware version. */
185196212Sscottl
186196212Sscottl	close(fd);
187196212Sscottl
188196212Sscottl	return (0);
189196212Sscottl}
190196212SscottlMPT_COMMAND(show, adapter, show_adapter);
191196212Sscottl
192196212Sscottlstatic void
193196212Sscottlprint_vol(CONFIG_PAGE_RAID_VOL_0 *info, int state_len)
194196212Sscottl{
195196212Sscottl	uint64_t size;
196196212Sscottl	const char *level, *state;
197196212Sscottl	char buf[6], stripe[5];
198196212Sscottl
199196212Sscottl	size = ((uint64_t)info->MaxLBAHigh << 32) | info->MaxLBA;
200196212Sscottl	humanize_number(buf, sizeof(buf), (size + 1) * 512, "", HN_AUTOSCALE,
201196212Sscottl	    HN_B | HN_NOSPACE | HN_DECIMAL);
202196212Sscottl	if (info->VolumeType == MPI_RAID_VOL_TYPE_IM)
203196212Sscottl		stripe[0] = '\0';
204196212Sscottl	else
205196212Sscottl		format_stripe(stripe, sizeof(stripe), info->StripeSize);
206196212Sscottl	level = mpt_raid_level(info->VolumeType);
207196212Sscottl	state = mpt_volstate(info->VolumeStatus.State);
208196212Sscottl	if (state_len > 0)
209196212Sscottl		printf("(%6s) %-8s %6s %-*s", buf, level, stripe, state_len,
210196212Sscottl		    state);
211196212Sscottl	else if (stripe[0] != '\0')
212196212Sscottl		printf("(%s) %s %s %s", buf, level, stripe, state);
213196212Sscottl	else
214196212Sscottl		printf("(%s) %s %s", buf, level, state);
215196212Sscottl}
216196212Sscottl
217196212Sscottlstatic void
218196212Sscottlprint_pd(CONFIG_PAGE_RAID_PHYS_DISK_0 *info, int state_len, int location)
219196212Sscottl{
220196212Sscottl	const char *inq, *state;
221196212Sscottl	char buf[6];
222196212Sscottl
223196212Sscottl	humanize_number(buf, sizeof(buf), ((uint64_t)info->MaxLBA + 1) * 512,
224196212Sscottl	    "", HN_AUTOSCALE, HN_B | HN_NOSPACE |HN_DECIMAL);
225196212Sscottl	state = mpt_pdstate(info);
226196212Sscottl	if (state_len > 0)
227196212Sscottl		printf("(%6s) %-*s", buf, state_len, state);
228196212Sscottl	else
229196212Sscottl		printf("(%s) %s", buf, state);
230196212Sscottl	inq = mpt_pd_inq_string(info);
231196212Sscottl	if (inq != NULL)
232196212Sscottl		printf(" %s", inq);
233196212Sscottl	if (!location)
234196212Sscottl		return;
235196212Sscottl	printf(" bus %d id %d", info->PhysDiskBus, info->PhysDiskID);
236196212Sscottl}
237196212Sscottl
238196212Sscottlstatic void
239196212Sscottlprint_standalone(struct mpt_standalone_disk *disk, int state_len, int location)
240196212Sscottl{
241196212Sscottl	char buf[6];
242196212Sscottl
243196212Sscottl	humanize_number(buf, sizeof(buf), (disk->maxlba + 1) * 512,
244196212Sscottl	    "", HN_AUTOSCALE, HN_B | HN_NOSPACE |HN_DECIMAL);
245196212Sscottl	if (state_len > 0)
246196212Sscottl		printf("(%6s) %-*s", buf, state_len, STANDALONE_STATE);
247196212Sscottl	else
248196212Sscottl		printf("(%s) %s", buf, STANDALONE_STATE);
249196212Sscottl	if (disk->inqstring[0] != '\0')
250196212Sscottl		printf(" %s", disk->inqstring);
251196212Sscottl	if (!location)
252196212Sscottl		return;
253196212Sscottl	printf(" bus %d id %d", disk->bus, disk->target);
254196212Sscottl}
255196212Sscottl
256196212Sscottlstatic void
257196212Sscottlprint_spare_pools(U8 HotSparePool)
258196212Sscottl{
259196212Sscottl	int i;
260196212Sscottl
261196212Sscottl	if (HotSparePool == 0) {
262196212Sscottl		printf("none");
263196212Sscottl		return;
264196212Sscottl	}
265196212Sscottl	for (i = 0; HotSparePool != 0; i++) {
266196212Sscottl		if (HotSparePool & 1) {
267196212Sscottl			printf("%d", i);
268196212Sscottl			if (HotSparePool == 1)
269196212Sscottl				break;
270196212Sscottl			printf(", ");
271196212Sscottl		}
272196212Sscottl		HotSparePool >>= 1;
273196212Sscottl	}
274196212Sscottl}
275196212Sscottl
276196212Sscottlstatic int
277196212Sscottlshow_config(int ac, char **av)
278196212Sscottl{
279196212Sscottl	CONFIG_PAGE_IOC_2 *ioc2;
280196212Sscottl	CONFIG_PAGE_IOC_2_RAID_VOL *vol;
281196212Sscottl	CONFIG_PAGE_IOC_5 *ioc5;
282196212Sscottl	IOC_5_HOT_SPARE *spare;
283196212Sscottl	CONFIG_PAGE_RAID_VOL_0 *vinfo;
284196212Sscottl	RAID_VOL0_PHYS_DISK *disk;
285196212Sscottl	CONFIG_PAGE_RAID_VOL_1 *vnames;
286196212Sscottl	CONFIG_PAGE_RAID_PHYS_DISK_0 *pinfo;
287196212Sscottl	struct mpt_standalone_disk *sdisks;
288215046Sjhb	int error, fd, i, j, nsdisks;
289196212Sscottl
290196212Sscottl	if (ac != 1) {
291196212Sscottl		warnx("show config: extra arguments");
292196212Sscottl		return (EINVAL);
293196212Sscottl	}
294196212Sscottl
295196212Sscottl	fd = mpt_open(mpt_unit);
296196212Sscottl	if (fd < 0) {
297215046Sjhb		error = errno;
298196212Sscottl		warn("mpt_open");
299215046Sjhb		return (error);
300196212Sscottl	}
301196212Sscottl
302196212Sscottl	/* Get the config from the controller. */
303196212Sscottl	ioc2 = mpt_read_ioc_page(fd, 2, NULL);
304196212Sscottl	ioc5 = mpt_read_ioc_page(fd, 5, NULL);
305196212Sscottl	if (ioc2 == NULL || ioc5 == NULL) {
306215046Sjhb		error = errno;
307196212Sscottl		warn("Failed to get config");
308215046Sjhb		return (error);
309196212Sscottl	}
310196212Sscottl	if (mpt_fetch_disks(fd, &nsdisks, &sdisks) < 0) {
311215046Sjhb		error = errno;
312196212Sscottl		warn("Failed to get standalone drive list");
313215046Sjhb		return (error);
314196212Sscottl	}
315196212Sscottl
316196212Sscottl	/* Dump out the configuration. */
317196212Sscottl	printf("mpt%d Configuration: %d volumes, %d drives\n",
318196212Sscottl	    mpt_unit, ioc2->NumActiveVolumes, ioc2->NumActivePhysDisks +
319196212Sscottl	    nsdisks);
320196212Sscottl	vol = ioc2->RaidVolume;
321196212Sscottl	for (i = 0; i < ioc2->NumActiveVolumes; vol++, i++) {
322196212Sscottl		printf("    volume %s ", mpt_volume_name(vol->VolumeBus,
323196212Sscottl		    vol->VolumeID));
324196212Sscottl		vinfo = mpt_vol_info(fd, vol->VolumeBus, vol->VolumeID, NULL);
325196212Sscottl		if (vinfo == NULL) {
326196212Sscottl			printf("%s UNKNOWN", mpt_raid_level(vol->VolumeType));
327196212Sscottl		} else
328196212Sscottl			print_vol(vinfo, -1);
329196212Sscottl		vnames = mpt_vol_names(fd, vol->VolumeBus, vol->VolumeID, NULL);
330196212Sscottl		if (vnames != NULL) {
331196212Sscottl			if (vnames->Name[0] != '\0')
332196212Sscottl				printf(" <%s>", vnames->Name);
333196212Sscottl			free(vnames);
334196212Sscottl		}
335196212Sscottl		if (vinfo == NULL) {
336196212Sscottl			printf("\n");
337196212Sscottl			continue;
338196212Sscottl		}
339196212Sscottl		printf(" spans:\n");
340196212Sscottl		disk = vinfo->PhysDisk;
341196212Sscottl		for (j = 0; j < vinfo->NumPhysDisks; disk++, j++) {
342196212Sscottl			printf("        drive %u ", disk->PhysDiskNum);
343196212Sscottl			pinfo = mpt_pd_info(fd, disk->PhysDiskNum, NULL);
344196212Sscottl			if (pinfo != NULL) {
345196212Sscottl				print_pd(pinfo, -1, 0);
346196212Sscottl				free(pinfo);
347196212Sscottl			}
348196212Sscottl			printf("\n");
349196212Sscottl		}
350196212Sscottl		if (vinfo->VolumeSettings.HotSparePool != 0) {
351196212Sscottl			printf("        spare pools: ");
352196212Sscottl			print_spare_pools(vinfo->VolumeSettings.HotSparePool);
353196212Sscottl			printf("\n");
354196212Sscottl		}
355196212Sscottl		free(vinfo);
356196212Sscottl	}
357196212Sscottl
358196212Sscottl	spare = ioc5->HotSpare;
359196212Sscottl	for (i = 0; i < ioc5->NumHotSpares; spare++, i++) {
360196212Sscottl		printf("    spare %u ", spare->PhysDiskNum);
361196212Sscottl		pinfo = mpt_pd_info(fd, spare->PhysDiskNum, NULL);
362196212Sscottl		if (pinfo != NULL) {
363196212Sscottl			print_pd(pinfo, -1, 0);
364196212Sscottl			free(pinfo);
365196212Sscottl		}
366196212Sscottl		printf(" backs pool %d\n", ffs(spare->HotSparePool) - 1);
367196212Sscottl	}
368196212Sscottl	for (i = 0; i < nsdisks; i++) {
369196212Sscottl		printf("    drive %s ", sdisks[i].devname);
370196212Sscottl		print_standalone(&sdisks[i], -1, 0);
371196212Sscottl		printf("\n");
372196212Sscottl	}
373196212Sscottl	free(ioc2);
374196212Sscottl	free(ioc5);
375196212Sscottl	free(sdisks);
376196212Sscottl	close(fd);
377196212Sscottl
378196212Sscottl	return (0);
379196212Sscottl}
380196212SscottlMPT_COMMAND(show, config, show_config);
381196212Sscottl
382196212Sscottlstatic int
383196212Sscottlshow_volumes(int ac, char **av)
384196212Sscottl{
385196212Sscottl	CONFIG_PAGE_IOC_2 *ioc2;
386196212Sscottl	CONFIG_PAGE_IOC_2_RAID_VOL *vol;
387196212Sscottl	CONFIG_PAGE_RAID_VOL_0 **volumes;
388196212Sscottl	CONFIG_PAGE_RAID_VOL_1 *vnames;
389215046Sjhb	int error, fd, i, len, state_len;
390196212Sscottl
391196212Sscottl	if (ac != 1) {
392196212Sscottl		warnx("show volumes: extra arguments");
393196212Sscottl		return (EINVAL);
394196212Sscottl	}
395196212Sscottl
396196212Sscottl	fd = mpt_open(mpt_unit);
397196212Sscottl	if (fd < 0) {
398215046Sjhb		error = errno;
399196212Sscottl		warn("mpt_open");
400215046Sjhb		return (error);
401196212Sscottl	}
402196212Sscottl
403196212Sscottl	/* Get the volume list from the controller. */
404196212Sscottl	ioc2 = mpt_read_ioc_page(fd, 2, NULL);
405196212Sscottl	if (ioc2 == NULL) {
406215046Sjhb		error = errno;
407196212Sscottl		warn("Failed to get volume list");
408215046Sjhb		return (error);
409196212Sscottl	}
410196212Sscottl
411196212Sscottl	/*
412196212Sscottl	 * Go ahead and read the info for all the volumes and figure
413196212Sscottl	 * out the maximum width of the state field.
414196212Sscottl	 */
415196212Sscottl	volumes = malloc(sizeof(*volumes) * ioc2->NumActiveVolumes);
416196212Sscottl	state_len = strlen("State");
417196212Sscottl	vol = ioc2->RaidVolume;
418196212Sscottl	for (i = 0; i < ioc2->NumActiveVolumes; vol++, i++) {
419196212Sscottl		volumes[i] = mpt_vol_info(fd, vol->VolumeBus, vol->VolumeID,
420196212Sscottl		    NULL);
421196212Sscottl		if (volumes[i] == NULL)
422196212Sscottl			len = strlen("UNKNOWN");
423196212Sscottl		else
424196212Sscottl			len = strlen(mpt_volstate(
425196212Sscottl			    volumes[i]->VolumeStatus.State));
426196212Sscottl		if (len > state_len)
427196212Sscottl			state_len = len;
428196212Sscottl	}
429196212Sscottl	printf("mpt%d Volumes:\n", mpt_unit);
430196212Sscottl	printf("  Id     Size    Level   Stripe ");
431196212Sscottl	len = state_len - strlen("State");
432196212Sscottl	for (i = 0; i < (len + 1) / 2; i++)
433196212Sscottl		printf(" ");
434196212Sscottl	printf("State");
435196212Sscottl	for (i = 0; i < len / 2; i++)
436196212Sscottl		printf(" ");
437196212Sscottl	printf(" Write-Cache  Name\n");
438196212Sscottl	vol = ioc2->RaidVolume;
439196212Sscottl	for (i = 0; i < ioc2->NumActiveVolumes; vol++, i++) {
440196212Sscottl		printf("%6s ", mpt_volume_name(vol->VolumeBus, vol->VolumeID));
441196212Sscottl		if (volumes[i] != NULL)
442196212Sscottl			print_vol(volumes[i], state_len);
443196212Sscottl		else
444196212Sscottl			printf("         %-8s %-*s",
445196212Sscottl			    mpt_raid_level(vol->VolumeType), state_len,
446196212Sscottl			    "UNKNOWN");
447196212Sscottl		if (volumes[i] != NULL) {
448196212Sscottl			if (volumes[i]->VolumeSettings.Settings &
449196212Sscottl			    MPI_RAIDVOL0_SETTING_WRITE_CACHING_ENABLE)
450196212Sscottl				printf("   Enabled   ");
451196212Sscottl			else
452196212Sscottl				printf("   Disabled  ");
453196212Sscottl		} else
454196212Sscottl			printf("             ");
455196212Sscottl		free(volumes[i]);
456196212Sscottl		vnames = mpt_vol_names(fd, vol->VolumeBus, vol->VolumeID, NULL);
457196212Sscottl		if (vnames != NULL) {
458196212Sscottl			if (vnames->Name[0] != '\0')
459196212Sscottl				printf(" <%s>", vnames->Name);
460196212Sscottl			free(vnames);
461196212Sscottl		}
462196212Sscottl		printf("\n");
463196212Sscottl	}
464196212Sscottl	free(ioc2);
465196212Sscottl	close(fd);
466196212Sscottl
467196212Sscottl	return (0);
468196212Sscottl}
469196212SscottlMPT_COMMAND(show, volumes, show_volumes);
470196212Sscottl
471196212Sscottlstatic int
472196212Sscottlshow_drives(int ac, char **av)
473196212Sscottl{
474196212Sscottl	struct mpt_drive_list *list;
475196212Sscottl	struct mpt_standalone_disk *sdisks;
476215046Sjhb	int error, fd, i, len, nsdisks, state_len;
477196212Sscottl
478196212Sscottl	if (ac != 1) {
479196212Sscottl		warnx("show drives: extra arguments");
480196212Sscottl		return (EINVAL);
481196212Sscottl	}
482196212Sscottl
483196212Sscottl	fd = mpt_open(mpt_unit);
484196212Sscottl	if (fd < 0) {
485215046Sjhb		error = errno;
486196212Sscottl		warn("mpt_open");
487215046Sjhb		return (error);
488196212Sscottl	}
489196212Sscottl
490196212Sscottl	/* Get the drive list. */
491196212Sscottl	list = mpt_pd_list(fd);
492196212Sscottl	if (list == NULL) {
493215046Sjhb		error = errno;
494196212Sscottl		warn("Failed to get drive list");
495215046Sjhb		return (error);
496196212Sscottl	}
497196212Sscottl
498196212Sscottl	/* Fetch the list of standalone disks for this controller. */
499196212Sscottl	state_len = 0;
500196212Sscottl	if (mpt_fetch_disks(fd, &nsdisks, &sdisks) != 0) {
501196212Sscottl		nsdisks = 0;
502196212Sscottl		sdisks = NULL;
503196212Sscottl	}
504196212Sscottl	if (nsdisks != 0)
505196212Sscottl		state_len = strlen(STANDALONE_STATE);
506196212Sscottl
507196212Sscottl	/* Walk the drive list to determine width of state column. */
508196212Sscottl	for (i = 0; i < list->ndrives; i++) {
509196212Sscottl		len = strlen(mpt_pdstate(list->drives[i]));
510196212Sscottl		if (len > state_len)
511196212Sscottl			state_len = len;
512196212Sscottl	}
513196212Sscottl
514196212Sscottl	/* List the drives. */
515196212Sscottl	printf("mpt%d Physical Drives:\n", mpt_unit);
516196212Sscottl	for (i = 0; i < list->ndrives; i++) {
517196212Sscottl		printf("%4u ", list->drives[i]->PhysDiskNum);
518196212Sscottl		print_pd(list->drives[i], state_len, 1);
519196212Sscottl		printf("\n");
520196212Sscottl	}
521196212Sscottl	mpt_free_pd_list(list);
522196212Sscottl	for (i = 0; i < nsdisks; i++) {
523196212Sscottl		printf("%4s ", sdisks[i].devname);
524196212Sscottl		print_standalone(&sdisks[i], state_len, 1);
525196212Sscottl		printf("\n");
526196212Sscottl	}
527196212Sscottl	free(sdisks);
528196212Sscottl
529196212Sscottl	close(fd);
530196212Sscottl
531196212Sscottl	return (0);
532196212Sscottl}
533196212SscottlMPT_COMMAND(show, drives, show_drives);
534196212Sscottl
535196212Sscottl#ifdef DEBUG
536196212Sscottlstatic int
537196212Sscottlshow_physdisks(int ac, char **av)
538196212Sscottl{
539196212Sscottl	CONFIG_PAGE_RAID_PHYS_DISK_0 *pinfo;
540196212Sscottl	U16 IOCStatus;
541236287Seadler	int error, fd, i;
542196212Sscottl
543196212Sscottl	if (ac != 1) {
544196212Sscottl		warnx("show drives: extra arguments");
545196212Sscottl		return (EINVAL);
546196212Sscottl	}
547196212Sscottl
548196212Sscottl	fd = mpt_open(mpt_unit);
549196212Sscottl	if (fd < 0) {
550215046Sjhb		error = errno;
551196212Sscottl		warn("mpt_open");
552215046Sjhb		return (error);
553196212Sscottl	}
554196212Sscottl
555196212Sscottl	/* Try to find each possible phys disk page. */
556196212Sscottl	for (i = 0; i <= 0xff; i++) {
557196212Sscottl		pinfo = mpt_pd_info(fd, i, &IOCStatus);
558196212Sscottl		if (pinfo == NULL) {
559204086Sjhb			if ((IOCStatus & MPI_IOCSTATUS_MASK) !=
560204086Sjhb			    MPI_IOCSTATUS_CONFIG_INVALID_PAGE)
561196212Sscottl				warnx("mpt_pd_info(%d): %s", i,
562196212Sscottl				    mpt_ioc_status(IOCStatus));
563196212Sscottl			continue;
564196212Sscottl		}
565196212Sscottl		printf("%3u ", i);
566196212Sscottl		print_pd(pinfo, -1, 1);
567196212Sscottl		printf("\n");
568196212Sscottl	}
569196212Sscottl
570196212Sscottl	close(fd);
571196212Sscottl
572196212Sscottl	return (0);
573196212Sscottl}
574196212SscottlMPT_COMMAND(show, pd, show_physdisks);
575196212Sscottl#endif
576