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.