1a6d42e7dSPeter Dunlap /*
2a6d42e7dSPeter Dunlap * CDDL HEADER START
3a6d42e7dSPeter Dunlap *
4a6d42e7dSPeter Dunlap * The contents of this file are subject to the terms of the
5a6d42e7dSPeter Dunlap * Common Development and Distribution License (the "License").
6a6d42e7dSPeter Dunlap * You may not use this file except in compliance with the License.
7a6d42e7dSPeter Dunlap *
8a6d42e7dSPeter Dunlap * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9a6d42e7dSPeter Dunlap * or http://www.opensolaris.org/os/licensing.
10a6d42e7dSPeter Dunlap * See the License for the specific language governing permissions
11a6d42e7dSPeter Dunlap * and limitations under the License.
12a6d42e7dSPeter Dunlap *
13a6d42e7dSPeter Dunlap * When distributing Covered Code, include this CDDL HEADER in each
14a6d42e7dSPeter Dunlap * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15a6d42e7dSPeter Dunlap * If applicable, add the following below this CDDL HEADER, with the
16a6d42e7dSPeter Dunlap * fields enclosed by brackets "[]" replaced with your own identifying
17a6d42e7dSPeter Dunlap * information: Portions Copyright [yyyy] [name of copyright owner]
18a6d42e7dSPeter Dunlap *
19a6d42e7dSPeter Dunlap * CDDL HEADER END
20a6d42e7dSPeter Dunlap */
21a6d42e7dSPeter Dunlap /*
22d618d68dSPriya Krishnan * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
2361dfa509SRick McNeal * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
24a6d42e7dSPeter Dunlap */
25a6d42e7dSPeter Dunlap
26a6d42e7dSPeter Dunlap #include <sys/cpuvar.h>
27a6d42e7dSPeter Dunlap #include <sys/conf.h>
28a6d42e7dSPeter Dunlap #include <sys/file.h>
29a6d42e7dSPeter Dunlap #include <sys/ddi.h>
30a6d42e7dSPeter Dunlap #include <sys/sunddi.h>
31a6d42e7dSPeter Dunlap #include <sys/modctl.h>
32a6d42e7dSPeter Dunlap
33a6d42e7dSPeter Dunlap #include <sys/socket.h>
34a6d42e7dSPeter Dunlap #include <sys/strsubr.h>
35a6d42e7dSPeter Dunlap #include <sys/sysmacros.h>
36a6d42e7dSPeter Dunlap
37a6d42e7dSPeter Dunlap #include <sys/socketvar.h>
38a6d42e7dSPeter Dunlap #include <netinet/in.h>
39a6d42e7dSPeter Dunlap
40a6d42e7dSPeter Dunlap #include <sys/idm/idm.h>
41a6d42e7dSPeter Dunlap #include <sys/idm/idm_so.h>
42a6d42e7dSPeter Dunlap
43a6d42e7dSPeter Dunlap #define IDM_NAME_VERSION "iSCSI Data Mover"
44a6d42e7dSPeter Dunlap
45a6d42e7dSPeter Dunlap extern struct mod_ops mod_miscops;
46a6d42e7dSPeter Dunlap extern struct mod_ops mod_miscops;
47a6d42e7dSPeter Dunlap
48a6d42e7dSPeter Dunlap static struct modlmisc modlmisc = {
49a6d42e7dSPeter Dunlap &mod_miscops, /* Type of module */
50a6d42e7dSPeter Dunlap IDM_NAME_VERSION
51a6d42e7dSPeter Dunlap };
52a6d42e7dSPeter Dunlap
53a6d42e7dSPeter Dunlap static struct modlinkage modlinkage = {
54a6d42e7dSPeter Dunlap MODREV_1, (void *)&modlmisc, NULL
55a6d42e7dSPeter Dunlap };
56a6d42e7dSPeter Dunlap
57a6d42e7dSPeter Dunlap extern void idm_wd_thread(void *arg);
58a6d42e7dSPeter Dunlap
59a6d42e7dSPeter Dunlap static int _idm_init(void);
60a6d42e7dSPeter Dunlap static int _idm_fini(void);
61a6d42e7dSPeter Dunlap static void idm_buf_bind_in_locked(idm_task_t *idt, idm_buf_t *buf);
62a6d42e7dSPeter Dunlap static void idm_buf_bind_out_locked(idm_task_t *idt, idm_buf_t *buf);
63a6d42e7dSPeter Dunlap static void idm_buf_unbind_in_locked(idm_task_t *idt, idm_buf_t *buf);
64a6d42e7dSPeter Dunlap static void idm_buf_unbind_out_locked(idm_task_t *idt, idm_buf_t *buf);
6561dfa509SRick McNeal static stmf_status_t idm_task_abort_one(idm_conn_t *ic, idm_task_t *idt,
66a6d42e7dSPeter Dunlap idm_abort_type_t abort_type);
67a6d42e7dSPeter Dunlap static void idm_task_aborted(idm_task_t *idt, idm_status_t status);
6830e7468fSPeter Dunlap static idm_pdu_t *idm_pdu_alloc_common(uint_t hdrlen, uint_t datalen,
6930e7468fSPeter Dunlap int sleepflag);
70a6d42e7dSPeter Dunlap
71a6d42e7dSPeter Dunlap boolean_t idm_conn_logging = 0;
72a6d42e7dSPeter Dunlap boolean_t idm_svc_logging = 0;
7330e7468fSPeter Dunlap #ifdef DEBUG
7430e7468fSPeter Dunlap boolean_t idm_pattern_checking = 1;
7530e7468fSPeter Dunlap #else
7630e7468fSPeter Dunlap boolean_t idm_pattern_checking = 0;
7730e7468fSPeter Dunlap #endif
78a6d42e7dSPeter Dunlap
79a6d42e7dSPeter Dunlap /*
80a6d42e7dSPeter Dunlap * Potential tuneable for the maximum number of tasks. Default to
81a6d42e7dSPeter Dunlap * IDM_TASKIDS_MAX
82a6d42e7dSPeter Dunlap */
83a6d42e7dSPeter Dunlap
84a6d42e7dSPeter Dunlap uint32_t idm_max_taskids = IDM_TASKIDS_MAX;
85a6d42e7dSPeter Dunlap
86a6d42e7dSPeter Dunlap /*
87a6d42e7dSPeter Dunlap * Global list of transport handles
88a6d42e7dSPeter Dunlap * These are listed in preferential order, so we can simply take the
89a6d42e7dSPeter Dunlap * first "it_conn_is_capable" hit. Note also that the order maps to
90a6d42e7dSPeter Dunlap * the order of the idm_transport_type_t list.
91a6d42e7dSPeter Dunlap */
92a6d42e7dSPeter Dunlap idm_transport_t idm_transport_list[] = {
93a6d42e7dSPeter Dunlap
94a6d42e7dSPeter Dunlap /* iSER on InfiniBand transport handle */
95a6d42e7dSPeter Dunlap {IDM_TRANSPORT_TYPE_ISER, /* type */
96a6d42e7dSPeter Dunlap "/devices/ib/iser@0:iser", /* device path */
97a6d42e7dSPeter Dunlap NULL, /* LDI handle */
98a6d42e7dSPeter Dunlap NULL, /* transport ops */
99a6d42e7dSPeter Dunlap NULL}, /* transport caps */
100a6d42e7dSPeter Dunlap
101a6d42e7dSPeter Dunlap /* IDM native sockets transport handle */
102a6d42e7dSPeter Dunlap {IDM_TRANSPORT_TYPE_SOCKETS, /* type */
103a6d42e7dSPeter Dunlap NULL, /* device path */
104a6d42e7dSPeter Dunlap NULL, /* LDI handle */
105a6d42e7dSPeter Dunlap NULL, /* transport ops */
106a6d42e7dSPeter Dunlap NULL} /* transport caps */
107a6d42e7dSPeter Dunlap
108a6d42e7dSPeter Dunlap };
109a6d42e7dSPeter Dunlap
110*a98e9e2eSToomas Soome idm_global_t idm; /* Global state */
111*a98e9e2eSToomas Soome
112a6d42e7dSPeter Dunlap int
_init(void)113a6d42e7dSPeter Dunlap _init(void)
114a6d42e7dSPeter Dunlap {
115a6d42e7dSPeter Dunlap int rc;
116a6d42e7dSPeter Dunlap
117a6d42e7dSPeter Dunlap if ((rc = _idm_init()) != 0) {
118a6d42e7dSPeter Dunlap return (rc);
119a6d42e7dSPeter Dunlap }
120a6d42e7dSPeter Dunlap
121a6d42e7dSPeter Dunlap return (mod_install(&modlinkage));
122a6d42e7dSPeter Dunlap }
123a6d42e7dSPeter Dunlap
124a6d42e7dSPeter Dunlap int
_fini(void)125a6d42e7dSPeter Dunlap _fini(void)
126a6d42e7dSPeter Dunlap {
127a6d42e7dSPeter Dunlap int rc;
128a6d42e7dSPeter Dunlap
129a6d42e7dSPeter Dunlap if ((rc = _idm_fini()) != 0) {
130a6d42e7dSPeter Dunlap return (rc);
131a6d42e7dSPeter Dunlap }
132a6d42e7dSPeter Dunlap
133a6d42e7dSPeter Dunlap if ((rc = mod_remove(&modlinkage)) != 0) {
134a6d42e7dSPeter Dunlap return (rc);
135a6d42e7dSPeter Dunlap }
136a6d42e7dSPeter Dunlap
137a6d42e7dSPeter Dunlap return (rc);
138a6d42e7dSPeter Dunlap }
139a6d42e7dSPeter Dunlap
140a6d42e7dSPeter Dunlap int
_info(struct modinfo * modinfop)141a6d42e7dSPeter Dunlap _info(struct modinfo *modinfop)
142a6d42e7dSPeter Dunlap {
143a6d42e7dSPeter Dunlap return (mod_info(&modlinkage, modinfop));
144a6d42e7dSPeter Dunlap }
145a6d42e7dSPeter Dunlap
146a6d42e7dSPeter Dunlap /*
147a6d42e7dSPeter Dunlap * idm_transport_register()
148a6d42e7dSPeter Dunlap *
149a6d42e7dSPeter Dunlap * Provides a mechanism for an IDM transport driver to register its
150a6d42e7dSPeter Dunlap * transport ops and caps with the IDM kernel module. Invoked during
151a6d42e7dSPeter Dunlap * a transport driver's attach routine.
152a6d42e7dSPeter Dunlap */
153a6d42e7dSPeter Dunlap idm_status_t
idm_transport_register(idm_transport_attr_t * attr)154a6d42e7dSPeter Dunlap idm_transport_register(idm_transport_attr_t *attr)
155a6d42e7dSPeter Dunlap {
156a6d42e7dSPeter Dunlap ASSERT(attr->it_ops != NULL);
157a6d42e7dSPeter Dunlap ASSERT(attr->it_caps != NULL);
158a6d42e7dSPeter Dunlap
159a6d42e7dSPeter Dunlap switch (attr->type) {
160a6d42e7dSPeter Dunlap /* All known non-native transports here; for now, iSER */
161a6d42e7dSPeter Dunlap case IDM_TRANSPORT_TYPE_ISER:
162a6d42e7dSPeter Dunlap idm_transport_list[attr->type].it_ops = attr->it_ops;
163a6d42e7dSPeter Dunlap idm_transport_list[attr->type].it_caps = attr->it_caps;
164a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS);
165a6d42e7dSPeter Dunlap
166a6d42e7dSPeter Dunlap default:
167a6d42e7dSPeter Dunlap cmn_err(CE_NOTE, "idm: unknown transport type (0x%x) in "
168a6d42e7dSPeter Dunlap "idm_transport_register", attr->type);
169a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS);
170a6d42e7dSPeter Dunlap }
171a6d42e7dSPeter Dunlap }
172a6d42e7dSPeter Dunlap
173a6d42e7dSPeter Dunlap /*
174a6d42e7dSPeter Dunlap * idm_ini_conn_create
175a6d42e7dSPeter Dunlap *
176a6d42e7dSPeter Dunlap * This function is invoked by the iSCSI layer to create a connection context.
177a6d42e7dSPeter Dunlap * This does not actually establish the socket connection.
178a6d42e7dSPeter Dunlap *
179a6d42e7dSPeter Dunlap * cr - Connection request parameters
180a6d42e7dSPeter Dunlap * new_con - Output parameter that contains the new request if successful
181a6d42e7dSPeter Dunlap *
182a6d42e7dSPeter Dunlap */
183a6d42e7dSPeter Dunlap idm_status_t
idm_ini_conn_create(idm_conn_req_t * cr,idm_conn_t ** new_con)184a6d42e7dSPeter Dunlap idm_ini_conn_create(idm_conn_req_t *cr, idm_conn_t **new_con)
185a6d42e7dSPeter Dunlap {
186a6d42e7dSPeter Dunlap idm_transport_t *it;
187a6d42e7dSPeter Dunlap idm_conn_t *ic;
188a6d42e7dSPeter Dunlap int rc;
189a6d42e7dSPeter Dunlap
190a6d42e7dSPeter Dunlap it = idm_transport_lookup(cr);
191a6d42e7dSPeter Dunlap
192a6d42e7dSPeter Dunlap retry:
193a6d42e7dSPeter Dunlap ic = idm_conn_create_common(CONN_TYPE_INI, it->it_type,
194a6d42e7dSPeter Dunlap &cr->icr_conn_ops);
195a6d42e7dSPeter Dunlap
196a6d42e7dSPeter Dunlap bcopy(&cr->cr_ini_dst_addr, &ic->ic_ini_dst_addr,
197a6d42e7dSPeter Dunlap sizeof (cr->cr_ini_dst_addr));
198a6d42e7dSPeter Dunlap
199a6d42e7dSPeter Dunlap /* create the transport-specific connection components */
200a6d42e7dSPeter Dunlap rc = it->it_ops->it_ini_conn_create(cr, ic);
201a6d42e7dSPeter Dunlap if (rc != IDM_STATUS_SUCCESS) {
202a6d42e7dSPeter Dunlap /* cleanup the failed connection */
203a6d42e7dSPeter Dunlap idm_conn_destroy_common(ic);
204a6d42e7dSPeter Dunlap
205a6d42e7dSPeter Dunlap /*
206a6d42e7dSPeter Dunlap * It is possible for an IB client to connect to
207a6d42e7dSPeter Dunlap * an ethernet-only client via an IB-eth gateway.
208a6d42e7dSPeter Dunlap * Therefore, if we are attempting to use iSER and
209a6d42e7dSPeter Dunlap * fail, retry with sockets before ultimately
210a6d42e7dSPeter Dunlap * failing the connection.
211a6d42e7dSPeter Dunlap */
212a6d42e7dSPeter Dunlap if (it->it_type == IDM_TRANSPORT_TYPE_ISER) {
213a6d42e7dSPeter Dunlap it = &idm_transport_list[IDM_TRANSPORT_TYPE_SOCKETS];
214a6d42e7dSPeter Dunlap goto retry;
215a6d42e7dSPeter Dunlap }
216a6d42e7dSPeter Dunlap
217a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL);
218a6d42e7dSPeter Dunlap }
219a6d42e7dSPeter Dunlap
220a6d42e7dSPeter Dunlap *new_con = ic;
221a6d42e7dSPeter Dunlap
222a6d42e7dSPeter Dunlap mutex_enter(&idm.idm_global_mutex);
223a6d42e7dSPeter Dunlap list_insert_tail(&idm.idm_ini_conn_list, ic);
224a6d42e7dSPeter Dunlap mutex_exit(&idm.idm_global_mutex);
225a6d42e7dSPeter Dunlap
226a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS);
227a6d42e7dSPeter Dunlap }
228a6d42e7dSPeter Dunlap
229a6d42e7dSPeter Dunlap /*
230a6d42e7dSPeter Dunlap * idm_ini_conn_destroy
231a6d42e7dSPeter Dunlap *
232a6d42e7dSPeter Dunlap * Releases any resources associated with the connection. This is the
233a6d42e7dSPeter Dunlap * complement to idm_ini_conn_create.
234a6d42e7dSPeter Dunlap * ic - idm_conn_t structure representing the relevant connection
235a6d42e7dSPeter Dunlap *
236a6d42e7dSPeter Dunlap */
23730e7468fSPeter Dunlap void
idm_ini_conn_destroy_task(void * ic_void)23830e7468fSPeter Dunlap idm_ini_conn_destroy_task(void *ic_void)
23930e7468fSPeter Dunlap {
24030e7468fSPeter Dunlap idm_conn_t *ic = ic_void;
24130e7468fSPeter Dunlap
24230e7468fSPeter Dunlap ic->ic_transport_ops->it_ini_conn_destroy(ic);
24330e7468fSPeter Dunlap idm_conn_destroy_common(ic);
24430e7468fSPeter Dunlap }
24530e7468fSPeter Dunlap
246a6d42e7dSPeter Dunlap void
idm_ini_conn_destroy(idm_conn_t * ic)247a6d42e7dSPeter Dunlap idm_ini_conn_destroy(idm_conn_t *ic)
248a6d42e7dSPeter Dunlap {
24930e7468fSPeter Dunlap /*
25030e7468fSPeter Dunlap * It's reasonable for the initiator to call idm_ini_conn_destroy
25130e7468fSPeter Dunlap * from within the context of the CN_CONNECT_DESTROY notification.
25230e7468fSPeter Dunlap * That's a problem since we want to destroy the taskq for the
25330e7468fSPeter Dunlap * state machine associated with the connection. Remove the
25430e7468fSPeter Dunlap * connection from the list right away then handle the remaining
25530e7468fSPeter Dunlap * work via the idm_global_taskq.
25630e7468fSPeter Dunlap */
257a6d42e7dSPeter Dunlap mutex_enter(&idm.idm_global_mutex);
258a6d42e7dSPeter Dunlap list_remove(&idm.idm_ini_conn_list, ic);
259a6d42e7dSPeter Dunlap mutex_exit(&idm.idm_global_mutex);
260a6d42e7dSPeter Dunlap
26130e7468fSPeter Dunlap if (taskq_dispatch(idm.idm_global_taskq,
262fc8ae2ecSToomas Soome &idm_ini_conn_destroy_task, ic, TQ_SLEEP) == TASKQID_INVALID) {
26330e7468fSPeter Dunlap cmn_err(CE_WARN,
26430e7468fSPeter Dunlap "idm_ini_conn_destroy: Couldn't dispatch task");
26530e7468fSPeter Dunlap }
266a6d42e7dSPeter Dunlap }
267a6d42e7dSPeter Dunlap
268a6d42e7dSPeter Dunlap /*
269a6d42e7dSPeter Dunlap * idm_ini_conn_connect
270a6d42e7dSPeter Dunlap *
271a6d42e7dSPeter Dunlap * Establish connection to the remote system identified in idm_conn_t.
272a6d42e7dSPeter Dunlap * The connection parameters including the remote IP address were established
27330e7468fSPeter Dunlap * in the call to idm_ini_conn_create. The IDM state machine will
27430e7468fSPeter Dunlap * perform client notifications as necessary to prompt the initiator through
27530e7468fSPeter Dunlap * the login process. IDM also keeps a timer running so that if the login
27630e7468fSPeter Dunlap * process doesn't complete in a timely manner it will fail.
277a6d42e7dSPeter Dunlap *
278a6d42e7dSPeter Dunlap * ic - idm_conn_t structure representing the relevant connection
279a6d42e7dSPeter Dunlap *
280a6d42e7dSPeter Dunlap * Returns success if the connection was established, otherwise some kind
281a6d42e7dSPeter Dunlap * of meaningful error code.
282a6d42e7dSPeter Dunlap *
28330e7468fSPeter Dunlap * Upon return the login has either failed or is loggin in (ffp)
284a6d42e7dSPeter Dunlap */
285a6d42e7dSPeter Dunlap idm_status_t
idm_ini_conn_connect(idm_conn_t * ic)286a6d42e7dSPeter Dunlap idm_ini_conn_connect(idm_conn_t *ic)
287a6d42e7dSPeter Dunlap {
2885f7d09c6SPeter Cudhea - Sun Microsystems - Burlington, MA United States idm_status_t rc;
289a6d42e7dSPeter Dunlap
290a6d42e7dSPeter Dunlap rc = idm_conn_sm_init(ic);
291a6d42e7dSPeter Dunlap if (rc != IDM_STATUS_SUCCESS) {
292a6d42e7dSPeter Dunlap return (ic->ic_conn_sm_status);
293a6d42e7dSPeter Dunlap }
29430e7468fSPeter Dunlap
29530e7468fSPeter Dunlap /* Hold connection until we return */
29630e7468fSPeter Dunlap idm_conn_hold(ic);
29730e7468fSPeter Dunlap
298a6d42e7dSPeter Dunlap /* Kick state machine */
2998e718be9SToomas Soome idm_conn_event(ic, CE_CONNECT_REQ, (uintptr_t)NULL);
300a6d42e7dSPeter Dunlap
301a6d42e7dSPeter Dunlap /* Wait for login flag */
302a6d42e7dSPeter Dunlap mutex_enter(&ic->ic_state_mutex);
303a6d42e7dSPeter Dunlap while (!(ic->ic_state_flags & CF_LOGIN_READY) &&
304a6d42e7dSPeter Dunlap !(ic->ic_state_flags & CF_ERROR)) {
305a6d42e7dSPeter Dunlap cv_wait(&ic->ic_state_cv, &ic->ic_state_mutex);
306a6d42e7dSPeter Dunlap }
307a6d42e7dSPeter Dunlap
3085f7d09c6SPeter Cudhea - Sun Microsystems - Burlington, MA United States /*
3095f7d09c6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * The CN_READY_TO_LOGIN and/or the CN_CONNECT_FAIL call to
3105f7d09c6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * idm_notify_client has already been generated by the idm conn
3115f7d09c6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * state machine. If connection fails any time after this
3125f7d09c6SPeter Cudhea - Sun Microsystems - Burlington, MA United States * check, we will detect it in iscsi_login.
3135f7d09c6SPeter Cudhea - Sun Microsystems - Burlington, MA United States */
314a6d42e7dSPeter Dunlap if (ic->ic_state_flags & CF_ERROR) {
3155f7d09c6SPeter Cudhea - Sun Microsystems - Burlington, MA United States rc = ic->ic_conn_sm_status;
316a6d42e7dSPeter Dunlap }
3175f7d09c6SPeter Cudhea - Sun Microsystems - Burlington, MA United States mutex_exit(&ic->ic_state_mutex);
31830e7468fSPeter Dunlap idm_conn_rele(ic);
31930e7468fSPeter Dunlap
32030e7468fSPeter Dunlap return (rc);
321a6d42e7dSPeter Dunlap }
322a6d42e7dSPeter Dunlap
323a6d42e7dSPeter Dunlap /*
32430e7468fSPeter Dunlap * idm_ini_conn_disconnect
325a6d42e7dSPeter Dunlap *
32630e7468fSPeter Dunlap * Forces a connection (previously established using idm_ini_conn_connect)
32730e7468fSPeter Dunlap * to perform a controlled shutdown, cleaning up any outstanding requests.
32830e7468fSPeter Dunlap *
32930e7468fSPeter Dunlap * ic - idm_conn_t structure representing the relevant connection
33030e7468fSPeter Dunlap *
33130e7468fSPeter Dunlap * This is asynchronous and will return before the connection is properly
33230e7468fSPeter Dunlap * shutdown
333a6d42e7dSPeter Dunlap */
33430e7468fSPeter Dunlap /* ARGSUSED */
33530e7468fSPeter Dunlap void
idm_ini_conn_disconnect(idm_conn_t * ic)33630e7468fSPeter Dunlap idm_ini_conn_disconnect(idm_conn_t *ic)
337a6d42e7dSPeter Dunlap {
3388e718be9SToomas Soome idm_conn_event(ic, CE_TRANSPORT_FAIL, (uintptr_t)NULL);
339a6d42e7dSPeter Dunlap }
340a6d42e7dSPeter Dunlap
341a6d42e7dSPeter Dunlap /*
34230e7468fSPeter Dunlap * idm_ini_conn_disconnect_wait
343a6d42e7dSPeter Dunlap *
344a6d42e7dSPeter Dunlap * Forces a connection (previously established using idm_ini_conn_connect)
34530e7468fSPeter Dunlap * to perform a controlled shutdown. Blocks until the connection is
34630e7468fSPeter Dunlap * disconnected.
347a6d42e7dSPeter Dunlap *
348a6d42e7dSPeter Dunlap * ic - idm_conn_t structure representing the relevant connection
349a6d42e7dSPeter Dunlap */
350a6d42e7dSPeter Dunlap /* ARGSUSED */
351a6d42e7dSPeter Dunlap void
idm_ini_conn_disconnect_sync(idm_conn_t * ic)35230e7468fSPeter Dunlap idm_ini_conn_disconnect_sync(idm_conn_t *ic)
353a6d42e7dSPeter Dunlap {
354a6d42e7dSPeter Dunlap mutex_enter(&ic->ic_state_mutex);
35530e7468fSPeter Dunlap if ((ic->ic_state != CS_S9_INIT_ERROR) &&
35630e7468fSPeter Dunlap (ic->ic_state != CS_S11_COMPLETE)) {
3578e718be9SToomas Soome idm_conn_event_locked(ic, CE_TRANSPORT_FAIL, (uintptr_t)NULL,
3588e718be9SToomas Soome CT_NONE);
35930e7468fSPeter Dunlap while ((ic->ic_state != CS_S9_INIT_ERROR) &&
36030e7468fSPeter Dunlap (ic->ic_state != CS_S11_COMPLETE))
36130e7468fSPeter Dunlap cv_wait(&ic->ic_state_cv, &ic->ic_state_mutex);
362a6d42e7dSPeter Dunlap }
363a6d42e7dSPeter Dunlap mutex_exit(&ic->ic_state_mutex);
364a6d42e7dSPeter Dunlap }
365a6d42e7dSPeter Dunlap
366a6d42e7dSPeter Dunlap /*
367a6d42e7dSPeter Dunlap * idm_tgt_svc_create
368a6d42e7dSPeter Dunlap *
369a6d42e7dSPeter Dunlap * The target calls this service to obtain a service context for each available
370a6d42e7dSPeter Dunlap * transport, starting a service of each type related to the IP address and port
371a6d42e7dSPeter Dunlap * passed. The idm_svc_req_t contains the service parameters.
372a6d42e7dSPeter Dunlap */
373a6d42e7dSPeter Dunlap idm_status_t
idm_tgt_svc_create(idm_svc_req_t * sr,idm_svc_t ** new_svc)374a6d42e7dSPeter Dunlap idm_tgt_svc_create(idm_svc_req_t *sr, idm_svc_t **new_svc)
375a6d42e7dSPeter Dunlap {
376a6d42e7dSPeter Dunlap idm_transport_type_t type;
377a6d42e7dSPeter Dunlap idm_transport_t *it;
378a6d42e7dSPeter Dunlap idm_svc_t *is;
379a6d42e7dSPeter Dunlap int rc;
380a6d42e7dSPeter Dunlap
381a6d42e7dSPeter Dunlap *new_svc = NULL;
382a6d42e7dSPeter Dunlap is = kmem_zalloc(sizeof (idm_svc_t), KM_SLEEP);
383a6d42e7dSPeter Dunlap
384a6d42e7dSPeter Dunlap /* Initialize transport-agnostic components of the service handle */
385a6d42e7dSPeter Dunlap is->is_svc_req = *sr;
386a6d42e7dSPeter Dunlap mutex_init(&is->is_mutex, NULL, MUTEX_DEFAULT, NULL);
387a6d42e7dSPeter Dunlap cv_init(&is->is_cv, NULL, CV_DEFAULT, NULL);
388a6d42e7dSPeter Dunlap mutex_init(&is->is_count_mutex, NULL, MUTEX_DEFAULT, NULL);
389a6d42e7dSPeter Dunlap cv_init(&is->is_count_cv, NULL, CV_DEFAULT, NULL);
390a6d42e7dSPeter Dunlap idm_refcnt_init(&is->is_refcnt, is);
391a6d42e7dSPeter Dunlap
392a6d42e7dSPeter Dunlap /*
393a6d42e7dSPeter Dunlap * Make sure all available transports are setup. We call this now
394a6d42e7dSPeter Dunlap * instead of at initialization time in case IB has become available
395a6d42e7dSPeter Dunlap * since we started (hotplug, etc).
396a6d42e7dSPeter Dunlap */
397bbe72583SJack Meng idm_transport_setup(sr->sr_li, B_FALSE);
398a6d42e7dSPeter Dunlap
399a6d42e7dSPeter Dunlap /*
400a6d42e7dSPeter Dunlap * Loop through the transports, configuring the transport-specific
401a6d42e7dSPeter Dunlap * components of each one.
402a6d42e7dSPeter Dunlap */
403a6d42e7dSPeter Dunlap for (type = 0; type < IDM_TRANSPORT_NUM_TYPES; type++) {
404a6d42e7dSPeter Dunlap
405a6d42e7dSPeter Dunlap it = &idm_transport_list[type];
406a6d42e7dSPeter Dunlap /*
407a6d42e7dSPeter Dunlap * If it_ops is NULL then the transport is unconfigured
408a6d42e7dSPeter Dunlap * and we shouldn't try to start the service.
409a6d42e7dSPeter Dunlap */
410a6d42e7dSPeter Dunlap if (it->it_ops == NULL) {
411a6d42e7dSPeter Dunlap continue;
412a6d42e7dSPeter Dunlap }
413a6d42e7dSPeter Dunlap
414a6d42e7dSPeter Dunlap rc = it->it_ops->it_tgt_svc_create(sr, is);
415a6d42e7dSPeter Dunlap if (rc != IDM_STATUS_SUCCESS) {
416a6d42e7dSPeter Dunlap /* Teardown any configured services */
417a6d42e7dSPeter Dunlap while (type--) {
418a6d42e7dSPeter Dunlap it = &idm_transport_list[type];
419a6d42e7dSPeter Dunlap if (it->it_ops == NULL) {
420a6d42e7dSPeter Dunlap continue;
421a6d42e7dSPeter Dunlap }
422a6d42e7dSPeter Dunlap it->it_ops->it_tgt_svc_destroy(is);
423a6d42e7dSPeter Dunlap }
424a6d42e7dSPeter Dunlap /* Free the svc context and return */
425a6d42e7dSPeter Dunlap kmem_free(is, sizeof (idm_svc_t));
426a6d42e7dSPeter Dunlap return (rc);
427a6d42e7dSPeter Dunlap }
428a6d42e7dSPeter Dunlap }
429a6d42e7dSPeter Dunlap
430a6d42e7dSPeter Dunlap *new_svc = is;
431a6d42e7dSPeter Dunlap
432a6d42e7dSPeter Dunlap mutex_enter(&idm.idm_global_mutex);
433a6d42e7dSPeter Dunlap list_insert_tail(&idm.idm_tgt_svc_list, is);
434a6d42e7dSPeter Dunlap mutex_exit(&idm.idm_global_mutex);
435a6d42e7dSPeter Dunlap
436a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS);
437a6d42e7dSPeter Dunlap }
438a6d42e7dSPeter Dunlap
439a6d42e7dSPeter Dunlap /*
440a6d42e7dSPeter Dunlap * idm_tgt_svc_destroy
441a6d42e7dSPeter Dunlap *
442a6d42e7dSPeter Dunlap * is - idm_svc_t returned by the call to idm_tgt_svc_create
443a6d42e7dSPeter Dunlap *
444a6d42e7dSPeter Dunlap * Cleanup any resources associated with the idm_svc_t.
445a6d42e7dSPeter Dunlap */
446a6d42e7dSPeter Dunlap void
idm_tgt_svc_destroy(idm_svc_t * is)447a6d42e7dSPeter Dunlap idm_tgt_svc_destroy(idm_svc_t *is)
448a6d42e7dSPeter Dunlap {
449a6d42e7dSPeter Dunlap idm_transport_type_t type;
450a6d42e7dSPeter Dunlap idm_transport_t *it;
451a6d42e7dSPeter Dunlap
452a6d42e7dSPeter Dunlap mutex_enter(&idm.idm_global_mutex);
453a6d42e7dSPeter Dunlap /* remove this service from the global list */
454a6d42e7dSPeter Dunlap list_remove(&idm.idm_tgt_svc_list, is);
455a6d42e7dSPeter Dunlap /* wakeup any waiters for service change */
456a6d42e7dSPeter Dunlap cv_broadcast(&idm.idm_tgt_svc_cv);
457a6d42e7dSPeter Dunlap mutex_exit(&idm.idm_global_mutex);
458a6d42e7dSPeter Dunlap
459a6d42e7dSPeter Dunlap /* teardown each transport-specific service */
460a6d42e7dSPeter Dunlap for (type = 0; type < IDM_TRANSPORT_NUM_TYPES; type++) {
461a6d42e7dSPeter Dunlap it = &idm_transport_list[type];
462a6d42e7dSPeter Dunlap if (it->it_ops == NULL) {
463a6d42e7dSPeter Dunlap continue;
464a6d42e7dSPeter Dunlap }
465a6d42e7dSPeter Dunlap
466a6d42e7dSPeter Dunlap it->it_ops->it_tgt_svc_destroy(is);
467a6d42e7dSPeter Dunlap }
468a6d42e7dSPeter Dunlap
46930e7468fSPeter Dunlap /* tear down the svc resources */
47030e7468fSPeter Dunlap idm_refcnt_destroy(&is->is_refcnt);
47130e7468fSPeter Dunlap cv_destroy(&is->is_count_cv);
47230e7468fSPeter Dunlap mutex_destroy(&is->is_count_mutex);
47330e7468fSPeter Dunlap cv_destroy(&is->is_cv);
47430e7468fSPeter Dunlap mutex_destroy(&is->is_mutex);
47530e7468fSPeter Dunlap
476a6d42e7dSPeter Dunlap /* free the svc handle */
477a6d42e7dSPeter Dunlap kmem_free(is, sizeof (idm_svc_t));
478a6d42e7dSPeter Dunlap }
479a6d42e7dSPeter Dunlap
480a6d42e7dSPeter Dunlap void
idm_tgt_svc_hold(idm_svc_t * is)481a6d42e7dSPeter Dunlap idm_tgt_svc_hold(idm_svc_t *is)
482a6d42e7dSPeter Dunlap {
483a6d42e7dSPeter Dunlap idm_refcnt_hold(&is->is_refcnt);
484a6d42e7dSPeter Dunlap }
485a6d42e7dSPeter Dunlap
486a6d42e7dSPeter Dunlap void
idm_tgt_svc_rele_and_destroy(idm_svc_t * is)487a6d42e7dSPeter Dunlap idm_tgt_svc_rele_and_destroy(idm_svc_t *is)
488a6d42e7dSPeter Dunlap {
489a6d42e7dSPeter Dunlap idm_refcnt_rele_and_destroy(&is->is_refcnt,
490a6d42e7dSPeter Dunlap (idm_refcnt_cb_t *)&idm_tgt_svc_destroy);
491a6d42e7dSPeter Dunlap }
492a6d42e7dSPeter Dunlap
493a6d42e7dSPeter Dunlap /*
494a6d42e7dSPeter Dunlap * idm_tgt_svc_online
495a6d42e7dSPeter Dunlap *
496a6d42e7dSPeter Dunlap * is - idm_svc_t returned by the call to idm_tgt_svc_create
497a6d42e7dSPeter Dunlap *
498a6d42e7dSPeter Dunlap * Online each transport service, as we want this target to be accessible
499a6d42e7dSPeter Dunlap * via any configured transport.
500a6d42e7dSPeter Dunlap *
501a6d42e7dSPeter Dunlap * When the initiator establishes a new connection to the target, IDM will
502a6d42e7dSPeter Dunlap * call the "new connect" callback defined in the idm_svc_req_t structure
503a6d42e7dSPeter Dunlap * and it will pass an idm_conn_t structure representing that new connection.
504a6d42e7dSPeter Dunlap */
505a6d42e7dSPeter Dunlap idm_status_t
idm_tgt_svc_online(idm_svc_t * is)506a6d42e7dSPeter Dunlap idm_tgt_svc_online(idm_svc_t *is)
507a6d42e7dSPeter Dunlap {
508a6d42e7dSPeter Dunlap
50930e7468fSPeter Dunlap idm_transport_type_t type, last_type;
510a6d42e7dSPeter Dunlap idm_transport_t *it;
51130e7468fSPeter Dunlap int rc = IDM_STATUS_SUCCESS;
512a6d42e7dSPeter Dunlap
513a6d42e7dSPeter Dunlap mutex_enter(&is->is_mutex);
514a6d42e7dSPeter Dunlap if (is->is_online == 0) {
51530e7468fSPeter Dunlap /* Walk through each of the transports and online them */
516a6d42e7dSPeter Dunlap for (type = 0; type < IDM_TRANSPORT_NUM_TYPES; type++) {
517a6d42e7dSPeter Dunlap it = &idm_transport_list[type];
518a6d42e7dSPeter Dunlap if (it->it_ops == NULL) {
519a6d42e7dSPeter Dunlap /* transport is not registered */
520a6d42e7dSPeter Dunlap continue;
521a6d42e7dSPeter Dunlap }
522a6d42e7dSPeter Dunlap
523a6d42e7dSPeter Dunlap mutex_exit(&is->is_mutex);
524a6d42e7dSPeter Dunlap rc = it->it_ops->it_tgt_svc_online(is);
525a6d42e7dSPeter Dunlap mutex_enter(&is->is_mutex);
52630e7468fSPeter Dunlap if (rc != IDM_STATUS_SUCCESS) {
52730e7468fSPeter Dunlap last_type = type;
52830e7468fSPeter Dunlap break;
52930e7468fSPeter Dunlap }
53030e7468fSPeter Dunlap }
53130e7468fSPeter Dunlap if (rc != IDM_STATUS_SUCCESS) {
53230e7468fSPeter Dunlap /*
53330e7468fSPeter Dunlap * The last transport failed to online.
53430e7468fSPeter Dunlap * Offline any transport onlined above and
53530e7468fSPeter Dunlap * do not online the target.
53630e7468fSPeter Dunlap */
53730e7468fSPeter Dunlap for (type = 0; type < last_type; type++) {
53830e7468fSPeter Dunlap it = &idm_transport_list[type];
53930e7468fSPeter Dunlap if (it->it_ops == NULL) {
54030e7468fSPeter Dunlap /* transport is not registered */
54130e7468fSPeter Dunlap continue;
54230e7468fSPeter Dunlap }
54330e7468fSPeter Dunlap
54430e7468fSPeter Dunlap mutex_exit(&is->is_mutex);
54530e7468fSPeter Dunlap it->it_ops->it_tgt_svc_offline(is);
54630e7468fSPeter Dunlap mutex_enter(&is->is_mutex);
547a6d42e7dSPeter Dunlap }
54830e7468fSPeter Dunlap } else {
54930e7468fSPeter Dunlap /* Target service now online */
55030e7468fSPeter Dunlap is->is_online = 1;
551a6d42e7dSPeter Dunlap }
552a6d42e7dSPeter Dunlap } else {
55330e7468fSPeter Dunlap /* Target service already online, just bump the count */
554a6d42e7dSPeter Dunlap is->is_online++;
55530e7468fSPeter Dunlap }
556a6d42e7dSPeter Dunlap mutex_exit(&is->is_mutex);
557a6d42e7dSPeter Dunlap
55830e7468fSPeter Dunlap return (rc);
559a6d42e7dSPeter Dunlap }
560a6d42e7dSPeter Dunlap
561a6d42e7dSPeter Dunlap /*
562a6d42e7dSPeter Dunlap * idm_tgt_svc_offline
563a6d42e7dSPeter Dunlap *
564a6d42e7dSPeter Dunlap * is - idm_svc_t returned by the call to idm_tgt_svc_create
565a6d42e7dSPeter Dunlap *
566a6d42e7dSPeter Dunlap * Shutdown any online target services.
567a6d42e7dSPeter Dunlap */
568a6d42e7dSPeter Dunlap void
idm_tgt_svc_offline(idm_svc_t * is)569a6d42e7dSPeter Dunlap idm_tgt_svc_offline(idm_svc_t *is)
570a6d42e7dSPeter Dunlap {
571a6d42e7dSPeter Dunlap idm_transport_type_t type;
572a6d42e7dSPeter Dunlap idm_transport_t *it;
573a6d42e7dSPeter Dunlap
574a6d42e7dSPeter Dunlap mutex_enter(&is->is_mutex);
575a6d42e7dSPeter Dunlap is->is_online--;
576a6d42e7dSPeter Dunlap if (is->is_online == 0) {
577a6d42e7dSPeter Dunlap /* Walk through each of the transports and offline them */
578a6d42e7dSPeter Dunlap for (type = 0; type < IDM_TRANSPORT_NUM_TYPES; type++) {
579a6d42e7dSPeter Dunlap it = &idm_transport_list[type];
580a6d42e7dSPeter Dunlap if (it->it_ops == NULL) {
581a6d42e7dSPeter Dunlap /* transport is not registered */
582a6d42e7dSPeter Dunlap continue;
583a6d42e7dSPeter Dunlap }
584a6d42e7dSPeter Dunlap
585a6d42e7dSPeter Dunlap mutex_exit(&is->is_mutex);
586a6d42e7dSPeter Dunlap it->it_ops->it_tgt_svc_offline(is);
587a6d42e7dSPeter Dunlap mutex_enter(&is->is_mutex);
588a6d42e7dSPeter Dunlap }
589a6d42e7dSPeter Dunlap }
590a6d42e7dSPeter Dunlap mutex_exit(&is->is_mutex);
591a6d42e7dSPeter Dunlap }
592a6d42e7dSPeter Dunlap
593a6d42e7dSPeter Dunlap /*
594a6d42e7dSPeter Dunlap * idm_tgt_svc_lookup
595a6d42e7dSPeter Dunlap *
596a6d42e7dSPeter Dunlap * Lookup a service instance listening on the specified port
597a6d42e7dSPeter Dunlap */
598a6d42e7dSPeter Dunlap
599a6d42e7dSPeter Dunlap idm_svc_t *
idm_tgt_svc_lookup(uint16_t port)600a6d42e7dSPeter Dunlap idm_tgt_svc_lookup(uint16_t port)
601a6d42e7dSPeter Dunlap {
602a6d42e7dSPeter Dunlap idm_svc_t *result;
603a6d42e7dSPeter Dunlap
604a6d42e7dSPeter Dunlap retry:
605a6d42e7dSPeter Dunlap mutex_enter(&idm.idm_global_mutex);
606a6d42e7dSPeter Dunlap for (result = list_head(&idm.idm_tgt_svc_list);
607a6d42e7dSPeter Dunlap result != NULL;
608a6d42e7dSPeter Dunlap result = list_next(&idm.idm_tgt_svc_list, result)) {
609a6d42e7dSPeter Dunlap if (result->is_svc_req.sr_port == port) {
610a6d42e7dSPeter Dunlap if (result->is_online == 0) {
611a6d42e7dSPeter Dunlap /*
612a6d42e7dSPeter Dunlap * A service exists on this port, but it
613a6d42e7dSPeter Dunlap * is going away, wait for it to cleanup.
614a6d42e7dSPeter Dunlap */
615a6d42e7dSPeter Dunlap cv_wait(&idm.idm_tgt_svc_cv,
616a6d42e7dSPeter Dunlap &idm.idm_global_mutex);
617a6d42e7dSPeter Dunlap mutex_exit(&idm.idm_global_mutex);
618a6d42e7dSPeter Dunlap goto retry;
619a6d42e7dSPeter Dunlap }
620a6d42e7dSPeter Dunlap idm_tgt_svc_hold(result);
621a6d42e7dSPeter Dunlap mutex_exit(&idm.idm_global_mutex);
622a6d42e7dSPeter Dunlap return (result);
623a6d42e7dSPeter Dunlap }
624a6d42e7dSPeter Dunlap }
625a6d42e7dSPeter Dunlap mutex_exit(&idm.idm_global_mutex);
626a6d42e7dSPeter Dunlap
627a6d42e7dSPeter Dunlap return (NULL);
628a6d42e7dSPeter Dunlap }
629a6d42e7dSPeter Dunlap
630a6d42e7dSPeter Dunlap /*
631a6d42e7dSPeter Dunlap * idm_negotiate_key_values()
632a6d42e7dSPeter Dunlap * Give IDM level a chance to negotiate any login parameters it should own.
633a6d42e7dSPeter Dunlap * -- leave unhandled parameters alone on request_nvl
634a6d42e7dSPeter Dunlap * -- move all handled parameters to response_nvl with an appropriate response
635a6d42e7dSPeter Dunlap * -- also add an entry to negotiated_nvl for any accepted parameters
636a6d42e7dSPeter Dunlap */
637a6d42e7dSPeter Dunlap kv_status_t
idm_negotiate_key_values(idm_conn_t * ic,nvlist_t * request_nvl,nvlist_t * response_nvl,nvlist_t * negotiated_nvl)638a6d42e7dSPeter Dunlap idm_negotiate_key_values(idm_conn_t *ic, nvlist_t *request_nvl,
639a6d42e7dSPeter Dunlap nvlist_t *response_nvl, nvlist_t *negotiated_nvl)
640a6d42e7dSPeter Dunlap {
641a6d42e7dSPeter Dunlap ASSERT(ic->ic_transport_ops != NULL);
642a6d42e7dSPeter Dunlap return (ic->ic_transport_ops->it_negotiate_key_values(ic,
643a6d42e7dSPeter Dunlap request_nvl, response_nvl, negotiated_nvl));
644a6d42e7dSPeter Dunlap }
645a6d42e7dSPeter Dunlap
646a6d42e7dSPeter Dunlap /*
647a6d42e7dSPeter Dunlap * idm_notice_key_values()
648a6d42e7dSPeter Dunlap * Activate at the IDM level any parameters that have been negotiated.
649a6d42e7dSPeter Dunlap * Passes the set of key value pairs to the transport for activation.
650a6d42e7dSPeter Dunlap * This will be invoked as the connection is entering full-feature mode.
651a6d42e7dSPeter Dunlap */
65230e7468fSPeter Dunlap void
idm_notice_key_values(idm_conn_t * ic,nvlist_t * negotiated_nvl)653a6d42e7dSPeter Dunlap idm_notice_key_values(idm_conn_t *ic, nvlist_t *negotiated_nvl)
654a6d42e7dSPeter Dunlap {
655a6d42e7dSPeter Dunlap ASSERT(ic->ic_transport_ops != NULL);
65630e7468fSPeter Dunlap ic->ic_transport_ops->it_notice_key_values(ic, negotiated_nvl);
657a6d42e7dSPeter Dunlap }
658a6d42e7dSPeter Dunlap
65956261083SCharles Ting /*
66056261083SCharles Ting * idm_declare_key_values()
66156261083SCharles Ting * Activate an operational set of declarative parameters from the config_nvl,
66256261083SCharles Ting * and return the selected values in the outgoing_nvl.
66356261083SCharles Ting */
66456261083SCharles Ting kv_status_t
idm_declare_key_values(idm_conn_t * ic,nvlist_t * config_nvl,nvlist_t * outgoing_nvl)66556261083SCharles Ting idm_declare_key_values(idm_conn_t *ic, nvlist_t *config_nvl,
66656261083SCharles Ting nvlist_t *outgoing_nvl)
66756261083SCharles Ting {
66856261083SCharles Ting ASSERT(ic->ic_transport_ops != NULL);
66956261083SCharles Ting return (ic->ic_transport_ops->it_declare_key_values(ic, config_nvl,
67056261083SCharles Ting outgoing_nvl));
67156261083SCharles Ting }
67256261083SCharles Ting
673a6d42e7dSPeter Dunlap /*
674a6d42e7dSPeter Dunlap * idm_buf_tx_to_ini
675a6d42e7dSPeter Dunlap *
676a6d42e7dSPeter Dunlap * This is IDM's implementation of the 'Put_Data' operational primitive.
677a6d42e7dSPeter Dunlap *
678a6d42e7dSPeter Dunlap * This function is invoked by a target iSCSI layer to request its local
679a6d42e7dSPeter Dunlap * Datamover layer to transmit the Data-In PDU to the peer iSCSI layer
680a6d42e7dSPeter Dunlap * on the remote iSCSI node. The I/O buffer represented by 'idb' is
681a6d42e7dSPeter Dunlap * transferred to the initiator associated with task 'idt'. The connection
682a6d42e7dSPeter Dunlap * info, contents of the Data-In PDU header, the DataDescriptorIn, BHS,
683a6d42e7dSPeter Dunlap * and the callback (idb->idb_buf_cb) at transfer completion are
684a6d42e7dSPeter Dunlap * provided as input.
685a6d42e7dSPeter Dunlap *
686a6d42e7dSPeter Dunlap * This data transfer takes place transparently to the remote iSCSI layer,
687a6d42e7dSPeter Dunlap * i.e. without its participation.
688a6d42e7dSPeter Dunlap *
689a6d42e7dSPeter Dunlap * Using sockets, IDM implements the data transfer by segmenting the data
690a6d42e7dSPeter Dunlap * buffer into appropriately sized iSCSI PDUs and transmitting them to the
691a6d42e7dSPeter Dunlap * initiator. iSER performs the transfer using RDMA write.
692a6d42e7dSPeter Dunlap *
693a6d42e7dSPeter Dunlap */
694a6d42e7dSPeter Dunlap 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)695a6d42e7dSPeter Dunlap idm_buf_tx_to_ini(idm_task_t *idt, idm_buf_t *idb,
696a6d42e7dSPeter Dunlap uint32_t offset, uint32_t xfer_len,
697a6d42e7dSPeter Dunlap idm_buf_cb_t idb_buf_cb, void *cb_arg)
698a6d42e7dSPeter Dunlap {
699a6d42e7dSPeter Dunlap idm_status_t rc;
700a6d42e7dSPeter Dunlap
701a6d42e7dSPeter Dunlap idb->idb_bufoffset = offset;
702a6d42e7dSPeter Dunlap idb->idb_xfer_len = xfer_len;
703a6d42e7dSPeter Dunlap idb->idb_buf_cb = idb_buf_cb;
704a6d42e7dSPeter Dunlap idb->idb_cb_arg = cb_arg;
70530e7468fSPeter Dunlap gethrestime(&idb->idb_xfer_start);
70630e7468fSPeter Dunlap
70730e7468fSPeter Dunlap /*
70830e7468fSPeter Dunlap * Buffer should not contain the pattern. If the pattern is
70930e7468fSPeter Dunlap * present then we've been asked to transmit initialized data
71030e7468fSPeter Dunlap */
71130e7468fSPeter Dunlap IDM_BUFPAT_CHECK(idb, xfer_len, BP_CHECK_ASSERT);
712a6d42e7dSPeter Dunlap
713a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex);
714a6d42e7dSPeter Dunlap switch (idt->idt_state) {
715a6d42e7dSPeter Dunlap case TASK_ACTIVE:
716a6d42e7dSPeter Dunlap idt->idt_tx_to_ini_start++;
717a6d42e7dSPeter Dunlap idm_task_hold(idt);
718a6d42e7dSPeter Dunlap idm_buf_bind_in_locked(idt, idb);
719a6d42e7dSPeter Dunlap idb->idb_in_transport = B_TRUE;
720a6d42e7dSPeter Dunlap rc = (*idt->idt_ic->ic_transport_ops->it_buf_tx_to_ini)
721a6d42e7dSPeter Dunlap (idt, idb);
722a6d42e7dSPeter Dunlap return (rc);
723a6d42e7dSPeter Dunlap
724a6d42e7dSPeter Dunlap case TASK_SUSPENDING:
725a6d42e7dSPeter Dunlap case TASK_SUSPENDED:
726a6d42e7dSPeter Dunlap /*
727a6d42e7dSPeter Dunlap * Bind buffer but don't start a transfer since the task
728a6d42e7dSPeter Dunlap * is suspended
729a6d42e7dSPeter Dunlap */
730a6d42e7dSPeter Dunlap idm_buf_bind_in_locked(idt, idb);
731a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex);
732a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS);
733a6d42e7dSPeter Dunlap
734a6d42e7dSPeter Dunlap case TASK_ABORTING:
735a6d42e7dSPeter Dunlap case TASK_ABORTED:
736a6d42e7dSPeter Dunlap /*
737a6d42e7dSPeter Dunlap * Once the task is aborted, any buffers added to the
738a6d42e7dSPeter Dunlap * idt_inbufv will never get cleaned up, so just return
739a6d42e7dSPeter Dunlap * SUCCESS. The buffer should get cleaned up by the
740a6d42e7dSPeter Dunlap * client or framework once task_aborted has completed.
741a6d42e7dSPeter Dunlap */
742a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex);
743a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS);
744a6d42e7dSPeter Dunlap
745a6d42e7dSPeter Dunlap default:
746a6d42e7dSPeter Dunlap ASSERT(0);
747a6d42e7dSPeter Dunlap break;
748a6d42e7dSPeter Dunlap }
749a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex);
750a6d42e7dSPeter Dunlap
751a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL);
752a6d42e7dSPeter Dunlap }
753a6d42e7dSPeter Dunlap
754a6d42e7dSPeter Dunlap /*
755a6d42e7dSPeter Dunlap * idm_buf_rx_from_ini
756a6d42e7dSPeter Dunlap *
757a6d42e7dSPeter Dunlap * This is IDM's implementation of the 'Get_Data' operational primitive.
758a6d42e7dSPeter Dunlap *
759a6d42e7dSPeter Dunlap * This function is invoked by a target iSCSI layer to request its local
760a6d42e7dSPeter Dunlap * Datamover layer to retrieve certain data identified by the R2T PDU from the
761a6d42e7dSPeter Dunlap * peer iSCSI layer on the remote node. The retrieved Data-Out PDU will be
762a6d42e7dSPeter Dunlap * mapped to the respective buffer by the task tags (ITT & TTT).
763a6d42e7dSPeter Dunlap * The connection information, contents of an R2T PDU, DataDescriptor, BHS, and
764a6d42e7dSPeter Dunlap * the callback (idb->idb_buf_cb) notification for data transfer completion are
765a6d42e7dSPeter Dunlap * are provided as input.
766a6d42e7dSPeter Dunlap *
767a6d42e7dSPeter Dunlap * When an iSCSI node sends an R2T PDU to its local Datamover layer, the local
768a6d42e7dSPeter Dunlap * Datamover layer, the local and remote Datamover layers transparently bring
769a6d42e7dSPeter Dunlap * about the data transfer requested by the R2T PDU, without the participation
770a6d42e7dSPeter Dunlap * of the iSCSI layers.
771a6d42e7dSPeter Dunlap *
772a6d42e7dSPeter Dunlap * Using sockets, IDM transmits an R2T PDU for each buffer and the rx_data_out()
773a6d42e7dSPeter Dunlap * assembles the Data-Out PDUs into the buffer. iSER uses RDMA read.
774a6d42e7dSPeter Dunlap *
775a6d42e7dSPeter Dunlap */
776a6d42e7dSPeter Dunlap 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)777a6d42e7dSPeter Dunlap idm_buf_rx_from_ini(idm_task_t *idt, idm_buf_t *idb,
778a6d42e7dSPeter Dunlap uint32_t offset, uint32_t xfer_len,
779a6d42e7dSPeter Dunlap idm_buf_cb_t idb_buf_cb, void *cb_arg)
780a6d42e7dSPeter Dunlap {
781a6d42e7dSPeter Dunlap idm_status_t rc;
782a6d42e7dSPeter Dunlap
783a6d42e7dSPeter Dunlap idb->idb_bufoffset = offset;
784a6d42e7dSPeter Dunlap idb->idb_xfer_len = xfer_len;
785a6d42e7dSPeter Dunlap idb->idb_buf_cb = idb_buf_cb;
786a6d42e7dSPeter Dunlap idb->idb_cb_arg = cb_arg;
78730e7468fSPeter Dunlap gethrestime(&idb->idb_xfer_start);
788a6d42e7dSPeter Dunlap
789a6d42e7dSPeter Dunlap /*
790a6d42e7dSPeter Dunlap * "In" buf list is for "Data In" PDU's, "Out" buf list is for
791a6d42e7dSPeter Dunlap * "Data Out" PDU's
792a6d42e7dSPeter Dunlap */
793a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex);
794a6d42e7dSPeter Dunlap switch (idt->idt_state) {
795a6d42e7dSPeter Dunlap case TASK_ACTIVE:
796a6d42e7dSPeter Dunlap idt->idt_rx_from_ini_start++;
797a6d42e7dSPeter Dunlap idm_task_hold(idt);
798a6d42e7dSPeter Dunlap idm_buf_bind_out_locked(idt, idb);
799a6d42e7dSPeter Dunlap idb->idb_in_transport = B_TRUE;
800a6d42e7dSPeter Dunlap rc = (*idt->idt_ic->ic_transport_ops->it_buf_rx_from_ini)
801a6d42e7dSPeter Dunlap (idt, idb);
802a6d42e7dSPeter Dunlap return (rc);
803a6d42e7dSPeter Dunlap case TASK_SUSPENDING:
804a6d42e7dSPeter Dunlap case TASK_SUSPENDED:
805a6d42e7dSPeter Dunlap case TASK_ABORTING:
806a6d42e7dSPeter Dunlap case TASK_ABORTED:
807a6d42e7dSPeter Dunlap /*
808a6d42e7dSPeter Dunlap * Bind buffer but don't start a transfer since the task
809a6d42e7dSPeter Dunlap * is suspended
810a6d42e7dSPeter Dunlap */
811a6d42e7dSPeter Dunlap idm_buf_bind_out_locked(idt, idb);
812a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex);
813a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS);
814a6d42e7dSPeter Dunlap default:
815a6d42e7dSPeter Dunlap ASSERT(0);
816a6d42e7dSPeter Dunlap break;
817a6d42e7dSPeter Dunlap }
818a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex);
819a6d42e7dSPeter Dunlap
820a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL);
821a6d42e7dSPeter Dunlap }
822a6d42e7dSPeter Dunlap
823a6d42e7dSPeter Dunlap /*
824a6d42e7dSPeter Dunlap * idm_buf_tx_to_ini_done
825a6d42e7dSPeter Dunlap *
826a6d42e7dSPeter Dunlap * The transport calls this after it has completed a transfer requested by
827a6d42e7dSPeter Dunlap * a call to transport_buf_tx_to_ini
828a6d42e7dSPeter Dunlap *
829a6d42e7dSPeter Dunlap * Caller holds idt->idt_mutex, idt->idt_mutex is released before returning.
830a6d42e7dSPeter Dunlap * idt may be freed after the call to idb->idb_buf_cb.
831a6d42e7dSPeter Dunlap */
832a6d42e7dSPeter Dunlap void
idm_buf_tx_to_ini_done(idm_task_t * idt,idm_buf_t * idb,idm_status_t status)833a6d42e7dSPeter Dunlap idm_buf_tx_to_ini_done(idm_task_t *idt, idm_buf_t *idb, idm_status_t status)
834a6d42e7dSPeter Dunlap {
835a6d42e7dSPeter Dunlap ASSERT(mutex_owned(&idt->idt_mutex));
836a6d42e7dSPeter Dunlap idb->idb_in_transport = B_FALSE;
837a6d42e7dSPeter Dunlap idb->idb_tx_thread = B_FALSE;
838a6d42e7dSPeter Dunlap idt->idt_tx_to_ini_done++;
83930e7468fSPeter Dunlap gethrestime(&idb->idb_xfer_done);
840a6d42e7dSPeter Dunlap
841a6d42e7dSPeter Dunlap /*
842a6d42e7dSPeter Dunlap * idm_refcnt_rele may cause TASK_SUSPENDING --> TASK_SUSPENDED or
843a6d42e7dSPeter Dunlap * TASK_ABORTING --> TASK_ABORTED transistion if the refcount goes
844a6d42e7dSPeter Dunlap * to 0.
845a6d42e7dSPeter Dunlap */
846a6d42e7dSPeter Dunlap idm_task_rele(idt);
847a6d42e7dSPeter Dunlap idb->idb_status = status;
848a6d42e7dSPeter Dunlap
849a6d42e7dSPeter Dunlap switch (idt->idt_state) {
850a6d42e7dSPeter Dunlap case TASK_ACTIVE:
85172cf3143Speter dunlap idt->idt_ic->ic_timestamp = ddi_get_lbolt();
852a6d42e7dSPeter Dunlap idm_buf_unbind_in_locked(idt, idb);
853a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex);
854a6d42e7dSPeter Dunlap (*idb->idb_buf_cb)(idb, status);
855a6d42e7dSPeter Dunlap return;
856a6d42e7dSPeter Dunlap case TASK_SUSPENDING:
857a6d42e7dSPeter Dunlap case TASK_SUSPENDED:
858a6d42e7dSPeter Dunlap case TASK_ABORTING:
859a6d42e7dSPeter Dunlap case TASK_ABORTED:
860a6d42e7dSPeter Dunlap /*
861a6d42e7dSPeter Dunlap * To keep things simple we will ignore the case where the
862a6d42e7dSPeter Dunlap * transfer was successful and leave all buffers bound to the
863a6d42e7dSPeter Dunlap * task. This allows us to also ignore the case where we've
864a6d42e7dSPeter Dunlap * been asked to abort a task but the last transfer of the
865a6d42e7dSPeter Dunlap * task has completed. IDM has no idea whether this was, in
866a6d42e7dSPeter Dunlap * fact, the last transfer of the task so it would be difficult
867a6d42e7dSPeter Dunlap * to handle this case. Everything should get sorted out again
868a6d42e7dSPeter Dunlap * after task reassignment is complete.
869a6d42e7dSPeter Dunlap *
870a6d42e7dSPeter Dunlap * In the case of TASK_ABORTING we could conceivably call the
871a6d42e7dSPeter Dunlap * buffer callback here but the timing of when the client's
872a6d42e7dSPeter Dunlap * client_task_aborted callback is invoked vs. when the client's
873a6d42e7dSPeter Dunlap * buffer callback gets invoked gets sticky. We don't want
874a6d42e7dSPeter Dunlap * the client to here from us again after the call to
875a6d42e7dSPeter Dunlap * client_task_aborted() but we don't want to give it a bunch
876a6d42e7dSPeter Dunlap * of failed buffer transfers until we've called
877a6d42e7dSPeter Dunlap * client_task_aborted(). Instead we'll just leave all the
878a6d42e7dSPeter Dunlap * buffers bound and allow the client to cleanup.
879a6d42e7dSPeter Dunlap */
880a6d42e7dSPeter Dunlap break;
881a6d42e7dSPeter Dunlap default:
882a6d42e7dSPeter Dunlap ASSERT(0);
883a6d42e7dSPeter Dunlap }
884a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex);
885a6d42e7dSPeter Dunlap }
886a6d42e7dSPeter Dunlap
887a6d42e7dSPeter Dunlap /*
888a6d42e7dSPeter Dunlap * idm_buf_rx_from_ini_done
889a6d42e7dSPeter Dunlap *
890a6d42e7dSPeter Dunlap * The transport calls this after it has completed a transfer requested by
891a6d42e7dSPeter Dunlap * a call totransport_buf_tx_to_ini
892a6d42e7dSPeter Dunlap *
893a6d42e7dSPeter Dunlap * Caller holds idt->idt_mutex, idt->idt_mutex is released before returning.
894a6d42e7dSPeter Dunlap * idt may be freed after the call to idb->idb_buf_cb.
895a6d42e7dSPeter Dunlap */
896a6d42e7dSPeter Dunlap void
idm_buf_rx_from_ini_done(idm_task_t * idt,idm_buf_t * idb,idm_status_t status)897a6d42e7dSPeter Dunlap idm_buf_rx_from_ini_done(idm_task_t *idt, idm_buf_t *idb, idm_status_t status)
898a6d42e7dSPeter Dunlap {
899a6d42e7dSPeter Dunlap ASSERT(mutex_owned(&idt->idt_mutex));
900a6d42e7dSPeter Dunlap idb->idb_in_transport = B_FALSE;
901a6d42e7dSPeter Dunlap idt->idt_rx_from_ini_done++;
90230e7468fSPeter Dunlap gethrestime(&idb->idb_xfer_done);
903a6d42e7dSPeter Dunlap
904a6d42e7dSPeter Dunlap /*
905a6d42e7dSPeter Dunlap * idm_refcnt_rele may cause TASK_SUSPENDING --> TASK_SUSPENDED or
906a6d42e7dSPeter Dunlap * TASK_ABORTING --> TASK_ABORTED transistion if the refcount goes
907a6d42e7dSPeter Dunlap * to 0.
908a6d42e7dSPeter Dunlap */
909a6d42e7dSPeter Dunlap idm_task_rele(idt);
910a6d42e7dSPeter Dunlap idb->idb_status = status;
911a6d42e7dSPeter Dunlap
91230e7468fSPeter Dunlap if (status == IDM_STATUS_SUCCESS) {
91330e7468fSPeter Dunlap /*
91430e7468fSPeter Dunlap * Buffer should not contain the pattern. If it does then
91530e7468fSPeter Dunlap * we did not get the data from the remote host.
91630e7468fSPeter Dunlap */
91730e7468fSPeter Dunlap IDM_BUFPAT_CHECK(idb, idb->idb_xfer_len, BP_CHECK_ASSERT);
91830e7468fSPeter Dunlap }
91930e7468fSPeter Dunlap
920a6d42e7dSPeter Dunlap switch (idt->idt_state) {
921a6d42e7dSPeter Dunlap case TASK_ACTIVE:
92272cf3143Speter dunlap idt->idt_ic->ic_timestamp = ddi_get_lbolt();
923a6d42e7dSPeter Dunlap idm_buf_unbind_out_locked(idt, idb);
924a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex);
925a6d42e7dSPeter Dunlap (*idb->idb_buf_cb)(idb, status);
926a6d42e7dSPeter Dunlap return;
927a6d42e7dSPeter Dunlap case TASK_SUSPENDING:
928a6d42e7dSPeter Dunlap case TASK_SUSPENDED:
929a6d42e7dSPeter Dunlap case TASK_ABORTING:
930a6d42e7dSPeter Dunlap case TASK_ABORTED:
931a6d42e7dSPeter Dunlap /*
932a6d42e7dSPeter Dunlap * To keep things simple we will ignore the case where the
933a6d42e7dSPeter Dunlap * transfer was successful and leave all buffers bound to the
934a6d42e7dSPeter Dunlap * task. This allows us to also ignore the case where we've
935a6d42e7dSPeter Dunlap * been asked to abort a task but the last transfer of the
936a6d42e7dSPeter Dunlap * task has completed. IDM has no idea whether this was, in
937a6d42e7dSPeter Dunlap * fact, the last transfer of the task so it would be difficult
938a6d42e7dSPeter Dunlap * to handle this case. Everything should get sorted out again
939a6d42e7dSPeter Dunlap * after task reassignment is complete.
940a6d42e7dSPeter Dunlap *
941a6d42e7dSPeter Dunlap * In the case of TASK_ABORTING we could conceivably call the
942a6d42e7dSPeter Dunlap * buffer callback here but the timing of when the client's
943a6d42e7dSPeter Dunlap * client_task_aborted callback is invoked vs. when the client's
944a6d42e7dSPeter Dunlap * buffer callback gets invoked gets sticky. We don't want
945a6d42e7dSPeter Dunlap * the client to here from us again after the call to
946a6d42e7dSPeter Dunlap * client_task_aborted() but we don't want to give it a bunch
947a6d42e7dSPeter Dunlap * of failed buffer transfers until we've called
948a6d42e7dSPeter Dunlap * client_task_aborted(). Instead we'll just leave all the
949a6d42e7dSPeter Dunlap * buffers bound and allow the client to cleanup.
950a6d42e7dSPeter Dunlap */
951a6d42e7dSPeter Dunlap break;
952a6d42e7dSPeter Dunlap default:
953a6d42e7dSPeter Dunlap ASSERT(0);
954a6d42e7dSPeter Dunlap }
955a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex);
956a6d42e7dSPeter Dunlap }
957a6d42e7dSPeter Dunlap
958a6d42e7dSPeter Dunlap /*
959a6d42e7dSPeter Dunlap * idm_buf_alloc
960a6d42e7dSPeter Dunlap *
961a6d42e7dSPeter Dunlap * Allocates a buffer handle and registers it for use with the transport
962a6d42e7dSPeter Dunlap * layer. If a buffer is not passed on bufptr, the buffer will be allocated
963a6d42e7dSPeter Dunlap * as well as the handle.
964a6d42e7dSPeter Dunlap *
965a6d42e7dSPeter Dunlap * ic - connection on which the buffer will be transferred
966a6d42e7dSPeter Dunlap * bufptr - allocate memory for buffer if NULL, else assign to buffer
967a6d42e7dSPeter Dunlap * buflen - length of buffer
968a6d42e7dSPeter Dunlap *
969a6d42e7dSPeter Dunlap * Returns idm_buf_t handle if successful, otherwise NULL
970a6d42e7dSPeter Dunlap */
971a6d42e7dSPeter Dunlap idm_buf_t *
idm_buf_alloc(idm_conn_t * ic,void * bufptr,uint64_t buflen)972a6d42e7dSPeter Dunlap idm_buf_alloc(idm_conn_t *ic, void *bufptr, uint64_t buflen)
973a6d42e7dSPeter Dunlap {
974a6d42e7dSPeter Dunlap idm_buf_t *buf = NULL;
975a6d42e7dSPeter Dunlap int rc;
976a6d42e7dSPeter Dunlap
977a6d42e7dSPeter Dunlap ASSERT(ic != NULL);
978a6d42e7dSPeter Dunlap ASSERT(idm.idm_buf_cache != NULL);
979a6d42e7dSPeter Dunlap ASSERT(buflen > 0);
980a6d42e7dSPeter Dunlap
981a6d42e7dSPeter Dunlap /* Don't allocate new buffers if we are not in FFP */
982a6d42e7dSPeter Dunlap mutex_enter(&ic->ic_state_mutex);
983a6d42e7dSPeter Dunlap if (!ic->ic_ffp) {
984a6d42e7dSPeter Dunlap mutex_exit(&ic->ic_state_mutex);
985a6d42e7dSPeter Dunlap return (NULL);
986a6d42e7dSPeter Dunlap }
987a6d42e7dSPeter Dunlap
988a6d42e7dSPeter Dunlap
989a6d42e7dSPeter Dunlap idm_conn_hold(ic);
990a6d42e7dSPeter Dunlap mutex_exit(&ic->ic_state_mutex);
991a6d42e7dSPeter Dunlap
992a6d42e7dSPeter Dunlap buf = kmem_cache_alloc(idm.idm_buf_cache, KM_NOSLEEP);
993a6d42e7dSPeter Dunlap if (buf == NULL) {
994a6d42e7dSPeter Dunlap idm_conn_rele(ic);
995a6d42e7dSPeter Dunlap return (NULL);
996a6d42e7dSPeter Dunlap }
997a6d42e7dSPeter Dunlap
998a6d42e7dSPeter Dunlap buf->idb_ic = ic;
999a6d42e7dSPeter Dunlap buf->idb_buflen = buflen;
1000a6d42e7dSPeter Dunlap buf->idb_exp_offset = 0;
1001a6d42e7dSPeter Dunlap buf->idb_bufoffset = 0;
10028e718be9SToomas Soome buf->idb_xfer_len = 0;
1003a6d42e7dSPeter Dunlap buf->idb_magic = IDM_BUF_MAGIC;
100430e7468fSPeter Dunlap buf->idb_in_transport = B_FALSE;
100530e7468fSPeter Dunlap buf->idb_bufbcopy = B_FALSE;
1006a6d42e7dSPeter Dunlap
1007a6d42e7dSPeter Dunlap /*
1008a6d42e7dSPeter Dunlap * If bufptr is NULL, we have an implicit request to allocate
1009a6d42e7dSPeter Dunlap * memory for this IDM buffer handle and register it for use
1010a6d42e7dSPeter Dunlap * with the transport. To simplify this, and to give more freedom
1011a6d42e7dSPeter Dunlap * to the transport layer for it's own buffer management, both of
1012a6d42e7dSPeter Dunlap * these actions will take place in the transport layer.
1013a6d42e7dSPeter Dunlap * If bufptr is set, then the caller has allocated memory (or more
1014a6d42e7dSPeter Dunlap * likely it's been passed from an upper layer), and we need only
1015a6d42e7dSPeter Dunlap * register the buffer for use with the transport layer.
1016a6d42e7dSPeter Dunlap */
1017a6d42e7dSPeter Dunlap if (bufptr == NULL) {
1018a6d42e7dSPeter Dunlap /*
1019a6d42e7dSPeter Dunlap * Allocate a buffer from the transport layer (which
1020a6d42e7dSPeter Dunlap * will also register the buffer for use).
1021a6d42e7dSPeter Dunlap */
1022a6d42e7dSPeter Dunlap rc = ic->ic_transport_ops->it_buf_alloc(buf, buflen);
1023a6d42e7dSPeter Dunlap if (rc != 0) {
1024a6d42e7dSPeter Dunlap idm_conn_rele(ic);
1025a6d42e7dSPeter Dunlap kmem_cache_free(idm.idm_buf_cache, buf);
1026a6d42e7dSPeter Dunlap return (NULL);
1027a6d42e7dSPeter Dunlap }
1028a6d42e7dSPeter Dunlap /* Set the bufalloc'd flag */
1029a6d42e7dSPeter Dunlap buf->idb_bufalloc = B_TRUE;
1030a6d42e7dSPeter Dunlap } else {
1031a6d42e7dSPeter Dunlap /*
103230e7468fSPeter Dunlap * For large transfers, Set the passed bufptr into
103330e7468fSPeter Dunlap * the buf handle, and register the handle with the
103430e7468fSPeter Dunlap * transport layer. As memory registration with the
103530e7468fSPeter Dunlap * transport layer is a time/cpu intensive operation,
103630e7468fSPeter Dunlap * for small transfers (up to a pre-defined bcopy
103730e7468fSPeter Dunlap * threshold), use pre-registered memory buffers
103830e7468fSPeter Dunlap * and bcopy data at the appropriate time.
1039a6d42e7dSPeter Dunlap */
1040a6d42e7dSPeter Dunlap buf->idb_buf = bufptr;
1041a6d42e7dSPeter Dunlap
1042a6d42e7dSPeter Dunlap rc = ic->ic_transport_ops->it_buf_setup(buf);
1043a6d42e7dSPeter Dunlap if (rc != 0) {
1044a6d42e7dSPeter Dunlap idm_conn_rele(ic);
1045a6d42e7dSPeter Dunlap kmem_cache_free(idm.idm_buf_cache, buf);
1046a6d42e7dSPeter Dunlap return (NULL);
1047a6d42e7dSPeter Dunlap }
104830e7468fSPeter Dunlap /*
104930e7468fSPeter Dunlap * The transport layer is now expected to set the idb_bufalloc
105030e7468fSPeter Dunlap * correctly to indicate if resources have been allocated.
105130e7468fSPeter Dunlap */
1052a6d42e7dSPeter Dunlap }
1053a6d42e7dSPeter Dunlap
105430e7468fSPeter Dunlap IDM_BUFPAT_SET(buf);
1055a6d42e7dSPeter Dunlap
105630e7468fSPeter Dunlap return (buf);
1057a6d42e7dSPeter Dunlap }
1058a6d42e7dSPeter Dunlap
1059a6d42e7dSPeter Dunlap /*
1060a6d42e7dSPeter Dunlap * idm_buf_free
1061a6d42e7dSPeter Dunlap *
1062a6d42e7dSPeter Dunlap * Release a buffer handle along with the associated buffer that was allocated
1063a6d42e7dSPeter Dunlap * or assigned with idm_buf_alloc
1064a6d42e7dSPeter Dunlap */
1065a6d42e7dSPeter Dunlap void
idm_buf_free(idm_buf_t * buf)1066a6d42e7dSPeter Dunlap idm_buf_free(idm_buf_t *buf)
1067a6d42e7dSPeter Dunlap {
1068a6d42e7dSPeter Dunlap idm_conn_t *ic = buf->idb_ic;
1069a6d42e7dSPeter Dunlap
1070a6d42e7dSPeter Dunlap
1071a6d42e7dSPeter Dunlap buf->idb_task_binding = NULL;
1072a6d42e7dSPeter Dunlap
1073a6d42e7dSPeter Dunlap if (buf->idb_bufalloc) {
1074a6d42e7dSPeter Dunlap ic->ic_transport_ops->it_buf_free(buf);
1075a6d42e7dSPeter Dunlap } else {
1076a6d42e7dSPeter Dunlap ic->ic_transport_ops->it_buf_teardown(buf);
1077a6d42e7dSPeter Dunlap }
1078a6d42e7dSPeter Dunlap kmem_cache_free(idm.idm_buf_cache, buf);
1079a6d42e7dSPeter Dunlap idm_conn_rele(ic);
1080a6d42e7dSPeter Dunlap }
1081a6d42e7dSPeter Dunlap
1082a6d42e7dSPeter Dunlap /*
1083a6d42e7dSPeter Dunlap * idm_buf_bind_in
1084a6d42e7dSPeter Dunlap *
1085a6d42e7dSPeter Dunlap * This function associates a buffer with a task. This is only for use by the
1086a6d42e7dSPeter Dunlap * iSCSI initiator that will have only one buffer per transfer direction
1087a6d42e7dSPeter Dunlap *
1088a6d42e7dSPeter Dunlap */
1089a6d42e7dSPeter Dunlap void
idm_buf_bind_in(idm_task_t * idt,idm_buf_t * buf)1090a6d42e7dSPeter Dunlap idm_buf_bind_in(idm_task_t *idt, idm_buf_t *buf)
1091a6d42e7dSPeter Dunlap {
1092a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex);
1093a6d42e7dSPeter Dunlap idm_buf_bind_in_locked(idt, buf);
1094a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex);
1095a6d42e7dSPeter Dunlap }
1096a6d42e7dSPeter Dunlap
1097a6d42e7dSPeter Dunlap static void
idm_buf_bind_in_locked(idm_task_t * idt,idm_buf_t * buf)1098a6d42e7dSPeter Dunlap idm_buf_bind_in_locked(idm_task_t *idt, idm_buf_t *buf)
1099a6d42e7dSPeter Dunlap {
1100a6d42e7dSPeter Dunlap buf->idb_task_binding = idt;
1101a6d42e7dSPeter Dunlap buf->idb_ic = idt->idt_ic;
1102a6d42e7dSPeter Dunlap idm_listbuf_insert(&idt->idt_inbufv, buf);
1103a6d42e7dSPeter Dunlap }
1104a6d42e7dSPeter Dunlap
1105a6d42e7dSPeter Dunlap void
idm_buf_bind_out(idm_task_t * idt,idm_buf_t * buf)1106a6d42e7dSPeter Dunlap idm_buf_bind_out(idm_task_t *idt, idm_buf_t *buf)
1107a6d42e7dSPeter Dunlap {
110830e7468fSPeter Dunlap /*
110930e7468fSPeter Dunlap * For small transfers, the iSER transport delegates the IDM
111030e7468fSPeter Dunlap * layer to bcopy the SCSI Write data for faster IOPS.
111130e7468fSPeter Dunlap */
111230e7468fSPeter Dunlap if (buf->idb_bufbcopy == B_TRUE) {
111330e7468fSPeter Dunlap
111430e7468fSPeter Dunlap bcopy(buf->idb_bufptr, buf->idb_buf, buf->idb_buflen);
111530e7468fSPeter Dunlap }
1116a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex);
1117a6d42e7dSPeter Dunlap idm_buf_bind_out_locked(idt, buf);
1118a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex);
1119a6d42e7dSPeter Dunlap }
1120a6d42e7dSPeter Dunlap
1121a6d42e7dSPeter Dunlap static void
idm_buf_bind_out_locked(idm_task_t * idt,idm_buf_t * buf)1122a6d42e7dSPeter Dunlap idm_buf_bind_out_locked(idm_task_t *idt, idm_buf_t *buf)
1123a6d42e7dSPeter Dunlap {
1124a6d42e7dSPeter Dunlap buf->idb_task_binding = idt;
1125a6d42e7dSPeter Dunlap buf->idb_ic = idt->idt_ic;
1126a6d42e7dSPeter Dunlap idm_listbuf_insert(&idt->idt_outbufv, buf);
1127a6d42e7dSPeter Dunlap }
1128a6d42e7dSPeter Dunlap
1129a6d42e7dSPeter Dunlap void
idm_buf_unbind_in(idm_task_t * idt,idm_buf_t * buf)1130a6d42e7dSPeter Dunlap idm_buf_unbind_in(idm_task_t *idt, idm_buf_t *buf)
1131a6d42e7dSPeter Dunlap {
113230e7468fSPeter Dunlap /*
113330e7468fSPeter Dunlap * For small transfers, the iSER transport delegates the IDM
113430e7468fSPeter Dunlap * layer to bcopy the SCSI Read data into the read buufer
113530e7468fSPeter Dunlap * for faster IOPS.
113630e7468fSPeter Dunlap */
113730e7468fSPeter Dunlap if (buf->idb_bufbcopy == B_TRUE) {
113830e7468fSPeter Dunlap bcopy(buf->idb_buf, buf->idb_bufptr, buf->idb_buflen);
113930e7468fSPeter Dunlap }
1140a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex);
1141a6d42e7dSPeter Dunlap idm_buf_unbind_in_locked(idt, buf);
1142a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex);
1143a6d42e7dSPeter Dunlap }
1144a6d42e7dSPeter Dunlap
1145a6d42e7dSPeter Dunlap static void
idm_buf_unbind_in_locked(idm_task_t * idt,idm_buf_t * buf)1146a6d42e7dSPeter Dunlap idm_buf_unbind_in_locked(idm_task_t *idt, idm_buf_t *buf)
1147a6d42e7dSPeter Dunlap {
1148a6d42e7dSPeter Dunlap list_remove(&idt->idt_inbufv, buf);
1149a6d42e7dSPeter Dunlap }
1150a6d42e7dSPeter Dunlap
1151a6d42e7dSPeter Dunlap void
idm_buf_unbind_out(idm_task_t * idt,idm_buf_t * buf)1152a6d42e7dSPeter Dunlap idm_buf_unbind_out(idm_task_t *idt, idm_buf_t *buf)
1153a6d42e7dSPeter Dunlap {
1154a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex);
1155a6d42e7dSPeter Dunlap idm_buf_unbind_out_locked(idt, buf);
1156a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex);
1157a6d42e7dSPeter Dunlap }
1158a6d42e7dSPeter Dunlap
1159a6d42e7dSPeter Dunlap static void
idm_buf_unbind_out_locked(idm_task_t * idt,idm_buf_t * buf)1160a6d42e7dSPeter Dunlap idm_buf_unbind_out_locked(idm_task_t *idt, idm_buf_t *buf)
1161a6d42e7dSPeter Dunlap {
1162a6d42e7dSPeter Dunlap list_remove(&idt->idt_outbufv, buf);
1163a6d42e7dSPeter Dunlap }
1164a6d42e7dSPeter Dunlap
1165a6d42e7dSPeter Dunlap /*
1166a6d42e7dSPeter Dunlap * idm_buf_find() will lookup the idm_buf_t based on the relative offset in the
1167a6d42e7dSPeter Dunlap * iSCSI PDU
1168a6d42e7dSPeter Dunlap */
1169a6d42e7dSPeter Dunlap idm_buf_t *
idm_buf_find(void * lbuf,size_t data_offset)1170a6d42e7dSPeter Dunlap idm_buf_find(void *lbuf, size_t data_offset)
1171a6d42e7dSPeter Dunlap {
1172a6d42e7dSPeter Dunlap idm_buf_t *idb;
1173a6d42e7dSPeter Dunlap list_t *lst = (list_t *)lbuf;
1174a6d42e7dSPeter Dunlap
1175a6d42e7dSPeter Dunlap /* iterate through the list to find the buffer */
1176a6d42e7dSPeter Dunlap for (idb = list_head(lst); idb != NULL; idb = list_next(lst, idb)) {
1177a6d42e7dSPeter Dunlap
1178a6d42e7dSPeter Dunlap ASSERT((idb->idb_ic->ic_conn_type == CONN_TYPE_TGT) ||
1179a6d42e7dSPeter Dunlap (idb->idb_bufoffset == 0));
1180a6d42e7dSPeter Dunlap
1181a6d42e7dSPeter Dunlap if ((data_offset >= idb->idb_bufoffset) &&
1182a6d42e7dSPeter Dunlap (data_offset < (idb->idb_bufoffset + idb->idb_buflen))) {
1183a6d42e7dSPeter Dunlap
1184a6d42e7dSPeter Dunlap return (idb);
1185a6d42e7dSPeter Dunlap }
1186a6d42e7dSPeter Dunlap }
1187a6d42e7dSPeter Dunlap
1188a6d42e7dSPeter Dunlap return (NULL);
1189a6d42e7dSPeter Dunlap }
1190a6d42e7dSPeter Dunlap
119130e7468fSPeter Dunlap void
idm_bufpat_set(idm_buf_t * idb)119230e7468fSPeter Dunlap idm_bufpat_set(idm_buf_t *idb)
119330e7468fSPeter Dunlap {
119430e7468fSPeter Dunlap idm_bufpat_t *bufpat;
119530e7468fSPeter Dunlap int len, i;
119630e7468fSPeter Dunlap
119730e7468fSPeter Dunlap len = idb->idb_buflen;
119830e7468fSPeter Dunlap len = (len / sizeof (idm_bufpat_t)) * sizeof (idm_bufpat_t);
119930e7468fSPeter Dunlap
120030e7468fSPeter Dunlap bufpat = idb->idb_buf;
120130e7468fSPeter Dunlap for (i = 0; i < len; i += sizeof (idm_bufpat_t)) {
120230e7468fSPeter Dunlap bufpat->bufpat_idb = idb;
120330e7468fSPeter Dunlap bufpat->bufpat_bufmagic = IDM_BUF_MAGIC;
120430e7468fSPeter Dunlap bufpat->bufpat_offset = i;
120530e7468fSPeter Dunlap bufpat++;
120630e7468fSPeter Dunlap }
120730e7468fSPeter Dunlap }
120830e7468fSPeter Dunlap
120930e7468fSPeter Dunlap boolean_t
idm_bufpat_check(idm_buf_t * idb,int check_len,idm_bufpat_check_type_t type)121030e7468fSPeter Dunlap idm_bufpat_check(idm_buf_t *idb, int check_len, idm_bufpat_check_type_t type)
121130e7468fSPeter Dunlap {
121230e7468fSPeter Dunlap idm_bufpat_t *bufpat;
121330e7468fSPeter Dunlap int len, i;
121430e7468fSPeter Dunlap
121530e7468fSPeter Dunlap len = (type == BP_CHECK_QUICK) ? sizeof (idm_bufpat_t) : check_len;
121630e7468fSPeter Dunlap len = (len / sizeof (idm_bufpat_t)) * sizeof (idm_bufpat_t);
121730e7468fSPeter Dunlap ASSERT(len <= idb->idb_buflen);
121830e7468fSPeter Dunlap bufpat = idb->idb_buf;
121930e7468fSPeter Dunlap
122030e7468fSPeter Dunlap /*
122130e7468fSPeter Dunlap * Don't check the pattern in buffers that came from outside IDM
122230e7468fSPeter Dunlap * (these will be buffers from the initiator that we opted not
122330e7468fSPeter Dunlap * to double-buffer)
122430e7468fSPeter Dunlap */
122530e7468fSPeter Dunlap if (!idb->idb_bufalloc)
122630e7468fSPeter Dunlap return (B_FALSE);
122730e7468fSPeter Dunlap
122830e7468fSPeter Dunlap /*
122930e7468fSPeter Dunlap * Return true if we find the pattern anywhere in the buffer
123030e7468fSPeter Dunlap */
123130e7468fSPeter Dunlap for (i = 0; i < len; i += sizeof (idm_bufpat_t)) {
123230e7468fSPeter Dunlap if (BUFPAT_MATCH(bufpat, idb)) {
123330e7468fSPeter Dunlap IDM_CONN_LOG(CE_WARN, "idm_bufpat_check found: "
123430e7468fSPeter Dunlap "idb %p bufpat %p "
123530e7468fSPeter Dunlap "bufpat_idb=%p bufmagic=%08x offset=%08x",
123630e7468fSPeter Dunlap (void *)idb, (void *)bufpat, bufpat->bufpat_idb,
123730e7468fSPeter Dunlap bufpat->bufpat_bufmagic, bufpat->bufpat_offset);
123830e7468fSPeter Dunlap DTRACE_PROBE2(bufpat__pattern__found,
123930e7468fSPeter Dunlap idm_buf_t *, idb, idm_bufpat_t *, bufpat);
124030e7468fSPeter Dunlap if (type == BP_CHECK_ASSERT) {
124130e7468fSPeter Dunlap ASSERT(0);
124230e7468fSPeter Dunlap }
124330e7468fSPeter Dunlap return (B_TRUE);
124430e7468fSPeter Dunlap }
124530e7468fSPeter Dunlap bufpat++;
124630e7468fSPeter Dunlap }
124730e7468fSPeter Dunlap
124830e7468fSPeter Dunlap return (B_FALSE);
124930e7468fSPeter Dunlap }
125030e7468fSPeter Dunlap
1251a6d42e7dSPeter Dunlap /*
1252a6d42e7dSPeter Dunlap * idm_task_alloc
1253a6d42e7dSPeter Dunlap *
1254a6d42e7dSPeter Dunlap * This function will allocate a idm_task_t structure. A task tag is also
1255a6d42e7dSPeter Dunlap * generated and saved in idt_tt. The task is not active.
1256a6d42e7dSPeter Dunlap */
1257a6d42e7dSPeter Dunlap idm_task_t *
idm_task_alloc(idm_conn_t * ic)1258a6d42e7dSPeter Dunlap idm_task_alloc(idm_conn_t *ic)
1259a6d42e7dSPeter Dunlap {
1260a6d42e7dSPeter Dunlap idm_task_t *idt;
1261a6d42e7dSPeter Dunlap
1262a6d42e7dSPeter Dunlap ASSERT(ic != NULL);
1263a6d42e7dSPeter Dunlap
1264a6d42e7dSPeter Dunlap /* Don't allocate new tasks if we are not in FFP */
1265a6d42e7dSPeter Dunlap if (!ic->ic_ffp) {
1266a6d42e7dSPeter Dunlap return (NULL);
1267a6d42e7dSPeter Dunlap }
1268a6d42e7dSPeter Dunlap idt = kmem_cache_alloc(idm.idm_task_cache, KM_NOSLEEP);
1269a6d42e7dSPeter Dunlap if (idt == NULL) {
1270a6d42e7dSPeter Dunlap return (NULL);
1271a6d42e7dSPeter Dunlap }
1272a6d42e7dSPeter Dunlap
1273a6d42e7dSPeter Dunlap ASSERT(list_is_empty(&idt->idt_inbufv));
1274a6d42e7dSPeter Dunlap ASSERT(list_is_empty(&idt->idt_outbufv));
1275a6d42e7dSPeter Dunlap
127692adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States mutex_enter(&ic->ic_state_mutex);
127792adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States if (!ic->ic_ffp) {
127892adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States mutex_exit(&ic->ic_state_mutex);
127992adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States kmem_cache_free(idm.idm_task_cache, idt);
128092adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States return (NULL);
128192adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States }
1282a6d42e7dSPeter Dunlap idm_conn_hold(ic);
1283a6d42e7dSPeter Dunlap mutex_exit(&ic->ic_state_mutex);
1284a6d42e7dSPeter Dunlap
1285a6d42e7dSPeter Dunlap idt->idt_state = TASK_IDLE;
1286a6d42e7dSPeter Dunlap idt->idt_ic = ic;
12878e718be9SToomas Soome idt->idt_private = NULL;
1288a6d42e7dSPeter Dunlap idt->idt_exp_datasn = 0;
1289a6d42e7dSPeter Dunlap idt->idt_exp_rttsn = 0;
129060220f10SPriya Krishnan idt->idt_flags = 0;
1291a6d42e7dSPeter Dunlap return (idt);
1292a6d42e7dSPeter Dunlap }
1293a6d42e7dSPeter Dunlap
1294a6d42e7dSPeter Dunlap /*
1295a6d42e7dSPeter Dunlap * idm_task_start
1296a6d42e7dSPeter Dunlap *
129730e7468fSPeter Dunlap * Mark the task active and initialize some stats. The caller
1298a6d42e7dSPeter Dunlap * sets up the idm_task_t structure with a prior call to idm_task_alloc().
1299a6d42e7dSPeter Dunlap * The task service does not function as a task/work engine, it is the
1300a6d42e7dSPeter Dunlap * responsibility of the initiator to start the data transfer and free the
1301a6d42e7dSPeter Dunlap * resources.
1302a6d42e7dSPeter Dunlap */
1303a6d42e7dSPeter Dunlap void
idm_task_start(idm_task_t * idt,uintptr_t handle)1304a6d42e7dSPeter Dunlap idm_task_start(idm_task_t *idt, uintptr_t handle)
1305a6d42e7dSPeter Dunlap {
1306a6d42e7dSPeter Dunlap ASSERT(idt != NULL);
1307a6d42e7dSPeter Dunlap
1308a6d42e7dSPeter Dunlap /* mark the task as ACTIVE */
1309a6d42e7dSPeter Dunlap idt->idt_state = TASK_ACTIVE;
1310a6d42e7dSPeter Dunlap idt->idt_client_handle = handle;
1311a6d42e7dSPeter Dunlap idt->idt_tx_to_ini_start = idt->idt_tx_to_ini_done =
131230e7468fSPeter Dunlap idt->idt_rx_from_ini_start = idt->idt_rx_from_ini_done =
131330e7468fSPeter Dunlap idt->idt_tx_bytes = idt->idt_rx_bytes = 0;
1314a6d42e7dSPeter Dunlap }
1315a6d42e7dSPeter Dunlap
1316a6d42e7dSPeter Dunlap /*
1317a6d42e7dSPeter Dunlap * idm_task_done
1318a6d42e7dSPeter Dunlap *
131930e7468fSPeter Dunlap * This function sets the state to indicate that the task is no longer active.
1320a6d42e7dSPeter Dunlap */
1321a6d42e7dSPeter Dunlap void
idm_task_done(idm_task_t * idt)1322a6d42e7dSPeter Dunlap idm_task_done(idm_task_t *idt)
1323a6d42e7dSPeter Dunlap {
1324a6d42e7dSPeter Dunlap ASSERT(idt != NULL);
1325a6d42e7dSPeter Dunlap
132630e7468fSPeter Dunlap mutex_enter(&idt->idt_mutex);
1327a6d42e7dSPeter Dunlap idt->idt_state = TASK_IDLE;
132830e7468fSPeter Dunlap mutex_exit(&idt->idt_mutex);
132930e7468fSPeter Dunlap
133030e7468fSPeter Dunlap /*
133130e7468fSPeter Dunlap * Although unlikely it is possible for a reference to come in after
133230e7468fSPeter Dunlap * the client has decided the task is over but before we've marked
133330e7468fSPeter Dunlap * the task idle. One specific unavoidable scenario is the case where
133430e7468fSPeter Dunlap * received PDU with the matching ITT/TTT results in a successful
133530e7468fSPeter Dunlap * lookup of this task. We are at the mercy of the remote node in
133630e7468fSPeter Dunlap * that case so we need to handle it. Now that the task state
133730e7468fSPeter Dunlap * has changed no more references will occur so a simple call to
133830e7468fSPeter Dunlap * idm_refcnt_wait_ref should deal with the situation.
133930e7468fSPeter Dunlap */
134030e7468fSPeter Dunlap idm_refcnt_wait_ref(&idt->idt_refcnt);
1341a6d42e7dSPeter Dunlap idm_refcnt_reset(&idt->idt_refcnt);
1342a6d42e7dSPeter Dunlap }
1343a6d42e7dSPeter Dunlap
1344a6d42e7dSPeter Dunlap /*
1345a6d42e7dSPeter Dunlap * idm_task_free
1346a6d42e7dSPeter Dunlap *
1347a6d42e7dSPeter Dunlap * This function will free the Task Tag and the memory allocated for the task
1348a6d42e7dSPeter Dunlap * idm_task_done should be called prior to this call
1349a6d42e7dSPeter Dunlap */
1350a6d42e7dSPeter Dunlap void
idm_task_free(idm_task_t * idt)1351a6d42e7dSPeter Dunlap idm_task_free(idm_task_t *idt)
1352a6d42e7dSPeter Dunlap {
135330e7468fSPeter Dunlap idm_conn_t *ic;
1354a6d42e7dSPeter Dunlap
1355a6d42e7dSPeter Dunlap ASSERT(idt != NULL);
135630e7468fSPeter Dunlap ASSERT(idt->idt_refcnt.ir_refcnt == 0);
1357a6d42e7dSPeter Dunlap ASSERT(idt->idt_state == TASK_IDLE);
1358a6d42e7dSPeter Dunlap
135930e7468fSPeter Dunlap ic = idt->idt_ic;
136030e7468fSPeter Dunlap
1361a6d42e7dSPeter Dunlap /*
1362a6d42e7dSPeter Dunlap * It's possible for items to still be in the idt_inbufv list if
136392adbba7SPeter Cudhea - Sun Microsystems - Burlington, MA United States * they were added after idm_free_task_rsrc was called. We rely on
1364a6d42e7dSPeter Dunlap * STMF to free all buffers associated with the task however STMF
1365a6d42e7dSPeter Dunlap * doesn't know that we have this reference to the buffers.
1366a6d42e7dSPeter Dunlap * Use list_create so that we don't end up with stale references
1367a6d42e7dSPeter Dunlap * to these buffers.
1368a6d42e7dSPeter Dunlap */
1369a6d42e7dSPeter Dunlap list_create(&idt->idt_inbufv, sizeof (idm_buf_t),
1370a6d42e7dSPeter Dunlap offsetof(idm_buf_t, idb_buflink));
1371a6d42e7dSPeter Dunlap list_create(&idt->idt_outbufv, sizeof (idm_buf_t),
1372a6d42e7dSPeter Dunlap offsetof(idm_buf_t, idb_buflink));
1373a6d42e7dSPeter Dunlap
1374a6d42e7dSPeter Dunlap kmem_cache_free(idm.idm_task_cache, idt);
1375a6d42e7dSPeter Dunlap
1376a6d42e7dSPeter Dunlap idm_conn_rele(ic);
1377a6d42e7dSPeter Dunlap }
1378a6d42e7dSPeter Dunlap
1379a6d42e7dSPeter Dunlap /*
138030e7468fSPeter Dunlap * idm_task_find_common
138130e7468fSPeter Dunlap * common code for idm_task_find() and idm_task_find_and_complete()
1382a6d42e7dSPeter Dunlap */
1383a6d42e7dSPeter Dunlap /*ARGSUSED*/
138430e7468fSPeter Dunlap static idm_task_t *
idm_task_find_common(idm_conn_t * ic,uint32_t itt,uint32_t ttt,boolean_t complete)138530e7468fSPeter Dunlap idm_task_find_common(idm_conn_t *ic, uint32_t itt, uint32_t ttt,
138630e7468fSPeter Dunlap boolean_t complete)
1387a6d42e7dSPeter Dunlap {
1388a6d42e7dSPeter Dunlap uint32_t tt, client_handle;
1389a6d42e7dSPeter Dunlap idm_task_t *idt;
1390a6d42e7dSPeter Dunlap
1391a6d42e7dSPeter Dunlap /*
1392a6d42e7dSPeter Dunlap * Must match both itt and ttt. The table is indexed by itt
1393a6d42e7dSPeter Dunlap * for initiator connections and ttt for target connections.
1394a6d42e7dSPeter Dunlap */
1395a6d42e7dSPeter Dunlap if (IDM_CONN_ISTGT(ic)) {
1396a6d42e7dSPeter Dunlap tt = ttt;
1397a6d42e7dSPeter Dunlap client_handle = itt;
1398a6d42e7dSPeter Dunlap } else {
1399a6d42e7dSPeter Dunlap tt = itt;
1400a6d42e7dSPeter Dunlap client_handle = ttt;
1401a6d42e7dSPeter Dunlap }
1402a6d42e7dSPeter Dunlap
1403a6d42e7dSPeter Dunlap rw_enter(&idm.idm_taskid_table_lock, RW_READER);
1404a6d42e7dSPeter Dunlap if (tt >= idm.idm_taskid_max) {
1405a6d42e7dSPeter Dunlap rw_exit(&idm.idm_taskid_table_lock);
1406a6d42e7dSPeter Dunlap return (NULL);
1407a6d42e7dSPeter Dunlap }
1408a6d42e7dSPeter Dunlap
1409a6d42e7dSPeter Dunlap idt = idm.idm_taskid_table[tt];
1410a6d42e7dSPeter Dunlap
1411a6d42e7dSPeter Dunlap if (idt != NULL) {
1412a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex);
1413a6d42e7dSPeter Dunlap if ((idt->idt_state != TASK_ACTIVE) ||
141430e7468fSPeter Dunlap (idt->idt_ic != ic) ||
1415a6d42e7dSPeter Dunlap (IDM_CONN_ISTGT(ic) &&
1416a6d42e7dSPeter Dunlap (idt->idt_client_handle != client_handle))) {
1417a6d42e7dSPeter Dunlap /*
141830e7468fSPeter Dunlap * Task doesn't match or task is aborting and
141930e7468fSPeter Dunlap * we don't want any more references.
1420a6d42e7dSPeter Dunlap */
142130e7468fSPeter Dunlap if ((idt->idt_ic != ic) &&
142230e7468fSPeter Dunlap (idt->idt_state == TASK_ACTIVE) &&
142330e7468fSPeter Dunlap (IDM_CONN_ISINI(ic) || idt->idt_client_handle ==
142430e7468fSPeter Dunlap client_handle)) {
142530e7468fSPeter Dunlap IDM_CONN_LOG(CE_WARN,
142630e7468fSPeter Dunlap "idm_task_find: wrong connection %p != %p",
142730e7468fSPeter Dunlap (void *)ic, (void *)idt->idt_ic);
142830e7468fSPeter Dunlap }
1429a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex);
1430a6d42e7dSPeter Dunlap rw_exit(&idm.idm_taskid_table_lock);
1431a6d42e7dSPeter Dunlap return (NULL);
1432a6d42e7dSPeter Dunlap }
1433a6d42e7dSPeter Dunlap idm_task_hold(idt);
143430e7468fSPeter Dunlap /*
143530e7468fSPeter Dunlap * Set the task state to TASK_COMPLETE so it can no longer
143630e7468fSPeter Dunlap * be found or aborted.
143730e7468fSPeter Dunlap */
143830e7468fSPeter Dunlap if (B_TRUE == complete)
143930e7468fSPeter Dunlap idt->idt_state = TASK_COMPLETE;
1440a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex);
1441a6d42e7dSPeter Dunlap }
1442a6d42e7dSPeter Dunlap rw_exit(&idm.idm_taskid_table_lock);
1443a6d42e7dSPeter Dunlap
1444a6d42e7dSPeter Dunlap return (idt);
1445a6d42e7dSPeter Dunlap }
1446a6d42e7dSPeter Dunlap
144730e7468fSPeter Dunlap /*
144830e7468fSPeter Dunlap * This function looks up a task by task tag.
144930e7468fSPeter Dunlap */
145030e7468fSPeter Dunlap idm_task_t *
idm_task_find(idm_conn_t * ic,uint32_t itt,uint32_t ttt)145130e7468fSPeter Dunlap idm_task_find(idm_conn_t *ic, uint32_t itt, uint32_t ttt)
145230e7468fSPeter Dunlap {
145330e7468fSPeter Dunlap return (idm_task_find_common(ic, itt, ttt, B_FALSE));
145430e7468fSPeter Dunlap }
145530e7468fSPeter Dunlap
145630e7468fSPeter Dunlap /*
145730e7468fSPeter Dunlap * This function looks up a task by task tag. If found, the task state
145830e7468fSPeter Dunlap * is atomically set to TASK_COMPLETE so it can longer be found or aborted.
145930e7468fSPeter Dunlap */
146030e7468fSPeter Dunlap idm_task_t *
idm_task_find_and_complete(idm_conn_t * ic,uint32_t itt,uint32_t ttt)146130e7468fSPeter Dunlap idm_task_find_and_complete(idm_conn_t *ic, uint32_t itt, uint32_t ttt)
146230e7468fSPeter Dunlap {
146330e7468fSPeter Dunlap return (idm_task_find_common(ic, itt, ttt, B_TRUE));
146430e7468fSPeter Dunlap }
146530e7468fSPeter Dunlap
1466a6d42e7dSPeter Dunlap /*
1467a6d42e7dSPeter Dunlap * idm_task_find_by_handle
1468a6d42e7dSPeter Dunlap *
1469a6d42e7dSPeter Dunlap * This function looks up a task by the client-private idt_client_handle.
1470a6d42e7dSPeter Dunlap *
1471a6d42e7dSPeter Dunlap * This function should NEVER be called in the performance path. It is
1472a6d42e7dSPeter Dunlap * intended strictly for error recovery/task management.
1473a6d42e7dSPeter Dunlap */
1474a6d42e7dSPeter Dunlap /*ARGSUSED*/
1475a6d42e7dSPeter Dunlap void *
idm_task_find_by_handle(idm_conn_t * ic,uintptr_t handle)1476a6d42e7dSPeter Dunlap idm_task_find_by_handle(idm_conn_t *ic, uintptr_t handle)
1477a6d42e7dSPeter Dunlap {
1478a6d42e7dSPeter Dunlap idm_task_t *idt = NULL;
1479a6d42e7dSPeter Dunlap int idx = 0;
1480a6d42e7dSPeter Dunlap
1481a6d42e7dSPeter Dunlap rw_enter(&idm.idm_taskid_table_lock, RW_READER);
1482a6d42e7dSPeter Dunlap
1483a6d42e7dSPeter Dunlap for (idx = 0; idx < idm.idm_taskid_max; idx++) {
1484a6d42e7dSPeter Dunlap idt = idm.idm_taskid_table[idx];
1485a6d42e7dSPeter Dunlap
1486a6d42e7dSPeter Dunlap if (idt == NULL)
1487a6d42e7dSPeter Dunlap continue;
1488a6d42e7dSPeter Dunlap
1489a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex);
1490a6d42e7dSPeter Dunlap
1491a6d42e7dSPeter Dunlap if (idt->idt_state != TASK_ACTIVE) {
1492a6d42e7dSPeter Dunlap /*
1493a6d42e7dSPeter Dunlap * Task is either in suspend, abort, or already
1494a6d42e7dSPeter Dunlap * complete.
1495a6d42e7dSPeter Dunlap */
1496a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex);
1497a6d42e7dSPeter Dunlap continue;
1498a6d42e7dSPeter Dunlap }
1499a6d42e7dSPeter Dunlap
1500a6d42e7dSPeter Dunlap if (idt->idt_client_handle == handle) {
1501a6d42e7dSPeter Dunlap idm_task_hold(idt);
1502a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex);
1503a6d42e7dSPeter Dunlap break;
1504a6d42e7dSPeter Dunlap }
1505a6d42e7dSPeter Dunlap
1506a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex);
1507a6d42e7dSPeter Dunlap }
1508a6d42e7dSPeter Dunlap
1509a6d42e7dSPeter Dunlap rw_exit(&idm.idm_taskid_table_lock);
1510a6d42e7dSPeter Dunlap
1511a6d42e7dSPeter Dunlap if ((idt == NULL) || (idx == idm.idm_taskid_max))
1512a6d42e7dSPeter Dunlap return (NULL);
1513a6d42e7dSPeter Dunlap
1514a6d42e7dSPeter Dunlap return (idt->idt_private);
1515a6d42e7dSPeter Dunlap }
1516a6d42e7dSPeter Dunlap
1517a6d42e7dSPeter Dunlap void
idm_task_hold(idm_task_t * idt)1518a6d42e7dSPeter Dunlap idm_task_hold(idm_task_t *idt)
1519a6d42e7dSPeter Dunlap {
1520a6d42e7dSPeter Dunlap idm_refcnt_hold(&idt->idt_refcnt);
1521a6d42e7dSPeter Dunlap }
1522a6d42e7dSPeter Dunlap
1523a6d42e7dSPeter Dunlap void
idm_task_rele(idm_task_t * idt)1524a6d42e7dSPeter Dunlap idm_task_rele(idm_task_t *idt)
1525a6d42e7dSPeter Dunlap {
1526a6d42e7dSPeter Dunlap idm_refcnt_rele(&idt->idt_refcnt);
1527a6d42e7dSPeter Dunlap }
1528a6d42e7dSPeter Dunlap
152961dfa509SRick McNeal stmf_status_t
idm_task_abort(idm_conn_t * ic,idm_task_t * idt,idm_abort_type_t abort_type)1530a6d42e7dSPeter Dunlap idm_task_abort(idm_conn_t *ic, idm_task_t *idt, idm_abort_type_t abort_type)
1531a6d42e7dSPeter Dunlap {
1532a6d42e7dSPeter Dunlap idm_task_t *task;
1533a6d42e7dSPeter Dunlap int idx;
153461dfa509SRick McNeal stmf_status_t s = STMF_SUCCESS;
1535a6d42e7dSPeter Dunlap
1536a6d42e7dSPeter Dunlap /*
1537a6d42e7dSPeter Dunlap * Passing NULL as the task indicates that all tasks
1538a6d42e7dSPeter Dunlap * for this connection should be aborted.
1539a6d42e7dSPeter Dunlap */
1540a6d42e7dSPeter Dunlap if (idt == NULL) {
1541a6d42e7dSPeter Dunlap /*
1542a6d42e7dSPeter Dunlap * Only the connection state machine should ask for
1543a6d42e7dSPeter Dunlap * all tasks to abort and this should never happen in FFP.
1544a6d42e7dSPeter Dunlap */
1545a6d42e7dSPeter Dunlap ASSERT(!ic->ic_ffp);
1546a6d42e7dSPeter Dunlap rw_enter(&idm.idm_taskid_table_lock, RW_READER);
1547a6d42e7dSPeter Dunlap for (idx = 0; idx < idm.idm_taskid_max; idx++) {
1548a6d42e7dSPeter Dunlap task = idm.idm_taskid_table[idx];
154930e7468fSPeter Dunlap if (task == NULL)
155030e7468fSPeter Dunlap continue;
155130e7468fSPeter Dunlap mutex_enter(&task->idt_mutex);
155230e7468fSPeter Dunlap if ((task->idt_state != TASK_IDLE) &&
155330e7468fSPeter Dunlap (task->idt_state != TASK_COMPLETE) &&
1554a6d42e7dSPeter Dunlap (task->idt_ic == ic)) {
1555a6d42e7dSPeter Dunlap rw_exit(&idm.idm_taskid_table_lock);
155661dfa509SRick McNeal s = idm_task_abort_one(ic, task, abort_type);
1557a6d42e7dSPeter Dunlap rw_enter(&idm.idm_taskid_table_lock, RW_READER);
155830e7468fSPeter Dunlap } else
155930e7468fSPeter Dunlap mutex_exit(&task->idt_mutex);
1560a6d42e7dSPeter Dunlap }
1561a6d42e7dSPeter Dunlap rw_exit(&idm.idm_taskid_table_lock);
1562a6d42e7dSPeter Dunlap } else {
156330e7468fSPeter Dunlap mutex_enter(&idt->idt_mutex);
156461dfa509SRick McNeal s = idm_task_abort_one(ic, idt, abort_type);
1565a6d42e7dSPeter Dunlap }
156661dfa509SRick McNeal return (s);
1567a6d42e7dSPeter Dunlap }
1568a6d42e7dSPeter Dunlap
1569a6d42e7dSPeter Dunlap static void
idm_task_abort_unref_cb(void * ref)1570a6d42e7dSPeter Dunlap idm_task_abort_unref_cb(void *ref)
1571a6d42e7dSPeter Dunlap {
1572a6d42e7dSPeter Dunlap idm_task_t *idt = ref;
1573a6d42e7dSPeter Dunlap
1574a6d42e7dSPeter Dunlap mutex_enter(&idt->idt_mutex);
1575a6d42e7dSPeter Dunlap switch (idt->idt_state) {
1576a6d42e7dSPeter Dunlap case TASK_SUSPENDING:
1577a6d42e7dSPeter Dunlap idt->idt_state = TASK_SUSPENDED;
1578a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex);
1579a6d42e7dSPeter Dunlap idm_task_aborted(idt, IDM_STATUS_SUSPENDED);
1580a6d42e7dSPeter Dunlap return;
1581a6d42e7dSPeter Dunlap case TASK_ABORTING:
1582a6d42e7dSPeter Dunlap idt->idt_state = TASK_ABORTED;
1583a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex);
1584a6d42e7dSPeter Dunlap idm_task_aborted(idt, IDM_STATUS_ABORTED);
1585a6d42e7dSPeter Dunlap return;
1586a6d42e7dSPeter Dunlap default:
1587a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex);
1588a6d42e7dSPeter Dunlap ASSERT(0);
1589a6d42e7dSPeter Dunlap break;
1590a6d42e7dSPeter Dunlap }
1591a6d42e7dSPeter Dunlap }
1592a6d42e7dSPeter Dunlap
159330e7468fSPeter Dunlap /*
159430e7468fSPeter Dunlap * Abort the idm task.
159530e7468fSPeter Dunlap * Caller must hold the task mutex, which will be released before return
159630e7468fSPeter Dunlap */
159761dfa509SRick McNeal static stmf_status_t
idm_task_abort_one(idm_conn_t * ic,idm_task_t * idt,idm_abort_type_t abort_type)1598a6d42e7dSPeter Dunlap idm_task_abort_one(idm_conn_t *ic, idm_task_t *idt, idm_abort_type_t abort_type)
1599a6d42e7dSPeter Dunlap {
160061dfa509SRick McNeal stmf_status_t s = STMF_SUCCESS;
160161dfa509SRick McNeal
1602a6d42e7dSPeter Dunlap /* Caller must hold connection mutex */
160330e7468fSPeter Dunlap ASSERT(mutex_owned(&idt->idt_mutex));
1604a6d42e7dSPeter Dunlap switch (idt->idt_state) {
1605a6d42e7dSPeter Dunlap case TASK_ACTIVE:
1606a6d42e7dSPeter Dunlap switch (abort_type) {
1607a6d42e7dSPeter Dunlap case AT_INTERNAL_SUSPEND:
1608a6d42e7dSPeter Dunlap /* Call transport to release any resources */
1609a6d42e7dSPeter Dunlap idt->idt_state = TASK_SUSPENDING;
1610a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex);
1611a6d42e7dSPeter Dunlap ic->ic_transport_ops->it_free_task_rsrc(idt);
1612a6d42e7dSPeter Dunlap
1613a6d42e7dSPeter Dunlap /*
1614a6d42e7dSPeter Dunlap * Wait for outstanding references. When all
1615a6d42e7dSPeter Dunlap * references are released the callback will call
1616a6d42e7dSPeter Dunlap * idm_task_aborted().
1617a6d42e7dSPeter Dunlap */
1618a6d42e7dSPeter Dunlap idm_refcnt_async_wait_ref(&idt->idt_refcnt,
1619a6d42e7dSPeter Dunlap &idm_task_abort_unref_cb);
162061dfa509SRick McNeal return (s);
1621a6d42e7dSPeter Dunlap case AT_INTERNAL_ABORT:
1622a6d42e7dSPeter Dunlap case AT_TASK_MGMT_ABORT:
1623a6d42e7dSPeter Dunlap idt->idt_state = TASK_ABORTING;
1624a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex);
1625a6d42e7dSPeter Dunlap ic->ic_transport_ops->it_free_task_rsrc(idt);
1626a6d42e7dSPeter Dunlap
1627a6d42e7dSPeter Dunlap /*
1628a6d42e7dSPeter Dunlap * Wait for outstanding references. When all
1629a6d42e7dSPeter Dunlap * references are released the callback will call
1630a6d42e7dSPeter Dunlap * idm_task_aborted().
1631a6d42e7dSPeter Dunlap */
1632a6d42e7dSPeter Dunlap idm_refcnt_async_wait_ref(&idt->idt_refcnt,
1633a6d42e7dSPeter Dunlap &idm_task_abort_unref_cb);
163461dfa509SRick McNeal return (s);
1635a6d42e7dSPeter Dunlap default:
1636a6d42e7dSPeter Dunlap ASSERT(0);
1637a6d42e7dSPeter Dunlap }
1638a6d42e7dSPeter Dunlap break;
1639a6d42e7dSPeter Dunlap case TASK_SUSPENDING:
1640a6d42e7dSPeter Dunlap /* Already called transport_free_task_rsrc(); */
1641a6d42e7dSPeter Dunlap switch (abort_type) {
1642a6d42e7dSPeter Dunlap case AT_INTERNAL_SUSPEND:
1643a6d42e7dSPeter Dunlap /* Already doing it */
1644a6d42e7dSPeter Dunlap break;
1645a6d42e7dSPeter Dunlap case AT_INTERNAL_ABORT:
1646a6d42e7dSPeter Dunlap case AT_TASK_MGMT_ABORT:
1647a6d42e7dSPeter Dunlap idt->idt_state = TASK_ABORTING;
1648a6d42e7dSPeter Dunlap break;
1649a6d42e7dSPeter Dunlap default:
1650a6d42e7dSPeter Dunlap ASSERT(0);
1651a6d42e7dSPeter Dunlap }
1652a6d42e7dSPeter Dunlap break;
1653a6d42e7dSPeter Dunlap case TASK_SUSPENDED:
1654a6d42e7dSPeter Dunlap /* Already called transport_free_task_rsrc(); */
1655a6d42e7dSPeter Dunlap switch (abort_type) {
1656a6d42e7dSPeter Dunlap case AT_INTERNAL_SUSPEND:
1657a6d42e7dSPeter Dunlap /* Already doing it */
1658a6d42e7dSPeter Dunlap break;
1659a6d42e7dSPeter Dunlap case AT_INTERNAL_ABORT:
1660a6d42e7dSPeter Dunlap case AT_TASK_MGMT_ABORT:
1661a6d42e7dSPeter Dunlap idt->idt_state = TASK_ABORTING;
1662a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex);
1663a6d42e7dSPeter Dunlap
1664a6d42e7dSPeter Dunlap /*
1665a6d42e7dSPeter Dunlap * We could probably call idm_task_aborted directly
1666a6d42e7dSPeter Dunlap * here but we may be holding the conn lock. It's
1667a6d42e7dSPeter Dunlap * easier to just switch contexts. Even though
1668a6d42e7dSPeter Dunlap * we shouldn't really have any references we'll
1669a6d42e7dSPeter Dunlap * set the state to TASK_ABORTING instead of
1670a6d42e7dSPeter Dunlap * TASK_ABORTED so we can use the same code path.
1671a6d42e7dSPeter Dunlap */
1672a6d42e7dSPeter Dunlap idm_refcnt_async_wait_ref(&idt->idt_refcnt,
1673a6d42e7dSPeter Dunlap &idm_task_abort_unref_cb);
167461dfa509SRick McNeal return (s);
1675a6d42e7dSPeter Dunlap default:
1676a6d42e7dSPeter Dunlap ASSERT(0);
1677a6d42e7dSPeter Dunlap }
1678a6d42e7dSPeter Dunlap break;
1679a6d42e7dSPeter Dunlap case TASK_ABORTING:
1680a6d42e7dSPeter Dunlap case TASK_ABORTED:
1681a6d42e7dSPeter Dunlap switch (abort_type) {
1682a6d42e7dSPeter Dunlap case AT_INTERNAL_SUSPEND:
1683a6d42e7dSPeter Dunlap /* We're already past this point... */
1684a6d42e7dSPeter Dunlap case AT_INTERNAL_ABORT:
1685a6d42e7dSPeter Dunlap case AT_TASK_MGMT_ABORT:
1686a6d42e7dSPeter Dunlap /* Already doing it */
1687a6d42e7dSPeter Dunlap break;
1688a6d42e7dSPeter Dunlap default:
1689a6d42e7dSPeter Dunlap ASSERT(0);
1690a6d42e7dSPeter Dunlap }
1691a6d42e7dSPeter Dunlap break;
1692a6d42e7dSPeter Dunlap case TASK_COMPLETE:
169361dfa509SRick McNeal idm_refcnt_wait_ref(&idt->idt_refcnt);
169461dfa509SRick McNeal s = STMF_ABORT_SUCCESS;
1695a6d42e7dSPeter Dunlap break;
1696a6d42e7dSPeter Dunlap default:
1697a6d42e7dSPeter Dunlap ASSERT(0);
1698a6d42e7dSPeter Dunlap }
1699a6d42e7dSPeter Dunlap mutex_exit(&idt->idt_mutex);
170061dfa509SRick McNeal
170161dfa509SRick McNeal return (s);
1702a6d42e7dSPeter Dunlap }
1703a6d42e7dSPeter Dunlap
1704a6d42e7dSPeter Dunlap static void
idm_task_aborted(idm_task_t * idt,idm_status_t status)1705a6d42e7dSPeter Dunlap idm_task_aborted(idm_task_t *idt, idm_status_t status)
1706a6d42e7dSPeter Dunlap {
1707a6d42e7dSPeter Dunlap (*idt->idt_ic->ic_conn_ops.icb_task_aborted)(idt, status);
1708a6d42e7dSPeter Dunlap }
1709a6d42e7dSPeter Dunlap
1710a6d42e7dSPeter Dunlap /*
1711a6d42e7dSPeter Dunlap * idm_pdu_tx
1712a6d42e7dSPeter Dunlap *
1713a6d42e7dSPeter Dunlap * This is IDM's implementation of the 'Send_Control' operational primitive.
1714a6d42e7dSPeter Dunlap * This function is invoked by an initiator iSCSI layer requesting the transfer
1715a6d42e7dSPeter Dunlap * of a iSCSI command PDU or a target iSCSI layer requesting the transfer of a
1716a6d42e7dSPeter Dunlap * iSCSI response PDU. The PDU will be transmitted as-is by the local Datamover
1717a6d42e7dSPeter Dunlap * layer to the peer iSCSI layer in the remote iSCSI node. The connection info
1718a6d42e7dSPeter Dunlap * and iSCSI PDU-specific qualifiers namely BHS, AHS, DataDescriptor and Size
1719a6d42e7dSPeter Dunlap * are provided as input.
1720a6d42e7dSPeter Dunlap *
1721a6d42e7dSPeter Dunlap */
1722a6d42e7dSPeter Dunlap void
idm_pdu_tx(idm_pdu_t * pdu)1723a6d42e7dSPeter Dunlap idm_pdu_tx(idm_pdu_t *pdu)
1724a6d42e7dSPeter Dunlap {
1725a6d42e7dSPeter Dunlap idm_conn_t *ic = pdu->isp_ic;
1726a6d42e7dSPeter Dunlap iscsi_async_evt_hdr_t *async_evt;
1727a6d42e7dSPeter Dunlap
1728a6d42e7dSPeter Dunlap /*
1729a6d42e7dSPeter Dunlap * If we are in full-featured mode then route SCSI-related
1730a6d42e7dSPeter Dunlap * commands to the appropriate function vector without checking
1731a6d42e7dSPeter Dunlap * the connection state. We will only be in full-feature mode
1732a6d42e7dSPeter Dunlap * when we are in an acceptable state for SCSI PDU's.
1733a6d42e7dSPeter Dunlap *
1734a6d42e7dSPeter Dunlap * We also need to ensure that there are no PDU events outstanding
1735a6d42e7dSPeter Dunlap * on the state machine. Any non-SCSI PDU's received in full-feature
1736a6d42e7dSPeter Dunlap * mode will result in PDU events and until these have been handled
1737a6d42e7dSPeter Dunlap * we need to route all PDU's through the state machine as PDU
1738a6d42e7dSPeter Dunlap * events to maintain ordering.
1739a6d42e7dSPeter Dunlap *
1740a6d42e7dSPeter Dunlap * Note that IDM cannot enter FFP mode until it processes in
1741a6d42e7dSPeter Dunlap * its state machine the last xmit of the login process.
1742a6d42e7dSPeter Dunlap * Hence, checking the IDM_PDU_LOGIN_TX flag here would be
1743a6d42e7dSPeter Dunlap * superfluous.
1744a6d42e7dSPeter Dunlap */
1745a6d42e7dSPeter Dunlap mutex_enter(&ic->ic_state_mutex);
1746a6d42e7dSPeter Dunlap if (ic->ic_ffp && (ic->ic_pdu_events == 0)) {
1747a6d42e7dSPeter Dunlap mutex_exit(&ic->ic_state_mutex);
1748a6d42e7dSPeter Dunlap switch (IDM_PDU_OPCODE(pdu)) {
1749a6d42e7dSPeter Dunlap case ISCSI_OP_SCSI_RSP:
1750a6d42e7dSPeter Dunlap /* Target only */
1751a668b114SPriya Krishnan DTRACE_ISCSI_2(scsi__response, idm_conn_t *, ic,
1752a668b114SPriya Krishnan iscsi_scsi_rsp_hdr_t *,
1753a668b114SPriya Krishnan (iscsi_scsi_rsp_hdr_t *)pdu->isp_hdr);
1754a6d42e7dSPeter Dunlap idm_pdu_tx_forward(ic, pdu);
1755a6d42e7dSPeter Dunlap return;
1756a6d42e7dSPeter Dunlap case ISCSI_OP_SCSI_TASK_MGT_RSP:
1757a6d42e7dSPeter Dunlap /* Target only */
1758a668b114SPriya Krishnan DTRACE_ISCSI_2(task__response, idm_conn_t *, ic,
1759a668b114SPriya Krishnan iscsi_text_rsp_hdr_t *,
1760a668b114SPriya Krishnan (iscsi_text_rsp_hdr_t *)pdu->isp_hdr);
1761a6d42e7dSPeter Dunlap idm_pdu_tx_forward(ic, pdu);
1762a6d42e7dSPeter Dunlap return;
1763a6d42e7dSPeter Dunlap case ISCSI_OP_SCSI_DATA_RSP:
1764a6d42e7dSPeter Dunlap /* Target only */
1765a668b114SPriya Krishnan DTRACE_ISCSI_2(data__send, idm_conn_t *, ic,
1766a668b114SPriya Krishnan iscsi_data_rsp_hdr_t *,
1767a668b114SPriya Krishnan (iscsi_data_rsp_hdr_t *)pdu->isp_hdr);
1768a6d42e7dSPeter Dunlap idm_pdu_tx_forward(ic, pdu);
1769a6d42e7dSPeter Dunlap return;
1770a6d42e7dSPeter Dunlap case ISCSI_OP_RTT_RSP:
1771a6d42e7dSPeter Dunlap /* Target only */
1772a668b114SPriya Krishnan DTRACE_ISCSI_2(data__request, idm_conn_t *, ic,
1773a668b114SPriya Krishnan iscsi_rtt_hdr_t *,
1774a668b114SPriya Krishnan (iscsi_rtt_hdr_t *)pdu->isp_hdr);
1775a6d42e7dSPeter Dunlap idm_pdu_tx_forward(ic, pdu);
1776a6d42e7dSPeter Dunlap return;
1777a6d42e7dSPeter Dunlap case ISCSI_OP_NOOP_IN:
1778a6d42e7dSPeter Dunlap /* Target only */
1779a668b114SPriya Krishnan DTRACE_ISCSI_2(nop__send, idm_conn_t *, ic,
1780a668b114SPriya Krishnan iscsi_nop_in_hdr_t *,
1781a668b114SPriya Krishnan (iscsi_nop_in_hdr_t *)pdu->isp_hdr);
1782a6d42e7dSPeter Dunlap idm_pdu_tx_forward(ic, pdu);
1783a6d42e7dSPeter Dunlap return;
1784a6d42e7dSPeter Dunlap case ISCSI_OP_TEXT_RSP:
1785a6d42e7dSPeter Dunlap /* Target only */
1786a668b114SPriya Krishnan DTRACE_ISCSI_2(text__response, idm_conn_t *, ic,
1787a668b114SPriya Krishnan iscsi_text_rsp_hdr_t *,
1788a668b114SPriya Krishnan (iscsi_text_rsp_hdr_t *)pdu->isp_hdr);
1789a6d42e7dSPeter Dunlap idm_pdu_tx_forward(ic, pdu);
1790a6d42e7dSPeter Dunlap return;
1791a6d42e7dSPeter Dunlap case ISCSI_OP_TEXT_CMD:
1792a6d42e7dSPeter Dunlap case ISCSI_OP_NOOP_OUT:
1793a6d42e7dSPeter Dunlap case ISCSI_OP_SCSI_CMD:
1794a6d42e7dSPeter Dunlap case ISCSI_OP_SCSI_DATA:
1795a6d42e7dSPeter Dunlap case ISCSI_OP_SCSI_TASK_MGT_MSG:
1796a6d42e7dSPeter Dunlap /* Initiator only */
1797a6d42e7dSPeter Dunlap idm_pdu_tx_forward(ic, pdu);
1798a6d42e7dSPeter Dunlap return;
1799a6d42e7dSPeter Dunlap default:
1800a6d42e7dSPeter Dunlap break;
1801a6d42e7dSPeter Dunlap }
1802a6d42e7dSPeter Dunlap
1803a6d42e7dSPeter Dunlap mutex_enter(&ic->ic_state_mutex);
1804a6d42e7dSPeter Dunlap }
1805a6d42e7dSPeter Dunlap
1806a6d42e7dSPeter Dunlap /*
1807a6d42e7dSPeter Dunlap * Any PDU's processed outside of full-feature mode and non-SCSI
1808a6d42e7dSPeter Dunlap * PDU's in full-feature mode are handled by generating an
1809a6d42e7dSPeter Dunlap * event to the connection state machine. The state machine
1810a6d42e7dSPeter Dunlap * will validate the PDU against the current state and either
1811a6d42e7dSPeter Dunlap * transmit the PDU if the opcode is allowed or handle an
1812a6d42e7dSPeter Dunlap * error if the PDU is not allowed.
1813a6d42e7dSPeter Dunlap *
1814a6d42e7dSPeter Dunlap * This code-path will also generate any events that are implied
1815a6d42e7dSPeter Dunlap * by the PDU opcode. For example a "login response" with success
1816a6d42e7dSPeter Dunlap * status generates a CE_LOGOUT_SUCCESS_SND event.
1817a6d42e7dSPeter Dunlap */
1818a6d42e7dSPeter Dunlap switch (IDM_PDU_OPCODE(pdu)) {
1819a6d42e7dSPeter Dunlap case ISCSI_OP_LOGIN_CMD:
1820a6d42e7dSPeter Dunlap idm_conn_tx_pdu_event(ic, CE_LOGIN_SND, (uintptr_t)pdu);
1821a6d42e7dSPeter Dunlap break;
1822a6d42e7dSPeter Dunlap case ISCSI_OP_LOGIN_RSP:
1823a668b114SPriya Krishnan DTRACE_ISCSI_2(login__response, idm_conn_t *, ic,
1824a668b114SPriya Krishnan iscsi_login_rsp_hdr_t *,
1825a668b114SPriya Krishnan (iscsi_login_rsp_hdr_t *)pdu->isp_hdr);
1826a6d42e7dSPeter Dunlap idm_parse_login_rsp(ic, pdu, /* Is RX */ B_FALSE);
1827a6d42e7dSPeter Dunlap break;
1828a6d42e7dSPeter Dunlap case ISCSI_OP_LOGOUT_CMD:
1829a6d42e7dSPeter Dunlap idm_parse_logout_req(ic, pdu, /* Is RX */ B_FALSE);
1830a6d42e7dSPeter Dunlap break;
1831a6d42e7dSPeter Dunlap case ISCSI_OP_LOGOUT_RSP:
1832a668b114SPriya Krishnan DTRACE_ISCSI_2(logout__response, idm_conn_t *, ic,
1833a668b114SPriya Krishnan iscsi_logout_rsp_hdr_t *,
1834a668b114SPriya Krishnan (iscsi_logout_rsp_hdr_t *)pdu->isp_hdr);
1835a6d42e7dSPeter Dunlap idm_parse_logout_rsp(ic, pdu, /* Is RX */ B_FALSE);
1836a6d42e7dSPeter Dunlap break;
1837a6d42e7dSPeter Dunlap case ISCSI_OP_ASYNC_EVENT:
1838a668b114SPriya Krishnan DTRACE_ISCSI_2(async__send, idm_conn_t *, ic,
1839a668b114SPriya Krishnan iscsi_async_evt_hdr_t *,
1840a668b114SPriya Krishnan (iscsi_async_evt_hdr_t *)pdu->isp_hdr);
1841a6d42e7dSPeter Dunlap async_evt = (iscsi_async_evt_hdr_t *)pdu->isp_hdr;
1842a6d42e7dSPeter Dunlap switch (async_evt->async_event) {
1843a6d42e7dSPeter Dunlap case ISCSI_ASYNC_EVENT_REQUEST_LOGOUT:
1844a6d42e7dSPeter Dunlap idm_conn_tx_pdu_event(ic, CE_ASYNC_LOGOUT_SND,
1845a6d42e7dSPeter Dunlap (uintptr_t)pdu);
1846a6d42e7dSPeter Dunlap break;
1847a6d42e7dSPeter Dunlap case ISCSI_ASYNC_EVENT_DROPPING_CONNECTION:
1848a6d42e7dSPeter Dunlap idm_conn_tx_pdu_event(ic, CE_ASYNC_DROP_CONN_SND,
1849a6d42e7dSPeter Dunlap (uintptr_t)pdu);
1850a6d42e7dSPeter Dunlap break;
1851a6d42e7dSPeter Dunlap case ISCSI_ASYNC_EVENT_DROPPING_ALL_CONNECTIONS:
1852a6d42e7dSPeter Dunlap idm_conn_tx_pdu_event(ic, CE_ASYNC_DROP_ALL_CONN_SND,
1853a6d42e7dSPeter Dunlap (uintptr_t)pdu);
1854a6d42e7dSPeter Dunlap break;
1855a6d42e7dSPeter Dunlap case ISCSI_ASYNC_EVENT_SCSI_EVENT:
1856a6d42e7dSPeter Dunlap case ISCSI_ASYNC_EVENT_PARAM_NEGOTIATION:
1857a6d42e7dSPeter Dunlap default:
1858a6d42e7dSPeter Dunlap idm_conn_tx_pdu_event(ic, CE_MISC_TX,
1859a6d42e7dSPeter Dunlap (uintptr_t)pdu);
1860a6d42e7dSPeter Dunlap break;
1861a6d42e7dSPeter Dunlap }
1862a6d42e7dSPeter Dunlap break;
1863a6d42e7dSPeter Dunlap case ISCSI_OP_SCSI_RSP:
1864a6d42e7dSPeter Dunlap /* Target only */
1865a668b114SPriya Krishnan DTRACE_ISCSI_2(scsi__response, idm_conn_t *, ic,
1866a668b114SPriya Krishnan iscsi_scsi_rsp_hdr_t *,
1867a668b114SPriya Krishnan (iscsi_scsi_rsp_hdr_t *)pdu->isp_hdr);
1868a6d42e7dSPeter Dunlap idm_conn_tx_pdu_event(ic, CE_MISC_TX, (uintptr_t)pdu);
1869a6d42e7dSPeter Dunlap break;
1870a6d42e7dSPeter Dunlap case ISCSI_OP_SCSI_TASK_MGT_RSP:
1871a6d42e7dSPeter Dunlap /* Target only */
1872a668b114SPriya Krishnan DTRACE_ISCSI_2(task__response, idm_conn_t *, ic,
1873a668b114SPriya Krishnan iscsi_scsi_task_mgt_rsp_hdr_t *,
1874a668b114SPriya Krishnan (iscsi_scsi_task_mgt_rsp_hdr_t *)pdu->isp_hdr);
1875a6d42e7dSPeter Dunlap idm_conn_tx_pdu_event(ic, CE_MISC_TX, (uintptr_t)pdu);
1876a6d42e7dSPeter Dunlap break;
1877a6d42e7dSPeter Dunlap case ISCSI_OP_SCSI_DATA_RSP:
1878a6d42e7dSPeter Dunlap /* Target only */
1879a668b114SPriya Krishnan DTRACE_ISCSI_2(data__send, idm_conn_t *, ic,
1880a668b114SPriya Krishnan iscsi_data_rsp_hdr_t *,
1881a668b114SPriya Krishnan (iscsi_data_rsp_hdr_t *)pdu->isp_hdr);
1882a6d42e7dSPeter Dunlap idm_conn_tx_pdu_event(ic, CE_MISC_TX, (uintptr_t)pdu);
1883a6d42e7dSPeter Dunlap break;
1884a6d42e7dSPeter Dunlap case ISCSI_OP_RTT_RSP:
1885a6d42e7dSPeter Dunlap /* Target only */
1886a668b114SPriya Krishnan DTRACE_ISCSI_2(data__request, idm_conn_t *, ic,
1887a668b114SPriya Krishnan iscsi_rtt_hdr_t *,
1888a668b114SPriya Krishnan (iscsi_rtt_hdr_t *)pdu->isp_hdr);
1889a6d42e7dSPeter Dunlap idm_conn_tx_pdu_event(ic, CE_MISC_TX, (uintptr_t)pdu);
1890a6d42e7dSPeter Dunlap break;
1891a6d42e7dSPeter Dunlap case ISCSI_OP_NOOP_IN:
1892a6d42e7dSPeter Dunlap /* Target only */
1893a668b114SPriya Krishnan DTRACE_ISCSI_2(nop__send, idm_conn_t *, ic,
1894a668b114SPriya Krishnan iscsi_nop_in_hdr_t *,
1895a668b114SPriya Krishnan (iscsi_nop_in_hdr_t *)pdu->isp_hdr);
1896a6d42e7dSPeter Dunlap idm_conn_tx_pdu_event(ic, CE_MISC_TX, (uintptr_t)pdu);
1897a6d42e7dSPeter Dunlap break;
1898a6d42e7dSPeter Dunlap case ISCSI_OP_TEXT_RSP:
1899a6d42e7dSPeter Dunlap /* Target only */
1900a668b114SPriya Krishnan DTRACE_ISCSI_2(text__response, idm_conn_t *, ic,
1901a668b114SPriya Krishnan iscsi_text_rsp_hdr_t *,
1902a668b114SPriya Krishnan (iscsi_text_rsp_hdr_t *)pdu->isp_hdr);
1903a6d42e7dSPeter Dunlap idm_conn_tx_pdu_event(ic, CE_MISC_TX, (uintptr_t)pdu);
1904a6d42e7dSPeter Dunlap break;
1905a6d42e7dSPeter Dunlap /* Initiator only */
1906a6d42e7dSPeter Dunlap case ISCSI_OP_SCSI_CMD:
1907a6d42e7dSPeter Dunlap case ISCSI_OP_SCSI_TASK_MGT_MSG:
1908a6d42e7dSPeter Dunlap case ISCSI_OP_SCSI_DATA:
1909a6d42e7dSPeter Dunlap case ISCSI_OP_NOOP_OUT:
1910a6d42e7dSPeter Dunlap case ISCSI_OP_TEXT_CMD:
1911a6d42e7dSPeter Dunlap case ISCSI_OP_SNACK_CMD:
1912a6d42e7dSPeter Dunlap case ISCSI_OP_REJECT_MSG:
1913a6d42e7dSPeter Dunlap default:
1914a6d42e7dSPeter Dunlap /*
1915a6d42e7dSPeter Dunlap * Connection state machine will validate these PDU's against
1916a6d42e7dSPeter Dunlap * the current state. A PDU not allowed in the current
1917a6d42e7dSPeter Dunlap * state will cause a protocol error.
1918a6d42e7dSPeter Dunlap */
1919a6d42e7dSPeter Dunlap idm_conn_tx_pdu_event(ic, CE_MISC_TX, (uintptr_t)pdu);
1920a6d42e7dSPeter Dunlap break;
1921a6d42e7dSPeter Dunlap }
1922a6d42e7dSPeter Dunlap mutex_exit(&ic->ic_state_mutex);
1923a6d42e7dSPeter Dunlap }
1924a6d42e7dSPeter Dunlap
1925a6d42e7dSPeter Dunlap /*
192630e7468fSPeter Dunlap * Common allocation of a PDU along with memory for header and data.
1927a6d42e7dSPeter Dunlap */
192830e7468fSPeter Dunlap static idm_pdu_t *
idm_pdu_alloc_common(uint_t hdrlen,uint_t datalen,int sleepflag)192930e7468fSPeter Dunlap idm_pdu_alloc_common(uint_t hdrlen, uint_t datalen, int sleepflag)
1930a6d42e7dSPeter Dunlap {
1931a6d42e7dSPeter Dunlap idm_pdu_t *result;
1932a6d42e7dSPeter Dunlap
1933a6d42e7dSPeter Dunlap /*
1934a6d42e7dSPeter Dunlap * IDM clients should cache these structures for performance
1935a6d42e7dSPeter Dunlap * critical paths. We can't cache effectively in IDM because we
1936a6d42e7dSPeter Dunlap * don't know the correct header and data size.
1937a6d42e7dSPeter Dunlap *
1938a6d42e7dSPeter Dunlap * Valid header length is assumed to be hdrlen and valid data
1939a6d42e7dSPeter Dunlap * length is assumed to be datalen. isp_hdrlen and isp_datalen
1940a6d42e7dSPeter Dunlap * can be adjusted after the PDU is returned if necessary.
1941a6d42e7dSPeter Dunlap */
194230e7468fSPeter Dunlap result = kmem_zalloc(sizeof (idm_pdu_t) + hdrlen + datalen, sleepflag);
194330e7468fSPeter Dunlap if (result != NULL) {
194430e7468fSPeter Dunlap /* For idm_pdu_free sanity check */
194530e7468fSPeter Dunlap result->isp_flags |= IDM_PDU_ALLOC;
194630e7468fSPeter Dunlap /* pointer arithmetic */
194730e7468fSPeter Dunlap result->isp_hdr = (iscsi_hdr_t *)(result + 1);
194830e7468fSPeter Dunlap result->isp_hdrlen = hdrlen;
194930e7468fSPeter Dunlap result->isp_hdrbuflen = hdrlen;
195030e7468fSPeter Dunlap result->isp_transport_hdrlen = 0;
19514142b486SJames Moore if (datalen != 0)
19524142b486SJames Moore result->isp_data = (uint8_t *)result->isp_hdr + hdrlen;
195330e7468fSPeter Dunlap result->isp_datalen = datalen;
195430e7468fSPeter Dunlap result->isp_databuflen = datalen;
195530e7468fSPeter Dunlap result->isp_magic = IDM_PDU_MAGIC;
195630e7468fSPeter Dunlap }
1957a6d42e7dSPeter Dunlap
1958a6d42e7dSPeter Dunlap return (result);
1959a6d42e7dSPeter Dunlap }
1960a6d42e7dSPeter Dunlap
196130e7468fSPeter Dunlap /*
196230e7468fSPeter Dunlap * Typical idm_pdu_alloc invocation, will block for resources.
196330e7468fSPeter Dunlap */
196430e7468fSPeter Dunlap idm_pdu_t *
idm_pdu_alloc(uint_t hdrlen,uint_t datalen)196530e7468fSPeter Dunlap idm_pdu_alloc(uint_t hdrlen, uint_t datalen)
196630e7468fSPeter Dunlap {
196730e7468fSPeter Dunlap return (idm_pdu_alloc_common(hdrlen, datalen, KM_SLEEP));
196830e7468fSPeter Dunlap }
196930e7468fSPeter Dunlap
197030e7468fSPeter Dunlap /*
197130e7468fSPeter Dunlap * Non-blocking idm_pdu_alloc implementation, returns NULL if resources
197230e7468fSPeter Dunlap * are not available. Needed for transport-layer allocations which may
197330e7468fSPeter Dunlap * be invoking in interrupt context.
197430e7468fSPeter Dunlap */
197530e7468fSPeter Dunlap idm_pdu_t *
idm_pdu_alloc_nosleep(uint_t hdrlen,uint_t datalen)197630e7468fSPeter Dunlap idm_pdu_alloc_nosleep(uint_t hdrlen, uint_t datalen)
197730e7468fSPeter Dunlap {
197830e7468fSPeter Dunlap return (idm_pdu_alloc_common(hdrlen, datalen, KM_NOSLEEP));
197930e7468fSPeter Dunlap }
198030e7468fSPeter Dunlap
1981a6d42e7dSPeter Dunlap /*
1982a6d42e7dSPeter Dunlap * Free a PDU previously allocated with idm_pdu_alloc() including any
1983a6d42e7dSPeter Dunlap * header and data space allocated as part of the original request.
1984a6d42e7dSPeter Dunlap * Additional memory regions referenced by subsequent modification of
1985a6d42e7dSPeter Dunlap * the isp_hdr and/or isp_data fields will not be freed.
1986a6d42e7dSPeter Dunlap */
1987a6d42e7dSPeter Dunlap void
idm_pdu_free(idm_pdu_t * pdu)1988a6d42e7dSPeter Dunlap idm_pdu_free(idm_pdu_t *pdu)
1989a6d42e7dSPeter Dunlap {
1990a6d42e7dSPeter Dunlap /* Make sure the structure was allocated using idm_pdu_alloc() */
1991a6d42e7dSPeter Dunlap ASSERT(pdu->isp_flags & IDM_PDU_ALLOC);
1992a6d42e7dSPeter Dunlap kmem_free(pdu,
1993a6d42e7dSPeter Dunlap sizeof (idm_pdu_t) + pdu->isp_hdrbuflen + pdu->isp_databuflen);
1994a6d42e7dSPeter Dunlap }
1995a6d42e7dSPeter Dunlap
1996a6d42e7dSPeter Dunlap /*
1997a6d42e7dSPeter Dunlap * Initialize the connection, private and callback fields in a PDU.
1998a6d42e7dSPeter Dunlap */
1999a6d42e7dSPeter Dunlap void
idm_pdu_init(idm_pdu_t * pdu,idm_conn_t * ic,void * private,idm_pdu_cb_t * cb)2000a6d42e7dSPeter Dunlap idm_pdu_init(idm_pdu_t *pdu, idm_conn_t *ic, void *private, idm_pdu_cb_t *cb)
2001a6d42e7dSPeter Dunlap {
2002a6d42e7dSPeter Dunlap /*
2003a6d42e7dSPeter Dunlap * idm_pdu_complete() will call idm_pdu_free if the callback is
2004a6d42e7dSPeter Dunlap * NULL. This will only work if the PDU was originally allocated
2005a6d42e7dSPeter Dunlap * with idm_pdu_alloc().
2006a6d42e7dSPeter Dunlap */
2007a6d42e7dSPeter Dunlap ASSERT((pdu->isp_flags & IDM_PDU_ALLOC) ||
2008a6d42e7dSPeter Dunlap (cb != NULL));
2009a6d42e7dSPeter Dunlap pdu->isp_magic = IDM_PDU_MAGIC;
2010a6d42e7dSPeter Dunlap pdu->isp_ic = ic;
2011a6d42e7dSPeter Dunlap pdu->isp_private = private;
2012a6d42e7dSPeter Dunlap pdu->isp_callback = cb;
2013a6d42e7dSPeter Dunlap }
2014a6d42e7dSPeter Dunlap
2015a6d42e7dSPeter Dunlap /*
2016a6d42e7dSPeter Dunlap * Initialize the header and header length field. This function should
2017a6d42e7dSPeter Dunlap * not be used to adjust the header length in a buffer allocated via
2018a6d42e7dSPeter Dunlap * pdu_pdu_alloc since it overwrites the existing header pointer.
2019a6d42e7dSPeter Dunlap */
2020a6d42e7dSPeter Dunlap void
idm_pdu_init_hdr(idm_pdu_t * pdu,uint8_t * hdr,uint_t hdrlen)2021a6d42e7dSPeter Dunlap idm_pdu_init_hdr(idm_pdu_t *pdu, uint8_t *hdr, uint_t hdrlen)
2022a6d42e7dSPeter Dunlap {
2023a6d42e7dSPeter Dunlap pdu->isp_hdr = (iscsi_hdr_t *)((void *)hdr);
2024a6d42e7dSPeter Dunlap pdu->isp_hdrlen = hdrlen;
2025a6d42e7dSPeter Dunlap }
2026a6d42e7dSPeter Dunlap
2027a6d42e7dSPeter Dunlap /*
2028a6d42e7dSPeter Dunlap * Initialize the data and data length fields. This function should
2029a6d42e7dSPeter Dunlap * not be used to adjust the data length of a buffer allocated via
2030a6d42e7dSPeter Dunlap * idm_pdu_alloc since it overwrites the existing data pointer.
2031a6d42e7dSPeter Dunlap */
2032a6d42e7dSPeter Dunlap void
idm_pdu_init_data(idm_pdu_t * pdu,uint8_t * data,uint_t datalen)2033a6d42e7dSPeter Dunlap idm_pdu_init_data(idm_pdu_t *pdu, uint8_t *data, uint_t datalen)
2034a6d42e7dSPeter Dunlap {
2035a6d42e7dSPeter Dunlap pdu->isp_data = data;
2036a6d42e7dSPeter Dunlap pdu->isp_datalen = datalen;
2037a6d42e7dSPeter Dunlap }
2038a6d42e7dSPeter Dunlap
2039a6d42e7dSPeter Dunlap void
idm_pdu_complete(idm_pdu_t * pdu,idm_status_t status)2040a6d42e7dSPeter Dunlap idm_pdu_complete(idm_pdu_t *pdu, idm_status_t status)
2041a6d42e7dSPeter Dunlap {
2042a6d42e7dSPeter Dunlap if (pdu->isp_callback) {
2043a6d42e7dSPeter Dunlap pdu->isp_status = status;
2044a6d42e7dSPeter Dunlap (*pdu->isp_callback)(pdu, status);
2045a6d42e7dSPeter Dunlap } else {
2046a6d42e7dSPeter Dunlap idm_pdu_free(pdu);
2047a6d42e7dSPeter Dunlap }
2048a6d42e7dSPeter Dunlap }
2049a6d42e7dSPeter Dunlap
2050a6d42e7dSPeter Dunlap /*
2051a6d42e7dSPeter Dunlap * State machine auditing
2052a6d42e7dSPeter Dunlap */
2053a6d42e7dSPeter Dunlap
2054a6d42e7dSPeter Dunlap void
idm_sm_audit_init(sm_audit_buf_t * audit_buf)2055a6d42e7dSPeter Dunlap idm_sm_audit_init(sm_audit_buf_t *audit_buf)
2056a6d42e7dSPeter Dunlap {
2057a6d42e7dSPeter Dunlap bzero(audit_buf, sizeof (sm_audit_buf_t));
2058a6d42e7dSPeter Dunlap audit_buf->sab_max_index = SM_AUDIT_BUF_MAX_REC - 1;
2059a6d42e7dSPeter Dunlap }
2060a6d42e7dSPeter Dunlap
2061a6d42e7dSPeter Dunlap static
2062a6d42e7dSPeter Dunlap 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)2063a6d42e7dSPeter Dunlap idm_sm_audit_common(sm_audit_buf_t *audit_buf, sm_audit_record_type_t r_type,
2064a6d42e7dSPeter Dunlap sm_audit_sm_type_t sm_type,
2065a6d42e7dSPeter Dunlap int current_state)
2066a6d42e7dSPeter Dunlap {
2067a6d42e7dSPeter Dunlap sm_audit_record_t *sar;
2068a6d42e7dSPeter Dunlap
2069a6d42e7dSPeter Dunlap sar = audit_buf->sab_records;
2070a6d42e7dSPeter Dunlap sar += audit_buf->sab_index;
2071a6d42e7dSPeter Dunlap audit_buf->sab_index++;
2072a6d42e7dSPeter Dunlap audit_buf->sab_index &= audit_buf->sab_max_index;
2073a6d42e7dSPeter Dunlap
2074a6d42e7dSPeter Dunlap sar->sar_type = r_type;
2075a6d42e7dSPeter Dunlap gethrestime(&sar->sar_timestamp);
2076a6d42e7dSPeter Dunlap sar->sar_sm_type = sm_type;
2077a6d42e7dSPeter Dunlap sar->sar_state = current_state;
2078a6d42e7dSPeter Dunlap
2079a6d42e7dSPeter Dunlap return (sar);
2080a6d42e7dSPeter Dunlap }
2081a6d42e7dSPeter Dunlap
2082a6d42e7dSPeter Dunlap 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)2083a6d42e7dSPeter Dunlap idm_sm_audit_event(sm_audit_buf_t *audit_buf,
2084a6d42e7dSPeter Dunlap sm_audit_sm_type_t sm_type, int current_state,
2085a6d42e7dSPeter Dunlap int event, uintptr_t event_info)
2086a6d42e7dSPeter Dunlap {
2087a6d42e7dSPeter Dunlap sm_audit_record_t *sar;
2088a6d42e7dSPeter Dunlap
2089a6d42e7dSPeter Dunlap sar = idm_sm_audit_common(audit_buf, SAR_STATE_EVENT,
2090a6d42e7dSPeter Dunlap sm_type, current_state);
2091a6d42e7dSPeter Dunlap sar->sar_event = event;
2092a6d42e7dSPeter Dunlap sar->sar_event_info = event_info;
2093a6d42e7dSPeter Dunlap }
2094a6d42e7dSPeter Dunlap
2095a6d42e7dSPeter Dunlap 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)2096a6d42e7dSPeter Dunlap idm_sm_audit_state_change(sm_audit_buf_t *audit_buf,
2097a6d42e7dSPeter Dunlap sm_audit_sm_type_t sm_type, int current_state, int new_state)
2098a6d42e7dSPeter Dunlap {
2099a6d42e7dSPeter Dunlap sm_audit_record_t *sar;
2100a6d42e7dSPeter Dunlap
2101a6d42e7dSPeter Dunlap sar = idm_sm_audit_common(audit_buf, SAR_STATE_CHANGE,
2102a6d42e7dSPeter Dunlap sm_type, current_state);
2103a6d42e7dSPeter Dunlap sar->sar_new_state = new_state;
2104a6d42e7dSPeter Dunlap }
2105a6d42e7dSPeter Dunlap
2106a6d42e7dSPeter Dunlap
2107a6d42e7dSPeter Dunlap /*
2108a6d42e7dSPeter Dunlap * Object reference tracking
2109a6d42e7dSPeter Dunlap */
2110a6d42e7dSPeter Dunlap
2111a6d42e7dSPeter Dunlap void
idm_refcnt_init(idm_refcnt_t * refcnt,void * referenced_obj)2112a6d42e7dSPeter Dunlap idm_refcnt_init(idm_refcnt_t *refcnt, void *referenced_obj)
2113a6d42e7dSPeter Dunlap {
2114a6d42e7dSPeter Dunlap bzero(refcnt, sizeof (*refcnt));
2115a6d42e7dSPeter Dunlap idm_refcnt_reset(refcnt);
2116a6d42e7dSPeter Dunlap refcnt->ir_referenced_obj = referenced_obj;
2117a6d42e7dSPeter Dunlap bzero(&refcnt->ir_audit_buf, sizeof (refcnt_audit_buf_t));
2118a6d42e7dSPeter Dunlap refcnt->ir_audit_buf.anb_max_index = REFCNT_AUDIT_BUF_MAX_REC - 1;
2119a6d42e7dSPeter Dunlap mutex_init(&refcnt->ir_mutex, NULL, MUTEX_DEFAULT, NULL);
2120a6d42e7dSPeter Dunlap cv_init(&refcnt->ir_cv, NULL, CV_DEFAULT, NULL);
2121a6d42e7dSPeter Dunlap }
2122a6d42e7dSPeter Dunlap
2123a6d42e7dSPeter Dunlap void
idm_refcnt_destroy(idm_refcnt_t * refcnt)2124a6d42e7dSPeter Dunlap idm_refcnt_destroy(idm_refcnt_t *refcnt)
2125a6d42e7dSPeter Dunlap {
212672cf3143Speter dunlap /*
212772cf3143Speter dunlap * Grab the mutex to there are no other lingering threads holding
212872cf3143Speter dunlap * the mutex before we destroy it (e.g. idm_refcnt_rele just after
212972cf3143Speter dunlap * the refcnt goes to zero if ir_waiting == REF_WAIT_ASYNC)
213072cf3143Speter dunlap */
213172cf3143Speter dunlap mutex_enter(&refcnt->ir_mutex);
2132a6d42e7dSPeter Dunlap ASSERT(refcnt->ir_refcnt == 0);
2133a6d42e7dSPeter Dunlap cv_destroy(&refcnt->ir_cv);
2134a6d42e7dSPeter Dunlap mutex_destroy(&refcnt->ir_mutex);
2135a6d42e7dSPeter Dunlap }
2136a6d42e7dSPeter Dunlap
2137a6d42e7dSPeter Dunlap void
idm_refcnt_reset(idm_refcnt_t * refcnt)2138a6d42e7dSPeter Dunlap idm_refcnt_reset(idm_refcnt_t *refcnt)
2139a6d42e7dSPeter Dunlap {
2140a6d42e7dSPeter Dunlap refcnt->ir_waiting = REF_NOWAIT;
2141a6d42e7dSPeter Dunlap refcnt->ir_refcnt = 0;
2142a6d42e7dSPeter Dunlap }
2143a6d42e7dSPeter Dunlap
2144a6d42e7dSPeter Dunlap void
idm_refcnt_hold(idm_refcnt_t * refcnt)2145a6d42e7dSPeter Dunlap idm_refcnt_hold(idm_refcnt_t *refcnt)
2146a6d42e7dSPeter Dunlap {
2147a6d42e7dSPeter Dunlap /*
2148a6d42e7dSPeter Dunlap * Nothing should take a hold on an object after a call to
2149a6d42e7dSPeter Dunlap * idm_refcnt_wait_ref or idm_refcnd_async_wait_ref
2150a6d42e7dSPeter Dunlap */
2151a6d42e7dSPeter Dunlap ASSERT(refcnt->ir_waiting == REF_NOWAIT);
2152a6d42e7dSPeter Dunlap
2153a6d42e7dSPeter Dunlap mutex_enter(&refcnt->ir_mutex);
2154a6d42e7dSPeter Dunlap refcnt->ir_refcnt++;
2155a6d42e7dSPeter Dunlap REFCNT_AUDIT(refcnt);
2156a6d42e7dSPeter Dunlap mutex_exit(&refcnt->ir_mutex);
2157a6d42e7dSPeter Dunlap }
2158a6d42e7dSPeter Dunlap
2159a6d42e7dSPeter Dunlap static void
idm_refcnt_unref_task(void * refcnt_void)2160a6d42e7dSPeter Dunlap idm_refcnt_unref_task(void *refcnt_void)
2161a6d42e7dSPeter Dunlap {
2162a6d42e7dSPeter Dunlap idm_refcnt_t *refcnt = refcnt_void;
2163a6d42e7dSPeter Dunlap
2164a6d42e7dSPeter Dunlap REFCNT_AUDIT(refcnt);
2165a6d42e7dSPeter Dunlap (*refcnt->ir_cb)(refcnt->ir_referenced_obj);
2166a6d42e7dSPeter Dunlap }
2167a6d42e7dSPeter Dunlap
2168a6d42e7dSPeter Dunlap void
idm_refcnt_rele(idm_refcnt_t * refcnt)2169a6d42e7dSPeter Dunlap idm_refcnt_rele(idm_refcnt_t *refcnt)
2170a6d42e7dSPeter Dunlap {
2171a6d42e7dSPeter Dunlap mutex_enter(&refcnt->ir_mutex);
2172a6d42e7dSPeter Dunlap ASSERT(refcnt->ir_refcnt > 0);
2173a6d42e7dSPeter Dunlap refcnt->ir_refcnt--;
2174a6d42e7dSPeter Dunlap REFCNT_AUDIT(refcnt);
2175a6d42e7dSPeter Dunlap if (refcnt->ir_waiting == REF_NOWAIT) {
2176a6d42e7dSPeter Dunlap /* No one is waiting on this object */
2177a6d42e7dSPeter Dunlap mutex_exit(&refcnt->ir_mutex);
2178a6d42e7dSPeter Dunlap return;
2179a6d42e7dSPeter Dunlap }
2180a6d42e7dSPeter Dunlap
2181a6d42e7dSPeter Dunlap /*
2182a6d42e7dSPeter Dunlap * Someone is waiting for this object to go idle so check if
2183a6d42e7dSPeter Dunlap * refcnt is 0. Waiting on an object then later grabbing another
2184a6d42e7dSPeter Dunlap * reference is not allowed so we don't need to handle that case.
2185a6d42e7dSPeter Dunlap */
2186a6d42e7dSPeter Dunlap if (refcnt->ir_refcnt == 0) {
2187a6d42e7dSPeter Dunlap if (refcnt->ir_waiting == REF_WAIT_ASYNC) {
2188a6d42e7dSPeter Dunlap if (taskq_dispatch(idm.idm_global_taskq,
2189fc8ae2ecSToomas Soome &idm_refcnt_unref_task, refcnt, TQ_SLEEP) ==
2190fc8ae2ecSToomas Soome TASKQID_INVALID) {
2191a6d42e7dSPeter Dunlap cmn_err(CE_WARN,
2192a6d42e7dSPeter Dunlap "idm_refcnt_rele: Couldn't dispatch task");
2193a6d42e7dSPeter Dunlap }
2194a6d42e7dSPeter Dunlap } else if (refcnt->ir_waiting == REF_WAIT_SYNC) {
2195a6d42e7dSPeter Dunlap cv_signal(&refcnt->ir_cv);
2196a6d42e7dSPeter Dunlap }
2197a6d42e7dSPeter Dunlap }
2198a6d42e7dSPeter Dunlap mutex_exit(&refcnt->ir_mutex);
2199a6d42e7dSPeter Dunlap }
2200a6d42e7dSPeter Dunlap
2201a6d42e7dSPeter Dunlap void
idm_refcnt_rele_and_destroy(idm_refcnt_t * refcnt,idm_refcnt_cb_t * cb_func)2202a6d42e7dSPeter Dunlap idm_refcnt_rele_and_destroy(idm_refcnt_t *refcnt, idm_refcnt_cb_t *cb_func)
2203a6d42e7dSPeter Dunlap {
2204a6d42e7dSPeter Dunlap mutex_enter(&refcnt->ir_mutex);
2205a6d42e7dSPeter Dunlap ASSERT(refcnt->ir_refcnt > 0);
2206a6d42e7dSPeter Dunlap refcnt->ir_refcnt--;
2207a6d42e7dSPeter Dunlap REFCNT_AUDIT(refcnt);
2208a6d42e7dSPeter Dunlap
2209a6d42e7dSPeter Dunlap /*
2210a6d42e7dSPeter Dunlap * Someone is waiting for this object to go idle so check if
2211a6d42e7dSPeter Dunlap * refcnt is 0. Waiting on an object then later grabbing another
2212a6d42e7dSPeter Dunlap * reference is not allowed so we don't need to handle that case.
2213a6d42e7dSPeter Dunlap */
2214a6d42e7dSPeter Dunlap if (refcnt->ir_refcnt == 0) {
2215a6d42e7dSPeter Dunlap refcnt->ir_cb = cb_func;
2216a6d42e7dSPeter Dunlap refcnt->ir_waiting = REF_WAIT_ASYNC;
2217a6d42e7dSPeter Dunlap if (taskq_dispatch(idm.idm_global_taskq,
22188e718be9SToomas Soome &idm_refcnt_unref_task, refcnt, TQ_SLEEP) ==
22198e718be9SToomas Soome TASKQID_INVALID) {
2220a6d42e7dSPeter Dunlap cmn_err(CE_WARN,
2221a6d42e7dSPeter Dunlap "idm_refcnt_rele: Couldn't dispatch task");
2222a6d42e7dSPeter Dunlap }
2223a6d42e7dSPeter Dunlap }
2224a6d42e7dSPeter Dunlap mutex_exit(&refcnt->ir_mutex);
2225a6d42e7dSPeter Dunlap }
2226a6d42e7dSPeter Dunlap
2227a6d42e7dSPeter Dunlap void
idm_refcnt_wait_ref(idm_refcnt_t * refcnt)2228a6d42e7dSPeter Dunlap idm_refcnt_wait_ref(idm_refcnt_t *refcnt)
2229a6d42e7dSPeter Dunlap {
2230a6d42e7dSPeter Dunlap mutex_enter(&refcnt->ir_mutex);
2231a6d42e7dSPeter Dunlap refcnt->ir_waiting = REF_WAIT_SYNC;
2232a6d42e7dSPeter Dunlap REFCNT_AUDIT(refcnt);
2233a6d42e7dSPeter Dunlap while (refcnt->ir_refcnt != 0)
2234a6d42e7dSPeter Dunlap cv_wait(&refcnt->ir_cv, &refcnt->ir_mutex);
2235a6d42e7dSPeter Dunlap mutex_exit(&refcnt->ir_mutex);
2236a6d42e7dSPeter Dunlap }
2237a6d42e7dSPeter Dunlap
2238a6d42e7dSPeter Dunlap void
idm_refcnt_async_wait_ref(idm_refcnt_t * refcnt,idm_refcnt_cb_t * cb_func)2239a6d42e7dSPeter Dunlap idm_refcnt_async_wait_ref(idm_refcnt_t *refcnt, idm_refcnt_cb_t *cb_func)
2240a6d42e7dSPeter Dunlap {
2241a6d42e7dSPeter Dunlap mutex_enter(&refcnt->ir_mutex);
2242a6d42e7dSPeter Dunlap refcnt->ir_waiting = REF_WAIT_ASYNC;
2243a6d42e7dSPeter Dunlap refcnt->ir_cb = cb_func;
2244a6d42e7dSPeter Dunlap REFCNT_AUDIT(refcnt);
2245a6d42e7dSPeter Dunlap /*
2246a6d42e7dSPeter Dunlap * It's possible we don't have any references. To make things easier
2247a6d42e7dSPeter Dunlap * on the caller use a taskq to call the callback instead of
2248a6d42e7dSPeter Dunlap * calling it synchronously
2249a6d42e7dSPeter Dunlap */
2250a6d42e7dSPeter Dunlap if (refcnt->ir_refcnt == 0) {
2251a6d42e7dSPeter Dunlap if (taskq_dispatch(idm.idm_global_taskq,
2252fc8ae2ecSToomas Soome &idm_refcnt_unref_task, refcnt, TQ_SLEEP) ==
2253fc8ae2ecSToomas Soome TASKQID_INVALID) {
2254a6d42e7dSPeter Dunlap cmn_err(CE_WARN,
2255a6d42e7dSPeter Dunlap "idm_refcnt_async_wait_ref: "
2256a6d42e7dSPeter Dunlap "Couldn't dispatch task");
2257a6d42e7dSPeter Dunlap }
2258a6d42e7dSPeter Dunlap }
2259a6d42e7dSPeter Dunlap mutex_exit(&refcnt->ir_mutex);
2260a6d42e7dSPeter Dunlap }
2261a6d42e7dSPeter Dunlap
2262a6d42e7dSPeter Dunlap void
idm_refcnt_destroy_unref_obj(idm_refcnt_t * refcnt,idm_refcnt_cb_t * cb_func)2263a6d42e7dSPeter Dunlap idm_refcnt_destroy_unref_obj(idm_refcnt_t *refcnt,
2264a6d42e7dSPeter Dunlap idm_refcnt_cb_t *cb_func)
2265a6d42e7dSPeter Dunlap {
2266a6d42e7dSPeter Dunlap mutex_enter(&refcnt->ir_mutex);
2267a6d42e7dSPeter Dunlap if (refcnt->ir_refcnt == 0) {
2268a6d42e7dSPeter Dunlap mutex_exit(&refcnt->ir_mutex);
2269a6d42e7dSPeter Dunlap (*cb_func)(refcnt->ir_referenced_obj);
2270a6d42e7dSPeter Dunlap return;
2271a6d42e7dSPeter Dunlap }
2272a6d42e7dSPeter Dunlap mutex_exit(&refcnt->ir_mutex);
2273a6d42e7dSPeter Dunlap }
2274a6d42e7dSPeter Dunlap
227561dfa509SRick McNeal /*
227661dfa509SRick McNeal * used to determine the status of the refcnt.
227761dfa509SRick McNeal *
227861dfa509SRick McNeal * if refcnt is 0 return is 0
227961dfa509SRick McNeal * if refcnt is negative return is -1
228061dfa509SRick McNeal * if refcnt > 0 and no waiters return is 1
228161dfa509SRick McNeal * if refcnt > 0 and waiters return is 2
228261dfa509SRick McNeal */
228361dfa509SRick McNeal int
idm_refcnt_is_held(idm_refcnt_t * refcnt)228461dfa509SRick McNeal idm_refcnt_is_held(idm_refcnt_t *refcnt)
228561dfa509SRick McNeal {
228661dfa509SRick McNeal if (refcnt->ir_refcnt < 0)
228761dfa509SRick McNeal return (-1);
228861dfa509SRick McNeal
228961dfa509SRick McNeal if (refcnt->ir_refcnt == 0)
229061dfa509SRick McNeal return (0);
229161dfa509SRick McNeal
229261dfa509SRick McNeal if (refcnt->ir_waiting == REF_NOWAIT && refcnt->ir_refcnt > 0)
229361dfa509SRick McNeal return (1);
229461dfa509SRick McNeal
229561dfa509SRick McNeal return (2);
229661dfa509SRick McNeal }
229761dfa509SRick McNeal
2298a6d42e7dSPeter Dunlap void
idm_conn_hold(idm_conn_t * ic)2299a6d42e7dSPeter Dunlap idm_conn_hold(idm_conn_t *ic)
2300a6d42e7dSPeter Dunlap {
2301a6d42e7dSPeter Dunlap idm_refcnt_hold(&ic->ic_refcnt);
2302a6d42e7dSPeter Dunlap }
2303a6d42e7dSPeter Dunlap
2304a6d42e7dSPeter Dunlap void
idm_conn_rele(idm_conn_t * ic)2305a6d42e7dSPeter Dunlap idm_conn_rele(idm_conn_t *ic)
2306a6d42e7dSPeter Dunlap {
2307a6d42e7dSPeter Dunlap idm_refcnt_rele(&ic->ic_refcnt);
2308a6d42e7dSPeter Dunlap }
2309a6d42e7dSPeter Dunlap
2310a668b114SPriya Krishnan void
idm_conn_set_target_name(idm_conn_t * ic,char * target_name)2311a668b114SPriya Krishnan idm_conn_set_target_name(idm_conn_t *ic, char *target_name)
2312a668b114SPriya Krishnan {
2313a668b114SPriya Krishnan (void) strlcpy(ic->ic_target_name, target_name, ISCSI_MAX_NAME_LEN + 1);
2314a668b114SPriya Krishnan }
2315a668b114SPriya Krishnan
2316a668b114SPriya Krishnan void
idm_conn_set_initiator_name(idm_conn_t * ic,char * initiator_name)2317a668b114SPriya Krishnan idm_conn_set_initiator_name(idm_conn_t *ic, char *initiator_name)
2318a668b114SPriya Krishnan {
2319a668b114SPriya Krishnan (void) strlcpy(ic->ic_initiator_name, initiator_name,
2320a668b114SPriya Krishnan ISCSI_MAX_NAME_LEN + 1);
2321a668b114SPriya Krishnan }
2322a668b114SPriya Krishnan
2323a668b114SPriya Krishnan void
idm_conn_set_isid(idm_conn_t * ic,uint8_t isid[ISCSI_ISID_LEN])2324a668b114SPriya Krishnan idm_conn_set_isid(idm_conn_t *ic, uint8_t isid[ISCSI_ISID_LEN])
2325a668b114SPriya Krishnan {
2326a668b114SPriya Krishnan (void) snprintf(ic->ic_isid, ISCSI_MAX_ISID_LEN + 1,
2327a668b114SPriya Krishnan "%02x%02x%02x%02x%02x%02x",
2328a668b114SPriya Krishnan isid[0], isid[1], isid[2], isid[3], isid[4], isid[5]);
2329a668b114SPriya Krishnan }
2330a6d42e7dSPeter Dunlap
2331a6d42e7dSPeter Dunlap static int
_idm_init(void)2332a6d42e7dSPeter Dunlap _idm_init(void)
2333a6d42e7dSPeter Dunlap {
2334a6d42e7dSPeter Dunlap /* Initialize the rwlock for the taskid table */
2335a6d42e7dSPeter Dunlap rw_init(&idm.idm_taskid_table_lock, NULL, RW_DRIVER, NULL);
2336a6d42e7dSPeter Dunlap
2337a6d42e7dSPeter Dunlap /* Initialize the global mutex and taskq */
2338a6d42e7dSPeter Dunlap mutex_init(&idm.idm_global_mutex, NULL, MUTEX_DEFAULT, NULL);
2339a6d42e7dSPeter Dunlap
2340a6d42e7dSPeter Dunlap cv_init(&idm.idm_tgt_svc_cv, NULL, CV_DEFAULT, NULL);
2341a6d42e7dSPeter Dunlap cv_init(&idm.idm_wd_cv, NULL, CV_DEFAULT, NULL);
2342a6d42e7dSPeter Dunlap
234330e7468fSPeter Dunlap /*
234430e7468fSPeter Dunlap * The maximum allocation needs to be high here since there can be
234530e7468fSPeter Dunlap * many concurrent tasks using the global taskq.
234630e7468fSPeter Dunlap */
2347a6d42e7dSPeter Dunlap idm.idm_global_taskq = taskq_create("idm_global_taskq", 1, minclsyspri,
234830e7468fSPeter Dunlap 128, 16384, TASKQ_PREPOPULATE);
2349a6d42e7dSPeter Dunlap if (idm.idm_global_taskq == NULL) {
2350a6d42e7dSPeter Dunlap cv_destroy(&idm.idm_wd_cv);
2351a6d42e7dSPeter Dunlap cv_destroy(&idm.idm_tgt_svc_cv);
2352a6d42e7dSPeter Dunlap mutex_destroy(&idm.idm_global_mutex);
2353a6d42e7dSPeter Dunlap rw_destroy(&idm.idm_taskid_table_lock);
2354a6d42e7dSPeter Dunlap return (ENOMEM);
2355a6d42e7dSPeter Dunlap }
2356a6d42e7dSPeter Dunlap
2357a41f9819SJames Moore /* Start watchdog thread */
2358a6d42e7dSPeter Dunlap idm.idm_wd_thread = thread_create(NULL, 0,
2359a6d42e7dSPeter Dunlap idm_wd_thread, NULL, 0, &p0, TS_RUN, minclsyspri);
2360a6d42e7dSPeter Dunlap if (idm.idm_wd_thread == NULL) {
2361a6d42e7dSPeter Dunlap /* Couldn't create the watchdog thread */
2362a6d42e7dSPeter Dunlap taskq_destroy(idm.idm_global_taskq);
2363a6d42e7dSPeter Dunlap cv_destroy(&idm.idm_wd_cv);
2364a6d42e7dSPeter Dunlap cv_destroy(&idm.idm_tgt_svc_cv);
2365a6d42e7dSPeter Dunlap mutex_destroy(&idm.idm_global_mutex);
2366a6d42e7dSPeter Dunlap rw_destroy(&idm.idm_taskid_table_lock);
2367a6d42e7dSPeter Dunlap return (ENOMEM);
2368a6d42e7dSPeter Dunlap }
2369a6d42e7dSPeter Dunlap
2370a41f9819SJames Moore /* Pause until the watchdog thread is running */
2371a6d42e7dSPeter Dunlap mutex_enter(&idm.idm_global_mutex);
2372a6d42e7dSPeter Dunlap while (!idm.idm_wd_thread_running)
2373a6d42e7dSPeter Dunlap cv_wait(&idm.idm_wd_cv, &idm.idm_global_mutex);
2374a6d42e7dSPeter Dunlap mutex_exit(&idm.idm_global_mutex);
2375a6d42e7dSPeter Dunlap
2376a6d42e7dSPeter Dunlap /*
2377a6d42e7dSPeter Dunlap * Allocate the task ID table and set "next" to 0.
2378a6d42e7dSPeter Dunlap */
2379a6d42e7dSPeter Dunlap
2380a6d42e7dSPeter Dunlap idm.idm_taskid_max = idm_max_taskids;
2381a6d42e7dSPeter Dunlap idm.idm_taskid_table = (idm_task_t **)
2382a6d42e7dSPeter Dunlap kmem_zalloc(idm.idm_taskid_max * sizeof (idm_task_t *), KM_SLEEP);
2383a6d42e7dSPeter Dunlap idm.idm_taskid_next = 0;
2384a6d42e7dSPeter Dunlap
2385a6d42e7dSPeter Dunlap /* Create the global buffer and task kmem caches */
2386a6d42e7dSPeter Dunlap idm.idm_buf_cache = kmem_cache_create("idm_buf_cache",
2387a6d42e7dSPeter Dunlap sizeof (idm_buf_t), 8, NULL, NULL, NULL, NULL, NULL, KM_SLEEP);
2388a6d42e7dSPeter Dunlap
2389a6d42e7dSPeter Dunlap /*
2390a6d42e7dSPeter Dunlap * Note, we're explicitly allocating an additional iSER header-
2391a6d42e7dSPeter Dunlap * sized chunk for each of these elements. See idm_task_constructor().
2392a6d42e7dSPeter Dunlap */
2393a6d42e7dSPeter Dunlap idm.idm_task_cache = kmem_cache_create("idm_task_cache",
2394a6d42e7dSPeter Dunlap sizeof (idm_task_t) + IDM_TRANSPORT_HEADER_LENGTH, 8,
2395a6d42e7dSPeter Dunlap &idm_task_constructor, &idm_task_destructor,
2396a6d42e7dSPeter Dunlap NULL, NULL, NULL, KM_SLEEP);
2397a6d42e7dSPeter Dunlap
2398a6d42e7dSPeter Dunlap /* Create the service and connection context lists */
2399a6d42e7dSPeter Dunlap list_create(&idm.idm_tgt_svc_list, sizeof (idm_svc_t),
2400a6d42e7dSPeter Dunlap offsetof(idm_svc_t, is_list_node));
2401a6d42e7dSPeter Dunlap list_create(&idm.idm_tgt_conn_list, sizeof (idm_conn_t),
2402a6d42e7dSPeter Dunlap offsetof(idm_conn_t, ic_list_node));
2403a6d42e7dSPeter Dunlap list_create(&idm.idm_ini_conn_list, sizeof (idm_conn_t),
2404a6d42e7dSPeter Dunlap offsetof(idm_conn_t, ic_list_node));
2405a6d42e7dSPeter Dunlap
2406a6d42e7dSPeter Dunlap /* Initialize the native sockets transport */
2407a6d42e7dSPeter Dunlap idm_so_init(&idm_transport_list[IDM_TRANSPORT_TYPE_SOCKETS]);
2408a6d42e7dSPeter Dunlap
2409a6d42e7dSPeter Dunlap /* Create connection ID pool */
2410a6d42e7dSPeter Dunlap (void) idm_idpool_create(&idm.idm_conn_id_pool);
2411a6d42e7dSPeter Dunlap
2412a6d42e7dSPeter Dunlap return (DDI_SUCCESS);
2413a6d42e7dSPeter Dunlap }
2414a6d42e7dSPeter Dunlap
2415a6d42e7dSPeter Dunlap static int
_idm_fini(void)2416a6d42e7dSPeter Dunlap _idm_fini(void)
2417a6d42e7dSPeter Dunlap {
2418a6d42e7dSPeter Dunlap if (!list_is_empty(&idm.idm_ini_conn_list) ||
2419a6d42e7dSPeter Dunlap !list_is_empty(&idm.idm_tgt_conn_list) ||
2420a6d42e7dSPeter Dunlap !list_is_empty(&idm.idm_tgt_svc_list)) {
2421a6d42e7dSPeter Dunlap return (EBUSY);
2422a6d42e7dSPeter Dunlap }
2423a6d42e7dSPeter Dunlap
2424a6d42e7dSPeter Dunlap mutex_enter(&idm.idm_global_mutex);
2425a6d42e7dSPeter Dunlap idm.idm_wd_thread_running = B_FALSE;
2426a6d42e7dSPeter Dunlap cv_signal(&idm.idm_wd_cv);
2427a6d42e7dSPeter Dunlap mutex_exit(&idm.idm_global_mutex);
2428a6d42e7dSPeter Dunlap
2429a6d42e7dSPeter Dunlap thread_join(idm.idm_wd_thread_did);
2430a6d42e7dSPeter Dunlap
2431a6d42e7dSPeter Dunlap idm_idpool_destroy(&idm.idm_conn_id_pool);
243230e7468fSPeter Dunlap
243330e7468fSPeter Dunlap /* Close any LDI handles we have open on transport drivers */
243430e7468fSPeter Dunlap mutex_enter(&idm.idm_global_mutex);
243530e7468fSPeter Dunlap idm_transport_teardown();
243630e7468fSPeter Dunlap mutex_exit(&idm.idm_global_mutex);
243730e7468fSPeter Dunlap
243830e7468fSPeter Dunlap /* Teardown the native sockets transport */
2439a6d42e7dSPeter Dunlap idm_so_fini();
244030e7468fSPeter Dunlap
2441a6d42e7dSPeter Dunlap list_destroy(&idm.idm_ini_conn_list);
2442a6d42e7dSPeter Dunlap list_destroy(&idm.idm_tgt_conn_list);
2443a6d42e7dSPeter Dunlap list_destroy(&idm.idm_tgt_svc_list);
2444a6d42e7dSPeter Dunlap kmem_cache_destroy(idm.idm_task_cache);
2445a6d42e7dSPeter Dunlap kmem_cache_destroy(idm.idm_buf_cache);
2446a6d42e7dSPeter Dunlap kmem_free(idm.idm_taskid_table,
2447a6d42e7dSPeter Dunlap idm.idm_taskid_max * sizeof (idm_task_t *));
2448a6d42e7dSPeter Dunlap mutex_destroy(&idm.idm_global_mutex);
2449a6d42e7dSPeter Dunlap cv_destroy(&idm.idm_wd_cv);
2450a6d42e7dSPeter Dunlap cv_destroy(&idm.idm_tgt_svc_cv);
2451a6d42e7dSPeter Dunlap rw_destroy(&idm.idm_taskid_table_lock);
2452a6d42e7dSPeter Dunlap
2453a6d42e7dSPeter Dunlap return (0);
2454a6d42e7dSPeter Dunlap }
2455