aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/scsi/scsi-disk.c51
1 files changed, 28 insertions, 23 deletions
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index 548a5297fa..a5a58d7db3 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -212,39 +212,44 @@ static bool scsi_handle_rw_error(SCSIDiskReq *r, int ret, bool acct_failed)
}
}
- action = blk_get_error_action(s->qdev.conf.blk, is_read, error);
- if (action == BLOCK_ERROR_ACTION_REPORT) {
+ /*
+ * Check whether the error has to be handled by the guest or should
+ * rather follow the rerror=/werror= settings. Guest-handled errors
+ * are usually retried immediately, so do not post them to QMP and
+ * do not account them as failed I/O.
+ */
+ if (req_has_sense &&
+ scsi_sense_buf_is_guest_recoverable(r->req.sense, sizeof(r->req.sense))) {
+ action = BLOCK_ERROR_ACTION_REPORT;
+ acct_failed = false;
+ } else {
+ action = blk_get_error_action(s->qdev.conf.blk, is_read, error);
+ blk_error_action(s->qdev.conf.blk, action, is_read, error);
+ }
+
+ switch (action) {
+ case BLOCK_ERROR_ACTION_REPORT:
if (acct_failed) {
block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct);
}
if (req_has_sense) {
- /* A passthrough command has run and has produced sense data; check
- * whether the error has to be handled by the guest or should rather
- * pause the host.
- */
- if (scsi_sense_buf_is_guest_recoverable(r->req.sense, sizeof(r->req.sense))) {
- /* These errors are handled by guest. */
- sdc->update_sense(&r->req);
- scsi_req_complete(&r->req, status);
- return true;
- }
- } else {
- if (status == CHECK_CONDITION) {
- scsi_req_build_sense(&r->req, sense);
- }
- scsi_req_complete(&r->req, status);
+ sdc->update_sense(&r->req);
+ } else if (status == CHECK_CONDITION) {
+ scsi_req_build_sense(&r->req, sense);
}
- }
+ scsi_req_complete(&r->req, status);
+ return true;
- blk_error_action(s->qdev.conf.blk, action, is_read, error);
- if (action == BLOCK_ERROR_ACTION_IGNORE) {
+ case BLOCK_ERROR_ACTION_IGNORE:
return false;
- }
- if (action == BLOCK_ERROR_ACTION_STOP) {
+ case BLOCK_ERROR_ACTION_STOP:
scsi_req_retry(&r->req);
+ return true;
+
+ default:
+ g_assert_not_reached();
}
- return true;
}
static bool scsi_disk_req_check_error(SCSIDiskReq *r, int ret, bool acct_failed)