diff --git a/scst/include/scst.h b/scst/include/scst.h index 3fdbcc546..570f05a26 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -160,77 +160,81 @@ static inline unsigned int queue_max_hw_sectors(struct request_queue *q) ** more efficient generated code of the corresponding ** "switch" statements. *************************************************************/ +enum { + /* Dev handler's parse() is going to be called */ + SCST_CMD_STATE_PARSE = 0, -/* Dev handler's parse() is going to be called */ -#define SCST_CMD_STATE_PARSE 0 + /* Allocation of the cmd's data buffer */ + SCST_CMD_STATE_PREPARE_SPACE, -/* Allocation of the cmd's data buffer */ -#define SCST_CMD_STATE_PREPARE_SPACE 1 + /* Calling preprocessing_done() */ + SCST_CMD_STATE_PREPROCESSING_DONE, -/* Calling preprocessing_done() */ -#define SCST_CMD_STATE_PREPROCESSING_DONE 2 + /* Target driver's rdy_to_xfer() is going to be called */ + SCST_CMD_STATE_RDY_TO_XFER, -/* Target driver's rdy_to_xfer() is going to be called */ -#define SCST_CMD_STATE_RDY_TO_XFER 3 + /* Target driver's pre_exec() is going to be called */ + SCST_CMD_STATE_TGT_PRE_EXEC, -/* Target driver's pre_exec() is going to be called */ -#define SCST_CMD_STATE_TGT_PRE_EXEC 4 + /* + * Cmd is going to be sent for execution. The first stage of it is + * order checking + */ + SCST_CMD_STATE_EXEC_CHECK_SN, -/* Cmd is going to be sent for execution */ -#define SCST_CMD_STATE_SEND_FOR_EXEC 5 + /* Internal post-exec checks */ + SCST_CMD_STATE_PRE_DEV_DONE, -/* Internal post-exec checks */ -#define SCST_CMD_STATE_PRE_DEV_DONE 6 + /* Internal MODE SELECT pages related checks */ + SCST_CMD_STATE_MODE_SELECT_CHECKS, -/* Internal MODE SELECT pages related checks */ -#define SCST_CMD_STATE_MODE_SELECT_CHECKS 7 + /* Dev handler's dev_done() is going to be called */ + SCST_CMD_STATE_DEV_DONE, -/* Dev handler's dev_done() is going to be called */ -#define SCST_CMD_STATE_DEV_DONE 8 + /* Checks before target driver's xmit_response() is called */ + SCST_CMD_STATE_PRE_XMIT_RESP, -/* Checks before target driver's xmit_response() is called */ -#define SCST_CMD_STATE_PRE_XMIT_RESP 9 + /* Target driver's xmit_response() is going to be called */ + SCST_CMD_STATE_XMIT_RESP, -/* Target driver's xmit_response() is going to be called */ -#define SCST_CMD_STATE_XMIT_RESP 10 + /* Cmd finished */ + SCST_CMD_STATE_FINISHED, -/* Cmd finished */ -#define SCST_CMD_STATE_FINISHED 11 + /* Internal cmd finished */ + SCST_CMD_STATE_FINISHED_INTERNAL, -/* Internal cmd finished */ -#define SCST_CMD_STATE_FINISHED_INTERNAL 12 + SCST_CMD_STATE_LAST_ACTIVE = (SCST_CMD_STATE_FINISHED_INTERNAL+100), -#define SCST_CMD_STATE_LAST_ACTIVE (SCST_CMD_STATE_FINISHED_INTERNAL+100) + /* A cmd is created, but scst_cmd_init_done() not called */ + SCST_CMD_STATE_INIT_WAIT, -/* A cmd is created, but scst_cmd_init_done() not called */ -#define SCST_CMD_STATE_INIT_WAIT (SCST_CMD_STATE_LAST_ACTIVE+1) + /* LUN translation (cmd->tgt_dev assignment) */ + SCST_CMD_STATE_INIT, -/* LUN translation (cmd->tgt_dev assignment) */ -#define SCST_CMD_STATE_INIT (SCST_CMD_STATE_LAST_ACTIVE+2) + /* Waiting for scst_restart_cmd() */ + SCST_CMD_STATE_PREPROCESSING_DONE_CALLED, -/* Waiting for scst_restart_cmd() */ -#define SCST_CMD_STATE_PREPROCESSING_DONE_CALLED (SCST_CMD_STATE_LAST_ACTIVE+3) + /* Waiting for data from the initiator (until scst_rx_data() called) */ + SCST_CMD_STATE_DATA_WAIT, -/* Waiting for data from the initiator (until scst_rx_data() called) */ -#define SCST_CMD_STATE_DATA_WAIT (SCST_CMD_STATE_LAST_ACTIVE+4) + /* + * Cmd is ready for exec (after check if its device is blocked or should + * be blocked) + */ + SCST_CMD_STATE_EXEC_CHECK_BLOCKING, -/* - * Cmd is ready for exec (after check if its device is blocked or should - * be blocked) - */ -#define SCST_CMD_STATE_START_EXEC (SCST_CMD_STATE_LAST_ACTIVE+5) + /* Cmd is being checked if it should be executed locally */ + SCST_CMD_STATE_LOCAL_EXEC, -/* Cmd is being checked if it should be executed locally */ -#define SCST_CMD_STATE_LOCAL_EXEC (SCST_CMD_STATE_LAST_ACTIVE+6) + /* Cmd is ready for execution */ + SCST_CMD_STATE_REAL_EXEC, -/* Cmd is ready for execution */ -#define SCST_CMD_STATE_REAL_EXEC (SCST_CMD_STATE_LAST_ACTIVE+7) + /* Waiting for CDB's execution finish */ + SCST_CMD_STATE_EXEC_WAIT, -/* Waiting for CDB's execution finish */ -#define SCST_CMD_STATE_REAL_EXECUTING (SCST_CMD_STATE_LAST_ACTIVE+8) - -/* Waiting for response's transmission finish */ -#define SCST_CMD_STATE_XMIT_WAIT (SCST_CMD_STATE_LAST_ACTIVE+9) + /* Waiting for response's transmission finish */ + SCST_CMD_STATE_XMIT_WAIT, +}; /************************************************************* * Can be returned instead of cmd's state by dev handlers' @@ -256,27 +260,28 @@ static inline unsigned int queue_max_hw_sectors(struct request_queue *q) /************************************************************* ** States of mgmt command processing state machine *************************************************************/ +enum { + /* LUN translation (mcmd->tgt_dev assignment) */ + SCST_MCMD_STATE_INIT = 0, -/* LUN translation (mcmd->tgt_dev assignment) */ -#define SCST_MCMD_STATE_INIT 0 + /* Mgmt cmd is being processed */ + SCST_MCMD_STATE_EXEC, -/* Mgmt cmd is being processed */ -#define SCST_MCMD_STATE_EXEC 1 + /* Waiting for affected commands done */ + SCST_MCMD_STATE_WAITING_AFFECTED_CMDS_DONE, -/* Waiting for affected commands done */ -#define SCST_MCMD_STATE_WAITING_AFFECTED_CMDS_DONE 2 + /* Post actions when affected commands done */ + SCST_MCMD_STATE_AFFECTED_CMDS_DONE, -/* Post actions when affected commands done */ -#define SCST_MCMD_STATE_AFFECTED_CMDS_DONE 3 + /* Waiting for affected local commands finished */ + SCST_MCMD_STATE_WAITING_AFFECTED_CMDS_FINISHED, -/* Waiting for affected local commands finished */ -#define SCST_MCMD_STATE_WAITING_AFFECTED_CMDS_FINISHED 4 + /* Target driver's task_mgmt_fn_done() is going to be called */ + SCST_MCMD_STATE_DONE, -/* Target driver's task_mgmt_fn_done() is going to be called */ -#define SCST_MCMD_STATE_DONE 5 - -/* The mcmd finished */ -#define SCST_MCMD_STATE_FINISHED 6 + /* The mcmd finished */ + SCST_MCMD_STATE_FINISHED, +}; /************************************************************* ** Constants for "atomic" parameter of SCST's functions @@ -1206,9 +1211,9 @@ struct scst_dev_type { * exec_sync flag and consider to setup dedicated threads by * setting threads_num > 0. * - * !! If this function is implemented, scst_check_local_events() !! - * !! shall be called inside it just before the actual command's !! - * !! execution. !! + * Dev handlers implementing internal queuing in their exec() callback + * should call scst_check_local_events() just before the actual + * command's execution (i.e. after it's taken from the internal queue). * * OPTIONAL, if not set, the commands will be sent directly to SCSI * device. @@ -1895,12 +1900,6 @@ struct scst_cmd { */ unsigned int finished:1; - /* - * Set if scst_check_local_events() can be called more than once. Set by - * scst_pre_check_local_events(). - */ - unsigned int check_local_events_once_done:1; - #ifdef CONFIG_SCST_DEBUG_TM /* Set if the cmd was delayed by task management debugging code */ unsigned int tm_dbg_delayed:1; @@ -1920,6 +1919,7 @@ struct scst_cmd { struct scst_tgt_template *tgtt; /* to save extra dereferences */ struct scst_tgt *tgt; /* to save extra dereferences */ struct scst_device *dev; /* to save extra dereferences */ + struct scst_dev_type *devt; /* to save extra dereferences */ /* corresponding I_T_L device for this cmd */ struct scst_tgt_dev *tgt_dev; @@ -3880,13 +3880,20 @@ void scst_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); +int __scst_check_local_events(struct scst_cmd *cmd, bool preempt_tests_only); -static inline int scst_pre_check_local_events(struct scst_cmd *cmd) +/** + * scst_check_local_events() - check if there are any local SCSI events + * + * See description of __scst_check_local_events(). + * + * Dev handlers implementing internal queuing in their exec() callback should + * call this function just before the actual command's execution (i.e. + * after it's taken from the internal queue). + */ +static inline int scst_check_local_events(struct scst_cmd *cmd) { - int res = scst_check_local_events(cmd); - cmd->check_local_events_once_done = 1; - return res; + return __scst_check_local_events(cmd, true); } int scst_set_cmd_abnormal_done_state(struct scst_cmd *cmd); diff --git a/scst/src/dev_handlers/scst_disk.c b/scst/src/dev_handlers/scst_disk.c index bfda494ee..2f325220d 100644 --- a/scst/src/dev_handlers/scst_disk.c +++ b/scst/src/dev_handlers/scst_disk.c @@ -566,10 +566,6 @@ split: 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; @@ -679,15 +675,11 @@ out_error: static int disk_perf_exec(struct scst_cmd *cmd) { - int res, rc; + int res; int opcode = cmd->cdb[0]; TRACE_ENTRY(); - 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; @@ -716,8 +708,6 @@ out: out_complete: cmd->completed = 1; - -out_done: res = SCST_EXEC_COMPLETED; cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT, SCST_CONTEXT_SAME); goto out; diff --git a/scst/src/dev_handlers/scst_modisk.c b/scst/src/dev_handlers/scst_modisk.c index bbf5dc3a0..49ba6eb75 100644 --- a/scst/src/dev_handlers/scst_modisk.c +++ b/scst/src/dev_handlers/scst_modisk.c @@ -335,15 +335,11 @@ static int modisk_done(struct scst_cmd *cmd) static int modisk_perf_exec(struct scst_cmd *cmd) { - int res = SCST_EXEC_NOT_COMPLETED, rc; + int res = SCST_EXEC_NOT_COMPLETED; int opcode = cmd->cdb[0]; TRACE_ENTRY(); - 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; diff --git a/scst/src/dev_handlers/scst_tape.c b/scst/src/dev_handlers/scst_tape.c index 63e727267..6d7eaa324 100644 --- a/scst/src/dev_handlers/scst_tape.c +++ b/scst/src/dev_handlers/scst_tape.c @@ -376,15 +376,11 @@ out: static int tape_perf_exec(struct scst_cmd *cmd) { - int res = SCST_EXEC_NOT_COMPLETED, rc; + int res = SCST_EXEC_NOT_COMPLETED; int opcode = cmd->cdb[0]; TRACE_ENTRY(); - 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; diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index 3329a1fd6..1e242e515 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -910,7 +910,7 @@ static void vdisk_detach_tgt(struct scst_tgt_dev *tgt_dev) static int vdisk_do_job(struct scst_cmd *cmd) { - int rc, res; + int res; uint64_t lba_start = 0; loff_t data_len = 0; uint8_t *cdb = cmd->cdb; @@ -936,10 +936,6 @@ static int vdisk_do_job(struct scst_cmd *cmd) break; } - 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; @@ -1167,8 +1163,6 @@ static int vdisk_do_job(struct scst_cmd *cmd) out_compl: cmd->completed = 1; - -out_done: cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT, SCST_CONTEXT_SAME); out_thr: diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 105ee853d..9588ae99d 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -1918,11 +1918,11 @@ static int scst_get_cmd_abnormal_done_state(const struct scst_cmd *cmd) case SCST_CMD_STATE_RDY_TO_XFER: case SCST_CMD_STATE_DATA_WAIT: case SCST_CMD_STATE_TGT_PRE_EXEC: - case SCST_CMD_STATE_START_EXEC: - case SCST_CMD_STATE_SEND_FOR_EXEC: + case SCST_CMD_STATE_EXEC_CHECK_BLOCKING: + case SCST_CMD_STATE_EXEC_CHECK_SN: case SCST_CMD_STATE_LOCAL_EXEC: case SCST_CMD_STATE_REAL_EXEC: - case SCST_CMD_STATE_REAL_EXECUTING: + case SCST_CMD_STATE_EXEC_WAIT: res = SCST_CMD_STATE_PRE_DEV_DONE; break; @@ -1977,11 +1977,11 @@ int scst_set_cmd_abnormal_done_state(struct scst_cmd *cmd) cmd->resid_possible = 1; break; case SCST_CMD_STATE_TGT_PRE_EXEC: - case SCST_CMD_STATE_SEND_FOR_EXEC: - case SCST_CMD_STATE_START_EXEC: + case SCST_CMD_STATE_EXEC_CHECK_SN: + case SCST_CMD_STATE_EXEC_CHECK_BLOCKING: case SCST_CMD_STATE_LOCAL_EXEC: case SCST_CMD_STATE_REAL_EXEC: - case SCST_CMD_STATE_REAL_EXECUTING: + case SCST_CMD_STATE_EXEC_WAIT: case SCST_CMD_STATE_DEV_DONE: case SCST_CMD_STATE_PRE_DEV_DONE: case SCST_CMD_STATE_MODE_SELECT_CHECKS: @@ -4275,15 +4275,15 @@ void scst_free_cmd(struct scst_cmd *cmd) } if (likely(cmd->dev != NULL)) { - struct scst_dev_type *handler = cmd->dev->handler; - if (handler->on_free_cmd != NULL) { + struct scst_dev_type *devt = cmd->devt; + if (devt->on_free_cmd != NULL) { TRACE_DBG("Calling dev handler %s on_free_cmd(%p)", - handler->name, cmd); + devt->name, cmd); scst_set_cur_start(cmd); - handler->on_free_cmd(cmd); + devt->on_free_cmd(cmd); scst_set_dev_on_free_time(cmd); TRACE_DBG("Dev handler %s on_free_cmd() returned", - handler->name); + devt->name); } } @@ -4444,10 +4444,10 @@ static bool scst_on_sg_tablesize_low(struct scst_cmd *cmd, bool out) goto failed; } - if (tgt_dev->dev->handler->on_sg_tablesize_low == NULL) + if (cmd->devt->on_sg_tablesize_low == NULL) goto failed; - res = tgt_dev->dev->handler->on_sg_tablesize_low(cmd); + res = cmd->devt->on_sg_tablesize_low(cmd); TRACE_DBG("on_sg_tablesize_low(%p) returned %d", cmd, res); @@ -5891,151 +5891,6 @@ enum dma_data_direction scst_to_tgt_dma_dir(int scst_dir) } EXPORT_SYMBOL(scst_to_tgt_dma_dir); -/** - * scst_obtain_device_parameters() - obtain device control parameters - * - * Issues a MODE SENSE for control mode page data and sets the corresponding - * dev's parameter from it. Returns 0 on success and not 0 otherwise. - */ -int scst_obtain_device_parameters(struct scst_device *dev) -{ - int rc, i; - uint8_t cmd[16]; - uint8_t buffer[4+0x0A]; - uint8_t sense_buffer[SCSI_SENSE_BUFFERSIZE]; - - TRACE_ENTRY(); - - EXTRACHECKS_BUG_ON(dev->scsi_dev == NULL); - - for (i = 0; i < 5; i++) { - /* Get control mode page */ - memset(cmd, 0, sizeof(cmd)); -#if 0 - cmd[0] = MODE_SENSE_10; - cmd[1] = 0; - cmd[2] = 0x0A; - cmd[8] = sizeof(buffer); /* it's < 256 */ -#else - cmd[0] = MODE_SENSE; - cmd[1] = 8; /* DBD */ - cmd[2] = 0x0A; - cmd[4] = sizeof(buffer); -#endif - - memset(buffer, 0, sizeof(buffer)); - memset(sense_buffer, 0, sizeof(sense_buffer)); - - TRACE(TRACE_SCSI, "%s", "Doing internal MODE_SENSE"); - rc = scsi_execute(dev->scsi_dev, cmd, SCST_DATA_READ, buffer, - sizeof(buffer), sense_buffer, 15, 0, 0 -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29) - , NULL -#endif - ); - - TRACE_DBG("MODE_SENSE done: %x", rc); - - if (scsi_status_is_good(rc)) { - int q; - - PRINT_BUFF_FLAG(TRACE_SCSI, "Returned control mode " - "page data", buffer, sizeof(buffer)); - - dev->tst = buffer[4+2] >> 5; - q = buffer[4+3] >> 4; - if (q > SCST_CONTR_MODE_QUEUE_ALG_UNRESTRICTED_REORDER) { - PRINT_ERROR("Too big QUEUE ALG %x, dev %s", - dev->queue_alg, dev->virt_name); - } - dev->queue_alg = q; - dev->swp = (buffer[4+4] & 0x8) >> 3; - dev->tas = (buffer[4+5] & 0x40) >> 6; - dev->d_sense = (buffer[4+2] & 0x4) >> 2; - - /* - * Unfortunately, SCSI ML doesn't provide a way to - * specify commands task attribute, so we can rely on - * device's restricted reordering only. Linux I/O - * subsystem doesn't reorder pass-through (PC) requests. - */ - dev->has_own_order_mgmt = !dev->queue_alg; - - PRINT_INFO("Device %s: TST %x, QUEUE ALG %x, SWP %x, " - "TAS %x, D_SENSE %d, has_own_order_mgmt %d", - dev->virt_name, dev->tst, dev->queue_alg, - dev->swp, dev->tas, dev->d_sense, - dev->has_own_order_mgmt); - - goto out; - } else { - scst_check_internal_sense(dev, rc, sense_buffer, - sizeof(sense_buffer)); -#if 0 - if ((status_byte(rc) == CHECK_CONDITION) && - SCST_SENSE_VALID(sense_buffer)) { -#else - /* - * 3ware controller is buggy and returns CONDITION_GOOD - * instead of CHECK_CONDITION - */ - if (SCST_SENSE_VALID(sense_buffer)) { -#endif - PRINT_BUFF_FLAG(TRACE_SCSI, "Returned sense " - "data", sense_buffer, - sizeof(sense_buffer)); - if (scst_analyze_sense(sense_buffer, - sizeof(sense_buffer), - SCST_SENSE_KEY_VALID, - ILLEGAL_REQUEST, 0, 0)) { - PRINT_INFO("Device %s doesn't support " - "MODE SENSE", dev->virt_name); - break; - } else if (scst_analyze_sense(sense_buffer, - sizeof(sense_buffer), - SCST_SENSE_KEY_VALID, - NOT_READY, 0, 0)) { - PRINT_ERROR("Device %s not ready", - dev->virt_name); - break; - } - } else { - PRINT_INFO("Internal MODE SENSE to " - "device %s failed: %x", - dev->virt_name, rc); - PRINT_BUFF_FLAG(TRACE_SCSI, "MODE SENSE sense", - sense_buffer, sizeof(sense_buffer)); - switch (host_byte(rc)) { - case DID_RESET: - case DID_ABORT: - case DID_SOFT_ERROR: - break; - default: - goto brk; - } - switch (driver_byte(rc)) { - case DRIVER_BUSY: - case DRIVER_SOFT: - break; - default: - goto brk; - } - } - } - } -brk: - PRINT_WARNING("Unable to get device's %s control mode page, using " - "existing values/defaults: TST %x, QUEUE ALG %x, SWP %x, " - "TAS %x, D_SENSE %d, has_own_order_mgmt %d", dev->virt_name, - dev->tst, dev->queue_alg, dev->swp, dev->tas, dev->d_sense, - dev->has_own_order_mgmt); - -out: - TRACE_EXIT(); - return 0; -} -EXPORT_SYMBOL_GPL(scst_obtain_device_parameters); - /* Called under dev_lock and BH off */ void scst_process_reset(struct scst_device *dev, struct scst_session *originator, struct scst_cmd *exclude_cmd, @@ -6775,6 +6630,151 @@ void scst_unblock_dev(struct scst_device *dev) return; } +/** + * scst_obtain_device_parameters() - obtain device control parameters + * + * Issues a MODE SENSE for control mode page data and sets the corresponding + * dev's parameter from it. Returns 0 on success and not 0 otherwise. + */ +int scst_obtain_device_parameters(struct scst_device *dev) +{ + int rc, i; + uint8_t cmd[16]; + uint8_t buffer[4+0x0A]; + uint8_t sense_buffer[SCSI_SENSE_BUFFERSIZE]; + + TRACE_ENTRY(); + + EXTRACHECKS_BUG_ON(dev->scsi_dev == NULL); + + for (i = 0; i < 5; i++) { + /* Get control mode page */ + memset(cmd, 0, sizeof(cmd)); +#if 0 + cmd[0] = MODE_SENSE_10; + cmd[1] = 0; + cmd[2] = 0x0A; + cmd[8] = sizeof(buffer); /* it's < 256 */ +#else + cmd[0] = MODE_SENSE; + cmd[1] = 8; /* DBD */ + cmd[2] = 0x0A; + cmd[4] = sizeof(buffer); +#endif + + memset(buffer, 0, sizeof(buffer)); + memset(sense_buffer, 0, sizeof(sense_buffer)); + + TRACE(TRACE_SCSI, "%s", "Doing internal MODE_SENSE"); + rc = scsi_execute(dev->scsi_dev, cmd, SCST_DATA_READ, buffer, + sizeof(buffer), sense_buffer, 15, 0, 0 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29) + , NULL +#endif + ); + + TRACE_DBG("MODE_SENSE done: %x", rc); + + if (scsi_status_is_good(rc)) { + int q; + + PRINT_BUFF_FLAG(TRACE_SCSI, "Returned control mode " + "page data", buffer, sizeof(buffer)); + + dev->tst = buffer[4+2] >> 5; + q = buffer[4+3] >> 4; + if (q > SCST_CONTR_MODE_QUEUE_ALG_UNRESTRICTED_REORDER) { + PRINT_ERROR("Too big QUEUE ALG %x, dev %s", + dev->queue_alg, dev->virt_name); + } + dev->queue_alg = q; + dev->swp = (buffer[4+4] & 0x8) >> 3; + dev->tas = (buffer[4+5] & 0x40) >> 6; + dev->d_sense = (buffer[4+2] & 0x4) >> 2; + + /* + * Unfortunately, SCSI ML doesn't provide a way to + * specify commands task attribute, so we can rely on + * device's restricted reordering only. Linux I/O + * subsystem doesn't reorder pass-through (PC) requests. + */ + dev->has_own_order_mgmt = !dev->queue_alg; + + PRINT_INFO("Device %s: TST %x, QUEUE ALG %x, SWP %x, " + "TAS %x, D_SENSE %d, has_own_order_mgmt %d", + dev->virt_name, dev->tst, dev->queue_alg, + dev->swp, dev->tas, dev->d_sense, + dev->has_own_order_mgmt); + + goto out; + } else { + scst_check_internal_sense(dev, rc, sense_buffer, + sizeof(sense_buffer)); +#if 0 + if ((status_byte(rc) == CHECK_CONDITION) && + SCST_SENSE_VALID(sense_buffer)) { +#else + /* + * 3ware controller is buggy and returns CONDITION_GOOD + * instead of CHECK_CONDITION + */ + if (SCST_SENSE_VALID(sense_buffer)) { +#endif + PRINT_BUFF_FLAG(TRACE_SCSI, "Returned sense " + "data", sense_buffer, + sizeof(sense_buffer)); + if (scst_analyze_sense(sense_buffer, + sizeof(sense_buffer), + SCST_SENSE_KEY_VALID, + ILLEGAL_REQUEST, 0, 0)) { + PRINT_INFO("Device %s doesn't support " + "MODE SENSE", dev->virt_name); + break; + } else if (scst_analyze_sense(sense_buffer, + sizeof(sense_buffer), + SCST_SENSE_KEY_VALID, + NOT_READY, 0, 0)) { + PRINT_ERROR("Device %s not ready", + dev->virt_name); + break; + } + } else { + PRINT_INFO("Internal MODE SENSE to " + "device %s failed: %x", + dev->virt_name, rc); + PRINT_BUFF_FLAG(TRACE_SCSI, "MODE SENSE sense", + sense_buffer, sizeof(sense_buffer)); + switch (host_byte(rc)) { + case DID_RESET: + case DID_ABORT: + case DID_SOFT_ERROR: + break; + default: + goto brk; + } + switch (driver_byte(rc)) { + case DRIVER_BUSY: + case DRIVER_SOFT: + break; + default: + goto brk; + } + } + } + } +brk: + PRINT_WARNING("Unable to get device's %s control mode page, using " + "existing values/defaults: TST %x, QUEUE ALG %x, SWP %x, " + "TAS %x, D_SENSE %d, has_own_order_mgmt %d", dev->virt_name, + dev->tst, dev->queue_alg, dev->swp, dev->tas, dev->d_sense, + dev->has_own_order_mgmt); + +out: + TRACE_EXIT(); + return 0; +} +EXPORT_SYMBOL_GPL(scst_obtain_device_parameters); + void scst_on_hq_cmd_response(struct scst_cmd *cmd) { struct scst_order_data *order_data = cmd->cur_order_data; diff --git a/scst/src/scst_pres.h b/scst/src/scst_pres.h index f7b5cca2b..9b9020c9a 100644 --- a/scst/src/scst_pres.h +++ b/scst/src/scst_pres.h @@ -73,10 +73,9 @@ static inline void scst_dec_pr_readers_count(struct scst_cmd *cmd, struct scst_device *dev = cmd->dev; if (unlikely(!cmd->dec_pr_readers_count_needed)) { - PRINT_ERROR("scst_check_local_events() should not be called " - "twice (cmd %p, op %x)! Use " - "scst_pre_check_local_events() instead.", cmd, - cmd->cdb[0]); + PRINT_ERROR("__scst_check_local_events(x, false) should not " + "be called twice (cmd %p, op %x)! Use " + "scst_check_local_events() instead.", cmd, cmd->cdb[0]); WARN_ON(1); goto out; } @@ -99,14 +98,6 @@ out: return; } -static inline void scst_reset_requeued_cmd(struct scst_cmd *cmd) -{ - TRACE_DBG("Reset requeued cmd %p (op %x)", cmd, cmd->cdb[0]); - scst_inc_pr_readers_count(cmd, false); - cmd->check_local_events_once_done = 0; - return; -} - static inline bool scst_pr_type_valid(uint8_t type) { switch (type) { diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index 619c07b6f..d787fc73e 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -466,6 +466,7 @@ int scst_pre_parse(struct scst_cmd *cmd) { int res; struct scst_device *dev = cmd->dev; + struct scst_dev_type *devt = cmd->devt; int rc; TRACE_ENTRY(); @@ -488,7 +489,7 @@ int scst_pre_parse(struct scst_cmd *cmd) TRACE(TRACE_MINOR, "Unknown opcode 0x%02x for %s. " "Should you update scst_scsi_op_table?", - cmd->cdb[0], dev->handler->name); + cmd->cdb[0], devt->name); PRINT_BUFF_FLAG(TRACE_MINOR, "Failed CDB", cmd->cdb, cmd->cdb_len); } else @@ -497,7 +498,7 @@ int scst_pre_parse(struct scst_cmd *cmd) #ifdef CONFIG_SCST_STRICT_SERIALIZING cmd->inc_expected_sn_on_done = 1; #else - cmd->inc_expected_sn_on_done = dev->handler->exec_sync || + cmd->inc_expected_sn_on_done = devt->exec_sync || (!dev->has_own_order_mgmt && (dev->queue_alg == SCST_CONTR_MODE_QUEUE_ALG_RESTRICTED_REORDER || cmd->queue_type == SCST_CMD_QUEUE_ORDERED)); @@ -555,45 +556,45 @@ static int scst_parse_cmd(struct scst_cmd *cmd) { int res = SCST_CMD_STATE_RES_CONT_SAME; int state; - struct scst_device *dev = cmd->dev; + struct scst_dev_type *devt = cmd->devt; int orig_bufflen = cmd->bufflen; TRACE_ENTRY(); if (likely(!scst_is_cmd_fully_local(cmd))) { - if (unlikely(!dev->handler->parse_atomic && + if (unlikely(!devt->parse_atomic && scst_cmd_atomic(cmd))) { /* * It shouldn't be because of the SCST_TGT_DEV_AFTER_* * optimization. */ TRACE_MGMT_DBG("Dev handler %s parse() needs thread " - "context, rescheduling", dev->handler->name); + "context, rescheduling", devt->name); res = SCST_CMD_STATE_RES_NEED_THREAD; goto out; } TRACE_DBG("Calling dev handler %s parse(%p)", - dev->handler->name, cmd); + devt->name, cmd); TRACE_BUFF_FLAG(TRACE_SND_BOT, "Parsing: ", cmd->cdb, cmd->cdb_len); scst_set_cur_start(cmd); - state = dev->handler->parse(cmd); + state = devt->parse(cmd); /* Caution: cmd can be already dead here */ TRACE_DBG("Dev handler %s parse() returned %d", - dev->handler->name, state); + devt->name, state); switch (state) { case SCST_CMD_STATE_NEED_THREAD_CTX: scst_set_parse_time(cmd); TRACE_DBG("Dev handler %s parse() requested thread " - "context, rescheduling", dev->handler->name); + "context, rescheduling", devt->name); res = SCST_CMD_STATE_RES_NEED_THREAD; goto out; case SCST_CMD_STATE_STOP: TRACE_DBG("Dev handler %s parse() requested stop " - "processing", dev->handler->name); + "processing", devt->name); res = SCST_CMD_STATE_RES_CONT_NEXT; goto out; } @@ -622,7 +623,7 @@ static int scst_parse_cmd(struct scst_cmd *cmd) } else { PRINT_ERROR("Unknown opcode 0x%02x for %s and " "target %s not supplied expected values", - cmd->cdb[0], dev->handler->name, cmd->tgtt->name); + cmd->cdb[0], devt->name, cmd->tgtt->name); scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_invalid_opcode)); goto out_done; @@ -683,7 +684,7 @@ static int scst_parse_cmd(struct scst_cmd *cmd) } else { PRINT_ERROR("Unknown data transfer length for opcode " "0x%x (handler %s, target %s)", cmd->cdb[0], - dev->handler->name, cmd->tgtt->name); + devt->name, cmd->tgtt->name); PRINT_BUFFER("Failed CDB", cmd->cdb, cmd->cdb_len); scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_invalid_message)); @@ -722,7 +723,7 @@ static int scst_parse_cmd(struct scst_cmd *cmd) ((cmd->sg == NULL) && (state > SCST_CMD_STATE_PREPARE_SPACE)))) { PRINT_ERROR("Dev handler %s parse() returned " "invalid cmd data_direction %d, bufflen %d, state %d " - "or sg %p (opcode 0x%x)", dev->handler->name, + "or sg %p (opcode 0x%x)", devt->name, cmd->data_direction, cmd->bufflen, state, cmd->sg, cmd->cdb[0]); PRINT_BUFFER("Failed CDB", cmd->cdb, cmd->cdb_len); @@ -761,7 +762,7 @@ static int scst_parse_cmd(struct scst_cmd *cmd) "opcode 0x%02x (handler %s, target %s) " "doesn't match decoded value %d", cmd->expected_data_direction, - cmd->cdb[0], dev->handler->name, + cmd->cdb[0], devt->name, cmd->tgtt->name, cmd->data_direction); PRINT_BUFFER("Failed CDB", cmd->cdb, cmd->cdb_len); @@ -776,8 +777,7 @@ static int scst_parse_cmd(struct scst_cmd *cmd) "(handler %s, target %s) doesn't match " "decoded value %d", cmd->expected_transfer_len, cmd->cdb[0], - dev->handler->name, cmd->tgtt->name, - cmd->bufflen); + devt->name, cmd->tgtt->name, cmd->bufflen); PRINT_BUFF_FLAG(TRACE_MINOR, "Suspicious CDB", cmd->cdb, cmd->cdb_len); if ((cmd->data_direction & SCST_DATA_READ) || @@ -790,7 +790,7 @@ static int scst_parse_cmd(struct scst_cmd *cmd) "(handler %s, target %s) doesn't match " "decoded value %d", cmd->expected_out_transfer_len, cmd->cdb[0], - dev->handler->name, cmd->tgtt->name, + devt->name, cmd->tgtt->name, cmd->out_bufflen); PRINT_BUFF_FLAG(TRACE_MINOR, "Suspicious CDB", cmd->cdb, cmd->cdb_len); @@ -801,7 +801,7 @@ static int scst_parse_cmd(struct scst_cmd *cmd) if (unlikely(cmd->data_direction == SCST_DATA_UNKNOWN)) { PRINT_ERROR("Unknown data direction. Opcode 0x%x, handler %s, " - "target %s", cmd->cdb[0], dev->handler->name, + "target %s", cmd->cdb[0], devt->name, cmd->tgtt->name); PRINT_BUFFER("Failed CDB", cmd->cdb, cmd->cdb_len); goto out_hw_error; @@ -825,8 +825,8 @@ set_res: case SCST_CMD_STATE_PARSE: case SCST_CMD_STATE_RDY_TO_XFER: case SCST_CMD_STATE_TGT_PRE_EXEC: - case SCST_CMD_STATE_SEND_FOR_EXEC: - case SCST_CMD_STATE_START_EXEC: + case SCST_CMD_STATE_EXEC_CHECK_SN: + case SCST_CMD_STATE_EXEC_CHECK_BLOCKING: case SCST_CMD_STATE_LOCAL_EXEC: case SCST_CMD_STATE_REAL_EXEC: case SCST_CMD_STATE_PRE_DEV_DONE: @@ -845,10 +845,10 @@ set_res: if (state >= 0) { PRINT_ERROR("Dev handler %s parse() returned " "invalid cmd state %d (opcode %d)", - dev->handler->name, state, cmd->cdb[0]); + devt->name, state, cmd->cdb[0]); } else { PRINT_ERROR("Dev handler %s parse() returned " - "error %d (opcode %d)", dev->handler->name, + "error %d (opcode %d)", devt->name, state, cmd->cdb[0]); } goto out_hw_error; @@ -937,7 +937,7 @@ out: 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; + struct scst_dev_type *devt = cmd->devt; TRACE_ENTRY(); @@ -945,10 +945,10 @@ static int scst_prepare_space(struct scst_cmd *cmd) goto done; if (likely(!scst_is_cmd_fully_local(cmd)) && - (dev->handler->alloc_data_buf != NULL)) { + (devt->alloc_data_buf != NULL)) { int state; - if (unlikely(!dev->handler->alloc_data_buf_atomic && + if (unlikely(!devt->alloc_data_buf_atomic && scst_cmd_atomic(cmd))) { /* * It shouldn't be because of the SCST_TGT_DEV_AFTER_* @@ -956,31 +956,35 @@ static int scst_prepare_space(struct scst_cmd *cmd) */ TRACE_MGMT_DBG("Dev handler %s alloc_data_buf() needs " "thread context, rescheduling", - dev->handler->name); + devt->name); res = SCST_CMD_STATE_RES_NEED_THREAD; goto out; } - TRACE_DBG("Calling dev handler %s alloc_data_buf(%p)", - dev->handler->name, cmd); + TRACE_DBG("Calling dev handler %s (%p) alloc_data_buf(%p)", + devt->name, devt, 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); + state = devt->alloc_data_buf(cmd); + /* + * Caution: cmd can be already dead here + */ + + /* cmd can be already dead here, so we can't dereference devt */ + TRACE_DBG("Dev handler %p alloc_data_buf() returned %d", + devt, 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); + "thread context, rescheduling", devt->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); + /* cmd can be already dead here, so we can't deref devt */ + TRACE_DBG("Dev handler %p alloc_data_buf() requested " + "stop processing", devt); res = SCST_CMD_STATE_RES_CONT_NEXT; goto out; } @@ -1507,7 +1511,7 @@ static int scst_tgt_pre_exec(struct scst_cmd *cmd) } } - cmd->state = SCST_CMD_STATE_SEND_FOR_EXEC; + cmd->state = SCST_CMD_STATE_EXEC_CHECK_SN; if ((cmd->tgtt->pre_exec == NULL) || unlikely(cmd->internal)) goto out; @@ -1686,7 +1690,7 @@ static void scst_cmd_done_local(struct scst_cmd *cmd, int next_state, static int scst_report_luns_local(struct scst_cmd *cmd) { - int res = SCST_EXEC_COMPLETED, rc; + int res = SCST_EXEC_COMPLETED; int dev_cnt = 0; int buffer_size; int i; @@ -1696,10 +1700,6 @@ static int scst_report_luns_local(struct scst_cmd *cmd) TRACE_ENTRY(); - 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; @@ -1791,7 +1791,6 @@ out_compl: } } -out_done: /* Report the result */ cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT, SCST_CONTEXT_SAME); @@ -1813,17 +1812,13 @@ out_hw_err: static int scst_request_sense_local(struct scst_cmd *cmd) { - int res = SCST_EXEC_COMPLETED, rc; + int res = SCST_EXEC_COMPLETED; struct scst_tgt_dev *tgt_dev = cmd->tgt_dev; uint8_t *buffer; int buffer_size = 0, sl = 0; TRACE_ENTRY(); - 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; @@ -1891,7 +1886,6 @@ static int scst_request_sense_local(struct scst_cmd *cmd) out_compl: cmd->completed = 1; -out_done: /* Report the result */ cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT, SCST_CONTEXT_SAME); @@ -1916,7 +1910,7 @@ out_unlock_compl: static int scst_reserve_local(struct scst_cmd *cmd) { - int res = SCST_EXEC_NOT_COMPLETED, rc; + int res = SCST_EXEC_NOT_COMPLETED; struct scst_device *dev; struct scst_tgt_dev *tgt_dev_tmp; @@ -1949,10 +1943,6 @@ static int scst_reserve_local(struct scst_cmd *cmd) * it, also there's no point to do any extra protection actions. */ - rc = scst_pre_check_local_events(cmd); - if (unlikely(rc != 0)) - goto out_done; - if (!list_empty(&dev->dev_registrants_list)) { if (scst_pr_crh_case(cmd)) goto out_completed; @@ -1997,7 +1987,7 @@ out_done: static int scst_release_local(struct scst_cmd *cmd) { - int res = SCST_EXEC_NOT_COMPLETED, rc; + int res = SCST_EXEC_NOT_COMPLETED; struct scst_tgt_dev *tgt_dev_tmp; struct scst_device *dev; @@ -2010,10 +2000,6 @@ static int scst_release_local(struct scst_cmd *cmd) * other protection is needed here. */ - rc = scst_pre_check_local_events(cmd); - if (unlikely(rc != 0)) - goto out_done; - if (!list_empty(&dev->dev_registrants_list)) { if (scst_pr_crh_case(cmd)) goto out_completed; @@ -2070,7 +2056,6 @@ out_done: /* No locks, no IRQ or IRQ-disabled context allowed */ static int scst_persistent_reserve_in_local(struct scst_cmd *cmd) { - int rc; struct scst_device *dev; struct scst_tgt_dev *tgt_dev; struct scst_session *session; @@ -2086,10 +2071,6 @@ static int scst_persistent_reserve_in_local(struct scst_cmd *cmd) tgt_dev = cmd->tgt_dev; session = cmd->sess; - rc = scst_check_local_events(cmd); - if (unlikely(rc != 0)) - goto out_done; - if (unlikely(dev->not_pr_supporting_tgt_devs_num != 0)) { PRINT_WARNING("Persistent Reservation command %x refused for " "device %s, because the device has not supporting PR " @@ -2177,7 +2158,6 @@ out_err: static int scst_persistent_reserve_out_local(struct scst_cmd *cmd) { int res = SCST_EXEC_COMPLETED; - int rc; struct scst_device *dev; struct scst_tgt_dev *tgt_dev; struct scst_session *session; @@ -2194,10 +2174,6 @@ static int scst_persistent_reserve_out_local(struct scst_cmd *cmd) tgt_dev = cmd->tgt_dev; session = cmd->sess; - rc = scst_check_local_events(cmd); - if (unlikely(rc != 0)) - goto out_done; - if (unlikely(dev->not_pr_supporting_tgt_devs_num != 0)) { PRINT_WARNING("Persistent Reservation command %x refused for " "device %s, because the device has not supporting PR " @@ -2312,7 +2288,7 @@ static int scst_persistent_reserve_out_local(struct scst_cmd *cmd) scst_pr_sync_device_file(tgt_dev, cmd); #endif - if ((dev->handler->pr_cmds_notifications) && + if ((cmd->devt->pr_cmds_notifications) && (cmd->status == SAM_STAT_GOOD)) /* sync file may change status */ res = SCST_EXEC_NOT_COMPLETED; @@ -2335,7 +2311,7 @@ out_done: } /** - * scst_check_local_events() - check if there are any local SCSI events + * __scst_check_local_events() - check if there are any local SCSI events * * Description: * Checks if the command can be executed or there are local events, @@ -2343,15 +2319,9 @@ out_done: * aborted, > 0 if there is an event and command should be immediately * completed, or 0 otherwise. * - * !! 1.Dev handlers implementing exec() callback must call this function there - * !! just before the actual command's execution! - * !! - * !! 2. If this function can be called more than once on the processing path - * !! scst_pre_check_local_events() should be used for the first call! - * * On call no locks, no IRQ or IRQ-disabled context allowed. */ -int scst_check_local_events(struct scst_cmd *cmd) +int __scst_check_local_events(struct scst_cmd *cmd, bool preempt_tests_only) { int res, rc; struct scst_tgt_dev *tgt_dev = cmd->tgt_dev; @@ -2376,7 +2346,7 @@ int scst_check_local_events(struct scst_cmd *cmd) } } - if (likely(!cmd->check_local_events_once_done)) { + if (!preempt_tests_only) { if (dev->pr_is_set) { if (unlikely(!scst_pr_is_cmd_allowed(cmd))) { scst_set_cmd_error_status(cmd, @@ -2451,7 +2421,7 @@ out_uncomplete: res = -1; goto out; } -EXPORT_SYMBOL_GPL(scst_check_local_events); +EXPORT_SYMBOL_GPL(__scst_check_local_events); /* No locks */ void scst_inc_expected_sn(struct scst_order_data *order_data, atomic_t *slot) @@ -2493,7 +2463,7 @@ inc: order_data->expected_sn++; /* * Write must be before def_cmd_count read to be in sync. with - * scst_post_exec_sn(). See comment in scst_send_for_exec(). + * scst_post_exec_sn(). See comment in scst_exec_check_sn(). */ smp_mb(); TRACE_SN("Next expected_sn: %d", order_data->expected_sn); @@ -2533,7 +2503,7 @@ static int scst_do_real_exec(struct scst_cmd *cmd) int res = SCST_EXEC_NOT_COMPLETED; int rc; struct scst_device *dev = cmd->dev; - struct scst_dev_type *handler = dev->handler; + struct scst_dev_type *devt = cmd->devt; struct io_context *old_ctx = NULL; bool ctx_changed = false; struct scsi_device *scsi_dev; @@ -2542,17 +2512,17 @@ static int scst_do_real_exec(struct scst_cmd *cmd) ctx_changed = scst_set_io_context(cmd, &old_ctx); - cmd->state = SCST_CMD_STATE_REAL_EXECUTING; + cmd->state = SCST_CMD_STATE_EXEC_WAIT; - if (handler->exec) { + if (devt->exec) { TRACE_DBG("Calling dev handler %s exec(%p)", - handler->name, cmd); + devt->name, cmd); TRACE_BUFF_FLAG(TRACE_SND_TOP, "Execing: ", cmd->cdb, cmd->cdb_len); scst_set_cur_start(cmd); - res = handler->exec(cmd); + res = devt->exec(cmd); TRACE_DBG("Dev handler %s exec() returned %d", - handler->name, res); + devt->name, res); if (res == SCST_EXEC_COMPLETED) goto out_complete; @@ -2573,10 +2543,6 @@ static int scst_do_real_exec(struct scst_cmd *cmd) goto out_error; } - res = scst_check_local_events(cmd); - if (unlikely(res != 0)) - goto out_done; - scst_set_cur_start(cmd); #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) @@ -2736,15 +2702,37 @@ static int scst_local_exec(struct scst_cmd *cmd) return res; } -static int scst_exec(struct scst_cmd **active_cmd) +static int scst_pre_exec_checks(struct scst_cmd *cmd) { - struct scst_cmd *cmd = *active_cmd; - struct scst_cmd *ref_cmd; - int res = SCST_CMD_STATE_RES_CONT_NEXT, count = 0; + int res, rc; TRACE_ENTRY(); - cmd->state = SCST_CMD_STATE_START_EXEC; + rc = __scst_check_local_events(cmd, false); + if (unlikely(rc != 0)) + goto out_done; + + res = SCST_CMD_STATE_RES_CONT_SAME; + +out: + TRACE_EXIT_RES(res); + return res; + +out_done: + cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT, SCST_CONTEXT_SAME); + res = SCST_CMD_STATE_RES_CONT_NEXT; + goto out; +} + +static int scst_exec_check_blocking(struct scst_cmd **active_cmd) +{ + struct scst_cmd *cmd = *active_cmd; + struct scst_cmd *ref_cmd; + int count = 0, rc; + + TRACE_ENTRY(); + + cmd->state = SCST_CMD_STATE_EXEC_CHECK_BLOCKING; if (unlikely(scst_check_blocked_dev(cmd))) goto out; @@ -2760,12 +2748,20 @@ static int scst_exec(struct scst_cmd **active_cmd) /* * To sync with scst_abort_cmd(). The above assignment must * be before SCST_CMD_ABORTED test, done later in - * scst_check_local_events(). It's far from here, so the order + * __scst_check_local_events(). It's far from here, so the order * is virtually guaranteed, but let's have it just in case. */ smp_mb(); cmd->scst_cmd_done = scst_cmd_done_local; + + rc = scst_pre_exec_checks(cmd); + if (unlikely(rc != SCST_CMD_STATE_RES_CONT_SAME)) { + EXTRACHECKS_BUG_ON(rc != SCST_CMD_STATE_RES_CONT_NEXT); + EXTRACHECKS_BUG_ON(cmd->state == SCST_CMD_STATE_EXEC_CHECK_BLOCKING); + goto done; + } + cmd->state = SCST_CMD_STATE_LOCAL_EXEC; rc = scst_do_local_exec(cmd); @@ -2788,7 +2784,7 @@ done: if (cmd == NULL) break; - cmd->state = SCST_CMD_STATE_START_EXEC; + cmd->state = SCST_CMD_STATE_EXEC_CHECK_BLOCKING; if (unlikely(scst_check_blocked_dev(cmd))) break; @@ -2796,7 +2792,6 @@ done: __scst_cmd_put(ref_cmd); ref_cmd = cmd; __scst_cmd_get(ref_cmd); - } *active_cmd = cmd; @@ -2814,12 +2809,11 @@ out_put: /* !! At this point sess, dev and tgt_dev can be already freed !! */ out: - EXTRACHECKS_BUG_ON(res == SCST_CMD_STATE_RES_NEED_THREAD); - TRACE_EXIT_RES(res); - return res; + TRACE_EXIT(); + return SCST_CMD_STATE_RES_CONT_NEXT; } -static int scst_send_for_exec(struct scst_cmd **active_cmd) +static int scst_exec_check_sn(struct scst_cmd **active_cmd) { int res; struct scst_cmd *cmd = *active_cmd; @@ -2885,7 +2879,7 @@ static int scst_send_for_exec(struct scst_cmd **active_cmd) } exec: - res = scst_exec(active_cmd); + res = scst_exec_check_blocking(active_cmd); out: TRACE_EXIT_HRES(res); @@ -2951,7 +2945,6 @@ static int scst_check_sense(struct scst_cmd *cmd) cmd->state = SCST_CMD_STATE_REAL_EXEC; cmd->retry = 1; - scst_reset_requeued_cmd(cmd); res = 1; goto out; } @@ -3270,35 +3263,35 @@ static int scst_dev_done(struct scst_cmd *cmd) { int res = SCST_CMD_STATE_RES_CONT_SAME; int state; - struct scst_device *dev = cmd->dev; + struct scst_dev_type *devt = cmd->devt; TRACE_ENTRY(); state = SCST_CMD_STATE_PRE_XMIT_RESP; if (likely(!scst_is_cmd_fully_local(cmd)) && - likely(dev->handler->dev_done != NULL)) { + likely(devt->dev_done != NULL)) { int rc; - if (unlikely(!dev->handler->dev_done_atomic && + if (unlikely(!devt->dev_done_atomic && scst_cmd_atomic(cmd))) { /* * It shouldn't be because of the SCST_TGT_DEV_AFTER_* * optimization. */ TRACE_MGMT_DBG("Dev handler %s dev_done() needs thread " - "context, rescheduling", dev->handler->name); + "context, rescheduling", devt->name); res = SCST_CMD_STATE_RES_NEED_THREAD; goto out; } TRACE_DBG("Calling dev handler %s dev_done(%p)", - dev->handler->name, cmd); + devt->name, cmd); scst_set_cur_start(cmd); - rc = dev->handler->dev_done(cmd); + rc = devt->dev_done(cmd); scst_set_dev_done_time(cmd); TRACE_DBG("Dev handler %s dev_done() returned %d", - dev->handler->name, rc); + devt->name, rc); if (rc != SCST_CMD_STATE_DEFAULT) state = rc; } @@ -3310,8 +3303,8 @@ static int scst_dev_done(struct scst_cmd *cmd) case SCST_CMD_STATE_PREPARE_SPACE: case SCST_CMD_STATE_RDY_TO_XFER: case SCST_CMD_STATE_TGT_PRE_EXEC: - case SCST_CMD_STATE_SEND_FOR_EXEC: - case SCST_CMD_STATE_START_EXEC: + case SCST_CMD_STATE_EXEC_CHECK_SN: + case SCST_CMD_STATE_EXEC_CHECK_BLOCKING: case SCST_CMD_STATE_LOCAL_EXEC: case SCST_CMD_STATE_REAL_EXEC: case SCST_CMD_STATE_PRE_DEV_DONE: @@ -3328,7 +3321,7 @@ static int scst_dev_done(struct scst_cmd *cmd) case SCST_CMD_STATE_NEED_THREAD_CTX: TRACE_DBG("Dev handler %s dev_done() requested " "thread context, rescheduling", - dev->handler->name); + devt->name); res = SCST_CMD_STATE_RES_NEED_THREAD; goto out; #ifdef CONFIG_SCST_EXTRACHECKS @@ -3336,11 +3329,10 @@ static int scst_dev_done(struct scst_cmd *cmd) if (state >= 0) { PRINT_ERROR("Dev handler %s dev_done() returned " "invalid cmd state %d", - dev->handler->name, state); + devt->name, state); } else { PRINT_ERROR("Dev handler %s dev_done() returned " - "error %d", dev->handler->name, - state); + "error %d", devt->name, state); } scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error)); @@ -3363,8 +3355,8 @@ static int scst_dev_done(struct scst_cmd *cmd) if (scst_cmd_atomic(cmd)) { switch (state) { case SCST_CMD_STATE_TGT_PRE_EXEC: - case SCST_CMD_STATE_SEND_FOR_EXEC: - case SCST_CMD_STATE_START_EXEC: + case SCST_CMD_STATE_EXEC_CHECK_SN: + case SCST_CMD_STATE_EXEC_CHECK_BLOCKING: case SCST_CMD_STATE_LOCAL_EXEC: case SCST_CMD_STATE_REAL_EXEC: TRACE_DBG("Atomic context and redirect, " @@ -3840,6 +3832,7 @@ static int scst_translate_lun(struct scst_cmd *cmd) cmd->tgt_dev = tgt_dev; cmd->cur_order_data = tgt_dev->curr_order_data; cmd->dev = tgt_dev->dev; + cmd->devt = tgt_dev->dev->handler; res = 0; break; @@ -4109,7 +4102,7 @@ void scst_process_active_cmd(struct scst_cmd *cmd, bool atomic) res = scst_tgt_pre_exec(cmd); break; - case SCST_CMD_STATE_SEND_FOR_EXEC: + case SCST_CMD_STATE_EXEC_CHECK_SN: if (tm_dbg_check_cmd(cmd) != 0) { res = SCST_CMD_STATE_RES_CONT_NEXT; TRACE_MGMT_DBG("Skipping cmd %p (tag %llu), " @@ -4117,7 +4110,7 @@ void scst_process_active_cmd(struct scst_cmd *cmd, bool atomic) (long long unsigned int)cmd->tag); break; } - res = scst_send_for_exec(&cmd); + res = scst_exec_check_sn(&cmd); EXTRACHECKS_BUG_ON(res == SCST_CMD_STATE_RES_NEED_THREAD); /* * !! At this point cmd, sess & tgt_dev can already be @@ -4125,8 +4118,8 @@ void scst_process_active_cmd(struct scst_cmd *cmd, bool atomic) */ break; - case SCST_CMD_STATE_START_EXEC: - res = scst_exec(&cmd); + case SCST_CMD_STATE_EXEC_CHECK_BLOCKING: + res = scst_exec_check_blocking(&cmd); EXTRACHECKS_BUG_ON(res == SCST_CMD_STATE_RES_NEED_THREAD); /* * !! At this point cmd, sess & tgt_dev can already be @@ -4205,8 +4198,8 @@ void scst_process_active_cmd(struct scst_cmd *cmd, bool atomic) case SCST_CMD_STATE_PREPARE_SPACE: case SCST_CMD_STATE_RDY_TO_XFER: case SCST_CMD_STATE_TGT_PRE_EXEC: - case SCST_CMD_STATE_SEND_FOR_EXEC: - case SCST_CMD_STATE_START_EXEC: + case SCST_CMD_STATE_EXEC_CHECK_SN: + case SCST_CMD_STATE_EXEC_CHECK_BLOCKING: case SCST_CMD_STATE_LOCAL_EXEC: case SCST_CMD_STATE_REAL_EXEC: case SCST_CMD_STATE_DEV_DONE: