17978SPeter.Dunlap@Sun.COM /*
27978SPeter.Dunlap@Sun.COM * CDDL HEADER START
37978SPeter.Dunlap@Sun.COM *
47978SPeter.Dunlap@Sun.COM * The contents of this file are subject to the terms of the
57978SPeter.Dunlap@Sun.COM * Common Development and Distribution License (the "License").
67978SPeter.Dunlap@Sun.COM * You may not use this file except in compliance with the License.
77978SPeter.Dunlap@Sun.COM *
87978SPeter.Dunlap@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97978SPeter.Dunlap@Sun.COM * or http://www.opensolaris.org/os/licensing.
107978SPeter.Dunlap@Sun.COM * See the License for the specific language governing permissions
117978SPeter.Dunlap@Sun.COM * and limitations under the License.
127978SPeter.Dunlap@Sun.COM *
137978SPeter.Dunlap@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
147978SPeter.Dunlap@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157978SPeter.Dunlap@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
167978SPeter.Dunlap@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
177978SPeter.Dunlap@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
187978SPeter.Dunlap@Sun.COM *
197978SPeter.Dunlap@Sun.COM * CDDL HEADER END
207978SPeter.Dunlap@Sun.COM */
217978SPeter.Dunlap@Sun.COM /*
22*12372SPriya.Krishnan@Sun.COM * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
237978SPeter.Dunlap@Sun.COM */
247978SPeter.Dunlap@Sun.COM
257978SPeter.Dunlap@Sun.COM #include <sys/cpuvar.h>
267978SPeter.Dunlap@Sun.COM #include <sys/conf.h>
277978SPeter.Dunlap@Sun.COM #include <sys/file.h>
287978SPeter.Dunlap@Sun.COM #include <sys/ddi.h>
297978SPeter.Dunlap@Sun.COM #include <sys/sunddi.h>
307978SPeter.Dunlap@Sun.COM #include <sys/modctl.h>
317978SPeter.Dunlap@Sun.COM
327978SPeter.Dunlap@Sun.COM #include <sys/socket.h>
337978SPeter.Dunlap@Sun.COM #include <sys/strsubr.h>
347978SPeter.Dunlap@Sun.COM #include <sys/sysmacros.h>
357978SPeter.Dunlap@Sun.COM
367978SPeter.Dunlap@Sun.COM #include <sys/socketvar.h>
377978SPeter.Dunlap@Sun.COM #include <netinet/in.h>
387978SPeter.Dunlap@Sun.COM
397978SPeter.Dunlap@Sun.COM #include <sys/idm/idm.h>
407978SPeter.Dunlap@Sun.COM #include <sys/idm/idm_so.h>
417978SPeter.Dunlap@Sun.COM
427978SPeter.Dunlap@Sun.COM #define IDM_NAME_VERSION "iSCSI Data Mover"
437978SPeter.Dunlap@Sun.COM
447978SPeter.Dunlap@Sun.COM extern struct mod_ops mod_miscops;
457978SPeter.Dunlap@Sun.COM extern struct mod_ops mod_miscops;
467978SPeter.Dunlap@Sun.COM
477978SPeter.Dunlap@Sun.COM static struct modlmisc modlmisc = {
487978SPeter.Dunlap@Sun.COM &mod_miscops, /* Type of module */
497978SPeter.Dunlap@Sun.COM IDM_NAME_VERSION
507978SPeter.Dunlap@Sun.COM };
517978SPeter.Dunlap@Sun.COM
527978SPeter.Dunlap@Sun.COM static struct modlinkage modlinkage = {
537978SPeter.Dunlap@Sun.COM MODREV_1, (void *)&modlmisc, NULL
547978SPeter.Dunlap@Sun.COM };
557978SPeter.Dunlap@Sun.COM
567978SPeter.Dunlap@Sun.COM extern void idm_wd_thread(void *arg);
577978SPeter.Dunlap@Sun.COM
587978SPeter.Dunlap@Sun.COM static int _idm_init(void);
597978SPeter.Dunlap@Sun.COM static int _idm_fini(void);
607978SPeter.Dunlap@Sun.COM static void idm_buf_bind_in_locked(idm_task_t *idt, idm_buf_t *buf);
617978SPeter.Dunlap@Sun.COM static void idm_buf_bind_out_locked(idm_task_t *idt, idm_buf_t *buf);
627978SPeter.Dunlap@Sun.COM static void idm_buf_unbind_in_locked(idm_task_t *idt, idm_buf_t *buf);
637978SPeter.Dunlap@Sun.COM static void idm_buf_unbind_out_locked(idm_task_t *idt, idm_buf_t *buf);
647978SPeter.Dunlap@Sun.COM static void idm_task_abort_one(idm_conn_t *ic, idm_task_t *idt,
657978SPeter.Dunlap@Sun.COM idm_abort_type_t abort_type);
667978SPeter.Dunlap@Sun.COM static void idm_task_aborted(idm_task_t *idt, idm_status_t status);
679162SPeter.Dunlap@Sun.COM static idm_pdu_t *idm_pdu_alloc_common(uint_t hdrlen, uint_t datalen,
689162SPeter.Dunlap@Sun.COM int sleepflag);
697978SPeter.Dunlap@Sun.COM
707978SPeter.Dunlap@Sun.COM boolean_t idm_conn_logging = 0;
717978SPeter.Dunlap@Sun.COM boolean_t idm_svc_logging = 0;
729162SPeter.Dunlap@Sun.COM #ifdef DEBUG
739162SPeter.Dunlap@Sun.COM boolean_t idm_pattern_checking = 1;
749162SPeter.Dunlap@Sun.COM #else
759162SPeter.Dunlap@Sun.COM boolean_t idm_pattern_checking = 0;
769162SPeter.Dunlap@Sun.COM #endif
777978SPeter.Dunlap@Sun.COM
787978SPeter.Dunlap@Sun.COM /*
797978SPeter.Dunlap@Sun.COM * Potential tuneable for the maximum number of tasks. Default to
807978SPeter.Dunlap@Sun.COM * IDM_TASKIDS_MAX
817978SPeter.Dunlap@Sun.COM */
827978SPeter.Dunlap@Sun.COM
837978SPeter.Dunlap@Sun.COM uint32_t idm_max_taskids = IDM_TASKIDS_MAX;
847978SPeter.Dunlap@Sun.COM
857978SPeter.Dunlap@Sun.COM /*
867978SPeter.Dunlap@Sun.COM * Global list of transport handles
877978SPeter.Dunlap@Sun.COM * These are listed in preferential order, so we can simply take the
887978SPeter.Dunlap@Sun.COM * first "it_conn_is_capable" hit. Note also that the order maps to
897978SPeter.Dunlap@Sun.COM * the order of the idm_transport_type_t list.
907978SPeter.Dunlap@Sun.COM */
917978SPeter.Dunlap@Sun.COM idm_transport_t idm_transport_list[] = {
927978SPeter.Dunlap@Sun.COM
937978SPeter.Dunlap@Sun.COM /* iSER on InfiniBand transport handle */
947978SPeter.Dunlap@Sun.COM {IDM_TRANSPORT_TYPE_ISER, /* type */
957978SPeter.Dunlap@Sun.COM "/devices/ib/iser@0:iser", /* device path */
967978SPeter.Dunlap@Sun.COM NULL, /* LDI handle */
977978SPeter.Dunlap@Sun.COM NULL, /* transport ops */
987978SPeter.Dunlap@Sun.COM NULL}, /* transport caps */
997978SPeter.Dunlap@Sun.COM
1007978SPeter.Dunlap@Sun.COM /* IDM native sockets transport handle */
1017978SPeter.Dunlap@Sun.COM {IDM_TRANSPORT_TYPE_SOCKETS, /* type */
1027978SPeter.Dunlap@Sun.COM NULL, /* device path */
1037978SPeter.Dunlap@Sun.COM NULL, /* LDI handle */
1047978SPeter.Dunlap@Sun.COM NULL, /* transport ops */
1057978SPeter.Dunlap@Sun.COM NULL} /* transport caps */
1067978SPeter.Dunlap@Sun.COM
1077978SPeter.Dunlap@Sun.COM };
1087978SPeter.Dunlap@Sun.COM
1097978SPeter.Dunlap@Sun.COM int
_init(void)1107978SPeter.Dunlap@Sun.COM _init(void)
1117978SPeter.Dunlap@Sun.COM {
1127978SPeter.Dunlap@Sun.COM int rc;
1137978SPeter.Dunlap@Sun.COM
1147978SPeter.Dunlap@Sun.COM if ((rc = _idm_init()) != 0) {
1157978SPeter.Dunlap@Sun.COM return (rc);
1167978SPeter.Dunlap@Sun.COM }
1177978SPeter.Dunlap@Sun.COM
1187978SPeter.Dunlap@Sun.COM return (mod_install(&modlinkage));
1197978SPeter.Dunlap@Sun.COM }
1207978SPeter.Dunlap@Sun.COM
1217978SPeter.Dunlap@Sun.COM int
_fini(void)1227978SPeter.Dunlap@Sun.COM _fini(void)
1237978SPeter.Dunlap@Sun.COM {
1247978SPeter.Dunlap@Sun.COM int rc;
1257978SPeter.Dunlap@Sun.COM
1267978SPeter.Dunlap@Sun.COM if ((rc = _idm_fini()) != 0) {
1277978SPeter.Dunlap@Sun.COM return (rc);
1287978SPeter.Dunlap@Sun.COM }
1297978SPeter.Dunlap@Sun.COM
1307978SPeter.Dunlap@Sun.COM if ((rc = mod_remove(&modlinkage)) != 0) {
1317978SPeter.Dunlap@Sun.COM return (rc);
1327978SPeter.Dunlap@Sun.COM }
1337978SPeter.Dunlap@Sun.COM
1347978SPeter.Dunlap@Sun.COM return (rc);
1357978SPeter.Dunlap@Sun.COM }
1367978SPeter.Dunlap@Sun.COM
1377978SPeter.Dunlap@Sun.COM int
_info(struct modinfo * modinfop)1387978SPeter.Dunlap@Sun.COM _info(struct modinfo *modinfop)
1397978SPeter.Dunlap@Sun.COM {
1407978SPeter.Dunlap@Sun.COM return (mod_info(&modlinkage, modinfop));
1417978SPeter.Dunlap@Sun.COM }
1427978SPeter.Dunlap@Sun.COM
1437978SPeter.Dunlap@Sun.COM /*
1447978SPeter.Dunlap@Sun.COM * idm_transport_register()
1457978SPeter.Dunlap@Sun.COM *
1467978SPeter.Dunlap@Sun.COM * Provides a mechanism for an IDM transport driver to register its
1477978SPeter.Dunlap@Sun.COM * transport ops and caps with the IDM kernel module. Invoked during
1487978SPeter.Dunlap@Sun.COM * a transport driver's attach routine.
1497978SPeter.Dunlap@Sun.COM */
1507978SPeter.Dunlap@Sun.COM idm_status_t
idm_transport_register(idm_transport_attr_t * attr)1517978SPeter.Dunlap@Sun.COM idm_transport_register(idm_transport_attr_t *attr)
1527978SPeter.Dunlap@Sun.COM {
1537978SPeter.Dunlap@Sun.COM ASSERT(attr->it_ops != NULL);
1547978SPeter.Dunlap@Sun.COM ASSERT(attr->it_caps != NULL);
1557978SPeter.Dunlap@Sun.COM
1567978SPeter.Dunlap@Sun.COM switch (attr->type) {
1577978SPeter.Dunlap@Sun.COM /* All known non-native transports here; for now, iSER */
1587978SPeter.Dunlap@Sun.COM case IDM_TRANSPORT_TYPE_ISER:
1597978SPeter.Dunlap@Sun.COM idm_transport_list[attr->type].it_ops = attr->it_ops;
1607978SPeter.Dunlap@Sun.COM idm_transport_list[attr->type].it_caps = attr->it_caps;
1617978SPeter.Dunlap@Sun.COM return (IDM_STATUS_SUCCESS);
1627978SPeter.Dunlap@Sun.COM
1637978SPeter.Dunlap@Sun.COM default:
1647978SPeter.Dunlap@Sun.COM cmn_err(CE_NOTE, "idm: unknown transport type (0x%x) in "
1657978SPeter.Dunlap@Sun.COM "idm_transport_register", attr->type);
1667978SPeter.Dunlap@Sun.COM return (IDM_STATUS_SUCCESS);
1677978SPeter.Dunlap@Sun.COM }
1687978SPeter.Dunlap@Sun.COM }
1697978SPeter.Dunlap@Sun.COM
1707978SPeter.Dunlap@Sun.COM /*
1717978SPeter.Dunlap@Sun.COM * idm_ini_conn_create
1727978SPeter.Dunlap@Sun.COM *
1737978SPeter.Dunlap@Sun.COM * This function is invoked by the iSCSI layer to create a connection context.
1747978SPeter.Dunlap@Sun.COM * This does not actually establish the socket connection.
1757978SPeter.Dunlap@Sun.COM *
1767978SPeter.Dunlap@Sun.COM * cr - Connection request parameters
1777978SPeter.Dunlap@Sun.COM * new_con - Output parameter that contains the new request if successful
1787978SPeter.Dunlap@Sun.COM *
1797978SPeter.Dunlap@Sun.COM */
1807978SPeter.Dunlap@Sun.COM idm_status_t
idm_ini_conn_create(idm_conn_req_t * cr,idm_conn_t ** new_con)1817978SPeter.Dunlap@Sun.COM idm_ini_conn_create(idm_conn_req_t *cr, idm_conn_t **new_con)
1827978SPeter.Dunlap@Sun.COM {
1837978SPeter.Dunlap@Sun.COM idm_transport_t *it;
1847978SPeter.Dunlap@Sun.COM idm_conn_t *ic;
1857978SPeter.Dunlap@Sun.COM int rc;
1867978SPeter.Dunlap@Sun.COM
1877978SPeter.Dunlap@Sun.COM it = idm_transport_lookup(cr);
1887978SPeter.Dunlap@Sun.COM
1897978SPeter.Dunlap@Sun.COM retry:
1907978SPeter.Dunlap@Sun.COM ic = idm_conn_create_common(CONN_TYPE_INI, it->it_type,
1917978SPeter.Dunlap@Sun.COM &cr->icr_conn_ops);
1927978SPeter.Dunlap@Sun.COM
1937978SPeter.Dunlap@Sun.COM bcopy(&cr->cr_ini_dst_addr, &ic->ic_ini_dst_addr,
1947978SPeter.Dunlap@Sun.COM sizeof (cr->cr_ini_dst_addr));
1957978SPeter.Dunlap@Sun.COM
1967978SPeter.Dunlap@Sun.COM /* create the transport-specific connection components */
1977978SPeter.Dunlap@Sun.COM rc = it->it_ops->it_ini_conn_create(cr, ic);
1987978SPeter.Dunlap@Sun.COM if (rc != IDM_STATUS_SUCCESS) {
1997978SPeter.Dunlap@Sun.COM /* cleanup the failed connection */
2007978SPeter.Dunlap@Sun.COM idm_conn_destroy_common(ic);
2017978SPeter.Dunlap@Sun.COM
2027978SPeter.Dunlap@Sun.COM /*
2037978SPeter.Dunlap@Sun.COM * It is possible for an IB client to connect to
2047978SPeter.Dunlap@Sun.COM * an ethernet-only client via an IB-eth gateway.
2057978SPeter.Dunlap@Sun.COM * Therefore, if we are attempting to use iSER and
2067978SPeter.Dunlap@Sun.COM * fail, retry with sockets before ultimately
2077978SPeter.Dunlap@Sun.COM * failing the connection.
2087978SPeter.Dunlap@Sun.COM */
2097978SPeter.Dunlap@Sun.COM if (it->it_type == IDM_TRANSPORT_TYPE_ISER) {
2107978SPeter.Dunlap@Sun.COM it = &idm_transport_list[IDM_TRANSPORT_TYPE_SOCKETS];
2117978SPeter.Dunlap@Sun.COM goto retry;
2127978SPeter.Dunlap@Sun.COM }
2137978SPeter.Dunlap@Sun.COM
2147978SPeter.Dunlap@Sun.COM return (IDM_STATUS_FAIL);
2157978SPeter.Dunlap@Sun.COM }
2167978SPeter.Dunlap@Sun.COM
2177978SPeter.Dunlap@Sun.COM *new_con = ic;
2187978SPeter.Dunlap@Sun.COM
2197978SPeter.Dunlap@Sun.COM mutex_enter(&idm.idm_global_mutex);
2207978SPeter.Dunlap@Sun.COM list_insert_tail(&idm.idm_ini_conn_list, ic);
2217978SPeter.Dunlap@Sun.COM mutex_exit(&idm.idm_global_mutex);
2227978SPeter.Dunlap@Sun.COM
2237978SPeter.Dunlap@Sun.COM return (IDM_STATUS_SUCCESS);
2247978SPeter.Dunlap@Sun.COM }
2257978SPeter.Dunlap@Sun.COM
2267978SPeter.Dunlap@Sun.COM /*
2277978SPeter.Dunlap@Sun.COM * idm_ini_conn_destroy
2287978SPeter.Dunlap@Sun.COM *
2297978SPeter.Dunlap@Sun.COM * Releases any resources associated with the connection. This is the
2307978SPeter.Dunlap@Sun.COM * complement to idm_ini_conn_create.
2317978SPeter.Dunlap@Sun.COM * ic - idm_conn_t structure representing the relevant connection
2327978SPeter.Dunlap@Sun.COM *
2337978SPeter.Dunlap@Sun.COM */
2347978SPeter.Dunlap@Sun.COM void
idm_ini_conn_destroy_task(void * ic_void)2359162SPeter.Dunlap@Sun.COM idm_ini_conn_destroy_task(void *ic_void)
2369162SPeter.Dunlap@Sun.COM {
2379162SPeter.Dunlap@Sun.COM idm_conn_t *ic = ic_void;
2389162SPeter.Dunlap@Sun.COM
2399162SPeter.Dunlap@Sun.COM ic->ic_transport_ops->it_ini_conn_destroy(ic);
2409162SPeter.Dunlap@Sun.COM idm_conn_destroy_common(ic);
2419162SPeter.Dunlap@Sun.COM }
2429162SPeter.Dunlap@Sun.COM
2439162SPeter.Dunlap@Sun.COM void
idm_ini_conn_destroy(idm_conn_t * ic)2447978SPeter.Dunlap@Sun.COM idm_ini_conn_destroy(idm_conn_t *ic)
2457978SPeter.Dunlap@Sun.COM {
2469162SPeter.Dunlap@Sun.COM /*
2479162SPeter.Dunlap@Sun.COM * It's reasonable for the initiator to call idm_ini_conn_destroy
2489162SPeter.Dunlap@Sun.COM * from within the context of the CN_CONNECT_DESTROY notification.
2499162SPeter.Dunlap@Sun.COM * That's a problem since we want to destroy the taskq for the
2509162SPeter.Dunlap@Sun.COM * state machine associated with the connection. Remove the
2519162SPeter.Dunlap@Sun.COM * connection from the list right away then handle the remaining
2529162SPeter.Dunlap@Sun.COM * work via the idm_global_taskq.
2539162SPeter.Dunlap@Sun.COM */
2547978SPeter.Dunlap@Sun.COM mutex_enter(&idm.idm_global_mutex);
2557978SPeter.Dunlap@Sun.COM list_remove(&idm.idm_ini_conn_list, ic);
2567978SPeter.Dunlap@Sun.COM mutex_exit(&idm.idm_global_mutex);
2577978SPeter.Dunlap@Sun.COM
2589162SPeter.Dunlap@Sun.COM if (taskq_dispatch(idm.idm_global_taskq,
2599162SPeter.Dunlap@Sun.COM &idm_ini_conn_destroy_task, ic, TQ_SLEEP) == NULL) {
2609162SPeter.Dunlap@Sun.COM cmn_err(CE_WARN,
2619162SPeter.Dunlap@Sun.COM "idm_ini_conn_destroy: Couldn't dispatch task");
2629162SPeter.Dunlap@Sun.COM }
2637978SPeter.Dunlap@Sun.COM }
2647978SPeter.Dunlap@Sun.COM
2657978SPeter.Dunlap@Sun.COM /*
2667978SPeter.Dunlap@Sun.COM * idm_ini_conn_connect
2677978SPeter.Dunlap@Sun.COM *
2687978SPeter.Dunlap@Sun.COM * Establish connection to the remote system identified in idm_conn_t.
2697978SPeter.Dunlap@Sun.COM * The connection parameters including the remote IP address were established
2709162SPeter.Dunlap@Sun.COM * in the call to idm_ini_conn_create. The IDM state machine will
2719162SPeter.Dunlap@Sun.COM * perform client notifications as necessary to prompt the initiator through
2729162SPeter.Dunlap@Sun.COM * the login process. IDM also keeps a timer running so that if the login
2739162SPeter.Dunlap@Sun.COM * process doesn't complete in a timely manner it will fail.
2747978SPeter.Dunlap@Sun.COM *
2757978SPeter.Dunlap@Sun.COM * ic - idm_conn_t structure representing the relevant connection
2767978SPeter.Dunlap@Sun.COM *
2777978SPeter.Dunlap@Sun.COM * Returns success if the connection was established, otherwise some kind
2787978SPeter.Dunlap@Sun.COM * of meaningful error code.
2797978SPeter.Dunlap@Sun.COM *
2809162SPeter.Dunlap@Sun.COM * Upon return the login has either failed or is loggin in (ffp)
2817978SPeter.Dunlap@Sun.COM */
2827978SPeter.Dunlap@Sun.COM idm_status_t
idm_ini_conn_connect(idm_conn_t * ic)2837978SPeter.Dunlap@Sun.COM idm_ini_conn_connect(idm_conn_t *ic)
2847978SPeter.Dunlap@Sun.COM {
28510766SPeter.Cudhea@Sun.COM idm_status_t rc;
2867978SPeter.Dunlap@Sun.COM
2877978SPeter.Dunlap@Sun.COM rc = idm_conn_sm_init(ic);
2887978SPeter.Dunlap@Sun.COM if (rc != IDM_STATUS_SUCCESS) {
2897978SPeter.Dunlap@Sun.COM return (ic->ic_conn_sm_status);
2907978SPeter.Dunlap@Sun.COM }
2919162SPeter.Dunlap@Sun.COM
2929162SPeter.Dunlap@Sun.COM /* Hold connection until we return */
2939162SPeter.Dunlap@Sun.COM idm_conn_hold(ic);
2949162SPeter.Dunlap@Sun.COM
2957978SPeter.Dunlap@Sun.COM /* Kick state machine */
2967978SPeter.Dunlap@Sun.COM idm_conn_event(ic, CE_CONNECT_REQ, NULL);
2977978SPeter.Dunlap@Sun.COM
2987978SPeter.Dunlap@Sun.COM /* Wait for login flag */
2997978SPeter.Dunlap@Sun.COM mutex_enter(&ic->ic_state_mutex);
3007978SPeter.Dunlap@Sun.COM while (!(ic->ic_state_flags & CF_LOGIN_READY) &&
3017978SPeter.Dunlap@Sun.COM !(ic->ic_state_flags & CF_ERROR)) {
3027978SPeter.Dunlap@Sun.COM cv_wait(&ic->ic_state_cv, &ic->ic_state_mutex);
3037978SPeter.Dunlap@Sun.COM }
3047978SPeter.Dunlap@Sun.COM
30510766SPeter.Cudhea@Sun.COM /*
30610766SPeter.Cudhea@Sun.COM * The CN_READY_TO_LOGIN and/or the CN_CONNECT_FAIL call to
30710766SPeter.Cudhea@Sun.COM * idm_notify_client has already been generated by the idm conn
30810766SPeter.Cudhea@Sun.COM * state machine. If connection fails any time after this
30910766SPeter.Cudhea@Sun.COM * check, we will detect it in iscsi_login.
31010766SPeter.Cudhea@Sun.COM */
3117978SPeter.Dunlap@Sun.COM if (ic->ic_state_flags & CF_ERROR) {
31210766SPeter.Cudhea@Sun.COM rc = ic->ic_conn_sm_status;
3137978SPeter.Dunlap@Sun.COM }
31410766SPeter.Cudhea@Sun.COM mutex_exit(&ic->ic_state_mutex);
3159162SPeter.Dunlap@Sun.COM idm_conn_rele(ic);
3167978SPeter.Dunlap@Sun.COM
3179162SPeter.Dunlap@Sun.COM return (rc);
3187978SPeter.Dunlap@Sun.COM }
3197978SPeter.Dunlap@Sun.COM
3207978SPeter.Dunlap@Sun.COM /*
3217978SPeter.Dunlap@Sun.COM * idm_ini_conn_disconnect
3227978SPeter.Dunlap@Sun.COM *
3237978SPeter.Dunlap@Sun.COM * Forces a connection (previously established using idm_ini_conn_connect)
3247978SPeter.Dunlap@Sun.COM * to perform a controlled shutdown, cleaning up any outstanding requests.
3257978SPeter.Dunlap@Sun.COM *
3267978SPeter.Dunlap@Sun.COM * ic - idm_conn_t structure representing the relevant connection
3277978SPeter.Dunlap@Sun.COM *
3289162SPeter.Dunlap@Sun.COM * This is asynchronous and will return before the connection is properly
3299162SPeter.Dunlap@Sun.COM * shutdown
3307978SPeter.Dunlap@Sun.COM */
3317978SPeter.Dunlap@Sun.COM /* ARGSUSED */
3327978SPeter.Dunlap@Sun.COM void
idm_ini_conn_disconnect(idm_conn_t * ic)3337978SPeter.Dunlap@Sun.COM idm_ini_conn_disconnect(idm_conn_t *ic)
3347978SPeter.Dunlap@Sun.COM {
3359162SPeter.Dunlap@Sun.COM idm_conn_event(ic, CE_TRANSPORT_FAIL, NULL);
3369162SPeter.Dunlap@Sun.COM }
3377978SPeter.Dunlap@Sun.COM
3389162SPeter.Dunlap@Sun.COM /*
3399162SPeter.Dunlap@Sun.COM * idm_ini_conn_disconnect_wait
3409162SPeter.Dunlap@Sun.COM *
3419162SPeter.Dunlap@Sun.COM * Forces a connection (previously established using idm_ini_conn_connect)
3429162SPeter.Dunlap@Sun.COM * to perform a controlled shutdown. Blocks until the connection is
3439162SPeter.Dunlap@Sun.COM * disconnected.
3449162SPeter.Dunlap@Sun.COM *
3459162SPeter.Dunlap@Sun.COM * ic - idm_conn_t structure representing the relevant connection
3469162SPeter.Dunlap@Sun.COM */
3479162SPeter.Dunlap@Sun.COM /* ARGSUSED */
3489162SPeter.Dunlap@Sun.COM void
idm_ini_conn_disconnect_sync(idm_conn_t * ic)3499162SPeter.Dunlap@Sun.COM idm_ini_conn_disconnect_sync(idm_conn_t *ic)
3509162SPeter.Dunlap@Sun.COM {
3519162SPeter.Dunlap@Sun.COM mutex_enter(&ic->ic_state_mutex);
3529162SPeter.Dunlap@Sun.COM if ((ic->ic_state != CS_S9_INIT_ERROR) &&
3539162SPeter.Dunlap@Sun.COM (ic->ic_state != CS_S11_COMPLETE)) {
3549162SPeter.Dunlap@Sun.COM idm_conn_event_locked(ic, CE_TRANSPORT_FAIL, NULL, CT_NONE);
3559162SPeter.Dunlap@Sun.COM while ((ic->ic_state != CS_S9_INIT_ERROR) &&
3569162SPeter.Dunlap@Sun.COM (ic->ic_state != CS_S11_COMPLETE))
3579162SPeter.Dunlap@Sun.COM cv_wait(&ic->ic_state_cv, &ic->ic_state_mutex);
3587978SPeter.Dunlap@Sun.COM }
3597978SPeter.Dunlap@Sun.COM mutex_exit(&ic->ic_state_mutex);
3607978SPeter.Dunlap@Sun.COM }
3617978SPeter.Dunlap@Sun.COM
3627978SPeter.Dunlap@Sun.COM /*
3637978SPeter.Dunlap@Sun.COM * idm_tgt_svc_create
3647978SPeter.Dunlap@Sun.COM *
3657978SPeter.Dunlap@Sun.COM * The target calls this service to obtain a service context for each available
3667978SPeter.Dunlap@Sun.COM * transport, starting a service of each type related to the IP address and port
3677978SPeter.Dunlap@Sun.COM * passed. The idm_svc_req_t contains the service parameters.
3687978SPeter.Dunlap@Sun.COM */
3697978SPeter.Dunlap@Sun.COM idm_status_t
idm_tgt_svc_create(idm_svc_req_t * sr,idm_svc_t ** new_svc)3707978SPeter.Dunlap@Sun.COM idm_tgt_svc_create(idm_svc_req_t *sr, idm_svc_t **new_svc)
3717978SPeter.Dunlap@Sun.COM {
3727978SPeter.Dunlap@Sun.COM idm_transport_type_t type;
3737978SPeter.Dunlap@Sun.COM idm_transport_t *it;
3747978SPeter.Dunlap@Sun.COM idm_svc_t *is;
3757978SPeter.Dunlap@Sun.COM int rc;
3767978SPeter.Dunlap@Sun.COM
3777978SPeter.Dunlap@Sun.COM *new_svc = NULL;
3787978SPeter.Dunlap@Sun.COM is = kmem_zalloc(sizeof (idm_svc_t), KM_SLEEP);
3797978SPeter.Dunlap@Sun.COM
3807978SPeter.Dunlap@Sun.COM /* Initialize transport-agnostic components of the service handle */
3817978SPeter.Dunlap@Sun.COM is->is_svc_req = *sr;
3827978SPeter.Dunlap@Sun.COM mutex_init(&is->is_mutex, NULL, MUTEX_DEFAULT, NULL);
3837978SPeter.Dunlap@Sun.COM cv_init(&is->is_cv, NULL, CV_DEFAULT, NULL);
3847978SPeter.Dunlap@Sun.COM mutex_init(&is->is_count_mutex, NULL, MUTEX_DEFAULT, NULL);
3857978SPeter.Dunlap@Sun.COM cv_init(&is->is_count_cv, NULL, CV_DEFAULT, NULL);
3867978SPeter.Dunlap@Sun.COM idm_refcnt_init(&is->is_refcnt, is);
3877978SPeter.Dunlap@Sun.COM
3887978SPeter.Dunlap@Sun.COM /*
3897978SPeter.Dunlap@Sun.COM * Make sure all available transports are setup. We call this now
3907978SPeter.Dunlap@Sun.COM * instead of at initialization time in case IB has become available
3917978SPeter.Dunlap@Sun.COM * since we started (hotplug, etc).
3927978SPeter.Dunlap@Sun.COM */
39311424SJack.Meng@Sun.COM idm_transport_setup(sr->sr_li, B_FALSE);
3947978SPeter.Dunlap@Sun.COM
3957978SPeter.Dunlap@Sun.COM /*
3967978SPeter.Dunlap@Sun.COM * Loop through the transports, configuring the transport-specific
3977978SPeter.Dunlap@Sun.COM * components of each one.
3987978SPeter.Dunlap@Sun.COM */
3997978SPeter.Dunlap@Sun.COM for (type = 0; type < IDM_TRANSPORT_NUM_TYPES; type++) {
4007978SPeter.Dunlap@Sun.COM
4017978SPeter.Dunlap@Sun.COM it = &idm_transport_list[type];
4027978SPeter.Dunlap@Sun.COM /*
4037978SPeter.Dunlap@Sun.COM * If it_ops is NULL then the transport is unconfigured
4047978SPeter.Dunlap@Sun.COM * and we shouldn't try to start the service.
4057978SPeter.Dunlap@Sun.COM */
4067978SPeter.Dunlap@Sun.COM if (it->it_ops == NULL) {
4077978SPeter.Dunlap@Sun.COM continue;
4087978SPeter.Dunlap@Sun.COM }
4097978SPeter.Dunlap@Sun.COM
4107978SPeter.Dunlap@Sun.COM rc = it->it_ops->it_tgt_svc_create(sr, is);
4117978SPeter.Dunlap@Sun.COM if (rc != IDM_STATUS_SUCCESS) {
4127978SPeter.Dunlap@Sun.COM /* Teardown any configured services */
4137978SPeter.Dunlap@Sun.COM while (type--) {
4147978SPeter.Dunlap@Sun.COM it = &idm_transport_list[type];
4157978SPeter.Dunlap@Sun.COM if (it->it_ops == NULL) {
4167978SPeter.Dunlap@Sun.COM continue;
4177978SPeter.Dunlap@Sun.COM }
4187978SPeter.Dunlap@Sun.COM it->it_ops->it_tgt_svc_destroy(is);
4197978SPeter.Dunlap@Sun.COM }
4207978SPeter.Dunlap@Sun.COM /* Free the svc context and return */
4217978SPeter.Dunlap@Sun.COM kmem_free(is, sizeof (idm_svc_t));
4227978SPeter.Dunlap@Sun.COM return (rc);
4237978SPeter.Dunlap@Sun.COM }
4247978SPeter.Dunlap@Sun.COM }
4257978SPeter.Dunlap@Sun.COM
4267978SPeter.Dunlap@Sun.COM *new_svc = is;
4277978SPeter.Dunlap@Sun.COM
4287978SPeter.Dunlap@Sun.COM mutex_enter(&idm.idm_global_mutex);
4297978SPeter.Dunlap@Sun.COM list_insert_tail(&idm.idm_tgt_svc_list, is);
4307978SPeter.Dunlap@Sun.COM mutex_exit(&idm.idm_global_mutex);
4317978SPeter.Dunlap@Sun.COM
4327978SPeter.Dunlap@Sun.COM return (IDM_STATUS_SUCCESS);
4337978SPeter.Dunlap@Sun.COM }
4347978SPeter.Dunlap@Sun.COM
4357978SPeter.Dunlap@Sun.COM /*
4367978SPeter.Dunlap@Sun.COM * idm_tgt_svc_destroy
4377978SPeter.Dunlap@Sun.COM *
4387978SPeter.Dunlap@Sun.COM * is - idm_svc_t returned by the call to idm_tgt_svc_create
4397978SPeter.Dunlap@Sun.COM *
4407978SPeter.Dunlap@Sun.COM * Cleanup any resources associated with the idm_svc_t.
4417978SPeter.Dunlap@Sun.COM */
4427978SPeter.Dunlap@Sun.COM void
idm_tgt_svc_destroy(idm_svc_t * is)4437978SPeter.Dunlap@Sun.COM idm_tgt_svc_destroy(idm_svc_t *is)
4447978SPeter.Dunlap@Sun.COM {
4457978SPeter.Dunlap@Sun.COM idm_transport_type_t type;
4467978SPeter.Dunlap@Sun.COM idm_transport_t *it;
4477978SPeter.Dunlap@Sun.COM
4487978SPeter.Dunlap@Sun.COM mutex_enter(&idm.idm_global_mutex);
4497978SPeter.Dunlap@Sun.COM /* remove this service from the global list */
4507978SPeter.Dunlap@Sun.COM list_remove(&idm.idm_tgt_svc_list, is);
4517978SPeter.Dunlap@Sun.COM /* wakeup any waiters for service change */
4527978SPeter.Dunlap@Sun.COM cv_broadcast(&idm.idm_tgt_svc_cv);
4537978SPeter.Dunlap@Sun.COM mutex_exit(&idm.idm_global_mutex);
4547978SPeter.Dunlap@Sun.COM
4557978SPeter.Dunlap@Sun.COM /* teardown each transport-specific service */
4567978SPeter.Dunlap@Sun.COM for (type = 0; type < IDM_TRANSPORT_NUM_TYPES; type++) {
4577978SPeter.Dunlap@Sun.COM it = &idm_transport_list[type];
4587978SPeter.Dunlap@Sun.COM if (it->it_ops == NULL) {
4597978SPeter.Dunlap@Sun.COM continue;
4607978SPeter.Dunlap@Sun.COM }
4617978SPeter.Dunlap@Sun.COM
4627978SPeter.Dunlap@Sun.COM it->it_ops->it_tgt_svc_destroy(is);
4637978SPeter.Dunlap@Sun.COM }
4647978SPeter.Dunlap@Sun.COM
4659162SPeter.Dunlap@Sun.COM /* tear down the svc resources */
4669162SPeter.Dunlap@Sun.COM idm_refcnt_destroy(&is->is_refcnt);
4679162SPeter.Dunlap@Sun.COM cv_destroy(&is->is_count_cv);
4689162SPeter.Dunlap@Sun.COM mutex_destroy(&is->is_count_mutex);
4699162SPeter.Dunlap@Sun.COM cv_destroy(&is->is_cv);
4709162SPeter.Dunlap@Sun.COM mutex_destroy(&is->is_mutex);
4719162SPeter.Dunlap@Sun.COM
4727978SPeter.Dunlap@Sun.COM /* free the svc handle */
4737978SPeter.Dunlap@Sun.COM kmem_free(is, sizeof (idm_svc_t));
4747978SPeter.Dunlap@Sun.COM }
4757978SPeter.Dunlap@Sun.COM
4767978SPeter.Dunlap@Sun.COM void
idm_tgt_svc_hold(idm_svc_t * is)4777978SPeter.Dunlap@Sun.COM idm_tgt_svc_hold(idm_svc_t *is)
4787978SPeter.Dunlap@Sun.COM {
4797978SPeter.Dunlap@Sun.COM idm_refcnt_hold(&is->is_refcnt);
4807978SPeter.Dunlap@Sun.COM }
4817978SPeter.Dunlap@Sun.COM
4827978SPeter.Dunlap@Sun.COM void
idm_tgt_svc_rele_and_destroy(idm_svc_t * is)4837978SPeter.Dunlap@Sun.COM idm_tgt_svc_rele_and_destroy(idm_svc_t *is)
4847978SPeter.Dunlap@Sun.COM {
4857978SPeter.Dunlap@Sun.COM idm_refcnt_rele_and_destroy(&is->is_refcnt,
4867978SPeter.Dunlap@Sun.COM (idm_refcnt_cb_t *)&idm_tgt_svc_destroy);
4877978SPeter.Dunlap@Sun.COM }
4887978SPeter.Dunlap@Sun.COM
4897978SPeter.Dunlap@Sun.COM /*
4907978SPeter.Dunlap@Sun.COM * idm_tgt_svc_online
4917978SPeter.Dunlap@Sun.COM *
4927978SPeter.Dunlap@Sun.COM * is - idm_svc_t returned by the call to idm_tgt_svc_create
4937978SPeter.Dunlap@Sun.COM *
4947978SPeter.Dunlap@Sun.COM * Online each transport service, as we want this target to be accessible
4957978SPeter.Dunlap@Sun.COM * via any configured transport.
4967978SPeter.Dunlap@Sun.COM *
4977978SPeter.Dunlap@Sun.COM * When the initiator establishes a new connection to the target, IDM will
4987978SPeter.Dunlap@Sun.COM * call the "new connect" callback defined in the idm_svc_req_t structure
4997978SPeter.Dunlap@Sun.COM * and it will pass an idm_conn_t structure representing that new connection.
5007978SPeter.Dunlap@Sun.COM */
5017978SPeter.Dunlap@Sun.COM idm_status_t
idm_tgt_svc_online(idm_svc_t * is)5027978SPeter.Dunlap@Sun.COM idm_tgt_svc_online(idm_svc_t *is)
5037978SPeter.Dunlap@Sun.COM {
5047978SPeter.Dunlap@Sun.COM
5059162SPeter.Dunlap@Sun.COM idm_transport_type_t type, last_type;
5067978SPeter.Dunlap@Sun.COM idm_transport_t *it;
5079162SPeter.Dunlap@Sun.COM int rc = IDM_STATUS_SUCCESS;
5087978SPeter.Dunlap@Sun.COM
5097978SPeter.Dunlap@Sun.COM mutex_enter(&is->is_mutex);
5107978SPeter.Dunlap@Sun.COM if (is->is_online == 0) {
5119162SPeter.Dunlap@Sun.COM /* Walk through each of the transports and online them */
5127978SPeter.Dunlap@Sun.COM for (type = 0; type < IDM_TRANSPORT_NUM_TYPES; type++) {
5137978SPeter.Dunlap@Sun.COM it = &idm_transport_list[type];
5147978SPeter.Dunlap@Sun.COM if (it->it_ops == NULL) {
5157978SPeter.Dunlap@Sun.COM /* transport is not registered */
5167978SPeter.Dunlap@Sun.COM continue;
5177978SPeter.Dunlap@Sun.COM }
5187978SPeter.Dunlap@Sun.COM
5197978SPeter.Dunlap@Sun.COM mutex_exit(&is->is_mutex);
5207978SPeter.Dunlap@Sun.COM rc = it->it_ops->it_tgt_svc_online(is);
5217978SPeter.Dunlap@Sun.COM mutex_enter(&is->is_mutex);
5229162SPeter.Dunlap@Sun.COM if (rc != IDM_STATUS_SUCCESS) {
5239162SPeter.Dunlap@Sun.COM last_type = type;
5249162SPeter.Dunlap@Sun.COM break;
5257978SPeter.Dunlap@Sun.COM }
5267978SPeter.Dunlap@Sun.COM }
5279162SPeter.Dunlap@Sun.COM if (rc != IDM_STATUS_SUCCESS) {
5289162SPeter.Dunlap@Sun.COM /*
5299162SPeter.Dunlap@Sun.COM * The last transport failed to online.
5309162SPeter.Dunlap@Sun.COM * Offline any transport onlined above and
5319162SPeter.Dunlap@Sun.COM * do not online the target.
5329162SPeter.Dunlap@Sun.COM */
5339162SPeter.Dunlap@Sun.COM for (type = 0; type < last_type; type++) {
5349162SPeter.Dunlap@Sun.COM it = &idm_transport_list[type];
5359162SPeter.Dunlap@Sun.COM if (it->it_ops == NULL) {
5369162SPeter.Dunlap@Sun.COM /* transport is not registered */
5379162SPeter.Dunlap@Sun.COM continue;
5389162SPeter.Dunlap@Sun.COM }
5399162SPeter.Dunlap@Sun.COM
5409162SPeter.Dunlap@Sun.COM mutex_exit(&is->is_mutex);
5419162SPeter.Dunlap@Sun.COM it->it_ops->it_tgt_svc_offline(is);
5429162SPeter.Dunlap@Sun.COM mutex_enter(&is->is_mutex);
5439162SPeter.Dunlap@Sun.COM }
5449162SPeter.Dunlap@Sun.COM } else {
5459162SPeter.Dunlap@Sun.COM /* Target service now online */
5469162SPeter.Dunlap@Sun.COM is->is_online = 1;
5479162SPeter.Dunlap@Sun.COM }
5487978SPeter.Dunlap@Sun.COM } else {
5499162SPeter.Dunlap@Sun.COM /* Target service already online, just bump the count */
5509162SPeter.Dunlap@Sun.COM is->is_online++;
5517978SPeter.Dunlap@Sun.COM }
5527978SPeter.Dunlap@Sun.COM mutex_exit(&is->is_mutex);
5537978SPeter.Dunlap@Sun.COM
5549162SPeter.Dunlap@Sun.COM return (rc);
5557978SPeter.Dunlap@Sun.COM }
5567978SPeter.Dunlap@Sun.COM
5577978SPeter.Dunlap@Sun.COM /*
5587978SPeter.Dunlap@Sun.COM * idm_tgt_svc_offline
5597978SPeter.Dunlap@Sun.COM *
5607978SPeter.Dunlap@Sun.COM * is - idm_svc_t returned by the call to idm_tgt_svc_create
5617978SPeter.Dunlap@Sun.COM *
5627978SPeter.Dunlap@Sun.COM * Shutdown any online target services.
5637978SPeter.Dunlap@Sun.COM */
5647978SPeter.Dunlap@Sun.COM void
idm_tgt_svc_offline(idm_svc_t * is)5657978SPeter.Dunlap@Sun.COM idm_tgt_svc_offline(idm_svc_t *is)
5667978SPeter.Dunlap@Sun.COM {
5677978SPeter.Dunlap@Sun.COM idm_transport_type_t type;
5687978SPeter.Dunlap@Sun.COM idm_transport_t *it;
5697978SPeter.Dunlap@Sun.COM
5707978SPeter.Dunlap@Sun.COM mutex_enter(&is->is_mutex);
5717978SPeter.Dunlap@Sun.COM is->is_online--;
5727978SPeter.Dunlap@Sun.COM if (is->is_online == 0) {
5737978SPeter.Dunlap@Sun.COM /* Walk through each of the transports and offline them */
5747978SPeter.Dunlap@Sun.COM for (type = 0; type < IDM_TRANSPORT_NUM_TYPES; type++) {
5757978SPeter.Dunlap@Sun.COM it = &idm_transport_list[type];
5767978SPeter.Dunlap@Sun.COM if (it->it_ops == NULL) {
5777978SPeter.Dunlap@Sun.COM /* transport is not registered */
5787978SPeter.Dunlap@Sun.COM continue;
5797978SPeter.Dunlap@Sun.COM }
5807978SPeter.Dunlap@Sun.COM
5817978SPeter.Dunlap@Sun.COM mutex_exit(&is->is_mutex);
5827978SPeter.Dunlap@Sun.COM it->it_ops->it_tgt_svc_offline(is);
5837978SPeter.Dunlap@Sun.COM mutex_enter(&is->is_mutex);
5847978SPeter.Dunlap@Sun.COM }
5857978SPeter.Dunlap@Sun.COM }
5867978SPeter.Dunlap@Sun.COM mutex_exit(&is->is_mutex);
5877978SPeter.Dunlap@Sun.COM }
5887978SPeter.Dunlap@Sun.COM
5897978SPeter.Dunlap@Sun.COM /*
5907978SPeter.Dunlap@Sun.COM * idm_tgt_svc_lookup
5917978SPeter.Dunlap@Sun.COM *
5927978SPeter.Dunlap@Sun.COM * Lookup a service instance listening on the specified port
5937978SPeter.Dunlap@Sun.COM */
5947978SPeter.Dunlap@Sun.COM
5957978SPeter.Dunlap@Sun.COM idm_svc_t *
idm_tgt_svc_lookup(uint16_t port)5967978SPeter.Dunlap@Sun.COM idm_tgt_svc_lookup(uint16_t port)
5977978SPeter.Dunlap@Sun.COM {
5987978SPeter.Dunlap@Sun.COM idm_svc_t *result;
5997978SPeter.Dunlap@Sun.COM
6007978SPeter.Dunlap@Sun.COM retry:
6017978SPeter.Dunlap@Sun.COM mutex_enter(&idm.idm_global_mutex);
6027978SPeter.Dunlap@Sun.COM for (result = list_head(&idm.idm_tgt_svc_list);
6037978SPeter.Dunlap@Sun.COM result != NULL;
6047978SPeter.Dunlap@Sun.COM result = list_next(&idm.idm_tgt_svc_list, result)) {
6057978SPeter.Dunlap@Sun.COM if (result->is_svc_req.sr_port == port) {
6067978SPeter.Dunlap@Sun.COM if (result->is_online == 0) {
6077978SPeter.Dunlap@Sun.COM /*
6087978SPeter.Dunlap@Sun.COM * A service exists on this port, but it
6097978SPeter.Dunlap@Sun.COM * is going away, wait for it to cleanup.
6107978SPeter.Dunlap@Sun.COM */
6117978SPeter.Dunlap@Sun.COM cv_wait(&idm.idm_tgt_svc_cv,
6127978SPeter.Dunlap@Sun.COM &idm.idm_global_mutex);
6137978SPeter.Dunlap@Sun.COM mutex_exit(&idm.idm_global_mutex);
6147978SPeter.Dunlap@Sun.COM goto retry;
6157978SPeter.Dunlap@Sun.COM }
6167978SPeter.Dunlap@Sun.COM idm_tgt_svc_hold(result);
6177978SPeter.Dunlap@Sun.COM mutex_exit(&idm.idm_global_mutex);
6187978SPeter.Dunlap@Sun.COM return (result);
6197978SPeter.Dunlap@Sun.COM }
6207978SPeter.Dunlap@Sun.COM }
6217978SPeter.Dunlap@Sun.COM mutex_exit(&idm.idm_global_mutex);
6227978SPeter.Dunlap@Sun.COM
6237978SPeter.Dunlap@Sun.COM return (NULL);
6247978SPeter.Dunlap@Sun.COM }
6257978SPeter.Dunlap@Sun.COM
6267978SPeter.Dunlap@Sun.COM /*
6277978SPeter.Dunlap@Sun.COM * idm_negotiate_key_values()
6287978SPeter.Dunlap@Sun.COM * Give IDM level a chance to negotiate any login parameters it should own.
6297978SPeter.Dunlap@Sun.COM * -- leave unhandled parameters alone on request_nvl
6307978SPeter.Dunlap@Sun.COM * -- move all handled parameters to response_nvl with an appropriate response
6317978SPeter.Dunlap@Sun.COM * -- also add an entry to negotiated_nvl for any accepted parameters
6327978SPeter.Dunlap@Sun.COM */
6337978SPeter.Dunlap@Sun.COM kv_status_t
idm_negotiate_key_values(idm_conn_t * ic,nvlist_t * request_nvl,nvlist_t * response_nvl,nvlist_t * negotiated_nvl)6347978SPeter.Dunlap@Sun.COM idm_negotiate_key_values(idm_conn_t *ic, nvlist_t *request_nvl,
6357978SPeter.Dunlap@Sun.COM nvlist_t *response_nvl, nvlist_t *negotiated_nvl)
6367978SPeter.Dunlap@Sun.COM {
6377978SPeter.Dunlap@Sun.COM ASSERT(ic->ic_transport_ops != NULL);
6387978SPeter.Dunlap@Sun.COM return (ic->ic_transport_ops->it_negotiate_key_values(ic,
6397978SPeter.Dunlap@Sun.COM request_nvl, response_nvl, negotiated_nvl));
6407978SPeter.Dunlap@Sun.COM }
6417978SPeter.Dunlap@Sun.COM
6427978SPeter.Dunlap@Sun.COM /*
6437978SPeter.Dunlap@Sun.COM * idm_notice_key_values()
6447978SPeter.Dunlap@Sun.COM * Activate at the IDM level any parameters that have been negotiated.
6457978SPeter.Dunlap@Sun.COM * Passes the set of key value pairs to the transport for activation.
6467978SPeter.Dunlap@Sun.COM * This will be invoked as the connection is entering full-feature mode.
6477978SPeter.Dunlap@Sun.COM */
6489162SPeter.Dunlap@Sun.COM void
idm_notice_key_values(idm_conn_t * ic,nvlist_t * negotiated_nvl)6497978SPeter.Dunlap@Sun.COM idm_notice_key_values(idm_conn_t *ic, nvlist_t *negotiated_nvl)
6507978SPeter.Dunlap@Sun.COM {
6517978SPeter.Dunlap@Sun.COM ASSERT(ic->ic_transport_ops != NULL);
6529162SPeter.Dunlap@Sun.COM ic->ic_transport_ops->it_notice_key_values(ic, negotiated_nvl);
6537978SPeter.Dunlap@Sun.COM }
6547978SPeter.Dunlap@Sun.COM
6557978SPeter.Dunlap@Sun.COM /*
65610261SCharles.Ting@Sun.COM * idm_declare_key_values()
65710261SCharles.Ting@Sun.COM * Activate an operational set of declarative parameters from the config_nvl,
65810261SCharles.Ting@Sun.COM * and return the selected values in the outgoing_nvl.
65910261SCharles.Ting@Sun.COM */
66010261SCharles.Ting@Sun.COM kv_status_t
idm_declare_key_values(idm_conn_t * ic,nvlist_t * config_nvl,nvlist_t * outgoing_nvl)66110261SCharles.Ting@Sun.COM idm_declare_key_values(idm_conn_t *ic, nvlist_t *config_nvl,
66210261SCharles.Ting@Sun.COM nvlist_t *outgoing_nvl)
66310261SCharles.Ting@Sun.COM {
66410261SCharles.Ting@Sun.COM ASSERT(ic->ic_transport_ops != NULL);
66510261SCharles.Ting@Sun.COM return (ic->ic_transport_ops->it_declare_key_values(ic, config_nvl,
66610261SCharles.Ting@Sun.COM outgoing_nvl));
66710261SCharles.Ting@Sun.COM }
66810261SCharles.Ting@Sun.COM
66910261SCharles.Ting@Sun.COM /*
6707978SPeter.Dunlap@Sun.COM * idm_buf_tx_to_ini
6717978SPeter.Dunlap@Sun.COM *
6727978SPeter.Dunlap@Sun.COM * This is IDM's implementation of the 'Put_Data' operational primitive.
6737978SPeter.Dunlap@Sun.COM *
6747978SPeter.Dunlap@Sun.COM * This function is invoked by a target iSCSI layer to request its local
6757978SPeter.Dunlap@Sun.COM * Datamover layer to transmit the Data-In PDU to the peer iSCSI layer
6767978SPeter.Dunlap@Sun.COM * on the remote iSCSI node. The I/O buffer represented by 'idb' is
6777978SPeter.Dunlap@Sun.COM * transferred to the initiator associated with task 'idt'. The connection
6787978SPeter.Dunlap@Sun.COM * info, contents of the Data-In PDU header, the DataDescriptorIn, BHS,
6797978SPeter.Dunlap@Sun.COM * and the callback (idb->idb_buf_cb) at transfer completion are
6807978SPeter.Dunlap@Sun.COM * provided as input.
6817978SPeter.Dunlap@Sun.COM *
6827978SPeter.Dunlap@Sun.COM * This data transfer takes place transparently to the remote iSCSI layer,
6837978SPeter.Dunlap@Sun.COM * i.e. without its participation.
6847978SPeter.Dunlap@Sun.COM *
6857978SPeter.Dunlap@Sun.COM * Using sockets, IDM implements the data transfer by segmenting the data
6867978SPeter.Dunlap@Sun.COM * buffer into appropriately sized iSCSI PDUs and transmitting them to the
6877978SPeter.Dunlap@Sun.COM * initiator. iSER performs the transfer using RDMA write.
6887978SPeter.Dunlap@Sun.COM *
6897978SPeter.Dunlap@Sun.COM */
6907978SPeter.Dunlap@Sun.COM idm_status_t
idm_buf_tx_to_ini(idm_task_t * idt,idm_buf_t * idb,uint32_t offset,uint32_t xfer_len,idm_buf_cb_t idb_buf_cb,void * cb_arg)6917978SPeter.Dunlap@Sun.COM idm_buf_tx_to_ini(idm_task_t *idt, idm_buf_t *idb,
6927978SPeter.Dunlap@Sun.COM uint32_t offset, uint32_t xfer_len,
6937978SPeter.Dunlap@Sun.COM idm_buf_cb_t idb_buf_cb, void *cb_arg)
6947978SPeter.Dunlap@Sun.COM {
6957978SPeter.Dunlap@Sun.COM idm_status_t rc;
6967978SPeter.Dunlap@Sun.COM
6977978SPeter.Dunlap@Sun.COM idb->idb_bufoffset = offset;
6987978SPeter.Dunlap@Sun.COM idb->idb_xfer_len = xfer_len;
6997978SPeter.Dunlap@Sun.COM idb->idb_buf_cb = idb_buf_cb;
7007978SPeter.Dunlap@Sun.COM idb->idb_cb_arg = cb_arg;
7019162SPeter.Dunlap@Sun.COM gethrestime(&idb->idb_xfer_start);
7029162SPeter.Dunlap@Sun.COM
7039162SPeter.Dunlap@Sun.COM /*
7049162SPeter.Dunlap@Sun.COM * Buffer should not contain the pattern. If the pattern is
7059162SPeter.Dunlap@Sun.COM * present then we've been asked to transmit initialized data
7069162SPeter.Dunlap@Sun.COM */
7079162SPeter.Dunlap@Sun.COM IDM_BUFPAT_CHECK(idb, xfer_len, BP_CHECK_ASSERT);
7087978SPeter.Dunlap@Sun.COM
7097978SPeter.Dunlap@Sun.COM mutex_enter(&idt->idt_mutex);
7107978SPeter.Dunlap@Sun.COM switch (idt->idt_state) {
7117978SPeter.Dunlap@Sun.COM case TASK_ACTIVE:
7127978SPeter.Dunlap@Sun.COM idt->idt_tx_to_ini_start++;
7137978SPeter.Dunlap@Sun.COM idm_task_hold(idt);
7147978SPeter.Dunlap@Sun.COM idm_buf_bind_in_locked(idt, idb);
7157978SPeter.Dunlap@Sun.COM idb->idb_in_transport = B_TRUE;
7167978SPeter.Dunlap@Sun.COM rc = (*idt->idt_ic->ic_transport_ops->it_buf_tx_to_ini)
7177978SPeter.Dunlap@Sun.COM (idt, idb);
7187978SPeter.Dunlap@Sun.COM return (rc);
7197978SPeter.Dunlap@Sun.COM
7207978SPeter.Dunlap@Sun.COM case TASK_SUSPENDING:
7217978SPeter.Dunlap@Sun.COM case TASK_SUSPENDED:
7227978SPeter.Dunlap@Sun.COM /*
7237978SPeter.Dunlap@Sun.COM * Bind buffer but don't start a transfer since the task
7247978SPeter.Dunlap@Sun.COM * is suspended
7257978SPeter.Dunlap@Sun.COM */
7267978SPeter.Dunlap@Sun.COM idm_buf_bind_in_locked(idt, idb);
7277978SPeter.Dunlap@Sun.COM mutex_exit(&idt->idt_mutex);
7287978SPeter.Dunlap@Sun.COM return (IDM_STATUS_SUCCESS);
7297978SPeter.Dunlap@Sun.COM
7307978SPeter.Dunlap@Sun.COM case TASK_ABORTING:
7317978SPeter.Dunlap@Sun.COM case TASK_ABORTED:
7327978SPeter.Dunlap@Sun.COM /*
7337978SPeter.Dunlap@Sun.COM * Once the task is aborted, any buffers added to the
7347978SPeter.Dunlap@Sun.COM * idt_inbufv will never get cleaned up, so just return
7357978SPeter.Dunlap@Sun.COM * SUCCESS. The buffer should get cleaned up by the
7367978SPeter.Dunlap@Sun.COM * client or framework once task_aborted has completed.
7377978SPeter.Dunlap@Sun.COM */
7387978SPeter.Dunlap@Sun.COM mutex_exit(&idt->idt_mutex);
7397978SPeter.Dunlap@Sun.COM return (IDM_STATUS_SUCCESS);
7407978SPeter.Dunlap@Sun.COM
7417978SPeter.Dunlap@Sun.COM default:
7427978SPeter.Dunlap@Sun.COM ASSERT(0);
7437978SPeter.Dunlap@Sun.COM break;
7447978SPeter.Dunlap@Sun.COM }
7457978SPeter.Dunlap@Sun.COM mutex_exit(&idt->idt_mutex);
7467978SPeter.Dunlap@Sun.COM
7477978SPeter.Dunlap@Sun.COM return (IDM_STATUS_FAIL);
7487978SPeter.Dunlap@Sun.COM }
7497978SPeter.Dunlap@Sun.COM
7507978SPeter.Dunlap@Sun.COM /*
7517978SPeter.Dunlap@Sun.COM * idm_buf_rx_from_ini
7527978SPeter.Dunlap@Sun.COM *
7537978SPeter.Dunlap@Sun.COM * This is IDM's implementation of the 'Get_Data' operational primitive.
7547978SPeter.Dunlap@Sun.COM *
7557978SPeter.Dunlap@Sun.COM * This function is invoked by a target iSCSI layer to request its local
7567978SPeter.Dunlap@Sun.COM * Datamover layer to retrieve certain data identified by the R2T PDU from the
7577978SPeter.Dunlap@Sun.COM * peer iSCSI layer on the remote node. The retrieved Data-Out PDU will be
7587978SPeter.Dunlap@Sun.COM * mapped to the respective buffer by the task tags (ITT & TTT).
7597978SPeter.Dunlap@Sun.COM * The connection information, contents of an R2T PDU, DataDescriptor, BHS, and
7607978SPeter.Dunlap@Sun.COM * the callback (idb->idb_buf_cb) notification for data transfer completion are
7617978SPeter.Dunlap@Sun.COM * are provided as input.
7627978SPeter.Dunlap@Sun.COM *
7637978SPeter.Dunlap@Sun.COM * When an iSCSI node sends an R2T PDU to its local Datamover layer, the local
7647978SPeter.Dunlap@Sun.COM * Datamover layer, the local and remote Datamover layers transparently bring
7657978SPeter.Dunlap@Sun.COM * about the data transfer requested by the R2T PDU, without the participation
7667978SPeter.Dunlap@Sun.COM * of the iSCSI layers.
7677978SPeter.Dunlap@Sun.COM *
7687978SPeter.Dunlap@Sun.COM * Using sockets, IDM transmits an R2T PDU for each buffer and the rx_data_out()
7697978SPeter.Dunlap@Sun.COM * assembles the Data-Out PDUs into the buffer. iSER uses RDMA read.
7707978SPeter.Dunlap@Sun.COM *
7717978SPeter.Dunlap@Sun.COM */
7727978SPeter.Dunlap@Sun.COM idm_status_t
idm_buf_rx_from_ini(idm_task_t * idt,idm_buf_t * idb,uint32_t offset,uint32_t xfer_len,idm_buf_cb_t idb_buf_cb,void * cb_arg)7737978SPeter.Dunlap@Sun.COM idm_buf_rx_from_ini(idm_task_t *idt, idm_buf_t *idb,
7747978SPeter.Dunlap@Sun.COM uint32_t offset, uint32_t xfer_len,
7757978SPeter.Dunlap@Sun.COM idm_buf_cb_t idb_buf_cb, void *cb_arg)
7767978SPeter.Dunlap@Sun.COM {
7777978SPeter.Dunlap@Sun.COM idm_status_t rc;
7787978SPeter.Dunlap@Sun.COM
7797978SPeter.Dunlap@Sun.COM idb->idb_bufoffset = offset;
7807978SPeter.Dunlap@Sun.COM idb->idb_xfer_len = xfer_len;
7817978SPeter.Dunlap@Sun.COM idb->idb_buf_cb = idb_buf_cb;
7827978SPeter.Dunlap@Sun.COM idb->idb_cb_arg = cb_arg;
7839162SPeter.Dunlap@Sun.COM gethrestime(&idb->idb_xfer_start);
7847978SPeter.Dunlap@Sun.COM
7857978SPeter.Dunlap@Sun.COM /*
7867978SPeter.Dunlap@Sun.COM * "In" buf list is for "Data In" PDU's, "Out" buf list is for
7877978SPeter.Dunlap@Sun.COM * "Data Out" PDU's
7887978SPeter.Dunlap@Sun.COM */
7897978SPeter.Dunlap@Sun.COM mutex_enter(&idt->idt_mutex);
7907978SPeter.Dunlap@Sun.COM switch (idt->idt_state) {
7917978SPeter.Dunlap@Sun.COM case TASK_ACTIVE:
7927978SPeter.Dunlap@Sun.COM idt->idt_rx_from_ini_start++;
7937978SPeter.Dunlap@Sun.COM idm_task_hold(idt);
7947978SPeter.Dunlap@Sun.COM idm_buf_bind_out_locked(idt, idb);
7957978SPeter.Dunlap@Sun.COM idb->idb_in_transport = B_TRUE;
7967978SPeter.Dunlap@Sun.COM rc = (*idt->idt_ic->ic_transport_ops->it_buf_rx_from_ini)
7977978SPeter.Dunlap@Sun.COM (idt, idb);
7987978SPeter.Dunlap@Sun.COM return (rc);
7997978SPeter.Dunlap@Sun.COM case TASK_SUSPENDING:
8007978SPeter.Dunlap@Sun.COM case TASK_SUSPENDED:
8017978SPeter.Dunlap@Sun.COM case TASK_ABORTING:
8027978SPeter.Dunlap@Sun.COM case TASK_ABORTED:
8037978SPeter.Dunlap@Sun.COM /*
8047978SPeter.Dunlap@Sun.COM * Bind buffer but don't start a transfer since the task
8057978SPeter.Dunlap@Sun.COM * is suspended
8067978SPeter.Dunlap@Sun.COM */
8077978SPeter.Dunlap@Sun.COM idm_buf_bind_out_locked(idt, idb);
8087978SPeter.Dunlap@Sun.COM mutex_exit(&idt->idt_mutex);
8097978SPeter.Dunlap@Sun.COM return (IDM_STATUS_SUCCESS);
8107978SPeter.Dunlap@Sun.COM default:
8117978SPeter.Dunlap@Sun.COM ASSERT(0);
8127978SPeter.Dunlap@Sun.COM break;
8137978SPeter.Dunlap@Sun.COM }
8147978SPeter.Dunlap@Sun.COM mutex_exit(&idt->idt_mutex);
8157978SPeter.Dunlap@Sun.COM
8167978SPeter.Dunlap@Sun.COM return (IDM_STATUS_FAIL);
8177978SPeter.Dunlap@Sun.COM }
8187978SPeter.Dunlap@Sun.COM
8197978SPeter.Dunlap@Sun.COM /*
8207978SPeter.Dunlap@Sun.COM * idm_buf_tx_to_ini_done
8217978SPeter.Dunlap@Sun.COM *
8227978SPeter.Dunlap@Sun.COM * The transport calls this after it has completed a transfer requested by
8237978SPeter.Dunlap@Sun.COM * a call to transport_buf_tx_to_ini
8247978SPeter.Dunlap@Sun.COM *
8257978SPeter.Dunlap@Sun.COM * Caller holds idt->idt_mutex, idt->idt_mutex is released before returning.
8267978SPeter.Dunlap@Sun.COM * idt may be freed after the call to idb->idb_buf_cb.
8277978SPeter.Dunlap@Sun.COM */
8287978SPeter.Dunlap@Sun.COM void
idm_buf_tx_to_ini_done(idm_task_t * idt,idm_buf_t * idb,idm_status_t status)8297978SPeter.Dunlap@Sun.COM idm_buf_tx_to_ini_done(idm_task_t *idt, idm_buf_t *idb, idm_status_t status)
8307978SPeter.Dunlap@Sun.COM {
8317978SPeter.Dunlap@Sun.COM ASSERT(mutex_owned(&idt->idt_mutex));
8327978SPeter.Dunlap@Sun.COM idb->idb_in_transport = B_FALSE;
8337978SPeter.Dunlap@Sun.COM idb->idb_tx_thread = B_FALSE;
8347978SPeter.Dunlap@Sun.COM idt->idt_tx_to_ini_done++;
8359162SPeter.Dunlap@Sun.COM gethrestime(&idb->idb_xfer_done);
8367978SPeter.Dunlap@Sun.COM
8377978SPeter.Dunlap@Sun.COM /*
8387978SPeter.Dunlap@Sun.COM * idm_refcnt_rele may cause TASK_SUSPENDING --> TASK_SUSPENDED or
8397978SPeter.Dunlap@Sun.COM * TASK_ABORTING --> TASK_ABORTED transistion if the refcount goes
8407978SPeter.Dunlap@Sun.COM * to 0.
8417978SPeter.Dunlap@Sun.COM */
8427978SPeter.Dunlap@Sun.COM idm_task_rele(idt);
8437978SPeter.Dunlap@Sun.COM idb->idb_status = status;
8447978SPeter.Dunlap@Sun.COM
8457978SPeter.Dunlap@Sun.COM switch (idt->idt_state) {
8467978SPeter.Dunlap@Sun.COM case TASK_ACTIVE:
8479586SPeter.Dunlap@Sun.COM idt->idt_ic->ic_timestamp = ddi_get_lbolt();
8487978SPeter.Dunlap@Sun.COM idm_buf_unbind_in_locked(idt, idb);
8497978SPeter.Dunlap@Sun.COM mutex_exit(&idt->idt_mutex);
8507978SPeter.Dunlap@Sun.COM (*idb->idb_buf_cb)(idb, status);
8517978SPeter.Dunlap@Sun.COM return;
8527978SPeter.Dunlap@Sun.COM case TASK_SUSPENDING:
8537978SPeter.Dunlap@Sun.COM case TASK_SUSPENDED:
8547978SPeter.Dunlap@Sun.COM case TASK_ABORTING:
8557978SPeter.Dunlap@Sun.COM case TASK_ABORTED:
8567978SPeter.Dunlap@Sun.COM /*
8577978SPeter.Dunlap@Sun.COM * To keep things simple we will ignore the case where the
8587978SPeter.Dunlap@Sun.COM * transfer was successful and leave all buffers bound to the
8597978SPeter.Dunlap@Sun.COM * task. This allows us to also ignore the case where we've
8607978SPeter.Dunlap@Sun.COM * been asked to abort a task but the last transfer of the
8617978SPeter.Dunlap@Sun.COM * task has completed. IDM has no idea whether this was, in
8627978SPeter.Dunlap@Sun.COM * fact, the last transfer of the task so it would be difficult
8637978SPeter.Dunlap@Sun.COM * to handle this case. Everything should get sorted out again
8647978SPeter.Dunlap@Sun.COM * after task reassignment is complete.
8657978SPeter.Dunlap@Sun.COM *
8667978SPeter.Dunlap@Sun.COM * In the case of TASK_ABORTING we could conceivably call the
8677978SPeter.Dunlap@Sun.COM * buffer callback here but the timing of when the client's
8687978SPeter.Dunlap@Sun.COM * client_task_aborted callback is invoked vs. when the client's
8697978SPeter.Dunlap@Sun.COM * buffer callback gets invoked gets sticky. We don't want
8707978SPeter.Dunlap@Sun.COM * the client to here from us again after the call to
8717978SPeter.Dunlap@Sun.COM * client_task_aborted() but we don't want to give it a bunch
8727978SPeter.Dunlap@Sun.COM * of failed buffer transfers until we've called
8737978SPeter.Dunlap@Sun.COM * client_task_aborted(). Instead we'll just leave all the
8747978SPeter.Dunlap@Sun.COM * buffers bound and allow the client to cleanup.
8757978SPeter.Dunlap@Sun.COM */
8767978SPeter.Dunlap@Sun.COM break;
8777978SPeter.Dunlap@Sun.COM default:
8787978SPeter.Dunlap@Sun.COM ASSERT(0);
8797978SPeter.Dunlap@Sun.COM }
8807978SPeter.Dunlap@Sun.COM mutex_exit(&idt->idt_mutex);
8817978SPeter.Dunlap@Sun.COM }
8827978SPeter.Dunlap@Sun.COM
8837978SPeter.Dunlap@Sun.COM /*
8847978SPeter.Dunlap@Sun.COM * idm_buf_rx_from_ini_done
8857978SPeter.Dunlap@Sun.COM *
8867978SPeter.Dunlap@Sun.COM * The transport calls this after it has completed a transfer requested by
8877978SPeter.Dunlap@Sun.COM * a call totransport_buf_tx_to_ini
8887978SPeter.Dunlap@Sun.COM *
8897978SPeter.Dunlap@Sun.COM * Caller holds idt->idt_mutex, idt->idt_mutex is released before returning.
8907978SPeter.Dunlap@Sun.COM * idt may be freed after the call to idb->idb_buf_cb.
8917978SPeter.Dunlap@Sun.COM */
8927978SPeter.Dunlap@Sun.COM void
idm_buf_rx_from_ini_done(idm_task_t * idt,idm_buf_t * idb,idm_status_t status)8937978SPeter.Dunlap@Sun.COM idm_buf_rx_from_ini_done(idm_task_t *idt, idm_buf_t *idb, idm_status_t status)
8947978SPeter.Dunlap@Sun.COM {
8957978SPeter.Dunlap@Sun.COM ASSERT(mutex_owned(&idt->idt_mutex));
8967978SPeter.Dunlap@Sun.COM idb->idb_in_transport = B_FALSE;
8977978SPeter.Dunlap@Sun.COM idt->idt_rx_from_ini_done++;
8989162SPeter.Dunlap@Sun.COM gethrestime(&idb->idb_xfer_done);
8997978SPeter.Dunlap@Sun.COM
9007978SPeter.Dunlap@Sun.COM /*
9017978SPeter.Dunlap@Sun.COM * idm_refcnt_rele may cause TASK_SUSPENDING --> TASK_SUSPENDED or
9027978SPeter.Dunlap@Sun.COM * TASK_ABORTING --> TASK_ABORTED transistion if the refcount goes
9037978SPeter.Dunlap@Sun.COM * to 0.
9047978SPeter.Dunlap@Sun.COM */
9057978SPeter.Dunlap@Sun.COM idm_task_rele(idt);
9067978SPeter.Dunlap@Sun.COM idb->idb_status = status;
9077978SPeter.Dunlap@Sun.COM
9089162SPeter.Dunlap@Sun.COM if (status == IDM_STATUS_SUCCESS) {
9099162SPeter.Dunlap@Sun.COM /*
9109162SPeter.Dunlap@Sun.COM * Buffer should not contain the pattern. If it does then
9119162SPeter.Dunlap@Sun.COM * we did not get the data from the remote host.
9129162SPeter.Dunlap@Sun.COM */
9139162SPeter.Dunlap@Sun.COM IDM_BUFPAT_CHECK(idb, idb->idb_xfer_len, BP_CHECK_ASSERT);
9149162SPeter.Dunlap@Sun.COM }
9159162SPeter.Dunlap@Sun.COM
9167978SPeter.Dunlap@Sun.COM switch (idt->idt_state) {
9177978SPeter.Dunlap@Sun.COM case TASK_ACTIVE:
9189586SPeter.Dunlap@Sun.COM idt->idt_ic->ic_timestamp = ddi_get_lbolt();
9197978SPeter.Dunlap@Sun.COM idm_buf_unbind_out_locked(idt, idb);
9207978SPeter.Dunlap@Sun.COM mutex_exit(&idt->idt_mutex);
9217978SPeter.Dunlap@Sun.COM (*idb->idb_buf_cb)(idb, status);
9227978SPeter.Dunlap@Sun.COM return;
9237978SPeter.Dunlap@Sun.COM case TASK_SUSPENDING:
9247978SPeter.Dunlap@Sun.COM case TASK_SUSPENDED:
9257978SPeter.Dunlap@Sun.COM case TASK_ABORTING:
9267978SPeter.Dunlap@Sun.COM case TASK_ABORTED:
9277978SPeter.Dunlap@Sun.COM /*
9287978SPeter.Dunlap@Sun.COM * To keep things simple we will ignore the case where the
9297978SPeter.Dunlap@Sun.COM * transfer was successful and leave all buffers bound to the
9307978SPeter.Dunlap@Sun.COM * task. This allows us to also ignore the case where we've
9317978SPeter.Dunlap@Sun.COM * been asked to abort a task but the last transfer of the
9327978SPeter.Dunlap@Sun.COM * task has completed. IDM has no idea whether this was, in
9337978SPeter.Dunlap@Sun.COM * fact, the last transfer of the task so it would be difficult
9347978SPeter.Dunlap@Sun.COM * to handle this case. Everything should get sorted out again
9357978SPeter.Dunlap@Sun.COM * after task reassignment is complete.
9367978SPeter.Dunlap@Sun.COM *
9377978SPeter.Dunlap@Sun.COM * In the case of TASK_ABORTING we could conceivably call the
9387978SPeter.Dunlap@Sun.COM * buffer callback here but the timing of when the client's
9397978SPeter.Dunlap@Sun.COM * client_task_aborted callback is invoked vs. when the client's
9407978SPeter.Dunlap@Sun.COM * buffer callback gets invoked gets sticky. We don't want
9417978SPeter.Dunlap@Sun.COM * the client to here from us again after the call to
9427978SPeter.Dunlap@Sun.COM * client_task_aborted() but we don't want to give it a bunch
9437978SPeter.Dunlap@Sun.COM * of failed buffer transfers until we've called
9447978SPeter.Dunlap@Sun.COM * client_task_aborted(). Instead we'll just leave all the
9457978SPeter.Dunlap@Sun.COM * buffers bound and allow the client to cleanup.
9467978SPeter.Dunlap@Sun.COM */
9477978SPeter.Dunlap@Sun.COM break;
9487978SPeter.Dunlap@Sun.COM default:
9497978SPeter.Dunlap@Sun.COM ASSERT(0);
9507978SPeter.Dunlap@Sun.COM }
9517978SPeter.Dunlap@Sun.COM mutex_exit(&idt->idt_mutex);
9527978SPeter.Dunlap@Sun.COM }
9537978SPeter.Dunlap@Sun.COM
9547978SPeter.Dunlap@Sun.COM /*
9557978SPeter.Dunlap@Sun.COM * idm_buf_alloc
9567978SPeter.Dunlap@Sun.COM *
9577978SPeter.Dunlap@Sun.COM * Allocates a buffer handle and registers it for use with the transport
9587978SPeter.Dunlap@Sun.COM * layer. If a buffer is not passed on bufptr, the buffer will be allocated
9597978SPeter.Dunlap@Sun.COM * as well as the handle.
9607978SPeter.Dunlap@Sun.COM *
9617978SPeter.Dunlap@Sun.COM * ic - connection on which the buffer will be transferred
9627978SPeter.Dunlap@Sun.COM * bufptr - allocate memory for buffer if NULL, else assign to buffer
9637978SPeter.Dunlap@Sun.COM * buflen - length of buffer
9647978SPeter.Dunlap@Sun.COM *
9657978SPeter.Dunlap@Sun.COM * Returns idm_buf_t handle if successful, otherwise NULL
9667978SPeter.Dunlap@Sun.COM */
9677978SPeter.Dunlap@Sun.COM idm_buf_t *
idm_buf_alloc(idm_conn_t * ic,void * bufptr,uint64_t buflen)9687978SPeter.Dunlap@Sun.COM idm_buf_alloc(idm_conn_t *ic, void *bufptr, uint64_t buflen)
9697978SPeter.Dunlap@Sun.COM {
9707978SPeter.Dunlap@Sun.COM idm_buf_t *buf = NULL;
9717978SPeter.Dunlap@Sun.COM int rc;
9727978SPeter.Dunlap@Sun.COM
9737978SPeter.Dunlap@Sun.COM ASSERT(ic != NULL);
9747978SPeter.Dunlap@Sun.COM ASSERT(idm.idm_buf_cache != NULL);
9757978SPeter.Dunlap@Sun.COM ASSERT(buflen > 0);
9767978SPeter.Dunlap@Sun.COM
9777978SPeter.Dunlap@Sun.COM /* Don't allocate new buffers if we are not in FFP */
9787978SPeter.Dunlap@Sun.COM mutex_enter(&ic->ic_state_mutex);
9797978SPeter.Dunlap@Sun.COM if (!ic->ic_ffp) {
9807978SPeter.Dunlap@Sun.COM mutex_exit(&ic->ic_state_mutex);
9817978SPeter.Dunlap@Sun.COM return (NULL);
9827978SPeter.Dunlap@Sun.COM }
9837978SPeter.Dunlap@Sun.COM
9847978SPeter.Dunlap@Sun.COM
9857978SPeter.Dunlap@Sun.COM idm_conn_hold(ic);
9867978SPeter.Dunlap@Sun.COM mutex_exit(&ic->ic_state_mutex);
9877978SPeter.Dunlap@Sun.COM
9887978SPeter.Dunlap@Sun.COM buf = kmem_cache_alloc(idm.idm_buf_cache, KM_NOSLEEP);
9897978SPeter.Dunlap@Sun.COM if (buf == NULL) {
9907978SPeter.Dunlap@Sun.COM idm_conn_rele(ic);
9917978SPeter.Dunlap@Sun.COM return (NULL);
9927978SPeter.Dunlap@Sun.COM }
9937978SPeter.Dunlap@Sun.COM
9947978SPeter.Dunlap@Sun.COM buf->idb_ic = ic;
9957978SPeter.Dunlap@Sun.COM buf->idb_buflen = buflen;
9967978SPeter.Dunlap@Sun.COM buf->idb_exp_offset = 0;
9977978SPeter.Dunlap@Sun.COM buf->idb_bufoffset = 0;
9987978SPeter.Dunlap@Sun.COM buf->idb_xfer_len = 0;
9997978SPeter.Dunlap@Sun.COM buf->idb_magic = IDM_BUF_MAGIC;
10009162SPeter.Dunlap@Sun.COM buf->idb_in_transport = B_FALSE;
10019162SPeter.Dunlap@Sun.COM buf->idb_bufbcopy = B_FALSE;
10027978SPeter.Dunlap@Sun.COM
10037978SPeter.Dunlap@Sun.COM /*
10047978SPeter.Dunlap@Sun.COM * If bufptr is NULL, we have an implicit request to allocate
10057978SPeter.Dunlap@Sun.COM * memory for this IDM buffer handle and register it for use
10067978SPeter.Dunlap@Sun.COM * with the transport. To simplify this, and to give more freedom
10077978SPeter.Dunlap@Sun.COM * to the transport layer for it's own buffer management, both of
10087978SPeter.Dunlap@Sun.COM * these actions will take place in the transport layer.
10097978SPeter.Dunlap@Sun.COM * If bufptr is set, then the caller has allocated memory (or more
10107978SPeter.Dunlap@Sun.COM * likely it's been passed from an upper layer), and we need only
10117978SPeter.Dunlap@Sun.COM * register the buffer for use with the transport layer.
10127978SPeter.Dunlap@Sun.COM */
10137978SPeter.Dunlap@Sun.COM if (bufptr == NULL) {
10147978SPeter.Dunlap@Sun.COM /*
10157978SPeter.Dunlap@Sun.COM * Allocate a buffer from the transport layer (which
10167978SPeter.Dunlap@Sun.COM * will also register the buffer for use).
10177978SPeter.Dunlap@Sun.COM */
10187978SPeter.Dunlap@Sun.COM rc = ic->ic_transport_ops->it_buf_alloc(buf, buflen);
10197978SPeter.Dunlap@Sun.COM if (rc != 0) {
10207978SPeter.Dunlap@Sun.COM idm_conn_rele(ic);
10217978SPeter.Dunlap@Sun.COM kmem_cache_free(idm.idm_buf_cache, buf);
10227978SPeter.Dunlap@Sun.COM return (NULL);
10237978SPeter.Dunlap@Sun.COM }
10247978SPeter.Dunlap@Sun.COM /* Set the bufalloc'd flag */
10257978SPeter.Dunlap@Sun.COM buf->idb_bufalloc = B_TRUE;
10267978SPeter.Dunlap@Sun.COM } else {
10277978SPeter.Dunlap@Sun.COM /*
10289162SPeter.Dunlap@Sun.COM * For large transfers, Set the passed bufptr into
10299162SPeter.Dunlap@Sun.COM * the buf handle, and register the handle with the
10309162SPeter.Dunlap@Sun.COM * transport layer. As memory registration with the
10319162SPeter.Dunlap@Sun.COM * transport layer is a time/cpu intensive operation,
10329162SPeter.Dunlap@Sun.COM * for small transfers (up to a pre-defined bcopy
10339162SPeter.Dunlap@Sun.COM * threshold), use pre-registered memory buffers
10349162SPeter.Dunlap@Sun.COM * and bcopy data at the appropriate time.
10357978SPeter.Dunlap@Sun.COM */
10367978SPeter.Dunlap@Sun.COM buf->idb_buf = bufptr;
10377978SPeter.Dunlap@Sun.COM
10387978SPeter.Dunlap@Sun.COM rc = ic->ic_transport_ops->it_buf_setup(buf);
10397978SPeter.Dunlap@Sun.COM if (rc != 0) {
10407978SPeter.Dunlap@Sun.COM idm_conn_rele(ic);
10417978SPeter.Dunlap@Sun.COM kmem_cache_free(idm.idm_buf_cache, buf);
10427978SPeter.Dunlap@Sun.COM return (NULL);
10437978SPeter.Dunlap@Sun.COM }
10449162SPeter.Dunlap@Sun.COM /*
10459162SPeter.Dunlap@Sun.COM * The transport layer is now expected to set the idb_bufalloc
10469162SPeter.Dunlap@Sun.COM * correctly to indicate if resources have been allocated.
10479162SPeter.Dunlap@Sun.COM */
10487978SPeter.Dunlap@Sun.COM }
10497978SPeter.Dunlap@Sun.COM
10509162SPeter.Dunlap@Sun.COM IDM_BUFPAT_SET(buf);
10519162SPeter.Dunlap@Sun.COM
10527978SPeter.Dunlap@Sun.COM return (buf);
10537978SPeter.Dunlap@Sun.COM }
10547978SPeter.Dunlap@Sun.COM
10557978SPeter.Dunlap@Sun.COM /*
10567978SPeter.Dunlap@Sun.COM * idm_buf_free
10577978SPeter.Dunlap@Sun.COM *
10587978SPeter.Dunlap@Sun.COM * Release a buffer handle along with the associated buffer that was allocated
10597978SPeter.Dunlap@Sun.COM * or assigned with idm_buf_alloc
10607978SPeter.Dunlap@Sun.COM */
10617978SPeter.Dunlap@Sun.COM void
idm_buf_free(idm_buf_t * buf)10627978SPeter.Dunlap@Sun.COM idm_buf_free(idm_buf_t *buf)
10637978SPeter.Dunlap@Sun.COM {
10647978SPeter.Dunlap@Sun.COM idm_conn_t *ic = buf->idb_ic;
10657978SPeter.Dunlap@Sun.COM
10667978SPeter.Dunlap@Sun.COM
10677978SPeter.Dunlap@Sun.COM buf->idb_task_binding = NULL;
10687978SPeter.Dunlap@Sun.COM
10697978SPeter.Dunlap@Sun.COM if (buf->idb_bufalloc) {
10707978SPeter.Dunlap@Sun.COM ic->ic_transport_ops->it_buf_free(buf);
10717978SPeter.Dunlap@Sun.COM } else {
10727978SPeter.Dunlap@Sun.COM ic->ic_transport_ops->it_buf_teardown(buf);
10737978SPeter.Dunlap@Sun.COM }
10747978SPeter.Dunlap@Sun.COM kmem_cache_free(idm.idm_buf_cache, buf);
10757978SPeter.Dunlap@Sun.COM idm_conn_rele(ic);
10767978SPeter.Dunlap@Sun.COM }
10777978SPeter.Dunlap@Sun.COM
10787978SPeter.Dunlap@Sun.COM /*
10797978SPeter.Dunlap@Sun.COM * idm_buf_bind_in
10807978SPeter.Dunlap@Sun.COM *
10817978SPeter.Dunlap@Sun.COM * This function associates a buffer with a task. This is only for use by the
10827978SPeter.Dunlap@Sun.COM * iSCSI initiator that will have only one buffer per transfer direction
10837978SPeter.Dunlap@Sun.COM *
10847978SPeter.Dunlap@Sun.COM */
10857978SPeter.Dunlap@Sun.COM void
idm_buf_bind_in(idm_task_t * idt,idm_buf_t * buf)10867978SPeter.Dunlap@Sun.COM idm_buf_bind_in(idm_task_t *idt, idm_buf_t *buf)
10877978SPeter.Dunlap@Sun.COM {
10887978SPeter.Dunlap@Sun.COM mutex_enter(&idt->idt_mutex);
10897978SPeter.Dunlap@Sun.COM idm_buf_bind_in_locked(idt, buf);
10907978SPeter.Dunlap@Sun.COM mutex_exit(&idt->idt_mutex);
10917978SPeter.Dunlap@Sun.COM }
10927978SPeter.Dunlap@Sun.COM
10937978SPeter.Dunlap@Sun.COM static void
idm_buf_bind_in_locked(idm_task_t * idt,idm_buf_t * buf)10947978SPeter.Dunlap@Sun.COM idm_buf_bind_in_locked(idm_task_t *idt, idm_buf_t *buf)
10957978SPeter.Dunlap@Sun.COM {
10967978SPeter.Dunlap@Sun.COM buf->idb_task_binding = idt;
10977978SPeter.Dunlap@Sun.COM buf->idb_ic = idt->idt_ic;
10987978SPeter.Dunlap@Sun.COM idm_listbuf_insert(&idt->idt_inbufv, buf);
10997978SPeter.Dunlap@Sun.COM }
11007978SPeter.Dunlap@Sun.COM
11017978SPeter.Dunlap@Sun.COM void
idm_buf_bind_out(idm_task_t * idt,idm_buf_t * buf)11027978SPeter.Dunlap@Sun.COM idm_buf_bind_out(idm_task_t *idt, idm_buf_t *buf)
11037978SPeter.Dunlap@Sun.COM {
11049162SPeter.Dunlap@Sun.COM /*
11059162SPeter.Dunlap@Sun.COM * For small transfers, the iSER transport delegates the IDM
11069162SPeter.Dunlap@Sun.COM * layer to bcopy the SCSI Write data for faster IOPS.
11079162SPeter.Dunlap@Sun.COM */
11089162SPeter.Dunlap@Sun.COM if (buf->idb_bufbcopy == B_TRUE) {
11099162SPeter.Dunlap@Sun.COM
11109162SPeter.Dunlap@Sun.COM bcopy(buf->idb_bufptr, buf->idb_buf, buf->idb_buflen);
11119162SPeter.Dunlap@Sun.COM }
11127978SPeter.Dunlap@Sun.COM mutex_enter(&idt->idt_mutex);
11137978SPeter.Dunlap@Sun.COM idm_buf_bind_out_locked(idt, buf);
11147978SPeter.Dunlap@Sun.COM mutex_exit(&idt->idt_mutex);
11157978SPeter.Dunlap@Sun.COM }
11167978SPeter.Dunlap@Sun.COM
11177978SPeter.Dunlap@Sun.COM static void
idm_buf_bind_out_locked(idm_task_t * idt,idm_buf_t * buf)11187978SPeter.Dunlap@Sun.COM idm_buf_bind_out_locked(idm_task_t *idt, idm_buf_t *buf)
11197978SPeter.Dunlap@Sun.COM {
11207978SPeter.Dunlap@Sun.COM buf->idb_task_binding = idt;
11217978SPeter.Dunlap@Sun.COM buf->idb_ic = idt->idt_ic;
11227978SPeter.Dunlap@Sun.COM idm_listbuf_insert(&idt->idt_outbufv, buf);
11237978SPeter.Dunlap@Sun.COM }
11247978SPeter.Dunlap@Sun.COM
11257978SPeter.Dunlap@Sun.COM void
idm_buf_unbind_in(idm_task_t * idt,idm_buf_t * buf)11267978SPeter.Dunlap@Sun.COM idm_buf_unbind_in(idm_task_t *idt, idm_buf_t *buf)
11277978SPeter.Dunlap@Sun.COM {
11289162SPeter.Dunlap@Sun.COM /*
11299162SPeter.Dunlap@Sun.COM * For small transfers, the iSER transport delegates the IDM
11309162SPeter.Dunlap@Sun.COM * layer to bcopy the SCSI Read data into the read buufer
11319162SPeter.Dunlap@Sun.COM * for faster IOPS.
11329162SPeter.Dunlap@Sun.COM */
11339162SPeter.Dunlap@Sun.COM if (buf->idb_bufbcopy == B_TRUE) {
11349162SPeter.Dunlap@Sun.COM bcopy(buf->idb_buf, buf->idb_bufptr, buf->idb_buflen);
11359162SPeter.Dunlap@Sun.COM }
11367978SPeter.Dunlap@Sun.COM mutex_enter(&idt->idt_mutex);
11377978SPeter.Dunlap@Sun.COM idm_buf_unbind_in_locked(idt, buf);
11387978SPeter.Dunlap@Sun.COM mutex_exit(&idt->idt_mutex);
11397978SPeter.Dunlap@Sun.COM }
11407978SPeter.Dunlap@Sun.COM
11417978SPeter.Dunlap@Sun.COM static void
idm_buf_unbind_in_locked(idm_task_t * idt,idm_buf_t * buf)11427978SPeter.Dunlap@Sun.COM idm_buf_unbind_in_locked(idm_task_t *idt, idm_buf_t *buf)
11437978SPeter.Dunlap@Sun.COM {
11447978SPeter.Dunlap@Sun.COM list_remove(&idt->idt_inbufv, buf);
11457978SPeter.Dunlap@Sun.COM }
11467978SPeter.Dunlap@Sun.COM
11477978SPeter.Dunlap@Sun.COM void
idm_buf_unbind_out(idm_task_t * idt,idm_buf_t * buf)11487978SPeter.Dunlap@Sun.COM idm_buf_unbind_out(idm_task_t *idt, idm_buf_t *buf)
11497978SPeter.Dunlap@Sun.COM {
11507978SPeter.Dunlap@Sun.COM mutex_enter(&idt->idt_mutex);
11517978SPeter.Dunlap@Sun.COM idm_buf_unbind_out_locked(idt, buf);
11527978SPeter.Dunlap@Sun.COM mutex_exit(&idt->idt_mutex);
11537978SPeter.Dunlap@Sun.COM }
11547978SPeter.Dunlap@Sun.COM
11557978SPeter.Dunlap@Sun.COM static void
idm_buf_unbind_out_locked(idm_task_t * idt,idm_buf_t * buf)11567978SPeter.Dunlap@Sun.COM idm_buf_unbind_out_locked(idm_task_t *idt, idm_buf_t *buf)
11577978SPeter.Dunlap@Sun.COM {
11587978SPeter.Dunlap@Sun.COM list_remove(&idt->idt_outbufv, buf);
11597978SPeter.Dunlap@Sun.COM }
11607978SPeter.Dunlap@Sun.COM
11617978SPeter.Dunlap@Sun.COM /*
11627978SPeter.Dunlap@Sun.COM * idm_buf_find() will lookup the idm_buf_t based on the relative offset in the
11637978SPeter.Dunlap@Sun.COM * iSCSI PDU
11647978SPeter.Dunlap@Sun.COM */
11657978SPeter.Dunlap@Sun.COM idm_buf_t *
idm_buf_find(void * lbuf,size_t data_offset)11667978SPeter.Dunlap@Sun.COM idm_buf_find(void *lbuf, size_t data_offset)
11677978SPeter.Dunlap@Sun.COM {
11687978SPeter.Dunlap@Sun.COM idm_buf_t *idb;
11697978SPeter.Dunlap@Sun.COM list_t *lst = (list_t *)lbuf;
11707978SPeter.Dunlap@Sun.COM
11717978SPeter.Dunlap@Sun.COM /* iterate through the list to find the buffer */
11727978SPeter.Dunlap@Sun.COM for (idb = list_head(lst); idb != NULL; idb = list_next(lst, idb)) {
11737978SPeter.Dunlap@Sun.COM
11747978SPeter.Dunlap@Sun.COM ASSERT((idb->idb_ic->ic_conn_type == CONN_TYPE_TGT) ||
11757978SPeter.Dunlap@Sun.COM (idb->idb_bufoffset == 0));
11767978SPeter.Dunlap@Sun.COM
11777978SPeter.Dunlap@Sun.COM if ((data_offset >= idb->idb_bufoffset) &&
11787978SPeter.Dunlap@Sun.COM (data_offset < (idb->idb_bufoffset + idb->idb_buflen))) {
11797978SPeter.Dunlap@Sun.COM
11807978SPeter.Dunlap@Sun.COM return (idb);
11817978SPeter.Dunlap@Sun.COM }
11827978SPeter.Dunlap@Sun.COM }
11837978SPeter.Dunlap@Sun.COM
11847978SPeter.Dunlap@Sun.COM return (NULL);
11857978SPeter.Dunlap@Sun.COM }
11867978SPeter.Dunlap@Sun.COM
11879162SPeter.Dunlap@Sun.COM void
idm_bufpat_set(idm_buf_t * idb)11889162SPeter.Dunlap@Sun.COM idm_bufpat_set(idm_buf_t *idb)
11899162SPeter.Dunlap@Sun.COM {
11909162SPeter.Dunlap@Sun.COM idm_bufpat_t *bufpat;
11919162SPeter.Dunlap@Sun.COM int len, i;
11929162SPeter.Dunlap@Sun.COM
11939162SPeter.Dunlap@Sun.COM len = idb->idb_buflen;
11949162SPeter.Dunlap@Sun.COM len = (len / sizeof (idm_bufpat_t)) * sizeof (idm_bufpat_t);
11959162SPeter.Dunlap@Sun.COM
11969162SPeter.Dunlap@Sun.COM bufpat = idb->idb_buf;
11979162SPeter.Dunlap@Sun.COM for (i = 0; i < len; i += sizeof (idm_bufpat_t)) {
11989162SPeter.Dunlap@Sun.COM bufpat->bufpat_idb = idb;
11999162SPeter.Dunlap@Sun.COM bufpat->bufpat_bufmagic = IDM_BUF_MAGIC;
12009162SPeter.Dunlap@Sun.COM bufpat->bufpat_offset = i;
12019162SPeter.Dunlap@Sun.COM bufpat++;
12029162SPeter.Dunlap@Sun.COM }
12039162SPeter.Dunlap@Sun.COM }
12049162SPeter.Dunlap@Sun.COM
12059162SPeter.Dunlap@Sun.COM boolean_t
idm_bufpat_check(idm_buf_t * idb,int check_len,idm_bufpat_check_type_t type)12069162SPeter.Dunlap@Sun.COM idm_bufpat_check(idm_buf_t *idb, int check_len, idm_bufpat_check_type_t type)
12079162SPeter.Dunlap@Sun.COM {
12089162SPeter.Dunlap@Sun.COM idm_bufpat_t *bufpat;
12099162SPeter.Dunlap@Sun.COM int len, i;
12109162SPeter.Dunlap@Sun.COM
12119162SPeter.Dunlap@Sun.COM len = (type == BP_CHECK_QUICK) ? sizeof (idm_bufpat_t) : check_len;
12129162SPeter.Dunlap@Sun.COM len = (len / sizeof (idm_bufpat_t)) * sizeof (idm_bufpat_t);
12139162SPeter.Dunlap@Sun.COM ASSERT(len <= idb->idb_buflen);
12149162SPeter.Dunlap@Sun.COM bufpat = idb->idb_buf;
12159162SPeter.Dunlap@Sun.COM
12169162SPeter.Dunlap@Sun.COM /*
12179162SPeter.Dunlap@Sun.COM * Don't check the pattern in buffers that came from outside IDM
12189162SPeter.Dunlap@Sun.COM * (these will be buffers from the initiator that we opted not
12199162SPeter.Dunlap@Sun.COM * to double-buffer)
12209162SPeter.Dunlap@Sun.COM */
12219162SPeter.Dunlap@Sun.COM if (!idb->idb_bufalloc)
12229162SPeter.Dunlap@Sun.COM return (B_FALSE);
12239162SPeter.Dunlap@Sun.COM
12249162SPeter.Dunlap@Sun.COM /*
12259162SPeter.Dunlap@Sun.COM * Return true if we find the pattern anywhere in the buffer
12269162SPeter.Dunlap@Sun.COM */
12279162SPeter.Dunlap@Sun.COM for (i = 0; i < len; i += sizeof (idm_bufpat_t)) {
12289162SPeter.Dunlap@Sun.COM if (BUFPAT_MATCH(bufpat, idb)) {
12299162SPeter.Dunlap@Sun.COM IDM_CONN_LOG(CE_WARN, "idm_bufpat_check found: "
12309162SPeter.Dunlap@Sun.COM "idb %p bufpat %p "
12319162SPeter.Dunlap@Sun.COM "bufpat_idb=%p bufmagic=%08x offset=%08x",
12329162SPeter.Dunlap@Sun.COM (void *)idb, (void *)bufpat, bufpat->bufpat_idb,
12339162SPeter.Dunlap@Sun.COM bufpat->bufpat_bufmagic, bufpat->bufpat_offset);
12349162SPeter.Dunlap@Sun.COM DTRACE_PROBE2(bufpat__pattern__found,
12359162SPeter.Dunlap@Sun.COM idm_buf_t *, idb, idm_bufpat_t *, bufpat);
12369162SPeter.Dunlap@Sun.COM if (type == BP_CHECK_ASSERT) {
12379162SPeter.Dunlap@Sun.COM ASSERT(0);
12389162SPeter.Dunlap@Sun.COM }
12399162SPeter.Dunlap@Sun.COM return (B_TRUE);
12409162SPeter.Dunlap@Sun.COM }
12419162SPeter.Dunlap@Sun.COM bufpat++;
12429162SPeter.Dunlap@Sun.COM }
12439162SPeter.Dunlap@Sun.COM
12449162SPeter.Dunlap@Sun.COM return (B_FALSE);
12459162SPeter.Dunlap@Sun.COM }
12469162SPeter.Dunlap@Sun.COM
12477978SPeter.Dunlap@Sun.COM /*
12487978SPeter.Dunlap@Sun.COM * idm_task_alloc
12497978SPeter.Dunlap@Sun.COM *
12507978SPeter.Dunlap@Sun.COM * This function will allocate a idm_task_t structure. A task tag is also
12517978SPeter.Dunlap@Sun.COM * generated and saved in idt_tt. The task is not active.
12527978SPeter.Dunlap@Sun.COM */
12537978SPeter.Dunlap@Sun.COM idm_task_t *
idm_task_alloc(idm_conn_t * ic)12547978SPeter.Dunlap@Sun.COM idm_task_alloc(idm_conn_t *ic)
12557978SPeter.Dunlap@Sun.COM {
12567978SPeter.Dunlap@Sun.COM idm_task_t *idt;
12577978SPeter.Dunlap@Sun.COM
12587978SPeter.Dunlap@Sun.COM ASSERT(ic != NULL);
12597978SPeter.Dunlap@Sun.COM
12607978SPeter.Dunlap@Sun.COM /* Don't allocate new tasks if we are not in FFP */
12617978SPeter.Dunlap@Sun.COM if (!ic->ic_ffp) {
12627978SPeter.Dunlap@Sun.COM return (NULL);
12637978SPeter.Dunlap@Sun.COM }
12647978SPeter.Dunlap@Sun.COM idt = kmem_cache_alloc(idm.idm_task_cache, KM_NOSLEEP);
12657978SPeter.Dunlap@Sun.COM if (idt == NULL) {
12667978SPeter.Dunlap@Sun.COM return (NULL);
12677978SPeter.Dunlap@Sun.COM }
12687978SPeter.Dunlap@Sun.COM
12697978SPeter.Dunlap@Sun.COM ASSERT(list_is_empty(&idt->idt_inbufv));
12707978SPeter.Dunlap@Sun.COM ASSERT(list_is_empty(&idt->idt_outbufv));
12717978SPeter.Dunlap@Sun.COM
127211078SPeter.Cudhea@Sun.COM mutex_enter(&ic->ic_state_mutex);
127311078SPeter.Cudhea@Sun.COM if (!ic->ic_ffp) {
127411078SPeter.Cudhea@Sun.COM mutex_exit(&ic->ic_state_mutex);
127511078SPeter.Cudhea@Sun.COM kmem_cache_free(idm.idm_task_cache, idt);
127611078SPeter.Cudhea@Sun.COM return (NULL);
127711078SPeter.Cudhea@Sun.COM }
12787978SPeter.Dunlap@Sun.COM idm_conn_hold(ic);
12797978SPeter.Dunlap@Sun.COM mutex_exit(&ic->ic_state_mutex);
12807978SPeter.Dunlap@Sun.COM
12817978SPeter.Dunlap@Sun.COM idt->idt_state = TASK_IDLE;
12827978SPeter.Dunlap@Sun.COM idt->idt_ic = ic;
12837978SPeter.Dunlap@Sun.COM idt->idt_private = NULL;
12847978SPeter.Dunlap@Sun.COM idt->idt_exp_datasn = 0;
12857978SPeter.Dunlap@Sun.COM idt->idt_exp_rttsn = 0;
128611081SPriya.Krishnan@Sun.COM idt->idt_flags = 0;
12877978SPeter.Dunlap@Sun.COM return (idt);
12887978SPeter.Dunlap@Sun.COM }
12897978SPeter.Dunlap@Sun.COM
12907978SPeter.Dunlap@Sun.COM /*
12917978SPeter.Dunlap@Sun.COM * idm_task_start
12927978SPeter.Dunlap@Sun.COM *
12939162SPeter.Dunlap@Sun.COM * Mark the task active and initialize some stats. The caller
12947978SPeter.Dunlap@Sun.COM * sets up the idm_task_t structure with a prior call to idm_task_alloc().
12957978SPeter.Dunlap@Sun.COM * The task service does not function as a task/work engine, it is the
12967978SPeter.Dunlap@Sun.COM * responsibility of the initiator to start the data transfer and free the
12977978SPeter.Dunlap@Sun.COM * resources.
12987978SPeter.Dunlap@Sun.COM */
12997978SPeter.Dunlap@Sun.COM void
idm_task_start(idm_task_t * idt,uintptr_t handle)13007978SPeter.Dunlap@Sun.COM idm_task_start(idm_task_t *idt, uintptr_t handle)
13017978SPeter.Dunlap@Sun.COM {
13027978SPeter.Dunlap@Sun.COM ASSERT(idt != NULL);
13037978SPeter.Dunlap@Sun.COM
13047978SPeter.Dunlap@Sun.COM /* mark the task as ACTIVE */
13057978SPeter.Dunlap@Sun.COM idt->idt_state = TASK_ACTIVE;
13067978SPeter.Dunlap@Sun.COM idt->idt_client_handle = handle;
13077978SPeter.Dunlap@Sun.COM idt->idt_tx_to_ini_start = idt->idt_tx_to_ini_done =
13089162SPeter.Dunlap@Sun.COM idt->idt_rx_from_ini_start = idt->idt_rx_from_ini_done =
13099162SPeter.Dunlap@Sun.COM idt->idt_tx_bytes = idt->idt_rx_bytes = 0;
13107978SPeter.Dunlap@Sun.COM }
13117978SPeter.Dunlap@Sun.COM
13127978SPeter.Dunlap@Sun.COM /*
13137978SPeter.Dunlap@Sun.COM * idm_task_done
13147978SPeter.Dunlap@Sun.COM *
13159162SPeter.Dunlap@Sun.COM * This function sets the state to indicate that the task is no longer active.
13167978SPeter.Dunlap@Sun.COM */
13177978SPeter.Dunlap@Sun.COM void
idm_task_done(idm_task_t * idt)13187978SPeter.Dunlap@Sun.COM idm_task_done(idm_task_t *idt)
13197978SPeter.Dunlap@Sun.COM {
13207978SPeter.Dunlap@Sun.COM ASSERT(idt != NULL);
13219162SPeter.Dunlap@Sun.COM
13229162SPeter.Dunlap@Sun.COM mutex_enter(&idt->idt_mutex);
13239162SPeter.Dunlap@Sun.COM idt->idt_state = TASK_IDLE;
13249162SPeter.Dunlap@Sun.COM mutex_exit(&idt->idt_mutex);
13257978SPeter.Dunlap@Sun.COM
13269162SPeter.Dunlap@Sun.COM /*
13279162SPeter.Dunlap@Sun.COM * Although unlikely it is possible for a reference to come in after
13289162SPeter.Dunlap@Sun.COM * the client has decided the task is over but before we've marked
13299162SPeter.Dunlap@Sun.COM * the task idle. One specific unavoidable scenario is the case where
13309162SPeter.Dunlap@Sun.COM * received PDU with the matching ITT/TTT results in a successful
13319162SPeter.Dunlap@Sun.COM * lookup of this task. We are at the mercy of the remote node in
13329162SPeter.Dunlap@Sun.COM * that case so we need to handle it. Now that the task state
13339162SPeter.Dunlap@Sun.COM * has changed no more references will occur so a simple call to
13349162SPeter.Dunlap@Sun.COM * idm_refcnt_wait_ref should deal with the situation.
13359162SPeter.Dunlap@Sun.COM */
13369162SPeter.Dunlap@Sun.COM idm_refcnt_wait_ref(&idt->idt_refcnt);
13377978SPeter.Dunlap@Sun.COM idm_refcnt_reset(&idt->idt_refcnt);
13387978SPeter.Dunlap@Sun.COM }
13397978SPeter.Dunlap@Sun.COM
13407978SPeter.Dunlap@Sun.COM /*
13417978SPeter.Dunlap@Sun.COM * idm_task_free
13427978SPeter.Dunlap@Sun.COM *
13437978SPeter.Dunlap@Sun.COM * This function will free the Task Tag and the memory allocated for the task
13447978SPeter.Dunlap@Sun.COM * idm_task_done should be called prior to this call
13457978SPeter.Dunlap@Sun.COM */
13467978SPeter.Dunlap@Sun.COM void
idm_task_free(idm_task_t * idt)13477978SPeter.Dunlap@Sun.COM idm_task_free(idm_task_t *idt)
13487978SPeter.Dunlap@Sun.COM {
13499162SPeter.Dunlap@Sun.COM idm_conn_t *ic;
13507978SPeter.Dunlap@Sun.COM
13517978SPeter.Dunlap@Sun.COM ASSERT(idt != NULL);
13529162SPeter.Dunlap@Sun.COM ASSERT(idt->idt_refcnt.ir_refcnt == 0);
13537978SPeter.Dunlap@Sun.COM ASSERT(idt->idt_state == TASK_IDLE);
13547978SPeter.Dunlap@Sun.COM
13559162SPeter.Dunlap@Sun.COM ic = idt->idt_ic;
13569162SPeter.Dunlap@Sun.COM
13577978SPeter.Dunlap@Sun.COM /*
13587978SPeter.Dunlap@Sun.COM * It's possible for items to still be in the idt_inbufv list if
135911078SPeter.Cudhea@Sun.COM * they were added after idm_free_task_rsrc was called. We rely on
13607978SPeter.Dunlap@Sun.COM * STMF to free all buffers associated with the task however STMF
13617978SPeter.Dunlap@Sun.COM * doesn't know that we have this reference to the buffers.
13627978SPeter.Dunlap@Sun.COM * Use list_create so that we don't end up with stale references
13637978SPeter.Dunlap@Sun.COM * to these buffers.
13647978SPeter.Dunlap@Sun.COM */
13657978SPeter.Dunlap@Sun.COM list_create(&idt->idt_inbufv, sizeof (idm_buf_t),
13667978SPeter.Dunlap@Sun.COM offsetof(idm_buf_t, idb_buflink));
13677978SPeter.Dunlap@Sun.COM list_create(&idt->idt_outbufv, sizeof (idm_buf_t),
13687978SPeter.Dunlap@Sun.COM offsetof(idm_buf_t, idb_buflink));
13697978SPeter.Dunlap@Sun.COM
13707978SPeter.Dunlap@Sun.COM kmem_cache_free(idm.idm_task_cache, idt);
13717978SPeter.Dunlap@Sun.COM
13727978SPeter.Dunlap@Sun.COM idm_conn_rele(ic);
13737978SPeter.Dunlap@Sun.COM }
13747978SPeter.Dunlap@Sun.COM
13757978SPeter.Dunlap@Sun.COM /*
13769162SPeter.Dunlap@Sun.COM * idm_task_find_common
13779162SPeter.Dunlap@Sun.COM * common code for idm_task_find() and idm_task_find_and_complete()
13787978SPeter.Dunlap@Sun.COM */
13797978SPeter.Dunlap@Sun.COM /*ARGSUSED*/
13809162SPeter.Dunlap@Sun.COM static idm_task_t *
idm_task_find_common(idm_conn_t * ic,uint32_t itt,uint32_t ttt,boolean_t complete)13819162SPeter.Dunlap@Sun.COM idm_task_find_common(idm_conn_t *ic, uint32_t itt, uint32_t ttt,
13829162SPeter.Dunlap@Sun.COM boolean_t complete)
13837978SPeter.Dunlap@Sun.COM {
13847978SPeter.Dunlap@Sun.COM uint32_t tt, client_handle;
13857978SPeter.Dunlap@Sun.COM idm_task_t *idt;
13867978SPeter.Dunlap@Sun.COM
13877978SPeter.Dunlap@Sun.COM /*
13887978SPeter.Dunlap@Sun.COM * Must match both itt and ttt. The table is indexed by itt
13897978SPeter.Dunlap@Sun.COM * for initiator connections and ttt for target connections.
13907978SPeter.Dunlap@Sun.COM */
13917978SPeter.Dunlap@Sun.COM if (IDM_CONN_ISTGT(ic)) {
13927978SPeter.Dunlap@Sun.COM tt = ttt;
13937978SPeter.Dunlap@Sun.COM client_handle = itt;
13947978SPeter.Dunlap@Sun.COM } else {
13957978SPeter.Dunlap@Sun.COM tt = itt;
13967978SPeter.Dunlap@Sun.COM client_handle = ttt;
13977978SPeter.Dunlap@Sun.COM }
13987978SPeter.Dunlap@Sun.COM
13997978SPeter.Dunlap@Sun.COM rw_enter(&idm.idm_taskid_table_lock, RW_READER);
14007978SPeter.Dunlap@Sun.COM if (tt >= idm.idm_taskid_max) {
14017978SPeter.Dunlap@Sun.COM rw_exit(&idm.idm_taskid_table_lock);
14027978SPeter.Dunlap@Sun.COM return (NULL);
14037978SPeter.Dunlap@Sun.COM }
14047978SPeter.Dunlap@Sun.COM
14057978SPeter.Dunlap@Sun.COM idt = idm.idm_taskid_table[tt];
14067978SPeter.Dunlap@Sun.COM
14077978SPeter.Dunlap@Sun.COM if (idt != NULL) {
14087978SPeter.Dunlap@Sun.COM mutex_enter(&idt->idt_mutex);
14097978SPeter.Dunlap@Sun.COM if ((idt->idt_state != TASK_ACTIVE) ||
14109162SPeter.Dunlap@Sun.COM (idt->idt_ic != ic) ||
14117978SPeter.Dunlap@Sun.COM (IDM_CONN_ISTGT(ic) &&
14127978SPeter.Dunlap@Sun.COM (idt->idt_client_handle != client_handle))) {
14137978SPeter.Dunlap@Sun.COM /*
14149162SPeter.Dunlap@Sun.COM * Task doesn't match or task is aborting and
14159162SPeter.Dunlap@Sun.COM * we don't want any more references.
14167978SPeter.Dunlap@Sun.COM */
14179162SPeter.Dunlap@Sun.COM if ((idt->idt_ic != ic) &&
14189162SPeter.Dunlap@Sun.COM (idt->idt_state == TASK_ACTIVE) &&
14199162SPeter.Dunlap@Sun.COM (IDM_CONN_ISINI(ic) || idt->idt_client_handle ==
14209162SPeter.Dunlap@Sun.COM client_handle)) {
14219162SPeter.Dunlap@Sun.COM IDM_CONN_LOG(CE_WARN,
14229162SPeter.Dunlap@Sun.COM "idm_task_find: wrong connection %p != %p",
14239162SPeter.Dunlap@Sun.COM (void *)ic, (void *)idt->idt_ic);
14249162SPeter.Dunlap@Sun.COM }
14257978SPeter.Dunlap@Sun.COM mutex_exit(&idt->idt_mutex);
14267978SPeter.Dunlap@Sun.COM rw_exit(&idm.idm_taskid_table_lock);
14277978SPeter.Dunlap@Sun.COM return (NULL);
14287978SPeter.Dunlap@Sun.COM }
14297978SPeter.Dunlap@Sun.COM idm_task_hold(idt);
14309162SPeter.Dunlap@Sun.COM /*
14319162SPeter.Dunlap@Sun.COM * Set the task state to TASK_COMPLETE so it can no longer
14329162SPeter.Dunlap@Sun.COM * be found or aborted.
14339162SPeter.Dunlap@Sun.COM */
14349162SPeter.Dunlap@Sun.COM if (B_TRUE == complete)
14359162SPeter.Dunlap@Sun.COM idt->idt_state = TASK_COMPLETE;
14367978SPeter.Dunlap@Sun.COM mutex_exit(&idt->idt_mutex);
14377978SPeter.Dunlap@Sun.COM }
14387978SPeter.Dunlap@Sun.COM rw_exit(&idm.idm_taskid_table_lock);
14397978SPeter.Dunlap@Sun.COM
14407978SPeter.Dunlap@Sun.COM return (idt);
14417978SPeter.Dunlap@Sun.COM }
14427978SPeter.Dunlap@Sun.COM
14437978SPeter.Dunlap@Sun.COM /*
14449162SPeter.Dunlap@Sun.COM * This function looks up a task by task tag.
14459162SPeter.Dunlap@Sun.COM */
14469162SPeter.Dunlap@Sun.COM idm_task_t *
idm_task_find(idm_conn_t * ic,uint32_t itt,uint32_t ttt)14479162SPeter.Dunlap@Sun.COM idm_task_find(idm_conn_t *ic, uint32_t itt, uint32_t ttt)
14489162SPeter.Dunlap@Sun.COM {
14499162SPeter.Dunlap@Sun.COM return (idm_task_find_common(ic, itt, ttt, B_FALSE));
14509162SPeter.Dunlap@Sun.COM }
14519162SPeter.Dunlap@Sun.COM
14529162SPeter.Dunlap@Sun.COM /*
14539162SPeter.Dunlap@Sun.COM * This function looks up a task by task tag. If found, the task state
14549162SPeter.Dunlap@Sun.COM * is atomically set to TASK_COMPLETE so it can longer be found or aborted.
14559162SPeter.Dunlap@Sun.COM */
14569162SPeter.Dunlap@Sun.COM idm_task_t *
idm_task_find_and_complete(idm_conn_t * ic,uint32_t itt,uint32_t ttt)14579162SPeter.Dunlap@Sun.COM idm_task_find_and_complete(idm_conn_t *ic, uint32_t itt, uint32_t ttt)
14589162SPeter.Dunlap@Sun.COM {
14599162SPeter.Dunlap@Sun.COM return (idm_task_find_common(ic, itt, ttt, B_TRUE));
14609162SPeter.Dunlap@Sun.COM }
14619162SPeter.Dunlap@Sun.COM
14629162SPeter.Dunlap@Sun.COM /*
14637978SPeter.Dunlap@Sun.COM * idm_task_find_by_handle
14647978SPeter.Dunlap@Sun.COM *
14657978SPeter.Dunlap@Sun.COM * This function looks up a task by the client-private idt_client_handle.
14667978SPeter.Dunlap@Sun.COM *
14677978SPeter.Dunlap@Sun.COM * This function should NEVER be called in the performance path. It is
14687978SPeter.Dunlap@Sun.COM * intended strictly for error recovery/task management.
14697978SPeter.Dunlap@Sun.COM */
14707978SPeter.Dunlap@Sun.COM /*ARGSUSED*/
14717978SPeter.Dunlap@Sun.COM void *
idm_task_find_by_handle(idm_conn_t * ic,uintptr_t handle)14727978SPeter.Dunlap@Sun.COM idm_task_find_by_handle(idm_conn_t *ic, uintptr_t handle)
14737978SPeter.Dunlap@Sun.COM {
14747978SPeter.Dunlap@Sun.COM idm_task_t *idt = NULL;
14757978SPeter.Dunlap@Sun.COM int idx = 0;
14767978SPeter.Dunlap@Sun.COM
14777978SPeter.Dunlap@Sun.COM rw_enter(&idm.idm_taskid_table_lock, RW_READER);
14787978SPeter.Dunlap@Sun.COM
14797978SPeter.Dunlap@Sun.COM for (idx = 0; idx < idm.idm_taskid_max; idx++) {
14807978SPeter.Dunlap@Sun.COM idt = idm.idm_taskid_table[idx];
14817978SPeter.Dunlap@Sun.COM
14827978SPeter.Dunlap@Sun.COM if (idt == NULL)
14837978SPeter.Dunlap@Sun.COM continue;
14847978SPeter.Dunlap@Sun.COM
14857978SPeter.Dunlap@Sun.COM mutex_enter(&idt->idt_mutex);
14867978SPeter.Dunlap@Sun.COM
14877978SPeter.Dunlap@Sun.COM if (idt->idt_state != TASK_ACTIVE) {
14887978SPeter.Dunlap@Sun.COM /*
14897978SPeter.Dunlap@Sun.COM * Task is either in suspend, abort, or already
14907978SPeter.Dunlap@Sun.COM * complete.
14917978SPeter.Dunlap@Sun.COM */
14927978SPeter.Dunlap@Sun.COM mutex_exit(&idt->idt_mutex);
14937978SPeter.Dunlap@Sun.COM continue;
14947978SPeter.Dunlap@Sun.COM }
14957978SPeter.Dunlap@Sun.COM
14967978SPeter.Dunlap@Sun.COM if (idt->idt_client_handle == handle) {
14977978SPeter.Dunlap@Sun.COM idm_task_hold(idt);
14987978SPeter.Dunlap@Sun.COM mutex_exit(&idt->idt_mutex);
14997978SPeter.Dunlap@Sun.COM break;
15007978SPeter.Dunlap@Sun.COM }
15017978SPeter.Dunlap@Sun.COM
15027978SPeter.Dunlap@Sun.COM mutex_exit(&idt->idt_mutex);
15037978SPeter.Dunlap@Sun.COM }
15047978SPeter.Dunlap@Sun.COM
15057978SPeter.Dunlap@Sun.COM rw_exit(&idm.idm_taskid_table_lock);
15067978SPeter.Dunlap@Sun.COM
15077978SPeter.Dunlap@Sun.COM if ((idt == NULL) || (idx == idm.idm_taskid_max))
15087978SPeter.Dunlap@Sun.COM return (NULL);
15097978SPeter.Dunlap@Sun.COM
15107978SPeter.Dunlap@Sun.COM return (idt->idt_private);
15117978SPeter.Dunlap@Sun.COM }
15127978SPeter.Dunlap@Sun.COM
15137978SPeter.Dunlap@Sun.COM void
idm_task_hold(idm_task_t * idt)15147978SPeter.Dunlap@Sun.COM idm_task_hold(idm_task_t *idt)
15157978SPeter.Dunlap@Sun.COM {
15167978SPeter.Dunlap@Sun.COM idm_refcnt_hold(&idt->idt_refcnt);
15177978SPeter.Dunlap@Sun.COM }
15187978SPeter.Dunlap@Sun.COM
15197978SPeter.Dunlap@Sun.COM void
idm_task_rele(idm_task_t * idt)15207978SPeter.Dunlap@Sun.COM idm_task_rele(idm_task_t *idt)
15217978SPeter.Dunlap@Sun.COM {
15227978SPeter.Dunlap@Sun.COM idm_refcnt_rele(&idt->idt_refcnt);
15237978SPeter.Dunlap@Sun.COM }
15247978SPeter.Dunlap@Sun.COM
15257978SPeter.Dunlap@Sun.COM void
idm_task_abort(idm_conn_t * ic,idm_task_t * idt,idm_abort_type_t abort_type)15267978SPeter.Dunlap@Sun.COM idm_task_abort(idm_conn_t *ic, idm_task_t *idt, idm_abort_type_t abort_type)
15277978SPeter.Dunlap@Sun.COM {
15287978SPeter.Dunlap@Sun.COM idm_task_t *task;
15297978SPeter.Dunlap@Sun.COM int idx;
15307978SPeter.Dunlap@Sun.COM
15317978SPeter.Dunlap@Sun.COM /*
15327978SPeter.Dunlap@Sun.COM * Passing NULL as the task indicates that all tasks
15337978SPeter.Dunlap@Sun.COM * for this connection should be aborted.
15347978SPeter.Dunlap@Sun.COM */
15357978SPeter.Dunlap@Sun.COM if (idt == NULL) {
15367978SPeter.Dunlap@Sun.COM /*
15377978SPeter.Dunlap@Sun.COM * Only the connection state machine should ask for
15387978SPeter.Dunlap@Sun.COM * all tasks to abort and this should never happen in FFP.
15397978SPeter.Dunlap@Sun.COM */
15407978SPeter.Dunlap@Sun.COM ASSERT(!ic->ic_ffp);
15417978SPeter.Dunlap@Sun.COM rw_enter(&idm.idm_taskid_table_lock, RW_READER);
15427978SPeter.Dunlap@Sun.COM for (idx = 0; idx < idm.idm_taskid_max; idx++) {
15437978SPeter.Dunlap@Sun.COM task = idm.idm_taskid_table[idx];
15449162SPeter.Dunlap@Sun.COM if (task == NULL)
15459162SPeter.Dunlap@Sun.COM continue;
15469162SPeter.Dunlap@Sun.COM mutex_enter(&task->idt_mutex);
15479162SPeter.Dunlap@Sun.COM if ((task->idt_state != TASK_IDLE) &&
15489162SPeter.Dunlap@Sun.COM (task->idt_state != TASK_COMPLETE) &&
15497978SPeter.Dunlap@Sun.COM (task->idt_ic == ic)) {
15507978SPeter.Dunlap@Sun.COM rw_exit(&idm.idm_taskid_table_lock);
15517978SPeter.Dunlap@Sun.COM idm_task_abort_one(ic, task, abort_type);
15527978SPeter.Dunlap@Sun.COM rw_enter(&idm.idm_taskid_table_lock, RW_READER);
15539162SPeter.Dunlap@Sun.COM } else
15549162SPeter.Dunlap@Sun.COM mutex_exit(&task->idt_mutex);
15557978SPeter.Dunlap@Sun.COM }
15567978SPeter.Dunlap@Sun.COM rw_exit(&idm.idm_taskid_table_lock);
15577978SPeter.Dunlap@Sun.COM } else {
15589162SPeter.Dunlap@Sun.COM mutex_enter(&idt->idt_mutex);
15597978SPeter.Dunlap@Sun.COM idm_task_abort_one(ic, idt, abort_type);
15607978SPeter.Dunlap@Sun.COM }
15617978SPeter.Dunlap@Sun.COM }
15627978SPeter.Dunlap@Sun.COM
15637978SPeter.Dunlap@Sun.COM static void
idm_task_abort_unref_cb(void * ref)15647978SPeter.Dunlap@Sun.COM idm_task_abort_unref_cb(void *ref)
15657978SPeter.Dunlap@Sun.COM {
15667978SPeter.Dunlap@Sun.COM idm_task_t *idt = ref;
15677978SPeter.Dunlap@Sun.COM
15687978SPeter.Dunlap@Sun.COM mutex_enter(&idt->idt_mutex);
15697978SPeter.Dunlap@Sun.COM switch (idt->idt_state) {
15707978SPeter.Dunlap@Sun.COM case TASK_SUSPENDING:
15717978SPeter.Dunlap@Sun.COM idt->idt_state = TASK_SUSPENDED;
15727978SPeter.Dunlap@Sun.COM mutex_exit(&idt->idt_mutex);
15737978SPeter.Dunlap@Sun.COM idm_task_aborted(idt, IDM_STATUS_SUSPENDED);
15747978SPeter.Dunlap@Sun.COM return;
15757978SPeter.Dunlap@Sun.COM case TASK_ABORTING:
15767978SPeter.Dunlap@Sun.COM idt->idt_state = TASK_ABORTED;
15777978SPeter.Dunlap@Sun.COM mutex_exit(&idt->idt_mutex);
15787978SPeter.Dunlap@Sun.COM idm_task_aborted(idt, IDM_STATUS_ABORTED);
15797978SPeter.Dunlap@Sun.COM return;
15807978SPeter.Dunlap@Sun.COM default:
15817978SPeter.Dunlap@Sun.COM mutex_exit(&idt->idt_mutex);
15827978SPeter.Dunlap@Sun.COM ASSERT(0);
15837978SPeter.Dunlap@Sun.COM break;
15847978SPeter.Dunlap@Sun.COM }
15857978SPeter.Dunlap@Sun.COM }
15867978SPeter.Dunlap@Sun.COM
15879162SPeter.Dunlap@Sun.COM /*
15889162SPeter.Dunlap@Sun.COM * Abort the idm task.
15899162SPeter.Dunlap@Sun.COM * Caller must hold the task mutex, which will be released before return
15909162SPeter.Dunlap@Sun.COM */
15917978SPeter.Dunlap@Sun.COM static void
idm_task_abort_one(idm_conn_t * ic,idm_task_t * idt,idm_abort_type_t abort_type)15927978SPeter.Dunlap@Sun.COM idm_task_abort_one(idm_conn_t *ic, idm_task_t *idt, idm_abort_type_t abort_type)
15937978SPeter.Dunlap@Sun.COM {
15947978SPeter.Dunlap@Sun.COM /* Caller must hold connection mutex */
15959162SPeter.Dunlap@Sun.COM ASSERT(mutex_owned(&idt->idt_mutex));
15967978SPeter.Dunlap@Sun.COM switch (idt->idt_state) {
15977978SPeter.Dunlap@Sun.COM case TASK_ACTIVE:
15987978SPeter.Dunlap@Sun.COM switch (abort_type) {
15997978SPeter.Dunlap@Sun.COM case AT_INTERNAL_SUSPEND:
16007978SPeter.Dunlap@Sun.COM /* Call transport to release any resources */
16017978SPeter.Dunlap@Sun.COM idt->idt_state = TASK_SUSPENDING;
16027978SPeter.Dunlap@Sun.COM mutex_exit(&idt->idt_mutex);
16037978SPeter.Dunlap@Sun.COM ic->ic_transport_ops->it_free_task_rsrc(idt);
16047978SPeter.Dunlap@Sun.COM
16057978SPeter.Dunlap@Sun.COM /*
16067978SPeter.Dunlap@Sun.COM * Wait for outstanding references. When all
16077978SPeter.Dunlap@Sun.COM * references are released the callback will call
16087978SPeter.Dunlap@Sun.COM * idm_task_aborted().
16097978SPeter.Dunlap@Sun.COM */
16107978SPeter.Dunlap@Sun.COM idm_refcnt_async_wait_ref(&idt->idt_refcnt,
16117978SPeter.Dunlap@Sun.COM &idm_task_abort_unref_cb);
16127978SPeter.Dunlap@Sun.COM return;
16137978SPeter.Dunlap@Sun.COM case AT_INTERNAL_ABORT:
16147978SPeter.Dunlap@Sun.COM case AT_TASK_MGMT_ABORT:
16157978SPeter.Dunlap@Sun.COM idt->idt_state = TASK_ABORTING;
16167978SPeter.Dunlap@Sun.COM mutex_exit(&idt->idt_mutex);
16177978SPeter.Dunlap@Sun.COM ic->ic_transport_ops->it_free_task_rsrc(idt);
16187978SPeter.Dunlap@Sun.COM
16197978SPeter.Dunlap@Sun.COM /*
16207978SPeter.Dunlap@Sun.COM * Wait for outstanding references. When all
16217978SPeter.Dunlap@Sun.COM * references are released the callback will call
16227978SPeter.Dunlap@Sun.COM * idm_task_aborted().
16237978SPeter.Dunlap@Sun.COM */
16247978SPeter.Dunlap@Sun.COM idm_refcnt_async_wait_ref(&idt->idt_refcnt,
16257978SPeter.Dunlap@Sun.COM &idm_task_abort_unref_cb);
16267978SPeter.Dunlap@Sun.COM return;
16277978SPeter.Dunlap@Sun.COM default:
16287978SPeter.Dunlap@Sun.COM ASSERT(0);
16297978SPeter.Dunlap@Sun.COM }
16307978SPeter.Dunlap@Sun.COM break;
16317978SPeter.Dunlap@Sun.COM case TASK_SUSPENDING:
16327978SPeter.Dunlap@Sun.COM /* Already called transport_free_task_rsrc(); */
16337978SPeter.Dunlap@Sun.COM switch (abort_type) {
16347978SPeter.Dunlap@Sun.COM case AT_INTERNAL_SUSPEND:
16357978SPeter.Dunlap@Sun.COM /* Already doing it */
16367978SPeter.Dunlap@Sun.COM break;
16377978SPeter.Dunlap@Sun.COM case AT_INTERNAL_ABORT:
16387978SPeter.Dunlap@Sun.COM case AT_TASK_MGMT_ABORT:
16397978SPeter.Dunlap@Sun.COM idt->idt_state = TASK_ABORTING;
16407978SPeter.Dunlap@Sun.COM break;
16417978SPeter.Dunlap@Sun.COM default:
16427978SPeter.Dunlap@Sun.COM ASSERT(0);
16437978SPeter.Dunlap@Sun.COM }
16447978SPeter.Dunlap@Sun.COM break;
16457978SPeter.Dunlap@Sun.COM case TASK_SUSPENDED:
16467978SPeter.Dunlap@Sun.COM /* Already called transport_free_task_rsrc(); */
16477978SPeter.Dunlap@Sun.COM switch (abort_type) {
16487978SPeter.Dunlap@Sun.COM case AT_INTERNAL_SUSPEND:
16497978SPeter.Dunlap@Sun.COM /* Already doing it */
16507978SPeter.Dunlap@Sun.COM break;
16517978SPeter.Dunlap@Sun.COM case AT_INTERNAL_ABORT:
16527978SPeter.Dunlap@Sun.COM case AT_TASK_MGMT_ABORT:
16537978SPeter.Dunlap@Sun.COM idt->idt_state = TASK_ABORTING;
16547978SPeter.Dunlap@Sun.COM mutex_exit(&idt->idt_mutex);
16557978SPeter.Dunlap@Sun.COM
16567978SPeter.Dunlap@Sun.COM /*
16577978SPeter.Dunlap@Sun.COM * We could probably call idm_task_aborted directly
16587978SPeter.Dunlap@Sun.COM * here but we may be holding the conn lock. It's
16597978SPeter.Dunlap@Sun.COM * easier to just switch contexts. Even though
16607978SPeter.Dunlap@Sun.COM * we shouldn't really have any references we'll
16617978SPeter.Dunlap@Sun.COM * set the state to TASK_ABORTING instead of
16627978SPeter.Dunlap@Sun.COM * TASK_ABORTED so we can use the same code path.
16637978SPeter.Dunlap@Sun.COM */
16647978SPeter.Dunlap@Sun.COM idm_refcnt_async_wait_ref(&idt->idt_refcnt,
16657978SPeter.Dunlap@Sun.COM &idm_task_abort_unref_cb);
16667978SPeter.Dunlap@Sun.COM return;
16677978SPeter.Dunlap@Sun.COM default:
16687978SPeter.Dunlap@Sun.COM ASSERT(0);
16697978SPeter.Dunlap@Sun.COM }
16707978SPeter.Dunlap@Sun.COM break;
16717978SPeter.Dunlap@Sun.COM case TASK_ABORTING:
16727978SPeter.Dunlap@Sun.COM case TASK_ABORTED:
16737978SPeter.Dunlap@Sun.COM switch (abort_type) {
16747978SPeter.Dunlap@Sun.COM case AT_INTERNAL_SUSPEND:
16757978SPeter.Dunlap@Sun.COM /* We're already past this point... */
16767978SPeter.Dunlap@Sun.COM case AT_INTERNAL_ABORT:
16777978SPeter.Dunlap@Sun.COM case AT_TASK_MGMT_ABORT:
16787978SPeter.Dunlap@Sun.COM /* Already doing it */
16797978SPeter.Dunlap@Sun.COM break;
16807978SPeter.Dunlap@Sun.COM default:
16817978SPeter.Dunlap@Sun.COM ASSERT(0);
16827978SPeter.Dunlap@Sun.COM }
16837978SPeter.Dunlap@Sun.COM break;
16847978SPeter.Dunlap@Sun.COM case TASK_COMPLETE:
16857978SPeter.Dunlap@Sun.COM /*
16867978SPeter.Dunlap@Sun.COM * In this case, let it go. The status has already been
16877978SPeter.Dunlap@Sun.COM * sent (which may or may not get successfully transmitted)
16887978SPeter.Dunlap@Sun.COM * and we don't want to end up in a race between completing
16897978SPeter.Dunlap@Sun.COM * the status PDU and marking the task suspended.
16907978SPeter.Dunlap@Sun.COM */
16917978SPeter.Dunlap@Sun.COM break;
16927978SPeter.Dunlap@Sun.COM default:
16937978SPeter.Dunlap@Sun.COM ASSERT(0);
16947978SPeter.Dunlap@Sun.COM }
16957978SPeter.Dunlap@Sun.COM mutex_exit(&idt->idt_mutex);
16967978SPeter.Dunlap@Sun.COM }
16977978SPeter.Dunlap@Sun.COM
16987978SPeter.Dunlap@Sun.COM static void
idm_task_aborted(idm_task_t * idt,idm_status_t status)16997978SPeter.Dunlap@Sun.COM idm_task_aborted(idm_task_t *idt, idm_status_t status)
17007978SPeter.Dunlap@Sun.COM {
17017978SPeter.Dunlap@Sun.COM (*idt->idt_ic->ic_conn_ops.icb_task_aborted)(idt, status);
17027978SPeter.Dunlap@Sun.COM }
17037978SPeter.Dunlap@Sun.COM
17047978SPeter.Dunlap@Sun.COM /*
17057978SPeter.Dunlap@Sun.COM * idm_pdu_tx
17067978SPeter.Dunlap@Sun.COM *
17077978SPeter.Dunlap@Sun.COM * This is IDM's implementation of the 'Send_Control' operational primitive.
17087978SPeter.Dunlap@Sun.COM * This function is invoked by an initiator iSCSI layer requesting the transfer
17097978SPeter.Dunlap@Sun.COM * of a iSCSI command PDU or a target iSCSI layer requesting the transfer of a
17107978SPeter.Dunlap@Sun.COM * iSCSI response PDU. The PDU will be transmitted as-is by the local Datamover
17117978SPeter.Dunlap@Sun.COM * layer to the peer iSCSI layer in the remote iSCSI node. The connection info
17127978SPeter.Dunlap@Sun.COM * and iSCSI PDU-specific qualifiers namely BHS, AHS, DataDescriptor and Size
17137978SPeter.Dunlap@Sun.COM * are provided as input.
17147978SPeter.Dunlap@Sun.COM *
17157978SPeter.Dunlap@Sun.COM */
17167978SPeter.Dunlap@Sun.COM void
idm_pdu_tx(idm_pdu_t * pdu)17177978SPeter.Dunlap@Sun.COM idm_pdu_tx(idm_pdu_t *pdu)
17187978SPeter.Dunlap@Sun.COM {
17197978SPeter.Dunlap@Sun.COM idm_conn_t *ic = pdu->isp_ic;
17207978SPeter.Dunlap@Sun.COM iscsi_async_evt_hdr_t *async_evt;
17217978SPeter.Dunlap@Sun.COM
17227978SPeter.Dunlap@Sun.COM /*
17237978SPeter.Dunlap@Sun.COM * If we are in full-featured mode then route SCSI-related
17247978SPeter.Dunlap@Sun.COM * commands to the appropriate function vector without checking
17257978SPeter.Dunlap@Sun.COM * the connection state. We will only be in full-feature mode
17267978SPeter.Dunlap@Sun.COM * when we are in an acceptable state for SCSI PDU's.
17277978SPeter.Dunlap@Sun.COM *
17287978SPeter.Dunlap@Sun.COM * We also need to ensure that there are no PDU events outstanding
17297978SPeter.Dunlap@Sun.COM * on the state machine. Any non-SCSI PDU's received in full-feature
17307978SPeter.Dunlap@Sun.COM * mode will result in PDU events and until these have been handled
17317978SPeter.Dunlap@Sun.COM * we need to route all PDU's through the state machine as PDU
17327978SPeter.Dunlap@Sun.COM * events to maintain ordering.
17337978SPeter.Dunlap@Sun.COM *
17347978SPeter.Dunlap@Sun.COM * Note that IDM cannot enter FFP mode until it processes in
17357978SPeter.Dunlap@Sun.COM * its state machine the last xmit of the login process.
17367978SPeter.Dunlap@Sun.COM * Hence, checking the IDM_PDU_LOGIN_TX flag here would be
17377978SPeter.Dunlap@Sun.COM * superfluous.
17387978SPeter.Dunlap@Sun.COM */
17397978SPeter.Dunlap@Sun.COM mutex_enter(&ic->ic_state_mutex);
17407978SPeter.Dunlap@Sun.COM if (ic->ic_ffp && (ic->ic_pdu_events == 0)) {
17417978SPeter.Dunlap@Sun.COM mutex_exit(&ic->ic_state_mutex);
17427978SPeter.Dunlap@Sun.COM switch (IDM_PDU_OPCODE(pdu)) {
17437978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_RSP:
17447978SPeter.Dunlap@Sun.COM /* Target only */
17459721SPriya.Krishnan@Sun.COM DTRACE_ISCSI_2(scsi__response, idm_conn_t *, ic,
17469721SPriya.Krishnan@Sun.COM iscsi_scsi_rsp_hdr_t *,
17479721SPriya.Krishnan@Sun.COM (iscsi_scsi_rsp_hdr_t *)pdu->isp_hdr);
17487978SPeter.Dunlap@Sun.COM idm_pdu_tx_forward(ic, pdu);
17497978SPeter.Dunlap@Sun.COM return;
17507978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_TASK_MGT_RSP:
17517978SPeter.Dunlap@Sun.COM /* Target only */
17529721SPriya.Krishnan@Sun.COM DTRACE_ISCSI_2(task__response, idm_conn_t *, ic,
17539721SPriya.Krishnan@Sun.COM iscsi_text_rsp_hdr_t *,
17549721SPriya.Krishnan@Sun.COM (iscsi_text_rsp_hdr_t *)pdu->isp_hdr);
17557978SPeter.Dunlap@Sun.COM idm_pdu_tx_forward(ic, pdu);
17567978SPeter.Dunlap@Sun.COM return;
17577978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_DATA_RSP:
17587978SPeter.Dunlap@Sun.COM /* Target only */
17599721SPriya.Krishnan@Sun.COM DTRACE_ISCSI_2(data__send, idm_conn_t *, ic,
17609721SPriya.Krishnan@Sun.COM iscsi_data_rsp_hdr_t *,
17619721SPriya.Krishnan@Sun.COM (iscsi_data_rsp_hdr_t *)pdu->isp_hdr);
17627978SPeter.Dunlap@Sun.COM idm_pdu_tx_forward(ic, pdu);
17637978SPeter.Dunlap@Sun.COM return;
17647978SPeter.Dunlap@Sun.COM case ISCSI_OP_RTT_RSP:
17657978SPeter.Dunlap@Sun.COM /* Target only */
17669721SPriya.Krishnan@Sun.COM DTRACE_ISCSI_2(data__request, idm_conn_t *, ic,
17679721SPriya.Krishnan@Sun.COM iscsi_rtt_hdr_t *,
17689721SPriya.Krishnan@Sun.COM (iscsi_rtt_hdr_t *)pdu->isp_hdr);
17697978SPeter.Dunlap@Sun.COM idm_pdu_tx_forward(ic, pdu);
17707978SPeter.Dunlap@Sun.COM return;
17717978SPeter.Dunlap@Sun.COM case ISCSI_OP_NOOP_IN:
17727978SPeter.Dunlap@Sun.COM /* Target only */
17739721SPriya.Krishnan@Sun.COM DTRACE_ISCSI_2(nop__send, idm_conn_t *, ic,
17749721SPriya.Krishnan@Sun.COM iscsi_nop_in_hdr_t *,
17759721SPriya.Krishnan@Sun.COM (iscsi_nop_in_hdr_t *)pdu->isp_hdr);
17767978SPeter.Dunlap@Sun.COM idm_pdu_tx_forward(ic, pdu);
17777978SPeter.Dunlap@Sun.COM return;
17787978SPeter.Dunlap@Sun.COM case ISCSI_OP_TEXT_RSP:
17797978SPeter.Dunlap@Sun.COM /* Target only */
17809721SPriya.Krishnan@Sun.COM DTRACE_ISCSI_2(text__response, idm_conn_t *, ic,
17819721SPriya.Krishnan@Sun.COM iscsi_text_rsp_hdr_t *,
17829721SPriya.Krishnan@Sun.COM (iscsi_text_rsp_hdr_t *)pdu->isp_hdr);
17837978SPeter.Dunlap@Sun.COM idm_pdu_tx_forward(ic, pdu);
17847978SPeter.Dunlap@Sun.COM return;
17857978SPeter.Dunlap@Sun.COM case ISCSI_OP_TEXT_CMD:
17867978SPeter.Dunlap@Sun.COM case ISCSI_OP_NOOP_OUT:
17877978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_CMD:
17887978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_DATA:
17897978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_TASK_MGT_MSG:
17907978SPeter.Dunlap@Sun.COM /* Initiator only */
17917978SPeter.Dunlap@Sun.COM idm_pdu_tx_forward(ic, pdu);
17927978SPeter.Dunlap@Sun.COM return;
17937978SPeter.Dunlap@Sun.COM default:
17947978SPeter.Dunlap@Sun.COM break;
17957978SPeter.Dunlap@Sun.COM }
17967978SPeter.Dunlap@Sun.COM
17977978SPeter.Dunlap@Sun.COM mutex_enter(&ic->ic_state_mutex);
17987978SPeter.Dunlap@Sun.COM }
17997978SPeter.Dunlap@Sun.COM
18007978SPeter.Dunlap@Sun.COM /*
18017978SPeter.Dunlap@Sun.COM * Any PDU's processed outside of full-feature mode and non-SCSI
18027978SPeter.Dunlap@Sun.COM * PDU's in full-feature mode are handled by generating an
18037978SPeter.Dunlap@Sun.COM * event to the connection state machine. The state machine
18047978SPeter.Dunlap@Sun.COM * will validate the PDU against the current state and either
18057978SPeter.Dunlap@Sun.COM * transmit the PDU if the opcode is allowed or handle an
18067978SPeter.Dunlap@Sun.COM * error if the PDU is not allowed.
18077978SPeter.Dunlap@Sun.COM *
18087978SPeter.Dunlap@Sun.COM * This code-path will also generate any events that are implied
18097978SPeter.Dunlap@Sun.COM * by the PDU opcode. For example a "login response" with success
18107978SPeter.Dunlap@Sun.COM * status generates a CE_LOGOUT_SUCCESS_SND event.
18117978SPeter.Dunlap@Sun.COM */
18127978SPeter.Dunlap@Sun.COM switch (IDM_PDU_OPCODE(pdu)) {
18137978SPeter.Dunlap@Sun.COM case ISCSI_OP_LOGIN_CMD:
18147978SPeter.Dunlap@Sun.COM idm_conn_tx_pdu_event(ic, CE_LOGIN_SND, (uintptr_t)pdu);
18157978SPeter.Dunlap@Sun.COM break;
18167978SPeter.Dunlap@Sun.COM case ISCSI_OP_LOGIN_RSP:
18179721SPriya.Krishnan@Sun.COM DTRACE_ISCSI_2(login__response, idm_conn_t *, ic,
18189721SPriya.Krishnan@Sun.COM iscsi_login_rsp_hdr_t *,
18199721SPriya.Krishnan@Sun.COM (iscsi_login_rsp_hdr_t *)pdu->isp_hdr);
18207978SPeter.Dunlap@Sun.COM idm_parse_login_rsp(ic, pdu, /* Is RX */ B_FALSE);
18217978SPeter.Dunlap@Sun.COM break;
18227978SPeter.Dunlap@Sun.COM case ISCSI_OP_LOGOUT_CMD:
18237978SPeter.Dunlap@Sun.COM idm_parse_logout_req(ic, pdu, /* Is RX */ B_FALSE);
18247978SPeter.Dunlap@Sun.COM break;
18257978SPeter.Dunlap@Sun.COM case ISCSI_OP_LOGOUT_RSP:
18269721SPriya.Krishnan@Sun.COM DTRACE_ISCSI_2(logout__response, idm_conn_t *, ic,
18279721SPriya.Krishnan@Sun.COM iscsi_logout_rsp_hdr_t *,
18289721SPriya.Krishnan@Sun.COM (iscsi_logout_rsp_hdr_t *)pdu->isp_hdr);
18297978SPeter.Dunlap@Sun.COM idm_parse_logout_rsp(ic, pdu, /* Is RX */ B_FALSE);
18307978SPeter.Dunlap@Sun.COM break;
18317978SPeter.Dunlap@Sun.COM case ISCSI_OP_ASYNC_EVENT:
18329721SPriya.Krishnan@Sun.COM DTRACE_ISCSI_2(async__send, idm_conn_t *, ic,
18339721SPriya.Krishnan@Sun.COM iscsi_async_evt_hdr_t *,
18349721SPriya.Krishnan@Sun.COM (iscsi_async_evt_hdr_t *)pdu->isp_hdr);
18357978SPeter.Dunlap@Sun.COM async_evt = (iscsi_async_evt_hdr_t *)pdu->isp_hdr;
18367978SPeter.Dunlap@Sun.COM switch (async_evt->async_event) {
18377978SPeter.Dunlap@Sun.COM case ISCSI_ASYNC_EVENT_REQUEST_LOGOUT:
18387978SPeter.Dunlap@Sun.COM idm_conn_tx_pdu_event(ic, CE_ASYNC_LOGOUT_SND,
18397978SPeter.Dunlap@Sun.COM (uintptr_t)pdu);
18407978SPeter.Dunlap@Sun.COM break;
18417978SPeter.Dunlap@Sun.COM case ISCSI_ASYNC_EVENT_DROPPING_CONNECTION:
18427978SPeter.Dunlap@Sun.COM idm_conn_tx_pdu_event(ic, CE_ASYNC_DROP_CONN_SND,
18437978SPeter.Dunlap@Sun.COM (uintptr_t)pdu);
18447978SPeter.Dunlap@Sun.COM break;
18457978SPeter.Dunlap@Sun.COM case ISCSI_ASYNC_EVENT_DROPPING_ALL_CONNECTIONS:
18467978SPeter.Dunlap@Sun.COM idm_conn_tx_pdu_event(ic, CE_ASYNC_DROP_ALL_CONN_SND,
18477978SPeter.Dunlap@Sun.COM (uintptr_t)pdu);
18487978SPeter.Dunlap@Sun.COM break;
18497978SPeter.Dunlap@Sun.COM case ISCSI_ASYNC_EVENT_SCSI_EVENT:
18507978SPeter.Dunlap@Sun.COM case ISCSI_ASYNC_EVENT_PARAM_NEGOTIATION:
18517978SPeter.Dunlap@Sun.COM default:
18527978SPeter.Dunlap@Sun.COM idm_conn_tx_pdu_event(ic, CE_MISC_TX,
18537978SPeter.Dunlap@Sun.COM (uintptr_t)pdu);
18547978SPeter.Dunlap@Sun.COM break;
18557978SPeter.Dunlap@Sun.COM }
18567978SPeter.Dunlap@Sun.COM break;
18577978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_RSP:
18587978SPeter.Dunlap@Sun.COM /* Target only */
18599721SPriya.Krishnan@Sun.COM DTRACE_ISCSI_2(scsi__response, idm_conn_t *, ic,
18609721SPriya.Krishnan@Sun.COM iscsi_scsi_rsp_hdr_t *,
18619721SPriya.Krishnan@Sun.COM (iscsi_scsi_rsp_hdr_t *)pdu->isp_hdr);
18627978SPeter.Dunlap@Sun.COM idm_conn_tx_pdu_event(ic, CE_MISC_TX, (uintptr_t)pdu);
18637978SPeter.Dunlap@Sun.COM break;
18647978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_TASK_MGT_RSP:
18657978SPeter.Dunlap@Sun.COM /* Target only */
18669721SPriya.Krishnan@Sun.COM DTRACE_ISCSI_2(task__response, idm_conn_t *, ic,
18679721SPriya.Krishnan@Sun.COM iscsi_scsi_task_mgt_rsp_hdr_t *,
18689721SPriya.Krishnan@Sun.COM (iscsi_scsi_task_mgt_rsp_hdr_t *)pdu->isp_hdr);
18697978SPeter.Dunlap@Sun.COM idm_conn_tx_pdu_event(ic, CE_MISC_TX, (uintptr_t)pdu);
18707978SPeter.Dunlap@Sun.COM break;
18717978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_DATA_RSP:
18727978SPeter.Dunlap@Sun.COM /* Target only */
18739721SPriya.Krishnan@Sun.COM DTRACE_ISCSI_2(data__send, idm_conn_t *, ic,
18749721SPriya.Krishnan@Sun.COM iscsi_data_rsp_hdr_t *,
18759721SPriya.Krishnan@Sun.COM (iscsi_data_rsp_hdr_t *)pdu->isp_hdr);
18767978SPeter.Dunlap@Sun.COM idm_conn_tx_pdu_event(ic, CE_MISC_TX, (uintptr_t)pdu);
18777978SPeter.Dunlap@Sun.COM break;
18787978SPeter.Dunlap@Sun.COM case ISCSI_OP_RTT_RSP:
18797978SPeter.Dunlap@Sun.COM /* Target only */
18809721SPriya.Krishnan@Sun.COM DTRACE_ISCSI_2(data__request, idm_conn_t *, ic,
18819721SPriya.Krishnan@Sun.COM iscsi_rtt_hdr_t *,
18829721SPriya.Krishnan@Sun.COM (iscsi_rtt_hdr_t *)pdu->isp_hdr);
18837978SPeter.Dunlap@Sun.COM idm_conn_tx_pdu_event(ic, CE_MISC_TX, (uintptr_t)pdu);
18847978SPeter.Dunlap@Sun.COM break;
18857978SPeter.Dunlap@Sun.COM case ISCSI_OP_NOOP_IN:
18867978SPeter.Dunlap@Sun.COM /* Target only */
18879721SPriya.Krishnan@Sun.COM DTRACE_ISCSI_2(nop__send, idm_conn_t *, ic,
18889721SPriya.Krishnan@Sun.COM iscsi_nop_in_hdr_t *,
18899721SPriya.Krishnan@Sun.COM (iscsi_nop_in_hdr_t *)pdu->isp_hdr);
18907978SPeter.Dunlap@Sun.COM idm_conn_tx_pdu_event(ic, CE_MISC_TX, (uintptr_t)pdu);
18917978SPeter.Dunlap@Sun.COM break;
18927978SPeter.Dunlap@Sun.COM case ISCSI_OP_TEXT_RSP:
18937978SPeter.Dunlap@Sun.COM /* Target only */
18949721SPriya.Krishnan@Sun.COM DTRACE_ISCSI_2(text__response, idm_conn_t *, ic,
18959721SPriya.Krishnan@Sun.COM iscsi_text_rsp_hdr_t *,
18969721SPriya.Krishnan@Sun.COM (iscsi_text_rsp_hdr_t *)pdu->isp_hdr);
18977978SPeter.Dunlap@Sun.COM idm_conn_tx_pdu_event(ic, CE_MISC_TX, (uintptr_t)pdu);
18987978SPeter.Dunlap@Sun.COM break;
18997978SPeter.Dunlap@Sun.COM /* Initiator only */
19007978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_CMD:
19017978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_TASK_MGT_MSG:
19027978SPeter.Dunlap@Sun.COM case ISCSI_OP_SCSI_DATA:
19037978SPeter.Dunlap@Sun.COM case ISCSI_OP_NOOP_OUT:
19047978SPeter.Dunlap@Sun.COM case ISCSI_OP_TEXT_CMD:
19057978SPeter.Dunlap@Sun.COM case ISCSI_OP_SNACK_CMD:
19067978SPeter.Dunlap@Sun.COM case ISCSI_OP_REJECT_MSG:
19077978SPeter.Dunlap@Sun.COM default:
19087978SPeter.Dunlap@Sun.COM /*
19097978SPeter.Dunlap@Sun.COM * Connection state machine will validate these PDU's against
19107978SPeter.Dunlap@Sun.COM * the current state. A PDU not allowed in the current
19117978SPeter.Dunlap@Sun.COM * state will cause a protocol error.
19127978SPeter.Dunlap@Sun.COM */
19137978SPeter.Dunlap@Sun.COM idm_conn_tx_pdu_event(ic, CE_MISC_TX, (uintptr_t)pdu);
19147978SPeter.Dunlap@Sun.COM break;
19157978SPeter.Dunlap@Sun.COM }
19167978SPeter.Dunlap@Sun.COM mutex_exit(&ic->ic_state_mutex);
19177978SPeter.Dunlap@Sun.COM }
19187978SPeter.Dunlap@Sun.COM
19197978SPeter.Dunlap@Sun.COM /*
19209162SPeter.Dunlap@Sun.COM * Common allocation of a PDU along with memory for header and data.
19217978SPeter.Dunlap@Sun.COM */
19229162SPeter.Dunlap@Sun.COM static idm_pdu_t *
idm_pdu_alloc_common(uint_t hdrlen,uint_t datalen,int sleepflag)19239162SPeter.Dunlap@Sun.COM idm_pdu_alloc_common(uint_t hdrlen, uint_t datalen, int sleepflag)
19247978SPeter.Dunlap@Sun.COM {
19257978SPeter.Dunlap@Sun.COM idm_pdu_t *result;
19267978SPeter.Dunlap@Sun.COM
19277978SPeter.Dunlap@Sun.COM /*
19287978SPeter.Dunlap@Sun.COM * IDM clients should cache these structures for performance
19297978SPeter.Dunlap@Sun.COM * critical paths. We can't cache effectively in IDM because we
19307978SPeter.Dunlap@Sun.COM * don't know the correct header and data size.
19317978SPeter.Dunlap@Sun.COM *
19327978SPeter.Dunlap@Sun.COM * Valid header length is assumed to be hdrlen and valid data
19337978SPeter.Dunlap@Sun.COM * length is assumed to be datalen. isp_hdrlen and isp_datalen
19347978SPeter.Dunlap@Sun.COM * can be adjusted after the PDU is returned if necessary.
19357978SPeter.Dunlap@Sun.COM */
19369162SPeter.Dunlap@Sun.COM result = kmem_zalloc(sizeof (idm_pdu_t) + hdrlen + datalen, sleepflag);
19379162SPeter.Dunlap@Sun.COM if (result != NULL) {
19389162SPeter.Dunlap@Sun.COM /* For idm_pdu_free sanity check */
19399162SPeter.Dunlap@Sun.COM result->isp_flags |= IDM_PDU_ALLOC;
19409162SPeter.Dunlap@Sun.COM /* pointer arithmetic */
19419162SPeter.Dunlap@Sun.COM result->isp_hdr = (iscsi_hdr_t *)(result + 1);
19429162SPeter.Dunlap@Sun.COM result->isp_hdrlen = hdrlen;
19439162SPeter.Dunlap@Sun.COM result->isp_hdrbuflen = hdrlen;
19449162SPeter.Dunlap@Sun.COM result->isp_transport_hdrlen = 0;
19459601SJames.Moore@Sun.COM if (datalen != 0)
19469601SJames.Moore@Sun.COM result->isp_data = (uint8_t *)result->isp_hdr + hdrlen;
19479162SPeter.Dunlap@Sun.COM result->isp_datalen = datalen;
19489162SPeter.Dunlap@Sun.COM result->isp_databuflen = datalen;
19499162SPeter.Dunlap@Sun.COM result->isp_magic = IDM_PDU_MAGIC;
19509162SPeter.Dunlap@Sun.COM }
19517978SPeter.Dunlap@Sun.COM
19527978SPeter.Dunlap@Sun.COM return (result);
19537978SPeter.Dunlap@Sun.COM }
19547978SPeter.Dunlap@Sun.COM
19557978SPeter.Dunlap@Sun.COM /*
19569162SPeter.Dunlap@Sun.COM * Typical idm_pdu_alloc invocation, will block for resources.
19579162SPeter.Dunlap@Sun.COM */
19589162SPeter.Dunlap@Sun.COM idm_pdu_t *
idm_pdu_alloc(uint_t hdrlen,uint_t datalen)19599162SPeter.Dunlap@Sun.COM idm_pdu_alloc(uint_t hdrlen, uint_t datalen)
19609162SPeter.Dunlap@Sun.COM {
19619162SPeter.Dunlap@Sun.COM return (idm_pdu_alloc_common(hdrlen, datalen, KM_SLEEP));
19629162SPeter.Dunlap@Sun.COM }
19639162SPeter.Dunlap@Sun.COM
19649162SPeter.Dunlap@Sun.COM /*
19659162SPeter.Dunlap@Sun.COM * Non-blocking idm_pdu_alloc implementation, returns NULL if resources
19669162SPeter.Dunlap@Sun.COM * are not available. Needed for transport-layer allocations which may
19679162SPeter.Dunlap@Sun.COM * be invoking in interrupt context.
19689162SPeter.Dunlap@Sun.COM */
19699162SPeter.Dunlap@Sun.COM idm_pdu_t *
idm_pdu_alloc_nosleep(uint_t hdrlen,uint_t datalen)19709162SPeter.Dunlap@Sun.COM idm_pdu_alloc_nosleep(uint_t hdrlen, uint_t datalen)
19719162SPeter.Dunlap@Sun.COM {
19729162SPeter.Dunlap@Sun.COM return (idm_pdu_alloc_common(hdrlen, datalen, KM_NOSLEEP));
19739162SPeter.Dunlap@Sun.COM }
19749162SPeter.Dunlap@Sun.COM
19759162SPeter.Dunlap@Sun.COM /*
19767978SPeter.Dunlap@Sun.COM * Free a PDU previously allocated with idm_pdu_alloc() including any
19777978SPeter.Dunlap@Sun.COM * header and data space allocated as part of the original request.
19787978SPeter.Dunlap@Sun.COM * Additional memory regions referenced by subsequent modification of
19797978SPeter.Dunlap@Sun.COM * the isp_hdr and/or isp_data fields will not be freed.
19807978SPeter.Dunlap@Sun.COM */
19817978SPeter.Dunlap@Sun.COM void
idm_pdu_free(idm_pdu_t * pdu)19827978SPeter.Dunlap@Sun.COM idm_pdu_free(idm_pdu_t *pdu)
19837978SPeter.Dunlap@Sun.COM {
19847978SPeter.Dunlap@Sun.COM /* Make sure the structure was allocated using idm_pdu_alloc() */
19857978SPeter.Dunlap@Sun.COM ASSERT(pdu->isp_flags & IDM_PDU_ALLOC);
19867978SPeter.Dunlap@Sun.COM kmem_free(pdu,
19877978SPeter.Dunlap@Sun.COM sizeof (idm_pdu_t) + pdu->isp_hdrbuflen + pdu->isp_databuflen);
19887978SPeter.Dunlap@Sun.COM }
19897978SPeter.Dunlap@Sun.COM
19907978SPeter.Dunlap@Sun.COM /*
19917978SPeter.Dunlap@Sun.COM * Initialize the connection, private and callback fields in a PDU.
19927978SPeter.Dunlap@Sun.COM */
19937978SPeter.Dunlap@Sun.COM void
idm_pdu_init(idm_pdu_t * pdu,idm_conn_t * ic,void * private,idm_pdu_cb_t * cb)19947978SPeter.Dunlap@Sun.COM idm_pdu_init(idm_pdu_t *pdu, idm_conn_t *ic, void *private, idm_pdu_cb_t *cb)
19957978SPeter.Dunlap@Sun.COM {
19967978SPeter.Dunlap@Sun.COM /*
19977978SPeter.Dunlap@Sun.COM * idm_pdu_complete() will call idm_pdu_free if the callback is
19987978SPeter.Dunlap@Sun.COM * NULL. This will only work if the PDU was originally allocated
19997978SPeter.Dunlap@Sun.COM * with idm_pdu_alloc().
20007978SPeter.Dunlap@Sun.COM */
20017978SPeter.Dunlap@Sun.COM ASSERT((pdu->isp_flags & IDM_PDU_ALLOC) ||
20027978SPeter.Dunlap@Sun.COM (cb != NULL));
20037978SPeter.Dunlap@Sun.COM pdu->isp_magic = IDM_PDU_MAGIC;
20047978SPeter.Dunlap@Sun.COM pdu->isp_ic = ic;
20057978SPeter.Dunlap@Sun.COM pdu->isp_private = private;
20067978SPeter.Dunlap@Sun.COM pdu->isp_callback = cb;
20077978SPeter.Dunlap@Sun.COM }
20087978SPeter.Dunlap@Sun.COM
20097978SPeter.Dunlap@Sun.COM /*
20107978SPeter.Dunlap@Sun.COM * Initialize the header and header length field. This function should
20117978SPeter.Dunlap@Sun.COM * not be used to adjust the header length in a buffer allocated via
20127978SPeter.Dunlap@Sun.COM * pdu_pdu_alloc since it overwrites the existing header pointer.
20137978SPeter.Dunlap@Sun.COM */
20147978SPeter.Dunlap@Sun.COM void
idm_pdu_init_hdr(idm_pdu_t * pdu,uint8_t * hdr,uint_t hdrlen)20157978SPeter.Dunlap@Sun.COM idm_pdu_init_hdr(idm_pdu_t *pdu, uint8_t *hdr, uint_t hdrlen)
20167978SPeter.Dunlap@Sun.COM {
20177978SPeter.Dunlap@Sun.COM pdu->isp_hdr = (iscsi_hdr_t *)((void *)hdr);
20187978SPeter.Dunlap@Sun.COM pdu->isp_hdrlen = hdrlen;
20197978SPeter.Dunlap@Sun.COM }
20207978SPeter.Dunlap@Sun.COM
20217978SPeter.Dunlap@Sun.COM /*
20227978SPeter.Dunlap@Sun.COM * Initialize the data and data length fields. This function should
20237978SPeter.Dunlap@Sun.COM * not be used to adjust the data length of a buffer allocated via
20247978SPeter.Dunlap@Sun.COM * idm_pdu_alloc since it overwrites the existing data pointer.
20257978SPeter.Dunlap@Sun.COM */
20267978SPeter.Dunlap@Sun.COM void
idm_pdu_init_data(idm_pdu_t * pdu,uint8_t * data,uint_t datalen)20277978SPeter.Dunlap@Sun.COM idm_pdu_init_data(idm_pdu_t *pdu, uint8_t *data, uint_t datalen)
20287978SPeter.Dunlap@Sun.COM {
20297978SPeter.Dunlap@Sun.COM pdu->isp_data = data;
20307978SPeter.Dunlap@Sun.COM pdu->isp_datalen = datalen;
20317978SPeter.Dunlap@Sun.COM }
20327978SPeter.Dunlap@Sun.COM
20337978SPeter.Dunlap@Sun.COM void
idm_pdu_complete(idm_pdu_t * pdu,idm_status_t status)20347978SPeter.Dunlap@Sun.COM idm_pdu_complete(idm_pdu_t *pdu, idm_status_t status)
20357978SPeter.Dunlap@Sun.COM {
20367978SPeter.Dunlap@Sun.COM if (pdu->isp_callback) {
20377978SPeter.Dunlap@Sun.COM pdu->isp_status = status;
20387978SPeter.Dunlap@Sun.COM (*pdu->isp_callback)(pdu, status);
20397978SPeter.Dunlap@Sun.COM } else {
20407978SPeter.Dunlap@Sun.COM idm_pdu_free(pdu);
20417978SPeter.Dunlap@Sun.COM }
20427978SPeter.Dunlap@Sun.COM }
20437978SPeter.Dunlap@Sun.COM
20447978SPeter.Dunlap@Sun.COM /*
20457978SPeter.Dunlap@Sun.COM * State machine auditing
20467978SPeter.Dunlap@Sun.COM */
20477978SPeter.Dunlap@Sun.COM
20487978SPeter.Dunlap@Sun.COM void
idm_sm_audit_init(sm_audit_buf_t * audit_buf)20497978SPeter.Dunlap@Sun.COM idm_sm_audit_init(sm_audit_buf_t *audit_buf)
20507978SPeter.Dunlap@Sun.COM {
20517978SPeter.Dunlap@Sun.COM bzero(audit_buf, sizeof (sm_audit_buf_t));
20527978SPeter.Dunlap@Sun.COM audit_buf->sab_max_index = SM_AUDIT_BUF_MAX_REC - 1;
20537978SPeter.Dunlap@Sun.COM }
20547978SPeter.Dunlap@Sun.COM
20557978SPeter.Dunlap@Sun.COM static
20567978SPeter.Dunlap@Sun.COM sm_audit_record_t *
idm_sm_audit_common(sm_audit_buf_t * audit_buf,sm_audit_record_type_t r_type,sm_audit_sm_type_t sm_type,int current_state)20577978SPeter.Dunlap@Sun.COM idm_sm_audit_common(sm_audit_buf_t *audit_buf, sm_audit_record_type_t r_type,
20587978SPeter.Dunlap@Sun.COM sm_audit_sm_type_t sm_type,
20597978SPeter.Dunlap@Sun.COM int current_state)
20607978SPeter.Dunlap@Sun.COM {
20617978SPeter.Dunlap@Sun.COM sm_audit_record_t *sar;
20627978SPeter.Dunlap@Sun.COM
20637978SPeter.Dunlap@Sun.COM sar = audit_buf->sab_records;
20647978SPeter.Dunlap@Sun.COM sar += audit_buf->sab_index;
20657978SPeter.Dunlap@Sun.COM audit_buf->sab_index++;
20667978SPeter.Dunlap@Sun.COM audit_buf->sab_index &= audit_buf->sab_max_index;
20677978SPeter.Dunlap@Sun.COM
20687978SPeter.Dunlap@Sun.COM sar->sar_type = r_type;
20697978SPeter.Dunlap@Sun.COM gethrestime(&sar->sar_timestamp);
20707978SPeter.Dunlap@Sun.COM sar->sar_sm_type = sm_type;
20717978SPeter.Dunlap@Sun.COM sar->sar_state = current_state;
20727978SPeter.Dunlap@Sun.COM
20737978SPeter.Dunlap@Sun.COM return (sar);
20747978SPeter.Dunlap@Sun.COM }
20757978SPeter.Dunlap@Sun.COM
20767978SPeter.Dunlap@Sun.COM void
idm_sm_audit_event(sm_audit_buf_t * audit_buf,sm_audit_sm_type_t sm_type,int current_state,int event,uintptr_t event_info)20777978SPeter.Dunlap@Sun.COM idm_sm_audit_event(sm_audit_buf_t *audit_buf,
20787978SPeter.Dunlap@Sun.COM sm_audit_sm_type_t sm_type, int current_state,
20797978SPeter.Dunlap@Sun.COM int event, uintptr_t event_info)
20807978SPeter.Dunlap@Sun.COM {
20817978SPeter.Dunlap@Sun.COM sm_audit_record_t *sar;
20827978SPeter.Dunlap@Sun.COM
20837978SPeter.Dunlap@Sun.COM sar = idm_sm_audit_common(audit_buf, SAR_STATE_EVENT,
20847978SPeter.Dunlap@Sun.COM sm_type, current_state);
20857978SPeter.Dunlap@Sun.COM sar->sar_event = event;
20867978SPeter.Dunlap@Sun.COM sar->sar_event_info = event_info;
20877978SPeter.Dunlap@Sun.COM }
20887978SPeter.Dunlap@Sun.COM
20897978SPeter.Dunlap@Sun.COM void
idm_sm_audit_state_change(sm_audit_buf_t * audit_buf,sm_audit_sm_type_t sm_type,int current_state,int new_state)20907978SPeter.Dunlap@Sun.COM idm_sm_audit_state_change(sm_audit_buf_t *audit_buf,
20917978SPeter.Dunlap@Sun.COM sm_audit_sm_type_t sm_type, int current_state, int new_state)
20927978SPeter.Dunlap@Sun.COM {
20937978SPeter.Dunlap@Sun.COM sm_audit_record_t *sar;
20947978SPeter.Dunlap@Sun.COM
20957978SPeter.Dunlap@Sun.COM sar = idm_sm_audit_common(audit_buf, SAR_STATE_CHANGE,
20967978SPeter.Dunlap@Sun.COM sm_type, current_state);
20977978SPeter.Dunlap@Sun.COM sar->sar_new_state = new_state;
20987978SPeter.Dunlap@Sun.COM }
20997978SPeter.Dunlap@Sun.COM
21007978SPeter.Dunlap@Sun.COM
21017978SPeter.Dunlap@Sun.COM /*
21027978SPeter.Dunlap@Sun.COM * Object reference tracking
21037978SPeter.Dunlap@Sun.COM */
21047978SPeter.Dunlap@Sun.COM
21057978SPeter.Dunlap@Sun.COM void
idm_refcnt_init(idm_refcnt_t * refcnt,void * referenced_obj)21067978SPeter.Dunlap@Sun.COM idm_refcnt_init(idm_refcnt_t *refcnt, void *referenced_obj)
21077978SPeter.Dunlap@Sun.COM {
21087978SPeter.Dunlap@Sun.COM bzero(refcnt, sizeof (*refcnt));
21097978SPeter.Dunlap@Sun.COM idm_refcnt_reset(refcnt);
21107978SPeter.Dunlap@Sun.COM refcnt->ir_referenced_obj = referenced_obj;
21117978SPeter.Dunlap@Sun.COM bzero(&refcnt->ir_audit_buf, sizeof (refcnt_audit_buf_t));
21127978SPeter.Dunlap@Sun.COM refcnt->ir_audit_buf.anb_max_index = REFCNT_AUDIT_BUF_MAX_REC - 1;
21137978SPeter.Dunlap@Sun.COM mutex_init(&refcnt->ir_mutex, NULL, MUTEX_DEFAULT, NULL);
21147978SPeter.Dunlap@Sun.COM cv_init(&refcnt->ir_cv, NULL, CV_DEFAULT, NULL);
21157978SPeter.Dunlap@Sun.COM }
21167978SPeter.Dunlap@Sun.COM
21177978SPeter.Dunlap@Sun.COM void
idm_refcnt_destroy(idm_refcnt_t * refcnt)21187978SPeter.Dunlap@Sun.COM idm_refcnt_destroy(idm_refcnt_t *refcnt)
21197978SPeter.Dunlap@Sun.COM {
21209586SPeter.Dunlap@Sun.COM /*
21219586SPeter.Dunlap@Sun.COM * Grab the mutex to there are no other lingering threads holding
21229586SPeter.Dunlap@Sun.COM * the mutex before we destroy it (e.g. idm_refcnt_rele just after
21239586SPeter.Dunlap@Sun.COM * the refcnt goes to zero if ir_waiting == REF_WAIT_ASYNC)
21249586SPeter.Dunlap@Sun.COM */
21259586SPeter.Dunlap@Sun.COM mutex_enter(&refcnt->ir_mutex);
21267978SPeter.Dunlap@Sun.COM ASSERT(refcnt->ir_refcnt == 0);
21277978SPeter.Dunlap@Sun.COM cv_destroy(&refcnt->ir_cv);
21287978SPeter.Dunlap@Sun.COM mutex_destroy(&refcnt->ir_mutex);
21297978SPeter.Dunlap@Sun.COM }
21307978SPeter.Dunlap@Sun.COM
21317978SPeter.Dunlap@Sun.COM void
idm_refcnt_reset(idm_refcnt_t * refcnt)21327978SPeter.Dunlap@Sun.COM idm_refcnt_reset(idm_refcnt_t *refcnt)
21337978SPeter.Dunlap@Sun.COM {
21347978SPeter.Dunlap@Sun.COM refcnt->ir_waiting = REF_NOWAIT;
21357978SPeter.Dunlap@Sun.COM refcnt->ir_refcnt = 0;
21367978SPeter.Dunlap@Sun.COM }
21377978SPeter.Dunlap@Sun.COM
21387978SPeter.Dunlap@Sun.COM void
idm_refcnt_hold(idm_refcnt_t * refcnt)21397978SPeter.Dunlap@Sun.COM idm_refcnt_hold(idm_refcnt_t *refcnt)
21407978SPeter.Dunlap@Sun.COM {
21417978SPeter.Dunlap@Sun.COM /*
21427978SPeter.Dunlap@Sun.COM * Nothing should take a hold on an object after a call to
21437978SPeter.Dunlap@Sun.COM * idm_refcnt_wait_ref or idm_refcnd_async_wait_ref
21447978SPeter.Dunlap@Sun.COM */
21457978SPeter.Dunlap@Sun.COM ASSERT(refcnt->ir_waiting == REF_NOWAIT);
21467978SPeter.Dunlap@Sun.COM
21477978SPeter.Dunlap@Sun.COM mutex_enter(&refcnt->ir_mutex);
21487978SPeter.Dunlap@Sun.COM refcnt->ir_refcnt++;
21497978SPeter.Dunlap@Sun.COM REFCNT_AUDIT(refcnt);
21507978SPeter.Dunlap@Sun.COM mutex_exit(&refcnt->ir_mutex);
21517978SPeter.Dunlap@Sun.COM }
21527978SPeter.Dunlap@Sun.COM
21537978SPeter.Dunlap@Sun.COM static void
idm_refcnt_unref_task(void * refcnt_void)21547978SPeter.Dunlap@Sun.COM idm_refcnt_unref_task(void *refcnt_void)
21557978SPeter.Dunlap@Sun.COM {
21567978SPeter.Dunlap@Sun.COM idm_refcnt_t *refcnt = refcnt_void;
21577978SPeter.Dunlap@Sun.COM
21587978SPeter.Dunlap@Sun.COM REFCNT_AUDIT(refcnt);
21597978SPeter.Dunlap@Sun.COM (*refcnt->ir_cb)(refcnt->ir_referenced_obj);
21607978SPeter.Dunlap@Sun.COM }
21617978SPeter.Dunlap@Sun.COM
21627978SPeter.Dunlap@Sun.COM void
idm_refcnt_rele(idm_refcnt_t * refcnt)21637978SPeter.Dunlap@Sun.COM idm_refcnt_rele(idm_refcnt_t *refcnt)
21647978SPeter.Dunlap@Sun.COM {
21657978SPeter.Dunlap@Sun.COM mutex_enter(&refcnt->ir_mutex);
21667978SPeter.Dunlap@Sun.COM ASSERT(refcnt->ir_refcnt > 0);
21677978SPeter.Dunlap@Sun.COM refcnt->ir_refcnt--;
21687978SPeter.Dunlap@Sun.COM REFCNT_AUDIT(refcnt);
21697978SPeter.Dunlap@Sun.COM if (refcnt->ir_waiting == REF_NOWAIT) {
21707978SPeter.Dunlap@Sun.COM /* No one is waiting on this object */
21717978SPeter.Dunlap@Sun.COM mutex_exit(&refcnt->ir_mutex);
21727978SPeter.Dunlap@Sun.COM return;
21737978SPeter.Dunlap@Sun.COM }
21747978SPeter.Dunlap@Sun.COM
21757978SPeter.Dunlap@Sun.COM /*
21767978SPeter.Dunlap@Sun.COM * Someone is waiting for this object to go idle so check if
21777978SPeter.Dunlap@Sun.COM * refcnt is 0. Waiting on an object then later grabbing another
21787978SPeter.Dunlap@Sun.COM * reference is not allowed so we don't need to handle that case.
21797978SPeter.Dunlap@Sun.COM */
21807978SPeter.Dunlap@Sun.COM if (refcnt->ir_refcnt == 0) {
21817978SPeter.Dunlap@Sun.COM if (refcnt->ir_waiting == REF_WAIT_ASYNC) {
21827978SPeter.Dunlap@Sun.COM if (taskq_dispatch(idm.idm_global_taskq,
21837978SPeter.Dunlap@Sun.COM &idm_refcnt_unref_task, refcnt, TQ_SLEEP) == NULL) {
21847978SPeter.Dunlap@Sun.COM cmn_err(CE_WARN,
21857978SPeter.Dunlap@Sun.COM "idm_refcnt_rele: Couldn't dispatch task");
21867978SPeter.Dunlap@Sun.COM }
21877978SPeter.Dunlap@Sun.COM } else if (refcnt->ir_waiting == REF_WAIT_SYNC) {
21887978SPeter.Dunlap@Sun.COM cv_signal(&refcnt->ir_cv);
21897978SPeter.Dunlap@Sun.COM }
21907978SPeter.Dunlap@Sun.COM }
21917978SPeter.Dunlap@Sun.COM mutex_exit(&refcnt->ir_mutex);
21927978SPeter.Dunlap@Sun.COM }
21937978SPeter.Dunlap@Sun.COM
21947978SPeter.Dunlap@Sun.COM void
idm_refcnt_rele_and_destroy(idm_refcnt_t * refcnt,idm_refcnt_cb_t * cb_func)21957978SPeter.Dunlap@Sun.COM idm_refcnt_rele_and_destroy(idm_refcnt_t *refcnt, idm_refcnt_cb_t *cb_func)
21967978SPeter.Dunlap@Sun.COM {
21977978SPeter.Dunlap@Sun.COM mutex_enter(&refcnt->ir_mutex);
21987978SPeter.Dunlap@Sun.COM ASSERT(refcnt->ir_refcnt > 0);
21997978SPeter.Dunlap@Sun.COM refcnt->ir_refcnt--;
22007978SPeter.Dunlap@Sun.COM REFCNT_AUDIT(refcnt);
22017978SPeter.Dunlap@Sun.COM
22027978SPeter.Dunlap@Sun.COM /*
22037978SPeter.Dunlap@Sun.COM * Someone is waiting for this object to go idle so check if
22047978SPeter.Dunlap@Sun.COM * refcnt is 0. Waiting on an object then later grabbing another
22057978SPeter.Dunlap@Sun.COM * reference is not allowed so we don't need to handle that case.
22067978SPeter.Dunlap@Sun.COM */
22077978SPeter.Dunlap@Sun.COM if (refcnt->ir_refcnt == 0) {
22087978SPeter.Dunlap@Sun.COM refcnt->ir_cb = cb_func;
22097978SPeter.Dunlap@Sun.COM refcnt->ir_waiting = REF_WAIT_ASYNC;
22107978SPeter.Dunlap@Sun.COM if (taskq_dispatch(idm.idm_global_taskq,
22117978SPeter.Dunlap@Sun.COM &idm_refcnt_unref_task, refcnt, TQ_SLEEP) == NULL) {
22127978SPeter.Dunlap@Sun.COM cmn_err(CE_WARN,
22137978SPeter.Dunlap@Sun.COM "idm_refcnt_rele: Couldn't dispatch task");
22147978SPeter.Dunlap@Sun.COM }
22157978SPeter.Dunlap@Sun.COM }
22167978SPeter.Dunlap@Sun.COM mutex_exit(&refcnt->ir_mutex);
22177978SPeter.Dunlap@Sun.COM }
22187978SPeter.Dunlap@Sun.COM
22197978SPeter.Dunlap@Sun.COM void
idm_refcnt_wait_ref(idm_refcnt_t * refcnt)22207978SPeter.Dunlap@Sun.COM idm_refcnt_wait_ref(idm_refcnt_t *refcnt)
22217978SPeter.Dunlap@Sun.COM {
22227978SPeter.Dunlap@Sun.COM mutex_enter(&refcnt->ir_mutex);
22237978SPeter.Dunlap@Sun.COM refcnt->ir_waiting = REF_WAIT_SYNC;
22247978SPeter.Dunlap@Sun.COM REFCNT_AUDIT(refcnt);
22257978SPeter.Dunlap@Sun.COM while (refcnt->ir_refcnt != 0)
22267978SPeter.Dunlap@Sun.COM cv_wait(&refcnt->ir_cv, &refcnt->ir_mutex);
22277978SPeter.Dunlap@Sun.COM mutex_exit(&refcnt->ir_mutex);
22287978SPeter.Dunlap@Sun.COM }
22297978SPeter.Dunlap@Sun.COM
22307978SPeter.Dunlap@Sun.COM void
idm_refcnt_async_wait_ref(idm_refcnt_t * refcnt,idm_refcnt_cb_t * cb_func)22317978SPeter.Dunlap@Sun.COM idm_refcnt_async_wait_ref(idm_refcnt_t *refcnt, idm_refcnt_cb_t *cb_func)
22327978SPeter.Dunlap@Sun.COM {
22337978SPeter.Dunlap@Sun.COM mutex_enter(&refcnt->ir_mutex);
22347978SPeter.Dunlap@Sun.COM refcnt->ir_waiting = REF_WAIT_ASYNC;
22357978SPeter.Dunlap@Sun.COM refcnt->ir_cb = cb_func;
22367978SPeter.Dunlap@Sun.COM REFCNT_AUDIT(refcnt);
22377978SPeter.Dunlap@Sun.COM /*
22387978SPeter.Dunlap@Sun.COM * It's possible we don't have any references. To make things easier
22397978SPeter.Dunlap@Sun.COM * on the caller use a taskq to call the callback instead of
22407978SPeter.Dunlap@Sun.COM * calling it synchronously
22417978SPeter.Dunlap@Sun.COM */
22427978SPeter.Dunlap@Sun.COM if (refcnt->ir_refcnt == 0) {
22437978SPeter.Dunlap@Sun.COM if (taskq_dispatch(idm.idm_global_taskq,
22447978SPeter.Dunlap@Sun.COM &idm_refcnt_unref_task, refcnt, TQ_SLEEP) == NULL) {
22457978SPeter.Dunlap@Sun.COM cmn_err(CE_WARN,
22467978SPeter.Dunlap@Sun.COM "idm_refcnt_async_wait_ref: "
22477978SPeter.Dunlap@Sun.COM "Couldn't dispatch task");
22487978SPeter.Dunlap@Sun.COM }
22497978SPeter.Dunlap@Sun.COM }
22507978SPeter.Dunlap@Sun.COM mutex_exit(&refcnt->ir_mutex);
22517978SPeter.Dunlap@Sun.COM }
22527978SPeter.Dunlap@Sun.COM
22537978SPeter.Dunlap@Sun.COM void
idm_refcnt_destroy_unref_obj(idm_refcnt_t * refcnt,idm_refcnt_cb_t * cb_func)22547978SPeter.Dunlap@Sun.COM idm_refcnt_destroy_unref_obj(idm_refcnt_t *refcnt,
22557978SPeter.Dunlap@Sun.COM idm_refcnt_cb_t *cb_func)
22567978SPeter.Dunlap@Sun.COM {
22577978SPeter.Dunlap@Sun.COM mutex_enter(&refcnt->ir_mutex);
22587978SPeter.Dunlap@Sun.COM if (refcnt->ir_refcnt == 0) {
22597978SPeter.Dunlap@Sun.COM mutex_exit(&refcnt->ir_mutex);
22607978SPeter.Dunlap@Sun.COM (*cb_func)(refcnt->ir_referenced_obj);
22617978SPeter.Dunlap@Sun.COM return;
22627978SPeter.Dunlap@Sun.COM }
22637978SPeter.Dunlap@Sun.COM mutex_exit(&refcnt->ir_mutex);
22647978SPeter.Dunlap@Sun.COM }
22657978SPeter.Dunlap@Sun.COM
22667978SPeter.Dunlap@Sun.COM void
idm_conn_hold(idm_conn_t * ic)22677978SPeter.Dunlap@Sun.COM idm_conn_hold(idm_conn_t *ic)
22687978SPeter.Dunlap@Sun.COM {
22697978SPeter.Dunlap@Sun.COM idm_refcnt_hold(&ic->ic_refcnt);
22707978SPeter.Dunlap@Sun.COM }
22717978SPeter.Dunlap@Sun.COM
22727978SPeter.Dunlap@Sun.COM void
idm_conn_rele(idm_conn_t * ic)22737978SPeter.Dunlap@Sun.COM idm_conn_rele(idm_conn_t *ic)
22747978SPeter.Dunlap@Sun.COM {
22757978SPeter.Dunlap@Sun.COM idm_refcnt_rele(&ic->ic_refcnt);
22767978SPeter.Dunlap@Sun.COM }
22777978SPeter.Dunlap@Sun.COM
22789721SPriya.Krishnan@Sun.COM void
idm_conn_set_target_name(idm_conn_t * ic,char * target_name)22799721SPriya.Krishnan@Sun.COM idm_conn_set_target_name(idm_conn_t *ic, char *target_name)
22809721SPriya.Krishnan@Sun.COM {
22819721SPriya.Krishnan@Sun.COM (void) strlcpy(ic->ic_target_name, target_name, ISCSI_MAX_NAME_LEN + 1);
22829721SPriya.Krishnan@Sun.COM }
22839721SPriya.Krishnan@Sun.COM
22849721SPriya.Krishnan@Sun.COM void
idm_conn_set_initiator_name(idm_conn_t * ic,char * initiator_name)22859721SPriya.Krishnan@Sun.COM idm_conn_set_initiator_name(idm_conn_t *ic, char *initiator_name)
22869721SPriya.Krishnan@Sun.COM {
22879721SPriya.Krishnan@Sun.COM (void) strlcpy(ic->ic_initiator_name, initiator_name,
22889721SPriya.Krishnan@Sun.COM ISCSI_MAX_NAME_LEN + 1);
22899721SPriya.Krishnan@Sun.COM }
22909721SPriya.Krishnan@Sun.COM
22919721SPriya.Krishnan@Sun.COM void
idm_conn_set_isid(idm_conn_t * ic,uint8_t isid[ISCSI_ISID_LEN])22929721SPriya.Krishnan@Sun.COM idm_conn_set_isid(idm_conn_t *ic, uint8_t isid[ISCSI_ISID_LEN])
22939721SPriya.Krishnan@Sun.COM {
22949721SPriya.Krishnan@Sun.COM (void) snprintf(ic->ic_isid, ISCSI_MAX_ISID_LEN + 1,
22959721SPriya.Krishnan@Sun.COM "%02x%02x%02x%02x%02x%02x",
22969721SPriya.Krishnan@Sun.COM isid[0], isid[1], isid[2], isid[3], isid[4], isid[5]);
22979721SPriya.Krishnan@Sun.COM }
22987978SPeter.Dunlap@Sun.COM
22997978SPeter.Dunlap@Sun.COM static int
_idm_init(void)23007978SPeter.Dunlap@Sun.COM _idm_init(void)
23017978SPeter.Dunlap@Sun.COM {
23027978SPeter.Dunlap@Sun.COM /* Initialize the rwlock for the taskid table */
23037978SPeter.Dunlap@Sun.COM rw_init(&idm.idm_taskid_table_lock, NULL, RW_DRIVER, NULL);
23047978SPeter.Dunlap@Sun.COM
23057978SPeter.Dunlap@Sun.COM /* Initialize the global mutex and taskq */
23067978SPeter.Dunlap@Sun.COM mutex_init(&idm.idm_global_mutex, NULL, MUTEX_DEFAULT, NULL);
23077978SPeter.Dunlap@Sun.COM
23087978SPeter.Dunlap@Sun.COM cv_init(&idm.idm_tgt_svc_cv, NULL, CV_DEFAULT, NULL);
23097978SPeter.Dunlap@Sun.COM cv_init(&idm.idm_wd_cv, NULL, CV_DEFAULT, NULL);
23107978SPeter.Dunlap@Sun.COM
23119162SPeter.Dunlap@Sun.COM /*
23129162SPeter.Dunlap@Sun.COM * The maximum allocation needs to be high here since there can be
23139162SPeter.Dunlap@Sun.COM * many concurrent tasks using the global taskq.
23149162SPeter.Dunlap@Sun.COM */
23157978SPeter.Dunlap@Sun.COM idm.idm_global_taskq = taskq_create("idm_global_taskq", 1, minclsyspri,
23169162SPeter.Dunlap@Sun.COM 128, 16384, TASKQ_PREPOPULATE);
23177978SPeter.Dunlap@Sun.COM if (idm.idm_global_taskq == NULL) {
23187978SPeter.Dunlap@Sun.COM cv_destroy(&idm.idm_wd_cv);
23197978SPeter.Dunlap@Sun.COM cv_destroy(&idm.idm_tgt_svc_cv);
23207978SPeter.Dunlap@Sun.COM mutex_destroy(&idm.idm_global_mutex);
23217978SPeter.Dunlap@Sun.COM rw_destroy(&idm.idm_taskid_table_lock);
23227978SPeter.Dunlap@Sun.COM return (ENOMEM);
23237978SPeter.Dunlap@Sun.COM }
23247978SPeter.Dunlap@Sun.COM
23258209SJames.Moore@Sun.COM /* Start watchdog thread */
23267978SPeter.Dunlap@Sun.COM idm.idm_wd_thread = thread_create(NULL, 0,
23277978SPeter.Dunlap@Sun.COM idm_wd_thread, NULL, 0, &p0, TS_RUN, minclsyspri);
23287978SPeter.Dunlap@Sun.COM if (idm.idm_wd_thread == NULL) {
23297978SPeter.Dunlap@Sun.COM /* Couldn't create the watchdog thread */
23307978SPeter.Dunlap@Sun.COM taskq_destroy(idm.idm_global_taskq);
23317978SPeter.Dunlap@Sun.COM cv_destroy(&idm.idm_wd_cv);
23327978SPeter.Dunlap@Sun.COM cv_destroy(&idm.idm_tgt_svc_cv);
23337978SPeter.Dunlap@Sun.COM mutex_destroy(&idm.idm_global_mutex);
23347978SPeter.Dunlap@Sun.COM rw_destroy(&idm.idm_taskid_table_lock);
23357978SPeter.Dunlap@Sun.COM return (ENOMEM);
23367978SPeter.Dunlap@Sun.COM }
23377978SPeter.Dunlap@Sun.COM
23388209SJames.Moore@Sun.COM /* Pause until the watchdog thread is running */
23397978SPeter.Dunlap@Sun.COM mutex_enter(&idm.idm_global_mutex);
23407978SPeter.Dunlap@Sun.COM while (!idm.idm_wd_thread_running)
23417978SPeter.Dunlap@Sun.COM cv_wait(&idm.idm_wd_cv, &idm.idm_global_mutex);
23427978SPeter.Dunlap@Sun.COM mutex_exit(&idm.idm_global_mutex);
23437978SPeter.Dunlap@Sun.COM
23447978SPeter.Dunlap@Sun.COM /*
23457978SPeter.Dunlap@Sun.COM * Allocate the task ID table and set "next" to 0.
23467978SPeter.Dunlap@Sun.COM */
23477978SPeter.Dunlap@Sun.COM
23487978SPeter.Dunlap@Sun.COM idm.idm_taskid_max = idm_max_taskids;
23497978SPeter.Dunlap@Sun.COM idm.idm_taskid_table = (idm_task_t **)
23507978SPeter.Dunlap@Sun.COM kmem_zalloc(idm.idm_taskid_max * sizeof (idm_task_t *), KM_SLEEP);
23517978SPeter.Dunlap@Sun.COM idm.idm_taskid_next = 0;
23527978SPeter.Dunlap@Sun.COM
23537978SPeter.Dunlap@Sun.COM /* Create the global buffer and task kmem caches */
23547978SPeter.Dunlap@Sun.COM idm.idm_buf_cache = kmem_cache_create("idm_buf_cache",
23557978SPeter.Dunlap@Sun.COM sizeof (idm_buf_t), 8, NULL, NULL, NULL, NULL, NULL, KM_SLEEP);
23567978SPeter.Dunlap@Sun.COM
23577978SPeter.Dunlap@Sun.COM /*
23587978SPeter.Dunlap@Sun.COM * Note, we're explicitly allocating an additional iSER header-
23597978SPeter.Dunlap@Sun.COM * sized chunk for each of these elements. See idm_task_constructor().
23607978SPeter.Dunlap@Sun.COM */
23617978SPeter.Dunlap@Sun.COM idm.idm_task_cache = kmem_cache_create("idm_task_cache",
23627978SPeter.Dunlap@Sun.COM sizeof (idm_task_t) + IDM_TRANSPORT_HEADER_LENGTH, 8,
23637978SPeter.Dunlap@Sun.COM &idm_task_constructor, &idm_task_destructor,
23647978SPeter.Dunlap@Sun.COM NULL, NULL, NULL, KM_SLEEP);
23657978SPeter.Dunlap@Sun.COM
23667978SPeter.Dunlap@Sun.COM /* Create the service and connection context lists */
23677978SPeter.Dunlap@Sun.COM list_create(&idm.idm_tgt_svc_list, sizeof (idm_svc_t),
23687978SPeter.Dunlap@Sun.COM offsetof(idm_svc_t, is_list_node));
23697978SPeter.Dunlap@Sun.COM list_create(&idm.idm_tgt_conn_list, sizeof (idm_conn_t),
23707978SPeter.Dunlap@Sun.COM offsetof(idm_conn_t, ic_list_node));
23717978SPeter.Dunlap@Sun.COM list_create(&idm.idm_ini_conn_list, sizeof (idm_conn_t),
23727978SPeter.Dunlap@Sun.COM offsetof(idm_conn_t, ic_list_node));
23737978SPeter.Dunlap@Sun.COM
23747978SPeter.Dunlap@Sun.COM /* Initialize the native sockets transport */
23757978SPeter.Dunlap@Sun.COM idm_so_init(&idm_transport_list[IDM_TRANSPORT_TYPE_SOCKETS]);
23767978SPeter.Dunlap@Sun.COM
23777978SPeter.Dunlap@Sun.COM /* Create connection ID pool */
23787978SPeter.Dunlap@Sun.COM (void) idm_idpool_create(&idm.idm_conn_id_pool);
23797978SPeter.Dunlap@Sun.COM
23807978SPeter.Dunlap@Sun.COM return (DDI_SUCCESS);
23817978SPeter.Dunlap@Sun.COM }
23827978SPeter.Dunlap@Sun.COM
23837978SPeter.Dunlap@Sun.COM static int
_idm_fini(void)23847978SPeter.Dunlap@Sun.COM _idm_fini(void)
23857978SPeter.Dunlap@Sun.COM {
23867978SPeter.Dunlap@Sun.COM if (!list_is_empty(&idm.idm_ini_conn_list) ||
23877978SPeter.Dunlap@Sun.COM !list_is_empty(&idm.idm_tgt_conn_list) ||
23887978SPeter.Dunlap@Sun.COM !list_is_empty(&idm.idm_tgt_svc_list)) {
23897978SPeter.Dunlap@Sun.COM return (EBUSY);
23907978SPeter.Dunlap@Sun.COM }
23917978SPeter.Dunlap@Sun.COM
23927978SPeter.Dunlap@Sun.COM mutex_enter(&idm.idm_global_mutex);
23937978SPeter.Dunlap@Sun.COM idm.idm_wd_thread_running = B_FALSE;
23947978SPeter.Dunlap@Sun.COM cv_signal(&idm.idm_wd_cv);
23957978SPeter.Dunlap@Sun.COM mutex_exit(&idm.idm_global_mutex);
23967978SPeter.Dunlap@Sun.COM
23977978SPeter.Dunlap@Sun.COM thread_join(idm.idm_wd_thread_did);
23987978SPeter.Dunlap@Sun.COM
23997978SPeter.Dunlap@Sun.COM idm_idpool_destroy(&idm.idm_conn_id_pool);
24009162SPeter.Dunlap@Sun.COM
24019162SPeter.Dunlap@Sun.COM /* Close any LDI handles we have open on transport drivers */
24029162SPeter.Dunlap@Sun.COM mutex_enter(&idm.idm_global_mutex);
24039162SPeter.Dunlap@Sun.COM idm_transport_teardown();
24049162SPeter.Dunlap@Sun.COM mutex_exit(&idm.idm_global_mutex);
24059162SPeter.Dunlap@Sun.COM
24069162SPeter.Dunlap@Sun.COM /* Teardown the native sockets transport */
24077978SPeter.Dunlap@Sun.COM idm_so_fini();
24089162SPeter.Dunlap@Sun.COM
24097978SPeter.Dunlap@Sun.COM list_destroy(&idm.idm_ini_conn_list);
24107978SPeter.Dunlap@Sun.COM list_destroy(&idm.idm_tgt_conn_list);
24117978SPeter.Dunlap@Sun.COM list_destroy(&idm.idm_tgt_svc_list);
24127978SPeter.Dunlap@Sun.COM kmem_cache_destroy(idm.idm_task_cache);
24137978SPeter.Dunlap@Sun.COM kmem_cache_destroy(idm.idm_buf_cache);
24147978SPeter.Dunlap@Sun.COM kmem_free(idm.idm_taskid_table,
24157978SPeter.Dunlap@Sun.COM idm.idm_taskid_max * sizeof (idm_task_t *));
24167978SPeter.Dunlap@Sun.COM mutex_destroy(&idm.idm_global_mutex);
24177978SPeter.Dunlap@Sun.COM cv_destroy(&idm.idm_wd_cv);
24187978SPeter.Dunlap@Sun.COM cv_destroy(&idm.idm_tgt_svc_cv);
24197978SPeter.Dunlap@Sun.COM rw_destroy(&idm.idm_taskid_table_lock);
24207978SPeter.Dunlap@Sun.COM
24217978SPeter.Dunlap@Sun.COM return (0);
24227978SPeter.Dunlap@Sun.COM }
2423