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 
73*9fe633fdSToomas Soome void
iscsi_login_cb(void * arg)74*9fe633fdSToomas Soome iscsi_login_cb(void *arg)
75*9fe633fdSToomas Soome {
76*9fe633fdSToomas Soome 	(void) iscsi_login_start(arg);
77*9fe633fdSToomas Soome }
78*9fe633fdSToomas Soome 
79fcf3ce44SJohn Forte /*
80fcf3ce44SJohn Forte  * iscsi_login_start - connect and perform iscsi protocol login
81fcf3ce44SJohn Forte  */
82fcf3ce44SJohn Forte iscsi_status_t
iscsi_login_start(void * arg)83fcf3ce44SJohn Forte iscsi_login_start(void *arg)
84fcf3ce44SJohn Forte {
85fcf3ce44SJohn Forte 	iscsi_task_t		*itp = (iscsi_task_t *)arg;
86fcf3ce44SJohn Forte 	iscsi_status_t		rval	= ISCSI_STATUS_LOGIN_FAILED;
87fcf3ce44SJohn Forte 	iscsi_conn_t		*icp;
88fcf3ce44SJohn Forte 	iscsi_sess_t		*isp;
89fcf3ce44SJohn Forte 	iscsi_hba_t		*ihp;
90fcf3ce44SJohn Forte 	unsigned char		status_class;
91fcf3ce44SJohn Forte 	unsigned char		status_detail;
92fcf3ce44SJohn Forte 
93fcf3ce44SJohn Forte 	ASSERT(itp != NULL);
94fcf3ce44SJohn Forte 	icp = (iscsi_conn_t *)itp->t_arg;
95fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
96fcf3ce44SJohn Forte 	isp = icp->conn_sess;
97fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
98fcf3ce44SJohn Forte 	ihp = isp->sess_hba;
99fcf3ce44SJohn Forte 	ASSERT(ihp != NULL);
100fcf3ce44SJohn Forte 
101fcf3ce44SJohn Forte login_start:
10230e7468fSPeter Dunlap 	ASSERT((icp->conn_state == ISCSI_CONN_STATE_IN_LOGIN) ||
10330e7468fSPeter Dunlap 	    (icp->conn_state == ISCSI_CONN_STATE_FAILED) ||
10430e7468fSPeter Dunlap 	    (icp->conn_state == ISCSI_CONN_STATE_POLLING));
10530e7468fSPeter Dunlap 
10630e7468fSPeter Dunlap 	icp->conn_state_ffp = B_FALSE;
107cc7ef495Syi zhang - Sun Microsystems - Beijing China 	icp->conn_login_status = ISCSI_INITIAL_LOGIN_STAGE;
10830e7468fSPeter Dunlap 
109fcf3ce44SJohn Forte 	/* reset connection statsn */
110fcf3ce44SJohn Forte 	icp->conn_expstatsn = 0;
111fcf3ce44SJohn Forte 	icp->conn_laststatsn = 0;
112fcf3ce44SJohn Forte 
113fcf3ce44SJohn Forte 	/* sync up authentication information */
114fcf3ce44SJohn Forte 	(void) iscsi_sess_set_auth(isp);
115fcf3ce44SJohn Forte 
116fcf3ce44SJohn Forte 	/* sync up login and session parameters */
117fcf3ce44SJohn Forte 	if (!ISCSI_SUCCESS(iscsi_conn_sync_params(icp))) {
118fcf3ce44SJohn Forte 		/* unable to sync params.  fail connection attempts */
11930e7468fSPeter Dunlap 		iscsi_login_end(icp, ISCSI_STATUS_LOGIN_FAILED, itp);
120fcf3ce44SJohn Forte 		return (ISCSI_STATUS_LOGIN_FAILED);
121fcf3ce44SJohn Forte 	}
122fcf3ce44SJohn Forte 
12330e7468fSPeter Dunlap 	/*
12430e7468fSPeter Dunlap 	 * Attempt to open TCP connection, associated IDM connection will
12530e7468fSPeter Dunlap 	 * have a hold on it that must be released after the call to
12630e7468fSPeter Dunlap 	 * iscsi_login() below.
12730e7468fSPeter Dunlap 	 */
128fcf3ce44SJohn Forte 	if (!ISCSI_SUCCESS(iscsi_login_connect(icp))) {
129bbe72583SJack Meng 		if ((isp->sess_boot == B_TRUE) &&
130bbe72583SJack Meng 		    (ihp->hba_service_status_overwrite == B_TRUE) &&
131bbe72583SJack Meng 		    (isp->sess_boot_nic_reset == B_FALSE)) {
132bbe72583SJack Meng 			/*
133bbe72583SJack Meng 			 * The connection to boot target failed
134bbe72583SJack Meng 			 * before the system fully started.
135bbe72583SJack Meng 			 * Reset the boot nic to the settings from
136bbe72583SJack Meng 			 * firmware before retrying the connect to
137bbe72583SJack Meng 			 * save the the system.
138bbe72583SJack Meng 			 */
139bbe72583SJack Meng 			if (iscsi_net_interface(B_TRUE) ==
140bbe72583SJack Meng 			    ISCSI_STATUS_SUCCESS) {
141bbe72583SJack Meng 				isp->sess_boot_nic_reset = B_TRUE;
142bbe72583SJack Meng 			}
143bbe72583SJack Meng 		}
144fcf3ce44SJohn Forte 		/* retry this failure */
145fcf3ce44SJohn Forte 		goto login_retry;
146fcf3ce44SJohn Forte 	}
147fcf3ce44SJohn Forte 
148fcf3ce44SJohn Forte 	/*
149fcf3ce44SJohn Forte 	 * allocate response buffer with based on default max
150fcf3ce44SJohn Forte 	 * transfer size.  This size might shift during login.
151fcf3ce44SJohn Forte 	 */
15230e7468fSPeter Dunlap 	icp->conn_login_max_data_length =
15330e7468fSPeter Dunlap 	    icp->conn_params.max_xmit_data_seg_len;
15430e7468fSPeter Dunlap 	icp->conn_login_data = kmem_zalloc(icp->conn_login_max_data_length,
15530e7468fSPeter Dunlap 	    KM_SLEEP);
156fcf3ce44SJohn Forte 
15730e7468fSPeter Dunlap 	/*
15830e7468fSPeter Dunlap 	 * Start protocol login, upon return we will be either logged in
15930e7468fSPeter Dunlap 	 * or disconnected
16030e7468fSPeter Dunlap 	 */
16130e7468fSPeter Dunlap 	rval = iscsi_login(icp, &status_class, &status_detail);
162fcf3ce44SJohn Forte 
163fcf3ce44SJohn Forte 	/* done with buffer */
16430e7468fSPeter Dunlap 	kmem_free(icp->conn_login_data, icp->conn_login_max_data_length);
16530e7468fSPeter Dunlap 
16630e7468fSPeter Dunlap 	/* Release connection hold */
16730e7468fSPeter Dunlap 	idm_conn_rele(icp->conn_ic);
168fcf3ce44SJohn Forte 
169fcf3ce44SJohn Forte 	/* hard failure in login */
170fcf3ce44SJohn Forte 	if (!ISCSI_SUCCESS(rval)) {
171fcf3ce44SJohn Forte 		/*
172fcf3ce44SJohn Forte 		 * We should just give up retry if these failures are
173fcf3ce44SJohn Forte 		 * detected.
174fcf3ce44SJohn Forte 		 */
175fcf3ce44SJohn Forte 		switch (rval) {
176fcf3ce44SJohn Forte 		/*
177fcf3ce44SJohn Forte 		 * We should just give up retry if these
178fcf3ce44SJohn Forte 		 * failures are detected.
179fcf3ce44SJohn Forte 		 */
181fcf3ce44SJohn Forte 		case ISCSI_STATUS_INTERNAL_ERROR:
182fcf3ce44SJohn Forte 		case ISCSI_STATUS_VERSION_MISMATCH:
183fcf3ce44SJohn Forte 		case ISCSI_STATUS_NEGO_FAIL:
184cc7ef495Syi zhang - Sun Microsystems - Beijing China 		case ISCSI_STATUS_LOGIN_TPGT_NEGO_FAIL:
185fcf3ce44SJohn Forte 			/* we don't want to retry this failure */
18630e7468fSPeter Dunlap 			iscsi_login_end(icp, ISCSI_STATUS_LOGIN_FAILED, itp);
187fcf3ce44SJohn Forte 			return (ISCSI_STATUS_LOGIN_FAILED);
188fcf3ce44SJohn Forte 		default:
189fcf3ce44SJohn Forte 			/* retry this failure */
190fcf3ce44SJohn Forte 			goto login_retry;
191fcf3ce44SJohn Forte 		}
192fcf3ce44SJohn Forte 	}
193fcf3ce44SJohn Forte 
194fcf3ce44SJohn Forte 	/* soft failure with reason */
195fcf3ce44SJohn Forte 	switch (status_class) {
196fcf3ce44SJohn Forte 	case ISCSI_STATUS_CLASS_SUCCESS:
197fcf3ce44SJohn Forte 		/* login was successful */
19830e7468fSPeter Dunlap 		iscsi_login_end(icp, ISCSI_STATUS_SUCCESS, itp);
199fcf3ce44SJohn Forte 		return (ISCSI_STATUS_SUCCESS);
200fcf3ce44SJohn Forte 	case ISCSI_STATUS_CLASS_REDIRECT:
201fcf3ce44SJohn Forte 		/* Retry at the redirected address */
202fcf3ce44SJohn Forte 		goto login_start;
203fcf3ce44SJohn Forte 	case ISCSI_STATUS_CLASS_TARGET_ERR:
204fcf3ce44SJohn Forte 		/* retry this failure */
205fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
206fcf3ce44SJohn Forte 		    "%s (0x%02x/0x%02x)", icp->conn_oid,
207fcf3ce44SJohn Forte 		    iscsi_login_failure_str(status_class, status_detail),
208fcf3ce44SJohn Forte 		    status_class, status_detail);
209fcf3ce44SJohn Forte 		goto login_retry;
210fcf3ce44SJohn Forte 	case ISCSI_STATUS_CLASS_INITIATOR_ERR:
211fcf3ce44SJohn Forte 	default:
212fcf3ce44SJohn Forte 		/* All other errors are hard failures */
213fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
2147f848965Sbing zhao - Sun Microsystems - Beijing China 		    "%s (0x%02x/0x%02x) Target: %s, TPGT: %d",
2157f848965Sbing zhao - Sun Microsystems - Beijing China 		    icp->conn_oid,
216fcf3ce44SJohn Forte 		    iscsi_login_failure_str(status_class, status_detail),
2177f848965Sbing zhao - Sun Microsystems - Beijing China 		    status_class, status_detail, isp->sess_name,
2187f848965Sbing zhao - Sun Microsystems - Beijing China 		    isp->sess_tpgt_conf);
219fcf3ce44SJohn Forte 
220fcf3ce44SJohn Forte 		/* we don't want to retry this failure */
22130e7468fSPeter Dunlap 		iscsi_login_end(icp, ISCSI_STATUS_LOGIN_FAILED, itp);
222fcf3ce44SJohn Forte 		break;
223fcf3ce44SJohn Forte 	}
22430e7468fSPeter Dunlap 
225fcf3ce44SJohn Forte 	return (ISCSI_STATUS_LOGIN_FAILED);
226fcf3ce44SJohn Forte 
227fcf3ce44SJohn Forte login_retry:
228fcf3ce44SJohn Forte 	/* retry this failure if we haven't run out of time */
229fcf3ce44SJohn Forte 	if (icp->conn_login_max > ddi_get_lbolt()) {
230fcf3ce44SJohn Forte 
231fcf3ce44SJohn Forte 		if (icp->conn_state == ISCSI_CONN_STATE_POLLING) {
232fcf3ce44SJohn Forte 			icp->conn_login_min = ddi_get_lbolt() +
233aff4bce5Syi zhang - Sun Microsystems - Beijing China 			    SEC_TO_TICK(icp->conn_tunable_params.
234aff4bce5Syi zhang - Sun Microsystems - Beijing China 			    polling_login_delay);
235fcf3ce44SJohn Forte 		} else {
236fcf3ce44SJohn Forte 			icp->conn_login_min = ddi_get_lbolt() +
237fcf3ce44SJohn Forte 			    SEC_TO_TICK(ISCSI_LOGIN_RETRY_DELAY);
238fcf3ce44SJohn Forte 		}
239fcf3ce44SJohn Forte 
240fcf3ce44SJohn Forte 		if (itp->t_blocking == B_TRUE) {
241fcf3ce44SJohn Forte 			goto login_start;
242fcf3ce44SJohn Forte 		} else {
243904e51f6SJack Meng 			if (ddi_taskq_dispatch(isp->sess_login_taskq,
244*9fe633fdSToomas Soome 			    iscsi_login_cb, itp, DDI_SLEEP) !=
245fcf3ce44SJohn Forte 			    DDI_SUCCESS) {
246fcf3ce44SJohn Forte 				iscsi_login_end(icp,
24730e7468fSPeter Dunlap 				    ISCSI_STATUS_LOGIN_TIMED_OUT, itp);
248fcf3ce44SJohn Forte 			}
249fcf3ce44SJohn Forte 			return (ISCSI_STATUS_SUCCESS);
250fcf3ce44SJohn Forte 		}
251fcf3ce44SJohn Forte 	} else {
252fcf3ce44SJohn Forte 		/* Retries exceeded */
25330e7468fSPeter Dunlap 		iscsi_login_end(icp, ISCSI_STATUS_LOGIN_TIMED_OUT, itp);
254fcf3ce44SJohn Forte 	}
25530e7468fSPeter Dunlap 
256fcf3ce44SJohn Forte 	return (ISCSI_STATUS_LOGIN_FAILED);
257fcf3ce44SJohn Forte }
258fcf3ce44SJohn Forte 
259fcf3ce44SJohn Forte static void
iscsi_login_end(iscsi_conn_t * icp,iscsi_status_t status,iscsi_task_t * itp)26030e7468fSPeter Dunlap iscsi_login_end(iscsi_conn_t *icp, iscsi_status_t status, iscsi_task_t *itp)
261fcf3ce44SJohn Forte {
262fcf3ce44SJohn Forte 	iscsi_sess_t	*isp;
263904e51f6SJack Meng 	uint32_t	event_count;
264fcf3ce44SJohn Forte 
265fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
266fcf3ce44SJohn Forte 	isp = icp->conn_sess;
267fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
268fcf3ce44SJohn Forte 
26930e7468fSPeter Dunlap 	if (status == ISCSI_STATUS_SUCCESS) {
27030e7468fSPeter Dunlap 		/* Inform IDM of the relevant negotiated values */
27130e7468fSPeter Dunlap 		iscsi_notice_key_values(icp);
27230e7468fSPeter Dunlap 
27330e7468fSPeter Dunlap 		/* We are now logged in */
27430e7468fSPeter Dunlap 		iscsi_conn_update_state(icp, ISCSI_CONN_STATE_LOGGED_IN);
27530e7468fSPeter Dunlap 
27630e7468fSPeter Dunlap 		/* startup TX thread */
27730e7468fSPeter Dunlap 		(void) iscsi_thread_start(icp->conn_tx_thread);
27830e7468fSPeter Dunlap 
27930e7468fSPeter Dunlap 		/*
28030e7468fSPeter Dunlap 		 * Move login state machine to LOGIN_FFP.  This will
28130e7468fSPeter Dunlap 		 * release the taskq thread handling the CN_FFP_ENABLED
28230e7468fSPeter Dunlap 		 * allowing the IDM connection state machine to resume
28330e7468fSPeter Dunlap 		 * processing events
28430e7468fSPeter Dunlap 		 */
28530e7468fSPeter Dunlap 		iscsi_login_update_state(icp, LOGIN_FFP);
286fcf3ce44SJohn Forte 
28730e7468fSPeter Dunlap 		/* Notify the session that a connection is logged in */
288904e51f6SJack Meng 		event_count = atomic_inc_32_nv(&isp->sess_state_event_count);
289904e51f6SJack Meng 		iscsi_sess_enter_state_zone(isp);
290904e51f6SJack Meng 		iscsi_sess_state_machine(isp, ISCSI_SESS_EVENT_N1, event_count);
291904e51f6SJack Meng 		iscsi_sess_exit_state_zone(isp);
29230e7468fSPeter Dunlap 	} else {
29330e7468fSPeter Dunlap 		/* If login failed reset nego tpgt */
294fcf3ce44SJohn Forte 		isp->sess_tpgt_nego = ISCSI_DEFAULT_TPGT;
29530e7468fSPeter Dunlap 
29630e7468fSPeter Dunlap 		mutex_enter(&icp->conn_state_mutex);
29730e7468fSPeter Dunlap 		switch (icp->conn_state) {
29830e7468fSPeter Dunlap 		case ISCSI_CONN_STATE_IN_LOGIN:
29930e7468fSPeter Dunlap 			iscsi_conn_update_state_locked(icp,
30030e7468fSPeter Dunlap 			    ISCSI_CONN_STATE_FREE);
30130e7468fSPeter Dunlap 			mutex_exit(&icp->conn_state_mutex);
30230e7468fSPeter Dunlap 			break;
30330e7468fSPeter Dunlap 		case ISCSI_CONN_STATE_FAILED:
30430e7468fSPeter Dunlap 			if (status == ISCSI_STATUS_LOGIN_FAILED) {
30530e7468fSPeter Dunlap 				iscsi_conn_update_state_locked(icp,
30630e7468fSPeter Dunlap 				    ISCSI_CONN_STATE_FREE);
30730e7468fSPeter Dunlap 			} else {
30830e7468fSPeter Dunlap 				/* ISCSI_STATUS_LOGIN_TIMED_OUT */
30930e7468fSPeter Dunlap 				iscsi_conn_update_state_locked(icp,
31030e7468fSPeter Dunlap 				    ISCSI_CONN_STATE_POLLING);
31130e7468fSPeter Dunlap 			}
31230e7468fSPeter Dunlap 			mutex_exit(&icp->conn_state_mutex);
313904e51f6SJack Meng 			event_count = atomic_inc_32_nv(
314904e51f6SJack Meng 			    &isp->sess_state_event_count);
315904e51f6SJack Meng 			iscsi_sess_enter_state_zone(isp);
316904e51f6SJack Meng 			iscsi_sess_state_machine(isp, ISCSI_SESS_EVENT_N6,
317904e51f6SJack Meng 			    event_count);
318904e51f6SJack Meng 			iscsi_sess_exit_state_zone(isp);
31930e7468fSPeter Dunlap 
32030e7468fSPeter Dunlap 			if (status == ISCSI_STATUS_LOGIN_TIMED_OUT) {
32130e7468fSPeter Dunlap 				iscsi_conn_retry(isp, icp);
32230e7468fSPeter Dunlap 			}
32330e7468fSPeter Dunlap 			break;
32430e7468fSPeter Dunlap 		case ISCSI_CONN_STATE_POLLING:
32530e7468fSPeter Dunlap 			if (status == ISCSI_STATUS_LOGIN_FAILED) {
32630e7468fSPeter Dunlap 				iscsi_conn_update_state_locked(icp,
32730e7468fSPeter Dunlap 				    ISCSI_CONN_STATE_FREE);
32830e7468fSPeter Dunlap 				mutex_exit(&icp->conn_state_mutex);
329904e51f6SJack Meng 				event_count = atomic_inc_32_nv(
330904e51f6SJack Meng 				    &isp->sess_state_event_count);
331904e51f6SJack Meng 				iscsi_sess_enter_state_zone(isp);
33230e7468fSPeter Dunlap 
33330e7468fSPeter Dunlap 				iscsi_sess_state_machine(isp,
334904e51f6SJack Meng 				    ISCSI_SESS_EVENT_N6, event_count);
335904e51f6SJack Meng 
336904e51f6SJack Meng 				iscsi_sess_exit_state_zone(isp);
33730e7468fSPeter Dunlap 			} else {
33830e7468fSPeter Dunlap 				/* ISCSI_STATUS_LOGIN_TIMED_OUT */
33930e7468fSPeter Dunlap 				if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
34030e7468fSPeter Dunlap 					mutex_exit(&icp->conn_state_mutex);
34130e7468fSPeter Dunlap 
34230e7468fSPeter Dunlap 					iscsi_conn_retry(isp, icp);
34330e7468fSPeter Dunlap 				} else {
34430e7468fSPeter Dunlap 					iscsi_conn_update_state_locked(icp,
34530e7468fSPeter Dunlap 					    ISCSI_CONN_STATE_FREE);
34630e7468fSPeter Dunlap 					mutex_exit(&icp->conn_state_mutex);
34730e7468fSPeter Dunlap 				}
34830e7468fSPeter Dunlap 			}
34930e7468fSPeter Dunlap 			break;
35019944f88Syi zhang - Sun Microsystems - Beijing China 		case ISCSI_CONN_STATE_FREE:
35119944f88Syi zhang - Sun Microsystems - Beijing China 			mutex_exit(&icp->conn_state_mutex);
35219944f88Syi zhang - Sun Microsystems - Beijing China 			break;
35330e7468fSPeter Dunlap 		default:
35419944f88Syi zhang - Sun Microsystems - Beijing China 			mutex_exit(&icp->conn_state_mutex);
35530e7468fSPeter Dunlap 			ASSERT(0);
35630e7468fSPeter Dunlap 			break;
35730e7468fSPeter Dunlap 		}
358fcf3ce44SJohn Forte 	}
359fcf3ce44SJohn Forte 
360fcf3ce44SJohn Forte 	if (itp->t_blocking == B_FALSE) {
361fcf3ce44SJohn Forte 		kmem_free(itp, sizeof (iscsi_task_t));
362fcf3ce44SJohn Forte 	}
363bbe72583SJack Meng 
364bbe72583SJack Meng 	isp->sess_boot_nic_reset = B_FALSE;
365fcf3ce44SJohn Forte }
366fcf3ce44SJohn Forte 
367fcf3ce44SJohn Forte /*
368fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
369fcf3ce44SJohn Forte  * | Begin of protocol login routines					|
370fcf3ce44SJohn Forte  * +--------------------------------------------------------------------+
371fcf3ce44SJohn Forte  */
372fcf3ce44SJohn Forte 
373fcf3ce44SJohn Forte /*
374fcf3ce44SJohn Forte  * iscsi_login - Attempt to login to the target.  The caller
375fcf3ce44SJohn Forte  * must check the status class to determine if the login succeeded.
376fcf3ce44SJohn Forte  * A return of 1 does not mean the login succeeded, it just means
377fcf3ce44SJohn Forte  * this function worked, and the status class is valid info.  This
378fcf3ce44SJohn Forte  * allows the caller to decide whether or not to retry logins, so
379fcf3ce44SJohn Forte  * that we don't have any policy logic here.
380fcf3ce44SJohn Forte  */
38130e7468fSPeter Dunlap iscsi_status_t
iscsi_login(iscsi_conn_t * icp,uint8_t * status_class,uint8_t * status_detail)38230e7468fSPeter Dunlap iscsi_login(iscsi_conn_t *icp, uint8_t *status_class, uint8_t *status_detail)
383fcf3ce44SJohn Forte {
384fcf3ce44SJohn Forte 	iscsi_status_t		rval		= ISCSI_STATUS_INTERNAL_ERROR;
385fcf3ce44SJohn Forte 	struct iscsi_sess	*isp		= NULL;
386fcf3ce44SJohn Forte 	IscsiAuthClient		*auth_client	= NULL;
387fcf3ce44SJohn Forte 	int			max_data_length	= 0;
388fcf3ce44SJohn Forte 	char			*data		= NULL;
38930e7468fSPeter Dunlap 	idm_pdu_t		*text_pdu;
39030e7468fSPeter Dunlap 	char			*buffer;
39130e7468fSPeter Dunlap 	size_t			bufsize;
39230e7468fSPeter Dunlap 	iscsi_login_rsp_hdr_t	*ilrhp;
39330e7468fSPeter Dunlap 	clock_t			response_timeout, timeout_result;
39430e7468fSPeter Dunlap 
39530e7468fSPeter Dunlap 	buffer = icp->conn_login_data;
39630e7468fSPeter Dunlap 	bufsize = icp->conn_login_max_data_length;
397fcf3ce44SJohn Forte 
398fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
399fcf3ce44SJohn Forte 	ASSERT(buffer != NULL);
400fcf3ce44SJohn Forte 	ASSERT(status_class != NULL);
401fcf3ce44SJohn Forte 	ASSERT(status_detail != NULL);
402fcf3ce44SJohn Forte 	isp = icp->conn_sess;
403fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
404fcf3ce44SJohn Forte 
405fcf3ce44SJohn Forte 	/*
40630e7468fSPeter Dunlap 	 * prepare the connection, hold IDM connection until login completes
407fcf3ce44SJohn Forte 	 */
408fcf3ce44SJohn Forte 	icp->conn_current_stage = ISCSI_INITIAL_LOGIN_STAGE;
409fcf3ce44SJohn Forte 	icp->conn_partial_response = 0;
410fcf3ce44SJohn Forte 
411fcf3ce44SJohn Forte 	if (isp->sess_auth.auth_buffers &&
412fcf3ce44SJohn Forte 	    isp->sess_auth.num_auth_buffers) {
413fcf3ce44SJohn Forte 
414fcf3ce44SJohn Forte 		auth_client = (IscsiAuthClient *)isp->
415fcf3ce44SJohn Forte 		    sess_auth.auth_buffers[0].address;
416fcf3ce44SJohn Forte 
417fcf3ce44SJohn Forte 		/*
418fcf3ce44SJohn Forte 		 * prepare for authentication
419fcf3ce44SJohn Forte 		 */
420fcf3ce44SJohn Forte 		if (iscsiAuthClientInit(iscsiAuthNodeTypeInitiator,
421fcf3ce44SJohn Forte 		    isp->sess_auth.num_auth_buffers,
422fcf3ce44SJohn Forte 		    isp->sess_auth.auth_buffers) !=
423fcf3ce44SJohn Forte 		    iscsiAuthStatusNoError) {
424fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
425fcf3ce44SJohn Forte 			    "unable to initialize authentication",
426fcf3ce44SJohn Forte 			    icp->conn_oid);
427cc7ef495Syi zhang - Sun Microsystems - Beijing China 			icp->conn_login_status = ISCSI_STATUS_INTERNAL_ERROR;
42830e7468fSPeter Dunlap 			iscsi_login_disconnect(icp);
42930e7468fSPeter Dunlap 			iscsi_login_update_state(icp, LOGIN_DONE);
430fcf3ce44SJohn Forte 			return (ISCSI_STATUS_INTERNAL_ERROR);
431fcf3ce44SJohn Forte 		}
432fcf3ce44SJohn Forte 
433fcf3ce44SJohn Forte 		if (iscsiAuthClientSetVersion(auth_client,
434fcf3ce44SJohn Forte 		    iscsiAuthVersionRfc) != iscsiAuthStatusNoError) {
435fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
436fcf3ce44SJohn Forte 			    "unable to set authentication", icp->conn_oid);
437fcf3ce44SJohn Forte 			goto iscsi_login_done;
438fcf3ce44SJohn Forte 		}
439fcf3ce44SJohn Forte 
440fcf3ce44SJohn Forte 		if (isp->sess_auth.username &&
441fcf3ce44SJohn Forte 		    (iscsiAuthClientSetUsername(auth_client,
442fcf3ce44SJohn Forte 		    isp->sess_auth.username) !=
443fcf3ce44SJohn Forte 		    iscsiAuthStatusNoError)) {
444fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
445fcf3ce44SJohn Forte 			    "unable to set username", icp->conn_oid);
446fcf3ce44SJohn Forte 			goto iscsi_login_done;
447fcf3ce44SJohn Forte 		}
448fcf3ce44SJohn Forte 
449fcf3ce44SJohn Forte 		if (isp->sess_auth.password &&
450fcf3ce44SJohn Forte 		    (iscsiAuthClientSetPassword(auth_client,
451fcf3ce44SJohn Forte 		    isp->sess_auth.password, isp->sess_auth.password_length) !=
452fcf3ce44SJohn Forte 		    iscsiAuthStatusNoError)) {
453fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
454fcf3ce44SJohn Forte 			    "unable to set password", icp->conn_oid);
455fcf3ce44SJohn Forte 			goto iscsi_login_done;
456fcf3ce44SJohn Forte 		}
457fcf3ce44SJohn Forte 
458fcf3ce44SJohn Forte 		if (iscsiAuthClientSetIpSec(auth_client, 1) !=
459fcf3ce44SJohn Forte 		    iscsiAuthStatusNoError) {
460fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
461fcf3ce44SJohn Forte 			    "unable to set ipsec", icp->conn_oid);
462fcf3ce44SJohn Forte 			goto iscsi_login_done;
463fcf3ce44SJohn Forte 		}
464fcf3ce44SJohn Forte 
465fcf3ce44SJohn Forte 		if (iscsiAuthClientSetAuthRemote(auth_client,
466fcf3ce44SJohn Forte 		    isp->sess_auth.bidirectional_auth) !=
467fcf3ce44SJohn Forte 		    iscsiAuthStatusNoError) {
468fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
469fcf3ce44SJohn Forte 			    "unable to set remote authentication",
470fcf3ce44SJohn Forte 			    icp->conn_oid);
471fcf3ce44SJohn Forte 			goto iscsi_login_done;
472fcf3ce44SJohn Forte 		}
473fcf3ce44SJohn Forte 	}
474fcf3ce44SJohn Forte 
475fcf3ce44SJohn Forte 	/*
476fcf3ce44SJohn Forte 	 * exchange PDUs until the login stage is complete, or an error occurs
477fcf3ce44SJohn Forte 	 */
478fcf3ce44SJohn Forte 	do {
479fcf3ce44SJohn Forte 		/* setup */
480fcf3ce44SJohn Forte 		bzero(buffer, bufsize);
481fcf3ce44SJohn Forte 		data = buffer;
482fcf3ce44SJohn Forte 		max_data_length = bufsize;
483fcf3ce44SJohn Forte 		rval = ISCSI_STATUS_INTERNAL_ERROR;
484fcf3ce44SJohn Forte 
48530e7468fSPeter Dunlap 		text_pdu = idm_pdu_alloc(sizeof (iscsi_hdr_t), 0);
48630e7468fSPeter Dunlap 		idm_pdu_init(text_pdu, icp->conn_ic, NULL, NULL);
48730e7468fSPeter Dunlap 
488fcf3ce44SJohn Forte 		/*
489fcf3ce44SJohn Forte 		 * fill in the PDU header and text data based on the
490fcf3ce44SJohn Forte 		 * login stage that we're in
491fcf3ce44SJohn Forte 		 */
49230e7468fSPeter Dunlap 		rval = iscsi_make_login_pdu(icp, text_pdu, data,
49330e7468fSPeter Dunlap 		    max_data_length);
494fcf3ce44SJohn Forte 		if (!ISCSI_SUCCESS(rval)) {
495fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
496fcf3ce44SJohn Forte 			    "unable to make login pdu", icp->conn_oid);
497fcf3ce44SJohn Forte 			goto iscsi_login_done;
498fcf3ce44SJohn Forte 		}
499fcf3ce44SJohn Forte 
50030e7468fSPeter Dunlap 		mutex_enter(&icp->conn_login_mutex);
50130e7468fSPeter Dunlap 		/*
50230e7468fSPeter Dunlap 		 * Make sure we are still in LOGIN_START or LOGIN_RX
50330e7468fSPeter Dunlap 		 * state before switching to LOGIN_TX.  It's possible
50430e7468fSPeter Dunlap 		 * for a connection failure to move us to LOGIN_ERROR
50530e7468fSPeter Dunlap 		 * before we get to this point.
50630e7468fSPeter Dunlap 		 */
50730e7468fSPeter Dunlap 		if (((icp->conn_login_state != LOGIN_READY) &&
50830e7468fSPeter Dunlap 		    (icp->conn_login_state != LOGIN_RX)) ||
50930e7468fSPeter Dunlap 		    !icp->conn_state_idm_connected) {
51030e7468fSPeter Dunlap 			/* Error occurred */
51130e7468fSPeter Dunlap 			mutex_exit(&icp->conn_login_mutex);
51230e7468fSPeter Dunlap 			rval = (ISCSI_STATUS_INTERNAL_ERROR);
513fcf3ce44SJohn Forte 			goto iscsi_login_done;
514fcf3ce44SJohn Forte 		}
515fcf3ce44SJohn Forte 
5166e7514aeSPeter Gill 		icp->conn_login_resp_hdr.opcode = 0;
51730e7468fSPeter Dunlap 		iscsi_login_update_state_locked(icp, LOGIN_TX);
51830e7468fSPeter Dunlap 		icp->conn_login_data = data;
51930e7468fSPeter Dunlap 		icp->conn_login_max_data_length = max_data_length;
52030e7468fSPeter Dunlap 
52130e7468fSPeter Dunlap 		/*
52230e7468fSPeter Dunlap 		 * send a PDU to the target.  This is asynchronous but
52330e7468fSPeter Dunlap 		 * we don't have any particular need for a TX completion
52430e7468fSPeter Dunlap 		 * notification since we are going to block waiting for the
52530e7468fSPeter Dunlap 		 * receive.
52630e7468fSPeter Dunlap 		 */
52730e7468fSPeter Dunlap 		response_timeout = ddi_get_lbolt() +
528aff4bce5Syi zhang - Sun Microsystems - Beijing China 		    SEC_TO_TICK(icp->conn_tunable_params.
529aff4bce5Syi zhang - Sun Microsystems - Beijing China 		    recv_login_rsp_timeout);
53030e7468fSPeter Dunlap 		idm_pdu_tx(text_pdu);
53130e7468fSPeter Dunlap 
53230e7468fSPeter Dunlap 		/*
53330e7468fSPeter Dunlap 		 * Wait for login failure indication or login RX.
53430e7468fSPeter Dunlap 		 * Handler for login response PDU will copy any data into
53530e7468fSPeter Dunlap 		 * the buffer pointed to by icp->conn_login_data
53630e7468fSPeter Dunlap 		 */
53730e7468fSPeter Dunlap 		while (icp->conn_login_state == LOGIN_TX) {
53830e7468fSPeter Dunlap 			timeout_result = cv_timedwait(&icp->conn_login_cv,
53930e7468fSPeter Dunlap 			    &icp->conn_login_mutex, response_timeout);
54030e7468fSPeter Dunlap 			if (timeout_result == -1)
54130e7468fSPeter Dunlap 				break;
542fcf3ce44SJohn Forte 		}
543fcf3ce44SJohn Forte 
5446e7514aeSPeter Gill 		/*
5456e7514aeSPeter Gill 		 * We have either received a login response or the connection
5466e7514aeSPeter Gill 		 * has gone down or both.  If a login response is present,
5476e7514aeSPeter Gill 		 * then process it.
5486e7514aeSPeter Gill 		 */
5496e7514aeSPeter Gill 		ilrhp = (iscsi_login_rsp_hdr_t *)&icp->conn_login_resp_hdr;
5506e7514aeSPeter Gill 		if (icp->conn_login_state != LOGIN_RX && ilrhp->opcode == 0) {
5516e7514aeSPeter Gill 			/* connection down, with no login response */
55230e7468fSPeter Dunlap 			mutex_exit(&icp->conn_login_mutex);
55330e7468fSPeter Dunlap 			rval = (ISCSI_STATUS_INTERNAL_ERROR);
554fcf3ce44SJohn Forte 			goto iscsi_login_done;
555fcf3ce44SJohn Forte 		}
55630e7468fSPeter Dunlap 		mutex_exit(&icp->conn_login_mutex);
557fcf3ce44SJohn Forte 
558fcf3ce44SJohn Forte 		/* check the PDU response type */
55930e7468fSPeter Dunlap 		if (ilrhp->opcode != ISCSI_OP_LOGIN_RSP) {
560fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
561fcf3ce44SJohn Forte 			    "received invalid login response (0x%02x)",
56230e7468fSPeter Dunlap 			    icp->conn_oid, ilrhp->opcode);
563fcf3ce44SJohn Forte 			rval = (ISCSI_STATUS_PROTOCOL_ERROR);
564fcf3ce44SJohn Forte 			goto iscsi_login_done;
565fcf3ce44SJohn Forte 		}
566fcf3ce44SJohn Forte 
567fcf3ce44SJohn Forte 		/*
568fcf3ce44SJohn Forte 		 * give the caller the status class and detail from the
569fcf3ce44SJohn Forte 		 * last login response PDU received
570fcf3ce44SJohn Forte 		 */
571fcf3ce44SJohn Forte 		if (status_class) {
572fcf3ce44SJohn Forte 			*status_class = ilrhp->status_class;
573fcf3ce44SJohn Forte 		}
574fcf3ce44SJohn Forte 		if (status_detail) {
575fcf3ce44SJohn Forte 			*status_detail = ilrhp->status_detail;
576fcf3ce44SJohn Forte 		}
577fcf3ce44SJohn Forte 
578fcf3ce44SJohn Forte 		switch (ilrhp->status_class) {
579fcf3ce44SJohn Forte 		case ISCSI_STATUS_CLASS_SUCCESS:
580fcf3ce44SJohn Forte 			/*
581fcf3ce44SJohn Forte 			 * process this response and possibly continue
582fcf3ce44SJohn Forte 			 * sending PDUs
583fcf3ce44SJohn Forte 			 */
584fcf3ce44SJohn Forte 			rval = iscsi_process_login_response(icp,
58530e7468fSPeter Dunlap 			    ilrhp, (char *)icp->conn_login_data,
58630e7468fSPeter Dunlap 			    icp->conn_login_max_data_length);
587fcf3ce44SJohn Forte 			/* pass back whatever error we discovered */
588fcf3ce44SJohn Forte 			if (!ISCSI_SUCCESS(rval)) {
58919944f88Syi zhang - Sun Microsystems - Beijing China 				if (ISCSI_LOGIN_TRANSIT_FFP(ilrhp->flags)) {
59019944f88Syi zhang - Sun Microsystems - Beijing China 					/*
59119944f88Syi zhang - Sun Microsystems - Beijing China 					 * iSCSI connection transit to next
59219944f88Syi zhang - Sun Microsystems - Beijing China 					 * FFP stage while iscsi params
59319944f88Syi zhang - Sun Microsystems - Beijing China 					 * ngeotiate error, LOGIN_ERROR
59419944f88Syi zhang - Sun Microsystems - Beijing China 					 * marked so CN_FFP_ENABLED can
59519944f88Syi zhang - Sun Microsystems - Beijing China 					 * be fully handled before
59619944f88Syi zhang - Sun Microsystems - Beijing China 					 * CN_FFP_DISABLED can be processed.
59719944f88Syi zhang - Sun Microsystems - Beijing China 					 */
59819944f88Syi zhang - Sun Microsystems - Beijing China 					iscsi_login_update_state(icp,
59919944f88Syi zhang - Sun Microsystems - Beijing China 					    LOGIN_ERROR);
60019944f88Syi zhang - Sun Microsystems - Beijing China 				}
601fcf3ce44SJohn Forte 				goto iscsi_login_done;
602fcf3ce44SJohn Forte 			}
603fcf3ce44SJohn Forte 
604fcf3ce44SJohn Forte 			break;
605fcf3ce44SJohn Forte 		case ISCSI_STATUS_CLASS_REDIRECT:
606fcf3ce44SJohn Forte 			/*
607fcf3ce44SJohn Forte 			 * we need to process this response to get the
608fcf3ce44SJohn Forte 			 * TargetAddress of the redirect, but we don't
609fcf3ce44SJohn Forte 			 * care about the return code.
610fcf3ce44SJohn Forte 			 */
61130e7468fSPeter Dunlap 			(void) iscsi_process_login_response(icp,
61230e7468fSPeter Dunlap 			    ilrhp, (char *)icp->conn_login_data,
61330e7468fSPeter Dunlap 			    icp->conn_login_max_data_length);
614fcf3ce44SJohn Forte 			rval = ISCSI_STATUS_SUCCESS;
615fcf3ce44SJohn Forte 			goto iscsi_login_done;
616fcf3ce44SJohn Forte 		case ISCSI_STATUS_CLASS_INITIATOR_ERR:
617fcf3ce44SJohn Forte 			if (ilrhp->status_detail ==
618fcf3ce44SJohn Forte 			    ISCSI_LOGIN_STATUS_AUTH_FAILED) {
619fcf3ce44SJohn Forte 				cmn_err(CE_WARN, "iscsi connection(%u) login "
620fcf3ce44SJohn Forte 				    "failed - login failed to authenticate "
621fcf3ce44SJohn Forte 				    "with target", icp->conn_oid);
622fcf3ce44SJohn Forte 			}
623fcf3ce44SJohn Forte 			rval = ISCSI_STATUS_SUCCESS;
624fcf3ce44SJohn Forte 			goto iscsi_login_done;
625fcf3ce44SJohn Forte 		default:
626fcf3ce44SJohn Forte 			/*
627fcf3ce44SJohn Forte 			 * some sort of error, login terminated unsuccessfully,
628fcf3ce44SJohn Forte 			 * though this function did it's job. the caller must
629fcf3ce44SJohn Forte 			 * check the status_class and status_detail and decide
630fcf3ce44SJohn Forte 			 * what to do next.
631fcf3ce44SJohn Forte 			 */
632fcf3ce44SJohn Forte 			rval = ISCSI_STATUS_SUCCESS;
633fcf3ce44SJohn Forte 			goto iscsi_login_done;
634fcf3ce44SJohn Forte 		}
635fcf3ce44SJohn Forte 
636fcf3ce44SJohn Forte 	} while (icp->conn_current_stage != ISCSI_FULL_FEATURE_PHASE);
637fcf3ce44SJohn Forte 
638fcf3ce44SJohn Forte 	rval = ISCSI_STATUS_SUCCESS;
639fcf3ce44SJohn Forte 
640fcf3ce44SJohn Forte iscsi_login_done:
641fcf3ce44SJohn Forte 	if (auth_client) {
642fcf3ce44SJohn Forte 		if (iscsiAuthClientFinish(auth_client) !=
643fcf3ce44SJohn Forte 		    iscsiAuthStatusNoError) {
644fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "iscsi connection(%u) login "
645fcf3ce44SJohn Forte 			    "failed - login failed to authenticate "
646fcf3ce44SJohn Forte 			    "with target", icp->conn_oid);
647fcf3ce44SJohn Forte 			if (ISCSI_SUCCESS(rval))
648fcf3ce44SJohn Forte 				rval = ISCSI_STATUS_INTERNAL_ERROR;
649fcf3ce44SJohn Forte 		}
650fcf3ce44SJohn Forte 	}
65130e7468fSPeter Dunlap 
652cc7ef495Syi zhang - Sun Microsystems - Beijing China 	icp->conn_login_status = rval;
65330e7468fSPeter Dunlap 	if (ISCSI_SUCCESS(rval) &&
65430e7468fSPeter Dunlap 	    (*status_class == ISCSI_STATUS_CLASS_SUCCESS)) {
65530e7468fSPeter Dunlap 		mutex_enter(&icp->conn_state_mutex);
65630e7468fSPeter Dunlap 		while (!icp->conn_state_ffp)
65730e7468fSPeter Dunlap 			cv_wait(&icp->conn_state_change,
65830e7468fSPeter Dunlap 			    &icp->conn_state_mutex);
65930e7468fSPeter Dunlap 		mutex_exit(&icp->conn_state_mutex);
66030e7468fSPeter Dunlap 	} else {
66130e7468fSPeter Dunlap 		iscsi_login_disconnect(icp);
66230e7468fSPeter Dunlap 	}
66330e7468fSPeter Dunlap 
66430e7468fSPeter Dunlap 	iscsi_login_update_state(icp, LOGIN_DONE);
66530e7468fSPeter Dunlap 
666fcf3ce44SJohn Forte 	return (rval);
667fcf3ce44SJohn Forte }
668fcf3ce44SJohn Forte 
669fcf3ce44SJohn Forte 
670fcf3ce44SJohn Forte /*
671fcf3ce44SJohn Forte  * iscsi_make_login_pdu -
672fcf3ce44SJohn Forte  *
673fcf3ce44SJohn Forte  */
674fcf3ce44SJohn Forte static iscsi_status_t
iscsi_make_login_pdu(iscsi_conn_t * icp,idm_pdu_t * text_pdu,char * data,int max_data_length)67530e7468fSPeter Dunlap iscsi_make_login_pdu(iscsi_conn_t *icp, idm_pdu_t *text_pdu,
676fcf3ce44SJohn Forte     char *data, int max_data_length)
677fcf3ce44SJohn Forte {
678fcf3ce44SJohn Forte 	struct iscsi_sess	*isp		= NULL;
679fcf3ce44SJohn Forte 	int			transit		= 0;
68030e7468fSPeter Dunlap 	iscsi_hdr_t		*ihp		= text_pdu->isp_hdr;
68130e7468fSPeter Dunlap 	iscsi_login_hdr_t	*ilhp		=
68230e7468fSPeter Dunlap 	    (iscsi_login_hdr_t *)text_pdu->isp_hdr;
683fcf3ce44SJohn Forte 	IscsiAuthClient		*auth_client	= NULL;
684fcf3ce44SJohn Forte 	int			keytype		= 0;
685fcf3ce44SJohn Forte 	int			rc		= 0;
686fcf3ce44SJohn Forte 	char			value[iscsiAuthStringMaxLength];
687fcf3ce44SJohn Forte 
688fcf3ce44SJohn Forte 	ASSERT(icp != NULL);
68930e7468fSPeter Dunlap 	ASSERT(text_pdu != NULL);
690fcf3ce44SJohn Forte 	isp = icp->conn_sess;
691fcf3ce44SJohn Forte 	ASSERT(isp != NULL);
692fcf3ce44SJohn Forte 
693fcf3ce44SJohn Forte 	auth_client =
694fcf3ce44SJohn Forte 	    (isp->sess_auth.auth_buffers && isp->sess_auth.num_auth_buffers) ?
695fcf3ce44SJohn Forte 	    (IscsiAuthClient *)isp->sess_auth.auth_buffers[0].address : NULL;
696fcf3ce44SJohn Forte 
697fcf3ce44SJohn Forte 	/*
698fcf3ce44SJohn Forte 	 * initialize the PDU header
699fcf3ce44SJohn Forte 	 */
700fcf3ce44SJohn Forte 	bzero(ilhp, sizeof (*ilhp));
701fcf3ce44SJohn Forte 	ilhp->opcode = ISCSI_OP_LOGIN_CMD | ISCSI_OP_IMMEDIATE;
702fcf3ce44SJohn Forte 	ilhp->cid = icp->conn_cid;
703fcf3ce44SJohn Forte 	bcopy(&isp->sess_isid[0], &ilhp->isid[0], sizeof (isp->sess_isid));
704fcf3ce44SJohn Forte 	ilhp->tsid = 0;
705fcf3ce44SJohn Forte 
70630e7468fSPeter Dunlap 	/*
70730e7468fSPeter Dunlap 	 * Set data buffer pointer.  The calls to iscsi_add_text will update the
70830e7468fSPeter Dunlap 	 * data length.
70930e7468fSPeter Dunlap 	 */
71030e7468fSPeter Dunlap 	text_pdu->isp_data = (uint8_t *)data;
71130e7468fSPeter Dunlap 
712fcf3ce44SJohn Forte 	/* don't increment on immediate */
713fcf3ce44SJohn Forte 	ilhp->cmdsn = htonl(isp->sess_cmdsn);
714fcf3ce44SJohn Forte 
715fcf3ce44SJohn Forte 	ilhp->min_version = ISCSI_DRAFT20_VERSION;
716fcf3ce44SJohn Forte 	ilhp->max_version = ISCSI_DRAFT20_VERSION;
717fcf3ce44SJohn Forte 
718fcf3ce44SJohn Forte 	/*
719fcf3ce44SJohn Forte 	 * we have to send 0 until full-feature stage
720fcf3ce44SJohn Forte 	 */
721fcf3ce44SJohn Forte 	ilhp->expstatsn = htonl(icp->conn_expstatsn);
722fcf3ce44SJohn Forte 
723fcf3ce44SJohn Forte 	/*
724fcf3ce44SJohn Forte 	 * the very first Login PDU has some additional requirements,
725fcf3ce44SJohn Forte 	 * * and we need to decide what stage to start in.
726fcf3ce44SJohn Forte 	 */
727fcf3ce44SJohn Forte 	if (icp->conn_current_stage == ISCSI_INITIAL_LOGIN_STAGE) {
728fcf3ce44SJohn Forte 		if ((isp->sess_hba->hba_name) &&
729fcf3ce44SJohn Forte 		    (isp->sess_hba->hba_name[0])) {
73030e7468fSPeter Dunlap 			if (!iscsi_add_text(text_pdu, max_data_length,
731fcf3ce44SJohn Forte 			    "InitiatorName",
732fcf3ce44SJohn Forte 			    (char *)isp->sess_hba->hba_name)) {
733fcf3ce44SJohn Forte 				return (ISCSI_STATUS_INTERNAL_ERROR);
734fcf3ce44SJohn Forte 			}
735fcf3ce44SJohn Forte 		} else {
736fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "iscsi connection(%u) login "
737fcf3ce44SJohn Forte 			    "failed - initiator name is required",
738fcf3ce44SJohn Forte 			    icp->conn_oid);
739fcf3ce44SJohn Forte 			return (ISCSI_STATUS_INTERNAL_ERROR);
740fcf3ce44SJohn Forte 		}
741fcf3ce44SJohn Forte 
742fcf3ce44SJohn Forte 		if ((isp->sess_hba->hba_alias) &&
743fcf3ce44SJohn Forte 		    (isp->sess_hba->hba_alias[0])) {
74430e7468fSPeter Dunlap 			if (!iscsi_add_text(text_pdu, max_data_length,
745fcf3ce44SJohn Forte 			    "InitiatorAlias",
746fcf3ce44SJohn Forte 			    (char *)isp->sess_hba->hba_alias)) {
747fcf3ce44SJohn Forte 				return (ISCSI_STATUS_INTERNAL_ERROR);
748fcf3ce44SJohn Forte 			}
749fcf3ce44SJohn Forte 		}
750fcf3ce44SJohn Forte 
751fcf3ce44SJohn Forte 		if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
752fcf3ce44SJohn Forte 			if (isp->sess_name[0] != '\0') {
75330e7468fSPeter Dunlap 				if (!iscsi_add_text(text_pdu, max_data_length,
754fcf3ce44SJohn Forte 				    "TargetName", (char *)isp->sess_name)) {
755fcf3ce44SJohn Forte 					return (ISCSI_STATUS_INTERNAL_ERROR);
756fcf3ce44SJohn Forte 				}
757fcf3ce44SJohn Forte 			}
758fcf3ce44SJohn Forte 
75930e7468fSPeter Dunlap 			if (!iscsi_add_text(text_pdu, max_data_length,
760fcf3ce44SJohn Forte 			    "SessionType", "Normal")) {
761fcf3ce44SJohn Forte 				return (ISCSI_STATUS_INTERNAL_ERROR);
762fcf3ce44SJohn Forte 			}
763fcf3ce44SJohn Forte 		} else if (isp->sess_type == ISCSI_SESS_TYPE_DISCOVERY) {
76430e7468fSPeter Dunlap 			if (!iscsi_add_text(text_pdu, max_data_length,
765fcf3ce44SJohn Forte 			    "SessionType", "Discovery")) {
766fcf3ce44SJohn Forte 				return (ISCSI_STATUS_INTERNAL_ERROR);
767fcf3ce44SJohn Forte 			}
768fcf3ce44SJohn Forte 		} else {
769fcf3ce44SJohn Forte 			return (ISCSI_STATUS_INTERNAL_ERROR);
770fcf3ce44SJohn Forte 		}
771fcf3ce44SJohn Forte 
772fcf3ce44SJohn Forte 		if (auth_client) {
773fcf3ce44SJohn Forte 			/* we're prepared to do authentication */
774fcf3ce44SJohn Forte 			icp->conn_current_stage =
776fcf3ce44SJohn Forte 		} else {
777fcf3ce44SJohn Forte 			/* can't do any authentication, skip that stage */
778fcf3ce44SJohn Forte 			icp->conn_current_stage =
779fcf3ce44SJohn Forte 			    ISCSI_OP_PARMS_NEGOTIATION_STAGE;
780fcf3ce44SJohn Forte 		}
781fcf3ce44SJohn Forte 	}
782fcf3ce44SJohn Forte 
783fcf3ce44SJohn Forte 	/*
784fcf3ce44SJohn Forte 	 * fill in text based on the stage
785fcf3ce44SJohn Forte 	 */
786fcf3ce44SJohn Forte 	switch (icp->conn_current_stage) {
787fcf3ce44SJohn Forte 	case ISCSI_OP_PARMS_NEGOTIATION_STAGE:
788fcf3ce44SJohn Forte 		/*
789fcf3ce44SJohn Forte 		 * we always try to go from op params to full
790fcf3ce44SJohn Forte 		 * feature stage
791fcf3ce44SJohn Forte 		 */
792fcf3ce44SJohn Forte 		icp->conn_next_stage	= ISCSI_FULL_FEATURE_PHASE;
793fcf3ce44SJohn Forte 		transit			= 1;
794fcf3ce44SJohn Forte 
795fcf3ce44SJohn Forte 		/*
796fcf3ce44SJohn Forte 		 * The terminology here may have gotten dated.  A partial
797fcf3ce44SJohn Forte 		 * response is a login response that doesn't complete a
798fcf3ce44SJohn Forte 		 * login.  If we haven't gotten a partial response, then
799fcf3ce44SJohn Forte 		 * either we shouldn't be here, or we just switched to
800fcf3ce44SJohn Forte 		 * this stage, and need to start offering keys.
801fcf3ce44SJohn Forte 		 */
802fcf3ce44SJohn Forte 		if (!icp->conn_partial_response) {
803fcf3ce44SJohn Forte 			/*
804fcf3ce44SJohn Forte 			 * request the desired settings the first time
805fcf3ce44SJohn Forte 			 * we are in this stage
806fcf3ce44SJohn Forte 			 */
807fcf3ce44SJohn Forte 			switch (icp->conn_params.header_digest) {
808fcf3ce44SJohn Forte 			case ISCSI_DIGEST_NONE:
80930e7468fSPeter Dunlap 				if (!iscsi_add_text(text_pdu,
810fcf3ce44SJohn Forte 				    max_data_length, "HeaderDigest", "None")) {
811fcf3ce44SJohn Forte 					return (ISCSI_STATUS_INTERNAL_ERROR);
812fcf3ce44SJohn Forte 				}
813fcf3ce44SJohn Forte 				break;
814fcf3ce44SJohn Forte 			case ISCSI_DIGEST_CRC32C:
81530e7468fSPeter Dunlap 				if (!iscsi_add_text(text_pdu,
816fcf3ce44SJohn Forte 				    max_data_length,
817fcf3ce44SJohn Forte 				    "HeaderDigest", "CRC32C")) {
818fcf3ce44SJohn Forte 					return (ISCSI_STATUS_INTERNAL_ERROR);
819fcf3ce44SJohn Forte 				}
820fcf3ce44SJohn Forte 				break;
821fcf3ce44SJohn Forte 			case ISCSI_DIGEST_CRC32C_NONE:
82230e7468fSPeter Dunlap 				if (!iscsi_add_text(text_pdu,
823fcf3ce44SJohn Forte 				    max_data_length, "HeaderDigest",
824fcf3ce44SJohn Forte 				    "CRC32C,None")) {
825fcf3ce44SJohn Forte 					return (ISCSI_STATUS_INTERNAL_ERROR);
826fcf3ce44SJohn Forte 				}
827fcf3ce44SJohn Forte 				break;
828fcf3ce44SJohn Forte 			default:
829fcf3ce44SJohn Forte 			case ISCSI_DIGEST_NONE_CRC32C:
83030e7468fSPeter Dunlap 				if (!iscsi_add_text(text_pdu,
831fcf3ce44SJohn Forte 				    max_data_length, "HeaderDigest",
832fcf3ce44SJohn Forte 				    "None,CRC32C")) {
833fcf3ce44SJohn Forte 					return (ISCSI_STATUS_INTERNAL_ERROR);
834fcf3ce44SJohn Forte 				}
835fcf3ce44SJohn Forte 				break;
836fcf3ce44SJohn Forte 			}
837fcf3ce44SJohn Forte 
838fcf3ce44SJohn Forte 			switch (icp->conn_params.data_digest) {
839fcf3ce44SJohn Forte 			case ISCSI_DIGEST_NONE:
84030e7468fSPeter Dunlap 				if (!iscsi_add_text(text_pdu,
841fcf3ce44SJohn Forte 				    max_data_length, "DataDigest", "None")) {
842fcf3ce44SJohn Forte 					return (ISCSI_STATUS_INTERNAL_ERROR);
843fcf3ce44SJohn Forte 				}
844fcf3ce44SJohn Forte 				break;
845fcf3ce44SJohn Forte 			case ISCSI_DIGEST_CRC32C:
84630e7468fSPeter Dunlap 				if (!iscsi_add_text(text_pdu,
847fcf3ce44SJohn Forte 				    max_data_length, "DataDigest", "CRC32C")) {
848fcf3ce44SJohn Forte 					return (ISCSI_STATUS_INTERNAL_ERROR);
849fcf3ce44SJohn Forte 				}
850fcf3ce44SJohn Forte 				break;
851fcf3ce44SJohn Forte 			case ISCSI_DIGEST_CRC32C_NONE:
85230e7468fSPeter Dunlap 				if (!iscsi_add_text(text_pdu,
853fcf3ce44SJohn Forte 				    max_data_length, "DataDigest",
854fcf3ce44SJohn Forte 				    "CRC32C,None")) {
855fcf3ce44SJohn Forte 					return (ISCSI_STATUS_INTERNAL_ERROR);
856fcf3ce44SJohn Forte 				}
857fcf3ce44SJohn Forte 				break;
858fcf3ce44SJohn Forte 			default:
859fcf3ce44SJohn Forte 			case ISCSI_DIGEST_NONE_CRC32C:
86030e7468fSPeter Dunlap 				if (!iscsi_add_text(text_pdu,
861fcf3ce44SJohn Forte 				    max_data_length, "DataDigest",
862fcf3ce44SJohn Forte 				    "None,CRC32C")) {
863fcf3ce44SJohn Forte 					return (ISCSI_STATUS_INTERNAL_ERROR);
864fcf3ce44SJohn Forte 				}
865fcf3ce44SJohn Forte 				break;
866fcf3ce44SJohn Forte 			}
867fcf3ce44SJohn Forte 
868fcf3ce44SJohn Forte 			(void) sprintf(value, "%d",
869fcf3ce44SJohn Forte 			    icp->conn_params.max_recv_data_seg_len);
87030e7468fSPeter Dunlap 			if (!iscsi_add_text(text_pdu, max_data_length,
871fcf3ce44SJohn Forte 			    "MaxRecvDataSegmentLength", value)) {
872fcf3ce44SJohn Forte 				return (ISCSI_STATUS_INTERNAL_ERROR);
873fcf3ce44SJohn Forte 			}
874fcf3ce44SJohn Forte 
875fcf3ce44SJohn Forte 			(void) sprintf(value, "%d",
876fcf3ce44SJohn Forte 			    icp->conn_params.default_time_to_wait);
87730e7468fSPeter Dunlap 			if (!iscsi_add_text(text_pdu,
878fcf3ce44SJohn Forte 			    max_data_length, "DefaultTime2Wait", value)) {
879fcf3ce44SJohn Forte 				return (ISCSI_STATUS_INTERNAL_ERROR);
880fcf3ce44SJohn Forte 			}
881fcf3ce44SJohn Forte 
882fcf3ce44SJohn Forte 			(void) sprintf(value, "%d",
883fcf3ce44SJohn Forte 			    icp->conn_params.default_time_to_retain);
88430e7468fSPeter Dunlap 			if (!iscsi_add_text(text_pdu,
885fcf3ce44SJohn Forte 			    max_data_length, "DefaultTime2Retain", value)) {
886fcf3ce44SJohn Forte 				return (ISCSI_STATUS_INTERNAL_ERROR);
887fcf3ce44SJohn Forte 			}
888fcf3ce44SJohn Forte 
889fcf3ce44SJohn Forte 			(void) sprintf(value, "%d",
890fcf3ce44SJohn Forte 			    icp->conn_params.error_recovery_level);
89130e7468fSPeter Dunlap 			if (!iscsi_add_text(text_pdu,
892fcf3ce44SJohn Forte 			    max_data_length, "ErrorRecoveryLevel", "0")) {
893fcf3ce44SJohn Forte 				return (ISCSI_STATUS_INTERNAL_ERROR);
894fcf3ce44SJohn Forte 			}
895fcf3ce44SJohn Forte 
89630e7468fSPeter Dunlap 			if (!iscsi_add_text(text_pdu,
897fcf3ce44SJohn Forte 			    max_data_length, "IFMarker",
898fcf3ce44SJohn Forte 			    icp->conn_params.ifmarker ? "Yes" : "No")) {
899fcf3ce44SJohn Forte 				return (ISCSI_STATUS_INTERNAL_ERROR);
900fcf3ce44SJohn Forte 			}
901fcf3ce44SJohn Forte 
90230e7468fSPeter Dunlap 			if (!iscsi_add_text(text_pdu,
903fcf3ce44SJohn Forte 			    max_data_length, "OFMarker",
904fcf3ce44SJohn Forte 			    icp->conn_params.ofmarker ? "Yes" : "No")) {
905fcf3ce44SJohn Forte 				return (ISCSI_STATUS_INTERNAL_ERROR);
906fcf3ce44SJohn Forte 			}
907fcf3ce44SJohn Forte 
908fcf3ce44SJohn Forte 			/*
909fcf3ce44SJohn Forte 			 * The following login parameters are "Irrelevant"
910fcf3ce44SJohn Forte 			 * for discovery sessions
911fcf3ce44SJohn Forte 			 */
912fcf3ce44SJohn Forte 			if (isp->sess_type != ISCSI_SESS_TYPE_DISCOVERY) {
913fcf3ce44SJohn Forte 
91430e7468fSPeter Dunlap 				if (!iscsi_add_text(text_pdu,
915fcf3ce44SJohn Forte 				    max_data_length, "InitialR2T",
916fcf3ce44SJohn Forte 				    icp->conn_params.initial_r2t ?
917fcf3ce44SJohn Forte 				    "Yes" : "No")) {
918fcf3ce44SJohn Forte 					return (ISCSI_STATUS_INTERNAL_ERROR);
919fcf3ce44SJohn Forte 				}
920fcf3ce44SJohn Forte 
92130e7468fSPeter Dunlap 				if (!iscsi_add_text(text_pdu,
922fcf3ce44SJohn Forte 				    max_data_length, "ImmediateData",
923fcf3ce44SJohn Forte 				    icp->conn_params.immediate_data ?
924fcf3ce44SJohn Forte 				    "Yes" : "No")) {
925fcf3ce44SJohn Forte 					return (ISCSI_STATUS_INTERNAL_ERROR);
926fcf3ce44SJohn Forte 				}
927fcf3ce44SJohn Forte 
928fcf3ce44SJohn Forte 				(void)