diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index e9cac69fd..84f08d2f9 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -5106,80 +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; - int res = CMD_SUCCEEDED, rc; - - TRACE_ENTRY(); - - 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) - 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) { @@ -5196,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) diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 8380794dc..9675cea8c 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -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 757edba71..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; 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_targ.c b/scst/src/scst_targ.c index 565536286..6726d4845 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -2708,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)