diff options
author | Boaz Harrosh <bharrosh@panasas.com> | 2009-01-25 10:15:16 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2009-03-12 13:58:09 -0400 |
commit | 98f3aea2bd4b4f9cd7a6a6479ed9410787f756fd (patch) | |
tree | 6b5eeab307ab09372c62e7aac4516548d763b030 /drivers/scsi/osd/osd_initiator.c | |
parent | 1b9dce94c8a24a3f1a01fcdf688f2d903b32acdf (diff) |
[SCSI] libosd: SCSI/OSD Sense decoding support
Implementation of the osd_req_decode_sense() API. Can be called by
library users to decode what failed in command executions.
Add SCSI_OSD_DPRINT_SENSE Kconfig variable. Possible values are:
0 - Do not print any errors to messages file <KERN_ERR>
1 - (Default) Print only decoded errors that are not recoverable.
Recoverable errors are those that the target has complied with
the request but with a warning. For example read passed end of
object will return zeros after the last valid byte.
2- Print all errors.
Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/osd/osd_initiator.c')
-rw-r--r-- | drivers/scsi/osd/osd_initiator.c | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c index f6340c2ceb25..0bbbf271fbb0 100644 --- a/drivers/scsi/osd/osd_initiator.c +++ b/drivers/scsi/osd/osd_initiator.c | |||
@@ -42,6 +42,8 @@ | |||
42 | #include <scsi/osd_initiator.h> | 42 | #include <scsi/osd_initiator.h> |
43 | #include <scsi/osd_sec.h> | 43 | #include <scsi/osd_sec.h> |
44 | #include <scsi/osd_attributes.h> | 44 | #include <scsi/osd_attributes.h> |
45 | #include <scsi/osd_sense.h> | ||
46 | |||
45 | #include <scsi/scsi_device.h> | 47 | #include <scsi/scsi_device.h> |
46 | 48 | ||
47 | #include "osd_debug.h" | 49 | #include "osd_debug.h" |
@@ -1339,6 +1341,195 @@ int osd_finalize_request(struct osd_request *or, | |||
1339 | } | 1341 | } |
1340 | EXPORT_SYMBOL(osd_finalize_request); | 1342 | EXPORT_SYMBOL(osd_finalize_request); |
1341 | 1343 | ||
1344 | #define OSD_SENSE_PRINT1(fmt, a...) \ | ||
1345 | do { \ | ||
1346 | if (__cur_sense_need_output) \ | ||
1347 | OSD_ERR(fmt, ##a); \ | ||
1348 | } while (0) | ||
1349 | |||
1350 | #define OSD_SENSE_PRINT2(fmt, a...) OSD_SENSE_PRINT1(" " fmt, ##a) | ||
1351 | |||
1352 | int osd_req_decode_sense_full(struct osd_request *or, | ||
1353 | struct osd_sense_info *osi, bool silent, | ||
1354 | struct osd_obj_id *bad_obj_list __unused, int max_obj __unused, | ||
1355 | struct osd_attr *bad_attr_list, int max_attr) | ||
1356 | { | ||
1357 | int sense_len, original_sense_len; | ||
1358 | struct osd_sense_info local_osi; | ||
1359 | struct scsi_sense_descriptor_based *ssdb; | ||
1360 | void *cur_descriptor; | ||
1361 | #if (CONFIG_SCSI_OSD_DPRINT_SENSE == 0) | ||
1362 | const bool __cur_sense_need_output = false; | ||
1363 | #else | ||
1364 | bool __cur_sense_need_output = !silent; | ||
1365 | #endif | ||
1366 | |||
1367 | if (!or->request->errors) | ||
1368 | return 0; | ||
1369 | |||
1370 | ssdb = or->request->sense; | ||
1371 | sense_len = or->request->sense_len; | ||
1372 | if ((sense_len < (int)sizeof(*ssdb) || !ssdb->sense_key)) { | ||
1373 | OSD_ERR("Block-layer returned error(0x%x) but " | ||
1374 | "sense_len(%u) || key(%d) is empty\n", | ||
1375 | or->request->errors, sense_len, ssdb->sense_key); | ||
1376 | return -EIO; | ||
1377 | } | ||
1378 | |||
1379 | if ((ssdb->response_code != 0x72) && (ssdb->response_code != 0x73)) { | ||
1380 | OSD_ERR("Unrecognized scsi sense: rcode=%x length=%d\n", | ||
1381 | ssdb->response_code, sense_len); | ||
1382 | return -EIO; | ||
1383 | } | ||
1384 | |||
1385 | osi = osi ? : &local_osi; | ||
1386 | memset(osi, 0, sizeof(*osi)); | ||
1387 | osi->key = ssdb->sense_key; | ||
1388 | osi->additional_code = be16_to_cpu(ssdb->additional_sense_code); | ||
1389 | original_sense_len = ssdb->additional_sense_length + 8; | ||
1390 | |||
1391 | #if (CONFIG_SCSI_OSD_DPRINT_SENSE == 1) | ||
1392 | if (__cur_sense_need_output) | ||
1393 | __cur_sense_need_output = (osi->key > scsi_sk_recovered_error); | ||
1394 | #endif | ||
1395 | OSD_SENSE_PRINT1("Main Sense information key=0x%x length(%d, %d) " | ||
1396 | "additional_code=0x%x\n", | ||
1397 | osi->key, original_sense_len, sense_len, | ||
1398 | osi->additional_code); | ||
1399 | |||
1400 | if (original_sense_len < sense_len) | ||
1401 | sense_len = original_sense_len; | ||
1402 | |||
1403 | cur_descriptor = ssdb->ssd; | ||
1404 | sense_len -= sizeof(*ssdb); | ||
1405 | while (sense_len > 0) { | ||
1406 | struct scsi_sense_descriptor *ssd = cur_descriptor; | ||
1407 | int cur_len = ssd->additional_length + 2; | ||
1408 | |||
1409 | sense_len -= cur_len; | ||
1410 | |||
1411 | if (sense_len < 0) | ||
1412 | break; /* sense was truncated */ | ||
1413 | |||
1414 | switch (ssd->descriptor_type) { | ||
1415 | case scsi_sense_information: | ||
1416 | case scsi_sense_command_specific_information: | ||
1417 | { | ||
1418 | struct scsi_sense_command_specific_data_descriptor | ||
1419 | *sscd = cur_descriptor; | ||
1420 | |||
1421 | osi->command_info = | ||
1422 | get_unaligned_be64(&sscd->information) ; | ||
1423 | OSD_SENSE_PRINT2( | ||
1424 | "command_specific_information 0x%llx \n", | ||
1425 | _LLU(osi->command_info)); | ||
1426 | break; | ||
1427 | } | ||
1428 | case scsi_sense_key_specific: | ||
1429 | { | ||
1430 | struct scsi_sense_key_specific_data_descriptor | ||
1431 | *ssks = cur_descriptor; | ||
1432 | |||
1433 | osi->sense_info = get_unaligned_be16(&ssks->value); | ||
1434 | OSD_SENSE_PRINT2( | ||
1435 | "sense_key_specific_information %u" | ||
1436 | "sksv_cd_bpv_bp (0x%x)\n", | ||
1437 | osi->sense_info, ssks->sksv_cd_bpv_bp); | ||
1438 | break; | ||
1439 | } | ||
1440 | case osd_sense_object_identification: | ||
1441 | { /*FIXME: Keep first not last, Store in array*/ | ||
1442 | struct osd_sense_identification_data_descriptor | ||
1443 | *osidd = cur_descriptor; | ||
1444 | |||
1445 | osi->not_initiated_command_functions = | ||
1446 | le32_to_cpu(osidd->not_initiated_functions); | ||
1447 | osi->completed_command_functions = | ||
1448 | le32_to_cpu(osidd->completed_functions); | ||
1449 | osi->obj.partition = be64_to_cpu(osidd->partition_id); | ||
1450 | osi->obj.id = be64_to_cpu(osidd->object_id); | ||
1451 | OSD_SENSE_PRINT2( | ||
1452 | "object_identification pid=0x%llx oid=0x%llx\n", | ||
1453 | _LLU(osi->obj.partition), _LLU(osi->obj.id)); | ||
1454 | OSD_SENSE_PRINT2( | ||
1455 | "not_initiated_bits(%x) " | ||
1456 | "completed_command_bits(%x)\n", | ||
1457 | osi->not_initiated_command_functions, | ||
1458 | osi->completed_command_functions); | ||
1459 | break; | ||
1460 | } | ||
1461 | case osd_sense_response_integrity_check: | ||
1462 | { | ||
1463 | struct osd_sense_response_integrity_check_descriptor | ||
1464 | *osricd = cur_descriptor; | ||
1465 | const unsigned len = | ||
1466 | sizeof(osricd->integrity_check_value); | ||
1467 | char key_dump[len*4 + 2]; /* 2nibbles+space+ASCII */ | ||
1468 | |||
1469 | hex_dump_to_buffer(osricd->integrity_check_value, len, | ||
1470 | 32, 1, key_dump, sizeof(key_dump), true); | ||
1471 | OSD_SENSE_PRINT2("response_integrity [%s]\n", key_dump); | ||
1472 | } | ||
1473 | case osd_sense_attribute_identification: | ||
1474 | { | ||
1475 | struct osd_sense_attributes_data_descriptor | ||
1476 | *osadd = cur_descriptor; | ||
1477 | int len = min(cur_len, sense_len); | ||
1478 | int i = 0; | ||
1479 | struct osd_sense_attr *pattr = osadd->sense_attrs; | ||
1480 | |||
1481 | while (len < 0) { | ||
1482 | u32 attr_page = be32_to_cpu(pattr->attr_page); | ||
1483 | u32 attr_id = be32_to_cpu(pattr->attr_id); | ||
1484 | |||
1485 | if (i++ == 0) { | ||
1486 | osi->attr.attr_page = attr_page; | ||
1487 | osi->attr.attr_id = attr_id; | ||
1488 | } | ||
1489 | |||
1490 | if (bad_attr_list && max_attr) { | ||
1491 | bad_attr_list->attr_page = attr_page; | ||
1492 | bad_attr_list->attr_id = attr_id; | ||
1493 | bad_attr_list++; | ||
1494 | max_attr--; | ||
1495 | } | ||
1496 | OSD_SENSE_PRINT2( | ||
1497 | "osd_sense_attribute_identification" | ||
1498 | "attr_page=0x%x attr_id=0x%x\n", | ||
1499 | attr_page, attr_id); | ||
1500 | } | ||
1501 | } | ||
1502 | /*These are not legal for OSD*/ | ||
1503 | case scsi_sense_field_replaceable_unit: | ||
1504 | OSD_SENSE_PRINT2("scsi_sense_field_replaceable_unit\n"); | ||
1505 | break; | ||
1506 | case scsi_sense_stream_commands: | ||
1507 | OSD_SENSE_PRINT2("scsi_sense_stream_commands\n"); | ||
1508 | break; | ||
1509 | case scsi_sense_block_commands: | ||
1510 | OSD_SENSE_PRINT2("scsi_sense_block_commands\n"); | ||
1511 | break; | ||
1512 | case scsi_sense_ata_return: | ||
1513 | OSD_SENSE_PRINT2("scsi_sense_ata_return\n"); | ||
1514 | break; | ||
1515 | default: | ||
1516 | if (ssd->descriptor_type <= scsi_sense_Reserved_last) | ||
1517 | OSD_SENSE_PRINT2( | ||
1518 | "scsi_sense Reserved descriptor (0x%x)", | ||
1519 | ssd->descriptor_type); | ||
1520 | else | ||
1521 | OSD_SENSE_PRINT2( | ||
1522 | "scsi_sense Vendor descriptor (0x%x)", | ||
1523 | ssd->descriptor_type); | ||
1524 | } | ||
1525 | |||
1526 | cur_descriptor += cur_len; | ||
1527 | } | ||
1528 | |||
1529 | return (osi->key > scsi_sk_recovered_error) ? -EIO : 0; | ||
1530 | } | ||
1531 | EXPORT_SYMBOL(osd_req_decode_sense_full); | ||
1532 | |||
1342 | /* | 1533 | /* |
1343 | * Implementation of osd_sec.h API | 1534 | * Implementation of osd_sec.h API |
1344 | * TODO: Move to a separate osd_sec.c file at a later stage. | 1535 | * TODO: Move to a separate osd_sec.c file at a later stage. |