aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/osd/osd_initiator.c
diff options
context:
space:
mode:
authorBoaz Harrosh <bharrosh@panasas.com>2009-01-25 10:15:16 -0500
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2009-03-12 13:58:09 -0400
commit98f3aea2bd4b4f9cd7a6a6479ed9410787f756fd (patch)
tree6b5eeab307ab09372c62e7aac4516548d763b030 /drivers/scsi/osd/osd_initiator.c
parent1b9dce94c8a24a3f1a01fcdf688f2d903b32acdf (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.c191
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}
1340EXPORT_SYMBOL(osd_finalize_request); 1342EXPORT_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
1352int 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}
1531EXPORT_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.