aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBoaz Harrosh <bharrosh@panasas.com>2009-11-16 13:48:38 -0500
committerJames Bottomley <James.Bottomley@suse.de>2009-12-04 13:01:47 -0500
commitaa9fffbe2c4db4557248c5c626a85bf3c7867044 (patch)
treee719a15e185a35f09e489a5a9f2a72d73c598dd1
parenteff21490c91f981126f0ead3c081dde4f425d387 (diff)
[SCSI] libosd: Error handling revamped
Administer some love to the osd_req_decode_sense function * Fix a bad bug with osd_req_decode_sense(). If there was no scsi residual, .i.e the request never reached the target, then all the osd_sense_info members where garbage. * Add grossly missing in/out_resid to osd_sense_info and fill them in properly. * Define an osd_err_priority enum which divides the possible errors into 7 categories in ascending severity. Each category is also assigned a Linux return code translation. Analyze the different osd/scsi/block returned errors and set the proper osd_err_priority and Linux return code accordingly. * extra check a few situations so not to get stuck with inconsistent error view. Example an empty residual with an error code, and other places ... Lots of libosd's osd_req_decode_sense clients had this logic in some form or another. Consolidate all these into one place that should actually know about osd returns. Thous translating it to a more abstract error. Signed-off-by: Boaz Harrosh <bharrosh@panasas.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
-rw-r--r--drivers/scsi/osd/osd_initiator.c85
-rw-r--r--include/scsi/osd_initiator.h26
2 files changed, 99 insertions, 12 deletions
diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c
index ba25b1e58a6c..950202a70bcf 100644
--- a/drivers/scsi/osd/osd_initiator.c
+++ b/drivers/scsi/osd/osd_initiator.c
@@ -475,7 +475,8 @@ EXPORT_SYMBOL(osd_end_request);
475 475
476int osd_execute_request(struct osd_request *or) 476int osd_execute_request(struct osd_request *or)
477{ 477{
478 return blk_execute_rq(or->request->q, NULL, or->request, 0); 478 return or->async_error =
479 blk_execute_rq(or->request->q, NULL, or->request, 0);
479} 480}
480EXPORT_SYMBOL(osd_execute_request); 481EXPORT_SYMBOL(osd_execute_request);
481 482
@@ -485,8 +486,12 @@ static void osd_request_async_done(struct request *req, int error)
485 486
486 or->async_error = error; 487 or->async_error = error;
487 488
488 if (error) 489 if (unlikely(error)) {
489 OSD_DEBUG("osd_request_async_done error recieved %d\n", error); 490 OSD_DEBUG("osd_request_async_done error recieved %d "
491 "errors 0x%x\n", error, req->errors);
492 if (!req->errors) /* don't miss out on this one */
493 req->errors = error;
494 }
490 495
491 if (or->async_done) 496 if (or->async_done)
492 or->async_done(or, or->async_private); 497 or->async_done(or, or->async_private);
@@ -1451,6 +1456,15 @@ int osd_finalize_request(struct osd_request *or,
1451} 1456}
1452EXPORT_SYMBOL(osd_finalize_request); 1457EXPORT_SYMBOL(osd_finalize_request);
1453 1458
1459static bool _is_osd_security_code(int code)
1460{
1461 return (code == osd_security_audit_value_frozen) ||
1462 (code == osd_security_working_key_frozen) ||
1463 (code == osd_nonce_not_unique) ||
1464 (code == osd_nonce_timestamp_out_of_range) ||
1465 (code == osd_invalid_dataout_buffer_integrity_check_value);
1466}
1467
1454#define OSD_SENSE_PRINT1(fmt, a...) \ 1468#define OSD_SENSE_PRINT1(fmt, a...) \
1455 do { \ 1469 do { \
1456 if (__cur_sense_need_output) \ 1470 if (__cur_sense_need_output) \
@@ -1473,9 +1487,16 @@ int osd_req_decode_sense_full(struct osd_request *or,
1473#else 1487#else
1474 bool __cur_sense_need_output = !silent; 1488 bool __cur_sense_need_output = !silent;
1475#endif 1489#endif
1490 int ret;
1476 1491
1477 if (!or->request->errors) 1492 if (likely(!or->request->errors)) {
1493 osi->out_resid = 0;
1494 osi->in_resid = 0;
1478 return 0; 1495 return 0;
1496 }
1497
1498 osi = osi ? : &local_osi;
1499 memset(osi, 0, sizeof(*osi));
1479 1500
1480 ssdb = or->request->sense; 1501 ssdb = or->request->sense;
1481 sense_len = or->request->sense_len; 1502 sense_len = or->request->sense_len;
@@ -1483,17 +1504,15 @@ int osd_req_decode_sense_full(struct osd_request *or,
1483 OSD_ERR("Block-layer returned error(0x%x) but " 1504 OSD_ERR("Block-layer returned error(0x%x) but "
1484 "sense_len(%u) || key(%d) is empty\n", 1505 "sense_len(%u) || key(%d) is empty\n",
1485 or->request->errors, sense_len, ssdb->sense_key); 1506 or->request->errors, sense_len, ssdb->sense_key);
1486 return -EIO; 1507 goto analyze;
1487 } 1508 }
1488 1509
1489 if ((ssdb->response_code != 0x72) && (ssdb->response_code != 0x73)) { 1510 if ((ssdb->response_code != 0x72) && (ssdb->response_code != 0x73)) {
1490 OSD_ERR("Unrecognized scsi sense: rcode=%x length=%d\n", 1511 OSD_ERR("Unrecognized scsi sense: rcode=%x length=%d\n",
1491 ssdb->response_code, sense_len); 1512 ssdb->response_code, sense_len);
1492 return -EIO; 1513 goto analyze;
1493 } 1514 }
1494 1515
1495 osi = osi ? : &local_osi;
1496 memset(osi, 0, sizeof(*osi));
1497 osi->key = ssdb->sense_key; 1516 osi->key = ssdb->sense_key;
1498 osi->additional_code = be16_to_cpu(ssdb->additional_sense_code); 1517 osi->additional_code = be16_to_cpu(ssdb->additional_sense_code);
1499 original_sense_len = ssdb->additional_sense_length + 8; 1518 original_sense_len = ssdb->additional_sense_length + 8;
@@ -1503,9 +1522,10 @@ int osd_req_decode_sense_full(struct osd_request *or,
1503 __cur_sense_need_output = (osi->key > scsi_sk_recovered_error); 1522 __cur_sense_need_output = (osi->key > scsi_sk_recovered_error);
1504#endif 1523#endif
1505 OSD_SENSE_PRINT1("Main Sense information key=0x%x length(%d, %d) " 1524 OSD_SENSE_PRINT1("Main Sense information key=0x%x length(%d, %d) "
1506 "additional_code=0x%x\n", 1525 "additional_code=0x%x async_error=%d errors=0x%x\n",
1507 osi->key, original_sense_len, sense_len, 1526 osi->key, original_sense_len, sense_len,
1508 osi->additional_code); 1527 osi->additional_code, or->async_error,
1528 or->request->errors);
1509 1529
1510 if (original_sense_len < sense_len) 1530 if (original_sense_len < sense_len)
1511 sense_len = original_sense_len; 1531 sense_len = original_sense_len;
@@ -1637,7 +1657,50 @@ int osd_req_decode_sense_full(struct osd_request *or,
1637 cur_descriptor += cur_len; 1657 cur_descriptor += cur_len;
1638 } 1658 }
1639 1659
1640 return (osi->key > scsi_sk_recovered_error) ? -EIO : 0; 1660analyze:
1661 if (!osi->key) {
1662 /* scsi sense is Empty, the request was never issued to target
1663 * linux return code might tell us what happened.
1664 */
1665 if (or->async_error == -ENOMEM)
1666 osi->osd_err_pri = OSD_ERR_PRI_RESOURCE;
1667 else
1668 osi->osd_err_pri = OSD_ERR_PRI_UNREACHABLE;
1669 ret = or->async_error;
1670 } else if (osi->key <= scsi_sk_recovered_error) {
1671 osi->osd_err_pri = 0;
1672 ret = 0;
1673 } else if (osi->additional_code == scsi_invalid_field_in_cdb) {
1674 if (osi->cdb_field_offset == OSD_CFO_STARTING_BYTE) {
1675 osi->osd_err_pri = OSD_ERR_PRI_CLEAR_PAGES;
1676 ret = -EFAULT; /* caller should recover from this */
1677 } else if (osi->cdb_field_offset == OSD_CFO_OBJECT_ID) {
1678 osi->osd_err_pri = OSD_ERR_PRI_NOT_FOUND;
1679 ret = -ENOENT;
1680 } else if (osi->cdb_field_offset == OSD_CFO_PERMISSIONS) {
1681 osi->osd_err_pri = OSD_ERR_PRI_NO_ACCESS;
1682 ret = -EACCES;
1683 } else {
1684 osi->osd_err_pri = OSD_ERR_PRI_BAD_CRED;
1685 ret = -EINVAL;
1686 }
1687 } else if (osi->additional_code == osd_quota_error) {
1688 osi->osd_err_pri = OSD_ERR_PRI_NO_SPACE;
1689 ret = -ENOSPC;
1690 } else if (_is_osd_security_code(osi->additional_code)) {
1691 osi->osd_err_pri = OSD_ERR_PRI_BAD_CRED;
1692 ret = -EINVAL;
1693 } else {
1694 osi->osd_err_pri = OSD_ERR_PRI_EIO;
1695 ret = -EIO;
1696 }
1697
1698 if (or->out.req)
1699 osi->out_resid = or->out.req->resid_len ?: or->out.total_bytes;
1700 if (or->in.req)
1701 osi->in_resid = or->in.req->resid_len ?: or->in.total_bytes;
1702
1703 return ret;
1641} 1704}
1642EXPORT_SYMBOL(osd_req_decode_sense_full); 1705EXPORT_SYMBOL(osd_req_decode_sense_full);
1643 1706
diff --git a/include/scsi/osd_initiator.h b/include/scsi/osd_initiator.h
index 3ec346e15dda..39d6d1097153 100644
--- a/include/scsi/osd_initiator.h
+++ b/include/scsi/osd_initiator.h
@@ -267,7 +267,7 @@ int osd_execute_request_async(struct osd_request *or,
267 * @bad_attr_list - List of failing attributes (optional) 267 * @bad_attr_list - List of failing attributes (optional)
268 * @max_attr - Size of @bad_attr_list. 268 * @max_attr - Size of @bad_attr_list.
269 * 269 *
270 * After execution, sense + return code can be analyzed using this function. The 270 * After execution, osd_request results are analyzed using this function. The
271 * return code is the final disposition on the error. So it is possible that a 271 * return code is the final disposition on the error. So it is possible that a
272 * CHECK_CONDITION was returned from target but this will return NO_ERROR, for 272 * CHECK_CONDITION was returned from target but this will return NO_ERROR, for
273 * example on recovered errors. All parameters are optional if caller does 273 * example on recovered errors. All parameters are optional if caller does
@@ -276,7 +276,31 @@ int osd_execute_request_async(struct osd_request *or,
276 * of the SCSI_OSD_DPRINT_SENSE Kconfig value. Set @silent if you know the 276 * of the SCSI_OSD_DPRINT_SENSE Kconfig value. Set @silent if you know the
277 * command would routinely fail, to not spam the dmsg file. 277 * command would routinely fail, to not spam the dmsg file.
278 */ 278 */
279
280/**
281 * osd_err_priority - osd categorized return codes in ascending severity.
282 *
283 * The categories are borrowed from the pnfs_osd_errno enum.
284 * See comments for translated Linux codes returned by osd_req_decode_sense.
285 */
286enum osd_err_priority {
287 OSD_ERR_PRI_NO_ERROR = 0,
288 /* Recoverable, caller should clear_highpage() all pages */
289 OSD_ERR_PRI_CLEAR_PAGES = 1, /* -EFAULT */
290 OSD_ERR_PRI_RESOURCE = 2, /* -ENOMEM */
291 OSD_ERR_PRI_BAD_CRED = 3, /* -EINVAL */
292 OSD_ERR_PRI_NO_ACCESS = 4, /* -EACCES */
293 OSD_ERR_PRI_UNREACHABLE = 5, /* any other */
294 OSD_ERR_PRI_NOT_FOUND = 6, /* -ENOENT */
295 OSD_ERR_PRI_NO_SPACE = 7, /* -ENOSPC */
296 OSD_ERR_PRI_EIO = 8, /* -EIO */
297};
298
279struct osd_sense_info { 299struct osd_sense_info {
300 u64 out_resid; /* Zero on success otherwise out residual */
301 u64 in_resid; /* Zero on success otherwise in residual */
302 enum osd_err_priority osd_err_pri;
303
280 int key; /* one of enum scsi_sense_keys */ 304 int key; /* one of enum scsi_sense_keys */
281 int additional_code ; /* enum osd_additional_sense_codes */ 305 int additional_code ; /* enum osd_additional_sense_codes */
282 union { /* Sense specific information */ 306 union { /* Sense specific information */