17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 233a4e43d3Ssafa * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate #include <ctype.h> 307c478bd9Sstevel@tonic-gate #include <dirent.h> 317c478bd9Sstevel@tonic-gate #include <errno.h> 327c478bd9Sstevel@tonic-gate #include <fcntl.h> 337c478bd9Sstevel@tonic-gate #include <langinfo.h> 347c478bd9Sstevel@tonic-gate #include <libintl.h> 357c478bd9Sstevel@tonic-gate #include <limits.h> 367c478bd9Sstevel@tonic-gate #include <locale.h> 377c478bd9Sstevel@tonic-gate #include <stdarg.h> 387c478bd9Sstevel@tonic-gate #include <stdio.h> 397c478bd9Sstevel@tonic-gate #include <stdlib.h> 407c478bd9Sstevel@tonic-gate #include <string.h> 417c478bd9Sstevel@tonic-gate #include <strings.h> 427c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 437c478bd9Sstevel@tonic-gate #include <sys/mpt/mpi.h> 447c478bd9Sstevel@tonic-gate #include <sys/mpt/mpi_ioc.h> 457c478bd9Sstevel@tonic-gate #include <sys/stat.h> 467c478bd9Sstevel@tonic-gate #include <sys/types.h> 477c478bd9Sstevel@tonic-gate #include <sys/pci.h> 487c478bd9Sstevel@tonic-gate #include <unistd.h> 497c478bd9Sstevel@tonic-gate #include <sys/mnttab.h> 507c478bd9Sstevel@tonic-gate #include <sys/dkio.h> 517c478bd9Sstevel@tonic-gate #include <config_admin.h> 527c478bd9Sstevel@tonic-gate #include <sys/param.h> 537c478bd9Sstevel@tonic-gate #include <sys/raidioctl.h> 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate /* 567c478bd9Sstevel@tonic-gate * list of controllers to list 577c478bd9Sstevel@tonic-gate * setup like this: 587c478bd9Sstevel@tonic-gate * [ctrl_num] [status] 597c478bd9Sstevel@tonic-gate * 607c478bd9Sstevel@tonic-gate * where status is: 617c478bd9Sstevel@tonic-gate * RAID Found, 627c478bd9Sstevel@tonic-gate * No RAID Found 637c478bd9Sstevel@tonic-gate * RAID not supported on this controller 647c478bd9Sstevel@tonic-gate * Invalid Controller 657c478bd9Sstevel@tonic-gate */ 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate typedef enum { 687c478bd9Sstevel@tonic-gate RAID_FOUND = 0x0, 697c478bd9Sstevel@tonic-gate RAID_NOT_FOUND, 707c478bd9Sstevel@tonic-gate RAID_NOT_SUPPORTED, 717c478bd9Sstevel@tonic-gate RAID_INVALID_CTRL, 727c478bd9Sstevel@tonic-gate RAID_DONT_USE 737c478bd9Sstevel@tonic-gate } raidctl_errno_t; 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate /* For no-mixup indexing of info_ctrl */ 767c478bd9Sstevel@tonic-gate #define INFO_CTRL 0 777c478bd9Sstevel@tonic-gate #define INFO_STATUS 1 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate static int **info_ctrl = NULL; 807c478bd9Sstevel@tonic-gate /* Length of conrollers list */ 817c478bd9Sstevel@tonic-gate static int ctrl_nums = 0; 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate 847c478bd9Sstevel@tonic-gate #define DEVDIR "/dev/rdsk" 857c478bd9Sstevel@tonic-gate 867c478bd9Sstevel@tonic-gate #define DO_HW_RAID_NOP -1 877c478bd9Sstevel@tonic-gate #define DO_HW_RAID_INFO 0 887c478bd9Sstevel@tonic-gate #define DO_HW_RAID_CREATE 1 897c478bd9Sstevel@tonic-gate #define DO_HW_RAID_DELETE 2 907c478bd9Sstevel@tonic-gate #define DO_HW_RAID_FLASH 3 917c478bd9Sstevel@tonic-gate 92*6fec3791Sjesseb /* values to use for raid level in raidctl */ 93*6fec3791Sjesseb #define RAID_STRIPE 0 94*6fec3791Sjesseb #define RAID_MIRROR 1 95*6fec3791Sjesseb 967c478bd9Sstevel@tonic-gate /* 977c478bd9Sstevel@tonic-gate * Error return codes 987c478bd9Sstevel@tonic-gate */ 997c478bd9Sstevel@tonic-gate #define SUCCESS 0 1007c478bd9Sstevel@tonic-gate #define INVALID_ARG 1 1017c478bd9Sstevel@tonic-gate #define FAILURE 2 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate /* 1047c478bd9Sstevel@tonic-gate * FW Update Stuff 1057c478bd9Sstevel@tonic-gate */ 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate /* signature and initial offset for PCI expansion rom images */ 1087c478bd9Sstevel@tonic-gate #define PCIROM_SIG 0xaa55 /* offset 0h, length 2 bytes */ 1097c478bd9Sstevel@tonic-gate #define PCIR_OFF 0x18 /* Pointer to PCI Data Structure */ 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate /* offsets in PCI data structure header */ 1127c478bd9Sstevel@tonic-gate #define PCIR_DEVID 0x6 /* PCI device id */ 1137c478bd9Sstevel@tonic-gate #define PCIR_CODETYPE 0x14 /* type of code (intel/fcode) */ 1147c478bd9Sstevel@tonic-gate #define PCIR_INDICATOR 0x15 /* "last image" indicator */ 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate /* flags for image types */ 1177c478bd9Sstevel@tonic-gate #define BIOS_IMAGE 0x1 1187c478bd9Sstevel@tonic-gate #define FCODE_IMAGE 0x2 1197c478bd9Sstevel@tonic-gate #define UNKNOWN_IMAGE 0x3 1207c478bd9Sstevel@tonic-gate #define LAST_IMAGE 0x80 1217c478bd9Sstevel@tonic-gate #define NOT_LAST_IMAGE 0 1227c478bd9Sstevel@tonic-gate #define PCI_IMAGE_UNIT_SIZE 512 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate /* ID's and offsets for MPT Firmware images */ 1257c478bd9Sstevel@tonic-gate #define FW_ROM_ID 0x5aea /* bytes 4 & 5 of file */ 1267c478bd9Sstevel@tonic-gate #define FW_ROM_OFFSET_CHIP_TYPE 0x22 /* (U16) */ 1277c478bd9Sstevel@tonic-gate #define FW_ROM_OFFSET_VERSION 0x24 /* (U16) */ 1287c478bd9Sstevel@tonic-gate #define FW_ROM_OFFSET_VERSION_NAME 0x44 /* (32 U8) */ 1297c478bd9Sstevel@tonic-gate 130*6fec3791Sjesseb /* ID's for supported chips */ 131*6fec3791Sjesseb #define LSI_1030 0x30 132*6fec3791Sjesseb #define LSI_1064 0x50 133*6fec3791Sjesseb #define LSI_1064E 0x56 134*6fec3791Sjesseb #define LSI_1068E 0x58 135*6fec3791Sjesseb 1367c478bd9Sstevel@tonic-gate /* Key to search for when looking for fcode version */ 1377c478bd9Sstevel@tonic-gate #define FCODE_VERS_KEY1 0x12 1387c478bd9Sstevel@tonic-gate #define FCODE_VERS_KEY2 0x7 1397c478bd9Sstevel@tonic-gate #define BIOS_STR "LSI1030 SCSI Host Adapter BIOS Driver: " 1407c478bd9Sstevel@tonic-gate 1417c478bd9Sstevel@tonic-gate /* get a word from a buffer (works with non-word aligned offsets) */ 1427c478bd9Sstevel@tonic-gate #define gw(x) (((x)[0]) + (((x)[1]) << 8)) 1437c478bd9Sstevel@tonic-gate 144*6fec3791Sjesseb /* Number of disks currently supported, per RAID volume */ 145*6fec3791Sjesseb #define N_DISKS 8 146*6fec3791Sjesseb 147*6fec3791Sjesseb /* Maximum number of RAID volumes currently supported per HBA */ 148*6fec3791Sjesseb #define N_RAIDVOLS 2 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate /* 1517c478bd9Sstevel@tonic-gate * Function and strings to properly localize our prompt. 1527c478bd9Sstevel@tonic-gate * So for example in german it would ask (ja/nein) or (yes/no) in 1537c478bd9Sstevel@tonic-gate * english. 1547c478bd9Sstevel@tonic-gate */ 155*6fec3791Sjesseb static int yes(void); 1567c478bd9Sstevel@tonic-gate static char yeschr[SCHAR_MAX + 2]; 1577c478bd9Sstevel@tonic-gate static char nochr[SCHAR_MAX +2]; 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate typedef struct raidlist { 160*6fec3791Sjesseb raid_config_t raid_config[N_RAIDVOLS]; 1617c478bd9Sstevel@tonic-gate int controller; 1627c478bd9Sstevel@tonic-gate char devctl[MAXPATHLEN]; 1637c478bd9Sstevel@tonic-gate struct raidlist *next; 1647c478bd9Sstevel@tonic-gate } raidlist_t; 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate static raidlist_t *raids; 1677c478bd9Sstevel@tonic-gate 168*6fec3791Sjesseb /* 169*6fec3791Sjesseb * usage: raidctl 170*6fec3791Sjesseb * usage: raidctl [-f] -c primary secondary 171*6fec3791Sjesseb * usage: raidctl [-f] -c -r 1 primary secondary 172*6fec3791Sjesseb * usage: raidctl [-f] -c -r 0 disk1 disk2 [disk3] ... 173*6fec3791Sjesseb * usage: raidctl [-f] -d volume 174*6fec3791Sjesseb * usage: raidctl [-f] -F image_file controller 175*6fec3791Sjesseb * usage: raidctl -l [controller...] 176*6fec3791Sjesseb * example: 177*6fec3791Sjesseb * raidctl -c c1t1d0 c1t2d0 178*6fec3791Sjesseb * raidctl -c -r 0 c1t1d0 c1t2d0 c1t3d0 c1t4d0 179*6fec3791Sjesseb * raidctl -d c1t1d0 180*6fec3791Sjesseb * raidctl -F image 1 181*6fec3791Sjesseb */ 1827c478bd9Sstevel@tonic-gate static void 1837c478bd9Sstevel@tonic-gate usage(char *prog_name) 1847c478bd9Sstevel@tonic-gate { 1857c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("usage: %s\n"), prog_name); 1867c478bd9Sstevel@tonic-gate 187*6fec3791Sjesseb (void) fprintf(stderr, gettext("usage: %s [-f] -c primary secondary\n"), 1887c478bd9Sstevel@tonic-gate prog_name); 189*6fec3791Sjesseb 190*6fec3791Sjesseb (void) fprintf(stderr, gettext("usage: %s [-f] -c -r 1 primary " 191*6fec3791Sjesseb "secondary\n"), prog_name); 192*6fec3791Sjesseb 193*6fec3791Sjesseb (void) fprintf(stderr, gettext("usage: %s [-f] -c -r 0 disk1 disk2 " 194*6fec3791Sjesseb "[disk3] ...\n"), prog_name); 195*6fec3791Sjesseb 196*6fec3791Sjesseb (void) fprintf(stderr, gettext("usage: %s [-f] -d volume\n"), 197*6fec3791Sjesseb prog_name); 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 2007c478bd9Sstevel@tonic-gate gettext("usage: %s [-f] -F image_file controller \n"), 2017c478bd9Sstevel@tonic-gate prog_name); 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("usage: %s -l [controller...]\n"), 2047c478bd9Sstevel@tonic-gate prog_name); 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("example:\n")); 2077c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s -c c1t1d0 c1t2d0\n", prog_name); 208*6fec3791Sjesseb (void) fprintf(stderr, "%s -c -r 0 c1t1d0 c1t2d0 " 209*6fec3791Sjesseb "c1t3d0 c1t4d0\n", prog_name); 2107c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s -d c1t1d0\n", prog_name); 2117c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s -F image 1\n", prog_name); 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate exit(1); 2147c478bd9Sstevel@tonic-gate } 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate /* Make errno message more "user friendly" */ 2177c478bd9Sstevel@tonic-gate static void 2187c478bd9Sstevel@tonic-gate raidctl_error(char *str) 2197c478bd9Sstevel@tonic-gate { 2207c478bd9Sstevel@tonic-gate switch (errno) { 2213a4e43d3Ssafa case EINVAL: 2223a4e43d3Ssafa (void) fprintf(stderr, gettext("Error: " 2233a4e43d3Ssafa "invalid argument would be returned\n")); 2243a4e43d3Ssafa break; 2257c478bd9Sstevel@tonic-gate case EIO: 2267c478bd9Sstevel@tonic-gate case EFAULT: 2277c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 2287c478bd9Sstevel@tonic-gate gettext("Error: Device inaccessible.\n")); 2297c478bd9Sstevel@tonic-gate break; 2307c478bd9Sstevel@tonic-gate case ENOTTY: 2317c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("Error: " 2327c478bd9Sstevel@tonic-gate "Device does not support requested action.\n")); 2337c478bd9Sstevel@tonic-gate break; 2347c478bd9Sstevel@tonic-gate default: 2357c478bd9Sstevel@tonic-gate perror(str); 2367c478bd9Sstevel@tonic-gate } 2377c478bd9Sstevel@tonic-gate } 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate static int 2407c478bd9Sstevel@tonic-gate get_link_path(const char *thing, char *buf) 2417c478bd9Sstevel@tonic-gate { 2427c478bd9Sstevel@tonic-gate if (readlink(thing, buf, MAXPATHLEN) < 0) 2437c478bd9Sstevel@tonic-gate return (1); 2447c478bd9Sstevel@tonic-gate return (0); 2457c478bd9Sstevel@tonic-gate } 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gate static int 2487c478bd9Sstevel@tonic-gate get_ctrl_devctl(char *ctrl, char *b) 2497c478bd9Sstevel@tonic-gate { 2507c478bd9Sstevel@tonic-gate char devctl_buf[MAXPATHLEN]; 2517c478bd9Sstevel@tonic-gate char *colon; 2527c478bd9Sstevel@tonic-gate 2537c478bd9Sstevel@tonic-gate (void) strlcpy(devctl_buf, ctrl, MAXPATHLEN); 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate colon = strrchr(devctl_buf, ':'); 2567c478bd9Sstevel@tonic-gate if (colon == NULL) 2577c478bd9Sstevel@tonic-gate return (1); 2587c478bd9Sstevel@tonic-gate 2597c478bd9Sstevel@tonic-gate *colon = 0; 2607c478bd9Sstevel@tonic-gate (void) snprintf(devctl_buf, MAXPATHLEN, "%s:devctl", devctl_buf); 2617c478bd9Sstevel@tonic-gate (void) strlcpy(b, devctl_buf, MAXPATHLEN); 2627c478bd9Sstevel@tonic-gate return (0); 2637c478bd9Sstevel@tonic-gate } 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate static int 2667c478bd9Sstevel@tonic-gate get_devctl(char *disk, char *b) 2677c478bd9Sstevel@tonic-gate { 2687c478bd9Sstevel@tonic-gate char buf1[MAXPATHLEN] = {0}; 2697c478bd9Sstevel@tonic-gate char devctl_buf[MAXPATHLEN]; 2707c478bd9Sstevel@tonic-gate char *slash; 2717c478bd9Sstevel@tonic-gate char devname[32]; 2727c478bd9Sstevel@tonic-gate 2737c478bd9Sstevel@tonic-gate if (get_link_path(disk, buf1)) 2747c478bd9Sstevel@tonic-gate return (1); 2757c478bd9Sstevel@tonic-gate 2767c478bd9Sstevel@tonic-gate (void) strlcpy(devctl_buf, buf1, MAXPATHLEN); 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate slash = strrchr(devctl_buf, '/'); 2797c478bd9Sstevel@tonic-gate if (slash == NULL) 2807c478bd9Sstevel@tonic-gate return (1); 2817c478bd9Sstevel@tonic-gate 2827c478bd9Sstevel@tonic-gate *slash = 0; 2837c478bd9Sstevel@tonic-gate slash = strrchr(devctl_buf, '/'); 2847c478bd9Sstevel@tonic-gate (void) strlcpy(devname, slash, 32); 2857c478bd9Sstevel@tonic-gate *slash = 0; 2867c478bd9Sstevel@tonic-gate 2877c478bd9Sstevel@tonic-gate (void) snprintf(devctl_buf, MAXPATHLEN, "%s%s:devctl", 2887c478bd9Sstevel@tonic-gate devctl_buf, devname); 289*6fec3791Sjesseb 2907c478bd9Sstevel@tonic-gate (void) strlcpy(b, devctl_buf, MAXPATHLEN); 291*6fec3791Sjesseb 2927c478bd9Sstevel@tonic-gate return (0); 2937c478bd9Sstevel@tonic-gate } 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate static int 2967c478bd9Sstevel@tonic-gate already_there(int controller) 2977c478bd9Sstevel@tonic-gate { 2987c478bd9Sstevel@tonic-gate raidlist_t *curr = raids; 2997c478bd9Sstevel@tonic-gate 3007c478bd9Sstevel@tonic-gate while (curr != NULL) { 3017c478bd9Sstevel@tonic-gate if (curr->controller == controller) 3027c478bd9Sstevel@tonic-gate return (1); 303*6fec3791Sjesseb 3047c478bd9Sstevel@tonic-gate curr = curr->next; 3057c478bd9Sstevel@tonic-gate } 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate return (0); 3087c478bd9Sstevel@tonic-gate } 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate /* 3117c478bd9Sstevel@tonic-gate * Display those controllers where RAID volumes were not found 3127c478bd9Sstevel@tonic-gate */ 3137c478bd9Sstevel@tonic-gate static void 3147c478bd9Sstevel@tonic-gate print_no_raids() 3157c478bd9Sstevel@tonic-gate { 3167c478bd9Sstevel@tonic-gate int i, space = 0; 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate if (info_ctrl == NULL) 3197c478bd9Sstevel@tonic-gate return; 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate for (i = 0; i < ctrl_nums; i++) { 3227c478bd9Sstevel@tonic-gate /* Status of '0' means RAID exists at that controller */ 3237c478bd9Sstevel@tonic-gate if (info_ctrl[i][INFO_STATUS] == RAID_FOUND || 3247c478bd9Sstevel@tonic-gate info_ctrl[i][INFO_STATUS] == RAID_DONT_USE) 3257c478bd9Sstevel@tonic-gate continue; 3267c478bd9Sstevel@tonic-gate 3277c478bd9Sstevel@tonic-gate if (!space && raids != NULL) { 3287c478bd9Sstevel@tonic-gate (void) printf("\n"); 3297c478bd9Sstevel@tonic-gate space = 1; 3307c478bd9Sstevel@tonic-gate } 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate /* switch statement used to enable gettext()'ing of text */ 3337c478bd9Sstevel@tonic-gate switch (info_ctrl[i][INFO_STATUS]) { 3347c478bd9Sstevel@tonic-gate case RAID_INVALID_CTRL: 3357c478bd9Sstevel@tonic-gate (void) printf(gettext("Invalid controller '%d'\n"), 3367c478bd9Sstevel@tonic-gate info_ctrl[i][INFO_CTRL]); 3377c478bd9Sstevel@tonic-gate break; 3387c478bd9Sstevel@tonic-gate case RAID_NOT_SUPPORTED: 3397c478bd9Sstevel@tonic-gate (void) printf(gettext("No RAID supported " 3407c478bd9Sstevel@tonic-gate "on controller '%d'\n"), 3417c478bd9Sstevel@tonic-gate info_ctrl[i][INFO_CTRL]); 3427c478bd9Sstevel@tonic-gate 3437c478bd9Sstevel@tonic-gate break; 3447c478bd9Sstevel@tonic-gate default: 3457c478bd9Sstevel@tonic-gate (void) printf(gettext("No RAID volumes found on " 3467c478bd9Sstevel@tonic-gate "controller '%d'\n"), info_ctrl[i][INFO_CTRL]); 3477c478bd9Sstevel@tonic-gate } 3487c478bd9Sstevel@tonic-gate } 3497c478bd9Sstevel@tonic-gate } 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate static void 3527c478bd9Sstevel@tonic-gate add_raid_to_raidlist(char *ctrl_name, int controller) 3537c478bd9Sstevel@tonic-gate { 3547c478bd9Sstevel@tonic-gate raidlist_t *curr; 3557c478bd9Sstevel@tonic-gate char buf[MAXPATHLEN] = {0}; 3567c478bd9Sstevel@tonic-gate char buf1[MAXPATHLEN] = {0}; 357*6fec3791Sjesseb int nvols; 3588ba1bcfcSdduvall int fd; 3598ba1bcfcSdduvall int i; 360*6fec3791Sjesseb int n; 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate if (readlink(ctrl_name, buf, sizeof (buf)) < 0) 3637c478bd9Sstevel@tonic-gate return; 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate if (get_ctrl_devctl(buf, buf1)) 3667c478bd9Sstevel@tonic-gate return; 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate /* 3697c478bd9Sstevel@tonic-gate * If "-l" was specified, then only look at those controllers 3707c478bd9Sstevel@tonic-gate * listed as part of the command line input. 3717c478bd9Sstevel@tonic-gate */ 3727c478bd9Sstevel@tonic-gate if (info_ctrl != NULL) { 3737c478bd9Sstevel@tonic-gate for (i = 0; i < ctrl_nums; i++) { 3747c478bd9Sstevel@tonic-gate if (info_ctrl[i][INFO_STATUS] == RAID_DONT_USE) 3757c478bd9Sstevel@tonic-gate continue; 376*6fec3791Sjesseb if (controller == info_ctrl[i][INFO_CTRL]) 3777c478bd9Sstevel@tonic-gate break; 3787c478bd9Sstevel@tonic-gate } 379*6fec3791Sjesseb /* return if we didn't find a controller */ 380*6fec3791Sjesseb if (i == ctrl_nums) 3817c478bd9Sstevel@tonic-gate return; 3827c478bd9Sstevel@tonic-gate } 3837c478bd9Sstevel@tonic-gate 3847c478bd9Sstevel@tonic-gate fd = open(buf1, O_RDONLY); 3857c478bd9Sstevel@tonic-gate if (fd == -1) { 3867c478bd9Sstevel@tonic-gate if (info_ctrl != NULL) 3877c478bd9Sstevel@tonic-gate info_ctrl[i][INFO_STATUS] = RAID_INVALID_CTRL; 3887c478bd9Sstevel@tonic-gate return; 3897c478bd9Sstevel@tonic-gate } 3907c478bd9Sstevel@tonic-gate 391*6fec3791Sjesseb /* 392*6fec3791Sjesseb * query the HBA driver for volume capacity 393*6fec3791Sjesseb */ 394*6fec3791Sjesseb if (ioctl(fd, RAID_NUMVOLUMES, &nvols) < 0) { 395*6fec3791Sjesseb if (info_ctrl != NULL) 396*6fec3791Sjesseb info_ctrl[i][INFO_STATUS] = RAID_NOT_SUPPORTED; 397*6fec3791Sjesseb (void) close(fd); 398*6fec3791Sjesseb return; 399*6fec3791Sjesseb } 400*6fec3791Sjesseb 401*6fec3791Sjesseb /* 402*6fec3791Sjesseb * now iterate through nvols configurations 403*6fec3791Sjesseb */ 404*6fec3791Sjesseb for (n = 0; n < nvols; n++) { 405*6fec3791Sjesseb raid_config_t config; 406*6fec3791Sjesseb 407*6fec3791Sjesseb /* use unitid to retrieve this volume */ 408*6fec3791Sjesseb config.unitid = n; 4097c478bd9Sstevel@tonic-gate if (ioctl(fd, RAID_GETCONFIG, &config) < 0) { 4107c478bd9Sstevel@tonic-gate if (info_ctrl != NULL) 4117c478bd9Sstevel@tonic-gate info_ctrl[i][INFO_STATUS] = RAID_NOT_SUPPORTED; 4127c478bd9Sstevel@tonic-gate (void) close(fd); 4137c478bd9Sstevel@tonic-gate return; 4147c478bd9Sstevel@tonic-gate } 4157c478bd9Sstevel@tonic-gate 416*6fec3791Sjesseb /* if ndisks is 0, this volume is not configured */ 417*6fec3791Sjesseb if (config.ndisks == 0) 418*6fec3791Sjesseb continue; 419*6fec3791Sjesseb 420*6fec3791Sjesseb /* otherwise, we have a raid volume */ 4217c478bd9Sstevel@tonic-gate if (info_ctrl != NULL) 4227c478bd9Sstevel@tonic-gate info_ctrl[i][INFO_STATUS] = RAID_FOUND; 4237c478bd9Sstevel@tonic-gate 424*6fec3791Sjesseb /* 425*6fec3791Sjesseb * if raids has not been initialized, do it. 426*6fec3791Sjesseb * otherwise, see if this controller is in 427*6fec3791Sjesseb * raids. 428*6fec3791Sjesseb */ 4297c478bd9Sstevel@tonic-gate if (raids == NULL) { 4307c478bd9Sstevel@tonic-gate raids = (raidlist_t *)malloc(sizeof (raidlist_t)); 4317c478bd9Sstevel@tonic-gate curr = raids; 4327c478bd9Sstevel@tonic-gate } else { 4337c478bd9Sstevel@tonic-gate curr = raids; 434*6fec3791Sjesseb if (already_there(controller)) 435*6fec3791Sjesseb goto already_there; 436*6fec3791Sjesseb 437*6fec3791Sjesseb /* add this controller to raids */ 4387c478bd9Sstevel@tonic-gate while (curr->next != NULL) 4397c478bd9Sstevel@tonic-gate curr = curr->next; 4407c478bd9Sstevel@tonic-gate curr->next = (raidlist_t *)malloc(sizeof (raidlist_t)); 4417c478bd9Sstevel@tonic-gate curr = curr->next; 4427c478bd9Sstevel@tonic-gate } 443*6fec3791Sjesseb 444*6fec3791Sjesseb already_there: 4457c478bd9Sstevel@tonic-gate curr->next = NULL; 4467c478bd9Sstevel@tonic-gate curr->controller = controller; 4477c478bd9Sstevel@tonic-gate (void) strlcpy(curr->devctl, buf1, sizeof (curr->devctl)); 4487c478bd9Sstevel@tonic-gate (void) fflush(stdout); 449*6fec3791Sjesseb (void) memcpy(&curr->raid_config[n], &config, 450*6fec3791Sjesseb (sizeof (raid_config_t))); 451*6fec3791Sjesseb } 452*6fec3791Sjesseb 453*6fec3791Sjesseb if (info_ctrl != NULL && info_ctrl[i][INFO_STATUS] != RAID_FOUND) 454*6fec3791Sjesseb info_ctrl[i][INFO_STATUS] = RAID_NOT_FOUND; 4557c478bd9Sstevel@tonic-gate } 4567c478bd9Sstevel@tonic-gate 4577c478bd9Sstevel@tonic-gate static void 4587c478bd9Sstevel@tonic-gate print_header() 4597c478bd9Sstevel@tonic-gate { 460*6fec3791Sjesseb (void) printf(gettext("RAID\tVolume\tRAID\t\tRAID\t\tDisk")); 4617c478bd9Sstevel@tonic-gate (void) printf("\n"); 462*6fec3791Sjesseb (void) printf(gettext("Volume\tType\tStatus\t\tDisk\t\tStatus")); 4637c478bd9Sstevel@tonic-gate (void) printf("\n"); 4647c478bd9Sstevel@tonic-gate (void) printf("------------------------------------------------------"); 4657c478bd9Sstevel@tonic-gate (void) printf("\n"); 4667c478bd9Sstevel@tonic-gate } 4677c478bd9Sstevel@tonic-gate 4687c478bd9Sstevel@tonic-gate static void 4697c478bd9Sstevel@tonic-gate print_raidconfig(int c, raid_config_t config) 4707c478bd9Sstevel@tonic-gate { 4717c478bd9Sstevel@tonic-gate int i; 472*6fec3791Sjesseb char voltype[8]; 4737c478bd9Sstevel@tonic-gate 474*6fec3791Sjesseb /* print RAID volume target ID and volume type */ 475*6fec3791Sjesseb if (config.raid_level == RAID_STRIPE) { 476*6fec3791Sjesseb (void) snprintf(voltype, sizeof (voltype), "IS"); 477*6fec3791Sjesseb } else if (config.raid_level == RAID_MIRROR) { 478*6fec3791Sjesseb (void) snprintf(voltype, sizeof (voltype), "IM"); 479*6fec3791Sjesseb } 480*6fec3791Sjesseb 481*6fec3791Sjesseb (void) printf("c%dt%dd0\t%s\t", c, config.targetid, voltype); 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate /* Get RAID Info */ 4847c478bd9Sstevel@tonic-gate if (config.flags & RAID_FLAG_RESYNCING && 4857c478bd9Sstevel@tonic-gate config.state == RAID_STATE_DEGRADED) { 4867c478bd9Sstevel@tonic-gate (void) printf(gettext("RESYNCING\t")); 4877c478bd9Sstevel@tonic-gate } else if (config.state == RAID_STATE_DEGRADED) { 4887c478bd9Sstevel@tonic-gate (void) printf(gettext("DEGRADED\t")); 4897c478bd9Sstevel@tonic-gate } else if (config.state == RAID_STATE_OPTIMAL) { 4907c478bd9Sstevel@tonic-gate (void) printf(gettext("OK\t\t")); 4917c478bd9Sstevel@tonic-gate } else if (config.state == RAID_STATE_FAILED) { 4927c478bd9Sstevel@tonic-gate (void) printf(gettext("FAILED\t\t")); 4937c478bd9Sstevel@tonic-gate } else { 4947c478bd9Sstevel@tonic-gate (void) printf(gettext("ERROR\t\t")); 4957c478bd9Sstevel@tonic-gate } 4967c478bd9Sstevel@tonic-gate 4977c478bd9Sstevel@tonic-gate /* Get RAID Disks */ 4987c478bd9Sstevel@tonic-gate (void) printf("c%dt%dd0\t\t", c, config.disk[0]); 4997c478bd9Sstevel@tonic-gate 5007c478bd9Sstevel@tonic-gate /* Get RAID Disk's Status */ 5017c478bd9Sstevel@tonic-gate if (config.diskstatus[0] & RAID_DISKSTATUS_FAILED) { 5027c478bd9Sstevel@tonic-gate (void) printf(gettext("FAILED\n")); 5037c478bd9Sstevel@tonic-gate } else if (config.diskstatus[0] & RAID_DISKSTATUS_MISSING) { 5047c478bd9Sstevel@tonic-gate (void) printf(gettext("MISSING\n")); 5057c478bd9Sstevel@tonic-gate } else { 5067c478bd9Sstevel@tonic-gate (void) printf(gettext("OK\n")); 5077c478bd9Sstevel@tonic-gate } 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate for (i = 1; i < config.ndisks; i++) { 5107c478bd9Sstevel@tonic-gate (void) printf("\t\t\t\tc%dt%dd0\t\t", c, config.disk[i]); 5117c478bd9Sstevel@tonic-gate if (config.diskstatus[i] & RAID_DISKSTATUS_FAILED) { 5127c478bd9Sstevel@tonic-gate (void) printf(gettext("FAILED\n")); 5137c478bd9Sstevel@tonic-gate } else if (config.diskstatus[i] & RAID_DISKSTATUS_MISSING) { 5147c478bd9Sstevel@tonic-gate (void) printf(gettext("MISSING\n")); 5157c478bd9Sstevel@tonic-gate } else { 5167c478bd9Sstevel@tonic-gate (void) printf(gettext("OK\n")); 5177c478bd9Sstevel@tonic-gate } 5187c478bd9Sstevel@tonic-gate } 5197c478bd9Sstevel@tonic-gate } 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate static void 5227c478bd9Sstevel@tonic-gate print_disklist() 5237c478bd9Sstevel@tonic-gate { 5247c478bd9Sstevel@tonic-gate raidlist_t *curr = raids; 525*6fec3791Sjesseb int i; 526*6fec3791Sjesseb 5277c478bd9Sstevel@tonic-gate while (curr != NULL) { 528*6fec3791Sjesseb for (i = 0; i < N_RAIDVOLS; i++) { 529*6fec3791Sjesseb if (curr->raid_config[i].ndisks != 0) { 530*6fec3791Sjesseb print_raidconfig(curr->controller, 531*6fec3791Sjesseb curr->raid_config[i]); 532*6fec3791Sjesseb } 533*6fec3791Sjesseb } 5347c478bd9Sstevel@tonic-gate curr = curr->next; 5357c478bd9Sstevel@tonic-gate } 5367c478bd9Sstevel@tonic-gate } 5377c478bd9Sstevel@tonic-gate 5387c478bd9Sstevel@tonic-gate static void 5397c478bd9Sstevel@tonic-gate free_disklist() 5407c478bd9Sstevel@tonic-gate { 5417c478bd9Sstevel@tonic-gate raidlist_t *curr = raids; 5427c478bd9Sstevel@tonic-gate 5437c478bd9Sstevel@tonic-gate while (curr != NULL) { 5447c478bd9Sstevel@tonic-gate raidlist_t *temp; 5457c478bd9Sstevel@tonic-gate temp = curr; 5467c478bd9Sstevel@tonic-gate curr = curr->next; 5477c478bd9Sstevel@tonic-gate free(temp); 5487c478bd9Sstevel@tonic-gate } 5497c478bd9Sstevel@tonic-gate } 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate static void 5527c478bd9Sstevel@tonic-gate do_search() 5537c478bd9Sstevel@tonic-gate { 5547c478bd9Sstevel@tonic-gate DIR *dir; 5557c478bd9Sstevel@tonic-gate struct dirent *dp; 5567c478bd9Sstevel@tonic-gate char buf[MAXPATHLEN]; 5577c478bd9Sstevel@tonic-gate int c; 5587c478bd9Sstevel@tonic-gate int i, j; 5597c478bd9Sstevel@tonic-gate 5607c478bd9Sstevel@tonic-gate /* 5617c478bd9Sstevel@tonic-gate * In case repeated numbers were found, assign the repititions as 5627c478bd9Sstevel@tonic-gate * RAID_DONT_USE 5637c478bd9Sstevel@tonic-gate */ 5647c478bd9Sstevel@tonic-gate for (i = 0; i < ctrl_nums; i++) { 5657c478bd9Sstevel@tonic-gate int first_one = 1; 5667c478bd9Sstevel@tonic-gate for (j = 0; j < ctrl_nums; j++) { 5677c478bd9Sstevel@tonic-gate if (info_ctrl[i][INFO_CTRL] == 5687c478bd9Sstevel@tonic-gate info_ctrl[j][INFO_CTRL]) { 5697c478bd9Sstevel@tonic-gate if (info_ctrl[j][INFO_STATUS] == RAID_DONT_USE) 5707c478bd9Sstevel@tonic-gate continue; 5717c478bd9Sstevel@tonic-gate if (first_one) { 5727c478bd9Sstevel@tonic-gate first_one = 0; 5737c478bd9Sstevel@tonic-gate } else { 5747c478bd9Sstevel@tonic-gate info_ctrl[j][INFO_STATUS] = 5757c478bd9Sstevel@tonic-gate RAID_DONT_USE; 5767c478bd9Sstevel@tonic-gate } 5777c478bd9Sstevel@tonic-gate } 5787c478bd9Sstevel@tonic-gate } 5797c478bd9Sstevel@tonic-gate } 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate if ((dir = opendir("/dev/cfg")) == NULL) { 5827c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 5837c478bd9Sstevel@tonic-gate gettext("Cannot open /dev/cfg: %s\n"), strerror(errno)); 5847c478bd9Sstevel@tonic-gate return; 5857c478bd9Sstevel@tonic-gate } 5867c478bd9Sstevel@tonic-gate while ((dp = readdir(dir)) != NULL) { 5877c478bd9Sstevel@tonic-gate if (strcmp(dp->d_name, ".") == 0 || 5887c478bd9Sstevel@tonic-gate strcmp(dp->d_name, "..") == 0) 5897c478bd9Sstevel@tonic-gate continue; 5907c478bd9Sstevel@tonic-gate if (sscanf(dp->d_name, "c%d", &c) != 1) 5917c478bd9Sstevel@tonic-gate continue; 5927c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "/dev/cfg/%s", dp->d_name); 5937c478bd9Sstevel@tonic-gate add_raid_to_raidlist(buf, c); 5947c478bd9Sstevel@tonic-gate } 5957c478bd9Sstevel@tonic-gate (void) closedir(dir); 5967c478bd9Sstevel@tonic-gate } 5977c478bd9Sstevel@tonic-gate 5987c478bd9Sstevel@tonic-gate /* 5997c478bd9Sstevel@tonic-gate * do_info() will do the following: 6007c478bd9Sstevel@tonic-gate * - create a list of disks' devctls 6017c478bd9Sstevel@tonic-gate * - try to talk to each of the devctls found 6027c478bd9Sstevel@tonic-gate * - if raid configuration is found, display it. 6037c478bd9Sstevel@tonic-gate */ 6047c478bd9Sstevel@tonic-gate static void 6057c478bd9Sstevel@tonic-gate do_info() 6067c478bd9Sstevel@tonic-gate { 6077c478bd9Sstevel@tonic-gate int i; 6087c478bd9Sstevel@tonic-gate (void) chdir(DEVDIR); 6097c478bd9Sstevel@tonic-gate 6107c478bd9Sstevel@tonic-gate do_search(); 6117c478bd9Sstevel@tonic-gate 6127c478bd9Sstevel@tonic-gate if (raids == NULL) { 6137c478bd9Sstevel@tonic-gate if (info_ctrl != NULL) { 6147c478bd9Sstevel@tonic-gate print_no_raids(); 6157c478bd9Sstevel@tonic-gate for (i = 0; i < ctrl_nums; i++) 6167c478bd9Sstevel@tonic-gate free(info_ctrl[i]); 6177c478bd9Sstevel@tonic-gate free(info_ctrl); 6187c478bd9Sstevel@tonic-gate } else { 6197c478bd9Sstevel@tonic-gate (void) printf(gettext("No RAID volumes found\n")); 6207c478bd9Sstevel@tonic-gate } 6217c478bd9Sstevel@tonic-gate return; 6227c478bd9Sstevel@tonic-gate } 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate print_header(); 6257c478bd9Sstevel@tonic-gate print_disklist(); 6267c478bd9Sstevel@tonic-gate print_no_raids(); 6277c478bd9Sstevel@tonic-gate free_disklist(); 6287c478bd9Sstevel@tonic-gate if (info_ctrl) { 6297c478bd9Sstevel@tonic-gate for (i = 0; i < ctrl_nums; i++) 6307c478bd9Sstevel@tonic-gate free(info_ctrl[i]); 6317c478bd9Sstevel@tonic-gate free(info_ctrl); 6327c478bd9Sstevel@tonic-gate } 6337c478bd9Sstevel@tonic-gate } 6347c478bd9Sstevel@tonic-gate 6357c478bd9Sstevel@tonic-gate static int 636*6fec3791Sjesseb disk_in_raid(int c, int t) 637*6fec3791Sjesseb { 638*6fec3791Sjesseb raidlist_t *curr; 639*6fec3791Sjesseb raid_config_t raid; 640*6fec3791Sjesseb int i, j, n; 641*6fec3791Sjesseb 642*6fec3791Sjesseb do_search(); 643*6fec3791Sjesseb curr = raids; 644*6fec3791Sjesseb 645*6fec3791Sjesseb while (curr != NULL) { 646*6fec3791Sjesseb if (curr->controller == c) { 647*6fec3791Sjesseb for (i = 0; i < N_RAIDVOLS; i++) { 648*6fec3791Sjesseb raid = curr->raid_config[i]; 649*6fec3791Sjesseb if ((n = raid.ndisks) != 0) { 650*6fec3791Sjesseb for (j = 0; j < n; j++) { 651*6fec3791Sjesseb if (raid.disk[j] == t) { 652*6fec3791Sjesseb return (1); 653*6fec3791Sjesseb } 654*6fec3791Sjesseb } 655*6fec3791Sjesseb } 656*6fec3791Sjesseb } 657*6fec3791Sjesseb } 658*6fec3791Sjesseb curr = curr->next; 659*6fec3791Sjesseb } 660*6fec3791Sjesseb return (0); 661*6fec3791Sjesseb } 662*6fec3791Sjesseb 663*6fec3791Sjesseb static int 6647c478bd9Sstevel@tonic-gate disk_there(int c, int t) 6657c478bd9Sstevel@tonic-gate { 6667c478bd9Sstevel@tonic-gate char disk[100]; 6677c478bd9Sstevel@tonic-gate int fd; 6687c478bd9Sstevel@tonic-gate 6697c478bd9Sstevel@tonic-gate (void) snprintf(disk, sizeof (disk), "c%dt%dd0s2", c, t); 6707c478bd9Sstevel@tonic-gate 6717c478bd9Sstevel@tonic-gate fd = open(disk, O_RDWR | O_NDELAY); 6727c478bd9Sstevel@tonic-gate if (fd == -1) { 6737c478bd9Sstevel@tonic-gate return (-1); 6747c478bd9Sstevel@tonic-gate } 6757c478bd9Sstevel@tonic-gate 6767c478bd9Sstevel@tonic-gate (void) close(fd); 6777c478bd9Sstevel@tonic-gate return (0); 6787c478bd9Sstevel@tonic-gate } 6797c478bd9Sstevel@tonic-gate 6807c478bd9Sstevel@tonic-gate static int 6817c478bd9Sstevel@tonic-gate get_controller(char *dev) 6827c478bd9Sstevel@tonic-gate { 6837c478bd9Sstevel@tonic-gate raidlist_t *curr; 6847c478bd9Sstevel@tonic-gate int c; 6857c478bd9Sstevel@tonic-gate do_search(); 6867c478bd9Sstevel@tonic-gate curr = raids; 6877c478bd9Sstevel@tonic-gate while (curr != NULL) { 6887c478bd9Sstevel@tonic-gate if (strcmp(curr->devctl, dev) == 0) { 6897c478bd9Sstevel@tonic-gate c = curr->controller; 6907c478bd9Sstevel@tonic-gate break; 6917c478bd9Sstevel@tonic-gate } 6927c478bd9Sstevel@tonic-gate curr = curr->next; 6937c478bd9Sstevel@tonic-gate } 6947c478bd9Sstevel@tonic-gate 6957c478bd9Sstevel@tonic-gate free_disklist(); 6967c478bd9Sstevel@tonic-gate return (c); 6977c478bd9Sstevel@tonic-gate } 6987c478bd9Sstevel@tonic-gate 6997c478bd9Sstevel@tonic-gate static int 7007c478bd9Sstevel@tonic-gate disk_mounted(char *d) 7017c478bd9Sstevel@tonic-gate { 7027c478bd9Sstevel@tonic-gate struct mnttab mt; 7037c478bd9Sstevel@tonic-gate FILE *f = fopen("/etc/mnttab", "r"); 7047c478bd9Sstevel@tonic-gate 7058ba1bcfcSdduvall while (getmntent(f, &mt) != EOF) 7067c478bd9Sstevel@tonic-gate if (strstr(mt.mnt_special, d) != NULL) 7077c478bd9Sstevel@tonic-gate return (1); 708*6fec3791Sjesseb 7097c478bd9Sstevel@tonic-gate return (0); 7107c478bd9Sstevel@tonic-gate } 7117c478bd9Sstevel@tonic-gate 7127c478bd9Sstevel@tonic-gate static int 7137c478bd9Sstevel@tonic-gate disk_big_enough(char **d, diskaddr_t *cap, int *errcond) 7147c478bd9Sstevel@tonic-gate { 7157c478bd9Sstevel@tonic-gate struct dk_minfo minfo; 7167c478bd9Sstevel@tonic-gate char disk[N_DISKS][MAXPATHLEN]; 717*6fec3791Sjesseb uint_t disk_lbsize[N_DISKS]; 7187c478bd9Sstevel@tonic-gate diskaddr_t disk_capacity[N_DISKS]; 7197c478bd9Sstevel@tonic-gate int i, fd; 7207c478bd9Sstevel@tonic-gate 7217c478bd9Sstevel@tonic-gate for (i = 0; i < N_DISKS; i++) { 722*6fec3791Sjesseb if (d[i] == NULL) 723*6fec3791Sjesseb break; 724*6fec3791Sjesseb 7257c478bd9Sstevel@tonic-gate (void) snprintf(disk[i], sizeof (disk[i]), DEVDIR"/%ss2", d[i]); 7267c478bd9Sstevel@tonic-gate fd = open(disk[i], O_RDWR | O_NDELAY); 727*6fec3791Sjesseb if (fd == -1) 7287c478bd9Sstevel@tonic-gate return (FAILURE); 7297c478bd9Sstevel@tonic-gate if (ioctl(fd, DKIOCGMEDIAINFO, &minfo) == -1) { 7307c478bd9Sstevel@tonic-gate (void) close(fd); 7317c478bd9Sstevel@tonic-gate return (FAILURE); 7327c478bd9Sstevel@tonic-gate } 7337c478bd9Sstevel@tonic-gate 7347c478bd9Sstevel@tonic-gate disk_lbsize[i] = minfo.dki_lbsize; 7357c478bd9Sstevel@tonic-gate disk_capacity[i] = minfo.dki_capacity; 7367c478bd9Sstevel@tonic-gate 737*6fec3791Sjesseb /* lbsize must be the same on all disks */ 738*6fec3791Sjesseb if (disk_lbsize[0] != disk_lbsize[i]) { 7397c478bd9Sstevel@tonic-gate *errcond = 2; 7407c478bd9Sstevel@tonic-gate return (INVALID_ARG); 7417c478bd9Sstevel@tonic-gate } 7427c478bd9Sstevel@tonic-gate 743*6fec3791Sjesseb /* ensure drive capacity is greater than or equal to first */ 744*6fec3791Sjesseb if (disk_capacity[0] > disk_capacity[i]) { 7457c478bd9Sstevel@tonic-gate *errcond = 1; 7467c478bd9Sstevel@tonic-gate return (INVALID_ARG); 7477c478bd9Sstevel@tonic-gate } 748*6fec3791Sjesseb (void) close(fd); 749*6fec3791Sjesseb } 7507c478bd9Sstevel@tonic-gate 751*6fec3791Sjesseb /* 752*6fec3791Sjesseb * setting capacity as the dk_minfo.dki_capacity of d[0] 753*6fec3791Sjesseb * this is the number of dki_lbsize blocks on disk 754*6fec3791Sjesseb */ 7557c478bd9Sstevel@tonic-gate *cap = disk_capacity[0]; 7567c478bd9Sstevel@tonic-gate return (SUCCESS); 7577c478bd9Sstevel@tonic-gate } 7587c478bd9Sstevel@tonic-gate 7597c478bd9Sstevel@tonic-gate static int 7607c478bd9Sstevel@tonic-gate do_config_change_state(cfga_cmd_t cmd, int d, int c) 7617c478bd9Sstevel@tonic-gate { 7627c478bd9Sstevel@tonic-gate cfga_err_t cfga_err; 7637c478bd9Sstevel@tonic-gate char *ap_id; 7647c478bd9Sstevel@tonic-gate int rv = SUCCESS; 7657c478bd9Sstevel@tonic-gate int count = 0; 7667c478bd9Sstevel@tonic-gate 7677c478bd9Sstevel@tonic-gate ap_id = (char *)malloc(100); 7687c478bd9Sstevel@tonic-gate if (ap_id == NULL) 7697c478bd9Sstevel@tonic-gate return (FAILURE); 7707c478bd9Sstevel@tonic-gate 7717c478bd9Sstevel@tonic-gate (void) snprintf(ap_id, 100, "c%d::dsk/c%dt%dd0", c, c, d); 7727c478bd9Sstevel@tonic-gate 7737c478bd9Sstevel@tonic-gate /* 7747c478bd9Sstevel@tonic-gate * If the config_change_state() funcation fails, we want to 7757c478bd9Sstevel@tonic-gate * retry. If the retry fails, then we return failure to fail. 7767c478bd9Sstevel@tonic-gate * 7777c478bd9Sstevel@tonic-gate * If we fail: 7787c478bd9Sstevel@tonic-gate * 7797c478bd9Sstevel@tonic-gate * If we were called from create, then we fail the raid 7807c478bd9Sstevel@tonic-gate * creation. 7817c478bd9Sstevel@tonic-gate * 7827c478bd9Sstevel@tonic-gate * If we were called from delete, then the disk will not 7837c478bd9Sstevel@tonic-gate * be re-configured by raidctl. 7847c478bd9Sstevel@tonic-gate */ 7857c478bd9Sstevel@tonic-gate do { 7867c478bd9Sstevel@tonic-gate cfga_err = config_change_state(cmd, 1, &ap_id, NULL, 7877c478bd9Sstevel@tonic-gate NULL, NULL, NULL, 0); 7887c478bd9Sstevel@tonic-gate count++; 7897c478bd9Sstevel@tonic-gate } while (cfga_err != CFGA_OK && count < 2); 7907c478bd9Sstevel@tonic-gate 7917c478bd9Sstevel@tonic-gate if (cfga_err != CFGA_OK) 7927c478bd9Sstevel@tonic-gate rv = FAILURE; 7937c478bd9Sstevel@tonic-gate 7947c478bd9Sstevel@tonic-gate free(ap_id); 7957c478bd9Sstevel@tonic-gate return (rv); 7967c478bd9Sstevel@tonic-gate } 7977c478bd9Sstevel@tonic-gate 7987c478bd9Sstevel@tonic-gate static int 799*6fec3791Sjesseb do_create(char **d, int rlevel, int force) 8007c478bd9Sstevel@tonic-gate { 8018ba1bcfcSdduvall raid_config_t config; 802*6fec3791Sjesseb raid_config_t newvol; 8037c478bd9Sstevel@tonic-gate char disk[N_DISKS][MAXPATHLEN] = {0}; 804*6fec3791Sjesseb int map[N_DISKS]; 8057c478bd9Sstevel@tonic-gate char channel1[MAXPATHLEN]; 8067c478bd9Sstevel@tonic-gate char channel2[MAXPATHLEN]; 8077c478bd9Sstevel@tonic-gate diskaddr_t capacity; 808*6fec3791Sjesseb int fd, fd2, size, errcond; 8097c478bd9Sstevel@tonic-gate int c[N_DISKS]; 8107c478bd9Sstevel@tonic-gate int t[N_DISKS]; 8117c478bd9Sstevel@tonic-gate char *tmp; 812*6fec3791Sjesseb int loc, i, devid, n, ndisks = 0; 8137c478bd9Sstevel@tonic-gate 8147c478bd9Sstevel@tonic-gate (void) chdir(DEVDIR); 8157c478bd9Sstevel@tonic-gate 816*6fec3791Sjesseb /* initialize target map */ 817*6fec3791Sjesseb for (i = 0; i < N_DISKS; i++) 818*6fec3791Sjesseb map[i] = -1; 819*6fec3791Sjesseb 8207c478bd9Sstevel@tonic-gate for (i = 0; i < N_DISKS; i++) { 821*6fec3791Sjesseb if (d[i] == NULL) 822*6fec3791Sjesseb break; 823*6fec3791Sjesseb 8247c478bd9Sstevel@tonic-gate if ((sscanf(d[i], "c%dt%dd0", &c[i], &t[i])) != 2 || 8257c478bd9Sstevel@tonic-gate t[i] < 0) { 8267c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 8277c478bd9Sstevel@tonic-gate gettext("Invalid disk format.\n")); 8287c478bd9Sstevel@tonic-gate return (INVALID_ARG); 8297c478bd9Sstevel@tonic-gate } 8307c478bd9Sstevel@tonic-gate 831*6fec3791Sjesseb /* ensure that all disks are on the same controller, */ 832*6fec3791Sjesseb if (c[i] != c[0]) { 833*6fec3791Sjesseb (void) fprintf(stderr, gettext("Disks must be " 834*6fec3791Sjesseb "on the same controller.\n")); 8357c478bd9Sstevel@tonic-gate return (INVALID_ARG); 8367c478bd9Sstevel@tonic-gate } 8377c478bd9Sstevel@tonic-gate 838*6fec3791Sjesseb /* that all disks are online, */ 839*6fec3791Sjesseb if (disk_there(c[0], t[i])) { 840*6fec3791Sjesseb (void) printf(gettext("Disk 'c%dt%dd0' is not " 841*6fec3791Sjesseb "present.\n"), c[0], t[i]); 8427c478bd9Sstevel@tonic-gate (void) printf(gettext("Cannot create RAID volume.\n")); 8437c478bd9Sstevel@tonic-gate return (INVALID_ARG); 8447c478bd9Sstevel@tonic-gate } 8457c478bd9Sstevel@tonic-gate 846*6fec3791Sjesseb /* that there are no duplicate disks, */ 847*6fec3791Sjesseb loc = t[i]; 848*6fec3791Sjesseb if (map[loc] == -1) { 849*6fec3791Sjesseb map[loc] = t[i]; 850*6fec3791Sjesseb } else { 851*6fec3791Sjesseb (void) fprintf(stderr, 852*6fec3791Sjesseb gettext("Disks must be different.\n")); 853*6fec3791Sjesseb return (INVALID_ARG); 854*6fec3791Sjesseb } 855*6fec3791Sjesseb 856*6fec3791Sjesseb /* that no disk is already in use by another volume, */ 857*6fec3791Sjesseb if (disk_in_raid(c[0], t[i])) { 858*6fec3791Sjesseb (void) fprintf(stderr, gettext("Disk %s is already in " 859*6fec3791Sjesseb "a RAID volume.\n"), d[i]); 860*6fec3791Sjesseb return (INVALID_ARG); 861*6fec3791Sjesseb } 862*6fec3791Sjesseb 863*6fec3791Sjesseb /* that no target's id is lower than the raidtarg, */ 864*6fec3791Sjesseb if (t[0] > t[i]) { 865*6fec3791Sjesseb (void) fprintf(stderr, gettext("First target ID must " 866*6fec3791Sjesseb "be less than other member target IDs.\n")); 867*6fec3791Sjesseb return (INVALID_ARG); 868*6fec3791Sjesseb } 869*6fec3791Sjesseb 870*6fec3791Sjesseb (void) snprintf(disk[i], sizeof (disk[i]), DEVDIR"/%ss2", d[i]); 871*6fec3791Sjesseb ndisks++; 872*6fec3791Sjesseb } 873*6fec3791Sjesseb 874*6fec3791Sjesseb /* confirm minimum number of disks */ 875*6fec3791Sjesseb if (ndisks < 2) { 876*6fec3791Sjesseb (void) fprintf(stderr, gettext("At least two disks are required" 877*6fec3791Sjesseb " for RAID creation.\n")); 878*6fec3791Sjesseb return (INVALID_ARG); 879*6fec3791Sjesseb } 880*6fec3791Sjesseb 881*6fec3791Sjesseb /* validate the drive capacities */ 8827c478bd9Sstevel@tonic-gate switch (disk_big_enough(d, &capacity, &errcond)) { 8837c478bd9Sstevel@tonic-gate case FAILURE: 8847c478bd9Sstevel@tonic-gate return (FAILURE); 8857c478bd9Sstevel@tonic-gate case INVALID_ARG: 8867c478bd9Sstevel@tonic-gate switch (errcond) { 8877c478bd9Sstevel@tonic-gate case 1: 8887c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("Cannot create RAID volume when " 8897c478bd9Sstevel@tonic-gate "primary disk is larger than secondary disk.\n")); 8907c478bd9Sstevel@tonic-gate break; 8917c478bd9Sstevel@tonic-gate case 2: 8927c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("Cannot create RAID volume when " 8937c478bd9Sstevel@tonic-gate "disk block sizes differ.\n")); 8947c478bd9Sstevel@tonic-gate } 8957c478bd9Sstevel@tonic-gate return (INVALID_ARG); 8967c478bd9Sstevel@tonic-gate } 8977c478bd9Sstevel@tonic-gate 898*6fec3791Sjesseb /* 899*6fec3791Sjesseb * capacity is now set to the number of blocks on a disk, which is 900*6fec3791Sjesseb * the total capacity of a mirror. the capacity of a stripe is the 901*6fec3791Sjesseb * cumulative amount of blocks on all disks 902*6fec3791Sjesseb */ 903*6fec3791Sjesseb if (rlevel == RAID_STRIPE) 904*6fec3791Sjesseb capacity *= ndisks; 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate if (get_devctl(disk[0], channel1)) 9077c478bd9Sstevel@tonic-gate return (FAILURE); 9087c478bd9Sstevel@tonic-gate 9097c478bd9Sstevel@tonic-gate fd = open(channel1, O_RDONLY); 9107c478bd9Sstevel@tonic-gate if (fd == -1) { 9117c478bd9Sstevel@tonic-gate perror(channel1); 9127c478bd9Sstevel@tonic-gate return (FAILURE); 9137c478bd9Sstevel@tonic-gate } 9147c478bd9Sstevel@tonic-gate 915*6fec3791Sjesseb /* 916*6fec3791Sjesseb * query the HBA driver for volume capacity 917*6fec3791Sjesseb */ 918*6fec3791Sjesseb if (ioctl(fd, RAID_NUMVOLUMES, &n) < 0) { 919*6fec3791Sjesseb raidctl_error("RAID_NUMVOLUMES"); 920*6fec3791Sjesseb goto fail; 921*6fec3791Sjesseb } 922*6fec3791Sjesseb 923*6fec3791Sjesseb /* 924*6fec3791Sjesseb * current support for both LSI1030 and LSI1064/1068 HBAs 925*6fec3791Sjesseb */ 926*6fec3791Sjesseb if (ioctl(fd, RAID_GETDEVID, &devid) < 0) { 927*6fec3791Sjesseb raidctl_error("RAID_GETDEVID"); 928*6fec3791Sjesseb goto fail; 929*6fec3791Sjesseb } 930*6fec3791Sjesseb 931*6fec3791Sjesseb if ((devid == LSI_1064) || (devid == LSI_1064E) || (devid == 932*6fec3791Sjesseb LSI_1068E)) { 933*6fec3791Sjesseb /* 934*6fec3791Sjesseb * no secondary channel, just check to make 935*6fec3791Sjesseb * sure we can fit a new volume 936*6fec3791Sjesseb */ 937*6fec3791Sjesseb for (i = 0; i < n; i++) { 938*6fec3791Sjesseb config.unitid = i; 9397c478bd9Sstevel@tonic-gate if (ioctl(fd, RAID_GETCONFIG, &config) < 0) { 9407c478bd9Sstevel@tonic-gate raidctl_error("RAID_GETCONFIG"); 941*6fec3791Sjesseb goto fail; 942*6fec3791Sjesseb } 943*6fec3791Sjesseb 944*6fec3791Sjesseb if (config.ndisks == 0) 945*6fec3791Sjesseb break; 946*6fec3791Sjesseb } 947*6fec3791Sjesseb 948*6fec3791Sjesseb if (i == n) { 949*6fec3791Sjesseb (void) printf(gettext("HBA supports a maximum of %d " 950*6fec3791Sjesseb "RAID Volumes, HBA is full\n"), n); 951*6fec3791Sjesseb goto fail; 952*6fec3791Sjesseb } 953*6fec3791Sjesseb 954*6fec3791Sjesseb /* 955*6fec3791Sjesseb * we have the capacity to add a volume, now confirm the 956*6fec3791Sjesseb * creation. the 1064 uses a much larger metadata region 957*6fec3791Sjesseb * than the 1030 (64MB, as opposed to 16KB). this larger 958*6fec3791Sjesseb * reservation is enough to alter the disk label. therefore, 959*6fec3791Sjesseb * once the volume is created, it must be relabeled. 960*6fec3791Sjesseb * first, confirm that no file systems are mounted, as 961*6fec3791Sjesseb * we will be pulling the disk out from under them 962*6fec3791Sjesseb */ 963*6fec3791Sjesseb for (i = 0; i < ndisks; i++) { 964*6fec3791Sjesseb if (disk_mounted(d[i])) { 965*6fec3791Sjesseb (void) fprintf(stderr, gettext("Cannot create " 966*6fec3791Sjesseb "RAID volume, disk \"%s\" is mounted " 967*6fec3791Sjesseb ".\n"), d[i]); 968*6fec3791Sjesseb return (INVALID_ARG); 969*6fec3791Sjesseb } 970*6fec3791Sjesseb } 971*6fec3791Sjesseb 972*6fec3791Sjesseb /* 973*6fec3791Sjesseb * will not support data migration or disk relabeling with 974*6fec3791Sjesseb * this utility, and so next we must confirm the creation as 975*6fec3791Sjesseb * all data on member disks will be lost. 976*6fec3791Sjesseb */ 977*6fec3791Sjesseb if (!force) { 978*6fec3791Sjesseb (void) fprintf(stderr, gettext("Creating RAID volume " 979*6fec3791Sjesseb "c%dt%dd0 will destroy all data on member disks, " 980*6fec3791Sjesseb "proceed (%s/%s)? "), c[0], t[0], yeschr, nochr); 981*6fec3791Sjesseb if (!yes()) { 982*6fec3791Sjesseb (void) fprintf(stderr, gettext("RAID volume " 983*6fec3791Sjesseb "c%dt%dd0 not created.\n\n"), c[0], t[0]); 984*6fec3791Sjesseb (void) close(fd); 985*6fec3791Sjesseb return (SUCCESS); 986*6fec3791Sjesseb } 987*6fec3791Sjesseb } 988*6fec3791Sjesseb 989*6fec3791Sjesseb /* 990*6fec3791Sjesseb * we are ready to move onto the creation 991*6fec3791Sjesseb */ 992*6fec3791Sjesseb goto no_secondary_channel; 993*6fec3791Sjesseb } 994*6fec3791Sjesseb 995*6fec3791Sjesseb /* 996*6fec3791Sjesseb * LSI1030, support for single IM volume 997*6fec3791Sjesseb */ 998*6fec3791Sjesseb if (rlevel != RAID_MIRROR) { 999*6fec3791Sjesseb (void) printf(gettext("HBA only supports RAID " 1000*6fec3791Sjesseb "level 1 (mirrored) volumes\n")); 1001*6fec3791Sjesseb goto fail; 1002*6fec3791Sjesseb } 1003*6fec3791Sjesseb /* 1004*6fec3791Sjesseb * look up the volume configuration 1005*6fec3791Sjesseb */ 1006*6fec3791Sjesseb config.unitid = n; 1007*6fec3791Sjesseb if (ioctl(fd, RAID_GETCONFIG, &config) < 0) { 1008*6fec3791Sjesseb raidctl_error("RAID_GETCONFIG"); 1009*6fec3791Sjesseb goto fail; 10107c478bd9Sstevel@tonic-gate } 10117c478bd9Sstevel@tonic-gate 10128ba1bcfcSdduvall if (config.ndisks != 0) { 1013*6fec3791Sjesseb (void) printf(gettext("RAID Volume already exists " 1014*6fec3791Sjesseb "on this controller 'c%dt%dd0'\n"), 1015*6fec3791Sjesseb c[0], config.targetid); 1016*6fec3791Sjesseb goto fail; 101705411564Sjesseb } 101805411564Sjesseb 101905411564Sjesseb /* 10207c478bd9Sstevel@tonic-gate * Make sure there isn't a raid created on this controller's 1021*6fec3791Sjesseb * other channel, if it has multiple channels 10227c478bd9Sstevel@tonic-gate */ 10237c478bd9Sstevel@tonic-gate (void) strlcpy(channel2, channel1, sizeof (channel2)); 10247c478bd9Sstevel@tonic-gate tmp = strrchr(channel2, ':'); 10257c478bd9Sstevel@tonic-gate tmp[0] = 0; 10267c478bd9Sstevel@tonic-gate size = strlen(channel2); 10277c478bd9Sstevel@tonic-gate 10287c478bd9Sstevel@tonic-gate /* 1029*6fec3791Sjesseb * Make sure that the secondary disk is not mounted 1030*6fec3791Sjesseb */ 1031*6fec3791Sjesseb if (disk_mounted(disk[1])) { 1032*6fec3791Sjesseb (void) fprintf(stderr, gettext("Cannot create RAID volume when " 1033*6fec3791Sjesseb "secondary disk \"%s\" is mounted.\n"), disk[1]); 1034*6fec3791Sjesseb return (INVALID_ARG); 1035*6fec3791Sjesseb } 1036*6fec3791Sjesseb 1037*6fec3791Sjesseb /* 10387c478bd9Sstevel@tonic-gate * Format the channel string for the other channel so we can 1039*6fec3791Sjesseb * see if a raid exists on it. In this case if we are being 1040*6fec3791Sjesseb * asked to create a raid on channel 2 (indicated by the 1,1 1041*6fec3791Sjesseb * at the end of the string) we want to check channel 1), 1042*6fec3791Sjesseb * otherwise we will check channel 2. 10437c478bd9Sstevel@tonic-gate */ 10447c478bd9Sstevel@tonic-gate if (channel2[size - 2] == ',') { 10457c478bd9Sstevel@tonic-gate channel2[size - 1] = 0; 10467c478bd9Sstevel@tonic-gate channel2[size - 2] = 0; 1047*6fec3791Sjesseb (void) snprintf(channel2, sizeof (channel2), 1048*6fec3791Sjesseb "%s:devctl", channel2); 10497c478bd9Sstevel@tonic-gate } else { 1050*6fec3791Sjesseb (void) snprintf(channel2, sizeof (channel2), 1051*6fec3791Sjesseb "%s,1:devctl", channel2); 10527c478bd9Sstevel@tonic-gate } 10537c478bd9Sstevel@tonic-gate 10547c478bd9Sstevel@tonic-gate fd2 = open(channel2, O_RDONLY); 10557c478bd9Sstevel@tonic-gate if (fd2 == -1) { 10567c478bd9Sstevel@tonic-gate if (errno == ENOENT) 10577c478bd9Sstevel@tonic-gate goto no_secondary_channel; 10587c478bd9Sstevel@tonic-gate perror(channel2); 1059*6fec3791Sjesseb goto fail; 10607c478bd9Sstevel@tonic-gate } 10617c478bd9Sstevel@tonic-gate 10627c478bd9Sstevel@tonic-gate if (ioctl(fd2, RAID_GETCONFIG, &config) < 0) { 1063*6fec3791Sjesseb goto fail; 10647c478bd9Sstevel@tonic-gate } 10657c478bd9Sstevel@tonic-gate 10668ba1bcfcSdduvall if (config.ndisks != 0) { 10677c478bd9Sstevel@tonic-gate int cx; 10687c478bd9Sstevel@tonic-gate cx = get_controller(channel2); 1069*6fec3791Sjesseb (void) printf(gettext("RAID Volume already exists " 1070*6fec3791Sjesseb "on this controller 'c%dt%dd0'\n"), cx, 1071*6fec3791Sjesseb config.targetid); 1072*6fec3791Sjesseb goto fail; 10737c478bd9Sstevel@tonic-gate } 10747c478bd9Sstevel@tonic-gate 10757c478bd9Sstevel@tonic-gate no_secondary_channel: 10767c478bd9Sstevel@tonic-gate 1077*6fec3791Sjesseb /* all checks complete, fill in the config */ 1078*6fec3791Sjesseb newvol.targetid = t[0]; 1079*6fec3791Sjesseb newvol.disk[0] = t[0]; 1080*6fec3791Sjesseb newvol.raid_level = rlevel; 1081*6fec3791Sjesseb newvol.ndisks = ndisks; 1082*6fec3791Sjesseb newvol.raid_capacity = capacity; 10837c478bd9Sstevel@tonic-gate 1084*6fec3791Sjesseb /* populate config.disk, and unconfigure all disks, except targetid */ 1085*6fec3791Sjesseb for (i = 1; i < ndisks; i++) { 10867c478bd9Sstevel@tonic-gate if (do_config_change_state(CFGA_CMD_UNCONFIGURE, 1087*6fec3791Sjesseb t[i], c[0])) { 10887c478bd9Sstevel@tonic-gate perror("config_change_state"); 1089*6fec3791Sjesseb goto fail; 1090*6fec3791Sjesseb } 1091*6fec3791Sjesseb newvol.disk[i] = t[i]; 10927c478bd9Sstevel@tonic-gate } 10937c478bd9Sstevel@tonic-gate 1094*6fec3791Sjesseb if (ioctl(fd, RAID_CREATE, &newvol)) { 1095*6fec3791Sjesseb /* reconfigure all disks, except targetid */ 1096*6fec3791Sjesseb for (i = 1; i < ndisks; i++) { 10977c478bd9Sstevel@tonic-gate (void) do_config_change_state(CFGA_CMD_CONFIGURE, 1098*6fec3791Sjesseb newvol.disk[i], c[0]); 1099*6fec3791Sjesseb } 11007c478bd9Sstevel@tonic-gate raidctl_error("RAID_CREATE"); 1101*6fec3791Sjesseb goto fail; 11027c478bd9Sstevel@tonic-gate } 11037c478bd9Sstevel@tonic-gate 11047c478bd9Sstevel@tonic-gate (void) printf(gettext("Volume 'c%dt%dd0' created\n"), c[0], t[0]); 11057c478bd9Sstevel@tonic-gate (void) close(fd); 11067c478bd9Sstevel@tonic-gate (void) close(fd2); 11077c478bd9Sstevel@tonic-gate return (SUCCESS); 11087c478bd9Sstevel@tonic-gate 1109*6fec3791Sjesseb fail: 11108ba1bcfcSdduvall (void) close(fd); 1111*6fec3791Sjesseb (void) close(fd2); 11127c478bd9Sstevel@tonic-gate return (FAILURE); 11137c478bd9Sstevel@tonic-gate } 11147c478bd9Sstevel@tonic-gate 11157c478bd9Sstevel@tonic-gate static int 1116*6fec3791Sjesseb do_delete(char *d, int force) 11177c478bd9Sstevel@tonic-gate { 11188ba1bcfcSdduvall raid_config_t config; 11197c478bd9Sstevel@tonic-gate char disk1[MAXPATHLEN]; 11207c478bd9Sstevel@tonic-gate char buf[MAXPATHLEN]; 11217c478bd9Sstevel@tonic-gate int fd; 11227c478bd9Sstevel@tonic-gate int target; 11237c478bd9Sstevel@tonic-gate int ctrl; 1124*6fec3791Sjesseb int i, j; 1125*6fec3791Sjesseb int wrong_targ = 0; 1126*6fec3791Sjesseb int nvols; 11277c478bd9Sstevel@tonic-gate uint8_t t; 11287c478bd9Sstevel@tonic-gate 11297c478bd9Sstevel@tonic-gate (void) chdir(DEVDIR); 11307c478bd9Sstevel@tonic-gate 11317c478bd9Sstevel@tonic-gate if ((sscanf(d, "c%dt%dd0", &ctrl, &target)) != 2) { 11327c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("Invalid disk format.\n")); 11337c478bd9Sstevel@tonic-gate return (INVALID_ARG); 11347c478bd9Sstevel@tonic-gate } 11357c478bd9Sstevel@tonic-gate t = (uint8_t)target; 11367c478bd9Sstevel@tonic-gate 11377c478bd9Sstevel@tonic-gate (void) snprintf(disk1, sizeof (disk1), DEVDIR"/%ss2", d); 11387c478bd9Sstevel@tonic-gate 11397c478bd9Sstevel@tonic-gate if (get_devctl(disk1, buf) != 0) { 1140*6fec3791Sjesseb (void) fprintf(stderr, gettext("Not a volume '%s'\n"), d); 11417c478bd9Sstevel@tonic-gate return (FAILURE); 11427c478bd9Sstevel@tonic-gate } 11437c478bd9Sstevel@tonic-gate 11447c478bd9Sstevel@tonic-gate fd = open(buf, O_RDONLY); 11457c478bd9Sstevel@tonic-gate if (fd == -1) { 11467c478bd9Sstevel@tonic-gate perror(buf); 11477c478bd9Sstevel@tonic-gate return (FAILURE); 11487c478bd9Sstevel@tonic-gate } 11497c478bd9Sstevel@tonic-gate 1150*6fec3791Sjesseb if (ioctl(fd, RAID_NUMVOLUMES, &nvols)) { 1151*6fec3791Sjesseb raidctl_error("RAID_NUMVOLUMES"); 1152*6fec3791Sjesseb goto fail; 1153*6fec3791Sjesseb } 1154*6fec3791Sjesseb 1155*6fec3791Sjesseb for (i = 0; i < nvols; i++) { 1156*6fec3791Sjesseb config.unitid = i; 11577c478bd9Sstevel@tonic-gate if (ioctl(fd, RAID_GETCONFIG, &config)) { 11587c478bd9Sstevel@tonic-gate raidctl_error("RAID_GETCONFIG"); 11597c478bd9Sstevel@tonic-gate goto fail; 11607c478bd9Sstevel@tonic-gate } 1161*6fec3791Sjesseb if (config.ndisks != 0) { 1162*6fec3791Sjesseb /* there is a RAID volume in this slot */ 1163*6fec3791Sjesseb if (config.targetid != t) { 1164*6fec3791Sjesseb wrong_targ++; 1165*6fec3791Sjesseb continue; 1166*6fec3791Sjesseb } 1167*6fec3791Sjesseb /* and it's our target */ 1168*6fec3791Sjesseb break; 1169*6fec3791Sjesseb } 1170*6fec3791Sjesseb } 11717c478bd9Sstevel@tonic-gate 1172*6fec3791Sjesseb if (i == nvols) { 1173*6fec3791Sjesseb /* we found no RAID volumes */ 1174*6fec3791Sjesseb (void) fprintf(stderr, gettext("No RAID volumes exist on " 11757c478bd9Sstevel@tonic-gate "controller '%d'\n"), ctrl); 11767c478bd9Sstevel@tonic-gate goto fail; 11777c478bd9Sstevel@tonic-gate } 11787c478bd9Sstevel@tonic-gate 1179*6fec3791Sjesseb if (wrong_targ == nvols) { 1180*6fec3791Sjesseb /* we found RAID volumes, but none matched */ 11817c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 11827c478bd9Sstevel@tonic-gate gettext("RAID volume 'c%dt%dd0' does not exist\n"), 11837c478bd9Sstevel@tonic-gate ctrl, t); 11847c478bd9Sstevel@tonic-gate goto fail; 11857c478bd9Sstevel@tonic-gate } 11867c478bd9Sstevel@tonic-gate 1187*6fec3791Sjesseb /* if this volume is a stripe, all data will be lost */ 1188*6fec3791Sjesseb if (config.raid_level == RAID_STRIPE) { 1189*6fec3791Sjesseb if (disk_mounted(d)) { 1190*6fec3791Sjesseb (void) fprintf(stderr, gettext("Cannot delete " 1191*6fec3791Sjesseb "RAID0 volume, \"%s\" is mounted.\n"), d); 1192*6fec3791Sjesseb return (INVALID_ARG); 1193*6fec3791Sjesseb } 1194*6fec3791Sjesseb 1195*6fec3791Sjesseb if (!force) { 1196*6fec3791Sjesseb (void) fprintf(stderr, gettext("Deleting volume " 1197*6fec3791Sjesseb "c%dt%dd0 will destroy all data it contains, " 1198*6fec3791Sjesseb "proceed (%s/%s)? "), ctrl, t, yeschr, nochr); 1199*6fec3791Sjesseb if (!yes()) { 1200*6fec3791Sjesseb (void) fprintf(stderr, gettext("RAID volume " 1201*6fec3791Sjesseb "c%dt%dd0 not deleted.\n\n"), ctrl, t); 1202*6fec3791Sjesseb (void) close(fd); 1203*6fec3791Sjesseb return (SUCCESS); 1204*6fec3791Sjesseb } 1205*6fec3791Sjesseb } 1206*6fec3791Sjesseb } 1207*6fec3791Sjesseb 12087c478bd9Sstevel@tonic-gate if (ioctl(fd, RAID_DELETE, &t)) { 12097c478bd9Sstevel@tonic-gate perror("RAID_DELETE"); 12107c478bd9Sstevel@tonic-gate goto fail; 12117c478bd9Sstevel@tonic-gate } 12127c478bd9Sstevel@tonic-gate 1213*6fec3791Sjesseb /* reconfigure all disks, except targetid */ 1214*6fec3791Sjesseb for (j = 1; j < config.ndisks; j++) { 1215*6fec3791Sjesseb (void) do_config_change_state(CFGA_CMD_CONFIGURE, 1216*6fec3791Sjesseb config.disk[j], ctrl); 1217*6fec3791Sjesseb } 12187c478bd9Sstevel@tonic-gate 12197c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("Volume 'c%dt%dd0' deleted.\n"), 12207c478bd9Sstevel@tonic-gate ctrl, target); 12217c478bd9Sstevel@tonic-gate (void) close(fd); 12227c478bd9Sstevel@tonic-gate return (SUCCESS); 12237c478bd9Sstevel@tonic-gate 12247c478bd9Sstevel@tonic-gate fail: 12257c478bd9Sstevel@tonic-gate (void) close(fd); 12267c478bd9Sstevel@tonic-gate return (FAILURE); 12277c478bd9Sstevel@tonic-gate } 12287c478bd9Sstevel@tonic-gate 12297c478bd9Sstevel@tonic-gate static int 12307c478bd9Sstevel@tonic-gate getfcodever(uint8_t *rombuf, uint32_t nbytes, char **fcodeversion) 12317c478bd9Sstevel@tonic-gate { 12327c478bd9Sstevel@tonic-gate int x, y, size; 12337c478bd9Sstevel@tonic-gate int found_1 = 0, found_2 = 0; 12347c478bd9Sstevel@tonic-gate int image_length = 0; 12357c478bd9Sstevel@tonic-gate int no_of_images = 0; 12367c478bd9Sstevel@tonic-gate uint8_t *rombuf_1 = NULL; 12377c478bd9Sstevel@tonic-gate uint16_t image_units = 0; 12387c478bd9Sstevel@tonic-gate 12397c478bd9Sstevel@tonic-gate /* 12407c478bd9Sstevel@tonic-gate * Single Image - Open firmware image 12417c478bd9Sstevel@tonic-gate */ 12427c478bd9Sstevel@tonic-gate if (rombuf[gw(&rombuf[PCIR_OFF]) + PCIR_CODETYPE] == 1) { 12437c478bd9Sstevel@tonic-gate rombuf_1 = rombuf + gw(rombuf + PCIR_OFF) + PCI_PDS_INDICATOR; 12447c478bd9Sstevel@tonic-gate no_of_images = 1; 12457c478bd9Sstevel@tonic-gate goto process_image; 12467c478bd9Sstevel@tonic-gate } 12477c478bd9Sstevel@tonic-gate 12487c478bd9Sstevel@tonic-gate /* 12497c478bd9Sstevel@tonic-gate * Combined Image - First Image - x86/PC-AT Bios image 12507c478bd9Sstevel@tonic-gate */ 12517c478bd9Sstevel@tonic-gate if (rombuf[gw(&rombuf[PCIR_OFF]) + PCIR_CODETYPE] != 0) { 12527c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("This is neither open image" 12537c478bd9Sstevel@tonic-gate " nor Bios/Fcode combined image\n")); 12547c478bd9Sstevel@tonic-gate return (1); 12557c478bd9Sstevel@tonic-gate } 12567c478bd9Sstevel@tonic-gate 12577c478bd9Sstevel@tonic-gate /* 12587c478bd9Sstevel@tonic-gate * Seek to 2nd Image 12597c478bd9Sstevel@tonic-gate */ 12607c478bd9Sstevel@tonic-gate rombuf_1 = rombuf + gw(rombuf + PCI_ROM_PCI_DATA_STRUCT_PTR); 12617c478bd9Sstevel@tonic-gate image_units = gw(rombuf_1 + PCI_PDS_IMAGE_LENGTH); 12627c478bd9Sstevel@tonic-gate image_length = image_units * PCI_IMAGE_UNIT_SIZE; 12637c478bd9Sstevel@tonic-gate rombuf_1 += image_length; 12647c478bd9Sstevel@tonic-gate 12657c478bd9Sstevel@tonic-gate /* 12667c478bd9Sstevel@tonic-gate * Combined Image - Second Image - Open Firmware image 12677c478bd9Sstevel@tonic-gate */ 12687c478bd9Sstevel@tonic-gate if (rombuf_1[PCI_PDS_CODE_TYPE] != 1) { 12697c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("This is neither open image" 12707c478bd9Sstevel@tonic-gate " nor Bios/Fcode combined image\n")); 12717c478bd9Sstevel@tonic-gate return (1); 12727c478bd9Sstevel@tonic-gate } 12737c478bd9Sstevel@tonic-gate rombuf_1 += PCI_PDS_INDICATOR; 12747c478bd9Sstevel@tonic-gate no_of_images = 2; 12757c478bd9Sstevel@tonic-gate 12767c478bd9Sstevel@tonic-gate process_image: 12777c478bd9Sstevel@tonic-gate /* 12787c478bd9Sstevel@tonic-gate * This should be the last image 12797c478bd9Sstevel@tonic-gate */ 12807c478bd9Sstevel@tonic-gate if (*rombuf_1 != LAST_IMAGE) { 12817c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("This is not a valid " 12827c478bd9Sstevel@tonic-gate "Bios/Fcode image file\n")); 12837c478bd9Sstevel@tonic-gate return (1); 12847c478bd9Sstevel@tonic-gate } 12857c478bd9Sstevel@tonic-gate 12867c478bd9Sstevel@tonic-gate /* 12877c478bd9Sstevel@tonic-gate * Scan through the bois/fcode file to get the fcode version 12887c478bd9Sstevel@tonic-gate * 0x12 and 0x7 indicate the start of the fcode version string 12897c478bd9Sstevel@tonic-gate */ 12907c478bd9Sstevel@tonic-gate for (x = 0; x < (nbytes - 8); x++) { 12917c478bd9Sstevel@tonic-gate if ((rombuf[x] == FCODE_VERS_KEY1) && 12927c478bd9Sstevel@tonic-gate (rombuf[x+1] == FCODE_VERS_KEY2) && 12937c478bd9Sstevel@tonic-gate (rombuf[x+2] == 'v') && (rombuf[x+3] == 'e') && 12947c478bd9Sstevel@tonic-gate (rombuf[x+4] == 'r') && (rombuf[x+5] == 's') && 12957c478bd9Sstevel@tonic-gate (rombuf[x+6] == 'i') && (rombuf[x+7] == 'o') && 12967c478bd9Sstevel@tonic-gate (rombuf[x+8] == 'n')) { 12977c478bd9Sstevel@tonic-gate found_1 = 1; 12987c478bd9Sstevel@tonic-gate break; 12997c478bd9Sstevel@tonic-gate } 13007c478bd9Sstevel@tonic-gate } 13017c478bd9Sstevel@tonic-gate 13027c478bd9Sstevel@tonic-gate /* 13037c478bd9Sstevel@tonic-gate * Store the version string if we have found the beginning of it 13047c478bd9Sstevel@tonic-gate */ 13057c478bd9Sstevel@tonic-gate if (found_1) { 13067c478bd9Sstevel@tonic-gate while (x > 0) { 13077c478bd9Sstevel@tonic-gate if (rombuf[--x] == FCODE_VERS_KEY1) { 13087c478bd9Sstevel@tonic-gate if (rombuf[x-1] != FCODE_VERS_KEY1) { 13097c478bd9Sstevel@tonic-gate x++; 13107c478bd9Sstevel@tonic-gate } 13117c478bd9Sstevel@tonic-gate break; 13127c478bd9Sstevel@tonic-gate } 13137c478bd9Sstevel@tonic-gate } 13147c478bd9Sstevel@tonic-gate if (x > 0) { 13157c478bd9Sstevel@tonic-gate *fcodeversion = (char *)malloc(rombuf[x] + 1); 13167c478bd9Sstevel@tonic-gate for (y = 0; y < rombuf[x]; y++) { 13177c478bd9Sstevel@tonic-gate (*fcodeversion)[y] = rombuf[x+y+1]; 13187c478bd9Sstevel@tonic-gate } 13197c478bd9Sstevel@tonic-gate (*fcodeversion)[y] = '\0'; 13207c478bd9Sstevel@tonic-gate } else { 13217c478bd9Sstevel@tonic-gate found_1 = 0; 13227c478bd9Sstevel@tonic-gate } 13237c478bd9Sstevel@tonic-gate } 13247c478bd9Sstevel@tonic-gate 13257c478bd9Sstevel@tonic-gate /* 13267c478bd9Sstevel@tonic-gate * Scan through the bois/fcode file to get the Bios version 13277c478bd9Sstevel@tonic-gate * "@(#)" string indicates the start of the Bios version string 13287c478bd9Sstevel@tonic-gate * Append this version string, after already existing fcode version. 13297c478bd9Sstevel@tonic-gate */ 13307c478bd9Sstevel@tonic-gate if (no_of_images == 2) { 13317c478bd9Sstevel@tonic-gate for (x = 0; x < (nbytes - 4); x++) { 13327c478bd9Sstevel@tonic-gate if ((rombuf[x] == '@') && (rombuf[x+1] == '(') && 13337c478bd9Sstevel@tonic-gate (rombuf[x+2] == '#') && (rombuf[x+3] == ')')) { 13347c478bd9Sstevel@tonic-gate found_2 = 1; 13357c478bd9Sstevel@tonic-gate break; 13367c478bd9Sstevel@tonic-gate } 13377c478bd9Sstevel@tonic-gate } 13387c478bd9Sstevel@tonic-gate 13397c478bd9Sstevel@tonic-gate if (found_2) { 13407c478bd9Sstevel@tonic-gate x += 4; 13417c478bd9Sstevel@tonic-gate (*fcodeversion)[y] = '\n'; 13427c478bd9Sstevel@tonic-gate size = y + strlen((char *)(rombuf + x)) + 13437c478bd9Sstevel@tonic-gate strlen(BIOS_STR) + 2; 13447c478bd9Sstevel@tonic-gate *fcodeversion = (char *)realloc((*fcodeversion), size); 13457c478bd9Sstevel@tonic-gate y++; 13467c478bd9Sstevel@tonic-gate (*fcodeversion)[y] = '\0'; 13477c478bd9Sstevel@tonic-gate (void) strlcat(*fcodeversion, BIOS_STR, size); 13487c478bd9Sstevel@tonic-gate (void) strlcat(*fcodeversion, (char *)(rombuf + x), 13497c478bd9Sstevel@tonic-gate size); 13507c478bd9Sstevel@tonic-gate } 13517c478bd9Sstevel@tonic-gate } 13527c478bd9Sstevel@tonic-gate 13537c478bd9Sstevel@tonic-gate return ((found_1 || found_2) ? 0 : 1); 13547c478bd9Sstevel@tonic-gate } 13557c478bd9Sstevel@tonic-gate 13567c478bd9Sstevel@tonic-gate static void 13577c478bd9Sstevel@tonic-gate getfwver(uint8_t *rombuf, char *fwversion) 13587c478bd9Sstevel@tonic-gate { 13597c478bd9Sstevel@tonic-gate (void) snprintf(fwversion, 8, "%d.%.2d.%.2d.%.2d", 13607c478bd9Sstevel@tonic-gate rombuf[FW_ROM_OFFSET_VERSION + 3], 13617c478bd9Sstevel@tonic-gate rombuf[FW_ROM_OFFSET_VERSION + 2], 13627c478bd9Sstevel@tonic-gate rombuf[FW_ROM_OFFSET_VERSION + 1], 13637c478bd9Sstevel@tonic-gate rombuf[FW_ROM_OFFSET_VERSION + 0]); 13647c478bd9Sstevel@tonic-gate } 13657c478bd9Sstevel@tonic-gate 13667c478bd9Sstevel@tonic-gate static int 13677c478bd9Sstevel@tonic-gate checkfile(uint8_t *rombuf, uint32_t nbytes, uint32_t chksum, int *imagetype) 13687c478bd9Sstevel@tonic-gate { 13697c478bd9Sstevel@tonic-gate char *imageversion = NULL; 13707c478bd9Sstevel@tonic-gate char *fwversion; 13717c478bd9Sstevel@tonic-gate 13727c478bd9Sstevel@tonic-gate fwversion = (char *)malloc(8); 13737c478bd9Sstevel@tonic-gate 13747c478bd9Sstevel@tonic-gate if (gw(&rombuf[0]) == PCIROM_SIG) { 13757c478bd9Sstevel@tonic-gate /* imageversion is malloc(2)'ed in getfcodever() */ 13767c478bd9Sstevel@tonic-gate if (getfcodever(rombuf, nbytes, &imageversion) == 0) { 13777c478bd9Sstevel@tonic-gate *imagetype = FCODE_IMAGE; 13787c478bd9Sstevel@tonic-gate } else { 13797c478bd9Sstevel@tonic-gate *imagetype = UNKNOWN_IMAGE; 13807c478bd9Sstevel@tonic-gate } 13817c478bd9Sstevel@tonic-gate if (*imagetype != UNKNOWN_IMAGE) { 13827c478bd9Sstevel@tonic-gate (void) printf(gettext("Image file contains:\n%s\n"), 13837c478bd9Sstevel@tonic-gate imageversion); 13847c478bd9Sstevel@tonic-gate free(imageversion); 13857c478bd9Sstevel@tonic-gate } else { 13867c478bd9Sstevel@tonic-gate if (imageversion != NULL) { 13877c478bd9Sstevel@tonic-gate free(imageversion); 13887c478bd9Sstevel@tonic-gate } 13897c478bd9Sstevel@tonic-gate return (-1); 13907c478bd9Sstevel@tonic-gate } 13917c478bd9Sstevel@tonic-gate } else if (gw(&rombuf[3]) == FW_ROM_ID) { 13927c478bd9Sstevel@tonic-gate if (chksum != 0) { 13937c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 13947c478bd9Sstevel@tonic-gate gettext("The ROM checksum appears bad " 13957c478bd9Sstevel@tonic-gate "(%d)\n"), chksum); 13967c478bd9Sstevel@tonic-gate return (-1); 13977c478bd9Sstevel@tonic-gate } 13987c478bd9Sstevel@tonic-gate getfwver(rombuf, fwversion); 13997c478bd9Sstevel@tonic-gate 14007c478bd9Sstevel@tonic-gate if ((gw(&rombuf[FW_ROM_OFFSET_CHIP_TYPE]) & 14017c478bd9Sstevel@tonic-gate MPI_FW_HEADER_PID_PROD_MASK) == 14027c478bd9Sstevel@tonic-gate MPI_FW_HEADER_PID_PROD_IM_SCSI) { 14037c478bd9Sstevel@tonic-gate (void) printf(gettext("ROM image contains " 14047c478bd9Sstevel@tonic-gate "MPT firmware version %s " 14057c478bd9Sstevel@tonic-gate "(w/Integrated Mirroring)\n"), 14067c478bd9Sstevel@tonic-gate fwversion); 14077c478bd9Sstevel@tonic-gate } else { 14087c478bd9Sstevel@tonic-gate (void) printf(gettext("ROM image contains " 14097c478bd9Sstevel@tonic-gate "MPT firmware ""version %s\n"), 14107c478bd9Sstevel@tonic-gate fwversion); 14117c478bd9Sstevel@tonic-gate } 14127c478bd9Sstevel@tonic-gate free(fwversion); 14137c478bd9Sstevel@tonic-gate } else { 14147c478bd9Sstevel@tonic-gate 14157c478bd9Sstevel@tonic-gate #ifdef DEBUG 14167c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "Not valid FCODE image %x\n", gw(&rombuf[0])); 14177c478bd9Sstevel@tonic-gate #else 14187c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("Not valid FCODE image\n")); 14197c478bd9Sstevel@tonic-gate #endif 14207c478bd9Sstevel@tonic-gate return (-1); 14217c478bd9Sstevel@tonic-gate } 14227c478bd9Sstevel@tonic-gate return (0); 14237c478bd9Sstevel@tonic-gate } 14247c478bd9Sstevel@tonic-gate 14257c478bd9Sstevel@tonic-gate static int 14267c478bd9Sstevel@tonic-gate updateflash(uint8_t *rombuf, uint32_t nbytes, char *devctl) 14277c478bd9Sstevel@tonic-gate { 14287c478bd9Sstevel@tonic-gate int fd = 0; 14297c478bd9Sstevel@tonic-gate update_flash_t flashdata; 14307c478bd9Sstevel@tonic-gate 14317c478bd9Sstevel@tonic-gate fd = open(devctl, O_RDONLY); 14327c478bd9Sstevel@tonic-gate if (fd == -1) { 14337c478bd9Sstevel@tonic-gate perror(devctl); 14347c478bd9Sstevel@tonic-gate return (-1); 14357c478bd9Sstevel@tonic-gate } 14367c478bd9Sstevel@tonic-gate (void) memset(&flashdata, 0, sizeof (flashdata)); 14377c478bd9Sstevel@tonic-gate flashdata.ptrbuffer = (caddr_t)rombuf; 14387c478bd9Sstevel@tonic-gate flashdata.size = nbytes; 14397c478bd9Sstevel@tonic-gate if ((rombuf[0] == 0x55) && (rombuf[1] == 0xaa)) { 14407c478bd9Sstevel@tonic-gate flashdata.type = FW_TYPE_FCODE; 14417c478bd9Sstevel@tonic-gate } else { 14427c478bd9Sstevel@tonic-gate flashdata.type = FW_TYPE_UCODE; 14437c478bd9Sstevel@tonic-gate } 14447c478bd9Sstevel@tonic-gate 14457c478bd9Sstevel@tonic-gate if (ioctl(fd, RAID_UPDATEFW, &flashdata)) { 14467c478bd9Sstevel@tonic-gate raidctl_error("RAID_UPDATEFW"); 14477c478bd9Sstevel@tonic-gate (void) close(fd); 14487c478bd9Sstevel@tonic-gate return (-1); 14497c478bd9Sstevel@tonic-gate } 14507c478bd9Sstevel@tonic-gate 14517c478bd9Sstevel@tonic-gate (void) close(fd); 14527c478bd9Sstevel@tonic-gate return (0); 14537c478bd9Sstevel@tonic-gate } 14547c478bd9Sstevel@tonic-gate 14557c478bd9Sstevel@tonic-gate static int 14567c478bd9Sstevel@tonic-gate readfile(char *filespec, uint8_t **rombuf, uint32_t *nbytes, uint32_t *chksum) 14577c478bd9Sstevel@tonic-gate { 14587c478bd9Sstevel@tonic-gate struct stat statbuf; 14597c478bd9Sstevel@tonic-gate uint32_t count; 14607c478bd9Sstevel@tonic-gate uint32_t checksum = 0; 14617c478bd9Sstevel@tonic-gate int fd, i; 14627c478bd9Sstevel@tonic-gate uint8_t *filebuf; 14637c478bd9Sstevel@tonic-gate 14647c478bd9Sstevel@tonic-gate 14657c478bd9Sstevel@tonic-gate if ((fd = open((const char *)filespec, O_RDONLY | O_NDELAY)) == -1) { 14667c478bd9Sstevel@tonic-gate perror(filespec); 14677c478bd9Sstevel@tonic-gate return (-1); 14687c478bd9Sstevel@tonic-gate } 14697c478bd9Sstevel@tonic-gate 14707c478bd9Sstevel@tonic-gate if (fstat(fd, &statbuf) != 0) { 14717c478bd9Sstevel@tonic-gate perror("fstat"); 14727c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 14737c478bd9Sstevel@tonic-gate gettext("Error getting stats on file\n")); 14747c478bd9Sstevel@tonic-gate (void) close(fd); 14757c478bd9Sstevel@tonic-gate return (-1); 14767c478bd9Sstevel@tonic-gate } 14777c478bd9Sstevel@tonic-gate 14787c478bd9Sstevel@tonic-gate #ifdef DEBUG 14797c478bd9Sstevel@tonic-gate (void) printf("Filesize = %ld\n", statbuf.st_size); 14807c478bd9Sstevel@tonic-gate #endif 14817c478bd9Sstevel@tonic-gate 14827c478bd9Sstevel@tonic-gate filebuf = (uint8_t *)realloc(*rombuf, statbuf.st_size + *nbytes); 14837c478bd9Sstevel@tonic-gate 14847c478bd9Sstevel@tonic-gate count = read(fd, filebuf + *nbytes, statbuf.st_size); 14857c478bd9Sstevel@tonic-gate (void) close(fd); 14867c478bd9Sstevel@tonic-gate if (count != statbuf.st_size) { 14877c478bd9Sstevel@tonic-gate perror("size check"); 14887c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("File is corrupt\n")); 14897c478bd9Sstevel@tonic-gate return (-1); 14907c478bd9Sstevel@tonic-gate } 14917c478bd9Sstevel@tonic-gate 14927c478bd9Sstevel@tonic-gate for (i = 0; i < *nbytes; i++) 14937c478bd9Sstevel@tonic-gate checksum += filebuf[i] << (8 * (i & 3)); 14947c478bd9Sstevel@tonic-gate 14957c478bd9Sstevel@tonic-gate *rombuf = filebuf; 14967c478bd9Sstevel@tonic-gate *nbytes = *nbytes + count; 14977c478bd9Sstevel@tonic-gate *chksum = checksum; 14987c478bd9Sstevel@tonic-gate 14997c478bd9Sstevel@tonic-gate return (0); 15007c478bd9Sstevel@tonic-gate } 15017c478bd9Sstevel@tonic-gate 15027c478bd9Sstevel@tonic-gate static int 1503*6fec3791Sjesseb yes(void) 15047c478bd9Sstevel@tonic-gate { 15057c478bd9Sstevel@tonic-gate int i, b; 15067c478bd9Sstevel@tonic-gate char ans[SCHAR_MAX + 1]; 15077c478bd9Sstevel@tonic-gate 15087c478bd9Sstevel@tonic-gate for (i = 0; ; i++) { 15097c478bd9Sstevel@tonic-gate b = getchar(); 15107c478bd9Sstevel@tonic-gate if (b == '\n' || b == '\0' || b == EOF) { 15117c478bd9Sstevel@tonic-gate ans[i] = 0; 15127c478bd9Sstevel@tonic-gate break; 15137c478bd9Sstevel@tonic-gate } 15147c478bd9Sstevel@tonic-gate if (i < SCHAR_MAX) 15157c478bd9Sstevel@tonic-gate ans[i] = b; 15167c478bd9Sstevel@tonic-gate } 15177c478bd9Sstevel@tonic-gate if (i >= SCHAR_MAX) { 15187c478bd9Sstevel@tonic-gate i = SCHAR_MAX; 15197c478bd9Sstevel@tonic-gate ans[SCHAR_MAX] = 0; 15207c478bd9Sstevel@tonic-gate } 1521*6fec3791Sjesseb if ((i != 0) && ((strncmp(yeschr, ans, i)) == 0)) 15227c478bd9Sstevel@tonic-gate return (1); 1523*6fec3791Sjesseb 15247c478bd9Sstevel@tonic-gate return (0); 15257c478bd9Sstevel@tonic-gate } 15267c478bd9Sstevel@tonic-gate 15277c478bd9Sstevel@tonic-gate static int 15287c478bd9Sstevel@tonic-gate do_flash(int c, char *fpath, int force) 15297c478bd9Sstevel@tonic-gate { 15307c478bd9Sstevel@tonic-gate char devctl[MAXPATHLEN] = {0}; 15317c478bd9Sstevel@tonic-gate char buf[MAXPATHLEN] = {0}; 15327c478bd9Sstevel@tonic-gate int rv = 0; 15337c478bd9Sstevel@tonic-gate int imagetype; 15347c478bd9Sstevel@tonic-gate uint32_t nbytes = 0; 15357c478bd9Sstevel@tonic-gate uint32_t chksum; 15367c478bd9Sstevel@tonic-gate uint8_t *rombuf = NULL; 15377c478bd9Sstevel@tonic-gate char cwd[MAXPATHLEN]; 15387c478bd9Sstevel@tonic-gate 15397c478bd9Sstevel@tonic-gate /* 15407c478bd9Sstevel@tonic-gate * Read fw file 15417c478bd9Sstevel@tonic-gate */ 15427c478bd9Sstevel@tonic-gate rv = readfile(fpath, &rombuf, &nbytes, &chksum); 15437c478bd9Sstevel@tonic-gate if (rv != 0) { 15447c478bd9Sstevel@tonic-gate return (FAILURE); 15457c478bd9Sstevel@tonic-gate } 15467c478bd9Sstevel@tonic-gate 15477c478bd9Sstevel@tonic-gate (void) getcwd(cwd, sizeof (cwd)); 15487c478bd9Sstevel@tonic-gate 15497c478bd9Sstevel@tonic-gate (void) chdir(DEVDIR); 15507c478bd9Sstevel@tonic-gate 15517c478bd9Sstevel@tonic-gate /* Get link from "/dev/cfg" */ 15527c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "/dev/cfg/c%d", c); 15537c478bd9Sstevel@tonic-gate if (get_link_path(buf, devctl) != 0) { 15547c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 15557c478bd9Sstevel@tonic-gate gettext("Invalid controller '%d'\n"), c); 15567c478bd9Sstevel@tonic-gate return (INVALID_ARG); 15577c478bd9Sstevel@tonic-gate } 15587c478bd9Sstevel@tonic-gate 15597c478bd9Sstevel@tonic-gate /* Check File */ 15607c478bd9Sstevel@tonic-gate rv = checkfile(rombuf, nbytes, chksum, &imagetype); 15617c478bd9Sstevel@tonic-gate if (rv != 0) { 15627c478bd9Sstevel@tonic-gate return (FAILURE); 15637c478bd9Sstevel@tonic-gate } 15647c478bd9Sstevel@tonic-gate 15657c478bd9Sstevel@tonic-gate /* Confirm */ 15667c478bd9Sstevel@tonic-gate if (!force) { 15677c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("Update flash image on " 15687c478bd9Sstevel@tonic-gate "controller %d (%s/%s)? "), c, yeschr, nochr); 1569*6fec3791Sjesseb if (!yes()) { 1570*6fec3791Sjesseb (void) fprintf(stderr, gettext("Controller %d not " 1571*6fec3791Sjesseb "flashed.\n\n"), c); 15727c478bd9Sstevel@tonic-gate return (SUCCESS); 15737c478bd9Sstevel@tonic-gate } 15747c478bd9Sstevel@tonic-gate } 15757c478bd9Sstevel@tonic-gate 15767c478bd9Sstevel@tonic-gate /* Do Flash */ 15777c478bd9Sstevel@tonic-gate if (updateflash(rombuf, nbytes, devctl)) { 15787c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("Flash not updated on " 15797c478bd9Sstevel@tonic-gate "Controller %d.\n\n"), c); 15807c478bd9Sstevel@tonic-gate return (INVALID_ARG); 15817c478bd9Sstevel@tonic-gate } 15827c478bd9Sstevel@tonic-gate (void) printf(gettext("Flash updated successfully.\n\n")); 15837c478bd9Sstevel@tonic-gate return (SUCCESS); 15847c478bd9Sstevel@tonic-gate } 15857c478bd9Sstevel@tonic-gate 15867c478bd9Sstevel@tonic-gate static int 15877c478bd9Sstevel@tonic-gate fully_numeric(char *str) 15887c478bd9Sstevel@tonic-gate { 15897c478bd9Sstevel@tonic-gate int size = strlen(str); 15907c478bd9Sstevel@tonic-gate int i; 15917c478bd9Sstevel@tonic-gate 15927c478bd9Sstevel@tonic-gate for (i = 0; i < size; i++) { 15937c478bd9Sstevel@tonic-gate if (i == 0 && str[i] == '-' && size != 1) 15947c478bd9Sstevel@tonic-gate continue; 15957c478bd9Sstevel@tonic-gate if (!isdigit(str[i])) 15967c478bd9Sstevel@tonic-gate return (0); 15977c478bd9Sstevel@tonic-gate } 15987c478bd9Sstevel@tonic-gate return (1); 15997c478bd9Sstevel@tonic-gate } 16007c478bd9Sstevel@tonic-gate 16017c478bd9Sstevel@tonic-gate /* 16027c478bd9Sstevel@tonic-gate * Useful parsing macros 16037c478bd9Sstevel@tonic-gate */ 16047c478bd9Sstevel@tonic-gate #define must_be(s, c) if (*s++ != c) return (0) 16057c478bd9Sstevel@tonic-gate #define skip_digits(s) while (isdigit(*s)) s++ 16067c478bd9Sstevel@tonic-gate 16077c478bd9Sstevel@tonic-gate /* 16087c478bd9Sstevel@tonic-gate * Return true if a name is in the internal canonical form 16097c478bd9Sstevel@tonic-gate */ 16107c478bd9Sstevel@tonic-gate static int 16117c478bd9Sstevel@tonic-gate canonical_name(char *name) 16127c478bd9Sstevel@tonic-gate { 16137c478bd9Sstevel@tonic-gate must_be(name, 'c'); 16147c478bd9Sstevel@tonic-gate skip_digits(name); 16157c478bd9Sstevel@tonic-gate if (*name == 't') { 16167c478bd9Sstevel@tonic-gate name++; 16177c478bd9Sstevel@tonic-gate skip_digits(name); 16187c478bd9Sstevel@tonic-gate } 16197c478bd9Sstevel@tonic-gate must_be(name, 'd'); 16207c478bd9Sstevel@tonic-gate skip_digits(name); 16217c478bd9Sstevel@tonic-gate return (*name == 0); 16227c478bd9Sstevel@tonic-gate } 16237c478bd9Sstevel@tonic-gate 16247c478bd9Sstevel@tonic-gate int 16257c478bd9Sstevel@tonic-gate main(int argc, char **argv) 16267c478bd9Sstevel@tonic-gate { 16277c478bd9Sstevel@tonic-gate int rv = SUCCESS; 16287c478bd9Sstevel@tonic-gate int i, c; 16297c478bd9Sstevel@tonic-gate int findex = DO_HW_RAID_INFO; 16307c478bd9Sstevel@tonic-gate int controller; 1631*6fec3791Sjesseb char *disks[N_DISKS] = {0}; 16327c478bd9Sstevel@tonic-gate char *darg; 16337c478bd9Sstevel@tonic-gate char *farg; 1634*6fec3791Sjesseb char *rarg; 16357c478bd9Sstevel@tonic-gate char *progname; 16367c478bd9Sstevel@tonic-gate 16377c478bd9Sstevel@tonic-gate int l_flag = 0; 16387c478bd9Sstevel@tonic-gate int c_flag = 0; 16397c478bd9Sstevel@tonic-gate int d_flag = 0; 16407c478bd9Sstevel@tonic-gate int f_flag = 0; 16417c478bd9Sstevel@tonic-gate int F_flag = 0; 1642*6fec3791Sjesseb int r_flag = 0; 16437c478bd9Sstevel@tonic-gate int no_flags = 1; 1644*6fec3791Sjesseb int r = RAID_MIRROR; /* default raid level is 1 */ 16457c478bd9Sstevel@tonic-gate char *current_dir; 16467c478bd9Sstevel@tonic-gate 16477c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 16487c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 16497c478bd9Sstevel@tonic-gate 16507c478bd9Sstevel@tonic-gate if (geteuid() != 0) { 16517c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("Must be root.\n")); 16527c478bd9Sstevel@tonic-gate exit(1); 16537c478bd9Sstevel@tonic-gate } 16547c478bd9Sstevel@tonic-gate 16557c478bd9Sstevel@tonic-gate if ((progname = strrchr(argv[0], '/')) == NULL) 16567c478bd9Sstevel@tonic-gate progname = argv[0]; 16577c478bd9Sstevel@tonic-gate else 16587c478bd9Sstevel@tonic-gate progname++; 16597c478bd9Sstevel@tonic-gate 16607c478bd9Sstevel@tonic-gate raids = NULL; 16617c478bd9Sstevel@tonic-gate 16627c478bd9Sstevel@tonic-gate (void) strncpy(yeschr, nl_langinfo(YESSTR), SCHAR_MAX + 1); 16637c478bd9Sstevel@tonic-gate (void) strncpy(nochr, nl_langinfo(NOSTR), SCHAR_MAX + 1); 16647c478bd9Sstevel@tonic-gate 1665*6fec3791Sjesseb while ((c = getopt(argc, argv, "cr:lfd:F:")) != EOF) { 16667c478bd9Sstevel@tonic-gate switch (c) { 16677c478bd9Sstevel@tonic-gate case 'c': 1668*6fec3791Sjesseb if (argc < 4) 16697c478bd9Sstevel@tonic-gate usage(progname); 16707c478bd9Sstevel@tonic-gate findex = DO_HW_RAID_CREATE; 16717c478bd9Sstevel@tonic-gate c_flag = 1; 16727c478bd9Sstevel@tonic-gate no_flags = 0; 16737c478bd9Sstevel@tonic-gate break; 1674*6fec3791Sjesseb case 'r': 1675*6fec3791Sjesseb rarg = optarg; 1676*6fec3791Sjesseb r = atoi(rarg); 1677*6fec3791Sjesseb if ((r != RAID_STRIPE) && (r != RAID_MIRROR)) 1678*6fec3791Sjesseb usage(progname); 1679*6fec3791Sjesseb r_flag = 1; 1680*6fec3791Sjesseb break; 16817c478bd9Sstevel@tonic-gate case 'd': 16827c478bd9Sstevel@tonic-gate darg = optarg; 16837c478bd9Sstevel@tonic-gate d_flag = 1; 16847c478bd9Sstevel@tonic-gate findex = DO_HW_RAID_DELETE; 16857c478bd9Sstevel@tonic-gate no_flags = 0; 16867c478bd9Sstevel@tonic-gate break; 16877c478bd9Sstevel@tonic-gate case 'l': 16887c478bd9Sstevel@tonic-gate findex = DO_HW_RAID_INFO; 16897c478bd9Sstevel@tonic-gate l_flag = 1; 16907c478bd9Sstevel@tonic-gate no_flags = 0; 16917c478bd9Sstevel@tonic-gate break; 16927c478bd9Sstevel@tonic-gate case 'F': 16937c478bd9Sstevel@tonic-gate findex = DO_HW_RAID_FLASH; 16947c478bd9Sstevel@tonic-gate farg = optarg; 16957c478bd9Sstevel@tonic-gate F_flag = 1; 16967c478bd9Sstevel@tonic-gate no_flags = 0; 16977c478bd9Sstevel@tonic-gate break; 16987c478bd9Sstevel@tonic-gate case 'f': 16997c478bd9Sstevel@tonic-gate f_flag = 1; 17007c478bd9Sstevel@tonic-gate no_flags = 0; 17017c478bd9Sstevel@tonic-gate break; 1702*6fec3791Sjesseb case '?': 1703*6fec3791Sjesseb default: 17047c478bd9Sstevel@tonic-gate usage(progname); 17057c478bd9Sstevel@tonic-gate } 17067c478bd9Sstevel@tonic-gate } 17077c478bd9Sstevel@tonic-gate 17087c478bd9Sstevel@tonic-gate if (no_flags && argc > 1) 17097c478bd9Sstevel@tonic-gate usage(progname); 17107c478bd9Sstevel@tonic-gate 17117c478bd9Sstevel@tonic-gate /* compatibility rules */ 17127c478bd9Sstevel@tonic-gate if (c_flag && d_flag) 17137c478bd9Sstevel@tonic-gate usage(progname); 1714*6fec3791Sjesseb if (l_flag && (d_flag || c_flag || f_flag || F_flag || r_flag)) 17157c478bd9Sstevel@tonic-gate usage(progname); 1716*6fec3791Sjesseb if (F_flag && (d_flag || c_flag || l_flag || r_flag)) 17177c478bd9Sstevel@tonic-gate usage(progname); 17187c478bd9Sstevel@tonic-gate 17197c478bd9Sstevel@tonic-gate switch (findex) { 17207c478bd9Sstevel@tonic-gate case DO_HW_RAID_INFO: 17217c478bd9Sstevel@tonic-gate if (l_flag) { 17227c478bd9Sstevel@tonic-gate /* 17237c478bd9Sstevel@tonic-gate * "raidctl" makes argc == 1 17247c478bd9Sstevel@tonic-gate * "-l" makes argc == 2 17257c478bd9Sstevel@tonic-gate */ 17267c478bd9Sstevel@tonic-gate ctrl_nums = argc - 2; 17277c478bd9Sstevel@tonic-gate if (ctrl_nums != 0) { 17287c478bd9Sstevel@tonic-gate info_ctrl = (int **) 17297c478bd9Sstevel@tonic-gate malloc(ctrl_nums * sizeof (int)); 17307c478bd9Sstevel@tonic-gate if (info_ctrl == NULL) 17317c478bd9Sstevel@tonic-gate return (FAILURE); 17327c478bd9Sstevel@tonic-gate } 17337c478bd9Sstevel@tonic-gate for (i = 0; i < ctrl_nums; i++) { 17347c478bd9Sstevel@tonic-gate char *tmp = argv[i + 2]; 17357c478bd9Sstevel@tonic-gate 17367c478bd9Sstevel@tonic-gate info_ctrl[i] = (int *)malloc(2 * sizeof (int)); 17377c478bd9Sstevel@tonic-gate if (info_ctrl[i] == NULL) { 17387c478bd9Sstevel@tonic-gate free(info_ctrl); 17397c478bd9Sstevel@tonic-gate return (FAILURE); 17407c478bd9Sstevel@tonic-gate } 17417c478bd9Sstevel@tonic-gate if (fully_numeric(tmp)) { 17427c478bd9Sstevel@tonic-gate (void) sscanf(tmp, "%d", 17437c478bd9Sstevel@tonic-gate &info_ctrl[i][INFO_CTRL]); 17447c478bd9Sstevel@tonic-gate info_ctrl[i][INFO_STATUS] = 17457c478bd9Sstevel@tonic-gate RAID_INVALID_CTRL; 17467c478bd9Sstevel@tonic-gate } else { 17477c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 17487c478bd9Sstevel@tonic-gate gettext("Invalid controller '%s'\n"), 17497c478bd9Sstevel@tonic-gate tmp); 17507c478bd9Sstevel@tonic-gate info_ctrl[i][INFO_STATUS] = 17517c478bd9Sstevel@tonic-gate RAID_DONT_USE; 17527c478bd9Sstevel@tonic-gate } 17537c478bd9Sstevel@tonic-gate } 17547c478bd9Sstevel@tonic-gate } else if (argc > 1) { 17557c478bd9Sstevel@tonic-gate usage(progname); 17567c478bd9Sstevel@tonic-gate } 17577c478bd9Sstevel@tonic-gate 17587c478bd9Sstevel@tonic-gate do_info(); 17597c478bd9Sstevel@tonic-gate break; 17607c478bd9Sstevel@tonic-gate case DO_HW_RAID_CREATE: 17617c478bd9Sstevel@tonic-gate for (i = 0; i < N_DISKS; i++) { 1762*6fec3791Sjesseb int p = 2 + (r_flag * 2) + f_flag + i; 1763*6fec3791Sjesseb 1764*6fec3791Sjesseb if (p == argc) 1765*6fec3791Sjesseb break; 1766*6fec3791Sjesseb 1767*6fec3791Sjesseb disks[i] = argv[p]; 1768*6fec3791Sjesseb 17697c478bd9Sstevel@tonic-gate if (!canonical_name(disks[i])) 17707c478bd9Sstevel@tonic-gate usage(progname); 1771*6fec3791Sjesseb 1772*6fec3791Sjesseb /* no more than 2 disks for raid level 1 */ 1773*6fec3791Sjesseb if ((r == RAID_MIRROR) && (i > 1)) 1774*6fec3791Sjesseb usage(progname); 17757c478bd9Sstevel@tonic-gate } 1776*6fec3791Sjesseb 1777*6fec3791Sjesseb rv = do_create(disks, r, f_flag); 17787c478bd9Sstevel@tonic-gate break; 17797c478bd9Sstevel@tonic-gate case DO_HW_RAID_DELETE: 17807c478bd9Sstevel@tonic-gate if (!canonical_name(darg)) 17817c478bd9Sstevel@tonic-gate usage(progname); 17827c478bd9Sstevel@tonic-gate 1783*6fec3791Sjesseb rv = do_delete(darg, f_flag); 17847c478bd9Sstevel@tonic-gate break; 17857c478bd9Sstevel@tonic-gate case DO_HW_RAID_FLASH: 17867c478bd9Sstevel@tonic-gate ctrl_nums = argc - f_flag - 3; 17877c478bd9Sstevel@tonic-gate if (ctrl_nums == 0) 17887c478bd9Sstevel@tonic-gate usage(progname); 17897c478bd9Sstevel@tonic-gate 17907c478bd9Sstevel@tonic-gate current_dir = getcwd(NULL, MAXPATHLEN); 17917c478bd9Sstevel@tonic-gate 17927c478bd9Sstevel@tonic-gate for (i = 0; i < ctrl_nums; i++) { 17937c478bd9Sstevel@tonic-gate char *tmp = argv[i + 3 + f_flag]; 17947c478bd9Sstevel@tonic-gate (void) chdir(current_dir); 17957c478bd9Sstevel@tonic-gate if (fully_numeric(tmp)) { 17967c478bd9Sstevel@tonic-gate (void) sscanf(tmp, "%d", &controller); 17977c478bd9Sstevel@tonic-gate rv = do_flash(controller, farg, f_flag); 17987c478bd9Sstevel@tonic-gate if (rv == FAILURE) 17997c478bd9Sstevel@tonic-gate break; 18007c478bd9Sstevel@tonic-gate } else { 18017c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 18027c478bd9Sstevel@tonic-gate gettext("Invalid controller '%s'\n"), 18037c478bd9Sstevel@tonic-gate tmp); 18047c478bd9Sstevel@tonic-gate } 18057c478bd9Sstevel@tonic-gate } 18067c478bd9Sstevel@tonic-gate free(current_dir); 18077c478bd9Sstevel@tonic-gate break; 18087c478bd9Sstevel@tonic-gate default: 18097c478bd9Sstevel@tonic-gate usage(progname); 18107c478bd9Sstevel@tonic-gate } 18117c478bd9Sstevel@tonic-gate return (rv); 18127c478bd9Sstevel@tonic-gate } 1813