From: Mike Christie <michaelc@cs.wisc.edu>
To: "Nicholas A. Bellinger" <nab@linux-iscsi.org>
Cc: Christoph Hellwig <hch@infradead.org>,
Jens Axboe <axboe@kernel.dk>,
James Bottomley <JBottomley@Parallels.com>,
linux-scsi@vger.kernel.org
Subject: Re: [PATCH 12/15] scsi: initial blk-mq support
Date: Fri, 07 Feb 2014 02:45:18 -0600 [thread overview]
Message-ID: <52F49D1E.2000007@cs.wisc.edu> (raw)
In-Reply-To: <1391724663.14985.11.camel@haakon3.risingtidesystems.com>
[-- Attachment #1: Type: text/plain, Size: 2072 bytes --]
On 02/06/2014 04:11 PM, Nicholas A. Bellinger wrote:
>> +struct request_queue *scsi_mq_alloc_queue(struct scsi_device *sdev)
>> > +{
>> > + struct Scsi_Host *shost = sdev->host;
>> > + struct blk_mq_hw_ctx *hctx;
>> > + struct request_queue *q;
>> > + struct request *rq;
>> > + struct scsi_cmnd *cmd;
>> > + struct blk_mq_reg reg;
>> > + int i, j, sgl_size;
>> > +
>> > + memset(®, 0, sizeof(reg));
>> > + reg.ops = &scsi_mq_ops;
>> > + reg.queue_depth = shost->cmd_per_lun;
>> > + if (!reg.queue_depth)
>> > + reg.queue_depth = 1;
>> > +
>> > + /* XXX: what to do about chained S/G lists? */
>> > + if (shost->hostt->sg_tablesize > SCSI_MAX_SG_SEGMENTS)
>> > + shost->sg_tablesize = SCSI_MAX_SG_SEGMENTS;
>> > + sgl_size = shost->sg_tablesize * sizeof(struct scatterlist);
>> > +
>> > + reg.cmd_size = sizeof(struct scsi_cmnd) +
>> > + sgl_size +
>> > + shost->hostt->cmd_size;
>> > + if (scsi_host_get_prot(shost))
>> > + reg.cmd_size += sizeof(struct scsi_data_buffer) + sgl_size;
> OK, so your in-lining the allocation of data + protection SGLs from
> blk-mq..
>
> The original prototype code was doing these allocations separately below
> for each pre-allocated cmd, and offering LLD's to optionally
> pre-allocate their own descripts using sh->hostt->cmd_size if
> necessary..
>
> This was necessary to eliminate all fast-path allocations for
> virtio-scsi, and I'd like to see something similar here as an optional
> feature as well.
Yeah, it would be nice if like in Nick's patches, the driver could just
set the scsi_host_template->cmd_size then when the scsi_cmnd got to the
driver's queuecommand, the driver could just get its internal cmd struct
from the scsi_cmnd struct (for example in Nick's patch it was off the
SCp.ptr).
I started converting my iscsi mq patch from Nick's code to Christoph's
and am currently trying to figure out how to setup the
scsi_host_template->cmd_pool.
Current iscsi patch is attached if anyone cares.
However, one question I had with both approaches is how to deal with per
cmd pci/dma memory and preallocations.
[-- Attachment #2: iscsi-mq-cmd-size.patch --]
[-- Type: text/plain, Size: 28244 bytes --]
diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index bc77a6f..1d0857c 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -320,10 +320,10 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc)
memset(inv_tbl, 0x0, sizeof(*inv_tbl) * BE2_CMDS_PER_CXN);
num_invalidate = 0;
for (i = 0; i < conn->session->cmds_max; i++) {
- abrt_task = conn->session->cmds[i];
- abrt_io_task = abrt_task->dd_data;
- if (!abrt_task->sc || abrt_task->state == ISCSI_TASK_FREE)
+ abrt_task = conn->session->task_map[i];
+ if (!abrt_task || abrt_task->state != ISCSI_TASK_RUNNING)
continue;
+ abrt_io_task = abrt_task->dd_data;
if (sc->device->lun != abrt_task->sc->device->lun)
continue;
diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c
index c00642f..34289b4 100644
--- a/drivers/scsi/bnx2i/bnx2i_iscsi.c
+++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c
@@ -447,7 +447,7 @@ static int bnx2i_alloc_bdt(struct bnx2i_hba *hba, struct iscsi_session *session,
io->bd_tbl = dma_alloc_coherent(&hba->pcidev->dev,
ISCSI_MAX_BDS_PER_CMD * sizeof(*bd),
- &io->bd_tbl_dma, GFP_KERNEL);
+ &io->bd_tbl_dma, GFP_ATOMIC);
if (!io->bd_tbl) {
iscsi_session_printk(KERN_ERR, session, "Could not "
"allocate bdt.\n");
@@ -458,61 +458,6 @@ static int bnx2i_alloc_bdt(struct bnx2i_hba *hba, struct iscsi_session *session,
}
/**
- * bnx2i_destroy_cmd_pool - destroys iscsi command pool and release BD table
- * @hba: adapter instance pointer
- * @session: iscsi session pointer
- * @cmd: iscsi command structure
- */
-static void bnx2i_destroy_cmd_pool(struct bnx2i_hba *hba,
- struct iscsi_session *session)
-{
- int i;
-
- for (i = 0; i < session->cmds_max; i++) {
- struct iscsi_task *task = session->cmds[i];
- struct bnx2i_cmd *cmd = task->dd_data;
-
- if (cmd->io_tbl.bd_tbl)
- dma_free_coherent(&hba->pcidev->dev,
- ISCSI_MAX_BDS_PER_CMD *
- sizeof(struct iscsi_bd),
- cmd->io_tbl.bd_tbl,
- cmd->io_tbl.bd_tbl_dma);
- }
-
-}
-
-
-/**
- * bnx2i_setup_cmd_pool - sets up iscsi command pool for the session
- * @hba: adapter instance pointer
- * @session: iscsi session pointer
- */
-static int bnx2i_setup_cmd_pool(struct bnx2i_hba *hba,
- struct iscsi_session *session)
-{
- int i;
-
- for (i = 0; i < session->cmds_max; i++) {
- struct iscsi_task *task = session->cmds[i];
- struct bnx2i_cmd *cmd = task->dd_data;
-
- task->hdr = &cmd->hdr;
- task->hdr_max = sizeof(struct iscsi_hdr);
-
- if (bnx2i_alloc_bdt(hba, session, cmd))
- goto free_bdts;
- }
-
- return 0;
-
-free_bdts:
- bnx2i_destroy_cmd_pool(hba, session);
- return -ENOMEM;
-}
-
-
-/**
* bnx2i_setup_mp_bdt - allocate BD table resources
* @hba: pointer to adapter structure
*
@@ -1157,7 +1102,14 @@ static void bnx2i_cleanup_task(struct iscsi_task *task)
struct iscsi_conn *conn = task->conn;
struct bnx2i_conn *bnx2i_conn = conn->dd_data;
struct bnx2i_hba *hba = bnx2i_conn->hba;
+ struct bnx2i_cmd *cmd = task->dd_data;
+ if (cmd->io_tbl.bd_tbl)
+ dma_free_coherent(&hba->pcidev->dev,
+ ISCSI_MAX_BDS_PER_CMD *
+ sizeof(struct iscsi_bd),
+ cmd->io_tbl.bd_tbl,
+ cmd->io_tbl.bd_tbl_dma);
/*
* mgmt task or cmd was never sent to us to transmit.
*/
@@ -1178,6 +1130,29 @@ static void bnx2i_cleanup_task(struct iscsi_task *task)
}
/**
+ * bnx2i_alloc_pdu - setup task/pdu and its bdt
+ * @task: transport layer command structure pointer
+ * @opcode: iscsi opcode for task/pdu to setup for
+ *
+ * The bdt will be freed in bnx2i_cleanup_task.
+ */
+static int bnx2i_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
+{
+ struct bnx2i_cmd *cmd = task->dd_data;
+ struct iscsi_conn *conn = task->conn;
+ struct bnx2i_conn *bnx2i_conn = conn->dd_data;
+ struct bnx2i_hba *hba = bnx2i_conn->hba;
+
+ task->hdr = &cmd->hdr;
+ task->hdr_max = sizeof(struct iscsi_hdr);
+
+ if (bnx2i_alloc_bdt(hba, conn->session, cmd))
+ return -ENOMEM;
+
+ return 0;
+}
+
+/**
* bnx2i_mtask_xmit - transmit mtask to chip for further processing
* @conn: transport layer conn structure pointer
* @task: transport layer command structure pointer
@@ -1284,7 +1259,6 @@ bnx2i_session_create(struct iscsi_endpoint *ep,
uint32_t initial_cmdsn)
{
struct Scsi_Host *shost;
- struct iscsi_cls_session *cls_session;
struct bnx2i_hba *hba;
struct bnx2i_endpoint *bnx2i_ep;
@@ -1308,40 +1282,11 @@ bnx2i_session_create(struct iscsi_endpoint *ep,
else if (cmds_max < BNX2I_SQ_WQES_MIN)
cmds_max = BNX2I_SQ_WQES_MIN;
- cls_session = iscsi_session_setup(&bnx2i_iscsi_transport, shost,
- cmds_max, 0, sizeof(struct bnx2i_cmd),
- initial_cmdsn, ISCSI_MAX_TARGET);
- if (!cls_session)
- return NULL;
-
- if (bnx2i_setup_cmd_pool(hba, cls_session->dd_data))
- goto session_teardown;
- return cls_session;
-
-session_teardown:
- iscsi_session_teardown(cls_session);
- return NULL;
-}
-
-
-/**
- * bnx2i_session_destroy - destroys iscsi session
- * @cls_session: pointer to iscsi cls session
- *
- * Destroys previously created iSCSI session instance and releases
- * all resources held by it
- */
-static void bnx2i_session_destroy(struct iscsi_cls_session *cls_session)
-{
- struct iscsi_session *session = cls_session->dd_data;
- struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
- struct bnx2i_hba *hba = iscsi_host_priv(shost);
-
- bnx2i_destroy_cmd_pool(hba, session);
- iscsi_session_teardown(cls_session);
+ return iscsi_session_setup(&bnx2i_iscsi_transport, shost,
+ cmds_max, 0, sizeof(struct bnx2i_cmd),
+ initial_cmdsn, ISCSI_MAX_TARGET);
}
-
/**
* bnx2i_conn_create - create iscsi connection instance
* @cls_session: pointer to iscsi cls session
@@ -2273,7 +2218,7 @@ struct iscsi_transport bnx2i_iscsi_transport = {
CAP_DATA_PATH_OFFLOAD |
CAP_TEXT_NEGO,
.create_session = bnx2i_session_create,
- .destroy_session = bnx2i_session_destroy,
+ .destroy_session = iscsi_session_teardown,
.create_conn = bnx2i_conn_create,
.bind_conn = bnx2i_conn_bind,
.destroy_conn = bnx2i_conn_destroy,
@@ -2284,6 +2229,7 @@ struct iscsi_transport bnx2i_iscsi_transport = {
.get_host_param = bnx2i_host_get_param,
.start_conn = bnx2i_conn_start,
.stop_conn = iscsi_conn_stop,
+ .alloc_pdu = bnx2i_alloc_pdu,
.send_pdu = iscsi_conn_send_pdu,
.xmit_task = bnx2i_task_xmit,
.get_stats = bnx2i_conn_get_stats,
diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c
index b44c1cf..9b64ddc 100644
--- a/drivers/scsi/cxgbi/libcxgbi.c
+++ b/drivers/scsi/cxgbi/libcxgbi.c
@@ -2306,7 +2306,6 @@ struct iscsi_cls_session *cxgbi_create_session(struct iscsi_endpoint *ep,
struct cxgbi_hba *chba;
struct Scsi_Host *shost;
struct iscsi_cls_session *cls_session;
- struct iscsi_session *session;
if (!ep) {
pr_err("missing endpoint.\n");
@@ -2327,17 +2326,9 @@ struct iscsi_cls_session *cxgbi_create_session(struct iscsi_endpoint *ep,
if (!cls_session)
return NULL;
- session = cls_session->dd_data;
- if (iscsi_tcp_r2tpool_alloc(session))
- goto remove_session;
-
log_debug(1 << CXGBI_DBG_ISCSI,
"ep 0x%p, cls sess 0x%p.\n", ep, cls_session);
return cls_session;
-
-remove_session:
- iscsi_session_teardown(cls_session);
- return NULL;
}
EXPORT_SYMBOL_GPL(cxgbi_create_session);
@@ -2346,7 +2337,6 @@ void cxgbi_destroy_session(struct iscsi_cls_session *cls_session)
log_debug(1 << CXGBI_DBG_ISCSI,
"cls sess 0x%p.\n", cls_session);
- iscsi_tcp_r2tpool_free(cls_session->dd_data);
iscsi_session_teardown(cls_session);
}
EXPORT_SYMBOL_GPL(cxgbi_destroy_session);
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index ad5244d..efb8d75 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -850,12 +850,8 @@ iscsi_sw_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max,
tcp_sw_host->session = session;
shost->can_queue = session->scsi_cmds_max;
- if (iscsi_tcp_r2tpool_alloc(session))
- goto remove_session;
return cls_session;
-remove_session:
- iscsi_session_teardown(cls_session);
remove_host:
iscsi_host_remove(shost);
free_host:
@@ -867,7 +863,6 @@ static void iscsi_sw_tcp_session_destroy(struct iscsi_cls_session *cls_session)
{
struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
- iscsi_tcp_r2tpool_free(cls_session->dd_data);
iscsi_session_teardown(cls_session);
iscsi_host_remove(shost);
@@ -961,6 +956,9 @@ static struct scsi_host_template iscsi_sw_tcp_sht = {
.proc_name = "iscsi_tcp",
.this_id = -1,
.use_blk_mq = true,
+ .cmd_size = sizeof(struct iscsi_task) +
+ sizeof(struct iscsi_tcp_task) +
+ sizeof(struct iscsi_sw_tcp_hdrbuf),
};
static struct iscsi_transport iscsi_sw_tcp_transport = {
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 63032d3..24b2c3f 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -426,6 +426,12 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
r2t->data_offset = task->imm_count;
r2t->ttt = cpu_to_be32(ISCSI_RESERVED_TAG);
r2t->exp_statsn = cpu_to_be32(conn->exp_statsn);
+ /*
+ * make sure if xmit thread is handling multiple tasks
+ * it sees all these updated
+ */
+ smp_wmb();
+ r2t->sent = 0;
}
if (!task->unsol_r2t.data_length)
@@ -496,9 +502,12 @@ static void iscsi_free_task(struct iscsi_task *task)
if (conn->login_task == task)
return;
- kfifo_in(&session->cmdpool.queue, (void*)&task, sizeof(void*));
+ session->task_map[task->itt] = NULL;
+ percpu_ida_free(&session->itts, task->itt);
- if (sc) {
+ if (!sc) {
+ kfifo_in(&session->mgmt_pool.queue, (void*)&task, sizeof(void*));
+ } else {
/* SCSI eh reuses commands to verify us */
sc->SCp.ptr = NULL;
/*
@@ -595,7 +604,7 @@ EXPORT_SYMBOL_GPL(iscsi_complete_scsi_task);
/*
- * session back_lock must be held and if not called for a task that is
+ * session frwd_lock must be held and if not called for a task that is
* still pending or from the xmit thread, then xmit thread must
* be suspended.
*/
@@ -696,6 +705,7 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
uint8_t opcode = hdr->opcode & ISCSI_OPCODE_MASK;
struct iscsi_task *task;
itt_t itt;
+ int tag;
if (session->state == ISCSI_STATE_TERMINATE)
return NULL;
@@ -721,10 +731,20 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
- if (!kfifo_out(&session->cmdpool.queue,
+ if (!kfifo_out(&session->mgmt_pool.queue,
(void*)&task, sizeof(void*)))
return NULL;
+
+ tag = percpu_ida_alloc(&session->itts, GFP_ATOMIC);
+ if (tag < 0) {
+ kfifo_in(&session->mgmt_pool.queue, (void*)&task,
+ sizeof(void*));
+ return NULL;
+ }
+ task->itt = tag;
+ session->task_map[tag] = task;
}
+
/*
* released in complete pdu for task we expect a response for, and
* released by the lld when it has transmitted the task for
@@ -735,6 +755,7 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
task->sc = NULL;
INIT_LIST_HEAD(&task->running);
task->state = ISCSI_TASK_PENDING;
+ task->dd_data = &task[1];
if (data_size) {
memcpy(task->data, data, data_size);
@@ -1095,7 +1116,7 @@ struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *conn, itt_t itt)
if (i >= session->cmds_max)
return NULL;
- return session->cmds[i];
+ return session->task_map[i];
}
EXPORT_SYMBOL_GPL(iscsi_itt_to_task);
@@ -1563,19 +1584,23 @@ static void iscsi_xmitworker(struct work_struct *work)
} while (rc >= 0 || rc == -EAGAIN);
}
-static inline struct iscsi_task *iscsi_alloc_task(struct iscsi_conn *conn,
- struct scsi_cmnd *sc)
+static inline struct iscsi_task *iscsi_init_task(struct iscsi_conn *conn,
+ struct scsi_cmnd *sc)
{
- struct iscsi_task *task;
-
- if (!kfifo_out(&conn->session->cmdpool.queue,
- (void *) &task, sizeof(void *)))
- return NULL;
+ struct iscsi_session *session = conn->session;
+ struct iscsi_task *task = scsi_get_drv_cmd(sc); /*TODO - how to go from cmd to driver struct in hch's patches */
+ int tag;
- sc->SCp.phase = conn->session->age;
+ sc->SCp.phase = session->age;
sc->SCp.ptr = (char *) task;
+ tag = percpu_ida_alloc(&session->itts, GFP_ATOMIC);
+ if (tag < 0)
+ return NULL;
+
+ task->dd_data = &task[1];
atomic_set(&task->refcount, 1);
+ task->itt = tag;
task->state = ISCSI_TASK_PENDING;
task->conn = conn;
task->sc = sc;
@@ -1583,6 +1608,7 @@ static inline struct iscsi_task *iscsi_alloc_task(struct iscsi_conn *conn,
task->last_timeout = jiffies;
task->last_xfer = jiffies;
INIT_LIST_HEAD(&task->running);
+ session->task_map[tag] = task;
return task;
}
@@ -1673,7 +1699,7 @@ int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc)
goto reject;
}
- task = iscsi_alloc_task(conn, sc);
+ task = iscsi_init_task(conn, sc);
if (!task) {
reason = FAILURE_OOM;
goto reject;
@@ -1824,8 +1850,8 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
}
/*
- * Fail commands. session lock held and recv side suspended and xmit
- * thread flushed
+ * Fail commands. session frwd_lock must be held and recv side suspended and
+ * xmit thread flushed
*/
static void fail_scsi_tasks(struct iscsi_conn *conn, unsigned lun,
int error)
@@ -1834,8 +1860,8 @@ static void fail_scsi_tasks(struct iscsi_conn *conn, unsigned lun,
int i;
for (i = 0; i < conn->session->cmds_max; i++) {
- task = conn->session->cmds[i];
- if (!task->sc || task->state == ISCSI_TASK_FREE)
+ task = conn->session->task_map[i];
+ if (!task || !task->sc || task->state == ISCSI_TASK_FREE)
continue;
if (lun != -1 && lun != task->sc->device->lun)
@@ -1978,9 +2004,10 @@ static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc)
}
for (i = 0; i < conn->session->cmds_max; i++) {
- running_task = conn->session->cmds[i];
- if (!running_task->sc || running_task == task ||
- running_task->state != ISCSI_TASK_RUNNING)
+ running_task = conn->session->task_map[i];
+ if (!running_task || !running_task->sc ||
+ running_task == task ||
+ running_task->state != ISCSI_TASK_RUNNING)
continue;
/*
@@ -2697,7 +2724,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
struct iscsi_host *ihost = shost_priv(shost);
struct iscsi_session *session;
struct iscsi_cls_session *cls_session;
- int cmd_i, scsi_cmds, total_cmds = cmds_max;
+ int scsi_cmds, total_cmds = cmds_max;
unsigned long flags;
spin_lock_irqsave(&ihost->lock, flags);
@@ -2766,22 +2793,23 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
spin_lock_init(&session->frwd_lock);
spin_lock_init(&session->back_lock);
- /* initialize SCSI PDU commands pool */
- if (iscsi_pool_init(&session->cmdpool, session->cmds_max,
- (void***)&session->cmds,
- cmd_task_size + sizeof(struct iscsi_task)))
- goto cmdpool_alloc_fail;
+ /*
+ * TODO: make block layer handle this like was done for
+ * the non-mq host wide tagging.
+ */
+ if (percpu_ida_init(&session->itts, total_cmds))
+ goto itts_init;
- /* pre-format cmds pool with ITT */
- for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) {
- struct iscsi_task *task = session->cmds[cmd_i];
+ /* initialize LOGIN/NOP/TMF PDU pool */
+ if (iscsi_pool_init(&session->mgmt_pool, ISCSI_MGMT_CMDS_MAX,
+ (void***)&session->mgmt_cmds,
+ cmd_task_size + sizeof(struct iscsi_task)))
+ goto mgmtpool_alloc_fail;
- if (cmd_task_size)
- task->dd_data = &task[1];
- task->itt = cmd_i;
- task->state = ISCSI_TASK_FREE;
- INIT_LIST_HEAD(&task->running);
- }
+ session->task_map = kzalloc(sizeof(struct iscsi_task *) *
+ session->cmds_max, GFP_KERNEL);
+ if (!session->task_map)
+ goto task_map_alloc_fail;
if (!try_module_get(iscsit->owner))
goto module_get_fail;
@@ -2794,8 +2822,12 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
cls_session_fail:
module_put(iscsit->owner);
module_get_fail:
- iscsi_pool_free(&session->cmdpool);
-cmdpool_alloc_fail:
+ kfree(session->task_map);
+task_map_alloc_fail:
+ iscsi_pool_free(&session->mgmt_pool);
+mgmtpool_alloc_fail:
+ percpu_ida_destroy(&session->itts);
+itts_init:
iscsi_free_session(cls_session);
dec_session_count:
iscsi_host_dec_session_cnt(shost);
@@ -2816,7 +2848,7 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
struct module *owner = cls_session->transport->owner;
struct Scsi_Host *shost = session->host;
- iscsi_pool_free(&session->cmdpool);
+ iscsi_pool_free(&session->mgmt_pool);
kfree(session->password);
kfree(session->password_in);
@@ -2831,6 +2863,9 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
kfree(session->ifacename);
kfree(session->portal_type);
kfree(session->discovery_parent_type);
+ kfree(session->task_map);
+
+ percpu_ida_destroy(&session->itts);
iscsi_destroy_session(cls_session);
iscsi_host_dec_session_cnt(shost);
@@ -2852,6 +2887,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
struct iscsi_conn *conn;
struct iscsi_cls_conn *cls_conn;
char *data;
+ int tag;
cls_conn = iscsi_create_conn(cls_session, sizeof(*conn) + dd_size,
conn_idx);
@@ -2879,7 +2915,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
/* allocate login_task used for the login/text sequences */
spin_lock_bh(&session->frwd_lock);
- if (!kfifo_out(&session->cmdpool.queue,
+ if (!kfifo_out(&session->mgmt_pool.queue,
(void*)&conn->login_task,
sizeof(void*))) {
spin_unlock_bh(&session->frwd_lock);
@@ -2893,13 +2929,22 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
goto login_task_data_alloc_fail;
conn->login_task->data = conn->data = data;
+ tag = percpu_ida_alloc(&session->itts, GFP_KERNEL);
+ if (tag < 0)
+ goto login_itt_fail;
+
+ conn->login_task->itt = tag;
+printk(KERN_ERR "iscsi login task !!!!!!!!!!!!!!!!!! %d\n", conn->login_task->itt);
+ session->task_map[tag] = conn->login_task;
init_timer(&conn->tmf_timer);
init_waitqueue_head(&conn->ehwait);
return cls_conn;
+login_itt_fail:
+ kfree(data);
login_task_data_alloc_fail:
- kfifo_in(&session->cmdpool.queue, (void*)&conn->login_task,
+ kfifo_in(&session->mgmt_pool.queue, (void*)&conn->login_task,
sizeof(void*));
login_task_alloc_fail:
iscsi_destroy_conn(cls_conn);
@@ -2965,7 +3010,8 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
kfree(conn->local_ipaddr);
/* regular RX path uses back_lock */
spin_lock_bh(&session->back_lock);
- kfifo_in(&session->cmdpool.queue, (void*)&conn->login_task,
+ percpu_ida_free(&session->itts, conn->login_task->itt);
+ kfifo_in(&session->mgmt_pool.queue, (void*)&conn->login_task,
sizeof(void*));
spin_unlock_bh(&session->back_lock);
if (session->leadconn == conn)
@@ -3051,8 +3097,8 @@ fail_mgmt_tasks(struct iscsi_session *session, struct iscsi_conn *conn)
int i, state;
for (i = 0; i < conn->session->cmds_max; i++) {
- task = conn->session->cmds[i];
- if (task->sc)
+ task = conn->session->task_map[i];
+ if (!task || task->sc)
continue;
if (task->state == ISCSI_TASK_FREE)
diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c
index e4bec58..3c95032 100644
--- a/drivers/scsi/libiscsi_tcp.c
+++ b/drivers/scsi/libiscsi_tcp.c
@@ -451,27 +451,13 @@ iscsi_tcp_data_recv_prep(struct iscsi_tcp_conn *tcp_conn)
void iscsi_tcp_cleanup_task(struct iscsi_task *task)
{
struct iscsi_tcp_task *tcp_task = task->dd_data;
- struct iscsi_r2t_info *r2t;
/* nothing to do for mgmt */
if (!task->sc)
return;
- spin_lock_bh(&tcp_task->queue2pool);
- /* flush task's r2t queues */
- while (kfifo_out(&tcp_task->r2tqueue, (void*)&r2t, sizeof(void*))) {
- kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
- sizeof(void*));
- ISCSI_DBG_TCP(task->conn, "pending r2t dropped\n");
- }
-
- r2t = tcp_task->r2t;
- if (r2t != NULL) {
- kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
- sizeof(void*));
- tcp_task->r2t = NULL;
- }
- spin_unlock_bh(&tcp_task->queue2pool);
+ tcp_task->r2t.data_length = 0;
+ tcp_task->r2t.sent = 0;
}
EXPORT_SYMBOL_GPL(iscsi_tcp_cleanup_task);
@@ -529,11 +515,10 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
struct iscsi_tcp_task *tcp_task = task->dd_data;
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
struct iscsi_r2t_rsp *rhdr = (struct iscsi_r2t_rsp *)tcp_conn->in.hdr;
- struct iscsi_r2t_info *r2t;
+ struct iscsi_r2t_info *r2t = &tcp_task->r2t;
int r2tsn = be32_to_cpu(rhdr->r2tsn);
u32 data_length;
u32 data_offset;
- int rc;
if (tcp_conn->in.datalen) {
iscsi_conn_printk(KERN_ERR, conn,
@@ -579,28 +564,21 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
return ISCSI_ERR_DATALEN;
}
- spin_lock(&tcp_task->pool2queue);
- rc = kfifo_out(&tcp_task->r2tpool.queue, (void*)&r2t, sizeof(void*));
- if (!rc) {
- iscsi_conn_printk(KERN_ERR, conn, "Could not allocate R2T. "
- "Target has sent more R2Ts than it "
- "negotiated for or driver has leaked.\n");
- spin_unlock(&tcp_task->pool2queue);
- return ISCSI_ERR_PROTO;
- }
-
r2t->exp_statsn = rhdr->statsn;
r2t->data_length = data_length;
r2t->data_offset = data_offset;
-
r2t->ttt = rhdr->ttt; /* no flip */
r2t->datasn = 0;
+ /*
+ * TODO: I think this is needed to make sure if the xmit thread
+ * is handling multiple tasks at a time then we want to make sure
+ * it sees these fields updated
+ */
+ smp_wmb();
r2t->sent = 0;
tcp_task->exp_datasn = r2tsn + 1;
- kfifo_in(&tcp_task->r2tqueue, (void*)&r2t, sizeof(void*));
conn->r2t_pdus_cnt++;
- spin_unlock(&tcp_task->pool2queue);
iscsi_requeue_task(task);
return 0;
@@ -971,7 +949,6 @@ int iscsi_tcp_task_init(struct iscsi_task *task)
return conn->session->tt->init_pdu(task, 0, task->data_count);
}
- BUG_ON(kfifo_len(&tcp_task->r2tqueue));
tcp_task->exp_datasn = 0;
/* Prepare PDU, optionally w/ immediate data */
@@ -989,37 +966,17 @@ EXPORT_SYMBOL_GPL(iscsi_tcp_task_init);
static struct iscsi_r2t_info *iscsi_tcp_get_curr_r2t(struct iscsi_task *task)
{
struct iscsi_tcp_task *tcp_task = task->dd_data;
- struct iscsi_r2t_info *r2t = NULL;
-
- if (iscsi_task_has_unsol_data(task))
- r2t = &task->unsol_r2t;
- else {
- spin_lock_bh(&tcp_task->queue2pool);
- if (tcp_task->r2t) {
- r2t = tcp_task->r2t;
- /* Continue with this R2T? */
- if (r2t->data_length <= r2t->sent) {
- ISCSI_DBG_TCP(task->conn,
- " done with r2t %p\n", r2t);
- kfifo_in(&tcp_task->r2tpool.queue,
- (void *)&tcp_task->r2t,
- sizeof(void *));
- tcp_task->r2t = r2t = NULL;
- }
- }
-
- if (r2t == NULL) {
- if (kfifo_out(&tcp_task->r2tqueue,
- (void *)&tcp_task->r2t, sizeof(void *)) !=
- sizeof(void *))
- r2t = NULL;
- else
- r2t = tcp_task->r2t;
- }
- spin_unlock_bh(&tcp_task->queue2pool);
- }
- return r2t;
+ if (task->unsol_r2t.sent == 0 && iscsi_task_has_unsol_data(task)) {
+ /* Make sure we see the queue sides update of these */
+ smp_rmb();
+ return &task->unsol_r2t;
+ } else if (tcp_task->r2t.data_length > tcp_task->r2t.sent) {
+ /* Make sure we see the recv sides update of these */
+ smp_rmb();
+ return &tcp_task->r2t;
+ } else
+ return NULL;
}
/**
@@ -1115,84 +1072,17 @@ void iscsi_tcp_conn_teardown(struct iscsi_cls_conn *cls_conn)
}
EXPORT_SYMBOL_GPL(iscsi_tcp_conn_teardown);
-int iscsi_tcp_r2tpool_alloc(struct iscsi_session *session)
-{
- int i;
- int cmd_i;
-
- /*
- * initialize per-task: R2T pool and xmit queue
- */
- for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) {
- struct iscsi_task *task = session->cmds[cmd_i];
- struct iscsi_tcp_task *tcp_task = task->dd_data;
-
- /*
- * pre-allocated x2 as much r2ts to handle race when
- * target acks DataOut faster than we data_xmit() queues
- * could replenish r2tqueue.
- */
-
- /* R2T pool */
- if (iscsi_pool_init(&tcp_task->r2tpool,
- session->max_r2t * 2, NULL,
- sizeof(struct iscsi_r2t_info))) {
- goto r2t_alloc_fail;
- }
-
- /* R2T xmit queue */
- if (kfifo_alloc(&tcp_task->r2tqueue,
- session->max_r2t * 4 * sizeof(void*), GFP_KERNEL)) {
- iscsi_pool_free(&tcp_task->r2tpool);
- goto r2t_alloc_fail;
- }
- spin_lock_init(&tcp_task->pool2queue);
- spin_lock_init(&tcp_task->queue2pool);
- }
-
- return 0;
-
-r2t_alloc_fail:
- for (i = 0; i < cmd_i; i++) {
- struct iscsi_task *task = session->cmds[i];
- struct iscsi_tcp_task *tcp_task = task->dd_data;
-
- kfifo_free(&tcp_task->r2tqueue);
- iscsi_pool_free(&tcp_task->r2tpool);
- }
- return -ENOMEM;
-}
-EXPORT_SYMBOL_GPL(iscsi_tcp_r2tpool_alloc);
-
-void iscsi_tcp_r2tpool_free(struct iscsi_session *session)
-{
- int i;
-
- for (i = 0; i < session->cmds_max; i++) {
- struct iscsi_task *task = session->cmds[i];
- struct iscsi_tcp_task *tcp_task = task->dd_data;
-
- kfifo_free(&tcp_task->r2tqueue);
- iscsi_pool_free(&tcp_task->r2tpool);
- }
-}
-EXPORT_SYMBOL_GPL(iscsi_tcp_r2tpool_free);
-
int iscsi_tcp_set_max_r2t(struct iscsi_conn *conn, char *buf)
{
struct iscsi_session *session = conn->session;
unsigned short r2ts = 0;
sscanf(buf, "%hu", &r2ts);
- if (session->max_r2t == r2ts)
- return 0;
-
- if (!r2ts || !is_power_of_2(r2ts))
+ if (r2ts != 1)
return -EINVAL;
session->max_r2t = r2ts;
- iscsi_tcp_r2tpool_free(session);
- return iscsi_tcp_r2tpool_alloc(session);
+ return 0;
}
EXPORT_SYMBOL_GPL(iscsi_tcp_set_max_r2t);
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index 7221a24..1ef3aa0 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -29,6 +29,7 @@
#include <linux/timer.h>
#include <linux/workqueue.h>
#include <linux/kfifo.h>
+#include <linux/percpu_ida.h>
#include <scsi/iscsi_proto.h>
#include <scsi/iscsi_if.h>
#include <scsi/scsi_transport_iscsi.h>
@@ -335,18 +336,18 @@ struct iscsi_session {
spinlock_t frwd_lock; /* protects session state, *
* cmdsn, queued_cmdsn *
* session resources: *
- * - cmdpool kfifo_out , *
- * - mgmtpool, */
+ * - mgmt_pool kfifo, */
spinlock_t back_lock; /* protects cmdsn_exp *
- * cmdsn_max, *
- * cmdpool kfifo_in */
+ * cmdsn_max, */
int state; /* session state */
int age; /* counts session re-opens */
- int scsi_cmds_max; /* max scsi commands */
+ int scsi_cmds_max; /* max scsi commands */
+ struct percpu_ida itts; /* itt ida */
+ struct iscsi_task **task_map; /* itt to task map */
int cmds_max; /* size of cmds array */
- struct iscsi_task **cmds; /* Original Cmds arr */
- struct iscsi_pool cmdpool; /* PDU's pool */
+ struct iscsi_task **mgmt_cmds; /* Mgmt cmds ar */
+ struct iscsi_pool mgmt_pool; /* Mgmt PDU pool */
void *dd_data; /* LLD private data */
};
diff --git a/include/scsi/libiscsi_tcp.h b/include/scsi/libiscsi_tcp.h
index 2a7aa75..c494660 100644
--- a/include/scsi/libiscsi_tcp.h
+++ b/include/scsi/libiscsi_tcp.h
@@ -79,12 +79,8 @@ struct iscsi_tcp_conn {
struct iscsi_tcp_task {
uint32_t exp_datasn; /* expected target's R2TSN/DataSN */
int data_offset;
- struct iscsi_r2t_info *r2t; /* in progress solict R2T */
- struct iscsi_pool r2tpool;
- struct kfifo r2tqueue;
+ struct iscsi_r2t_info r2t;
void *dd_data;
- spinlock_t pool2queue;
- spinlock_t queue2pool;
};
enum {
@@ -128,8 +124,6 @@ iscsi_tcp_conn_setup(struct iscsi_cls_session *cls_session, int dd_data_size,
extern void iscsi_tcp_conn_teardown(struct iscsi_cls_conn *cls_conn);
/* misc helpers */
-extern int iscsi_tcp_r2tpool_alloc(struct iscsi_session *session);
-extern void iscsi_tcp_r2tpool_free(struct iscsi_session *session);
extern int iscsi_tcp_set_max_r2t(struct iscsi_conn *conn, char *buf);
extern void iscsi_tcp_conn_get_stats(struct iscsi_cls_conn *cls_conn,
struct iscsi_stats *stats);
next prev parent reply other threads:[~2014-02-07 8:59 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-02-05 12:41 [PATCH 00/15] A different approach for using blk-mq in the SCSI layer Christoph Hellwig
2014-02-05 12:41 ` [PATCH 01/15] block: rework flush sequencing for blk-mq Christoph Hellwig
2014-02-06 2:08 ` Muthu Kumar
2014-02-06 16:18 ` Christoph Hellwig
2014-02-05 12:41 ` [PATCH 02/15] blk-mq: support at_head inserations for blk_execute_rq Christoph Hellwig
2014-02-06 2:27 ` Muthu Kumar
2014-02-06 16:17 ` Christoph Hellwig
2014-02-06 17:05 ` Muthu Kumar
2014-02-06 17:10 ` Christoph Hellwig
2014-02-05 12:41 ` [PATCH 03/15] blk-mq: divert __blk_put_request for MQ ops Christoph Hellwig
2014-02-05 12:41 ` [PATCH 04/15] blk-mq: handle dma_drain_size Christoph Hellwig
2014-02-05 12:41 ` [PATCH 05/15] blk-mq: initialize sg_reserved_size Christoph Hellwig
2014-02-05 12:41 ` [PATCH 06/15] scsi: reintroduce scsi_driver.init_command Christoph Hellwig
2014-02-05 12:41 ` [PATCH 07/15] block: remove unprep_rq_fn Christoph Hellwig
2014-02-05 12:41 ` [PATCH 08/15] scsi: cleanup scsi_end_request calling conventions Christoph Hellwig
2014-02-05 12:41 ` [PATCH 09/15] scsi: centralize command re-queueing in scsi_dispatch_fn Christoph Hellwig
2014-02-05 12:41 ` [PATCH 10/15] scsi: split __scsi_queue_insert Christoph Hellwig
2014-02-05 12:41 ` [PATCH 11/15] scsi: factor out __scsi_init_queue Christoph Hellwig
2014-02-05 12:41 ` [PATCH 12/15] scsi: initial blk-mq support Christoph Hellwig
2014-02-06 8:38 ` Sagi Grimberg
2014-02-06 16:16 ` Christoph Hellwig
2014-02-06 22:11 ` Nicholas A. Bellinger
2014-02-07 8:45 ` Mike Christie [this message]
2014-02-07 12:42 ` Christoph Hellwig
2014-02-07 12:51 ` Christoph Hellwig
2014-02-05 12:41 ` [PATCH 13/15] scsi: partially stub out scsi_adjust_queue_depth when using blk-mq Christoph Hellwig
2014-02-05 12:41 ` [PATCH 14/15] iscsi_tcp: use blk_mq Christoph Hellwig
2014-02-05 12:41 ` [PATCH 15/15] virtio_scsi: " Christoph Hellwig
2014-02-10 11:35 ` [PATCH 00/15] A different approach for using blk-mq in the SCSI layer Christoph Hellwig
2014-02-10 19:38 ` Nicholas A. Bellinger
2014-02-24 14:46 ` Christoph Hellwig
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=52F49D1E.2000007@cs.wisc.edu \
--to=michaelc@cs.wisc.edu \
--cc=JBottomley@Parallels.com \
--cc=axboe@kernel.dk \
--cc=hch@infradead.org \
--cc=linux-scsi@vger.kernel.org \
--cc=nab@linux-iscsi.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox