aboutsummaryrefslogtreecommitdiff
path: root/util/scsi.c
blob: 472293d59b16d076d455ee1096a89183cf420417 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
/*
 *  SCSI helpers
 *
 *  Copyright 2017 Red Hat, Inc.
 *
 *  Authors:
 *   Fam Zheng <famz@redhat.com>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 */

#include "qemu/osdep.h"
#include "scsi/scsi.h"

int scsi_sense_to_errno(int key, int asc, int ascq)
{
    switch (key) {
    case 0x00: /* NO SENSE */
    case 0x01: /* RECOVERED ERROR */
    case 0x06: /* UNIT ATTENTION */
        /* These sense keys are not errors */
        return 0;
    case 0x0b: /* COMMAND ABORTED */
        return ECANCELED;
    case 0x02: /* NOT READY */
    case 0x05: /* ILLEGAL REQUEST */
    case 0x07: /* DATA PROTECTION */
        /* Parse ASCQ */
        break;
    default:
        return EIO;
    }
    switch ((asc << 8) | ascq) {
    case 0x1a00: /* PARAMETER LIST LENGTH ERROR */
    case 0x2000: /* INVALID OPERATION CODE */
    case 0x2400: /* INVALID FIELD IN CDB */
    case 0x2600: /* INVALID FIELD IN PARAMETER LIST */
        return EINVAL;
    case 0x2100: /* LBA OUT OF RANGE */
    case 0x2707: /* SPACE ALLOC FAILED */
        return ENOSPC;
    case 0x2500: /* LOGICAL UNIT NOT SUPPORTED */
        return ENOTSUP;
    case 0x3a00: /* MEDIUM NOT PRESENT */
    case 0x3a01: /* MEDIUM NOT PRESENT TRAY CLOSED */
    case 0x3a02: /* MEDIUM NOT PRESENT TRAY OPEN */
        return ENOMEDIUM;
    case 0x2700: /* WRITE PROTECTED */
        return EACCES;
    case 0x0401: /* NOT READY, IN PROGRESS OF BECOMING READY */
        return EAGAIN;
    case 0x0402: /* NOT READY, INITIALIZING COMMAND REQUIRED */
        return ENOTCONN;
    default:
        return EIO;
    }
}

int scsi_sense_buf_to_errno(const uint8_t *sense, size_t sense_size)
{
    int key, asc, ascq;
    if (sense_size < 1) {
        return EIO;
    }
    switch (sense[0]) {
    case 0x70: /* Fixed format sense data. */
        if (sense_size < 14) {
            return EIO;
        }
        key = sense[2] & 0xF;
        asc = sense[12];
        ascq = sense[13];
        break;
    case 0x72: /* Descriptor format sense data. */
        if (sense_size < 4) {
            return EIO;
        }
        key = sense[1] & 0xF;
        asc = sense[2];
        ascq = sense[3];
        break;
    default:
        return EIO;
        break;
    }
    return scsi_sense_to_errno(key, asc, ascq);
}