diff options
| author | jc156560 <none@none> | 2007-01-21 16:17:27 -0800 |
|---|---|---|
| committer | jc156560 <none@none> | 2007-01-21 16:17:27 -0800 |
| commit | 711890bc9379ceea66272dc8d4981812224ea86e (patch) | |
| tree | b1e518a5474da8ddcbedad3919bf88a2f8f4f567 /usr/src/cmd/raidctl | |
| parent | c7a40cc4a9ca339dad64780ebf91c8ca8a28715a (diff) | |
| download | illumos-joyent-711890bc9379ceea66272dc8d4981812224ea86e.tar.gz | |
PSARC 2005/204 RaidCfg project
PSARC 2006/663 RaidCfg mpt adjustment
6508590 raidctl utility should use the pass_thru interface for mpt support
Diffstat (limited to 'usr/src/cmd/raidctl')
| -rw-r--r-- | usr/src/cmd/raidctl/Makefile | 11 | ||||
| -rw-r--r-- | usr/src/cmd/raidctl/raidctl.c | 3982 |
2 files changed, 2523 insertions, 1470 deletions
diff --git a/usr/src/cmd/raidctl/Makefile b/usr/src/cmd/raidctl/Makefile index 1ff5118c4f..3dbd866b23 100644 --- a/usr/src/cmd/raidctl/Makefile +++ b/usr/src/cmd/raidctl/Makefile @@ -2,9 +2,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. @@ -19,8 +18,7 @@ # # CDDL HEADER END # -# -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -32,9 +30,8 @@ PROG= raidctl include $(SRC)/cmd/Makefile.cmd -LDLIBS += -lcfgadm +LDLIBS += -lraidcfg CFLAGS += $(CCVERBOSE) -CPPFLAGS += -I$(SRC)/uts/common .KEEP_STATE: diff --git a/usr/src/cmd/raidctl/raidctl.c b/usr/src/cmd/raidctl/raidctl.c index 15b657c3c5..fcec737124 100644 --- a/usr/src/cmd/raidctl/raidctl.c +++ b/usr/src/cmd/raidctl/raidctl.c @@ -17,1877 +17,2933 @@ * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END - */ -/* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * raidctl.c is the entry file of RAID configuration utility. */ #pragma ident "%Z%%M% %I% %E% SMI" #include <ctype.h> -#include <dirent.h> -#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> #include <fcntl.h> #include <langinfo.h> -#include <libintl.h> -#include <limits.h> +#include <regex.h> #include <locale.h> -#include <stdarg.h> +#include <libintl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <strings.h> -#include <sys/ddi.h> -#include <sys/mpt/mpi.h> -#include <sys/mpt/mpi_ioc.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <sys/pci.h> #include <unistd.h> -#include <sys/mnttab.h> -#include <sys/dkio.h> -#include <config_admin.h> -#include <sys/param.h> -#include <sys/raidioctl.h> - -/* - * list of controllers to list - * setup like this: - * [ctrl_num] [status] - * - * where status is: - * RAID Found, - * No RAID Found - * RAID not supported on this controller - * Invalid Controller - */ - -typedef enum { - RAID_FOUND = 0x0, - RAID_NOT_FOUND, - RAID_NOT_SUPPORTED, - RAID_INVALID_CTRL, - RAID_DONT_USE -} raidctl_errno_t; - -/* For no-mixup indexing of info_ctrl */ -#define INFO_CTRL 0 -#define INFO_STATUS 1 - -static int **info_ctrl = NULL; -/* Length of conrollers list */ -static int ctrl_nums = 0; +#include <errno.h> +#include <libgen.h> +#include <raidcfg.h> -#define DEVDIR "/dev/rdsk" +#define TRUE 1 +#define FALSE 0 -#define DO_HW_RAID_NOP -1 -#define DO_HW_RAID_INFO 0 -#define DO_HW_RAID_CREATE 1 -#define DO_HW_RAID_DELETE 2 -#define DO_HW_RAID_FLASH 3 +#ifndef TEXT_DOMAIN +#define TEXT_DOMAIN "SYS_TEST" +#endif -/* values to use for raid level in raidctl */ -#define RAID_STRIPE 0 -#define RAID_MIRROR 1 +/* + * Return value of command + */ +#define SUCCESS 0 +#define INVALID_ARG 1 +#define FAILURE 2 /* - * Error return codes + * Initial value of variables */ -#define SUCCESS 0 -#define INVALID_ARG 1 -#define FAILURE 2 +#define INIT_HANDLE_VALUE -3 +#define MAX64BIT 0xffffffffffffffffull +#define MAX32BIT 0xfffffffful /* - * FW Update Stuff + * Flag of set or unset HSP */ +#define HSP_SET 1 +#define HSP_UNSET 0 -/* signature and initial offset for PCI expansion rom images */ -#define PCIROM_SIG 0xaa55 /* offset 0h, length 2 bytes */ -#define PCIR_OFF 0x18 /* Pointer to PCI Data Structure */ - -/* offsets in PCI data structure header */ -#define PCIR_DEVID 0x6 /* PCI device id */ -#define PCIR_CODETYPE 0x14 /* type of code (intel/fcode) */ -#define PCIR_INDICATOR 0x15 /* "last image" indicator */ - -/* flags for image types */ -#define BIOS_IMAGE 0x1 -#define FCODE_IMAGE 0x2 -#define UNKNOWN_IMAGE 0x3 -#define LAST_IMAGE 0x80 -#define NOT_LAST_IMAGE 0 -#define PCI_IMAGE_UNIT_SIZE 512 - -/* ID's and offsets for MPT Firmware images */ -#define FW_ROM_ID 0x5aea /* bytes 4 & 5 of file */ -#define FW_ROM_OFFSET_CHIP_TYPE 0x22 /* (U16) */ -#define FW_ROM_OFFSET_VERSION 0x24 /* (U16) */ -#define FW_ROM_OFFSET_VERSION_NAME 0x44 /* (32 U8) */ - -/* ID's for supported chips */ -#define LSI_1030 0x30 -#define LSI_1064 0x50 -#define LSI_1068 0x54 -#define LSI_1064E 0x56 -#define LSI_1068E 0x58 - -/* Key to search for when looking for fcode version */ -#define FCODE_VERS_KEY1 0x12 -#define FCODE_VERS_KEY2 0x7 -#define BIOS_STR "LSI SCSI Host Adapter BIOS Driver: " - -/* get a word from a buffer (works with non-word aligned offsets) */ -#define gw(x) (((x)[0]) + (((x)[1]) << 8)) - -/* Number of disks currently supported, per RAID volume */ -#define N_DISKS 8 - -/* Maximum number of RAID volumes currently supported per HBA */ -#define N_RAIDVOLS 2 +/* + * Operate codes of command + */ +#define DO_HW_RAID_NOP -1 +#define DO_HW_RAID_HELP 0 +#define DO_HW_RAID_CREATEO 1 +#define DO_HW_RAID_CREATEN 2 +#define DO_HW_RAID_DELETE 3 +#define DO_HW_RAID_LIST 4 +#define DO_HW_RAID_FLASH 5 +#define DO_HW_RAID_HSP 6 +#define DO_HW_RAID_SET_ATTR 7 +#define DO_HW_RAID_SNAPSHOT 8 + +#define LOWER_H (1 << 0) +#define LOWER_C (1 << 1) +#define LOWER_D (1 << 2) +#define LOWER_L (1 << 3) +#define LOWER_R (1 << 4) +#define LOWER_Z (1 << 5) +#define LOWER_G (1 << 6) +#define LOWER_A (1 << 7) +#define LOWER_S (1 << 8) +#define LOWER_P (1 << 9) +#define LOWER_F (1 << 10) +#define UPPER_S (1 << 11) +#define UPPER_C (1 << 12) +#define UPPER_F (1 << 13) + +/* Add a ARRAY state (temporary) */ +#define ARRAY_STATE_SYNC 100 /* * Function and strings to properly localize our prompt. - * So for example in german it would ask (ja/nein) or (yes/no) in + * So for example in German it would ask (ja/nein) or (yes/no) in * english. */ +#ifndef SCHAR_MAX +#define SCHAR_MAX 10 +#endif + +#define RAIDCTL_LOCKF "/var/run/lockf_raidctl" + +/* Locale setting */ static int yes(void); -static char yeschr[SCHAR_MAX + 2]; -static char nochr[SCHAR_MAX +2]; +static int rpmatch(char *s); +static char *yesstr = NULL; +static char *nostr = NULL; +static char *yesexpr = NULL; + +static char *default_yesexpr = "^[yY]"; +static char *default_yesstr = "yes"; +static char *default_nostr = "no"; + +static regex_t re; + +#define SET_DEFAULT_STRS \ + regfree(&re); \ + free(yesexpr); \ + free(yesstr); \ + free(nostr); \ + yesexpr = default_yesexpr; \ + yesstr = default_yesstr; \ + nostr = default_nostr; + +#define FREE_STRS \ + if (yesexpr != default_yesexpr) \ + free(yesexpr); \ + if (yesstr != default_yesstr) \ + free(yesstr); \ + if (nostr != default_nostr) \ + free(nostr); + +/* program name */ +static char *prog_namep; -typedef struct raidlist { - raid_config_t raid_config[N_RAIDVOLS]; - int controller; - char devctl[MAXPATHLEN]; - struct raidlist *next; -} raidlist_t; -static raidlist_t *raids; +/* + * Functions declaration + */ +static void helpinfo(char *prog_namep); +static int do_create_cidl(char *raid_levelp, char *capacityp, char *disk_argp, + char *stripe_sizep, uint32_t f_flag, char **argv, uint32_t optind); +static int do_create_ctd(char *raid_levelp, char **disks_argpp, + uint32_t disks_num, uint32_t argindex, uint32_t f_flag); +static int do_list(char *disk_argp, char **argv, uint32_t optind, + uint8_t is_snapshot); +static int do_delete(uint32_t f_flag, char **argv, uint32_t optind); +static int do_flash(uint8_t f_flag, char *filep, char **ctls_argpp, + uint32_t index, uint32_t ctl_num); +static int do_set_hsp(char *a_argp, char *disk_argp, char **argv, + uint32_t optind); +static int do_set_array_attr(uint32_t f_flag, char *p_argp, char **argv, + uint32_t optind); +static int snapshot_raidsystem(uint8_t recursive, uint8_t indent, + uint8_t is_snapshot); +static int snapshot_ctl(raid_obj_handle_t ctl_handle, uint8_t recursive, + uint8_t indent, uint8_t is_snapshot); +static int snapshot_array(raid_obj_handle_t array_handle, + uint8_t indent, uint8_t is_sub, uint8_t is_snapshot); +static int snapshot_disk(uint32_t ctl_tag, raid_obj_handle_t disk_handle, + uint8_t indent, uint8_t is_snapshot); +static int print_ctl_table(raid_obj_handle_t ctl_handle); +static int print_array_table(raid_obj_handle_t ctl_handle, + raid_obj_handle_t array_handle); +static int print_disk_table(raid_obj_handle_t ctl_handle, + raid_obj_handle_t disk_handle); +static int print_ctl_attr(raidcfg_controller_t *attrp); +static int print_array_attr(raidcfg_array_t *attrp); +static int print_arraypart_attr(raidcfg_arraypart_t *attrp); +static int print_disk_attr(raid_obj_handle_t ctl_handle, + raid_obj_handle_t disk_handle, raidcfg_disk_t *attrp); +static void print_indent(uint8_t indent); +static int get_disk_handle_cidl(uint32_t ctl_tag, char *disks_argp, + int *comps_nump, raid_obj_handle_t **handlespp); +static int get_disk_handle_ctd(int disks_num, char **disks_argpp, + uint32_t *ctl_tagp, raid_obj_handle_t *disks_handlep); +static int get_ctl_tag(char *argp, uint32_t *ctl_tagp); +static int get_array_tag(char *argp, uint32_t *ctl_tagp, + array_tag_t *array_tagp); +static int get_disk_tag_ctd(char *argp, disk_tag_t *disk_tagp, + uint32_t *controller_id); +static int get_disk_tag_cidl(char *argp, disk_tag_t *disk_tagp); +static int calc_size(char *sizep, uint64_t *valp); +static int is_fully_numeric(char *strp); +static int size_to_string(uint64_t size, char *string, int len); +static int enter_raidctl_lock(int *fd); +static void exit_raidctl_lock(int fd); /* - * usage: raidctl - * usage: raidctl [-f] -c primary secondary - * usage: raidctl [-f] -c -r 1 primary secondary - * usage: raidctl [-f] -c -r 0 disk1 disk2 [disk3] ... - * usage: raidctl [-f] -d volume - * usage: raidctl [-f] -F image_file controller - * usage: raidctl -l [controller...] - * example: - * raidctl -c c1t1d0 c1t2d0 - * raidctl -c -r 0 c1t1d0 c1t2d0 c1t3d0 c1t4d0 - * raidctl -d c1t1d0 - * raidctl -F image 1 + * Entry function of raidctl command */ -static void -usage(char *prog_name) +int +main(int argc, char **argv) { - (void) fprintf(stderr, gettext("usage: %s\n"), prog_name); + /* operation index */ + int8_t findex = DO_HW_RAID_NOP; + + /* argument pointers */ + char *r_argp = NULL; + char *z_argp = NULL; + char *g_argp = NULL; + char *a_argp = NULL; + char *s_argp = NULL; + char *p_argp = NULL; + char *F_argp = NULL; + char *C_argp = NULL; - (void) fprintf(stderr, gettext("usage: %s [-f] -c primary secondary\n"), - prog_name); + /* + * operation flags. + */ + uint8_t r_flag = FALSE; + uint8_t f_flag = FALSE; + uint8_t action = FALSE; + uint64_t options = 0; - (void) fprintf(stderr, gettext("usage: %s [-f] -c -r 1 primary " - "secondary\n"), prog_name); + /* index and temporary variables */ + int ret; + int status; + char c = '\0'; - (void) fprintf(stderr, gettext("usage: %s [-f] -c -r 0 disk1 disk2 " - "[disk3] ...\n"), prog_name); + /* fd for the filelock */ + int fd; - (void) fprintf(stderr, gettext("usage: %s [-f] -d volume\n"), - prog_name); + if (enter_raidctl_lock(&fd) != SUCCESS) { + return (FAILURE); + } - (void) fprintf(stderr, - gettext("usage: %s [-f] -F image_file controller \n"), - prog_name); + (void) setlocale(LC_ALL, ""); + (void) textdomain(TEXT_DOMAIN); - (void) fprintf(stderr, gettext("usage: %s -l [controller...]\n"), - prog_name); + /* parse command line, and get program name */ + if ((prog_namep = strrchr(argv[0], '/')) == NULL) { + prog_namep = argv[0]; + } else { + prog_namep++; + } - (void) fprintf(stderr, gettext("example:\n")); - (void) fprintf(stderr, "%s -c c1t1d0 c1t2d0\n", prog_name); - (void) fprintf(stderr, "%s -c -r 0 c1t1d0 c1t2d0 " - "c1t3d0 c1t4d0\n", prog_name); - (void) fprintf(stderr, "%s -d c1t1d0\n", prog_name); - (void) fprintf(stderr, "%s -F image 1\n", prog_name); + /* close error option messages from getopt */ + opterr = 0; - exit(1); -} + /* get yes expression according to current locale */ + yesexpr = strdup(nl_langinfo(YESEXPR)); + yesstr = strdup(nl_langinfo(YESSTR)); + nostr = strdup(nl_langinfo(NOSTR)); + if (yesexpr == NULL || yesstr == NULL || nostr == NULL) { + return (FAILURE); + } -/* Make errno message more "user friendly" */ -static void -raidctl_error(char *str) -{ - switch (errno) { - case EINVAL: - (void) fprintf(stderr, gettext("Error: " - "invalid argument would be returned\n")); + /* + * If the was no expression or if there is a compile error + * use default yes expression. + */ + status = regcomp(&re, yesexpr, REG_EXTENDED | REG_NOSUB); + if ((*yesexpr == (char)NULL) || + (*yesstr == (char)NULL) || + (*nostr == (char)NULL) || + (status != 0)) { + SET_DEFAULT_STRS; + if (regcomp(&re, default_yesexpr, + REG_EXTENDED | REG_NOSUB) != 0) { + return (FALSE); + } + } + + while ((c = getopt(argc, argv, + "?hC:cdlF:r:z:g:a:s:p:fS")) != EOF) { + switch (c) { + case 'h': + case '?': + if (action == FALSE) { + findex = DO_HW_RAID_HELP; + action = TRUE; + options |= LOWER_H; + } else { + findex = DO_HW_RAID_NOP; + } + break; + case 'C': + if (action == FALSE) { + findex = DO_HW_RAID_CREATEN; + C_argp = optarg; + action = TRUE; + options |= UPPER_C; + } else { + findex = DO_HW_RAID_NOP; + } + break; + case 'c': + if (action == FALSE) { + findex = DO_HW_RAID_CREATEO; + action = TRUE; + options |= LOWER_C; + } else { + findex = DO_HW_RAID_NOP; + } + break; + case 'd': + if (action == FALSE) { + findex = DO_HW_RAID_DELETE; + action = TRUE; + options |= LOWER_D; + } else { + findex = DO_HW_RAID_NOP; + } + break; + case 'l': + if (action == FALSE) { + findex = DO_HW_RAID_LIST; + action = TRUE; + options |= LOWER_L; + } else { + findex = DO_HW_RAID_NOP; + } + break; + case 'F': + if (action == FALSE) { + findex = DO_HW_RAID_FLASH; + F_argp = optarg; + action = TRUE; + options |= UPPER_F; + } else { + findex = DO_HW_RAID_NOP; + } + break; + case 'a': + if (action == FALSE) { + findex = DO_HW_RAID_HSP; + a_argp = optarg; + action = TRUE; + options |= LOWER_A; + } else { + findex = DO_HW_RAID_NOP; + } + break; + case 'p': + if (action == FALSE) { + findex = DO_HW_RAID_SET_ATTR; + p_argp = optarg; + action = TRUE; + options |= LOWER_P; + } else { + findex = DO_HW_RAID_NOP; + } + break; + case 'r': + r_argp = optarg; + r_flag = TRUE; + options |= LOWER_R; + break; + case 'z': + z_argp = optarg; + options |= LOWER_Z; + break; + case 'g': + g_argp = optarg; + options |= LOWER_G; + break; + case 's': + s_argp = optarg; + options |= LOWER_S; + break; + case 'f': + f_flag = TRUE; + options |= LOWER_F; + break; + case 'S': + if (action == FALSE) { + findex = DO_HW_RAID_SNAPSHOT; + action = TRUE; + options |= UPPER_S; + } else { + findex = DO_HW_RAID_NOP; + } + break; + default: + (void) fprintf(stderr, + gettext("Invalid argument(s).\n")); + exit_raidctl_lock(fd); + FREE_STRS; + regfree(&re); + return (INVALID_ARG); + } + } + + /* parse options */ + switch (findex) { + case DO_HW_RAID_HELP: + if ((options & ~(LOWER_H)) != 0) { + ret = INVALID_ARG; + } else { + helpinfo(prog_namep); + ret = SUCCESS; + } break; - case EIO: - case EFAULT: - (void) fprintf(stderr, - gettext("Error: Device inaccessible.\n")); + case DO_HW_RAID_CREATEO: + if ((options & ~(LOWER_F | LOWER_C | LOWER_R)) != 0) { + ret = INVALID_ARG; + } else { + if (r_flag != FALSE && f_flag == FALSE) { + ret = do_create_ctd(r_argp, argv, argc - 4, + optind, f_flag); + } else if (r_flag == FALSE && f_flag == FALSE) { + ret = do_create_ctd(NULL, argv, argc - 2, + optind, f_flag); + } else if (r_flag != FALSE && f_flag != FALSE) { + ret = do_create_ctd(r_argp, argv, argc - 5, + optind, f_flag); + } else { + ret = do_create_ctd(NULL, argv, argc - 3, + optind, f_flag); + } + } + break; + case DO_HW_RAID_CREATEN: + if ((options & ~(LOWER_F | UPPER_C | LOWER_R | LOWER_Z | + LOWER_S)) != 0) { + ret = INVALID_ARG; + } else { + ret = do_create_cidl(r_argp, z_argp, C_argp, s_argp, + f_flag, argv, optind); + } + break; + case DO_HW_RAID_DELETE: + if ((options & ~(LOWER_F | LOWER_D)) != 0) { + ret = INVALID_ARG; + } else { + ret = do_delete(f_flag, argv, optind); + } + break; + case DO_HW_RAID_LIST: + if ((options & ~(LOWER_L | LOWER_G)) != 0) { + ret = INVALID_ARG; + } else { + ret = do_list(g_argp, argv, optind, FALSE); + } + break; + case DO_HW_RAID_SNAPSHOT: + if ((options & ~(UPPER_S | LOWER_G)) != 0) { + ret = INVALID_ARG; + } else { + ret = do_list(g_argp, argv, optind, TRUE); + } + break; + case DO_HW_RAID_FLASH: + if ((options & ~(LOWER_F | UPPER_F)) != 0) { + ret = INVALID_ARG; + } else { + if (f_flag == FALSE) { + ret = do_flash(f_flag, F_argp, argv, optind, + argc - 3); + } else { + ret = do_flash(f_flag, F_argp, argv, optind, + argc - 4); + } + } + break; + case DO_HW_RAID_HSP: + if ((options & ~(LOWER_A | LOWER_G)) != 0) { + ret = INVALID_ARG; + } else { + ret = do_set_hsp(a_argp, g_argp, argv, optind); + } break; - case ENOTTY: - (void) fprintf(stderr, gettext("Error: " - "Device does not support requested action.\n")); + case DO_HW_RAID_SET_ATTR: + if ((options & ~(LOWER_F | LOWER_P)) != 0) { + ret = INVALID_ARG; + } else { + ret = do_set_array_attr(f_flag, p_argp, argv, optind); + } + break; + case DO_HW_RAID_NOP: + if (argc == 1) { + ret = do_list(g_argp, argv, optind, FALSE); + } else { + ret = INVALID_ARG; + } break; default: - perror(str); + ret = INVALID_ARG; + break; } -} -static int -get_link_path(const char *thing, char *buf) -{ - if (readlink(thing, buf, MAXPATHLEN) < 0) - return (1); - return (0); + if (ret == INVALID_ARG) { + (void) fprintf(stderr, + gettext("Invalid argument(s).\n")); + } + exit_raidctl_lock(fd); + + FREE_STRS; + regfree(&re); + return (ret); } -static int -get_ctrl_devctl(char *ctrl, char *b) +/* + * helpinfo(prog_namep) + * This function prints help informations for usrs. + */ +static void +helpinfo(char *prog_namep) { - char devctl_buf[MAXPATHLEN]; - char *colon; + char quote = '"'; - (void) strlcpy(devctl_buf, ctrl, MAXPATHLEN); + (void) printf(gettext("%s [-f] -C %c<disks>%c [-r <raid_level>] " + "[-z <capacity>] [-s <stripe_size>] <controller>\n"), prog_namep, + quote, quote); - colon = strrchr(devctl_buf, ':'); - if (colon == NULL) - return (1); - - *colon = 0; - (void) snprintf(devctl_buf, MAXPATHLEN, "%s:devctl", devctl_buf); - (void) strlcpy(b, devctl_buf, MAXPATHLEN); - return (0); -} - -static int -get_devctl(char *disk, char *b) -{ - char buf1[MAXPATHLEN] = {0}; - char devctl_buf[MAXPATHLEN]; - char *slash; - char devname[32]; + (void) printf(gettext("%s [-f] -d <volume>\n"), prog_namep); - if (get_link_path(disk, buf1)) - return (1); + (void) printf(gettext("%s [-f] -F <filename> <controller1> " + "[<controller2> ...]\n"), prog_namep); - (void) strlcpy(devctl_buf, buf1, MAXPATHLEN); + (void) printf(gettext("%s [-f] -p %c<param>=<value>%c <volume>\n"), + prog_namep, quote, quote); - slash = strrchr(devctl_buf, '/'); - if (slash == NULL) - return (1); + (void) printf(gettext("%s [-f] -c [-r <raid_level>] <disk1> <disk2> " + "[<disk3> ...]\n"), prog_namep); - *slash = 0; - slash = strrchr(devctl_buf, '/'); - (void) strlcpy(devname, slash, 32); - *slash = 0; + (void) printf(gettext("%s [-l]\n"), prog_namep); - (void) snprintf(devctl_buf, MAXPATHLEN, "%s%s:devctl", - devctl_buf, devname); + (void) printf(gettext("%s -l -g <disk> <controller>\n"), prog_namep); - (void) strlcpy(b, devctl_buf, MAXPATHLEN); + (void) printf(gettext("%s -l <volume>\n"), prog_namep); - return (0); -} + (void) printf(gettext("%s -l <controller1> [<controller2> ...]\n"), + prog_namep); -raidlist_t * -already_there(int controller) -{ - raidlist_t *curr = raids; + (void) printf(gettext("%s -a {set | unset} -g <disk> " + "{<volume> | <controller>}\n"), prog_namep); - while (curr != NULL) { - if (curr->controller == controller) - return (curr); + (void) printf(gettext("%s -S [<volume> | <controller>]\n"), prog_namep); - curr = curr->next; - } + (void) printf(gettext("%s -S -g <disk> <controller>\n"), prog_namep); - return (NULL); + (void) printf(gettext("%s -h\n"), prog_namep); } /* - * Display those controllers where RAID volumes were not found + * do_create_cidl(raid_levelp, capacityp, disks_argp, stripe_sizep, + * f_flag, argv, optind) + * This function creates a new RAID volume with specified arguments, + * and returns result as SUCCESS, INVALID_ARG or FAILURE. + * The "c.id.l" is used to express single physical disk. 'c' expresses + * bus number, 'id' expresses target number, and 'l' expresses lun. + * The physical disks represented by c.id.l may be invisible to OS, which + * means physical disks attached to controllers are not accessible by + * OS directly. The disks should be organized as a logical volume, and + * the logical volume is exported to OS as a single unit. Some hardware + * RAID controllers also support physical disks accessed by OS directly, + * for example LSI1068. In this case, it's both OK to express physical + * disk by c.id.l format or canonical ctd format. */ -static void -print_no_raids() +static int +do_create_cidl(char *raid_levelp, char *capacityp, char *disks_argp, + char *stripe_sizep, uint32_t f_flag, char **argv, uint32_t optind) { - int i, space = 0; - - if (info_ctrl == NULL) - return; - - for (i = 0; i < ctrl_nums; i++) { - /* Status of '0' means RAID exists at that controller */ - if (info_ctrl[i][INFO_STATUS] == RAID_FOUND || - info_ctrl[i][INFO_STATUS] == RAID_DONT_USE) - continue; + uint32_t ctl_tag = MAX32BIT; + raid_obj_handle_t ctl_handle = INIT_HANDLE_VALUE; + uint32_t raid_level = RAID_LEVEL_1; + uint64_t capacity = 0; + uint64_t stripe_size = (uint64_t)OBJ_ATTR_NONE; + raid_obj_handle_t *disk_handlesp = NULL; + raid_obj_handle_t array_handle = INIT_HANDLE_VALUE; + raidcfg_controller_t ctl_attr; + int comps_num = 0; + int ret = 0; + + raidcfg_array_t array_attr; + + if (argv[optind] == NULL || argv[optind + 1] != NULL) { + return (INVALID_ARG); + } - if (!space && raids != NULL) { - (void) printf("\n"); - space = 1; - } + if (disks_argp == NULL) { + return (INVALID_ARG); + } - /* switch statement used to enable gettext()'ing of text */ - switch (info_ctrl[i][INFO_STATUS]) { - case RAID_INVALID_CTRL: - (void) printf(gettext("Invalid controller '%d'\n"), - info_ctrl[i][INFO_CTRL]); - break; - case RAID_NOT_SUPPORTED: - (void) printf(gettext("No RAID supported " - "on controller '%d'\n"), - info_ctrl[i][INFO_CTRL]); + /* Check controller tag */ + if (get_ctl_tag(argv[optind], &ctl_tag) != SUCCESS) { + return (INVALID_ARG); + } - break; - default: - (void) printf(gettext("No RAID volumes found on " - "controller '%d'\n"), info_ctrl[i][INFO_CTRL]); - } + ctl_handle = raidcfg_get_controller(ctl_tag); + if (ctl_handle <= 0) { + (void) fprintf(stderr, "%s\n", raidcfg_errstr(ctl_handle)); + return (FAILURE); } -} -static void -add_raid_to_raidlist(char *ctrl_name, int controller) -{ - raidlist_t *curr; - char buf[MAXPATHLEN] = {0}; - char buf1[MAXPATHLEN] = {0}; - int nvols; - int fd; - int i; - int n; + if ((ret = raidcfg_get_attr(ctl_handle, &ctl_attr)) < 0) { + (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); + return (FAILURE); + } - if (readlink(ctrl_name, buf, sizeof (buf)) < 0) - return; + /* Get raid level */ + if (raid_levelp != NULL) { + if (*raid_levelp == '1' && + (*(raid_levelp + 1) == 'E' || *(raid_levelp + 1) == 'e')) { + raid_level = RAID_LEVEL_1E; + } else { + if (is_fully_numeric(raid_levelp) == FALSE) { + return (INVALID_ARG); + } - if (get_ctrl_devctl(buf, buf1)) - return; + switch (atoi(raid_levelp)) { + case 0: + raid_level = RAID_LEVEL_0; + break; + case 1: + raid_level = RAID_LEVEL_1; + break; + case 5: + raid_level = RAID_LEVEL_5; + break; + case 10: + raid_level = RAID_LEVEL_10; + break; + case 50: + raid_level = RAID_LEVEL_50; + break; + default: + return (INVALID_ARG); + } + } + } /* - * If "-l" was specified, then only look at those controllers - * listed as part of the command line input. + * The rang check of capacity and stripe size is performed in library, + * and it relates to hardware feature. */ - if (info_ctrl != NULL) { - for (i = 0; i < ctrl_nums; i++) { - if (info_ctrl[i][INFO_STATUS] == RAID_DONT_USE) - continue; - if (controller == info_ctrl[i][INFO_CTRL]) - break; + + /* Capacity in bytes. Capacity 0 means max available space. */ + if (capacityp != NULL) { + if (*capacityp == '-' || + calc_size(capacityp, &capacity) != SUCCESS) { + return (INVALID_ARG); } - /* return if we didn't find a controller */ - if (i == ctrl_nums) - return; } - fd = open(buf1, O_RDONLY); - if (fd == -1) { - if (info_ctrl != NULL) - info_ctrl[i][INFO_STATUS] = RAID_INVALID_CTRL; - return; + /* Stripe size in bytes */ + if (stripe_sizep != NULL) { + if (calc_size(stripe_sizep, &stripe_size) != SUCCESS || + *stripe_sizep == '-') { + return (INVALID_ARG); + } } - /* - * query the HBA driver for volume capacity - */ - if (ioctl(fd, RAID_NUMVOLUMES, &nvols) < 0) { - if (info_ctrl != NULL) - info_ctrl[i][INFO_STATUS] = RAID_NOT_SUPPORTED; - (void) close(fd); - return; + /* Open controller before accessing its object */ + if ((ret = raidcfg_open_controller(ctl_handle, NULL)) < 0) { + (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); + return (FAILURE); } - /* - * now iterate through nvols configurations - */ - for (n = 0; n < nvols; n++) { - raid_config_t config; - - /* use unitid to retrieve this volume */ - config.unitid = n; - if (ioctl(fd, RAID_GETCONFIG, &config) < 0) { - if (info_ctrl != NULL) - info_ctrl[i][INFO_STATUS] = RAID_NOT_SUPPORTED; - (void) close(fd); - return; - } - - /* if ndisks is 0, this volume is not configured */ - if (config.ndisks == 0) - continue; - - /* otherwise, we have a raid volume */ - if (info_ctrl != NULL) - info_ctrl[i][INFO_STATUS] = RAID_FOUND; - - /* - * if raids has not been initialized, then do so. - * otherwise, see if this controller is in raids. - * if it is not, add it. then, add this volume to - * the raidlist - */ - if (raids == NULL) { - raids = (raidlist_t *)malloc(sizeof (raidlist_t)); - curr = raids; - } else { - if ((curr = already_there(controller)) != NULL) - goto already_there; + /* Get disks' handles */ + if ((ret = get_disk_handle_cidl(ctl_tag, disks_argp, &comps_num, + &disk_handlesp)) != SUCCESS) { + (void) raidcfg_close_controller(ctl_handle, NULL); + return (ret); + } - curr = raids; + if (f_flag == FALSE) { + (void) fprintf(stdout, gettext("Creating RAID volume " + "will destroy all data on spare space of member disks, " + "proceed (%s/%s)? "), yesstr, nostr); + if (!yes()) { + (void) fprintf(stdout, gettext("RAID volume " + "not created.\n\n")); + (void) raidcfg_close_controller(ctl_handle, NULL); + free(disk_handlesp); + return (SUCCESS); + } + } - /* add this controller to raids */ - while (curr->next != NULL) - curr = curr->next; + /* Create array */ + array_handle = raidcfg_create_array(comps_num, + disk_handlesp, raid_level, capacity, stripe_size, NULL); - curr->next = (raidlist_t *)malloc(sizeof (raidlist_t)); - curr = curr->next; - } + if (array_handle <= 0) { + (void) fprintf(stderr, "%s\n", raidcfg_errstr(array_handle)); + free(disk_handlesp); + (void) raidcfg_close_controller(ctl_handle, NULL); + return (FAILURE); + } -already_there: - /* - * curr is now pointing to this controller. since we are - * adding controllers one at a time from do_search(), set - * curr->next to NULL so that we know where the end of our - * currently added controllers lies. - */ - curr->next = NULL; - curr->controller = controller; - (void) strlcpy(curr->devctl, buf1, sizeof (curr->devctl)); - (void) fflush(stdout); - (void) memcpy(&curr->raid_config[n], &config, - (sizeof (raid_config_t))); + /* Get attribute of the new created array */ + if ((ret = raidcfg_get_attr(array_handle, &array_attr)) < 0) { + (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); + free(disk_handlesp); + (void) raidcfg_close_controller(ctl_handle, NULL); + return (FAILURE); } - if (info_ctrl != NULL && info_ctrl[i][INFO_STATUS] != RAID_FOUND) - info_ctrl[i][INFO_STATUS] = RAID_NOT_FOUND; -} + (void) fprintf(stdout, gettext("Volume c%ut%llud%llu is created " + "successfully!\n"), ctl_tag, array_attr.tag.idl.target_id, + array_attr.tag.idl.lun); -static void -print_header() -{ - (void) printf(gettext("RAID\tVolume\tRAID\t\tRAID\t\tDisk")); - (void) printf("\n"); - (void) printf(gettext("Volume\tType\tStatus\t\tDisk\t\tStatus")); - (void) printf("\n"); - (void) printf("------------------------------------------------------"); - (void) printf("\n"); -} + /* Print attribute of array */ + (void) print_array_table(ctl_handle, array_handle); -static void -print_raidconfig(int c, raid_config_t config) -{ - int i; - char voltype[8]; - - /* print RAID volume target ID and volume type */ - if (config.raid_level == RAID_STRIPE) { - (void) snprintf(voltype, sizeof (voltype), "IS"); - } else if (config.raid_level == RAID_MIRROR) { - (void) snprintf(voltype, sizeof (voltype), "IM"); - } - - (void) printf("c%dt%dd0\t%s\t", c, config.targetid, voltype); - - /* Get RAID Info */ - if (config.flags & RAID_FLAG_RESYNCING && - config.state == RAID_STATE_DEGRADED) { - (void) printf(gettext("RESYNCING\t")); - } else if (config.state == RAID_STATE_DEGRADED) { - (void) printf(gettext("DEGRADED\t")); - } else if (config.state == RAID_STATE_OPTIMAL) { - (void) printf(gettext("OK\t\t")); - } else if (config.state == RAID_STATE_FAILED) { - (void) printf(gettext("FAILED\t\t")); - } else { - (void) printf(gettext("ERROR\t\t")); - } + /* Close controller */ + (void) raidcfg_close_controller(ctl_handle, NULL); - /* Get RAID Disks */ - if (config.disk[0] != 0xff) - (void) printf("c%dt%dd0\t\t", c, config.disk[0]); - else - (void) printf("-\t\t"); + free(disk_handlesp); + return (SUCCESS); +} - /* Get RAID Disk's Status */ - if (config.diskstatus[0] & RAID_DISKSTATUS_FAILED) { - (void) printf(gettext("FAILED\n")); - } else if (config.diskstatus[0] & RAID_DISKSTATUS_MISSING) { - (void) printf(gettext("MISSING\n")); - } else { - (void) printf(gettext("OK\n")); +/* + * do_create_ctd(raid_levelp, disks_argpp, disks_num, argindex, f_flag) + * This function creates array with specified arguments, and return result + * as SUCCESS, FAILURE, or INVALID_ARG. It only supports LSI MPT controller + * to be compatible with old raidctl. The capacity and stripe size can't + * be specified for LSI MPT controller, and they use zero and default value. + * The "ctd" is the canonical expression of physical disks which are + * accessible by OS. + */ +static int +do_create_ctd(char *raid_levelp, char **disks_argpp, uint32_t disks_num, + uint32_t argindex, uint32_t f_flag) +{ + uint32_t ctl_tag = MAX32BIT; + raid_obj_handle_t ctl_handle = INIT_HANDLE_VALUE; + uint32_t raid_level = RAID_LEVEL_1; + uint64_t capacity = 0; + uint32_t stripe_size = (uint32_t)OBJ_ATTR_NONE; + raid_obj_handle_t *disk_handlesp = NULL; + raid_obj_handle_t array_handle = INIT_HANDLE_VALUE; + raidcfg_controller_t ctl_attr; + int ret; + + raidcfg_array_t array_attr; + int i, j; + + /* Check disks parameter */ + if (disks_argpp == NULL || disks_num < 2) { + return (INVALID_ARG); } - for (i = 1; i < config.ndisks; i++) { - if (config.disk[i] != 0xff) - (void) printf("\t\t\t\tc%dt%dd0\t\t", c, - config.disk[i]); - else - (void) printf("\t\t\t\t-\t\t"); - - if (config.diskstatus[i] & RAID_DISKSTATUS_FAILED) { - (void) printf(gettext("FAILED\n")); - } else if (config.diskstatus[i] & RAID_DISKSTATUS_MISSING) { - (void) printf(gettext("MISSING\n")); - } else { - (void) printf(gettext("OK\n")); + for (i = 0, j = argindex; i < disks_num; i++, j++) { + if (disks_argpp[j] == NULL) { + return (INVALID_ARG); } } -} -static void -print_disklist() -{ - raidlist_t *curr = raids; - int i; + /* + * We need check if the raid_level string is fully numeric. If user + * input string with unsupported letters, such as "s10", atoi() will + * return zero because it is an illegal string, but it doesn't mean + * RAID_LEVEL_0. + */ + if (raid_levelp != NULL) { + if (*raid_levelp == '1' && + (*(raid_levelp + 1) == 'E' || *(raid_levelp + 1) == 'e')) { + raid_level = RAID_LEVEL_1E; + } else { + if (is_fully_numeric(raid_levelp) == FALSE) { + return (INVALID_ARG); + } - while (curr != NULL) { - for (i = 0; i < N_RAIDVOLS; i++) { - if (curr->raid_config[i].ndisks != 0) { - print_raidconfig(curr->controller, - curr->raid_config[i]); + switch (atoi(raid_levelp)) { + case 0: + raid_level = RAID_LEVEL_0; + break; + case 1: + raid_level = RAID_LEVEL_1; + break; + case 5: + raid_level = RAID_LEVEL_5; + break; + default: + return (INVALID_ARG); } } - curr = curr->next; } -} -static void -free_disklist() -{ - raidlist_t *curr = raids; + /* Get disks tag and controller tag */ + disk_handlesp = (raid_obj_handle_t *)calloc(disks_num + 2, + sizeof (raid_obj_handle_t)); + if (disk_handlesp == NULL) { + return (FAILURE); + } - while (curr != NULL) { - raidlist_t *temp; - temp = curr; - curr = curr->next; - free(temp); + disk_handlesp[0] = OBJ_SEPARATOR_BEGIN; + disk_handlesp[disks_num + 1] = OBJ_SEPARATOR_END; + + if ((ret = get_disk_handle_ctd(disks_num, &disks_argpp[argindex], + &ctl_tag, &disk_handlesp[1])) != SUCCESS) { + free(disk_handlesp); + return (ret); } -} -static void -do_search() -{ - DIR *dir; - struct dirent *dp; - char buf[MAXPATHLEN]; - int c; - int i, j; + /* LIB API should check whether all disks here belong to one ctl. */ + /* get_disk_handle_ctd has opened controller. */ + ctl_handle = raidcfg_get_controller(ctl_tag); - /* - * In case repeated numbers were found, assign the repititions as - * RAID_DONT_USE - */ - for (i = 0; i < ctrl_nums; i++) { - int first_one = 1; - for (j = 0; j < ctrl_nums; j++) { - if (info_ctrl[i][INFO_CTRL] == - info_ctrl[j][INFO_CTRL]) { - if (info_ctrl[j][INFO_STATUS] == RAID_DONT_USE) - continue; - if (first_one) { - first_one = 0; - } else { - info_ctrl[j][INFO_STATUS] = - RAID_DONT_USE; - } - } - } + if (ctl_handle <= 0) { + (void) fprintf(stderr, "%s\n", raidcfg_errstr(ctl_handle)); + (void) raidcfg_close_controller(ctl_handle, NULL); + free(disk_handlesp); + return (FAILURE); } - if ((dir = opendir("/dev/cfg")) == NULL) { + /* Check if the controller is host raid type */ + if ((ret = raidcfg_get_attr(ctl_handle, &ctl_attr)) < 0) { + (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); + (void) raidcfg_close_controller(ctl_handle, NULL); + free(disk_handlesp); + return (FAILURE); + } + + if ((ctl_attr.capability & RAID_CAP_DISK_TRANS) == 0) { + /* -c only support host raid controller, return failure here */ (void) fprintf(stderr, - gettext("Cannot open /dev/cfg: %s\n"), strerror(errno)); - return; + gettext("Option -c only supports host raid controller.\n")); + (void) raidcfg_close_controller(ctl_handle, NULL); + free(disk_handlesp); + return (FAILURE); } + + if (f_flag == FALSE) { + (void) fprintf(stdout, gettext("Creating RAID volume " + "will destroy all data on spare space of member disks, " + "proceed (%s/%s)? "), yesstr, nostr); + if (!yes()) { + (void) fprintf(stdout, gettext("RAID volume " + "not created.\n\n")); + free(disk_handlesp); + (void) raidcfg_close_controller(ctl_handle, NULL); + return (SUCCESS); + } + } + /* - * iterate over the controllers and add any - * controllers with RAID volumes to the raids - * list, one at a time + * For old raidctl, capacity is 0, which means to creates + * max possible capacity of array. */ - while ((dp = readdir(dir)) != NULL) { - if (strcmp(dp->d_name, ".") == 0 || - strcmp(dp->d_name, "..") == 0) - continue; - if (sscanf(dp->d_name, "c%d", &c) != 1) - continue; - (void) snprintf(buf, sizeof (buf), "/dev/cfg/%s", dp->d_name); - add_raid_to_raidlist(buf, c); - } - (void) closedir(dir); -} - -/* - * do_info() will do the following: - * - create a list of disks' devctls - * - try to talk to each of the devctls found - * - if raid configuration is found, display it. - */ -static void -do_info() -{ - int i; - (void) chdir(DEVDIR); - do_search(); + array_handle = raidcfg_create_array(disks_num + 2, + disk_handlesp, raid_level, capacity, stripe_size, NULL); - if (raids == NULL) { - if (info_ctrl != NULL) { - print_no_raids(); - for (i = 0; i < ctrl_nums; i++) - free(info_ctrl[i]); - free(info_ctrl); - } else { - (void) printf(gettext("No RAID volumes found\n")); - } - return; + if (array_handle <= 0) { + (void) fprintf(stderr, "%s\n", raidcfg_errstr(array_handle)); + free(disk_handlesp); + (void) raidcfg_close_controller(ctl_handle, NULL); + return (FAILURE); } - print_header(); - print_disklist(); - print_no_raids(); - free_disklist(); - if (info_ctrl) { - for (i = 0; i < ctrl_nums; i++) - free(info_ctrl[i]); - free(info_ctrl); + /* Get attribute of array */ + if ((ret = raidcfg_get_attr(array_handle, &array_attr)) < 0) { + (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); + free(disk_handlesp); + (void) raidcfg_close_controller(ctl_handle, NULL); + return (FAILURE); } + + /* Close controller */ + (void) raidcfg_close_controller(ctl_handle, NULL); + + /* Print feedback for user */ + (void) fprintf(stdout, + gettext("Volume c%ut%llud%llu is created successfully!\n"), + ctl_tag, array_attr.tag.idl.target_id, + array_attr.tag.idl.lun); + free(disk_handlesp); + return (SUCCESS); } +/* + * do_list(disk_arg, argv, optind, is_snapshot) + * This function lists RAID's system configuration. It supports various RAID + * controller. The return value can be SUCCESS, FAILURE, or INVALID_ARG. + */ static int -disk_in_raid(int c, int t) +do_list(char *disk_argp, char **argv, uint32_t optind, uint8_t is_snapshot) { - raidlist_t *curr; - raid_config_t raid; - int i, j, n; - - do_search(); - curr = raids; - - while (curr != NULL) { - if (curr->controller == c) { - for (i = 0; i < N_RAIDVOLS; i++) { - raid = curr->raid_config[i]; - if ((n = raid.ndisks) != 0) { - for (j = 0; j < n; j++) { - if (raid.disk[j] == t) { - return (1); - } + uint32_t ctl_tag = MAX32BIT; + raid_obj_handle_t ctl_handle = INIT_HANDLE_VALUE; + raid_obj_handle_t disk_handle = INIT_HANDLE_VALUE; + raid_obj_handle_t array_handle = INIT_HANDLE_VALUE; + disk_tag_t disk_tag; + array_tag_t array_tag; + + int ret; + + /* print RAID system */ + if (disk_argp == NULL) { + if (argv[optind] == NULL) { + ret = snapshot_raidsystem(TRUE, 0, is_snapshot); + return (ret); + } else { + if (is_fully_numeric(argv[optind]) == TRUE) { + while (argv[optind] != NULL) { + if (get_ctl_tag(argv[optind], &ctl_tag) + != SUCCESS) { + ret = INVALID_ARG; + optind++; + continue; + } + ctl_handle = + raidcfg_get_controller(ctl_tag); + if (ctl_handle <= 0) { + (void) fprintf(stderr, "%s\n", + raidcfg_errstr(ctl_handle)); + ret = FAILURE; + optind++; + continue; } + ret = + raidcfg_open_controller(ctl_handle, + NULL); + if (ret < 0) { + (void) fprintf(stderr, "%s\n", + raidcfg_errstr(ret)); + ret = FAILURE; + optind++; + continue; + } + if (is_snapshot == FALSE) { + ret = + print_ctl_table(ctl_handle); + } else { + ret = + snapshot_ctl(ctl_handle, + FALSE, 0, is_snapshot); + } + (void) raidcfg_close_controller( + ctl_handle, NULL); + optind++; + } + } else { + if (get_array_tag(argv[optind], + &ctl_tag, &array_tag) != SUCCESS) { + return (INVALID_ARG); + } + ctl_handle = raidcfg_get_controller(ctl_tag); + if (ctl_handle <= 0) { + (void) fprintf(stderr, "%s\n", + raidcfg_errstr(ctl_handle)); + return (FAILURE); + } + + ret = raidcfg_open_controller(ctl_handle, NULL); + if (ret < 0) { + (void) fprintf(stderr, "%s\n", + raidcfg_errstr(ret)); + return (FAILURE); + } + + array_handle = raidcfg_get_array(ctl_handle, + array_tag.idl.target_id, array_tag.idl.lun); + if (array_handle <= 0) { + (void) fprintf(stderr, "%s\n", + raidcfg_errstr(array_handle)); + (void) raidcfg_close_controller( + ctl_handle, NULL); + return (FAILURE); } + if (is_snapshot == FALSE) { + ret = print_array_table(ctl_handle, + array_handle); + } else { + ret = snapshot_array(array_handle, 0, + FALSE, is_snapshot); + } + (void) raidcfg_close_controller( + ctl_handle, NULL); } } - curr = curr->next; + } else { + if (argv[optind + 1] != NULL) { + return (INVALID_ARG); + } + + if (get_ctl_tag(argv[optind], &ctl_tag) != SUCCESS) { + return (INVALID_ARG); + } + + ctl_handle = raidcfg_get_controller(ctl_tag); + if (ctl_handle <= 0) { + (void) fprintf(stderr, "%s\n", + raidcfg_errstr(ctl_handle)); + return (FAILURE); + } + + if (get_disk_tag_cidl(disk_argp, &disk_tag) != SUCCESS) { + return (INVALID_ARG); + } + + ret = raidcfg_open_controller(ctl_handle, NULL); + if (ret < 0) { + (void) fprintf(stderr, "%s\n", + raidcfg_errstr(ret)); + return (FAILURE); + } + + disk_handle = raidcfg_get_disk(ctl_handle, disk_tag); + if (disk_handle <= 0) { + (void) fprintf(stderr, "%s\n", + raidcfg_errstr(disk_handle)); + (void) raidcfg_close_controller(ctl_handle, NULL); + return (FAILURE); + } + + if (is_snapshot == FALSE) { + ret = print_disk_table(ctl_handle, disk_handle); + } else { + ret = snapshot_disk(ctl_tag, disk_handle, 0, + is_snapshot); + } + (void) raidcfg_close_controller(ctl_handle, NULL); } - return (0); + return (ret); } +/* + * do_delete(f_flag, argv, optind) + * This function deletes a specified array, and return result as SUCCESS, + * FAILURE or INVALID_ARG. + */ static int -disk_there(int c, int t) +do_delete(uint32_t f_flag, char **argv, uint32_t optind) { - char disk[100]; - int fd; + uint32_t ctl_tag; + char *array_argp; + array_tag_t array_tag; + raid_obj_handle_t ctl_handle; + raid_obj_handle_t array_handle; + int ret; + + array_argp = argv[optind]; + if (array_argp == NULL || argv[optind + 1] != NULL) { + return (INVALID_ARG); + } - (void) snprintf(disk, sizeof (disk), "c%dt%dd0s2", c, t); + if (get_array_tag(array_argp, &ctl_tag, &array_tag) != SUCCESS) { + return (INVALID_ARG); + } - fd = open(disk, O_RDWR | O_NDELAY); - if (fd == -1) { - return (-1); + ctl_handle = raidcfg_get_controller(ctl_tag); + if (ctl_handle <= 0) { + (void) fprintf(stderr, "%s\n", raidcfg_errstr(ctl_handle)); + return (INVALID_ARG); } - (void) close(fd); - return (0); -} + ret = raidcfg_open_controller(ctl_handle, NULL); + if (ret < 0) { + (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); + return (FAILURE); + } -static int -get_controller(char *dev) -{ - raidlist_t *curr; - int c; - do_search(); - curr = raids; - while (curr != NULL) { - if (strcmp(curr->devctl, dev) == 0) { - c = curr->controller; - break; + array_handle = raidcfg_get_array(ctl_handle, array_tag.idl.target_id, + array_tag.idl.lun); + if (array_handle <= 0) { + (void) fprintf(stderr, "%s\n", raidcfg_errstr(array_handle)); + (void) raidcfg_close_controller(ctl_handle, NULL); + return (FAILURE); + } + + if (f_flag == FALSE) { + (void) fprintf(stdout, gettext("Deleting RAID volume " + "%s will destroy all data it contains, " + "proceed (%s/%s)? "), array_argp, yesstr, nostr); + if (!yes()) { + (void) fprintf(stdout, gettext("RAID Volume " + "%s not deleted.\n\n"), array_argp); + (void) raidcfg_close_controller(ctl_handle, NULL); + return (SUCCESS); } - curr = curr->next; } - free_disklist(); - return (c); -} -static int -disk_mounted(char *d) -{ - struct mnttab mt; - FILE *f = fopen("/etc/mnttab", "r"); + if ((ret = raidcfg_delete_array(array_handle, NULL)) < 0) { + (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); + (void) raidcfg_close_controller(ctl_handle, NULL); + return (FAILURE); + } - while (getmntent(f, &mt) != EOF) - if (strstr(mt.mnt_special, d) != NULL) - return (1); + (void) fprintf(stdout, gettext("Volume %s is deleted successfully!\n"), + array_argp); + (void) raidcfg_close_controller(ctl_handle, NULL); - return (0); + return (SUCCESS); } +/* + * do_flash(f_flag, filep, ctls_argpp, index, ctl_num) + * This function downloads and updates firmware for specified controller, and + * return result as SUCCESS, FAILURE or INVALID_ARG. + */ static int -disk_big_enough(char **d, diskaddr_t *cap, int *errcond) +do_flash(uint8_t f_flag, char *filep, char **ctls_argpp, + uint32_t index, uint32_t ctl_num) { - struct dk_minfo minfo; - char disk[N_DISKS][MAXPATHLEN]; - uint_t disk_lbsize[N_DISKS]; - diskaddr_t disk_capacity[N_DISKS]; - int i, fd; - - for (i = 0; i < N_DISKS; i++) { - if (d[i] == NULL) - break; + uint32_t ctl_tag = MAX32BIT; + char *ctl_argp = NULL; + raid_obj_handle_t ctl_handle = INIT_HANDLE_VALUE; + int ret; + int i, j; + + if (ctl_num == 0) + return (INVALID_ARG); + + for (i = 0, j = index; i < ctl_num; i++, j++) { + ctl_argp = ctls_argpp[j]; + if (get_ctl_tag(ctl_argp, &ctl_tag) != SUCCESS) { + return (INVALID_ARG); + } + + /* Ask user to confirm operation. */ + if (f_flag == FALSE) { + (void) fprintf(stdout, gettext("Update flash image on " + "controller %d (%s/%s)? "), ctl_tag, yesstr, nostr); + if (!yes()) { + (void) fprintf(stdout, + gettext("Controller %d not " + "flashed.\n\n"), ctl_tag); + return (SUCCESS); + } + } - (void) snprintf(disk[i], sizeof (disk[i]), DEVDIR"/%ss2", d[i]); - fd = open(disk[i], O_RDWR | O_NDELAY); - if (fd == -1) + if ((ctl_handle = raidcfg_get_controller(ctl_tag)) < 0) { + (void) fprintf(stderr, "%s\n", + raidcfg_errstr(ctl_handle)); return (FAILURE); - if (ioctl(fd, DKIOCGMEDIAINFO, &minfo) == -1) { - (void) close(fd); + } + + ret = raidcfg_open_controller(ctl_handle, NULL); + if (ret < 0) { + (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); return (FAILURE); } - disk_lbsize[i] = minfo.dki_lbsize; - disk_capacity[i] = minfo.dki_capacity; + (void) fprintf(stdout, gettext("Start updating controller " + "c%u firmware....\n"), ctl_tag); - /* lbsize must be the same on all disks */ - if (disk_lbsize[0] != disk_lbsize[i]) { - *errcond = 2; - return (INVALID_ARG); + if ((ret = raidcfg_update_fw(ctl_handle, filep, NULL)) < 0) { + (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); + (void) raidcfg_close_controller(ctl_handle, NULL); + return (FAILURE); } - /* ensure drive capacity is greater than or equal to first */ - if (disk_capacity[0] > disk_capacity[i]) { - *errcond = 1; - return (INVALID_ARG); - } - (void) close(fd); + (void) fprintf(stdout, gettext("Update controller " + "c%u firmware successfully.\n"), ctl_tag); + + (void) raidcfg_close_controller(ctl_handle, NULL); } - /* - * setting capacity as the dk_minfo.dki_capacity of d[0] - * this is the number of dki_lbsize blocks on disk - */ - *cap = disk_capacity[0]; return (SUCCESS); } +/* + * do_set_hsp(a_argp, disk_argp, argv, optind) + * This function set or unset HSP relationship between disk and controller/ + * array, and return result as SUCCESS, FAILURE or INVALID_ARG. + */ static int -do_config_change_state(cfga_cmd_t cmd, int d, int c) +do_set_hsp(char *a_argp, char *disk_argp, char **argv, uint32_t optind) { - cfga_err_t cfga_err; - char *ap_id; - int rv = SUCCESS; - int count = 0; + uint32_t flag = MAX32BIT; + uint32_t ctl_tag = MAX32BIT; + array_tag_t array_tag; + raid_obj_handle_t ctl_handle = INIT_HANDLE_VALUE; + raid_obj_handle_t disk_handle = INIT_HANDLE_VALUE; + raid_obj_handle_t array_handle = INIT_HANDLE_VALUE; + raidcfg_controller_t ctl_attr; + disk_tag_t disk_tag; + + int ret; + int hsp_type; + raidcfg_hsp_relation_t hsp_relation; + + (void) memset(&hsp_relation, 0, sizeof (raidcfg_hsp_relation_t)); + + if (a_argp == NULL) { + return (INVALID_ARG); + } - ap_id = (char *)malloc(100); - if (ap_id == NULL) - return (FAILURE); + if (strcmp(a_argp, "set") == 0) { + flag = HSP_SET; + } else if (strcmp(a_argp, "unset") == 0) { + flag = HSP_UNSET; + } else { + return (INVALID_ARG); + } - (void) snprintf(ap_id, 100, "c%d::dsk/c%dt%dd0", c, c, d); + if (disk_argp == NULL) { + return (INVALID_ARG); + } - /* - * If the config_change_state() funcation fails, we want to - * retry. If the retry fails, then we return failure to fail. - * - * If we fail: - * - * If we were called from create, then we fail the raid - * creation. - * - * If we were called from delete, then the disk will not - * be re-configured by raidctl. - */ - do { - cfga_err = config_change_state(cmd, 1, &ap_id, NULL, - NULL, NULL, NULL, 0); - count++; - } while (cfga_err != CFGA_OK && count < 2); + if (argv[optind] == NULL || argv[optind + 1] != NULL) { + return (INVALID_ARG); + } else if (is_fully_numeric(argv[optind]) == TRUE) { + /* Global HSP */ + hsp_type = 0; + if (get_disk_tag_cidl(disk_argp, &disk_tag) != SUCCESS) { + return (INVALID_ARG); + } - if (cfga_err != CFGA_OK) - rv = FAILURE; + if (get_ctl_tag(argv[optind], &ctl_tag) != SUCCESS) { + return (INVALID_ARG); + } - free(ap_id); - return (rv); -} + ctl_handle = raidcfg_get_controller(ctl_tag); + if (ctl_handle <= 0) { + (void) fprintf(stderr, "%s\n", + raidcfg_errstr(ctl_handle)); + return (FAILURE); + } -static int -do_create(char **d, int rlevel, int force) -{ - raid_config_t config; - raid_config_t newvol; - char disk[N_DISKS][MAXPATHLEN] = {0}; - int map[N_DISKS]; - char channel1[MAXPATHLEN]; - char channel2[MAXPATHLEN]; - diskaddr_t capacity; - int fd, fd2, size, errcond; - int c[N_DISKS]; - int t[N_DISKS]; - char *tmp; - int loc, i, devid, n, ndisks = 0; - - (void) chdir(DEVDIR); - - /* initialize target map */ - for (i = 0; i < N_DISKS; i++) - map[i] = -1; - - for (i = 0; i < N_DISKS; i++) { - if (d[i] == NULL) - break; + ret = raidcfg_open_controller(ctl_handle, NULL); + if (ret < 0) { + (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); + return (FAILURE); + } - if ((sscanf(d[i], "c%dt%dd0", &c[i], &t[i])) != 2 || - t[i] < 0) { - (void) fprintf(stderr, - gettext("Invalid disk format.\n")); + disk_handle = raidcfg_get_disk(ctl_handle, disk_tag); + if (disk_handle <= 0) { + (void) fprintf(stderr, "%s\n", + raidcfg_errstr(disk_handle)); + (void) raidcfg_close_controller(ctl_handle, NULL); + return (FAILURE); + } + } else { + /* Local HSP */ + hsp_type = 1; + if (get_array_tag(argv[optind], &ctl_tag, &array_tag) != + SUCCESS) { return (INVALID_ARG); } - /* ensure that all disks are on the same controller, */ - if (c[i] != c[0]) { - (void) fprintf(stderr, gettext("Disks must be " - "on the same controller.\n")); - return (INVALID_ARG); + /* Open controller */ + ctl_handle = raidcfg_get_controller(ctl_tag); + if (ctl_handle <= 0) { + (void) fprintf(stderr, "%s\n", + raidcfg_errstr(ctl_handle)); + return (FAILURE); + } + + ret = raidcfg_open_controller(ctl_handle, NULL); + if (ret < 0) { + (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); + return (FAILURE); + } + + /* Get controller's attribute */ + if ((ret = raidcfg_get_attr(ctl_handle, &ctl_attr)) < 0) { + (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); + (void) raidcfg_close_controller(ctl_handle, NULL); + return (FAILURE); } - /* that all disks are online, */ - if (disk_there(c[0], t[i])) { - (void) printf(gettext("Disk 'c%dt%dd0' is not " - "present.\n"), c[0], t[i]); - (void) printf(gettext("Cannot create RAID volume.\n")); + if (get_disk_tag_cidl(disk_argp, &disk_tag) != SUCCESS) { + (void) raidcfg_close_controller(ctl_handle, NULL); return (INVALID_ARG); } - /* that there are no duplicate disks, */ - loc = t[i]; - if (map[loc] == -1) { - map[loc] = t[i]; + /* Get disk handle */ + disk_handle = raidcfg_get_disk(ctl_handle, disk_tag); + if (disk_handle <= 0) { + (void) fprintf(stderr, "%s\n", + raidcfg_errstr(disk_handle)); + (void) raidcfg_close_controller(ctl_handle, NULL); + return (FAILURE); + } + + /* Get array handle */ + array_handle = raidcfg_get_array(ctl_handle, + array_tag.idl.target_id, array_tag.idl.lun); + if (array_handle <= 0) { + (void) fprintf(stderr, "%s\n", + raidcfg_errstr(array_handle)); + (void) raidcfg_close_controller(ctl_handle, NULL); + return (FAILURE); + } + } + + hsp_relation.disk_handle = disk_handle; + if (hsp_type) { + /* Set or unset local HSP */ + hsp_relation.array_handle = array_handle; + } else { + /* Set or unset global HSP */ + hsp_relation.array_handle = OBJ_ATTR_NONE; + } + + /* Perform operation of set or unset */ + if (flag == HSP_SET) { + if ((ret = raidcfg_set_hsp(1, &hsp_relation, NULL)) < 0) { + (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); + (void) raidcfg_close_controller(ctl_handle, NULL); + return (FAILURE); + } + + if (hsp_type) { + (void) printf(gettext("Set local HSP between disk %s " + "and RAID volume %s successfully.\n"), + disk_argp, argv[optind]); } else { - (void) fprintf(stderr, - gettext("Disks must be different.\n")); - return (INVALID_ARG); + (void) printf(gettext("Set global HSP between disk %s " + "and controller %s successfully.\n"), + disk_argp, argv[optind]); + } + } else { + if ((ret = raidcfg_unset_hsp(1, &hsp_relation, NULL)) < 0) { + (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); + (void) raidcfg_close_controller(ctl_handle, NULL); + return (FAILURE); } - /* that no disk is already in use by another volume, */ - if (disk_in_raid(c[0], t[i])) { - (void) fprintf(stderr, gettext("Disk %s is already in " - "a RAID volume.\n"), d[i]); + if (hsp_type) { + (void) printf(gettext("Unset local HSP between " + "disk %s and RAID volume %s successfully.\n"), + disk_argp, argv[optind]); + } else { + (void) printf(gettext("Unset global HSP between " + "disk %s and controller %s successfully.\n"), + disk_argp, argv[optind]); + } + } + (void) raidcfg_close_controller(ctl_handle, NULL); + return (SUCCESS); +} + +/* + * do_set_array_attr(f_flag, p_argp, argv, optind) + * This function changes array's attribute when array is running. + * The changeable attribute is up to controller's feature. + * The return value can be SUCCESS, FAILURE or INVALID_ARG. + */ +static int +do_set_array_attr(uint32_t f_flag, char *p_argp, char **argv, uint32_t optind) +{ + uint32_t ctl_tag = MAX32BIT; + array_tag_t array_tag; + uint32_t type = MAX32BIT; + uint32_t value = MAX32BIT; + raid_obj_handle_t ctl_handle = INIT_HANDLE_VALUE; + raid_obj_handle_t array_handle = INIT_HANDLE_VALUE; + + char *param, *op = "="; + + int ret; + + if (argv[optind] == NULL || argv[optind + 1] != NULL) { + return (INVALID_ARG); + } + + if (p_argp != NULL) { + param = strtok(p_argp, op); + if (strcmp(param, "wp") == 0) { + type = SET_CACHE_WR_PLY; + } else { return (INVALID_ARG); } - /* that no target's id is lower than the raidtarg, */ - if (t[0] > t[i]) { - (void) fprintf(stderr, gettext("First target ID must " - "be less than other member target IDs.\n")); + param = strtok(NULL, op); + if (strcmp(param, "on") == 0) { + value = CACHE_WR_ON; + } else if (strcmp(param, "off") == 0) { + value = CACHE_WR_OFF; + } else { return (INVALID_ARG); } - (void) snprintf(disk[i], sizeof (disk[i]), DEVDIR"/%ss2", d[i]); - ndisks++; + } else { + return (INVALID_ARG); } - /* confirm minimum number of disks */ - if (ndisks < 2) { - (void) fprintf(stderr, gettext("At least two disks are required" - " for RAID creation.\n")); + if (get_array_tag(argv[optind], &ctl_tag, &array_tag) != SUCCESS) { return (INVALID_ARG); } - /* validate the drive capacities */ - switch (disk_big_enough(d, &capacity, &errcond)) { - case FAILURE: + ctl_handle = raidcfg_get_controller(ctl_tag); + if (ctl_handle <= 0) { + (void) fprintf(stderr, "%s\n", raidcfg_errstr(ctl_handle)); return (FAILURE); - case INVALID_ARG: - switch (errcond) { - case 1: - (void) fprintf(stderr, gettext("Cannot create RAID volume when " - "primary disk is larger than secondary disk.\n")); - break; - case 2: - (void) fprintf(stderr, gettext("Cannot create RAID volume when " - "disk block sizes differ.\n")); - } - return (INVALID_ARG); } - /* - * capacity is now set to the number of blocks on a disk, which is - * the total capacity of a mirror. the capacity of a stripe is the - * cumulative amount of blocks on all disks - */ - if (rlevel == RAID_STRIPE) - capacity *= ndisks; - - if (get_devctl(disk[0], channel1)) + ret = raidcfg_open_controller(ctl_handle, NULL); + if (ret < 0) { + (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); return (FAILURE); + } - fd = open(channel1, O_RDONLY); - if (fd == -1) { - perror(channel1); + array_handle = raidcfg_get_array(ctl_handle, array_tag.idl.target_id, + array_tag.idl.lun); + if (array_handle <= 0) { + (void) fprintf(stderr, "%s\n", raidcfg_errstr(array_handle)); return (FAILURE); } - /* - * query the HBA driver for volume capacity - */ - if (ioctl(fd, RAID_NUMVOLUMES, &n) < 0) { - raidctl_error("RAID_NUMVOLUMES"); - goto fail; + /* Ask user to confirm operation. */ + if (f_flag == FALSE) { + (void) fprintf(stdout, gettext("Update attribute of " + "array %s (%s/%s)? "), argv[optind], yesstr, nostr); + if (!yes()) { + (void) fprintf(stdout, + gettext("Array %s not " + "changed.\n\n"), argv[optind]); + (void) raidcfg_close_controller(ctl_handle, NULL); + return (SUCCESS); + } } - /* - * current support for both LSI1030 and LSI1064/1068 HBAs - */ - if (ioctl(fd, RAID_GETDEVID, &devid) < 0) { - raidctl_error("RAID_GETDEVID"); - goto fail; - } - - if ((devid == LSI_1064) || (devid == LSI_1064E) || - (devid == LSI_1068) || (devid == LSI_1068E)) { - /* - * no secondary channel, just check to make - * sure we can fit a new volume - */ - for (i = 0; i < n; i++) { - config.unitid = i; - if (ioctl(fd, RAID_GETCONFIG, &config) < 0) { - raidctl_error("RAID_GETCONFIG"); - goto fail; - } + if ((ret = raidcfg_set_attr(array_handle, type, &value, NULL)) < 0) { + (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); + (void) raidcfg_close_controller(ctl_handle, NULL); + return (FAILURE); + } - if (config.ndisks == 0) - break; - } + (void) printf(gettext("Set attribute of RAID volume %s " + "successfully.\n"), argv[optind]); + (void) raidcfg_close_controller(ctl_handle, NULL); - if (i == n) { - (void) printf(gettext("HBA supports a maximum of %d " - "RAID Volumes, HBA is full\n"), n); - goto fail; - } - - /* - * we have the capacity to add a volume, now confirm the - * creation. the 1064/1068 uses a much larger metadata region - * than the 1030 (64MB, as opposed to 16KB). this larger - * reservation is enough to alter the disk label. therefore, - * once the volume is created, it must be relabeled. - * first, confirm that no file systems are mounted, as - * we will be pulling the disk out from under them - */ - for (i = 0; i < ndisks; i++) { - if (disk_mounted(d[i])) { - (void) fprintf(stderr, gettext("Cannot create " - "RAID volume, disk \"%s\" is mounted " - ".\n"), d[i]); - return (INVALID_ARG); - } - } + return (SUCCESS); +} - /* - * will not support data migration or disk relabeling with - * this utility, and so next we must confirm the creation as - * all data on member disks will be lost. - */ - if (!force) { - (void) fprintf(stderr, gettext("Creating RAID volume " - "c%dt%dd0 will destroy all data on member disks, " - "proceed (%s/%s)? "), c[0], t[0], yeschr, nochr); - if (!yes()) { - (void) fprintf(stderr, gettext("RAID volume " - "c%dt%dd0 not created.\n\n"), c[0], t[0]); - (void) close(fd); - return (SUCCESS); +/* + * snapshot_raidsystem(recursive, indent, is_snapshot) + * This function prints the snapshot of whole RAID's system configuration, + * and return result as SUCCESS or FAILURE. + */ +static int +snapshot_raidsystem(uint8_t recursive, uint8_t indent, uint8_t is_snapshot) +{ + raid_obj_handle_t ctl_handle = INIT_HANDLE_VALUE; + int ret; + + ctl_handle = raidcfg_list_head(OBJ_SYSTEM, OBJ_TYPE_CONTROLLER); + while (ctl_handle > 0) { + ret = raidcfg_open_controller(ctl_handle, NULL); + if (ret == 0) { + if (snapshot_ctl(ctl_handle, recursive, indent, + is_snapshot) == FAILURE) { + (void) raidcfg_close_controller(ctl_handle, + NULL); } } - - /* - * we are ready to move onto the creation - */ - goto no_secondary_channel; + ctl_handle = raidcfg_list_next(ctl_handle); } + return (SUCCESS); +} - /* - * LSI1030, support for single IM volume - */ - if (rlevel != RAID_MIRROR) { - (void) printf(gettext("HBA only supports RAID " - "level 1 (mirrored) volumes\n")); - goto fail; - } - /* - * look up the volume configuration - */ - config.unitid = n; - if (ioctl(fd, RAID_GETCONFIG, &config) < 0) { - raidctl_error("RAID_GETCONFIG"); - goto fail; +/* + * snapshot_ctl(ctl_handle, recursive, indent, is_snapshot) + * This function prints snapshot of specified controller's configuration, + * and return result as SUCCESS or FAILURE. + */ +static int +snapshot_ctl(raid_obj_handle_t ctl_handle, uint8_t recursive, uint8_t indent, + uint8_t is_snapshot) +{ + raid_obj_handle_t array_handle = INIT_HANDLE_VALUE; + raid_obj_handle_t disk_handle = INIT_HANDLE_VALUE; + raidcfg_controller_t ctl_attr; + uint32_t ctl_tag; + char ctlbuf[256]; + int ret; + + if ((ret = raidcfg_get_attr(ctl_handle, &ctl_attr)) < 0) { + (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); + return (FAILURE); } - if (config.ndisks != 0) { - (void) printf(gettext("RAID Volume already exists " - "on this controller 'c%dt%dd0'\n"), - c[0], config.targetid); - goto fail; + ctl_tag = ctl_attr.controller_id; + if (is_snapshot == FALSE) { + print_indent(indent); + (void) fprintf(stdout, gettext("Controller: %u\n"), ctl_tag); + } else { + (void) snprintf(ctlbuf, sizeof (ctlbuf), "%u \"%s\"", + ctl_tag, ctl_attr.controller_type); + (void) fprintf(stdout, "%s", ctlbuf); + + (void) fprintf(stdout, "\n"); } - /* - * Make sure there isn't a raid created on this controller's - * other channel, if it has multiple channels - */ - (void) strlcpy(channel2, channel1, sizeof (channel2)); - tmp = strrchr(channel2, ':'); - tmp[0] = 0; - size = strlen(channel2); + if (recursive == TRUE) { + array_handle = raidcfg_list_head(ctl_handle, OBJ_TYPE_ARRAY); + while (array_handle > 0) { + if (snapshot_array(array_handle, + indent + 1, FALSE, is_snapshot) == FAILURE) { + return (FAILURE); + } - /* - * Make sure that the secondary disk is not mounted - */ - if (disk_mounted(disk[1])) { - (void) fprintf(stderr, gettext("Cannot create RAID volume when " - "secondary disk \"%s\" is mounted.\n"), disk[1]); - return (INVALID_ARG); - } + array_handle = raidcfg_list_next(array_handle); + } - /* - * Format the channel string for the other channel so we can - * see if a raid exists on it. In this case if we are being - * asked to create a raid on channel 2 (indicated by the 1,1 - * at the end of the string) we want to check channel 1), - * otherwise we will check channel 2. - */ - if (channel2[size - 2] == ',') { - channel2[size - 1] = 0; - channel2[size - 2] = 0; - (void) snprintf(channel2, sizeof (channel2), - "%s:devctl", channel2); - } else { - (void) snprintf(channel2, sizeof (channel2), - "%s,1:devctl", channel2); - } + disk_handle = raidcfg_list_head(ctl_handle, OBJ_TYPE_DISK); + while (disk_handle > 0) { + if (snapshot_disk(ctl_tag, disk_handle, + indent + 1, is_snapshot) == FAILURE) { + return (FAILURE); + } - fd2 = open(channel2, O_RDONLY); - if (fd2 == -1) { - if (errno == ENOENT) - goto no_secondary_channel; - perror(channel2); - goto fail; + disk_handle = raidcfg_list_next(disk_handle); + } } + return (SUCCESS); +} - if (ioctl(fd2, RAID_GETCONFIG, &config) < 0) { - goto fail; + +/* + * snapshot_array(array_handle, indent, is_sub, is_snapshot) + * This function prints snapshot of specified array's configuration, + * and return result as SUCCESS or FAILURE. + */ +static int +snapshot_array(raid_obj_handle_t array_handle, uint8_t indent, uint8_t is_sub, + uint8_t is_snapshot) +{ + raid_obj_handle_t ctl_handle; + raid_obj_handle_t subarray_handle; + raid_obj_handle_t arraypart_handle; + raid_obj_handle_t task_handle; + + raidcfg_controller_t ctl_attr; + raidcfg_array_t array_attr; + raidcfg_arraypart_t arraypart_attr; + raidcfg_task_t task_attr; + + char arraybuf[256] = "\0"; + char diskbuf[256] = "\0"; + char tempbuf[256] = "\0"; + int disknum = 0; + + uint32_t ctl_tag; + int ret; + + ctl_handle = raidcfg_get_container(array_handle); + ret = raidcfg_get_attr(ctl_handle, &ctl_attr); + if (ret < 0) { + (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); + return (FAILURE); } + ctl_tag = ctl_attr.controller_id; - if (config.ndisks != 0) { - int cx; - cx = get_controller(channel2); - (void) printf(gettext("RAID Volume already exists " - "on this controller 'c%dt%dd0'\n"), cx, - config.targetid); - goto fail; + /* Print array attribute */ + if ((ret = raidcfg_get_attr(array_handle, &array_attr)) < 0) { + (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); + return (FAILURE); } -no_secondary_channel: + if (is_snapshot == FALSE) { + print_indent(indent); + if (is_sub == FALSE) { + (void) fprintf(stdout, gettext("Volume:" + "c%ut%llud%llu\n"), + ctl_tag, array_attr.tag.idl.target_id, + array_attr.tag.idl.lun); + } else { + (void) fprintf(stdout, gettext("Sub-Volume\n")); + } + } else { + (void) snprintf(arraybuf, sizeof (arraybuf), "c%ut%llud%llu ", + ctl_tag, array_attr.tag.idl.target_id, + array_attr.tag.idl.lun); + + /* Check if array is in sync state */ + task_handle = raidcfg_list_head(array_handle, OBJ_TYPE_TASK); + if (task_handle > 0) { + (void) raidcfg_get_attr(task_handle, &task_attr); + if (task_attr.task_func == TASK_FUNC_BUILD) { + array_attr.state = ARRAY_STATE_SYNC; + } + } else { + subarray_handle = raidcfg_list_head(array_handle, + OBJ_TYPE_ARRAY); + while (subarray_handle > 0) { + task_handle = raidcfg_list_head(subarray_handle, + OBJ_TYPE_TASK); + if (task_handle > 0) { + (void) raidcfg_get_attr(task_handle, + &task_attr); + if (task_attr.task_func == + TASK_FUNC_BUILD) { + array_attr.state = + ARRAY_STATE_SYNC; + } + break; + } + subarray_handle = + raidcfg_list_next(subarray_handle); + } + } - /* all checks complete, fill in the config */ - newvol.targetid = t[0]; - newvol.disk[0] = t[0]; - newvol.raid_level = rlevel; - newvol.ndisks = ndisks; - newvol.raid_capacity = capacity; + /* Print sub array */ + subarray_handle = raidcfg_list_head(array_handle, + OBJ_TYPE_ARRAY); + while (subarray_handle > 0) { + /* print subarraypart */ + arraypart_handle = raidcfg_list_head(subarray_handle, + OBJ_TYPE_ARRAY_PART); + while (arraypart_handle > 0) { + if ((ret = raidcfg_get_attr(arraypart_handle, + &arraypart_attr)) < 0) { + (void) fprintf(stderr, "%s\n", + raidcfg_errstr(ret)); + return (FAILURE); + } - /* populate config.disk, and unconfigure all disks, except targetid */ - for (i = 1; i < ndisks; i++) { - if (do_config_change_state(CFGA_CMD_UNCONFIGURE, - t[i], c[0])) { - perror("config_change_state"); - goto fail; + if (arraypart_attr.tag.cidl.bus == MAX64BIT) { + (void) snprintf(tempbuf, + sizeof (tempbuf), + gettext("N/A")); + } else { + (void) snprintf(tempbuf, + sizeof (tempbuf), + "%llu.%llu.%llu", + arraypart_attr.tag.cidl.bus, + arraypart_attr.tag.cidl.target_id, + arraypart_attr.tag.cidl.lun); + } + (void) strcat(diskbuf, tempbuf); + (void) strcat(diskbuf, " "); + disknum++; + arraypart_handle = + raidcfg_list_next(arraypart_handle); + } + subarray_handle = raidcfg_list_next(subarray_handle); } - newvol.disk[i] = t[i]; - } - if (ioctl(fd, RAID_CREATE, &newvol)) { - /* reconfigure all disks, except targetid */ - for (i = 1; i < ndisks; i++) { - (void) do_config_change_state(CFGA_CMD_CONFIGURE, - newvol.disk[i], c[0]); + /* Print arraypart */ + arraypart_handle = raidcfg_list_head(array_handle, + OBJ_TYPE_ARRAY_PART); + while (arraypart_handle > 0) { + if ((ret = raidcfg_get_attr(arraypart_handle, + &arraypart_attr)) < 0) { + (void) fprintf(stderr, "%s\n", + raidcfg_errstr(ret)); + return (FAILURE); + } + + if (arraypart_attr.tag.cidl.bus == MAX64BIT) { + (void) snprintf(tempbuf, sizeof (tempbuf), + gettext("N/A")); + } else { + (void) snprintf(tempbuf, sizeof (tempbuf), + "%llu.%llu.%llu", + arraypart_attr.tag.cidl.bus, + arraypart_attr.tag.cidl.target_id, + arraypart_attr.tag.cidl.lun); + } + (void) strcat(diskbuf, tempbuf); + (void) strcat(diskbuf, " "); + disknum++; + arraypart_handle = raidcfg_list_next(arraypart_handle); } - raidctl_error("RAID_CREATE"); - goto fail; + (void) snprintf(tempbuf, sizeof (tempbuf), "%u ", disknum); + (void) strcat(arraybuf, tempbuf); + (void) strcat(arraybuf, diskbuf); + + switch (array_attr.raid_level) { + case RAID_LEVEL_0: + (void) sprintf(tempbuf, "0"); + break; + case RAID_LEVEL_1: + (void) sprintf(tempbuf, "1"); + break; + case RAID_LEVEL_1E: + (void) sprintf(tempbuf, "1E"); + break; + case RAID_LEVEL_5: + (void) sprintf(tempbuf, "5"); + break; + case RAID_LEVEL_10: + (void) sprintf(tempbuf, "10"); + break; + case RAID_LEVEL_50: + (void) sprintf(tempbuf, "50"); + break; + default: + (void) snprintf(tempbuf, sizeof (tempbuf), + gettext("N/A")); + break; + } + (void) strcat(arraybuf, tempbuf); + (void) fprintf(stdout, "%s ", arraybuf); + + switch (array_attr.state) { + case ARRAY_STATE_OPTIMAL: + (void) fprintf(stdout, gettext("OPTIMAL")); + break; + case ARRAY_STATE_DEGRADED: + (void) fprintf(stdout, gettext("DEGRADED")); + break; + case ARRAY_STATE_FAILED: + (void) fprintf(stdout, gettext("FAILED")); + break; + case ARRAY_STATE_SYNC: + (void) fprintf(stdout, gettext("SYNC")); + break; + default: + (void) fprintf(stdout, gettext("N/A")); + break; + } + (void) fprintf(stdout, "\n"); } - (void) printf(gettext("Volume 'c%dt%dd0' created\n"), c[0], t[0]); - (void) close(fd); - (void) close(fd2); return (SUCCESS); - -fail: - (void) close(fd); - (void) close(fd2); - return (FAILURE); } +/* + * snapshot_disk(ctl_tag, disk_handle, indent, is_snapshot) + * This function prints snapshot of specified disk's configuration, and return + * result as SUCCESS or FAILURE. + */ static int -do_delete(char *d, int force) +snapshot_disk(uint32_t ctl_tag, raid_obj_handle_t disk_handle, uint8_t indent, + uint8_t is_snapshot) { - raid_config_t config; - char disk1[MAXPATHLEN]; - char buf[MAXPATHLEN]; - int fd; - int target; - int ctrl; - int i, j; - int wrong_targ = 0; - int nvols; - uint8_t t; - - (void) chdir(DEVDIR); - - if ((sscanf(d, "c%dt%dd0", &ctrl, &target)) != 2) { - (void) fprintf(stderr, gettext("Invalid disk format.\n")); - return (INVALID_ARG); + raid_obj_handle_t ctl_handle = INIT_HANDLE_VALUE; + raid_obj_handle_t hsp_handle; + + raidcfg_controller_t ctl_attr; + raidcfg_disk_t disk_attr; + char diskbuf[256] = ""; + char tempbuf[256] = ""; + + int ret; + + ctl_handle = raidcfg_get_controller(ctl_tag); + ret = raidcfg_get_attr(ctl_handle, &ctl_attr); + if (ret < 0) { + (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); + return (FAILURE); } - t = (uint8_t)target; - (void) snprintf(disk1, sizeof (disk1), DEVDIR"/%ss2", d); + /* Print attribute of disk */ + if ((ret = raidcfg_get_attr(disk_handle, &disk_attr)) < 0) { + (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); + return (FAILURE); + } + + if (is_snapshot == FALSE) { + print_indent(indent); - if (get_devctl(disk1, buf) != 0) { - (void) fprintf(stderr, gettext("Not a volume '%s'\n"), d); + hsp_handle = raidcfg_list_head(disk_handle, OBJ_TYPE_HSP); + + if (disk_attr.tag.cidl.bus == MAX64BIT) { + (void) fprintf(stdout, gettext("Disk: N/A")); + } else { + (void) fprintf(stdout, gettext("Disk: %llu.%llu.%llu"), + disk_attr.tag.cidl.bus, + disk_attr.tag.cidl.target_id, + disk_attr.tag.cidl.lun); + } + if (hsp_handle > 0) { + (void) fprintf(stdout, "(HSP)"); + } + (void) fprintf(stdout, "\n"); + } else { + if (disk_attr.tag.cidl.bus == MAX64BIT) { + (void) fprintf(stdout, gettext("N/A")); + } else { + (void) snprintf(diskbuf, sizeof (diskbuf), + "%llu.%llu.%llu ", + disk_attr.tag.cidl.bus, + disk_attr.tag.cidl.target_id, + disk_attr.tag.cidl.lun); + } + hsp_handle = raidcfg_list_head(disk_handle, OBJ_TYPE_HSP); + if (hsp_handle > 0) { + (void) snprintf(tempbuf, sizeof (tempbuf), + gettext("HSP")); + } else if (disk_attr.state == DISK_STATE_GOOD) { + (void) snprintf(tempbuf, sizeof (tempbuf), + gettext("GOOD")); + } else if (disk_attr.state == DISK_STATE_FAILED) { + (void) snprintf(tempbuf, sizeof (tempbuf), + gettext("FAILED")); + } else { + (void) snprintf(tempbuf, sizeof (tempbuf), + gettext("N/A")); + } + + (void) strcat(diskbuf, tempbuf); + (void) fprintf(stdout, "%s\n", diskbuf); + } + + return (SUCCESS); +} + +static int +print_ctl_table(raid_obj_handle_t ctl_handle) +{ + raidcfg_controller_t ctl_attr; + char controller[8]; + int ret; + + if ((ret = raidcfg_get_attr(ctl_handle, &ctl_attr)) < 0) { + (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); return (FAILURE); } - fd = open(buf, O_RDONLY); - if (fd == -1) { - perror(buf); + (void) fprintf(stdout, gettext("Controller\tType\t\tVersion")); + (void) fprintf(stdout, "\n"); + (void) fprintf(stdout, "--------------------------------"); + (void) fprintf(stdout, "--------------------------------"); + (void) fprintf(stdout, "\n"); + + (void) snprintf(controller, sizeof (controller), "%u", + ctl_attr.controller_id); + (void) printf("c%s\t\t", controller); + + (void) print_ctl_attr(&ctl_attr); + (void) fprintf(stdout, "\n"); + + return (SUCCESS); +} + +static int +print_array_table(raid_obj_handle_t ctl_handle, raid_obj_handle_t array_handle) +{ + raidcfg_controller_t ctl_attr; + raidcfg_array_t array_attr; + raidcfg_array_t subarray_attr; + raidcfg_arraypart_t arraypart_attr; + raidcfg_task_t task_attr; + + raid_obj_handle_t subarray_handle; + raid_obj_handle_t arraypart_handle; + raid_obj_handle_t task_handle; + + char array[8]; + char arraypart[8]; + int ret; + int i; + + /* Controller attribute */ + if ((ret = raidcfg_get_attr(ctl_handle, &ctl_attr)) < 0) { + (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); return (FAILURE); } - if (ioctl(fd, RAID_NUMVOLUMES, &nvols)) { - raidctl_error("RAID_NUMVOLUMES"); - goto fail; + /* Array attribute */ + if ((ret = raidcfg_get_attr(array_handle, &array_attr)) < 0) { + (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); + return (FAILURE); } - for (i = 0; i < nvols; i++) { - config.unitid = i; - if (ioctl(fd, RAID_GETCONFIG, &config)) { - raidctl_error("RAID_GETCONFIG"); - goto fail; + /* print header */ + (void) fprintf(stdout, gettext("Volume\t\t\tSize\tStripe\tStatus\t" + " Cache\tRAID")); + (void) fprintf(stdout, "\n"); + (void) fprintf(stdout, gettext("\tSub\t\t\tSize\t\t\tLevel")); + (void) fprintf(stdout, "\n"); + (void) fprintf(stdout, gettext("\t\tDisk\t\t\t\t\t")); + (void) fprintf(stdout, "\n"); + (void) fprintf(stdout, "--------------------------------"); + (void) fprintf(stdout, "--------------------------------"); + (void) fprintf(stdout, "\n"); + + /* print array */ + (void) snprintf(array, sizeof (array), "c%ut%llud%llu", + ctl_attr.controller_id, array_attr.tag.idl.target_id, + array_attr.tag.idl.lun); + (void) fprintf(stdout, "%s\t\t\t", array); + + /* check if array is in sync state */ + task_handle = raidcfg_list_head(array_handle, OBJ_TYPE_TASK); + if (task_handle > 0) { + (void) raidcfg_get_attr(task_handle, &task_attr); + if (task_attr.task_func == TASK_FUNC_BUILD) { + array_attr.state = ARRAY_STATE_SYNC; } - if (config.ndisks != 0) { - /* there is a RAID volume in this slot */ - if (config.targetid != t) { - wrong_targ++; - continue; + } else { + subarray_handle = raidcfg_list_head(array_handle, + OBJ_TYPE_ARRAY); + while (subarray_handle > 0) { + task_handle = raidcfg_list_head(subarray_handle, + OBJ_TYPE_TASK); + if (task_handle > 0) { + (void) raidcfg_get_attr(task_handle, + &task_attr); + if (task_attr.task_func == TASK_FUNC_BUILD) { + array_attr.state = ARRAY_STATE_SYNC; + } + break; } - /* and it's our target */ - break; + subarray_handle = raidcfg_list_next(subarray_handle); } } - if (i == nvols) { - /* we found no RAID volumes */ - (void) fprintf(stderr, gettext("No RAID volumes exist on " - "controller '%d'\n"), ctrl); - goto fail; - } + (void) print_array_attr(&array_attr); + (void) fprintf(stdout, "\n"); - if (wrong_targ == nvols) { - /* we found RAID volumes, but none matched */ - (void) fprintf(stderr, - gettext("RAID volume 'c%dt%dd0' does not exist\n"), - ctrl, t); - goto fail; - } + /* Print sub array */ + i = 0; /* Count sub array number */ + subarray_handle = raidcfg_list_head(array_handle, OBJ_TYPE_ARRAY); + while (subarray_handle > 0) { + if ((ret = raidcfg_get_attr(subarray_handle, + &subarray_attr)) < 0) { + (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); + return (FAILURE); + } - /* if this volume is a stripe, all data will be lost */ - if (config.raid_level == RAID_STRIPE) { - if (disk_mounted(d)) { - (void) fprintf(stderr, gettext("Cannot delete " - "RAID0 volume, \"%s\" is mounted.\n"), d); - return (INVALID_ARG); + /* Use sub0/sub1 here, not cxtxd0 for subarray */ + (void) snprintf(array, sizeof (array), "sub%u", i++); + (void) fprintf(stdout, "\t%s\t\t", array); + + /* Check if array is in sync */ + task_handle = raidcfg_list_head(subarray_handle, OBJ_TYPE_TASK); + if (task_handle > 0) { + (void) raidcfg_get_attr(task_handle, &task_attr); + if (task_attr.task_func == TASK_FUNC_BUILD) { + subarray_attr.state = ARRAY_STATE_SYNC; + } } - if (!force) { - (void) fprintf(stderr, gettext("Deleting volume " - "c%dt%dd0 will destroy all data it contains, " - "proceed (%s/%s)? "), ctrl, t, yeschr, nochr); - if (!yes()) { - (void) fprintf(stderr, gettext("RAID volume " - "c%dt%dd0 not deleted.\n\n"), ctrl, t); - (void) close(fd); - return (SUCCESS); + + (void) print_array_attr(&subarray_attr); + (void) fprintf(stdout, "\n"); + + /* Print subarraypart */ + arraypart_handle = raidcfg_list_head(subarray_handle, + OBJ_TYPE_ARRAY_PART); + while (arraypart_handle > 0) { + if ((ret = raidcfg_get_attr(arraypart_handle, + &arraypart_attr)) < 0) { + (void) fprintf(stderr, "%s\n", + raidcfg_errstr(ret)); + return (FAILURE); } + + if (arraypart_attr.tag.cidl.bus == MAX64BIT) { + (void) snprintf(arraypart, sizeof (arraypart), + gettext("N/A")); + } else { + (void) snprintf(arraypart, sizeof (arraypart), + "%llu.%llu.%llu", + arraypart_attr.tag.cidl.bus, + arraypart_attr.tag.cidl.target_id, + arraypart_attr.tag.cidl.lun); + } + + (void) fprintf(stdout, "\t\t%s\t", arraypart); + (void) print_arraypart_attr(&arraypart_attr); + (void) fprintf(stdout, "\n"); + arraypart_handle = raidcfg_list_next(arraypart_handle); } + subarray_handle = raidcfg_list_next(subarray_handle); } - /* if this volume is a mirror, prompt user to verify the operation */ - else if (config.raid_level == RAID_MIRROR && !force) { - (void) fprintf(stderr, gettext("Are you sure you want to " - "delete RAID-1 Volume c%dt%dd0(%s/%s)? "), - ctrl, t, yeschr, nochr); - if (!yes()) { - (void) fprintf(stderr, gettext("RAID volume " - "c%dt%dd0 not deleted.\n\n"), ctrl, t); - (void) close(fd); - return (SUCCESS); + + /* Print arraypart */ + arraypart_handle = raidcfg_list_head(array_handle, + OBJ_TYPE_ARRAY_PART); + while (arraypart_handle > 0) { + if ((ret = raidcfg_get_attr(arraypart_handle, + &arraypart_attr)) < 0) { + (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); + return (FAILURE); } + + if (arraypart_attr.tag.cidl.bus == MAX64BIT) { + (void) snprintf(arraypart, sizeof (arraypart), + gettext("N/A")); + } else { + (void) snprintf(arraypart, sizeof (arraypart), + "%llu.%llu.%llu", + arraypart_attr.tag.cidl.bus, + arraypart_attr.tag.cidl.target_id, + arraypart_attr.tag.cidl.lun); + } + + (void) fprintf(stdout, "\t\t%s\t", arraypart); + (void) print_arraypart_attr(&arraypart_attr); + (void) fprintf(stdout, "\n"); + arraypart_handle = raidcfg_list_next(arraypart_handle); } - if (ioctl(fd, RAID_DELETE, &t)) { - perror("RAID_DELETE"); - goto fail; + return (SUCCESS); +} + +static int +print_disk_table(raid_obj_handle_t ctl_handle, raid_obj_handle_t disk_handle) +{ + raidcfg_controller_t ctl_attr; + raidcfg_disk_t disk_attr; + char disk[8]; + int ret; + + if ((ret = raidcfg_get_attr(ctl_handle, &ctl_attr)) < 0) { + (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); + return (FAILURE); } - /* reconfigure all disks, except targetid */ - for (j = 1; j < config.ndisks; j++) { - (void) do_config_change_state(CFGA_CMD_CONFIGURE, - config.disk[j], ctrl); + if ((ret = raidcfg_get_attr(disk_handle, &disk_attr)) < 0) { + (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); + return (FAILURE); } - (void) fprintf(stderr, gettext("Volume 'c%dt%dd0' deleted.\n"), - ctrl, target); - (void) close(fd); + /* Print header */ + (void) fprintf(stdout, gettext("Disk\tVendor\tProduct\t\tCapacity\t" + "Status\tHSP")); + (void) fprintf(stdout, "\n"); + (void) fprintf(stdout, "--------------------------------"); + (void) fprintf(stdout, "--------------------------------"); + (void) fprintf(stdout, "\n"); + + + (void) snprintf(disk, sizeof (disk), "%llu.%llu.%llu", + disk_attr.tag.cidl.bus, + disk_attr.tag.cidl.target_id, + disk_attr.tag.cidl.lun); + + (void) fprintf(stdout, "%s\t", disk); + + (void) print_disk_attr(ctl_handle, disk_handle, &disk_attr); + (void) fprintf(stdout, "\n"); + return (SUCCESS); +} -fail: - (void) close(fd); - return (FAILURE); +/* + * print_ctl_attr(attrp) + * This function prints attribute of specified controller, and return + * result as SUCCESS or FAILURE. + */ +static int +print_ctl_attr(raidcfg_controller_t *attrp) +{ + char type[CONTROLLER_TYPE_LEN]; + char version[CONTROLLER_FW_LEN]; + + if (attrp == NULL) { + return (FAILURE); + } + + (void) snprintf(type, sizeof (type), "%s", attrp->controller_type); + (void) fprintf(stdout, "%-16s", type); + + (void) snprintf(version, sizeof (version), "%s", attrp->fw_version); + (void) fprintf(stdout, "%s", version); + + return (SUCCESS); } -static void -getimagetype(uint8_t *rombuf, int *imagetype) +/* + * print_array_attr(attrp) + * This function prints attribute of specified array, and return + * result as SUCCESS or FAILURE. + */ +static int +print_array_attr(raidcfg_array_t *attrp) { - uint8_t type = rombuf[gw(&rombuf[PCIR_OFF]) + PCIR_CODETYPE]; - if (type == 0) { - *imagetype = BIOS_IMAGE; - return; + char capacity[8]; + char stripe_size[8]; + char raid_level[8]; + + if (attrp == NULL) { + return (FAILURE); + } + + if (attrp->capacity != MAX64BIT) { + if (size_to_string(attrp->capacity, capacity, 8) != SUCCESS) { + return (FAILURE); + } + (void) printf("%s\t", capacity); + } else { + (void) printf(gettext("N/A\t")); } - if (type == 1) { - *imagetype = FCODE_IMAGE; - return; + + if (attrp->stripe_size != MAX32BIT) { + (void) snprintf(stripe_size, sizeof (stripe_size), "%uK", + attrp->stripe_size / 1024); + (void) printf("%s\t", stripe_size); + } else { + (void) printf(gettext("N/A\t")); } + + switch (attrp->state) { + case ARRAY_STATE_OPTIMAL: + (void) printf("%-8s", gettext("OPTIMAL")); + break; + case ARRAY_STATE_DEGRADED: + (void) printf("%-8s", gettext("DEGRADED")); + break; + case ARRAY_STATE_FAILED: + (void) printf("%-8s", gettext("FAILED")); + break; + case ARRAY_STATE_SYNC: + (void) printf("%-8s", gettext("SYNC")); + break; + default: + (void) printf("%-8s", gettext("N/A")); + break; + } + (void) printf(" "); + + if (attrp->write_policy == CACHE_WR_OFF) { + (void) printf(gettext("OFF")); + } else if (attrp->write_policy == CACHE_WR_ON) { + (void) printf(gettext("ON")); + } else { + (void) printf(gettext("N/A")); + } + (void) printf("\t"); + + switch (attrp->raid_level) { + case RAID_LEVEL_0: + (void) sprintf(raid_level, "RAID0"); + break; + case RAID_LEVEL_1: + (void) sprintf(raid_level, "RAID1"); + break; + case RAID_LEVEL_1E: + (void) sprintf(raid_level, "RAID1E"); + break; + case RAID_LEVEL_5: + (void) sprintf(raid_level, "RAID5"); + break; + case RAID_LEVEL_10: + (void) sprintf(raid_level, "RAID10"); + break; + case RAID_LEVEL_50: + (void) sprintf(raid_level, "RAID50"); + break; + default: + (void) snprintf(raid_level, sizeof (raid_level), + gettext("N/A")); + break; + } + (void) printf("%s", raid_level); + + return (SUCCESS); } +/* + * print_arraypart_attr(attrp) + * This function print attribute of specified arraypart, and return + * result as SUCCESS or FAILURE. + */ static int -getfcodever(uint8_t *rombuf, uint32_t nbytes, char **fcodeversion) +print_arraypart_attr(raidcfg_arraypart_t *attrp) { - int x, y, size; - int found_1 = 0, found_2 = 0; - int image_length = 0; - int no_of_images = 0; - uint8_t *rombuf_1 = NULL; - uint16_t image_units = 0; + char size[8]; - /* - * Single Image - Open firmware image - */ - if (rombuf[gw(&rombuf[PCIR_OFF]) + PCIR_CODETYPE] == 1) { - rombuf_1 = rombuf + gw(rombuf + PCIR_OFF) + PCI_PDS_INDICATOR; - no_of_images = 1; - goto process_image; + if (attrp == NULL) { + return (FAILURE); } - /* - * Combined Image - First Image - x86/PC-AT Bios image - */ - if (rombuf[gw(&rombuf[PCIR_OFF]) + PCIR_CODETYPE] != 0) { - (void) fprintf(stderr, gettext("This is neither open image" - " nor Bios/Fcode combined image\n")); - return (1); + if (attrp->size != MAX64BIT) { + if (size_to_string(attrp->size, size, 8) != SUCCESS) { + return (FAILURE); + } + (void) printf("%s\t", size); + } else { + (void) printf(gettext("N/A\t")); } - /* - * Seek to 2nd Image - */ - rombuf_1 = rombuf + gw(rombuf + PCI_ROM_PCI_DATA_STRUCT_PTR); - image_units = gw(rombuf_1 + PCI_PDS_IMAGE_LENGTH); - image_length = image_units * PCI_IMAGE_UNIT_SIZE; - rombuf_1 += image_length; + (void) printf("\t"); - /* - * Combined Image - Second Image - Open Firmware image - */ - if (rombuf_1[PCI_PDS_CODE_TYPE] != 1) { - (void) fprintf(stderr, gettext("This is neither open image" - " nor Bios/Fcode combined image\n")); - return (1); + if (attrp->state == DISK_STATE_GOOD) { + (void) printf(gettext("GOOD")); + } else if (attrp->state == DISK_STATE_FAILED) { + (void) printf(gettext("FAILED")); + } else { + (void) printf(gettext("N/A")); } - rombuf_1 += PCI_PDS_INDICATOR; - no_of_images = 2; + (void) printf("\t"); -process_image: - /* - * This should be the last image - */ - if (*rombuf_1 != LAST_IMAGE) { - (void) fprintf(stderr, gettext("This is not a valid " - "Bios/Fcode image file\n")); - return (1); + return (SUCCESS); +} + +/* + * print_disk_attr(ctl_handle, disk_handle, attrp) + * This function prints attribute of specified disk, and return + * result as SUCCESS or FAILURE. + */ +static int +print_disk_attr(raid_obj_handle_t ctl_handle, raid_obj_handle_t disk_handle, + raidcfg_disk_t *attrp) +{ + char vendor[DISK_VENDER_LEN]; + char product[DISK_PRODUCT_LEN]; + char capacity[16]; + char hsp[16]; + + raid_obj_handle_t hsp_handle; + raidcfg_hsp_t hsp_attr; + raidcfg_controller_t ctl_attr; + int ret; + char is_indent; + + if (attrp == NULL) { + return (FAILURE); } - /* - * Scan through the bios/fcode file to get the fcode version - * 0x12 and 0x7 indicate the start of the fcode version string - */ - for (x = 0; x < (nbytes - 8); x++) { - if ((rombuf[x] == FCODE_VERS_KEY1) && - (rombuf[x+1] == FCODE_VERS_KEY2) && - (rombuf[x+2] == 'v') && (rombuf[x+3] == 'e') && - (rombuf[x+4] == 'r') && (rombuf[x+5] == 's') && - (rombuf[x+6] == 'i') && (rombuf[x+7] == 'o') && - (rombuf[x+8] == 'n')) { - found_1 = 1; - break; + (void) snprintf(vendor, sizeof (vendor), "%s", attrp->vendorid); + (void) printf("%s\t", vendor); + + (void) snprintf(product, sizeof (product), "%s", attrp->productid); + (void) printf("%s\t", product); + + if (attrp->capacity != MAX64BIT) { + if (size_to_string(attrp->capacity, capacity, 16) != SUCCESS) { + return (FAILURE); } + (void) printf("%s\t\t", capacity); + } else { + (void) printf(gettext("N/A")); } - /* - * Store the version string if we have found the beginning of it - */ - if (found_1) { - while (x > 0) { - if (rombuf[--x] == FCODE_VERS_KEY1) { - if (rombuf[x-1] != FCODE_VERS_KEY1) { - x++; - } - break; + if (attrp->state == DISK_STATE_GOOD) { + (void) printf(gettext("GOOD")); + } else if (attrp->state == DISK_STATE_FAILED) { + (void) printf(gettext("FAILED")); + } else { + (void) printf(gettext("N/A")); + } + (void) printf("\t"); + + /* Controller attribute */ + if ((ret = raidcfg_get_attr(ctl_handle, &ctl_attr)) < 0) { + (void) fprintf(stderr, "%s\n", raidcfg_errstr(ret)); + return (FAILURE); + } + + hsp_handle = raidcfg_list_head(disk_handle, OBJ_TYPE_HSP); + if (hsp_handle == 0) { + (void) printf(gettext("N/A\n")); + } else { + is_indent = FALSE; + while (hsp_handle > 0) { + if ((ret = raidcfg_get_attr(hsp_handle, + &hsp_attr)) < 0) { + (void) fprintf(stderr, "%s\n", + raidcfg_errstr(ret)); + return (FAILURE); } - } - if (x > 0) { - *fcodeversion = (char *)malloc(rombuf[x] + 1); - for (y = 0; y < rombuf[x]; y++) { - (*fcodeversion)[y] = rombuf[x+y+1]; + + if (is_indent == TRUE) { + (void) printf("\t\t\t\t\t\t\t"); + } else { + is_indent = TRUE; } - (*fcodeversion)[y] = '\0'; - } else { - found_1 = 0; - } - } - /* - * Scan through the bios/fcode file to get the Bios version - * "@(#)" string indicates the start of the Bios version string - * Append this version string, after already existing fcode version. - */ - if (no_of_images == 2) { - for (x = 0; x < (nbytes - 4); x++) { - if ((rombuf[x] == '@') && (rombuf[x+1] == '(') && - (rombuf[x+2] == '#') && (rombuf[x+3] == ')')) { - found_2 = 1; - break; + if (hsp_attr.type == HSP_TYPE_LOCAL) { + (void) snprintf(hsp, sizeof (hsp), + "c%ut%llud%llu", + ctl_attr.controller_id, + hsp_attr.tag.idl.target_id, + hsp_attr.tag.idl.lun); + (void) printf("%s\n", hsp); + } else if (hsp_attr.type == HSP_TYPE_GLOBAL) { + (void) printf(gettext("Global\n")); + } else { + return (FAILURE); } - } - if (found_2) { - x += 4; - (*fcodeversion)[y] = '\n'; - size = y + strlen((char *)(rombuf + x)) + - strlen(BIOS_STR) + 2; - *fcodeversion = (char *)realloc((*fcodeversion), size); - y++; - (*fcodeversion)[y] = '\0'; - (void) strlcat(*fcodeversion, BIOS_STR, size); - (void) strlcat(*fcodeversion, (char *)(rombuf + x), - size); + hsp_handle = raidcfg_list_next(hsp_handle); } } - - return ((found_1 || found_2) ? 0 : 1); + return (SUCCESS); } + +/* + * print_indent(indent) + * This function prints specified number of tab characters. It's used to + * format layout. + */ static void -getfwver(uint8_t *rombuf, char *fwversion) +print_indent(uint8_t indent) { - (void) snprintf(fwversion, 8, "%d.%.2d.%.2d.%.2d", - rombuf[FW_ROM_OFFSET_VERSION + 3], - rombuf[FW_ROM_OFFSET_VERSION + 2], - rombuf[FW_ROM_OFFSET_VERSION + 1], - rombuf[FW_ROM_OFFSET_VERSION + 0]); + uint32_t i; + for (i = 0; i < indent; i++) { + (void) fprintf(stdout, "\t"); + } } +/* + * get_disk_handle_cidl(ctl_tag, disks_argp, comps_num, handlespp) + * This function parses the string of disk argument, and gets the disks tag + * and separators from the string. Then it translates the tag to handle, and + * stores handles and separators to new buffer pointed by parameter handlespp. + * The format of disk_arg must be C:ID:L, for example, it is 0.1.0. The first + * "0" is channel number, and the second "1" is target number, and the third + * "0" is LUN number. The disk tags are separated by comma and parenthesis. + * Function returns SUCCESS or FAILURE. + */ static int -getbioscodever(uint8_t *rombuf, uint32_t nbytes, char **biosversion) +get_disk_handle_cidl(uint32_t ctl_tag, char *disks_argp, int *comps_nump, + raid_obj_handle_t **handlespp) { - int x, size; - int found = 0; + int len = 0; + int i = 0, j = 0; + char *p, *t; + char *delimit = " "; + char *disks_str; + disk_tag_t disk_tag; + + if (disks_argp == NULL || comps_nump == NULL) { + return (FAILURE); + } - for (x = 0; x < (nbytes - 4); x++) { - if ((rombuf[x] == '@') && (rombuf[x+1] == '(') && - (rombuf[x+2] == '#') && (rombuf[x+3] == ')')) { - found = 1; - break; - } + p = disks_argp; + len = strlen(disks_argp); + + if ((disks_str = (char *)malloc(3 * len + 4)) == NULL) { + return (FAILURE); + } + + /* Insert whitespace between disk tags, '(' , and ')' */ + disks_str[j ++] = '('; + disks_str[j ++] = ' '; + + while (p[i] != '\0') { + if (p[i] == ')' || p[i] == '(') { + disks_str[j ++] = ' '; + disks_str[j ++] = p[i]; + disks_str[j ++] = ' '; + } else + disks_str[j ++] = p[i]; + i ++; + } + disks_str[j ++] = ' '; + disks_str[j ++] = ')'; + disks_str[j] = '\0'; + + len = strlen(disks_str) + 1; + + if ((t = (char *)malloc(len)) == NULL) { + return (FAILURE); } + (void) memcpy(t, disks_str, len); + p = strtok(t, delimit); + while (p != NULL) { + (*comps_nump)++; + p = strtok(NULL, delimit); + } + free(t); - if (found) { - x += 4; - size = strlen((char *)(rombuf + x)) + strlen(BIOS_STR) + 1; - *biosversion = (char *)realloc((*biosversion), size); - bcopy((char *)(rombuf + x), *biosversion, size - 1); - (*biosversion)[size - 1] = '\0'; + *handlespp = calloc(*comps_nump, sizeof (raid_obj_handle_t)); + if (*handlespp == NULL) { + return (FAILURE); } - return (found); + for (i = 0; i < *comps_nump; i++) + (*handlespp)[i] = INIT_HANDLE_VALUE; + + i = 0; + p = strtok(disks_str, delimit); + while (p != NULL) { + if (*p == '(') { + (*handlespp)[i] = OBJ_SEPARATOR_BEGIN; + } else if (*p == ')') { + (*handlespp)[i] = OBJ_SEPARATOR_END; + } else { + if (get_disk_tag_cidl(p, &disk_tag) != SUCCESS) { + free(*handlespp); + free(disks_str); + return (INVALID_ARG); + } + (*handlespp)[i] = + raidcfg_get_disk(raidcfg_get_controller(ctl_tag), + disk_tag); + if ((*handlespp)[i] <= 0) { + (void) fprintf(stderr, "%s\n", + raidcfg_errstr((*handlespp)[i])); + free(*handlespp); + free(disks_str); + return (FAILURE); + } + } + p = strtok(NULL, delimit); + i++; + } + free(disks_str); + return (SUCCESS); } +/* + * get_disk_handle_ctd(disks_num, disks_argpp, ctl_tagp, disks_handlep) + * This function parses string of single disk with "ctd" format, for example, + * c0t0d0, and translates it to controller tag and disk tag. + * Then it calls lib api and get disk handle. The controller tag and disk + * handle are both returned by out parameters. + * The return value is SUCCESS or FAILURE. + */ static int -checkfile(uint8_t *rombuf, uint32_t nbytes, uint32_t chksum, int *imagetype) +get_disk_handle_ctd(int disks_num, char **disks_argpp, uint32_t *ctl_tagp, + raid_obj_handle_t *disks_handlep) { - char *imageversion = NULL; - char *biosversion = NULL; - char *fwversion; + raid_obj_handle_t ctl_handle; + disk_tag_t disk_tag; + uint32_t ctl_id; + int i; + int ret; - fwversion = (char *)malloc(8); + if (disks_handlep == NULL) { + return (FAILURE); + } - if (gw(&rombuf[0]) == PCIROM_SIG) { + for (i = 0; i < disks_num; i++) { + if (get_disk_tag_ctd(disks_argpp[i], &disk_tag, &ctl_id) != + SUCCESS) { + return (INVALID_ARG); + } - *imagetype = UNKNOWN_IMAGE; - getimagetype(rombuf, imagetype); + *ctl_tagp = ctl_id; - if (*imagetype == FCODE_IMAGE) { - if (getfcodever(rombuf, nbytes, &imageversion) == 0 && - imageversion != NULL) { - (void) printf(gettext("Image file contains " - "fcode version \t%s\n"), imageversion); - free(imageversion); + if (i == 0) { + ctl_handle = raidcfg_get_controller(*ctl_tagp); + if (ctl_handle <= 0) { + (void) fprintf(stderr, "%s\n", + raidcfg_errstr(ctl_handle)); + return (FAILURE); } - } else if (*imagetype == BIOS_IMAGE) { - if (getbioscodever(rombuf, nbytes, &biosversion) == 1 && - biosversion != NULL) { - (void) printf(gettext("Image file contains " - "BIOS version \t%s\n"), biosversion); - free(biosversion); + ret = raidcfg_open_controller(ctl_handle, NULL); + if (ret < 0) { + (void) fprintf(stderr, "%s\n", + raidcfg_errstr(ret)); + return (FAILURE); } - } else { - /* When imagetype equals to UNKNOWN_IMAGE */ - return (-1); } - } else if (gw(&rombuf[3]) == FW_ROM_ID) { - if (chksum != 0) { - (void) fprintf(stderr, - gettext("The ROM checksum appears bad " - "(%d)\n"), chksum); - return (-1); - } - getfwver(rombuf, fwversion); - - if ((gw(&rombuf[FW_ROM_OFFSET_CHIP_TYPE]) & - MPI_FW_HEADER_PID_PROD_MASK) == - MPI_FW_HEADER_PID_PROD_IM_SCSI) { - (void) printf(gettext("ROM image contains " - "MPT firmware version %s " - "(w/Integrated Mirroring)\n"), - fwversion); - } else { - (void) printf(gettext("ROM image contains " - "MPT firmware ""version %s\n"), - fwversion); - } - free(fwversion); - } else { - -#ifdef DEBUG - (void) fprintf(stderr, "Not valid FCODE image %x\n", gw(&rombuf[0])); -#else - (void) fprintf(stderr, gettext("Not valid FCODE image\n")); -#endif - return (-1); + if ((disks_handlep[i] = + raidcfg_get_disk(ctl_handle, disk_tag)) < 0) { + (void) fprintf(stderr, "%s\n", + raidcfg_errstr(disks_handlep[i])); + (void) raidcfg_close_controller(ctl_handle, NULL); + return (FAILURE); + } } - return (0); + + return (SUCCESS); } +/* + * get_ctl_tag(argp) + * This function translates controller string to tag. The return value is + * SUCCESS if the string has legal format and is parsed successfully, + * or FAILURE if it fails. + */ static int -updateflash(uint8_t *rombuf, uint32_t nbytes, char *devctl) +get_ctl_tag(char *argp, uint32_t *ctl_tagp) { - int fd = 0; - update_flash_t flashdata; - - fd = open(devctl, O_RDONLY); - if (fd == -1) { - perror(devctl); - return (-1); - } - (void) memset(&flashdata, 0, sizeof (flashdata)); - flashdata.ptrbuffer = (caddr_t)rombuf; - flashdata.size = nbytes; - if ((rombuf[0] == 0x55) && (rombuf[1] == 0xaa)) { - flashdata.type = FW_TYPE_FCODE; - } else { - flashdata.type = FW_TYPE_UCODE; - } - - if (ioctl(fd, RAID_UPDATEFW, &flashdata)) { - raidctl_error("RAID_UPDATEFW"); - (void) close(fd); - return (-1); + if (argp == NULL || is_fully_numeric(argp) == FALSE || + ctl_tagp == NULL) { + return (FAILURE); } - - (void) close(fd); - return (0); + *ctl_tagp = (atoi(argp)); + return (SUCCESS); } +/* + * get_array_tag(argp, ctl_tagp, array_tagp) + * This function parses array string to get array tag and controller tag. + * The return value is SUCCESS if the string has legal format, or + * FAILURE if it fails. + */ static int -readfile(char *filespec, uint8_t **rombuf, uint32_t *nbytes, uint32_t *chksum) +get_array_tag(char *argp, uint32_t *ctl_tagp, array_tag_t *array_tagp) { - struct stat statbuf; - uint32_t count; - uint32_t checksum = 0; - int fd, i; - uint8_t *filebuf; + char *t = NULL; + char *cp = NULL; + char *tp = NULL; + char *dp = NULL; + + uint32_t value_c = MAX32BIT; + uint32_t value_t = MAX32BIT; + uint32_t value_d = MAX32BIT; + int len = 0; - if ((fd = open((const char *)filespec, O_RDONLY | O_NDELAY)) == -1) { - perror(filespec); - return (-1); + if (argp == NULL || (len = strlen(argp)) == 0 || + array_tagp == NULL) { + return (FAILURE); } - if (fstat(fd, &statbuf) != 0) { - perror("fstat"); - (void) fprintf(stderr, - gettext("Error getting stats on file\n")); - (void) close(fd); - return (-1); + t = (char *)malloc(len + 1); + if (t == NULL) { + return (FAILURE); } -#ifdef DEBUG - (void) printf("Filesize = %ld\n", statbuf.st_size); -#endif + (void) memcpy(t, argp, len + 1); - filebuf = (uint8_t *)realloc(*rombuf, statbuf.st_size + *nbytes); + /* Now remmber to release t memory if exception occurs */ + if (((dp = strchr(t, 'd')) == NULL) || + ((tp = strchr(t, 't')) == NULL) || + ((cp = strchr(t, 'c')) == NULL)) { + free(t); + return (FAILURE); + } + cp = t; - count = read(fd, filebuf + *nbytes, statbuf.st_size); - (void) close(fd); - if (count != statbuf.st_size) { - perror("size check"); - (void) fprintf(stderr, gettext("File is corrupt\n")); - return (-1); + *dp = '\0'; + dp++; + *tp = '\0'; + tp++; + cp++; + + if (is_fully_numeric(dp) == FALSE || + is_fully_numeric(tp) == FALSE || + is_fully_numeric(cp) == FALSE) { + free(t); + return (FAILURE); } - for (i = 0; i < *nbytes; i++) - checksum += filebuf[i] << (8 * (i & 3)); + value_c = atoi(cp); + value_t = atoi(tp); + value_d = atoi(dp); + + array_tagp->idl.target_id = value_t; + array_tagp->idl.lun = value_d; - *rombuf = filebuf; - *nbytes = *nbytes + count; - *chksum = checksum; + if (ctl_tagp != NULL) { + *ctl_tagp = value_c; + } - return (0); + free(t); + return (SUCCESS); } +/* + * get_disk_tag_ctd(argp, disk_tagp) + * This function parses disk string of ctd format, and translates it to + * disk tag and controller tag. The tags is returned by out parameters. + * The return value is SUCCESS if the string has legal format, or FAILURE + * if it fails. + */ static int -yes(void) +get_disk_tag_ctd(char *argp, disk_tag_t *disk_tagp, uint32_t *ctl_tag) { - int i, b; - char ans[SCHAR_MAX + 1]; + char *t = NULL; + char *cp = NULL; + char *tp = NULL; + char *dp = NULL; - for (i = 0; ; i++) { - b = getchar(); - if (b == '\n' || b == '\0' || b == EOF) { - ans[i] = 0; - break; - } - if (i < SCHAR_MAX) - ans[i] = b; + uint32_t value_c = MAX32BIT; + uint32_t value_t = MAX32BIT; + uint32_t value_d = MAX32BIT; + + int len = 0; + + if (argp == NULL || (len = strlen(argp)) == 0 || + disk_tagp == NULL) { + return (FAILURE); } - if (i >= SCHAR_MAX) { - i = SCHAR_MAX; - ans[SCHAR_MAX] = 0; + + t = (char *)malloc(len + 1); + if (t == NULL) { + return (FAILURE); + } + + (void) memcpy(t, argp, len + 1); + + /* Now remmber to release t memory if exception occurs */ + if (((dp = strchr(t, 'd')) == NULL) || + ((tp = strchr(t, 't')) == NULL) || + ((cp = strchr(t, 'c')) == NULL)) { + free(t); + return (FAILURE); } - if ((i != 0) && ((strncmp(yeschr, ans, i)) == 0)) - return (1); + cp = t; + + *dp = '\0'; + dp++; + *tp = '\0'; + tp++; + cp++; - return (0); + if (is_fully_numeric(dp) == FALSE || + is_fully_numeric(tp) == FALSE || + is_fully_numeric(cp) == FALSE) { + free(t); + return (FAILURE); + } + + value_c = atoi(cp); + value_t = atoi(tp); + value_d = atoi(dp); + + disk_tagp->cidl.bus = 0; + disk_tagp->cidl.target_id = value_t; + disk_tagp->cidl.lun = value_d; + *ctl_tag = value_c; + + free(t); + return (SUCCESS); } +/* + * get_disk_tag_cidl(argp, disk_tagp) + * This function parses disk string of cidl format and translates it to tag. + * The return value is disk tag if the string has legal format, or FAILURE + * if it fails. + */ static int -do_flash(int c, char *fpath, int force) +get_disk_tag_cidl(char *argp, disk_tag_t *disk_tagp) { - char devctl[MAXPATHLEN] = {0}; - char buf[MAXPATHLEN] = {0}; - int rv = 0; - int imagetype; - uint32_t nbytes = 0; - uint32_t chksum; - uint8_t *rombuf = NULL; - char cwd[MAXPATHLEN]; + int len = 0; + char *p = NULL; + char *t = NULL; + char *dot1p = NULL; + char *dot2p = NULL; - /* - * Read fw file - */ - rv = readfile(fpath, &rombuf, &nbytes, &chksum); - if (rv != 0) { + if (argp == NULL || (len = strlen(argp)) == 0) { return (FAILURE); } - (void) getcwd(cwd, sizeof (cwd)); + if (disk_tagp == NULL) { + return (FAILURE); + } - (void) chdir(DEVDIR); + t = (char *)malloc(len + 1); + if (t == NULL) { + return (FAILURE); + } - /* Get link from "/dev/cfg" */ - (void) snprintf(buf, sizeof (buf), "/dev/cfg/c%d", c); - if (get_link_path(buf, devctl) != 0) { - (void) fprintf(stderr, - gettext("Invalid controller '%d'\n"), c); - return (INVALID_ARG); + (void) memcpy(t, argp, len + 1); + p = t; + + dot2p = strrchr(p, '.'); + if (dot2p == NULL) { + free(t); + return (FAILURE); } + *dot2p = '\0'; + dot2p++; - /* Check File */ - rv = checkfile(rombuf, nbytes, chksum, &imagetype); - if (rv != 0) { + dot1p = strrchr(p, '.'); + if (dot1p == NULL) { + free(t); return (FAILURE); } + *dot1p = '\0'; + dot1p++; - /* Confirm */ - if (!force) { - (void) fprintf(stderr, gettext("Update flash image on " - "controller %d (%s/%s)? "), c, yeschr, nochr); - if (!yes()) { - (void) fprintf(stderr, gettext("Controller %d not " - "flashed.\n\n"), c); - return (SUCCESS); - } + /* Assert only 2 dots in this string */ + if (strrchr(p, '.') != NULL) { + free(t); + return (FAILURE); } - /* Do Flash */ - if (updateflash(rombuf, nbytes, devctl)) { - (void) fprintf(stderr, gettext("Flash not updated on " - "Controller %d.\n\n"), c); - return (INVALID_ARG); + while (*p == ' ') + p++; + + if (is_fully_numeric(p) == FALSE || + is_fully_numeric(dot1p) == FALSE || + is_fully_numeric(dot2p) == FALSE) { + free(t); + return (FAILURE); } - (void) printf(gettext("Flash updated successfully.\n\n")); + + disk_tagp->cidl.bus = atoi(p); + disk_tagp->cidl.target_id = atoi(dot1p); + disk_tagp->cidl.lun = atoi(dot2p); + + free(t); return (SUCCESS); } +/* + * calc_size(sizep, valp) + * This function calculates the value represented by string sizep. + * The string sizep can be decomposed into three parts: an initial, + * possibly empty, sequence of white-space characters; a subject digital + * sequence interpreted as an integer with unit k/K/m/M/g/G/t/T; and a + * final string of one or more unrecognized characters or white-sapce + * characters, including the terminating null. If unrecognized character + * exists or overflow happens, the conversion must fail and return + * INVALID_ARG. If the conversion is performed successfully, result will + * be saved into valp and function returns SUCCESS. It returns FAILURE + * when memory allocation fails. + */ static int -fully_numeric(char *str) +calc_size(char *sizep, uint64_t *valp) { - int size = strlen(str); - int i; + int len; + uint64_t size; + uint64_t unit; + char *t = NULL; + char *tailp = NULL; - for (i = 0; i < size; i++) { - if (i == 0 && str[i] == '-' && size != 1) - continue; - if (!isdigit(str[i])) - return (0); + if (sizep == NULL || valp == NULL) { + return (INVALID_ARG); } - return (1); -} -/* - * Useful parsing macros - */ -#define must_be(s, c) if (*s++ != c) return (0) -#define skip_digits(s) while (isdigit(*s)) s++ + len = strlen(sizep); + if (len == 0) { + return (INVALID_ARG); + } + + t = (char *)malloc(len + 1); + if (t == NULL) { + return (FAILURE); + } + + (void) memcpy(t, sizep, len + 1); + + switch (*(t + len - 1)) { + case 'k': + case 'K': + unit = 1024ull; + errno = 0; + size = strtoll(t, &tailp, 0); + break; + case 'm': + case 'M': + unit = 1024ull * 1024ull; + errno = 0; + size = strtoll(t, &tailp, 0); + break; + case 'g': + case 'G': + unit = 1024ull * 1024ull * 1024ull; + errno = 0; + size = strtoll(t, &tailp, 0); + break; + case 't': + case 'T': + unit = 1024ull * 1024ull * 1024ull * 1024ull; + errno = 0; + size = strtoll(t, &tailp, 0); + break; + default: + /* The unit must be kilobyte at least. */ + free(t); + return (INVALID_ARG); + } + + *(t + len - 1) = '\0'; + if (is_fully_numeric(t) != TRUE) { + free(t); + return (INVALID_ARG); + } + + errno = 0; + size = strtoll(t, &tailp, 0); + + /* Check overflow condition */ + if (errno == ERANGE || (size > (MAX64BIT / unit))) { + free(t); + return (INVALID_ARG); + } + + *valp = size * unit; + free(t); + return (SUCCESS); +} /* - * Return true if a name is in the internal canonical form + * is_fully_numeric(str) + * This function checks if the string are legal numeric string. The beginning + * or ending characters can be white spaces. + * Return value is TRUE if the string are legal numeric string, or FALSE + * otherwise. */ static int -canonical_name(char *name) +is_fully_numeric(char *strp) { - must_be(name, 'c'); - skip_digits(name); - if (*name == 't') { - name++; - skip_digits(name); - } - must_be(name, 'd'); - skip_digits(name); - return (*name == 0); -} + uint32_t len; + uint32_t i; -int -main(int argc, char **argv) -{ - int rv = SUCCESS; - int i, c; - int findex = DO_HW_RAID_INFO; - int controller; - char *disks[N_DISKS] = {0}; - char *darg; - char *farg; - char *rarg; - char *progname; - - int l_flag = 0; - int c_flag = 0; - int d_flag = 0; - int f_flag = 0; - int F_flag = 0; - int r_flag = 0; - int no_flags = 1; - int r = RAID_MIRROR; /* default raid level is 1 */ - char *current_dir; + if (strp == NULL) { + return (FALSE); + } - (void) setlocale(LC_ALL, ""); - (void) textdomain(TEXT_DOMAIN); + len = strlen(strp); + if (len == 0) { + return (FALSE); + } - if (geteuid() != 0) { - (void) fprintf(stderr, gettext("Must be root.\n")); - exit(1); + /* Skip whitespace characters */ + for (i = 0; i < len; i++) { + if (strp[i] != ' ') { + break; + } } - if ((progname = strrchr(argv[0], '/')) == NULL) - progname = argv[0]; - else - progname++; + /* if strp points all space characters */ + if (i == len) { + return (FALSE); + } - raids = NULL; + /* Check the digitals in string */ + for (; i < len; i++) { + if (!isdigit(strp[i])) { + break; + } + } - (void) strncpy(yeschr, nl_langinfo(YESSTR), SCHAR_MAX + 1); - (void) strncpy(nochr, nl_langinfo(NOSTR), SCHAR_MAX + 1); + /* Check the ending string */ + for (; i < len; i++) { + if (strp[i] != ' ') { + return (FALSE); + } + } - while ((c = getopt(argc, argv, "cr:lfd:F:")) != EOF) { - switch (c) { - case 'c': - if (argc < 4) - usage(progname); - findex = DO_HW_RAID_CREATE; - c_flag = 1; - no_flags = 0; - break; - case 'r': - rarg = optarg; - r = atoi(rarg); - if ((r != RAID_STRIPE) && (r != RAID_MIRROR)) - usage(progname); - r_flag = 1; - break; - case 'd': - darg = optarg; - d_flag = 1; - findex = DO_HW_RAID_DELETE; - no_flags = 0; - break; - case 'l': - findex = DO_HW_RAID_INFO; - l_flag = 1; - no_flags = 0; - break; - case 'F': - findex = DO_HW_RAID_FLASH; - farg = optarg; - F_flag = 1; - no_flags = 0; - break; - case 'f': - f_flag = 1; - no_flags = 0; + return (TRUE); +} + +static int +yes(void) +{ + int i, b; + char ans[SCHAR_MAX + 1]; + + for (i = 0; ; i++) { + b = getchar(); + if (b == '\n' || b == '\0' || b == EOF) { + ans[i] = 0; break; - case '?': - default: - usage(progname); + } + if (i < SCHAR_MAX) { + ans[i] = b; } } + if (i >= SCHAR_MAX) { + i = SCHAR_MAX; + ans[SCHAR_MAX] = 0; + } - if (no_flags && argc > 1) - usage(progname); + return (rpmatch(ans)); +} - /* compatibility rules */ - if (c_flag && d_flag) - usage(progname); - if (l_flag && (d_flag || c_flag || f_flag || F_flag || r_flag)) - usage(progname); - if (F_flag && (d_flag || c_flag || l_flag || r_flag)) - usage(progname); +/* + * Function: int rpmatch(char *) + * + * Description: + * + * Internationalized get yes / no answer. + * + * Inputs: + * s -> Pointer to answer to compare against. + * + * Returns: + * TRUE -> Answer was affirmative + * FALSE -> Answer was negative + */ - switch (findex) { - case DO_HW_RAID_INFO: - if (l_flag) { - /* - * "raidctl" makes argc == 1 - * "-l" makes argc == 2 - */ - ctrl_nums = argc - 2; - if (ctrl_nums != 0) { - info_ctrl = (int **) - malloc(ctrl_nums * sizeof (int)); - if (info_ctrl == NULL) - return (FAILURE); - } - for (i = 0; i < ctrl_nums; i++) { - char *tmp = argv[i + 2]; +static int +rpmatch(char *s) +{ + int status; - info_ctrl[i] = (int *)malloc(2 * sizeof (int)); - if (info_ctrl[i] == NULL) { - free(info_ctrl); - return (FAILURE); - } - if (fully_numeric(tmp)) { - (void) sscanf(tmp, "%d", - &info_ctrl[i][INFO_CTRL]); - info_ctrl[i][INFO_STATUS] = - RAID_INVALID_CTRL; - } else { - (void) fprintf(stderr, - gettext("Invalid controller '%s'\n"), - tmp); - info_ctrl[i][INFO_STATUS] = - RAID_DONT_USE; - } - } - } else if (argc > 1) { - usage(progname); - } + /* match yesexpr */ + status = regexec(&re, s, (size_t)0, NULL, 0); + if (status != 0) { + return (FALSE); + } + return (TRUE); +} - do_info(); - break; - case DO_HW_RAID_CREATE: - for (i = 0; i < N_DISKS; i++) { - int p = 2 + (r_flag * 2) + f_flag + i; +static int +size_to_string(uint64_t size, char *string, int len) +{ + int i = 0; + uint32_t remainder; + char unit[][2] = {" ", "K", "M", "G", "T"}; - if (p == argc) - break; + if (string == NULL) { + return (FAILURE); + } + while (size > 1023) { + remainder = size % 1024; + size /= 1024; + i++; + } - disks[i] = argv[p]; + if (i > 4) { + return (FAILURE); + } - if (!canonical_name(disks[i])) - usage(progname); + remainder /= 103; + if (remainder == 0) { + (void) snprintf(string, len, "%llu", size); + } else { + (void) snprintf(string, len, "%llu.%1u", size, + remainder); + } - /* no more than 2 disks for raid level 1 */ - if ((r == RAID_MIRROR) && (i > 1)) - usage(progname); - } + /* make sure there is one byte for unit */ + if ((strlen(string) + 1) >= len) { + return (FAILURE); + } + (void) strcat(string, unit[i]); - rv = do_create(disks, r, f_flag); - break; - case DO_HW_RAID_DELETE: - if (!canonical_name(darg)) - usage(progname); + return (SUCCESS); +} - rv = do_delete(darg, f_flag); - break; - case DO_HW_RAID_FLASH: - ctrl_nums = argc - f_flag - 3; - if (ctrl_nums == 0) - usage(progname); - - current_dir = getcwd(NULL, MAXPATHLEN); - - for (i = 0; i < ctrl_nums; i++) { - char *tmp = argv[i + 3 + f_flag]; - (void) chdir(current_dir); - if (fully_numeric(tmp)) { - (void) sscanf(tmp, "%d", &controller); - rv = do_flash(controller, farg, f_flag); - if (rv == FAILURE) - break; - } else { - (void) fprintf(stderr, - gettext("Invalid controller '%s'\n"), - tmp); - } +/* + * Only one raidctl is running at one time. + */ +static int +enter_raidctl_lock(int *fd) +{ + int fd0 = -1; + struct flock lock; + + fd0 = open(RAIDCTL_LOCKF, O_CREAT|O_WRONLY, 0600); + if (fd0 < 0) { + (void) fprintf(stderr, gettext("raidctl:failed to open lockfile" + " '"RAIDCTL_LOCKF"': %s\n"), strerror(errno)); + return (FAILURE); + } + + *fd = fd0; + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 0; + + if ((fcntl(fd0, F_SETLK, &lock) == -1) && + (errno == EAGAIN || errno == EDEADLK)) { + if (fcntl(fd0, F_GETLK, &lock) == -1) { + (void) fprintf(stderr, + gettext("raidctl:enter_filelock error\n")); + return (FAILURE); } - free(current_dir); - break; - default: - usage(progname); + (void) fprintf(stderr, gettext("raidctl:" + "enter_filelock:filelock is owned " + "by 'process %d'\n"), lock.l_pid); + return (FAILURE); } - return (rv); + + return (SUCCESS); +} + +static void +exit_raidctl_lock(int fd) +{ + struct flock lock; + + lock.l_type = F_UNLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 0; + if (fcntl(fd, F_SETLK, &lock) == -1) { + (void) fprintf(stderr, gettext("raidctl: failed to" + " exit_filelock: %s\n"), + strerror(errno)); + } + (void) close(fd); } |
