summaryrefslogtreecommitdiffstats
path: root/nvme-status.c
blob: 270eb06326f4b6d09a2b356f7543f373d3203a95 (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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
#include <linux/types.h>
#include <stdbool.h>
#include <errno.h>

#include "nvme.h"
#include "nvme-status.h"

static inline __u8 nvme_generic_status_to_errno(__u16 status)
{
	switch (status) {
	case NVME_SC_INVALID_OPCODE:
	case NVME_SC_INVALID_FIELD:
	case NVME_SC_INVALID_NS:
	case NVME_SC_SGL_INVALID_LAST:
	case NVME_SC_SGL_INVALID_COUNT:
	case NVME_SC_SGL_INVALID_DATA:
	case NVME_SC_SGL_INVALID_METADATA:
	case NVME_SC_SGL_INVALID_TYPE:
	case NVME_SC_SGL_INVALID_OFFSET:
	case NVME_SC_CMB_INVALID_USE:
	case NVME_SC_PRP_INVALID_OFFSET:
		return EINVAL;
	case NVME_SC_CMDID_CONFLICT:
		return EADDRINUSE;
	case NVME_SC_DATA_XFER_ERROR:
	case NVME_SC_INTERNAL:
	case NVME_SC_SANITIZE_FAILED:
		return EIO;
	case NVME_SC_POWER_LOSS:
	case NVME_SC_ABORT_REQ:
	case NVME_SC_ABORT_QUEUE:
	case NVME_SC_FUSED_FAIL:
	case NVME_SC_FUSED_MISSING:
		return EWOULDBLOCK;
	case NVME_SC_CMD_SEQ_ERROR:
		return EILSEQ;
	case NVME_SC_SANITIZE_IN_PROGRESS:
	case NVME_SC_FORMAT_IN_PROGRESS:
		return EINPROGRESS;
	case NVME_SC_NS_WRITE_PROTECTED:
	case NVME_SC_NS_NOT_READY:
	case NVME_SC_RESERVATION_CONFLICT:
		return EACCES;
	case NVME_SC_LBA_RANGE:
		return EREMOTEIO;
	case NVME_SC_CAP_EXCEEDED:
		return ENOSPC;
	case NVME_SC_OPERATION_DENIED:
		return EPERM;
	}

	return EIO;
}

static inline __u8 nvme_cmd_specific_status_to_errno(__u16 status)
{
	switch (status) {
	case NVME_SC_CQ_INVALID:
	case NVME_SC_QID_INVALID:
	case NVME_SC_QUEUE_SIZE:
	case NVME_SC_FIRMWARE_SLOT:
	case NVME_SC_FIRMWARE_IMAGE:
	case NVME_SC_INVALID_VECTOR:
	case NVME_SC_INVALID_LOG_PAGE:
	case NVME_SC_INVALID_FORMAT:
	case NVME_SC_INVALID_QUEUE:
	case NVME_SC_NS_INSUFFICIENT_CAP:
	case NVME_SC_NS_ID_UNAVAILABLE:
	case NVME_SC_CTRL_LIST_INVALID:
	case NVME_SC_BAD_ATTRIBUTES:
	case NVME_SC_INVALID_PI:
	case NVME_SC_INVALID_CTRL_ID:
	case NVME_SC_INVALID_SECONDARY_CTRL_STATE:
	case NVME_SC_INVALID_NUM_CTRL_RESOURCE:
	case NVME_SC_INVALID_RESOURCE_ID:
	case NVME_SC_ANA_INVALID_GROUP_ID:
		return EINVAL;
	case NVME_SC_ABORT_LIMIT:
	case NVME_SC_ASYNC_LIMIT:
		return EDQUOT;
	case NVME_SC_FW_NEEDS_CONV_RESET:
	case NVME_SC_FW_NEEDS_SUBSYS_RESET:
	case NVME_SC_FW_NEEDS_MAX_TIME:
		return ERESTART;
	case NVME_SC_FEATURE_NOT_SAVEABLE:
	case NVME_SC_FEATURE_NOT_CHANGEABLE:
	case NVME_SC_FEATURE_NOT_PER_NS:
	case NVME_SC_FW_ACTIVATE_PROHIBITED:
	case NVME_SC_NS_IS_PRIVATE:
	case NVME_SC_BP_WRITE_PROHIBITED:
	case NVME_SC_READ_ONLY:
	case NVME_SC_PMR_SAN_PROHIBITED:
		return EPERM;
	case NVME_SC_OVERLAPPING_RANGE:
	case NVME_SC_NS_NOT_ATTACHED:
		return ENOSPC;
	case NVME_SC_NS_ALREADY_ATTACHED:
		return EALREADY;
	case NVME_SC_THIN_PROV_NOT_SUPP:
		return EOPNOTSUPP;
	case NVME_SC_DEVICE_SELF_TEST_IN_PROGRESS:
		return EINPROGRESS;
	}

	return EIO;
}

static inline __u8 nvme_fabrics_status_to_errno(__u16 status)
{
	switch (status) {
	case NVME_SC_CONNECT_FORMAT:
	case NVME_SC_CONNECT_INVALID_PARAM:
		return EINVAL;
	case NVME_SC_CONNECT_CTRL_BUSY:
		return EBUSY;
	case NVME_SC_CONNECT_RESTART_DISC:
		return ERESTART;
	case NVME_SC_CONNECT_INVALID_HOST:
		return ECONNREFUSED;
	case NVME_SC_DISCOVERY_RESTART:
		return EAGAIN;
	case NVME_SC_AUTH_REQUIRED:
		return EPERM;
	}

	return EIO;
}

static inline __u8 nvme_path_status_to_errno(__u16 status)
{
	switch (status) {
	case NVME_SC_INTERNAL_PATH_ERROR:
	case NVME_SC_ANA_PERSISTENT_LOSS:
	case NVME_SC_ANA_INACCESSIBLE:
	case NVME_SC_ANA_TRANSITION:
	case NVME_SC_CTRL_PATHING_ERROR:
	case NVME_SC_HOST_PATHING_ERROR:
	case NVME_SC_HOST_CMD_ABORT:
		return EACCES;
	}

	return EIO;
}

/*
 * nvme_status_to_errno - It converts given status to errno mapped
 * @status: >= 0 for nvme status field in completion queue entry,
 *          < 0 for linux internal errors
 * @fabrics: true if given status is for fabrics
 *
 * Notes: This function will convert a given status to an errno mapped
 */
__u8 nvme_status_to_errno(int status, bool fabrics)
{
	__u8 sct;

	if (!status)
		return 0;

	if (status < 0) {
		if (errno)
			return errno;
		return status;
	}

	/*
	 * The actual status code is enough with masking 0xff, but we need to
	 * cover status code type which is 3bits with 0x7ff.
	 */
	status &= 0x7ff;

	sct = nvme_status_type(status);
	switch (sct) {
	case NVME_SCT_GENERIC:
		return nvme_generic_status_to_errno(status);
	case NVME_SCT_CMD_SPECIFIC:
		if (!fabrics) {
			return nvme_cmd_specific_status_to_errno(status);
		}
		return nvme_fabrics_status_to_errno(status);
	case NVME_SCT_PATH:
		return nvme_path_status_to_errno(status);
	}

	/*
	 * Media, integrity related status, and the others will be mapped to
	 * EIO.
	 */
	return EIO;
}