iprutils/iprconfig.c
brking 4c5eeb2ffc - Removed mention of primary/secondary adapters in some error
screens since multi-initiator RAID is not supported and the
  messages will just cause confusion.
- iprconfig: During disk hotplug, wait for sd devices to show
  up. Fixes errors getting logged by iprconfig during hotplug.
- iprconfig: Fix cancel path on concurrent add/remove of disks
- Don't display current bus width and speed for SAS disks
- Fix scoping bug caught by gcc 4.0.
- Stop iprupdate from continually logging errors for adapters with
  backlevel adapter firmware.
2005-03-25 22:21:00 +00:00

9082 lines
225 KiB
C

/**
* IBM IPR adapter configuration utility
*
* (C) Copyright 2000, 2004
* International Business Machines Corporation and others.
* All Rights Reserved. This program and the accompanying
* materials are made available under the terms of the
* Common Public License v1.0 which accompanies this distribution.
**/
#ifndef iprlib_h
#include "iprlib.h"
#endif
#include <nl_types.h>
#include <locale.h>
#include <term.h>
#include <ncurses.h>
#include <form.h>
#include <panel.h>
#include <menu.h>
#include <string.h>
#include "iprconfig.h"
#include <sys/ioctl.h>
#include <scsi/sg.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
char *tool_name = "iprconfig";
struct devs_to_init_t {
struct ipr_dev *dev;
struct ipr_ioa *ioa;
int new_block_size;
#define IPR_JBOD_BLOCK_SIZE 512
int cmplt;
int do_init;
int dev_type;
#define IPR_AF_DASD_DEVICE 1
#define IPR_JBOD_DASD_DEVICE 2
struct devs_to_init_t *next;
};
#define for_each_dev_to_init(dev) for (dev = dev_init_head; dev; dev = dev->next)
struct prot_level {
struct ipr_array_cap_entry *array_cap_entry;
u8 is_valid:1;
u8 reserved:7;
};
struct array_cmd_data {
u8 array_id;
u8 prot_level;
u16 stripe_size;
int qdepth;
u32 do_cmd;
struct ipr_ioa *ioa;
struct ipr_dev *dev;
struct ipr_array_query_data *qac;
struct array_cmd_data *next;
};
/* not needed once menus incorporated into screen_driver */
struct window_l {
WINDOW *win;
struct window_l *next;
};
struct panel_l {
PANEL *panel;
struct panel_l *next;
};
static struct devs_to_init_t *dev_init_head = NULL;
static struct devs_to_init_t *dev_init_tail = NULL;
static struct array_cmd_data *raid_cmd_head = NULL;
static struct array_cmd_data *raid_cmd_tail = NULL;
static i_container *i_con_head = NULL; /* FIXME requires multiple heads */
static char log_root_dir[200];
static char editor[200];
FILE *errpath;
static int toggle_field;
nl_catd catd;
#define for_each_raid_cmd(cmd) for (cmd = raid_cmd_head; cmd; cmd = cmd->next)
#define DEFAULT_LOG_DIR "/var/log"
#define DEFAULT_EDITOR "vi -R"
#define FAILSAFE_EDITOR "vi -R -"
#define IS_CANCEL_KEY(c) ((c == KEY_F(12)) || (c == 'q') || (c == 'Q'))
#define CANCEL_KEY_LABEL "q=Cancel "
#define IS_EXIT_KEY(c) ((c == KEY_F(3)) || (c == 'e') || (c == 'E'))
#define EXIT_KEY_LABEL "e=Exit "
#define CONFIRM_KEY_LABEL "c=Confirm "
#define CONFIRM_REC_KEY_LABEL "s=Confirm Reclaim "
#define ENTER_KEY '\n'
#define IS_ENTER_KEY(c) ((c == KEY_ENTER) || (c == ENTER_KEY))
#define IS_REFRESH_KEY(c) ((c == 'r') || (c == 'R'))
#define REFRESH_KEY_LABEL "r=Refresh "
#define IS_TOGGLE_KEY(c) ((c == 't') || (c == 'T'))
#define TOGGLE_KEY_LABEL "t=Toggle "
#define IS_PGDN_KEY(c) ((c == KEY_NPAGE) || (c == 'f') || (c == 'F'))
#define PAGE_DOWN_KEY_LABEL "f=PageDn "
#define IS_PGUP_KEY(c) ((c == KEY_PPAGE) || (c == 'b') || (c == 'B'))
#define PAGE_UP_KEY_LABEL "b=PageUp "
#define IS_5250_CHAR(c) (c == 0xa)
#define is_digit(ch) (((ch)>=(unsigned)'0'&&(ch)<=(unsigned)'9')?1:0)
struct special_status {
int index;
int num;
char *str;
} s_status;
char *print_device(struct ipr_dev *, char *, char *, struct ipr_ioa *, int);
int display_menu(ITEM **, int, int, int **);
#define print_dev(i, dev, buf, fmt, ioa, type) \
for (i = 0; i < 2; i++) \
(buf)[i] = print_device(dev, (buf)[i], fmt, ioa, type);
/* not needed after screen_driver can do menus */
static void flush_stdscr()
{
nodelay(stdscr, TRUE);
while(getch() != ERR) {}
nodelay(stdscr, FALSE);
}
static i_container *free_i_con(i_container *i_con)
{
i_container *temp_i_con;
i_con = i_con_head;
if (i_con == NULL)
return NULL;
do {
temp_i_con = i_con->next_item;
free(i_con);
i_con = temp_i_con;
} while (i_con);
i_con_head = NULL;
return NULL;
}
static i_container *add_i_con(i_container *i_con, char *f, void *d)
{
i_container *new_i_con;
new_i_con = malloc(sizeof(i_container));
new_i_con->next_item = NULL;
/* used to hold data entered into user-entry fields */
strncpy(new_i_con->field_data, f, MAX_FIELD_SIZE+1);
new_i_con->field_data[strlen(f)+1] = '\0';
/* a pointer to the device information represented by the i_con */
new_i_con->data = d;
if (i_con)
i_con->next_item = new_i_con;
else
i_con_head = new_i_con;
return new_i_con;
}
int exit_confirmed(i_container *i_con)
{
exit_func();
exit(0);
return 0;
}
/*not needed after screen_driver can do menus */
static void free_screen(struct panel_l *panel, struct window_l *win,
FIELD **fields)
{
struct panel_l *cur_panel;
struct window_l *cur_win;
int i;
cur_panel = panel;
while(cur_panel) {
panel = panel->next;
del_panel(cur_panel->panel);
free(cur_panel);
cur_panel = panel;
}
cur_win = win;
while(cur_win) {
win = win->next;
delwin(cur_win->win);
free(cur_win);
cur_win = win;
}
if (fields) {
for (i = 0; fields[i] != NULL; i++)
free_field(fields[i]);
}
}
static void add_raid_cmd_tail(struct ipr_ioa *ioa, struct ipr_dev *dev, u8 array_id)
{
if (raid_cmd_head) {
raid_cmd_tail->next = malloc(sizeof(struct array_cmd_data));
raid_cmd_tail = raid_cmd_tail->next;
} else {
raid_cmd_head = raid_cmd_tail = malloc(sizeof(struct array_cmd_data));
}
memset(raid_cmd_tail, 0, sizeof(struct array_cmd_data));
raid_cmd_tail->array_id = array_id;
raid_cmd_tail->ioa = ioa;
raid_cmd_tail->dev = dev;
}
static void free_devs_to_init()
{
struct devs_to_init_t *dev = dev_init_head;
while (dev) {
dev = dev->next;
free(dev_init_head);
dev_init_head = dev;
}
}
static char *strip_trailing_whitespace(char *p_str)
{
int len;
char *p_tmp;
len = strlen(p_str);
if (len == 0)
return p_str;
p_tmp = p_str + len - 1;
while(*p_tmp == ' ' || *p_tmp == '\n')
p_tmp--;
p_tmp++;
*p_tmp = '\0';
return p_str;
}
static void tool_exit_func()
{
clearenv();
clear();
refresh();
endwin();
}
static void cmdline_exit_func()
{
endwin();
}
static char *ipr_list_opts(char *body, char *key, char *list_str)
{
char *string_buf = _("Select one of the following");
int start_len = 0;
if (!body) {
body = realloc(body, strlen(string_buf) + 8);
sprintf(body, "\n%s:\n\n", string_buf);
}
start_len = strlen(body);
body = realloc(body, start_len + strlen(key) + strlen(_(list_str)) + 16);
sprintf(body + start_len, " %s. %s\n", key, _(list_str));
return body;
}
static char *ipr_end_list(char *body)
{
int start_len = 0;
char *string_buf = _("Selection");
start_len = strlen(body);
body = realloc(body, start_len + strlen(string_buf) + 16);
sprintf(body + start_len, "\n\n%s: %%1", string_buf);
return body;
}
static struct screen_output *screen_driver(s_node *screen, int header_lines, i_container *i_con)
{
WINDOW *w_pad = NULL,*w_page_header = NULL; /* windows to hold text */
FIELD **fields = NULL; /* field list for forms */
FORM *form = NULL; /* form for input fields */
int rc = 0; /* the status of the screen */
char *status; /* displays screen operations */
char buffer[100]; /* needed for special status strings */
bool invalid = false; /* invalid status display */
bool ground_cursor=false;
int stdscr_max_y,stdscr_max_x;
int w_pad_max_y=0,w_pad_max_x=0; /* limits of the windows */
int pad_l=0,pad_scr_r,pad_t=0,viewable_body_lines;
int title_lines=2,footer_lines=2; /* position of the pad */
int center,len=0,ch;
int i=0,j,k,row=0,col=0,bt_len=0; /* text positioning */
int field_width,num_fields=0; /* form positioning */
int h,w,t,l,o,b; /* form querying */
int active_field = 0; /* return to same active field after a quit */
bool pages = false,is_bottom = false; /* control page up/down in multi-page screens */
bool form_adjust = false; /* correct cursor position in multi-page screens */
bool refresh_stdscr = true;
bool x_offscr,y_offscr; /* scrolling windows */
char *input;
struct screen_output *s_out;
struct screen_opts *temp; /* reference to another screen */
char *title,*body,*body_text; /* screen text */
i_container *temp_i_con;
int num_i_cons = 0;
int x, y;
int f_flags;
s_out = malloc(sizeof(struct screen_output)); /* passes an i_con and an rc value back to the function */
/* create text strings */
title = _(screen->title);
body = screen->body;
f_flags = screen->f_flags;
if (f_flags & ENTER_FLAG)
footer_lines += 3;
else if (f_flags & FWD_FLAG)
footer_lines++;
if (f_flags & TOGGLE_FLAG)
active_field = toggle_field;
bt_len = strlen(body);
body_text = calloc(bt_len + 1, sizeof(char));
/* determine max size needed and find where to put form fields and device input in the text and add them
* '%' marks a field. The number after '%' represents the field's width
*/
i=0;
temp_i_con = i_con_head;
while(body[i] != '\0') {
if (body[i] == '\n') {
row++;
col = -1;
body_text[len] = body[i];
len++;
} else if ((body[i] == '%') && is_digit(body[i+1])) {
fields = realloc(fields,sizeof(FIELD **) * (num_fields + 1));
i++;
field_width = 0;
sscanf(&(body[i]),"%d",&field_width);
fields[num_fields] = new_field(1,field_width,row,col,0,0);
if (field_width >= 30)
field_opts_off(fields[num_fields],O_AUTOSKIP);
if (field_width > 9)
/* skip second digit of field index */
i++;
if ((temp_i_con) && (temp_i_con->field_data[0]) && (f_flags & MENU_FLAG)) {
set_field_buffer(fields[num_fields], 0, temp_i_con->field_data);
input = field_buffer(fields[num_fields],0);
temp_i_con = temp_i_con->next_item;
num_i_cons++;
}
set_field_userptr(fields[num_fields],NULL);
num_fields++;
col += field_width-1;
bt_len += field_width;
body_text = realloc(body_text,bt_len);
for(k=0;k<field_width;k++)
body_text[len+k] = ' ';
len += field_width;
} else {
body_text[len] = body[i];
len++;
}
col++;
i++;
if (col > w_pad_max_x)
w_pad_max_x = col;
}
body_text[len] = '\0';
w_pad_max_y = row;
w_pad_max_y++; /* some forms may not display correctly if this is not included */
w_pad_max_x++; /* adds a column for return char \n : else, a blank line will appear in the pad */
w_pad = newpad(w_pad_max_y,w_pad_max_x);
keypad(w_pad,TRUE);
if (num_fields) {
fields = realloc(fields,sizeof(FIELD **) * (num_fields + 1));
fields[num_fields] = NULL;
form = new_form(fields);
}
/* make the form appear in the pad; not stdscr */
set_form_win(form,w_pad);
set_form_sub(form,w_pad);
while(1) {
getmaxyx(stdscr,stdscr_max_y,stdscr_max_x);
/* clear all windows before writing new text to them */
clear();
wclear(w_pad);
if(pages)
wclear(w_page_header);
center = stdscr_max_x/2;
len = strlen(title);
/* add the title at the center of stdscr */
mvaddstr(0,(center-len/2)>0?center-len/2:0,title);
/* set the boundaries of the pad based on the size of the screen
and determine whether or not the user is able to scroll */
if ((stdscr_max_y - title_lines - footer_lines + 1) >= w_pad_max_y) {
viewable_body_lines = w_pad_max_y;
pad_t = 0;
y_offscr = false; /*not scrollable*/
pages = false;
for (i = 0; i < num_fields; i++)
field_opts_on(fields[i],O_ACTIVE);
} else {
viewable_body_lines = stdscr_max_y - title_lines - footer_lines - 1;
y_offscr = true; /*scrollable*/
if (f_flags & FWD_FLAG) {
pages = true;
w_page_header = subpad(w_pad,header_lines,w_pad_max_x,0,0);
}
}
if (stdscr_max_x > w_pad_max_x) {
pad_scr_r = w_pad_max_x;
pad_l = 0;
x_offscr = false;
} else {
pad_scr_r = stdscr_max_x;
x_offscr = true;
}
move(stdscr_max_y - footer_lines,0);
if (f_flags & ENTER_FLAG) {
if (num_fields == 0) {
addstr(_("\nPress Enter to Continue\n\n"));
ground_cursor = true;
} else
addstr(_("\nOr leave blank and press Enter to cancel\n\n"));
}
if ((f_flags & FWD_FLAG) && !(f_flags & ENTER_FLAG))
addstr("\n");
if (f_flags & CONFIRM_FLAG)
addstr(CONFIRM_KEY_LABEL);
if (f_flags & EXIT_FLAG)
addstr(EXIT_KEY_LABEL);
if (f_flags & CANCEL_FLAG)
addstr(CANCEL_KEY_LABEL);
if (f_flags & CONFIRM_REC_FLAG)
addstr(CONFIRM_REC_KEY_LABEL);
if (f_flags & REFRESH_FLAG)
addstr(REFRESH_KEY_LABEL);
if (f_flags & TOGGLE_FLAG)
addstr(TOGGLE_KEY_LABEL);
if ((f_flags & FWD_FLAG) && y_offscr) {
addstr(PAGE_DOWN_KEY_LABEL);
addstr(PAGE_UP_KEY_LABEL);
}
post_form(form);
/* add the body of the text to the screen */
if (pages) {
wmove(w_page_header,0,0);
waddstr(w_page_header,body_text);
}
wmove(w_pad,0,0);
waddstr(w_pad,body_text);
if (num_fields) {
set_current_field(form,fields[active_field]);
if (active_field == 0)
form_driver(form,REQ_NEXT_FIELD);
form_driver(form,REQ_PREV_FIELD);
}
refresh_stdscr = true;
for(;;) {
/* add global status if defined */
if (s_status.index) {
rc = s_status.index;
s_status.index = 0;
}
if (invalid) {
status = (char *)screen_status[INVALID_OPTION_STATUS];
invalid = false;
} else if (rc != 0) {
if ((status = strchr(screen_status[rc],'%')) == NULL) {
status = (char *)screen_status[rc];
} else if (status[1] == 'd') {
sprintf(buffer,screen_status[rc],s_status.num);
status = buffer;
} else if (status[1] == 's') {
sprintf(buffer,screen_status[rc],s_status.str);
status = buffer;
}
rc = 0;
} else
status = NULL;
move(stdscr_max_y-1,0);
clrtoeol(); /* clear last line */
mvaddstr(stdscr_max_y-1,0,status);
status = NULL;
if ((f_flags & FWD_FLAG) && y_offscr) {
if (!is_bottom)
mvaddstr(stdscr_max_y-footer_lines,stdscr_max_x-8,_("More..."));
else
mvaddstr(stdscr_max_y-footer_lines,stdscr_max_x-8," ");
for (i=0;i<num_fields;i++) {
if (fields[i] != NULL) {
/* height, width, top, left, offscreen rows, buffer */
field_info(fields[i],&h,&w,&t,&l,&o,&b);
/* turn all offscreen fields off */
if ((t >= (header_lines + pad_t)) &&
(t <= (viewable_body_lines + pad_t))) {
field_opts_on(fields[i],O_ACTIVE);
if (form_adjust) {
if (!(f_flags & TOGGLE_FLAG) || !toggle_field)
set_current_field(form,fields[i]);
form_adjust = false;
}
} else
field_opts_off(fields[i],O_ACTIVE);
}
}
}
if (f_flags & MENU_FLAG) {
for (i=0;i<num_fields;i++) {
field_opts_off(fields[i],O_VISIBLE);
field_opts_on(fields[i],O_VISIBLE);
set_field_fore(fields[i],A_BOLD);
}
}
if ((f_flags & TOGGLE_FLAG) && toggle_field &&
((field_opts(fields[toggle_field]) & O_ACTIVE) != O_ACTIVE)) {
ch = KEY_NPAGE;
} else {
toggle_field = 0;
if (refresh_stdscr) {
touchwin(stdscr);
refresh_stdscr = FALSE;
} else
touchline(stdscr,stdscr_max_y - 1,1);
refresh();
if (pages) {
touchwin(w_page_header);
prefresh(w_page_header, 0, pad_l,
title_lines, 0,
title_lines + header_lines - 1, pad_scr_r - 1);
touchwin(w_pad);
prefresh(w_pad, pad_t + header_lines, pad_l,
title_lines + header_lines, 0,
title_lines + viewable_body_lines, pad_scr_r - 1);
} else {
touchwin(w_pad);
prefresh(w_pad, pad_t, pad_l,
title_lines, 0,
title_lines + viewable_body_lines, pad_scr_r - 1);
}
if (ground_cursor) {
move(stdscr_max_y - 1, stdscr_max_x - 1);
refresh();
}
ch = wgetch(w_pad); /* pause for user input */
}
if (ch == KEY_RESIZE)
break;
if (IS_ENTER_KEY(ch)) {
if (num_fields > 0)
active_field = field_index(current_field(form));
if ((f_flags & ENTER_FLAG) && num_fields == 0) {
rc = (CANCEL_FLAG | rc);
goto leave;
} else if (f_flags & ENTER_FLAG) {
/* cancel if all fields are empty */
form_driver(form,REQ_VALIDATION);
for (i = 0; i < num_fields; i++) {
if (strlen(field_buffer(fields[i],0)) != 0)
/* fields are not empty -> continue */
break;
if (i == (num_fields - 1)) {
/* all fields are empty */
rc = (CANCEL_FLAG | rc);
goto leave;
}
}
}
if (num_fields > 0)
input = field_buffer(fields[active_field],0);
invalid = true;
for (i = 0; i < screen->num_opts; i++) {
temp = &(screen->options[i]);
if ((temp->key == "\n") ||
((num_fields > 0)?(strcasecmp(input,temp->key) == 0):0)) {
invalid = false;
if ((temp->key == "\n") && (num_fields > 0)) {
/* store field data to existing i_con (which should already
contain pointers) */
i_container *temp_i_con = i_con_head;
form_driver(form,REQ_VALIDATION);
for (i = 0; i < num_fields; i++) {
strncpy(temp_i_con->field_data,field_buffer(fields[i],0),MAX_FIELD_SIZE);
temp_i_con = temp_i_con->next_item;
}
}
if (temp->screen_function == NULL)
/* continue with function */
goto leave;
toggle_field = 0;
do
rc = temp->screen_function(i_con_head);
while (rc == REFRESH_SCREEN || rc & REFRESH_FLAG);
/* if screen flags exist on rc and they don't match
the screen's flags, return */
if ((rc & 0xF000) && !(screen->rc_flags & (rc & 0xF000)))
goto leave;
/* strip screen flags from rc */
rc &= ~(EXIT_FLAG | CANCEL_FLAG | REFRESH_FLAG);
if (screen->rc_flags & REFRESH_FLAG) {
s_status.index = rc;
rc = (REFRESH_FLAG | rc);
goto leave;
}
break;
}
}
if (!invalid) {
/*clear fields*/
form_driver(form,REQ_LAST_FIELD);
for (i = 0; i < num_fields; i++) {
form_driver(form,REQ_CLR_FIELD);
form_driver(form,REQ_NEXT_FIELD);
}
break;
}
} else if (IS_EXIT_KEY(ch) && (f_flags & EXIT_FLAG)) {
rc = (EXIT_FLAG | rc);
goto leave;
} else if (IS_CANCEL_KEY(ch) &&
((f_flags & CANCEL_FLAG) || screen == &n_main_menu)) {
rc = (CANCEL_FLAG | rc);
goto leave;
} else if ((IS_REFRESH_KEY(ch) && (f_flags & REFRESH_FLAG)) ||
(ch == KEY_HOME && (f_flags & REFRESH_FLAG))) {
rc = REFRESH_SCREEN;
if (num_fields > 1)
toggle_field = field_index(current_field(form)) + 1;
goto leave;
} else if (IS_TOGGLE_KEY(ch) && (f_flags & TOGGLE_FLAG)) {
rc = TOGGLE_SCREEN;
if (num_fields > 1)
toggle_field = field_index(current_field(form)) + 1;
goto leave;
} else if (IS_PGUP_KEY(ch) && (f_flags & FWD_FLAG) && y_offscr) {
invalid = false;
if (pad_t > 0) {
pad_t -= (viewable_body_lines - header_lines + 1);
rc = PGUP_STATUS;
} else if ((f_flags & FWD_FLAG) && y_offscr)
rc = TOP_STATUS;
else
invalid = true;
if (!invalid) {
if (pad_t < 0)
pad_t = 0;
is_bottom = false;
form_adjust = true;
refresh_stdscr = true;
}
} else if (IS_PGDN_KEY(ch) && (f_flags & FWD_FLAG) && y_offscr) {
invalid = false;
if ((stdscr_max_y - title_lines - footer_lines + 1) < (w_pad_max_y - pad_t)) {
pad_t += (viewable_body_lines - header_lines + 1);
rc = PGDN_STATUS;
if ((stdscr_max_y - title_lines - footer_lines + 1) >= (w_pad_max_y - pad_t))
is_bottom = true;
} else if (is_bottom)
rc = BTM_STATUS;
else
invalid = true;
if (!invalid) {
form_adjust = true;
refresh_stdscr = true;
}
} else if (ch == KEY_RIGHT) {
if (x_offscr && stdscr_max_x+pad_l<w_pad_max_x)
pad_l++;
else
form_driver(form, REQ_NEXT_CHAR);
} else if (ch == KEY_LEFT) {
if (pad_l>0)
pad_l--;
else
form_driver(form, REQ_PREV_CHAR);
} else if (ch == KEY_UP) {
if ((y_offscr || (num_fields == 0)) && !pages) {
if (pad_t > 0) {
pad_t--;
form_adjust = true;
is_bottom = false;
}
} else
form_driver(form, REQ_PREV_FIELD);
} else if (ch == KEY_DOWN) {
if ((y_offscr || (num_fields == 0)) && !pages) {
if (y_offscr && ((stdscr_max_y + pad_t ) <
(w_pad_max_y + title_lines + footer_lines))) {
pad_t++;
form_adjust = true;
}
if (!((stdscr_max_y + pad_t) <
(w_pad_max_y + title_lines + footer_lines)))
is_bottom = true;
}
else
form_driver(form, REQ_NEXT_FIELD);
} else if ((ch == KEY_BACKSPACE) || (ch == 127))
form_driver(form, REQ_DEL_PREV);
else if (ch == KEY_DC)
form_driver(form, REQ_DEL_CHAR);
else if (ch == KEY_IC)
form_driver(form, REQ_INS_MODE);
else if (ch == KEY_EIC)
form_driver(form, REQ_OVL_MODE);
else if (ch == KEY_HOME)
form_driver(form, REQ_BEG_FIELD);
else if (ch == KEY_END)
form_driver(form, REQ_END_FIELD);
else if (ch == '\t')
form_driver(form, REQ_NEXT_FIELD);
else if ((f_flags & MENU_FLAG) || (num_fields == 0)) {
invalid = true;
for (i = 0; i < screen->num_opts; i++) {
temp = &(screen->options[i]);
if ((temp->key) && (ch == temp->key[0])) {
invalid = false;
if (num_fields > 0) {
active_field = field_index(current_field(form));
input = field_buffer(fields[active_field],0);
if (active_field < num_i_cons) {
temp_i_con = i_con_head;
for (j = 0; j < active_field; j++)
temp_i_con = temp_i_con->next_item;
temp_i_con->field_data[0] = '\0';
getyx(w_pad,y,x);
temp_i_con->y = y;
temp_i_con->x = x;
}
toggle_field = field_index(current_field(form)) + 1;
}
if (temp->screen_function == NULL)
goto leave;
do
rc = temp->screen_function(i_con_head);
while (rc == REFRESH_SCREEN || rc & REFRESH_FLAG);
if ((rc & 0xF000) && !(screen->rc_flags & (rc & 0xF000)))
goto leave;
rc &= ~(EXIT_FLAG | CANCEL_FLAG | REFRESH_FLAG);
if (screen->rc_flags & REFRESH_FLAG) {
rc = (REFRESH_FLAG | rc);
goto leave;
}
break;
}
}
} else if (isascii(ch))
form_driver(form, ch);
}
}
leave:
s_out->i_con = i_con_head;
s_out->rc = rc;
free(body_text);
unpost_form(form);
free_form(form);
for (i=0;i < num_fields;i++) {
if (fields[i] != NULL)
free_field(fields[i]);
}
free(fields);
delwin(w_pad);
delwin(w_page_header);
return s_out;
}
static char *status_header(char *buffer, int *num_lines, int type)
{
int cur_len = strlen(buffer);
int header_lines = 0;
char *header[] = {
/* . . . . . */
/*0123456789012345678901234567890123456789012345678901234567890123456789901234567890 */
"OPT Name PCI/SCSI Location Vendor Product ID Status",
"OPT Name PCI/SCSI Location Description Status"};
char *sep[] = {
"--- ------ -------------------------- -------- ---------------- -----------------",
"--- ------ -------------------------- ------------------------- -----------------"};
if (type > 1)
type = 0;
buffer = realloc(buffer, cur_len + strlen(header[type]) + strlen(sep[type]) + 8);
cur_len += sprintf(buffer + cur_len, "%s\n", header[type]);
cur_len += sprintf(buffer + cur_len, "%s\n", sep[type]);
header_lines += 2;
*num_lines = header_lines + *num_lines;
return buffer;
}
/* add_string_to_body adds a string of data to fit in the text window, putting
carraige returns in when necessary
NOTE: This routine expect the language conversion to be done before
entering this routine */
static char *add_string_to_body(char *body, char *new_text, char *line_fill, int *line_num)
{
int body_len = 0;
int new_text_len = strlen(new_text);
int line_fill_len = strlen(line_fill);
int rem_length;
int new_text_offset = 0;
int max_y, max_x;
int len, i;
int num_lines = 0;
getmaxyx(stdscr,max_y,max_x);
if (body)
body_len = strlen(body);
len = body_len;
rem_length = max_x - 1;
for (i=0; i<strlen(new_text); i++) {
if (new_text[i] == '\n')
num_lines++;
}
while (len != 0) {
if (body[len--] == '\n')
break;
rem_length--;
}
while (1) {
if (new_text_len < rem_length) {
/* done, all data fits in current line */
body = realloc(body, body_len + new_text_len + 8);
sprintf(body + body_len, "%s", &new_text[new_text_offset]);
break;
}
len = rem_length;
while (len != 0) {
if (new_text[new_text_offset + len] == ' ') {
/* found a place to \n */
break;
}
len--;
}
if (len == 0)
/* no space to fit any word */
return 0;
/* adjust len to compensate 0 based array */
len += 1;
body = realloc(body, body_len + len + line_fill_len + 8);
strncpy(body + body_len, new_text + new_text_offset, len);
body_len += len;
new_text_offset += len;
new_text_len -= len;
body_len += sprintf(body + body_len, "\n%s", line_fill);
rem_length = max_x - 1 - line_fill_len;
num_lines++;
}
if (line_num)
*line_num = *line_num + num_lines;
return body;
}
/* add_line_to_body adds a single line to the body text of the screen,
it is intented primarily to list items with the desciptor on the
left of the screen and ". . . :" to the data field for the descriptor.
NOTE: This routine expect the language conversion to be done before
entering this routine */
#define DETAILS_DESCR_LEN 40
static char *add_line_to_body(char *body, char *new_text, char *field_data)
{
int cur_len = 0, start_len = 0;
int str_len, field_data_len;
int i;
if (body != NULL)
start_len = cur_len = strlen(body);
str_len = strlen(new_text);
if (!field_data) {
body = realloc(body, cur_len + str_len + 8);
sprintf(body + cur_len, "%s\n", new_text);
} else {
field_data_len = strlen(field_data);
if (str_len < DETAILS_DESCR_LEN) {
body = realloc(body, cur_len + field_data_len + DETAILS_DESCR_LEN + 8);
cur_len += sprintf(body + cur_len, "%s", new_text);
for (i = cur_len; i < DETAILS_DESCR_LEN + start_len; i++) {
if ((cur_len + start_len) % 2)
cur_len += sprintf(body + cur_len, ".");
else
cur_len += sprintf(body + cur_len, " ");
}
sprintf(body + cur_len, " : %s\n", field_data);
} else {
body = realloc(body, cur_len + str_len + field_data_len + 8);
sprintf(body + cur_len, "%s : %s\n",new_text, field_data);
}
}
return body;
}
static char *__body_init_status(char **header, int *num_lines, int type)
{
char *buffer = NULL;
int header_lines = 0;
int j;
char *x_header;
for (j = 0, x_header = _(header[j]); strlen(x_header) != 0; j++, x_header = _(header[j]))
buffer = add_string_to_body(buffer, x_header, "", &header_lines);
buffer = status_header(buffer, &header_lines, type);
if (num_lines != NULL)
*num_lines = header_lines;
return buffer;
}
static void body_init_status(char *buffer[2], char **header, int *num_lines)
{
int z;
for (z = 0; z < 2; z++)
buffer[z] = __body_init_status(header, num_lines, z);
}
static char *__body_init(char *buffer, char **header, int *num_lines)
{
int j;
int header_lines = 0;
char *x_header;
if (num_lines)
header_lines = *num_lines;
for (j = 0, x_header = _(header[j]); strlen(x_header) != 0; j++, x_header = _(header[j])) {
if (j == 0)
buffer = add_string_to_body(buffer, x_header, "", &header_lines);
else
buffer = add_string_to_body(buffer, x_header, " ", &header_lines);
}
if (num_lines)
*num_lines = header_lines;
return buffer;
}
static char *body_init(char **header, int *num_lines)
{
if (num_lines)
*num_lines = 0;
return __body_init(NULL, header, num_lines);
}
static int __complete_screen_driver(s_node *n_screen, char *complete, int allow_exit)
{
int stdscr_max_y,stdscr_max_x,center,len;
int ch;
char *exit = _("Return to menu, current operations will continue.");
char *exit_str;
getmaxyx(stdscr,stdscr_max_y,stdscr_max_x);
clear();
center = stdscr_max_x/2;
len = strlen(n_screen->title);
/* add the title at the center of stdscr */
mvaddstr(0,(center - len/2) > 0 ? center-len/2:0, n_screen->title);
mvaddstr(2,0,n_screen->body);
len = strlen(complete);
mvaddstr(stdscr_max_y/2,(center - len/2) > 0 ? center - len/2:0,
complete);
if (allow_exit) {
exit_str = malloc(strlen(exit) + strlen(EXIT_KEY_LABEL) + 8);
sprintf(exit_str, EXIT_KEY_LABEL"%s",exit);
mvaddstr(stdscr_max_y - 3, 2, exit_str);
nodelay(stdscr, TRUE);
do {
ch = getch();
if (IS_EXIT_KEY(ch)) {
nodelay(stdscr, FALSE);
return EXIT_FLAG;
}
} while (ch != ERR);
nodelay(stdscr, FALSE);
}
move(stdscr_max_y - 1, stdscr_max_x - 1);
refresh();
return 0;
}
static int complete_screen_driver(s_node *n_screen, int percent, int allow_exit)
{
char *complete = _("Complete");
char *percent_comp;
int rc;
percent_comp = malloc(strlen(complete) + 8);
sprintf(percent_comp,"%3d%% %s", percent, complete);
rc = __complete_screen_driver(n_screen, percent_comp, allow_exit);
free(percent_comp);
return rc;
}
static int time_screen_driver(s_node *n_screen, unsigned long seconds, int allow_exit)
{
char *complete = _("Elapsed Time: ");
char *comp_str;
int rc, hours, minutes;
hours = seconds/3600;
seconds -= (hours * 3600);
minutes = seconds/60;
seconds -= (minutes *60);
comp_str = malloc(strlen(complete) + 40);
sprintf(comp_str,"%s%d:%02d:%02ld", complete, hours, minutes, seconds);
rc = __complete_screen_driver(n_screen, comp_str, allow_exit);
free(comp_str);
return rc;
}
static int is_format_allowed(struct ipr_dev *dev)
{
int rc;
struct ipr_cmd_status cmd_status;
struct ipr_cmd_status_record *status_record;
struct sense_data_t sense_data;
if (ipr_is_af_dasd_device(dev)) {
rc = ipr_query_command_status(dev, &cmd_status);
if (rc == 0 && cmd_status.num_records != 0) {
status_record = cmd_status.record;
if ((status_record->status != IPR_CMD_STATUS_SUCCESSFUL) &&
(status_record->status != IPR_CMD_STATUS_FAILED))
return 0;
}
} else {
rc = ipr_test_unit_ready(dev, &sense_data);
if (rc == CHECK_CONDITION && (sense_data.error_code & 0x7F) == 0x70) {
if (sense_data.add_sense_code == 0x31 &&
sense_data.add_sense_code_qual == 0x00)
return 1;
else if ((sense_data.sense_key & 0x0F) == 0x02)
return 0;
}
}
return 1;
}
static void evaluate_device(struct ipr_dev *ipr_dev, struct ipr_ioa *ioa,
int new_block_size)
{
struct scsi_dev_data *scsi_dev_data = ipr_dev->scsi_dev_data;
struct ipr_res_addr res_addr;
struct ipr_dev_record *dev_record;
int device_converted;
int timeout = 60;
u32 res_handle;
if (scsi_dev_data) {
res_handle = scsi_dev_data->handle;
res_addr.bus = scsi_dev_data->channel;
res_addr.target = scsi_dev_data->id;
res_addr.lun = scsi_dev_data->lun;
} else if (ipr_is_af_dasd_device(ipr_dev)) {
dev_record = ipr_dev->dev_rcd;
if (dev_record->no_cfgte_dev)
return;
res_handle = ntohl(dev_record->resource_handle);
res_addr.bus = dev_record->resource_addr.bus;
res_addr.target = dev_record->resource_addr.target;
res_addr.lun = dev_record->resource_addr.lun;
}
/* send evaluate device down */
ipr_evaluate_device(&ioa->ioa, res_handle);
device_converted = 0;
while (!device_converted && timeout) {
/* xxx FIXME how to determine evaluate device completed? */
device_converted = 1;
sleep(1);
timeout--;
}
}
static void verify_device(struct ipr_dev *dev)
{
int rc;
struct ipr_cmd_status cmd_status;
u8 ioctl_buffer[IPR_MODE_SENSE_LENGTH];
struct sense_data_t sense_data;
struct ipr_mode_parm_hdr *mode_parm_hdr;
struct ipr_block_desc *block_desc;
/* Send Test Unit Ready to start device if its a volume set */
if (ipr_is_volume_set(dev)) {
ipr_test_unit_ready(dev, &sense_data);
return;
}
if (ipr_is_af(dev)) {
if ((rc = ipr_query_command_status(dev, &cmd_status)))
return;
if (cmd_status.num_records != 0 &&
cmd_status.record->status == IPR_CMD_STATUS_SUCCESSFUL) {
if (!(rc = ipr_mode_sense(dev, 0, ioctl_buffer))) {
mode_parm_hdr = (struct ipr_mode_parm_hdr *)ioctl_buffer;
if (mode_parm_hdr->block_desc_len > 0) {
block_desc = (struct ipr_block_desc *)(mode_parm_hdr+1);
if (block_desc->block_length[1] == 0x02 &&
block_desc->block_length[2] == 0x00)
evaluate_device(dev, dev->ioa, IPR_JBOD_BLOCK_SIZE);
}
}
}
} else if (dev->scsi_dev_data->type == TYPE_DISK) {
rc = ipr_test_unit_ready(dev, &sense_data);
if (rc != CHECK_CONDITION) {
if (!(rc = ipr_mode_sense(dev, 0x0a, &ioctl_buffer))) {
mode_parm_hdr = (struct ipr_mode_parm_hdr *)ioctl_buffer;
if (mode_parm_hdr->block_desc_len > 0) {
block_desc = (struct ipr_block_desc *)(mode_parm_hdr+1);
if ((!(block_desc->block_length[1] == 0x02) ||
!(block_desc->block_length[2] == 0x00)) &&
dev->ioa->qac_data->num_records != 0) {
enable_af(dev);
evaluate_device(dev, dev->ioa, dev->ioa->af_block_size);
}
}
}
}
}
}
static void processing()
{
int max_y, max_x;
getmaxyx(stdscr,max_y,max_x);
move(max_y-1,0);
printw(_("Processing"));
refresh();
}
int main_menu(i_container *i_con)
{
int rc;
int j;
struct ipr_ioa *ioa;
struct screen_output *s_out;
struct scsi_dev_data *scsi_dev_data;
processing();
check_current_config(false);
for_each_ioa(ioa) {
for (j = 0; j < ioa->num_devices; j++) {
scsi_dev_data = ioa->dev[j].scsi_dev_data;
if (!scsi_dev_data || scsi_dev_data->type == IPR_TYPE_ADAPTER)
continue;
verify_device(&ioa->dev[j]);
}
}
for (j = 0; j < n_main_menu.num_opts; j++) {
n_main_menu.body = ipr_list_opts(n_main_menu.body,
n_main_menu.options[j].key,
n_main_menu.options[j].list_str);
}
n_main_menu.body = ipr_end_list(n_main_menu.body);
s_out = screen_driver(&n_main_menu,0,NULL);
free(n_main_menu.body);
n_main_menu.body = NULL;
rc = s_out->rc;
i_con = s_out->i_con;
i_con = free_i_con(i_con);
free(s_out);
return rc;
}
static int print_standalone_disks(struct ipr_ioa *ioa,
i_container **i_con, char **buffer)
{
struct scsi_dev_data *scsi_dev_data;
int j, k;
int num_lines = 0;
/* print JBOD and non-member AF devices*/
for (j = 0; j < ioa->num_devices; j++) {
scsi_dev_data = ioa->dev[j].scsi_dev_data;
if (!scsi_dev_data ||
(scsi_dev_data->type != TYPE_DISK &&
scsi_dev_data->type != IPR_TYPE_AF_DISK) ||
ipr_is_hot_spare(&ioa->dev[j]) ||
ipr_is_volume_set(&ioa->dev[j]) ||
ipr_is_array_member(&ioa->dev[j]))
continue;
/* check if evaluate_device is needed for this device */
verify_device(&ioa->dev[j]);
print_dev(k, &ioa->dev[j], buffer, "%1", ioa, 2+k);
*i_con = add_i_con(*i_con,"\0",&ioa->dev[j]);
num_lines++;
}
return num_lines;
}
static int print_hotspare_disks(struct ipr_ioa *ioa,
i_container **i_con, char **buffer)
{
struct scsi_dev_data *scsi_dev_data;
int j, k;
int num_lines = 0;
/* print Hot Spare devices*/
for (j = 0; j < ioa->num_devices; j++) {
scsi_dev_data = ioa->dev[j].scsi_dev_data;
if (!scsi_dev_data || !ipr_is_hot_spare(&ioa->dev[j]))
continue;
print_dev(k, &ioa->dev[j], buffer, "%1", ioa, 2+k);
*i_con = add_i_con(*i_con,"\0",&ioa->dev[j]);
num_lines++;
}
return num_lines;
}
static int print_vsets(struct ipr_ioa *ioa,
i_container **i_con, char **buffer)
{
int j, k, i;
int num_lines = 0;
char *prot_level_str;
int array_id;
/* print volume set and associated devices*/
for (j = 0; j < ioa->num_devices; j++) {
if (!ipr_is_volume_set(&ioa->dev[j]))
continue;
if (ioa->dev[j].array_rcd->start_cand)
continue;
/* query resource state to acquire protection level string */
prot_level_str = get_prot_level_str(ioa->supported_arrays,
ioa->dev[j].array_rcd->raid_level);
strncpy(ioa->dev[j].prot_level_str,prot_level_str, 8);
print_dev(k, &ioa->dev[j], buffer, "%1", ioa, 2+k);
*i_con = add_i_con(*i_con,"\0",&ioa->dev[j]);
array_id = ioa->dev[j].dev_rcd->array_id;
num_lines++;
for (i = 0; i < ioa->num_devices; i++) {
if (!ipr_is_array_member(&ioa->dev[i]) ||
ipr_is_volume_set(&ioa->dev[i]) ||
(ioa->dev[i].dev_rcd && ioa->dev[i].dev_rcd->array_id != array_id))
continue;
strncpy(ioa->dev[i].prot_level_str, prot_level_str, 8);
print_dev(k, &ioa->dev[i], buffer, "%1", ioa, 2+k);
*i_con = add_i_con(*i_con,"\0",&ioa->dev[i]);
num_lines++;
}
}
return num_lines;
}
int disk_status(i_container *i_con)
{
int rc, k;
int len = 0;
int num_lines = 0;
struct ipr_ioa *ioa;
struct screen_output *s_out;
int header_lines;
char *buffer[2];
int toggle = 1;
processing();
rc = RC_SUCCESS;
i_con = free_i_con(i_con);
check_current_config(false);
body_init_status(buffer, n_disk_status.header, &header_lines);
for_each_ioa(ioa) {
if (!ioa->ioa.scsi_dev_data)
continue;
print_dev(k, &ioa->ioa, buffer, "%1", ioa, 2+k);
i_con = add_i_con(i_con, "\0", &ioa->ioa);
num_lines++;
num_lines += print_standalone_disks(ioa, &i_con, buffer);
num_lines += print_hotspare_disks(ioa, &i_con, buffer);
num_lines += print_vsets(ioa, &i_con, buffer);
}
if (num_lines == 0) {
for (k = 0; k < 2; k++) {
len = strlen(buffer[k]);
buffer[k] = realloc(buffer[k], len +
strlen(_(no_dev_found)) + 8);
sprintf(buffer[k] + len, "\n%s", _(no_dev_found));
}
}
do {
n_disk_status.body = buffer[toggle&1];
s_out = screen_driver(&n_disk_status,header_lines,i_con);
toggle++;
} while (s_out->rc == TOGGLE_SCREEN);
for (k = 0; k < 2; k++) {
free(buffer[k]);
buffer[k] = NULL;
}
n_disk_status.body = NULL;
rc = s_out->rc;
free(s_out);
return rc;
}
static int device_details_get_device(i_container *i_con,
struct ipr_dev **device)
{
i_container *temp_i_con;
int invalid=0;
int dev_num = 0;
struct ipr_dev *cur_device;
char *input;
if (!i_con)
return 1;
for (temp_i_con = i_con_head; temp_i_con && !invalid;
temp_i_con = temp_i_con->next_item) {
cur_device = (struct ipr_dev *)(temp_i_con->data);
if (!cur_device)
continue;
input = temp_i_con->field_data;
if (!input)
continue;
if (strcmp(input, "1") == 0) {
if (dev_num) {
dev_num++;
break;
} else {
*device = cur_device;
dev_num++;
}
} else if ((strcmp(input, " ") != 0) &&
(input != NULL) &&
(strcmp(input, "") != 0)) {
invalid = 1;
}
}
if (invalid)
/* The selection is not valid */
return 15;
if (dev_num == 0)
/* Invalid option. No devices selected. */
return 17;
else if (dev_num != 1)
/* Error. More than one unit was selected. */
return 16;
return 0;
}
static char *ioa_details(char *body, struct ipr_dev *dev)
{
struct ipr_ioa_vpd ioa_vpd;
struct ipr_cfc_vpd cfc_vpd;
struct ipr_dram_vpd dram_vpd;
struct ipr_inquiry_page0 page0_inq;
struct scsi_dev_data *scsi_dev_data = dev->scsi_dev_data;
struct ipr_dual_ioa_entry *ioa_entry;
int rc, i;
char buffer[200];
int cache_size;
u32 fw_level;
memset(&ioa_vpd, 0, sizeof(ioa_vpd));
memset(&cfc_vpd, 0, sizeof(cfc_vpd));
memset(&dram_vpd, 0, sizeof(dram_vpd));
ipr_inquiry(dev, IPR_STD_INQUIRY, &ioa_vpd, sizeof(ioa_vpd));
rc = ipr_inquiry(dev, 0, &page0_inq, sizeof(page0_inq));
for (i = 0; !rc && i < page0_inq.page_length; i++) {
if (page0_inq.supported_page_codes[i] == 1) {
ipr_inquiry(dev, 1, &cfc_vpd, sizeof(cfc_vpd));
break;
}
}
ipr_inquiry(dev, 2, &dram_vpd, sizeof(dram_vpd));
fw_level = get_ioa_fw_version(dev->ioa);
body = add_line_to_body(body,"", NULL);
ipr_strncpy_0(buffer, scsi_dev_data->vendor_id, IPR_VENDOR_ID_LEN);
body = add_line_to_body(body,_("Manufacturer"), buffer);
ipr_strncpy_0(buffer, scsi_dev_data->product_id, IPR_PROD_ID_LEN);
body = add_line_to_body(body,_("Machine Type and Model"), buffer);
sprintf(buffer,"%08X", fw_level);
body = add_line_to_body(body,_("Firmware Version"), buffer);
if (!dev->ioa->ioa_dead) {
ipr_strncpy_0(buffer, ioa_vpd.std_inq_data.serial_num, IPR_SERIAL_NUM_LEN);
body = add_line_to_body(body,_("Serial Number"), buffer);
ipr_strncpy_0(buffer, ioa_vpd.ascii_part_num, IPR_VPD_PART_NUM_LEN);
body = add_line_to_body(body,_("Part Number"), buffer);
ipr_strncpy_0(buffer, ioa_vpd.ascii_plant_code, IPR_VPD_PLANT_CODE_LEN);
body = add_line_to_body(body,_("Plant of Manufacturer"), buffer);
if (cfc_vpd.cache_size[0]) {
ipr_strncpy_0(buffer, cfc_vpd.cache_size, IPR_VPD_CACHE_SIZE_LEN);
cache_size = strtoul(buffer, NULL, 16);
sprintf(buffer,"%d MB", cache_size);
body = add_line_to_body(body,_("Cache Size"), buffer);
}
memcpy(buffer, dram_vpd.dram_size, IPR_VPD_DRAM_SIZE_LEN);
sprintf(buffer + IPR_VPD_DRAM_SIZE_LEN, " MB");
body = add_line_to_body(body,_("DRAM Size"), buffer);
}
body = add_line_to_body(body,_("Resource Name"), dev->gen_name);
body = add_line_to_body(body,"", NULL);
body = add_line_to_body(body,_("Physical location"), NULL);
body = add_line_to_body(body,_("PCI Address"), dev->ioa->pci_address);
sprintf(buffer,"%d", dev->ioa->host_num);
body = add_line_to_body(body,_("SCSI Host Number"), buffer);
if (dev->ioa->dual_raid_support) {
ioa_entry = (struct ipr_dual_ioa_entry *)
(((unsigned long)&dev->ioa->ioa_status.cap) +
ntohl(dev->ioa->ioa_status.cap.length));
body = add_line_to_body(body,"", NULL);
body = add_line_to_body(body,_("Current Dual Adapter State"),
dev->ioa->dual_state);
body = add_line_to_body(body,_("Preferred Dual Adapter State"),
dev->ioa->preferred_dual_state);
if (ntohl(dev->ioa->ioa_status.num_entries)) {
ipr_strncpy_0(buffer, ioa_entry->remote_vendor_id, IPR_VENDOR_ID_LEN);
body = add_line_to_body(body,_("Remote Adapter Manufacturer"), buffer);
ipr_strncpy_0(buffer, ioa_entry->remote_prod_id, IPR_PROD_ID_LEN);
body = add_line_to_body(body,_("Remote Adapter Machine Type And Model"),
buffer);
ipr_strncpy_0(buffer, ioa_entry->remote_sn, IPR_SERIAL_NUM_LEN);
body = add_line_to_body(body,_("Remote Adapter Serial Number"), buffer);
}
}
return body;
}
static char *vset_details(char *body, struct ipr_dev *dev)
{
struct ipr_read_cap16 read_cap16;
unsigned long long max_user_lba_int;
long double device_capacity;
double lba_divisor;
struct ipr_array_record *array_rcd = dev->array_rcd;
char buffer[100];
int rc;
int scsi_channel, scsi_id, scsi_lun;
if (dev->scsi_dev_data) {
scsi_channel = dev->scsi_dev_data->channel;
scsi_id = dev->scsi_dev_data->id;
scsi_lun = dev->scsi_dev_data->lun;
} else {
scsi_channel = array_rcd->last_resource_addr.bus;
scsi_id = array_rcd->last_resource_addr.target;
scsi_lun = array_rcd->last_resource_addr.lun;
}
body = add_line_to_body(body,"", NULL);
ipr_strncpy_0(buffer, array_rcd->vendor_id, IPR_VENDOR_ID_LEN);
body = add_line_to_body(body,_("Manufacturer"), buffer);
sprintf(buffer,"RAID %s", dev->prot_level_str);
body = add_line_to_body(body,_("RAID Level"), buffer);
if (ntohs(array_rcd->stripe_size) > 1024)
sprintf(buffer,"%d M", ntohs(array_rcd->stripe_size)/1024);
else
sprintf(buffer,"%d k", ntohs(array_rcd->stripe_size));
body = add_line_to_body(body,_("Stripe Size"), buffer);
/* Do a read capacity to determine the capacity */
rc = ipr_read_capacity_16(dev, &read_cap16);
if (!rc && (ntohl(read_cap16.max_user_lba_hi) ||
ntohl(read_cap16.max_user_lba_lo)) &&
ntohl(read_cap16.block_length)) {
max_user_lba_int = ntohl(read_cap16.max_user_lba_hi);
max_user_lba_int <<= 32;
max_user_lba_int |= ntohl(read_cap16.max_user_lba_lo);
device_capacity = max_user_lba_int + 1;
lba_divisor =
(1000*1000*1000) / ntohl(read_cap16.block_length);
sprintf(buffer, "%.2Lf GB", device_capacity / lba_divisor);
body = add_line_to_body(body, _("Capacity"), buffer);
}
body = add_line_to_body(body, _("Resource Name"), dev->dev_name);
body = add_line_to_body(body, "", NULL);
body = add_line_to_body(body, _("Physical location"), NULL);
body = add_line_to_body(body, _("PCI Address"), dev->ioa->pci_address);
sprintf(buffer, "%d", dev->ioa->host_num);
body = add_line_to_body(body, _("SCSI Host Number"), buffer);
sprintf(buffer, "%d", scsi_channel);
body = add_line_to_body(body, _("SCSI Channel"), buffer);
sprintf(buffer, "%d", scsi_id);
body = add_line_to_body(body, _("SCSI Id"), buffer);
sprintf(buffer, "%d", scsi_lun);
body = add_line_to_body(body, _("SCSI Lun"), buffer);
return body;
}
static char *disk_extended_details(char *body, struct ipr_dev *dev,
struct ipr_std_inq_data_long *std_inq)
{
int rc, i;
struct ipr_inquiry_page0 page0_inq;
char buffer[100];
char *hex;
rc = ipr_inquiry(dev, 0, &page0_inq, sizeof(page0_inq));
for (i = 0; !rc && i < page0_inq.page_length; i++) {
if (page0_inq.supported_page_codes[i] == 0xC7) {
/* FIXME 0xC7 is SCSD, do further research to find
what needs to be tested for this affirmation.*/
/* xxx add_str_to_body that does the strncpy_0? */
body = add_line_to_body(body,"", NULL);
body = add_line_to_body(body,_("Extended Details"), NULL);
ipr_strncpy_0(buffer, std_inq->fru_number, IPR_STD_INQ_FRU_NUM_LEN);
body = add_line_to_body(body,_("FRU Number"), buffer);
ipr_strncpy_0(buffer, std_inq->ec_level, IPR_STD_INQ_EC_LEVEL_LEN);
body = add_line_to_body(body,_("EC Level"), buffer);
ipr_strncpy_0(buffer, std_inq->part_number, IPR_STD_INQ_PART_NUM_LEN);
body = add_line_to_body(body,_("Part Number"), buffer);
hex = (u8 *)&std_inq->std_inq_data;
sprintf(buffer, "%02X%02X%02X%02X%02X%02X%02X%02X",
hex[0], hex[1], hex[2], hex[3], hex[4], hex[5], hex[6], hex[7]);
body = add_line_to_body(body,_("Device Specific (Z0)"), buffer);
ipr_strncpy_0(buffer, std_inq->z1_term, IPR_STD_INQ_Z1_TERM_LEN);
body = add_line_to_body(body,_("Device Specific (Z1)"), buffer);
ipr_strncpy_0(buffer, std_inq->z2_term, IPR_STD_INQ_Z2_TERM_LEN);
body = add_line_to_body(body,_("Device Specific (Z2)"), buffer);
ipr_strncpy_0(buffer, std_inq->z3_term, IPR_STD_INQ_Z3_TERM_LEN);
body = add_line_to_body(body,_("Device Specific (Z3)"), buffer);
ipr_strncpy_0(buffer, std_inq->z4_term, IPR_STD_INQ_Z4_TERM_LEN);
body = add_line_to_body(body,_("Device Specific (Z4)"), buffer);
ipr_strncpy_0(buffer, std_inq->z5_term, IPR_STD_INQ_Z5_TERM_LEN);
body = add_line_to_body(body,_("Device Specific (Z5)"), buffer);
ipr_strncpy_0(buffer, std_inq->z6_term, IPR_STD_INQ_Z6_TERM_LEN);
body = add_line_to_body(body,_("Device Specific (Z6)"), buffer);
break;
}
}
return body;
}
static char *disk_details(char *body, struct ipr_dev *dev)
{
int rc;
struct ipr_std_inq_data_long std_inq;
struct ipr_dev_record *device_record;
struct ipr_dasd_inquiry_page3 page3_inq;
struct ipr_read_cap read_cap;
struct ipr_query_res_state res_state;
long double device_capacity;
double lba_divisor;
u8 product_id[IPR_PROD_ID_LEN+1];
u8 vendor_id[IPR_VENDOR_ID_LEN+1];
u8 serial_num[IPR_SERIAL_NUM_LEN+1];
char buffer[100];
int len, scsi_channel, scsi_id, scsi_lun;
device_record = (struct ipr_dev_record *)dev->dev_rcd;
if (dev->scsi_dev_data) {
scsi_channel = dev->scsi_dev_data->channel;
scsi_id = dev->scsi_dev_data->id;
scsi_lun = dev->scsi_dev_data->lun;
} else if (device_record) {
scsi_channel = device_record->last_resource_addr.bus;
scsi_id = device_record->last_resource_addr.target;
scsi_lun = device_record->last_resource_addr.lun;
}
read_cap.max_user_lba = 0;
read_cap.block_length = 0;
rc = ipr_inquiry(dev, IPR_STD_INQUIRY, &std_inq, sizeof(std_inq));
if (!rc) {
ipr_strncpy_0(vendor_id, std_inq.std_inq_data.vpids.vendor_id,
IPR_VENDOR_ID_LEN);
ipr_strncpy_0(product_id, std_inq.std_inq_data.vpids.product_id,
IPR_PROD_ID_LEN);
ipr_strncpy_0(serial_num, std_inq.std_inq_data.serial_num,
IPR_SERIAL_NUM_LEN);
} else if (device_record) {
ipr_strncpy_0(vendor_id, device_record->vendor_id, IPR_VENDOR_ID_LEN);
ipr_strncpy_0(product_id, device_record->product_id, IPR_PROD_ID_LEN);
ipr_strncpy_0(serial_num, device_record->serial_num, IPR_SERIAL_NUM_LEN);
} else {
ipr_strncpy_0(vendor_id, dev->scsi_dev_data->vendor_id, IPR_VENDOR_ID_LEN);
ipr_strncpy_0(product_id, dev->scsi_dev_data->product_id, IPR_PROD_ID_LEN);
}
body = add_line_to_body(body,"", NULL);
body = add_line_to_body(body,_("Manufacturer"), vendor_id);
body = add_line_to_body(body,_("Product ID"), product_id);
rc = ipr_inquiry(dev, 0x03, &page3_inq, sizeof(page3_inq));
if (!rc) {
len = sprintf(buffer, "%X%X%X%X", page3_inq.release_level[0],
page3_inq.release_level[1], page3_inq.release_level[2],
page3_inq.release_level[3]);
if (isalnum(page3_inq.release_level[0]) && isalnum(page3_inq.release_level[1]) &&
isalnum(page3_inq.release_level[2]) && isalnum(page3_inq.release_level[3])) {
sprintf(buffer + len, " (%c%c%c%c)", page3_inq.release_level[0],
page3_inq.release_level[1], page3_inq.release_level[2],
page3_inq.release_level[3]);
}
body = add_line_to_body(body, _("Firmware Version"), buffer);
}
if (strcmp(vendor_id,"IBMAS400") == 0) {
sprintf(buffer, "%X", std_inq.as400_service_level);
body = add_line_to_body(body,_("Level"), buffer);
}
body = add_line_to_body(body,_("Serial Number"), serial_num);
memset(&read_cap, 0, sizeof(read_cap));
rc = ipr_read_capacity(dev, &read_cap);
if (!rc && ntohl(read_cap.block_length) &&
ntohl(read_cap.max_user_lba)) {
lba_divisor = (1000*1000*1000) /
ntohl(read_cap.block_length);
device_capacity = ntohl(read_cap.max_user_lba) + 1;
sprintf(buffer,"%.2Lf GB", device_capacity / lba_divisor);
body = add_line_to_body(body,_("Capacity"), buffer);
}
if (strlen(dev->dev_name) > 0)
body = add_line_to_body(body,_("Resource Name"), dev->dev_name);
rc = ipr_query_resource_state(dev, &res_state);
if (!rc) {
if (is_spi(dev->ioa)) {
if (ntohl(res_state.gscsi.data_path_width) == 16)
body = add_line_to_body(body, _("Wide Enabled"), _("Yes"));
else
body = add_line_to_body(body, _("Wide Enabled"), _("No"));
sprintf(buffer, "%d MB/s",
(ntohl(res_state.gscsi.data_xfer_rate) *
ntohl(res_state.gscsi.data_path_width))/(10 * 8));
if (res_state.gscsi.data_xfer_rate != 0xffffffff)
body = add_line_to_body(body, _("Current Bus Throughput"), buffer);
}
}
body = add_line_to_body(body, "", NULL);
body = add_line_to_body(body, _("Physical location"), NULL);
body = add_line_to_body(body ,_("PCI Address"), dev->ioa->pci_address);
sprintf(buffer, "%d", dev->ioa->host_num);
body = add_line_to_body(body, _("SCSI Host Number"), buffer);
sprintf(buffer, "%d", scsi_channel);
body = add_line_to_body(body, _("SCSI Channel"), buffer);
sprintf(buffer, "%d", scsi_id);
body = add_line_to_body(body, _("SCSI Id"), buffer);
sprintf(buffer, "%d", scsi_lun);
body = add_line_to_body(body, _("SCSI Lun"), buffer);
body = disk_extended_details(body, dev, &std_inq);
return body;
}
int device_details(i_container *i_con)
{
char *body = NULL;
struct ipr_dev *dev;
struct screen_output *s_out;
s_node *n_screen;
int rc;
processing();
if ((rc = device_details_get_device(i_con, &dev)))
return rc;
if (dev->scsi_dev_data && dev->scsi_dev_data->type == IPR_TYPE_ADAPTER) {
n_screen = &n_adapter_details;
body = ioa_details(body, dev);
} else if (ipr_is_volume_set(dev)) {
n_screen = &n_vset_details;
body = vset_details(body, dev);
} else {
n_screen = &n_device_details;
body = disk_details(body, dev);
}
n_screen->body = body;
s_out = screen_driver(n_screen, 0, i_con);
free(n_screen->body);
n_screen->body = NULL;
rc = s_out->rc;
free(s_out);
return rc;
}
#define IPR_INCLUDE 0
#define IPR_REMOVE 1
#define IPR_ADD_HOT_SPARE 0
#define IPR_RMV_HOT_SPARE 1
int raid_screen(i_container *i_con)
{
int rc;
struct array_cmd_data *cur_raid_cmd;
struct screen_output *s_out;
int loop;
cur_raid_cmd = raid_cmd_head;
while(cur_raid_cmd) {
cur_raid_cmd = cur_raid_cmd->next;
free(raid_cmd_head);
raid_cmd_head = cur_raid_cmd;
}
for (loop = 0; loop < n_raid_screen.num_opts; loop++) {
n_raid_screen.body =
ipr_list_opts(n_raid_screen.body,
n_raid_screen.options[loop].key,
n_raid_screen.options[loop].list_str);
}
n_raid_screen.body = ipr_end_list(n_raid_screen.body);
s_out = screen_driver(&n_raid_screen,0,NULL);
free(n_raid_screen.body);
n_raid_screen.body = NULL;
rc = s_out->rc;
free(s_out);
return rc;
}
int raid_status(i_container *i_con)
{
int rc, j, i, k;
int len = 0;
int num_lines = 0;
struct ipr_ioa *ioa;
struct scsi_dev_data *scsi_dev_data;
struct screen_output *s_out;
int header_lines;
int array_id;
char *buffer[2];
int toggle = 1;
char *prot_level_str;
processing();
rc = RC_SUCCESS;
i_con = free_i_con(i_con);
check_current_config(false);
body_init_status(buffer, n_raid_status.header, &header_lines);
for_each_ioa(ioa) {
if (!ioa->ioa.scsi_dev_data)
continue;
/* print Hot Spare devices*/
for (j = 0; j < ioa->num_devices; j++) {
if (!ipr_is_hot_spare(&ioa->dev[j]))
continue;
print_dev(k, &ioa->dev[j], buffer, "%1", ioa, 2+k);
i_con = add_i_con(i_con, "\0", &ioa->dev[j]);
num_lines++;
}
/* print volume set and associated devices*/
for (j = 0; j < ioa->num_devices; j++) {
if (!ipr_is_volume_set(&ioa->dev[j]))
continue;
if (ioa->dev[j].array_rcd && ioa->dev[j].array_rcd->start_cand)
continue;
/* query resource state to acquire protection level string */
prot_level_str = get_prot_level_str(ioa->supported_arrays,
ioa->dev[j].array_rcd->raid_level);
strncpy(ioa->dev[j].prot_level_str, prot_level_str, 8);
print_dev(k, &ioa->dev[j], buffer, "%1", ioa, 2+k);
i_con = add_i_con(i_con,"\0",&ioa->dev[j]);
array_id = ioa->dev[j].dev_rcd->array_id;
num_lines++;
for (i = 0; i < ioa->num_devices; i++) {
scsi_dev_data = ioa->dev[i].scsi_dev_data;
if (!ipr_is_array_member(&ioa->dev[i]) ||
ipr_is_volume_set(&ioa->dev[i]) ||
(ioa->dev[i].dev_rcd && ioa->dev[i].dev_rcd->array_id != array_id))
continue;
strncpy(ioa->dev[i].prot_level_str, prot_level_str, 8);
print_dev(k, &ioa->dev[i], buffer, "%1", ioa, 2+k);
i_con = add_i_con(i_con, "\0", &ioa->dev[i]);
num_lines++;
}
}
}
if (num_lines == 0) {
for (k=0; k<2; k++) {
len = strlen(buffer[k]);
buffer[k] = realloc(buffer[k], len +
strlen(_(no_dev_found)) + 8);
sprintf(buffer[k] + len, "%s\n", _(no_dev_found));
}
}
toggle_field = 0;
do {
n_raid_status.body = buffer[toggle&1];
s_out = screen_driver(&n_raid_status,header_lines,i_con);
toggle++;
} while (s_out->rc == TOGGLE_SCREEN);
for (k = 0; k < 2; k++) {
free(buffer[k]);
buffer[k] = NULL;
}
n_raid_status.body = NULL;
rc = s_out->rc;
free(s_out);
return rc;
}
static int is_array_in_use(struct ipr_ioa *ioa,
u8 array_id)
{
int j, opens;
struct ipr_dev_record *device_record;
struct ipr_array_record *array_record;
struct scsi_dev_data *scsi_dev_data;
for (j = 0; j < ioa->num_devices; j++) {
device_record = ioa->dev[j].dev_rcd;
array_record = ioa->dev[j].array_rcd;
if (!device_record)
continue;
if (array_record->common.record_id == IPR_RECORD_ID_ARRAY_RECORD) {
if (array_id == array_record->array_id) {
scsi_dev_data = ioa->dev[j].scsi_dev_data;
if (!scsi_dev_data)
continue;
opens = num_device_opens(scsi_dev_data->host,
scsi_dev_data->channel,
scsi_dev_data->id,
scsi_dev_data->lun);
if (opens != 0)
return 1;
}
}
}
return 0;
}
int raid_stop(i_container *i_con)
{
int rc, i, k;
int found = 0;
struct ipr_array_record *array_record;
char *buffer[2];
struct ipr_ioa *ioa;
int header_lines;
int toggle = 1;
struct screen_output *s_out;
char *prot_level_str;
processing();
/* empty the linked list that contains field pointers */
i_con = free_i_con(i_con);
rc = RC_SUCCESS;
check_current_config(false);
body_init_status(buffer, n_raid_stop.header, &header_lines);
for_each_ioa(ioa) {
for (i = 0; i < ioa->num_devices; i++) {
if (!ipr_is_volume_set(&ioa->dev[i]))
continue;
array_record = ioa->dev[i].array_rcd;
if (!array_record->stop_cand)
continue;
if ((rc = is_array_in_use(ioa, array_record->array_id)))
continue;
add_raid_cmd_tail(ioa, &ioa->dev[i], array_record->array_id);
i_con = add_i_con(i_con,"\0",raid_cmd_tail);
prot_level_str = get_prot_level_str(ioa->supported_arrays,
array_record->raid_level);
strncpy(ioa->dev[i].prot_level_str,prot_level_str, 8);
print_dev(k, &ioa->dev[i], buffer, "%1", ioa, 2+k);
found++;
}
}
if (!found) {
/* Stop Device Parity Protection Failed */
n_raid_stop_fail.body = body_init(n_raid_stop_fail.header, NULL);
s_out = screen_driver(&n_raid_stop_fail,0,i_con);
free(n_raid_stop_fail.body);
n_raid_stop_fail.body = NULL;
} else {
toggle_field = 0;
do {
n_raid_stop.body = buffer[toggle&1];
s_out = screen_driver(&n_raid_stop,header_lines,i_con);
toggle++;
} while (s_out->rc == TOGGLE_SCREEN);
}
rc = s_out->rc;
free(s_out);
for (k = 0; k < 2; k++) {
free(buffer[k]);
buffer[k] = NULL;
}
n_raid_stop.body = NULL;
return rc;
}
int confirm_raid_stop(i_container *i_con)
{
struct ipr_dev *ipr_dev;
struct ipr_array_record *array_record;
struct array_cmd_data *cur_raid_cmd;
struct ipr_ioa *ioa;
int rc, j, k;
int found = 0;
char *input;
char *buffer[2];
struct ipr_dev_record *dev_record;
i_container *temp_i_con;
struct screen_output *s_out;
int toggle = 1;
int header_lines;
found = 0;
body_init_status(buffer, n_confirm_raid_stop.header, &header_lines);
for_each_icon(temp_i_con) {
cur_raid_cmd = (struct array_cmd_data *)(temp_i_con->data);
if (!cur_raid_cmd)
continue;
input = temp_i_con->field_data;
array_record = cur_raid_cmd->dev->array_rcd;
if (strcmp(input, "1") == 0) {
found = 1;
cur_raid_cmd->do_cmd = 1;
if (!array_record->issue_cmd)
array_record->issue_cmd = 1;
} else {
cur_raid_cmd->do_cmd = 0;
if (array_record->issue_cmd)
array_record->issue_cmd = 0;
}
}
if (!found)
return INVALID_OPTION_STATUS;
rc = RC_SUCCESS;
for_each_raid_cmd(cur_raid_cmd) {
if (!cur_raid_cmd->do_cmd)
continue;
ioa = cur_raid_cmd->ioa;
ipr_dev = cur_raid_cmd->dev;
print_dev(k, ipr_dev, buffer, "1", ioa, 2+k);
for (j = 0; j < ioa->num_devices; j++) {
dev_record = ioa->dev[j].dev_rcd;
if (ipr_is_array_member(&ioa->dev[j]) &&
ipr_is_af_dasd_device(&ioa->dev[j]) &&
dev_record->array_id == cur_raid_cmd->array_id) {
strncpy(ioa->dev[j].prot_level_str,ipr_dev->prot_level_str, 8);
print_dev(k, &ioa->dev[j], buffer, "1", ioa, 2+k);
}
}
}
toggle_field = 0;
do {
n_confirm_raid_stop.body = buffer[toggle&1];
s_out = screen_driver(&n_confirm_raid_stop,header_lines,i_con);
toggle++;
} while (s_out->rc == TOGGLE_SCREEN);
rc = s_out->rc;
free(s_out);
for (k = 0; k < 2; k++) {
free(buffer[k]);
buffer[k] = NULL;
}
n_confirm_raid_stop.body = NULL;
return rc;
}
static int raid_stop_complete()
{
struct ipr_cmd_status cmd_status;
struct ipr_cmd_status_record *status_record;
int done_bad;
int not_done = 0;
int rc, j;
struct ipr_ioa *ioa;
struct array_cmd_data *cur_raid_cmd;
while(1) {
done_bad = 0;
not_done = 0;
for_each_raid_cmd(cur_raid_cmd) {
ioa = cur_raid_cmd->ioa;
rc = ipr_query_command_status(&ioa->ioa, &cmd_status);
if (rc) {
done_bad = 1;
continue;
}
status_record = cmd_status.record;
for (j = 0; j < cmd_status.num_records; j++, status_record++) {
if (status_record->command_code == IPR_STOP_ARRAY_PROTECTION &&
cur_raid_cmd->array_id == status_record->array_id) {
if (status_record->status == IPR_CMD_STATUS_IN_PROGRESS)
not_done = 1;
else if (status_record->status != IPR_CMD_STATUS_SUCCESSFUL)
/* "Stop Parity Protection failed" */
done_bad = 1;
break;
}
}
}
if (!not_done) {
if (done_bad)
/* "Stop Parity Protection failed" */
return (20 | EXIT_FLAG);
check_current_config(false);
/* "Stop Parity Protection completed successfully" */
return (21 | EXIT_FLAG);
}
not_done = 0;
sleep(1);
}
}
int do_confirm_raid_stop(i_container *i_con)
{
struct ipr_dev *ipr_dev;
struct array_cmd_data *cur_raid_cmd;
struct ipr_ioa *ioa;
int rc;
int max_y, max_x;
for_each_raid_cmd(cur_raid_cmd) {
if (!cur_raid_cmd->do_cmd)
continue;
ioa = cur_raid_cmd->ioa;
ipr_dev = cur_raid_cmd->dev;
rc = is_array_in_use(ioa, cur_raid_cmd->array_id);
if (rc != 0) {
syslog(LOG_ERR,
_("Array %s is currently in use and cannot be deleted.\n"),
ipr_dev->dev_name);
return (20 | EXIT_FLAG);
}
if (ipr_dev->qac_entry->record_id != IPR_RECORD_ID_ARRAY_RECORD)
continue;
getmaxyx(stdscr,max_y,max_x);
move(max_y-1,0);
printw(_("Operation in progress - please wait"));
refresh();
if (ipr_dev->scsi_dev_data)
rc = ipr_start_stop_stop(ipr_dev);
if (rc != 0)
return (20 | EXIT_FLAG);
ioa->num_raid_cmds++;
}
for_each_ioa(ioa) {
if (ioa->num_raid_cmds == 0)
continue;
ioa->num_raid_cmds = 0;
rc = ipr_stop_array_protection(ioa);
if (rc != 0)
return (20 | EXIT_FLAG);
}
rc = raid_stop_complete();
return rc;
}
int raid_start(i_container *i_con)
{
int rc, k;
int found = 0;
struct array_cmd_data *cur_raid_cmd;
struct ipr_array_record *array_record;
char *buffer[2];
struct ipr_ioa *ioa;
struct screen_output *s_out;
int header_lines;
int toggle = 0;
processing();
/* empty the linked list that contains field pointers */
i_con = free_i_con(i_con);
rc = RC_SUCCESS;
check_current_config(false);
body_init_status(buffer, n_raid_start.header, &header_lines);
for_each_ioa(ioa) {
array_record = ioa->start_array_qac_entry;
if (!array_record)
continue;
add_raid_cmd_tail(ioa, &ioa->ioa, array_record->array_id);
i_con = add_i_con(i_con,"\0",raid_cmd_tail);
print_dev(k, &ioa->ioa, buffer, "%1", ioa, k);
found++;
}
if (!found) {
/* Start Device Parity Protection Failed */
n_raid_start_fail.body = body_init(n_raid_start_fail.header, NULL);
s_out = screen_driver(&n_raid_start_fail,0,i_con);
free(n_raid_start_fail.body);
n_raid_start_fail.body = NULL;
rc = s_out->rc;
free(s_out);
} else {
do {
n_raid_start.body = buffer[toggle&1];
s_out = screen_driver(&n_raid_start,header_lines,i_con);
toggle++;
} while (s_out->rc == TOGGLE_SCREEN);
rc = s_out->rc;
free(s_out);
cur_raid_cmd = raid_cmd_head;
while(cur_raid_cmd) {
cur_raid_cmd = cur_raid_cmd->next;
free(raid_cmd_head);
raid_cmd_head = cur_raid_cmd;
}
}
for (k=0; k<2; k++) {
free(buffer[k]);
buffer[k] = NULL;
}
n_raid_start.body = NULL;
return rc;
}
int raid_start_loop(i_container *i_con)
{
int rc;
struct array_cmd_data *cur_raid_cmd;
int found = 0;
char *input;
i_container *temp_i_con;
for_each_icon(temp_i_con) {
cur_raid_cmd = (struct array_cmd_data *)(temp_i_con->data);
if (!cur_raid_cmd)
continue;
input = temp_i_con->field_data;
if (strcmp(input, "1") == 0) {
rc = configure_raid_start(temp_i_con);
if (RC_SUCCESS == rc) {
found = 1;
cur_raid_cmd->do_cmd = 1;
} else
return rc;
} else
cur_raid_cmd->do_cmd = 0;
}
if (found != 0) {
/* Go to verification screen */
rc = confirm_raid_start(NULL);
rc |= EXIT_FLAG;
} else
rc = INVALID_OPTION_STATUS; /* "Invalid options specified" */
return rc;
}
int configure_raid_start(i_container *i_con)
{
char *input;
int found;
struct ipr_dev *ipr_dev;
struct array_cmd_data *cur_raid_cmd;
int rc, j, k;
char *buffer[2];
struct ipr_ioa *ioa;
struct scsi_dev_data *scsi_dev_data;
i_container *i_con2 = NULL;
i_container *i_con_head_saved;
i_container *temp_i_con = NULL;
struct screen_output *s_out;
int header_lines;
int toggle = 0;
rc = RC_SUCCESS;
cur_raid_cmd = (struct array_cmd_data *)(i_con->data);
ioa = cur_raid_cmd->ioa;
body_init_status(buffer, n_configure_raid_start.header, &header_lines);
i_con_head_saved = i_con_head;
i_con_head = NULL;
for (j = 0; j < ioa->num_devices; j++) {
scsi_dev_data = ioa->dev[j].scsi_dev_data;
if (!ipr_is_af_dasd_device(&ioa->dev[j]) || !scsi_dev_data)
continue;
if (ioa->dev[j].dev_rcd->start_cand && device_supported(&ioa->dev[j])) {
print_dev(k, &ioa->dev[j], buffer, "%1", ioa, k);
i_con2 = add_i_con(i_con2,"\0",&ioa->dev[j]);
}
}
do {
toggle_field = 0;
do {
n_configure_raid_start.body = buffer[toggle&1];
s_out = screen_driver(&n_configure_raid_start,header_lines,i_con2);
toggle++;
} while (s_out->rc == TOGGLE_SCREEN);
rc = s_out->rc;
if (rc > 0)
goto leave;
i_con2 = s_out->i_con;
free(s_out);
found = 0;
for_each_icon(temp_i_con) {
ipr_dev = (struct ipr_dev *)temp_i_con->data;
input = temp_i_con->field_data;
if ((ipr_dev != NULL) &&
(strcmp(input, "1") == 0)) {
found = 1;
ipr_dev->dev_rcd->issue_cmd = 1;
}
}
if (found != 0) {
/* Go to parameters screen */
rc = configure_raid_parameters(i_con);
if ((rc & EXIT_FLAG) ||
!(rc & CANCEL_FLAG))
goto leave;
/* User selected Cancel, clear out current selections
for redisplay */
for_each_icon(temp_i_con) {
ipr_dev = (struct ipr_dev *)temp_i_con->data;
input = temp_i_con->field_data;
if (ipr_dev && (strcmp(input, "1") == 0))
ipr_dev->dev_rcd->issue_cmd = 0;
}
rc = REFRESH_FLAG;
continue;
} else {
s_status.index = INVALID_OPTION_STATUS;
rc = REFRESH_FLAG;
}
} while (rc & REFRESH_FLAG);
leave:
i_con2 = free_i_con(i_con2);
i_con_head = i_con_head_saved;
for (k=0; k<2; k++) {
free(buffer[k]);
buffer[k] = NULL;
}
n_configure_raid_start.body = NULL;
return rc;
}
int display_input(int field_start_row, int *userptr)
{
FIELD *input_fields[3];
FORM *form;
WINDOW *box1_win, *field_win;
int field_rows = 2;
int field_cols = 16;
char *input;
int ch;
int rc = RC_SUCCESS;
input_fields[0] = new_field(1, 16, 0, 0, 0, 0);
input_fields[1] = new_field(1, 3, 1, 0, 0, 0);
input_fields[2] = NULL;
set_field_buffer(input_fields[0],0, "Enter new value");
field_opts_off(input_fields[0], O_ACTIVE);
field_opts_off(input_fields[0], O_EDIT);
box1_win = newwin(field_rows + 2, field_cols + 2, field_start_row - 1, 54);
field_win = newwin(field_rows, field_cols, field_start_row, 55);
box(box1_win,ACS_VLINE,ACS_HLINE);
form = new_form(input_fields);
set_current_field(form, input_fields[1]);
set_form_win(form,field_win);
set_form_sub(form,field_win);
post_form(form);
form_driver(form, REQ_FIRST_FIELD);
wnoutrefresh(box1_win);
while (1) {
wnoutrefresh(field_win);
doupdate();
ch = getch();
if (IS_ENTER_KEY(ch)) {
form_driver(form,REQ_VALIDATION);
input = field_buffer(input_fields[1],0);
sscanf(input, "%d",userptr);
break;
} else if (IS_EXIT_KEY(ch)) {
rc = EXIT_FLAG;
break;
} else if (IS_CANCEL_KEY(ch)) {
rc = CANCEL_FLAG;
break;
} else if (isascii(ch))
form_driver(form, ch);
}
wclear(field_win);
wrefresh(field_win);
delwin(field_win);
wclear(box1_win);
wrefresh(box1_win);
delwin(box1_win);
return rc;
}
int configure_raid_parameters(i_container *i_con)
{
FIELD *input_fields[5];
FIELD *cur_field;
FORM *form;
ITEM **raid_item = NULL;
struct array_cmd_data *cur_raid_cmd = (struct array_cmd_data *)(i_con->data);
int raid_index_default;
unsigned long raid_index = 0;
unsigned long index;
char buffer[24];
int rc, i;
struct ipr_ioa *ioa;
struct ipr_supported_arrays *supported_arrays;
struct ipr_array_cap_entry *cap_entry;
struct text_str
{
char line[16];
} *raid_menu_str = NULL, *stripe_menu_str = NULL;
char raid_str[16], stripe_str[16], qdepth_str[4];
int ch, start_row;
int cur_field_index;
int selected_count = 0;
int stripe_sz, stripe_sz_mask, stripe_sz_list[16];
struct prot_level *prot_level_list;
int *userptr = NULL;
int *retptr;
int max_x,max_y,start_y,start_x;
int qdepth, new_qdepth;
getmaxyx(stdscr,max_y,max_x);
getbegyx(stdscr,start_y,start_x);
rc = RC_SUCCESS;
ioa = cur_raid_cmd->ioa;
supported_arrays = ioa->supported_arrays;
cap_entry = supported_arrays->entry;
/* determine number of devices selected for this parity set */
for (i=0; i<ioa->num_devices; i++) {
if (ipr_is_af_dasd_device(&ioa->dev[i]) && ioa->dev[i].dev_rcd->issue_cmd)
selected_count++;
}
qdepth = selected_count * 4;
cur_raid_cmd->qdepth = qdepth;
/* set up raid lists */
raid_index = 0;
raid_index_default = -1;
prot_level_list = malloc(sizeof(struct prot_level));
prot_level_list[raid_index].is_valid = 0;
for_each_cap_entry(i, cap_entry, supported_arrays) {
if (selected_count <= cap_entry->max_num_array_devices &&
selected_count >= cap_entry->min_num_array_devices &&
((selected_count % cap_entry->min_mult_array_devices) == 0)) {
prot_level_list[raid_index].array_cap_entry = cap_entry;
prot_level_list[raid_index].is_valid = 1;
if (raid_index_default == -1 &&
!strcmp(cap_entry->prot_level_str, "10"))
raid_index_default = raid_index;
else if (!strcmp(cap_entry->prot_level_str, IPR_DEFAULT_RAID_LVL))
raid_index_default = raid_index;
raid_index++;
prot_level_list = realloc(prot_level_list, sizeof(struct prot_level) * (raid_index + 1));
prot_level_list[raid_index].is_valid = 0;
}
}
if (!raid_index)
return 69 | EXIT_FLAG;
if (raid_index_default == -1)
raid_index_default = 0;
/* Title */
input_fields[0] = new_field(1, max_x - start_x, /* new field size */
0, 0, /* upper left corner */
0, /* number of offscreen rows */
0); /* number of working buffers */
/* Protection Level */
input_fields[1] = new_field(1, 9, /* new field size */
8, 44, /* */
0, /* number of offscreen rows */
0); /* number of working buffers */
/* Stripe Size */
input_fields[2] = new_field(1, 9, /* new field size */
9, 44, /* */
0, /* number of offscreen rows */
0); /* number of working buffers */
/* Queue depth */
input_fields[3] = new_field(1, 3, /* new field size */
10, 44, /* */
0, /* number of offscreen rows */
0); /* number of working buffers */
input_fields[4] = NULL;
raid_index = raid_index_default;
cap_entry = prot_level_list[raid_index].array_cap_entry;
stripe_sz = ntohs(cap_entry->recommended_stripe_size);
form = new_form(input_fields);
set_current_field(form, input_fields[1]);
set_field_just(input_fields[0], JUSTIFY_CENTER);
set_field_just(input_fields[3], JUSTIFY_LEFT);
field_opts_off(input_fields[0], O_ACTIVE);
field_opts_off(input_fields[1], O_EDIT);
field_opts_off(input_fields[2], O_EDIT);
field_opts_off(input_fields[3], O_EDIT);
set_field_buffer(input_fields[0], /* field to alter */
0, /* number of buffer to alter */
_("Select Protection Level and Stripe Size")); /* string value to set */
form_opts_off(form, O_BS_OVERLOAD);
flush_stdscr();
clear();
set_form_win(form,stdscr);
set_form_sub(form,stdscr);
post_form(form);
mvaddstr(2, 1, _("Default array configurations are shown. To change"));
mvaddstr(3, 1, _("setting hit \"c\" for options menu. Highlight desired"));
mvaddstr(4, 1, _("option then hit Enter"));
mvaddstr(6, 1, _("c=Change Setting"));
mvaddstr(8, 0, "Protection Level . . . . . . . . . . . . :");
mvaddstr(9, 0, "Stripe Size . . . . . . . . . . . . . . :");
mvprintw(10, 0, "Queue Depth (default = %3d). . . . . . . :", qdepth);
mvaddstr(max_y - 4, 0, _("Press Enter to Continue"));
mvaddstr(max_y - 2, 0, EXIT_KEY_LABEL CANCEL_KEY_LABEL);
form_driver(form, /* form to pass input to */
REQ_FIRST_FIELD ); /* form request code */
while (1) {
sprintf(raid_str,"RAID %s",cap_entry->prot_level_str);
set_field_buffer(input_fields[1], /* field to alter */
0, /* number of buffer to alter */
raid_str); /* string value to set */
if (stripe_sz > 1024)
sprintf(stripe_str,"%d M",stripe_sz/1024);
else
sprintf(stripe_str,"%d k",stripe_sz);
set_field_buffer(input_fields[2], /* field to alter */
0, /* number of buffer to alter */
stripe_str); /* string value to set */
sprintf(qdepth_str,"%3d",qdepth);
set_field_buffer(input_fields[3], /* field to alter */
0, /* number of buffer to alter */
qdepth_str); /* string value to set */
refresh();
ch = getch();
if (IS_EXIT_KEY(ch)) {
rc = EXIT_FLAG;
goto leave;
} else if (IS_CANCEL_KEY(ch)) {
rc = CANCEL_FLAG;
goto leave;
} else if (ch == 'c') {
cur_field = current_field(form);
cur_field_index = field_index(cur_field);
if (cur_field_index == 1) {
/* count the number of valid entries */
index = 0;
while (prot_level_list[index].is_valid)
index++;
/* get appropriate memory, the text portion needs to be
done up front as the new_item() function uses the
passed pointer to display data */
raid_item = realloc(raid_item, sizeof(ITEM **) * (index + 1));
raid_menu_str = realloc(raid_menu_str, sizeof(struct text_str) * (index));
userptr = realloc(userptr, sizeof(int) * (index + 1));
/* set up protection level menu */
index = 0;
while (prot_level_list[index].is_valid) {
raid_item[index] = (ITEM *)NULL;
sprintf(raid_menu_str[index].line,"RAID %s",prot_level_list[index].array_cap_entry->prot_level_str);
raid_item[index] = new_item(raid_menu_str[index].line,"");
userptr[index] = index;
set_item_userptr(raid_item[index],
(char *)&userptr[index]);
index++;
}
raid_item[index] = (ITEM *)NULL;
start_row = 8;
rc = display_menu(raid_item, start_row, index, &retptr);
if (rc == RC_SUCCESS) {
raid_index = *retptr;
/* find recommended stripe size */
cap_entry = prot_level_list[raid_index].array_cap_entry;
stripe_sz = ntohs(cap_entry->recommended_stripe_size);
}
} else if (cur_field_index == 2) {
/* count the number of valid entries */
index = 0;
for (i=0; i<16; i++) {
stripe_sz_mask = 1 << i;
if ((stripe_sz_mask & ntohs(cap_entry->supported_stripe_sizes))
== stripe_sz_mask) {
index++;
}
}
/* get appropriate memory, the text portion needs to be
done up front as the new_item() function uses the
passed pointer to display data */
raid_item = realloc(raid_item, sizeof(ITEM **) * (index + 1));
stripe_menu_str = realloc(stripe_menu_str, sizeof(struct text_str) * (index));
userptr = realloc(userptr, sizeof(int) * (index + 1));
/* set up stripe size menu */
index = 0;
for (i = 0; i < 16; i++) {
stripe_sz_mask = 1 << i;
raid_item[index] = (ITEM *)NULL;
if ((stripe_sz_mask & ntohs(cap_entry->supported_stripe_sizes))
== stripe_sz_mask) {
stripe_sz_list[index] = stripe_sz_mask;
if (stripe_sz_mask > 1024)
sprintf(stripe_menu_str[index].line,"%d M",stripe_sz_mask/1024);
else
sprintf(stripe_menu_str[index].line,"%d k",stripe_sz_mask);
if (stripe_sz_mask == ntohs(cap_entry->recommended_stripe_size)) {
sprintf(buffer,_("%s - recommend"),stripe_menu_str[index].line);
raid_item[index] = new_item(buffer, "");
} else {
raid_item[index] = new_item(stripe_menu_str[index].line, "");
}
userptr[index] = index;
set_item_userptr(raid_item[index],
(char *)&userptr[index]);
index++;
}
}
raid_item[index] = (ITEM *)NULL;
start_row = 9;
rc = display_menu(raid_item, start_row, index, &retptr);
if (rc == RC_SUCCESS)
stripe_sz = stripe_sz_list[*retptr];
} else if (cur_field_index == 3) {
start_row = 10;
rc = display_input(start_row, &new_qdepth);
if (rc == EXIT_FLAG)
goto leave;
if (rc == CANCEL_FLAG)
continue;
if (new_qdepth > 128)
qdepth = 128;
else
qdepth = new_qdepth;
continue;
} else
continue;
i = 0;
while (raid_item[i] != NULL)
free_item(raid_item[i++]);
realloc(raid_item, 0);
raid_item = NULL;
if (rc == EXIT_FLAG)
goto leave;
} else if (IS_ENTER_KEY(ch)) {
/* set protection level and stripe size appropriately */
cur_raid_cmd->prot_level = cap_entry->prot_level;
cur_raid_cmd->stripe_size = stripe_sz;
cur_raid_cmd->qdepth = qdepth;
goto leave;
} else if (ch == KEY_RIGHT)
form_driver(form, REQ_NEXT_CHAR);
else if (ch == KEY_LEFT)
form_driver(form, REQ_PREV_CHAR);
else if ((ch == KEY_BACKSPACE) || (ch == 127))
form_driver(form, REQ_DEL_PREV);
else if (ch == KEY_DC)
form_driver(form, REQ_DEL_CHAR);
else if (ch == KEY_IC)
form_driver(form, REQ_INS_MODE);
else if (ch == KEY_EIC)
form_driver(form, REQ_OVL_MODE);
else if (ch == KEY_HOME)
form_driver(form, REQ_BEG_FIELD);
else if (ch == KEY_END)
form_driver(form, REQ_END_FIELD);
else if (ch == '\t')
form_driver(form, REQ_NEXT_FIELD);
else if (ch == KEY_UP)
form_driver(form, REQ_PREV_FIELD);
else if (ch == KEY_DOWN)
form_driver(form, REQ_NEXT_FIELD);
else if (isascii(ch))
form_driver(form, ch);
}
leave:
unpost_form(form);
free_form(form);
free_screen(NULL, NULL, input_fields);
flush_stdscr();
return rc;
}
int confirm_raid_start(i_container *i_con)
{
struct array_cmd_data *cur_raid_cmd;
struct ipr_ioa *ioa;
int rc, j, k;
char *buffer[2];
struct ipr_dev *dev;
int header_lines;
int toggle = 0;
struct screen_output *s_out;
rc = RC_SUCCESS;
body_init_status(buffer, n_confirm_raid_start.header, &header_lines);
for_each_raid_cmd(cur_raid_cmd) {
if (cur_raid_cmd->do_cmd) {
ioa = cur_raid_cmd->ioa;
dev = cur_raid_cmd->dev;
print_dev(k, dev, buffer, "1", ioa, k);
for (j = 0; j < ioa->num_devices; j++) {
if (ipr_is_af_dasd_device(&ioa->dev[j]) && ioa->dev[j].dev_rcd->issue_cmd)
print_dev(k, &ioa->dev[j], buffer, "1", ioa, k);
}
}
}
toggle_field = 0;
do {
n_confirm_raid_start.body = buffer[toggle&1];
s_out = screen_driver(&n_confirm_raid_start,header_lines,NULL);
toggle++;
} while (s_out->rc == TOGGLE_SCREEN);
rc = s_out->rc;
free(s_out);
for (k=0; k<2; k++) {
free(buffer[k]);
buffer[k] = NULL;
}
n_confirm_raid_start.body = NULL;
if (rc > 0)
return rc;
/* verify the devices are not in use */
for_each_raid_cmd(cur_raid_cmd) {
if (!cur_raid_cmd->do_cmd)
continue;
ioa = cur_raid_cmd->ioa;
rc = is_array_in_use(ioa, cur_raid_cmd->array_id);
if (rc != 0) {
/* "Start Parity Protection failed." */
rc = 19;
syslog(LOG_ERR, _("Devices may have changed state. Command cancelled,"
" please issue commands again if RAID still desired %s.\n"),
ioa->ioa.gen_name);
return rc;
}
}
/* now issue the start array command */
for_each_raid_cmd(cur_raid_cmd) {
if (!cur_raid_cmd->do_cmd)
continue;
ioa = cur_raid_cmd->ioa;
rc = ipr_start_array_protection(ioa,
cur_raid_cmd->stripe_size,
cur_raid_cmd->prot_level);
}
rc = raid_start_complete();
return rc;
}
int raid_start_complete()
{
struct ipr_cmd_status cmd_status;
struct ipr_cmd_status_record *status_record;
int done_bad;
int not_done = 0;
int rc, j;
u32 percent_cmplt = 0;
int device_available = 0;
int wait_device = 0;
int exit_now = 0;
struct ipr_ioa *ioa;
struct array_cmd_data *cur_raid_cmd;
struct ipr_dev *ipr_dev;
struct ipr_disk_attr attr;
while (1) {
rc = complete_screen_driver(&n_raid_start_complete,percent_cmplt,1);
if ((rc & EXIT_FLAG) || exit_now) {
exit_now = 1;
if (device_available)
return EXIT_FLAG;
}
percent_cmplt = 100;
done_bad = 0;
not_done = 0;
for_each_raid_cmd(cur_raid_cmd) {
if (cur_raid_cmd->do_cmd == 0)
continue;
ioa = cur_raid_cmd->ioa;
rc = ipr_query_command_status(&ioa->ioa, &cmd_status);
if (rc) {
done_bad = 1;
continue;
}
status_record = cmd_status.record;
for (j=0; j < cmd_status.num_records; j++, status_record++) {
if ((status_record->command_code != IPR_START_ARRAY_PROTECTION) ||
(cur_raid_cmd->array_id != status_record->array_id))
continue;
if (!device_available &&
(status_record->resource_handle != IPR_IOA_RESOURCE_HANDLE)) {
check_current_config(false);
ipr_dev = get_dev_from_handle(status_record->resource_handle);
if ((ipr_dev) && (ipr_dev->scsi_dev_data)) {
device_available = 1;
ipr_init_new_dev(ipr_dev);
if (ipr_get_dev_attr(ipr_dev, &attr)) {
syslog(LOG_ERR, _("Unable to read queue_depth"));
} else {
attr.queue_depth = cur_raid_cmd->qdepth;
if (ipr_set_dev_attr(ipr_dev, &attr, 1))
syslog(LOG_ERR, _("Unable to set queue_depth"));
}
}
}
if (status_record->status == IPR_CMD_STATUS_IN_PROGRESS) {
if (status_record->percent_complete < percent_cmplt)
percent_cmplt = status_record->percent_complete;
not_done = 1;
} else if (status_record->status != IPR_CMD_STATUS_SUCCESSFUL) {
done_bad = 1;
syslog(LOG_ERR, _("Start parity protect to %s failed. "
"Check device configuration for proper format.\n"),
ioa->ioa.gen_name);
rc = RC_FAILED;
} else if (!(device_available)) {
wait_device++;
/* if device did not show up after
parity set created, allow exit */
if (wait_device == 20)
syslog(LOG_ERR, _("Unable to set queue_depth"));
else
not_done = 1;
}
break;
}
}
if (!not_done) {
flush_stdscr();
if (done_bad)
/* Start Parity Protection failed. */
return 19;
check_current_config(false);
/* Start Parity Protection completed successfully */
return 18;
}
not_done = 0;
sleep(1);
}
}
int raid_rebuild(i_container *i_con)
{
int rc, i, k;
int found = 0;
struct array_cmd_data *cur_raid_cmd;
char *buffer[2];
struct ipr_ioa *ioa;
struct screen_output *s_out;
int header_lines;
int toggle=1;
processing();
i_con = free_i_con(i_con);
rc = RC_SUCCESS;
check_current_config(true);
body_init_status(buffer, n_raid_rebuild.header, &header_lines);
for_each_ioa(ioa) {
ioa->num_raid_cmds = 0;
for (i = 0; i < ioa->num_devices; i++) {
if (!ipr_is_af_dasd_device(&ioa->dev[i]))
continue;
if (!ioa->dev[i].dev_rcd->rebuild_cand)
continue;
add_raid_cmd_tail(ioa, &ioa->dev[i], 0);
i_con = add_i_con(i_con,"\0",raid_cmd_tail);
print_dev(k, &ioa->dev[i], buffer, "%1", ioa, k);
enable_af(&ioa->dev[i]);
found++;
ioa->num_raid_cmds++;
}
}
if (!found) {
/* Start Device Parity Protection Failed */
n_raid_rebuild_fail.body = body_init(n_raid_rebuild_fail.header, NULL);
s_out = screen_driver(&n_raid_rebuild_fail,0,NULL);
free(n_raid_rebuild_fail.body);
n_raid_rebuild_fail.body = NULL;
rc = s_out->rc;
free(s_out);
} else {
do {
n_raid_rebuild.body = buffer[toggle&1];
s_out = screen_driver(&n_raid_rebuild,header_lines,i_con);
toggle++;
} while (s_out->rc == TOGGLE_SCREEN);
rc = s_out->rc;
free(s_out);
cur_raid_cmd = raid_cmd_head;
while(cur_raid_cmd) {
cur_raid_cmd = cur_raid_cmd->next;
free(raid_cmd_head);
raid_cmd_head = cur_raid_cmd;
}
}
for (k = 0; k < 2; k++) {
free(buffer[k]);
buffer[k] = NULL;
}
n_raid_rebuild.body = NULL;
return rc;
}
int confirm_raid_rebuild(i_container *i_con)
{
struct array_cmd_data *cur_raid_cmd;
struct ipr_ioa *ioa;
int rc;
char *buffer[2];
int found = 0;
char *input;
int k;
int header_lines;
int toggle=1;
i_container *temp_i_con;
struct screen_output *s_out;
for_each_icon(temp_i_con) {
cur_raid_cmd = (struct array_cmd_data *)temp_i_con->data;
if (!cur_raid_cmd)
continue;
input = temp_i_con->field_data;
if (strcmp(input, "1") == 0) {
cur_raid_cmd->do_cmd = 1;
if (cur_raid_cmd->dev->dev_rcd)
cur_raid_cmd->dev->dev_rcd->issue_cmd = 1;
found++;
} else {
cur_raid_cmd->do_cmd = 0;
if (cur_raid_cmd->dev->dev_rcd)
cur_raid_cmd->dev->dev_rcd->issue_cmd = 0;
}
}
if (!found)
return INVALID_OPTION_STATUS;
body_init_status(buffer, n_confirm_raid_rebuild.header, &header_lines);
for_each_raid_cmd(cur_raid_cmd) {
if (!cur_raid_cmd->do_cmd)
continue;
ioa = cur_raid_cmd->ioa;
print_dev(k, cur_raid_cmd->dev, buffer, "1", ioa, k);
}
do {
n_confirm_raid_rebuild.body = buffer[toggle&1];
s_out = screen_driver(&n_confirm_raid_rebuild,header_lines,NULL);
toggle++;
} while (s_out->rc == TOGGLE_SCREEN);
rc = s_out->rc;
free(s_out);
for (k = 0; k < 2; k++) {
free(buffer[k]);
buffer[k] = NULL;
}
n_confirm_raid_rebuild.body = NULL;
if (rc)
return rc;
for_each_ioa(ioa) {
if (ioa->num_raid_cmds == 0)
continue;
if ((rc = ipr_rebuild_device_data(ioa)))
/* Rebuild failed */
return (29 | EXIT_FLAG);
}
/* Rebuild started, view Parity Status Window for rebuild progress */
return (28 | EXIT_FLAG);
}
int raid_include(i_container *i_con)
{
int i, k;
int found = 0;
struct ipr_array_record *array_rcd;
struct array_cmd_data *cur_raid_cmd;
char *buffer[2];
struct ipr_ioa *ioa;
int include_allowed;
struct ipr_array_cap_entry *cap_entry;
int rc = RC_SUCCESS;
struct screen_output *s_out;
int header_lines;
int toggle = 1;
processing();
i_con = free_i_con(i_con);
check_current_config(false);
body_init_status(buffer, n_raid_include.header, &header_lines);
for_each_ioa(ioa) {
for (i = 0; i < ioa->num_devices; i++) {
if (!ipr_is_volume_set(&ioa->dev[i]) || ioa->is_secondary)
continue;
array_rcd = ioa->dev[i].array_rcd;
include_allowed = 0;
cap_entry = get_raid_cap_entry(ioa->supported_arrays,
array_rcd->raid_level);
if (cap_entry) {
if (cap_entry->include_allowed)
include_allowed = 1;
strncpy(ioa->dev[i].prot_level_str,
cap_entry->prot_level_str, 8);
}
if (!include_allowed || !array_rcd->established)
continue;
add_raid_cmd_tail(ioa, &ioa->dev[i], array_rcd->array_id);
i_con = add_i_con(i_con,"\0",raid_cmd_tail);
print_dev(k, &ioa->dev[i], buffer, "%1", ioa, k);
found++;
}
}
if (!found) {
/* Include Device Parity Protection Failed */
n_raid_include_fail.body = body_init(n_raid_include_fail.header, NULL);
s_out = screen_driver(&n_raid_include_fail,0,i_con);
free(n_raid_include_fail.body);
n_raid_include_fail.body = NULL;
rc = s_out->rc;
free(s_out);
} else {
toggle_field = 0;
do {
n_raid_include.body = buffer[toggle&1];
s_out = screen_driver(&n_raid_include,header_lines,i_con);
toggle++;
} while (s_out->rc == TOGGLE_SCREEN);
rc = s_out->rc;
free(s_out);
cur_raid_cmd = raid_cmd_head;
while(cur_raid_cmd) {
if (cur_raid_cmd->qac) {
free(cur_raid_cmd->qac);
cur_raid_cmd->qac = NULL;
}
cur_raid_cmd = cur_raid_cmd->next;
free(raid_cmd_head);
raid_cmd_head = cur_raid_cmd;
}
}
for (k = 0; k < 2; k++) {
free(buffer[k]);
buffer[k] = NULL;
}
n_raid_include.body = NULL;
return rc;
}
int configure_raid_include(i_container *i_con)
{
int j, k, i;
int found = 0;
struct array_cmd_data *cur_raid_cmd;
struct ipr_array_query_data *qac_data = calloc(1,sizeof(struct ipr_array_query_data));
struct ipr_common_record *common_record;
struct ipr_dev_record *device_record;
struct scsi_dev_data *scsi_dev_data;
char *buffer[2];
struct ipr_ioa *ioa;
char *input;
struct ipr_dev *dev;
struct ipr_array_cap_entry *cap_entry;
u8 min_mult_array_devices = 1;
int rc = RC_SUCCESS;
int header_lines;
i_container *temp_i_con;
int toggle = 0;
struct screen_output *s_out;
for_each_icon(temp_i_con) {
cur_raid_cmd = i_con->data;
if (!cur_raid_cmd)
continue;
input = temp_i_con->field_data;
if (strcmp(input, "1") == 0) {
found++;
cur_raid_cmd->do_cmd = 1;
break;
}
}
if (found != 1)
return INVALID_OPTION_STATUS;
i_con = free_i_con(i_con);
body_init_status(buffer, n_configure_raid_include.header, &header_lines);
ioa = cur_raid_cmd->ioa;
dev = cur_raid_cmd->dev;
/* Get Query Array Config Data */
rc = ipr_query_array_config(ioa, 0, 1, cur_raid_cmd->array_id, qac_data);
found = 0;
if (rc != 0)
free(qac_data);
else {
cur_raid_cmd->qac = qac_data;
for_each_qac_entry(common_record, i, qac_data) {
if (common_record->record_id == IPR_RECORD_ID_DEVICE_RECORD) {
for (j = 0; j < ioa->num_devices; j++) {
scsi_dev_data = ioa->dev[j].scsi_dev_data;
device_record = (struct ipr_dev_record *)common_record;
if (!scsi_dev_data)
continue;
if (scsi_dev_data->handle == device_record->resource_handle &&
scsi_dev_data->opens == 0 &&
device_record->include_cand &&
device_supported(&ioa->dev[j])) {
ioa->dev[j].qac_entry = common_record;
i_con = add_i_con(i_con,"\0",&ioa->dev[j]);
print_dev(k, &ioa->dev[j], buffer, "%1", ioa, k);
found++;
break;
}
}
}
/* find minimum multiple for the raid level being used */
if (common_record->record_id == IPR_RECORD_ID_SUPPORTED_ARRAYS) {
cap_entry = get_raid_cap_entry((struct ipr_supported_arrays *)common_record,
dev->array_rcd->raid_level);
if (cap_entry)
min_mult_array_devices = cap_entry->min_mult_array_devices;
}
}
}
if (found < min_mult_array_devices) {
/* Include Device Parity Protection Failed */
n_configure_raid_include_fail.body = body_init(n_configure_raid_include_fail.header, NULL);
s_out = screen_driver(&n_configure_raid_include_fail,0,i_con);
free(n_configure_raid_include_fail.body);
n_configure_raid_include_fail.body = NULL;
rc = s_out->rc;
free(s_out);
return rc;
}
toggle_field = 0;
do {
n_configure_raid_include.body = buffer[toggle&1];
s_out = screen_driver(&n_configure_raid_include,header_lines,i_con);
toggle++;
} while (s_out->rc == TOGGLE_SCREEN);
for (k = 0; k < 2; k++) {
free(buffer[k]);
buffer[k] = NULL;
}
n_configure_raid_include.body = NULL;
i_con = s_out->i_con;
if ((rc = s_out->rc) > 0)
goto leave;
/* first, count devices select to be sure min multiple
is satisfied */
found = 0;
for_each_icon(temp_i_con) {
input = temp_i_con->field_data;
if (strcmp(input, "1") == 0)
found++;
}
if (found % min_mult_array_devices != 0) {
/* "Error: number of devices selected must be a multiple of %d" */
s_status.num = min_mult_array_devices;
return 25 | REFRESH_FLAG;
}
for_each_icon(temp_i_con) {
dev = (struct ipr_dev *)temp_i_con->data;
if (!dev)
continue;
input = temp_i_con->field_data;
if (strcmp(input, "1") == 0) {
if (!dev->dev_rcd->issue_cmd) {
dev->dev_rcd->issue_cmd = 1;
dev->dev_rcd->known_zeroed = 1;
}
} else {
if (dev->dev_rcd->issue_cmd) {
dev->dev_rcd->issue_cmd = 0;
dev->dev_rcd->known_zeroed = 0;
}
}
}
rc = confirm_raid_include(i_con);
leave:
free(s_out);
return rc;
}
int confirm_raid_include(i_container *i_con)
{
struct array_cmd_data *cur_raid_cmd;
struct ipr_ioa *ioa;
struct ipr_dev *dev;
int i, k;
char *buffer[2];
int rc = RC_SUCCESS;
struct screen_output *s_out;
int num_devs = 0;
int dev_include_complete(u8 num_devs);
int format_include_cand();
int header_lines;
int toggle = 0;
int need_formats = 0;
body_init_status(buffer, n_confirm_raid_include.header, &header_lines);
for_each_raid_cmd(cur_raid_cmd) {
if (!cur_raid_cmd->qac)
continue;
ioa = cur_raid_cmd->ioa;
for (i = 0, dev = ioa->dev; i < ioa->num_devices; i++, dev++) {
if (!dev->qac_entry)
continue;
if (dev->qac_entry->record_id != IPR_RECORD_ID_DEVICE_RECORD)
continue;
if (!dev->dev_rcd->issue_cmd)
continue;
print_dev(k, dev, buffer, "1", ioa, k);
if (!ipr_device_is_zeroed(dev))
need_formats = 1;
num_devs++;
}
}
do {
n_confirm_raid_include.body = buffer[toggle&1];
s_out = screen_driver(&n_confirm_raid_include, header_lines, NULL);
toggle++;
} while (s_out->rc == TOGGLE_SCREEN);
rc = s_out->rc;
free(s_out);
for (k = 0; k < 2; k++) {
free(buffer[k]);
buffer[k] = NULL;
}
n_confirm_raid_include.body = NULL;
if (rc)
return rc;
/* now format each of the devices */
if (need_formats)
num_devs = format_include_cand();
rc = dev_include_complete(num_devs);
free_devs_to_init();
return rc;
}
int format_include_cand()
{
struct scsi_dev_data *scsi_dev_data;
struct array_cmd_data *cur_raid_cmd;
struct ipr_ioa *ioa;
int num_devs = 0;
int rc = 0;
struct ipr_dev_record *device_record;
int i, opens = 0;
for_each_raid_cmd(cur_raid_cmd) {
if (!cur_raid_cmd->do_cmd)
continue;
ioa = cur_raid_cmd->ioa;
for (i = 0; i < ioa->num_devices; i++) {
device_record = ioa->dev[i].dev_rcd;
if (!device_record || !device_record->issue_cmd)
continue;
/* get current "opens" data for this device to determine conditions to continue */
scsi_dev_data = ioa->dev[i].scsi_dev_data;
if (scsi_dev_data)
opens = num_device_opens(scsi_dev_data->host,
scsi_dev_data->channel,
scsi_dev_data->id,
scsi_dev_data->lun);
if (opens != 0) {
syslog(LOG_ERR,_("Include Device not allowed, device in use - %s\n"),
ioa->dev[i].gen_name);
device_record->issue_cmd = 0;
continue;
}
if (dev_init_head) {
dev_init_tail->next = malloc(sizeof(struct devs_to_init_t));
dev_init_tail = dev_init_tail->next;
} else
dev_init_head = dev_init_tail =
malloc(sizeof(struct devs_to_init_t));
memset(dev_init_tail, 0, sizeof(struct devs_to_init_t));
dev_init_tail->ioa = ioa;
dev_init_tail->dev = &ioa->dev[i];
dev_init_tail->do_init = 1;
/* Issue the format. Failure will be detected by query command status */
rc = ipr_format_unit(dev_init_tail->dev);
num_devs++;
}
}
return num_devs;
}
static int update_include_qac_data(struct ipr_array_query_data *old_qac,
struct ipr_array_query_data *new_qac)
{
struct ipr_dev_record *old_dev_rcd, *new_dev_rcd;
int found, i, j;
for_each_dev_rcd(old_dev_rcd, i, old_qac) {
if (!old_dev_rcd->issue_cmd)
continue;
found = 0;
for_each_dev_rcd(new_dev_rcd, j, new_qac) {
if (new_dev_rcd->resource_handle != old_dev_rcd->resource_handle)
continue;
new_dev_rcd->issue_cmd = 1;
new_dev_rcd->known_zeroed = 1;
found = 1;
break;
}
if (!found)
return 26;
}
return 0;
}
int dev_include_complete(u8 num_devs)
{
int done_bad;
struct ipr_cmd_status cmd_status;
struct ipr_cmd_status_record *status_record;
int not_done = 0;
int rc, j, fd;
struct devs_to_init_t *cur_dev_init;
u32 percent_cmplt = 0;
struct ipr_ioa *ioa;
struct array_cmd_data *cur_raid_cmd;
struct ipr_common_record *common_record;
struct ipr_array_query_data qac_data;
n_dev_include_complete.body = n_dev_include_complete.header[0];
while(1) {
complete_screen_driver(&n_dev_include_complete, percent_cmplt,0);
percent_cmplt = 100;
done_bad = 0;
for_each_dev_to_init(cur_dev_init) {
if (cur_dev_init->do_init) {
rc = ipr_query_command_status(cur_dev_init->dev, &cmd_status);
if (rc || cmd_status.num_records == 0) {
cur_dev_init->cmplt = 100;
continue;
}
status_record = cmd_status.record;
if (status_record->status == IPR_CMD_STATUS_FAILED) {
cur_dev_init->cmplt = 100;
done_bad = 1;
} else if (status_record->status != IPR_CMD_STATUS_SUCCESSFUL) {
cur_dev_init->cmplt = status_record->percent_complete;
if (cur_dev_init->cmplt < percent_cmplt)
percent_cmplt = cur_dev_init->cmplt;
not_done = 1;
}
}
}
if (!not_done) {
flush_stdscr();
if (done_bad) {
/* "Include failed" */
rc = 26;
return rc | EXIT_FLAG;
}
break;
}
not_done = 0;
sleep(1);
}
complete_screen_driver(&n_dev_include_complete, percent_cmplt, 0);
/* now issue the start array command with "known to be zero" */
for_each_raid_cmd(cur_raid_cmd) {
if (!cur_raid_cmd->do_cmd)
continue;
ioa = cur_raid_cmd->ioa;
memset(&qac_data, 0, sizeof(qac_data));
fd = open(ioa->ioa.gen_name, O_RDWR);
if (fd <= 1) {
rc = 26;
continue;
}
rc = flock(fd, LOCK_EX);
if (rc) {
rc = 26;
close(fd);
continue;
}
rc = __ipr_query_array_config(ioa, fd, 0, 1,
cur_raid_cmd->array_id, &qac_data);
if (rc != 0) {
rc = 26;
close(fd);
continue;
}
rc = update_include_qac_data(cur_raid_cmd->qac, &qac_data);
if (rc != 0) {
close(fd);
continue;
}
rc = ipr_add_array_device(ioa, fd, &qac_data);
if (rc != 0)
rc = 26;
close(fd);
}
not_done = 0;
percent_cmplt = 0;
n_dev_include_complete.body = n_dev_include_complete.header[1];
while(1) {
complete_screen_driver(&n_dev_include_complete, percent_cmplt, 1);
percent_cmplt = 100;
done_bad = 0;
for_each_raid_cmd(cur_raid_cmd) {
ioa = cur_raid_cmd->ioa;
rc = ipr_query_command_status(&ioa->ioa, &cmd_status);
if (rc) {
done_bad = 1;
continue;
}
status_record = cmd_status.record;
for (j=0; j < cmd_status.num_records; j++, status_record++) {
if (status_record->command_code == IPR_ADD_ARRAY_DEVICE &&
cur_raid_cmd->array_id == status_record->array_id) {
if (status_record->status == IPR_CMD_STATUS_IN_PROGRESS) {
if (status_record->percent_complete < percent_cmplt)
percent_cmplt = status_record->percent_complete;
not_done = 1;
} else if (status_record->status != IPR_CMD_STATUS_SUCCESSFUL)
/* "Include failed" */
rc = 26;
break;
}
}
}
if (!not_done) {
/* Call ioctl() to re-read partition table to handle change in size */
for_each_raid_cmd(cur_raid_cmd) {
if (!cur_raid_cmd->do_cmd)
continue;
common_record = cur_raid_cmd->dev->qac_entry;
if (common_record &&
common_record->record_id == IPR_RECORD_ID_ARRAY_RECORD)
rc = ipr_write_dev_attr(cur_raid_cmd->dev, "rescan", "1");
}
flush_stdscr();
if (done_bad)
/* "Include failed" */
return 26 | EXIT_FLAG;
/* "Include Unit completed successfully" */
complete_screen_driver(&n_dev_include_complete, percent_cmplt,1);
return 27 | EXIT_FLAG;
}
not_done = 0;
sleep(1);
}
}
static void add_format_device(struct ipr_dev *dev, int blk_size)
{
if (dev_init_head) {
dev_init_tail->next = malloc(sizeof(struct devs_to_init_t));
dev_init_tail = dev_init_tail->next;
}
else
dev_init_head = dev_init_tail = malloc(sizeof(struct devs_to_init_t));
memset(dev_init_tail, 0, sizeof(struct devs_to_init_t));
dev_init_tail->ioa = dev->ioa;
if (ipr_is_af_dasd_device(dev))
dev_init_tail->dev_type = IPR_AF_DASD_DEVICE;
else
dev_init_tail->dev_type = IPR_JBOD_DASD_DEVICE;
dev_init_tail->new_block_size = blk_size;
dev_init_tail->dev = dev;
}
static int configure_af_device(i_container *i_con, int action_code)
{
int rc, j, k;
struct scsi_dev_data *scsi_dev_data;
int can_init;
int dev_type;
int new_block_size;
char *buffer[2];
int num_devs = 0;
struct ipr_ioa *ioa;
int toggle = 0;
int header_lines;
s_node *n_screen;
struct screen_output *s_out;
processing();
i_con = free_i_con(i_con);
rc = RC_SUCCESS;
check_current_config(false);
/* Setup screen title */
if (action_code == IPR_INCLUDE)
n_screen = &n_af_init_device;
else
n_screen = &n_jbod_init_device;
body_init_status(buffer, n_screen->header, &header_lines);
for_each_ioa(ioa) {
if (ioa->is_secondary)
continue;
for (j = 0; j < ioa->num_devices; j++) {
can_init = 1;
scsi_dev_data = ioa->dev[j].scsi_dev_data;
/* If not a DASD, disallow format */
if (!scsi_dev_data ||
ipr_is_hot_spare(&ioa->dev[j]) ||
ipr_is_volume_set(&ioa->dev[j]) ||
!device_supported(&ioa->dev[j]) ||
(scsi_dev_data->type != TYPE_DISK &&
scsi_dev_data->type != IPR_TYPE_AF_DISK))
continue;
/* If Advanced Function DASD */
if (ipr_is_af_dasd_device(&ioa->dev[j])) {
if (action_code == IPR_INCLUDE) {
if (ipr_device_is_zeroed(&ioa->dev[j]))
continue;
new_block_size = 0;
} else
new_block_size = IPR_JBOD_BLOCK_SIZE;
dev_type = IPR_AF_DASD_DEVICE;
/* We allow the user to format the drive if nobody is using it */
if (ioa->dev[j].scsi_dev_data->opens != 0) {
syslog(LOG_ERR, _("Format not allowed to %s, device in use\n"), ioa->dev[j].gen_name);
continue;
}
if (ipr_is_array_member(&ioa->dev[j])) {
if (ioa->dev[j].dev_rcd->no_cfgte_vol)
can_init = 1;
else
can_init = 0;
} else
can_init = is_format_allowed(&ioa->dev[j]);
} else if (scsi_dev_data->type == TYPE_DISK){
/* If on a JBOD adapter */
if (!ioa->qac_data->num_records) {
if (action_code != IPR_REMOVE)
continue;
} else if (is_af_blocked(&ioa->dev[j], 0))
continue;
if (action_code == IPR_REMOVE && !format_req(&ioa->dev[j]))
continue;
if (action_code == IPR_REMOVE)
new_block_size = IPR_JBOD_BLOCK_SIZE;
else
new_block_size = ioa->af_block_size;
dev_type = IPR_JBOD_DASD_DEVICE;
/* We allow the user to format the drive if nobody is using it, or
the device is read write protected. If the drive fails, then is replaced
concurrently it will be read write protected, but the system may still
have a use count for it. We need to allow the format to get the device
into a state where the system can use it */
if (ioa->dev[j].scsi_dev_data->opens != 0) {
syslog(LOG_ERR, _("Format not allowed to %s, device in use\n"), ioa->dev[j].gen_name);
continue;
}
can_init = is_format_allowed(&ioa->dev[j]);
} else
continue;
if (can_init) {
add_format_device(&ioa->dev[j], new_block_size);
print_dev(k, &ioa->dev[j], buffer, "%1", ioa, k);
i_con = add_i_con(i_con,"\0",dev_init_tail);
num_devs++;
}
}
}
if (!num_devs) {
if (action_code == IPR_INCLUDE) {
n_af_include_fail.body = body_init(n_af_include_fail.header, NULL);
s_out = screen_driver(&n_af_include_fail,0,i_con);
free(n_af_include_fail.body);
n_af_include_fail.body = NULL;
} else {
n_af_remove_fail.body = body_init(n_af_remove_fail.header, NULL);
s_out = screen_driver(&n_af_remove_fail,0,i_con);
free(n_af_remove_fail.body);
n_af_remove_fail.body = NULL;
}
} else {
toggle_field = 0;
do {
n_screen->body = buffer[toggle&1];
s_out = screen_driver(n_screen,header_lines,i_con);
toggle++;
} while (s_out->rc == TOGGLE_SCREEN);
free_devs_to_init();
}
rc = s_out->rc;
free(s_out);
for (k=0; k<2; k++) {
free(buffer[k]);
buffer[k] = NULL;
}
n_screen->body = NULL;
return rc;
}
int af_include(i_container *i_con)
{
int rc;
rc = configure_af_device(i_con, IPR_INCLUDE);
return rc;
}
int af_remove(i_container *i_con)
{
int rc;
rc = configure_af_device(i_con, IPR_REMOVE);
return rc;
}
int add_hot_spare(i_container *i_con)
{
int rc;
do {
rc = hot_spare(i_con, IPR_ADD_HOT_SPARE);
} while (rc & REFRESH_FLAG);
return rc;
}
int remove_hot_spare(i_container *i_con)
{
int rc;
do {
rc = hot_spare(i_con, IPR_RMV_HOT_SPARE);
} while (rc & REFRESH_FLAG);
return rc;
}
int hot_spare(i_container *i_con, int action)
{
int rc, i, k;
struct array_cmd_data *cur_raid_cmd;
char *buffer[2];
struct ipr_ioa *ioa;
int found = 0;
char *input;
int toggle = 0;
i_container *temp_i_con;
struct screen_output *s_out;
s_node *n_screen;
int header_lines;
processing();
i_con = free_i_con(i_con);
rc = RC_SUCCESS;
check_current_config(false);
if (action == IPR_ADD_HOT_SPARE)
n_screen = &n_add_hot_spare;
else
n_screen = &n_remove_hot_spare;
body_init_status(buffer, n_screen->header, &header_lines);
for_each_ioa(ioa) {
for (i = 0; i < ioa->num_devices; i++) {
if (!ipr_is_af_dasd_device(&ioa->dev[i]))
continue;
if ((action == IPR_ADD_HOT_SPARE &&
ioa->dev[i].dev_rcd->add_hot_spare_cand) ||
(action == IPR_RMV_HOT_SPARE &&
ioa->dev[i].dev_rcd->rmv_hot_spare_cand)) {
add_raid_cmd_tail(ioa, NULL, 0);
i_con = add_i_con(i_con,"\0",raid_cmd_tail);
print_dev(k, &ioa->ioa, buffer, "%1", ioa, k);
found++;
break;
}
}
}
if (!found)
{
if (action == IPR_ADD_HOT_SPARE) {
n_add_hot_spare_fail.body = body_init(n_add_hot_spare_fail.header, NULL);
s_out = screen_driver(&n_add_hot_spare_fail,0,i_con);
free(n_add_hot_spare_fail.body);
n_add_hot_spare_fail.body = NULL;
} else {
n_remove_hot_spare_fail.body = body_init(n_remove_hot_spare_fail.header, NULL);
s_out = screen_driver(&n_remove_hot_spare_fail,0,i_con);
free(n_remove_hot_spare_fail.body);
n_remove_hot_spare_fail.body = NULL;
}
rc = EXIT_FLAG;
goto leave;
}
do {
n_screen->body = buffer[toggle&1];
s_out = screen_driver(n_screen,header_lines,i_con);
toggle++;
} while (s_out->rc == TOGGLE_SCREEN);
rc = s_out->rc;
free(s_out);
i_con = s_out->i_con;
if (rc > 0) {
rc = EXIT_FLAG;
goto leave;
}
found = 0;
for_each_icon(temp_i_con) {
cur_raid_cmd = (struct array_cmd_data *)temp_i_con->data;
if (cur_raid_cmd) {
input = temp_i_con->field_data;
if (strcmp(input, "1") == 0) {
do {
rc = select_hot_spare(temp_i_con, action);
} while (rc & REFRESH_FLAG);
if (rc > 0)
goto leave;
found = 1;
cur_raid_cmd->do_cmd = 1;
} else {
cur_raid_cmd->do_cmd = 0;
}
}
}
if (found) {
/* Go to verification screen */
rc = confirm_hot_spare(action);
} else
rc = REFRESH_FLAG | INVALID_OPTION_STATUS;
leave:
if (rc & CANCEL_FLAG) {
s_status.index = (rc & ~CANCEL_FLAG);
rc = (rc | REFRESH_FLAG) & ~CANCEL_FLAG;
}
i_con = free_i_con(i_con);
for (k = 0; k < 2; k++) {
free(buffer[k]);
buffer[k] = NULL;
}
n_screen->body = NULL;
cur_raid_cmd = raid_cmd_head;
while(cur_raid_cmd) {
cur_raid_cmd = cur_raid_cmd->next;
free(raid_cmd_head);
raid_cmd_head = cur_raid_cmd;
}
return rc;
}
int select_hot_spare(i_container *i_con, int action)
{
struct array_cmd_data *cur_raid_cmd;
int rc, j, k, found;
char *buffer[2];
int num_devs = 0;
struct ipr_ioa *ioa;
char *input;
struct ipr_dev *ipr_dev;
struct scsi_dev_data *scsi_dev_data;
struct ipr_dev_record *device_record;
i_container *temp_i_con,*i_con2 = NULL;
struct screen_output *s_out = NULL;
int header_lines;
s_node *n_screen;
int toggle = 0;
i_container *i_con_head_saved;
if (action == IPR_ADD_HOT_SPARE)
n_screen = &n_select_add_hot_spare;
else
n_screen = &n_select_remove_hot_spare;
body_init_status(buffer, n_screen->header, &header_lines);
cur_raid_cmd = (struct array_cmd_data *) i_con->data;
rc = RC_SUCCESS;
ioa = cur_raid_cmd->ioa;
i_con_head_saved = i_con_head; /* FIXME */
i_con_head = NULL;
for (j = 0; j < ioa->num_devices; j++) {
scsi_dev_data = ioa->dev[j].scsi_dev_data;
device_record = ioa->dev[j].dev_rcd;
if (!scsi_dev_data || !device_record)
continue;
if (ipr_is_af_dasd_device(&ioa->dev[j]) &&
device_supported(&ioa->dev[j]) &&
((device_record->add_hot_spare_cand && action == IPR_ADD_HOT_SPARE) ||
(device_record->rmv_hot_spare_cand && action == IPR_RMV_HOT_SPARE))) {
i_con2 = add_i_con(i_con2,"\0",&ioa->dev[j]);
print_dev(k, &ioa->dev[j], buffer, "%1", ioa, k);
num_devs++;
}
}
if (num_devs) {
do {
n_screen->body = buffer[toggle&1];
s_out = screen_driver(n_screen,header_lines,i_con2);
toggle++;
} while (s_out->rc == TOGGLE_SCREEN);
for (k = 0; k < 2; k++) {
free(buffer[k]);
buffer[k] = NULL;
}
n_screen->body = NULL;
rc = s_out->rc;
i_con2 = s_out->i_con;
if (rc > 0)
goto leave;
found = 0;
for_each_icon(temp_i_con) {
ipr_dev = (struct ipr_dev *)temp_i_con->data;
if (ipr_dev != NULL) {
input = temp_i_con->field_data;
if (strcmp(input, "1") == 0) {
found = 1;
ipr_dev->dev_rcd->issue_cmd = 1;
}
}
}
if (found)
rc = RC_SUCCESS;
else {
s_status.index = INVALID_OPTION_STATUS;
rc = REFRESH_FLAG;
}
} else
/* "No devices available for the selected hot spare operation" */
rc = 52 | CANCEL_FLAG;
leave:
i_con2 = free_i_con(i_con2);
i_con_head = i_con_head_saved;
free(s_out);
return rc;
}
int confirm_hot_spare(int action)
{
struct array_cmd_data *cur_raid_cmd;
struct ipr_ioa *ioa;
int rc, j, k;
char *buffer[2];
int hot_spare_complete(int action);
struct screen_output *s_out;
s_node *n_screen;
int header_lines;
int toggle = 0;
rc = RC_SUCCESS;
if (action == IPR_ADD_HOT_SPARE)
n_screen = &n_confirm_add_hot_spare;
else
n_screen = &n_confirm_remove_hot_spare;
body_init_status(buffer, n_screen->header, &header_lines);
for_each_raid_cmd(cur_raid_cmd) {
if (!cur_raid_cmd->do_cmd)
continue;
ioa = cur_raid_cmd->ioa;
for (j = 0; j < ioa->num_devices; j++) {
if (ipr_is_af_dasd_device(&ioa->dev[j]) && ioa->dev[j].dev_rcd->issue_cmd)
print_dev(k, &ioa->dev[j], buffer, "1", ioa, k);
}
}
do {
n_screen->body = buffer[toggle&1];
s_out = screen_driver(n_screen,header_lines,NULL);
toggle++;
} while (s_out->rc == TOGGLE_SCREEN);
for (k = 0; k < 2; k++) {
free(buffer[k]);
buffer[k] = NULL;
}
n_screen->body = NULL;
rc = s_out->rc;
free(s_out);
if(rc > 0)
goto leave;
rc = hot_spare_complete(action);
leave:
return rc;
}
int hot_spare_complete(int action)
{
int rc;
struct ipr_ioa *ioa;
struct array_cmd_data *cmd;
for_each_ioa(ioa) {
for_each_raid_cmd(cmd) {
if (cmd->do_cmd == 0 || ioa != cmd->ioa)
continue;
flush_stdscr();
if (action == IPR_ADD_HOT_SPARE)
rc = ipr_add_hot_spare(ioa);
else
rc = ipr_remove_hot_spare(ioa);
if (rc != 0) {
if (action == IPR_ADD_HOT_SPARE)
/* Enable Device as Hot Spare failed */
return 55 | EXIT_FLAG;
else
/* Disable Device as Hot Spare failed */
return 56 | EXIT_FLAG;
}
}
}
flush_stdscr();
if (action == IPR_ADD_HOT_SPARE)
/* "Enable Device as Hot Spare Completed successfully" */
rc = 53 | EXIT_FLAG;
else
/* "Disable Device as Hot Spare Completed successfully" */
rc = 54 | EXIT_FLAG;
return rc;
}
int disk_unit_recovery(i_container *i_con)
{
int rc;
struct screen_output *s_out;
int loop;
for (loop = 0; loop < n_disk_unit_recovery.num_opts; loop++) {
n_disk_unit_recovery.body = ipr_list_opts(n_disk_unit_recovery.body,
n_disk_unit_recovery.options[loop].key,
n_disk_unit_recovery.options[loop].list_str);
}
n_disk_unit_recovery.body = ipr_end_list(n_disk_unit_recovery.body);
s_out = screen_driver(&n_disk_unit_recovery,0,NULL);
free(n_disk_unit_recovery.body);
n_disk_unit_recovery.body = NULL;
rc = s_out->rc;
free(s_out);
return rc;
}
static void get_res_addr(struct ipr_dev *dev, struct ipr_res_addr *res_addr)
{
struct ipr_dev_record *dev_record;
struct ipr_array_record *array_record;
if (dev->scsi_dev_data) {
res_addr->host = dev->scsi_dev_data->host;
res_addr->bus = dev->scsi_dev_data->channel;
res_addr->target = dev->scsi_dev_data->id;
res_addr->lun = dev->scsi_dev_data->lun;
} else if (ipr_is_af_dasd_device(dev)) {
dev_record = dev->dev_rcd;
if (dev_record && dev_record->no_cfgte_dev) {
res_addr->host = dev->ioa->host_num;
res_addr->bus = dev_record->last_resource_addr.bus;
res_addr->target = dev_record->last_resource_addr.target;
res_addr->lun = dev_record->last_resource_addr.lun;
} else if (dev_record) {
res_addr->host = dev->ioa->host_num;
res_addr->bus = dev_record->resource_addr.bus;
res_addr->target = dev_record->resource_addr.target;
res_addr->lun = dev_record->resource_addr.lun;
}
} else if (ipr_is_volume_set(dev)) {
array_record = dev->array_rcd;
if (array_record && array_record->no_config_entry) {
res_addr->host = dev->ioa->host_num;
res_addr->bus = array_record->last_resource_addr.bus;
res_addr->target = array_record->last_resource_addr.target;
res_addr->lun = array_record->last_resource_addr.lun;
} else if (dev_record) {
res_addr->host = dev->ioa->host_num;
res_addr->bus = array_record->resource_addr.bus;
res_addr->target = array_record->resource_addr.target;
res_addr->lun = array_record->resource_addr.lun;
}
}
}
int process_conc_maint(i_container *i_con, int action)
{
i_container *temp_i_con;
int found = 0;
struct ipr_dev *ipr_dev;
char *input;
struct ipr_ioa *ioa;
int i, j, k, rc;
struct scsi_dev_data *scsi_dev_data;
struct ipr_dev_record *dev_rcd;
struct ipr_encl_status_ctl_pg ses_data;
char *buffer[2];
int header_lines;
int toggle=1;
s_node *n_screen;
struct screen_output *s_out;
struct ipr_res_addr res_addr;
int time = 12;
int max_y, max_x;
for_each_icon(temp_i_con) {
input = temp_i_con->field_data;
if (strcmp(input, "1") == 0) {
ipr_dev = (struct ipr_dev *)temp_i_con->data;
if (ipr_dev != NULL)
found++;
}
}
if (found != 1)
return INVALID_OPTION_STATUS;
get_res_addr(ipr_dev, &res_addr);
if (ipr_is_af_dasd_device(ipr_dev) &&
(action == IPR_VERIFY_CONC_REMOVE || action == IPR_WAIT_CONC_REMOVE)) {
/* issue suspend device bus to verify operation
is allowable */
rc = ipr_suspend_device_bus(ipr_dev->ioa, &res_addr,
IPR_SDB_CHECK_ONLY);
if (rc)
return INVALID_OPTION_STATUS; /* FIXME */
} else if (num_device_opens(res_addr.host, res_addr.bus,
res_addr.target, res_addr.lun))
return INVALID_OPTION_STATUS; /* FIXME */
ioa = ipr_dev->ioa;
/* flash light at location of specified device */
for (j = 0; j < ioa->num_devices; j++) {
scsi_dev_data = ioa->dev[j].scsi_dev_data;
if (!scsi_dev_data || scsi_dev_data->type != TYPE_ENCLOSURE)
continue;
rc = ipr_receive_diagnostics(&ioa->dev[j], 2, &ses_data,
sizeof(struct ipr_encl_status_ctl_pg));
if (rc || res_addr.bus != scsi_dev_data->channel)
continue;
found = 0;
for_each_elem_status(i, &ses_data) {
if (res_addr.target == ses_data.elem_status[i].scsi_id) {
found++;
if ((action == IPR_VERIFY_CONC_REMOVE) ||
(action == IPR_VERIFY_CONC_ADD)) {
ses_data.elem_status[i].select = 1;
ses_data.elem_status[i].identify = 1;
} else if (action == IPR_WAIT_CONC_REMOVE) {
ses_data.elem_status[i].select = 1;
ses_data.elem_status[i].remove = 1;
} else if (action == IPR_WAIT_CONC_ADD) {
ses_data.elem_status[i].select = 1;
ses_data.elem_status[i].insert = 1;
}
break;
}
}
break;
}
if (!found)
return INVALID_OPTION_STATUS;
if (action == IPR_WAIT_CONC_REMOVE || action == IPR_WAIT_CONC_ADD) {
ses_data.overall_status_select = 1;
ses_data.overall_status_disable_resets = 1;
ses_data.overall_status_insert = 0;
ses_data.overall_status_remove = 0;
ses_data.overall_status_identify = 0;
}
rc = ipr_send_diagnostics(&ioa->dev[j], &ses_data,
sizeof(struct ipr_encl_status_ctl_pg));
if (rc)
return 30 | EXIT_FLAG;
if (action == IPR_VERIFY_CONC_REMOVE)
n_screen = &n_verify_conc_remove;
else if (action == IPR_VERIFY_CONC_ADD)
n_screen = &n_verify_conc_add;
else if (action == IPR_WAIT_CONC_REMOVE)
n_screen = &n_wait_conc_remove;
else
n_screen = &n_wait_conc_add;
processing();
for (k = 0; k < 2; k++) {
buffer[k] = __body_init_status(n_screen->header, &header_lines, k);
buffer[k] = print_device(ipr_dev, buffer[k], "1", ioa, k);
}
/* call screen driver */
do {
n_screen->body = buffer[toggle&1];
s_out = screen_driver(n_screen,header_lines,i_con);
toggle++;
} while (s_out->rc == TOGGLE_SCREEN);
rc = s_out->rc;
for (k = 0; k < 2; k++) {
free(buffer[k]);
buffer[k] = NULL;
}
n_screen->body = NULL;
/* turn light off flashing light */
ses_data.overall_status_select = 1;
ses_data.overall_status_disable_resets = 0;
ses_data.overall_status_insert = 0;
ses_data.overall_status_remove = 0;
ses_data.overall_status_identify = 0;
ses_data.elem_status[i].select = 1;
ses_data.elem_status[i].insert = 0;
ses_data.elem_status[i].remove = 0;
ses_data.elem_status[i].identify = 0;
ipr_send_diagnostics(&ioa->dev[j], &ses_data,
sizeof(struct ipr_encl_status_ctl_pg));
/* call function to complete conc maint */
if (!rc) {
if (action == IPR_VERIFY_CONC_REMOVE) {
rc = process_conc_maint(i_con, IPR_WAIT_CONC_REMOVE);
if (!rc) {
dev_rcd = ipr_dev->dev_rcd;
getmaxyx(stdscr,max_y,max_x);
move(max_y-1,0);
printw(_("Operation in progress - please wait"));
refresh();
ipr_write_dev_attr(ipr_dev, "delete", "1");
evaluate_device(ipr_dev, ipr_dev->ioa, 0);
ipr_del_zeroed_dev(ipr_dev);
}
} else if (action == IPR_VERIFY_CONC_ADD) {
rc = process_conc_maint(i_con, IPR_WAIT_CONC_ADD);
if (!rc) {
getmaxyx(stdscr,max_y,max_x);
move(max_y-1,0);
printw(_("Operation in progress - please wait"));
refresh();
ipr_scan(ioa, res_addr.bus, res_addr.target, res_addr.lun);
while (time--) {
check_current_config(false);
if ((ipr_dev = get_dev_from_addr(&res_addr))) {
ipr_init_new_dev(ipr_dev);
break;
}
sleep(5);
}
}
}
}
return rc;
}
void get_dev_raid_level(struct ipr_ioa *ioa)
{
int j, i;
struct ipr_array_record *array_record;
char *prot_level_str;
struct ipr_dev_record *dev_record;
int array_id;
/* extract RAID level from vset to pass to device */
for (j = 0; j < ioa->num_devices; j++) {
if (!ipr_is_volume_set(&ioa->dev[j]))
continue;
array_record = ioa->dev[j].array_rcd;
if (array_record->start_cand)
continue;
/* query resource state to acquire protection level string */
prot_level_str = get_prot_level_str(ioa->supported_arrays,
array_record->raid_level);
strncpy(ioa->dev[j].prot_level_str,prot_level_str, 8);
dev_record = ioa->dev[j].dev_rcd;
array_id = dev_record->array_id;
for (i = 0; i < ioa->num_devices; i++) {
dev_record = ioa->dev[i].dev_rcd;
if (!(ipr_is_array_member(&ioa->dev[i])) ||
(ipr_is_volume_set(&ioa->dev[i])) ||
((dev_record != NULL) &&
(dev_record->array_id != array_id)))
continue;
strncpy(ioa->dev[i].prot_level_str, prot_level_str, 8);
}
}
}
static int format_in_prog(struct ipr_dev *dev)
{
struct ipr_cmd_status cmd_status;
struct sense_data_t sense_data;
int rc;
if (ipr_is_af_dasd_device(dev)) {
rc = ipr_query_command_status(dev, &cmd_status);
if (!rc && cmd_status.num_records != 0 &&
cmd_status.record->status == IPR_CMD_STATUS_IN_PROGRESS)
return 1;
} else if (ipr_is_gscsi(dev)) {
rc = ipr_test_unit_ready(dev, &sense_data);
if (rc == CHECK_CONDITION &&
(sense_data.error_code & 0x7F) == 0x70 &&
(sense_data.sense_key & 0x0F) == 0x02 && /* NOT READY */
sense_data.add_sense_code == 0x04 && /* LOGICAL UNIT NOT READY */
sense_data.add_sense_code_qual == 0x04) /* FORMAT IN PROGRESS */
return 1;
}
return 0;
}
int start_conc_maint(i_container *i_con, int action)
{
int rc, i, j, k, l;
char *buffer[2];
int num_lines = 0;
struct ipr_ioa *ioa;
struct scsi_dev_data *scsi_dev_data;
struct ipr_res_addr res_addr;
struct screen_output *s_out;
struct ipr_encl_status_ctl_pg ses_data;
struct ipr_dev **local_dev = NULL;
int local_dev_count = 0;
u8 ses_channel;
int toggle = 1;
s_node *n_screen;
int header_lines;
processing();
rc = RC_SUCCESS;
i_con = free_i_con(i_con);
check_current_config(false);
/* Setup screen title */
if (action == IPR_CONC_REMOVE)
n_screen = &n_concurrent_remove_device;
else
n_screen = &n_concurrent_add_device;
body_init_status(buffer, n_screen->header, &header_lines);
for_each_ioa(ioa) {
if (ioa->is_secondary)
continue;
for (j = 0; j < ioa->num_devices; j++) {
scsi_dev_data = ioa->dev[j].scsi_dev_data;
if (!scsi_dev_data || scsi_dev_data->type != TYPE_ENCLOSURE)
continue;
rc = ipr_receive_diagnostics(&ioa->dev[j], 2, &ses_data,
sizeof(struct ipr_encl_status_ctl_pg));
if (rc)
continue;
ses_channel = scsi_dev_data->channel;
for_each_elem_status(i, &ses_data) {
get_dev_raid_level(ioa);
if (ses_data.elem_status[i].status == IPR_DRIVE_ELEM_STATUS_EMPTY) {
local_dev = realloc(local_dev, (sizeof(void *) *
local_dev_count) + 1);
local_dev[local_dev_count] = calloc(1,sizeof(struct ipr_dev));
scsi_dev_data = calloc(1, sizeof(struct scsi_dev_data));
scsi_dev_data->type = IPR_TYPE_EMPTY_SLOT;
scsi_dev_data->host = ioa->host_num;
scsi_dev_data->channel = ses_channel;
scsi_dev_data->id = ses_data.elem_status[i].scsi_id;
local_dev[local_dev_count]->scsi_dev_data = scsi_dev_data;
local_dev[local_dev_count]->ioa = ioa;
print_dev(k, local_dev[local_dev_count], buffer, "%1", ioa, k);
i_con = add_i_con(i_con,"\0", local_dev[local_dev_count]);
num_lines++;
continue;
}
for (l = 0; l < ioa->num_devices; l++) {
get_res_addr(&ioa->dev[l], &res_addr);
if (res_addr.bus == ses_channel &&
res_addr.target == ses_data.elem_status[i].scsi_id) {
if (action == IPR_CONC_REMOVE) {
if (ipr_suspend_device_bus(ioa, &res_addr, IPR_SDB_CHECK_ONLY))
break;
if (format_in_prog(&ioa->dev[l]))
break;
} else if (ioa->dev[l].scsi_dev_data)
break;
print_dev(k, &ioa->dev[l], buffer, "%1", ioa, k);
i_con = add_i_con(i_con,"\0", &ioa->dev[l]);
num_lines++;
break;
}
}
if (l == ioa->num_devices) {
local_dev = realloc(local_dev, (sizeof(void *) *
local_dev_count) + 1);
local_dev[local_dev_count] = calloc(1,sizeof(struct ipr_dev));
scsi_dev_data = calloc(1, sizeof(struct scsi_dev_data));
scsi_dev_data->type = IPR_TYPE_EMPTY_SLOT;
scsi_dev_data->host = ioa->host_num;
scsi_dev_data->channel = ses_channel;
scsi_dev_data->id = ses_data.elem_status[i].scsi_id;
local_dev[local_dev_count]->scsi_dev_data = scsi_dev_data;
local_dev[local_dev_count]->ioa = ioa;
print_dev(k, local_dev[local_dev_count], buffer, "%1", ioa, k);
i_con = add_i_con(i_con,"\0", local_dev[local_dev_count]);
num_lines++;
}
}
}
}
if (num_lines == 0) {
for (k = 0; k < 2; k++)
buffer[k] = add_string_to_body(buffer[k], _("(No Eligible Devices Found)"),
"", NULL);
}
do {
n_screen->body = buffer[toggle&1];
s_out = screen_driver(n_screen,header_lines,i_con);
toggle++;
} while (s_out->rc == TOGGLE_SCREEN);
for (k = 0; k < 2; k++) {
free(buffer[k]);
buffer[k] = NULL;
}
n_screen->body = NULL;
if (!s_out->rc) {
if (action == IPR_CONC_REMOVE)
rc = process_conc_maint(i_con, IPR_VERIFY_CONC_REMOVE);
else
rc = process_conc_maint(i_con, IPR_VERIFY_CONC_ADD);
}
if (rc & CANCEL_FLAG) {
s_status.index = (rc & ~CANCEL_FLAG);
rc = (rc | REFRESH_FLAG) & ~CANCEL_FLAG;
}
for (k = 0; k < local_dev_count; k++) {
if (!local_dev[k])
continue;
if (local_dev[k]->scsi_dev_data)
free(local_dev[k]->scsi_dev_data);
free(local_dev[k]);
}
free(local_dev);
free(s_out);
return rc;
}
int concurrent_add_device(i_container *i_con)
{
return start_conc_maint(i_con, IPR_CONC_ADD);
}
int concurrent_remove_device(i_container *i_con)
{
return start_conc_maint(i_con, IPR_CONC_REMOVE);
}
int init_device(i_container *i_con)
{
int rc, j, k;
struct scsi_dev_data *scsi_dev_data;
struct ipr_dev_record *device_record;
int can_init;
int dev_type;
char *buffer[2];
int num_devs = 0;
struct ipr_ioa *ioa;
struct screen_output *s_out;
int header_lines;
int toggle = 0;
rc = RC_SUCCESS;
processing();
i_con = free_i_con(i_con);
check_current_config(false);
body_init_status(buffer, n_init_device.header, &header_lines);
for_each_ioa(ioa) {
for (j = 0; j < ioa->num_devices; j++) {
can_init = 1;
scsi_dev_data = ioa->dev[j].scsi_dev_data;
/* If not a DASD, disallow format */
if (!scsi_dev_data || ioa->ioa_dead ||
ipr_is_hot_spare(&ioa->dev[j]) ||
ipr_is_volume_set(&ioa->dev[j]) ||
!device_supported(&ioa->dev[j]) ||
(scsi_dev_data->type != TYPE_DISK &&
scsi_dev_data->type != IPR_TYPE_AF_DISK))
continue;
/* If Advanced Function DASD */
if (ipr_is_af_dasd_device(&ioa->dev[j])) {
dev_type = IPR_AF_DASD_DEVICE;
device_record = ioa->dev[j].dev_rcd;
/* We allow the user to format the drive if nobody is using it */
if (ioa->dev[j].scsi_dev_data->opens != 0) {
syslog(LOG_ERR,
_("Format not allowed to %s, device in use\n"),
ioa->dev[j].gen_name);
continue;
}
if (ipr_is_array_member(&ioa->dev[j])) {
if (device_record->no_cfgte_vol)
can_init = 1;
else
can_init = 0;
} else
can_init = is_format_allowed(&ioa->dev[j]);
} else if (scsi_dev_data->type == TYPE_DISK) {
/* We allow the user to format the drive if nobody is using it */
if (ioa->dev[j].scsi_dev_data->opens != 0) {
syslog(LOG_ERR,
_("Format not allowed to %s, device in use\n"),
ioa->dev[j].gen_name);
continue;
}
dev_type = IPR_JBOD_DASD_DEVICE;
can_init = is_format_allowed(&ioa->dev[j]);
} else
continue;
if (can_init) {
if (dev_init_head) {
dev_init_tail->next = malloc(sizeof(struct devs_to_init_t));
dev_init_tail = dev_init_tail->next;
}
else
dev_init_head = dev_init_tail = malloc(sizeof(struct devs_to_init_t));
memset(dev_init_tail, 0, sizeof(struct devs_to_init_t));
dev_init_tail->ioa = ioa;
dev_init_tail->dev_type = dev_type;
dev_init_tail->dev = &ioa->dev[j];
dev_init_tail->new_block_size = 0;
print_dev(k, &ioa->dev[j], buffer, "%1", ioa, k);
i_con = add_i_con(i_con,"\0",dev_init_tail);
num_devs++;
}
}
}
if (!num_devs)
/* "No units available for initialize and format" */
return 49;
do {
n_init_device.body = buffer[toggle&1];
s_out = screen_driver(&n_init_device,header_lines,i_con);
toggle++;
} while (s_out->rc == TOGGLE_SCREEN);
rc = s_out->rc;
free(s_out);
for (k = 0; k < 2; k++) {
free(buffer[k]);
buffer[k] = NULL;
}
n_init_device.body = NULL;
free_devs_to_init();
return rc;
}
int confirm_init_device(i_container *i_con)
{
char *input;
char *buffer[2];
struct devs_to_init_t *cur_dev_init;
int rc = RC_SUCCESS;
struct screen_output *s_out;
int header_lines = 0;
int toggle = 0;
int k;
i_container *temp_i_con;
int found = 0;
int post_attention = 0;
struct ipr_dev *dev;
for_each_icon(temp_i_con) {
if (temp_i_con->data == NULL)
continue;
input = temp_i_con->field_data;
if (strcmp(input, "1") == 0) {
found++;
cur_dev_init =(struct devs_to_init_t *)(temp_i_con->data);
cur_dev_init->do_init = 1;
dev = cur_dev_init->dev;
if (ipr_is_gscsi(dev))
post_attention++;
} else {
cur_dev_init = (struct devs_to_init_t *)(temp_i_con->data);
cur_dev_init->do_init = 0;
}
}
if (!found)
return INVALID_OPTION_STATUS;
if (post_attention) {
for (k=0; k<2; k++) {
header_lines = 0;
buffer[k] = add_string_to_body(NULL, _("ATTENTION! System crash may occur "
"if selected device is in use. Data loss will "
"occur on selected device. Proceed with "
"caution.\n\n"), "", &header_lines);
buffer[k] = __body_init(buffer[k],n_confirm_init_device.header, &header_lines);
buffer[k] = status_header(buffer[k], &header_lines, k);
}
} else {
body_init_status(buffer, n_confirm_init_device.header, &header_lines);
}
for_each_dev_to_init(cur_dev_init) {
if (!cur_dev_init->do_init)
continue;
print_dev(k, cur_dev_init->dev, buffer, "1", cur_dev_init->ioa, k);
}
do {
n_confirm_init_device.body = buffer[toggle&1];
s_out = screen_driver(&n_confirm_init_device,header_lines,NULL);
toggle++;
} while (s_out->rc == TOGGLE_SCREEN);
rc = s_out->rc;
free(s_out);
for (k = 0; k < 2; k++) {
free(buffer[k]);
buffer[k] = NULL;
}
n_confirm_init_device.body = NULL;
return rc;
}
static int dev_init_complete(u8 num_devs)
{
int done_bad;
struct ipr_cmd_status cmd_status;
struct ipr_cmd_status_record *status_record;
int not_done = 0;
int rc;
struct devs_to_init_t *dev;
u32 percent_cmplt = 0;
struct sense_data_t sense_data;
struct ipr_ioa *ioa;
int pid = 1;
while(1) {
if (pid)
rc = complete_screen_driver(&n_dev_init_complete, percent_cmplt,1);
if (rc & EXIT_FLAG) {
pid = fork();
if (pid)
return rc;
rc = 0;
}
percent_cmplt = 100;
done_bad = 0;
for_each_dev_to_init(dev) {
if (dev->do_init && dev->dev_type == IPR_AF_DASD_DEVICE) {
rc = ipr_query_command_status(dev->dev, &cmd_status);
if (rc || cmd_status.num_records == 0)
continue;
status_record = cmd_status.record;
if (status_record->status == IPR_CMD_STATUS_FAILED) {
done_bad = 1;
} else if (status_record->status != IPR_CMD_STATUS_SUCCESSFUL) {
if (status_record->percent_complete < percent_cmplt)
percent_cmplt = status_record->percent_complete;
not_done = 1;
}
} else if (dev->do_init && dev->dev_type == IPR_JBOD_DASD_DEVICE) {
/* Send Test Unit Ready to find percent complete in sense data. */
rc = ipr_test_unit_ready(dev->dev,
&sense_data);
if (rc < 0)
continue;
if (rc == CHECK_CONDITION &&
(sense_data.error_code & 0x7F) == 0x70 &&
(sense_data.sense_key & 0x0F) == 0x02) {
dev->cmplt = ((int)sense_data.sense_key_spec[1]*100)/0x100;
if (dev->cmplt < percent_cmplt)
percent_cmplt = dev->cmplt;
not_done = 1;
}
}
}
if (!not_done) {
for_each_dev_to_init(dev) {
if (!dev->do_init)
continue;
ioa = dev->ioa;
if (dev->new_block_size != ioa->af_block_size && ipr_is_gscsi(dev->dev)) {
ipr_write_dev_attr(dev->dev, "rescan", "1");
ipr_init_dev(dev->dev);
}
if (dev->new_block_size != 0) {
if (dev->new_block_size == ioa->af_block_size)
enable_af(dev->dev);
evaluate_device(dev->dev, ioa, dev->new_block_size);
}
if (dev->new_block_size == ioa->af_block_size || ipr_is_af_dasd_device(dev->dev))
ipr_add_zeroed_dev(dev->dev);
}
flush_stdscr();
if (done_bad) {
if (!pid)
exit(0);
/* Initialize and format failed */
return 51 | EXIT_FLAG;
}
if (!pid)
exit(0);
/* Initialize and format completed successfully */
return 50 | EXIT_FLAG;
}
not_done = 0;
sleep(1);
}
}
int send_dev_inits(i_container *i_con)
{
u8 num_devs = 0;
struct devs_to_init_t *cur_dev_init;
int rc;
struct ipr_query_res_state res_state;
u8 ioctl_buffer[IOCTL_BUFFER_SIZE];
struct ipr_mode_parm_hdr *mode_parm_hdr;
struct ipr_block_desc *block_desc;
struct scsi_dev_data *scsi_dev_data;
struct ipr_ioa *ioa;
int status;
int opens;
u8 failure = 0;
int max_y, max_x;
u8 length;
getmaxyx(stdscr,max_y,max_x);
mvaddstr(max_y-1,0,wait_for_next_screen);
refresh();
for_each_dev_to_init(cur_dev_init) {
if (cur_dev_init->do_init &&
cur_dev_init->dev_type == IPR_AF_DASD_DEVICE) {
num_devs++;
ioa = cur_dev_init->ioa;
rc = ipr_query_resource_state(cur_dev_init->dev, &res_state);
if (rc != 0) {
cur_dev_init->do_init = 0;
num_devs--;
failure++;
continue;
}
scsi_dev_data = cur_dev_init->dev->scsi_dev_data;
if (!scsi_dev_data) {
cur_dev_init->do_init = 0;
num_devs--;
failure++;
continue;
}
opens = num_device_opens(scsi_dev_data->host,
scsi_dev_data->channel,
scsi_dev_data->id,
scsi_dev_data->lun);
if ((opens != 0) && (!res_state.read_write_prot)) {
syslog(LOG_ERR,
_("Cannot obtain exclusive access to %s\n"),
cur_dev_init->dev->gen_name);
cur_dev_init->do_init = 0;
num_devs--;
failure++;
continue;
}
ipr_disable_qerr(cur_dev_init->dev);
if (cur_dev_init->new_block_size == IPR_JBOD_BLOCK_SIZE) {
/* Issue mode select to change block size */
mode_parm_hdr = (struct ipr_mode_parm_hdr *)ioctl_buffer;
memset(ioctl_buffer, 0, 255);
mode_parm_hdr->block_desc_len = sizeof(struct ipr_block_desc);
block_desc = (struct ipr_block_desc *)(mode_parm_hdr + 1);
/* Setup block size */
block_desc->block_length[0] = 0x00;
block_desc->block_length[1] = IPR_JBOD_BLOCK_SIZE >> 8;
block_desc->block_length[2] = IPR_JBOD_BLOCK_SIZE & 0xff;
rc = ipr_mode_select(cur_dev_init->dev,ioctl_buffer,
sizeof(struct ipr_block_desc) +
sizeof(struct ipr_mode_parm_hdr));
if (rc != 0) {
cur_dev_init->do_init = 0;
num_devs--;
failure++;
continue;
}
}
/* Issue the format. Failure will be detected by query command status */
rc = ipr_format_unit(cur_dev_init->dev); /* FIXME Mandatory lock? */
} else if (cur_dev_init->do_init &&
cur_dev_init->dev_type == IPR_JBOD_DASD_DEVICE) {
num_devs++;
ioa = cur_dev_init->ioa;
scsi_dev_data = cur_dev_init->dev->scsi_dev_data;
if (!scsi_dev_data) {
cur_dev_init->do_init = 0;
num_devs--;
failure++;
continue;
}
opens = num_device_opens(scsi_dev_data->host,
scsi_dev_data->channel,
scsi_dev_data->id,
scsi_dev_data->lun);
if (opens) {
syslog(LOG_ERR,
_("Cannot obtain exclusive access to %s\n"),
cur_dev_init->dev->gen_name);
cur_dev_init->do_init = 0;
num_devs--;
failure++;
continue;
}
ipr_disable_qerr(cur_dev_init->dev);
/* Issue mode select to setup block size */
mode_parm_hdr = (struct ipr_mode_parm_hdr *)ioctl_buffer;
memset(ioctl_buffer, 0, 255);
mode_parm_hdr->block_desc_len = sizeof(struct ipr_block_desc);
block_desc = (struct ipr_block_desc *)(mode_parm_hdr + 1);
/* xxx Setup block size */
if (cur_dev_init->new_block_size == ioa->af_block_size) {
block_desc->block_length[0] = 0x00;
block_desc->block_length[1] = ioa->af_block_size >> 8;
block_desc->block_length[2] = ioa->af_block_size & 0xff;
} else {
block_desc->block_length[0] = 0x00;
block_desc->block_length[1] = IPR_JBOD_BLOCK_SIZE >> 8;
block_desc->block_length[2] = IPR_JBOD_BLOCK_SIZE & 0xff;
}
length = sizeof(struct ipr_block_desc) +
sizeof(struct ipr_mode_parm_hdr);
status = ipr_mode_select(cur_dev_init->dev,
&ioctl_buffer, length);
if (status && cur_dev_init->new_block_size == ioa->af_block_size) {
cur_dev_init->do_init = 0;
num_devs--;
failure++;
continue;
}
/* Issue format */
status = ipr_format_unit(cur_dev_init->dev); /* FIXME Mandatory lock? */
if (status) {
/* Send a device reset to cleanup any old state */
rc = ipr_reset_device(cur_dev_init->dev);
cur_dev_init->do_init = 0;
num_devs--;
failure++;
continue;
}
}
}
if (num_devs)
rc = dev_init_complete(num_devs);
if (failure == 0)
return rc;
else
/* "Initialize and format failed" */
return 51 | EXIT_FLAG;
}
int reclaim_cache(i_container* i_con)
{
int rc;
struct ipr_ioa *ioa;
struct ipr_reclaim_query_data *reclaim_buffer;
struct ipr_reclaim_query_data *cur_reclaim_buffer;
int found = 0;
char *buffer[2];
struct screen_output *s_out;
int header_lines;
int toggle=1;
int k;
processing();
/* empty the linked list that contains field pointers */
i_con = free_i_con(i_con);
check_current_config(false);
body_init_status(buffer, n_reclaim_cache.header, &header_lines);
reclaim_buffer = malloc(sizeof(struct ipr_reclaim_query_data) * num_ioas);
for (ioa = ipr_ioa_head, cur_reclaim_buffer = reclaim_buffer;
ioa != NULL; ioa = ioa->next, cur_reclaim_buffer++) {
rc = ipr_reclaim_cache_store(ioa,
IPR_RECLAIM_QUERY,
cur_reclaim_buffer);
if (rc != 0) {
ioa->reclaim_data = NULL;
continue;
}
ioa->reclaim_data = cur_reclaim_buffer;
if (cur_reclaim_buffer->reclaim_known_needed ||
cur_reclaim_buffer->reclaim_unknown_needed) {
print_dev(k, &ioa->ioa, buffer, "%1", ioa, k);
i_con = add_i_con(i_con, "\0",ioa);
found++;
}
}
if (!found) {
/* "No Reclaim IOA Cache Storage is necessary" */
rc = 38;
goto leave;
}
do {
n_reclaim_cache.body = buffer[toggle&1];
s_out = screen_driver(&n_reclaim_cache,header_lines,i_con);
toggle++;
} while (s_out->rc == TOGGLE_SCREEN);
rc = s_out->rc;
free(s_out);
leave:
for (k = 0; k < 2; k++) {
free(buffer[k]);
buffer[k] = NULL;
}
n_reclaim_cache.body = NULL;
return rc;
}
int confirm_reclaim(i_container *i_con)
{
struct ipr_ioa *ioa, *reclaim_ioa;
struct scsi_dev_data *scsi_dev_data;
struct ipr_query_res_state res_state;
struct ipr_dev_record *dev_rcd;
struct ipr_array_record *array_rcd;
int j, k, rc;
char *buffer[2];
i_container* temp_i_con;
struct screen_output *s_out;
int header_lines;
int toggle=1;
int ioa_num = 0;
char *prot_level_str;
for_each_icon(temp_i_con) {
ioa = (struct ipr_ioa *) temp_i_con->data;
if (!ioa)
continue;
if (strcmp(temp_i_con->field_data, "1") != 0)
continue;
if (ioa->reclaim_data->reclaim_known_needed ||
ioa->reclaim_data->reclaim_unknown_needed) {
reclaim_ioa = ioa;
ioa_num++;
}
}
if (ioa_num == 0)
/* "Invalid option. No devices selected." */
return 17;
else if (ioa_num > 1)
/* "Error. More than one unit was selected." */
return 16;
/* One IOA selected, ready to proceed */
body_init_status(buffer, n_confirm_reclaim.header, &header_lines);
for (j = 0; j < reclaim_ioa->num_devices; j++) {
scsi_dev_data = reclaim_ioa->dev[j].scsi_dev_data;
if (!scsi_dev_data || !ipr_is_af(&reclaim_ioa->dev[j]))
continue;
/* Do a query resource state to see whether or not the
device will be affected by the operation */
rc = ipr_query_resource_state(&reclaim_ioa->dev[j], &res_state);
if (rc != 0)
res_state.not_oper = 1;
if (!res_state.read_write_prot && !res_state.not_oper)
continue;
if (ipr_is_volume_set(&reclaim_ioa->dev[j])) {
strcpy(reclaim_ioa->dev[j].prot_level_str, res_state.vset.prot_level_str);
} else if (ipr_is_af_dasd_device(&reclaim_ioa->dev[j])) {
dev_rcd = reclaim_ioa->dev[j].dev_rcd;
for (k = 0; k < reclaim_ioa->num_devices; k++) {
if (!ipr_is_volume_set(&reclaim_ioa->dev[k]))
continue;
array_rcd = reclaim_ioa->dev[k].array_rcd;
if (array_rcd->array_id == dev_rcd->array_id) {
prot_level_str = get_prot_level_str(reclaim_ioa->supported_arrays,
array_rcd->raid_level);
strcpy(reclaim_ioa->dev[j].prot_level_str, prot_level_str);
break;
}
}
}
print_dev(k, &reclaim_ioa->dev[j], buffer, "1", reclaim_ioa, k);
}
i_con = free_i_con(i_con);
/* Save the chosen IOA for later use */
add_i_con(i_con, "\0", reclaim_ioa);
do {
n_confirm_reclaim.body = buffer[toggle&1];
s_out = screen_driver(&n_confirm_reclaim,header_lines,i_con);
toggle++;
} while (s_out->rc == TOGGLE_SCREEN);
rc = s_out->rc;
free(s_out);
for (k = 0; k < 2; k++) {
free(buffer[k]);
buffer[k] = NULL;
}
n_confirm_reclaim.body = NULL;
return rc;
}
int reclaim_warning(i_container *i_con)
{
struct ipr_ioa *reclaim_ioa;
int k, rc;
char *buffer[2];
struct screen_output *s_out;
int header_lines;
int toggle=1;
reclaim_ioa = (struct ipr_ioa *)i_con->data;
if (!reclaim_ioa)
/* "Invalid option. No devices selected." */
return 17;
for (k = 0; k < 2; k++) {
buffer[k] = __body_init_status(n_confirm_reclaim_warning.header, &header_lines, k);
buffer[k] = print_device(&reclaim_ioa->ioa, buffer[k], "1", reclaim_ioa, k);
}
do {
n_confirm_reclaim_warning.body = buffer[toggle&1];
s_out = screen_driver(&n_confirm_reclaim_warning,header_lines,i_con);
toggle++;
} while (s_out->rc == TOGGLE_SCREEN);
rc = s_out->rc;
free(s_out);
for (k = 0; k < 2; k++) {
free(buffer[k]);
buffer[k] = NULL;
}
n_confirm_reclaim_warning.body = NULL;
return rc;
}
int reclaim_result(i_container *i_con)
{
int rc;
struct ipr_ioa *reclaim_ioa;
int max_y,max_x;
struct screen_output *s_out;
int action;
char buffer[32];
char *body = NULL;
reclaim_ioa = (struct ipr_ioa *) i_con->data;
action = IPR_RECLAIM_PERFORM;
/* Everything going according to plan. Proceed with reclaim. */
getmaxyx(stdscr,max_y,max_x);
move(max_y-1,0);
printw("Please wait - reclaim in progress");
refresh();
if (reclaim_ioa->reclaim_data->reclaim_unknown_needed)
action |= IPR_RECLAIM_UNKNOWN_PERM;
rc = ipr_reclaim_cache_store(reclaim_ioa,
action,
reclaim_ioa->reclaim_data);
if (rc != 0)
/* "Reclaim IOA Cache Storage failed" */
return (EXIT_FLAG | 37);
memset(reclaim_ioa->reclaim_data, 0, sizeof(struct ipr_reclaim_query_data));
rc = ipr_reclaim_cache_store(reclaim_ioa,
IPR_RECLAIM_QUERY,
reclaim_ioa->reclaim_data);
if (rc != 0)
/* "Reclaim IOA Cache Storage failed" */
return (EXIT_FLAG | 37);
if (reclaim_ioa->reclaim_data->reclaim_known_performed) {
body = add_string_to_body(body,
_("IOA cache storage reclamation has completed. "
"Use the number of lost sectors to decide whether "
"to restore data from the most recent save media "
"or to continue with possible data loss.\n"),
"", NULL);
if (reclaim_ioa->reclaim_data->num_blocks_needs_multiplier)
sprintf(buffer, "%12d",
ntohs(reclaim_ioa->reclaim_data->num_blocks) *
IPR_RECLAIM_NUM_BLOCKS_MULTIPLIER);
else
sprintf(buffer, "%12d",
ntohs(reclaim_ioa->reclaim_data->num_blocks));
body = add_line_to_body(body,_("Number of lost sectors"),buffer);
} else if (reclaim_ioa->reclaim_data->reclaim_unknown_performed) {
body = add_string_to_body(body,
_("IOA cache storage reclamation has completed. "
"The number of lost sectors could not be determined.\n"),
"", NULL);
}
n_reclaim_result.body = body;
s_out = screen_driver(&n_reclaim_result,0,NULL);
free(s_out);
free(n_reclaim_result.body);
n_reclaim_result.body = NULL;
rc = ipr_reclaim_cache_store(reclaim_ioa,
IPR_RECLAIM_RESET,
reclaim_ioa->reclaim_data);
if (rc != 0)
rc = (EXIT_FLAG | 37);
else
rc = EXIT_FLAG;
return rc;
}
int battery_maint(i_container *i_con)
{
int rc, k;
struct ipr_reclaim_query_data *cur_reclaim_buffer;
struct ipr_ioa *ioa;
int found = 0;
char *buffer[2];
struct screen_output *s_out;
int header_lines;
int toggle=1;
i_con = free_i_con(i_con);
body_init_status(buffer, n_battery_maint.header, &header_lines);
cur_reclaim_buffer = malloc(sizeof(struct ipr_reclaim_query_data) * num_ioas);
for (ioa = ipr_ioa_head; ioa != NULL;
ioa = ioa->next, cur_reclaim_buffer++) {
rc = ipr_reclaim_cache_store(ioa,
IPR_RECLAIM_QUERY | IPR_RECLAIM_EXTENDED_INFO,
cur_reclaim_buffer);
if (rc != 0) {
ioa->reclaim_data = NULL;
continue;
}
ioa->reclaim_data = cur_reclaim_buffer;
if (cur_reclaim_buffer->rechargeable_battery_type) {
i_con = add_i_con(i_con, "\0",ioa);
print_dev(k, &ioa->ioa, buffer, "%1", ioa, k);
found++;
}
}
if (!found) {
/* No configured resources contain a cache battery pack */
rc = 44;
goto leave;
}
do {
n_battery_maint.body = buffer[toggle&1];
s_out = screen_driver(&n_battery_maint,header_lines,i_con);
toggle++;
} while (s_out->rc == TOGGLE_SCREEN);
rc = s_out->rc;
free(s_out);
leave:
for (k = 0; k < 2; k++) {
free(buffer[k]);
buffer[k] = NULL;
}
n_battery_maint.body = NULL;
return rc;
}
int show_battery_info(struct ipr_ioa *ioa)
{
int rc;
struct ipr_reclaim_query_data *reclaim_data = ioa->reclaim_data;
char buffer[128];
struct screen_output *s_out;
struct ipr_ioa_vpd ioa_vpd;
struct ipr_cfc_vpd cfc_vpd;
u8 product_id[IPR_PROD_ID_LEN+1];
u8 serial_num[IPR_SERIAL_NUM_LEN+1];
char *body = NULL;
memset(&ioa_vpd, 0, sizeof(ioa_vpd));
memset(&cfc_vpd, 0, sizeof(cfc_vpd));
ipr_inquiry(&ioa->ioa, IPR_STD_INQUIRY, &ioa_vpd, sizeof(ioa_vpd));
ipr_inquiry(&ioa->ioa, 1, &cfc_vpd, sizeof(cfc_vpd));
ipr_strncpy_0(product_id,
ioa_vpd.std_inq_data.vpids.product_id,
IPR_PROD_ID_LEN);
ipr_strncpy_0(serial_num, cfc_vpd.serial_num,
IPR_SERIAL_NUM_LEN);
body = add_line_to_body(body,"", NULL);
body = add_line_to_body(body,_("Resource Name"), ioa->ioa.gen_name);
body = add_line_to_body(body,_("Serial Number"), serial_num);
body = add_line_to_body(body,_("Type"), product_id);
body = add_line_to_body(body,_("PCI Address"), ioa->pci_address);
sprintf(buffer,"%d", ioa->host_num);
body = add_line_to_body(body,_("SCSI Host Number"), buffer);
switch (reclaim_data->rechargeable_battery_type) {
case IPR_BATTERY_TYPE_NICD:
sprintf(buffer,_("Nickel Cadmium (NiCd)"));
break;
case IPR_BATTERY_TYPE_NIMH:
sprintf(buffer,_("Nickel Metal Hydride (NiMH)"));
break;
case IPR_BATTERY_TYPE_LIION:
sprintf(buffer,_("Lithium Ion (LiIon)"));
break;
default:
sprintf(buffer,_("Unknown"));
break;
}
body = add_line_to_body(body,_("Battery type"), buffer);
switch (reclaim_data->rechargeable_battery_error_state) {
case IPR_BATTERY_NO_ERROR_STATE:
sprintf(buffer,_("No battery warning"));
break;
case IPR_BATTERY_WARNING_STATE:
sprintf(buffer,_("Battery warning issued"));
break;
case IPR_BATTERY_ERROR_STATE:
sprintf(buffer,_("Battery error issued"));
break;
default:
sprintf(buffer,_("Unknown"));
break;
}
body = add_line_to_body(body,_("Battery state"), buffer);
sprintf(buffer,"%d",reclaim_data->raw_power_on_time);
body = add_line_to_body(body,_("Power on time (days)"), buffer);
sprintf(buffer,"%d",reclaim_data->adjusted_power_on_time);
body = add_line_to_body(body,_("Adjusted power on time (days)"), buffer);
sprintf(buffer,"%d",reclaim_data->estimated_time_to_battery_warning);
body = add_line_to_body(body,_("Estimated time to warning (days)"), buffer);
sprintf(buffer,"%d",reclaim_data->estimated_time_to_battery_failure);
body = add_line_to_body(body,_("Estimated time to error (days)"), buffer);
if (reclaim_data->conc_maint_battery)
sprintf(buffer, "%s", _("Yes"));
else
sprintf(buffer, "%s", _("No"));
body = add_line_to_body(body,_("Concurrently maintainable battery pack"), buffer);
if (reclaim_data->battery_replace_allowed)
sprintf(buffer, "%s", _("Yes"));
else
sprintf(buffer, "%s", _("No"));
body = add_line_to_body(body,_("Battery pack can be safely replaced"), buffer);
n_show_battery_info.body = body;
s_out = screen_driver(&n_show_battery_info,0,NULL);
free(n_show_battery_info.body);
n_show_battery_info.body = NULL;
rc = s_out->rc;
free(s_out);
return rc;
}
int confirm_force_battery_error(void)
{
int rc,k;
struct ipr_ioa *ioa;
char *buffer[2];
struct screen_output *s_out;
int header_lines;
int toggle=1;
rc = RC_SUCCESS;
body_init_status(buffer, n_confirm_force_battery_error.header, &header_lines);
for_each_ioa(ioa) {
if (!ioa->reclaim_data || !ioa->ioa.is_reclaim_cand)
continue;
print_dev(k, &ioa->ioa, buffer, "2", ioa, k);
}
do {
n_confirm_force_battery_error.body = buffer[toggle&1];
s_out = screen_driver(&n_confirm_force_battery_error,header_lines,NULL);
toggle++;
} while (s_out->rc == TOGGLE_SCREEN);
rc = s_out->rc;
free(s_out);
for (k = 0; k < 2; k++) {
free(buffer[k]);
buffer[k] = NULL;
}
n_confirm_force_battery_error.body = NULL;
return rc;
}
int enable_battery(i_container *i_con)
{
int rc, reclaim_rc;
struct ipr_ioa *ioa;
reclaim_rc = rc = RC_SUCCESS;
for_each_ioa(ioa) {
if (!ioa->reclaim_data || !ioa->ioa.is_reclaim_cand)
continue;
rc = ipr_reclaim_cache_store(ioa,
IPR_RECLAIM_RESET_BATTERY_ERROR | IPR_RECLAIM_EXTENDED_INFO,
ioa->reclaim_data);
if (rc != 0)
reclaim_rc = 70;
if (ioa->reclaim_data->action_status != IPR_ACTION_SUCCESSFUL) {
ioa_err(ioa, "Start IOA cache failed.\n");
reclaim_rc = 70;
}
}
if (reclaim_rc != RC_SUCCESS)
return reclaim_rc | EXIT_FLAG;
return 71 | EXIT_FLAG;
}
int confirm_enable_battery(void)
{
int rc,k;
struct ipr_ioa *ioa;
char *buffer[2];
struct screen_output *s_out;
int header_lines;
int toggle=1;
rc = RC_SUCCESS;
body_init_status(buffer, n_confirm_start_cache.header, &header_lines);
for_each_ioa(ioa) {
if (!ioa->reclaim_data || !ioa->ioa.is_reclaim_cand)
continue;
print_dev(k, &ioa->ioa, buffer, "3", ioa, k);
}
do {
n_confirm_start_cache.body = buffer[toggle&1];
s_out = screen_driver(&n_confirm_start_cache,header_lines,NULL);
toggle++;
} while (s_out->rc == TOGGLE_SCREEN);
rc = s_out->rc;
free(s_out);
for (k=0; k<2; k++) {
free(buffer[k]);
buffer[k] = NULL;
}
n_confirm_start_cache.body = NULL;
return rc;
}
int battery_fork(i_container *i_con)
{
int rc = 0;
int force_error = 0;
struct ipr_ioa *ioa;
char *input;
i_container *temp_i_con;
for_each_icon(temp_i_con) {
ioa = (struct ipr_ioa *)temp_i_con->data;
if (ioa == NULL)
continue;
input = temp_i_con->field_data;
if (strcmp(input, "3") == 0) {
ioa->ioa.is_reclaim_cand = 1;
return confirm_enable_battery();
} else if (strcmp(input, "2") == 0) {
force_error++;
ioa->ioa.is_reclaim_cand = 1;
} else if (strcmp(input, "1") == 0) {
rc = show_battery_info(ioa);
return rc;
} else
ioa->ioa.is_reclaim_cand = 0;
}
if (force_error) {
rc = confirm_force_battery_error();
return rc;
}
return INVALID_OPTION_STATUS;
}
int force_battery_error(i_container *i_con)
{
int rc, reclaim_rc;
struct ipr_ioa *ioa;
struct ipr_reclaim_query_data reclaim_buffer;
reclaim_rc = rc = RC_SUCCESS;
for_each_ioa(ioa) {
if (!ioa->reclaim_data || !ioa->ioa.is_reclaim_cand)
continue;
rc = ipr_reclaim_cache_store(ioa,
IPR_RECLAIM_FORCE_BATTERY_ERROR,
&reclaim_buffer);
if (rc != 0)
reclaim_rc = 43;
if (reclaim_buffer.action_status != IPR_ACTION_SUCCESSFUL) {
ioa_err(ioa, "Battery Force Error failed.\n");
reclaim_rc = 43;
}
}
if (reclaim_rc != RC_SUCCESS)
return reclaim_rc | EXIT_FLAG;
return 72 | EXIT_FLAG;
}
int bus_config(i_container *i_con)
{
int rc, k;
int found = 0;
char *buffer[2];
struct ipr_ioa *ioa;
u8 ioctl_buffer[255];
struct ipr_mode_parm_hdr *mode_parm_hdr;
struct ipr_mode_page_28_header *modepage_28_hdr;
struct screen_output *s_out;
int header_lines;
int toggle = 0;
rc = RC_SUCCESS;
processing();
i_con = free_i_con(i_con);
check_current_config(false);
body_init_status(buffer, n_bus_config.header, &header_lines);
for_each_ioa(ioa) {
if (!is_spi(ioa) && !ipr_debug)
continue;
/* mode sense page28 to focal point */
mode_parm_hdr = (struct ipr_mode_parm_hdr *)ioctl_buffer;
rc = ipr_mode_sense(&ioa->ioa, 0x28, mode_parm_hdr);
if (rc != 0)
continue;
modepage_28_hdr = (struct ipr_mode_page_28_header *) (mode_parm_hdr + 1);
if (modepage_28_hdr->num_dev_entries == 0)
continue;
i_con = add_i_con(i_con,"\0",(char *)ioa);
print_dev(k, &ioa->ioa, buffer, "%1", ioa, k);
found++;
}
if (!found) {
n_bus_config_fail.body = body_init(n_bus_config_fail.header, NULL);
s_out = screen_driver(&n_bus_config_fail,0,NULL);
free(n_bus_config_fail.body);
n_bus_config_fail.body = NULL;
rc = s_out->rc;
free(s_out);
} else {
do {
n_bus_config.body = buffer[toggle&1];
s_out = screen_driver(&n_bus_config,header_lines,i_con);
toggle++;
} while (s_out->rc == TOGGLE_SCREEN);
rc = s_out->rc;
free(s_out);
}
for (k=0; k<2; k++) {
free(buffer[k]);
buffer[k] = NULL;
}
n_bus_config.body = NULL;
return rc;
}
enum attr_type {qas_capability_type, scsi_id_type, bus_width_type, max_xfer_rate_type};
struct bus_attr {
enum attr_type type;
u8 bus;
struct ipr_scsi_buses *page_28;
struct ipr_ioa *ioa;
struct bus_attr *next;
};
struct bus_attr *bus_attr_head = NULL;
static struct bus_attr *get_bus_attr_buf(struct bus_attr *bus_attr)
{
if (!bus_attr) {
bus_attr_head = malloc(sizeof(struct bus_attr));
bus_attr_head->next = NULL;
return bus_attr_head;
}
bus_attr->next = malloc(sizeof(struct bus_attr));
bus_attr->next->next = NULL;
return bus_attr->next;
}
static void free_all_bus_attr_buf(void)
{
struct bus_attr *bus_attr;
while (bus_attr_head) {
bus_attr = bus_attr_head->next;
free(bus_attr_head);
bus_attr_head = bus_attr;
}
}
int change_bus_attr(i_container *i_con)
{
struct ipr_ioa *ioa;
int rc, j, i;
struct ipr_scsi_buses page_28_cur;
struct ipr_scsi_buses page_28_chg;
struct scsi_dev_data *scsi_dev_data;
char scsi_id_str[5][16];
char max_xfer_rate_str[5][16];
i_container *temp_i_con;
int found = 0;
char *input;
struct bus_attr *bus_attr = NULL;
int header_lines = 0;
char *body = NULL;
char buffer[128];
struct screen_output *s_out;
u8 bus_num;
int bus_attr_menu(struct ipr_ioa *ioa,
struct bus_attr *bus_attr,
int row,
int header_lines);
rc = RC_SUCCESS;
for_each_icon(temp_i_con) {
ioa = (struct ipr_ioa *)temp_i_con->data;
if (ioa == NULL)
continue;
input = temp_i_con->field_data;
if (strcmp(input, "1") == 0) {
found++;
break;
}
}
if (!found)
return INVALID_OPTION_STATUS;
i_con = free_i_con(i_con);
/* zero out user page 28 page, this data is used to indicate
which fields the user changed */
memset(&page_28_cur, 0, sizeof(struct ipr_scsi_buses));
memset(&page_28_chg, 0, sizeof(struct ipr_scsi_buses));
/* mode sense page28 to get current parms */
rc = ipr_get_bus_attr(ioa, &page_28_cur);
if (rc != 0)
/* "Change SCSI Bus configurations failed" */
return 46 | EXIT_FLAG;
/* determine changable and default values */
for (j = 0; j < page_28_cur.num_buses; j++) {
page_28_chg.bus[j].qas_capability = 0;
if (ioa->scsi_id_changeable)
page_28_chg.bus[j].scsi_id = 1;
else
page_28_chg.bus[j].scsi_id = 0;
page_28_chg.bus[j].bus_width = 1;
page_28_chg.bus[j].max_xfer_rate = 1;
}
body = body_init(n_change_bus_attr.header, &header_lines);
sprintf(buffer, "Adapter Location: %s\n", ioa->pci_address);
body = add_line_to_body(body, buffer, NULL);
header_lines++;
for (j = 0; j < page_28_cur.num_buses; j++) {
sprintf(buffer,_(" BUS%d"), j);
body = add_line_to_body(body, buffer, NULL);
if (page_28_chg.bus[j].qas_capability) {
body = add_line_to_body(body,_("QAS Capability"), "%9");
bus_attr = get_bus_attr_buf(bus_attr);
bus_attr->type = qas_capability_type;
bus_attr->bus = j;
bus_attr->page_28 = &page_28_cur;
bus_attr->ioa = ioa;
if (page_28_cur.bus[j].qas_capability ==
IPR_MODEPAGE28_QAS_CAPABILITY_DISABLE_ALL)
i_con = add_i_con(i_con,_("Disabled"),bus_attr);
else
i_con = add_i_con(i_con,_("Enabled"),bus_attr);
}
if (page_28_chg.bus[j].scsi_id) {
body = add_line_to_body(body,_("Host SCSI ID"), "%3");
bus_attr = get_bus_attr_buf(bus_attr);
bus_attr->type = scsi_id_type;
bus_attr->bus = j;
bus_attr->page_28 = &page_28_cur;
bus_attr->ioa = ioa;
sprintf(scsi_id_str[j],"%d",page_28_cur.bus[j].scsi_id);
i_con = add_i_con(i_con,scsi_id_str[j],bus_attr);
}
if (page_28_chg.bus[j].bus_width) {
/* check if 8 bit bus is allowable with current configuration before
enabling option */
for (i=0; i < ioa->num_devices; i++) {
scsi_dev_data = ioa->dev[i].scsi_dev_data;
if ((scsi_dev_data) && (scsi_dev_data->id & 0xF8) &&
(j == scsi_dev_data->channel)) {
page_28_chg.bus[j].bus_width = 0;
break;
}
}
}
if (page_28_chg.bus[j].bus_width) {
body = add_line_to_body(body,_("Wide Enabled"), "%4");
bus_attr = get_bus_attr_buf(bus_attr);
bus_attr->type = bus_width_type;
bus_attr->bus = j;
bus_attr->page_28 = &page_28_cur;
bus_attr->ioa = ioa;
if (page_28_cur.bus[j].bus_width == 16)
i_con = add_i_con(i_con,_("Yes"),bus_attr);
else
i_con = add_i_con(i_con,_("No"),bus_attr);
}
if (page_28_chg.bus[j].max_xfer_rate) {
body = add_line_to_body(body,_("Maximum Bus Throughput"), "%9");
bus_attr = get_bus_attr_buf(bus_attr);
bus_attr->type = max_xfer_rate_type;
bus_attr->bus = j;
bus_attr->page_28 = &page_28_cur;
bus_attr->ioa = ioa;
sprintf(max_xfer_rate_str[j],"%d MB/s",
(page_28_cur.bus[j].max_xfer_rate *
page_28_cur.bus[j].bus_width)/(10 * 8));
i_con = add_i_con(i_con,max_xfer_rate_str[j],bus_attr);
}
}
n_change_bus_attr.body = body;
while (1) {
s_out = screen_driver(&n_change_bus_attr,header_lines,i_con);
rc = s_out->rc;
for_each_icon(temp_i_con) {
if (!temp_i_con->field_data[0]) {
bus_attr = (struct bus_attr *)temp_i_con->data;
rc = bus_attr_menu(ioa, bus_attr, temp_i_con->y, header_lines);
if (rc == CANCEL_FLAG)
rc = RC_SUCCESS;
bus_num = bus_attr->bus;
if (bus_attr->type == qas_capability_type) {
if (page_28_cur.bus[bus_num].qas_capability ==
IPR_MODEPAGE28_QAS_CAPABILITY_DISABLE_ALL)
sprintf(temp_i_con->field_data,_("Disable"));
else
sprintf(temp_i_con->field_data,_("Enable"));
} else if (bus_attr->type == scsi_id_type) {
sprintf(temp_i_con->field_data,"%d",page_28_cur.bus[bus_num].scsi_id);
} else if (bus_attr->type == bus_width_type) {
if (page_28_cur.bus[bus_num].bus_width == 16)
sprintf(temp_i_con->field_data,_("Yes"));
else
sprintf(temp_i_con->field_data,_("No"));
} else if (bus_attr->type == max_xfer_rate_type) {
sprintf(temp_i_con->field_data,"%d MB/s",
(page_28_cur.bus[bus_num].max_xfer_rate *
page_28_cur.bus[bus_num].bus_width)/(10 * 8));
}
break;
}
}
if (rc)
goto leave;
}
leave:
free_all_bus_attr_buf();
free(n_change_bus_attr.body);
n_change_bus_attr.body = NULL;
free_i_con(i_con);
free(s_out);
return rc;
}
int confirm_change_bus_attr(i_container *i_con)
{
struct ipr_ioa *ioa;
int rc, j, i;
struct ipr_scsi_buses *page_28_cur;
struct ipr_scsi_buses page_28_chg;
struct scsi_dev_data *scsi_dev_data;
char scsi_id_str[5][16];
char max_xfer_rate_str[5][16];
int header_lines = 0;
char *body = NULL;
char buffer[128];
struct screen_output *s_out;
rc = RC_SUCCESS;
page_28_cur = bus_attr_head->page_28;
ioa = bus_attr_head->ioa;
/* determine changable and default values */
for (j = 0; j < page_28_cur->num_buses; j++) {
page_28_chg.bus[j].qas_capability = 0;
if (ioa->scsi_id_changeable)
page_28_chg.bus[j].scsi_id = 1;
else
page_28_chg.bus[j].scsi_id = 0;
page_28_chg.bus[j].bus_width = 1;
page_28_chg.bus[j].max_xfer_rate = 1;
}
body = body_init(n_confirm_change_bus_attr.header, &header_lines);
body = add_line_to_body(body, ioa->ioa.gen_name, NULL);
header_lines++;
for (j = 0; j < page_28_cur->num_buses; j++) {
sprintf(buffer,_(" BUS%d"), j);
body = add_line_to_body(body, buffer, NULL);
if (page_28_chg.bus[j].qas_capability) {
if (page_28_cur->bus[j].qas_capability ==
IPR_MODEPAGE28_QAS_CAPABILITY_DISABLE_ALL)
body = add_line_to_body(body, _("QAS Capability"), _("Disable"));
else
body = add_line_to_body(body, _("QAS Capability"), _("Enable"));
}
if (page_28_chg.bus[j].scsi_id) {
sprintf(scsi_id_str[j],"%d",page_28_cur->bus[j].scsi_id);
body = add_line_to_body(body,_("Host SCSI ID"), scsi_id_str[j]);
}
if (page_28_chg.bus[j].bus_width) {
/* check if 8 bit bus is allowable with current configuration before
enabling option */
for (i=0; i < ioa->num_devices; i++) {
scsi_dev_data = ioa->dev[i].scsi_dev_data;
if ((scsi_dev_data) && (scsi_dev_data->id & 0xF8) &&
(j == scsi_dev_data->channel)) {
page_28_chg.bus[j].bus_width = 0;
break;
}
}
}
if (page_28_chg.bus[j].bus_width) {
if (page_28_cur->bus[j].bus_width == 16)
body = add_line_to_body(body,_("Wide Enabled"), _("Yes"));
else
body = add_line_to_body(body,_("Wide Enabled"), _("No"));
}
if (page_28_chg.bus[j].max_xfer_rate) {
sprintf(max_xfer_rate_str[j],"%d MB/s",
(page_28_cur->bus[j].max_xfer_rate *
page_28_cur->bus[j].bus_width)/(10 * 8));
body = add_line_to_body(body,_("Maximum Bus Throughput"), max_xfer_rate_str[j]);
}
}
n_confirm_change_bus_attr.body = body;
s_out = screen_driver(&n_confirm_change_bus_attr,header_lines,NULL);
rc = s_out->rc;
free(s_out);
free(n_confirm_change_bus_attr.body);
n_confirm_change_bus_attr.body = NULL;
if (rc)
return rc;
processing();
rc = ipr_set_bus_attr(ioa, page_28_cur, 1);
if (!rc)
rc = 45 | EXIT_FLAG;
return rc;
}
int bus_attr_menu(struct ipr_ioa *ioa, struct bus_attr *bus_attr, int start_row, int header_lines)
{
int i, scsi_id, found;
int num_menu_items;
int menu_index;
ITEM **menu_item = NULL;
struct scsi_dev_data *scsi_dev_data;
struct ipr_scsi_buses *page_28_cur;
int *userptr;
int *retptr;
u8 bus_num;
int max_bus_width, max_xfer_rate;
int rc = RC_SUCCESS;
/* start_row represents the row in which the top most
menu item will be placed. Ideally this will be on the
same line as the field in which the menu is opened for*/
start_row += 2; /* for title */ /* FIXME */
page_28_cur = bus_attr->page_28;
bus_num = bus_attr->bus;
if (bus_attr->type == qas_capability_type) {
num_menu_items = 2;
menu_item = malloc(sizeof(ITEM **) * (num_menu_items + 1));
userptr = malloc(sizeof(int) * num_menu_items);
menu_item[0] = new_item("Enable","");
userptr[0] = 2;
set_item_userptr(menu_item[0],
(char *)&userptr[0]);
menu_item[1] = new_item("Disable","");
userptr[1] = 1;
set_item_userptr(menu_item[1],
(char *)&userptr[1]);
menu_item[2] = (ITEM *)NULL;
rc = display_menu(menu_item, start_row, menu_index, &retptr);
if ((rc == RC_SUCCESS) &&
(page_28_cur->bus[bus_num].qas_capability != *retptr)) {
page_28_cur->bus[bus_num].qas_capability = *retptr;
}
i=0;
while (menu_item[i] != NULL)
free_item(menu_item[i++]);
free(menu_item);
free(userptr);
menu_item = NULL;
} else if (bus_attr->type == scsi_id_type) {
num_menu_items = 16;
menu_item = malloc(sizeof(ITEM **) * (num_menu_items + 1));
userptr = malloc(sizeof(int) * num_menu_items);
menu_index = 0;
for (scsi_id = 0, found = 0; scsi_id < 16; scsi_id++, found = 0) {
for (i=0; i < ioa->num_devices; i++) {
scsi_dev_data = ioa->dev[i].scsi_dev_data;
if (scsi_dev_data == NULL)
continue;
if ((scsi_id == scsi_dev_data->id) &&
(bus_num == scsi_dev_data->channel)) {
found = 1;
break;
}
}
if (!found) {
switch (scsi_id) {
case 0:
menu_item[menu_index] = new_item("0","");
userptr[menu_index] = 0;
set_item_userptr(menu_item[menu_index],
(char *)&userptr[menu_index]);
menu_index++;
break;
case 1:
menu_item[menu_index] = new_item("1","");
userptr[menu_index] = 1;
set_item_userptr(menu_item[menu_index],
(char *)&userptr[menu_index]);
menu_index++;
break;
case 2:
menu_item[menu_index] = new_item("2","");
userptr[menu_index] = 2;
set_item_userptr(menu_item[menu_index],
(char *)&userptr[menu_index]);
menu_index++;
break;
case 3:
menu_item[menu_index] = new_item("3","");
userptr[menu_index] = 3;
set_item_userptr(menu_item[menu_index],
(char *)&userptr[menu_index]);
menu_index++;
break;
case 4:
menu_item[menu_index] = new_item("4","");
userptr[menu_index] = 4;
set_item_userptr(menu_item[menu_index],
(char *)&userptr[menu_index]);
menu_index++;
break;
case 5:
menu_item[menu_index] = new_item("5","");
userptr[menu_index] = 5;
set_item_userptr(menu_item[menu_index],
(char *)&userptr[menu_index]);
menu_index++;
break;
case 6:
menu_item[menu_index] = new_item("6","");
userptr[menu_index] = 6;
set_item_userptr(menu_item[menu_index],
(char *)&userptr[menu_index]);
menu_index++;
break;
case 7:
menu_item[menu_index] = new_item("7","");
userptr[menu_index] = 7;
set_item_userptr(menu_item[menu_index],
(char *)&userptr[menu_index]);
menu_index++;
break;
default:
break;
}
}
}
menu_item[menu_index] = (ITEM *)NULL;
rc = display_menu(menu_item, start_row, menu_index, &retptr);
if ((rc == RC_SUCCESS) &&
(page_28_cur->bus[bus_num].scsi_id != *retptr)) {
page_28_cur->bus[bus_num].scsi_id = *retptr;
}
i=0;
while (menu_item[i] != NULL)
free_item(menu_item[i++]);
free(menu_item);
free(userptr);
menu_item = NULL;
} else if (bus_attr->type == bus_width_type) {
num_menu_items = 2;
menu_item = malloc(sizeof(ITEM **) * (num_menu_items + 1));
userptr = malloc(sizeof(int) * num_menu_items);
menu_index = 0;
menu_item[menu_index] = new_item("No","");
userptr[menu_index] = 8;
set_item_userptr(menu_item[menu_index],
(char *)&userptr[menu_index]);
menu_index++;
max_bus_width = 16;
if (max_bus_width == 16) {
menu_item[menu_index] = new_item("Yes","");
userptr[menu_index] = 16;
set_item_userptr(menu_item[menu_index],
(char *)&userptr[menu_index]);
menu_index++;
}
menu_item[menu_index] = (ITEM *)NULL;
rc = display_menu(menu_item, start_row, menu_index, &retptr);
if ((rc == RC_SUCCESS) &&
(page_28_cur->bus[bus_num].bus_width != *retptr)) {
page_28_cur->bus[bus_num].bus_width = *retptr;
}
i=0;
while (menu_item[i] != NULL)
free_item(menu_item[i++]);
free(menu_item);
free(userptr);
menu_item = NULL;
} else if (bus_attr->type == max_xfer_rate_type) {
num_menu_items = 7;
menu_item = malloc(sizeof(ITEM **) * (num_menu_items + 1));
userptr = malloc(sizeof(int) * num_menu_items);
menu_index = 0;
max_xfer_rate = get_max_bus_speed(ioa, bus_num);
switch (max_xfer_rate) {
case 320:
menu_item[menu_index] = new_item("320 MB/s","");
userptr[menu_index] = 3200;
set_item_userptr(menu_item[menu_index],
(char *)&userptr[menu_index]);
menu_index++;
case 160:
menu_item[menu_index] = new_item("160 MB/s","");
userptr[menu_index] = 1600;
set_item_userptr(menu_item[menu_index],
(char *)&userptr[menu_index]);
menu_index++;
case 80:
menu_item[menu_index] = new_item(" 80 MB/s","");
userptr[menu_index] = 800;
set_item_userptr(menu_item[menu_index],
(char *)&userptr[menu_index]);
menu_index++;
case 40:
menu_item[menu_index] = new_item(" 40 MB/s","");
userptr[menu_index] = 400;
set_item_userptr(menu_item[menu_index],
(char *)&userptr[menu_index]);
menu_index++;
case 20:
menu_item[menu_index] = new_item(" 20 MB/s","");
userptr[menu_index] = 200;
set_item_userptr(menu_item[menu_index],
(char *)&userptr[menu_index]);
menu_index++;
case 10:
menu_item[menu_index] = new_item(" 10 MB/s","");
userptr[menu_index] = 100;
set_item_userptr(menu_item[menu_index],
(char *)&userptr[menu_index]);
menu_index++;
case 5:
menu_item[menu_index] = new_item(" 5 MB/s","");
userptr[menu_index] = 50;
set_item_userptr(menu_item[menu_index],
(char *)&userptr[menu_index]);
menu_index++;
break;
default:
menu_item[menu_index] = new_item(" ","");
userptr[menu_index] = 0;
set_item_userptr(menu_item[menu_index],
(char *)&userptr[menu_index]);
menu_index++;
break;
}
menu_item[menu_index] = (ITEM *)NULL;
rc = display_menu(menu_item, start_row, menu_index, &retptr);
if ((rc == RC_SUCCESS) &&
(page_28_cur->bus[bus_num].max_xfer_rate !=
((*retptr) * 8)/page_28_cur->bus[bus_num].bus_width)) {
page_28_cur->bus[bus_num].max_xfer_rate =
((*retptr) * 8)/page_28_cur->bus[bus_num].bus_width;
}
i=0;
while (menu_item[i] != NULL)
free_item(menu_item[i++]);
free(menu_item);
free(userptr);
menu_item = NULL;
}
return rc;
}
int display_menu(ITEM **menu_item,
int menu_start_row,
int menu_index_max,
int **userptrptr)
{
ITEM *cur_item;
MENU *menu;
WINDOW *box1_win, *box2_win, *field_win;
int menu_rows, menu_cols, menu_rows_disp;
int menu_index;
int use_box2 = 0;
int cur_item_index;
int ch, i;
int rc = RC_SUCCESS;
int max_y,max_x;
getmaxyx(stdscr,max_y,max_x);
menu = new_menu(menu_item);
scale_menu(menu, &menu_rows, &menu_cols);
menu_rows_disp = menu_rows;
/* check if fits in current screen, + 1 is added for
bottom border, +1 is added for buffer */
if ((menu_start_row + menu_rows + 1 + 1) > max_y) {
menu_start_row = max_y - (menu_rows + 1 + 1);
if (menu_start_row < (8 + 1)) {
/* size is adjusted by 2 to allow for top
and bottom border, add +1 for buffer */
menu_rows_disp = max_y - (8 + 2 + 1);
menu_start_row = (8 + 1);
}
}
if (menu_rows > menu_rows_disp) {
set_menu_format(menu, menu_rows_disp, 1);
use_box2 = 1;
}
set_menu_mark(menu, "*");
scale_menu(menu, &menu_rows, &menu_cols);
box1_win = newwin(menu_rows + 2, menu_cols + 2, menu_start_row - 1, 54);
field_win = newwin(menu_rows, menu_cols, menu_start_row, 55);
set_menu_win(menu, field_win);
post_menu(menu);
box(box1_win,ACS_VLINE,ACS_HLINE);
if (use_box2) {
box2_win = newwin(menu_rows + 2, 3, menu_start_row - 1, 54 + menu_cols + 1);
box(box2_win,ACS_VLINE,ACS_HLINE);
/* initialize scroll bar */
for (i = 0; i < menu_rows_disp/2; i++)
mvwaddstr(box2_win, i + 1, 1, "#");
/* put down arrows in */
for (i = menu_rows_disp; i > (menu_rows_disp - menu_rows_disp/2); i--)
mvwaddstr(box2_win, i, 1, "v");
}
wnoutrefresh(box1_win);
menu_index = 0;
while (1) {
if (use_box2)
wnoutrefresh(box2_win);
wnoutrefresh(field_win);
doupdate();
ch = getch();
if (IS_ENTER_KEY(ch)) {
cur_item = current_item(menu);
cur_item_index = item_index(cur_item);
*userptrptr = item_userptr(menu_item[cur_item_index]);
break;
} else if ((ch == KEY_DOWN) || (ch == '\t')) {
if (use_box2 && (menu_index < (menu_index_max - 1))) {
menu_index++;
if (menu_index == menu_rows_disp) {
/* put up arrows in */
for (i = 0; i < menu_rows_disp/2; i++)
mvwaddstr(box2_win, i + 1, 1, "^");
}
if (menu_index == (menu_index_max - 1)) {
/* remove down arrows */
for (i = menu_rows_disp; i > (menu_rows_disp - menu_rows_disp/2); i--)
mvwaddstr(box2_win, i, 1, "#");
}
}
menu_driver(menu,REQ_DOWN_ITEM);
} else if (ch == KEY_UP) {
if (use_box2 && menu_index != 0) {
menu_index--;
if (menu_index == (menu_index_max - menu_rows_disp - 1)) {
/* put down arrows in */
for (i = menu_rows_disp; i > (menu_rows_disp - menu_rows_disp/2); i--)
mvwaddstr(box2_win, i, 1, "v");
}
if (menu_index == 0) {
/* remove up arrows */
for (i = 0; i < menu_rows_disp/2; i++)
mvwaddstr(box2_win, i + 1, 1, "#");
}
}
menu_driver(menu,REQ_UP_ITEM);
} else if (IS_EXIT_KEY(ch)) {
rc = EXIT_FLAG;
break;
} else if (IS_CANCEL_KEY(ch)) {
rc = CANCEL_FLAG;
break;
}
}
unpost_menu(menu);
free_menu(menu);
wclear(field_win);
wrefresh(field_win);
delwin(field_win);
wclear(box1_win);
wrefresh(box1_win);
delwin(box1_win);
if (use_box2) {
wclear(box2_win);
wrefresh(box2_win);
delwin(box2_win);
}
return rc;
}
int driver_config(i_container *i_con)
{
int rc, k;
char *buffer[2];
struct ipr_ioa *ioa;
struct screen_output *s_out;
int header_lines;
int toggle = 0;
processing();
/* empty the linked list that contains field pointers */
i_con = free_i_con(i_con);
rc = RC_SUCCESS;
check_current_config(false);
body_init_status(buffer, n_driver_config.header, &header_lines);
for_each_ioa(ioa) {
i_con = add_i_con(i_con,"\0",ioa);
print_dev(k, &ioa->ioa, buffer, "%1", ioa, k);
}
do {
n_driver_config.body = buffer[toggle&1];
s_out = screen_driver(&n_driver_config,header_lines,i_con);
toggle++;
} while (s_out->rc == TOGGLE_SCREEN);
rc = s_out->rc;
free(s_out);
for (k=0; k<2; k++) {
free(buffer[k]);
buffer[k] = NULL;
}
n_driver_config.body = NULL;
return rc;
}
int get_log_level(struct ipr_ioa *ioa)
{
struct sysfs_class_device *class_device;
struct sysfs_attribute *attr;
int value;
class_device = sysfs_open_class_device("scsi_host",
ioa->host_name);
if (!class_device)
return 0;
attr = sysfs_get_classdev_attr(class_device,
"log_level");
if (!attr)
return 0;
sscanf(attr->value, "%d", &value);
sysfs_close_class_device(class_device);
return value;
}
void set_log_level(struct ipr_ioa *ioa, char *log_level)
{
struct sysfs_class_device *class_device;
struct sysfs_attribute *attr;
class_device = sysfs_open_class_device("scsi_host",
ioa->host_name);
if (!class_device)
return;
attr = sysfs_get_classdev_attr(class_device,
"log_level");
if (!attr)
return;
sysfs_write_attribute(attr, log_level, 2);
sysfs_close_class_device(class_device);
}
int change_driver_config(i_container *i_con)
{
int rc, i, digits;
int found = 0;
i_container *temp_i_con;
struct ipr_ioa *ioa;
struct screen_output *s_out;
char buffer[128];
char *body = NULL;
char *input;
for_each_icon(temp_i_con) {
ioa = (struct ipr_ioa *)(temp_i_con->data);
if (ioa == NULL)
continue;
input = temp_i_con->field_data;
if (strcmp(input, "1") == 0) {
found++;
break;
}
}
if (!found)
return 2;
i_con = free_i_con(i_con);
/* i_con to return field data */
i_con = add_i_con(i_con,"",NULL);
body = body_init(n_change_driver_config.header, NULL);
sprintf(buffer,"Adapter Location: %s\n", ioa->pci_address);
body = add_line_to_body(body, buffer, NULL);
sprintf(buffer,"%d", get_log_level(ioa));
body = add_line_to_body(body,_("Current Log Level"), buffer);
body = add_line_to_body(body,_("New Log Level"), "%2");
n_change_driver_config.body = body;
s_out = screen_driver(&n_change_driver_config, 0, i_con);
free(n_change_driver_config.body);
n_change_driver_config.body = NULL;
rc = s_out->rc;
if (!rc) {
for (i = 0, digits = 0; i < strlen(i_con->field_data); i++) {
if (isdigit(i_con->field_data[i])) {
digits++;
} else if (!isspace(i_con->field_data[i])) {
rc = 48;
break;
}
}
if (!rc && digits) {
set_log_level(ioa, i_con->field_data);
rc = 57;
}
}
free(s_out);
return rc;
}
int disk_config(i_container * i_con)
{
int rc, j, i, k;
int len = 0;
int num_lines = 0;
struct ipr_ioa *ioa;
struct scsi_dev_data *scsi_dev_data;
struct screen_output *s_out;
int header_lines;
int array_id;
char *buffer[2];
int toggle = 1;
struct ipr_dev_record *dev_record;
struct ipr_array_record *array_record;
char *prot_level_str;
processing();
rc = RC_SUCCESS;
i_con = free_i_con(i_con);
check_current_config(false);
body_init_status(buffer, n_disk_config.header, &header_lines);
for_each_ioa(ioa) {
if (ioa->ioa.scsi_dev_data == NULL)
continue;
/* print JBOD and non-member AF devices*/
for (j = 0; j < ioa->num_devices; j++) {
scsi_dev_data = ioa->dev[j].scsi_dev_data;
if (!scsi_dev_data || ioa->ioa_dead ||
((scsi_dev_data->type != TYPE_DISK) &&
(scsi_dev_data->type != IPR_TYPE_AF_DISK)) ||
(ipr_is_hot_spare(&ioa->dev[j])) ||
(ipr_is_volume_set(&ioa->dev[j])) ||
(ipr_is_array_member(&ioa->dev[j])))
continue;
if (ipr_is_af_dasd_device(&ioa->dev[j]) && ioa->is_secondary)
continue;
print_dev(k, &ioa->dev[j], buffer, "%1", ioa, k);
i_con = add_i_con(i_con,"\0",&ioa->dev[j]);
num_lines++;
}
/* print Hot Spare devices*/
for (j = 0; j < ioa->num_devices; j++) {
scsi_dev_data = ioa->dev[j].scsi_dev_data;
if ((scsi_dev_data == NULL ) ||
ioa->ioa_dead || ioa->is_secondary ||
(!ipr_is_hot_spare(&ioa->dev[j])))
continue;
print_dev(k, &ioa->dev[j], buffer, "%1", ioa, k);
i_con = add_i_con(i_con,"\0",&ioa->dev[j]);
num_lines++;
}
/* print volume set and associated devices*/
for (j = 0; j < ioa->num_devices; j++) {
if (!ipr_is_volume_set(&ioa->dev[j]))
continue;
array_record = ioa->dev[j].array_rcd;
if (array_record->start_cand)
continue;
/* query resource state to acquire protection level string */
prot_level_str = get_prot_level_str(ioa->supported_arrays,
array_record->raid_level);
strncpy(ioa->dev[j].prot_level_str,prot_level_str, 8);
print_dev(k, &ioa->dev[j], buffer, "%1", ioa, k);
i_con = add_i_con(i_con,"\0",&ioa->dev[j]);
dev_record = ioa->dev[j].dev_rcd;
array_id = dev_record->array_id;
num_lines++;
for (i = 0; i < ioa->num_devices; i++) {
dev_record = ioa->dev[i].dev_rcd;
if (!(ipr_is_array_member(&ioa->dev[i])) ||
(ipr_is_volume_set(&ioa->dev[i])) ||
((dev_record != NULL) &&
(dev_record->array_id != array_id)))
continue;
if (ioa->is_secondary)
continue;
strncpy(ioa->dev[i].prot_level_str, prot_level_str, 8);
print_dev(k, &ioa->dev[i], buffer, "%1", ioa, k);
i_con = add_i_con(i_con,"\0",&ioa->dev[i]);
num_lines++;
}
}
}
if (num_lines == 0) {
for (k=0; k<2; k++) {
len = strlen(buffer[k]);
buffer[k] = realloc(buffer[k], len +
strlen(_(no_dev_found)) + 8);
sprintf(buffer[k] + len, "\n%s", _(no_dev_found));
}
}
do {
n_disk_config.body = buffer[toggle&1];
s_out = screen_driver(&n_disk_config,header_lines,i_con);
toggle++;
} while (s_out->rc == TOGGLE_SCREEN);
for (k=0; k<2; k++) {
free(buffer[k]);
buffer[k] = NULL;
}
n_disk_config.body = NULL;
rc = s_out->rc;
free(s_out);
return rc;
}
struct disk_config_attr {
int option;
int queue_depth;
int format_timeout;
int tcq_enabled;
};
static int disk_config_menu(struct ipr_dev *ipr_dev, struct disk_config_attr *disk_config_attr,
int start_row, int header_lines)
{
int i;
int num_menu_items;
int menu_index;
ITEM **menu_item = NULL;
int *retptr;
int *userptr = NULL;
int rc = RC_SUCCESS;
/* start_row represents the row in which the top most
menu item will be placed. Ideally this will be on the
same line as the field in which the menu is opened for*/
start_row += 2; /* for title */ /* FIXME */
if (disk_config_attr->option == 1) { /* queue depth*/
rc = display_input(start_row, &disk_config_attr->queue_depth);
if (disk_config_attr->queue_depth > 128)
disk_config_attr->queue_depth = 128;
} else if (disk_config_attr->option == 3) { /* tag command queue.*/
num_menu_items = 2;
menu_item = malloc(sizeof(ITEM **) * (num_menu_items + 1));
userptr = malloc(sizeof(int) * num_menu_items);
menu_index = 0;
menu_item[menu_index] = new_item("No","");
userptr[menu_index] = 0;
set_item_userptr(menu_item[menu_index],
(char *)&userptr[menu_index]);
menu_index++;
menu_item[menu_index] = new_item("Yes","");
userptr[menu_index] = 1;
set_item_userptr(menu_item[menu_index],
(char *)&userptr[menu_index]);
menu_index++;
menu_item[menu_index] = (ITEM *)NULL;
rc = display_menu(menu_item, start_row, menu_index, &retptr);
if (rc == RC_SUCCESS)
disk_config_attr->tcq_enabled = *retptr;
i=0;
while (menu_item[i] != NULL)
free_item(menu_item[i++]);
free(menu_item);
free(userptr);
menu_item = NULL;
} else if (disk_config_attr->option == 2) { /* format t.o.*/
num_menu_items = 5;
menu_item = malloc(sizeof(ITEM **) * (num_menu_items + 1));
userptr = malloc(sizeof(int) * num_menu_items);
menu_index = 0;
menu_item[menu_index] = new_item("8 hr","");
userptr[menu_index] = 8;
set_item_userptr(menu_item[menu_index],
(char *)&userptr[menu_index]);
menu_index++;
menu_item[menu_index] = new_item("4 hr","");
userptr[menu_index] = 4;
set_item_userptr(menu_item[menu_index],
(char *)&userptr[menu_index]);
menu_index++;
menu_item[menu_index] = new_item("3 hr","");
userptr[menu_index] = 3;
set_item_userptr(menu_item[menu_index],
(char *)&userptr[menu_index]);
menu_index++;
menu_item[menu_index] = new_item("2 hr","");
userptr[menu_index] = 2;
set_item_userptr(menu_item[menu_index],
(char *)&userptr[menu_index]);
menu_index++;
menu_item[menu_index] = new_item("1 hr","");
userptr[menu_index] = 1;
set_item_userptr(menu_item[menu_index],
(char *)&userptr[menu_index]);
menu_index++;
menu_item[menu_index] = (ITEM *)NULL;
rc = display_menu(menu_item, start_row, menu_index, &retptr);
if (rc == RC_SUCCESS)
disk_config_attr->format_timeout = *retptr;
i=0;
while (menu_item[i] != NULL)
free_item(menu_item[i++]);
free(menu_item);
free(userptr);
menu_item = NULL;
}
return rc;
}
int change_disk_config(i_container * i_con)
{
int rc;
i_container *i_con_head_saved;
struct ipr_dev *ipr_dev;
char qdepth_str[4];
char format_timeout_str[5];
char buffer[128];
i_container *temp_i_con;
int found = 0;
char *input;
struct disk_config_attr disk_config_attr[3];
struct disk_config_attr *config_attr = NULL;
struct ipr_disk_attr disk_attr;
int header_lines = 0;
char *body = NULL;
struct screen_output *s_out;
struct ipr_array_record *array_record;
int tcq_warning = 0;
int tcq_blocked = 0;
int tcq_enabled = 0;
rc = RC_SUCCESS;
for_each_icon(temp_i_con) {
ipr_dev = (struct ipr_dev *)temp_i_con->data;
if (ipr_dev == NULL)
continue;
input = temp_i_con->field_data;
if (strcmp(input, "1") == 0) {
found++;
break;
}
}
if (!found)
return INVALID_OPTION_STATUS;
rc = ipr_get_dev_attr(ipr_dev, &disk_attr);
if (rc)
return 66 | EXIT_FLAG;
i_con_head_saved = i_con_head; /* FIXME */
i_con_head = i_con = NULL;
body = body_init(n_change_disk_config.header, &header_lines);
sprintf(buffer, "Device: %s %s\n", ipr_dev->scsi_dev_data->sysfs_device_name,
ipr_dev->dev_name);
header_lines += 2;
if (ipr_is_volume_set(ipr_dev) || page0x0a_setup(ipr_dev))
header_lines += 1;
/* xxx
else if (ipr_is_af_dasd_device(ipr_dev) && disk_attr.queue_depth > 1)
tcq_warning = 1;
else if (ipr_is_gscsi(ipr_dev) && disk_attr.tcq_enabled)
tcq_warning = 1;
else
tcq_blocked = 1;
*/
if (tcq_warning) {
body = add_line_to_body(body, buffer, NULL);
body = add_string_to_body(body,
_("Note: Tagged queuing to this device is ENABLED "
"and it does not support the required "
"control mode page settings to run safely in this mode!\n\n"),
"", &header_lines);
} else if (tcq_blocked) {
body = add_line_to_body(body, buffer, NULL);
body = add_string_to_body(body,
_("Note: Tagged queuing to this device is disabled by default "
"since it does not support the required control mode page "
"settings to run safely in this mode.\n\n"),
"", &header_lines);
}
if (ipr_force)
tcq_warning = tcq_blocked = 0;
if (!tcq_blocked || ipr_is_gscsi(ipr_dev)) {
body = add_line_to_body(body,_("Queue Depth"), "%3");
disk_config_attr[0].option = 1;
disk_config_attr[0].queue_depth = disk_attr.queue_depth;
sprintf(qdepth_str,"%d",disk_config_attr[0].queue_depth);
i_con = add_i_con(i_con, qdepth_str, &disk_config_attr[0]);
}
array_record = ipr_dev->array_rcd;
if (array_record &&
array_record->common.record_id == IPR_RECORD_ID_ARRAY_RECORD) {
/* VSET, no further fields */
} else if (ipr_is_af_dasd_device(ipr_dev)) {
disk_config_attr[1].option = 2;
disk_config_attr[1].format_timeout = disk_attr.format_timeout / (60 * 60);
body = add_line_to_body(body,_("Format Timeout"), "%4");
sprintf(format_timeout_str,"%d hr",disk_config_attr[1].format_timeout);
i_con = add_i_con(i_con, format_timeout_str, &disk_config_attr[1]);
} else if (!tcq_blocked) {
disk_config_attr[2].option = 3;
disk_config_attr[2].tcq_enabled = disk_attr.tcq_enabled;
body = add_line_to_body(body,_("Tag Command Queueing"), "%4");
tcq_enabled = disk_config_attr[2].tcq_enabled;
if (disk_config_attr[2].tcq_enabled)
i_con = add_i_con(i_con,_("Yes"),&disk_config_attr[2]);
else
i_con = add_i_con(i_con,_("No"),&disk_config_attr[2]);
}
n_change_disk_config.body = body;
while (1) {
s_out = screen_driver(&n_change_disk_config, header_lines, i_con);
rc = s_out->rc;
found = 0;
for_each_icon(temp_i_con) {
if (!temp_i_con->field_data[0]) {
config_attr = (struct disk_config_attr *)temp_i_con->data;
rc = disk_config_menu(ipr_dev, config_attr, temp_i_con->y, header_lines);
if (rc == CANCEL_FLAG)
rc = RC_SUCCESS;
if (config_attr->option == 1) {
sprintf(temp_i_con->field_data,"%d", config_attr->queue_depth);
disk_attr.queue_depth = config_attr->queue_depth;
}
else if (config_attr->option == 2) {
sprintf(temp_i_con->field_data,"%d hr", config_attr->format_timeout);
disk_attr.format_timeout = config_attr->format_timeout * 60 * 60;
}
else if (config_attr->option == 3) {
if (config_attr->tcq_enabled)
sprintf(temp_i_con->field_data,_("Yes"));
else
sprintf(temp_i_con->field_data,_("No"));
disk_attr.tcq_enabled = config_attr->tcq_enabled;
}
found++;
break;
}
}
if (rc)
goto leave;
if (!found)
break;
}
ipr_set_dev_attr(ipr_dev, &disk_attr, 1);
leave:
free(n_change_disk_config.body);
n_change_disk_config.body = NULL;
free_i_con(i_con);
i_con_head = i_con_head_saved;
free(s_out);
return rc;
}
int ioa_config(i_container * i_con)
{
int rc, k;
int len = 0;
int num_lines = 0;
struct ipr_ioa *ioa;
struct screen_output *s_out;
int header_lines;
char *buffer[2];
int toggle = 1;
processing();
rc = RC_SUCCESS;
i_con = free_i_con(i_con);
check_current_config(false);
body_init_status(buffer, n_ioa_config.header, &header_lines);
for_each_ioa(ioa) {
if (ioa->ioa.scsi_dev_data == NULL)
continue;
if (!ioa->dual_raid_support)
continue;
print_dev(k, &ioa->ioa, buffer, "%1", ioa, k);
i_con = add_i_con(i_con, "\0", &ioa->ioa);
num_lines++;
}
if (num_lines == 0) {
for (k = 0; k < 2; k++) {
len = strlen(buffer[k]);
buffer[k] = realloc(buffer[k], len +
strlen(_(no_dev_found)) + 8);
sprintf(buffer[k] + len, "\n%s", _(no_dev_found));
}
}
do {
n_ioa_config.body = buffer[toggle&1];
s_out = screen_driver(&n_ioa_config,header_lines,i_con);
toggle++;
} while (s_out->rc == TOGGLE_SCREEN);
for (k = 0; k < 2; k++) {
free(buffer[k]);
buffer[k] = NULL;
}
n_ioa_config.body = NULL;
rc = s_out->rc;
free(s_out);
return rc;
}
struct ioa_config_attr {
int option;
int preferred_primary;
};
int ioa_config_menu(struct ipr_dev *ipr_dev, struct ioa_config_attr *ioa_config_attr,
int start_row, int header_lines)
{
int i;
int num_menu_items;
int menu_index;
ITEM **menu_item = NULL;
int *retptr;
int *userptr = NULL;
int rc = RC_SUCCESS;
/* start_row represents the row in which the top most
menu item will be placed. Ideally this will be on the
same line as the field in which the menu is opened for*/
start_row += 2; /* for title */ /* FIXME */
if (ioa_config_attr->option == 1) {
num_menu_items = 2;
menu_item = malloc(sizeof(ITEM **) * (num_menu_items + 1));
userptr = malloc(sizeof(int) * num_menu_items);
menu_index = 0;
menu_item[menu_index] = new_item("None","");
userptr[menu_index] = 0;
set_item_userptr(menu_item[menu_index],
(char *)&userptr[menu_index]);
menu_index++;
menu_item[menu_index] = new_item("Primary","");
userptr[menu_index] = 1;
set_item_userptr(menu_item[menu_index],
(char *)&userptr[menu_index]);
menu_index++;
menu_item[menu_index] = (ITEM *)NULL;
rc = display_menu(menu_item, start_row, menu_index, &retptr);
if (rc == RC_SUCCESS)
ioa_config_attr->preferred_primary = *retptr;
i = 0;
while (menu_item[i] != NULL)
free_item(menu_item[i++]);
free(menu_item);
free(userptr);
menu_item = NULL;
}
return rc;
}
int change_ioa_config(i_container * i_con)
{
int rc;
i_container *i_con_head_saved;
struct ipr_dev *ipr_dev;
char pref_str[20];
char buffer[128];
i_container *temp_i_con;
int found = 0;
char *input;
struct ioa_config_attr ioa_config_attr[3];
struct ioa_config_attr *config_attr = NULL;
struct ipr_ioa_attr ioa_attr;
int header_lines = 0;
char *body = NULL;
struct screen_output *s_out;
rc = RC_SUCCESS;
for_each_icon(temp_i_con) {
ipr_dev = (struct ipr_dev *)temp_i_con->data;
if (ipr_dev == NULL)
continue;
input = temp_i_con->field_data;
if (strcmp(input, "1") == 0) {
found++;
break;
}
}
if (!found)
return INVALID_OPTION_STATUS;
rc = ipr_get_ioa_attr(ipr_dev->ioa, &ioa_attr);
if (rc)
return 66 | EXIT_FLAG;
i_con_head_saved = i_con_head; /* FIXME */
i_con_head = i_con = NULL;
body = body_init(n_change_disk_config.header, &header_lines);
sprintf(buffer, "Adapter: %s/%d %s %s\n", ipr_dev->ioa->pci_address,
ipr_dev->ioa->host_num, ipr_dev->scsi_dev_data->vendor_id,
ipr_dev->scsi_dev_data->product_id);
body = add_line_to_body(body, buffer, NULL);
header_lines += 2;
body = add_line_to_body(body,_("Preferred Dual Adapter State"), "%13");
ioa_config_attr[0].option = 1;
ioa_config_attr[0].preferred_primary = ioa_attr.preferred_primary;
if (ioa_attr.preferred_primary)
sprintf(pref_str, "Primary");
else
sprintf(pref_str, "None");
i_con = add_i_con(i_con, pref_str, &ioa_config_attr[0]);
n_change_ioa_config.body = body;
while (1) {
s_out = screen_driver(&n_change_ioa_config, header_lines, i_con);
rc = s_out->rc;
found = 0;
for_each_icon(temp_i_con) {
if (!temp_i_con->field_data[0]) {
config_attr = (struct ioa_config_attr *)temp_i_con->data;
rc = ioa_config_menu(ipr_dev, config_attr, temp_i_con->y, header_lines);
if (rc == CANCEL_FLAG)
rc = RC_SUCCESS;
if (config_attr->option == 1) {
if (config_attr->preferred_primary)
sprintf(temp_i_con->field_data, "Primary");
else
sprintf(temp_i_con->field_data, "None");
ioa_attr.preferred_primary = config_attr->preferred_primary;
}
found++;
break;
}
}
if (rc)
goto leave;
if (!found)
break;
}
ipr_set_ioa_attr(ipr_dev->ioa, &ioa_attr, 1);
leave:
free(n_change_ioa_config.body);
n_change_ioa_config.body = NULL;
free_i_con(i_con);
i_con_head = i_con_head_saved;
free(s_out);
return rc;
}
int download_ucode(i_container * i_con)
{
int rc, j, i, k;
int len = 0;
int num_lines = 0;
struct ipr_ioa *ioa;
struct scsi_dev_data *scsi_dev_data;
struct screen_output *s_out;
int header_lines;
int array_id;
char *buffer[2];
int toggle = 0;
struct ipr_dev_record *dev_record;
struct ipr_array_record *array_record;
char *prot_level_str;
processing();
rc = RC_SUCCESS;
i_con = free_i_con(i_con);
check_current_config(false);
body_init_status(buffer, n_download_ucode.header, &header_lines);
for_each_ioa(ioa) {
if (!ioa->ioa.scsi_dev_data || ioa->ioa_dead)
continue;
print_dev(k, &ioa->ioa, buffer, "%1", ioa, k);
i_con = add_i_con(i_con, "\0", &ioa->ioa);
num_lines++;
/* print JBOD and non-member AF devices*/
for (j = 0; j < ioa->num_devices; j++) {
scsi_dev_data = ioa->dev[j].scsi_dev_data;
if ((scsi_dev_data == NULL) || ioa->ioa_dead ||
((scsi_dev_data->type != TYPE_DISK) &&
(scsi_dev_data->type != IPR_TYPE_AF_DISK) /* &&
(scsi_dev_data->type != TYPE_ENCLOSURE) &&
(scsi_dev_data->type != TYPE_PROCESSOR) */) ||
(ipr_is_hot_spare(&ioa->dev[j])) ||
(ipr_is_volume_set(&ioa->dev[j])) ||
(ipr_is_array_member(&ioa->dev[j])))
continue;
if (ioa->is_secondary)
continue;
print_dev(k, &ioa->dev[j], buffer, "%1", ioa, k);
i_con = add_i_con(i_con,"\0",&ioa->dev[j]);
num_lines++;
}
/* print Hot Spare devices*/
for (j = 0; j < ioa->num_devices; j++) {
if (ioa->ioa_dead || !ipr_is_hot_spare(&ioa->dev[j]))
continue;
if (ioa->is_secondary)
continue;
print_dev(k, &ioa->dev[j], buffer, "%1", ioa, k);
i_con = add_i_con(i_con,"\0",&ioa->dev[j]);
num_lines++;
}
/* print volume set and associated devices*/
for (j = 0; j < ioa->num_devices; j++) {
if (!ipr_is_volume_set(&ioa->dev[j]) || ioa->is_secondary)
continue;
array_record = ioa->dev[j].array_rcd;
if (array_record->start_cand)
continue;
/* query resource state to acquire protection level string */
prot_level_str = get_prot_level_str(ioa->supported_arrays,
array_record->raid_level);
strncpy(ioa->dev[j].prot_level_str,prot_level_str, 8);
dev_record = ioa->dev[j].dev_rcd;
array_id = dev_record->array_id;
num_lines++;
for (i = 0; i < ioa->num_devices; i++) {
dev_record = ioa->dev[i].dev_rcd;
if (!(ipr_is_array_member(&ioa->dev[i])) ||
(ipr_is_volume_set(&ioa->dev[i])) ||
((dev_record != NULL) &&
(dev_record->array_id != array_id)))
continue;
strncpy(ioa->dev[i].prot_level_str, prot_level_str, 8);
print_dev(k, &ioa->dev[i], buffer, "%1", ioa, k);
i_con = add_i_con(i_con,"\0",&ioa->dev[i]);
num_lines++;
}
}
}
if (num_lines == 0) {
for (k=0; k<2; k++) {
len = strlen(buffer[k]);
buffer[k] = realloc(buffer[k], len +
strlen(_(no_dev_found)) + 8);
sprintf(buffer[k] + len, "\n%s", _(no_dev_found));
}
}
do {
n_download_ucode.body = buffer[toggle&1];
s_out = screen_driver(&n_download_ucode,header_lines,i_con);
toggle++;
} while (s_out->rc == TOGGLE_SCREEN);
for (k=0; k<2; k++) {
free(buffer[k]);
buffer[k] = NULL;
}
n_download_ucode.body = NULL;
rc = s_out->rc;
free(s_out);
return rc;
}
static int update_ucode(struct ipr_dev *dev, struct ipr_fw_images *fw_image)
{
char *body;
int header_lines, status, time = 0;
pid_t pid, done;
struct ipr_dasd_inquiry_page3 page3_inq;
u32 fw_version;
int rc = 0;
body = body_init(n_download_ucode_in_progress.header, &header_lines);
n_download_ucode_in_progress.body = body;
time_screen_driver(&n_download_ucode_in_progress, time, 0);
pid = fork();
if (pid) {
do {
done = waitpid(pid, &status, WNOHANG);
sleep(1);
time++;
time_screen_driver(&n_download_ucode_in_progress, time, 0);
} while (done == 0);
} else {
if (dev->scsi_dev_data && dev->scsi_dev_data->type == IPR_TYPE_ADAPTER)
ipr_update_ioa_fw(dev->ioa, fw_image, 1);
else
ipr_update_disk_fw(dev, fw_image, 1);
exit(0);
}
memset(&page3_inq, 0, sizeof(page3_inq));
ipr_inquiry(dev, 3, &page3_inq, sizeof(page3_inq));
fw_version = page3_inq.release_level[0] << 24 |
page3_inq.release_level[1] << 16 |
page3_inq.release_level[2] << 8 |
page3_inq.release_level[3];
if (fw_version != fw_image->version)
rc = 67 | EXIT_FLAG;
free(n_download_ucode_in_progress.body);
n_download_ucode_in_progress.body = NULL;
return rc;
}
int process_choose_ucode(struct ipr_dev *ipr_dev)
{
struct ipr_fw_images *list;
struct ipr_fw_images *fw_image;
char *body = NULL;
int header_lines = 0;
int list_count, rc, i;
char buffer[256];
int found = 0;
i_container *i_con_head_saved;
i_container *i_con = NULL;
i_container *temp_i_con;
char *input;
int version_swp;
char *version;
struct screen_output *s_out;
struct ipr_dasd_inquiry_page3 page3_inq;
struct ipr_res_addr res_addr;
if (!ipr_dev->scsi_dev_data)
return 67 | EXIT_FLAG;
if (ipr_dev->scsi_dev_data->type == IPR_TYPE_ADAPTER)
rc = get_ioa_firmware_image_list(ipr_dev->ioa, &list);
/*
else if (ipr_dev->scsi_dev_data->type == TYPE_ENCLOSURE || ipr_dev->scsi_dev_data->type == TYPE_PROCESSOR)
rc = get_ses_firmware_image_list(ipr_dev, &list);
*/
else
rc = get_dasd_firmware_image_list(ipr_dev, &list);
if (rc < 0)
return 67 | EXIT_FLAG;
else
list_count = rc;
memset(&page3_inq, 0, sizeof(page3_inq));
ipr_inquiry(ipr_dev, 3, &page3_inq, sizeof(page3_inq));
if (ipr_dev->scsi_dev_data &&
ipr_dev->scsi_dev_data->type == IPR_TYPE_ADAPTER) {
sprintf(buffer, _("Adapter to download: %-8s %-16s\n"),
ipr_dev->scsi_dev_data->vendor_id,
ipr_dev->scsi_dev_data->product_id);
body = add_string_to_body(NULL, buffer, "", &header_lines);
sprintf(buffer, _("Adapter Location: %s.%d/\n"),
ipr_dev->ioa->pci_address, ipr_dev->ioa->host_num);
} else {
get_res_addr(ipr_dev, &res_addr);
sprintf(buffer, _("Device to download: %-8s %-16s\n"),
ipr_dev->scsi_dev_data->vendor_id,
ipr_dev->scsi_dev_data->product_id);
body = add_string_to_body(NULL, buffer, "", &header_lines);
sprintf(buffer, _("Device Location: %d:%d:%d\n"),
res_addr.bus, res_addr.target, res_addr.lun);
}
body = add_string_to_body(body, buffer, "", &header_lines);
if (isprint(page3_inq.release_level[0]) &&
isprint(page3_inq.release_level[1]) &&
isprint(page3_inq.release_level[2]) &&
isprint(page3_inq.release_level[3]))
sprintf(buffer, "%s%02X%02X%02X%02X (%c%c%c%c)\n\n",
_("The current microcode for this device is: "),
page3_inq.release_level[0],
page3_inq.release_level[1],
page3_inq.release_level[2],
page3_inq.release_level[3],
page3_inq.release_level[0],
page3_inq.release_level[1],
page3_inq.release_level[2],
page3_inq.release_level[3]);
else
sprintf(buffer, "%s%02X%02X%02X%02X\n\n",
_("The current microcode for this device is: "),
page3_inq.release_level[0],
page3_inq.release_level[1],
page3_inq.release_level[2],
page3_inq.release_level[3]);
body = add_string_to_body(body, buffer, "", &header_lines);
body = __body_init(body, n_choose_ucode.header, &header_lines);
i_con_head_saved = i_con_head;
i_con_head = i_con = NULL;
if (list_count) {
for (i = 0; i < list_count; i++) {
version_swp = htonl(list[i].version);
version = (char *)&version_swp;
if (isprint(version[0]) && isprint(version[1]) &&
isprint(version[2]) && isprint(version[3]))
sprintf(buffer," %%1 %.8X (%c%c%c%c) %s\n",list[i].version,
version[0], version[1], version[2], version[3],
list[i].file);
else
sprintf(buffer," %%1 %.8X %s",list[i].version,list[i].file);
body = add_line_to_body(body, buffer, NULL);
i_con = add_i_con(i_con, "\0", &list[i]);
}
} else {
body = add_line_to_body(body,"(No available images)",NULL);
}
n_choose_ucode.body = body;
s_out = screen_driver(&n_choose_ucode, header_lines, i_con);
free(n_choose_ucode.body);
n_choose_ucode.body = NULL;
for_each_icon(temp_i_con) {
fw_image =(struct ipr_fw_images *)(temp_i_con->data);
if (ipr_dev == NULL)
continue;
input = temp_i_con->field_data;
if (input == NULL)
continue;
if (strcmp(input, "1") == 0) {
found++;
break;
}
}
if (!found)
goto leave;
body = body_init(n_confirm_download_ucode.header, &header_lines);
version_swp = htonl(fw_image->version);
version = (char *)&version_swp;
if (isprint(version[0]) && isprint(version[1]) &&
isprint(version[2]) && isprint(version[3]))
sprintf(buffer," 1 %.8X (%c%c%c%c) %s\n",fw_image->version,
version[0], version[1], version[2], version[3],
fw_image->file);
else
sprintf(buffer," 1 %.8X %s\n",fw_image->version,fw_image->file);
body = add_line_to_body(body, buffer, NULL);
n_confirm_download_ucode.body = body;
s_out = screen_driver(&n_confirm_download_ucode,header_lines,i_con);
free(n_confirm_download_ucode.body);
n_confirm_download_ucode.body = NULL;
if (!s_out->rc)
rc = update_ucode(ipr_dev, fw_image);
leave:
free(list);
i_con = free_i_con(i_con);
i_con_head = i_con_head_saved;
free(s_out);
return rc;
}
int choose_ucode(i_container * i_con)
{
i_container *temp_i_con;
struct ipr_dev *ipr_dev;
char *input;
int rc;
int dev_num = 0;
if (i_con == NULL)
return 1;
for_each_icon(temp_i_con) {
ipr_dev =(struct ipr_dev *)(temp_i_con->data);
if (ipr_dev == NULL)
continue;
input = temp_i_con->field_data;
if (input == NULL)
continue;
if (strcmp(input, "1") == 0) {
rc = process_choose_ucode(ipr_dev);
if (rc & EXIT_FLAG)
return rc;
dev_num++;
}
}
if (dev_num == 0)
/* Invalid option. No devices selected. */
return 17;
return 0;
}
#define MAX_CMD_LENGTH 1000
int log_menu(i_container *i_con)
{
char cmnd[MAX_CMD_LENGTH];
int rc, loop;
struct stat file_stat;
struct screen_output *s_out;
int offset = 0;
sprintf(cmnd,"%s/boot.msg",log_root_dir);
rc = stat(cmnd, &file_stat);
if (rc)
/* file does not exist - do not display option */
offset--;
for (loop = 0; loop < (n_log_menu.num_opts + offset); loop++) {
n_log_menu.body = ipr_list_opts(n_log_menu.body,
n_log_menu.options[loop].key,
n_log_menu.options[loop].list_str);
}
n_log_menu.body = ipr_end_list(n_log_menu.body);
s_out = screen_driver(&n_log_menu,0,NULL);
free(n_log_menu.body);
n_log_menu.body = NULL;
rc = s_out->rc;
i_con = s_out->i_con;
i_con = free_i_con(i_con);
free(s_out);
return rc;
}
int ibm_storage_log_tail(i_container *i_con)
{
char cmnd[MAX_CMD_LENGTH];
int rc, len;
def_prog_mode();
rc = system("rm -rf "_PATH_TMP".ipr.err; mkdir "_PATH_TMP".ipr.err");
if (rc != 0) {
len = sprintf(cmnd, "cd %s; zcat -f messages", log_root_dir);
len += sprintf(cmnd + len," | grep ipr | ");
len += sprintf(cmnd + len, "sed \"s/ `hostname -s` kernel: ipr//g\" | ");
len += sprintf(cmnd + len, "sed \"s/ localhost kernel: ipr//g\" | ");
len += sprintf(cmnd + len, "sed \"s/ kernel: ipr//g\" | ");
len += sprintf(cmnd + len, "sed \"s/\\^M//g\" | ");
len += sprintf(cmnd + len, FAILSAFE_EDITOR);
closelog();
openlog("iprconfig", LOG_PERROR | LOG_PID | LOG_CONS, LOG_USER);
syslog(LOG_ERR, "Error encountered concatenating log files...\n");
syslog(LOG_ERR, "Using failsafe editor...\n");
closelog();
openlog("iprconfig", LOG_PID | LOG_CONS, LOG_USER);
sleep(3);
} else {
len = sprintf(cmnd,"cd %s; zcat -f messages | grep ipr |", log_root_dir);
len += sprintf(cmnd + len, "sed \"s/ `hostname -s` kernel: ipr//g\"");
len += sprintf(cmnd + len, " | sed \"s/ localhost kernel: ipr//g\"");
len += sprintf(cmnd + len, " | sed \"s/ kernel: ipr//g\"");
len += sprintf(cmnd + len, " | sed \"s/\\^M//g\" ");
len += sprintf(cmnd + len, ">> "_PATH_TMP".ipr.err/errors");
system(cmnd);
sprintf(cmnd, "%s "_PATH_TMP".ipr.err/errors", editor);
}
rc = system(cmnd);
if ((rc != 0) && (rc != 127)) {
/* "Editor returned %d. Try setting the default editor" */
s_status.num = rc;
return 65;
} else
/* return with no status */
return 1;
}
static int select_log_file(const struct dirent *dir_entry)
{
if (dir_entry) {
if (strstr(dir_entry->d_name, "messages") == dir_entry->d_name)
return 1;
}
return 0;
}
static int compare_log_file(const void *log_file1, const void *log_file2)
{
char *first_start_num, *first_end_num;
char *second_start_num, *second_end_num;
struct dirent **first_dir, **second_dir;
char name1[100], name2[100];
int first, second;
first_dir = (struct dirent **)log_file1;
second_dir = (struct dirent **)log_file2;
if (strcmp((*first_dir)->d_name, "messages") == 0)
return 1;
if (strcmp((*second_dir)->d_name, "messages") == 0)
return -1;
strcpy(name1, (*first_dir)->d_name);
strcpy(name2, (*second_dir)->d_name);
first_start_num = strchr(name1, '.');
first_end_num = strrchr(name1, '.');
second_start_num = strchr(name2, '.');
second_end_num = strrchr(name2, '.');
if (first_start_num == first_end_num) {
/* Not compressed */
first_end_num = name1 + strlen(name1);
second_end_num = name2 + strlen(name2);
} else {
*first_end_num = '\0';
*second_end_num = '\0';
}
first = strtoul(first_start_num, NULL, 10);
second = strtoul(second_start_num, NULL, 10);
if (first > second)
return -1;
else
return 1;
}
int ibm_storage_log(i_container *i_con)
{
char cmnd[MAX_CMD_LENGTH];
int rc, i;
struct dirent **log_files;
struct dirent **dirent;
int num_dir_entries;
int len;
def_prog_mode();
num_dir_entries = scandir(log_root_dir, &log_files, select_log_file, compare_log_file);
rc = system("rm -rf "_PATH_TMP".ipr.err; mkdir "_PATH_TMP".ipr.err");
if (num_dir_entries)
dirent = log_files;
if (rc != 0) {
len = sprintf(cmnd, "cd %s; zcat -f ", log_root_dir);
/* Probably have a read-only root file system */
for (i = 0; i < num_dir_entries; i++) {
len += sprintf(cmnd + len, "%s ", (*dirent)->d_name);
dirent++;
}
len += sprintf(cmnd + len," | grep ipr-err | ");
len += sprintf(cmnd + len, "sed \"s/ `hostname -s` kernel: ipr//g\" | ");
len += sprintf(cmnd + len, "sed \"s/ localhost kernel: ipr//g\" | ");
len += sprintf(cmnd + len, "sed \"s/ kernel: ipr//g\" | ");
len += sprintf(cmnd + len, "sed \"s/\\^M//g\" | ");
len += sprintf(cmnd + len, FAILSAFE_EDITOR);
closelog();
openlog("iprconfig", LOG_PERROR | LOG_PID | LOG_CONS, LOG_USER);
syslog(LOG_ERR, "Error encountered concatenating log files...\n");
syslog(LOG_ERR, "Using failsafe editor...\n");
closelog();
openlog("iprconfig", LOG_PID | LOG_CONS, LOG_USER);
sleep(3);
} else {
for (i = 0; i < num_dir_entries; i++) {
len = sprintf(cmnd,"cd %s; zcat -f %s | grep ipr |", log_root_dir, (*dirent)->d_name);
len += sprintf(cmnd + len, "sed \"s/ `hostname -s` kernel: ipr//g\"");
len += sprintf(cmnd + len, " | sed \"s/ localhost kernel: ipr//g\"");
len += sprintf(cmnd + len, " | sed \"s/ kernel: ipr//g\"");
len += sprintf(cmnd + len, " | sed \"s/\\^M//g\" ");
len += sprintf(cmnd + len, ">> "_PATH_TMP".ipr.err/errors");
system(cmnd);
dirent++;
}
sprintf(cmnd, "%s "_PATH_TMP".ipr.err/errors", editor);
}
rc = system(cmnd);
if (num_dir_entries)
free(*log_files);
if ((rc != 0) && (rc != 127)) {
/* "Editor returned %d. Try setting the default editor" */
s_status.num = rc;
return 65;
} else
/* return with no status */
return 1;
}
int kernel_log(i_container *i_con)
{
char cmnd[MAX_CMD_LENGTH];
int rc, i;
struct dirent **log_files;
struct dirent **dirent;
int num_dir_entries;
int len;
def_prog_mode();
num_dir_entries = scandir(log_root_dir, &log_files, select_log_file, compare_log_file);
if (num_dir_entries)
dirent = log_files;
rc = system("rm -rf "_PATH_TMP".ipr.err; mkdir "_PATH_TMP".ipr.err");
if (rc != 0) {
/* Probably have a read-only root file system */
len = sprintf(cmnd, "cd %s; zcat -f ", log_root_dir);
/* Probably have a read-only root file system */
for (i = 0; i < num_dir_entries; i++) {
len += sprintf(cmnd + len, "%s ", (*dirent)->d_name);
dirent++;
}
len += sprintf(cmnd + len, " | sed \"s/\\^M//g\" ");
len += sprintf(cmnd + len, "| %s", FAILSAFE_EDITOR);
closelog();
openlog("iprconfig", LOG_PERROR | LOG_PID | LOG_CONS, LOG_USER);
syslog(LOG_ERR, "Error encountered concatenating log files...\n");
syslog(LOG_ERR, "Using failsafe editor...\n");
openlog("iprconfig", LOG_PID | LOG_CONS, LOG_USER);
sleep(3);
} else {
for (i = 0; i < num_dir_entries; i++) {
sprintf(cmnd,
"cd %s; zcat -f %s | sed \"s/\\^M//g\" >> "_PATH_TMP".ipr.err/errors",
log_root_dir, (*dirent)->d_name);
system(cmnd);
dirent++;
}
sprintf(cmnd, "%s "_PATH_TMP".ipr.err/errors", editor);
}
rc = system(cmnd);
if (num_dir_entries)
free(*log_files);
if ((rc != 0) && (rc != 127)) {
/* "Editor returned %d. Try setting the default editor" */
s_status.num = rc;
return 65;
}
else
/* return with no status */
return 1;
}
int iprconfig_log(i_container *i_con)
{
char cmnd[MAX_CMD_LENGTH];
int rc, i;
struct dirent **log_files;
struct dirent **dirent;
int num_dir_entries;
int len;
def_prog_mode();
num_dir_entries = scandir(log_root_dir, &log_files, select_log_file, compare_log_file);
rc = system("rm -rf "_PATH_TMP".ipr.err; mkdir "_PATH_TMP".ipr.err");
if (num_dir_entries)
dirent = log_files;
if (rc != 0) {
len = sprintf(cmnd, "cd %s; zcat -f ", log_root_dir);
/* Probably have a read-only root file system */
for (i = 0; i < num_dir_entries; i++) {
len += sprintf(cmnd + len, "%s ", (*dirent)->d_name);
dirent++;
}
len += sprintf(cmnd + len," | grep iprconfig | ");
len += sprintf(cmnd + len, FAILSAFE_EDITOR);
closelog();
openlog("iprconfig", LOG_PERROR | LOG_PID | LOG_CONS, LOG_USER);
syslog(LOG_ERR, "Error encountered concatenating log files...\n");
syslog(LOG_ERR, "Using failsafe editor...\n");
openlog("iprconfig", LOG_PID | LOG_CONS, LOG_USER);
sleep(3);
} else {
for (i = 0; i < num_dir_entries; i++) {
len = sprintf(cmnd,"cd %s; zcat -f %s | grep iprconfig ", log_root_dir, (*dirent)->d_name);
len += sprintf(cmnd + len, ">> "_PATH_TMP".ipr.err/errors");
system(cmnd);
dirent++;
}
sprintf(cmnd, "%s "_PATH_TMP".ipr.err/errors", editor);
}
rc = system(cmnd);
if (num_dir_entries)
free(*log_files);
if ((rc != 0) && (rc != 127)) {
/* "Editor returned %d. Try setting the default editor" */
s_status.num = rc;
return 65;
} else
/* return with no status */
return 1;
}
int kernel_root(i_container *i_con)
{
int rc;
struct screen_output *s_out;
char *body = NULL;
i_con = free_i_con(i_con);
/* i_con to return field data */
i_con = add_i_con(i_con,"",NULL);
body = body_init(n_kernel_root.header, NULL);
body = add_line_to_body(body,_("Current root directory"), log_root_dir);
body = add_line_to_body(body,_("New root directory"), "%39");
n_kernel_root.body = body;
s_out = screen_driver(&n_kernel_root,0,i_con);
free(n_kernel_root.body);
n_kernel_root.body = NULL;
rc = s_out->rc;
free(s_out);
return rc;
}
int confirm_kernel_root(i_container *i_con)
{
int rc;
DIR *dir;
char *input;
struct screen_output *s_out;
char *body = NULL;
input = strip_trailing_whitespace(i_con->field_data);
dir = opendir(input);
if (dir == NULL)
/* "Invalid directory" */
return 59;
else {
closedir(dir);
if (strcmp(log_root_dir, input) == 0)
/*"Root directory unchanged"*/
return 61;
}
body = body_init(n_confirm_kernel_root.header, NULL);
body = add_line_to_body(body,_("New root directory"), input);
n_confirm_kernel_root.body = body;
s_out = screen_driver(&n_confirm_kernel_root,0,i_con);
free(n_confirm_kernel_root.body);
n_confirm_kernel_root.body = NULL;
rc = s_out->rc;
if (rc == 0) {
/*"Root directory changed to %s"*/
strcpy(log_root_dir, i_con->field_data);
s_status.str = log_root_dir;
rc = (EXIT_FLAG | 60);
}
else
/*"Root directory unchanged"*/
rc = (EXIT_FLAG | 61);
free(s_out);
return rc;
}
int set_default_editor(i_container *i_con)
{
int rc = 0;
struct screen_output *s_out;
char *body = NULL;
i_con = free_i_con(i_con);
i_con = add_i_con(i_con,"",NULL);
body = body_init(n_set_default_editor.header, NULL);
body = add_line_to_body(body, _("Current editor"), editor);
body = add_line_to_body(body, _("New editor"), "%39");
n_set_default_editor.body = body;
s_out = screen_driver(&n_set_default_editor,0,i_con);
free(n_set_default_editor.body);
n_set_default_editor.body = NULL;
rc = s_out->rc;
free(s_out);
return rc;
}
int confirm_set_default_editor(i_container *i_con)
{
int rc;
char *input;
struct screen_output *s_out;
char *body = NULL;
input = strip_trailing_whitespace(i_con->field_data);
if (strcmp(editor, input) == 0)
/*"Editor unchanged"*/
return 63;
body = body_init(n_confirm_set_default_editor.header, NULL);
body = add_line_to_body(body,_("New editor"), input);
n_confirm_set_default_editor.body = body;
s_out = screen_driver(&n_confirm_set_default_editor,0,i_con);
free(n_confirm_set_default_editor.body);
n_confirm_set_default_editor.body = NULL;
rc = s_out->rc;
if (rc == 0) {
/*"Editor changed to %s"*/
strcpy(editor, i_con->field_data);
s_status.str = editor;
rc = (EXIT_FLAG | 62);
} else
/*"Editor unchanged"*/
rc = (EXIT_FLAG | 63);
free(s_out);
return rc;
}
int restore_log_defaults(i_container *i_con)
{
strcpy(log_root_dir, DEFAULT_LOG_DIR);
strcpy(editor, DEFAULT_EDITOR);
return 64; /*"Default log values restored"*/
}
int ibm_boot_log(i_container *i_con)
{
char cmnd[MAX_CMD_LENGTH];
int rc;
int len;
struct stat file_stat;
sprintf(cmnd,"%s/boot.msg",log_root_dir);
rc = stat(cmnd, &file_stat);
if (rc)
return 2; /* "Invalid option specified" */
def_prog_mode();
rc = system("rm -rf "_PATH_TMP".ipr.err; mkdir "_PATH_TMP".ipr.err");
if (rc != 0) {
len = sprintf(cmnd, "cd %s; zcat -f ", log_root_dir);
/* Probably have a read-only root file system */
len += sprintf(cmnd + len, "boot.msg");
len += sprintf(cmnd + len," | grep ipr |");
len += sprintf(cmnd + len, FAILSAFE_EDITOR);
closelog();
openlog("iprconfig", LOG_PERROR | LOG_PID | LOG_CONS, LOG_USER);
syslog(LOG_ERR, "Error encountered concatenating log files...\n");
syslog(LOG_ERR, "Using failsafe editor...\n");
closelog();
openlog("iprconfig", LOG_PID | LOG_CONS, LOG_USER);
sleep(3);
} else {
len = sprintf(cmnd,"cd %s; zcat -f boot.msg | grep ipr | "
"sed 's/<[0-9]>ipr-err: //g' | sed 's/<[0-9]>ipr: //g'",
log_root_dir);
len += sprintf(cmnd + len, ">> "_PATH_TMP".ipr.err/errors");
system(cmnd);
sprintf(cmnd, "%s "_PATH_TMP".ipr.err/errors", editor);
}
rc = system(cmnd);
if ((rc != 0) && (rc != 127)) {
s_status.num = rc;
return 65; /* "Editor returned %d. Try setting the default editor" */
} else
return 1; /* return with no status */
}
char *print_device(struct ipr_dev *ipr_dev, char *body, char *option,
struct ipr_ioa *ioa, int type)
{
u16 len = 0;
struct scsi_dev_data *scsi_dev_data = ipr_dev->scsi_dev_data;
int i, rc;
struct ipr_query_res_state res_state;
struct ipr_res_addr res_addr;
u8 ioctl_buffer[255];
char raid_str[48];
int status;
int format_req = 0;
struct ipr_mode_parm_hdr *mode_parm_hdr;
struct ipr_block_desc *block_desc;
struct sense_data_t sense_data;
char *dev_name = ipr_dev->dev_name;
char *gen_name = ipr_dev->gen_name;
char node_name[7];
int tab_stop = 0;
char vendor_id[IPR_VENDOR_ID_LEN + 1];
char product_id[IPR_PROD_ID_LEN + 1];
struct ipr_common_record *common_record;
struct ipr_dev_record *device_record;
struct ipr_array_record *array_record;
struct ipr_cmd_status cmd_status;
struct ipr_cmd_status_record *status_record;
int percent_cmplt = 0;
int format_in_progress = 0;
if (body)
len = strlen(body);
body = realloc(body, len + 256);
if (((type & 3) == 2) && (strlen(gen_name) > 5))
ipr_strncpy_0(node_name, &gen_name[5], 6);
else if (strlen(dev_name) > 5)
ipr_strncpy_0(node_name, &dev_name[5], 6);
else
node_name[0] = '\0';
len += sprintf(body + len, " %s %-6s %s/%d:",
option,
node_name,
ioa->pci_address,
ioa->host_num);
if (scsi_dev_data && scsi_dev_data->type == IPR_TYPE_ADAPTER) {
if (type&1) {
len += sprintf(body + len," %-25s ", get_ioa_desc(ipr_dev->ioa));
} else
len += sprintf(body + len," %-8s %-16s ",
scsi_dev_data->vendor_id,
scsi_dev_data->product_id);
if (ioa->ioa_dead)
len += sprintf(body + len, "Not Operational\n");
else if (ioa->nr_ioa_microcode)
len += sprintf(body + len, "Not Ready\n");
else
len += sprintf(body + len, "Operational\n");
} else if ((scsi_dev_data) &&
(scsi_dev_data->type == IPR_TYPE_EMPTY_SLOT)) {
tab_stop = sprintf(body + len,"%d:%d: ",
scsi_dev_data->channel,
scsi_dev_data->id);
len += tab_stop;
for (i=0;i<12-tab_stop;i++)
body[len+i] = ' ';
len += 12-tab_stop;
len += sprintf(body + len, "%-8s %-16s "," ", " ");
len += sprintf(body + len, "Empty\n");
} else {
get_res_addr(ipr_dev, &res_addr);
tab_stop = sprintf(body + len,"%d:%d:%d ", res_addr.bus,
res_addr.target, res_addr.lun);
if (scsi_dev_data) {
ipr_strncpy_0(vendor_id, scsi_dev_data->vendor_id, IPR_VENDOR_ID_LEN);
ipr_strncpy_0(product_id, scsi_dev_data->product_id, IPR_PROD_ID_LEN);
}
else if (ipr_dev->qac_entry) {
common_record = ipr_dev->qac_entry;
if (common_record->record_id == IPR_RECORD_ID_DEVICE_RECORD) {
device_record = (struct ipr_dev_record *)common_record;
ipr_strncpy_0(vendor_id, device_record->vendor_id, IPR_VENDOR_ID_LEN);
ipr_strncpy_0(product_id , device_record->product_id, IPR_PROD_ID_LEN);
} else if (common_record->record_id == IPR_RECORD_ID_ARRAY_RECORD) {
array_record = (struct ipr_array_record *)common_record;
ipr_strncpy_0(vendor_id, array_record->vendor_id, IPR_VENDOR_ID_LEN);
ipr_strncpy_0(product_id , array_record->product_id,
IPR_PROD_ID_LEN);
}
}
len += tab_stop;
for (i=0;i<12-tab_stop;i++)
body[len+i] = ' ';
len += 12-tab_stop;
if (ipr_is_volume_set(ipr_dev)) {
rc = ipr_query_command_status(&ioa->ioa, &cmd_status);
if (!rc) {
array_record = ipr_dev->array_rcd;
status_record = cmd_status.record;
for (i=0; i < cmd_status.num_records; i++, status_record++) {
if (array_record->array_id == status_record->array_id) {
if (status_record->status == IPR_CMD_STATUS_IN_PROGRESS)
percent_cmplt = status_record->percent_complete;
}
}
}
} else if (ipr_is_af_dasd_device(ipr_dev)) {
rc = ipr_query_command_status(ipr_dev, &cmd_status);
if ((rc == 0) && (cmd_status.num_records != 0)) {
status_record = cmd_status.record;
if ((status_record->status != IPR_CMD_STATUS_SUCCESSFUL) &&
(status_record->status != IPR_CMD_STATUS_FAILED)) {
percent_cmplt = status_record->percent_complete;
format_in_progress++;
}
}
} else if (ipr_is_gscsi(ipr_dev)) {
/* Send Test Unit Ready to find percent complete in sense data. */
rc = ipr_test_unit_ready(ipr_dev, &sense_data);
if ((rc == CHECK_CONDITION) &&
((sense_data.error_code & 0x7F) == 0x70) &&
((sense_data.sense_key & 0x0F) == 0x02) && /* NOT READY */
(sense_data.add_sense_code == 0x04) && /* LOGICAL UNIT NOT READY */
(sense_data.add_sense_code_qual == 0x04)) {/* FORMAT IN PROGRESS */
percent_cmplt = ((int)sense_data.sense_key_spec[1]*100)/0x100;
format_in_progress++;
}
}
if (!(type&1)) {
len += sprintf(body + len, "%-8s %-16s ",
vendor_id, product_id);
} else {
if (ipr_is_hot_spare(ipr_dev))
len += sprintf(body + len, "%-25s ", "Hot Spare");
else if (ipr_is_volume_set(ipr_dev)) {
sprintf(ioctl_buffer, "RAID %s Disk Array",
ipr_dev->prot_level_str);
len += sprintf(body + len, "%-25s ", ioctl_buffer);
} else if (ipr_is_array_member(ipr_dev)) {
if (type&2)
sprintf(raid_str," RAID %s Array Member",
ipr_dev->prot_level_str);
else
sprintf(raid_str,"RAID %s Array Member",
ipr_dev->prot_level_str);
len += sprintf(body + len, "%-25s ", raid_str);
} else if (ipr_is_af_dasd_device(ipr_dev))
len += sprintf(body + len, "%-25s ", "Advanced Function Disk");
else if (scsi_dev_data && scsi_dev_data->type == TYPE_ENCLOSURE)
len += sprintf(body + len, "%-25s ", "Enclosure");
else if (scsi_dev_data && scsi_dev_data->type == TYPE_PROCESSOR)
len += sprintf(body + len, "%-25s ", "Processor");
else
len += sprintf(body + len, "%-25s ", "Physical Disk");
}
if (ipr_is_af(ipr_dev)) {
memset(&res_state, 0, sizeof(res_state));
/* Do a query resource state */
rc = ipr_query_resource_state(ipr_dev, &res_state);
if (rc != 0)
res_state.not_oper = 1;
} else { /* JBOD */
memset(&res_state, 0, sizeof(res_state));
format_req = 0;
/* Issue mode sense/mode select to determine if device needs to be formatted */
status = ipr_mode_sense(ipr_dev, 0x0a, &ioctl_buffer);
if (status == CHECK_CONDITION &&
sense_data.add_sense_code == 0x31 &&
sense_data.add_sense_code_qual == 0x00) {
format_req = 1;
} else {
if (!status) {
mode_parm_hdr = (struct ipr_mode_parm_hdr *)ioctl_buffer;
if (mode_parm_hdr->block_desc_len > 0) {
block_desc = (struct ipr_block_desc *)(mode_parm_hdr+1);
if ((block_desc->block_length[1] != 0x02) ||
(block_desc->block_length[2] != 0x00))
format_req = 1;
}
}
/* check device with test unit ready */
rc = ipr_test_unit_ready(ipr_dev, &sense_data);
if (rc == CHECK_CONDITION &&
sense_data.add_sense_code == 0x31 &&
sense_data.add_sense_code_qual == 0x00)
format_req = 1;
else if (rc)
res_state.not_oper = 1;
}
}
if (format_in_progress)
sprintf(body + len, "%d%% Formatted\n", percent_cmplt);
else if (!scsi_dev_data && ipr_dev->ioa->is_secondary)
sprintf(body + len, "Remote\n");
else if (!scsi_dev_data)
sprintf(body + len, "Missing\n");
else if (!scsi_dev_data->online)
sprintf(body + len, "Offline\n");
else if (res_state.not_oper || res_state.not_func)
sprintf(body + len, "Failed\n");
else if (res_state.read_write_prot)
sprintf(body + len, "R/W Protected\n");
else if (res_state.prot_dev_failed)
sprintf(body + len, "Failed\n");
else if (ipr_is_volume_set(ipr_dev)) {
if (res_state.prot_suspended && ipr_is_volume_set(ipr_dev))
sprintf(body + len, "Degraded\n");
else if (res_state.prot_resuming && ipr_is_volume_set(ipr_dev)) {
if (!(type&1) || (percent_cmplt == 0))
sprintf(body + len, "Rebuilding\n");
else
sprintf(body + len, "%d%% Rebuilt\n", percent_cmplt);
} else if (res_state.degraded_oper || res_state.service_req)
sprintf(body + len, "Degraded\n");
else
sprintf(body + len, "Active\n");
} else if (format_req)
sprintf(body + len, "Format Required\n");
else if (ipr_device_is_zeroed(ipr_dev))
sprintf(body + len, "Zeroed\n");
else
sprintf(body + len, "Active\n");
}
return body;
}
static void usage()
{
printf(_("Usage: iprconfig [options]\n"));
printf(_(" Options: -e name Default editor for viewing error logs\n"));
printf(_(" -k dir Kernel messages root directory\n"));
printf(_(" -c command Command line configuration\n"));
printf(_(" See man page for complete details\n"));
printf(_(" --version Print iprconfig version\n"));
printf(_(" --debug Enable additional error logging\n"));
printf(_(" --force Disable safety checks. See man page for details.\n"));
printf(_(" Use quotes around parameters with spaces\n"));
}
static struct sysfs_dev *head_sdev;
static struct sysfs_dev *tail_sdev;
static struct ipr_dev *find_and_add_dev(char *name)
{
struct ipr_dev *dev = find_blk_dev(name);
if (!dev)
dev = find_gen_dev(name);
if (!dev) {
syslog(LOG_ERR, _("Invalid device specified: %s\n"), name);
return NULL;
}
ipr_add_sysfs_dev(dev, &head_sdev, &tail_sdev);
return dev;
}
static int raid_create_add_dev(char *name)
{
struct ipr_dev *dev = find_and_add_dev(name);
if (!dev)
return -EINVAL;
if (ipr_is_gscsi(dev)) {
if (is_af_blocked(dev, 0))
return -EINVAL;
if (!is_format_allowed(dev))
return -EIO;
add_format_device(dev, dev->ioa->af_block_size);
dev_init_tail->do_init = 1;
}
return 0;
}
static int raid_create_check_num_devs(struct ipr_array_cap_entry *cap,
int num_devs)
{
if (num_devs < cap->min_num_array_devices ||
num_devs > cap->max_num_array_devices ||
(num_devs % cap->min_mult_array_devices) != 0) {
syslog(LOG_ERR, _("Invalid number of devices selected for RAID %s array. %d. "
"Must select minimum of %d devices, maximum of %d devices, "
"and must be a multiple of %d devices\n"),
cap->prot_level_str, num_devs, cap->min_num_array_devices,
cap->max_num_array_devices, cap->min_mult_array_devices);
return -EINVAL;
}
return 0;
}
static int raid_create(char **args, int num_args)
{
int i, num_devs = 0, rc;
int next_raid_level, next_stripe_size, next_qdepth;
char *raid_level = IPR_DEFAULT_RAID_LVL;
int stripe_size, qdepth;
struct ipr_dev *dev;
struct sysfs_dev *sdev;
struct ipr_ioa *ioa = NULL;
struct ipr_array_cap_entry *cap;
next_raid_level = 0;
next_stripe_size = 0;
next_qdepth = 0;
stripe_size = 0;
for (i = 0; i < num_args; i++) {
if (strcmp(args[i], "-r") == 0)
next_raid_level = 1;
else if (strcmp(args[i], "-s") == 0)
next_stripe_size = 1;
else if (strcmp(args[i], "-q") == 0)
next_qdepth = 1;
else if (next_raid_level) {
next_raid_level = 0;
raid_level = args[i];
} else if (next_stripe_size) {
next_stripe_size = 0;
stripe_size = strtoul(args[i], NULL, 10);
} else if (next_qdepth) {
next_qdepth = 0;
qdepth = strtoul(args[i], NULL, 10);
} else if (strncmp(args[i], "/dev", 4) == 0) {
num_devs++;
if (raid_create_add_dev(args[i]))
return -EIO;
}
}
for (sdev = head_sdev; sdev; sdev = sdev->next) {
dev = ipr_sysfs_dev_to_dev(sdev);
if (!dev) {
syslog(LOG_ERR, _("Cannot find device\n"));
return -EINVAL;
}
if (!ioa)
ioa = dev->ioa;
else if (ioa != dev->ioa) {
syslog(LOG_ERR, _("All devices must be attached to the same adapter\n"));
return -EINVAL;
}
}
cap = get_cap_entry(ioa->supported_arrays, raid_level);
if (!cap) {
syslog(LOG_ERR, _("Invalid RAID level for selected adapter. %s\n"), raid_level);
return -EINVAL;
}
if (stripe_size && ((cap->supported_stripe_sizes & stripe_size) != stripe_size)) {
syslog(LOG_ERR, _("Unsupported stripe size for selected adapter. %d\n"),
stripe_size);
return -EINVAL;
}
if ((rc = raid_create_check_num_devs(cap, num_devs)))
return rc;
if (!stripe_size)
stripe_size = cap->recommended_stripe_size;
if (!qdepth)
qdepth = num_devs * 4;
if (dev_init_head) {
send_dev_inits(NULL);
free_devs_to_init();
}
check_current_config(false);
for (sdev = head_sdev; sdev; sdev = sdev->next) {
dev = ipr_sysfs_dev_to_dev(sdev);
if (!dev) {
syslog(LOG_ERR, _("Cannot find device: %s\n"),
sdev->sysfs_device_name);
return -EIO;
}
if (!ipr_is_af_dasd_device(dev)) {
scsi_err(dev, "Invalid device type\n");
return -EIO;
}
dev->dev_rcd->issue_cmd = 1;
}
add_raid_cmd_tail(ioa, &ioa->ioa, ioa->start_array_qac_entry->array_id);
raid_cmd_tail->qdepth = qdepth;
raid_cmd_tail->do_cmd = 1;
rc = ipr_start_array_protection(ioa, stripe_size, cap->prot_level);
if (rc)
return rc;
return raid_start_complete();
}
static int raid_delete(char **args, int num_args)
{
int rc;
struct ipr_dev *dev;
if (num_args != 1) {
syslog(LOG_ERR, _("Specify one array at a time to delete\n"));
return -EINVAL;
}
if (strncmp(args[0], "/dev", 4)) {
syslog(LOG_ERR, _("Invalid argument: %s\n"), args[0]);
return -EINVAL;
}
dev = find_and_add_dev(args[0]);
if (!dev) {
syslog(LOG_ERR, _("Invalid device specified: %s\n"), args[0]);
return -EINVAL;
}
dev->array_rcd->issue_cmd = 1;
if (dev->scsi_dev_data)
rc = ipr_start_stop_stop(dev);
if ((rc = ipr_stop_array_protection(dev->ioa)))
return rc;
return rc;
}
int main(int argc, char *argv[])
{
int next_editor, next_dir, next_cmd, next_dev, i, rc = 0;
char parm_editor[200], parm_dir[200], cmd[200];
char **dev = NULL;
int non_interactive = 0, num_devs = 0;
/* makes program compatible with all terminals -
originally did not display text correctly when user was running xterm */
setenv("TERM", "vt100", 1);
setlocale(LC_ALL, "");
strcpy(parm_dir, DEFAULT_LOG_DIR);
strcpy(parm_editor, DEFAULT_EDITOR);
openlog("iprconfig",
LOG_PID | /* Include the PID with each error */
LOG_CONS, /* Write to system console if there is an error
sending to system logger */
LOG_USER);
if (argc > 1) {
next_editor = 0;
next_dir = 0;
next_cmd = 0;
next_dev = 0;
for (i = 1; i < argc; i++) {
if (parse_option(argv[i]))
continue;
else if (strcmp(argv[i], "-e") == 0)
next_editor = 1;
else if (strcmp(argv[i], "-k") == 0)
next_dir = 1;
else if (strcmp(argv[i], "-c") == 0)
next_cmd = 1;
else if (next_editor) {
strcpy(parm_editor, argv[i]);
next_editor = 0;
} else if (next_dir) {
strcpy(parm_dir, argv[i]);
next_dir = 0;
} else if (next_cmd) {
strcpy(cmd, argv[i]);
non_interactive = 1;
next_cmd = 0;
next_dev = 1;
} else if (next_dev) {
dev = realloc(dev, sizeof(*dev) * (num_devs + 1));
dev[num_devs] = malloc(strlen(argv[i]) + 1);
strcpy(dev[num_devs], argv[i]);
num_devs++;
} else {
usage();
exit(1);
}
}
}
strcpy(log_root_dir, parm_dir);
strcpy(editor, parm_editor);
system("modprobe sg");
exit_func = tool_exit_func;
tool_init(0);
initscr();
if (non_interactive) {
exit_func = cmdline_exit_func;
closelog();
openlog("iprconfig", LOG_PERROR | LOG_PID | LOG_CONS, LOG_USER);
check_current_config(false);
if (num_devs == 0) {
exit_func();
usage();
return -EINVAL;
} else if (strcmp(cmd, "primary") == 0)
rc = set_preferred_primary(dev[0], 1);
else if (strcmp(cmd, "secondary") == 0)
rc = set_preferred_primary(dev[0], 0);
else if (strcmp(cmd, "raid-create") == 0)
rc = raid_create(dev, num_devs);
else if (strcmp(cmd, "raid-delete") == 0)
rc = raid_delete(dev, num_devs);
else {
exit_func();
usage();
return -EINVAL;
}
exit_func();
return rc;
}
cbreak(); /* take input chars one at a time, no wait for \n */
keypad(stdscr,TRUE);
noecho();
s_status.index = 0;
main_menu(NULL);
if (head_zdev){
check_current_config(false);
ipr_cleanup_zeroed_devs();
}
while (head_zdev) {
struct screen_output *s_out;
i_container *i_con;
n_exit_confirm.body = body_init(n_exit_confirm.header, NULL);
for (i = 0; i < n_exit_confirm.num_opts; i++) {
n_exit_confirm.body = ipr_list_opts(n_exit_confirm.body,
n_exit_confirm.options[i].key,
n_exit_confirm.options[i].list_str);
}
n_exit_confirm.body = ipr_end_list(n_exit_confirm.body);
s_out = screen_driver(&n_exit_confirm,0,NULL);
free(n_exit_confirm.body);
n_exit_confirm.body = NULL;
rc = s_out->rc;
i_con = s_out->i_con;
i_con = free_i_con(i_con);
free(s_out);
check_current_config(false);
ipr_cleanup_zeroed_devs();
}
clear();
refresh();
endwin();
exit(0);
return 0;
}