diff options
author | Brian King <brking@us.ibm.com> | 2006-11-21 11:28:35 -0500 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2006-11-22 13:21:44 -0500 |
commit | 49dc6a18185c12bae4980d17512fbe54ca6bae54 (patch) | |
tree | dc3e9dc84647d485622c42b9715dceee00ecab19 /drivers/scsi/ipr.c | |
parent | 9d66bdf81f97673b6e330a26438fcaea38c26cd5 (diff) |
[SCSI] ipr: Add support for logging SAS fabric errors
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>
Diffstat (limited to 'drivers/scsi/ipr.c')
-rw-r--r-- | drivers/scsi/ipr.c | 225 |
1 files changed, 218 insertions, 7 deletions
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index e53cfbd0e076..94345e79ef1e 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c | |||
@@ -1321,6 +1321,219 @@ static void ipr_log_dual_ioa_error(struct ipr_ioa_cfg *ioa_cfg, | |||
1321 | offsetof(struct ipr_hostrcb_type_07_error, data))); | 1321 | offsetof(struct ipr_hostrcb_type_07_error, data))); |
1322 | } | 1322 | } |
1323 | 1323 | ||
1324 | static const struct { | ||
1325 | u8 active; | ||
1326 | char *desc; | ||
1327 | } path_active_desc[] = { | ||
1328 | { IPR_PATH_NO_INFO, "Path" }, | ||
1329 | { IPR_PATH_ACTIVE, "Active path" }, | ||
1330 | { IPR_PATH_NOT_ACTIVE, "Inactive path" } | ||
1331 | }; | ||
1332 | |||
1333 | static const struct { | ||
1334 | u8 state; | ||
1335 | char *desc; | ||
1336 | } path_state_desc[] = { | ||
1337 | { IPR_PATH_STATE_NO_INFO, "has no path state information available" }, | ||
1338 | { IPR_PATH_HEALTHY, "is healthy" }, | ||
1339 | { IPR_PATH_DEGRADED, "is degraded" }, | ||
1340 | { IPR_PATH_FAILED, "is failed" } | ||
1341 | }; | ||
1342 | |||
1343 | /** | ||
1344 | * ipr_log_fabric_path - Log a fabric path error | ||
1345 | * @hostrcb: hostrcb struct | ||
1346 | * @fabric: fabric descriptor | ||
1347 | * | ||
1348 | * Return value: | ||
1349 | * none | ||
1350 | **/ | ||
1351 | static void ipr_log_fabric_path(struct ipr_hostrcb *hostrcb, | ||
1352 | struct ipr_hostrcb_fabric_desc *fabric) | ||
1353 | { | ||
1354 | int i, j; | ||
1355 | u8 path_state = fabric->path_state; | ||
1356 | u8 active = path_state & IPR_PATH_ACTIVE_MASK; | ||
1357 | u8 state = path_state & IPR_PATH_STATE_MASK; | ||
1358 | |||
1359 | for (i = 0; i < ARRAY_SIZE(path_active_desc); i++) { | ||
1360 | if (path_active_desc[i].active != active) | ||
1361 | continue; | ||
1362 | |||
1363 | for (j = 0; j < ARRAY_SIZE(path_state_desc); j++) { | ||
1364 | if (path_state_desc[j].state != state) | ||
1365 | continue; | ||
1366 | |||
1367 | if (fabric->cascaded_expander == 0xff && fabric->phy == 0xff) { | ||
1368 | ipr_hcam_err(hostrcb, "%s %s: IOA Port=%d\n", | ||
1369 | path_active_desc[i].desc, path_state_desc[j].desc, | ||
1370 | fabric->ioa_port); | ||
1371 | } else if (fabric->cascaded_expander == 0xff) { | ||
1372 | ipr_hcam_err(hostrcb, "%s %s: IOA Port=%d, Phy=%d\n", | ||
1373 | path_active_desc[i].desc, path_state_desc[j].desc, | ||
1374 | fabric->ioa_port, fabric->phy); | ||
1375 | } else if (fabric->phy == 0xff) { | ||
1376 | ipr_hcam_err(hostrcb, "%s %s: IOA Port=%d, Cascade=%d\n", | ||
1377 | path_active_desc[i].desc, path_state_desc[j].desc, | ||
1378 | fabric->ioa_port, fabric->cascaded_expander); | ||
1379 | } else { | ||
1380 | ipr_hcam_err(hostrcb, "%s %s: IOA Port=%d, Cascade=%d, Phy=%d\n", | ||
1381 | path_active_desc[i].desc, path_state_desc[j].desc, | ||
1382 | fabric->ioa_port, fabric->cascaded_expander, fabric->phy); | ||
1383 | } | ||
1384 | return; | ||
1385 | } | ||
1386 | } | ||
1387 | |||
1388 | ipr_err("Path state=%02X IOA Port=%d Cascade=%d Phy=%d\n", path_state, | ||
1389 | fabric->ioa_port, fabric->cascaded_expander, fabric->phy); | ||
1390 | } | ||
1391 | |||
1392 | static const struct { | ||
1393 | u8 type; | ||
1394 | char *desc; | ||
1395 | } path_type_desc[] = { | ||
1396 | { IPR_PATH_CFG_IOA_PORT, "IOA port" }, | ||
1397 | { IPR_PATH_CFG_EXP_PORT, "Expander port" }, | ||
1398 | { IPR_PATH_CFG_DEVICE_PORT, "Device port" }, | ||
1399 | { IPR_PATH_CFG_DEVICE_LUN, "Device LUN" } | ||
1400 | }; | ||
1401 | |||
1402 | static const struct { | ||
1403 | u8 status; | ||
1404 | char *desc; | ||
1405 | } path_status_desc[] = { | ||
1406 | { IPR_PATH_CFG_NO_PROB, "Functional" }, | ||
1407 | { IPR_PATH_CFG_DEGRADED, "Degraded" }, | ||
1408 | { IPR_PATH_CFG_FAILED, "Failed" }, | ||
1409 | { IPR_PATH_CFG_SUSPECT, "Suspect" }, | ||
1410 | { IPR_PATH_NOT_DETECTED, "Missing" }, | ||
1411 | { IPR_PATH_INCORRECT_CONN, "Incorrectly connected" } | ||
1412 | }; | ||
1413 | |||
1414 | static const char *link_rate[] = { | ||
1415 | "unknown", | ||
1416 | "disabled", | ||
1417 | "phy reset problem", | ||
1418 | "spinup hold", | ||
1419 | "port selector", | ||
1420 | "unknown", | ||
1421 | "unknown", | ||
1422 | "unknown", | ||
1423 | "1.5Gbps", | ||
1424 | "3.0Gbps", | ||
1425 | "unknown", | ||
1426 | "unknown", | ||
1427 | "unknown", | ||
1428 | "unknown", | ||
1429 | "unknown", | ||
1430 | "unknown" | ||
1431 | }; | ||
1432 | |||
1433 | /** | ||
1434 | * ipr_log_path_elem - Log a fabric path element. | ||
1435 | * @hostrcb: hostrcb struct | ||
1436 | * @cfg: fabric path element struct | ||
1437 | * | ||
1438 | * Return value: | ||
1439 | * none | ||
1440 | **/ | ||
1441 | static void ipr_log_path_elem(struct ipr_hostrcb *hostrcb, | ||
1442 | struct ipr_hostrcb_config_element *cfg) | ||
1443 | { | ||
1444 | int i, j; | ||
1445 | u8 type = cfg->type_status & IPR_PATH_CFG_TYPE_MASK; | ||
1446 | u8 status = cfg->type_status & IPR_PATH_CFG_STATUS_MASK; | ||
1447 | |||
1448 | if (type == IPR_PATH_CFG_NOT_EXIST) | ||
1449 | return; | ||
1450 | |||
1451 | for (i = 0; i < ARRAY_SIZE(path_type_desc); i++) { | ||
1452 | if (path_type_desc[i].type != type) | ||
1453 | continue; | ||
1454 | |||
1455 | for (j = 0; j < ARRAY_SIZE(path_status_desc); j++) { | ||
1456 | if (path_status_desc[j].status != status) | ||
1457 | continue; | ||
1458 | |||
1459 | if (type == IPR_PATH_CFG_IOA_PORT) { | ||
1460 | ipr_hcam_err(hostrcb, "%s %s: Phy=%d, Link rate=%s, WWN=%08X%08X\n", | ||
1461 | path_status_desc[j].desc, path_type_desc[i].desc, | ||
1462 | cfg->phy, link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK], | ||
1463 | be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1])); | ||
1464 | } else { | ||
1465 | if (cfg->cascaded_expander == 0xff && cfg->phy == 0xff) { | ||
1466 | ipr_hcam_err(hostrcb, "%s %s: Link rate=%s, WWN=%08X%08X\n", | ||
1467 | path_status_desc[j].desc, path_type_desc[i].desc, | ||
1468 | link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK], | ||
1469 | be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1])); | ||
1470 | } else if (cfg->cascaded_expander == 0xff) { | ||
1471 | ipr_hcam_err(hostrcb, "%s %s: Phy=%d, Link rate=%s, " | ||
1472 | "WWN=%08X%08X\n", path_status_desc[j].desc, | ||
1473 | path_type_desc[i].desc, cfg->phy, | ||
1474 | link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK], | ||
1475 | be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1])); | ||
1476 | } else if (cfg->phy == 0xff) { | ||
1477 | ipr_hcam_err(hostrcb, "%s %s: Cascade=%d, Link rate=%s, " | ||
1478 | "WWN=%08X%08X\n", path_status_desc[j].desc, | ||
1479 | path_type_desc[i].desc, cfg->cascaded_expander, | ||
1480 | link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK], | ||
1481 | be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1])); | ||
1482 | } else { | ||
1483 | ipr_hcam_err(hostrcb, "%s %s: Cascade=%d, Phy=%d, Link rate=%s " | ||
1484 | "WWN=%08X%08X\n", path_status_desc[j].desc, | ||
1485 | path_type_desc[i].desc, cfg->cascaded_expander, cfg->phy, | ||
1486 | link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK], | ||
1487 | be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1])); | ||
1488 | } | ||
1489 | } | ||
1490 | return; | ||
1491 | } | ||
1492 | } | ||
1493 | |||
1494 | ipr_hcam_err(hostrcb, "Path element=%02X: Cascade=%d Phy=%d Link rate=%s " | ||
1495 | "WWN=%08X%08X\n", cfg->type_status, cfg->cascaded_expander, cfg->phy, | ||
1496 | link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK], | ||
1497 | be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1])); | ||
1498 | } | ||
1499 | |||
1500 | /** | ||
1501 | * ipr_log_fabric_error - Log a fabric error. | ||
1502 | * @ioa_cfg: ioa config struct | ||
1503 | * @hostrcb: hostrcb struct | ||
1504 | * | ||
1505 | * Return value: | ||
1506 | * none | ||
1507 | **/ | ||
1508 | static void ipr_log_fabric_error(struct ipr_ioa_cfg *ioa_cfg, | ||
1509 | struct ipr_hostrcb *hostrcb) | ||
1510 | { | ||
1511 | struct ipr_hostrcb_type_20_error *error; | ||
1512 | struct ipr_hostrcb_fabric_desc *fabric; | ||
1513 | struct ipr_hostrcb_config_element *cfg; | ||
1514 | int i, add_len; | ||
1515 | |||
1516 | error = &hostrcb->hcam.u.error.u.type_20_error; | ||
1517 | error->failure_reason[sizeof(error->failure_reason) - 1] = '\0'; | ||
1518 | ipr_hcam_err(hostrcb, "%s\n", error->failure_reason); | ||
1519 | |||
1520 | add_len = be32_to_cpu(hostrcb->hcam.length) - | ||
1521 | (offsetof(struct ipr_hostrcb_error, u) + | ||
1522 | offsetof(struct ipr_hostrcb_type_20_error, desc)); | ||
1523 | |||
1524 | for (i = 0, fabric = error->desc; i < error->num_entries; i++) { | ||
1525 | ipr_log_fabric_path(hostrcb, fabric); | ||
1526 | for_each_fabric_cfg(fabric, cfg) | ||
1527 | ipr_log_path_elem(hostrcb, cfg); | ||
1528 | |||
1529 | add_len -= be16_to_cpu(fabric->length); | ||
1530 | fabric = (struct ipr_hostrcb_fabric_desc *) | ||
1531 | ((unsigned long)fabric + be16_to_cpu(fabric->length)); | ||
1532 | } | ||
1533 | |||
1534 | ipr_log_hex_data((u32 *)fabric, add_len); | ||
1535 | } | ||
1536 | |||
1324 | /** | 1537 | /** |
1325 | * ipr_log_generic_error - Log an adapter error. | 1538 | * ipr_log_generic_error - Log an adapter error. |
1326 | * @ioa_cfg: ioa config struct | 1539 | * @ioa_cfg: ioa config struct |
@@ -1394,13 +1607,7 @@ static void ipr_handle_log_data(struct ipr_ioa_cfg *ioa_cfg, | |||
1394 | if (!ipr_error_table[error_index].log_hcam) | 1607 | if (!ipr_error_table[error_index].log_hcam) |
1395 | return; | 1608 | return; |
1396 | 1609 | ||
1397 | if (ipr_is_device(&hostrcb->hcam.u.error.failing_dev_res_addr)) { | 1610 | ipr_hcam_err(hostrcb, "%s\n", ipr_error_table[error_index].error); |
1398 | ipr_ra_err(ioa_cfg, hostrcb->hcam.u.error.failing_dev_res_addr, | ||
1399 | "%s\n", ipr_error_table[error_index].error); | ||
1400 | } else { | ||
1401 | dev_err(&ioa_cfg->pdev->dev, "%s\n", | ||
1402 | ipr_error_table[error_index].error); | ||
1403 | } | ||
1404 | 1611 | ||
1405 | /* Set indication we have logged an error */ | 1612 | /* Set indication we have logged an error */ |
1406 | ioa_cfg->errors_logged++; | 1613 | ioa_cfg->errors_logged++; |
@@ -1437,6 +1644,9 @@ static void ipr_handle_log_data(struct ipr_ioa_cfg *ioa_cfg, | |||
1437 | case IPR_HOST_RCB_OVERLAY_ID_17: | 1644 | case IPR_HOST_RCB_OVERLAY_ID_17: |
1438 | ipr_log_enhanced_dual_ioa_error(ioa_cfg, hostrcb); | 1645 | ipr_log_enhanced_dual_ioa_error(ioa_cfg, hostrcb); |
1439 | break; | 1646 | break; |
1647 | case IPR_HOST_RCB_OVERLAY_ID_20: | ||
1648 | ipr_log_fabric_error(ioa_cfg, hostrcb); | ||
1649 | break; | ||
1440 | case IPR_HOST_RCB_OVERLAY_ID_1: | 1650 | case IPR_HOST_RCB_OVERLAY_ID_1: |
1441 | case IPR_HOST_RCB_OVERLAY_ID_DEFAULT: | 1651 | case IPR_HOST_RCB_OVERLAY_ID_DEFAULT: |
1442 | default: | 1652 | default: |
@@ -6812,6 +7022,7 @@ static int __devinit ipr_alloc_mem(struct ipr_ioa_cfg *ioa_cfg) | |||
6812 | 7022 | ||
6813 | ioa_cfg->hostrcb[i]->hostrcb_dma = | 7023 | ioa_cfg->hostrcb[i]->hostrcb_dma = |
6814 | ioa_cfg->hostrcb_dma[i] + offsetof(struct ipr_hostrcb, hcam); | 7024 | ioa_cfg->hostrcb_dma[i] + offsetof(struct ipr_hostrcb, hcam); |
7025 | ioa_cfg->hostrcb[i]->ioa_cfg = ioa_cfg; | ||
6815 | list_add_tail(&ioa_cfg->hostrcb[i]->queue, &ioa_cfg->hostrcb_free_q); | 7026 | list_add_tail(&ioa_cfg->hostrcb[i]->queue, &ioa_cfg->hostrcb_free_q); |
6816 | } | 7027 | } |
6817 | 7028 | ||