iscsi_sess.c revision 8a16ae8f6efb5a6c02ab0aec860e229706335bb9
/*
* 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 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <strings.h>
#include <syslog.h>
#include "iscsi_conn.h"
#include "iscsi_sess.h"
#include "t10.h"
#include "utility.h"
#include "xml.h"
#include "target.h"
int sess_num;
static void session_free(struct iscsi_sess *s);
static void *sess_from_t10(void *v);
static void *sess_process(void *v);
/*
* []----
* | session_init -- initialize global variables and mutexs
* []----
*/
void
{
sess_num = 0;
sess_head = 0;
}
/*
* []----
* | session_alloc -- create a new session attached to the lead connection
* []----
*/
{
iscsi_sess_t *s,
*n;
return (True);
if (s == NULL)
return (False);
(void) pthread_mutex_lock(&sess_mutex);
s->s_state = SS_STARTED;
sess_head = s;
else {
;
n->s_next = s;
}
(void) pthread_mutex_unlock(&sess_mutex);
c->c_sess = s;
s->s_conn_head = c;
s->s_sessq = queue_alloc();
s->s_t10q = queue_alloc();
s->s_type = SessionNormal;
sess_set_auth(s);
return (True);
}
/*
* []----
* | session_free -- remove connection from session
* []----
*/
static void
{
iscsi_sess_t *n;
/*
* Early errors in connection setup can still call this routine
* which means the session hasn't been called.
*/
if (s == NULL)
return;
if (s->s_i_name)
if (s->s_t_name)
if (s->s_i_alias)
(void) pthread_mutex_lock(&sess_mutex);
if (sess_head == s)
else {
if (n->s_next == s) {
break;
}
}
if (n == NULL) {
"SES%x NOT IN SESSION LIST!", s->s_num);
}
}
(void) pthread_mutex_unlock(&sess_mutex);
}
/*
* []----
* | session_remove_connection -- removes conn from sess list
* |
* | Returns True if this was the last connection which is always the case
* | for now. In the future with multiple connections per session it'll be
* | different.
* []----
*/
/*ARGSUSED*/
static Boolean_t
{
return (True);
}
/*
* []----
* | convert_i_local -- Return a local name for the initiator if avilable.
* |
* | NOTE: If this routine returns true, it's the callers responsibility
* | to free the memory.
* []----
*/
{
char *iname,
*name;
NULL) {
False) {
continue;
}
return (False);
} else
return (True);
} else
}
return (False);
}
/*
* []----
* | sess_from_t10 -- handle messages from the T10 layer
* []----
*/
void *
sess_from_t10(void *v)
{
iscsi_sess_t *s = (iscsi_sess_t *)v;
msg_t *m;
m = queue_message_get(s->s_t10q);
switch (m->msg_type) {
case msg_cmd_data_rqst:
msg_cmd_data_rqst, m->msg_data);
break;
case msg_cmd_data_in:
msg_cmd_data_in, m->msg_data);
break;
case msg_cmd_cmplt:
msg_cmd_cmplt, m->msg_data);
break;
case msg_shutdown_rsp:
if (s->s_t10) {
t10_handle_destroy(s->s_t10);
}
(void) pthread_mutex_lock(&s->s_mutex);
s->s_state = SS_SHUTDOWN_CMPLT;
(void) pthread_mutex_unlock(&s->s_mutex);
session_free(s);
/*
* Let the connection, which is the last, know
* about our completion of the shutdown.
*/
msg_shutdown_rsp, (void *)True);
break;
default:
"SES%x Unknown msg type (%d) from T10 ",
break;
}
}
free(s);
return (NULL);
}
/*
* []----
* | sess_process -- handle messages from the connection(s)
* []----
*/
static void *
sess_process(void *v)
{
iscsi_sess_t *s = (iscsi_sess_t *)v;
iscsi_conn_t *c;
msg_t *m;
char **buf,
local_buf[16];
int lun;
(void) pthread_mutex_lock(&s->s_mutex);
s->s_state = SS_RUNNING;
(void) pthread_mutex_unlock(&s->s_mutex);
do {
m = queue_message_get(s->s_sessq);
switch (m->msg_type) {
case msg_cmd_send:
/*
* The value of 0x960 comes from T10.
* See SPC-4, revision 1a, section 6.4.2,
* table 87
*
* XXX Need to rethink how I should do
* the callback.
*/
s->s_t10q, dataout_callback);
}
/*
* If the command create failed, the T10 layer
* will attempt to create a sense buffer
* telling the initiator what went wrong. If
* that layer was unable to accomplish that
* things are really bad and we need to just
* close the connection.
*/
0, msg_cmd_cmplt, t10_cmd);
} else {
"SES%x FAILED to create cmd",
s->s_num);
}
} else {
(void) pthread_mutex_lock(
(void) t10_cmd_send(s->s_t10,
cmd->c_data_len);
} else {
}
(void) pthread_mutex_unlock(
}
break;
case msg_cmd_data_out:
cmd->c_data_len);
break;
0, 0);
break;
case msg_lu_capacity_change:
lun, 0);
break;
case msg_reset_targ:
0, 0);
break;
case msg_reset_lu:
break;
case msg_shutdown:
(void) pthread_mutex_lock(&s->s_mutex);
s->s_state = SS_SHUTDOWN_START;
(void) pthread_mutex_unlock(&s->s_mutex);
/*
* Shutdown rquest comming from a connection. Only
* shutdown the STE if this is the last connection
* for this session.
*/
c = (iscsi_conn_t *)m->msg_data;
if (session_remove_connection(s, c) == True) {
"SES%x Starting shutdown", s->s_num);
/*
* If this is the last connection for this
* session send a message to the SAM-3 layer to
* shutdown.
*/
t10_handle_disable(s->s_t10);
}
queue_message_set(s->s_t10q, 0,
msg_shutdown_rsp, 0);
} else {
/*
* Since this isn't the last connection for
* the session, acknowledge the connection
* request now since it's references from
* this session have been removed.
*/
queue_message_set(c->c_dataq, 0,
msg_shutdown_rsp, (void *)False);
}
break;
case msg_initiator_name:
/*
* Acknowledge the request by sending back an empty
* message.
*/
break;
case msg_initiator_alias:
/*
* Acknowledge the request by sending back an empty
* message.
*/
break;
case msg_target_name:
/*
* Acknowledge the request by sending back an empty
* message.
*/
break;
case msg_mgmt_rqst:
if ((s->s_type == SessionNormal) &&
s->s_i_alias);
}
/*
* Need to loop through the connections
* and create one time_connected tag for
* each. This will be needed once MC/S support
* is added.
*/
"%d",
}
break;
default:
"SES%x Unknown msg type (%d) from Connection",
break;
}
return (NULL);
}
/*
* []----
* | session_validate -- do what the name says
* |
* | At this point the connection has processed the login command so that
* | we have InitiatorName and ISID at a minimum. Check to see if there
* | are other sessions which match. If so, log that one out and proceed with
* | this session. If nothing matches, then link this into a global list.
* |
* | Once we support multiple connections per session need to scan list
* | to see if other connection have the same CID. If so, log out that
* | connection.
* []----
*/
{
"SES%x %s ISID[%02x%02x%02x%02x%02x%02x]",
/*
* SessionType=Discovery which means no target name and therefore
* this is okay.
*/
return (True);
(void) pthread_mutex_lock(&sess_mutex);
/*
* Ignore ourselves in this check.
*/
if (check == s)
continue;
continue;
continue;
continue;
/*
* Section 5.3.5
* Session reinstatement is the process of the initiator
* logging in with an ISID that is possible active from
* the target's perspective. Thus implicitly logging out
* the session that corresponds to the ISID and
* reinstating a new iSCSI session in its place (with the
* same ISID).
*/
else
break;
}
}
(void) pthread_mutex_unlock(&sess_mutex);
return (True);
}
/*
* []----
* | static iscsi_sess_set_auth -
* []----
*/
static void
{
return;
/* Zero out the session authentication structure */
/* Load CHAP name */
return;
/* Load CHAP secret */
return;
/* Set up authentication buffers only if configured */
}
/*
* prepare for authentication
*/
"unable to initialize authentication\n");
return;
}
"unable to set version\n");
return;
}
"unable to set username\n");
return;
}
"unable to set password\n");
return;
}
/*
* FIXME: we disable the minimum size check for now
*/
"unable to set ipsec\n");
return;
}
"unable to set remote authentication\n");
return;
}
}
}