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  */
21483b029bSYuri Pankov 
22a6d42e7dSPeter Dunlap /*
234558d122SViswanathan Kannappan  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
241ef61828SYuri Pankov  * Copyright 2016 Nexenta Systems, Inc.
25a6d42e7dSPeter Dunlap  */
26a6d42e7dSPeter Dunlap 
27a6d42e7dSPeter Dunlap #include <sys/cpuvar.h>
28a6d42e7dSPeter Dunlap #include <sys/types.h>
29a6d42e7dSPeter Dunlap #include <sys/conf.h>
30a6d42e7dSPeter Dunlap #include <sys/file.h>
31a6d42e7dSPeter Dunlap #include <sys/ddi.h>
32a6d42e7dSPeter Dunlap #include <sys/sunddi.h>
33a6d42e7dSPeter Dunlap #include <sys/modctl.h>
34716c1805SNattuvetty Bhavyan #include <sys/scsi/generic/persist.h>
351ef61828SYuri Pankov #include <sys/scsi/scsi_names.h>
36a6d42e7dSPeter Dunlap 
37a6d42e7dSPeter Dunlap #include <sys/socket.h>
38a6d42e7dSPeter Dunlap #include <sys/strsubr.h>
39a6d42e7dSPeter Dunlap #include <sys/sysmacros.h>
40a6d42e7dSPeter Dunlap #include <sys/note.h>
41a6d42e7dSPeter Dunlap #include <sys/sdt.h>
421ef61828SYuri Pankov #include <sys/errno.h>
43a6d42e7dSPeter Dunlap 
44a6d42e7dSPeter Dunlap #include <sys/stmf.h>
45a6d42e7dSPeter Dunlap #include <sys/stmf_ioctl.h>
46a6d42e7dSPeter Dunlap #include <sys/portif.h>
47a6d42e7dSPeter Dunlap #include <sys/idm/idm.h>
48a6d42e7dSPeter Dunlap #include <sys/idm/idm_text.h>
49*61dfa509SRick McNeal #include <sys/idm/idm_so.h>
50a6d42e7dSPeter Dunlap 
51a6d42e7dSPeter Dunlap #define	ISCSIT_LOGIN_SM_STRINGS
524558d122SViswanathan Kannappan #include "iscsit.h"
534558d122SViswanathan Kannappan #include "iscsit_auth.h"
54a6d42e7dSPeter Dunlap 
55a6d42e7dSPeter Dunlap typedef struct {
56a6d42e7dSPeter Dunlap 	list_node_t		le_ctx_node;
57a6d42e7dSPeter Dunlap 	iscsit_login_event_t	le_ctx_event;
58a6d42e7dSPeter Dunlap 	idm_pdu_t		*le_pdu;
59a6d42e7dSPeter Dunlap } login_event_ctx_t;
60a6d42e7dSPeter Dunlap 
61a6d42e7dSPeter Dunlap #ifndef TRUE
62a6d42e7dSPeter Dunlap #define	TRUE B_TRUE
63a6d42e7dSPeter Dunlap #endif
64a6d42e7dSPeter Dunlap 
65a6d42e7dSPeter Dunlap #ifndef FALSE
66a6d42e7dSPeter Dunlap #define	FALSE B_FALSE
67a6d42e7dSPeter Dunlap #endif
68a6d42e7dSPeter Dunlap 
69a6d42e7dSPeter Dunlap #define	DEFAULT_RADIUS_PORT	1812
70a6d42e7dSPeter Dunlap 
71a6d42e7dSPeter Dunlap static void
72a6d42e7dSPeter Dunlap login_sm_complete(void *ict_void);
73a6d42e7dSPeter Dunlap 
74a6d42e7dSPeter Dunlap static void
75a6d42e7dSPeter Dunlap login_sm_event_dispatch(iscsit_conn_login_t *lsm, iscsit_conn_t *ict,
76a6d42e7dSPeter Dunlap     login_event_ctx_t *ctx);
77a6d42e7dSPeter Dunlap 
78a6d42e7dSPeter Dunlap static void
79a6d42e7dSPeter Dunlap login_sm_init(iscsit_conn_t *ict, login_event_ctx_t *ctx);
80a6d42e7dSPeter Dunlap 
81a6d42e7dSPeter Dunlap static void
82a6d42e7dSPeter Dunlap login_sm_waiting(iscsit_conn_t *ict, login_event_ctx_t *ctx);
83a6d42e7dSPeter Dunlap 
84a6d42e7dSPeter Dunlap static void
85a6d42e7dSPeter Dunlap login_sm_processing(iscsit_conn_t *ict, login_event_ctx_t *ctx);
86a6d42e7dSPeter Dunlap 
87a6d42e7dSPeter Dunlap static void
88a6d42e7dSPeter Dunlap login_sm_responding(iscsit_conn_t *ict, login_event_ctx_t *ctx);
89a6d42e7dSPeter Dunlap 
90a6d42e7dSPeter Dunlap static void
91a6d42e7dSPeter Dunlap login_sm_responded(iscsit_conn_t *ict, login_event_ctx_t *ctx);
92a6d42e7dSPeter Dunlap 
93a6d42e7dSPeter Dunlap static void
94a6d42e7dSPeter Dunlap login_sm_ffp(iscsit_conn_t *ict, login_event_ctx_t *ctx);
95a6d42e7dSPeter Dunlap 
96a6d42e7dSPeter Dunlap static void
97a6d42e7dSPeter Dunlap login_sm_done(iscsit_conn_t *ict, login_event_ctx_t *ctx);
98a6d42e7dSPeter Dunlap 
99a6d42e7dSPeter Dunlap static void
100a6d42e7dSPeter Dunlap login_sm_error(iscsit_conn_t *ict, login_event_ctx_t *ctx);
101a6d42e7dSPeter Dunlap 
102a6d42e7dSPeter Dunlap static void
103a6d42e7dSPeter Dunlap login_sm_new_state(iscsit_conn_t *ict, login_event_ctx_t *ctx,
104a6d42e7dSPeter Dunlap     iscsit_login_state_t new_state);
105a6d42e7dSPeter Dunlap 
106a6d42e7dSPeter Dunlap static void
107a6d42e7dSPeter Dunlap login_sm_send_ack(iscsit_conn_t *ict, idm_pdu_t *pdu);
108a6d42e7dSPeter Dunlap 
109a6d42e7dSPeter Dunlap static idm_status_t
110a6d42e7dSPeter Dunlap login_sm_validate_ack(iscsit_conn_t *ict, idm_pdu_t *pdu);
111a6d42e7dSPeter Dunlap 
112a6d42e7dSPeter Dunlap static boolean_t
1134142b486SJames Moore login_sm_is_last_response(idm_pdu_t *pdu);
114a6d42e7dSPeter Dunlap 
115a6d42e7dSPeter Dunlap static void
116a6d42e7dSPeter Dunlap login_sm_handle_initial_login(iscsit_conn_t *ict, idm_pdu_t *pdu);
117a6d42e7dSPeter Dunlap 
118a6d42e7dSPeter Dunlap static void
1194142b486SJames Moore login_sm_send_next_response(iscsit_conn_t *ict, idm_pdu_t *pdu);
120a6d42e7dSPeter Dunlap 
121a6d42e7dSPeter Dunlap static void
122a6d42e7dSPeter Dunlap login_sm_process_request(iscsit_conn_t *ict);
123a6d42e7dSPeter Dunlap 
124a6d42e7dSPeter Dunlap static idm_status_t
125a6d42e7dSPeter Dunlap login_sm_req_pdu_check(iscsit_conn_t *ict, idm_pdu_t *pdu);
126a6d42e7dSPeter Dunlap 
127a6d42e7dSPeter Dunlap static idm_status_t
128a6d42e7dSPeter Dunlap login_sm_process_nvlist(iscsit_conn_t *ict);
129a6d42e7dSPeter Dunlap 
130a6d42e7dSPeter Dunlap static idm_status_t
131a6d42e7dSPeter Dunlap login_sm_check_security(iscsit_conn_t *ict);
132a6d42e7dSPeter Dunlap 
1334142b486SJames Moore static idm_pdu_t *
134a6d42e7dSPeter Dunlap login_sm_build_login_response(iscsit_conn_t *ict);
135a6d42e7dSPeter Dunlap 
136a6d42e7dSPeter Dunlap static void
137a6d42e7dSPeter Dunlap login_sm_ffp_actions(iscsit_conn_t *ict);
138a6d42e7dSPeter Dunlap 
139a6d42e7dSPeter Dunlap static idm_status_t
140a6d42e7dSPeter Dunlap login_sm_validate_initial_parameters(iscsit_conn_t *ict);
141a6d42e7dSPeter Dunlap 
142a6d42e7dSPeter Dunlap static idm_status_t
143a6d42e7dSPeter Dunlap login_sm_session_bind(iscsit_conn_t *ict);
144a6d42e7dSPeter Dunlap 
145a6d42e7dSPeter Dunlap static idm_status_t
146a6d42e7dSPeter Dunlap login_sm_set_auth(iscsit_conn_t *ict);
147a6d42e7dSPeter Dunlap 
148a6d42e7dSPeter Dunlap static idm_status_t
149a6d42e7dSPeter Dunlap login_sm_session_register(iscsit_conn_t *ict);
150a6d42e7dSPeter Dunlap 
151a6d42e7dSPeter Dunlap static kv_status_t
152a6d42e7dSPeter Dunlap iscsit_handle_key(iscsit_conn_t *ict, nvpair_t *nvp, char *nvp_name);
153a6d42e7dSPeter Dunlap 
154a6d42e7dSPeter Dunlap static kv_status_t
155a6d42e7dSPeter Dunlap iscsit_handle_common_key(iscsit_conn_t *ict, nvpair_t *nvp,
156a6d42e7dSPeter Dunlap     const idm_kv_xlate_t *ikvx);
157a6d42e7dSPeter Dunlap 
158a6d42e7dSPeter Dunlap static kv_status_t
159a6d42e7dSPeter Dunlap iscsit_handle_security_key(iscsit_conn_t *ict, nvpair_t *nvp,
160a6d42e7dSPeter Dunlap     const idm_kv_xlate_t *ikvx);
161a6d42e7dSPeter Dunlap 
162a6d42e7dSPeter Dunlap static kv_status_t
163a6d42e7dSPeter Dunlap iscsit_reply_security_key(iscsit_conn_t *ict);
164a6d42e7dSPeter Dunlap 
165a6d42e7dSPeter Dunlap static kv_status_t
166a6d42e7dSPeter Dunlap iscsit_handle_operational_key(iscsit_conn_t *ict, nvpair_t *nvp,
167a6d42e7dSPeter Dunlap     const idm_kv_xlate_t *ikvx);
168a6d42e7dSPeter Dunlap 
169a6d42e7dSPeter Dunlap static kv_status_t
170a6d42e7dSPeter Dunlap iscsit_reply_numerical(iscsit_conn_t *ict,
171a6d42e7dSPeter Dunlap     const char *nvp_name, const uint64_t value);
172a6d42e7dSPeter Dunlap 
173a6d42e7dSPeter Dunlap static kv_status_t
174a6d42e7dSPeter Dunlap iscsit_reply_string(iscsit_conn_t *ict,
175a6d42e7dSPeter Dunlap     const char *nvp_name, const char *text);
176a6d42e7dSPeter Dunlap 
177a6d42e7dSPeter Dunlap static kv_status_t
178a6d42e7dSPeter Dunlap iscsit_handle_digest(iscsit_conn_t *ict, nvpair_t *choices,
179a6d42e7dSPeter Dunlap     const idm_kv_xlate_t *ikvx);
180a6d42e7dSPeter Dunlap 
181a6d42e7dSPeter Dunlap static kv_status_t
182a6d42e7dSPeter Dunlap iscsit_handle_boolean(iscsit_conn_t *ict, nvpair_t *nvp, boolean_t value,
183a6d42e7dSPeter Dunlap     const idm_kv_xlate_t *ikvx, boolean_t iscsit_value);
184a6d42e7dSPeter Dunlap 
185a6d42e7dSPeter Dunlap static kv_status_t
186a6d42e7dSPeter Dunlap iscsit_handle_numerical(iscsit_conn_t *ict, nvpair_t *nvp, uint64_t value,
187a6d42e7dSPeter Dunlap     const idm_kv_xlate_t *ikvx,
188a6d42e7dSPeter Dunlap     uint64_t iscsi_min_value, uint64_t iscsi_max_value,
189a6d42e7dSPeter Dunlap     uint64_t iscsit_max_value);
190a6d42e7dSPeter Dunlap 
191a6d42e7dSPeter Dunlap static void
192a6d42e7dSPeter Dunlap iscsit_process_negotiated_values(iscsit_conn_t *ict);
193a6d42e7dSPeter Dunlap 
194a6d42e7dSPeter Dunlap static void
195a6d42e7dSPeter Dunlap login_resp_complete_cb(idm_pdu_t *pdu, idm_status_t status);
196a6d42e7dSPeter Dunlap 
19756261083SCharles Ting static idm_status_t
19856261083SCharles Ting iscsit_add_declarative_keys(iscsit_conn_t *ict);
19956261083SCharles Ting 
2001ef61828SYuri Pankov static char *
2011ef61828SYuri Pankov iscsit_fold_name(char *name, size_t *buflen);
2021ef61828SYuri Pankov 
20356261083SCharles Ting uint64_t max_dataseglen_target = ISCSIT_MAX_RECV_DATA_SEGMENT_LENGTH;
20456261083SCharles Ting 
2053fc1e17eSPriya Krishnan /*
2063fc1e17eSPriya Krishnan  * global mutex defined in iscsit.c to enforce
2073fc1e17eSPriya Krishnan  * login_sm_session_bind as a critical section
2083fc1e17eSPriya Krishnan  */
2093fc1e17eSPriya Krishnan extern kmutex_t login_sm_session_mutex;
2103fc1e17eSPriya Krishnan 
211a6d42e7dSPeter Dunlap idm_status_t
iscsit_login_sm_init(iscsit_conn_t * ict)212a6d42e7dSPeter Dunlap iscsit_login_sm_init(iscsit_conn_t *ict)
213a6d42e7dSPeter Dunlap {
214a6d42e7dSPeter Dunlap 	iscsit_conn_login_t *lsm = &ict->ict_login_sm;
215a6d42e7dSPeter Dunlap 
216a6d42e7dSPeter Dunlap 	bzero(lsm, sizeof (iscsit_conn_login_t));
217a6d42e7dSPeter Dunlap 
218a6d42e7dSPeter Dunlap 	(void) nvlist_alloc(&lsm->icl_negotiated_values, NV_UNIQUE_NAME,
219a6d42e7dSPeter Dunlap 	    KM_SLEEP);
220a6d42e7dSPeter Dunlap 
221a6d42e7dSPeter Dunlap 	/*
222a6d42e7dSPeter Dunlap 	 * Hold connection until the login state machine completes
223a6d42e7dSPeter Dunlap 	 */
224a6d42e7dSPeter Dunlap 	iscsit_conn_hold(ict);
225a6d42e7dSPeter Dunlap 
226a6d42e7dSPeter Dunlap 	/*
227a6d42e7dSPeter Dunlap 	 * Pre-allocating a login response PDU means we will always be
228a6d42e7dSPeter Dunlap 	 * able to respond to a login request -- even if we can't allocate
229a6d42e7dSPeter Dunlap 	 * a data buffer to hold the text responses we can at least send
230a6d42e7dSPeter Dunlap 	 * a login failure.
231a6d42e7dSPeter Dunlap 	 */
232a6d42e7dSPeter Dunlap 	lsm->icl_login_resp_tmpl = kmem_zalloc(sizeof (iscsi_login_rsp_hdr_t),
233a6d42e7dSPeter Dunlap 	    KM_SLEEP);
234a6d42e7dSPeter Dunlap 
235a6d42e7dSPeter Dunlap 	idm_sm_audit_init(&lsm->icl_state_audit);
236a6d42e7dSPeter Dunlap 	mutex_init(&lsm->icl_mutex, NULL, MUTEX_DEFAULT, NULL);
237a6d42e7dSPeter Dunlap 	list_create(&lsm->icl_login_events, sizeof (login_event_ctx_t),
238a6d42e7dSPeter Dunlap 	    offsetof(login_event_ctx_t, le_ctx_node));
239a6d42e7dSPeter Dunlap 	list_create(&lsm->icl_pdu_list, sizeof (idm_pdu_t),
240a6d42e7dSPeter Dunlap 	    offsetof(idm_pdu_t, isp_client_lnd));
241a6d42e7dSPeter Dunlap 
242a6d42e7dSPeter Dunlap 	lsm->icl_login_state = ILS_LOGIN_INIT;
243a6d42e7dSPeter Dunlap 	lsm->icl_login_last_state = ILS_LOGIN_INIT;
244a6d42e7dSPeter Dunlap 
245a6d42e7dSPeter Dunlap 	/*
246a6d42e7dSPeter Dunlap 	 * Initialize operational parameters to default values.  Anything
247a6d42e7dSPeter Dunlap 	 * we don't specifically negotiate stays at the default.
248a6d42e7dSPeter Dunlap 	 */
249a6d42e7dSPeter Dunlap 	ict->ict_op.op_discovery_session = B_FALSE;
250a6d42e7dSPeter Dunlap 	ict->ict_op.op_initial_r2t = ISCSI_DEFAULT_INITIALR2T;
251a6d42e7dSPeter Dunlap 	ict->ict_op.op_immed_data = ISCSI_DEFAULT_IMMEDIATE_DATA;
252a6d42e7dSPeter Dunlap 	ict->ict_op.op_data_pdu_in_order = ISCSI_DEFAULT_DATA_PDU_IN_ORDER;
253a6d42e7dSPeter Dunlap 	ict->ict_op.op_data_sequence_in_order =
254a6d42e7dSPeter Dunlap 	    ISCSI_DEFAULT_DATA_SEQUENCE_IN_ORDER;
255a6d42e7dSPeter Dunlap 	ict->ict_op.op_max_connections = ISCSI_DEFAULT_MAX_CONNECTIONS;
256a6d42e7dSPeter Dunlap 	ict->ict_op.op_max_recv_data_segment_length =
257a6d42e7dSPeter Dunlap 	    ISCSI_DEFAULT_MAX_RECV_SEG_LEN;
258a6d42e7dSPeter Dunlap 	ict->ict_op.op_max_burst_length = ISCSI_DEFAULT_MAX_BURST_LENGTH;
259a6d42e7dSPeter Dunlap 	ict->ict_op.op_first_burst_length = ISCSI_DEFAULT_FIRST_BURST_LENGTH;
260a6d42e7dSPeter Dunlap 	ict->ict_op.op_default_time_2_wait = ISCSI_DEFAULT_TIME_TO_WAIT;
261a6d42e7dSPeter Dunlap 	ict->ict_op.op_default_time_2_retain = ISCSI_DEFAULT_TIME_TO_RETAIN;
262a6d42e7dSPeter Dunlap 	ict->ict_op.op_max_outstanding_r2t = ISCSI_DEFAULT_MAX_OUT_R2T;
263a6d42e7dSPeter Dunlap 	ict->ict_op.op_error_recovery_level =
264a6d42e7dSPeter Dunlap 	    ISCSI_DEFAULT_ERROR_RECOVERY_LEVEL;
265a6d42e7dSPeter Dunlap 
266a6d42e7dSPeter Dunlap 	return (IDM_STATUS_SUCCESS);
267a6d42e7dSPeter Dunlap }
268a6d42e7dSPeter Dunlap 
269a6d42e7dSPeter Dunlap static void
login_resp_complete_cb(idm_pdu_t * pdu,idm_status_t status)270a6d42e7dSPeter Dunlap login_resp_complete_cb(idm_pdu_t *pdu, idm_status_t status)
271a6d42e7dSPeter Dunlap {
272a6d42e7dSPeter Dunlap 	iscsit_conn_t *ict = pdu->isp_private;
273a6d42e7dSPeter Dunlap 
274a6d42e7dSPeter Dunlap 	/*
2754142b486SJames Moore 	 * Check that this is a login pdu
276a6d42e7dSPeter Dunlap 	 */
277a6d42e7dSPeter Dunlap 	ASSERT((pdu->isp_flags & IDM_PDU_LOGIN_TX) != 0);
2784142b486SJames Moore 	idm_pdu_free(pdu);
279a6d42e7dSPeter Dunlap 
280a6d42e7dSPeter Dunlap 	if ((status != IDM_STATUS_SUCCESS) ||
281a6d42e7dSPeter Dunlap 	    (ict->ict_login_sm.icl_login_resp_err_class != 0)) {
2824142b486SJames Moore 		/*
2834142b486SJames Moore 		 * Transport or login error occurred.
2844142b486SJames Moore 		 */
285a6d42e7dSPeter Dunlap 		iscsit_login_sm_event(ict, ILE_LOGIN_ERROR, NULL);
286a6d42e7dSPeter Dunlap 	}
2874142b486SJames Moore 	iscsit_conn_rele(ict);
288a6d42e7dSPeter Dunlap }
289a6d42e7dSPeter Dunlap 
290a6d42e7dSPeter Dunlap void
iscsit_login_sm_fini(iscsit_conn_t * ict)291a6d42e7dSPeter Dunlap iscsit_login_sm_fini(iscsit_conn_t *ict)
292a6d42e7dSPeter Dunlap {
293a6d42e7dSPeter Dunlap 	iscsit_conn_login_t *lsm = &ict->ict_login_sm;
294a6d42e7dSPeter Dunlap 
295a6d42e7dSPeter Dunlap 	mutex_enter(&lsm->icl_mutex);
296a6d42e7dSPeter Dunlap 	list_destroy(&lsm->icl_pdu_list);
297a6d42e7dSPeter Dunlap 	list_destroy(&lsm->icl_login_events);
298a6d42e7dSPeter Dunlap 
299a6d42e7dSPeter Dunlap 	kmem_free(lsm->icl_login_resp_tmpl, sizeof (iscsi_login_rsp_hdr_t));
300a6d42e7dSPeter Dunlap 
301a6d42e7dSPeter Dunlap 	/* clean up the login response idm text buffer */
302a6d42e7dSPeter Dunlap 	if (lsm->icl_login_resp_itb != NULL) {
303a6d42e7dSPeter Dunlap 		idm_itextbuf_free(lsm->icl_login_resp_itb);
304a6d42e7dSPeter Dunlap 		lsm->icl_login_resp_itb = NULL;
305a6d42e7dSPeter Dunlap 	}
306a6d42e7dSPeter Dunlap 
307a6d42e7dSPeter Dunlap 	nvlist_free(lsm->icl_negotiated_values);
3084142b486SJames Moore 	mutex_destroy(&lsm->icl_mutex);
309a6d42e7dSPeter Dunlap }
310a6d42e7dSPeter Dunlap 
311a6d42e7dSPeter Dunlap void
iscsit_login_sm_event(iscsit_conn_t * ict,iscsit_login_event_t event,idm_pdu_t * pdu)312a6d42e7dSPeter Dunlap iscsit_login_sm_event(iscsit_conn_t *ict, iscsit_login_event_t event,
313a6d42e7dSPeter Dunlap     idm_pdu_t *pdu)
314a6d42e7dSPeter Dunlap {
315a6d42e7dSPeter Dunlap 	/*
316a6d42e7dSPeter Dunlap 	 * This is a bit ugly but if we're already in ILS_LOGIN_ERROR
317a6d42e7dSPeter Dunlap 	 * or ILS_LOGIN_DONE then just drop any additional events.  They
318a6d42e7dSPeter Dunlap 	 * won't change the state and it's possible we've already called
319a6d42e7dSPeter Dunlap 	 * iscsit_login_sm_fini in which case the mutex is destroyed.
320a6d42e7dSPeter Dunlap 	 */
321a6d42e7dSPeter Dunlap 	if ((ict->ict_login_sm.icl_login_state == ILS_LOGIN_ERROR) ||
322a6d42e7dSPeter Dunlap 	    (ict->ict_login_sm.icl_login_state == ILS_LOGIN_DONE))
323a6d42e7dSPeter Dunlap 		return;
324a6d42e7dSPeter Dunlap 
325a6d42e7dSPeter Dunlap 	mutex_enter(&ict->ict_login_sm.icl_mutex);
326a6d42e7dSPeter Dunlap 	iscsit_login_sm_event_locked(ict, event, pdu);
327a6d42e7dSPeter Dunlap 	mutex_exit(&ict->ict_login_sm.icl_mutex);
328a6d42e7dSPeter Dunlap }
329a6d42e7dSPeter Dunlap void
iscsit_login_sm_event_locked(iscsit_conn_t * ict,iscsit_login_event_t event,idm_pdu_t * pdu)330a6d42e7dSPeter Dunlap iscsit_login_sm_event_locked(iscsit_conn_t *ict, iscsit_login_event_t event,
331a6d42e7dSPeter Dunlap     idm_pdu_t *pdu)
332a6d42e7dSPeter Dunlap {
333a6d42e7dSPeter Dunlap 	iscsit_conn_login_t *lsm = &ict->ict_login_sm;
334a6d42e7dSPeter Dunlap 	login_event_ctx_t *ctx;
335a6d42e7dSPeter Dunlap 
3364142b486SJames Moore 	ASSERT(mutex_owned(&lsm->icl_mutex));
337a6d42e7dSPeter Dunlap 	ctx = kmem_zalloc(sizeof (*ctx), KM_SLEEP);
338a6d42e7dSPeter Dunlap 
339a6d42e7dSPeter Dunlap 	ctx->le_ctx_event = event;
340a6d42e7dSPeter Dunlap 	ctx->le_pdu = pdu;
341a6d42e7dSPeter Dunlap 
342a6d42e7dSPeter Dunlap 	list_insert_tail(&lsm->icl_login_events, ctx);
343a6d42e7dSPeter Dunlap 
344a6d42e7dSPeter Dunlap 	/*
345a6d42e7dSPeter Dunlap 	 * Use the icl_busy flag to keep the state machine single threaded.
346a6d42e7dSPeter Dunlap 	 * This also serves as recursion avoidance since this flag will
347a6d42e7dSPeter Dunlap 	 * always be set if we call login_sm_event from within the
348a6d42e7dSPeter Dunlap 	 * state machine code.
349a6d42e7dSPeter Dunlap 	 */
350a6d42e7dSPeter Dunlap 	if (!lsm->icl_busy) {
351a6d42e7dSPeter Dunlap 		lsm->icl_busy = B_TRUE;
352a6d42e7dSPeter Dunlap 		while (!list_is_empty(&lsm->icl_login_events)) {
353a6d42e7dSPeter Dunlap 			ctx = list_head(&lsm->icl_login_events);
354a6d42e7dSPeter Dunlap 			list_remove(&lsm->icl_login_events, ctx);
355a6d42e7dSPeter Dunlap 			idm_sm_audit_event(&lsm->icl_state_audit,
356a6d42e7dSPeter Dunlap 			    SAS_ISCSIT_LOGIN, (int)lsm->icl_login_state,
357a6d42e7dSPeter Dunlap 			    (int)ctx->le_ctx_event, (uintptr_t)pdu);
358a6d42e7dSPeter Dunlap 
35930e7468fSPeter Dunlap 			/*
36030e7468fSPeter Dunlap 			 * If the lsm is in a terminal state, just drain
36130e7468fSPeter Dunlap 			 * any remaining events.
36230e7468fSPeter Dunlap 			 */
36330e7468fSPeter Dunlap 			if ((lsm->icl_login_state == ILS_LOGIN_ERROR) ||
36430e7468fSPeter Dunlap 			    (lsm->icl_login_state == ILS_LOGIN_DONE)) {
36530e7468fSPeter Dunlap 				kmem_free(ctx, sizeof (*ctx));
36630e7468fSPeter Dunlap 				continue;
36730e7468fSPeter Dunlap 			}
368a6d42e7dSPeter Dunlap 			mutex_exit(&lsm->icl_mutex);
369a6d42e7dSPeter Dunlap 			login_sm_event_dispatch(lsm, ict, ctx);
370a6d42e7dSPeter Dunlap 			mutex_enter(&lsm->icl_mutex);
371a6d42e7dSPeter Dunlap 		}
372a6d42e7dSPeter Dunlap 		lsm->icl_busy = B_FALSE;
373a6d42e7dSPeter Dunlap 
374a6d42e7dSPeter Dunlap 		/*
375a6d42e7dSPeter Dunlap 		 * When the state machine reaches ILS_LOGIN_DONE or
376a6d42e7dSPeter Dunlap 		 * ILS_LOGIN_ERROR state the login process has completed
377a6d42e7dSPeter Dunlap 		 * and it's time to cleanup.  The state machine code will
378a6d42e7dSPeter Dunlap 		 * mark itself "complete" when this happens.
379a6d42e7dSPeter Dunlap 		 *
380a6d42e7dSPeter Dunlap 		 * To protect against spurious events (which shouldn't
381a6d42e7dSPeter Dunlap 		 * happen) set icl_busy again.
382a6d42e7dSPeter Dunlap 		 */
383a6d42e7dSPeter Dunlap 		if (lsm->icl_login_complete) {
384a6d42e7dSPeter Dunlap 			lsm->icl_busy = B_TRUE;
385a6d42e7dSPeter Dunlap 			if (taskq_dispatch(iscsit_global.global_dispatch_taskq,
386fc8ae2ecSToomas Soome 			    login_sm_complete, ict, DDI_SLEEP) ==
387fc8ae2ecSToomas Soome 			    TASKQID_INVALID) {
388a6d42e7dSPeter Dunlap 				cmn_err(CE_WARN, "iscsit_login_sm_event_locked:"
389a6d42e7dSPeter Dunlap 				    " Failed to dispatch task");
390a6d42e7dSPeter Dunlap 			}
391a6d42e7dSPeter Dunlap 		}
392a6d42e7dSPeter Dunlap 	}
393a6d42e7dSPeter Dunlap }
394a6d42e7dSPeter Dunlap 
395a6d42e7dSPeter Dunlap static void
login_sm_complete(void * ict_void)396a6d42e7dSPeter Dunlap login_sm_complete(void *ict_void)
397a6d42e7dSPeter Dunlap {
398a6d42e7dSPeter Dunlap 	iscsit_conn_t *ict = ict_void;
399a6d42e7dSPeter Dunlap 
400a6d42e7dSPeter Dunlap 	/*
4014142b486SJames Moore 	 * State machine has run to completion, resources
4024142b486SJames Moore 	 * will be cleaned up when connection is destroyed.
403a6d42e7dSPeter Dunlap 	 */
4044142b486SJames Moore 	iscsit_conn_rele(ict);
405a6d42e7dSPeter Dunlap }
406a6d42e7dSPeter Dunlap 
407a6d42e7dSPeter Dunlap static void
login_sm_event_dispatch(iscsit_conn_login_t * lsm,iscsit_conn_t * ict,login_event_ctx_t * ctx)408a6d42e7dSPeter Dunlap login_sm_event_dispatch(iscsit_conn_login_t *lsm, iscsit_conn_t *ict,
409a6d42e7dSPeter Dunlap     login_event_ctx_t *ctx)
410a6d42e7dSPeter Dunlap {
411a6d42e7dSPeter Dunlap 	idm_pdu_t *pdu = ctx->le_pdu; /* Only valid for some events */
412a6d42e7dSPeter Dunlap 
413a6d42e7dSPeter Dunlap 	DTRACE_PROBE2(login__event, iscsit_conn_t *, ict,
414a6d42e7dSPeter Dunlap 	    login_event_ctx_t *, ctx);
415a6d42e7dSPeter Dunlap 
416a6d42e7dSPeter Dunlap 	IDM_SM_LOG(CE_NOTE, "login_sm_event_dispatch: ict %p event %s(%d)",
417a6d42e7dSPeter Dunlap 	    (void *)ict,
418a6d42e7dSPeter Dunlap 	    iscsit_ile_name[ctx->le_ctx_event], ctx->le_ctx_event);
419a6d42e7dSPeter Dunlap 
420a6d42e7dSPeter Dunlap 	/* State independent actions */
421a6d42e7dSPeter Dunlap 	switch (ctx->le_ctx_event) {
422a6d42e7dSPeter Dunlap 	case ILE_LOGIN_RCV:
423a6d42e7dSPeter Dunlap 		/* Perform basic sanity checks on the header */
424a6d42e7dSPeter Dunlap 		if (login_sm_req_pdu_check(ict, pdu) != IDM_STATUS_SUCCESS) {
4254142b486SJames Moore 			idm_pdu_t *rpdu;
4264142b486SJames Moore 
427a6d42e7dSPeter Dunlap 			SET_LOGIN_ERROR(ict, ISCSI_STATUS_CLASS_INITIATOR_ERR,
428a6d42e7dSPeter Dunlap 			    ISCSI_LOGIN_STATUS_INVALID_REQUEST);
429a6d42e7dSPeter Dunlap 			/*
430a6d42e7dSPeter Dunlap 			 * If we haven't processed any PDU's yet then use
431a6d42e7dSPeter Dunlap 			 * this one as a template for the response
432a6d42e7dSPeter Dunlap 			 */
433a6d42e7dSPeter Dunlap 			if (ict->ict_login_sm.icl_login_resp_tmpl->opcode == 0)
434a6d42e7dSPeter Dunlap 				login_sm_handle_initial_login(ict, pdu);
4354142b486SJames Moore 			rpdu = login_sm_build_login_response(ict);
4364142b486SJames Moore 			login_sm_send_next_response(ict, rpdu);
437a6d42e7dSPeter Dunlap 			idm_pdu_complete(pdu, IDM_STATUS_SUCCESS);
43830e7468fSPeter Dunlap 			kmem_free(ctx, sizeof (*ctx));
439a6d42e7dSPeter Dunlap 			return;
440a6d42e7dSPeter Dunlap 		}
441a6d42e7dSPeter Dunlap 		break;
442a6d42e7dSPeter Dunlap 	default:
443a6d42e7dSPeter Dunlap 		break;
444a6d42e7dSPeter Dunlap 	}
445a6d42e7dSPeter Dunlap 
446a6d42e7dSPeter Dunlap 	/* State dependent actions */
447a6d42e7dSPeter Dunlap 	switch (lsm->icl_login_state) {
448a6d42e7dSPeter Dunlap 	case ILS_LOGIN_INIT:
449a6d42e7dSPeter Dunlap 		login_sm_init(ict, ctx);
450a6d42e7dSPeter Dunlap 		break;
451a6d42e7dSPeter Dunlap 	case ILS_LOGIN_WAITING:
452a6d42e7dSPeter Dunlap 		login_sm_waiting(ict, ctx);
453a6d42e7dSPeter Dunlap 		break;
454a6d42e7dSPeter Dunlap 	case ILS_LOGIN_PROCESSING:
455a6d42e7dSPeter Dunlap 		login_sm_processing(ict, ctx);
456a6d42e7dSPeter Dunlap 		break;
457a6d42e7dSPeter Dunlap 	case ILS_LOGIN_RESPONDING:
458a6d42e7dSPeter Dunlap 		login_sm_responding(ict, ctx);
459a6d42e7dSPeter Dunlap 		break;
460a6d42e7dSPeter Dunlap 	case ILS_LOGIN_RESPONDED:
461a6d42e7dSPeter Dunlap 		login_sm_responded(ict, ctx);
462a6d42e7dSPeter Dunlap 		break;
463a6d42e7dSPeter Dunlap 	case ILS_LOGIN_FFP:
464a6d42e7dSPeter Dunlap 		login_sm_ffp(ict, ctx);
465a6d42e7dSPeter Dunlap 		break;
466a6d42e7dSPeter Dunlap 	case ILS_LOGIN_DONE:
467a6d42e7dSPeter Dunlap 		login_sm_done(ict, ctx);
468a6d42e7dSPeter Dunlap 		break;
469a6d42e7dSPeter Dunlap 	case ILS_LOGIN_ERROR:
470a6d42e7dSPeter Dunlap 		login_sm_error(ict, ctx);
471a6d42e7dSPeter Dunlap 		break;
472a6d42e7dSPeter Dunlap 	}
473a6d42e7dSPeter Dunlap 
474a6d42e7dSPeter Dunlap 	kmem_free(ctx, sizeof (*ctx));
475a6d42e7dSPeter Dunlap }
476a6d42e7dSPeter Dunlap 
477a6d42e7dSPeter Dunlap static void
login_sm_init(iscsit_conn_t * ict,login_event_ctx_t * ctx)478a6d42e7dSPeter Dunlap login_sm_init(iscsit_conn_t *ict, login_event_ctx_t *ctx)
479a6d42e7dSPeter Dunlap {
480a6d42e7dSPeter Dunlap 	idm_pdu_t *pdu;
481a6d42e7dSPeter Dunlap 
482a6d42e7dSPeter Dunlap 	switch (ctx->le_ctx_event) {
483a6d42e7dSPeter Dunlap 	case ILE_LOGIN_RCV:
484a6d42e7dSPeter Dunlap 		pdu = ctx->le_pdu;
485a6d42e7dSPeter Dunlap 
486a6d42e7dSPeter Dunlap 		/*
487a6d42e7dSPeter Dunlap 		 * This is the first login PDU we've received so use
488a6d42e7dSPeter Dunlap 		 * it to build the login response template and set our CSG.
489a6d42e7dSPeter Dunlap 		 */
490a6d42e7dSPeter Dunlap 		login_sm_handle_initial_login(ict, pdu);
491a6d42e7dSPeter Dunlap 
492a6d42e7dSPeter Dunlap 		/*
493a6d42e7dSPeter Dunlap 		 * Accumulate all the login PDU's that make up this
494a6d42e7dSPeter Dunlap 		 * request on a queue.
495a6d42e7dSPeter Dunlap 		 */
496a6d42e7dSPeter Dunlap 		mutex_enter(&ict->ict_login_sm.icl_mutex);
497a6d42e7dSPeter Dunlap 		list_insert_tail(&ict->ict_login_sm.icl_pdu_list, pdu);
498a6d42e7dSPeter Dunlap 		mutex_exit(&ict->ict_login_sm.icl_mutex);
499a6d42e7dSPeter Dunlap 
500a6d42e7dSPeter Dunlap 		if (pdu->isp_hdr->flags & ISCSI_FLAG_LOGIN_CONTINUE) {
501a6d42e7dSPeter Dunlap 			login_sm_send_ack(ict, pdu);
502a6d42e7dSPeter Dunlap 			login_sm_new_state(ict, ctx, ILS_LOGIN_WAITING);
503a6d42e7dSPeter Dunlap 		} else {
504a6d42e7dSPeter Dunlap 			login_sm_new_state(ict, ctx, ILS_LOGIN_PROCESSING);
505a6d42e7dSPeter Dunlap 		}
506a6d42e7dSPeter Dunlap 		break;
507a6d42e7dSPeter Dunlap 	case ILE_LOGIN_CONN_ERROR:
508a6d42e7dSPeter Dunlap 	case ILE_LOGIN_ERROR:
509a6d42e7dSPeter Dunlap 		login_sm_new_state(ict, ctx, ILS_LOGIN_ERROR);
510a6d42e7dSPeter Dunlap 		break;
511a6d42e7dSPeter Dunlap 	default:
512a6d42e7dSPeter Dunlap 		ASSERT(0);
513a6d42e7dSPeter Dunlap 	}
514a6d42e7dSPeter Dunlap }
515a6d42e7dSPeter Dunlap 
516a6d42e7dSPeter Dunlap static void
login_sm_waiting(iscsit_conn_t * ict,login_event_ctx_t * ctx)517a6d42e7dSPeter Dunlap login_sm_waiting(iscsit_conn_t *ict, login_event_ctx_t *ctx)
518a6d42e7dSPeter Dunlap {
519a6d42e7dSPeter Dunlap 	idm_pdu_t *pdu;
520a6d42e7dSPeter Dunlap 
521a6d42e7dSPeter Dunlap 	switch (ctx->le_ctx_event) {
522a6d42e7dSPeter Dunlap 	case ILE_LOGIN_RCV:
523a6d42e7dSPeter Dunlap 		pdu = ctx->le_pdu;
524a6d42e7dSPeter Dunlap 		mutex_enter(&ict->ict_login_sm.icl_mutex);
525a6d42e7dSPeter Dunlap 		list_insert_tail(&ict->ict_login_sm.icl_pdu_list, pdu);
526a6d42e7dSPeter Dunlap 		mutex_exit(&ict->ict_login_sm.icl_mutex);
527a6d42e7dSPeter Dunlap 		if (!(pdu->isp_hdr->flags & ISCSI_FLAG_LOGIN_CONTINUE)) {
528a6d42e7dSPeter Dunlap 			login_sm_new_state(ict, ctx, ILS_LOGIN_PROCESSING);
529a6d42e7dSPeter Dunlap 		} else {
530a6d42e7dSPeter Dunlap 			login_sm_send_ack(ict, pdu);
531a6d42e7dSPeter Dunlap 		}
532a6d42e7dSPeter Dunlap 		break;
533a6d42e7dSPeter Dunlap 	case ILE_LOGIN_ERROR:
534a6d42e7dSPeter Dunlap 		login_sm_new_state(ict, ctx, ILS_LOGIN_ERROR);
535a6d42e7dSPeter Dunlap 		break;
536a6d42e7dSPeter Dunlap 	case ILE_LOGIN_RESP_COMPLETE:
537a6d42e7dSPeter Dunlap 		break;
538a6d42e7dSPeter Dunlap 	default:
539a6d42e7dSPeter Dunlap 		ASSERT(0);
540a6d42e7dSPeter Dunlap 	}
541a6d42e7dSPeter Dunlap }
542a6d42e7dSPeter Dunlap 
543a6d42e7dSPeter Dunlap static void
login_sm_processing(iscsit_conn_t * ict,login_event_ctx_t * ctx)544a6d42e7dSPeter Dunlap login_sm_processing(iscsit_conn_t *ict, login_event_ctx_t *ctx)
545a6d42e7dSPeter Dunlap {
546a6d42e7dSPeter Dunlap 	switch (ctx->le_ctx_event) {
547a6d42e7dSPeter Dunlap 	case ILE_LOGIN_RESP_READY:
548a6d42e7dSPeter Dunlap 		login_sm_new_state(ict, ctx, ILS_LOGIN_RESPONDING);
549a6d42e7dSPeter Dunlap 		break;
550a6d42e7dSPeter Dunlap 	case ILE_LOGIN_RCV:
551a6d42e7dSPeter Dunlap 		idm_pdu_complete(ctx->le_pdu, IDM_STATUS_SUCCESS);
552a6d42e7dSPeter Dunlap 		/*FALLTHROUGH*/
553a6d42e7dSPeter Dunlap 	case ILE_LOGIN_CONN_ERROR:
554a6d42e7dSPeter Dunlap 	case ILE_LOGIN_ERROR:
555a6d42e7dSPeter Dunlap 		login_sm_new_state(ict, ctx, ILS_LOGIN_ERROR);
556a6d42e7dSPeter Dunlap 		break;
557a6d42e7dSPeter Dunlap 	default:
558a6d42e7dSPeter Dunlap 		ASSERT(0);
559a6d42e7dSPeter Dunlap 	}
560a6d42e7dSPeter Dunlap }
561a6d42e7dSPeter Dunlap 
562a6d42e7dSPeter Dunlap static void
login_sm_responding(iscsit_conn_t * ict,login_event_ctx_t * ctx)563a6d42e7dSPeter Dunlap login_sm_responding(iscsit_conn_t *ict, login_event_ctx_t *ctx)
564a6d42e7dSPeter Dunlap {
5654142b486SJames Moore 	idm_pdu_t *pdu, *rpdu;
566a6d42e7dSPeter Dunlap 
567a6d42e7dSPeter Dunlap 	switch (ctx->le_ctx_event) {
568a6d42e7dSPeter Dunlap 	case ILE_LOGIN_RCV:
569a6d42e7dSPeter Dunlap 		pdu = ctx->le_pdu;
570a6d42e7dSPeter Dunlap 		/*
571a6d42e7dSPeter Dunlap 		 * We should only be in "responding" state if we have not
572a6d42e7dSPeter Dunlap 		 * sent the last PDU of a multi-PDU login response sequence.
573a6d42e7dSPeter Dunlap 		 * In that case we expect this received PDU to be an
574a6d42e7dSPeter Dunlap 		 * acknowledgement from the initiator (login PDU with C
575a6d42e7dSPeter Dunlap 		 * bit cleared and no data).  If it's the acknowledgement
576a6d42e7dSPeter Dunlap 		 * we are expecting then we send the next PDU in the login
577a6d42e7dSPeter Dunlap 		 * response sequence.  Otherwise it's a protocol error and
578a6d42e7dSPeter Dunlap 		 * the login fails.
579a6d42e7dSPeter Dunlap 		 */
580a6d42e7dSPeter Dunlap 		if (login_sm_validate_ack(ict, pdu) == IDM_STATUS_SUCCESS) {
5814142b486SJames Moore 			rpdu = login_sm_build_login_response(ict);
5824142b486SJames Moore 			login_sm_send_next_response(ict, rpdu);
583a6d42e7dSPeter Dunlap 		} else {
584a6d42e7dSPeter Dunlap 			login_sm_new_state(ict, ctx, ILS_LOGIN_ERROR);
585a6d42e7dSPeter Dunlap 		}
586a6d42e7dSPeter Dunlap 		idm_pdu_complete(pdu, IDM_STATUS_SUCCESS);
587a6d42e7dSPeter Dunlap 		break;
588a6d42e7dSPeter Dunlap 	case ILE_LOGIN_FFP:
589a6d42e7dSPeter Dunlap 		login_sm_new_state(ict, ctx, ILS_LOGIN_FFP);
590a6d42e7dSPeter Dunlap 		break;
591a6d42e7dSPeter Dunlap 	case ILE_LOGIN_RESP_COMPLETE:
592a6d42e7dSPeter Dunlap 		login_sm_new_state(ict, ctx, ILS_LOGIN_RESPONDED);
593a6d42e7dSPeter Dunlap 		break;
594a6d42e7dSPeter Dunlap 	case ILE_LOGIN_CONN_ERROR:
595a6d42e7dSPeter Dunlap 	case ILE_LOGIN_ERROR:
596a6d42e7dSPeter Dunlap 		login_sm_new_state(ict, ctx, ILS_LOGIN_ERROR);
597a6d42e7dSPeter Dunlap 		break;
598a6d42e7dSPeter Dunlap 	default:
599a6d42e7dSPeter Dunlap 		ASSERT(0);
600a6d42e7dSPeter Dunlap 	}
601a6d42e7dSPeter Dunlap }
602a6d42e7dSPeter Dunlap 
603a6d42e7dSPeter Dunlap static void
login_sm_responded(iscsit_conn_t * ict,login_event_ctx_t * ctx)604a6d42e7dSPeter Dunlap login_sm_responded(iscsit_conn_t *ict, login_event_ctx_t *ctx)
605a6d42e7dSPeter Dunlap {
606a6d42e7dSPeter Dunlap 	idm_pdu_t		*pdu;
607a6d42e7dSPeter Dunlap 	iscsi_login_hdr_t	*lh;
608a6d42e7dSPeter Dunlap 
609a6d42e7dSPeter Dunlap 	switch (ctx->le_ctx_event) {
610a6d42e7dSPeter Dunlap 	case ILE_LOGIN_RCV:
611a6d42e7dSPeter Dunlap 		pdu = ctx->le_pdu;
612a6d42e7dSPeter Dunlap 		lh = (iscsi_login_hdr_t *)pdu->isp_hdr;
613a6d42e7dSPeter Dunlap 		/*
614a6d42e7dSPeter Dunlap 		 * Set the CSG, NSG and Transit bits based on the this PDU.
615a6d42e7dSPeter Dunlap 		 * The CSG already validated in login_sm_req_pdu_check().
616a6d42e7dSPeter Dunlap 		 * We'll clear the transit bit if we encounter any login
617a6d42e7dSPeter Dunlap 		 * parameters in the request that required an additional
618a6d42e7dSPeter Dunlap 		 * login transfer (i.e. no acceptable
619a6d42e7dSPeter Dunlap 		 * choices in range or we needed to change a boolean
620a6d42e7dSPeter Dunlap 		 * value from "Yes" to "No").
621a6d42e7dSPeter Dunlap 		 */
622a6d42e7dSPeter Dunlap 		ict->ict_login_sm.icl_login_csg =
623a6d42e7dSPeter Dunlap 		    ISCSI_LOGIN_CURRENT_STAGE(lh->flags);
624a6d42e7dSPeter Dunlap 		ict->ict_login_sm.icl_login_nsg =
625a6d42e7dSPeter Dunlap 		    ISCSI_LOGIN_NEXT_STAGE(lh->flags);
626a6d42e7dSPeter Dunlap 		ict->ict_login_sm.icl_login_transit =
627a6d42e7dSPeter Dunlap 		    lh->flags & ISCSI_FLAG_LOGIN_TRANSIT;
628a6d42e7dSPeter Dunlap 		mutex_enter(&ict->ict_login_sm.icl_mutex);
629a6d42e7dSPeter Dunlap 		list_insert_tail(&ict->ict_login_sm.icl_pdu_list, pdu);
630a6d42e7dSPeter Dunlap 		mutex_exit(&ict->ict_login_sm.icl_mutex);
631a6d42e7dSPeter Dunlap 		if (pdu->isp_hdr->flags & ISCSI_FLAG_LOGIN_CONTINUE) {
632a6d42e7dSPeter Dunlap 			login_sm_send_ack(ict, pdu);
633a6d42e7dSPeter Dunlap 			login_sm_new_state(ict, ctx, ILS_LOGIN_WAITING);
634a6d42e7dSPeter Dunlap 		} else {
635a6d42e7dSPeter Dunlap 			login_sm_new_state(ict, ctx, ILS_LOGIN_PROCESSING);
636a6d42e7dSPeter Dunlap 		}
637a6d42e7dSPeter Dunlap 		break;
638a6d42e7dSPeter Dunlap 	case ILE_LOGIN_CONN_ERROR:
639a6d42e7dSPeter Dunlap 	case ILE_LOGIN_ERROR:
640a6d42e7dSPeter Dunlap 		login_sm_new_state(ict, ctx, ILS_LOGIN_ERROR);
641a6d42e7dSPeter Dunlap 		break;
642a6d42e7dSPeter Dunlap 	default:
643a6d42e7dSPeter Dunlap 		ASSERT(0);
644a6d42e7dSPeter Dunlap 	}
645a6d42e7dSPeter Dunlap }
646a6d42e7dSPeter Dunlap 
647a6d42e7dSPeter Dunlap static void
login_sm_ffp(iscsit_conn_t * ict,login_event_ctx_t * ctx)648a6d42e7dSPeter Dunlap login_sm_ffp(iscsit_conn_t *ict, login_event_ctx_t *ctx)
649a6d42e7dSPeter Dunlap {
650a6d42e7dSPeter Dunlap 	switch (ctx->le_ctx_event) {
651a6d42e7dSPeter Dunlap 	case ILE_LOGIN_RESP_COMPLETE:
652a6d42e7dSPeter Dunlap 		login_sm_new_state(ict, ctx, ILS_LOGIN_DONE);
653a6d42e7dSPeter Dunlap 		break;
654a6d42e7dSPeter Dunlap 	case ILE_LOGIN_CONN_ERROR:
655a6d42e7dSPeter Dunlap 	case ILE_LOGIN_ERROR:
656a6d42e7dSPeter Dunlap 		login_sm_new_state(ict, ctx, ILS_LOGIN_ERROR);
657a6d42e7dSPeter Dunlap 		break;
658a6d42e7dSPeter Dunlap 	default:
659a6d42e7dSPeter Dunlap 		ASSERT(0);
660a6d42e7dSPeter Dunlap 	}
661a6d42e7dSPeter Dunlap 
662a6d42e7dSPeter Dunlap }
663a6d42e7dSPeter Dunlap 
664a6d42e7dSPeter Dunlap /*ARGSUSED*/
665a6d42e7dSPeter Dunlap static void
login_sm_done(iscsit_conn_t * ict,login_event_ctx_t * ctx)666a6d42e7dSPeter Dunlap login_sm_done(iscsit_conn_t *ict, login_event_ctx_t *ctx)
667a6d42e7dSPeter Dunlap {
668a6d42e7dSPeter Dunlap 	/* Terminal state, we should get no events */
669a6d42e7dSPeter Dunlap 	switch (ctx->le_ctx_event) {
670a6d42e7dSPeter Dunlap 	case ILE_LOGIN_RCV:
671a6d42e7dSPeter Dunlap 		/*
672a6d42e7dSPeter Dunlap 		 * We've already processed everything we're going to
673a6d42e7dSPeter Dunlap 		 * process.  Drop any additional login PDU's.
674a6d42e7dSPeter Dunlap 		 */
675a6d42e7dSPeter Dunlap 		idm_pdu_complete(ctx->le_pdu, IDM_STATUS_SUCCESS);
676a6d42e7dSPeter Dunlap 		break;
677a6d42e7dSPeter Dunlap 	case ILE_LOGIN_CONN_ERROR:
678a6d42e7dSPeter Dunlap 		/* Don't care */
679a6d42e7dSPeter Dunlap 		break;
680a6d42e7dSPeter Dunlap 	default:
681a6d42e7dSPeter Dunlap 		ASSERT(0);
682a6d42e7dSPeter Dunlap 	}
683a6d42e7dSPeter Dunlap }
684a6d42e7dSPeter Dunlap 
685a6d42e7dSPeter Dunlap /*ARGSUSED*/
686a6d42e7dSPeter Dunlap static void
login_sm_error(iscsit_conn_t * ict,login_event_ctx_t * ctx)687a6d42e7dSPeter Dunlap login_sm_error(iscsit_conn_t *ict, login_event_ctx_t *ctx)
688a6d42e7dSPeter Dunlap {
689a6d42e7dSPeter Dunlap 	switch (ctx->le_ctx_event) {
690a6d42e7dSPeter Dunlap 	case ILE_LOGIN_RCV:
691a6d42e7dSPeter Dunlap 		/*
692a6d42e7dSPeter Dunlap 		 * We've already processed everything we're going to
693a6d42e7dSPeter Dunlap 		 * process.  Drop any additional login PDU's.
694a6d42e7dSPeter Dunlap 		 */
695a6d42e7dSPeter Dunlap 		idm_pdu_complete(ctx->le_pdu, IDM_STATUS_SUCCESS);
696a6d42e7dSPeter Dunlap 		break;
697a6d42e7dSPeter Dunlap 	case ILE_LOGIN_CONN_ERROR:
698a6d42e7dSPeter Dunlap 		/* Don't care */
699a6d42e7dSPeter Dunlap 		break;
700a6d42e7dSPeter Dunlap 	default:
701a6d42e7dSPeter Dunlap 		ASSERT(0);
702a6d42e7dSPeter Dunlap 	}
703a6d42e7dSPeter Dunlap }
704a6d42e7dSPeter Dunlap 
705a6d42e7dSPeter Dunlap static void
login_sm_new_state(iscsit_conn_t * ict,login_event_ctx_t * ctx,iscsit_login_state_t new_state)706a6d42e7dSPeter Dunlap login_sm_new_state(iscsit_conn_t *ict, login_event_ctx_t *ctx,
707a6d42e7dSPeter Dunlap     iscsit_login_state_t new_state)
708a6d42e7dSPeter Dunlap {
709a6d42e7dSPeter Dunlap 	iscsit_conn_login_t *lsm = &ict->ict_login_sm;
7104142b486SJames Moore 	idm_pdu_t *rpdu;
711a6d42e7dSPeter Dunlap 
712a6d42e7dSPeter Dunlap 	/*
713a6d42e7dSPeter Dunlap 	 * Validate new state
714a6d42e7dSPeter Dunlap 	 */
715a6d42e7dSPeter Dunlap 	ASSERT(new_state != ILS_UNDEFINED);
716a6d42e7dSPeter Dunlap 	ASSERT3U(new_state, <, ILS_MAX_STATE);
717a6d42e7dSPeter Dunlap 
718a6d42e7dSPeter Dunlap 	new_state = (new_state < ILS_MAX_STATE) ?
719a6d42e7dSPeter Dunlap 	    new_state : ILS_UNDEFINED;
720a6d42e7dSPeter Dunlap 
721a6d42e7dSPeter Dunlap 	IDM_SM_LOG(CE_NOTE, "login_sm_new_state: conn %p "
722a6d42e7dSPeter Dunlap 	    "%s (%d) --> %s (%d)\n", (void *)ict->ict_ic,
723a6d42e7dSPeter Dunlap 	    iscsit_ils_name[lsm->icl_login_state], lsm->icl_login_state,
724a6d42e7dSPeter Dunlap 	    iscsit_ils_name[new_state], new_state);
725a6d42e7dSPeter Dunlap 
726a6d42e7dSPeter Dunlap 	DTRACE_PROBE3(login__state__change,
727a6d42e7dSPeter Dunlap 	    iscsit_conn_t *, ict, login_event_ctx_t *, ctx,
728a6d42e7dSPeter Dunlap 	    iscsit_login_state_t, new_state);
729a6d42e7dSPeter Dunlap 
730a6d42e7dSPeter Dunlap 	mutex_enter(&lsm->icl_mutex);
731a6d42e7dSPeter Dunlap 	idm_sm_audit_state_change(&lsm->icl_state_audit, SAS_ISCSIT_LOGIN,
732a6d42e7dSPeter Dunlap 	    (int)lsm->icl_login_state, (int)new_state);
733a6d42e7dSPeter Dunlap 	lsm->icl_login_last_state = lsm->icl_login_state;
734a6d42e7dSPeter Dunlap 	lsm->icl_login_state = new_state;
735a6d42e7dSPeter Dunlap 	mutex_exit(&lsm->icl_mutex);
736a6d42e7dSPeter Dunlap 
737*61dfa509SRick McNeal 	/*
738*61dfa509SRick McNeal 	 * Tale of caution here. The use of new_state instead of using
739*61dfa509SRick McNeal 	 * lsm->icl_login_state is deliberate (which had been used originally).
740*61dfa509SRick McNeal 	 * Since the icl_mutex is dropped under the right circumstances
741*61dfa509SRick McNeal 	 * the login state changes between setting the state and examining
742*61dfa509SRick McNeal 	 * the state to proceed. No big surprise since the lock was being
743*61dfa509SRick McNeal 	 * used in the first place to prevent just that type of change.
744*61dfa509SRick McNeal 	 *
745*61dfa509SRick McNeal 	 * There has been a case where network errors occurred while a client
746*61dfa509SRick McNeal 	 * was attempting to reinstate the connection causing multiple
747*61dfa509SRick McNeal 	 * login packets to arrive into the state machine. Those multiple
748*61dfa509SRick McNeal 	 * packets which were processed incorrectly caused the reference
749*61dfa509SRick McNeal 	 * count on the connection to be one higher than it should be and
750*61dfa509SRick McNeal 	 * from then on the connection can't close correctly causing a hang.
751*61dfa509SRick McNeal 	 *
752*61dfa509SRick McNeal 	 * Upon examination of the core it was found that the connection
753*61dfa509SRick McNeal 	 * audit data had calls looking like:
754*61dfa509SRick McNeal 	 *    login_sm_event_dispatch
755*61dfa509SRick McNeal 	 *    login_sm_processing
756*61dfa509SRick McNeal 	 *    login_sm_new_state
757*61dfa509SRick McNeal 	 * That call sequence means the new state was/is ILS_LOGIN_ERROR
758*61dfa509SRick McNeal 	 * yet the audit trail continues with a call to
759*61dfa509SRick McNeal 	 *    login_sm_send_next_response
760*61dfa509SRick McNeal 	 * which could only occur if icl_login_state had changed. Had the
761*61dfa509SRick McNeal 	 * design of COMSTAR taken this into account the code would
762*61dfa509SRick McNeal 	 * originally have held the icl_mutex across the processing of the
763*61dfa509SRick McNeal 	 * state processing. Lock order and calls which sleep prevent that
764*61dfa509SRick McNeal 	 * from being possible. The next best solution is to use the local
765*61dfa509SRick McNeal 	 * variable which holds the state.
766*61dfa509SRick McNeal 	 */
767*61dfa509SRick McNeal 	switch (new_state) {
768a6d42e7dSPeter Dunlap 	case ILS_LOGIN_WAITING:
769a6d42e7dSPeter Dunlap 		/* Do nothing, waiting for more login PDU's */
770a6d42e7dSPeter Dunlap 		break;
771a6d42e7dSPeter Dunlap 	case ILS_LOGIN_PROCESSING:
772a6d42e7dSPeter Dunlap 		/* All login PDU's received, process login request */
773a6d42e7dSPeter Dunlap 		login_sm_process_request(ict);
774a6d42e7dSPeter Dunlap 		break;
775a6d42e7dSPeter Dunlap 	case ILS_LOGIN_RESPONDING:
7764142b486SJames Moore 		rpdu = login_sm_build_login_response(ict);
7774142b486SJames Moore 		login_sm_send_next_response(ict, rpdu);
778a6d42e7dSPeter Dunlap 		break;
779a6d42e7dSPeter Dunlap 	case ILS_LOGIN_RESPONDED:
780a6d42e7dSPeter Dunlap 		/* clean up the login response idm text buffer */
781a6d42e7dSPeter Dunlap 		if (lsm->icl_login_resp_itb != NULL) {
782a6d42e7dSPeter Dunlap 			idm_itextbuf_free(lsm->icl_login_resp_itb);
783a6d42e7dSPeter Dunlap 			lsm->icl_login_resp_itb = NULL;
784a6d42e7dSPeter Dunlap 		}
785a6d42e7dSPeter Dunlap 		break;
786a6d42e7dSPeter Dunlap 	case ILS_LOGIN_FFP:
787a6d42e7dSPeter Dunlap 		login_sm_ffp_actions(ict);
788a6d42e7dSPeter Dunlap 		break;
789a6d42e7dSPeter Dunlap 	case ILS_LOGIN_DONE:
790a6d42e7dSPeter Dunlap 	case ILS_LOGIN_ERROR:
7914142b486SJames Moore 		/*
7924142b486SJames Moore 		 * Flag the terminal state for the dispatcher
7934142b486SJames Moore 		 */
794a6d42e7dSPeter Dunlap 		lsm->icl_login_complete = B_TRUE;
795a6d42e7dSPeter Dunlap 		break;
796a6d42e7dSPeter Dunlap 	case ILS_LOGIN_INIT: /* Initial state, can't return */
797a6d42e7dSPeter Dunlap 	default:
798a6d42e7dSPeter Dunlap 		ASSERT(0);
799a6d42e7dSPeter Dunlap 		/*NOTREACHED*/
800a6d42e7dSPeter Dunlap 	}
801a6d42e7dSPeter Dunlap }
802a6d42e7dSPeter Dunlap 
803a6d42e7dSPeter Dunlap /*ARGSUSED*/
804a6d42e7dSPeter Dunlap static void
login_sm_send_ack(iscsit_conn_t * ict,idm_pdu_t * pdu)805a6d42e7dSPeter Dunlap login_sm_send_ack(iscsit_conn_t *ict, idm_pdu_t *pdu)
806a6d42e7dSPeter Dunlap {
807a6d42e7dSPeter Dunlap 	iscsit_conn_login_t	*lsm = &ict->ict_login_sm;
8084142b486SJames Moore 	idm_pdu_t		*lack;
809a6d42e7dSPeter Dunlap 
8104142b486SJames Moore 	/*
8114142b486SJames Moore 	 * allocate the response pdu
8124142b486SJames Moore 	 */
8134142b486SJames Moore 	lack = idm_pdu_alloc(sizeof (iscsi_hdr_t), 0);
814