diff options
-rw-r--r-- | hw/scsi/scsi-disk.c | 51 |
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) |