Print this page
NEX-20098 idm_refcnt_unref_task() fails to hold mutex before calling REFCNT_AUDIT
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-9981 Deadman timer panic from idm_refcnt_wait_ref thread while offlining iSCSI targets
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
NEX-6018 Return of the walking dead idm_refcnt_wait_ref comstar threads
Reviewed by:  Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by:  Evan Layton <evan.layton@nexenta.com>


   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)