3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 #include <sys/cpuvar.h>
26 #include <sys/conf.h>
27 #include <sys/file.h>
28 #include <sys/ddi.h>
29 #include <sys/sunddi.h>
30 #include <sys/modctl.h>
31
32 #include <sys/socket.h>
33 #include <sys/strsubr.h>
34 #include <sys/sysmacros.h>
35
36 #include <sys/socketvar.h>
37 #include <netinet/in.h>
38
39 #include <sys/idm/idm.h>
40 #include <sys/idm/idm_so.h>
41
42 #define IDM_NAME_VERSION "iSCSI Data Mover"
44 extern struct mod_ops mod_miscops;
45 extern struct mod_ops mod_miscops;
46
47 static struct modlmisc modlmisc = {
48 &mod_miscops, /* Type of module */
49 IDM_NAME_VERSION
50 };
51
52 static struct modlinkage modlinkage = {
53 MODREV_1, (void *)&modlmisc, NULL
54 };
55
56 extern void idm_wd_thread(void *arg);
57
58 static int _idm_init(void);
59 static int _idm_fini(void);
60 static void idm_buf_bind_in_locked(idm_task_t *idt, idm_buf_t *buf);
61 static void idm_buf_bind_out_locked(idm_task_t *idt, idm_buf_t *buf);
62 static void idm_buf_unbind_in_locked(idm_task_t *idt, idm_buf_t *buf);
63 static void idm_buf_unbind_out_locked(idm_task_t *idt, idm_buf_t *buf);
64 static void idm_task_abort_one(idm_conn_t *ic, idm_task_t *idt,
65 idm_abort_type_t abort_type);
66 static void idm_task_aborted(idm_task_t *idt, idm_status_t status);
67 static idm_pdu_t *idm_pdu_alloc_common(uint_t hdrlen, uint_t datalen,
68 int sleepflag);
69
70 boolean_t idm_conn_logging = 0;
71 boolean_t idm_svc_logging = 0;
72 #ifdef DEBUG
73 boolean_t idm_pattern_checking = 1;
74 #else
75 boolean_t idm_pattern_checking = 0;
76 #endif
77
78 /*
79 * Potential tuneable for the maximum number of tasks. Default to
80 * IDM_TASKIDS_MAX
81 */
82
83 uint32_t idm_max_taskids = IDM_TASKIDS_MAX;
84
1505 rw_exit(&idm.idm_taskid_table_lock);
1506
1507 if ((idt == NULL) || (idx == idm.idm_taskid_max))
1508 return (NULL);
1509
1510 return (idt->idt_private);
1511 }
1512
1513 void
1514 idm_task_hold(idm_task_t *idt)
1515 {
1516 idm_refcnt_hold(&idt->idt_refcnt);
1517 }
1518
1519 void
1520 idm_task_rele(idm_task_t *idt)
1521 {
1522 idm_refcnt_rele(&idt->idt_refcnt);
1523 }
1524
1525 void
1526 idm_task_abort(idm_conn_t *ic, idm_task_t *idt, idm_abort_type_t abort_type)
1527 {
1528 idm_task_t *task;
1529 int idx;
1530
1531 /*
1532 * Passing NULL as the task indicates that all tasks
1533 * for this connection should be aborted.
1534 */
1535 if (idt == NULL) {
1536 /*
1537 * Only the connection state machine should ask for
1538 * all tasks to abort and this should never happen in FFP.
1539 */
1540 ASSERT(!ic->ic_ffp);
1541 rw_enter(&idm.idm_taskid_table_lock, RW_READER);
1542 for (idx = 0; idx < idm.idm_taskid_max; idx++) {
1543 task = idm.idm_taskid_table[idx];
1544 if (task == NULL)
1545 continue;
1546 mutex_enter(&task->idt_mutex);
1547 if ((task->idt_state != TASK_IDLE) &&
1548 (task->idt_state != TASK_COMPLETE) &&
1549 (task->idt_ic == ic)) {
1550 rw_exit(&idm.idm_taskid_table_lock);
1551 idm_task_abort_one(ic, task, abort_type);
1552 rw_enter(&idm.idm_taskid_table_lock, RW_READER);
1553 } else
1554 mutex_exit(&task->idt_mutex);
1555 }
1556 rw_exit(&idm.idm_taskid_table_lock);
1557 } else {
1558 mutex_enter(&idt->idt_mutex);
1559 idm_task_abort_one(ic, idt, abort_type);
1560 }
1561 }
1562
1563 static void
1564 idm_task_abort_unref_cb(void *ref)
1565 {
1566 idm_task_t *idt = ref;
1567
1568 mutex_enter(&idt->idt_mutex);
1569 switch (idt->idt_state) {
1570 case TASK_SUSPENDING:
1571 idt->idt_state = TASK_SUSPENDED;
1572 mutex_exit(&idt->idt_mutex);
1573 idm_task_aborted(idt, IDM_STATUS_SUSPENDED);
1574 return;
1575 case TASK_ABORTING:
1576 idt->idt_state = TASK_ABORTED;
1577 mutex_exit(&idt->idt_mutex);
1578 idm_task_aborted(idt, IDM_STATUS_ABORTED);
1579 return;
1580 default:
1581 mutex_exit(&idt->idt_mutex);
1582 ASSERT(0);
1583 break;
1584 }
1585 }
1586
1587 /*
1588 * Abort the idm task.
1589 * Caller must hold the task mutex, which will be released before return
1590 */
1591 static void
1592 idm_task_abort_one(idm_conn_t *ic, idm_task_t *idt, idm_abort_type_t abort_type)
1593 {
1594 /* Caller must hold connection mutex */
1595 ASSERT(mutex_owned(&idt->idt_mutex));
1596 switch (idt->idt_state) {
1597 case TASK_ACTIVE:
1598 switch (abort_type) {
1599 case AT_INTERNAL_SUSPEND:
1600 /* Call transport to release any resources */
1601 idt->idt_state = TASK_SUSPENDING;
1602 mutex_exit(&idt->idt_mutex);
1603 ic->ic_transport_ops->it_free_task_rsrc(idt);
1604
1605 /*
1606 * Wait for outstanding references. When all
1607 * references are released the callback will call
1608 * idm_task_aborted().
1609 */
1610 idm_refcnt_async_wait_ref(&idt->idt_refcnt,
1611 &idm_task_abort_unref_cb);
1612 return;
1613 case AT_INTERNAL_ABORT:
1614 case AT_TASK_MGMT_ABORT:
1615 idt->idt_state = TASK_ABORTING;
1616 mutex_exit(&idt->idt_mutex);
1617 ic->ic_transport_ops->it_free_task_rsrc(idt);
1618
1619 /*
1620 * Wait for outstanding references. When all
1621 * references are released the callback will call
1622 * idm_task_aborted().
1623 */
1624 idm_refcnt_async_wait_ref(&idt->idt_refcnt,
1625 &idm_task_abort_unref_cb);
1626 return;
1627 default:
1628 ASSERT(0);
1629 }
1630 break;
1631 case TASK_SUSPENDING:
1632 /* Already called transport_free_task_rsrc(); */
1633 switch (abort_type) {
1634 case AT_INTERNAL_SUSPEND:
1635 /* Already doing it */
1636 break;
1637 case AT_INTERNAL_ABORT:
1638 case AT_TASK_MGMT_ABORT:
1639 idt->idt_state = TASK_ABORTING;
1640 break;
1641 default:
1642 ASSERT(0);
1643 }
1644 break;
1645 case TASK_SUSPENDED:
1646 /* Already called transport_free_task_rsrc(); */
1647 switch (abort_type) {
1648 case AT_INTERNAL_SUSPEND:
1649 /* Already doing it */
1650 break;
1651 case AT_INTERNAL_ABORT:
1652 case AT_TASK_MGMT_ABORT:
1653 idt->idt_state = TASK_ABORTING;
1654 mutex_exit(&idt->idt_mutex);
1655
1656 /*
1657 * We could probably call idm_task_aborted directly
1658 * here but we may be holding the conn lock. It's
1659 * easier to just switch contexts. Even though
1660 * we shouldn't really have any references we'll
1661 * set the state to TASK_ABORTING instead of
1662 * TASK_ABORTED so we can use the same code path.
1663 */
1664 idm_refcnt_async_wait_ref(&idt->idt_refcnt,
1665 &idm_task_abort_unref_cb);
1666 return;
1667 default:
1668 ASSERT(0);
1669 }
1670 break;
1671 case TASK_ABORTING:
1672 case TASK_ABORTED:
1673 switch (abort_type) {
1674 case AT_INTERNAL_SUSPEND:
1675 /* We're already past this point... */
1676 case AT_INTERNAL_ABORT:
1677 case AT_TASK_MGMT_ABORT:
1678 /* Already doing it */
1679 break;
1680 default:
1681 ASSERT(0);
1682 }
1683 break;
1684 case TASK_COMPLETE:
1685 /*
1686 * In this case, let it go. The status has already been
1687 * sent (which may or may not get successfully transmitted)
1688 * and we don't want to end up in a race between completing
1689 * the status PDU and marking the task suspended.
1690 */
1691 break;
1692 default:
1693 ASSERT(0);
1694 }
1695 mutex_exit(&idt->idt_mutex);
1696 }
1697
1698 static void
1699 idm_task_aborted(idm_task_t *idt, idm_status_t status)
1700 {
1701 (*idt->idt_ic->ic_conn_ops.icb_task_aborted)(idt, status);
1702 }
1703
1704 /*
1705 * idm_pdu_tx
1706 *
1707 * This is IDM's implementation of the 'Send_Control' operational primitive.
1708 * This function is invoked by an initiator iSCSI layer requesting the transfer
1709 * of a iSCSI command PDU or a target iSCSI layer requesting the transfer of a
1710 * iSCSI response PDU. The PDU will be transmitted as-is by the local Datamover
1711 * layer to the peer iSCSI layer in the remote iSCSI node. The connection info
1712 * and iSCSI PDU-specific qualifiers namely BHS, AHS, DataDescriptor and Size
1713 * are provided as input.
1714 *
1715 */
2138 void
2139 idm_refcnt_hold(idm_refcnt_t *refcnt)
2140 {
2141 /*
2142 * Nothing should take a hold on an object after a call to
2143 * idm_refcnt_wait_ref or idm_refcnd_async_wait_ref
2144 */
2145 ASSERT(refcnt->ir_waiting == REF_NOWAIT);
2146
2147 mutex_enter(&refcnt->ir_mutex);
2148 refcnt->ir_refcnt++;
2149 REFCNT_AUDIT(refcnt);
2150 mutex_exit(&refcnt->ir_mutex);
2151 }
2152
2153 static void
2154 idm_refcnt_unref_task(void *refcnt_void)
2155 {
2156 idm_refcnt_t *refcnt = refcnt_void;
2157
2158 REFCNT_AUDIT(refcnt);
2159 (*refcnt->ir_cb)(refcnt->ir_referenced_obj);
2160 }
2161
2162 void
2163 idm_refcnt_rele(idm_refcnt_t *refcnt)
2164 {
2165 mutex_enter(&refcnt->ir_mutex);
2166 ASSERT(refcnt->ir_refcnt > 0);
2167 refcnt->ir_refcnt--;
2168 REFCNT_AUDIT(refcnt);
2169 if (refcnt->ir_waiting == REF_NOWAIT) {
2170 /* No one is waiting on this object */
2171 mutex_exit(&refcnt->ir_mutex);
2172 return;
2173 }
2174
2175 /*
2176 * Someone is waiting for this object to go idle so check if
2177 * refcnt is 0. Waiting on an object then later grabbing another
2178 * reference is not allowed so we don't need to handle that case.
2246 "idm_refcnt_async_wait_ref: "
2247 "Couldn't dispatch task");
2248 }
2249 }
2250 mutex_exit(&refcnt->ir_mutex);
2251 }
2252
2253 void
2254 idm_refcnt_destroy_unref_obj(idm_refcnt_t *refcnt,
2255 idm_refcnt_cb_t *cb_func)
2256 {
2257 mutex_enter(&refcnt->ir_mutex);
2258 if (refcnt->ir_refcnt == 0) {
2259 mutex_exit(&refcnt->ir_mutex);
2260 (*cb_func)(refcnt->ir_referenced_obj);
2261 return;
2262 }
2263 mutex_exit(&refcnt->ir_mutex);
2264 }
2265
2266 void
2267 idm_conn_hold(idm_conn_t *ic)
2268 {
2269 idm_refcnt_hold(&ic->ic_refcnt);
2270 }
2271
2272 void
2273 idm_conn_rele(idm_conn_t *ic)
2274 {
2275 idm_refcnt_rele(&ic->ic_refcnt);
2276 }
2277
2278 void
2279 idm_conn_set_target_name(idm_conn_t *ic, char *target_name)
2280 {
2281 (void) strlcpy(ic->ic_target_name, target_name, ISCSI_MAX_NAME_LEN + 1);
2282 }
2283
2284 void
2285 idm_conn_set_initiator_name(idm_conn_t *ic, char *initiator_name)
|
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2019 Nexenta Systems, Inc. All rights reserved.
24 */
25
26 #include <sys/cpuvar.h>
27 #include <sys/conf.h>
28 #include <sys/file.h>
29 #include <sys/ddi.h>
30 #include <sys/sunddi.h>
31 #include <sys/modctl.h>
32
33 #include <sys/socket.h>
34 #include <sys/strsubr.h>
35 #include <sys/sysmacros.h>
36
37 #include <sys/socketvar.h>
38 #include <netinet/in.h>
39
40 #include <sys/idm/idm.h>
41 #include <sys/idm/idm_so.h>
42
43 #define IDM_NAME_VERSION "iSCSI Data Mover"
45 extern struct mod_ops mod_miscops;
46 extern struct mod_ops mod_miscops;
47
48 static struct modlmisc modlmisc = {
49 &mod_miscops, /* Type of module */
50 IDM_NAME_VERSION
51 };
52
53 static struct modlinkage modlinkage = {
54 MODREV_1, (void *)&modlmisc, NULL
55 };
56
57 extern void idm_wd_thread(void *arg);
58
59 static int _idm_init(void);
60 static int _idm_fini(void);
61 static void idm_buf_bind_in_locked(idm_task_t *idt, idm_buf_t *buf);
62 static void idm_buf_bind_out_locked(idm_task_t *idt, idm_buf_t *buf);
63 static void idm_buf_unbind_in_locked(idm_task_t *idt, idm_buf_t *buf);
64 static void idm_buf_unbind_out_locked(idm_task_t *idt, idm_buf_t *buf);
65 static stmf_status_t idm_task_abort_one(idm_conn_t *ic, idm_task_t *idt,
66 idm_abort_type_t abort_type);
67 static void idm_task_aborted(idm_task_t *idt, idm_status_t status);
68 static idm_pdu_t *idm_pdu_alloc_common(uint_t hdrlen, uint_t datalen,
69 int sleepflag);
70
71 boolean_t idm_conn_logging = 0;
72 boolean_t idm_svc_logging = 0;
73 #ifdef DEBUG
74 boolean_t idm_pattern_checking = 1;
75 #else
76 boolean_t idm_pattern_checking = 0;
77 #endif
78
79 /*
80 * Potential tuneable for the maximum number of tasks. Default to
81 * IDM_TASKIDS_MAX
82 */
83
84 uint32_t idm_max_taskids = IDM_TASKIDS_MAX;
85
1506 rw_exit(&idm.idm_taskid_table_lock);
1507
1508 if ((idt == NULL) || (idx == idm.idm_taskid_max))
1509 return (NULL);
1510
1511 return (idt->idt_private);
1512 }
1513
1514 void
1515 idm_task_hold(idm_task_t *idt)
1516 {
1517 idm_refcnt_hold(&idt->idt_refcnt);
1518 }
1519
1520 void
1521 idm_task_rele(idm_task_t *idt)
1522 {
1523 idm_refcnt_rele(&idt->idt_refcnt);
1524 }
1525
1526 stmf_status_t
1527 idm_task_abort(idm_conn_t *ic, idm_task_t *idt, idm_abort_type_t abort_type)
1528 {
1529 idm_task_t *task;
1530 int idx;
1531 stmf_status_t s = STMF_SUCCESS;
1532
1533 /*
1534 * Passing NULL as the task indicates that all tasks
1535 * for this connection should be aborted.
1536 */
1537 if (idt == NULL) {
1538 /*
1539 * Only the connection state machine should ask for
1540 * all tasks to abort and this should never happen in FFP.
1541 */
1542 ASSERT(!ic->ic_ffp);
1543 rw_enter(&idm.idm_taskid_table_lock, RW_READER);
1544 for (idx = 0; idx < idm.idm_taskid_max; idx++) {
1545 task = idm.idm_taskid_table[idx];
1546 if (task == NULL)
1547 continue;
1548 mutex_enter(&task->idt_mutex);
1549 if ((task->idt_state != TASK_IDLE) &&
1550 (task->idt_state != TASK_COMPLETE) &&
1551 (task->idt_ic == ic)) {
1552 rw_exit(&idm.idm_taskid_table_lock);
1553 s = idm_task_abort_one(ic, task, abort_type);
1554 rw_enter(&idm.idm_taskid_table_lock, RW_READER);
1555 } else
1556 mutex_exit(&task->idt_mutex);
1557 }
1558 rw_exit(&idm.idm_taskid_table_lock);
1559 } else {
1560 mutex_enter(&idt->idt_mutex);
1561 s = idm_task_abort_one(ic, idt, abort_type);
1562 }
1563 return (s);
1564 }
1565
1566 static void
1567 idm_task_abort_unref_cb(void *ref)
1568 {
1569 idm_task_t *idt = ref;
1570
1571 mutex_enter(&idt->idt_mutex);
1572 switch (idt->idt_state) {
1573 case TASK_SUSPENDING:
1574 idt->idt_state = TASK_SUSPENDED;
1575 mutex_exit(&idt->idt_mutex);
1576 idm_task_aborted(idt, IDM_STATUS_SUSPENDED);
1577 return;
1578 case TASK_ABORTING:
1579 idt->idt_state = TASK_ABORTED;
1580 mutex_exit(&idt->idt_mutex);
1581 idm_task_aborted(idt, IDM_STATUS_ABORTED);
1582 return;
1583 default:
1584 mutex_exit(&idt->idt_mutex);
1585 ASSERT(0);
1586 break;
1587 }
1588 }
1589
1590 /*
1591 * Abort the idm task.
1592 * Caller must hold the task mutex, which will be released before return
1593 */
1594 static stmf_status_t
1595 idm_task_abort_one(idm_conn_t *ic, idm_task_t *idt, idm_abort_type_t abort_type)
1596 {
1597 stmf_status_t s = STMF_SUCCESS;
1598
1599 /* Caller must hold connection mutex */
1600 ASSERT(mutex_owned(&idt->idt_mutex));
1601 switch (idt->idt_state) {
1602 case TASK_ACTIVE:
1603 switch (abort_type) {
1604 case AT_INTERNAL_SUSPEND:
1605 /* Call transport to release any resources */
1606 idt->idt_state = TASK_SUSPENDING;
1607 mutex_exit(&idt->idt_mutex);
1608 ic->ic_transport_ops->it_free_task_rsrc(idt);
1609
1610 /*
1611 * Wait for outstanding references. When all
1612 * references are released the callback will call
1613 * idm_task_aborted().
1614 */
1615 idm_refcnt_async_wait_ref(&idt->idt_refcnt,
1616 &idm_task_abort_unref_cb);
1617 return (s);
1618 case AT_INTERNAL_ABORT:
1619 case AT_TASK_MGMT_ABORT:
1620 idt->idt_state = TASK_ABORTING;
1621 mutex_exit(&idt->idt_mutex);
1622 ic->ic_transport_ops->it_free_task_rsrc(idt);
1623
1624 /*
1625 * Wait for outstanding references. When all
1626 * references are released the callback will call
1627 * idm_task_aborted().
1628 */
1629 idm_refcnt_async_wait_ref(&idt->idt_refcnt,
1630 &idm_task_abort_unref_cb);
1631 return (s);
1632 default:
1633 ASSERT(0);
1634 }
1635 break;
1636 case TASK_SUSPENDING:
1637 /* Already called transport_free_task_rsrc(); */
1638 switch (abort_type) {
1639 case AT_INTERNAL_SUSPEND:
1640 /* Already doing it */
1641 break;
1642 case AT_INTERNAL_ABORT:
1643 case AT_TASK_MGMT_ABORT:
1644 idt->idt_state = TASK_ABORTING;
1645 break;
1646 default:
1647 ASSERT(0);
1648 }
1649 break;
1650 case TASK_SUSPENDED:
1651 /* Already called transport_free_task_rsrc(); */
1652 switch (abort_type) {
1653 case AT_INTERNAL_SUSPEND:
1654 /* Already doing it */
1655 break;
1656 case AT_INTERNAL_ABORT:
1657 case AT_TASK_MGMT_ABORT:
1658 idt->idt_state = TASK_ABORTING;
1659 mutex_exit(&idt->idt_mutex);
1660
1661 /*
1662 * We could probably call idm_task_aborted directly
1663 * here but we may be holding the conn lock. It's
1664 * easier to just switch contexts. Even though
1665 * we shouldn't really have any references we'll
1666 * set the state to TASK_ABORTING instead of
1667 * TASK_ABORTED so we can use the same code path.
1668 */
1669 idm_refcnt_async_wait_ref(&idt->idt_refcnt,
1670 &idm_task_abort_unref_cb);
1671 return (s);
1672 default:
1673 ASSERT(0);
1674 }
1675 break;
1676 case TASK_ABORTING:
1677 case TASK_ABORTED:
1678 switch (abort_type) {
1679 case AT_INTERNAL_SUSPEND:
1680 /* We're already past this point... */
1681 case AT_INTERNAL_ABORT:
1682 case AT_TASK_MGMT_ABORT:
1683 /* Already doing it */
1684 break;
1685 default:
1686 ASSERT(0);
1687 }
1688 break;
1689 case TASK_COMPLETE:
1690 idm_refcnt_wait_ref(&idt->idt_refcnt);
1691 s = STMF_ABORT_SUCCESS;
1692 break;
1693 default:
1694 ASSERT(0);
1695 }
1696 mutex_exit(&idt->idt_mutex);
1697
1698 return (s);
1699 }
1700
1701 static void
1702 idm_task_aborted(idm_task_t *idt, idm_status_t status)
1703 {
1704 (*idt->idt_ic->ic_conn_ops.icb_task_aborted)(idt, status);
1705 }
1706
1707 /*
1708 * idm_pdu_tx
1709 *
1710 * This is IDM's implementation of the 'Send_Control' operational primitive.
1711 * This function is invoked by an initiator iSCSI layer requesting the transfer
1712 * of a iSCSI command PDU or a target iSCSI layer requesting the transfer of a
1713 * iSCSI response PDU. The PDU will be transmitted as-is by the local Datamover
1714 * layer to the peer iSCSI layer in the remote iSCSI node. The connection info
1715 * and iSCSI PDU-specific qualifiers namely BHS, AHS, DataDescriptor and Size
1716 * are provided as input.
1717 *
1718 */
2141 void
2142 idm_refcnt_hold(idm_refcnt_t *refcnt)
2143 {
2144 /*
2145 * Nothing should take a hold on an object after a call to
2146 * idm_refcnt_wait_ref or idm_refcnd_async_wait_ref
2147 */
2148 ASSERT(refcnt->ir_waiting == REF_NOWAIT);
2149
2150 mutex_enter(&refcnt->ir_mutex);
2151 refcnt->ir_refcnt++;
2152 REFCNT_AUDIT(refcnt);
2153 mutex_exit(&refcnt->ir_mutex);
2154 }
2155
2156 static void
2157 idm_refcnt_unref_task(void *refcnt_void)
2158 {
2159 idm_refcnt_t *refcnt = refcnt_void;
2160
2161 mutex_enter(&refcnt->ir_mutex);
2162 REFCNT_AUDIT(refcnt);
2163 mutex_exit(&refcnt->ir_mutex);
2164 (*refcnt->ir_cb)(refcnt->ir_referenced_obj);
2165 }
2166
2167 void
2168 idm_refcnt_rele(idm_refcnt_t *refcnt)
2169 {
2170 mutex_enter(&refcnt->ir_mutex);
2171 ASSERT(refcnt->ir_refcnt > 0);
2172 refcnt->ir_refcnt--;
2173 REFCNT_AUDIT(refcnt);
2174 if (refcnt->ir_waiting == REF_NOWAIT) {
2175 /* No one is waiting on this object */
2176 mutex_exit(&refcnt->ir_mutex);
2177 return;
2178 }
2179
2180 /*
2181 * Someone is waiting for this object to go idle so check if
2182 * refcnt is 0. Waiting on an object then later grabbing another
2183 * reference is not allowed so we don't need to handle that case.
2251 "idm_refcnt_async_wait_ref: "
2252 "Couldn't dispatch task");
2253 }
2254 }
2255 mutex_exit(&refcnt->ir_mutex);
2256 }
2257
2258 void
2259 idm_refcnt_destroy_unref_obj(idm_refcnt_t *refcnt,
2260 idm_refcnt_cb_t *cb_func)
2261 {
2262 mutex_enter(&refcnt->ir_mutex);
2263 if (refcnt->ir_refcnt == 0) {
2264 mutex_exit(&refcnt->ir_mutex);
2265 (*cb_func)(refcnt->ir_referenced_obj);
2266 return;
2267 }
2268 mutex_exit(&refcnt->ir_mutex);
2269 }
2270
2271 /*
2272 * used to determine the status of the refcnt.
2273 *
2274 * if refcnt is 0 return is 0
2275 * if refcnt is negative return is -1
2276 * if refcnt > 0 and no waiters return is 1
2277 * if refcnt > 0 and waiters return is 2
2278 */
2279 int
2280 idm_refcnt_is_held(idm_refcnt_t *refcnt)
2281 {
2282 if (refcnt->ir_refcnt < 0)
2283 return (-1);
2284
2285 if (refcnt->ir_refcnt == 0)
2286 return (0);
2287
2288 if (refcnt->ir_waiting == REF_NOWAIT && refcnt->ir_refcnt > 0)
2289 return (1);
2290
2291 return (2);
2292 }
2293
2294 void
2295 idm_conn_hold(idm_conn_t *ic)
2296 {
2297 idm_refcnt_hold(&ic->ic_refcnt);
2298 }
2299
2300 void
2301 idm_conn_rele(idm_conn_t *ic)
2302 {
2303 idm_refcnt_rele(&ic->ic_refcnt);
2304 }
2305
2306 void
2307 idm_conn_set_target_name(idm_conn_t *ic, char *target_name)
2308 {
2309 (void) strlcpy(ic->ic_target_name, target_name, ISCSI_MAX_NAME_LEN + 1);
2310 }
2311
2312 void
2313 idm_conn_set_initiator_name(idm_conn_t *ic, char *initiator_name)
|