2 * Copyright (c) 2008 Yahoo!, Inc.
4 * Written by: John Baldwin <jhb@FreeBSD.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the author nor the names of any co-contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * $FreeBSD: src/usr.sbin/mptutil/mpt_show.c,v 1.3 2010/11/09 19:28:06 jhb Exp $
33 #include <sys/param.h>
34 #include <sys/errno.h>
45 #define STANDALONE_STATE "ONLINE"
48 format_stripe(char *buf
, size_t buflen
, U32 stripe
)
51 humanize_number(buf
, buflen
, stripe
* 512, "", HN_AUTOSCALE
,
56 display_stripe_map(const char *label
, U32 StripeMap
)
62 printf("%s: ", label
);
63 for (i
= 0; StripeMap
!= 0; i
++, StripeMap
>>= 1)
65 format_stripe(stripe
, sizeof(stripe
), 1 << i
);
75 show_adapter(int ac
, char **av __unused
)
77 CONFIG_PAGE_MANUFACTURING_0
*man0
;
78 CONFIG_PAGE_IOC_2
*ioc2
;
79 CONFIG_PAGE_IOC_6
*ioc6
;
84 warnx("show adapter: extra arguments");
88 fd
= mpt_open(mpt_unit
);
95 man0
= mpt_read_man_page(fd
, 0, NULL
);
98 warn("Failed to get controller info");
101 if (man0
->Header
.PageLength
< sizeof(*man0
) / 4) {
102 warnx("Invalid controller info");
105 printf("mpt%d Adapter:\n", mpt_unit
);
106 printf(" Board Name: %.16s\n", man0
->BoardName
);
107 printf(" Board Assembly: %.16s\n", man0
->BoardAssembly
);
108 printf(" Chip Name: %.16s\n", man0
->ChipName
);
109 printf(" Chip Revision: %.16s\n", man0
->ChipRevision
);
113 ioc2
= mpt_read_ioc_page(fd
, 2, &IOCStatus
);
115 printf(" RAID Levels:");
117 if (ioc2
->CapabilitiesFlags
&
118 MPI_IOCPAGE2_CAP_FLAGS_IS_SUPPORT
) {
122 if (ioc2
->CapabilitiesFlags
&
123 MPI_IOCPAGE2_CAP_FLAGS_IM_SUPPORT
) {
124 printf("%s RAID1", comma
? "," : "");
127 if (ioc2
->CapabilitiesFlags
&
128 MPI_IOCPAGE2_CAP_FLAGS_IME_SUPPORT
) {
129 printf("%s RAID1E", comma
? "," : "");
132 if (ioc2
->CapabilitiesFlags
&
133 MPI_IOCPAGE2_CAP_FLAGS_RAID_5_SUPPORT
) {
134 printf("%s RAID5", comma
? "," : "");
137 if (ioc2
->CapabilitiesFlags
&
138 MPI_IOCPAGE2_CAP_FLAGS_RAID_6_SUPPORT
) {
139 printf("%s RAID6", comma
? "," : "");
142 if (ioc2
->CapabilitiesFlags
&
143 MPI_IOCPAGE2_CAP_FLAGS_RAID_10_SUPPORT
) {
144 printf("%s RAID10", comma
? "," : "");
147 if (ioc2
->CapabilitiesFlags
&
148 MPI_IOCPAGE2_CAP_FLAGS_RAID_50_SUPPORT
) {
149 printf("%s RAID50", comma
? "," : "");
156 } else if ((IOCStatus
& MPI_IOCSTATUS_MASK
) !=
157 MPI_IOCSTATUS_CONFIG_INVALID_PAGE
)
158 warnx("mpt_read_ioc_page(2): %s", mpt_ioc_status(IOCStatus
));
160 ioc6
= mpt_read_ioc_page(fd
, 6, &IOCStatus
);
162 display_stripe_map(" RAID0 Stripes",
163 ioc6
->SupportedStripeSizeMapIS
);
164 display_stripe_map(" RAID1E Stripes",
165 ioc6
->SupportedStripeSizeMapIME
);
166 printf(" RAID0 Drives/Vol: %u", ioc6
->MinDrivesIS
);
167 if (ioc6
->MinDrivesIS
!= ioc6
->MaxDrivesIS
)
168 printf("-%u", ioc6
->MaxDrivesIS
);
170 printf(" RAID1 Drives/Vol: %u", ioc6
->MinDrivesIM
);
171 if (ioc6
->MinDrivesIM
!= ioc6
->MaxDrivesIM
)
172 printf("-%u", ioc6
->MaxDrivesIM
);
174 printf("RAID1E Drives/Vol: %u", ioc6
->MinDrivesIME
);
175 if (ioc6
->MinDrivesIME
!= ioc6
->MaxDrivesIME
)
176 printf("-%u", ioc6
->MaxDrivesIME
);
179 } else if ((IOCStatus
& MPI_IOCSTATUS_MASK
) !=
180 MPI_IOCSTATUS_CONFIG_INVALID_PAGE
)
181 warnx("mpt_read_ioc_page(6): %s", mpt_ioc_status(IOCStatus
));
183 /* TODO: Add an ioctl to fetch IOC_FACTS and print firmware version. */
189 MPT_COMMAND(show
, adapter
, show_adapter
);
192 print_vol(CONFIG_PAGE_RAID_VOL_0
*info
, int state_len
)
195 const char *level
, *state
;
196 char buf
[6], stripe
[5];
198 size
= ((uint64_t)info
->MaxLBAHigh
<< 32) | info
->MaxLBA
;
199 humanize_number(buf
, sizeof(buf
), (size
+ 1) * 512, "", HN_AUTOSCALE
,
200 HN_B
| HN_NOSPACE
| HN_DECIMAL
);
201 if (info
->VolumeType
== MPI_RAID_VOL_TYPE_IM
)
204 format_stripe(stripe
, sizeof(stripe
), info
->StripeSize
);
205 level
= mpt_raid_level(info
->VolumeType
);
206 state
= mpt_volstate(info
->VolumeStatus
.State
);
208 printf("(%6s) %-8s %6s %-*s", buf
, level
, stripe
, state_len
,
210 else if (stripe
[0] != '\0')
211 printf("(%s) %s %s %s", buf
, level
, stripe
, state
);
213 printf("(%s) %s %s", buf
, level
, state
);
217 print_pd(CONFIG_PAGE_RAID_PHYS_DISK_0
*info
, int state_len
, int location
)
219 const char *inq
, *state
;
222 humanize_number(buf
, sizeof(buf
), ((uint64_t)info
->MaxLBA
+ 1) * 512,
223 "", HN_AUTOSCALE
, HN_B
| HN_NOSPACE
|HN_DECIMAL
);
224 state
= mpt_pdstate(info
);
226 printf("(%6s) %-*s", buf
, state_len
, state
);
228 printf("(%s) %s", buf
, state
);
229 inq
= mpt_pd_inq_string(info
);
234 printf(" bus %d id %d", info
->PhysDiskBus
, info
->PhysDiskID
);
238 print_standalone(struct mpt_standalone_disk
*disk
, int state_len
, int location
)
242 humanize_number(buf
, sizeof(buf
), (disk
->maxlba
+ 1) * 512,
243 "", HN_AUTOSCALE
, HN_B
| HN_NOSPACE
|HN_DECIMAL
);
245 printf("(%6s) %-*s", buf
, state_len
, STANDALONE_STATE
);
247 printf("(%s) %s", buf
, STANDALONE_STATE
);
248 if (disk
->inqstring
[0] != '\0')
249 printf(" %s", disk
->inqstring
);
252 printf(" bus %d id %d", disk
->bus
, disk
->target
);
256 print_spare_pools(U8 HotSparePool
)
260 if (HotSparePool
== 0) {
264 for (i
= 0; HotSparePool
!= 0; i
++) {
265 if (HotSparePool
& 1) {
267 if (HotSparePool
== 1)
276 show_config(int ac
, char **av __unused
)
278 CONFIG_PAGE_IOC_2
*ioc2
;
279 CONFIG_PAGE_IOC_2_RAID_VOL
*vol
;
280 CONFIG_PAGE_IOC_5
*ioc5
;
281 IOC_5_HOT_SPARE
*spare
;
282 CONFIG_PAGE_RAID_VOL_0
*vinfo
;
283 RAID_VOL0_PHYS_DISK
*disk
;
284 CONFIG_PAGE_RAID_VOL_1
*vnames
;
285 CONFIG_PAGE_RAID_PHYS_DISK_0
*pinfo
;
286 struct mpt_standalone_disk
*sdisks
;
287 int error
, fd
, i
, j
, nsdisks
;
290 warnx("show config: extra arguments");
294 fd
= mpt_open(mpt_unit
);
301 /* Get the config from the controller. */
302 ioc2
= mpt_read_ioc_page(fd
, 2, NULL
);
303 ioc5
= mpt_read_ioc_page(fd
, 5, NULL
);
304 if (ioc2
== NULL
|| ioc5
== NULL
) {
306 warn("Failed to get config");
309 if (mpt_fetch_disks(fd
, &nsdisks
, &sdisks
) < 0) {
311 warn("Failed to get standalone drive list");
315 /* Dump out the configuration. */
316 printf("mpt%d Configuration: %d volumes, %d drives\n",
317 mpt_unit
, ioc2
->NumActiveVolumes
, ioc2
->NumActivePhysDisks
+
319 vol
= ioc2
->RaidVolume
;
320 for (i
= 0; i
< ioc2
->NumActiveVolumes
; vol
++, i
++) {
321 printf(" volume %s ", mpt_volume_name(vol
->VolumeBus
,
323 vinfo
= mpt_vol_info(fd
, vol
->VolumeBus
, vol
->VolumeID
, NULL
);
325 printf("%s UNKNOWN", mpt_raid_level(vol
->VolumeType
));
327 print_vol(vinfo
, -1);
328 vnames
= mpt_vol_names(fd
, vol
->VolumeBus
, vol
->VolumeID
, NULL
);
329 if (vnames
!= NULL
) {
330 if (vnames
->Name
[0] != '\0')
331 printf(" <%s>", vnames
->Name
);
339 disk
= vinfo
->PhysDisk
;
340 for (j
= 0; j
< vinfo
->NumPhysDisks
; disk
++, j
++) {
341 printf(" drive %u ", disk
->PhysDiskNum
);
342 pinfo
= mpt_pd_info(fd
, disk
->PhysDiskNum
, NULL
);
344 print_pd(pinfo
, -1, 0);
349 if (vinfo
->VolumeSettings
.HotSparePool
!= 0) {
350 printf(" spare pools: ");
351 print_spare_pools(vinfo
->VolumeSettings
.HotSparePool
);
357 spare
= ioc5
->HotSpare
;
358 for (i
= 0; i
< ioc5
->NumHotSpares
; spare
++, i
++) {
359 printf(" spare %u ", spare
->PhysDiskNum
);
360 pinfo
= mpt_pd_info(fd
, spare
->PhysDiskNum
, NULL
);
362 print_pd(pinfo
, -1, 0);
365 printf(" backs pool %d\n", ffs(spare
->HotSparePool
) - 1);
367 for (i
= 0; i
< nsdisks
; i
++) {
368 printf(" drive %s ", sdisks
[i
].devname
);
369 print_standalone(&sdisks
[i
], -1, 0);
379 MPT_COMMAND(show
, config
, show_config
);
382 show_volumes(int ac
, char **av __unused
)
384 CONFIG_PAGE_IOC_2
*ioc2
;
385 CONFIG_PAGE_IOC_2_RAID_VOL
*vol
;
386 CONFIG_PAGE_RAID_VOL_0
**volumes
;
387 CONFIG_PAGE_RAID_VOL_1
*vnames
;
388 int error
, fd
, i
, len
, state_len
;
391 warnx("show volumes: extra arguments");
395 fd
= mpt_open(mpt_unit
);
402 /* Get the volume list from the controller. */
403 ioc2
= mpt_read_ioc_page(fd
, 2, NULL
);
406 warn("Failed to get volume list");
411 * Go ahead and read the info for all the volumes and figure
412 * out the maximum width of the state field.
414 volumes
= malloc(sizeof(*volumes
) * ioc2
->NumActiveVolumes
);
415 state_len
= strlen("State");
416 vol
= ioc2
->RaidVolume
;
417 for (i
= 0; i
< ioc2
->NumActiveVolumes
; vol
++, i
++) {
418 volumes
[i
] = mpt_vol_info(fd
, vol
->VolumeBus
, vol
->VolumeID
,
420 if (volumes
[i
] == NULL
)
421 len
= strlen("UNKNOWN");
423 len
= strlen(mpt_volstate(
424 volumes
[i
]->VolumeStatus
.State
));
428 printf("mpt%d Volumes:\n", mpt_unit
);
429 printf(" Id Size Level Stripe ");
430 len
= state_len
- strlen("State");
431 for (i
= 0; i
< (len
+ 1) / 2; i
++)
434 for (i
= 0; i
< len
/ 2; i
++)
436 printf(" Write-Cache Name\n");
437 vol
= ioc2
->RaidVolume
;
438 for (i
= 0; i
< ioc2
->NumActiveVolumes
; vol
++, i
++) {
439 printf("%6s ", mpt_volume_name(vol
->VolumeBus
, vol
->VolumeID
));
440 if (volumes
[i
] != NULL
)
441 print_vol(volumes
[i
], state_len
);
444 mpt_raid_level(vol
->VolumeType
), state_len
,
446 if (volumes
[i
] != NULL
) {
447 if (volumes
[i
]->VolumeSettings
.Settings
&
448 MPI_RAIDVOL0_SETTING_WRITE_CACHING_ENABLE
)
451 printf(" Disabled ");
455 vnames
= mpt_vol_names(fd
, vol
->VolumeBus
, vol
->VolumeID
, NULL
);
456 if (vnames
!= NULL
) {
457 if (vnames
->Name
[0] != '\0')
458 printf(" <%s>", vnames
->Name
);
468 MPT_COMMAND(show
, volumes
, show_volumes
);
471 show_drives(int ac
, char **av __unused
)
473 struct mpt_drive_list
*list
;
474 struct mpt_standalone_disk
*sdisks
;
475 int error
, fd
, i
, len
, nsdisks
, state_len
;
478 warnx("show drives: extra arguments");
482 fd
= mpt_open(mpt_unit
);
489 /* Get the drive list. */
490 list
= mpt_pd_list(fd
);
493 warn("Failed to get drive list");
497 /* Fetch the list of standalone disks for this controller. */
499 if (mpt_fetch_disks(fd
, &nsdisks
, &sdisks
) != 0) {
504 state_len
= strlen(STANDALONE_STATE
);
506 /* Walk the drive list to determine width of state column. */
507 for (i
= 0; i
< list
->ndrives
; i
++) {
508 len
= strlen(mpt_pdstate(list
->drives
[i
]));
513 /* List the drives. */
514 printf("mpt%d Physical Drives:\n", mpt_unit
);
515 for (i
= 0; i
< list
->ndrives
; i
++) {
516 printf("%4u ", list
->drives
[i
]->PhysDiskNum
);
517 print_pd(list
->drives
[i
], state_len
, 1);
520 mpt_free_pd_list(list
);
521 for (i
= 0; i
< nsdisks
; i
++) {
522 printf("%4s ", sdisks
[i
].devname
);
523 print_standalone(&sdisks
[i
], state_len
, 1);
532 MPT_COMMAND(show
, drives
, show_drives
);
536 show_physdisks(int ac
, char **av
)
538 CONFIG_PAGE_RAID_PHYS_DISK_0
*pinfo
;
543 warnx("show drives: extra arguments");
547 fd
= mpt_open(mpt_unit
);
554 /* Try to find each possible phys disk page. */
555 for (i
= 0; i
<= 0xff; i
++) {
556 pinfo
= mpt_pd_info(fd
, i
, &IOCStatus
);
558 if ((IOCStatus
& MPI_IOCSTATUS_MASK
) !=
559 MPI_IOCSTATUS_CONFIG_INVALID_PAGE
)
560 warnx("mpt_pd_info(%d): %s", i
,
561 mpt_ioc_status(IOCStatus
));
565 print_pd(pinfo
, -1, 1);
573 MPT_COMMAND(show
, pd
, show_physdisks
);