struct target_fabric_configfs *tf = wwn->wwn_tf;
 
        configfs_remove_default_groups(&wwn->fabric_stat_group);
+       configfs_remove_default_groups(&wwn->param_group);
        tf->tf_ops->fabric_drop_wwn(wwn);
 }
 
 
 /* End of tfc_wwn_fabric_stats_cit */
 
+static ssize_t
+target_fabric_wwn_cmd_completion_affinity_show(struct config_item *item,
+                                              char *page)
+{
+       struct se_wwn *wwn = container_of(to_config_group(item), struct se_wwn,
+                                         param_group);
+       return sprintf(page, "%d\n",
+                      wwn->cmd_compl_affinity == WORK_CPU_UNBOUND ?
+                      SE_COMPL_AFFINITY_CURR_CPU : wwn->cmd_compl_affinity);
+}
+
+static ssize_t
+target_fabric_wwn_cmd_completion_affinity_store(struct config_item *item,
+                                               const char *page, size_t count)
+{
+       struct se_wwn *wwn = container_of(to_config_group(item), struct se_wwn,
+                                         param_group);
+       int compl_val;
+
+       if (kstrtoint(page, 0, &compl_val))
+               return -EINVAL;
+
+       switch (compl_val) {
+       case SE_COMPL_AFFINITY_CPUID:
+               wwn->cmd_compl_affinity = compl_val;
+               break;
+       case SE_COMPL_AFFINITY_CURR_CPU:
+               wwn->cmd_compl_affinity = WORK_CPU_UNBOUND;
+               break;
+       default:
+               if (compl_val < 0 || compl_val >= nr_cpu_ids ||
+                   !cpu_online(compl_val)) {
+                       pr_err("Command completion value must be between %d and %d or an online CPU.\n",
+                              SE_COMPL_AFFINITY_CPUID,
+                              SE_COMPL_AFFINITY_CURR_CPU);
+                       return -EINVAL;
+               }
+               wwn->cmd_compl_affinity = compl_val;
+       }
+
+       return count;
+}
+CONFIGFS_ATTR(target_fabric_wwn_, cmd_completion_affinity);
+
+static struct configfs_attribute *target_fabric_wwn_param_attrs[] = {
+       &target_fabric_wwn_attr_cmd_completion_affinity,
+       NULL,
+};
+
+TF_CIT_SETUP(wwn_param, NULL, NULL, target_fabric_wwn_param_attrs);
+
 /* Start of tfc_wwn_cit */
 
 static struct config_group *target_fabric_make_wwn(
        if (!wwn || IS_ERR(wwn))
                return ERR_PTR(-EINVAL);
 
+       wwn->cmd_compl_affinity = SE_COMPL_AFFINITY_CPUID;
        wwn->wwn_tf = tf;
 
        config_group_init_type_name(&wwn->wwn_group, name, &tf->tf_tpg_cit);
                        &tf->tf_wwn_fabric_stats_cit);
        configfs_add_default_group(&wwn->fabric_stat_group, &wwn->wwn_group);
 
+       config_group_init_type_name(&wwn->param_group, "param",
+                       &tf->tf_wwn_param_cit);
+       configfs_add_default_group(&wwn->param_group, &wwn->wwn_group);
+
        if (tf->tf_ops->add_wwn_groups)
                tf->tf_ops->add_wwn_groups(wwn);
        return &wwn->wwn_group;
        target_fabric_setup_discovery_cit(tf);
        target_fabric_setup_wwn_cit(tf);
        target_fabric_setup_wwn_fabric_stats_cit(tf);
+       target_fabric_setup_wwn_param_cit(tf);
        target_fabric_setup_tpg_cit(tf);
        target_fabric_setup_tpg_base_cit(tf);
        target_fabric_setup_tpg_port_cit(tf);
 
 /* May be called from interrupt context so must not sleep. */
 void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status)
 {
-       int success;
+       struct se_wwn *wwn = cmd->se_sess->se_tpg->se_tpg_wwn;
+       int success, cpu;
        unsigned long flags;
 
        if (target_cmd_interrupted(cmd))
 
        INIT_WORK(&cmd->work, success ? target_complete_ok_work :
                  target_complete_failure_work);
-       queue_work_on(cmd->cpuid, target_completion_wq, &cmd->work);
+
+       if (wwn->cmd_compl_affinity == SE_COMPL_AFFINITY_CPUID)
+               cpu = cmd->cpuid;
+       else
+               cpu = wwn->cmd_compl_affinity;
+
+       queue_work_on(cpu, target_completion_wq, &cmd->work);
 }
 EXPORT_SYMBOL(target_complete_cmd);