iprutils: suspend/resume utility for BlueHawk

---

This patch implemented suspend/resume utility for BlueHawk drawer according to
BlueHawk Concurrent Maintenance Workbook. The patch included support for both
of GUI and command line interfaces.

Signed-off-by: wenxiong@linux.vnet.ibm.com
This commit is contained in:
Wen Xiong 2012-09-05 14:19:55 -05:00
commit f2f6944780
5 changed files with 910 additions and 79 deletions

10
README
View file

@ -80,6 +80,10 @@ maintanence actions to be performed against those resources when necessary.
Changes Log:
1. Concurrent maintience commands line changes from PCI location to physical location(3/12/2012).
#iprconfig --identify-slot "U5886.001.P915059-P1-D1 1"
#iprconfig --remove-slot "U5886.001.P915059-P1-D1 1"
#iprconfig --add-slot "U5886.001.P915059-P1-D1 1"
#iprconfig -c identify-slot "U5886.001.P915059-P1-D1 1"
#iprconfig -c remove-slot "U5886.001.P915059-P1-D1 1"
#iprconfig -c add-slot "U5886.001.P915059-P1-D1 1"
2. Work with disk enclosures
#iprconfig -c query-disk-enclosure-status
#iprconfig -c suspend-disk-enclosure sg8
#iprconfig -c resume-disk-enclosure sg8

View file

@ -123,7 +123,7 @@ struct special_status {
char *print_device(struct ipr_dev *, char *, char *, int);
int display_menu(ITEM **, int, int, int **);
char *__print_device(struct ipr_dev *, char *, char *, int, int, int, int, int, int, int, int, int, int);
char *__print_device(struct ipr_dev *, char *, char *, int, int, int, int, int, int, int, int, int, int, int, int);
static char *print_path_details(struct ipr_dev *, char *);
static int get_drive_phy_loc(struct ipr_ioa *ioa);
@ -135,6 +135,14 @@ static int get_drive_phy_loc(struct ipr_ioa *ioa);
for (i = 0; i < 3; i++) \
(buf)[i] = print_device(dev, (buf)[i], fmt, (type + 5));
#define print_dev_enclosure(i, dev, buf, fmt, type) \
for (i = 0; i < 2; i++) { \
if ( i == 0 ) \
(buf)[i] = print_device(dev, (buf)[i], fmt, (type + 8)); \
if (i == 1) \
(buf)[i] = print_device(dev, (buf)[i], fmt, (type + 8)); \
}
static struct sysfs_dev *head_sdev;
static struct sysfs_dev *tail_sdev;
@ -1101,31 +1109,37 @@ static char *status_hdr[] = {
/* . . . . . */
/*012345678901234567890123456789012345678901234567890123456789012345678901234567890 */
"OPT Name Resource Path/Address Vendor Product ID Status",
"OPT Name PCI/SCSI Location Description Status",
"OPT Name PCI/SCSI Location Description Status",
"Name Resource Path/Address Vendor Product ID Status",
"Name PCI/SCSI Location Description Status",
"Name PCI/SCSI Location Description Status",
"OPT SAS Port/SAS Address Description Active Status Info",
"OPT SAS Port/SAS Address Description Active Status Info",
"SAS Port/SAS Address Description Active Status Info",
"SAS Port/SAS Address Description Active Status Info",
"OPT Name Platform Location Description Status",
"OPT Name Platform Location Description Status",
"OPT Name SCSI Host/Resource Path Vendor Product ID Status",
"OPT Name SCSI Host/Resource Path Vendor Product ID Status",
"Name Platform Location Description Status"};
"Name Platform Location Description Status",
"OPT Name PCI/Host/Resource Path Serial Number Status",
"OPT Name Physical Location Production ID Status",
"Name Physical Location Serial Number Status"};
static char *status_sep[] = {
"--- ------ -------------------------- -------- ---------------- -----------------",
"--- ------ -------------------------- ------------------------- -----------------",
"--- ------ ------------------------- ------------------------- -----------------",
"------ -------------------------- -------- ---------------- -----------------",
"------ -------------------------- ------------------------- -----------------",
"--- ---------------------- ------------------ ------ ----------------- ----------",
"------ ------------------------- ------------------------- -----------------",
"--- --------------------- ------------------ ------ ----------------- ----------",
"--- ---------------------- ------------------ ------ ----------------- ----------",
"---------------------- ------------------ ------ ----------------- ----------",
"---------------------- ------------------ ------ ----------------- ----------",
"--- ------ -------------------------- ------------------------ -----------------",
"--- ------ -------------------------- -------- ---------------- -----------------",
"--- ------ -------------------------- -------- ---------------- -----------------",
"------ -------------------------- ------------------------ -----------------",
"--- ------ -------------------------- ------------------------- -----------------",
"--- ------ ---------------------------- -------- ---------------- --------------",
"--- ------ ---------------------------- -------- ---------------- --------------",
"------ -------------------------- ------------------------- ------------",
"--- ------ ---------------------------------------- ------------- ------------",
"--- ------ ---------------------------------------- ---------------- ------------",
"------ ---------------------------------------- ------------- ------------",
};
/**
@ -1355,6 +1369,21 @@ static void body_init_status_conc(char *buffer[3], char **header, int *num_lines
buffer[z] = __body_init_status(header, num_lines, (z + 8));
}
/**
* body_init_status_enclosure -
* @buffer: char array
* @header:
* @num_lines: number of lines
*
* Returns:
* nothing
**/
static void body_init_status_enclosure(char *buffer[2], char **header, int *num_lines)
{
buffer[0] = __body_init_status(header, num_lines, 12);
buffer[1] = __body_init_status(header, num_lines, 13);
}
/**
* __body_init -
* @buffer: char array
@ -2414,6 +2443,7 @@ int get_ses_phy_loc(struct ipr_dev *dev)
int rc, i, ret = 1;
struct ses_inquiry_page0 ses_page0_inq;
struct ses_serial_num_vpd ses_vpd_inq;
struct esm_serial_num_vpd esm_vpd_inq;
char buffer[100];
memset(&ses_vpd_inq, 0, sizeof(ses_vpd_inq));
@ -2442,22 +2472,43 @@ int get_ses_phy_loc(struct ipr_dev *dev)
strncat(dev->physical_location, ".", strlen("."));
strncat(dev->physical_location, buffer, strlen(buffer));
}
for (i = 0; !rc && i < ses_page0_inq.page_length; i++) {
if (ses_page0_inq.supported_vpd_page[i] == 0x01) {
ret = ipr_inquiry(dev, 0x01, &esm_vpd_inq, sizeof(esm_vpd_inq));
break;
}
}
if (ret == 0 ) {
ipr_strncpy_0((char *)&dev->serial_number, (char *)&esm_vpd_inq.esm_serial_num[0], sizeof(esm_vpd_inq.esm_serial_num));
ipr_strncpy_0(buffer, (char *)esm_vpd_inq.frb_label,
sizeof(esm_vpd_inq.frb_label));
strncat(dev->physical_location, "-", strlen("-"));
strncat(dev->physical_location, buffer, strlen(buffer));
return 0;
}
return 1;
}
int get_drive_phy_loc_with_ses_phy_loc(struct ipr_dev *ses, struct drive_elem_desc_pg *drive_data, int slot_id, char *buf)
int get_drive_phy_loc_with_ses_phy_loc(struct ipr_dev *ses, struct drive_elem_desc_pg *drive_data, int slot_id, char *buf, int conc_maint)
{
char buffer[DISK_PHY_LOC_LENGTH + 1];
char buffer[DISK_PHY_LOC_LENGTH + 1], *first_hyphen;
char unit_phy_loc[PHYSICAL_LOCATION_LENGTH+1];
ipr_strncpy_0(buffer, (char *)drive_data->dev_elem[slot_id].disk_physical_loc, DISK_PHY_LOC_LENGTH);
if (strlen(ses->physical_location))
sprintf(buf, "%s-%s", ses->physical_location, buffer);
if (!conc_maint)
sprintf(buf, "%s-%s", ses->physical_location, buffer);
else {
ipr_strncpy_0(unit_phy_loc, ses->physical_location, PHYSICAL_LOCATION_LENGTH);
first_hyphen = strchr(unit_phy_loc, '-');
*first_hyphen = '\0';
sprintf(buf, "%s-%s", unit_phy_loc, buffer);
}
else if (strlen(buffer)) {
char unit_phy_loc[PHYSICAL_LOCATION_LENGTH+1], *first_hyphen;
ipr_strncpy_0(unit_phy_loc, ses->ioa->physical_location, PHYSICAL_LOCATION_LENGTH);
first_hyphen = strchr(unit_phy_loc, '-');
*first_hyphen = '\0';
@ -2489,10 +2540,12 @@ static char *ses_details(char *body, struct ipr_dev *dev)
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);
ipr_strncpy_0(buffer, (char *)&dev->serial_number, ESM_SERIAL_NUM_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);
body = add_line_to_body(body,_("Serial Number"), buffer);
rc = ipr_get_fw_version(dev, release_level);
@ -7862,7 +7915,7 @@ static int get_conc_devs(struct ipr_dev ***ret, int action)
scsi_dbg(ses, "%s\n", is_vses ? "Found VSES" : "Found real SES");
for_each_elem_status(elem_status, &ses_data, &ses_cfg) {
get_drive_phy_loc_with_ses_phy_loc(ses, &drive_data, elem_status->slot_id, phy_loc);
get_drive_phy_loc_with_ses_phy_loc(ses, &drive_data, elem_status->slot_id, phy_loc, 1);
if (elem_status->status == IPR_DRIVE_ELEM_STATUS_UNSUPP)
continue;
if (elem_status->status == IPR_DRIVE_ELEM_STATUS_NO_ACCESS)
@ -8104,8 +8157,8 @@ int path_status(i_container * i_con)
continue;
for_each_disk(ioa, dev) {
buffer[0] = __print_device(dev, buffer[0], "%1", 1, 1, 1, 0, 0, 1, 0, 1, 0 ,0);
buffer[1] = __print_device(dev, buffer[1], "%1", 1, 1, 0, 0, 0, 0, 0, 1, 0 ,0);
buffer[0] = __print_device(dev, buffer[0], "%1", 1, 1, 1, 0, 0, 1, 0, 1, 0 ,0, 0, 0);
buffer[1] = __print_device(dev, buffer[1], "%1", 1, 1, 0, 0, 0, 0, 0, 1, 0 ,0, 0, 0);
i_con = add_i_con(i_con, "\0", dev);
num_devs++;
}
@ -12026,6 +12079,19 @@ int ibm_boot_log(i_container *i_con)
return 1; /* return with no status */
}
int get_ses_ioport_status(struct ipr_dev *ses)
{
struct ipr_query_io_port io_status;
int rc = ipr_query_io_dev_port(ses, &io_status);
if (!rc)
ses->active_suspend = io_status.port_state;
else
ses->active_suspend = IOA_DEV_PORT_UNKNOWN;
return rc;
}
/**
* get_status -
* @dev: ipr dev struct
@ -12169,8 +12235,15 @@ static void get_status(struct ipr_dev *dev, char *buf, int percent, int path_sta
sprintf(buf, "Remote");
else if (!scsi_dev_data)
sprintf(buf, "Missing");
else if (!scsi_dev_data->online)
sprintf(buf, "Offline");
else if (!scsi_dev_data->online) {
if (dev->scsi_dev_data->type == TYPE_ENCLOSURE) {
get_ses_ioport_status(dev);
if (dev->active_suspend == IOA_DEV_PORT_SUSPEND)
sprintf(buf, "Suspend");
else
sprintf(buf, "Offline");
}
}
else if (res_state.not_oper || res_state.not_func)
sprintf(buf, "Failed");
else if (res_state.read_write_prot)
@ -12509,7 +12582,7 @@ static char *print_path_details(struct ipr_dev *dev, char *body)
char *__print_device(struct ipr_dev *dev, char *body, char *option,
int sd, int sg, int vpd, int percent, int indent,
int res_path, int ra, int path_status,
int hw_loc, int conc_main)
int hw_loc, int conc_main, int ioa_flag, int serial_num)
{
u16 len = 0;
struct scsi_dev_data *scsi_dev_data = dev->scsi_dev_data;
@ -12522,12 +12595,15 @@ char *__print_device(struct ipr_dev *dev, char *body, char *option,
int loc_len = 0;
char vendor_id[IPR_VENDOR_ID_LEN + 1];
char product_id[IPR_PROD_ID_LEN + 1];
struct ipr_ioa *ioa = dev->ioa;
struct ipr_ioa *ioa = dev->ioa, *ioa_phy_loc;
/* In cases where we're having problems with the device */
if (!ioa)
return body;
if (ioa_flag)
ioa_phy_loc = dev->ioa;
if (body)
len = strlen(body);
body = realloc(body, len + 256);
@ -12542,31 +12618,71 @@ char *__print_device(struct ipr_dev *dev, char *body, char *option,
if (option)
len += sprintf(body + len, " %s ", option);
len += sprintf(body + len, "%-6s ", node_name);
if (scsi_dev_data && scsi_dev_data->type == TYPE_ENCLOSURE && (serial_num == 1 || hw_loc == 1))
len += sprintf(body + len, "%-8s ", node_name);
else
len += sprintf(body + len, "%-6s ", node_name);
if (hw_loc) {
if (strlen(dev->physical_location)) {
loc_len = sprintf(body + len, "%-26s ", dev->physical_location);
len += loc_len;
}
else {
loc_len = sprintf(body + len, "%s/%d:",
ioa->pci_address,
ioa->host_num);
len += loc_len;
if (ioa_flag) {
if (strlen(ioa_phy_loc->physical_location)) {
loc_len = sprintf(body + len, "%-40s ", ioa_phy_loc->physical_location);
len += loc_len;
}
else {
for (i = 0; i < 40-loc_len; i++)
body[len+i] = ' ';
len += 40-loc_len;
}
} else {
if (strlen(dev->physical_location)) {
if (conc_main) {
loc_len = sprintf(body + len, "%-26s ", dev->physical_location);
len += loc_len;
} else {
loc_len = sprintf(body + len, "%-38s ", dev->physical_location);
len += loc_len;
}
} else {
if (conc_main) {
for (i = 0; i < 26-loc_len; i++)
body[len+i] = ' ';
len += 26-loc_len;
} else {
for (i = 0; i < 39-loc_len; i++)
body[len+i] = ' ';
len += 39-loc_len;
}
}
}
}
else {
if (res_path) {
if (ioa->sis64)
if (conc_main) {
if (serial_num == 1) {
if (scsi_dev_data && scsi_dev_data->type == IPR_TYPE_ADAPTER)
loc_len = sprintf(body + len, "%s/%-28d", ioa->pci_address, ioa->host_num);
else {
ipr_format_res_path(dev->res_path[ra].res_path_bytes, res_path_name, IPR_MAX_RES_PATH_LEN);
loc_len = sprintf(body + len, "%s/%d/%-24s", ioa->pci_address, ioa->host_num, res_path_name);
}
} else if (conc_main) {
ipr_format_res_path(dev->res_path[ra].res_path_bytes, res_path_name, IPR_MAX_RES_PATH_LEN);
loc_len = sprintf(body + len, "%d/%-26s ", ioa->host_num, res_path_name);
} else
loc_len = sprintf(body + len, "%-26s ", scsi_dev_data ?
loc_len = sprintf(body + len, "%-26s ",scsi_dev_data ?
scsi_dev_data->res_path : "<unknown>");
else
if (conc_main)
else /*32bit*/
if (serial_num == 1) {
if (scsi_dev_data && scsi_dev_data->type == IPR_TYPE_ADAPTER)
loc_len = sprintf(body + len, "%s/%-29d:", ioa->pci_address, ioa->host_num);
else
loc_len = sprintf(body + len, "%s/%d", ioa->pci_address, ioa->host_num);
} else if (conc_main)
loc_len = sprintf(body + len, "%d/%d:", ioa->host_num,ioa->host_num);
else
loc_len = sprintf(body + len, "%d:", ioa->host_num);
@ -12582,27 +12698,50 @@ char *__print_device(struct ipr_dev *dev, char *body, char *option,
}
if (scsi_dev_data && scsi_dev_data->type == IPR_TYPE_ADAPTER && dev == &ioa->ioa) {
if (!res_path || !ioa->sis64) {
for (i = 0; i < 27-loc_len; i++)
body[len+i] = ' ';
if (serial_num == 1 ) {
if (!res_path || !ioa->sis64) {
for (i = 0; i < 28-loc_len; i++)
body[len+i] = ' ';
len += 27-loc_len;
}
len += 28-loc_len;
}
if (!vpd) {
tab_stop = sprintf(body + len,"%s %s", get_bus_desc(ioa),
get_ioa_desc(dev->ioa));
len += sprintf(body + len,"%-13s ",
ioa->yl_serial_num);
len += tab_stop;
} else if (hw_loc == 1 ) {
if (!res_path || !ioa->sis64) {
for (i = 0; i < 40-loc_len; i++)
body[len+i] = ' ';
for (i = 0; i < 26-tab_stop; i++)
body[len+i] = ' ';
len += 26-tab_stop;
} else
len += sprintf(body + len,"%-8s %-16s ",
scsi_dev_data->vendor_id,
len += 40-loc_len;
}
len += sprintf(body + len,"%-16s ",
scsi_dev_data->product_id);
}
else {
if (!res_path || !ioa->sis64) {
for (i = 0; i < 26-loc_len; i++)
body[len+i] = ' ';
len += 26-loc_len;
}
if (!vpd) {
tab_stop = sprintf(body + len,"%s %s", get_bus_desc(ioa),
get_ioa_desc(dev->ioa));
len += tab_stop;
for (i = 0; i < 26-tab_stop; i++)
body[len+i] = ' ';
len += 26-tab_stop;
} else
len += sprintf(body + len,"%-8s %-16s ",
scsi_dev_data->vendor_id,
scsi_dev_data->product_id);
}
} else if (scsi_dev_data && scsi_dev_data->type == IPR_TYPE_EMPTY_SLOT) {
if (!res_path || !ioa->sis64) {
tab_stop = sprintf(body + len,"%d:%d: ",
@ -12619,17 +12758,35 @@ char *__print_device(struct ipr_dev *dev, char *body, char *option,
}
len += sprintf(body + len, "%-8s %-16s ", " ", " ");
} else {
if (!res_path || !ioa->sis64) {
tab_stop = sprintf(body + len,"%d:%d:%d ", dev->res_addr[ra].bus,
dev->res_addr[ra].target, dev->res_addr[ra].lun);
if (serial_num) {
if (!res_path || !ioa->sis64) {
for (i = 0; i < 26-loc_len; i++)
body[len+i] = ' ';
loc_len += tab_stop;
len += tab_stop;
len += 26-loc_len;
}
}
else if (hw_loc) {
if (!res_path || !ioa->sis64) {
for (i = 0; i < 27-loc_len; i++)
body[len+i] = ' ';
for (i = 0; i < 27-loc_len; i++)
body[len+i] = ' ';
len += 27-loc_len;
}
}
else {
if (!res_path || !ioa->sis64) {
tab_stop = sprintf(body + len,"%d:%d:%d ", dev->res_addr[ra].bus,
dev->res_addr[ra].target, dev->res_addr[ra].lun);
len += 27-loc_len;
loc_len += tab_stop;
len += tab_stop;
for (i = 0; i < 26-loc_len; i++)
body[len+i] = ' ';
len += 26-loc_len;
}
}
if (vpd) {
@ -12645,9 +12802,15 @@ char *__print_device(struct ipr_dev *dev, char *body, char *option,
ipr_strncpy_0(product_id, (char *)dev->product_id, IPR_PROD_ID_LEN);
}
}
if (hw_loc) {
len += sprintf(body + len, "%-16s ",
product_id);
}
else {
len += sprintf(body + len, "%-8s %-16s ",
vendor_id, product_id);
}
len += sprintf(body + len, "%-8s %-16s ",
vendor_id, product_id);
} else {
if (ipr_is_hot_spare(dev))
if (dev->block_dev_class == IPR_SSD)
@ -12684,9 +12847,13 @@ char *__print_device(struct ipr_dev *dev, char *body, char *option,
len += sprintf(body + len, "%-25s ", "Advanced Function SSD");
else
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)
else if (scsi_dev_data && scsi_dev_data->type == TYPE_ENCLOSURE) {
if (serial_num == 1)
len += sprintf(body + len, "%-13s ", (char *)&dev->serial_number);
else
len += sprintf(body + len, "%-25s ", "Enclosure");
} else if (scsi_dev_data && scsi_dev_data->type == TYPE_PROCESSOR)
len += sprintf(body + len, "%-25s ", "Processor");
else if (ioa->ioa_dead)
len += sprintf(body + len, "%-25s ", "Unavailable Device");
@ -12722,12 +12889,18 @@ char *__print_device(struct ipr_dev *dev, char *body, char *option,
* 5: print sd, hardware location, status
* 6: print sd, the first resource adress(sis32)/resource path(sis64), dev VPD
* 7: print sd, the second resource adress(sis32)/resource path(sis64), dev VPD
* 8: print sg, pci/host/resource path, serial number, status
* 9: print sg, physical location, production id, status
*/
char *print_device(struct ipr_dev *dev, char *body, char *option, int type)
{
int sd, sg, vpd, percent, indent, res_path, hw_loc, conc_main;
int sd, sg, vpd, percent, indent, res_path, hw_loc, conc_main, ioa_flag, serial_num;
sd = sg = vpd = percent = indent = res_path = hw_loc = conc_main = 0;
sd = sg = vpd = percent = indent = res_path = hw_loc = conc_main = ioa_flag = serial_num = 0;
if ((type & 0x1000) == 0x1000) ioa_flag = 1;
type &= 0x0fff;
if (type == 2 || type == 4)
sg = 1;
@ -12745,6 +12918,7 @@ char *print_device(struct ipr_dev *dev, char *body, char *option, int type)
if (type == 5) {
hw_loc = 1;
conc_main = 1;
sg = 1;
}
@ -12752,8 +12926,25 @@ char *print_device(struct ipr_dev *dev, char *body, char *option, int type)
conc_main = 1;
sg = 1;
}
if (type == 8) {
sg = 1;
if (dev->ioa->sis64)
res_path = 1;
else
res_path = 0;
serial_num = 1;
}
if (type == 9) {
sg = 1;
hw_loc = 1;
if (dev->ioa->sis64)
res_path = 1;
else
res_path = 0;
vpd = 1;
}
return __print_device(dev, body, option, sd, sg, vpd, percent, indent, res_path, type&1, 0, hw_loc, conc_main);
return __print_device(dev, body, option, sd, sg, vpd, percent, indent, res_path, type&1, 0, hw_loc, conc_main, ioa_flag, serial_num);
}
/**
@ -13336,7 +13527,7 @@ static void printf_device(struct ipr_dev *dev, int type)
static void __printf_device(struct ipr_dev *dev, int sd, int sg, int vpd,
int percent, int indent, int res_path)
{
char *buf = __print_device(dev, NULL, NULL, sd, sg, vpd, percent, indent, res_path, 0, 0, 0, 0);
char *buf = __print_device(dev, NULL, NULL, sd, sg, vpd, percent, indent, res_path, 0, 0, 0, 0, 0, 0);
if (buf) {
printf("%s", buf);
free(buf);
@ -14566,7 +14757,7 @@ static int query_path_details(char **args, int num_args)
**/
static void printf_path_status(struct ipr_dev *dev)
{
char *buf = __print_device(dev, NULL, NULL, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0);
char *buf = __print_device(dev, NULL, NULL, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0);
if (buf) {
printf("%s", buf);
free(buf);
@ -16378,7 +16569,7 @@ static int get_drive_phy_loc(struct ipr_ioa *ioa)
scsi_dbg(ses, "%s\n", is_vses ? "Found VSES" : "Found real SES");
for_each_elem_status(elem_status, &ses_data, &ses_cfg) {
get_drive_phy_loc_with_ses_phy_loc(ses, &drive_data, elem_status->slot_id, phy_loc);
get_drive_phy_loc_with_ses_phy_loc(ses, &drive_data, elem_status->slot_id, phy_loc, 0);
if (elem_status->status == IPR_DRIVE_ELEM_STATUS_UNSUPP)
continue;
if (elem_status->status == IPR_DRIVE_ELEM_STATUS_NO_ACCESS)
@ -16683,6 +16874,436 @@ static int set_ses_mode (char **args, int num_args)
return 0;
}
/**
* show_enclosure_info -
* @ioa: ipr ioa struct
*
* Returns:
* 0 if success / non-zero on failure FIXME
**/
int show_enclosure_info(struct ipr_dev *ses)
{
struct screen_output *s_out;
int rc;
if (ses->scsi_dev_data->type == TYPE_ENCLOSURE)
n_show_enclosure_info.body = ses_details(n_show_enclosure_info.body, ses);
else
n_show_enclosure_info.body = ioa_details(n_show_enclosure_info.body, ses);
s_out = screen_driver(&n_show_enclosure_info, 0, NULL);
free(n_show_enclosure_info.body);
n_show_enclosure_info.body = NULL;
rc = s_out->rc;
free(s_out);
return rc;
}
int ipr_suspend_disk_enclosure(i_container *i_con)
{
int rc, suspend_rc;
struct ipr_ioa *ioa;
struct ipr_dev *ses;
suspend_rc = rc = RC_SUCCESS;
for_each_ioa(ioa) {
for_each_ses(ioa, ses) {
if (ses->is_suspend_cand) {
rc = ipr_suspend_device_bus(ses, &ses->res_addr[0],
IPR_SDB_CHECK_AND_QUIESCE_ENC);
if (rc !=0 )
suspend_rc = 82;
else
rc = ipr_write_dev_attr(ses, "state", "offline\n");
}
}
}
if (suspend_rc != RC_SUCCESS)
return suspend_rc | EXIT_FLAG;
return 81 | EXIT_FLAG;
}
int ipr_resume_disk_enclosure(i_container *i_con)
{
int rc, resume_rc;
struct ipr_ioa *ioa;
struct ipr_dev *ses;
resume_rc = rc = RC_SUCCESS;
for_each_ioa(ioa) {
for_each_ses(ioa, ses) {
if (ses->is_resume_cand) {
rc = ipr_resume_device_bus(ses, &ses->res_addr[0]);
if (rc !=0 )
resume_rc = 86;
else
ipr_write_dev_attr(ses, "state", "running\n");
}
}
}
if (resume_rc != RC_SUCCESS)
return resume_rc | EXIT_FLAG;
return 85 | EXIT_FLAG;
}
/**
* confirm_suspend_disk_enclosure -
*
* Returns:
* 0 if success / non-zero on failure FIXME
**/
int confirm_suspend_disk_enclosure(void)
{
int rc,k;
struct ipr_ioa *ioa;
struct ipr_dev *ses;
char *buffer[2];
struct screen_output *s_out;
int header_lines;
int toggle= 0;
rc = RC_SUCCESS;
body_init_status_enclosure(buffer, n_confirm_suspend_disk_enclosure.header, &header_lines);
for_each_ioa(ioa) {
for_each_ses(ioa, ses) {
if (!ses->is_suspend_cand)
continue;
print_dev_enclosure(k, ses, buffer, "2", k);
}
}
do {
n_confirm_suspend_disk_enclosure.body = buffer[toggle&1];
s_out = screen_driver(&n_confirm_suspend_disk_enclosure, header_lines, NULL);
rc = s_out->rc;
free(s_out);
toggle++;
} while (rc == TOGGLE_SCREEN);
for (k = 0; k < 2; k++) {
free(buffer[k]);
buffer[k] = NULL;
}
n_confirm_suspend_disk_enclosure.body = NULL;
return rc;
}
/**
* confirm_resume_disk_enclosure -
*
* Returns:
* 0 if success / non-zero on failure FIXME
**/
int confirm_resume_disk_enclosure(void)
{
int rc,k;
struct ipr_ioa *ioa;
struct ipr_dev *ses;
char *buffer[2];
struct screen_output *s_out;
int header_lines;
int toggle= 0;
rc = RC_SUCCESS;
body_init_status_enclosure(buffer, n_confirm_resume_disk_enclosure.header, &header_lines);
for_each_ioa(ioa) {
for_each_ses(ioa, ses) {
if (!ses->is_resume_cand)
continue;
print_dev_enclosure(k, ses, buffer, "3", k);
}
}
do {
n_confirm_resume_disk_enclosure.body = buffer[toggle&1];
s_out = screen_driver(&n_confirm_resume_disk_enclosure, header_lines, NULL);
rc = s_out->rc;
free(s_out);
toggle++;
} while (rc == TOGGLE_SCREEN);
for (k = 0; k < 2; k++) {
free(buffer[k]);
buffer[k] = NULL;
}
n_confirm_resume_disk_enclosure.body = NULL;
return rc;
}
/**
* enclosures_fork -
* @i_con: i_container struct
*
* Returns:
* 0 if success / non-zero on failure FIXME
**/
int enclosures_fork(i_container *i_con)
{
int rc = 0, suspend_flag =0, resume_flag = 0;
struct ipr_dev *ses;
struct ipr_ioa *ioa;
char *input;
i_container *temp_i_con;
for_each_icon(temp_i_con) {
ses = (struct ipr_dev *)temp_i_con->data;
if (ses == NULL)
continue;
input = temp_i_con->field_data;
if (strcmp(input, "3") == 0) {
if (ses->scsi_dev_data && ses->scsi_dev_data->type == IPR_TYPE_ADAPTER && ses == &ses->ioa->ioa)
return 89;
if (ses->active_suspend == IOA_DEV_PORT_UNKNOWN)
return 90;
if (ses->active_suspend == IOA_DEV_PORT_ACTIVE)
return 84;
ses->is_resume_cand = 1;
resume_flag = 1;
} else if (strcmp(input, "2") == 0) {
if (ses->scsi_dev_data && ses->scsi_dev_data->type == IPR_TYPE_ADAPTER && ses == &ses->ioa->ioa)
return 88;
if (ses->active_suspend == IOA_DEV_PORT_UNKNOWN)
return 90;
if (!strncmp((char *)&ses->serial_number, (char *)&ses->ioa->yl_serial_num[0], ESM_SERIAL_NUM_LEN))
return 87;
if (ses->active_suspend == IOA_DEV_PORT_SUSPEND)
return 83;
ses->is_suspend_cand = 1;
suspend_flag = 1;
} else if (strcmp(input, "1") == 0) {
rc = show_enclosure_info(ses);
return rc;
}
}
if (suspend_flag) {
rc =confirm_suspend_disk_enclosure();
for_each_ioa(ioa)
for_each_ses(ioa, ses)
ses->is_suspend_cand = 0;
return rc;
}
if (resume_flag) {
rc = confirm_resume_disk_enclosure();
for_each_ioa(ioa)
for_each_ses(ioa, ses)
ses->is_resume_cand = 0;
return rc;
}
return INVALID_OPTION_STATUS;
}
/**
* enclosures_maint -
* @i_con: i_container struct
*
* Returns:
* 0 if success / non-zero on failure FIXME
**/
int enclosures_maint(i_container *i_con)
{
int rc, k, first_ses;
struct ipr_ioa *ioa;
struct ipr_dev *ses;
char *buffer[2];
struct screen_output *s_out;
int header_lines;
int toggle=0;
char product_id[IPR_PROD_ID_LEN + 1];
processing();
i_con = free_i_con(i_con);
body_init_status_enclosure(buffer, n_enclosures_maint.header, &header_lines);
check_current_config(false);
for_each_ioa(ioa) {
if (!ioa->sis64)
continue;
first_ses = 1;
for_each_ses(ioa, ses) {
ipr_strncpy_0(product_id, ses->scsi_dev_data->product_id, IPR_PROD_ID_LEN);
if (!strncmp(product_id,"5888", strlen("5888")) || !strncmp(product_id, "EDR1", strlen("EDR1"))) {
if (strlen(ses->physical_location) == 0)
get_ses_phy_loc(ses);
if (first_ses) {
i_con = add_i_con(i_con, "\0",ioa);
print_dev_enclosure(k, &ioa->ioa, buffer, "%1", (k | 0x1000));
first_ses = 0;
}
i_con = add_i_con(i_con, "\0",ses);
print_dev_enclosure(k, ses, buffer, "%1", k);
}
}
}
do {
n_enclosures_maint.body = buffer[toggle&1];
s_out = screen_driver(&n_enclosures_maint, header_lines, i_con);
rc = s_out->rc;
free(s_out);
toggle++;
} while (rc == TOGGLE_SCREEN);
for (k = 0; k < 2; k++) {
free(buffer[k]);
buffer[k] = NULL;
}
n_enclosures_maint.body = NULL;
return rc;
}
/**
* suspend_disk_enclosure -
* @args: argument vector
* @num_args: number of arguments
*
* Returns:
* 0 if success / non-zero on failure
**/
static int suspend_disk_enclosure(char **args, int num_args)
{
struct ipr_dev *ses;
int rc = 0;
ses = find_dev(args[0]);
get_ses_ioport_status(ses);
if (ses->scsi_dev_data && ses->scsi_dev_data->type == IPR_TYPE_ADAPTER && ses == &ses->ioa->ioa) {
fprintf(stderr,"Incorrect device type specified. Please specify a valid SAS device to suspend.\n");
return 1;
}
if (ses->scsi_dev_data && ses->scsi_dev_data->type != TYPE_ENCLOSURE) {
fprintf(stderr, "Selected device is not SAS expander.\n");
return 1;
}
if (strlen(ses->physical_location) == 0)
get_ses_phy_loc(ses);
if (!strncmp((char *)&ses->serial_number, (char *)&ses->ioa->yl_serial_num[0], ESM_SERIAL_NUM_LEN)) {
fprintf(stderr, "Could not suspend an expander from the RAID controller with the same serial number.\n");
return 1;
}
if (ses->active_suspend == IOA_DEV_PORT_SUSPEND) {
printf("The expander is already suspended\n");
return 1;
}
if (ses->active_suspend == IOA_DEV_PORT_UNKNOWN)
return 90;
rc = ipr_suspend_device_bus(ses, &ses->res_addr[0],
IPR_SDB_CHECK_AND_QUIESCE_ENC);
if (!rc) {
rc = ipr_write_dev_attr(ses, "state", "offline\n");
printf("Selected disk enclosure was suspended successfully.\n");
return rc;
}
fprintf(stderr, "Failed to suspend this SAS expander.\n");
return 1;
}
/**
* resume_disk_enclosure -
* @args: argument vector
* @num_args: number of arguments
*
* Returns:
* 0 if success / non-zero on failure
**/
static int resume_disk_enclosure(char **args, int num_args)
{
struct ipr_dev *ses;
int rc = 0;
ses = find_dev(args[0]);
get_ses_ioport_status(ses);
if (ses->scsi_dev_data && ses->scsi_dev_data->type == IPR_TYPE_ADAPTER && ses == &ses->ioa->ioa) {
fprintf(stderr,"Incorrect device type specified. Please specify a valid SAS device to resume.\n");
return 1;
}
if (ses->scsi_dev_data && ses->scsi_dev_data->type != TYPE_ENCLOSURE) {
fprintf(stderr, "Selected device is not SAS expander.\n");
return 1;
}
if (ses->active_suspend == IOA_DEV_PORT_ACTIVE) {
printf("The expander is already in active state.\n");
return 1;
}
if (ses->active_suspend == IOA_DEV_PORT_UNKNOWN) {
printf("The expander is an unknown state.\n");
return 1;
}
rc = ipr_resume_device_bus(ses, &ses->res_addr[0]);
if (!rc) {
ipr_write_dev_attr(ses, "state", "running\n");
printf("Selected disk enclosure was resumed successfully.\n");
return rc;
}
printf("Failed to resume this SAS expander.\n");
return 1;
}
/**
* query_disk_enclosure_status -
* @args: argument vector
* @num_args: number of arguments
*
* Returns:
* 0 if success / non-zero on failure
**/
static int query_disk_enclosure_status(char **args, int num_args)
{
struct ipr_ioa *ioa;
struct ipr_dev *ses;
int rc = 0;
printf("%s\n%s\n", status_hdr[14], status_sep[14]);
for_each_ioa(ioa) {
printf_device((struct ipr_dev *)ioa, 0x8 | 0x1000);
for_each_ses(ioa, ses) {
get_ses_ioport_status(ses);
if (strlen(ses->physical_location) == 0)
get_ses_phy_loc(ses);
printf_device(ses, 0x8);
}
}
return rc;
}
static const struct {
char *cmd;
int min_args;
@ -16785,6 +17406,9 @@ static const struct {
{ "get-live-dump", 1, 0, 1, get_live_dump, "sg5" },
{ "query-ses-mode", 1, 0, 1, query_ses_mode, "sg8"},
{ "set-ses-mode", 2, 0, 2, set_ses_mode, "sg8 2"},
{ "query-disk-enclosure-status", 0, 0, 0, query_disk_enclosure_status},
{ "suspend-disk-enclosure", 1, 0, 1, suspend_disk_enclosure, "sg8"},
{ "resume-disk-enclosure", 1, 0, 1, resume_disk_enclosure, "sg8 "},
};
/**

View file

@ -119,9 +119,13 @@ int raid_resync(i_container * i_con);
int confirm_raid_resync(i_container * i_con);
int battery_maint(i_container * i_con);
int enclosures_maint(i_container * i_con);
int battery_fork(i_container * i_con);
int enclosures_fork(i_container * i_con);
int force_battery_error(i_container *i_con);
int enable_battery(i_container *i_con);
int ipr_suspend_disk_enclosure(i_container *i_con);
int ipr_resume_disk_enclosure(i_container *i_con);
int bus_config(i_container * i_con);
int change_bus_attr(i_container * i_con);
int confirm_change_bus_attr(i_container *i_con);
@ -781,7 +785,8 @@ struct screen_opts disk_unit_recovery_opt[] = {
{raid_rebuild, "5", __("Rebuild disk unit data")},
{raid_resync, "6", __("Force RAID Consistency Check")},
{battery_maint, "7", __("Work with resources containing cache battery packs")},
{path_status, "8", __("Display SAS path status")}
{path_status, "8", __("Display SAS path status")},
{enclosures_maint, "9", __("Work with disk enclosures")}
};
s_node n_disk_unit_recovery = {
@ -1159,6 +1164,61 @@ s_node n_show_battery_info = {
.title = __("Battery Information")
};
struct screen_opts enclosures_maint_opt[] = {
{enclosures_fork, "\n"}
};
s_node n_enclosures_maint = {
.rc_flags = (CANCEL_FLAG),
.f_flags = (EXIT_FLAG | CANCEL_FLAG | TOGGLE_FLAG | FWD_FLAG),
.num_opts = NUM_OPTS(enclosures_maint_opt),
.options = &enclosures_maint_opt[0],
.title = __("Work with disk enclosures"),
.header = {
__("Type options, press Enter\n"),
__(" 1=Display disk enclosure details\n"),
__(" 2=Suspend disk enclosure path\n"),
__(" 3=Resume disk enclosure path\n\n"),
"" }
};
struct screen_opts confirm_suspend_disk_enclosure_opt[] = {
{ipr_suspend_disk_enclosure, "c"}
};
s_node n_confirm_suspend_disk_enclosure = {
.f_flags = (EXIT_FLAG | CANCEL_FLAG | TOGGLE_FLAG | FWD_FLAG),
.num_opts = NUM_OPTS(confirm_suspend_disk_enclosure_opt),
.options = &confirm_suspend_disk_enclosure_opt[0],
.title = __("Suspend Disk Enclosure"),
.header = {
__("ATTENTION: This service function should be run only "
"under the direction of the IBM Hardware Service Support\n\n"),
__(" c=Continue to issue suspend enclosure command\n\n"),
"" },
};
struct screen_opts confirm_resume_disk_enclosure_opt[] = {
{ipr_resume_disk_enclosure, "c"}
};
s_node n_confirm_resume_disk_enclosure = {
.f_flags = (EXIT_FLAG | CANCEL_FLAG | TOGGLE_FLAG | FWD_FLAG),
.num_opts = NUM_OPTS(confirm_resume_disk_enclosure_opt),
.options = &confirm_resume_disk_enclosure_opt[0],
.title = __("Resume Disk Enclosure"),
.header = {
__("ATTENTION: This service function should be run only "
"under the direction of the IBM Hardware Service Support\n\n"),
__(" c=Continue to issue resume enclosure command\n\n"),
"" },
};
s_node n_show_enclosure_info = {
.f_flags = (ENTER_FLAG | EXIT_FLAG | CANCEL_FLAG),
.title = __("Hardware detail Information")
};
struct screen_opts path_status_opt[] = {
{path_details, "\n"}
};
@ -1577,6 +1637,16 @@ const char *screen_status[] = {
/* 78 */ __("Too few disks were selected. The minimum is %d."),
/* 79 */ __("Migrate Array Protection completed successfully."),
/* 80 */ __("Migrate Array Protection failed."),
/* 81 */ __("Selected disk enclosure was suspended successfully."),
/* 82 */ __("Failed to suspend disk enclosure"),
/* 83 */ __("Disk enclosure is already in suspend state"),
/* 84 */ __("Disk enclosure is already in active state"),
/* 85 */ __("Selected disk enclosure was resumed successfully."),
/* 86 */ __("Failed to resume disk enclosure"),
/* 87 */ __("Can not suspend an expander from the RAID controller with the same serial number"),
/* 88 */ __("Incorrect device type specified. Please specify a valid disk enclosure to suspend"),
/* 89 */ __("Incorrect device type specified. Please specify a valid disk enclosure to resume"),
/* 90 */ __("Selected disk enclosure is in Unknown state. Please check your hardware support"),
/* NOTE: 127 maximum limit */
};

View file

@ -4301,7 +4301,7 @@ fail:
* Returns:
* 0 if success / non-zero on failure
**/
static int ipr_resume_device_bus(struct ipr_dev *dev,
int ipr_resume_device_bus(struct ipr_dev *dev,
struct ipr_res_addr *res_addr)
{
int fd, rc, cdb_num;
@ -6026,6 +6026,8 @@ void check_current_config(bool allow_rebuild_refresh)
struct ipr_res_addr res_addr, *ra;
struct ipr_dev *dev;
int *qac_entry_ref;
struct ipr_dev_identify_vpd di_vpd;
char *pchr;
if (ipr_qac_data == NULL) {
ipr_qac_data =
@ -6235,6 +6237,18 @@ void check_current_config(bool allow_rebuild_refresh)
get_prot_levels(ioa);
}
for_each_ioa(ioa) {
if (strlen((char *)ioa->yl_serial_num) == 0) {
memset(&di_vpd, 0, sizeof(di_vpd));
ipr_inquiry(&ioa->ioa, 0x83, &di_vpd, sizeof(di_vpd));
if (ntohs(di_vpd.add_page_len) > 120) {
pchr = strstr((char *)&di_vpd.dev_identify_contxt[0],"SN");
strncpy((char *)ioa->yl_serial_num, (pchr + 3), YL_SERIAL_NUM_LEN);
}
}
}
link_multipath_vsets();
ipr_cleanup_zeroed_devs();
resolve_old_config();
@ -7557,18 +7571,22 @@ int ipr_write_dev_attr(struct ipr_dev *dev, char *attr, char *value)
class_device = sysfs_open_class_device("scsi_device",
sysfs_dev_name);
if (!class_device)
if (!class_device) {
printf("Cannot open class_device\n");
return -EIO;
}
device = sysfs_get_classdev_device(class_device);
if (!device) {
printf("Cannot get classdev\n");
sysfs_close_class_device(class_device);
return -EIO;
}
dev_attr = sysfs_get_device_attr(device, attr);
if (sysfs_write_attribute(dev_attr, value, strlen(value))) {
printf("Failed to write attribute: %p\n", dev_attr);
sysfs_close_class_device(class_device);
return -EIO;
}
@ -9283,3 +9301,68 @@ void ipr_set_manage_start_stop(struct ipr_dev *dev)
sysfs_close_attribute(sysfs_attr);
}
/**
* ipr_query_ioa_device_port -
* @ioa: ipr ioa struct
* @res_addr: ipr_res_addr struct
* @option: option value
*
* Returns:
* 0 if success / non-zero on failure
**/
int ipr_query_io_dev_port(struct ipr_dev *dev, struct ipr_query_io_port *io_port)
{
int fd, rc, cdb_num;
u8 cdb[IPR_CCB_CDB_LEN];
struct ipr_ioa *ioa = dev->ioa;
struct sense_data_t sense_data;
char *rp, *endptr;
if (strlen(ioa->ioa.gen_name) == 0)
return -ENOENT;
fd = open(ioa->ioa.gen_name, O_RDWR);
if (fd <= 1) {
if (!strcmp(tool_name, "iprconfig") || ipr_debug)
syslog(LOG_ERR, "Could not open %s. %m\n", ioa->ioa.gen_name);
return errno;
}
memset(cdb, 0, IPR_CCB_CDB_LEN);
cdb[0] = IPR_IOA_SERVICE_ACTION;
cdb[1] = IPR_QUERY_IOA_DEV_PORT;
if (ioa->sis64) {
/* convert res path string to bytes */
cdb_num = 2;
rp = dev->res_path_name;
do {
cdb[cdb_num++] = (u8)strtol(rp, &endptr, 16);
rp = endptr+1;
} while (*endptr != '\0' && cdb_num < 10);
while (cdb_num < 10)
cdb[cdb_num++] = 0xff;
cdb[10] = sizeof(*io_port) >> 24;
cdb[11] = (sizeof(*io_port) >> 16) & 0xff;
cdb[12] = (sizeof(*io_port) >> 8) & 0xff;
cdb[13] = sizeof(*io_port) & 0xff;
}
else {
close(fd);
return -1;
}
rc = sg_ioctl(fd, cdb, io_port,
sizeof(*io_port), SG_DXFER_FROM_DEV,
&sense_data, IPR_INTERNAL_TIMEOUT);
if (rc != 0)
scsi_cmd_err(dev, &sense_data, "Query IO port status", rc);
close(fd);
return rc;
}

View file

@ -73,6 +73,8 @@
#define IPR_VENDOR_ID_LEN 8
#define IPR_PROD_ID_LEN 16
#define IPR_SERIAL_NUM_LEN 8
#define ESM_SERIAL_NUM_LEN 12
#define YL_SERIAL_NUM_LEN 12
#define IPR_DESCRIPTION_LEN 16
#define IPR_VPD_PLANT_CODE_LEN 4
#define IPR_VPD_CACHE_SIZE_LEN 3
@ -158,6 +160,7 @@
#define IPR_CHANGE_CACHE_PARAMETERS 0x14
#define IPR_QUERY_CACHE_PARAMETERS 0x16
#define IPR_LIVE_DUMP 0x31
#define IPR_QUERY_IOA_DEV_PORT 0x32
#define IPR_EVALUATE_DEVICE 0xE4
#define SKIP_READ 0xE8
#define SKIP_WRITE 0xEA
@ -680,6 +683,18 @@ struct ipr_query_res_state {
};
};
struct ipr_query_io_port {
u32 length;
#define IOA_DEV_PORT_ACTIVE 0x0
#define IOA_DEV_PORT_SUSPEND 0x1
#define IOA_DEV_PORT_PARTIAL_SUSPEND 0x2
#define IOA_DEV_PORT_UNKNOWN 0xFF
u8 port_state;
u8 reserved1;
u8 reserved2;
u8 reserved3;
};
struct ipr_res_addr_aliases {
u32 length;
struct ipr_res_addr res_addr[10];
@ -1310,6 +1325,9 @@ struct ipr_dev {
u32 init_not_allowed:1;
u32 local_flag:1;
u32 rescan:1;
u8 active_suspend;
u32 is_suspend_cand:1;
u32 is_resume_cand:1;
struct scsi_dev_data *scsi_dev_data;
struct ipr_dev *ses[IPR_DEV_MAX_PATHS];
struct ipr_res_addr res_addr[IPR_DEV_MAX_PATHS];
@ -1380,6 +1398,7 @@ struct ipr_ioa {
char pci_address[16];
char host_name[16];
char physical_location[1024];
u8 yl_serial_num[YL_SERIAL_NUM_LEN];
struct ipr_dev dev[IPR_MAX_IOA_DEVICES];
struct ipr_multi_ioa_status ioa_status;
struct ipr_array_query_data *qac_data;
@ -1851,6 +1870,14 @@ struct ipr_cache_cap_vpd {
u32 comp_read_cache_size;
};
struct ipr_dev_identify_vpd {
u8 peri_dev_type;
u8 page_code;
u16 add_page_len;
u8 reserved[80];
u8 dev_identify_contxt[40];
};
#define IPR_IOA_MAX_SUPP_LOG_PAGES 16
struct ipr_supp_log_pages {
u8 page_code;
@ -2204,6 +2231,27 @@ struct ses_serial_num_vpd {
u8 ses_serial_num[7];
};
struct esm_serial_num_vpd {
u8 peri_dev_type;
u8 page_code;
u8 reserved1;
u8 page_len;
u8 ascii_len;
u8 fru_part_number[3];
u8 frb_number[8];
u8 reserved2;
u8 serial_num_head[3];
u8 esm_serial_num[12];
u8 reserved3;
u8 model_num_head[3];
u8 model_num[4];
u8 reserved4;
u8 frb_label_head[3];
u8 frb_label[5];
u8 reserved5;
};
struct drive_elem_desc {
u8 reserved1[2];
u8 desc_length[2];
@ -2408,6 +2456,7 @@ bool is_af_blocked(struct ipr_dev *, int);
int ipr_query_array_config(struct ipr_ioa *, bool, bool, bool, int, struct ipr_array_query_data *);
int __ipr_query_array_config(struct ipr_ioa *, int, bool, bool, bool, int, struct ipr_array_query_data *);
int ipr_query_command_status(struct ipr_dev *, void *);
int ipr_query_io_dev_port(struct ipr_dev *, struct ipr_query_io_port *);
int ipr_mode_sense(struct ipr_dev *, u8, void *);
int ipr_mode_select(struct ipr_dev *, void *, int);
int ipr_log_sense(struct ipr_dev *, u8, void *, u16);
@ -2455,6 +2504,7 @@ void ipr_scan(struct ipr_ioa *, int, int, int);
int ipr_read_dev_attr(struct ipr_dev *, char *, char *);
int ipr_write_dev_attr(struct ipr_dev *, char *, char *);
int ipr_suspend_device_bus(struct ipr_dev *, struct ipr_res_addr *, u8);
int ipr_resume_device_bus(struct ipr_dev *, struct ipr_res_addr *);
int ipr_can_remove_device(struct ipr_dev *);
int ipr_receive_diagnostics(struct ipr_dev *, u8, void *, int);
int ipr_send_diagnostics(struct ipr_dev *, void *, int);