]> CyberLeo.Net >> Repos - FreeBSD/releng/8.2.git/blob - usr.sbin/mfiutil/mfi_show.c
MFC r213265:
[FreeBSD/releng/8.2.git] / usr.sbin / mfiutil / mfi_show.c
1 /*-
2  * Copyright (c) 2008, 2009 Yahoo!, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. The names of the authors may not be used to endorse or promote
14  *    products derived from this software without specific prior written
15  *    permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31
32 #include <sys/types.h>
33 #include <sys/errno.h>
34 #include <err.h>
35 #include <libutil.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 #include "mfiutil.h"
41
42 MFI_TABLE(top, show);
43
44 static void
45 format_stripe(char *buf, size_t buflen, uint8_t stripe)
46 {
47
48         humanize_number(buf, buflen, (1 << stripe) * 512, "", HN_AUTOSCALE,  
49             HN_B | HN_NOSPACE);
50 }
51
52 static int
53 show_adapter(int ac, char **av)
54 {
55         struct mfi_ctrl_info info;
56         char stripe[5];
57         int error, fd, comma;
58
59         if (ac != 1) {
60                 warnx("show adapter: extra arguments");
61                 return (EINVAL);
62         }
63
64         fd = mfi_open(mfi_unit);
65         if (fd < 0) {
66                 error = errno;
67                 warn("mfi_open");
68                 return (error);
69         }
70
71         if (mfi_ctrl_get_info(fd, &info, NULL) < 0) {
72                 error = errno;
73                 warn("Failed to get controller info");
74                 return (error);
75         }
76         printf("mfi%d Adapter:\n", mfi_unit);
77         printf("    Product Name: %.80s\n", info.product_name);
78         printf("   Serial Number: %.32s\n", info.serial_number);
79         if (info.package_version[0] != '\0')
80                 printf("        Firmware: %s\n", info.package_version);
81         printf("     RAID Levels:");
82 #ifdef DEBUG
83         printf(" (%#x)", info.raid_levels);
84 #endif
85         comma = 0;
86         if (info.raid_levels & MFI_INFO_RAID_0) {
87                 printf(" JBOD, RAID0");
88                 comma = 1;
89         }
90         if (info.raid_levels & MFI_INFO_RAID_1) {
91                 printf("%s RAID1", comma ? "," : "");
92                 comma = 1;
93         }
94         if (info.raid_levels & MFI_INFO_RAID_5) {
95                 printf("%s RAID5", comma ? "," : "");
96                 comma = 1;
97         }
98         if (info.raid_levels & MFI_INFO_RAID_1E) {
99                 printf("%s RAID1E", comma ? "," : "");
100                 comma = 1;
101         }
102         if (info.raid_levels & MFI_INFO_RAID_6) {
103                 printf("%s RAID6", comma ? "," : "");
104                 comma = 1;
105         }
106         if ((info.raid_levels & (MFI_INFO_RAID_0 | MFI_INFO_RAID_1)) ==
107             (MFI_INFO_RAID_0 | MFI_INFO_RAID_1)) {
108                 printf("%s RAID10", comma ? "," : "");
109                 comma = 1;
110         }
111         if ((info.raid_levels & (MFI_INFO_RAID_0 | MFI_INFO_RAID_5)) ==
112             (MFI_INFO_RAID_0 | MFI_INFO_RAID_5)) {
113                 printf("%s RAID50", comma ? "," : "");
114                 comma = 1;
115         }
116         printf("\n");
117         printf("  Battery Backup: ");
118         if (info.hw_present & MFI_INFO_HW_BBU)
119                 printf("present\n");
120         else
121                 printf("not present\n");
122         if (info.hw_present & MFI_INFO_HW_NVRAM)
123                 printf("           NVRAM: %uK\n", info.nvram_size);
124         printf("  Onboard Memory: %uM\n", info.memory_size);
125         format_stripe(stripe, sizeof(stripe), info.stripe_sz_ops.min);
126         printf("  Minimum Stripe: %s\n", stripe);
127         format_stripe(stripe, sizeof(stripe), info.stripe_sz_ops.max);
128         printf("  Maximum Stripe: %s\n", stripe);
129
130         close(fd);
131
132         return (0);
133 }
134 MFI_COMMAND(show, adapter, show_adapter);
135
136 static int
137 show_battery(int ac, char **av)
138 {
139         struct mfi_bbu_capacity_info cap;
140         struct mfi_bbu_design_info design;
141         uint8_t status;
142         int error, fd;
143
144         if (ac != 1) {
145                 warnx("show battery: extra arguments");
146                 return (EINVAL);
147         }
148
149         fd = mfi_open(mfi_unit);
150         if (fd < 0) {
151                 error = errno;
152                 warn("mfi_open");
153                 return (error);
154         }
155
156         if (mfi_dcmd_command(fd, MFI_DCMD_BBU_GET_CAPACITY_INFO, &cap,
157             sizeof(cap), NULL, 0, &status) < 0) {
158                 if (status == MFI_STAT_NO_HW_PRESENT) {
159                         printf("mfi%d: No battery present\n", mfi_unit);
160                         return (0);
161                 }
162                 error = errno;
163                 warn("Failed to get capacity info");
164                 return (error);
165         }
166
167         if (mfi_dcmd_command(fd, MFI_DCMD_BBU_GET_DESIGN_INFO, &design,
168             sizeof(design), NULL, 0, NULL) < 0) {
169                 error = errno;
170                 warn("Failed to get design info");
171                 return (error);
172         }
173
174         printf("mfi%d: Battery State:\n", mfi_unit);
175         printf(" Manufacture Date: %d/%d/%d\n", design.mfg_date >> 5 & 0x0f,
176             design.mfg_date & 0x1f, design.mfg_date >> 9 & 0xffff);
177         printf("    Serial Number: %d\n", design.serial_number);
178         printf("     Manufacturer: %s\n", design.mfg_name);
179         printf("            Model: %s\n", design.device_name);
180         printf("        Chemistry: %s\n", design.device_chemistry);
181         printf("  Design Capacity: %d mAh\n", design.design_capacity);
182         printf("   Design Voltage: %d mV\n", design.design_voltage);
183         printf("   Current Charge: %d%%\n", cap.relative_charge);
184
185         close(fd);
186
187         return (0);
188 }
189 MFI_COMMAND(show, battery, show_battery);
190
191 static void
192 print_ld(struct mfi_ld_info *info, int state_len)
193 {
194         struct mfi_ld_params *params = &info->ld_config.params;
195         const char *level;
196         char size[6], stripe[5];
197
198         humanize_number(size, sizeof(size), info->size * 512,
199             "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
200         format_stripe(stripe, sizeof(stripe),
201             info->ld_config.params.stripe_size);
202         level = mfi_raid_level(params->primary_raid_level,
203             params->secondary_raid_level);
204         if (state_len > 0)
205                 printf("(%6s) %-8s %6s %-*s", size, level, stripe, state_len,
206                     mfi_ldstate(params->state));
207         else
208                 printf("(%s) %s %s %s", size, level, stripe,
209                     mfi_ldstate(params->state));
210 }
211
212 static void
213 print_pd(struct mfi_pd_info *info, int state_len, int location)
214 {
215         const char *s;
216         char buf[6];
217
218         humanize_number(buf, sizeof(buf), info->raw_size * 512, "",
219             HN_AUTOSCALE, HN_B | HN_NOSPACE |HN_DECIMAL);
220         printf("(%6s) ", buf);
221         if (state_len > 0)
222                 printf("%-*s", state_len, mfi_pdstate(info->fw_state));
223         else
224                 printf("%s", mfi_pdstate(info->fw_state));
225         s = mfi_pd_inq_string(info);
226         if (s != NULL)
227                 printf(" %s", s);
228         if (!location)
229                 return;
230         if (info->encl_device_id == 0xffff)
231                 printf(" slot %d", info->slot_number);
232         else if (info->encl_device_id == info->ref.v.device_id)
233                 printf(" enclosure %d", info->encl_index);
234         else
235                 printf(" enclosure %d, slot %d", info->encl_index,
236                     info->slot_number);
237 }
238
239 static int
240 show_config(int ac, char **av)
241 {
242         struct mfi_config_data *config;
243         struct mfi_array *ar;
244         struct mfi_ld_config *ld;
245         struct mfi_spare *sp;
246         struct mfi_ld_info linfo;
247         struct mfi_pd_info pinfo;
248         uint16_t device_id;
249         char *p;
250         int error, fd, i, j;
251
252         if (ac != 1) {
253                 warnx("show config: extra arguments");
254                 return (EINVAL);
255         }
256
257         fd = mfi_open(mfi_unit);
258         if (fd < 0) {
259                 error = errno;
260                 warn("mfi_open");
261                 return (error);
262         }
263
264         /* Get the config from the controller. */
265         if (mfi_config_read(fd, &config) < 0) {
266                 error = errno;
267                 warn("Failed to get config");
268                 return (error);
269         }
270
271         /* Dump out the configuration. */
272         printf("mfi%d Configuration: %d arrays, %d volumes, %d spares\n",
273             mfi_unit, config->array_count, config->log_drv_count,
274             config->spares_count);
275         p = (char *)config->array;
276
277         for (i = 0; i < config->array_count; i++) {
278                 ar = (struct mfi_array *)p;
279                 printf("    array %u of %u drives:\n", ar->array_ref,
280                     ar->num_drives);
281                 for (j = 0; j < ar->num_drives; j++) {
282                         device_id = ar->pd[j].ref.v.device_id;
283                         if (device_id == 0xffff)
284                                 printf("        drive MISSING\n");
285                         else {
286                                 printf("        drive %u ", device_id);
287                                 if (mfi_pd_get_info(fd, device_id, &pinfo,
288                                     NULL) < 0)
289                                         printf("%s",
290                                             mfi_pdstate(ar->pd[j].fw_state));
291                                 else
292                                         print_pd(&pinfo, -1, 1);
293                                 printf("\n");
294                         }
295                 }
296                 p += config->array_size;
297         }
298
299         for (i = 0; i < config->log_drv_count; i++) {
300                 ld = (struct mfi_ld_config *)p;
301                 printf("    volume %s ",
302                     mfi_volume_name(fd, ld->properties.ld.v.target_id));
303                 if (mfi_ld_get_info(fd, ld->properties.ld.v.target_id, &linfo,
304                     NULL) < 0) {
305                         printf("%s %s",
306                             mfi_raid_level(ld->params.primary_raid_level,
307                                 ld->params.secondary_raid_level),
308                             mfi_ldstate(ld->params.state));
309                 } else
310                         print_ld(&linfo, -1);
311                 if (ld->properties.name[0] != '\0')
312                         printf(" <%s>", ld->properties.name);
313                 printf(" spans:\n");
314                 for (j = 0; j < ld->params.span_depth; j++)
315                         printf("        array %u\n", ld->span[j].array_ref);
316                 p += config->log_drv_size;
317         }
318
319         for (i = 0; i < config->spares_count; i++) {
320                 sp = (struct mfi_spare *)p;
321                 printf("    %s spare %u ",
322                     sp->spare_type & MFI_SPARE_DEDICATED ? "dedicated" :
323                     "global", sp->ref.v.device_id);
324                 if (mfi_pd_get_info(fd, sp->ref.v.device_id, &pinfo, NULL) < 0)
325                         printf("%s", mfi_pdstate(MFI_PD_STATE_HOT_SPARE));
326                 else
327                         print_pd(&pinfo, -1, 1);
328                 if (sp->spare_type & MFI_SPARE_DEDICATED) {
329                         printf(" backs:\n");
330                         for (j = 0; j < sp->array_count; j++)
331                                 printf("        array %u\n", sp->array_ref[j]);
332                 } else
333                         printf("\n");
334                 p += config->spares_size;
335         }
336         close(fd);
337
338         return (0);
339 }
340 MFI_COMMAND(show, config, show_config);
341
342 static int
343 show_volumes(int ac, char **av)
344 {
345         struct mfi_ld_list list;
346         struct mfi_ld_info info;
347         int error, fd;
348         u_int i, len, state_len;
349
350         if (ac != 1) {
351                 warnx("show volumes: extra arguments");
352                 return (EINVAL);
353         }
354
355         fd = mfi_open(mfi_unit);
356         if (fd < 0) {
357                 error = errno;
358                 warn("mfi_open");
359                 return (error);
360         }
361
362         /* Get the logical drive list from the controller. */
363         if (mfi_ld_get_list(fd, &list, NULL) < 0) {
364                 error = errno;
365                 warn("Failed to get volume list");
366                 return (error);
367         }
368
369         /* List the volumes. */
370         printf("mfi%d Volumes:\n", mfi_unit);
371         state_len = strlen("State");
372         for (i = 0; i < list.ld_count; i++) {
373                 len = strlen(mfi_ldstate(list.ld_list[i].state));
374                 if (len > state_len)
375                         state_len = len;
376         }
377         printf("  Id     Size    Level   Stripe ");
378         len = state_len - strlen("State");
379         for (i = 0; i < (len + 1) / 2; i++)
380                 printf(" ");
381         printf("State");
382         for (i = 0; i < len / 2; i++)
383                 printf(" ");
384         printf("  Cache   Name\n");
385         for (i = 0; i < list.ld_count; i++) {
386                 if (mfi_ld_get_info(fd, list.ld_list[i].ld.v.target_id, &info,
387                     NULL) < 0) {
388                         error = errno;
389                         warn("Failed to get info for volume %d",
390                             list.ld_list[i].ld.v.target_id);
391                         return (error);
392                 }
393                 printf("%6s ",
394                     mfi_volume_name(fd, list.ld_list[i].ld.v.target_id));
395                 print_ld(&info, state_len);
396                 switch (info.ld_config.properties.current_cache_policy &
397                     (MR_LD_CACHE_ALLOW_WRITE_CACHE |
398                     MR_LD_CACHE_ALLOW_READ_CACHE)) {
399                 case 0:
400                         printf(" Disabled");
401                         break;
402                 case MR_LD_CACHE_ALLOW_READ_CACHE:
403                         printf(" Reads   ");
404                         break;
405                 case MR_LD_CACHE_ALLOW_WRITE_CACHE:
406                         printf(" Writes  ");
407                         break;
408                 case MR_LD_CACHE_ALLOW_WRITE_CACHE |
409                     MR_LD_CACHE_ALLOW_READ_CACHE:
410                         printf(" Enabled ");
411                         break;
412                 }
413                 if (info.ld_config.properties.name[0] != '\0')
414                         printf(" <%s>", info.ld_config.properties.name);
415                 printf("\n");
416         }
417         close(fd);
418
419         return (0);
420 }
421 MFI_COMMAND(show, volumes, show_volumes);
422
423 static int
424 show_drives(int ac, char **av)
425 {
426         struct mfi_pd_list *list;
427         struct mfi_pd_info info;
428         u_int i, len, state_len;
429         int error, fd;
430
431         if (ac != 1) {
432                 warnx("show drives: extra arguments");
433                 return (EINVAL);
434         }
435
436         fd = mfi_open(mfi_unit);
437         if (fd < 0) {
438                 error = errno;
439                 warn("mfi_open");
440                 return (error);
441         }
442
443         if (mfi_pd_get_list(fd, &list, NULL) < 0) {
444                 error = errno;
445                 warn("Failed to get drive list");
446                 return (error);
447         }
448
449         /* Walk the list of drives to determine width of state column. */
450         state_len = 0;
451         for (i = 0; i < list->count; i++) {
452                 if (list->addr[i].scsi_dev_type != 0)
453                         continue;
454
455                 if (mfi_pd_get_info(fd, list->addr[i].device_id, &info,
456                     NULL) < 0) {
457                         error = errno;
458                         warn("Failed to fetch info for drive %u",
459                             list->addr[i].device_id);
460                         return (error);
461                 }
462                 len = strlen(mfi_pdstate(info.fw_state));
463                 if (len > state_len)
464                         state_len = len;
465         }
466
467         /* List the drives. */
468         printf("mfi%d Physical Drives:\n", mfi_unit);
469         for (i = 0; i < list->count; i++) {
470
471                 /* Skip non-hard disks. */
472                 if (list->addr[i].scsi_dev_type != 0)
473                         continue;
474
475                 /* Fetch details for this drive. */
476                 if (mfi_pd_get_info(fd, list->addr[i].device_id, &info,
477                     NULL) < 0) {
478                         error = errno;
479                         warn("Failed to fetch info for drive %u",
480                             list->addr[i].device_id);
481                         return (error);
482                 }
483
484                 print_pd(&info, state_len, 1);
485                 printf("\n");
486         }
487         close(fd);
488
489         return (0);
490 }
491 MFI_COMMAND(show, drives, show_drives);
492
493 int fw_name_width, fw_version_width, fw_date_width, fw_time_width;
494
495 static void
496 scan_firmware(struct mfi_info_component *comp)
497 {
498         int len;
499
500         len = strlen(comp->name);
501         if (fw_name_width < len)
502                 fw_name_width = len;
503         len = strlen(comp->version);
504         if (fw_version_width < len)
505                 fw_version_width = len;
506         len = strlen(comp->build_date);
507         if (fw_date_width < len)
508                 fw_date_width = len;
509         len = strlen(comp->build_time);
510         if (fw_time_width < len)
511                 fw_time_width = len;
512 }
513
514 static void
515 display_firmware(struct mfi_info_component *comp, const char *tag)
516 {
517
518         printf("%-*s  %-*s  %-*s  %-*s  %s\n", fw_name_width, comp->name,
519             fw_version_width, comp->version, fw_date_width, comp->build_date,
520             fw_time_width, comp->build_time, tag);
521 }
522
523 static int
524 show_firmware(int ac, char **av)
525 {
526         struct mfi_ctrl_info info;
527         struct mfi_info_component header;
528         int error, fd;
529         u_int i;
530
531         if (ac != 1) {
532                 warnx("show drives: extra arguments");
533                 return (EINVAL);
534         }
535
536         fd = mfi_open(mfi_unit);
537         if (fd < 0) {
538                 error = errno;
539                 warn("mfi_open");
540                 return (error);
541         }
542
543         if (mfi_ctrl_get_info(fd, &info, NULL) < 0) {
544                 error = errno;
545                 warn("Failed to get controller info");
546                 return (error);
547         }
548
549         if (info.package_version[0] != '\0')
550                 printf("mfi%d Firmware Package Version: %s\n", mfi_unit,
551                     info.package_version);
552         printf("mfi%d Firmware Images:\n", mfi_unit);
553         strcpy(header.name, "Name");
554         strcpy(header.version, "Version");
555         strcpy(header.build_date, "Date");
556         strcpy(header.build_time, "Time");
557         scan_firmware(&header);
558         if (info.image_component_count > 8)
559                 info.image_component_count = 8;
560         for (i = 0; i < info.image_component_count; i++)
561                 scan_firmware(&info.image_component[i]);
562         if (info.pending_image_component_count > 8)
563                 info.pending_image_component_count = 8;
564         for (i = 0; i < info.pending_image_component_count; i++)
565                 scan_firmware(&info.pending_image_component[i]);
566         display_firmware(&header, "Status");
567         for (i = 0; i < info.image_component_count; i++)
568                 display_firmware(&info.image_component[i], "active");
569         for (i = 0; i < info.pending_image_component_count; i++)
570                 display_firmware(&info.pending_image_component[i], "pending");
571
572         close(fd);
573
574         return (0);
575 }
576 MFI_COMMAND(show, firmware, show_firmware);