mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-23 13:41:27 +00:00
Saved mode pages added
git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@5479 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
15
scst/README
15
scst/README
@@ -945,6 +945,9 @@ cache. The following parameters possible for vdisk_fileio:
|
||||
will go from the initiator. This option overrides "write_through"
|
||||
option. Disabled by default.
|
||||
|
||||
- tst - sets TST field of SCSI Control mode page. See SPC-4 for more
|
||||
details about this field as well as about possible values.
|
||||
|
||||
- thin_provisioned - enables thin provisioning facility, when remote
|
||||
initiators can unmap blocks of storage, if they don't need them
|
||||
anymore. Backend storage also must support this facility.
|
||||
@@ -966,8 +969,8 @@ between application and disk or need the large block throughput. See
|
||||
below for more info.
|
||||
|
||||
The following parameters possible for vdisk_blockio: filename,
|
||||
blocksize, nv_cache, read_only, removable, rotational, thin_provisioned.
|
||||
See vdisk_fileio above for description of those parameters.
|
||||
blocksize, nv_cache, read_only, removable, rotational, thin_provisioned,
|
||||
tst. See vdisk_fileio above for description of those parameters.
|
||||
|
||||
Handler vdisk_nullio provides NULLIO mode to create virtual devices. In
|
||||
this mode no real I/O is done, but success returned to initiators.
|
||||
@@ -1025,6 +1028,9 @@ Each vdisk_fileio's device has the following attributes in
|
||||
SCST device belongs to (in SCSI terminology all SCST devices called
|
||||
Logical Units). See SPC for more info.
|
||||
|
||||
- tst - contains TST field of SCSI Control mode page. See SPC-4 for
|
||||
more details about this field.
|
||||
|
||||
- thin_provisioned - contains thin provisioning status of this virtual
|
||||
device.
|
||||
|
||||
@@ -1087,6 +1093,7 @@ For example:
|
||||
|-- thin_provisioned
|
||||
|-- threads_num
|
||||
|-- threads_pool_type
|
||||
|-- tst
|
||||
|-- type
|
||||
|-- usn
|
||||
`-- write_through
|
||||
@@ -1094,8 +1101,8 @@ For example:
|
||||
Each vdisk_blockio's device has the following attributes in
|
||||
/sys/kernel/scst_tgt/devices/device_name: blocksize, filename, nv_cache,
|
||||
read_only, removable, resync_size, rotational, size_mb, t10_dev_id,
|
||||
thin_provisioned, threads_num, threads_pool_type, type, usn. See above
|
||||
description of those parameters.
|
||||
thin_provisioned, threads_num, threads_pool_type, tst, type, usn. See
|
||||
above description of those parameters.
|
||||
|
||||
Each vdisk_nullio's device has the following attributes in
|
||||
/sys/kernel/scst_tgt/devices/device_name: blocksize, read_only,
|
||||
|
||||
@@ -803,6 +803,9 @@ cache. The following parameters possible for vdisk_fileio:
|
||||
will go from the initiator. This option overrides "write_through"
|
||||
option. Disabled by default.
|
||||
|
||||
- tst - sets TST field of SCSI Control mode page. See SPC-4 for more
|
||||
details about this field as well as about possible values.
|
||||
|
||||
- thin_provisioned - enables thin provisioning facility, when remote
|
||||
initiators can unmap blocks of storage, if they don't need them
|
||||
anymore. Backend storage also must support this facility.
|
||||
@@ -824,8 +827,8 @@ between application and disk or need the large block throughput. See
|
||||
below for more info.
|
||||
|
||||
The following parameters possible for vdisk_blockio: filename,
|
||||
blocksize, nv_cache, read_only, removable, rotational, thin_provisioned.
|
||||
See vdisk_fileio above for description of those parameters.
|
||||
blocksize, nv_cache, read_only, removable, rotational, thin_provisioned,
|
||||
tst. See vdisk_fileio above for description of those parameters.
|
||||
|
||||
Handler vdisk_nullio provides NULLIO mode to create virtual devices. In
|
||||
this mode no real I/O is done, but success returned to initiators.
|
||||
@@ -883,6 +886,9 @@ Each vdisk_fileio's device has the following attributes in
|
||||
SCST device belongs to (in SCSI terminology all SCST devices called
|
||||
Logical Units). See SPC for more info.
|
||||
|
||||
- tst - contains TST field of SCSI Control mode page. See SPC-4 for
|
||||
more details about this field.
|
||||
|
||||
- thin_provisioned - contains thin provisioning status of this virtual
|
||||
device.
|
||||
|
||||
@@ -939,6 +945,7 @@ For example:
|
||||
|-- thin_provisioned
|
||||
|-- threads_num
|
||||
|-- threads_pool_type
|
||||
|-- tst
|
||||
|-- type
|
||||
|-- usn
|
||||
`-- write_through
|
||||
@@ -946,8 +953,8 @@ For example:
|
||||
Each vdisk_blockio's device has the following attributes in
|
||||
/sys/kernel/scst_tgt/devices/device_name: blocksize, filename, nv_cache,
|
||||
read_only, removable, resync_size, rotational, size_mb, t10_dev_id,
|
||||
thin_provisioned, threads_num, threads_pool_type, type, usn. See above
|
||||
description of those parameters.
|
||||
thin_provisioned, threads_num, threads_pool_type, tst, type, usn. See
|
||||
above description of those parameters.
|
||||
|
||||
Each vdisk_nullio's device has the following attributes in
|
||||
/sys/kernel/scst_tgt/devices/device_name: blocksize, read_only,
|
||||
|
||||
@@ -2414,10 +2414,31 @@ struct scst_device {
|
||||
unsigned int swp:1;
|
||||
unsigned int d_sense:1;
|
||||
|
||||
/**
|
||||
** Saved and default versions of them, which supported. TST is not
|
||||
** among them, because it's hard to switch curr_order_data on the
|
||||
** fly. To ensure that no commands lost, we need to flush the previous
|
||||
** curr_order_data at first and with one being active command (MODE
|
||||
** SELECT), we don't have facility for that at the moment. Suspending
|
||||
** activities will hang waiting for the active MODE SELECT. ToDo.
|
||||
**/
|
||||
|
||||
unsigned int queue_alg_saved:4;
|
||||
unsigned int queue_alg_default:4;
|
||||
|
||||
unsigned int tas_saved:1;
|
||||
unsigned int tas_default:1;
|
||||
|
||||
unsigned int swp_saved:1;
|
||||
unsigned int swp_default:1;
|
||||
|
||||
unsigned int d_sense_saved:1;
|
||||
unsigned int d_sense_default:1;
|
||||
|
||||
/*
|
||||
* Set if device implements own ordered commands management. If not set
|
||||
* and queue_alg is SCST_CONTR_MODE_QUEUE_ALG_RESTRICTED_REORDER,
|
||||
* expected_sn will be incremented only after commands finished.
|
||||
* and queue_alg is SCST_QUEUE_ALG_0_RESTRICTED_REORDER, expected_sn
|
||||
* will be incremented only after commands finished.
|
||||
*/
|
||||
unsigned int has_own_order_mgmt:1;
|
||||
|
||||
@@ -4695,4 +4716,16 @@ void scst_write_same(struct scst_cmd *cmd);
|
||||
__be64 scst_pack_lun(const uint64_t lun, enum scst_lun_addr_method addr_method);
|
||||
uint64_t scst_unpack_lun(const uint8_t *lun, int len);
|
||||
|
||||
int scst_save_global_mode_pages(const struct scst_device *dev,
|
||||
uint8_t *buf, int size);
|
||||
int scst_restore_global_mode_pages(struct scst_device *dev, char *params,
|
||||
char **last_param);
|
||||
|
||||
int scst_read_file_transactional(const char *name, const char *name1,
|
||||
const char *signature, int signature_len, uint8_t *buf, int size);
|
||||
int scst_write_file_transactional(const char *name, const char *name1,
|
||||
const char *signature, int signature_len, const uint8_t *buf, int size);
|
||||
|
||||
int scst_remove_file(const char *name);
|
||||
|
||||
#endif /* __SCST_H */
|
||||
|
||||
@@ -495,20 +495,20 @@ enum {
|
||||
/*************************************************************
|
||||
** Values for the control mode page TST field
|
||||
*************************************************************/
|
||||
#define SCST_CONTR_MODE_ONE_TASK_SET 0
|
||||
#define SCST_CONTR_MODE_SEP_TASK_SETS 1
|
||||
#define SCST_TST_0_SINGLE_TASK_SET 0
|
||||
#define SCST_TST_1_SEP_TASK_SETS 1
|
||||
|
||||
/*******************************************************************
|
||||
** Values for the control mode page QUEUE ALGORITHM MODIFIER field
|
||||
*******************************************************************/
|
||||
#define SCST_CONTR_MODE_QUEUE_ALG_RESTRICTED_REORDER 0
|
||||
#define SCST_CONTR_MODE_QUEUE_ALG_UNRESTRICTED_REORDER 1
|
||||
#define SCST_QUEUE_ALG_0_RESTRICTED_REORDER 0
|
||||
#define SCST_QUEUE_ALG_1_UNRESTRICTED_REORDER 1
|
||||
|
||||
/*************************************************************
|
||||
** Values for the control mode page D_SENSE field
|
||||
*************************************************************/
|
||||
#define SCST_CONTR_MODE_FIXED_SENSE 0
|
||||
#define SCST_CONTR_MODE_DESCR_SENSE 1
|
||||
#define SCST_D_SENSE_0_FIXED_SENSE 0
|
||||
#define SCST_D_SENSE_1_DESCR_SENSE 1
|
||||
|
||||
/*************************************************************
|
||||
** TransportID protocol identifiers
|
||||
|
||||
@@ -71,6 +71,7 @@ all:
|
||||
$(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd)
|
||||
|
||||
install: all
|
||||
mkdir -p $(DESTDIR)/var/lib/scst/vdev_mode_pages
|
||||
$(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) \
|
||||
modules_install
|
||||
|
||||
|
||||
@@ -2620,8 +2620,14 @@ static int dev_user_attach(struct scst_device *sdev)
|
||||
sdev->tst = dev->tst;
|
||||
sdev->queue_alg = dev->queue_alg;
|
||||
sdev->swp = dev->swp;
|
||||
sdev->swp_saved = dev->swp;
|
||||
sdev->swp_default = dev->swp;
|
||||
sdev->tas = dev->tas;
|
||||
sdev->tas_saved = dev->tas;
|
||||
sdev->tas_default = dev->tas;
|
||||
sdev->d_sense = dev->d_sense;
|
||||
sdev->d_sense_saved = dev->d_sense;
|
||||
sdev->d_sense_default = dev->d_sense;
|
||||
sdev->has_own_order_mgmt = dev->has_own_order_mgmt;
|
||||
|
||||
dev->sdev = sdev;
|
||||
@@ -3350,10 +3356,10 @@ static int __dev_user_set_opt(struct scst_user_dev *dev,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (((opt->tst != SCST_CONTR_MODE_ONE_TASK_SET) &&
|
||||
(opt->tst != SCST_CONTR_MODE_SEP_TASK_SETS)) ||
|
||||
((opt->queue_alg != SCST_CONTR_MODE_QUEUE_ALG_RESTRICTED_REORDER) &&
|
||||
(opt->queue_alg != SCST_CONTR_MODE_QUEUE_ALG_UNRESTRICTED_REORDER)) ||
|
||||
if (((opt->tst != SCST_TST_0_SINGLE_TASK_SET) &&
|
||||
(opt->tst != SCST_TST_1_SEP_TASK_SETS)) ||
|
||||
((opt->queue_alg != SCST_QUEUE_ALG_0_RESTRICTED_REORDER) &&
|
||||
(opt->queue_alg != SCST_QUEUE_ALG_1_UNRESTRICTED_REORDER)) ||
|
||||
(opt->swp > 1) || (opt->tas > 1) || (opt->has_own_order_mgmt > 1) ||
|
||||
(opt->d_sense > 1)) {
|
||||
PRINT_ERROR("Invalid SCSI option (tst %x, queue_alg %x, swp %x,"
|
||||
@@ -3364,6 +3370,16 @@ static int __dev_user_set_opt(struct scst_user_dev *dev,
|
||||
goto out;
|
||||
}
|
||||
|
||||
#if 1
|
||||
if ((dev->tst != opt->tst) && (dev->sdev != NULL) &&
|
||||
!list_empty(&dev->sdev->dev_tgt_dev_list)) {
|
||||
PRINT_ERROR("On the fly setting of TST not supported. "
|
||||
"See comment in struct scst_device.");
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
dev->parse_type = opt->parse_type;
|
||||
dev->on_free_cmd_type = opt->on_free_cmd_type;
|
||||
dev->memory_reuse_type = opt->memory_reuse_type;
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/namei.h>
|
||||
#ifndef INSIDE_KERNEL_TREE
|
||||
#include <linux/version.h>
|
||||
#endif
|
||||
@@ -114,18 +115,18 @@ static struct scst_trace_log vdisk_local_trace_tbl[] = {
|
||||
|
||||
#define VDISK_NULLIO_SIZE (5LL*1024*1024*1024*1024/2)
|
||||
|
||||
#define DEF_TST SCST_CONTR_MODE_SEP_TASK_SETS
|
||||
#define DEF_TST SCST_TST_1_SEP_TASK_SETS
|
||||
|
||||
/*
|
||||
* Since we can't control backstorage device's reordering, we have to always
|
||||
* report unrestricted reordering.
|
||||
*/
|
||||
#define DEF_QUEUE_ALG_WT SCST_CONTR_MODE_QUEUE_ALG_UNRESTRICTED_REORDER
|
||||
#define DEF_QUEUE_ALG SCST_CONTR_MODE_QUEUE_ALG_UNRESTRICTED_REORDER
|
||||
#define DEF_QUEUE_ALG_WT SCST_QUEUE_ALG_1_UNRESTRICTED_REORDER
|
||||
#define DEF_QUEUE_ALG SCST_QUEUE_ALG_1_UNRESTRICTED_REORDER
|
||||
#define DEF_SWP 0
|
||||
#define DEF_TAS 0
|
||||
|
||||
#define DEF_DSENSE SCST_CONTR_MODE_FIXED_SENSE
|
||||
#define DEF_DSENSE SCST_D_SENSE_0_FIXED_SENSE
|
||||
|
||||
#ifdef CONFIG_SCST_PROC
|
||||
#define VDISK_PROC_HELP "help"
|
||||
@@ -162,6 +163,8 @@ struct scst_vdisk_dev {
|
||||
unsigned int thin_provisioned_manually_set:1;
|
||||
unsigned int dev_thin_provisioned:1;
|
||||
unsigned int rotational:1;
|
||||
unsigned int wt_flag_saved:1;
|
||||
unsigned int tst:3;
|
||||
unsigned int format_active:1;
|
||||
|
||||
struct file *fd;
|
||||
@@ -217,6 +220,8 @@ struct vdisk_cmd_params {
|
||||
bool use_zero_copy;
|
||||
};
|
||||
|
||||
static bool vdev_saved_mode_pages_enabled = true;
|
||||
|
||||
enum compl_status_e {
|
||||
#if defined(SCST_DEBUG)
|
||||
COMPL_STATUS_START_AT = 777,
|
||||
@@ -332,6 +337,8 @@ static ssize_t vdisk_sysfs_wt_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf);
|
||||
static ssize_t vdisk_sysfs_tp_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf);
|
||||
static ssize_t vdisk_sysfs_tst_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf);
|
||||
static ssize_t vdisk_sysfs_rotational_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf);
|
||||
static ssize_t vdisk_sysfs_nv_cache_show(struct kobject *kobj,
|
||||
@@ -402,6 +409,8 @@ static struct kobj_attribute vdisk_wt_attr =
|
||||
__ATTR(write_through, S_IRUGO, vdisk_sysfs_wt_show, NULL);
|
||||
static struct kobj_attribute vdisk_tp_attr =
|
||||
__ATTR(thin_provisioned, S_IRUGO, vdisk_sysfs_tp_show, NULL);
|
||||
static struct kobj_attribute vdisk_tst_attr =
|
||||
__ATTR(tst, S_IRUGO, vdisk_sysfs_tst_show, NULL);
|
||||
static struct kobj_attribute vdisk_rotational_attr =
|
||||
__ATTR(rotational, S_IRUGO, vdisk_sysfs_rotational_show, NULL);
|
||||
static struct kobj_attribute vdisk_nv_cache_attr =
|
||||
@@ -455,6 +464,7 @@ static const struct attribute *vdisk_fileio_attrs[] = {
|
||||
&vdisk_rd_only_attr.attr,
|
||||
&vdisk_wt_attr.attr,
|
||||
&vdisk_tp_attr.attr,
|
||||
&vdisk_tst_attr.attr,
|
||||
&vdisk_rotational_attr.attr,
|
||||
&vdisk_nv_cache_attr.attr,
|
||||
&vdisk_o_direct_attr.attr,
|
||||
@@ -480,6 +490,7 @@ static const struct attribute *vdisk_blockio_attrs[] = {
|
||||
&vdisk_rd_only_attr.attr,
|
||||
&vdisk_wt_attr.attr,
|
||||
&vdisk_nv_cache_attr.attr,
|
||||
&vdisk_tst_attr.attr,
|
||||
&vdisk_removable_attr.attr,
|
||||
&vdisk_rotational_attr.attr,
|
||||
&vdisk_filename_attr.attr,
|
||||
@@ -501,6 +512,7 @@ static const struct attribute *vdisk_nullio_attrs[] = {
|
||||
&vdev_size_mb_rw_attr.attr,
|
||||
&vdisk_blocksize_attr.attr,
|
||||
&vdisk_rd_only_attr.attr,
|
||||
&vdisk_tst_attr.attr,
|
||||
&vdev_dummy_attr.attr,
|
||||
&vdisk_removable_attr.attr,
|
||||
&vdev_t10_vend_id_attr.attr,
|
||||
@@ -519,6 +531,7 @@ static const struct attribute *vcdrom_attrs[] = {
|
||||
&vdev_size_ro_attr.attr,
|
||||
&vdev_size_mb_ro_attr.attr,
|
||||
&vcdrom_filename_attr.attr,
|
||||
&vdisk_tst_attr.attr,
|
||||
&vdev_t10_vend_id_attr.attr,
|
||||
&vdev_vend_specific_id_attr.attr,
|
||||
&vdev_prod_id_attr.attr,
|
||||
@@ -589,6 +602,7 @@ static struct scst_dev_type vdisk_file_devtype = {
|
||||
"removable, "
|
||||
"rotational, "
|
||||
"thin_provisioned, "
|
||||
"tst, "
|
||||
"write_through, "
|
||||
"zero_copy",
|
||||
#endif
|
||||
@@ -634,6 +648,7 @@ static struct scst_dev_type vdisk_blk_devtype = {
|
||||
"removable, "
|
||||
"rotational, "
|
||||
"thin_provisioned, "
|
||||
"tst, "
|
||||
"write_through",
|
||||
#endif
|
||||
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
|
||||
@@ -675,7 +690,8 @@ static struct scst_dev_type vdisk_null_devtype = {
|
||||
"removable, "
|
||||
"rotational, "
|
||||
"size, "
|
||||
"size_mb",
|
||||
"size_mb, "
|
||||
"tst",
|
||||
#endif
|
||||
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
|
||||
.default_trace_flags = SCST_DEFAULT_DEV_LOG_FLAGS,
|
||||
@@ -711,7 +727,7 @@ static struct scst_dev_type vcdrom_devtype = {
|
||||
.add_device = vcdrom_add_device,
|
||||
.del_device = vcdrom_del_device,
|
||||
.dev_attrs = vcdrom_attrs,
|
||||
.add_device_parameters = NULL,
|
||||
.add_device_parameters = "tst",
|
||||
#endif
|
||||
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
|
||||
.default_trace_flags = SCST_DEFAULT_DEV_LOG_FLAGS,
|
||||
@@ -944,6 +960,262 @@ static struct scst_vdisk_dev *vdev_find(const char *name)
|
||||
return res;
|
||||
}
|
||||
|
||||
#define VDEV_WT_LABEL "WRITE_THROUGH"
|
||||
#define VDEV_MODE_PAGES_BUF_SIZE (64*1024)
|
||||
#define VDEV_MODE_PAGES_DIR "/var/lib/scst/vdev_mode_pages"
|
||||
|
||||
static int __vdev_save_mode_pages(const struct scst_vdisk_dev *virt_dev,
|
||||
uint8_t *buf, int size)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
if (virt_dev->wt_flag != DEF_WRITE_THROUGH) {
|
||||
res += scnprintf(&buf[res], size - res, "%s=%d\n",
|
||||
VDEV_WT_LABEL, virt_dev->wt_flag);
|
||||
if (res >= size-1)
|
||||
goto out_overflow;
|
||||
}
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
|
||||
out_overflow:
|
||||
PRINT_ERROR("Mode pages buffer overflow (size %d)", size);
|
||||
res = -EOVERFLOW;
|
||||
goto out;
|
||||
}
|
||||
|
||||
static int vdev_save_mode_pages(const struct scst_vdisk_dev *virt_dev)
|
||||
{
|
||||
int res, rc, offs;
|
||||
uint8_t *buf;
|
||||
int size;
|
||||
char *name, *name1;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
size = VDEV_MODE_PAGES_BUF_SIZE;
|
||||
|
||||
buf = vzalloc(size);
|
||||
if (buf == NULL) {
|
||||
PRINT_ERROR("Unable to alloc mode pages buffer (size %d)", size);
|
||||
res = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
name = kasprintf(GFP_KERNEL, "%s/%s", VDEV_MODE_PAGES_DIR, virt_dev->name);
|
||||
if (name == NULL) {
|
||||
PRINT_ERROR("Unable to create name %s/%s", VDEV_MODE_PAGES_DIR,
|
||||
virt_dev->name);
|
||||
res = -ENOMEM;
|
||||
goto out_vfree;
|
||||
}
|
||||
|
||||
name1 = kasprintf(GFP_KERNEL, "%s/%s1", VDEV_MODE_PAGES_DIR, virt_dev->name);
|
||||
if (name1 == NULL) {
|
||||
PRINT_ERROR("Unable to create name %s/%s1", VDEV_MODE_PAGES_DIR,
|
||||
virt_dev->name);
|
||||
res = -ENOMEM;
|
||||
goto out_free_name;
|
||||
}
|
||||
|
||||
offs = scst_save_global_mode_pages(virt_dev->dev, buf, size);
|
||||
if (offs < 0) {
|
||||
res = offs;
|
||||
goto out_free_name1;
|
||||
}
|
||||
|
||||
rc = __vdev_save_mode_pages(virt_dev, &buf[offs], size - offs);
|
||||
if (rc < 0) {
|
||||
res = rc;
|
||||
goto out_free_name1;
|
||||
}
|
||||
|
||||
offs += rc;
|
||||
if (offs == 0) {
|
||||
res = 0;
|
||||
scst_remove_file(name);
|
||||
scst_remove_file(name1);
|
||||
goto out_free_name1;
|
||||
}
|
||||
|
||||
res = scst_write_file_transactional(name, name1,
|
||||
virt_dev->name, strlen(virt_dev->name), buf, offs);
|
||||
|
||||
out_free_name1:
|
||||
kfree(name1);
|
||||
|
||||
out_free_name:
|
||||
kfree(name);
|
||||
|
||||
out_vfree:
|
||||
vfree(buf);
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int vdev_restore_wt(struct scst_vdisk_dev *virt_dev, unsigned int val)
|
||||
{
|
||||
int res;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
if (val > 1) {
|
||||
PRINT_ERROR("Invalid value %d for parameter %s (device %s)",
|
||||
val, VDEV_WT_LABEL, virt_dev->name);
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
virt_dev->wt_flag = val;
|
||||
virt_dev->wt_flag_saved = val;
|
||||
|
||||
PRINT_INFO("WT_FLAG restored to %d for vdev %s", virt_dev->wt_flag,
|
||||
virt_dev->name);
|
||||
|
||||
res = 0;
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Params are NULL-terminated */
|
||||
static int __vdev_load_mode_pages(struct scst_vdisk_dev *virt_dev, char *params)
|
||||
{
|
||||
int res;
|
||||
char *param, *p, *pp;
|
||||
unsigned long val;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
while (1) {
|
||||
param = scst_get_next_token_str(¶ms);
|
||||
if (param == NULL)
|
||||
break;
|
||||
|
||||
p = scst_get_next_lexem(¶m);
|
||||
if (*p == '\0')
|
||||
break;
|
||||
|
||||
pp = scst_get_next_lexem(¶m);
|
||||
if (*pp == '\0')
|
||||
goto out_need_param;
|
||||
|
||||
if (scst_get_next_lexem(¶m)[0] != '\0')
|
||||
goto out_too_many;
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
|
||||
res = kstrtoul(pp, 0, &val);
|
||||
#else
|
||||
res = strict_strtoul(pp, 0, &val);
|
||||
#endif
|
||||
if (res != 0)
|
||||
goto out_strtoul_failed;
|
||||
|
||||
if (strcasecmp(VDEV_WT_LABEL, p) == 0)
|
||||
res = vdev_restore_wt(virt_dev, val);
|
||||
else {
|
||||
TRACE_DBG("Unknown parameter %s", p);
|
||||
res = -EINVAL;
|
||||
break;
|
||||
}
|
||||
if (res != 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
res = 0;
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
|
||||
out_strtoul_failed:
|
||||
PRINT_ERROR("strtoul() for %s failed: %d (device %s)", pp, res,
|
||||
virt_dev->name);
|
||||
goto out;
|
||||
|
||||
out_need_param:
|
||||
PRINT_ERROR("Parameter %s value missed for device %s", p, virt_dev->name);
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
|
||||
out_too_many:
|
||||
PRINT_ERROR("Too many parameter's %s values (device %s)", p, virt_dev->name);
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
static int vdev_load_mode_pages(struct scst_vdisk_dev *virt_dev)
|
||||
{
|
||||
int res;
|
||||
struct scst_device *dev = virt_dev->dev;
|
||||
uint8_t *buf;
|
||||
int size;
|
||||
char *name, *name1, *params;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
size = VDEV_MODE_PAGES_BUF_SIZE;
|
||||
|
||||
buf = vzalloc(size);
|
||||
if (buf == NULL) {
|
||||
PRINT_ERROR("Unable to alloc mode pages buffer (size %d)", size);
|
||||
res = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
name = kasprintf(GFP_KERNEL, "%s/%s", VDEV_MODE_PAGES_DIR, virt_dev->name);
|
||||
if (name == NULL) {
|
||||
PRINT_ERROR("Unable to create name %s/%s", VDEV_MODE_PAGES_DIR,
|
||||
virt_dev->name);
|
||||
res = -ENOMEM;
|
||||
goto out_vfree;
|
||||
}
|
||||
|
||||
name1 = kasprintf(GFP_KERNEL, "%s/%s1", VDEV_MODE_PAGES_DIR, virt_dev->name);
|
||||
if (name1 == NULL) {
|
||||
PRINT_ERROR("Unable to create name %s/%s1", VDEV_MODE_PAGES_DIR,
|
||||
virt_dev->name);
|
||||
res = -ENOMEM;
|
||||
goto out_free_name;
|
||||
}
|
||||
|
||||
size = scst_read_file_transactional(name, name1,
|
||||
virt_dev->name, strlen(virt_dev->name), buf, size-1);
|
||||
if (size <= 0) {
|
||||
res = size;
|
||||
goto out_free_name1;
|
||||
}
|
||||
|
||||
buf[size-1] = '\0';
|
||||
|
||||
res = scst_restore_global_mode_pages(dev, &buf[strlen(virt_dev->name)+1],
|
||||
¶ms);
|
||||
if ((res != 0) || (params == NULL))
|
||||
goto out_free_name1;
|
||||
|
||||
res = __vdev_load_mode_pages(virt_dev, params);
|
||||
|
||||
out_free_name1:
|
||||
kfree(name1);
|
||||
|
||||
out_free_name:
|
||||
kfree(name);
|
||||
|
||||
out_vfree:
|
||||
vfree(buf);
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int vdisk_attach(struct scst_device *dev)
|
||||
{
|
||||
int res = 0;
|
||||
@@ -1021,14 +1293,25 @@ static int vdisk_attach(struct scst_device *dev)
|
||||
|
||||
dev->dh_priv = virt_dev;
|
||||
|
||||
dev->tst = DEF_TST;
|
||||
dev->tst = virt_dev->tst;
|
||||
dev->d_sense = DEF_DSENSE;
|
||||
dev->d_sense_saved = DEF_DSENSE;
|
||||
dev->d_sense_default = DEF_DSENSE;
|
||||
if (virt_dev->wt_flag && !virt_dev->nv_cache)
|
||||
dev->queue_alg = DEF_QUEUE_ALG_WT;
|
||||
else
|
||||
dev->queue_alg = DEF_QUEUE_ALG;
|
||||
dev->queue_alg_saved = dev->queue_alg;
|
||||
dev->queue_alg_default = dev->queue_alg;
|
||||
dev->swp = DEF_SWP;
|
||||
dev->swp_saved = DEF_SWP;
|
||||
dev->swp_default = DEF_SWP;
|
||||
dev->tas = DEF_TAS;
|
||||
dev->tas_saved = DEF_TAS;
|
||||
dev->tas_default = DEF_TAS;
|
||||
|
||||
if (vdev_saved_mode_pages_enabled)
|
||||
vdev_load_mode_pages(virt_dev);
|
||||
|
||||
out:
|
||||
TRACE_EXIT();
|
||||
@@ -3383,22 +3666,47 @@ static int vdisk_format_pg(unsigned char *p, int pcontrol,
|
||||
static int vdisk_caching_pg(unsigned char *p, int pcontrol,
|
||||
struct scst_vdisk_dev *virt_dev)
|
||||
{ /* Caching page for mode_sense */
|
||||
const unsigned char caching_pg[] = {0x8, 0x12, 0x0, 0, 0, 0, 0, 0,
|
||||
unsigned char caching_pg[] = {0x8, 0x12, 0x0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
memcpy(p, caching_pg, sizeof(caching_pg));
|
||||
p[2] |= !(virt_dev->wt_flag || virt_dev->nv_cache) ? WCE : 0;
|
||||
if (1 == pcontrol)
|
||||
if (!virt_dev->nv_cache && vdev_saved_mode_pages_enabled)
|
||||
caching_pg[0] |= 0x80;
|
||||
|
||||
switch (pcontrol) {
|
||||
case 0: /* current */
|
||||
memcpy(p, caching_pg, sizeof(caching_pg));
|
||||
p[2] |= (virt_dev->wt_flag || virt_dev->nv_cache) ? 0 : WCE;
|
||||
break;
|
||||
case 1: /* changeable */
|
||||
memset(p + 2, 0, sizeof(caching_pg) - 2);
|
||||
if (!virt_dev->nv_cache)
|
||||
p[2] |= WCE;
|
||||
break;
|
||||
case 2: /* default */
|
||||
memcpy(p, caching_pg, sizeof(caching_pg));
|
||||
p[2] |= (DEF_WRITE_THROUGH || virt_dev->nv_cache) ? 0: WCE;
|
||||
break;
|
||||
case 3: /* saved */
|
||||
memcpy(p, caching_pg, sizeof(caching_pg));
|
||||
p[2] |= (virt_dev->wt_flag_saved || virt_dev->nv_cache) ? 0: WCE;
|
||||
break;
|
||||
default:
|
||||
sBUG_ON(1);
|
||||
break;
|
||||
}
|
||||
|
||||
return sizeof(caching_pg);
|
||||
}
|
||||
|
||||
static int vdisk_ctrl_m_pg(unsigned char *p, int pcontrol,
|
||||
struct scst_vdisk_dev *virt_dev)
|
||||
{ /* Control mode page for mode_sense */
|
||||
const unsigned char ctrl_m_pg[] = {0xa, 0xa, 0, 0, 0, 0, 0, 0,
|
||||
unsigned char ctrl_m_pg[] = {0xa, 0xa, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0x2, 0x4b};
|
||||
|
||||
if (vdev_saved_mode_pages_enabled)
|
||||
ctrl_m_pg[0] |= 0x80;
|
||||
|
||||
memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
|
||||
switch (pcontrol) {
|
||||
case 0: /* current */
|
||||
@@ -3411,27 +3719,31 @@ static int vdisk_ctrl_m_pg(unsigned char *p, int pcontrol,
|
||||
case 1: /* changeable */
|
||||
memset(p + 2, 0, sizeof(ctrl_m_pg) - 2);
|
||||
#if 0 /*
|
||||
* It's too early to implement it, since we can't control the
|
||||
* backstorage device parameters. ToDo
|
||||
* See comment in struct scst_device definition.
|
||||
*
|
||||
* If enable it, fix the default and saved cases below!
|
||||
*/
|
||||
p[2] |= 7 << 5; /* TST */
|
||||
p[3] |= 0xF << 4; /* QUEUE ALGORITHM MODIFIER */
|
||||
#endif
|
||||
p[2] |= 1 << 2; /* D_SENSE */
|
||||
p[3] |= 0xF << 4; /* QUEUE ALGORITHM MODIFIER */
|
||||
p[4] |= 1 << 3; /* SWP */
|
||||
p[5] |= 1 << 6; /* TAS */
|
||||
break;
|
||||
case 2: /* default */
|
||||
p[2] |= DEF_TST << 5;
|
||||
p[2] |= DEF_DSENSE << 2;
|
||||
if (virt_dev->wt_flag || virt_dev->nv_cache)
|
||||
p[3] |= DEF_QUEUE_ALG_WT << 4;
|
||||
else
|
||||
p[3] |= DEF_QUEUE_ALG << 4;
|
||||
p[4] |= DEF_SWP << 3;
|
||||
p[5] |= DEF_TAS << 6;
|
||||
p[2] |= virt_dev->tst << 5;
|
||||
p[2] |= virt_dev->dev->d_sense_default << 2;
|
||||
p[3] |= virt_dev->dev->queue_alg_default << 4;
|
||||
p[4] |= virt_dev->dev->swp_default << 3;
|
||||
p[5] |= virt_dev->dev->tas_default << 6;
|
||||
break;
|
||||
case 3: /* saved */
|
||||
p[2] |= virt_dev->dev->tst << 5;
|
||||
p[2] |= virt_dev->dev->d_sense_saved << 2;
|
||||
p[3] |= virt_dev->dev->queue_alg_saved << 4;
|
||||
p[4] |= virt_dev->dev->swp_saved << 3;
|
||||
p[5] |= virt_dev->dev->tas_saved << 6;
|
||||
break;
|
||||
case 3: /* saved, blocked by the caller */
|
||||
default:
|
||||
sBUG();
|
||||
}
|
||||
@@ -3491,7 +3803,7 @@ static enum compl_status_e vdisk_exec_mode_sense(struct vdisk_cmd_params *p)
|
||||
if (unlikely(length <= 0))
|
||||
goto out_free;
|
||||
|
||||
if (0x3 == pcontrol) {
|
||||
if (!vdev_saved_mode_pages_enabled && (0x3 == pcontrol)) {
|
||||
TRACE_DBG("%s", "MODE SENSE: Saving values not supported");
|
||||
scst_set_cmd_error(cmd,
|
||||
SCST_LOAD_SENSE(scst_sense_saving_params_unsup));
|
||||
@@ -3648,31 +3960,119 @@ out:
|
||||
}
|
||||
|
||||
static void vdisk_ctrl_m_pg_select(unsigned char *p,
|
||||
struct scst_vdisk_dev *virt_dev, struct scst_cmd *cmd)
|
||||
struct scst_vdisk_dev *virt_dev, struct scst_cmd *cmd, bool save)
|
||||
{
|
||||
struct scst_device *dev = virt_dev->dev;
|
||||
int old_swp = dev->swp, old_tas = dev->tas, old_dsense = dev->d_sense;
|
||||
int old_queue_alg = dev->queue_alg;
|
||||
int rc;
|
||||
|
||||
#if 0 /* Not implemented yet, see comment in vdisk_ctrl_m_pg() */
|
||||
dev->tst = (p[2] >> 5) & 1;
|
||||
dev->queue_alg = p[3] >> 4;
|
||||
#else
|
||||
if ((dev->tst != ((p[2] >> 5) & 1)) || (dev->queue_alg != (p[3] >> 4))) {
|
||||
TRACE(TRACE_MINOR|TRACE_SCSI, "%s", "MODE SELECT: Changing of "
|
||||
"TST and QUEUE ALGORITHM not supported");
|
||||
TRACE_ENTRY();
|
||||
|
||||
if (save && !vdev_saved_mode_pages_enabled) {
|
||||
TRACE(TRACE_MINOR|TRACE_SCSI, "MODE SELECT: saved control page "
|
||||
"not supported");
|
||||
scst_set_cmd_error(cmd,
|
||||
SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb));
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
#if 0 /* Not implemented yet, see comment in struct scst_device */
|
||||
dev->tst = (p[2] >> 5) & 1;
|
||||
#else
|
||||
if (dev->tst != ((p[2] >> 5) & 1)) {
|
||||
TRACE(TRACE_MINOR|TRACE_SCSI, "%s", "MODE SELECT: Changing of "
|
||||
"TST not supported");
|
||||
scst_set_cmd_error(cmd,
|
||||
SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb));
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
dev->queue_alg = p[3] >> 4;
|
||||
dev->swp = (p[4] & 0x8) >> 3;
|
||||
dev->tas = (p[5] & 0x40) >> 6;
|
||||
dev->d_sense = (p[2] & 0x4) >> 2;
|
||||
|
||||
if ((dev->swp == old_swp) && (dev->tas == old_tas) &&
|
||||
(dev->d_sense == old_dsense) && (dev->queue_alg == old_queue_alg))
|
||||
goto out;
|
||||
|
||||
if (!save)
|
||||
goto out_ok;
|
||||
|
||||
rc = vdev_save_mode_pages(virt_dev);
|
||||
if (rc != 0) {
|
||||
dev->swp = old_swp;
|
||||
dev->tas = old_tas;
|
||||
dev->d_sense = old_dsense;
|
||||
dev->queue_alg = old_queue_alg;
|
||||
/* Hopefully, the error is temporary */
|
||||
scst_set_busy(cmd);
|
||||
goto out;
|
||||
}
|
||||
|
||||
dev->swp_saved = dev->swp;
|
||||
dev->tas_saved = dev->tas;
|
||||
dev->d_sense_saved = dev->d_sense;
|
||||
dev->queue_alg_saved = dev->queue_alg;
|
||||
|
||||
out_ok:
|
||||
PRINT_INFO("Device %s: new control mode page parameters: SWP %x "
|
||||
"(was %x), TAS %x (was %x), D_SENSE %d (was %d)",
|
||||
virt_dev->name, dev->swp, old_swp, dev->tas, old_tas,
|
||||
dev->d_sense, old_dsense);
|
||||
"(was %x), TAS %x (was %x), D_SENSE %d (was %d), "
|
||||
"QUEUE ALG %d (was %d)", virt_dev->name, dev->swp,
|
||||
old_swp, dev->tas, old_tas, dev->d_sense, old_dsense,
|
||||
dev->queue_alg, old_queue_alg);
|
||||
|
||||
out:
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
|
||||
static void vdisk_caching_m_pg_select(unsigned char *p,
|
||||
struct scst_vdisk_dev *virt_dev, struct scst_cmd *cmd, bool save,
|
||||
bool read_only)
|
||||
{
|
||||
int old_wt = virt_dev->wt_flag, new_wt, rc;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
if (save && (!vdev_saved_mode_pages_enabled || virt_dev->nv_cache)) {
|
||||
TRACE(TRACE_MINOR|TRACE_SCSI, "MODE SELECT: saved cache page "
|
||||
"not supported");
|
||||
scst_set_cmd_error(cmd,
|
||||
SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb));
|
||||
goto out;
|
||||
}
|
||||
|
||||
new_wt = (p[2] & WCE) ? 0 : 1;
|
||||
|
||||
if (new_wt == old_wt)
|
||||
goto out;
|
||||
|
||||
if (vdisk_set_wt(virt_dev, new_wt, read_only) != 0) {
|
||||
scst_set_busy(cmd);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!save)
|
||||
goto out_ok;
|
||||
|
||||
rc = vdev_save_mode_pages(virt_dev);
|
||||
if (rc != 0) {
|
||||
vdisk_set_wt(virt_dev, old_wt, read_only);
|
||||
/* Hopefully, the error is temporary */
|
||||
scst_set_busy(cmd);
|
||||
goto out;
|
||||
}
|
||||
|
||||
virt_dev->wt_flag_saved = virt_dev->wt_flag;
|
||||
|
||||
out_ok:
|
||||
PRINT_INFO("Device %s: new wt_flag: %x (was %x)", virt_dev->name,
|
||||
virt_dev->wt_flag, old_wt);
|
||||
|
||||
out:
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3694,10 +4094,9 @@ static enum compl_status_e vdisk_exec_mode_select(struct vdisk_cmd_params *p)
|
||||
if (unlikely(length <= 0))
|
||||
goto out;
|
||||
|
||||
if (!(cmd->cdb[1] & PF) || (cmd->cdb[1] & SP)) {
|
||||
if (!(cmd->cdb[1] & PF)) {
|
||||
TRACE(TRACE_MINOR|TRACE_SCSI, "MODE SELECT: Unsupported "
|
||||
"value(s) of PF and/or SP bits (cdb[1]=%x)",
|
||||
cmd->cdb[1]);
|
||||
"PF bit zero (cdb[1]=%x)", cmd->cdb[1]);
|
||||
scst_set_invalid_field_in_cdb(cmd, 1, 0);
|
||||
goto out_put;
|
||||
}
|
||||
@@ -3730,11 +4129,8 @@ static enum compl_status_e vdisk_exec_mode_select(struct vdisk_cmd_params *p)
|
||||
scst_set_invalid_field_in_parm_list(cmd, offset+1, 0);
|
||||
goto out_put;
|
||||
}
|
||||
if (vdisk_set_wt(virt_dev, (address[offset + 2] & WCE) ? 0 : 1,
|
||||
cmd->tgt_dev->tgt_dev_rd_only) != 0) {
|
||||
scst_set_busy(cmd);
|
||||
goto out_put;
|
||||
}
|
||||
vdisk_caching_m_pg_select(&address[offset], virt_dev,
|
||||
cmd, cmd->cdb[1] & SP, cmd->tgt_dev->tgt_dev_rd_only);
|
||||
break;
|
||||
} else if ((address[offset] & 0x3f) == 0xA) {
|
||||
/* Control page */
|
||||
@@ -3744,7 +4140,8 @@ static enum compl_status_e vdisk_exec_mode_select(struct vdisk_cmd_params *p)
|
||||
scst_set_invalid_field_in_parm_list(cmd, offset+1, 0);
|
||||
goto out_put;
|
||||
}
|
||||
vdisk_ctrl_m_pg_select(&address[offset], virt_dev, cmd);
|
||||
vdisk_ctrl_m_pg_select(&address[offset], virt_dev, cmd,
|
||||
cmd->cdb[1] & SP);
|
||||
} else {
|
||||
TRACE(TRACE_MINOR, "MODE SELECT: Invalid request %x",
|
||||
address[offset] & 0x3f);
|
||||
@@ -5220,15 +5617,12 @@ static void vdisk_task_mgmt_fn_done(struct scst_mgmt_cmd *mcmd,
|
||||
struct scst_vdisk_dev *virt_dev = dev->dh_priv;
|
||||
int rc;
|
||||
|
||||
dev->tst = DEF_TST;
|
||||
dev->d_sense = DEF_DSENSE;
|
||||
dev->swp = DEF_SWP;
|
||||
dev->tas = DEF_TAS;
|
||||
dev->d_sense = dev->d_sense_saved;
|
||||
dev->swp = dev->swp_saved;
|
||||
dev->tas = dev->tas_saved;
|
||||
dev->queue_alg = dev->queue_alg_saved;
|
||||
|
||||
if (virt_dev->wt_flag && !virt_dev->nv_cache)
|
||||
dev->queue_alg = DEF_QUEUE_ALG_WT;
|
||||
else
|
||||
dev->queue_alg = DEF_QUEUE_ALG;
|
||||
dev->tst = virt_dev->tst;
|
||||
|
||||
rc = vdisk_set_wt(virt_dev, DEF_WRITE_THROUGH,
|
||||
tgt_dev->tgt_dev_rd_only);
|
||||
@@ -5288,6 +5682,10 @@ static void vdisk_report_registering(const struct scst_vdisk_dev *virt_dev)
|
||||
i += snprintf(&buf[i], sizeof(buf) - i, "%sREMOVABLE",
|
||||
(j == i) ? "(" : ", ");
|
||||
|
||||
if (virt_dev->tst != DEF_TST)
|
||||
i += snprintf(&buf[i], sizeof(buf) - i, "%sTST %d",
|
||||
(j == i) ? "(" : ", ", virt_dev->tst);
|
||||
|
||||
if (virt_dev->rotational)
|
||||
i += snprintf(&buf[i], sizeof(buf) - i, "%sROTATIONAL",
|
||||
(j == i) ? "(" : ", ");
|
||||
@@ -5383,6 +5781,7 @@ static int vdev_create(struct scst_dev_type *devt,
|
||||
virt_dev->removable = DEF_REMOVABLE;
|
||||
virt_dev->rotational = DEF_ROTATIONAL;
|
||||
virt_dev->thin_provisioned = DEF_THIN_PROVISIONED;
|
||||
virt_dev->tst = DEF_TST;
|
||||
|
||||
virt_dev->blk_shift = DEF_DISK_BLOCK_SHIFT;
|
||||
|
||||
@@ -5571,6 +5970,15 @@ static int vdev_parse_add_dev_params(struct scst_vdisk_dev *virt_dev,
|
||||
} else if (!strcasecmp("rotational", p)) {
|
||||
virt_dev->rotational = val;
|
||||
TRACE_DBG("ROTATIONAL %d", virt_dev->rotational);
|
||||
} else if (!strcasecmp("tst", p)) {
|
||||
if ((val != SCST_TST_0_SINGLE_TASK_SET) &&
|
||||
(val != SCST_TST_1_SEP_TASK_SETS)) {
|
||||
PRINT_ERROR("Invalid TST value %d", (int)val);
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
virt_dev->tst = val;
|
||||
TRACE_DBG("TST %d", virt_dev->tst);
|
||||
} else if (!strcasecmp("thin_provisioned", p)) {
|
||||
virt_dev->thin_provisioned = val;
|
||||
virt_dev->thin_provisioned_manually_set = 1;
|
||||
@@ -5676,7 +6084,7 @@ static int vdev_blockio_add_device(const char *device_name, char *params)
|
||||
int res = 0;
|
||||
const char *const allowed_params[] = { "filename", "read_only", "write_through",
|
||||
"removable", "blocksize", "nv_cache",
|
||||
"rotational", "thin_provisioned", NULL };
|
||||
"rotational", "thin_provisioned", "tst", NULL };
|
||||
struct scst_vdisk_dev *virt_dev;
|
||||
|
||||
TRACE_ENTRY();
|
||||
@@ -5734,7 +6142,7 @@ static int vdev_nullio_add_device(const char *device_name, char *params)
|
||||
int res = 0;
|
||||
static const char *const allowed_params[] = {
|
||||
"read_only", "dummy", "removable", "blocksize", "rotational",
|
||||
"size", "size_mb", NULL
|
||||
"size", "size_mb", "tst", NULL
|
||||
};
|
||||
struct scst_vdisk_dev *virt_dev;
|
||||
|
||||
@@ -5891,7 +6299,7 @@ out:
|
||||
static ssize_t __vcdrom_add_device(const char *device_name, char *params)
|
||||
{
|
||||
int res = 0;
|
||||
const char *allowed_params[] = { NULL }; /* no params */
|
||||
const char *allowed_params[] = { "tst", NULL };
|
||||
struct scst_vdisk_dev *virt_dev;
|
||||
|
||||
TRACE_ENTRY();
|
||||
@@ -6462,6 +6870,27 @@ static ssize_t vdisk_sysfs_removable_show(struct kobject *kobj,
|
||||
return pos;
|
||||
}
|
||||
|
||||
static ssize_t vdisk_sysfs_tst_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
int pos = 0;
|
||||
struct scst_device *dev;
|
||||
struct scst_vdisk_dev *virt_dev;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
dev = container_of(kobj, struct scst_device, dev_kobj);
|
||||
virt_dev = dev->dh_priv;
|
||||
|
||||
pos = sprintf(buf, "%d\n", virt_dev->tst);
|
||||
|
||||
if (virt_dev->tst != DEF_TST)
|
||||
pos += sprintf(&buf[pos], "%s\n", SCST_SYSFS_KEY_MARK);
|
||||
|
||||
TRACE_EXIT_RES(pos);
|
||||
return pos;
|
||||
}
|
||||
|
||||
static ssize_t vdisk_sysfs_rotational_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
@@ -7848,6 +8277,46 @@ static void init_ops(vdisk_op_fn *ops, int count)
|
||||
return;
|
||||
}
|
||||
|
||||
static int __init vdev_check_mode_pages_path(void)
|
||||
{
|
||||
int res;
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
|
||||
struct nameidata nd;
|
||||
#else
|
||||
struct path path;
|
||||
#endif
|
||||
mm_segment_t old_fs = get_fs();
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
set_fs(KERNEL_DS);
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
|
||||
res = path_lookup(VDEV_MODE_PAGES_DIR, 0, &nd);
|
||||
if (res == 0)
|
||||
scst_path_put(&nd);
|
||||
#else
|
||||
res = kern_path(VDEV_MODE_PAGES_DIR, 0, &path);
|
||||
if (res == 0)
|
||||
path_put(&path);
|
||||
#endif
|
||||
if (res != 0) {
|
||||
PRINT_WARNING("Unable to find %s (err %d), saved mode pages "
|
||||
"disabled. You should create this directory manually "
|
||||
"or reinstall SCST", VDEV_MODE_PAGES_DIR, res);
|
||||
vdev_saved_mode_pages_enabled = false;
|
||||
goto out_setfs;
|
||||
}
|
||||
|
||||
out_setfs:
|
||||
set_fs(old_fs);
|
||||
|
||||
res = 0; /* always succeed */
|
||||
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int __init init_scst_vdisk_driver(void)
|
||||
{
|
||||
int res;
|
||||
@@ -7856,6 +8325,10 @@ static int __init init_scst_vdisk_driver(void)
|
||||
init_ops(blockio_ops, ARRAY_SIZE(blockio_ops));
|
||||
init_ops(nullio_ops, ARRAY_SIZE(nullio_ops));
|
||||
|
||||
res = vdev_check_mode_pages_path();
|
||||
if (res != 0)
|
||||
goto out;
|
||||
|
||||
vdisk_cmd_param_cachep = KMEM_CACHE(vdisk_cmd_params,
|
||||
SCST_SLAB_FLAGS|SLAB_HWCACHE_ALIGN);
|
||||
if (vdisk_cmd_param_cachep == NULL) {
|
||||
|
||||
@@ -3676,7 +3676,7 @@ int scst_alloc_device(gfp_t gfp_mask, struct scst_device **out_dev)
|
||||
INIT_LIST_HEAD(&dev->dev_tgt_dev_list);
|
||||
INIT_LIST_HEAD(&dev->dev_acg_dev_list);
|
||||
dev->dev_double_ua_possible = 1;
|
||||
dev->queue_alg = SCST_CONTR_MODE_QUEUE_ALG_UNRESTRICTED_REORDER;
|
||||
dev->queue_alg = SCST_QUEUE_ALG_1_UNRESTRICTED_REORDER;
|
||||
|
||||
mutex_init(&dev->dev_pr_mutex);
|
||||
dev->pr_generation = 0;
|
||||
@@ -4422,7 +4422,7 @@ static int scst_alloc_add_tgt_dev(struct scst_session *sess,
|
||||
INIT_LIST_HEAD(&tgt_dev->UA_list);
|
||||
|
||||
scst_init_order_data(&tgt_dev->tgt_dev_order_data);
|
||||
if (dev->tst == SCST_CONTR_MODE_SEP_TASK_SETS)
|
||||
if (dev->tst == SCST_TST_1_SEP_TASK_SETS)
|
||||
tgt_dev->curr_order_data = &tgt_dev->tgt_dev_order_data;
|
||||
else
|
||||
tgt_dev->curr_order_data = &dev->dev_order_data;
|
||||
@@ -8738,7 +8738,7 @@ int scst_obtain_device_parameters(struct scst_device *dev,
|
||||
|
||||
dev->tst = buffer[4+2] >> 5;
|
||||
q = buffer[4+3] >> 4;
|
||||
if (q > SCST_CONTR_MODE_QUEUE_ALG_UNRESTRICTED_REORDER) {
|
||||
if (q > SCST_QUEUE_ALG_1_UNRESTRICTED_REORDER) {
|
||||
PRINT_ERROR("Too big QUEUE ALG %x, dev %s",
|
||||
dev->queue_alg, dev->virt_name);
|
||||
}
|
||||
@@ -9266,6 +9266,245 @@ static void scst_free_descriptors(struct scst_cmd *cmd)
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
** We currently have only few saved parameters and it is impossible to get
|
||||
** pointer on a bit field, so let's have a simple straightforward
|
||||
** implementation.
|
||||
**/
|
||||
|
||||
#define SCST_TAS_LABEL "TAS"
|
||||
#define SCST_SWP_LABEL "SWP"
|
||||
#define SCST_DSENSE_LABEL "D_SENSE"
|
||||
#define SCST_QUEUE_ALG_LABEL "QUEUE_ALG"
|
||||
|
||||
int scst_save_global_mode_pages(const struct scst_device *dev,
|
||||
uint8_t *buf, int size)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
if (dev->tas != dev->tas_default) {
|
||||
res += scnprintf(&buf[res], size - res, "%s=%d\n",
|
||||
SCST_TAS_LABEL, dev->tas);
|
||||
if (res >= size-1)
|
||||
goto out_overflow;
|
||||
}
|
||||
|
||||
if (dev->swp != dev->swp_default) {
|
||||
res += scnprintf(&buf[res], size - res, "%s=%d\n",
|
||||
SCST_SWP_LABEL, dev->swp);
|
||||
if (res >= size-1)
|
||||
goto out_overflow;
|
||||
}
|
||||
|
||||
if (dev->d_sense != dev->d_sense_default) {
|
||||
res += scnprintf(&buf[res], size - res, "%s=%d\n",
|
||||
SCST_DSENSE_LABEL, dev->d_sense);
|
||||
if (res >= size-1)
|
||||
goto out_overflow;
|
||||
}
|
||||
|
||||
if (dev->queue_alg != dev->queue_alg_default) {
|
||||
res += scnprintf(&buf[res], size - res, "%s=%d\n",
|
||||
SCST_QUEUE_ALG_LABEL, dev->queue_alg);
|
||||
if (res >= size-1)
|
||||
goto out_overflow;
|
||||
}
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
|
||||
out_overflow:
|
||||
PRINT_ERROR("Global mode pages buffer overflow (size %d)", size);
|
||||
res = -EOVERFLOW;
|
||||
goto out;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scst_save_global_mode_pages);
|
||||
|
||||
static int scst_restore_tas(struct scst_device *dev, unsigned int val)
|
||||
{
|
||||
int res;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
if (val > 1) {
|
||||
PRINT_ERROR("Invalid value %d for parameter %s (device %s)",
|
||||
val, SCST_TAS_LABEL, dev->virt_name);
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
dev->tas = val;
|
||||
dev->tas_saved = val;
|
||||
|
||||
PRINT_INFO("%s restored to %d for device %s", SCST_TAS_LABEL,
|
||||
dev->tas, dev->virt_name);
|
||||
|
||||
res = 0;
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int scst_restore_swp(struct scst_device *dev, unsigned int val)
|
||||
{
|
||||
int res;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
if (val > 1) {
|
||||
PRINT_ERROR("Invalid value %d for parameter %s (device %s)",
|
||||
val, SCST_SWP_LABEL, dev->virt_name);
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
dev->swp = val;
|
||||
dev->swp_saved = val;
|
||||
|
||||
PRINT_INFO("%s restored to %d for device %s", SCST_SWP_LABEL,
|
||||
dev->swp, dev->virt_name);
|
||||
|
||||
res = 0;
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int scst_restore_dsense(struct scst_device *dev, unsigned int val)
|
||||
{
|
||||
int res;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
if (val > 1) {
|
||||
PRINT_ERROR("Invalid value %d for parameter %s (device %s)",
|
||||
val, SCST_DSENSE_LABEL, dev->virt_name);
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
dev->d_sense = val;
|
||||
dev->d_sense_saved = val;
|
||||
|
||||
PRINT_INFO("%s restored to %d for device %s", SCST_DSENSE_LABEL,
|
||||
dev->d_sense, dev->virt_name);
|
||||
|
||||
res = 0;
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int scst_restore_queue_alg(struct scst_device *dev, unsigned int val)
|
||||
{
|
||||
int res;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
if ((val != SCST_QUEUE_ALG_0_RESTRICTED_REORDER) &&
|
||||
(val != SCST_QUEUE_ALG_1_UNRESTRICTED_REORDER)) {
|
||||
PRINT_ERROR("Invalid value %d for parameter %s (device %s)",
|
||||
val, SCST_QUEUE_ALG_LABEL, dev->virt_name);
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
dev->queue_alg = val;
|
||||
dev->queue_alg_saved = val;
|
||||
|
||||
PRINT_INFO("%s restored to %d for device %s", SCST_QUEUE_ALG_LABEL,
|
||||
dev->queue_alg, dev->virt_name);
|
||||
|
||||
res = 0;
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Params are NULL-terminated */
|
||||
int scst_restore_global_mode_pages(struct scst_device *dev, char *params,
|
||||
char **last_param)
|
||||
{
|
||||
int res;
|
||||
char *param, *p, *pp;
|
||||
unsigned long val;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
while (1) {
|
||||
param = scst_get_next_token_str(¶ms);
|
||||
if (param == NULL)
|
||||
break;
|
||||
|
||||
p = scst_get_next_lexem(¶m);
|
||||
if (*p == '\0')
|
||||
break;
|
||||
|
||||
pp = scst_get_next_lexem(¶m);
|
||||
if (*pp == '\0')
|
||||
goto out_need_param;
|
||||
|
||||
if (scst_get_next_lexem(¶m)[0] != '\0')
|
||||
goto out_too_many;
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
|
||||
res = kstrtoul(pp, 0, &val);
|
||||
#else
|
||||
res = strict_strtoul(pp, 0, &val);
|
||||
#endif
|
||||
if (res != 0)
|
||||
goto out_strtoul_failed;
|
||||
|
||||
if (strcasecmp(SCST_TAS_LABEL, p) == 0)
|
||||
res = scst_restore_tas(dev, val);
|
||||
else if (strcasecmp(SCST_SWP_LABEL, p) == 0)
|
||||
res = scst_restore_swp(dev, val);
|
||||
else if (strcasecmp(SCST_DSENSE_LABEL, p) == 0)
|
||||
res = scst_restore_dsense(dev, val);
|
||||
else if (strcasecmp(SCST_QUEUE_ALG_LABEL, p) == 0)
|
||||
res = scst_restore_queue_alg(dev, val);
|
||||
else {
|
||||
TRACE_DBG("Unknown parameter %s", p);
|
||||
scst_restore_token_str(p, param);
|
||||
*last_param = p;
|
||||
goto out;
|
||||
}
|
||||
if (res != 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
*last_param = NULL;
|
||||
res = 0;
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
|
||||
out_strtoul_failed:
|
||||
PRINT_ERROR("strtoul() for %s failed: %d (device %s)", pp, res,
|
||||
dev->virt_name);
|
||||
goto out;
|
||||
|
||||
out_need_param:
|
||||
PRINT_ERROR("Parameter %s value missed for device %s", p, dev->virt_name);
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
|
||||
out_too_many:
|
||||
PRINT_ERROR("Too many parameter's %s values (device %s)", p, dev->virt_name);
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scst_restore_global_mode_pages);
|
||||
|
||||
|
||||
/* Abstract vfs_unlink() for different kernel versions (as possible) */
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
|
||||
void scst_vfs_unlink_and_put(struct nameidata *nd)
|
||||
@@ -9450,6 +9689,195 @@ int scst_remove_file(const char *name)
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scst_remove_file);
|
||||
|
||||
/* Returns 0 on success, error code otherwise */
|
||||
int scst_write_file_transactional(const char *name, const char *name1,
|
||||
const char *signature, int signature_len, const uint8_t *buf, int size)
|
||||
{
|
||||
int res;
|
||||
struct file *file;
|
||||
mm_segment_t old_fs = get_fs();
|
||||
loff_t pos = 0;
|
||||
char n = '\n';
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
res = scst_copy_file(name, name1);
|
||||
if ((res != 0) && (res != -ENOENT))
|
||||
goto out;
|
||||
|
||||
set_fs(KERNEL_DS);
|
||||
|
||||
file = filp_open(name, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
if (IS_ERR(file)) {
|
||||
res = PTR_ERR(file);
|
||||
PRINT_ERROR("Unable to (re)create file '%s' - error %d",
|
||||
name, res);
|
||||
goto out_set_fs;
|
||||
}
|
||||
|
||||
TRACE_DBG("Writing file '%s'", name);
|
||||
|
||||
pos = signature_len+1;
|
||||
|
||||
res = vfs_write(file, (void __force __user *)buf, size, &pos);
|
||||
if (res != size)
|
||||
goto write_error;
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
|
||||
res = scst_vfs_fsync(file, 0, pos);
|
||||
#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
|
||||
res = vfs_fsync(file, file->f_path.dentry, 1);
|
||||
#else
|
||||
res = vfs_fsync(file, 1);
|
||||
#endif
|
||||
if (res != 0) {
|
||||
PRINT_ERROR("fsync() of file %s failed: %d", name, res);
|
||||
goto write_error_close;
|
||||
}
|
||||
|
||||
pos = 0;
|
||||
res = vfs_write(file, (void __force __user *)signature, signature_len, &pos);
|
||||
if (res != signature_len)
|
||||
goto write_error;
|
||||
|
||||
res = vfs_write(file, (void __force __user *)&n, sizeof(n), &pos);
|
||||
if (res != sizeof(n))
|
||||
goto write_error;
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
|
||||
res = scst_vfs_fsync(file, 0, sizeof(signature));
|
||||
#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
|
||||
res = vfs_fsync(file, file->f_path.dentry, 1);
|
||||
#else
|
||||
res = vfs_fsync(file, 1);
|
||||
#endif
|
||||
if (res != 0) {
|
||||
PRINT_ERROR("fsync() of file %s failed: %d", name, res);
|
||||
goto write_error_close;
|
||||
}
|
||||
|
||||
res = 0;
|
||||
|
||||
filp_close(file, NULL);
|
||||
|
||||
out_set_fs:
|
||||
set_fs(old_fs);
|
||||
|
||||
if (res == 0)
|
||||
scst_remove_file(name1);
|
||||
else
|
||||
scst_remove_file(name);
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
|
||||
write_error:
|
||||
PRINT_ERROR("Error writing to '%s' - error %d", name, res);
|
||||
|
||||
write_error_close:
|
||||
filp_close(file, NULL);
|
||||
if (res > 0)
|
||||
res = -EIO;
|
||||
goto out_set_fs;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scst_write_file_transactional);
|
||||
|
||||
static int __scst_read_file_transactional(const char *file_name,
|
||||
const char *signature, int signature_len, uint8_t *buf, int size)
|
||||
{
|
||||
int res;
|
||||
struct file *file = NULL;
|
||||
struct inode *inode;
|
||||
loff_t file_size, pos;
|
||||
mm_segment_t old_fs;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
old_fs = get_fs();
|
||||
set_fs(KERNEL_DS);
|
||||
|
||||
TRACE_DBG("Loading file '%s'", file_name);
|
||||
|
||||
file = filp_open(file_name, O_RDONLY, 0);
|
||||
if (IS_ERR(file)) {
|
||||
res = PTR_ERR(file);
|
||||
TRACE_DBG("Unable to open file '%s' - error %d", file_name, res);
|
||||
goto out;
|
||||
}
|
||||
|
||||
inode = file->f_dentry->d_inode;
|
||||
|
||||
if (S_ISREG(inode->i_mode))
|
||||
/* Nothing to do */;
|
||||
else if (S_ISBLK(inode->i_mode))
|
||||
inode = inode->i_bdev->bd_inode;
|
||||
else {
|
||||
PRINT_ERROR("Invalid file mode 0x%x", inode->i_mode);
|
||||
res = -EINVAL;
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
file_size = inode->i_size;
|
||||
|
||||
if (file_size > size) {
|
||||
PRINT_ERROR("Supplied buffer (%d) too small (need %d)", size,
|
||||
(int)file_size);
|
||||
res = -EOVERFLOW;
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
pos = 0;
|
||||
res = vfs_read(file, (void __force __user *)buf, file_size, &pos);
|
||||
if (res != file_size) {
|
||||
PRINT_ERROR("Unable to read file '%s' - error %d", file_name, res);
|
||||
if (res > 0)
|
||||
res = -EIO;
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
if (memcmp(buf, signature, signature_len) != 0) {
|
||||
res = -EINVAL;
|
||||
PRINT_ERROR("Invalid signature in file %s", file_name);
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
out_close:
|
||||
filp_close(file, NULL);
|
||||
|
||||
out:
|
||||
set_fs(old_fs);
|
||||
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns read data size on success, error code otherwise. The first
|
||||
* signature_len+1 bytes of the read data contain signature, so should be
|
||||
* skipped.
|
||||
*/
|
||||
int scst_read_file_transactional(const char *name, const char *name1,
|
||||
const char *signature, int signature_len, uint8_t *buf, int size)
|
||||
{
|
||||
int res;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
res = __scst_read_file_transactional(name, signature, signature_len, buf, size);
|
||||
if (res <= 0)
|
||||
res = __scst_read_file_transactional(name1, signature,
|
||||
signature_len, buf, size);
|
||||
|
||||
if (res > 0)
|
||||
TRACE_BUFFER("Read data", buf, res);
|
||||
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scst_read_file_transactional);
|
||||
|
||||
static void __init scst_scsi_op_list_init(void)
|
||||
{
|
||||
|
||||
@@ -779,7 +779,6 @@ int scst_vfs_fsync(struct file *file, loff_t loff, loff_t len);
|
||||
#endif
|
||||
|
||||
int scst_copy_file(const char *src, const char *dest);
|
||||
int scst_remove_file(const char *name);
|
||||
|
||||
#ifdef CONFIG_SCST_DEBUG_TM
|
||||
extern void tm_dbg_check_released_cmds(void);
|
||||
|
||||
@@ -570,7 +570,7 @@ int scst_pre_parse(struct scst_cmd *cmd)
|
||||
#else
|
||||
cmd->inc_expected_sn_on_done = devt->exec_sync ||
|
||||
(!dev->has_own_order_mgmt &&
|
||||
(dev->queue_alg == SCST_CONTR_MODE_QUEUE_ALG_RESTRICTED_REORDER ||
|
||||
(dev->queue_alg == SCST_QUEUE_ALG_0_RESTRICTED_REORDER ||
|
||||
cmd->queue_type == SCST_CMD_QUEUE_ORDERED));
|
||||
#endif
|
||||
|
||||
@@ -2358,7 +2358,7 @@ static int scst_reserve_local(struct scst_cmd *cmd)
|
||||
|
||||
/*
|
||||
* There's no need to block this device, even for
|
||||
* SCST_CONTR_MODE_ONE_TASK_SET, or anyhow else protect reservations
|
||||
* SCST_TST_0_SINGLE_TASK_SET, or anyhow else protect reservations
|
||||
* changes, because:
|
||||
*
|
||||
* 1. The reservation changes are (rather) atomic, i.e., in contrast
|
||||
@@ -2367,7 +2367,7 @@ static int scst_reserve_local(struct scst_cmd *cmd)
|
||||
*
|
||||
* 2. It's a duty of initiators to ensure order of regular commands
|
||||
* around the reservation command either by ORDERED attribute, or by
|
||||
* queue draining, or etc. For case of SCST_CONTR_MODE_ONE_TASK_SET
|
||||
* queue draining, or etc. For case of SCST_TST_0_SINGLE_TASK_SET
|
||||
* there are no target drivers which can ensure even for ORDERED
|
||||
* commands order of their delivery, so, because initiators know
|
||||
* it, also there's no point to do any extra protection actions.
|
||||
@@ -4177,7 +4177,7 @@ static void scst_cmd_set_sn(struct scst_cmd *cmd)
|
||||
cmd->queue_type = SCST_CMD_QUEUE_ORDERED;
|
||||
#endif
|
||||
|
||||
if (cmd->dev->queue_alg == SCST_CONTR_MODE_QUEUE_ALG_RESTRICTED_REORDER) {
|
||||
if (cmd->dev->queue_alg == SCST_QUEUE_ALG_0_RESTRICTED_REORDER) {
|
||||
if (likely(cmd->queue_type != SCST_CMD_QUEUE_HEAD_OF_QUEUE)) {
|
||||
/*
|
||||
* Not the best way, but good enough until there is a
|
||||
@@ -6183,8 +6183,7 @@ static int scst_mgmt_cmd_exec(struct scst_mgmt_cmd *mcmd)
|
||||
break;
|
||||
|
||||
case SCST_CLEAR_TASK_SET:
|
||||
if (mcmd->mcmd_tgt_dev->dev->tst ==
|
||||
SCST_CONTR_MODE_SEP_TASK_SETS)
|
||||
if (mcmd->mcmd_tgt_dev->dev->tst == SCST_TST_1_SEP_TASK_SETS)
|
||||
res = scst_abort_task_set(mcmd);
|
||||
else
|
||||
res = scst_clear_task_set(mcmd);
|
||||
|
||||
@@ -383,9 +383,9 @@ int start(int argc, char **argv)
|
||||
desc.opt.on_free_cmd_type = on_free_cmd_type;
|
||||
desc.opt.memory_reuse_type = memory_reuse_type;
|
||||
|
||||
desc.opt.tst = SCST_CONTR_MODE_SEP_TASK_SETS;
|
||||
desc.opt.queue_alg = SCST_CONTR_MODE_QUEUE_ALG_UNRESTRICTED_REORDER;
|
||||
desc.opt.d_sense = SCST_CONTR_MODE_FIXED_SENSE;
|
||||
desc.opt.tst = SCST_TST_1_SEP_TASK_SETS;
|
||||
desc.opt.queue_alg = SCST_QUEUE_ALG_1_UNRESTRICTED_REORDER;
|
||||
desc.opt.d_sense = SCST_D_SENSE_0_FIXED_SENSE;
|
||||
|
||||
res = ioctl(devs[i].scst_usr_fd, SCST_USER_REGISTER_DEVICE, &desc);
|
||||
if (res != 0) {
|
||||
|
||||
Reference in New Issue
Block a user