xref: /illumos-gate/usr/src/uts/common/io/idm/idm_impl.c (revision 30e7468f)
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 
22a6d42e7dSPeter Dunlap /*
23*30e7468fSPeter Dunlap  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24a6d42e7dSPeter Dunlap  * Use is subject to license terms.
25a6d42e7dSPeter Dunlap  */
26a6d42e7dSPeter Dunlap 
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/cpuvar.h>
32a6d42e7dSPeter Dunlap 
33a6d42e7dSPeter Dunlap #include <sys/socket.h>
34a6d42e7dSPeter Dunlap #include <sys/strsubr.h>
35a6d42e7dSPeter Dunlap #include <sys/socketvar.h>
36a6d42e7dSPeter Dunlap #include <sys/sysmacros.h>
37a6d42e7dSPeter Dunlap 
38a6d42e7dSPeter Dunlap #include <sys/idm/idm.h>
39a6d42e7dSPeter Dunlap #include <sys/idm/idm_so.h>
40a6d42e7dSPeter Dunlap 
41a6d42e7dSPeter Dunlap extern idm_transport_t  idm_transport_list[];
42a6d42e7dSPeter Dunlap 
43a6d42e7dSPeter Dunlap void
44a6d42e7dSPeter Dunlap idm_pdu_rx(idm_conn_t *ic, idm_pdu_t *pdu)
45a6d42e7dSPeter Dunlap {
46a6d42e7dSPeter Dunlap 	iscsi_async_evt_hdr_t *async_evt;
47a6d42e7dSPeter Dunlap 
48a6d42e7dSPeter Dunlap 	/*
49a6d42e7dSPeter Dunlap 	 * If we are in full-featured mode then route SCSI-related
50a6d42e7dSPeter Dunlap 	 * commands to the appropriate function vector
51a6d42e7dSPeter Dunlap 	 */
52a6d42e7dSPeter Dunlap 	ic->ic_timestamp = ddi_get_lbolt();
53a6d42e7dSPeter Dunlap 	mutex_enter(&ic->ic_state_mutex);
54a6d42e7dSPeter Dunlap 	if (ic->ic_ffp && ic->ic_pdu_events == 0) {
55a6d42e7dSPeter Dunlap 		mutex_exit(&ic->ic_state_mutex);
56a6d42e7dSPeter Dunlap 
57a6d42e7dSPeter Dunlap 		if (idm_pdu_rx_forward_ffp(ic, pdu) == B_TRUE) {
58a6d42e7dSPeter Dunlap 			/* Forwarded SCSI-related commands */
59a6d42e7dSPeter Dunlap 			return;
60a6d42e7dSPeter Dunlap 		}
61a6d42e7dSPeter Dunlap 		mutex_enter(&ic->ic_state_mutex);
62a6d42e7dSPeter Dunlap 	}
63a6d42e7dSPeter Dunlap 
64a6d42e7dSPeter Dunlap 	/*
65a6d42e7dSPeter Dunlap 	 * If we get here with a SCSI-related PDU then we are not in
66a6d42e7dSPeter Dunlap 	 * full-feature mode and the PDU is a protocol error (SCSI command
67a6d42e7dSPeter Dunlap 	 * PDU's may sometimes be an exception, see below).  All
68a6d42e7dSPeter Dunlap 	 * non-SCSI PDU's get treated them the same regardless of whether
69a6d42e7dSPeter Dunlap 	 * we are in full-feature mode.
70a6d42e7dSPeter Dunlap 	 *
71a6d42e7dSPeter Dunlap 	 * Look at the opcode and in some cases the PDU status and
72a6d42e7dSPeter Dunlap 	 * determine the appropriate event to send to the connection
73a6d42e7dSPeter Dunlap 	 * state machine.  Generate the event, passing the PDU as data.
74a6d42e7dSPeter Dunlap 	 * If the current connection state allows reception of the event
75a6d42e7dSPeter Dunlap 	 * the PDU will be submitted to the IDM client for processing,
76a6d42e7dSPeter Dunlap 	 * otherwise the PDU will be dropped.
77a6d42e7dSPeter Dunlap 	 */
78a6d42e7dSPeter Dunlap 	switch (IDM_PDU_OPCODE(pdu)) {
79a6d42e7dSPeter Dunlap 	case ISCSI_OP_LOGIN_CMD:
80a6d42e7dSPeter Dunlap 		idm_conn_rx_pdu_event(ic, CE_LOGIN_RCV, (uintptr_t)pdu);
81a6d42e7dSPeter Dunlap 		break;
82a6d42e7dSPeter Dunlap 	case ISCSI_OP_LOGIN_RSP:
83a6d42e7dSPeter Dunlap 		idm_parse_login_rsp(ic, pdu, /* RX */ B_TRUE);
84a6d42e7dSPeter Dunlap 		break;
85a6d42e7dSPeter Dunlap 	case ISCSI_OP_LOGOUT_CMD:
86a6d42e7dSPeter Dunlap 		idm_parse_logout_req(ic, pdu, /* RX */ B_TRUE);
87a6d42e7dSPeter Dunlap 		break;
88a6d42e7dSPeter Dunlap 	case ISCSI_OP_LOGOUT_RSP:
89a6d42e7dSPeter Dunlap 		idm_parse_logout_rsp(ic, pdu, /* RX */ B_TRUE);
90a6d42e7dSPeter Dunlap 		break;
91a6d42e7dSPeter Dunlap 	case ISCSI_OP_ASYNC_EVENT:
92a6d42e7dSPeter Dunlap 		async_evt = (iscsi_async_evt_hdr_t *)pdu->isp_hdr;
93*30e7468fSPeter Dunlap 		switch (async_evt->async_event) {
94a6d42e7dSPeter Dunlap 		case ISCSI_ASYNC_EVENT_REQUEST_LOGOUT:
95a6d42e7dSPeter Dunlap 			idm_conn_rx_pdu_event(ic, CE_ASYNC_LOGOUT_RCV,
96a6d42e7dSPeter Dunlap 			    (uintptr_t)pdu);
97a6d42e7dSPeter Dunlap 			break;
98a6d42e7dSPeter Dunlap 		case ISCSI_ASYNC_EVENT_DROPPING_CONNECTION:
99a6d42e7dSPeter Dunlap 			idm_conn_rx_pdu_event(ic, CE_ASYNC_DROP_CONN_RCV,
100a6d42e7dSPeter Dunlap 			    (uintptr_t)pdu);
101a6d42e7dSPeter Dunlap 			break;
102a6d42e7dSPeter Dunlap 		case ISCSI_ASYNC_EVENT_DROPPING_ALL_CONNECTIONS:
103a6d42e7dSPeter Dunlap 			idm_conn_rx_pdu_event(ic, CE_ASYNC_DROP_ALL_CONN_RCV,
104a6d42e7dSPeter Dunlap 			    (uintptr_t)pdu);
105a6d42e7dSPeter Dunlap 			break;
106a6d42e7dSPeter Dunlap 		case ISCSI_ASYNC_EVENT_SCSI_EVENT:
107a6d42e7dSPeter Dunlap 		case ISCSI_ASYNC_EVENT_PARAM_NEGOTIATION:
108a6d42e7dSPeter Dunlap 		default:
109a6d42e7dSPeter Dunlap 			idm_conn_rx_pdu_event(ic, CE_MISC_RX,
110a6d42e7dSPeter Dunlap 			    (uintptr_t)pdu);
111a6d42e7dSPeter Dunlap 			break;
112a6d42e7dSPeter Dunlap 		}
113a6d42e7dSPeter Dunlap 		break;
114a6d42e7dSPeter Dunlap 	case ISCSI_OP_SCSI_CMD:
115a6d42e7dSPeter Dunlap 		/*
116a6d42e7dSPeter Dunlap 		 * Consider this scenario:  We are a target connection
117a6d42e7dSPeter Dunlap 		 * in "in login" state and a "login success sent" event has
118a6d42e7dSPeter Dunlap 		 * been generated but not yet handled.  Since we've sent
119a6d42e7dSPeter Dunlap 		 * the login response but we haven't actually transitioned
120a6d42e7dSPeter Dunlap 		 * to FFP mode we might conceivably receive a SCSI command
121a6d42e7dSPeter Dunlap 		 * from the initiator before we are ready.  We are actually
122a6d42e7dSPeter Dunlap 		 * in FFP we just don't know it yet -- to address this we
123a6d42e7dSPeter Dunlap 		 * can generate an event corresponding to the SCSI command.
124a6d42e7dSPeter Dunlap 		 * At the point when the event is handled by the state
125a6d42e7dSPeter Dunlap 		 * machine the login request will have been handled and we
126a6d42e7dSPeter Dunlap 		 * should be in FFP.  If we are not in FFP by that time
127a6d42e7dSPeter Dunlap 		 * we can reject the SCSI command with a protocol error.
128a6d42e7dSPeter Dunlap 		 *
129a6d42e7dSPeter Dunlap 		 * This scenario only applies to the target.
130a6d42e7dSPeter Dunlap 		 */
131a6d42e7dSPeter Dunlap 	case ISCSI_OP_SCSI_DATA:
132a6d42e7dSPeter Dunlap 	case ISCSI_OP_SCSI_DATA_RSP:
133a6d42e7dSPeter Dunlap 	case ISCSI_OP_RTT_RSP:
134a6d42e7dSPeter Dunlap 	case ISCSI_OP_SNACK_CMD:
135a6d42e7dSPeter Dunlap 	case ISCSI_OP_NOOP_IN:
136a6d42e7dSPeter Dunlap 	case ISCSI_OP_NOOP_OUT:
137a6d42e7dSPeter Dunlap 	case ISCSI_OP_TEXT_CMD:
138a6d42e7dSPeter Dunlap 	case ISCSI_OP_TEXT_RSP:
139a6d42e7dSPeter Dunlap 	case ISCSI_OP_REJECT_MSG:
140a6d42e7dSPeter Dunlap 	case ISCSI_OP_SCSI_TASK_MGT_MSG:
141a6d42e7dSPeter Dunlap 	case ISCSI_OP_SCSI_TASK_MGT_RSP:
142a6d42e7dSPeter Dunlap 		/* Validate received PDU against current state */
143a6d42e7dSPeter Dunlap 		idm_conn_rx_pdu_event(ic, CE_MISC_RX,
144a6d42e7dSPeter Dunlap 		    (uintptr_t)pdu);
145a6d42e7dSPeter Dunlap 		break;
146a6d42e7dSPeter Dunlap 	}
147a6d42e7dSPeter Dunlap 	mutex_exit(&ic->ic_state_mutex);
148a6d42e7dSPeter Dunlap }
149a6d42e7dSPeter Dunlap 
150a6d42e7dSPeter Dunlap void
151a6d42e7dSPeter Dunlap idm_pdu_tx_forward(idm_conn_t *ic, idm_pdu_t *pdu)
152a6d42e7dSPeter Dunlap {
153a6d42e7dSPeter Dunlap 	(*ic->ic_transport_ops->it_tx_pdu)(ic, pdu);
154a6d42e7dSPeter Dunlap }
155a6d42e7dSPeter Dunlap 
156a6d42e7dSPeter Dunlap boolean_t
157a6d42e7dSPeter Dunlap idm_pdu_rx_forward_ffp(idm_conn_t *ic, idm_pdu_t *pdu)
158a6d42e7dSPeter Dunlap {
159a6d42e7dSPeter Dunlap 	/*
160a6d42e7dSPeter Dunlap 	 * If this is an FFP request, call the appropriate handler
161a6d42e7dSPeter Dunlap 	 * and return B_TRUE, otherwise return B_FALSE.
162a6d42e7dSPeter Dunlap 	 */
163a6d42e7dSPeter Dunlap 	switch (IDM_PDU_OPCODE(pdu)) {
164a6d42e7dSPeter Dunlap 	case ISCSI_OP_SCSI_CMD:
165a6d42e7dSPeter Dunlap 		(*ic->ic_conn_ops.icb_rx_scsi_cmd)(ic, pdu);
166a6d42e7dSPeter Dunlap 		return (B_TRUE);
167a6d42e7dSPeter Dunlap 	case ISCSI_OP_SCSI_RSP:
168a6d42e7dSPeter Dunlap 		(*ic->ic_conn_ops.icb_rx_scsi_rsp)(ic, pdu);
169a6d42e7dSPeter Dunlap 		return (B_TRUE);
170a6d42e7dSPeter Dunlap 	case ISCSI_OP_SCSI_DATA:
171a6d42e7dSPeter Dunlap 		(*ic->ic_transport_ops->it_rx_dataout)(ic, pdu);
172a6d42e7dSPeter Dunlap 		return (B_TRUE);
173a6d42e7dSPeter Dunlap 	case ISCSI_OP_SCSI_DATA_RSP:
174a6d42e7dSPeter Dunlap 		(*ic->ic_transport_ops->it_rx_datain)(ic, pdu);
175a6d42e7dSPeter Dunlap 		return (B_TRUE);
176a6d42e7dSPeter Dunlap 	case ISCSI_OP_RTT_RSP:
177a6d42e7dSPeter Dunlap 		(*ic->ic_transport_ops->it_rx_rtt)(ic, pdu);
178a6d42e7dSPeter Dunlap 		return (B_TRUE);
179a6d42e7dSPeter Dunlap 	case ISCSI_OP_SCSI_TASK_MGT_MSG:
180a6d42e7dSPeter Dunlap 	case ISCSI_OP_SCSI_TASK_MGT_RSP:
181a6d42e7dSPeter Dunlap 	case ISCSI_OP_TEXT_CMD:
182a6d42e7dSPeter Dunlap 	case ISCSI_OP_TEXT_RSP:
183a6d42e7dSPeter Dunlap 	case ISCSI_OP_NOOP_OUT:
184a6d42e7dSPeter Dunlap 	case ISCSI_OP_NOOP_IN:
185a6d42e7dSPeter Dunlap 		(*ic->ic_conn_ops.icb_rx_misc)(ic, pdu);
186a6d42e7dSPeter Dunlap 		return (B_TRUE);
187a6d42e7dSPeter Dunlap 	default:
188a6d42e7dSPeter Dunlap 		return (B_FALSE);
189a6d42e7dSPeter Dunlap 	}
190a6d42e7dSPeter Dunlap 	/*NOTREACHED*/
191a6d42e7dSPeter Dunlap }
192a6d42e7dSPeter Dunlap 
193a6d42e7dSPeter Dunlap void
194a6d42e7dSPeter Dunlap idm_pdu_rx_forward(idm_conn_t *ic, idm_pdu_t *pdu)
195a6d42e7dSPeter Dunlap {
196a6d42e7dSPeter Dunlap 	/*
197a6d42e7dSPeter Dunlap 	 * Some PDU's specific to FFP get special handling.  This function
198a6d42e7dSPeter Dunlap 	 * will normally never be called in FFP with an FFP PDU since this
199a6d42e7dSPeter Dunlap 	 * is a slow path but in can happen on the target side during
200a6d42e7dSPeter Dunlap 	 * the transition to FFP.  We primarily call
201a6d42e7dSPeter Dunlap 	 * idm_pdu_rx_forward_ffp here to avoid code duplication.
202a6d42e7dSPeter Dunlap 	 */
203a6d42e7dSPeter Dunlap 	if (idm_pdu_rx_forward_ffp(ic, pdu) == B_FALSE) {
204a6d42e7dSPeter Dunlap 		/*
205a6d42e7dSPeter Dunlap 		 * Non-FFP PDU, use generic RC handler
206a6d42e7dSPeter Dunlap 		 */
207a6d42e7dSPeter Dunlap 		(*ic->ic_conn_ops.icb_rx_misc)(ic, pdu);
208a6d42e7dSPeter Dunlap 	}
209a6d42e7dSPeter Dunlap }
210a6d42e7dSPeter Dunlap 
211a6d42e7dSPeter Dunlap void
212a6d42e7dSPeter Dunlap idm_parse_login_rsp(idm_conn_t *ic, idm_pdu_t *login_rsp_pdu, boolean_t rx)
213a6d42e7dSPeter Dunlap {
214a6d42e7dSPeter Dunlap 	iscsi_login_rsp_hdr_t	*login_rsp =
215a6d42e7dSPeter Dunlap 	    (iscsi_login_rsp_hdr_t *)login_rsp_pdu->isp_hdr;
216a6d42e7dSPeter Dunlap 	idm_conn_event_t	new_event;
217a6d42e7dSPeter Dunlap 
218a6d42e7dSPeter Dunlap 	if (login_rsp->status_class == ISCSI_STATUS_CLASS_SUCCESS) {
219a6d42e7dSPeter Dunlap 		if (!(login_rsp->flags & ISCSI_FLAG_LOGIN_CONTINUE) &&
220a6d42e7dSPeter Dunlap 		    (login_rsp->flags & ISCSI_FLAG_LOGIN_TRANSIT) &&
221a6d42e7dSPeter Dunlap 		    (ISCSI_LOGIN_NEXT_STAGE(login_rsp->flags) ==
222a6d42e7dSPeter Dunlap 		    ISCSI_FULL_FEATURE_PHASE)) {
223a6d42e7dSPeter Dunlap 			new_event = (rx ? CE_LOGIN_SUCCESS_RCV :
224a6d42e7dSPeter Dunlap 			    CE_LOGIN_SUCCESS_SND);
225a6d42e7dSPeter Dunlap 		} else {
226a6d42e7dSPeter Dunlap 			new_event = (rx ? CE_MISC_RX : CE_MISC_TX);
227a6d42e7dSPeter Dunlap 		}
228a6d42e7dSPeter Dunlap 	} else {
229a6d42e7dSPeter Dunlap 		new_event = (rx ? CE_LOGIN_FAIL_RCV : CE_LOGIN_FAIL_SND);
230a6d42e7dSPeter Dunlap 	}
231a6d42e7dSPeter Dunlap 
232a6d42e7dSPeter Dunlap 	if (rx) {
233a6d42e7dSPeter Dunlap 		idm_conn_rx_pdu_event(ic, new_event, (uintptr_t)login_rsp_pdu);
234a6d42e7dSPeter Dunlap 	} else {
235a6d42e7dSPeter Dunlap 		idm_conn_tx_pdu_event(ic, new_event, (uintptr_t)login_rsp_pdu);
236a6d42e7dSPeter Dunlap 	}
237a6d42e7dSPeter Dunlap }
238a6d42e7dSPeter Dunlap 
239a6d42e7dSPeter Dunlap 
240a6d42e7dSPeter Dunlap void
241a6d42e7dSPeter Dunlap idm_parse_logout_req(idm_conn_t *ic, idm_pdu_t *logout_req_pdu, boolean_t rx)
242a6d42e7dSPeter Dunlap {
243a6d42e7dSPeter Dunlap 	iscsi_logout_hdr_t 	*logout_req =
244a6d42e7dSPeter Dunlap 	    (iscsi_logout_hdr_t *)logout_req_pdu->isp_hdr;
245a6d42e7dSPeter Dunlap 	idm_conn_event_t	new_event;
246a6d42e7dSPeter Dunlap 	uint8_t			reason =
247a6d42e7dSPeter Dunlap 	    (logout_req->flags & ISCSI_FLAG_LOGOUT_REASON_MASK);
248a6d42e7dSPeter Dunlap 
249a6d42e7dSPeter Dunlap 	/*
250a6d42e7dSPeter Dunlap 	 *	For a normal logout (close connection or close session) IDM
251a6d42e7dSPeter Dunlap 	 *	will terminate processing of all tasks completing the tasks
252a6d42e7dSPeter Dunlap 	 *	back to the client with a status indicating the connection
253a6d42e7dSPeter Dunlap 	 *	was logged out.  These tasks do not get completed.
254a6d42e7dSPeter Dunlap 	 *
255a6d42e7dSPeter Dunlap 	 *	For a "close connection for recovery logout) IDM suspends
256a6d42e7dSPeter Dunlap 	 *	processing of all tasks and completes them back to the client
257a6d42e7dSPeter Dunlap 	 *	with a status indicating connection was logged out for
258a6d42e7dSPeter Dunlap 	 *	recovery.  Both initiator and target hang onto these tasks.
259a6d42e7dSPeter Dunlap 	 *	When we add ERL2 support IDM will need to provide mechanisms
260a6d42e7dSPeter Dunlap 	 *	to change the task and buffer associations to a new connection.
261a6d42e7dSPeter Dunlap 	 *
262a6d42e7dSPeter Dunlap 	 *	This code doesn't address the possibility of MC/S.  We'll
263a6d42e7dSPeter Dunlap 	 *	need to decide how the separate connections get handled
264a6d42e7dSPeter Dunlap 	 *	in that case.  One simple option is to make the client
265a6d42e7dSPeter Dunlap 	 *	generate the events for the other connections.
266a6d42e7dSPeter Dunlap 	 */
267a6d42e7dSPeter Dunlap 	if (reason == ISCSI_LOGOUT_REASON_CLOSE_SESSION) {
268a6d42e7dSPeter Dunlap 		new_event =
269a6d42e7dSPeter Dunlap 		    (rx ? CE_LOGOUT_SESSION_RCV : CE_LOGOUT_SESSION_SND);
270a6d42e7dSPeter Dunlap 	} else if ((reason == ISCSI_LOGOUT_REASON_CLOSE_CONNECTION) ||
271a6d42e7dSPeter Dunlap 	    (reason == ISCSI_LOGOUT_REASON_RECOVERY)) {
272a6d42e7dSPeter Dunlap 		/* Check logout CID against this connection's CID */
273a6d42e7dSPeter Dunlap 		if (ntohs(logout_req->cid) == ic->ic_login_cid) {
274a6d42e7dSPeter Dunlap 			/* Logout is for this connection */
275a6d42e7dSPeter Dunlap 			new_event = (rx ? CE_LOGOUT_THIS_CONN_RCV :
276a6d42e7dSPeter Dunlap 			    CE_LOGOUT_THIS_CONN_SND);
277a6d42e7dSPeter Dunlap 		} else {
278a6d42e7dSPeter Dunlap 			/*
279a6d42e7dSPeter Dunlap 			 * Logout affects another connection.  This is not
280a6d42e7dSPeter Dunlap 			 * a relevant event for this connection so we'll
281a6d42e7dSPeter Dunlap 			 * just treat it as a normal PDU event.  Client
282a6d42e7dSPeter Dunlap 			 * will need to lookup the other connection and
283a6d42e7dSPeter Dunlap 			 * generate the event.
284a6d42e7dSPeter Dunlap 			 */
285a6d42e7dSPeter Dunlap 			new_event = (rx ? CE_MISC_RX : CE_MISC_TX);
286a6d42e7dSPeter Dunlap 		}
287a6d42e7dSPeter Dunlap 	} else {
288a6d42e7dSPeter Dunlap 		/* Invalid reason code */
289a6d42e7dSPeter Dunlap 		new_event = (rx ? CE_RX_PROTOCOL_ERROR : CE_TX_PROTOCOL_ERROR);
290a6d42e7dSPeter Dunlap 	}
291a6d42e7dSPeter Dunlap 
292a6d42e7dSPeter Dunlap 	if (rx) {
293a6d42e7dSPeter Dunlap 		idm_conn_rx_pdu_event(ic, new_event, (uintptr_t)logout_req_pdu);
294a6d42e7dSPeter Dunlap 	} else {
295a6d42e7dSPeter Dunlap 		idm_conn_tx_pdu_event(ic, new_event, (uintptr_t)logout_req_pdu);
296a6d42e7dSPeter Dunlap 	}
297a6d42e7dSPeter Dunlap }
298a6d42e7dSPeter Dunlap 
299a6d42e7dSPeter Dunlap 
300a6d42e7dSPeter Dunlap 
301a6d42e7dSPeter Dunlap void
302a6d42e7dSPeter Dunlap idm_parse_logout_rsp(idm_conn_t *ic, idm_pdu_t *logout_rsp_pdu, boolean_t rx)
303a6d42e7dSPeter Dunlap {
304a6d42e7dSPeter Dunlap 	idm_conn_event_t	new_event;
305a6d42e7dSPeter Dunlap 	iscsi_logout_rsp_hdr_t *logout_rsp =
306a6d42e7dSPeter Dunlap 	    (iscsi_logout_rsp_hdr_t *)logout_rsp_pdu->isp_hdr;
307a6d42e7dSPeter Dunlap 
308a6d42e7dSPeter Dunlap 	if (logout_rsp->response == ISCSI_STATUS_CLASS_SUCCESS) {
309a6d42e7dSPeter Dunlap 		new_event = rx ? CE_LOGOUT_SUCCESS_RCV : CE_LOGOUT_SUCCESS_SND;
310a6d42e7dSPeter Dunlap 	} else {
311a6d42e7dSPeter Dunlap 		new_event = rx ? CE_LOGOUT_FAIL_RCV : CE_LOGOUT_FAIL_SND;
312a6d42e7dSPeter Dunlap 	}
313a6d42e7dSPeter Dunlap 
314a6d42e7dSPeter Dunlap 	if (rx) {
315a6d42e7dSPeter Dunlap 		idm_conn_rx_pdu_event(ic, new_event, (uintptr_t)logout_rsp_pdu);
316a6d42e7dSPeter Dunlap 	} else {
317a6d42e7dSPeter Dunlap 		idm_conn_tx_pdu_event(ic, new_event, (uintptr_t)logout_rsp_pdu);
318a6d42e7dSPeter Dunlap 	}
319a6d42e7dSPeter Dunlap }
320a6d42e7dSPeter Dunlap 
321a6d42e7dSPeter Dunlap /*
322a6d42e7dSPeter Dunlap  * idm_svc_conn_create()
323a6d42e7dSPeter Dunlap  * Transport-agnostic service connection creation, invoked from the transport
324a6d42e7dSPeter Dunlap  * layer.
325a6d42e7dSPeter Dunlap  */
326a6d42e7dSPeter Dunlap idm_status_t
327a6d42e7dSPeter Dunlap idm_svc_conn_create(idm_svc_t *is, idm_transport_type_t tt,
328a6d42e7dSPeter Dunlap     idm_conn_t **ic_result)
329a6d42e7dSPeter Dunlap {
330a6d42e7dSPeter Dunlap 	idm_conn_t	*ic;
331a6d42e7dSPeter Dunlap 	idm_status_t	rc;
332a6d42e7dSPeter Dunlap 
333*30e7468fSPeter Dunlap 	mutex_enter(&is->is_mutex);
334*30e7468fSPeter Dunlap 	if (!is->is_online) {
335*30e7468fSPeter Dunlap 		mutex_exit(&is->is_mutex);
336*30e7468fSPeter Dunlap 		return (IDM_STATUS_FAIL);
337*30e7468fSPeter Dunlap 	}
338*30e7468fSPeter Dunlap 	mutex_exit(&is->is_mutex);
339*30e7468fSPeter Dunlap 
340a6d42e7dSPeter Dunlap 	ic = idm_conn_create_common(CONN_TYPE_TGT, tt,
341a6d42e7dSPeter Dunlap 	    &is->is_svc_req.sr_conn_ops);
342a6d42e7dSPeter Dunlap 	ic->ic_svc_binding = is;
343a6d42e7dSPeter Dunlap 
344a6d42e7dSPeter Dunlap 	/*
345a6d42e7dSPeter Dunlap 	 * Prepare connection state machine
346a6d42e7dSPeter Dunlap 	 */
347a6d42e7dSPeter Dunlap 	if ((rc = idm_conn_sm_init(ic)) != 0) {
348a6d42e7dSPeter Dunlap 		idm_conn_destroy_common(ic);
349a6d42e7dSPeter Dunlap 		return (rc);
350a6d42e7dSPeter Dunlap 	}
351a6d42e7dSPeter Dunlap 
352a6d42e7dSPeter Dunlap 
353a6d42e7dSPeter Dunlap 	*ic_result = ic;
354a6d42e7dSPeter Dunlap 
355a6d42e7dSPeter Dunlap 	mutex_enter(&idm.idm_global_mutex);
356a6d42e7dSPeter Dunlap 	list_insert_tail(&idm.idm_tgt_conn_list, ic);
357a6d42e7dSPeter Dunlap 	idm.idm_tgt_conn_count++;
358a6d42e7dSPeter Dunlap 	mutex_exit(&idm.idm_global_mutex);
359a6d42e7dSPeter Dunlap 
360*30e7468fSPeter Dunlap 	return (IDM_STATUS_SUCCESS);
361a6d42e7dSPeter Dunlap }
362a6d42e7dSPeter Dunlap 
363a6d42e7dSPeter Dunlap void
364a6d42e7dSPeter Dunlap idm_svc_conn_destroy(idm_conn_t *ic)
365a6d42e7dSPeter Dunlap {
366a6d42e7dSPeter Dunlap 	mutex_enter(&idm.idm_global_mutex);
367a6d42e7dSPeter Dunlap 	list_remove(&idm.idm_tgt_conn_list, ic);
368a6d42e7dSPeter Dunlap 	idm.idm_tgt_conn_count--;
369a6d42e7dSPeter Dunlap 	mutex_exit(&idm.idm_global_mutex);
370a6d42e7dSPeter Dunlap 
371a6d42e7dSPeter Dunlap 	if (ic->ic_transport_private != NULL) {
372a6d42e7dSPeter Dunlap 		ic->ic_transport_ops->it_tgt_conn_destroy(ic);
373a6d42e7dSPeter Dunlap 	}
374a6d42e7dSPeter Dunlap 	idm_conn_destroy_common(ic);
375a6d42e7dSPeter Dunlap }
376a6d42e7dSPeter Dunlap 
377a6d42e7dSPeter Dunlap /*
378a6d42e7dSPeter Dunlap  * idm_conn_create_common()
379a6d42e7dSPeter Dunlap  *
380a6d42e7dSPeter Dunlap  * Allocate and initialize IDM connection context
381a6d42e7dSPeter Dunlap  */
382a6d42e7dSPeter Dunlap idm_conn_t *
383a6d42e7dSPeter Dunlap idm_conn_create_common(idm_conn_type_t conn_type, idm_transport_type_t tt,
384a6d42e7dSPeter Dunlap     idm_conn_ops_t *conn_ops)
385a6d42e7dSPeter Dunlap {
386a6d42e7dSPeter Dunlap 	idm_conn_t		*ic;
387a6d42e7dSPeter Dunlap 	idm_transport_t		*it;
388a6d42e7dSPeter Dunlap 	idm_transport_type_t	type;
389a6d42e7dSPeter Dunlap 
390a6d42e7dSPeter Dunlap 	for (type = 0; type < IDM_TRANSPORT_NUM_TYPES; type++) {
391a6d42e7dSPeter Dunlap 		it = &idm_transport_list[type];
392a6d42e7dSPeter Dunlap 
393a6d42e7dSPeter Dunlap 		if ((it->it_ops != NULL) && (it->it_type == tt))
394a6d42e7dSPeter Dunlap 			break;
395a6d42e7dSPeter Dunlap 	}
396a6d42e7dSPeter Dunlap 	ASSERT(it->it_type == tt);
397a6d42e7dSPeter Dunlap 	if (it->it_type != tt)
398a6d42e7dSPeter Dunlap 		return (NULL);
399a6d42e7dSPeter Dunlap 
400a6d42e7dSPeter Dunlap 	ic = kmem_zalloc(sizeof (idm_conn_t), KM_SLEEP);
401a6d42e7dSPeter Dunlap 
402a6d42e7dSPeter Dunlap 	/* Initialize data */
403a6d42e7dSPeter Dunlap 	ic->ic_conn_type = conn_type;
404a6d42e7dSPeter Dunlap 	ic->ic_conn_ops = *conn_ops;
405a6d42e7dSPeter Dunlap 	ic->ic_transport_ops = it->it_ops;
406a6d42e7dSPeter Dunlap 	ic->ic_transport_type = tt;
407a6d42e7dSPeter Dunlap 	ic->ic_transport_private = NULL; /* Set by transport service */
408a6d42e7dSPeter Dunlap 	ic->ic_internal_cid = idm_cid_alloc();
409a6d42e7dSPeter Dunlap 	if (ic->ic_internal_cid == 0) {
410a6d42e7dSPeter Dunlap 		kmem_free(ic, sizeof (idm_conn_t));
411a6d42e7dSPeter Dunlap 		return (NULL);
412a6d42e7dSPeter Dunlap 	}
413a6d42e7dSPeter Dunlap 	mutex_init(&ic->ic_mutex, NULL, MUTEX_DEFAULT, NULL);
414a6d42e7dSPeter Dunlap 	cv_init(&ic->ic_cv, NULL, CV_DEFAULT, NULL);
415a6d42e7dSPeter Dunlap 	idm_refcnt_init(&ic->ic_refcnt, ic);
416a6d42e7dSPeter Dunlap 
417a6d42e7dSPeter Dunlap 	return (ic);
418a6d42e7dSPeter Dunlap }
419a6d42e7dSPeter Dunlap 
420a6d42e7dSPeter Dunlap void
421a6d42e7dSPeter Dunlap idm_conn_destroy_common(idm_conn_t *ic)
422a6d42e7dSPeter Dunlap {
423*30e7468fSPeter Dunlap 	idm_conn_sm_fini(ic);
424a6d42e7dSPeter Dunlap 	idm_refcnt_destroy(&ic->ic_refcnt);
425a6d42e7dSPeter Dunlap 	cv_destroy(&ic->ic_cv);
426a6d42e7dSPeter Dunlap 	mutex_destroy(&ic->ic_mutex);
427a6d42e7dSPeter Dunlap 	idm_cid_free(ic->ic_internal_cid);
428a6d42e7dSPeter Dunlap 
429a6d42e7dSPeter Dunlap 	kmem_free(ic, sizeof (idm_conn_t));
430a6d42e7dSPeter Dunlap }
431a6d42e7dSPeter Dunlap 
432a6d42e7dSPeter Dunlap /*
433a6d42e7dSPeter Dunlap  * Invoked from the SM as a result of client's invocation of
434a6d42e7dSPeter Dunlap  * idm_ini_conn_connect()
435a6d42e7dSPeter Dunlap  */
436a6d42e7dSPeter Dunlap idm_status_t
437a6d42e7dSPeter Dunlap idm_ini_conn_finish(idm_conn_t *ic)
438a6d42e7dSPeter Dunlap {
439a6d42e7dSPeter Dunlap 	/* invoke transport-specific connection */
440a6d42e7dSPeter Dunlap 	return (ic->ic_transport_ops->it_ini_conn_connect(ic));
441a6d42e7dSPeter Dunlap }
442a6d42e7dSPeter Dunlap 
443a6d42e7dSPeter Dunlap idm_status_t
444a6d42e7dSPeter Dunlap idm_tgt_conn_finish(idm_conn_t *ic)
445a6d42e7dSPeter Dunlap {
446a6d42e7dSPeter Dunlap 	idm_status_t rc;
447a6d42e7dSPeter Dunlap 
448a6d42e7dSPeter Dunlap 	rc = idm_notify_client(ic, CN_CONNECT_ACCEPT, NULL);
449a6d42e7dSPeter Dunlap 	if (rc != IDM_STATUS_SUCCESS) {
450a6d42e7dSPeter Dunlap 		return (IDM_STATUS_REJECT);
451a6d42e7dSPeter Dunlap 	}
452a6d42e7dSPeter Dunlap 
453a6d42e7dSPeter Dunlap 	/* Target client is ready to receive a login, start connection */
454a6d42e7dSPeter Dunlap 	return (ic->ic_transport_ops->it_tgt_conn_connect(ic));
455a6d42e7dSPeter Dunlap }
456a6d42e7dSPeter Dunlap 
457a6d42e7dSPeter Dunlap idm_transport_t *
458a6d42e7dSPeter Dunlap idm_transport_lookup(idm_conn_req_t *cr)
459a6d42e7dSPeter Dunlap {
460a6d42e7dSPeter Dunlap 	idm_transport_type_t	type;
461a6d42e7dSPeter Dunlap 	idm_transport_t		*it;
462a6d42e7dSPeter Dunlap 	idm_transport_caps_t	caps;
463a6d42e7dSPeter Dunlap 
464a6d42e7dSPeter Dunlap 	/*
465a6d42e7dSPeter Dunlap 	 * Make sure all available transports are setup.  We call this now
466a6d42e7dSPeter Dunlap 	 * instead of at initialization time in case IB has become available
467a6d42e7dSPeter Dunlap 	 * since we started (hotplug, etc).
468a6d42e7dSPeter Dunlap 	 */
469a6d42e7dSPeter Dunlap 	idm_transport_setup(cr->cr_li);
470a6d42e7dSPeter Dunlap 
471a6d42e7dSPeter Dunlap 	/* Determine the transport for this connection */
472a6d42e7dSPeter Dunlap 	for (type = 0; type < IDM_TRANSPORT_NUM_TYPES; type++) {
473a6d42e7dSPeter Dunlap 		it = &idm_transport_list[type];
474a6d42e7dSPeter Dunlap 
475a6d42e7dSPeter Dunlap 		if (it->it_ops == NULL) {
476a6d42e7dSPeter Dunlap 			/* transport is not registered */
477a6d42e7dSPeter Dunlap 			continue;
478a6d42e7dSPeter Dunlap 		}
479a6d42e7dSPeter Dunlap 
480a6d42e7dSPeter Dunlap 		if (it->it_ops->it_conn_is_capable(cr, &caps)) {
481a6d42e7dSPeter Dunlap 			return (it);
482a6d42e7dSPeter Dunlap 		}
483a6d42e7dSPeter Dunlap 	}
484a6d42e7dSPeter Dunlap 
485a6d42e7dSPeter Dunlap 	ASSERT(0);
486a6d42e7dSPeter Dunlap 	return (NULL); /* Make gcc happy */
487a6d42e7dSPeter Dunlap }
488a6d42e7dSPeter Dunlap 
489a6d42e7dSPeter Dunlap void
490a6d42e7dSPeter Dunlap idm_transport_setup(ldi_ident_t li)
491a6d42e7dSPeter Dunlap {
492a6d42e7dSPeter Dunlap 	idm_transport_type_t	type;
493a6d42e7dSPeter Dunlap 	idm_transport_t		*it;
494a6d42e7dSPeter Dunlap 	int			rc;
495a6d42e7dSPeter Dunlap 
496a6d42e7dSPeter Dunlap 	for (type = 0; type < IDM_TRANSPORT_NUM_TYPES; type++) {
497a6d42e7dSPeter Dunlap 		it = &idm_transport_list[type];
498a6d42e7dSPeter Dunlap 		/*
499a6d42e7dSPeter Dunlap 		 * We may want to store the LDI handle in the idm_svc_t
500a6d42e7dSPeter Dunlap 		 * and then allow multiple calls to ldi_open_by_name.  This
501a6d42e7dSPeter Dunlap 		 * would enable the LDI code to track who has the device open
502a6d42e7dSPeter Dunlap 		 * which could be useful in the case where we have multiple
503a6d42e7dSPeter Dunlap 		 * services and perhaps also have initiator and target opening
504a6d42e7dSPeter Dunlap 		 * the transport simultaneously.  For now we stick with the
505a6d42e7dSPeter Dunlap 		 * plan.
506a6d42e7dSPeter Dunlap 		 */
507a6d42e7dSPeter Dunlap 		if (it->it_ops == NULL) {
508a6d42e7dSPeter Dunlap 			/* transport is not ready, try to initialize it */
509a6d42e7dSPeter Dunlap 			if (it->it_type == IDM_TRANSPORT_TYPE_SOCKETS) {
510a6d42e7dSPeter Dunlap 				idm_so_init(it);
511a6d42e7dSPeter Dunlap 			} else {
512a6d42e7dSPeter Dunlap 				rc = ldi_open_by_name(it->it_device_path,
513a6d42e7dSPeter Dunlap 				    FREAD | FWRITE, kcred, &it->it_ldi_hdl, li);
514a6d42e7dSPeter Dunlap 				/*
515a6d42e7dSPeter Dunlap 				 * If the open is successful we will have
516a6d42e7dSPeter Dunlap 				 * filled in the LDI handle in the transport
517a6d42e7dSPeter Dunlap 				 * table and we expect that the transport
518a6d42e7dSPeter Dunlap 				 * registered itself.
519a6d42e7dSPeter Dunlap 				 */
520a6d42e7dSPeter Dunlap 				if (rc != 0) {
521a6d42e7dSPeter Dunlap 					it->it_ldi_hdl = NULL;
522a6d42e7dSPeter Dunlap 				}
523a6d42e7dSPeter Dunlap 			}
524a6d42e7dSPeter Dunlap 		}
525a6d42e7dSPeter Dunlap 	}
526a6d42e7dSPeter Dunlap }
527a6d42e7dSPeter Dunlap 
528*30e7468fSPeter Dunlap void
529*30e7468fSPeter Dunlap idm_transport_teardown()
530*30e7468fSPeter Dunlap {
531*30e7468fSPeter Dunlap 	idm_transport_type_t	type;
532*30e7468fSPeter Dunlap 	idm_transport_t		*it;
533*30e7468fSPeter Dunlap 
534*30e7468fSPeter Dunlap 	ASSERT(mutex_owned(&idm.idm_global_mutex));
535*30e7468fSPeter Dunlap 
536*30e7468fSPeter Dunlap 	/* Caller holds the IDM global mutex */
537*30e7468fSPeter Dunlap 	for (type = 0; type < IDM_TRANSPORT_NUM_TYPES; type++) {
538*30e7468fSPeter Dunlap 		it = &idm_transport_list[type];
539*30e7468fSPeter Dunlap 		/* If we have an open LDI handle on this driver, close it */
540*30e7468fSPeter Dunlap 		if (it->it_ldi_hdl != NULL) {
541*30e7468fSPeter Dunlap 			(void) ldi_close(it->it_ldi_hdl, FNDELAY, kcred);
542*30e7468fSPeter Dunlap 			it->it_ldi_hdl = NULL;
543*30e7468fSPeter Dunlap 		}
544*30e7468fSPeter Dunlap 	}
545*30e7468fSPeter Dunlap }
546*30e7468fSPeter Dunlap 
547a6d42e7dSPeter Dunlap /*
548a6d42e7dSPeter Dunlap  * ID pool code.  We use this to generate unique structure identifiers without
549a6d42e7dSPeter Dunlap  * searching the existing structures.  This avoids the need to lock entire
550a6d42e7dSPeter Dunlap  * sets of structures at inopportune times.  Adapted from the CIFS server code.
551a6d42e7dSPeter Dunlap  *
552a6d42e7dSPeter Dunlap  *    A pool of IDs is a pool of 16 bit numbers. It is implemented as a bitmap.
553a6d42e7dSPeter Dunlap  *    A bit set to '1' indicates that that particular value has been allocated.
554a6d42e7dSPeter Dunlap  *    The allocation process is done shifting a bit through the whole bitmap.
555a6d42e7dSPeter Dunlap  *    The current position of that index bit is kept in the idm_idpool_t
556a6d42e7dSPeter Dunlap  *    structure and represented by a byte index (0 to buffer size minus 1) and
557a6d42e7dSPeter Dunlap  *    a bit index (0 to 7).
558a6d42e7dSPeter Dunlap  *
559a6d42e7dSPeter Dunlap  *    The pools start with a size of 8 bytes or 64 IDs. Each time the pool runs
560a6d42e7dSPeter Dunlap  *    out of IDs its current size is doubled until it reaches its maximum size
561a6d42e7dSPeter Dunlap  *    (8192 bytes or 65536 IDs). The IDs 0 and 65535 are never given out which
562a6d42e7dSPeter Dunlap  *    means that a pool can have a maximum number of 65534 IDs available.
563a6d42e7dSPeter Dunlap  */
564a6d42e7dSPeter Dunlap 
565a6d42e7dSPeter Dunlap static int
566a6d42e7dSPeter Dunlap idm_idpool_increment(
567a6d42e7dSPeter Dunlap     idm_idpool_t	*pool)
568a6d42e7dSPeter Dunlap {
569a6d42e7dSPeter Dunlap 	uint8_t		*new_pool;
570a6d42e7dSPeter Dunlap 	uint32_t	new_size;
571a6d42e7dSPeter Dunlap 
572a6d42e7dSPeter Dunlap 	ASSERT(pool->id_magic == IDM_IDPOOL_MAGIC);
573a6d42e7dSPeter Dunlap 
574a6d42e7dSPeter Dunlap 	new_size = pool->id_size * 2;
575a6d42e7dSPeter Dunlap 	if (new_size <= IDM_IDPOOL_MAX_SIZE) {
576a6d42e7dSPeter Dunlap 		new_pool = kmem_alloc(new_size / 8, KM_NOSLEEP);
577a6d42e7dSPeter Dunlap 		if (new_pool) {
578a6d42e7dSPeter Dunlap 			bzero(new_pool, new_size / 8);
579a6d42e7dSPeter Dunlap 			bcopy(pool->id_pool, new_pool, pool->id_size / 8);
580a6d42e7dSPeter Dunlap 			kmem_free(pool->id_pool, pool->id_size / 8);
581a6d42e7dSPeter Dunlap 			pool->id_pool = new_pool;
582a6d42e7dSPeter Dunlap 			pool->id_free_counter += new_size - pool->id_size;
583a6d42e7dSPeter Dunlap 			pool->id_max_free_counter += new_size - pool->id_size;
584a6d42e7dSPeter Dunlap 			pool->id_size = new_size;
585a6d42e7dSPeter Dunlap 			pool->id_idx_msk = (new_size / 8) - 1;
586a6d42e7dSPeter Dunlap 			if (new_size >= IDM_IDPOOL_MAX_SIZE) {
587a6d42e7dSPeter Dunlap 				/* id -1 made unavailable */
588a6d42e7dSPeter Dunlap 				pool->id_pool[pool->id_idx_msk] = 0x80;
589a6d42e7dSPeter Dunlap 				pool->id_free_counter--;
590a6d42e7dSPeter Dunlap 				pool->id_max_free_counter--;
591a6d42e7dSPeter Dunlap 			}
592a6d42e7dSPeter Dunlap 			return (0);
593a6d42e7dSPeter Dunlap 		}
594a6d42e7dSPeter Dunlap 	}
595a6d42e7dSPeter Dunlap 	return (-1);
596a6d42e7dSPeter Dunlap }
597a6d42e7dSPeter Dunlap 
598a6d42e7dSPeter Dunlap /*
599a6d42e7dSPeter Dunlap  * idm_idpool_constructor
600a6d42e7dSPeter Dunlap  *
601a6d42e7dSPeter Dunlap  * This function initializes the pool structure provided.
602a6d42e7dSPeter Dunlap  */
603a6d42e7dSPeter Dunlap 
604a6d42e7dSPeter Dunlap int
605a6d42e7dSPeter Dunlap idm_idpool_create(idm_idpool_t *pool)
606a6d42e7dSPeter Dunlap {
607a6d42e7dSPeter Dunlap 
608a6d42e7dSPeter Dunlap 	ASSERT(pool->id_magic != IDM_IDPOOL_MAGIC);
609a6d42e7dSPeter Dunlap 
610a6d42e7dSPeter Dunlap 	pool->id_size = IDM_IDPOOL_MIN_SIZE;
611a6d42e7dSPeter Dunlap 	pool->id_idx_msk = (IDM_IDPOOL_MIN_SIZE / 8) - 1;
612a6d42e7dSPeter Dunlap 	pool->id_free_counter = IDM_IDPOOL_MIN_SIZE - 1;
613a6d42e7dSPeter Dunlap 	pool->id_max_free_counter = IDM_IDPOOL_MIN_SIZE - 1;
614a6d42e7dSPeter Dunlap 	pool->id_bit = 0x02;
615a6d42e7dSPeter Dunlap 	pool->id_bit_idx = 1;
616a6d42e7dSPeter Dunlap 	pool->id_idx = 0;
617a6d42e7dSPeter Dunlap 	pool->id_pool = (uint8_t *)kmem_alloc((IDM_IDPOOL_MIN_SIZE / 8),
618a6d42e7dSPeter Dunlap 	    KM_SLEEP);
619a6d42e7dSPeter Dunlap 	bzero(pool->id_pool, (IDM_IDPOOL_MIN_SIZE / 8));
620a6d42e7dSPeter Dunlap 	/* -1 id made unavailable */
621a6d42e7dSPeter Dunlap 	pool->id_pool[0] = 0x01;		/* id 0 made unavailable */
622a6d42e7dSPeter Dunlap 	mutex_init(&pool->id_mutex, NULL, MUTEX_DEFAULT, NULL);
623a6d42e7dSPeter Dunlap 	pool->id_magic = IDM_IDPOOL_MAGIC;
624a6d42e7dSPeter Dunlap 	return (0);
625a6d42e7dSPeter Dunlap }
626a6d42e7dSPeter Dunlap 
627a6d42e7dSPeter Dunlap /*
628a6d42e7dSPeter Dunlap  * idm_idpool_destructor
629a6d42e7dSPeter Dunlap  *
630a6d42e7dSPeter Dunlap  * This function tears down and frees the resources associated with the
631a6d42e7dSPeter Dunlap  * pool provided.
632a6d42e7dSPeter Dunlap  */
633a6d42e7dSPeter Dunlap 
634a6d42e7dSPeter Dunlap void
635a6d42e7dSPeter Dunlap idm_idpool_destroy(idm_idpool_t *pool)
636a6d42e7dSPeter Dunlap {
637a6d42e7dSPeter Dunlap 	ASSERT(pool->id_magic == IDM_IDPOOL_MAGIC);
638a6d42e7dSPeter Dunlap 	ASSERT(pool->id_free_counter == pool->id_max_free_counter);
639a6d42e7dSPeter Dunlap 	pool->id_magic = (uint32_t)~IDM_IDPOOL_MAGIC;
640a6d42e7dSPeter Dunlap 	mutex_destroy(&pool->id_mutex);
641a6d42e7dSPeter Dunlap 	kmem_free(pool->id_pool, (size_t)(pool->id_size / 8));
642a6d42e7dSPeter Dunlap }
643a6d42e7dSPeter Dunlap 
644a6d42e7dSPeter Dunlap /*
645a6d42e7dSPeter Dunlap  * idm_idpool_alloc
646a6d42e7dSPeter Dunlap  *
647a6d42e7dSPeter Dunlap  * This function allocates an ID from the pool provided.
648a6d42e7dSPeter Dunlap  */
649a6d42e7dSPeter Dunlap int
650a6d42e7dSPeter Dunlap idm_idpool_alloc(idm_idpool_t *pool, uint16_t *id)
651a6d42e7dSPeter Dunlap {
652a6d42e7dSPeter Dunlap 	uint32_t	i;
653a6d42e7dSPeter Dunlap 	uint8_t		bit;
654a6d42e7dSPeter Dunlap 	uint8_t		bit_idx;
655a6d42e7dSPeter Dunlap 	uint8_t		byte;
656a6d42e7dSPeter Dunlap 
657a6d42e7dSPeter Dunlap 	ASSERT(pool->id_magic == IDM_IDPOOL_MAGIC);
658a6d42e7dSPeter Dunlap 
659a6d42e7dSPeter Dunlap 	mutex_enter(&pool->id_mutex);
660a6d42e7dSPeter Dunlap 	if ((pool->id_free_counter == 0) && idm_idpool_increment(pool)) {
661a6d42e7dSPeter Dunlap 		mutex_exit(&pool->id_mutex);
662a6d42e7dSPeter Dunlap 		return (-1);
663a6d42e7dSPeter Dunlap 	}
664a6d42e7dSPeter Dunlap 
665a6d42e7dSPeter Dunlap 	i = pool->id_size;
666a6d42e7dSPeter Dunlap 	while (i) {
667a6d42e7dSPeter Dunlap 		bit = pool->id_bit;
668a6d42e7dSPeter Dunlap 		bit_idx = pool->id_bit_idx;
669a6d42e7dSPeter Dunlap 		byte = pool->id_pool[pool->id_idx];
670a6d42e7dSPeter Dunlap 		while (bit) {
671a6d42e7dSPeter Dunlap 			if (byte & bit) {
672a6d42e7dSPeter Dunlap 				bit = bit << 1;
673a6d42e7dSPeter Dunlap 				bit_idx++;
674a6d42e7dSPeter Dunlap 				continue;
675a6d42e7dSPeter Dunlap 			}
676a6d42e7dSPeter Dunlap 			pool->id_pool[pool->id_idx] |= bit;
677a6d42e7dSPeter Dunlap 			*id = (uint16_t)(pool->id_idx * 8 + (uint32_t)bit_idx);
678a6d42e7dSPeter Dunlap 			pool->id_free_counter--;
679a6d42e7dSPeter Dunlap 			pool->id_bit = bit;
680a6d42e7dSPeter Dunlap 			pool->id_bit_idx = bit_idx;
681a6d42e7dSPeter Dunlap 			mutex_exit(&pool->id_mutex);
682a6d42e7dSPeter Dunlap 			return (0);
683a6d42e7dSPeter Dunlap 		}
684a6d42e7dSPeter Dunlap 		pool->id_bit = 1;
685a6d42e7dSPeter Dunlap 		pool->id_bit_idx = 0;
686a6d42e7dSPeter Dunlap 		pool->id_idx++;
687a6d42e7dSPeter Dunlap 		pool->id_idx &= pool->id_idx_msk;
688a6d42e7dSPeter Dunlap 		--i;
689a6d42e7dSPeter Dunlap 	}
690a6d42e7dSPeter Dunlap 	/*
691a6d42e7dSPeter Dunlap 	 * This section of code shouldn't be reached. If there are IDs
692a6d42e7dSPeter Dunlap 	 * available and none could be found there's a problem.
693a6d42e7dSPeter Dunlap 	 */
694a6d42e7dSPeter Dunlap 	ASSERT(0);
695a6d42e7dSPeter Dunlap 	mutex_exit(&pool->id_mutex);
696a6d42e7dSPeter Dunlap 	return (-1);
697a6d42e7dSPeter Dunlap }
698a6d42e7dSPeter Dunlap 
699a6d42e7dSPeter Dunlap /*
700a6d42e7dSPeter Dunlap  * idm_idpool_free
701a6d42e7dSPeter Dunlap  *
702a6d42e7dSPeter Dunlap  * This function frees the ID provided.
703a6d42e7dSPeter Dunlap  */
704a6d42e7dSPeter Dunlap void
705a6d42e7dSPeter Dunlap idm_idpool_free(idm_idpool_t *pool, uint16_t id)
706a6d42e7dSPeter Dunlap {
707a6d42e7dSPeter Dunlap 	ASSERT(pool->id_magic == IDM_IDPOOL_MAGIC);
708a6d42e7dSPeter Dunlap 	ASSERT(id != 0);
709a6d42e7dSPeter Dunlap 	ASSERT(id != 0xFFFF);
710a6d42e7dSPeter Dunlap 
711a6d42e7dSPeter Dunlap 	mutex_enter(&pool->id_mutex);
712a6d42e7dSPeter Dunlap 	if (pool->id_pool[id >> 3] & (1 << (id & 7))) {
713a6d42e7dSPeter Dunlap 		pool->id_pool[id >> 3] &= ~(1 << (id & 7));
714a6d42e7dSPeter Dunlap 		pool->id_free_counter++;
715a6d42e7dSPeter Dunlap 		ASSERT(pool->id_free_counter <= pool->id_max_free_counter);
716a6d42e7dSPeter Dunlap 		mutex_exit(&pool->id_mutex);
717a6d42e7dSPeter Dunlap 		return;
718a6d42e7dSPeter Dunlap 	}
719a6d42e7dSPeter Dunlap 	/* Freeing a free ID. */
720a6d42e7dSPeter Dunlap 	ASSERT(0);
721a6d42e7dSPeter Dunlap 	mutex_exit(&pool->id_mutex);
722a6d42e7dSPeter Dunlap }
723a6d42e7dSPeter Dunlap 
724a6d42e7dSPeter Dunlap uint32_t
725a6d42e7dSPeter Dunlap idm_cid_alloc(void)
726a6d42e7dSPeter Dunlap {
727a6d42e7dSPeter Dunlap 	/*
728a6d42e7dSPeter Dunlap 	 * ID pool works with 16-bit identifiers right now.  That should
729a6d42e7dSPeter Dunlap 	 * be plenty since we will probably never have more than 2^16
730a6d42e7dSPeter Dunlap 	 * connections simultaneously.
731a6d42e7dSPeter Dunlap 	 */
732a6d42e7dSPeter Dunlap 	uint16_t cid16;
733a6d42e7dSPeter Dunlap 
734a6d42e7dSPeter Dunlap 	if (idm_idpool_alloc(&idm.idm_conn_id_pool, &cid16) == -1) {
735a6d42e7dSPeter Dunlap 		return (0); /* Fail */
736a6d42e7dSPeter Dunlap 	}
737a6d42e7dSPeter Dunlap 
738a6d42e7dSPeter Dunlap 	return ((uint32_t)cid16);
739a6d42e7dSPeter Dunlap }
740a6d42e7dSPeter Dunlap 
741a6d42e7dSPeter Dunlap void
742a6d42e7dSPeter Dunlap idm_cid_free(uint32_t cid)
743a6d42e7dSPeter Dunlap {
744a6d42e7dSPeter Dunlap 	idm_idpool_free(&idm.idm_conn_id_pool, (uint16_t)cid);
745a6d42e7dSPeter Dunlap }
746a6d42e7dSPeter Dunlap 
747a6d42e7dSPeter Dunlap 
748a6d42e7dSPeter Dunlap /*
749a6d42e7dSPeter Dunlap  * Code for generating the header and data digests
750a6d42e7dSPeter Dunlap  *
751a6d42e7dSPeter Dunlap  * This is the CRC-32C table
752a6d42e7dSPeter Dunlap  * Generated with:
753a6d42e7dSPeter Dunlap  * width = 32 bits
754a6d42e7dSPeter Dunlap  * poly = 0x1EDC6F41
755a6d42e7dSPeter Dunlap  * reflect input bytes = true
756a6d42e7dSPeter Dunlap  * reflect output bytes = true
757a6d42e7dSPeter Dunlap  */
758a6d42e7dSPeter Dunlap 
759a6d42e7dSPeter Dunlap uint32_t idm_crc32c_table[256] =
760a6d42e7dSPeter Dunlap {
761a6d42e7dSPeter Dunlap 	0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4,
762a6d42e7dSPeter Dunlap 	0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
763a6d42e7dSPeter Dunlap 	0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B,
764a6d42e7dSPeter Dunlap 	0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,
765a6d42e7dSPeter Dunlap 	0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B,
766a6d42e7dSPeter Dunlap 	0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384,
767a6d42e7dSPeter Dunlap 	0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54,
768a6d42e7dSPeter Dunlap 	0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B,
769a6d42e7dSPeter Dunlap 	0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A,
770a6d42e7dSPeter Dunlap 	0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,
771a6d42e7dSPeter Dunlap 	0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5,
772a6d42e7dSPeter Dunlap 	0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA,
773a6d42e7dSPeter Dunlap 	0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45,
774a6d42e7dSPeter Dunlap 	0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A,
775a6d42e7dSPeter Dunlap 	0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A,
776a6d42e7dSPeter Dunlap 	0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595,
777a6d42e7dSPeter Dunlap 	0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48,
778a6d42e7dSPeter Dunlap 	0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957,
779a6d42e7dSPeter Dunlap 	0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687,
780a6d42e7dSPeter Dunlap 	0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,
781a6d42e7dSPeter Dunlap 	0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927,
782a6d42e7dSPeter Dunlap 	0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38,
783a6d42e7dSPeter Dunlap 	0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8,
784a6d42e7dSPeter Dunlap 	0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7,
785a6d42e7dSPeter Dunlap 	0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096,
786a6d42e7dSPeter Dunlap 	0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789,
787a6d42e7dSPeter Dunlap 	0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859,
788a6d42e7dSPeter Dunlap 	0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46,
789a6d42e7dSPeter Dunlap 	0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9,
790a6d42e7dSPeter Dunlap 	0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,
791a6d42e7dSPeter Dunlap 	0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36,
792a6d42e7dSPeter Dunlap 	0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829,
793a6d42e7dSPeter Dunlap 	0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C,
794a6d42e7dSPeter Dunlap 	0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93,
795a6d42e7dSPeter Dunlap 	0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043,
796a6d42e7dSPeter Dunlap 	0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C,
797a6d42e7dSPeter Dunlap 	0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3,
798a6d42e7dSPeter Dunlap 	0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC,
799a6d42e7dSPeter Dunlap 	0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C,
800a6d42e7dSPeter Dunlap 	0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,
801a6d42e7dSPeter Dunlap 	0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652,
802a6d42e7dSPeter Dunlap 	0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D,
803a6d42e7dSPeter Dunlap 	0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D,
804a6d42e7dSPeter Dunlap 	0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982,
805a6d42e7dSPeter Dunlap 	0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D,
806a6d42e7dSPeter Dunlap 	0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622,
807a6d42e7dSPeter Dunlap 	0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2,
808a6d42e7dSPeter Dunlap 	0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED,
809a6d42e7dSPeter Dunlap 	0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530,
810a6d42e7dSPeter Dunlap 	0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,
811a6d42e7dSPeter Dunlap 	0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF,
812a6d42e7dSPeter Dunlap 	0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0,
813a6d42e7dSPeter Dunlap 	0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F,
814a6d42e7dSPeter Dunlap 	0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540,
815a6d42e7dSPeter Dunlap 	0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90,
816a6d42e7dSPeter Dunlap 	0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F,
817a6d42e7dSPeter Dunlap 	0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE,
818a6d42e7dSPeter Dunlap 	0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1,
819a6d42e7dSPeter Dunlap 	0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321,
820a6d42e7dSPeter Dunlap 	0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,
821a6d42e7dSPeter Dunlap 	0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81,
822a6d42e7dSPeter Dunlap 	0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
823a6d42e7dSPeter Dunlap 	0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E,
824a6d42e7dSPeter Dunlap 	0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351
825a6d42e7dSPeter Dunlap };
826a6d42e7dSPeter Dunlap 
827a6d42e7dSPeter Dunlap /*
828a6d42e7dSPeter Dunlap  * iscsi_crc32c - Steps through buffer one byte at at time, calculates
829a6d42e7dSPeter Dunlap  * reflected crc using table.
830a6d42e7dSPeter Dunlap  */
831a6d42e7dSPeter Dunlap uint32_t
832a6d42e7dSPeter Dunlap idm_crc32c(void *address, unsigned long length)
833a6d42e7dSPeter Dunlap {
834a6d42e7dSPeter Dunlap 	uint8_t *buffer = address;
835a6d42e7dSPeter Dunlap 	uint32_t crc = 0xffffffff, result;
836a6d42e7dSPeter Dunlap #ifdef _BIG_ENDIAN
837a6d42e7dSPeter Dunlap 	uint8_t byte0, byte1, byte2, byte3;
838a6d42e7dSPeter Dunlap #endif
839a6d42e7dSPeter Dunlap 
840a6d42e7dSPeter Dunlap 	ASSERT(address != NULL);
841a6d42e7dSPeter Dunlap 
842a6d42e7dSPeter Dunlap 	while (length--) {
843a6d42e7dSPeter Dunlap 		crc = idm_crc32c_table[(crc ^ *buffer++) & 0xFFL] ^
844a6d42e7dSPeter Dunlap 		    (crc >> 8);
845a6d42e7dSPeter Dunlap 	}
846a6d42e7dSPeter Dunlap 	result = crc ^ 0xffffffff;
847a6d42e7dSPeter Dunlap 
848a6d42e7dSPeter Dunlap #ifdef	_BIG_ENDIAN
849a6d42e7dSPeter Dunlap 	byte0 = (uint8_t)(result & 0xFF);
850a6d42e7dSPeter Dunlap 	byte1 = (uint8_t)((result >> 8) & 0xFF);
851a6d42e7dSPeter Dunlap 	byte2 = (uint8_t)((result >> 16) & 0xFF);
852a6d42e7dSPeter Dunlap 	byte3 = (uint8_t)((result >> 24) & 0xFF);
853a6d42e7dSPeter Dunlap 	result = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3);
854a6d42e7dSPeter Dunlap #endif	/* _BIG_ENDIAN */
855a6d42e7dSPeter Dunlap 
856a6d42e7dSPeter Dunlap 	return (result);
857a6d42e7dSPeter Dunlap }
858a6d42e7dSPeter Dunlap 
859a6d42e7dSPeter Dunlap 
860a6d42e7dSPeter Dunlap /*
861a6d42e7dSPeter Dunlap  * idm_crc32c_continued - Continues stepping through buffer one
862a6d42e7dSPeter Dunlap  * byte at at time, calculates reflected crc using table.
863a6d42e7dSPeter Dunlap  */
864a6d42e7dSPeter Dunlap uint32_t
865a6d42e7dSPeter Dunlap idm_crc32c_continued(void *address, unsigned long length, uint32_t crc)
866a6d42e7dSPeter Dunlap {
867a6d42e7dSPeter Dunlap 	uint8_t *buffer = address;
868a6d42e7dSPeter Dunlap 	uint32_t result;
869a6d42e7dSPeter Dunlap #ifdef	_BIG_ENDIAN
870a6d42e7dSPeter Dunlap 	uint8_t byte0, byte1, byte2, byte3;
871a6d42e7dSPeter Dunlap #endif
872a6d42e7dSPeter Dunlap 
873a6d42e7dSPeter Dunlap 	ASSERT(address != NULL);
874a6d42e7dSPeter Dunlap 
875a6d42e7dSPeter Dunlap #ifdef	_BIG_ENDIAN
876a6d42e7dSPeter Dunlap 	byte0 = (uint8_t)((crc >> 24) & 0xFF);
877a6d42e7dSPeter Dunlap 	byte1 = (uint8_t)((crc >> 16) & 0xFF);
878a6d42e7dSPeter Dunlap 	byte2 = (uint8_t)((crc >> 8) & 0xFF);
879a6d42e7dSPeter Dunlap 	byte3 = (uint8_t)(crc & 0xFF);
880a6d42e7dSPeter Dunlap 	crc = ((byte3 << 24) | (byte2 << 16) | (byte1 << 8) | byte0);
881a6d42e7dSPeter Dunlap #endif
882a6d42e7dSPeter Dunlap 
883a6d42e7dSPeter Dunlap 	crc = crc ^ 0xffffffff;
884a6d42e7dSPeter Dunlap 	while (length--) {
885a6d42e7dSPeter Dunlap 		crc = idm_crc32c_table[(crc ^ *buffer++) & 0xFFL] ^
886a6d42e7dSPeter Dunlap 		    (crc >> 8);
887a6d42e7dSPeter Dunlap 	}
888a6d42e7dSPeter Dunlap 	result = crc ^ 0xffffffff;
889a6d42e7dSPeter Dunlap 
890a6d42e7dSPeter Dunlap #ifdef	_BIG_ENDIAN
891a6d42e7dSPeter Dunlap 	byte0 = (uint8_t)(result & 0xFF);
892a6d42e7dSPeter Dunlap 	byte1 = (uint8_t)((result >> 8) & 0xFF);
893a6d42e7dSPeter Dunlap 	byte2 = (uint8_t)((result >> 16) & 0xFF);
894a6d42e7dSPeter Dunlap 	byte3 = (uint8_t)((result >> 24) & 0xFF);
895a6d42e7dSPeter Dunlap 	result = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3);
896a6d42e7dSPeter Dunlap #endif
897a6d42e7dSPeter Dunlap 	return (result);
898a6d42e7dSPeter Dunlap }
899a6d42e7dSPeter Dunlap 
900a6d42e7dSPeter Dunlap /* ARGSUSED */
901a6d42e7dSPeter Dunlap int
902a6d42e7dSPeter Dunlap idm_task_constructor(void *hdl, void *arg, int flags)
903a6d42e7dSPeter Dunlap {
904a6d42e7dSPeter Dunlap 	idm_task_t *idt = (idm_task_t *)hdl;
905a6d42e7dSPeter Dunlap 	uint32_t next_task;
906a6d42e7dSPeter Dunlap 
907a6d42e7dSPeter Dunlap 	mutex_init(&idt->idt_mutex, NULL, MUTEX_DEFAULT, NULL);
908a6d42e7dSPeter Dunlap 
909a6d42e7dSPeter Dunlap 	/* Find the next free task ID */
910a6d42e7dSPeter Dunlap 	rw_enter(&idm.idm_taskid_table_lock, RW_WRITER);
911a6d42e7dSPeter Dunlap 	next_task = idm.idm_taskid_next;
912a6d42e7dSPeter Dunlap 	while (idm.idm_taskid_table[next_task]) {
913a6d42e7dSPeter Dunlap 		next_task++;
914a6d42e7dSPeter Dunlap 		if (next_task == idm.idm_taskid_max)
915a6d42e7dSPeter Dunlap 			next_task = 0;
916a6d42e7dSPeter Dunlap 		if (next_task == idm.idm_taskid_next) {
917a6d42e7dSPeter Dunlap 			rw_exit(&idm.idm_taskid_table_lock);
918a6d42e7dSPeter Dunlap 			return (-1);
919a6d42e7dSPeter Dunlap 		}
920a6d42e7dSPeter Dunlap 	}
921a6d42e7dSPeter Dunlap 
922a6d42e7dSPeter Dunlap 	idm.idm_taskid_table[next_task] = idt;
923a6d42e7dSPeter Dunlap 	idm.idm_taskid_next = (next_task + 1) % idm.idm_taskid_max;
924a6d42e7dSPeter Dunlap 	rw_exit(&idm.idm_taskid_table_lock);
925a6d42e7dSPeter Dunlap 
926a6d42e7dSPeter Dunlap 	idt->idt_tt = next_task;
927a6d42e7dSPeter Dunlap 
928a6d42e7dSPeter Dunlap 	list_create(&idt->idt_inbufv, sizeof (idm_buf_t),
929a6d42e7dSPeter Dunlap 	    offsetof(idm_buf_t, idb_buflink));
930a6d42e7dSPeter Dunlap 	list_create(&idt->idt_outbufv, sizeof (idm_buf_t),
931a6d42e7dSPeter Dunlap 	    offsetof(idm_buf_t, idb_buflink));
932a6d42e7dSPeter Dunlap 	idm_refcnt_init(&idt->idt_refcnt, idt);
933a6d42e7dSPeter Dunlap 
934a6d42e7dSPeter Dunlap 	/*
935a6d42e7dSPeter Dunlap 	 * Set the transport header pointer explicitly.  This removes the
936a6d42e7dSPeter Dunlap 	 * need for per-transport header allocation, which simplifies cache
937a6d42e7dSPeter Dunlap 	 * init considerably.  If at a later date we have an additional IDM
938a6d42e7dSPeter Dunlap 	 * transport that requires a different size, we'll revisit this.
939a6d42e7dSPeter Dunlap 	 */
940a6d42e7dSPeter Dunlap 	idt->idt_transport_hdr = (void *)(idt + 1); /* pointer arithmetic */
941a6d42e7dSPeter Dunlap 
942a6d42e7dSPeter Dunlap 	return (0);
943a6d42e7dSPeter Dunlap }
944a6d42e7dSPeter Dunlap 
945a6d42e7dSPeter Dunlap /* ARGSUSED */
946a6d42e7dSPeter Dunlap void
947a6d42e7dSPeter Dunlap idm_task_destructor(void *hdl, void *arg)
948a6d42e7dSPeter Dunlap {
949a6d42e7dSPeter Dunlap 	idm_task_t *idt = (idm_task_t *)hdl;
950a6d42e7dSPeter Dunlap 
951a6d42e7dSPeter Dunlap 	/* Remove the task from the ID table */
952a6d42e7dSPeter Dunlap 	rw_enter(&idm.idm_taskid_table_lock, RW_WRITER);
953a6d42e7dSPeter Dunlap 	idm.idm_taskid_table[idt->idt_tt] = NULL;
954a6d42e7dSPeter Dunlap 	rw_exit(&idm.idm_taskid_table_lock);
955a6d42e7dSPeter Dunlap 
956a6d42e7dSPeter Dunlap 	/* free the inbuf and outbuf */
957a6d42e7dSPeter Dunlap 	idm_refcnt_destroy(&idt->idt_refcnt);
958a6d42e7dSPeter Dunlap 	list_destroy(&idt->idt_inbufv);
959a6d42e7dSPeter Dunlap 	list_destroy(&idt->idt_outbufv);
960a6d42e7dSPeter Dunlap 
961*30e7468fSPeter Dunlap 	/*
962*30e7468fSPeter Dunlap 	 * The final call to idm_task_rele may happen with the task
963*30e7468fSPeter Dunlap 	 * mutex held which may invoke this destructor immediately.
964*30e7468fSPeter Dunlap 	 * Stall here until the task mutex owner lets go.
965*30e7468fSPeter Dunlap 	 */
966*30e7468fSPeter Dunlap 	mutex_enter(&idt->idt_mutex);
967a6d42e7dSPeter Dunlap 	mutex_destroy(&idt->idt_mutex);
968a6d42e7dSPeter Dunlap }
969a6d42e7dSPeter Dunlap 
970a6d42e7dSPeter Dunlap /*
971a6d42e7dSPeter Dunlap  * idm_listbuf_insert searches from the back of the list looking for the
972a6d42e7dSPeter Dunlap  * insertion point.
973a6d42e7dSPeter Dunlap  */
974a6d42e7dSPeter Dunlap void
975a6d42e7dSPeter Dunlap idm_listbuf_insert(list_t *lst, idm_buf_t *buf)
976a6d42e7dSPeter Dunlap {
977a6d42e7dSPeter Dunlap 	idm_buf_t	*idb;
978a6d42e7dSPeter Dunlap 
979a6d42e7dSPeter Dunlap 	/* iterate through the list to find the insertion point */
980a6d42e7dSPeter Dunlap 	for (idb = list_tail(lst); idb != NULL; idb = list_prev(lst, idb)) {
981a6d42e7dSPeter Dunlap 
982a6d42e7dSPeter Dunlap 		if (idb->idb_bufoffset < buf->idb_bufoffset) {
983a6d42e7dSPeter Dunlap 
984a6d42e7dSPeter Dunlap 			list_insert_after(lst, idb, buf);
985a6d42e7dSPeter Dunlap 			return;
986a6d42e7dSPeter Dunlap 		}
987a6d42e7dSPeter Dunlap 	}
988a6d42e7dSPeter Dunlap 
989a6d42e7dSPeter Dunlap 	/* add the buf to the head of the list */
990a6d42e7dSPeter Dunlap 	list_insert_head(lst, buf);
991a6d42e7dSPeter Dunlap 
992a6d42e7dSPeter Dunlap }
993a6d42e7dSPeter Dunlap 
994a6d42e7dSPeter Dunlap /*ARGSUSED*/
995a6d42e7dSPeter Dunlap void
996a6d42e7dSPeter Dunlap idm_wd_thread(void *arg)
997a6d42e7dSPeter Dunlap {
998a6d42e7dSPeter Dunlap 	idm_conn_t	*ic;
999a6d42e7dSPeter Dunlap 	clock_t		wake_time;
1000a6d42e7dSPeter Dunlap 	clock_t		idle_time;
1001a6d42e7dSPeter Dunlap 
1002a41f9819SJames Moore 	/* Record the thread id for thread_join() */
1003a41f9819SJames Moore 	idm.idm_wd_thread_did = curthread->t_did;
1004a6d42e7dSPeter Dunlap 	mutex_enter(&idm.idm_global_mutex);
1005a6d42e7dSPeter Dunlap 	idm.idm_wd_thread_running = B_TRUE;
1006a6d42e7dSPeter Dunlap 	cv_signal(&idm.idm_wd_cv);
1007a6d42e7dSPeter Dunlap 
1008a6d42e7dSPeter Dunlap 	while (idm.idm_wd_thread_running) {
1009a6d42e7dSPeter Dunlap 		for (ic = list_head(&idm.idm_tgt_conn_list);
1010a6d42e7dSPeter Dunlap 		    ic != NULL;
1011a6d42e7dSPeter Dunlap 		    ic = list_next(&idm.idm_tgt_conn_list, ic)) {
1012a6d42e7dSPeter Dunlap 			idle_time = ddi_get_lbolt() - ic->ic_timestamp;
1013a6d42e7dSPeter Dunlap 
1014a6d42e7dSPeter Dunlap 			/*
1015a6d42e7dSPeter Dunlap 			 * If there hasn't been any activity on this
1016a6d42e7dSPeter Dunlap 			 * connection for the specified period then
1017a6d42e7dSPeter Dunlap 			 * drop the connection.  We expect the initiator
1018a6d42e7dSPeter Dunlap 			 * to keep the connection alive if it wants the
1019a6d42e7dSPeter Dunlap 			 * connection to stay open.
1020a6d42e7dSPeter Dunlap 			 *
1021a6d42e7dSPeter Dunlap 			 * If it turns out to be desireable to take a
1022a6d42e7dSPeter Dunlap 			 * more active role in maintaining the connect
1023a6d42e7dSPeter Dunlap 			 * we could add a client callback to send
1024a6d42e7dSPeter Dunlap 			 * a "keepalive" kind of message (no doubt a nop)
1025a6d42e7dSPeter Dunlap 			 * and fire that on a shorter timer.
1026a6d42e7dSPeter Dunlap 			 */
1027a6d42e7dSPeter Dunlap 			if (TICK_TO_SEC(idle_time) >
1028a6d42e7dSPeter Dunlap 			    IDM_TRANSPORT_FAIL_IDLE_TIMEOUT) {
1029a6d42e7dSPeter Dunlap 				/*
1030a6d42e7dSPeter Dunlap 				 * Only send the transport fail if we're in
1031a6d42e7dSPeter Dunlap 				 * FFP.  State machine timers should handle
1032a6d42e7dSPeter Dunlap 				 * problems in non-ffp states.
1033a6d42e7dSPeter Dunlap 				 */
1034a6d42e7dSPeter Dunlap 				if (ic->ic_ffp) {
1035a6d42e7dSPeter Dunlap 					mutex_exit(&idm.idm_global_mutex);
1036a6d42e7dSPeter Dunlap 					IDM_SM_LOG(CE_WARN, "idm_wd_thread: "
1037a6d42e7dSPeter Dunlap 					    "conn %p idle for %d seconds, "
1038a6d42e7dSPeter Dunlap 					    "sending CE_TRANSPORT_FAIL",
1039a6d42e7dSPeter Dunlap 					    (void *)ic, (int)idle_time);
1040a6d42e7dSPeter Dunlap 					idm_conn_event(ic, CE_TRANSPORT_FAIL,
1041a6d42e7dSPeter Dunlap 					    NULL);
1042a6d42e7dSPeter Dunlap 					mutex_enter(&idm.idm_global_mutex);
1043a6d42e7dSPeter Dunlap 				}
1044a6d42e7dSPeter Dunlap 			}
1045a6d42e7dSPeter Dunlap 		}
1046a6d42e7dSPeter Dunlap 
1047a6d42e7dSPeter Dunlap 		wake_time = lbolt + SEC_TO_TICK(IDM_WD_INTERVAL);
1048a6d42e7dSPeter Dunlap 		(void) cv_timedwait(&idm.idm_wd_cv, &idm.idm_global_mutex,
1049a6d42e7dSPeter Dunlap 		    wake_time);
1050a6d42e7dSPeter Dunlap 	}
1051a6d42e7dSPeter Dunlap 	mutex_exit(&idm.idm_global_mutex);
1052a6d42e7dSPeter Dunlap 
1053a6d42e7dSPeter Dunlap 	thread_exit();
1054a6d42e7dSPeter Dunlap }
1055