iscsi_cmd.c revision 36c5fee33fa8b822175d410202aebcf592c8d342
/*
* 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 <pthread.h>
#include <stdlib.h>
#include <assert.h>
#include <syslog.h>
#include <synch.h>
#include "iscsi_conn.h"
#include "iscsi_cmd.h"
#include "utility.h"
static pthread_mutex_t cmd_mutex;
static int cmd_ttt;
/*
* []----
* | iscsi_cmd_init -- called at the beginning of time to initialize locks
* []----
*/
void
{
cmd_ttt = 0;
}
/*
* []----
* | iscsi_cmd_alloc -- allocate space for new command
* []----
*/
{
return (NULL);
(void) pthread_mutex_lock(&cmd_mutex);
(void) pthread_mutex_unlock(&cmd_mutex);
(void) pthread_mutex_lock(&c->c_mutex);
if (c->c_cmd_head == NULL) {
c->c_cmd_head = cmd;
c->c_cmd_tail = cmd;
} else {
c->c_cmd_tail = cmd;
}
cmd->c_allegiance = c;
c->c_cmds_active++;
(void) pthread_mutex_unlock(&c->c_mutex);
return (cmd);
}
/*
* []----
* | iscsi_cmd_find -- search for a specific command and return it
* |
* | XXX Need to switch to use an AVL tree.
* []----
*/
{
(void) pthread_mutex_lock(&c->c_mutex);
/*
* Depending on type determine correct matching value.
* Only return a hit if the command hasn't already been
* freed.
*/
break;
}
(void) pthread_mutex_unlock(&c->c_mutex);
return (cmd);
}
/*
* []----
* | iscsi_cmd_free -- mark a command as freed.
* []----
*/
void
{
c->c_cmds_avg_cnt++;
}
/*
* []----
* | iscsi_cmd_cancel -- mark a command as canceled
* |
* | We don't actually stop commands in flight. We only prevent the canceled
* | connection layer if a command is canceled nothing will be sent on the
* | wire and at that point the command is marked CmdFree so that future calls
* | to cmd_remove will actually free the space.
* []----
*/
void
{
(void) pthread_mutex_lock(&c->c_mutex);
}
(void) pthread_mutex_unlock(&c->c_mutex);
}
/*
* []----
* | iscsi_cmd_remove -- actually free space allocated to commands
* |
* | According to the iSCSI specification the target must kept resources
* | around until the initiator sends a command with a status serial
* | number higher than the held resource. This is so that an initiator
* | can request data again if needed. During the processing of each new
* | command this routine is called to free old commands.
* []----
*/
void
{
*n;
(void) pthread_mutex_lock(&c->c_mutex);
/*
* If the StatusSN for this command is less than the incoming
* StatusSN and the command has been freed remove it from
* list. Don't bother with commands that are in the state of
* CmdCanceled. Once the I/O has been completed the command
* is passed back to the connection handler where the state
* will be noticed and then the command will be freed. At that
* point the next incoming command with a valid expected
* status serial number will free the memory.
*/
if (c->c_cmd_head == cmd) {
if (c->c_cmd_head == NULL)
c->c_cmd_tail = NULL;
} else {
else {
c->c_cmd_tail = n;
}
}
if (cmd->c_scb_extended)
}
c->c_cmds_active--;
cmd = n;
break;
} else {
}
}
(void) pthread_mutex_unlock(&c->c_mutex);
}
/*
* []----
* | iscsi_cmd_window -- return the number of available commands
* |
* | There are currently 7 different places where this routine is called.
* | In some cases and command is allocated which will be freed shortly and
* | in others no command is held. This is why the number of commands found
* | will be decremented if larger than 0. Since the daemon doesn't have
* | any hard limits on the number of commands being supported this is more
* | arbitrary and the command window size is used for debugging other
* | initiators.
* |
* | NOTE: connection mutex must be held during this call.
* []----
*/
int
{
int cnt;
if (c->c_cmds_avg_cnt == 0) {
/*
* If there are no outstanding commands clear the averages
* so that the initiator can start again.
*/
c->c_cmds_avg_sum = 0;
c->c_cmds_avg_cnt = 0;
/*
* It would appear things are taking a real long time to
* complete on our end. Close down the command window to
* prevent the initiator from timing out commands.
*/
} else {
c->c_maxcmdsn - c->c_cmds_active;
}
return (cnt);
}
void
{
iscsi_delayed_t *d,
*n,
*l = NULL;
"CON%x Failed calloc for delayed I/O",
return;
}
d->id_offset = T10_DATA_OFFSET(t);
d->id_t10_cmd = t;
l = n;
d->id_next = n;
n->id_prev = d;
cmd->c_t10_delayed = d;
} else {
n->id_prev = d;
d->id_next = n;
}
return;
}
}
if (l == NULL) {
cmd->c_t10_delayed = d;
} else {
l->id_next = d;
d->id_prev = l;
}
}
void
{
if (cmd->c_t10_delayed == d) {
if (d->id_next)
} else {
}
free(d);
}