Skip to content

Commit

Permalink
[SCSI] ipr: Add support for logging SAS fabric errors
Browse files Browse the repository at this point in the history
Adds support for logging SAS fabric errors logged by
the ipr firmware.

Signed-off-by: Brian King <brking@us.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
  • Loading branch information
Brian King authored and James Bottomley committed Nov 22, 2006
1 parent 9d66bdf commit 49dc6a1
Show file tree
Hide file tree
Showing 2 changed files with 290 additions and 7 deletions.
225 changes: 218 additions & 7 deletions drivers/scsi/ipr.c
Original file line number Diff line number Diff line change
Expand Up @@ -1321,6 +1321,219 @@ static void ipr_log_dual_ioa_error(struct ipr_ioa_cfg *ioa_cfg,
offsetof(struct ipr_hostrcb_type_07_error, data)));
}

static const struct {
u8 active;
char *desc;
} path_active_desc[] = {
{ IPR_PATH_NO_INFO, "Path" },
{ IPR_PATH_ACTIVE, "Active path" },
{ IPR_PATH_NOT_ACTIVE, "Inactive path" }
};

static const struct {
u8 state;
char *desc;
} path_state_desc[] = {
{ IPR_PATH_STATE_NO_INFO, "has no path state information available" },
{ IPR_PATH_HEALTHY, "is healthy" },
{ IPR_PATH_DEGRADED, "is degraded" },
{ IPR_PATH_FAILED, "is failed" }
};

/**
* ipr_log_fabric_path - Log a fabric path error
* @hostrcb: hostrcb struct
* @fabric: fabric descriptor
*
* Return value:
* none
**/
static void ipr_log_fabric_path(struct ipr_hostrcb *hostrcb,
struct ipr_hostrcb_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;

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;

if (fabric->cascaded_expander == 0xff && fabric->phy == 0xff) {
ipr_hcam_err(hostrcb, "%s %s: IOA Port=%d\n",
path_active_desc[i].desc, path_state_desc[j].desc,
fabric->ioa_port);
} else if (fabric->cascaded_expander == 0xff) {
ipr_hcam_err(hostrcb, "%s %s: IOA Port=%d, Phy=%d\n",
path_active_desc[i].desc, path_state_desc[j].desc,
fabric->ioa_port, fabric->phy);
} else if (fabric->phy == 0xff) {
ipr_hcam_err(hostrcb, "%s %s: IOA Port=%d, Cascade=%d\n",
path_active_desc[i].desc, path_state_desc[j].desc,
fabric->ioa_port, fabric->cascaded_expander);
} else {
ipr_hcam_err(hostrcb, "%s %s: IOA Port=%d, Cascade=%d, Phy=%d\n",
path_active_desc[i].desc, path_state_desc[j].desc,
fabric->ioa_port, fabric->cascaded_expander, fabric->phy);
}
return;
}
}

ipr_err("Path state=%02X IOA Port=%d Cascade=%d Phy=%d\n", path_state,
fabric->ioa_port, fabric->cascaded_expander, fabric->phy);
}

static const struct {
u8 type;
char *desc;
} path_type_desc[] = {
{ IPR_PATH_CFG_IOA_PORT, "IOA port" },
{ IPR_PATH_CFG_EXP_PORT, "Expander port" },
{ IPR_PATH_CFG_DEVICE_PORT, "Device port" },
{ IPR_PATH_CFG_DEVICE_LUN, "Device LUN" }
};

static const struct {
u8 status;
char *desc;
} path_status_desc[] = {
{ IPR_PATH_CFG_NO_PROB, "Functional" },
{ IPR_PATH_CFG_DEGRADED, "Degraded" },
{ IPR_PATH_CFG_FAILED, "Failed" },
{ IPR_PATH_CFG_SUSPECT, "Suspect" },
{ IPR_PATH_NOT_DETECTED, "Missing" },
{ IPR_PATH_INCORRECT_CONN, "Incorrectly connected" }
};

static const char *link_rate[] = {
"unknown",
"disabled",
"phy reset problem",
"spinup hold",
"port selector",
"unknown",
"unknown",
"unknown",
"1.5Gbps",
"3.0Gbps",
"unknown",
"unknown",
"unknown",
"unknown",
"unknown",
"unknown"
};

/**
* ipr_log_path_elem - Log a fabric path element.
* @hostrcb: hostrcb struct
* @cfg: fabric path element struct
*
* Return value:
* none
**/
static void ipr_log_path_elem(struct ipr_hostrcb *hostrcb,
struct ipr_hostrcb_config_element *cfg)
{
int i, j;
u8 type = cfg->type_status & IPR_PATH_CFG_TYPE_MASK;
u8 status = cfg->type_status & IPR_PATH_CFG_STATUS_MASK;

if (type == IPR_PATH_CFG_NOT_EXIST)
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;

if (type == IPR_PATH_CFG_IOA_PORT) {
ipr_hcam_err(hostrcb, "%s %s: Phy=%d, Link rate=%s, WWN=%08X%08X\n",
path_status_desc[j].desc, path_type_desc[i].desc,
cfg->phy, link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK],
be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1]));
} else {
if (cfg->cascaded_expander == 0xff && cfg->phy == 0xff) {
ipr_hcam_err(hostrcb, "%s %s: Link rate=%s, WWN=%08X%08X\n",
path_status_desc[j].desc, path_type_desc[i].desc,
link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK],
be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1]));
} else if (cfg->cascaded_expander == 0xff) {
ipr_hcam_err(hostrcb, "%s %s: Phy=%d, Link rate=%s, "
"WWN=%08X%08X\n", path_status_desc[j].desc,
path_type_desc[i].desc, cfg->phy,
link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK],
be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1]));
} else if (cfg->phy == 0xff) {
ipr_hcam_err(hostrcb, "%s %s: Cascade=%d, Link rate=%s, "
"WWN=%08X%08X\n", path_status_desc[j].desc,
path_type_desc[i].desc, cfg->cascaded_expander,
link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK],
be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1]));
} else {
ipr_hcam_err(hostrcb, "%s %s: Cascade=%d, Phy=%d, Link rate=%s "
"WWN=%08X%08X\n", path_status_desc[j].desc,
path_type_desc[i].desc, cfg->cascaded_expander, cfg->phy,
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: Cascade=%d Phy=%d Link rate=%s "
"WWN=%08X%08X\n", cfg->type_status, cfg->cascaded_expander, cfg->phy,
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
* @hostrcb: hostrcb struct
*
* Return value:
* none
**/
static void ipr_log_fabric_error(struct ipr_ioa_cfg *ioa_cfg,
struct ipr_hostrcb *hostrcb)
{
struct ipr_hostrcb_type_20_error *error;
struct ipr_hostrcb_fabric_desc *fabric;
struct ipr_hostrcb_config_element *cfg;
int i, add_len;

error = &hostrcb->hcam.u.error.u.type_20_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_hostrcb_error, u) +
offsetof(struct ipr_hostrcb_type_20_error, desc));

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

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

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

/**
* ipr_log_generic_error - Log an adapter error.
* @ioa_cfg: ioa config struct
Expand Down Expand Up @@ -1394,13 +1607,7 @@ static void ipr_handle_log_data(struct ipr_ioa_cfg *ioa_cfg,
if (!ipr_error_table[error_index].log_hcam)
return;

if (ipr_is_device(&hostrcb->hcam.u.error.failing_dev_res_addr)) {
ipr_ra_err(ioa_cfg, hostrcb->hcam.u.error.failing_dev_res_addr,
"%s\n", ipr_error_table[error_index].error);
} else {
dev_err(&ioa_cfg->pdev->dev, "%s\n",
ipr_error_table[error_index].error);
}
ipr_hcam_err(hostrcb, "%s\n", ipr_error_table[error_index].error);

/* Set indication we have logged an error */
ioa_cfg->errors_logged++;
Expand Down Expand Up @@ -1437,6 +1644,9 @@ static void ipr_handle_log_data(struct ipr_ioa_cfg *ioa_cfg,
case IPR_HOST_RCB_OVERLAY_ID_17:
ipr_log_enhanced_dual_ioa_error(ioa_cfg, hostrcb);
break;
case IPR_HOST_RCB_OVERLAY_ID_20:
ipr_log_fabric_error(ioa_cfg, hostrcb);
break;
case IPR_HOST_RCB_OVERLAY_ID_1:
case IPR_HOST_RCB_OVERLAY_ID_DEFAULT:
default:
Expand Down Expand Up @@ -6812,6 +7022,7 @@ static int __devinit ipr_alloc_mem(struct ipr_ioa_cfg *ioa_cfg)

ioa_cfg->hostrcb[i]->hostrcb_dma =
ioa_cfg->hostrcb_dma[i] + offsetof(struct ipr_hostrcb, hcam);
ioa_cfg->hostrcb[i]->ioa_cfg = ioa_cfg;
list_add_tail(&ioa_cfg->hostrcb[i]->queue, &ioa_cfg->hostrcb_free_q);
}

Expand Down
72 changes: 72 additions & 0 deletions drivers/scsi/ipr.h
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,64 @@ struct ipr_hostrcb_type_17_error {
u32 data[476];
}__attribute__((packed, aligned (4)));

struct ipr_hostrcb_config_element {
u8 type_status;
#define IPR_PATH_CFG_TYPE_MASK 0xF0
#define IPR_PATH_CFG_NOT_EXIST 0x00
#define IPR_PATH_CFG_IOA_PORT 0x10
#define IPR_PATH_CFG_EXP_PORT 0x20
#define IPR_PATH_CFG_DEVICE_PORT 0x30
#define IPR_PATH_CFG_DEVICE_LUN 0x40

#define IPR_PATH_CFG_STATUS_MASK 0x0F
#define IPR_PATH_CFG_NO_PROB 0x00
#define IPR_PATH_CFG_DEGRADED 0x01
#define IPR_PATH_CFG_FAILED 0x02
#define IPR_PATH_CFG_SUSPECT 0x03
#define IPR_PATH_NOT_DETECTED 0x04
#define IPR_PATH_INCORRECT_CONN 0x05

u8 cascaded_expander;
u8 phy;
u8 link_rate;
#define IPR_PHY_LINK_RATE_MASK 0x0F

__be32 wwid[2];
}__attribute__((packed, aligned (4)));

struct ipr_hostrcb_fabric_desc {
__be16 length;
u8 ioa_port;
u8 cascaded_expander;
u8 phy;
u8 path_state;
#define IPR_PATH_ACTIVE_MASK 0xC0
#define IPR_PATH_NO_INFO 0x00
#define IPR_PATH_ACTIVE 0x40
#define IPR_PATH_NOT_ACTIVE 0x80

#define IPR_PATH_STATE_MASK 0x0F
#define IPR_PATH_STATE_NO_INFO 0x00
#define IPR_PATH_HEALTHY 0x01
#define IPR_PATH_DEGRADED 0x02
#define IPR_PATH_FAILED 0x03

__be16 num_entries;
struct ipr_hostrcb_config_element elem[1];
}__attribute__((packed, aligned (4)));

#define for_each_fabric_cfg(fabric, cfg) \
for (cfg = (fabric)->elem; \
cfg < ((fabric)->elem + be16_to_cpu((fabric)->num_entries)); \
cfg++)

struct ipr_hostrcb_type_20_error {
u8 failure_reason[64];
u8 reserved[3];
u8 num_entries;
struct ipr_hostrcb_fabric_desc desc[1];
}__attribute__((packed, aligned (4)));

struct ipr_hostrcb_error {
__be32 failing_dev_ioasc;
struct ipr_res_addr failing_dev_res_addr;
Expand All @@ -753,6 +811,7 @@ struct ipr_hostrcb_error {
struct ipr_hostrcb_type_13_error type_13_error;
struct ipr_hostrcb_type_14_error type_14_error;
struct ipr_hostrcb_type_17_error type_17_error;
struct ipr_hostrcb_type_20_error type_20_error;
} u;
}__attribute__((packed, aligned (4)));

Expand Down Expand Up @@ -792,6 +851,7 @@ struct ipr_hcam {
#define IPR_HOST_RCB_OVERLAY_ID_14 0x14
#define IPR_HOST_RCB_OVERLAY_ID_16 0x16
#define IPR_HOST_RCB_OVERLAY_ID_17 0x17
#define IPR_HOST_RCB_OVERLAY_ID_20 0x20
#define IPR_HOST_RCB_OVERLAY_ID_DEFAULT 0xFF

u8 reserved1[3];
Expand All @@ -811,6 +871,7 @@ struct ipr_hostrcb {
struct ipr_hcam hcam;
dma_addr_t hostrcb_dma;
struct list_head queue;
struct ipr_ioa_cfg *ioa_cfg;
};

/* IPR smart dump table structures */
Expand Down Expand Up @@ -1289,6 +1350,17 @@ struct ipr_ucode_image_header {
} \
}

#define ipr_hcam_err(hostrcb, fmt, ...) \
{ \
if (ipr_is_device(&(hostrcb)->hcam.u.error.failing_dev_res_addr)) { \
ipr_ra_err((hostrcb)->ioa_cfg, \
(hostrcb)->hcam.u.error.failing_dev_res_addr, \
fmt, ##__VA_ARGS__); \
} else { \
dev_err(&(hostrcb)->ioa_cfg->pdev->dev, fmt, ##__VA_ARGS__); \
} \
}

#define ipr_trace ipr_dbg("%s: %s: Line: %d\n",\
__FILE__, __FUNCTION__, __LINE__)

Expand Down

0 comments on commit 49dc6a1

Please sign in to comment.