raidctl.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* 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.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* 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 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <langinfo.h>
#include <libintl.h>
#include <limits.h>
#include <locale.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <config_admin.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,
/* For no-mixup indexing of info_ctrl */
#define INFO_CTRL 0
#define INFO_STATUS 1
/* Length of conrollers list */
static int ctrl_nums = 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
/*
* Error return codes
*/
#define SUCCESS 0
#define INVALID_ARG 1
#define FAILURE 2
/*
* FW Update Stuff
*/
/* signature and initial offset for PCI expansion rom images */
/* offsets in PCI data structure header */
/* 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 */
/* Key to search for when looking for fcode version */
#define FCODE_VERS_KEY1 0x12
#define FCODE_VERS_KEY2 0x7
#define BIOS_STR "LSI1030 SCSI Host Adapter BIOS Driver: "
/* get a word from a buffer (works with non-word aligned offsets) */
/* Number of disks currently supported */
#define N_DISKS 2
/*
* Function and strings to properly localize our prompt.
* english.
*/
static int yes(int c);
typedef struct raidlist {
int controller;
char devctl[MAXPATHLEN];
} raidlist_t;
static raidlist_t *raids;
static void
{
gettext("usage: %s [-f] -F image_file controller \n"),
exit(1);
}
/* Make errno message more "user friendly" */
static void
raidctl_error(char *str)
{
switch (errno) {
case EIO:
case EFAULT:
gettext("Error: Device inaccessible.\n"));
break;
case ENOTTY:
"Device does not support requested action.\n"));
break;
default:
}
}
static int
{
return (1);
return (0);
}
static int
get_ctrl_devctl(char *ctrl, char *b)
{
char devctl_buf[MAXPATHLEN];
char *colon;
return (1);
*colon = 0;
return (0);
}
static int
get_devctl(char *disk, char *b)
{
char buf1[MAXPATHLEN] = {0};
char devctl_buf[MAXPATHLEN];
char *slash;
char devname[32];
return (1);
return (1);
*slash = 0;
*slash = 0;
return (0);
}
static int
already_there(int controller)
{
return (1);
}
return (0);
}
/*
* Display those controllers where RAID volumes were not found
*/
static void
{
int i, space = 0;
return;
for (i = 0; i < ctrl_nums; i++) {
/* Status of '0' means RAID exists at that controller */
continue;
(void) printf("\n");
space = 1;
}
/* switch statement used to enable gettext()'ing of text */
switch (info_ctrl[i][INFO_STATUS]) {
case RAID_INVALID_CTRL:
break;
case RAID_NOT_SUPPORTED:
"on controller '%d'\n"),
break;
default:
}
}
}
static void
{
char buf[MAXPATHLEN] = {0};
char buf1[MAXPATHLEN] = {0};
int fd;
int i;
return;
return;
/*
* If "-l" was specified, then only look at those controllers
* listed as part of the command line input.
*/
int found = 0;
for (i = 0; i < ctrl_nums; i++) {
continue;
found = 1;
break;
}
}
if (!found)
return;
}
if (fd == -1) {
return;
}
/* Fail silently */
return;
}
return;
}
} else {
if (already_there(controller)) {
return;
}
/* Seek to the end */
}
}
static void
{
(void) printf("\n");
(void) printf("\n");
(void) printf("------------------------------------------------------");
(void) printf("\n");
}
static void
{
int i;
/* Get RAID Volume */
/* Get RAID Info */
} else {
}
/* Get RAID Disks */
/* Get RAID Disk's Status */
} else {
}
} else {
}
}
}
static void
{
}
}
static void
{
}
}
static void
{
char buf[MAXPATHLEN];
int c;
int i, j;
/*
* 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++) {
continue;
if (first_one) {
first_one = 0;
} else {
info_ctrl[j][INFO_STATUS] =
}
}
}
}
return;
}
continue;
continue;
add_raid_to_raidlist(buf, c);
}
}
/*
* 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;
do_search();
for (i = 0; i < ctrl_nums; i++)
} else {
}
return;
}
print_header();
if (info_ctrl) {
for (i = 0; i < ctrl_nums; i++)
}
}
static int
disk_there(int c, int t)
{
char disk[100];
int fd;
if (fd == -1) {
return (-1);
}
return (0);
}
static int
get_controller(char *dev)
{
int c;
do_search();
c = curr->controller;
break;
}
}
return (c);
}
static int
disk_mounted(char *d)
{
return (1);
return (0);
}
static int
{
int i, fd;
for (i = 0; i < N_DISKS; i++) {
if (fd == -1) {
return (FAILURE);
}
return (FAILURE);
}
}
/* lbsize must be the same on both disks */
*errcond = 2;
return (INVALID_ARG);
}
/* secondary size is not greater than or equal to primary size */
*errcond = 1;
return (INVALID_ARG);
}
/* Secondary disk is big enough */
*cap = disk_capacity[0];
return (SUCCESS);
}
static int
{
char *ap_id;
int count = 0;
return (FAILURE);
/*
* 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 {
count++;
return (rv);
}
static int
do_create(char **d)
{
char channel1[MAXPATHLEN];
char channel2[MAXPATHLEN];
int c[N_DISKS];
int t[N_DISKS];
char *tmp;
int i;
for (i = 0; i < N_DISKS; i++) {
t[i] < 0) {
gettext("Invalid disk format.\n"));
return (INVALID_ARG);
}
}
/* Must be on same controller */
if (c[0] != c[1]) {
gettext("Disks must be on the same controller.\n"));
return (INVALID_ARG);
}
/* primary disk target must be lower than secondary disk target */
if (t[0] > t[1]) {
"must be less than secondary target ID.\n"));
return (INVALID_ARG);
}
/* disks must not be the same */
if (t[0] == t[1]) {
return (INVALID_ARG);
}
/* disks must be present */
if (disk_there(c[0], t[0])) {
c[0], t[0]);
disk_here = 0;
}
c[0], t[1]);
disk_here = 0;
}
if (!disk_here) {
return (INVALID_ARG);
}
/* secondary disk's size must be greater or equal to primary disk's */
case FAILURE:
return (FAILURE);
case INVALID_ARG:
switch (errcond) {
case 1:
"primary disk is larger than secondary disk.\n"));
break;
case 2:
"disk block sizes differ.\n"));
}
return (INVALID_ARG);
}
/* secondary disk must not be mounted */
if (disk_mounted(d[1])) {
"secondary disk \"%s\" is mounted.\n"), d[1]);
return (INVALID_ARG);
}
/* Only one RAID can exist per controller */
return (FAILURE);
if (fd == -1) {
return (FAILURE);
}
raidctl_error("RAID_GETCONFIG");
goto fail1;
}
goto fail1;
}
/*
* Make sure there isn't a raid created on this controller's
* other channel
*/
tmp[0] = 0;
/*
* 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.
*/
channel2);
} else {
channel2);
}
if (fd2 == -1) {
goto no_secondary_channel;
goto fail1;
}
goto fail2;
}
int cx;
goto fail2;
}
/* No other RAID volumes exist, so we may continue */
/* Make secondary disk inaccessible to the system */
perror("config_change_state");
goto fail2;
}
raidctl_error("RAID_CREATE");
goto fail2;
}
return (SUCCESS);
return (FAILURE);
}
static int
do_delete(char *d)
{
char disk1[MAXPATHLEN];
char buf[MAXPATHLEN];
int fd;
int target;
int ctrl;
uint8_t t;
return (INVALID_ARG);
}
return (FAILURE);
}
if (fd == -1) {
return (FAILURE);
}
raidctl_error("RAID_GETCONFIG");
goto fail;
}
"controller '%d'\n"), ctrl);
goto fail;
}
gettext("RAID volume 'c%dt%dd0' does not exist\n"),
ctrl, t);
goto fail;
}
perror("RAID_DELETE");
goto fail;
}
/*
* Make secondary disk accessible to the system.
* Ignore return value from do_config_change_state.
*/
return (SUCCESS);
fail:
return (FAILURE);
}
static int
{
int x, y, size;
int image_length = 0;
int no_of_images = 0;
uint16_t image_units = 0;
/*
* Single Image - Open firmware image
*/
no_of_images = 1;
goto process_image;
}
/*
*/
return (1);
}
/*
* Seek to 2nd Image
*/
rombuf_1 += image_length;
/*
* Combined Image - Second Image - Open Firmware image
*/
return (1);
}
no_of_images = 2;
/*
* This should be the last image
*/
if (*rombuf_1 != LAST_IMAGE) {
return (1);
}
/*
* 0x12 and 0x7 indicate the start of the fcode version string
*/
for (x = 0; x < (nbytes - 8); x++) {
if ((rombuf[x] == FCODE_VERS_KEY1) &&
found_1 = 1;
break;
}
}
/*
* Store the version string if we have found the beginning of it
*/
if (found_1) {
while (x > 0) {
if (rombuf[--x] == FCODE_VERS_KEY1) {
x++;
}
break;
}
}
if (x > 0) {
for (y = 0; y < rombuf[x]; y++) {
}
(*fcodeversion)[y] = '\0';
} else {
found_1 = 0;
}
}
/*
* "@(#)" 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++) {
found_2 = 1;
break;
}
}
if (found_2) {
x += 4;
(*fcodeversion)[y] = '\n';
y++;
(*fcodeversion)[y] = '\0';
size);
}
}
}
static void
{
rombuf[FW_ROM_OFFSET_VERSION + 0]);
}
static int
{
char *imageversion = NULL;
char *fwversion;
/* imageversion is malloc(2)'ed in getfcodever() */
*imagetype = FCODE_IMAGE;
} else {
}
if (*imagetype != UNKNOWN_IMAGE) {
} else {
if (imageversion != NULL) {
}
return (-1);
}
if (chksum != 0) {
gettext("The ROM checksum appears bad "
"(%d)\n"), chksum);
return (-1);
}
"MPT firmware version %s "
"(w/Integrated Mirroring)\n"),
} else {
"MPT firmware ""version %s\n"),
}
} else {
#ifdef DEBUG
#else
#endif
return (-1);
}
return (0);
}
static int
{
int fd = 0;
if (fd == -1) {
return (-1);
}
} else {
}
raidctl_error("RAID_UPDATEFW");
return (-1);
}
return (0);
}
static int
{
int fd, i;
return (-1);
}
perror("fstat");
gettext("Error getting stats on file\n"));
return (-1);
}
#ifdef DEBUG
#endif
perror("size check");
return (-1);
}
for (i = 0; i < *nbytes; i++)
return (0);
}
static int
yes(int c)
{
int i, b;
for (i = 0; ; i++) {
b = getchar();
ans[i] = 0;
break;
}
if (i < SCHAR_MAX)
ans[i] = b;
}
if (i >= SCHAR_MAX) {
i = SCHAR_MAX;
}
return (1);
} else {
"Controller %d not flashed.\n\n"), ans, c);
return (0);
}
}
static int
{
char devctl[MAXPATHLEN] = {0};
char buf[MAXPATHLEN] = {0};
int rv = 0;
int imagetype;
char cwd[MAXPATHLEN];
/*
* Read fw file
*/
if (rv != 0) {
return (FAILURE);
}
gettext("Invalid controller '%d'\n"), c);
return (INVALID_ARG);
}
/* Check File */
if (rv != 0) {
return (FAILURE);
}
/* Confirm */
if (!force) {
if (!yes(c)) {
return (SUCCESS);
}
}
/* Do Flash */
"Controller %d.\n\n"), c);
return (INVALID_ARG);
}
return (SUCCESS);
}
static int
fully_numeric(char *str)
{
int i;
for (i = 0; i < size; i++) {
continue;
return (0);
}
return (1);
}
/*
* Useful parsing macros
*/
#define must_be(s, c) if (*s++ != c) return (0)
#define skip_digits(s) while (isdigit(*s)) s++
/*
* Return true if a name is in the internal canonical form
*/
static int
canonical_name(char *name)
{
if (*name == 't') {
name++;
}
return (*name == 0);
}
int
{
int i, c;
int findex = DO_HW_RAID_INFO;
int controller;
char *darg;
char *farg;
char *progname;
int l_flag = 0;
int c_flag = 0;
int d_flag = 0;
int f_flag = 0;
int F_flag = 0;
int no_flags = 1;
char *current_dir;
(void) textdomain(TEXT_DOMAIN);
if (geteuid() != 0) {
exit(1);
}
else
progname++;
switch (c) {
case 'c':
}
c_flag = 1;
no_flags = 0;
break;
case 'd':
d_flag = 1;
no_flags = 0;
break;
case 'l':
l_flag = 1;
no_flags = 0;
break;
case 'F':
F_flag = 1;
no_flags = 0;
break;
case 'f':
f_flag = 1;
no_flags = 0;
break;
case '?': default:
}
}
/* compatibility rules */
switch (findex) {
case DO_HW_RAID_INFO:
if (l_flag) {
/*
* "raidctl" makes argc == 1
* "-l" makes argc == 2
*/
if (ctrl_nums != 0) {
info_ctrl = (int **)
return (FAILURE);
}
for (i = 0; i < ctrl_nums; i++) {
return (FAILURE);
}
if (fully_numeric(tmp)) {
info_ctrl[i][INFO_STATUS] =
} else {
gettext("Invalid controller '%s'\n"),
tmp);
info_ctrl[i][INFO_STATUS] =
}
}
} else if (argc > 1) {
}
do_info();
break;
case DO_HW_RAID_CREATE:
for (i = 0; i < N_DISKS; i++) {
if (!canonical_name(disks[i]))
}
break;
case DO_HW_RAID_DELETE:
if (!canonical_name(darg))
break;
case DO_HW_RAID_FLASH:
/*
* "raidctl" makes argc == 1
* "-F" makes argc == 2
* "filename" makes argc == 3
* "-f" makes argc == 4 if added.
*/
if (ctrl_nums == 0)
for (i = 0; i < ctrl_nums; i++) {
(void) chdir(current_dir);
if (fully_numeric(tmp)) {
break;
} else {
gettext("Invalid controller '%s'\n"),
tmp);
}
}
break;
default:
}
return (rv);
}