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