scsi: explicitly list guest-recoverable sense codes

It's not really possible to fit all sense codes into errno codes,
especially in such a way that sense codes can be properly categorized as
either guest-recoverable or host-handled.  Create a new function that
checks for guest recoverable sense, then scsi_sense_buf_to_errno only
needs to be called for host handled sense codes.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Paolo Bonzini 2019-07-02 10:23:20 +02:00
parent d31347f5ff
commit bdf9613b7f
3 changed files with 46 additions and 3 deletions

View file

@ -454,14 +454,13 @@ static bool scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed)
* pause the host.
*/
assert(r->status && *r->status);
error = scsi_sense_buf_to_errno(r->req.sense, sizeof(r->req.sense));
if (error == ECANCELED || error == EAGAIN || error == ENOTCONN ||
error == 0) {
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, *r->status);
return true;
}
error = scsi_sense_buf_to_errno(r->req.sense, sizeof(r->req.sense));
break;
case ENOMEDIUM:
scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));

View file

@ -106,6 +106,7 @@ extern const struct SCSISense sense_code_SPACE_ALLOC_FAILED;
int scsi_sense_to_errno(int key, int asc, int ascq);
int scsi_sense_buf_to_errno(const uint8_t *sense, size_t sense_size);
bool scsi_sense_buf_is_guest_recoverable(const uint8_t *sense, size_t sense_size);
int scsi_convert_sense(uint8_t *in_buf, int in_len,
uint8_t *buf, int len, bool fixed);

View file

@ -336,6 +336,38 @@ int scsi_convert_sense(uint8_t *in_buf, int in_len,
}
}
static bool scsi_sense_is_guest_recoverable(int key, int asc, int ascq)
{
switch (key) {
case NO_SENSE:
case RECOVERED_ERROR:
case UNIT_ATTENTION:
case ABORTED_COMMAND:
return true;
case NOT_READY:
case ILLEGAL_REQUEST:
case DATA_PROTECT:
/* Parse ASCQ */
break;
default:
return false;
}
switch ((asc << 8) | ascq) {
case 0x1a00: /* PARAMETER LIST LENGTH ERROR */
case 0x2000: /* INVALID OPERATION CODE */
case 0x2400: /* INVALID FIELD IN CDB */
case 0x2500: /* LOGICAL UNIT NOT SUPPORTED */
case 0x2600: /* INVALID FIELD IN PARAMETER LIST */
case 0x0401: /* NOT READY, IN PROGRESS OF BECOMING READY */
case 0x0402: /* NOT READY, INITIALIZING COMMAND REQUIRED */
return true;
default:
return false;
}
}
int scsi_sense_to_errno(int key, int asc, int ascq)
{
switch (key) {
@ -391,6 +423,17 @@ int scsi_sense_buf_to_errno(const uint8_t *in_buf, size_t in_len)
return scsi_sense_to_errno(sense.key, sense.asc, sense.ascq);
}
bool scsi_sense_buf_is_guest_recoverable(const uint8_t *in_buf, size_t in_len)
{
SCSISense sense;
if (in_len < 1) {
return false;
}
sense = scsi_parse_sense_buf(in_buf, in_len);
return scsi_sense_is_guest_recoverable(sense.key, sense.asc, sense.ascq);
}
const char *scsi_command_name(uint8_t cmd)
{
static const char *names[] = {