diff --git a/fcst/ft_cmd.c b/fcst/ft_cmd.c index 4ff371cf9..8274c60b2 100644 --- a/fcst/ft_cmd.c +++ b/fcst/ft_cmd.c @@ -82,12 +82,8 @@ void ft_cmd_dump(struct scst_cmd *cmd, const char *caller) ft_cmd_flag(buf, sizeof(buf), "retry"); if (cmd->internal) ft_cmd_flag(buf, sizeof(buf), "internal"); - if (cmd->inc_blocking) - ft_cmd_flag(buf, sizeof(buf), "inc_blk"); - if (cmd->needs_unblocking) - ft_cmd_flag(buf, sizeof(buf), "needs_unblk"); - if (cmd->dec_on_dev_needed) - ft_cmd_flag(buf, sizeof(buf), "dec_on_dev"); + if (cmd->unblock_dev) + ft_cmd_flag(buf, sizeof(buf), "unblock_dev"); if (cmd->cmd_hw_pending) ft_cmd_flag(buf, sizeof(buf), "hw_pend"); if (cmd->tgt_need_alloc_data_buf) diff --git a/scst/include/scst.h b/scst/include/scst.h index b158338ab..0e6e45278 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -1636,14 +1636,8 @@ struct scst_cmd { /* Set if cmd is internally generated */ unsigned int internal:1; - /* Set if the device was blocked by scst_inc_on_dev_cmd() (for debug) */ - unsigned int inc_blocking:1; - - /* Set if the device should be unblocked after cmd's finish */ - unsigned int needs_unblocking:1; - - /* Set if scst_dec_on_dev_cmd() call is needed on the cmd's finish */ - unsigned int dec_on_dev_needed:1; + /* Set if the device was blocked by scst_check_blocked_dev() */ + unsigned int unblock_dev:1; /* Set if cmd is queued as hw pending */ unsigned int cmd_hw_pending:1; @@ -2068,6 +2062,15 @@ struct scst_device { /**************************************************************/ + /* + * How many times device was blocked for new cmds execution. + * Protected by dev_lock + */ + int block_count; + + /* How many cmds alive on this dev */ + atomic_t dev_cmd_count; + /* * Set if dev is persistently reserved. Protected by dev_pr_mutex. * Modified independently to the above field, hence the alignment. @@ -2105,21 +2108,6 @@ struct scst_device { /* Memory limits for this device */ struct scst_mem_lim dev_mem_lim; - /* How many cmds alive on this dev */ - atomic_t dev_cmd_count; - - /* - * How many there are "on_dev" commands, i.e. ones those are being - * executed by the underlying SCSI/virtual device. - */ - atomic_t on_dev_count; - - /* - * How many times device was blocked for new cmds execution. - * Protected by dev_lock - */ - int block_count; - /* How many write cmds alive on this dev. Temporary, ToDo */ atomic_t write_cmd_count; @@ -2168,9 +2156,6 @@ struct scst_device { struct list_head blocked_cmd_list; /* protected by dev_lock */ - /* Used to wait for requested amount of "on_dev" commands */ - wait_queue_head_t on_dev_waitQ; - /* A list entry used during TM, protected by scst_mutex */ struct list_head tm_dev_list_entry; diff --git a/scst/include/scst_const.h b/scst/include/scst_const.h index 2ca2c43ac..ac8bc7f68 100644 --- a/scst/include/scst_const.h +++ b/scst/include/scst_const.h @@ -141,6 +141,10 @@ enum scst_cmd_queue_type { /************************************************************* ** CDB flags + ** + ** Implicit ordered used for commands which need calm environment + ** without any simultaneous activities. For instance, for MODE + ** SELECT it is needed to correctly generate its UA. *************************************************************/ enum scst_cdb_flags { SCST_TRANSFER_LEN_TYPE_FIXED = 0x0001, @@ -150,13 +154,14 @@ enum scst_cdb_flags { SCST_INFO_VALID = 0x0010, /* must be single bit */ SCST_VERIFY_BYTCHK_MISMATCH_ALLOWED = 0x0020, SCST_IMPLICIT_HQ = 0x0040, - SCST_SKIP_UA = 0x0080, - SCST_WRITE_MEDIUM = 0x0100, - SCST_LOCAL_CMD = 0x0200, - SCST_FULLY_LOCAL_CMD = 0x0400, - SCST_REG_RESERVE_ALLOWED = 0x0800, - SCST_WRITE_EXCL_ALLOWED = 0x1000, - SCST_EXCL_ACCESS_ALLOWED = 0x2000, + SCST_IMPLICIT_ORDERED = 0x0080, + SCST_SKIP_UA = 0x0100, + SCST_WRITE_MEDIUM = 0x0200, + SCST_LOCAL_CMD = 0x0400, + SCST_FULLY_LOCAL_CMD = 0x0800, + SCST_REG_RESERVE_ALLOWED = 0x1000, + SCST_WRITE_EXCL_ALLOWED = 0x2000, + SCST_EXCL_ACCESS_ALLOWED = 0x4000, #ifdef CONFIG_SCST_TEST_IO_IN_SIRQ SCST_TEST_IO_IN_SIRQ_ALLOWED = 0x8000, #endif diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index bc45eb0f7..f1980a10a 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -271,7 +271,7 @@ static const struct scst_sdbops scst_scsi_op_table[] = { SCST_WRITE_EXCL_ALLOWED, 2, get_trans_len_3}, {0x15, "OMOOOOOOOOOOOOOO", "MODE SELECT(6)", - SCST_DATA_WRITE, SCST_LOCAL_CMD, 4, get_trans_len_1}, + SCST_DATA_WRITE, SCST_IMPLICIT_ORDERED, 4, get_trans_len_1}, {0x16, "MMMMMMMMMMMMMMMM", "RESERVE", SCST_DATA_NONE, SCST_SMALL_TIMEOUT|SCST_LOCAL_CMD| SCST_WRITE_EXCL_ALLOWED|SCST_EXCL_ACCESS_ALLOWED, @@ -432,7 +432,7 @@ static const struct scst_sdbops scst_scsi_op_table[] = { {0x4B, " O ", "PAUSE/RESUME", SCST_DATA_NONE, FLAG_NONE, 0, get_trans_len_none}, {0x4C, "OOOOOOOOOOOOOOOO", "LOG SELECT", - SCST_DATA_WRITE, SCST_SMALL_TIMEOUT, 7, get_trans_len_2}, + SCST_DATA_WRITE, SCST_IMPLICIT_ORDERED, 7, get_trans_len_2}, {0x4D, "OOOOOOOOOOOOOOOO", "LOG SENSE", SCST_DATA_READ, SCST_SMALL_TIMEOUT| SCST_REG_RESERVE_ALLOWED| @@ -458,7 +458,7 @@ static const struct scst_sdbops scst_scsi_op_table[] = { {0x54, " O ", "SEND OPC INFORMATION", SCST_DATA_WRITE, FLAG_NONE, 7, get_trans_len_2}, {0x55, "OOOOOOOOOOOOOOOO", "MODE SELECT(10)", - SCST_DATA_WRITE, SCST_LOCAL_CMD, 7, get_trans_len_2}, + SCST_DATA_WRITE, SCST_IMPLICIT_ORDERED, 7, get_trans_len_2}, {0x56, "OOOOOOOOOOOOOOOO", "RESERVE(10)", SCST_DATA_NONE, SCST_SMALL_TIMEOUT|SCST_LOCAL_CMD, 0, get_trans_len_none}, @@ -2579,11 +2579,9 @@ int scst_alloc_device(gfp_t gfp_mask, struct scst_device **out_dev) atomic_set(&dev->write_cmd_count, 0); scst_init_mem_lim(&dev->dev_mem_lim); spin_lock_init(&dev->dev_lock); - atomic_set(&dev->on_dev_count, 0); INIT_LIST_HEAD(&dev->blocked_cmd_list); INIT_LIST_HEAD(&dev->dev_tgt_dev_list); INIT_LIST_HEAD(&dev->dev_acg_dev_list); - init_waitqueue_head(&dev->on_dev_waitQ); dev->dev_double_ua_possible = 1; dev->queue_alg = SCST_CONTR_MODE_QUEUE_ALG_UNRESTRICTED_REORDER; @@ -4231,8 +4229,7 @@ void scst_free_cmd(struct scst_cmd *cmd) cmd, atomic_read(&scst_cmd_count)); } - sBUG_ON(cmd->inc_blocking || cmd->needs_unblocking || - cmd->dec_on_dev_needed); + sBUG_ON(cmd->unblock_dev); #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) #if defined(CONFIG_SCST_EXTRACHECKS) @@ -6685,47 +6682,12 @@ bool scst_del_thr_data(struct scst_tgt_dev *tgt_dev, struct task_struct *tsk) } /* dev_lock supposed to be held and BH disabled */ -void __scst_block_dev(struct scst_device *dev) +void scst_block_dev(struct scst_device *dev) { dev->block_count++; TRACE_MGMT_DBG("Device BLOCK(new %d), dev %p", dev->block_count, dev); } -/* No locks */ -static void scst_block_dev(struct scst_device *dev, int outstanding) -{ - spin_lock_bh(&dev->dev_lock); - __scst_block_dev(dev); - spin_unlock_bh(&dev->dev_lock); - - /* - * Memory barrier is necessary here, because we need to read - * on_dev_count in wait_event() below after we increased block_count. - * Otherwise, we can miss wake up in scst_dec_on_dev_cmd(). - * We use the explicit barrier, because spin_unlock_bh() doesn't - * provide the necessary memory barrier functionality. - */ - smp_mb(); - - TRACE_MGMT_DBG("Waiting during blocking outstanding %d (on_dev_count " - "%d)", outstanding, atomic_read(&dev->on_dev_count)); - wait_event(dev->on_dev_waitQ, - atomic_read(&dev->on_dev_count) <= outstanding); - TRACE_MGMT_DBG("%s", "wait_event() returned"); -} - -/* No locks */ -void scst_block_dev_cmd(struct scst_cmd *cmd, int outstanding) -{ - sBUG_ON(cmd->needs_unblocking); - - cmd->needs_unblocking = 1; - TRACE_MGMT_DBG("Needs unblocking cmd %p (tag %llu)", - cmd, (long long unsigned int)cmd->tag); - - scst_block_dev(cmd->dev, outstanding); -} - /* No locks */ void scst_unblock_dev(struct scst_device *dev) { @@ -6739,25 +6701,14 @@ void scst_unblock_dev(struct scst_device *dev) } /* No locks */ -void scst_unblock_dev_cmd(struct scst_cmd *cmd) +bool __scst_check_blocked_dev(struct scst_cmd *cmd) { - scst_unblock_dev(cmd->dev); - cmd->needs_unblocking = 0; -} - -/* No locks */ -int scst_inc_on_dev_cmd(struct scst_cmd *cmd) -{ - int res = 0; + int res = false; struct scst_device *dev = cmd->dev; TRACE_ENTRY(); - sBUG_ON(cmd->inc_blocking || cmd->dec_on_dev_needed); - - atomic_inc(&dev->on_dev_count); - cmd->dec_on_dev_needed = 1; - TRACE_DBG("New on_dev_count %d", atomic_read(&dev->on_dev_count)); + EXTRACHECKS_BUG_ON(cmd->unblock_dev); if (unlikely(cmd->internal) && (cmd->cdb[0] == REQUEST_SENSE)) { /* @@ -6768,18 +6719,17 @@ int scst_inc_on_dev_cmd(struct scst_cmd *cmd) } repeat: - if (unlikely(dev->block_count > 0)) { + if (dev->block_count > 0) { spin_lock_bh(&dev->dev_lock); if (unlikely(test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags))) goto out_unlock; if (dev->block_count > 0) { - scst_dec_on_dev_cmd(cmd); TRACE_MGMT_DBG("Delaying cmd %p due to blocking " "(tag %llu, dev %p)", cmd, (long long unsigned int)cmd->tag, dev); list_add_tail(&cmd->blocked_cmd_list_entry, &dev->blocked_cmd_list); - res = 1; + res = true; spin_unlock_bh(&dev->dev_lock); goto out; } else { @@ -6788,14 +6738,15 @@ repeat: } spin_unlock_bh(&dev->dev_lock); } - if (unlikely(dev->dev_double_ua_possible)) { + + if (dev->dev_double_ua_possible) { spin_lock_bh(&dev->dev_lock); if (dev->block_count == 0) { TRACE_MGMT_DBG("cmd %p (tag %llu), blocking further " "cmds due to possible double reset UA (dev %p)", cmd, (long long unsigned int)cmd->tag, dev); - __scst_block_dev(dev); - cmd->inc_blocking = 1; + scst_block_dev(dev); + cmd->unblock_dev = 1; } else { spin_unlock_bh(&dev->dev_lock); TRACE_MGMT_DBG("Somebody blocked the device, " diff --git a/scst/src/scst_priv.h b/scst/src/scst_priv.h index 994c16fa3..7cc159eb6 100644 --- a/scst/src/scst_priv.h +++ b/scst/src/scst_priv.h @@ -558,6 +558,11 @@ static inline bool scst_is_implicit_hq(struct scst_cmd *cmd) return (cmd->op_flags & SCST_IMPLICIT_HQ) != 0; } +static inline bool scst_is_implicit_ordered(struct scst_cmd *cmd) +{ + return (cmd->op_flags & SCST_IMPLICIT_ORDERED) != 0; +} + /* * Some notes on devices "blocking". Blocking means that no * commands will go from SCST to underlying SCSI device until it @@ -565,40 +570,29 @@ static inline bool scst_is_implicit_hq(struct scst_cmd *cmd) * already on the device. */ -extern int scst_inc_on_dev_cmd(struct scst_cmd *cmd); - -extern void __scst_block_dev(struct scst_device *dev); -extern void scst_block_dev_cmd(struct scst_cmd *cmd, int outstanding); +extern void scst_block_dev(struct scst_device *dev); extern void scst_unblock_dev(struct scst_device *dev); -extern void scst_unblock_dev_cmd(struct scst_cmd *cmd); + +extern bool __scst_check_blocked_dev(struct scst_cmd *cmd); + +static inline bool scst_check_blocked_dev(struct scst_cmd *cmd) +{ + if (unlikely(cmd->dev->block_count > 0) || + unlikely(cmd->dev->dev_double_ua_possible)) + return __scst_check_blocked_dev(cmd); + else + return false; +} /* No locks */ -static inline void scst_dec_on_dev_cmd(struct scst_cmd *cmd) +static inline void scst_check_unblock_dev(struct scst_cmd *cmd) { - struct scst_device *dev = cmd->dev; - bool unblock_dev = cmd->inc_blocking; - - if (cmd->inc_blocking) { + if (unlikely(cmd->unblock_dev)) { TRACE_MGMT_DBG("cmd %p (tag %llu): unblocking dev %p", cmd, (long long unsigned int)cmd->tag, cmd->dev); - cmd->inc_blocking = 0; + cmd->unblock_dev = 0; + scst_unblock_dev(cmd->dev); } - cmd->dec_on_dev_needed = 0; - - if (unblock_dev) - scst_unblock_dev(dev); - - atomic_dec(&dev->on_dev_count); - /* See comment in scst_block_dev() */ - smp_mb__after_atomic_dec(); - - TRACE_DBG("New on_dev_count %d", atomic_read(&dev->on_dev_count)); - - sBUG_ON(atomic_read(&dev->on_dev_count) < 0); - - if (unlikely(dev->block_count != 0)) - wake_up_all(&dev->on_dev_waitQ); - return; } diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index 5c5adc3e6..4d6d097e5 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -414,9 +414,10 @@ static int scst_pre_parse(struct scst_cmd *cmd) cmd->inc_expected_sn_on_done = 1; #else cmd->inc_expected_sn_on_done = dev->handler->exec_sync || - (!dev->has_own_order_mgmt && - (dev->queue_alg == SCST_CONTR_MODE_QUEUE_ALG_RESTRICTED_REORDER || - cmd->queue_type == SCST_CMD_QUEUE_ORDERED)); + scst_is_implicit_ordered(cmd) || + (!dev->has_own_order_mgmt && + (dev->queue_alg == SCST_CONTR_MODE_QUEUE_ALG_RESTRICTED_REORDER || + cmd->queue_type == SCST_CMD_QUEUE_ORDERED)); #endif /* @@ -1927,20 +1928,6 @@ out_unlock_compl: goto out_compl; } -static int scst_pre_select(struct scst_cmd *cmd) -{ - int res = SCST_EXEC_NOT_COMPLETED; - - TRACE_ENTRY(); - - scst_block_dev_cmd(cmd, 1); - - /* Check for local events will be done when cmd will be executed */ - - TRACE_EXIT_RES(res); - return res; -} - static int scst_reserve_local(struct scst_cmd *cmd) { int res = SCST_EXEC_NOT_COMPLETED, rc; @@ -2704,11 +2691,6 @@ static int scst_do_local_exec(struct scst_cmd *cmd) } switch (cmd->cdb[0]) { - case MODE_SELECT: - case MODE_SELECT_10: - case LOG_SELECT: - res = scst_pre_select(cmd); - break; case RESERVE: case RESERVE_10: res = scst_reserve_local(cmd); @@ -2780,7 +2762,7 @@ static int scst_exec(struct scst_cmd **active_cmd) TRACE_ENTRY(); - if (unlikely(scst_inc_on_dev_cmd(cmd) != 0)) + if (unlikely(scst_check_blocked_dev(cmd))) goto out; /* To protect tgt_dev */ @@ -2823,7 +2805,7 @@ done: if (cmd == NULL) break; - if (unlikely(scst_inc_on_dev_cmd(cmd) != 0)) + if (unlikely(scst_check_blocked_dev(cmd))) break; __scst_cmd_put(ref_cmd); @@ -3372,11 +3354,7 @@ static int scst_dev_done(struct scst_cmd *cmd) #endif } - if (cmd->needs_unblocking) - scst_unblock_dev_cmd(cmd); - - if (likely(cmd->dec_on_dev_needed)) - scst_dec_on_dev_cmd(cmd); + scst_check_unblock_dev(cmd); if (cmd->inc_expected_sn_on_done && cmd->sent_for_exec) scst_inc_check_expected_sn(cmd); @@ -3694,6 +3672,9 @@ static void scst_cmd_set_sn(struct scst_cmd *cmd) cmd->queue_type = SCST_CMD_QUEUE_HEAD_OF_QUEUE; } + if (unlikely(scst_is_implicit_ordered(cmd))) + cmd->queue_type = SCST_CMD_QUEUE_ORDERED; + EXTRACHECKS_BUG_ON(cmd->sn_set || cmd->hq_cmd_inced); /* Optimized for lockless fast path */ @@ -5047,7 +5028,7 @@ static int scst_clear_task_set(struct scst_mgmt_cmd *mcmd) */ mcmd->needs_unblocking = 1; spin_lock_bh(&dev->dev_lock); - __scst_block_dev(dev); + scst_block_dev(dev); spin_unlock_bh(&dev->dev_lock); #endif @@ -5207,7 +5188,7 @@ static int scst_target_reset(struct scst_mgmt_cmd *mcmd) dev = acg_dev->dev; spin_lock_bh(&dev->dev_lock); - __scst_block_dev(dev); + scst_block_dev(dev); scst_process_reset(dev, mcmd->sess, NULL, mcmd, true); spin_unlock_bh(&dev->dev_lock); @@ -5311,7 +5292,7 @@ static int scst_lun_reset(struct scst_mgmt_cmd *mcmd) mcmd->needs_unblocking = 1; spin_lock_bh(&dev->dev_lock); - __scst_block_dev(dev); + scst_block_dev(dev); scst_process_reset(dev, mcmd->sess, NULL, mcmd, true); spin_unlock_bh(&dev->dev_lock);