aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/osd
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/osd')
-rw-r--r--drivers/scsi/osd/osd_initiator.c181
-rw-r--r--drivers/scsi/osd/osd_uld.c261
2 files changed, 314 insertions, 128 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
76static int _osd_print_system_info(struct osd_dev *od, void *caps) 78static 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 }
176out: 191out:
@@ -178,16 +193,17 @@ out:
178 return ret; 193 return ret;
179} 194}
180 195
181int osd_auto_detect_ver(struct osd_dev *od, void *caps) 196int 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
421static void _put_request(struct request *rq , bool is_async) 437static 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
440void osd_end_request(struct osd_request *or) 451void 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}
460EXPORT_SYMBOL(osd_end_request); 469EXPORT_SYMBOL(osd_end_request);
461 470
471static 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
462int osd_execute_request(struct osd_request *or) 483int 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}
466EXPORT_SYMBOL(osd_execute_request); 490EXPORT_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}
1437EXPORT_SYMBOL(osd_finalize_request); 1472EXPORT_SYMBOL(osd_finalize_request);
1438 1473
1474static 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; 1672analyze:
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}
1626EXPORT_SYMBOL(osd_req_decode_sense_full); 1717EXPORT_SYMBOL(osd_req_decode_sense_full);
1627 1718
diff --git a/drivers/scsi/osd/osd_uld.c b/drivers/scsi/osd/osd_uld.c
index 0bdef3390902..ffdd9fdb9995 100644
--- a/drivers/scsi/osd/osd_uld.c
+++ b/drivers/scsi/osd/osd_uld.c
@@ -50,6 +50,7 @@
50#include <linux/idr.h> 50#include <linux/idr.h>
51#include <linux/major.h> 51#include <linux/major.h>
52#include <linux/file.h> 52#include <linux/file.h>
53#include <linux/slab.h>
53 54
54#include <scsi/scsi.h> 55#include <scsi/scsi.h>
55#include <scsi/scsi_driver.h> 56#include <scsi/scsi_driver.h>
@@ -71,8 +72,7 @@
71#define SCSI_OSD_MAX_MINOR 64 72#define SCSI_OSD_MAX_MINOR 64
72 73
73static const char osd_name[] = "osd"; 74static const char osd_name[] = "osd";
74static const char *osd_version_string = "open-osd 0.1.0"; 75static const char *osd_version_string = "open-osd 0.2.0";
75const char osd_symlink[] = "scsi_osd";
76 76
77MODULE_AUTHOR("Boaz Harrosh <bharrosh@panasas.com>"); 77MODULE_AUTHOR("Boaz Harrosh <bharrosh@panasas.com>");
78MODULE_DESCRIPTION("open-osd Upper-Layer-Driver osd.ko"); 78MODULE_DESCRIPTION("open-osd Upper-Layer-Driver osd.ko");
@@ -82,15 +82,25 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_OSD);
82 82
83struct osd_uld_device { 83struct osd_uld_device {
84 int minor; 84 int minor;
85 struct kref kref; 85 struct device class_dev;
86 struct cdev cdev; 86 struct cdev cdev;
87 struct osd_dev od; 87 struct osd_dev od;
88 struct osd_dev_info odi;
88 struct gendisk *disk; 89 struct gendisk *disk;
89 struct device *class_member;
90}; 90};
91 91
92static void __uld_get(struct osd_uld_device *oud); 92struct osd_dev_handle {
93static void __uld_put(struct osd_uld_device *oud); 93 struct osd_dev od;
94 struct file *file;
95 struct osd_uld_device *oud;
96} ;
97
98static DEFINE_IDA(osd_minor_ida);
99
100static struct class osd_uld_class = {
101 .owner = THIS_MODULE,
102 .name = "scsi_osd",
103};
94 104
95/* 105/*
96 * Char Device operations 106 * Char Device operations
@@ -101,7 +111,7 @@ static int osd_uld_open(struct inode *inode, struct file *file)
101 struct osd_uld_device *oud = container_of(inode->i_cdev, 111 struct osd_uld_device *oud = container_of(inode->i_cdev,
102 struct osd_uld_device, cdev); 112 struct osd_uld_device, cdev);
103 113
104 __uld_get(oud); 114 get_device(&oud->class_dev);
105 /* cache osd_uld_device on file handle */ 115 /* cache osd_uld_device on file handle */
106 file->private_data = oud; 116 file->private_data = oud;
107 OSD_DEBUG("osd_uld_open %p\n", oud); 117 OSD_DEBUG("osd_uld_open %p\n", oud);
@@ -114,7 +124,7 @@ static int osd_uld_release(struct inode *inode, struct file *file)
114 124
115 OSD_DEBUG("osd_uld_release %p\n", file->private_data); 125 OSD_DEBUG("osd_uld_release %p\n", file->private_data);
116 file->private_data = NULL; 126 file->private_data = NULL;
117 __uld_put(oud); 127 put_device(&oud->class_dev);
118 return 0; 128 return 0;
119} 129}
120 130
@@ -177,7 +187,7 @@ static const struct file_operations osd_fops = {
177struct osd_dev *osduld_path_lookup(const char *name) 187struct osd_dev *osduld_path_lookup(const char *name)
178{ 188{
179 struct osd_uld_device *oud; 189 struct osd_uld_device *oud;
180 struct osd_dev *od; 190 struct osd_dev_handle *odh;
181 struct file *file; 191 struct file *file;
182 int error; 192 int error;
183 193
@@ -186,8 +196,8 @@ struct osd_dev *osduld_path_lookup(const char *name)
186 return ERR_PTR(-EINVAL); 196 return ERR_PTR(-EINVAL);
187 } 197 }
188 198
189 od = kzalloc(sizeof(*od), GFP_KERNEL); 199 odh = kzalloc(sizeof(*odh), GFP_KERNEL);
190 if (!od) 200 if (unlikely(!odh))
191 return ERR_PTR(-ENOMEM); 201 return ERR_PTR(-ENOMEM);
192 202
193 file = filp_open(name, O_RDWR, 0); 203 file = filp_open(name, O_RDWR, 0);
@@ -203,33 +213,134 @@ struct osd_dev *osduld_path_lookup(const char *name)
203 213
204 oud = file->private_data; 214 oud = file->private_data;
205 215
206 *od = oud->od; 216 odh->od = oud->od;
207 od->file = file; 217 odh->file = file;
218 odh->oud = oud;
208 219
209 return od; 220 return &odh->od;
210 221
211close_file: 222close_file:
212 fput(file); 223 fput(file);
213free_od: 224free_od:
214 kfree(od); 225 kfree(odh);
215 return ERR_PTR(error); 226 return ERR_PTR(error);
216} 227}
217EXPORT_SYMBOL(osduld_path_lookup); 228EXPORT_SYMBOL(osduld_path_lookup);
218 229
219void osduld_put_device(struct osd_dev *od) 230static inline bool _the_same_or_null(const u8 *a1, unsigned a1_len,
231 const u8 *a2, unsigned a2_len)
220{ 232{
233 if (!a2_len) /* User string is Empty means don't care */
234 return true;
235
236 if (a1_len != a2_len)
237 return false;
238
239 return 0 == memcmp(a1, a2, a1_len);
240}
241
242struct find_oud_t {
243 const struct osd_dev_info *odi;
244 struct device *dev;
245 struct osd_uld_device *oud;
246} ;
247
248int _mach_odi(struct device *dev, void *find_data)
249{
250 struct osd_uld_device *oud = container_of(dev, struct osd_uld_device,
251 class_dev);
252 struct find_oud_t *fot = find_data;
253 const struct osd_dev_info *odi = fot->odi;
254
255 if (_the_same_or_null(oud->odi.systemid, oud->odi.systemid_len,
256 odi->systemid, odi->systemid_len) &&
257 _the_same_or_null(oud->odi.osdname, oud->odi.osdname_len,
258 odi->osdname, odi->osdname_len)) {
259 OSD_DEBUG("found device sysid_len=%d osdname=%d\n",
260 odi->systemid_len, odi->osdname_len);
261 fot->oud = oud;
262 return 1;
263 } else {
264 return 0;
265 }
266}
267
268/* osduld_info_lookup - Loop through all devices, return the requested osd_dev.
269 *
270 * if @odi->systemid_len and/or @odi->osdname_len are zero, they act as a don't
271 * care. .e.g if they're both zero /dev/osd0 is returned.
272 */
273struct osd_dev *osduld_info_lookup(const struct osd_dev_info *odi)
274{
275 struct find_oud_t find = {.odi = odi};
276
277 find.dev = class_find_device(&osd_uld_class, NULL, &find, _mach_odi);
278 if (likely(find.dev)) {
279 struct osd_dev_handle *odh = kzalloc(sizeof(*odh), GFP_KERNEL);
280
281 if (unlikely(!odh)) {
282 put_device(find.dev);
283 return ERR_PTR(-ENOMEM);
284 }
221 285
286 odh->od = find.oud->od;
287 odh->oud = find.oud;
288
289 return &odh->od;
290 }
291
292 return ERR_PTR(-ENODEV);
293}
294EXPORT_SYMBOL(osduld_info_lookup);
295
296void osduld_put_device(struct osd_dev *od)
297{
222 if (od && !IS_ERR(od)) { 298 if (od && !IS_ERR(od)) {
223 struct osd_uld_device *oud = od->file->private_data; 299 struct osd_dev_handle *odh =
300 container_of(od, struct osd_dev_handle, od);
301 struct osd_uld_device *oud = odh->oud;
224 302
225 BUG_ON(od->scsi_device != oud->od.scsi_device); 303 BUG_ON(od->scsi_device != oud->od.scsi_device);
226 304
227 fput(od->file); 305 /* If scsi has released the device (logout), and exofs has last
228 kfree(od); 306 * reference on oud it will be freed by above osd_uld_release
307 * within fput below. But this will oops in cdev_release which
308 * is called after the fops->release. A get_/put_ pair makes
309 * sure we have a cdev for the duration of fput
310 */
311 if (odh->file) {
312 get_device(&oud->class_dev);
313 fput(odh->file);
314 }
315 put_device(&oud->class_dev);
316 kfree(odh);
229 } 317 }
230} 318}
231EXPORT_SYMBOL(osduld_put_device); 319EXPORT_SYMBOL(osduld_put_device);
232 320
321const struct osd_dev_info *osduld_device_info(struct osd_dev *od)
322{
323 struct osd_dev_handle *odh =
324 container_of(od, struct osd_dev_handle, od);
325 return &odh->oud->odi;
326}
327EXPORT_SYMBOL(osduld_device_info);
328
329bool osduld_device_same(struct osd_dev *od, const struct osd_dev_info *odi)
330{
331 struct osd_dev_handle *odh =
332 container_of(od, struct osd_dev_handle, od);
333 struct osd_uld_device *oud = odh->oud;
334
335 return (oud->odi.systemid_len == odi->systemid_len) &&
336 _the_same_or_null(oud->odi.systemid, oud->odi.systemid_len,
337 odi->systemid, odi->systemid_len) &&
338 (oud->odi.osdname_len == odi->osdname_len) &&
339 _the_same_or_null(oud->odi.osdname, oud->odi.osdname_len,
340 odi->osdname, odi->osdname_len);
341}
342EXPORT_SYMBOL(osduld_device_same);
343
233/* 344/*
234 * Scsi Device operations 345 * Scsi Device operations
235 */ 346 */
@@ -250,14 +361,35 @@ static int __detect_osd(struct osd_uld_device *oud)
250 OSD_ERR("warning: scsi_test_unit_ready failed\n"); 361 OSD_ERR("warning: scsi_test_unit_ready failed\n");
251 362
252 osd_sec_init_nosec_doall_caps(caps, &osd_root_object, false, true); 363 osd_sec_init_nosec_doall_caps(caps, &osd_root_object, false, true);
253 if (osd_auto_detect_ver(&oud->od, caps)) 364 if (osd_auto_detect_ver(&oud->od, caps, &oud->odi))
254 return -ENODEV; 365 return -ENODEV;
255 366
256 return 0; 367 return 0;
257} 368}
258 369
259static struct class *osd_sysfs_class; 370static void __remove(struct device *dev)
260static DEFINE_IDA(osd_minor_ida); 371{
372 struct osd_uld_device *oud = container_of(dev, struct osd_uld_device,
373 class_dev);
374 struct scsi_device *scsi_device = oud->od.scsi_device;
375
376 kfree(oud->odi.osdname);
377
378 if (oud->cdev.owner)
379 cdev_del(&oud->cdev);
380
381 osd_dev_fini(&oud->od);
382 scsi_device_put(scsi_device);
383
384 OSD_INFO("osd_remove %s\n",
385 oud->disk ? oud->disk->disk_name : NULL);
386
387 if (oud->disk)
388 put_disk(oud->disk);
389 ida_remove(&osd_minor_ida, oud->minor);
390
391 kfree(oud);
392}
261 393
262static int osd_probe(struct device *dev) 394static int osd_probe(struct device *dev)
263{ 395{
@@ -289,7 +421,6 @@ static int osd_probe(struct device *dev)
289 if (NULL == oud) 421 if (NULL == oud)
290 goto err_retract_minor; 422 goto err_retract_minor;
291 423
292 kref_init(&oud->kref);
293 dev_set_drvdata(dev, oud); 424 dev_set_drvdata(dev, oud);
294 oud->minor = minor; 425 oud->minor = minor;
295 426
@@ -327,18 +458,25 @@ static int osd_probe(struct device *dev)
327 OSD_ERR("cdev_add failed\n"); 458 OSD_ERR("cdev_add failed\n");
328 goto err_put_disk; 459 goto err_put_disk;
329 } 460 }
330 kobject_get(&oud->cdev.kobj); /* 2nd ref see osd_remove() */ 461
331 462 /* class device member */
332 /* class_member */ 463 oud->class_dev.devt = oud->cdev.dev;
333 oud->class_member = device_create(osd_sysfs_class, dev, 464 oud->class_dev.class = &osd_uld_class;
334 MKDEV(SCSI_OSD_MAJOR, oud->minor), "%s", disk->disk_name); 465 oud->class_dev.parent = dev;
335 if (IS_ERR(oud->class_member)) { 466 oud->class_dev.release = __remove;
336 OSD_ERR("class_device_create failed\n"); 467 error = dev_set_name(&oud->class_dev, disk->disk_name);
337 error = PTR_ERR(oud->class_member); 468 if (error) {
469 OSD_ERR("dev_set_name failed => %d\n", error);
470 goto err_put_cdev;
471 }
472
473 error = device_register(&oud->class_dev);
474 if (error) {
475 OSD_ERR("device_register failed => %d\n", error);
338 goto err_put_cdev; 476 goto err_put_cdev;
339 } 477 }
340 478
341 dev_set_drvdata(oud->class_member, oud); 479 get_device(&oud->class_dev);
342 480
343 OSD_INFO("osd_probe %s\n", disk->disk_name); 481 OSD_INFO("osd_probe %s\n", disk->disk_name);
344 return 0; 482 return 0;
@@ -367,54 +505,12 @@ static int osd_remove(struct device *dev)
367 scsi_device); 505 scsi_device);
368 } 506 }
369 507
370 if (oud->class_member) 508 device_unregister(&oud->class_dev);
371 device_destroy(osd_sysfs_class,
372 MKDEV(SCSI_OSD_MAJOR, oud->minor));
373 509
374 /* We have 2 references to the cdev. One is released here 510 put_device(&oud->class_dev);
375 * and also takes down the /dev/osdX mapping. The second
376 * Will be released in __remove() after all users have released
377 * the osd_uld_device.
378 */
379 if (oud->cdev.owner)
380 cdev_del(&oud->cdev);
381
382 __uld_put(oud);
383 return 0; 511 return 0;
384} 512}
385 513
386static void __remove(struct kref *kref)
387{
388 struct osd_uld_device *oud = container_of(kref,
389 struct osd_uld_device, kref);
390 struct scsi_device *scsi_device = oud->od.scsi_device;
391
392 /* now let delete the char_dev */
393 kobject_put(&oud->cdev.kobj);
394
395 osd_dev_fini(&oud->od);
396 scsi_device_put(scsi_device);
397
398 OSD_INFO("osd_remove %s\n",
399 oud->disk ? oud->disk->disk_name : NULL);
400
401 if (oud->disk)
402 put_disk(oud->disk);
403
404 ida_remove(&osd_minor_ida, oud->minor);
405 kfree(oud);
406}
407
408static void __uld_get(struct osd_uld_device *oud)
409{
410 kref_get(&oud->kref);
411}
412
413static void __uld_put(struct osd_uld_device *oud)
414{
415 kref_put(&oud->kref, __remove);
416}
417
418/* 514/*
419 * Global driver and scsi registration 515 * Global driver and scsi registration
420 */ 516 */
@@ -432,11 +528,10 @@ static int __init osd_uld_init(void)
432{ 528{
433 int err; 529 int err;
434 530
435 osd_sysfs_class = class_create(THIS_MODULE, osd_symlink); 531 err = class_register(&osd_uld_class);
436 if (IS_ERR(osd_sysfs_class)) { 532 if (err) {
437 OSD_ERR("Unable to register sysfs class => %ld\n", 533 OSD_ERR("Unable to register sysfs class => %d\n", err);
438 PTR_ERR(osd_sysfs_class)); 534 return err;
439 return PTR_ERR(osd_sysfs_class);
440 } 535 }
441 536
442 err = register_chrdev_region(MKDEV(SCSI_OSD_MAJOR, 0), 537 err = register_chrdev_region(MKDEV(SCSI_OSD_MAJOR, 0),
@@ -459,7 +554,7 @@ static int __init osd_uld_init(void)
459err_out_chrdev: 554err_out_chrdev:
460 unregister_chrdev_region(MKDEV(SCSI_OSD_MAJOR, 0), SCSI_OSD_MAX_MINOR); 555 unregister_chrdev_region(MKDEV(SCSI_OSD_MAJOR, 0), SCSI_OSD_MAX_MINOR);
461err_out: 556err_out:
462 class_destroy(osd_sysfs_class); 557 class_unregister(&osd_uld_class);
463 return err; 558 return err;
464} 559}
465 560
@@ -467,7 +562,7 @@ static void __exit osd_uld_exit(void)
467{ 562{
468 scsi_unregister_driver(&osd_driver.gendrv); 563 scsi_unregister_driver(&osd_driver.gendrv);
469 unregister_chrdev_region(MKDEV(SCSI_OSD_MAJOR, 0), SCSI_OSD_MAX_MINOR); 564 unregister_chrdev_region(MKDEV(SCSI_OSD_MAJOR, 0), SCSI_OSD_MAX_MINOR);
470 class_destroy(osd_sysfs_class); 565 class_unregister(&osd_uld_class);
471 OSD_INFO("UNLOADED %s\n", osd_version_string); 566 OSD_INFO("UNLOADED %s\n", osd_version_string);
472} 567}
473 568