diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /drivers/scsi/osd/osd_initiator.c | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'drivers/scsi/osd/osd_initiator.c')
-rw-r--r-- | drivers/scsi/osd/osd_initiator.c | 181 |
1 files changed, 136 insertions, 45 deletions
diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c index 7a117c18114c..ee4b6914667f 100644 --- a/drivers/scsi/osd/osd_initiator.c +++ b/drivers/scsi/osd/osd_initiator.c | |||
@@ -39,6 +39,8 @@ | |||
39 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 39 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
40 | */ | 40 | */ |
41 | 41 | ||
42 | #include <linux/slab.h> | ||
43 | |||
42 | #include <scsi/osd_initiator.h> | 44 | #include <scsi/osd_initiator.h> |
43 | #include <scsi/osd_sec.h> | 45 | #include <scsi/osd_sec.h> |
44 | #include <scsi/osd_attributes.h> | 46 | #include <scsi/osd_attributes.h> |
@@ -73,7 +75,8 @@ static const char *_osd_ver_desc(struct osd_request *or) | |||
73 | 75 | ||
74 | #define ATTR_DEF_RI(id, len) ATTR_DEF(OSD_APAGE_ROOT_INFORMATION, id, len) | 76 | #define ATTR_DEF_RI(id, len) ATTR_DEF(OSD_APAGE_ROOT_INFORMATION, id, len) |
75 | 77 | ||
76 | static int _osd_print_system_info(struct osd_dev *od, void *caps) | 78 | static int _osd_get_print_system_info(struct osd_dev *od, |
79 | void *caps, struct osd_dev_info *odi) | ||
77 | { | 80 | { |
78 | struct osd_request *or; | 81 | struct osd_request *or; |
79 | struct osd_attr get_attrs[] = { | 82 | struct osd_attr get_attrs[] = { |
@@ -137,8 +140,12 @@ static int _osd_print_system_info(struct osd_dev *od, void *caps) | |||
137 | OSD_INFO("PRODUCT_SERIAL_NUMBER [%s]\n", | 140 | OSD_INFO("PRODUCT_SERIAL_NUMBER [%s]\n", |
138 | (char *)pFirst); | 141 | (char *)pFirst); |
139 | 142 | ||
140 | pFirst = get_attrs[a].val_ptr; | 143 | odi->osdname_len = get_attrs[a].len; |
141 | OSD_INFO("OSD_NAME [%s]\n", (char *)pFirst); | 144 | /* Avoid NULL for memcmp optimization 0-length is good enough */ |
145 | odi->osdname = kzalloc(odi->osdname_len + 1, GFP_KERNEL); | ||
146 | if (odi->osdname_len) | ||
147 | memcpy(odi->osdname, get_attrs[a].val_ptr, odi->osdname_len); | ||
148 | OSD_INFO("OSD_NAME [%s]\n", odi->osdname); | ||
142 | a++; | 149 | a++; |
143 | 150 | ||
144 | pFirst = get_attrs[a++].val_ptr; | 151 | pFirst = get_attrs[a++].val_ptr; |
@@ -171,6 +178,14 @@ static int _osd_print_system_info(struct osd_dev *od, void *caps) | |||
171 | sid_dump, sizeof(sid_dump), true); | 178 | sid_dump, sizeof(sid_dump), true); |
172 | OSD_INFO("OSD_SYSTEM_ID(%d)\n" | 179 | OSD_INFO("OSD_SYSTEM_ID(%d)\n" |
173 | " [%s]\n", len, sid_dump); | 180 | " [%s]\n", len, sid_dump); |
181 | |||
182 | if (unlikely(len > sizeof(odi->systemid))) { | ||
183 | OSD_ERR("OSD Target error: OSD_SYSTEM_ID too long(%d). " | ||
184 | "device idetification might not work\n", len); | ||
185 | len = sizeof(odi->systemid); | ||
186 | } | ||
187 | odi->systemid_len = len; | ||
188 | memcpy(odi->systemid, get_attrs[a].val_ptr, len); | ||
174 | a++; | 189 | a++; |
175 | } | 190 | } |
176 | out: | 191 | out: |
@@ -178,16 +193,17 @@ out: | |||
178 | return ret; | 193 | return ret; |
179 | } | 194 | } |
180 | 195 | ||
181 | int osd_auto_detect_ver(struct osd_dev *od, void *caps) | 196 | int osd_auto_detect_ver(struct osd_dev *od, |
197 | void *caps, struct osd_dev_info *odi) | ||
182 | { | 198 | { |
183 | int ret; | 199 | int ret; |
184 | 200 | ||
185 | /* Auto-detect the osd version */ | 201 | /* Auto-detect the osd version */ |
186 | ret = _osd_print_system_info(od, caps); | 202 | ret = _osd_get_print_system_info(od, caps, odi); |
187 | if (ret) { | 203 | if (ret) { |
188 | osd_dev_set_ver(od, OSD_VER1); | 204 | osd_dev_set_ver(od, OSD_VER1); |
189 | OSD_DEBUG("converting to OSD1\n"); | 205 | OSD_DEBUG("converting to OSD1\n"); |
190 | ret = _osd_print_system_info(od, caps); | 206 | ret = _osd_get_print_system_info(od, caps, odi); |
191 | } | 207 | } |
192 | 208 | ||
193 | return ret; | 209 | return ret; |
@@ -418,30 +434,23 @@ static void _osd_free_seg(struct osd_request *or __unused, | |||
418 | seg->alloc_size = 0; | 434 | seg->alloc_size = 0; |
419 | } | 435 | } |
420 | 436 | ||
421 | static void _put_request(struct request *rq , bool is_async) | 437 | static void _put_request(struct request *rq) |
422 | { | 438 | { |
423 | if (is_async) { | 439 | /* |
424 | WARN_ON(rq->bio); | 440 | * If osd_finalize_request() was called but the request was not |
425 | __blk_put_request(rq->q, rq); | 441 | * executed through the block layer, then we must release BIOs. |
426 | } else { | 442 | * TODO: Keep error code in or->async_error. Need to audit all |
427 | /* | 443 | * code paths. |
428 | * If osd_finalize_request() was called but the request was not | 444 | */ |
429 | * executed through the block layer, then we must release BIOs. | 445 | if (unlikely(rq->bio)) |
430 | * TODO: Keep error code in or->async_error. Need to audit all | 446 | blk_end_request(rq, -ENOMEM, blk_rq_bytes(rq)); |
431 | * code paths. | 447 | else |
432 | */ | 448 | blk_put_request(rq); |
433 | if (unlikely(rq->bio)) | ||
434 | blk_end_request(rq, -ENOMEM, blk_rq_bytes(rq)); | ||
435 | else | ||
436 | blk_put_request(rq); | ||
437 | } | ||
438 | } | 449 | } |
439 | 450 | ||
440 | void osd_end_request(struct osd_request *or) | 451 | void osd_end_request(struct osd_request *or) |
441 | { | 452 | { |
442 | struct request *rq = or->request; | 453 | struct request *rq = or->request; |
443 | /* IMPORTANT: make sure this agrees with osd_execute_request_async */ | ||
444 | bool is_async = (or->request->end_io_data == or); | ||
445 | 454 | ||
446 | _osd_free_seg(or, &or->set_attr); | 455 | _osd_free_seg(or, &or->set_attr); |
447 | _osd_free_seg(or, &or->enc_get_attr); | 456 | _osd_free_seg(or, &or->enc_get_attr); |
@@ -449,19 +458,34 @@ void osd_end_request(struct osd_request *or) | |||
449 | 458 | ||
450 | if (rq) { | 459 | if (rq) { |
451 | if (rq->next_rq) { | 460 | if (rq->next_rq) { |
452 | _put_request(rq->next_rq, is_async); | 461 | _put_request(rq->next_rq); |
453 | rq->next_rq = NULL; | 462 | rq->next_rq = NULL; |
454 | } | 463 | } |
455 | 464 | ||
456 | _put_request(rq, is_async); | 465 | _put_request(rq); |
457 | } | 466 | } |
458 | _osd_request_free(or); | 467 | _osd_request_free(or); |
459 | } | 468 | } |
460 | EXPORT_SYMBOL(osd_end_request); | 469 | EXPORT_SYMBOL(osd_end_request); |
461 | 470 | ||
471 | static void _set_error_resid(struct osd_request *or, struct request *req, | ||
472 | int error) | ||
473 | { | ||
474 | or->async_error = error; | ||
475 | or->req_errors = req->errors ? : error; | ||
476 | or->sense_len = req->sense_len; | ||
477 | if (or->out.req) | ||
478 | or->out.residual = or->out.req->resid_len; | ||
479 | if (or->in.req) | ||
480 | or->in.residual = or->in.req->resid_len; | ||
481 | } | ||
482 | |||
462 | int osd_execute_request(struct osd_request *or) | 483 | int osd_execute_request(struct osd_request *or) |
463 | { | 484 | { |
464 | return blk_execute_rq(or->request->q, NULL, or->request, 0); | 485 | int error = blk_execute_rq(or->request->q, NULL, or->request, 0); |
486 | |||
487 | _set_error_resid(or, or->request, error); | ||
488 | return error; | ||
465 | } | 489 | } |
466 | EXPORT_SYMBOL(osd_execute_request); | 490 | EXPORT_SYMBOL(osd_execute_request); |
467 | 491 | ||
@@ -469,10 +493,16 @@ static void osd_request_async_done(struct request *req, int error) | |||
469 | { | 493 | { |
470 | struct osd_request *or = req->end_io_data; | 494 | struct osd_request *or = req->end_io_data; |
471 | 495 | ||
472 | or->async_error = error; | 496 | _set_error_resid(or, req, error); |
497 | if (req->next_rq) { | ||
498 | __blk_put_request(req->q, req->next_rq); | ||
499 | req->next_rq = NULL; | ||
500 | } | ||
473 | 501 | ||
474 | if (error) | 502 | __blk_put_request(req->q, req); |
475 | OSD_DEBUG("osd_request_async_done error recieved %d\n", error); | 503 | or->request = NULL; |
504 | or->in.req = NULL; | ||
505 | or->out.req = NULL; | ||
476 | 506 | ||
477 | if (or->async_done) | 507 | if (or->async_done) |
478 | or->async_done(or, or->async_private); | 508 | or->async_done(or, or->async_private); |
@@ -1153,6 +1183,7 @@ int osd_req_decode_get_attr_list(struct osd_request *or, | |||
1153 | "c=%d r=%d n=%d\n", | 1183 | "c=%d r=%d n=%d\n", |
1154 | cur_bytes, returned_bytes, n); | 1184 | cur_bytes, returned_bytes, n); |
1155 | oa->val_ptr = NULL; | 1185 | oa->val_ptr = NULL; |
1186 | cur_bytes = returned_bytes; /* break the caller loop */ | ||
1156 | break; | 1187 | break; |
1157 | } | 1188 | } |
1158 | 1189 | ||
@@ -1404,6 +1435,10 @@ int osd_finalize_request(struct osd_request *or, | |||
1404 | cdbh->command_specific_options |= or->attributes_mode; | 1435 | cdbh->command_specific_options |= or->attributes_mode; |
1405 | if (or->attributes_mode == OSD_CDB_GET_ATTR_PAGE_SET_ONE) { | 1436 | if (or->attributes_mode == OSD_CDB_GET_ATTR_PAGE_SET_ONE) { |
1406 | ret = _osd_req_finalize_attr_page(or); | 1437 | ret = _osd_req_finalize_attr_page(or); |
1438 | if (ret) { | ||
1439 | OSD_DEBUG("_osd_req_finalize_attr_page failed\n"); | ||
1440 | return ret; | ||
1441 | } | ||
1407 | } else { | 1442 | } else { |
1408 | /* TODO: I think that for the GET_ATTR command these 2 should | 1443 | /* TODO: I think that for the GET_ATTR command these 2 should |
1409 | * be reversed to keep them in execution order (for embeded | 1444 | * be reversed to keep them in execution order (for embeded |
@@ -1436,6 +1471,15 @@ int osd_finalize_request(struct osd_request *or, | |||
1436 | } | 1471 | } |
1437 | EXPORT_SYMBOL(osd_finalize_request); | 1472 | EXPORT_SYMBOL(osd_finalize_request); |
1438 | 1473 | ||
1474 | static bool _is_osd_security_code(int code) | ||
1475 | { | ||
1476 | return (code == osd_security_audit_value_frozen) || | ||
1477 | (code == osd_security_working_key_frozen) || | ||
1478 | (code == osd_nonce_not_unique) || | ||
1479 | (code == osd_nonce_timestamp_out_of_range) || | ||
1480 | (code == osd_invalid_dataout_buffer_integrity_check_value); | ||
1481 | } | ||
1482 | |||
1439 | #define OSD_SENSE_PRINT1(fmt, a...) \ | 1483 | #define OSD_SENSE_PRINT1(fmt, a...) \ |
1440 | do { \ | 1484 | do { \ |
1441 | if (__cur_sense_need_output) \ | 1485 | if (__cur_sense_need_output) \ |
@@ -1458,27 +1502,29 @@ int osd_req_decode_sense_full(struct osd_request *or, | |||
1458 | #else | 1502 | #else |
1459 | bool __cur_sense_need_output = !silent; | 1503 | bool __cur_sense_need_output = !silent; |
1460 | #endif | 1504 | #endif |
1505 | int ret; | ||
1461 | 1506 | ||
1462 | if (!or->request->errors) | 1507 | if (likely(!or->req_errors)) |
1463 | return 0; | 1508 | return 0; |
1464 | 1509 | ||
1465 | ssdb = or->request->sense; | 1510 | osi = osi ? : &local_osi; |
1466 | sense_len = or->request->sense_len; | 1511 | memset(osi, 0, sizeof(*osi)); |
1512 | |||
1513 | ssdb = (typeof(ssdb))or->sense; | ||
1514 | sense_len = or->sense_len; | ||
1467 | if ((sense_len < (int)sizeof(*ssdb) || !ssdb->sense_key)) { | 1515 | if ((sense_len < (int)sizeof(*ssdb) || !ssdb->sense_key)) { |
1468 | OSD_ERR("Block-layer returned error(0x%x) but " | 1516 | OSD_ERR("Block-layer returned error(0x%x) but " |
1469 | "sense_len(%u) || key(%d) is empty\n", | 1517 | "sense_len(%u) || key(%d) is empty\n", |
1470 | or->request->errors, sense_len, ssdb->sense_key); | 1518 | or->req_errors, sense_len, ssdb->sense_key); |
1471 | return -EIO; | 1519 | goto analyze; |
1472 | } | 1520 | } |
1473 | 1521 | ||
1474 | if ((ssdb->response_code != 0x72) && (ssdb->response_code != 0x73)) { | 1522 | if ((ssdb->response_code != 0x72) && (ssdb->response_code != 0x73)) { |
1475 | OSD_ERR("Unrecognized scsi sense: rcode=%x length=%d\n", | 1523 | OSD_ERR("Unrecognized scsi sense: rcode=%x length=%d\n", |
1476 | ssdb->response_code, sense_len); | 1524 | ssdb->response_code, sense_len); |
1477 | return -EIO; | 1525 | goto analyze; |
1478 | } | 1526 | } |
1479 | 1527 | ||
1480 | osi = osi ? : &local_osi; | ||
1481 | memset(osi, 0, sizeof(*osi)); | ||
1482 | osi->key = ssdb->sense_key; | 1528 | osi->key = ssdb->sense_key; |
1483 | osi->additional_code = be16_to_cpu(ssdb->additional_sense_code); | 1529 | osi->additional_code = be16_to_cpu(ssdb->additional_sense_code); |
1484 | original_sense_len = ssdb->additional_sense_length + 8; | 1530 | original_sense_len = ssdb->additional_sense_length + 8; |
@@ -1488,9 +1534,10 @@ int osd_req_decode_sense_full(struct osd_request *or, | |||
1488 | __cur_sense_need_output = (osi->key > scsi_sk_recovered_error); | 1534 | __cur_sense_need_output = (osi->key > scsi_sk_recovered_error); |
1489 | #endif | 1535 | #endif |
1490 | OSD_SENSE_PRINT1("Main Sense information key=0x%x length(%d, %d) " | 1536 | OSD_SENSE_PRINT1("Main Sense information key=0x%x length(%d, %d) " |
1491 | "additional_code=0x%x\n", | 1537 | "additional_code=0x%x async_error=%d errors=0x%x\n", |
1492 | osi->key, original_sense_len, sense_len, | 1538 | osi->key, original_sense_len, sense_len, |
1493 | osi->additional_code); | 1539 | osi->additional_code, or->async_error, |
1540 | or->req_errors); | ||
1494 | 1541 | ||
1495 | if (original_sense_len < sense_len) | 1542 | if (original_sense_len < sense_len) |
1496 | sense_len = original_sense_len; | 1543 | sense_len = original_sense_len; |
@@ -1569,15 +1616,14 @@ int osd_req_decode_sense_full(struct osd_request *or, | |||
1569 | { | 1616 | { |
1570 | struct osd_sense_attributes_data_descriptor | 1617 | struct osd_sense_attributes_data_descriptor |
1571 | *osadd = cur_descriptor; | 1618 | *osadd = cur_descriptor; |
1572 | int len = min(cur_len, sense_len); | 1619 | unsigned len = min(cur_len, sense_len); |
1573 | int i = 0; | ||
1574 | struct osd_sense_attr *pattr = osadd->sense_attrs; | 1620 | struct osd_sense_attr *pattr = osadd->sense_attrs; |
1575 | 1621 | ||
1576 | while (len < 0) { | 1622 | while (len >= sizeof(*pattr)) { |
1577 | u32 attr_page = be32_to_cpu(pattr->attr_page); | 1623 | u32 attr_page = be32_to_cpu(pattr->attr_page); |
1578 | u32 attr_id = be32_to_cpu(pattr->attr_id); | 1624 | u32 attr_id = be32_to_cpu(pattr->attr_id); |
1579 | 1625 | ||
1580 | if (i++ == 0) { | 1626 | if (!osi->attr.attr_page) { |
1581 | osi->attr.attr_page = attr_page; | 1627 | osi->attr.attr_page = attr_page; |
1582 | osi->attr.attr_id = attr_id; | 1628 | osi->attr.attr_id = attr_id; |
1583 | } | 1629 | } |
@@ -1588,6 +1634,8 @@ int osd_req_decode_sense_full(struct osd_request *or, | |||
1588 | bad_attr_list++; | 1634 | bad_attr_list++; |
1589 | max_attr--; | 1635 | max_attr--; |
1590 | } | 1636 | } |
1637 | |||
1638 | len -= sizeof(*pattr); | ||
1591 | OSD_SENSE_PRINT2( | 1639 | OSD_SENSE_PRINT2( |
1592 | "osd_sense_attribute_identification" | 1640 | "osd_sense_attribute_identification" |
1593 | "attr_page=0x%x attr_id=0x%x\n", | 1641 | "attr_page=0x%x attr_id=0x%x\n", |
@@ -1621,7 +1669,50 @@ int osd_req_decode_sense_full(struct osd_request *or, | |||
1621 | cur_descriptor += cur_len; | 1669 | cur_descriptor += cur_len; |
1622 | } | 1670 | } |
1623 | 1671 | ||
1624 | return (osi->key > scsi_sk_recovered_error) ? -EIO : 0; | 1672 | analyze: |
1673 | if (!osi->key) { | ||
1674 | /* scsi sense is Empty, the request was never issued to target | ||
1675 | * linux return code might tell us what happened. | ||
1676 | */ | ||
1677 | if (or->async_error == -ENOMEM) | ||
1678 | osi->osd_err_pri = OSD_ERR_PRI_RESOURCE; | ||
1679 | else | ||
1680 | osi->osd_err_pri = OSD_ERR_PRI_UNREACHABLE; | ||
1681 | ret = or->async_error; | ||
1682 | } else if (osi->key <= scsi_sk_recovered_error) { | ||
1683 | osi->osd_err_pri = 0; | ||
1684 | ret = 0; | ||
1685 | } else if (osi->additional_code == scsi_invalid_field_in_cdb) { | ||
1686 | if (osi->cdb_field_offset == OSD_CFO_STARTING_BYTE) { | ||
1687 | osi->osd_err_pri = OSD_ERR_PRI_CLEAR_PAGES; | ||
1688 | ret = -EFAULT; /* caller should recover from this */ | ||
1689 | } else if (osi->cdb_field_offset == OSD_CFO_OBJECT_ID) { | ||
1690 | osi->osd_err_pri = OSD_ERR_PRI_NOT_FOUND; | ||
1691 | ret = -ENOENT; | ||
1692 | } else if (osi->cdb_field_offset == OSD_CFO_PERMISSIONS) { | ||
1693 | osi->osd_err_pri = OSD_ERR_PRI_NO_ACCESS; | ||
1694 | ret = -EACCES; | ||
1695 | } else { | ||
1696 | osi->osd_err_pri = OSD_ERR_PRI_BAD_CRED; | ||
1697 | ret = -EINVAL; | ||
1698 | } | ||
1699 | } else if (osi->additional_code == osd_quota_error) { | ||
1700 | osi->osd_err_pri = OSD_ERR_PRI_NO_SPACE; | ||
1701 | ret = -ENOSPC; | ||
1702 | } else if (_is_osd_security_code(osi->additional_code)) { | ||
1703 | osi->osd_err_pri = OSD_ERR_PRI_BAD_CRED; | ||
1704 | ret = -EINVAL; | ||
1705 | } else { | ||
1706 | osi->osd_err_pri = OSD_ERR_PRI_EIO; | ||
1707 | ret = -EIO; | ||
1708 | } | ||
1709 | |||
1710 | if (!or->out.residual) | ||
1711 | or->out.residual = or->out.total_bytes; | ||
1712 | if (!or->in.residual) | ||
1713 | or->in.residual = or->in.total_bytes; | ||
1714 | |||
1715 | return ret; | ||
1625 | } | 1716 | } |
1626 | EXPORT_SYMBOL(osd_req_decode_sense_full); | 1717 | EXPORT_SYMBOL(osd_req_decode_sense_full); |
1627 | 1718 | ||