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
945