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 | |
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')
23 files changed, 8153 insertions, 1475 deletions
diff --git a/usr/src/Makefile.lint b/usr/src/Makefile.lint index 50773f685d..6d14d280e7 100644 --- a/usr/src/Makefile.lint +++ b/usr/src/Makefile.lint @@ -356,6 +356,7 @@ COMMON_SUBDIRS = \ lib/libpool \ lib/libproc \ lib/libpthread \ + lib/libraidcfg \ lib/librcm \ lib/librestart \ lib/librt \ @@ -392,6 +393,7 @@ COMMON_SUBDIRS = \ lib/passwdutil \ lib/pkcs11 \ lib/print \ + lib/raidcfg_plugins \ lib/fm \ lib/udapl \ lib/watchmalloc \ 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); } diff --git a/usr/src/head/Makefile b/usr/src/head/Makefile index f4cc4e82e0..1a92230e86 100644 --- a/usr/src/head/Makefile +++ b/usr/src/head/Makefile @@ -19,7 +19,7 @@ # 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. # # ident "%Z%%M% %I% %E% SMI" @@ -135,6 +135,8 @@ HDRS= $($(MACH)_HDRS) $(ATTRDB_HDRS) \ pthread.h \ pw.h \ pwd.h \ + raidcfg.h \ + raidcfg_spi.h \ rctl.h \ re_comp.h \ regex.h \ diff --git a/usr/src/head/raidcfg.h b/usr/src/head/raidcfg.h new file mode 100644 index 0000000000..995397b015 --- /dev/null +++ b/usr/src/head/raidcfg.h @@ -0,0 +1,103 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * 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. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _RAIDCFG_H +#define _RAIDCFG_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <raidcfg_spi.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Reserved Raid object IDs; + * ID 0 is reserved for root object; + * ID 0 also stands for NONE OBJECT. + */ +#define OBJ_SYSTEM 0 +#define OBJ_NONE 0 + +typedef int raid_obj_handle_t; + +/* + * API data structure definition + */ +typedef struct { + int array_handle; + int disk_handle; +} raidcfg_hsp_relation_t; + +typedef controller_attr_t raidcfg_controller_t; +typedef array_attr_t raidcfg_array_t; +typedef disk_attr_t raidcfg_disk_t; + +typedef struct { + uint32_t associated_id; + uint32_t type; + array_tag_t tag; +} raidcfg_hsp_t; + +typedef struct { + uint32_t disk_id; + uint32_t state; + uint64_t offset; + uint64_t size; + disk_tag_t tag; +} raidcfg_arraypart_t; + +typedef diskseg_attr_t raidcfg_diskseg_t; +typedef task_attr_t raidcfg_task_t; + +/* + * raidcfg common library APIs + */ +const char *raidcfg_errstr(int); +int raidcfg_get_controller(uint32_t); +int raidcfg_get_array(int, uint64_t, uint64_t); +int raidcfg_get_disk(int, disk_tag_t); +int raidcfg_open_controller(int, char **); +int raidcfg_close_controller(int, char **); +int raidcfg_get_type(int); +int raidcfg_get_attr(int, void *); +int raidcfg_get_container(int); +int raidcfg_list_head(int, raid_obj_type_id_t); +int raidcfg_list_next(int); +int raidcfg_set_attr(int, uint32_t, void *, char **); +int raidcfg_set_hsp(int, raidcfg_hsp_relation_t *, char **); +int raidcfg_unset_hsp(int, raidcfg_hsp_relation_t *, char **); +int raidcfg_create_array(int, int *, uint32_t, uint64_t, uint32_t, char **); +int raidcfg_delete_array(int, char **); +int raidcfg_update_fw(int, char *, char **); + +#ifdef __cplusplus +} +#endif + +#endif /* _RAIDCFG_H */ diff --git a/usr/src/head/raidcfg_spi.h b/usr/src/head/raidcfg_spi.h new file mode 100644 index 0000000000..62c23fb42a --- /dev/null +++ b/usr/src/head/raidcfg_spi.h @@ -0,0 +1,353 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * 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. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SYS_RAIDCFG_SPI_H +#define _SYS_RAIDCFG_SPI_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Controller capabilities + */ +#define RAID_CAP_RAID0 1 +#define RAID_CAP_RAID1 1 << 1 +#define RAID_CAP_RAID1E 1 << 2 +#define RAID_CAP_RAID5 1 << 3 +#define RAID_CAP_RAID10 1 << 4 +#define RAID_CAP_RAID50 1 << 5 +#define RAID_CAP_G_HSP 1 << 6 +#define RAID_CAP_L_HSP 1 << 7 +#define RAID_CAP_DISK_TRANS 1 << 8 +#define RAID_CAP_FULL_DISK_ONLY 1 << 9 +#define RAID_CAP_SMART_ALLOC 1 << 10 +#define RAID_CAP_ARRAY_ALIGN 1 << 11 + +/* + * General constants + */ +#define OBJ_SEPARATOR_BEGIN -1 +#define OBJ_SEPARATOR_END -2 + +#define OBJ_ATTR_NONE -1 + +/* + * Array RAID level definition + */ +#define RAID_LEVEL_0 1 +#define RAID_LEVEL_1 2 +#define RAID_LEVEL_1E 3 +#define RAID_LEVEL_5 4 +#define RAID_LEVEL_10 5 +#define RAID_LEVEL_50 6 + +/* + * Array cache write policy + */ +#define CACHE_WR_OFF 0 +#define CACHE_WR_ON 1 + +/* + * Array cache read policy + */ +#define CACHE_RD_OFF 0 +#define CACHE_RD_ON 1 + +/* + * Array status + */ +#define ARRAY_STATE_OPTIMAL 0 +#define ARRAY_STATE_DEGRADED 1 +#define ARRAY_STATE_FAILED 2 + +/* + * Disk state + */ +#define DISK_STATE_GOOD 0 +#define DISK_STATE_FAILED 1 + +/* + * Array part state + */ +#define ARRAYPART_STATE_GOOD 0 +#define ARRAYPART_STATE_MISSED 1 + +/* + * Disk segment state + */ +#define DISKSEG_STATE_GOOD 1 +#define DISKSEG_STATE_RESERVED 1 << 1 +#define DISKSEG_STATE_DEAD 1 << 2 +#define DISKSEG_STATE_NORMAL 1 << 3 + +/* + * Controller connection type + */ +#define TYPE_UNKNOWN 0 +#define TYPE_SCSI 1 +#define TYPE_SAS 2 + +#define RAID_TASK_SUSPEND 0 +#define RAID_TASK_RESUME 1 +#define RAID_TASK_TERMINATE 2 + +#define HSP_TYPE_GLOBAL 0 +#define HSP_TYPE_LOCAL 1 + +/* + * Sub-command of set attribute + */ +#define SET_CACHE_WR_PLY 0 +#define SET_CACHE_RD_PLY 1 + +/* + * Sub-commands for act method of object + */ +#define ACT_CONTROLLER_OPEN 0 +#define ACT_CONTROLLER_CLOSE 1 +#define ACT_CONTROLLER_FLASH_FW 2 + +/* + * Some definitions + */ +#define CONTROLLER_FW_LEN 32 +#define CONTROLLER_TYPE_LEN 32 + +#define DISK_VENDER_LEN 8 +#define DISK_PRODUCT_LEN 16 +#define DISK_REV_LEN 4 + +#define DISK_ID(c, id, l) ((c) << 7 | (l) << 4 | (id)) +#define BUS(disk_id) ((disk_id) >> 7) +#define TARGET(disk_id) ((disk_id) & 0xf) +#define LUN(disk_id) (((disk_id) >> 4) & 0x7) + +#define ARRAY_ID(id, l) ((l) << 16 | (id)) +#define ARRAY_TARGET(array_id) ((array_id) & 0xffff) +#define ARRAY_LUN(array_id) ((array_id) >> 16) + +#define RDCFG_PLUGIN_V1 0x10000 +#define CFGDIR "/dev/cfg" +#define MAX_PATH_LEN 255 + +/* + * Mininum array part size: 256M + */ +#define ARRAYPART_MIN_SIZE (uint64_t)(1 << 28) + +/* + * Return code + */ +#define SUCCESS 0 +#define STD_IOCTL -1 +#define ERR_DRIVER_NOT_FOUND -2 +#define ERR_DRIVER_OPEN -3 +#define ERR_DRIVER_LOCK -4 +#define ERR_DRIVER_CLOSED -5 +#define ERR_DRIVER_ACROSS -6 +#define ERR_ARRAY_LEVEL -7 +#define ERR_ARRAY_SIZE -8 +#define ERR_ARRAY_STRIPE_SIZE -9 +#define ERR_ARRAY_CACHE_POLICY -10 +#define ERR_ARRAY_IN_USE -11 +#define ERR_ARRAY_TASK -12 +#define ERR_ARRAY_CONFIG -13 +#define ERR_ARRAY_DISKNUM -14 +#define ERR_ARRAY_LAYOUT -15 +#define ERR_ARRAY_AMOUNT -16 +#define ERR_DISK_STATE -17 +#define ERR_DISK_SPACE -18 +#define ERR_DISK_SEG_AMOUNT -19 +#define ERR_DISK_NOT_EMPTY -20 +#define ERR_DISK_TASK -21 +#define ERR_TASK_STATE -22 +#define ERR_OP_ILLEGAL -23 +#define ERR_OP_NO_IMPL -24 +#define ERR_OP_FAILED -25 +#define ERR_DEVICE_NOENT -26 +#define ERR_DEVICE_TYPE -27 +#define ERR_DEVICE_DUP -28 +#define ERR_DEVICE_OVERFLOW -29 +#define ERR_DEVICE_UNCLEAN -30 +#define ERR_DEVICE_INVALID -31 +#define ERR_NOMEM -32 +#define ERR_PRIV -33 +#define ERR_PLUGIN -34 + +/* + * Raid object types + */ +typedef enum { + OBJ_TYPE_SYSTEM, + OBJ_TYPE_CONTROLLER, + OBJ_TYPE_ARRAY, + OBJ_TYPE_DISK, + OBJ_TYPE_HSP, + OBJ_TYPE_ARRAY_PART, + OBJ_TYPE_DISK_SEG, + OBJ_TYPE_TASK, + OBJ_TYPE_ALL +} raid_obj_type_id_t; + +/* + * Task functions + */ +typedef enum { + TASK_FUNC_UNKNOWN, + TASK_FUNC_INIT, + TASK_FUNC_BUILD, + TASK_FUNC_VERIFY +} raidtask_func_t; + +/* + * Task state + */ +typedef enum { + TASK_STATE_UNKNOWN, + TASK_STATE_TERMINATED, + TASK_STATE_FAILED, + TASK_STATE_DONE, + TASK_STATE_RUNNING, + TASK_STATE_SUSPENDED +} raidtask_state_t; + +/* + * Attributes of all RAID objects + */ +typedef union { + uint64_t reserved[3]; + struct { + uint64_t target_id; + uint64_t lun; + } idl; +} array_tag_t; + +typedef union { + struct { + uint64_t bus; + uint64_t target_id; + uint64_t lun; + } cidl; +} disk_tag_t; + +typedef struct { + uint32_t controller_id; + uint32_t max_array_num; + uint32_t max_seg_per_disk; + uint32_t connection_type; + uint64_t capability; + char fw_version[CONTROLLER_FW_LEN]; + char controller_type[CONTROLLER_TYPE_LEN]; +} controller_attr_t; + +typedef struct { + uint32_t array_id; + uint32_t state; + array_tag_t tag; + uint64_t capacity; + uint32_t raid_level; + uint32_t stripe_size; + uint32_t write_policy; + uint32_t read_policy; +} array_attr_t; + +typedef struct { + uint32_t disk_id; + uint32_t state; + disk_tag_t tag; + uint64_t capacity; + char vendorid[DISK_VENDER_LEN]; + char productid[DISK_PRODUCT_LEN]; + char revision[DISK_REV_LEN]; +} disk_attr_t; + +typedef struct { + uint32_t associated_id; + uint32_t type; +} hsp_attr_t; + +typedef struct { + uint32_t disk_id; + uint32_t state; + uint64_t offset; + uint64_t size; +} arraypart_attr_t; + +typedef struct { + uint32_t seq_no; + uint32_t state; + uint64_t offset; + uint64_t size; +} diskseg_attr_t; + +typedef struct { + uint32_t task_id; + uint32_t task_func; + uint32_t task_state; + uint32_t progress; +} task_attr_t; + +typedef struct { + uint32_t array_id; + uint32_t disk_id; +} hsp_relation_t; + +/* + * Structure used to register plug-in modules + */ +typedef struct raid_lib_type { + uint32_t version; + struct raid_lib_type *next; + void *lib_handle; + const char *name; + + int (*open_controller)(uint32_t, char **); + int (*close_controller)(uint32_t, char **); + int (*compnum)(uint32_t, uint32_t, raid_obj_type_id_t, + raid_obj_type_id_t); + int (*complist)(uint32_t, uint32_t, raid_obj_type_id_t, + raid_obj_type_id_t, int, void *); + int (*get_attr)(uint32_t, uint32_t, uint32_t, raid_obj_type_id_t, + void *); + int (*set_attr)(uint32_t, uint32_t, uint32_t, uint32_t *, char **); + int (*array_create)(uint32_t, array_attr_t *, int, + arraypart_attr_t *, char **); + int (*array_delete)(uint32_t, uint32_t, char **); + int (*hsp_bind)(uint32_t, uint32_t, hsp_relation_t *, char **); + int (*hsp_unbind)(uint32_t, uint32_t, hsp_relation_t *, char **); + int (*flash_fw)(uint32_t, char *, uint32_t, char **); +} raid_lib_t; + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_RAIDCFG_SPI_H */ diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile index c541fcb01c..dd0c8d7801 100644 --- a/usr/src/lib/Makefile +++ b/usr/src/lib/Makefile @@ -19,7 +19,7 @@ # 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. # # ident "%Z%%M% %I% %E% SMI" @@ -199,10 +199,12 @@ SUBDIRS += \ gss_mechs/mech_dummy \ gss_mechs/mech_dh \ rpcsec_gss \ + libraidcfg .WAIT \ librcm .WAIT \ libcfgadm .WAIT \ libpicl .WAIT \ libpicltree .WAIT \ + raidcfg_plugins \ cfgadm_plugins \ libmail \ lvm \ diff --git a/usr/src/lib/libraidcfg/Makefile b/usr/src/lib/libraidcfg/Makefile new file mode 100644 index 0000000000..2505f2f5c5 --- /dev/null +++ b/usr/src/lib/libraidcfg/Makefile @@ -0,0 +1,61 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# 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. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#pragma ident "%Z%%M% %I% %E% SMI" +# +# lib/libraidcfg/Makefile +# + +include $(SRC)/lib/Makefile.lib + +SUBDIRS = $(MACH) +$(BUILD64)SUBDIRS += $(MACH64) + +POFILE = libraidcfg.po +MSGSRCS :sh = echo */*.c +MSGFILES = $(MSGSRCS:%.c=%.i) + +all := TARGET= all +clean := TARGET= clean +clobber := TARGET= clobber +install := TARGET= install +lint := TARGET= lint + +.KEEP_STATE: + +all clean clobber install lint: $(SUBDIRS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +_msg: $(MSGDOMAINPOFILE) + +$(POFILE): $(MSGFILES) + $(BUILDPO.msgfiles) + +FRC: + +include $(SRC)/Makefile.msg.targ +include $(SRC)/lib/Makefile.targ diff --git a/usr/src/lib/libraidcfg/Makefile.com b/usr/src/lib/libraidcfg/Makefile.com new file mode 100644 index 0000000000..e523a79552 --- /dev/null +++ b/usr/src/lib/libraidcfg/Makefile.com @@ -0,0 +1,51 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# 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. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#pragma ident "%Z%%M% %I% %E% SMI" +# +# lib/libraidcfg/Makefile.com +# + +LIBRARY = libraidcfg.a +VERS = .1 +OBJECTS = raidcfg.o + +include ../../Makefile.lib + +LIBS = $(DYNLIB) $(LINTLIB) +LDLIBS += -lcfgadm -ldevinfo -lc + +SRCDIR = ../common +$(LINTLIB):= SRCS = $(LINTSRC:%=$(SRCDIR)/%) + +CFLAGS += $(CCVERBOSE) + +.KEEP_STATE: + +all: $(LIBS) + +lint: lintcheck + +include ../../Makefile.targ diff --git a/usr/src/lib/libraidcfg/amd64/Makefile b/usr/src/lib/libraidcfg/amd64/Makefile new file mode 100644 index 0000000000..22ff31377a --- /dev/null +++ b/usr/src/lib/libraidcfg/amd64/Makefile @@ -0,0 +1,32 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# 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. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#pragma ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com +include ../../Makefile.lib.64 + +install: all $(ROOTLIBS64) $(ROOTLINKS64) diff --git a/usr/src/lib/libraidcfg/common/llib-lraidcfg b/usr/src/lib/libraidcfg/common/llib-lraidcfg new file mode 100644 index 0000000000..7992f52add --- /dev/null +++ b/usr/src/lib/libraidcfg/common/llib-lraidcfg @@ -0,0 +1,122 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * 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. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/*LINTLIBRARY*/ +/*PROTOLIB1*/ + +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <raidcfg.h> + +const char * +raidcfg_errstr( + int err_code); + +int +raidcfg_get_controller( + uint32_t controller_id); + +int +raidcfg_get_array( + int controller_handle, + uint64_t target_id, + uint64_t lun); + +int +raidcfg_get_disk( + int controller_handle, + disk_tag_t tag); + +int +raidcfg_open_controller( + int handle, + char **plugin_err_str); + +int +raidcfg_close_controller( + int handle, + char **plugin_err_str); + +int +raidcfg_get_type( + int handle); + +int +raidcfg_get_attr( + int handle, + void *attr); + +int +raidcfg_get_container( + int handle); + +int +raidcfg_list_head( + int handle, + raid_obj_type_id_t type); + +int +raidcfg_list_next( + int handle); + +int +raidcfg_set_attr( + int handle, + uint32_t set_cmd, + void *value, + char **plugin_err_str); + +int +raidcfg_update_fw( + int handle, + char *file, + char **plugin_err_str); + +int +raidcfg_create_array( + int num_of_comps, + int *disk_handles, + uint32_t raid_level, + uint64_t size, + uint32_t stripe_size, + char **plugin_err_str); + +int +raidcfg_delete_array( + int array_handle, + char **plugin_err_str); + +int +raidcfg_set_hsp( + int num, + raidcfg_hsp_relation_t *hsp_relations, + char **plugin_err_str); + +int +raidcfg_unset_hsp( + int num, + raidcfg_hsp_relation_t *hsp_relations, + char **plugin_err_str); + diff --git a/usr/src/lib/libraidcfg/common/mapfile-vers b/usr/src/lib/libraidcfg/common/mapfile-vers new file mode 100644 index 0000000000..e08383e4a3 --- /dev/null +++ b/usr/src/lib/libraidcfg/common/mapfile-vers @@ -0,0 +1,49 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# 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. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +SUNWprivate { + global: + raidcfg_errstr; + raidcfg_get_controller; + raidcfg_get_array; + raidcfg_get_disk; + raidcfg_open_controller; + raidcfg_close_controller; + raidcfg_get_type; + raidcfg_get_attr; + raidcfg_get_container; + raidcfg_list_head; + raidcfg_list_next; + raidcfg_set_attr; + raidcfg_create_array; + raidcfg_delete_array; + raidcfg_set_hsp; + raidcfg_unset_hsp; + raidcfg_update_fw; + local: + *; +}; diff --git a/usr/src/lib/libraidcfg/common/raidcfg.c b/usr/src/lib/libraidcfg/common/raidcfg.c new file mode 100644 index 0000000000..085853585f --- /dev/null +++ b/usr/src/lib/libraidcfg/common/raidcfg.c @@ -0,0 +1,4672 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * 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. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <stddef.h> +#include <stdlib.h> +#include <dirent.h> +#include <dlfcn.h> +#include <link.h> +#include <strings.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/mnttab.h> +#include <config_admin.h> +#include <sys/param.h> +#include <libintl.h> +#include <libdevinfo.h> +#include <raidcfg.h> +#include <thread.h> +#include <synch.h> + +#ifndef TEXT_DOMAIN +#define TEXT_DOMAIN "SYS_TEST" +#endif + +#define HASH_SLOTS 16 +#define HANDLER_SLOTS 256 + +/* + * Raid object status; + */ +#define OBJ_STATUS_CMD_CLEAN -1 +#define OBJ_STATUS_OPENED 1 +#define OBJ_STATUS_SCANCOMP 1 << 1 + +#if defined(__sparcv9) +#define SUPP_PLUGIN_DIR "/usr/lib/raidcfg/sparcv9" +#elif defined(__amd64) +#define SUPP_PLUGIN_DIR "/usr/lib/raidcfg/amd64" +#else +#define SUPP_PLUGIN_DIR "/usr/lib/raidcfg" +#endif + +/* + * Basic types + */ +typedef int raid_obj_id_t; +typedef int raid_obj_status_t; + +/* + * Data structures used for object maintennance + */ +typedef struct { + void *head; + void *tail; + size_t offset; /* offset of double-linked element (raid_list_el_t) */ + /* in the linked data structures (objects) */ +} raid_list_t; + +typedef struct { + void *prev; + void *next; +} raid_list_el_t; + +typedef struct { + raid_obj_id_t obj_id_cnt; /* id 0 is reserved */ + size_t slots; /* How many lists linked by *table */ + raid_list_t *table; +} raid_obj_tab_t; + +/* + * Object type structure containing function pointers; + */ +typedef struct { + int (*compnum)(raid_obj_tab_t *, raid_obj_id_t, raid_obj_type_id_t); + int (*complist)(raid_obj_tab_t *, raid_obj_id_t, int, raid_obj_id_t *, + raid_obj_type_id_t); + int (*get_attr)(raid_obj_tab_t *, raid_obj_id_t); + int (*set_attr)(raid_obj_tab_t *, raid_obj_id_t, uint32_t, uint32_t *, + char **); + int (*act)(raid_obj_tab_t *, raid_obj_id_t, uint32_t, void *, char **); + int (*create_obj)(raid_obj_tab_t *, raid_obj_id_t, int, + raid_obj_id_t *, char **); + int (*delete_obj)(raid_obj_tab_t *, raid_obj_id_t, char **); + int (*bind_obj)(raid_obj_tab_t *, int, raid_obj_id_t *, char **); + int (*unbind_obj)(raid_obj_tab_t *, int, raid_obj_id_t *, char **); +} raid_obj_op_t; + +/* + * Common object data structure + */ +typedef struct { + raid_list_el_t el; /* double-links */ + + raid_obj_type_id_t obj_type_id; + raid_obj_id_t obj_id; + raid_obj_status_t status; + + raid_obj_id_t container; + raid_obj_id_t sibling; + raid_obj_id_t component; + + void *data; /* Pointer to attribute structure */ + raid_obj_handle_t handle; +} raid_obj_t; + +/* + * Definition about handle + */ +typedef struct { + uint32_t next; + uint32_t type; + uint32_t controller_id; + uint32_t array_id; + uint32_t disk_id; + uint64_t seq_id; + uint32_t task_id; + uint32_t fd; /* Only for controller */ + raid_lib_t *raid_lib; /* Only for controller */ +} handle_attr_t; + +#define LIST_OBJ_TO_EL(list, obj) \ + ((void *)((char *)(obj) + (list)->offset)) +#define OBJ_TAB_SLOT(tab, id) \ + ((tab)->table + ((id)%(tab)->slots)) + +#pragma init(raidcfg_init) +#pragma fini(raidcfg_fini) + +/* + * Function prototypes + */ +static int intcompare(const void *p1, const void *p2); +static uint64_t raid_space_noalign(raid_obj_tab_t *, uint32_t, int, + raid_obj_id_t *, arraypart_attr_t *); +static int raid_dev_config(cfga_cmd_t, uint32_t, uint32_t, uint8_t); +static int raid_dev_unmounted(uint32_t, uint32_t); +static int raid_handle_init(); +static void raid_handle_fini(); +static raid_obj_handle_t raid_handle_new(raid_obj_type_id_t); +static void raid_handle_delete(raid_obj_handle_t); +static void raid_handle_delete_controller_comp(uint32_t); +static raid_obj_id_t raid_handle_to_obj(raid_obj_tab_t *, + raid_obj_handle_t); +static raid_obj_handle_t raid_obj_to_handle(raid_obj_tab_t *, + raid_obj_id_t); +static raid_lib_t *raid_obj_get_lib(raid_obj_tab_t *, raid_obj_id_t); +static int raid_obj_set_lib(raid_obj_tab_t *, raid_obj_id_t, raid_lib_t *); +static int raid_obj_get_fd(raid_obj_tab_t *, raid_obj_id_t); +static int raid_obj_set_fd(raid_obj_tab_t *, raid_obj_id_t, int); +static int obj_scan_comp(raid_obj_tab_t *, raid_obj_id_t); +static int obj_rescan(raid_obj_tab_t *); +static raid_obj_id_t obj_get_comp(raid_obj_tab_t *, raid_obj_id_t, + raid_obj_type_id_t); +static raid_obj_id_t obj_get_sibling(raid_obj_tab_t *, raid_obj_id_t); +static int obj_get_attr(raid_obj_tab_t *, raid_obj_id_t, void **); +static raid_obj_id_t obj_locate_controller(raid_obj_tab_t *, uint32_t); +static raid_obj_id_t obj_locate_array(raid_obj_tab_t *, uint32_t, uint32_t); +static raid_obj_id_t obj_locate_array_recur(raid_obj_tab_t *, raid_obj_id_t, + uint32_t); +static raid_obj_id_t obj_locate_hsp(raid_obj_tab_t *, uint32_t, + uint32_t, uint32_t); +static raid_obj_id_t obj_locate_disk(raid_obj_tab_t *, uint32_t, uint32_t); +static raid_obj_id_t obj_locate_arraypart(raid_obj_tab_t *, uint32_t, + uint32_t, uint32_t); +static raid_obj_id_t obj_locate_diskseg(raid_obj_tab_t *, uint32_t, + uint32_t, uint32_t); +static raid_obj_id_t obj_locate_task(raid_obj_tab_t *, uint32_t, uint32_t); +static raid_obj_id_t obj_get_controller(raid_obj_tab_t *, raid_obj_id_t); + +static int obj_sys_compnum(raid_obj_tab_t *, raid_obj_id_t, + raid_obj_type_id_t); +static int obj_sys_complist(raid_obj_tab_t *, raid_obj_id_t, int, + raid_obj_id_t *, raid_obj_type_id_t); +static int obj_controller_compnum(raid_obj_tab_t *, raid_obj_id_t, + raid_obj_type_id_t); +static int obj_controller_complist(raid_obj_tab_t *, raid_obj_id_t, int, + raid_obj_id_t *, raid_obj_type_id_t); +static int obj_controller_get_attr(raid_obj_tab_t *, raid_obj_id_t); +static int obj_controller_act(raid_obj_tab_t *, raid_obj_id_t, + uint32_t, void *, char **); +static int obj_array_compnum(raid_obj_tab_t *, raid_obj_id_t, + raid_obj_type_id_t); +static int obj_array_complist(raid_obj_tab_t *, raid_obj_id_t, int, + raid_obj_id_t *, raid_obj_type_id_t); +static int obj_array_get_attr(raid_obj_tab_t *, raid_obj_id_t); +static int obj_array_set_attr(raid_obj_tab_t *, raid_obj_id_t, + uint32_t, uint32_t *, char **); +static int obj_disk_compnum(raid_obj_tab_t *, raid_obj_id_t, + raid_obj_type_id_t); +static int obj_disk_complist(raid_obj_tab_t *, raid_obj_id_t, int, + raid_obj_id_t *, raid_obj_type_id_t); +static int obj_disk_get_attr(raid_obj_tab_t *, raid_obj_id_t); +static int obj_hsp_get_attr(raid_obj_tab_t *, raid_obj_id_t); +static int obj_arraypart_get_attr(raid_obj_tab_t *, raid_obj_id_t); +static int obj_diskseg_get_attr(raid_obj_tab_t *, raid_obj_id_t); +static int obj_task_get_attr(raid_obj_tab_t *, raid_obj_id_t); +static int obj_array_create(raid_obj_tab_t *, raid_obj_id_t, int, + raid_obj_id_t *, char **); +static int obj_array_delete(raid_obj_tab_t *, raid_obj_id_t, char **); +static int obj_hsp_bind(raid_obj_tab_t *, int, raid_obj_id_t *, char **); +static int obj_hsp_unbind(raid_obj_tab_t *, int, raid_obj_id_t *, char **); + +static int raid_obj_create_system_obj(raid_obj_tab_t *); +static raid_obj_id_t raid_obj_id_new(raid_obj_tab_t *); +static void *raid_obj_attr_new(raid_obj_type_id_t); +static raid_obj_id_t raid_obj_create(raid_obj_tab_t *, raid_obj_type_id_t); +static int raid_obj_delete(raid_obj_tab_t *, raid_obj_id_t); +static int raid_obj_add_org(raid_obj_tab_t *, raid_obj_id_t, raid_obj_id_t); +static raid_obj_type_id_t raid_obj_get_type(raid_obj_tab_t *, raid_obj_id_t); +static int raid_obj_set_type(raid_obj_tab_t *, raid_obj_id_t, + raid_obj_type_id_t); +static raid_obj_status_t raid_obj_get_status(raid_obj_tab_t *, raid_obj_id_t); +static int raid_obj_set_status(raid_obj_tab_t *, raid_obj_id_t, + raid_obj_status_t); +static int raid_obj_clear_status(raid_obj_tab_t *, raid_obj_id_t, + raid_obj_status_t); +static raid_obj_id_t raid_obj_get_container(raid_obj_tab_t *, raid_obj_id_t); +static int raid_obj_set_container(raid_obj_tab_t *, raid_obj_id_t, + raid_obj_id_t); +static raid_obj_id_t raid_obj_get_comp(raid_obj_tab_t *, raid_obj_id_t); +static int raid_obj_set_comp(raid_obj_tab_t *, raid_obj_id_t, raid_obj_id_t); +static raid_obj_id_t raid_obj_get_sibling(raid_obj_tab_t *, raid_obj_id_t); +static int raid_obj_set_sibling(raid_obj_tab_t *, raid_obj_id_t, + raid_obj_id_t); +static void *raid_obj_get_data_ptr(raid_obj_tab_t *, raid_obj_id_t); +static int raid_obj_set_data_ptr(raid_obj_tab_t *, raid_obj_id_t, void *); +static raid_obj_handle_t raid_obj_get_handle(raid_obj_tab_t *, + raid_obj_id_t); +static int raid_obj_set_handle(raid_obj_tab_t *, raid_obj_id_t, + raid_obj_handle_t); + +static void raid_list_create(raid_list_t *, size_t); +static void *raid_list_head(raid_list_t *); +static void *raid_list_next(raid_list_t *, void *); +static void raid_list_insert_tail(raid_list_t *, void *); +static void raid_list_remove(raid_list_t *, void *); +static void *raid_list_remove_head(raid_list_t *); +static void *raid_list_find(raid_list_t *, raid_obj_id_t); +static int raid_obj_tab_create(raid_obj_tab_t *, size_t); +static void raid_obj_tab_destroy(raid_obj_tab_t *); +static int raid_obj_tab_insert(raid_obj_tab_t *, raid_obj_id_t, void *); +static void *raid_obj_tab_remove(raid_obj_tab_t *, raid_obj_id_t); +static void *raid_obj_tab_find(raid_obj_tab_t *, raid_obj_id_t); +static void raid_list_destroy(raid_list_t *); + +static int controller_id_to_path(uint32_t, char *); +static char *controller_id_to_driver_name(uint32_t); +static void raid_plugin_init(); +static raid_lib_t *raid_plugin_load(char *); +static raid_lib_t *raid_find_lib(raid_obj_tab_t *, raid_obj_id_t); + +/* Global object table */ +static raid_obj_tab_t raid_tab_sys = {0, 0, NULL}; + +/* Plug-in modules maintenance data structures */ +static raid_lib_t *raid_lib_sys = NULL; + +/* Handle table definition */ +static struct { + int handle_num; + int used; + int unused; + handle_attr_t *handles; +} raid_handle_sys = {0, 0, 0, NULL}; + +/* + * RAID object method table definition + */ +static raid_obj_op_t raid_obj_op_sys[OBJ_TYPE_ALL] = { + {obj_sys_compnum, obj_sys_complist, NULL, NULL, NULL, + NULL, NULL, NULL, NULL}, /* system object methods */ + {obj_controller_compnum, obj_controller_complist, + obj_controller_get_attr, NULL, obj_controller_act, + NULL, NULL, NULL, NULL}, /* controller object methods */ + {obj_array_compnum, obj_array_complist, obj_array_get_attr, + obj_array_set_attr, NULL, obj_array_create, + obj_array_delete, NULL, NULL}, /* array object methods */ + {obj_disk_compnum, obj_disk_complist, obj_disk_get_attr, NULL, + NULL, NULL, NULL, NULL, NULL}, /* disk object methods */ + {NULL, NULL, obj_hsp_get_attr, NULL, NULL, NULL, NULL, obj_hsp_bind, + obj_hsp_unbind}, /* hsp object methods */ + {NULL, NULL, obj_arraypart_get_attr, NULL, NULL, NULL, NULL, + NULL, NULL}, /* array part object methods */ + {NULL, NULL, obj_diskseg_get_attr, NULL, NULL, NULL, NULL, NULL, NULL}, + {NULL, NULL, obj_task_get_attr, NULL, NULL, NULL, NULL, + NULL, NULL} /* disk seg object methods */ +}; + +/* + * Mutex for multithread safe + */ +static mutex_t raidcfg_mp; + +/* + * RaidCfg library APIs + */ +const char * +raidcfg_errstr(int err_code) +{ + char *ret_val; + + (void) mutex_lock(&raidcfg_mp); + switch (err_code) { + case SUCCESS: + ret_val = dgettext(TEXT_DOMAIN, "Operation succeeded.\n"); + break; + case STD_IOCTL: + ret_val = dgettext(TEXT_DOMAIN, + "Request standard IOCTL service.\n"); + break; + case ERR_DRIVER_NOT_FOUND: + ret_val = dgettext(TEXT_DOMAIN, + "Controller device can not be found.\n"); + break; + case ERR_DRIVER_OPEN: + ret_val = dgettext(TEXT_DOMAIN, "Can not open controller.\n"); + break; + case ERR_DRIVER_LOCK: + ret_val = dgettext(TEXT_DOMAIN, "Controller is locked.\n"); + break; + case ERR_DRIVER_CLOSED: + ret_val = dgettext(TEXT_DOMAIN, "Controller is not opened.\n"); + break; + case ERR_DRIVER_ACROSS: + ret_val = dgettext(TEXT_DOMAIN, + "Operation across multiple controllers.\n"); + break; + case ERR_ARRAY_LEVEL: + ret_val = dgettext(TEXT_DOMAIN, + "Operation not support with volume of this level.\n"); + break; + case ERR_ARRAY_SIZE: + ret_val = dgettext(TEXT_DOMAIN, + "Capacity of array out of range.\n"); + break; + case ERR_ARRAY_STRIPE_SIZE: + ret_val = dgettext(TEXT_DOMAIN, "Illegal stripe size.\n"); + break; + case ERR_ARRAY_CACHE_POLICY: + ret_val = dgettext(TEXT_DOMAIN, + "Illegal cache-write policy.\n"); + break; + case ERR_ARRAY_IN_USE: + ret_val = dgettext(TEXT_DOMAIN, "Array in use.\n"); + break; + case ERR_ARRAY_TASK: + ret_val = dgettext(TEXT_DOMAIN, "Array has background task.\n"); + break; + case ERR_ARRAY_CONFIG: + ret_val = dgettext(TEXT_DOMAIN, + "Configuration over device node failed.\n"); + break; + case ERR_ARRAY_DISKNUM: + ret_val = dgettext(TEXT_DOMAIN, "Incorrect number of disks.\n"); + break; + case ERR_ARRAY_LAYOUT: + ret_val = dgettext(TEXT_DOMAIN, "Illegal array layout.\n"); + break; + case ERR_ARRAY_AMOUNT: + ret_val = dgettext(TEXT_DOMAIN, "Too many arrays.\n"); + break; + case ERR_DISK_STATE: + ret_val = dgettext(TEXT_DOMAIN, + "Incorrect disk status for current operation.\n"); + break; + case ERR_DISK_SPACE: + ret_val = dgettext(TEXT_DOMAIN, "No enough disk space.\n"); + break; + case ERR_DISK_SEG_AMOUNT: + ret_val = dgettext(TEXT_DOMAIN, "Too many disk segments.\n"); + break; + case ERR_DISK_NOT_EMPTY: + ret_val = dgettext(TEXT_DOMAIN, "Disk has occupied space.\n"); + break; + case ERR_DISK_TASK: + ret_val = dgettext(TEXT_DOMAIN, "Disk has background task.\n"); + break; + case ERR_TASK_STATE: + ret_val = dgettext(TEXT_DOMAIN, + "Incorrect task state for current operation.\n"); + break; + case ERR_OP_ILLEGAL: + ret_val = dgettext(TEXT_DOMAIN, "Illegal operation.\n"); + break; + case ERR_OP_NO_IMPL: + ret_val = dgettext(TEXT_DOMAIN, + "Operation is not implemented.\n"); + break; + case ERR_OP_FAILED: + ret_val = dgettext(TEXT_DOMAIN, + "Operation in plugin failed.\n"); + break; + case ERR_DEVICE_NOENT: + ret_val = dgettext(TEXT_DOMAIN, "Device not found.\n"); + break; + case ERR_DEVICE_TYPE: + ret_val = dgettext(TEXT_DOMAIN, "Illegal type of device.\n"); + break; + case ERR_DEVICE_DUP: + ret_val = dgettext(TEXT_DOMAIN, "Device record duplicated.\n"); + break; + case ERR_DEVICE_OVERFLOW: + ret_val = dgettext(TEXT_DOMAIN, "Too many devices.\n"); + break; + case ERR_DEVICE_UNCLEAN: + ret_val = dgettext(TEXT_DOMAIN, "Device pool is not clean.\n"); + break; + case ERR_DEVICE_INVALID: + ret_val = dgettext(TEXT_DOMAIN, "Device record is invalid.\n"); + break; + case ERR_NOMEM: + ret_val = dgettext(TEXT_DOMAIN, + "Can not allocate more memory space.\n"); + break; + case ERR_PRIV: + ret_val = dgettext(TEXT_DOMAIN, "No privilege.\n"); + break; + default: + ret_val = dgettext(TEXT_DOMAIN, "Undefined error.\n"); + } + (void) mutex_unlock(&raidcfg_mp); + + return (ret_val); +} + +int +raidcfg_get_controller(uint32_t controller_id) +{ + raid_obj_id_t obj_id; + int ret_val; + + (void) mutex_lock(&raidcfg_mp); + (void) obj_rescan(&raid_tab_sys); + obj_id = obj_locate_controller(&raid_tab_sys, controller_id); + if (obj_id < OBJ_NONE) { + (void) mutex_unlock(&raidcfg_mp); + return (obj_id); + } + + if (obj_id == OBJ_NONE) { + (void) mutex_unlock(&raidcfg_mp); + return (ERR_DEVICE_NOENT); + } + ret_val = raid_obj_to_handle(&raid_tab_sys, obj_id); + (void) mutex_unlock(&raidcfg_mp); + + return (ret_val); +} + +int +raidcfg_get_array(int controller_handle, uint64_t target_id, uint64_t lun) +{ + raid_obj_id_t obj_id; + raidcfg_array_t *attr; + int ret_val; + + (void) mutex_lock(&raidcfg_mp); + (void) obj_rescan(&raid_tab_sys); + obj_id = raid_handle_to_obj(&raid_tab_sys, controller_handle); + if (obj_id < OBJ_NONE) { + (void) mutex_unlock(&raidcfg_mp); + return (obj_id); + } + + obj_id = obj_get_comp(&raid_tab_sys, obj_id, OBJ_TYPE_ARRAY); + + while (obj_id > OBJ_NONE) { + (void) obj_get_attr(&raid_tab_sys, obj_id, (void **)(&attr)); + if (attr->tag.idl.target_id == target_id && + attr->tag.idl.lun == lun) + break; + + obj_id = obj_get_sibling(&raid_tab_sys, obj_id); + } + + if (obj_id < OBJ_NONE) { + (void) mutex_unlock(&raidcfg_mp); + return (obj_id); + } + if (obj_id == OBJ_NONE) { + (void) mutex_unlock(&raidcfg_mp); + return (ERR_DEVICE_NOENT); + } + ret_val = raid_obj_to_handle(&raid_tab_sys, obj_id); + (void) mutex_unlock(&raidcfg_mp); + + return (ret_val); +} + +int +raidcfg_get_disk(int controller_handle, disk_tag_t tag) +{ + raid_obj_id_t obj_id; + raidcfg_disk_t *attr; + int ret_val; + + (void) mutex_lock(&raidcfg_mp); + (void) obj_rescan(&raid_tab_sys); + obj_id = raid_handle_to_obj(&raid_tab_sys, controller_handle); + if (obj_id < OBJ_NONE) { + (void) mutex_unlock(&raidcfg_mp); + return (obj_id); + } + + obj_id = obj_get_comp(&raid_tab_sys, obj_id, OBJ_TYPE_DISK); + + while (obj_id > OBJ_NONE) { + (void) obj_get_attr(&raid_tab_sys, obj_id, (void **)(&attr)); + if (attr->tag.cidl.bus == tag.cidl.bus && + attr->tag.cidl.target_id == tag.cidl.target_id && + attr->tag.cidl.lun == tag.cidl.lun) + break; + + obj_id = obj_get_sibling(&raid_tab_sys, obj_id); + } + + if (obj_id < OBJ_NONE) { + (void) mutex_unlock(&raidcfg_mp); + return (obj_id); + } + if (obj_id == OBJ_NONE) { + (void) mutex_unlock(&raidcfg_mp); + return (ERR_DEVICE_NOENT); + } + ret_val = raid_obj_to_handle(&raid_tab_sys, obj_id); + (void) mutex_unlock(&raidcfg_mp); + + return (ret_val); +} + +int +raidcfg_open_controller(int handle, char **plugin_err_str) +{ + raid_obj_id_t obj_id; + int ret; + + (void) mutex_lock(&raidcfg_mp); + (void) obj_rescan(&raid_tab_sys); + obj_id = raid_handle_to_obj(&raid_tab_sys, handle); + if (obj_id < OBJ_NONE) { + raid_handle_delete(handle); + (void) mutex_unlock(&raidcfg_mp); + return (ERR_DEVICE_NOENT); + } + + ret = obj_controller_act(&raid_tab_sys, obj_id, + ACT_CONTROLLER_OPEN, NULL, plugin_err_str); + if (ret < SUCCESS) { + (void) mutex_unlock(&raidcfg_mp); + return (ret); + } + (void) mutex_unlock(&raidcfg_mp); + + return (SUCCESS); +} + +int +raidcfg_close_controller(int handle, char **plugin_err_str) +{ + raid_obj_id_t obj_id; + int ret; + + (void) mutex_lock(&raidcfg_mp); + (void) obj_rescan(&raid_tab_sys); + obj_id = raid_handle_to_obj(&raid_tab_sys, handle); + if (obj_id < OBJ_NONE) { + raid_handle_delete(handle); + (void) mutex_unlock(&raidcfg_mp); + return (ERR_DEVICE_NOENT); + } + + ret = obj_controller_act(&raid_tab_sys, obj_id, + ACT_CONTROLLER_CLOSE, NULL, plugin_err_str); + if (ret < SUCCESS) { + (void) mutex_unlock(&raidcfg_mp); + return (ret); + } + (void) mutex_unlock(&raidcfg_mp); + + return (SUCCESS); +} + +int +raidcfg_get_type(int handle) +{ + raid_obj_id_t obj_id; + int ret_val; + + (void) mutex_lock(&raidcfg_mp); + (void) obj_rescan(&raid_tab_sys); + obj_id = raid_handle_to_obj(&raid_tab_sys, handle); + if (obj_id < OBJ_NONE) { + raid_handle_delete(handle); + (void) mutex_unlock(&raidcfg_mp); + return (ERR_DEVICE_NOENT); + } + ret_val = raid_obj_get_type(&raid_tab_sys, obj_id); + (void) mutex_unlock(&raidcfg_mp); + + return (ret_val); +} + +int +raidcfg_get_attr(int handle, void *attr) +{ + raid_obj_id_t obj_id; + raid_obj_type_id_t type; + void *data; + int ret, size; + + (void) mutex_lock(&raidcfg_mp); + (void) obj_rescan(&raid_tab_sys); + if (attr == NULL) { + (void) mutex_unlock(&raidcfg_mp); + return (ERR_DEVICE_INVALID); + } + + obj_id = raid_handle_to_obj(&raid_tab_sys, handle); + if (obj_id < OBJ_NONE) { + raid_handle_delete(handle); + (void) mutex_unlock(&raidcfg_mp); + return (ERR_DEVICE_NOENT); + } + + type = raid_obj_get_type(&raid_tab_sys, obj_id); + ret = obj_get_attr(&raid_tab_sys, obj_id, &data); + if (ret < SUCCESS) { + (void) mutex_unlock(&raidcfg_mp); + return (ret); + } + + switch (type) { + case OBJ_TYPE_CONTROLLER: + size = sizeof (controller_attr_t); + break; + case OBJ_TYPE_ARRAY: + size = sizeof (array_attr_t); + break; + case OBJ_TYPE_HSP: + { + raidcfg_hsp_t *dst = attr; + hsp_attr_t *src = data; + controller_attr_t *ctlr_attr; + array_attr_t *array_attr; + + dst->associated_id = src->associated_id; + dst->type = src->type; + + obj_id = obj_get_controller(&raid_tab_sys, obj_id); + ret = obj_get_attr(&raid_tab_sys, obj_id, + (void **)(&ctlr_attr)); + if (ret < SUCCESS) { + (void) mutex_unlock(&raidcfg_mp); + return (ret); + } + + if (src->type == HSP_TYPE_LOCAL) { + obj_id = obj_locate_array(&raid_tab_sys, + ctlr_attr->controller_id, + src->associated_id); + ret = obj_get_attr(&raid_tab_sys, obj_id, + (void **)(&array_attr)); + if (ret < SUCCESS) { + (void) mutex_unlock(&raidcfg_mp); + return (ret); + } + + dst->tag.idl.target_id = + array_attr->tag.idl.target_id; + dst->tag.idl.lun = array_attr->tag.idl.lun; + } + } + (void) mutex_unlock(&raidcfg_mp); + return (SUCCESS); + case OBJ_TYPE_DISK: + size = sizeof (disk_attr_t); + break; + case OBJ_TYPE_ARRAY_PART: + { + raidcfg_arraypart_t *dst = attr; + arraypart_attr_t *src = data; + controller_attr_t *ctlr_attr; + disk_attr_t *disk_attr; + + dst->disk_id = src->disk_id; + dst->offset = src->offset; + dst->size = src->size; + dst->state = src->state; + + obj_id = obj_get_controller(&raid_tab_sys, obj_id); + ret = obj_get_attr(&raid_tab_sys, obj_id, + (void **)(&ctlr_attr)); + if (ret < SUCCESS) { + (void) mutex_unlock(&raidcfg_mp); + return (ret); + } + + obj_id = obj_locate_disk(&raid_tab_sys, + ctlr_attr->controller_id, src->disk_id); + if (obj_id <= OBJ_NONE) { + dst->tag.cidl.bus = (uint64_t)OBJ_ATTR_NONE; + dst->tag.cidl.target_id = + (uint64_t)OBJ_ATTR_NONE; + dst->tag.cidl.lun = (uint64_t)OBJ_ATTR_NONE; + (void) mutex_unlock(&raidcfg_mp); + return (SUCCESS); + } + + ret = obj_get_attr(&raid_tab_sys, obj_id, + (void **)(&disk_attr)); + if (ret < SUCCESS) { + (void) mutex_unlock(&raidcfg_mp); + return (ret); + } + + dst->tag.cidl.bus = disk_attr->tag.cidl.bus; + dst->tag.cidl.target_id = disk_attr->tag.cidl.target_id; + dst->tag.cidl.lun = disk_attr->tag.cidl.lun; + } + (void) mutex_unlock(&raidcfg_mp); + return (SUCCESS); + case OBJ_TYPE_DISK_SEG: + size = sizeof (diskseg_attr_t); + break; + case OBJ_TYPE_TASK: + size = sizeof (task_attr_t); + break; + default: + (void) mutex_unlock(&raidcfg_mp); + return (ERR_DEVICE_TYPE); + } + + (void) memcpy(attr, data, size); + + (void) mutex_unlock(&raidcfg_mp); + return (ret); +} + +int +raidcfg_get_container(int handle) +{ + raid_obj_id_t obj_id; + int ret_val; + + (void) mutex_lock(&raidcfg_mp); + (void) obj_rescan(&raid_tab_sys); + obj_id = raid_handle_to_obj(&raid_tab_sys, handle); + if (obj_id < OBJ_NONE) { + raid_handle_delete(handle); + (void) mutex_unlock(&raidcfg_mp); + return (ERR_DEVICE_NOENT); + } + + obj_id = raid_obj_get_container(&raid_tab_sys, obj_id); + if (obj_id < OBJ_NONE) { + (void) mutex_unlock(&raidcfg_mp); + return (obj_id); + } + ret_val = raid_obj_to_handle(&raid_tab_sys, obj_id); + (void) mutex_unlock(&raidcfg_mp); + + return (ret_val); +} + +int +raidcfg_list_head(int handle, raid_obj_type_id_t type) +{ + raid_obj_id_t obj_id; + int ret_val; + + (void) mutex_lock(&raidcfg_mp); + (void) obj_rescan(&raid_tab_sys); + obj_id = raid_handle_to_obj(&raid_tab_sys, handle); + if (obj_id < OBJ_NONE) { + raid_handle_delete(handle); + (void) mutex_unlock(&raidcfg_mp); + return (ERR_DEVICE_NOENT); + } + + obj_id = obj_get_comp(&raid_tab_sys, obj_id, type); + if (obj_id < OBJ_NONE) { + (void) mutex_unlock(&raidcfg_mp); + return (obj_id); + } + ret_val = raid_obj_to_handle(&raid_tab_sys, obj_id); + (void) mutex_unlock(&raidcfg_mp); + + return (ret_val); +} + +int +raidcfg_list_next(int handle) +{ + raid_obj_id_t obj_id; + int ret_val; + + (void) mutex_lock(&raidcfg_mp); + (void) obj_rescan(&raid_tab_sys); + obj_id = raid_handle_to_obj(&raid_tab_sys, handle); + if (obj_id < OBJ_NONE) { + raid_handle_delete(handle); + (void) mutex_unlock(&raidcfg_mp); + return (ERR_DEVICE_NOENT); + } + + obj_id = obj_get_sibling(&raid_tab_sys, obj_id); + if (obj_id < OBJ_NONE) { + (void) mutex_unlock(&raidcfg_mp); + return (obj_id); + } + ret_val = raid_obj_to_handle(&raid_tab_sys, obj_id); + (void) mutex_unlock(&raidcfg_mp); + + return (ret_val); +} + +int +raidcfg_set_attr(int handle, uint32_t set_cmd, void *value, + char **plugin_err_str) +{ + raid_obj_id_t obj_id; + raid_obj_type_id_t type; + int ret; + + (void) mutex_lock(&raidcfg_mp); + (void) obj_rescan(&raid_tab_sys); + obj_id = raid_handle_to_obj(&raid_tab_sys, handle); + if (obj_id < OBJ_NONE) { + raid_handle_delete(handle); + (void) mutex_unlock(&raidcfg_mp); + return (ERR_DEVICE_NOENT); + } + + type = raid_obj_get_type(&raid_tab_sys, obj_id); + if (raid_obj_op_sys[type].set_attr == NULL) { + (void) mutex_unlock(&raidcfg_mp); + return (ERR_OP_NO_IMPL); + } + + ret = raid_obj_op_sys[type].set_attr(&raid_tab_sys, + obj_id, set_cmd, value, plugin_err_str); + + (void) mutex_unlock(&raidcfg_mp); + return (ret); +} + +int +raidcfg_update_fw(int handle, char *file, char **plugin_err_str) +{ + raid_obj_id_t obj_id; + int ret; + + (void) mutex_lock(&raidcfg_mp); + (void) obj_rescan(&raid_tab_sys); + obj_id = raid_handle_to_obj(&raid_tab_sys, handle); + if (obj_id < OBJ_NONE) { + raid_handle_delete(handle); + (void) mutex_unlock(&raidcfg_mp); + return (ERR_DEVICE_NOENT); + } + + if (raid_obj_get_type(&raid_tab_sys, obj_id) != OBJ_TYPE_CONTROLLER) { + (void) mutex_unlock(&raidcfg_mp); + return (ERR_OP_NO_IMPL); + } + + ret = raid_obj_op_sys[OBJ_TYPE_CONTROLLER].act(&raid_tab_sys, + obj_id, ACT_CONTROLLER_FLASH_FW, file, plugin_err_str); + + (void) mutex_unlock(&raidcfg_mp); + return (ret); +} + +int +raidcfg_create_array(int num_of_comps, int *disk_handles, + uint32_t raid_level, uint64_t size, uint32_t stripe_size, + char **plugin_err_str) +{ + raid_obj_id_t *disk_obj_ids, obj_id; + array_attr_t *array_attr; + raid_obj_handle_t array_handle; + int i, ret; + + (void) mutex_lock(&raidcfg_mp); + (void) obj_rescan(&raid_tab_sys); + + disk_obj_ids = calloc(num_of_comps, sizeof (raid_obj_id_t)); + if (disk_obj_ids == NULL) { + (void) mutex_unlock(&raidcfg_mp); + return (ERR_NOMEM); + } + + /* convert disk handles into disk object ids; */ + for (i = 0; i < num_of_comps; ++i) { + if (*(disk_handles + i) == OBJ_SEPARATOR_BEGIN || + *(disk_handles + i) == OBJ_SEPARATOR_END) { + *(disk_obj_ids + i) = *(disk_handles + i); + continue; + } + + *(disk_obj_ids + i) = raid_handle_to_obj(&raid_tab_sys, + *(disk_handles + i)); + if (raid_obj_get_type(&raid_tab_sys, *(disk_obj_ids + i)) != + OBJ_TYPE_DISK) { + free(disk_obj_ids); + (void) obj_rescan(&raid_tab_sys); + (void) mutex_unlock(&raidcfg_mp); + return (ERR_DEVICE_TYPE); + } + } + + /* Create an empty array object */ + obj_id = raid_obj_create(&raid_tab_sys, OBJ_TYPE_ARRAY); + if (obj_id < OBJ_NONE) { + free(disk_obj_ids); + (void) obj_rescan(&raid_tab_sys); + (void) mutex_unlock(&raidcfg_mp); + return (obj_id); + } + (void) raid_obj_clear_status(&raid_tab_sys, obj_id, + OBJ_STATUS_CMD_CLEAN); + + array_attr = raid_obj_get_data_ptr(&raid_tab_sys, obj_id); + array_attr->array_id = (uint32_t)OBJ_ATTR_NONE; + array_attr->raid_level = raid_level; + array_attr->capacity = size; + array_attr->stripe_size = stripe_size; + array_attr->write_policy = CACHE_WR_ON; + array_attr->read_policy = CACHE_RD_ON; + + ret = raid_obj_op_sys[OBJ_TYPE_ARRAY].create_obj(&raid_tab_sys, obj_id, + num_of_comps, disk_obj_ids, plugin_err_str); + free(disk_obj_ids); + + if (ret < SUCCESS) { + (void) obj_rescan(&raid_tab_sys); + (void) mutex_unlock(&raidcfg_mp); + return (ret); + } + + /* create_obj() method should put the array object in the device tree */ + array_handle = raid_obj_to_handle(&raid_tab_sys, obj_id); + + (void) obj_rescan(&raid_tab_sys); + (void) mutex_unlock(&raidcfg_mp); + return (array_handle); +} + +int +raidcfg_delete_array(int array_handle, char **plugin_err_str) +{ + raid_obj_id_t array_obj_id; + int ret; + + (void) mutex_lock(&raidcfg_mp); + (void) obj_rescan(&raid_tab_sys); + + if (raidcfg_get_type(array_handle) != OBJ_TYPE_ARRAY) { + (void) mutex_unlock(&raidcfg_mp); + return (ERR_DEVICE_TYPE); + } + + array_obj_id = raid_handle_to_obj(&raid_tab_sys, array_handle); + if (array_obj_id < OBJ_NONE) { + (void) mutex_unlock(&raidcfg_mp); + return (array_obj_id); + } + if (array_obj_id == OBJ_NONE) { + (void) mutex_unlock(&raidcfg_mp); + return (ERR_DEVICE_INVALID); + } + + ret = raid_obj_op_sys[OBJ_TYPE_ARRAY].delete_obj(&raid_tab_sys, + array_obj_id, plugin_err_str); + (void) obj_rescan(&raid_tab_sys); + + (void) mutex_unlock(&raidcfg_mp); + return (ret); +} + +int +raidcfg_set_hsp(int num, raidcfg_hsp_relation_t *hsp_relations, + char **plugin_err_str) +{ + raid_obj_id_t disk_obj_id, array_obj_id; + raid_obj_id_t *hsp_relation_objs; + int ret, i; + + (void) mutex_lock(&raidcfg_mp); + (void) obj_rescan(&raid_tab_sys); + if ((num == 0) || (hsp_relations == NULL)) { + (void) mutex_unlock(&raidcfg_mp); + return (ERR_OP_ILLEGAL); + } + + hsp_relation_objs = malloc(2 * num * sizeof (raid_obj_id_t)); + if (hsp_relation_objs == NULL) { + (void) mutex_unlock(&raidcfg_mp); + return (ERR_NOMEM); + } + + (void) obj_rescan(&raid_tab_sys); + + for (i = 0; i < num; ++ i) { + if (hsp_relations->array_handle != OBJ_ATTR_NONE) { + array_obj_id = raid_handle_to_obj(&raid_tab_sys, + hsp_relations[i].array_handle); + if (array_obj_id < OBJ_NONE) { + free(hsp_relation_objs); + (void) mutex_unlock(&raidcfg_mp); + return (array_obj_id); + } + if (array_obj_id == OBJ_NONE) { + (void) free(hsp_relation_objs); + (void) mutex_unlock(&raidcfg_mp); + return (ERR_DEVICE_NOENT); + } + if (raidcfg_get_type(hsp_relations[i].array_handle) != + OBJ_TYPE_ARRAY) { + free(hsp_relation_objs); + (void) mutex_unlock(&raidcfg_mp); + return (ERR_DEVICE_TYPE); + } + } else + array_obj_id = OBJ_ATTR_NONE; + + disk_obj_id = raid_handle_to_obj(&raid_tab_sys, + hsp_relations[i].disk_handle); + if (disk_obj_id < OBJ_NONE) { + free(hsp_relation_objs); + (void) mutex_unlock(&raidcfg_mp); + return (disk_obj_id); + } + if (disk_obj_id == OBJ_NONE) { + free(hsp_relation_objs); + (void) mutex_unlock(&raidcfg_mp); + return (ERR_DEVICE_NOENT); + } + if (raidcfg_get_type(hsp_relations[i].disk_handle) != + OBJ_TYPE_DISK) { + free(hsp_relation_objs); + (void) mutex_unlock(&raidcfg_mp); + return (ERR_DEVICE_TYPE); + } + + hsp_relation_objs[2 * i] = array_obj_id; + hsp_relation_objs[2 * i + 1] = disk_obj_id; + } + + ret = raid_obj_op_sys[OBJ_TYPE_HSP].bind_obj(&raid_tab_sys, num, + hsp_relation_objs, plugin_err_str); + + (void) obj_rescan(&raid_tab_sys); + free(hsp_relation_objs); + (void) mutex_unlock(&raidcfg_mp); + + return (ret); +} + +int +raidcfg_unset_hsp(int num, raidcfg_hsp_relation_t *hsp_relations, + char **plugin_err_str) +{ + raid_obj_id_t disk_obj_id, array_obj_id; + raid_obj_id_t *hsp_relation_objs; + int ret, i; + + (void) mutex_lock(&raidcfg_mp); + (void) obj_rescan(&raid_tab_sys); + if ((num == 0) || (hsp_relations == NULL)) { + (void) mutex_unlock(&raidcfg_mp); + return (ERR_OP_ILLEGAL); + } + + hsp_relation_objs = malloc(2 * num * sizeof (raid_obj_id_t)); + if (hsp_relation_objs == NULL) { + (void) mutex_unlock(&raidcfg_mp); + return (ERR_NOMEM); + } + + (void) obj_rescan(&raid_tab_sys); + + for (i = 0; i < num; ++ i) { + if (hsp_relations->array_handle != OBJ_ATTR_NONE) { + array_obj_id = raid_handle_to_obj(&raid_tab_sys, + hsp_relations[i].array_handle); + if (array_obj_id < OBJ_NONE) { + free(hsp_relation_objs); + (void) mutex_unlock(&raidcfg_mp); + return (array_obj_id); + } + if (array_obj_id == OBJ_NONE) { + free(hsp_relation_objs); + (void) mutex_unlock(&raidcfg_mp); + return (ERR_DEVICE_NOENT); + } + if (raidcfg_get_type(hsp_relations[i].array_handle) != + OBJ_TYPE_ARRAY) { + free(hsp_relation_objs); + (void) mutex_unlock(&raidcfg_mp); + return (ERR_DEVICE_TYPE); + } + } else + array_obj_id = OBJ_ATTR_NONE; + + disk_obj_id = raid_handle_to_obj(&raid_tab_sys, + hsp_relations[i].disk_handle); + if (disk_obj_id < OBJ_NONE) { + free(hsp_relation_objs); + (void) mutex_unlock(&raidcfg_mp); + return (disk_obj_id); + } + if (disk_obj_id == OBJ_NONE) { + free(hsp_relation_objs); + (void) mutex_unlock(&raidcfg_mp); + return (ERR_DEVICE_NOENT); + } + if (raidcfg_get_type(hsp_relations[i].disk_handle) != + OBJ_TYPE_DISK) { + free(hsp_relation_objs); + (void) mutex_unlock(&raidcfg_mp); + return (ERR_DEVICE_TYPE); + } + + hsp_relation_objs[2 * i] = array_obj_id; + hsp_relation_objs[2 * i + 1] = disk_obj_id; + } + + ret = raid_obj_op_sys[OBJ_TYPE_HSP].unbind_obj(&raid_tab_sys, + num, hsp_relation_objs, plugin_err_str); + + (void) obj_rescan(&raid_tab_sys); + free(hsp_relation_objs); + (void) mutex_unlock(&raidcfg_mp); + + return (ret); +} + +/* + * RaidCfg lib routines + */ +void +raidcfg_init(void) +{ + (void) mutex_init(&raidcfg_mp, NULL, NULL); + raid_plugin_init(); + (void) raid_handle_init(); + (void) obj_rescan(&raid_tab_sys); +} + +void +raidcfg_fini(void) +{ + /* + * Need to close all opened controllers before destroying object table + */ + (void) obj_rescan(&raid_tab_sys); + raid_handle_fini(); + raid_obj_tab_destroy(&raid_tab_sys); + raid_plugin_init(); + (void) mutex_destroy(&raidcfg_mp); +} + +/* + * Support routines + */ +static int +intcompare(const void *p1, const void *p2) +{ + int i, j; + i = *((int *)p1); + j = *((int *)p2); + return (i - j); +} + +static uint64_t +raid_space_noalign(raid_obj_tab_t *raid_tab, uint32_t raid_level, int num, + raid_obj_id_t *disk_objs, arraypart_attr_t *arraypart_attrs) +{ + disk_attr_t *disk_attr; + diskseg_attr_t *diskseg_attr; + raid_obj_id_t obj_id; + uint64_t offset, capacity; + int i, disk_num, sub_array_num, disk_layer; + + /* Find out the maximum available space for all disks */ + for (i = 0; i < num; ++i) { + if ((disk_objs[i] == OBJ_SEPARATOR_BEGIN) || + (disk_objs[i] == OBJ_SEPARATOR_END)) + continue; + + (void) obj_get_attr(raid_tab, disk_objs[i], + (void **)(&disk_attr)); + obj_id = obj_get_comp(raid_tab, disk_objs[i], + OBJ_TYPE_DISK_SEG); + if (obj_id == OBJ_NONE) { + arraypart_attrs[i].offset = 0; + arraypart_attrs[i].size = disk_attr->capacity; + continue; + } + + (void) obj_get_attr(raid_tab, obj_id, (void **) + (&diskseg_attr)); + arraypart_attrs[i].offset = 0; + arraypart_attrs[i].size = diskseg_attr->offset; + offset = diskseg_attr->offset + diskseg_attr->size; + + while ((obj_id = obj_get_sibling(raid_tab, obj_id)) != + OBJ_NONE) { + (void) obj_get_attr(raid_tab, obj_id, + (void **)(&diskseg_attr)); + if ((diskseg_attr->offset - offset) > + arraypart_attrs[i].size) { + arraypart_attrs[i].offset = offset; + arraypart_attrs[i].size = diskseg_attr->offset + - offset; + } + + offset = diskseg_attr->offset + diskseg_attr->size; + } + + if ((disk_attr->capacity - offset) > arraypart_attrs[i].size) { + arraypart_attrs[i].offset = offset; + arraypart_attrs[i].size = disk_attr->capacity + - offset; + } + } + + capacity = OBJ_ATTR_NONE; + disk_num = 0; + disk_layer = 0; + sub_array_num = 0; + for (i = 0; i < num; ++i) { + if (disk_objs[i] == OBJ_SEPARATOR_BEGIN) { + ++ disk_layer; + continue; + } + if (disk_objs[i] == OBJ_SEPARATOR_END) { + -- disk_layer; + if (disk_layer != 0) + ++ sub_array_num; + continue; + } + + if (capacity > arraypart_attrs[i].size) + capacity = arraypart_attrs[i].size; + ++disk_num; + } + + switch (raid_level) { + case RAID_LEVEL_0: + capacity = capacity * disk_num; + break; + case RAID_LEVEL_1: + capacity = capacity * disk_num / 2; + break; + case RAID_LEVEL_1E: + capacity = capacity * disk_num / 2; + break; + case RAID_LEVEL_5: + capacity = capacity * (disk_num - 1); + break; + case RAID_LEVEL_10: + capacity = capacity * disk_num / 2; + break; + case RAID_LEVEL_50: + capacity = capacity * (disk_num - sub_array_num); + break; + default: + return (ERR_ARRAY_LEVEL); + break; + } + + return (capacity); +} + +static int +raid_dev_config(cfga_cmd_t cmd, uint32_t controller_id, uint32_t target_id, + uint8_t type) +{ + cfga_err_t cfga_err; + char *ap_id; + int count = 0; + + ap_id = (char *)malloc(MAX_PATH_LEN); + if (ap_id == NULL) + return (ERR_NOMEM); + + if (type == 0) { + (void) snprintf(ap_id, MAX_PATH_LEN, "c%d::dsk/c%dt%dd0", + controller_id, controller_id, target_id); + } else + (void) snprintf(ap_id, MAX_PATH_LEN, "c%d", controller_id); + + do { + cfga_err = config_change_state(cmd, 1, &ap_id, "disable_rcm", + NULL, NULL, NULL, 0); + count++; + } while (cfga_err != CFGA_OK && count < 2); + + if (cfga_err != CFGA_OK) { + free(ap_id); + return (ERR_ARRAY_CONFIG); + } + + free(ap_id); + return (SUCCESS); +} + +static int +raid_dev_unmounted(uint32_t controller_id, uint32_t target_id) +{ + struct mnttab mt; + FILE *f; + char path[MAX_PATH_LEN]; + + (void) snprintf(path, MAX_PATH_LEN, "c%dt%dd0", + controller_id, target_id); + + f = fopen(MNTTAB, "r"); + + while (getmntent(f, &mt) != EOF) + if (strstr(mt.mnt_special, path) != NULL) { + (void) fclose(f); + return (ERR_ARRAY_IN_USE); + } + + (void) fclose(f); + return (SUCCESS); +} + +/* + * Raid handle maintenance routines + */ +static int +raid_handle_init() +{ + int i; + void *ptr; + + raid_handle_sys.handle_num += HANDLER_SLOTS; + ptr = realloc(raid_handle_sys.handles, + raid_handle_sys.handle_num * sizeof (handle_attr_t)); + if (ptr == NULL) + return (ERR_NOMEM); + raid_handle_sys.handles = ptr; + + /* Clean up the new allocated handles */ + for (i = raid_handle_sys.handle_num - HANDLER_SLOTS; + i < raid_handle_sys.handle_num; ++i) { + raid_handle_sys.handles[i].type = OBJ_TYPE_ALL; + raid_handle_sys.handles[i].next = i + 1; + } + + /* For the first time of allocation, set up the system object handle */ + if (raid_handle_sys.handle_num == HANDLER_SLOTS) { + raid_handle_sys.handles[0].type = OBJ_TYPE_SYSTEM; + raid_handle_sys.handles[0].next = 0; + raid_handle_sys.unused = 1; + raid_handle_sys.used = 0; + } + return (SUCCESS); +} + +static void +raid_handle_fini() +{ + raid_obj_handle_t i; + + i = raid_handle_sys.used; + + /* Close all opened controllers */ + while (i != 0) { + if ((raid_handle_sys.handles[i].type == OBJ_TYPE_CONTROLLER) && + (raid_handle_sys.handles[i].fd != 0) && + (raid_handle_sys.handles[i].raid_lib != NULL)) + raid_handle_sys.handles[i].raid_lib->close_controller( + raid_handle_sys.handles[i].controller_id, NULL); + i = raid_handle_sys.handles[i].next; + } + + /* Clean up handle space */ + raid_handle_sys.handle_num = 0; + raid_handle_sys.unused = 0; + raid_handle_sys.used = 0; + free(raid_handle_sys.handles); + raid_handle_sys.handles = NULL; +} + +static raid_obj_handle_t +raid_handle_new(raid_obj_type_id_t type) +{ + int ret; + + if (raid_handle_sys.unused == raid_handle_sys.handle_num - 1) { + ret = raid_handle_init(); + if (ret < SUCCESS) + return (ret); + } + + ret = raid_handle_sys.unused; + raid_handle_sys.unused = raid_handle_sys.handles[ret].next; + + raid_handle_sys.handles[ret].next = raid_handle_sys.used; + raid_handle_sys.used = ret; + raid_handle_sys.handles[ret].type = type; + + return (ret); +} + +static void +raid_handle_delete(raid_obj_handle_t handle) +{ + int i = raid_handle_sys.used, j = 0; + + if (handle == 0) + return; + + while (i != 0 && i != handle) { + j = i; + i = raid_handle_sys.handles[i].next; + } + + if (i == handle) { + if (j != 0) + raid_handle_sys.handles[j].next = + raid_handle_sys.handles[i].next; + else + raid_handle_sys.used = + raid_handle_sys.handles[i].next; + + raid_handle_sys.handles[i].type = OBJ_TYPE_ALL; + raid_handle_sys.handles[i].next = + raid_handle_sys.unused; + raid_handle_sys.unused = i; + } +} + +static void +raid_handle_delete_controller_comp(uint32_t controller_id) +{ + int i = raid_handle_sys.used, j; + + while (i != 0) { + j = i; + i = raid_handle_sys.handles[i].next; + if ((raid_handle_sys.handles[j].controller_id == controller_id) && + (raid_handle_sys.handles[j].type != OBJ_TYPE_CONTROLLER)) + raid_handle_delete(j); + } +} + +static raid_obj_id_t +raid_handle_to_obj(raid_obj_tab_t *raid_tab, raid_obj_handle_t handle) +{ + handle_attr_t *handle_attr; + raid_obj_id_t obj_id; + + if (handle == OBJ_SYSTEM) + return (OBJ_SYSTEM); + + handle_attr = raid_handle_sys.handles + handle; + + switch (handle_attr->type) { + case OBJ_TYPE_SYSTEM: + return (OBJ_SYSTEM); + case OBJ_TYPE_CONTROLLER: + obj_id = obj_locate_controller(raid_tab, + handle_attr->controller_id); + break; + case OBJ_TYPE_ARRAY: + obj_id = obj_locate_array(raid_tab, + handle_attr->controller_id, handle_attr->array_id); + break; + case OBJ_TYPE_HSP: + obj_id = obj_locate_hsp(raid_tab, + handle_attr->controller_id, handle_attr->disk_id, + handle_attr->array_id); + break; + case OBJ_TYPE_DISK: + obj_id = obj_locate_disk(raid_tab, + handle_attr->controller_id, handle_attr->disk_id); + break; + case OBJ_TYPE_ARRAY_PART: + obj_id = obj_locate_arraypart(raid_tab, + handle_attr->controller_id, handle_attr->array_id, + handle_attr->disk_id); + break; + case OBJ_TYPE_DISK_SEG: + obj_id = obj_locate_diskseg(raid_tab, + handle_attr->controller_id, + handle_attr->disk_id, handle_attr->seq_id); + break; + case OBJ_TYPE_TASK: + obj_id = obj_locate_task(raid_tab, + handle_attr->controller_id, handle_attr->task_id); + break; + default: + return (ERR_DEVICE_INVALID); + } + + if (obj_id < OBJ_NONE) + return (obj_id); + if (obj_id == OBJ_NONE) + return (ERR_DEVICE_NOENT); + + (void) raid_obj_set_handle(raid_tab, obj_id, handle); + return (obj_id); +} + +static raid_obj_handle_t +raid_obj_to_handle(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id) +{ + raid_obj_id_t obj_id_backup = obj_id; + raid_obj_type_id_t type; + raid_obj_handle_t handle; + controller_attr_t *controller_attr; + array_attr_t *array_attr; + hsp_attr_t *hsp_attr; + disk_attr_t *disk_attr; + arraypart_attr_t *arraypart_attr; + diskseg_attr_t *diskseg_attr; + task_attr_t *task_attr; + + if (obj_id == OBJ_SYSTEM) + return (OBJ_SYSTEM); + + /* If the object mapped by a handle */ + handle = raid_obj_get_handle(raid_tab, obj_id); + if (handle != 0) + return (handle); + + /* Search for existing handles */ + for (handle = raid_handle_sys.used; handle != 0; + handle = raid_handle_sys.handles[handle].next) + if (raid_handle_to_obj(raid_tab, handle) == obj_id) + break; + + if (handle != 0) + return (handle); + + /* Allocate new handle for this object */ + type = raid_obj_get_type(raid_tab, obj_id); + handle = raid_handle_new(type); + (void) raid_obj_set_handle(raid_tab, obj_id, handle); + raid_handle_sys.handles[handle].type = type; + + switch (type) { + case OBJ_TYPE_SYSTEM: + break; + case OBJ_TYPE_CONTROLLER: + controller_attr = raid_obj_get_data_ptr(raid_tab, obj_id); + raid_handle_sys.handles[handle].controller_id = + controller_attr->controller_id; + break; + case OBJ_TYPE_ARRAY: + array_attr = raid_obj_get_data_ptr(raid_tab, obj_id); + raid_handle_sys.handles[handle].array_id = array_attr->array_id; + obj_id = obj_get_controller(raid_tab, obj_id); + controller_attr = raid_obj_get_data_ptr(raid_tab, obj_id); + raid_handle_sys.handles[handle].controller_id = + controller_attr->controller_id; + break; + case OBJ_TYPE_HSP: + hsp_attr = raid_obj_get_data_ptr(raid_tab, obj_id); + raid_handle_sys.handles[handle].array_id = + hsp_attr->associated_id; + obj_id = raid_obj_get_container(raid_tab, obj_id); + disk_attr = raid_obj_get_data_ptr(raid_tab, obj_id); + raid_handle_sys.handles[handle].disk_id = disk_attr->disk_id; + obj_id = obj_get_controller(raid_tab, obj_id); + controller_attr = raid_obj_get_data_ptr(raid_tab, obj_id); + raid_handle_sys.handles[handle].controller_id = + controller_attr->controller_id; + break; + case OBJ_TYPE_DISK: + disk_attr = raid_obj_get_data_ptr(raid_tab, obj_id); + raid_handle_sys.handles[handle].disk_id = disk_attr->disk_id; + obj_id = obj_get_controller(raid_tab, obj_id); + controller_attr = raid_obj_get_data_ptr(raid_tab, obj_id); + raid_handle_sys.handles[handle].controller_id = + controller_attr->controller_id; + break; + case OBJ_TYPE_ARRAY_PART: + arraypart_attr = raid_obj_get_data_ptr(raid_tab, obj_id); + raid_handle_sys.handles[handle].disk_id = + arraypart_attr->disk_id; + obj_id = raid_obj_get_container(raid_tab, obj_id); + array_attr = raid_obj_get_data_ptr(raid_tab, obj_id); + raid_handle_sys.handles[handle].array_id = + array_attr->array_id; + obj_id = obj_get_controller(raid_tab, obj_id); + controller_attr = raid_obj_get_data_ptr(raid_tab, obj_id); + raid_handle_sys.handles[handle].controller_id = + controller_attr->controller_id; + break; + case OBJ_TYPE_DISK_SEG: + diskseg_attr = raid_obj_get_data_ptr(raid_tab, obj_id); + raid_handle_sys.handles[handle].seq_id = diskseg_attr->seq_no; + obj_id = raid_obj_get_container(raid_tab, obj_id); + disk_attr = raid_obj_get_data_ptr(raid_tab, obj_id); + raid_handle_sys.handles[handle].disk_id = + disk_attr->disk_id; + obj_id = obj_get_controller(raid_tab, obj_id); + controller_attr = raid_obj_get_data_ptr(raid_tab, obj_id); + raid_handle_sys.handles[handle].controller_id = + controller_attr->controller_id; + break; + case OBJ_TYPE_TASK: + task_attr = raid_obj_get_data_ptr(raid_tab, obj_id); + raid_handle_sys.handles[handle].task_id = task_attr->task_id; + obj_id = obj_get_controller(raid_tab, obj_id); + controller_attr = raid_obj_get_data_ptr(raid_tab, obj_id); + raid_handle_sys.handles[handle].controller_id = + controller_attr->controller_id; + break; + default: + return (ERR_DEVICE_INVALID); + } + + (void) raid_obj_set_handle(raid_tab, obj_id_backup, handle); + return (handle); +} + +static raid_lib_t * +raid_obj_get_lib(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id) +{ + raid_obj_handle_t handle; + controller_attr_t *attr; + + if (raid_obj_get_type(raid_tab, obj_id) != OBJ_TYPE_CONTROLLER) + return (NULL); + + attr = raid_obj_get_data_ptr(raid_tab, obj_id); + handle = raid_handle_sys.used; + while (raid_handle_sys.handles[handle].type != OBJ_TYPE_CONTROLLER || + raid_handle_sys.handles[handle].controller_id != + attr->controller_id) + handle = raid_handle_sys.handles[handle].next; + + if (handle == 0) + return (NULL); + + return (raid_handle_sys.handles[handle].raid_lib); +} + +static int +raid_obj_set_lib(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id, + raid_lib_t *raid_lib) +{ + raid_obj_handle_t handle; + controller_attr_t *attr; + + if (raid_obj_get_type(raid_tab, obj_id) != OBJ_TYPE_CONTROLLER) + return (ERR_DEVICE_TYPE); + + attr = raid_obj_get_data_ptr(raid_tab, obj_id); + handle = raid_handle_sys.used; + while (raid_handle_sys.handles[handle].type != OBJ_TYPE_CONTROLLER || + raid_handle_sys.handles[handle].controller_id != + attr->controller_id) + handle = raid_handle_sys.handles[handle].next; + + if (handle == 0) + return (ERR_DEVICE_NOENT); + + raid_handle_sys.handles[handle].raid_lib = raid_lib; + return (SUCCESS); +} + +static int +raid_obj_get_fd(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id) +{ + raid_obj_handle_t handle; + controller_attr_t *attr; + + if (raid_obj_get_type(raid_tab, obj_id) != OBJ_TYPE_CONTROLLER) + return (ERR_DEVICE_TYPE); + + attr = raid_obj_get_data_ptr(raid_tab, obj_id); + handle = raid_handle_sys.used; + while (raid_handle_sys.handles[handle].type != OBJ_TYPE_CONTROLLER || + raid_handle_sys.handles[handle].controller_id != + attr->controller_id) + handle = raid_handle_sys.handles[handle].next; + + if (handle == 0) + return (ERR_DEVICE_NOENT); + + return (raid_handle_sys.handles[handle].fd); +} + +static int +raid_obj_set_fd(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id, int fd) +{ + raid_obj_handle_t handle; + controller_attr_t *attr; + + if (raid_obj_get_type(raid_tab, obj_id) != OBJ_TYPE_CONTROLLER) + return (ERR_DEVICE_TYPE); + + attr = raid_obj_get_data_ptr(raid_tab, obj_id); + handle = raid_handle_sys.used; + while (raid_handle_sys.handles[handle].type != OBJ_TYPE_CONTROLLER || + raid_handle_sys.handles[handle].controller_id != + attr->controller_id) + handle = raid_handle_sys.handles[handle].next; + + if (handle == 0) + return (ERR_DEVICE_NOENT); + + raid_handle_sys.handles[handle].fd = fd; + return (SUCCESS); +} + +/* + * Raid object maintenance routines + */ +static int +obj_scan_comp(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id) +{ + raid_obj_status_t status; + raid_obj_type_id_t type; + int ret, i, obj_type_cnt, comp_num; + raid_obj_id_t *comp_list; + + status = raid_obj_get_status(raid_tab, obj_id); + if (status < SUCCESS) + return (status); + + if (status & OBJ_STATUS_SCANCOMP) + return (SUCCESS); + + type = raid_obj_get_type(raid_tab, obj_id); + if (type < OBJ_TYPE_SYSTEM || type > OBJ_TYPE_ALL) + return (ERR_DEVICE_INVALID); + + for (obj_type_cnt = OBJ_SYSTEM; obj_type_cnt < OBJ_TYPE_ALL; + ++obj_type_cnt) { + if (raid_obj_op_sys[type].compnum != NULL) + comp_num = raid_obj_op_sys[type].compnum( + raid_tab, obj_id, obj_type_cnt); + else + comp_num = 0; + + if (comp_num < SUCCESS) + return (comp_num); + if (comp_num == 0) + continue; + + comp_list = calloc(comp_num, sizeof (raid_obj_id_t)); + if (comp_list == NULL) + return (ERR_NOMEM); + + for (i = 0; i < comp_num; ++i) { + *(comp_list + i) = raid_obj_create(raid_tab, + obj_type_cnt); + if (*(comp_list + i) < SUCCESS) { + ret = *(comp_list + i); + free(comp_list); + return (ret); + } + + (void) raid_obj_clear_status(raid_tab, + *(comp_list + i), OBJ_STATUS_CMD_CLEAN); + (void) raid_obj_add_org(raid_tab, *(comp_list + i), + obj_id); + } + + if (raid_obj_op_sys[type].complist != NULL) + raid_obj_op_sys[type].complist(raid_tab, + obj_id, comp_num, comp_list, obj_type_cnt); + free(comp_list); + } + + (void) raid_obj_set_status(raid_tab, obj_id, OBJ_STATUS_SCANCOMP); + return (SUCCESS); +} + +static int +obj_rescan(raid_obj_tab_t *raid_tab) +{ + int ret; + + raid_obj_tab_destroy(raid_tab); + + if (raid_obj_tab_create(raid_tab, HASH_SLOTS) != SUCCESS) + return (ERR_NOMEM); + + if ((ret = raid_obj_create_system_obj(raid_tab)) != SUCCESS) { + raid_obj_tab_destroy(raid_tab); + return (ret); + } + + return (SUCCESS); +} + +static raid_obj_id_t +obj_get_comp(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id, + raid_obj_type_id_t obj_type) +{ + raid_obj_id_t id; + raid_obj_type_id_t type; + raid_obj_status_t status; + int ret; + + if ((obj_type < OBJ_TYPE_SYSTEM) || (obj_type > OBJ_TYPE_ALL)) + return (ERR_DEVICE_TYPE); + + status = raid_obj_get_status(raid_tab, obj_id); + if (status < SUCCESS) + return (status); + + if (!(status & OBJ_STATUS_SCANCOMP)) { + ret = obj_scan_comp(raid_tab, obj_id); + if (ret < SUCCESS) + return (ret); + } + + id = raid_obj_get_comp(raid_tab, obj_id); + if (id <= OBJ_NONE) + return (id); + + type = raid_obj_get_type(raid_tab, id); + if (type < OBJ_TYPE_SYSTEM) + return (type); + + if (type == obj_type) + return (id); + + while (id > OBJ_NONE) { + id = raid_obj_get_sibling(raid_tab, id); + if (id <= OBJ_NONE) + return (id); + + type = raid_obj_get_type(raid_tab, id); + if (type < OBJ_TYPE_SYSTEM) + return (type); + + if (type == obj_type) + break; + }; + + return (id); +} + +static raid_obj_id_t +obj_get_sibling(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id) +{ + raid_obj_id_t id; + raid_obj_type_id_t type, obj_type; + + id = obj_id; + obj_type = raid_obj_get_type(raid_tab, id); + if (obj_type < OBJ_TYPE_SYSTEM) + return (obj_type); + + do { + id = raid_obj_get_sibling(raid_tab, id); + if (id < OBJ_NONE) + return (id); + + type = raid_obj_get_type(raid_tab, id); + if (type < OBJ_TYPE_SYSTEM) + return (type); + } while ((type != obj_type) && (id != OBJ_NONE)); + + return (id); +} + +static int +obj_get_attr(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id, void **data) +{ + raid_obj_type_id_t type; + raid_obj_status_t status; + void *attr; + int ret = SUCCESS; + + status = raid_obj_get_status(raid_tab, obj_id); + if (status < SUCCESS) + return (status); + + type = raid_obj_get_type(raid_tab, obj_id); + if (type < OBJ_TYPE_SYSTEM) + return (type); + + if (!(status & OBJ_STATUS_OPENED)) { + if (raid_obj_op_sys[type].get_attr == NULL) + (void) raid_obj_set_status(raid_tab, obj_id, + OBJ_STATUS_OPENED); + else + ret = raid_obj_op_sys[type].get_attr(raid_tab, obj_id); + } + if (ret < SUCCESS) + return (ret); + + attr = raid_obj_get_data_ptr(raid_tab, obj_id); + if (attr == NULL && type != OBJ_TYPE_SYSTEM) + return (ERR_DEVICE_INVALID); + + *data = attr; + return (SUCCESS); +} + +static raid_obj_id_t +obj_locate_controller(raid_obj_tab_t *raid_tab, uint32_t controller_id) +{ + raid_obj_id_t obj_id; + controller_attr_t *attr; + + obj_id = obj_get_comp(raid_tab, OBJ_SYSTEM, OBJ_TYPE_CONTROLLER); + if (obj_id <= OBJ_NONE) + return (obj_id); + + do { + attr = raid_obj_get_data_ptr(raid_tab, obj_id); + if (attr == NULL) + return (ERR_DEVICE_INVALID); + + if (attr->controller_id == controller_id) + break; + } while ((obj_id = obj_get_sibling(raid_tab, obj_id)) != OBJ_NONE); + + return (obj_id); +} + +static raid_obj_id_t +obj_locate_array(raid_obj_tab_t *raid_tab, uint32_t controller_id, + uint32_t array_id) +{ + raid_obj_id_t obj_id; + + obj_id = obj_locate_controller(raid_tab, controller_id); + if (obj_id < OBJ_NONE) + return (obj_id); + + obj_id = obj_locate_array_recur(raid_tab, obj_id, array_id); + + return (obj_id); +} + +static raid_obj_id_t +obj_locate_array_recur(raid_obj_tab_t *raid_tab, + raid_obj_id_t container_obj_id, uint32_t array_id) +{ + raid_obj_id_t obj_id, ret; + array_attr_t *attr; + + obj_id = obj_get_comp(raid_tab, container_obj_id, OBJ_TYPE_ARRAY); + if (obj_id <= OBJ_NONE) + return (obj_id); + + do { + attr = raid_obj_get_data_ptr(raid_tab, obj_id); + if (attr == NULL) + return (ERR_DEVICE_INVALID); + + if (attr->array_id == array_id) + break; + + ret = obj_locate_array_recur(raid_tab, obj_id, array_id); + if (ret != OBJ_NONE) + return (ret); + + } while ((obj_id = obj_get_sibling(raid_tab, obj_id)) > OBJ_NONE); + + return (obj_id); +} + +static raid_obj_id_t +obj_locate_hsp(raid_obj_tab_t *raid_tab, uint32_t controller_id, + uint32_t disk_id, uint32_t array_id) +{ + raid_obj_id_t obj_id; + hsp_attr_t *hsp_attr; + + obj_id = obj_locate_disk(raid_tab, controller_id, disk_id); + if (obj_id <= OBJ_NONE) + return (obj_id); + + obj_id = obj_get_comp(raid_tab, obj_id, OBJ_TYPE_HSP); + if (obj_id <= OBJ_NONE) + return (obj_id); + + do { + (void) obj_get_attr(raid_tab, obj_id, (void **)(&hsp_attr)); + if (hsp_attr->associated_id == array_id) + break; + + obj_id = obj_get_sibling(raid_tab, obj_id); + if (obj_id < OBJ_NONE) + return (obj_id); + } while (obj_id > OBJ_NONE); + + return (obj_id); +} + +static raid_obj_id_t +obj_locate_disk(raid_obj_tab_t *raid_tab, uint32_t controller_id, + uint32_t disk_id) +{ + raid_obj_id_t obj_id; + disk_attr_t *attr; + + obj_id = obj_locate_controller(raid_tab, controller_id); + if (obj_id <= OBJ_NONE) + return (obj_id); + + obj_id = obj_get_comp(raid_tab, obj_id, OBJ_TYPE_DISK); + if (obj_id <= OBJ_NONE) + return (obj_id); + + do { + attr = raid_obj_get_data_ptr(raid_tab, obj_id); + if (attr == NULL) + return (ERR_DEVICE_INVALID); + + if (attr->disk_id == disk_id) + break; + } while ((obj_id = obj_get_sibling(raid_tab, obj_id)) > OBJ_NONE); + + return (obj_id); +} + +static raid_obj_id_t +obj_locate_arraypart(raid_obj_tab_t *raid_tab, uint32_t controller_id, + uint32_t array_id, uint32_t disk_id) +{ + raid_obj_id_t obj_id; + + arraypart_attr_t *attr; + + obj_id = obj_locate_array(raid_tab, controller_id, array_id); + if (obj_id <= OBJ_NONE) + return (obj_id); + + obj_id = obj_get_comp(raid_tab, obj_id, OBJ_TYPE_ARRAY_PART); + if (obj_id <= OBJ_NONE) + return (obj_id); + + do { + attr = raid_obj_get_data_ptr(raid_tab, obj_id); + if (attr == NULL) + return (ERR_DEVICE_INVALID); + + if (attr->disk_id == disk_id) + break; + } while ((obj_id = obj_get_sibling(raid_tab, obj_id)) > + OBJ_NONE); + + return (obj_id); +} + +static raid_obj_id_t +obj_locate_diskseg(raid_obj_tab_t *raid_tab, uint32_t controller_id, + uint32_t disk_id, uint32_t seq_no) +{ + raid_obj_id_t obj_id; + diskseg_attr_t *attr; + + obj_id = obj_locate_disk(raid_tab, controller_id, disk_id); + if (obj_id <= OBJ_NONE) + return (obj_id); + + obj_id = obj_get_comp(raid_tab, obj_id, OBJ_TYPE_DISK_SEG); + if (obj_id <= OBJ_NONE) + return (obj_id); + + do { + attr = raid_obj_get_data_ptr(raid_tab, obj_id); + if (attr == NULL) + return (ERR_DEVICE_INVALID); + + if (attr->seq_no == seq_no) + break; + } while ((obj_id = obj_get_sibling(raid_tab, obj_id)) > OBJ_NONE); + + return (obj_id); +} + +static raid_obj_id_t +obj_locate_task(raid_obj_tab_t *raid_tab, uint32_t controller_id, + uint32_t task_id) +{ + raid_obj_id_t obj_id, obj_id2, task_obj_id; + task_attr_t *attr; + + obj_id = obj_locate_controller(raid_tab, controller_id); + if (obj_id <= OBJ_NONE) + return (obj_id); + + obj_id = obj_get_comp(raid_tab, obj_id, OBJ_TYPE_ARRAY); + if (obj_id < OBJ_NONE) + return (obj_id); + + do { + obj_id2 = obj_get_comp(raid_tab, obj_id, OBJ_TYPE_ARRAY); + while (obj_id2 != OBJ_NONE) { + task_obj_id = obj_get_comp(raid_tab, obj_id2, + OBJ_TYPE_TASK); + + if (task_obj_id < OBJ_NONE) + return (task_obj_id); + + if (task_obj_id == OBJ_NONE) { + obj_id2 = obj_get_sibling(raid_tab, obj_id2); + continue; + } + + attr = raid_obj_get_data_ptr(raid_tab, task_obj_id); + if (attr == NULL) + return (ERR_DEVICE_INVALID); + + if (attr->task_id == task_id) + return (task_obj_id); + + obj_id2 = obj_get_sibling(raid_tab, obj_id2); + } + + task_obj_id = obj_get_comp(raid_tab, obj_id, OBJ_TYPE_TASK); + if (task_obj_id < OBJ_NONE) + return (task_obj_id); + + if (task_obj_id == OBJ_NONE) + continue; + + attr = raid_obj_get_data_ptr(raid_tab, task_obj_id); + if (attr == NULL) + return (ERR_DEVICE_INVALID); + + if (attr->task_id == task_id) + return (task_obj_id); + } while ((obj_id = obj_get_sibling(raid_tab, obj_id)) > OBJ_NONE); + + if (obj_id < OBJ_NONE) + return (obj_id); + + obj_id = obj_locate_controller(raid_tab, controller_id); + obj_id = obj_get_comp(raid_tab, obj_id, OBJ_TYPE_DISK); + if (obj_id < OBJ_NONE) + return (obj_id); + + do { + task_obj_id = obj_get_comp(raid_tab, obj_id, OBJ_TYPE_TASK); + if (task_obj_id < OBJ_NONE) + return (task_obj_id); + + if (task_obj_id == OBJ_NONE) + continue; + + attr = raid_obj_get_data_ptr(raid_tab, task_obj_id); + if (attr == NULL) + return (ERR_DEVICE_INVALID); + + if (attr->task_id == task_id) + return (task_obj_id); + } while ((obj_id = obj_get_sibling(raid_tab, obj_id)) > OBJ_NONE); + + return (obj_id); + +} + +static raid_obj_id_t +obj_get_controller(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id) +{ + raid_obj_id_t id = obj_id; + + while (raid_obj_get_type(raid_tab, id) != OBJ_TYPE_CONTROLLER) { + id = raid_obj_get_container(raid_tab, id); + if ((id == OBJ_SYSTEM) || (id < OBJ_NONE)) + return (ERR_DEVICE_INVALID); + } + + return (id); +} + +/* + * Raid object operation routines + */ +static int +obj_sys_compnum(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id, + raid_obj_type_id_t comp_type) +{ + DIR *dir; + struct dirent *dp; + int num = 0; + + if ((raid_obj_get_type(raid_tab, obj_id) != OBJ_TYPE_SYSTEM)) + return (ERR_DEVICE_TYPE); + + if (comp_type != OBJ_TYPE_CONTROLLER) + return (0); + + if ((dir = opendir(CFGDIR)) == NULL) + return (ERR_DRIVER_NOT_FOUND); + + while ((dp = readdir(dir)) != NULL) { + uint32_t controller_id; + char path[MAX_PATH_LEN]; + + if (strcmp(dp->d_name, ".") == 0 || + strcmp(dp->d_name, "..") == 0) + continue; + + if (sscanf(dp->d_name, "c%u", &controller_id) != 1) + continue; + + if (controller_id_to_path(controller_id, path) == SUCCESS) + ++ num; + } + + (void) closedir(dir); + return (num); +} + +static int +obj_sys_complist(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id, + int num, raid_obj_id_t *comp_list, raid_obj_type_id_t comp_type) +{ + DIR *dir; + struct dirent *dp; + controller_attr_t *attr; + uint32_t controller_id; + uint32_t *tmplist; + char path[MAX_PATH_LEN]; + int i = 0; + + if (raid_obj_get_type(raid_tab, obj_id) != OBJ_TYPE_SYSTEM) + return (ERR_DEVICE_TYPE); + if ((num <= 0) || (comp_list == NULL)) + return (ERR_OP_ILLEGAL); + + if (comp_type != OBJ_TYPE_CONTROLLER) + return (0); + + if ((dir = opendir(CFGDIR)) == NULL) + return (ERR_DRIVER_NOT_FOUND); + tmplist = calloc(num, sizeof (uint32_t)); + if (tmplist == NULL) { + return (ERR_NOMEM); + } + while ((dp = readdir(dir)) != NULL) { + if (strcmp(dp->d_name, ".") == 0 || + strcmp(dp->d_name, "..") == 0) + continue; + + if (sscanf(dp->d_name, "c%u", &controller_id) != 1) + continue; + + if (controller_id_to_path(controller_id, path) == SUCCESS) { + tmplist[i] = controller_id; + ++ i; + } + } + qsort((void *)tmplist, num, sizeof (uint32_t), intcompare); + for (i = 0; i < num; i++) { + attr = raid_obj_get_data_ptr(raid_tab, + *(comp_list + i)); + + if (attr == NULL) { + free(tmplist); + return (ERR_DEVICE_INVALID); + } + + attr->controller_id = tmplist[i]; + } + free(tmplist); + (void) closedir(dir); + return (SUCCESS); +} + +static int +obj_controller_compnum(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id, + raid_obj_type_id_t comp_type) +{ + raid_lib_t *raid_lib; + int ret = SUCCESS, fd; + controller_attr_t *ctl_attrp; + + if (raid_obj_get_type(raid_tab, obj_id) != OBJ_TYPE_CONTROLLER) + return (ERR_DEVICE_TYPE); + + if ((comp_type != OBJ_TYPE_ARRAY) && (comp_type != OBJ_TYPE_DISK)) + return (0); + + raid_lib = raid_obj_get_lib(raid_tab, obj_id); + fd = raid_obj_get_fd(raid_tab, obj_id); + ctl_attrp = raid_obj_get_data_ptr(raid_tab, obj_id); + if ((raid_lib == NULL) || (ctl_attrp == NULL) || (fd == 0)) + return (ERR_DRIVER_CLOSED); + + ret = raid_lib->compnum(ctl_attrp->controller_id, 0, + OBJ_TYPE_CONTROLLER, comp_type); + + return (ret); +} + +static int +obj_controller_complist(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id, + int comp_num, raid_obj_id_t *comp_list, raid_obj_type_id_t comp_type) +{ + raid_lib_t *raid_lib; + controller_attr_t *ctl_attrp; + int ret, i, fd; + uint32_t *ids; + + if (raid_obj_get_type(raid_tab, obj_id) != OBJ_TYPE_CONTROLLER) + return (ERR_DEVICE_TYPE); + + if ((comp_type != OBJ_TYPE_ARRAY) && (comp_type != OBJ_TYPE_DISK)) + return (0); + + if ((comp_num <= 0) || (comp_list == NULL)) + return (ERR_OP_ILLEGAL); + + for (i = 0; i < comp_num; ++i) + if (raid_obj_get_type(raid_tab, *(comp_list + i)) != + comp_type) + return (ERR_DEVICE_TYPE); + + raid_lib = raid_obj_get_lib(raid_tab, obj_id); + ctl_attrp = raid_obj_get_data_ptr(raid_tab, obj_id); + fd = raid_obj_get_fd(raid_tab, obj_id); + if ((raid_lib == NULL) || (ctl_attrp == NULL)|| (fd == 0)) + return (ERR_DRIVER_CLOSED); + + ids = malloc(comp_num * sizeof (uint32_t)); + if (ids == NULL) + return (ERR_NOMEM); + + ret = raid_lib->complist(ctl_attrp->controller_id, 0, + OBJ_TYPE_CONTROLLER, comp_type, comp_num, ids); + if (ret < SUCCESS) { + free(ids); + return (ret); + } + qsort((void *)ids, comp_num, sizeof (uint32_t), intcompare); + for (i = 0; i < comp_num; ++ i) { + array_attr_t *array_attr; + disk_attr_t *disk_attr; + void *attr_buf; + + attr_buf = raid_obj_get_data_ptr(raid_tab, *(comp_list + i)); + if (attr_buf == NULL) { + free(ids); + return (ERR_DEVICE_INVALID); + } + + switch (comp_type) { + case OBJ_TYPE_ARRAY: + array_attr = attr_buf; + array_attr->array_id = *(ids + i); + break; + case OBJ_TYPE_DISK: + disk_attr = attr_buf; + disk_attr->disk_id = *(ids + i); + break; + default: + free(ids); + return (ERR_DEVICE_INVALID); + } + } + + free(ids); + return (SUCCESS); +} + +static int +obj_controller_get_attr(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id) +{ + controller_attr_t *attr; + raid_lib_t *raid_lib; + int ret = SUCCESS, fd; + + if (raid_obj_get_type(raid_tab, obj_id) != OBJ_TYPE_CONTROLLER) + return (ERR_DEVICE_TYPE); + + if (raid_obj_get_status(raid_tab, obj_id) & OBJ_STATUS_OPENED) + return (SUCCESS); + + attr = raid_obj_get_data_ptr(raid_tab, obj_id); + if (attr == NULL) + return (ERR_DEVICE_INVALID); + + raid_lib = raid_obj_get_lib(raid_tab, obj_id); + fd = raid_obj_get_fd(raid_tab, obj_id); + + /* + * For a controller, even it's not opened, we can still + * get the driver name + */ + + if (fd == 0) + return (SUCCESS); + + if (raid_lib == NULL) { + return (SUCCESS); + } + + ret = raid_lib->get_attr(attr->controller_id, OBJ_ATTR_NONE, + OBJ_ATTR_NONE, OBJ_TYPE_CONTROLLER, attr); + if (ret < SUCCESS) + return (ret); + + (void) raid_obj_set_status(raid_tab, obj_id, OBJ_STATUS_OPENED); + + return (ret); +} + +static int +obj_controller_act(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id, + uint32_t sub_cmd, void *prop_list, char **plugin_err_str) +{ + controller_attr_t *attr; + raid_lib_t *raid_lib; + int ret, fd; + + if (raid_obj_get_type(raid_tab, obj_id) != OBJ_TYPE_CONTROLLER) + return (ERR_DEVICE_TYPE); + + attr = raid_obj_get_data_ptr(raid_tab, obj_id); + + raid_lib = raid_obj_get_lib(raid_tab, obj_id); + fd = raid_obj_get_fd(raid_tab, obj_id); + + switch (sub_cmd) { + case ACT_CONTROLLER_OPEN: + /* Check if already opened */ + + if (fd > 0) + return (SUCCESS); + + /* Check if plugin is already attached */ + if (raid_lib == NULL) { + raid_lib = raid_find_lib(raid_tab, obj_id); + if (raid_lib == NULL) + return (ERR_DRIVER_NOT_FOUND); + } + + ret = raid_lib->open_controller(attr->controller_id, + plugin_err_str); + if (ret == SUCCESS) { + (void) raid_obj_set_lib(raid_tab, obj_id, raid_lib); + (void) raid_obj_set_fd(raid_tab, obj_id, 1); + } + break; + case ACT_CONTROLLER_CLOSE: + + if (fd <= 0) + return (SUCCESS); + + if (raid_lib == NULL) { + return (SUCCESS); + } + ret = raid_lib->close_controller(attr->controller_id, + plugin_err_str); + if (ret == SUCCESS) { + (void) raid_obj_set_fd(raid_tab, obj_id, 0); + (void) raid_obj_set_lib(raid_tab, obj_id, NULL); + raid_handle_delete_controller_comp(attr->controller_id); + } + break; + case ACT_CONTROLLER_FLASH_FW: + { + char *filebuf; + int image_fd; + uint32_t size; + struct stat statbuf; + + if (prop_list == NULL) + return (ERR_OP_ILLEGAL); + + /* Open firmware image file */ + image_fd = open((const char *)prop_list, + O_RDONLY | O_NDELAY); + if (image_fd == -1) + return (ERR_OP_FAILED); + + if (fstat(image_fd, &statbuf) != 0) { + (void) close(image_fd); + return (ERR_OP_FAILED); + } + + filebuf = malloc(statbuf.st_size); + if (filebuf == NULL) { + (void) close(image_fd); + return (ERR_NOMEM); + } + + size = read(image_fd, filebuf, statbuf.st_size); + if (size != statbuf.st_size) { + (void) close(image_fd); + free(filebuf); + return (ERR_OP_FAILED); + } + + if (fd <= 0) { + (void) close(image_fd); + free(filebuf); + return (ERR_DRIVER_CLOSED); + } + + if (raid_lib == NULL) { + (void) close(image_fd); + free(filebuf); + return (ERR_DRIVER_CLOSED); + } + if (raid_lib->flash_fw == NULL) { + (void) close(image_fd); + free(filebuf); + return (ERR_OP_NO_IMPL); + } + + ret = raid_lib->flash_fw(attr->controller_id, + filebuf, size, plugin_err_str); + } + break; + default: + return (ERR_OP_ILLEGAL); + } + + return (ret); +} + +static int +obj_array_compnum(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id, + raid_obj_type_id_t comp_type) +{ + array_attr_t *attr; + controller_attr_t *ctl_attrp; + raid_obj_id_t controller_obj_id; + raid_lib_t *raid_lib; + int ret = SUCCESS, fd; + + if (raid_obj_get_type(raid_tab, obj_id) != OBJ_TYPE_ARRAY) + return (ERR_DEVICE_TYPE); + + if (comp_type != OBJ_TYPE_ARRAY_PART && + comp_type != OBJ_TYPE_ARRAY && + comp_type != OBJ_TYPE_TASK) + return (0); + + attr = raid_obj_get_data_ptr(raid_tab, obj_id); + if (attr == NULL) + return (ERR_DEVICE_INVALID); + + controller_obj_id = obj_get_controller(raid_tab, obj_id); + if (controller_obj_id < OBJ_NONE) + return (ERR_DEVICE_INVALID); + + ctl_attrp = raid_obj_get_data_ptr(raid_tab, controller_obj_id); + if (ctl_attrp == NULL) { + return (ERR_DEVICE_INVALID); + } + + raid_lib = raid_obj_get_lib(raid_tab, controller_obj_id); + fd = raid_obj_get_fd(raid_tab, controller_obj_id); + if ((raid_lib == NULL) || (fd == 0)) + return (ERR_DRIVER_CLOSED); + + ret = raid_lib->compnum(ctl_attrp->controller_id, attr->array_id, + OBJ_TYPE_ARRAY, comp_type); + + return (ret); +} + +static int +obj_array_complist(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id, + int comp_num, raid_obj_id_t *comp_list, raid_obj_type_id_t comp_type) +{ + array_attr_t *attr; + controller_attr_t *ctl_attrp; + raid_obj_id_t controller_obj_id; + raid_lib_t *raid_lib; + int ret, i, fd; + uint32_t *ids; + + if (raid_obj_get_type(raid_tab, obj_id) != OBJ_TYPE_ARRAY) + return (ERR_DEVICE_TYPE); + + if (comp_type != OBJ_TYPE_ARRAY_PART && + comp_type != OBJ_TYPE_ARRAY && + comp_type != OBJ_TYPE_TASK) + return (0); + + if (comp_num <= 0 || comp_list == NULL) + return (ERR_OP_ILLEGAL); + + for (i = 0; i < comp_num; ++i) + if (raid_obj_get_type(raid_tab, *(comp_list + i)) != + comp_type) + return (ERR_DEVICE_TYPE); + + attr = raid_obj_get_data_ptr(raid_tab, obj_id); + if (attr == NULL) + return (ERR_DEVICE_INVALID); + + controller_obj_id = obj_get_controller(raid_tab, obj_id); + if (controller_obj_id < OBJ_NONE) + return (ERR_DEVICE_INVALID); + + ctl_attrp = raid_obj_get_data_ptr(raid_tab, controller_obj_id); + if (ctl_attrp == NULL) { + return (ERR_DEVICE_INVALID); + } + + raid_lib = raid_obj_get_lib(raid_tab, controller_obj_id); + fd = raid_obj_get_fd(raid_tab, controller_obj_id); + if ((raid_lib == NULL) || (fd == 0)) + return (ERR_DRIVER_CLOSED); + + ids = malloc(comp_num * sizeof (uint32_t)); + if (ids == NULL) + return (ERR_NOMEM); + + ret = raid_lib->complist(ctl_attrp->controller_id, + attr->array_id, OBJ_TYPE_ARRAY, comp_type, comp_num, ids); + + if (ret < SUCCESS) { + free(ids); + return (ret); + } + + for (i = 0; i < comp_num; ++ i) { + array_attr_t *array_attr; + arraypart_attr_t *arraypart_attr; + task_attr_t *task_attr; + void *attr_buf; + + attr_buf = raid_obj_get_data_ptr(raid_tab, *(comp_list + i)); + if (attr_buf == NULL) { + free(ids); + return (ERR_DEVICE_INVALID); + } + + switch (comp_type) { + case OBJ_TYPE_ARRAY: + array_attr = attr_buf; + array_attr->array_id = *(ids + i); + break; + case OBJ_TYPE_ARRAY_PART: + arraypart_attr = attr_buf; + arraypart_attr->disk_id = *(ids + i); + break; + case OBJ_TYPE_TASK: + task_attr = attr_buf; + task_attr->task_id = *(ids + i); + break; + default: + free(ids); + return (ERR_DEVICE_INVALID); + } + } + + + free(ids); + return (ret); +} + +static int +obj_array_get_attr(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id) +{ + array_attr_t *attr; + controller_attr_t *ctl_attrp; + raid_lib_t *raid_lib; + int ret = SUCCESS, fd; + raid_obj_id_t controller_obj_id; + + if (raid_obj_get_type(raid_tab, obj_id) != OBJ_TYPE_ARRAY) + return (ERR_DEVICE_TYPE); + + if (raid_obj_get_status(raid_tab, obj_id) & OBJ_STATUS_OPENED) + return (SUCCESS); + + attr = raid_obj_get_data_ptr(raid_tab, obj_id); + if (attr == NULL) + return (ERR_DEVICE_INVALID); + + controller_obj_id = obj_get_controller(raid_tab, obj_id); + if (controller_obj_id < OBJ_NONE) + return (ERR_DEVICE_INVALID); + + ctl_attrp = raid_obj_get_data_ptr(raid_tab, controller_obj_id); + if (ctl_attrp == NULL) { + return (ERR_DEVICE_INVALID); + } + + raid_lib = raid_obj_get_lib(raid_tab, controller_obj_id); + fd = raid_obj_get_fd(raid_tab, controller_obj_id); + if ((raid_lib == NULL) || (fd == 0)) + return (ERR_DRIVER_CLOSED); + + ret = raid_lib->get_attr(ctl_attrp->controller_id, + attr->array_id, 0, OBJ_TYPE_ARRAY, attr); + + if (ret < SUCCESS) + return (ret); + + (void) raid_obj_set_status(raid_tab, obj_id, OBJ_STATUS_OPENED); + + return (ret); +} + +static int +obj_array_set_attr(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id, + uint32_t sub_cmd, uint32_t *value, char **plugin_err_str) +{ + array_attr_t *attr; + controller_attr_t *ctl_attrp; + raid_lib_t *raid_lib; + int ret = SUCCESS, fd; + raid_obj_id_t controller_obj_id; + + if (raid_obj_get_type(raid_tab, obj_id) != OBJ_TYPE_ARRAY) + return (ERR_DEVICE_TYPE); + + switch (sub_cmd) { + case SET_CACHE_WR_PLY: + if (*value != CACHE_WR_OFF && + *value != CACHE_WR_ON) + return (ERR_OP_ILLEGAL); + break; + case SET_CACHE_RD_PLY: + if (*value != CACHE_RD_OFF && + *value != CACHE_RD_ON) + return (ERR_OP_ILLEGAL); + break; + default: + return (ERR_OP_ILLEGAL); + } + + (void) obj_get_attr(raid_tab, obj_id, (void **)(&attr)); + + controller_obj_id = obj_get_controller(raid_tab, obj_id); + if (controller_obj_id < OBJ_NONE) + return (ERR_DEVICE_INVALID); + + ctl_attrp = raid_obj_get_data_ptr(raid_tab, controller_obj_id); + if (ctl_attrp == NULL) { + return (ERR_DEVICE_INVALID); + } + + raid_lib = raid_obj_get_lib(raid_tab, controller_obj_id); + fd = raid_obj_get_fd(raid_tab, controller_obj_id); + if ((raid_lib == NULL) || (fd == 0)) + return (ERR_DRIVER_CLOSED); + + if (raid_lib->set_attr == NULL) + return (ERR_OP_NO_IMPL); + + ret = raid_lib->set_attr(ctl_attrp->controller_id, + attr->array_id, sub_cmd, value, plugin_err_str); + + return (ret); +} + +static int +obj_disk_compnum(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id, + raid_obj_type_id_t comp_type) +{ + disk_attr_t *attr; + controller_attr_t *ctl_attrp; + raid_obj_id_t controller_obj_id; + raid_lib_t *raid_lib; + int ret = SUCCESS, fd; + + if (raid_obj_get_type(raid_tab, obj_id) != OBJ_TYPE_DISK) + return (ERR_DEVICE_TYPE); + + if (comp_type != OBJ_TYPE_DISK_SEG && + comp_type != OBJ_TYPE_HSP && + comp_type != OBJ_TYPE_TASK) + return (0); + ret = obj_get_attr(raid_tab, obj_id, (void **)(&attr)); + if ((ret != SUCCESS) || (attr == NULL)) { + return (ERR_DEVICE_INVALID); + } + if (attr->state == DISK_STATE_FAILED) { + return (SUCCESS); + } + + controller_obj_id = obj_get_controller(raid_tab, obj_id); + if (controller_obj_id < OBJ_NONE) + return (ERR_DEVICE_INVALID); + + ctl_attrp = raid_obj_get_data_ptr(raid_tab, controller_obj_id); + if (ctl_attrp == NULL) { + return (ERR_DEVICE_INVALID); + } + + raid_lib = raid_obj_get_lib(raid_tab, controller_obj_id); + fd = raid_obj_get_fd(raid_tab, controller_obj_id); + if ((raid_lib == NULL) || (fd == 0)) + return (ERR_DRIVER_CLOSED); + + ret = raid_lib->compnum(ctl_attrp->controller_id, + attr->disk_id, OBJ_TYPE_DISK, comp_type); + + return (ret); +} + +static int +obj_disk_complist(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id, + int comp_num, raid_obj_id_t *comp_list, raid_obj_type_id_t comp_type) +{ + disk_attr_t *attr; + controller_attr_t *ctl_attrp; + raid_obj_id_t controller_obj_id; + raid_lib_t *raid_lib; + int ret, i, fd; + uint32_t *ids; + + if (raid_obj_get_type(raid_tab, obj_id) != OBJ_TYPE_DISK) + return (ERR_DEVICE_TYPE); + + if (comp_type != OBJ_TYPE_DISK_SEG && + comp_type != OBJ_TYPE_HSP && + comp_type != OBJ_TYPE_TASK) + return (0); + + if (comp_num <= 0 || comp_list == NULL) + return (ERR_OP_ILLEGAL); + + for (i = 0; i < comp_num; ++i) + if (raid_obj_get_type(raid_tab, *(comp_list + i)) != + comp_type) + return (ERR_DEVICE_TYPE); + ret = obj_get_attr(raid_tab, obj_id, (void **)(&attr)); + if ((ret != SUCCESS) || (attr == NULL)) { + return (ERR_DEVICE_INVALID); + } + if (attr->state == DISK_STATE_FAILED) { + return (SUCCESS); + } + + controller_obj_id = obj_get_controller(raid_tab, obj_id); + if (controller_obj_id < OBJ_NONE) + return (ERR_DEVICE_INVALID); + + ctl_attrp = raid_obj_get_data_ptr(raid_tab, controller_obj_id); + if (ctl_attrp == NULL) { + return (ERR_DEVICE_INVALID); + } + + raid_lib = raid_obj_get_lib(raid_tab, controller_obj_id); + fd = raid_obj_get_fd(raid_tab, controller_obj_id); + if ((raid_lib == NULL) || (fd == 0)) + return (ERR_DRIVER_CLOSED); + + ids = malloc(comp_num * sizeof (uint32_t)); + if (ids == NULL) + return (ERR_NOMEM); + + ret = raid_lib->complist(ctl_attrp->controller_id, + attr->disk_id, OBJ_TYPE_DISK, comp_type, comp_num, ids); + + if (ret < SUCCESS) { + free(ids); + return (ret); + } + + for (i = 0; i < comp_num; ++ i) { + diskseg_attr_t *diskseg_attr; + hsp_attr_t *hsp_attr; + task_attr_t *task_attr; + void *attr_buf; + + attr_buf = raid_obj_get_data_ptr(raid_tab, *(comp_list + i)); + if (attr_buf == NULL) { + free(ids); + return (ERR_DEVICE_INVALID); + } + + switch (comp_type) { + case OBJ_TYPE_DISK_SEG: + diskseg_attr = attr_buf; + diskseg_attr->seq_no = *(ids + i); + break; + case OBJ_TYPE_HSP: + hsp_attr = attr_buf; + hsp_attr->associated_id = *(ids + i); + break; + case OBJ_TYPE_TASK: + task_attr = attr_buf; + task_attr->task_id = *(ids + i); + break; + default: + free(ids); + return (ERR_DEVICE_INVALID); + } + } + + + free(ids); + return (ret); +} + +static int +obj_disk_get_attr(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id) +{ + disk_attr_t *attr; + controller_attr_t *ctl_attrp; + raid_lib_t *raid_lib; + int ret = SUCCESS, fd; + raid_obj_id_t controller_obj_id; + + if (raid_obj_get_type(raid_tab, obj_id) != OBJ_TYPE_DISK) + return (ERR_DEVICE_TYPE); + + if (raid_obj_get_status(raid_tab, obj_id) & OBJ_STATUS_OPENED) + return (SUCCESS); + + attr = raid_obj_get_data_ptr(raid_tab, obj_id); + if (attr == NULL) + return (ERR_DEVICE_INVALID); + + controller_obj_id = obj_get_controller(raid_tab, obj_id); + if (controller_obj_id < OBJ_NONE) + return (ERR_DEVICE_INVALID); + + ctl_attrp = raid_obj_get_data_ptr(raid_tab, controller_obj_id); + if (ctl_attrp == NULL) { + return (ERR_DEVICE_INVALID); + } + + raid_lib = raid_obj_get_lib(raid_tab, controller_obj_id); + fd = raid_obj_get_fd(raid_tab, controller_obj_id); + if ((raid_lib == NULL) || (fd == 0)) + return (ERR_DRIVER_CLOSED); + + ret = raid_lib->get_attr(ctl_attrp->controller_id, + attr->disk_id, 0, OBJ_TYPE_DISK, attr); + + if (ret < SUCCESS) + return (ret); + + (void) raid_obj_set_status(raid_tab, obj_id, OBJ_STATUS_OPENED); + + return (ret); +} + +static int +obj_hsp_get_attr(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id) +{ + hsp_attr_t *attr; + + if (raid_obj_get_type(raid_tab, obj_id) != OBJ_TYPE_HSP) + return (ERR_DEVICE_TYPE); + + if (raid_obj_get_status(raid_tab, obj_id) & OBJ_STATUS_OPENED) + return (SUCCESS); + + attr = raid_obj_get_data_ptr(raid_tab, obj_id); + if (attr == NULL) + return (ERR_DEVICE_INVALID); + + if (attr->associated_id == (uint32_t)OBJ_ATTR_NONE) + attr->type = HSP_TYPE_GLOBAL; + else + attr->type = HSP_TYPE_LOCAL; + + return (SUCCESS); +} + +static int +obj_arraypart_get_attr(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id) +{ + arraypart_attr_t *attr; + array_attr_t *array_attr; + controller_attr_t *ctl_attrp; + raid_lib_t *raid_lib; + int ret = SUCCESS, fd; + raid_obj_id_t controller_obj_id, array_obj_id; + + if (raid_obj_get_type(raid_tab, obj_id) != OBJ_TYPE_ARRAY_PART) + return (ERR_DEVICE_TYPE); + + if (raid_obj_get_status(raid_tab, obj_id) & OBJ_STATUS_OPENED) + return (SUCCESS); + + attr = raid_obj_get_data_ptr(raid_tab, obj_id); + if (attr == NULL) + return (ERR_DEVICE_INVALID); + + array_obj_id = raid_obj_get_container(raid_tab, obj_id); + if (array_obj_id < OBJ_NONE) + return (ERR_DEVICE_INVALID); + + array_attr = raid_obj_get_data_ptr(raid_tab, array_obj_id); + if (array_attr == NULL) + return (ERR_DEVICE_INVALID); + + controller_obj_id = obj_get_controller(raid_tab, obj_id); + if (controller_obj_id < OBJ_NONE) + return (ERR_DEVICE_INVALID); + + ctl_attrp = raid_obj_get_data_ptr(raid_tab, controller_obj_id); + if (ctl_attrp == NULL) { + return (ERR_DEVICE_INVALID); + } + + raid_lib = raid_obj_get_lib(raid_tab, controller_obj_id); + fd = raid_obj_get_fd(raid_tab, controller_obj_id); + if ((raid_lib == NULL) || (fd == 0)) + return (ERR_DRIVER_CLOSED); + + ret = raid_lib->get_attr(ctl_attrp->controller_id, + array_attr->array_id, attr->disk_id, + OBJ_TYPE_ARRAY_PART, attr); + + if (ret < SUCCESS) + return (ret); + + (void) raid_obj_set_status(raid_tab, obj_id, OBJ_STATUS_OPENED); + + return (ret); +} + +static int +obj_diskseg_get_attr(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id) +{ + diskseg_attr_t *attr; + disk_attr_t *disk_attr; + controller_attr_t *ctl_attrp; + raid_lib_t *raid_lib; + int ret = SUCCESS, fd; + raid_obj_id_t controller_obj_id, disk_obj_id; + + if (raid_obj_get_type(raid_tab, obj_id) != OBJ_TYPE_DISK_SEG) + return (ERR_DEVICE_TYPE); + + if (raid_obj_get_status(raid_tab, obj_id) & OBJ_STATUS_OPENED) + return (SUCCESS); + + attr = raid_obj_get_data_ptr(raid_tab, obj_id); + if (attr == NULL) + return (ERR_DEVICE_INVALID); + + disk_obj_id = raid_obj_get_container(raid_tab, obj_id); + if (disk_obj_id < OBJ_NONE) + return (ERR_DEVICE_INVALID); + + disk_attr = raid_obj_get_data_ptr(raid_tab, disk_obj_id); + if (disk_attr == NULL) + return (ERR_DEVICE_INVALID); + + controller_obj_id = obj_get_controller(raid_tab, obj_id); + if (controller_obj_id < OBJ_NONE) + return (ERR_DEVICE_INVALID); + + ctl_attrp = raid_obj_get_data_ptr(raid_tab, controller_obj_id); + if (ctl_attrp == NULL) { + return (ERR_DEVICE_INVALID); + } + + raid_lib = raid_obj_get_lib(raid_tab, controller_obj_id); + fd = raid_obj_get_fd(raid_tab, controller_obj_id); + if ((raid_lib == NULL) || (fd == 0)) + return (ERR_DRIVER_CLOSED); + + ret = raid_lib->get_attr(ctl_attrp->controller_id, + disk_attr->disk_id, attr->seq_no, OBJ_TYPE_DISK_SEG, attr); + + if (ret < SUCCESS) + return (ret); + + (void) raid_obj_set_status(raid_tab, obj_id, OBJ_STATUS_OPENED); + + return (ret); +} + +static int +obj_task_get_attr(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id) +{ + task_attr_t *attr; + controller_attr_t *ctl_attrp; + raid_lib_t *raid_lib; + int ret = SUCCESS, fd; + raid_obj_id_t controller_obj_id; + + if (raid_obj_get_type(raid_tab, obj_id) != OBJ_TYPE_TASK) + return (ERR_DEVICE_TYPE); + + attr = raid_obj_get_data_ptr(raid_tab, obj_id); + if (attr == NULL) + return (ERR_DEVICE_INVALID); + + controller_obj_id = obj_get_controller(raid_tab, obj_id); + if (controller_obj_id < OBJ_NONE) + return (ERR_DEVICE_INVALID); + + ctl_attrp = raid_obj_get_data_ptr(raid_tab, controller_obj_id); + if (ctl_attrp == NULL) { + return (ERR_DEVICE_INVALID); + } + + raid_lib = raid_obj_get_lib(raid_tab, controller_obj_id); + fd = raid_obj_get_fd(raid_tab, controller_obj_id); + if ((raid_lib == NULL) || (fd == 0)) + return (ERR_DRIVER_CLOSED); + + ret = raid_lib->get_attr(ctl_attrp->controller_id, + attr->task_id, OBJ_ATTR_NONE, OBJ_TYPE_TASK, attr); + + return (ret); +} + +static int +obj_array_create(raid_obj_tab_t *raid_tab, raid_obj_id_t array_obj_id, + int num_of_comp, raid_obj_id_t *disk_list, char **plugin_err_str) +{ + controller_attr_t *controller_attr; + array_attr_t *array_attr, array_attr2; + disk_attr_t *disk_attr; + arraypart_attr_t *arraypart_attrs; + raid_obj_id_t obj_id, controller_obj_id = OBJ_NONE; + raid_lib_t *raid_lib; + int i, j, ret, fd; + int disk_cnt = 0, disk_set_num = 0, set_num = 0, layer_cnt = 0; + uint64_t min_disk_capacity = 0; + uint32_t *diskid_list; + + array_attr = raid_obj_get_data_ptr(raid_tab, array_obj_id); + if (array_attr == NULL) + return (ERR_DEVICE_INVALID); + + /* Check the disk layout expression */ + if (disk_list[0] != OBJ_SEPARATOR_BEGIN || + disk_list[num_of_comp - 1] != OBJ_SEPARATOR_END) + return (ERR_ARRAY_LAYOUT); + for (i = 0; i < num_of_comp; ++i) { + if (disk_list[i] == OBJ_SEPARATOR_BEGIN) { + if (disk_cnt != 0) + return (ERR_ARRAY_LAYOUT); + ++layer_cnt; + continue; + } + if (disk_list[i] == OBJ_SEPARATOR_END) { + if (disk_set_num == 0) + disk_set_num = disk_cnt; + else if (disk_set_num != disk_cnt && disk_cnt != 0) + return (ERR_ARRAY_LAYOUT); + disk_cnt = 0; + ++set_num; + --layer_cnt; + continue; + } + switch (array_attr->raid_level) { + case RAID_LEVEL_0: + case RAID_LEVEL_1: + case RAID_LEVEL_1E: + case RAID_LEVEL_5: + if (layer_cnt != 1) + return (ERR_ARRAY_LAYOUT); + break; + case RAID_LEVEL_10: + case RAID_LEVEL_50: + if (layer_cnt != 2) + return (ERR_ARRAY_LAYOUT); + break; + default: + return (ERR_ARRAY_LEVEL); + } + ++disk_cnt; + } + + if (layer_cnt != 0) + return (ERR_ARRAY_LAYOUT); + + switch (array_attr->raid_level) { + case RAID_LEVEL_0: + if (disk_set_num < 2 || set_num != 1) + return (ERR_ARRAY_LAYOUT); + break; + case RAID_LEVEL_1: + if (disk_set_num != 2 || set_num != 1) + return (ERR_ARRAY_LAYOUT); + break; + case RAID_LEVEL_1E: + case RAID_LEVEL_5: + if (disk_set_num < 3 || set_num != 1) + return (ERR_ARRAY_LAYOUT); + break; + case RAID_LEVEL_10: + if (disk_set_num != 2 || set_num < 2) + return (ERR_ARRAY_LAYOUT); + break; + case RAID_LEVEL_50: + if (disk_set_num < 3 || set_num < 2) + return (ERR_ARRAY_LAYOUT); + break; + default: + return (ERR_ARRAY_LEVEL); + } + + arraypart_attrs = calloc(num_of_comp, sizeof (arraypart_attr_t)); + if (arraypart_attrs == NULL) + return (ERR_NOMEM); + + for (i = 0; i < num_of_comp; ++i) { + /* Keep seperators */ + if (*(disk_list + i) == OBJ_SEPARATOR_BEGIN) { + arraypart_attrs[i].disk_id = + (uint32_t)OBJ_SEPARATOR_BEGIN; + continue; + } + + if (*(disk_list + i) == OBJ_SEPARATOR_END) { + arraypart_attrs[i].disk_id = + (uint32_t)OBJ_SEPARATOR_END; + continue; + } + + disk_cnt++; + /* Check if it's a disk */ + if (raid_obj_get_type(raid_tab, *(disk_list + i)) != + OBJ_TYPE_DISK) + return (ERR_DEVICE_TYPE); + + /* Check if it's duplicated with other disks */ + for (j = 0; j < i; ++j) + if (*(disk_list + j) == *(disk_list + i)) { + free(arraypart_attrs); + return (ERR_DEVICE_DUP); + } + + /* Check disk status */ + ret = obj_get_attr(raid_tab, *(disk_list + i), + (void **)(&disk_attr)); + if (ret != SUCCESS) + return (ret); + + if (disk_attr->state != DISK_STATE_GOOD) { + free(arraypart_attrs); + return (ERR_DISK_STATE); + } + + /* All disks must belong to the same controller */ + obj_id = obj_get_controller(raid_tab, *(disk_list + i)); + if (obj_id <= OBJ_NONE) + return (obj_id); + if (controller_obj_id == OBJ_NONE) { + controller_obj_id = obj_id; + ret = obj_get_attr(raid_tab, controller_obj_id, + (void **)(&controller_attr)); + } else if (obj_id != controller_obj_id) { + free(arraypart_attrs); + return (ERR_DRIVER_ACROSS); + } + + /* Check if the disk contains too many segments */ + obj_id = obj_get_comp(raid_tab, *(disk_list + i), + OBJ_TYPE_DISK_SEG); + j = 0; + while (obj_id > OBJ_NONE) { + ++j; + obj_id = obj_get_sibling(raid_tab, obj_id); + } + if (j > controller_attr->max_seg_per_disk) { + free(arraypart_attrs); + return (ERR_DISK_SEG_AMOUNT); + } + + /* Each disk should be un-used */ + if ((ret = raid_dev_unmounted(controller_attr->controller_id, + disk_attr->disk_id)) != SUCCESS) { + free(arraypart_attrs); + return (ret); + } + + /* Check if controller is a hostraid controller */ + if (controller_attr->capability & RAID_CAP_DISK_TRANS) { + /* + * For hostraid, the first disk should + * be with of minimum capacity + */ + if (min_disk_capacity == 0) { + min_disk_capacity = disk_attr->capacity; + + /* Can not specify capacity for hostraid */ + if (array_attr->capacity != 0) { + free(arraypart_attrs); + return (ERR_DISK_SPACE); + } + } else if (min_disk_capacity > disk_attr->capacity) { + free(arraypart_attrs); + return (ERR_DISK_SPACE); + } + + /* Disk should not be used for hostraid */ + obj_id = obj_get_comp(raid_tab, *(disk_list + i), + OBJ_TYPE_DISK_SEG); + if (obj_id < OBJ_NONE) { + free(arraypart_attrs); + return (obj_id); + } else if (obj_id > OBJ_NONE) { + free(arraypart_attrs); + return (ERR_DISK_NOT_EMPTY); + } + } + + arraypart_attrs[i].disk_id = disk_attr->disk_id; + arraypart_attrs[i].offset = OBJ_ATTR_NONE; + arraypart_attrs[i].size = OBJ_ATTR_NONE; + } + + /* Check if array amount exceeds limit */ + if (controller_attr->max_array_num <= + obj_controller_compnum(raid_tab, controller_obj_id, + OBJ_TYPE_ARRAY)) + return (ERR_ARRAY_AMOUNT); + + + raid_lib = raid_obj_get_lib(raid_tab, controller_obj_id); + fd = raid_obj_get_fd(raid_tab, controller_obj_id); + if ((raid_lib == NULL) || (fd == 0)) + return (ERR_DRIVER_CLOSED); + + /* Check if the controller can support the array RAID level */ + switch (array_attr->raid_level) { + case RAID_LEVEL_0: + if (!(controller_attr->capability & RAID_CAP_RAID0)) { + free(arraypart_attrs); + return (ERR_ARRAY_LEVEL); + } + break; + case RAID_LEVEL_1: + if (!(controller_attr->capability & RAID_CAP_RAID1)) { + free(arraypart_attrs); + return (ERR_ARRAY_LEVEL); + } + break; + case RAID_LEVEL_1E: + if (!(controller_attr->capability & RAID_CAP_RAID1E)) { + free(arraypart_attrs); + return (ERR_ARRAY_LEVEL); + } + break; + case RAID_LEVEL_5: + if (!(controller_attr->capability & RAID_CAP_RAID5)) { + free(arraypart_attrs); + return (ERR_ARRAY_LEVEL); + } + break; + case RAID_LEVEL_10: + if (!(controller_attr->capability & RAID_CAP_RAID10)) { + free(arraypart_attrs); + return (ERR_ARRAY_LEVEL); + } + break; + case RAID_LEVEL_50: + if (!(controller_attr->capability & RAID_CAP_RAID50)) { + free(arraypart_attrs); + return (ERR_ARRAY_LEVEL); + } + break; + default: + free(arraypart_attrs); + return (ERR_ARRAY_LEVEL); + } + + /* Check if plug in can calculate the maximum size */ + (void) memcpy(&array_attr2, array_attr, sizeof (array_attr_t)); + array_attr2.capacity = OBJ_ATTR_NONE; + ret = raid_lib->array_create(controller_attr->controller_id, + &array_attr2, num_of_comp, arraypart_attrs, plugin_err_str); + + /* If plugin/driver will not calculate space */ + if (ret == ERR_OP_NO_IMPL) { + /* Calculate the maximum capacity */ + array_attr2.capacity = raid_space_noalign(raid_tab, + array_attr2.raid_level, num_of_comp, disk_list, + arraypart_attrs); + + /* + * If controller is capable to allocate space, + * set offset and size attributes to OBJ_ATTR_NONE + * and let the controller to determine these value + */ + if (controller_attr->capability & RAID_CAP_SMART_ALLOC) + for (i = 0; i < num_of_comp; ++i) { + arraypart_attrs[i].offset = + OBJ_ATTR_NONE; + arraypart_attrs[i].size = + OBJ_ATTR_NONE; + } + + /* There's no enough space for specified capacity */ + if (array_attr->capacity > array_attr2.capacity) { + free(arraypart_attrs); + return (ERR_ARRAY_SIZE); + } + + /* capacity == 0, allocate maximum space */ + if (array_attr->capacity == 0) + array_attr->capacity = array_attr2.capacity; + } else if (ret < SUCCESS) { + free(arraypart_attrs); + return (ret); + } else if (array_attr2.capacity < array_attr->capacity) { + /* Return the maximum size */ + array_attr->capacity = array_attr2.capacity; + free(arraypart_attrs); + return (ERR_ARRAY_SIZE); + } + + if (array_attr->capacity < ARRAYPART_MIN_SIZE * disk_cnt) { + free(arraypart_attrs); + return (ERR_ARRAY_SIZE); + } + + + ret = raid_lib->array_create(controller_attr->controller_id, + array_attr, num_of_comp, arraypart_attrs, plugin_err_str); + free(arraypart_attrs); + + if (ret != SUCCESS) + return (ret); + + /* Add array object into device tree so that we can map the handle */ + (void) raid_obj_add_org(raid_tab, array_obj_id, controller_obj_id); + + /* unconfig disk minor nodes if it's hostraid */ + if (controller_attr->capability & RAID_CAP_DISK_TRANS) { + diskid_list = (uint32_t *)calloc(num_of_comp, + sizeof (uint32_t)); + if (diskid_list == NULL) { + return (ERR_NOMEM); + } + + for (i = 0; i < num_of_comp; ++i) { + if (*(disk_list + i) == OBJ_SEPARATOR_BEGIN) { + diskid_list[i] = (uint32_t)OBJ_SEPARATOR_BEGIN; + } else if (*(disk_list + i) == OBJ_SEPARATOR_END) { + diskid_list[i] = (uint32_t)OBJ_SEPARATOR_END; + } else { + ret = obj_get_attr(raid_tab, *(disk_list + i), + (void **)(&disk_attr)); + if (ret != SUCCESS) { + free(diskid_list); + return (ret); + } + diskid_list[i] = disk_attr->disk_id; + } + } + + for (i = 0; i < num_of_comp; ++i) { + if (diskid_list[i] == (uint32_t)OBJ_SEPARATOR_BEGIN || + diskid_list[i] == (uint32_t)OBJ_SEPARATOR_END) { + continue; + } + + if (TARGET(diskid_list[i]) == + ARRAY_TARGET(array_attr->array_id) && + LUN(diskid_list[i]) == + ARRAY_LUN(array_attr->array_id)) + continue; + + ret = raid_dev_config(CFGA_CMD_UNCONFIGURE, + controller_attr->controller_id, diskid_list[i], 0); + if (ret != SUCCESS) { + free(diskid_list); + return (ret); + } + } + free(diskid_list); + } else { + /* for HW raid */ + ret = raid_dev_config(CFGA_CMD_CONFIGURE, + controller_attr->controller_id, array_attr->array_id, 1); + } + + return (ret); +} + +static int +obj_array_delete(raid_obj_tab_t *raid_tab, raid_obj_id_t array_obj_id, + char **plugin_err_str) +{ + raid_obj_id_t controller_obj_id; + controller_attr_t *controller_attr; + array_attr_t *array_attr; + arraypart_attr_t *arraypart_attr; + raid_obj_id_t arraypart_obj_id; + raid_lib_t *raid_lib; + int i = 0, j = 0, ret, fd; + uint32_t *disk_ids = NULL; + + controller_obj_id = obj_get_controller(raid_tab, array_obj_id); + if (controller_obj_id <= OBJ_NONE) + return (controller_obj_id); + + ret = obj_get_attr(raid_tab, controller_obj_id, + (void **)(&controller_attr)); + if (ret < SUCCESS) { + return (ret); + } + ret = obj_get_attr(raid_tab, array_obj_id, (void **)(&array_attr)); + if (ret < SUCCESS) + return (ret); + + raid_lib = raid_obj_get_lib(raid_tab, controller_obj_id); + fd = raid_obj_get_fd(raid_tab, controller_obj_id); + if ((raid_lib == NULL) || (fd == 0)) + return (ERR_DRIVER_CLOSED); + + if ((ret = raid_dev_unmounted(controller_attr->controller_id, + array_attr->array_id)) != SUCCESS) + return (ret); + + /* change minor nodes state for disks */ + if (controller_attr->capability & RAID_CAP_DISK_TRANS) { + arraypart_obj_id = obj_get_comp(raid_tab, array_obj_id, + OBJ_TYPE_ARRAY_PART); + if (arraypart_obj_id < OBJ_NONE) { + return (arraypart_obj_id); + } + + /* + * Check how many disks in volume and malloc space for + * disk_ids; note that the number should be the disk + * number minors 1 since the primary disk should not + * be counted in. + */ + while (arraypart_obj_id = obj_get_sibling(raid_tab, + arraypart_obj_id)) { + if (arraypart_obj_id < OBJ_NONE) + return (arraypart_obj_id); + ++i; + } + disk_ids = calloc(i, sizeof (uint32_t)); + if (disk_ids == NULL) + return (ERR_NOMEM); + + /* Stor all member disk ids into disk_ids */ + arraypart_obj_id = obj_get_comp(raid_tab, array_obj_id, + OBJ_TYPE_ARRAY_PART); + + while (arraypart_obj_id > OBJ_NONE) { + ret = obj_get_attr(raid_tab, arraypart_obj_id, + (void **)(&arraypart_attr)); + if (ret != SUCCESS) { + return (ret); + } + if (TARGET(arraypart_attr->disk_id) == + ARRAY_TARGET(array_attr->array_id) && + LUN(arraypart_attr->disk_id) == + ARRAY_LUN(array_attr->array_id)) { + arraypart_obj_id = obj_get_sibling(raid_tab, + arraypart_obj_id); + continue; + } + + disk_ids[j] = arraypart_attr->disk_id; + ++j; + arraypart_obj_id = obj_get_sibling(raid_tab, + arraypart_obj_id); + } + } else { + ret = raid_dev_config(CFGA_CMD_UNCONFIGURE, + controller_attr->controller_id, array_attr->array_id, 1); + if (ret != SUCCESS) + return (ret); + } + + ret = raid_lib->array_delete(controller_attr->controller_id, + array_attr->array_id, plugin_err_str); + if (ret < SUCCESS) { + if (disk_ids) + free(disk_ids); + return (ret); + } + + if (controller_attr->capability & RAID_CAP_DISK_TRANS) { + for (i = 0; i < j; ++i) + ret = raid_dev_config(CFGA_CMD_CONFIGURE, + controller_attr->controller_id, + disk_ids[i], 0); + if (ret < SUCCESS) { + free(disk_ids); + return (ret); + } + } + + if (disk_ids) + free(disk_ids); + return (ret); +} + +static int +obj_hsp_bind(raid_obj_tab_t *raid_tab, int num, raid_obj_id_t *obj_ids, + char **plugin_err_str) +{ + raid_obj_id_t obj_id, controller_obj_id = OBJ_NONE; + raid_obj_id_t array_obj_id, disk_obj_id; + hsp_relation_t *hsp_relation; + controller_attr_t *controller_attr; + array_attr_t *array_attr; + arraypart_attr_t *arraypart_attr; + disk_attr_t *disk_attr; + diskseg_attr_t *diskseg_attr; + hsp_attr_t *hsp_attr; + raid_lib_t *raid_lib; + int ret, fd, i, j = 0; + + hsp_relation = malloc(sizeof (hsp_relation_t) * num); + if (hsp_relation == NULL) + return (ERR_NOMEM); + + for (i = 0; i < num; ++i) { + array_obj_id = *(obj_ids + i * 2); + disk_obj_id = *(obj_ids + i * 2 + 1); + + if (raid_obj_get_type(raid_tab, disk_obj_id) != OBJ_TYPE_DISK || + (array_obj_id != OBJ_ATTR_NONE && + raid_obj_get_type(raid_tab, array_obj_id) != + OBJ_TYPE_ARRAY)) { + free(hsp_relation); + return (ERR_DEVICE_TYPE); + } + + /* Get controller attributes */ + if (controller_obj_id == OBJ_NONE) + controller_obj_id = obj_get_controller(raid_tab, + disk_obj_id); + else if (controller_obj_id != obj_get_controller(raid_tab, + disk_obj_id)) { + free(hsp_relation); + return (ERR_DRIVER_ACROSS); + } + + ret = obj_get_attr(raid_tab, controller_obj_id, + (void **)(&controller_attr)); + + /* Get disk attributes */ + ret = obj_get_attr(raid_tab, disk_obj_id, + (void **)(&disk_attr)); + if (disk_attr->state == DISK_STATE_FAILED) { + free(hsp_relation); + return (ERR_DISK_STATE); + } + + /* If it's not a hsp disk, check if there's occupied space */ + if (obj_get_comp(raid_tab, disk_obj_id, OBJ_TYPE_HSP) == + OBJ_NONE) { + obj_id = obj_get_comp(raid_tab, disk_obj_id, + OBJ_TYPE_DISK_SEG); + while (obj_id != OBJ_NONE) { + ret = obj_get_attr(raid_tab, obj_id, + (void **)(&diskseg_attr)); + if (!(diskseg_attr->state & + DISKSEG_STATE_RESERVED)) { + free(hsp_relation); + return (ERR_DISK_NOT_EMPTY); + } + obj_id = obj_get_sibling(raid_tab, obj_id); + } + } + + if (array_obj_id != OBJ_ATTR_NONE) { + /* If local hsp is supported */ + if (!(controller_attr->capability & RAID_CAP_L_HSP)) { + free(hsp_relation); + return (ERR_OP_ILLEGAL); + } + + if (raid_obj_get_type(raid_tab, array_obj_id) != + OBJ_TYPE_ARRAY) { + free(hsp_relation); + return (ERR_DEVICE_TYPE); + } + + /* Get array attributes */ + ret = obj_get_attr(raid_tab, array_obj_id, + (void **)(&array_attr)); + /* RAID 0 array can not use hsp */ + if (array_attr->raid_level == RAID_LEVEL_0) { + free(hsp_relation); + return (ERR_ARRAY_LEVEL); + } + + /* If It's belong to another controller */ + if (controller_obj_id != obj_get_controller(raid_tab, + array_obj_id)) { + free(hsp_relation); + return (ERR_DRIVER_ACROSS); + } + + /* Get an array part attributes */ + if ((array_attr->raid_level == RAID_LEVEL_10) || + (array_attr->raid_level == RAID_LEVEL_50)) + obj_id = obj_get_comp(raid_tab, array_obj_id, + OBJ_TYPE_ARRAY); + else + obj_id = array_obj_id; + obj_id = obj_get_comp(raid_tab, obj_id, + OBJ_TYPE_ARRAY_PART); + ret = obj_get_attr(raid_tab, obj_id, + (void **)(&arraypart_attr)); + + /* Check if disk space is enough for array */ + if (arraypart_attr->size > disk_attr->capacity) { + free(hsp_relation); + return (ERR_DISK_SPACE); + } + if (controller_attr->capability & RAID_CAP_ARRAY_ALIGN) + if ((arraypart_attr->size + + arraypart_attr->offset) > + disk_attr->capacity) { + free(hsp_relation); + return (ERR_DISK_SPACE); + } + } else if (!(controller_attr->capability & RAID_CAP_G_HSP)) { + /* if global hsp is supported */ + free(hsp_relation); + return (ERR_OP_ILLEGAL); + } + + /* + * If the array is already associated with the + * local hsp, or it's a global hsp, ignore it + */ + obj_id = obj_get_comp(raid_tab, disk_obj_id, OBJ_TYPE_HSP); + if (obj_id > OBJ_NONE) { + if (obj_get_attr(raid_tab, obj_id, + (void **)&hsp_attr) >= SUCCESS) { + if (((hsp_attr->type == HSP_TYPE_GLOBAL) && + (array_obj_id != OBJ_ATTR_NONE)) || + ((hsp_attr->type == HSP_TYPE_LOCAL) && + (array_obj_id == OBJ_ATTR_NONE))) { + free(hsp_relation); + return (ERR_OP_ILLEGAL); + } + } + } + + if (array_obj_id != OBJ_ATTR_NONE) + hsp_relation[j].array_id = array_attr->array_id; + else + hsp_relation[j].array_id = (uint32_t)OBJ_ATTR_NONE; + hsp_relation[j].disk_id = disk_attr->disk_id; + ++ j; + } + + + if (j == 0) + return (SUCCESS); + + raid_lib = raid_obj_get_lib(raid_tab, controller_obj_id); + fd = raid_obj_get_fd(raid_tab, controller_obj_id); + if ((raid_lib == NULL) || (fd == 0)) + return (ERR_DRIVER_CLOSED); + + if (raid_lib->hsp_bind == NULL) { + free(hsp_relation); + return (ERR_OP_NO_IMPL); + } + + ret = raid_lib->hsp_bind(controller_attr->controller_id, + j, hsp_relation, plugin_err_str); + + free(hsp_relation); + return (ret); +} + +static int +obj_hsp_unbind(raid_obj_tab_t *raid_tab, int num, raid_obj_id_t *obj_ids, + char **plugin_err_str) +{ + raid_obj_id_t obj_id, controller_obj_id = OBJ_NONE; + raid_obj_id_t array_obj_id, disk_obj_id; + hsp_relation_t *hsp_relation; + controller_attr_t *controller_attr; + array_attr_t *array_attr; + disk_attr_t *disk_attr; + hsp_attr_t *hsp_attr; + raid_lib_t *raid_lib; + int ret, fd, i, j = 0; + + hsp_relation = malloc(sizeof (hsp_relation_t) * num); + if (hsp_relation == NULL) + return (ERR_NOMEM); + + for (i = 0; i < num; ++i) { + array_obj_id = *(obj_ids + i * 2); + disk_obj_id = *(obj_ids + i * 2 + 1); + + if (raid_obj_get_type(raid_tab, disk_obj_id) != OBJ_TYPE_DISK) { + free(hsp_relation); + return (ERR_DEVICE_TYPE); + } + + /* Get controller attributes */ + if (controller_obj_id == OBJ_NONE) + controller_obj_id = obj_get_controller(raid_tab, + disk_obj_id); + else if (controller_obj_id != obj_get_controller(raid_tab, + disk_obj_id)) { + free(hsp_relation); + return (ERR_DRIVER_ACROSS); + } + + ret = obj_get_attr(raid_tab, controller_obj_id, + (void **)(&controller_attr)); + + /* Get disk attributes */ + ret = obj_get_attr(raid_tab, disk_obj_id, + (void **)(&disk_attr)); + if (disk_attr->state == DISK_STATE_FAILED) { + free(hsp_relation); + return (ERR_DISK_STATE); + } + + /* If it's not a hsp disk */ + obj_id = obj_get_comp(raid_tab, disk_obj_id, OBJ_TYPE_HSP); + if (obj_id == OBJ_NONE) { + free(hsp_relation); + return (ERR_DISK_STATE); + } + ret = obj_get_attr(raid_tab, obj_id, (void **)(&hsp_attr)); + + if (array_obj_id != OBJ_ATTR_NONE) { + if (raid_obj_get_type(raid_tab, array_obj_id) != + OBJ_TYPE_ARRAY) { + free(hsp_relation); + return (ERR_DEVICE_TYPE); + } + + /* Get array attributes */ + ret = obj_get_attr(raid_tab, array_obj_id, + (void **)(&array_attr)); + + /* If It's belong to another controller */ + if (controller_obj_id != obj_get_controller(raid_tab, + array_obj_id)) { + free(hsp_relation); + return (ERR_DRIVER_ACROSS); + } + + /* If want to remove an array from a global hsp */ + if (hsp_attr->type == HSP_TYPE_GLOBAL) { + free(hsp_relation); + return (ERR_OP_ILLEGAL); + } + + do { + (void) obj_get_attr(raid_tab, obj_id, + (void **)(&hsp_attr)); + + if (hsp_attr->associated_id == + array_attr->array_id || + hsp_attr->type == HSP_TYPE_GLOBAL) + break; + + obj_id = obj_get_sibling(raid_tab, obj_id); + } while (obj_id > OBJ_NONE); + } else if (hsp_attr->type != HSP_TYPE_GLOBAL) { + /* if global hsp is supported */ + free(hsp_relation); + return (ERR_OP_ILLEGAL); + } + + /* + * If array is associated with a local hsp, or remove a + * global hsp disk + */ + if ((obj_id && (array_obj_id != OBJ_ATTR_NONE)) || + (array_obj_id == OBJ_ATTR_NONE)) { + if (array_obj_id != OBJ_ATTR_NONE) + hsp_relation[j].array_id = array_attr->array_id; + else + hsp_relation[j].array_id = + (uint32_t)OBJ_ATTR_NONE; + hsp_relation[j].disk_id = disk_attr->disk_id; + ++ j; + } else { + free(hsp_relation); + return (ERR_OP_ILLEGAL); + } + } + + + raid_lib = raid_obj_get_lib(raid_tab, controller_obj_id); + fd = raid_obj_get_fd(raid_tab, controller_obj_id); + if ((raid_lib == NULL) || (fd == 0)) + return (ERR_DRIVER_CLOSED); + + if (raid_lib->hsp_unbind == NULL) { + free(hsp_relation); + return (ERR_OP_NO_IMPL); + } + + ret = raid_lib->hsp_unbind(controller_attr->controller_id, + j, hsp_relation, plugin_err_str); + + free(hsp_relation); + return (ret); +} + +/* + * Object maintennance routines + */ +static int +raid_obj_create_system_obj(raid_obj_tab_t *raid_tab) +{ + raid_obj_t *raid_obj; + int ret; + + raid_obj = calloc(1, sizeof (raid_obj_t)); + if (raid_obj == NULL) + return (ERR_NOMEM); + + raid_obj->obj_id = OBJ_SYSTEM; + raid_obj->obj_type_id = OBJ_TYPE_SYSTEM; + raid_obj->data = NULL; + + ret = raid_obj_tab_insert(raid_tab, raid_obj->obj_id, raid_obj); + if (ret == ERR_DEVICE_DUP) { + free(raid_obj); + return (ERR_DEVICE_UNCLEAN); + } + + return (SUCCESS); +} + +static raid_obj_id_t +raid_obj_id_new(raid_obj_tab_t *raid_tab) +{ + ++ raid_tab->obj_id_cnt; + if (raid_tab->obj_id_cnt <= 0) + return (ERR_DEVICE_OVERFLOW); + + return (raid_tab->obj_id_cnt); +} + +static void * +raid_obj_attr_new(raid_obj_type_id_t obj_type) +{ + void *obj_attr = NULL; + + switch (obj_type) { + case OBJ_TYPE_CONTROLLER: + obj_attr = calloc(1, sizeof (controller_attr_t)); + break; + case OBJ_TYPE_ARRAY: + obj_attr = calloc(1, sizeof (array_attr_t)); + break; + case OBJ_TYPE_DISK: + obj_attr = calloc(1, sizeof (disk_attr_t)); + break; + case OBJ_TYPE_HSP: + obj_attr = calloc(1, sizeof (hsp_attr_t)); + break; + case OBJ_TYPE_ARRAY_PART: + obj_attr = calloc(1, sizeof (arraypart_attr_t)); + break; + case OBJ_TYPE_DISK_SEG: + obj_attr = calloc(1, sizeof (diskseg_attr_t)); + break; + case OBJ_TYPE_TASK: + obj_attr = calloc(1, sizeof (task_attr_t)); + break; + default: + break; + } + + return (obj_attr); +} + +static raid_obj_id_t +raid_obj_create(raid_obj_tab_t *raid_tab, raid_obj_type_id_t obj_type) +{ + raid_obj_t *raid_obj; + int ret; + void *data_ptr; + + raid_obj = calloc(1, sizeof (raid_obj_t)); + if (raid_obj == NULL) + return (ERR_NOMEM); + + raid_obj->obj_id = raid_obj_id_new(raid_tab); + if (raid_obj->obj_id < OBJ_NONE) + return (ERR_DEVICE_OVERFLOW); + + ret = raid_obj_tab_insert(raid_tab, raid_obj->obj_id, raid_obj); + if (ret == ERR_DEVICE_DUP) { + free(raid_obj); + return (ERR_DEVICE_DUP); + } + + data_ptr = raid_obj_attr_new(obj_type); + if (data_ptr == NULL) { + (void) raid_obj_delete(raid_tab, raid_obj->obj_id); + return (ERR_NOMEM); + } + + (void) raid_obj_set_data_ptr(raid_tab, raid_obj->obj_id, data_ptr); + + (void) raid_obj_set_type(raid_tab, raid_obj->obj_id, obj_type); + return (raid_obj->obj_id); +} + +static int +raid_obj_delete(raid_obj_tab_t *raid_tab, raid_obj_id_t raid_obj_id) +{ + raid_obj_t *obj; + + obj = raid_obj_tab_remove(raid_tab, raid_obj_id); + if (obj != NULL) { + free(obj->data); + free(obj); + return (SUCCESS); + } + + return (ERR_DEVICE_NOENT); +} + +static int +raid_obj_add_org(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id, + raid_obj_id_t container_id) +{ + raid_obj_id_t tmp, tmp1; + + tmp = raid_obj_get_comp(raid_tab, container_id); + if (tmp < OBJ_NONE) + return (ERR_DEVICE_NOENT); + + if (tmp == OBJ_NONE) { + (void) raid_obj_set_container(raid_tab, obj_id, container_id); + (void) raid_obj_set_comp(raid_tab, container_id, obj_id); + return (SUCCESS); + } + + while ((tmp1 = raid_obj_get_sibling(raid_tab, tmp)) != OBJ_NONE) + tmp = tmp1; + + if (raid_obj_set_sibling(raid_tab, tmp, obj_id) < SUCCESS) + return (ERR_DEVICE_NOENT); + (void) raid_obj_set_container(raid_tab, obj_id, container_id); + + return (SUCCESS); +} + +static raid_obj_type_id_t +raid_obj_get_type(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id) +{ + raid_obj_t *obj; + + obj = raid_obj_tab_find(raid_tab, obj_id); + if (obj == NULL) + return (ERR_DEVICE_NOENT); + + if ((obj->obj_type_id < OBJ_TYPE_SYSTEM) || + (obj->obj_type_id >= OBJ_TYPE_ALL)) + return (ERR_DEVICE_INVALID); + + return (obj->obj_type_id); +} + +static int +raid_obj_set_type(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id, + raid_obj_type_id_t type) +{ + raid_obj_t *obj; + + obj = raid_obj_tab_find(raid_tab, obj_id); + if (obj == NULL) + return (ERR_DEVICE_NOENT); + + if ((type < OBJ_TYPE_SYSTEM) || (type >= OBJ_TYPE_ALL)) + return (ERR_DEVICE_TYPE); + + obj->obj_type_id = type; + return (SUCCESS); +} + +static raid_obj_status_t +raid_obj_get_status(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id) +{ + raid_obj_t *obj; + + obj = raid_obj_tab_find(raid_tab, obj_id); + if (obj == NULL) + return (ERR_DEVICE_NOENT); + + return (obj->status); +} + +static int +raid_obj_set_status(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id, + raid_obj_status_t status) +{ + raid_obj_t *obj; + + obj = raid_obj_tab_find(raid_tab, obj_id); + if (obj == NULL) + return (ERR_DEVICE_NOENT); + + obj->status = obj->status | status; + + return (SUCCESS); +} + +static int +raid_obj_clear_status(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id, + raid_obj_status_t status) +{ + raid_obj_t *obj; + + obj = raid_obj_tab_find(raid_tab, obj_id); + if (obj == NULL) + return (ERR_DEVICE_NOENT); + + obj->status = obj->status & ~status; + + return (SUCCESS); +} + +static raid_obj_id_t +raid_obj_get_container(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id) +{ + raid_obj_t *obj; + + obj = raid_obj_tab_find(raid_tab, obj_id); + if (obj == NULL) + return (ERR_DEVICE_NOENT); + + return (obj->container); +} + +static int +raid_obj_set_container(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id, + raid_obj_id_t container_id) +{ + raid_obj_t *obj; + + obj = raid_obj_tab_find(raid_tab, obj_id); + if (obj == NULL) + return (ERR_DEVICE_NOENT); + + obj->container = container_id; + return (SUCCESS); +} + +static raid_obj_id_t +raid_obj_get_comp(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id) +{ + raid_obj_t *obj; + + obj = raid_obj_tab_find(raid_tab, obj_id); + if (obj == NULL) + return (ERR_DEVICE_NOENT); + + return (obj->component); +} + +static int +raid_obj_set_comp(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id, + raid_obj_id_t comp) +{ + raid_obj_t *obj; + + obj = raid_obj_tab_find(raid_tab, obj_id); + if (obj == NULL) + return (ERR_DEVICE_NOENT); + + obj->component = comp; + return (SUCCESS); +} + +static raid_obj_id_t +raid_obj_get_sibling(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id) +{ + raid_obj_t *obj; + + obj = raid_obj_tab_find(raid_tab, obj_id); + if (obj == NULL) + return (ERR_DEVICE_NOENT); + + return (obj->sibling); +} + +static int +raid_obj_set_sibling(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id, + raid_obj_id_t sibling) +{ + raid_obj_t *obj; + + obj = raid_obj_tab_find(raid_tab, obj_id); + if (obj == NULL) + return (ERR_DEVICE_NOENT); + + obj->sibling = sibling; + + return (SUCCESS); +} + +static void * +raid_obj_get_data_ptr(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id) +{ + raid_obj_t *obj; + + obj = raid_obj_tab_find(raid_tab, obj_id); + if (obj == NULL) + return (NULL); + + return (obj->data); +} + +static int +raid_obj_set_data_ptr(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id, + void *data) +{ + raid_obj_t *obj; + + obj = raid_obj_tab_find(raid_tab, obj_id); + if (obj == NULL) + return (ERR_DEVICE_NOENT); + + obj->data = data; + + return (SUCCESS); +} + +static raid_obj_handle_t +raid_obj_get_handle(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id) +{ + raid_obj_t *obj; + + obj = raid_obj_tab_find(raid_tab, obj_id); + if (obj == NULL) + return (ERR_DEVICE_NOENT); + + return (obj->handle); +} + +static int +raid_obj_set_handle(raid_obj_tab_t *raid_tab, raid_obj_id_t obj_id, + raid_obj_handle_t handle) +{ + raid_obj_t *obj; + + obj = raid_obj_tab_find(raid_tab, obj_id); + if (obj == NULL) + return (ERR_DEVICE_NOENT); + + obj->handle = handle; + return (SUCCESS); +} +/* + * Object list maintennance routines + */ +static void +raid_list_create(raid_list_t *list, size_t offset) +{ + list->head = NULL; + list->tail = NULL; + list->offset = offset; +} + +static void * +raid_list_head(raid_list_t *list) +{ + return (list->head); +} + +static void * +raid_list_next(raid_list_t *list, void *obj) +{ + raid_list_el_t *el = LIST_OBJ_TO_EL(list, obj); + + return (el->next); +} + +static void +raid_list_insert_tail(raid_list_t *list, void *obj) +{ + raid_list_el_t *el = LIST_OBJ_TO_EL(list, obj), *el1; + + el->prev = list->tail; + list->tail = obj; + + el->next = NULL; + + if (list->head == NULL) + list->head = obj; + + if (el->prev != NULL) { + el1 = LIST_OBJ_TO_EL(list, el->prev); + el1->next = obj; + } +} + +static void +raid_list_remove(raid_list_t *list, void *obj) +{ + raid_list_el_t *el = LIST_OBJ_TO_EL(list, obj), *el1; + + if (list->head == obj) + list->head = el->next; + + if (list->tail == obj) + list->tail = el->prev; + + if (el->next != NULL) { + el1 = LIST_OBJ_TO_EL(list, el->next); + el1->prev = el->prev; + } + + if (el->prev != NULL) { + el1 = LIST_OBJ_TO_EL(list, el->prev); + el1->next = el->next; + } + + el->prev = el->next = NULL; +} + +static void * +raid_list_remove_head(raid_list_t *list) +{ + void *obj = list->head; + + if (obj != NULL) + raid_list_remove(list, obj); + + return (obj); +} + +static void * +raid_list_find(raid_list_t *list, raid_obj_id_t obj_id) +{ + raid_obj_t *obj; + + for (obj = raid_list_head(list); obj != NULL; + obj = raid_list_next(list, obj)) + if (obj->obj_id == obj_id) + break; + + return (obj); +} + +static int +raid_obj_tab_create(raid_obj_tab_t *tab, size_t hash_slots) +{ + unsigned i; + + if (hash_slots == 0) + return (ERR_OP_ILLEGAL); + + tab->slots = hash_slots; + + if ((tab->table = calloc(hash_slots, sizeof (raid_list_t))) == NULL) + return (ERR_NOMEM); + + for (i = 0; i < hash_slots; i++) + raid_list_create(&tab->table[i], offsetof(raid_obj_t, el)); + + return (SUCCESS); +} + +static void +raid_obj_tab_destroy(raid_obj_tab_t *tab) +{ + unsigned i; + + for (i = 0; i < tab->slots; i++) { + struct raid_obj_t *obj; + + while ((obj = raid_list_remove_head(&tab->table[i])) != NULL) + free(obj); + + raid_list_destroy(&tab->table[i]); + } + + if (tab->table) + free(tab->table); + + tab->table = NULL; + tab->slots = 0; + tab->obj_id_cnt = 0; +} + +static int +raid_obj_tab_insert(raid_obj_tab_t *tab, raid_obj_id_t id, void *obj) +{ + raid_list_t *list; + + list = OBJ_TAB_SLOT(tab, id); + + if (raid_list_find(list, id) != NULL) + return (ERR_DEVICE_DUP); + + raid_list_insert_tail(list, obj); + + return (SUCCESS); +} + +static void * +raid_obj_tab_remove(raid_obj_tab_t *tab, raid_obj_id_t id) +{ + raid_list_t *list; + raid_obj_t *obj; + + list = OBJ_TAB_SLOT(tab, id); + + if ((obj = raid_list_find(list, id)) != NULL) + raid_list_remove(list, obj); + + return (obj); +} + +static void * +raid_obj_tab_find(raid_obj_tab_t *tab, raid_obj_id_t id) +{ + raid_list_t *list; + raid_obj_t *obj; + + list = OBJ_TAB_SLOT(tab, id); + obj = raid_list_find(list, id); + + return (obj); +} + +static void +raid_list_destroy(raid_list_t *list) +{ + list->head = NULL; + list->tail = NULL; + list->offset = 0; +} + +/* + * Plug-in maintennance routines + */ +static int +controller_id_to_path(uint32_t controller_id, char *path) +{ + char buf[MAX_PATH_LEN] = {0}, buf1[MAX_PATH_LEN] = {0}, *colon; + + (void) snprintf(buf, MAX_PATH_LEN, "%s/c%d", CFGDIR, controller_id); + if (readlink(buf, buf1, sizeof (buf1)) < 0) + return (ERR_DRIVER_NOT_FOUND); + + if (buf1[0] != '/') + (void) snprintf(buf, sizeof (buf), "%s/", CFGDIR); + else + buf[0] = 0; + (void) strlcat(buf, buf1, MAX_PATH_LEN); + + colon = strrchr(buf, ':'); + if (colon == NULL) + return (ERR_DRIVER_NOT_FOUND); + else + *colon = 0; + + (void) snprintf(path, MAX_PATH_LEN, "%s:devctl", buf); + + if (access(path, F_OK) < 0) + return (ERR_DRIVER_NOT_FOUND); + + return (SUCCESS); +} + +static char * +controller_id_to_driver_name(uint32_t controller_id) +{ + char buf[MAX_PATH_LEN]; + di_node_t di_node; + char *name, *tmp; + int ret; + + ret = controller_id_to_path(controller_id, buf); + if (ret < SUCCESS) + return (NULL); + + tmp = strrchr(buf, ':'); + if (tmp != NULL) + *tmp = 0; + + tmp = strstr(buf, "pci"); + if (tmp == NULL) + return (NULL); + + di_node = di_init(tmp, DINFOPROP); + if (di_node == DI_NODE_NIL) + return (NULL); + + name = di_driver_name(di_node); + + return (name); +} + +static void +raid_plugin_init() +{ + raid_lib_t *raid_lib = raid_lib_sys; + + while (raid_lib) { + raid_lib_sys = raid_lib->next; + (void) dlclose(raid_lib->lib_handle); + free(raid_lib); + raid_lib = raid_lib_sys; + } +} + +static raid_lib_t * +raid_plugin_load(char *driver_name) +{ + char buf[MAX_PATH_LEN] = {0}; + raid_lib_t *supplib; + void *sym; + + supplib = calloc(1, sizeof (raid_lib_t)); + if (supplib == NULL) + return (NULL); + + (void) snprintf(buf, MAX_PATH_LEN, "%s/%s.so.1", + SUPP_PLUGIN_DIR, driver_name); + + supplib->lib_handle = dlopen(buf, RTLD_LAZY); + if (supplib->lib_handle == NULL) { + free(supplib); + return (NULL); + } + + supplib->name = driver_name; + + if ((sym = dlsym(supplib->lib_handle, "rdcfg_version")) == NULL) + supplib->version = RDCFG_PLUGIN_V1; + else { + supplib->version = *((uint32_t *)sym); + if (supplib->version != RDCFG_PLUGIN_V1) { + (void) dlclose(supplib->lib_handle); + free(supplib); + return (NULL); + } + } + + if ((sym = dlsym(supplib->lib_handle, "rdcfg_open_controller")) == + NULL) { + (void) dlclose(supplib->lib_handle); + free(supplib); + return (NULL); + } else + supplib->open_controller = (int(*)(uint32_t, char **))sym; + + if ((sym = dlsym(supplib->lib_handle, "rdcfg_close_controller")) == + NULL) { + (void) dlclose(supplib->lib_handle); + free(supplib); + return (NULL); + } else + supplib->close_controller = (int (*)(uint32_t, char **))sym; + + if ((sym = dlsym(supplib->lib_handle, "rdcfg_compnum")) == NULL) { + (void) dlclose(supplib->lib_handle); + free(supplib); + return (NULL); + } else + supplib->compnum = (int (*)(uint32_t, uint32_t, + raid_obj_type_id_t, raid_obj_type_id_t))sym; + + if ((sym = dlsym(supplib->lib_handle, "rdcfg_complist")) == NULL) { + (void) dlclose(supplib->lib_handle); + free(supplib); + return (NULL); + } else + supplib->complist = (int (*)(uint32_t, uint32_t, + raid_obj_type_id_t, raid_obj_type_id_t, int, void *))sym; + + if ((sym = dlsym(supplib->lib_handle, "rdcfg_get_attr")) == NULL) { + (void) dlclose(supplib->lib_handle); + free(supplib); + return (NULL); + } else + supplib->get_attr = (int (*)(uint32_t, uint32_t, uint32_t, + raid_obj_type_id_t, void*))sym; + + if ((sym = dlsym(supplib->lib_handle, "rdcfg_array_create")) == NULL) { + (void) dlclose(supplib->lib_handle); + free(supplib); + return (NULL); + } else + supplib->array_create = (int (*)(uint32_t, array_attr_t *, int, + arraypart_attr_t *, char **))sym; + + if ((sym = dlsym(supplib->lib_handle, "rdcfg_array_delete")) == NULL) { + (void) dlclose(supplib->lib_handle); + free(supplib); + return (NULL); + } else + supplib->array_delete = + (int (*)(uint32_t, uint32_t, char **))sym; + + supplib->hsp_bind = (int (*)(uint32_t, uint32_t, hsp_relation_t *, + char **))dlsym(supplib->lib_handle, "rdcfg_hsp_bind"); + supplib->hsp_unbind = (int (*)(uint32_t, uint32_t, hsp_relation_t *, + char **))dlsym(supplib->lib_handle, "rdcfg_hsp_unbind"); + supplib->set_attr = (int (*)(uint32_t, uint32_t, uint32_t, uint32_t *, + char **))dlsym(supplib->lib_handle, "rdcfg_set_attr"); + supplib->flash_fw = (int (*)(uint32_t, char *, uint32_t, char **)) + dlsym(supplib->lib_handle, "rdcfg_flash_fw"); + + supplib->next = raid_lib_sys; + raid_lib_sys = supplib; + return (supplib); +} + +static raid_lib_t * +raid_find_lib(raid_obj_tab_t *raid_tab, raid_obj_id_t controller_obj_id) +{ + controller_attr_t *controller_attr; + raid_lib_t *raid_lib; + char *driver_name; + raid_obj_handle_t handle; + + /* Check if it's mapped to handle structure */ + handle = raid_obj_to_handle(raid_tab, controller_obj_id); + if (raid_handle_sys.handles[handle].raid_lib != NULL) + return (raid_handle_sys.handles[handle].raid_lib); + + (void) obj_get_attr(raid_tab, controller_obj_id, + (void **)(&controller_attr)); + + /* Check if the plugin module is already loaded */ + driver_name = controller_id_to_driver_name( + controller_attr->controller_id); + if (driver_name == NULL) + return (NULL); + + raid_lib = raid_lib_sys; + while (raid_lib != NULL) { + if (raid_lib->name != NULL && + strcmp(driver_name, raid_lib->name) == 0) + return (raid_lib); + + raid_lib = raid_lib->next; + } + + /* Loading the plugin module */ + raid_lib = raid_plugin_load(driver_name); + + return (raid_lib); +} diff --git a/usr/src/lib/libraidcfg/i386/Makefile b/usr/src/lib/libraidcfg/i386/Makefile new file mode 100644 index 0000000000..f8ddafac61 --- /dev/null +++ b/usr/src/lib/libraidcfg/i386/Makefile @@ -0,0 +1,31 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# 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. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#pragma ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT) diff --git a/usr/src/lib/libraidcfg/sparc/Makefile b/usr/src/lib/libraidcfg/sparc/Makefile new file mode 100644 index 0000000000..f8ddafac61 --- /dev/null +++ b/usr/src/lib/libraidcfg/sparc/Makefile @@ -0,0 +1,31 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# 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. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#pragma ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT) diff --git a/usr/src/lib/libraidcfg/sparcv9/Makefile b/usr/src/lib/libraidcfg/sparcv9/Makefile new file mode 100644 index 0000000000..22ff31377a --- /dev/null +++ b/usr/src/lib/libraidcfg/sparcv9/Makefile @@ -0,0 +1,32 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# 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. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#pragma ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com +include ../../Makefile.lib.64 + +install: all $(ROOTLIBS64) $(ROOTLINKS64) diff --git a/usr/src/lib/libsecdb/exec_attr.txt b/usr/src/lib/libsecdb/exec_attr.txt index e568985fcb..1f410856a0 100644 --- a/usr/src/lib/libsecdb/exec_attr.txt +++ b/usr/src/lib/libsecdb/exec_attr.txt @@ -95,6 +95,7 @@ File System Management:suser:cmd:::/usr/sbin/mountall:uid=0 File System Management:solaris:cmd:::/usr/sbin/quotacheck:uid=0;gid=sys File System Management:solaris:cmd:::/usr/sbin/quotaoff:uid=0;gid=sys File System Management:solaris:cmd:::/usr/sbin/quotaon:uid=0;gid=sys +File System Management:solaris:cmd:::/usr/sbin/raidctl:privs=sys_config,sys_devices;euid=0 File System Management:suser:cmd:::/usr/sbin/ramdiskadm:euid=0 File System Management:suser:cmd:::/usr/sbin/share:uid=0;gid=root File System Management:suser:cmd:::/usr/sbin/sharemgr:uid=0;gid=root diff --git a/usr/src/lib/raidcfg_plugins/Makefile b/usr/src/lib/raidcfg_plugins/Makefile new file mode 100644 index 0000000000..ec46aed318 --- /dev/null +++ b/usr/src/lib/raidcfg_plugins/Makefile @@ -0,0 +1,52 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# 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. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# lib/raidcfg_plugins/Makefile +# + +include $(SRC)/Makefile.master + +CLOSED_PLUGIN = $(CLOSED)/lib/raidcfg_plugins/ + +$(CLOSED_BUILD)COMMON_SUBDIRS += $(CLOSED_PLUGIN)/mpt + +SUBDIRS= $(COMMON_SUBDIRS) $($(MACH)_SUBDIRS) + +all:= TARGET= all +install:= TARGET= install +clean:= TARGET= clean +clobber:= TARGET= clobber +lint:= TARGET= lint +_msg:= TARGET= _msg + +.KEEP_STATE: + +all clean clobber lint install _msg: $(SUBDIRS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: diff --git a/usr/src/pkgdefs/SUNWcsl/prototype_com b/usr/src/pkgdefs/SUNWcsl/prototype_com index 5e557a0004..4a8c324b85 100644 --- a/usr/src/pkgdefs/SUNWcsl/prototype_com +++ b/usr/src/pkgdefs/SUNWcsl/prototype_com @@ -21,7 +21,7 @@ # # -# Copyright 2006 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" @@ -221,6 +221,7 @@ s none usr/lib/librt.so.1=../../lib/librt.so.1 s none usr/lib/librt.so=../../lib/librt.so.1 s none usr/lib/libposix4.so=../../lib/librt.so.1 s none usr/lib/libposix4.so.1=../../lib/librt.so.1 +f none usr/lib/libraidcfg.so.1 755 root bin s none usr/lib/librtld.so.1=../../lib/librtld.so.1 s none usr/lib/librtld_db.so=../../lib/librtld_db.so.1 s none usr/lib/librtld_db.so.1=../../lib/librtld_db.so.1 @@ -289,6 +290,8 @@ s none usr/lib/nss_nis.so.1=../../lib/nss_nis.so.1 s none usr/lib/nss_nisplus.so.1=../../lib/nss_nisplus.so.1 s none usr/lib/nss_user.so.1=../../lib/nss_user.so.1 f none usr/lib/passwdutil.so.1 755 root bin +d none usr/lib/raidcfg 755 root bin +f none usr/lib/raidcfg/mpt.so.1 755 root bin s none usr/lib/straddr.so=./straddr.so.2 f none usr/lib/straddr.so.2 755 root bin d none usr/lib/security 755 root bin diff --git a/usr/src/pkgdefs/SUNWcsl/prototype_i386 b/usr/src/pkgdefs/SUNWcsl/prototype_i386 index 4c65a8fd58..3e59533bc2 100644 --- a/usr/src/pkgdefs/SUNWcsl/prototype_i386 +++ b/usr/src/pkgdefs/SUNWcsl/prototype_i386 @@ -20,7 +20,7 @@ # # -# Copyright 2006 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" @@ -86,6 +86,8 @@ d none usr/lib/lwp/amd64 755 root bin s none usr/lib/lwp/64=amd64 s none usr/lib/lwp/amd64/libthread.so.1=../../amd64/libthread.so.1 s none usr/lib/lwp/amd64/libthread_db.so.1=../../amd64/libthread_db.so.1 +d none usr/lib/raidcfg/amd64 755 root bin +f none usr/lib/raidcfg/amd64/mpt.so.1 755 root bin d none usr/lib/security/amd64 755 root bin s none usr/lib/security/64=amd64 f none usr/lib/security/amd64/crypt_bsdmd5.so.1 755 root bin @@ -196,6 +198,7 @@ f none usr/lib/amd64/libproject.so.1 755 root bin s none usr/lib/amd64/libproject.so=libproject.so.1 f none usr/lib/amd64/libpkcs11.so.1 755 root bin s none usr/lib/amd64/libpkcs11.so=libpkcs11.so.1 +f none usr/lib/amd64/libraidcfg.so.1 755 root bin f none usr/lib/amd64/lib300.so.1 755 root bin s none usr/lib/amd64/lib300.so=./lib300.so.1 f none usr/lib/amd64/lib300s.so.1 755 root bin diff --git a/usr/src/pkgdefs/SUNWcsl/prototype_sparc b/usr/src/pkgdefs/SUNWcsl/prototype_sparc index 1bcdad558d..3b103442f9 100644 --- a/usr/src/pkgdefs/SUNWcsl/prototype_sparc +++ b/usr/src/pkgdefs/SUNWcsl/prototype_sparc @@ -21,7 +21,7 @@ # # -# Copyright 2006 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" @@ -79,6 +79,8 @@ d none usr/lib/lwp/sparcv9 755 root bin s none usr/lib/lwp/64=sparcv9 s none usr/lib/lwp/sparcv9/libthread.so.1=../../sparcv9/libthread.so.1 s none usr/lib/lwp/sparcv9/libthread_db.so.1=../../sparcv9/libthread_db.so.1 +d none usr/lib/raidcfg/sparcv9 755 root bin +f none usr/lib/raidcfg/sparcv9/mpt.so.1 755 root bin d none usr/lib/security/sparcv9 755 root bin s none usr/lib/security/64=sparcv9 f none usr/lib/security/sparcv9/crypt_bsdmd5.so.1 755 root bin @@ -189,6 +191,7 @@ f none usr/lib/sparcv9/libproject.so.1 755 root bin s none usr/lib/sparcv9/libproject.so=libproject.so.1 f none usr/lib/sparcv9/libpkcs11.so.1 755 root bin s none usr/lib/sparcv9/libpkcs11.so=libpkcs11.so.1 +f none usr/lib/sparcv9/libraidcfg.so.1 755 root bin f none usr/lib/sparcv9/lib300.so.1 755 root bin s none usr/lib/sparcv9/lib300.so=./lib300.so.1 f none usr/lib/sparcv9/lib300s.so.1 755 root bin diff --git a/usr/src/pkgdefs/etc/exception_list_i386 b/usr/src/pkgdefs/etc/exception_list_i386 index c20e9716df..724028cff5 100644 --- a/usr/src/pkgdefs/etc/exception_list_i386 +++ b/usr/src/pkgdefs/etc/exception_list_i386 @@ -423,6 +423,16 @@ usr/lib/llib-ldisasm i386 usr/lib/llib-ldisasm.ln i386 usr/lib/amd64/llib-ldisasm.ln i386 # +# Private interfaces for libraidcfg +# +usr/include/raidcfg.h i386 +usr/include/raidcfg_spi.h i386 +usr/lib/libraidcfg.so i386 +usr/lib/llib-lraidcfg i386 +usr/lib/llib-lraidcfg.ln i386 +usr/lib/amd64/libraidcfg.so i386 +usr/lib/amd64/llib-lraidcfg.ln i386 +# # This file is used for private communication between mdb, drv/kmdb, and # misc/kmdb. The interfaces described herein are not intended for customer # use, and are thus excluded from packaging. diff --git a/usr/src/pkgdefs/etc/exception_list_sparc b/usr/src/pkgdefs/etc/exception_list_sparc index d8930e923a..a280a97752 100644 --- a/usr/src/pkgdefs/etc/exception_list_sparc +++ b/usr/src/pkgdefs/etc/exception_list_sparc @@ -427,6 +427,16 @@ usr/lib/llib-ldisasm sparc usr/lib/llib-ldisasm.ln sparc usr/lib/sparcv9/llib-ldisasm.ln sparc # +# Private interfaces for libraidcfg +# +usr/include/raidcfg.h sparc +usr/include/raidcfg_spi.h sparc +usr/lib/libraidcfg.so sparc +usr/lib/llib-lraidcfg sparc +usr/lib/llib-lraidcfg.ln sparc +usr/lib/sparcv9/llib-lraidcfg.ln sparc +usr/lib/sparcv9/libraidcfg.so sparc +# # This file is used for private communication between mdb, drv/kmdb, and # misc/kmdb. The interfaces described herein are not intended for customer # use, and are thus excluded from packaging. |