Merge ~paelzer/ubuntu/+source/qemu:lp-1967814-scsi-error-handling into ubuntu/+source/qemu:ubuntu/focal-devel
- Git
- lp:~paelzer/ubuntu/+source/qemu
- lp-1967814-scsi-error-handling
- Merge into ubuntu/focal-devel
Proposed by
Christian Ehrhardt
Status: | Merged |
---|---|
Merge reported by: | Christian Ehrhardt |
Merged at revision: | 483d938cd49b476e85094dce727f766efdbdf1ef |
Proposed branch: | ~paelzer/ubuntu/+source/qemu:lp-1967814-scsi-error-handling |
Merge into: | ubuntu/+source/qemu:ubuntu/focal-devel |
Diff against target: |
1135 lines (+1071/-0) 10 files modified
debian/changelog (+9/-0) debian/patches/series (+8/-0) debian/patches/ubuntu/lp-1967814-scsi-Add-mapping-for-generic-SCSI_HOST-status-to-sen.patch (+126/-0) debian/patches/ubuntu/lp-1967814-scsi-Rename-linux-specific-SG_ERR-codes-to-generic-S.patch (+90/-0) debian/patches/ubuntu/lp-1967814-scsi-disk-convert-more-errno-values-back-to-SCSI-sta.patch (+54/-0) debian/patches/ubuntu/lp-1967814-scsi-disk-move-scsi_handle_rw_error-earlier.patch (+213/-0) debian/patches/ubuntu/lp-1967814-scsi-disk-pass-SCSI-status-to-scsi_handle_rw_error.patch (+97/-0) debian/patches/ubuntu/lp-1967814-scsi-fix-sense-code-for-EREMOTEIO.patch (+51/-0) debian/patches/ubuntu/lp-1967814-scsi-inline-sg_io_sense_from_errno-into-the-callers.patch (+251/-0) debian/patches/ubuntu/lp-1967814-scsi-introduce-scsi_sense_from_errno.patch (+172/-0) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Bryce Harrington (community) | Approve | ||
Canonical Server | Pending | ||
git-ubuntu import | Pending | ||
Review via email: mp+418636@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Revision history for this message
Christian Ehrhardt (paelzer) wrote : | # |
Revision history for this message
Bryce Harrington (bryce) wrote : | # |
Quite a few patches, so my review is not as in depth as normal: I've not checked tests or build, but instead code review on each patch, verifying DEP3, review LP and upstream bug reports, and checked packaging work.
It seems the changelog entry might be good to include a mention that it's improving and refactoring handling of sense codes and SCSI status. But you know better what the appropriate level of detail is for qemu so will leave to your prerogative.
LGTM, +1
review:
Approve
Revision history for this message
Christian Ehrhardt (paelzer) wrote : | # |
Thanks, I enhanced the changelog entry accordingly.
Revision history for this message
Christian Ehrhardt (paelzer) wrote : | # |
Uploaded
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/debian/changelog b/debian/changelog |
2 | index 556e73f..429ed96 100644 |
3 | --- a/debian/changelog |
4 | +++ b/debian/changelog |
5 | @@ -1,3 +1,12 @@ |
6 | +qemu (1:4.2-3ubuntu6.22) focal; urgency=medium |
7 | + |
8 | + * d/p/u/lp-1967814-*: avoid interpreting failed scsi requests as |
9 | + good which could lead to silent data corruption (LP: #1967814) |
10 | + This refactors handling of sense codes and SCSI status to be able |
11 | + detect, handle and pass that information to the guest as needed. |
12 | + |
13 | + -- Christian Ehrhardt <christian.ehrhardt@canonical.com> Wed, 06 Apr 2022 14:24:56 +0200 |
14 | + |
15 | qemu (1:4.2-3ubuntu6.21) focal-security; urgency=medium |
16 | |
17 | * SECURITY UPDATE: crash or code exec in USB redirector device emulation |
18 | diff --git a/debian/patches/series b/debian/patches/series |
19 | index 39c9d00..8f525ba 100644 |
20 | --- a/debian/patches/series |
21 | +++ b/debian/patches/series |
22 | @@ -324,3 +324,11 @@ CVE-2021-3930.patch |
23 | CVE-2021-20196-1.patch |
24 | CVE-2021-20196-2.patch |
25 | CVE-2021-20203.patch |
26 | +ubuntu/lp-1967814-scsi-disk-convert-more-errno-values-back-to-SCSI-sta.patch |
27 | +ubuntu/lp-1967814-scsi-disk-move-scsi_handle_rw_error-earlier.patch |
28 | +ubuntu/lp-1967814-scsi-introduce-scsi_sense_from_errno.patch |
29 | +ubuntu/lp-1967814-scsi-disk-pass-SCSI-status-to-scsi_handle_rw_error.patch |
30 | +ubuntu/lp-1967814-scsi-Rename-linux-specific-SG_ERR-codes-to-generic-S.patch |
31 | +ubuntu/lp-1967814-scsi-Add-mapping-for-generic-SCSI_HOST-status-to-sen.patch |
32 | +ubuntu/lp-1967814-scsi-inline-sg_io_sense_from_errno-into-the-callers.patch |
33 | +ubuntu/lp-1967814-scsi-fix-sense-code-for-EREMOTEIO.patch |
34 | diff --git a/debian/patches/ubuntu/lp-1967814-scsi-Add-mapping-for-generic-SCSI_HOST-status-to-sen.patch b/debian/patches/ubuntu/lp-1967814-scsi-Add-mapping-for-generic-SCSI_HOST-status-to-sen.patch |
35 | new file mode 100644 |
36 | index 0000000..aa7fb8a |
37 | --- /dev/null |
38 | +++ b/debian/patches/ubuntu/lp-1967814-scsi-Add-mapping-for-generic-SCSI_HOST-status-to-sen.patch |
39 | @@ -0,0 +1,126 @@ |
40 | +From db66a15cb80f09da24a5311a3f3b8f0c1835bf71 Mon Sep 17 00:00:00 2001 |
41 | +From: Hannes Reinecke <hare@suse.de> |
42 | +Date: Mon, 16 Nov 2020 19:40:39 +0100 |
43 | +Subject: [PATCH] scsi: Add mapping for generic SCSI_HOST status to sense codes |
44 | + |
45 | +As we don't have a driver-specific mapping (yet) we should provide |
46 | +for a detailed mapping from host_status to SCSI sense codes. |
47 | + |
48 | +Signed-off-by: Hannes Reinecke <hare@suse.de> |
49 | +Message-Id: <20201116184041.60465-6-hare@suse.de> |
50 | +Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
51 | + |
52 | +Origin: upstream, https://git.qemu.org/?p=qemu.git;a=commit;h=db66a15cb80f09da24a5311a3f3b8f0c1835bf71 |
53 | +Bug-Ubuntu: https://bugs.launchpad.net/bugs/1967814 |
54 | +Last-Update: 2022-04-06 |
55 | + |
56 | +--- |
57 | + include/scsi/utils.h | 1 + |
58 | + scsi/utils.c | 65 +++++++++++++++++++++++++++++++++++++++----- |
59 | + 2 files changed, 59 insertions(+), 7 deletions(-) |
60 | + |
61 | +diff --git a/include/scsi/utils.h b/include/scsi/utils.h |
62 | +index ddb22b56df..9080d65e27 100644 |
63 | +--- a/include/scsi/utils.h |
64 | ++++ b/include/scsi/utils.h |
65 | +@@ -145,5 +145,6 @@ int sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr, |
66 | + #endif |
67 | + |
68 | + int scsi_sense_from_errno(int errno_value, SCSISense *sense); |
69 | ++int scsi_sense_from_host_status(uint8_t host_status, SCSISense *sense); |
70 | + |
71 | + #endif |
72 | +diff --git a/scsi/utils.c b/scsi/utils.c |
73 | +index 4d994b6d56..28eb32746e 100644 |
74 | +--- a/scsi/utils.c |
75 | ++++ b/scsi/utils.c |
76 | +@@ -257,6 +257,21 @@ const struct SCSISense sense_code_LUN_COMM_FAILURE = { |
77 | + .key = ABORTED_COMMAND, .asc = 0x08, .ascq = 0x00 |
78 | + }; |
79 | + |
80 | ++/* Command aborted, LUN does not respond to selection */ |
81 | ++const struct SCSISense sense_code_LUN_NOT_RESPONDING = { |
82 | ++ .key = ABORTED_COMMAND, .asc = 0x05, .ascq = 0x00 |
83 | ++}; |
84 | ++ |
85 | ++/* Command aborted, Command Timeout during processing */ |
86 | ++const struct SCSISense sense_code_COMMAND_TIMEOUT = { |
87 | ++ .key = ABORTED_COMMAND, .asc = 0x2e, .ascq = 0x02 |
88 | ++}; |
89 | ++ |
90 | ++/* Command aborted, Commands cleared by device server */ |
91 | ++const struct SCSISense sense_code_COMMAND_ABORTED = { |
92 | ++ .key = ABORTED_COMMAND, .asc = 0x2f, .ascq = 0x02 |
93 | ++}; |
94 | ++ |
95 | + /* Medium Error, Unrecovered read error */ |
96 | + const struct SCSISense sense_code_READ_ERROR = { |
97 | + .key = MEDIUM_ERROR, .asc = 0x11, .ascq = 0x00 |
98 | +@@ -605,6 +620,45 @@ int scsi_sense_from_errno(int errno_value, SCSISense *sense) |
99 | + } |
100 | + } |
101 | + |
102 | ++int scsi_sense_from_host_status(uint8_t host_status, |
103 | ++ SCSISense *sense) |
104 | ++{ |
105 | ++ switch (host_status) { |
106 | ++ case SCSI_HOST_NO_LUN: |
107 | ++ *sense = SENSE_CODE(LUN_NOT_RESPONDING); |
108 | ++ return CHECK_CONDITION; |
109 | ++ case SCSI_HOST_BUSY: |
110 | ++ return BUSY; |
111 | ++ case SCSI_HOST_TIME_OUT: |
112 | ++ *sense = SENSE_CODE(COMMAND_TIMEOUT); |
113 | ++ return CHECK_CONDITION; |
114 | ++ case SCSI_HOST_BAD_RESPONSE: |
115 | ++ *sense = SENSE_CODE(LUN_COMM_FAILURE); |
116 | ++ return CHECK_CONDITION; |
117 | ++ case SCSI_HOST_ABORTED: |
118 | ++ *sense = SENSE_CODE(COMMAND_ABORTED); |
119 | ++ return CHECK_CONDITION; |
120 | ++ case SCSI_HOST_RESET: |
121 | ++ *sense = SENSE_CODE(RESET); |
122 | ++ return CHECK_CONDITION; |
123 | ++ case SCSI_HOST_TRANSPORT_DISRUPTED: |
124 | ++ *sense = SENSE_CODE(I_T_NEXUS_LOSS); |
125 | ++ return CHECK_CONDITION; |
126 | ++ case SCSI_HOST_TARGET_FAILURE: |
127 | ++ *sense = SENSE_CODE(TARGET_FAILURE); |
128 | ++ return CHECK_CONDITION; |
129 | ++ case SCSI_HOST_RESERVATION_ERROR: |
130 | ++ return RESERVATION_CONFLICT; |
131 | ++ case SCSI_HOST_ALLOCATION_FAILURE: |
132 | ++ *sense = SENSE_CODE(SPACE_ALLOC_FAILED); |
133 | ++ return CHECK_CONDITION; |
134 | ++ case SCSI_HOST_MEDIUM_ERROR: |
135 | ++ *sense = SENSE_CODE(READ_ERROR); |
136 | ++ return CHECK_CONDITION; |
137 | ++ } |
138 | ++ return GOOD; |
139 | ++} |
140 | ++ |
141 | + #ifdef CONFIG_LINUX |
142 | + int sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr, |
143 | + SCSISense *sense) |
144 | +@@ -612,14 +666,11 @@ int sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr, |
145 | + if (errno_value != 0) { |
146 | + return scsi_sense_from_errno(errno_value, sense); |
147 | + } else { |
148 | +- if (io_hdr->host_status == SCSI_HOST_NO_LUN || |
149 | +- io_hdr->host_status == SCSI_HOST_BUSY || |
150 | +- io_hdr->host_status == SCSI_HOST_TIME_OUT || |
151 | +- (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT)) { |
152 | ++ int status = scsi_sense_from_host_status(io_hdr->host_status, sense); |
153 | ++ if (status) { |
154 | ++ return status; |
155 | ++ } else if (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT) { |
156 | + return BUSY; |
157 | +- } else if (io_hdr->host_status) { |
158 | +- *sense = SENSE_CODE(I_T_NEXUS_LOSS); |
159 | +- return CHECK_CONDITION; |
160 | + } else if (io_hdr->status) { |
161 | + return io_hdr->status; |
162 | + } else if (io_hdr->driver_status & SG_ERR_DRIVER_SENSE) { |
163 | +-- |
164 | +2.35.1 |
165 | + |
166 | diff --git a/debian/patches/ubuntu/lp-1967814-scsi-Rename-linux-specific-SG_ERR-codes-to-generic-S.patch b/debian/patches/ubuntu/lp-1967814-scsi-Rename-linux-specific-SG_ERR-codes-to-generic-S.patch |
167 | new file mode 100644 |
168 | index 0000000..f0d1533 |
169 | --- /dev/null |
170 | +++ b/debian/patches/ubuntu/lp-1967814-scsi-Rename-linux-specific-SG_ERR-codes-to-generic-S.patch |
171 | @@ -0,0 +1,90 @@ |
172 | +From 41af878b96582fc8c83303ab8921e40468403702 Mon Sep 17 00:00:00 2001 |
173 | +From: Hannes Reinecke <hare@suse.de> |
174 | +Date: Mon, 16 Nov 2020 19:40:38 +0100 |
175 | +Subject: [PATCH] scsi: Rename linux-specific SG_ERR codes to generic SCSI_HOST |
176 | + error codes |
177 | + |
178 | +We really should make a distinction between legitimate sense codes |
179 | +(ie if one is running against an emulated block device or for |
180 | +pass-through sense codes), and the intermediate errors generated |
181 | +during processing of the command, which really are not sense codes |
182 | +but refer to some specific internal status. And this internal |
183 | +state is not necessarily linux-specific, but rather can refer to |
184 | +the qemu implementation itself. |
185 | +So rename the linux-only SG_ERR codes to SCSI_HOST codes and make |
186 | +them available generally. |
187 | + |
188 | +Signed-off-by: Hannes Reinecke <hare@suse.de> |
189 | +Message-Id: <20201116184041.60465-5-hare@suse.de> |
190 | +Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
191 | + |
192 | +Origin: upstream, https://git.qemu.org/?p=qemu.git;a=commit;h=41af878b96582fc8c83303ab8921e40468403702 |
193 | +Bug-Ubuntu: https://bugs.launchpad.net/bugs/1967814 |
194 | +Last-Update: 2022-04-06 |
195 | + |
196 | +--- |
197 | + include/scsi/utils.h | 23 ++++++++++++++++------- |
198 | + scsi/utils.c | 6 +++--- |
199 | + 2 files changed, 19 insertions(+), 10 deletions(-) |
200 | + |
201 | +diff --git a/include/scsi/utils.h b/include/scsi/utils.h |
202 | +index ff7c7091b6..ddb22b56df 100644 |
203 | +--- a/include/scsi/utils.h |
204 | ++++ b/include/scsi/utils.h |
205 | +@@ -16,6 +16,22 @@ enum SCSIXferMode { |
206 | + SCSI_XFER_TO_DEV, /* WRITE, MODE_SELECT, ... */ |
207 | + }; |
208 | + |
209 | ++enum SCSIHostStatus { |
210 | ++ SCSI_HOST_OK, |
211 | ++ SCSI_HOST_NO_LUN, |
212 | ++ SCSI_HOST_BUSY, |
213 | ++ SCSI_HOST_TIME_OUT, |
214 | ++ SCSI_HOST_BAD_RESPONSE, |
215 | ++ SCSI_HOST_ABORTED, |
216 | ++ SCSI_HOST_ERROR = 0x07, |
217 | ++ SCSI_HOST_RESET = 0x08, |
218 | ++ SCSI_HOST_TRANSPORT_DISRUPTED = 0xe, |
219 | ++ SCSI_HOST_TARGET_FAILURE = 0x10, |
220 | ++ SCSI_HOST_RESERVATION_ERROR = 0x11, |
221 | ++ SCSI_HOST_ALLOCATION_FAILURE = 0x12, |
222 | ++ SCSI_HOST_MEDIUM_ERROR = 0x13, |
223 | ++}; |
224 | ++ |
225 | + typedef struct SCSICommand { |
226 | + uint8_t buf[SCSI_CMD_BUF_SIZE]; |
227 | + int len; |
228 | +@@ -124,13 +140,6 @@ int scsi_cdb_length(uint8_t *buf); |
229 | + #define SG_ERR_DRIVER_TIMEOUT 0x06 |
230 | + #define SG_ERR_DRIVER_SENSE 0x08 |
231 | + |
232 | +-#define SG_ERR_DID_OK 0x00 |
233 | +-#define SG_ERR_DID_NO_CONNECT 0x01 |
234 | +-#define SG_ERR_DID_BUS_BUSY 0x02 |
235 | +-#define SG_ERR_DID_TIME_OUT 0x03 |
236 | +- |
237 | +-#define SG_ERR_DRIVER_SENSE 0x08 |
238 | +- |
239 | + int sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr, |
240 | + SCSISense *sense); |
241 | + #endif |
242 | +diff --git a/scsi/utils.c b/scsi/utils.c |
243 | +index 6b56e01002..4d994b6d56 100644 |
244 | +--- a/scsi/utils.c |
245 | ++++ b/scsi/utils.c |
246 | +@@ -612,9 +612,9 @@ int sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr, |
247 | + if (errno_value != 0) { |
248 | + return scsi_sense_from_errno(errno_value, sense); |
249 | + } else { |
250 | +- if (io_hdr->host_status == SG_ERR_DID_NO_CONNECT || |
251 | +- io_hdr->host_status == SG_ERR_DID_BUS_BUSY || |
252 | +- io_hdr->host_status == SG_ERR_DID_TIME_OUT || |
253 | ++ if (io_hdr->host_status == SCSI_HOST_NO_LUN || |
254 | ++ io_hdr->host_status == SCSI_HOST_BUSY || |
255 | ++ io_hdr->host_status == SCSI_HOST_TIME_OUT || |
256 | + (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT)) { |
257 | + return BUSY; |
258 | + } else if (io_hdr->host_status) { |
259 | +-- |
260 | +2.35.1 |
261 | + |
262 | diff --git a/debian/patches/ubuntu/lp-1967814-scsi-disk-convert-more-errno-values-back-to-SCSI-sta.patch b/debian/patches/ubuntu/lp-1967814-scsi-disk-convert-more-errno-values-back-to-SCSI-sta.patch |
263 | new file mode 100644 |
264 | index 0000000..cb5e293 |
265 | --- /dev/null |
266 | +++ b/debian/patches/ubuntu/lp-1967814-scsi-disk-convert-more-errno-values-back-to-SCSI-sta.patch |
267 | @@ -0,0 +1,54 @@ |
268 | +From 3b12a7fd39307017c8968b8d05986a63b33752b5 Mon Sep 17 00:00:00 2001 |
269 | +From: Paolo Bonzini <pbonzini@redhat.com> |
270 | +Date: Thu, 12 Nov 2020 10:52:04 +0100 |
271 | +Subject: [PATCH] scsi-disk: convert more errno values back to SCSI statuses |
272 | + |
273 | +Linux has some OS-specific (and sometimes weird) mappings for various SCSI |
274 | +statuses and sense codes. The most important is probably RESERVATION |
275 | +CONFLICT. Add them so that they can be reported back to the guest |
276 | +kernel. |
277 | + |
278 | +Cc: Hannes Reinecke <hare@suse.de> |
279 | +Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
280 | + |
281 | +Origin: upstream, https://git.qemu.org/?p=qemu.git;a=commit;h=3b12a7fd39307017c8968b8d05986a63b33752b5 |
282 | +Bug-Ubuntu: https://bugs.launchpad.net/bugs/1967814 |
283 | +Last-Update: 2022-04-06 |
284 | + |
285 | +--- |
286 | + hw/scsi/scsi-disk.c | 19 +++++++++++++++++++ |
287 | + 1 file changed, 19 insertions(+) |
288 | + |
289 | +diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c |
290 | +index e859534eaf..90841ad791 100644 |
291 | +--- a/hw/scsi/scsi-disk.c |
292 | ++++ b/hw/scsi/scsi-disk.c |
293 | +@@ -461,6 +461,25 @@ static bool scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed) |
294 | + } |
295 | + error = scsi_sense_buf_to_errno(r->req.sense, sizeof(r->req.sense)); |
296 | + break; |
297 | ++#ifdef CONFIG_LINUX |
298 | ++ /* These errno mapping are specific to Linux. For more information: |
299 | ++ * - scsi_decide_disposition in drivers/scsi/scsi_error.c |
300 | ++ * - scsi_result_to_blk_status in drivers/scsi/scsi_lib.c |
301 | ++ * - blk_errors[] in block/blk-core.c |
302 | ++ */ |
303 | ++ case EBADE: |
304 | ++ /* DID_NEXUS_FAILURE -> BLK_STS_NEXUS. */ |
305 | ++ scsi_req_complete(&r->req, RESERVATION_CONFLICT); |
306 | ++ break; |
307 | ++ case ENODATA: |
308 | ++ /* DID_MEDIUM_ERROR -> BLK_STS_MEDIUM. */ |
309 | ++ scsi_check_condition(r, SENSE_CODE(READ_ERROR)); |
310 | ++ break; |
311 | ++ case EREMOTEIO: |
312 | ++ /* DID_TARGET_FAILURE -> BLK_STS_TARGET. */ |
313 | ++ scsi_req_complete(&r->req, HARDWARE_ERROR); |
314 | ++ break; |
315 | ++#endif |
316 | + case ENOMEDIUM: |
317 | + scsi_check_condition(r, SENSE_CODE(NO_MEDIUM)); |
318 | + break; |
319 | +-- |
320 | +2.35.1 |
321 | + |
322 | diff --git a/debian/patches/ubuntu/lp-1967814-scsi-disk-move-scsi_handle_rw_error-earlier.patch b/debian/patches/ubuntu/lp-1967814-scsi-disk-move-scsi_handle_rw_error-earlier.patch |
323 | new file mode 100644 |
324 | index 0000000..882d532 |
325 | --- /dev/null |
326 | +++ b/debian/patches/ubuntu/lp-1967814-scsi-disk-move-scsi_handle_rw_error-earlier.patch |
327 | @@ -0,0 +1,213 @@ |
328 | +From f95f61c2c9618fae7d8ea4c1d63e7416884bad52 Mon Sep 17 00:00:00 2001 |
329 | +From: Paolo Bonzini <pbonzini@redhat.com> |
330 | +Date: Wed, 24 Feb 2021 13:14:07 +0100 |
331 | +Subject: [PATCH] scsi-disk: move scsi_handle_rw_error earlier |
332 | + |
333 | +Remove the forward declaration. |
334 | + |
335 | +Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
336 | + |
337 | +Origin: backport, https://git.qemu.org/?p=qemu.git;a=commit;h=f95f61c2c9618fae7d8ea4c1d63e7416884bad52 |
338 | +Bug-Ubuntu: https://bugs.launchpad.net/bugs/1967814 |
339 | +Last-Update: 2022-04-06 |
340 | + |
341 | +--- |
342 | + hw/scsi/scsi-disk.c | 168 ++++++++++++++++++++++---------------------- |
343 | + 1 file changed, 83 insertions(+), 85 deletions(-) |
344 | + |
345 | +diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c |
346 | +index 5916bdd71d..bfe4162fdf 100644 |
347 | +--- a/hw/scsi/scsi-disk.c |
348 | ++++ b/hw/scsi/scsi-disk.c |
349 | +@@ -115,8 +115,6 @@ typedef struct SCSIDiskState |
350 | + uint16_t rotation_rate; |
351 | + } SCSIDiskState; |
352 | + |
353 | +-static bool scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed); |
354 | +- |
355 | + static void scsi_free_request(SCSIRequest *req) |
356 | + { |
357 | + SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); |
358 | +@@ -186,6 +184,89 @@ static void scsi_disk_load_request(QEMUFile *f, SCSIRequest *req) |
359 | + qemu_iovec_init_external(&r->qiov, &r->iov, 1); |
360 | + } |
361 | + |
362 | ++/* |
363 | ++ * scsi_handle_rw_error has two return values. False means that the error |
364 | ++ * must be ignored, true means that the error has been processed and the |
365 | ++ * caller should not do anything else for this request. Note that |
366 | ++ * scsi_handle_rw_error always manages its reference counts, independent |
367 | ++ * of the return value. |
368 | ++ */ |
369 | ++static bool scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed) |
370 | ++{ |
371 | ++ bool is_read = (r->req.cmd.mode == SCSI_XFER_FROM_DEV); |
372 | ++ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); |
373 | ++ SCSIDiskClass *sdc = (SCSIDiskClass *) object_get_class(OBJECT(s)); |
374 | ++ BlockErrorAction action = blk_get_error_action(s->qdev.conf.blk, |
375 | ++ is_read, error); |
376 | ++ |
377 | ++ if (action == BLOCK_ERROR_ACTION_REPORT) { |
378 | ++ if (acct_failed) { |
379 | ++ block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct); |
380 | ++ } |
381 | ++ switch (error) { |
382 | ++ case 0: |
383 | ++ /* A passthrough command has run and has produced sense data; check |
384 | ++ * whether the error has to be handled by the guest or should rather |
385 | ++ * pause the host. |
386 | ++ */ |
387 | ++ assert(r->status && *r->status); |
388 | ++ if (scsi_sense_buf_is_guest_recoverable(r->req.sense, sizeof(r->req.sense))) { |
389 | ++ /* These errors are handled by guest. */ |
390 | ++ sdc->update_sense(&r->req); |
391 | ++ scsi_req_complete(&r->req, *r->status); |
392 | ++ return true; |
393 | ++ } |
394 | ++ error = scsi_sense_buf_to_errno(r->req.sense, sizeof(r->req.sense)); |
395 | ++ break; |
396 | ++#ifdef CONFIG_LINUX |
397 | ++ /* These errno mapping are specific to Linux. For more information: |
398 | ++ * - scsi_decide_disposition in drivers/scsi/scsi_error.c |
399 | ++ * - scsi_result_to_blk_status in drivers/scsi/scsi_lib.c |
400 | ++ * - blk_errors[] in block/blk-core.c |
401 | ++ */ |
402 | ++ case EBADE: |
403 | ++ /* DID_NEXUS_FAILURE -> BLK_STS_NEXUS. */ |
404 | ++ scsi_req_complete(&r->req, RESERVATION_CONFLICT); |
405 | ++ break; |
406 | ++ case ENODATA: |
407 | ++ /* DID_MEDIUM_ERROR -> BLK_STS_MEDIUM. */ |
408 | ++ scsi_check_condition(r, SENSE_CODE(READ_ERROR)); |
409 | ++ break; |
410 | ++ case EREMOTEIO: |
411 | ++ /* DID_TARGET_FAILURE -> BLK_STS_TARGET. */ |
412 | ++ scsi_req_complete(&r->req, HARDWARE_ERROR); |
413 | ++ break; |
414 | ++#endif |
415 | ++ case ENOMEDIUM: |
416 | ++ scsi_check_condition(r, SENSE_CODE(NO_MEDIUM)); |
417 | ++ break; |
418 | ++ case ENOMEM: |
419 | ++ scsi_check_condition(r, SENSE_CODE(TARGET_FAILURE)); |
420 | ++ break; |
421 | ++ case EINVAL: |
422 | ++ scsi_check_condition(r, SENSE_CODE(INVALID_FIELD)); |
423 | ++ break; |
424 | ++ case ENOSPC: |
425 | ++ scsi_check_condition(r, SENSE_CODE(SPACE_ALLOC_FAILED)); |
426 | ++ break; |
427 | ++ default: |
428 | ++ scsi_check_condition(r, SENSE_CODE(IO_ERROR)); |
429 | ++ break; |
430 | ++ } |
431 | ++ } |
432 | ++ |
433 | ++ blk_error_action(s->qdev.conf.blk, action, is_read, error); |
434 | ++ if (action == BLOCK_ERROR_ACTION_IGNORE) { |
435 | ++ scsi_req_complete(&r->req, 0); |
436 | ++ return true; |
437 | ++ } |
438 | ++ |
439 | ++ if (action == BLOCK_ERROR_ACTION_STOP) { |
440 | ++ scsi_req_retry(&r->req); |
441 | ++ } |
442 | ++ return true; |
443 | ++} |
444 | ++ |
445 | + static bool scsi_disk_req_check_error(SCSIDiskReq *r, int ret, bool acct_failed) |
446 | + { |
447 | + if (r->req.io_canceled) { |
448 | +@@ -432,89 +513,6 @@ static void scsi_read_data(SCSIRequest *req) |
449 | + } |
450 | + } |
451 | + |
452 | +-/* |
453 | +- * scsi_handle_rw_error has two return values. False means that the error |
454 | +- * must be ignored, true means that the error has been processed and the |
455 | +- * caller should not do anything else for this request. Note that |
456 | +- * scsi_handle_rw_error always manages its reference counts, independent |
457 | +- * of the return value. |
458 | +- */ |
459 | +-static bool scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed) |
460 | +-{ |
461 | +- bool is_read = (r->req.cmd.mode == SCSI_XFER_FROM_DEV); |
462 | +- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); |
463 | +- SCSIDiskClass *sdc = (SCSIDiskClass *) object_get_class(OBJECT(s)); |
464 | +- BlockErrorAction action = blk_get_error_action(s->qdev.conf.blk, |
465 | +- is_read, error); |
466 | +- |
467 | +- if (action == BLOCK_ERROR_ACTION_REPORT) { |
468 | +- if (acct_failed) { |
469 | +- block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct); |
470 | +- } |
471 | +- switch (error) { |
472 | +- case 0: |
473 | +- /* A passthrough command has run and has produced sense data; check |
474 | +- * whether the error has to be handled by the guest or should rather |
475 | +- * pause the host. |
476 | +- */ |
477 | +- assert(r->status && *r->status); |
478 | +- if (scsi_sense_buf_is_guest_recoverable(r->req.sense, sizeof(r->req.sense))) { |
479 | +- /* These errors are handled by guest. */ |
480 | +- sdc->update_sense(&r->req); |
481 | +- scsi_req_complete(&r->req, *r->status); |
482 | +- return true; |
483 | +- } |
484 | +- error = scsi_sense_buf_to_errno(r->req.sense, sizeof(r->req.sense)); |
485 | +- break; |
486 | +-#ifdef CONFIG_LINUX |
487 | +- /* These errno mapping are specific to Linux. For more information: |
488 | +- * - scsi_decide_disposition in drivers/scsi/scsi_error.c |
489 | +- * - scsi_result_to_blk_status in drivers/scsi/scsi_lib.c |
490 | +- * - blk_errors[] in block/blk-core.c |
491 | +- */ |
492 | +- case EBADE: |
493 | +- /* DID_NEXUS_FAILURE -> BLK_STS_NEXUS. */ |
494 | +- scsi_req_complete(&r->req, RESERVATION_CONFLICT); |
495 | +- break; |
496 | +- case ENODATA: |
497 | +- /* DID_MEDIUM_ERROR -> BLK_STS_MEDIUM. */ |
498 | +- scsi_check_condition(r, SENSE_CODE(READ_ERROR)); |
499 | +- break; |
500 | +- case EREMOTEIO: |
501 | +- /* DID_TARGET_FAILURE -> BLK_STS_TARGET. */ |
502 | +- scsi_req_complete(&r->req, HARDWARE_ERROR); |
503 | +- break; |
504 | +-#endif |
505 | +- case ENOMEDIUM: |
506 | +- scsi_check_condition(r, SENSE_CODE(NO_MEDIUM)); |
507 | +- break; |
508 | +- case ENOMEM: |
509 | +- scsi_check_condition(r, SENSE_CODE(TARGET_FAILURE)); |
510 | +- break; |
511 | +- case EINVAL: |
512 | +- scsi_check_condition(r, SENSE_CODE(INVALID_FIELD)); |
513 | +- break; |
514 | +- case ENOSPC: |
515 | +- scsi_check_condition(r, SENSE_CODE(SPACE_ALLOC_FAILED)); |
516 | +- break; |
517 | +- default: |
518 | +- scsi_check_condition(r, SENSE_CODE(IO_ERROR)); |
519 | +- break; |
520 | +- } |
521 | +- } |
522 | +- |
523 | +- blk_error_action(s->qdev.conf.blk, action, is_read, error); |
524 | +- if (action == BLOCK_ERROR_ACTION_IGNORE) { |
525 | +- scsi_req_complete(&r->req, 0); |
526 | +- return true; |
527 | +- } |
528 | +- |
529 | +- if (action == BLOCK_ERROR_ACTION_STOP) { |
530 | +- scsi_req_retry(&r->req); |
531 | +- } |
532 | +- return true; |
533 | +-} |
534 | +- |
535 | + static void scsi_write_complete_noio(SCSIDiskReq *r, int ret) |
536 | + { |
537 | + uint32_t n; |
538 | +-- |
539 | +2.31.1 |
540 | + |
541 | diff --git a/debian/patches/ubuntu/lp-1967814-scsi-disk-pass-SCSI-status-to-scsi_handle_rw_error.patch b/debian/patches/ubuntu/lp-1967814-scsi-disk-pass-SCSI-status-to-scsi_handle_rw_error.patch |
542 | new file mode 100644 |
543 | index 0000000..d82ddd7 |
544 | --- /dev/null |
545 | +++ b/debian/patches/ubuntu/lp-1967814-scsi-disk-pass-SCSI-status-to-scsi_handle_rw_error.patch |
546 | @@ -0,0 +1,97 @@ |
547 | +From f63c68bc0f514694a958b2e84a204b7792d28b17 Mon Sep 17 00:00:00 2001 |
548 | +From: Paolo Bonzini <pbonzini@redhat.com> |
549 | +Date: Wed, 24 Feb 2021 18:59:36 +0100 |
550 | +Subject: [PATCH] scsi-disk: pass SCSI status to scsi_handle_rw_error |
551 | + |
552 | +Instead of fishing it from *r->status, just pass the SCSI status |
553 | +as a positive value of the second parameter and an errno as a |
554 | +negative value. |
555 | + |
556 | +Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
557 | + |
558 | +Origin: upstream, https://git.qemu.org/?p=qemu.git;a=commit;h=f63c68bc0f514694a958b2e84a204b7792d28b17 |
559 | +Bug-Ubuntu: https://bugs.launchpad.net/bugs/1967814 |
560 | +Last-Update: 2022-04-06 |
561 | + |
562 | +--- |
563 | + hw/scsi/scsi-disk.c | 38 +++++++++++++++++++++++++++----------- |
564 | + 1 file changed, 27 insertions(+), 11 deletions(-) |
565 | + |
566 | +diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c |
567 | +index 9c6099ffc4..548a5297fa 100644 |
568 | +--- a/hw/scsi/scsi-disk.c |
569 | ++++ b/hw/scsi/scsi-disk.c |
570 | +@@ -187,34 +187,48 @@ static void scsi_disk_load_request(QEMUFile *f, SCSIRequest *req) |
571 | + * scsi_handle_rw_error always manages its reference counts, independent |
572 | + * of the return value. |
573 | + */ |
574 | +-static bool scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed) |
575 | ++static bool scsi_handle_rw_error(SCSIDiskReq *r, int ret, bool acct_failed) |
576 | + { |
577 | + bool is_read = (r->req.cmd.mode == SCSI_XFER_FROM_DEV); |
578 | + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); |
579 | + SCSIDiskClass *sdc = (SCSIDiskClass *) object_get_class(OBJECT(s)); |
580 | +- BlockErrorAction action = blk_get_error_action(s->qdev.conf.blk, |
581 | +- is_read, error); |
582 | +- SCSISense sense; |
583 | ++ SCSISense sense = SENSE_CODE(NO_SENSE); |
584 | ++ int error = 0; |
585 | ++ bool req_has_sense = false; |
586 | ++ BlockErrorAction action; |
587 | ++ int status; |
588 | + |
589 | ++ if (ret < 0) { |
590 | ++ status = scsi_sense_from_errno(-ret, &sense); |
591 | ++ error = -ret; |
592 | ++ } else { |
593 | ++ /* A passthrough command has completed with nonzero status. */ |
594 | ++ status = ret; |
595 | ++ if (status == CHECK_CONDITION) { |
596 | ++ req_has_sense = true; |
597 | ++ error = scsi_sense_buf_to_errno(r->req.sense, sizeof(r->req.sense)); |
598 | ++ } else { |
599 | ++ error = EINVAL; |
600 | ++ } |
601 | ++ } |
602 | ++ |
603 | ++ action = blk_get_error_action(s->qdev.conf.blk, is_read, error); |
604 | + if (action == BLOCK_ERROR_ACTION_REPORT) { |
605 | + if (acct_failed) { |
606 | + block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct); |
607 | + } |
608 | +- if (error == 0) { |
609 | ++ if (req_has_sense) { |
610 | + /* A passthrough command has run and has produced sense data; check |
611 | + * whether the error has to be handled by the guest or should rather |
612 | + * pause the host. |
613 | + */ |
614 | +- assert(r->status && *r->status); |
615 | + if (scsi_sense_buf_is_guest_recoverable(r->req.sense, sizeof(r->req.sense))) { |
616 | + /* These errors are handled by guest. */ |
617 | + sdc->update_sense(&r->req); |
618 | +- scsi_req_complete(&r->req, *r->status); |
619 | ++ scsi_req_complete(&r->req, status); |
620 | + return true; |
621 | + } |
622 | +- error = scsi_sense_buf_to_errno(r->req.sense, sizeof(r->req.sense)); |
623 | + } else { |
624 | +- int status = scsi_sense_from_errno(error, &sense); |
625 | + if (status == CHECK_CONDITION) { |
626 | + scsi_req_build_sense(&r->req, sense); |
627 | + } |
628 | +@@ -240,8 +254,10 @@ static bool scsi_disk_req_check_error(SCSIDiskReq *r, int ret, bool acct_failed) |
629 | + return true; |
630 | + } |
631 | + |
632 | +- if (ret < 0 || (r->status && *r->status)) { |
633 | +- return scsi_handle_rw_error(r, -ret, acct_failed); |
634 | ++ if (ret < 0) { |
635 | ++ return scsi_handle_rw_error(r, ret, acct_failed); |
636 | ++ } else if (r->status && *r->status) { |
637 | ++ return scsi_handle_rw_error(r, *r->status, acct_failed); |
638 | + } |
639 | + |
640 | + return false; |
641 | +-- |
642 | +2.35.1 |
643 | + |
644 | diff --git a/debian/patches/ubuntu/lp-1967814-scsi-fix-sense-code-for-EREMOTEIO.patch b/debian/patches/ubuntu/lp-1967814-scsi-fix-sense-code-for-EREMOTEIO.patch |
645 | new file mode 100644 |
646 | index 0000000..ec85439 |
647 | --- /dev/null |
648 | +++ b/debian/patches/ubuntu/lp-1967814-scsi-fix-sense-code-for-EREMOTEIO.patch |
649 | @@ -0,0 +1,51 @@ |
650 | +From dc293f60b02ff9a4d51ccae153b1685cc8a34d79 Mon Sep 17 00:00:00 2001 |
651 | +From: Paolo Bonzini <pbonzini@redhat.com> |
652 | +Date: Tue, 9 Mar 2021 14:56:42 +0100 |
653 | +Subject: [PATCH] scsi: fix sense code for EREMOTEIO |
654 | +MIME-Version: 1.0 |
655 | +Content-Type: text/plain; charset=UTF-8 |
656 | +Content-Transfer-Encoding: 8bit |
657 | + |
658 | +SENSE_CODE(LUN_COMM_FAILURE) has an ABORTED COMMAND sense key, |
659 | +so it results in a retry in Linux. To ensure that EREMOTEIO |
660 | +is forwarded to the guest, use a HARDWARE ERROR sense key |
661 | +instead. Note that the code before commit d7a84021d was incorrect |
662 | +because it used HARDWARE_ERROR as a SCSI status, not as a sense |
663 | +key. |
664 | + |
665 | +Reported-by: Marc-André Lureau <marcandre.lureau@redhat.com> |
666 | +Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
667 | + |
668 | +Origin: upstream, https://git.qemu.org/?p=qemu.git;a=commit;h=dc293f60b02ff9a4d51ccae153b1685cc8a34d79 |
669 | +Bug-Ubuntu: https://bugs.launchpad.net/bugs/1967814 |
670 | +Last-Update: 2022-04-06 |
671 | + |
672 | +--- |
673 | + scsi/utils.c | 4 ++-- |
674 | + 1 file changed, 2 insertions(+), 2 deletions(-) |
675 | + |
676 | +diff --git a/scsi/utils.c b/scsi/utils.c |
677 | +index 873e05aeaf..357b036671 100644 |
678 | +--- a/scsi/utils.c |
679 | ++++ b/scsi/utils.c |
680 | +@@ -589,7 +589,7 @@ int scsi_sense_from_errno(int errno_value, SCSISense *sense) |
681 | + return TASK_SET_FULL; |
682 | + #ifdef CONFIG_LINUX |
683 | + /* These errno mapping are specific to Linux. For more information: |
684 | +- * - scsi_decide_disposition in drivers/scsi/scsi_error.c |
685 | ++ * - scsi_check_sense and scsi_decide_disposition in drivers/scsi/scsi_error.c |
686 | + * - scsi_result_to_blk_status in drivers/scsi/scsi_lib.c |
687 | + * - blk_errors[] in block/blk-core.c |
688 | + */ |
689 | +@@ -599,7 +599,7 @@ int scsi_sense_from_errno(int errno_value, SCSISense *sense) |
690 | + *sense = SENSE_CODE(READ_ERROR); |
691 | + return CHECK_CONDITION; |
692 | + case EREMOTEIO: |
693 | +- *sense = SENSE_CODE(LUN_COMM_FAILURE); |
694 | ++ *sense = SENSE_CODE(TARGET_FAILURE); |
695 | + return CHECK_CONDITION; |
696 | + #endif |
697 | + case ENOMEDIUM: |
698 | +-- |
699 | +2.35.1 |
700 | + |
701 | diff --git a/debian/patches/ubuntu/lp-1967814-scsi-inline-sg_io_sense_from_errno-into-the-callers.patch b/debian/patches/ubuntu/lp-1967814-scsi-inline-sg_io_sense_from_errno-into-the-callers.patch |
702 | new file mode 100644 |
703 | index 0000000..8dc5b2d |
704 | --- /dev/null |
705 | +++ b/debian/patches/ubuntu/lp-1967814-scsi-inline-sg_io_sense_from_errno-into-the-callers.patch |
706 | @@ -0,0 +1,251 @@ |
707 | +From a108557bbff8a3f44233982f015f996426411be8 Mon Sep 17 00:00:00 2001 |
708 | +From: Hannes Reinecke <hare@suse.de> |
709 | +Date: Mon, 16 Nov 2020 19:40:40 +0100 |
710 | +Subject: [PATCH] scsi: inline sg_io_sense_from_errno() into the callers. |
711 | + |
712 | +Currently sg_io_sense_from_errno() converts the two input parameters |
713 | +'errno' and 'io_hdr' into sense code and SCSI status. Having |
714 | +split the function off into scsi_sense_from_errno() and |
715 | +scsi_sense_from_host_status(), both of which are available generically, |
716 | +we now inline the logic in the callers so that scsi-disk and |
717 | +scsi-generic will be able to pass host_status to the HBA. |
718 | + |
719 | +Signed-off-by: Hannes Reinecke <hare@suse.de> |
720 | +Message-Id: <20201116184041.60465-7-hare@suse.de> |
721 | +[Put together from "scsi-disk: Add sg_io callback to evaluate status" |
722 | + and what remains of "scsi: split sg_io_sense_from_errno() in two functions", |
723 | + with many other fixes. - Paolo] |
724 | +Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
725 | + |
726 | +Origin: backport, https://git.qemu.org/?p=qemu.git;a=commit;h=a108557bbff8a3f44233982f015f996426411be8 |
727 | +Bug-Ubuntu: https://bugs.launchpad.net/bugs/1967814 |
728 | +Last-Update: 2022-04-06 |
729 | + |
730 | +--- |
731 | + hw/scsi/scsi-disk.c | 47 +++++++++++++++++++++++++++++++++++++----- |
732 | + hw/scsi/scsi-generic.c | 22 ++++++++++++++------ |
733 | + include/scsi/utils.h | 3 --- |
734 | + scsi/qemu-pr-helper.c | 24 ++++++++++++++------- |
735 | + scsi/utils.c | 23 --------------------- |
736 | + 5 files changed, 75 insertions(+), 44 deletions(-) |
737 | + |
738 | +diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c |
739 | +index f14c435a38..d6c2a28ac2 100644 |
740 | +--- a/hw/scsi/scsi-disk.c |
741 | ++++ b/hw/scsi/scsi-disk.c |
742 | +@@ -80,7 +80,6 @@ typedef struct SCSIDiskReq { |
743 | + struct iovec iov; |
744 | + QEMUIOVector qiov; |
745 | + BlockAcctCookie acct; |
746 | +- unsigned char *status; |
747 | + } SCSIDiskReq; |
748 | + |
749 | + #define SCSI_DISK_F_REMOVABLE 0 |
750 | +@@ -261,8 +260,6 @@ static bool scsi_disk_req_check_error(SCSIDiskReq *r, int ret, bool acct_failed) |
751 | + |
752 | + if (ret < 0) { |
753 | + return scsi_handle_rw_error(r, ret, acct_failed); |
754 | +- } else if (r->status && *r->status) { |
755 | +- return scsi_handle_rw_error(r, *r->status, acct_failed); |
756 | + } |
757 | + |
758 | + return false; |
759 | +@@ -2698,8 +2695,47 @@ typedef struct SCSIBlockReq { |
760 | + |
761 | + /* CDB passed to SG_IO. */ |
762 | + uint8_t cdb[16]; |
763 | ++ BlockCompletionFunc *cb; |
764 | ++ void *cb_opaque; |
765 | + } SCSIBlockReq; |
766 | + |
767 | ++static void scsi_block_sgio_complete(void *opaque, int ret) |
768 | ++{ |
769 | ++ SCSIBlockReq *req = (SCSIBlockReq *)opaque; |
770 | ++ SCSIDiskReq *r = &req->req; |
771 | ++ SCSIDevice *s = r->req.dev; |
772 | ++ sg_io_hdr_t *io_hdr = &req->io_header; |
773 | ++ SCSISense sense; |
774 | ++ |
775 | ++ if (ret == 0) { |
776 | ++ if (io_hdr->host_status != SCSI_HOST_OK) { |
777 | ++ ret = scsi_sense_from_host_status(io_hdr->host_status, &sense); |
778 | ++ if (ret == CHECK_CONDITION) { |
779 | ++ scsi_req_build_sense(&r->req, sense); |
780 | ++ } |
781 | ++ } else if (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT) { |
782 | ++ ret = BUSY; |
783 | ++ } else { |
784 | ++ ret = io_hdr->status; |
785 | ++ } |
786 | ++ |
787 | ++ if (ret > 0) { |
788 | ++ aio_context_acquire(blk_get_aio_context(s->conf.blk)); |
789 | ++ if (scsi_handle_rw_error(r, ret, true)) { |
790 | ++ aio_context_release(blk_get_aio_context(s->conf.blk)); |
791 | ++ scsi_req_unref(&r->req); |
792 | ++ return; |
793 | ++ } |
794 | ++ aio_context_release(blk_get_aio_context(s->conf.blk)); |
795 | ++ |
796 | ++ /* Ignore error. */ |
797 | ++ ret = 0; |
798 | ++ } |
799 | ++ } |
800 | ++ |
801 | ++ req->cb(req->cb_opaque, ret); |
802 | ++} |
803 | ++ |
804 | + static BlockAIOCB *scsi_block_do_sgio(SCSIBlockReq *req, |
805 | + int64_t offset, QEMUIOVector *iov, |
806 | + int direction, |
807 | +@@ -2779,7 +2815,9 @@ static BlockAIOCB *scsi_block_do_sgio(SCSIBlockReq *req, |
808 | + io_header->usr_ptr = r; |
809 | + io_header->flags |= SG_FLAG_DIRECT_IO; |
810 | + |
811 | +- aiocb = blk_aio_ioctl(s->qdev.conf.blk, SG_IO, io_header, cb, opaque); |
812 | ++ req->cb = cb; |
813 | ++ req->cb_opaque = opaque; |
814 | ++ aiocb = blk_aio_ioctl(s->qdev.conf.blk, SG_IO, io_header, scsi_block_sgio_complete, req); |
815 | + assert(aiocb != NULL); |
816 | + return aiocb; |
817 | + } |
818 | +@@ -2893,7 +2931,6 @@ static int32_t scsi_block_dma_command(SCSIRequest *req, uint8_t *buf) |
819 | + return 0; |
820 | + } |
821 | + |
822 | +- r->req.status = &r->io_header.status; |
823 | + return scsi_disk_dma_command(req, buf); |
824 | + } |
825 | + |
826 | +diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c |
827 | +index e7798ebcd0..740f601b51 100644 |
828 | +--- a/hw/scsi/scsi-generic.c |
829 | ++++ b/hw/scsi/scsi-generic.c |
830 | +@@ -74,6 +74,7 @@ static void scsi_command_complete_noio(SCSIGenericReq *r, int ret) |
831 | + { |
832 | + int status; |
833 | + SCSISense sense; |
834 | ++ sg_io_hdr_t *io_hdr = &r->io_header; |
835 | + |
836 | + assert(r->req.aiocb == NULL); |
837 | + |
838 | +@@ -81,15 +82,24 @@ static void scsi_command_complete_noio(SCSIGenericReq *r, int ret) |
839 | + scsi_req_cancel_complete(&r->req); |
840 | + goto done; |
841 | + } |
842 | +- status = sg_io_sense_from_errno(-ret, &r->io_header, &sense); |
843 | +- if (status == CHECK_CONDITION) { |
844 | +- if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) { |
845 | +- r->req.sense_len = r->io_header.sb_len_wr; |
846 | +- } else { |
847 | ++ if (ret < 0) { |
848 | ++ status = scsi_sense_from_errno(-ret, &sense); |
849 | ++ if (status == CHECK_CONDITION) { |
850 | ++ scsi_req_build_sense(&r->req, sense); |
851 | ++ } |
852 | ++ } else if (io_hdr->host_status != SCSI_HOST_OK) { |
853 | ++ status = scsi_sense_from_host_status(io_hdr->host_status, &sense); |
854 | ++ if (status == CHECK_CONDITION) { |
855 | + scsi_req_build_sense(&r->req, sense); |
856 | + } |
857 | ++ } else if (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT) { |
858 | ++ status = BUSY; |
859 | ++ } else { |
860 | ++ status = io_hdr->status; |
861 | ++ if (io_hdr->driver_status & SG_ERR_DRIVER_SENSE) { |
862 | ++ r->req.sense_len = io_hdr->sb_len_wr; |
863 | ++ } |
864 | + } |
865 | +- |
866 | + trace_scsi_generic_command_complete_noio(r, r->req.tag, status); |
867 | + |
868 | + scsi_req_complete(&r->req, status); |
869 | +diff --git a/include/scsi/utils.h b/include/scsi/utils.h |
870 | +index 490d783e44..581caf15e0 100644 |
871 | +--- a/include/scsi/utils.h |
872 | ++++ b/include/scsi/utils.h |
873 | +@@ -137,9 +137,6 @@ int scsi_cdb_length(uint8_t *buf); |
874 | + #ifdef CONFIG_LINUX |
875 | + #define SG_ERR_DRIVER_TIMEOUT 0x06 |
876 | + #define SG_ERR_DRIVER_SENSE 0x08 |
877 | +- |
878 | +-int sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr, |
879 | +- SCSISense *sense); |
880 | + #endif |
881 | + |
882 | + int scsi_sense_from_errno(int errno_value, SCSISense *sense); |
883 | +diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c |
884 | +index debb18f4aa..7796bb19ac 100644 |
885 | +--- a/scsi/qemu-pr-helper.c |
886 | ++++ b/scsi/qemu-pr-helper.c |
887 | +@@ -149,19 +149,29 @@ static int do_sgio_worker(void *opaque) |
888 | + io_hdr.dxferp = (char *)data->buf; |
889 | + io_hdr.dxfer_len = data->sz; |
890 | + ret = ioctl(data->fd, SG_IO, &io_hdr); |
891 | +- status = sg_io_sense_from_errno(ret < 0 ? errno : 0, &io_hdr, |
892 | +- &sense_code); |
893 | ++ |
894 | ++ if (ret < 0) { |
895 | ++ status = scsi_sense_from_errno(errno, &sense_code); |
896 | ++ if (status == CHECK_CONDITION) { |
897 | ++ scsi_build_sense(data->sense, sense_code); |
898 | ++ } |
899 | ++ } else if (io_hdr.host_status != SCSI_HOST_OK) { |
900 | ++ status = scsi_sense_from_host_status(io_hdr.host_status, &sense_code); |
901 | ++ if (status == CHECK_CONDITION) { |
902 | ++ scsi_build_sense(data->sense, sense_code); |
903 | ++ } |
904 | ++ } else if (io_hdr.driver_status & SG_ERR_DRIVER_TIMEOUT) { |
905 | ++ status = BUSY; |
906 | ++ } else { |
907 | ++ status = io_hdr.status; |
908 | ++ } |
909 | ++ |
910 | + if (status == GOOD) { |
911 | + data->sz -= io_hdr.resid; |
912 | + } else { |
913 | + data->sz = 0; |
914 | + } |
915 | + |
916 | +- if (status == CHECK_CONDITION && |
917 | +- !(io_hdr.driver_status & SG_ERR_DRIVER_SENSE)) { |
918 | +- scsi_build_sense(data->sense, sense_code); |
919 | +- } |
920 | +- |
921 | + return status; |
922 | + } |
923 | + |
924 | +diff --git a/scsi/utils.c b/scsi/utils.c |
925 | +index 2d843c884a..1cb2507149 100644 |
926 | +--- a/scsi/utils.c |
927 | ++++ b/scsi/utils.c |
928 | +@@ -657,26 +657,3 @@ int scsi_sense_from_host_status(uint8_t host_status, |
929 | + } |
930 | + return GOOD; |
931 | + } |
932 | +- |
933 | +-#ifdef CONFIG_LINUX |
934 | +-int sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr, |
935 | +- SCSISense *sense) |
936 | +-{ |
937 | +- if (errno_value != 0) { |
938 | +- return scsi_sense_from_errno(errno_value, sense); |
939 | +- } else { |
940 | +- int status = scsi_sense_from_host_status(io_hdr->host_status, sense); |
941 | +- if (status) { |
942 | +- return status; |
943 | +- } else if (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT) { |
944 | +- return BUSY; |
945 | +- } else if (io_hdr->status) { |
946 | +- return io_hdr->status; |
947 | +- } else if (io_hdr->driver_status & SG_ERR_DRIVER_SENSE) { |
948 | +- return CHECK_CONDITION; |
949 | +- } else { |
950 | +- return GOOD; |
951 | +- } |
952 | +- } |
953 | +-} |
954 | +-#endif |
955 | +-- |
956 | +2.31.1 |
957 | + |
958 | diff --git a/debian/patches/ubuntu/lp-1967814-scsi-introduce-scsi_sense_from_errno.patch b/debian/patches/ubuntu/lp-1967814-scsi-introduce-scsi_sense_from_errno.patch |
959 | new file mode 100644 |
960 | index 0000000..a319280 |
961 | --- /dev/null |
962 | +++ b/debian/patches/ubuntu/lp-1967814-scsi-introduce-scsi_sense_from_errno.patch |
963 | @@ -0,0 +1,172 @@ |
964 | +From d7a84021db8eeddcd5d24ab591a1434763caff6c Mon Sep 17 00:00:00 2001 |
965 | +From: Paolo Bonzini <pbonzini@redhat.com> |
966 | +Date: Wed, 24 Feb 2021 16:30:09 +0100 |
967 | +Subject: [PATCH] scsi: introduce scsi_sense_from_errno() |
968 | + |
969 | +The new function is an extension of the switch statement in scsi-disk.c |
970 | +which also includes the errno cases only found in sg_io_sense_from_errno. |
971 | +This allows us to consolidate the errno handling. |
972 | + |
973 | +Extracted from a patch by Hannes Reinecke <hare@suse.de>. |
974 | + |
975 | +Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
976 | + |
977 | +Origin: upstream, https://git.qemu.org/?p=qemu.git;a=commit;h=d7a84021db8eeddcd5d24ab591a1434763caff6c |
978 | +Bug-Ubuntu: https://bugs.launchpad.net/bugs/1967814 |
979 | +Last-Update: 2022-04-06 |
980 | + |
981 | +--- |
982 | + hw/scsi/scsi-disk.c | 45 +++++++------------------------------- |
983 | + include/scsi/utils.h | 2 ++ |
984 | + scsi/utils.c | 51 +++++++++++++++++++++++++++++++++++--------- |
985 | + 3 files changed, 51 insertions(+), 47 deletions(-) |
986 | + |
987 | +diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c |
988 | +index 36aa872445..9c6099ffc4 100644 |
989 | +--- a/hw/scsi/scsi-disk.c |
990 | ++++ b/hw/scsi/scsi-disk.c |
991 | +@@ -194,13 +194,13 @@ static bool scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed) |
992 | + SCSIDiskClass *sdc = (SCSIDiskClass *) object_get_class(OBJECT(s)); |
993 | + BlockErrorAction action = blk_get_error_action(s->qdev.conf.blk, |
994 | + is_read, error); |
995 | ++ SCSISense sense; |
996 | + |
997 | + if (action == BLOCK_ERROR_ACTION_REPORT) { |
998 | + if (acct_failed) { |
999 | + block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct); |
1000 | + } |
1001 | +- switch (error) { |
1002 | +- case 0: |
1003 | ++ if (error == 0) { |
1004 | + /* A passthrough command has run and has produced sense data; check |
1005 | + * whether the error has to be handled by the guest or should rather |
1006 | + * pause the host. |
1007 | +@@ -213,41 +213,12 @@ static bool scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed) |
1008 | + return true; |
1009 | + } |
1010 | + error = scsi_sense_buf_to_errno(r->req.sense, sizeof(r->req.sense)); |
1011 | +- break; |
1012 | +-#ifdef CONFIG_LINUX |
1013 | +- /* These errno mapping are specific to Linux. For more information: |
1014 | +- * - scsi_decide_disposition in drivers/scsi/scsi_error.c |
1015 | +- * - scsi_result_to_blk_status in drivers/scsi/scsi_lib.c |
1016 | +- * - blk_errors[] in block/blk-core.c |
1017 | +- */ |
1018 | +- case EBADE: |
1019 | +- /* DID_NEXUS_FAILURE -> BLK_STS_NEXUS. */ |
1020 | +- scsi_req_complete(&r->req, RESERVATION_CONFLICT); |
1021 | +- break; |
1022 | +- case ENODATA: |
1023 | +- /* DID_MEDIUM_ERROR -> BLK_STS_MEDIUM. */ |
1024 | +- scsi_check_condition(r, SENSE_CODE(READ_ERROR)); |
1025 | +- break; |
1026 | +- case EREMOTEIO: |
1027 | +- /* DID_TARGET_FAILURE -> BLK_STS_TARGET. */ |
1028 | +- scsi_req_complete(&r->req, HARDWARE_ERROR); |
1029 | +- break; |
1030 | +-#endif |
1031 | +- case ENOMEDIUM: |
1032 | +- scsi_check_condition(r, SENSE_CODE(NO_MEDIUM)); |
1033 | +- break; |
1034 | +- case ENOMEM: |
1035 | +- scsi_check_condition(r, SENSE_CODE(TARGET_FAILURE)); |
1036 | +- break; |
1037 | +- case EINVAL: |
1038 | +- scsi_check_condition(r, SENSE_CODE(INVALID_FIELD)); |
1039 | +- break; |
1040 | +- case ENOSPC: |
1041 | +- scsi_check_condition(r, SENSE_CODE(SPACE_ALLOC_FAILED)); |
1042 | +- break; |
1043 | +- default: |
1044 | +- scsi_check_condition(r, SENSE_CODE(IO_ERROR)); |
1045 | +- break; |
1046 | ++ } else { |
1047 | ++ int status = scsi_sense_from_errno(error, &sense); |
1048 | ++ if (status == CHECK_CONDITION) { |
1049 | ++ scsi_req_build_sense(&r->req, sense); |
1050 | ++ } |
1051 | ++ scsi_req_complete(&r->req, status); |
1052 | + } |
1053 | + } |
1054 | + |
1055 | +diff --git a/include/scsi/utils.h b/include/scsi/utils.h |
1056 | +index 096489c6cd..ff7c7091b6 100644 |
1057 | +--- a/include/scsi/utils.h |
1058 | ++++ b/include/scsi/utils.h |
1059 | +@@ -135,4 +135,6 @@ int sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr, |
1060 | + SCSISense *sense); |
1061 | + #endif |
1062 | + |
1063 | ++int scsi_sense_from_errno(int errno_value, SCSISense *sense); |
1064 | ++ |
1065 | + #endif |
1066 | +diff --git a/scsi/utils.c b/scsi/utils.c |
1067 | +index 793c3a6b9c..6b56e01002 100644 |
1068 | +--- a/scsi/utils.c |
1069 | ++++ b/scsi/utils.c |
1070 | +@@ -565,21 +565,52 @@ const char *scsi_command_name(uint8_t cmd) |
1071 | + return names[cmd]; |
1072 | + } |
1073 | + |
1074 | ++int scsi_sense_from_errno(int errno_value, SCSISense *sense) |
1075 | ++{ |
1076 | ++ switch (errno_value) { |
1077 | ++ case 0: |
1078 | ++ return GOOD; |
1079 | ++ case EDOM: |
1080 | ++ return TASK_SET_FULL; |
1081 | ++#ifdef CONFIG_LINUX |
1082 | ++ /* These errno mapping are specific to Linux. For more information: |
1083 | ++ * - scsi_decide_disposition in drivers/scsi/scsi_error.c |
1084 | ++ * - scsi_result_to_blk_status in drivers/scsi/scsi_lib.c |
1085 | ++ * - blk_errors[] in block/blk-core.c |
1086 | ++ */ |
1087 | ++ case EBADE: |
1088 | ++ return RESERVATION_CONFLICT; |
1089 | ++ case ENODATA: |
1090 | ++ *sense = SENSE_CODE(READ_ERROR); |
1091 | ++ return CHECK_CONDITION; |
1092 | ++ case EREMOTEIO: |
1093 | ++ *sense = SENSE_CODE(LUN_COMM_FAILURE); |
1094 | ++ return CHECK_CONDITION; |
1095 | ++#endif |
1096 | ++ case ENOMEDIUM: |
1097 | ++ *sense = SENSE_CODE(NO_MEDIUM); |
1098 | ++ return CHECK_CONDITION; |
1099 | ++ case ENOMEM: |
1100 | ++ *sense = SENSE_CODE(TARGET_FAILURE); |
1101 | ++ return CHECK_CONDITION; |
1102 | ++ case EINVAL: |
1103 | ++ *sense = SENSE_CODE(INVALID_FIELD); |
1104 | ++ return CHECK_CONDITION; |
1105 | ++ case ENOSPC: |
1106 | ++ *sense = SENSE_CODE(SPACE_ALLOC_FAILED); |
1107 | ++ return CHECK_CONDITION; |
1108 | ++ default: |
1109 | ++ *sense = SENSE_CODE(IO_ERROR); |
1110 | ++ return CHECK_CONDITION; |
1111 | ++ } |
1112 | ++} |
1113 | ++ |
1114 | + #ifdef CONFIG_LINUX |
1115 | + int sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr, |
1116 | + SCSISense *sense) |
1117 | + { |
1118 | + if (errno_value != 0) { |
1119 | +- switch (errno_value) { |
1120 | +- case EDOM: |
1121 | +- return TASK_SET_FULL; |
1122 | +- case ENOMEM: |
1123 | +- *sense = SENSE_CODE(TARGET_FAILURE); |
1124 | +- return CHECK_CONDITION; |
1125 | +- default: |
1126 | +- *sense = SENSE_CODE(IO_ERROR); |
1127 | +- return CHECK_CONDITION; |
1128 | +- } |
1129 | ++ return scsi_sense_from_errno(errno_value, sense); |
1130 | + } else { |
1131 | + if (io_hdr->host_status == SG_ERR_DID_NO_CONNECT || |
1132 | + io_hdr->host_status == SG_ERR_DID_BUS_BUSY || |
1133 | +-- |
1134 | +2.35.1 |
1135 | + |
PPA: https:/ /launchpad. net/~paelzer/ +archive/ ubuntu/ lp-1967814- scsi-error- handling