Merge ~paelzer/ubuntu/+source/qemu:lp-1967814-scsi-error-handling into ubuntu/+source/qemu: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)
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
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
1diff --git a/debian/changelog b/debian/changelog
2index 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
18diff --git a/debian/patches/series b/debian/patches/series
19index 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
34diff --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
35new file mode 100644
36index 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+
166diff --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
167new file mode 100644
168index 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+
262diff --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
263new file mode 100644
264index 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+
322diff --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
323new file mode 100644
324index 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+
541diff --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
542new file mode 100644
543index 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+
644diff --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
645new file mode 100644
646index 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+
701diff --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
702new file mode 100644
703index 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+
958diff --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
959new file mode 100644
960index 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+

Subscribers

People subscribed via source and target branches