From b1c8432588e75af8cf83c500319115043f19ff15 Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Sat, 21 Feb 2015 04:07:53 +0000 Subject: [PATCH] Merged revisions 5933,5940 via svnmerge from svn+ssh://vlnb@svn.code.sf.net/p/scst/svn/trunk ........ r5933 | vlnb | 2014-12-10 20:38:04 -0800 (Wed, 10 Dec 2014) | 11 lines vdisk_blockio: Report invalid scatterlists It is possible for a target driver to pass a scatterlist via scst_cmd_set_tgt_sg() that is valid for the vdisk_fileio handler but not for the vdisk_blockio handler. Complain loudly if an invalid scatterlist is passed to vdisk_blockio because such scatterlists cause silent data corruption with most Linux block drivers. Signed-off-by: Bart Van Assche ........ r5940 | vlnb | 2014-12-18 19:55:14 -0800 (Thu, 18 Dec 2014) | 7 lines Replace in cases, where sporadic failures are possible, HARDWARE ERROR by INTERNAL TARGET FAILURE, which is retriable (some OS'es don't retry HARDWARE ERROR) Reported and suggested by Shahar Salzman ........ git-svn-id: http://svn.code.sf.net/p/scst/svn/branches/3.0.x@6109 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- qla2x00t/qla2x00-target/qla2x00t.c | 6 +++-- scst/include/scst_const.h | 3 ++- scst/src/dev_handlers/scst_disk.c | 2 +- scst/src/dev_handlers/scst_tape.c | 2 +- scst/src/dev_handlers/scst_user.c | 24 +++++++++---------- scst/src/dev_handlers/scst_vdisk.c | 38 ++++++++++++++++++++---------- scst/src/scst_lib.c | 6 ++--- scst/src/scst_pres.c | 2 +- scst/src/scst_targ.c | 8 +++---- usr/fileio/common.c | 2 +- 10 files changed, 55 insertions(+), 38 deletions(-) diff --git a/qla2x00t/qla2x00-target/qla2x00t.c b/qla2x00t/qla2x00-target/qla2x00t.c index 3741f88fa..85e81b59e 100644 --- a/qla2x00t/qla2x00-target/qla2x00t.c +++ b/qla2x00t/qla2x00-target/qla2x00t.c @@ -5823,8 +5823,10 @@ static void q2t_on_hw_pending_cmd_timeout(struct scst_cmd *scst_cmd) q2t_cleanup_hw_pending_cmd(ha, cmd); - scst_rx_data(scst_cmd, SCST_RX_STATUS_ERROR_FATAL, - SCST_CONTEXT_THREAD); + /* It might be sporadic, hence retriable */ + scst_set_cmd_error(scst_cmd, + SCST_LOAD_SENSE(scst_sense_internal_failure)); + scst_rx_data(scst_cmd, SCST_RX_STATUS_ERROR_SENSE_SET, SCST_CONTEXT_THREAD); goto out_unlock; } else if (cmd->state == Q2T_STATE_ABORTED) { TRACE_MGMT_DBG("Force finishing aborted cmd %p (tag %d)", diff --git a/scst/include/scst_const.h b/scst/include/scst_const.h index c18f874fa..c1b5f4440 100644 --- a/scst/include/scst_const.h +++ b/scst/include/scst_const.h @@ -298,7 +298,7 @@ static inline int scst_sense_response_code(const uint8_t *sense) #define scst_sense_read_error MEDIUM_ERROR, 0x11, 0 /* HARDWARE_ERROR is 4 */ -#define scst_sense_hardw_error HARDWARE_ERROR, 0x44, 0 +#define scst_sense_hardw_error HARDWARE_ERROR, 0x44, 0 /* non-retriable */ /* ILLEGAL_REQUEST is 5 */ #define scst_sense_invalid_opcode ILLEGAL_REQUEST, 0x20, 0 @@ -333,6 +333,7 @@ static inline int scst_sense_response_code(const uint8_t *sense) /* ABORTED_COMMAND is 0xb */ #define scst_sense_aborted_command ABORTED_COMMAND, 0x00, 0 +#define scst_sense_internal_failure ABORTED_COMMAND, 0x44, 0 /* retriable */ /* MISCOMPARE is 0xe */ #define scst_sense_miscompare_error MISCOMPARE, 0x1D, 0 diff --git a/scst/src/dev_handlers/scst_disk.c b/scst/src/dev_handlers/scst_disk.c index 684aca4ff..555c8c093 100644 --- a/scst/src/dev_handlers/scst_disk.c +++ b/scst/src/dev_handlers/scst_disk.c @@ -536,7 +536,7 @@ out: return res; out_err_restore: - scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error)); + scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_internal_failure)); goto out_restore; out_error: diff --git a/scst/src/dev_handlers/scst_tape.c b/scst/src/dev_handlers/scst_tape.c index ec4e85bc8..4aeba2417 100644 --- a/scst/src/dev_handlers/scst_tape.c +++ b/scst/src/dev_handlers/scst_tape.c @@ -291,7 +291,7 @@ static int tape_done(struct scst_cmd *cmd) PRINT_ERROR("Sense format 0x%x is not supported", scst_sense_response_code(cmd->sense)); scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_hardw_error)); + SCST_LOAD_SENSE(scst_sense_internal_failure)); goto out; } diff --git a/scst/src/dev_handlers/scst_user.c b/scst/src/dev_handlers/scst_user.c index 0ba4f86bc..3b0ebc8bd 100644 --- a/scst/src/dev_handlers/scst_user.c +++ b/scst/src/dev_handlers/scst_user.c @@ -1260,7 +1260,7 @@ out_unmap: ucmd->data_pages = NULL; res = -EFAULT; if (ucmd->cmd != NULL) - scst_set_cmd_error(ucmd->cmd, SCST_LOAD_SENSE(scst_sense_hardw_error)); + scst_set_cmd_error(ucmd->cmd, SCST_LOAD_SENSE(scst_sense_internal_failure)); goto out_err; } @@ -1377,8 +1377,8 @@ out_inval: res = -EINVAL; goto out_abnormal; -out_hwerr_res_set: - scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error)); +out_intern_fail_res_set: + scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_internal_failure)); out_abnormal: scst_set_cmd_abnormal_done_state(cmd); @@ -1393,7 +1393,7 @@ out_status: res = scst_alloc_sense(cmd, 0); if (res != 0) - goto out_hwerr_res_set; + goto out_intern_fail_res_set; sense_len = min_t(int, cmd->sense_buflen, preply->sense_len); @@ -1403,7 +1403,7 @@ out_status: if (rc != 0) { PRINT_ERROR("Failed to copy %d sense's bytes", rc); res = -EFAULT; - goto out_hwerr_res_set; + goto out_intern_fail_res_set; } cmd->sense_valid_len = sense_len; } @@ -1495,7 +1495,7 @@ static int dev_user_process_reply_exec(struct scst_user_cmd *ucmd, if (unlikely((ereply->pbuf & ~PAGE_MASK) != 0)) { PRINT_ERROR("Supplied pbuf %llx isn't " "page aligned", ereply->pbuf); - goto out_hwerr; + goto out_intern_fail; } pages = cmd->sg_cnt; } else @@ -1540,7 +1540,7 @@ static int dev_user_process_reply_exec(struct scst_user_cmd *ucmd, if (rc != 0) { PRINT_ERROR("Failed to copy %d sense's bytes", rc); res = -EFAULT; - goto out_hwerr_res_set; + goto out_intern_fail_res_set; } cmd->sense_valid_len = sense_len; } @@ -1560,16 +1560,16 @@ out_inval: (long long unsigned int)cmd->lun, scst_get_opcode_name(cmd), cmd); PRINT_BUFFER("Invalid exec_reply", reply, sizeof(*reply)); -out_hwerr: +out_intern_fail: res = -EINVAL; -out_hwerr_res_set: +out_intern_fail_res_set: if (ucmd->background_exec) { ucmd_put(ucmd); goto out; } else { scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_hardw_error)); + SCST_LOAD_SENSE(scst_sense_internal_failure)); goto out_compl; } @@ -2261,7 +2261,7 @@ static void dev_user_unjam_cmd(struct scst_user_cmd *ucmd, int busy, scst_set_busy(ucmd->cmd); else scst_set_cmd_error(ucmd->cmd, - SCST_LOAD_SENSE(scst_sense_hardw_error)); + SCST_LOAD_SENSE(scst_sense_internal_failure)); } scst_set_cmd_abnormal_done_state(ucmd->cmd); @@ -2292,7 +2292,7 @@ static void dev_user_unjam_cmd(struct scst_user_cmd *ucmd, int busy, scst_set_busy(ucmd->cmd); else scst_set_cmd_error(ucmd->cmd, - SCST_LOAD_SENSE(scst_sense_hardw_error)); + SCST_LOAD_SENSE(scst_sense_internal_failure)); } ucmd->cmd->scst_cmd_done(ucmd->cmd, SCST_CMD_STATE_DEFAULT, diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index 8aa6576dc..57ee0572e 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -4787,7 +4787,7 @@ static enum compl_status_e fileio_exec_read(struct vdisk_cmd_params *p) if (unlikely(length < 0)) { PRINT_ERROR("scst_get_buf_first() failed: %zd", length); scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_hardw_error)); + SCST_LOAD_SENSE(scst_sense_internal_failure)); goto out; } @@ -4816,7 +4816,7 @@ static enum compl_status_e fileio_exec_read(struct vdisk_cmd_params *p) } else if (unlikely(length < 0)) { PRINT_ERROR("scst_get_buf_next() failed: %zd", length); scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_hardw_error)); + SCST_LOAD_SENSE(scst_sense_internal_failure)); goto out_set_fs; } @@ -4910,7 +4910,7 @@ static enum compl_status_e fileio_exec_write(struct vdisk_cmd_params *p) if (unlikely(length < 0)) { PRINT_ERROR("scst_get_buf_first() failed: %zd", length); scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_hardw_error)); + SCST_LOAD_SENSE(scst_sense_internal_failure)); goto out; } @@ -4939,7 +4939,7 @@ static enum compl_status_e fileio_exec_write(struct vdisk_cmd_params *p) } else if (unlikely(length < 0)) { PRINT_ERROR("scst_get_buf_next() failed: %zd", length); scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_hardw_error)); + SCST_LOAD_SENSE(scst_sense_internal_failure)); goto out_set_fs; } @@ -5176,8 +5176,10 @@ static void blockio_exec_rw(struct vdisk_cmd_params *p, bool write, bool fua) /* Allocate and initialize blockio_work struct */ blockio_work = kmem_cache_alloc(blockio_work_cachep, gfp_mask); - if (blockio_work == NULL) - goto out_no_mem; + if (blockio_work == NULL) { + scst_set_busy(cmd); + goto finish_cmd; + } #if 0 { @@ -5199,6 +5201,18 @@ static void blockio_exec_rw(struct vdisk_cmd_params *p, bool write, bool fua) need_new_bio = 1; length = scst_get_sg_page_first(cmd, &page, &offset); + /* + * bv_len and bv_offset must be a multiple of 512 (SECTOR_SIZE), so + * check this here. + */ + if (WARN_ONCE((length & 511) != 0 || (offset & 511) != 0, + "Refused bio with invalid length %d and/or offset %d.\n", + length, offset)) { + scst_set_cmd_error(cmd, + SCST_LOAD_SENSE(scst_sense_hardw_error)); + goto free_bio; + } + while (length > 0) { int len, bytes, off, thislen; struct page *pg; @@ -5219,7 +5233,8 @@ static void blockio_exec_rw(struct vdisk_cmd_params *p, bool write, bool fua) PRINT_ERROR("Failed to create bio " "for data segment %d (cmd %p)", cmd->get_sg_buf_entry_num, cmd); - goto out_no_bio; + scst_set_busy(cmd); + goto free_bio; } bios++; @@ -5303,7 +5318,7 @@ out: TRACE_EXIT(); return; -out_no_bio: +free_bio: while (hbio) { bio = hbio; hbio = hbio->bi_next; @@ -5311,8 +5326,7 @@ out_no_bio: } kmem_cache_free(blockio_work_cachep, blockio_work); -out_no_mem: - scst_set_busy(cmd); +finish_cmd: cmd->completed = 1; cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT, SCST_CONTEXT_SAME); goto out; @@ -5677,7 +5691,7 @@ static enum compl_status_e vdev_exec_verify(struct vdisk_cmd_params *p) if (length < 0) { PRINT_ERROR("scst_get_buf_() failed: %zd", length); scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_hardw_error)); + SCST_LOAD_SENSE(scst_sense_internal_failure)); } out_free: @@ -5735,7 +5749,7 @@ static enum compl_status_e vdisk_exec_caw(struct vdisk_cmd_params *p) scst_set_busy(cmd); else scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_hardw_error)); + SCST_LOAD_SENSE(scst_sense_internal_failure)); goto out; } diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 44132e9e8..62cd4197c 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -4959,7 +4959,7 @@ static void scst_complete_request_sense(struct scst_cmd *req_cmd) PRINT_ERROR("%s", "Unable to get the sense via " "REQUEST SENSE, returning HARDWARE ERROR"); scst_set_cmd_error(orig_cmd, - SCST_LOAD_SENSE(scst_sense_hardw_error)); + SCST_LOAD_SENSE(scst_sense_internal_failure)); } } @@ -6483,7 +6483,7 @@ int scst_get_buf_full_sense(struct scst_cmd *cmd, uint8_t **buf) scst_set_busy(cmd); else scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_hardw_error)); + SCST_LOAD_SENSE(scst_sense_internal_failure)); goto out; } @@ -10505,7 +10505,7 @@ void tm_dbg_release_cmd(struct scst_cmd *cmd) if (((scst_random() % 10) == 5)) { scst_set_cmd_error(cmd, SCST_LOAD_SENSE( - scst_sense_hardw_error)); + scst_sense_internal_failure)); /* It's completed now */ } } diff --git a/scst/src/scst_pres.c b/scst/src/scst_pres.c index cc06ac361..f17cd5e36 100644 --- a/scst/src/scst_pres.c +++ b/scst/src/scst_pres.c @@ -1032,7 +1032,7 @@ out: * the affected initiator. */ if (cmd != NULL) - scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error)); + scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_internal_failure)); #endif } diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index 175af61bf..7e43b6747 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -3516,7 +3516,7 @@ static bool scst_check_auto_sense(struct scst_cmd *cmd) "%s)", cmd->host_status, cmd, scst_get_opcode_name(cmd), cmd->tgt->tgt_name, cmd->dev->virt_name); scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_hardw_error)); + SCST_LOAD_SENSE(scst_sense_internal_failure)); } } @@ -3544,7 +3544,7 @@ static int scst_pre_dev_done(struct scst_cmd *cmd) PRINT_ERROR("%s", "Unable to issue REQUEST SENSE, " "returning HARDWARE ERROR"); scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_hardw_error)); + SCST_LOAD_SENSE(scst_sense_internal_failure)); } goto out; } @@ -3580,7 +3580,7 @@ next: "MODE_SENSE buffer"); scst_set_cmd_error(cmd, SCST_LOAD_SENSE( - scst_sense_hardw_error)); + scst_sense_internal_failure)); err = true; } else if (length > 2 && cmd->cdb[0] == MODE_SENSE) address[2] |= 0x80; /* Write Protect*/ @@ -3621,7 +3621,7 @@ next: PRINT_ERROR("%s", "Unable to get INQUIRY " "buffer"); scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_hardw_error)); + SCST_LOAD_SENSE(scst_sense_internal_failure)); err = true; } if (buflen > 0) diff --git a/usr/fileio/common.c b/usr/fileio/common.c index ac98120af..75d09a7d7 100644 --- a/usr/fileio/common.c +++ b/usr/fileio/common.c @@ -209,7 +209,7 @@ static int do_exec(struct vdisk_cmd *vcmd) #ifdef DEBUG_SENSE if ((random() % 100000) == 75) { - set_cmd_error(vcmd, SCST_LOAD_SENSE(scst_sense_hardw_error)); + set_cmd_error(vcmd, SCST_LOAD_SENSE(scst_sense_internal_failure)); goto out; } #endif