--- /dev/null Fri Apr 4 13:31:04 2008 +++ new/src/sun_nws/comstar/port_providers/iscsit/hdrs/iscsit.h Fri Apr 4 13:31:04 2008 @@ -0,0 +1,505 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at src/sun_nws/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at src/sun_nws/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +#ifndef _ISCSIT_H_ +#define _ISCSIT_H_ + +#pragma ident "@(#)iscsit.h 1.15 08/03/28 SMI" + +#include "iscsit_authclient.h" + +/* + * For some reason iscsi_protocol.h lists the max version as "0x02" and the + * min version as "0x00". RFC3720 clearly states that the current version + * number is 0x00 so that is what we will use. + */ +#define ISCSIT_MIN_VERSION 0x00 +#define ISCSIT_MAX_VERSION 0x00 +#define ISCSIT_MAX_CONNECTIONS 1 /* No MC/S support */ +#define ISCSIT_MAX_RECV_DATA_SEGMENT_LENGTH (32*1024) +#define ISCSIT_MAX_BURST_LENGTH (512*1024) +#define ISCSIT_MAX_FIRST_BURST_LENGTH ISCSI_DEFAULT_FIRST_BURST_LENGTH +#define ISCSIT_MAX_TIME2WAIT ISCSI_DEFAULT_TIME_TO_WAIT +#define ISCSIT_MAX_TIME2RETAIN ISCSI_DEFAULT_TIME_TO_RETAIN +/* XXX We want to increase max outstanding R2T at some point for performance */ +#define ISCSIT_MAX_OUTSTANDING_R2T ISCSI_DEFAULT_MAX_OUT_R2T +#define ISCSIT_MAX_ERROR_RECOVERY_LEVEL 0 + +#define ISCSIT_DEFAULT_TPG "iscsit-default-tpg" +#define ISCSIT_DEFAULT_TPGT 1 + +#define ISCSI_MAX_TSIH 0xffff +#define ISCSI_UNSPEC_TSIH 0 + +#define ISCSIT_GLOBAL_LOCK() mutex_enter(&iscsit_global.global_mutex) +#define ISCSIT_GLOBAL_UNLOCK() mutex_exit(&iscsit_global.global_mutex) + +typedef struct { + char *tpg_name; + kmutex_t tpg_mutex; + int tpg_online; + avl_tree_t tpg_portal_list; + avl_node_t tpg_global_ln; +} iscsit_tpg_t; + +typedef struct { + iscsit_tpg_t *tpgt_tpg; + avl_node_t tpgt_tgt_ln; + uint16_t tpgt_tag; +} iscsit_tpgt_t; + +typedef struct { + struct sockaddr_storage portal_addr; + uint16_t portal_port; + int portal_online; + avl_node_t portal_tpg_ln; + iscsit_tpg_t *portal_tpg; + idm_svc_t *portal_svc; +} iscsit_portal_t; + + +#define ISCSIT_TEMP_TARGET_NAME "eui.abcd001122334455" + +typedef struct { + char *target_name; + kmutex_t target_mutex; + avl_tree_t target_tpgt_list; + avl_tree_t target_sess_list; + avl_node_t target_global_ln; + /* STMF lport == iSCSI target */ + scsi_devid_desc_t *target_devid; + stmf_local_port_t *target_stmf_lport; + uint8_t target_stmf_state; + uint8_t target_stmf_state_not_acked; +} iscsit_tgt_t; + +/* + * iSCSI Auth Information + */ +typedef struct sess_auth { + /* Initiator's authentication information. */ + char username[iscsiAuthStringMaxLength]; + uint8_t password[iscsiAuthStringMaxLength]; + int password_length; + + /* Target's authentication information. */ + char username_in[iscsiAuthStringMaxLength]; + uint8_t password_in[iscsiAuthStringMaxLength]; + int password_length_in; + + /* authentication method list */ + int authMethodValidList[iscsiAuthMethodMaxCount]; +} sess_auth_t; + +/* + * We have three state machines (so far) between the IDM connection state + * machine, the session state machine, and the login state machine. All + * of these states have some concept of "full feature mode". It's going + * to be obnoxious if we use a mixture of these "ffp" representations + * since it will be difficult to ensure the three state machines + * transition at exactly the same time. We should drive decisions that + * depend on FFP from the IDM state machine which is actually snooping + * the iSCSI PDU's and will always transition at the correct time. + * + * A consequence of this approach is that there is a window just after + * login completes where we may get a SCSI request but the session + * or login state machine has not quite transitioned to "FFP". Whether + * this is a problem depends on how we use those state machines. This + * is what we should use them for: + * + * IDM Connection state machine - Decisions related to command processing + * including whether a connection is in FFP + * + * Session state machine - Summarize the state of all available connections + * for the purposes of ERL1, ERL2 and MC/S. A session in LOGGED_IN state + * should always have at least one FFP connection but there may be a brief + * window where a session in ACTIVE might have one or more FFP connections + * even though ACTIVE is not strictly an FFP state according to the RFC. + * + * Login state machine -- drive the login process, collect negotiated + * parameters. Another side effect of this approach is that we may get + * the "notify ffp" callback from the IDM connection state machine before + * the login state machine has actually transitioned to FFP state. + */ + +struct iscsit_conn_s; + +/* Update iscsit_ss_name table whenever session states are modified */ +typedef enum { + SS_UNDEFINED = 0, + SS_Q1_FREE, + SS_Q2_ACTIVE, + SS_Q3_LOGGED_IN, + SS_Q4_FAILED, + SS_Q5_CONTINUE, + SS_Q6_DONE, + SS_Q7_ERROR, + SS_MAX_STATE +} iscsit_session_state_t; + +/* Update iscsit_se_name table whenever session events are modified */ +typedef enum { + SE_UNDEFINED = 0, + SE_CONN_IN_LOGIN, /* From login state machine */ + SE_CONN_LOGGED_IN, /* FFP enabled client notification */ + SE_CONN_FFP_FAIL, /* FFP disabled client notification */ + SE_CONN_FAIL, /* Conn destroy client notification */ + SE_SESSION_CLOSE, /* From Logout PDU handler */ + SE_SESSION_REINSTATE, /* From login state machine */ + SE_SESSION_TIMEOUT, /* Internal? */ + SE_SESSION_CONTINUE, /* From login state machine */ + SE_SESSION_CONTINUE_FAIL, /* From login state machine? */ + SE_MAX_EVENT +} iscsit_session_event_t; + +typedef struct { + stmf_scsi_session_t *ist_stmf_sess; + stmf_local_port_t *ist_lport; + iscsit_tgt_t *ist_tgt; + kmem_cache_t *ist_task_cache; + kmutex_t ist_mutex; + kcondvar_t ist_cv; + iscsit_session_state_t ist_state; + iscsit_session_state_t ist_last_state; + boolean_t ist_sm_busy; + boolean_t ist_sm_complete; + list_t ist_events; + int ist_conn_count; + int ist_ffp_conn_count; + struct iscsit_conn_s *ist_failed_conn; + timeout_id_t ist_state_timeout; + /* Track ffp connections separately? Might be handy... XXX */ + list_t ist_conn_list; + avl_node_t ist_tgt_ln; + char *ist_initiator_name; + char *ist_initiator_alias; + char *ist_target_name; + char *ist_target_alias; + uint8_t ist_isid[ISCSI_ISID_LEN]; + uint16_t ist_tsih; + uint32_t ist_expcmdsn; + uint32_t ist_maxcmdsn; + sess_auth_t ist_auth; +} iscsit_sess_t; + +/* Update iscsit_ils_name table whenever login states are modified */ +typedef enum { + ILS_UNDEFINED = 0, + ILS_LOGIN_INIT, + ILS_LOGIN_WAITING, /* Waiting for more login PDU's */ + ILS_LOGIN_PROCESSING, /* Processing login request */ + ILS_LOGIN_RESPONDING, /* Sending login response */ + ILS_LOGIN_RESPONDED, /* Sent login response (no trans. to FFP) */ + ILS_LOGIN_FFP, /* Sending last login PDU for final response */ + ILS_LOGIN_DONE, /* Last login PDU sent (so we can free it) */ + ILS_LOGIN_ERROR, /* Login error, login failed */ + ILS_MAX_STATE +} iscsit_login_state_t; + +/* Update iscsit_ile_name table whenever login events are modified */ +typedef enum { + ILE_UNDEFINED = 0, + ILE_LOGIN_RCV, + ILE_LOGIN_RESP_READY, + ILE_LOGIN_FFP, + ILE_LOGIN_RESP_COMPLETE, + ILE_LOGIN_ERROR, + ILE_LOGIN_CONN_ERROR, + ILE_MAX_EVENT +} iscsit_login_event_t; + +typedef struct { + uint32_t op_initial_params_set:1, + op_discovery_session:1, + op_initial_r2t:1, + op_immed_data:1, + op_data_pdu_in_order:1, + op_data_sequence_in_order:1; + uint64_t op_max_connections; + uint64_t op_max_recv_data_segment_length; + uint64_t op_max_burst_length; + uint64_t op_first_burst_length; + uint64_t op_default_time_2_wait; + uint64_t op_default_time_2_retain; + uint64_t op_max_outstanding_r2t; + uint64_t op_error_recovery_level; +} iscsit_op_params_t; + +typedef struct { + iscsit_login_state_t icl_login_state; + iscsit_login_state_t icl_login_last_state; + boolean_t icl_busy; + boolean_t icl_login_complete; + kmutex_t icl_mutex; + uint32_t icl_login_itt; + uint8_t icl_login_csg; + uint8_t icl_login_nsg; + boolean_t icl_login_transit; + iscsit_auth_client_t icl_auth_client; + int icl_auth_pass; + list_t icl_login_events; + list_t icl_pdu_list; + uint16_t icl_tsih; + uint8_t icl_isid[ISCSI_ISID_LEN]; + uint32_t icl_cmdsn; + char *icl_target_name; + char *icl_initiator_name; + char *icl_login_resp_buf; + int icl_login_resp_len; /* For kmem_free */ + int icl_login_resp_valid_len; + uint8_t icl_login_resp_err_class; + uint8_t icl_login_resp_err_detail; + idm_pdu_t *icl_login_rej_resp; + idm_pdu_t *icl_login_resp; + nvlist_t *icl_request_nvlist; + nvlist_t *icl_response_nvlist; + nvlist_t *icl_negotiated_values; +} iscsit_conn_login_t; + +#define SET_LOGIN_ERROR(SLE_ICT, SLE_CLASS, SLE_DETAIL) \ + (SLE_ICT)->ict_login_sm.icl_login_resp_err_class = (SLE_CLASS); \ + (SLE_ICT)->ict_login_sm.icl_login_resp_err_detail = (SLE_DETAIL); + +typedef struct iscsit_conn_s { + idm_conn_t *ict_ic; + iscsit_sess_t *ict_sess; + list_node_t ict_sess_ln; + iscsit_conn_login_t ict_login_sm; + iscsit_op_params_t ict_op; + uint16_t ict_cid; + uint32_t ict_statsn; + struct iscsit_conn_s *ict_reinstate_conn; + uint32_t ict_reinstating:1; +} iscsit_conn_t; + +#define ICT_FLAGS_DISCOVERY 0x00000001 + +typedef struct { + scsi_task_t *it_stmf_task; + idm_task_t *it_idm_task; + iscsit_conn_t *it_ict; + uint32_t it_cmdsn; + uint32_t it_itt; + uint32_t it_ttt; +} iscsit_task_t; + + +typedef struct { + dev_info_t *global_dip; + stmf_port_provider_t *global_pp; + stmf_dbuf_store_t *global_dbuf_store; + taskq_t *global_dispatch_taskq; + int global_drv_opencount; + avl_tree_t global_discovery_sessions; + avl_tree_t global_target_list; + avl_tree_t global_tpg_list; + iscsit_tpg_t *global_default_tpg; + vmem_t *global_tsih_pool; + kmutex_t global_mutex; +} iscsit_global_t; + +extern iscsit_global_t iscsit_global; + + +idm_status_t +iscsit_login_sm_init(iscsit_conn_t *ict); + +void +iscsit_login_sm_fini(iscsit_conn_t *ict); + +void +iscsit_login_sm_event(iscsit_conn_t *ic, iscsit_login_event_t event, + idm_pdu_t *pdu); + +void +iscsit_login_sm_event_locked(iscsit_conn_t *ic, iscsit_login_event_t event, + idm_pdu_t *pdu); + +void +iscsit_send_async_event(iscsit_conn_t *ict, uint8_t async_event); + +void +iscsit_pdu_tx(idm_pdu_t *pdu); + +/* + * IDM conn ops + */ + +idm_rx_pdu_cb_t iscsit_op_scsi_cmd; +idm_rx_pdu_cb_t iscsit_rx_pdu; +idm_rx_pdu_error_cb_t iscsit_rx_pdu_error; +idm_client_notify_cb_t iscsit_client_notify; +idm_build_hdr_cb_t iscsit_build_hdr; + +/* + * lport entry points + */ +stmf_status_t +iscsit_xfer_scsi_data(scsi_task_t *task, stmf_data_buf_t *dbuf, + uint32_t ioflags); + +stmf_status_t +iscsit_send_scsi_status(scsi_task_t *task, uint32_t ioflags); + +void +iscsit_lport_task_free(scsi_task_t *task); + +stmf_status_t +iscsit_abort(stmf_local_port_t *lport, int abort_cmd, void *arg, + uint32_t flags); + +void +iscsit_ctl(stmf_local_port_t *lport, int cmd, void *arg); + +/* + * Connection functions + */ +idm_status_t +iscsit_conn_reinstate(iscsit_conn_t *existing_ict, iscsit_conn_t *ict); + +void +iscsit_conn_destroy_done(iscsit_conn_t *ict); + +/* + * Session functions + */ +int +iscsit_sess_avl_compare(const void *void_sess1, const void *void_sess2); + +iscsit_sess_t * +iscsit_sess_create(iscsit_tgt_t *tgt, iscsit_conn_t *ict, + uint32_t cmdsn, uint8_t *isid, char *initiator_name, char *target_name, + uint8_t *error_class, uint8_t *error_detail); + +void +iscsit_sess_destroy(iscsit_sess_t *ist); + +iscsit_conn_t * +iscsit_sess_lookup_conn(iscsit_sess_t *ist, uint16_t cid); + +void +iscsit_sess_bind_conn(iscsit_sess_t *ist, iscsit_conn_t *ict); + +void +iscsit_sess_unbind_conn(iscsit_sess_t *ist, iscsit_conn_t *ict); + +void +iscsit_sess_set_auth(iscsit_sess_t *ist); + +iscsit_sess_t * +iscsit_sess_reinstate(iscsit_sess_t *ist, iscsit_conn_t *ict, + uint8_t *error_class, uint8_t *error_detail); + +void +iscsit_sess_sm_event(iscsit_sess_t *ist, iscsit_session_event_t event, + iscsit_conn_t *ict); + +/* + * Target, TPGT, TPGT and portal functions + */ +iscsit_tgt_t * +iscsit_tgt_lookup(char *target_name); + +iscsit_tgt_t * +iscsit_tgt_create(char *target_name); + +void +iscsit_tgt_destroy(iscsit_tgt_t *tgt); + +int +iscsit_tgt_avl_compare(const void *void_tgt1, const void *void_tgt2); + +iscsit_tpgt_t * +iscsit_tgt_lookup_tpgt(iscsit_tgt_t *tgt, uint16_t tag); + +iscsit_portal_t * +iscsit_tgt_lookup_portal(iscsit_tgt_t *tgt, struct sockaddr_storage *sa, + uint16_t port); + +iscsit_sess_t * +iscsit_tgt_lookup_sess(iscsit_tgt_t *tgt, char *initiator_name, + uint8_t *isid, uint16_t tsih); + +void +iscsit_tgt_bind_sess(iscsit_tgt_t *tgt, iscsit_sess_t *sess); + +void +iscsit_tgt_unbind_sess(iscsit_tgt_t *tgt, iscsit_sess_t *sess); + +idm_status_t +iscsit_tgt_bind_tpgt(iscsit_tgt_t *tgt, iscsit_tpg_t *tpg, uint16_t tag); + +void +iscsit_tgt_unbind_tpgt(iscsit_tgt_t *tgt, iscsit_tpgt_t *tpgt); + +idm_status_t +iscsit_tgt_online(iscsit_tgt_t *tgt); + +void +iscsit_tgt_offline(iscsit_tgt_t *tgt); + +iscsit_tpg_t * +iscsit_tpg_lookup(char *tpg_name); + +iscsit_tpg_t * +iscsit_tpg_create(char *tpg_name); + +void +iscsit_tpg_destroy(iscsit_tpg_t *tpg); + +int +iscsit_tpg_avl_compare(const void *void_tpg1, const void *void_tpg2); + +iscsit_tpg_t * +iscsit_tpg_createdefault(); + +idm_status_t +iscsit_tpg_online(iscsit_tpg_t *tpg); + +void +iscsit_tpg_offline(iscsit_tpg_t *tpg); + +iscsit_portal_t * +iscsit_portal_lookup(iscsit_tpg_t *tpg, struct sockaddr_storage *sa, + uint16_t port); + +iscsit_portal_t * +iscsit_portal_create(iscsit_tpg_t *tpg, struct sockaddr_storage *sa, + uint16_t port); + +void +iscsit_portal_destroy(iscsit_portal_t *portal); + +int +iscsit_portal_avl_compare(const void *void_portal1, const void *void_portal2); + +idm_status_t +iscsit_portal_online(iscsit_portal_t *portal); + +void +iscsit_portal_offline(iscsit_portal_t *portal); + + + +#endif /* _ISCSIT_H_ */