]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/mfiutil/mfi_show.c
THIS BRANCH IS OBSOLETE, PLEASE READ:
[FreeBSD/FreeBSD.git] / usr.sbin / mfiutil / mfi_show.c
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$
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
45 static const char* foreign_state = " (FOREIGN)";
46
47 MFI_TABLE(top, show);
48
49 void
50 format_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
57 static int
58 show_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 }
140 MFI_COMMAND(show, adapter, show_adapter);
141
142 static int
143 show_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 }
296 MFI_COMMAND(show, battery, show_battery);
297
298 void
299 print_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
319 void
320 print_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
342 static int
343 show_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 }
446 MFI_COMMAND(show, config, show_config);
447
448 static int
449 show_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 }
529 MFI_COMMAND(show, volumes, show_volumes);
530
531 static int
532 show_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;
603 error:
604         free(list);
605         close(fd);
606
607         return (error);
608 }
609 MFI_COMMAND(show, drives, show_drives);
610
611 static int
612 show_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 }
665 MFI_COMMAND(show, firmware, show_firmware);
666
667 static int
668 show_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 }
783 MFI_COMMAND(show, progress, show_progress);
784
785 static int
786 show_foreign(int ac, char **av)
787 {
788         return(display_format(ac, av, 0/*normal display*/, MFI_DCMD_CFG_FOREIGN_DISPLAY));
789 }
790 MFI_COMMAND(show, foreign, show_foreign);