From f6a2a6b4db84b019ba309a0ace65d81b534437cb Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Mon, 13 Sep 2010 21:02:35 +0000 Subject: [PATCH] CDB splitting added git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@2115 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/include/scst.h | 41 +++- scst/src/dev_handlers/scst_disk.c | 384 +++++++++++++++++++++++++----- scst/src/scst_lib.c | 72 ++++-- scst/src/scst_priv.h | 9 +- scst/src/scst_targ.c | 21 +- scst_local/scst_local.c | 3 +- 6 files changed, 438 insertions(+), 92 deletions(-) diff --git a/scst/include/scst.h b/scst/include/scst.h index 25d69f9d6..2ce518640 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -1120,12 +1120,17 @@ struct scst_dev_type { * 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 (*dev_done) (struct scst_cmd *cmd); /* * Called to notify dev hander that the command is about to be freed. + * * Could be called on IRQ context. + * + * OPTIONAL */ void (*on_free_cmd) (struct scst_cmd *cmd); @@ -1140,26 +1145,52 @@ struct scst_dev_type { * command should be done * * Called without any locks held from a thread context. + * + * OPTIONAL */ int (*task_mgmt_fn) (struct scst_mgmt_cmd *mgmt_cmd, struct scst_tgt_dev *tgt_dev); + /* + * Called to notify dev handler that its sg_tablesize is too low to + * satisfy this command's data transfer requirements. Should return + * true if exec() callback will split this command's CDB on smaller + * transfers, false otherwise. + * + * Could be called on SIRQ context. + * + * MUST HAVE, if dev handler supports CDB splitting. + */ + bool (*on_sg_tablesize_low) (struct scst_cmd *cmd); + /* * Called when new device is attaching to the dev handler * Returns 0 on success, error code otherwise. + * + * OPTIONAL */ int (*attach) (struct scst_device *dev); - /* Called when a device is detaching from the dev handler */ + /* + * Called when a device is detaching from the dev handler. + * + * OPTIONAL + */ void (*detach) (struct scst_device *dev); /* * Called when new tgt_dev (session) is attaching to the dev handler. * Returns 0 on success, error code otherwise. + * + * OPTIONAL */ int (*attach_tgt) (struct scst_tgt_dev *tgt_dev); - /* Called when tgt_dev (session) is detaching from the dev handler */ + /* + * Called when tgt_dev (session) is detaching from the dev handler. + * + * OPTIONAL + */ void (*detach_tgt) (struct scst_tgt_dev *tgt_dev); #ifdef CONFIG_SCST_PROC @@ -3808,4 +3839,10 @@ char *scst_get_next_token_str(char **input_str); void scst_init_threads(struct scst_cmd_threads *cmd_threads); void scst_deinit_threads(struct scst_cmd_threads *cmd_threads); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && defined(SCSI_EXEC_REQ_FIFO_DEFINED) +void scst_pass_through_cmd_done(void *data, char *sense, int result, int resid); +int scst_scsi_exec_async(struct scst_cmd *cmd, void *data, + void (*done)(void *data, char *sense, int result, int resid)); +#endif + #endif /* __SCST_H */ diff --git a/scst/src/dev_handlers/scst_disk.c b/scst/src/dev_handlers/scst_disk.c index 77cacec0c..09f45ff3c 100644 --- a/scst/src/dev_handlers/scst_disk.c +++ b/scst/src/dev_handlers/scst_disk.c @@ -25,6 +25,7 @@ #include #include #include +#include #define LOG_PREFIX "dev_disk" @@ -47,8 +48,12 @@ struct disk_params { static int disk_attach(struct scst_device *dev); static void disk_detach(struct scst_device *dev); static int disk_parse(struct scst_cmd *cmd); +static int disk_perf_exec(struct scst_cmd *cmd); static int disk_done(struct scst_cmd *cmd); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && defined(SCSI_EXEC_REQ_FIFO_DEFINED) static int disk_exec(struct scst_cmd *cmd); +static bool disk_on_sg_tablesize_low(struct scst_cmd *cmd); +#endif static struct scst_dev_type disk_devtype = { .name = DISK_NAME, @@ -59,6 +64,10 @@ static struct scst_dev_type disk_devtype = { .attach = disk_attach, .detach = disk_detach, .parse = disk_parse, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && defined(SCSI_EXEC_REQ_FIFO_DEFINED) + .exec = disk_exec, + .on_sg_tablesize_low = disk_on_sg_tablesize_low, +#endif .dev_done = disk_done, #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) .default_trace_flags = SCST_DEFAULT_DEV_LOG_FLAGS, @@ -74,8 +83,11 @@ static struct scst_dev_type disk_devtype_perf = { .attach = disk_attach, .detach = disk_detach, .parse = disk_parse, + .exec = disk_perf_exec, .dev_done = disk_done, - .exec = disk_exec, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && defined(SCSI_EXEC_REQ_FIFO_DEFINED) + .on_sg_tablesize_low = disk_on_sg_tablesize_low, +#endif #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) .default_trace_flags = SCST_DEFAULT_DEV_LOG_FLAGS, .trace_flags = &trace_flag, @@ -145,15 +157,6 @@ static void __exit exit_scst_disk_driver(void) module_init(init_scst_disk_driver); module_exit(exit_scst_disk_driver); -/************************************************************** - * Function: disk_attach - * - * Argument: - * - * Returns : 1 if attached, error code otherwise - * - * Description: - *************************************************************/ static int disk_attach(struct scst_device *dev) { int res, rc; @@ -260,15 +263,6 @@ out: return res; } -/************************************************************ - * Function: disk_detach - * - * Argument: - * - * Returns : None - * - * Description: Called to detach this device type driver - ************************************************************/ static void disk_detach(struct scst_device *dev) { struct disk_params *params = @@ -293,17 +287,6 @@ static int disk_get_block_shift(struct scst_cmd *cmd) return params->block_shift; } -/******************************************************************** - * Function: disk_parse - * - * Argument: - * - * Returns : The state of the command - * - * Description: This does the parsing of the command - * - * Note: Not all states are allowed on return - ********************************************************************/ static int disk_parse(struct scst_cmd *cmd) { int res = SCST_CMD_STATE_DEFAULT; @@ -329,17 +312,6 @@ static void disk_set_block_shift(struct scst_cmd *cmd, int block_shift) return; } -/******************************************************************** - * Function: disk_done - * - * Argument: - * - * Returns : - * - * Description: This is the completion routine for the command, - * it is used to extract any necessary information - * about a command. - ********************************************************************/ static int disk_done(struct scst_cmd *cmd) { int res = SCST_CMD_STATE_DEFAULT; @@ -352,19 +324,315 @@ static int disk_done(struct scst_cmd *cmd) return res; } -/******************************************************************** - * Function: disk_exec - * - * Argument: - * - * Returns : - * - * Description: Make SCST do nothing for data READs and WRITES. - * Intended for raw line performance testing - ********************************************************************/ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && defined(SCSI_EXEC_REQ_FIFO_DEFINED) + +static bool disk_on_sg_tablesize_low(struct scst_cmd *cmd) +{ + bool res; + + TRACE_ENTRY(); + + switch (cmd-> cdb[0]) { + case WRITE_6: + case READ_6: + case WRITE_10: + case READ_10: + case WRITE_VERIFY: + case WRITE_12: + case READ_12: + case WRITE_VERIFY_12: + case WRITE_16: + case READ_16: + case WRITE_VERIFY_16: + res = true; + /* See comment in disk_exec */ + cmd->inc_expected_sn_on_done = 1; + break; + default: + res = false; + break; + } + + TRACE_EXIT_RES(res); + return res; +} + +struct disk_work { + struct scst_cmd *cmd; + struct completion disk_work_cmpl; + volatile int result; + unsigned int left; + uint64_t save_lba; + unsigned int save_len; + struct scatterlist *save_sg; + int save_sg_cnt; +}; + +static int disk_cdb_get_transfer_data(const uint8_t *cdb, + uint64_t *out_lba, unsigned int *out_length) +{ + int res; + uint64_t lba; + unsigned int len; + + TRACE_ENTRY(); + + switch (cdb[0]) { + case WRITE_6: + case READ_6: + lba = be16_to_cpu(get_unaligned((__be16 *)&cdb[2])); + len = cdb[4]; + break; + case WRITE_10: + case READ_10: + case WRITE_VERIFY: + lba = be32_to_cpu(get_unaligned((__be32 *)&cdb[2])); + len = be16_to_cpu(get_unaligned((__be16 *)&cdb[7])); + break; + case WRITE_12: + case READ_12: + case WRITE_VERIFY_12: + lba = be32_to_cpu(get_unaligned((__be32 *)&cdb[2])); + len = be32_to_cpu(get_unaligned((__be32 *)&cdb[6])); + break; + case WRITE_16: + case READ_16: + case WRITE_VERIFY_16: + lba = be64_to_cpu(get_unaligned((__be64 *)&cdb[2])); + len = be32_to_cpu(get_unaligned((__be32 *)&cdb[10])); + break; + default: + res = -EINVAL; + goto out; + } + + res = 0; + *out_lba = lba; + *out_length = len; + + TRACE_DBG("LBA %lld, length %d", (unsigned long long)lba, len); + +out: + TRACE_EXIT_RES(res); + return res; +} + +static int disk_cdb_set_transfer_data(uint8_t *cdb, + uint64_t lba, unsigned int len) +{ + int res; + + TRACE_ENTRY(); + + switch (cdb[0]) { + case WRITE_6: + case READ_6: + put_unaligned(cpu_to_be16(lba), (__be16 *)&cdb[2]); + cdb[4] = len; + break; + case WRITE_10: + case READ_10: + case WRITE_VERIFY: + put_unaligned(cpu_to_be32(lba), (__be32 *)&cdb[2]); + put_unaligned(cpu_to_be16(len), (__be16 *)&cdb[7]); + break; + case WRITE_12: + case READ_12: + case WRITE_VERIFY_12: + put_unaligned(cpu_to_be32(lba), (__be32 *)&cdb[2]); + put_unaligned(cpu_to_be32(len), (__be32 *)&cdb[6]); + break; + case WRITE_16: + case READ_16: + case WRITE_VERIFY_16: + put_unaligned(cpu_to_be64(lba), (__be64 *)&cdb[2]); + put_unaligned(cpu_to_be32(len), (__be32 *)&cdb[10]); + break; + default: + res = -EINVAL; + goto out; + } + + res = 0; + + TRACE_DBG("LBA %lld, length %d", (unsigned long long)lba, len); + TRACE_BUFFER("New CDB", cdb, SCST_MAX_CDB_SIZE); + +out: + TRACE_EXIT_RES(res); + return res; +} + +static void disk_cmd_done(void *data, char *sense, int result, int resid) +{ + struct disk_work *work = data; + + TRACE_ENTRY(); + + TRACE_DBG("work %p, cmd %p, left %d, result %d, sense %p, resid %d", + work, work->cmd, work->left, result, sense, resid); + + if (result == SAM_STAT_GOOD) + goto out_complete; + + work->result = result; + + disk_cdb_set_transfer_data(work->cmd->cdb, work->save_lba, work->save_len); + work->cmd->sg = work->save_sg; + work->cmd->sg_cnt = work->save_sg_cnt; + + scst_pass_through_cmd_done(work->cmd, sense, result, resid + work->left); + +out_complete: + complete_all(&work->disk_work_cmpl); + + TRACE_EXIT(); + return; +} + +/* Executes command and split CDB, if necessary */ static int disk_exec(struct scst_cmd *cmd) { - int res = SCST_EXEC_NOT_COMPLETED, rc; + int res, rc; + struct disk_params *params = (struct disk_params *)cmd->dev->dh_priv; + struct disk_work work; + unsigned int offset, cur_len; + struct scatterlist *sg, *start_sg; + int cur_sg_cnt; + int sg_tablesize = cmd->dev->scsi_dev->host->sg_tablesize; + int num, j; + + TRACE_ENTRY(); + + if (likely((cmd->sg_cnt <= sg_tablesize) && + (cmd->out_sg_cnt <= sg_tablesize))) { + res = SCST_EXEC_NOT_COMPLETED; + goto out; + } + + memset(&work, 0, sizeof(work)); + work.cmd = cmd; + work.save_sg = cmd->sg; + work.save_sg_cnt = cmd->sg_cnt; + rc = disk_cdb_get_transfer_data(cmd->cdb, &work.save_lba, + &work.save_len); + if (rc != 0) + goto out_error; + + rc = scst_check_local_events(cmd); + if (unlikely(rc != 0)) + goto out_done; + + cmd->status = 0; + cmd->msg_status = 0; + cmd->host_status = DID_OK; + cmd->driver_status = 0; + + TRACE_DBG("cmd %p, save_sg %p, save_sg_cnt %d, save_lba %lld, " + "save_len %d (sg_tablesize %d, sizeof(*sg) 0x%x)", cmd, + work.save_sg, work.save_sg_cnt, + (unsigned long long)work.save_lba, work.save_len, + sg_tablesize, sizeof(*sg)); + + /* + * If we submit all chunks async'ly, it will be very not trivial what + * to do if several of them finish with sense or residual. So, let's + * do it synchronously. + */ + + num = 1; + j = 0; + offset = 0; + cur_len = 0; + sg = work.save_sg; + start_sg = sg; + cur_sg_cnt = 0; + while (1) { + unsigned int l; + + if (unlikely(sg_is_chain(&sg[j]))) { + bool reset_start_sg = (start_sg == &sg[j]); + sg = sg_chain_ptr(&sg[j]); + j = 0; + if (reset_start_sg) + start_sg = sg; + } + + l = sg[j].length >> params->block_shift; + cur_len += l; + cur_sg_cnt++; + + TRACE_DBG("l %d, j %d, num %d, offset %d, cur_len %d, " + "cur_sg_cnt %d, start_sg %p", l, j, num, offset, + cur_len, cur_sg_cnt, start_sg); + + if (((num % sg_tablesize) == 0) || (num == work.save_sg_cnt)) { + TRACE_DBG("%s", "Execing..."); + + disk_cdb_set_transfer_data(cmd->cdb, + work.save_lba + offset, cur_len); + cmd->sg = start_sg; + cmd->sg_cnt = cur_sg_cnt; + + work.left = work.save_len - (offset + cur_len); + init_completion(&work.disk_work_cmpl); + + rc = scst_scsi_exec_async(cmd, &work, disk_cmd_done); + if (unlikely(rc != 0)) { + PRINT_ERROR("scst_scsi_exec_async() failed: %d", + rc); + goto out_err_restore; + } + + wait_for_completion(&work.disk_work_cmpl); + + if (work.result != SAM_STAT_GOOD) { + /* cmd can be already dead */ + res = SCST_EXEC_COMPLETED; + goto out; + } + + offset += cur_len; + cur_len = 0; + cur_sg_cnt = 0; + start_sg = &sg[j+1]; + + if (num == work.save_sg_cnt) + break; + } + num++; + j++; + } + + cmd->completed = 1; + +out_restore: + disk_cdb_set_transfer_data(cmd->cdb, work.save_lba, work.save_len); + cmd->sg = work.save_sg; + cmd->sg_cnt = work.save_sg_cnt; + +out_done: + res = SCST_EXEC_COMPLETED; + cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT, SCST_CONTEXT_SAME); + +out: + TRACE_EXIT_RES(res); + return res; + +out_err_restore: + scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error)); + goto out_restore; + +out_error: + scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error)); + goto out_done; +} + +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && defined(SCSI_EXEC_REQ_FIFO_DEFINED) */ + +static int disk_perf_exec(struct scst_cmd *cmd) +{ + int res; int opcode = cmd->cdb[0]; TRACE_ENTRY(); @@ -387,14 +655,21 @@ static int disk_exec(struct scst_cmd *cmd) case READ_10: case READ_12: case READ_16: - cmd->completed = 1; - goto out_done; + case WRITE_VERIFY: + case WRITE_VERIFY_12: + case WRITE_VERIFY_16: + goto out_complete; } + res = SCST_EXEC_NOT_COMPLETED; + out: TRACE_EXIT_RES(res); return res; +out_complete: + cmd->completed = 1; + out_done: res = SCST_EXEC_COMPLETED; cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT, SCST_CONTEXT_SAME); @@ -405,3 +680,4 @@ MODULE_AUTHOR("Vladislav Bolkhovitin & Leonid Stoljar"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SCSI disk (type 0) dev handler for SCST"); MODULE_VERSION(SCST_VERSION_STRING); + diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 34868f20c..adbd3b0c8 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -4444,6 +4444,43 @@ void scst_release_request(struct scst_cmd *cmd) } #endif +static bool scst_on_sg_tablesize_low(struct scst_cmd *cmd, bool out) +{ + bool res; + int sg_cnt = out ? cmd->out_sg_cnt : cmd->sg_cnt; + static int ll; + struct scst_tgt_dev *tgt_dev = cmd->tgt_dev; + + TRACE_ENTRY(); + + if (sg_cnt > cmd->tgt->sg_tablesize) { + /* It's the target's side business */ + goto failed; + } + + if (tgt_dev->dev->handler->on_sg_tablesize_low == NULL) + goto failed; + + res = tgt_dev->dev->handler->on_sg_tablesize_low(cmd); + + TRACE_DBG("on_sg_tablesize_low(%p) returned %d", cmd, res); + +out: + TRACE_EXIT_RES(res); + return res; + +failed: + res = false; + if ((ll < 10) || TRACING_MINOR()) { + PRINT_INFO("Unable to complete command due to SG IO count " + "limitation (%srequested %d, available %d, tgt lim %d)", + out ? "OUT buffer, " : "", cmd->sg_cnt, + tgt_dev->max_sg_cnt, cmd->tgt->sg_tablesize); + ll++; + } + goto out; +} + int scst_alloc_space(struct scst_cmd *cmd) { gfp_t gfp_mask; @@ -4451,7 +4488,6 @@ int scst_alloc_space(struct scst_cmd *cmd) int atomic = scst_cmd_atomic(cmd); int flags; struct scst_tgt_dev *tgt_dev = cmd->tgt_dev; - static int ll; TRACE_ENTRY(); @@ -4466,16 +4502,9 @@ int scst_alloc_space(struct scst_cmd *cmd) if (cmd->sg == NULL) goto out; - if (unlikely(cmd->sg_cnt > tgt_dev->max_sg_cnt)) { - if ((ll < 10) || TRACING_MINOR()) { - PRINT_INFO("Unable to complete command due to " - "SG IO count limitation (requested %d, " - "available %d, tgt lim %d)", cmd->sg_cnt, - tgt_dev->max_sg_cnt, cmd->tgt->sg_tablesize); - ll++; - } - goto out_sg_free; - } + if (unlikely(cmd->sg_cnt > tgt_dev->max_sg_cnt)) + if (!scst_on_sg_tablesize_low(cmd, false)) + goto out_sg_free; if (cmd->data_direction != SCST_DATA_BIDI) goto success; @@ -4486,16 +4515,9 @@ int scst_alloc_space(struct scst_cmd *cmd) if (cmd->out_sg == NULL) goto out_sg_free; - if (unlikely(cmd->out_sg_cnt > tgt_dev->max_sg_cnt)) { - if ((ll < 10) || TRACING_MINOR()) { - PRINT_INFO("Unable to complete command due to " - "SG IO count limitation (OUT buffer, requested " - "%d, available %d, tgt lim %d)", cmd->out_sg_cnt, - tgt_dev->max_sg_cnt, cmd->tgt->sg_tablesize); - ll++; - } - goto out_out_sg_free; - } + if (unlikely(cmd->out_sg_cnt > tgt_dev->max_sg_cnt)) + if (!scst_on_sg_tablesize_low(cmd, true)) + goto out_out_sg_free; success: res = 0; @@ -4718,10 +4740,11 @@ static void scsi_end_async(struct request *req, int error) /** * scst_scsi_exec_async - executes a SCSI command in pass-through mode * @cmd: scst command + * @data: pointer passed to done() as "data" * @done: callback function when done */ -int scst_scsi_exec_async(struct scst_cmd *cmd, - void (*done)(void *, char *, int, int)) +int scst_scsi_exec_async(struct scst_cmd *cmd, void *data, + void (*done)(void *data, char *sense, int result, int resid)) { int res = 0; struct request_queue *q = cmd->dev->scsi_dev->request_queue; @@ -4806,7 +4829,7 @@ int scst_scsi_exec_async(struct scst_cmd *cmd, done: TRACE_DBG("sioc %p, cmd %p", sioc, cmd); - sioc->data = cmd; + sioc->data = data; sioc->done = done; rq->cmd_len = cmd_len; @@ -4844,6 +4867,7 @@ out_free_sioc: kfree(sioc); goto out; } +EXPORT_SYMBOL(scst_scsi_exec_async); #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30) && defined(SCSI_EXEC_REQ_FIFO_DEFINED) */ diff --git a/scst/src/scst_priv.h b/scst/src/scst_priv.h index 585fbf31d..5c22c991b 100644 --- a/scst/src/scst_priv.h +++ b/scst/src/scst_priv.h @@ -406,12 +406,9 @@ static inline int scst_exec_req(struct scsi_device *sdev, #endif } #else /* i.e. LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30) */ -#if defined(SCSI_EXEC_REQ_FIFO_DEFINED) -int scst_scsi_exec_async(struct scst_cmd *cmd, - void (*done)(void *, char *, int, int)); -#else -static inline int scst_scsi_exec_async(struct scst_cmd *cmd, - void (*done)(void *, char *, int, int)) +#if !defined(SCSI_EXEC_REQ_FIFO_DEFINED) +static inline int scst_scsi_exec_async(struct scst_cmd *cmd, void *data, + void (*done)(void *data, char *sense, int result, int resid)) { WARN_ON_ONCE(1); return -1; diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index e68b7b0ca..5c5adc3e6 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -1568,7 +1568,15 @@ out: return; } #else /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) */ -static void scst_cmd_done(void *data, char *sense, int result, int resid) + +/** + * scst_pass_through_cmd_done - done callback for pass-through commands + * @data: private opaque data + * @sense: pointer to the sense data, if any + * @result: command's execution result + * @resid: residual, if any + */ +void scst_pass_through_cmd_done(void *data, char *sense, int result, int resid) { struct scst_cmd *cmd; @@ -1589,6 +1597,8 @@ out: TRACE_EXIT(); return; } +EXPORT_SYMBOL_GPL(scst_pass_through_cmd_done); + #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) */ static void scst_cmd_done_local(struct scst_cmd *cmd, int next_state, @@ -2602,11 +2612,11 @@ static int scst_do_real_exec(struct scst_cmd *cmd) #else #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) rc = scst_exec_req(dev->scsi_dev, cmd->cdb, cmd->cdb_len, - cmd->data_direction, cmd->sg, cmd->bufflen, cmd->sg_cnt, - cmd->timeout, cmd->retries, cmd, scst_cmd_done, - GFP_KERNEL); + cmd->data_direction, cmd->sg, cmd->bufflen, + cmd->sg_cnt, cmd->timeout, cmd->retries, cmd, + scst_pass_through_cmd_done, GFP_KERNEL); #else - rc = scst_scsi_exec_async(cmd, scst_cmd_done); + rc = scst_scsi_exec_async(cmd, cmd, scst_pass_through_cmd_done); #endif if (unlikely(rc != 0)) { PRINT_ERROR("scst pass-through exec failed: %x", rc); @@ -4839,6 +4849,7 @@ static int scst_set_mcmd_next_state(struct scst_mgmt_cmd *mcmd) mcmd, mcmd->state, mcmd->fn, mcmd->cmd_finish_wait_count, mcmd->cmd_done_wait_count); spin_unlock_irq(&scst_mcmd_lock); + res = -1; sBUG(); goto out; } diff --git a/scst_local/scst_local.c b/scst_local/scst_local.c index bf0ec4256..885d2fa21 100644 --- a/scst_local/scst_local.c +++ b/scst_local/scst_local.c @@ -1367,7 +1367,8 @@ static struct scsi_host_template scst_lcl_ini_driver_template = { .sg_tablesize = 0xFFFF, .cmd_per_lun = 32, .max_sectors = 0xffff, - .use_clustering = ENABLE_CLUSTERING, + /* Possible pass-through backend device may not support clustering */ + .use_clustering = DISABLE_CLUSTERING, .skip_settle_delay = 1, .module = THIS_MODULE, };