diff --git a/scst/ChangeLog b/scst/ChangeLog index 8176681bd..140030676 100644 --- a/scst/ChangeLog +++ b/scst/ChangeLog @@ -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 diff --git a/scst/README b/scst/README index b58f9baa2..64b7ea8e5 100644 --- a/scst/README +++ b/scst/README @@ -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 diff --git a/scst/include/backport.h b/scst/include/backport.h index 32d624d5d..566ad0112 100644 --- a/scst/include/backport.h +++ b/scst/include/backport.h @@ -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) diff --git a/scst/include/scst.h b/scst/include/scst.h index 118629bb6..4797753df 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -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 @@ -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. diff --git a/scst/src/dev_handlers/scst_disk.c b/scst/src/dev_handlers/scst_disk.c index cd2ab0bff..785d4bcf7 100644 --- a/scst/src/dev_handlers/scst_disk.c +++ b/scst/src/dev_handlers/scst_disk.c @@ -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 diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index 7e320d069..84f08d2f9 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -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); diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index e3c832110..9675cea8c 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -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; diff --git a/scst/src/scst_local_cmd.c b/scst/src/scst_local_cmd.c index 2abea3b0b..845207509 100644 --- a/scst/src/scst_local_cmd.c +++ b/scst/src/scst_local_cmd.c @@ -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)) diff --git a/scst/src/scst_local_cmd.h b/scst/src/scst_local_cmd.h index 89809167b..a058aa131 100644 --- a/scst/src/scst_local_cmd.h +++ b/scst/src/scst_local_cmd.h @@ -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); diff --git a/scst/src/scst_main.c b/scst/src/scst_main.c index f03210d4e..21c1fd517 100644 --- a/scst/src/scst_main.c +++ b/scst/src/scst_main.c @@ -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); diff --git a/scst/src/scst_pres.c b/scst/src/scst_pres.c index b3022c644..99c9e44db 100644 --- a/scst/src/scst_pres.c +++ b/scst/src/scst_pres.c @@ -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; diff --git a/scst/src/scst_sysfs.c b/scst/src/scst_sysfs.c index 3d6bc0432..7381dee96 100644 --- a/scst/src/scst_sysfs.c +++ b/scst/src/scst_sysfs.c @@ -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, diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index 12ea2ce1e..6726d4845 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -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) diff --git a/scst/src/scst_tg.c b/scst/src/scst_tg.c index 0f0fb9fcf..8b6b1a6f6 100644 --- a/scst/src/scst_tg.c +++ b/scst/src/scst_tg.c @@ -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);