Commit 052d0144 authored by Mike Christie's avatar Mike Christie Committed by James Bottomley

[SCSI] libiscsi: modify libiscsi so it supports offloaded data paths

This patch modifies libiscsi, so drivers like bnx2i and iser can execute
a command from queuecommand/send_pdu instead of having to be queued to
be run in a workq.
Signed-off-by: default avatarMike Christie <michaelc@cs.wisc.edu>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
parent 0af967f5
...@@ -79,10 +79,12 @@ iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr) ...@@ -79,10 +79,12 @@ iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr)
* xmit thread * xmit thread
*/ */
if (!list_empty(&session->leadconn->xmitqueue) || if (!list_empty(&session->leadconn->xmitqueue) ||
!list_empty(&session->leadconn->mgmtqueue)) !list_empty(&session->leadconn->mgmtqueue)) {
if (!(session->tt->caps & CAP_DATA_PATH_OFFLOAD))
scsi_queue_work(session->host, scsi_queue_work(session->host,
&session->leadconn->xmitwork); &session->leadconn->xmitwork);
} }
}
} }
EXPORT_SYMBOL_GPL(iscsi_update_cmdsn); EXPORT_SYMBOL_GPL(iscsi_update_cmdsn);
...@@ -298,8 +300,12 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) ...@@ -298,8 +300,12 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
WARN_ON(hdrlength >= 256); WARN_ON(hdrlength >= 256);
hdr->hlength = hdrlength & 0xFF; hdr->hlength = hdrlength & 0xFF;
if (conn->session->tt->init_cmd_task(conn->ctask)) if (conn->session->tt->init_cmd_task &&
return EIO; conn->session->tt->init_cmd_task(ctask))
return -EIO;
ctask->state = ISCSI_TASK_RUNNING;
list_move_tail(&ctask->running, &conn->run_list);
conn->scsicmd_pdus_cnt++; conn->scsicmd_pdus_cnt++;
debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x " debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x "
...@@ -334,6 +340,8 @@ static void iscsi_complete_command(struct iscsi_cmd_task *ctask) ...@@ -334,6 +340,8 @@ static void iscsi_complete_command(struct iscsi_cmd_task *ctask)
conn->ctask = NULL; conn->ctask = NULL;
list_del_init(&ctask->running); list_del_init(&ctask->running);
__kfifo_put(session->cmdpool.queue, (void*)&ctask, sizeof(void*)); __kfifo_put(session->cmdpool.queue, (void*)&ctask, sizeof(void*));
if (sc->scsi_done)
sc->scsi_done(sc); sc->scsi_done(sc);
} }
...@@ -403,6 +411,50 @@ void iscsi_free_mgmt_task(struct iscsi_conn *conn, ...@@ -403,6 +411,50 @@ void iscsi_free_mgmt_task(struct iscsi_conn *conn,
} }
EXPORT_SYMBOL_GPL(iscsi_free_mgmt_task); EXPORT_SYMBOL_GPL(iscsi_free_mgmt_task);
static int iscsi_prep_mtask(struct iscsi_conn *conn,
struct iscsi_mgmt_task *mtask)
{
struct iscsi_session *session = conn->session;
struct iscsi_hdr *hdr = mtask->hdr;
struct iscsi_nopout *nop = (struct iscsi_nopout *)hdr;
if (conn->session->state == ISCSI_STATE_LOGGING_OUT)
return -ENOTCONN;
if (hdr->opcode != (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) &&
hdr->opcode != (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE))
nop->exp_statsn = cpu_to_be32(conn->exp_statsn);
/*
* pre-format CmdSN for outgoing PDU.
*/
nop->cmdsn = cpu_to_be32(session->cmdsn);
if (hdr->itt != RESERVED_ITT) {
hdr->itt = build_itt(mtask->itt, session->age);
/*
* TODO: We always use immediate, so we never hit this.
* If we start to send tmfs or nops as non-immediate then
* we should start checking the cmdsn numbers for mgmt tasks.
*/
if (conn->c_stage == ISCSI_CONN_STARTED &&
!(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
session->queued_cmdsn++;
session->cmdsn++;
}
}
if (session->tt->init_mgmt_task)
session->tt->init_mgmt_task(conn, mtask);
if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT)
session->state = ISCSI_STATE_LOGGING_OUT;
list_move_tail(&mtask->running, &conn->mgmt_run_list);
debug_scsi("mgmtpdu [op 0x%x hdr->itt 0x%x datalen %d]\n",
hdr->opcode & ISCSI_OPCODE_MASK, hdr->itt,
mtask->data_count);
return 0;
}
static struct iscsi_mgmt_task * static struct iscsi_mgmt_task *
__iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
char *data, uint32_t data_size) char *data, uint32_t data_size)
...@@ -429,6 +481,12 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, ...@@ -429,6 +481,12 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
if (!__kfifo_get(session->mgmtpool.queue, if (!__kfifo_get(session->mgmtpool.queue,
(void*)&mtask, sizeof(void*))) (void*)&mtask, sizeof(void*)))
return NULL; return NULL;
if ((hdr->opcode == (ISCSI_OP_NOOP_OUT | ISCSI_OP_IMMEDIATE)) &&
hdr->ttt == RESERVED_ITT) {
conn->ping_mtask = mtask;
conn->last_ping = jiffies;
}
} }
if (data_size) { if (data_size) {
...@@ -440,6 +498,19 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, ...@@ -440,6 +498,19 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
memcpy(mtask->hdr, hdr, sizeof(struct iscsi_hdr)); memcpy(mtask->hdr, hdr, sizeof(struct iscsi_hdr));
INIT_LIST_HEAD(&mtask->running); INIT_LIST_HEAD(&mtask->running);
list_add_tail(&mtask->running, &conn->mgmtqueue); list_add_tail(&mtask->running, &conn->mgmtqueue);
if (session->tt->caps & CAP_DATA_PATH_OFFLOAD) {
if (iscsi_prep_mtask(conn, mtask)) {
iscsi_free_mgmt_task(conn, mtask);
return NULL;
}
if (session->tt->xmit_mgmt_task(conn, mtask))
mtask = NULL;
} else
scsi_queue_work(conn->session->host, &conn->xmitwork);
return mtask; return mtask;
} }
...@@ -454,7 +525,6 @@ int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr, ...@@ -454,7 +525,6 @@ int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr,
if (!__iscsi_conn_send_pdu(conn, hdr, data, data_size)) if (!__iscsi_conn_send_pdu(conn, hdr, data, data_size))
err = -EPERM; err = -EPERM;
spin_unlock_bh(&session->lock); spin_unlock_bh(&session->lock);
scsi_queue_work(session->host, &conn->xmitwork);
return err; return err;
} }
EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu); EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu);
...@@ -581,17 +651,8 @@ static void iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr) ...@@ -581,17 +651,8 @@ static void iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr)
hdr.ttt = RESERVED_ITT; hdr.ttt = RESERVED_ITT;
mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)&hdr, NULL, 0); mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)&hdr, NULL, 0);
if (!mtask) { if (!mtask)
iscsi_conn_printk(KERN_ERR, conn, "Could not send nopout\n"); iscsi_conn_printk(KERN_ERR, conn, "Could not send nopout\n");
return;
}
/* only track our nops */
if (!rhdr) {
conn->ping_mtask = mtask;
conn->last_ping = jiffies;
}
scsi_queue_work(conn->session->host, &conn->xmitwork);
} }
static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr, static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
...@@ -868,56 +929,15 @@ void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err) ...@@ -868,56 +929,15 @@ void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err)
} }
EXPORT_SYMBOL_GPL(iscsi_conn_failure); EXPORT_SYMBOL_GPL(iscsi_conn_failure);
static void iscsi_prep_mtask(struct iscsi_conn *conn,
struct iscsi_mgmt_task *mtask)
{
struct iscsi_session *session = conn->session;
struct iscsi_hdr *hdr = mtask->hdr;
struct iscsi_nopout *nop = (struct iscsi_nopout *)hdr;
if (hdr->opcode != (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) &&
hdr->opcode != (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE))
nop->exp_statsn = cpu_to_be32(conn->exp_statsn);
/*
* pre-format CmdSN for outgoing PDU.
*/
nop->cmdsn = cpu_to_be32(session->cmdsn);
if (hdr->itt != RESERVED_ITT) {
hdr->itt = build_itt(mtask->itt, session->age);
/*
* TODO: We always use immediate, so we never hit this.
* If we start to send tmfs or nops as non-immediate then
* we should start checking the cmdsn numbers for mgmt tasks.
*/
if (conn->c_stage == ISCSI_CONN_STARTED &&
!(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
session->queued_cmdsn++;
session->cmdsn++;
}
}
if (session->tt->init_mgmt_task)
session->tt->init_mgmt_task(conn, mtask);
debug_scsi("mgmtpdu [op 0x%x hdr->itt 0x%x datalen %d]\n",
hdr->opcode & ISCSI_OPCODE_MASK, hdr->itt,
mtask->data_count);
}
static int iscsi_xmit_mtask(struct iscsi_conn *conn) static int iscsi_xmit_mtask(struct iscsi_conn *conn)
{ {
struct iscsi_hdr *hdr = conn->mtask->hdr;
int rc; int rc;
if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT)
conn->session->state = ISCSI_STATE_LOGGING_OUT;
spin_unlock_bh(&conn->session->lock); spin_unlock_bh(&conn->session->lock);
rc = conn->session->tt->xmit_mgmt_task(conn, conn->mtask); rc = conn->session->tt->xmit_mgmt_task(conn, conn->mtask);
spin_lock_bh(&conn->session->lock); spin_lock_bh(&conn->session->lock);
if (rc) if (rc)
return rc; return rc;
/* done with this in-progress mtask */ /* done with this in-progress mtask */
conn->mtask = NULL; conn->mtask = NULL;
return 0; return 0;
...@@ -961,7 +981,8 @@ static int iscsi_xmit_ctask(struct iscsi_conn *conn) ...@@ -961,7 +981,8 @@ static int iscsi_xmit_ctask(struct iscsi_conn *conn)
* @ctask: ctask to requeue * @ctask: ctask to requeue
* *
* LLDs that need to run a ctask from the session workqueue should call * LLDs that need to run a ctask from the session workqueue should call
* this. The session lock must be held. * this. The session lock must be held. This should only be called
* by software drivers.
*/ */
void iscsi_requeue_ctask(struct iscsi_cmd_task *ctask) void iscsi_requeue_ctask(struct iscsi_cmd_task *ctask)
{ {
...@@ -1013,14 +1034,11 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) ...@@ -1013,14 +1034,11 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
while (!list_empty(&conn->mgmtqueue)) { while (!list_empty(&conn->mgmtqueue)) {
conn->mtask = list_entry(conn->mgmtqueue.next, conn->mtask = list_entry(conn->mgmtqueue.next,
struct iscsi_mgmt_task, running); struct iscsi_mgmt_task, running);
if (conn->session->state == ISCSI_STATE_LOGGING_OUT) { if (iscsi_prep_mtask(conn, conn->mtask)) {
iscsi_free_mgmt_task(conn, conn->mtask); iscsi_free_mgmt_task(conn, conn->mtask);
conn->mtask = NULL; conn->mtask = NULL;
continue; continue;
} }
iscsi_prep_mtask(conn, conn->mtask);
list_move_tail(conn->mgmtqueue.next, &conn->mgmt_run_list);
rc = iscsi_xmit_mtask(conn); rc = iscsi_xmit_mtask(conn);
if (rc) if (rc)
goto again; goto again;
...@@ -1041,9 +1059,6 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) ...@@ -1041,9 +1059,6 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
fail_command(conn, conn->ctask, DID_ABORT << 16); fail_command(conn, conn->ctask, DID_ABORT << 16);
continue; continue;
} }
conn->ctask->state = ISCSI_TASK_RUNNING;
list_move_tail(conn->xmitqueue.next, &conn->run_list);
rc = iscsi_xmit_ctask(conn); rc = iscsi_xmit_ctask(conn);
if (rc) if (rc)
goto again; goto again;
...@@ -1192,8 +1207,6 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) ...@@ -1192,8 +1207,6 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
reason = FAILURE_OOM; reason = FAILURE_OOM;
goto reject; goto reject;
} }
session->queued_cmdsn++;
sc->SCp.phase = session->age; sc->SCp.phase = session->age;
sc->SCp.ptr = (char *)ctask; sc->SCp.ptr = (char *)ctask;
...@@ -1202,11 +1215,26 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) ...@@ -1202,11 +1215,26 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
ctask->conn = conn; ctask->conn = conn;
ctask->sc = sc; ctask->sc = sc;
INIT_LIST_HEAD(&ctask->running); INIT_LIST_HEAD(&ctask->running);
list_add_tail(&ctask->running, &conn->xmitqueue); list_add_tail(&ctask->running, &conn->xmitqueue);
spin_unlock(&session->lock);
scsi_queue_work(host, &conn->xmitwork); if (session->tt->caps & CAP_DATA_PATH_OFFLOAD) {
if (iscsi_prep_scsi_cmd_pdu(ctask)) {
sc->result = DID_ABORT << 16;
sc->scsi_done = NULL;
iscsi_complete_command(ctask);
goto fault;
}
if (session->tt->xmit_cmd_task(conn, ctask)) {
sc->scsi_done = NULL;
iscsi_complete_command(ctask);
reason = FAILURE_SESSION_NOT_READY;
goto reject;
}
} else
scsi_queue_work(session->host, &conn->xmitwork);
session->queued_cmdsn++;
spin_unlock(&session->lock);
spin_lock(host->host_lock); spin_lock(host->host_lock);
return 0; return 0;
...@@ -1225,7 +1253,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) ...@@ -1225,7 +1253,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
scsi_out(sc)->resid = scsi_out(sc)->length; scsi_out(sc)->resid = scsi_out(sc)->length;
scsi_in(sc)->resid = scsi_in(sc)->length; scsi_in(sc)->resid = scsi_in(sc)->length;
} }
sc->scsi_done(sc); done(sc);
spin_lock(host->host_lock); spin_lock(host->host_lock);
return 0; return 0;
} }
...@@ -1344,7 +1372,6 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn, ...@@ -1344,7 +1372,6 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
spin_unlock_bh(&session->lock); spin_unlock_bh(&session->lock);
mutex_unlock(&session->eh_mutex); mutex_unlock(&session->eh_mutex);
scsi_queue_work(session->host, &conn->xmitwork);
/* /*
* block eh thread until: * block eh thread until:
...@@ -1412,6 +1439,7 @@ static void fail_all_commands(struct iscsi_conn *conn, unsigned lun, ...@@ -1412,6 +1439,7 @@ static void fail_all_commands(struct iscsi_conn *conn, unsigned lun,
void iscsi_suspend_tx(struct iscsi_conn *conn) void iscsi_suspend_tx(struct iscsi_conn *conn)
{ {
set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
if (!(conn->session->tt->caps & CAP_DATA_PATH_OFFLOAD))
scsi_flush_work(conn->session->host); scsi_flush_work(conn->session->host);
} }
EXPORT_SYMBOL_GPL(iscsi_suspend_tx); EXPORT_SYMBOL_GPL(iscsi_suspend_tx);
...@@ -1419,6 +1447,7 @@ EXPORT_SYMBOL_GPL(iscsi_suspend_tx); ...@@ -1419,6 +1447,7 @@ EXPORT_SYMBOL_GPL(iscsi_suspend_tx);
static void iscsi_start_tx(struct iscsi_conn *conn) static void iscsi_start_tx(struct iscsi_conn *conn)
{ {
clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
if (!(conn->session->tt->caps & CAP_DATA_PATH_OFFLOAD))
scsi_queue_work(conn->session->host, &conn->xmitwork); scsi_queue_work(conn->session->host, &conn->xmitwork);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment