mirror of
https://github.com/SCST-project/scst.git
synced 2026-07-25 17:42:38 +00:00
Merge branch 'svn-trunk'
This commit is contained in:
@@ -1,3 +1,8 @@
|
||||
Summary of changes between versions 3.4 and 3.5
|
||||
-----------------------------------------------
|
||||
- Added the forward_src and forward_dst sysfs attributes. Removed
|
||||
CONFIG_SCST_FORWARD_MODE_PASS_THROUGH.
|
||||
|
||||
Summary of changes between versions 3.3 and 3.4
|
||||
-----------------------------------------------
|
||||
- I/O keeps running at full speed if a LUN is added or removed and also if
|
||||
|
||||
+18
-17
@@ -343,16 +343,6 @@ in/out in Makefile and scst.h:
|
||||
functionality is working only if dif_mode doesn't contain dev_store
|
||||
and dif_type is 1.
|
||||
|
||||
- CONFIG_SCST_FORWARD_MODE_PASS_THROUGH - if defined, the pass-through
|
||||
subsystem starts working in the forwarding mode, where reservation
|
||||
commands processed locally and not passed to the backend SCSI device,
|
||||
while COMPARE AND WRITE, EXTENDED COPY and RECEIVE COPY RESULTS
|
||||
commands, which normally processed locally by the SCST core, not
|
||||
processed locally, but passed to the backend device. Intended to be
|
||||
used to implement NON-OPTIMIZED ALUA state together with "forwarding"
|
||||
target attribute on the remote node. See below for more details.
|
||||
Disabled by default for safety.
|
||||
|
||||
- CONFIG_SCST_NO_TOTAL_MEM_CHECKS - disables checks of allocated
|
||||
memory, see scst_max_cmd_mem below. Allows to avoid 2 global
|
||||
variables on the fast path, hence get better multi-queue performance.
|
||||
@@ -807,9 +797,19 @@ Every target should have at least the following entries:
|
||||
until rel_tgt_id becomes unique. This attribute initialized unique by
|
||||
SCST by default.
|
||||
|
||||
- forwarding - if set this target is forwarding target, i.e. does not check
|
||||
any local SCSI events (reservations, etc.). Those event supposed to
|
||||
be checked on the another, requester's side.
|
||||
- forward_src - if set this target port is a forwarding source. This means
|
||||
that commands like COMPARE AND WRITE, EXTENDED COPY and RECEIVE COPY
|
||||
RESULTS are submitted to the SCSI device instead of being handled inside
|
||||
the SCST core. PERSISTENT RESERVE IN and OUT commands are processed by the
|
||||
SCST core, whether or not this mode is enabled. The name 'forwarding_src'
|
||||
refers to the use case where SCSI passthrough is used to send SCSI commands
|
||||
to another H.A. node.
|
||||
|
||||
- forward_dst - if set this target port is a forwarding destination. This means
|
||||
that it does not check any local SCSI events (reservations, etc.). Those
|
||||
event are supposed to be checked at the forwarding source side.
|
||||
|
||||
- forwarding - obsolete synonym for forward_dst.
|
||||
|
||||
- *count*, e.g. read_io_count_kb, - statistics about executed
|
||||
commands and transferred data. Those attributes have speaking names
|
||||
@@ -1788,7 +1788,7 @@ attribute.
|
||||
closes open handles on all affected SCST devices and after transition
|
||||
reopens them, if the new state is active or nonoptimized. Alternatively,
|
||||
set "bind_alua_state=0" for SCST BLOCKIO devices and ALUA state changes
|
||||
will not open/close the backing block device, the user will neeed to handle
|
||||
will not open/close the backing block device, the user will need to handle
|
||||
this manually or via a cluster RA in an HA setup.
|
||||
|
||||
Thus, the recommended implicit ALUA state change procedure for primary
|
||||
@@ -1984,13 +1984,13 @@ The link between block devices I and J stands for synchronous replication.
|
||||
|
||||
Such a setup can be configured as follows:
|
||||
|
||||
1. Build SCST with CONFIG_SCST_FORWARD_MODE_PASS_THROUGH enabled in scst.h
|
||||
1. Build SCST.
|
||||
|
||||
2. Setup on active node internal redirect target, which is going to
|
||||
accept redirected commands from the passive node. It must be visible
|
||||
only to the passive node.
|
||||
|
||||
3. Set "forwarding" attribute for this target to 1. This is necessary to
|
||||
3. Set "forward_dst" attribute for this target to 1. This is necessary to
|
||||
correctly handle PRs.
|
||||
|
||||
4. Export through this target the SAME backend SCST device as being
|
||||
@@ -2005,7 +2005,8 @@ device on the passive side pointing to the active node.
|
||||
*pass-through* handler (scst_disk). Pass-though is needed to redirect
|
||||
non-block commands as well: ATS, XCOPY, etc.
|
||||
|
||||
7. Set ALUA state to this target as "nonoptimized".
|
||||
7. Set ALUA state to this target as "nonoptimized". Set the forward_src
|
||||
attribute to one.
|
||||
|
||||
That's it on the normal path. Now the initiator(s) would see 2 paths:
|
||||
OPTIMIZED going to the active node and NON-OPTIMIZED going to the
|
||||
|
||||
@@ -674,6 +674,20 @@ static inline int __must_check kstrtol(const char *s, unsigned int base,
|
||||
{
|
||||
return strict_strtol(s, base, res);
|
||||
}
|
||||
|
||||
static inline int __must_check kstrtoint(const char *s, unsigned int base,
|
||||
int *result)
|
||||
{
|
||||
long val;
|
||||
int ret = strict_strtol(s, base, &val);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
*result = val;
|
||||
if (*result != val)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 17, 0)
|
||||
|
||||
+23
-7
@@ -28,7 +28,6 @@
|
||||
|
||||
/** See README for description of those conditional defines **/
|
||||
#define CONFIG_SCST_DIF_INJECT_CORRUPTED_TAGS
|
||||
/* #define CONFIG_SCST_FORWARD_MODE_PASS_THROUGH */
|
||||
#define CONFIG_SCST_NO_TOTAL_MEM_CHECKS
|
||||
|
||||
#include <linux/types.h>
|
||||
@@ -479,8 +478,8 @@ enum scst_exec_res {
|
||||
/* Cache of acg->acg_black_hole_type */
|
||||
#define SCST_TGT_DEV_BLACK_HOLE 1
|
||||
|
||||
/* Cache of tgt->tgt_forwarding */
|
||||
#define SCST_TGT_DEV_FORWARDING 5
|
||||
/* Cache of tgt->tgt_forward_dst */
|
||||
#define SCST_TGT_DEV_FORWARD_DST 5
|
||||
|
||||
/*************************************************************
|
||||
** I/O grouping types. Changing them don't forget to change
|
||||
@@ -1688,11 +1687,23 @@ struct scst_tgt {
|
||||
struct list_head tgt_acg_list; /* target ACG groups */
|
||||
|
||||
/*
|
||||
* Set, if this target is forwarding target, i.e. does not check
|
||||
* any local SCSI events (reservations, etc.). Those event supposed
|
||||
* to be checked on the another, requester's side.
|
||||
* Set if and only if this target port is a forwarding source. If
|
||||
* enabled, the dev_disk handler submits COMPARE AND WRITE, EXTENDED
|
||||
* COPY and RECEIVE COPY RESULTS commands to the SCSI device instead
|
||||
* of handling these inside the SCST core. PERSISTENT RESERVE IN and
|
||||
* OUT commands are processed by the SCST core, whether or not this
|
||||
* mode is enabled. The name 'forwarding_src' refers to the use case
|
||||
* where SCSI passthrough is used to send SCSI commands to another
|
||||
* H.A. node.
|
||||
*/
|
||||
unsigned tgt_forwarding:1;
|
||||
unsigned tgt_forward_src:1;
|
||||
|
||||
/*
|
||||
* Set, if this target is forwarding destination, i.e. does not check
|
||||
* any local SCSI events (reservations, etc.). Those events are
|
||||
* supposed to be checked at the side of the forwarding source.
|
||||
*/
|
||||
unsigned tgt_forward_dst:1;
|
||||
|
||||
/* Per target analog of the corresponding driver's fields */
|
||||
unsigned tgt_dif_supported:1;
|
||||
@@ -2862,6 +2873,11 @@ struct scst_device {
|
||||
*/
|
||||
int dev_scsi_atomic_cmd_active;
|
||||
|
||||
/*
|
||||
* Whether or not explicit ALUA has been enabled. Protected by dev_lock.
|
||||
*/
|
||||
unsigned int expl_alua:1;
|
||||
|
||||
/*
|
||||
* List of all being executed on the dev commands.
|
||||
* Protected by dev_lock.
|
||||
|
||||
@@ -144,6 +144,7 @@ static void disk_detach(struct scst_device *dev)
|
||||
|
||||
static int disk_parse(struct scst_cmd *cmd)
|
||||
{
|
||||
struct scst_tgt *tgt = cmd->tgt;
|
||||
int res = SCST_CMD_STATE_DEFAULT, rc;
|
||||
|
||||
rc = scst_sbc_generic_parse(cmd);
|
||||
@@ -152,8 +153,7 @@ static int disk_parse(struct scst_cmd *cmd)
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SCST_FORWARD_MODE_PASS_THROUGH
|
||||
if (unlikely(cmd->op_flags & SCST_LOCAL_CMD)) {
|
||||
if (unlikely(tgt->tgt_forward_src && cmd->op_flags & SCST_LOCAL_CMD)) {
|
||||
switch (cmd->cdb[0]) {
|
||||
case COMPARE_AND_WRITE:
|
||||
case EXTENDED_COPY:
|
||||
@@ -164,7 +164,6 @@ static int disk_parse(struct scst_cmd *cmd)
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
cmd->retries = SCST_PASSTHROUGH_RETRIES;
|
||||
out:
|
||||
@@ -286,6 +285,7 @@ out_complete:
|
||||
/* Executes command and split CDB, if necessary */
|
||||
static enum scst_exec_res disk_exec(struct scst_cmd *cmd)
|
||||
{
|
||||
struct scst_tgt *tgt = cmd->tgt;
|
||||
enum scst_exec_res res;
|
||||
int rc;
|
||||
struct disk_work work;
|
||||
@@ -299,8 +299,7 @@ static enum scst_exec_res disk_exec(struct scst_cmd *cmd)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
#ifdef CONFIG_SCST_FORWARD_MODE_PASS_THROUGH
|
||||
if (unlikely(cmd->op_flags & SCST_LOCAL_CMD)) {
|
||||
if (unlikely(tgt->tgt_forward_src && cmd->op_flags & SCST_LOCAL_CMD)) {
|
||||
switch (cmd->cdb[0]) {
|
||||
case RESERVE:
|
||||
case RESERVE_10:
|
||||
@@ -315,7 +314,6 @@ static enum scst_exec_res disk_exec(struct scst_cmd *cmd)
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* For PC requests we are going to submit max_hw_sectors used instead
|
||||
|
||||
@@ -184,7 +184,6 @@ struct scst_vdisk_dev {
|
||||
unsigned int tst:3;
|
||||
unsigned int format_active:1;
|
||||
unsigned int discard_zeroes_data:1;
|
||||
unsigned int expl_alua:1;
|
||||
unsigned int reexam_pending:1;
|
||||
unsigned int size_key:1;
|
||||
unsigned int opt_trans_len_set:1;
|
||||
@@ -2554,7 +2553,6 @@ static int vdisk_get_supported_opcodes(struct scst_cmd *cmd,
|
||||
int *out_supp_opcodes_cnt)
|
||||
{
|
||||
struct scst_device *dev = cmd->dev;
|
||||
struct scst_vdisk_dev *virt_dev = dev->dh_priv;
|
||||
|
||||
if (cmd->dev->dev_dif_type != 2) {
|
||||
*out_supp_opcodes = vdisk_opcode_descriptors;
|
||||
@@ -2563,7 +2561,7 @@ static int vdisk_get_supported_opcodes(struct scst_cmd *cmd,
|
||||
*out_supp_opcodes = vdisk_opcode_descriptors_type2;
|
||||
*out_supp_opcodes_cnt = ARRAY_SIZE(vdisk_opcode_descriptors_type2);
|
||||
}
|
||||
if (!virt_dev->expl_alua) {
|
||||
if (!dev->expl_alua) {
|
||||
(*out_supp_opcodes_cnt)--;
|
||||
sBUG_ON((*out_supp_opcodes)[*out_supp_opcodes_cnt]->od_serv_action != MO_SET_TARGET_PGS);
|
||||
}
|
||||
@@ -3981,6 +3979,7 @@ static int vdisk_tp_vpd(uint8_t *buf, struct scst_cmd *cmd,
|
||||
static int vdisk_inq(uint8_t *buf, struct scst_cmd *cmd,
|
||||
struct scst_vdisk_dev *virt_dev)
|
||||
{
|
||||
struct scst_device *dev = cmd->dev;
|
||||
int num;
|
||||
|
||||
if (virt_dev->removable)
|
||||
@@ -3993,7 +3992,7 @@ static int vdisk_inq(uint8_t *buf, struct scst_cmd *cmd,
|
||||
buf[5] |= 1; /* PROTECT */
|
||||
if (scst_alua_configured(cmd->dev)) {
|
||||
buf[5] |= SCST_INQ_TPGS_MODE_IMPLICIT;
|
||||
if (virt_dev->expl_alua)
|
||||
if (dev->expl_alua)
|
||||
buf[5] |= SCST_INQ_TPGS_MODE_EXPLICIT;
|
||||
}
|
||||
buf[5] |= 8; /* 3PC */
|
||||
@@ -5107,81 +5106,6 @@ static enum compl_status_e vdisk_exec_get_lba_status(struct vdisk_cmd_params *p)
|
||||
return CMD_SUCCEEDED;
|
||||
}
|
||||
|
||||
/* SPC-4 REPORT TARGET PORT GROUPS command */
|
||||
static enum compl_status_e vdisk_exec_report_tpgs(struct vdisk_cmd_params *p)
|
||||
{
|
||||
struct scst_cmd *cmd = p->cmd;
|
||||
struct scst_device *dev;
|
||||
uint8_t *address;
|
||||
void *buf;
|
||||
int32_t buf_len;
|
||||
uint32_t data_length, length;
|
||||
uint8_t data_format;
|
||||
int res;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
buf_len = scst_get_buf_full_sense(cmd, &address);
|
||||
if (buf_len <= 0)
|
||||
goto out;
|
||||
|
||||
dev = cmd->dev;
|
||||
data_format = cmd->cdb[1] >> 5;
|
||||
|
||||
res = scst_tg_get_group_info(&buf, &data_length, dev, data_format);
|
||||
if (res == -ENOMEM) {
|
||||
scst_set_busy(cmd);
|
||||
goto out_put;
|
||||
} else if (res < 0) {
|
||||
scst_set_cmd_error(cmd,
|
||||
SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb));
|
||||
goto out_put;
|
||||
}
|
||||
|
||||
length = min_t(uint32_t, data_length, buf_len);
|
||||
memcpy(address, buf, length);
|
||||
kfree(buf);
|
||||
if (length < cmd->resp_data_len)
|
||||
scst_set_resp_data_len(cmd, length);
|
||||
|
||||
out_put:
|
||||
scst_put_buf_full(cmd, address);
|
||||
|
||||
out:
|
||||
TRACE_EXIT();
|
||||
return CMD_SUCCEEDED;
|
||||
}
|
||||
|
||||
/* SPC-4 SET TARGET PORT GROUPS command */
|
||||
static enum compl_status_e vdisk_exec_set_tpgs(struct vdisk_cmd_params *p)
|
||||
{
|
||||
struct scst_cmd *cmd = p->cmd;
|
||||
struct scst_device *dev = cmd->dev;
|
||||
struct scst_vdisk_dev *virt_dev = dev->dh_priv;
|
||||
int res = CMD_SUCCEEDED, rc;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
if (!virt_dev->expl_alua) {
|
||||
PRINT_ERROR("SET TARGET PORT GROUPS: not explicit ALUA mode "
|
||||
"(dev %s)", dev->virt_name);
|
||||
/* Invalid opcode, i.e. SA field */
|
||||
scst_set_invalid_field_in_cdb(cmd, 1,
|
||||
0 | SCST_INVAL_FIELD_BIT_OFFS_VALID);
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = scst_tg_set_group_info(cmd);
|
||||
if (rc == 0)
|
||||
res = RUNNING_ASYNC;
|
||||
else
|
||||
scst_stpg_del_unblock_next(cmd);
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static enum compl_status_e vdisk_exec_sai_16(struct vdisk_cmd_params *p)
|
||||
{
|
||||
switch (p->cmd->cdb[1] & 0x1f) {
|
||||
@@ -5198,25 +5122,15 @@ static enum compl_status_e vdisk_exec_sai_16(struct vdisk_cmd_params *p)
|
||||
|
||||
static enum compl_status_e vdisk_exec_maintenance_in(struct vdisk_cmd_params *p)
|
||||
{
|
||||
switch (p->cmd->cdb[1] & 0x1f) {
|
||||
case MI_REPORT_TARGET_PGS:
|
||||
vdisk_exec_report_tpgs(p);
|
||||
return CMD_SUCCEEDED;
|
||||
}
|
||||
scst_set_invalid_field_in_cdb(p->cmd, 1,
|
||||
0 | SCST_INVAL_FIELD_BIT_OFFS_VALID);
|
||||
return CMD_SUCCEEDED;
|
||||
/* For the code that handles RTPG, see also scst_local_cmd.c. */
|
||||
return CMD_FAILED;
|
||||
}
|
||||
|
||||
static enum compl_status_e vdisk_exec_maintenance_out(struct vdisk_cmd_params *p)
|
||||
static enum compl_status_e
|
||||
vdisk_exec_maintenance_out(struct vdisk_cmd_params *p)
|
||||
{
|
||||
switch (p->cmd->cdb[1] & 0x1f) {
|
||||
case MO_SET_TARGET_PGS:
|
||||
return vdisk_exec_set_tpgs(p);
|
||||
}
|
||||
scst_set_invalid_field_in_cdb(p->cmd, 1,
|
||||
0 | SCST_INVAL_FIELD_BIT_OFFS_VALID);
|
||||
return CMD_SUCCEEDED;
|
||||
/* For the code that handles RTPG, see also scst_local_cmd.c. */
|
||||
return CMD_FAILED;
|
||||
}
|
||||
|
||||
static enum compl_status_e vdisk_exec_read_toc(struct vdisk_cmd_params *p)
|
||||
@@ -7010,7 +6924,6 @@ static int vdev_create_node(struct scst_dev_type *devt,
|
||||
virt_dev->rotational = DEF_ROTATIONAL;
|
||||
virt_dev->thin_provisioned = DEF_THIN_PROVISIONED;
|
||||
virt_dev->tst = DEF_TST;
|
||||
virt_dev->expl_alua = DEF_EXPL_ALUA;
|
||||
INIT_WORK(&virt_dev->vdev_inq_changed_work, vdev_inq_changed_fn);
|
||||
|
||||
virt_dev->blk_shift = DEF_DISK_BLOCK_SHIFT;
|
||||
@@ -8217,7 +8130,7 @@ static ssize_t vdisk_sysfs_rd_only_show(struct kobject *kobj,
|
||||
dev = container_of(kobj, struct scst_device, dev_kobj);
|
||||
virt_dev = dev->dh_priv;
|
||||
|
||||
pos = sprintf(buf, "%d\n%s", virt_dev->rd_only ? 1 : 0,
|
||||
pos = sprintf(buf, "%d\n%s", virt_dev->rd_only,
|
||||
(virt_dev->rd_only == DEF_RD_ONLY) ? "" :
|
||||
SCST_SYSFS_KEY_MARK "\n");
|
||||
|
||||
@@ -8237,7 +8150,7 @@ static ssize_t vdisk_sysfs_wt_show(struct kobject *kobj,
|
||||
dev = container_of(kobj, struct scst_device, dev_kobj);
|
||||
virt_dev = dev->dh_priv;
|
||||
|
||||
pos = sprintf(buf, "%d\n%s", virt_dev->wt_flag ? 1 : 0,
|
||||
pos = sprintf(buf, "%d\n%s", virt_dev->wt_flag,
|
||||
(virt_dev->wt_flag == DEF_WRITE_THROUGH) ? "" :
|
||||
SCST_SYSFS_KEY_MARK "\n");
|
||||
|
||||
@@ -8257,7 +8170,7 @@ static ssize_t vdisk_sysfs_tp_show(struct kobject *kobj,
|
||||
dev = container_of(kobj, struct scst_device, dev_kobj);
|
||||
virt_dev = dev->dh_priv;
|
||||
|
||||
pos = sprintf(buf, "%d\n%s", virt_dev->thin_provisioned ? 1 : 0,
|
||||
pos = sprintf(buf, "%d\n%s", virt_dev->thin_provisioned,
|
||||
virt_dev->thin_provisioned_manually_set &&
|
||||
(virt_dev->thin_provisioned !=
|
||||
virt_dev->dev_thin_provisioned) ?
|
||||
@@ -8297,50 +8210,33 @@ static ssize_t vdisk_sysfs_expl_alua_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct scst_device *dev;
|
||||
struct scst_vdisk_dev *virt_dev;
|
||||
int pos;
|
||||
struct scst_device *dev = container_of(kobj, struct scst_device,
|
||||
dev_kobj);
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
dev = container_of(kobj, struct scst_device, dev_kobj);
|
||||
virt_dev = dev->dh_priv;
|
||||
pos = sprintf(buf, "%d\n%s", virt_dev->expl_alua,
|
||||
virt_dev->expl_alua != DEF_EXPL_ALUA ?
|
||||
return sprintf(buf, "%d\n%s", dev->expl_alua,
|
||||
dev->expl_alua != DEF_EXPL_ALUA ?
|
||||
SCST_SYSFS_KEY_MARK "\n" : "");
|
||||
|
||||
TRACE_EXIT_RES(pos);
|
||||
return pos;
|
||||
}
|
||||
|
||||
static ssize_t vdisk_sysfs_expl_alua_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct scst_device *dev;
|
||||
struct scst_vdisk_dev *virt_dev;
|
||||
char ch[16];
|
||||
struct scst_device *dev = container_of(kobj, struct scst_device,
|
||||
dev_kobj);
|
||||
unsigned long expl_alua;
|
||||
int res;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
dev = container_of(kobj, struct scst_device, dev_kobj);
|
||||
virt_dev = dev->dh_priv;
|
||||
sprintf(ch, "%.*s", min_t(int, sizeof(ch) - 1, count), buf);
|
||||
res = kstrtoul(ch, 0, &expl_alua);
|
||||
res = kstrtoul(buf, 0, &expl_alua);
|
||||
if (res < 0)
|
||||
goto out;
|
||||
return res;
|
||||
|
||||
spin_lock(&virt_dev->flags_lock);
|
||||
virt_dev->expl_alua = !!expl_alua;
|
||||
spin_unlock(&virt_dev->flags_lock);
|
||||
spin_lock_bh(&dev->dev_lock);
|
||||
dev->expl_alua = !!expl_alua;
|
||||
spin_unlock_bh(&dev->dev_lock);
|
||||
|
||||
res = count;
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t vdisk_sysfs_nv_cache_show(struct kobject *kobj,
|
||||
@@ -8355,7 +8251,7 @@ static ssize_t vdisk_sysfs_nv_cache_show(struct kobject *kobj,
|
||||
dev = container_of(kobj, struct scst_device, dev_kobj);
|
||||
virt_dev = dev->dh_priv;
|
||||
|
||||
pos = sprintf(buf, "%d\n%s", virt_dev->nv_cache ? 1 : 0,
|
||||
pos = sprintf(buf, "%d\n%s", virt_dev->nv_cache,
|
||||
(virt_dev->nv_cache == DEF_NV_CACHE) ? "" :
|
||||
SCST_SYSFS_KEY_MARK "\n");
|
||||
|
||||
@@ -8375,7 +8271,7 @@ static ssize_t vdisk_sysfs_o_direct_show(struct kobject *kobj,
|
||||
dev = container_of(kobj, struct scst_device, dev_kobj);
|
||||
virt_dev = dev->dh_priv;
|
||||
|
||||
pos = sprintf(buf, "%d\n%s", virt_dev->o_direct_flag ? 1 : 0,
|
||||
pos = sprintf(buf, "%d\n%s", virt_dev->o_direct_flag,
|
||||
(virt_dev->o_direct_flag == DEF_O_DIRECT) ? "" :
|
||||
SCST_SYSFS_KEY_MARK "\n");
|
||||
|
||||
@@ -8447,7 +8343,7 @@ static ssize_t vdisk_sysfs_removable_show(struct kobject *kobj,
|
||||
dev = container_of(kobj, struct scst_device, dev_kobj);
|
||||
virt_dev = dev->dh_priv;
|
||||
|
||||
pos = sprintf(buf, "%d\n", virt_dev->removable ? 1 : 0);
|
||||
pos = sprintf(buf, "%d\n", virt_dev->removable);
|
||||
|
||||
if ((virt_dev->dev->type != TYPE_ROM) &&
|
||||
(virt_dev->removable != DEF_REMOVABLE))
|
||||
@@ -8490,7 +8386,7 @@ static ssize_t vdisk_sysfs_rotational_show(struct kobject *kobj,
|
||||
dev = container_of(kobj, struct scst_device, dev_kobj);
|
||||
virt_dev = dev->dh_priv;
|
||||
|
||||
pos = sprintf(buf, "%d\n", virt_dev->rotational ? 1 : 0);
|
||||
pos = sprintf(buf, "%d\n", virt_dev->rotational);
|
||||
|
||||
if (virt_dev->rotational != DEF_ROTATIONAL)
|
||||
pos += sprintf(&buf[pos], "%s\n", SCST_SYSFS_KEY_MARK);
|
||||
|
||||
+5
-5
@@ -5337,10 +5337,10 @@ static int scst_alloc_add_tgt_dev(struct scst_session *sess,
|
||||
tgt_dev->lun = acg_dev->lun;
|
||||
tgt_dev->acg_dev = acg_dev;
|
||||
tgt_dev->tgt_dev_rd_only = acg_dev->acg_dev_rd_only || dev->dev_rd_only;
|
||||
if (sess->tgt->tgt_forwarding)
|
||||
set_bit(SCST_TGT_DEV_FORWARDING, &tgt_dev->tgt_dev_flags);
|
||||
if (sess->tgt->tgt_forward_dst)
|
||||
set_bit(SCST_TGT_DEV_FORWARD_DST, &tgt_dev->tgt_dev_flags);
|
||||
else
|
||||
clear_bit(SCST_TGT_DEV_FORWARDING, &tgt_dev->tgt_dev_flags);
|
||||
clear_bit(SCST_TGT_DEV_FORWARD_DST, &tgt_dev->tgt_dev_flags);
|
||||
tgt_dev->hw_dif_same_sg_layout_required = sess->tgt->tgt_hw_dif_same_sg_layout_required;
|
||||
tgt_dev->tgt_dev_dif_guard_format = acg_dev->acg_dev_dif_guard_format;
|
||||
if (tgt_dev->tgt_dev_dif_guard_format == SCST_DIF_GUARD_FORMAT_IP)
|
||||
@@ -11936,7 +11936,7 @@ static int get_cdb_info_min(struct scst_cmd *cmd,
|
||||
break;
|
||||
case MI_REPORT_TARGET_PGS:
|
||||
cmd->op_name = "REPORT TARGET PORT GROUPS";
|
||||
cmd->op_flags |= SCST_REG_RESERVE_ALLOWED |
|
||||
cmd->op_flags |= SCST_LOCAL_CMD | SCST_REG_RESERVE_ALLOWED |
|
||||
SCST_WRITE_EXCL_ALLOWED | SCST_EXCL_ACCESS_ALLOWED;
|
||||
break;
|
||||
case MI_REPORT_SUPPORTED_OPERATION_CODES:
|
||||
@@ -11967,7 +11967,7 @@ static int get_cdb_info_mo(struct scst_cmd *cmd,
|
||||
unsigned long flags;
|
||||
|
||||
cmd->op_name = "SET TARGET PORT GROUPS";
|
||||
cmd->op_flags |= SCST_STRICTLY_SERIALIZED;
|
||||
cmd->op_flags |= SCST_LOCAL_CMD | SCST_STRICTLY_SERIALIZED;
|
||||
spin_lock_irqsave(&scst_global_stpg_list_lock, flags);
|
||||
TRACE_DBG("Adding STPG cmd %p to global_stpg_list", cmd);
|
||||
cmd->cmd_on_global_stpg_list = 1;
|
||||
|
||||
@@ -253,6 +253,82 @@ out_unlock_put_not_completed:
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* SPC-4 REPORT TARGET PORT GROUPS command */
|
||||
static enum scst_exec_res scst_report_tpgs(struct scst_cmd *cmd)
|
||||
{
|
||||
struct scst_device *dev;
|
||||
uint8_t *address;
|
||||
void *buf;
|
||||
int32_t buf_len;
|
||||
uint32_t data_length, length;
|
||||
uint8_t data_format;
|
||||
int res;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
buf_len = scst_get_buf_full_sense(cmd, &address);
|
||||
if (buf_len <= 0)
|
||||
goto out;
|
||||
|
||||
dev = cmd->dev;
|
||||
data_format = cmd->cdb[1] >> 5;
|
||||
|
||||
res = scst_tg_get_group_info(&buf, &data_length, dev, data_format);
|
||||
if (res == -ENOMEM) {
|
||||
scst_set_busy(cmd);
|
||||
goto out_put;
|
||||
} else if (res < 0) {
|
||||
scst_set_cmd_error(cmd,
|
||||
SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb));
|
||||
goto out_put;
|
||||
}
|
||||
|
||||
length = min_t(uint32_t, data_length, buf_len);
|
||||
memcpy(address, buf, length);
|
||||
kfree(buf);
|
||||
if (length < cmd->resp_data_len)
|
||||
scst_set_resp_data_len(cmd, length);
|
||||
|
||||
out_put:
|
||||
scst_put_buf_full(cmd, address);
|
||||
|
||||
out:
|
||||
cmd->completed = 1;
|
||||
|
||||
/* Report the result */
|
||||
cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT, SCST_CONTEXT_SAME);
|
||||
|
||||
return SCST_EXEC_COMPLETED;
|
||||
}
|
||||
|
||||
/* SPC-4 SET TARGET PORT GROUPS command */
|
||||
static enum scst_exec_res scst_exec_set_tpgs(struct scst_cmd *cmd)
|
||||
{
|
||||
struct scst_device *dev = cmd->dev;
|
||||
int rc;
|
||||
|
||||
if (!dev->expl_alua) {
|
||||
PRINT_ERROR("SET TARGET PORT GROUPS: not explicit ALUA mode "
|
||||
"(dev %s)", dev->virt_name);
|
||||
/* Invalid opcode, i.e. SA field */
|
||||
scst_set_invalid_field_in_cdb(cmd, 1,
|
||||
0 | SCST_INVAL_FIELD_BIT_OFFS_VALID);
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = scst_tg_set_group_info(cmd);
|
||||
if (rc == 0) {
|
||||
/* Running async */
|
||||
return SCST_CMD_STATE_RES_CONT_NEXT;
|
||||
}
|
||||
scst_stpg_del_unblock_next(cmd);
|
||||
|
||||
out:
|
||||
cmd->completed = 1;
|
||||
cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT, SCST_CONTEXT_SAME);
|
||||
return SCST_EXEC_COMPLETED;
|
||||
}
|
||||
|
||||
static enum scst_exec_res scst_report_supported_tm_fns(struct scst_cmd *cmd)
|
||||
{
|
||||
const enum scst_exec_res res = SCST_EXEC_COMPLETED;
|
||||
@@ -505,6 +581,9 @@ enum scst_exec_res scst_maintenance_in(struct scst_cmd *cmd)
|
||||
TRACE_ENTRY();
|
||||
|
||||
switch (cmd->cdb[1] & 0x1f) {
|
||||
case MI_REPORT_TARGET_PGS:
|
||||
res = scst_report_tpgs(cmd);
|
||||
break;
|
||||
case MI_REPORT_SUPPORTED_TASK_MANAGEMENT_FUNCTIONS:
|
||||
res = scst_report_supported_tm_fns(cmd);
|
||||
break;
|
||||
@@ -520,6 +599,22 @@ enum scst_exec_res scst_maintenance_in(struct scst_cmd *cmd)
|
||||
return res;
|
||||
}
|
||||
|
||||
enum scst_exec_res scst_maintenance_out(struct scst_cmd *cmd)
|
||||
{
|
||||
enum scst_exec_res res;
|
||||
|
||||
switch (cmd->cdb[1] & 0x1f) {
|
||||
case MO_SET_TARGET_PGS:
|
||||
res = scst_exec_set_tpgs(cmd);
|
||||
break;
|
||||
default:
|
||||
res = SCST_EXEC_NOT_COMPLETED;
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
enum scst_exec_res scst_reserve_local(struct scst_cmd *cmd)
|
||||
{
|
||||
enum scst_exec_res res = SCST_EXEC_NOT_COMPLETED;
|
||||
@@ -714,15 +809,13 @@ enum scst_exec_res scst_persistent_reserve_in_local(struct scst_cmd *cmd)
|
||||
goto out_done;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_SCST_FORWARD_MODE_PASS_THROUGH
|
||||
if (dev->scsi_dev != NULL) {
|
||||
if (cmd->tgt->tgt_forward_src && dev->scsi_dev) {
|
||||
PRINT_WARNING("PR commands for pass-through devices not "
|
||||
"supported (device %s)", dev->virt_name);
|
||||
scst_set_cmd_error(cmd,
|
||||
SCST_LOAD_SENSE(scst_sense_invalid_opcode));
|
||||
goto out_done;
|
||||
}
|
||||
#endif
|
||||
|
||||
buffer_size = scst_get_buf_full_sense(cmd, &buffer);
|
||||
if (unlikely(buffer_size <= 0))
|
||||
|
||||
@@ -8,6 +8,7 @@ enum scst_exec_res scst_cm_ext_copy_exec(struct scst_cmd *cmd);
|
||||
enum scst_exec_res scst_cm_rcv_copy_res_exec(struct scst_cmd *cmd);
|
||||
enum scst_exec_res scst_cmp_wr_local(struct scst_cmd *cmd);
|
||||
enum scst_exec_res scst_maintenance_in(struct scst_cmd *cmd);
|
||||
enum scst_exec_res scst_maintenance_out(struct scst_cmd *cmd);
|
||||
enum scst_exec_res scst_persistent_reserve_in_local(struct scst_cmd *cmd);
|
||||
enum scst_exec_res scst_persistent_reserve_out_local(struct scst_cmd *cmd);
|
||||
enum scst_exec_res scst_release_local(struct scst_cmd *cmd);
|
||||
|
||||
+3
-10
@@ -1111,7 +1111,7 @@ static int scst_register_device(struct scsi_device *scsidp)
|
||||
|
||||
dev->scsi_dev = scsidp;
|
||||
|
||||
#ifdef CONFIG_SCST_FORWARD_MODE_PASS_THROUGH
|
||||
/* For target ports that function as forwarding source. */
|
||||
res = scst_pr_set_file_name(dev, NULL, "%s/%s", SCST_PR_DIR,
|
||||
dev->virt_name);
|
||||
if (res != 0)
|
||||
@@ -1120,7 +1120,6 @@ static int scst_register_device(struct scsi_device *scsidp)
|
||||
res = scst_pr_init_dev(dev);
|
||||
if (res != 0)
|
||||
goto out_free_dev;
|
||||
#endif
|
||||
|
||||
list_add_tail(&dev->dev_list_entry, &scst_dev_list);
|
||||
|
||||
@@ -1143,14 +1142,9 @@ out:
|
||||
out_del_unlocked:
|
||||
mutex_lock(&scst_mutex);
|
||||
list_del_init(&dev->dev_list_entry);
|
||||
mutex_unlock(&scst_mutex);
|
||||
|
||||
percpu_ref_kill(&dev->refcnt);
|
||||
goto out;
|
||||
|
||||
#ifdef CONFIG_SCST_FORWARD_MODE_PASS_THROUGH
|
||||
/* If used as a forwarding source (see also tgt_forward_src). */
|
||||
scst_pr_clear_dev(dev);
|
||||
#endif
|
||||
|
||||
out_free_dev:
|
||||
percpu_ref_kill(&dev->refcnt);
|
||||
@@ -1193,9 +1187,8 @@ static void scst_unregister_device(struct scsi_device *scsidp)
|
||||
|
||||
list_del_init(&dev->dev_list_entry);
|
||||
|
||||
#ifdef CONFIG_SCST_FORWARD_MODE_PASS_THROUGH
|
||||
/* For forwarding sources (see also tgt_forward_src). */
|
||||
scst_pr_clear_dev(dev);
|
||||
#endif
|
||||
|
||||
scst_dg_dev_remove_by_dev(dev);
|
||||
|
||||
|
||||
@@ -1594,7 +1594,7 @@ static int scst_pr_register_all_tg_pt(struct scst_cmd *cmd, uint8_t *buffer,
|
||||
continue;
|
||||
if (tgt->rel_tgt_id == 0)
|
||||
continue;
|
||||
if (tgt->tgt_forwarding) {
|
||||
if (tgt->tgt_forward_dst) {
|
||||
TRACE_PR("ALL_TG_PT: skipping forwarding "
|
||||
"target %s", tgt->tgt_name);
|
||||
continue;
|
||||
|
||||
+68
-19
@@ -2072,10 +2072,10 @@ static ssize_t __scst_acg_cpu_mask_store(struct scst_acg *acg,
|
||||
* We can't use cpumask_parse_user() here, because it expects
|
||||
* buffer in the user space.
|
||||
*/
|
||||
res = __bitmap_parse(buf, count, 0, cpumask_bits(&work->cpu_mask),
|
||||
nr_cpumask_bits);
|
||||
res = bitmap_parse(buf, count, cpumask_bits(&work->cpu_mask),
|
||||
nr_cpumask_bits);
|
||||
if (res != 0) {
|
||||
PRINT_ERROR("__bitmap_parse() failed: %d", res);
|
||||
PRINT_ERROR("bitmap_parse() failed: %d", res);
|
||||
goto out_release;
|
||||
}
|
||||
|
||||
@@ -2513,7 +2513,45 @@ static struct kobj_attribute scst_rel_tgt_id =
|
||||
__ATTR(rel_tgt_id, S_IRUGO | S_IWUSR, scst_rel_tgt_id_show,
|
||||
scst_rel_tgt_id_store);
|
||||
|
||||
static ssize_t scst_tgt_forwarding_show(struct kobject *kobj,
|
||||
static ssize_t scst_tgt_forward_src_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
struct scst_tgt *tgt = container_of(kobj, struct scst_tgt, tgt_kobj);
|
||||
|
||||
return sprintf(buf, "%d\n%s", tgt->tgt_forward_src,
|
||||
tgt->tgt_forward_src ? SCST_SYSFS_KEY_MARK "\n" : "");
|
||||
}
|
||||
|
||||
static ssize_t scst_tgt_forward_src_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct scst_tgt *tgt = container_of(kobj, struct scst_tgt, tgt_kobj);
|
||||
int res, old, new;
|
||||
|
||||
res = kstrtoint(buf, 0, &new);
|
||||
if (res < 0)
|
||||
return res;
|
||||
if (new < 0 || new > 1)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&scst_mutex);
|
||||
old = tgt->tgt_forward_src;
|
||||
if (old != new) {
|
||||
tgt->tgt_forward_src = new;
|
||||
PRINT_INFO("%s target %s as forwarding source",
|
||||
tgt->tgt_forward_src ? "Set" : "Clear",
|
||||
tgt->tgt_name);
|
||||
}
|
||||
mutex_unlock(&scst_mutex);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct kobj_attribute scst_tgt_forward_src =
|
||||
__ATTR(forward_src, S_IRUGO | S_IWUSR, scst_tgt_forward_src_show,
|
||||
scst_tgt_forward_src_store);
|
||||
|
||||
static ssize_t scst_tgt_forward_dst_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
struct scst_tgt *tgt;
|
||||
@@ -2523,14 +2561,14 @@ static ssize_t scst_tgt_forwarding_show(struct kobject *kobj,
|
||||
|
||||
tgt = container_of(kobj, struct scst_tgt, tgt_kobj);
|
||||
|
||||
res = sprintf(buf, "%d\n%s", tgt->tgt_forwarding,
|
||||
tgt->tgt_forwarding ? SCST_SYSFS_KEY_MARK "\n" : "");
|
||||
res = sprintf(buf, "%d\n%s", tgt->tgt_forward_dst,
|
||||
tgt->tgt_forward_dst ? SCST_SYSFS_KEY_MARK "\n" : "");
|
||||
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static ssize_t scst_tgt_forwarding_store(struct kobject *kobj,
|
||||
static ssize_t scst_tgt_forward_dst_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
int res = 0;
|
||||
@@ -2549,14 +2587,14 @@ static ssize_t scst_tgt_forwarding_store(struct kobject *kobj,
|
||||
|
||||
mutex_lock(&scst_mutex);
|
||||
|
||||
old = tgt->tgt_forwarding;
|
||||
old = tgt->tgt_forward_dst;
|
||||
|
||||
switch (buf[0]) {
|
||||
case '0':
|
||||
tgt->tgt_forwarding = 0;
|
||||
tgt->tgt_forward_dst = 0;
|
||||
break;
|
||||
case '1':
|
||||
tgt->tgt_forwarding = 1;
|
||||
tgt->tgt_forward_dst = 1;
|
||||
break;
|
||||
default:
|
||||
PRINT_ERROR("%s: Requested action not understood: %s",
|
||||
@@ -2565,7 +2603,7 @@ static ssize_t scst_tgt_forwarding_store(struct kobject *kobj,
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (tgt->tgt_forwarding == old)
|
||||
if (tgt->tgt_forward_dst == old)
|
||||
goto out_unlock;
|
||||
|
||||
list_for_each_entry(sess, &tgt->sess_list, sess_list_entry) {
|
||||
@@ -2576,18 +2614,22 @@ static ssize_t scst_tgt_forwarding_store(struct kobject *kobj,
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
|
||||
list_for_each_entry(tgt_dev, head, sess_tgt_dev_list_entry) {
|
||||
if (tgt->tgt_forwarding)
|
||||
set_bit(SCST_TGT_DEV_FORWARDING, &tgt_dev->tgt_dev_flags);
|
||||
if (tgt->tgt_forward_dst)
|
||||
set_bit(SCST_TGT_DEV_FORWARD_DST,
|
||||
&tgt_dev->tgt_dev_flags);
|
||||
else
|
||||
clear_bit(SCST_TGT_DEV_FORWARDING, &tgt_dev->tgt_dev_flags);
|
||||
clear_bit(SCST_TGT_DEV_FORWARD_DST,
|
||||
&tgt_dev->tgt_dev_flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tgt->tgt_forwarding)
|
||||
PRINT_INFO("Set target %s as forwarding", tgt->tgt_name);
|
||||
if (tgt->tgt_forward_dst)
|
||||
PRINT_INFO("Set target %s as forwarding destination",
|
||||
tgt->tgt_name);
|
||||
else
|
||||
PRINT_INFO("Clear target %s as forwarding", tgt->tgt_name);
|
||||
PRINT_INFO("Clear target %s as forwarding destination",
|
||||
tgt->tgt_name);
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&scst_mutex);
|
||||
@@ -2600,9 +2642,14 @@ out:
|
||||
return res;
|
||||
}
|
||||
|
||||
static struct kobj_attribute scst_tgt_forward_dst =
|
||||
__ATTR(forward_dst, S_IRUGO | S_IWUSR, scst_tgt_forward_dst_show,
|
||||
scst_tgt_forward_dst_store);
|
||||
|
||||
// To do: remove the 'forwarding' sysfs attribute and keep 'forward_dst'.
|
||||
static struct kobj_attribute scst_tgt_forwarding =
|
||||
__ATTR(forwarding, S_IRUGO | S_IWUSR, scst_tgt_forwarding_show,
|
||||
scst_tgt_forwarding_store);
|
||||
__ATTR(forwarding, S_IRUGO | S_IWUSR, scst_tgt_forward_dst_show,
|
||||
scst_tgt_forward_dst_store);
|
||||
|
||||
static ssize_t scst_tgt_comment_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
@@ -2876,6 +2923,8 @@ SCST_TGT_SYSFS_STAT_ATTR(cmd_count, none_cmd_count, SCST_DATA_NONE, >> 0);
|
||||
|
||||
static struct attribute *scst_tgt_attrs[] = {
|
||||
&scst_rel_tgt_id.attr,
|
||||
&scst_tgt_forward_src.attr,
|
||||
&scst_tgt_forward_dst.attr,
|
||||
&scst_tgt_forwarding.attr,
|
||||
&scst_tgt_comment.attr,
|
||||
&scst_tgt_addr_method.attr,
|
||||
|
||||
@@ -2363,7 +2363,8 @@ int __scst_check_local_events(struct scst_cmd *cmd, bool preempt_tests_only)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (unlikely(test_bit(SCST_TGT_DEV_FORWARDING, &cmd->tgt_dev->tgt_dev_flags))) {
|
||||
if (unlikely(test_bit(SCST_TGT_DEV_FORWARD_DST,
|
||||
&cmd->tgt_dev->tgt_dev_flags))) {
|
||||
/*
|
||||
* All the checks are supposed to be done on the
|
||||
* forwarding requester's side.
|
||||
@@ -2707,6 +2708,7 @@ static scst_local_exec_fn scst_local_fns[256] = {
|
||||
[EXTENDED_COPY] = scst_cm_ext_copy_exec,
|
||||
[RECEIVE_COPY_RESULTS] = scst_cm_rcv_copy_res_exec,
|
||||
[MAINTENANCE_IN] = scst_maintenance_in,
|
||||
[MAINTENANCE_OUT] = scst_maintenance_out,
|
||||
};
|
||||
|
||||
static enum scst_exec_res scst_do_local_exec(struct scst_cmd *cmd)
|
||||
|
||||
+179
-154
@@ -1663,6 +1663,169 @@ static void scst_stpg_ext_blocking_done(struct scst_device *dev,
|
||||
scst_stpg_check_blocking_done(*((struct scst_stpg_wait **)data));
|
||||
}
|
||||
|
||||
/**
|
||||
* struct osi - Information needed to process an STPG command.
|
||||
*
|
||||
* The 'on' in 'osi' refers to 'on_stpg', a concept from the ION SCST code base
|
||||
* that has not yet been ported.
|
||||
*
|
||||
* @group_id: Target port group ID.
|
||||
* @tg: Target port group.
|
||||
* @prev_state: previous target port group ALUA state.
|
||||
* @new_state: new target port group ALUA state.
|
||||
*/
|
||||
struct osi {
|
||||
uint16_t group_id;
|
||||
struct scst_target_group *tg;
|
||||
enum scst_tg_state prev_state;
|
||||
enum scst_tg_state new_state;
|
||||
};
|
||||
|
||||
static int scst_emit_stpg_event(struct scst_cmd *cmd, struct scst_dev_group *dg,
|
||||
struct osi *osi, int tpg_desc_count)
|
||||
{
|
||||
int j, payload_len, event_entry_len, valid_desc_count, res;
|
||||
struct scst_event_stpg_payload *payload;
|
||||
struct scst_event_entry *event_entry;
|
||||
struct scst_event_stpg_descr *descr;
|
||||
struct scst_device *dev = cmd->dev;
|
||||
struct scst_stpg_wait *wait;
|
||||
struct scst_event *event;
|
||||
struct scst_dg_dev *dgd;
|
||||
|
||||
payload_len = sizeof(*payload) + sizeof(*descr) * tpg_desc_count;
|
||||
event_entry_len = sizeof(*event_entry) + payload_len;
|
||||
event_entry = kzalloc(event_entry_len, GFP_KERNEL);
|
||||
if (event_entry == NULL) {
|
||||
PRINT_ERROR("Unable to allocate event (size %d)", event_entry_len);
|
||||
res = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
TRACE_MEM("event_entry %p (len %d) allocated", event_entry,
|
||||
event_entry_len);
|
||||
|
||||
event = &event_entry->event;
|
||||
event->payload_len = payload_len;
|
||||
|
||||
payload = (struct scst_event_stpg_payload *)event->payload;
|
||||
payload->stpg_cmd_tag = cmd->tag;
|
||||
|
||||
res = 1;
|
||||
|
||||
if (strlcpy(payload->device_name, dev->virt_name,
|
||||
sizeof(payload->device_name)) >=
|
||||
sizeof(payload->device_name)) {
|
||||
PRINT_ERROR("Device name %s too long", dev->virt_name);
|
||||
goto out_too_long;
|
||||
}
|
||||
|
||||
valid_desc_count = 0;
|
||||
for (j = 0, descr = &payload->stpg_descriptors[0]; j < tpg_desc_count;
|
||||
j++) {
|
||||
if (osi[j].prev_state == osi[j].new_state)
|
||||
continue;
|
||||
|
||||
if (strlcpy(descr->prev_state,
|
||||
scst_alua_state_name(osi[j].prev_state),
|
||||
sizeof(descr->prev_state)) >=
|
||||
sizeof(descr->prev_state) ||
|
||||
strlcpy(descr->new_state,
|
||||
scst_alua_state_name(osi[j].new_state),
|
||||
sizeof(descr->new_state)) >=
|
||||
sizeof(descr->new_state) ||
|
||||
strlcpy(descr->dg_name, dg->name, sizeof(descr->dg_name))
|
||||
>= sizeof(descr->dg_name) ||
|
||||
strlcpy(descr->tg_name, osi[j].tg->name,
|
||||
sizeof(descr->tg_name)) >=
|
||||
sizeof(descr->tg_name))
|
||||
goto out_too_long;
|
||||
|
||||
descr->group_id = osi[j].group_id;
|
||||
|
||||
TRACE_DBG("group_id %u, prev_state %s, new_state %s, dg_name %s, tg_name %s",
|
||||
descr->group_id, descr->prev_state, descr->new_state,
|
||||
descr->dg_name, descr->tg_name);
|
||||
|
||||
valid_desc_count++;
|
||||
descr++;
|
||||
}
|
||||
|
||||
payload->stpg_descriptors_cnt = valid_desc_count;
|
||||
|
||||
if (valid_desc_count == 0) {
|
||||
TRACE_DBG("Nothing to do");
|
||||
goto out;
|
||||
}
|
||||
|
||||
dg->stpg_rel_tgt_id = cmd->tgt->rel_tgt_id;
|
||||
dg->stpg_transport_id = kmemdup(cmd->sess->transport_id,
|
||||
scst_tid_size(cmd->sess->transport_id), GFP_KERNEL);
|
||||
if (dg->stpg_transport_id == NULL) {
|
||||
PRINT_ERROR("Unable to duplicate stpg_transport_id");
|
||||
goto out;
|
||||
}
|
||||
|
||||
wait = kzalloc(sizeof(*wait), GFP_KERNEL);
|
||||
if (wait == NULL) {
|
||||
PRINT_ERROR("Unable to allocate STPG wait struct "
|
||||
"(size %zd)", sizeof(*wait));
|
||||
res = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
atomic_set(&wait->stpg_wait_left, 1);
|
||||
wait->event_entry = event_entry;
|
||||
|
||||
event_entry->event_notify_fn = scst_event_stpg_notify_fn;
|
||||
event_entry->notify_fn_priv = cmd;
|
||||
|
||||
mutex_lock(&scst_dg_mutex);
|
||||
list_for_each_entry(dgd, &dg->dev_list, entry) {
|
||||
int rc;
|
||||
|
||||
if (dgd->dev == dev)
|
||||
continue;
|
||||
|
||||
TRACE_DBG("STPG: ext blocking dev %s",
|
||||
dgd->dev->virt_name);
|
||||
|
||||
atomic_inc(&wait->stpg_wait_left);
|
||||
|
||||
rc = scst_ext_block_dev(dgd->dev,
|
||||
scst_stpg_ext_blocking_done,
|
||||
(uint8_t *)&wait, sizeof(wait),
|
||||
SCST_EXT_BLOCK_STPG);
|
||||
if (rc != 0) {
|
||||
TRACE_DBG("scst_ext_block_dev() failed "
|
||||
"with %d, reverting (cmd %p)", rc, cmd);
|
||||
wait->status = rc;
|
||||
wait->dg = dg;
|
||||
atomic_dec(&wait->stpg_wait_left);
|
||||
spin_lock_bh(&dev->dev_lock);
|
||||
WARN_ON(dgd->dev->stpg_ext_blocked);
|
||||
dgd->dev->stpg_ext_blocked = 0;
|
||||
spin_unlock_bh(&dev->dev_lock);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&scst_dg_mutex);
|
||||
|
||||
scst_stpg_check_blocking_done(wait);
|
||||
/* !! cmd can be already dead here !! */
|
||||
|
||||
return 0;
|
||||
|
||||
out_too_long:
|
||||
res = -EOVERFLOW;
|
||||
|
||||
out:
|
||||
kfree(dg->stpg_transport_id);
|
||||
dg->stpg_transport_id = NULL;
|
||||
kfree(event_entry);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* scst_tg_set_group_info - SET TARGET PORT GROUPS implementation.
|
||||
*
|
||||
@@ -1679,19 +1842,9 @@ int scst_tg_set_group_info(struct scst_cmd *cmd)
|
||||
struct scst_device *dev = cmd->dev;
|
||||
uint8_t *buf;
|
||||
int len;
|
||||
int i, j, res = 1, tpg_desc_count, valid_desc_count;
|
||||
int i, j, res = 1, tpg_desc_count;
|
||||
struct scst_dev_group *dg;
|
||||
struct osi {
|
||||
uint16_t group_id;
|
||||
struct scst_target_group *tg;
|
||||
enum scst_tg_state prev_state;
|
||||
enum scst_tg_state new_state;
|
||||
} *osi = NULL;
|
||||
int event_entry_len, payload_len;
|
||||
struct scst_event_entry *event_entry;
|
||||
struct scst_event *event;
|
||||
struct scst_event_stpg_payload *payload;
|
||||
struct scst_event_stpg_descr *descr;
|
||||
struct osi *osi = NULL;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
@@ -1816,140 +1969,23 @@ int scst_tg_set_group_info(struct scst_cmd *cmd)
|
||||
|
||||
scst_put_buf_full(cmd, buf);
|
||||
|
||||
payload_len = sizeof(*payload) + sizeof(*descr) * tpg_desc_count;
|
||||
event_entry_len = sizeof(*event_entry) + payload_len;
|
||||
event_entry = kzalloc(event_entry_len, GFP_KERNEL);
|
||||
if (event_entry == NULL) {
|
||||
PRINT_ERROR("Unable to allocate event (size %d)", event_entry_len);
|
||||
res = -ENOMEM;
|
||||
res = scst_emit_stpg_event(cmd, dg, osi, tpg_desc_count);
|
||||
switch (res) {
|
||||
case 1:
|
||||
case 0:
|
||||
break;
|
||||
case -ENOMEM:
|
||||
scst_set_busy(cmd);
|
||||
goto out_free;
|
||||
break;
|
||||
default:
|
||||
WARN_ONCE(true, "res = %d\n", res);
|
||||
/* fall through */
|
||||
case -EOVERFLOW:
|
||||
scst_set_cmd_error(cmd,
|
||||
SCST_LOAD_SENSE(scst_sense_set_target_pgs_failed));
|
||||
break;
|
||||
}
|
||||
|
||||
TRACE_MEM("event_entry %p (len %d) allocated", event_entry,
|
||||
event_entry_len);
|
||||
|
||||
event = &event_entry->event;
|
||||
event->payload_len = payload_len;
|
||||
|
||||
payload = (struct scst_event_stpg_payload *)event->payload;
|
||||
payload->stpg_cmd_tag = cmd->tag;
|
||||
|
||||
res = 1;
|
||||
|
||||
if (strlen(dev->virt_name) >= sizeof(payload->device_name)) {
|
||||
PRINT_ERROR("Device name %s too long", dev->virt_name);
|
||||
goto out_too_long;
|
||||
}
|
||||
strlcpy(payload->device_name, dev->virt_name, sizeof(payload->device_name));
|
||||
|
||||
valid_desc_count = 0;
|
||||
for (j = 0, descr = &payload->stpg_descriptors[0]; j < tpg_desc_count; j++) {
|
||||
if (osi[j].prev_state == osi[j].new_state)
|
||||
continue;
|
||||
|
||||
if (strlen(scst_alua_state_name(osi[j].prev_state)) >= sizeof(descr->prev_state)) {
|
||||
PRINT_ERROR("prev state too long (%d)", osi[j].prev_state);
|
||||
goto out_too_long;
|
||||
}
|
||||
strlcpy(descr->prev_state, scst_alua_state_name(osi[j].prev_state),
|
||||
sizeof(descr->prev_state));
|
||||
|
||||
if (strlen(scst_alua_state_name(osi[j].new_state)) >= sizeof(descr->new_state)) {
|
||||
PRINT_ERROR("new state too long (%d)", osi[j].new_state);
|
||||
goto out_too_long;
|
||||
}
|
||||
strlcpy(descr->new_state, scst_alua_state_name(osi[j].new_state),
|
||||
sizeof(descr->new_state));
|
||||
|
||||
if (strlen(dg->name) >= sizeof(descr->dg_name)) {
|
||||
PRINT_ERROR("dg_name too long (%s)", dg->name);
|
||||
goto out_too_long;
|
||||
}
|
||||
strlcpy(descr->dg_name, dg->name, sizeof(descr->dg_name));
|
||||
|
||||
if (strlen(osi[j].tg->name) >= sizeof(descr->tg_name)) {
|
||||
PRINT_ERROR("tg_name too long (%s)", osi[j].tg->name);
|
||||
goto out_too_long;
|
||||
}
|
||||
strlcpy(descr->tg_name, osi[j].tg->name,
|
||||
sizeof(descr->tg_name));
|
||||
|
||||
descr->group_id = osi[j].group_id;
|
||||
|
||||
TRACE_DBG("group_id %u, prev_state %s, new_state %s, dg_name %s, "
|
||||
"tg_name %s", descr->group_id, descr->prev_state,
|
||||
descr->new_state, descr->dg_name, descr->tg_name);
|
||||
|
||||
valid_desc_count++;
|
||||
descr++;
|
||||
}
|
||||
|
||||
payload->stpg_descriptors_cnt = valid_desc_count;
|
||||
|
||||
if (valid_desc_count > 0) {
|
||||
struct scst_dg_dev *dgd;
|
||||
struct scst_stpg_wait *wait;
|
||||
int rc;
|
||||
|
||||
dg->stpg_rel_tgt_id = cmd->tgt->rel_tgt_id;
|
||||
dg->stpg_transport_id = kmemdup(cmd->sess->transport_id,
|
||||
scst_tid_size(cmd->sess->transport_id), GFP_KERNEL);
|
||||
if (dg->stpg_transport_id == NULL) {
|
||||
PRINT_ERROR("Unable to duplicate stpg_transport_id");
|
||||
goto out_free_event;
|
||||
}
|
||||
|
||||
wait = kzalloc(sizeof(*wait), GFP_KERNEL);
|
||||
if (wait == NULL) {
|
||||
PRINT_ERROR("Unable to allocate STPG wait struct "
|
||||
"(size %zd)", sizeof(*wait));
|
||||
scst_set_busy(cmd);
|
||||
res = -ENOMEM;
|
||||
goto out_free_tr_id;
|
||||
}
|
||||
|
||||
atomic_set(&wait->stpg_wait_left, 1);
|
||||
wait->event_entry = event_entry;
|
||||
|
||||
event_entry->event_notify_fn = scst_event_stpg_notify_fn;
|
||||
event_entry->notify_fn_priv = cmd;
|
||||
|
||||
mutex_lock(&scst_dg_mutex);
|
||||
list_for_each_entry(dgd, &dg->dev_list, entry) {
|
||||
if (dgd->dev == dev)
|
||||
continue;
|
||||
|
||||
TRACE_DBG("STPG: ext blocking dev %s", dgd->dev->virt_name);
|
||||
|
||||
atomic_inc(&wait->stpg_wait_left);
|
||||
|
||||
rc = scst_ext_block_dev(dgd->dev, scst_stpg_ext_blocking_done,
|
||||
(uint8_t *)&wait, sizeof(wait), SCST_EXT_BLOCK_STPG);
|
||||
if (rc != 0) {
|
||||
TRACE_DBG("scst_ext_block_dev() failed "
|
||||
"with %d, reverting (cmd %p)", rc, cmd);
|
||||
wait->status = rc;
|
||||
wait->dg = dg;
|
||||
atomic_dec(&wait->stpg_wait_left);
|
||||
spin_lock_bh(&dev->dev_lock);
|
||||
WARN_ON(dgd->dev->stpg_ext_blocked);
|
||||
dgd->dev->stpg_ext_blocked = 0;
|
||||
spin_unlock_bh(&dev->dev_lock);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&scst_dg_mutex);
|
||||
|
||||
scst_stpg_check_blocking_done(wait);
|
||||
/* !! cmd can be already dead here !! */
|
||||
} else {
|
||||
TRACE_DBG("Nothing to do");
|
||||
goto out_free_event;
|
||||
}
|
||||
|
||||
res = 0;
|
||||
|
||||
out_free:
|
||||
kfree(osi);
|
||||
|
||||
@@ -1968,16 +2004,5 @@ out_unlock_sm_fail:
|
||||
out_put:
|
||||
scst_put_buf_full(cmd, buf);
|
||||
goto out_free;
|
||||
|
||||
out_too_long:
|
||||
scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_set_target_pgs_failed));
|
||||
res = -EOVERFLOW;
|
||||
|
||||
out_free_tr_id:
|
||||
kfree(dg->stpg_transport_id);
|
||||
|
||||
out_free_event:
|
||||
kfree(event_entry);
|
||||
goto out_free;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scst_tg_set_group_info);
|
||||
|
||||
Reference in New Issue
Block a user