diff --git a/scst/README b/scst/README index 978d8f6fb..395be9cc6 100644 --- a/scst/README +++ b/scst/README @@ -441,6 +441,19 @@ following entries: have different IDs and SNs. For instance, VDISK dev handler uses this ID to generate T10 vendor specific identifier and SN of the devices. + - suspend - globally suspends or releases all SCSI activities on all + devices. Useful for mass management, like adding or deleting LUNs. + Writing to it value v: + + * v > 0 - suspends activities, but waits no more, than v seconds + + * v = 0 - suspends activities, waits indefinitely + + * V < 0 - releases activities. + + Reading from this attribute returns number of previous suspend + requests. + - threads - allows to read and set number of global SCST I/O threads. Those threads used with async. dev handlers, for instance, vdisk BLOCKIO or NULLIO. diff --git a/scst/README_in-tree b/scst/README_in-tree index 91d0b6ca6..d1bcc9d59 100644 --- a/scst/README_in-tree +++ b/scst/README_in-tree @@ -305,6 +305,19 @@ following entries: have different IDs and SNs. For instance, VDISK dev handler uses this ID to generate T10 vendor specific identifier and SN of the devices. + - suspend - globally suspends or releases all SCSI activities on all + devices. Useful for mass management, like adding or deleting LUNs. + Writing to it value v: + + * v > 0 - suspends activities, but waits no more, than v seconds + + * v = 0 - suspends activities, waits indefinitely + + * V < 0 - releases activities. + + Reading from this attribute returns number of previous suspend + requests. + - threads - allows to read and set number of global SCST I/O threads. Those threads used with async. dev handlers, for instance, vdisk BLOCKIO or NULLIO. diff --git a/scst/src/scst_main.c b/scst/src/scst_main.c index 85ab18fe1..4bfde9df1 100644 --- a/scst/src/scst_main.c +++ b/scst/src/scst_main.c @@ -1057,6 +1057,11 @@ static void __scst_resume_activity(void) TRACE_ENTRY(); + if (suspend_count == 0) { + PRINT_WARNING("Resume without suspend"); + goto out; + } + suspend_count--; TRACE_MGMT_DBG("suspend_count %d left", suspend_count); if (suspend_count > 0) @@ -1117,6 +1122,11 @@ void scst_resume_activity(void) } EXPORT_SYMBOL_GPL(scst_resume_activity); +int scst_get_suspend_count(void) +{ + return suspend_count; +} + static int scst_register_device(struct scsi_device *scsidp) { int res; diff --git a/scst/src/scst_priv.h b/scst/src/scst_priv.h index 327504f35..6740845c6 100644 --- a/scst/src/scst_priv.h +++ b/scst/src/scst_priv.h @@ -729,6 +729,8 @@ void scst_ext_unblock_dev(struct scst_device *dev, bool stpg); void __scst_ext_blocking_done(struct scst_device *dev); void scst_ext_blocking_done(struct scst_device *dev); +int scst_get_suspend_count(void); + /* * Increases global SCST ref counters which prevent from entering into suspended * activities stage, so protects from any global management operations. diff --git a/scst/src/scst_sysfs.c b/scst/src/scst_sysfs.c index 9b7336dd8..62497ecdc 100644 --- a/scst/src/scst_sysfs.c +++ b/scst/src/scst_sysfs.c @@ -7056,6 +7056,55 @@ static struct kobj_attribute scst_max_tasklet_cmd_attr = __ATTR(max_tasklet_cmd, S_IRUGO | S_IWUSR, scst_max_tasklet_cmd_show, scst_max_tasklet_cmd_store); +static ssize_t scst_suspend_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + int count; + + TRACE_ENTRY(); + + count = sprintf(buf, "%d\n", scst_get_suspend_count()); + + TRACE_EXIT(); + return count; +} + +static ssize_t scst_suspend_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + int res; + long val; + + TRACE_ENTRY(); + + res = kstrtol(buf, 0, &val); + if (res != 0) { + PRINT_ERROR("kstrtoul() for %s failed: %d ", buf, res); + goto out; + } + + if (val >= 0) { + PRINT_INFO("SYSFS: suspending activities (timeout %ld)...", val); + res = scst_suspend_activity(val*HZ); + if (res == 0) + PRINT_INFO("sysfs suspending done"); + } else { + PRINT_INFO("SYSFS: resuming activities"); + scst_resume_activity(); + } + + if (res == 0) + res = count; + +out: + TRACE_EXIT_RES(res); + return res; +} + +static struct kobj_attribute scst_suspend_attr = + __ATTR(suspend, S_IRUGO | S_IWUSR, scst_suspend_show, + scst_suspend_store); + #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) static ssize_t scst_main_trace_level_show(struct kobject *kobj, @@ -7281,6 +7330,7 @@ static struct attribute *scst_sysfs_root_default_attrs[] = { &scst_threads_attr.attr, &scst_setup_id_attr.attr, &scst_max_tasklet_cmd_attr.attr, + &scst_suspend_attr.attr, #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) &scst_main_trace_level_attr.attr, #endif