17836SJohn.Forte@Sun.COM /*
27836SJohn.Forte@Sun.COM * CDDL HEADER START
37836SJohn.Forte@Sun.COM *
47836SJohn.Forte@Sun.COM * The contents of this file are subject to the terms of the
57836SJohn.Forte@Sun.COM * Common Development and Distribution License (the "License").
67836SJohn.Forte@Sun.COM * You may not use this file except in compliance with the License.
77836SJohn.Forte@Sun.COM *
87836SJohn.Forte@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97836SJohn.Forte@Sun.COM * or http://www.opensolaris.org/os/licensing.
107836SJohn.Forte@Sun.COM * See the License for the specific language governing permissions
117836SJohn.Forte@Sun.COM * and limitations under the License.
127836SJohn.Forte@Sun.COM *
137836SJohn.Forte@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
147836SJohn.Forte@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157836SJohn.Forte@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
167836SJohn.Forte@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
177836SJohn.Forte@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
187836SJohn.Forte@Sun.COM *
197836SJohn.Forte@Sun.COM * CDDL HEADER END
207836SJohn.Forte@Sun.COM */
217836SJohn.Forte@Sun.COM /*
227836SJohn.Forte@Sun.COM * Copyright 2000 by Cisco Systems, Inc. All rights reserved.
2312161SJack.Meng@Sun.COM * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
247836SJohn.Forte@Sun.COM *
257836SJohn.Forte@Sun.COM * iSCSI protocol login and enumeration
267836SJohn.Forte@Sun.COM */
277836SJohn.Forte@Sun.COM
287836SJohn.Forte@Sun.COM #include "iscsi.h"
298656SPeter.Dunlap@Sun.COM #include <sys/iscsi_protocol.h>
307836SJohn.Forte@Sun.COM #include <sys/scsi/adapters/iscsi_door.h>
317836SJohn.Forte@Sun.COM
329162SPeter.Dunlap@Sun.COM boolean_t iscsi_login_logging = B_FALSE;
339162SPeter.Dunlap@Sun.COM
347836SJohn.Forte@Sun.COM /* internal login protocol interfaces */
357836SJohn.Forte@Sun.COM static iscsi_status_t iscsi_login(iscsi_conn_t *icp,
369162SPeter.Dunlap@Sun.COM uint8_t *status_class, uint8_t *status_detail);
379162SPeter.Dunlap@Sun.COM static int iscsi_add_text(idm_pdu_t *text_pdu,
387836SJohn.Forte@Sun.COM int max_data_length, char *param, char *value);
397836SJohn.Forte@Sun.COM static int iscsi_find_key_value(char *param, char *ihp, char *pdu_end,
407836SJohn.Forte@Sun.COM char **value_start, char **value_end);
417836SJohn.Forte@Sun.COM static void iscsi_null_callback(void *user_handle, void *message_handle,
427836SJohn.Forte@Sun.COM int auth_status);
437836SJohn.Forte@Sun.COM static iscsi_status_t iscsi_process_login_response(iscsi_conn_t *icp,
447836SJohn.Forte@Sun.COM iscsi_login_rsp_hdr_t *ilrhp, char *data, int max_data_length);
457836SJohn.Forte@Sun.COM static iscsi_status_t iscsi_make_login_pdu(iscsi_conn_t *icp,
469162SPeter.Dunlap@Sun.COM idm_pdu_t *text_pdu, char *data, int max_data_length);
477836SJohn.Forte@Sun.COM static iscsi_status_t iscsi_update_address(iscsi_conn_t *icp,
487836SJohn.Forte@Sun.COM char *address);
497836SJohn.Forte@Sun.COM static char *iscsi_login_failure_str(uchar_t status_class,
507836SJohn.Forte@Sun.COM uchar_t status_detail);
517836SJohn.Forte@Sun.COM static void iscsi_login_end(iscsi_conn_t *icp,
529162SPeter.Dunlap@Sun.COM iscsi_status_t status, iscsi_task_t *itp);
537836SJohn.Forte@Sun.COM static iscsi_status_t iscsi_login_connect(iscsi_conn_t *icp);
549162SPeter.Dunlap@Sun.COM static void iscsi_login_disconnect(iscsi_conn_t *icp);
559162SPeter.Dunlap@Sun.COM static void iscsi_notice_key_values(iscsi_conn_t *icp);
567836SJohn.Forte@Sun.COM
577836SJohn.Forte@Sun.COM #define ISCSI_LOGIN_RETRY_DELAY 5 /* seconds */
587836SJohn.Forte@Sun.COM
5910317SZhang.Yi@Sun.COM #define ISCSI_LOGIN_TRANSIT_FFP(flags) \
6010317SZhang.Yi@Sun.COM (!(flags & ISCSI_FLAG_LOGIN_CONTINUE) && \
6110317SZhang.Yi@Sun.COM (flags & ISCSI_FLAG_LOGIN_TRANSIT) && \
6210317SZhang.Yi@Sun.COM (ISCSI_LOGIN_CURRENT_STAGE(flags) == \
6310317SZhang.Yi@Sun.COM ISCSI_OP_PARMS_NEGOTIATION_STAGE) && \
6410317SZhang.Yi@Sun.COM (ISCSI_LOGIN_NEXT_STAGE(flags) == \
6510317SZhang.Yi@Sun.COM ISCSI_FULL_FEATURE_PHASE))
6610317SZhang.Yi@Sun.COM
677836SJohn.Forte@Sun.COM /*
687836SJohn.Forte@Sun.COM * +--------------------------------------------------------------------+
697836SJohn.Forte@Sun.COM * | External Login Interface |
707836SJohn.Forte@Sun.COM * +--------------------------------------------------------------------+
717836SJohn.Forte@Sun.COM */
727836SJohn.Forte@Sun.COM
737836SJohn.Forte@Sun.COM /*
747836SJohn.Forte@Sun.COM * iscsi_login_start - connect and perform iscsi protocol login
757836SJohn.Forte@Sun.COM */
767836SJohn.Forte@Sun.COM iscsi_status_t
iscsi_login_start(void * arg)777836SJohn.Forte@Sun.COM iscsi_login_start(void *arg)
787836SJohn.Forte@Sun.COM {
797836SJohn.Forte@Sun.COM iscsi_task_t *itp = (iscsi_task_t *)arg;
807836SJohn.Forte@Sun.COM iscsi_status_t rval = ISCSI_STATUS_LOGIN_FAILED;
817836SJohn.Forte@Sun.COM iscsi_conn_t *icp;
827836SJohn.Forte@Sun.COM iscsi_sess_t *isp;
837836SJohn.Forte@Sun.COM iscsi_hba_t *ihp;
847836SJohn.Forte@Sun.COM unsigned char status_class;
857836SJohn.Forte@Sun.COM unsigned char status_detail;
867836SJohn.Forte@Sun.COM
877836SJohn.Forte@Sun.COM ASSERT(itp != NULL);
887836SJohn.Forte@Sun.COM icp = (iscsi_conn_t *)itp->t_arg;
897836SJohn.Forte@Sun.COM ASSERT(icp != NULL);
907836SJohn.Forte@Sun.COM isp = icp->conn_sess;
917836SJohn.Forte@Sun.COM ASSERT(isp != NULL);
927836SJohn.Forte@Sun.COM ihp = isp->sess_hba;
937836SJohn.Forte@Sun.COM ASSERT(ihp != NULL);
947836SJohn.Forte@Sun.COM
957836SJohn.Forte@Sun.COM login_start:
969162SPeter.Dunlap@Sun.COM ASSERT((icp->conn_state == ISCSI_CONN_STATE_IN_LOGIN) ||
979162SPeter.Dunlap@Sun.COM (icp->conn_state == ISCSI_CONN_STATE_FAILED) ||
989162SPeter.Dunlap@Sun.COM (icp->conn_state == ISCSI_CONN_STATE_POLLING));
999162SPeter.Dunlap@Sun.COM
1009162SPeter.Dunlap@Sun.COM icp->conn_state_ffp = B_FALSE;
10112001SZhang.Yi@Sun.COM icp->conn_login_status = ISCSI_INITIAL_LOGIN_STAGE;
1029162SPeter.Dunlap@Sun.COM
1037836SJohn.Forte@Sun.COM /* reset connection statsn */
1047836SJohn.Forte@Sun.COM icp->conn_expstatsn = 0;
1057836SJohn.Forte@Sun.COM icp->conn_laststatsn = 0;
1067836SJohn.Forte@Sun.COM
1077836SJohn.Forte@Sun.COM /* sync up authentication information */
1087836SJohn.Forte@Sun.COM (void) iscsi_sess_set_auth(isp);
1097836SJohn.Forte@Sun.COM
1107836SJohn.Forte@Sun.COM /* sync up login and session parameters */
1117836SJohn.Forte@Sun.COM if (!ISCSI_SUCCESS(iscsi_conn_sync_params(icp))) {
1127836SJohn.Forte@Sun.COM /* unable to sync params. fail connection attempts */
1139162SPeter.Dunlap@Sun.COM iscsi_login_end(icp, ISCSI_STATUS_LOGIN_FAILED, itp);
1147836SJohn.Forte@Sun.COM return (ISCSI_STATUS_LOGIN_FAILED);
1157836SJohn.Forte@Sun.COM }
1167836SJohn.Forte@Sun.COM
1179162SPeter.Dunlap@Sun.COM /*
1189162SPeter.Dunlap@Sun.COM * Attempt to open TCP connection, associated IDM connection will
1199162SPeter.Dunlap@Sun.COM * have a hold on it that must be released after the call to
1209162SPeter.Dunlap@Sun.COM * iscsi_login() below.
1219162SPeter.Dunlap@Sun.COM */
1227836SJohn.Forte@Sun.COM if (!ISCSI_SUCCESS(iscsi_login_connect(icp))) {
12311424SJack.Meng@Sun.COM if ((isp->sess_boot == B_TRUE) &&
12411424SJack.Meng@Sun.COM (ihp->hba_service_status_overwrite == B_TRUE) &&
12511424SJack.Meng@Sun.COM (isp->sess_boot_nic_reset == B_FALSE)) {
12611424SJack.Meng@Sun.COM /*
12711424SJack.Meng@Sun.COM * The connection to boot target failed
12811424SJack.Meng@Sun.COM * before the system fully started.
12911424SJack.Meng@Sun.COM * Reset the boot nic to the settings from
13011424SJack.Meng@Sun.COM * firmware before retrying the connect to
13111424SJack.Meng@Sun.COM * save the the system.
13211424SJack.Meng@Sun.COM */
13311424SJack.Meng@Sun.COM if (iscsi_net_interface(B_TRUE) ==
13411424SJack.Meng@Sun.COM ISCSI_STATUS_SUCCESS) {
13511424SJack.Meng@Sun.COM isp->sess_boot_nic_reset = B_TRUE;
13611424SJack.Meng@Sun.COM }
13711424SJack.Meng@Sun.COM }
1387836SJohn.Forte@Sun.COM /* retry this failure */
1397836SJohn.Forte@Sun.COM goto login_retry;
1407836SJohn.Forte@Sun.COM }
1417836SJohn.Forte@Sun.COM
1427836SJohn.Forte@Sun.COM /*
1437836SJohn.Forte@Sun.COM * allocate response buffer with based on default max
1447836SJohn.Forte@Sun.COM * transfer size. This size might shift during login.
1457836SJohn.Forte@Sun.COM */
1469162SPeter.Dunlap@Sun.COM icp->conn_login_max_data_length =
1479162SPeter.Dunlap@Sun.COM icp->conn_params.max_xmit_data_seg_len;
1489162SPeter.Dunlap@Sun.COM icp->conn_login_data = kmem_zalloc(icp->conn_login_max_data_length,
1499162SPeter.Dunlap@Sun.COM KM_SLEEP);
1507836SJohn.Forte@Sun.COM
1519162SPeter.Dunlap@Sun.COM /*
1529162SPeter.Dunlap@Sun.COM * Start protocol login, upon return we will be either logged in
1539162SPeter.Dunlap@Sun.COM * or disconnected
1549162SPeter.Dunlap@Sun.COM */
1559162SPeter.Dunlap@Sun.COM rval = iscsi_login(icp, &status_class, &status_detail);
1567836SJohn.Forte@Sun.COM
1577836SJohn.Forte@Sun.COM /* done with buffer */
1589162SPeter.Dunlap@Sun.COM kmem_free(icp->conn_login_data, icp->conn_login_max_data_length);
1599162SPeter.Dunlap@Sun.COM
1609162SPeter.Dunlap@Sun.COM /* Release connection hold */
1619162SPeter.Dunlap@Sun.COM idm_conn_rele(icp->conn_ic);
1627836SJohn.Forte@Sun.COM
1637836SJohn.Forte@Sun.COM /* hard failure in login */
1647836SJohn.Forte@Sun.COM if (!ISCSI_SUCCESS(rval)) {
1657836SJohn.Forte@Sun.COM /*
1667836SJohn.Forte@Sun.COM * We should just give up retry if these failures are
1677836SJohn.Forte@Sun.COM * detected.
1687836SJohn.Forte@Sun.COM */
1697836SJohn.Forte@Sun.COM switch (rval) {
1707836SJohn.Forte@Sun.COM /*
1717836SJohn.Forte@Sun.COM * We should just give up retry if these
1727836SJohn.Forte@Sun.COM * failures are detected.
1737836SJohn.Forte@Sun.COM */
1747836SJohn.Forte@Sun.COM case ISCSI_STATUS_AUTHENTICATION_FAILED:
1757836SJohn.Forte@Sun.COM case ISCSI_STATUS_INTERNAL_ERROR:
1767836SJohn.Forte@Sun.COM case ISCSI_STATUS_VERSION_MISMATCH:
1777836SJohn.Forte@Sun.COM case ISCSI_STATUS_NEGO_FAIL:
17812001SZhang.Yi@Sun.COM case ISCSI_STATUS_LOGIN_TPGT_NEGO_FAIL:
1797836SJohn.Forte@Sun.COM /* we don't want to retry this failure */
1809162SPeter.Dunlap@Sun.COM iscsi_login_end(icp, ISCSI_STATUS_LOGIN_FAILED, itp);
1817836SJohn.Forte@Sun.COM return (ISCSI_STATUS_LOGIN_FAILED);
1827836SJohn.Forte@Sun.COM default:
1837836SJohn.Forte@Sun.COM /* retry this failure */
1847836SJohn.Forte@Sun.COM goto login_retry;
1857836SJohn.Forte@Sun.COM }
1867836SJohn.Forte@Sun.COM }
1877836SJohn.Forte@Sun.COM
1887836SJohn.Forte@Sun.COM /* soft failure with reason */
1897836SJohn.Forte@Sun.COM switch (status_class) {
1907836SJohn.Forte@Sun.COM case ISCSI_STATUS_CLASS_SUCCESS:
1917836SJohn.Forte@Sun.COM /* login was successful */
1929162SPeter.Dunlap@Sun.COM iscsi_login_end(icp, ISCSI_STATUS_SUCCESS, itp);
1937836SJohn.Forte@Sun.COM return (ISCSI_STATUS_SUCCESS);
1947836SJohn.Forte@Sun.COM case ISCSI_STATUS_CLASS_REDIRECT:
1957836SJohn.Forte@Sun.COM /* Retry at the redirected address */
1967836SJohn.Forte@Sun.COM goto login_start;
1977836SJohn.Forte@Sun.COM case ISCSI_STATUS_CLASS_TARGET_ERR:
1987836SJohn.Forte@Sun.COM /* retry this failure */
1997836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
2007836SJohn.Forte@Sun.COM "%s (0x%02x/0x%02x)", icp->conn_oid,
2017836SJohn.Forte@Sun.COM iscsi_login_failure_str(status_class, status_detail),
2027836SJohn.Forte@Sun.COM status_class, status_detail);
2037836SJohn.Forte@Sun.COM goto login_retry;
2047836SJohn.Forte@Sun.COM case ISCSI_STATUS_CLASS_INITIATOR_ERR:
2057836SJohn.Forte@Sun.COM default:
2067836SJohn.Forte@Sun.COM /* All other errors are hard failures */
2077836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
2088265SBing.Zhao@Sun.COM "%s (0x%02x/0x%02x) Target: %s, TPGT: %d",
2098265SBing.Zhao@Sun.COM icp->conn_oid,
2107836SJohn.Forte@Sun.COM iscsi_login_failure_str(status_class, status_detail),
2118265SBing.Zhao@Sun.COM status_class, status_detail, isp->sess_name,
2128265SBing.Zhao@Sun.COM isp->sess_tpgt_conf);
2137836SJohn.Forte@Sun.COM
2147836SJohn.Forte@Sun.COM /* we don't want to retry this failure */
2159162SPeter.Dunlap@Sun.COM iscsi_login_end(icp, ISCSI_STATUS_LOGIN_FAILED, itp);
2167836SJohn.Forte@Sun.COM break;
2177836SJohn.Forte@Sun.COM }
2189162SPeter.Dunlap@Sun.COM
2197836SJohn.Forte@Sun.COM return (ISCSI_STATUS_LOGIN_FAILED);
2207836SJohn.Forte@Sun.COM
2217836SJohn.Forte@Sun.COM login_retry:
2227836SJohn.Forte@Sun.COM /* retry this failure if we haven't run out of time */
2237836SJohn.Forte@Sun.COM if (icp->conn_login_max > ddi_get_lbolt()) {
2247836SJohn.Forte@Sun.COM
2257836SJohn.Forte@Sun.COM if (icp->conn_state == ISCSI_CONN_STATE_POLLING) {
2267836SJohn.Forte@Sun.COM icp->conn_login_min = ddi_get_lbolt() +
22710156SZhang.Yi@Sun.COM SEC_TO_TICK(icp->conn_tunable_params.
22810156SZhang.Yi@Sun.COM polling_login_delay);
2297836SJohn.Forte@Sun.COM } else {
2307836SJohn.Forte@Sun.COM icp->conn_login_min = ddi_get_lbolt() +
2317836SJohn.Forte@Sun.COM SEC_TO_TICK(ISCSI_LOGIN_RETRY_DELAY);
2327836SJohn.Forte@Sun.COM }
2337836SJohn.Forte@Sun.COM
2347836SJohn.Forte@Sun.COM if (itp->t_blocking == B_TRUE) {
2357836SJohn.Forte@Sun.COM goto login_start;
2367836SJohn.Forte@Sun.COM } else {
23712161SJack.Meng@Sun.COM if (ddi_taskq_dispatch(isp->sess_login_taskq,
2387836SJohn.Forte@Sun.COM (void(*)())iscsi_login_start, itp, DDI_SLEEP) !=
2397836SJohn.Forte@Sun.COM DDI_SUCCESS) {
2407836SJohn.Forte@Sun.COM iscsi_login_end(icp,
2419162SPeter.Dunlap@Sun.COM ISCSI_STATUS_LOGIN_TIMED_OUT, itp);
2427836SJohn.Forte@Sun.COM }
2437836SJohn.Forte@Sun.COM return (ISCSI_STATUS_SUCCESS);
2447836SJohn.Forte@Sun.COM }
2457836SJohn.Forte@Sun.COM } else {
2467836SJohn.Forte@Sun.COM /* Retries exceeded */
2479162SPeter.Dunlap@Sun.COM iscsi_login_end(icp, ISCSI_STATUS_LOGIN_TIMED_OUT, itp);
2487836SJohn.Forte@Sun.COM }
2499162SPeter.Dunlap@Sun.COM
2507836SJohn.Forte@Sun.COM return (ISCSI_STATUS_LOGIN_FAILED);
2517836SJohn.Forte@Sun.COM }
2527836SJohn.Forte@Sun.COM
2537836SJohn.Forte@Sun.COM static void
iscsi_login_end(iscsi_conn_t * icp,iscsi_status_t status,iscsi_task_t * itp)2549162SPeter.Dunlap@Sun.COM iscsi_login_end(iscsi_conn_t *icp, iscsi_status_t status, iscsi_task_t *itp)
2557836SJohn.Forte@Sun.COM {
2567836SJohn.Forte@Sun.COM iscsi_sess_t *isp;
25712161SJack.Meng@Sun.COM uint32_t event_count;
2587836SJohn.Forte@Sun.COM
2597836SJohn.Forte@Sun.COM ASSERT(icp != NULL);
2607836SJohn.Forte@Sun.COM isp = icp->conn_sess;
2617836SJohn.Forte@Sun.COM ASSERT(isp != NULL);
2627836SJohn.Forte@Sun.COM
2639162SPeter.Dunlap@Sun.COM if (status == ISCSI_STATUS_SUCCESS) {
2649162SPeter.Dunlap@Sun.COM /* Inform IDM of the relevant negotiated values */
2659162SPeter.Dunlap@Sun.COM iscsi_notice_key_values(icp);
2669162SPeter.Dunlap@Sun.COM
2679162SPeter.Dunlap@Sun.COM /* We are now logged in */
2689162SPeter.Dunlap@Sun.COM iscsi_conn_update_state(icp, ISCSI_CONN_STATE_LOGGED_IN);
2699162SPeter.Dunlap@Sun.COM
2709162SPeter.Dunlap@Sun.COM /* startup TX thread */
2719162SPeter.Dunlap@Sun.COM (void) iscsi_thread_start(icp->conn_tx_thread);
2729162SPeter.Dunlap@Sun.COM
2739162SPeter.Dunlap@Sun.COM /*
2749162SPeter.Dunlap@Sun.COM * Move login state machine to LOGIN_FFP. This will
2759162SPeter.Dunlap@Sun.COM * release the taskq thread handling the CN_FFP_ENABLED
2769162SPeter.Dunlap@Sun.COM * allowing the IDM connection state machine to resume
2779162SPeter.Dunlap@Sun.COM * processing events
2789162SPeter.Dunlap@Sun.COM */
2799162SPeter.Dunlap@Sun.COM iscsi_login_update_state(icp, LOGIN_FFP);
2809162SPeter.Dunlap@Sun.COM
2819162SPeter.Dunlap@Sun.COM /* Notify the session that a connection is logged in */
28212161SJack.Meng@Sun.COM event_count = atomic_inc_32_nv(&isp->sess_state_event_count);
28312161SJack.Meng@Sun.COM iscsi_sess_enter_state_zone(isp);
28412161SJack.Meng@Sun.COM iscsi_sess_state_machine(isp, ISCSI_SESS_EVENT_N1, event_count);
28512161SJack.Meng@Sun.COM iscsi_sess_exit_state_zone(isp);
2869162SPeter.Dunlap@Sun.COM } else {
2879162SPeter.Dunlap@Sun.COM /* If login failed reset nego tpgt */
2889162SPeter.Dunlap@Sun.COM isp->sess_tpgt_nego = ISCSI_DEFAULT_TPGT;
2897836SJohn.Forte@Sun.COM
2909162SPeter.Dunlap@Sun.COM mutex_enter(&icp->conn_state_mutex);
2919162SPeter.Dunlap@Sun.COM switch (icp->conn_state) {
2929162SPeter.Dunlap@Sun.COM case ISCSI_CONN_STATE_IN_LOGIN:
2939162SPeter.Dunlap@Sun.COM iscsi_conn_update_state_locked(icp,
2949162SPeter.Dunlap@Sun.COM ISCSI_CONN_STATE_FREE);
2959162SPeter.Dunlap@Sun.COM mutex_exit(&icp->conn_state_mutex);
2969162SPeter.Dunlap@Sun.COM break;
2979162SPeter.Dunlap@Sun.COM case ISCSI_CONN_STATE_FAILED:
2989162SPeter.Dunlap@Sun.COM if (status == ISCSI_STATUS_LOGIN_FAILED) {
2999162SPeter.Dunlap@Sun.COM iscsi_conn_update_state_locked(icp,
3009162SPeter.Dunlap@Sun.COM ISCSI_CONN_STATE_FREE);
3019162SPeter.Dunlap@Sun.COM } else {
3029162SPeter.Dunlap@Sun.COM /* ISCSI_STATUS_LOGIN_TIMED_OUT */
3039162SPeter.Dunlap@Sun.COM iscsi_conn_update_state_locked(icp,
3049162SPeter.Dunlap@Sun.COM ISCSI_CONN_STATE_POLLING);
3059162SPeter.Dunlap@Sun.COM }
3069162SPeter.Dunlap@Sun.COM mutex_exit(&icp->conn_state_mutex);
30712161SJack.Meng@Sun.COM event_count = atomic_inc_32_nv(
30812161SJack.Meng@Sun.COM &isp->sess_state_event_count);
30912161SJack.Meng@Sun.COM iscsi_sess_enter_state_zone(isp);
31012161SJack.Meng@Sun.COM iscsi_sess_state_machine(isp, ISCSI_SESS_EVENT_N6,
31112161SJack.Meng@Sun.COM event_count);
31212161SJack.Meng@Sun.COM iscsi_sess_exit_state_zone(isp);
3139162SPeter.Dunlap@Sun.COM
3149162SPeter.Dunlap@Sun.COM if (status == ISCSI_STATUS_LOGIN_TIMED_OUT) {
3159162SPeter.Dunlap@Sun.COM iscsi_conn_retry(isp, icp);
3169162SPeter.Dunlap@Sun.COM }
3179162SPeter.Dunlap@Sun.COM break;
3189162SPeter.Dunlap@Sun.COM case ISCSI_CONN_STATE_POLLING:
3199162SPeter.Dunlap@Sun.COM if (status == ISCSI_STATUS_LOGIN_FAILED) {
3209162SPeter.Dunlap@Sun.COM iscsi_conn_update_state_locked(icp,
3219162SPeter.Dunlap@Sun.COM ISCSI_CONN_STATE_FREE);
3229162SPeter.Dunlap@Sun.COM mutex_exit(&icp->conn_state_mutex);
32312161SJack.Meng@Sun.COM event_count = atomic_inc_32_nv(
32412161SJack.Meng@Sun.COM &isp->sess_state_event_count);
32512161SJack.Meng@Sun.COM iscsi_sess_enter_state_zone(isp);
3269162SPeter.Dunlap@Sun.COM
3279162SPeter.Dunlap@Sun.COM iscsi_sess_state_machine(isp,
32812161SJack.Meng@Sun.COM ISCSI_SESS_EVENT_N6, event_count);
32912161SJack.Meng@Sun.COM
33012161SJack.Meng@Sun.COM iscsi_sess_exit_state_zone(isp);
3319162SPeter.Dunlap@Sun.COM } else {
3329162SPeter.Dunlap@Sun.COM /* ISCSI_STATUS_LOGIN_TIMED_OUT */
3339162SPeter.Dunlap@Sun.COM if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
3349162SPeter.Dunlap@Sun.COM mutex_exit(&icp->conn_state_mutex);
3359162SPeter.Dunlap@Sun.COM
3369162SPeter.Dunlap@Sun.COM iscsi_conn_retry(isp, icp);
3379162SPeter.Dunlap@Sun.COM } else {
3389162SPeter.Dunlap@Sun.COM iscsi_conn_update_state_locked(icp,
3399162SPeter.Dunlap@Sun.COM ISCSI_CONN_STATE_FREE);
3409162SPeter.Dunlap@Sun.COM mutex_exit(&icp->conn_state_mutex);
3419162SPeter.Dunlap@Sun.COM }
3429162SPeter.Dunlap@Sun.COM }
3439162SPeter.Dunlap@Sun.COM break;
34410317SZhang.Yi@Sun.COM case ISCSI_CONN_STATE_FREE:
34510317SZhang.Yi@Sun.COM mutex_exit(&icp->conn_state_mutex);
34610317SZhang.Yi@Sun.COM break;
3479162SPeter.Dunlap@Sun.COM default:
34810317SZhang.Yi@Sun.COM mutex_exit(&icp->conn_state_mutex);
3499162SPeter.Dunlap@Sun.COM ASSERT(0);
3509162SPeter.Dunlap@Sun.COM break;
3519162SPeter.Dunlap@Sun.COM }
3527836SJohn.Forte@Sun.COM }
3537836SJohn.Forte@Sun.COM
3547836SJohn.Forte@Sun.COM if (itp->t_blocking == B_FALSE) {
3557836SJohn.Forte@Sun.COM kmem_free(itp, sizeof (iscsi_task_t));
3567836SJohn.Forte@Sun.COM }
35711424SJack.Meng@Sun.COM
35811424SJack.Meng@Sun.COM isp->sess_boot_nic_reset = B_FALSE;
3597836SJohn.Forte@Sun.COM }
3607836SJohn.Forte@Sun.COM
3617836SJohn.Forte@Sun.COM /*
3627836SJohn.Forte@Sun.COM * +--------------------------------------------------------------------+
3637836SJohn.Forte@Sun.COM * | Begin of protocol login routines |
3647836SJohn.Forte@Sun.COM * +--------------------------------------------------------------------+
3657836SJohn.Forte@Sun.COM */
3667836SJohn.Forte@Sun.COM
3677836SJohn.Forte@Sun.COM /*
3687836SJohn.Forte@Sun.COM * iscsi_login - Attempt to login to the target. The caller
3697836SJohn.Forte@Sun.COM * must check the status class to determine if the login succeeded.
3707836SJohn.Forte@Sun.COM * A return of 1 does not mean the login succeeded, it just means
3717836SJohn.Forte@Sun.COM * this function worked, and the status class is valid info. This
3727836SJohn.Forte@Sun.COM * allows the caller to decide whether or not to retry logins, so
3737836SJohn.Forte@Sun.COM * that we don't have any policy logic here.
3747836SJohn.Forte@Sun.COM */
3759162SPeter.Dunlap@Sun.COM iscsi_status_t
iscsi_login(iscsi_conn_t * icp,uint8_t * status_class,uint8_t * status_detail)3769162SPeter.Dunlap@Sun.COM iscsi_login(iscsi_conn_t *icp, uint8_t *status_class, uint8_t *status_detail)
3777836SJohn.Forte@Sun.COM {
3787836SJohn.Forte@Sun.COM iscsi_status_t rval = ISCSI_STATUS_INTERNAL_ERROR;
3797836SJohn.Forte@Sun.COM struct iscsi_sess *isp = NULL;
3807836SJohn.Forte@Sun.COM IscsiAuthClient *auth_client = NULL;
3817836SJohn.Forte@Sun.COM int max_data_length = 0;
3827836SJohn.Forte@Sun.COM char *data = NULL;
3839162SPeter.Dunlap@Sun.COM idm_pdu_t *text_pdu;
3849162SPeter.Dunlap@Sun.COM char *buffer;
3859162SPeter.Dunlap@Sun.COM size_t bufsize;
3869162SPeter.Dunlap@Sun.COM iscsi_login_rsp_hdr_t *ilrhp;
3879162SPeter.Dunlap@Sun.COM clock_t response_timeout, timeout_result;
3889162SPeter.Dunlap@Sun.COM
3899162SPeter.Dunlap@Sun.COM buffer = icp->conn_login_data;
3909162SPeter.Dunlap@Sun.COM bufsize = icp->conn_login_max_data_length;
3917836SJohn.Forte@Sun.COM
3927836SJohn.Forte@Sun.COM ASSERT(icp != NULL);
3937836SJohn.Forte@Sun.COM ASSERT(buffer != NULL);
3947836SJohn.Forte@Sun.COM ASSERT(status_class != NULL);
3957836SJohn.Forte@Sun.COM ASSERT(status_detail != NULL);
3967836SJohn.Forte@Sun.COM isp = icp->conn_sess;
3977836SJohn.Forte@Sun.COM ASSERT(isp != NULL);
3987836SJohn.Forte@Sun.COM
3997836SJohn.Forte@Sun.COM /*
4009162SPeter.Dunlap@Sun.COM * prepare the connection, hold IDM connection until login completes
4017836SJohn.Forte@Sun.COM */
4027836SJohn.Forte@Sun.COM icp->conn_current_stage = ISCSI_INITIAL_LOGIN_STAGE;
4037836SJohn.Forte@Sun.COM icp->conn_partial_response = 0;
4047836SJohn.Forte@Sun.COM
4057836SJohn.Forte@Sun.COM if (isp->sess_auth.auth_buffers &&
4067836SJohn.Forte@Sun.COM isp->sess_auth.num_auth_buffers) {
4077836SJohn.Forte@Sun.COM
4087836SJohn.Forte@Sun.COM auth_client = (IscsiAuthClient *)isp->
4097836SJohn.Forte@Sun.COM sess_auth.auth_buffers[0].address;
4107836SJohn.Forte@Sun.COM
4117836SJohn.Forte@Sun.COM /*
4127836SJohn.Forte@Sun.COM * prepare for authentication
4137836SJohn.Forte@Sun.COM */
4147836SJohn.Forte@Sun.COM if (iscsiAuthClientInit(iscsiAuthNodeTypeInitiator,
4157836SJohn.Forte@Sun.COM isp->sess_auth.num_auth_buffers,
4167836SJohn.Forte@Sun.COM isp->sess_auth.auth_buffers) !=
4177836SJohn.Forte@Sun.COM iscsiAuthStatusNoError) {
4187836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
4197836SJohn.Forte@Sun.COM "unable to initialize authentication",
4207836SJohn.Forte@Sun.COM icp->conn_oid);
42112001SZhang.Yi@Sun.COM icp->conn_login_status = ISCSI_STATUS_INTERNAL_ERROR;
4229162SPeter.Dunlap@Sun.COM iscsi_login_disconnect(icp);
4239162SPeter.Dunlap@Sun.COM iscsi_login_update_state(icp, LOGIN_DONE);
4247836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
4257836SJohn.Forte@Sun.COM }
4267836SJohn.Forte@Sun.COM
4277836SJohn.Forte@Sun.COM if (iscsiAuthClientSetVersion(auth_client,
4287836SJohn.Forte@Sun.COM iscsiAuthVersionRfc) != iscsiAuthStatusNoError) {
4297836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
4307836SJohn.Forte@Sun.COM "unable to set authentication", icp->conn_oid);
4317836SJohn.Forte@Sun.COM goto iscsi_login_done;
4327836SJohn.Forte@Sun.COM }
4337836SJohn.Forte@Sun.COM
4347836SJohn.Forte@Sun.COM if (isp->sess_auth.username &&
4357836SJohn.Forte@Sun.COM (iscsiAuthClientSetUsername(auth_client,
4367836SJohn.Forte@Sun.COM isp->sess_auth.username) !=
4377836SJohn.Forte@Sun.COM iscsiAuthStatusNoError)) {
4387836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
4397836SJohn.Forte@Sun.COM "unable to set username", icp->conn_oid);
4407836SJohn.Forte@Sun.COM goto iscsi_login_done;
4417836SJohn.Forte@Sun.COM }
4427836SJohn.Forte@Sun.COM
4437836SJohn.Forte@Sun.COM if (isp->sess_auth.password &&
4447836SJohn.Forte@Sun.COM (iscsiAuthClientSetPassword(auth_client,
4457836SJohn.Forte@Sun.COM isp->sess_auth.password, isp->sess_auth.password_length) !=
4467836SJohn.Forte@Sun.COM iscsiAuthStatusNoError)) {
4477836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
4487836SJohn.Forte@Sun.COM "unable to set password", icp->conn_oid);
4497836SJohn.Forte@Sun.COM goto iscsi_login_done;
4507836SJohn.Forte@Sun.COM }
4517836SJohn.Forte@Sun.COM
4527836SJohn.Forte@Sun.COM if (iscsiAuthClientSetIpSec(auth_client, 1) !=
4537836SJohn.Forte@Sun.COM iscsiAuthStatusNoError) {
4547836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
4557836SJohn.Forte@Sun.COM "unable to set ipsec", icp->conn_oid);
4567836SJohn.Forte@Sun.COM goto iscsi_login_done;
4577836SJohn.Forte@Sun.COM }
4587836SJohn.Forte@Sun.COM
4597836SJohn.Forte@Sun.COM if (iscsiAuthClientSetAuthRemote(auth_client,
4607836SJohn.Forte@Sun.COM isp->sess_auth.bidirectional_auth) !=
4617836SJohn.Forte@Sun.COM iscsiAuthStatusNoError) {
4627836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
4637836SJohn.Forte@Sun.COM "unable to set remote authentication",
4647836SJohn.Forte@Sun.COM icp->conn_oid);
4657836SJohn.Forte@Sun.COM goto iscsi_login_done;
4667836SJohn.Forte@Sun.COM }
4677836SJohn.Forte@Sun.COM }
4687836SJohn.Forte@Sun.COM
4697836SJohn.Forte@Sun.COM /*
4707836SJohn.Forte@Sun.COM * exchange PDUs until the login stage is complete, or an error occurs
4717836SJohn.Forte@Sun.COM */
4727836SJohn.Forte@Sun.COM do {
4737836SJohn.Forte@Sun.COM /* setup */
4747836SJohn.Forte@Sun.COM bzero(buffer, bufsize);
4757836SJohn.Forte@Sun.COM data = buffer;
4767836SJohn.Forte@Sun.COM max_data_length = bufsize;
4777836SJohn.Forte@Sun.COM rval = ISCSI_STATUS_INTERNAL_ERROR;
4787836SJohn.Forte@Sun.COM
4799162SPeter.Dunlap@Sun.COM text_pdu = idm_pdu_alloc(sizeof (iscsi_hdr_t), 0);
4809162SPeter.Dunlap@Sun.COM idm_pdu_init(text_pdu, icp->conn_ic, NULL, NULL);
4819162SPeter.Dunlap@Sun.COM
4827836SJohn.Forte@Sun.COM /*
4837836SJohn.Forte@Sun.COM * fill in the PDU header and text data based on the
4847836SJohn.Forte@Sun.COM * login stage that we're in
4857836SJohn.Forte@Sun.COM */
4869162SPeter.Dunlap@Sun.COM rval = iscsi_make_login_pdu(icp, text_pdu, data,
4879162SPeter.Dunlap@Sun.COM max_data_length);
4887836SJohn.Forte@Sun.COM if (!ISCSI_SUCCESS(rval)) {
4897836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
4907836SJohn.Forte@Sun.COM "unable to make login pdu", icp->conn_oid);
4917836SJohn.Forte@Sun.COM goto iscsi_login_done;
4927836SJohn.Forte@Sun.COM }
4937836SJohn.Forte@Sun.COM
4949162SPeter.Dunlap@Sun.COM mutex_enter(&icp->conn_login_mutex);
4959162SPeter.Dunlap@Sun.COM /*
4969162SPeter.Dunlap@Sun.COM * Make sure we are still in LOGIN_START or LOGIN_RX
4979162SPeter.Dunlap@Sun.COM * state before switching to LOGIN_TX. It's possible
4989162SPeter.Dunlap@Sun.COM * for a connection failure to move us to LOGIN_ERROR
4999162SPeter.Dunlap@Sun.COM * before we get to this point.
5009162SPeter.Dunlap@Sun.COM */
5019162SPeter.Dunlap@Sun.COM if (((icp->conn_login_state != LOGIN_READY) &&
5029162SPeter.Dunlap@Sun.COM (icp->conn_login_state != LOGIN_RX)) ||
5039162SPeter.Dunlap@Sun.COM !icp->conn_state_idm_connected) {
5049162SPeter.Dunlap@Sun.COM /* Error occurred */
5059162SPeter.Dunlap@Sun.COM mutex_exit(&icp->conn_login_mutex);
5069162SPeter.Dunlap@Sun.COM rval = (ISCSI_STATUS_INTERNAL_ERROR);
5077836SJohn.Forte@Sun.COM goto iscsi_login_done;
5087836SJohn.Forte@Sun.COM }
5097836SJohn.Forte@Sun.COM
510*12697SPeter.Gill@Sun.COM icp->conn_login_resp_hdr.opcode = 0;
5119162SPeter.Dunlap@Sun.COM iscsi_login_update_state_locked(icp, LOGIN_TX);
5129162SPeter.Dunlap@Sun.COM icp->conn_login_data = data;
5139162SPeter.Dunlap@Sun.COM icp->conn_login_max_data_length = max_data_length;
5149162SPeter.Dunlap@Sun.COM
5159162SPeter.Dunlap@Sun.COM /*
5169162SPeter.Dunlap@Sun.COM * send a PDU to the target. This is asynchronous but
5179162SPeter.Dunlap@Sun.COM * we don't have any particular need for a TX completion
5189162SPeter.Dunlap@Sun.COM * notification since we are going to block waiting for the
5199162SPeter.Dunlap@Sun.COM * receive.
5209162SPeter.Dunlap@Sun.COM */
5219162SPeter.Dunlap@Sun.COM response_timeout = ddi_get_lbolt() +
52210156SZhang.Yi@Sun.COM SEC_TO_TICK(icp->conn_tunable_params.
52310156SZhang.Yi@Sun.COM recv_login_rsp_timeout);
5249162SPeter.Dunlap@Sun.COM idm_pdu_tx(text_pdu);
5259162SPeter.Dunlap@Sun.COM
5269162SPeter.Dunlap@Sun.COM /*
5279162SPeter.Dunlap@Sun.COM * Wait for login failure indication or login RX.
5289162SPeter.Dunlap@Sun.COM * Handler for login response PDU will copy any data into
5299162SPeter.Dunlap@Sun.COM * the buffer pointed to by icp->conn_login_data
5309162SPeter.Dunlap@Sun.COM */
5319162SPeter.Dunlap@Sun.COM while (icp->conn_login_state == LOGIN_TX) {
5329162SPeter.Dunlap@Sun.COM timeout_result = cv_timedwait(&icp->conn_login_cv,
5339162SPeter.Dunlap@Sun.COM &icp->conn_login_mutex, response_timeout);
5349162SPeter.Dunlap@Sun.COM if (timeout_result == -1)
5359162SPeter.Dunlap@Sun.COM break;
5369162SPeter.Dunlap@Sun.COM }
5379162SPeter.Dunlap@Sun.COM
538*12697SPeter.Gill@Sun.COM /*
539*12697SPeter.Gill@Sun.COM * We have either received a login response or the connection
540*12697SPeter.Gill@Sun.COM * has gone down or both. If a login response is present,
541*12697SPeter.Gill@Sun.COM * then process it.
542*12697SPeter.Gill@Sun.COM */
543*12697SPeter.Gill@Sun.COM ilrhp = (iscsi_login_rsp_hdr_t *)&icp->conn_login_resp_hdr;
544*12697SPeter.Gill@Sun.COM if (icp->conn_login_state != LOGIN_RX && ilrhp->opcode == 0) {
545*12697SPeter.Gill@Sun.COM /* connection down, with no login response */
5469162SPeter.Dunlap@Sun.COM mutex_exit(&icp->conn_login_mutex);
5479162SPeter.Dunlap@Sun.COM rval = (ISCSI_STATUS_INTERNAL_ERROR);
5487836SJohn.Forte@Sun.COM goto iscsi_login_done;
5497836SJohn.Forte@Sun.COM }
5509162SPeter.Dunlap@Sun.COM mutex_exit(&icp->conn_login_mutex);
5517836SJohn.Forte@Sun.COM
5527836SJohn.Forte@Sun.COM /* check the PDU response type */
5539162SPeter.Dunlap@Sun.COM if (ilrhp->opcode != ISCSI_OP_LOGIN_RSP) {
5547836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
5557836SJohn.Forte@Sun.COM "received invalid login response (0x%02x)",
5569162SPeter.Dunlap@Sun.COM icp->conn_oid, ilrhp->opcode);
5577836SJohn.Forte@Sun.COM rval = (ISCSI_STATUS_PROTOCOL_ERROR);
5587836SJohn.Forte@Sun.COM goto iscsi_login_done;
5597836SJohn.Forte@Sun.COM }
5607836SJohn.Forte@Sun.COM
5617836SJohn.Forte@Sun.COM /*
5627836SJohn.Forte@Sun.COM * give the caller the status class and detail from the
5637836SJohn.Forte@Sun.COM * last login response PDU received
5647836SJohn.Forte@Sun.COM */
5657836SJohn.Forte@Sun.COM if (status_class) {
5667836SJohn.Forte@Sun.COM *status_class = ilrhp->status_class;
5677836SJohn.Forte@Sun.COM }
5687836SJohn.Forte@Sun.COM if (status_detail) {
5697836SJohn.Forte@Sun.COM *status_detail = ilrhp->status_detail;
5707836SJohn.Forte@Sun.COM }
5717836SJohn.Forte@Sun.COM
5727836SJohn.Forte@Sun.COM switch (ilrhp->status_class) {
5737836SJohn.Forte@Sun.COM case ISCSI_STATUS_CLASS_SUCCESS:
5747836SJohn.Forte@Sun.COM /*
5757836SJohn.Forte@Sun.COM * process this response and possibly continue
5767836SJohn.Forte@Sun.COM * sending PDUs
5777836SJohn.Forte@Sun.COM */
5787836SJohn.Forte@Sun.COM rval = iscsi_process_login_response(icp,
5799162SPeter.Dunlap@Sun.COM ilrhp, (char *)icp->conn_login_data,
5809162SPeter.Dunlap@Sun.COM icp->conn_login_max_data_length);
5817836SJohn.Forte@Sun.COM /* pass back whatever error we discovered */
5827836SJohn.Forte@Sun.COM if (!ISCSI_SUCCESS(rval)) {
58310317SZhang.Yi@Sun.COM if (ISCSI_LOGIN_TRANSIT_FFP(ilrhp->flags)) {
58410317SZhang.Yi@Sun.COM /*
58510317SZhang.Yi@Sun.COM * iSCSI connection transit to next
58610317SZhang.Yi@Sun.COM * FFP stage while iscsi params
58710317SZhang.Yi@Sun.COM * ngeotiate error, LOGIN_ERROR
58810317SZhang.Yi@Sun.COM * marked so CN_FFP_ENABLED can
58910317SZhang.Yi@Sun.COM * be fully handled before
59010317SZhang.Yi@Sun.COM * CN_FFP_DISABLED can be processed.
59110317SZhang.Yi@Sun.COM */
59210317SZhang.Yi@Sun.COM iscsi_login_update_state(icp,
59310317SZhang.Yi@Sun.COM LOGIN_ERROR);
59410317SZhang.Yi@Sun.COM }
5957836SJohn.Forte@Sun.COM goto iscsi_login_done;
5967836SJohn.Forte@Sun.COM }
5977836SJohn.Forte@Sun.COM
5987836SJohn.Forte@Sun.COM break;
5997836SJohn.Forte@Sun.COM case ISCSI_STATUS_CLASS_REDIRECT:
6007836SJohn.Forte@Sun.COM /*
6017836SJohn.Forte@Sun.COM * we need to process this response to get the
6027836SJohn.Forte@Sun.COM * TargetAddress of the redirect, but we don't
6037836SJohn.Forte@Sun.COM * care about the return code.
6047836SJohn.Forte@Sun.COM */
6059162SPeter.Dunlap@Sun.COM (void) iscsi_process_login_response(icp,
6069162SPeter.Dunlap@Sun.COM ilrhp, (char *)icp->conn_login_data,
6079162SPeter.Dunlap@Sun.COM icp->conn_login_max_data_length);
6087836SJohn.Forte@Sun.COM rval = ISCSI_STATUS_SUCCESS;
6097836SJohn.Forte@Sun.COM goto iscsi_login_done;
6107836SJohn.Forte@Sun.COM case ISCSI_STATUS_CLASS_INITIATOR_ERR:
6117836SJohn.Forte@Sun.COM if (ilrhp->status_detail ==
6127836SJohn.Forte@Sun.COM ISCSI_LOGIN_STATUS_AUTH_FAILED) {
6137836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) login "
6147836SJohn.Forte@Sun.COM "failed - login failed to authenticate "
6157836SJohn.Forte@Sun.COM "with target", icp->conn_oid);
6167836SJohn.Forte@Sun.COM }
6177836SJohn.Forte@Sun.COM rval = ISCSI_STATUS_SUCCESS;
6187836SJohn.Forte@Sun.COM goto iscsi_login_done;
6197836SJohn.Forte@Sun.COM default:
6207836SJohn.Forte@Sun.COM /*
6217836SJohn.Forte@Sun.COM * some sort of error, login terminated unsuccessfully,
6227836SJohn.Forte@Sun.COM * though this function did it's job. the caller must
6237836SJohn.Forte@Sun.COM * check the status_class and status_detail and decide
6247836SJohn.Forte@Sun.COM * what to do next.
6257836SJohn.Forte@Sun.COM */
6267836SJohn.Forte@Sun.COM rval = ISCSI_STATUS_SUCCESS;
6277836SJohn.Forte@Sun.COM goto iscsi_login_done;
6287836SJohn.Forte@Sun.COM }
6297836SJohn.Forte@Sun.COM
6307836SJohn.Forte@Sun.COM } while (icp->conn_current_stage != ISCSI_FULL_FEATURE_PHASE);
6317836SJohn.Forte@Sun.COM
6327836SJohn.Forte@Sun.COM rval = ISCSI_STATUS_SUCCESS;
6337836SJohn.Forte@Sun.COM
6347836SJohn.Forte@Sun.COM iscsi_login_done:
6357836SJohn.Forte@Sun.COM if (auth_client) {
6367836SJohn.Forte@Sun.COM if (iscsiAuthClientFinish(auth_client) !=
6377836SJohn.Forte@Sun.COM iscsiAuthStatusNoError) {
6387836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) login "
6397836SJohn.Forte@Sun.COM "failed - login failed to authenticate "
6407836SJohn.Forte@Sun.COM "with target", icp->conn_oid);
6417836SJohn.Forte@Sun.COM if (ISCSI_SUCCESS(rval))
6427836SJohn.Forte@Sun.COM rval = ISCSI_STATUS_INTERNAL_ERROR;
6437836SJohn.Forte@Sun.COM }
6447836SJohn.Forte@Sun.COM }
6459162SPeter.Dunlap@Sun.COM
64612001SZhang.Yi@Sun.COM icp->conn_login_status = rval;
6479162SPeter.Dunlap@Sun.COM if (ISCSI_SUCCESS(rval) &&
6489162SPeter.Dunlap@Sun.COM (*status_class == ISCSI_STATUS_CLASS_SUCCESS)) {
6499162SPeter.Dunlap@Sun.COM mutex_enter(&icp->conn_state_mutex);
6509162SPeter.Dunlap@Sun.COM while (!icp->conn_state_ffp)
6519162SPeter.Dunlap@Sun.COM cv_wait(&icp->conn_state_change,
6529162SPeter.Dunlap@Sun.COM &icp->conn_state_mutex);
6539162SPeter.Dunlap@Sun.COM mutex_exit(&icp->conn_state_mutex);
6549162SPeter.Dunlap@Sun.COM } else {
6559162SPeter.Dunlap@Sun.COM iscsi_login_disconnect(icp);
6569162SPeter.Dunlap@Sun.COM }
6579162SPeter.Dunlap@Sun.COM
6589162SPeter.Dunlap@Sun.COM iscsi_login_update_state(icp, LOGIN_DONE);
6599162SPeter.Dunlap@Sun.COM
6607836SJohn.Forte@Sun.COM return (rval);
6617836SJohn.Forte@Sun.COM }
6627836SJohn.Forte@Sun.COM
6637836SJohn.Forte@Sun.COM
6647836SJohn.Forte@Sun.COM /*
6657836SJohn.Forte@Sun.COM * iscsi_make_login_pdu -
6667836SJohn.Forte@Sun.COM *
6677836SJohn.Forte@Sun.COM */
6687836SJohn.Forte@Sun.COM static iscsi_status_t
iscsi_make_login_pdu(iscsi_conn_t * icp,idm_pdu_t * text_pdu,char * data,int max_data_length)6699162SPeter.Dunlap@Sun.COM iscsi_make_login_pdu(iscsi_conn_t *icp, idm_pdu_t *text_pdu,
6707836SJohn.Forte@Sun.COM char *data, int max_data_length)
6717836SJohn.Forte@Sun.COM {
6727836SJohn.Forte@Sun.COM struct iscsi_sess *isp = NULL;
6737836SJohn.Forte@Sun.COM int transit = 0;
6749162SPeter.Dunlap@Sun.COM iscsi_hdr_t *ihp = text_pdu->isp_hdr;
6759162SPeter.Dunlap@Sun.COM iscsi_login_hdr_t *ilhp =
6769162SPeter.Dunlap@Sun.COM (iscsi_login_hdr_t *)text_pdu->isp_hdr;
6777836SJohn.Forte@Sun.COM IscsiAuthClient *auth_client = NULL;
6787836SJohn.Forte@Sun.COM int keytype = 0;
6797836SJohn.Forte@Sun.COM int rc = 0;
6807836SJohn.Forte@Sun.COM char value[iscsiAuthStringMaxLength];
6817836SJohn.Forte@Sun.COM
6827836SJohn.Forte@Sun.COM ASSERT(icp != NULL);
6839162SPeter.Dunlap@Sun.COM ASSERT(text_pdu != NULL);
6847836SJohn.Forte@Sun.COM isp = icp->conn_sess;
6857836SJohn.Forte@Sun.COM ASSERT(isp != NULL);
6867836SJohn.Forte@Sun.COM
6877836SJohn.Forte@Sun.COM auth_client =
6887836SJohn.Forte@Sun.COM (isp->sess_auth.auth_buffers && isp->sess_auth.num_auth_buffers) ?
6897836SJohn.Forte@Sun.COM (IscsiAuthClient *)isp->sess_auth.auth_buffers[0].address : NULL;
6907836SJohn.Forte@Sun.COM
6917836SJohn.Forte@Sun.COM /*
6927836SJohn.Forte@Sun.COM * initialize the PDU header
6937836SJohn.Forte@Sun.COM */
6947836SJohn.Forte@Sun.COM bzero(ilhp, sizeof (*ilhp));
6957836SJohn.Forte@Sun.COM ilhp->opcode = ISCSI_OP_LOGIN_CMD | ISCSI_OP_IMMEDIATE;
6967836SJohn.Forte@Sun.COM ilhp->cid = icp->conn_cid;
6977836SJohn.Forte@Sun.COM bcopy(&isp->sess_isid[0], &ilhp->isid[0], sizeof (isp->sess_isid));
6987836SJohn.Forte@Sun.COM ilhp->tsid = 0;
6997836SJohn.Forte@Sun.COM
7009162SPeter.Dunlap@Sun.COM /*
7019162SPeter.Dunlap@Sun.COM * Set data buffer pointer. The calls to iscsi_add_text will update the
7029162SPeter.Dunlap@Sun.COM * data length.
7039162SPeter.Dunlap@Sun.COM */
7049162SPeter.Dunlap@Sun.COM text_pdu->isp_data = (uint8_t *)data;
7059162SPeter.Dunlap@Sun.COM
7067836SJohn.Forte@Sun.COM /* don't increment on immediate */
7077836SJohn.Forte@Sun.COM ilhp->cmdsn = htonl(isp->sess_cmdsn);
7087836SJohn.Forte@Sun.COM
7097836SJohn.Forte@Sun.COM ilhp->min_version = ISCSI_DRAFT20_VERSION;
7107836SJohn.Forte@Sun.COM ilhp->max_version = ISCSI_DRAFT20_VERSION;
7117836SJohn.Forte@Sun.COM
7127836SJohn.Forte@Sun.COM /*
7137836SJohn.Forte@Sun.COM * we have to send 0 until full-feature stage
7147836SJohn.Forte@Sun.COM */
7157836SJohn.Forte@Sun.COM ilhp->expstatsn = htonl(icp->conn_expstatsn);
7167836SJohn.Forte@Sun.COM
7177836SJohn.Forte@Sun.COM /*
7187836SJohn.Forte@Sun.COM * the very first Login PDU has some additional requirements,
7197836SJohn.Forte@Sun.COM * * and we need to decide what stage to start in.
7207836SJohn.Forte@Sun.COM */
7217836SJohn.Forte@Sun.COM if (icp->conn_current_stage == ISCSI_INITIAL_LOGIN_STAGE) {
7227836SJohn.Forte@Sun.COM if ((isp->sess_hba->hba_name) &&
7237836SJohn.Forte@Sun.COM (isp->sess_hba->hba_name[0])) {
7249162SPeter.Dunlap@Sun.COM if (!iscsi_add_text(text_pdu, max_data_length,
7257836SJohn.Forte@Sun.COM "InitiatorName",
7267836SJohn.Forte@Sun.COM (char *)isp->sess_hba->hba_name)) {
7277836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
7287836SJohn.Forte@Sun.COM }
7297836SJohn.Forte@Sun.COM } else {
7307836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) login "
7317836SJohn.Forte@Sun.COM "failed - initiator name is required",
7327836SJohn.Forte@Sun.COM icp->conn_oid);
7337836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
7347836SJohn.Forte@Sun.COM }
7357836SJohn.Forte@Sun.COM
7367836SJohn.Forte@Sun.COM if ((isp->sess_hba->hba_alias) &&
7377836SJohn.Forte@Sun.COM (isp->sess_hba->hba_alias[0])) {
7389162SPeter.Dunlap@Sun.COM if (!iscsi_add_text(text_pdu, max_data_length,
7397836SJohn.Forte@Sun.COM "InitiatorAlias",
7407836SJohn.Forte@Sun.COM (char *)isp->sess_hba->hba_alias)) {
7417836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
7427836SJohn.Forte@Sun.COM }
7437836SJohn.Forte@Sun.COM }
7447836SJohn.Forte@Sun.COM
7457836SJohn.Forte@Sun.COM if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
7467836SJohn.Forte@Sun.COM if (isp->sess_name[0] != '\0') {
7479162SPeter.Dunlap@Sun.COM if (!iscsi_add_text(text_pdu, max_data_length,
7487836SJohn.Forte@Sun.COM "TargetName", (char *)isp->sess_name)) {
7497836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
7507836SJohn.Forte@Sun.COM }
7517836SJohn.Forte@Sun.COM }
7527836SJohn.Forte@Sun.COM
7539162SPeter.Dunlap@Sun.COM if (!iscsi_add_text(text_pdu, max_data_length,
7547836SJohn.Forte@Sun.COM "SessionType", "Normal")) {
7557836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
7567836SJohn.Forte@Sun.COM }
7577836SJohn.Forte@Sun.COM } else if (isp->sess_type == ISCSI_SESS_TYPE_DISCOVERY) {
7589162SPeter.Dunlap@Sun.COM if (!iscsi_add_text(text_pdu, max_data_length,
7597836SJohn.Forte@Sun.COM "SessionType", "Discovery")) {
7607836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
7617836SJohn.Forte@Sun.COM }
7627836SJohn.Forte@Sun.COM } else {
7637836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
7647836SJohn.Forte@Sun.COM }
7657836SJohn.Forte@Sun.COM
7667836SJohn.Forte@Sun.COM if (auth_client) {
7677836SJohn.Forte@Sun.COM /* we're prepared to do authentication */
7687836SJohn.Forte@Sun.COM icp->conn_current_stage =
7697836SJohn.Forte@Sun.COM ISCSI_SECURITY_NEGOTIATION_STAGE;
7707836SJohn.Forte@Sun.COM } else {
7717836SJohn.Forte@Sun.COM /* can't do any authentication, skip that stage */
7727836SJohn.Forte@Sun.COM icp->conn_current_stage =
7737836SJohn.Forte@Sun.COM ISCSI_OP_PARMS_NEGOTIATION_STAGE;
7747836SJohn.Forte@Sun.COM }
7757836SJohn.Forte@Sun.COM }
7767836SJohn.Forte@Sun.COM
7777836SJohn.Forte@Sun.COM /*
7787836SJohn.Forte@Sun.COM * fill in text based on the stage
7797836SJohn.Forte@Sun.COM */
7807836SJohn.Forte@Sun.COM switch (icp->conn_current_stage) {
7817836SJohn.Forte@Sun.COM case ISCSI_OP_PARMS_NEGOTIATION_STAGE:
7827836SJohn.Forte@Sun.COM /*
7837836SJohn.Forte@Sun.COM * we always try to go from op params to full
7847836SJohn.Forte@Sun.COM * feature stage
7857836SJohn.Forte@Sun.COM */
7867836SJohn.Forte@Sun.COM icp->conn_next_stage = ISCSI_FULL_FEATURE_PHASE;
7877836SJohn.Forte@Sun.COM transit = 1;
7887836SJohn.Forte@Sun.COM
7897836SJohn.Forte@Sun.COM /*
7907836SJohn.Forte@Sun.COM * The terminology here may have gotten dated. A partial
7917836SJohn.Forte@Sun.COM * response is a login response that doesn't complete a
7927836SJohn.Forte@Sun.COM * login. If we haven't gotten a partial response, then
7937836SJohn.Forte@Sun.COM * either we shouldn't be here, or we just switched to
7947836SJohn.Forte@Sun.COM * this stage, and need to start offering keys.
7957836SJohn.Forte@Sun.COM */
7967836SJohn.Forte@Sun.COM if (!icp->conn_partial_response) {
7977836SJohn.Forte@Sun.COM /*
7987836SJohn.Forte@Sun.COM * request the desired settings the first time
7997836SJohn.Forte@Sun.COM * we are in this stage
8007836SJohn.Forte@Sun.COM */
8017836SJohn.Forte@Sun.COM switch (icp->conn_params.header_digest) {
8027836SJohn.Forte@Sun.COM case ISCSI_DIGEST_NONE:
8039162SPeter.Dunlap@Sun.COM if (!iscsi_add_text(text_pdu,
8047836SJohn.Forte@Sun.COM max_data_length, "HeaderDigest", "None")) {
8057836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
8067836SJohn.Forte@Sun.COM }
8077836SJohn.Forte@Sun.COM break;
8087836SJohn.Forte@Sun.COM case ISCSI_DIGEST_CRC32C:
8099162SPeter.Dunlap@Sun.COM if (!iscsi_add_text(text_pdu,
8107836SJohn.Forte@Sun.COM max_data_length,
8117836SJohn.Forte@Sun.COM "HeaderDigest", "CRC32C")) {
8127836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
8137836SJohn.Forte@Sun.COM }
8147836SJohn.Forte@Sun.COM break;
8157836SJohn.Forte@Sun.COM case ISCSI_DIGEST_CRC32C_NONE:
8169162SPeter.Dunlap@Sun.COM if (!iscsi_add_text(text_pdu,
8177836SJohn.Forte@Sun.COM max_data_length, "HeaderDigest",
8187836SJohn.Forte@Sun.COM "CRC32C,None")) {
8197836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
8207836SJohn.Forte@Sun.COM }
8217836SJohn.Forte@Sun.COM break;
8227836SJohn.Forte@Sun.COM default:
8237836SJohn.Forte@Sun.COM case ISCSI_DIGEST_NONE_CRC32C:
8249162SPeter.Dunlap@Sun.COM if (!iscsi_add_text(text_pdu,
8257836SJohn.Forte@Sun.COM max_data_length, "HeaderDigest",
8267836SJohn.Forte@Sun.COM "None,CRC32C")) {
8277836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
8287836SJohn.Forte@Sun.COM }
8297836SJohn.Forte@Sun.COM break;
8307836SJohn.Forte@Sun.COM }
8317836SJohn.Forte@Sun.COM
8327836SJohn.Forte@Sun.COM switch (icp->conn_params.data_digest) {
8337836SJohn.Forte@Sun.COM case ISCSI_DIGEST_NONE:
8349162SPeter.Dunlap@Sun.COM if (!iscsi_add_text(text_pdu,
8357836SJohn.Forte@Sun.COM max_data_length, "DataDigest", "None")) {
8367836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
8377836SJohn.Forte@Sun.COM }
8387836SJohn.Forte@Sun.COM break;
8397836SJohn.Forte@Sun.COM case ISCSI_DIGEST_CRC32C:
8409162SPeter.Dunlap@Sun.COM if (!iscsi_add_text(text_pdu,
8417836SJohn.Forte@Sun.COM max_data_length, "DataDigest", "CRC32C")) {
8427836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
8437836SJohn.Forte@Sun.COM }
8447836SJohn.Forte@Sun.COM break;
8457836SJohn.Forte@Sun.COM case ISCSI_DIGEST_CRC32C_NONE:
8469162SPeter.Dunlap@Sun.COM if (!iscsi_add_text(text_pdu,
8477836SJohn.Forte@Sun.COM max_data_length, "DataDigest",
8487836SJohn.Forte@Sun.COM "CRC32C,None")) {
8497836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
8507836SJohn.Forte@Sun.COM }
8517836SJohn.Forte@Sun.COM break;
8527836SJohn.Forte@Sun.COM default:
8537836SJohn.Forte@Sun.COM case ISCSI_DIGEST_NONE_CRC32C:
8549162SPeter.Dunlap@Sun.COM if (!iscsi_add_text(text_pdu,
8557836SJohn.Forte@Sun.COM max_data_length, "DataDigest",
8567836SJohn.Forte@Sun.COM "None,CRC32C")) {
8577836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
8587836SJohn.Forte@Sun.COM }
8597836SJohn.Forte@Sun.COM break;
8607836SJohn.Forte@Sun.COM }
8617836SJohn.Forte@Sun.COM
8627836SJohn.Forte@Sun.COM (void) sprintf(value, "%d",
8637836SJohn.Forte@Sun.COM icp->conn_params.max_recv_data_seg_len);
8649162SPeter.Dunlap@Sun.COM if (!iscsi_add_text(text_pdu, max_data_length,
8657836SJohn.Forte@Sun.COM "MaxRecvDataSegmentLength", value)) {
8667836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
8677836SJohn.Forte@Sun.COM }
8687836SJohn.Forte@Sun.COM
8697836SJohn.Forte@Sun.COM (void) sprintf(value, "%d",
8707836SJohn.Forte@Sun.COM icp->conn_params.default_time_to_wait);
8719162SPeter.Dunlap@Sun.COM if (!iscsi_add_text(text_pdu,
8727836SJohn.Forte@Sun.COM max_data_length, "DefaultTime2Wait", value)) {
8737836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
8747836SJohn.Forte@Sun.COM }
8757836SJohn.Forte@Sun.COM
8767836SJohn.Forte@Sun.COM (void) sprintf(value, "%d",
8777836SJohn.Forte@Sun.COM icp->conn_params.default_time_to_retain);
8789162SPeter.Dunlap@Sun.COM if (!iscsi_add_text(text_pdu,
8797836SJohn.Forte@Sun.COM max_data_length, "DefaultTime2Retain", value)) {
8807836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
8817836SJohn.Forte@Sun.COM }
8827836SJohn.Forte@Sun.COM
8837836SJohn.Forte@Sun.COM (void) sprintf(value, "%d",
8847836SJohn.Forte@Sun.COM icp->conn_params.error_recovery_level);
8859162SPeter.Dunlap@Sun.COM if (!iscsi_add_text(text_pdu,
8867836SJohn.Forte@Sun.COM max_data_length, "ErrorRecoveryLevel", "0")) {
8877836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
8887836SJohn.Forte@Sun.COM }
8897836SJohn.Forte@Sun.COM
8909162SPeter.Dunlap@Sun.COM if (!iscsi_add_text(text_pdu,
8917836SJohn.Forte@Sun.COM max_data_length, "IFMarker",
8927836SJohn.Forte@Sun.COM icp->conn_params.ifmarker ? "Yes" : "No")) {
8937836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
8947836SJohn.Forte@Sun.COM }
8957836SJohn.Forte@Sun.COM
8969162SPeter.Dunlap@Sun.COM if (!iscsi_add_text(text_pdu,
8977836SJohn.Forte@Sun.COM max_data_length, "OFMarker",
8987836SJohn.Forte@Sun.COM icp->conn_params.ofmarker ? "Yes" : "No")) {
8997836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
9007836SJohn.Forte@Sun.COM }
9017836SJohn.Forte@Sun.COM
9027836SJohn.Forte@Sun.COM /*
9037836SJohn.Forte@Sun.COM * The following login parameters are "Irrelevant"
9047836SJohn.Forte@Sun.COM * for discovery sessions
9057836SJohn.Forte@Sun.COM */
9067836SJohn.Forte@Sun.COM if (isp->sess_type != ISCSI_SESS_TYPE_DISCOVERY) {
9077836SJohn.Forte@Sun.COM
9089162SPeter.Dunlap@Sun.COM if (!iscsi_add_text(text_pdu,
9097836SJohn.Forte@Sun.COM max_data_length, "InitialR2T",
9107836SJohn.Forte@Sun.COM icp->conn_params.initial_r2t ?
9117836SJohn.Forte@Sun.COM "Yes" : "No")) {
9127836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
9137836SJohn.Forte@Sun.COM }
9147836SJohn.Forte@Sun.COM
9159162SPeter.Dunlap@Sun.COM if (!iscsi_add_text(text_pdu,
9167836SJohn.Forte@Sun.COM max_data_length, "ImmediateData",
9177836SJohn.Forte@Sun.COM icp->conn_params.immediate_data ?
9187836SJohn.Forte@Sun.COM "Yes" : "No")) {
9197836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
9207836SJohn.Forte@Sun.COM }
9217836SJohn.Forte@Sun.COM
9227836SJohn.Forte@Sun.COM (void) sprintf(value, "%d",
9237836SJohn.Forte@Sun.COM icp->conn_params.max_burst_length);
9249162SPeter.Dunlap@Sun.COM if (!iscsi_add_text(text_pdu,
9257836SJohn.Forte@Sun.COM max_data_length, "MaxBurstLength", value)) {
9267836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
9277836SJohn.Forte@Sun.COM }
9287836SJohn.Forte@Sun.COM
9297836SJohn.Forte@Sun.COM (void) sprintf(value, "%d",
9307836SJohn.Forte@Sun.COM icp->conn_params.first_burst_length);
9319162SPeter.Dunlap@Sun.COM if (!iscsi_add_text(text_pdu, max_data_length,
9327836SJohn.Forte@Sun.COM "FirstBurstLength", value)) {
9337836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
9347836SJohn.Forte@Sun.COM }
9357836SJohn.Forte@Sun.COM
9367836SJohn.Forte@Sun.COM (void) sprintf(value, "%d",
9377836SJohn.Forte@Sun.COM icp->conn_params.max_outstanding_r2t);
9389162SPeter.Dunlap@Sun.COM if (!iscsi_add_text(text_pdu, max_data_length,
9397836SJohn.Forte@Sun.COM "MaxOutstandingR2T", value)) {
9407836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
9417836SJohn.Forte@Sun.COM }
9427836SJohn.Forte@Sun.COM
9437836SJohn.Forte@Sun.COM (void) sprintf(value, "%d",
9447836SJohn.Forte@Sun.COM icp->conn_params.max_connections);
9459162SPeter.Dunlap@Sun.COM if (!iscsi_add_text(text_pdu, max_data_length,
9467836SJohn.Forte@Sun.COM "MaxConnections", value)) {
9477836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
9487836SJohn.Forte@Sun.COM }
9497836SJohn.Forte@Sun.COM
9509162SPeter.Dunlap@Sun.COM if (!iscsi_add_text(text_pdu,
9517836SJohn.Forte@Sun.COM max_data_length, "DataPDUInOrder",
9527836SJohn.Forte@Sun.COM icp->conn_params.data_pdu_in_order ?
9537836SJohn.Forte@Sun.COM "Yes" : "No")) {
9547836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
9557836SJohn.Forte@Sun.COM }
9567836SJohn.Forte@Sun.COM
9579162SPeter.Dunlap@Sun.COM if (!iscsi_add_text(text_pdu,
9587836SJohn.Forte@Sun.COM max_data_length, "DataSequenceInOrder",
9597836SJohn.Forte@Sun.COM icp->conn_params.data_sequence_in_order ?
9607836SJohn.Forte@Sun.COM "Yes" : "No")) {
9617836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
9627836SJohn.Forte@Sun.COM }
9637836SJohn.Forte@Sun.COM }
9647836SJohn.Forte@Sun.COM }
9657836SJohn.Forte@Sun.COM break;
9667836SJohn.Forte@Sun.COM
9677836SJohn.Forte@Sun.COM case ISCSI_SECURITY_NEGOTIATION_STAGE:
9687836SJohn.Forte@Sun.COM keytype = iscsiAuthKeyTypeNone;
9697836SJohn.Forte@Sun.COM rc = iscsiAuthClientSendTransitBit(auth_client, &transit);
9707836SJohn.Forte@Sun.COM
9717836SJohn.Forte@Sun.COM /*
9727836SJohn.Forte@Sun.COM * see if we're ready for a stage change
9737836SJohn.Forte@Sun.COM */
9747836SJohn.Forte@Sun.COM if (rc == iscsiAuthStatusNoError) {
9757836SJohn.Forte@Sun.COM if (transit) {
9767836SJohn.Forte@Sun.COM icp->conn_next_stage =
9777836SJohn.Forte@Sun.COM ISCSI_OP_PARMS_NEGOTIATION_STAGE;
9787836SJohn.Forte@Sun.COM } else {
9797836SJohn.Forte@Sun.COM icp->conn_next_stage =
9807836SJohn.Forte@Sun.COM ISCSI_SECURITY_NEGOTIATION_STAGE;
9817836SJohn.Forte@Sun.COM }
9827836SJohn.Forte@Sun.COM } else {
9837836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
9847836SJohn.Forte@Sun.COM }
9857836SJohn.Forte@Sun.COM
9867836SJohn.Forte@Sun.COM /*
9877836SJohn.Forte@Sun.COM * enumerate all the keys the auth code might want to send
9887836SJohn.Forte@Sun.COM */
9897836SJohn.Forte@Sun.COM while (iscsiAuthClientGetNextKeyType(&keytype) ==
9907836SJohn.Forte@Sun.COM iscsiAuthStatusNoError) {
9917836SJohn.Forte@Sun.COM int present = 0;
9927836SJohn.Forte@Sun.COM char *key = (char *)iscsiAuthClientGetKeyName(keytype);
9937836SJohn.Forte@Sun.COM int key_length = key ? strlen(key) : 0;
9949162SPeter.Dunlap@Sun.COM int pdu_length = text_pdu->isp_datalen;
9957836SJohn.Forte@Sun.COM char *auth_value = data + pdu_length + key_length + 1;
9967836SJohn.Forte@Sun.COM unsigned int max_length = max_data_length -
9977836SJohn.Forte@Sun.COM (pdu_length + key_length + 1);
9987836SJohn.Forte@Sun.COM
9997836SJohn.Forte@Sun.COM /*
10007836SJohn.Forte@Sun.COM * add the key/value pairs the auth code wants to
10017836SJohn.Forte@Sun.COM * send directly to the PDU, since they could in
10027836SJohn.Forte@Sun.COM * theory be large.
10037836SJohn.Forte@Sun.COM */
10047836SJohn.Forte@Sun.COM rc = iscsiAuthClientSendKeyValue(auth_client, keytype,
10057836SJohn.Forte@Sun.COM &present, auth_value, max_length);
10067836SJohn.Forte@Sun.COM if ((rc == iscsiAuthStatusNoError) && present) {
10077836SJohn.Forte@Sun.COM /*
10087836SJohn.Forte@Sun.COM * actually fill in the key
10097836SJohn.Forte@Sun.COM */
10107836SJohn.Forte@Sun.COM (void) strncpy(&data[pdu_length], key,
10117836SJohn.Forte@Sun.COM key_length);
10127836SJohn.Forte@Sun.COM pdu_length += key_length;
10137836SJohn.Forte@Sun.COM data[pdu_length] = '=';
10147836SJohn.Forte@Sun.COM pdu_length++;
10157836SJohn.Forte@Sun.COM /*
10167836SJohn.Forte@Sun.COM * adjust the PDU's data segment length to
10177836SJohn.Forte@Sun.COM * include the value and trailing NULL
10187836SJohn.Forte@Sun.COM */
10197836SJohn.Forte@Sun.COM pdu_length += strlen(auth_value) + 1;
10209162SPeter.Dunlap@Sun.COM text_pdu->isp_datalen = pdu_length;
10217836SJohn.Forte@Sun.COM hton24(ihp->dlength, pdu_length);
10227836SJohn.Forte@Sun.COM }
10237836SJohn.Forte@Sun.COM }
10247836SJohn.Forte@Sun.COM
10257836SJohn.Forte@Sun.COM break;
10267836SJohn.Forte@Sun.COM case ISCSI_FULL_FEATURE_PHASE:
10277836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) login "
10287836SJohn.Forte@Sun.COM "failed - can't send login in full feature stage",
10297836SJohn.Forte@Sun.COM icp->conn_oid);
10307836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
10317836SJohn.Forte@Sun.COM default:
10327836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) login "
10337836SJohn.Forte@Sun.COM "failed - can't send login in unknown stage (%d)",
10347836SJohn.Forte@Sun.COM icp->conn_oid, icp->conn_current_stage);
10357836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
10367836SJohn.Forte@Sun.COM }
10377836SJohn.Forte@Sun.COM
10387836SJohn.Forte@Sun.COM /* fill in the flags */
10397836SJohn.Forte@Sun.COM ilhp->flags = icp->conn_current_stage << 2;
10407836SJohn.Forte@Sun.COM if (transit) {
10417836SJohn.Forte@Sun.COM /* transit to the next stage */
10427836SJohn.Forte@Sun.COM ilhp->flags |= icp->conn_next_stage;
10437836SJohn.Forte@Sun.COM ilhp->flags |= ISCSI_FLAG_LOGIN_TRANSIT;
10447836SJohn.Forte@Sun.COM } else {
10457836SJohn.Forte@Sun.COM /* next == current */
10467836SJohn.Forte@Sun.COM ilhp->flags |= icp->conn_current_stage;
10477836SJohn.Forte@Sun.COM }
10487836SJohn.Forte@Sun.COM
10497836SJohn.Forte@Sun.COM return (ISCSI_STATUS_SUCCESS);
10507836SJohn.Forte@Sun.COM }
10517836SJohn.Forte@Sun.COM
10527836SJohn.Forte@Sun.COM
10537836SJohn.Forte@Sun.COM /*
10547836SJohn.Forte@Sun.COM * iscsi_process_login_response - This assumes the text data is
10557836SJohn.Forte@Sun.COM * always NUL terminated. The caller can always arrange for that by
10567836SJohn.Forte@Sun.COM * using a slightly larger buffer than the max PDU size, and then
10577836SJohn.Forte@Sun.COM * appending a NUL to the PDU.
10587836SJohn.Forte@Sun.COM */
10597836SJohn.Forte@Sun.COM static iscsi_status_t
iscsi_process_login_response(iscsi_conn_t * icp,iscsi_login_rsp_hdr_t * ilrhp,char * data,int max_data_length)10607836SJohn.Forte@Sun.COM iscsi_process_login_response(iscsi_conn_t *icp,
10617836SJohn.Forte@Sun.COM iscsi_login_rsp_hdr_t *ilrhp, char *data, int max_data_length)
10627836SJohn.Forte@Sun.COM {
10637836SJohn.Forte@Sun.COM iscsi_sess_t *isp = NULL;
10647836SJohn.Forte@Sun.COM IscsiAuthClient *auth_client = NULL;
10657836SJohn.Forte@Sun.COM int transit = 0;
10667836SJohn.Forte@Sun.COM char *text = data;
10677836SJohn.Forte@Sun.COM char *end = NULL;
10687836SJohn.Forte@Sun.COM int pdu_current_stage = 0;
10697836SJohn.Forte@Sun.COM int pdu_next_stage = 0;
10707836SJohn.Forte@Sun.COM int debug_status = 0;
10717836SJohn.Forte@Sun.COM unsigned long tmp;
10727836SJohn.Forte@Sun.COM char *tmpe;
10737836SJohn.Forte@Sun.COM boolean_t fbl_irrelevant = B_FALSE;
10747836SJohn.Forte@Sun.COM
10757836SJohn.Forte@Sun.COM ASSERT(icp != NULL);
10767836SJohn.Forte@Sun.COM ASSERT(ilrhp != NULL);
10777836SJohn.Forte@Sun.COM ASSERT(data != NULL);
10787836SJohn.Forte@Sun.COM isp = icp->conn_sess;
10797836SJohn.Forte@Sun.COM ASSERT(isp != NULL);
10807836SJohn.Forte@Sun.COM
10817836SJohn.Forte@Sun.COM auth_client =
10827836SJohn.Forte@Sun.COM (isp->sess_auth.auth_buffers && isp->sess_auth.num_auth_buffers) ?
10837836SJohn.Forte@Sun.COM (IscsiAuthClient *) isp->sess_auth.auth_buffers[0].address : NULL;
10847836SJohn.Forte@Sun.COM transit = ilrhp->flags & ISCSI_FLAG_LOGIN_TRANSIT;
10857836SJohn.Forte@Sun.COM
10867836SJohn.Forte@Sun.COM /* verify the initial buffer was big enough to hold everything */
10877836SJohn.Forte@Sun.COM end = text + ntoh24(ilrhp->dlength) + 1;
10887836SJohn.Forte@Sun.COM if (end >= (data + max_data_length)) {
10897836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
10907836SJohn.Forte@Sun.COM "buffer too small", icp->conn_oid);
10917836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
10927836SJohn.Forte@Sun.COM }
10937836SJohn.Forte@Sun.COM *end = '\0';
10947836SJohn.Forte@Sun.COM
10957836SJohn.Forte@Sun.COM /* if the response status was success, sanity check the response */
10967836SJohn.Forte@Sun.COM if (ilrhp->status_class == ISCSI_STATUS_CLASS_SUCCESS) {
10977836SJohn.Forte@Sun.COM /* check the active version */
10987836SJohn.Forte@Sun.COM if (ilrhp->active_version != ISCSI_DRAFT20_VERSION) {
10997836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) login "
11007836SJohn.Forte@Sun.COM "failed - target version incompatible "
11017836SJohn.Forte@Sun.COM "received:0x%0x2x expected:0x%02x",
11027836SJohn.Forte@Sun.COM icp->conn_oid, ilrhp->active_version,
11037836SJohn.Forte@Sun.COM ISCSI_DRAFT20_VERSION);
11047836SJohn.Forte@Sun.COM return (ISCSI_STATUS_VERSION_MISMATCH);
11057836SJohn.Forte@Sun.COM }
11067836SJohn.Forte@Sun.COM
11077836SJohn.Forte@Sun.COM /* make sure the current stage matches */
11087836SJohn.Forte@Sun.COM pdu_current_stage = (ilrhp->flags &
11097836SJohn.Forte@Sun.COM ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2;
11107836SJohn.Forte@Sun.COM if (pdu_current_stage != icp->conn_current_stage) {
11117836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) login "
11127836SJohn.Forte@Sun.COM "failed - login response contained invalid "
11137836SJohn.Forte@Sun.COM "stage %d", icp->conn_oid, pdu_current_stage);
11147836SJohn.Forte@Sun.COM return (ISCSI_STATUS_PROTOCOL_ERROR);
11157836SJohn.Forte@Sun.COM }
11167836SJohn.Forte@Sun.COM
11177836SJohn.Forte@Sun.COM /*
11187836SJohn.Forte@Sun.COM * Make sure that we're actually advancing
11197836SJohn.Forte@Sun.COM * if the T-bit is set
11207836SJohn.Forte@Sun.COM */
11217836SJohn.Forte@Sun.COM pdu_next_stage = ilrhp->flags &
11227836SJohn.Forte@Sun.COM ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK;
11237836SJohn.Forte@Sun.COM if (transit && (pdu_next_stage <= icp->conn_current_stage)) {
11247836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) login "
11257836SJohn.Forte@Sun.COM "failed - login response wants to go to stage "
11267836SJohn.Forte@Sun.COM "%d, but we want stage %d", icp->conn_oid,
11277836SJohn.Forte@Sun.COM pdu_next_stage, icp->conn_next_stage);
11287836SJohn.Forte@Sun.COM return (ISCSI_STATUS_PROTOCOL_ERROR);
11297836SJohn.Forte@Sun.COM }
11307836SJohn.Forte@Sun.COM }
11317836SJohn.Forte@Sun.COM
11327836SJohn.Forte@Sun.COM if (icp->conn_current_stage == ISCSI_SECURITY_NEGOTIATION_STAGE) {
11337836SJohn.Forte@Sun.COM if (iscsiAuthClientRecvBegin(auth_client) !=
11347836SJohn.Forte@Sun.COM iscsiAuthStatusNoError) {
11357836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
11367836SJohn.Forte@Sun.COM "authentication receive failed", icp->conn_oid);
11377836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
11387836SJohn.Forte@Sun.COM }
11397836SJohn.Forte@Sun.COM
11407836SJohn.Forte@Sun.COM if (iscsiAuthClientRecvTransitBit(auth_client,
11417836SJohn.Forte@Sun.COM transit) != iscsiAuthStatusNoError) {
11427836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
11437836SJohn.Forte@Sun.COM "authentication transmit failed", icp->conn_oid);
11447836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
11457836SJohn.Forte@Sun.COM }
11467836SJohn.Forte@Sun.COM }
11477836SJohn.Forte@Sun.COM
11487836SJohn.Forte@Sun.COM /*
11497836SJohn.Forte@Sun.COM * scan the text data
11507836SJohn.Forte@Sun.COM */
11517836SJohn.Forte@Sun.COM more_text:
11527836SJohn.Forte@Sun.COM while (text && (text < end)) {
11537836SJohn.Forte@Sun.COM char *value = NULL;
11547836SJohn.Forte@Sun.COM char *value_end = NULL;
11557836SJohn.Forte@Sun.COM
11567836SJohn.Forte@Sun.COM /*
11577836SJohn.Forte@Sun.COM * skip any NULs separating each text key=value pair
11587836SJohn.Forte@Sun.COM */
11597836SJohn.Forte@Sun.COM while ((text < end) && (*text == '\0')) {
11607836SJohn.Forte@Sun.COM text++;
11617836SJohn.Forte@Sun.COM }
11627836SJohn.Forte@Sun.COM if (text >= end) {
11637836SJohn.Forte@Sun.COM break;
11647836SJohn.Forte@Sun.COM }
11657836SJohn.Forte@Sun.COM
11667836SJohn.Forte@Sun.COM /*
11677836SJohn.Forte@Sun.COM * handle keys appropriate for each stage
11687836SJohn.Forte@Sun.COM */
11697836SJohn.Forte@Sun.COM switch (icp->conn_current_stage) {
11707836SJohn.Forte@Sun.COM case ISCSI_SECURITY_NEGOTIATION_STAGE:
11717836SJohn.Forte@Sun.COM /*
11727836SJohn.Forte@Sun.COM * a few keys are possible in Security stage
11737836SJohn.Forte@Sun.COM * * which the auth code doesn't care about,
11747836SJohn.Forte@Sun.COM * * but which we might want to see, or at
11757836SJohn.Forte@Sun.COM * * least not choke on.
11767836SJohn.Forte@Sun.COM */
11777836SJohn.Forte@Sun.COM if (iscsi_find_key_value("TargetAlias",
11787836SJohn.Forte@Sun.COM text, end, &value, &value_end)) {
11797836SJohn.Forte@Sun.COM isp->sess_alias_length =
11807836SJohn.Forte@Sun.COM sizeof (isp->sess_alias) - 1;
11817836SJohn.Forte@Sun.COM
11827836SJohn.Forte@Sun.COM if ((value_end - value) <
11837836SJohn.Forte@Sun.COM isp->sess_alias_length) {
11847836SJohn.Forte@Sun.COM isp->sess_alias_length =
11857836SJohn.Forte@Sun.COM value_end - value;
11867836SJohn.Forte@Sun.COM }
11877836SJohn.Forte@Sun.COM
11887836SJohn.Forte@Sun.COM bcopy(value, isp->sess_alias,
11897836SJohn.Forte@Sun.COM isp->sess_alias_length);
11907836SJohn.Forte@Sun.COM isp->sess_alias[isp->sess_alias_length + 1] =
11917836SJohn.Forte@Sun.COM '\0';
11927836SJohn.Forte@Sun.COM text = value_end;
11937836SJohn.Forte@Sun.COM
11947836SJohn.Forte@Sun.COM } else if (iscsi_find_key_value("TargetAddress",
11957836SJohn.Forte@Sun.COM text, end, &value, &value_end)) {
11967836SJohn.Forte@Sun.COM if (!ISCSI_SUCCESS(iscsi_update_address(
11977836SJohn.Forte@Sun.COM icp, value))) {
11987836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) "
11997836SJohn.Forte@Sun.COM "login failed - login redirection "
12007836SJohn.Forte@Sun.COM "invalid", icp->conn_oid);
12017836SJohn.Forte@Sun.COM return (ISCSI_STATUS_PROTOCOL_ERROR);
12027836SJohn.Forte@Sun.COM }
12037836SJohn.Forte@Sun.COM text = value_end;
12047836SJohn.Forte@Sun.COM } else if (iscsi_find_key_value("TargetPortalGroupTag",
12057836SJohn.Forte@Sun.COM text, end, &value, &value_end)) {
12067836SJohn.Forte@Sun.COM /*
12077836SJohn.Forte@Sun.COM * We should have already obtained this via
12087836SJohn.Forte@Sun.COM * discovery. We've already picked an isid,
12097836SJohn.Forte@Sun.COM * so the most we can do is confirm we reached
12107836SJohn.Forte@Sun.COM * the portal group we were expecting to.
12117836SJohn.Forte@Sun.COM */
12127836SJohn.Forte@Sun.COM if (ddi_strtoul(value, &tmpe, 0, &tmp) != 0) {
12137836SJohn.Forte@Sun.COM return (ISCSI_STATUS_PROTOCOL_ERROR);
12147836SJohn.Forte@Sun.COM }
12157836SJohn.Forte@Sun.COM if (isp->sess_tpgt_conf != ISCSI_DEFAULT_TPGT) {
12167836SJohn.Forte@Sun.COM if (tmp != isp->sess_tpgt_conf) {
12177836SJohn.Forte@Sun.COM
12187836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) login failed - target "
12197836SJohn.Forte@Sun.COM "protocol group tag mismatch, expected %d, received %lu",
12207836SJohn.Forte@Sun.COM icp->conn_oid, isp->sess_tpgt_conf, tmp);
122112001SZhang.Yi@Sun.COM return (ISCSI_STATUS_LOGIN_TPGT_NEGO_FAIL);
12227836SJohn.Forte@Sun.COM
12237836SJohn.Forte@Sun.COM }
12247836SJohn.Forte@Sun.COM }
12257836SJohn.Forte@Sun.COM isp->sess_tpgt_nego = (int)tmp;
12267836SJohn.Forte@Sun.COM text = value_end;
12277836SJohn.Forte@Sun.COM } else {
12287836SJohn.Forte@Sun.COM /*
12297836SJohn.Forte@Sun.COM * any key we don't recognize either goes
12307836SJohn.Forte@Sun.COM * to the auth code, or we choke on it
12317836SJohn.Forte@Sun.COM */
12327836SJohn.Forte@Sun.COM int keytype = iscsiAuthKeyTypeNone;
12337836SJohn.Forte@Sun.COM
12347836SJohn.Forte@Sun.COM while (iscsiAuthClientGetNextKeyType(
12357836SJohn.Forte@Sun.COM &keytype) == iscsiAuthStatusNoError) {
12367836SJohn.Forte@Sun.COM
12377836SJohn.Forte@Sun.COM char *key =
12387836SJohn.Forte@Sun.COM (char *)iscsiAuthClientGetKeyName(
12397836SJohn.Forte@Sun.COM keytype);
12407836SJohn.Forte@Sun.COM
12417836SJohn.Forte@Sun.COM if ((key) &&
12427836SJohn.Forte@Sun.COM (iscsi_find_key_value(key,
12437836SJohn.Forte@Sun.COM text, end, &value, &value_end))) {
12447836SJohn.Forte@Sun.COM
12457836SJohn.Forte@Sun.COM if (iscsiAuthClientRecvKeyValue
12467836SJohn.Forte@Sun.COM (auth_client, keytype,
12477836SJohn.Forte@Sun.COM value) !=
12487836SJohn.Forte@Sun.COM iscsiAuthStatusNoError) {
12497836SJohn.Forte@Sun.COM
12507836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) login failed - can't accept "
12517836SJohn.Forte@Sun.COM "%s in security stage", icp->conn_oid, text);
12527836SJohn.Forte@Sun.COM return (ISCSI_STATUS_NEGO_FAIL);
12537836SJohn.Forte@Sun.COM
12547836SJohn.Forte@Sun.COM }
12557836SJohn.Forte@Sun.COM text = value_end;
12567836SJohn.Forte@Sun.COM goto more_text;
12577836SJohn.Forte@Sun.COM }
12587836SJohn.Forte@Sun.COM }
12597836SJohn.Forte@Sun.COM
12607836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) login failed - can't except "
12617836SJohn.Forte@Sun.COM "%s in security stage", icp->conn_oid, text);
12627836SJohn.Forte@Sun.COM
12637836SJohn.Forte@Sun.COM return (ISCSI_STATUS_NEGO_FAIL);
12647836SJohn.Forte@Sun.COM }
12657836SJohn.Forte@Sun.COM break;
12667836SJohn.Forte@Sun.COM case ISCSI_OP_PARMS_NEGOTIATION_STAGE:
12677836SJohn.Forte@Sun.COM if (iscsi_find_key_value("TargetAlias", text,
12687836SJohn.Forte@Sun.COM end, &value, &value_end)) {
12697836SJohn.Forte@Sun.COM isp->sess_alias_length =
12707836SJohn.Forte@Sun.COM sizeof (isp->sess_alias) - 1;
12717836SJohn.Forte@Sun.COM
12727836SJohn.Forte@Sun.COM if ((value_end - value) <
12737836SJohn.Forte@Sun.COM isp->sess_alias_length) {
12747836SJohn.Forte@Sun.COM isp->sess_alias_length =
12757836SJohn.Forte@Sun.COM value_end - value;
12767836SJohn.Forte@Sun.COM }
12777836SJohn.Forte@Sun.COM
12787836SJohn.Forte@Sun.COM bcopy(value, isp->sess_alias,
12797836SJohn.Forte@Sun.COM isp->sess_alias_length);
12807836SJohn.Forte@Sun.COM isp->sess_alias[isp->sess_alias_length + 1] =
12817836SJohn.Forte@Sun.COM '\0';
12827836SJohn.Forte@Sun.COM text = value_end;
12837836SJohn.Forte@Sun.COM
12847836SJohn.Forte@Sun.COM } else if (iscsi_find_key_value("TargetAddress",
12857836SJohn.Forte@Sun.COM text, end, &value, &value_end)) {
12867836SJohn.Forte@Sun.COM if (!ISCSI_SUCCESS(iscsi_update_address(
12877836SJohn.Forte@Sun.COM icp, value))) {
12887836SJohn.Forte@Sun.COM
12897836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) login failed - login "
12907836SJohn.Forte@Sun.COM "redirection invalid", icp->conn_oid);
12917836SJohn.Forte@Sun.COM
12927836SJohn.Forte@Sun.COM return (ISCSI_STATUS_PROTOCOL_ERROR);
12937836SJohn.Forte@Sun.COM }
12947836SJohn.Forte@Sun.COM text = value_end;
12957836SJohn.Forte@Sun.COM } else if (iscsi_find_key_value("TargetPortalGroupTag",
12967836SJohn.Forte@Sun.COM text, end, &value, &value_end)) {
12977836SJohn.Forte@Sun.COM /*
12987836SJohn.Forte@Sun.COM * We should have already obtained this via
12997836SJohn.Forte@Sun.COM * discovery. We've already picked an isid,
13007836SJohn.Forte@Sun.COM * so the most we can do is confirm we reached
13017836SJohn.Forte@Sun.COM * the portal group we were expecting to.
13027836SJohn.Forte@Sun.COM */
13037836SJohn.Forte@Sun.COM if (ddi_strtoul(value, &tmpe, 0, &tmp) != 0) {
13047836SJohn.Forte@Sun.COM return (ISCSI_STATUS_PROTOCOL_ERROR);
13057836SJohn.Forte@Sun.COM }
13067836SJohn.Forte@Sun.COM if (isp->sess_tpgt_conf != ISCSI_DEFAULT_TPGT) {
13077836SJohn.Forte@Sun.COM if (tmp != isp->sess_tpgt_conf) {
13087836SJohn.Forte@Sun.COM
13097836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) login failed - target portal "
13107836SJohn.Forte@Sun.COM "tag mismatch, expected:%d received:%lu", icp->conn_oid,
13117836SJohn.Forte@Sun.COM isp->sess_tpgt_conf, tmp);
131212001SZhang.Yi@Sun.COM return (ISCSI_STATUS_LOGIN_TPGT_NEGO_FAIL);
13137836SJohn.Forte@Sun.COM
13147836SJohn.Forte@Sun.COM }
13157836SJohn.Forte@Sun.COM }
13167836SJohn.Forte@Sun.COM isp->sess_tpgt_nego = (int)tmp;
13177836SJohn.Forte@Sun.COM text = value_end;
13187836SJohn.Forte@Sun.COM
13197836SJohn.Forte@Sun.COM } else if (iscsi_find_key_value("InitialR2T",
13207836SJohn.Forte@Sun.COM text, end, &value, &value_end)) {
13217836SJohn.Forte@Sun.COM
13227836SJohn.Forte@Sun.COM /*
13237836SJohn.Forte@Sun.COM * iSCSI RFC section 12.10 states that
13247836SJohn.Forte@Sun.COM * InitialR2T is Irrelevant for a
13257836SJohn.Forte@Sun.COM * discovery session.
13267836SJohn.Forte@Sun.COM */
13277836SJohn.Forte@Sun.COM if (isp->sess_type ==
13287836SJohn.Forte@Sun.COM ISCSI_SESS_TYPE_DISCOVERY) {
13297836SJohn.Forte@Sun.COM /* EMPTY */
13307836SJohn.Forte@Sun.COM } else if (value == NULL) {
13317836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) "
13327836SJohn.Forte@Sun.COM "login failed - InitialR2T is "
13337836SJohn.Forte@Sun.COM "invalid - protocol error",
13347836SJohn.Forte@Sun.COM icp->conn_oid);
13357836SJohn.Forte@Sun.COM return (ISCSI_STATUS_PROTOCOL_ERROR);
13367836SJohn.Forte@Sun.COM } else if (strcmp(value, "Yes") == 0) {
13377836SJohn.Forte@Sun.COM icp->conn_params.initial_r2t = B_TRUE;
13387836SJohn.Forte@Sun.COM } else if (strcmp(value, "No") == 0) {
13397836SJohn.Forte@Sun.COM icp->conn_params.initial_r2t = B_FALSE;
13407836SJohn.Forte@Sun.COM } else {
13417836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) "
13427836SJohn.Forte@Sun.COM "login failed - InitialR2T is "
13437836SJohn.Forte@Sun.COM "invalid - protocol error",
13447836SJohn.Forte@Sun.COM icp->conn_oid);
13457836SJohn.Forte@Sun.COM return (ISCSI_STATUS_PROTOCOL_ERROR);
13467836SJohn.Forte@Sun.COM }
13477836SJohn.Forte@Sun.COM text = value_end;
13487836SJohn.Forte@Sun.COM
13497836SJohn.Forte@Sun.COM } else if (iscsi_find_key_value("ImmediateData",
13507836SJohn.Forte@Sun.COM text, end, &value, &value_end)) {
13517836SJohn.Forte@Sun.COM
13527836SJohn.Forte@Sun.COM /*
13537836SJohn.Forte@Sun.COM * iSCSI RFC section 12.11 states that
13547836SJohn.Forte@Sun.COM * ImmediateData is Irrelevant for a
13557836SJohn.Forte@Sun.COM * discovery session.
13567836SJohn.Forte@Sun.COM */
13577836SJohn.Forte@Sun.COM if (isp->sess_type ==
13587836SJohn.Forte@Sun.COM ISCSI_SESS_TYPE_DISCOVERY) {
13597836SJohn.Forte@Sun.COM /* EMPTY */
13607836SJohn.Forte@Sun.COM } else if (value == NULL) {
13617836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) "
13627836SJohn.Forte@Sun.COM "login failed - ImmediateData is "
13637836SJohn.Forte@Sun.COM "invalid - protocol error",
13647836SJohn.Forte@Sun.COM icp->conn_oid);
13657836SJohn.Forte@Sun.COM return (ISCSI_STATUS_PROTOCOL_ERROR);
13667836SJohn.Forte@Sun.COM } else if (strcmp(value, "Yes") == 0) {
13677836SJohn.Forte@Sun.COM icp->conn_params.immediate_data = 1;
13687836SJohn.Forte@Sun.COM } else if (strcmp(value, "No") == 0) {
13697836SJohn.Forte@Sun.COM icp->conn_params.immediate_data = 0;
13707836SJohn.Forte@Sun.COM } else {
13717836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) "
13727836SJohn.Forte@Sun.COM "login failed - ImmediateData is "
13737836SJohn.Forte@Sun.COM "invalid - protocol error",
13747836SJohn.Forte@Sun.COM icp->conn_oid);
13757836SJohn.Forte@Sun.COM return (ISCSI_STATUS_PROTOCOL_ERROR);
13767836SJohn.Forte@Sun.COM }
13777836SJohn.Forte@Sun.COM text = value_end;
13787836SJohn.Forte@Sun.COM
13797836SJohn.Forte@Sun.COM } else if (iscsi_find_key_value(
13807836SJohn.Forte@Sun.COM "MaxRecvDataSegmentLength", text, end,
13817836SJohn.Forte@Sun.COM &value, &value_end)) {
13827836SJohn.Forte@Sun.COM
13837836SJohn.Forte@Sun.COM if (ddi_strtoul(value, &tmpe, 0, &tmp) != 0) {
13847836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) "
13857836SJohn.Forte@Sun.COM "login failed - MaxRecvDataSegment"
13867836SJohn.Forte@Sun.COM "Length is invalid - protocol "
13877836SJohn.Forte@Sun.COM "error", icp->conn_oid);
13887836SJohn.Forte@Sun.COM return (ISCSI_STATUS_NEGO_FAIL);
13897836SJohn.Forte@Sun.COM }
13907836SJohn.Forte@Sun.COM icp->conn_params.max_recv_data_seg_len =
13917836SJohn.Forte@Sun.COM icp->conn_params.max_xmit_data_seg_len =
13927836SJohn.Forte@Sun.COM (int)tmp;
13937836SJohn.Forte@Sun.COM
13947836SJohn.Forte@Sun.COM text = value_end;
13957836SJohn.Forte@Sun.COM } else if (iscsi_find_key_value("FirstBurstLength",
13967836SJohn.Forte@Sun.COM text, end, &value, &value_end)) {
13977836SJohn.Forte@Sun.COM
13987836SJohn.Forte@Sun.COM /*
13997836SJohn.Forte@Sun.COM * iSCSI RFC section 12.14 states that
14007836SJohn.Forte@Sun.COM * FirstBurstLength is Irrelevant if
14017836SJohn.Forte@Sun.COM * InitialR2T=Yes and ImmediateData=No
14027836SJohn.Forte@Sun.COM * or is this is a discovery session.
14037836SJohn.Forte@Sun.COM */
14047836SJohn.Forte@Sun.COM if ((isp->sess_type ==
14057836SJohn.Forte@Sun.COM ISCSI_SESS_TYPE_DISCOVERY)) {
14067836SJohn.Forte@Sun.COM /* EMPTY */
14077836SJohn.Forte@Sun.COM } else if (value &&
14087836SJohn.Forte@Sun.COM (strcmp(value, "Irrelevant") == 0)) {
14097836SJohn.Forte@Sun.COM /* irrelevant */
14107836SJohn.Forte@Sun.COM fbl_irrelevant = B_TRUE;
14117836SJohn.Forte@Sun.COM } else if (ddi_strtoul(
14127836SJohn.Forte@Sun.COM value, &tmpe, 0, &tmp) != 0) {
14137836SJohn.Forte@Sun.COM /* bad value */
14147836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) "
14157836SJohn.Forte@Sun.COM "login failed - FirstBurstLength"
14167836SJohn.Forte@Sun.COM "is invalid - protocol error",
14177836SJohn.Forte@Sun.COM icp->conn_oid);
14187836SJohn.Forte@Sun.COM return (ISCSI_STATUS_PROTOCOL_ERROR);
14197836SJohn.Forte@Sun.COM } else {
14207836SJohn.Forte@Sun.COM /* good value */
14217836SJohn.Forte@Sun.COM icp->conn_params.first_burst_length =
14227836SJohn.Forte@Sun.COM (int)tmp;
14237836SJohn.Forte@Sun.COM }
14247836SJohn.Forte@Sun.COM text = value_end;
14257836SJohn.Forte@Sun.COM } else if (iscsi_find_key_value("MaxBurstLength",
14267836SJohn.Forte@Sun.COM text, end, &value, &value_end)) {
14277836SJohn.Forte@Sun.COM /*
14287836SJohn.Forte@Sun.COM * iSCSI RFC section 12.13 states that
14297836SJohn.Forte@Sun.COM * MaxBurstLength is Irrelevant for a
14307836SJohn.Forte@Sun.COM * discovery session.
14317836SJohn.Forte@Sun.COM */
14327836SJohn.Forte@Sun.COM if (isp->sess_type ==
14337836SJohn.Forte@Sun.COM ISCSI_SESS_TYPE_DISCOVERY) {
14347836SJohn.Forte@Sun.COM /* EMPTY */
14357836SJohn.Forte@Sun.COM } else if (ddi_strtoul(
14367836SJohn.Forte@Sun.COM value, &tmpe, 0, &tmp) != 0) {
14377836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) "
14387836SJohn.Forte@Sun.COM "login failed - MaxBurstLength"
14397836SJohn.Forte@Sun.COM "is invalid - protocol error",
14407836SJohn.Forte@Sun.COM icp->conn_oid);
14417836SJohn.Forte@Sun.COM return (ISCSI_STATUS_PROTOCOL_ERROR);
14427836SJohn.Forte@Sun.COM } else {
14437836SJohn.Forte@Sun.COM icp->conn_params.max_burst_length =
14447836SJohn.Forte@Sun.COM (int)tmp;
14457836SJohn.Forte@Sun.COM }
14467836SJohn.Forte@Sun.COM
14477836SJohn.Forte@Sun.COM text = value_end;
14487836SJohn.Forte@Sun.COM
14497836SJohn.Forte@Sun.COM } else if (iscsi_find_key_value("HeaderDigest",
14507836SJohn.Forte@Sun.COM text, end, &value, &value_end)) {
14517836SJohn.Forte@Sun.COM
14527836SJohn.Forte@Sun.COM if (strcmp(value, "None") == 0) {
14537836SJohn.Forte@Sun.COM if (icp->conn_params.header_digest !=
14547836SJohn.Forte@Sun.COM ISCSI_DIGEST_CRC32C) {
14557836SJohn.Forte@Sun.COM icp->conn_params.header_digest =
14567836SJohn.Forte@Sun.COM ISCSI_DIGEST_NONE;
14577836SJohn.Forte@Sun.COM } else {
14587836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi "
14597836SJohn.Forte@Sun.COM "connection(%u) login "
14607836SJohn.Forte@Sun.COM "failed - HeaderDigest="
14617836SJohn.Forte@Sun.COM "CRC32 is required, can't "
14627836SJohn.Forte@Sun.COM "accept %s",
14637836SJohn.Forte@Sun.COM icp->conn_oid, text);
14647836SJohn.Forte@Sun.COM return (ISCSI_STATUS_NEGO_FAIL);
14657836SJohn.Forte@Sun.COM }
14667836SJohn.Forte@Sun.COM } else if (strcmp(value, "CRC32C") == 0) {
14677836SJohn.Forte@Sun.COM if (icp->conn_params.header_digest !=
14687836SJohn.Forte@Sun.COM ISCSI_DIGEST_NONE) {
14697836SJohn.Forte@Sun.COM icp->conn_params.header_digest =
14707836SJohn.Forte@Sun.COM ISCSI_DIGEST_CRC32C;
14717836SJohn.Forte@Sun.COM } else {
14727836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi "
14737836SJohn.Forte@Sun.COM "connection(%u) login "
14747836SJohn.Forte@Sun.COM "failed - HeaderDigest="
14757836SJohn.Forte@Sun.COM "None is required, can't "
14767836SJohn.Forte@Sun.COM "accept %s",
14777836SJohn.Forte@Sun.COM icp->conn_oid, text);
14787836SJohn.Forte@Sun.COM return (ISCSI_STATUS_NEGO_FAIL);
14797836SJohn.Forte@Sun.COM }
14807836SJohn.Forte@Sun.COM } else {
14817836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) "
14827836SJohn.Forte@Sun.COM "login failed - HeaderDigest "
14837836SJohn.Forte@Sun.COM "can't accept %s", icp->conn_oid,
14847836SJohn.Forte@Sun.COM text);
14857836SJohn.Forte@Sun.COM return (ISCSI_STATUS_NEGO_FAIL);
14867836SJohn.Forte@Sun.COM }
14877836SJohn.Forte@Sun.COM text = value_end;
14887836SJohn.Forte@Sun.COM } else if (iscsi_find_key_value("DataDigest", text,
14897836SJohn.Forte@Sun.COM end, &value, &value_end)) {
14907836SJohn.Forte@Sun.COM
14917836SJohn.Forte@Sun.COM if (strcmp(value, "None") == 0) {
14927836SJohn.Forte@Sun.COM if (icp->conn_params.data_digest !=
14937836SJohn.Forte@Sun.COM ISCSI_DIGEST_CRC32C) {
14947836SJohn.Forte@Sun.COM icp->conn_params.data_digest =
14957836SJohn.Forte@Sun.COM ISCSI_DIGEST_NONE;
14967836SJohn.Forte@Sun.COM } else {
14977836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi "
14987836SJohn.Forte@Sun.COM "connection(%u) login "
14997836SJohn.Forte@Sun.COM "failed - DataDigest="
15007836SJohn.Forte@Sun.COM "CRC32C is required, "
15017836SJohn.Forte@Sun.COM "can't accept %s",
15027836SJohn.Forte@Sun.COM icp->conn_oid, text);
15037836SJohn.Forte@Sun.COM return (ISCSI_STATUS_NEGO_FAIL);
15047836SJohn.Forte@Sun.COM }
15057836SJohn.Forte@Sun.COM } else if (strcmp(value, "CRC32C") == 0) {
15067836SJohn.Forte@Sun.COM if (icp->conn_params.data_digest !=
15077836SJohn.Forte@Sun.COM ISCSI_DIGEST_NONE) {
15087836SJohn.Forte@Sun.COM icp->conn_params.data_digest =
15097836SJohn.Forte@Sun.COM ISCSI_DIGEST_CRC32C;
15107836SJohn.Forte@Sun.COM } else {
15117836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi "
15127836SJohn.Forte@Sun.COM "connection(%u) login "
15137836SJohn.Forte@Sun.COM "failed - DataDigest=None "
15147836SJohn.Forte@Sun.COM "is required, can't "
15157836SJohn.Forte@Sun.COM "accept %s",
15167836SJohn.Forte@Sun.COM icp->conn_oid, text);
15177836SJohn.Forte@Sun.COM return (ISCSI_STATUS_NEGO_FAIL);
15187836SJohn.Forte@Sun.COM }
15197836SJohn.Forte@Sun.COM } else {
15207836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) "
15217836SJohn.Forte@Sun.COM "login failed - can't accept %s",
15227836SJohn.Forte@Sun.COM icp->conn_oid, text);
15237836SJohn.Forte@Sun.COM return (ISCSI_STATUS_NEGO_FAIL);
15247836SJohn.Forte@Sun.COM }
15257836SJohn.Forte@Sun.COM text = value_end;
15267836SJohn.Forte@Sun.COM
15277836SJohn.Forte@Sun.COM } else if (iscsi_find_key_value("DefaultTime2Wait",
15287836SJohn.Forte@Sun.COM text, end, &value, &value_end)) {
15297836SJohn.Forte@Sun.COM
15307836SJohn.Forte@Sun.COM if (ddi_strtoul(value, &tmpe, 0, &tmp) != 0) {
15317836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) "
15327836SJohn.Forte@Sun.COM "login failed - DefaultTime2Wait "
15337836SJohn.Forte@Sun.COM "is invalid - protocol error",
15347836SJohn.Forte@Sun.COM icp->conn_oid);
15357836SJohn.Forte@Sun.COM return (ISCSI_STATUS_PROTOCOL_ERROR);
15367836SJohn.Forte@Sun.COM }
15377836SJohn.Forte@Sun.COM icp->conn_params.default_time_to_wait =
15387836SJohn.Forte@Sun.COM (int)tmp;
15397836SJohn.Forte@Sun.COM
15407836SJohn.Forte@Sun.COM text = value_end;
15417836SJohn.Forte@Sun.COM
15427836SJohn.Forte@Sun.COM } else if (iscsi_find_key_value("DefaultTime2Retain",
15437836SJohn.Forte@Sun.COM text, end, &value, &value_end)) {
15447836SJohn.Forte@Sun.COM
15457836SJohn.Forte@Sun.COM if (ddi_strtoul(value, &tmpe, 0, &tmp) != 0) {
15467836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) "
15477836SJohn.Forte@Sun.COM "login failed - DefaultTime2Retain "
15487836SJohn.Forte@Sun.COM "is invalid - protocol error",
15497836SJohn.Forte@Sun.COM icp->conn_oid);
15507836SJohn.Forte@Sun.COM return (ISCSI_STATUS_PROTOCOL_ERROR);
15517836SJohn.Forte@Sun.COM }
15527836SJohn.Forte@Sun.COM icp->conn_params.default_time_to_retain =
15537836SJohn.Forte@Sun.COM (int)tmp;
15547836SJohn.Forte@Sun.COM
15557836SJohn.Forte@Sun.COM text = value_end;
15567836SJohn.Forte@Sun.COM
15577836SJohn.Forte@Sun.COM } else if (iscsi_find_key_value("OFMarker", text,
15587836SJohn.Forte@Sun.COM end, &value, &value_end)) {
15597836SJohn.Forte@Sun.COM
15607836SJohn.Forte@Sun.COM /*
15617836SJohn.Forte@Sun.COM * result function is AND, target must
15627836SJohn.Forte@Sun.COM * honor our No
15637836SJohn.Forte@Sun.COM */
15647836SJohn.Forte@Sun.COM text = value_end;
15657836SJohn.Forte@Sun.COM
15667836SJohn.Forte@Sun.COM } else if (iscsi_find_key_value("OFMarkInt", text,
15677836SJohn.Forte@Sun.COM end, &value, &value_end)) {
15687836SJohn.Forte@Sun.COM
15697836SJohn.Forte@Sun.COM /*
15707836SJohn.Forte@Sun.COM * we don't do markers, so we don't care
15717836SJohn.Forte@Sun.COM */
15727836SJohn.Forte@Sun.COM text = value_end;
15737836SJohn.Forte@Sun.COM
15747836SJohn.Forte@Sun.COM } else if (iscsi_find_key_value("IFMarker", text,
15757836SJohn.Forte@Sun.COM end, &value, &value_end)) {
15767836SJohn.Forte@Sun.COM
15777836SJohn.Forte@Sun.COM /*
15787836SJohn.Forte@Sun.COM * result function is AND, target must
15797836SJohn.Forte@Sun.COM * honor our No
15807836SJohn.Forte@Sun.COM */
15817836SJohn.Forte@Sun.COM text = value_end;
15827836SJohn.Forte@Sun.COM
15837836SJohn.Forte@Sun.COM } else if (iscsi_find_key_value("IFMarkInt", text,
15847836SJohn.Forte@Sun.COM end, &value, &value_end)) {
15857836SJohn.Forte@Sun.COM
15867836SJohn.Forte@Sun.COM /*
15877836SJohn.Forte@Sun.COM * we don't do markers, so we don't care
15887836SJohn.Forte@Sun.COM */
15897836SJohn.Forte@Sun.COM text = value_end;
15907836SJohn.Forte@Sun.COM
15917836SJohn.Forte@Sun.COM } else if (iscsi_find_key_value("DataPDUInOrder",
15927836SJohn.Forte@Sun.COM text, end, &value, &value_end)) {
15937836SJohn.Forte@Sun.COM
15947836SJohn.Forte@Sun.COM /*
15957836SJohn.Forte@Sun.COM * iSCSI RFC section 12.18 states that
15967836SJohn.Forte@Sun.COM * DataPDUInOrder is Irrelevant for a
15977836SJohn.Forte@Sun.COM * discovery session.
15987836SJohn.Forte@Sun.COM */
15997836SJohn.Forte@Sun.COM if (isp->sess_type ==
16007836SJohn.Forte@Sun.COM ISCSI_SESS_TYPE_DISCOVERY) {
16017836SJohn.Forte@Sun.COM /* EMPTY */
16027836SJohn.Forte@Sun.COM } else if (value == NULL) {
16037836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) "
16047836SJohn.Forte@Sun.COM "login failed - InitialR2T is "
16057836SJohn.Forte@Sun.COM "invalid - protocol error",
16067836SJohn.Forte@Sun.COM icp->conn_oid);
16077836SJohn.Forte@Sun.COM return (ISCSI_STATUS_PROTOCOL_ERROR);
16087836SJohn.Forte@Sun.COM } else if (strcmp(value, "Yes") == 0) {
16097836SJohn.Forte@Sun.COM icp->conn_params.data_pdu_in_order =
16107836SJohn.Forte@Sun.COM B_TRUE;
16117836SJohn.Forte@Sun.COM } else if (strcmp(value, "No") == 0) {
16127836SJohn.Forte@Sun.COM icp->conn_params.data_pdu_in_order =
16137836SJohn.Forte@Sun.COM B_FALSE;
16147836SJohn.Forte@Sun.COM } else {
16157836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) "
16167836SJohn.Forte@Sun.COM "login failed - InitialR2T is "
16177836SJohn.Forte@Sun.COM "invalid - protocol error",
16187836SJohn.Forte@Sun.COM icp->conn_oid);
16197836SJohn.Forte@Sun.COM return (ISCSI_STATUS_PROTOCOL_ERROR);
16207836SJohn.Forte@Sun.COM }
16217836SJohn.Forte@Sun.COM text = value_end;
16227836SJohn.Forte@Sun.COM
16237836SJohn.Forte@Sun.COM } else if (iscsi_find_key_value("DataSequenceInOrder",
16247836SJohn.Forte@Sun.COM text, end, &value, &value_end)) {
16257836SJohn.Forte@Sun.COM
16267836SJohn.Forte@Sun.COM /*
16277836SJohn.Forte@Sun.COM * iSCSI RFC section 12.19 states that
16287836SJohn.Forte@Sun.COM * DataSequenceInOrder is Irrelevant for a
16297836SJohn.Forte@Sun.COM * discovery session.
16307836SJohn.Forte@Sun.COM */
16317836SJohn.Forte@Sun.COM if (isp->sess_type ==
16327836SJohn.Forte@Sun.COM ISCSI_SESS_TYPE_DISCOVERY) {
16337836SJohn.Forte@Sun.COM /* EMPTY */
16347836SJohn.Forte@Sun.COM } else if (value == NULL) {
16357836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) "
16367836SJohn.Forte@Sun.COM "login failed - InitialR2T is "
16377836SJohn.Forte@Sun.COM "invalid - protocol error",
16387836SJohn.Forte@Sun.COM icp->conn_oid);
16397836SJohn.Forte@Sun.COM return (ISCSI_STATUS_PROTOCOL_ERROR);
16407836SJohn.Forte@Sun.COM } else if (strcmp(value, "Yes") == 0) {
16417836SJohn.Forte@Sun.COM icp->conn_params.
16427836SJohn.Forte@Sun.COM data_sequence_in_order = B_TRUE;
16437836SJohn.Forte@Sun.COM } else if (strcmp(value, "No") == 0) {
16447836SJohn.Forte@Sun.COM icp->conn_params.
16457836SJohn.Forte@Sun.COM data_sequence_in_order = B_FALSE;
16467836SJohn.Forte@Sun.COM } else {
16477836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) "
16487836SJohn.Forte@Sun.COM "login failed - InitialR2T is "
16497836SJohn.Forte@Sun.COM "invalid - protocol error",
16507836SJohn.Forte@Sun.COM icp->conn_oid);
16517836SJohn.Forte@Sun.COM return (ISCSI_STATUS_PROTOCOL_ERROR);
16527836SJohn.Forte@Sun.COM }
16537836SJohn.Forte@Sun.COM text = value_end;
16547836SJohn.Forte@Sun.COM
16557836SJohn.Forte@Sun.COM } else if (iscsi_find_key_value("MaxOutstandingR2T",
16567836SJohn.Forte@Sun.COM text, end, &value, &value_end)) {
16577836SJohn.Forte@Sun.COM
16587836SJohn.Forte@Sun.COM /*
16597836SJohn.Forte@Sun.COM * iSCSI RFC section 12.17 states that
16607836SJohn.Forte@Sun.COM * MaxOutstandingR2T is Irrelevant for a
16617836SJohn.Forte@Sun.COM * discovery session.
16627836SJohn.Forte@Sun.COM */
16637836SJohn.Forte@Sun.COM if (isp->sess_type ==
16647836SJohn.Forte@Sun.COM ISCSI_SESS_TYPE_DISCOVERY) {
16657836SJohn.Forte@Sun.COM /* EMPTY */
16667836SJohn.Forte@Sun.COM } else if (strcmp(value, "1")) {
16677836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) "
16687836SJohn.Forte@Sun.COM "login failed - can't accept "
16697836SJohn.Forte@Sun.COM "MaxOutstandingR2T %s",
16707836SJohn.Forte@Sun.COM icp->conn_oid, value);
16717836SJohn.Forte@Sun.COM return (ISCSI_STATUS_NEGO_FAIL);
16727836SJohn.Forte@Sun.COM }
16737836SJohn.Forte@Sun.COM text = value_end;
16747836SJohn.Forte@Sun.COM
16757836SJohn.Forte@Sun.COM } else if (iscsi_find_key_value("MaxConnections",
16767836SJohn.Forte@Sun.COM text, end, &value, &value_end)) {
16777836SJohn.Forte@Sun.COM
16787836SJohn.Forte@Sun.COM /*
16797836SJohn.Forte@Sun.COM * iSCSI RFC section 12.2 states that
16807836SJohn.Forte@Sun.COM * MaxConnections is Irrelevant for a
16817836SJohn.Forte@Sun.COM * discovery session.
16827836SJohn.Forte@Sun.COM */
16837836SJohn.Forte@Sun.COM if (isp->sess_type ==
16847836SJohn.Forte@Sun.COM ISCSI_SESS_TYPE_DISCOVERY) {
16857836SJohn.Forte@Sun.COM /* EMPTY */
16867836SJohn.Forte@Sun.COM } else if (strcmp(value, "1")) {
16877836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) "
16887836SJohn.Forte@Sun.COM "login failed - can't accept "
16897836SJohn.Forte@Sun.COM "MaxConnections %s",
16907836SJohn.Forte@Sun.COM icp->conn_oid, value);
16917836SJohn.Forte@Sun.COM return (ISCSI_STATUS_NEGO_FAIL);
16927836SJohn.Forte@Sun.COM }
16937836SJohn.Forte@Sun.COM text = value_end;
16947836SJohn.Forte@Sun.COM
16957836SJohn.Forte@Sun.COM } else if (iscsi_find_key_value("ErrorRecoveryLevel",
16967836SJohn.Forte@Sun.COM text, end, &value, &value_end)) {
16977836SJohn.Forte@Sun.COM
16987836SJohn.Forte@Sun.COM if (strcmp(value, "0")) {
16997836SJohn.Forte@Sun.COM
17007836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) "
17017836SJohn.Forte@Sun.COM "login failed - can't accept "
17027836SJohn.Forte@Sun.COM "ErrorRecoveryLevel %s",
17037836SJohn.Forte@Sun.COM icp->conn_oid, value);
17047836SJohn.Forte@Sun.COM return (ISCSI_STATUS_NEGO_FAIL);
17057836SJohn.Forte@Sun.COM }
17067836SJohn.Forte@Sun.COM text = value_end;
17077836SJohn.Forte@Sun.COM
17087836SJohn.Forte@Sun.COM } else {
17097836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) "
17107836SJohn.Forte@Sun.COM "login failed - ignoring login "
17117836SJohn.Forte@Sun.COM "parameter %s", icp->conn_oid, value);
17127836SJohn.Forte@Sun.COM text = value_end;
17137836SJohn.Forte@Sun.COM }
17147836SJohn.Forte@Sun.COM break;
17157836SJohn.Forte@Sun.COM default:
17167836SJohn.Forte@Sun.COM return (ISCSI_STATUS_INTERNAL_ERROR);
17177836SJohn.Forte@Sun.COM }
17187836SJohn.Forte@Sun.COM }
17197836SJohn.Forte@Sun.COM
17207836SJohn.Forte@Sun.COM /*
17217836SJohn.Forte@Sun.COM * iSCSI RFC section 12.14 states that
17227836SJohn.Forte@Sun.COM * FirstBurstLength is Irrelevant if
17237836SJohn.Forte@Sun.COM * InitialR2T=Yes and ImmediateData=No.
17247836SJohn.Forte@Sun.COM * This is a final check to make sure
17257836SJohn.Forte@Sun.COM * the array didn't make a protocol
17267836SJohn.Forte@Sun.COM * violation.
17277836SJohn.Forte@Sun.COM */
17287836SJohn.Forte@Sun.COM if ((fbl_irrelevant == B_TRUE) &&
17297836SJohn.Forte@Sun.COM ((icp->conn_params.initial_r2t != B_TRUE) ||
17307836SJohn.Forte@Sun.COM (icp->conn_params.immediate_data != B_FALSE))) {
17317836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
17327836SJohn.Forte@Sun.COM "FirstBurstLength=Irrelevant and (InitialR2T!=Yes or "
17337836SJohn.Forte@Sun.COM "ImmediateData!=No) - protocol error", icp->conn_oid);
17347836SJohn.Forte@Sun.COM return (ISCSI_STATUS_PROTOCOL_ERROR);
17357836SJohn.Forte@Sun.COM }
17367836SJohn.Forte@Sun.COM
17377836SJohn.Forte@Sun.COM if (icp->conn_current_stage == ISCSI_SECURITY_NEGOTIATION_STAGE) {
17387836SJohn.Forte@Sun.COM switch (iscsiAuthClientRecvEnd(auth_client, iscsi_null_callback,
17397836SJohn.Forte@Sun.COM (void *)isp, NULL)) {
17407836SJohn.Forte@Sun.COM case iscsiAuthStatusContinue:
17417836SJohn.Forte@Sun.COM /*
17427836SJohn.Forte@Sun.COM * continue sending PDUs
17437836SJohn.Forte@Sun.COM */
17447836SJohn.Forte@Sun.COM break;
17457836SJohn.Forte@Sun.COM
17467836SJohn.Forte@Sun.COM case iscsiAuthStatusPass:
17477836SJohn.Forte@Sun.COM break;
17487836SJohn.Forte@Sun.COM
17497836SJohn.Forte@Sun.COM case iscsiAuthStatusInProgress:
17507836SJohn.Forte@Sun.COM /*
17517836SJohn.Forte@Sun.COM * this should only occur if we were authenticating the
17527836SJohn.Forte@Sun.COM * target, which we don't do yet, so treat this as an
17537836SJohn.Forte@Sun.COM * error.
17547836SJohn.Forte@Sun.COM */
17557836SJohn.Forte@Sun.COM case iscsiAuthStatusNoError:
17567836SJohn.Forte@Sun.COM /*
17577836SJohn.Forte@Sun.COM * treat this as an error, since we should get a
17587836SJohn.Forte@Sun.COM * different code
17597836SJohn.Forte@Sun.COM */
17607836SJohn.Forte@Sun.COM case iscsiAuthStatusError:
17617836SJohn.Forte@Sun.COM case iscsiAuthStatusFail:
17627836SJohn.Forte@Sun.COM default:
17637836SJohn.Forte@Sun.COM debug_status = 0;
17647836SJohn.Forte@Sun.COM
17657836SJohn.Forte@Sun.COM if (iscsiAuthClientGetDebugStatus(auth_client,
17667836SJohn.Forte@Sun.COM &debug_status) != iscsiAuthStatusNoError) {
17677836SJohn.Forte@Sun.COM
17687836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) login "
17697836SJohn.Forte@Sun.COM "failed - authentication failed with "
17707836SJohn.Forte@Sun.COM "target (%s)", icp->conn_oid,
17717836SJohn.Forte@Sun.COM iscsiAuthClientDebugStatusToText(
17727836SJohn.Forte@Sun.COM debug_status));
17737836SJohn.Forte@Sun.COM
17747836SJohn.Forte@Sun.COM } else {
17757836SJohn.Forte@Sun.COM
17767836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "iscsi connection(%u) login "
17777836SJohn.Forte@Sun.COM "failed - authentication failed with "
17787836SJohn.Forte@Sun.COM "target", icp->conn_oid);
17797836SJohn.Forte@Sun.COM
17807836SJohn.Forte@Sun.COM }
17817836SJohn.Forte@Sun.COM return (ISCSI_STATUS_AUTHENTICATION_FAILED);
17827836SJohn.Forte@Sun.COM }
17837836SJohn.Forte@Sun.COM }
17847836SJohn.Forte@Sun.COM
17857836SJohn.Forte@Sun.COM /*
17867836SJohn.Forte@Sun.COM * record some of the PDU fields for later use
17877836SJohn.Forte@Sun.COM */
17887836SJohn.Forte@Sun.COM isp->sess_tsid = ntohs(ilrhp->tsid);
17897836SJohn.Forte@Sun.COM isp->sess_expcmdsn = ntohl(ilrhp->expcmdsn);
17907836SJohn.Forte@Sun.COM isp->sess_maxcmdsn = ntohl(ilrhp->maxcmdsn);
17917836SJohn.Forte@Sun.COM if (ilrhp->status_class == ISCSI_STATUS_CLASS_SUCCESS) {
17927836SJohn.Forte@Sun.COM icp->conn_expstatsn = ntohl(ilrhp->statsn) + 1;
17937836SJohn.Forte@Sun.COM }
17947836SJohn.Forte@Sun.COM
17957836SJohn.Forte@Sun.COM if (transit) {
17967836SJohn.Forte@Sun.COM /*
17977836SJohn.Forte@Sun.COM * advance to the next stage
17987836SJohn.Forte@Sun.COM */
17997836SJohn.Forte@Sun.COM icp->conn_partial_response = 0;
18007836SJohn.Forte@Sun.COM icp->conn_current_stage =
18017836SJohn.Forte@Sun.COM ilrhp->flags & ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK;
18027836SJohn.Forte@Sun.COM } else {
18037836SJohn.Forte@Sun.COM /*
18047836SJohn.Forte@Sun.COM * we got a partial response, don't advance, more
18057836SJohn.Forte@Sun.COM * negotiation to do
18067836SJohn.Forte@Sun.COM */
18077836SJohn.Forte@Sun.COM icp->conn_partial_response = 1;
18087836SJohn.Forte@Sun.COM }
18097836SJohn.Forte@Sun.COM
18107836SJohn.Forte@Sun.COM /*
18117836SJohn.Forte@Sun.COM * this PDU is ok, though the login process
18127836SJohn.Forte@Sun.COM * may not be done yet
18137836SJohn.Forte@Sun.COM */
18147836SJohn.Forte@Sun.COM return (ISCSI_STATUS_SUCCESS);
18157836SJohn.Forte@Sun.COM }
18167836SJohn.Forte@Sun.COM
18177836SJohn.Forte@Sun.COM /*
18187836SJohn.Forte@Sun.COM * iscsi_add_text - caller is assumed to be well-behaved and passing NUL
18197836SJohn.Forte@Sun.COM * terminated strings
18207836SJohn.Forte@Sun.COM */
18217836SJohn.Forte@Sun.COM int
iscsi_add_text(idm_pdu_t * text_pdu,int max_data_length,char * param,char * value)18229162SPeter.Dunlap@Sun.COM iscsi_add_text(idm_pdu_t *text_pdu, int max_data_length,
18237836SJohn.Forte@Sun.COM char *param, char *value)
18247836SJohn.Forte@Sun.COM {
18257836SJohn.Forte@Sun.COM int param_len = 0;
18267836SJohn.Forte@Sun.COM int value_len = 0;
18277836SJohn.Forte@Sun.COM int length = 0;
18287836SJohn.Forte@Sun.COM int pdu_length = 0;
18297836SJohn.Forte@Sun.COM char *text = NULL;
18307836SJohn.Forte@Sun.COM char *end = NULL;
18317836SJohn.Forte@Sun.COM
18329162SPeter.Dunlap@Sun.COM ASSERT(text_pdu != NULL);
18337836SJohn.Forte@Sun.COM ASSERT(param != NULL);
18347836SJohn.Forte@Sun.COM ASSERT(value != NULL);
18357836SJohn.Forte@Sun.COM
18367836SJohn.Forte@Sun.COM param_len = strlen(param);
18377836SJohn.Forte@Sun.COM value_len = strlen(value);
18387836SJohn.Forte@Sun.COM /* param, separator, value, and trailing NULL */
18397836SJohn.Forte@Sun.COM length = param_len + 1 + value_len + 1;
18409162SPeter.Dunlap@Sun.COM pdu_length = text_pdu->isp_datalen;
18419162SPeter.Dunlap@Sun.COM text = (char *)text_pdu->isp_data + pdu_length;
18429162SPeter.Dunlap@Sun.COM end = (char *)text_pdu->isp_data + max_data_length;
18437836SJohn.Forte@Sun.COM pdu_length += length;
18447836SJohn.Forte@Sun.COM
18457836SJohn.Forte@Sun.COM if (text + length >= end) {
18467836SJohn.Forte@Sun.COM return (0);
18477836SJohn.Forte@Sun.COM }
18487836SJohn.Forte@Sun.COM
18497836SJohn.Forte@Sun.COM /* param */
18507836SJohn.Forte@Sun.COM (void) strncpy(text, param, param_len);
18517836SJohn.Forte@Sun.COM text += param_len;
18527836SJohn.Forte@Sun.COM
18537836SJohn.Forte@Sun.COM /* separator */
18547836SJohn.Forte@Sun.COM *text++ = ISCSI_TEXT_SEPARATOR;
18557836SJohn.Forte@Sun.COM
18567836SJohn.Forte@Sun.COM /* value */
18577836SJohn.Forte@Sun.COM (void) strncpy(text, value, value_len);
18587836SJohn.Forte@Sun.COM text += value_len;
18597836SJohn.Forte@Sun.COM
18607836SJohn.Forte@Sun.COM /* NULL */
18617836SJohn.Forte@Sun.COM *text++ = '\0';
18627836SJohn.Forte@Sun.COM
18637836SJohn.Forte@Sun.COM /* update the length in the PDU header */
18649162SPeter.Dunlap@Sun.COM text_pdu->isp_datalen = pdu_length;
18659162SPeter.Dunlap@Sun.COM hton24(text_pdu->isp_hdr->dlength, pdu_length);
18667836SJohn.Forte@Sun.COM
18677836SJohn.Forte@Sun.COM return (1);
18687836SJohn.Forte@Sun.COM }
18697836SJohn.Forte@Sun.COM
18707836SJohn.Forte@Sun.COM /*
18717836SJohn.Forte@Sun.COM * iscsi_get_next_text - get the next line of text from the given data
18727836SJohn.Forte@Sun.COM * buffer. This function searches from the address given for the
18737836SJohn.Forte@Sun.COM * curr_text parameter. If curr_text_parameter is NULL return first
18747836SJohn.Forte@Sun.COM * line in buffer. The return value is the address of the next line
18757836SJohn.Forte@Sun.COM * based upon where curr_text is located.
18767836SJohn.Forte@Sun.COM *
18777836SJohn.Forte@Sun.COM */
18787836SJohn.Forte@Sun.COM char *
iscsi_get_next_text(char * data,int max_data_length,char * curr_text)18797836SJohn.Forte@Sun.COM iscsi_get_next_text(char *data, int max_data_length, char *curr_text)
18807836SJohn.Forte@Sun.COM {
18817836SJohn.Forte@Sun.COM char *curr_data;
18827836SJohn.Forte@Sun.COM
18837836SJohn.Forte@Sun.COM ASSERT(data != NULL);
18847836SJohn.Forte@Sun.COM
18857836SJohn.Forte@Sun.COM /* check if any data exists, if not return */
18867836SJohn.Forte@Sun.COM if (max_data_length == 0) {
18877836SJohn.Forte@Sun.COM return (NULL);
18887836SJohn.Forte@Sun.COM }
18897836SJohn.Forte@Sun.COM
18907836SJohn.Forte@Sun.COM /* handle first call to this function */
18917836SJohn.Forte@Sun.COM if (curr_text == NULL) {
18927836SJohn.Forte@Sun.COM return (data);
18937836SJohn.Forte@Sun.COM }
18947836SJohn.Forte@Sun.COM
18957836SJohn.Forte@Sun.COM /* move to next text string */
18967836SJohn.Forte@Sun.COM curr_data = curr_text;
18977836SJohn.Forte@Sun.COM while ((curr_data < (data + max_data_length)) && *curr_data) {
18987836SJohn.Forte@Sun.COM curr_data++;
18997836SJohn.Forte@Sun.COM }
19007836SJohn.Forte@Sun.COM curr_data++; /* go past the NULL to the next entry */
19017836SJohn.Forte@Sun.COM
19027836SJohn.Forte@Sun.COM /* check whether data end reached */
19037836SJohn.Forte@Sun.COM if (curr_data >= (data + max_data_length)) {
19047836SJohn.Forte@Sun.COM return (NULL);
19057836SJohn.Forte@Sun.COM }
19067836SJohn.Forte@Sun.COM
19077836SJohn.Forte@Sun.COM return (curr_data);
19087836SJohn.Forte@Sun.COM }
19097836SJohn.Forte@Sun.COM
19107836SJohn.Forte@Sun.COM
19117836SJohn.Forte@Sun.COM /*
19127836SJohn.Forte@Sun.COM * iscsi_find_key_value -
19137836SJohn.Forte@Sun.COM *
19147836SJohn.Forte@Sun.COM */
19157836SJohn.Forte@Sun.COM static int
iscsi_find_key_value(char * param,char * ihp,char * pdu_end,char ** value_start,char ** value_end)19167836SJohn.Forte@Sun.COM iscsi_find_key_value(char *param, char *ihp, char *pdu_end,
19177836SJohn.Forte@Sun.COM char **value_start, char **value_end)
19187836SJohn.Forte@Sun.COM {
19197836SJohn.Forte@Sun.COM char *str = param;
19207836SJohn.Forte@Sun.COM char *text = ihp;
19217836SJohn.Forte@Sun.COM char *value = NULL;
19227836SJohn.Forte@Sun.COM
19237836SJohn.Forte@Sun.COM if (value_start)
19247836SJohn.Forte@Sun.COM *value_start = NULL;
19257836SJohn.Forte@Sun.COM if (value_end)
19267836SJohn.Forte@Sun.COM *value_end = NULL;
19277836SJohn.Forte@Sun.COM
19287836SJohn.Forte@Sun.COM /*
19297836SJohn.Forte@Sun.COM * make sure they contain the same bytes
19307836SJohn.Forte@Sun.COM */
19317836SJohn.Forte@Sun.COM while (*str) {
19327836SJohn.Forte@Sun.COM if (text >= pdu_end) {
19337836SJohn.Forte@Sun.COM return (0);
19347836SJohn.Forte@Sun.COM }
19357836SJohn.Forte@Sun.COM if (*text == '\0') {
19367836SJohn.Forte@Sun.COM return (0);
19377836SJohn.Forte@Sun.COM }
19387836SJohn.Forte@Sun.COM if (*str != *text) {
19397836SJohn.Forte@Sun.COM return (0);
19407836SJohn.Forte@Sun.COM }
19417836SJohn.Forte@Sun.COM str++;
19427836SJohn.Forte@Sun.COM text++;
19437836SJohn.Forte@Sun.COM }
19447836SJohn.Forte@Sun.COM
19457836SJohn.Forte@Sun.COM if ((text >= pdu_end) ||
19467836SJohn.Forte@Sun.COM (*text == '\0') ||
19477836SJohn.Forte@Sun.COM (*text != ISCSI_TEXT_SEPARATOR)) {
19487836SJohn.Forte@Sun.COM return (0);
19497836SJohn.Forte@Sun.COM }
19507836SJohn.Forte@Sun.COM
19517836SJohn.Forte@Sun.COM /*
19527836SJohn.Forte@Sun.COM * find the value
19537836SJohn.Forte@Sun.COM */
19547836SJohn.Forte@Sun.COM value = text + 1;
19557836SJohn.Forte@Sun.COM
19567836SJohn.Forte@Sun.COM /*
19577836SJohn.Forte@Sun.COM * find the end of the value
19587836SJohn.Forte@Sun.COM */
19597836SJohn.Forte@Sun.COM while ((text < pdu_end) && (*text))
19607836SJohn.Forte@Sun.COM text++;
19617836SJohn.Forte@Sun.COM
19627836SJohn.Forte@Sun.COM if (value_start)
19637836SJohn.Forte@Sun.COM *value_start = value;
19647836SJohn.Forte@Sun.COM if (value_end)
19657836SJohn.Forte@Sun.COM *value_end = text;
19667836SJohn.Forte@Sun.COM
19677836SJohn.Forte@Sun.COM return (1);
19687836SJohn.Forte@Sun.COM }
19697836SJohn.Forte@Sun.COM
19707836SJohn.Forte@Sun.COM
19717836SJohn.Forte@Sun.COM /*
19727836SJohn.Forte@Sun.COM * iscsi_update_address - This function is used on a login redirection.
19737836SJohn.Forte@Sun.COM * During the login redirection we are asked to switch to an IP address
19747836SJohn.Forte@Sun.COM * port different than the one we were logging into.
19757836SJohn.Forte@Sun.COM */
19767836SJohn.Forte@Sun.COM static iscsi_status_t
iscsi_update_address(iscsi_conn_t * icp,char * in)19777836SJohn.Forte@Sun.COM iscsi_update_address(iscsi_conn_t *icp, char *in)
19787836SJohn.Forte@Sun.COM {
19797836SJohn.Forte@Sun.COM char *addr_str, *port_str, *tpgt_str;
19807836SJohn.Forte@Sun.COM int type;
19817836SJohn.Forte@Sun.COM struct hostent *hptr;
19827836SJohn.Forte@Sun.COM unsigned long tmp;
19837836SJohn.Forte@Sun.COM int error_num;
19847836SJohn.Forte@Sun.COM int port;
19857836SJohn.Forte@Sun.COM
19867836SJohn.Forte@Sun.COM ASSERT(icp != NULL);
19877836SJohn.Forte@Sun.COM ASSERT(in != NULL);
19887836SJohn.Forte@Sun.COM
19897836SJohn.Forte@Sun.COM /* parse login redirection response */
19907836SJohn.Forte@Sun.COM if (parse_addr_port_tpgt(in, &addr_str, &type,
19917836SJohn.Forte@Sun.COM &port_str, &tpgt_str) == B_FALSE) {
19927836SJohn.Forte@Sun.COM return (ISCSI_STATUS_PROTOCOL_ERROR);
19937836SJohn.Forte@Sun.COM }
19947836SJohn.Forte@Sun.COM
19957836SJohn.Forte@Sun.COM /* convert addr_str */
19967836SJohn.Forte@Sun.COM hptr = kgetipnodebyname(addr_str, type, AI_ALL, &error_num);
19977836SJohn.Forte@Sun.COM if (!hptr) {
19987836SJohn.Forte@Sun.COM return (ISCSI_STATUS_PROTOCOL_ERROR);
19997836SJohn.Forte@Sun.COM }
20007836SJohn.Forte@Sun.COM
20017836SJohn.Forte@Sun.COM /* convert port_str */
20027836SJohn.Forte@Sun.COM if (port_str != NULL) {
20037836SJohn.Forte@Sun.COM (void) ddi_strtoul(port_str, NULL, 0, &tmp);
20047836SJohn.Forte@Sun.COM port = (int)tmp;
20057836SJohn.Forte@Sun.COM } else {
20067836SJohn.Forte@Sun.COM port = ISCSI_LISTEN_PORT;
20077836SJohn.Forte@Sun.COM }
20087836SJohn.Forte@Sun.COM
20097836SJohn.Forte@Sun.COM iscsid_addr_to_sockaddr(hptr->h_length, *hptr->h_addr_list,
20107836SJohn.Forte@Sun.COM port, &icp->conn_curr_addr.sin);
20117836SJohn.Forte@Sun.COM
20127836SJohn.Forte@Sun.COM kfreehostent(hptr);
20137836SJohn.Forte@Sun.COM return (ISCSI_STATUS_SUCCESS);
20147836SJohn.Forte@Sun.COM }
20157836SJohn.Forte@Sun.COM
20169162SPeter.Dunlap@Sun.COM void
iscsi_login_update_state(iscsi_conn_t * icp,iscsi_login_state_t next_state)20179162SPeter.Dunlap@Sun.COM iscsi_login_update_state(iscsi_conn_t *icp, iscsi_login_state_t next_state)
20189162SPeter.Dunlap@Sun.COM {
20199162SPeter.Dunlap@Sun.COM mutex_enter(&icp->conn_login_mutex);
20209162SPeter.Dunlap@Sun.COM (void) iscsi_login_update_state_locked(icp, next_state);
20219162SPeter.Dunlap@Sun.COM mutex_exit(&icp->conn_login_mutex);
20229162SPeter.Dunlap@Sun.COM }
20239162SPeter.Dunlap@Sun.COM
20249162SPeter.Dunlap@Sun.COM void
iscsi_login_update_state_locked(iscsi_conn_t * icp,iscsi_login_state_t next_state)20259162SPeter.Dunlap@Sun.COM iscsi_login_update_state_locked(iscsi_conn_t *icp,
20269162SPeter.Dunlap@Sun.COM iscsi_login_state_t next_state)
20279162SPeter.Dunlap@Sun.COM {
20289162SPeter.Dunlap@Sun.COM ASSERT(mutex_owned(&icp->conn_login_mutex));
20299162SPeter.Dunlap@Sun.COM next_state = (next_state > LOGIN_MAX) ? LOGIN_MAX : next_state;
20309162SPeter.Dunlap@Sun.COM idm_sm_audit_state_change(&icp->conn_state_audit,
20319162SPeter.Dunlap@Sun.COM SAS_ISCSI_LOGIN, icp->conn_login_state, next_state);
20329162SPeter.Dunlap@Sun.COM
20339162SPeter.Dunlap@Sun.COM ISCSI_LOGIN_LOG(CE_NOTE, "iscsi_login_update_state conn %p %d -> %d",
20349162SPeter.Dunlap@Sun.COM (void *)icp, icp->conn_login_state, next_state);
20359162SPeter.Dunlap@Sun.COM
20369162SPeter.Dunlap@Sun.COM icp->conn_login_state = next_state;
20379162SPeter.Dunlap@Sun.COM cv_broadcast(&icp->conn_login_cv);
20389162SPeter.Dunlap@Sun.COM }
20399162SPeter.Dunlap@Sun.COM
20409162SPeter.Dunlap@Sun.COM
20417836SJohn.Forte@Sun.COM
20427836SJohn.Forte@Sun.COM /*
20437836SJohn.Forte@Sun.COM * iscsi_null_callback - This callback may be used under certain
20447836SJohn.Forte@Sun.COM * conditions when authenticating a target, but I'm not sure what
20457836SJohn.Forte@Sun.COM * we need to do here.
20467836SJohn.Forte@Sun.COM */
20477836SJohn.Forte@Sun.COM /* ARGSUSED */
20487836SJohn.Forte@Sun.COM static void
iscsi_null_callback(void * user_handle,void * message_handle,int auth_status)20497836SJohn.Forte@Sun.COM iscsi_null_callback(void *user_handle, void *message_handle, int auth_status)
20507836SJohn.Forte@Sun.COM {
20517836SJohn.Forte@Sun.COM }
20527836SJohn.Forte@Sun.COM
20537836SJohn.Forte@Sun.COM
20547836SJohn.Forte@Sun.COM /*
20557836SJohn.Forte@Sun.COM * iscsi_login_failure_str -
20567836SJohn.Forte@Sun.COM *
20577836SJohn.Forte@Sun.COM */
20587836SJohn.Forte@Sun.COM static char *
iscsi_login_failure_str(uchar_t status_class,uchar_t status_detail)20597836SJohn.Forte@Sun.COM iscsi_login_failure_str(uchar_t status_class, uchar_t status_detail)
20607836SJohn.Forte@Sun.COM {
20617836SJohn.Forte@Sun.COM switch (status_class) {
20627836SJohn.Forte@Sun.COM case 0x00:
20637836SJohn.Forte@Sun.COM switch (status_detail) {
20647836SJohn.Forte@Sun.COM case 0x00:
20657836SJohn.Forte@Sun.COM return ("Login is proceeding okay.");
20667836SJohn.Forte@Sun.COM default:
20677836SJohn.Forte@Sun.COM break;
20687836SJohn.Forte@Sun.COM }
20697836SJohn.Forte@Sun.COM case 0x01:
20707836SJohn.Forte@Sun.COM switch (status_detail) {
20717836SJohn.Forte@Sun.COM case 0x01:
20727836SJohn.Forte@Sun.COM return ("Requested ITN has moved temporarily to "
20737836SJohn.Forte@Sun.COM "the address provided.");
20747836SJohn.Forte@Sun.COM case 0x02:
20757836SJohn.Forte@Sun.COM return ("Requested ITN has moved permanently to "
20767836SJohn.Forte@Sun.COM "the address provided.");
20777836SJohn.Forte@Sun.COM default:
20787836SJohn.Forte@Sun.COM break;
20797836SJohn.Forte@Sun.COM }
20807836SJohn.Forte@Sun.COM case 0x02:
20817836SJohn.Forte@Sun.COM switch (status_detail) {
20827836SJohn.Forte@Sun.COM case 0x00:
20837836SJohn.Forte@Sun.COM return ("Miscellaneous iSCSI initiator errors.");
20847836SJohn.Forte@Sun.COM case 0x01:
20857836SJohn.Forte@Sun.COM return ("Initiator could not be successfully "
20867836SJohn.Forte@Sun.COM "authenticated.");
20877836SJohn.Forte@Sun.COM case 0x02:
20887836SJohn.Forte@Sun.COM return ("Initiator is not allowed access to the "
20897836SJohn.Forte@Sun.COM "given target.");
20907836SJohn.Forte@Sun.COM case 0x03:
20917836SJohn.Forte@Sun.COM return ("Requested ITN does not exist at this "
20927836SJohn.Forte@Sun.COM "address.");
20937836SJohn.Forte@Sun.COM case 0x04:
20947836SJohn.Forte@Sun.COM return ("Requested ITN has been removed and no "
20957836SJohn.Forte@Sun.COM "forwarding address is provided.");
20967836SJohn.Forte@Sun.COM case 0x05:
20977836SJohn.Forte@Sun.COM return ("Requested iSCSI version range is not "
20987836SJohn.Forte@Sun.COM "supported by the target.");
20997836SJohn.Forte@Sun.COM case 0x06:
21007836SJohn.Forte@Sun.COM return ("No more connections can be accepted on "
21017836SJohn.Forte@Sun.COM "this Session ID (SSID).");
21027836SJohn.Forte@Sun.COM case 0x07:
21037836SJohn.Forte@Sun.COM return ("Missing parameters (e.g., iSCSI initiator "
21047836SJohn.Forte@Sun.COM "and/or target name).");
21057836SJohn.Forte@Sun.COM case 0x08:
21067836SJohn.Forte@Sun.COM return ("Target does not support session spanning "
21077836SJohn.Forte@Sun.COM "to this connection (address).");
21087836SJohn.Forte@Sun.COM case 0x09:
21097836SJohn.Forte@Sun.COM return ("Target does not support this type of "
21107836SJohn.Forte@Sun.COM "session or not from this initiator.");
21117836SJohn.Forte@Sun.COM case 0x0A:
21127836SJohn.Forte@Sun.COM return ("Attempt to add a connection to a "
21137836SJohn.Forte@Sun.COM "nonexistent session.");
21147836SJohn.Forte@Sun.COM case 0x0B:
21157836SJohn.Forte@Sun.COM return ("Invalid request type during login.");
21167836SJohn.Forte@Sun.COM default:
21177836SJohn.Forte@Sun.COM break;
21187836SJohn.Forte@Sun.COM }
21197836SJohn.Forte@Sun.COM case 0x03:
21207836SJohn.Forte@Sun.COM switch (status_detail) {
21217836SJohn.Forte@Sun.COM case 0x00:
21227836SJohn.Forte@Sun.COM return ("Target hardware or software error.");
21237836SJohn.Forte@Sun.COM case 0x01:
21247836SJohn.Forte@Sun.COM return ("iSCSI service or target is not currently "
21257836SJohn.Forte@Sun.COM "operational.");
21267836SJohn.Forte@Sun.COM case 0x02:
21277836SJohn.Forte@Sun.COM return ("Target has insufficient session, connection "
21287836SJohn.Forte@Sun.COM "or other resources.");
21297836SJohn.Forte@Sun.COM default:
21307836SJohn.Forte@Sun.COM break;
21317836SJohn.Forte@Sun.COM }
21327836SJohn.Forte@Sun.COM }
21337836SJohn.Forte@Sun.COM return ("Unknown login response received.");
21347836SJohn.Forte@Sun.COM }
21357836SJohn.Forte@Sun.COM
21367836SJohn.Forte@Sun.COM
21377836SJohn.Forte@Sun.COM /*
21387836SJohn.Forte@Sun.COM * iscsi_login_connect -
21397836SJohn.Forte@Sun.COM */
21407836SJohn.Forte@Sun.COM static iscsi_status_t
iscsi_login_connect(iscsi_conn_t * icp)21417836SJohn.Forte@Sun.COM iscsi_login_connect(iscsi_conn_t *icp)
21427836SJohn.Forte@Sun.COM {
21438348SEric.Yu@Sun.COM iscsi_hba_t *ihp;
21448348SEric.Yu@Sun.COM iscsi_sess_t *isp;
21458348SEric.Yu@Sun.COM struct sockaddr *addr;
21469162SPeter.Dunlap@Sun.COM idm_conn_req_t cr;
21479162SPeter.Dunlap@Sun.COM idm_status_t rval;
214811066Srafael.vanoni@sun.com clock_t lbolt;
21497836SJohn.Forte@Sun.COM
21507836SJohn.Forte@Sun.COM ASSERT(icp != NULL);
21517836SJohn.Forte@Sun.COM isp = icp->conn_sess;
21527836SJohn.Forte@Sun.COM ASSERT(isp != NULL);
21537836SJohn.Forte@Sun.COM ihp = isp->sess_hba;
21547836SJohn.Forte@Sun.COM ASSERT(ihp != NULL);
21557836SJohn.Forte@Sun.COM addr = &icp->conn_curr_addr.sin;
21567836SJohn.Forte@Sun.COM
21577836SJohn.Forte@Sun.COM /* Make sure that scope_id is zero if it is an IPv6 address */
21587836SJohn.Forte@Sun.COM if (addr->sa_family == AF_INET6) {
21597836SJohn.Forte@Sun.COM ((struct sockaddr_in6 *)addr)->sin6_scope_id = 0;
21607836SJohn.Forte@Sun.COM }
21617836SJohn.Forte@Sun.COM
21629162SPeter.Dunlap@Sun.COM /* delay the connect process if required */
21639162SPeter.Dunlap@Sun.COM lbolt = ddi_get_lbolt();
21649162SPeter.Dunlap@Sun.COM if (lbolt < icp->conn_login_min) {
216510156SZhang.Yi@Sun.COM if (icp->conn_login_max < icp->conn_login_min) {
216610156SZhang.Yi@Sun.COM delay(icp->conn_login_max - lbolt);
216710156SZhang.Yi@Sun.COM } else {
216810156SZhang.Yi@Sun.COM delay(icp->conn_login_min - lbolt);
216910156SZhang.Yi@Sun.COM }
21709162SPeter.Dunlap@Sun.COM }
21719162SPeter.Dunlap@Sun.COM
21729162SPeter.Dunlap@Sun.COM /* Create IDM connection context */
21739162SPeter.Dunlap@Sun.COM cr.cr_domain = addr->sa_family;
21749162SPeter.Dunlap@Sun.COM cr.cr_type = SOCK_STREAM;
21759162SPeter.Dunlap@Sun.COM cr.cr_protocol = 0;
21769162SPeter.Dunlap@Sun.COM cr.cr_bound = icp->conn_bound;
21779162SPeter.Dunlap@Sun.COM cr.cr_li = icp->conn_sess->sess_hba->hba_li;
21789162SPeter.Dunlap@Sun.COM cr.icr_conn_ops.icb_rx_misc = &iscsi_rx_misc_pdu;
21799162SPeter.Dunlap@Sun.COM cr.icr_conn_ops.icb_rx_error = &iscsi_rx_error_pdu;
21809162SPeter.Dunlap@Sun.COM cr.icr_conn_ops.icb_rx_scsi_rsp = &iscsi_rx_scsi_rsp;
21819162SPeter.Dunlap@Sun.COM cr.icr_conn_ops.icb_client_notify = &iscsi_client_notify;
21829162SPeter.Dunlap@Sun.COM cr.icr_conn_ops.icb_build_hdr = &iscsi_build_hdr;
21839162SPeter.Dunlap@Sun.COM cr.icr_conn_ops.icb_task_aborted = &iscsi_task_aborted;
21849162SPeter.Dunlap@Sun.COM bcopy(addr, &cr.cr_ini_dst_addr,
21859162SPeter.Dunlap@Sun.COM sizeof (cr.cr_ini_dst_addr));
21869162SPeter.Dunlap@Sun.COM bcopy(&icp->conn_bound_addr, &cr.cr_bound_addr,
21879162SPeter.Dunlap@Sun.COM sizeof (cr.cr_bound_addr));
218810822SJack.Meng@Sun.COM if (isp->sess_boot == B_TRUE) {
218910822SJack.Meng@Sun.COM cr.cr_boot_conn = B_TRUE;
219010822SJack.Meng@Sun.COM } else {
219110822SJack.Meng@Sun.COM cr.cr_boot_conn = B_FALSE;
219210822SJack.Meng@Sun.COM }
21937836SJohn.Forte@Sun.COM
21949162SPeter.Dunlap@Sun.COM /*
21959162SPeter.Dunlap@Sun.COM * Allocate IDM connection context
21969162SPeter.Dunlap@Sun.COM */
21979162SPeter.Dunlap@Sun.COM rval = idm_ini_conn_create(&cr, &icp->conn_ic);
21989162SPeter.Dunlap@Sun.COM if (rval != IDM_STATUS_SUCCESS) {
21999162SPeter.Dunlap@Sun.COM return (ISCSI_STATUS_LOGIN_FAILED);
22009162SPeter.Dunlap@Sun.COM }
22019162SPeter.Dunlap@Sun.COM
22029162SPeter.Dunlap@Sun.COM icp->conn_ic->ic_handle = icp;
22039162SPeter.Dunlap@Sun.COM
22049162SPeter.Dunlap@Sun.COM /*
22059162SPeter.Dunlap@Sun.COM * About to initiate connect, reset login state.
22069162SPeter.Dunlap@Sun.COM */
22079162SPeter.Dunlap@Sun.COM iscsi_login_update_state(icp, LOGIN_START);
22089162SPeter.Dunlap@Sun.COM
22099162SPeter.Dunlap@Sun.COM /*
22109162SPeter.Dunlap@Sun.COM * Make sure the connection doesn't go away until we are done with it.
22119162SPeter.Dunlap@Sun.COM * This hold will prevent us from receiving a CN_CONNECT_DESTROY
22129162SPeter.Dunlap@Sun.COM * notification on this connection until we are ready.
22139162SPeter.Dunlap@Sun.COM */
22149162SPeter.Dunlap@Sun.COM idm_conn_hold(icp->conn_ic);
22159162SPeter.Dunlap@Sun.COM
22169162SPeter.Dunlap@Sun.COM /*
221710156SZhang.Yi@Sun.COM * When iSCSI initiator to target IO timeout or connection failure
221810156SZhang.Yi@Sun.COM * Connection retry is needed for normal operational session.
221910156SZhang.Yi@Sun.COM */
222010156SZhang.Yi@Sun.COM if ((icp->conn_sess->sess_type == ISCSI_SESS_TYPE_NORMAL) &&
222110156SZhang.Yi@Sun.COM ((icp->conn_state == ISCSI_CONN_STATE_FAILED) ||
222210156SZhang.Yi@Sun.COM (icp->conn_state == ISCSI_CONN_STATE_POLLING))) {
222310156SZhang.Yi@Sun.COM icp->conn_ic->ic_conn_params.nonblock_socket = B_TRUE;
222410156SZhang.Yi@Sun.COM icp->conn_ic->ic_conn_params.conn_login_max =
222510156SZhang.Yi@Sun.COM icp->conn_login_max;
222610156SZhang.Yi@Sun.COM if (icp->conn_state == ISCSI_CONN_STATE_POLLING) {
222710156SZhang.Yi@Sun.COM icp->conn_ic->ic_conn_params.conn_login_interval =
222810156SZhang.Yi@Sun.COM icp->conn_tunable_params.polling_login_delay;
222910156SZhang.Yi@Sun.COM } else {
223010156SZhang.Yi@Sun.COM icp->conn_ic->ic_conn_params.conn_login_interval =
223110156SZhang.Yi@Sun.COM ISCSI_LOGIN_RETRY_DELAY;
223210156SZhang.Yi@Sun.COM }
223310156SZhang.Yi@Sun.COM
223410156SZhang.Yi@Sun.COM } else {
223510156SZhang.Yi@Sun.COM icp->conn_ic->ic_conn_params.nonblock_socket = B_FALSE;
223610156SZhang.Yi@Sun.COM icp->conn_ic->ic_conn_params.conn_login_max = 0;
223710156SZhang.Yi@Sun.COM icp->conn_ic->ic_conn_params.conn_login_interval = 0;
223810156SZhang.Yi@Sun.COM }
223910156SZhang.Yi@Sun.COM /*
22409162SPeter.Dunlap@Sun.COM * Attempt connection. Upon return we will either be ready to
22419162SPeter.Dunlap@Sun.COM * login or disconnected. If idm_ini_conn_connect fails we
22429162SPeter.Dunlap@Sun.COM * will eventually receive a CN_CONNECT_DESTROY at which point
22439162SPeter.Dunlap@Sun.COM * we will destroy the connection allocated above (so there
22449162SPeter.Dunlap@Sun.COM * is no need to explicitly free it here).
22459162SPeter.Dunlap@Sun.COM */
22469162SPeter.Dunlap@Sun.COM rval = idm_ini_conn_connect(icp->conn_ic);
22479162SPeter.Dunlap@Sun.COM
22489162SPeter.Dunlap@Sun.COM if (rval != IDM_STATUS_SUCCESS) {
22497836SJohn.Forte@Sun.COM cmn_err(CE_NOTE, "iscsi connection(%u) unable to "
22507836SJohn.Forte@Sun.COM "connect to target %s", icp->conn_oid,
22517836SJohn.Forte@Sun.COM icp->conn_sess->sess_name);
22529162SPeter.Dunlap@Sun.COM idm_conn_rele(icp->conn_ic);
22537836SJohn.Forte@Sun.COM }
22547836SJohn.Forte@Sun.COM
22559162SPeter.Dunlap@Sun.COM return (rval == IDM_STATUS_SUCCESS ?
22569162SPeter.Dunlap@Sun.COM ISCSI_STATUS_SUCCESS : ISCSI_STATUS_INTERNAL_ERROR);
22579162SPeter.Dunlap@Sun.COM }
22589162SPeter.Dunlap@Sun.COM
22599162SPeter.Dunlap@Sun.COM /*
22609162SPeter.Dunlap@Sun.COM * iscsi_login_disconnect
22619162SPeter.Dunlap@Sun.COM */
22629162SPeter.Dunlap@Sun.COM static void
iscsi_login_disconnect(iscsi_conn_t * icp)22639162SPeter.Dunlap@Sun.COM iscsi_login_disconnect(iscsi_conn_t *icp)
22649162SPeter.Dunlap@Sun.COM {
22659162SPeter.Dunlap@Sun.COM /* Tell IDM to disconnect is if we are not already disconnect */
22669162SPeter.Dunlap@Sun.COM idm_ini_conn_disconnect_sync(icp->conn_ic);
22679162SPeter.Dunlap@Sun.COM
22689162SPeter.Dunlap@Sun.COM /*
22699162SPeter.Dunlap@Sun.COM * The function above may return before the CN_CONNECT_LOST
22709162SPeter.Dunlap@Sun.COM * notification. Wait for it.
22719162SPeter.Dunlap@Sun.COM */
22729162SPeter.Dunlap@Sun.COM mutex_enter(&icp->conn_state_mutex);
22739162SPeter.Dunlap@Sun.COM while (icp->conn_state_idm_connected)
22749162SPeter.Dunlap@Sun.COM cv_wait(&icp->conn_state_change,
22759162SPeter.Dunlap@Sun.COM &icp->conn_state_mutex);
22769162SPeter.Dunlap@Sun.COM mutex_exit(&icp->conn_state_mutex);
22779162SPeter.Dunlap@Sun.COM }
22789162SPeter.Dunlap@Sun.COM
22799162SPeter.Dunlap@Sun.COM /*
22809162SPeter.Dunlap@Sun.COM * iscsi_notice_key_values - Create an nvlist containing the values
22819162SPeter.Dunlap@Sun.COM * that have been negotiated for this connection and pass them down to
22829162SPeter.Dunlap@Sun.COM * IDM so it can pick up any values that are important.
22839162SPeter.Dunlap@Sun.COM */
22849162SPeter.Dunlap@Sun.COM static void
iscsi_notice_key_values(iscsi_conn_t * icp)22859162SPeter.Dunlap@Sun.COM iscsi_notice_key_values(iscsi_conn_t *icp)
22869162SPeter.Dunlap@Sun.COM {
22879162SPeter.Dunlap@Sun.COM nvlist_t *neg_nvl;
22889162SPeter.Dunlap@Sun.COM int rc;
22899162SPeter.Dunlap@Sun.COM
22909162SPeter.Dunlap@Sun.COM rc = nvlist_alloc(&neg_nvl, NV_UNIQUE_NAME, KM_SLEEP);
22919162SPeter.Dunlap@Sun.COM ASSERT(rc == 0);
22929162SPeter.Dunlap@Sun.COM
22939162SPeter.Dunlap@Sun.COM /* Only crc32c is supported so the digest logic is simple */
22949162SPeter.Dunlap@Sun.COM if (icp->conn_params.header_digest) {
22959162SPeter.Dunlap@Sun.COM rc = nvlist_add_string(neg_nvl, "HeaderDigest", "crc32c");
22969162SPeter.Dunlap@Sun.COM } else {
22979162SPeter.Dunlap@Sun.COM rc = nvlist_add_string(neg_nvl, "HeaderDigest", "none");
22987836SJohn.Forte@Sun.COM }
22999162SPeter.Dunlap@Sun.COM ASSERT(rc == 0);
23007836SJohn.Forte@Sun.COM
23019162SPeter.Dunlap@Sun.COM if (icp->conn_params.data_digest) {
23029162SPeter.Dunlap@Sun.COM rc = nvlist_add_string(neg_nvl, "DataDigest", "crc32c");
23039162SPeter.Dunlap@Sun.COM } else {
23049162SPeter.Dunlap@Sun.COM rc = nvlist_add_string(neg_nvl, "DataDigest", "none");
23059162SPeter.Dunlap@Sun.COM }
23069162SPeter.Dunlap@Sun.COM ASSERT(rc == 0);
23079162SPeter.Dunlap@Sun.COM
23089162SPeter.Dunlap@Sun.COM rc = nvlist_add_uint64(neg_nvl, "MaxRecvDataSegmentLength",
23099162SPeter.Dunlap@Sun.COM (uint64_t)icp->conn_params.max_recv_data_seg_len);
23109162SPeter.Dunlap@Sun.COM ASSERT(rc == 0);
23119162SPeter.Dunlap@Sun.COM
23129162SPeter.Dunlap@Sun.COM rc = nvlist_add_uint64(neg_nvl, "MaxBurstLength",
23139162SPeter.Dunlap@Sun.COM (uint64_t)icp->conn_params.max_burst_length);
23149162SPeter.Dunlap@Sun.COM ASSERT(rc == 0);
23159162SPeter.Dunlap@Sun.COM
23169162SPeter.Dunlap@Sun.COM rc = nvlist_add_uint64(neg_nvl, "MaxOutstandingR2T",
23179162SPeter.Dunlap@Sun.COM (uint64_t)icp->conn_params.max_outstanding_r2t);
23189162SPeter.Dunlap@Sun.COM ASSERT(rc == 0);
23199162SPeter.Dunlap@Sun.COM
23209162SPeter.Dunlap@Sun.COM rc = nvlist_add_uint64(neg_nvl, "ErrorRecoveryLevel",
23219162SPeter.Dunlap@Sun.COM (uint64_t)icp->conn_params.error_recovery_level);
23229162SPeter.Dunlap@Sun.COM ASSERT(rc == 0);
23239162SPeter.Dunlap@Sun.COM
23249162SPeter.Dunlap@Sun.COM rc = nvlist_add_uint64(neg_nvl, "DefaultTime2Wait",
23259162SPeter.Dunlap@Sun.COM (uint64_t)icp->conn_params.default_time_to_wait);
23269162SPeter.Dunlap@Sun.COM ASSERT(rc == 0);
23279162SPeter.Dunlap@Sun.COM
23289162SPeter.Dunlap@Sun.COM rc = nvlist_add_uint64(neg_nvl, "DefaultTime2Retain",
23299162SPeter.Dunlap@Sun.COM (uint64_t)icp->conn_params.default_time_to_retain);
23309162SPeter.Dunlap@Sun.COM ASSERT(rc == 0);
23319162SPeter.Dunlap@Sun.COM
23329162SPeter.Dunlap@Sun.COM /* Pass the list to IDM to examine, then free it */
23339162SPeter.Dunlap@Sun.COM idm_notice_key_values(icp->conn_ic, neg_nvl);
23349162SPeter.Dunlap@Sun.COM nvlist_free(neg_nvl);
23357836SJohn.Forte@Sun.COM }
2336