diff --git a/scst/README b/scst/README index 37c638396..640cc016e 100644 --- a/scst/README +++ b/scst/README @@ -580,7 +580,7 @@ Every target should have at least the following entries: mapping to the corresponding hardware port. It isn't anyhow used by SCST. - - enabled - using this attribute you can enable or disable this target/ + - enabled - using this attribute you can enable or disable this target. It allows to finish configuring it before it starts accepting new connections. 0 by default. @@ -592,6 +592,28 @@ Every target should have at least the following entries: can assign the addressing method on per-initiator basis. See also the "Logical unit addressing (LUN)" section in SAM-5 for more information. + - black_hole - if set, all LUNs in the corresponding initiator group, + default target group in this case, start "swallowing" requests from + initiators. Possible values are: + + * 0 - disable black hole mode + + * 1 - immediately abort all coming commands + + * 2 - immediately abort all coming commands and drop all coming TM + commands + + * 3 - immediately abort all coming data transfer commands. This is + the most evil mode, because it is not too well handled by many + initiator OS'es, including Linux, so they may never recover from + it. + + * 4 - immediately abort all coming data transfer commands and drop all + coming TM commands + + CAUTION! With some target drivers modes 2 and 4 can cause internal + resources leaks, so don't abuse those options! + - cpu_mask - defines CPU affinity mask for threads serving this target. For threads serving LUNs it is used only for devices with threads_pool_type "per_initiator". @@ -750,7 +772,7 @@ commands by looking inside this file. Each security group's subdirectory contains 2 subdirectories: initiators and luns as well as the following attributes: addr_method, cpu_mask and -io_grouping_type. See above description of them. +io_grouping_type, black_hole. See above description of them. Each "initiators" subdirectory contains list of added to this groups initiator as well as as well as file "mgmt". This file has the following diff --git a/scst/README_in-tree b/scst/README_in-tree index 1a419af93..ba1824acb 100644 --- a/scst/README_in-tree +++ b/scst/README_in-tree @@ -442,7 +442,7 @@ Every target should have at least the following entries: mapping to the corresponding hardware port. It isn't anyhow used by SCST. - - enabled - using this attribute you can enable or disable this target/ + - enabled - using this attribute you can enable or disable this target. It allows to finish configuring it before it starts accepting new connections. 0 by default. @@ -454,6 +454,28 @@ Every target should have at least the following entries: can assign the addressing method on per-initiator basis. See also the "Logical unit addressing (LUN)" section in SAM-5 for more information. + - black_hole - if set, all LUNs in the corresponding initiator group, + default target group in this case, start "swallowing" requests from + initiators. Possible values are: + + * 0 - disable black hole mode + + * 1 - immediately abort all coming commands + + * 2 - immediately abort all coming commands and drop all coming TM + commands + + * 3 - immediately abort all coming data transfer commands. This is + the most evil mode, because it is not too well handled by many + initiator OS'es, including Linux, so they may never recover from + it. + + * 4 - immediately abort all coming data transfer commands and drop all + coming TM commands + + CAUTION! With some target drivers modes 2 and 4 can cause internal + resources leaks, so don't abuse those options! + - cpu_mask - defines CPU affinity mask for threads serving this target. For threads serving LUNs it is used only for devices with threads_pool_type "per_initiator". @@ -612,7 +634,7 @@ commands by looking inside this file. Each security group's subdirectory contains 2 subdirectories: initiators and luns as well as the following attributes: addr_method, cpu_mask and -io_grouping_type. See above description of them. +io_grouping_type, black_hole. See above description of them. Each "initiators" subdirectory contains list of added to this groups initiator as well as as well as file "mgmt". This file has the following diff --git a/scst/include/scst.h b/scst/include/scst.h index 734673935..673edb93f 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -592,6 +592,9 @@ enum scst_exec_context { /* Set if tgt_dev has Unit Attention sense */ #define SCST_TGT_DEV_UA_PENDING 0 +/* Cache of acg->acg_black_hole_type */ +#define SCST_TGT_DEV_BLACK_HOLE 1 + /************************************************************* ** I/O grouping types. Changing them don't forget to change ** the corresponding *_STR values in scst_const.h! @@ -2727,6 +2730,33 @@ struct scst_acg { unsigned int tgt_acg:1; +/* Not a black hole */ +#define SCST_ACG_BLACK_HOLE_NONE 0 + +/* Immediately abort all coming commands */ +#define SCST_ACG_BLACK_HOLE_CMD 1 + +/* + * Immediately abort all coming commands and drop all coming TM commands. + * + * CAUTION! With some target drivers it can cause internal resources + * leaks, so don't abuse this option! + */ +#define SCST_ACG_BLACK_HOLE_ALL 2 + +/* Immediately abort all coming data transfer commands */ +#define SCST_ACG_BLACK_HOLE_DATA_CMD 3 + +/* + * Immediately abort all coming data transfer commands and drop all + * coming TM commands. + * + * CAUTION! With some target drivers it can cause internal resources + * leaks, so don't abuse this option! + */ +#define SCST_ACG_BLACK_HOLE_DATA_MCMD 4 + volatile int acg_black_hole_type; + /* sysfs release completion */ struct completion *acg_kobj_release_cmpl; diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 6cde29e44..f0b6d001f 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -4152,6 +4152,10 @@ static int scst_alloc_add_tgt_dev(struct scst_session *sess, tgt_dev->tgt_dev_rd_only = acg_dev->acg_dev_rd_only || dev->dev_rd_only; tgt_dev->sess = sess; atomic_set(&tgt_dev->tgt_dev_cmd_count, 0); + if (sess->acg->acg_black_hole_type != SCST_ACG_BLACK_HOLE_NONE) + set_bit(SCST_TGT_DEV_BLACK_HOLE, &tgt_dev->tgt_dev_flags); + else + clear_bit(SCST_TGT_DEV_BLACK_HOLE, &tgt_dev->tgt_dev_flags); scst_sgv_pool_use_norm(tgt_dev); diff --git a/scst/src/scst_sysfs.c b/scst/src/scst_sysfs.c index c7e08ab7d..bcd351f56 100644 --- a/scst/src/scst_sysfs.c +++ b/scst/src/scst_sysfs.c @@ -1756,6 +1756,125 @@ static struct kobj_attribute scst_tgt_io_grouping_type = scst_tgt_io_grouping_type_show, scst_tgt_io_grouping_type_store); +static ssize_t __scst_acg_black_hole_show(struct scst_acg *acg, char *buf) +{ + int res, t = acg->acg_black_hole_type; + + res = sprintf(buf, "%d\n%s\n", t, + (t != SCST_ACG_BLACK_HOLE_NONE) ? SCST_SYSFS_KEY_MARK : ""); + + return res; +} + +static ssize_t __scst_acg_black_hole_store(struct scst_acg *acg, + const char *buf, size_t count) +{ + int res = 0; + int prev, t; + struct scst_session *sess; + + prev = acg->acg_black_hole_type; + + if ((buf == NULL) || (count == 0)) { + res = 0; + goto out; + } + + mutex_lock(&scst_mutex); + + BUILD_BUG_ON((SCST_ACG_BLACK_HOLE_NONE != 0) || + (SCST_ACG_BLACK_HOLE_CMD != 1) || + (SCST_ACG_BLACK_HOLE_ALL != 2) || + (SCST_ACG_BLACK_HOLE_DATA_CMD != 3) || + (SCST_ACG_BLACK_HOLE_DATA_MCMD != 4)); + switch (buf[0]) { + case '0': + acg->acg_black_hole_type = SCST_ACG_BLACK_HOLE_NONE; + break; + case '1': + acg->acg_black_hole_type = SCST_ACG_BLACK_HOLE_CMD; + break; + case '2': + acg->acg_black_hole_type = SCST_ACG_BLACK_HOLE_ALL; + break; + case '3': + acg->acg_black_hole_type = SCST_ACG_BLACK_HOLE_DATA_CMD; + break; + case '4': + acg->acg_black_hole_type = SCST_ACG_BLACK_HOLE_DATA_MCMD; + break; + default: + PRINT_ERROR("%s: Requested action not understood: %s", + __func__, buf); + res = -EINVAL; + goto out_unlock; + } + + t = acg->acg_black_hole_type; + + if (prev == t) + goto out_unlock; + + list_for_each_entry(sess, &acg->acg_sess_list, acg_sess_list_entry) { + int i; + for (i = 0; i < SESS_TGT_DEV_LIST_HASH_SIZE; i++) { + struct list_head *head = &sess->sess_tgt_dev_list[i]; + struct scst_tgt_dev *tgt_dev; + list_for_each_entry(tgt_dev, head, sess_tgt_dev_list_entry) { + if (t != SCST_ACG_BLACK_HOLE_NONE) + set_bit(SCST_TGT_DEV_BLACK_HOLE, &tgt_dev->tgt_dev_flags); + else + clear_bit(SCST_TGT_DEV_BLACK_HOLE, &tgt_dev->tgt_dev_flags); + } + } + } + + PRINT_INFO("Black hole set to %d for ACG %s", t, acg->acg_name); + +out_unlock: + mutex_unlock(&scst_mutex); + +out: + return res; +} + +static ssize_t scst_tgt_black_hole_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct scst_acg *acg; + struct scst_tgt *tgt; + + tgt = container_of(kobj, struct scst_tgt, tgt_kobj); + acg = tgt->default_acg; + + return __scst_acg_black_hole_show(acg, buf); +} + +static ssize_t scst_tgt_black_hole_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + int res; + struct scst_acg *acg; + struct scst_tgt *tgt; + + tgt = container_of(kobj, struct scst_tgt, tgt_kobj); + acg = tgt->default_acg; + + res = __scst_acg_black_hole_store(acg, buf, count); + if (res != 0) + goto out; + + res = count; + +out: + TRACE_EXIT_RES(res); + return res; +} + +static struct kobj_attribute scst_tgt_black_hole = + __ATTR(black_hole, S_IRUGO | S_IWUSR, + scst_tgt_black_hole_show, scst_tgt_black_hole_store); + static ssize_t __scst_acg_cpu_mask_show(struct scst_acg *acg, char *buf) { int res; @@ -2473,6 +2592,7 @@ static struct attribute *scst_tgt_attrs[] = { &scst_tgt_comment.attr, &scst_tgt_addr_method.attr, &scst_tgt_io_grouping_type.attr, + &scst_tgt_black_hole.attr, &scst_tgt_cpu_mask.attr, &scst_tgt_unknown_cmd_count_attr.attr, &scst_tgt_write_cmd_count_attr.attr, @@ -4285,6 +4405,39 @@ static struct kobj_attribute scst_acg_io_grouping_type = scst_acg_io_grouping_type_show, scst_acg_io_grouping_type_store); +static ssize_t scst_acg_black_hole_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct scst_acg *acg; + + acg = container_of(kobj, struct scst_acg, acg_kobj); + + return __scst_acg_black_hole_show(acg, buf); +} + +static ssize_t scst_acg_black_hole_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + int res; + struct scst_acg *acg; + + acg = container_of(kobj, struct scst_acg, acg_kobj); + + res = __scst_acg_black_hole_store(acg, buf, count); + if (res != 0) + goto out; + + res = count; + +out: + TRACE_EXIT_RES(res); + return res; +} + +static struct kobj_attribute scst_acg_black_hole = + __ATTR(black_hole, S_IRUGO | S_IWUSR, + scst_acg_black_hole_show, scst_acg_black_hole_store); + static ssize_t scst_acg_cpu_mask_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { @@ -4408,6 +4561,13 @@ int scst_acg_sysfs_create(struct scst_tgt *tgt, goto out_del; } + res = sysfs_create_file(&acg->acg_kobj, &scst_acg_black_hole.attr); + if (res != 0) { + PRINT_ERROR("Can't add tgt attr %s for tgt %s", + scst_acg_black_hole.attr.name, tgt->tgt_name); + goto out_del; + } + res = sysfs_create_file(&acg->acg_kobj, &scst_acg_cpu_mask.attr); if (res != 0) { PRINT_ERROR("Can't add tgt attr %s for tgt %s", diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index d6b6f81bf..f84a9fe64 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -972,6 +972,32 @@ out: } #endif + if (unlikely(test_bit(SCST_TGT_DEV_BLACK_HOLE, &cmd->tgt_dev->tgt_dev_flags))) { + struct scst_session *sess = cmd->sess; + bool abort = false; + switch (sess->acg->acg_black_hole_type) { + case SCST_ACG_BLACK_HOLE_CMD: + case SCST_ACG_BLACK_HOLE_ALL: + abort = true; + break; + case SCST_ACG_BLACK_HOLE_DATA_CMD: + case SCST_ACG_BLACK_HOLE_DATA_MCMD: + if (cmd->data_direction != SCST_DATA_NONE) + abort = true; + break; + default: + break; + } + if (abort) { + TRACE_MGMT_DBG("Black hole: aborting cmd %p (op %x, " + "initiator %s)", cmd, cmd->cdb[0], + sess->initiator_name); + spin_lock_irq(&sess->sess_list_lock); + scst_abort_cmd(cmd, NULL, false, false); + spin_unlock_irq(&sess->sess_list_lock); + } + } + TRACE_EXIT_HRES(res); return res; @@ -5466,10 +5492,20 @@ static int scst_clear_task_set(struct scst_mgmt_cmd *mcmd) * >0, if it should be requeued, <0 otherwise */ static int scst_mgmt_cmd_init(struct scst_mgmt_cmd *mcmd) { - int res = 0, rc; + int res = 0, rc, t; TRACE_ENTRY(); + t = mcmd->sess->acg->acg_black_hole_type; + + if (unlikely((t == SCST_ACG_BLACK_HOLE_ALL) || + (t == SCST_ACG_BLACK_HOLE_DATA_MCMD))) { + TRACE_MGMT_DBG("Dropping mcmd %p (fn %d, initiator %s)", mcmd, + mcmd->fn, mcmd->sess->initiator_name); + mcmd->state = SCST_MCMD_STATE_FINISHED; + goto out; + } + switch (mcmd->fn) { case SCST_ABORT_TASK: {