1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2000 by Cisco Systems, Inc.  All rights reserved.
23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  *
26  * iSCSI protocol login and enumeration
27  */
28 
29 #include "iscsi.h"
30 #include <sys/iscsi_protocol.h>
31 #include <sys/scsi/adapters/iscsi_door.h>
32 
33 boolean_t iscsi_login_logging = B_FALSE;
34 
35 /* internal login protocol interfaces */
36 static iscsi_status_t iscsi_login(iscsi_conn_t *icp,
37     uint8_t *status_class, uint8_t *status_detail);
38 static int iscsi_add_text(idm_pdu_t *text_pdu,
39     int max_data_length, char *param, char *value);
40 static int iscsi_find_key_value(char *param, char *ihp, char *pdu_end,
41     char **value_start, char **value_end);
42 static void iscsi_null_callback(void *user_handle, void *message_handle,
43     int auth_status);
44 static iscsi_status_t iscsi_process_login_response(iscsi_conn_t *icp,
45     iscsi_login_rsp_hdr_t *ilrhp, char *data, int max_data_length);
46 static iscsi_status_t iscsi_make_login_pdu(iscsi_conn_t *icp,
47     idm_pdu_t *text_pdu, char *data, int max_data_length);
48 static iscsi_status_t iscsi_update_address(iscsi_conn_t *icp,
49     char *address);
50 static char *iscsi_login_failure_str(uchar_t status_class,
51     uchar_t status_detail);
52 static void iscsi_login_end(iscsi_conn_t *icp,
53     iscsi_status_t status, iscsi_task_t *itp);
54 static iscsi_status_t iscsi_login_connect(iscsi_conn_t *icp);
55 static void iscsi_login_disconnect(iscsi_conn_t *icp);
56 static void iscsi_notice_key_values(iscsi_conn_t *icp);
57 
58 #define	ISCSI_LOGIN_RETRY_DELAY		5	/* seconds */
59 
60 #define	ISCSI_LOGIN_TRANSIT_FFP(flags) \
61 	(!(flags & ISCSI_FLAG_LOGIN_CONTINUE) && \
62 	(flags & ISCSI_FLAG_LOGIN_TRANSIT) && \
63 	(ISCSI_LOGIN_CURRENT_STAGE(flags) == \
64 	ISCSI_OP_PARMS_NEGOTIATION_STAGE) && \
65 	(ISCSI_LOGIN_NEXT_STAGE(flags) == \
66 	ISCSI_FULL_FEATURE_PHASE))
67 
68 /*
69  * +--------------------------------------------------------------------+
70  * | External Login Interface						|
71  * +--------------------------------------------------------------------+
72  */
73 
74 /*
75  * iscsi_login_start - connect and perform iscsi protocol login
76  */
77 iscsi_status_t
78 iscsi_login_start(void *arg)
79 {
80 	iscsi_task_t		*itp = (iscsi_task_t *)arg;
81 	iscsi_status_t		rval	= ISCSI_STATUS_LOGIN_FAILED;
82 	iscsi_conn_t		*icp;
83 	iscsi_sess_t		*isp;
84 	iscsi_hba_t		*ihp;
85 	unsigned char		status_class;
86 	unsigned char		status_detail;
87 
88 	ASSERT(itp != NULL);
89 	icp = (iscsi_conn_t *)itp->t_arg;
90 	ASSERT(icp != NULL);
91 	isp = icp->conn_sess;
92 	ASSERT(isp != NULL);
93 	ihp = isp->sess_hba;
94 	ASSERT(ihp != NULL);
95 
96 login_start:
97 	ASSERT((icp->conn_state == ISCSI_CONN_STATE_IN_LOGIN) ||
98 	    (icp->conn_state == ISCSI_CONN_STATE_FAILED) ||
99 	    (icp->conn_state == ISCSI_CONN_STATE_POLLING));
100 
101 	icp->conn_state_ffp = B_FALSE;
102 
103 	/* reset connection statsn */
104 	icp->conn_expstatsn = 0;
105 	icp->conn_laststatsn = 0;
106 
107 	/* sync up authentication information */
108 	(void) iscsi_sess_set_auth(isp);
109 
110 	/* sync up login and session parameters */
111 	if (!ISCSI_SUCCESS(iscsi_conn_sync_params(icp))) {
112 		/* unable to sync params.  fail connection attempts */
113 		iscsi_login_end(icp, ISCSI_STATUS_LOGIN_FAILED, itp);
114 		return (ISCSI_STATUS_LOGIN_FAILED);
115 	}
116 
117 	/*
118 	 * Attempt to open TCP connection, associated IDM connection will
119 	 * have a hold on it that must be released after the call to
120 	 * iscsi_login() below.
121 	 */
122 	if (!ISCSI_SUCCESS(iscsi_login_connect(icp))) {
123 		if ((isp->sess_boot == B_TRUE) &&
124 		    (ihp->hba_service_status_overwrite == B_TRUE) &&
125 		    (isp->sess_boot_nic_reset == B_FALSE)) {
126 			/*
127 			 * The connection to boot target failed
128 			 * before the system fully started.
129 			 * Reset the boot nic to the settings from
130 			 * firmware before retrying the connect to
131 			 * save the the system.
132 			 */
133 			if (iscsi_net_interface(B_TRUE) ==
134 			    ISCSI_STATUS_SUCCESS) {
135 				isp->sess_boot_nic_reset = B_TRUE;
136 			}
137 		}
138 		/* retry this failure */
139 		goto login_retry;
140 	}
141 
142 	/*
143 	 * allocate response buffer with based on default max
144 	 * transfer size.  This size might shift during login.
145 	 */
146 	icp->conn_login_max_data_length =
147 	    icp->conn_params.max_xmit_data_seg_len;
148 	icp->conn_login_data = kmem_zalloc(icp->conn_login_max_data_length,
149 	    KM_SLEEP);
150 
151 	/*
152 	 * Start protocol login, upon return we will be either logged in
153 	 * or disconnected
154 	 */
155 	rval = iscsi_login(icp, &status_class, &status_detail);
156 
157 	/* done with buffer */
158 	kmem_free(icp->conn_login_data, icp->conn_login_max_data_length);
159 
160 	/* Release connection hold */
161 	idm_conn_rele(icp->conn_ic);
162 
163 	/* hard failure in login */
164 	if (!ISCSI_SUCCESS(rval)) {
165 		/*
166 		 * We should just give up retry if these failures are
167 		 * detected.
168 		 */
169 		switch (rval) {
170 		/*
171 		 * We should just give up retry if these
172 		 * failures are detected.
173 		 */
174 		case ISCSI_STATUS_AUTHENTICATION_FAILED:
175 		case ISCSI_STATUS_INTERNAL_ERROR:
176 		case ISCSI_STATUS_VERSION_MISMATCH:
177 		case ISCSI_STATUS_NEGO_FAIL:
178 			/* we don't want to retry this failure */
179 			iscsi_login_end(icp, ISCSI_STATUS_LOGIN_FAILED, itp);
180 			return (ISCSI_STATUS_LOGIN_FAILED);
181 		default:
182 			/* retry this failure */
183 			goto login_retry;
184 		}
185 	}
186 
187 	/* soft failure with reason */
188 	switch (status_class) {
189 	case ISCSI_STATUS_CLASS_SUCCESS:
190 		/* login was successful */
191 		iscsi_login_end(icp, ISCSI_STATUS_SUCCESS, itp);
192 		return (ISCSI_STATUS_SUCCESS);
193 	case ISCSI_STATUS_CLASS_REDIRECT:
194 		/* Retry at the redirected address */
195 		goto login_start;
196 	case ISCSI_STATUS_CLASS_TARGET_ERR:
197 		/* retry this failure */
198 		cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
199 		    "%s (0x%02x/0x%02x)", icp->conn_oid,
200 		    iscsi_login_failure_str(status_class, status_detail),
201 		    status_class, status_detail);
202 		goto login_retry;
203 	case ISCSI_STATUS_CLASS_INITIATOR_ERR:
204 	default:
205 		/* All other errors are hard failures */
206 		cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
207 		    "%s (0x%02x/0x%02x) Target: %s, TPGT: %d",
208 		    icp->conn_oid,
209 		    iscsi_login_failure_str(status_class, status_detail),
210 		    status_class, status_detail, isp->sess_name,
211 		    isp->sess_tpgt_conf);
212 
213 		/* we don't want to retry this failure */
214 		iscsi_login_end(icp, ISCSI_STATUS_LOGIN_FAILED, itp);
215 		break;
216 	}
217 
218 	return (ISCSI_STATUS_LOGIN_FAILED);
219 
220 login_retry:
221 	/* retry this failure if we haven't run out of time */
222 	if (icp->conn_login_max > ddi_get_lbolt()) {
223 
224 		if (icp->conn_state == ISCSI_CONN_STATE_POLLING) {
225 			icp->conn_login_min = ddi_get_lbolt() +
226 			    SEC_TO_TICK(icp->conn_tunable_params.
227 			    polling_login_delay);
228 		} else {
229 			icp->conn_login_min = ddi_get_lbolt() +
230 			    SEC_TO_TICK(ISCSI_LOGIN_RETRY_DELAY);
231 		}
232 
233 		if (itp->t_blocking == B_TRUE) {
234 			goto login_start;
235 		} else {
236 			if (ddi_taskq_dispatch(isp->sess_taskq,
237 			    (void(*)())iscsi_login_start, itp, DDI_SLEEP) !=
238 			    DDI_SUCCESS) {
239 				iscsi_login_end(icp,
240 				    ISCSI_STATUS_LOGIN_TIMED_OUT, itp);
241 			}
242 			return (ISCSI_STATUS_SUCCESS);
243 		}
244 	} else {
245 		/* Retries exceeded */
246 		iscsi_login_end(icp, ISCSI_STATUS_LOGIN_TIMED_OUT, itp);
247 	}
248 
249 	return (ISCSI_STATUS_LOGIN_FAILED);
250 }
251 
252 static void
253 iscsi_login_end(iscsi_conn_t *icp, iscsi_status_t status, iscsi_task_t *itp)
254 {
255 	iscsi_sess_t	*isp;
256 
257 	ASSERT(icp != NULL);
258 	isp = icp->conn_sess;
259 	ASSERT(isp != NULL);
260 
261 	if (status == ISCSI_STATUS_SUCCESS) {
262 		/* Inform IDM of the relevant negotiated values */
263 		iscsi_notice_key_values(icp);
264 
265 		/* We are now logged in */
266 		iscsi_conn_update_state(icp, ISCSI_CONN_STATE_LOGGED_IN);
267 
268 		/* startup TX thread */
269 		(void) iscsi_thread_start(icp->conn_tx_thread);
270 
271 		/*
272 		 * Move login state machine to LOGIN_FFP.  This will
273 		 * release the taskq thread handling the CN_FFP_ENABLED
274 		 * allowing the IDM connection state machine to resume
275 		 * processing events
276 		 */
277 		iscsi_login_update_state(icp, LOGIN_FFP);
278 
279 		/* Notify the session that a connection is logged in */
280 		mutex_enter(&isp->sess_state_mutex);
281 		iscsi_sess_state_machine(isp, ISCSI_SESS_EVENT_N1);
282 		mutex_exit(&isp->sess_state_mutex);
283 	} else {
284 		/* If login failed reset nego tpgt */
285 		isp->sess_tpgt_nego = ISCSI_DEFAULT_TPGT;
286 
287 		mutex_enter(&icp->conn_state_mutex);
288 		switch (icp->conn_state) {
289 		case ISCSI_CONN_STATE_IN_LOGIN:
290 			iscsi_conn_update_state_locked(icp,
291 			    ISCSI_CONN_STATE_FREE);
292 			mutex_exit(&icp->conn_state_mutex);
293 			break;
294 		case ISCSI_CONN_STATE_FAILED:
295 			if (status == ISCSI_STATUS_LOGIN_FAILED) {
296 				iscsi_conn_update_state_locked(icp,
297 				    ISCSI_CONN_STATE_FREE);
298 			} else {
299 				/* ISCSI_STATUS_LOGIN_TIMED_OUT */
300 				iscsi_conn_update_state_locked(icp,
301 				    ISCSI_CONN_STATE_POLLING);
302 			}
303 			mutex_exit(&icp->conn_state_mutex);
304 
305 			mutex_enter(&isp->sess_state_mutex);
306 			iscsi_sess_state_machine(isp, ISCSI_SESS_EVENT_N6);
307 			mutex_exit(&isp->sess_state_mutex);
308 
309 			if (status == ISCSI_STATUS_LOGIN_TIMED_OUT) {
310 				iscsi_conn_retry(isp, icp);
311 			}
312 			break;
313 		case ISCSI_CONN_STATE_POLLING:
314 			if (status == ISCSI_STATUS_LOGIN_FAILED) {
315 				iscsi_conn_update_state_locked(icp,
316 				    ISCSI_CONN_STATE_FREE);
317 				mutex_exit(&icp->conn_state_mutex);
318 
319 				mutex_enter(&isp->sess_state_mutex);
320 				iscsi_sess_state_machine(isp,
321 				    ISCSI_SESS_EVENT_N6);
322 				mutex_exit(&isp->sess_state_mutex);
323 			} else {
324 				/* ISCSI_STATUS_LOGIN_TIMED_OUT */
325 				if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
326 					mutex_exit(&icp->conn_state_mutex);
327 
328 					iscsi_conn_retry(isp, icp);
329 				} else {
330 					iscsi_conn_update_state_locked(icp,
331 					    ISCSI_CONN_STATE_FREE);
332 					mutex_exit(&icp->conn_state_mutex);
333 				}
334 			}
335 			break;
336 		case ISCSI_CONN_STATE_FREE:
337 			mutex_exit(&icp->conn_state_mutex);
338 			break;
339 		default:
340 			mutex_exit(&icp->conn_state_mutex);
341 			ASSERT(0);
342 			break;
343 		}
344 	}
345 
346 	if (itp->t_blocking == B_FALSE) {
347 		kmem_free(itp, sizeof (iscsi_task_t));
348 	}
349 
350 	isp->sess_boot_nic_reset = B_FALSE;
351 }
352 
353 /*
354  * +--------------------------------------------------------------------+
355  * | Begin of protocol login routines					|
356  * +--------------------------------------------------------------------+
357  */
358 
359 /*
360  * iscsi_login - Attempt to login to the target.  The caller
361  * must check the status class to determine if the login succeeded.
362  * A return of 1 does not mean the login succeeded, it just means
363  * this function worked, and the status class is valid info.  This
364  * allows the caller to decide whether or not to retry logins, so
365  * that we don't have any policy logic here.
366  */
367 iscsi_status_t
368 iscsi_login(iscsi_conn_t *icp, uint8_t *status_class, uint8_t *status_detail)
369 {
370 	iscsi_status_t		rval		= ISCSI_STATUS_INTERNAL_ERROR;
371 	struct iscsi_sess	*isp		= NULL;
372 	IscsiAuthClient		*auth_client	= NULL;
373 	int			max_data_length	= 0;
374 	char			*data		= NULL;
375 	idm_pdu_t		*text_pdu;
376 	char			*buffer;
377 	size_t			bufsize;
378 	iscsi_login_rsp_hdr_t	*ilrhp;
379 	clock_t			response_timeout, timeout_result;
380 
381 	buffer = icp->conn_login_data;
382 	bufsize = icp->conn_login_max_data_length;
383 
384 	ASSERT(icp != NULL);
385 	ASSERT(buffer != NULL);
386 	ASSERT(status_class != NULL);
387 	ASSERT(status_detail != NULL);
388 	isp = icp->conn_sess;
389 	ASSERT(isp != NULL);
390 
391 	/*
392 	 * prepare the connection, hold IDM connection until login completes
393 	 */
394 	icp->conn_current_stage = ISCSI_INITIAL_LOGIN_STAGE;
395 	icp->conn_partial_response = 0;
396 
397 	if (isp->sess_auth.auth_buffers &&
398 	    isp->sess_auth.num_auth_buffers) {
399 
400 		auth_client = (IscsiAuthClient *)isp->
401 		    sess_auth.auth_buffers[0].address;
402 
403 		/*
404 		 * prepare for authentication
405 		 */
406 		if (iscsiAuthClientInit(iscsiAuthNodeTypeInitiator,
407 		    isp->sess_auth.num_auth_buffers,
408 		    isp->sess_auth.auth_buffers) !=
409 		    iscsiAuthStatusNoError) {
410 			cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
411 			    "unable to initialize authentication",
412 			    icp->conn_oid);
413 			iscsi_login_disconnect(icp);
414 			iscsi_login_update_state(icp, LOGIN_DONE);
415 			return (ISCSI_STATUS_INTERNAL_ERROR);
416 		}
417 
418 		if (iscsiAuthClientSetVersion(auth_client,
419 		    iscsiAuthVersionRfc) != iscsiAuthStatusNoError) {
420 			cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
421 			    "unable to set authentication", icp->conn_oid);
422 			goto iscsi_login_done;
423 		}
424 
425 		if (isp->sess_auth.username &&
426 		    (iscsiAuthClientSetUsername(auth_client,
427 		    isp->sess_auth.username) !=
428 		    iscsiAuthStatusNoError)) {
429 			cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
430 			    "unable to set username", icp->conn_oid);
431 			goto iscsi_login_done;
432 		}
433 
434 		if (isp->sess_auth.password &&
435 		    (iscsiAuthClientSetPassword(auth_client,
436 		    isp->sess_auth.password, isp->sess_auth.password_length) !=
437 		    iscsiAuthStatusNoError)) {
438 			cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
439 			    "unable to set password", icp->conn_oid);
440 			goto iscsi_login_done;
441 		}
442 
443 		if (iscsiAuthClientSetIpSec(auth_client, 1) !=
444 		    iscsiAuthStatusNoError) {
445 			cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
446 			    "unable to set ipsec", icp->conn_oid);
447 			goto iscsi_login_done;
448 		}
449 
450 		if (iscsiAuthClientSetAuthRemote(auth_client,
451 		    isp->sess_auth.bidirectional_auth) !=
452 		    iscsiAuthStatusNoError) {
453 			cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
454 			    "unable to set remote authentication",
455 			    icp->conn_oid);
456 			goto iscsi_login_done;
457 		}
458 	}
459 
460 	/*
461 	 * exchange PDUs until the login stage is complete, or an error occurs
462 	 */
463 	do {
464 		/* setup */
465 		bzero(buffer, bufsize);
466 		data = buffer;
467 		max_data_length = bufsize;
468 		rval = ISCSI_STATUS_INTERNAL_ERROR;
469 
470 		text_pdu = idm_pdu_alloc(sizeof (iscsi_hdr_t), 0);
471 		idm_pdu_init(text_pdu, icp->conn_ic, NULL, NULL);
472 
473 		/*
474 		 * fill in the PDU header and text data based on the
475 		 * login stage that we're in
476 		 */
477 		rval = iscsi_make_login_pdu(icp, text_pdu, data,
478 		    max_data_length);
479 		if (!ISCSI_SUCCESS(rval)) {
480 			cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
481 			    "unable to make login pdu", icp->conn_oid);
482 			goto iscsi_login_done;
483 		}
484 
485 		mutex_enter(&icp->conn_login_mutex);
486 		/*
487 		 * Make sure we are still in LOGIN_START or LOGIN_RX
488 		 * state before switching to LOGIN_TX.  It's possible
489 		 * for a connection failure to move us to LOGIN_ERROR
490 		 * before we get to this point.
491 		 */
492 		if (((icp->conn_login_state != LOGIN_READY) &&
493 		    (icp->conn_login_state != LOGIN_RX)) ||
494 		    !icp->conn_state_idm_connected) {
495 			/* Error occurred */
496 			mutex_exit(&icp->conn_login_mutex);
497 			rval = (ISCSI_STATUS_INTERNAL_ERROR);
498 			goto iscsi_login_done;
499 		}
500 
501 		iscsi_login_update_state_locked(icp, LOGIN_TX);
502 		icp->conn_login_data = data;
503 		icp->conn_login_max_data_length = max_data_length;
504 
505 		/*
506 		 * send a PDU to the target.  This is asynchronous but
507 		 * we don't have any particular need for a TX completion
508 		 * notification since we are going to block waiting for the
509 		 * receive.
510 		 */
511 		response_timeout = ddi_get_lbolt() +
512 		    SEC_TO_TICK(icp->conn_tunable_params.
513 		    recv_login_rsp_timeout);
514 		idm_pdu_tx(text_pdu);
515 
516 		/*
517 		 * Wait for login failure indication or login RX.
518 		 * Handler for login response PDU will copy any data into
519 		 * the buffer pointed to by icp->conn_login_data
520 		 */
521 		while (icp->conn_login_state == LOGIN_TX) {
522 			timeout_result = cv_timedwait(&icp->conn_login_cv,
523 			    &icp->conn_login_mutex, response_timeout);
524 			if (timeout_result == -1)
525 				break;
526 		}
527 
528 		if (icp->conn_login_state != LOGIN_RX) {
529 			mutex_exit(&icp->conn_login_mutex);
530 			rval = (ISCSI_STATUS_INTERNAL_ERROR);
531 			goto iscsi_login_done;
532 		}
533 		mutex_exit(&icp->conn_login_mutex);
534 
535 		/* check the PDU response type */
536 		ilrhp = (iscsi_login_rsp_hdr_t *)&icp->conn_login_resp_hdr;
537 		if (ilrhp->opcode != ISCSI_OP_LOGIN_RSP) {
538 			cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
539 			    "received invalid login response (0x%02x)",
540 			    icp->conn_oid, ilrhp->opcode);
541 			rval = (ISCSI_STATUS_PROTOCOL_ERROR);
542 			goto iscsi_login_done;
543 		}
544 
545 		/*
546 		 * give the caller the status class and detail from the
547 		 * last login response PDU received
548 		 */
549 		if (status_class) {
550 			*status_class = ilrhp->status_class;
551 		}
552 		if (status_detail) {
553 			*status_detail = ilrhp->status_detail;
554 		}
555 
556 		switch (ilrhp->status_class) {
557 		case ISCSI_STATUS_CLASS_SUCCESS:
558 			/*
559 			 * process this response and possibly continue
560 			 * sending PDUs
561 			 */
562 			rval = iscsi_process_login_response(icp,
563 			    ilrhp, (char *)icp->conn_login_data,
564 			    icp->conn_login_max_data_length);
565 			/* pass back whatever error we discovered */
566 			if (!ISCSI_SUCCESS(rval)) {
567 				if (ISCSI_LOGIN_TRANSIT_FFP(ilrhp->flags)) {
568 					/*
569 					 * iSCSI connection transit to next
570 					 * FFP stage while iscsi params
571 					 * ngeotiate error, LOGIN_ERROR
572 					 * marked so CN_FFP_ENABLED can
573 					 * be fully handled before
574 					 * CN_FFP_DISABLED can be processed.
575 					 */
576 					iscsi_login_update_state(icp,
577 					    LOGIN_ERROR);
578 				}
579 				goto iscsi_login_done;
580 			}
581 
582 			break;
583 		case ISCSI_STATUS_CLASS_REDIRECT:
584 			/*
585 			 * we need to process this response to get the
586 			 * TargetAddress of the redirect, but we don't
587 			 * care about the return code.
588 			 */
589 			(void) iscsi_process_login_response(icp,
590 			    ilrhp, (char *)icp->conn_login_data,
591 			    icp->conn_login_max_data_length);
592 			rval = ISCSI_STATUS_SUCCESS;
593 			goto iscsi_login_done;
594 		case ISCSI_STATUS_CLASS_INITIATOR_ERR:
595 			if (ilrhp->status_detail ==
596 			    ISCSI_LOGIN_STATUS_AUTH_FAILED) {
597 				cmn_err(CE_WARN, "iscsi connection(%u) login "
598 				    "failed - login failed to authenticate "
599 				    "with target", icp->conn_oid);
600 			}
601 			rval = ISCSI_STATUS_SUCCESS;
602 			goto iscsi_login_done;
603 		default:
604 			/*
605 			 * some sort of error, login terminated unsuccessfully,
606 			 * though this function did it's job. the caller must
607 			 * check the status_class and status_detail and decide
608 			 * what to do next.
609 			 */
610 			rval = ISCSI_STATUS_SUCCESS;
611 			goto iscsi_login_done;
612 		}
613 
614 	} while (icp->conn_current_stage != ISCSI_FULL_FEATURE_PHASE);
615 
616 	rval = ISCSI_STATUS_SUCCESS;
617 
618 iscsi_login_done:
619 	if (auth_client) {
620 		if (iscsiAuthClientFinish(auth_client) !=
621 		    iscsiAuthStatusNoError) {
622 			cmn_err(CE_WARN, "iscsi connection(%u) login "
623 			    "failed - login failed to authenticate "
624 			    "with target", icp->conn_oid);
625 			if (ISCSI_SUCCESS(rval))
626 				rval = ISCSI_STATUS_INTERNAL_ERROR;
627 		}
628 	}
629 
630 	if (ISCSI_SUCCESS(rval) &&
631 	    (*status_class == ISCSI_STATUS_CLASS_SUCCESS)) {
632 		mutex_enter(&icp->conn_state_mutex);
633 		while (!icp->conn_state_ffp)
634 			cv_wait(&icp->conn_state_change,
635 			    &icp->conn_state_mutex);
636 		mutex_exit(&icp->conn_state_mutex);
637 	} else {
638 		iscsi_login_disconnect(icp);
639 	}
640 
641 	iscsi_login_update_state(icp, LOGIN_DONE);
642 
643 	return (rval);
644 }
645 
646 
647 /*
648  * iscsi_make_login_pdu -
649  *
650  */
651 static iscsi_status_t
652 iscsi_make_login_pdu(iscsi_conn_t *icp, idm_pdu_t *text_pdu,
653     char *data, int max_data_length)
654 {
655 	struct iscsi_sess	*isp		= NULL;
656 	int			transit		= 0;
657 	iscsi_hdr_t		*ihp		= text_pdu->isp_hdr;
658 	iscsi_login_hdr_t	*ilhp		=
659 	    (iscsi_login_hdr_t *)text_pdu->isp_hdr;
660 	IscsiAuthClient		*auth_client	= NULL;
661 	int			keytype		= 0;
662 	int			rc		= 0;
663 	char			value[iscsiAuthStringMaxLength];
664 
665 	ASSERT(icp != NULL);
666 	ASSERT(text_pdu != NULL);
667 	isp = icp->conn_sess;
668 	ASSERT(isp != NULL);
669 
670 	auth_client =
671 	    (isp->sess_auth.auth_buffers && isp->sess_auth.num_auth_buffers) ?
672 	    (IscsiAuthClient *)isp->sess_auth.auth_buffers[0].address : NULL;
673 
674 	/*
675 	 * initialize the PDU header
676 	 */
677 	bzero(ilhp, sizeof (*ilhp));
678 	ilhp->opcode = ISCSI_OP_LOGIN_CMD | ISCSI_OP_IMMEDIATE;
679 	ilhp->cid = icp->conn_cid;
680 	bcopy(&isp->sess_isid[0], &ilhp->isid[0], sizeof (isp->sess_isid));
681 	ilhp->tsid = 0;
682 
683 	/*
684 	 * Set data buffer pointer.  The calls to iscsi_add_text will update the
685 	 * data length.
686 	 */
687 	text_pdu->isp_data = (uint8_t *)data;
688 
689 	/* don't increment on immediate */
690 	ilhp->cmdsn = htonl(isp->sess_cmdsn);
691 
692 	ilhp->min_version = ISCSI_DRAFT20_VERSION;
693 	ilhp->max_version = ISCSI_DRAFT20_VERSION;
694 
695 	/*
696 	 * we have to send 0 until full-feature stage
697 	 */
698 	ilhp->expstatsn = htonl(icp->conn_expstatsn);
699 
700 	/*
701 	 * the very first Login PDU has some additional requirements,
702 	 * * and we need to decide what stage to start in.
703 	 */
704 	if (icp->conn_current_stage == ISCSI_INITIAL_LOGIN_STAGE) {
705 		if ((isp->sess_hba->hba_name) &&
706 		    (isp->sess_hba->hba_name[0])) {
707 			if (!iscsi_add_text(text_pdu, max_data_length,
708 			    "InitiatorName",
709 			    (char *)isp->sess_hba->hba_name)) {
710 				return (ISCSI_STATUS_INTERNAL_ERROR);
711 			}
712 		} else {
713 			cmn_err(CE_WARN, "iscsi connection(%u) login "
714 			    "failed - initiator name is required",
715 			    icp->conn_oid);
716 			return (ISCSI_STATUS_INTERNAL_ERROR);
717 		}
718 
719 		if ((isp->sess_hba->hba_alias) &&
720 		    (isp->sess_hba->hba_alias[0])) {
721 			if (!iscsi_add_text(text_pdu, max_data_length,
722 			    "InitiatorAlias",
723 			    (char *)isp->sess_hba->hba_alias)) {
724 				return (ISCSI_STATUS_INTERNAL_ERROR);
725 			}
726 		}
727 
728 		if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
729 			if (isp->sess_name[0] != '\0') {
730 				if (!iscsi_add_text(text_pdu, max_data_length,
731 				    "TargetName", (char *)isp->sess_name)) {
732 					return (ISCSI_STATUS_INTERNAL_ERROR);
733 				}
734 			}
735 
736 			if (!iscsi_add_text(text_pdu, max_data_length,
737 			    "SessionType", "Normal")) {
738 				return (ISCSI_STATUS_INTERNAL_ERROR);
739 			}
740 		} else if (isp->sess_type == ISCSI_SESS_TYPE_DISCOVERY) {
741 			if (!iscsi_add_text(text_pdu, max_data_length,
742 			    "SessionType", "Discovery")) {
743 				return (ISCSI_STATUS_INTERNAL_ERROR);
744 			}
745 		} else {
746 			return (ISCSI_STATUS_INTERNAL_ERROR);
747 		}
748 
749 		if (auth_client) {
750 			/* we're prepared to do authentication */
751 			icp->conn_current_stage =
752 			    ISCSI_SECURITY_NEGOTIATION_STAGE;
753 		} else {
754 			/* can't do any authentication, skip that stage */
755 			icp->conn_current_stage =
756 			    ISCSI_OP_PARMS_NEGOTIATION_STAGE;
757 		}
758 	}
759 
760 	/*
761 	 * fill in text based on the stage
762 	 */
763 	switch (icp->conn_current_stage) {
764 	case ISCSI_OP_PARMS_NEGOTIATION_STAGE:
765 		/*
766 		 * we always try to go from op params to full
767 		 * feature stage
768 		 */
769 		icp->conn_next_stage	= ISCSI_FULL_FEATURE_PHASE;
770 		transit			= 1;
771 
772 		/*
773 		 * The terminology here may have gotten dated.  A partial
774 		 * response is a login response that doesn't complete a
775 		 * login.  If we haven't gotten a partial response, then
776 		 * either we shouldn't be here, or we just switched to
777 		 * this stage, and need to start offering keys.
778 		 */
779 		if (!icp->conn_partial_response) {
780 			/*
781 			 * request the desired settings the first time
782 			 * we are in this stage
783 			 */
784 			switch (icp->conn_params.header_digest) {
785 			case ISCSI_DIGEST_NONE:
786 				if (!iscsi_add_text(text_pdu,
787 				    max_data_length, "HeaderDigest", "None")) {
788 					return (ISCSI_STATUS_INTERNAL_ERROR);
789 				}
790 				break;
791 			case ISCSI_DIGEST_CRC32C:
792 				if (!iscsi_add_text(text_pdu,
793 				    max_data_length,
794 				    "HeaderDigest", "CRC32C")) {
795 					return (ISCSI_STATUS_INTERNAL_ERROR);
796 				}
797 				break;
798 			case ISCSI_DIGEST_CRC32C_NONE:
799 				if (!iscsi_add_text(text_pdu,
800 				    max_data_length, "HeaderDigest",
801 				    "CRC32C,None")) {
802 					return (ISCSI_STATUS_INTERNAL_ERROR);
803 				}
804 				break;
805 			default:
806 			case ISCSI_DIGEST_NONE_CRC32C:
807 				if (!iscsi_add_text(text_pdu,
808 				    max_data_length, "HeaderDigest",
809 				    "None,CRC32C")) {
810 					return (ISCSI_STATUS_INTERNAL_ERROR);
811 				}
812 				break;
813 			}
814 
815 			switch (icp->conn_params.data_digest) {
816 			case ISCSI_DIGEST_NONE:
817 				if (!iscsi_add_text(text_pdu,
818 				    max_data_length, "DataDigest", "None")) {
819 					return (ISCSI_STATUS_INTERNAL_ERROR);
820 				}
821 				break;
822 			case ISCSI_DIGEST_CRC32C:
823 				if (!iscsi_add_text(text_pdu,
824 				    max_data_length, "DataDigest", "CRC32C")) {
825 					return (ISCSI_STATUS_INTERNAL_ERROR);
826 				}
827 				break;
828 			case ISCSI_DIGEST_CRC32C_NONE:
829 				if (!iscsi_add_text(text_pdu,
830 				    max_data_length, "DataDigest",
831 				    "CRC32C,None")) {
832 					return (ISCSI_STATUS_INTERNAL_ERROR);
833 				}
834 				break;
835 			default:
836 			case ISCSI_DIGEST_NONE_CRC32C:
837 				if (!iscsi_add_text(text_pdu,
838 				    max_data_length, "DataDigest",
839 				    "None,CRC32C")) {
840 					return (ISCSI_STATUS_INTERNAL_ERROR);
841 				}
842 				break;
843 			}
844 
845 			(void) sprintf(value, "%d",
846 			    icp->conn_params.max_recv_data_seg_len);
847 			if (!iscsi_add_text(text_pdu, max_data_length,
848 			    "MaxRecvDataSegmentLength", value)) {
849 				return (ISCSI_STATUS_INTERNAL_ERROR);
850 			}
851 
852 			(void) sprintf(value, "%d",
853 			    icp->conn_params.default_time_to_wait);
854 			if (!iscsi_add_text(text_pdu,
855 			    max_data_length, "DefaultTime2Wait", value)) {
856 				return (ISCSI_STATUS_INTERNAL_ERROR);
857 			}
858 
859 			(void) sprintf(value, "%d",
860 			    icp->conn_params.default_time_to_retain);
861 			if (!iscsi_add_text(text_pdu,
862 			    max_data_length, "DefaultTime2Retain", value)) {
863 				return (ISCSI_STATUS_INTERNAL_ERROR);
864 			}
865 
866 			(void) sprintf(value, "%d",
867 			    icp->conn_params.error_recovery_level);
868 			if (!iscsi_add_text(text_pdu,
869 			    max_data_length, "ErrorRecoveryLevel", "0")) {
870 				return (ISCSI_STATUS_INTERNAL_ERROR);
871 			}
872 
873 			if (!iscsi_add_text(text_pdu,
874 			    max_data_length, "IFMarker",
875 			    icp->conn_params.ifmarker ? "Yes" : "No")) {
876 				return (ISCSI_STATUS_INTERNAL_ERROR);
877 			}
878 
879 			if (!iscsi_add_text(text_pdu,
880 			    max_data_length, "OFMarker",
881 			    icp->conn_params.ofmarker ? "Yes" : "No")) {
882 				return (ISCSI_STATUS_INTERNAL_ERROR);
883 			}
884 
885 			/*
886 			 * The following login parameters are "Irrelevant"
887 			 * for discovery sessions
888 			 */
889 			if (isp->sess_type != ISCSI_SESS_TYPE_DISCOVERY) {
890 
891 				if (!iscsi_add_text(text_pdu,
892 				    max_data_length, "InitialR2T",
893 				    icp->conn_params.initial_r2t ?
894 				    "Yes" : "No")) {
895 					return (ISCSI_STATUS_INTERNAL_ERROR);
896 				}
897 
898 				if (!iscsi_add_text(text_pdu,
899 				    max_data_length, "ImmediateData",
900 				    icp->conn_params.immediate_data ?
901 				    "Yes" : "No")) {
902 					return (ISCSI_STATUS_INTERNAL_ERROR);
903 				}
904 
905 				(void) sprintf(value, "%d",
906 				    icp->conn_params.max_burst_length);
907 				if (!iscsi_add_text(text_pdu,
908 				    max_data_length, "MaxBurstLength", value)) {
909 					return (ISCSI_STATUS_INTERNAL_ERROR);
910 				}
911 
912 				(void) sprintf(value, "%d",
913 				    icp->conn_params.first_burst_length);
914 				if (!iscsi_add_text(text_pdu, max_data_length,
915 				    "FirstBurstLength", value)) {
916 					return (ISCSI_STATUS_INTERNAL_ERROR);
917 				}
918 
919 				(void) sprintf(value, "%d",
920 				    icp->conn_params.max_outstanding_r2t);
921 				if (!iscsi_add_text(text_pdu, max_data_length,
922 				    "MaxOutstandingR2T", value)) {
923 					return (ISCSI_STATUS_INTERNAL_ERROR);
924 				}
925 
926 				(void) sprintf(value, "%d",
927 				    icp->conn_params.max_connections);
928 				if (!iscsi_add_text(text_pdu, max_data_length,
929 				    "MaxConnections", value)) {
930 					return (ISCSI_STATUS_INTERNAL_ERROR);
931 				}
932 
933 				if (!iscsi_add_text(text_pdu,
934 				    max_data_length, "DataPDUInOrder",
935 				    icp->conn_params.data_pdu_in_order ?
936 				    "Yes" : "No")) {
937 					return (ISCSI_STATUS_INTERNAL_ERROR);
938 				}
939 
940 				if (!iscsi_add_text(text_pdu,
941 				    max_data_length, "DataSequenceInOrder",
942 				    icp->conn_params.data_sequence_in_order ?
943 				    "Yes" : "No")) {
944 					return (ISCSI_STATUS_INTERNAL_ERROR);
945 				}
946 			}
947 		}
948 		break;
949 
950 	case ISCSI_SECURITY_NEGOTIATION_STAGE:
951 		keytype = iscsiAuthKeyTypeNone;
952 		rc = iscsiAuthClientSendTransitBit(auth_client, &transit);
953 
954 		/*
955 		 * see if we're ready for a stage change
956 		 */
957 		if (rc == iscsiAuthStatusNoError) {
958 			if (transit) {
959 				icp->conn_next_stage =
960 				    ISCSI_OP_PARMS_NEGOTIATION_STAGE;
961 			} else {
962 				icp->conn_next_stage =
963 				    ISCSI_SECURITY_NEGOTIATION_STAGE;
964 			}
965 		} else {
966 			return (ISCSI_STATUS_INTERNAL_ERROR);
967 		}
968 
969 		/*
970 		 * enumerate all the keys the auth code might want to send
971 		 */
972 		while (iscsiAuthClientGetNextKeyType(&keytype) ==
973 		    iscsiAuthStatusNoError) {
974 			int present = 0;
975 			char *key = (char *)iscsiAuthClientGetKeyName(keytype);
976 			int key_length = key ? strlen(key) : 0;
977 			int pdu_length = text_pdu->isp_datalen;
978 			char *auth_value = data + pdu_length + key_length + 1;
979 			unsigned int max_length = max_data_length -
980 			    (pdu_length + key_length + 1);
981 
982 			/*
983 			 * add the key/value pairs the auth code wants to
984 			 * send directly to the PDU, since they could in
985 			 * theory be large.
986 			 */
987 			rc = iscsiAuthClientSendKeyValue(auth_client, keytype,
988 			    &present, auth_value, max_length);
989 			if ((rc == iscsiAuthStatusNoError) && present) {
990 				/*
991 				 * actually fill in the key
992 				 */
993 				(void) strncpy(&data[pdu_length], key,
994 				    key_length);
995 				pdu_length += key_length;
996 				data[pdu_length] = '=';
997 				pdu_length++;
998 				/*
999 				 * adjust the PDU's data segment length to
1000 				 * include the value and trailing NULL
1001 				 */
1002 				pdu_length += strlen(auth_value) + 1;
1003 				text_pdu->isp_datalen = pdu_length;
1004 				hton24(ihp->dlength, pdu_length);
1005 			}
1006 		}
1007 
1008 		break;
1009 	case ISCSI_FULL_FEATURE_PHASE:
1010 		cmn_err(CE_WARN, "iscsi connection(%u) login "
1011 		    "failed - can't send login in full feature stage",
1012 		    icp->conn_oid);
1013 		return (ISCSI_STATUS_INTERNAL_ERROR);
1014 	default:
1015 		cmn_err(CE_WARN, "iscsi connection(%u) login "
1016 		    "failed - can't send login in unknown stage (%d)",
1017 		    icp->conn_oid, icp->conn_current_stage);
1018 		return (ISCSI_STATUS_INTERNAL_ERROR);
1019 	}
1020 
1021 	/* fill in the flags */
1022 	ilhp->flags = icp->conn_current_stage << 2;
1023 	if (transit) {
1024 		/* transit to the next stage */
1025 		ilhp->flags |= icp->conn_next_stage;
1026 		ilhp->flags |= ISCSI_FLAG_LOGIN_TRANSIT;
1027 	} else {
1028 		/* next == current */
1029 		ilhp->flags |= icp->conn_current_stage;
1030 	}
1031 
1032 	return (ISCSI_STATUS_SUCCESS);
1033 }
1034 
1035 
1036 /*
1037  * iscsi_process_login_response - This assumes the text data is
1038  * always NUL terminated.  The caller can always arrange for that by
1039  * using a slightly larger buffer than the max PDU size, and then
1040  * appending a NUL to the PDU.
1041  */
1042 static iscsi_status_t
1043 iscsi_process_login_response(iscsi_conn_t *icp,
1044     iscsi_login_rsp_hdr_t *ilrhp, char *data, int max_data_length)
1045 {
1046 	iscsi_sess_t		*isp			= NULL;
1047 	IscsiAuthClient		*auth_client		= NULL;
1048 	int			transit			= 0;
1049 	char			*text			= data;
1050 	char			*end			= NULL;
1051 	int			pdu_current_stage	= 0;
1052 	int			pdu_next_stage		= 0;
1053 	int			debug_status		= 0;
1054 	unsigned long		tmp;
1055 	char			*tmpe;
1056 	boolean_t		fbl_irrelevant		= B_FALSE;
1057 
1058 	ASSERT(icp != NULL);
1059 	ASSERT(ilrhp != NULL);
1060 	ASSERT(data != NULL);
1061 	isp = icp->conn_sess;
1062 	ASSERT(isp != NULL);
1063 
1064 	auth_client =
1065 	    (isp->sess_auth.auth_buffers && isp->sess_auth.num_auth_buffers) ?
1066 	    (IscsiAuthClient *) isp->sess_auth.auth_buffers[0].address : NULL;
1067 	transit = ilrhp->flags & ISCSI_FLAG_LOGIN_TRANSIT;
1068 
1069 	/* verify the initial buffer was big enough to hold everything */
1070 	end = text + ntoh24(ilrhp->dlength) + 1;
1071 	if (end >= (data + max_data_length)) {
1072 		cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
1073 		    "buffer too small", icp->conn_oid);
1074 		return (ISCSI_STATUS_INTERNAL_ERROR);
1075 	}
1076 	*end = '\0';
1077 
1078 	/* if the response status was success, sanity check the response */
1079 	if (ilrhp->status_class == ISCSI_STATUS_CLASS_SUCCESS) {
1080 		/* check the active version */
1081 		if (ilrhp->active_version != ISCSI_DRAFT20_VERSION) {
1082 			cmn_err(CE_WARN, "iscsi connection(%u) login "
1083 			    "failed - target version incompatible "
1084 			    "received:0x%0x2x expected:0x%02x",
1085 			    icp->conn_oid, ilrhp->active_version,
1086 			    ISCSI_DRAFT20_VERSION);
1087 			return (ISCSI_STATUS_VERSION_MISMATCH);
1088 		}
1089 
1090 		/* make sure the current stage matches */
1091 		pdu_current_stage = (ilrhp->flags &
1092 		    ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2;
1093 		if (pdu_current_stage != icp->conn_current_stage) {
1094 			cmn_err(CE_WARN, "iscsi connection(%u) login "
1095 			    "failed - login response contained invalid "
1096 			    "stage %d", icp->conn_oid, pdu_current_stage);
1097 			return (ISCSI_STATUS_PROTOCOL_ERROR);
1098 		}
1099 
1100 		/*
1101 		 * Make sure that we're actually advancing
1102 		 * if the T-bit is set
1103 		 */
1104 		pdu_next_stage = ilrhp->flags &
1105 		    ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK;
1106 		if (transit && (pdu_next_stage <= icp->conn_current_stage)) {
1107 			cmn_err(CE_WARN, "iscsi connection(%u) login "
1108 			    "failed - login response wants to go to stage "
1109 			    "%d, but we want stage %d", icp->conn_oid,
1110 			    pdu_next_stage, icp->conn_next_stage);
1111 			return (ISCSI_STATUS_PROTOCOL_ERROR);
1112 		}
1113 	}
1114 
1115 	if (icp->conn_current_stage == ISCSI_SECURITY_NEGOTIATION_STAGE) {
1116 		if (iscsiAuthClientRecvBegin(auth_client) !=
1117 		    iscsiAuthStatusNoError) {
1118 			cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
1119 			    "authentication receive failed", icp->conn_oid);
1120 			return (ISCSI_STATUS_INTERNAL_ERROR);
1121 		}
1122 
1123 		if (iscsiAuthClientRecvTransitBit(auth_client,
1124 		    transit) != iscsiAuthStatusNoError) {
1125 			cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
1126 			    "authentication transmit failed", icp->conn_oid);
1127 			return (ISCSI_STATUS_INTERNAL_ERROR);
1128 		}
1129 	}
1130 
1131 	/*
1132 	 * scan the text data
1133 	 */
1134 more_text:
1135 	while (text && (text < end)) {
1136 		char *value = NULL;
1137 		char *value_end = NULL;
1138 
1139 		/*
1140 		 * skip any NULs separating each text key=value pair
1141 		 */
1142 		while ((text < end) && (*text == '\0')) {
1143 			text++;
1144 		}
1145 		if (text >= end) {
1146 			break;
1147 		}
1148 
1149 		/*
1150 		 * handle keys appropriate for each stage
1151 		 */
1152 		switch (icp->conn_current_stage) {
1153 		case ISCSI_SECURITY_NEGOTIATION_STAGE:
1154 			/*
1155 			 * a few keys are possible in Security stage
1156 			 * * which the auth code doesn't care about,
1157 			 * * but which we might want to see, or at
1158 			 * * least not choke on.
1159 			 */
1160 			if (iscsi_find_key_value("TargetAlias",
1161 			    text, end, &value, &value_end)) {
1162 				isp->sess_alias_length =
1163 				    sizeof (isp->sess_alias) - 1;
1164 
1165 				if ((value_end - value) <
1166 				    isp->sess_alias_length) {
1167 					isp->sess_alias_length =
1168 					    value_end - value;
1169 				}
1170 
1171 				bcopy(value, isp->sess_alias,
1172 				    isp->sess_alias_length);
1173 				isp->sess_alias[isp->sess_alias_length + 1] =
1174 				    '\0';
1175 				text = value_end;
1176 
1177 			} else if (iscsi_find_key_value("TargetAddress",
1178 			    text, end, &value, &value_end)) {
1179 				if (!ISCSI_SUCCESS(iscsi_update_address(
1180 				    icp, value))) {
1181 					cmn_err(CE_WARN, "iscsi connection(%u) "
1182 					    "login failed - login redirection "
1183 					    "invalid", icp->conn_oid);
1184 					return (ISCSI_STATUS_PROTOCOL_ERROR);
1185 				}
1186 				text = value_end;
1187 			} else if (iscsi_find_key_value("TargetPortalGroupTag",
1188 			    text, end, &value, &value_end)) {
1189 				/*
1190 				 * We should have already obtained this via
1191 				 * discovery.  We've already picked an isid,
1192 				 * so the most we can do is confirm we reached
1193 				 * the portal group we were expecting to.
1194 				 */
1195 				if (ddi_strtoul(value, &tmpe, 0, &tmp) != 0) {
1196 					return (ISCSI_STATUS_PROTOCOL_ERROR);
1197 				}
1198 				if (isp->sess_tpgt_conf != ISCSI_DEFAULT_TPGT) {
1199 					if (tmp != isp->sess_tpgt_conf) {
1200 
1201 	cmn_err(CE_WARN, "iscsi connection(%u) login failed - target "
1202 	    "protocol group tag mismatch, expected %d, received %lu",
1203 	    icp->conn_oid, isp->sess_tpgt_conf, tmp);
1204 	return (ISCSI_STATUS_PROTOCOL_ERROR);
1205 
1206 					}
1207 				}
1208 				isp->sess_tpgt_nego = (int)tmp;
1209 				text = value_end;
1210 			} else {
1211 				/*
1212 				 * any key we don't recognize either goes
1213 				 * to the auth code, or we choke on it
1214 				 */
1215 				int keytype = iscsiAuthKeyTypeNone;
1216 
1217 				while (iscsiAuthClientGetNextKeyType(
1218 				    &keytype) == iscsiAuthStatusNoError) {
1219 
1220 					char *key =
1221 					    (char *)iscsiAuthClientGetKeyName(
1222 					    keytype);
1223 
1224 					if ((key) &&
1225 					    (iscsi_find_key_value(key,
1226 					    text, end, &value, &value_end))) {
1227 
1228 						if (iscsiAuthClientRecvKeyValue
1229 						    (auth_client, keytype,
1230 						    value) !=
1231 						    iscsiAuthStatusNoError) {
1232 
1233 	cmn_err(CE_WARN, "iscsi connection(%u) login failed - can't accept "
1234 	    "%s in security stage", icp->conn_oid, text);
1235 	return (ISCSI_STATUS_NEGO_FAIL);
1236 
1237 						}
1238 						text = value_end;
1239 						goto more_text;
1240 					}
1241 				}
1242 
1243 	cmn_err(CE_WARN, "iscsi connection(%u) login failed - can't except "
1244 	    "%s in security stage", icp->conn_oid, text);
1245 
1246 				return (ISCSI_STATUS_NEGO_FAIL);
1247 			}
1248 			break;
1249 		case ISCSI_OP_PARMS_NEGOTIATION_STAGE:
1250 			if (iscsi_find_key_value("TargetAlias", text,
1251 			    end, &value, &value_end)) {
1252 				isp->sess_alias_length =
1253 				    sizeof (isp->sess_alias) - 1;
1254 
1255 				if ((value_end - value) <
1256 				    isp->sess_alias_length) {
1257 					isp->sess_alias_length =
1258 					    value_end - value;
1259 				}
1260 
1261 				bcopy(value, isp->sess_alias,
1262 				    isp->sess_alias_length);
1263 				isp->sess_alias[isp->sess_alias_length + 1] =
1264 				    '\0';
1265 				text = value_end;
1266 
1267 			} else if (iscsi_find_key_value("TargetAddress",
1268 			    text, end, &value, &value_end)) {
1269 				if (!ISCSI_SUCCESS(iscsi_update_address(
1270 				    icp, value))) {
1271 
1272 	cmn_err(CE_WARN, "iscsi connection(%u) login failed - login "
1273 	    "redirection invalid", icp->conn_oid);
1274 
1275 					return (ISCSI_STATUS_PROTOCOL_ERROR);
1276 				}
1277 				text = value_end;
1278 			} else if (iscsi_find_key_value("TargetPortalGroupTag",
1279 			    text, end, &value, &value_end)) {
1280 				/*
1281 				 * We should have already obtained this via
1282 				 * discovery.  We've already picked an isid,
1283 				 * so the most we can do is confirm we reached
1284 				 * the portal group we were expecting to.
1285 				 */
1286 				if (ddi_strtoul(value, &tmpe, 0, &tmp) != 0) {
1287 					return (ISCSI_STATUS_PROTOCOL_ERROR);
1288 				}
1289 				if (isp->sess_tpgt_conf != ISCSI_DEFAULT_TPGT) {
1290 					if (tmp != isp->sess_tpgt_conf) {
1291 
1292 	cmn_err(CE_WARN, "iscsi connection(%u) login failed - target portal "
1293 	    "tag mismatch, expected:%d received:%lu", icp->conn_oid,
1294 	    isp->sess_tpgt_conf, tmp);
1295 	return (ISCSI_STATUS_PROTOCOL_ERROR);
1296 
1297 					}
1298 				}
1299 				isp->sess_tpgt_nego = (int)tmp;
1300 				text = value_end;
1301 
1302 			} else if (iscsi_find_key_value("InitialR2T",
1303 			    text, end, &value, &value_end)) {
1304 
1305 				/*
1306 				 * iSCSI RFC section 12.10 states that
1307 				 * InitialR2T is Irrelevant for a
1308 				 * discovery session.
1309 				 */
1310 				if (isp->sess_type ==
1311 				    ISCSI_SESS_TYPE_DISCOVERY) {
1312 					/* EMPTY */
1313 				} else if (value == NULL) {
1314 					cmn_err(CE_WARN, "iscsi connection(%u) "
1315 					    "login failed - InitialR2T is "
1316 					    "invalid - protocol error",
1317 					    icp->conn_oid);
1318 					return (ISCSI_STATUS_PROTOCOL_ERROR);
1319 				} else if (strcmp(value, "Yes") == 0) {
1320 					icp->conn_params.initial_r2t = B_TRUE;
1321 				} else if (strcmp(value, "No") == 0) {
1322 					icp->conn_params.initial_r2t = B_FALSE;
1323 				} else {
1324 					cmn_err(CE_WARN, "iscsi connection(%u) "
1325 					    "login failed - InitialR2T  is "
1326 					    "invalid - protocol error",
1327 					    icp->conn_oid);
1328 					return (ISCSI_STATUS_PROTOCOL_ERROR);
1329 				}
1330 				text = value_end;
1331 
1332 			} else if (iscsi_find_key_value("ImmediateData",
1333 			    text, end, &value, &value_end)) {
1334 
1335 				/*
1336 				 * iSCSI RFC section 12.11 states that
1337 				 * ImmediateData is Irrelevant for a
1338 				 * discovery session.
1339 				 */
1340 				if (isp->sess_type ==
1341 				    ISCSI_SESS_TYPE_DISCOVERY) {
1342 					/* EMPTY */
1343 				} else if (value == NULL) {
1344 					cmn_err(CE_WARN, "iscsi connection(%u) "
1345 					    "login failed - ImmediateData is "
1346 					    "invalid - protocol error",
1347 					    icp->conn_oid);
1348 					return (ISCSI_STATUS_PROTOCOL_ERROR);
1349 				} else if (strcmp(value, "Yes") == 0) {
1350 					icp->conn_params.immediate_data = 1;
1351 				} else if (strcmp(value, "No") == 0) {
1352 					icp->conn_params.immediate_data = 0;
1353 				} else {
1354 					cmn_err(CE_WARN, "iscsi connection(%u) "
1355 					    "login failed - ImmediateData is "
1356 					    "invalid - protocol error",
1357 					    icp->conn_oid);
1358 					return (ISCSI_STATUS_PROTOCOL_ERROR);
1359 				}
1360 				text = value_end;
1361 
1362 			} else if (iscsi_find_key_value(
1363 			    "MaxRecvDataSegmentLength", text, end,
1364 			    &value, &value_end)) {
1365 
1366 				if (ddi_strtoul(value, &tmpe, 0, &tmp) != 0) {
1367 					cmn_err(CE_WARN, "iscsi connection(%u) "
1368 					    "login failed - MaxRecvDataSegment"
1369 					    "Length is invalid - protocol "
1370 					    "error", icp->conn_oid);
1371 					return (ISCSI_STATUS_NEGO_FAIL);
1372 				}
1373 				icp->conn_params.max_recv_data_seg_len =
1374 				    icp->conn_params.max_xmit_data_seg_len =
1375 				    (int)tmp;
1376 
1377 				text = value_end;
1378 			} else if (iscsi_find_key_value("FirstBurstLength",
1379 			    text, end, &value, &value_end)) {
1380 
1381 				/*
1382 				 * iSCSI RFC section 12.14 states that
1383 				 * FirstBurstLength is Irrelevant if
1384 				 * InitialR2T=Yes and ImmediateData=No
1385 				 * or is this is a discovery session.
1386 				 */
1387 				if ((isp->sess_type ==
1388 				    ISCSI_SESS_TYPE_DISCOVERY)) {
1389 					/* EMPTY */
1390 				} else if (value &&
1391 				    (strcmp(value, "Irrelevant") == 0)) {
1392 					/* irrelevant */
1393 					fbl_irrelevant = B_TRUE;
1394 				} else if (ddi_strtoul(
1395 				    value, &tmpe, 0, &tmp) != 0) {
1396 					/* bad value */
1397 					cmn_err(CE_WARN, "iscsi connection(%u) "
1398 					    "login failed - FirstBurstLength"
1399 					    "is invalid - protocol error",
1400 					    icp->conn_oid);
1401 					return (ISCSI_STATUS_PROTOCOL_ERROR);
1402 				} else {
1403 					/* good value */
1404 					icp->conn_params.first_burst_length =
1405 					    (int)tmp;
1406 				}
1407 				text = value_end;
1408 			} else if (iscsi_find_key_value("MaxBurstLength",
1409 			    text, end, &value, &value_end)) {
1410 				/*
1411 				 * iSCSI RFC section 12.13 states that
1412 				 * MaxBurstLength is Irrelevant for a
1413 				 * discovery session.
1414 				 */
1415 				if (isp->sess_type ==
1416 				    ISCSI_SESS_TYPE_DISCOVERY) {
1417 					/* EMPTY */
1418 				} else if (ddi_strtoul(
1419 				    value, &tmpe, 0, &tmp) != 0) {
1420 					cmn_err(CE_WARN, "iscsi connection(%u) "
1421 					    "login failed - MaxBurstLength"
1422 					    "is invalid - protocol error",
1423 					    icp->conn_oid);
1424 					return (ISCSI_STATUS_PROTOCOL_ERROR);
1425 				} else {
1426 					icp->conn_params.max_burst_length =
1427 					    (int)tmp;
1428 				}
1429 
1430 				text = value_end;
1431 
1432 			} else if (iscsi_find_key_value("HeaderDigest",
1433 			    text, end, &value, &value_end)) {
1434 
1435 				if (strcmp(value, "None") == 0) {
1436 					if (icp->conn_params.header_digest !=
1437 					    ISCSI_DIGEST_CRC32C) {
1438 						icp->conn_params.header_digest =
1439 						    ISCSI_DIGEST_NONE;
1440 					} else {
1441 						cmn_err(CE_WARN, "iscsi "
1442 						    "connection(%u) login "
1443 						    "failed - HeaderDigest="
1444 						    "CRC32 is required, can't "
1445 						    "accept %s",
1446 						    icp->conn_oid, text);
1447 						return (ISCSI_STATUS_NEGO_FAIL);
1448 					}
1449 				} else if (strcmp(value, "CRC32C") == 0) {
1450 					if (icp->conn_params.header_digest !=
1451 					    ISCSI_DIGEST_NONE) {
1452 						icp->conn_params.header_digest =
1453 						    ISCSI_DIGEST_CRC32C;
1454 					} else {
1455 						cmn_err(CE_WARN, "iscsi "
1456 						    "connection(%u) login "
1457 						    "failed - HeaderDigest="
1458 						    "None is required, can't "
1459 						    "accept %s",
1460 						    icp->conn_oid, text);
1461 						return (ISCSI_STATUS_NEGO_FAIL);
1462 					}
1463 				} else {
1464 					cmn_err(CE_WARN, "iscsi connection(%u) "
1465 					    "login failed - HeaderDigest "
1466 					    "can't accept %s", icp->conn_oid,
1467 					    text);
1468 					return (ISCSI_STATUS_NEGO_FAIL);
1469 				}
1470 				text = value_end;
1471 			} else if (iscsi_find_key_value("DataDigest", text,
1472 			    end, &value, &value_end)) {
1473 
1474 				if (strcmp(value, "None") == 0) {
1475 					if (icp->conn_params.data_digest !=
1476 					    ISCSI_DIGEST_CRC32C) {
1477 						icp->conn_params.data_digest =
1478 						    ISCSI_DIGEST_NONE;
1479 					} else {
1480 						cmn_err(CE_WARN, "iscsi "
1481 						    "connection(%u) login "
1482 						    "failed - DataDigest="
1483 						    "CRC32C is required, "
1484 						    "can't accept %s",
1485 						    icp->conn_oid, text);
1486 						return (ISCSI_STATUS_NEGO_FAIL);
1487 					}
1488 				} else if (strcmp(value, "CRC32C") == 0) {
1489 					if (icp->conn_params.data_digest !=
1490 					    ISCSI_DIGEST_NONE) {
1491 						icp->conn_params.data_digest =
1492 						    ISCSI_DIGEST_CRC32C;
1493 					} else {
1494 						cmn_err(CE_WARN, "iscsi "
1495 						    "connection(%u) login "
1496 						    "failed - DataDigest=None "
1497 						    "is required, can't "
1498 						    "accept %s",
1499 						    icp->conn_oid, text);
1500 						return (ISCSI_STATUS_NEGO_FAIL);
1501 					}
1502 				} else {
1503 					cmn_err(CE_WARN, "iscsi connection(%u) "
1504 					    "login failed - can't accept %s",
1505 					    icp->conn_oid, text);
1506 					return (ISCSI_STATUS_NEGO_FAIL);
1507 				}
1508 				text = value_end;
1509 
1510 			} else if (iscsi_find_key_value("DefaultTime2Wait",
1511 			    text, end, &value, &value_end)) {
1512 
1513 				if (ddi_strtoul(value, &tmpe, 0, &tmp) != 0) {
1514 					cmn_err(CE_WARN, "iscsi connection(%u) "
1515 					    "login failed - DefaultTime2Wait "
1516 					    "is invalid - protocol error",
1517 					    icp->conn_oid);
1518 					return (ISCSI_STATUS_PROTOCOL_ERROR);
1519 				}
1520 				icp->conn_params.default_time_to_wait =
1521 				    (int)tmp;
1522 
1523 				text = value_end;
1524 
1525 			} else if (iscsi_find_key_value("DefaultTime2Retain",
1526 			    text, end, &value, &value_end)) {
1527 
1528 				if (ddi_strtoul(value, &tmpe, 0, &tmp) != 0) {
1529 					cmn_err(CE_WARN, "iscsi connection(%u) "
1530 					    "login failed - DefaultTime2Retain "
1531 					    "is invalid - protocol error",
1532 					    icp->conn_oid);
1533 					return (ISCSI_STATUS_PROTOCOL_ERROR);
1534 				}
1535 				icp->conn_params.default_time_to_retain =
1536 				    (int)tmp;
1537 
1538 				text = value_end;
1539 
1540 			} else if (iscsi_find_key_value("OFMarker", text,
1541 			    end, &value, &value_end)) {
1542 
1543 				/*
1544 				 * result function is AND, target must
1545 				 * honor our No
1546 				 */
1547 				text = value_end;
1548 
1549 			} else if (iscsi_find_key_value("OFMarkInt", text,
1550 			    end, &value, &value_end)) {
1551 
1552 				/*
1553 				 * we don't do markers, so we don't care
1554 				 */
1555 				text = value_end;
1556 
1557 			} else if (iscsi_find_key_value("IFMarker", text,
1558 			    end, &value, &value_end)) {
1559 
1560 				/*
1561 				 * result function is AND, target must
1562 				 * honor our No
1563 				 */
1564 				text = value_end;
1565 
1566 			} else if (iscsi_find_key_value("IFMarkInt", text,
1567 			    end, &value, &value_end)) {
1568 
1569 				/*
1570 				 * we don't do markers, so we don't care
1571 				 */
1572 				text = value_end;
1573 
1574 			} else if (iscsi_find_key_value("DataPDUInOrder",
1575 			    text, end, &value, &value_end)) {
1576 
1577 				/*
1578 				 * iSCSI RFC section 12.18 states that
1579 				 * DataPDUInOrder is Irrelevant for a
1580 				 * discovery session.
1581 				 */
1582 				if (isp->sess_type ==
1583 				    ISCSI_SESS_TYPE_DISCOVERY) {
1584 					/* EMPTY */
1585 				} else if (value == NULL) {
1586 					cmn_err(CE_WARN, "iscsi connection(%u) "
1587 					    "login failed - InitialR2T is "
1588 					    "invalid - protocol error",
1589 					    icp->conn_oid);
1590 					return (ISCSI_STATUS_PROTOCOL_ERROR);
1591 				} else if (strcmp(value, "Yes") == 0) {
1592 					icp->conn_params.data_pdu_in_order =
1593 					    B_TRUE;
1594 				} else if (strcmp(value, "No") == 0) {
1595 					icp->conn_params.data_pdu_in_order =
1596 					    B_FALSE;
1597 				} else {
1598 					cmn_err(CE_WARN, "iscsi connection(%u) "
1599 					    "login failed - InitialR2T is "
1600 					    "invalid - protocol error",
1601 					    icp->conn_oid);
1602 					return (ISCSI_STATUS_PROTOCOL_ERROR);
1603 				}
1604 				text = value_end;
1605 
1606 			} else if (iscsi_find_key_value("DataSequenceInOrder",
1607 			    text, end, &value, &value_end)) {
1608 
1609 				/*
1610 				 * iSCSI RFC section 12.19 states that
1611 				 * DataSequenceInOrder is Irrelevant for a
1612 				 * discovery session.
1613 				 */
1614 				if (isp->sess_type ==
1615 				    ISCSI_SESS_TYPE_DISCOVERY) {
1616 					/* EMPTY */
1617 				} else if (value == NULL) {
1618 					cmn_err(CE_WARN, "iscsi connection(%u) "
1619 					    "login failed - InitialR2T is "
1620 					    "invalid - protocol error",
1621 					    icp->conn_oid);
1622 					return (ISCSI_STATUS_PROTOCOL_ERROR);
1623 				} else if (strcmp(value, "Yes") == 0) {
1624 					icp->conn_params.
1625 					    data_sequence_in_order = B_TRUE;
1626 				} else if (strcmp(value, "No") == 0) {
1627 					icp->conn_params.
1628 					    data_sequence_in_order = B_FALSE;
1629 				} else {
1630 					cmn_err(CE_WARN, "iscsi connection(%u) "
1631 					    "login failed - InitialR2T is "
1632 					    "invalid - protocol error",
1633 					    icp->conn_oid);
1634 					return (ISCSI_STATUS_PROTOCOL_ERROR);
1635 				}
1636 				text = value_end;
1637 
1638 			} else if (iscsi_find_key_value("MaxOutstandingR2T",
1639 			    text, end, &value, &value_end)) {
1640 
1641 				/*
1642 				 * iSCSI RFC section 12.17 states that
1643 				 * MaxOutstandingR2T is Irrelevant for a
1644 				 * discovery session.
1645 				 */
1646 				if (isp->sess_type ==
1647 				    ISCSI_SESS_TYPE_DISCOVERY) {
1648 					/* EMPTY */
1649 				} else if (strcmp(value, "1")) {
1650 					cmn_err(CE_WARN, "iscsi connection(%u) "
1651 					    "login failed - can't accept "
1652 					    "MaxOutstandingR2T %s",
1653 					    icp->conn_oid, value);
1654 					return (ISCSI_STATUS_NEGO_FAIL);
1655 				}
1656 				text = value_end;
1657 
1658 			} else if (iscsi_find_key_value("MaxConnections",
1659 			    text, end, &value, &value_end)) {
1660 
1661 				/*
1662 				 * iSCSI RFC section 12.2 states that
1663 				 * MaxConnections is Irrelevant for a
1664 				 * discovery session.
1665 				 */
1666 				if (isp->sess_type ==
1667 				    ISCSI_SESS_TYPE_DISCOVERY) {
1668 					/* EMPTY */
1669 				} else if (strcmp(value, "1")) {
1670 					cmn_err(CE_WARN, "iscsi connection(%u) "
1671 					    "login failed - can't accept "
1672 					    "MaxConnections %s",
1673 					    icp->conn_oid, value);
1674 					return (ISCSI_STATUS_NEGO_FAIL);
1675 				}
1676 				text = value_end;
1677 
1678 			} else if (iscsi_find_key_value("ErrorRecoveryLevel",
1679 			    text, end, &value, &value_end)) {
1680 
1681 				if (strcmp(value, "0")) {
1682 
1683 					cmn_err(CE_WARN, "iscsi connection(%u) "
1684 					    "login failed - can't accept "
1685 					    "ErrorRecoveryLevel %s",
1686 					    icp->conn_oid, value);
1687 					return (ISCSI_STATUS_NEGO_FAIL);
1688 				}
1689 				text = value_end;
1690 
1691 			} else {
1692 				cmn_err(CE_WARN, "iscsi connection(%u) "
1693 				    "login failed - ignoring login "
1694 				    "parameter %s", icp->conn_oid, value);
1695 				text = value_end;
1696 			}
1697 			break;
1698 		default:
1699 			return (ISCSI_STATUS_INTERNAL_ERROR);
1700 		}
1701 	}
1702 
1703 	/*
1704 	 * iSCSI RFC section 12.14 states that
1705 	 * FirstBurstLength is Irrelevant if
1706 	 * InitialR2T=Yes and ImmediateData=No.
1707 	 * This is a final check to make sure
1708 	 * the array didn't make a protocol
1709 	 * violation.
1710 	 */
1711 	if ((fbl_irrelevant == B_TRUE) &&
1712 	    ((icp->conn_params.initial_r2t != B_TRUE) ||
1713 	    (icp->conn_params.immediate_data != B_FALSE))) {
1714 		cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
1715 		    "FirstBurstLength=Irrelevant and (InitialR2T!=Yes or "
1716 		    "ImmediateData!=No) - protocol error", icp->conn_oid);
1717 		return (ISCSI_STATUS_PROTOCOL_ERROR);
1718 	}
1719 
1720 	if (icp->conn_current_stage == ISCSI_SECURITY_NEGOTIATION_STAGE) {
1721 		switch (iscsiAuthClientRecvEnd(auth_client, iscsi_null_callback,
1722 		    (void *)isp, NULL)) {
1723 		case iscsiAuthStatusContinue:
1724 			/*
1725 			 * continue sending PDUs
1726 			 */
1727 			break;
1728 
1729 		case iscsiAuthStatusPass:
1730 			break;
1731 
1732 		case iscsiAuthStatusInProgress:
1733 			/*
1734 			 * this should only occur if we were authenticating the
1735 			 * target, which we don't do yet, so treat this as an
1736 			 * error.
1737 			 */
1738 		case iscsiAuthStatusNoError:
1739 			/*
1740 			 * treat this as an error, since we should get a
1741 			 * different code
1742 			 */
1743 		case iscsiAuthStatusError:
1744 		case iscsiAuthStatusFail:
1745 		default:
1746 			debug_status = 0;
1747 
1748 			if (iscsiAuthClientGetDebugStatus(auth_client,
1749 			    &debug_status) != iscsiAuthStatusNoError) {
1750 
1751 				cmn_err(CE_WARN, "iscsi connection(%u) login "
1752 				    "failed - authentication failed with "
1753 				    "target (%s)", icp->conn_oid,
1754 				    iscsiAuthClientDebugStatusToText(
1755 				    debug_status));
1756 
1757 			} else {
1758 
1759 				cmn_err(CE_WARN, "iscsi connection(%u) login "
1760 				    "failed - authentication failed with "
1761 				    "target", icp->conn_oid);
1762 
1763 			}
1764 			return (ISCSI_STATUS_AUTHENTICATION_FAILED);
1765 		}
1766 	}
1767 
1768 	/*
1769 	 * record some of the PDU fields for later use
1770 	 */
1771 	isp->sess_tsid = ntohs(ilrhp->tsid);
1772 	isp->sess_expcmdsn = ntohl(ilrhp->expcmdsn);
1773 	isp->sess_maxcmdsn = ntohl(ilrhp->maxcmdsn);
1774 	if (ilrhp->status_class == ISCSI_STATUS_CLASS_SUCCESS) {
1775 		icp->conn_expstatsn = ntohl(ilrhp->statsn) + 1;
1776 	}
1777 
1778 	if (transit) {
1779 		/*
1780 		 * advance to the next stage
1781 		 */
1782 		icp->conn_partial_response = 0;
1783 		icp->conn_current_stage =
1784 		    ilrhp->flags & ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK;
1785 	} else {
1786 		/*
1787 		 * we got a partial response, don't advance, more
1788 		 * negotiation to do
1789 		 */
1790 		icp->conn_partial_response = 1;
1791 	}
1792 
1793 	/*
1794 	 * this PDU is ok, though the login process
1795 	 * may not be done yet
1796 	 */
1797 	return (ISCSI_STATUS_SUCCESS);
1798 }
1799 
1800 /*
1801  * iscsi_add_text - caller is assumed to be well-behaved and passing NUL
1802  * terminated strings
1803  */
1804 int
1805 iscsi_add_text(idm_pdu_t *text_pdu, int max_data_length,
1806     char *param, char *value)
1807 {
1808 	int	param_len	= 0;
1809 	int	value_len	= 0;
1810 	int	length		= 0;
1811 	int	pdu_length	= 0;
1812 	char	*text		= NULL;
1813 	char	*end		= NULL;
1814 
1815 	ASSERT(text_pdu != NULL);
1816 	ASSERT(param != NULL);
1817 	ASSERT(value != NULL);
1818 
1819 	param_len = strlen(param);
1820 	value_len = strlen(value);
1821 	/* param, separator, value, and trailing NULL */
1822 	length		= param_len + 1 + value_len + 1;
1823 	pdu_length	= text_pdu->isp_datalen;
1824 	text		= (char *)text_pdu->isp_data + pdu_length;
1825 	end		= (char *)text_pdu->isp_data + max_data_length;
1826 	pdu_length	+= length;
1827 
1828 	if (text + length >= end) {
1829 		return (0);
1830 	}
1831 
1832 	/* param */
1833 	(void) strncpy(text, param, param_len);
1834 	text += param_len;
1835 
1836 	/* separator */
1837 	*text++ = ISCSI_TEXT_SEPARATOR;
1838 
1839 	/* value */
1840 	(void) strncpy(text, value, value_len);
1841 	text += value_len;
1842 
1843 	/* NULL */
1844 	*text++ = '\0';
1845 
1846 	/* update the length in the PDU header */
1847 	text_pdu->isp_datalen = pdu_length;
1848 	hton24(text_pdu->isp_hdr->dlength, pdu_length);
1849 
1850 	return (1);
1851 }
1852 
1853 /*
1854  * iscsi_get_next_text - get the next line of text from the given data
1855  * buffer.  This function searches from the address given for the
1856  * curr_text parameter.  If curr_text_parameter is NULL return first
1857  * line in buffer.  The return value is the address of the next line
1858  * based upon where curr_text is located.
1859  *
1860  */
1861 char *
1862 iscsi_get_next_text(char *data, int max_data_length, char *curr_text)
1863 {
1864 	char *curr_data;
1865 
1866 	ASSERT(data != NULL);
1867 
1868 	/* check if any data exists, if not return */
1869 	if (max_data_length == 0) {
1870 		return (NULL);
1871 	}
1872 
1873 	/* handle first call to this function */
1874 	if (curr_text == NULL) {
1875 		return (data);
1876 	}
1877 
1878 	/* move to next text string */
1879 	curr_data = curr_text;
1880 	while ((curr_data < (data + max_data_length)) && *curr_data) {
1881 		curr_data++;
1882 	}
1883 	curr_data++;		/* go past the NULL to the next entry */
1884 
1885 	/* check whether data end reached */
1886 	if (curr_data >= (data + max_data_length)) {
1887 		return (NULL);
1888 	}
1889 
1890 	return (curr_data);
1891 }
1892 
1893 
1894 /*
1895  * iscsi_find_key_value -
1896  *
1897  */
1898 static int
1899 iscsi_find_key_value(char *param, char *ihp, char *pdu_end,
1900     char **value_start, char **value_end)
1901 {
1902 	char *str = param;
1903 	char *text = ihp;
1904 	char *value = NULL;
1905 
1906 	if (value_start)
1907 		*value_start = NULL;
1908 	if (value_end)
1909 		*value_end = NULL;
1910 
1911 	/*
1912 	 * make sure they contain the same bytes
1913 	 */
1914 	while (*str) {
1915 		if (text >= pdu_end) {
1916 			return (0);
1917 		}
1918 		if (*text == '\0') {
1919 			return (0);
1920 		}
1921 		if (*str != *text) {
1922 			return (0);
1923 		}
1924 		str++;
1925 		text++;
1926 	}
1927 
1928 	if ((text >= pdu_end) ||
1929 	    (*text == '\0') ||
1930 	    (*text != ISCSI_TEXT_SEPARATOR)) {
1931 		return (0);
1932 	}
1933 
1934 	/*
1935 	 * find the value
1936 	 */
1937 	value = text + 1;
1938 
1939 	/*
1940 	 * find the end of the value
1941 	 */
1942 	while ((text < pdu_end) && (*text))
1943 		text++;
1944 
1945 	if (value_start)
1946 		*value_start = value;
1947 	if (value_end)
1948 		*value_end = text;
1949 
1950 	return (1);
1951 }
1952 
1953 
1954 /*
1955  * iscsi_update_address - This function is used on a login redirection.
1956  * During the login redirection we are asked to switch to an IP address
1957  * port different than the one we were logging into.
1958  */
1959 static iscsi_status_t
1960 iscsi_update_address(iscsi_conn_t *icp, char *in)
1961 {
1962 	char		*addr_str, *port_str, *tpgt_str;
1963 	int		type;
1964 	struct hostent	*hptr;
1965 	unsigned long	tmp;
1966 	int		error_num;
1967 	int		port;
1968 
1969 	ASSERT(icp != NULL);
1970 	ASSERT(in != NULL);
1971 
1972 	/* parse login redirection response */
1973 	if (parse_addr_port_tpgt(in, &addr_str, &type,
1974 	    &port_str, &tpgt_str) == B_FALSE) {
1975 		return (ISCSI_STATUS_PROTOCOL_ERROR);
1976 	}
1977 
1978 	/* convert addr_str */
1979 	hptr = kgetipnodebyname(addr_str, type, AI_ALL, &error_num);
1980 	if (!hptr) {
1981 		return (ISCSI_STATUS_PROTOCOL_ERROR);
1982 	}
1983 
1984 	/* convert port_str */
1985 	if (port_str != NULL) {
1986 		(void) ddi_strtoul(port_str, NULL, 0, &tmp);
1987 		port = (int)tmp;
1988 	} else {
1989 		port = ISCSI_LISTEN_PORT;
1990 	}
1991 
1992 	iscsid_addr_to_sockaddr(hptr->h_length, *hptr->h_addr_list,
1993 	    port, &icp->conn_curr_addr.sin);
1994 
1995 	kfreehostent(hptr);
1996 	return (ISCSI_STATUS_SUCCESS);
1997 }
1998 
1999 void
2000 iscsi_login_update_state(iscsi_conn_t *icp, iscsi_login_state_t next_state)
2001 {
2002 	mutex_enter(&icp->conn_login_mutex);
2003 	(void) iscsi_login_update_state_locked(icp, next_state);
2004 	mutex_exit(&icp->conn_login_mutex);
2005 }
2006 
2007 void
2008 iscsi_login_update_state_locked(iscsi_conn_t *icp,
2009     iscsi_login_state_t next_state)
2010 {
2011 	ASSERT(mutex_owned(&icp->conn_login_mutex));
2012 	next_state = (next_state > LOGIN_MAX) ? LOGIN_MAX : next_state;
2013 	idm_sm_audit_state_change(&icp->conn_state_audit,
2014 	    SAS_ISCSI_LOGIN, icp->conn_login_state, next_state);
2015 
2016 	ISCSI_LOGIN_LOG(CE_NOTE, "iscsi_login_update_state conn %p %d -> %d",
2017 	    (void *)icp, icp->conn_login_state, next_state);
2018 
2019 	icp->conn_login_state = next_state;
2020 	cv_broadcast(&icp->conn_login_cv);
2021 }
2022 
2023 
2024 
2025 /*
2026  * iscsi_null_callback - This callback may be used under certain
2027  * conditions when authenticating a target, but I'm not sure what
2028  * we need to do here.
2029  */
2030 /* ARGSUSED */
2031 static void
2032 iscsi_null_callback(void *user_handle, void *message_handle, int auth_status)
2033 {
2034 }
2035 
2036 
2037 /*
2038  * iscsi_login_failure_str -
2039  *
2040  */
2041 static char *
2042 iscsi_login_failure_str(uchar_t status_class, uchar_t status_detail)
2043 {
2044 	switch (status_class) {
2045 	case 0x00:
2046 		switch (status_detail) {
2047 		case 0x00:
2048 			return ("Login is proceeding okay.");
2049 		default:
2050 			break;
2051 		}
2052 	case 0x01:
2053 		switch (status_detail) {
2054 		case 0x01:
2055 			return ("Requested ITN has moved temporarily to "
2056 			    "the address provided.");
2057 		case 0x02:
2058 			return ("Requested ITN has moved permanently to "
2059 			    "the address provided.");
2060 		default:
2061 			break;
2062 		}
2063 	case 0x02:
2064 		switch (status_detail) {
2065 		case 0x00:
2066 			return ("Miscellaneous iSCSI initiator errors.");
2067 		case 0x01:
2068 			return ("Initiator could not be successfully "
2069 			    "authenticated.");
2070 		case 0x02:
2071 			return ("Initiator is not allowed access to the "
2072 			    "given target.");
2073 		case 0x03:
2074 			return ("Requested ITN does not exist at this "
2075 			    "address.");
2076 		case 0x04:
2077 			return ("Requested ITN has been removed and no "
2078 			    "forwarding address is provided.");
2079 		case 0x05:
2080 			return ("Requested iSCSI version range is not "
2081 			    "supported by the target.");
2082 		case 0x06:
2083 			return ("No more connections can be accepted on "
2084 			    "this Session ID (SSID).");
2085 		case 0x07:
2086 			return ("Missing parameters (e.g., iSCSI initiator "
2087 			    "and/or target name).");
2088 		case 0x08:
2089 			return ("Target does not support session spanning "
2090 			    "to this connection (address).");
2091 		case 0x09:
2092 			return ("Target does not support this type of "
2093 			    "session or not from this initiator.");
2094 		case 0x0A:
2095 			return ("Attempt to add a connection to a "
2096 			    "nonexistent session.");
2097 		case 0x0B:
2098 			return ("Invalid request type during login.");
2099 		default:
2100 			break;
2101 		}
2102 	case 0x03:
2103 		switch (status_detail) {
2104 		case 0x00:
2105 			return ("Target hardware or software error.");
2106 		case 0x01:
2107 			return ("iSCSI service or target is not currently "
2108 			    "operational.");
2109 		case 0x02:
2110 			return ("Target has insufficient session, connection "
2111 			    "or other resources.");
2112 		default:
2113 			break;
2114 		}
2115 	}
2116 	return ("Unknown login response received.");
2117 }
2118 
2119 
2120 /*
2121  * iscsi_login_connect -
2122  */
2123 static iscsi_status_t
2124 iscsi_login_connect(iscsi_conn_t *icp)
2125 {
2126 	iscsi_hba_t		*ihp;
2127 	iscsi_sess_t		*isp;
2128 	struct sockaddr		*addr;
2129 	idm_conn_req_t		cr;
2130 	idm_status_t		rval;
2131 	clock_t			lbolt;
2132 
2133 	ASSERT(icp != NULL);
2134 	isp = icp->conn_sess;
2135 	ASSERT(isp != NULL);
2136 	ihp = isp->sess_hba;
2137 	ASSERT(ihp != NULL);
2138 	addr = &icp->conn_curr_addr.sin;
2139 
2140 	/* Make sure that scope_id is zero if it is an IPv6 address */
2141 	if (addr->sa_family == AF_INET6) {
2142 		((struct sockaddr_in6 *)addr)->sin6_scope_id = 0;
2143 	}
2144 
2145 	/* delay the connect process if required */
2146 	lbolt = ddi_get_lbolt();
2147 	if (lbolt < icp->conn_login_min) {
2148 		if (icp->conn_login_max < icp->conn_login_min) {
2149 			delay(icp->conn_login_max - lbolt);
2150 		} else {
2151 			delay(icp->conn_login_min - lbolt);
2152 		}
2153 	}
2154 
2155 	/* Create IDM connection context */
2156 	cr.cr_domain = addr->sa_family;
2157 	cr.cr_type = SOCK_STREAM;
2158 	cr.cr_protocol = 0;
2159 	cr.cr_bound = icp->conn_bound;
2160 	cr.cr_li = icp->conn_sess->sess_hba->hba_li;
2161 	cr.icr_conn_ops.icb_rx_misc = &iscsi_rx_misc_pdu;
2162 	cr.icr_conn_ops.icb_rx_error = &iscsi_rx_error_pdu;
2163 	cr.icr_conn_ops.icb_rx_scsi_rsp = &iscsi_rx_scsi_rsp;
2164 	cr.icr_conn_ops.icb_client_notify = &iscsi_client_notify;
2165 	cr.icr_conn_ops.icb_build_hdr = &iscsi_build_hdr;
2166 	cr.icr_conn_ops.icb_task_aborted = &iscsi_task_aborted;
2167 	bcopy(addr, &cr.cr_ini_dst_addr,
2168 	    sizeof (cr.cr_ini_dst_addr));
2169 	bcopy(&icp->conn_bound_addr, &cr.cr_bound_addr,
2170 	    sizeof (cr.cr_bound_addr));
2171 	if (isp->sess_boot == B_TRUE) {
2172 		cr.cr_boot_conn = B_TRUE;
2173 	} else {
2174 		cr.cr_boot_conn = B_FALSE;
2175 	}
2176 
2177 	/*
2178 	 * Allocate IDM connection context
2179 	 */
2180 	rval = idm_ini_conn_create(&cr, &icp->conn_ic);
2181 	if (rval != IDM_STATUS_SUCCESS) {
2182 		return (ISCSI_STATUS_LOGIN_FAILED);
2183 	}
2184 
2185 	icp->conn_ic->ic_handle = icp;
2186 
2187 	/*
2188 	 * About to initiate connect, reset login state.
2189 	 */
2190 	iscsi_login_update_state(icp, LOGIN_START);
2191 
2192 	/*
2193 	 * Make sure the connection doesn't go away until we are done with it.
2194 	 * This hold will prevent us from receiving a CN_CONNECT_DESTROY
2195 	 * notification on this connection until we are ready.
2196 	 */
2197 	idm_conn_hold(icp->conn_ic);
2198 
2199 	/*
2200 	 * When iSCSI initiator to target IO timeout or connection failure
2201 	 * Connection retry is needed for normal operational session.
2202 	 */
2203 	if ((icp->conn_sess->sess_type == ISCSI_SESS_TYPE_NORMAL) &&
2204 	    ((icp->conn_state == ISCSI_CONN_STATE_FAILED) ||
2205 	    (icp->conn_state == ISCSI_CONN_STATE_POLLING))) {
2206 		icp->conn_ic->ic_conn_params.nonblock_socket = B_TRUE;
2207 		icp->conn_ic->ic_conn_params.conn_login_max =
2208 		    icp->conn_login_max;
2209 		if (icp->conn_state == ISCSI_CONN_STATE_POLLING) {
2210 			icp->conn_ic->ic_conn_params.conn_login_interval =
2211 			    icp->conn_tunable_params.polling_login_delay;
2212 		} else {
2213 			icp->conn_ic->ic_conn_params.conn_login_interval =
2214 			    ISCSI_LOGIN_RETRY_DELAY;
2215 		}
2216 
2217 	} else {
2218 		icp->conn_ic->ic_conn_params.nonblock_socket = B_FALSE;
2219 		icp->conn_ic->ic_conn_params.conn_login_max = 0;
2220 		icp->conn_ic->ic_conn_params.conn_login_interval = 0;
2221 	}
2222 	/*
2223 	 * Attempt connection.  Upon return we will either be ready to
2224 	 * login or disconnected.  If idm_ini_conn_connect fails we
2225 	 * will eventually receive a CN_CONNECT_DESTROY at which point
2226 	 * we will destroy the connection allocated above (so there
2227 	 * is no need to explicitly free it here).
2228 	 */
2229 	rval = idm_ini_conn_connect(icp->conn_ic);
2230 
2231 	if (rval != IDM_STATUS_SUCCESS) {
2232 		cmn_err(CE_NOTE, "iscsi connection(%u) unable to "
2233 		    "connect to target %s", icp->conn_oid,
2234 		    icp->conn_sess->sess_name);
2235 		idm_conn_rele(icp->conn_ic);
2236 	}
2237 
2238 	return (rval == IDM_STATUS_SUCCESS ?
2239 	    ISCSI_STATUS_SUCCESS : ISCSI_STATUS_INTERNAL_ERROR);
2240 }
2241 
2242 /*
2243  * iscsi_login_disconnect
2244  */
2245 static void
2246 iscsi_login_disconnect(iscsi_conn_t *icp)
2247 {
2248 	/* Tell IDM to disconnect is if we are not already disconnect */
2249 	idm_ini_conn_disconnect_sync(icp->conn_ic);
2250 
2251 	/*
2252 	 * The function above may return before the CN_CONNECT_LOST
2253 	 * notification.  Wait for it.
2254 	 */
2255 	mutex_enter(&icp->conn_state_mutex);
2256 	while (icp->conn_state_idm_connected)
2257 		cv_wait(&icp->conn_state_change,
2258 		    &icp->conn_state_mutex);
2259 	mutex_exit(&icp->conn_state_mutex);
2260 }
2261 
2262 /*
2263  * iscsi_notice_key_values - Create an nvlist containing the values
2264  * that have been negotiated for this connection and pass them down to
2265  * IDM so it can pick up any values that are important.
2266  */
2267 static void
2268 iscsi_notice_key_values(iscsi_conn_t *icp)
2269 {
2270 	nvlist_t	*neg_nvl;
2271 	int		rc;
2272 
2273 	rc = nvlist_alloc(&neg_nvl, NV_UNIQUE_NAME, KM_SLEEP);
2274 	ASSERT(rc == 0);
2275 
2276 	/* Only crc32c is supported so the digest logic is simple */
2277 	if (icp->conn_params.header_digest) {
2278 		rc = nvlist_add_string(neg_nvl, "HeaderDigest", "crc32c");
2279 	} else {
2280 		rc = nvlist_add_string(neg_nvl, "HeaderDigest", "none");
2281 	}
2282 	ASSERT(rc == 0);
2283 
2284 	if (icp->conn_params.data_digest) {
2285 		rc = nvlist_add_string(neg_nvl, "DataDigest", "crc32c");
2286 	} else {
2287 		rc = nvlist_add_string(neg_nvl, "DataDigest", "none");
2288 	}
2289 	ASSERT(rc == 0);
2290 
2291 	rc = nvlist_add_uint64(neg_nvl, "MaxRecvDataSegmentLength",
2292 	    (uint64_t)icp->conn_params.max_recv_data_seg_len);
2293 	ASSERT(rc == 0);
2294 
2295 	rc = nvlist_add_uint64(neg_nvl, "MaxBurstLength",
2296 	    (uint64_t)icp->conn_params.max_burst_length);
2297 	ASSERT(rc == 0);
2298 
2299 	rc = nvlist_add_uint64(neg_nvl, "MaxOutstandingR2T",
2300 	    (uint64_t)icp->conn_params.max_outstanding_r2t);
2301 	ASSERT(rc == 0);
2302 
2303 	rc = nvlist_add_uint64(neg_nvl, "ErrorRecoveryLevel",
2304 	    (uint64_t)icp->conn_params.error_recovery_level);
2305 	ASSERT(rc == 0);
2306 
2307 	rc = nvlist_add_uint64(neg_nvl, "DefaultTime2Wait",
2308 	    (uint64_t)icp->conn_params.default_time_to_wait);
2309 	ASSERT(rc == 0);
2310 
2311 	rc = nvlist_add_uint64(neg_nvl, "DefaultTime2Retain",
2312 	    (uint64_t)icp->conn_params.default_time_to_retain);
2313 	ASSERT(rc == 0);
2314 
2315 	/* Pass the list to IDM to examine, then free it */
2316 	idm_notice_key_values(icp->conn_ic, neg_nvl);
2317 	nvlist_free(neg_nvl);
2318 }
2319