#include "iscsi.h"
static void iscsi_enqueue_cmd_tail(iscsi_cmd_t **head, iscsi_cmd_t **tail,
iscsi_cmd_t *icmdp);
void
iscsi_init_queue(iscsi_queue_t *queue)
{
ASSERT(queue != NULL);
queue->head = NULL;
queue->tail = NULL;
queue->count = 0;
mutex_init(&queue->mutex, NULL, MUTEX_DRIVER, NULL);
}
void
iscsi_destroy_queue(iscsi_queue_t *queue)
{
ASSERT(queue != NULL);
ASSERT(queue->count == 0);
mutex_destroy(&queue->mutex);
}
void
iscsi_enqueue_pending_cmd(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
{
ASSERT(isp != NULL);
ASSERT(icmdp != NULL);
ASSERT(mutex_owned(&isp->sess_queue_pending.mutex));
icmdp->cmd_state = ISCSI_CMD_STATE_PENDING;
if (icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI) {
iscsi_enqueue_cmd_tail(&isp->sess_queue_pending.head,
&isp->sess_queue_pending.tail, icmdp);
isp->sess_queue_pending.count++;
KSTAT_WAITQ_ENTER(isp);
} else {
iscsi_enqueue_cmd_head(&isp->sess_queue_pending.head,
&isp->sess_queue_pending.tail, icmdp);
isp->sess_queue_pending.count++;
KSTAT_WAITQ_ENTER(isp);
}
iscsi_sess_redrive_io(isp);
}
void
iscsi_dequeue_pending_cmd(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
{
iscsi_status_t rval = ISCSI_STATUS_SUCCESS;
ASSERT(isp != NULL);
ASSERT(icmdp != NULL);
ASSERT(mutex_owned(&isp->sess_queue_pending.mutex));
rval = iscsi_dequeue_cmd(&isp->sess_queue_pending.head,
&isp->sess_queue_pending.tail, icmdp);
if (ISCSI_SUCCESS(rval)) {
isp->sess_queue_pending.count--;
if (((kstat_io_t *)(&isp->stats.ks_io_data))->wcnt) {
KSTAT_WAITQ_EXIT(isp);
} else {
cmn_err(CE_WARN,
"kstat wcnt == 0 when exiting waitq,"
" please check\n");
}
} else {
ASSERT(FALSE);
}
}
void
iscsi_enqueue_active_cmd(iscsi_conn_t *icp, iscsi_cmd_t *icmdp)
{
iscsi_sess_t *isp = NULL;
ASSERT(icp != NULL);
ASSERT(icmdp != NULL);
isp = icp->conn_sess;
ASSERT(isp != NULL);
if (icmdp->cmd_state != ISCSI_CMD_STATE_ABORTING) {
icmdp->cmd_state = ISCSI_CMD_STATE_ACTIVE;
}
if (icmdp->cmd_lbolt_active == 0) {
icmdp->cmd_lbolt_active = ddi_get_lbolt();
iscsi_enqueue_cmd_tail(&icp->conn_queue_active.head,
&icp->conn_queue_active.tail, icmdp);
} else if ((icp->conn_queue_active.head != NULL) &&
(icmdp->cmd_lbolt_active <
icp->conn_queue_active.head->cmd_lbolt_active)) {
iscsi_enqueue_cmd_head(&icp->conn_queue_active.head,
&icp->conn_queue_active.tail, icmdp);
} else {
iscsi_enqueue_cmd_tail(&icp->conn_queue_active.head,
&icp->conn_queue_active.tail, icmdp);
}
icp->conn_queue_active.count++;
if (icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI) {
KSTAT_RUNQ_ENTER(isp);
}
}
void
iscsi_dequeue_active_cmd(iscsi_conn_t *icp, iscsi_cmd_t *icmdp)
{
iscsi_status_t rval = ISCSI_STATUS_SUCCESS;
iscsi_sess_t *isp = NULL;
ASSERT(icp != NULL);
ASSERT(icmdp != NULL);
isp = icp->conn_sess;
ASSERT(isp != NULL);
ASSERT(mutex_owned(&icp->conn_queue_active.mutex));
rval = iscsi_dequeue_cmd(&icp->conn_queue_active.head,
&icp->conn_queue_active.tail, icmdp);
if (ISCSI_SUCCESS(rval)) {
icp->conn_queue_active.count--;
if (icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI) {
if (((kstat_io_t *)(&isp->stats.ks_io_data))->rcnt) {
KSTAT_RUNQ_EXIT(isp);
} else {
cmn_err(CE_WARN,
"kstat rcnt == 0 when exiting runq,"
" please check\n");
}
}
} else {
ASSERT(FALSE);
}
}
void
iscsi_enqueue_idm_aborting_cmd(iscsi_conn_t *icp, iscsi_cmd_t *icmdp)
{
iscsi_sess_t *isp = NULL;
ASSERT(icp != NULL);
ASSERT(icmdp != NULL);
isp = icp->conn_sess;
ASSERT(isp != NULL);
ASSERT(icmdp->cmd_type == ISCSI_CMD_TYPE_SCSI);
ASSERT(mutex_owned(&icp->conn_queue_idm_aborting.mutex));
icmdp->cmd_state = ISCSI_CMD_STATE_IDM_ABORTING;
icmdp->cmd_lbolt_idm_aborting = ddi_get_lbolt();
iscsi_enqueue_cmd_tail(&icp->conn_queue_idm_aborting.head,
&icp->conn_queue_idm_aborting.tail, icmdp);
icp->conn_queue_idm_aborting.count++;
}
void
iscsi_dequeue_idm_aborting_cmd(iscsi_conn_t *icp, iscsi_cmd_t *icmdp)
{
iscsi_sess_t *isp = NULL;
ASSERT(icp != NULL);
ASSERT(icmdp != NULL);
isp = icp->conn_sess;
ASSERT(isp != NULL);
ASSERT(mutex_owned(&icp->conn_queue_idm_aborting.mutex));
(void) iscsi_dequeue_cmd(&icp->conn_queue_idm_aborting.head,
&icp->conn_queue_idm_aborting.tail, icmdp);
icp->conn_queue_idm_aborting.count--;
}
void
iscsi_enqueue_completed_cmd(iscsi_sess_t *isp, iscsi_cmd_t *icmdp)
{
ASSERT(isp != NULL);
ASSERT(icmdp != NULL);
mutex_enter(&isp->sess_queue_completion.mutex);
if (icmdp->cmd_state != ISCSI_CMD_STATE_COMPLETED) {
icmdp->cmd_state = ISCSI_CMD_STATE_COMPLETED;
} else {
mutex_exit(&isp->sess_queue_completion.mutex);
return;
}
iscsi_enqueue_cmd_tail(&isp->sess_queue_completion.head,
&isp->sess_queue_completion.tail, icmdp);
++isp->sess_queue_completion.count;
mutex_exit(&isp->sess_queue_completion.mutex);
(void) iscsi_thread_send_wakeup(isp->sess_ic_thread);
}
void
iscsi_move_queue(
iscsi_queue_t *src_queue,
iscsi_queue_t *dst_queue
)
{
ASSERT(src_queue != NULL);
ASSERT(dst_queue != NULL);
mutex_enter(&src_queue->mutex);
dst_queue->count = src_queue->count;
dst_queue->head = src_queue->head;
dst_queue->tail = src_queue->tail;
src_queue->count = 0;
src_queue->head = NULL;
src_queue->tail = NULL;
mutex_exit(&src_queue->mutex);
}
iscsi_status_t
iscsi_dequeue_cmd(iscsi_cmd_t **head, iscsi_cmd_t **tail, iscsi_cmd_t *icmdp)
{
#ifdef DEBUG
iscsi_cmd_t *tp = NULL;
#endif
ASSERT(head != NULL);
ASSERT(tail != NULL);
ASSERT(icmdp != NULL);
if (*head == NULL) {
return (ISCSI_STATUS_INTERNAL_ERROR);
} else if (*head == *tail) {
if (*head == icmdp) {
*head = NULL;
*tail = NULL;
} else {
return (ISCSI_STATUS_INTERNAL_ERROR);
}
} else {
if (*head == icmdp) {
*head = icmdp->cmd_next;
(*head)->cmd_prev = NULL;
} else if (*tail == icmdp) {
*tail = icmdp->cmd_prev;
(*tail)->cmd_next = NULL;
} else {
#ifdef DEBUG
for (tp = (*head)->cmd_next; (tp != NULL) &&
(tp != icmdp); tp = tp->cmd_next)
;
if (tp == NULL) {
return (ISCSI_STATUS_INTERNAL_ERROR);
}
#endif
if (icmdp->cmd_prev == NULL) {
return (ISCSI_STATUS_INTERNAL_ERROR);
}
icmdp->cmd_prev->cmd_next = icmdp->cmd_next;
if (icmdp->cmd_next == NULL) {
return (ISCSI_STATUS_INTERNAL_ERROR);
}
icmdp->cmd_next->cmd_prev = icmdp->cmd_prev;
}
}
icmdp->cmd_prev = NULL;
icmdp->cmd_next = NULL;
return (ISCSI_STATUS_SUCCESS);
}
void
iscsi_enqueue_cmd_head(iscsi_cmd_t **head, iscsi_cmd_t **tail,
iscsi_cmd_t *icmdp)
{
ASSERT(icmdp != NULL);
ASSERT(icmdp->cmd_next == NULL);
ASSERT(icmdp->cmd_prev == NULL);
ASSERT(icmdp != *head);
ASSERT(icmdp != *tail);
if (*head == NULL) {
*head = *tail = icmdp;
icmdp->cmd_prev = NULL;
icmdp->cmd_next = NULL;
} else {
icmdp->cmd_next = *head;
icmdp->cmd_prev = NULL;
(*head)->cmd_prev = icmdp;
*head = icmdp;
}
}
static void
iscsi_enqueue_cmd_tail(iscsi_cmd_t **head, iscsi_cmd_t **tail,
iscsi_cmd_t *icmdp)
{
ASSERT(icmdp != NULL);
ASSERT(icmdp->cmd_next == NULL);
ASSERT(icmdp->cmd_prev == NULL);
ASSERT(icmdp != *head);
ASSERT(icmdp != *tail);
if (*head == NULL) {
*head = *tail = icmdp;
icmdp->cmd_prev = NULL;
icmdp->cmd_next = NULL;
} else {
icmdp->cmd_next = NULL;
icmdp->cmd_prev = *tail;
(*tail)->cmd_next = icmdp;
*tail = icmdp;
}
}