1
The following changes since commit 23919ddfd56135cad3cb468a8f54d5a595f024f4:
1
The following changes since commit 813bac3d8d70d85cb7835f7945eb9eed84c2d8d0:
2
2
3
Merge remote-tracking branch 'remotes/aperard/tags/pull-xen-20190827' into staging (2019-08-27 15:52:36 +0100)
3
Merge tag '2023q3-bsd-user-pull-request' of https://gitlab.com/bsdimp/qemu into staging (2023-08-29 08:58:00 -0400)
4
4
5
are available in the Git repository at:
5
are available in the Git repository at:
6
6
7
https://github.com/XanClic/qemu.git tags/pull-block-2019-08-27
7
https://gitlab.com/stefanha/qemu.git tags/block-pull-request
8
8
9
for you to fetch changes up to bb043c056cffcc2f3ce88bfdaf2e76e455c09e2c:
9
for you to fetch changes up to 3f5f2285bfcdd855508a55da7875fb92de1a6ed0:
10
10
11
iotests: Unify cache mode quoting (2019-08-27 19:48:44 +0200)
11
tests/qemu-iotests/197: add testcase for CoR with subclusters (2023-08-29 13:19:56 -0400)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block patches:
14
Pull request
15
- qemu-io now accepts a file to read a write pattern from
15
16
- Ensure that raw files have their first block allocated so we can probe
16
v2:
17
the O_DIRECT alignment if necessary
17
- Fix authorship information lost by the mailing list for Andrey Drobyshev
18
- Various fixes
19
18
20
----------------------------------------------------------------
19
----------------------------------------------------------------
21
Denis Plotnikov (1):
22
qemu-io: add pattern file for write command
23
20
24
Max Reitz (7):
21
Andrey Drobyshev (3):
25
iotests: Fix _filter_img_create()
22
block: add subcluster_size field to BlockDriverInfo
26
vmdk: Use bdrv_dirname() for relative extent paths
23
block/io: align requests to subcluster_size
27
iotests: Keep testing broken relative extent paths
24
tests/qemu-iotests/197: add testcase for CoR with subclusters
28
vmdk: Reject invalid compressed writes
29
iotests: Disable broken streamOptimized tests
30
iotests: Disable 110 for vmdk.twoGbMaxExtentSparse
31
iotests: Disable 126 for flat vmdk subformats
32
25
33
Nir Soffer (3):
26
Fabiano Rosas (1):
34
block: posix: Always allocate the first block
27
block-migration: Ensure we don't crash during migration cleanup
35
iotests: Test allocate_first_block() with O_DIRECT
36
iotests: Unify cache mode quoting
37
28
38
Stefan Hajnoczi (1):
29
Jeuk Kim (4):
39
file-posix: fix request_alignment typo
30
hw/ufs: Initial commit for emulated Universal-Flash-Storage
31
hw/ufs: Support for Query Transfer Requests
32
hw/ufs: Support for UFS logical unit
33
tests/qtest: Introduce tests for UFS
40
34
41
Thomas Huth (2):
35
MAINTAINERS | 7 +
42
iotests: Check for enabled drivers before testing them
36
docs/specs/pci-ids.rst | 2 +
43
tests/check-block: Skip iotests when sanitizers are enabled
37
meson.build | 1 +
44
38
hw/ufs/trace.h | 1 +
45
Vladimir Sementsov-Ogievskiy (1):
39
hw/ufs/ufs.h | 131 +++
46
block: fix permission update in bdrv_replace_node
40
include/block/block-common.h | 5 +
47
41
include/block/block-io.h | 8 +-
48
block.c | 5 +-
42
include/block/ufs.h | 1090 +++++++++++++++++++++++++
49
block/file-posix.c | 53 +++++++++-
43
include/hw/pci/pci.h | 1 +
50
block/vmdk.c | 64 ++++++++----
44
include/hw/pci/pci_ids.h | 1 +
51
qemu-io-cmds.c | 99 +++++++++++++++++--
45
include/scsi/constants.h | 1 +
52
tests/check-block.sh | 5 +
46
block.c | 7 +
53
tests/qemu-iotests/002 | 1 +
47
block/io.c | 50 +-
54
tests/qemu-iotests/003 | 1 +
48
block/mirror.c | 8 +-
55
tests/qemu-iotests/005 | 3 +-
49
block/qcow2.c | 1 +
56
tests/qemu-iotests/009 | 1 +
50
hw/ufs/lu.c | 1445 ++++++++++++++++++++++++++++++++
57
tests/qemu-iotests/010 | 1 +
51
hw/ufs/ufs.c | 1494 ++++++++++++++++++++++++++++++++++
58
tests/qemu-iotests/011 | 1 +
52
migration/block.c | 11 +-
59
tests/qemu-iotests/017 | 3 +-
53
tests/qtest/ufs-test.c | 584 +++++++++++++
60
tests/qemu-iotests/018 | 3 +-
54
hw/Kconfig | 1 +
61
tests/qemu-iotests/019 | 3 +-
55
hw/meson.build | 1 +
62
tests/qemu-iotests/020 | 3 +-
56
hw/ufs/Kconfig | 4 +
63
tests/qemu-iotests/026 | 4 +-
57
hw/ufs/meson.build | 1 +
64
tests/qemu-iotests/027 | 1 +
58
hw/ufs/trace-events | 58 ++
65
tests/qemu-iotests/032 | 1 +
59
tests/qemu-iotests/197 | 29 +
66
tests/qemu-iotests/033 | 1 +
60
tests/qemu-iotests/197.out | 24 +
67
tests/qemu-iotests/034 | 3 +-
61
tests/qtest/meson.build | 1 +
68
tests/qemu-iotests/037 | 3 +-
62
27 files changed, 4932 insertions(+), 35 deletions(-)
69
tests/qemu-iotests/039 | 4 +-
63
create mode 100644 hw/ufs/trace.h
70
tests/qemu-iotests/052 | 2 +-
64
create mode 100644 hw/ufs/ufs.h
71
tests/qemu-iotests/059 | 34 ++++++-
65
create mode 100644 include/block/ufs.h
72
tests/qemu-iotests/059.out | 26 +++--
66
create mode 100644 hw/ufs/lu.c
73
tests/qemu-iotests/063 | 3 +-
67
create mode 100644 hw/ufs/ufs.c
74
tests/qemu-iotests/071 | 1 +
68
create mode 100644 tests/qtest/ufs-test.c
75
tests/qemu-iotests/072 | 1 +
69
create mode 100644 hw/ufs/Kconfig
76
tests/qemu-iotests/081 | 4 +-
70
create mode 100644 hw/ufs/meson.build
77
tests/qemu-iotests/091 | 4 +-
71
create mode 100644 hw/ufs/trace-events
78
tests/qemu-iotests/099 | 1 +
79
tests/qemu-iotests/105 | 3 +-
80
tests/qemu-iotests/110 | 3 +-
81
tests/qemu-iotests/120 | 1 +
82
tests/qemu-iotests/126 | 2 +
83
tests/qemu-iotests/{150.out => 150.out.qcow2} | 0
84
tests/qemu-iotests/150.out.raw | 12 +++
85
tests/qemu-iotests/162 | 4 +-
86
tests/qemu-iotests/175 | 47 +++++++--
87
tests/qemu-iotests/175.out | 16 ++-
88
tests/qemu-iotests/178.out.qcow2 | 4 +-
89
tests/qemu-iotests/184 | 1 +
90
tests/qemu-iotests/186 | 1 +
91
tests/qemu-iotests/197 | 1 +
92
tests/qemu-iotests/215 | 1 +
93
tests/qemu-iotests/221.out | 12 ++-
94
tests/qemu-iotests/251 | 1 +
95
tests/qemu-iotests/253.out | 12 ++-
96
tests/qemu-iotests/common.filter | 4 +-
97
tests/qemu-iotests/common.rc | 14 +++
98
50 files changed, 391 insertions(+), 87 deletions(-)
99
rename tests/qemu-iotests/{150.out => 150.out.qcow2} (100%)
100
create mode 100644 tests/qemu-iotests/150.out.raw
101
72
102
--
73
--
103
2.21.0
74
2.41.0
104
105
diff view generated by jsdifflib
1
From: Denis Plotnikov <dplotnikov@virtuozzo.com>
1
From: Jeuk Kim <jeuk20.kim@gmail.com>
2
2
3
The patch allows to provide a pattern file for write
3
Universal Flash Storage (UFS) is a high-performance mass storage device
4
command. There was no similar ability before.
4
with a serial interface. It is primarily used as a high-performance
5
data storage device for embedded applications.
5
6
6
Signed-off-by: Denis Plotnikov <dplotnikov@virtuozzo.com>
7
This commit contains code for UFS device to be recognized
7
Message-id: 20190820164616.4072-1-dplotnikov@virtuozzo.com
8
as a UFS PCI device.
8
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Patches to handle UFS logical unit and Transfer Request will follow.
9
[mreitz: Keep optstring in alphabetical order]
10
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>
12
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
13
Message-id: 9f3db32fe1c708090a6bb764d456973b5abef55f.1691062912.git.jeuk20.kim@samsung.com
14
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
---
15
---
12
qemu-io-cmds.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++---
16
MAINTAINERS | 6 +
13
1 file changed, 93 insertions(+), 6 deletions(-)
17
docs/specs/pci-ids.rst | 2 +
18
meson.build | 1 +
19
hw/ufs/trace.h | 1 +
20
hw/ufs/ufs.h | 42 ++
21
include/block/ufs.h | 1090 ++++++++++++++++++++++++++++++++++++++
22
include/hw/pci/pci.h | 1 +
23
include/hw/pci/pci_ids.h | 1 +
24
hw/ufs/ufs.c | 278 ++++++++++
25
hw/Kconfig | 1 +
26
hw/meson.build | 1 +
27
hw/ufs/Kconfig | 4 +
28
hw/ufs/meson.build | 1 +
29
hw/ufs/trace-events | 32 ++
30
14 files changed, 1461 insertions(+)
31
create mode 100644 hw/ufs/trace.h
32
create mode 100644 hw/ufs/ufs.h
33
create mode 100644 include/block/ufs.h
34
create mode 100644 hw/ufs/ufs.c
35
create mode 100644 hw/ufs/Kconfig
36
create mode 100644 hw/ufs/meson.build
37
create mode 100644 hw/ufs/trace-events
14
38
15
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
39
diff --git a/MAINTAINERS b/MAINTAINERS
16
index XXXXXXX..XXXXXXX 100644
40
index XXXXXXX..XXXXXXX 100644
17
--- a/qemu-io-cmds.c
41
--- a/MAINTAINERS
18
+++ b/qemu-io-cmds.c
42
+++ b/MAINTAINERS
19
@@ -XXX,XX +XXX,XX @@ static void qemu_io_free(void *p)
43
@@ -XXX,XX +XXX,XX @@ F: tests/qtest/nvme-test.c
20
qemu_vfree(p);
44
F: docs/system/devices/nvme.rst
21
}
45
T: git git://git.infradead.org/qemu-nvme.git nvme-next
22
46
23
+/*
47
+ufs
24
+ * qemu_io_alloc_from_file()
48
+M: Jeuk Kim <jeuk20.kim@samsung.com>
49
+S: Supported
50
+F: hw/ufs/*
51
+F: include/block/ufs.h
52
+
53
megasas
54
M: Hannes Reinecke <hare@suse.com>
55
L: qemu-block@nongnu.org
56
diff --git a/docs/specs/pci-ids.rst b/docs/specs/pci-ids.rst
57
index XXXXXXX..XXXXXXX 100644
58
--- a/docs/specs/pci-ids.rst
59
+++ b/docs/specs/pci-ids.rst
60
@@ -XXX,XX +XXX,XX @@ PCI devices (other than virtio):
61
PCI PVPanic device (``-device pvpanic-pci``)
62
1b36:0012
63
PCI ACPI ERST device (``-device acpi-erst``)
64
+1b36:0013
65
+ PCI UFS device (``-device ufs``)
66
67
All these devices are documented in :doc:`index`.
68
69
diff --git a/meson.build b/meson.build
70
index XXXXXXX..XXXXXXX 100644
71
--- a/meson.build
72
+++ b/meson.build
73
@@ -XXX,XX +XXX,XX @@ if have_system
74
'hw/ssi',
75
'hw/timer',
76
'hw/tpm',
77
+ 'hw/ufs',
78
'hw/usb',
79
'hw/vfio',
80
'hw/virtio',
81
diff --git a/hw/ufs/trace.h b/hw/ufs/trace.h
82
new file mode 100644
83
index XXXXXXX..XXXXXXX
84
--- /dev/null
85
+++ b/hw/ufs/trace.h
86
@@ -0,0 +1 @@
87
+#include "trace/trace-hw_ufs.h"
88
diff --git a/hw/ufs/ufs.h b/hw/ufs/ufs.h
89
new file mode 100644
90
index XXXXXXX..XXXXXXX
91
--- /dev/null
92
+++ b/hw/ufs/ufs.h
93
@@ -XXX,XX +XXX,XX @@
94
+/*
95
+ * QEMU UFS
25
+ *
96
+ *
26
+ * Allocates the buffer and populates it with the content of the given file
97
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd. All rights reserved.
27
+ * up to @len bytes. If the file length is less than @len, then the buffer
28
+ * is populated with the file content cyclically.
29
+ *
98
+ *
30
+ * @blk - the block backend where the buffer content is going to be written to
99
+ * Written by Jeuk Kim <jeuk20.kim@samsung.com>
31
+ * @len - the buffer length
32
+ * @file_name - the file to read the content from
33
+ *
100
+ *
34
+ * Returns: the buffer pointer on success
101
+ * SPDX-License-Identifier: GPL-2.0-or-later
35
+ * NULL on error
102
+ */
36
+ */
103
+
37
+static void *qemu_io_alloc_from_file(BlockBackend *blk, size_t len,
104
+#ifndef HW_UFS_UFS_H
38
+ const char *file_name)
105
+#define HW_UFS_UFS_H
106
+
107
+#include "hw/pci/pci_device.h"
108
+#include "hw/scsi/scsi.h"
109
+#include "block/ufs.h"
110
+
111
+#define UFS_MAX_LUS 32
112
+#define UFS_BLOCK_SIZE 4096
113
+
114
+typedef struct UfsParams {
115
+ char *serial;
116
+ uint8_t nutrs; /* Number of UTP Transfer Request Slots */
117
+ uint8_t nutmrs; /* Number of UTP Task Management Request Slots */
118
+} UfsParams;
119
+
120
+typedef struct UfsHc {
121
+ PCIDevice parent_obj;
122
+ MemoryRegion iomem;
123
+ UfsReg reg;
124
+ UfsParams params;
125
+ uint32_t reg_size;
126
+
127
+ qemu_irq irq;
128
+ QEMUBH *doorbell_bh;
129
+ QEMUBH *complete_bh;
130
+} UfsHc;
131
+
132
+#define TYPE_UFS "ufs"
133
+#define UFS(obj) OBJECT_CHECK(UfsHc, (obj), TYPE_UFS)
134
+
135
+#endif /* HW_UFS_UFS_H */
136
diff --git a/include/block/ufs.h b/include/block/ufs.h
137
new file mode 100644
138
index XXXXXXX..XXXXXXX
139
--- /dev/null
140
+++ b/include/block/ufs.h
141
@@ -XXX,XX +XXX,XX @@
142
+/* SPDX-License-Identifier: GPL-2.0-or-later */
143
+
144
+#ifndef BLOCK_UFS_H
145
+#define BLOCK_UFS_H
146
+
147
+#include "hw/registerfields.h"
148
+
149
+typedef struct QEMU_PACKED UfsReg {
150
+ uint32_t cap;
151
+ uint32_t rsvd0;
152
+ uint32_t ver;
153
+ uint32_t rsvd1;
154
+ uint32_t hcpid;
155
+ uint32_t hcmid;
156
+ uint32_t ahit;
157
+ uint32_t rsvd2;
158
+ uint32_t is;
159
+ uint32_t ie;
160
+ uint32_t rsvd3[2];
161
+ uint32_t hcs;
162
+ uint32_t hce;
163
+ uint32_t uecpa;
164
+ uint32_t uecdl;
165
+ uint32_t uecn;
166
+ uint32_t uect;
167
+ uint32_t uecdme;
168
+ uint32_t utriacr;
169
+ uint32_t utrlba;
170
+ uint32_t utrlbau;
171
+ uint32_t utrldbr;
172
+ uint32_t utrlclr;
173
+ uint32_t utrlrsr;
174
+ uint32_t utrlcnr;
175
+ uint32_t rsvd4[2];
176
+ uint32_t utmrlba;
177
+ uint32_t utmrlbau;
178
+ uint32_t utmrldbr;
179
+ uint32_t utmrlclr;
180
+ uint32_t utmrlrsr;
181
+ uint32_t rsvd5[3];
182
+ uint32_t uiccmd;
183
+ uint32_t ucmdarg1;
184
+ uint32_t ucmdarg2;
185
+ uint32_t ucmdarg3;
186
+ uint32_t rsvd6[4];
187
+ uint32_t rsvd7[4];
188
+ uint32_t rsvd8[16];
189
+ uint32_t ccap;
190
+} UfsReg;
191
+
192
+REG32(CAP, offsetof(UfsReg, cap))
193
+ FIELD(CAP, NUTRS, 0, 5)
194
+ FIELD(CAP, RTT, 8, 8)
195
+ FIELD(CAP, NUTMRS, 16, 3)
196
+ FIELD(CAP, AUTOH8, 23, 1)
197
+ FIELD(CAP, 64AS, 24, 1)
198
+ FIELD(CAP, OODDS, 25, 1)
199
+ FIELD(CAP, UICDMETMS, 26, 1)
200
+ FIELD(CAP, CS, 28, 1)
201
+REG32(VER, offsetof(UfsReg, ver))
202
+REG32(HCPID, offsetof(UfsReg, hcpid))
203
+REG32(HCMID, offsetof(UfsReg, hcmid))
204
+REG32(AHIT, offsetof(UfsReg, ahit))
205
+REG32(IS, offsetof(UfsReg, is))
206
+ FIELD(IS, UTRCS, 0, 1)
207
+ FIELD(IS, UDEPRI, 1, 1)
208
+ FIELD(IS, UE, 2, 1)
209
+ FIELD(IS, UTMS, 3, 1)
210
+ FIELD(IS, UPMS, 4, 1)
211
+ FIELD(IS, UHXS, 5, 1)
212
+ FIELD(IS, UHES, 6, 1)
213
+ FIELD(IS, ULLS, 7, 1)
214
+ FIELD(IS, ULSS, 8, 1)
215
+ FIELD(IS, UTMRCS, 9, 1)
216
+ FIELD(IS, UCCS, 10, 1)
217
+ FIELD(IS, DFES, 11, 1)
218
+ FIELD(IS, UTPES, 12, 1)
219
+ FIELD(IS, HCFES, 16, 1)
220
+ FIELD(IS, SBFES, 17, 1)
221
+ FIELD(IS, CEFES, 18, 1)
222
+REG32(IE, offsetof(UfsReg, ie))
223
+ FIELD(IE, UTRCE, 0, 1)
224
+ FIELD(IE, UDEPRIE, 1, 1)
225
+ FIELD(IE, UEE, 2, 1)
226
+ FIELD(IE, UTMSE, 3, 1)
227
+ FIELD(IE, UPMSE, 4, 1)
228
+ FIELD(IE, UHXSE, 5, 1)
229
+ FIELD(IE, UHESE, 6, 1)
230
+ FIELD(IE, ULLSE, 7, 1)
231
+ FIELD(IE, ULSSE, 8, 1)
232
+ FIELD(IE, UTMRCE, 9, 1)
233
+ FIELD(IE, UCCE, 10, 1)
234
+ FIELD(IE, DFEE, 11, 1)
235
+ FIELD(IE, UTPEE, 12, 1)
236
+ FIELD(IE, HCFEE, 16, 1)
237
+ FIELD(IE, SBFEE, 17, 1)
238
+ FIELD(IE, CEFEE, 18, 1)
239
+REG32(HCS, offsetof(UfsReg, hcs))
240
+ FIELD(HCS, DP, 0, 1)
241
+ FIELD(HCS, UTRLRDY, 1, 1)
242
+ FIELD(HCS, UTMRLRDY, 2, 1)
243
+ FIELD(HCS, UCRDY, 3, 1)
244
+ FIELD(HCS, UPMCRS, 8, 3)
245
+REG32(HCE, offsetof(UfsReg, hce))
246
+ FIELD(HCE, HCE, 0, 1)
247
+ FIELD(HCE, CGE, 1, 1)
248
+REG32(UECPA, offsetof(UfsReg, uecpa))
249
+REG32(UECDL, offsetof(UfsReg, uecdl))
250
+REG32(UECN, offsetof(UfsReg, uecn))
251
+REG32(UECT, offsetof(UfsReg, uect))
252
+REG32(UECDME, offsetof(UfsReg, uecdme))
253
+REG32(UTRIACR, offsetof(UfsReg, utriacr))
254
+REG32(UTRLBA, offsetof(UfsReg, utrlba))
255
+ FIELD(UTRLBA, UTRLBA, 9, 22)
256
+REG32(UTRLBAU, offsetof(UfsReg, utrlbau))
257
+REG32(UTRLDBR, offsetof(UfsReg, utrldbr))
258
+REG32(UTRLCLR, offsetof(UfsReg, utrlclr))
259
+REG32(UTRLRSR, offsetof(UfsReg, utrlrsr))
260
+REG32(UTRLCNR, offsetof(UfsReg, utrlcnr))
261
+REG32(UTMRLBA, offsetof(UfsReg, utmrlba))
262
+ FIELD(UTMRLBA, UTMRLBA, 9, 22)
263
+REG32(UTMRLBAU, offsetof(UfsReg, utmrlbau))
264
+REG32(UTMRLDBR, offsetof(UfsReg, utmrldbr))
265
+REG32(UTMRLCLR, offsetof(UfsReg, utmrlclr))
266
+REG32(UTMRLRSR, offsetof(UfsReg, utmrlrsr))
267
+REG32(UICCMD, offsetof(UfsReg, uiccmd))
268
+REG32(UCMDARG1, offsetof(UfsReg, ucmdarg1))
269
+REG32(UCMDARG2, offsetof(UfsReg, ucmdarg2))
270
+REG32(UCMDARG3, offsetof(UfsReg, ucmdarg3))
271
+REG32(CCAP, offsetof(UfsReg, ccap))
272
+
273
+#define UFS_INTR_MASK \
274
+ ((1 << R_IS_CEFES_SHIFT) | (1 << R_IS_SBFES_SHIFT) | \
275
+ (1 << R_IS_HCFES_SHIFT) | (1 << R_IS_UTPES_SHIFT) | \
276
+ (1 << R_IS_DFES_SHIFT) | (1 << R_IS_UCCS_SHIFT) | \
277
+ (1 << R_IS_UTMRCS_SHIFT) | (1 << R_IS_ULSS_SHIFT) | \
278
+ (1 << R_IS_ULLS_SHIFT) | (1 << R_IS_UHES_SHIFT) | \
279
+ (1 << R_IS_UHXS_SHIFT) | (1 << R_IS_UPMS_SHIFT) | \
280
+ (1 << R_IS_UTMS_SHIFT) | (1 << R_IS_UE_SHIFT) | \
281
+ (1 << R_IS_UDEPRI_SHIFT) | (1 << R_IS_UTRCS_SHIFT))
282
+
283
+#define UFS_UPIU_HEADER_TRANSACTION_TYPE_SHIFT 24
284
+#define UFS_UPIU_HEADER_TRANSACTION_TYPE_MASK 0xff
285
+#define UFS_UPIU_HEADER_TRANSACTION_TYPE(dword0) \
286
+ ((be32_to_cpu(dword0) >> UFS_UPIU_HEADER_TRANSACTION_TYPE_SHIFT) & \
287
+ UFS_UPIU_HEADER_TRANSACTION_TYPE_MASK)
288
+
289
+#define UFS_UPIU_HEADER_QUERY_FUNC_SHIFT 16
290
+#define UFS_UPIU_HEADER_QUERY_FUNC_MASK 0xff
291
+#define UFS_UPIU_HEADER_QUERY_FUNC(dword1) \
292
+ ((be32_to_cpu(dword1) >> UFS_UPIU_HEADER_QUERY_FUNC_SHIFT) & \
293
+ UFS_UPIU_HEADER_QUERY_FUNC_MASK)
294
+
295
+#define UFS_UPIU_HEADER_DATA_SEGMENT_LENGTH_SHIFT 0
296
+#define UFS_UPIU_HEADER_DATA_SEGMENT_LENGTH_MASK 0xffff
297
+#define UFS_UPIU_HEADER_DATA_SEGMENT_LENGTH(dword2) \
298
+ ((be32_to_cpu(dword2) >> UFS_UPIU_HEADER_DATA_SEGMENT_LENGTH_SHIFT) & \
299
+ UFS_UPIU_HEADER_DATA_SEGMENT_LENGTH_MASK)
300
+
301
+typedef struct QEMU_PACKED DeviceDescriptor {
302
+ uint8_t length;
303
+ uint8_t descriptor_idn;
304
+ uint8_t device;
305
+ uint8_t device_class;
306
+ uint8_t device_sub_class;
307
+ uint8_t protocol;
308
+ uint8_t number_lu;
309
+ uint8_t number_wlu;
310
+ uint8_t boot_enable;
311
+ uint8_t descr_access_en;
312
+ uint8_t init_power_mode;
313
+ uint8_t high_priority_lun;
314
+ uint8_t secure_removal_type;
315
+ uint8_t security_lu;
316
+ uint8_t background_ops_term_lat;
317
+ uint8_t init_active_icc_level;
318
+ uint16_t spec_version;
319
+ uint16_t manufacture_date;
320
+ uint8_t manufacturer_name;
321
+ uint8_t product_name;
322
+ uint8_t serial_number;
323
+ uint8_t oem_id;
324
+ uint16_t manufacturer_id;
325
+ uint8_t ud_0_base_offset;
326
+ uint8_t ud_config_p_length;
327
+ uint8_t device_rtt_cap;
328
+ uint16_t periodic_rtc_update;
329
+ uint8_t ufs_features_support;
330
+ uint8_t ffu_timeout;
331
+ uint8_t queue_depth;
332
+ uint16_t device_version;
333
+ uint8_t num_secure_wp_area;
334
+ uint32_t psa_max_data_size;
335
+ uint8_t psa_state_timeout;
336
+ uint8_t product_revision_level;
337
+ uint8_t reserved[36];
338
+ uint32_t extended_ufs_features_support;
339
+ uint8_t write_booster_buffer_preserve_user_space_en;
340
+ uint8_t write_booster_buffer_type;
341
+ uint32_t num_shared_write_booster_buffer_alloc_units;
342
+} DeviceDescriptor;
343
+
344
+typedef struct QEMU_PACKED GeometryDescriptor {
345
+ uint8_t length;
346
+ uint8_t descriptor_idn;
347
+ uint8_t media_technology;
348
+ uint8_t reserved;
349
+ uint64_t total_raw_device_capacity;
350
+ uint8_t max_number_lu;
351
+ uint32_t segment_size;
352
+ uint8_t allocation_unit_size;
353
+ uint8_t min_addr_block_size;
354
+ uint8_t optimal_read_block_size;
355
+ uint8_t optimal_write_block_size;
356
+ uint8_t max_in_buffer_size;
357
+ uint8_t max_out_buffer_size;
358
+ uint8_t rpmb_read_write_size;
359
+ uint8_t dynamic_capacity_resource_policy;
360
+ uint8_t data_ordering;
361
+ uint8_t max_context_id_number;
362
+ uint8_t sys_data_tag_unit_size;
363
+ uint8_t sys_data_tag_res_size;
364
+ uint8_t supported_sec_r_types;
365
+ uint16_t supported_memory_types;
366
+ uint32_t system_code_max_n_alloc_u;
367
+ uint16_t system_code_cap_adj_fac;
368
+ uint32_t non_persist_max_n_alloc_u;
369
+ uint16_t non_persist_cap_adj_fac;
370
+ uint32_t enhanced_1_max_n_alloc_u;
371
+ uint16_t enhanced_1_cap_adj_fac;
372
+ uint32_t enhanced_2_max_n_alloc_u;
373
+ uint16_t enhanced_2_cap_adj_fac;
374
+ uint32_t enhanced_3_max_n_alloc_u;
375
+ uint16_t enhanced_3_cap_adj_fac;
376
+ uint32_t enhanced_4_max_n_alloc_u;
377
+ uint16_t enhanced_4_cap_adj_fac;
378
+ uint32_t optimal_logical_block_size;
379
+ uint8_t reserved2[7];
380
+ uint32_t write_booster_buffer_max_n_alloc_units;
381
+ uint8_t device_max_write_booster_l_us;
382
+ uint8_t write_booster_buffer_cap_adj_fac;
383
+ uint8_t supported_write_booster_buffer_user_space_reduction_types;
384
+ uint8_t supported_write_booster_buffer_types;
385
+} GeometryDescriptor;
386
+
387
+#define UFS_GEOMETRY_CAPACITY_SHIFT 9
388
+
389
+typedef struct QEMU_PACKED UnitDescriptor {
390
+ uint8_t length;
391
+ uint8_t descriptor_idn;
392
+ uint8_t unit_index;
393
+ uint8_t lu_enable;
394
+ uint8_t boot_lun_id;
395
+ uint8_t lu_write_protect;
396
+ uint8_t lu_queue_depth;
397
+ uint8_t psa_sensitive;
398
+ uint8_t memory_type;
399
+ uint8_t data_reliability;
400
+ uint8_t logical_block_size;
401
+ uint64_t logical_block_count;
402
+ uint32_t erase_block_size;
403
+ uint8_t provisioning_type;
404
+ uint64_t phy_mem_resource_count;
405
+ uint16_t context_capabilities;
406
+ uint8_t large_unit_granularity_m1;
407
+ uint8_t reserved[6];
408
+ uint32_t lu_num_write_booster_buffer_alloc_units;
409
+} UnitDescriptor;
410
+
411
+typedef struct QEMU_PACKED RpmbUnitDescriptor {
412
+ uint8_t length;
413
+ uint8_t descriptor_idn;
414
+ uint8_t unit_index;
415
+ uint8_t lu_enable;
416
+ uint8_t boot_lun_id;
417
+ uint8_t lu_write_protect;
418
+ uint8_t lu_queue_depth;
419
+ uint8_t psa_sensitive;
420
+ uint8_t memory_type;
421
+ uint8_t reserved;
422
+ uint8_t logical_block_size;
423
+ uint64_t logical_block_count;
424
+ uint32_t erase_block_size;
425
+ uint8_t provisioning_type;
426
+ uint64_t phy_mem_resource_count;
427
+ uint8_t reserved2[3];
428
+} RpmbUnitDescriptor;
429
+
430
+typedef struct QEMU_PACKED PowerParametersDescriptor {
431
+ uint8_t length;
432
+ uint8_t descriptor_idn;
433
+ uint16_t active_icc_levels_vcc[16];
434
+ uint16_t active_icc_levels_vccq[16];
435
+ uint16_t active_icc_levels_vccq_2[16];
436
+} PowerParametersDescriptor;
437
+
438
+typedef struct QEMU_PACKED InterconnectDescriptor {
439
+ uint8_t length;
440
+ uint8_t descriptor_idn;
441
+ uint16_t bcd_unipro_version;
442
+ uint16_t bcd_mphy_version;
443
+} InterconnectDescriptor;
444
+
445
+typedef struct QEMU_PACKED StringDescriptor {
446
+ uint8_t length;
447
+ uint8_t descriptor_idn;
448
+ uint16_t UC[126];
449
+} StringDescriptor;
450
+
451
+typedef struct QEMU_PACKED DeviceHealthDescriptor {
452
+ uint8_t length;
453
+ uint8_t descriptor_idn;
454
+ uint8_t pre_eol_info;
455
+ uint8_t device_life_time_est_a;
456
+ uint8_t device_life_time_est_b;
457
+ uint8_t vendor_prop_info[32];
458
+ uint32_t refresh_total_count;
459
+ uint32_t refresh_progress;
460
+} DeviceHealthDescriptor;
461
+
462
+typedef struct QEMU_PACKED Flags {
463
+ uint8_t reserved;
464
+ uint8_t device_init;
465
+ uint8_t permanent_wp_en;
466
+ uint8_t power_on_wp_en;
467
+ uint8_t background_ops_en;
468
+ uint8_t device_life_span_mode_en;
469
+ uint8_t purge_enable;
470
+ uint8_t refresh_enable;
471
+ uint8_t phy_resource_removal;
472
+ uint8_t busy_rtc;
473
+ uint8_t reserved2;
474
+ uint8_t permanently_disable_fw_update;
475
+ uint8_t reserved3[2];
476
+ uint8_t wb_en;
477
+ uint8_t wb_buffer_flush_en;
478
+ uint8_t wb_buffer_flush_during_hibernate;
479
+ uint8_t reserved4[2];
480
+} Flags;
481
+
482
+typedef struct Attributes {
483
+ uint8_t boot_lun_en;
484
+ uint8_t reserved;
485
+ uint8_t current_power_mode;
486
+ uint8_t active_icc_level;
487
+ uint8_t out_of_order_data_en;
488
+ uint8_t background_op_status;
489
+ uint8_t purge_status;
490
+ uint8_t max_data_in_size;
491
+ uint8_t max_data_out_size;
492
+ uint32_t dyn_cap_needed;
493
+ uint8_t ref_clk_freq;
494
+ uint8_t config_descr_lock;
495
+ uint8_t max_num_of_rtt;
496
+ uint16_t exception_event_control;
497
+ uint16_t exception_event_status;
498
+ uint32_t seconds_passed;
499
+ uint16_t context_conf;
500
+ uint8_t device_ffu_status;
501
+ uint8_t psa_state;
502
+ uint32_t psa_data_size;
503
+ uint8_t ref_clk_gating_wait_time;
504
+ uint8_t device_case_rough_temperaure;
505
+ uint8_t device_too_high_temp_boundary;
506
+ uint8_t device_too_low_temp_boundary;
507
+ uint8_t throttling_status;
508
+ uint8_t wb_buffer_flush_status;
509
+ uint8_t available_wb_buffer_size;
510
+ uint8_t wb_buffer_life_time_est;
511
+ uint32_t current_wb_buffer_size;
512
+ uint8_t refresh_status;
513
+ uint8_t refresh_freq;
514
+ uint8_t refresh_unit;
515
+ uint8_t refresh_method;
516
+} Attributes;
517
+
518
+#define UFS_TRANSACTION_SPECIFIC_FIELD_SIZE 20
519
+#define UFS_MAX_QUERY_DATA_SIZE 256
520
+
521
+/* Command response result code */
522
+typedef enum CommandRespCode {
523
+ COMMAND_RESULT_SUCESS = 0x00,
524
+ COMMAND_RESULT_FAIL = 0x01,
525
+} CommandRespCode;
526
+
527
+enum {
528
+ UFS_UPIU_FLAG_UNDERFLOW = 0x20,
529
+ UFS_UPIU_FLAG_OVERFLOW = 0x40,
530
+};
531
+
532
+typedef struct QEMU_PACKED UtpUpiuHeader {
533
+ uint8_t trans_type;
534
+ uint8_t flags;
535
+ uint8_t lun;
536
+ uint8_t task_tag;
537
+ uint8_t iid_cmd_set_type;
538
+ uint8_t query_func;
539
+ uint8_t response;
540
+ uint8_t scsi_status;
541
+ uint8_t ehs_len;
542
+ uint8_t device_inf;
543
+ uint16_t data_segment_length;
544
+} UtpUpiuHeader;
545
+
546
+/*
547
+ * The code below is copied from the linux kernel
548
+ * ("include/uapi/scsi/scsi_bsg_ufs.h") and modified to fit the qemu style.
549
+ */
550
+
551
+typedef struct QEMU_PACKED UtpUpiuQuery {
552
+ uint8_t opcode;
553
+ uint8_t idn;
554
+ uint8_t index;
555
+ uint8_t selector;
556
+ uint16_t reserved_osf;
557
+ uint16_t length;
558
+ uint32_t value;
559
+ uint32_t reserved[2];
560
+ /* EHS length should be 0. We don't have to worry about EHS area. */
561
+ uint8_t data[UFS_MAX_QUERY_DATA_SIZE];
562
+} UtpUpiuQuery;
563
+
564
+#define UFS_CDB_SIZE 16
565
+
566
+/*
567
+ * struct UtpUpiuCmd - Command UPIU structure
568
+ * @data_transfer_len: Data Transfer Length DW-3
569
+ * @cdb: Command Descriptor Block CDB DW-4 to DW-7
570
+ */
571
+typedef struct QEMU_PACKED UtpUpiuCmd {
572
+ uint32_t exp_data_transfer_len;
573
+ uint8_t cdb[UFS_CDB_SIZE];
574
+} UtpUpiuCmd;
575
+
576
+/*
577
+ * struct UtpUpiuReq - general upiu request structure
578
+ * @header:UPIU header structure DW-0 to DW-2
579
+ * @sc: fields structure for scsi command DW-3 to DW-7
580
+ * @qr: fields structure for query request DW-3 to DW-7
581
+ * @uc: use utp_upiu_query to host the 4 dwords of uic command
582
+ */
583
+typedef struct QEMU_PACKED UtpUpiuReq {
584
+ UtpUpiuHeader header;
585
+ union {
586
+ UtpUpiuCmd sc;
587
+ UtpUpiuQuery qr;
588
+ };
589
+} UtpUpiuReq;
590
+
591
+/*
592
+ * The code below is copied from the linux kernel ("include/ufs/ufshci.h") and
593
+ * modified to fit the qemu style.
594
+ */
595
+
596
+enum {
597
+ PWR_OK = 0x0,
598
+ PWR_LOCAL = 0x01,
599
+ PWR_REMOTE = 0x02,
600
+ PWR_BUSY = 0x03,
601
+ PWR_ERROR_CAP = 0x04,
602
+ PWR_FATAL_ERROR = 0x05,
603
+};
604
+
605
+/* UIC Commands */
606
+enum uic_cmd_dme {
607
+ UIC_CMD_DME_GET = 0x01,
608
+ UIC_CMD_DME_SET = 0x02,
609
+ UIC_CMD_DME_PEER_GET = 0x03,
610
+ UIC_CMD_DME_PEER_SET = 0x04,
611
+ UIC_CMD_DME_POWERON = 0x10,
612
+ UIC_CMD_DME_POWEROFF = 0x11,
613
+ UIC_CMD_DME_ENABLE = 0x12,
614
+ UIC_CMD_DME_RESET = 0x14,
615
+ UIC_CMD_DME_END_PT_RST = 0x15,
616
+ UIC_CMD_DME_LINK_STARTUP = 0x16,
617
+ UIC_CMD_DME_HIBER_ENTER = 0x17,
618
+ UIC_CMD_DME_HIBER_EXIT = 0x18,
619
+ UIC_CMD_DME_TEST_MODE = 0x1A,
620
+};
621
+
622
+/* UIC Config result code / Generic error code */
623
+enum {
624
+ UIC_CMD_RESULT_SUCCESS = 0x00,
625
+ UIC_CMD_RESULT_INVALID_ATTR = 0x01,
626
+ UIC_CMD_RESULT_FAILURE = 0x01,
627
+ UIC_CMD_RESULT_INVALID_ATTR_VALUE = 0x02,
628
+ UIC_CMD_RESULT_READ_ONLY_ATTR = 0x03,
629
+ UIC_CMD_RESULT_WRITE_ONLY_ATTR = 0x04,
630
+ UIC_CMD_RESULT_BAD_INDEX = 0x05,
631
+ UIC_CMD_RESULT_LOCKED_ATTR = 0x06,
632
+ UIC_CMD_RESULT_BAD_TEST_FEATURE_INDEX = 0x07,
633
+ UIC_CMD_RESULT_PEER_COMM_FAILURE = 0x08,
634
+ UIC_CMD_RESULT_BUSY = 0x09,
635
+ UIC_CMD_RESULT_DME_FAILURE = 0x0A,
636
+};
637
+
638
+#define MASK_UIC_COMMAND_RESULT 0xFF
639
+
640
+/*
641
+ * Request Descriptor Definitions
642
+ */
643
+
644
+/* Transfer request command type */
645
+enum {
646
+ UTP_CMD_TYPE_SCSI = 0x0,
647
+ UTP_CMD_TYPE_UFS = 0x1,
648
+ UTP_CMD_TYPE_DEV_MANAGE = 0x2,
649
+};
650
+
651
+/* To accommodate UFS2.0 required Command type */
652
+enum {
653
+ UTP_CMD_TYPE_UFS_STORAGE = 0x1,
654
+};
655
+
656
+enum {
657
+ UTP_SCSI_COMMAND = 0x00000000,
658
+ UTP_NATIVE_UFS_COMMAND = 0x10000000,
659
+ UTP_DEVICE_MANAGEMENT_FUNCTION = 0x20000000,
660
+ UTP_REQ_DESC_INT_CMD = 0x01000000,
661
+ UTP_REQ_DESC_CRYPTO_ENABLE_CMD = 0x00800000,
662
+};
663
+
664
+/* UTP Transfer Request Data Direction (DD) */
665
+enum {
666
+ UTP_NO_DATA_TRANSFER = 0x00000000,
667
+ UTP_HOST_TO_DEVICE = 0x02000000,
668
+ UTP_DEVICE_TO_HOST = 0x04000000,
669
+};
670
+
671
+/* Overall command status values */
672
+enum UtpOcsCodes {
673
+ OCS_SUCCESS = 0x0,
674
+ OCS_INVALID_CMD_TABLE_ATTR = 0x1,
675
+ OCS_INVALID_PRDT_ATTR = 0x2,
676
+ OCS_MISMATCH_DATA_BUF_SIZE = 0x3,
677
+ OCS_MISMATCH_RESP_UPIU_SIZE = 0x4,
678
+ OCS_PEER_COMM_FAILURE = 0x5,
679
+ OCS_ABORTED = 0x6,
680
+ OCS_FATAL_ERROR = 0x7,
681
+ OCS_DEVICE_FATAL_ERROR = 0x8,
682
+ OCS_INVALID_CRYPTO_CONFIG = 0x9,
683
+ OCS_GENERAL_CRYPTO_ERROR = 0xa,
684
+ OCS_INVALID_COMMAND_STATUS = 0xf,
685
+};
686
+
687
+enum {
688
+ MASK_OCS = 0x0F,
689
+};
690
+
691
+/*
692
+ * struct UfshcdSgEntry - UFSHCI PRD Entry
693
+ * @addr: Physical address; DW-0 and DW-1.
694
+ * @reserved: Reserved for future use DW-2
695
+ * @size: size of physical segment DW-3
696
+ */
697
+typedef struct QEMU_PACKED UfshcdSgEntry {
698
+ uint64_t addr;
699
+ uint32_t reserved;
700
+ uint32_t size;
701
+ /*
702
+ * followed by variant-specific fields if
703
+ * CONFIG_SCSI_UFS_VARIABLE_SG_ENTRY_SIZE has been defined.
704
+ */
705
+} UfshcdSgEntry;
706
+
707
+/*
708
+ * struct RequestDescHeader - Descriptor Header common to both UTRD and UTMRD
709
+ * @dword0: Descriptor Header DW0
710
+ * @dword1: Descriptor Header DW1
711
+ * @dword2: Descriptor Header DW2
712
+ * @dword3: Descriptor Header DW3
713
+ */
714
+typedef struct QEMU_PACKED RequestDescHeader {
715
+ uint32_t dword_0;
716
+ uint32_t dword_1;
717
+ uint32_t dword_2;
718
+ uint32_t dword_3;
719
+} RequestDescHeader;
720
+
721
+/*
722
+ * struct UtpTransferReqDesc - UTP Transfer Request Descriptor (UTRD)
723
+ * @header: UTRD header DW-0 to DW-3
724
+ * @command_desc_base_addr_lo: UCD base address low DW-4
725
+ * @command_desc_base_addr_hi: UCD base address high DW-5
726
+ * @response_upiu_length: response UPIU length DW-6
727
+ * @response_upiu_offset: response UPIU offset DW-6
728
+ * @prd_table_length: Physical region descriptor length DW-7
729
+ * @prd_table_offset: Physical region descriptor offset DW-7
730
+ */
731
+typedef struct QEMU_PACKED UtpTransferReqDesc {
732
+ /* DW 0-3 */
733
+ RequestDescHeader header;
734
+
735
+ /* DW 4-5*/
736
+ uint32_t command_desc_base_addr_lo;
737
+ uint32_t command_desc_base_addr_hi;
738
+
739
+ /* DW 6 */
740
+ uint16_t response_upiu_length;
741
+ uint16_t response_upiu_offset;
742
+
743
+ /* DW 7 */
744
+ uint16_t prd_table_length;
745
+ uint16_t prd_table_offset;
746
+} UtpTransferReqDesc;
747
+
748
+/*
749
+ * UTMRD structure.
750
+ */
751
+typedef struct QEMU_PACKED UtpTaskReqDesc {
752
+ /* DW 0-3 */
753
+ RequestDescHeader header;
754
+
755
+ /* DW 4-11 - Task request UPIU structure */
756
+ struct {
757
+ UtpUpiuHeader req_header;
758
+ uint32_t input_param1;
759
+ uint32_t input_param2;
760
+ uint32_t input_param3;
761
+ uint32_t reserved1[2];
762
+ } upiu_req;
763
+
764
+ /* DW 12-19 - Task Management Response UPIU structure */
765
+ struct {
766
+ UtpUpiuHeader rsp_header;
767
+ uint32_t output_param1;
768
+ uint32_t output_param2;
769
+ uint32_t reserved2[3];
770
+ } upiu_rsp;
771
+} UtpTaskReqDesc;
772
+
773
+/*
774
+ * The code below is copied from the linux kernel ("include/ufs/ufs.h") and
775
+ * modified to fit the qemu style.
776
+ */
777
+
778
+#define GENERAL_UPIU_REQUEST_SIZE (sizeof(UtpUpiuReq))
779
+#define QUERY_DESC_MAX_SIZE 255
780
+#define QUERY_DESC_MIN_SIZE 2
781
+#define QUERY_DESC_HDR_SIZE 2
782
+#define QUERY_OSF_SIZE (GENERAL_UPIU_REQUEST_SIZE - (sizeof(UtpUpiuHeader)))
783
+#define UFS_SENSE_SIZE 18
784
+
785
+/*
786
+ * UFS device may have standard LUs and LUN id could be from 0x00 to
787
+ * 0x7F. Standard LUs use "Peripheral Device Addressing Format".
788
+ * UFS device may also have the Well Known LUs (also referred as W-LU)
789
+ * which again could be from 0x00 to 0x7F. For W-LUs, device only use
790
+ * the "Extended Addressing Format" which means the W-LUNs would be
791
+ * from 0xc100 (SCSI_W_LUN_BASE) onwards.
792
+ * This means max. LUN number reported from UFS device could be 0xC17F.
793
+ */
794
+#define UFS_UPIU_MAX_UNIT_NUM_ID 0x7F
795
+#define UFS_UPIU_WLUN_ID (1 << 7)
796
+
797
+/* WriteBooster buffer is available only for the logical unit from 0 to 7 */
798
+#define UFS_UPIU_MAX_WB_LUN_ID 8
799
+
800
+/*
801
+ * WriteBooster buffer lifetime has a limit setted by vendor.
802
+ * If it is over the limit, WriteBooster feature will be disabled.
803
+ */
804
+#define UFS_WB_EXCEED_LIFETIME 0x0B
805
+
806
+/*
807
+ * In UFS Spec, the Extra Header Segment (EHS) starts from byte 32 in UPIU
808
+ * request/response packet
809
+ */
810
+#define EHS_OFFSET_IN_RESPONSE 32
811
+
812
+/* Well known logical unit id in LUN field of UPIU */
813
+enum {
814
+ UFS_UPIU_REPORT_LUNS_WLUN = 0x81,
815
+ UFS_UPIU_UFS_DEVICE_WLUN = 0xD0,
816
+ UFS_UPIU_BOOT_WLUN = 0xB0,
817
+ UFS_UPIU_RPMB_WLUN = 0xC4,
818
+};
819
+
820
+/*
821
+ * UFS Protocol Information Unit related definitions
822
+ */
823
+
824
+/* Task management functions */
825
+enum {
826
+ UFS_ABORT_TASK = 0x01,
827
+ UFS_ABORT_TASK_SET = 0x02,
828
+ UFS_CLEAR_TASK_SET = 0x04,
829
+ UFS_LOGICAL_RESET = 0x08,
830
+ UFS_QUERY_TASK = 0x80,
831
+ UFS_QUERY_TASK_SET = 0x81,
832
+};
833
+
834
+/* UTP UPIU Transaction Codes Initiator to Target */
835
+enum {
836
+ UPIU_TRANSACTION_NOP_OUT = 0x00,
837
+ UPIU_TRANSACTION_COMMAND = 0x01,
838
+ UPIU_TRANSACTION_DATA_OUT = 0x02,
839
+ UPIU_TRANSACTION_TASK_REQ = 0x04,
840
+ UPIU_TRANSACTION_QUERY_REQ = 0x16,
841
+};
842
+
843
+/* UTP UPIU Transaction Codes Target to Initiator */
844
+enum {
845
+ UPIU_TRANSACTION_NOP_IN = 0x20,
846
+ UPIU_TRANSACTION_RESPONSE = 0x21,
847
+ UPIU_TRANSACTION_DATA_IN = 0x22,
848
+ UPIU_TRANSACTION_TASK_RSP = 0x24,
849
+ UPIU_TRANSACTION_READY_XFER = 0x31,
850
+ UPIU_TRANSACTION_QUERY_RSP = 0x36,
851
+ UPIU_TRANSACTION_REJECT_UPIU = 0x3F,
852
+};
853
+
854
+/* UPIU Read/Write flags */
855
+enum {
856
+ UPIU_CMD_FLAGS_NONE = 0x00,
857
+ UPIU_CMD_FLAGS_WRITE = 0x20,
858
+ UPIU_CMD_FLAGS_READ = 0x40,
859
+};
860
+
861
+/* UPIU Task Attributes */
862
+enum {
863
+ UPIU_TASK_ATTR_SIMPLE = 0x00,
864
+ UPIU_TASK_ATTR_ORDERED = 0x01,
865
+ UPIU_TASK_ATTR_HEADQ = 0x02,
866
+ UPIU_TASK_ATTR_ACA = 0x03,
867
+};
868
+
869
+/* UPIU Query request function */
870
+enum {
871
+ UPIU_QUERY_FUNC_STANDARD_READ_REQUEST = 0x01,
872
+ UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST = 0x81,
873
+};
874
+
875
+/* Flag idn for Query Requests*/
876
+enum flag_idn {
877
+ QUERY_FLAG_IDN_FDEVICEINIT = 0x01,
878
+ QUERY_FLAG_IDN_PERMANENT_WPE = 0x02,
879
+ QUERY_FLAG_IDN_PWR_ON_WPE = 0x03,
880
+ QUERY_FLAG_IDN_BKOPS_EN = 0x04,
881
+ QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE = 0x05,
882
+ QUERY_FLAG_IDN_PURGE_ENABLE = 0x06,
883
+ QUERY_FLAG_IDN_REFRESH_ENABLE = 0x07,
884
+ QUERY_FLAG_IDN_FPHYRESOURCEREMOVAL = 0x08,
885
+ QUERY_FLAG_IDN_BUSY_RTC = 0x09,
886
+ QUERY_FLAG_IDN_RESERVED3 = 0x0A,
887
+ QUERY_FLAG_IDN_PERMANENTLY_DISABLE_FW_UPDATE = 0x0B,
888
+ QUERY_FLAG_IDN_WB_EN = 0x0E,
889
+ QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN = 0x0F,
890
+ QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8 = 0x10,
891
+ QUERY_FLAG_IDN_HPB_RESET = 0x11,
892
+ QUERY_FLAG_IDN_HPB_EN = 0x12,
893
+ QUERY_FLAG_IDN_COUNT,
894
+};
895
+
896
+/* Attribute idn for Query requests */
897
+enum attr_idn {
898
+ QUERY_ATTR_IDN_BOOT_LU_EN = 0x00,
899
+ QUERY_ATTR_IDN_MAX_HPB_SINGLE_CMD = 0x01,
900
+ QUERY_ATTR_IDN_POWER_MODE = 0x02,
901
+ QUERY_ATTR_IDN_ACTIVE_ICC_LVL = 0x03,
902
+ QUERY_ATTR_IDN_OOO_DATA_EN = 0x04,
903
+ QUERY_ATTR_IDN_BKOPS_STATUS = 0x05,
904
+ QUERY_ATTR_IDN_PURGE_STATUS = 0x06,
905
+ QUERY_ATTR_IDN_MAX_DATA_IN = 0x07,
906
+ QUERY_ATTR_IDN_MAX_DATA_OUT = 0x08,
907
+ QUERY_ATTR_IDN_DYN_CAP_NEEDED = 0x09,
908
+ QUERY_ATTR_IDN_REF_CLK_FREQ = 0x0A,
909
+ QUERY_ATTR_IDN_CONF_DESC_LOCK = 0x0B,
910
+ QUERY_ATTR_IDN_MAX_NUM_OF_RTT = 0x0C,
911
+ QUERY_ATTR_IDN_EE_CONTROL = 0x0D,
912
+ QUERY_ATTR_IDN_EE_STATUS = 0x0E,
913
+ QUERY_ATTR_IDN_SECONDS_PASSED = 0x0F,
914
+ QUERY_ATTR_IDN_CNTX_CONF = 0x10,
915
+ QUERY_ATTR_IDN_CORR_PRG_BLK_NUM = 0x11,
916
+ QUERY_ATTR_IDN_RESERVED2 = 0x12,
917
+ QUERY_ATTR_IDN_RESERVED3 = 0x13,
918
+ QUERY_ATTR_IDN_FFU_STATUS = 0x14,
919
+ QUERY_ATTR_IDN_PSA_STATE = 0x15,
920
+ QUERY_ATTR_IDN_PSA_DATA_SIZE = 0x16,
921
+ QUERY_ATTR_IDN_REF_CLK_GATING_WAIT_TIME = 0x17,
922
+ QUERY_ATTR_IDN_CASE_ROUGH_TEMP = 0x18,
923
+ QUERY_ATTR_IDN_HIGH_TEMP_BOUND = 0x19,
924
+ QUERY_ATTR_IDN_LOW_TEMP_BOUND = 0x1A,
925
+ QUERY_ATTR_IDN_THROTTLING_STATUS = 0x1B,
926
+ QUERY_ATTR_IDN_WB_FLUSH_STATUS = 0x1C,
927
+ QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE = 0x1D,
928
+ QUERY_ATTR_IDN_WB_BUFF_LIFE_TIME_EST = 0x1E,
929
+ QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE = 0x1F,
930
+ QUERY_ATTR_IDN_REFRESH_STATUS = 0x2C,
931
+ QUERY_ATTR_IDN_REFRESH_FREQ = 0x2D,
932
+ QUERY_ATTR_IDN_REFRESH_UNIT = 0x2E,
933
+ QUERY_ATTR_IDN_COUNT,
934
+};
935
+
936
+/* Descriptor idn for Query requests */
937
+enum desc_idn {
938
+ QUERY_DESC_IDN_DEVICE = 0x0,
939
+ QUERY_DESC_IDN_CONFIGURATION = 0x1,
940
+ QUERY_DESC_IDN_UNIT = 0x2,
941
+ QUERY_DESC_IDN_RFU_0 = 0x3,
942
+ QUERY_DESC_IDN_INTERCONNECT = 0x4,
943
+ QUERY_DESC_IDN_STRING = 0x5,
944
+ QUERY_DESC_IDN_RFU_1 = 0x6,
945
+ QUERY_DESC_IDN_GEOMETRY = 0x7,
946
+ QUERY_DESC_IDN_POWER = 0x8,
947
+ QUERY_DESC_IDN_HEALTH = 0x9,
948
+ QUERY_DESC_IDN_MAX,
949
+};
950
+
951
+enum desc_header_offset {
952
+ QUERY_DESC_LENGTH_OFFSET = 0x00,
953
+ QUERY_DESC_DESC_TYPE_OFFSET = 0x01,
954
+};
955
+
956
+/* Unit descriptor parameters offsets in bytes*/
957
+enum unit_desc_param {
958
+ UNIT_DESC_PARAM_LEN = 0x0,
959
+ UNIT_DESC_PARAM_TYPE = 0x1,
960
+ UNIT_DESC_PARAM_UNIT_INDEX = 0x2,
961
+ UNIT_DESC_PARAM_LU_ENABLE = 0x3,
962
+ UNIT_DESC_PARAM_BOOT_LUN_ID = 0x4,
963
+ UNIT_DESC_PARAM_LU_WR_PROTECT = 0x5,
964
+ UNIT_DESC_PARAM_LU_Q_DEPTH = 0x6,
965
+ UNIT_DESC_PARAM_PSA_SENSITIVE = 0x7,
966
+ UNIT_DESC_PARAM_MEM_TYPE = 0x8,
967
+ UNIT_DESC_PARAM_DATA_RELIABILITY = 0x9,
968
+ UNIT_DESC_PARAM_LOGICAL_BLK_SIZE = 0xA,
969
+ UNIT_DESC_PARAM_LOGICAL_BLK_COUNT = 0xB,
970
+ UNIT_DESC_PARAM_ERASE_BLK_SIZE = 0x13,
971
+ UNIT_DESC_PARAM_PROVISIONING_TYPE = 0x17,
972
+ UNIT_DESC_PARAM_PHY_MEM_RSRC_CNT = 0x18,
973
+ UNIT_DESC_PARAM_CTX_CAPABILITIES = 0x20,
974
+ UNIT_DESC_PARAM_LARGE_UNIT_SIZE_M1 = 0x22,
975
+ UNIT_DESC_PARAM_HPB_LU_MAX_ACTIVE_RGNS = 0x23,
976
+ UNIT_DESC_PARAM_HPB_PIN_RGN_START_OFF = 0x25,
977
+ UNIT_DESC_PARAM_HPB_NUM_PIN_RGNS = 0x27,
978
+ UNIT_DESC_PARAM_WB_BUF_ALLOC_UNITS = 0x29,
979
+};
980
+
981
+/* RPMB Unit descriptor parameters offsets in bytes*/
982
+enum rpmb_unit_desc_param {
983
+ RPMB_UNIT_DESC_PARAM_LEN = 0x0,
984
+ RPMB_UNIT_DESC_PARAM_TYPE = 0x1,
985
+ RPMB_UNIT_DESC_PARAM_UNIT_INDEX = 0x2,
986
+ RPMB_UNIT_DESC_PARAM_LU_ENABLE = 0x3,
987
+ RPMB_UNIT_DESC_PARAM_BOOT_LUN_ID = 0x4,
988
+ RPMB_UNIT_DESC_PARAM_LU_WR_PROTECT = 0x5,
989
+ RPMB_UNIT_DESC_PARAM_LU_Q_DEPTH = 0x6,
990
+ RPMB_UNIT_DESC_PARAM_PSA_SENSITIVE = 0x7,
991
+ RPMB_UNIT_DESC_PARAM_MEM_TYPE = 0x8,
992
+ RPMB_UNIT_DESC_PARAM_REGION_EN = 0x9,
993
+ RPMB_UNIT_DESC_PARAM_LOGICAL_BLK_SIZE = 0xA,
994
+ RPMB_UNIT_DESC_PARAM_LOGICAL_BLK_COUNT = 0xB,
995
+ RPMB_UNIT_DESC_PARAM_REGION0_SIZE = 0x13,
996
+ RPMB_UNIT_DESC_PARAM_REGION1_SIZE = 0x14,
997
+ RPMB_UNIT_DESC_PARAM_REGION2_SIZE = 0x15,
998
+ RPMB_UNIT_DESC_PARAM_REGION3_SIZE = 0x16,
999
+ RPMB_UNIT_DESC_PARAM_PROVISIONING_TYPE = 0x17,
1000
+ RPMB_UNIT_DESC_PARAM_PHY_MEM_RSRC_CNT = 0x18,
1001
+};
1002
+
1003
+/* Device descriptor parameters offsets in bytes*/
1004
+enum device_desc_param {
1005
+ DEVICE_DESC_PARAM_LEN = 0x0,
1006
+ DEVICE_DESC_PARAM_TYPE = 0x1,
1007
+ DEVICE_DESC_PARAM_DEVICE_TYPE = 0x2,
1008
+ DEVICE_DESC_PARAM_DEVICE_CLASS = 0x3,
1009
+ DEVICE_DESC_PARAM_DEVICE_SUB_CLASS = 0x4,
1010
+ DEVICE_DESC_PARAM_PRTCL = 0x5,
1011
+ DEVICE_DESC_PARAM_NUM_LU = 0x6,
1012
+ DEVICE_DESC_PARAM_NUM_WLU = 0x7,
1013
+ DEVICE_DESC_PARAM_BOOT_ENBL = 0x8,
1014
+ DEVICE_DESC_PARAM_DESC_ACCSS_ENBL = 0x9,
1015
+ DEVICE_DESC_PARAM_INIT_PWR_MODE = 0xA,
1016
+ DEVICE_DESC_PARAM_HIGH_PR_LUN = 0xB,
1017
+ DEVICE_DESC_PARAM_SEC_RMV_TYPE = 0xC,
1018
+ DEVICE_DESC_PARAM_SEC_LU = 0xD,
1019
+ DEVICE_DESC_PARAM_BKOP_TERM_LT = 0xE,
1020
+ DEVICE_DESC_PARAM_ACTVE_ICC_LVL = 0xF,
1021
+ DEVICE_DESC_PARAM_SPEC_VER = 0x10,
1022
+ DEVICE_DESC_PARAM_MANF_DATE = 0x12,
1023
+ DEVICE_DESC_PARAM_MANF_NAME = 0x14,
1024
+ DEVICE_DESC_PARAM_PRDCT_NAME = 0x15,
1025
+ DEVICE_DESC_PARAM_SN = 0x16,
1026
+ DEVICE_DESC_PARAM_OEM_ID = 0x17,
1027
+ DEVICE_DESC_PARAM_MANF_ID = 0x18,
1028
+ DEVICE_DESC_PARAM_UD_OFFSET = 0x1A,
1029
+ DEVICE_DESC_PARAM_UD_LEN = 0x1B,
1030
+ DEVICE_DESC_PARAM_RTT_CAP = 0x1C,
1031
+ DEVICE_DESC_PARAM_FRQ_RTC = 0x1D,
1032
+ DEVICE_DESC_PARAM_UFS_FEAT = 0x1F,
1033
+ DEVICE_DESC_PARAM_FFU_TMT = 0x20,
1034
+ DEVICE_DESC_PARAM_Q_DPTH = 0x21,
1035
+ DEVICE_DESC_PARAM_DEV_VER = 0x22,
1036
+ DEVICE_DESC_PARAM_NUM_SEC_WPA = 0x24,
1037
+ DEVICE_DESC_PARAM_PSA_MAX_DATA = 0x25,
1038
+ DEVICE_DESC_PARAM_PSA_TMT = 0x29,
1039
+ DEVICE_DESC_PARAM_PRDCT_REV = 0x2A,
1040
+ DEVICE_DESC_PARAM_HPB_VER = 0x40,
1041
+ DEVICE_DESC_PARAM_HPB_CONTROL = 0x42,
1042
+ DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP = 0x4F,
1043
+ DEVICE_DESC_PARAM_WB_PRESRV_USRSPC_EN = 0x53,
1044
+ DEVICE_DESC_PARAM_WB_TYPE = 0x54,
1045
+ DEVICE_DESC_PARAM_WB_SHARED_ALLOC_UNITS = 0x55,
1046
+};
1047
+
1048
+/* Interconnect descriptor parameters offsets in bytes*/
1049
+enum interconnect_desc_param {
1050
+ INTERCONNECT_DESC_PARAM_LEN = 0x0,
1051
+ INTERCONNECT_DESC_PARAM_TYPE = 0x1,
1052
+ INTERCONNECT_DESC_PARAM_UNIPRO_VER = 0x2,
1053
+ INTERCONNECT_DESC_PARAM_MPHY_VER = 0x4,
1054
+};
1055
+
1056
+/* Geometry descriptor parameters offsets in bytes*/
1057
+enum geometry_desc_param {
1058
+ GEOMETRY_DESC_PARAM_LEN = 0x0,
1059
+ GEOMETRY_DESC_PARAM_TYPE = 0x1,
1060
+ GEOMETRY_DESC_PARAM_DEV_CAP = 0x4,
1061
+ GEOMETRY_DESC_PARAM_MAX_NUM_LUN = 0xC,
1062
+ GEOMETRY_DESC_PARAM_SEG_SIZE = 0xD,
1063
+ GEOMETRY_DESC_PARAM_ALLOC_UNIT_SIZE = 0x11,
1064
+ GEOMETRY_DESC_PARAM_MIN_BLK_SIZE = 0x12,
1065
+ GEOMETRY_DESC_PARAM_OPT_RD_BLK_SIZE = 0x13,
1066
+ GEOMETRY_DESC_PARAM_OPT_WR_BLK_SIZE = 0x14,
1067
+ GEOMETRY_DESC_PARAM_MAX_IN_BUF_SIZE = 0x15,
1068
+ GEOMETRY_DESC_PARAM_MAX_OUT_BUF_SIZE = 0x16,
1069
+ GEOMETRY_DESC_PARAM_RPMB_RW_SIZE = 0x17,
1070
+ GEOMETRY_DESC_PARAM_DYN_CAP_RSRC_PLC = 0x18,
1071
+ GEOMETRY_DESC_PARAM_DATA_ORDER = 0x19,
1072
+ GEOMETRY_DESC_PARAM_MAX_NUM_CTX = 0x1A,
1073
+ GEOMETRY_DESC_PARAM_TAG_UNIT_SIZE = 0x1B,
1074
+ GEOMETRY_DESC_PARAM_TAG_RSRC_SIZE = 0x1C,
1075
+ GEOMETRY_DESC_PARAM_SEC_RM_TYPES = 0x1D,
1076
+ GEOMETRY_DESC_PARAM_MEM_TYPES = 0x1E,
1077
+ GEOMETRY_DESC_PARAM_SCM_MAX_NUM_UNITS = 0x20,
1078
+ GEOMETRY_DESC_PARAM_SCM_CAP_ADJ_FCTR = 0x24,
1079
+ GEOMETRY_DESC_PARAM_NPM_MAX_NUM_UNITS = 0x26,
1080
+ GEOMETRY_DESC_PARAM_NPM_CAP_ADJ_FCTR = 0x2A,
1081
+ GEOMETRY_DESC_PARAM_ENM1_MAX_NUM_UNITS = 0x2C,
1082
+ GEOMETRY_DESC_PARAM_ENM1_CAP_ADJ_FCTR = 0x30,
1083
+ GEOMETRY_DESC_PARAM_ENM2_MAX_NUM_UNITS = 0x32,
1084
+ GEOMETRY_DESC_PARAM_ENM2_CAP_ADJ_FCTR = 0x36,
1085
+ GEOMETRY_DESC_PARAM_ENM3_MAX_NUM_UNITS = 0x38,
1086
+ GEOMETRY_DESC_PARAM_ENM3_CAP_ADJ_FCTR = 0x3C,
1087
+ GEOMETRY_DESC_PARAM_ENM4_MAX_NUM_UNITS = 0x3E,
1088
+ GEOMETRY_DESC_PARAM_ENM4_CAP_ADJ_FCTR = 0x42,
1089
+ GEOMETRY_DESC_PARAM_OPT_LOG_BLK_SIZE = 0x44,
1090
+ GEOMETRY_DESC_PARAM_HPB_REGION_SIZE = 0x48,
1091
+ GEOMETRY_DESC_PARAM_HPB_NUMBER_LU = 0x49,
1092
+ GEOMETRY_DESC_PARAM_HPB_SUBREGION_SIZE = 0x4A,
1093
+ GEOMETRY_DESC_PARAM_HPB_MAX_ACTIVE_REGS = 0x4B,
1094
+ GEOMETRY_DESC_PARAM_WB_MAX_ALLOC_UNITS = 0x4F,
1095
+ GEOMETRY_DESC_PARAM_WB_MAX_WB_LUNS = 0x53,
1096
+ GEOMETRY_DESC_PARAM_WB_BUFF_CAP_ADJ = 0x54,
1097
+ GEOMETRY_DESC_PARAM_WB_SUP_RED_TYPE = 0x55,
1098
+ GEOMETRY_DESC_PARAM_WB_SUP_WB_TYPE = 0x56,
1099
+};
1100
+
1101
+/* Health descriptor parameters offsets in bytes*/
1102
+enum health_desc_param {
1103
+ HEALTH_DESC_PARAM_LEN = 0x0,
1104
+ HEALTH_DESC_PARAM_TYPE = 0x1,
1105
+ HEALTH_DESC_PARAM_EOL_INFO = 0x2,
1106
+ HEALTH_DESC_PARAM_LIFE_TIME_EST_A = 0x3,
1107
+ HEALTH_DESC_PARAM_LIFE_TIME_EST_B = 0x4,
1108
+};
1109
+
1110
+/* WriteBooster buffer mode */
1111
+enum {
1112
+ WB_BUF_MODE_LU_DEDICATED = 0x0,
1113
+ WB_BUF_MODE_SHARED = 0x1,
1114
+};
1115
+
1116
+/*
1117
+ * Logical Unit Write Protect
1118
+ * 00h: LU not write protected
1119
+ * 01h: LU write protected when fPowerOnWPEn =1
1120
+ * 02h: LU permanently write protected when fPermanentWPEn =1
1121
+ */
1122
+enum ufs_lu_wp_type {
1123
+ UFS_LU_NO_WP = 0x00,
1124
+ UFS_LU_POWER_ON_WP = 0x01,
1125
+ UFS_LU_PERM_WP = 0x02,
1126
+};
1127
+
1128
+/* UTP QUERY Transaction Specific Fields OpCode */
1129
+enum query_opcode {
1130
+ UPIU_QUERY_OPCODE_NOP = 0x0,
1131
+ UPIU_QUERY_OPCODE_READ_DESC = 0x1,
1132
+ UPIU_QUERY_OPCODE_WRITE_DESC = 0x2,
1133
+ UPIU_QUERY_OPCODE_READ_ATTR = 0x3,
1134
+ UPIU_QUERY_OPCODE_WRITE_ATTR = 0x4,
1135
+ UPIU_QUERY_OPCODE_READ_FLAG = 0x5,
1136
+ UPIU_QUERY_OPCODE_SET_FLAG = 0x6,
1137
+ UPIU_QUERY_OPCODE_CLEAR_FLAG = 0x7,
1138
+ UPIU_QUERY_OPCODE_TOGGLE_FLAG = 0x8,
1139
+};
1140
+
1141
+/* Query response result code */
1142
+typedef enum QueryRespCode {
1143
+ QUERY_RESULT_SUCCESS = 0x00,
1144
+ QUERY_RESULT_NOT_READABLE = 0xF6,
1145
+ QUERY_RESULT_NOT_WRITEABLE = 0xF7,
1146
+ QUERY_RESULT_ALREADY_WRITTEN = 0xF8,
1147
+ QUERY_RESULT_INVALID_LENGTH = 0xF9,
1148
+ QUERY_RESULT_INVALID_VALUE = 0xFA,
1149
+ QUERY_RESULT_INVALID_SELECTOR = 0xFB,
1150
+ QUERY_RESULT_INVALID_INDEX = 0xFC,
1151
+ QUERY_RESULT_INVALID_IDN = 0xFD,
1152
+ QUERY_RESULT_INVALID_OPCODE = 0xFE,
1153
+ QUERY_RESULT_GENERAL_FAILURE = 0xFF,
1154
+} QueryRespCode;
1155
+
1156
+/* UTP Transfer Request Command Type (CT) */
1157
+enum {
1158
+ UPIU_COMMAND_SET_TYPE_SCSI = 0x0,
1159
+ UPIU_COMMAND_SET_TYPE_UFS = 0x1,
1160
+ UPIU_COMMAND_SET_TYPE_QUERY = 0x2,
1161
+};
1162
+
1163
+/* Task management service response */
1164
+enum {
1165
+ UPIU_TASK_MANAGEMENT_FUNC_COMPL = 0x00,
1166
+ UPIU_TASK_MANAGEMENT_FUNC_NOT_SUPPORTED = 0x04,
1167
+ UPIU_TASK_MANAGEMENT_FUNC_SUCCEEDED = 0x08,
1168
+ UPIU_TASK_MANAGEMENT_FUNC_FAILED = 0x05,
1169
+ UPIU_INCORRECT_LOGICAL_UNIT_NO = 0x09,
1170
+};
1171
+
1172
+/* UFS device power modes */
1173
+enum ufs_dev_pwr_mode {
1174
+ UFS_ACTIVE_PWR_MODE = 1,
1175
+ UFS_SLEEP_PWR_MODE = 2,
1176
+ UFS_POWERDOWN_PWR_MODE = 3,
1177
+ UFS_DEEPSLEEP_PWR_MODE = 4,
1178
+};
1179
+
1180
+/*
1181
+ * struct UtpCmdRsp - Response UPIU structure
1182
+ * @residual_transfer_count: Residual transfer count DW-3
1183
+ * @reserved: Reserved double words DW-4 to DW-7
1184
+ * @sense_data_len: Sense data length DW-8 U16
1185
+ * @sense_data: Sense data field DW-8 to DW-12
1186
+ */
1187
+typedef struct QEMU_PACKED UtpCmdRsp {
1188
+ uint32_t residual_transfer_count;
1189
+ uint32_t reserved[4];
1190
+ uint16_t sense_data_len;
1191
+ uint8_t sense_data[UFS_SENSE_SIZE];
1192
+} UtpCmdRsp;
1193
+
1194
+/*
1195
+ * struct UtpUpiuRsp - general upiu response structure
1196
+ * @header: UPIU header structure DW-0 to DW-2
1197
+ * @sr: fields structure for scsi command DW-3 to DW-12
1198
+ * @qr: fields structure for query request DW-3 to DW-7
1199
+ */
1200
+typedef struct QEMU_PACKED UtpUpiuRsp {
1201
+ UtpUpiuHeader header;
1202
+ union {
1203
+ UtpCmdRsp sr;
1204
+ UtpUpiuQuery qr;
1205
+ };
1206
+} UtpUpiuRsp;
1207
+
1208
+static inline void _ufs_check_size(void)
39
+{
1209
+{
40
+ char *buf, *buf_origin;
1210
+ QEMU_BUILD_BUG_ON(sizeof(UfsReg) != 0x104);
41
+ FILE *f = fopen(file_name, "r");
1211
+ QEMU_BUILD_BUG_ON(sizeof(DeviceDescriptor) != 89);
42
+ int pattern_len;
1212
+ QEMU_BUILD_BUG_ON(sizeof(GeometryDescriptor) != 87);
43
+
1213
+ QEMU_BUILD_BUG_ON(sizeof(UnitDescriptor) != 45);
44
+ if (!f) {
1214
+ QEMU_BUILD_BUG_ON(sizeof(RpmbUnitDescriptor) != 35);
45
+ perror(file_name);
1215
+ QEMU_BUILD_BUG_ON(sizeof(PowerParametersDescriptor) != 98);
46
+ return NULL;
1216
+ QEMU_BUILD_BUG_ON(sizeof(InterconnectDescriptor) != 6);
1217
+ QEMU_BUILD_BUG_ON(sizeof(StringDescriptor) != 254);
1218
+ QEMU_BUILD_BUG_ON(sizeof(DeviceHealthDescriptor) != 45);
1219
+ QEMU_BUILD_BUG_ON(sizeof(Flags) != 0x13);
1220
+ QEMU_BUILD_BUG_ON(sizeof(UtpUpiuHeader) != 12);
1221
+ QEMU_BUILD_BUG_ON(sizeof(UtpUpiuQuery) != 276);
1222
+ QEMU_BUILD_BUG_ON(sizeof(UtpUpiuCmd) != 20);
1223
+ QEMU_BUILD_BUG_ON(sizeof(UtpUpiuReq) != 288);
1224
+ QEMU_BUILD_BUG_ON(sizeof(UfshcdSgEntry) != 16);
1225
+ QEMU_BUILD_BUG_ON(sizeof(RequestDescHeader) != 16);
1226
+ QEMU_BUILD_BUG_ON(sizeof(UtpTransferReqDesc) != 32);
1227
+ QEMU_BUILD_BUG_ON(sizeof(UtpTaskReqDesc) != 80);
1228
+ QEMU_BUILD_BUG_ON(sizeof(UtpCmdRsp) != 40);
1229
+ QEMU_BUILD_BUG_ON(sizeof(UtpUpiuRsp) != 288);
1230
+}
1231
+#endif
1232
diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
1233
index XXXXXXX..XXXXXXX 100644
1234
--- a/include/hw/pci/pci.h
1235
+++ b/include/hw/pci/pci.h
1236
@@ -XXX,XX +XXX,XX @@ extern bool pci_available;
1237
#define PCI_DEVICE_ID_REDHAT_NVME 0x0010
1238
#define PCI_DEVICE_ID_REDHAT_PVPANIC 0x0011
1239
#define PCI_DEVICE_ID_REDHAT_ACPI_ERST 0x0012
1240
+#define PCI_DEVICE_ID_REDHAT_UFS 0x0013
1241
#define PCI_DEVICE_ID_REDHAT_QXL 0x0100
1242
1243
#define FMT_PCIBUS PRIx64
1244
diff --git a/include/hw/pci/pci_ids.h b/include/hw/pci/pci_ids.h
1245
index XXXXXXX..XXXXXXX 100644
1246
--- a/include/hw/pci/pci_ids.h
1247
+++ b/include/hw/pci/pci_ids.h
1248
@@ -XXX,XX +XXX,XX @@
1249
#define PCI_CLASS_STORAGE_SATA 0x0106
1250
#define PCI_CLASS_STORAGE_SAS 0x0107
1251
#define PCI_CLASS_STORAGE_EXPRESS 0x0108
1252
+#define PCI_CLASS_STORAGE_UFS 0x0109
1253
#define PCI_CLASS_STORAGE_OTHER 0x0180
1254
1255
#define PCI_BASE_CLASS_NETWORK 0x02
1256
diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c
1257
new file mode 100644
1258
index XXXXXXX..XXXXXXX
1259
--- /dev/null
1260
+++ b/hw/ufs/ufs.c
1261
@@ -XXX,XX +XXX,XX @@
1262
+/*
1263
+ * QEMU Universal Flash Storage (UFS) Controller
1264
+ *
1265
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd. All rights reserved.
1266
+ *
1267
+ * Written by Jeuk Kim <jeuk20.kim@samsung.com>
1268
+ *
1269
+ * SPDX-License-Identifier: GPL-2.0-or-later
1270
+ */
1271
+
1272
+#include "qemu/osdep.h"
1273
+#include "qapi/error.h"
1274
+#include "migration/vmstate.h"
1275
+#include "trace.h"
1276
+#include "ufs.h"
1277
+
1278
+/* The QEMU-UFS device follows spec version 3.1 */
1279
+#define UFS_SPEC_VER 0x00000310
1280
+#define UFS_MAX_NUTRS 32
1281
+#define UFS_MAX_NUTMRS 8
1282
+
1283
+static void ufs_irq_check(UfsHc *u)
1284
+{
1285
+ PCIDevice *pci = PCI_DEVICE(u);
1286
+
1287
+ if ((u->reg.is & UFS_INTR_MASK) & u->reg.ie) {
1288
+ trace_ufs_irq_raise();
1289
+ pci_irq_assert(pci);
1290
+ } else {
1291
+ trace_ufs_irq_lower();
1292
+ pci_irq_deassert(pci);
47
+ }
1293
+ }
48
+
1294
+}
49
+ if (qemuio_misalign) {
1295
+
50
+ len += MISALIGN_OFFSET;
1296
+static void ufs_process_uiccmd(UfsHc *u, uint32_t val)
1297
+{
1298
+ trace_ufs_process_uiccmd(val, u->reg.ucmdarg1, u->reg.ucmdarg2,
1299
+ u->reg.ucmdarg3);
1300
+ /*
1301
+ * Only the essential uic commands for running drivers on Linux and Windows
1302
+ * are implemented.
1303
+ */
1304
+ switch (val) {
1305
+ case UIC_CMD_DME_LINK_STARTUP:
1306
+ u->reg.hcs = FIELD_DP32(u->reg.hcs, HCS, DP, 1);
1307
+ u->reg.hcs = FIELD_DP32(u->reg.hcs, HCS, UTRLRDY, 1);
1308
+ u->reg.hcs = FIELD_DP32(u->reg.hcs, HCS, UTMRLRDY, 1);
1309
+ u->reg.ucmdarg2 = UIC_CMD_RESULT_SUCCESS;
1310
+ break;
1311
+ /* TODO: Revisit it when Power Management is implemented */
1312
+ case UIC_CMD_DME_HIBER_ENTER:
1313
+ u->reg.is = FIELD_DP32(u->reg.is, IS, UHES, 1);
1314
+ u->reg.hcs = FIELD_DP32(u->reg.hcs, HCS, UPMCRS, PWR_LOCAL);
1315
+ u->reg.ucmdarg2 = UIC_CMD_RESULT_SUCCESS;
1316
+ break;
1317
+ case UIC_CMD_DME_HIBER_EXIT:
1318
+ u->reg.is = FIELD_DP32(u->reg.is, IS, UHXS, 1);
1319
+ u->reg.hcs = FIELD_DP32(u->reg.hcs, HCS, UPMCRS, PWR_LOCAL);
1320
+ u->reg.ucmdarg2 = UIC_CMD_RESULT_SUCCESS;
1321
+ break;
1322
+ default:
1323
+ u->reg.ucmdarg2 = UIC_CMD_RESULT_FAILURE;
51
+ }
1324
+ }
52
+
1325
+
53
+ buf_origin = buf = blk_blockalign(blk, len);
1326
+ u->reg.is = FIELD_DP32(u->reg.is, IS, UCCS, 1);
54
+
1327
+
55
+ if (qemuio_misalign) {
1328
+ ufs_irq_check(u);
56
+ buf_origin += MISALIGN_OFFSET;
1329
+}
57
+ buf += MISALIGN_OFFSET;
1330
+
58
+ len -= MISALIGN_OFFSET;
1331
+static void ufs_write_reg(UfsHc *u, hwaddr offset, uint32_t data, unsigned size)
1332
+{
1333
+ switch (offset) {
1334
+ case A_IS:
1335
+ u->reg.is &= ~data;
1336
+ ufs_irq_check(u);
1337
+ break;
1338
+ case A_IE:
1339
+ u->reg.ie = data;
1340
+ ufs_irq_check(u);
1341
+ break;
1342
+ case A_HCE:
1343
+ if (!FIELD_EX32(u->reg.hce, HCE, HCE) && FIELD_EX32(data, HCE, HCE)) {
1344
+ u->reg.hcs = FIELD_DP32(u->reg.hcs, HCS, UCRDY, 1);
1345
+ u->reg.hce = FIELD_DP32(u->reg.hce, HCE, HCE, 1);
1346
+ } else if (FIELD_EX32(u->reg.hce, HCE, HCE) &&
1347
+ !FIELD_EX32(data, HCE, HCE)) {
1348
+ u->reg.hcs = 0;
1349
+ u->reg.hce = FIELD_DP32(u->reg.hce, HCE, HCE, 0);
1350
+ }
1351
+ break;
1352
+ case A_UTRLBA:
1353
+ u->reg.utrlba = data & R_UTRLBA_UTRLBA_MASK;
1354
+ break;
1355
+ case A_UTRLBAU:
1356
+ u->reg.utrlbau = data;
1357
+ break;
1358
+ case A_UTRLDBR:
1359
+ /* Not yet supported */
1360
+ break;
1361
+ case A_UTRLRSR:
1362
+ u->reg.utrlrsr = data;
1363
+ break;
1364
+ case A_UTRLCNR:
1365
+ u->reg.utrlcnr &= ~data;
1366
+ break;
1367
+ case A_UTMRLBA:
1368
+ u->reg.utmrlba = data & R_UTMRLBA_UTMRLBA_MASK;
1369
+ break;
1370
+ case A_UTMRLBAU:
1371
+ u->reg.utmrlbau = data;
1372
+ break;
1373
+ case A_UICCMD:
1374
+ ufs_process_uiccmd(u, data);
1375
+ break;
1376
+ case A_UCMDARG1:
1377
+ u->reg.ucmdarg1 = data;
1378
+ break;
1379
+ case A_UCMDARG2:
1380
+ u->reg.ucmdarg2 = data;
1381
+ break;
1382
+ case A_UCMDARG3:
1383
+ u->reg.ucmdarg3 = data;
1384
+ break;
1385
+ case A_UTRLCLR:
1386
+ case A_UTMRLDBR:
1387
+ case A_UTMRLCLR:
1388
+ case A_UTMRLRSR:
1389
+ trace_ufs_err_unsupport_register_offset(offset);
1390
+ break;
1391
+ default:
1392
+ trace_ufs_err_invalid_register_offset(offset);
1393
+ break;
59
+ }
1394
+ }
60
+
1395
+}
61
+ pattern_len = fread(buf_origin, 1, len, f);
1396
+
62
+
1397
+static uint64_t ufs_mmio_read(void *opaque, hwaddr addr, unsigned size)
63
+ if (ferror(f)) {
1398
+{
64
+ perror(file_name);
1399
+ UfsHc *u = (UfsHc *)opaque;
65
+ goto error;
1400
+ uint8_t *ptr = (uint8_t *)&u->reg;
1401
+ uint64_t value;
1402
+
1403
+ if (addr > sizeof(u->reg) - size) {
1404
+ trace_ufs_err_invalid_register_offset(addr);
1405
+ return 0;
66
+ }
1406
+ }
67
+
1407
+
68
+ if (pattern_len == 0) {
1408
+ value = *(uint32_t *)(ptr + addr);
69
+ fprintf(stderr, "%s: file is empty\n", file_name);
1409
+ trace_ufs_mmio_read(addr, value, size);
70
+ goto error;
1410
+ return value;
1411
+}
1412
+
1413
+static void ufs_mmio_write(void *opaque, hwaddr addr, uint64_t data,
1414
+ unsigned size)
1415
+{
1416
+ UfsHc *u = (UfsHc *)opaque;
1417
+
1418
+ if (addr > sizeof(u->reg) - size) {
1419
+ trace_ufs_err_invalid_register_offset(addr);
1420
+ return;
71
+ }
1421
+ }
72
+
1422
+
73
+ fclose(f);
1423
+ trace_ufs_mmio_write(addr, data, size);
74
+
1424
+ ufs_write_reg(u, addr, data, size);
75
+ if (len > pattern_len) {
1425
+}
76
+ len -= pattern_len;
1426
+
77
+ buf += pattern_len;
1427
+static const MemoryRegionOps ufs_mmio_ops = {
78
+
1428
+ .read = ufs_mmio_read,
79
+ while (len > 0) {
1429
+ .write = ufs_mmio_write,
80
+ size_t len_to_copy = MIN(pattern_len, len);
1430
+ .endianness = DEVICE_LITTLE_ENDIAN,
81
+
1431
+ .impl = {
82
+ memcpy(buf, buf_origin, len_to_copy);
1432
+ .min_access_size = 4,
83
+
1433
+ .max_access_size = 4,
84
+ len -= len_to_copy;
1434
+ },
85
+ buf += len_to_copy;
1435
+};
86
+ }
1436
+
1437
+static bool ufs_check_constraints(UfsHc *u, Error **errp)
1438
+{
1439
+ if (u->params.nutrs > UFS_MAX_NUTRS) {
1440
+ error_setg(errp, "nutrs must be less than or equal to %d",
1441
+ UFS_MAX_NUTRS);
1442
+ return false;
87
+ }
1443
+ }
88
+
1444
+
89
+ return buf_origin;
1445
+ if (u->params.nutmrs > UFS_MAX_NUTMRS) {
90
+
1446
+ error_setg(errp, "nutmrs must be less than or equal to %d",
91
+error:
1447
+ UFS_MAX_NUTMRS);
92
+ qemu_io_free(buf_origin);
1448
+ return false;
93
+ return NULL;
1449
+ }
1450
+
1451
+ return true;
94
+}
1452
+}
95
+
1453
+
96
static void dump_buffer(const void *buffer, int64_t offset, int64_t len)
1454
+static void ufs_init_pci(UfsHc *u, PCIDevice *pci_dev)
97
{
1455
+{
98
uint64_t i;
1456
+ uint8_t *pci_conf = pci_dev->config;
99
@@ -XXX,XX +XXX,XX @@ static void write_help(void)
1457
+
100
" -n, -- with -z, don't allow slow fallback\n"
1458
+ pci_conf[PCI_INTERRUPT_PIN] = 1;
101
" -p, -- ignored for backwards compatibility\n"
1459
+ pci_config_set_prog_interface(pci_conf, 0x1);
102
" -P, -- use different pattern to fill file\n"
1460
+
103
+" -s, -- use a pattern file to fill the write buffer\n"
1461
+ memory_region_init_io(&u->iomem, OBJECT(u), &ufs_mmio_ops, u, "ufs",
104
" -C, -- report statistics in a machine parsable format\n"
1462
+ u->reg_size);
105
" -q, -- quiet mode, do not show I/O statistics\n"
1463
+ pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &u->iomem);
106
" -u, -- with -z, allow unmapping\n"
1464
+ u->irq = pci_allocate_irq(pci_dev);
107
@@ -XXX,XX +XXX,XX @@ static const cmdinfo_t write_cmd = {
1465
+}
108
.perm = BLK_PERM_WRITE,
1466
+
109
.argmin = 2,
1467
+static void ufs_init_hc(UfsHc *u)
110
.argmax = -1,
1468
+{
111
- .args = "[-bcCfnquz] [-P pattern] off len",
1469
+ uint32_t cap = 0;
112
+ .args = "[-bcCfnquz] [-P pattern | -s source_file] off len",
1470
+
113
.oneline = "writes a number of bytes at a specified offset",
1471
+ u->reg_size = pow2ceil(sizeof(UfsReg));
114
.help = write_help,
1472
+
115
};
1473
+ memset(&u->reg, 0, sizeof(u->reg));
116
@@ -XXX,XX +XXX,XX @@ static int write_f(BlockBackend *blk, int argc, char **argv)
1474
+ cap = FIELD_DP32(cap, CAP, NUTRS, (u->params.nutrs - 1));
117
{
1475
+ cap = FIELD_DP32(cap, CAP, RTT, 2);
118
struct timespec t1, t2;
1476
+ cap = FIELD_DP32(cap, CAP, NUTMRS, (u->params.nutmrs - 1));
119
bool Cflag = false, qflag = false, bflag = false;
1477
+ cap = FIELD_DP32(cap, CAP, AUTOH8, 0);
120
- bool Pflag = false, zflag = false, cflag = false;
1478
+ cap = FIELD_DP32(cap, CAP, 64AS, 1);
121
+ bool Pflag = false, zflag = false, cflag = false, sflag = false;
1479
+ cap = FIELD_DP32(cap, CAP, OODDS, 0);
122
int flags = 0;
1480
+ cap = FIELD_DP32(cap, CAP, UICDMETMS, 0);
123
int c, cnt, ret;
1481
+ cap = FIELD_DP32(cap, CAP, CS, 0);
124
char *buf = NULL;
1482
+ u->reg.cap = cap;
125
@@ -XXX,XX +XXX,XX @@ static int write_f(BlockBackend *blk, int argc, char **argv)
1483
+ u->reg.ver = UFS_SPEC_VER;
126
/* Some compilers get confused and warn if this is not initialized. */
1484
+}
127
int64_t total = 0;
1485
+
128
int pattern = 0xcd;
1486
+static void ufs_realize(PCIDevice *pci_dev, Error **errp)
129
+ const char *file_name = NULL;
1487
+{
130
1488
+ UfsHc *u = UFS(pci_dev);
131
- while ((c = getopt(argc, argv, "bcCfnpP:quz")) != -1) {
1489
+
132
+ while ((c = getopt(argc, argv, "bcCfnpP:qs:uz")) != -1) {
1490
+ if (!ufs_check_constraints(u, errp)) {
133
switch (c) {
1491
+ return;
134
case 'b':
1492
+ }
135
bflag = true;
1493
+
136
@@ -XXX,XX +XXX,XX @@ static int write_f(BlockBackend *blk, int argc, char **argv)
1494
+ ufs_init_hc(u);
137
case 'q':
1495
+ ufs_init_pci(u, pci_dev);
138
qflag = true;
1496
+}
139
break;
1497
+
140
+ case 's':
1498
+static Property ufs_props[] = {
141
+ sflag = true;
1499
+ DEFINE_PROP_STRING("serial", UfsHc, params.serial),
142
+ file_name = optarg;
1500
+ DEFINE_PROP_UINT8("nutrs", UfsHc, params.nutrs, 32),
143
+ break;
1501
+ DEFINE_PROP_UINT8("nutmrs", UfsHc, params.nutmrs, 8),
144
case 'u':
1502
+ DEFINE_PROP_END_OF_LIST(),
145
flags |= BDRV_REQ_MAY_UNMAP;
1503
+};
146
break;
1504
+
147
@@ -XXX,XX +XXX,XX @@ static int write_f(BlockBackend *blk, int argc, char **argv)
1505
+static const VMStateDescription ufs_vmstate = {
148
return -EINVAL;
1506
+ .name = "ufs",
149
}
1507
+ .unmigratable = 1,
150
1508
+};
151
- if (zflag && Pflag) {
1509
+
152
- printf("-z and -P cannot be specified at the same time\n");
1510
+static void ufs_class_init(ObjectClass *oc, void *data)
153
+ if (zflag + Pflag + sflag > 1) {
1511
+{
154
+ printf("Only one of -z, -P, and -s "
1512
+ DeviceClass *dc = DEVICE_CLASS(oc);
155
+ "can be specified at the same time\n");
1513
+ PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc);
156
return -EINVAL;
1514
+
157
}
1515
+ pc->realize = ufs_realize;
158
1516
+ pc->vendor_id = PCI_VENDOR_ID_REDHAT;
159
@@ -XXX,XX +XXX,XX @@ static int write_f(BlockBackend *blk, int argc, char **argv)
1517
+ pc->device_id = PCI_DEVICE_ID_REDHAT_UFS;
160
}
1518
+ pc->class_id = PCI_CLASS_STORAGE_UFS;
161
1519
+
162
if (!zflag) {
1520
+ set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
163
- buf = qemu_io_alloc(blk, count, pattern);
1521
+ dc->desc = "Universal Flash Storage";
164
+ if (sflag) {
1522
+ device_class_set_props(dc, ufs_props);
165
+ buf = qemu_io_alloc_from_file(blk, count, file_name);
1523
+ dc->vmsd = &ufs_vmstate;
166
+ if (!buf) {
1524
+}
167
+ return -EINVAL;
1525
+
168
+ }
1526
+static const TypeInfo ufs_info = {
169
+ } else {
1527
+ .name = TYPE_UFS,
170
+ buf = qemu_io_alloc(blk, count, pattern);
1528
+ .parent = TYPE_PCI_DEVICE,
171
+ }
1529
+ .class_init = ufs_class_init,
172
}
1530
+ .instance_size = sizeof(UfsHc),
173
1531
+ .interfaces = (InterfaceInfo[]){ { INTERFACE_PCIE_DEVICE }, {} },
174
clock_gettime(CLOCK_MONOTONIC, &t1);
1532
+};
1533
+
1534
+static void ufs_register_types(void)
1535
+{
1536
+ type_register_static(&ufs_info);
1537
+}
1538
+
1539
+type_init(ufs_register_types)
1540
diff --git a/hw/Kconfig b/hw/Kconfig
1541
index XXXXXXX..XXXXXXX 100644
1542
--- a/hw/Kconfig
1543
+++ b/hw/Kconfig
1544
@@ -XXX,XX +XXX,XX @@ source smbios/Kconfig
1545
source ssi/Kconfig
1546
source timer/Kconfig
1547
source tpm/Kconfig
1548
+source ufs/Kconfig
1549
source usb/Kconfig
1550
source virtio/Kconfig
1551
source vfio/Kconfig
1552
diff --git a/hw/meson.build b/hw/meson.build
1553
index XXXXXXX..XXXXXXX 100644
1554
--- a/hw/meson.build
1555
+++ b/hw/meson.build
1556
@@ -XXX,XX +XXX,XX @@ subdir('smbios')
1557
subdir('ssi')
1558
subdir('timer')
1559
subdir('tpm')
1560
+subdir('ufs')
1561
subdir('usb')
1562
subdir('vfio')
1563
subdir('virtio')
1564
diff --git a/hw/ufs/Kconfig b/hw/ufs/Kconfig
1565
new file mode 100644
1566
index XXXXXXX..XXXXXXX
1567
--- /dev/null
1568
+++ b/hw/ufs/Kconfig
1569
@@ -XXX,XX +XXX,XX @@
1570
+config UFS_PCI
1571
+ bool
1572
+ default y if PCI_DEVICES
1573
+ depends on PCI
1574
diff --git a/hw/ufs/meson.build b/hw/ufs/meson.build
1575
new file mode 100644
1576
index XXXXXXX..XXXXXXX
1577
--- /dev/null
1578
+++ b/hw/ufs/meson.build
1579
@@ -0,0 +1 @@
1580
+system_ss.add(when: 'CONFIG_UFS_PCI', if_true: files('ufs.c'))
1581
diff --git a/hw/ufs/trace-events b/hw/ufs/trace-events
1582
new file mode 100644
1583
index XXXXXXX..XXXXXXX
1584
--- /dev/null
1585
+++ b/hw/ufs/trace-events
1586
@@ -XXX,XX +XXX,XX @@
1587
+# ufs.c
1588
+ufs_irq_raise(void) "INTx"
1589
+ufs_irq_lower(void) "INTx"
1590
+ufs_mmio_read(uint64_t addr, uint64_t data, unsigned size) "addr 0x%"PRIx64" data 0x%"PRIx64" size %d"
1591
+ufs_mmio_write(uint64_t addr, uint64_t data, unsigned size) "addr 0x%"PRIx64" data 0x%"PRIx64" size %d"
1592
+ufs_process_db(uint32_t slot) "UTRLDBR slot %"PRIu32""
1593
+ufs_process_req(uint32_t slot) "UTRLDBR slot %"PRIu32""
1594
+ufs_complete_req(uint32_t slot) "UTRLDBR slot %"PRIu32""
1595
+ufs_sendback_req(uint32_t slot) "UTRLDBR slot %"PRIu32""
1596
+ufs_exec_nop_cmd(uint32_t slot) "UTRLDBR slot %"PRIu32""
1597
+ufs_exec_scsi_cmd(uint32_t slot, uint8_t lun, uint8_t opcode) "slot %"PRIu32", lun 0x%"PRIx8", opcode 0x%"PRIx8""
1598
+ufs_exec_query_cmd(uint32_t slot, uint8_t opcode) "slot %"PRIu32", opcode 0x%"PRIx8""
1599
+ufs_process_uiccmd(uint32_t uiccmd, uint32_t ucmdarg1, uint32_t ucmdarg2, uint32_t ucmdarg3) "uiccmd 0x%"PRIx32", ucmdarg1 0x%"PRIx32", ucmdarg2 0x%"PRIx32", ucmdarg3 0x%"PRIx32""
1600
+
1601
+# error condition
1602
+ufs_err_dma_read_utrd(uint32_t slot, uint64_t addr) "failed to read utrd. UTRLDBR slot %"PRIu32", UTRD dma addr %"PRIu64""
1603
+ufs_err_dma_read_req_upiu(uint32_t slot, uint64_t addr) "failed to read req upiu. UTRLDBR slot %"PRIu32", request upiu addr %"PRIu64""
1604
+ufs_err_dma_read_prdt(uint32_t slot, uint64_t addr) "failed to read prdt. UTRLDBR slot %"PRIu32", prdt addr %"PRIu64""
1605
+ufs_err_dma_write_utrd(uint32_t slot, uint64_t addr) "failed to write utrd. UTRLDBR slot %"PRIu32", UTRD dma addr %"PRIu64""
1606
+ufs_err_dma_write_rsp_upiu(uint32_t slot, uint64_t addr) "failed to write rsp upiu. UTRLDBR slot %"PRIu32", response upiu addr %"PRIu64""
1607
+ufs_err_utrl_slot_busy(uint32_t slot) "UTRLDBR slot %"PRIu32" is busy"
1608
+ufs_err_unsupport_register_offset(uint32_t offset) "Register offset 0x%"PRIx32" is not yet supported"
1609
+ufs_err_invalid_register_offset(uint32_t offset) "Register offset 0x%"PRIx32" is invalid"
1610
+ufs_err_scsi_cmd_invalid_lun(uint8_t lun) "scsi command has invalid lun: 0x%"PRIx8""
1611
+ufs_err_query_flag_not_readable(uint8_t idn) "query flag idn 0x%"PRIx8" is denied to read"
1612
+ufs_err_query_flag_not_writable(uint8_t idn) "query flag idn 0x%"PRIx8" is denied to write"
1613
+ufs_err_query_attr_not_readable(uint8_t idn) "query attribute idn 0x%"PRIx8" is denied to read"
1614
+ufs_err_query_attr_not_writable(uint8_t idn) "query attribute idn 0x%"PRIx8" is denied to write"
1615
+ufs_err_query_invalid_opcode(uint8_t opcode) "query request has invalid opcode. opcode: 0x%"PRIx8""
1616
+ufs_err_query_invalid_idn(uint8_t opcode, uint8_t idn) "query request has invalid idn. opcode: 0x%"PRIx8", idn 0x%"PRIx8""
1617
+ufs_err_query_invalid_index(uint8_t opcode, uint8_t index) "query request has invalid index. opcode: 0x%"PRIx8", index 0x%"PRIx8""
1618
+ufs_err_invalid_trans_code(uint32_t slot, uint8_t trans_code) "request upiu has invalid transaction code. slot: %"PRIu32", trans_code: 0x%"PRIx8""
175
--
1619
--
176
2.21.0
1620
2.41.0
177
178
diff view generated by jsdifflib
1
From: Thomas Huth <thuth@redhat.com>
1
From: Jeuk Kim <jeuk20.kim@gmail.com>
2
2
3
It is possible to enable only a subset of the block drivers with the
3
This commit makes the UFS device support query
4
"--block-drv-rw-whitelist" option of the "configure" script. All other
4
and nop out transfer requests.
5
drivers are marked as unusable (or only included as read-only with the
6
"--block-drv-ro-whitelist" option). If an iotest is now using such a
7
disabled block driver, it is failing - which is bad, since at least the
8
tests in the "auto" group should be able to deal with this situation.
9
Thus let's introduce a "_require_drivers" function that can be used by
10
the shell tests to check for the availability of certain drivers first,
11
and marks the test as "not run" if one of the drivers is missing.
12
5
13
This patch mainly targets the test in the "auto" group which should
6
The next patch would be support for UFS logical
14
never fail in such a case, but also improves some of the other tests
7
unit and scsi command transfer request.
15
along the way. Note that we also assume that the "qcow2" and "file"
16
drivers are always available - otherwise it does not make sense to
17
run "make check-block" at all (which only tests with qcow2 by default).
18
8
19
Signed-off-by: Thomas Huth <thuth@redhat.com>
9
Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>
20
Message-id: 20190823133552.11680-1-thuth@redhat.com
10
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
21
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
Message-id: d06b440d660872092f70af1b8167bd5f4704c957.1691062912.git.jeuk20.kim@samsung.com
12
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
22
---
13
---
23
tests/qemu-iotests/071 | 1 +
14
hw/ufs/ufs.h | 46 +++
24
tests/qemu-iotests/081 | 4 +---
15
hw/ufs/ufs.c | 980 +++++++++++++++++++++++++++++++++++++++++++-
25
tests/qemu-iotests/099 | 1 +
16
hw/ufs/trace-events | 1 +
26
tests/qemu-iotests/120 | 1 +
17
3 files changed, 1025 insertions(+), 2 deletions(-)
27
tests/qemu-iotests/162 | 4 +---
28
tests/qemu-iotests/184 | 1 +
29
tests/qemu-iotests/186 | 1 +
30
tests/qemu-iotests/common.rc | 14 ++++++++++++++
31
8 files changed, 21 insertions(+), 6 deletions(-)
32
18
33
diff --git a/tests/qemu-iotests/071 b/tests/qemu-iotests/071
19
diff --git a/hw/ufs/ufs.h b/hw/ufs/ufs.h
34
index XXXXXXX..XXXXXXX 100755
20
index XXXXXXX..XXXXXXX 100644
35
--- a/tests/qemu-iotests/071
21
--- a/hw/ufs/ufs.h
36
+++ b/tests/qemu-iotests/071
22
+++ b/hw/ufs/ufs.h
37
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
23
@@ -XXX,XX +XXX,XX @@
38
24
#define UFS_MAX_LUS 32
39
_supported_fmt qcow2
25
#define UFS_BLOCK_SIZE 4096
40
_supported_proto file
26
41
+_require_drivers blkdebug blkverify
27
+typedef enum UfsRequestState {
42
28
+ UFS_REQUEST_IDLE = 0,
43
do_run_qemu()
29
+ UFS_REQUEST_READY = 1,
30
+ UFS_REQUEST_RUNNING = 2,
31
+ UFS_REQUEST_COMPLETE = 3,
32
+ UFS_REQUEST_ERROR = 4,
33
+} UfsRequestState;
34
+
35
+typedef enum UfsReqResult {
36
+ UFS_REQUEST_SUCCESS = 0,
37
+ UFS_REQUEST_FAIL = 1,
38
+} UfsReqResult;
39
+
40
+typedef struct UfsRequest {
41
+ struct UfsHc *hc;
42
+ UfsRequestState state;
43
+ int slot;
44
+
45
+ UtpTransferReqDesc utrd;
46
+ UtpUpiuReq req_upiu;
47
+ UtpUpiuRsp rsp_upiu;
48
+
49
+ /* for scsi command */
50
+ QEMUSGList *sg;
51
+} UfsRequest;
52
+
53
typedef struct UfsParams {
54
char *serial;
55
uint8_t nutrs; /* Number of UTP Transfer Request Slots */
56
@@ -XXX,XX +XXX,XX @@ typedef struct UfsHc {
57
UfsReg reg;
58
UfsParams params;
59
uint32_t reg_size;
60
+ UfsRequest *req_list;
61
+
62
+ DeviceDescriptor device_desc;
63
+ GeometryDescriptor geometry_desc;
64
+ Attributes attributes;
65
+ Flags flags;
66
67
qemu_irq irq;
68
QEMUBH *doorbell_bh;
69
@@ -XXX,XX +XXX,XX @@ typedef struct UfsHc {
70
#define TYPE_UFS "ufs"
71
#define UFS(obj) OBJECT_CHECK(UfsHc, (obj), TYPE_UFS)
72
73
+typedef enum UfsQueryFlagPerm {
74
+ UFS_QUERY_FLAG_NONE = 0x0,
75
+ UFS_QUERY_FLAG_READ = 0x1,
76
+ UFS_QUERY_FLAG_SET = 0x2,
77
+ UFS_QUERY_FLAG_CLEAR = 0x4,
78
+ UFS_QUERY_FLAG_TOGGLE = 0x8,
79
+} UfsQueryFlagPerm;
80
+
81
+typedef enum UfsQueryAttrPerm {
82
+ UFS_QUERY_ATTR_NONE = 0x0,
83
+ UFS_QUERY_ATTR_READ = 0x1,
84
+ UFS_QUERY_ATTR_WRITE = 0x2,
85
+} UfsQueryAttrPerm;
86
+
87
#endif /* HW_UFS_UFS_H */
88
diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c
89
index XXXXXXX..XXXXXXX 100644
90
--- a/hw/ufs/ufs.c
91
+++ b/hw/ufs/ufs.c
92
@@ -XXX,XX +XXX,XX @@
93
#include "ufs.h"
94
95
/* The QEMU-UFS device follows spec version 3.1 */
96
-#define UFS_SPEC_VER 0x00000310
97
+#define UFS_SPEC_VER 0x0310
98
#define UFS_MAX_NUTRS 32
99
#define UFS_MAX_NUTMRS 8
100
101
+static MemTxResult ufs_addr_read(UfsHc *u, hwaddr addr, void *buf, int size)
102
+{
103
+ hwaddr hi = addr + size - 1;
104
+
105
+ if (hi < addr) {
106
+ return MEMTX_DECODE_ERROR;
107
+ }
108
+
109
+ if (!FIELD_EX32(u->reg.cap, CAP, 64AS) && (hi >> 32)) {
110
+ return MEMTX_DECODE_ERROR;
111
+ }
112
+
113
+ return pci_dma_read(PCI_DEVICE(u), addr, buf, size);
114
+}
115
+
116
+static MemTxResult ufs_addr_write(UfsHc *u, hwaddr addr, const void *buf,
117
+ int size)
118
+{
119
+ hwaddr hi = addr + size - 1;
120
+ if (hi < addr) {
121
+ return MEMTX_DECODE_ERROR;
122
+ }
123
+
124
+ if (!FIELD_EX32(u->reg.cap, CAP, 64AS) && (hi >> 32)) {
125
+ return MEMTX_DECODE_ERROR;
126
+ }
127
+
128
+ return pci_dma_write(PCI_DEVICE(u), addr, buf, size);
129
+}
130
+
131
+static void ufs_complete_req(UfsRequest *req, UfsReqResult req_result);
132
+
133
+static inline hwaddr ufs_get_utrd_addr(UfsHc *u, uint32_t slot)
134
+{
135
+ hwaddr utrl_base_addr = (((hwaddr)u->reg.utrlbau) << 32) + u->reg.utrlba;
136
+ hwaddr utrd_addr = utrl_base_addr + slot * sizeof(UtpTransferReqDesc);
137
+
138
+ return utrd_addr;
139
+}
140
+
141
+static inline hwaddr ufs_get_req_upiu_base_addr(const UtpTransferReqDesc *utrd)
142
+{
143
+ uint32_t cmd_desc_base_addr_lo =
144
+ le32_to_cpu(utrd->command_desc_base_addr_lo);
145
+ uint32_t cmd_desc_base_addr_hi =
146
+ le32_to_cpu(utrd->command_desc_base_addr_hi);
147
+
148
+ return (((hwaddr)cmd_desc_base_addr_hi) << 32) + cmd_desc_base_addr_lo;
149
+}
150
+
151
+static inline hwaddr ufs_get_rsp_upiu_base_addr(const UtpTransferReqDesc *utrd)
152
+{
153
+ hwaddr req_upiu_base_addr = ufs_get_req_upiu_base_addr(utrd);
154
+ uint32_t rsp_upiu_byte_off =
155
+ le16_to_cpu(utrd->response_upiu_offset) * sizeof(uint32_t);
156
+ return req_upiu_base_addr + rsp_upiu_byte_off;
157
+}
158
+
159
+static MemTxResult ufs_dma_read_utrd(UfsRequest *req)
160
+{
161
+ UfsHc *u = req->hc;
162
+ hwaddr utrd_addr = ufs_get_utrd_addr(u, req->slot);
163
+ MemTxResult ret;
164
+
165
+ ret = ufs_addr_read(u, utrd_addr, &req->utrd, sizeof(req->utrd));
166
+ if (ret) {
167
+ trace_ufs_err_dma_read_utrd(req->slot, utrd_addr);
168
+ }
169
+ return ret;
170
+}
171
+
172
+static MemTxResult ufs_dma_read_req_upiu(UfsRequest *req)
173
+{
174
+ UfsHc *u = req->hc;
175
+ hwaddr req_upiu_base_addr = ufs_get_req_upiu_base_addr(&req->utrd);
176
+ UtpUpiuReq *req_upiu = &req->req_upiu;
177
+ uint32_t copy_size;
178
+ uint16_t data_segment_length;
179
+ MemTxResult ret;
180
+
181
+ /*
182
+ * To know the size of the req_upiu, we need to read the
183
+ * data_segment_length in the header first.
184
+ */
185
+ ret = ufs_addr_read(u, req_upiu_base_addr, &req_upiu->header,
186
+ sizeof(UtpUpiuHeader));
187
+ if (ret) {
188
+ trace_ufs_err_dma_read_req_upiu(req->slot, req_upiu_base_addr);
189
+ return ret;
190
+ }
191
+ data_segment_length = be16_to_cpu(req_upiu->header.data_segment_length);
192
+
193
+ copy_size = sizeof(UtpUpiuHeader) + UFS_TRANSACTION_SPECIFIC_FIELD_SIZE +
194
+ data_segment_length;
195
+
196
+ ret = ufs_addr_read(u, req_upiu_base_addr, &req->req_upiu, copy_size);
197
+ if (ret) {
198
+ trace_ufs_err_dma_read_req_upiu(req->slot, req_upiu_base_addr);
199
+ }
200
+ return ret;
201
+}
202
+
203
+static MemTxResult ufs_dma_read_prdt(UfsRequest *req)
204
+{
205
+ UfsHc *u = req->hc;
206
+ uint16_t prdt_len = le16_to_cpu(req->utrd.prd_table_length);
207
+ uint16_t prdt_byte_off =
208
+ le16_to_cpu(req->utrd.prd_table_offset) * sizeof(uint32_t);
209
+ uint32_t prdt_size = prdt_len * sizeof(UfshcdSgEntry);
210
+ g_autofree UfshcdSgEntry *prd_entries = NULL;
211
+ hwaddr req_upiu_base_addr, prdt_base_addr;
212
+ int err;
213
+
214
+ assert(!req->sg);
215
+
216
+ if (prdt_size == 0) {
217
+ return MEMTX_OK;
218
+ }
219
+ prd_entries = g_new(UfshcdSgEntry, prdt_size);
220
+
221
+ req_upiu_base_addr = ufs_get_req_upiu_base_addr(&req->utrd);
222
+ prdt_base_addr = req_upiu_base_addr + prdt_byte_off;
223
+
224
+ err = ufs_addr_read(u, prdt_base_addr, prd_entries, prdt_size);
225
+ if (err) {
226
+ trace_ufs_err_dma_read_prdt(req->slot, prdt_base_addr);
227
+ return err;
228
+ }
229
+
230
+ req->sg = g_malloc0(sizeof(QEMUSGList));
231
+ pci_dma_sglist_init(req->sg, PCI_DEVICE(u), prdt_len);
232
+
233
+ for (uint16_t i = 0; i < prdt_len; ++i) {
234
+ hwaddr data_dma_addr = le64_to_cpu(prd_entries[i].addr);
235
+ uint32_t data_byte_count = le32_to_cpu(prd_entries[i].size) + 1;
236
+ qemu_sglist_add(req->sg, data_dma_addr, data_byte_count);
237
+ }
238
+ return MEMTX_OK;
239
+}
240
+
241
+static MemTxResult ufs_dma_read_upiu(UfsRequest *req)
242
+{
243
+ MemTxResult ret;
244
+
245
+ ret = ufs_dma_read_utrd(req);
246
+ if (ret) {
247
+ return ret;
248
+ }
249
+
250
+ ret = ufs_dma_read_req_upiu(req);
251
+ if (ret) {
252
+ return ret;
253
+ }
254
+
255
+ ret = ufs_dma_read_prdt(req);
256
+ if (ret) {
257
+ return ret;
258
+ }
259
+
260
+ return 0;
261
+}
262
+
263
+static MemTxResult ufs_dma_write_utrd(UfsRequest *req)
264
+{
265
+ UfsHc *u = req->hc;
266
+ hwaddr utrd_addr = ufs_get_utrd_addr(u, req->slot);
267
+ MemTxResult ret;
268
+
269
+ ret = ufs_addr_write(u, utrd_addr, &req->utrd, sizeof(req->utrd));
270
+ if (ret) {
271
+ trace_ufs_err_dma_write_utrd(req->slot, utrd_addr);
272
+ }
273
+ return ret;
274
+}
275
+
276
+static MemTxResult ufs_dma_write_rsp_upiu(UfsRequest *req)
277
+{
278
+ UfsHc *u = req->hc;
279
+ hwaddr rsp_upiu_base_addr = ufs_get_rsp_upiu_base_addr(&req->utrd);
280
+ uint32_t rsp_upiu_byte_len =
281
+ le16_to_cpu(req->utrd.response_upiu_length) * sizeof(uint32_t);
282
+ uint16_t data_segment_length =
283
+ be16_to_cpu(req->rsp_upiu.header.data_segment_length);
284
+ uint32_t copy_size = sizeof(UtpUpiuHeader) +
285
+ UFS_TRANSACTION_SPECIFIC_FIELD_SIZE +
286
+ data_segment_length;
287
+ MemTxResult ret;
288
+
289
+ if (copy_size > rsp_upiu_byte_len) {
290
+ copy_size = rsp_upiu_byte_len;
291
+ }
292
+
293
+ ret = ufs_addr_write(u, rsp_upiu_base_addr, &req->rsp_upiu, copy_size);
294
+ if (ret) {
295
+ trace_ufs_err_dma_write_rsp_upiu(req->slot, rsp_upiu_base_addr);
296
+ }
297
+ return ret;
298
+}
299
+
300
+static MemTxResult ufs_dma_write_upiu(UfsRequest *req)
301
+{
302
+ MemTxResult ret;
303
+
304
+ ret = ufs_dma_write_rsp_upiu(req);
305
+ if (ret) {
306
+ return ret;
307
+ }
308
+
309
+ return ufs_dma_write_utrd(req);
310
+}
311
+
312
static void ufs_irq_check(UfsHc *u)
44
{
313
{
45
diff --git a/tests/qemu-iotests/081 b/tests/qemu-iotests/081
314
PCIDevice *pci = PCI_DEVICE(u);
46
index XXXXXXX..XXXXXXX 100755
315
@@ -XXX,XX +XXX,XX @@ static void ufs_irq_check(UfsHc *u)
47
--- a/tests/qemu-iotests/081
316
}
48
+++ b/tests/qemu-iotests/081
317
}
49
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
318
50
_supported_fmt raw
319
+static void ufs_process_db(UfsHc *u, uint32_t val)
51
_supported_proto file
320
+{
52
_supported_os Linux
321
+ uint32_t slot;
53
+_require_drivers quorum
322
+ uint32_t nutrs = u->params.nutrs;
54
323
+ UfsRequest *req;
55
do_run_qemu()
324
+
325
+ val &= ~u->reg.utrldbr;
326
+ if (!val) {
327
+ return;
328
+ }
329
+
330
+ slot = find_first_bit((unsigned long *)&val, nutrs);
331
+
332
+ while (slot < nutrs) {
333
+ req = &u->req_list[slot];
334
+ if (req->state == UFS_REQUEST_ERROR) {
335
+ trace_ufs_err_utrl_slot_error(req->slot);
336
+ return;
337
+ }
338
+
339
+ if (req->state != UFS_REQUEST_IDLE) {
340
+ trace_ufs_err_utrl_slot_busy(req->slot);
341
+ return;
342
+ }
343
+
344
+ trace_ufs_process_db(slot);
345
+ req->state = UFS_REQUEST_READY;
346
+ slot = find_next_bit((unsigned long *)&val, nutrs, slot + 1);
347
+ }
348
+
349
+ qemu_bh_schedule(u->doorbell_bh);
350
+}
351
+
352
static void ufs_process_uiccmd(UfsHc *u, uint32_t val)
56
{
353
{
57
@@ -XXX,XX +XXX,XX @@ run_qemu()
354
trace_ufs_process_uiccmd(val, u->reg.ucmdarg1, u->reg.ucmdarg2,
58
| _filter_qemu_io | _filter_generated_node_ids
355
@@ -XXX,XX +XXX,XX @@ static void ufs_write_reg(UfsHc *u, hwaddr offset, uint32_t data, unsigned size)
356
u->reg.utrlbau = data;
357
break;
358
case A_UTRLDBR:
359
- /* Not yet supported */
360
+ ufs_process_db(u, data);
361
+ u->reg.utrldbr |= data;
362
break;
363
case A_UTRLRSR:
364
u->reg.utrlrsr = data;
365
@@ -XXX,XX +XXX,XX @@ static const MemoryRegionOps ufs_mmio_ops = {
366
},
367
};
368
369
+static void ufs_build_upiu_header(UfsRequest *req, uint8_t trans_type,
370
+ uint8_t flags, uint8_t response,
371
+ uint8_t scsi_status,
372
+ uint16_t data_segment_length)
373
+{
374
+ memcpy(&req->rsp_upiu.header, &req->req_upiu.header, sizeof(UtpUpiuHeader));
375
+ req->rsp_upiu.header.trans_type = trans_type;
376
+ req->rsp_upiu.header.flags = flags;
377
+ req->rsp_upiu.header.response = response;
378
+ req->rsp_upiu.header.scsi_status = scsi_status;
379
+ req->rsp_upiu.header.data_segment_length = cpu_to_be16(data_segment_length);
380
+}
381
+
382
+static UfsReqResult ufs_exec_nop_cmd(UfsRequest *req)
383
+{
384
+ trace_ufs_exec_nop_cmd(req->slot);
385
+ ufs_build_upiu_header(req, UPIU_TRANSACTION_NOP_IN, 0, 0, 0, 0);
386
+ return UFS_REQUEST_SUCCESS;
387
+}
388
+
389
+/*
390
+ * This defines the permission of flags based on their IDN. There are some
391
+ * things that are declared read-only, which is inconsistent with the ufs spec,
392
+ * because we want to return an error for features that are not yet supported.
393
+ */
394
+static const int flag_permission[QUERY_FLAG_IDN_COUNT] = {
395
+ [QUERY_FLAG_IDN_FDEVICEINIT] = UFS_QUERY_FLAG_READ | UFS_QUERY_FLAG_SET,
396
+ /* Write protection is not supported */
397
+ [QUERY_FLAG_IDN_PERMANENT_WPE] = UFS_QUERY_FLAG_READ,
398
+ [QUERY_FLAG_IDN_PWR_ON_WPE] = UFS_QUERY_FLAG_READ,
399
+ [QUERY_FLAG_IDN_BKOPS_EN] = UFS_QUERY_FLAG_READ | UFS_QUERY_FLAG_SET |
400
+ UFS_QUERY_FLAG_CLEAR | UFS_QUERY_FLAG_TOGGLE,
401
+ [QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE] =
402
+ UFS_QUERY_FLAG_READ | UFS_QUERY_FLAG_SET | UFS_QUERY_FLAG_CLEAR |
403
+ UFS_QUERY_FLAG_TOGGLE,
404
+ /* Purge Operation is not supported */
405
+ [QUERY_FLAG_IDN_PURGE_ENABLE] = UFS_QUERY_FLAG_NONE,
406
+ /* Refresh Operation is not supported */
407
+ [QUERY_FLAG_IDN_REFRESH_ENABLE] = UFS_QUERY_FLAG_NONE,
408
+ /* Physical Resource Removal is not supported */
409
+ [QUERY_FLAG_IDN_FPHYRESOURCEREMOVAL] = UFS_QUERY_FLAG_READ,
410
+ [QUERY_FLAG_IDN_BUSY_RTC] = UFS_QUERY_FLAG_READ,
411
+ [QUERY_FLAG_IDN_PERMANENTLY_DISABLE_FW_UPDATE] = UFS_QUERY_FLAG_READ,
412
+ /* Write Booster is not supported */
413
+ [QUERY_FLAG_IDN_WB_EN] = UFS_QUERY_FLAG_READ,
414
+ [QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN] = UFS_QUERY_FLAG_READ,
415
+ [QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8] = UFS_QUERY_FLAG_READ,
416
+};
417
+
418
+static inline QueryRespCode ufs_flag_check_idn_valid(uint8_t idn, int op)
419
+{
420
+ if (idn >= QUERY_FLAG_IDN_COUNT) {
421
+ return QUERY_RESULT_INVALID_IDN;
422
+ }
423
+
424
+ if (!(flag_permission[idn] & op)) {
425
+ if (op == UFS_QUERY_FLAG_READ) {
426
+ trace_ufs_err_query_flag_not_readable(idn);
427
+ return QUERY_RESULT_NOT_READABLE;
428
+ }
429
+ trace_ufs_err_query_flag_not_writable(idn);
430
+ return QUERY_RESULT_NOT_WRITEABLE;
431
+ }
432
+
433
+ return QUERY_RESULT_SUCCESS;
434
+}
435
+
436
+static const int attr_permission[QUERY_ATTR_IDN_COUNT] = {
437
+ /* booting is not supported */
438
+ [QUERY_ATTR_IDN_BOOT_LU_EN] = UFS_QUERY_ATTR_READ,
439
+ [QUERY_ATTR_IDN_POWER_MODE] = UFS_QUERY_ATTR_READ,
440
+ [QUERY_ATTR_IDN_ACTIVE_ICC_LVL] =
441
+ UFS_QUERY_ATTR_READ | UFS_QUERY_ATTR_WRITE,
442
+ [QUERY_ATTR_IDN_OOO_DATA_EN] = UFS_QUERY_ATTR_READ,
443
+ [QUERY_ATTR_IDN_BKOPS_STATUS] = UFS_QUERY_ATTR_READ,
444
+ [QUERY_ATTR_IDN_PURGE_STATUS] = UFS_QUERY_ATTR_READ,
445
+ [QUERY_ATTR_IDN_MAX_DATA_IN] = UFS_QUERY_ATTR_READ | UFS_QUERY_ATTR_WRITE,
446
+ [QUERY_ATTR_IDN_MAX_DATA_OUT] = UFS_QUERY_ATTR_READ | UFS_QUERY_ATTR_WRITE,
447
+ [QUERY_ATTR_IDN_DYN_CAP_NEEDED] = UFS_QUERY_ATTR_READ,
448
+ [QUERY_ATTR_IDN_REF_CLK_FREQ] = UFS_QUERY_ATTR_READ | UFS_QUERY_ATTR_WRITE,
449
+ [QUERY_ATTR_IDN_CONF_DESC_LOCK] = UFS_QUERY_ATTR_READ,
450
+ [QUERY_ATTR_IDN_MAX_NUM_OF_RTT] =
451
+ UFS_QUERY_ATTR_READ | UFS_QUERY_ATTR_WRITE,
452
+ [QUERY_ATTR_IDN_EE_CONTROL] = UFS_QUERY_ATTR_READ | UFS_QUERY_ATTR_WRITE,
453
+ [QUERY_ATTR_IDN_EE_STATUS] = UFS_QUERY_ATTR_READ,
454
+ [QUERY_ATTR_IDN_SECONDS_PASSED] = UFS_QUERY_ATTR_WRITE,
455
+ [QUERY_ATTR_IDN_CNTX_CONF] = UFS_QUERY_ATTR_READ,
456
+ [QUERY_ATTR_IDN_FFU_STATUS] = UFS_QUERY_ATTR_READ,
457
+ [QUERY_ATTR_IDN_PSA_STATE] = UFS_QUERY_ATTR_READ | UFS_QUERY_ATTR_WRITE,
458
+ [QUERY_ATTR_IDN_PSA_DATA_SIZE] = UFS_QUERY_ATTR_READ | UFS_QUERY_ATTR_WRITE,
459
+ [QUERY_ATTR_IDN_REF_CLK_GATING_WAIT_TIME] = UFS_QUERY_ATTR_READ,
460
+ [QUERY_ATTR_IDN_CASE_ROUGH_TEMP] = UFS_QUERY_ATTR_READ,
461
+ [QUERY_ATTR_IDN_HIGH_TEMP_BOUND] = UFS_QUERY_ATTR_READ,
462
+ [QUERY_ATTR_IDN_LOW_TEMP_BOUND] = UFS_QUERY_ATTR_READ,
463
+ [QUERY_ATTR_IDN_THROTTLING_STATUS] = UFS_QUERY_ATTR_READ,
464
+ [QUERY_ATTR_IDN_WB_FLUSH_STATUS] = UFS_QUERY_ATTR_READ,
465
+ [QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE] = UFS_QUERY_ATTR_READ,
466
+ [QUERY_ATTR_IDN_WB_BUFF_LIFE_TIME_EST] = UFS_QUERY_ATTR_READ,
467
+ [QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE] = UFS_QUERY_ATTR_READ,
468
+ /* refresh operation is not supported */
469
+ [QUERY_ATTR_IDN_REFRESH_STATUS] = UFS_QUERY_ATTR_READ,
470
+ [QUERY_ATTR_IDN_REFRESH_FREQ] = UFS_QUERY_ATTR_READ,
471
+ [QUERY_ATTR_IDN_REFRESH_UNIT] = UFS_QUERY_ATTR_READ,
472
+};
473
+
474
+static inline QueryRespCode ufs_attr_check_idn_valid(uint8_t idn, int op)
475
+{
476
+ if (idn >= QUERY_ATTR_IDN_COUNT) {
477
+ return QUERY_RESULT_INVALID_IDN;
478
+ }
479
+
480
+ if (!(attr_permission[idn] & op)) {
481
+ if (op == UFS_QUERY_ATTR_READ) {
482
+ trace_ufs_err_query_attr_not_readable(idn);
483
+ return QUERY_RESULT_NOT_READABLE;
484
+ }
485
+ trace_ufs_err_query_attr_not_writable(idn);
486
+ return QUERY_RESULT_NOT_WRITEABLE;
487
+ }
488
+
489
+ return QUERY_RESULT_SUCCESS;
490
+}
491
+
492
+static QueryRespCode ufs_exec_query_flag(UfsRequest *req, int op)
493
+{
494
+ UfsHc *u = req->hc;
495
+ uint8_t idn = req->req_upiu.qr.idn;
496
+ uint32_t value;
497
+ QueryRespCode ret;
498
+
499
+ ret = ufs_flag_check_idn_valid(idn, op);
500
+ if (ret) {
501
+ return ret;
502
+ }
503
+
504
+ if (idn == QUERY_FLAG_IDN_FDEVICEINIT) {
505
+ value = 0;
506
+ } else if (op == UFS_QUERY_FLAG_READ) {
507
+ value = *(((uint8_t *)&u->flags) + idn);
508
+ } else if (op == UFS_QUERY_FLAG_SET) {
509
+ value = 1;
510
+ } else if (op == UFS_QUERY_FLAG_CLEAR) {
511
+ value = 0;
512
+ } else if (op == UFS_QUERY_FLAG_TOGGLE) {
513
+ value = *(((uint8_t *)&u->flags) + idn);
514
+ value = !value;
515
+ } else {
516
+ trace_ufs_err_query_invalid_opcode(op);
517
+ return QUERY_RESULT_INVALID_OPCODE;
518
+ }
519
+
520
+ *(((uint8_t *)&u->flags) + idn) = value;
521
+ req->rsp_upiu.qr.value = cpu_to_be32(value);
522
+ return QUERY_RESULT_SUCCESS;
523
+}
524
+
525
+static uint32_t ufs_read_attr_value(UfsHc *u, uint8_t idn)
526
+{
527
+ switch (idn) {
528
+ case QUERY_ATTR_IDN_BOOT_LU_EN:
529
+ return u->attributes.boot_lun_en;
530
+ case QUERY_ATTR_IDN_POWER_MODE:
531
+ return u->attributes.current_power_mode;
532
+ case QUERY_ATTR_IDN_ACTIVE_ICC_LVL:
533
+ return u->attributes.active_icc_level;
534
+ case QUERY_ATTR_IDN_OOO_DATA_EN:
535
+ return u->attributes.out_of_order_data_en;
536
+ case QUERY_ATTR_IDN_BKOPS_STATUS:
537
+ return u->attributes.background_op_status;
538
+ case QUERY_ATTR_IDN_PURGE_STATUS:
539
+ return u->attributes.purge_status;
540
+ case QUERY_ATTR_IDN_MAX_DATA_IN:
541
+ return u->attributes.max_data_in_size;
542
+ case QUERY_ATTR_IDN_MAX_DATA_OUT:
543
+ return u->attributes.max_data_out_size;
544
+ case QUERY_ATTR_IDN_DYN_CAP_NEEDED:
545
+ return be32_to_cpu(u->attributes.dyn_cap_needed);
546
+ case QUERY_ATTR_IDN_REF_CLK_FREQ:
547
+ return u->attributes.ref_clk_freq;
548
+ case QUERY_ATTR_IDN_CONF_DESC_LOCK:
549
+ return u->attributes.config_descr_lock;
550
+ case QUERY_ATTR_IDN_MAX_NUM_OF_RTT:
551
+ return u->attributes.max_num_of_rtt;
552
+ case QUERY_ATTR_IDN_EE_CONTROL:
553
+ return be16_to_cpu(u->attributes.exception_event_control);
554
+ case QUERY_ATTR_IDN_EE_STATUS:
555
+ return be16_to_cpu(u->attributes.exception_event_status);
556
+ case QUERY_ATTR_IDN_SECONDS_PASSED:
557
+ return be32_to_cpu(u->attributes.seconds_passed);
558
+ case QUERY_ATTR_IDN_CNTX_CONF:
559
+ return be16_to_cpu(u->attributes.context_conf);
560
+ case QUERY_ATTR_IDN_FFU_STATUS:
561
+ return u->attributes.device_ffu_status;
562
+ case QUERY_ATTR_IDN_PSA_STATE:
563
+ return be32_to_cpu(u->attributes.psa_state);
564
+ case QUERY_ATTR_IDN_PSA_DATA_SIZE:
565
+ return be32_to_cpu(u->attributes.psa_data_size);
566
+ case QUERY_ATTR_IDN_REF_CLK_GATING_WAIT_TIME:
567
+ return u->attributes.ref_clk_gating_wait_time;
568
+ case QUERY_ATTR_IDN_CASE_ROUGH_TEMP:
569
+ return u->attributes.device_case_rough_temperaure;
570
+ case QUERY_ATTR_IDN_HIGH_TEMP_BOUND:
571
+ return u->attributes.device_too_high_temp_boundary;
572
+ case QUERY_ATTR_IDN_LOW_TEMP_BOUND:
573
+ return u->attributes.device_too_low_temp_boundary;
574
+ case QUERY_ATTR_IDN_THROTTLING_STATUS:
575
+ return u->attributes.throttling_status;
576
+ case QUERY_ATTR_IDN_WB_FLUSH_STATUS:
577
+ return u->attributes.wb_buffer_flush_status;
578
+ case QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE:
579
+ return u->attributes.available_wb_buffer_size;
580
+ case QUERY_ATTR_IDN_WB_BUFF_LIFE_TIME_EST:
581
+ return u->attributes.wb_buffer_life_time_est;
582
+ case QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE:
583
+ return be32_to_cpu(u->attributes.current_wb_buffer_size);
584
+ case QUERY_ATTR_IDN_REFRESH_STATUS:
585
+ return u->attributes.refresh_status;
586
+ case QUERY_ATTR_IDN_REFRESH_FREQ:
587
+ return u->attributes.refresh_freq;
588
+ case QUERY_ATTR_IDN_REFRESH_UNIT:
589
+ return u->attributes.refresh_unit;
590
+ }
591
+ return 0;
592
+}
593
+
594
+static void ufs_write_attr_value(UfsHc *u, uint8_t idn, uint32_t value)
595
+{
596
+ switch (idn) {
597
+ case QUERY_ATTR_IDN_ACTIVE_ICC_LVL:
598
+ u->attributes.active_icc_level = value;
599
+ break;
600
+ case QUERY_ATTR_IDN_MAX_DATA_IN:
601
+ u->attributes.max_data_in_size = value;
602
+ break;
603
+ case QUERY_ATTR_IDN_MAX_DATA_OUT:
604
+ u->attributes.max_data_out_size = value;
605
+ break;
606
+ case QUERY_ATTR_IDN_REF_CLK_FREQ:
607
+ u->attributes.ref_clk_freq = value;
608
+ break;
609
+ case QUERY_ATTR_IDN_MAX_NUM_OF_RTT:
610
+ u->attributes.max_num_of_rtt = value;
611
+ break;
612
+ case QUERY_ATTR_IDN_EE_CONTROL:
613
+ u->attributes.exception_event_control = cpu_to_be16(value);
614
+ break;
615
+ case QUERY_ATTR_IDN_SECONDS_PASSED:
616
+ u->attributes.seconds_passed = cpu_to_be32(value);
617
+ break;
618
+ case QUERY_ATTR_IDN_PSA_STATE:
619
+ u->attributes.psa_state = value;
620
+ break;
621
+ case QUERY_ATTR_IDN_PSA_DATA_SIZE:
622
+ u->attributes.psa_data_size = cpu_to_be32(value);
623
+ break;
624
+ }
625
+}
626
+
627
+static QueryRespCode ufs_exec_query_attr(UfsRequest *req, int op)
628
+{
629
+ UfsHc *u = req->hc;
630
+ uint8_t idn = req->req_upiu.qr.idn;
631
+ uint32_t value;
632
+ QueryRespCode ret;
633
+
634
+ ret = ufs_attr_check_idn_valid(idn, op);
635
+ if (ret) {
636
+ return ret;
637
+ }
638
+
639
+ if (op == UFS_QUERY_ATTR_READ) {
640
+ value = ufs_read_attr_value(u, idn);
641
+ } else {
642
+ value = be32_to_cpu(req->req_upiu.qr.value);
643
+ ufs_write_attr_value(u, idn, value);
644
+ }
645
+
646
+ req->rsp_upiu.qr.value = cpu_to_be32(value);
647
+ return QUERY_RESULT_SUCCESS;
648
+}
649
+
650
+static const RpmbUnitDescriptor rpmb_unit_desc = {
651
+ .length = sizeof(RpmbUnitDescriptor),
652
+ .descriptor_idn = 2,
653
+ .unit_index = UFS_UPIU_RPMB_WLUN,
654
+ .lu_enable = 0,
655
+};
656
+
657
+static QueryRespCode ufs_read_unit_desc(UfsRequest *req)
658
+{
659
+ uint8_t lun = req->req_upiu.qr.index;
660
+
661
+ if (lun != UFS_UPIU_RPMB_WLUN && lun > UFS_MAX_LUS) {
662
+ trace_ufs_err_query_invalid_index(req->req_upiu.qr.opcode, lun);
663
+ return QUERY_RESULT_INVALID_INDEX;
664
+ }
665
+
666
+ if (lun == UFS_UPIU_RPMB_WLUN) {
667
+ memcpy(&req->rsp_upiu.qr.data, &rpmb_unit_desc, rpmb_unit_desc.length);
668
+ } else {
669
+ /* unit descriptor is not yet supported */
670
+ return QUERY_RESULT_INVALID_INDEX;
671
+ }
672
+
673
+ return QUERY_RESULT_SUCCESS;
674
+}
675
+
676
+static inline StringDescriptor manufacturer_str_desc(void)
677
+{
678
+ StringDescriptor desc = {
679
+ .length = 0x12,
680
+ .descriptor_idn = QUERY_DESC_IDN_STRING,
681
+ };
682
+ desc.UC[0] = cpu_to_be16('R');
683
+ desc.UC[1] = cpu_to_be16('E');
684
+ desc.UC[2] = cpu_to_be16('D');
685
+ desc.UC[3] = cpu_to_be16('H');
686
+ desc.UC[4] = cpu_to_be16('A');
687
+ desc.UC[5] = cpu_to_be16('T');
688
+ return desc;
689
+}
690
+
691
+static inline StringDescriptor product_name_str_desc(void)
692
+{
693
+ StringDescriptor desc = {
694
+ .length = 0x22,
695
+ .descriptor_idn = QUERY_DESC_IDN_STRING,
696
+ };
697
+ desc.UC[0] = cpu_to_be16('Q');
698
+ desc.UC[1] = cpu_to_be16('E');
699
+ desc.UC[2] = cpu_to_be16('M');
700
+ desc.UC[3] = cpu_to_be16('U');
701
+ desc.UC[4] = cpu_to_be16(' ');
702
+ desc.UC[5] = cpu_to_be16('U');
703
+ desc.UC[6] = cpu_to_be16('F');
704
+ desc.UC[7] = cpu_to_be16('S');
705
+ return desc;
706
+}
707
+
708
+static inline StringDescriptor product_rev_level_str_desc(void)
709
+{
710
+ StringDescriptor desc = {
711
+ .length = 0x0a,
712
+ .descriptor_idn = QUERY_DESC_IDN_STRING,
713
+ };
714
+ desc.UC[0] = cpu_to_be16('0');
715
+ desc.UC[1] = cpu_to_be16('0');
716
+ desc.UC[2] = cpu_to_be16('0');
717
+ desc.UC[3] = cpu_to_be16('1');
718
+ return desc;
719
+}
720
+
721
+static const StringDescriptor null_str_desc = {
722
+ .length = 0x02,
723
+ .descriptor_idn = QUERY_DESC_IDN_STRING,
724
+};
725
+
726
+static QueryRespCode ufs_read_string_desc(UfsRequest *req)
727
+{
728
+ UfsHc *u = req->hc;
729
+ uint8_t index = req->req_upiu.qr.index;
730
+ StringDescriptor desc;
731
+
732
+ if (index == u->device_desc.manufacturer_name) {
733
+ desc = manufacturer_str_desc();
734
+ memcpy(&req->rsp_upiu.qr.data, &desc, desc.length);
735
+ } else if (index == u->device_desc.product_name) {
736
+ desc = product_name_str_desc();
737
+ memcpy(&req->rsp_upiu.qr.data, &desc, desc.length);
738
+ } else if (index == u->device_desc.serial_number) {
739
+ memcpy(&req->rsp_upiu.qr.data, &null_str_desc, null_str_desc.length);
740
+ } else if (index == u->device_desc.oem_id) {
741
+ memcpy(&req->rsp_upiu.qr.data, &null_str_desc, null_str_desc.length);
742
+ } else if (index == u->device_desc.product_revision_level) {
743
+ desc = product_rev_level_str_desc();
744
+ memcpy(&req->rsp_upiu.qr.data, &desc, desc.length);
745
+ } else {
746
+ trace_ufs_err_query_invalid_index(req->req_upiu.qr.opcode, index);
747
+ return QUERY_RESULT_INVALID_INDEX;
748
+ }
749
+ return QUERY_RESULT_SUCCESS;
750
+}
751
+
752
+static inline InterconnectDescriptor interconnect_desc(void)
753
+{
754
+ InterconnectDescriptor desc = {
755
+ .length = sizeof(InterconnectDescriptor),
756
+ .descriptor_idn = QUERY_DESC_IDN_INTERCONNECT,
757
+ };
758
+ desc.bcd_unipro_version = cpu_to_be16(0x180);
759
+ desc.bcd_mphy_version = cpu_to_be16(0x410);
760
+ return desc;
761
+}
762
+
763
+static QueryRespCode ufs_read_desc(UfsRequest *req)
764
+{
765
+ UfsHc *u = req->hc;
766
+ QueryRespCode status;
767
+ uint8_t idn = req->req_upiu.qr.idn;
768
+ uint16_t length = be16_to_cpu(req->req_upiu.qr.length);
769
+ InterconnectDescriptor desc;
770
+
771
+ switch (idn) {
772
+ case QUERY_DESC_IDN_DEVICE:
773
+ memcpy(&req->rsp_upiu.qr.data, &u->device_desc, sizeof(u->device_desc));
774
+ status = QUERY_RESULT_SUCCESS;
775
+ break;
776
+ case QUERY_DESC_IDN_UNIT:
777
+ status = ufs_read_unit_desc(req);
778
+ break;
779
+ case QUERY_DESC_IDN_GEOMETRY:
780
+ memcpy(&req->rsp_upiu.qr.data, &u->geometry_desc,
781
+ sizeof(u->geometry_desc));
782
+ status = QUERY_RESULT_SUCCESS;
783
+ break;
784
+ case QUERY_DESC_IDN_INTERCONNECT: {
785
+ desc = interconnect_desc();
786
+ memcpy(&req->rsp_upiu.qr.data, &desc, sizeof(InterconnectDescriptor));
787
+ status = QUERY_RESULT_SUCCESS;
788
+ break;
789
+ }
790
+ case QUERY_DESC_IDN_STRING:
791
+ status = ufs_read_string_desc(req);
792
+ break;
793
+ case QUERY_DESC_IDN_POWER:
794
+ /* mocking of power descriptor is not supported */
795
+ memset(&req->rsp_upiu.qr.data, 0, sizeof(PowerParametersDescriptor));
796
+ req->rsp_upiu.qr.data[0] = sizeof(PowerParametersDescriptor);
797
+ req->rsp_upiu.qr.data[1] = QUERY_DESC_IDN_POWER;
798
+ status = QUERY_RESULT_SUCCESS;
799
+ break;
800
+ case QUERY_DESC_IDN_HEALTH:
801
+ /* mocking of health descriptor is not supported */
802
+ memset(&req->rsp_upiu.qr.data, 0, sizeof(DeviceHealthDescriptor));
803
+ req->rsp_upiu.qr.data[0] = sizeof(DeviceHealthDescriptor);
804
+ req->rsp_upiu.qr.data[1] = QUERY_DESC_IDN_HEALTH;
805
+ status = QUERY_RESULT_SUCCESS;
806
+ break;
807
+ default:
808
+ length = 0;
809
+ trace_ufs_err_query_invalid_idn(req->req_upiu.qr.opcode, idn);
810
+ status = QUERY_RESULT_INVALID_IDN;
811
+ }
812
+
813
+ if (length > req->rsp_upiu.qr.data[0]) {
814
+ length = req->rsp_upiu.qr.data[0];
815
+ }
816
+ req->rsp_upiu.qr.opcode = req->req_upiu.qr.opcode;
817
+ req->rsp_upiu.qr.idn = req->req_upiu.qr.idn;
818
+ req->rsp_upiu.qr.index = req->req_upiu.qr.index;
819
+ req->rsp_upiu.qr.selector = req->req_upiu.qr.selector;
820
+ req->rsp_upiu.qr.length = cpu_to_be16(length);
821
+
822
+ return status;
823
+}
824
+
825
+static QueryRespCode ufs_exec_query_read(UfsRequest *req)
826
+{
827
+ QueryRespCode status;
828
+ switch (req->req_upiu.qr.opcode) {
829
+ case UPIU_QUERY_OPCODE_NOP:
830
+ status = QUERY_RESULT_SUCCESS;
831
+ break;
832
+ case UPIU_QUERY_OPCODE_READ_DESC:
833
+ status = ufs_read_desc(req);
834
+ break;
835
+ case UPIU_QUERY_OPCODE_READ_ATTR:
836
+ status = ufs_exec_query_attr(req, UFS_QUERY_ATTR_READ);
837
+ break;
838
+ case UPIU_QUERY_OPCODE_READ_FLAG:
839
+ status = ufs_exec_query_flag(req, UFS_QUERY_FLAG_READ);
840
+ break;
841
+ default:
842
+ trace_ufs_err_query_invalid_opcode(req->req_upiu.qr.opcode);
843
+ status = QUERY_RESULT_INVALID_OPCODE;
844
+ break;
845
+ }
846
+
847
+ return status;
848
+}
849
+
850
+static QueryRespCode ufs_exec_query_write(UfsRequest *req)
851
+{
852
+ QueryRespCode status;
853
+ switch (req->req_upiu.qr.opcode) {
854
+ case UPIU_QUERY_OPCODE_NOP:
855
+ status = QUERY_RESULT_SUCCESS;
856
+ break;
857
+ case UPIU_QUERY_OPCODE_WRITE_DESC:
858
+ /* write descriptor is not supported */
859
+ status = QUERY_RESULT_NOT_WRITEABLE;
860
+ break;
861
+ case UPIU_QUERY_OPCODE_WRITE_ATTR:
862
+ status = ufs_exec_query_attr(req, UFS_QUERY_ATTR_WRITE);
863
+ break;
864
+ case UPIU_QUERY_OPCODE_SET_FLAG:
865
+ status = ufs_exec_query_flag(req, UFS_QUERY_FLAG_SET);
866
+ break;
867
+ case UPIU_QUERY_OPCODE_CLEAR_FLAG:
868
+ status = ufs_exec_query_flag(req, UFS_QUERY_FLAG_CLEAR);
869
+ break;
870
+ case UPIU_QUERY_OPCODE_TOGGLE_FLAG:
871
+ status = ufs_exec_query_flag(req, UFS_QUERY_FLAG_TOGGLE);
872
+ break;
873
+ default:
874
+ trace_ufs_err_query_invalid_opcode(req->req_upiu.qr.opcode);
875
+ status = QUERY_RESULT_INVALID_OPCODE;
876
+ break;
877
+ }
878
+
879
+ return status;
880
+}
881
+
882
+static UfsReqResult ufs_exec_query_cmd(UfsRequest *req)
883
+{
884
+ uint8_t query_func = req->req_upiu.header.query_func;
885
+ uint16_t data_segment_length;
886
+ QueryRespCode status;
887
+
888
+ trace_ufs_exec_query_cmd(req->slot, req->req_upiu.qr.opcode);
889
+ if (query_func == UPIU_QUERY_FUNC_STANDARD_READ_REQUEST) {
890
+ status = ufs_exec_query_read(req);
891
+ } else if (query_func == UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST) {
892
+ status = ufs_exec_query_write(req);
893
+ } else {
894
+ status = QUERY_RESULT_GENERAL_FAILURE;
895
+ }
896
+
897
+ data_segment_length = be16_to_cpu(req->rsp_upiu.qr.length);
898
+ ufs_build_upiu_header(req, UPIU_TRANSACTION_QUERY_RSP, 0, status, 0,
899
+ data_segment_length);
900
+
901
+ if (status != QUERY_RESULT_SUCCESS) {
902
+ return UFS_REQUEST_FAIL;
903
+ }
904
+ return UFS_REQUEST_SUCCESS;
905
+}
906
+
907
+static void ufs_exec_req(UfsRequest *req)
908
+{
909
+ UfsReqResult req_result;
910
+
911
+ if (ufs_dma_read_upiu(req)) {
912
+ return;
913
+ }
914
+
915
+ switch (req->req_upiu.header.trans_type) {
916
+ case UPIU_TRANSACTION_NOP_OUT:
917
+ req_result = ufs_exec_nop_cmd(req);
918
+ break;
919
+ case UPIU_TRANSACTION_COMMAND:
920
+ /* Not yet implemented */
921
+ req_result = UFS_REQUEST_FAIL;
922
+ break;
923
+ case UPIU_TRANSACTION_QUERY_REQ:
924
+ req_result = ufs_exec_query_cmd(req);
925
+ break;
926
+ default:
927
+ trace_ufs_err_invalid_trans_code(req->slot,
928
+ req->req_upiu.header.trans_type);
929
+ req_result = UFS_REQUEST_FAIL;
930
+ }
931
+
932
+ ufs_complete_req(req, req_result);
933
+}
934
+
935
+static void ufs_process_req(void *opaque)
936
+{
937
+ UfsHc *u = opaque;
938
+ UfsRequest *req;
939
+ int slot;
940
+
941
+ for (slot = 0; slot < u->params.nutrs; slot++) {
942
+ req = &u->req_list[slot];
943
+
944
+ if (req->state != UFS_REQUEST_READY) {
945
+ continue;
946
+ }
947
+ trace_ufs_process_req(slot);
948
+ req->state = UFS_REQUEST_RUNNING;
949
+
950
+ ufs_exec_req(req);
951
+ }
952
+}
953
+
954
+static void ufs_complete_req(UfsRequest *req, UfsReqResult req_result)
955
+{
956
+ UfsHc *u = req->hc;
957
+ assert(req->state == UFS_REQUEST_RUNNING);
958
+
959
+ if (req_result == UFS_REQUEST_SUCCESS) {
960
+ req->utrd.header.dword_2 = cpu_to_le32(OCS_SUCCESS);
961
+ } else {
962
+ req->utrd.header.dword_2 = cpu_to_le32(OCS_INVALID_CMD_TABLE_ATTR);
963
+ }
964
+
965
+ trace_ufs_complete_req(req->slot);
966
+ req->state = UFS_REQUEST_COMPLETE;
967
+ qemu_bh_schedule(u->complete_bh);
968
+}
969
+
970
+static void ufs_clear_req(UfsRequest *req)
971
+{
972
+ if (req->sg != NULL) {
973
+ qemu_sglist_destroy(req->sg);
974
+ g_free(req->sg);
975
+ req->sg = NULL;
976
+ }
977
+
978
+ memset(&req->utrd, 0, sizeof(req->utrd));
979
+ memset(&req->req_upiu, 0, sizeof(req->req_upiu));
980
+ memset(&req->rsp_upiu, 0, sizeof(req->rsp_upiu));
981
+}
982
+
983
+static void ufs_sendback_req(void *opaque)
984
+{
985
+ UfsHc *u = opaque;
986
+ UfsRequest *req;
987
+ int slot;
988
+
989
+ for (slot = 0; slot < u->params.nutrs; slot++) {
990
+ req = &u->req_list[slot];
991
+
992
+ if (req->state != UFS_REQUEST_COMPLETE) {
993
+ continue;
994
+ }
995
+
996
+ if (ufs_dma_write_upiu(req)) {
997
+ req->state = UFS_REQUEST_ERROR;
998
+ continue;
999
+ }
1000
+
1001
+ /*
1002
+ * TODO: UTP Transfer Request Interrupt Aggregation Control is not yet
1003
+ * supported
1004
+ */
1005
+ if (le32_to_cpu(req->utrd.header.dword_2) != OCS_SUCCESS ||
1006
+ le32_to_cpu(req->utrd.header.dword_0) & UTP_REQ_DESC_INT_CMD) {
1007
+ u->reg.is = FIELD_DP32(u->reg.is, IS, UTRCS, 1);
1008
+ }
1009
+
1010
+ u->reg.utrldbr &= ~(1 << slot);
1011
+ u->reg.utrlcnr |= (1 << slot);
1012
+
1013
+ trace_ufs_sendback_req(req->slot);
1014
+
1015
+ ufs_clear_req(req);
1016
+ req->state = UFS_REQUEST_IDLE;
1017
+ }
1018
+
1019
+ ufs_irq_check(u);
1020
+}
1021
+
1022
static bool ufs_check_constraints(UfsHc *u, Error **errp)
1023
{
1024
if (u->params.nutrs > UFS_MAX_NUTRS) {
1025
@@ -XXX,XX +XXX,XX @@ static void ufs_init_pci(UfsHc *u, PCIDevice *pci_dev)
1026
u->irq = pci_allocate_irq(pci_dev);
59
}
1027
}
60
1028
61
-test_quorum=$($QEMU_IMG --help|grep quorum)
1029
+static void ufs_init_state(UfsHc *u)
62
-[ "$test_quorum" = "" ] && _supported_fmt quorum
1030
+{
63
-
1031
+ u->req_list = g_new0(UfsRequest, u->params.nutrs);
64
quorum="driver=raw,file.driver=quorum,file.vote-threshold=2"
1032
+
65
quorum="$quorum,file.children.0.file.filename=$TEST_DIR/1.raw"
1033
+ for (int i = 0; i < u->params.nutrs; i++) {
66
quorum="$quorum,file.children.1.file.filename=$TEST_DIR/2.raw"
1034
+ u->req_list[i].hc = u;
67
diff --git a/tests/qemu-iotests/099 b/tests/qemu-iotests/099
1035
+ u->req_list[i].slot = i;
68
index XXXXXXX..XXXXXXX 100755
1036
+ u->req_list[i].sg = NULL;
69
--- a/tests/qemu-iotests/099
1037
+ u->req_list[i].state = UFS_REQUEST_IDLE;
70
+++ b/tests/qemu-iotests/099
1038
+ }
71
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
1039
+
72
_supported_fmt qcow qcow2 qed vdi vhdx vmdk vpc
1040
+ u->doorbell_bh = qemu_bh_new_guarded(ufs_process_req, u,
73
_supported_proto file
1041
+ &DEVICE(u)->mem_reentrancy_guard);
74
_supported_os Linux
1042
+ u->complete_bh = qemu_bh_new_guarded(ufs_sendback_req, u,
75
+_require_drivers blkdebug blkverify
1043
+ &DEVICE(u)->mem_reentrancy_guard);
76
_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat" \
1044
+}
77
"subformat=twoGbMaxExtentSparse"
1045
+
78
1046
static void ufs_init_hc(UfsHc *u)
79
diff --git a/tests/qemu-iotests/120 b/tests/qemu-iotests/120
80
index XXXXXXX..XXXXXXX 100755
81
--- a/tests/qemu-iotests/120
82
+++ b/tests/qemu-iotests/120
83
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
84
_supported_fmt generic
85
_supported_proto file
86
_unsupported_fmt luks
87
+_require_drivers raw
88
89
_make_test_img 64M
90
91
diff --git a/tests/qemu-iotests/162 b/tests/qemu-iotests/162
92
index XXXXXXX..XXXXXXX 100755
93
--- a/tests/qemu-iotests/162
94
+++ b/tests/qemu-iotests/162
95
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
96
. ./common.filter
97
98
_supported_fmt generic
99
-
100
-test_ssh=$($QEMU_IMG --help | grep '^Supported formats:.* ssh\( \|$\)')
101
-[ "$test_ssh" = "" ] && _notrun "ssh support required"
102
+_require_drivers ssh
103
104
echo
105
echo '=== NBD ==='
106
diff --git a/tests/qemu-iotests/184 b/tests/qemu-iotests/184
107
index XXXXXXX..XXXXXXX 100755
108
--- a/tests/qemu-iotests/184
109
+++ b/tests/qemu-iotests/184
110
@@ -XXX,XX +XXX,XX @@ trap "exit \$status" 0 1 2 3 15
111
. ./common.filter
112
113
_supported_os Linux
114
+_require_drivers throttle
115
116
do_run_qemu()
117
{
1047
{
118
diff --git a/tests/qemu-iotests/186 b/tests/qemu-iotests/186
1048
uint32_t cap = 0;
119
index XXXXXXX..XXXXXXX 100755
1049
@@ -XXX,XX +XXX,XX @@ static void ufs_init_hc(UfsHc *u)
120
--- a/tests/qemu-iotests/186
1050
cap = FIELD_DP32(cap, CAP, CS, 0);
121
+++ b/tests/qemu-iotests/186
1051
u->reg.cap = cap;
122
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
1052
u->reg.ver = UFS_SPEC_VER;
123
1053
+
124
_supported_fmt qcow2
1054
+ memset(&u->device_desc, 0, sizeof(DeviceDescriptor));
125
_supported_proto file
1055
+ u->device_desc.length = sizeof(DeviceDescriptor);
126
+_require_drivers null-co
1056
+ u->device_desc.descriptor_idn = QUERY_DESC_IDN_DEVICE;
127
1057
+ u->device_desc.device_sub_class = 0x01;
128
if [ "$QEMU_DEFAULT_MACHINE" != "pc" ]; then
1058
+ u->device_desc.number_lu = 0x00;
129
_notrun "Requires a PC machine"
1059
+ u->device_desc.number_wlu = 0x04;
130
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
1060
+ /* TODO: Revisit it when Power Management is implemented */
1061
+ u->device_desc.init_power_mode = 0x01; /* Active Mode */
1062
+ u->device_desc.high_priority_lun = 0x7F; /* Same Priority */
1063
+ u->device_desc.spec_version = cpu_to_be16(UFS_SPEC_VER);
1064
+ u->device_desc.manufacturer_name = 0x00;
1065
+ u->device_desc.product_name = 0x01;
1066
+ u->device_desc.serial_number = 0x02;
1067
+ u->device_desc.oem_id = 0x03;
1068
+ u->device_desc.ud_0_base_offset = 0x16;
1069
+ u->device_desc.ud_config_p_length = 0x1A;
1070
+ u->device_desc.device_rtt_cap = 0x02;
1071
+ u->device_desc.queue_depth = u->params.nutrs;
1072
+ u->device_desc.product_revision_level = 0x04;
1073
+
1074
+ memset(&u->geometry_desc, 0, sizeof(GeometryDescriptor));
1075
+ u->geometry_desc.length = sizeof(GeometryDescriptor);
1076
+ u->geometry_desc.descriptor_idn = QUERY_DESC_IDN_GEOMETRY;
1077
+ u->geometry_desc.max_number_lu = (UFS_MAX_LUS == 32) ? 0x1 : 0x0;
1078
+ u->geometry_desc.segment_size = cpu_to_be32(0x2000); /* 4KB */
1079
+ u->geometry_desc.allocation_unit_size = 0x1; /* 4KB */
1080
+ u->geometry_desc.min_addr_block_size = 0x8; /* 4KB */
1081
+ u->geometry_desc.max_in_buffer_size = 0x8;
1082
+ u->geometry_desc.max_out_buffer_size = 0x8;
1083
+ u->geometry_desc.rpmb_read_write_size = 0x40;
1084
+ u->geometry_desc.data_ordering =
1085
+ 0x0; /* out-of-order data transfer is not supported */
1086
+ u->geometry_desc.max_context_id_number = 0x5;
1087
+ u->geometry_desc.supported_memory_types = cpu_to_be16(0x8001);
1088
+
1089
+ memset(&u->attributes, 0, sizeof(u->attributes));
1090
+ u->attributes.max_data_in_size = 0x08;
1091
+ u->attributes.max_data_out_size = 0x08;
1092
+ u->attributes.ref_clk_freq = 0x01; /* 26 MHz */
1093
+ /* configure descriptor is not supported */
1094
+ u->attributes.config_descr_lock = 0x01;
1095
+ u->attributes.max_num_of_rtt = 0x02;
1096
+
1097
+ memset(&u->flags, 0, sizeof(u->flags));
1098
+ u->flags.permanently_disable_fw_update = 1;
1099
}
1100
1101
static void ufs_realize(PCIDevice *pci_dev, Error **errp)
1102
@@ -XXX,XX +XXX,XX @@ static void ufs_realize(PCIDevice *pci_dev, Error **errp)
1103
return;
1104
}
1105
1106
+ ufs_init_state(u);
1107
ufs_init_hc(u);
1108
ufs_init_pci(u, pci_dev);
1109
}
1110
1111
+static void ufs_exit(PCIDevice *pci_dev)
1112
+{
1113
+ UfsHc *u = UFS(pci_dev);
1114
+
1115
+ qemu_bh_delete(u->doorbell_bh);
1116
+ qemu_bh_delete(u->complete_bh);
1117
+
1118
+ for (int i = 0; i < u->params.nutrs; i++) {
1119
+ ufs_clear_req(&u->req_list[i]);
1120
+ }
1121
+ g_free(u->req_list);
1122
+}
1123
+
1124
static Property ufs_props[] = {
1125
DEFINE_PROP_STRING("serial", UfsHc, params.serial),
1126
DEFINE_PROP_UINT8("nutrs", UfsHc, params.nutrs, 32),
1127
@@ -XXX,XX +XXX,XX @@ static void ufs_class_init(ObjectClass *oc, void *data)
1128
PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc);
1129
1130
pc->realize = ufs_realize;
1131
+ pc->exit = ufs_exit;
1132
pc->vendor_id = PCI_VENDOR_ID_REDHAT;
1133
pc->device_id = PCI_DEVICE_ID_REDHAT_UFS;
1134
pc->class_id = PCI_CLASS_STORAGE_UFS;
1135
diff --git a/hw/ufs/trace-events b/hw/ufs/trace-events
131
index XXXXXXX..XXXXXXX 100644
1136
index XXXXXXX..XXXXXXX 100644
132
--- a/tests/qemu-iotests/common.rc
1137
--- a/hw/ufs/trace-events
133
+++ b/tests/qemu-iotests/common.rc
1138
+++ b/hw/ufs/trace-events
134
@@ -XXX,XX +XXX,XX @@ _require_command()
1139
@@ -XXX,XX +XXX,XX @@ ufs_err_dma_read_req_upiu(uint32_t slot, uint64_t addr) "failed to read req upiu
135
[ -x "$c" ] || _notrun "$1 utility required, skipped this test"
1140
ufs_err_dma_read_prdt(uint32_t slot, uint64_t addr) "failed to read prdt. UTRLDBR slot %"PRIu32", prdt addr %"PRIu64""
136
}
1141
ufs_err_dma_write_utrd(uint32_t slot, uint64_t addr) "failed to write utrd. UTRLDBR slot %"PRIu32", UTRD dma addr %"PRIu64""
137
1142
ufs_err_dma_write_rsp_upiu(uint32_t slot, uint64_t addr) "failed to write rsp upiu. UTRLDBR slot %"PRIu32", response upiu addr %"PRIu64""
138
+# Check that a set of drivers has been whitelisted in the QEMU binary
1143
+ufs_err_utrl_slot_error(uint32_t slot) "UTRLDBR slot %"PRIu32" is in error"
139
+#
1144
ufs_err_utrl_slot_busy(uint32_t slot) "UTRLDBR slot %"PRIu32" is busy"
140
+_require_drivers()
1145
ufs_err_unsupport_register_offset(uint32_t offset) "Register offset 0x%"PRIx32" is not yet supported"
141
+{
1146
ufs_err_invalid_register_offset(uint32_t offset) "Register offset 0x%"PRIx32" is invalid"
142
+ available=$($QEMU -drive format=help | \
143
+ sed -e '/Supported formats:/!d' -e 's/Supported formats://')
144
+ for driver
145
+ do
146
+ if ! echo "$available" | grep -q " $driver\( \|$\)"; then
147
+ _notrun "$driver not available"
148
+ fi
149
+ done
150
+}
151
+
152
# make sure this script returns success
153
true
154
--
1147
--
155
2.21.0
1148
2.41.0
156
157
diff view generated by jsdifflib
1
From: Nir Soffer <nirsof@gmail.com>
1
From: Jeuk Kim <jeuk20.kim@gmail.com>
2
2
3
When creating an image with preallocation "off" or "falloc", the first
3
This commit adds support for ufs logical unit.
4
block of the image is typically not allocated. When using Gluster
4
The LU handles processing for the SCSI command,
5
storage backed by XFS filesystem, reading this block using direct I/O
5
unit descriptor query request.
6
succeeds regardless of request length, fooling alignment detection.
7
6
8
In this case we fallback to a safe value (4096) instead of the optimal
7
This commit enables the UFS device to process
9
value (512), which may lead to unneeded data copying when aligning
8
IO requests.
10
requests. Allocating the first block avoids the fallback.
11
9
12
Since we allocate the first block even with preallocation=off, we no
10
Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>
13
longer create images with zero disk size:
11
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Message-id: 898cea923e819dc21a99597bf045a12d7983be28.1691062912.git.jeuk20.kim@samsung.com
13
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
14
---
15
hw/ufs/ufs.h | 43 ++
16
include/scsi/constants.h | 1 +
17
hw/ufs/lu.c | 1445 ++++++++++++++++++++++++++++++++++++++
18
hw/ufs/ufs.c | 252 ++++++-
19
hw/ufs/meson.build | 2 +-
20
hw/ufs/trace-events | 25 +
21
6 files changed, 1761 insertions(+), 7 deletions(-)
22
create mode 100644 hw/ufs/lu.c
14
23
15
$ ./qemu-img create -f raw test.raw 1g
24
diff --git a/hw/ufs/ufs.h b/hw/ufs/ufs.h
16
Formatting 'test.raw', fmt=raw size=1073741824
17
18
$ ls -lhs test.raw
19
4.0K -rw-r--r--. 1 nsoffer nsoffer 1.0G Aug 16 23:48 test.raw
20
21
And converting the image requires additional cluster:
22
23
$ ./qemu-img measure -f raw -O qcow2 test.raw
24
required size: 458752
25
fully allocated size: 1074135040
26
27
When using format like vmdk with multiple files per image, we allocate
28
one block per file:
29
30
$ ./qemu-img create -f vmdk -o subformat=twoGbMaxExtentFlat test.vmdk 4g
31
Formatting 'test.vmdk', fmt=vmdk size=4294967296 compat6=off hwversion=undefined subformat=twoGbMaxExtentFlat
32
33
$ ls -lhs test*.vmdk
34
4.0K -rw-r--r--. 1 nsoffer nsoffer 2.0G Aug 27 03:23 test-f001.vmdk
35
4.0K -rw-r--r--. 1 nsoffer nsoffer 2.0G Aug 27 03:23 test-f002.vmdk
36
4.0K -rw-r--r--. 1 nsoffer nsoffer 353 Aug 27 03:23 test.vmdk
37
38
I did quick performance test for copying disks with qemu-img convert to
39
new raw target image to Gluster storage with sector size of 512 bytes:
40
41
for i in $(seq 10); do
42
rm -f dst.raw
43
sleep 10
44
time ./qemu-img convert -f raw -O raw -t none -T none src.raw dst.raw
45
done
46
47
Here is a table comparing the total time spent:
48
49
Type Before(s) After(s) Diff(%)
50
---------------------------------------
51
real 530.028 469.123 -11.4
52
user 17.204 10.768 -37.4
53
sys 17.881 7.011 -60.7
54
55
We can see very clear improvement in CPU usage.
56
57
Signed-off-by: Nir Soffer <nsoffer@redhat.com>
58
Message-id: 20190827010528.8818-2-nsoffer@redhat.com
59
Reviewed-by: Max Reitz <mreitz@redhat.com>
60
Signed-off-by: Max Reitz <mreitz@redhat.com>
61
---
62
block/file-posix.c | 51 +++++++++++++++++++
63
tests/qemu-iotests/059.out | 2 +-
64
tests/qemu-iotests/{150.out => 150.out.qcow2} | 0
65
tests/qemu-iotests/150.out.raw | 12 +++++
66
tests/qemu-iotests/175 | 19 ++++---
67
tests/qemu-iotests/175.out | 8 +--
68
tests/qemu-iotests/178.out.qcow2 | 4 +-
69
tests/qemu-iotests/221.out | 12 +++--
70
tests/qemu-iotests/253.out | 12 +++--
71
9 files changed, 99 insertions(+), 21 deletions(-)
72
rename tests/qemu-iotests/{150.out => 150.out.qcow2} (100%)
73
create mode 100644 tests/qemu-iotests/150.out.raw
74
75
diff --git a/block/file-posix.c b/block/file-posix.c
76
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100644
77
--- a/block/file-posix.c
26
--- a/hw/ufs/ufs.h
78
+++ b/block/file-posix.c
27
+++ b/hw/ufs/ufs.h
79
@@ -XXX,XX +XXX,XX @@ static int handle_aiocb_discard(void *opaque)
28
@@ -XXX,XX +XXX,XX @@
80
return ret;
29
#define UFS_MAX_LUS 32
81
}
30
#define UFS_BLOCK_SIZE 4096
82
31
83
+/*
32
+typedef struct UfsBusClass {
84
+ * Help alignment probing by allocating the first block.
33
+ BusClass parent_class;
85
+ *
34
+ bool (*parent_check_address)(BusState *bus, DeviceState *dev, Error **errp);
86
+ * When reading with direct I/O from unallocated area on Gluster backed by XFS,
35
+} UfsBusClass;
87
+ * reading succeeds regardless of request length. In this case we fallback to
36
+
88
+ * safe alignment which is not optimal. Allocating the first block avoids this
37
+typedef struct UfsBus {
89
+ * fallback.
38
+ SCSIBus parent_bus;
90
+ *
39
+} UfsBus;
91
+ * fd may be opened with O_DIRECT, but we don't know the buffer alignment or
40
+
92
+ * request alignment, so we use safe values.
41
+#define TYPE_UFS_BUS "ufs-bus"
93
+ *
42
+DECLARE_OBJ_CHECKERS(UfsBus, UfsBusClass, UFS_BUS, TYPE_UFS_BUS)
94
+ * Returns: 0 on success, -errno on failure. Since this is an optimization,
43
+
95
+ * caller may ignore failures.
44
typedef enum UfsRequestState {
96
+ */
45
UFS_REQUEST_IDLE = 0,
97
+static int allocate_first_block(int fd, size_t max_size)
46
UFS_REQUEST_READY = 1,
98
+{
47
@@ -XXX,XX +XXX,XX @@ typedef enum UfsRequestState {
99
+ size_t write_size = (max_size < MAX_BLOCKSIZE)
48
typedef enum UfsReqResult {
100
+ ? BDRV_SECTOR_SIZE
49
UFS_REQUEST_SUCCESS = 0,
101
+ : MAX_BLOCKSIZE;
50
UFS_REQUEST_FAIL = 1,
102
+ size_t max_align = MAX(MAX_BLOCKSIZE, getpagesize());
51
+ UFS_REQUEST_NO_COMPLETE = 2,
103
+ void *buf;
52
} UfsReqResult;
104
+ ssize_t n;
53
105
+ int ret;
54
typedef struct UfsRequest {
106
+
55
@@ -XXX,XX +XXX,XX @@ typedef struct UfsRequest {
107
+ buf = qemu_memalign(max_align, write_size);
56
QEMUSGList *sg;
108
+ memset(buf, 0, write_size);
57
} UfsRequest;
109
+
58
110
+ do {
59
+typedef struct UfsLu {
111
+ n = pwrite(fd, buf, write_size, 0);
60
+ SCSIDevice qdev;
112
+ } while (n == -1 && errno == EINTR);
61
+ uint8_t lun;
113
+
62
+ UnitDescriptor unit_desc;
114
+ ret = (n == -1) ? -errno : 0;
63
+} UfsLu;
115
+
64
+
116
+ qemu_vfree(buf);
65
+typedef struct UfsWLu {
117
+ return ret;
66
+ SCSIDevice qdev;
118
+}
67
+ uint8_t lun;
119
+
68
+} UfsWLu;
120
static int handle_aiocb_truncate(void *opaque)
69
+
121
{
70
typedef struct UfsParams {
122
RawPosixAIOData *aiocb = opaque;
71
char *serial;
123
@@ -XXX,XX +XXX,XX @@ static int handle_aiocb_truncate(void *opaque)
72
uint8_t nutrs; /* Number of UTP Transfer Request Slots */
124
/* posix_fallocate() doesn't set errno. */
73
@@ -XXX,XX +XXX,XX @@ typedef struct UfsParams {
125
error_setg_errno(errp, -result,
74
126
"Could not preallocate new data");
75
typedef struct UfsHc {
127
+ } else if (current_length == 0) {
76
PCIDevice parent_obj;
128
+ /*
77
+ UfsBus bus;
129
+ * posix_fallocate() uses fallocate() if the filesystem
78
MemoryRegion iomem;
130
+ * supports it, or fallback to manually writing zeroes. If
79
UfsReg reg;
131
+ * fallocate() was used, unaligned reads from the fallocated
80
UfsParams params;
132
+ * area in raw_probe_alignment() will succeed, hence we need to
81
uint32_t reg_size;
133
+ * allocate the first block.
82
UfsRequest *req_list;
134
+ *
83
135
+ * Optimize future alignment probing; ignore failures.
84
+ UfsLu *lus[UFS_MAX_LUS];
136
+ */
85
+ UfsWLu *report_wlu;
137
+ allocate_first_block(fd, offset);
86
+ UfsWLu *dev_wlu;
138
}
87
+ UfsWLu *boot_wlu;
139
} else {
88
+ UfsWLu *rpmb_wlu;
140
result = 0;
89
DeviceDescriptor device_desc;
141
@@ -XXX,XX +XXX,XX @@ static int handle_aiocb_truncate(void *opaque)
90
GeometryDescriptor geometry_desc;
142
if (ftruncate(fd, offset) != 0) {
91
Attributes attributes;
143
result = -errno;
92
@@ -XXX,XX +XXX,XX @@ typedef struct UfsHc {
144
error_setg_errno(errp, -result, "Could not resize file");
93
#define TYPE_UFS "ufs"
145
+ } else if (current_length == 0 && offset > current_length) {
94
#define UFS(obj) OBJECT_CHECK(UfsHc, (obj), TYPE_UFS)
146
+ /* Optimize future alignment probing; ignore failures. */
95
147
+ allocate_first_block(fd, offset);
96
+#define TYPE_UFS_LU "ufs-lu"
148
}
97
+#define UFSLU(obj) OBJECT_CHECK(UfsLu, (obj), TYPE_UFS_LU)
149
return result;
98
+
150
default:
99
+#define TYPE_UFS_WLU "ufs-wlu"
151
diff --git a/tests/qemu-iotests/059.out b/tests/qemu-iotests/059.out
100
+#define UFSWLU(obj) OBJECT_CHECK(UfsWLu, (obj), TYPE_UFS_WLU)
101
+
102
typedef enum UfsQueryFlagPerm {
103
UFS_QUERY_FLAG_NONE = 0x0,
104
UFS_QUERY_FLAG_READ = 0x1,
105
@@ -XXX,XX +XXX,XX @@ typedef enum UfsQueryAttrPerm {
106
UFS_QUERY_ATTR_WRITE = 0x2,
107
} UfsQueryAttrPerm;
108
109
+static inline bool is_wlun(uint8_t lun)
110
+{
111
+ return (lun == UFS_UPIU_REPORT_LUNS_WLUN ||
112
+ lun == UFS_UPIU_UFS_DEVICE_WLUN || lun == UFS_UPIU_BOOT_WLUN ||
113
+ lun == UFS_UPIU_RPMB_WLUN);
114
+}
115
+
116
#endif /* HW_UFS_UFS_H */
117
diff --git a/include/scsi/constants.h b/include/scsi/constants.h
152
index XXXXXXX..XXXXXXX 100644
118
index XXXXXXX..XXXXXXX 100644
153
--- a/tests/qemu-iotests/059.out
119
--- a/include/scsi/constants.h
154
+++ b/tests/qemu-iotests/059.out
120
+++ b/include/scsi/constants.h
155
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824000 subformat=twoGbMax
121
@@ -XXX,XX +XXX,XX @@
156
image: TEST_DIR/t.vmdk
122
#define MODE_PAGE_FLEXIBLE_DISK_GEOMETRY 0x05
157
file format: vmdk
123
#define MODE_PAGE_CACHING 0x08
158
virtual size: 0.977 TiB (1073741824000 bytes)
124
#define MODE_PAGE_AUDIO_CTL 0x0e
159
-disk size: 16 KiB
125
+#define MODE_PAGE_CONTROL 0x0a
160
+disk size: 1.97 MiB
126
#define MODE_PAGE_POWER 0x1a
161
Format specific information:
127
#define MODE_PAGE_FAULT_FAIL 0x1c
162
cid: XXXXXXXX
128
#define MODE_PAGE_TO_PROTECT 0x1d
163
parent cid: XXXXXXXX
129
diff --git a/hw/ufs/lu.c b/hw/ufs/lu.c
164
diff --git a/tests/qemu-iotests/150.out b/tests/qemu-iotests/150.out.qcow2
165
similarity index 100%
166
rename from tests/qemu-iotests/150.out
167
rename to tests/qemu-iotests/150.out.qcow2
168
diff --git a/tests/qemu-iotests/150.out.raw b/tests/qemu-iotests/150.out.raw
169
new file mode 100644
130
new file mode 100644
170
index XXXXXXX..XXXXXXX
131
index XXXXXXX..XXXXXXX
171
--- /dev/null
132
--- /dev/null
172
+++ b/tests/qemu-iotests/150.out.raw
133
+++ b/hw/ufs/lu.c
173
@@ -XXX,XX +XXX,XX @@
134
@@ -XXX,XX +XXX,XX @@
174
+QA output created by 150
135
+/*
175
+
136
+ * QEMU UFS Logical Unit
176
+=== Mapping sparse conversion ===
137
+ *
177
+
138
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd. All rights reserved.
178
+Offset Length File
139
+ *
179
+0 0x1000 TEST_DIR/t.IMGFMT
140
+ * Written by Jeuk Kim <jeuk20.kim@samsung.com>
180
+
141
+ *
181
+=== Mapping non-sparse conversion ===
142
+ * This code is licensed under the GNU GPL v2 or later.
182
+
143
+ */
183
+Offset Length File
144
+
184
+0 0x100000 TEST_DIR/t.IMGFMT
145
+#include "qemu/osdep.h"
185
+*** done
146
+#include "qemu/units.h"
186
diff --git a/tests/qemu-iotests/175 b/tests/qemu-iotests/175
147
+#include "qapi/error.h"
187
index XXXXXXX..XXXXXXX 100755
148
+#include "qemu/memalign.h"
188
--- a/tests/qemu-iotests/175
149
+#include "hw/scsi/scsi.h"
189
+++ b/tests/qemu-iotests/175
150
+#include "scsi/constants.h"
190
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
151
+#include "sysemu/block-backend.h"
191
# the file size. This function hides the resulting difference in the
152
+#include "qemu/cutils.h"
192
# stat -c '%b' output.
153
+#include "trace.h"
193
# Parameter 1: Number of blocks an empty file occupies
154
+#include "ufs.h"
194
-# Parameter 2: Image size in bytes
155
+
195
+# Parameter 2: Minimal number of blocks in an image
156
+/*
196
+# Parameter 3: Image size in bytes
157
+ * The code below handling SCSI commands is copied from hw/scsi/scsi-disk.c,
197
_filter_blocks()
158
+ * with minor adjustments to make it work for UFS.
159
+ */
160
+
161
+#define SCSI_DMA_BUF_SIZE (128 * KiB)
162
+#define SCSI_MAX_INQUIRY_LEN 256
163
+#define SCSI_INQUIRY_DATA_SIZE 36
164
+#define SCSI_MAX_MODE_LEN 256
165
+
166
+typedef struct UfsSCSIReq {
167
+ SCSIRequest req;
168
+ /* Both sector and sector_count are in terms of BDRV_SECTOR_SIZE bytes. */
169
+ uint64_t sector;
170
+ uint32_t sector_count;
171
+ uint32_t buflen;
172
+ bool started;
173
+ bool need_fua_emulation;
174
+ struct iovec iov;
175
+ QEMUIOVector qiov;
176
+ BlockAcctCookie acct;
177
+} UfsSCSIReq;
178
+
179
+static void ufs_scsi_free_request(SCSIRequest *req)
180
+{
181
+ UfsSCSIReq *r = DO_UPCAST(UfsSCSIReq, req, req);
182
+
183
+ qemu_vfree(r->iov.iov_base);
184
+}
185
+
186
+static void scsi_check_condition(UfsSCSIReq *r, SCSISense sense)
187
+{
188
+ trace_ufs_scsi_check_condition(r->req.tag, sense.key, sense.asc,
189
+ sense.ascq);
190
+ scsi_req_build_sense(&r->req, sense);
191
+ scsi_req_complete(&r->req, CHECK_CONDITION);
192
+}
193
+
194
+static int ufs_scsi_emulate_vpd_page(SCSIRequest *req, uint8_t *outbuf,
195
+ uint32_t outbuf_len)
196
+{
197
+ UfsHc *u = UFS(req->bus->qbus.parent);
198
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, req->dev);
199
+ uint8_t page_code = req->cmd.buf[2];
200
+ int start, buflen = 0;
201
+
202
+ if (outbuf_len < SCSI_INQUIRY_DATA_SIZE) {
203
+ return -1;
204
+ }
205
+
206
+ outbuf[buflen++] = lu->qdev.type & 0x1f;
207
+ outbuf[buflen++] = page_code;
208
+ outbuf[buflen++] = 0x00;
209
+ outbuf[buflen++] = 0x00;
210
+ start = buflen;
211
+
212
+ switch (page_code) {
213
+ case 0x00: /* Supported page codes, mandatory */
214
+ {
215
+ trace_ufs_scsi_emulate_vpd_page_00(req->cmd.xfer);
216
+ outbuf[buflen++] = 0x00; /* list of supported pages (this page) */
217
+ if (u->params.serial) {
218
+ outbuf[buflen++] = 0x80; /* unit serial number */
219
+ }
220
+ outbuf[buflen++] = 0x87; /* mode page policy */
221
+ break;
222
+ }
223
+ case 0x80: /* Device serial number, optional */
224
+ {
225
+ int l;
226
+
227
+ if (!u->params.serial) {
228
+ trace_ufs_scsi_emulate_vpd_page_80_not_supported();
229
+ return -1;
230
+ }
231
+
232
+ l = strlen(u->params.serial);
233
+ if (l > SCSI_INQUIRY_DATA_SIZE) {
234
+ l = SCSI_INQUIRY_DATA_SIZE;
235
+ }
236
+
237
+ trace_ufs_scsi_emulate_vpd_page_80(req->cmd.xfer);
238
+ memcpy(outbuf + buflen, u->params.serial, l);
239
+ buflen += l;
240
+ break;
241
+ }
242
+ case 0x87: /* Mode Page Policy, mandatory */
243
+ {
244
+ trace_ufs_scsi_emulate_vpd_page_87(req->cmd.xfer);
245
+ outbuf[buflen++] = 0x3f; /* apply to all mode pages and subpages */
246
+ outbuf[buflen++] = 0xff;
247
+ outbuf[buflen++] = 0; /* shared */
248
+ outbuf[buflen++] = 0;
249
+ break;
250
+ }
251
+ default:
252
+ return -1;
253
+ }
254
+ /* done with EVPD */
255
+ assert(buflen - start <= 255);
256
+ outbuf[start - 1] = buflen - start;
257
+ return buflen;
258
+}
259
+
260
+static int ufs_scsi_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf,
261
+ uint32_t outbuf_len)
262
+{
263
+ int buflen = 0;
264
+
265
+ if (outbuf_len < SCSI_INQUIRY_DATA_SIZE) {
266
+ return -1;
267
+ }
268
+
269
+ if (req->cmd.buf[1] & 0x1) {
270
+ /* Vital product data */
271
+ return ufs_scsi_emulate_vpd_page(req, outbuf, outbuf_len);
272
+ }
273
+
274
+ /* Standard INQUIRY data */
275
+ if (req->cmd.buf[2] != 0) {
276
+ return -1;
277
+ }
278
+
279
+ /* PAGE CODE == 0 */
280
+ buflen = req->cmd.xfer;
281
+ if (buflen > SCSI_MAX_INQUIRY_LEN) {
282
+ buflen = SCSI_MAX_INQUIRY_LEN;
283
+ }
284
+
285
+ if (is_wlun(req->lun)) {
286
+ outbuf[0] = TYPE_WLUN;
287
+ } else {
288
+ outbuf[0] = 0;
289
+ }
290
+ outbuf[1] = 0;
291
+
292
+ strpadcpy((char *)&outbuf[16], 16, "QEMU UFS", ' ');
293
+ strpadcpy((char *)&outbuf[8], 8, "QEMU", ' ');
294
+
295
+ memset(&outbuf[32], 0, 4);
296
+
297
+ outbuf[2] = 0x06; /* SPC-4 */
298
+ outbuf[3] = 0x2;
299
+
300
+ if (buflen > SCSI_INQUIRY_DATA_SIZE) {
301
+ outbuf[4] = buflen - 5; /* Additional Length = (Len - 1) - 4 */
302
+ } else {
303
+ /*
304
+ * If the allocation length of CDB is too small, the additional
305
+ * length is not adjusted
306
+ */
307
+ outbuf[4] = SCSI_INQUIRY_DATA_SIZE - 5;
308
+ }
309
+
310
+ /* Support TCQ. */
311
+ outbuf[7] = req->bus->info->tcq ? 0x02 : 0;
312
+ return buflen;
313
+}
314
+
315
+static int mode_sense_page(UfsLu *lu, int page, uint8_t **p_outbuf,
316
+ int page_control)
317
+{
318
+ static const int mode_sense_valid[0x3f] = {
319
+ [MODE_PAGE_CACHING] = 1,
320
+ [MODE_PAGE_R_W_ERROR] = 1,
321
+ [MODE_PAGE_CONTROL] = 1,
322
+ };
323
+
324
+ uint8_t *p = *p_outbuf + 2;
325
+ int length;
326
+
327
+ assert(page < ARRAY_SIZE(mode_sense_valid));
328
+ if ((mode_sense_valid[page]) == 0) {
329
+ return -1;
330
+ }
331
+
332
+ /*
333
+ * If Changeable Values are requested, a mask denoting those mode parameters
334
+ * that are changeable shall be returned. As we currently don't support
335
+ * parameter changes via MODE_SELECT all bits are returned set to zero.
336
+ * The buffer was already memset to zero by the caller of this function.
337
+ */
338
+ switch (page) {
339
+ case MODE_PAGE_CACHING:
340
+ length = 0x12;
341
+ if (page_control == 1 || /* Changeable Values */
342
+ blk_enable_write_cache(lu->qdev.conf.blk)) {
343
+ p[0] = 4; /* WCE */
344
+ }
345
+ break;
346
+
347
+ case MODE_PAGE_R_W_ERROR:
348
+ length = 10;
349
+ if (page_control == 1) { /* Changeable Values */
350
+ break;
351
+ }
352
+ p[0] = 0x80; /* Automatic Write Reallocation Enabled */
353
+ break;
354
+
355
+ case MODE_PAGE_CONTROL:
356
+ length = 10;
357
+ if (page_control == 1) { /* Changeable Values */
358
+ break;
359
+ }
360
+ p[1] = 0x10; /* Queue Algorithm modifier */
361
+ p[8] = 0xff; /* Busy Timeout Period */
362
+ p[9] = 0xff;
363
+ break;
364
+
365
+ default:
366
+ return -1;
367
+ }
368
+
369
+ assert(length < 256);
370
+ (*p_outbuf)[0] = page;
371
+ (*p_outbuf)[1] = length;
372
+ *p_outbuf += length + 2;
373
+ return length + 2;
374
+}
375
+
376
+static int ufs_scsi_emulate_mode_sense(UfsSCSIReq *r, uint8_t *outbuf)
377
+{
378
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, r->req.dev);
379
+ bool dbd;
380
+ int page, buflen, ret, page_control;
381
+ uint8_t *p;
382
+ uint8_t dev_specific_param = 0;
383
+
384
+ dbd = (r->req.cmd.buf[1] & 0x8) != 0;
385
+ if (!dbd) {
386
+ return -1;
387
+ }
388
+
389
+ page = r->req.cmd.buf[2] & 0x3f;
390
+ page_control = (r->req.cmd.buf[2] & 0xc0) >> 6;
391
+
392
+ trace_ufs_scsi_emulate_mode_sense((r->req.cmd.buf[0] == MODE_SENSE) ? 6 :
393
+ 10,
394
+ page, r->req.cmd.xfer, page_control);
395
+ memset(outbuf, 0, r->req.cmd.xfer);
396
+ p = outbuf;
397
+
398
+ if (!blk_is_writable(lu->qdev.conf.blk)) {
399
+ dev_specific_param |= 0x80; /* Readonly. */
400
+ }
401
+
402
+ p[2] = 0; /* Medium type. */
403
+ p[3] = dev_specific_param;
404
+ p[6] = p[7] = 0; /* Block descriptor length. */
405
+ p += 8;
406
+
407
+ if (page_control == 3) {
408
+ /* Saved Values */
409
+ scsi_check_condition(r, SENSE_CODE(SAVING_PARAMS_NOT_SUPPORTED));
410
+ return -1;
411
+ }
412
+
413
+ if (page == 0x3f) {
414
+ for (page = 0; page <= 0x3e; page++) {
415
+ mode_sense_page(lu, page, &p, page_control);
416
+ }
417
+ } else {
418
+ ret = mode_sense_page(lu, page, &p, page_control);
419
+ if (ret == -1) {
420
+ return -1;
421
+ }
422
+ }
423
+
424
+ buflen = p - outbuf;
425
+ /*
426
+ * The mode data length field specifies the length in bytes of the
427
+ * following data that is available to be transferred. The mode data
428
+ * length does not include itself.
429
+ */
430
+ outbuf[0] = ((buflen - 2) >> 8) & 0xff;
431
+ outbuf[1] = (buflen - 2) & 0xff;
432
+ return buflen;
433
+}
434
+
435
+/*
436
+ * scsi_handle_rw_error has two return values. False means that the error
437
+ * must be ignored, true means that the error has been processed and the
438
+ * caller should not do anything else for this request. Note that
439
+ * scsi_handle_rw_error always manages its reference counts, independent
440
+ * of the return value.
441
+ */
442
+static bool scsi_handle_rw_error(UfsSCSIReq *r, int ret, bool acct_failed)
443
+{
444
+ bool is_read = (r->req.cmd.mode == SCSI_XFER_FROM_DEV);
445
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, r->req.dev);
446
+ SCSISense sense = SENSE_CODE(NO_SENSE);
447
+ int error = 0;
448
+ bool req_has_sense = false;
449
+ BlockErrorAction action;
450
+ int status;
451
+
452
+ if (ret < 0) {
453
+ status = scsi_sense_from_errno(-ret, &sense);
454
+ error = -ret;
455
+ } else {
456
+ /* A passthrough command has completed with nonzero status. */
457
+ status = ret;
458
+ if (status == CHECK_CONDITION) {
459
+ req_has_sense = true;
460
+ error = scsi_sense_buf_to_errno(r->req.sense, sizeof(r->req.sense));
461
+ } else {
462
+ error = EINVAL;
463
+ }
464
+ }
465
+
466
+ /*
467
+ * Check whether the error has to be handled by the guest or should
468
+ * rather follow the rerror=/werror= settings. Guest-handled errors
469
+ * are usually retried immediately, so do not post them to QMP and
470
+ * do not account them as failed I/O.
471
+ */
472
+ if (req_has_sense && scsi_sense_buf_is_guest_recoverable(
473
+ r->req.sense, sizeof(r->req.sense))) {
474
+ action = BLOCK_ERROR_ACTION_REPORT;
475
+ acct_failed = false;
476
+ } else {
477
+ action = blk_get_error_action(lu->qdev.conf.blk, is_read, error);
478
+ blk_error_action(lu->qdev.conf.blk, action, is_read, error);
479
+ }
480
+
481
+ switch (action) {
482
+ case BLOCK_ERROR_ACTION_REPORT:
483
+ if (acct_failed) {
484
+ block_acct_failed(blk_get_stats(lu->qdev.conf.blk), &r->acct);
485
+ }
486
+ if (!req_has_sense && status == CHECK_CONDITION) {
487
+ scsi_req_build_sense(&r->req, sense);
488
+ }
489
+ scsi_req_complete(&r->req, status);
490
+ return true;
491
+
492
+ case BLOCK_ERROR_ACTION_IGNORE:
493
+ return false;
494
+
495
+ case BLOCK_ERROR_ACTION_STOP:
496
+ scsi_req_retry(&r->req);
497
+ return true;
498
+
499
+ default:
500
+ g_assert_not_reached();
501
+ }
502
+}
503
+
504
+static bool ufs_scsi_req_check_error(UfsSCSIReq *r, int ret, bool acct_failed)
505
+{
506
+ if (r->req.io_canceled) {
507
+ scsi_req_cancel_complete(&r->req);
508
+ return true;
509
+ }
510
+
511
+ if (ret < 0) {
512
+ return scsi_handle_rw_error(r, ret, acct_failed);
513
+ }
514
+
515
+ return false;
516
+}
517
+
518
+static void scsi_aio_complete(void *opaque, int ret)
519
+{
520
+ UfsSCSIReq *r = (UfsSCSIReq *)opaque;
521
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, r->req.dev);
522
+
523
+ assert(r->req.aiocb != NULL);
524
+ r->req.aiocb = NULL;
525
+ aio_context_acquire(blk_get_aio_context(lu->qdev.conf.blk));
526
+ if (ufs_scsi_req_check_error(r, ret, true)) {
527
+ goto done;
528
+ }
529
+
530
+ block_acct_done(blk_get_stats(lu->qdev.conf.blk), &r->acct);
531
+ scsi_req_complete(&r->req, GOOD);
532
+
533
+done:
534
+ aio_context_release(blk_get_aio_context(lu->qdev.conf.blk));
535
+ scsi_req_unref(&r->req);
536
+}
537
+
538
+static int32_t ufs_scsi_emulate_command(SCSIRequest *req, uint8_t *buf)
539
+{
540
+ UfsSCSIReq *r = DO_UPCAST(UfsSCSIReq, req, req);
541
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, req->dev);
542
+ uint32_t last_block = 0;
543
+ uint8_t *outbuf;
544
+ int buflen;
545
+
546
+ switch (req->cmd.buf[0]) {
547
+ case INQUIRY:
548
+ case MODE_SENSE_10:
549
+ case START_STOP:
550
+ case REQUEST_SENSE:
551
+ break;
552
+
553
+ default:
554
+ if (!blk_is_available(lu->qdev.conf.blk)) {
555
+ scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
556
+ return 0;
557
+ }
558
+ break;
559
+ }
560
+
561
+ /*
562
+ * FIXME: we shouldn't return anything bigger than 4k, but the code
563
+ * requires the buffer to be as big as req->cmd.xfer in several
564
+ * places. So, do not allow CDBs with a very large ALLOCATION
565
+ * LENGTH. The real fix would be to modify scsi_read_data and
566
+ * dma_buf_read, so that they return data beyond the buflen
567
+ * as all zeros.
568
+ */
569
+ if (req->cmd.xfer > 65536) {
570
+ goto illegal_request;
571
+ }
572
+ r->buflen = MAX(4096, req->cmd.xfer);
573
+
574
+ if (!r->iov.iov_base) {
575
+ r->iov.iov_base = blk_blockalign(lu->qdev.conf.blk, r->buflen);
576
+ }
577
+
578
+ outbuf = r->iov.iov_base;
579
+ memset(outbuf, 0, r->buflen);
580
+ switch (req->cmd.buf[0]) {
581
+ case TEST_UNIT_READY:
582
+ assert(blk_is_available(lu->qdev.conf.blk));
583
+ break;
584
+ case INQUIRY:
585
+ buflen = ufs_scsi_emulate_inquiry(req, outbuf, r->buflen);
586
+ if (buflen < 0) {
587
+ goto illegal_request;
588
+ }
589
+ break;
590
+ case MODE_SENSE_10:
591
+ buflen = ufs_scsi_emulate_mode_sense(r, outbuf);
592
+ if (buflen < 0) {
593
+ goto illegal_request;
594
+ }
595
+ break;
596
+ case READ_CAPACITY_10:
597
+ /* The normal LEN field for this command is zero. */
598
+ memset(outbuf, 0, 8);
599
+ if (lu->qdev.max_lba > 0) {
600
+ last_block = lu->qdev.max_lba - 1;
601
+ };
602
+ outbuf[0] = (last_block >> 24) & 0xff;
603
+ outbuf[1] = (last_block >> 16) & 0xff;
604
+ outbuf[2] = (last_block >> 8) & 0xff;
605
+ outbuf[3] = last_block & 0xff;
606
+ outbuf[4] = (lu->qdev.blocksize >> 24) & 0xff;
607
+ outbuf[5] = (lu->qdev.blocksize >> 16) & 0xff;
608
+ outbuf[6] = (lu->qdev.blocksize >> 8) & 0xff;
609
+ outbuf[7] = lu->qdev.blocksize & 0xff;
610
+ break;
611
+ case REQUEST_SENSE:
612
+ /* Just return "NO SENSE". */
613
+ buflen = scsi_convert_sense(NULL, 0, outbuf, r->buflen,
614
+ (req->cmd.buf[1] & 1) == 0);
615
+ if (buflen < 0) {
616
+ goto illegal_request;
617
+ }
618
+ break;
619
+ case SYNCHRONIZE_CACHE:
620
+ /* The request is used as the AIO opaque value, so add a ref. */
621
+ scsi_req_ref(&r->req);
622
+ block_acct_start(blk_get_stats(lu->qdev.conf.blk), &r->acct, 0,
623
+ BLOCK_ACCT_FLUSH);
624
+ r->req.aiocb = blk_aio_flush(lu->qdev.conf.blk, scsi_aio_complete, r);
625
+ return 0;
626
+ case VERIFY_10:
627
+ trace_ufs_scsi_emulate_command_VERIFY((req->cmd.buf[1] >> 1) & 3);
628
+ if (req->cmd.buf[1] & 6) {
629
+ goto illegal_request;
630
+ }
631
+ break;
632
+ case SERVICE_ACTION_IN_16:
633
+ /* Service Action In subcommands. */
634
+ if ((req->cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) {
635
+ trace_ufs_scsi_emulate_command_SAI_16();
636
+ memset(outbuf, 0, req->cmd.xfer);
637
+
638
+ if (lu->qdev.max_lba > 0) {
639
+ last_block = lu->qdev.max_lba - 1;
640
+ };
641
+ outbuf[0] = 0;
642
+ outbuf[1] = 0;
643
+ outbuf[2] = 0;
644
+ outbuf[3] = 0;
645
+ outbuf[4] = (last_block >> 24) & 0xff;
646
+ outbuf[5] = (last_block >> 16) & 0xff;
647
+ outbuf[6] = (last_block >> 8) & 0xff;
648
+ outbuf[7] = last_block & 0xff;
649
+ outbuf[8] = (lu->qdev.blocksize >> 24) & 0xff;
650
+ outbuf[9] = (lu->qdev.blocksize >> 16) & 0xff;
651
+ outbuf[10] = (lu->qdev.blocksize >> 8) & 0xff;
652
+ outbuf[11] = lu->qdev.blocksize & 0xff;
653
+ outbuf[12] = 0;
654
+ outbuf[13] = get_physical_block_exp(&lu->qdev.conf);
655
+
656
+ if (lu->unit_desc.provisioning_type == 2 ||
657
+ lu->unit_desc.provisioning_type == 3) {
658
+ outbuf[14] = 0x80;
659
+ }
660
+ /* Protection, exponent and lowest lba field left blank. */
661
+ break;
662
+ }
663
+ trace_ufs_scsi_emulate_command_SAI_unsupported();
664
+ goto illegal_request;
665
+ case MODE_SELECT_10:
666
+ trace_ufs_scsi_emulate_command_MODE_SELECT_10(r->req.cmd.xfer);
667
+ break;
668
+ case START_STOP:
669
+ /*
670
+ * TODO: START_STOP is not yet implemented. It always returns success.
671
+ * Revisit it when ufs power management is implemented.
672
+ */
673
+ trace_ufs_scsi_emulate_command_START_STOP();
674
+ break;
675
+ case FORMAT_UNIT:
676
+ trace_ufs_scsi_emulate_command_FORMAT_UNIT();
677
+ break;
678
+ case SEND_DIAGNOSTIC:
679
+ trace_ufs_scsi_emulate_command_SEND_DIAGNOSTIC();
680
+ break;
681
+ default:
682
+ trace_ufs_scsi_emulate_command_UNKNOWN(buf[0],
683
+ scsi_command_name(buf[0]));
684
+ scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
685
+ return 0;
686
+ }
687
+ assert(!r->req.aiocb);
688
+ r->iov.iov_len = MIN(r->buflen, req->cmd.xfer);
689
+ if (r->iov.iov_len == 0) {
690
+ scsi_req_complete(&r->req, GOOD);
691
+ }
692
+ if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
693
+ assert(r->iov.iov_len == req->cmd.xfer);
694
+ return -r->iov.iov_len;
695
+ } else {
696
+ return r->iov.iov_len;
697
+ }
698
+
699
+illegal_request:
700
+ if (r->req.status == -1) {
701
+ scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
702
+ }
703
+ return 0;
704
+}
705
+
706
+static void ufs_scsi_emulate_read_data(SCSIRequest *req)
707
+{
708
+ UfsSCSIReq *r = DO_UPCAST(UfsSCSIReq, req, req);
709
+ int buflen = r->iov.iov_len;
710
+
711
+ if (buflen) {
712
+ trace_ufs_scsi_emulate_read_data(buflen);
713
+ r->iov.iov_len = 0;
714
+ r->started = true;
715
+ scsi_req_data(&r->req, buflen);
716
+ return;
717
+ }
718
+
719
+ /* This also clears the sense buffer for REQUEST SENSE. */
720
+ scsi_req_complete(&r->req, GOOD);
721
+}
722
+
723
+static int ufs_scsi_check_mode_select(UfsLu *lu, int page, uint8_t *inbuf,
724
+ int inlen)
725
+{
726
+ uint8_t mode_current[SCSI_MAX_MODE_LEN];
727
+ uint8_t mode_changeable[SCSI_MAX_MODE_LEN];
728
+ uint8_t *p;
729
+ int len, expected_len, changeable_len, i;
730
+
731
+ /*
732
+ * The input buffer does not include the page header, so it is
733
+ * off by 2 bytes.
734
+ */
735
+ expected_len = inlen + 2;
736
+ if (expected_len > SCSI_MAX_MODE_LEN) {
737
+ return -1;
738
+ }
739
+
740
+ /* MODE_PAGE_ALLS is only valid for MODE SENSE commands */
741
+ if (page == MODE_PAGE_ALLS) {
742
+ return -1;
743
+ }
744
+
745
+ p = mode_current;
746
+ memset(mode_current, 0, inlen + 2);
747
+ len = mode_sense_page(lu, page, &p, 0);
748
+ if (len < 0 || len != expected_len) {
749
+ return -1;
750
+ }
751
+
752
+ p = mode_changeable;
753
+ memset(mode_changeable, 0, inlen + 2);
754
+ changeable_len = mode_sense_page(lu, page, &p, 1);
755
+ assert(changeable_len == len);
756
+
757
+ /*
758
+ * Check that unchangeable bits are the same as what MODE SENSE
759
+ * would return.
760
+ */
761
+ for (i = 2; i < len; i++) {
762
+ if (((mode_current[i] ^ inbuf[i - 2]) & ~mode_changeable[i]) != 0) {
763
+ return -1;
764
+ }
765
+ }
766
+ return 0;
767
+}
768
+
769
+static void ufs_scsi_apply_mode_select(UfsLu *lu, int page, uint8_t *p)
770
+{
771
+ switch (page) {
772
+ case MODE_PAGE_CACHING:
773
+ blk_set_enable_write_cache(lu->qdev.conf.blk, (p[0] & 4) != 0);
774
+ break;
775
+
776
+ default:
777
+ break;
778
+ }
779
+}
780
+
781
+static int mode_select_pages(UfsSCSIReq *r, uint8_t *p, int len, bool change)
782
+{
783
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, r->req.dev);
784
+
785
+ while (len > 0) {
786
+ int page, page_len;
787
+
788
+ page = p[0] & 0x3f;
789
+ if (p[0] & 0x40) {
790
+ goto invalid_param;
791
+ } else {
792
+ if (len < 2) {
793
+ goto invalid_param_len;
794
+ }
795
+ page_len = p[1];
796
+ p += 2;
797
+ len -= 2;
798
+ }
799
+
800
+ if (page_len > len) {
801
+ goto invalid_param_len;
802
+ }
803
+
804
+ if (!change) {
805
+ if (ufs_scsi_check_mode_select(lu, page, p, page_len) < 0) {
806
+ goto invalid_param;
807
+ }
808
+ } else {
809
+ ufs_scsi_apply_mode_select(lu, page, p);
810
+ }
811
+
812
+ p += page_len;
813
+ len -= page_len;
814
+ }
815
+ return 0;
816
+
817
+invalid_param:
818
+ scsi_check_condition(r, SENSE_CODE(INVALID_PARAM));
819
+ return -1;
820
+
821
+invalid_param_len:
822
+ scsi_check_condition(r, SENSE_CODE(INVALID_PARAM_LEN));
823
+ return -1;
824
+}
825
+
826
+static void ufs_scsi_emulate_mode_select(UfsSCSIReq *r, uint8_t *inbuf)
827
+{
828
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, r->req.dev);
829
+ uint8_t *p = inbuf;
830
+ int len = r->req.cmd.xfer;
831
+ int hdr_len = 8;
832
+ int bd_len;
833
+ int pass;
834
+
835
+ /* We only support PF=1, SP=0. */
836
+ if ((r->req.cmd.buf[1] & 0x11) != 0x10) {
837
+ goto invalid_field;
838
+ }
839
+
840
+ if (len < hdr_len) {
841
+ goto invalid_param_len;
842
+ }
843
+
844
+ bd_len = lduw_be_p(&p[6]);
845
+ if (bd_len != 0) {
846
+ goto invalid_param;
847
+ }
848
+
849
+ len -= hdr_len;
850
+ p += hdr_len;
851
+
852
+ /* Ensure no change is made if there is an error! */
853
+ for (pass = 0; pass < 2; pass++) {
854
+ if (mode_select_pages(r, p, len, pass == 1) < 0) {
855
+ assert(pass == 0);
856
+ return;
857
+ }
858
+ }
859
+
860
+ if (!blk_enable_write_cache(lu->qdev.conf.blk)) {
861
+ /* The request is used as the AIO opaque value, so add a ref. */
862
+ scsi_req_ref(&r->req);
863
+ block_acct_start(blk_get_stats(lu->qdev.conf.blk), &r->acct, 0,
864
+ BLOCK_ACCT_FLUSH);
865
+ r->req.aiocb = blk_aio_flush(lu->qdev.conf.blk, scsi_aio_complete, r);
866
+ return;
867
+ }
868
+
869
+ scsi_req_complete(&r->req, GOOD);
870
+ return;
871
+
872
+invalid_param:
873
+ scsi_check_condition(r, SENSE_CODE(INVALID_PARAM));
874
+ return;
875
+
876
+invalid_param_len:
877
+ scsi_check_condition(r, SENSE_CODE(INVALID_PARAM_LEN));
878
+ return;
879
+
880
+invalid_field:
881
+ scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
882
+}
883
+
884
+/* block_num and nb_blocks expected to be in qdev blocksize */
885
+static inline bool check_lba_range(UfsLu *lu, uint64_t block_num,
886
+ uint32_t nb_blocks)
887
+{
888
+ /*
889
+ * The first line tests that no overflow happens when computing the last
890
+ * block. The second line tests that the last accessed block is in
891
+ * range.
892
+ *
893
+ * Careful, the computations should not underflow for nb_blocks == 0,
894
+ * and a 0-block read to the first LBA beyond the end of device is
895
+ * valid.
896
+ */
897
+ return (block_num <= block_num + nb_blocks &&
898
+ block_num + nb_blocks <= lu->qdev.max_lba + 1);
899
+}
900
+
901
+static void ufs_scsi_emulate_write_data(SCSIRequest *req)
902
+{
903
+ UfsSCSIReq *r = DO_UPCAST(UfsSCSIReq, req, req);
904
+
905
+ if (r->iov.iov_len) {
906
+ int buflen = r->iov.iov_len;
907
+ trace_ufs_scsi_emulate_write_data(buflen);
908
+ r->iov.iov_len = 0;
909
+ scsi_req_data(&r->req, buflen);
910
+ return;
911
+ }
912
+
913
+ switch (req->cmd.buf[0]) {
914
+ case MODE_SELECT_10:
915
+ /* This also clears the sense buffer for REQUEST SENSE. */
916
+ ufs_scsi_emulate_mode_select(r, r->iov.iov_base);
917
+ break;
918
+ default:
919
+ abort();
920
+ }
921
+}
922
+
923
+/* Return a pointer to the data buffer. */
924
+static uint8_t *ufs_scsi_get_buf(SCSIRequest *req)
925
+{
926
+ UfsSCSIReq *r = DO_UPCAST(UfsSCSIReq, req, req);
927
+
928
+ return (uint8_t *)r->iov.iov_base;
929
+}
930
+
931
+static int32_t ufs_scsi_dma_command(SCSIRequest *req, uint8_t *buf)
932
+{
933
+ UfsSCSIReq *r = DO_UPCAST(UfsSCSIReq, req, req);
934
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, req->dev);
935
+ uint32_t len;
936
+ uint8_t command;
937
+
938
+ command = buf[0];
939
+
940
+ if (!blk_is_available(lu->qdev.conf.blk)) {
941
+ scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
942
+ return 0;
943
+ }
944
+
945
+ len = scsi_data_cdb_xfer(r->req.cmd.buf);
946
+ switch (command) {
947
+ case READ_6:
948
+ case READ_10:
949
+ trace_ufs_scsi_dma_command_READ(r->req.cmd.lba, len);
950
+ if (r->req.cmd.buf[1] & 0xe0) {
951
+ goto illegal_request;
952
+ }
953
+ if (!check_lba_range(lu, r->req.cmd.lba, len)) {
954
+ goto illegal_lba;
955
+ }
956
+ r->sector = r->req.cmd.lba * (lu->qdev.blocksize / BDRV_SECTOR_SIZE);
957
+ r->sector_count = len * (lu->qdev.blocksize / BDRV_SECTOR_SIZE);
958
+ break;
959
+ case WRITE_6:
960
+ case WRITE_10:
961
+ trace_ufs_scsi_dma_command_WRITE(r->req.cmd.lba, len);
962
+ if (!blk_is_writable(lu->qdev.conf.blk)) {
963
+ scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED));
964
+ return 0;
965
+ }
966
+ if (r->req.cmd.buf[1] & 0xe0) {
967
+ goto illegal_request;
968
+ }
969
+ if (!check_lba_range(lu, r->req.cmd.lba, len)) {
970
+ goto illegal_lba;
971
+ }
972
+ r->sector = r->req.cmd.lba * (lu->qdev.blocksize / BDRV_SECTOR_SIZE);
973
+ r->sector_count = len * (lu->qdev.blocksize / BDRV_SECTOR_SIZE);
974
+ break;
975
+ default:
976
+ abort();
977
+ illegal_request:
978
+ scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
979
+ return 0;
980
+ illegal_lba:
981
+ scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
982
+ return 0;
983
+ }
984
+ r->need_fua_emulation = ((r->req.cmd.buf[1] & 8) != 0);
985
+ if (r->sector_count == 0) {
986
+ scsi_req_complete(&r->req, GOOD);
987
+ }
988
+ assert(r->iov.iov_len == 0);
989
+ if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
990
+ return -r->sector_count * BDRV_SECTOR_SIZE;
991
+ } else {
992
+ return r->sector_count * BDRV_SECTOR_SIZE;
993
+ }
994
+}
995
+
996
+static void scsi_write_do_fua(UfsSCSIReq *r)
997
+{
998
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, r->req.dev);
999
+
1000
+ assert(r->req.aiocb == NULL);
1001
+ assert(!r->req.io_canceled);
1002
+
1003
+ if (r->need_fua_emulation) {
1004
+ block_acct_start(blk_get_stats(lu->qdev.conf.blk), &r->acct, 0,
1005
+ BLOCK_ACCT_FLUSH);
1006
+ r->req.aiocb = blk_aio_flush(lu->qdev.conf.blk, scsi_aio_complete, r);
1007
+ return;
1008
+ }
1009
+
1010
+ scsi_req_complete(&r->req, GOOD);
1011
+ scsi_req_unref(&r->req);
1012
+}
1013
+
1014
+static void scsi_dma_complete_noio(UfsSCSIReq *r, int ret)
1015
+{
1016
+ assert(r->req.aiocb == NULL);
1017
+ if (ufs_scsi_req_check_error(r, ret, false)) {
1018
+ goto done;
1019
+ }
1020
+
1021
+ r->sector += r->sector_count;
1022
+ r->sector_count = 0;
1023
+ if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
1024
+ scsi_write_do_fua(r);
1025
+ return;
1026
+ } else {
1027
+ scsi_req_complete(&r->req, GOOD);
1028
+ }
1029
+
1030
+done:
1031
+ scsi_req_unref(&r->req);
1032
+}
1033
+
1034
+static void scsi_dma_complete(void *opaque, int ret)
1035
+{
1036
+ UfsSCSIReq *r = (UfsSCSIReq *)opaque;
1037
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, r->req.dev);
1038
+
1039
+ assert(r->req.aiocb != NULL);
1040
+ r->req.aiocb = NULL;
1041
+
1042
+ aio_context_acquire(blk_get_aio_context(lu->qdev.conf.blk));
1043
+ if (ret < 0) {
1044
+ block_acct_failed(blk_get_stats(lu->qdev.conf.blk), &r->acct);
1045
+ } else {
1046
+ block_acct_done(blk_get_stats(lu->qdev.conf.blk), &r->acct);
1047
+ }
1048
+ scsi_dma_complete_noio(r, ret);
1049
+ aio_context_release(blk_get_aio_context(lu->qdev.conf.blk));
1050
+}
1051
+
1052
+static BlockAIOCB *scsi_dma_readv(int64_t offset, QEMUIOVector *iov,
1053
+ BlockCompletionFunc *cb, void *cb_opaque,
1054
+ void *opaque)
1055
+{
1056
+ UfsSCSIReq *r = opaque;
1057
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, r->req.dev);
1058
+ return blk_aio_preadv(lu->qdev.conf.blk, offset, iov, 0, cb, cb_opaque);
1059
+}
1060
+
1061
+static void scsi_init_iovec(UfsSCSIReq *r, size_t size)
1062
+{
1063
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, r->req.dev);
1064
+
1065
+ if (!r->iov.iov_base) {
1066
+ r->buflen = size;
1067
+ r->iov.iov_base = blk_blockalign(lu->qdev.conf.blk, r->buflen);
1068
+ }
1069
+ r->iov.iov_len = MIN(r->sector_count * BDRV_SECTOR_SIZE, r->buflen);
1070
+ qemu_iovec_init_external(&r->qiov, &r->iov, 1);
1071
+}
1072
+
1073
+static void scsi_read_complete_noio(UfsSCSIReq *r, int ret)
1074
+{
1075
+ uint32_t n;
1076
+
1077
+ assert(r->req.aiocb == NULL);
1078
+ if (ufs_scsi_req_check_error(r, ret, false)) {
1079
+ goto done;
1080
+ }
1081
+
1082
+ n = r->qiov.size / BDRV_SECTOR_SIZE;
1083
+ r->sector += n;
1084
+ r->sector_count -= n;
1085
+ scsi_req_data(&r->req, r->qiov.size);
1086
+
1087
+done:
1088
+ scsi_req_unref(&r->req);
1089
+}
1090
+
1091
+static void scsi_read_complete(void *opaque, int ret)
1092
+{
1093
+ UfsSCSIReq *r = (UfsSCSIReq *)opaque;
1094
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, r->req.dev);
1095
+
1096
+ assert(r->req.aiocb != NULL);
1097
+ r->req.aiocb = NULL;
1098
+ trace_ufs_scsi_read_data_count(r->sector_count);
1099
+ aio_context_acquire(blk_get_aio_context(lu->qdev.conf.blk));
1100
+ if (ret < 0) {
1101
+ block_acct_failed(blk_get_stats(lu->qdev.conf.blk), &r->acct);
1102
+ } else {
1103
+ block_acct_done(blk_get_stats(lu->qdev.conf.blk), &r->acct);
1104
+ trace_ufs_scsi_read_complete(r->req.tag, r->qiov.size);
1105
+ }
1106
+ scsi_read_complete_noio(r, ret);
1107
+ aio_context_release(blk_get_aio_context(lu->qdev.conf.blk));
1108
+}
1109
+
1110
+/* Actually issue a read to the block device. */
1111
+static void scsi_do_read(UfsSCSIReq *r, int ret)
1112
+{
1113
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, r->req.dev);
1114
+
1115
+ assert(r->req.aiocb == NULL);
1116
+ if (ufs_scsi_req_check_error(r, ret, false)) {
1117
+ goto done;
1118
+ }
1119
+
1120
+ /* The request is used as the AIO opaque value, so add a ref. */
1121
+ scsi_req_ref(&r->req);
1122
+
1123
+ if (r->req.sg) {
1124
+ dma_acct_start(lu->qdev.conf.blk, &r->acct, r->req.sg, BLOCK_ACCT_READ);
1125
+ r->req.residual -= r->req.sg->size;
1126
+ r->req.aiocb = dma_blk_io(
1127
+ blk_get_aio_context(lu->qdev.conf.blk), r->req.sg,
1128
+ r->sector << BDRV_SECTOR_BITS, BDRV_SECTOR_SIZE, scsi_dma_readv, r,
1129
+ scsi_dma_complete, r, DMA_DIRECTION_FROM_DEVICE);
1130
+ } else {
1131
+ scsi_init_iovec(r, SCSI_DMA_BUF_SIZE);
1132
+ block_acct_start(blk_get_stats(lu->qdev.conf.blk), &r->acct,
1133
+ r->qiov.size, BLOCK_ACCT_READ);
1134
+ r->req.aiocb = scsi_dma_readv(r->sector << BDRV_SECTOR_BITS, &r->qiov,
1135
+ scsi_read_complete, r, r);
1136
+ }
1137
+
1138
+done:
1139
+ scsi_req_unref(&r->req);
1140
+}
1141
+
1142
+static void scsi_do_read_cb(void *opaque, int ret)
1143
+{
1144
+ UfsSCSIReq *r = (UfsSCSIReq *)opaque;
1145
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, r->req.dev);
1146
+
1147
+ assert(r->req.aiocb != NULL);
1148
+ r->req.aiocb = NULL;
1149
+
1150
+ aio_context_acquire(blk_get_aio_context(lu->qdev.conf.blk));
1151
+ if (ret < 0) {
1152
+ block_acct_failed(blk_get_stats(lu->qdev.conf.blk), &r->acct);
1153
+ } else {
1154
+ block_acct_done(blk_get_stats(lu->qdev.conf.blk), &r->acct);
1155
+ }
1156
+ scsi_do_read(opaque, ret);
1157
+ aio_context_release(blk_get_aio_context(lu->qdev.conf.blk));
1158
+}
1159
+
1160
+/* Read more data from scsi device into buffer. */
1161
+static void scsi_read_data(SCSIRequest *req)
1162
+{
1163
+ UfsSCSIReq *r = DO_UPCAST(UfsSCSIReq, req, req);
1164
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, r->req.dev);
1165
+ bool first;
1166
+
1167
+ trace_ufs_scsi_read_data_count(r->sector_count);
1168
+ if (r->sector_count == 0) {
1169
+ /* This also clears the sense buffer for REQUEST SENSE. */
1170
+ scsi_req_complete(&r->req, GOOD);
1171
+ return;
1172
+ }
1173
+
1174
+ /* No data transfer may already be in progress */
1175
+ assert(r->req.aiocb == NULL);
1176
+
1177
+ /* The request is used as the AIO opaque value, so add a ref. */
1178
+ scsi_req_ref(&r->req);
1179
+ if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
1180
+ trace_ufs_scsi_read_data_invalid();
1181
+ scsi_read_complete_noio(r, -EINVAL);
1182
+ return;
1183
+ }
1184
+
1185
+ if (!blk_is_available(req->dev->conf.blk)) {
1186
+ scsi_read_complete_noio(r, -ENOMEDIUM);
1187
+ return;
1188
+ }
1189
+
1190
+ first = !r->started;
1191
+ r->started = true;
1192
+ if (first && r->need_fua_emulation) {
1193
+ block_acct_start(blk_get_stats(lu->qdev.conf.blk), &r->acct, 0,
1194
+ BLOCK_ACCT_FLUSH);
1195
+ r->req.aiocb = blk_aio_flush(lu->qdev.conf.blk, scsi_do_read_cb, r);
1196
+ } else {
1197
+ scsi_do_read(r, 0);
1198
+ }
1199
+}
1200
+
1201
+static void scsi_write_complete_noio(UfsSCSIReq *r, int ret)
1202
+{
1203
+ uint32_t n;
1204
+
1205
+ assert(r->req.aiocb == NULL);
1206
+ if (ufs_scsi_req_check_error(r, ret, false)) {
1207
+ goto done;
1208
+ }
1209
+
1210
+ n = r->qiov.size / BDRV_SECTOR_SIZE;
1211
+ r->sector += n;
1212
+ r->sector_count -= n;
1213
+ if (r->sector_count == 0) {
1214
+ scsi_write_do_fua(r);
1215
+ return;
1216
+ } else {
1217
+ scsi_init_iovec(r, SCSI_DMA_BUF_SIZE);
1218
+ trace_ufs_scsi_write_complete_noio(r->req.tag, r->qiov.size);
1219
+ scsi_req_data(&r->req, r->qiov.size);
1220
+ }
1221
+
1222
+done:
1223
+ scsi_req_unref(&r->req);
1224
+}
1225
+
1226
+static void scsi_write_complete(void *opaque, int ret)
1227
+{
1228
+ UfsSCSIReq *r = (UfsSCSIReq *)opaque;
1229
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, r->req.dev);
1230
+
1231
+ assert(r->req.aiocb != NULL);
1232
+ r->req.aiocb = NULL;
1233
+
1234
+ aio_context_acquire(blk_get_aio_context(lu->qdev.conf.blk));
1235
+ if (ret < 0) {
1236
+ block_acct_failed(blk_get_stats(lu->qdev.conf.blk), &r->acct);
1237
+ } else {
1238
+ block_acct_done(blk_get_stats(lu->qdev.conf.blk), &r->acct);
1239
+ }
1240
+ scsi_write_complete_noio(r, ret);
1241
+ aio_context_release(blk_get_aio_context(lu->qdev.conf.blk));
1242
+}
1243
+
1244
+static BlockAIOCB *scsi_dma_writev(int64_t offset, QEMUIOVector *iov,
1245
+ BlockCompletionFunc *cb, void *cb_opaque,
1246
+ void *opaque)
1247
+{
1248
+ UfsSCSIReq *r = opaque;
1249
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, r->req.dev);
1250
+ return blk_aio_pwritev(lu->qdev.conf.blk, offset, iov, 0, cb, cb_opaque);
1251
+}
1252
+
1253
+static void scsi_write_data(SCSIRequest *req)
1254
+{
1255
+ UfsSCSIReq *r = DO_UPCAST(UfsSCSIReq, req, req);
1256
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, r->req.dev);
1257
+
1258
+ /* No data transfer may already be in progress */
1259
+ assert(r->req.aiocb == NULL);
1260
+
1261
+ /* The request is used as the AIO opaque value, so add a ref. */
1262
+ scsi_req_ref(&r->req);
1263
+ if (r->req.cmd.mode != SCSI_XFER_TO_DEV) {
1264
+ trace_ufs_scsi_write_data_invalid();
1265
+ scsi_write_complete_noio(r, -EINVAL);
1266
+ return;
1267
+ }
1268
+
1269
+ if (!r->req.sg && !r->qiov.size) {
1270
+ /* Called for the first time. Ask the driver to send us more data. */
1271
+ r->started = true;
1272
+ scsi_write_complete_noio(r, 0);
1273
+ return;
1274
+ }
1275
+ if (!blk_is_available(req->dev->conf.blk)) {
1276
+ scsi_write_complete_noio(r, -ENOMEDIUM);
1277
+ return;
1278
+ }
1279
+
1280
+ if (r->req.sg) {
1281
+ dma_acct_start(lu->qdev.conf.blk, &r->acct, r->req.sg,
1282
+ BLOCK_ACCT_WRITE);
1283
+ r->req.residual -= r->req.sg->size;
1284
+ r->req.aiocb = dma_blk_io(
1285
+ blk_get_aio_context(lu->qdev.conf.blk), r->req.sg,
1286
+ r->sector << BDRV_SECTOR_BITS, BDRV_SECTOR_SIZE, scsi_dma_writev, r,
1287
+ scsi_dma_complete, r, DMA_DIRECTION_TO_DEVICE);
1288
+ } else {
1289
+ block_acct_start(blk_get_stats(lu->qdev.conf.blk), &r->acct,
1290
+ r->qiov.size, BLOCK_ACCT_WRITE);
1291
+ r->req.aiocb = scsi_dma_writev(r->sector << BDRV_SECTOR_BITS, &r->qiov,
1292
+ scsi_write_complete, r, r);
1293
+ }
1294
+}
1295
+
1296
+static const SCSIReqOps ufs_scsi_emulate_reqops = {
1297
+ .size = sizeof(UfsSCSIReq),
1298
+ .free_req = ufs_scsi_free_request,
1299
+ .send_command = ufs_scsi_emulate_command,
1300
+ .read_data = ufs_scsi_emulate_read_data,
1301
+ .write_data = ufs_scsi_emulate_write_data,
1302
+ .get_buf = ufs_scsi_get_buf,
1303
+};
1304
+
1305
+static const SCSIReqOps ufs_scsi_dma_reqops = {
1306
+ .size = sizeof(UfsSCSIReq),
1307
+ .free_req = ufs_scsi_free_request,
1308
+ .send_command = ufs_scsi_dma_command,
1309
+ .read_data = scsi_read_data,
1310
+ .write_data = scsi_write_data,
1311
+ .get_buf = ufs_scsi_get_buf,
1312
+};
1313
+
1314
+/*
1315
+ * Following commands are not yet supported
1316
+ * PRE_FETCH(10),
1317
+ * UNMAP,
1318
+ * WRITE_BUFFER, READ_BUFFER,
1319
+ * SECURITY_PROTOCOL_IN, SECURITY_PROTOCOL_OUT
1320
+ */
1321
+static const SCSIReqOps *const ufs_scsi_reqops_dispatch[256] = {
1322
+ [TEST_UNIT_READY] = &ufs_scsi_emulate_reqops,
1323
+ [INQUIRY] = &ufs_scsi_emulate_reqops,
1324
+ [MODE_SENSE_10] = &ufs_scsi_emulate_reqops,
1325
+ [START_STOP] = &ufs_scsi_emulate_reqops,
1326
+ [READ_CAPACITY_10] = &ufs_scsi_emulate_reqops,
1327
+ [REQUEST_SENSE] = &ufs_scsi_emulate_reqops,
1328
+ [SYNCHRONIZE_CACHE] = &ufs_scsi_emulate_reqops,
1329
+ [MODE_SELECT_10] = &ufs_scsi_emulate_reqops,
1330
+ [VERIFY_10] = &ufs_scsi_emulate_reqops,
1331
+ [FORMAT_UNIT] = &ufs_scsi_emulate_reqops,
1332
+ [SERVICE_ACTION_IN_16] = &ufs_scsi_emulate_reqops,
1333
+ [SEND_DIAGNOSTIC] = &ufs_scsi_emulate_reqops,
1334
+
1335
+ [READ_6] = &ufs_scsi_dma_reqops,
1336
+ [READ_10] = &ufs_scsi_dma_reqops,
1337
+ [WRITE_6] = &ufs_scsi_dma_reqops,
1338
+ [WRITE_10] = &ufs_scsi_dma_reqops,
1339
+};
1340
+
1341
+static SCSIRequest *scsi_new_request(SCSIDevice *dev, uint32_t tag,
1342
+ uint32_t lun, uint8_t *buf,
1343
+ void *hba_private)
1344
+{
1345
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, dev);
1346
+ SCSIRequest *req;
1347
+ const SCSIReqOps *ops;
1348
+ uint8_t command;
1349
+
1350
+ command = buf[0];
1351
+ ops = ufs_scsi_reqops_dispatch[command];
1352
+ if (!ops) {
1353
+ ops = &ufs_scsi_emulate_reqops;
1354
+ }
1355
+ req = scsi_req_alloc(ops, &lu->qdev, tag, lun, hba_private);
1356
+
1357
+ return req;
1358
+}
1359
+
1360
+static Property ufs_lu_props[] = {
1361
+ DEFINE_PROP_DRIVE("drive", UfsLu, qdev.conf.blk),
1362
+ DEFINE_PROP_END_OF_LIST(),
1363
+};
1364
+
1365
+static bool ufs_lu_brdv_init(UfsLu *lu, Error **errp)
1366
+{
1367
+ SCSIDevice *dev = &lu->qdev;
1368
+ bool read_only;
1369
+
1370
+ if (!lu->qdev.conf.blk) {
1371
+ error_setg(errp, "drive property not set");
1372
+ return false;
1373
+ }
1374
+
1375
+ if (!blkconf_blocksizes(&lu->qdev.conf, errp)) {
1376
+ return false;
1377
+ }
1378
+
1379
+ if (blk_get_aio_context(lu->qdev.conf.blk) != qemu_get_aio_context() &&
1380
+ !lu->qdev.hba_supports_iothread) {
1381
+ error_setg(errp, "HBA does not support iothreads");
1382
+ return false;
1383
+ }
1384
+
1385
+ read_only = !blk_supports_write_perm(lu->qdev.conf.blk);
1386
+
1387
+ if (!blkconf_apply_backend_options(&dev->conf, read_only,
1388
+ dev->type == TYPE_DISK, errp)) {
1389
+ return false;
1390
+ }
1391
+
1392
+ if (blk_is_sg(lu->qdev.conf.blk)) {
1393
+ error_setg(errp, "unwanted /dev/sg*");
1394
+ return false;
1395
+ }
1396
+
1397
+ blk_iostatus_enable(lu->qdev.conf.blk);
1398
+ return true;
1399
+}
1400
+
1401
+static bool ufs_add_lu(UfsHc *u, UfsLu *lu, Error **errp)
1402
+{
1403
+ BlockBackend *blk = lu->qdev.conf.blk;
1404
+ int64_t brdv_len = blk_getlength(blk);
1405
+ uint64_t raw_dev_cap =
1406
+ be64_to_cpu(u->geometry_desc.total_raw_device_capacity);
1407
+
1408
+ if (u->device_desc.number_lu >= UFS_MAX_LUS) {
1409
+ error_setg(errp, "ufs host controller has too many logical units.");
1410
+ return false;
1411
+ }
1412
+
1413
+ if (u->lus[lu->lun] != NULL) {
1414
+ error_setg(errp, "ufs logical unit %d already exists.", lu->lun);
1415
+ return false;
1416
+ }
1417
+
1418
+ u->lus[lu->lun] = lu;
1419
+ u->device_desc.number_lu++;
1420
+ raw_dev_cap += (brdv_len >> UFS_GEOMETRY_CAPACITY_SHIFT);
1421
+ u->geometry_desc.total_raw_device_capacity = cpu_to_be64(raw_dev_cap);
1422
+ return true;
1423
+}
1424
+
1425
+static inline uint8_t ufs_log2(uint64_t input)
1426
+{
1427
+ int log = 0;
1428
+ while (input >>= 1) {
1429
+ log++;
1430
+ }
1431
+ return log;
1432
+}
1433
+
1434
+static void ufs_init_lu(UfsLu *lu)
1435
+{
1436
+ BlockBackend *blk = lu->qdev.conf.blk;
1437
+ int64_t brdv_len = blk_getlength(blk);
1438
+
1439
+ lu->lun = lu->qdev.lun;
1440
+ memset(&lu->unit_desc, 0, sizeof(lu->unit_desc));
1441
+ lu->unit_desc.length = sizeof(UnitDescriptor);
1442
+ lu->unit_desc.descriptor_idn = QUERY_DESC_IDN_UNIT;
1443
+ lu->unit_desc.lu_enable = 0x01;
1444
+ lu->unit_desc.logical_block_size = ufs_log2(lu->qdev.blocksize);
1445
+ lu->unit_desc.unit_index = lu->qdev.lun;
1446
+ lu->unit_desc.logical_block_count =
1447
+ cpu_to_be64(brdv_len / (1 << lu->unit_desc.logical_block_size));
1448
+}
1449
+
1450
+static bool ufs_lu_check_constraints(UfsLu *lu, Error **errp)
1451
+{
1452
+ if (!lu->qdev.conf.blk) {
1453
+ error_setg(errp, "drive property not set");
1454
+ return false;
1455
+ }
1456
+
1457
+ if (lu->qdev.channel != 0) {
1458
+ error_setg(errp, "ufs logical unit does not support channel");
1459
+ return false;
1460
+ }
1461
+
1462
+ if (lu->qdev.lun >= UFS_MAX_LUS) {
1463
+ error_setg(errp, "lun must be between 1 and %d", UFS_MAX_LUS - 1);
1464
+ return false;
1465
+ }
1466
+
1467
+ return true;
1468
+}
1469
+
1470
+static void ufs_lu_realize(SCSIDevice *dev, Error **errp)
1471
+{
1472
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, dev);
1473
+ BusState *s = qdev_get_parent_bus(&dev->qdev);
1474
+ UfsHc *u = UFS(s->parent);
1475
+ AioContext *ctx = NULL;
1476
+ uint64_t nb_sectors, nb_blocks;
1477
+
1478
+ if (!ufs_lu_check_constraints(lu, errp)) {
1479
+ return;
1480
+ }
1481
+
1482
+ if (lu->qdev.conf.blk) {
1483
+ ctx = blk_get_aio_context(lu->qdev.conf.blk);
1484
+ aio_context_acquire(ctx);
1485
+ if (!blkconf_blocksizes(&lu->qdev.conf, errp)) {
1486
+ goto out;
1487
+ }
1488
+ }
1489
+ lu->qdev.blocksize = UFS_BLOCK_SIZE;
1490
+ blk_get_geometry(lu->qdev.conf.blk, &nb_sectors);
1491
+ nb_blocks = nb_sectors / (lu->qdev.blocksize / BDRV_SECTOR_SIZE);
1492
+ if (nb_blocks > UINT32_MAX) {
1493
+ nb_blocks = UINT32_MAX;
1494
+ }
1495
+ lu->qdev.max_lba = nb_blocks;
1496
+ lu->qdev.type = TYPE_DISK;
1497
+
1498
+ ufs_init_lu(lu);
1499
+ if (!ufs_add_lu(u, lu, errp)) {
1500
+ goto out;
1501
+ }
1502
+
1503
+ ufs_lu_brdv_init(lu, errp);
1504
+out:
1505
+ if (ctx) {
1506
+ aio_context_release(ctx);
1507
+ }
1508
+}
1509
+
1510
+static void ufs_lu_unrealize(SCSIDevice *dev)
1511
+{
1512
+ UfsLu *lu = DO_UPCAST(UfsLu, qdev, dev);
1513
+
1514
+ blk_drain(lu->qdev.conf.blk);
1515
+}
1516
+
1517
+static void ufs_wlu_realize(DeviceState *qdev, Error **errp)
1518
+{
1519
+ UfsWLu *wlu = UFSWLU(qdev);
1520
+ SCSIDevice *dev = &wlu->qdev;
1521
+
1522
+ if (!is_wlun(dev->lun)) {
1523
+ error_setg(errp, "not well-known logical unit number");
1524
+ return;
1525
+ }
1526
+
1527
+ QTAILQ_INIT(&dev->requests);
1528
+}
1529
+
1530
+static void ufs_lu_class_init(ObjectClass *oc, void *data)
1531
+{
1532
+ DeviceClass *dc = DEVICE_CLASS(oc);
1533
+ SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(oc);
1534
+
1535
+ sc->realize = ufs_lu_realize;
1536
+ sc->unrealize = ufs_lu_unrealize;
1537
+ sc->alloc_req = scsi_new_request;
1538
+ dc->bus_type = TYPE_UFS_BUS;
1539
+ device_class_set_props(dc, ufs_lu_props);
1540
+ dc->desc = "Virtual UFS logical unit";
1541
+}
1542
+
1543
+static void ufs_wlu_class_init(ObjectClass *oc, void *data)
1544
+{
1545
+ DeviceClass *dc = DEVICE_CLASS(oc);
1546
+ SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(oc);
1547
+
1548
+ /*
1549
+ * The realize() function of TYPE_SCSI_DEVICE causes a segmentation fault
1550
+ * if a block drive does not exist. Define a new realize function for
1551
+ * well-known LUs that do not have a block drive.
1552
+ */
1553
+ dc->realize = ufs_wlu_realize;
1554
+ sc->alloc_req = scsi_new_request;
1555
+ dc->bus_type = TYPE_UFS_BUS;
1556
+ dc->desc = "Virtual UFS well-known logical unit";
1557
+}
1558
+
1559
+static const TypeInfo ufs_lu_info = {
1560
+ .name = TYPE_UFS_LU,
1561
+ .parent = TYPE_SCSI_DEVICE,
1562
+ .class_init = ufs_lu_class_init,
1563
+ .instance_size = sizeof(UfsLu),
1564
+};
1565
+
1566
+static const TypeInfo ufs_wlu_info = {
1567
+ .name = TYPE_UFS_WLU,
1568
+ .parent = TYPE_SCSI_DEVICE,
1569
+ .class_init = ufs_wlu_class_init,
1570
+ .instance_size = sizeof(UfsWLu),
1571
+};
1572
+
1573
+static void ufs_lu_register_types(void)
1574
+{
1575
+ type_register_static(&ufs_lu_info);
1576
+ type_register_static(&ufs_wlu_info);
1577
+}
1578
+
1579
+type_init(ufs_lu_register_types)
1580
diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c
1581
index XXXXXXX..XXXXXXX 100644
1582
--- a/hw/ufs/ufs.c
1583
+++ b/hw/ufs/ufs.c
1584
@@ -XXX,XX +XXX,XX @@
1585
* SPDX-License-Identifier: GPL-2.0-or-later
1586
*/
1587
1588
+/**
1589
+ * Reference Specs: https://www.jedec.org/, 3.1
1590
+ *
1591
+ * Usage
1592
+ * -----
1593
+ *
1594
+ * Add options:
1595
+ * -drive file=<file>,if=none,id=<drive_id>
1596
+ * -device ufs,serial=<serial>,id=<bus_name>, \
1597
+ * nutrs=<N[optional]>,nutmrs=<N[optional]>
1598
+ * -device ufs-lu,drive=<drive_id>,bus=<bus_name>
1599
+ */
1600
+
1601
#include "qemu/osdep.h"
1602
#include "qapi/error.h"
1603
#include "migration/vmstate.h"
1604
@@ -XXX,XX +XXX,XX @@ static const MemoryRegionOps ufs_mmio_ops = {
1605
},
1606
};
1607
1608
+static QEMUSGList *ufs_get_sg_list(SCSIRequest *scsi_req)
1609
+{
1610
+ UfsRequest *req = scsi_req->hba_private;
1611
+ return req->sg;
1612
+}
1613
+
1614
+static void ufs_build_upiu_sense_data(UfsRequest *req, SCSIRequest *scsi_req)
1615
+{
1616
+ req->rsp_upiu.sr.sense_data_len = cpu_to_be16(scsi_req->sense_len);
1617
+ assert(scsi_req->sense_len <= SCSI_SENSE_LEN);
1618
+ memcpy(req->rsp_upiu.sr.sense_data, scsi_req->sense, scsi_req->sense_len);
1619
+}
1620
+
1621
static void ufs_build_upiu_header(UfsRequest *req, uint8_t trans_type,
1622
uint8_t flags, uint8_t response,
1623
uint8_t scsi_status,
1624
@@ -XXX,XX +XXX,XX @@ static void ufs_build_upiu_header(UfsRequest *req, uint8_t trans_type,
1625
req->rsp_upiu.header.data_segment_length = cpu_to_be16(data_segment_length);
1626
}
1627
1628
+static void ufs_scsi_command_complete(SCSIRequest *scsi_req, size_t resid)
1629
+{
1630
+ UfsRequest *req = scsi_req->hba_private;
1631
+ int16_t status = scsi_req->status;
1632
+ uint32_t expected_len = be32_to_cpu(req->req_upiu.sc.exp_data_transfer_len);
1633
+ uint32_t transfered_len = scsi_req->cmd.xfer - resid;
1634
+ uint8_t flags = 0, response = COMMAND_RESULT_SUCESS;
1635
+ uint16_t data_segment_length;
1636
+
1637
+ if (expected_len > transfered_len) {
1638
+ req->rsp_upiu.sr.residual_transfer_count =
1639
+ cpu_to_be32(expected_len - transfered_len);
1640
+ flags |= UFS_UPIU_FLAG_UNDERFLOW;
1641
+ } else if (expected_len < transfered_len) {
1642
+ req->rsp_upiu.sr.residual_transfer_count =
1643
+ cpu_to_be32(transfered_len - expected_len);
1644
+ flags |= UFS_UPIU_FLAG_OVERFLOW;
1645
+ }
1646
+
1647
+ if (status != 0) {
1648
+ ufs_build_upiu_sense_data(req, scsi_req);
1649
+ response = COMMAND_RESULT_FAIL;
1650
+ }
1651
+
1652
+ data_segment_length = cpu_to_be16(scsi_req->sense_len +
1653
+ sizeof(req->rsp_upiu.sr.sense_data_len));
1654
+ ufs_build_upiu_header(req, UPIU_TRANSACTION_RESPONSE, flags, response,
1655
+ status, data_segment_length);
1656
+
1657
+ ufs_complete_req(req, UFS_REQUEST_SUCCESS);
1658
+
1659
+ scsi_req->hba_private = NULL;
1660
+ scsi_req_unref(scsi_req);
1661
+}
1662
+
1663
+static const struct SCSIBusInfo ufs_scsi_info = {
1664
+ .tcq = true,
1665
+ .max_target = 0,
1666
+ .max_lun = UFS_MAX_LUS,
1667
+ .max_channel = 0,
1668
+
1669
+ .get_sg_list = ufs_get_sg_list,
1670
+ .complete = ufs_scsi_command_complete,
1671
+};
1672
+
1673
+static UfsReqResult ufs_exec_scsi_cmd(UfsRequest *req)
1674
+{
1675
+ UfsHc *u = req->hc;
1676
+ uint8_t lun = req->req_upiu.header.lun;
1677
+ uint8_t task_tag = req->req_upiu.header.task_tag;
1678
+ SCSIDevice *dev = NULL;
1679
+
1680
+ trace_ufs_exec_scsi_cmd(req->slot, lun, req->req_upiu.sc.cdb[0]);
1681
+
1682
+ if (!is_wlun(lun)) {
1683
+ if (lun >= u->device_desc.number_lu) {
1684
+ trace_ufs_err_scsi_cmd_invalid_lun(lun);
1685
+ return UFS_REQUEST_FAIL;
1686
+ } else if (u->lus[lun] == NULL) {
1687
+ trace_ufs_err_scsi_cmd_invalid_lun(lun);
1688
+ return UFS_REQUEST_FAIL;
1689
+ }
1690
+ }
1691
+
1692
+ switch (lun) {
1693
+ case UFS_UPIU_REPORT_LUNS_WLUN:
1694
+ dev = &u->report_wlu->qdev;
1695
+ break;
1696
+ case UFS_UPIU_UFS_DEVICE_WLUN:
1697
+ dev = &u->dev_wlu->qdev;
1698
+ break;
1699
+ case UFS_UPIU_BOOT_WLUN:
1700
+ dev = &u->boot_wlu->qdev;
1701
+ break;
1702
+ case UFS_UPIU_RPMB_WLUN:
1703
+ dev = &u->rpmb_wlu->qdev;
1704
+ break;
1705
+ default:
1706
+ dev = &u->lus[lun]->qdev;
1707
+ }
1708
+
1709
+ SCSIRequest *scsi_req = scsi_req_new(
1710
+ dev, task_tag, lun, req->req_upiu.sc.cdb, UFS_CDB_SIZE, req);
1711
+
1712
+ uint32_t len = scsi_req_enqueue(scsi_req);
1713
+ if (len) {
1714
+ scsi_req_continue(scsi_req);
1715
+ }
1716
+
1717
+ return UFS_REQUEST_NO_COMPLETE;
1718
+}
1719
+
1720
static UfsReqResult ufs_exec_nop_cmd(UfsRequest *req)
198
{
1721
{
199
extra_blocks=$1
1722
trace_ufs_exec_nop_cmd(req->slot);
200
- img_size=$2
1723
@@ -XXX,XX +XXX,XX @@ static const RpmbUnitDescriptor rpmb_unit_desc = {
201
+ min_blocks=$2
1724
202
+ img_size=$3
1725
static QueryRespCode ufs_read_unit_desc(UfsRequest *req)
203
1726
{
204
- sed -e "s/blocks=$extra_blocks\\(\$\\|[^0-9]\\)/nothing allocated/" \
1727
+ UfsHc *u = req->hc;
205
- -e "s/blocks=$((extra_blocks + img_size / 512))\\(\$\\|[^0-9]\\)/everything allocated/"
1728
uint8_t lun = req->req_upiu.qr.index;
206
+ sed -e "s/blocks=$min_blocks\\(\$\\|[^0-9]\\)/min allocation/" \
1729
207
+ -e "s/blocks=$((extra_blocks + img_size / 512))\\(\$\\|[^0-9]\\)/max allocation/"
1730
- if (lun != UFS_UPIU_RPMB_WLUN && lun > UFS_MAX_LUS) {
1731
+ if (lun != UFS_UPIU_RPMB_WLUN &&
1732
+ (lun > UFS_MAX_LUS || u->lus[lun] == NULL)) {
1733
trace_ufs_err_query_invalid_index(req->req_upiu.qr.opcode, lun);
1734
return QUERY_RESULT_INVALID_INDEX;
1735
}
1736
@@ -XXX,XX +XXX,XX @@ static QueryRespCode ufs_read_unit_desc(UfsRequest *req)
1737
if (lun == UFS_UPIU_RPMB_WLUN) {
1738
memcpy(&req->rsp_upiu.qr.data, &rpmb_unit_desc, rpmb_unit_desc.length);
1739
} else {
1740
- /* unit descriptor is not yet supported */
1741
- return QUERY_RESULT_INVALID_INDEX;
1742
+ memcpy(&req->rsp_upiu.qr.data, &u->lus[lun]->unit_desc,
1743
+ sizeof(u->lus[lun]->unit_desc));
1744
}
1745
1746
return QUERY_RESULT_SUCCESS;
1747
@@ -XXX,XX +XXX,XX @@ static void ufs_exec_req(UfsRequest *req)
1748
req_result = ufs_exec_nop_cmd(req);
1749
break;
1750
case UPIU_TRANSACTION_COMMAND:
1751
- /* Not yet implemented */
1752
- req_result = UFS_REQUEST_FAIL;
1753
+ req_result = ufs_exec_scsi_cmd(req);
1754
break;
1755
case UPIU_TRANSACTION_QUERY_REQ:
1756
req_result = ufs_exec_query_cmd(req);
1757
@@ -XXX,XX +XXX,XX @@ static void ufs_exec_req(UfsRequest *req)
1758
req_result = UFS_REQUEST_FAIL;
1759
}
1760
1761
- ufs_complete_req(req, req_result);
1762
+ /*
1763
+ * The ufs_complete_req for scsi commands is handled by the
1764
+ * ufs_scsi_command_complete() callback function. Therefore, to avoid
1765
+ * duplicate processing, ufs_complete_req() is not called for scsi commands.
1766
+ */
1767
+ if (req_result != UFS_REQUEST_NO_COMPLETE) {
1768
+ ufs_complete_req(req, req_result);
1769
+ }
208
}
1770
}
209
1771
210
# get standard environment, filters and checks
1772
static void ufs_process_req(void *opaque)
211
@@ -XXX,XX +XXX,XX @@ size=$((1 * 1024 * 1024))
1773
@@ -XXX,XX +XXX,XX @@ static void ufs_init_hc(UfsHc *u)
212
touch "$TEST_DIR/empty"
1774
u->flags.permanently_disable_fw_update = 1;
213
extra_blocks=$(stat -c '%b' "$TEST_DIR/empty")
1775
}
214
1776
215
+# We always write the first byte; check how many blocks this filesystem
1777
+static bool ufs_init_wlu(UfsHc *u, UfsWLu **wlu, uint8_t wlun, Error **errp)
216
+# allocates to match empty image alloation.
1778
+{
217
+printf "\0" > "$TEST_DIR/empty"
1779
+ UfsWLu *new_wlu = UFSWLU(qdev_new(TYPE_UFS_WLU));
218
+min_blocks=$(stat -c '%b' "$TEST_DIR/empty")
1780
+
219
+
1781
+ qdev_prop_set_uint32(DEVICE(new_wlu), "lun", wlun);
220
echo
1782
+
221
echo "== creating image with default preallocation =="
1783
+ /*
222
_make_test_img $size | _filter_imgfmt
1784
+ * The well-known lu shares the same bus as the normal lu. If the well-known
223
-stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $size
1785
+ * lu writes the same channel value as the normal lu, the report will be
224
+stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $min_blocks $size
1786
+ * made not only for the normal lu but also for the well-known lu at
225
1787
+ * REPORT_LUN time. To prevent this, the channel value of normal lu is fixed
226
for mode in off full falloc; do
1788
+ * to 0 and the channel value of well-known lu is fixed to 1.
227
echo
1789
+ */
228
echo "== creating image with preallocation $mode =="
1790
+ qdev_prop_set_uint32(DEVICE(new_wlu), "channel", 1);
229
IMGOPTS=preallocation=$mode _make_test_img $size | _filter_imgfmt
1791
+ if (!qdev_realize_and_unref(DEVICE(new_wlu), BUS(&u->bus), errp)) {
230
- stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $size
1792
+ return false;
231
+ stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $min_blocks $size
1793
+ }
232
done
1794
+
233
1795
+ *wlu = new_wlu;
234
# success, all done
1796
+ return true;
235
diff --git a/tests/qemu-iotests/175.out b/tests/qemu-iotests/175.out
1797
+}
1798
+
1799
static void ufs_realize(PCIDevice *pci_dev, Error **errp)
1800
{
1801
UfsHc *u = UFS(pci_dev);
1802
@@ -XXX,XX +XXX,XX @@ static void ufs_realize(PCIDevice *pci_dev, Error **errp)
1803
return;
1804
}
1805
1806
+ qbus_init(&u->bus, sizeof(UfsBus), TYPE_UFS_BUS, &pci_dev->qdev,
1807
+ u->parent_obj.qdev.id);
1808
+ u->bus.parent_bus.info = &ufs_scsi_info;
1809
+
1810
ufs_init_state(u);
1811
ufs_init_hc(u);
1812
ufs_init_pci(u, pci_dev);
1813
+
1814
+ if (!ufs_init_wlu(u, &u->report_wlu, UFS_UPIU_REPORT_LUNS_WLUN, errp)) {
1815
+ return;
1816
+ }
1817
+
1818
+ if (!ufs_init_wlu(u, &u->dev_wlu, UFS_UPIU_UFS_DEVICE_WLUN, errp)) {
1819
+ return;
1820
+ }
1821
+
1822
+ if (!ufs_init_wlu(u, &u->boot_wlu, UFS_UPIU_BOOT_WLUN, errp)) {
1823
+ return;
1824
+ }
1825
+
1826
+ if (!ufs_init_wlu(u, &u->rpmb_wlu, UFS_UPIU_RPMB_WLUN, errp)) {
1827
+ return;
1828
+ }
1829
}
1830
1831
static void ufs_exit(PCIDevice *pci_dev)
1832
{
1833
UfsHc *u = UFS(pci_dev);
1834
1835
+ if (u->dev_wlu) {
1836
+ object_unref(OBJECT(u->dev_wlu));
1837
+ u->dev_wlu = NULL;
1838
+ }
1839
+
1840
+ if (u->report_wlu) {
1841
+ object_unref(OBJECT(u->report_wlu));
1842
+ u->report_wlu = NULL;
1843
+ }
1844
+
1845
+ if (u->rpmb_wlu) {
1846
+ object_unref(OBJECT(u->rpmb_wlu));
1847
+ u->rpmb_wlu = NULL;
1848
+ }
1849
+
1850
+ if (u->boot_wlu) {
1851
+ object_unref(OBJECT(u->boot_wlu));
1852
+ u->boot_wlu = NULL;
1853
+ }
1854
+
1855
qemu_bh_delete(u->doorbell_bh);
1856
qemu_bh_delete(u->complete_bh);
1857
1858
@@ -XXX,XX +XXX,XX @@ static void ufs_class_init(ObjectClass *oc, void *data)
1859
dc->vmsd = &ufs_vmstate;
1860
}
1861
1862
+static bool ufs_bus_check_address(BusState *qbus, DeviceState *qdev,
1863
+ Error **errp)
1864
+{
1865
+ SCSIDevice *dev = SCSI_DEVICE(qdev);
1866
+ UfsBusClass *ubc = UFS_BUS_GET_CLASS(qbus);
1867
+ UfsHc *u = UFS(qbus->parent);
1868
+
1869
+ if (strcmp(object_get_typename(OBJECT(dev)), TYPE_UFS_WLU) == 0) {
1870
+ if (dev->lun != UFS_UPIU_REPORT_LUNS_WLUN &&
1871
+ dev->lun != UFS_UPIU_UFS_DEVICE_WLUN &&
1872
+ dev->lun != UFS_UPIU_BOOT_WLUN && dev->lun != UFS_UPIU_RPMB_WLUN) {
1873
+ error_setg(errp, "bad well-known lun: %d", dev->lun);
1874
+ return false;
1875
+ }
1876
+
1877
+ if ((dev->lun == UFS_UPIU_REPORT_LUNS_WLUN && u->report_wlu != NULL) ||
1878
+ (dev->lun == UFS_UPIU_UFS_DEVICE_WLUN && u->dev_wlu != NULL) ||
1879
+ (dev->lun == UFS_UPIU_BOOT_WLUN && u->boot_wlu != NULL) ||
1880
+ (dev->lun == UFS_UPIU_RPMB_WLUN && u->rpmb_wlu != NULL)) {
1881
+ error_setg(errp, "well-known lun %d already exists", dev->lun);
1882
+ return false;
1883
+ }
1884
+
1885
+ return true;
1886
+ }
1887
+
1888
+ if (strcmp(object_get_typename(OBJECT(dev)), TYPE_UFS_LU) != 0) {
1889
+ error_setg(errp, "%s cannot be connected to ufs-bus",
1890
+ object_get_typename(OBJECT(dev)));
1891
+ return false;
1892
+ }
1893
+
1894
+ return ubc->parent_check_address(qbus, qdev, errp);
1895
+}
1896
+
1897
+static void ufs_bus_class_init(ObjectClass *class, void *data)
1898
+{
1899
+ BusClass *bc = BUS_CLASS(class);
1900
+ UfsBusClass *ubc = UFS_BUS_CLASS(class);
1901
+ ubc->parent_check_address = bc->check_address;
1902
+ bc->check_address = ufs_bus_check_address;
1903
+}
1904
+
1905
static const TypeInfo ufs_info = {
1906
.name = TYPE_UFS,
1907
.parent = TYPE_PCI_DEVICE,
1908
@@ -XXX,XX +XXX,XX @@ static const TypeInfo ufs_info = {
1909
.interfaces = (InterfaceInfo[]){ { INTERFACE_PCIE_DEVICE }, {} },
1910
};
1911
1912
+static const TypeInfo ufs_bus_info = {
1913
+ .name = TYPE_UFS_BUS,
1914
+ .parent = TYPE_SCSI_BUS,
1915
+ .class_init = ufs_bus_class_init,
1916
+ .class_size = sizeof(UfsBusClass),
1917
+ .instance_size = sizeof(UfsBus),
1918
+};
1919
+
1920
static void ufs_register_types(void)
1921
{
1922
type_register_static(&ufs_info);
1923
+ type_register_static(&ufs_bus_info);
1924
}
1925
1926
type_init(ufs_register_types)
1927
diff --git a/hw/ufs/meson.build b/hw/ufs/meson.build
236
index XXXXXXX..XXXXXXX 100644
1928
index XXXXXXX..XXXXXXX 100644
237
--- a/tests/qemu-iotests/175.out
1929
--- a/hw/ufs/meson.build
238
+++ b/tests/qemu-iotests/175.out
1930
+++ b/hw/ufs/meson.build
239
@@ -XXX,XX +XXX,XX @@ QA output created by 175
1931
@@ -1 +1 @@
240
1932
-system_ss.add(when: 'CONFIG_UFS_PCI', if_true: files('ufs.c'))
241
== creating image with default preallocation ==
1933
+system_ss.add(when: 'CONFIG_UFS_PCI', if_true: files('ufs.c', 'lu.c'))
242
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
1934
diff --git a/hw/ufs/trace-events b/hw/ufs/trace-events
243
-size=1048576, nothing allocated
244
+size=1048576, min allocation
245
246
== creating image with preallocation off ==
247
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 preallocation=off
248
-size=1048576, nothing allocated
249
+size=1048576, min allocation
250
251
== creating image with preallocation full ==
252
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 preallocation=full
253
-size=1048576, everything allocated
254
+size=1048576, max allocation
255
256
== creating image with preallocation falloc ==
257
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 preallocation=falloc
258
-size=1048576, everything allocated
259
+size=1048576, max allocation
260
*** done
261
diff --git a/tests/qemu-iotests/178.out.qcow2 b/tests/qemu-iotests/178.out.qcow2
262
index XXXXXXX..XXXXXXX 100644
1935
index XXXXXXX..XXXXXXX 100644
263
--- a/tests/qemu-iotests/178.out.qcow2
1936
--- a/hw/ufs/trace-events
264
+++ b/tests/qemu-iotests/178.out.qcow2
1937
+++ b/hw/ufs/trace-events
265
@@ -XXX,XX +XXX,XX @@ converted image file size in bytes: 196608
1938
@@ -XXX,XX +XXX,XX @@ ufs_exec_scsi_cmd(uint32_t slot, uint8_t lun, uint8_t opcode) "slot %"PRIu32", l
266
== raw input image with data (human) ==
1939
ufs_exec_query_cmd(uint32_t slot, uint8_t opcode) "slot %"PRIu32", opcode 0x%"PRIx8""
267
1940
ufs_process_uiccmd(uint32_t uiccmd, uint32_t ucmdarg1, uint32_t ucmdarg2, uint32_t ucmdarg3) "uiccmd 0x%"PRIx32", ucmdarg1 0x%"PRIx32", ucmdarg2 0x%"PRIx32", ucmdarg3 0x%"PRIx32""
268
Formatting 'TEST_DIR/t.qcow2', fmt=IMGFMT size=1073741824
1941
269
-required size: 393216
1942
+# lu.c
270
+required size: 458752
1943
+ufs_scsi_check_condition(uint32_t tag, uint8_t key, uint8_t asc, uint8_t ascq) "Command complete tag=0x%x sense=%d/%d/%d"
271
fully allocated size: 1074135040
1944
+ufs_scsi_read_complete(uint32_t tag, size_t size) "Data ready tag=0x%x len=%zd"
272
wrote 512/512 bytes at offset 512
1945
+ufs_scsi_read_data_count(uint32_t sector_count) "Read sector_count=%d"
273
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
1946
+ufs_scsi_read_data_invalid(void) "Data transfer direction invalid"
274
@@ -XXX,XX +XXX,XX @@ converted image file size in bytes: 196608
1947
+ufs_scsi_write_complete_noio(uint32_t tag, size_t size) "Write complete tag=0x%x more=%zd"
275
1948
+ufs_scsi_write_data_invalid(void) "Data transfer direction invalid"
276
Formatting 'TEST_DIR/t.qcow2', fmt=IMGFMT size=1073741824
1949
+ufs_scsi_emulate_vpd_page_00(size_t xfer) "Inquiry EVPD[Supported pages] buffer size %zd"
277
{
1950
+ufs_scsi_emulate_vpd_page_80_not_supported(void) "Inquiry EVPD[Serial number] not supported"
278
- "required": 393216,
1951
+ufs_scsi_emulate_vpd_page_80(size_t xfer) "Inquiry EVPD[Serial number] buffer size %zd"
279
+ "required": 458752,
1952
+ufs_scsi_emulate_vpd_page_87(size_t xfer) "Inquiry EVPD[Mode Page Policy] buffer size %zd"
280
"fully-allocated": 1074135040
1953
+ufs_scsi_emulate_mode_sense(int cmd, int page, size_t xfer, int control) "Mode Sense(%d) (page %d, xfer %zd, page_control %d)"
281
}
1954
+ufs_scsi_emulate_read_data(int buflen) "Read buf_len=%d"
282
wrote 512/512 bytes at offset 512
1955
+ufs_scsi_emulate_write_data(int buflen) "Write buf_len=%d"
283
diff --git a/tests/qemu-iotests/221.out b/tests/qemu-iotests/221.out
1956
+ufs_scsi_emulate_command_START_STOP(void) "START STOP UNIT"
284
index XXXXXXX..XXXXXXX 100644
1957
+ufs_scsi_emulate_command_FORMAT_UNIT(void) "FORMAT UNIT"
285
--- a/tests/qemu-iotests/221.out
1958
+ufs_scsi_emulate_command_SEND_DIAGNOSTIC(void) "SEND DIAGNOSTIC"
286
+++ b/tests/qemu-iotests/221.out
1959
+ufs_scsi_emulate_command_SAI_16(void) "SAI READ CAPACITY(16)"
287
@@ -XXX,XX +XXX,XX @@ QA output created by 221
1960
+ufs_scsi_emulate_command_SAI_unsupported(void) "Unsupported Service Action In"
288
=== Check mapping of unaligned raw image ===
1961
+ufs_scsi_emulate_command_MODE_SELECT_10(size_t xfer) "Mode Select(10) (len %zd)"
289
1962
+ufs_scsi_emulate_command_VERIFY(int bytchk) "Verify (bytchk %d)"
290
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=65537
1963
+ufs_scsi_emulate_command_UNKNOWN(int cmd, const char *name) "Unknown SCSI command (0x%2.2x=%s)"
291
-[{ "start": 0, "length": 66048, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
1964
+ufs_scsi_dma_command_READ(uint64_t lba, uint32_t len) "Read (block %" PRIu64 ", count %u)"
292
-[{ "start": 0, "length": 66048, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
1965
+ufs_scsi_dma_command_WRITE(uint64_t lba, int len) "Write (block %" PRIu64 ", count %u)"
293
+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
1966
+
294
+{ "start": 4096, "length": 61952, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
1967
# error condition
295
+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
1968
ufs_err_dma_read_utrd(uint32_t slot, uint64_t addr) "failed to read utrd. UTRLDBR slot %"PRIu32", UTRD dma addr %"PRIu64""
296
+{ "start": 4096, "length": 61952, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
1969
ufs_err_dma_read_req_upiu(uint32_t slot, uint64_t addr) "failed to read req upiu. UTRLDBR slot %"PRIu32", request upiu addr %"PRIu64""
297
wrote 1/1 bytes at offset 65536
298
1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
299
-[{ "start": 0, "length": 65536, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
300
+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
301
+{ "start": 4096, "length": 61440, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
302
{ "start": 65536, "length": 1, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
303
{ "start": 65537, "length": 511, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
304
-[{ "start": 0, "length": 65536, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
305
+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
306
+{ "start": 4096, "length": 61440, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
307
{ "start": 65536, "length": 1, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
308
{ "start": 65537, "length": 511, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
309
*** done
310
diff --git a/tests/qemu-iotests/253.out b/tests/qemu-iotests/253.out
311
index XXXXXXX..XXXXXXX 100644
312
--- a/tests/qemu-iotests/253.out
313
+++ b/tests/qemu-iotests/253.out
314
@@ -XXX,XX +XXX,XX @@ QA output created by 253
315
=== Check mapping of unaligned raw image ===
316
317
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048575
318
-[{ "start": 0, "length": 1048576, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
319
-[{ "start": 0, "length": 1048576, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
320
+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
321
+{ "start": 4096, "length": 1044480, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
322
+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
323
+{ "start": 4096, "length": 1044480, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
324
wrote 65535/65535 bytes at offset 983040
325
63.999 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
326
-[{ "start": 0, "length": 983040, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
327
+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
328
+{ "start": 4096, "length": 978944, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
329
{ "start": 983040, "length": 65536, "depth": 0, "zero": false, "data": true, "offset": OFFSET}]
330
-[{ "start": 0, "length": 983040, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
331
+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
332
+{ "start": 4096, "length": 978944, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
333
{ "start": 983040, "length": 65536, "depth": 0, "zero": false, "data": true, "offset": OFFSET}]
334
*** done
335
--
1970
--
336
2.21.0
1971
2.41.0
337
338
diff view generated by jsdifflib
1
From: Nir Soffer <nirsof@gmail.com>
1
From: Jeuk Kim <jeuk20.kim@gmail.com>
2
2
3
Quoting cache mode is not needed, and most tests use unquoted values.
3
This patch includes the following tests
4
Unify all test to use the same style.
4
Test mmio read
5
Test ufs device initialization and ufs-lu recognition
6
Test I/O (Performs a write followed by a read to verify)
5
7
6
Message-id: 20190827173432.7656-1-nsoffer@redhat.com
8
Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>
7
Signed-off-by: Nir Soffer <nsoffer@redhat.com>
9
Acked-by: Thomas Huth <thuth@redhat.com>
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Message-id: af6b8d54c049490b3533a784a0aeac4798bb9217.1691062912.git.jeuk20.kim@samsung.com
12
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
---
13
---
10
tests/qemu-iotests/026 | 4 ++--
14
MAINTAINERS | 1 +
11
tests/qemu-iotests/039 | 4 ++--
15
tests/qtest/ufs-test.c | 584 ++++++++++++++++++++++++++++++++++++++++
12
tests/qemu-iotests/052 | 2 +-
16
tests/qtest/meson.build | 1 +
13
tests/qemu-iotests/091 | 4 ++--
17
3 files changed, 586 insertions(+)
14
4 files changed, 7 insertions(+), 7 deletions(-)
18
create mode 100644 tests/qtest/ufs-test.c
15
19
16
diff --git a/tests/qemu-iotests/026 b/tests/qemu-iotests/026
20
diff --git a/MAINTAINERS b/MAINTAINERS
17
index XXXXXXX..XXXXXXX 100755
21
index XXXXXXX..XXXXXXX 100644
18
--- a/tests/qemu-iotests/026
22
--- a/MAINTAINERS
19
+++ b/tests/qemu-iotests/026
23
+++ b/MAINTAINERS
20
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
24
@@ -XXX,XX +XXX,XX @@ M: Jeuk Kim <jeuk20.kim@samsung.com>
21
# Currently only qcow2 supports rebasing
25
S: Supported
22
_supported_fmt qcow2
26
F: hw/ufs/*
23
_supported_proto file
27
F: include/block/ufs.h
24
-_default_cache_mode "writethrough"
28
+F: tests/qtest/ufs-test.c
25
-_supported_cache_modes "writethrough" "none"
29
26
+_default_cache_mode writethrough
30
megasas
27
+_supported_cache_modes writethrough none
31
M: Hannes Reinecke <hare@suse.com>
28
# The refcount table tests expect a certain minimum width for refcount entries
32
diff --git a/tests/qtest/ufs-test.c b/tests/qtest/ufs-test.c
29
# (so that the refcount table actually needs to grow); that minimum is 16 bits,
33
new file mode 100644
30
# being the default refcount entry width.
34
index XXXXXXX..XXXXXXX
31
diff --git a/tests/qemu-iotests/039 b/tests/qemu-iotests/039
35
--- /dev/null
32
index XXXXXXX..XXXXXXX 100755
36
+++ b/tests/qtest/ufs-test.c
33
--- a/tests/qemu-iotests/039
37
@@ -XXX,XX +XXX,XX @@
34
+++ b/tests/qemu-iotests/039
38
+/*
35
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
39
+ * QTest testcase for UFS
36
_supported_fmt qcow2
40
+ *
37
_supported_proto file
41
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd. All rights reserved.
38
_supported_os Linux
42
+ *
39
-_default_cache_mode "writethrough"
43
+ * SPDX-License-Identifier: GPL-2.0-or-later
40
-_supported_cache_modes "writethrough"
44
+ */
41
+_default_cache_mode writethrough
45
+
42
+_supported_cache_modes writethrough
46
+#include "qemu/osdep.h"
43
47
+#include "qemu/module.h"
44
size=128M
48
+#include "qemu/units.h"
45
49
+#include "libqtest.h"
46
diff --git a/tests/qemu-iotests/052 b/tests/qemu-iotests/052
50
+#include "libqos/qgraph.h"
47
index XXXXXXX..XXXXXXX 100755
51
+#include "libqos/pci.h"
48
--- a/tests/qemu-iotests/052
52
+#include "scsi/constants.h"
49
+++ b/tests/qemu-iotests/052
53
+#include "include/block/ufs.h"
50
@@ -XXX,XX +XXX,XX @@ _supported_fmt generic
54
+
51
_supported_proto file
55
+/* Test images sizes in Bytes */
52
56
+#define TEST_IMAGE_SIZE (64 * 1024 * 1024)
53
# Don't do O_DIRECT on tmpfs
57
+/* Timeout for various operations, in seconds. */
54
-_supported_cache_modes "writeback" "writethrough" "unsafe"
58
+#define TIMEOUT_SECONDS 10
55
+_supported_cache_modes writeback writethrough unsafe
59
+/* Maximum PRD entry count */
56
60
+#define MAX_PRD_ENTRY_COUNT 10
57
size=128M
61
+#define PRD_ENTRY_DATA_SIZE 4096
58
_make_test_img $size
62
+/* Constants to build upiu */
59
diff --git a/tests/qemu-iotests/091 b/tests/qemu-iotests/091
63
+#define UTP_COMMAND_DESCRIPTOR_SIZE 4096
60
index XXXXXXX..XXXXXXX 100755
64
+#define UTP_RESPONSE_UPIU_OFFSET 1024
61
--- a/tests/qemu-iotests/091
65
+#define UTP_PRDT_UPIU_OFFSET 2048
62
+++ b/tests/qemu-iotests/091
66
+
63
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
67
+typedef struct QUfs QUfs;
64
_supported_fmt qcow2
68
+
65
_supported_proto file
69
+struct QUfs {
66
_supported_os Linux
70
+ QOSGraphObject obj;
67
-_default_cache_mode "none"
71
+ QPCIDevice dev;
68
-_supported_cache_modes "writethrough" "none" "writeback"
72
+ QPCIBar bar;
69
+_default_cache_mode none
73
+
70
+_supported_cache_modes writethrough none writeback
74
+ uint64_t utrlba;
71
75
+ uint64_t utmrlba;
72
size=1G
76
+ uint64_t cmd_desc_addr;
73
77
+ uint64_t data_buffer_addr;
78
+
79
+ bool enabled;
80
+};
81
+
82
+static inline uint32_t ufs_rreg(QUfs *ufs, size_t offset)
83
+{
84
+ return qpci_io_readl(&ufs->dev, ufs->bar, offset);
85
+}
86
+
87
+static inline void ufs_wreg(QUfs *ufs, size_t offset, uint32_t value)
88
+{
89
+ qpci_io_writel(&ufs->dev, ufs->bar, offset, value);
90
+}
91
+
92
+static void ufs_wait_for_irq(QUfs *ufs)
93
+{
94
+ uint64_t end_time;
95
+ uint32_t is;
96
+ /* Wait for device to reset as the linux driver does. */
97
+ end_time = g_get_monotonic_time() + TIMEOUT_SECONDS * G_TIME_SPAN_SECOND;
98
+ do {
99
+ qtest_clock_step(ufs->dev.bus->qts, 100);
100
+ is = ufs_rreg(ufs, A_IS);
101
+ } while (is == 0 && g_get_monotonic_time() < end_time);
102
+}
103
+
104
+static UtpTransferReqDesc ufs_build_req_utrd(uint64_t cmd_desc_addr,
105
+ uint8_t slot,
106
+ uint32_t data_direction,
107
+ uint16_t prd_table_length)
108
+{
109
+ UtpTransferReqDesc req = { 0 };
110
+ uint64_t command_desc_base_addr =
111
+ cmd_desc_addr + slot * UTP_COMMAND_DESCRIPTOR_SIZE;
112
+
113
+ req.header.dword_0 =
114
+ cpu_to_le32(1 << 28 | data_direction | UTP_REQ_DESC_INT_CMD);
115
+ req.header.dword_2 = cpu_to_le32(OCS_INVALID_COMMAND_STATUS);
116
+
117
+ req.command_desc_base_addr_hi = cpu_to_le32(command_desc_base_addr >> 32);
118
+ req.command_desc_base_addr_lo =
119
+ cpu_to_le32(command_desc_base_addr & 0xffffffff);
120
+ req.response_upiu_offset =
121
+ cpu_to_le16(UTP_RESPONSE_UPIU_OFFSET / sizeof(uint32_t));
122
+ req.response_upiu_length = cpu_to_le16(sizeof(UtpUpiuRsp));
123
+ req.prd_table_offset = cpu_to_le16(UTP_PRDT_UPIU_OFFSET / sizeof(uint32_t));
124
+ req.prd_table_length = cpu_to_le16(prd_table_length);
125
+ return req;
126
+}
127
+
128
+static void ufs_send_nop_out(QUfs *ufs, uint8_t slot,
129
+ UtpTransferReqDesc *utrd_out, UtpUpiuRsp *rsp_out)
130
+{
131
+ /* Build up utp transfer request descriptor */
132
+ UtpTransferReqDesc utrd =
133
+ ufs_build_req_utrd(ufs->cmd_desc_addr, slot, UTP_NO_DATA_TRANSFER, 0);
134
+ uint64_t utrd_addr = ufs->utrlba + slot * sizeof(UtpTransferReqDesc);
135
+ uint64_t req_upiu_addr =
136
+ ufs->cmd_desc_addr + slot * UTP_COMMAND_DESCRIPTOR_SIZE;
137
+ uint64_t rsp_upiu_addr = req_upiu_addr + UTP_RESPONSE_UPIU_OFFSET;
138
+ qtest_memwrite(ufs->dev.bus->qts, utrd_addr, &utrd, sizeof(utrd));
139
+
140
+ /* Build up request upiu */
141
+ UtpUpiuReq req_upiu = { 0 };
142
+ req_upiu.header.trans_type = UPIU_TRANSACTION_NOP_OUT;
143
+ req_upiu.header.task_tag = slot;
144
+ qtest_memwrite(ufs->dev.bus->qts, req_upiu_addr, &req_upiu,
145
+ sizeof(req_upiu));
146
+
147
+ /* Ring Doorbell */
148
+ ufs_wreg(ufs, A_UTRLDBR, 1);
149
+ ufs_wait_for_irq(ufs);
150
+ g_assert_true(FIELD_EX32(ufs_rreg(ufs, A_IS), IS, UTRCS));
151
+ ufs_wreg(ufs, A_IS, FIELD_DP32(0, IS, UTRCS, 1));
152
+
153
+ qtest_memread(ufs->dev.bus->qts, utrd_addr, utrd_out, sizeof(*utrd_out));
154
+ qtest_memread(ufs->dev.bus->qts, rsp_upiu_addr, rsp_out, sizeof(*rsp_out));
155
+}
156
+
157
+static void ufs_send_query(QUfs *ufs, uint8_t slot, uint8_t query_function,
158
+ uint8_t query_opcode, uint8_t idn, uint8_t index,
159
+ UtpTransferReqDesc *utrd_out, UtpUpiuRsp *rsp_out)
160
+{
161
+ /* Build up utp transfer request descriptor */
162
+ UtpTransferReqDesc utrd =
163
+ ufs_build_req_utrd(ufs->cmd_desc_addr, slot, UTP_NO_DATA_TRANSFER, 0);
164
+ uint64_t utrd_addr = ufs->utrlba + slot * sizeof(UtpTransferReqDesc);
165
+ uint64_t req_upiu_addr =
166
+ ufs->cmd_desc_addr + slot * UTP_COMMAND_DESCRIPTOR_SIZE;
167
+ uint64_t rsp_upiu_addr = req_upiu_addr + UTP_RESPONSE_UPIU_OFFSET;
168
+ qtest_memwrite(ufs->dev.bus->qts, utrd_addr, &utrd, sizeof(utrd));
169
+
170
+ /* Build up request upiu */
171
+ UtpUpiuReq req_upiu = { 0 };
172
+ req_upiu.header.trans_type = UPIU_TRANSACTION_QUERY_REQ;
173
+ req_upiu.header.query_func = query_function;
174
+ req_upiu.header.task_tag = slot;
175
+ /*
176
+ * QEMU UFS does not currently support Write descriptor and Write attribute,
177
+ * so the value of data_segment_length is always 0.
178
+ */
179
+ req_upiu.header.data_segment_length = 0;
180
+ req_upiu.qr.opcode = query_opcode;
181
+ req_upiu.qr.idn = idn;
182
+ req_upiu.qr.index = index;
183
+ qtest_memwrite(ufs->dev.bus->qts, req_upiu_addr, &req_upiu,
184
+ sizeof(req_upiu));
185
+
186
+ /* Ring Doorbell */
187
+ ufs_wreg(ufs, A_UTRLDBR, 1);
188
+ ufs_wait_for_irq(ufs);
189
+ g_assert_true(FIELD_EX32(ufs_rreg(ufs, A_IS), IS, UTRCS));
190
+ ufs_wreg(ufs, A_IS, FIELD_DP32(0, IS, UTRCS, 1));
191
+
192
+ qtest_memread(ufs->dev.bus->qts, utrd_addr, utrd_out, sizeof(*utrd_out));
193
+ qtest_memread(ufs->dev.bus->qts, rsp_upiu_addr, rsp_out, sizeof(*rsp_out));
194
+}
195
+
196
+static void ufs_send_scsi_command(QUfs *ufs, uint8_t slot, uint8_t lun,
197
+ const uint8_t *cdb, const uint8_t *data_in,
198
+ size_t data_in_len, uint8_t *data_out,
199
+ size_t data_out_len,
200
+ UtpTransferReqDesc *utrd_out,
201
+ UtpUpiuRsp *rsp_out)
202
+
203
+{
204
+ /* Build up PRDT */
205
+ UfshcdSgEntry entries[MAX_PRD_ENTRY_COUNT] = {
206
+ 0,
207
+ };
208
+ uint8_t flags;
209
+ uint16_t prd_table_length, i;
210
+ uint32_t data_direction, data_len;
211
+ uint64_t req_upiu_addr =
212
+ ufs->cmd_desc_addr + slot * UTP_COMMAND_DESCRIPTOR_SIZE;
213
+ uint64_t prdt_addr = req_upiu_addr + UTP_PRDT_UPIU_OFFSET;
214
+
215
+ g_assert_true(data_in_len < MAX_PRD_ENTRY_COUNT * PRD_ENTRY_DATA_SIZE);
216
+ g_assert_true(data_out_len < MAX_PRD_ENTRY_COUNT * PRD_ENTRY_DATA_SIZE);
217
+ if (data_in_len > 0) {
218
+ g_assert_nonnull(data_in);
219
+ data_direction = UTP_HOST_TO_DEVICE;
220
+ data_len = data_in_len;
221
+ flags = UPIU_CMD_FLAGS_WRITE;
222
+ } else if (data_out_len > 0) {
223
+ g_assert_nonnull(data_out);
224
+ data_direction = UTP_DEVICE_TO_HOST;
225
+ data_len = data_out_len;
226
+ flags = UPIU_CMD_FLAGS_READ;
227
+ } else {
228
+ data_direction = UTP_NO_DATA_TRANSFER;
229
+ data_len = 0;
230
+ flags = UPIU_CMD_FLAGS_NONE;
231
+ }
232
+ prd_table_length = DIV_ROUND_UP(data_len, PRD_ENTRY_DATA_SIZE);
233
+
234
+ qtest_memset(ufs->dev.bus->qts, ufs->data_buffer_addr, 0,
235
+ MAX_PRD_ENTRY_COUNT * PRD_ENTRY_DATA_SIZE);
236
+ if (data_in_len) {
237
+ qtest_memwrite(ufs->dev.bus->qts, ufs->data_buffer_addr, data_in,
238
+ data_in_len);
239
+ }
240
+
241
+ for (i = 0; i < prd_table_length; i++) {
242
+ entries[i].addr =
243
+ cpu_to_le64(ufs->data_buffer_addr + i * sizeof(UfshcdSgEntry));
244
+ if (i + 1 != prd_table_length) {
245
+ entries[i].size = cpu_to_le32(PRD_ENTRY_DATA_SIZE - 1);
246
+ } else {
247
+ entries[i].size = cpu_to_le32(
248
+ data_len - (PRD_ENTRY_DATA_SIZE * (prd_table_length - 1)) - 1);
249
+ }
250
+ }
251
+ qtest_memwrite(ufs->dev.bus->qts, prdt_addr, entries,
252
+ prd_table_length * sizeof(UfshcdSgEntry));
253
+
254
+ /* Build up utp transfer request descriptor */
255
+ UtpTransferReqDesc utrd = ufs_build_req_utrd(
256
+ ufs->cmd_desc_addr, slot, data_direction, prd_table_length);
257
+ uint64_t utrd_addr = ufs->utrlba + slot * sizeof(UtpTransferReqDesc);
258
+ uint64_t rsp_upiu_addr = req_upiu_addr + UTP_RESPONSE_UPIU_OFFSET;
259
+ qtest_memwrite(ufs->dev.bus->qts, utrd_addr, &utrd, sizeof(utrd));
260
+
261
+ /* Build up request upiu */
262
+ UtpUpiuReq req_upiu = { 0 };
263
+ req_upiu.header.trans_type = UPIU_TRANSACTION_COMMAND;
264
+ req_upiu.header.flags = flags;
265
+ req_upiu.header.lun = lun;
266
+ req_upiu.header.task_tag = slot;
267
+ req_upiu.sc.exp_data_transfer_len = cpu_to_be32(data_len);
268
+ memcpy(req_upiu.sc.cdb, cdb, UFS_CDB_SIZE);
269
+ qtest_memwrite(ufs->dev.bus->qts, req_upiu_addr, &req_upiu,
270
+ sizeof(req_upiu));
271
+
272
+ /* Ring Doorbell */
273
+ ufs_wreg(ufs, A_UTRLDBR, 1);
274
+ ufs_wait_for_irq(ufs);
275
+ g_assert_true(FIELD_EX32(ufs_rreg(ufs, A_IS), IS, UTRCS));
276
+ ufs_wreg(ufs, A_IS, FIELD_DP32(0, IS, UTRCS, 1));
277
+
278
+ qtest_memread(ufs->dev.bus->qts, utrd_addr, utrd_out, sizeof(*utrd_out));
279
+ qtest_memread(ufs->dev.bus->qts, rsp_upiu_addr, rsp_out, sizeof(*rsp_out));
280
+ if (data_out_len) {
281
+ qtest_memread(ufs->dev.bus->qts, ufs->data_buffer_addr, data_out,
282
+ data_out_len);
283
+ }
284
+}
285
+
286
+/**
287
+ * Initialize Ufs host controller and logical unit.
288
+ * After running this function, you can make a transfer request to the UFS.
289
+ */
290
+static void ufs_init(QUfs *ufs, QGuestAllocator *alloc)
291
+{
292
+ uint64_t end_time;
293
+ uint32_t nutrs, nutmrs;
294
+ uint32_t hcs, is, ucmdarg2, cap;
295
+ uint32_t hce = 0, ie = 0;
296
+ UtpTransferReqDesc utrd;
297
+ UtpUpiuRsp rsp_upiu;
298
+
299
+ ufs->bar = qpci_iomap(&ufs->dev, 0, NULL);
300
+ qpci_device_enable(&ufs->dev);
301
+
302
+ /* Start host controller initialization */
303
+ hce = FIELD_DP32(hce, HCE, HCE, 1);
304
+ ufs_wreg(ufs, A_HCE, hce);
305
+
306
+ /* Wait for device to reset */
307
+ end_time = g_get_monotonic_time() + TIMEOUT_SECONDS * G_TIME_SPAN_SECOND;
308
+ do {
309
+ qtest_clock_step(ufs->dev.bus->qts, 100);
310
+ hce = FIELD_EX32(ufs_rreg(ufs, A_HCE), HCE, HCE);
311
+ } while (hce == 0 && g_get_monotonic_time() < end_time);
312
+ g_assert_cmpuint(hce, ==, 1);
313
+
314
+ /* Enable interrupt */
315
+ ie = FIELD_DP32(ie, IE, UCCE, 1);
316
+ ie = FIELD_DP32(ie, IE, UHESE, 1);
317
+ ie = FIELD_DP32(ie, IE, UHXSE, 1);
318
+ ie = FIELD_DP32(ie, IE, UPMSE, 1);
319
+ ufs_wreg(ufs, A_IE, ie);
320
+
321
+ /* Send DME_LINK_STARTUP uic command */
322
+ hcs = ufs_rreg(ufs, A_HCS);
323
+ g_assert_true(FIELD_EX32(hcs, HCS, UCRDY));
324
+
325
+ ufs_wreg(ufs, A_UCMDARG1, 0);
326
+ ufs_wreg(ufs, A_UCMDARG2, 0);
327
+ ufs_wreg(ufs, A_UCMDARG3, 0);
328
+ ufs_wreg(ufs, A_UICCMD, UIC_CMD_DME_LINK_STARTUP);
329
+
330
+ is = ufs_rreg(ufs, A_IS);
331
+ g_assert_true(FIELD_EX32(is, IS, UCCS));
332
+ ufs_wreg(ufs, A_IS, FIELD_DP32(0, IS, UCCS, 1));
333
+
334
+ ucmdarg2 = ufs_rreg(ufs, A_UCMDARG2);
335
+ g_assert_cmpuint(ucmdarg2, ==, 0);
336
+ is = ufs_rreg(ufs, A_IS);
337
+ g_assert_cmpuint(is, ==, 0);
338
+ hcs = ufs_rreg(ufs, A_HCS);
339
+ g_assert_true(FIELD_EX32(hcs, HCS, DP));
340
+ g_assert_true(FIELD_EX32(hcs, HCS, UTRLRDY));
341
+ g_assert_true(FIELD_EX32(hcs, HCS, UTMRLRDY));
342
+ g_assert_true(FIELD_EX32(hcs, HCS, UCRDY));
343
+
344
+ /* Enable all interrupt functions */
345
+ ie = FIELD_DP32(ie, IE, UTRCE, 1);
346
+ ie = FIELD_DP32(ie, IE, UEE, 1);
347
+ ie = FIELD_DP32(ie, IE, UPMSE, 1);
348
+ ie = FIELD_DP32(ie, IE, UHXSE, 1);
349
+ ie = FIELD_DP32(ie, IE, UHESE, 1);
350
+ ie = FIELD_DP32(ie, IE, UTMRCE, 1);
351
+ ie = FIELD_DP32(ie, IE, UCCE, 1);
352
+ ie = FIELD_DP32(ie, IE, DFEE, 1);
353
+ ie = FIELD_DP32(ie, IE, HCFEE, 1);
354
+ ie = FIELD_DP32(ie, IE, SBFEE, 1);
355
+ ie = FIELD_DP32(ie, IE, CEFEE, 1);
356
+ ufs_wreg(ufs, A_IE, ie);
357
+ ufs_wreg(ufs, A_UTRIACR, 0);
358
+
359
+ /* Enable tranfer request and task management request */
360
+ cap = ufs_rreg(ufs, A_CAP);
361
+ nutrs = FIELD_EX32(cap, CAP, NUTRS) + 1;
362
+ nutmrs = FIELD_EX32(cap, CAP, NUTMRS) + 1;
363
+ ufs->cmd_desc_addr =
364
+ guest_alloc(alloc, nutrs * UTP_COMMAND_DESCRIPTOR_SIZE);
365
+ ufs->data_buffer_addr =
366
+ guest_alloc(alloc, MAX_PRD_ENTRY_COUNT * PRD_ENTRY_DATA_SIZE);
367
+ ufs->utrlba = guest_alloc(alloc, nutrs * sizeof(UtpTransferReqDesc));
368
+ ufs->utmrlba = guest_alloc(alloc, nutmrs * sizeof(UtpTaskReqDesc));
369
+
370
+ ufs_wreg(ufs, A_UTRLBA, ufs->utrlba & 0xffffffff);
371
+ ufs_wreg(ufs, A_UTRLBAU, ufs->utrlba >> 32);
372
+ ufs_wreg(ufs, A_UTMRLBA, ufs->utmrlba & 0xffffffff);
373
+ ufs_wreg(ufs, A_UTMRLBAU, ufs->utmrlba >> 32);
374
+ ufs_wreg(ufs, A_UTRLRSR, 1);
375
+ ufs_wreg(ufs, A_UTMRLRSR, 1);
376
+
377
+ /* Send nop out to test transfer request */
378
+ ufs_send_nop_out(ufs, 0, &utrd, &rsp_upiu);
379
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, OCS_SUCCESS);
380
+
381
+ /* Set fDeviceInit flag via query request */
382
+ ufs_send_query(ufs, 0, UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
383
+ UPIU_QUERY_OPCODE_SET_FLAG, QUERY_FLAG_IDN_FDEVICEINIT, 0,
384
+ &utrd, &rsp_upiu);
385
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, OCS_SUCCESS);
386
+
387
+ /* Wait for device to reset */
388
+ end_time = g_get_monotonic_time() + TIMEOUT_SECONDS * G_TIME_SPAN_SECOND;
389
+ do {
390
+ qtest_clock_step(ufs->dev.bus->qts, 100);
391
+ ufs_send_query(ufs, 0, UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
392
+ UPIU_QUERY_OPCODE_READ_FLAG, QUERY_FLAG_IDN_FDEVICEINIT,
393
+ 0, &utrd, &rsp_upiu);
394
+ } while (be32_to_cpu(rsp_upiu.qr.value) != 0 &&
395
+ g_get_monotonic_time() < end_time);
396
+ g_assert_cmpuint(be32_to_cpu(rsp_upiu.qr.value), ==, 0);
397
+
398
+ ufs->enabled = true;
399
+}
400
+
401
+static void ufs_exit(QUfs *ufs, QGuestAllocator *alloc)
402
+{
403
+ if (ufs->enabled) {
404
+ guest_free(alloc, ufs->utrlba);
405
+ guest_free(alloc, ufs->utmrlba);
406
+ guest_free(alloc, ufs->cmd_desc_addr);
407
+ guest_free(alloc, ufs->data_buffer_addr);
408
+ }
409
+
410
+ qpci_iounmap(&ufs->dev, ufs->bar);
411
+}
412
+
413
+static void *ufs_get_driver(void *obj, const char *interface)
414
+{
415
+ QUfs *ufs = obj;
416
+
417
+ if (!g_strcmp0(interface, "pci-device")) {
418
+ return &ufs->dev;
419
+ }
420
+
421
+ fprintf(stderr, "%s not present in ufs\n", interface);
422
+ g_assert_not_reached();
423
+}
424
+
425
+static void *ufs_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
426
+{
427
+ QUfs *ufs = g_new0(QUfs, 1);
428
+ QPCIBus *bus = pci_bus;
429
+
430
+ qpci_device_init(&ufs->dev, bus, addr);
431
+ ufs->obj.get_driver = ufs_get_driver;
432
+
433
+ return &ufs->obj;
434
+}
435
+
436
+static void ufstest_reg_read(void *obj, void *data, QGuestAllocator *alloc)
437
+{
438
+ QUfs *ufs = obj;
439
+ uint32_t cap;
440
+
441
+ ufs->bar = qpci_iomap(&ufs->dev, 0, NULL);
442
+ qpci_device_enable(&ufs->dev);
443
+
444
+ cap = ufs_rreg(ufs, A_CAP);
445
+ g_assert_cmpuint(FIELD_EX32(cap, CAP, NUTRS), ==, 31);
446
+ g_assert_cmpuint(FIELD_EX32(cap, CAP, NUTMRS), ==, 7);
447
+ g_assert_cmpuint(FIELD_EX32(cap, CAP, 64AS), ==, 1);
448
+
449
+ qpci_iounmap(&ufs->dev, ufs->bar);
450
+}
451
+
452
+static void ufstest_init(void *obj, void *data, QGuestAllocator *alloc)
453
+{
454
+ QUfs *ufs = obj;
455
+
456
+ uint8_t buf[4096] = { 0 };
457
+ const uint8_t report_luns_cdb[UFS_CDB_SIZE] = {
458
+ /* allocation length 4096 */
459
+ REPORT_LUNS, 0x00, 0x00, 0x00, 0x00, 0x00,
460
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00
461
+ };
462
+ const uint8_t test_unit_ready_cdb[UFS_CDB_SIZE] = {
463
+ TEST_UNIT_READY,
464
+ };
465
+ UtpTransferReqDesc utrd;
466
+ UtpUpiuRsp rsp_upiu;
467
+
468
+ ufs_init(ufs, alloc);
469
+
470
+ /* Check REPORT_LUNS */
471
+ ufs_send_scsi_command(ufs, 0, 0, report_luns_cdb, NULL, 0, buf, sizeof(buf),
472
+ &utrd, &rsp_upiu);
473
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, OCS_SUCCESS);
474
+ g_assert_cmpuint(rsp_upiu.header.scsi_status, ==, GOOD);
475
+ /* LUN LIST LENGTH should be 8, in big endian */
476
+ g_assert_cmpuint(buf[3], ==, 8);
477
+ /* There is one logical unit whose lun is 0 */
478
+ g_assert_cmpuint(buf[9], ==, 0);
479
+
480
+ /* Check TEST_UNIT_READY */
481
+ ufs_send_scsi_command(ufs, 0, 0, test_unit_ready_cdb, NULL, 0, NULL, 0,
482
+ &utrd, &rsp_upiu);
483
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, OCS_SUCCESS);
484
+ g_assert_cmpuint(rsp_upiu.header.scsi_status, ==, GOOD);
485
+
486
+ ufs_exit(ufs, alloc);
487
+}
488
+
489
+static void ufstest_read_write(void *obj, void *data, QGuestAllocator *alloc)
490
+{
491
+ QUfs *ufs = obj;
492
+ uint8_t read_buf[4096] = { 0 };
493
+ uint8_t write_buf[4096] = { 0 };
494
+ const uint8_t read_capacity_cdb[UFS_CDB_SIZE] = {
495
+ /* allocation length 4096 */
496
+ SERVICE_ACTION_IN_16,
497
+ SAI_READ_CAPACITY_16,
498
+ 0x00,
499
+ 0x00,
500
+ 0x00,
501
+ 0x00,
502
+ 0x00,
503
+ 0x00,
504
+ 0x00,
505
+ 0x00,
506
+ 0x00,
507
+ 0x00,
508
+ 0x10,
509
+ 0x00,
510
+ 0x00,
511
+ 0x00
512
+ };
513
+ const uint8_t read_cdb[UFS_CDB_SIZE] = {
514
+ /* READ(10) to LBA 0, transfer length 1 */
515
+ READ_10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00
516
+ };
517
+ const uint8_t write_cdb[UFS_CDB_SIZE] = {
518
+ /* WRITE(10) to LBA 0, transfer length 1 */
519
+ WRITE_10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00
520
+ };
521
+ uint32_t block_size;
522
+ UtpTransferReqDesc utrd;
523
+ UtpUpiuRsp rsp_upiu;
524
+
525
+ ufs_init(ufs, alloc);
526
+
527
+ /* Read capacity */
528
+ ufs_send_scsi_command(ufs, 0, 1, read_capacity_cdb, NULL, 0, read_buf,
529
+ sizeof(read_buf), &utrd, &rsp_upiu);
530
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, OCS_SUCCESS);
531
+ g_assert_cmpuint(rsp_upiu.header.scsi_status, ==, COMMAND_RESULT_SUCESS);
532
+ block_size = ldl_be_p(&read_buf[8]);
533
+ g_assert_cmpuint(block_size, ==, 4096);
534
+
535
+ /* Write data */
536
+ memset(write_buf, rand() % 255 + 1, block_size);
537
+ ufs_send_scsi_command(ufs, 0, 1, write_cdb, write_buf, block_size, NULL, 0,
538
+ &utrd, &rsp_upiu);
539
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, OCS_SUCCESS);
540
+ g_assert_cmpuint(rsp_upiu.header.scsi_status, ==, COMMAND_RESULT_SUCESS);
541
+
542
+ /* Read data and verify */
543
+ ufs_send_scsi_command(ufs, 0, 1, read_cdb, NULL, 0, read_buf, block_size,
544
+ &utrd, &rsp_upiu);
545
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, OCS_SUCCESS);
546
+ g_assert_cmpuint(rsp_upiu.header.scsi_status, ==, COMMAND_RESULT_SUCESS);
547
+ g_assert_cmpint(memcmp(read_buf, write_buf, block_size), ==, 0);
548
+
549
+ ufs_exit(ufs, alloc);
550
+}
551
+
552
+static void drive_destroy(void *path)
553
+{
554
+ unlink(path);
555
+ g_free(path);
556
+ qos_invalidate_command_line();
557
+}
558
+
559
+static char *drive_create(void)
560
+{
561
+ int fd, ret;
562
+ char *t_path;
563
+
564
+ /* Create a temporary raw image */
565
+ fd = g_file_open_tmp("qtest-ufs.XXXXXX", &t_path, NULL);
566
+ g_assert_cmpint(fd, >=, 0);
567
+ ret = ftruncate(fd, TEST_IMAGE_SIZE);
568
+ g_assert_cmpint(ret, ==, 0);
569
+ close(fd);
570
+
571
+ g_test_queue_destroy(drive_destroy, t_path);
572
+ return t_path;
573
+}
574
+
575
+static void *ufs_blk_test_setup(GString *cmd_line, void *arg)
576
+{
577
+ char *tmp_path = drive_create();
578
+
579
+ g_string_append_printf(cmd_line,
580
+ " -blockdev file,filename=%s,node-name=drv1 "
581
+ "-device ufs-lu,bus=ufs0,drive=drv1,lun=1 ",
582
+ tmp_path);
583
+
584
+ return arg;
585
+}
586
+
587
+static void ufs_register_nodes(void)
588
+{
589
+ const char *arch;
590
+ QOSGraphEdgeOptions edge_opts = {
591
+ .before_cmd_line = "-blockdev null-co,node-name=drv0,read-zeroes=on",
592
+ .after_cmd_line = "-device ufs-lu,bus=ufs0,drive=drv0,lun=0",
593
+ .extra_device_opts = "addr=04.0,id=ufs0,nutrs=32,nutmrs=8"
594
+ };
595
+
596
+ QOSGraphTestOptions io_test_opts = {
597
+ .before = ufs_blk_test_setup,
598
+ };
599
+
600
+ add_qpci_address(&edge_opts, &(QPCIAddress){ .devfn = QPCI_DEVFN(4, 0) });
601
+
602
+ qos_node_create_driver("ufs", ufs_create);
603
+ qos_node_consumes("ufs", "pci-bus", &edge_opts);
604
+ qos_node_produces("ufs", "pci-device");
605
+
606
+ qos_add_test("reg-read", "ufs", ufstest_reg_read, NULL);
607
+
608
+ /*
609
+ * Check architecture
610
+ * TODO: Enable ufs io tests for ppc64
611
+ */
612
+ arch = qtest_get_arch();
613
+ if (!strcmp(arch, "ppc64")) {
614
+ g_test_message("Skipping ufs io tests for ppc64");
615
+ return;
616
+ }
617
+ qos_add_test("init", "ufs", ufstest_init, NULL);
618
+ qos_add_test("read-write", "ufs", ufstest_read_write, &io_test_opts);
619
+}
620
+
621
+libqos_init(ufs_register_nodes);
622
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
623
index XXXXXXX..XXXXXXX 100644
624
--- a/tests/qtest/meson.build
625
+++ b/tests/qtest/meson.build
626
@@ -XXX,XX +XXX,XX @@ qos_test_ss.add(
627
'virtio-iommu-test.c',
628
'vmxnet3-test.c',
629
'igb-test.c',
630
+ 'ufs-test.c',
631
)
632
633
if config_all_devices.has_key('CONFIG_VIRTIO_SERIAL')
74
--
634
--
75
2.21.0
635
2.41.0
76
77
diff view generated by jsdifflib
1
From: Nir Soffer <nirsof@gmail.com>
1
From: Fabiano Rosas <farosas@suse.de>
2
2
3
Using block_resize we can test allocate_first_block() with file
3
We can fail the blk_insert_bs() at init_blk_migration(), leaving the
4
descriptor opened with O_DIRECT, ensuring that it works for any size
4
BlkMigDevState without a dirty_bitmap and BlockDriverState. Account
5
larger than 4096 bytes.
5
for the possibly missing elements when doing cleanup.
6
6
7
Testing smaller sizes is tricky as the result depends on the filesystem
7
Fix the following crashes:
8
used for testing. For example on NFS any size will work since O_DIRECT
9
does not require any alignment.
10
8
11
Signed-off-by: Nir Soffer <nsoffer@redhat.com>
9
Thread 1 "qemu-system-x86" received signal SIGSEGV, Segmentation fault.
12
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
0x0000555555ec83ef in bdrv_release_dirty_bitmap (bitmap=0x0) at ../block/dirty-bitmap.c:359
13
Message-id: 20190827010528.8818-3-nsoffer@redhat.com
11
359 BlockDriverState *bs = bitmap->bs;
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
#0 0x0000555555ec83ef in bdrv_release_dirty_bitmap (bitmap=0x0) at ../block/dirty-bitmap.c:359
13
#1 0x0000555555bba331 in unset_dirty_tracking () at ../migration/block.c:371
14
#2 0x0000555555bbad98 in block_migration_cleanup_bmds () at ../migration/block.c:681
15
16
Thread 1 "qemu-system-x86" received signal SIGSEGV, Segmentation fault.
17
0x0000555555e971ff in bdrv_op_unblock (bs=0x0, op=BLOCK_OP_TYPE_BACKUP_SOURCE, reason=0x0) at ../block.c:7073
18
7073 QLIST_FOREACH_SAFE(blocker, &bs->op_blockers[op], list, next) {
19
#0 0x0000555555e971ff in bdrv_op_unblock (bs=0x0, op=BLOCK_OP_TYPE_BACKUP_SOURCE, reason=0x0) at ../block.c:7073
20
#1 0x0000555555e9734a in bdrv_op_unblock_all (bs=0x0, reason=0x0) at ../block.c:7095
21
#2 0x0000555555bbae13 in block_migration_cleanup_bmds () at ../migration/block.c:690
22
23
Signed-off-by: Fabiano Rosas <farosas@suse.de>
24
Message-id: 20230731203338.27581-1-farosas@suse.de
25
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
15
---
26
---
16
tests/qemu-iotests/175 | 28 ++++++++++++++++++++++++++++
27
migration/block.c | 11 +++++++++--
17
tests/qemu-iotests/175.out | 8 ++++++++
28
1 file changed, 9 insertions(+), 2 deletions(-)
18
2 files changed, 36 insertions(+)
19
29
20
diff --git a/tests/qemu-iotests/175 b/tests/qemu-iotests/175
30
diff --git a/migration/block.c b/migration/block.c
21
index XXXXXXX..XXXXXXX 100755
31
index XXXXXXX..XXXXXXX 100644
22
--- a/tests/qemu-iotests/175
32
--- a/migration/block.c
23
+++ b/tests/qemu-iotests/175
33
+++ b/migration/block.c
24
@@ -XXX,XX +XXX,XX @@ _filter_blocks()
34
@@ -XXX,XX +XXX,XX @@ static void unset_dirty_tracking(void)
25
-e "s/blocks=$((extra_blocks + img_size / 512))\\(\$\\|[^0-9]\\)/max allocation/"
35
BlkMigDevState *bmds;
36
37
QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
38
- bdrv_release_dirty_bitmap(bmds->dirty_bitmap);
39
+ if (bmds->dirty_bitmap) {
40
+ bdrv_release_dirty_bitmap(bmds->dirty_bitmap);
41
+ }
42
}
26
}
43
}
27
44
28
+# Resize image using block_resize.
45
@@ -XXX,XX +XXX,XX @@ static int64_t get_remaining_dirty(void)
29
+# Parameter 1: image path
46
static void block_migration_cleanup_bmds(void)
30
+# Parameter 2: new size
47
{
31
+_block_resize()
48
BlkMigDevState *bmds;
32
+{
49
+ BlockDriverState *bs;
33
+ local path=$1
50
AioContext *ctx;
34
+ local size=$2
51
52
unset_dirty_tracking();
53
54
while ((bmds = QSIMPLEQ_FIRST(&block_mig_state.bmds_list)) != NULL) {
55
QSIMPLEQ_REMOVE_HEAD(&block_mig_state.bmds_list, entry);
56
- bdrv_op_unblock_all(blk_bs(bmds->blk), bmds->blocker);
35
+
57
+
36
+ $QEMU -qmp stdio -nographic -nodefaults \
58
+ bs = blk_bs(bmds->blk);
37
+ -blockdev file,node-name=file,filename=$path,cache.direct=on \
59
+ if (bs) {
38
+ <<EOF
60
+ bdrv_op_unblock_all(bs, bmds->blocker);
39
+{'execute': 'qmp_capabilities'}
61
+ }
40
+{'execute': 'block_resize', 'arguments': {'node-name': 'file', 'size': $size}}
62
error_free(bmds->blocker);
41
+{'execute': 'quit'}
63
42
+EOF
64
/* Save ctx, because bmds->blk can disappear during blk_unref. */
43
+}
44
+
45
# get standard environment, filters and checks
46
. ./common.rc
47
. ./common.filter
48
@@ -XXX,XX +XXX,XX @@ _supported_fmt raw
49
_supported_proto file
50
_supported_os Linux
51
52
+_default_cache_mode none
53
+_supported_cache_modes none directsync
54
+
55
size=$((1 * 1024 * 1024))
56
57
touch "$TEST_DIR/empty"
58
@@ -XXX,XX +XXX,XX @@ for mode in off full falloc; do
59
stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $min_blocks $size
60
done
61
62
+for new_size in 4096 1048576; do
63
+ echo
64
+ echo "== resize empty image with block_resize =="
65
+ _make_test_img 0 | _filter_imgfmt
66
+ _block_resize $TEST_IMG $new_size >/dev/null
67
+ stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $min_blocks $new_size
68
+done
69
+
70
# success, all done
71
echo "*** done"
72
rm -f $seq.full
73
diff --git a/tests/qemu-iotests/175.out b/tests/qemu-iotests/175.out
74
index XXXXXXX..XXXXXXX 100644
75
--- a/tests/qemu-iotests/175.out
76
+++ b/tests/qemu-iotests/175.out
77
@@ -XXX,XX +XXX,XX @@ size=1048576, max allocation
78
== creating image with preallocation falloc ==
79
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 preallocation=falloc
80
size=1048576, max allocation
81
+
82
+== resize empty image with block_resize ==
83
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=0
84
+size=4096, min allocation
85
+
86
+== resize empty image with block_resize ==
87
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=0
88
+size=1048576, min allocation
89
*** done
90
--
65
--
91
2.21.0
66
2.41.0
92
93
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>
2
2
3
It's wrong to OR shared permissions. It may lead to crash on further
3
This is going to be used in the subsequent commit as requests alignment
4
permission updates.
4
(in particular, during copy-on-read). This value only makes sense for
5
Also, no needs to consider previously calculated permissions, as at
5
the formats which support subclusters (currently QCOW2 only). If this
6
this point we already bind all new parents and bdrv_get_cumulative_perm
6
field isn't set by driver's own bdrv_get_info() implementation, we
7
result is enough. So fix the bug by just set permissions by
7
simply set it equal to the cluster size thus treating each cluster as
8
bdrv_get_cumulative_perm result.
8
having a single subcluster.
9
9
10
Bug was introduced in long ago 234ac1a9025, in 2.9.
10
Reviewed-by: Eric Blake <eblake@redhat.com>
11
Reviewed-by: Denis V. Lunev <den@openvz.org>
12
Signed-off-by: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>
13
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
14
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
15
Message-ID: <20230711172553.234055-2-andrey.drobyshev@virtuozzo.com>
16
---
17
include/block/block-common.h | 5 +++++
18
block.c | 7 +++++++
19
block/qcow2.c | 1 +
20
3 files changed, 13 insertions(+)
11
21
12
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
22
diff --git a/include/block/block-common.h b/include/block/block-common.h
13
Message-id: 20190824100740.61635-1-vsementsov@virtuozzo.com
23
index XXXXXXX..XXXXXXX 100644
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
24
--- a/include/block/block-common.h
15
---
25
+++ b/include/block/block-common.h
16
block.c | 5 ++---
26
@@ -XXX,XX +XXX,XX @@ typedef struct BlockZoneWps {
17
1 file changed, 2 insertions(+), 3 deletions(-)
27
typedef struct BlockDriverInfo {
18
28
/* in bytes, 0 if irrelevant */
29
int cluster_size;
30
+ /*
31
+ * A fraction of cluster_size, if supported (currently QCOW2 only); if
32
+ * disabled or unsupported, set equal to cluster_size.
33
+ */
34
+ int subcluster_size;
35
/* offset at which the VM state can be saved (0 if not possible) */
36
int64_t vm_state_offset;
37
bool is_dirty;
19
diff --git a/block.c b/block.c
38
diff --git a/block.c b/block.c
20
index XXXXXXX..XXXXXXX 100644
39
index XXXXXXX..XXXXXXX 100644
21
--- a/block.c
40
--- a/block.c
22
+++ b/block.c
41
+++ b/block.c
23
@@ -XXX,XX +XXX,XX @@ void bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
42
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
43
}
44
memset(bdi, 0, sizeof(*bdi));
45
ret = drv->bdrv_co_get_info(bs, bdi);
46
+ if (bdi->subcluster_size == 0) {
47
+ /*
48
+ * If the driver left this unset, subclusters are not supported.
49
+ * Then it is safe to treat each cluster as having only one subcluster.
50
+ */
51
+ bdi->subcluster_size = bdi->cluster_size;
52
+ }
53
if (ret < 0) {
54
return ret;
55
}
56
diff --git a/block/qcow2.c b/block/qcow2.c
57
index XXXXXXX..XXXXXXX 100644
58
--- a/block/qcow2.c
59
+++ b/block/qcow2.c
60
@@ -XXX,XX +XXX,XX @@ qcow2_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
24
{
61
{
25
BdrvChild *c, *next;
62
BDRVQcow2State *s = bs->opaque;
26
GSList *list = NULL, *p;
63
bdi->cluster_size = s->cluster_size;
27
- uint64_t old_perm, old_shared;
64
+ bdi->subcluster_size = s->subcluster_size;
28
uint64_t perm = 0, shared = BLK_PERM_ALL;
65
bdi->vm_state_offset = qcow2_vm_state_offset(s);
29
int ret;
66
bdi->is_dirty = s->incompatible_features & QCOW2_INCOMPAT_DIRTY;
30
67
return 0;
31
@@ -XXX,XX +XXX,XX @@ void bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
32
bdrv_unref(from);
33
}
34
35
- bdrv_get_cumulative_perm(to, &old_perm, &old_shared);
36
- bdrv_set_perm(to, old_perm | perm, old_shared | shared);
37
+ bdrv_get_cumulative_perm(to, &perm, &shared);
38
+ bdrv_set_perm(to, perm, shared);
39
40
out:
41
g_slist_free(list);
42
--
68
--
43
2.21.0
69
2.41.0
44
45
diff view generated by jsdifflib
Deleted patch
1
fe646693acc changed qemu-img create's output so that it no longer prints
2
single quotes around parameter values. The subformat and adapter_type
3
filters in _filter_img_create() have never been adapted to that change.
4
1
5
Fixes: fe646693acc13ac48b98435d14149ab04dc597bc
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
Reviewed-by: John Snow <jsnow@redhat.com>
8
Message-id: 20190815153638.4600-2-mreitz@redhat.com
9
Reviewed-by: John Snow <jsnow@redhat.com>
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
---
12
tests/qemu-iotests/059.out | 16 ++++++++--------
13
tests/qemu-iotests/common.filter | 4 ++--
14
2 files changed, 10 insertions(+), 10 deletions(-)
15
16
diff --git a/tests/qemu-iotests/059.out b/tests/qemu-iotests/059.out
17
index XXXXXXX..XXXXXXX 100644
18
--- a/tests/qemu-iotests/059.out
19
+++ b/tests/qemu-iotests/059.out
20
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
21
qemu-io: can't open device TEST_DIR/t.vmdk: L1 size too big
22
23
=== Testing monolithicFlat creation and opening ===
24
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2147483648 subformat=monolithicFlat
25
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2147483648
26
image: TEST_DIR/t.IMGFMT
27
file format: IMGFMT
28
virtual size: 2 GiB (2147483648 bytes)
29
30
=== Testing monolithicFlat with zeroed_grain ===
31
qemu-img: TEST_DIR/t.IMGFMT: Flat image can't enable zeroed grain
32
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2147483648 subformat=monolithicFlat
33
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2147483648
34
35
=== Testing big twoGbMaxExtentFlat ===
36
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824000 subformat=twoGbMaxExtentFlat
37
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824000
38
image: TEST_DIR/t.vmdk
39
file format: vmdk
40
virtual size: 0.977 TiB (1073741824000 bytes)
41
@@ -XXX,XX +XXX,XX @@ Format specific information:
42
qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Invalid extent line: RW 12582912 VMFS "dummy.IMGFMT" 1
43
44
=== Testing truncated sparse ===
45
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=107374182400 subformat=monolithicSparse
46
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=107374182400
47
qemu-img: Could not open 'TEST_DIR/t.IMGFMT': File truncated, expecting at least 13172736 bytes
48
49
=== Converting to streamOptimized from image with small cluster size===
50
@@ -XXX,XX +XXX,XX @@ wrote 512/512 bytes at offset 10240
51
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
52
53
=== Testing monolithicFlat with internally generated JSON file name ===
54
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 subformat=monolithicFlat
55
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
56
qemu-io: can't open: Cannot use relative extent paths with VMDK descriptor file 'json:{"image": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "driver": "blkdebug", "inject-error.0.event": "read_aio"}'
57
58
=== Testing version 3 ===
59
@@ -XXX,XX +XXX,XX @@ read 512/512 bytes at offset 64931328
60
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
61
62
=== Testing 4TB monolithicFlat creation and IO ===
63
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4398046511104 subformat=monolithicFlat
64
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4398046511104
65
image: TEST_DIR/t.IMGFMT
66
file format: IMGFMT
67
virtual size: 4 TiB (4398046511104 bytes)
68
@@ -XXX,XX +XXX,XX @@ read 1024/1024 bytes at offset 966367641600
69
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
70
71
=== Testing qemu-img map on extents ===
72
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33285996544 subformat=monolithicSparse
73
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33285996544
74
wrote 1024/1024 bytes at offset 65024
75
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
76
wrote 1024/1024 bytes at offset 2147483136
77
@@ -XXX,XX +XXX,XX @@ Offset Length Mapped to File
78
0 0x20000 0x3f0000 TEST_DIR/t.vmdk
79
0x7fff0000 0x20000 0x410000 TEST_DIR/t.vmdk
80
0x140000000 0x10000 0x430000 TEST_DIR/t.vmdk
81
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33285996544 subformat=twoGbMaxExtentSparse
82
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33285996544
83
wrote 1024/1024 bytes at offset 65024
84
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
85
wrote 1024/1024 bytes at offset 2147483136
86
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
87
index XXXXXXX..XXXXXXX 100644
88
--- a/tests/qemu-iotests/common.filter
89
+++ b/tests/qemu-iotests/common.filter
90
@@ -XXX,XX +XXX,XX @@ _filter_img_create()
91
-e "s# compat6=\\(on\\|off\\)##g" \
92
-e "s# static=\\(on\\|off\\)##g" \
93
-e "s# zeroed_grain=\\(on\\|off\\)##g" \
94
- -e "s# subformat='[^']*'##g" \
95
- -e "s# adapter_type='[^']*'##g" \
96
+ -e "s# subformat=[^ ]*##g" \
97
+ -e "s# adapter_type=[^ ]*##g" \
98
-e "s# hwversion=[^ ]*##g" \
99
-e "s# lazy_refcounts=\\(on\\|off\\)##g" \
100
-e "s# block_size=[0-9]\\+##g" \
101
--
102
2.21.0
103
104
diff view generated by jsdifflib
1
This makes iotest 033 pass with e.g. subformat=monolithicFlat. It also
1
From: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>
2
turns a former error in 059 into success.
2
3
3
When target image is using subclusters, and we align the request during
4
Signed-off-by: Max Reitz <mreitz@redhat.com>
4
copy-on-read, it makes sense to align to subcluster_size rather than
5
Message-id: 20190815153638.4600-3-mreitz@redhat.com
5
cluster_size. Otherwise we end up with unnecessary allocations.
6
Reviewed-by: John Snow <jsnow@redhat.com>
6
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
This commit renames bdrv_round_to_clusters() to bdrv_round_to_subclusters()
8
and utilizes subcluster_size field of BlockDriverInfo to make necessary
9
alignments. It affects copy-on-read as well as mirror job (which is
10
using bdrv_round_to_clusters()).
11
12
This change also fixes the following bug with failing assert (covered by
13
the test in the subsequent commit):
14
15
qemu-img create -f qcow2 base.qcow2 64K
16
qemu-img create -f qcow2 -o extended_l2=on,backing_file=base.qcow2,backing_fmt=qcow2 img.qcow2 64K
17
qemu-io -c "write -P 0xaa 0 2K" img.qcow2
18
qemu-io -C -c "read -P 0x00 2K 62K" img.qcow2
19
20
qemu-io: ../block/io.c:1236: bdrv_co_do_copy_on_readv: Assertion `skip_bytes < pnum' failed.
21
22
Reviewed-by: Eric Blake <eblake@redhat.com>
23
Reviewed-by: Denis V. Lunev <den@openvz.org>
24
Signed-off-by: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>
25
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
26
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
27
Message-ID: <20230711172553.234055-3-andrey.drobyshev@virtuozzo.com>
8
---
28
---
9
block/vmdk.c | 54 ++++++++++++++++++++++++--------------
29
include/block/block-io.h | 8 +++----
10
tests/qemu-iotests/059 | 7 +++--
30
block/io.c | 50 ++++++++++++++++++++--------------------
11
tests/qemu-iotests/059.out | 4 ++-
31
block/mirror.c | 8 +++----
12
3 files changed, 42 insertions(+), 23 deletions(-)
32
3 files changed, 33 insertions(+), 33 deletions(-)
13
33
14
diff --git a/block/vmdk.c b/block/vmdk.c
34
diff --git a/include/block/block-io.h b/include/block/block-io.h
15
index XXXXXXX..XXXXXXX 100644
35
index XXXXXXX..XXXXXXX 100644
16
--- a/block/vmdk.c
36
--- a/include/block/block-io.h
17
+++ b/block/vmdk.c
37
+++ b/include/block/block-io.h
18
@@ -XXX,XX +XXX,XX @@ static const char *next_line(const char *s)
38
@@ -XXX,XX +XXX,XX @@ bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi);
39
ImageInfoSpecific *bdrv_get_specific_info(BlockDriverState *bs,
40
Error **errp);
41
BlockStatsSpecific *bdrv_get_specific_stats(BlockDriverState *bs);
42
-void bdrv_round_to_clusters(BlockDriverState *bs,
43
- int64_t offset, int64_t bytes,
44
- int64_t *cluster_offset,
45
- int64_t *cluster_bytes);
46
+void bdrv_round_to_subclusters(BlockDriverState *bs,
47
+ int64_t offset, int64_t bytes,
48
+ int64_t *cluster_offset,
49
+ int64_t *cluster_bytes);
50
51
void bdrv_get_backing_filename(BlockDriverState *bs,
52
char *filename, int filename_size);
53
diff --git a/block/io.c b/block/io.c
54
index XXXXXXX..XXXXXXX 100644
55
--- a/block/io.c
56
+++ b/block/io.c
57
@@ -XXX,XX +XXX,XX @@ BdrvTrackedRequest *coroutine_fn bdrv_co_get_self_request(BlockDriverState *bs)
19
}
58
}
20
59
21
static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
60
/**
22
- const char *desc_file_path, QDict *options,
61
- * Round a region to cluster boundaries
23
- Error **errp)
62
+ * Round a region to subcluster (if supported) or cluster boundaries
24
+ QDict *options, Error **errp)
63
*/
64
void coroutine_fn GRAPH_RDLOCK
65
-bdrv_round_to_clusters(BlockDriverState *bs, int64_t offset, int64_t bytes,
66
- int64_t *cluster_offset, int64_t *cluster_bytes)
67
+bdrv_round_to_subclusters(BlockDriverState *bs, int64_t offset, int64_t bytes,
68
+ int64_t *align_offset, int64_t *align_bytes)
25
{
69
{
70
BlockDriverInfo bdi;
71
IO_CODE();
72
- if (bdrv_co_get_info(bs, &bdi) < 0 || bdi.cluster_size == 0) {
73
- *cluster_offset = offset;
74
- *cluster_bytes = bytes;
75
+ if (bdrv_co_get_info(bs, &bdi) < 0 || bdi.subcluster_size == 0) {
76
+ *align_offset = offset;
77
+ *align_bytes = bytes;
78
} else {
79
- int64_t c = bdi.cluster_size;
80
- *cluster_offset = QEMU_ALIGN_DOWN(offset, c);
81
- *cluster_bytes = QEMU_ALIGN_UP(offset - *cluster_offset + bytes, c);
82
+ int64_t c = bdi.subcluster_size;
83
+ *align_offset = QEMU_ALIGN_DOWN(offset, c);
84
+ *align_bytes = QEMU_ALIGN_UP(offset - *align_offset + bytes, c);
85
}
86
}
87
88
@@ -XXX,XX +XXX,XX @@ bdrv_co_do_copy_on_readv(BdrvChild *child, int64_t offset, int64_t bytes,
89
void *bounce_buffer = NULL;
90
91
BlockDriver *drv = bs->drv;
92
- int64_t cluster_offset;
93
- int64_t cluster_bytes;
94
+ int64_t align_offset;
95
+ int64_t align_bytes;
96
int64_t skip_bytes;
26
int ret;
97
int ret;
27
int matches;
98
int max_transfer = MIN_NON_ZERO(bs->bl.max_transfer,
28
@@ -XXX,XX +XXX,XX @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
99
@@ -XXX,XX +XXX,XX @@ bdrv_co_do_copy_on_readv(BdrvChild *child, int64_t offset, int64_t bytes,
29
const char *p, *np;
100
* BDRV_REQUEST_MAX_BYTES (even when the original read did not), which
30
int64_t sectors = 0;
101
* is one reason we loop rather than doing it all at once.
31
int64_t flat_offset;
102
*/
32
+ char *desc_file_dir = NULL;
103
- bdrv_round_to_clusters(bs, offset, bytes, &cluster_offset, &cluster_bytes);
33
char *extent_path;
104
- skip_bytes = offset - cluster_offset;
34
BdrvChild *extent_file;
105
+ bdrv_round_to_subclusters(bs, offset, bytes, &align_offset, &align_bytes);
35
BDRVVmdkState *s = bs->opaque;
106
+ skip_bytes = offset - align_offset;
36
@@ -XXX,XX +XXX,XX @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
107
37
continue;
108
trace_bdrv_co_do_copy_on_readv(bs, offset, bytes,
109
- cluster_offset, cluster_bytes);
110
+ align_offset, align_bytes);
111
112
- while (cluster_bytes) {
113
+ while (align_bytes) {
114
int64_t pnum;
115
116
if (skip_write) {
117
ret = 1; /* "already allocated", so nothing will be copied */
118
- pnum = MIN(cluster_bytes, max_transfer);
119
+ pnum = MIN(align_bytes, max_transfer);
120
} else {
121
- ret = bdrv_is_allocated(bs, cluster_offset,
122
- MIN(cluster_bytes, max_transfer), &pnum);
123
+ ret = bdrv_is_allocated(bs, align_offset,
124
+ MIN(align_bytes, max_transfer), &pnum);
125
if (ret < 0) {
126
/*
127
* Safe to treat errors in querying allocation as if
128
* unallocated; we'll probably fail again soon on the
129
* read, but at least that will set a decent errno.
130
*/
131
- pnum = MIN(cluster_bytes, max_transfer);
132
+ pnum = MIN(align_bytes, max_transfer);
133
}
134
135
/* Stop at EOF if the image ends in the middle of the cluster */
136
@@ -XXX,XX +XXX,XX @@ bdrv_co_do_copy_on_readv(BdrvChild *child, int64_t offset, int64_t bytes,
137
/* Must copy-on-read; use the bounce buffer */
138
pnum = MIN(pnum, MAX_BOUNCE_BUFFER);
139
if (!bounce_buffer) {
140
- int64_t max_we_need = MAX(pnum, cluster_bytes - pnum);
141
+ int64_t max_we_need = MAX(pnum, align_bytes - pnum);
142
int64_t max_allowed = MIN(max_transfer, MAX_BOUNCE_BUFFER);
143
int64_t bounce_buffer_len = MIN(max_we_need, max_allowed);
144
145
@@ -XXX,XX +XXX,XX @@ bdrv_co_do_copy_on_readv(BdrvChild *child, int64_t offset, int64_t bytes,
146
}
147
qemu_iovec_init_buf(&local_qiov, bounce_buffer, pnum);
148
149
- ret = bdrv_driver_preadv(bs, cluster_offset, pnum,
150
+ ret = bdrv_driver_preadv(bs, align_offset, pnum,
151
&local_qiov, 0, 0);
152
if (ret < 0) {
153
goto err;
154
@@ -XXX,XX +XXX,XX @@ bdrv_co_do_copy_on_readv(BdrvChild *child, int64_t offset, int64_t bytes,
155
/* FIXME: Should we (perhaps conditionally) be setting
156
* BDRV_REQ_MAY_UNMAP, if it will allow for a sparser copy
157
* that still correctly reads as zero? */
158
- ret = bdrv_co_do_pwrite_zeroes(bs, cluster_offset, pnum,
159
+ ret = bdrv_co_do_pwrite_zeroes(bs, align_offset, pnum,
160
BDRV_REQ_WRITE_UNCHANGED);
161
} else {
162
/* This does not change the data on the disk, it is not
163
* necessary to flush even in cache=writethrough mode.
164
*/
165
- ret = bdrv_driver_pwritev(bs, cluster_offset, pnum,
166
+ ret = bdrv_driver_pwritev(bs, align_offset, pnum,
167
&local_qiov, 0,
168
BDRV_REQ_WRITE_UNCHANGED);
169
}
170
@@ -XXX,XX +XXX,XX @@ bdrv_co_do_copy_on_readv(BdrvChild *child, int64_t offset, int64_t bytes,
171
}
38
}
172
}
39
173
40
- if (!path_is_absolute(fname) && !path_has_protocol(fname) &&
174
- cluster_offset += pnum;
41
- !desc_file_path[0])
175
- cluster_bytes -= pnum;
42
- {
176
+ align_offset += pnum;
43
- bdrv_refresh_filename(bs->file->bs);
177
+ align_bytes -= pnum;
44
- error_setg(errp, "Cannot use relative extent paths with VMDK "
178
progress += pnum - skip_bytes;
45
- "descriptor file '%s'", bs->file->bs->filename);
179
skip_bytes = 0;
46
- return -EINVAL;
47
- }
48
+ if (path_is_absolute(fname)) {
49
+ extent_path = g_strdup(fname);
50
+ } else {
51
+ if (!desc_file_dir) {
52
+ desc_file_dir = bdrv_dirname(bs->file->bs, errp);
53
+ if (!desc_file_dir) {
54
+ bdrv_refresh_filename(bs->file->bs);
55
+ error_prepend(errp, "Cannot use relative paths with VMDK "
56
+ "descriptor file '%s': ",
57
+ bs->file->bs->filename);
58
+ ret = -EINVAL;
59
+ goto out;
60
+ }
61
+ }
62
63
- extent_path = path_combine(desc_file_path, fname);
64
+ extent_path = g_strconcat(desc_file_dir, fname, NULL);
65
+ }
66
67
ret = snprintf(extent_opt_prefix, 32, "extents.%d", s->num_extents);
68
assert(ret < 32);
69
@@ -XXX,XX +XXX,XX @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
70
g_free(extent_path);
71
if (local_err) {
72
error_propagate(errp, local_err);
73
- return -EINVAL;
74
+ ret = -EINVAL;
75
+ goto out;
76
}
77
78
/* save to extents array */
79
@@ -XXX,XX +XXX,XX @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
80
0, 0, 0, 0, 0, &extent, errp);
81
if (ret < 0) {
82
bdrv_unref_child(bs, extent_file);
83
- return ret;
84
+ goto out;
85
}
86
extent->flat_start_offset = flat_offset << 9;
87
} else if (!strcmp(type, "SPARSE") || !strcmp(type, "VMFSSPARSE")) {
88
@@ -XXX,XX +XXX,XX @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
89
g_free(buf);
90
if (ret) {
91
bdrv_unref_child(bs, extent_file);
92
- return ret;
93
+ goto out;
94
}
95
extent = &s->extents[s->num_extents - 1];
96
} else if (!strcmp(type, "SESPARSE")) {
97
ret = vmdk_open_se_sparse(bs, extent_file, bs->open_flags, errp);
98
if (ret) {
99
bdrv_unref_child(bs, extent_file);
100
- return ret;
101
+ goto out;
102
}
103
extent = &s->extents[s->num_extents - 1];
104
} else {
105
error_setg(errp, "Unsupported extent type '%s'", type);
106
bdrv_unref_child(bs, extent_file);
107
- return -ENOTSUP;
108
+ ret = -ENOTSUP;
109
+ goto out;
110
}
111
extent->type = g_strdup(type);
112
}
180
}
113
- return 0;
181
diff --git a/block/mirror.c b/block/mirror.c
114
+
182
index XXXXXXX..XXXXXXX 100644
115
+ ret = 0;
183
--- a/block/mirror.c
116
+ goto out;
184
+++ b/block/mirror.c
117
185
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_cow_align(MirrorBlockJob *s, int64_t *offset,
118
invalid:
186
need_cow |= !test_bit((*offset + *bytes - 1) / s->granularity,
119
np = next_line(p);
187
s->cow_bitmap);
120
@@ -XXX,XX +XXX,XX @@ invalid:
188
if (need_cow) {
121
np--;
189
- bdrv_round_to_clusters(blk_bs(s->target), *offset, *bytes,
190
- &align_offset, &align_bytes);
191
+ bdrv_round_to_subclusters(blk_bs(s->target), *offset, *bytes,
192
+ &align_offset, &align_bytes);
122
}
193
}
123
error_setg(errp, "Invalid extent line: %.*s", (int)(np - p), p);
194
124
- return -EINVAL;
195
if (align_bytes > max_bytes) {
125
+ ret = -EINVAL;
196
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn mirror_iteration(MirrorBlockJob *s)
126
+
197
int64_t target_offset;
127
+out:
198
int64_t target_bytes;
128
+ g_free(desc_file_dir);
199
WITH_GRAPH_RDLOCK_GUARD() {
129
+ return ret;
200
- bdrv_round_to_clusters(blk_bs(s->target), offset, io_bytes,
130
}
201
- &target_offset, &target_bytes);
131
202
+ bdrv_round_to_subclusters(blk_bs(s->target), offset, io_bytes,
132
static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf,
203
+ &target_offset, &target_bytes);
133
@@ -XXX,XX +XXX,XX @@ static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf,
204
}
134
}
205
if (target_offset == offset &&
135
s->create_type = g_strdup(ct);
206
target_bytes == io_bytes) {
136
s->desc_offset = 0;
137
- ret = vmdk_parse_extents(buf, bs, bs->file->bs->exact_filename, options,
138
- errp);
139
+ ret = vmdk_parse_extents(buf, bs, options, errp);
140
exit:
141
return ret;
142
}
143
diff --git a/tests/qemu-iotests/059 b/tests/qemu-iotests/059
144
index XXXXXXX..XXXXXXX 100755
145
--- a/tests/qemu-iotests/059
146
+++ b/tests/qemu-iotests/059
147
@@ -XXX,XX +XXX,XX @@ $QEMU_IMG convert -f qcow2 -O vmdk -o subformat=streamOptimized "$TEST_IMG.qcow2
148
149
echo
150
echo "=== Testing monolithicFlat with internally generated JSON file name ==="
151
+# Should work, because bdrv_dirname() works fine with blkdebug
152
IMGOPTS="subformat=monolithicFlat" _make_test_img 64M
153
-$QEMU_IO -c "open -o driver=$IMGFMT,file.driver=blkdebug,file.image.filename=$TEST_IMG,file.inject-error.0.event=read_aio" 2>&1 \
154
- | _filter_testdir | _filter_imgfmt
155
+$QEMU_IO -c "open -o driver=$IMGFMT,file.driver=blkdebug,file.image.filename=$TEST_IMG,file.inject-error.0.event=read_aio" \
156
+ -c info \
157
+ 2>&1 \
158
+ | _filter_testdir | _filter_imgfmt | _filter_img_info
159
_cleanup_test_img
160
161
echo
162
diff --git a/tests/qemu-iotests/059.out b/tests/qemu-iotests/059.out
163
index XXXXXXX..XXXXXXX 100644
164
--- a/tests/qemu-iotests/059.out
165
+++ b/tests/qemu-iotests/059.out
166
@@ -XXX,XX +XXX,XX @@ wrote 512/512 bytes at offset 10240
167
168
=== Testing monolithicFlat with internally generated JSON file name ===
169
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
170
-qemu-io: can't open: Cannot use relative extent paths with VMDK descriptor file 'json:{"image": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "driver": "blkdebug", "inject-error.0.event": "read_aio"}'
171
+format name: IMGFMT
172
+cluster size: 0 bytes
173
+vm state offset: 0 bytes
174
175
=== Testing version 3 ===
176
image: TEST_DIR/iotest-version3.IMGFMT
177
--
207
--
178
2.21.0
208
2.41.0
179
180
diff view generated by jsdifflib
Deleted patch
1
We had a test for a case where relative extent paths did not work, but
2
unfortunately we just fixed the underlying problem, so it works now.
3
This patch adds a new test case that still fails.
4
1
5
Signed-off-by: Max Reitz <mreitz@redhat.com>
6
Reviewed-by: John Snow <jsnow@redhat.com>
7
Message-id: 20190815153638.4600-4-mreitz@redhat.com
8
Reviewed-by: John Snow <jsnow@redhat.com>
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
---
11
tests/qemu-iotests/059 | 27 +++++++++++++++++++++++++++
12
tests/qemu-iotests/059.out | 4 ++++
13
2 files changed, 31 insertions(+)
14
15
diff --git a/tests/qemu-iotests/059 b/tests/qemu-iotests/059
16
index XXXXXXX..XXXXXXX 100755
17
--- a/tests/qemu-iotests/059
18
+++ b/tests/qemu-iotests/059
19
@@ -XXX,XX +XXX,XX @@ $QEMU_IMG convert -f qcow2 -O vmdk -o subformat=streamOptimized "$TEST_IMG.qcow2
20
21
echo
22
echo "=== Testing monolithicFlat with internally generated JSON file name ==="
23
+
24
+echo '--- blkdebug ---'
25
# Should work, because bdrv_dirname() works fine with blkdebug
26
IMGOPTS="subformat=monolithicFlat" _make_test_img 64M
27
$QEMU_IO -c "open -o driver=$IMGFMT,file.driver=blkdebug,file.image.filename=$TEST_IMG,file.inject-error.0.event=read_aio" \
28
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c "open -o driver=$IMGFMT,file.driver=blkdebug,file.image.filename=$TE
29
| _filter_testdir | _filter_imgfmt | _filter_img_info
30
_cleanup_test_img
31
32
+echo '--- quorum ---'
33
+# Should not work, because bdrv_dirname() does not work with quorum
34
+IMGOPTS="subformat=monolithicFlat" _make_test_img 64M
35
+cp "$TEST_IMG" "$TEST_IMG.orig"
36
+
37
+filename="json:{
38
+ \"driver\": \"$IMGFMT\",
39
+ \"file\": {
40
+ \"driver\": \"quorum\",
41
+ \"children\": [ {
42
+ \"driver\": \"file\",
43
+ \"filename\": \"$TEST_IMG\"
44
+ }, {
45
+ \"driver\": \"file\",
46
+ \"filename\": \"$TEST_IMG.orig\"
47
+ } ],
48
+ \"vote-threshold\": 1
49
+ } }"
50
+
51
+filename=$(echo "$filename" | tr '\n' ' ' | sed -e 's/\s\+/ /g')
52
+$QEMU_IMG info "$filename" 2>&1 \
53
+ | sed -e "s/'json:[^']*'/\$QUORUM_FILE/g" \
54
+ | _filter_testdir | _filter_imgfmt | _filter_img_info
55
+
56
+
57
echo
58
echo "=== Testing version 3 ==="
59
_use_sample_img iotest-version3.vmdk.bz2
60
diff --git a/tests/qemu-iotests/059.out b/tests/qemu-iotests/059.out
61
index XXXXXXX..XXXXXXX 100644
62
--- a/tests/qemu-iotests/059.out
63
+++ b/tests/qemu-iotests/059.out
64
@@ -XXX,XX +XXX,XX @@ wrote 512/512 bytes at offset 10240
65
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
66
67
=== Testing monolithicFlat with internally generated JSON file name ===
68
+--- blkdebug ---
69
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
70
format name: IMGFMT
71
cluster size: 0 bytes
72
vm state offset: 0 bytes
73
+--- quorum ---
74
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
75
+qemu-img: Could not open $QUORUM_FILE: Cannot use relative paths with VMDK descriptor file $QUORUM_FILE: Cannot generate a base directory for quorum nodes
76
77
=== Testing version 3 ===
78
image: TEST_DIR/iotest-version3.IMGFMT
79
--
80
2.21.0
81
82
diff view generated by jsdifflib
Deleted patch
1
Compressed writes generally have to write full clusters, not just in
2
theory but also in practice when it comes to vmdk's streamOptimized
3
subformat. It currently is just silently broken for writes with
4
non-zero in-cluster offsets:
5
1
6
$ qemu-img create -f vmdk -o subformat=streamOptimized foo.vmdk 1M
7
$ qemu-io -c 'write 4k 4k' -c 'read 4k 4k' foo.vmdk
8
wrote 4096/4096 bytes at offset 4096
9
4 KiB, 1 ops; 00.01 sec (443.724 KiB/sec and 110.9309 ops/sec)
10
read failed: Invalid argument
11
12
(The technical reason is that vmdk_write_extent() just writes the
13
incomplete compressed data actually to offset 4k. When reading the
14
data, vmdk_read_extent() looks at offset 0 and finds the compressed data
15
size to be 0, because that is what it reads from there. This yields an
16
error.)
17
18
For incomplete writes with zero in-cluster offsets, the error path when
19
reading the rest of the cluster is a bit different, but the result is
20
the same:
21
22
$ qemu-img create -f vmdk -o subformat=streamOptimized foo.vmdk 1M
23
$ qemu-io -c 'write 0k 4k' -c 'read 4k 4k' foo.vmdk
24
wrote 4096/4096 bytes at offset 0
25
4 KiB, 1 ops; 00.01 sec (362.641 KiB/sec and 90.6603 ops/sec)
26
read failed: Invalid argument
27
28
(Here, vmdk_read_extent() finds the data and then sees that the
29
uncompressed data is short.)
30
31
It is better to reject invalid writes than to make the user believe they
32
might have succeeded and then fail when trying to read it back.
33
34
Signed-off-by: Max Reitz <mreitz@redhat.com>
35
Reviewed-by: John Snow <jsnow@redhat.com>
36
Message-id: 20190815153638.4600-5-mreitz@redhat.com
37
Reviewed-by: John Snow <jsnow@redhat.com>
38
Signed-off-by: Max Reitz <mreitz@redhat.com>
39
---
40
block/vmdk.c | 10 ++++++++++
41
1 file changed, 10 insertions(+)
42
43
diff --git a/block/vmdk.c b/block/vmdk.c
44
index XXXXXXX..XXXXXXX 100644
45
--- a/block/vmdk.c
46
+++ b/block/vmdk.c
47
@@ -XXX,XX +XXX,XX @@ static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset,
48
if (extent->compressed) {
49
void *compressed_data;
50
51
+ /* Only whole clusters */
52
+ if (offset_in_cluster ||
53
+ n_bytes > (extent->cluster_sectors * SECTOR_SIZE) ||
54
+ (n_bytes < (extent->cluster_sectors * SECTOR_SIZE) &&
55
+ offset + n_bytes != extent->end_sector * SECTOR_SIZE))
56
+ {
57
+ ret = -EINVAL;
58
+ goto out;
59
+ }
60
+
61
if (!extent->has_marker) {
62
ret = -EINVAL;
63
goto out;
64
--
65
2.21.0
66
67
diff view generated by jsdifflib
1
streamOptimized does not support writes that do not span exactly one
1
From: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>
2
cluster. Furthermore, it cannot rewrite already allocated clusters.
3
As such, many iotests do not work with it. Disable them.
4
2
5
Signed-off-by: Max Reitz <mreitz@redhat.com>
3
Add testcase which checks that allocations during copy-on-read are
6
Message-id: 20190815153638.4600-6-mreitz@redhat.com
4
performed on the subcluster basis when subclusters are enabled in target
7
Reviewed-by: John Snow <jsnow@redhat.com>
5
image.
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
6
7
This testcase also triggers the following assert with previous commit
8
not being applied, so we check that as well:
9
10
qemu-io: ../block/io.c:1236: bdrv_co_do_copy_on_readv: Assertion `skip_bytes < pnum' failed.
11
12
Reviewed-by: Eric Blake <eblake@redhat.com>
13
Reviewed-by: Denis V. Lunev <den@openvz.org>
14
Signed-off-by: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>
15
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
16
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
17
Message-ID: <20230711172553.234055-4-andrey.drobyshev@virtuozzo.com>
9
---
18
---
10
tests/qemu-iotests/002 | 1 +
19
tests/qemu-iotests/197 | 29 +++++++++++++++++++++++++++++
11
tests/qemu-iotests/003 | 1 +
20
tests/qemu-iotests/197.out | 24 ++++++++++++++++++++++++
12
tests/qemu-iotests/005 | 3 ++-
21
2 files changed, 53 insertions(+)
13
tests/qemu-iotests/009 | 1 +
14
tests/qemu-iotests/010 | 1 +
15
tests/qemu-iotests/011 | 1 +
16
tests/qemu-iotests/017 | 3 ++-
17
tests/qemu-iotests/018 | 3 ++-
18
tests/qemu-iotests/019 | 3 ++-
19
tests/qemu-iotests/020 | 3 ++-
20
tests/qemu-iotests/027 | 1 +
21
tests/qemu-iotests/032 | 1 +
22
tests/qemu-iotests/033 | 1 +
23
tests/qemu-iotests/034 | 3 ++-
24
tests/qemu-iotests/037 | 3 ++-
25
tests/qemu-iotests/063 | 3 ++-
26
tests/qemu-iotests/072 | 1 +
27
tests/qemu-iotests/105 | 3 ++-
28
tests/qemu-iotests/197 | 1 +
29
tests/qemu-iotests/215 | 1 +
30
tests/qemu-iotests/251 | 1 +
31
21 files changed, 30 insertions(+), 9 deletions(-)
32
22
33
diff --git a/tests/qemu-iotests/002 b/tests/qemu-iotests/002
34
index XXXXXXX..XXXXXXX 100755
35
--- a/tests/qemu-iotests/002
36
+++ b/tests/qemu-iotests/002
37
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
38
39
_supported_fmt generic
40
_supported_proto generic
41
+_unsupported_imgopts "subformat=streamOptimized"
42
43
44
size=128M
45
diff --git a/tests/qemu-iotests/003 b/tests/qemu-iotests/003
46
index XXXXXXX..XXXXXXX 100755
47
--- a/tests/qemu-iotests/003
48
+++ b/tests/qemu-iotests/003
49
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
50
51
_supported_fmt generic
52
_supported_proto generic
53
+_unsupported_imgopts "subformat=streamOptimized"
54
55
size=128M
56
offset=67M
57
diff --git a/tests/qemu-iotests/005 b/tests/qemu-iotests/005
58
index XXXXXXX..XXXXXXX 100755
59
--- a/tests/qemu-iotests/005
60
+++ b/tests/qemu-iotests/005
61
@@ -XXX,XX +XXX,XX @@ _supported_fmt generic
62
_supported_proto generic
63
_supported_os Linux
64
_unsupported_imgopts "subformat=twoGbMaxExtentFlat" \
65
- "subformat=twoGbMaxExtentSparse"
66
+ "subformat=twoGbMaxExtentSparse" \
67
+ "subformat=streamOptimized"
68
69
# vpc is limited to 127GB, so we can't test it here
70
if [ "$IMGFMT" = "vpc" ]; then
71
diff --git a/tests/qemu-iotests/009 b/tests/qemu-iotests/009
72
index XXXXXXX..XXXXXXX 100755
73
--- a/tests/qemu-iotests/009
74
+++ b/tests/qemu-iotests/009
75
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
76
77
_supported_fmt generic
78
_supported_proto generic
79
+_unsupported_imgopts "subformat=streamOptimized"
80
81
82
size=6G
83
diff --git a/tests/qemu-iotests/010 b/tests/qemu-iotests/010
84
index XXXXXXX..XXXXXXX 100755
85
--- a/tests/qemu-iotests/010
86
+++ b/tests/qemu-iotests/010
87
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
88
89
_supported_fmt generic
90
_supported_proto generic
91
+_unsupported_imgopts "subformat=streamOptimized"
92
93
94
size=6G
95
diff --git a/tests/qemu-iotests/011 b/tests/qemu-iotests/011
96
index XXXXXXX..XXXXXXX 100755
97
--- a/tests/qemu-iotests/011
98
+++ b/tests/qemu-iotests/011
99
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
100
101
_supported_fmt generic
102
_supported_proto generic
103
+_unsupported_imgopts "subformat=streamOptimized"
104
105
106
size=6G
107
diff --git a/tests/qemu-iotests/017 b/tests/qemu-iotests/017
108
index XXXXXXX..XXXXXXX 100755
109
--- a/tests/qemu-iotests/017
110
+++ b/tests/qemu-iotests/017
111
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
112
_supported_fmt qcow qcow2 vmdk qed
113
_supported_proto generic
114
_unsupported_proto vxhs
115
-_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat"
116
+_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat" \
117
+ "subformat=streamOptimized"
118
119
TEST_OFFSETS="0 4294967296"
120
121
diff --git a/tests/qemu-iotests/018 b/tests/qemu-iotests/018
122
index XXXXXXX..XXXXXXX 100755
123
--- a/tests/qemu-iotests/018
124
+++ b/tests/qemu-iotests/018
125
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
126
_supported_fmt qcow qcow2 vmdk qed
127
_supported_proto file
128
_supported_os Linux
129
-_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat"
130
+_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat" \
131
+ "streamOptimized"
132
133
TEST_OFFSETS="0 4294967296"
134
135
diff --git a/tests/qemu-iotests/019 b/tests/qemu-iotests/019
136
index XXXXXXX..XXXXXXX 100755
137
--- a/tests/qemu-iotests/019
138
+++ b/tests/qemu-iotests/019
139
@@ -XXX,XX +XXX,XX @@ _supported_proto file
140
_supported_os Linux
141
_unsupported_imgopts "subformat=monolithicFlat" \
142
"subformat=twoGbMaxExtentFlat" \
143
- "subformat=twoGbMaxExtentSparse"
144
+ "subformat=twoGbMaxExtentSparse" \
145
+ "subformat=streamOptimized"
146
147
TEST_OFFSETS="0 4294967296"
148
CLUSTER_SIZE=65536
149
diff --git a/tests/qemu-iotests/020 b/tests/qemu-iotests/020
150
index XXXXXXX..XXXXXXX 100755
151
--- a/tests/qemu-iotests/020
152
+++ b/tests/qemu-iotests/020
153
@@ -XXX,XX +XXX,XX @@ _supported_fmt qcow qcow2 vmdk qed
154
_supported_proto file
155
_unsupported_imgopts "subformat=monolithicFlat" \
156
"subformat=twoGbMaxExtentFlat" \
157
- "subformat=twoGbMaxExtentSparse"
158
+ "subformat=twoGbMaxExtentSparse" \
159
+ "subformat=streamOptimized"
160
161
TEST_OFFSETS="0 4294967296"
162
163
diff --git a/tests/qemu-iotests/027 b/tests/qemu-iotests/027
164
index XXXXXXX..XXXXXXX 100755
165
--- a/tests/qemu-iotests/027
166
+++ b/tests/qemu-iotests/027
167
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
168
169
_supported_fmt vmdk qcow qcow2 qed
170
_supported_proto generic
171
+_unsupported_imgopts "subformat=streamOptimized"
172
173
174
size=128M
175
diff --git a/tests/qemu-iotests/032 b/tests/qemu-iotests/032
176
index XXXXXXX..XXXXXXX 100755
177
--- a/tests/qemu-iotests/032
178
+++ b/tests/qemu-iotests/032
179
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
180
# This works for any image format (though unlikely to segfault for raw)
181
_supported_fmt generic
182
_supported_proto generic
183
+_unsupported_imgopts "subformat=streamOptimized"
184
185
echo
186
echo === Prepare image ===
187
diff --git a/tests/qemu-iotests/033 b/tests/qemu-iotests/033
188
index XXXXXXX..XXXXXXX 100755
189
--- a/tests/qemu-iotests/033
190
+++ b/tests/qemu-iotests/033
191
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
192
193
_supported_fmt generic
194
_supported_proto generic
195
+_unsupported_imgopts "subformat=streamOptimized"
196
197
198
size=128M
199
diff --git a/tests/qemu-iotests/034 b/tests/qemu-iotests/034
200
index XXXXXXX..XXXXXXX 100755
201
--- a/tests/qemu-iotests/034
202
+++ b/tests/qemu-iotests/034
203
@@ -XXX,XX +XXX,XX @@ _supported_proto file
204
_supported_os Linux
205
_unsupported_imgopts "subformat=monolithicFlat" \
206
"subformat=twoGbMaxExtentFlat" \
207
- "subformat=twoGbMaxExtentSparse"
208
+ "subformat=twoGbMaxExtentSparse" \
209
+ "subformat=streamOptimized"
210
211
CLUSTER_SIZE=4k
212
size=128M
213
diff --git a/tests/qemu-iotests/037 b/tests/qemu-iotests/037
214
index XXXXXXX..XXXXXXX 100755
215
--- a/tests/qemu-iotests/037
216
+++ b/tests/qemu-iotests/037
217
@@ -XXX,XX +XXX,XX @@ _supported_fmt qcow qcow2 vmdk qed
218
_supported_proto file
219
_unsupported_imgopts "subformat=monolithicFlat" \
220
"subformat=twoGbMaxExtentFlat" \
221
- "subformat=twoGbMaxExtentSparse"
222
+ "subformat=twoGbMaxExtentSparse" \
223
+ "subformat=streamOptimized"
224
225
CLUSTER_SIZE=4k
226
size=128M
227
diff --git a/tests/qemu-iotests/063 b/tests/qemu-iotests/063
228
index XXXXXXX..XXXXXXX 100755
229
--- a/tests/qemu-iotests/063
230
+++ b/tests/qemu-iotests/063
231
@@ -XXX,XX +XXX,XX @@ _supported_fmt qcow qcow2 vmdk qed raw
232
_supported_proto file
233
_unsupported_imgopts "subformat=monolithicFlat" \
234
"subformat=twoGbMaxExtentFlat" \
235
- "subformat=twoGbMaxExtentSparse"
236
+ "subformat=twoGbMaxExtentSparse" \
237
+ "subformat=streamOptimized"
238
239
_make_test_img 4M
240
241
diff --git a/tests/qemu-iotests/072 b/tests/qemu-iotests/072
242
index XXXXXXX..XXXXXXX 100755
243
--- a/tests/qemu-iotests/072
244
+++ b/tests/qemu-iotests/072
245
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
246
247
_supported_fmt vpc vmdk vhdx vdi qed qcow2 qcow
248
_supported_proto file
249
+_unsupported_imgopts "subformat=streamOptimized"
250
251
IMG_SIZE=64M
252
253
diff --git a/tests/qemu-iotests/105 b/tests/qemu-iotests/105
254
index XXXXXXX..XXXXXXX 100755
255
--- a/tests/qemu-iotests/105
256
+++ b/tests/qemu-iotests/105
257
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
258
_supported_fmt qcow2 vmdk vhdx qed
259
_supported_proto generic
260
_unsupported_imgopts "subformat=twoGbMaxExtentFlat" \
261
- "subformat=twoGbMaxExtentSparse"
262
+ "subformat=twoGbMaxExtentSparse" \
263
+ "subformat=streamOptimized"
264
265
echo
266
echo "creating large image"
267
diff --git a/tests/qemu-iotests/197 b/tests/qemu-iotests/197
23
diff --git a/tests/qemu-iotests/197 b/tests/qemu-iotests/197
268
index XXXXXXX..XXXXXXX 100755
24
index XXXXXXX..XXXXXXX 100755
269
--- a/tests/qemu-iotests/197
25
--- a/tests/qemu-iotests/197
270
+++ b/tests/qemu-iotests/197
26
+++ b/tests/qemu-iotests/197
271
@@ -XXX,XX +XXX,XX @@ _supported_fmt generic
27
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -f qcow2 -C -c 'read 0 1024' "$TEST_WRAP" | _filter_qemu_io
272
_supported_proto generic
28
$QEMU_IO -f qcow2 -c map "$TEST_WRAP"
273
# LUKS support may be possible, but it complicates things.
29
_check_test_img
274
_unsupported_fmt luks
30
275
+_unsupported_imgopts "subformat=streamOptimized"
31
+echo
276
32
+echo '=== Copy-on-read with subclusters ==='
277
echo
33
+echo
278
echo '=== Copy-on-read ==='
34
+
279
diff --git a/tests/qemu-iotests/215 b/tests/qemu-iotests/215
35
+# Create base and top images 64K (1 cluster) each. Make subclusters enabled
280
index XXXXXXX..XXXXXXX 100755
36
+# for the top image
281
--- a/tests/qemu-iotests/215
37
+_make_test_img 64K
282
+++ b/tests/qemu-iotests/215
38
+IMGPROTO=file IMGFMT=qcow2 TEST_IMG_FILE="$TEST_WRAP" \
283
@@ -XXX,XX +XXX,XX @@ _supported_fmt generic
39
+ _make_test_img --no-opts -o extended_l2=true -F "$IMGFMT" -b "$TEST_IMG" \
284
_supported_proto generic
40
+ 64K | _filter_img_create
285
# LUKS support may be possible, but it complicates things.
41
+
286
_unsupported_fmt luks
42
+$QEMU_IO -c "write -P 0xaa 0 64k" "$TEST_IMG" | _filter_qemu_io
287
+_unsupported_imgopts "subformat=streamOptimized"
43
+
288
44
+# Allocate individual subclusters in the top image, and not the whole cluster
289
echo
45
+$QEMU_IO -c "write -P 0xbb 28K 2K" -c "write -P 0xcc 34K 2K" "$TEST_WRAP" \
290
echo '=== Copy-on-read ==='
46
+ | _filter_qemu_io
291
diff --git a/tests/qemu-iotests/251 b/tests/qemu-iotests/251
47
+
292
index XXXXXXX..XXXXXXX 100755
48
+# Only 2 subclusters should be allocated in the top image at this point
293
--- a/tests/qemu-iotests/251
49
+$QEMU_IMG map "$TEST_WRAP" | _filter_qemu_img_map
294
+++ b/tests/qemu-iotests/251
50
+
295
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
51
+# Actual copy-on-read operation
296
_supported_fmt generic
52
+$QEMU_IO -C -c "read -P 0xaa 30K 4K" "$TEST_WRAP" | _filter_qemu_io
297
_supported_proto file
53
+
298
_supported_os Linux
54
+# And here we should have 4 subclusters allocated right in the middle of the
299
+_unsupported_imgopts "subformat=streamOptimized"
55
+# top image. Make sure the whole cluster remains unallocated
300
56
+$QEMU_IMG map "$TEST_WRAP" | _filter_qemu_img_map
301
if [ "$IMGOPTSSYNTAX" = "true" ]; then
57
+
302
# We use json:{} filenames here, so we cannot work with additional options.
58
+_check_test_img
59
+
60
# success, all done
61
echo '*** done'
62
status=0
63
diff --git a/tests/qemu-iotests/197.out b/tests/qemu-iotests/197.out
64
index XXXXXXX..XXXXXXX 100644
65
--- a/tests/qemu-iotests/197.out
66
+++ b/tests/qemu-iotests/197.out
67
@@ -XXX,XX +XXX,XX @@ read 1024/1024 bytes at offset 0
68
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
69
1 KiB (0x400) bytes allocated at offset 0 bytes (0x0)
70
No errors were found on the image.
71
+
72
+=== Copy-on-read with subclusters ===
73
+
74
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=65536
75
+Formatting 'TEST_DIR/t.wrap.IMGFMT', fmt=IMGFMT size=65536 backing_file=TEST_DIR/t.IMGFMT backing_fmt=IMGFMT
76
+wrote 65536/65536 bytes at offset 0
77
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
78
+wrote 2048/2048 bytes at offset 28672
79
+2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
80
+wrote 2048/2048 bytes at offset 34816
81
+2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
82
+Offset Length File
83
+0 0x7000 TEST_DIR/t.IMGFMT
84
+0x7000 0x800 TEST_DIR/t.wrap.IMGFMT
85
+0x7800 0x1000 TEST_DIR/t.IMGFMT
86
+0x8800 0x800 TEST_DIR/t.wrap.IMGFMT
87
+0x9000 0x7000 TEST_DIR/t.IMGFMT
88
+read 4096/4096 bytes at offset 30720
89
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
90
+Offset Length File
91
+0 0x7000 TEST_DIR/t.IMGFMT
92
+0x7000 0x2000 TEST_DIR/t.wrap.IMGFMT
93
+0x9000 0x7000 TEST_DIR/t.IMGFMT
94
+No errors were found on the image.
95
*** done
303
--
96
--
304
2.21.0
97
2.41.0
305
306
diff view generated by jsdifflib
Deleted patch
1
The error message for the test case where we have a quorum node for
2
which no directory name can be generated is different: For
3
twoGbMaxExtentSparse, it complains that it cannot open the extent file.
4
For other (sub)formats, it just notes that it cannot determine the
5
backing file path. Both are fine, but just disable twoGbMaxExtentSparse
6
for simplicity's sake.
7
1
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
Reviewed-by: John Snow <jsnow@redhat.com>
10
Message-id: 20190815153638.4600-7-mreitz@redhat.com
11
Reviewed-by: John Snow <jsnow@redhat.com>
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
---
14
tests/qemu-iotests/110 | 3 ++-
15
1 file changed, 2 insertions(+), 1 deletion(-)
16
17
diff --git a/tests/qemu-iotests/110 b/tests/qemu-iotests/110
18
index XXXXXXX..XXXXXXX 100755
19
--- a/tests/qemu-iotests/110
20
+++ b/tests/qemu-iotests/110
21
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
22
# Any format supporting backing files
23
_supported_fmt qed qcow qcow2 vmdk
24
_supported_proto file
25
-_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat"
26
+_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat" \
27
+ "subformat=twoGbMaxExtentSparse"
28
29
TEST_IMG_REL=$(basename "$TEST_IMG")
30
31
--
32
2.21.0
33
34
diff view generated by jsdifflib
Deleted patch
1
iotest 126 requires backing file support, which flat vmdks cannot offer.
2
Skip this test for such subformats.
3
1
4
Signed-off-by: Max Reitz <mreitz@redhat.com>
5
Message-id: 20190815153638.4600-8-mreitz@redhat.com
6
Reviewed-by: John Snow <jsnow@redhat.com>
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
---
9
tests/qemu-iotests/126 | 2 ++
10
1 file changed, 2 insertions(+)
11
12
diff --git a/tests/qemu-iotests/126 b/tests/qemu-iotests/126
13
index XXXXXXX..XXXXXXX 100755
14
--- a/tests/qemu-iotests/126
15
+++ b/tests/qemu-iotests/126
16
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
17
18
# Needs backing file support
19
_supported_fmt qcow qcow2 qed vmdk
20
+_unsupported_imgopts "subformat=monolithicFlat" \
21
+ "subformat=twoGbMaxExtentFlat"
22
# This is the default protocol (and we want to test the difference between
23
# colons which separate a protocol prefix from the rest and colons which are
24
# just part of the filename, so we cannot test protocols which require a prefix)
25
--
26
2.21.0
27
28
diff view generated by jsdifflib
Deleted patch
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
1
3
Fixes: a6b257a08e3d72219f03e461a52152672fec0612
4
("file-posix: Handle undetectable alignment")
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
6
Message-id: 20190827101328.4062-1-stefanha@redhat.com
7
Reviewed-by: Thomas Huth <thuth@redhat.com>
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
---
10
block/file-posix.c | 2 +-
11
1 file changed, 1 insertion(+), 1 deletion(-)
12
13
diff --git a/block/file-posix.c b/block/file-posix.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/block/file-posix.c
16
+++ b/block/file-posix.c
17
@@ -XXX,XX +XXX,XX @@ static void raw_probe_alignment(BlockDriverState *bs, int fd, Error **errp)
18
for (i = 0; i < ARRAY_SIZE(alignments); i++) {
19
align = alignments[i];
20
if (raw_is_io_aligned(fd, buf + align, max_align)) {
21
- /* Fallback to request_aligment. */
22
+ /* Fallback to request_alignment. */
23
s->buf_align = (align != 1) ? align : bs->bl.request_alignment;
24
break;
25
}
26
--
27
2.21.0
28
29
diff view generated by jsdifflib
Deleted patch
1
From: Thomas Huth <thuth@redhat.com>
2
1
3
The sanitizers (especially the address sanitizer from Clang) are
4
sometimes printing out warnings or false positives - this spoils
5
the output of the iotests, causing some of the tests to fail.
6
Thus let's skip the automatic iotests during "make check" when the
7
user configured QEMU with --enable-sanitizers.
8
9
Signed-off-by: Thomas Huth <thuth@redhat.com>
10
Message-id: 20190823084203.29734-1-thuth@redhat.com
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
13
tests/check-block.sh | 5 +++++
14
1 file changed, 5 insertions(+)
15
16
diff --git a/tests/check-block.sh b/tests/check-block.sh
17
index XXXXXXX..XXXXXXX 100755
18
--- a/tests/check-block.sh
19
+++ b/tests/check-block.sh
20
@@ -XXX,XX +XXX,XX @@ if grep -q "TARGET_GPROF=y" *-softmmu/config-target.mak 2>/dev/null ; then
21
exit 0
22
fi
23
24
+if grep -q "CFLAGS.*-fsanitize" config-host.mak 2>/dev/null ; then
25
+ echo "Sanitizers are enabled ==> Not running the qemu-iotests."
26
+ exit 0
27
+fi
28
+
29
if [ -z "$(find . -name 'qemu-system-*' -print)" ]; then
30
echo "No qemu-system binary available ==> Not running the qemu-iotests."
31
exit 0
32
--
33
2.21.0
34
35
diff view generated by jsdifflib