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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.