#include "iscsi.h"
static void iscsi_cmd_state_free(iscsi_cmd_t *icmdp,
iscsi_cmd_event_t event, void *arg);
static void iscsi_cmd_state_pending(iscsi_cmd_t *icmdp,
iscsi_cmd_event_t event, void *arg);
static void iscsi_cmd_state_active(iscsi_cmd_t *icmdp,
iscsi_cmd_event_t event, void *arg);
static void iscsi_cmd_state_aborting(iscsi_cmd_t *icmdp,
iscsi_cmd_event_t event, void *arg);
static void iscsi_cmd_state_idm_aborting(iscsi_cmd_t *icmdp,
iscsi_cmd_event_t event, void *arg);
static void iscsi_cmd_state_completed(iscsi_cmd_t *icmdp,
iscsi_cmd_event_t event, void *arg);
static char *iscsi_cmd_state_str(iscsi_cmd_state_t state);
static char *iscsi_cmd_event_str(iscsi_cmd_event_t event);
static char *iscsi_cmd_type_str(iscsi_cmd_type_t type);
#define ISCSI_INTERNAL_CMD_TIMEOUT 60
#define ISCSI_CMD_ISSUE_CALLBACK(icmdp, status) \
icmdp->cmd_completed = B_TRUE; \
icmdp->cmd_result = status; \
cv_broadcast(&icmdp->cmd_completion);
#define ISCSI_CMD_SET_REASON_STAT(icmdp, reason, stat) \
icmdp->cmd_un.scsi.pkt->pkt_reason = reason; \
icmdp->cmd_un.scsi.pkt->pkt_statistics = stat;
int iscsi_cmd_timeout_factor = 1;
void
iscsi_cmd_state_machine(iscsi_cmd_t *icmdp, iscsi_cmd_event_t event, void *arg)
{
boolean_t release_lock = B_TRUE;
ASSERT(icmdp != NULL);
ASSERT(arg != NULL);
DTRACE_PROBE3(event, iscsi_cmd_t *, icmdp, char *,
iscsi_cmd_state_str(icmdp->cmd_state),
char *, iscsi_cmd_event_str(event));
mutex_enter(&icmdp->cmd_mutex);
idm_sm_audit_event(&icmdp->cmd_state_audit,
SAS_ISCSI_CMD, icmdp->cmd_state, event, (uintptr_t)arg);
icmdp->cmd_prev_state = icmdp->cmd_state;
switch (icmdp->cmd_state) {
case ISCSI_CMD_STATE_FREE:
iscsi_cmd_state_free(icmdp, event, arg);
break;
case ISCSI_CMD_STATE_PENDING:
iscsi_cmd_state_pending(icmdp, event, arg);
break;
case ISCSI_CMD_STATE_ACTIVE:
iscsi_cmd_state_active(icmdp, event, arg);
break;
case ISCSI_CMD_STATE_ABORTING:
iscsi_cmd_state_aborting(icmdp, event, arg);
break;
case ISCSI_CMD_STATE_IDM_ABORTING:
iscsi_cmd_state_idm_aborting(icmdp, event, arg);
break;
case ISCSI_CMD_STATE_COMPLETED:
iscsi_cmd_state_completed(icmdp, event, arg);
release_lock = B_FALSE;
break;
default:
ASSERT(FALSE);
}
if (release_lock == B_TRUE) {
idm_sm_audit_state_change(&icmdp->cmd_state_audit,
SAS_ISCSI_CMD, icmdp->cmd_prev_state, icmdp->cmd_state);
if (!(icmdp->cmd_misc_flags & ISCSI_CMD_MISCFLAG_FREE) ||
!(icmdp->cmd_misc_flags &
ISCSI_CMD_MISCFLAG_INTERNAL)) {
mutex_exit(&icmdp->cmd_mutex);
return;
}
mutex_exit(&icmdp->cmd_mutex);
iscsi_cmd_free(icmdp);
}
}
iscsi_cmd_t *
iscsi_cmd_alloc(iscsi_conn_t *icp, int km_flags)
{
iscsi_cmd_t *icmdp;
icmdp = kmem_zalloc(sizeof (iscsi_cmd_t), km_flags);
if (icmdp) {
icmdp->cmd_sig = ISCSI_SIG_CMD;
icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
icmdp->cmd_conn = icp;
icmdp->cmd_misc_flags |= ISCSI_CMD_MISCFLAG_INTERNAL;
idm_sm_audit_init(&icmdp->cmd_state_audit);
mutex_init(&icmdp->cmd_mutex, NULL, MUTEX_DRIVER, NULL);
cv_init(&icmdp->cmd_completion, NULL, CV_DRIVER, NULL);
}
return (icmdp);
}
void
iscsi_cmd_free(iscsi_cmd_t *icmdp)
{
ASSERT(icmdp != NULL);
ASSERT(icmdp->cmd_sig == ISCSI_SIG_CMD);
ASSERT(icmdp->cmd_state == ISCSI_CMD_STATE_FREE);
ASSERT(icmdp->cmd_next == NULL);
ASSERT(icmdp->cmd_prev == NULL);
ASSERT(icmdp->cmd_misc_flags & ISCSI_CMD_MISCFLAG_INTERNAL);
if (icmdp->cmd_type == ISCSI_CMD_TYPE_ABORT)
ASSERT(icmdp->cmd_un.abort.icmdp == NULL);
else if (icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI) {
ASSERT(icmdp->cmd_un.scsi.r2t_icmdp == NULL);
ASSERT(icmdp->cmd_un.scsi.abort_icmdp == NULL);
}
mutex_destroy(&icmdp->cmd_mutex);
cv_destroy(&icmdp->cmd_completion);
kmem_free(icmdp, sizeof (iscsi_cmd_t));
}
static void
iscsi_cmd_state_free(iscsi_cmd_t *icmdp, iscsi_cmd_event_t event, void *arg)
{
iscsi_sess_t *isp = (iscsi_sess_t *)arg;
ASSERT(icmdp != NULL);
ASSERT(icmdp->cmd_state == ISCSI_CMD_STATE_FREE);
ASSERT(isp != NULL);
switch (event) {
case ISCSI_CMD_EVENT_E1:
icmdp->cmd_lbolt_pending = ddi_get_lbolt();
if (icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI) {
if (icmdp->cmd_un.scsi.pkt &&
icmdp->cmd_un.scsi.pkt->pkt_time)
icmdp->cmd_lbolt_timeout =
icmdp->cmd_lbolt_pending + SEC_TO_TICK(
icmdp->cmd_un.scsi.pkt->pkt_time *
iscsi_cmd_timeout_factor);
else
icmdp->cmd_lbolt_timeout = 0;
icmdp->cmd_un.scsi.pkt_stat &=
ISCSI_CMD_PKT_STAT_INIT;
} else {
icmdp->cmd_lbolt_timeout = icmdp->cmd_lbolt_pending +
SEC_TO_TICK(ISCSI_INTERNAL_CMD_TIMEOUT *
iscsi_cmd_timeout_factor);
}
iscsi_enqueue_pending_cmd(isp, icmdp);
break;
default:
ASSERT(FALSE);
}
}
static void
iscsi_cmd_state_pending(iscsi_cmd_t *icmdp, iscsi_cmd_event_t event, void *arg)
{
iscsi_status_t status;
iscsi_sess_t *isp = (iscsi_sess_t *)arg;
boolean_t free_icmdp = B_FALSE;
int rval;
ASSERT(icmdp != NULL);
ASSERT(icmdp->cmd_state == ISCSI_CMD_STATE_PENDING);
ASSERT(isp != NULL);
switch (event) {
case ISCSI_CMD_EVENT_E2:
ASSERT(mutex_owned(&isp->sess_queue_pending.mutex));
ASSERT(icmdp->cmd_conn != NULL);
switch (icmdp->cmd_type) {
case ISCSI_CMD_TYPE_SCSI:
mutex_enter(&isp->sess_cmdsn_mutex);
if (!iscsi_sna_lte(isp->sess_cmdsn,
isp->sess_maxcmdsn)) {
mutex_exit(&isp->sess_cmdsn_mutex);
mutex_exit(&isp->sess_queue_pending.mutex);
isp->sess_window_open = B_FALSE;
icmdp->cmd_misc_flags |=
ISCSI_CMD_MISCFLAG_STUCK;
return;
}
status = iscsi_sess_reserve_scsi_itt(icmdp);
if (!ISCSI_SUCCESS(status)) {
mutex_exit(&isp->sess_cmdsn_mutex);
mutex_exit(&isp->sess_queue_pending.mutex);
isp->sess_window_open = B_FALSE;
icmdp->cmd_misc_flags |=
ISCSI_CMD_MISCFLAG_STUCK;
return;
}
mutex_exit(&isp->sess_cmdsn_mutex);
break;
case ISCSI_CMD_TYPE_ABORT:
ASSERT(icmdp->cmd_un.abort.icmdp != NULL);
if (icmdp->cmd_un.abort.icmdp->cmd_state ==
ISCSI_CMD_STATE_COMPLETED) {
iscsi_dequeue_pending_cmd(isp, icmdp);
mutex_exit(&isp->sess_queue_pending.mutex);
mutex_enter(&icmdp->cmd_un.abort.icmdp->
cmd_mutex);
icmdp->cmd_un.abort.icmdp->
cmd_un.scsi.abort_icmdp = NULL;
cv_broadcast(&icmdp->cmd_un.abort.icmdp->
cmd_completion);
mutex_exit(&icmdp->cmd_un.abort.icmdp->
cmd_mutex);
icmdp->cmd_un.abort.icmdp = NULL;
icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
icmdp->cmd_misc_flags |=
ISCSI_CMD_MISCFLAG_FREE;
return;
}
case ISCSI_CMD_TYPE_RESET:
case ISCSI_CMD_TYPE_LOGOUT:
mutex_enter(&isp->sess_cmdsn_mutex);
status = iscsi_sess_reserve_itt(isp, icmdp);
if (!ISCSI_SUCCESS(status)) {
mutex_exit(&isp->sess_cmdsn_mutex);
mutex_exit(&isp->sess_queue_pending.mutex);
isp->sess_window_open = B_FALSE;
return;
}
mutex_exit(&isp->sess_cmdsn_mutex);
break;
case ISCSI_CMD_TYPE_NOP:
if (icmdp->cmd_itt == ISCSI_RSVD_TASK_TAG) {
free_icmdp = B_TRUE;
} else {
mutex_enter(&isp->sess_cmdsn_mutex);
status = iscsi_sess_reserve_itt(isp, icmdp);
if (!ISCSI_SUCCESS(status)) {
mutex_exit(&isp->sess_cmdsn_mutex);
mutex_exit(&isp->sess_queue_pending.
mutex);
isp->sess_window_open = B_FALSE;
return;
}
mutex_exit(&isp->sess_cmdsn_mutex);
}
break;
case ISCSI_CMD_TYPE_TEXT:
mutex_enter(&isp->sess_cmdsn_mutex);
if (!iscsi_sna_lte(isp->sess_cmdsn,
isp->sess_maxcmdsn)) {
isp->sess_window_open = B_FALSE;
mutex_exit(&isp->sess_cmdsn_mutex);
mutex_exit(&isp->sess_queue_pending.mutex);
icmdp->cmd_misc_flags |=
ISCSI_CMD_MISCFLAG_STUCK;
return;
}
if (icmdp->cmd_un.text.stage ==
ISCSI_CMD_TEXT_INITIAL_REQ) {
status = iscsi_sess_reserve_itt(isp, icmdp);
if (!ISCSI_SUCCESS(status)) {
mutex_exit(&isp->sess_cmdsn_mutex);
mutex_exit(&isp->sess_queue_pending.
mutex);
isp->sess_window_open = B_FALSE;
icmdp->cmd_misc_flags |=
ISCSI_CMD_MISCFLAG_STUCK;
return;
}
}
mutex_exit(&isp->sess_cmdsn_mutex);
break;
default:
ASSERT(FALSE);
}
if (icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI) {
if (icmdp->cmd_un.scsi.pkt &&
icmdp->cmd_un.scsi.pkt->pkt_time)
icmdp->cmd_lbolt_timeout =
ddi_get_lbolt() + SEC_TO_TICK(
icmdp->cmd_un.scsi.pkt->pkt_time *
iscsi_cmd_timeout_factor);
else
icmdp->cmd_lbolt_timeout = 0;
} else if (icmdp->cmd_type == ISCSI_CMD_TYPE_TEXT) {
icmdp->cmd_lbolt_timeout = ddi_get_lbolt() +
SEC_TO_TICK(ISCSI_INTERNAL_CMD_TIMEOUT *
iscsi_cmd_timeout_factor);
}
iscsi_dequeue_pending_cmd(isp, icmdp);
if (free_icmdp == B_FALSE) {
mutex_enter(&icmdp->cmd_conn->conn_queue_active.mutex);
iscsi_enqueue_active_cmd(icmdp->cmd_conn, icmdp);
mutex_exit(&icmdp->cmd_conn->conn_queue_active.mutex);
}
rval = iscsi_tx_cmd(isp, icmdp);
ASSERT(!mutex_owned(&isp->sess_queue_pending.mutex));
if (!ISCSI_SUCCESS(rval)) {
}
if (free_icmdp == B_TRUE) {
icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
icmdp->cmd_misc_flags |= ISCSI_CMD_MISCFLAG_FREE;
}
break;
case ISCSI_CMD_EVENT_E10:
ASSERT(mutex_owned(&icmdp->cmd_conn->conn_queue_active.mutex));
mutex_enter(&isp->sess_queue_pending.mutex);
icmdp->cmd_lbolt_aborting = ddi_get_lbolt();
iscsi_dequeue_pending_cmd(isp, icmdp);
icmdp->cmd_un.abort.icmdp->cmd_un.scsi.abort_icmdp = NULL;
icmdp->cmd_un.abort.icmdp = NULL;
icmdp->cmd_misc_flags |= ISCSI_CMD_MISCFLAG_FREE;
icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
mutex_exit(&isp->sess_queue_pending.mutex);
break;
case ISCSI_CMD_EVENT_E4:
ASSERT(mutex_owned(&isp->sess_queue_pending.mutex));
icmdp->cmd_lbolt_aborting = ddi_get_lbolt();
ISCSI_CMD_SET_REASON_STAT(icmdp,
CMD_ABORTED, STAT_ABORTED);
iscsi_dequeue_pending_cmd(isp, icmdp);
iscsi_enqueue_completed_cmd(isp, icmdp);
icmdp->cmd_lbolt_aborting = ddi_get_lbolt();
break;
case ISCSI_CMD_EVENT_E7:
case ISCSI_CMD_EVENT_E6:
ASSERT(mutex_owned(&isp->sess_queue_pending.mutex));
iscsi_dequeue_pending_cmd(isp, icmdp);
switch (icmdp->cmd_type) {
case ISCSI_CMD_TYPE_SCSI:
if (event == ISCSI_CMD_EVENT_E6) {
ISCSI_CMD_SET_REASON_STAT(icmdp,
CMD_TIMEOUT, STAT_TIMEOUT);
} else {
ISCSI_CMD_SET_REASON_STAT(icmdp,
CMD_TRAN_ERR, icmdp->cmd_un.scsi.pkt_stat);
}
iscsi_enqueue_completed_cmd(isp, icmdp);
break;
case ISCSI_CMD_TYPE_NOP:
icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
icmdp->cmd_misc_flags |=
ISCSI_CMD_MISCFLAG_FREE;
break;
case ISCSI_CMD_TYPE_ABORT:
mutex_enter(&icmdp->cmd_un.abort.icmdp->cmd_mutex);
icmdp->cmd_un.abort.icmdp->
cmd_un.scsi.abort_icmdp = NULL;
cv_broadcast(&icmdp->cmd_un.abort.icmdp->
cmd_completion);
mutex_exit(&icmdp->cmd_un.abort.icmdp->cmd_mutex);
icmdp->cmd_un.abort.icmdp = NULL;
icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
icmdp->cmd_misc_flags |=
ISCSI_CMD_MISCFLAG_FREE;
break;
case ISCSI_CMD_TYPE_RESET:
icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
ISCSI_CMD_ISSUE_CALLBACK(icmdp,
ISCSI_STATUS_CMD_FAILED);
break;
case ISCSI_CMD_TYPE_LOGOUT:
icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
ISCSI_CMD_ISSUE_CALLBACK(icmdp,
ISCSI_STATUS_CMD_FAILED);
break;
case ISCSI_CMD_TYPE_TEXT:
icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_FINAL_RSP;
ISCSI_CMD_ISSUE_CALLBACK(icmdp,
ISCSI_STATUS_CMD_FAILED);
break;
default:
ASSERT(FALSE);
break;
}
break;
default:
ASSERT(FALSE);
}
}
static void
iscsi_cmd_state_active(iscsi_cmd_t *icmdp, iscsi_cmd_event_t event, void *arg)
{
iscsi_sess_t *isp = (iscsi_sess_t *)arg;
iscsi_hba_t *ihp;
iscsi_cmd_t *t_icmdp = NULL;
iscsi_conn_t *icp = NULL;
ASSERT(icmdp != NULL);
ASSERT(icmdp->cmd_state == ISCSI_CMD_STATE_ACTIVE);
ASSERT(isp != NULL);
ihp = isp->sess_hba;
ASSERT(ihp != NULL);
icp = icmdp->cmd_conn;
ASSERT(icp != NULL);
ASSERT(mutex_owned(&icp->conn_queue_active.mutex));
switch (event) {
case ISCSI_CMD_EVENT_E3:
mutex_enter(&isp->sess_cmdsn_mutex);
iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
switch (icmdp->cmd_type) {
case ISCSI_CMD_TYPE_SCSI:
iscsi_sess_release_scsi_itt(icmdp);
mutex_exit(&isp->sess_cmdsn_mutex);
iscsi_enqueue_completed_cmd(isp, icmdp);
break;
case ISCSI_CMD_TYPE_NOP:
icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
iscsi_sess_release_itt(isp, icmdp);
mutex_exit(&isp->sess_cmdsn_mutex);
icmdp->cmd_misc_flags |=
ISCSI_CMD_MISCFLAG_FREE;
break;
case ISCSI_CMD_TYPE_ABORT:
icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
iscsi_sess_release_itt(isp, icmdp);
mutex_exit(&isp->sess_cmdsn_mutex);
t_icmdp = icmdp->cmd_un.abort.icmdp;
ASSERT(t_icmdp != NULL);
mutex_enter(&t_icmdp->cmd_mutex);
t_icmdp->cmd_un.scsi.abort_icmdp = NULL;
if (t_icmdp->cmd_state != ISCSI_CMD_STATE_COMPLETED) {
iscsi_dequeue_active_cmd(
t_icmdp->cmd_conn, t_icmdp);
mutex_enter(
&icp->conn_queue_idm_aborting.mutex);
iscsi_enqueue_idm_aborting_cmd(
t_icmdp->cmd_conn,
t_icmdp);
mutex_exit(&icp->conn_queue_idm_aborting.mutex);
ISCSI_CMD_SET_REASON_STAT(
t_icmdp, CMD_TIMEOUT, STAT_ABORTED);
(void) idm_task_abort(icp->conn_ic,
t_icmdp->cmd_itp, AT_TASK_MGMT_ABORT);
} else {
cv_broadcast(&t_icmdp->cmd_completion);
}
mutex_exit(&t_icmdp->cmd_mutex);
icmdp->cmd_un.abort.icmdp = NULL;
icmdp->cmd_misc_flags |=
ISCSI_CMD_MISCFLAG_FREE;
break;
case ISCSI_CMD_TYPE_RESET:
icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
iscsi_sess_release_itt(isp, icmdp);
mutex_exit(&isp->sess_cmdsn_mutex);
if (icmdp->cmd_un.reset.response !=
SCSI_TCP_TM_RESP_COMPLETE) {
ISCSI_CMD_ISSUE_CALLBACK(icmdp,
ISCSI_STATUS_CMD_FAILED);
} else {
ISCSI_CMD_ISSUE_CALLBACK(icmdp,
ISCSI_STATUS_SUCCESS);
}
break;
case ISCSI_CMD_TYPE_LOGOUT:
icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
iscsi_sess_release_itt(isp, icmdp);
mutex_exit(&isp->sess_cmdsn_mutex);
ISCSI_CMD_ISSUE_CALLBACK(icmdp, ISCSI_STATUS_SUCCESS);
break;
case ISCSI_CMD_TYPE_TEXT:
icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
if (icmdp->cmd_un.text.stage ==
ISCSI_CMD_TEXT_FINAL_RSP) {
iscsi_sess_release_itt(isp, icmdp);
}
mutex_exit(&isp->sess_cmdsn_mutex);
ISCSI_CMD_ISSUE_CALLBACK(icmdp, icmdp->cmd_result);
break;
default:
mutex_exit(&isp->sess_cmdsn_mutex);
ASSERT(FALSE);
}
ASSERT(!mutex_owned(&isp->sess_cmdsn_mutex));
break;
case ISCSI_CMD_EVENT_E10:
case ISCSI_CMD_EVENT_E4:
ASSERT((icmdp->cmd_type == ISCSI_CMD_TYPE_ABORT) ||
(icmdp->cmd_type == ISCSI_CMD_TYPE_RESET));
case ISCSI_CMD_EVENT_E6:
switch (icmdp->cmd_type) {
case ISCSI_CMD_TYPE_SCSI:
icmdp->cmd_state = ISCSI_CMD_STATE_ABORTING;
iscsi_handle_abort(icmdp);
break;
case ISCSI_CMD_TYPE_NOP:
icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
mutex_enter(&isp->sess_cmdsn_mutex);
iscsi_sess_release_itt(isp, icmdp);
iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
mutex_exit(&isp->sess_cmdsn_mutex);
icmdp->cmd_misc_flags |=
ISCSI_CMD_MISCFLAG_FREE;
break;
case ISCSI_CMD_TYPE_ABORT:
icmdp->cmd_state =
ISCSI_CMD_STATE_FREE;
mutex_enter(&isp->sess_cmdsn_mutex);
iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
iscsi_sess_release_itt(isp, icmdp);
mutex_exit(&isp->sess_cmdsn_mutex);
t_icmdp = icmdp->cmd_un.abort.icmdp;
ASSERT(t_icmdp != NULL);
if (event != ISCSI_CMD_EVENT_E10) {
mutex_enter(&t_icmdp->cmd_mutex);
t_icmdp->cmd_un.scsi.abort_icmdp = NULL;
if ((event == ISCSI_CMD_EVENT_E6) &&
(t_icmdp->cmd_state !=
ISCSI_CMD_STATE_IDM_ABORTING) &&
(t_icmdp->cmd_state !=
ISCSI_CMD_STATE_COMPLETED)) {
iscsi_dequeue_active_cmd(
t_icmdp->cmd_conn, t_icmdp);
mutex_enter(&icp->
conn_queue_idm_aborting.mutex);
iscsi_enqueue_idm_aborting_cmd(
t_icmdp->cmd_conn, t_icmdp);
mutex_exit(&icp->
conn_queue_idm_aborting.mutex);
ISCSI_CMD_SET_REASON_STAT(t_icmdp,
CMD_TIMEOUT, STAT_TIMEOUT);
(void) idm_task_abort(icp->conn_ic,
t_icmdp->cmd_itp,
AT_TASK_MGMT_ABORT);
} else {
cv_broadcast(&t_icmdp->cmd_completion);
}
mutex_exit(&t_icmdp->cmd_mutex);
} else {
t_icmdp->cmd_un.scsi.abort_icmdp = NULL;
}
icmdp->cmd_un.abort.icmdp = NULL;
icmdp->cmd_misc_flags |=
ISCSI_CMD_MISCFLAG_FREE;
break;
case ISCSI_CMD_TYPE_RESET:
icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
mutex_enter(&isp->sess_cmdsn_mutex);
iscsi_sess_release_itt(isp, icmdp);
iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
mutex_exit(&isp->sess_cmdsn_mutex);
ISCSI_CMD_ISSUE_CALLBACK(icmdp,
ISCSI_STATUS_CMD_FAILED);
break;
case ISCSI_CMD_TYPE_LOGOUT:
icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
mutex_enter(&isp->sess_cmdsn_mutex);
iscsi_sess_release_itt(isp, icmdp);
iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
mutex_exit(&isp->sess_cmdsn_mutex);
ISCSI_CMD_ISSUE_CALLBACK(icmdp,
ISCSI_STATUS_CMD_FAILED);
break;
case ISCSI_CMD_TYPE_TEXT:
icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_FINAL_RSP;
mutex_enter(&isp->sess_cmdsn_mutex);
iscsi_sess_release_itt(isp, icmdp);
iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
mutex_exit(&isp->sess_cmdsn_mutex);
ISCSI_CMD_ISSUE_CALLBACK(icmdp,
ISCSI_STATUS_CMD_FAILED);
break;
default:
ASSERT(FALSE);
}
ASSERT(!mutex_owned(&isp->sess_cmdsn_mutex));
break;
case ISCSI_CMD_EVENT_E7:
mutex_enter(&isp->sess_cmdsn_mutex);
iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
switch (icmdp->cmd_type) {
case ISCSI_CMD_TYPE_SCSI:
mutex_exit(&isp->sess_cmdsn_mutex);
mutex_enter(&icp->conn_queue_idm_aborting.mutex);
iscsi_enqueue_idm_aborting_cmd(icmdp->cmd_conn, icmdp);
mutex_exit(&icp->conn_queue_idm_aborting.mutex);
ISCSI_CMD_SET_REASON_STAT(icmdp,
CMD_TRAN_ERR, icmdp->cmd_un.scsi.pkt_stat);
(void) idm_task_abort(icp->conn_ic, icmdp->cmd_itp,
AT_TASK_MGMT_ABORT);
break;
case ISCSI_CMD_TYPE_NOP:
icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
iscsi_sess_release_itt(isp, icmdp);
mutex_exit(&isp->sess_cmdsn_mutex);
icmdp->cmd_misc_flags |=
ISCSI_CMD_MISCFLAG_FREE;
break;
case ISCSI_CMD_TYPE_ABORT:
icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
iscsi_sess_release_itt(isp, icmdp);
mutex_exit(&isp->sess_cmdsn_mutex);
mutex_enter(&icmdp->cmd_un.abort.icmdp->cmd_mutex);
icmdp->cmd_un.abort.icmdp->
cmd_un.scsi.abort_icmdp = NULL;
cv_broadcast(&icmdp->cmd_un.abort.icmdp->
cmd_completion);
mutex_exit(&icmdp->cmd_un.abort.icmdp->cmd_mutex);
icmdp->cmd_un.abort.icmdp = NULL;
icmdp->cmd_misc_flags |=
ISCSI_CMD_MISCFLAG_FREE;
break;
case ISCSI_CMD_TYPE_RESET:
icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
iscsi_sess_release_itt(isp, icmdp);
mutex_exit(&isp->sess_cmdsn_mutex);
ISCSI_CMD_ISSUE_CALLBACK(icmdp,
ISCSI_STATUS_CMD_FAILED);
break;
case ISCSI_CMD_TYPE_LOGOUT:
icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
iscsi_sess_release_itt(isp, icmdp);
mutex_exit(&isp->sess_cmdsn_mutex);
ISCSI_CMD_ISSUE_CALLBACK(icmdp, ISCSI_STATUS_SUCCESS);
break;
case ISCSI_CMD_TYPE_TEXT:
icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
icmdp->cmd_un.text.stage = ISCSI_CMD_TEXT_FINAL_RSP;
iscsi_sess_release_itt(isp, icmdp);
mutex_exit(&isp->sess_cmdsn_mutex);
ISCSI_CMD_ISSUE_CALLBACK(icmdp,
ISCSI_STATUS_CMD_FAILED);
break;
default:
mutex_exit(&isp->sess_cmdsn_mutex);
ASSERT(FALSE);
break;
}
ASSERT(!mutex_owned(&isp->sess_cmdsn_mutex));
break;
case ISCSI_CMD_EVENT_E9:
iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
iscsi_task_cleanup(ISCSI_OP_SCSI_RSP, icmdp);
iscsi_sess_release_scsi_itt(icmdp);
ISCSI_CMD_SET_REASON_STAT(icmdp, CMD_TRAN_ERR,
icmdp->cmd_un.scsi.pkt_stat);
iscsi_enqueue_completed_cmd(isp, icmdp);
break;
default:
ASSERT(FALSE);
}
}
static void
iscsi_cmd_state_aborting(iscsi_cmd_t *icmdp, iscsi_cmd_event_t event, void *arg)
{
iscsi_sess_t *isp = (iscsi_sess_t *)arg;
iscsi_cmd_t *a_icmdp;
ASSERT(icmdp != NULL);
ASSERT(icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI);
ASSERT(icmdp->cmd_state == ISCSI_CMD_STATE_ABORTING);
ASSERT(isp != NULL);
ASSERT(mutex_owned(&icmdp->cmd_conn->conn_queue_active.mutex));
switch (event) {
case ISCSI_CMD_EVENT_E3:
mutex_enter(&isp->sess_cmdsn_mutex);
iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
iscsi_sess_release_scsi_itt(icmdp);
mutex_exit(&isp->sess_cmdsn_mutex);
iscsi_enqueue_completed_cmd(isp, icmdp);
break;
case ISCSI_CMD_EVENT_E4:
break;
case ISCSI_CMD_EVENT_E6:
ASSERT(FALSE);
break;
case ISCSI_CMD_EVENT_E7:
iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
mutex_enter(&icmdp->cmd_conn->conn_queue_idm_aborting.mutex);
iscsi_enqueue_idm_aborting_cmd(icmdp->cmd_conn, icmdp);
mutex_exit(&icmdp->cmd_conn->conn_queue_idm_aborting.mutex);
if ((a_icmdp = icmdp->cmd_un.scsi.abort_icmdp) != NULL) {
iscsi_cmd_state_machine(a_icmdp,
ISCSI_CMD_EVENT_E10, arg);
}
ISCSI_CMD_SET_REASON_STAT(icmdp,
CMD_TRAN_ERR, icmdp->cmd_un.scsi.pkt_stat);
(void) idm_task_abort(icmdp->cmd_conn->conn_ic, icmdp->cmd_itp,
AT_TASK_MGMT_ABORT);
break;
case ISCSI_CMD_EVENT_E9:
iscsi_dequeue_active_cmd(icmdp->cmd_conn, icmdp);
iscsi_task_cleanup(ISCSI_OP_SCSI_RSP, icmdp);
iscsi_sess_release_scsi_itt(icmdp);
ISCSI_CMD_SET_REASON_STAT(icmdp, CMD_TRAN_ERR,
icmdp->cmd_un.scsi.pkt_stat);
iscsi_enqueue_completed_cmd(isp, icmdp);
break;
default:
ASSERT(FALSE);
}
}
static void
iscsi_cmd_state_idm_aborting(iscsi_cmd_t *icmdp, iscsi_cmd_event_t event,
void *arg)
{
iscsi_sess_t *isp = (iscsi_sess_t *)arg;
ASSERT(icmdp != NULL);
ASSERT(icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI);
ASSERT(icmdp->cmd_state == ISCSI_CMD_STATE_IDM_ABORTING);
ASSERT(isp != NULL);
switch (event) {
case ISCSI_CMD_EVENT_E3:
ASSERT(0);
break;
case ISCSI_CMD_EVENT_E4:
break;
case ISCSI_CMD_EVENT_E6:
ASSERT(FALSE);
break;
case ISCSI_CMD_EVENT_E7:
ISCSI_CMD_SET_REASON_STAT(icmdp,
CMD_TRAN_ERR, icmdp->cmd_un.scsi.pkt_stat);
break;
case ISCSI_CMD_EVENT_E9:
mutex_enter(&icmdp->cmd_conn->conn_queue_idm_aborting.mutex);
iscsi_dequeue_idm_aborting_cmd(icmdp->cmd_conn, icmdp);
mutex_exit(&icmdp->cmd_conn->conn_queue_idm_aborting.mutex);
ASSERT(icmdp->cmd_un.scsi.pkt->pkt_reason != CMD_CMPLT);
iscsi_task_cleanup(ISCSI_OP_SCSI_RSP, icmdp);
iscsi_sess_release_scsi_itt(icmdp);
iscsi_enqueue_completed_cmd(isp, icmdp);
cv_broadcast(&icmdp->cmd_completion);
break;
default:
ASSERT(FALSE);
}
}
static void
iscsi_cmd_state_completed(iscsi_cmd_t *icmdp,
iscsi_cmd_event_t event, void *arg)
{
iscsi_sess_t *isp = (iscsi_sess_t *)arg;
ASSERT(icmdp != NULL);
ASSERT(icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI);
ASSERT(icmdp->cmd_state == ISCSI_CMD_STATE_COMPLETED);
ASSERT(isp != NULL);
switch (event) {
case ISCSI_CMD_EVENT_E8:
icmdp->cmd_state = ISCSI_CMD_STATE_FREE;
icmdp->cmd_next = NULL;
icmdp->cmd_prev = NULL;
iscsi_iodone(isp, icmdp);
break;
default:
ASSERT(FALSE);
}
}
static char *
iscsi_cmd_state_str(iscsi_cmd_state_t state)
{
switch (state) {
case ISCSI_CMD_STATE_FREE:
return ("free");
case ISCSI_CMD_STATE_PENDING:
return ("pending");
case ISCSI_CMD_STATE_ACTIVE:
return ("active");
case ISCSI_CMD_STATE_ABORTING:
return ("aborting");
case ISCSI_CMD_STATE_IDM_ABORTING:
return ("idm-aborting");
case ISCSI_CMD_STATE_COMPLETED:
return ("completed");
default:
return ("unknown");
}
}
static char *
iscsi_cmd_event_str(iscsi_cmd_event_t event)
{
switch (event) {
case ISCSI_CMD_EVENT_E1:
return ("E1");
case ISCSI_CMD_EVENT_E2:
return ("E2");
case ISCSI_CMD_EVENT_E3:
return ("E3");
case ISCSI_CMD_EVENT_E4:
return ("E4");
case ISCSI_CMD_EVENT_E6:
return ("E6");
case ISCSI_CMD_EVENT_E7:
return ("E7");
case ISCSI_CMD_EVENT_E8:
return ("E8");
case ISCSI_CMD_EVENT_E9:
return ("E9");
case ISCSI_CMD_EVENT_E10:
return ("E10");
default:
return ("unknown");
}
}
static char *
iscsi_cmd_type_str(iscsi_cmd_type_t type)
{
switch (type) {
case ISCSI_CMD_TYPE_SCSI:
return ("scsi");
case ISCSI_CMD_TYPE_NOP:
return ("nop");
case ISCSI_CMD_TYPE_ABORT:
return ("abort");
case ISCSI_CMD_TYPE_RESET:
return ("reset");
case ISCSI_CMD_TYPE_LOGOUT:
return ("logout");
default:
return ("unknown");
}
}