1fcf3ce44SJohn Forte /*
2fcf3ce44SJohn Forte  * CDDL HEADER START
3fcf3ce44SJohn Forte  *
4fcf3ce44SJohn Forte  * The contents of this file are subject to the terms of the
5fcf3ce44SJohn Forte  * Common Development and Distribution License (the "License").
6fcf3ce44SJohn Forte  * You may not use this file except in compliance with the License.
7fcf3ce44SJohn Forte  *
8fcf3ce44SJohn Forte  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fcf3ce44SJohn Forte  * or http://www.opensolaris.org/os/licensing.
10fcf3ce44SJohn Forte  * See the License for the specific language governing permissions
11fcf3ce44SJohn Forte  * and limitations under the License.
12fcf3ce44SJohn Forte  *
13fcf3ce44SJohn Forte  * When distributing Covered Code, include this CDDL HEADER in each
14fcf3ce44SJohn Forte  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fcf3ce44SJohn Forte  * If applicable, add the following below this CDDL HEADER, with the
16fcf3ce44SJohn Forte  * fields enclosed by brackets "[]" replaced with your own identifying
17fcf3ce44SJohn Forte  * information: Portions Copyright [yyyy] [name of copyright owner]
18fcf3ce44SJohn Forte  *
19fcf3ce44SJohn Forte  * CDDL HEADER END
20fcf3ce44SJohn Forte  */
21fcf3ce44SJohn Forte /*
22fcf3ce44SJohn Forte  * Copyright 2000 by Cisco Systems, Inc.  All rights reserved.
23904e51f6SJack Meng  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24fcf3ce44SJohn Forte  *
25fcf3ce44SJohn Forte  * iSCSI protocol login and enumeration
26fcf3ce44SJohn Forte  */
27fcf3ce44SJohn Forte 
28fcf3ce44SJohn Forte #include "iscsi.h"
291a1a84a3SPeter Dunlap #include <sys/iscsi_protocol.h>
30fcf3ce44SJohn Forte #include <sys/scsi/adapters/iscsi_door.h>
31fcf3ce44SJohn Forte 
3230e7468fSPeter Dunlap boolean_t iscsi_login_logging = B_FALSE;
3330e7468fSPeter Dunlap 
34fcf3ce44SJohn Forte /* internal login protocol interfaces */
35fcf3ce44SJohn Forte static iscsi_status_t iscsi_login(iscsi_conn_t *icp,
3630e7468fSPeter Dunlap     uint8_t *status_class, uint8_t *status_detail);
3730e7468fSPeter Dunlap static int iscsi_add_text(idm_pdu_t *text_pdu,
38fcf3ce44SJohn Forte     int max_data_length, char *param, char *value);
39fcf3ce44SJohn Forte static int iscsi_find_key_value(char *param, char *ihp, char *pdu_end,
40fcf3ce44SJohn Forte     char **value_start, char **value_end);
41fcf3ce44SJohn Forte static void iscsi_null_callback(void *user_handle, void *message_handle,
42fcf3ce44SJohn Forte     int auth_status);
43fcf3ce44SJohn Forte static iscsi_status_t iscsi_process_login_response(iscsi_conn_t *icp,
44fcf3ce44SJohn Forte     iscsi_login_rsp_hdr_t *ilrhp, char *data, int max_data_length);
45fcf3ce44SJohn Forte static iscsi_status_t iscsi_make_login_pdu(iscsi_conn_t *icp,
4630e7468fSPeter Dunlap     idm_pdu_t *text_pdu, char *data, int max_data_length);
47fcf3ce44SJohn Forte static iscsi_status_t iscsi_update_address(iscsi_conn_t *icp,
48fcf3ce44SJohn Forte     char *address);
49fcf3ce44SJohn Forte static char *iscsi_login_failure_str(uchar_t status_class,
50fcf3ce44SJohn Forte     uchar_t status_detail);
51fcf3ce44SJohn Forte static void iscsi_login_end(iscsi_conn_t *icp,
5230e7468fSPeter Dunlap     iscsi_status_t status, iscsi_task_t *itp);
53fcf3ce44SJohn Forte static iscsi_status_t iscsi_login_connect(iscsi_conn_t *icp);
5430e7468fSPeter Dunlap static void iscsi_login_disconnect(iscsi_conn_t *icp);
5530e7468fSPeter Dunlap static void iscsi_notice_key_values(iscsi_conn_t *icp);
56fcf3ce44SJohn Forte 
57fcf3ce44SJohn Forte #define	ISCSI_LOGIN_RETRY_DELAY		5	/* seconds */
58fcf3ce44SJohn Forte 
5919944f88Syi zhang - Sun Microsystems - Beijing China #define	ISCSI_LOGIN_TRANSIT_FFP(flags) \
6019944f88Syi zhang - Sun Microsystems - Beijing China 	(!(flags & ISCSI_FLAG_LOGIN_CONTINUE) && \
6119944f88Syi zhang - Sun Microsystems - Beijing China 	(flags & ISCSI_FLAG_LOGIN_TRANSIT) && \
6219944f88Syi zhang - Sun Microsystems - Beijing China 	(ISCSI_LOGIN_CURRENT_STAGE(flags) == \
6319944f88Syi zhang - Sun Microsystems - Beijing China 	ISCSI_OP_PARMS_NEGOTIATION_STAGE) && \
6419944f88Syi zhang - Sun Microsystems - Beijing China 	(ISCSI_LOGIN_NEXT_STAGE(flags) == \
6519944f88Syi zhang - Sun Microsystems - Beijing China 	ISCSI_FULL_FEATURE_PHASE))
6619944f88Syi zhang - Sun Microsystems - Beijing China 
67fcf3ce44SJohn Forte /*
68fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
69fcf3ce44SJohn Forte  * | External Login Interface						|
70fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
71fcf3ce44SJohn Forte  */
72fcf3ce44SJohn Forte 
73fcf3ce44SJohn Forte /*
74fcf3ce44SJohn Forte  * iscsi_login_start - connect and perform iscsi protocol login
75fcf3ce44SJohn Forte  */
76fcf3ce44SJohn Forte iscsi_status_t
77fcf3ce44SJohn Forte iscsi_login_start(void *arg)
78fcf3ce44SJohn Forte {
79fcf3ce44SJohn Forte 	iscsi_task_t		*itp = (iscsi_task_t *)arg;
80fcf3ce44SJohn Forte 	iscsi_status_t		rval	= ISCSI_STATUS_LOGIN_FAILED;
81fcf3ce44SJohn Forte 	iscsi_conn_t		*icp;
82fcf3ce44SJohn Forte 	iscsi_sess_t		*isp;
83fcf3ce44SJohn Forte 	iscsi_hba_t		*ihp;
84fcf3ce44SJohn Forte 	unsigned char		status_class;
85fcf3ce44SJohn Forte 	unsigned char		status_detail;
86fcf3ce44SJohn Forte 
87fcf3ce44SJohn Forte 	ASSERT(itp != NULL);
88fcf3ce44SJohn Forte 	icp = (iscsi_conn_t *)itp->t_arg;
89fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
90fcf3ce44SJohn Forte 	isp = icp->conn_sess;
91fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
92fcf3ce44SJohn Forte 	ihp = isp->sess_hba;
93fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
94fcf3ce44SJohn Forte 
95fcf3ce44SJohn Forte login_start:
9630e7468fSPeter Dunlap 	ASSERT((icp->conn_state == ISCSI_CONN_STATE_IN_LOGIN) ||
9730e7468fSPeter Dunlap 	    (icp->conn_state == ISCSI_CONN_STATE_FAILED) ||
9830e7468fSPeter Dunlap 	    (icp->conn_state == ISCSI_CONN_STATE_POLLING));
9930e7468fSPeter Dunlap 
10030e7468fSPeter Dunlap 	icp->conn_state_ffp = B_FALSE;
101cc7ef495Syi zhang - Sun Microsystems - Beijing China 	icp->conn_login_status = ISCSI_INITIAL_LOGIN_STAGE;
10230e7468fSPeter Dunlap 
103fcf3ce44SJohn Forte 	/* reset connection statsn */
104fcf3ce44SJohn Forte 	icp->conn_expstatsn = 0;
105fcf3ce44SJohn Forte 	icp->conn_laststatsn = 0;
106fcf3ce44SJohn Forte 
107fcf3ce44SJohn Forte 	/* sync up authentication information */
108fcf3ce44SJohn Forte 	(void) iscsi_sess_set_auth(isp);
109fcf3ce44SJohn Forte 
110fcf3ce44SJohn Forte 	/* sync up login and session parameters */
111fcf3ce44SJohn Forte 	if (!ISCSI_SUCCESS(iscsi_conn_sync_params(icp))) {
112fcf3ce44SJohn Forte 		/* unable to sync params.  fail connection attempts */
11330e7468fSPeter Dunlap 		iscsi_login_end(icp, ISCSI_STATUS_LOGIN_FAILED, itp);
114fcf3ce44SJohn Forte 		return (ISCSI_STATUS_LOGIN_FAILED);
115fcf3ce44SJohn Forte 	}
116fcf3ce44SJohn Forte 
11730e7468fSPeter Dunlap 	/*
11830e7468fSPeter Dunlap 	 * Attempt to open TCP connection, associated IDM connection will
11930e7468fSPeter Dunlap 	 * have a hold on it that must be released after the call to
12030e7468fSPeter Dunlap 	 * iscsi_login() below.
12130e7468fSPeter Dunlap 	 */
122fcf3ce44SJohn Forte 	if (!ISCSI_SUCCESS(iscsi_login_connect(icp))) {
123bbe72583SJack Meng 		if ((isp->sess_boot == B_TRUE) &&
124bbe72583SJack Meng 		    (ihp->hba_service_status_overwrite == B_TRUE) &&
125bbe72583SJack Meng 		    (isp->sess_boot_nic_reset == B_FALSE)) {
126bbe72583SJack Meng 			/*
127bbe72583SJack Meng 			 * The connection to boot target failed
128bbe72583SJack Meng 			 * before the system fully started.
129bbe72583SJack Meng 			 * Reset the boot nic to the settings from
130bbe72583SJack Meng 			 * firmware before retrying the connect to
131bbe72583SJack Meng 			 * save the the system.
132bbe72583SJack Meng 			 */
133bbe72583SJack Meng 			if (iscsi_net_interface(B_TRUE) ==
134bbe72583SJack Meng 			    ISCSI_STATUS_SUCCESS) {
135bbe72583SJack Meng 				isp->sess_boot_nic_reset = B_TRUE;
136bbe72583SJack Meng 			}
137bbe72583SJack Meng 		}
138fcf3ce44SJohn Forte 		/* retry this failure */
139fcf3ce44SJohn Forte 		goto login_retry;
140fcf3ce44SJohn Forte 	}
141fcf3ce44SJohn Forte 
142fcf3ce44SJohn Forte 	/*
143fcf3ce44SJohn Forte 	 * allocate response buffer with based on default max
144fcf3ce44SJohn Forte 	 * transfer size.  This size might shift during login.
145fcf3ce44SJohn Forte 	 */
14630e7468fSPeter Dunlap 	icp->conn_login_max_data_length =
14730e7468fSPeter Dunlap 	    icp->conn_params.max_xmit_data_seg_len;
14830e7468fSPeter Dunlap 	icp->conn_login_data = kmem_zalloc(icp->conn_login_max_data_length,
14930e7468fSPeter Dunlap 	    KM_SLEEP);
150fcf3ce44SJohn Forte 
15130e7468fSPeter Dunlap 	/*
15230e7468fSPeter Dunlap 	 * Start protocol login, upon return we will be either logged in
15330e7468fSPeter Dunlap 	 * or disconnected
15430e7468fSPeter Dunlap 	 */
15530e7468fSPeter Dunlap 	rval = iscsi_login(icp, &status_class, &status_detail);
156fcf3ce44SJohn Forte 
157fcf3ce44SJohn Forte 	/* done with buffer */
15830e7468fSPeter Dunlap 	kmem_free(icp->conn_login_data, icp->conn_login_max_data_length);
15930e7468fSPeter Dunlap 
16030e7468fSPeter Dunlap 	/* Release connection hold */
16130e7468fSPeter Dunlap 	idm_conn_rele(icp->conn_ic);
162fcf3ce44SJohn Forte 
163fcf3ce44SJohn Forte 	/* hard failure in login */
164fcf3ce44SJohn Forte 	if (!ISCSI_SUCCESS(rval)) {
165fcf3ce44SJohn Forte 		/*
166fcf3ce44SJohn Forte 		 * We should just give up retry if these failures are
167fcf3ce44SJohn Forte 		 * detected.
168fcf3ce44SJohn Forte 		 */
169fcf3ce44SJohn Forte 		switch (rval) {
170fcf3ce44SJohn Forte 		/*
171fcf3ce44SJohn Forte 		 * We should just give up retry if these
172fcf3ce44SJohn Forte 		 * failures are detected.
173fcf3ce44SJohn Forte 		 */
174fcf3ce44SJohn Forte 		case ISCSI_STATUS_AUTHENTICATION_FAILED:
175fcf3ce44SJohn Forte 		case ISCSI_STATUS_INTERNAL_ERROR:
176fcf3ce44SJohn Forte 		case ISCSI_STATUS_VERSION_MISMATCH:
177fcf3ce44SJohn Forte 		case ISCSI_STATUS_NEGO_FAIL:
178cc7ef495Syi zhang - Sun Microsystems - Beijing China 		case ISCSI_STATUS_LOGIN_TPGT_NEGO_FAIL:
179fcf3ce44SJohn Forte 			/* we don't want to retry this failure */
18030e7468fSPeter Dunlap 			iscsi_login_end(icp, ISCSI_STATUS_LOGIN_FAILED, itp);
181fcf3ce44SJohn Forte 			return (ISCSI_STATUS_LOGIN_FAILED);
182fcf3ce44SJohn Forte 		default:
183fcf3ce44SJohn Forte 			/* retry this failure */
184fcf3ce44SJohn Forte 			goto login_retry;
185fcf3ce44SJohn Forte 		}
186fcf3ce44SJohn Forte 	}
187fcf3ce44SJohn Forte 
188fcf3ce44SJohn Forte 	/* soft failure with reason */
189fcf3ce44SJohn Forte 	switch (status_class) {
190fcf3ce44SJohn Forte 	case ISCSI_STATUS_CLASS_SUCCESS:
191fcf3ce44SJohn Forte 		/* login was successful */
19230e7468fSPeter Dunlap 		iscsi_login_end(icp, ISCSI_STATUS_SUCCESS, itp);
193fcf3ce44SJohn Forte 		return (ISCSI_STATUS_SUCCESS);
194fcf3ce44SJohn Forte 	case ISCSI_STATUS_CLASS_REDIRECT:
195fcf3ce44SJohn Forte 		/* Retry at the redirected address */
196fcf3ce44SJohn Forte 		goto login_start;
197fcf3ce44SJohn Forte 	case ISCSI_STATUS_CLASS_TARGET_ERR:
198fcf3ce44SJohn Forte 		/* retry this failure */
199fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
200fcf3ce44SJohn Forte 		    "%s (0x%02x/0x%02x)", icp->conn_oid,
201fcf3ce44SJohn Forte 		    iscsi_login_failure_str(status_class, status_detail),
202fcf3ce44SJohn Forte 		    status_class, status_detail);
203fcf3ce44SJohn Forte 		goto login_retry;
204fcf3ce44SJohn Forte 	case ISCSI_STATUS_CLASS_INITIATOR_ERR:
205fcf3ce44SJohn Forte 	default:
206fcf3ce44SJohn Forte 		/* All other errors are hard failures */
207fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
2087f848965Sbing zhao - Sun Microsystems - Beijing China 		    "%s (0x%02x/0x%02x) Target: %s, TPGT: %d",
2097f848965Sbing zhao - Sun Microsystems - Beijing China 		    icp->conn_oid,
210fcf3ce44SJohn Forte 		    iscsi_login_failure_str(status_class, status_detail),
2117f848965Sbing zhao - Sun Microsystems - Beijing China 		    status_class, status_detail, isp->sess_name,
2127f848965Sbing zhao - Sun Microsystems - Beijing China 		    isp->sess_tpgt_conf);
213fcf3ce44SJohn Forte 
214fcf3ce44SJohn Forte 		/* we don't want to retry this failure */
21530e7468fSPeter Dunlap 		iscsi_login_end(icp, ISCSI_STATUS_LOGIN_FAILED, itp);
216fcf3ce44SJohn Forte 		break;
217fcf3ce44SJohn Forte 	}
21830e7468fSPeter Dunlap 
219fcf3ce44SJohn Forte 	return (ISCSI_STATUS_LOGIN_FAILED);
220fcf3ce44SJohn Forte 
221fcf3ce44SJohn Forte login_retry:
222fcf3ce44SJohn Forte 	/* retry this failure if we haven't run out of time */
223fcf3ce44SJohn Forte 	if (icp->conn_login_max > ddi_get_lbolt()) {
224fcf3ce44SJohn Forte 
225fcf3ce44SJohn Forte 		if (icp->conn_state == ISCSI_CONN_STATE_POLLING) {
226fcf3ce44SJohn Forte 			icp->conn_login_min = ddi_get_lbolt() +
227aff4bce5Syi zhang - Sun Microsystems - Beijing China 			    SEC_TO_TICK(icp->conn_tunable_params.
228aff4bce5Syi zhang - Sun Microsystems - Beijing China 			    polling_login_delay);
229fcf3ce44SJohn Forte 		} else {
230fcf3ce44SJohn Forte 			icp->conn_login_min = ddi_get_lbolt() +
231fcf3ce44SJohn Forte 			    SEC_TO_TICK(ISCSI_LOGIN_RETRY_DELAY);
232fcf3ce44SJohn Forte 		}
233fcf3ce44SJohn Forte 
234fcf3ce44SJohn Forte 		if (itp->t_blocking == B_TRUE) {
235fcf3ce44SJohn Forte 			goto login_start;
236fcf3ce44SJohn Forte 		} else {
237904e51f6SJack Meng 			if (ddi_taskq_dispatch(isp->sess_login_taskq,
238fcf3ce44SJohn Forte 			    (void(*)())iscsi_login_start, itp, DDI_SLEEP) !=
239fcf3ce44SJohn Forte 			    DDI_SUCCESS) {
240fcf3ce44SJohn Forte 				iscsi_login_end(icp,
24130e7468fSPeter Dunlap 				    ISCSI_STATUS_LOGIN_TIMED_OUT, itp);
242fcf3ce44SJohn Forte 			}
243fcf3ce44SJohn Forte 			return (ISCSI_STATUS_SUCCESS);
244fcf3ce44SJohn Forte 		}
245fcf3ce44SJohn Forte 	} else {
246fcf3ce44SJohn Forte 		/* Retries exceeded */
24730e7468fSPeter Dunlap 		iscsi_login_end(icp, ISCSI_STATUS_LOGIN_TIMED_OUT, itp);
248fcf3ce44SJohn Forte 	}
24930e7468fSPeter Dunlap 
250fcf3ce44SJohn Forte 	return (ISCSI_STATUS_LOGIN_FAILED);
251fcf3ce44SJohn Forte }
252fcf3ce44SJohn Forte 
253fcf3ce44SJohn Forte static void
25430e7468fSPeter Dunlap iscsi_login_end(iscsi_conn_t *icp, iscsi_status_t status, iscsi_task_t *itp)
255fcf3ce44SJohn Forte {
256fcf3ce44SJohn Forte 	iscsi_sess_t	*isp;
257904e51f6SJack Meng 	uint32_t	event_count;
258fcf3ce44SJohn Forte 
259fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
260fcf3ce44SJohn Forte 	isp = icp->conn_sess;
261fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
262fcf3ce44SJohn Forte 
26330e7468fSPeter Dunlap 	if (status == ISCSI_STATUS_SUCCESS) {
26430e7468fSPeter Dunlap 		/* Inform IDM of the relevant negotiated values */
26530e7468fSPeter Dunlap 		iscsi_notice_key_values(icp);
26630e7468fSPeter Dunlap 
26730e7468fSPeter Dunlap 		/* We are now logged in */
26830e7468fSPeter Dunlap 		iscsi_conn_update_state(icp, ISCSI_CONN_STATE_LOGGED_IN);
26930e7468fSPeter Dunlap 
27030e7468fSPeter Dunlap 		/* startup TX thread */
27130e7468fSPeter Dunlap 		(void) iscsi_thread_start(icp->conn_tx_thread);
27230e7468fSPeter Dunlap 
27330e7468fSPeter Dunlap 		/*
27430e7468fSPeter Dunlap 		 * Move login state machine to LOGIN_FFP.  This will
27530e7468fSPeter Dunlap 		 * release the taskq thread handling the CN_FFP_ENABLED
27630e7468fSPeter Dunlap 		 * allowing the IDM connection state machine to resume
27730e7468fSPeter Dunlap 		 * processing events
27830e7468fSPeter Dunlap 		 */
27930e7468fSPeter Dunlap 		iscsi_login_update_state(icp, LOGIN_FFP);
28030e7468fSPeter Dunlap 
28130e7468fSPeter Dunlap 		/* Notify the session that a connection is logged in */
282904e51f6SJack Meng 		event_count = atomic_inc_32_nv(&isp->sess_state_event_count);
283904e51f6SJack Meng 		iscsi_sess_enter_state_zone(isp);
284904e51f6SJack Meng 		iscsi_sess_state_machine(isp, ISCSI_SESS_EVENT_N1, event_count);
285904e51f6SJack Meng 		iscsi_sess_exit_state_zone(isp);
28630e7468fSPeter Dunlap 	} else {
28730e7468fSPeter Dunlap 		/* If login failed reset nego tpgt */
28830e7468fSPeter Dunlap 		isp->sess_tpgt_nego = ISCSI_DEFAULT_TPGT;
28930e7468fSPeter Dunlap 
290fcf3ce44SJohn Forte 		mutex_enter(&icp->conn_state_mutex);
29130e7468fSPeter Dunlap 		switch (icp->conn_state) {
29230e7468fSPeter Dunlap 		case ISCSI_CONN_STATE_IN_LOGIN:
29330e7468fSPeter Dunlap 			iscsi_conn_update_state_locked(icp,
29430e7468fSPeter Dunlap 			    ISCSI_CONN_STATE_FREE);
29530e7468fSPeter Dunlap 			mutex_exit(&icp->conn_state_mutex);
29630e7468fSPeter Dunlap 			break;
29730e7468fSPeter Dunlap 		case ISCSI_CONN_STATE_FAILED:
29830e7468fSPeter Dunlap 			if (status == ISCSI_STATUS_LOGIN_FAILED) {
29930e7468fSPeter Dunlap 				iscsi_conn_update_state_locked(icp,
30030e7468fSPeter Dunlap 				    ISCSI_CONN_STATE_FREE);
30130e7468fSPeter Dunlap 			} else {
30230e7468fSPeter Dunlap 				/* ISCSI_STATUS_LOGIN_TIMED_OUT */
30330e7468fSPeter Dunlap 				iscsi_conn_update_state_locked(icp,
30430e7468fSPeter Dunlap 				    ISCSI_CONN_STATE_POLLING);
30530e7468fSPeter Dunlap 			}
306fcf3ce44SJohn Forte 			mutex_exit(&icp->conn_state_mutex);
307904e51f6SJack Meng 			event_count = atomic_inc_32_nv(
308904e51f6SJack Meng 			    &isp->sess_state_event_count);
309904e51f6SJack Meng 			iscsi_sess_enter_state_zone(isp);
310904e51f6SJack Meng 			iscsi_sess_state_machine(isp, ISCSI_SESS_EVENT_N6,
311904e51f6SJack Meng 			    event_count);
312904e51f6SJack Meng 			iscsi_sess_exit_state_zone(isp);
31330e7468fSPeter Dunlap 
31430e7468fSPeter Dunlap 			if (status == ISCSI_STATUS_LOGIN_TIMED_OUT) {
31530e7468fSPeter Dunlap 				iscsi_conn_retry(isp, icp);
31630e7468fSPeter Dunlap 			}
31730e7468fSPeter Dunlap 			break;
31830e7468fSPeter Dunlap 		case ISCSI_CONN_STATE_POLLING:
31930e7468fSPeter Dunlap 			if (status == ISCSI_STATUS_LOGIN_FAILED) {
32030e7468fSPeter Dunlap 				iscsi_conn_update_state_locked(icp,
32130e7468fSPeter Dunlap 				    ISCSI_CONN_STATE_FREE);
32230e7468fSPeter Dunlap 				mutex_exit(&icp->conn_state_mutex);
323904e51f6SJack Meng 				event_count = atomic_inc_32_nv(
324904e51f6SJack Meng 				    &isp->sess_state_event_count);
325904e51f6SJack Meng 				iscsi_sess_enter_state_zone(isp);
32630e7468fSPeter Dunlap 
32730e7468fSPeter Dunlap 				iscsi_sess_state_machine(isp,
328904e51f6SJack Meng 				    ISCSI_SESS_EVENT_N6, event_count);
329904e51f6SJack Meng 
330904e51f6SJack Meng 				iscsi_sess_exit_state_zone(isp);
33130e7468fSPeter Dunlap 			} else {
33230e7468fSPeter Dunlap 				/* ISCSI_STATUS_LOGIN_TIMED_OUT */
33330e7468fSPeter Dunlap 				if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
33430e7468fSPeter Dunlap 					mutex_exit(&icp->conn_state_mutex);
33530e7468fSPeter Dunlap 
33630e7468fSPeter Dunlap 					iscsi_conn_retry(isp, icp);
33730e7468fSPeter Dunlap 				} else {
33830e7468fSPeter Dunlap 					iscsi_conn_update_state_locked(icp,
33930e7468fSPeter Dunlap 					    ISCSI_CONN_STATE_FREE);
34030e7468fSPeter Dunlap 					mutex_exit(&icp->conn_state_mutex);
34130e7468fSPeter Dunlap 				}
34230e7468fSPeter Dunlap 			}
34330e7468fSPeter Dunlap 			break;
34419944f88Syi zhang - Sun Microsystems - Beijing China 		case ISCSI_CONN_STATE_FREE:
34519944f88Syi zhang - Sun Microsystems - Beijing China 			mutex_exit(&icp->conn_state_mutex);
34619944f88Syi zhang - Sun Microsystems - Beijing China 			break;
34730e7468fSPeter Dunlap 		default:
34819944f88Syi zhang - Sun Microsystems - Beijing China 			mutex_exit(&icp->conn_state_mutex);
34930e7468fSPeter Dunlap 			ASSERT(0);
35030e7468fSPeter Dunlap 			break;
35130e7468fSPeter Dunlap 		}
352fcf3ce44SJohn Forte 	}
353fcf3ce44SJohn Forte 
354fcf3ce44SJohn Forte 	if (itp->t_blocking == B_FALSE) {
355fcf3ce44SJohn Forte 		kmem_free(itp, sizeof (iscsi_task_t));
356fcf3ce44SJohn Forte 	}
357bbe72583SJack Meng 
358bbe72583SJack Meng 	isp->sess_boot_nic_reset = B_FALSE;
359fcf3ce44SJohn Forte }
360fcf3ce44SJohn Forte 
361fcf3ce44SJohn Forte /*
362fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
363fcf3ce44SJohn Forte  * | Begin of protocol login routines					|
364fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
365fcf3ce44SJohn Forte  */
366fcf3ce44SJohn Forte 
367fcf3ce44SJohn Forte /*
368fcf3ce44SJohn Forte  * iscsi_login - Attempt to login to the target.  The caller
369fcf3ce44SJohn Forte  * must check the status class to determine if the login succeeded.
370fcf3ce44SJohn Forte  * A return of 1 does not mean the login succeeded, it just means
371fcf3ce44SJohn Forte  * this function worked, and the status class is valid info.  This
372fcf3ce44SJohn Forte  * allows the caller to decide whether or not to retry logins, so
373fcf3ce44SJohn Forte  * that we don't have any policy logic here.
374fcf3ce44SJohn Forte  */
37530e7468fSPeter Dunlap iscsi_status_t
37630e7468fSPeter Dunlap iscsi_login(iscsi_conn_t *icp, uint8_t *status_class, uint8_t *status_detail)
377fcf3ce44SJohn Forte {
378fcf3ce44SJohn Forte 	iscsi_status_t		rval		= ISCSI_STATUS_INTERNAL_ERROR;
379fcf3ce44SJohn Forte 	struct iscsi_sess	*isp		= NULL;
380fcf3ce44SJohn Forte 	IscsiAuthClient		*auth_client	= NULL;
381fcf3ce44SJohn Forte 	int			max_data_length	= 0;
382fcf3ce44SJohn Forte 	char			*data		= NULL;
38330e7468fSPeter Dunlap 	idm_pdu_t		*text_pdu;
38430e7468fSPeter Dunlap 	char			*buffer;
38530e7468fSPeter Dunlap 	size_t			bufsize;
38630e7468fSPeter Dunlap 	iscsi_login_rsp_hdr_t	*ilrhp;
38730e7468fSPeter Dunlap 	clock_t			response_timeout, timeout_result;
38830e7468fSPeter Dunlap 
38930e7468fSPeter Dunlap 	buffer = icp->conn_login_data;
39030e7468fSPeter Dunlap 	bufsize = icp->conn_login_max_data_length;
391fcf3ce44SJohn Forte 
392fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
393fcf3ce44SJohn Forte 	ASSERT(buffer != NULL);
394fcf3ce44SJohn Forte 	ASSERT(status_class != NULL);
395fcf3ce44SJohn Forte 	ASSERT(status_detail != NULL);
396fcf3ce44SJohn Forte 	isp = icp->conn_sess;
397fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
398fcf3ce44SJohn Forte 
399fcf3ce44SJohn Forte 	/*
40030e7468fSPeter Dunlap 	 * prepare the connection, hold IDM connection until login completes
401fcf3ce44SJohn Forte 	 */
402fcf3ce44SJohn Forte 	icp->conn_current_stage = ISCSI_INITIAL_LOGIN_STAGE;
403fcf3ce44SJohn Forte 	icp->conn_partial_response = 0;
404fcf3ce44SJohn Forte 
405fcf3ce44SJohn Forte 	if (isp->sess_auth.auth_buffers &&
406fcf3ce44SJohn Forte 	    isp->sess_auth.num_auth_buffers) {
407fcf3ce44SJohn Forte 
408fcf3ce44SJohn Forte 		auth_client = (IscsiAuthClient *)isp->
409fcf3ce44SJohn Forte 		    sess_auth.auth_buffers[0].address;
410fcf3ce44SJohn Forte 
411fcf3ce44SJohn Forte 		/*
412fcf3ce44SJohn Forte 		 * prepare for authentication
413fcf3ce44SJohn Forte 		 */
414fcf3ce44SJohn Forte 		if (iscsiAuthClientInit(iscsiAuthNodeTypeInitiator,
415fcf3ce44SJohn Forte 		    isp->sess_auth.num_auth_buffers,
416fcf3ce44SJohn Forte 		    isp->sess_auth.auth_buffers) !=
417fcf3ce44SJohn Forte 		    iscsiAuthStatusNoError) {
418fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
419fcf3ce44SJohn Forte 			    "unable to initialize authentication",
420fcf3ce44SJohn Forte 			    icp->conn_oid);
421cc7ef495Syi zhang - Sun Microsystems - Beijing China 			icp->conn_login_status = ISCSI_STATUS_INTERNAL_ERROR;
42230e7468fSPeter Dunlap 			iscsi_login_disconnect(icp);
42330e7468fSPeter Dunlap 			iscsi_login_update_state(icp, LOGIN_DONE);
424fcf3ce44SJohn Forte 			return (ISCSI_STATUS_INTERNAL_ERROR);
425fcf3ce44SJohn Forte 		}
426fcf3ce44SJohn Forte 
427fcf3ce44SJohn Forte 		if (iscsiAuthClientSetVersion(auth_client,
428fcf3ce44SJohn Forte 		    iscsiAuthVersionRfc) != iscsiAuthStatusNoError) {
429fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
430fcf3ce44SJohn Forte 			    "unable to set authentication", icp->conn_oid);
431fcf3ce44SJohn Forte 			goto iscsi_login_done;
432fcf3ce44SJohn Forte 		}
433fcf3ce44SJohn Forte 
434fcf3ce44SJohn Forte 		if (isp->sess_auth.username &&
435fcf3ce44SJohn Forte 		    (iscsiAuthClientSetUsername(auth_client,
436fcf3ce44SJohn Forte 		    isp->sess_auth.username) !=
437fcf3ce44SJohn Forte 		    iscsiAuthStatusNoError)) {
438fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
439fcf3ce44SJohn Forte 			    "unable to set username", icp->conn_oid);
440fcf3ce44SJohn Forte 			goto iscsi_login_done;
441fcf3ce44SJohn Forte 		}
442fcf3ce44SJohn Forte 
443fcf3ce44SJohn Forte 		if (isp->sess_auth.password &&
444fcf3ce44SJohn Forte 		    (iscsiAuthClientSetPassword(auth_client,
445fcf3ce44SJohn Forte 		    isp->sess_auth.password, isp->sess_auth.password_length) !=
446fcf3ce44SJohn Forte 		    iscsiAuthStatusNoError)) {
447fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
448fcf3ce44SJohn Forte 			    "unable to set password", icp->conn_oid);
449fcf3ce44SJohn Forte 			goto iscsi_login_done;
450fcf3ce44SJohn Forte 		}
451fcf3ce44SJohn Forte 
452fcf3ce44SJohn Forte 		if (iscsiAuthClientSetIpSec(auth_client, 1) !=
453fcf3ce44SJohn Forte 		    iscsiAuthStatusNoError) {
454fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
455fcf3ce44SJohn Forte 			    "unable to set ipsec", icp->conn_oid);
456fcf3ce44SJohn Forte 			goto iscsi_login_done;
457fcf3ce44SJohn Forte 		}
458fcf3ce44SJohn Forte 
459fcf3ce44SJohn Forte 		if (iscsiAuthClientSetAuthRemote(auth_client,
460fcf3ce44SJohn Forte 		    isp->sess_auth.bidirectional_auth) !=
461fcf3ce44SJohn Forte 		    iscsiAuthStatusNoError) {
462fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
463fcf3ce44SJohn Forte 			    "unable to set remote authentication",
464fcf3ce44SJohn Forte 			    icp->conn_oid);
465fcf3ce44SJohn Forte 			goto iscsi_login_done;
466fcf3ce44SJohn Forte 		}
467fcf3ce44SJohn Forte 	}
468fcf3ce44SJohn Forte 
469fcf3ce44SJohn Forte 	/*
470fcf3ce44SJohn Forte 	 * exchange PDUs until the login stage is complete, or an error occurs
471fcf3ce44SJohn Forte 	 */
472fcf3ce44SJohn Forte 	do {
473fcf3ce44SJohn Forte 		/* setup */
474fcf3ce44SJohn Forte 		bzero(buffer, bufsize);
475fcf3ce44SJohn Forte 		data = buffer;
476fcf3ce44SJohn Forte 		max_data_length = bufsize;
477fcf3ce44SJohn Forte 		rval = ISCSI_STATUS_INTERNAL_ERROR;
478fcf3ce44SJohn Forte 
47930e7468fSPeter Dunlap 		text_pdu = idm_pdu_alloc(sizeof (iscsi_hdr_t), 0);
48030e7468fSPeter Dunlap 		idm_pdu_init(text_pdu, icp->conn_ic, NULL, NULL);
48130e7468fSPeter Dunlap 
482fcf3ce44SJohn Forte 		/*
483fcf3ce44SJohn Forte 		 * fill in the PDU header and text data based on the
484fcf3ce44SJohn Forte 		 * login stage that we're in
485fcf3ce44SJohn Forte 		 */
48630e7468fSPeter Dunlap 		rval = iscsi_make_login_pdu(icp, text_pdu, data,
48730e7468fSPeter Dunlap 		    max_data_length);
488fcf3ce44SJohn Forte 		if (!ISCSI_SUCCESS(rval)) {
489fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
490fcf3ce44SJohn Forte 			    "unable to make login pdu", icp->conn_oid);
491fcf3ce44SJohn Forte 			goto iscsi_login_done;
492fcf3ce44SJohn Forte 		}
493fcf3ce44SJohn Forte 
49430e7468fSPeter Dunlap 		mutex_enter(&icp->conn_login_mutex);
49530e7468fSPeter Dunlap 		/*
49630e7468fSPeter Dunlap 		 * Make sure we are still in LOGIN_START or LOGIN_RX
49730e7468fSPeter Dunlap 		 * state before switching to LOGIN_TX.  It's possible
49830e7468fSPeter Dunlap 		 * for a connection failure to move us to LOGIN_ERROR
49930e7468fSPeter Dunlap 		 * before we get to this point.
50030e7468fSPeter Dunlap 		 */
50130e7468fSPeter Dunlap 		if (((icp->conn_login_state != LOGIN_READY) &&
50230e7468fSPeter Dunlap 		    (icp->conn_login_state != LOGIN_RX)) ||
50330e7468fSPeter Dunlap 		    !icp->conn_state_idm_connected) {
50430e7468fSPeter Dunlap 			/* Error occurred */
50530e7468fSPeter Dunlap 			mutex_exit(&icp->conn_login_mutex);
50630e7468fSPeter Dunlap 			rval = (ISCSI_STATUS_INTERNAL_ERROR);
507fcf3ce44SJohn Forte 			goto iscsi_login_done;
508fcf3ce44SJohn Forte 		}
509fcf3ce44SJohn Forte 
510*6e7514aeSPeter Gill 		icp->conn_login_resp_hdr.opcode = 0;
51130e7468fSPeter Dunlap 		iscsi_login_update_state_locked(icp, LOGIN_TX);
51230e7468fSPeter Dunlap 		icp->conn_login_data = data;
51330e7468fSPeter Dunlap 		icp->conn_login_max_data_length = max_data_length;
514fcf3ce44SJohn Forte 
51530e7468fSPeter Dunlap 		/*
51630e7468fSPeter Dunlap 		 * send a PDU to the target.  This is asynchronous but
51730e7468fSPeter Dunlap 		 * we don't have any particular need for a TX completion
51830e7468fSPeter Dunlap 		 * notification since we are going to block waiting for the
51930e7468fSPeter Dunlap 		 * receive.
52030e7468fSPeter Dunlap 		 */
52130e7468fSPeter Dunlap 		response_timeout = ddi_get_lbolt() +
522aff4bce5Syi zhang - Sun Microsystems - Beijing China 		    SEC_TO_TICK(icp->conn_tunable_params.
523aff4bce5Syi zhang - Sun Microsystems - Beijing China 		    recv_login_rsp_timeout);
52430e7468fSPeter Dunlap 		idm_pdu_tx(text_pdu);
52530e7468fSPeter Dunlap 
52630e7468fSPeter Dunlap 		/*
52730e7468fSPeter Dunlap 		 * Wait for login failure indication or login RX.
52830e7468fSPeter Dunlap 		 * Handler for login response PDU will copy any data into
52930e7468fSPeter Dunlap 		 * the buffer pointed to by icp->conn_login_data
53030e7468fSPeter Dunlap 		 */
53130e7468fSPeter Dunlap 		while (icp->conn_login_state == LOGIN_TX) {
53230e7468fSPeter Dunlap 			timeout_result = cv_timedwait(&icp->conn_login_cv,
53330e7468fSPeter Dunlap 			    &icp->conn_login_mutex, response_timeout);
53430e7468fSPeter Dunlap 			if (timeout_result == -1)
53530e7468fSPeter Dunlap 				break;
53630e7468fSPeter Dunlap 		}
53730e7468fSPeter Dunlap 
538*6e7514aeSPeter Gill 		/*
539*6e7514aeSPeter Gill 		 * We have either received a login response or the connection
540*6e7514aeSPeter Gill 		 * has gone down or both.  If a login response is present,
541*6e7514aeSPeter Gill 		 * then process it.
542*6e7514aeSPeter Gill 		 */
543*6e7514aeSPeter Gill 		ilrhp = (iscsi_login_rsp_hdr_t *)&icp->conn_login_resp_hdr;
544*6e7514aeSPeter Gill 		if (icp->conn_login_state != LOGIN_RX && ilrhp->opcode == 0) {
545*6e7514aeSPeter Gill 			/* connection down, with no login response */
54630e7468fSPeter Dunlap 			mutex_exit(&icp->conn_login_mutex);
54730e7468fSPeter Dunlap 			rval = (ISCSI_STATUS_INTERNAL_ERROR);
548fcf3ce44SJohn Forte 			goto iscsi_login_done;
549fcf3ce44SJohn Forte 		}
55030e7468fSPeter Dunlap 		mutex_exit(&icp->conn_login_mutex);
551fcf3ce44SJohn Forte 
552fcf3ce44SJohn Forte 		/* check the PDU response type */
55330e7468fSPeter Dunlap 		if (ilrhp->opcode != ISCSI_OP_LOGIN_RSP) {
554fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
555fcf3ce44SJohn Forte 			    "received invalid login response (0x%02x)",
55630e7468fSPeter Dunlap 			    icp->conn_oid, ilrhp->opcode);
557fcf3ce44SJohn Forte 			rval = (ISCSI_STATUS_PROTOCOL_ERROR);
558fcf3ce44SJohn Forte 			goto iscsi_login_done;
559fcf3ce44SJohn Forte 		}
560fcf3ce44SJohn Forte 
561fcf3ce44SJohn Forte 		/*
562fcf3ce44SJohn Forte 		 * give the caller the status class and detail from the
563fcf3ce44SJohn Forte 		 * last login response PDU received
564fcf3ce44SJohn Forte 		 */
565fcf3ce44SJohn Forte 		if (status_class) {
566fcf3ce44SJohn Forte 			*status_class = ilrhp->status_class;
567fcf3ce44SJohn Forte 		}
568fcf3ce44SJohn Forte 		if (status_detail) {
569fcf3ce44SJohn Forte 			*status_detail = ilrhp->status_detail;
570fcf3ce44SJohn Forte 		}
571fcf3ce44SJohn Forte 
572fcf3ce44SJohn Forte 		switch (ilrhp->status_class) {
573fcf3ce44SJohn Forte 		case ISCSI_STATUS_CLASS_SUCCESS:
574fcf3ce44SJohn Forte 			/*
575fcf3ce44SJohn Forte 			 * process this response and possibly continue
576fcf3ce44SJohn Forte 			 * sending PDUs
577fcf3ce44SJohn Forte 			 */
578fcf3ce44SJohn Forte 			rval = iscsi_process_login_response(icp,
57930e7468fSPeter Dunlap 			    ilrhp, (char *)icp->conn_login_data,
58030e7468fSPeter Dunlap 			    icp->conn_login_max_data_length);
581fcf3ce44SJohn Forte 			/* pass back whatever error we discovered */
582fcf3ce44SJohn Forte 			if (!ISCSI_SUCCESS(rval)) {
58319944f88Syi zhang - Sun Microsystems - Beijing China 				if (ISCSI_LOGIN_TRANSIT_FFP(ilrhp->flags)) {
58419944f88Syi zhang - Sun Microsystems - Beijing China 					/*
58519944f88Syi zhang - Sun Microsystems - Beijing China 					 * iSCSI connection transit to next
58619944f88Syi zhang - Sun Microsystems - Beijing China 					 * FFP stage while iscsi params
58719944f88Syi zhang - Sun Microsystems - Beijing China 					 * ngeotiate error, LOGIN_ERROR
58819944f88Syi zhang - Sun Microsystems - Beijing China 					 * marked so CN_FFP_ENABLED can
58919944f88Syi zhang - Sun Microsystems - Beijing China 					 * be fully handled before
59019944f88Syi zhang - Sun Microsystems - Beijing China 					 * CN_FFP_DISABLED can be processed.
59119944f88Syi zhang - Sun Microsystems - Beijing China 					 */
59219944f88Syi zhang - Sun Microsystems - Beijing China 					iscsi_login_update_state(icp,
59319944f88Syi zhang - Sun Microsystems - Beijing China 					    LOGIN_ERROR);
59419944f88Syi zhang - Sun Microsystems - Beijing China 				}
595fcf3ce44SJohn Forte 				goto iscsi_login_done;
596fcf3ce44SJohn Forte 			}
597fcf3ce44SJohn Forte 
598fcf3ce44SJohn Forte 			break;
599fcf3ce44SJohn Forte 		case ISCSI_STATUS_CLASS_REDIRECT:
600fcf3ce44SJohn Forte 			/*
601fcf3ce44SJohn Forte 			 * we need to process this response to get the
602fcf3ce44SJohn Forte 			 * TargetAddress of the redirect, but we don't
603fcf3ce44SJohn Forte 			 * care about the return code.
604fcf3ce44SJohn Forte 			 */
60530e7468fSPeter Dunlap 			(void) iscsi_process_login_response(icp,
60630e7468fSPeter Dunlap 			    ilrhp, (char *)icp->conn_login_data,
60730e7468fSPeter Dunlap 			    icp->conn_login_max_data_length);
608fcf3ce44SJohn Forte 			rval = ISCSI_STATUS_SUCCESS;
609fcf3ce44SJohn Forte 			goto iscsi_login_done;
610fcf3ce44SJohn Forte 		case ISCSI_STATUS_CLASS_INITIATOR_ERR:
611fcf3ce44SJohn Forte 			if (ilrhp->status_detail ==
612fcf3ce44SJohn Forte 			    ISCSI_LOGIN_STATUS_AUTH_FAILED) {
613fcf3ce44SJohn Forte 				cmn_err(CE_WARN, "iscsi connection(%u) login "
614fcf3ce44SJohn Forte 				    "failed - login failed to authenticate "
615fcf3ce44SJohn Forte 				    "with target", icp->conn_oid);
616fcf3ce44SJohn Forte 			}
617fcf3ce44SJohn Forte 			rval = ISCSI_STATUS_SUCCESS;
618fcf3ce44SJohn Forte 			goto iscsi_login_done;
619fcf3ce44SJohn Forte 		default:
620fcf3ce44SJohn Forte 			/*
621fcf3ce44SJohn Forte 			 * some sort of error, login terminated unsuccessfully,
622fcf3ce44SJohn Forte 			 * though this function did it's job. the caller must
623fcf3ce44SJohn Forte 			 * check the status_class and status_detail and decide
624fcf3ce44SJohn Forte 			 * what to do next.
625fcf3ce44SJohn Forte 			 */
626fcf3ce44SJohn Forte 			rval = ISCSI_STATUS_SUCCESS;
627fcf3ce44SJohn Forte 			goto iscsi_login_done;
628fcf3ce44SJohn Forte 		}
629fcf3ce44SJohn Forte 
630fcf3ce44SJohn Forte 	} while (icp->conn_current_stage != ISCSI_FULL_FEATURE_PHASE);
631fcf3ce44SJohn Forte 
632fcf3ce44SJohn Forte 	rval = ISCSI_STATUS_SUCCESS;
633fcf3ce44SJohn Forte 
634fcf3ce44SJohn Forte iscsi_login_done:
635fcf3ce44SJohn Forte 	if (auth_client) {
636fcf3ce44SJohn Forte 		if (iscsiAuthClientFinish(auth_client) !=
637fcf3ce44SJohn Forte 		    iscsiAuthStatusNoError) {
638fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "iscsi connection(%u) login "
639fcf3ce44SJohn Forte 			    "failed - login failed to authenticate "
640fcf3ce44SJohn Forte 			    "with target", icp->conn_oid);
641fcf3ce44SJohn Forte 			if (ISCSI_SUCCESS(rval))
642fcf3ce44SJohn Forte 				rval = ISCSI_STATUS_INTERNAL_ERROR;
643fcf3ce44SJohn Forte 		}
644fcf3ce44SJohn Forte 	}
64530e7468fSPeter Dunlap 
646cc7ef495Syi zhang - Sun Microsystems - Beijing China 	icp->conn_login_status = rval;
64730e7468fSPeter Dunlap 	if (ISCSI_SUCCESS(rval) &&
64830e7468fSPeter Dunlap 	    (*status_class == ISCSI_STATUS_CLASS_SUCCESS)) {
64930e7468fSPeter Dunlap 		mutex_enter(&icp->conn_state_mutex);
65030e7468fSPeter Dunlap 		while (!icp->conn_state_ffp)
65130e7468fSPeter Dunlap 			cv_wait(&icp->conn_state_change,
65230e7468fSPeter Dunlap 			    &icp->conn_state_mutex);
65330e7468fSPeter Dunlap 		mutex_exit(&icp->conn_state_mutex);
65430e7468fSPeter Dunlap 	} else {
65530e7468fSPeter Dunlap 		iscsi_login_disconnect(icp);
65630e7468fSPeter Dunlap 	}
65730e7468fSPeter Dunlap 
65830e7468fSPeter Dunlap 	iscsi_login_update_state(icp, LOGIN_DONE);
65930e7468fSPeter Dunlap 
660fcf3ce44SJohn Forte 	return (rval);
661fcf3ce44SJohn Forte }
662fcf3ce44SJohn Forte 
663fcf3ce44SJohn Forte 
664fcf3ce44SJohn Forte /*
665fcf3ce44SJohn Forte  * iscsi_make_login_pdu -
666fcf3ce44SJohn Forte  *
667fcf3ce44SJohn Forte  */
668fcf3ce44SJohn Forte static iscsi_status_t
66930e7468fSPeter Dunlap iscsi_make_login_pdu(iscsi_conn_t *icp, idm_pdu_t *text_pdu,
670fcf3ce44SJohn Forte     char *data, int max_data_length)
671fcf3ce44SJohn Forte {
672fcf3ce44SJohn Forte 	struct iscsi_sess	*isp		= NULL;
673fcf3ce44SJohn Forte 	int			transit		= 0;
67430e7468fSPeter Dunlap 	iscsi_hdr_t		*ihp		= text_pdu->isp_hdr;
67530e7468fSPeter Dunlap 	iscsi_login_hdr_t	*ilhp		=
67630e7468fSPeter Dunlap 	    (iscsi_login_hdr_t *)text_pdu->isp_hdr;
677fcf3ce44SJohn Forte 	IscsiAuthClient		*auth_client	= NULL;
678fcf3ce44SJohn Forte 	int			keytype		= 0;
679fcf3ce44SJohn Forte 	int			rc		= 0;
680fcf3ce44SJohn Forte 	char			value[iscsiAuthStringMaxLength];
681fcf3ce44SJohn Forte 
682fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
68330e7468fSPeter Dunlap 	ASSERT(text_pdu != NULL);
684fcf3ce44SJohn Forte 	isp = icp->conn_sess;
685fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
686fcf3ce44SJohn Forte 
687fcf3ce44SJohn Forte 	auth_client =
688fcf3ce44SJohn Forte 	    (isp->sess_auth.auth_buffers && isp->sess_auth.num_auth_buffers) ?
689fcf3ce44SJohn Forte 	    (IscsiAuthClient *)isp->sess_auth.auth_buffers[0].address : NULL;
690fcf3ce44SJohn Forte 
691fcf3ce44SJohn Forte 	/*
692fcf3ce44SJohn Forte 	 * initialize the PDU header
693fcf3ce44SJohn Forte 	 */
694fcf3ce44SJohn Forte 	bzero(ilhp, sizeof (*ilhp));
695fcf3ce44SJohn Forte 	ilhp->opcode = ISCSI_OP_LOGIN_CMD | ISCSI_OP_IMMEDIATE;
696fcf3ce44SJohn Forte 	ilhp->cid = icp->conn_cid;
697fcf3ce44SJohn Forte 	bcopy(&isp->sess_isid[0], &ilhp->isid[0], sizeof (isp->sess_isid));
698fcf3ce44SJohn Forte 	ilhp->tsid = 0;
699fcf3ce44SJohn Forte 
70030e7468fSPeter Dunlap 	/*
70130e7468fSPeter Dunlap 	 * Set data buffer pointer.  The calls to iscsi_add_text will update the
70230e7468fSPeter Dunlap 	 * data length.
70330e7468fSPeter Dunlap 	 */
70430e7468fSPeter Dunlap 	text_pdu->isp_data = (uint8_t *)data;
70530e7468fSPeter Dunlap 
706fcf3ce44SJohn Forte 	/* don't increment on immediate */
707fcf3ce44SJohn Forte 	ilhp->cmdsn = htonl(isp->sess_cmdsn);
708fcf3ce44SJohn Forte 
709fcf3ce44SJohn Forte 	ilhp->min_version = ISCSI_DRAFT20_VERSION;
710fcf3ce44SJohn Forte 	ilhp->max_version = ISCSI_DRAFT20_VERSION;
711fcf3ce44SJohn Forte 
712fcf3ce44SJohn Forte 	/*
713fcf3ce44SJohn Forte 	 * we have to send 0 until full-feature stage
714fcf3ce44SJohn Forte 	 */
715fcf3ce44SJohn Forte 	ilhp->expstatsn = htonl(icp->conn_expstatsn);
716fcf3ce44SJohn Forte 
717fcf3ce44SJohn Forte 	/*
718fcf3ce44SJohn Forte 	 * the very first Login PDU has some additional requirements,
719fcf3ce44SJohn Forte 	 * * and we need to decide what stage to start in.
720fcf3ce44SJohn Forte 	 */
721fcf3ce44SJohn Forte 	if (icp->conn_current_stage == ISCSI_INITIAL_LOGIN_STAGE) {
722fcf3ce44SJohn Forte 		if ((isp->sess_hba->hba_name) &&
723fcf3ce44SJohn Forte 		    (isp->sess_hba->hba_name[0])) {
72430e7468fSPeter Dunlap 			if (!iscsi_add_text(text_pdu, max_data_length,
725fcf3ce44SJohn Forte 			    "InitiatorName",
726fcf3ce44SJohn Forte 			    (char *)isp->sess_hba->hba_name)) {
727fcf3ce44SJohn Forte 				return (ISCSI_STATUS_INTERNAL_ERROR);
728fcf3ce44SJohn Forte 			}
729fcf3ce44SJohn Forte 		} else {
730fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "iscsi connection(%u) login "
731fcf3ce44SJohn Forte 			    "failed - initiator name is required",
732fcf3ce44SJohn Forte 			    icp->conn_oid);
733fcf3ce44SJohn Forte 			return (ISCSI_STATUS_INTERNAL_ERROR);
734fcf3ce44SJohn Forte 		}
735fcf3ce44SJohn Forte 
736fcf3ce44SJohn Forte 		if ((isp->sess_hba->hba_alias) &&
737fcf3ce44SJohn Forte 		    (isp->sess_hba->hba_alias[0])) {
73830e7468fSPeter Dunlap 			if (!iscsi_add_text(text_pdu, max_data_length,
739fcf3ce44SJohn Forte 			    "InitiatorAlias",
740fcf3ce44SJohn Forte 			    (char *)isp->sess_hba->hba_alias)) {
741fcf3ce44SJohn Forte 				return (ISCSI_STATUS_INTERNAL_ERROR);
742fcf3ce44SJohn Forte 			}
743fcf3ce44SJohn Forte 		}
744fcf3ce44SJohn Forte 
745fcf3ce44SJohn Forte 		if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
746fcf3ce44SJohn Forte 			if (isp->sess_name[0] != '\0') {
74730e7468fSPeter Dunlap 				if (!iscsi_add_text(text_pdu, max_data_length,
748fcf3ce44SJohn Forte 				    "TargetName", (char *)isp->sess_name)) {
749fcf3ce44SJohn Forte 					return (ISCSI_STATUS_INTERNAL_ERROR);
750fcf3ce44SJohn Forte 				}
751fcf3ce44SJohn Forte 			}
752fcf3ce44SJohn Forte 
75330e7468fSPeter Dunlap 			if (!iscsi_add_text(text_pdu, max_data_length,
754fcf3ce44SJohn Forte 			    "SessionType", "Normal")) {
755fcf3ce44SJohn Forte 				return (ISCSI_STATUS_INTERNAL_ERROR);
756fcf3ce44SJohn Forte 			}
757fcf3ce44SJohn Forte 		} else if (isp->sess_type == ISCSI_SESS_TYPE_DISCOVERY) {
75830e7468fSPeter Dunlap 			if (!iscsi_add_text(text_pdu, max_data_length,
759fcf3ce44SJohn Forte 			    "SessionType", "Discovery")) {
760fcf3ce44SJohn Forte 				return (ISCSI_STATUS_INTERNAL_ERROR);
761fcf3ce44SJohn Forte 			}
762fcf3ce44SJohn Forte 		} else {
763fcf3ce44SJohn Forte 			return (ISCSI_STATUS_INTERNAL_ERROR);
764fcf3ce44SJohn Forte 		}
765fcf3ce44SJohn Forte 
766fcf3ce44SJohn Forte 		if (auth_client) {
767fcf3ce44SJohn Forte 			/* we're prepared to do authentication */
768fcf3ce44SJohn Forte 			icp->conn_current_stage =
769fcf3ce44SJohn Forte 			    ISCSI_SECURITY_NEGOTIATION_STAGE;
770fcf3ce44SJohn Forte 		} else {
771fcf3ce44SJohn Forte 			/* can't do any authentication, skip that stage */
772fcf3ce44SJohn Forte 			icp->conn_current_stage =
773fcf3ce44SJohn Forte 			    ISCSI_OP_PARMS_NEGOTIATION_STAGE;
774fcf3ce44SJohn Forte 		}
775fcf3ce44SJohn Forte 	}
776fcf3ce44SJohn Forte 
777fcf3ce44SJohn Forte 	/*
778fcf3ce44SJohn Forte 	 * fill in text based on the stage
779fcf3ce44SJohn Forte 	 */
780fcf3ce44SJohn Forte 	switch (icp->conn_current_stage) {
781fcf3ce44SJohn Forte 	case ISCSI_OP_PARMS_NEGOTIATION_STAGE:
782fcf3ce44SJohn Forte 		/*
783fcf3ce44SJohn Forte 		 * we always try to go from op params to full
784fcf3ce44SJohn Forte 		 * feature stage
785fcf3ce44SJohn Forte 		 */
786fcf3ce44SJohn Forte 		icp->conn_next_stage	= ISCSI_FULL_FEATURE_PHASE;
787fcf3ce44SJohn Forte 		transit			= 1;
788fcf3ce44SJohn Forte 
789fcf3ce44SJohn Forte 		/*
790fcf3ce44SJohn Forte 		 * The terminology here may have gotten dated.  A partial
791fcf3ce44SJohn Forte 		 * response is a login response that doesn't complete a
792fcf3ce44SJohn Forte 		 * login.  If we haven't gotten a partial response, then
793fcf3ce44SJohn Forte 		 * either we shouldn't be here, or we just switched to
794fcf3ce44SJohn Forte 		 * this stage, and need to start offering keys.
795fcf3ce44SJohn Forte 		 */
796fcf3ce44SJohn Forte 		if (!icp->conn_partial_response) {
797fcf3ce44SJohn Forte 			/*
798fcf3ce44SJohn Forte 			 * request the desired settings the first time
799fcf3ce44SJohn Forte 			 * we are in this stage
800fcf3ce44SJohn Forte 			 */
801fcf3ce44SJohn Forte 			switch (icp->conn_params.header_digest) {
802fcf3ce44SJohn Forte 			case ISCSI_DIGEST_NONE:
80330e7468fSPeter Dunlap 				if (!iscsi_add_text(text_pdu,
804fcf3ce44SJohn Forte 				    max_data_length, "HeaderDigest", "None")) {
805fcf3ce44SJohn Forte 					return (ISCSI_STATUS_INTERNAL_ERROR);
806fcf3ce44SJohn Forte 				}
807fcf3ce44SJohn Forte 				break;
808fcf3ce44SJohn Forte 			case ISCSI_DIGEST_CRC32C:
80930e7468fSPeter Dunlap 				if (!iscsi_add_text(text_pdu,
810fcf3ce44SJohn Forte 				    max_data_length,
811fcf3ce44SJohn Forte 				    "HeaderDigest", "CRC32C")) {
812fcf3ce44SJohn Forte 					return (ISCSI_STATUS_INTERNAL_ERROR);
813fcf3ce44SJohn Forte 				}
814fcf3ce44SJohn Forte 				break;
815fcf3ce44SJohn Forte 			case ISCSI_DIGEST_CRC32C_NONE:
81630e7468fSPeter Dunlap 				if (!iscsi_add_text(text_pdu,
817fcf3ce44SJohn Forte 				    max_data_length, "HeaderDigest",
818fcf3ce44SJohn Forte 				    "CRC32C,None")) {
819fcf3ce44SJohn Forte 					return (ISCSI_STATUS_INTERNAL_ERROR);
820fcf3ce44SJohn Forte 				}
821fcf3ce44SJohn Forte 				break;
822fcf3ce44SJohn Forte 			default:
823fcf3ce44SJohn Forte 			case ISCSI_DIGEST_NONE_CRC32C:
82430e7468fSPeter Dunlap 				if (!iscsi_add_text(text_pdu,
825fcf3ce44SJohn Forte 				    max_data_length, "HeaderDigest",
826fcf3ce44SJohn Forte 				    "None,CRC32C")) {
827fcf3ce44SJohn Forte 					return (ISCSI_STATUS_INTERNAL_ERROR);
828fcf3ce44SJohn Forte 				}
829fcf3ce44SJohn Forte 				break;
830fcf3ce44SJohn Forte 			}
831fcf3ce44SJohn Forte 
832fcf3ce44SJohn Forte 			switch (icp->conn_params.data_digest) {
833fcf3ce44SJohn Forte 			case ISCSI_DIGEST_NONE:
83430e7468fSPeter Dunlap 				if (!iscsi_add_text(text_pdu,
835fcf3ce44SJohn Forte 				    max_data_length, "DataDigest", "None")) {
836fcf3ce44SJohn Forte 					return (ISCSI_STATUS_INTERNAL_ERROR);
837fcf3ce44SJohn Forte 				}
838fcf3ce44SJohn Forte 				break;
839fcf3ce44SJohn Forte 			case ISCSI_DIGEST_CRC32C:
84030e7468fSPeter Dunlap 				if (!iscsi_add_text(text_pdu,
841fcf3ce44SJohn Forte 				    max_data_length, "DataDigest", "CRC32C")) {
842fcf3ce44SJohn Forte 					return (ISCSI_STATUS_INTERNAL_ERROR);
843fcf3ce44SJohn Forte 				}
844fcf3ce44SJohn Forte 				break;
845fcf3ce44SJohn Forte 			case ISCSI_DIGEST_CRC32C_NONE:
84630e7468fSPeter Dunlap 				if (!iscsi_add_text(text_pdu,
847fcf3ce44SJohn Forte 				    max_data_length, "DataDigest",
848fcf3ce44SJohn Forte 				    "CRC32C,None")) {
849fcf3ce44SJohn Forte 					return (ISCSI_STATUS_INTERNAL_ERROR);
850fcf3ce44SJohn Forte 				}
851fcf3ce44SJohn Forte 				break;
852fcf3ce44SJohn Forte 			default:
853fcf3ce44SJohn Forte 			case ISCSI_DIGEST_NONE_CRC32C:
85430e7468fSPeter Dunlap 				if (!iscsi_add_text(text_pdu,
855fcf3ce44SJohn Forte 				    max_data_length, "DataDigest",
856fcf3ce44SJohn Forte 				    "None,CRC32C")) {
857fcf3ce44SJohn Forte 					return (ISCSI_STATUS_INTERNAL_ERROR);
858fcf3ce44SJohn Forte 				}
859fcf3ce44SJohn Forte 				break;
860fcf3ce44SJohn Forte 			}
861fcf3ce44SJohn Forte 
862fcf3ce44SJohn Forte 			(void) sprintf(value, "%d",
863fcf3ce44SJohn Forte 			    icp->conn_params.max_recv_data_seg_len);
86430e7468fSPeter Dunlap 			if (!iscsi_add_text(text_pdu, max_data_length,
865fcf3ce44SJohn Forte 			    "MaxRecvDataSegmentLength", value)) {
866fcf3ce44SJohn Forte 				return (ISCSI_STATUS_INTERNAL_ERROR);
867fcf3ce44SJohn Forte 			}
868fcf3ce44SJohn Forte 
869fcf3ce44SJohn Forte 			(void) sprintf(value, "%d",
870fcf3ce44SJohn Forte 			    icp->conn_params.default_time_to_wait);
87130e7468fSPeter Dunlap 			if (!iscsi_add_text(text_pdu,
872fcf3ce44SJohn Forte 			    max_data_length, "DefaultTime2Wait", value)) {
873fcf3ce44SJohn Forte 				return (ISCSI_STATUS_INTERNAL_ERROR);
874fcf3ce44SJohn Forte 			}
875fcf3ce44SJohn Forte 
876fcf3ce44SJohn Forte 			(void) sprintf(value, "%d",
877fcf3ce44SJohn Forte 			    icp->conn_params.default_time_to_retain);
87830e7468fSPeter Dunlap 			if (!iscsi_add_text(text_pdu,
879fcf3ce44SJohn Forte 			    max_data_length, "DefaultTime2Retain", value)) {
880fcf3ce44SJohn Forte 				return (ISCSI_STATUS_INTERNAL_ERROR);
881fcf3ce44SJohn Forte 			}
882fcf3ce44SJohn Forte 
883fcf3ce44SJohn Forte 			(void) sprintf(value, "%d",
884fcf3ce44SJohn Forte 			    icp->conn_params.error_recovery_level);
88530e7468fSPeter Dunlap 			if (!iscsi_add_text(text_pdu,
886fcf3ce44SJohn Forte 			    max_data_length, "ErrorRecoveryLevel", "0")) {
887fcf3ce44SJohn Forte 				return (ISCSI_STATUS_INTERNAL_ERROR);
888fcf3ce44SJohn Forte 			}
889fcf3ce44SJohn Forte 
89030e7468fSPeter Dunlap 			if (!iscsi_add_text(text_pdu,
891fcf3ce44SJohn Forte 			    max_data_length, "IFMarker",
892fcf3ce44SJohn Forte 			    icp->conn_params.ifmarker ? "Yes" : "No")) {
893fcf3ce44SJohn Forte 				return (ISCSI_STATUS_INTERNAL_ERROR);
894fcf3ce44SJohn Forte 			}
895fcf3ce44SJohn Forte 
89630e7468fSPeter Dunlap 			if (!iscsi_add_text(text_pdu,
897fcf3ce44SJohn Forte 			    max_data_length, "OFMarker",
898fcf3ce44SJohn Forte 			    icp->conn_params.ofmarker ? "Yes" : "No")) {
899fcf3ce44SJohn Forte 				return (ISCSI_STATUS_INTERNAL_ERROR);
900fcf3ce44SJohn Forte 			}
901fcf3ce44SJohn Forte 
902fcf3ce44SJohn Forte 			/*
903fcf3ce44SJohn Forte 			 * The following login parameters are "Irrelevant"
904fcf3ce44SJohn Forte 			 * for discovery sessions
905fcf3ce44SJohn Forte 			 */
906fcf3ce44SJohn Forte 			if (isp->sess_type != ISCSI_SESS_TYPE_DISCOVERY) {
907fcf3ce44SJohn Forte 
90830e7468fSPeter Dunlap 				if (!iscsi_add_text(text_pdu,
909fcf3ce44SJohn Forte 				    max_data_length, "InitialR2T",
910fcf3ce44SJohn Forte 				    icp->conn_params.initial_r2t ?
911fcf3ce44SJohn Forte 				    "Yes" : "No")) {
912fcf3ce44SJohn Forte 					return (ISCSI_STATUS_INTERNAL_ERROR);
913fcf3ce44SJohn Forte 				}
914fcf3ce44SJohn Forte 
91530e7468fSPeter Dunlap 				if (!iscsi_add_text(text_pdu,
916fcf3ce44SJohn Forte 				    max_data_length, "ImmediateData",
917fcf3ce44SJohn Forte 				    icp->conn_params.immediate_data ?
918fcf3ce44SJohn Forte 				    "Yes" : "No")) {
919fcf3ce44SJohn Forte 					return (ISCSI_STATUS_INTERNAL_ERROR);
920fcf3ce44SJohn Forte 				}
921fcf3ce44SJohn Forte 
922fcf3ce44SJohn Forte 				(void) sprintf(value, "%d",
923fcf3ce44SJohn Forte 				    icp->conn_params.max_burst_length);
92430e7468fSPeter Dunlap 				if (!iscsi_add_text(text_pdu,
925fcf3ce44SJohn Forte 				    max_data_length, "MaxBurstLength", value)) {
926fcf3ce44SJohn Forte 					return (ISCSI_STATUS_INTERNAL_ERROR);
927fcf3ce44SJohn Forte 				}
928fcf3ce44SJohn Forte 
929fcf3ce44SJohn Forte 				(void) sprintf(value, "%d",
930fcf3ce44SJohn Forte 				    icp->conn_params.first_burst_length);
93130e7468fSPeter Dunlap 				if (!iscsi_add_text(text_pdu, max_data_length,
932fcf3ce44SJohn Forte 				    "FirstBurstLength", value)) {
933fcf3ce44SJohn Forte 					return (ISCSI_STATUS_INTERNAL_ERROR);
934fcf3ce44SJohn Forte 				}
935fcf3ce44SJohn Forte 
936fcf3ce44SJohn Forte 				(void) sprintf(value, "%d",
937fcf3ce44SJohn Forte 				    icp->conn_params.max_outstanding_r2t);
93830e7468fSPeter Dunlap 				if (!iscsi_add_text(text_pdu, max_data_length,
939fcf3ce44SJohn Forte 				    "MaxOutstandingR2T", value)) {
940fcf3ce44SJohn Forte 					return (ISCSI_STATUS_INTERNAL_ERROR);
941fcf3ce44SJohn Forte 				}
942fcf3ce44SJohn Forte 
943fcf3ce44SJohn Forte 				(void) sprintf(value, "%d",
944fcf3ce44SJohn Forte 				    icp->conn_params.max_connections);
94530e7468fSPeter Dunlap 				if (!iscsi_add_text(text_pdu, max_data_length,
946fcf3ce44SJohn Forte 				    "MaxConnections", value)) {
947fcf3ce44SJohn Forte 					return (ISCSI_STATUS_INTERNAL_ERROR);
948fcf3ce44SJohn Forte 				}
949fcf3ce44SJohn Forte 
95030e7468fSPeter Dunlap 				if (!iscsi_add_text(text_pdu,
951fcf3ce44SJohn Forte 				    max_data_length, "DataPDUInOrder",
952fcf3ce44SJohn Forte 				    icp->conn_params.data_pdu_in_order ?
953fcf3ce44SJohn Forte 				    "Yes" : "No")) {
954fcf3ce44SJohn Forte 					return (ISCSI_STATUS_INTERNAL_ERROR);
955fcf3ce44SJohn Forte 				}
956fcf3ce44SJohn Forte 
95730e7468fSPeter Dunlap 				if (!iscsi_add_text(text_pdu,
958fcf3ce44SJohn Forte 				    max_data_length, "DataSequenceInOrder",
959fcf3ce44SJohn Forte 				    icp->conn_params.data_sequence_in_order ?
960fcf3ce44SJohn Forte 				    "Yes" : "No")) {
961fcf3ce44SJohn Forte 					return (ISCSI_STATUS_INTERNAL_ERROR);
962fcf3ce44SJohn Forte 				}
963fcf3ce44SJohn Forte 			}
964fcf3ce44SJohn Forte 		}
965fcf3ce44SJohn Forte 		break;
966fcf3ce44SJohn Forte 
967fcf3ce44SJohn Forte 	case ISCSI_SECURITY_NEGOTIATION_STAGE:
968fcf3ce44SJohn Forte 		keytype = iscsiAuthKeyTypeNone;
969fcf3ce44SJohn Forte 		rc = iscsiAuthClientSendTransitBit(auth_client, &transit);
970fcf3ce44SJohn Forte 
971fcf3ce44SJohn Forte 		/*
972fcf3ce44SJohn Forte 		 * see if we're ready for a stage change
973fcf3ce44SJohn Forte 		 */
974fcf3ce44SJohn Forte 		if (rc == iscsiAuthStatusNoError) {
975fcf3ce44SJohn Forte 			if (transit) {
976fcf3ce44SJohn Forte 				icp->conn_next_stage =
977fcf3ce44SJohn Forte 				    ISCSI_OP_PARMS_NEGOTIATION_STAGE;
978fcf3ce44SJohn Forte 			} else {
979fcf3ce44SJohn Forte 				icp->conn_next_stage =
980fcf3ce44SJohn Forte 				    ISCSI_SECURITY_NEGOTIATION_STAGE;
981fcf3ce44SJohn Forte 			}
982fcf3ce44SJohn Forte 		} else {
983fcf3ce44SJohn Forte 			return (ISCSI_STATUS_INTERNAL_ERROR);
984fcf3ce44SJohn Forte 		}
985fcf3ce44SJohn Forte 
986fcf3ce44SJohn Forte 		/*
987fcf3ce44SJohn Forte 		 * enumerate all the keys the auth code might want to send
988fcf3ce44SJohn Forte 		 */
989fcf3ce44SJohn Forte 		while (iscsiAuthClientGetNextKeyType(&keytype) ==
990fcf3ce44SJohn Forte 		    iscsiAuthStatusNoError) {
991fcf3ce44SJohn Forte 			int present = 0;
992fcf3ce44SJohn Forte 			char *key = (char *)iscsiAuthClientGetKeyName(keytype);
993fcf3ce44SJohn Forte 			int key_length = key ? strlen(key) : 0;
99430e7468fSPeter Dunlap 			int pdu_length = text_pdu->isp_datalen;
995fcf3ce44SJohn Forte 			char *auth_value = data + pdu_length + key_length + 1;
996fcf3ce44SJohn Forte 			unsigned int max_length = max_data_length -
997fcf3ce44SJohn Forte 			    (pdu_length + key_length + 1);
998fcf3ce44SJohn Forte 
999fcf3ce44SJohn Forte 			/*
1000fcf3ce44SJohn Forte 			 * add the key/value pairs the auth code wants to
1001fcf3ce44SJohn Forte 			 * send directly to the PDU, since they could in
1002fcf3ce44SJohn Forte 			 * theory be large.
1003fcf3ce44SJohn Forte 			 */
1004fcf3ce44SJohn Forte 			rc = iscsiAuthClientSendKeyValue(auth_client, keytype,
1005fcf3ce44SJohn Forte 			    &present, auth_value, max_length);
1006fcf3ce44SJohn Forte 			if ((rc == iscsiAuthStatusNoError) && present) {
1007fcf3ce44SJohn Forte 				/*
1008fcf3ce44SJohn Forte 				 * actually fill in the key
1009fcf3ce44SJohn Forte 				 */
1010fcf3ce44SJohn Forte 				(void) strncpy(&data[pdu_length], key,
1011fcf3ce44SJohn Forte 				    key_length);
1012fcf3ce44SJohn Forte 				pdu_length += key_length;
1013fcf3ce44SJohn Forte 				data[pdu_length] = '=';
1014fcf3ce44SJohn Forte 				pdu_length++;
1015fcf3ce44SJohn Forte 				/*
1016fcf3ce44SJohn Forte 				 * adjust the PDU's data segment length to
1017fcf3ce44SJohn Forte 				 * include the value and trailing NULL
1018fcf3ce44SJohn Forte 				 */
1019fcf3ce44SJohn Forte 				pdu_length += strlen(auth_value) + 1;
102030e7468fSPeter Dunlap 				text_pdu->isp_datalen = pdu_length;
1021fcf3ce44SJohn Forte 				hton24(ihp->dlength, pdu_length);
1022fcf3ce44SJohn Forte 			}
1023fcf3ce44SJohn Forte 		}
1024fcf3ce44SJohn Forte 
1025fcf3ce44SJohn Forte 		break;
1026fcf3ce44SJohn Forte 	case ISCSI_FULL_FEATURE_PHASE:
1027fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi connection(%u) login "
1028fcf3ce44SJohn Forte 		    "failed - can't send login in full feature stage",
1029fcf3ce44SJohn Forte 		    icp->conn_oid);
1030fcf3ce44SJohn Forte 		return (ISCSI_STATUS_INTERNAL_ERROR);
1031fcf3ce44SJohn Forte 	default:
1032fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi connection(%u) login "
1033fcf3ce44SJohn Forte 		    "failed - can't send login in unknown stage (%d)",
1034fcf3ce44SJohn Forte 		    icp->conn_oid, icp->conn_current_stage);
1035fcf3ce44SJohn Forte 		return (ISCSI_STATUS_INTERNAL_ERROR);
1036fcf3ce44SJohn Forte 	}
1037fcf3ce44SJohn Forte 
1038fcf3ce44SJohn Forte 	/* fill in the flags */
1039fcf3ce44SJohn Forte 	ilhp->flags = icp->conn_current_stage << 2;
1040fcf3ce44SJohn Forte 	if (transit) {
1041fcf3ce44SJohn Forte 		/* transit to the next stage */
1042fcf3ce44SJohn Forte 		ilhp->flags |= icp->conn_next_stage;
1043fcf3ce44SJohn Forte 		ilhp->flags |= ISCSI_FLAG_LOGIN_TRANSIT;
1044fcf3ce44SJohn Forte 	} else {
1045fcf3ce44SJohn Forte 		/* next == current */
1046fcf3ce44SJohn Forte 		ilhp->flags |= icp->conn_current_stage;
1047fcf3ce44SJohn Forte 	}
1048fcf3ce44SJohn Forte 
1049fcf3ce44SJohn Forte 	return (ISCSI_STATUS_SUCCESS);
1050fcf3ce44SJohn Forte }
1051fcf3ce44SJohn Forte 
1052fcf3ce44SJohn Forte 
1053fcf3ce44SJohn Forte /*
1054fcf3ce44SJohn Forte  * iscsi_process_login_response - This assumes the text data is
1055fcf3ce44SJohn Forte  * always NUL terminated.  The caller can always arrange for that by
1056fcf3ce44SJohn Forte  * using a slightly larger buffer than the max PDU size, and then
1057fcf3ce44SJohn Forte  * appending a NUL to the PDU.
1058fcf3ce44SJohn Forte  */
1059fcf3ce44SJohn Forte static iscsi_status_t
1060fcf3ce44SJohn Forte iscsi_process_login_response(iscsi_conn_t *icp,
1061fcf3ce44SJohn Forte     iscsi_login_rsp_hdr_t *ilrhp, char *data, int max_data_length)
1062fcf3ce44SJohn Forte {
1063fcf3ce44SJohn Forte 	iscsi_sess_t		*isp			= NULL;
1064fcf3ce44SJohn Forte 	IscsiAuthClient		*auth_client		= NULL;
1065fcf3ce44SJohn Forte 	int			transit			= 0;
1066fcf3ce44SJohn Forte 	char			*text			= data;
1067fcf3ce44SJohn Forte 	char			*end			= NULL;
1068fcf3ce44SJohn Forte 	int			pdu_current_stage	= 0;
1069fcf3ce44SJohn Forte 	int			pdu_next_stage		= 0;
1070fcf3ce44SJohn Forte 	int			debug_status		= 0;
1071fcf3ce44SJohn Forte 	unsigned long		tmp;
1072fcf3ce44SJohn Forte 	char			*tmpe;
1073fcf3ce44SJohn Forte 	boolean_t		fbl_irrelevant		= B_FALSE;
1074fcf3ce44SJohn Forte 
1075fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
1076fcf3ce44SJohn Forte 	ASSERT(ilrhp != NULL);
1077fcf3ce44SJohn Forte 	ASSERT(data != NULL);
1078fcf3ce44SJohn Forte 	isp = icp->conn_sess;
1079fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
1080fcf3ce44SJohn Forte 
1081fcf3ce44SJohn Forte 	auth_client =
1082fcf3ce44SJohn Forte 	    (isp->sess_auth.auth_buffers && isp->sess_auth.num_auth_buffers) ?
1083fcf3ce44SJohn Forte 	    (IscsiAuthClient *) isp->sess_auth.auth_buffers[0].address : NULL;
1084fcf3ce44SJohn Forte 	transit = ilrhp->flags & ISCSI_FLAG_LOGIN_TRANSIT;
1085fcf3ce44SJohn Forte 
1086fcf3ce44SJohn Forte 	/* verify the initial buffer was big enough to hold everything */
1087fcf3ce44SJohn Forte 	end = text + ntoh24(ilrhp->dlength) + 1;
1088fcf3ce44SJohn Forte 	if (end >= (data + max_data_length)) {
1089fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
1090fcf3ce44SJohn Forte 		    "buffer too small", icp->conn_oid);
1091fcf3ce44SJohn Forte 		return (ISCSI_STATUS_INTERNAL_ERROR);
1092fcf3ce44SJohn Forte 	}
1093fcf3ce44SJohn Forte 	*end = '\0';
1094fcf3ce44SJohn Forte 
1095fcf3ce44SJohn Forte 	/* if the response status was success, sanity check the response */
1096fcf3ce44SJohn Forte 	if (ilrhp->status_class == ISCSI_STATUS_CLASS_SUCCESS) {
1097fcf3ce44SJohn Forte 		/* check the active version */
1098fcf3ce44SJohn Forte 		if (ilrhp->active_version != ISCSI_DRAFT20_VERSION) {
1099fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "iscsi connection(%u) login "
1100fcf3ce44SJohn Forte 			    "failed - target version incompatible "
1101fcf3ce44SJohn Forte 			    "received:0x%0x2x expected:0x%02x",
1102fcf3ce44SJohn Forte 			    icp->conn_oid, ilrhp->active_version,
1103fcf3ce44SJohn Forte 			    ISCSI_DRAFT20_VERSION);
1104fcf3ce44SJohn Forte 			return (ISCSI_STATUS_VERSION_MISMATCH);
1105fcf3ce44SJohn Forte 		}
1106fcf3ce44SJohn Forte 
1107fcf3ce44SJohn Forte 		/* make sure the current stage matches */
1108fcf3ce44SJohn Forte 		pdu_current_stage = (ilrhp->flags &
1109fcf3ce44SJohn Forte 		    ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2;
1110fcf3ce44SJohn Forte 		if (pdu_current_stage != icp->conn_current_stage) {
1111fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "iscsi connection(%u) login "
1112fcf3ce44SJohn Forte 			    "failed - login response contained invalid "
1113fcf3ce44SJohn Forte 			    "stage %d", icp->conn_oid, pdu_current_stage);
1114fcf3ce44SJohn Forte 			return (ISCSI_STATUS_PROTOCOL_ERROR);
1115fcf3ce44SJohn Forte 		}
1116fcf3ce44SJohn Forte 
1117fcf3ce44SJohn Forte 		/*
1118fcf3ce44SJohn Forte 		 * Make sure that we're actually advancing
1119fcf3ce44SJohn Forte 		 * if the T-bit is set
1120fcf3ce44SJohn Forte 		 */
1121fcf3ce44SJohn Forte 		pdu_next_stage = ilrhp->flags &
1122fcf3ce44SJohn Forte 		    ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK;
1123fcf3ce44SJohn Forte 		if (transit && (pdu_next_stage <= icp->conn_current_stage)) {
1124fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "iscsi connection(%u) login "
1125fcf3ce44SJohn Forte 			    "failed - login response wants to go to stage "
1126fcf3ce44SJohn Forte 			    "%d, but we want stage %d", icp->conn_oid,
1127fcf3ce44SJohn Forte 			    pdu_next_stage, icp->conn_next_stage);
1128fcf3ce44SJohn Forte 			return (ISCSI_STATUS_PROTOCOL_ERROR);
1129fcf3ce44SJohn Forte 		}
1130fcf3ce44SJohn Forte 	}
1131fcf3ce44SJohn Forte 
1132fcf3ce44SJohn Forte 	if (icp->conn_current_stage == ISCSI_SECURITY_NEGOTIATION_STAGE) {
1133fcf3ce44SJohn Forte 		if (iscsiAuthClientRecvBegin(auth_client) !=
1134fcf3ce44SJohn Forte 		    iscsiAuthStatusNoError) {
1135fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
1136fcf3ce44SJohn Forte 			    "authentication receive failed", icp->conn_oid);
1137fcf3ce44SJohn Forte 			return (ISCSI_STATUS_INTERNAL_ERROR);
1138fcf3ce44SJohn Forte 		}
1139fcf3ce44SJohn Forte 
1140fcf3ce44SJohn Forte 		if (iscsiAuthClientRecvTransitBit(auth_client,
1141fcf3ce44SJohn Forte 		    transit) != iscsiAuthStatusNoError) {
1142fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
1143fcf3ce44SJohn Forte 			    "authentication transmit failed", icp->conn_oid);
1144fcf3ce44SJohn Forte 			return (ISCSI_STATUS_INTERNAL_ERROR);
1145fcf3ce44SJohn Forte 		}
1146fcf3ce44SJohn Forte 	}
1147fcf3ce44SJohn Forte 
1148fcf3ce44SJohn Forte 	/*
1149fcf3ce44SJohn Forte 	 * scan the text data
1150fcf3ce44SJohn Forte 	 */
1151fcf3ce44SJohn Forte more_text:
1152fcf3ce44SJohn Forte 	while (text && (text < end)) {
1153fcf3ce44SJohn Forte 		char *value = NULL;
1154fcf3ce44SJohn Forte 		char *value_end = NULL;
1155fcf3ce44SJohn Forte 
1156fcf3ce44SJohn Forte 		/*
1157fcf3ce44SJohn Forte 		 * skip any NULs separating each text key=value pair
1158fcf3ce44SJohn Forte 		 */
1159fcf3ce44SJohn Forte 		while ((text < end) && (*text == '\0')) {
1160fcf3ce44SJohn Forte 			text++;
1161fcf3ce44SJohn Forte 		}
1162fcf3ce44SJohn Forte 		if (text >= end) {
1163fcf3ce44SJohn Forte 			break;
1164fcf3ce44SJohn Forte 		}
1165fcf3ce44SJohn Forte 
1166fcf3ce44SJohn Forte 		/*
1167fcf3ce44SJohn Forte 		 * handle keys appropriate for each stage
1168fcf3ce44SJohn Forte 		 */
1169fcf3ce44SJohn Forte 		switch (icp->conn_current_stage) {
1170fcf3ce44SJohn Forte 		case ISCSI_SECURITY_NEGOTIATION_STAGE:
1171fcf3ce44SJohn Forte 			/*
1172fcf3ce44SJohn Forte 			 * a few keys are possible in Security stage
1173fcf3ce44SJohn Forte 			 * * which the auth code doesn't care about,
1174fcf3ce44SJohn Forte 			 * * but which we might want to see, or at
1175fcf3ce44SJohn Forte 			 * * least not choke on.
1176fcf3ce44SJohn Forte 			 */
1177fcf3ce44SJohn Forte 			if (iscsi_find_key_value("TargetAlias",
1178fcf3ce44SJohn Forte 			    text, end, &value, &value_end)) {
1179fcf3ce44SJohn Forte 				isp->sess_alias_length =
1180fcf3ce44SJohn Forte 				    sizeof (isp->sess_alias) - 1;
1181fcf3ce44SJohn Forte 
1182fcf3ce44SJohn Forte 				if ((value_end - value) <
1183fcf3ce44SJohn Forte 				    isp->sess_alias_length) {
1184fcf3ce44SJohn Forte 					isp->sess_alias_length =
1185fcf3ce44SJohn Forte 					    value_end - value;
1186fcf3ce44SJohn Forte 				}
1187fcf3ce44SJohn Forte 
1188fcf3ce44SJohn Forte 				bcopy(value, isp->sess_alias,
1189fcf3ce44SJohn Forte 				    isp->sess_alias_length);
1190fcf3ce44SJohn Forte 				isp->sess_alias[isp->sess_alias_length + 1] =
1191fcf3ce44SJohn Forte 				    '\0';
1192fcf3ce44SJohn Forte 				text = value_end;
1193fcf3ce44SJohn Forte 
1194fcf3ce44SJohn Forte 			} else if (iscsi_find_key_value("TargetAddress",
1195fcf3ce44SJohn Forte 			    text, end, &value, &value_end)) {
1196fcf3ce44SJohn Forte 				if (!ISCSI_SUCCESS(iscsi_update_address(
1197fcf3ce44SJohn Forte 				    icp, value))) {
1198fcf3ce44SJohn Forte 					cmn_err(CE_WARN, "iscsi connection(%u) "
1199fcf3ce44SJohn Forte 					    "login failed - login redirection "
1200fcf3ce44SJohn Forte 					    "invalid", icp->conn_oid);
1201fcf3ce44SJohn Forte 					return (ISCSI_STATUS_PROTOCOL_ERROR);
1202fcf3ce44SJohn Forte 				}
1203fcf3ce44SJohn Forte 				text = value_end;
1204fcf3ce44SJohn Forte 			} else if (iscsi_find_key_value("TargetPortalGroupTag",
1205fcf3ce44SJohn Forte 			    text, end, &value, &value_end)) {
1206fcf3ce44SJohn Forte 				/*
1207fcf3ce44SJohn Forte 				 * We should have already obtained this via
1208fcf3ce44SJohn Forte 				 * discovery.  We've already picked an isid,
1209fcf3ce44SJohn Forte 				 * so the most we can do is confirm we reached
1210fcf3ce44SJohn Forte 				 * the portal group we were expecting to.
1211fcf3ce44SJohn Forte 				 */
1212fcf3ce44SJohn Forte 				if (ddi_strtoul(value, &tmpe, 0, &tmp) != 0) {
1213fcf3ce44SJohn Forte 					return (ISCSI_STATUS_PROTOCOL_ERROR);
1214fcf3ce44SJohn Forte 				}
1215fcf3ce44SJohn Forte 				if (isp->sess_tpgt_conf != ISCSI_DEFAULT_TPGT) {
1216fcf3ce44SJohn Forte 					if (tmp != isp->sess_tpgt_conf) {
1217fcf3ce44SJohn Forte 
1218fcf3ce44SJohn Forte 	cmn_err(CE_WARN, "iscsi connection(%u) login failed - target "
1219fcf3ce44SJohn Forte 	    "protocol group tag mismatch, expected %d, received %lu",
1220fcf3ce44SJohn Forte 	    icp->conn_oid, isp->sess_tpgt_conf, tmp);
1221cc7ef495Syi zhang - Sun Microsystems - Beijing China 	return (ISCSI_STATUS_LOGIN_TPGT_NEGO_FAIL);
1222fcf3ce44SJohn Forte 
1223fcf3ce44SJohn Forte 					}
1224fcf3ce44SJohn Forte 				}
1225fcf3ce44SJohn Forte 				isp->sess_tpgt_nego = (int)tmp;
1226fcf3ce44SJohn Forte 				text = value_end;
1227fcf3ce44SJohn Forte 			} else {
1228fcf3ce44SJohn Forte 				/*
1229fcf3ce44SJohn Forte 				 * any key we don't recognize either goes
1230fcf3ce44SJohn Forte 				 * to the auth code, or we choke on it
1231fcf3ce44SJohn Forte 				 */
1232fcf3ce44SJohn Forte 				int keytype = iscsiAuthKeyTypeNone;
1233fcf3ce44SJohn Forte 
1234fcf3ce44SJohn Forte 				while (iscsiAuthClientGetNextKeyType(
1235fcf3ce44SJohn Forte 				    &keytype) == iscsiAuthStatusNoError) {
1236fcf3ce44SJohn Forte 
1237fcf3ce44SJohn Forte 					char *key =
1238fcf3ce44SJohn Forte 					    (char *)iscsiAuthClientGetKeyName(
1239fcf3ce44SJohn Forte 					    keytype);
1240fcf3ce44SJohn Forte 
1241fcf3ce44SJohn Forte 					if ((key) &&
1242fcf3ce44SJohn Forte 					    (iscsi_find_key_value(key,
1243fcf3ce44SJohn Forte 					    text, end, &value, &value_end))) {
1244fcf3ce44SJohn Forte 
1245fcf3ce44SJohn Forte 						if (iscsiAuthClientRecvKeyValue
1246fcf3ce44SJohn Forte 						    (auth_client, keytype,
1247fcf3ce44SJohn Forte 						    value) !=
1248fcf3ce44SJohn Forte 						    iscsiAuthStatusNoError) {
1249fcf3ce44SJohn Forte 
1250fcf3ce44SJohn Forte 	cmn_err(CE_WARN, "iscsi connection(%u) login failed - can't accept "
1251fcf3ce44SJohn Forte 	    "%s in security stage", icp->conn_oid, text);
1252fcf3ce44SJohn Forte 	return (ISCSI_STATUS_NEGO_FAIL);
1253fcf3ce44SJohn Forte 
1254fcf3ce44SJohn Forte 						}
1255fcf3ce44SJohn Forte 						text = value_end;
1256fcf3ce44SJohn Forte 						goto more_text;
1257fcf3ce44SJohn Forte 					}
1258fcf3ce44SJohn Forte 				}
1259fcf3ce44SJohn Forte 
1260fcf3ce44SJohn Forte 	cmn_err(CE_WARN, "iscsi connection(%u) login failed - can't except "
1261fcf3ce44SJohn Forte 	    "%s in security stage", icp->conn_oid, text);
1262fcf3ce44SJohn Forte 
1263fcf3ce44SJohn Forte 				return (ISCSI_STATUS_NEGO_FAIL);
1264fcf3ce44SJohn Forte 			}
1265fcf3ce44SJohn Forte 			break;
1266fcf3ce44SJohn Forte 		case ISCSI_OP_PARMS_NEGOTIATION_STAGE:
1267fcf3ce44SJohn Forte 			if (iscsi_find_key_value("TargetAlias", text,
1268fcf3ce44SJohn Forte 			    end, &value, &value_end)) {
1269fcf3ce44SJohn Forte 				isp->sess_alias_length =
1270fcf3ce44SJohn Forte 				    sizeof (isp->sess_alias) - 1;
1271fcf3ce44SJohn Forte 
1272fcf3ce44SJohn Forte 				if ((value_end - value) <
1273fcf3ce44SJohn Forte 				    isp->sess_alias_length) {
1274fcf3ce44SJohn Forte 					isp->sess_alias_length =
1275fcf3ce44SJohn Forte 					    value_end - value;
1276fcf3ce44SJohn Forte 				}
1277fcf3ce44SJohn Forte 
1278fcf3ce44SJohn Forte 				bcopy(value, isp->sess_alias,
1279fcf3ce44SJohn Forte 				    isp->sess_alias_length);
1280fcf3ce44SJohn Forte 				isp->sess_alias[isp->sess_alias_length + 1] =
1281fcf3ce44SJohn Forte 				    '\0';
1282fcf3ce44SJohn Forte 				text = value_end;
1283fcf3ce44SJohn Forte 
1284fcf3ce44SJohn Forte 			} else if (iscsi_find_key_value("TargetAddress",
1285fcf3ce44SJohn Forte 			    text, end, &value, &value_end)) {
1286fcf3ce44SJohn Forte 				if (!ISCSI_SUCCESS(iscsi_update_address(
1287fcf3ce44SJohn Forte 				    icp, value))) {
1288fcf3ce44SJohn Forte 
1289fcf3ce44SJohn Forte 	cmn_err(CE_WARN, "iscsi connection(%u) login failed - login "
1290fcf3ce44SJohn Forte 	    "redirection invalid", icp->conn_oid);
1291fcf3ce44SJohn Forte 
1292fcf3ce44SJohn Forte 					return (ISCSI_STATUS_PROTOCOL_ERROR);
1293fcf3ce44SJohn Forte 				}
1294fcf3ce44SJohn Forte 				text = value_end;
1295fcf3ce44SJohn Forte 			} else if (iscsi_find_key_value("TargetPortalGroupTag",
1296fcf3ce44SJohn Forte 			    text, end, &value, &value_end)) {
1297fcf3ce44SJohn Forte 				/*
1298fcf3ce44SJohn Forte 				 * We should have already obtained this via
1299fcf3ce44SJohn Forte 				 * discovery.  We've already picked an isid,
1300fcf3ce44SJohn Forte 				 * so the most we can do is confirm we reached
1301fcf3ce44SJohn Forte 				 * the portal group we were expecting to.
1302fcf3ce44SJohn Forte 				 */
1303fcf3ce44SJohn Forte 				if (ddi_strtoul(value, &tmpe, 0, &tmp) != 0) {
1304fcf3ce44SJohn Forte 					return (ISCSI_STATUS_PROTOCOL_ERROR);
1305fcf3ce44SJohn Forte 				}
1306fcf3ce44SJohn Forte 				if (isp->sess_tpgt_conf != ISCSI_DEFAULT_TPGT) {
1307fcf3ce44SJohn Forte 					if (tmp != isp->sess_tpgt_conf) {
1308fcf3ce44SJohn Forte 
1309fcf3ce44SJohn Forte 	cmn_err(CE_WARN, "iscsi connection(%u) login failed - target portal "
1310fcf3ce44SJohn Forte 	    "tag mismatch, expected:%d received:%lu", icp->conn_oid,
1311fcf3ce44SJohn Forte 	    isp->sess_tpgt_conf, tmp);
1312cc7ef495Syi zhang - Sun Microsystems - Beijing China 	return (ISCSI_STATUS_LOGIN_TPGT_NEGO_FAIL);
1313fcf3ce44SJohn Forte 
1314fcf3ce44SJohn Forte 					}
1315fcf3ce44SJohn Forte 				}
1316fcf3ce44SJohn Forte 				isp->sess_tpgt_nego = (int)tmp;
1317fcf3ce44SJohn Forte 				text = value_end;
1318fcf3ce44SJohn Forte 
1319fcf3ce44SJohn Forte 			} else if (iscsi_find_key_value("InitialR2T",
1320fcf3ce44SJohn Forte 			    text, end, &value, &value_end)) {
1321fcf3ce44SJohn Forte 
1322fcf3ce44SJohn Forte 				/*
1323fcf3ce44SJohn Forte 				 * iSCSI RFC section 12.10 states that
1324fcf3ce44SJohn Forte 				 * InitialR2T is Irrelevant for a
1325fcf3ce44SJohn Forte 				 * discovery session.
1326fcf3ce44SJohn Forte 				 */
1327fcf3ce44SJohn Forte 				if (isp->sess_type ==
1328fcf3ce44SJohn Forte 				    ISCSI_SESS_TYPE_DISCOVERY) {
1329fcf3ce44SJohn Forte 					/* EMPTY */
1330fcf3ce44SJohn Forte 				} else if (value == NULL) {
1331fcf3ce44SJohn Forte 					cmn_err(CE_WARN, "iscsi connection(%u) "
1332fcf3ce44SJohn Forte 					    "login failed - InitialR2T is "
1333fcf3ce44SJohn Forte 					    "invalid - protocol error",
1334fcf3ce44SJohn Forte 					    icp->conn_oid);
1335fcf3ce44SJohn Forte 					return (ISCSI_STATUS_PROTOCOL_ERROR);
1336fcf3ce44SJohn Forte 				} else if (strcmp(value, "Yes") == 0) {
1337fcf3ce44SJohn Forte 					icp->conn_params.initial_r2t = B_TRUE;
1338fcf3ce44SJohn Forte 				} else if (strcmp(value, "No") == 0) {
1339fcf3ce44SJohn Forte 					icp->conn_params.initial_r2t = B_FALSE;
1340fcf3ce44SJohn Forte 				} else {
1341fcf3ce44SJohn Forte 					cmn_err(CE_WARN, "iscsi connection(%u) "
1342fcf3ce44SJohn Forte 					    "login failed - InitialR2T  is "
1343fcf3ce44SJohn Forte 					    "invalid - protocol error",
1344fcf3ce44SJohn Forte 					    icp->conn_oid);
1345fcf3ce44SJohn Forte 					return (ISCSI_STATUS_PROTOCOL_ERROR);
1346fcf3ce44SJohn Forte 				}
1347fcf3ce44SJohn Forte 				text = value_end;
1348fcf3ce44SJohn Forte 
1349fcf3ce44SJohn Forte 			} else if (iscsi_find_key_value("ImmediateData",
1350fcf3ce44SJohn Forte 			    text, end, &value, &value_end)) {
1351fcf3ce44SJohn Forte 
1352fcf3ce44SJohn Forte 				/*
1353fcf3ce44SJohn Forte 				 * iSCSI RFC section 12.11 states that
1354fcf3ce44SJohn Forte 				 * ImmediateData is Irrelevant for a
1355fcf3ce44SJohn Forte 				 * discovery session.
1356fcf3ce44SJohn Forte 				 */
1357fcf3ce44SJohn Forte 				if (isp->sess_type ==
1358fcf3ce44SJohn Forte 				    ISCSI_SESS_TYPE_DISCOVERY) {
1359fcf3ce44SJohn Forte 					/* EMPTY */
1360fcf3ce44SJohn Forte 				} else if (value == NULL) {
1361fcf3ce44SJohn Forte 					cmn_err(CE_WARN, "iscsi connection(%u) "
1362fcf3ce44SJohn Forte 					    "login failed - ImmediateData is "
1363fcf3ce44SJohn Forte 					    "invalid - protocol error",
1364fcf3ce44SJohn Forte 					    icp->conn_oid);
1365fcf3ce44SJohn Forte 					return (ISCSI_STATUS_PROTOCOL_ERROR);
1366fcf3ce44SJohn Forte 				} else if (strcmp(value, "Yes") == 0) {
1367fcf3ce44SJohn Forte 					icp->conn_params.immediate_data = 1;
1368fcf3ce44SJohn Forte 				} else if (strcmp(value, "No") == 0) {
1369fcf3ce44SJohn Forte 					icp->conn_params.immediate_data = 0;
1370fcf3ce44SJohn Forte 				} else {
1371fcf3ce44SJohn Forte 					cmn_err(CE_WARN, "iscsi connection(%u) "
1372fcf3ce44SJohn Forte 					    "login failed - ImmediateData is "
1373fcf3ce44SJohn Forte 					    "invalid - protocol error",
1374fcf3ce44SJohn Forte 					    icp->conn_oid);
1375fcf3ce44SJohn Forte 					return (ISCSI_STATUS_PROTOCOL_ERROR);
1376fcf3ce44SJohn Forte 				}
1377fcf3ce44SJohn Forte 				text = value_end;
1378fcf3ce44SJohn Forte 
1379fcf3ce44SJohn Forte 			} else if (iscsi_find_key_value(
1380fcf3ce44SJohn Forte 			    "MaxRecvDataSegmentLength", text, end,
1381fcf3ce44SJohn Forte 			    &value, &value_end)) {
1382fcf3ce44SJohn Forte 
1383fcf3ce44SJohn Forte 				if (ddi_strtoul(value, &tmpe, 0, &tmp) != 0) {
1384fcf3ce44SJohn Forte 					cmn_err(CE_WARN, "iscsi connection(%u) "
1385fcf3ce44SJohn Forte 					    "login failed - MaxRecvDataSegment"
1386fcf3ce44SJohn Forte 					    "Length is invalid - protocol "
1387fcf3ce44SJohn Forte 					    "error", icp->conn_oid);
1388fcf3ce44SJohn Forte 					return (ISCSI_STATUS_NEGO_FAIL);
1389fcf3ce44SJohn Forte 				}
1390fcf3ce44SJohn Forte 				icp->conn_params.max_recv_data_seg_len =
1391fcf3ce44SJohn Forte 				    icp->conn_params.max_xmit_data_seg_len =
1392fcf3ce44SJohn Forte 				    (int)tmp;
1393fcf3ce44SJohn Forte 
1394fcf3ce44SJohn Forte 				text = value_end;
1395fcf3ce44SJohn Forte 			} else if (iscsi_find_key_value("FirstBurstLength",
1396fcf3ce44SJohn Forte 			    text, end, &value, &value_end)) {
1397fcf3ce44SJohn Forte 
1398fcf3ce44SJohn Forte 				/*
1399fcf3ce44SJohn Forte 				 * iSCSI RFC section 12.14 states that
1400fcf3ce44SJohn Forte 				 * FirstBurstLength is Irrelevant if
1401fcf3ce44SJohn Forte 				 * InitialR2T=Yes and ImmediateData=No
1402fcf3ce44SJohn Forte 				 * or is this is a discovery session.
1403fcf3ce44SJohn Forte 				 */
1404fcf3ce44SJohn Forte 				if ((isp->sess_type ==
1405fcf3ce44SJohn Forte 				    ISCSI_SESS_TYPE_DISCOVERY)) {
1406fcf3ce44SJohn Forte 					/* EMPTY */
1407fcf3ce44SJohn Forte 				} else if (value &&
1408fcf3ce44SJohn Forte 				    (strcmp(value, "Irrelevant") == 0)) {
1409fcf3ce44SJohn Forte 					/* irrelevant */
1410fcf3ce44SJohn Forte 					fbl_irrelevant = B_TRUE;
1411fcf3ce44SJohn Forte 				} else if (ddi_strtoul(
1412fcf3ce44SJohn Forte 				    value, &tmpe, 0, &tmp) != 0) {
1413fcf3ce44SJohn Forte 					/* bad value */
1414fcf3ce44SJohn Forte 					cmn_err(CE_WARN, "iscsi connection(%u) "
1415fcf3ce44SJohn Forte 					    "login failed - FirstBurstLength"
1416fcf3ce44SJohn Forte 					    "is invalid - protocol error",
1417fcf3ce44SJohn Forte 					    icp->conn_oid);
1418fcf3ce44SJohn Forte 					return (ISCSI_STATUS_PROTOCOL_ERROR);
1419fcf3ce44SJohn Forte 				} else {
1420fcf3ce44SJohn Forte 					/* good value */
1421fcf3ce44SJohn Forte 					icp->conn_params.first_burst_length =
1422fcf3ce44SJohn Forte 					    (int)tmp;
1423fcf3ce44SJohn Forte 				}
1424fcf3ce44SJohn Forte 				text = value_end;
1425fcf3ce44SJohn Forte 			} else if (iscsi_find_key_value("MaxBurstLength",
1426fcf3ce44SJohn Forte 			    text, end, &value, &value_end)) {
1427fcf3ce44SJohn Forte 				/*
1428fcf3ce44SJohn Forte 				 * iSCSI RFC section 12.13 states that
1429fcf3ce44SJohn Forte 				 * MaxBurstLength is Irrelevant for a
1430fcf3ce44SJohn Forte 				 * discovery session.
1431fcf3ce44SJohn Forte 				 */
1432fcf3ce44SJohn Forte 				if (isp->sess_type ==
1433fcf3ce44SJohn Forte 				    ISCSI_SESS_TYPE_DISCOVERY) {
1434fcf3ce44SJohn Forte 					/* EMPTY */
1435fcf3ce44SJohn Forte 				} else if (ddi_strtoul(
1436fcf3ce44SJohn Forte 				    value, &tmpe, 0, &tmp) != 0) {
1437fcf3ce44SJohn Forte 					cmn_err(CE_WARN, "iscsi connection(%u) "
1438fcf3ce44SJohn Forte 					    "login failed - MaxBurstLength"
1439fcf3ce44SJohn Forte 					    "is invalid - protocol error",
1440fcf3ce44SJohn Forte 					    icp->conn_oid);
1441fcf3ce44SJohn Forte 					return (ISCSI_STATUS_PROTOCOL_ERROR);
1442fcf3ce44SJohn Forte 				} else {
1443fcf3ce44SJohn Forte 					icp->conn_params.max_burst_length =
1444fcf3ce44SJohn Forte 					    (int)tmp;
1445fcf3ce44SJohn Forte 				}
1446fcf3ce44SJohn Forte 
1447fcf3ce44SJohn Forte 				text = value_end;
1448fcf3ce44SJohn Forte 
1449fcf3ce44SJohn Forte 			} else if (iscsi_find_key_value("HeaderDigest",
1450fcf3ce44SJohn Forte 			    text, end, &value, &value_end)) {
1451fcf3ce44SJohn Forte 
1452fcf3ce44SJohn Forte 				if (strcmp(value, "None") == 0) {
1453fcf3ce44SJohn Forte 					if (icp->conn_params.header_digest !=
1454fcf3ce44SJohn Forte 					    ISCSI_DIGEST_CRC32C) {
1455fcf3ce44SJohn Forte 						icp->conn_params.header_digest =
1456fcf3ce44SJohn Forte 						    ISCSI_DIGEST_NONE;
1457fcf3ce44SJohn Forte 					} else {
1458fcf3ce44SJohn Forte 						cmn_err(CE_WARN, "iscsi "
1459fcf3ce44SJohn Forte 						    "connection(%u) login "
1460fcf3ce44SJohn Forte 						    "failed - HeaderDigest="
1461fcf3ce44SJohn Forte 						    "CRC32 is required, can't "
1462fcf3ce44SJohn Forte 						    "accept %s",
1463fcf3ce44SJohn Forte 						    icp->conn_oid, text);
1464fcf3ce44SJohn Forte 						return (ISCSI_STATUS_NEGO_FAIL);
1465fcf3ce44SJohn Forte 					}
1466fcf3ce44SJohn Forte 				} else if (strcmp(value, "CRC32C") == 0) {
1467fcf3ce44SJohn Forte 					if (icp->conn_params.header_digest !=
1468fcf3ce44SJohn Forte 					    ISCSI_DIGEST_NONE) {
1469fcf3ce44SJohn Forte 						icp->conn_params.header_digest =
1470fcf3ce44SJohn Forte 						    ISCSI_DIGEST_CRC32C;
1471fcf3ce44SJohn Forte 					} else {
1472fcf3ce44SJohn Forte 						cmn_err(CE_WARN, "iscsi "
1473fcf3ce44SJohn Forte 						    "connection(%u) login "
1474fcf3ce44SJohn Forte 						    "failed - HeaderDigest="
1475fcf3ce44SJohn Forte 						    "None is required, can't "
1476fcf3ce44SJohn Forte 						    "accept %s",
1477fcf3ce44SJohn Forte 						    icp->conn_oid, text);
1478fcf3ce44SJohn Forte 						return (ISCSI_STATUS_NEGO_FAIL);
1479fcf3ce44SJohn Forte 					}
1480fcf3ce44SJohn Forte 				} else {
1481fcf3ce44SJohn Forte 					cmn_err(CE_WARN, "iscsi connection(%u) "
1482fcf3ce44SJohn Forte 					    "login failed - HeaderDigest "
1483fcf3ce44SJohn Forte 					    "can't accept %s", icp->conn_oid,
1484fcf3ce44SJohn Forte 					    text);
1485fcf3ce44SJohn Forte 					return (ISCSI_STATUS_NEGO_FAIL);
1486fcf3ce44SJohn Forte 				}
1487fcf3ce44SJohn Forte 				text = value_end;
1488fcf3ce44SJohn Forte 			} else if (iscsi_find_key_value("DataDigest", text,
1489fcf3ce44SJohn Forte 			    end, &value, &value_end)) {
1490fcf3ce44SJohn Forte 
1491fcf3ce44SJohn Forte 				if (strcmp(value, "None") == 0) {
1492fcf3ce44SJohn Forte 					if (icp->conn_params.data_digest !=
1493fcf3ce44SJohn Forte 					    ISCSI_DIGEST_CRC32C) {
1494fcf3ce44SJohn Forte 						icp->conn_params.data_digest =
1495fcf3ce44SJohn Forte 						    ISCSI_DIGEST_NONE;
1496fcf3ce44SJohn Forte 					} else {
1497fcf3ce44SJohn Forte 						cmn_err(CE_WARN, "iscsi "
1498fcf3ce44SJohn Forte 						    "connection(%u) login "
1499fcf3ce44SJohn Forte 						    "failed - DataDigest="
1500fcf3ce44SJohn Forte 						    "CRC32C is required, "
1501fcf3ce44SJohn Forte 						    "can't accept %s",
1502fcf3ce44SJohn Forte 						    icp->conn_oid, text);
1503fcf3ce44SJohn Forte 						return (ISCSI_STATUS_NEGO_FAIL);
1504fcf3ce44SJohn Forte 					}
1505fcf3ce44SJohn Forte 				} else if (strcmp(value, "CRC32C") == 0) {
1506fcf3ce44SJohn Forte 					if (icp->conn_params.data_digest !=
1507fcf3ce44SJohn Forte 					    ISCSI_DIGEST_NONE) {
1508fcf3ce44SJohn Forte 						icp->conn_params.data_digest =
1509fcf3ce44SJohn Forte 						    ISCSI_DIGEST_CRC32C;
1510fcf3ce44SJohn Forte 					} else {
1511fcf3ce44SJohn Forte 						cmn_err(CE_WARN, "iscsi "
1512fcf3ce44SJohn Forte 						    "connection(%u) login "
1513fcf3ce44SJohn Forte 						    "failed - DataDigest=None "
1514fcf3ce44SJohn Forte 						    "is required, can't "
1515fcf3ce44SJohn Forte 						    "accept %s",
1516fcf3ce44SJohn Forte 						    icp->conn_oid, text);
1517fcf3ce44SJohn Forte 						return (ISCSI_STATUS_NEGO_FAIL);
1518fcf3ce44SJohn Forte 					}
1519fcf3ce44SJohn Forte 				} else {
1520fcf3ce44SJohn Forte 					cmn_err(CE_WARN, "iscsi connection(%u) "
1521fcf3ce44SJohn Forte 					    "login failed - can't accept %s",
1522fcf3ce44SJohn Forte 					    icp->conn_oid, text);
1523fcf3ce44SJohn Forte 					return (ISCSI_STATUS_NEGO_FAIL);
1524fcf3ce44SJohn Forte 				}
1525fcf3ce44SJohn Forte 				text = value_end;
1526fcf3ce44SJohn Forte 
1527fcf3ce44SJohn Forte 			} else if (iscsi_find_key_value("DefaultTime2Wait",
1528fcf3ce44SJohn Forte 			    text, end, &value, &value_end)) {
1529fcf3ce44SJohn Forte 
1530fcf3ce44SJohn Forte 				if (ddi_strtoul(value, &tmpe, 0, &tmp) != 0) {
1531fcf3ce44SJohn Forte 					cmn_err(CE_WARN, "iscsi connection(%u) "
1532fcf3ce44SJohn Forte 					    "login failed - DefaultTime2Wait "
1533fcf3ce44SJohn Forte 					    "is invalid - protocol error",
1534fcf3ce44SJohn Forte 					    icp->conn_oid);
1535fcf3ce44SJohn Forte 					return (ISCSI_STATUS_PROTOCOL_ERROR);
1536fcf3ce44SJohn Forte 				}
1537fcf3ce44SJohn Forte 				icp->conn_params.default_time_to_wait =
1538fcf3ce44SJohn Forte 				    (int)tmp;
1539fcf3ce44SJohn Forte 
1540fcf3ce44SJohn Forte 				text = value_end;
1541fcf3ce44SJohn Forte 
1542fcf3ce44SJohn Forte 			} else if (iscsi_find_key_value("DefaultTime2Retain",
1543fcf3ce44SJohn Forte 			    text, end, &value, &value_end)) {
1544fcf3ce44SJohn Forte 
1545fcf3ce44SJohn Forte 				if (ddi_strtoul(value, &tmpe, 0, &tmp) != 0) {
1546fcf3ce44SJohn Forte 					cmn_err(CE_WARN, "iscsi connection(%u) "
1547fcf3ce44SJohn Forte 					    "login failed - DefaultTime2Retain "
1548fcf3ce44SJohn Forte 					    "is invalid - protocol error",
1549fcf3ce44SJohn Forte 					    icp->conn_oid);
1550fcf3ce44SJohn Forte 					return (ISCSI_STATUS_PROTOCOL_ERROR);
1551fcf3ce44SJohn Forte 				}
1552fcf3ce44SJohn Forte 				icp->conn_params.default_time_to_retain =
1553fcf3ce44SJohn Forte 				    (int)tmp;
1554fcf3ce44SJohn Forte 
1555fcf3ce44SJohn Forte 				text = value_end;
1556fcf3ce44SJohn Forte 
1557fcf3ce44SJohn Forte 			} else if (iscsi_find_key_value("OFMarker", text,
1558fcf3ce44SJohn Forte 			    end, &value, &value_end)) {
1559fcf3ce44SJohn Forte 
1560fcf3ce44SJohn Forte 				/*
1561fcf3ce44SJohn Forte 				 * result function is AND, target must
1562fcf3ce44SJohn Forte 				 * honor our No
1563fcf3ce44SJohn Forte 				 */
1564fcf3ce44SJohn Forte 				text = value_end;
1565fcf3ce44SJohn Forte 
1566fcf3ce44SJohn Forte 			} else if (iscsi_find_key_value("OFMarkInt", text,
1567fcf3ce44SJohn Forte 			    end, &value, &value_end)) {
1568fcf3ce44SJohn Forte 
1569fcf3ce44SJohn Forte 				/*
1570fcf3ce44SJohn Forte 				 * we don't do markers, so we don't care
1571fcf3ce44SJohn Forte 				 */
1572fcf3ce44SJohn Forte 				text = value_end;
1573fcf3ce44SJohn Forte 
1574fcf3ce44SJohn Forte 			} else if (iscsi_find_key_value("IFMarker", text,
1575fcf3ce44SJohn Forte 			    end, &value, &value_end)) {
1576fcf3ce44SJohn Forte 
1577fcf3ce44SJohn Forte 				/*
1578fcf3ce44SJohn Forte 				 * result function is AND, target must
1579fcf3ce44SJohn Forte 				 * honor our No
1580fcf3ce44SJohn Forte 				 */
1581fcf3ce44SJohn Forte 				text = value_end;
1582fcf3ce44SJohn Forte 
1583fcf3ce44SJohn Forte 			} else if (iscsi_find_key_value("IFMarkInt", text,
1584fcf3ce44SJohn Forte 			    end, &value, &value_end)) {
1585fcf3ce44SJohn Forte 
1586fcf3ce44SJohn Forte 				/*
1587fcf3ce44SJohn Forte 				 * we don't do markers, so we don't care
1588fcf3ce44SJohn Forte 				 */
1589fcf3ce44SJohn Forte 				text = value_end;
1590fcf3ce44SJohn Forte 
1591fcf3ce44SJohn Forte 			} else if (iscsi_find_key_value("DataPDUInOrder",
1592fcf3ce44SJohn Forte 			    text, end, &value, &value_end)) {
1593fcf3ce44SJohn Forte 
1594fcf3ce44SJohn Forte 				/*
1595fcf3ce44SJohn Forte 				 * iSCSI RFC section 12.18 states that
1596fcf3ce44SJohn Forte 				 * DataPDUInOrder is Irrelevant for a
1597fcf3ce44SJohn Forte 				 * discovery session.
1598fcf3ce44SJohn Forte 				 */
1599fcf3ce44SJohn Forte 				if (isp->sess_type ==
1600fcf3ce44SJohn Forte 				    ISCSI_SESS_TYPE_DISCOVERY) {
1601fcf3ce44SJohn Forte 					/* EMPTY */
1602fcf3ce44SJohn Forte 				} else if (value == NULL) {
1603fcf3ce44SJohn Forte 					cmn_err(CE_WARN, "iscsi connection(%u) "
1604fcf3ce44SJohn Forte 					    "login failed - InitialR2T is "
1605fcf3ce44SJohn Forte 					    "invalid - protocol error",
1606fcf3ce44SJohn Forte 					    icp->conn_oid);
1607fcf3ce44SJohn Forte 					return (ISCSI_STATUS_PROTOCOL_ERROR);
1608fcf3ce44SJohn Forte 				} else if (strcmp(value, "Yes") == 0) {
1609fcf3ce44SJohn Forte 					icp->conn_params.data_pdu_in_order =
1610fcf3ce44SJohn Forte 					    B_TRUE;
1611fcf3ce44SJohn Forte 				} else if (strcmp(value, "No") == 0) {
1612fcf3ce44SJohn Forte 					icp->conn_params.data_pdu_in_order =
1613fcf3ce44SJohn Forte 					    B_FALSE;
1614fcf3ce44SJohn Forte 				} else {
1615fcf3ce44SJohn Forte 					cmn_err(CE_WARN, "iscsi connection(%u) "
1616fcf3ce44SJohn Forte 					    "login failed - InitialR2T is "
1617fcf3ce44SJohn Forte 					    "invalid - protocol error",
1618fcf3ce44SJohn Forte 					    icp->conn_oid);
1619fcf3ce44SJohn Forte 					return (ISCSI_STATUS_PROTOCOL_ERROR);
1620fcf3ce44SJohn Forte 				}
1621fcf3ce44SJohn Forte 				text = value_end;
1622fcf3ce44SJohn Forte 
1623fcf3ce44SJohn Forte 			} else if (iscsi_find_key_value("DataSequenceInOrder",
1624fcf3ce44SJohn Forte 			    text, end, &value, &value_end)) {
1625fcf3ce44SJohn Forte 
1626fcf3ce44SJohn Forte 				/*
1627fcf3ce44SJohn Forte 				 * iSCSI RFC section 12.19 states that
1628fcf3ce44SJohn Forte 				 * DataSequenceInOrder is Irrelevant for a
1629fcf3ce44SJohn Forte 				 * discovery session.
1630fcf3ce44SJohn Forte 				 */
1631fcf3ce44SJohn Forte 				if (isp->sess_type ==
1632fcf3ce44SJohn Forte 				    ISCSI_SESS_TYPE_DISCOVERY) {
1633fcf3ce44SJohn Forte 					/* EMPTY */
1634fcf3ce44SJohn Forte 				} else if (value == NULL) {
1635fcf3ce44SJohn Forte 					cmn_err(CE_WARN, "iscsi connection(%u) "
1636fcf3ce44SJohn Forte 					    "login failed - InitialR2T is "
1637fcf3ce44SJohn Forte 					    "invalid - protocol error",
1638fcf3ce44SJohn Forte 					    icp->conn_oid);
1639fcf3ce44SJohn Forte 					return (ISCSI_STATUS_PROTOCOL_ERROR);
1640fcf3ce44SJohn Forte 				} else if (strcmp(value, "Yes") == 0) {
1641fcf3ce44SJohn Forte 					icp->conn_params.
1642fcf3ce44SJohn Forte 					    data_sequence_in_order = B_TRUE;
1643fcf3ce44SJohn Forte 				} else if (strcmp(value, "No") == 0) {
1644fcf3ce44SJohn Forte 					icp->conn_params.
1645fcf3ce44SJohn Forte 					    data_sequence_in_order = B_FALSE;
1646fcf3ce44SJohn Forte 				} else {
1647fcf3ce44SJohn Forte 					cmn_err(CE_WARN, "iscsi connection(%u) "
1648fcf3ce44SJohn Forte 					    "login failed - InitialR2T is "
1649fcf3ce44SJohn Forte 					    "invalid - protocol error",
1650fcf3ce44SJohn Forte 					    icp->conn_oid);
1651fcf3ce44SJohn Forte 					return (ISCSI_STATUS_PROTOCOL_ERROR);
1652fcf3ce44SJohn Forte 				}
1653fcf3ce44SJohn Forte 				text = value_end;
1654fcf3ce44SJohn Forte 
1655fcf3ce44SJohn Forte 			} else if (iscsi_find_key_value("MaxOutstandingR2T",
1656fcf3ce44SJohn Forte 			    text, end, &value, &value_end)) {
1657fcf3ce44SJohn Forte 
1658fcf3ce44SJohn Forte 				/*
1659fcf3ce44SJohn Forte 				 * iSCSI RFC section 12.17 states that
1660fcf3ce44SJohn Forte 				 * MaxOutstandingR2T is Irrelevant for a
1661fcf3ce44SJohn Forte 				 * discovery session.
1662fcf3ce44SJohn Forte 				 */
1663fcf3ce44SJohn Forte 				if (isp->sess_type ==
1664fcf3ce44SJohn Forte 				    ISCSI_SESS_TYPE_DISCOVERY) {
1665fcf3ce44SJohn Forte 					/* EMPTY */
1666fcf3ce44SJohn Forte 				} else if (strcmp(value, "1")) {
1667fcf3ce44SJohn Forte 					cmn_err(CE_WARN, "iscsi connection(%u) "
1668fcf3ce44SJohn Forte 					    "login failed - can't accept "
1669fcf3ce44SJohn Forte 					    "MaxOutstandingR2T %s",
1670fcf3ce44SJohn Forte 					    icp->conn_oid, value);
1671fcf3ce44SJohn Forte 					return (ISCSI_STATUS_NEGO_FAIL);
1672fcf3ce44SJohn Forte 				}
1673fcf3ce44SJohn Forte 				text = value_end;
1674fcf3ce44SJohn Forte 
1675fcf3ce44SJohn Forte 			} else if (iscsi_find_key_value("MaxConnections",
1676fcf3ce44SJohn Forte 			    text, end, &value, &value_end)) {
1677fcf3ce44SJohn Forte 
1678fcf3ce44SJohn Forte 				/*
1679fcf3ce44SJohn Forte 				 * iSCSI RFC section 12.2 states that
1680fcf3ce44SJohn Forte 				 * MaxConnections is Irrelevant for a
1681fcf3ce44SJohn Forte 				 * discovery session.
1682fcf3ce44SJohn Forte 				 */
1683fcf3ce44SJohn Forte 				if (isp->sess_type ==
1684fcf3ce44SJohn Forte 				    ISCSI_SESS_TYPE_DISCOVERY) {
1685fcf3ce44SJohn Forte 					/* EMPTY */
1686fcf3ce44SJohn Forte 				} else if (strcmp(value, "1")) {
1687fcf3ce44SJohn Forte 					cmn_err(CE_WARN, "iscsi connection(%u) "
1688fcf3ce44SJohn Forte 					    "login failed - can't accept "
1689fcf3ce44SJohn Forte 					    "MaxConnections %s",
1690fcf3ce44SJohn Forte 					    icp->conn_oid, value);
1691fcf3ce44SJohn Forte 					return (ISCSI_STATUS_NEGO_FAIL);
1692fcf3ce44SJohn Forte 				}
1693fcf3ce44SJohn Forte 				text = value_end;
1694fcf3ce44SJohn Forte 
1695fcf3ce44SJohn Forte 			} else if (iscsi_find_key_value("ErrorRecoveryLevel",
1696fcf3ce44SJohn Forte 			    text, end, &value, &value_end)) {
1697fcf3ce44SJohn Forte 
1698fcf3ce44SJohn Forte 				if (strcmp(value, "0")) {
1699fcf3ce44SJohn Forte 
1700fcf3ce44SJohn Forte 					cmn_err(CE_WARN, "iscsi connection(%u) "
1701fcf3ce44SJohn Forte 					    "login failed - can't accept "
1702fcf3ce44SJohn Forte 					    "ErrorRecoveryLevel %s",
1703fcf3ce44SJohn Forte 					    icp->conn_oid, value);
1704fcf3ce44SJohn Forte 					return (ISCSI_STATUS_NEGO_FAIL);
1705fcf3ce44SJohn Forte 				}
1706fcf3ce44SJohn Forte 				text = value_end;
1707fcf3ce44SJohn Forte 
1708fcf3ce44SJohn Forte 			} else {
1709fcf3ce44SJohn Forte 				cmn_err(CE_WARN, "iscsi connection(%u) "
1710fcf3ce44SJohn Forte 				    "login failed - ignoring login "
1711fcf3ce44SJohn Forte 				    "parameter %s", icp->conn_oid, value);
1712fcf3ce44SJohn Forte 				text = value_end;
1713fcf3ce44SJohn Forte 			}
1714fcf3ce44SJohn Forte 			break;
1715fcf3ce44SJohn Forte 		default:
1716fcf3ce44SJohn Forte 			return (ISCSI_STATUS_INTERNAL_ERROR);
1717fcf3ce44SJohn Forte 		}
1718fcf3ce44SJohn Forte 	}
1719fcf3ce44SJohn Forte 
1720fcf3ce44SJohn Forte 	/*
1721fcf3ce44SJohn Forte 	 * iSCSI RFC section 12.14 states that
1722fcf3ce44SJohn Forte 	 * FirstBurstLength is Irrelevant if
1723fcf3ce44SJohn Forte 	 * InitialR2T=Yes and ImmediateData=No.
1724fcf3ce44SJohn Forte 	 * This is a final check to make sure
1725fcf3ce44SJohn Forte 	 * the array didn't make a protocol
1726fcf3ce44SJohn Forte 	 * violation.
1727fcf3ce44SJohn Forte 	 */
1728fcf3ce44SJohn Forte 	if ((fbl_irrelevant == B_TRUE) &&
1729fcf3ce44SJohn Forte 	    ((icp->conn_params.initial_r2t != B_TRUE) ||
1730fcf3ce44SJohn Forte 	    (icp->conn_params.immediate_data != B_FALSE))) {
1731fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
1732fcf3ce44SJohn Forte 		    "FirstBurstLength=Irrelevant and (InitialR2T!=Yes or "
1733fcf3ce44SJohn Forte 		    "ImmediateData!=No) - protocol error", icp->conn_oid);
1734fcf3ce44SJohn Forte 		return (ISCSI_STATUS_PROTOCOL_ERROR);
1735fcf3ce44SJohn Forte 	}
1736fcf3ce44SJohn Forte 
1737fcf3ce44SJohn Forte 	if (icp->conn_current_stage == ISCSI_SECURITY_NEGOTIATION_STAGE) {
1738fcf3ce44SJohn Forte 		switch (iscsiAuthClientRecvEnd(auth_client, iscsi_null_callback,
1739fcf3ce44SJohn Forte 		    (void *)isp, NULL)) {
1740fcf3ce44SJohn Forte 		case iscsiAuthStatusContinue:
1741fcf3ce44SJohn Forte 			/*
1742fcf3ce44SJohn Forte 			 * continue sending PDUs
1743fcf3ce44SJohn Forte 			 */
1744fcf3ce44SJohn Forte 			break;
1745fcf3ce44SJohn Forte 
1746fcf3ce44SJohn Forte 		case iscsiAuthStatusPass:
1747fcf3ce44SJohn Forte 			break;
1748fcf3ce44SJohn Forte 
1749fcf3ce44SJohn Forte 		case iscsiAuthStatusInProgress:
1750fcf3ce44SJohn Forte 			/*
1751fcf3ce44SJohn Forte 			 * this should only occur if we were authenticating the
1752fcf3ce44SJohn Forte 			 * target, which we don't do yet, so treat this as an
1753fcf3ce44SJohn Forte 			 * error.
1754fcf3ce44SJohn Forte 			 */
1755fcf3ce44SJohn Forte 		case iscsiAuthStatusNoError:
1756fcf3ce44SJohn Forte 			/*
1757fcf3ce44SJohn Forte 			 * treat this as an error, since we should get a
1758fcf3ce44SJohn Forte 			 * different code
1759fcf3ce44SJohn Forte 			 */
1760fcf3ce44SJohn Forte 		case iscsiAuthStatusError:
1761fcf3ce44SJohn Forte 		case iscsiAuthStatusFail:
1762fcf3ce44SJohn Forte 		default:
1763fcf3ce44SJohn Forte 			debug_status = 0;
1764fcf3ce44SJohn Forte 
1765fcf3ce44SJohn Forte 			if (iscsiAuthClientGetDebugStatus(auth_client,
1766fcf3ce44SJohn Forte 			    &debug_status) != iscsiAuthStatusNoError) {
1767fcf3ce44SJohn Forte 
1768fcf3ce44SJohn Forte 				cmn_err(CE_WARN, "iscsi connection(%u) login "
1769fcf3ce44SJohn Forte 				    "failed - authentication failed with "
1770fcf3ce44SJohn Forte 				    "target (%s)", icp->conn_oid,
1771fcf3ce44SJohn Forte 				    iscsiAuthClientDebugStatusToText(
1772fcf3ce44SJohn Forte 				    debug_status));
1773fcf3ce44SJohn Forte 
1774fcf3ce44SJohn Forte 			} else {
1775fcf3ce44SJohn Forte 
1776fcf3ce44SJohn Forte 				cmn_err(CE_WARN, "iscsi connection(%u) login "
1777fcf3ce44SJohn Forte 				    "failed - authentication failed with "
1778fcf3ce44SJohn Forte 				    "target", icp->conn_oid);
1779fcf3ce44SJohn Forte 
1780fcf3ce44SJohn Forte 			}
1781fcf3ce44SJohn Forte 			return (ISCSI_STATUS_AUTHENTICATION_FAILED);
1782fcf3ce44SJohn Forte 		}
1783fcf3ce44SJohn Forte 	}
1784fcf3ce44SJohn Forte 
1785fcf3ce44SJohn Forte 	/*
1786fcf3ce44SJohn Forte 	 * record some of the PDU fields for later use
1787fcf3ce44SJohn Forte 	 */
1788fcf3ce44SJohn Forte 	isp->sess_tsid = ntohs(ilrhp->tsid);
1789fcf3ce44SJohn Forte 	isp->sess_expcmdsn = ntohl(ilrhp->expcmdsn);
1790fcf3ce44SJohn Forte 	isp->sess_maxcmdsn = ntohl(ilrhp->maxcmdsn);
1791fcf3ce44SJohn Forte 	if (ilrhp->status_class == ISCSI_STATUS_CLASS_SUCCESS) {
1792fcf3ce44SJohn Forte 		icp->conn_expstatsn = ntohl(ilrhp->statsn) + 1;
1793fcf3ce44SJohn Forte 	}
1794fcf3ce44SJohn Forte 
1795fcf3ce44SJohn Forte 	if (transit) {
1796fcf3ce44SJohn Forte 		/*
1797fcf3ce44SJohn Forte 		 * advance to the next stage
1798fcf3ce44SJohn Forte 		 */
1799fcf3ce44SJohn Forte 		icp->conn_partial_response = 0;
1800fcf3ce44SJohn Forte 		icp->conn_current_stage =
1801fcf3ce44SJohn Forte 		    ilrhp->flags & ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK;
1802fcf3ce44SJohn Forte 	} else {
1803fcf3ce44SJohn Forte 		/*
1804fcf3ce44SJohn Forte 		 * we got a partial response, don't advance, more
1805fcf3ce44SJohn Forte 		 * negotiation to do
1806fcf3ce44SJohn Forte 		 */
1807fcf3ce44SJohn Forte 		icp->conn_partial_response = 1;
1808fcf3ce44SJohn Forte 	}
1809fcf3ce44SJohn Forte 
1810fcf3ce44SJohn Forte 	/*
1811fcf3ce44SJohn Forte 	 * this PDU is ok, though the login process
1812fcf3ce44SJohn Forte 	 * may not be done yet
1813fcf3ce44SJohn Forte 	 */
1814fcf3ce44SJohn Forte 	return (ISCSI_STATUS_SUCCESS);
1815fcf3ce44SJohn Forte }
1816fcf3ce44SJohn Forte 
1817fcf3ce44SJohn Forte /*
1818fcf3ce44SJohn Forte  * iscsi_add_text - caller is assumed to be well-behaved and passing NUL
1819fcf3ce44SJohn Forte  * terminated strings
1820fcf3ce44SJohn Forte  */
1821fcf3ce44SJohn Forte int
182230e7468fSPeter Dunlap iscsi_add_text(idm_pdu_t *text_pdu, int max_data_length,
1823fcf3ce44SJohn Forte     char *param, char *value)
1824fcf3ce44SJohn Forte {
1825fcf3ce44SJohn Forte 	int	param_len	= 0;
1826fcf3ce44SJohn Forte 	int	value_len	= 0;
1827fcf3ce44SJohn Forte 	int	length		= 0;
1828fcf3ce44SJohn Forte 	int	pdu_length	= 0;
1829fcf3ce44SJohn Forte 	char	*text		= NULL;
1830fcf3ce44SJohn Forte 	char	*end		= NULL;
1831fcf3ce44SJohn Forte 
183230e7468fSPeter Dunlap 	ASSERT(text_pdu != NULL);
1833fcf3ce44SJohn Forte 	ASSERT(param != NULL);
1834fcf3ce44SJohn Forte 	ASSERT(value != NULL);
1835fcf3ce44SJohn Forte 
1836fcf3ce44SJohn Forte 	param_len = strlen(param);
1837fcf3ce44SJohn Forte 	value_len = strlen(value);
1838fcf3ce44SJohn Forte 	/* param, separator, value, and trailing NULL */
1839fcf3ce44SJohn Forte 	length		= param_len + 1 + value_len + 1;
184030e7468fSPeter Dunlap 	pdu_length	= text_pdu->isp_datalen;
184130e7468fSPeter Dunlap 	text		= (char *)text_pdu->isp_data + pdu_length;
184230e7468fSPeter Dunlap 	end		= (char *)text_pdu->isp_data + max_data_length;
1843fcf3ce44SJohn Forte 	pdu_length	+= length;
1844fcf3ce44SJohn Forte 
1845fcf3ce44SJohn Forte 	if (text + length >= end) {
1846fcf3ce44SJohn Forte 		return (0);
1847fcf3ce44SJohn Forte 	}
1848fcf3ce44SJohn Forte 
1849fcf3ce44SJohn Forte 	/* param */
1850fcf3ce44SJohn Forte 	(void) strncpy(text, param, param_len);
1851fcf3ce44SJohn Forte 	text += param_len;
1852fcf3ce44SJohn Forte 
1853fcf3ce44SJohn Forte 	/* separator */
1854fcf3ce44SJohn Forte 	*text++ = ISCSI_TEXT_SEPARATOR;
1855fcf3ce44SJohn Forte 
1856fcf3ce44SJohn Forte 	/* value */
1857fcf3ce44SJohn Forte 	(void) strncpy(text, value, value_len);
1858fcf3ce44SJohn Forte 	text += value_len;
1859fcf3ce44SJohn Forte 
1860fcf3ce44SJohn Forte 	/* NULL */
1861fcf3ce44SJohn Forte 	*text++ = '\0';
1862fcf3ce44SJohn Forte 
1863fcf3ce44SJohn Forte 	/* update the length in the PDU header */
186430e7468fSPeter Dunlap 	text_pdu->isp_datalen = pdu_length;
186530e7468fSPeter Dunlap 	hton24(text_pdu->isp_hdr->dlength, pdu_length);
1866fcf3ce44SJohn Forte 
1867fcf3ce44SJohn Forte 	return (1);
1868fcf3ce44SJohn Forte }
1869fcf3ce44SJohn Forte 
1870fcf3ce44SJohn Forte /*
1871fcf3ce44SJohn Forte  * iscsi_get_next_text - get the next line of text from the given data
1872fcf3ce44SJohn Forte  * buffer.  This function searches from the address given for the
1873fcf3ce44SJohn Forte  * curr_text parameter.  If curr_text_parameter is NULL return first
1874fcf3ce44SJohn Forte  * line in buffer.  The return value is the address of the next line
1875fcf3ce44SJohn Forte  * based upon where curr_text is located.
1876fcf3ce44SJohn Forte  *
1877fcf3ce44SJohn Forte  */
1878fcf3ce44SJohn Forte char *
1879fcf3ce44SJohn Forte iscsi_get_next_text(char *data, int max_data_length, char *curr_text)
1880fcf3ce44SJohn Forte {
1881fcf3ce44SJohn Forte 	char *curr_data;
1882fcf3ce44SJohn Forte 
1883fcf3ce44SJohn Forte 	ASSERT(data != NULL);
1884fcf3ce44SJohn Forte 
1885fcf3ce44SJohn Forte 	/* check if any data exists, if not return */
1886fcf3ce44SJohn Forte 	if (max_data_length == 0) {
1887fcf3ce44SJohn Forte 		return (NULL);
1888fcf3ce44SJohn Forte 	}
1889fcf3ce44SJohn Forte 
1890fcf3ce44SJohn Forte 	/* handle first call to this function */
1891fcf3ce44SJohn Forte 	if (curr_text == NULL) {
1892fcf3ce44SJohn Forte 		return (data);
1893fcf3ce44SJohn Forte 	}
1894fcf3ce44SJohn Forte 
1895fcf3ce44SJohn Forte 	/* move to next text string */
1896fcf3ce44SJohn Forte 	curr_data = curr_text;
1897fcf3ce44SJohn Forte 	while ((curr_data < (data + max_data_length)) && *curr_data) {
1898fcf3ce44SJohn Forte 		curr_data++;
1899fcf3ce44SJohn Forte 	}
1900fcf3ce44SJohn Forte 	curr_data++;		/* go past the NULL to the next entry */
1901fcf3ce44SJohn Forte 
1902fcf3ce44SJohn Forte 	/* check whether data end reached */
1903fcf3ce44SJohn Forte 	if (curr_data >= (data + max_data_length)) {
1904fcf3ce44SJohn Forte 		return (NULL);
1905fcf3ce44SJohn Forte 	}
1906fcf3ce44SJohn Forte 
1907fcf3ce44SJohn Forte 	return (curr_data);
1908fcf3ce44SJohn Forte }
1909fcf3ce44SJohn Forte 
1910fcf3ce44SJohn Forte 
1911fcf3ce44SJohn Forte /*
1912fcf3ce44SJohn Forte  * iscsi_find_key_value -
1913fcf3ce44SJohn Forte  *
1914fcf3ce44SJohn Forte  */
1915fcf3ce44SJohn Forte static int
1916fcf3ce44SJohn Forte iscsi_find_key_value(char *param, char *ihp, char *pdu_end,
1917fcf3ce44SJohn Forte     char **value_start, char **value_end)
1918fcf3ce44SJohn Forte {
1919fcf3ce44SJohn Forte 	char *str = param;
1920fcf3ce44SJohn Forte 	char *text = ihp;
1921fcf3ce44SJohn Forte 	char *value = NULL;
1922fcf3ce44SJohn Forte 
1923fcf3ce44SJohn Forte 	if (value_start)
1924fcf3ce44SJohn Forte 		*value_start = NULL;
1925fcf3ce44SJohn Forte 	if (value_end)
1926fcf3ce44SJohn Forte 		*value_end = NULL;
1927fcf3ce44SJohn Forte 
1928fcf3ce44SJohn Forte 	/*
1929fcf3ce44SJohn Forte 	 * make sure they contain the same bytes
1930fcf3ce44SJohn Forte 	 */
1931fcf3ce44SJohn Forte 	while (*str) {
1932fcf3ce44SJohn Forte 		if (text >= pdu_end) {
1933fcf3ce44SJohn Forte 			return (0);
1934fcf3ce44SJohn Forte 		}
1935fcf3ce44SJohn Forte 		if (*text == '\0') {
1936fcf3ce44SJohn Forte 			return (0);
1937fcf3ce44SJohn Forte 		}
1938fcf3ce44SJohn Forte 		if (*str != *text) {
1939fcf3ce44SJohn Forte 			return (0);
1940fcf3ce44SJohn Forte 		}
1941fcf3ce44SJohn Forte 		str++;
1942fcf3ce44SJohn Forte 		text++;
1943fcf3ce44SJohn Forte 	}
1944fcf3ce44SJohn Forte 
1945fcf3ce44SJohn Forte 	if ((text >= pdu_end) ||
1946fcf3ce44SJohn Forte 	    (*text == '\0') ||
1947fcf3ce44SJohn Forte 	    (*text != ISCSI_TEXT_SEPARATOR)) {
1948fcf3ce44SJohn Forte 		return (0);
1949fcf3ce44SJohn Forte 	}
1950fcf3ce44SJohn Forte 
1951fcf3ce44SJohn Forte 	/*
1952fcf3ce44SJohn Forte 	 * find the value
1953fcf3ce44SJohn Forte 	 */
1954fcf3ce44SJohn Forte 	value = text + 1;
1955fcf3ce44SJohn Forte 
1956fcf3ce44SJohn Forte 	/*
1957fcf3ce44SJohn Forte 	 * find the end of the value
1958fcf3ce44SJohn Forte 	 */
1959fcf3ce44SJohn Forte 	while ((text < pdu_end) && (*text))
1960fcf3ce44SJohn Forte 		text++;
1961fcf3ce44SJohn Forte 
1962fcf3ce44SJohn Forte 	if (value_start)
1963fcf3ce44SJohn Forte 		*value_start = value;
1964fcf3ce44SJohn Forte 	if (value_end)
1965fcf3ce44SJohn Forte 		*value_end = text;
1966fcf3ce44SJohn Forte 
1967fcf3ce44SJohn Forte 	return (1);
1968fcf3ce44SJohn Forte }
1969fcf3ce44SJohn Forte 
1970fcf3ce44SJohn Forte 
1971fcf3ce44SJohn Forte /*
1972fcf3ce44SJohn Forte  * iscsi_update_address - This function is used on a login redirection.
1973fcf3ce44SJohn Forte  * During the login redirection we are asked to switch to an IP address
1974fcf3ce44SJohn Forte  * port different than the one we were logging into.
1975fcf3ce44SJohn Forte  */
1976fcf3ce44SJohn Forte static iscsi_status_t
1977fcf3ce44SJohn Forte iscsi_update_address(iscsi_conn_t *icp, char *in)
1978fcf3ce44SJohn Forte {
1979fcf3ce44SJohn Forte 	char		*addr_str, *port_str, *tpgt_str;
1980fcf3ce44SJohn Forte 	int		type;
1981fcf3ce44SJohn Forte 	struct hostent	*hptr;
1982fcf3ce44SJohn Forte 	unsigned long	tmp;
1983fcf3ce44SJohn Forte 	int		error_num;
1984fcf3ce44SJohn Forte 	int		port;
1985fcf3ce44SJohn Forte 
1986fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
1987fcf3ce44SJohn Forte 	ASSERT(in != NULL);
1988fcf3ce44SJohn Forte 
1989fcf3ce44SJohn Forte 	/* parse login redirection response */
1990fcf3ce44SJohn Forte 	if (parse_addr_port_tpgt(in, &addr_str, &type,
1991fcf3ce44SJohn Forte 	    &port_str, &tpgt_str) == B_FALSE) {
1992fcf3ce44SJohn Forte 		return (ISCSI_STATUS_PROTOCOL_ERROR);
1993fcf3ce44SJohn Forte 	}
1994fcf3ce44SJohn Forte 
1995fcf3ce44SJohn Forte 	/* convert addr_str */
1996fcf3ce44SJohn Forte 	hptr = kgetipnodebyname(addr_str, type, AI_ALL, &error_num);
1997fcf3ce44SJohn Forte 	if (!hptr) {
1998fcf3ce44SJohn Forte 		return (ISCSI_STATUS_PROTOCOL_ERROR);
1999fcf3ce44SJohn Forte 	}
2000fcf3ce44SJohn Forte 
2001fcf3ce44SJohn Forte 	/* convert port_str */
2002fcf3ce44SJohn Forte 	if (port_str != NULL) {
2003fcf3ce44SJohn Forte 		(void) ddi_strtoul(port_str, NULL, 0, &tmp);
2004fcf3ce44SJohn Forte 		port = (int)tmp;
2005fcf3ce44SJohn Forte 	} else {
2006fcf3ce44SJohn Forte 		port = ISCSI_LISTEN_PORT;
2007fcf3ce44SJohn Forte 	}
2008fcf3ce44SJohn Forte 
2009fcf3ce44SJohn Forte 	iscsid_addr_to_sockaddr(hptr->h_length, *hptr->h_addr_list,
2010fcf3ce44SJohn Forte 	    port, &icp->conn_curr_addr.sin);
2011fcf3ce44SJohn Forte 
2012fcf3ce44SJohn Forte 	kfreehostent(hptr);
2013fcf3ce44SJohn Forte 	return (ISCSI_STATUS_SUCCESS);
2014fcf3ce44SJohn Forte }
2015fcf3ce44SJohn Forte 
201630e7468fSPeter Dunlap void
201730e7468fSPeter Dunlap iscsi_login_update_state(iscsi_conn_t *icp, iscsi_login_state_t next_state)
201830e7468fSPeter Dunlap {
201930e7468fSPeter Dunlap 	mutex_enter(&icp->conn_login_mutex);
202030e7468fSPeter Dunlap 	(void) iscsi_login_update_state_locked(icp, next_state);
202130e7468fSPeter Dunlap 	mutex_exit(&icp->conn_login_mutex);
202230e7468fSPeter Dunlap }
202330e7468fSPeter Dunlap 
202430e7468fSPeter Dunlap void
202530e7468fSPeter Dunlap iscsi_login_update_state_locked(iscsi_conn_t *icp,
202630e7468fSPeter Dunlap     iscsi_login_state_t next_state)
202730e7468fSPeter Dunlap {
202830e7468fSPeter Dunlap 	ASSERT(mutex_owned(&icp->conn_login_mutex));
202930e7468fSPeter Dunlap 	next_state = (next_state > LOGIN_MAX) ? LOGIN_MAX : next_state;
203030e7468fSPeter Dunlap 	idm_sm_audit_state_change(&icp->conn_state_audit,
203130e7468fSPeter Dunlap 	    SAS_ISCSI_LOGIN, icp->conn_login_state, next_state);
203230e7468fSPeter Dunlap 
203330e7468fSPeter Dunlap 	ISCSI_LOGIN_LOG(CE_NOTE, "iscsi_login_update_state conn %p %d -> %d",
203430e7468fSPeter Dunlap 	    (void *)icp, icp->conn_login_state, next_state);
203530e7468fSPeter Dunlap 
203630e7468fSPeter Dunlap 	icp->conn_login_state = next_state;
203730e7468fSPeter Dunlap 	cv_broadcast(&icp->conn_login_cv);
203830e7468fSPeter Dunlap }
203930e7468fSPeter Dunlap 
204030e7468fSPeter Dunlap 
2041fcf3ce44SJohn Forte 
2042fcf3ce44SJohn Forte /*
2043fcf3ce44SJohn Forte  * iscsi_null_callback - This callback may be used under certain
2044fcf3ce44SJohn Forte  * conditions when authenticating a target, but I'm not sure what
2045fcf3ce44SJohn Forte  * we need to do here.
2046fcf3ce44SJohn Forte  */
2047fcf3ce44SJohn Forte /* ARGSUSED */
2048fcf3ce44SJohn Forte static void
2049fcf3ce44SJohn Forte iscsi_null_callback(void *user_handle, void *message_handle, int auth_status)
2050fcf3ce44SJohn Forte {
2051fcf3ce44SJohn Forte }
2052fcf3ce44SJohn Forte 
2053fcf3ce44SJohn Forte 
2054fcf3ce44SJohn Forte /*
2055fcf3ce44SJohn Forte  * iscsi_login_failure_str -
2056fcf3ce44SJohn Forte  *
2057fcf3ce44SJohn Forte  */
2058fcf3ce44SJohn Forte static char *
2059fcf3ce44SJohn Forte iscsi_login_failure_str(uchar_t status_class, uchar_t status_detail)
2060fcf3ce44SJohn Forte {
2061fcf3ce44SJohn Forte 	switch (status_class) {
2062fcf3ce44SJohn Forte 	case 0x00:
2063fcf3ce44SJohn Forte 		switch (status_detail) {
2064fcf3ce44SJohn Forte 		case 0x00:
2065fcf3ce44SJohn Forte 			return ("Login is proceeding okay.");
2066fcf3ce44SJohn Forte 		default:
2067fcf3ce44SJohn Forte 			break;
2068fcf3ce44SJohn Forte 		}
2069fcf3ce44SJohn Forte 	case 0x01:
2070fcf3ce44SJohn Forte 		switch (status_detail) {
2071fcf3ce44SJohn Forte 		case 0x01:
2072fcf3ce44SJohn Forte 			return ("Requested ITN has moved temporarily to "
2073fcf3ce44SJohn Forte 			    "the address provided.");
2074fcf3ce44SJohn Forte 		case 0x02:
2075fcf3ce44SJohn Forte 			return ("Requested ITN has moved permanently to "
2076fcf3ce44SJohn Forte 			    "the address provided.");
2077fcf3ce44SJohn Forte 		default:
2078fcf3ce44SJohn Forte 			break;
2079fcf3ce44SJohn Forte 		}
2080fcf3ce44SJohn Forte 	case 0x02:
2081fcf3ce44SJohn Forte 		switch (status_detail) {
2082fcf3ce44SJohn Forte 		case 0x00:
2083fcf3ce44SJohn Forte 			return ("Miscellaneous iSCSI initiator errors.");
2084fcf3ce44SJohn Forte 		case 0x01:
2085fcf3ce44SJohn Forte 			return ("Initiator could not be successfully "
2086fcf3ce44SJohn Forte 			    "authenticated.");
2087fcf3ce44SJohn Forte 		case 0x02:
2088fcf3ce44SJohn Forte 			return ("Initiator is not allowed access to the "
2089fcf3ce44SJohn Forte 			    "given target.");
2090fcf3ce44SJohn Forte 		case 0x03:
2091fcf3ce44SJohn Forte 			return ("Requested ITN does not exist at this "
2092fcf3ce44SJohn Forte 			    "address.");
2093fcf3ce44SJohn Forte 		case 0x04:
2094fcf3ce44SJohn Forte 			return ("Requested ITN has been removed and no "
2095fcf3ce44SJohn Forte 			    "forwarding address is provided.");
2096fcf3ce44SJohn Forte 		case 0x05:
2097fcf3ce44SJohn Forte 			return ("Requested iSCSI version range is not "
2098fcf3ce44SJohn Forte 			    "supported by the target.");
2099fcf3ce44SJohn Forte 		case 0x06:
2100fcf3ce44SJohn Forte 			return ("No more connections can be accepted on "
2101fcf3ce44SJohn Forte 			    "this Session ID (SSID).");
2102fcf3ce44SJohn Forte 		case 0x07:
2103fcf3ce44SJohn Forte 			return ("Missing parameters (e.g., iSCSI initiator "
2104fcf3ce44SJohn Forte 			    "and/or target name).");
2105fcf3ce44SJohn Forte 		case 0x08:
2106fcf3ce44SJohn Forte 			return ("Target does not support session spanning "
2107fcf3ce44SJohn Forte 			    "to this connection (address).");
2108fcf3ce44SJohn Forte 		case 0x09:
2109fcf3ce44SJohn Forte 			return ("Target does not support this type of "
2110fcf3ce44SJohn Forte 			    "session or not from this initiator.");
2111fcf3ce44SJohn Forte 		case 0x0A:
2112fcf3ce44SJohn Forte 			return ("Attempt to add a connection to a "
2113fcf3ce44SJohn Forte 			    "nonexistent session.");
2114fcf3ce44SJohn Forte 		case 0x0B:
2115fcf3ce44SJohn Forte 			return ("Invalid request type during login.");
2116fcf3ce44SJohn Forte 		default:
2117fcf3ce44SJohn Forte 			break;
2118fcf3ce44SJohn Forte 		}
2119fcf3ce44SJohn Forte 	case 0x03:
2120fcf3ce44SJohn Forte 		switch (status_detail) {
2121fcf3ce44SJohn Forte 		case 0x00:
2122fcf3ce44SJohn Forte 			return ("Target hardware or software error.");
2123fcf3ce44SJohn Forte 		case 0x01:
2124fcf3ce44SJohn Forte 			return ("iSCSI service or target is not currently "
2125fcf3ce44SJohn Forte 			    "operational.");
2126fcf3ce44SJohn Forte 		case 0x02:
2127fcf3ce44SJohn Forte 			return ("Target has insufficient session, connection "
2128fcf3ce44SJohn Forte 			    "or other resources.");
2129fcf3ce44SJohn Forte 		default:
2130fcf3ce44SJohn Forte 			break;
2131fcf3ce44SJohn Forte 		}
2132fcf3ce44SJohn Forte 	}
2133fcf3ce44SJohn Forte 	return ("Unknown login response received.");
2134fcf3ce44SJohn Forte }
2135fcf3ce44SJohn Forte 
2136fcf3ce44SJohn Forte 
2137fcf3ce44SJohn Forte /*
2138fcf3ce44SJohn Forte  * iscsi_login_connect -
2139fcf3ce44SJohn Forte  */
2140fcf3ce44SJohn Forte static iscsi_status_t
2141fcf3ce44SJohn Forte iscsi_login_connect(iscsi_conn_t *icp)
2142fcf3ce44SJohn Forte {
2143fcf3ce44SJohn Forte 	iscsi_hba_t		*ihp;
2144fcf3ce44SJohn Forte 	iscsi_sess_t		*isp;
2145fcf3ce44SJohn Forte 	struct sockaddr		*addr;
214630e7468fSPeter Dunlap 	idm_conn_req_t		cr;
214730e7468fSPeter Dunlap 	idm_status_t		rval;
2148d3d50737SRafael Vanoni 	clock_t			lbolt;
2149fcf3ce44SJohn Forte 
2150fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
2151fcf3ce44SJohn Forte 	isp = icp->conn_sess;
2152fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
2153fcf3ce44SJohn Forte 	ihp = isp->sess_hba;
2154fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
2155fcf3ce44SJohn Forte 	addr = &icp->conn_curr_addr.sin;
2156fcf3ce44SJohn Forte 
2157fcf3ce44SJohn Forte 	/* Make sure that scope_id is zero if it is an IPv6 address */
2158fcf3ce44SJohn Forte 	if (addr->sa_family == AF_INET6) {
2159fcf3ce44SJohn Forte 		((struct sockaddr_in6 *)addr)->sin6_scope_id = 0;
2160fcf3ce44SJohn Forte 	}
2161fcf3ce44SJohn Forte 
216230e7468fSPeter Dunlap 	/* delay the connect process if required */
216330e7468fSPeter Dunlap 	lbolt = ddi_get_lbolt();
216430e7468fSPeter Dunlap 	if (lbolt < icp->conn_login_min) {
2165aff4bce5Syi zhang - Sun Microsystems - Beijing China 		if (icp->conn_login_max < icp->conn_login_min) {
2166aff4bce5Syi zhang - Sun Microsystems - Beijing China 			delay(icp->conn_login_max - lbolt);
2167aff4bce5Syi zhang - Sun Microsystems - Beijing China 		} else {
216830e7468fSPeter Dunlap 			delay(icp->conn_login_min - lbolt);
216930e7468fSPeter Dunlap 		}
2170aff4bce5Syi zhang - Sun Microsystems - Beijing China 	}
2171fcf3ce44SJohn Forte 
217230e7468fSPeter Dunlap 	/* Create IDM connection context */
217330e7468fSPeter Dunlap 	cr.cr_domain = addr->sa_family;
217430e7468fSPeter Dunlap 	cr.cr_type = SOCK_STREAM;
217530e7468fSPeter Dunlap 	cr.cr_protocol = 0;
217630e7468fSPeter Dunlap 	cr.cr_bound = icp->conn_bound;
217730e7468fSPeter Dunlap 	cr.cr_li = icp->conn_sess->sess_hba->hba_li;
217830e7468fSPeter Dunlap 	cr.icr_conn_ops.icb_rx_misc = &iscsi_rx_misc_pdu;
217930e7468fSPeter Dunlap 	cr.icr_conn_ops.icb_rx_error = &iscsi_rx_error_pdu;
218030e7468fSPeter Dunlap 	cr.icr_conn_ops.icb_rx_scsi_rsp = &iscsi_rx_scsi_rsp;
218130e7468fSPeter Dunlap 	cr.icr_conn_ops.icb_client_notify = &iscsi_client_notify;
218230e7468fSPeter Dunlap 	cr.icr_conn_ops.icb_build_hdr = &iscsi_build_hdr;
218330e7468fSPeter Dunlap 	cr.icr_conn_ops.icb_task_aborted = &iscsi_task_aborted;
218430e7468fSPeter Dunlap 	bcopy(addr, &cr.cr_ini_dst_addr,
218530e7468fSPeter Dunlap 	    sizeof (cr.cr_ini_dst_addr));
218630e7468fSPeter Dunlap 	bcopy(&icp->conn_bound_addr, &cr.cr_bound_addr,
218730e7468fSPeter Dunlap 	    sizeof (cr.cr_bound_addr));
2188dedec472SJack Meng 	if (isp->sess_boot == B_TRUE) {
2189dedec472SJack Meng 		cr.cr_boot_conn = B_TRUE;
2190dedec472SJack Meng 	} else {
2191dedec472SJack Meng 		cr.cr_boot_conn = B_FALSE;
2192dedec472SJack Meng 	}
219330e7468fSPeter Dunlap 
219430e7468fSPeter Dunlap 	/*
219530e7468fSPeter Dunlap 	 * Allocate IDM connection context
219630e7468fSPeter Dunlap 	 */
219730e7468fSPeter Dunlap 	rval = idm_ini_conn_create(&cr, &icp->conn_ic);
219830e7468fSPeter Dunlap 	if (rval != IDM_STATUS_SUCCESS) {
219930e7468fSPeter Dunlap 		return (ISCSI_STATUS_LOGIN_FAILED);
220030e7468fSPeter Dunlap 	}
220130e7468fSPeter Dunlap 
220230e7468fSPeter Dunlap 	icp->conn_ic->ic_handle = icp;
220330e7468fSPeter Dunlap 
220430e7468fSPeter Dunlap 	/*
220530e7468fSPeter Dunlap 	 * About to initiate connect, reset login state.
220630e7468fSPeter Dunlap 	 */
220730e7468fSPeter Dunlap 	iscsi_login_update_state(icp, LOGIN_START);
220830e7468fSPeter Dunlap 
220930e7468fSPeter Dunlap 	/*
221030e7468fSPeter Dunlap 	 * Make sure the connection doesn't go away until we are done with it.
221130e7468fSPeter Dunlap 	 * This hold will prevent us from receiving a CN_CONNECT_DESTROY
221230e7468fSPeter Dunlap 	 * notification on this connection until we are ready.
221330e7468fSPeter Dunlap 	 */
221430e7468fSPeter Dunlap 	idm_conn_hold(icp->conn_ic);
221530e7468fSPeter Dunlap 
221630e7468fSPeter Dunlap 	/*
2217aff4bce5Syi zhang - Sun Microsystems - Beijing China 	 * When iSCSI initiator to target IO timeout or connection failure
2218aff4bce5Syi zhang - Sun Microsystems - Beijing China 	 * Connection retry is needed for normal operational session.
2219aff4bce5Syi zhang - Sun Microsystems - Beijing China 	 */
2220aff4bce5Syi zhang - Sun Microsystems - Beijing China 	if ((icp->conn_sess->sess_type == ISCSI_SESS_TYPE_NORMAL) &&
2221aff4bce5Syi zhang - Sun Microsystems - Beijing China 	    ((icp->conn_state == ISCSI_CONN_STATE_FAILED) ||
2222aff4bce5Syi zhang - Sun Microsystems - Beijing China 	    (icp->conn_state == ISCSI_CONN_STATE_POLLING))) {
2223aff4bce5Syi zhang - Sun Microsystems - Beijing China 		icp->conn_ic->ic_conn_params.nonblock_socket = B_TRUE;
2224aff4bce5Syi zhang - Sun Microsystems - Beijing China 		icp->conn_ic->ic_conn_params.conn_login_max =
2225aff4bce5Syi zhang - Sun Microsystems - Beijing China 		    icp->conn_login_max;
2226aff4bce5Syi zhang - Sun Microsystems - Beijing China 		if (icp->conn_state == ISCSI_CONN_STATE_POLLING) {
2227aff4bce5Syi zhang - Sun Microsystems - Beijing China 			icp->conn_ic->ic_conn_params.conn_login_interval =
2228aff4bce5Syi zhang - Sun Microsystems - Beijing China 			    icp->conn_tunable_params.polling_login_delay;
2229aff4bce5Syi zhang - Sun Microsystems - Beijing China 		} else {
2230aff4bce5Syi zhang - Sun Microsystems - Beijing China 			icp->conn_ic->ic_conn_params.conn_login_interval =
2231aff4bce5Syi zhang - Sun Microsystems - Beijing China 			    ISCSI_LOGIN_RETRY_DELAY;
2232aff4bce5Syi zhang - Sun Microsystems - Beijing China 		}
2233aff4bce5Syi zhang - Sun Microsystems - Beijing China 
2234aff4bce5Syi zhang - Sun Microsystems - Beijing China 	} else {
2235aff4bce5Syi zhang - Sun Microsystems - Beijing China 		icp->conn_ic->ic_conn_params.nonblock_socket = B_FALSE;
2236aff4bce5Syi zhang - Sun Microsystems - Beijing China 		icp->conn_ic->ic_conn_params.conn_login_max = 0;
2237aff4bce5Syi zhang - Sun Microsystems - Beijing China 		icp->conn_ic->ic_conn_params.conn_login_interval = 0;
2238aff4bce5Syi zhang - Sun Microsystems - Beijing China 	}
2239aff4bce5Syi zhang - Sun Microsystems - Beijing China 	/*
224030e7468fSPeter Dunlap 	 * Attempt connection.  Upon return we will either be ready to
224130e7468fSPeter Dunlap 	 * login or disconnected.  If idm_ini_conn_connect fails we
224230e7468fSPeter Dunlap 	 * will eventually receive a CN_CONNECT_DESTROY at which point
224330e7468fSPeter Dunlap 	 * we will destroy the connection allocated above (so there
224430e7468fSPeter Dunlap 	 * is no need to explicitly free it here).
224530e7468fSPeter Dunlap 	 */
224630e7468fSPeter Dunlap 	rval = idm_ini_conn_connect(icp->conn_ic);
224730e7468fSPeter Dunlap 
224830e7468fSPeter Dunlap 	if (rval != IDM_STATUS_SUCCESS) {
2249fcf3ce44SJohn Forte 		cmn_err(CE_NOTE, "iscsi connection(%u) unable to "
2250fcf3ce44SJohn Forte 		    "connect to target %s", icp->conn_oid,
2251fcf3ce44SJohn Forte 		    icp->conn_sess->sess_name);
225230e7468fSPeter Dunlap 		idm_conn_rele(icp->conn_ic);
2253fcf3ce44SJohn Forte 	}
2254fcf3ce44SJohn Forte 
225530e7468fSPeter Dunlap 	return (rval == IDM_STATUS_SUCCESS ?
225630e7468fSPeter Dunlap 	    ISCSI_STATUS_SUCCESS : ISCSI_STATUS_INTERNAL_ERROR);
2257fcf3ce44SJohn Forte }
2258fcf3ce44SJohn Forte 
225930e7468fSPeter Dunlap /*
226030e7468fSPeter Dunlap  * iscsi_login_disconnect
226130e7468fSPeter Dunlap  */
226230e7468fSPeter Dunlap static void
226330e7468fSPeter Dunlap iscsi_login_disconnect(iscsi_conn_t *icp)
226430e7468fSPeter Dunlap {
226530e7468fSPeter Dunlap 	/* Tell IDM to disconnect is if we are not already disconnect */
226630e7468fSPeter Dunlap 	idm_ini_conn_disconnect_sync(icp->conn_ic);
226730e7468fSPeter Dunlap 
226830e7468fSPeter Dunlap 	/*
226930e7468fSPeter Dunlap 	 * The function above may return before the CN_CONNECT_LOST
227030e7468fSPeter Dunlap 	 * notification.  Wait for it.
227130e7468fSPeter Dunlap 	 */
227230e7468fSPeter Dunlap 	mutex_enter(&icp->conn_state_mutex);
227330e7468fSPeter Dunlap 	while (icp->conn_state_idm_connected)
227430e7468fSPeter Dunlap 		cv_wait(&icp->conn_state_change,
227530e7468fSPeter Dunlap 		    &icp->conn_state_mutex);
227630e7468fSPeter Dunlap 	mutex_exit(&icp->conn_state_mutex);
227730e7468fSPeter Dunlap }
227830e7468fSPeter Dunlap 
227930e7468fSPeter Dunlap /*
228030e7468fSPeter Dunlap  * iscsi_notice_key_values - Create an nvlist containing the values
228130e7468fSPeter Dunlap  * that have been negotiated for this connection and pass them down to
228230e7468fSPeter Dunlap  * IDM so it can pick up any values that are important.
228330e7468fSPeter Dunlap  */
228430e7468fSPeter Dunlap static void
228530e7468fSPeter Dunlap iscsi_notice_key_values(iscsi_conn_t *icp)
228630e7468fSPeter Dunlap {
228730e7468fSPeter Dunlap 	nvlist_t	*neg_nvl;
228830e7468fSPeter Dunlap 	int		rc;
228930e7468fSPeter Dunlap 
229030e7468fSPeter Dunlap 	rc = nvlist_alloc(&neg_nvl, NV_UNIQUE_NAME, KM_SLEEP);
229130e7468fSPeter Dunlap 	ASSERT(rc == 0);
229230e7468fSPeter Dunlap 
229330e7468fSPeter Dunlap 	/* Only crc32c is supported so the digest logic is simple */
229430e7468fSPeter Dunlap 	if (icp->conn_params.header_digest) {
229530e7468fSPeter Dunlap 		rc = nvlist_add_string(neg_nvl, "HeaderDigest", "crc32c");
229630e7468fSPeter Dunlap 	} else {
229730e7468fSPeter Dunlap 		rc = nvlist_add_string(neg_nvl, "HeaderDigest", "none");
229830e7468fSPeter Dunlap 	}
229930e7468fSPeter Dunlap 	ASSERT(rc == 0);
230030e7468fSPeter Dunlap 
230130e7468fSPeter Dunlap 	if (icp->conn_params.data_digest) {
230230e7468fSPeter Dunlap 		rc = nvlist_add_string(neg_nvl, "DataDigest", "crc32c");
230330e7468fSPeter Dunlap 	} else {
230430e7468fSPeter Dunlap 		rc = nvlist_add_string(neg_nvl, "DataDigest", "none");
230530e7468fSPeter Dunlap 	}
230630e7468fSPeter Dunlap 	ASSERT(rc == 0);
230730e7468fSPeter Dunlap 
230830e7468fSPeter Dunlap 	rc = nvlist_add_uint64(neg_nvl, "MaxRecvDataSegmentLength",
230930e7468fSPeter Dunlap 	    (uint64_t)icp->conn_params.max_recv_data_seg_len);
231030e7468fSPeter Dunlap 	ASSERT(rc == 0);
231130e7468fSPeter Dunlap 
231230e7468fSPeter Dunlap 	rc = nvlist_add_uint64(neg_nvl, "MaxBurstLength",
231330e7468fSPeter Dunlap 	    (uint64_t)icp->conn_params.max_burst_length);
231430e7468fSPeter Dunlap 	ASSERT(rc == 0);
231530e7468fSPeter Dunlap 
231630e7468fSPeter Dunlap 	rc = nvlist_add_uint64(neg_nvl, "MaxOutstandingR2T",
231730e7468fSPeter Dunlap 	    (uint64_t)icp->conn_params.max_outstanding_r2t);
231830e7468fSPeter Dunlap 	ASSERT(rc == 0);
231930e7468fSPeter Dunlap 
232030e7468fSPeter Dunlap 	rc = nvlist_add_uint64(neg_nvl, "ErrorRecoveryLevel",
232130e7468fSPeter Dunlap 	    (uint64_t)icp->conn_params.error_recovery_level);
232230e7468fSPeter Dunlap 	ASSERT(rc == 0);
232330e7468fSPeter Dunlap 
232430e7468fSPeter Dunlap 	rc = nvlist_add_uint64(neg_nvl, "DefaultTime2Wait",
232530e7468fSPeter Dunlap 	    (uint64_t)icp->conn_params.default_time_to_wait);
232630e7468fSPeter Dunlap 	ASSERT(rc == 0);
232730e7468fSPeter Dunlap 
232830e7468fSPeter Dunlap 	rc = nvlist_add_uint64(neg_nvl, "DefaultTime2Retain",
232930e7468fSPeter Dunlap 	    (uint64_t)icp->conn_params.default_time_to_retain);
233030e7468fSPeter Dunlap 	ASSERT(rc == 0);
233130e7468fSPeter Dunlap 
233230e7468fSPeter Dunlap 	/* Pass the list to IDM to examine, then free it */
233330e7468fSPeter Dunlap 	idm_notice_key_values(icp->conn_ic, neg_nvl);
233430e7468fSPeter Dunlap 	nvlist_free(neg_nvl);
2335fcf3ce44SJohn Forte }
2336