From 5a87f2af9ea59d0cc00e5b5959ac35916e176cdb Mon Sep 17 00:00:00 2001
From: Vladislav Bolkhovitin
Date: Wed, 28 Apr 2010 13:05:18 +0000
Subject: [PATCH] - Unify unknown commands handling between kernel and user
mode dev handlers. Particularly, new hook alloc_data_buf was added to struct
scst_dev_type - Minor web updates
git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@1661 d57e44dd-8a1f-0410-8b47-8ef2f437770f
---
scst/include/scst.h | 26 ++++++++-
scst/src/dev_handlers/scst_user.c | 46 ++++++++++++----
scst/src/scst_lib.c | 1 +
scst/src/scst_main.c | 3 ++
scst/src/scst_targ.c | 89 ++++++++++++++++++++++++++-----
www/users.html | 5 +-
6 files changed, 144 insertions(+), 26 deletions(-)
diff --git a/scst/include/scst.h b/scst/include/scst.h
index cd3329a0c..ed10dcdda 100644
--- a/scst/include/scst.h
+++ b/scst/include/scst.h
@@ -971,6 +971,7 @@ struct scst_dev_type {
* the atomic (non-sleeping) context
*/
unsigned parse_atomic:1;
+ unsigned alloc_data_buf_atomic:1;
unsigned exec_atomic:1;
unsigned dev_done_atomic:1;
@@ -988,6 +989,7 @@ struct scst_dev_type {
/*
* Called to parse CDB from the cmd and initialize
* cmd->bufflen and cmd->data_direction (both - REQUIRED).
+ *
* Returns the command's next state or SCST_CMD_STATE_DEFAULT,
* if the next default state should be used, or
* SCST_CMD_STATE_NEED_THREAD_CTX if the function called in atomic
@@ -1004,6 +1006,26 @@ struct scst_dev_type {
*/
int (*parse) (struct scst_cmd *cmd);
+ /*
+ * This function allows dev handler to handle data buffer
+ * allocations on its own.
+ *
+ * Returns the command's next state or SCST_CMD_STATE_DEFAULT,
+ * if the next default state should be used, or
+ * SCST_CMD_STATE_NEED_THREAD_CTX if the function called in atomic
+ * context, but requires sleeping, or SCST_CMD_STATE_STOP if the
+ * command should not be further processed for now. In the
+ * SCST_CMD_STATE_NEED_THREAD_CTX case the function
+ * will be recalled in the thread context, where sleeping is allowed.
+ *
+ * Pay attention to "atomic" attribute of the cmd, which can be get
+ * by scst_cmd_atomic(): it is true if the function called in the
+ * atomic (non-sleeping) context.
+ *
+ * OPTIONAL
+ */
+ int (*alloc_data_buf) (struct scst_cmd *cmd);
+
/*
* Called to execute CDB. Useful, for instance, to implement
* data caching. The result of CDB execution is reported via
@@ -3153,7 +3175,9 @@ int scst_suspend_activity(bool interruptible);
void scst_resume_activity(void);
void scst_process_active_cmd(struct scst_cmd *cmd, bool atomic);
-void scst_post_parse_process_active_cmd(struct scst_cmd *cmd, bool atomic);
+
+void scst_post_parse(struct scst_cmd *cmd);
+void scst_post_alloc_data_buf(struct scst_cmd *cmd);
int scst_check_local_events(struct scst_cmd *cmd);
diff --git a/scst/src/dev_handlers/scst_user.c b/scst/src/dev_handlers/scst_user.c
index ef4fd6388..3f36b723b 100644
--- a/scst/src/dev_handlers/scst_user.c
+++ b/scst/src/dev_handlers/scst_user.c
@@ -145,6 +145,7 @@ static struct scst_user_cmd *dev_user_alloc_ucmd(struct scst_user_dev *dev,
static void dev_user_free_ucmd(struct scst_user_cmd *ucmd);
static int dev_user_parse(struct scst_cmd *cmd);
+static int dev_user_alloc_data_buf(struct scst_cmd *cmd);
static int dev_user_exec(struct scst_cmd *cmd);
static void dev_user_on_free_cmd(struct scst_cmd *cmd);
static int dev_user_task_mgmt_fn(struct scst_mgmt_cmd *mcmd,
@@ -777,14 +778,18 @@ static int dev_user_parse(struct scst_cmd *cmd)
TRACE_DBG("ucmd %p, cmd %p, state %x", ucmd, cmd, ucmd->state);
- if (ucmd->state != UCMD_STATE_NEW)
- goto alloc;
+ if (ucmd->state == UCMD_STATE_PARSING) {
+ /* We've already done */
+ goto done;
+ }
+
+ EXTRACHECKS_BUG_ON(ucmd->state != UCMD_STATE_NEW);
switch (dev->parse_type) {
case SCST_USER_PARSE_STANDARD:
TRACE_DBG("PARSE STANDARD: ucmd %p", ucmd);
rc = dev->generic_parse(cmd, dev_user_get_block);
- if ((rc != 0) || !(cmd->op_flags & SCST_INFO_VALID))
+ if (rc != 0)
goto out_invalid;
break;
@@ -837,7 +842,7 @@ static int dev_user_parse(struct scst_cmd *cmd)
goto out;
}
-alloc:
+done:
if (cmd->bufflen == 0) {
/*
* According to SPC bufflen 0 for data transfer commands isn't
@@ -846,9 +851,6 @@ alloc:
cmd->data_direction = SCST_DATA_NONE;
}
- if (cmd->data_direction != SCST_DATA_NONE)
- res = dev_user_alloc_space(ucmd);
-
out:
TRACE_EXIT_RES(res);
return res;
@@ -862,6 +864,23 @@ out_error:
goto out;
}
+static int dev_user_alloc_data_buf(struct scst_cmd *cmd)
+{
+ int res = SCST_CMD_STATE_DEFAULT;
+ struct scst_user_cmd *ucmd = (struct scst_user_cmd *)cmd->dh_priv;
+
+ TRACE_ENTRY();
+
+ EXTRACHECKS_BUG_ON((ucmd->state != UCMD_STATE_NEW) &&
+ (ucmd->state != UCMD_STATE_PARSING) &&
+ (ucmd->state != UCMD_STATE_BUF_ALLOCING));
+
+ res = dev_user_alloc_space(ucmd);
+
+ TRACE_EXIT_RES(res);
+ return res;
+}
+
static void dev_user_flush_dcache(struct scst_user_cmd *ucmd)
{
struct scst_user_cmd *buf_ucmd = ucmd->buf_ucmd;
@@ -1234,7 +1253,8 @@ static int dev_user_process_reply_alloc(struct scst_user_cmd *ucmd,
}
out_process:
- scst_post_parse_process_active_cmd(cmd, false);
+ scst_post_alloc_data_buf(cmd);
+ scst_process_active_cmd(cmd, false);
TRACE_EXIT_RES(res);
return res;
@@ -1294,7 +1314,8 @@ static int dev_user_process_reply_parse(struct scst_user_cmd *ucmd,
cmd->op_flags = preply->op_flags;
out_process:
- scst_post_parse_process_active_cmd(cmd, false);
+ scst_post_parse(cmd);
+ scst_process_active_cmd(cmd, false);
TRACE_EXIT_RES(res);
return res;
@@ -2192,6 +2213,11 @@ static void dev_user_unjam_cmd(struct scst_user_cmd *ucmd, int busy,
}
scst_set_cmd_abnormal_done_state(ucmd->cmd);
+ if (state == UCMD_STATE_PARSING)
+ scst_post_parse(ucmd->cmd);
+ else
+ scst_post_alloc_data_buf(ucmd->cmd);
+
TRACE_MGMT_DBG("Adding ucmd %p to active list", ucmd);
list_add(&ucmd->cmd->cmd_list_entry,
&ucmd->cmd->cmd_threads->active_cmd_list);
@@ -2682,6 +2708,7 @@ static void dev_user_setup_functions(struct scst_user_dev *dev)
TRACE_ENTRY();
dev->devtype.parse = dev_user_parse;
+ dev->devtype.alloc_data_buf = dev_user_alloc_data_buf;
dev->devtype.dev_done = NULL;
if (dev->parse_type != SCST_USER_PARSE_CALL) {
@@ -2862,6 +2889,7 @@ static int dev_user_register_dev(struct file *file,
dev->devtype.type = dev_desc->type;
dev->devtype.threads_num = -1;
dev->devtype.parse_atomic = 1;
+ dev->devtype.alloc_data_buf_atomic = 1;
dev->devtype.exec_atomic = 0; /* no point to make it 1 */
dev->devtype.dev_done_atomic = 1;
#ifdef CONFIG_SCST_PROC
diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c
index 8610ac1a0..e534e43fd 100644
--- a/scst/src/scst_lib.c
+++ b/scst/src/scst_lib.c
@@ -2841,6 +2841,7 @@ static struct scst_tgt_dev *scst_alloc_add_tgt_dev(struct scst_session *sess,
atomic_set(&tgt_dev->sn_slots[i], 0);
if (dev->handler->parse_atomic &&
+ dev->handler->alloc_data_buf_atomic &&
(sess->tgt->tgtt->preprocessing_done == NULL)) {
if (sess->tgt->tgtt->rdy_to_xfer_atomic)
__set_bit(SCST_TGT_DEV_AFTER_INIT_WR_ATOMIC,
diff --git a/scst/src/scst_main.c b/scst/src/scst_main.c
index b7882ef8a..f90007203 100644
--- a/scst/src/scst_main.c
+++ b/scst/src/scst_main.c
@@ -963,6 +963,9 @@ static int scst_dev_handler_check(struct scst_dev_type *dev_handler)
#endif
}
+ if (dev_handler->alloc_data_buf == NULL)
+ dev_handler->alloc_data_buf_atomic = 1;
+
if (dev_handler->dev_done == NULL)
dev_handler->dev_done_atomic = 1;
diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c
index 6c3ba1713..87354e546 100644
--- a/scst/src/scst_targ.c
+++ b/scst/src/scst_targ.c
@@ -51,6 +51,31 @@ static struct scst_cmd *__scst_find_cmd_by_tag(struct scst_session *sess,
static void scst_process_redirect_cmd(struct scst_cmd *cmd,
enum scst_exec_context context, int check_retries);
+/**
+ * scst_post_parse() - do post parse actions
+ *
+ * This function must be called by dev handler after its parse() callback
+ * returned SCST_CMD_STATE_STOP before calling scst_process_active_cmd().
+ */
+void scst_post_parse(struct scst_cmd *cmd)
+{
+ scst_set_parse_time(cmd);
+}
+EXPORT_SYMBOL(scst_post_parse);
+
+/**
+ * scst_post_alloc_data_buf() - do post alloc_data_buf actions
+ *
+ * This function must be called by dev handler after its alloc_data_buf()
+ * callback returned SCST_CMD_STATE_STOP before calling
+ * scst_process_active_cmd().
+ */
+void scst_post_alloc_data_buf(struct scst_cmd *cmd)
+{
+ scst_set_alloc_buf_time(cmd);
+}
+EXPORT_SYMBOL(scst_post_alloc_data_buf);
+
static inline void scst_schedule_tasklet(struct scst_cmd *cmd)
{
struct scst_tasklet *t = &scst_tasklets[smp_processor_id()];
@@ -762,12 +787,62 @@ out_done:
static int scst_prepare_space(struct scst_cmd *cmd)
{
int r = 0, res = SCST_CMD_STATE_RES_CONT_SAME;
+ struct scst_device *dev = cmd->dev;
TRACE_ENTRY();
if (cmd->data_direction == SCST_DATA_NONE)
goto done;
+ if (likely(!scst_is_cmd_fully_local(cmd)) &&
+ (dev->handler->alloc_data_buf != NULL)) {
+ int state;
+
+ if (unlikely(!dev->handler->alloc_data_buf_atomic &&
+ scst_cmd_atomic(cmd))) {
+ /*
+ * It shouldn't be because of the SCST_TGT_DEV_AFTER_*
+ * optimization.
+ */
+ TRACE_DBG("Dev handler %s alloc_data_buf() needs "
+ "thread context, rescheduling",
+ dev->handler->name);
+ res = SCST_CMD_STATE_RES_NEED_THREAD;
+ goto out;
+ }
+
+ TRACE_DBG("Calling dev handler %s alloc_data_buf(%p)",
+ dev->handler->name, cmd);
+ scst_set_cur_start(cmd);
+ state = dev->handler->alloc_data_buf(cmd);
+ /* Caution: cmd can be already dead here */
+ TRACE_DBG("Dev handler %s alloc_data_buf() returned %d",
+ dev->handler->name, state);
+
+ switch (state) {
+ case SCST_CMD_STATE_NEED_THREAD_CTX:
+ scst_set_alloc_buf_time(cmd);
+ TRACE_DBG("Dev handler %s alloc_data_buf() requested "
+ "thread context, rescheduling",
+ dev->handler->name);
+ res = SCST_CMD_STATE_RES_NEED_THREAD;
+ goto out;
+
+ case SCST_CMD_STATE_STOP:
+ TRACE_DBG("Dev handler %s alloc_data_buf() requested "
+ "stop processing", dev->handler->name);
+ res = SCST_CMD_STATE_RES_CONT_NEXT;
+ goto out;
+ }
+
+ scst_set_alloc_buf_time(cmd);
+
+ if (unlikely(state != SCST_CMD_STATE_DEFAULT)) {
+ cmd->state = state;
+ goto out;
+ }
+ }
+
if (cmd->tgt_need_alloc_data_buf) {
int orig_bufflen = cmd->bufflen;
@@ -3800,20 +3875,6 @@ void scst_process_active_cmd(struct scst_cmd *cmd, bool atomic)
}
EXPORT_SYMBOL(scst_process_active_cmd);
-/**
- * scst_post_parse_process_active_cmd() - process command after parse
- *
- * SCST commands processing routine, which should be called by dev handler
- * after its parse() callback returned SCST_CMD_STATE_STOP. Arguments are
- * the same as for scst_process_active_cmd().
- */
-void scst_post_parse_process_active_cmd(struct scst_cmd *cmd, bool atomic)
-{
- scst_set_parse_time(cmd);
- scst_process_active_cmd(cmd, atomic);
-}
-EXPORT_SYMBOL(scst_post_parse_process_active_cmd);
-
/* Called under cmd_list_lock and IRQs disabled */
static void scst_do_job_active(struct list_head *cmd_list,
spinlock_t *cmd_list_lock, bool atomic)
diff --git a/www/users.html b/www/users.html
index 10848b3a8..84343b8d9 100644
--- a/www/users.html
+++ b/www/users.html
@@ -135,8 +135,9 @@
made using SCST SRP target by Hewlett Packard and Oracle.
If your company is using SCST in its products, solutions or internal storage infrastructure,
- please contact vst at vlnb net and we will list you on this page. This is the least appreciation
- your company can do for SCST.
+ please contact vst at vlnb net and we will be proud to add you on this page. Also, if your company has certified its
+ SCST-powered product or solution, we will be proud to write on our pages that SCST engine has successfully
+ passed the certification tests. This is the least appreciation your company can do for SCST.