iscsi_conn.c revision fcf3ce441efd61da9bb2884968af01cb7c1452cc
/*
* 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 usr/src/OPENSOLARIS.LICENSE
* 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 usr/src/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.
*
* iSCSI connection interfaces
*/
#include "iscsi.h"
#include "persistent.h"
/* interface connection interfaces */
iscsi_conn_t *icp);
iscsi_conn_t *icp);
/*
* +--------------------------------------------------------------------+
* | External Connection Interfaces |
* +--------------------------------------------------------------------+
*/
/*
* iscsi_conn_create - This creates an iscsi connection structure and
* associates it with a session structure. The session's sess_conn_list_rwlock
* should be held as a writer before calling this function.
*/
{
char th_name[ISCSI_TH_MAX_NAME_LEN];
/* See if this connection already exists */
/*
* Compare the ioctl information to see if
* its a match for this connection. (This
* is done by making sure the IPs are of
* the same size and then they are the
* same value.
*/
SIZEOF_SOCKADDR(addr)) == 0) {
/* It's a match, record this connection */
break;
}
}
/* If icp is found return it */
return (ISCSI_STATUS_SUCCESS);
}
/* We are creating the connection, allocate, and setup */
/*
* Setup connection
*/
/* Creation of the receive thread */
return (ISCSI_STATUS_INTERNAL_ERROR);
}
/* Creation of the transfer thread */
return (ISCSI_STATUS_INTERNAL_ERROR);
}
/* setup connection queues */
/* Add new connection to the session connection list */
} else {
}
(void) iscsi_conn_kstat_init(icp);
return (ISCSI_STATUS_SUCCESS);
}
/*
* iscsi_conn_offline - This attempts to take a connection from
* any state to ISCSI_CONN_STATE_FREE.
*/
{
/*
* We can only destroy a connection if its either in
* a state of FREE or LOGGED. The other states are
* transitionary and its unsafe to perform actions
* on the connection in those states. Set a flag
* on the connection to influence the transitions
* to quickly complete. Then wait for a state
* transition.
*/
(ddi_get_lbolt() < delay)) {
/* wait for transition */
}
/* Final check whether we can destroy the connection */
switch (icp->conn_state) {
case ISCSI_CONN_STATE_FREE:
/* Easy case - Connection is dead */
break;
/* Hard case - Force connection logout */
(void) iscsi_conn_state_machine(icp,
break;
case ISCSI_CONN_STATE_FAILED:
case ISCSI_CONN_STATE_POLLING:
default:
/* All other cases fail the destroy */
return (ISCSI_STATUS_INTERNAL_ERROR);
}
return (ISCSI_STATUS_SUCCESS);
}
/*
* iscsi_conn_destroy - This destroys an iscsi connection structure
* and de-associates it with the session. The connection should
* already been in the ISCSI_CONN_STATE_FREE when attempting this
* operation.
*/
{
return (ISCSI_STATUS_INTERNAL_ERROR);
}
/* Destroy receive thread */
/* Destroy transfer thread */
/* Terminate connection queues */
/*
* Remove connection from sessions linked list.
*/
/* connection first item in list */
/*
* check if this is also the last item in the list
*/
}
} else {
/*
* search session list for icp pointing
* to connection being removed. Then
* update that connections next pointer.
*/
break;
}
}
/*
* if this is the last connection in the list
* update the last_ptr to point to t_icp
*/
}
} else {
/* couldn't find session */
}
}
/* Free this Connections Data */
return (ISCSI_STATUS_SUCCESS);
}
/*
*
* Used to set the min and max login window. Input values
* are in seconds.
*/
void
{
}
/*
* iscsi_conn_state_machine - This function is used to drive the
* state machine of the iscsi connection. It takes in a connection
* and the associated event effecting the connection.
*
* 7.1.3 Connection State Diagram for an Initiator
* Symbolic Names for States:
* S1: FREE - State on instantiation, or after successful
* connection closure.
* S2: IN_LOGIN - Waiting for login process to conclude,
* possibly involving several PDU exchanges.
* S3: LOGGED_IN - In Full Feature Phase, waiting for all internal,
* iSCSI, and transport events
* S4: IN_LOGOUT - Waiting for the Logout repsonse.
* S5: FAILED - The connection has failed. Attempting
* to reconnect.
* S6: POLLING - The connection reconnect attempts have
* failed. Continue to poll at a lower
* frequency.
*
* States S3, S4 constitute the Full Feature Phase
* of the connection.
*
* The state diagram is as follows:
* -------
* +-------->/ S1 \<------------------------------+
* | +->\ /<---+ /---\ |
* | / ---+--- |T7/30 T7| | |
* | + | | \->------ |
* | T8| |T1 / T5 / S6 \--->|
* | | | / +----------\ /T30 |
* | | V / / ------ |
* | | ------- / / ^ |
* | | / S2 \ / T5 |T7 |
* | | \ / +-------------- --+--- |
* | | ---+--- / / S5 \--->|
* | | |T5 / +-------------> ------ |
* | | | / / |
* | | | / / T11 |
* | | | / / +----+ |
* | | V V / | | |
* | | ------+ ----+-- | |
* | +-----/ S3 \T9/11/ S4 \<+ |
* +----------\ /---->\ /----------------+
*
* The state transition table is as follows:
*
* +-----+---+---+------+------+---+
* |S1 |S2 |S3 |S4 |S5 |S6 |
* ---+-----+---+---+------+------+---+
* S1|T1 |T1 | - | - | - | |
* ---+-----+---+---+------+------+---+
* S2|T7/30|- |T5 | - | - | |
* ---+-----+---+---+------+------+---+
* S3|T8 |- | - |T9/11 |T14/15| |
* ---+-----+---+---+------+------+---+
* S4| |- | - |T11 |T15/17| |
* ---+-----+---+---+------+------+---+
* S5|T30 | |T5 | | |T7 |
* ---+-----+---+---+------+------+---+
* S6|T30 | |T5 | | |T7 |
* ---+-----+---+---+------+------+---+
*
* Events definitions:
*
* -T1: Transport connection request was made (e.g., TCP SYN sent).
* -T5: The final iSCSI Login response with a Status-Class of zero was
* received.
* -T7: One of the following events caused the transition:
* - Login timed out.
* - A transport disconnect indication was received.
* - A transport reset was received.
* - An internal event indicating a transport timeout was
* received.
* - An internal event of receiving a Logout repsonse (success)
* on another connection for a "close the session" Logout
* request was received.
* * In all these cases, the transport connection is closed.
* -T8: An internal event of receiving a Logout response (success)
* on another connection for a "close the session" Logout request
* was received, thus closing this connection requiring no further
* cleanup.
* -T9: An internal event that indicates the readiness to start the
* Logout process was received, thus prompting an iSCSI Logout to
* be sent by the initiator.
* -T11: Async PDU with AsyncEvent "Request Logout" was received.
* -T13: An iSCSI Logout response (success) was received, or an internal
* event of receiving a Logout response (success) on another
* connection was received.
* -T14: One or more of the following events case this transition:
* - Header Digest Error
* - Protocol Error
* -T15: One or more of the following events caused this transition:
* - Internal event that indicates a transport connection timeout
* was received thus prompting transport RESET or transport
* connection closure.
* - A transport RESET
* - A transport disconnect indication.
* - Async PDU with AsyncEvent "Drop connection" (for this CID)
* - Async PDU with AsyncEvent "Drop all connections"
* -T17: One or more of the following events caused this transition:
* - Logout response, (failure i.e., a non-zero status) was
* received, or Logout timed out.
* - Any of the events specified for T15.
* -T30: One of the following event caused the transition:
* - Thefinal iSCSI Login response was received with a non-zero
* Status-Class.
*/
{
char *, iscsi_conn_event_str(event));
switch (icp->conn_state) {
case ISCSI_CONN_STATE_FREE:
break;
break;
break;
break;
case ISCSI_CONN_STATE_FAILED:
break;
case ISCSI_CONN_STATE_POLLING:
break;
default:
}
return (status);
}
/*
* iscsi_conn_state_str - converts state enum to a string
*/
char *
{
switch (state) {
case ISCSI_CONN_STATE_FREE:
return ("free");
return ("in_login");
return ("logged_in");
return ("in_logout");
case ISCSI_CONN_STATE_FAILED:
return ("failed");
case ISCSI_CONN_STATE_POLLING:
return ("polling");
default:
return ("unknown");
}
}
/*
* iscsi_conn_sync_params - used to update connection parameters
*
* Used to update connection parameters with current configured
* parameters in the persistent store. This should be called
* before starting to make a new iscsi connection in iscsi_login.
*/
{
int param_id;
char *name;
/*
* Check if someone is trying to destroy this
* connection. If so fail the sync request,
* as a method of fast fail.
*/
return (ISCSI_STATUS_SHUTDOWN);
}
/* First get a copy of the HBA params */
sizeof (iscsi_login_params_t));
/*
* Now we need to get the session configured
* values from the persistent store and apply
* them to our connection.
*/
param_id++) {
switch (param_id) {
/*
* Boolean parameters
*/
break;
break;
break;
break;
/*
* Integer parameters
*/
break;
break;
break;
break;
break;
break;
break;
/*
* Integer parameters which currently are unsettable
*/
/* FALLTHRU */
/* FALLTHRU */
/* FALLTHRU */
default:
break;
}
}
}
/* Skip binding checks on discovery sessions */
return (ISCSI_STATUS_SUCCESS);
}
/*
* Now we need to get the current optional connection
* binding information.
*/
/* setup initial buffer for configured session information */
/* get configured sessions information */
/*
* If we were unable to get target level information
* then check the initiator level information.
*/
/*
* No hba information is found. So assume default
* one session unbound behavior.
*/
}
}
/*
* Check to make sure this session is still a configured
* session. The user might have decreased the session
* count. (NOTE: byte 5 of the sess_isid is the session
* count (via MS/T). This counter starts at 0.)
*/
/*
* No longer a configured session. Return a
* failure so we don't attempt to relogin.
*/
return (ISCSI_STATUS_SHUTDOWN);
}
/*
* If sessions are unbound set this information on
* the connection and return success.
*/
return (ISCSI_STATUS_SUCCESS);
}
/*
* Since the sessions are bound we need to find the matching
* binding information for the session's isid. If this
* session's isid is > 0 then we need to get more configured
* session information to find the binding info.
*/
if (idx > 0) {
int ics_out;
/* record new size and free last buffer */
/* allocate new buffer */
/* get configured sessions information */
"unable to get configured session information\n",
return (ISCSI_STATUS_SHUTDOWN);
}
}
/* Copy correct binding information to the connection */
sizeof (struct in_addr));
} else {
sizeof (struct in6_addr));
}
return (ISCSI_STATUS_SUCCESS);
}
/*
* +--------------------------------------------------------------------+
* | Internal Connection Interfaces |
* +--------------------------------------------------------------------+
*/
/*
* iscsi_conn_state_free -
*
* S1: FREE - State on instantiation, or after successful
* connection closure.
*/
static iscsi_status_t
{
/* switch on event change */
switch (event) {
/* -T1: Transport connection request was request */
case ISCSI_CONN_EVENT_T1:
/*
* Release the connection state mutex cross the
* the dispatch of the login task. The login task
* will reacquire the connection state mutex when
* it pushes the connection successful or failed.
*/
/* start login */
/*
* Sync base connection information before login
* A login redirection might have shifted the
* current information from the base.
*/
sizeof (icp->conn_curr_addr));
break;
/* All other events are invalid for this state */
default:
}
return (status);
}
/*
* iscsi_conn_state_in_login - During this state we are trying to
* connect the TCP connection and make a successful login to the
* target. To complete this we have a task queue item that is
* trying this processing at this point in time. When the task
* queue completed its processing it will issue either a T5/7
* event.
*/
static void
{
/* switch on event change */
switch (event) {
/*
* -T5: The final iSCSI Login response with a Status-Class of zero
* was received.
*/
case ISCSI_CONN_EVENT_T5:
break;
/*
* -T30: One of the following event caused the transition:
* - Thefinal iSCSI Login response was received with a non-zero
* Status-Class.
*/
case ISCSI_CONN_EVENT_T30:
/* FALLTHRU */
/*
* -T7: One of the following events caused the transition:
* - Login timed out.
* - A transport disconnect indication was received.
* - A transport reset was received.
* - An internal event indicating a transport timeout was
* received.
* - An internal event of receiving a Logout repsonse (success)
* on another connection for a "close the session" Logout
* request was received.
* * In all these cases, the transport connection is closed.
*/
case ISCSI_CONN_EVENT_T7:
break;
/* All other events are invalid for this state */
default:
}
}
/*
* iscsi_conn_state_logged_in -
*
*/
static void
{
/* switch on event change */
switch (event) {
/*
* -T8: An internal event of receiving a Logout response (success)
* on another connection for a "close the session" Logout request
* was received, thus closing this connection requiring no further
* cleanup.
*/
case ISCSI_CONN_EVENT_T8:
/* stop tx thread */
/* Disconnect connection */
/* Notify session that a connection logged out */
break;
/*
* -T9: An internal event that indicates the readiness to start the
* Logout process was received, thus prompting an iSCSI Logout
* to be sent by the initiator.
*/
case ISCSI_CONN_EVENT_T9:
/* FALLTHRU */
/*
* -T11: Aync PDU with AsyncEvent "Request Logout" was recevied
*/
case ISCSI_CONN_EVENT_T11:
(void) iscsi_handle_logout(icp);
break;
/*
* -T14: One or more of the following events case this transition:
* - Header Digest Error
* - Protocol Error
*/
case ISCSI_CONN_EVENT_T14:
/* stop tx thread */
/*
* Error Recovery Level 0 states we should drop
* the connection here. Then we will fall through
* and treat this event like a T15.
*/
/* FALLTHRU */
/*
* -T15: One or more of the following events caused this transition
* - Internal event that indicates a transport connection timeout
* was received thus prompting transport RESET or transport
* connection closure.
* - A transport RESET
* - A transport disconnect indication.
* - Async PDU with AsyncEvent "Drop connection" (for this CID)
* - Async PDU with AsyncEvent "Drop all connections"
*/
case ISCSI_CONN_EVENT_T15:
/* stop tx thread, no-op if already done for T14 */
/*
* If session type is NORMAL, create a new login task
* to get this connection reestablished.
*/
} else {
}
break;
/* All other events are invalid for this state */
default:
}
}
/*
* iscsi_conn_state_in_logout -
*
*/
static void
{
/* switch on event change */
switch (event) {
/*
* -T11: Async PDU with AsyncEvent "Request Logout" was received again
*/
case ISCSI_CONN_EVENT_T11:
/* Already in LOGOUT ignore the request */
break;
/*
* -T17: One or more of the following events caused this transition:
* - Logout response, (failure i.e., a non-zero status) was
* received, or logout timed out.
* - Any of the events specified for T15
*
* -T14: One or more of the following events case this transition:
* - Header Digest Error
* - Protocol Error
*
* -T15: One or more of the following events caused this transition
* - Internal event that indicates a transport connection timeout
* was received thus prompting transport RESET or transport
* connection closure.
* - A transport RESET
* - A transport disconnect indication.
* - Async PDU with AsyncEvent "Drop connection" (for this CID)
* - Async PDU with AsyncEvent "Drop all connections"
*/
case ISCSI_CONN_EVENT_T17:
case ISCSI_CONN_EVENT_T14:
case ISCSI_CONN_EVENT_T15:
/* stop tx thread */
/* Disconnect Connection */
/* Notify session of a failed logout */
break;
/* All other events are invalid for this state */
default:
}
}
/*
* iscsi_conn_state_failed -
*
*/
static void
{
/* switch on event change */
switch (event) {
/*
* -T5: The final iSCSI Login response with a Status-Class of zero
* was received.
*/
case ISCSI_CONN_EVENT_T5:
break;
/*
* -T30: One of the following event caused the transition:
* - Thefinal iSCSI Login response was received with a non-zero
* Status-Class.
*/
case ISCSI_CONN_EVENT_T30:
break;
/*
* -T7: One of the following events caused the transition:
* - Login timed out.
* - A transport disconnect indication was received.
* - A transport reset was received.
* - An internal event indicating a transport timeout was
* received.
* - An internal event of receiving a Logout repsonse (success)
* on another connection for a "close the session" Logout
* request was received.
* * In all these cases, the transport connection is closed.
*/
case ISCSI_CONN_EVENT_T7:
break;
/* There are no valid transition out of this state. */
default:
}
}
/*
* iscsi_conn_state_polling -
*
* S6: POLLING - State on instantiation, or after successful
* connection closure.
*/
static void
{
/* switch on event change */
switch (event) {
/*
* -T5: The final iSCSI Login response with a Status-Class of zero
* was received.
*/
case ISCSI_CONN_EVENT_T5:
break;
/*
* -T30: One of the following event caused the transition:
* - Thefinal iSCSI Login response was received with a non-zero
* Status-Class.
*/
case ISCSI_CONN_EVENT_T30:
break;
/*
* -T7: One of the following events caused the transition:
* - Login timed out.
* - A transport disconnect indication was received.
* - A transport reset was received.
* - An internal event indicating a transport timeout was
* received.
* - An internal event of receiving a Logout repsonse (success)
* on another connection for a "close the session" Logout
* request was received.
* * In all these cases, the transport connection is closed.
*/
case ISCSI_CONN_EVENT_T7:
/*
* If session type is NORMAL, create a new login task
* to get this connection reestablished.
*/
} else {
}
break;
/* All other events are invalid for this state */
default:
}
}
/*
* iscsi_conn_event_str - converts event enum to a string
*/
static char *
{
switch (event) {
case ISCSI_CONN_EVENT_T1:
return ("T1");
case ISCSI_CONN_EVENT_T5:
return ("T5");
case ISCSI_CONN_EVENT_T7:
return ("T7");
case ISCSI_CONN_EVENT_T8:
return ("T8");
case ISCSI_CONN_EVENT_T9:
return ("T9");
case ISCSI_CONN_EVENT_T11:
return ("T11");
case ISCSI_CONN_EVENT_T14:
return ("T14");
case ISCSI_CONN_EVENT_T15:
return ("T15");
case ISCSI_CONN_EVENT_T17:
return ("T17");
case ISCSI_CONN_EVENT_T30:
return ("T30");
default:
return ("unknown");
}
}
/*
* iscsi_conn_flush_active_cmds - flush all active icmdps
* for a connection.
*/
static void
{
} else {
}
/* Flush active queue */
}
}
}
/*
* iscsi_conn_logged_in - connection has successfully logged in
*/
static void
{
/*
* We need to drop the connection state lock
* before updating the session state. On update
* of the session state it will enumerate the
* target. If we hold the lock during enumeration
* will block the watchdog thread from timing
* a scsi_pkt, if required. This will lead to
* a possible hang condition.
*
* Also the lock is no longer needed once the
* connection state was updated.
*/
/* startup threads */
/* Notify the session that a connection is logged in */
}
/*
*/
static void
{
/*
* Sync base connection information before login.
* A login redirection might have shifted the
* current information from the base.
*/
sizeof (icp->conn_curr_addr));
/* schedule login task */
DDI_SUCCESS) {
"iscsi connection(%u) failure - "
"unable to schedule login task",
}
}