Skip to content

Commit

Permalink
[SCSI] ipr: add error handling updates for the next generation chip
Browse files Browse the repository at this point in the history
Add support for the new log data notification and overlay IDs.

Signed-off-by: Wayne Boyer <wayneb@linux.vnet.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
  • Loading branch information
Wayne Boyer authored and James Bottomley committed Mar 3, 2010
1 parent 3e7ebdf commit 4565e37
Show file tree
Hide file tree
Showing 2 changed files with 388 additions and 29 deletions.
257 changes: 247 additions & 10 deletions drivers/scsi/ipr.c
Original file line number Diff line number Diff line change
Expand Up @@ -1079,7 +1079,7 @@ static char *ipr_format_resource_path(u8 *res_path, char *buffer)

sprintf(buffer, "%02X", res_path[0]);
for (i=1; res_path[i] != 0xff; i++)
sprintf(buffer, "%s:%02X", buffer, res_path[i]);
sprintf(buffer, "%s-%02X", buffer, res_path[i]);

return buffer;
}
Expand Down Expand Up @@ -1385,8 +1385,12 @@ static void ipr_log_ext_vpd(struct ipr_ext_vpd *vpd)
static void ipr_log_enhanced_cache_error(struct ipr_ioa_cfg *ioa_cfg,
struct ipr_hostrcb *hostrcb)
{
struct ipr_hostrcb_type_12_error *error =
&hostrcb->hcam.u.error.u.type_12_error;
struct ipr_hostrcb_type_12_error *error;

if (ioa_cfg->sis64)
error = &hostrcb->hcam.u.error64.u.type_12_error;
else
error = &hostrcb->hcam.u.error.u.type_12_error;

ipr_err("-----Current Configuration-----\n");
ipr_err("Cache Directory Card Information:\n");
Expand Down Expand Up @@ -1478,6 +1482,48 @@ static void ipr_log_enhanced_config_error(struct ipr_ioa_cfg *ioa_cfg,
}
}

/**
* ipr_log_sis64_config_error - Log a device error.
* @ioa_cfg: ioa config struct
* @hostrcb: hostrcb struct
*
* Return value:
* none
**/
static void ipr_log_sis64_config_error(struct ipr_ioa_cfg *ioa_cfg,
struct ipr_hostrcb *hostrcb)
{
int errors_logged, i;
struct ipr_hostrcb64_device_data_entry_enhanced *dev_entry;
struct ipr_hostrcb_type_23_error *error;
char buffer[IPR_MAX_RES_PATH_LENGTH];

error = &hostrcb->hcam.u.error64.u.type_23_error;
errors_logged = be32_to_cpu(error->errors_logged);

ipr_err("Device Errors Detected/Logged: %d/%d\n",
be32_to_cpu(error->errors_detected), errors_logged);

dev_entry = error->dev;

for (i = 0; i < errors_logged; i++, dev_entry++) {
ipr_err_separator;

ipr_err("Device %d : %s", i + 1,
ipr_format_resource_path(&dev_entry->res_path[0], &buffer[0]));
ipr_log_ext_vpd(&dev_entry->vpd);

ipr_err("-----New Device Information-----\n");
ipr_log_ext_vpd(&dev_entry->new_vpd);

ipr_err("Cache Directory Card Information:\n");
ipr_log_ext_vpd(&dev_entry->ioa_last_with_dev_vpd);

ipr_err("Adapter Card Information:\n");
ipr_log_ext_vpd(&dev_entry->cfc_last_with_dev_vpd);
}
}

/**
* ipr_log_config_error - Log a configuration error.
* @ioa_cfg: ioa config struct
Expand Down Expand Up @@ -1672,7 +1718,11 @@ static void ipr_log_enhanced_dual_ioa_error(struct ipr_ioa_cfg *ioa_cfg,
{
struct ipr_hostrcb_type_17_error *error;

error = &hostrcb->hcam.u.error.u.type_17_error;
if (ioa_cfg->sis64)
error = &hostrcb->hcam.u.error64.u.type_17_error;
else
error = &hostrcb->hcam.u.error.u.type_17_error;

error->failure_reason[sizeof(error->failure_reason) - 1] = '\0';
strim(error->failure_reason);

Expand Down Expand Up @@ -1779,6 +1829,42 @@ static void ipr_log_fabric_path(struct ipr_hostrcb *hostrcb,
fabric->ioa_port, fabric->cascaded_expander, fabric->phy);
}

/**
* ipr_log64_fabric_path - Log a fabric path error
* @hostrcb: hostrcb struct
* @fabric: fabric descriptor
*
* Return value:
* none
**/
static void ipr_log64_fabric_path(struct ipr_hostrcb *hostrcb,
struct ipr_hostrcb64_fabric_desc *fabric)
{
int i, j;
u8 path_state = fabric->path_state;
u8 active = path_state & IPR_PATH_ACTIVE_MASK;
u8 state = path_state & IPR_PATH_STATE_MASK;
char buffer[IPR_MAX_RES_PATH_LENGTH];

for (i = 0; i < ARRAY_SIZE(path_active_desc); i++) {
if (path_active_desc[i].active != active)
continue;

for (j = 0; j < ARRAY_SIZE(path_state_desc); j++) {
if (path_state_desc[j].state != state)
continue;

ipr_hcam_err(hostrcb, "%s %s: Resource Path=%s\n",
path_active_desc[i].desc, path_state_desc[j].desc,
ipr_format_resource_path(&fabric->res_path[0], &buffer[0]));
return;
}
}

ipr_err("Path state=%02X Resource Path=%s\n", path_state,
ipr_format_resource_path(&fabric->res_path[0], &buffer[0]));
}

static const struct {
u8 type;
char *desc;
Expand Down Expand Up @@ -1887,6 +1973,49 @@ static void ipr_log_path_elem(struct ipr_hostrcb *hostrcb,
be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1]));
}

/**
* ipr_log64_path_elem - Log a fabric path element.
* @hostrcb: hostrcb struct
* @cfg: fabric path element struct
*
* Return value:
* none
**/
static void ipr_log64_path_elem(struct ipr_hostrcb *hostrcb,
struct ipr_hostrcb64_config_element *cfg)
{
int i, j;
u8 desc_id = cfg->descriptor_id & IPR_DESCRIPTOR_MASK;
u8 type = cfg->type_status & IPR_PATH_CFG_TYPE_MASK;
u8 status = cfg->type_status & IPR_PATH_CFG_STATUS_MASK;
char buffer[IPR_MAX_RES_PATH_LENGTH];

if (type == IPR_PATH_CFG_NOT_EXIST || desc_id != IPR_DESCRIPTOR_SIS64)
return;

for (i = 0; i < ARRAY_SIZE(path_type_desc); i++) {
if (path_type_desc[i].type != type)
continue;

for (j = 0; j < ARRAY_SIZE(path_status_desc); j++) {
if (path_status_desc[j].status != status)
continue;

ipr_hcam_err(hostrcb, "%s %s: Resource Path=%s, Link rate=%s, WWN=%08X%08X\n",
path_status_desc[j].desc, path_type_desc[i].desc,
ipr_format_resource_path(&cfg->res_path[0], &buffer[0]),
link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK],
be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1]));
return;
}
}
ipr_hcam_err(hostrcb, "Path element=%02X: Resource Path=%s, Link rate=%s "
"WWN=%08X%08X\n", cfg->type_status,
ipr_format_resource_path(&cfg->res_path[0], &buffer[0]),
link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK],
be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1]));
}

/**
* ipr_log_fabric_error - Log a fabric error.
* @ioa_cfg: ioa config struct
Expand Down Expand Up @@ -1924,6 +2053,96 @@ static void ipr_log_fabric_error(struct ipr_ioa_cfg *ioa_cfg,
ipr_log_hex_data(ioa_cfg, (u32 *)fabric, add_len);
}

/**
* ipr_log_sis64_array_error - Log a sis64 array error.
* @ioa_cfg: ioa config struct
* @hostrcb: hostrcb struct
*
* Return value:
* none
**/
static void ipr_log_sis64_array_error(struct ipr_ioa_cfg *ioa_cfg,
struct ipr_hostrcb *hostrcb)
{
int i, num_entries;
struct ipr_hostrcb_type_24_error *error;
struct ipr_hostrcb64_array_data_entry *array_entry;
char buffer[IPR_MAX_RES_PATH_LENGTH];
const u8 zero_sn[IPR_SERIAL_NUM_LEN] = { [0 ... IPR_SERIAL_NUM_LEN-1] = '0' };

error = &hostrcb->hcam.u.error64.u.type_24_error;

ipr_err_separator;

ipr_err("RAID %s Array Configuration: %s\n",
error->protection_level,
ipr_format_resource_path(&error->last_res_path[0], &buffer[0]));

ipr_err_separator;

array_entry = error->array_member;
num_entries = min_t(u32, be32_to_cpu(error->num_entries),
sizeof(error->array_member));

for (i = 0; i < num_entries; i++, array_entry++) {

if (!memcmp(array_entry->vpd.vpd.sn, zero_sn, IPR_SERIAL_NUM_LEN))
continue;

if (error->exposed_mode_adn == i)
ipr_err("Exposed Array Member %d:\n", i);
else
ipr_err("Array Member %d:\n", i);

ipr_err("Array Member %d:\n", i);
ipr_log_ext_vpd(&array_entry->vpd);
ipr_err("Current Location: %s",
ipr_format_resource_path(&array_entry->res_path[0], &buffer[0]));
ipr_err("Expected Location: %s",
ipr_format_resource_path(&array_entry->expected_res_path[0], &buffer[0]));

ipr_err_separator;
}
}

/**
* ipr_log_sis64_fabric_error - Log a sis64 fabric error.
* @ioa_cfg: ioa config struct
* @hostrcb: hostrcb struct
*
* Return value:
* none
**/
static void ipr_log_sis64_fabric_error(struct ipr_ioa_cfg *ioa_cfg,
struct ipr_hostrcb *hostrcb)
{
struct ipr_hostrcb_type_30_error *error;
struct ipr_hostrcb64_fabric_desc *fabric;
struct ipr_hostrcb64_config_element *cfg;
int i, add_len;

error = &hostrcb->hcam.u.error64.u.type_30_error;

error->failure_reason[sizeof(error->failure_reason) - 1] = '\0';
ipr_hcam_err(hostrcb, "%s\n", error->failure_reason);

add_len = be32_to_cpu(hostrcb->hcam.length) -
(offsetof(struct ipr_hostrcb64_error, u) +
offsetof(struct ipr_hostrcb_type_30_error, desc));

for (i = 0, fabric = error->desc; i < error->num_entries; i++) {
ipr_log64_fabric_path(hostrcb, fabric);
for_each_fabric_cfg(fabric, cfg)
ipr_log64_path_elem(hostrcb, cfg);

add_len -= be16_to_cpu(fabric->length);
fabric = (struct ipr_hostrcb64_fabric_desc *)
((unsigned long)fabric + be16_to_cpu(fabric->length));
}

ipr_log_hex_data(ioa_cfg, (u32 *)fabric, add_len);
}

/**
* ipr_log_generic_error - Log an adapter error.
* @ioa_cfg: ioa config struct
Expand Down Expand Up @@ -1983,13 +2202,16 @@ static void ipr_handle_log_data(struct ipr_ioa_cfg *ioa_cfg,
if (hostrcb->hcam.notifications_lost == IPR_HOST_RCB_NOTIFICATIONS_LOST)
dev_err(&ioa_cfg->pdev->dev, "Error notifications lost\n");

ioasc = be32_to_cpu(hostrcb->hcam.u.error.failing_dev_ioasc);
if (ioa_cfg->sis64)
ioasc = be32_to_cpu(hostrcb->hcam.u.error64.fd_ioasc);
else
ioasc = be32_to_cpu(hostrcb->hcam.u.error.fd_ioasc);

if (ioasc == IPR_IOASC_BUS_WAS_RESET ||
ioasc == IPR_IOASC_BUS_WAS_RESET_BY_OTHER) {
if (!ioa_cfg->sis64 && (ioasc == IPR_IOASC_BUS_WAS_RESET ||
ioasc == IPR_IOASC_BUS_WAS_RESET_BY_OTHER)) {
/* Tell the midlayer we had a bus reset so it will handle the UA properly */
scsi_report_bus_reset(ioa_cfg->host,
hostrcb->hcam.u.error.failing_dev_res_addr.bus);
hostrcb->hcam.u.error.fd_res_addr.bus);
}

error_index = ipr_get_error(ioasc);
Expand Down Expand Up @@ -2037,6 +2259,16 @@ static void ipr_handle_log_data(struct ipr_ioa_cfg *ioa_cfg,
case IPR_HOST_RCB_OVERLAY_ID_20:
ipr_log_fabric_error(ioa_cfg, hostrcb);
break;
case IPR_HOST_RCB_OVERLAY_ID_23:
ipr_log_sis64_config_error(ioa_cfg, hostrcb);
break;
case IPR_HOST_RCB_OVERLAY_ID_24:
case IPR_HOST_RCB_OVERLAY_ID_26:
ipr_log_sis64_array_error(ioa_cfg, hostrcb);
break;
case IPR_HOST_RCB_OVERLAY_ID_30:
ipr_log_sis64_fabric_error(ioa_cfg, hostrcb);
break;
case IPR_HOST_RCB_OVERLAY_ID_1:
case IPR_HOST_RCB_OVERLAY_ID_DEFAULT:
default:
Expand All @@ -2061,7 +2293,12 @@ static void ipr_process_error(struct ipr_cmnd *ipr_cmd)
struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
struct ipr_hostrcb *hostrcb = ipr_cmd->u.hostrcb;
u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
u32 fd_ioasc = be32_to_cpu(hostrcb->hcam.u.error.failing_dev_ioasc);
u32 fd_ioasc;

if (ioa_cfg->sis64)
fd_ioasc = be32_to_cpu(hostrcb->hcam.u.error64.fd_ioasc);
else
fd_ioasc = be32_to_cpu(hostrcb->hcam.u.error.fd_ioasc);

list_del(&hostrcb->queue);
list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
Expand Down Expand Up @@ -6996,7 +7233,7 @@ static void ipr_get_unit_check_buffer(struct ipr_ioa_cfg *ioa_cfg)

if (!rc) {
ipr_handle_log_data(ioa_cfg, hostrcb);
ioasc = be32_to_cpu(hostrcb->hcam.u.error.failing_dev_ioasc);
ioasc = be32_to_cpu(hostrcb->hcam.u.error.fd_ioasc);
if (ioasc == IPR_IOASC_NR_IOA_RESET_REQUIRED &&
ioa_cfg->sdt_state == GET_DUMP)
ioa_cfg->sdt_state = WAIT_FOR_DUMP;
Expand Down
Loading

0 comments on commit 4565e37

Please sign in to comment.