1
The following changes since commit 248b23735645f7cbb503d9be6f5bf825f2a603ab:
1
The following changes since commit 03a3a62fbd0aa5227e978eef3c67d3978aec9e5f:
2
2
3
Update version for v2.10.0-rc4 release (2017-08-24 17:34:26 +0100)
3
Merge tag 'for-upstream' of https://gitlab.com/bonzini/qemu into staging (2023-09-07 10:29:06 -0400)
4
4
5
are available in the git repository at:
5
are available in the Git repository at:
6
6
7
git://github.com/stefanha/qemu.git tags/block-pull-request
7
https://gitlab.com/stefanha/qemu.git tags/block-pull-request
8
8
9
for you to fetch changes up to 3e4c705212abfe8c9882a00beb2d1466a8a53cec:
9
for you to fetch changes up to 631c872614aca91eaf947c1748f0f27f99635d92:
10
10
11
qcow2: allocate cluster_cache/cluster_data on demand (2017-08-30 18:02:10 +0100)
11
tests/qtest: Introduce tests for UFS (2023-09-07 14:01:29 -0400)
12
13
----------------------------------------------------------------
14
Pull request
15
16
- Jeuk Kim's emulated UFS device
17
- Fabiano Rosas' IOThread GSource "name" debugging aid
12
18
13
----------------------------------------------------------------
19
----------------------------------------------------------------
14
20
15
----------------------------------------------------------------
21
Fabiano Rosas (1):
22
iothread: Set the GSource "name" field
16
23
17
Alberto Garcia (8):
24
Jeuk Kim (4):
18
throttle: Fix wrong variable name in the header documentation
25
hw/ufs: Initial commit for emulated Universal-Flash-Storage
19
throttle: Update the throttle_fix_bucket() documentation
26
hw/ufs: Support for Query Transfer Requests
20
throttle: Make throttle_is_valid() a bit less verbose
27
hw/ufs: Support for UFS logical unit
21
throttle: Remove throttle_fix_bucket() / throttle_unfix_bucket()
28
tests/qtest: Introduce tests for UFS
22
throttle: Make LeakyBucket.avg and LeakyBucket.max integer types
23
throttle: Make burst_length 64bit and add range checks
24
throttle: Test the valid range of config values
25
misc: Remove unused Error variables
26
29
27
Dan Aloni (1):
30
MAINTAINERS | 7 +
28
nvme: Fix get/set number of queues feature, again
31
docs/specs/pci-ids.rst | 2 +
29
32
meson.build | 1 +
30
Eduardo Habkost (1):
33
hw/ufs/trace.h | 1 +
31
oslib-posix: Print errors before aborting on qemu_alloc_stack()
34
hw/ufs/ufs.h | 131 ++++
32
35
include/block/ufs.h | 1090 +++++++++++++++++++++++++++
33
Fred Rolland (1):
36
include/hw/pci/pci.h | 1 +
34
qemu-doc: Add UUID support in initiator name
37
include/hw/pci/pci_ids.h | 1 +
35
38
include/scsi/constants.h | 1 +
36
Stefan Hajnoczi (4):
39
hw/ufs/lu.c | 1445 ++++++++++++++++++++++++++++++++++++
37
scripts: add argparse module for Python 2.6 compatibility
40
hw/ufs/ufs.c | 1502 ++++++++++++++++++++++++++++++++++++++
38
docker.py: Python 2.6 argparse compatibility
41
iothread.c | 14 +-
39
tests: migration/guestperf Python 2.6 argparse compatibility
42
tests/qtest/ufs-test.c | 587 +++++++++++++++
40
qcow2: allocate cluster_cache/cluster_data on demand
43
hw/Kconfig | 1 +
41
44
hw/meson.build | 1 +
42
include/qemu/throttle.h | 8 +-
45
hw/ufs/Kconfig | 4 +
43
block/qcow.c | 12 +-
46
hw/ufs/meson.build | 1 +
44
block/qcow2-cluster.c | 17 +
47
hw/ufs/trace-events | 58 ++
45
block/qcow2.c | 20 +-
48
tests/qtest/meson.build | 1 +
46
dump.c | 4 +-
49
19 files changed, 4843 insertions(+), 6 deletions(-)
47
hw/block/nvme.c | 4 +-
50
create mode 100644 hw/ufs/trace.h
48
tests/test-throttle.c | 80 +-
51
create mode 100644 hw/ufs/ufs.h
49
util/oslib-posix.c | 2 +
52
create mode 100644 include/block/ufs.h
50
util/throttle.c | 86 +-
53
create mode 100644 hw/ufs/lu.c
51
COPYING.PYTHON | 270 ++++
54
create mode 100644 hw/ufs/ufs.c
52
qemu-doc.texi | 5 +-
55
create mode 100644 tests/qtest/ufs-test.c
53
scripts/argparse.py | 2406 ++++++++++++++++++++++++++++++++++++
56
create mode 100644 hw/ufs/Kconfig
54
tests/docker/docker.py | 4 +-
57
create mode 100644 hw/ufs/meson.build
55
tests/migration/guestperf/shell.py | 8 +-
58
create mode 100644 hw/ufs/trace-events
56
14 files changed, 2831 insertions(+), 95 deletions(-)
57
create mode 100644 COPYING.PYTHON
58
create mode 100644 scripts/argparse.py
59
59
60
--
60
--
61
2.13.5
61
2.41.0
62
63
diff view generated by jsdifflib
Deleted patch
1
From: Dan Aloni <dan@kernelim.com>
2
1
3
The number of queues that should be return by the admin command should:
4
5
1) Only mention the number of non-admin queues.
6
2) It is zero-based, meaning that '0 == one non-admin queue',
7
'1 == two non-admin queues', and so forth.
8
9
Because our `num_queues` means the number of queues _plus_ the admin
10
queue, then the right calculation for the number returned from the admin
11
command is `num_queues - 2`, combining the two requirements mentioned.
12
13
The issue was discovered by reducing num_queues from 64 to 8 and running
14
a Linux VM with an SMP parameter larger than that (e.g. 22). It tries to
15
utilize all queues, and therefore fails with an invalid queue number
16
when trying to queue I/Os on the last queue.
17
18
Signed-off-by: Dan Aloni <dan@kernelim.com>
19
CC: Alex Friedman <alex@e8storage.com>
20
CC: Keith Busch <keith.busch@intel.com>
21
CC: Stefan Hajnoczi <stefanha@redhat.com>
22
Reviewed-by: Keith Busch <keith.busch@intel.com>
23
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
24
---
25
hw/block/nvme.c | 4 ++--
26
1 file changed, 2 insertions(+), 2 deletions(-)
27
28
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
29
index XXXXXXX..XXXXXXX 100644
30
--- a/hw/block/nvme.c
31
+++ b/hw/block/nvme.c
32
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
33
result = blk_enable_write_cache(n->conf.blk);
34
break;
35
case NVME_NUMBER_OF_QUEUES:
36
- result = cpu_to_le32((n->num_queues - 1) | ((n->num_queues - 1) << 16));
37
+ result = cpu_to_le32((n->num_queues - 2) | ((n->num_queues - 2) << 16));
38
break;
39
default:
40
return NVME_INVALID_FIELD | NVME_DNR;
41
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
42
break;
43
case NVME_NUMBER_OF_QUEUES:
44
req->cqe.result =
45
- cpu_to_le32((n->num_queues - 1) | ((n->num_queues - 1) << 16));
46
+ cpu_to_le32((n->num_queues - 2) | ((n->num_queues - 2) << 16));
47
break;
48
default:
49
return NVME_INVALID_FIELD | NVME_DNR;
50
--
51
2.13.5
52
53
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
The level of the burst bucket is stored in bkt.burst_level, not
4
bkt.burst_length.
5
6
Signed-off-by: Alberto Garcia <berto@igalia.com>
7
Reviewed-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
8
Message-id: 49aab2711d02f285567f3b3b13a113847af33812.1503580370.git.berto@igalia.com
9
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
---
11
include/qemu/throttle.h | 2 +-
12
1 file changed, 1 insertion(+), 1 deletion(-)
13
14
diff --git a/include/qemu/throttle.h b/include/qemu/throttle.h
15
index XXXXXXX..XXXXXXX 100644
16
--- a/include/qemu/throttle.h
17
+++ b/include/qemu/throttle.h
18
@@ -XXX,XX +XXX,XX @@ typedef enum {
19
* - The bkt.avg rate does not apply until the bucket is full,
20
* allowing the user to do bursts until then. The I/O limit during
21
* bursts is bkt.max. To enforce this limit we keep an additional
22
- * bucket in bkt.burst_length that leaks at a rate of bkt.max units
23
+ * bucket in bkt.burst_level that leaks at a rate of bkt.max units
24
* per second.
25
*
26
* - Because of all of the above, the user can perform I/O at a
27
--
28
2.13.5
29
30
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
The way the throttling algorithm works is that requests start being
4
throttled once the bucket level exceeds the burst limit. When we get
5
there the bucket leaks at the level set by the user (bkt->avg), and
6
that leak rate is what prevents guest I/O from exceeding the desired
7
limit.
8
9
If we don't allow bursts (i.e. bkt->max == 0) then we can start
10
throttling requests immediately. The problem with keeping the
11
threshold at 0 is that it only allows one request at a time, and as
12
soon as there's a bit of I/O from the guest every other request will
13
be throttled and performance will suffer considerably. That can even
14
make the guest unable to reach the throttle limit if that limit is
15
high enough, and that happens regardless of the block scheduler used
16
by the guest.
17
18
Increasing that threshold gives flexibility to the guest, allowing it
19
to perform short bursts of I/O before being throttled. Increasing the
20
threshold too much does not make a difference in the long run (because
21
it's the leak rate what defines the actual throughput) but it does
22
allow the guest to perform longer initial bursts and exceed the
23
throttle limit for a short while.
24
25
A burst value of bkt->avg / 10 allows the guest to perform 100ms'
26
worth of I/O at the target rate without being throttled.
27
28
Signed-off-by: Alberto Garcia <berto@igalia.com>
29
Message-id: 31aae6645f0d1fbf3860fb2b528b757236f0c0a7.1503580370.git.berto@igalia.com
30
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
31
---
32
util/throttle.c | 11 +++--------
33
1 file changed, 3 insertions(+), 8 deletions(-)
34
35
diff --git a/util/throttle.c b/util/throttle.c
36
index XXXXXXX..XXXXXXX 100644
37
--- a/util/throttle.c
38
+++ b/util/throttle.c
39
@@ -XXX,XX +XXX,XX @@ static void throttle_fix_bucket(LeakyBucket *bkt)
40
/* zero bucket level */
41
bkt->level = bkt->burst_level = 0;
42
43
- /* The following is done to cope with the Linux CFQ block scheduler
44
- * which regroup reads and writes by block of 100ms in the guest.
45
- * When they are two process one making reads and one making writes cfq
46
- * make a pattern looking like the following:
47
- * WWWWWWWWWWWRRRRRRRRRRRRRRWWWWWWWWWWWWWwRRRRRRRRRRRRRRRRR
48
- * Having a max burst value of 100ms of the average will help smooth the
49
- * throttling
50
- */
51
+ /* If bkt->max is 0 we still want to allow short bursts of I/O
52
+ * from the guest, otherwise every other request will be throttled
53
+ * and performance will suffer considerably. */
54
min = bkt->avg / 10;
55
if (bkt->avg && !bkt->max) {
56
bkt->max = min;
57
--
58
2.13.5
59
60
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Fabiano Rosas <farosas@suse.de>
2
2
3
Use a pointer to the bucket instead of repeating cfg->buckets[i] all
3
Having a name in the source helps with debugging core dumps when one
4
the time. This makes the code more concise and will help us expand the
4
might not have access to TLS data to cross-reference AioContexts with
5
checks later and save a few line breaks.
5
their addresses.
6
6
7
Signed-off-by: Alberto Garcia <berto@igalia.com>
7
Signed-off-by: Fabiano Rosas <farosas@suse.de>
8
Message-id: 763ffc40a26b17d54cf93f5a999e4656049fcf0c.1503580370.git.berto@igalia.com
8
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
9
Message-id: 20230905180359.14083-1-farosas@suse.de
9
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
---
11
---
11
util/throttle.c | 15 +++++++--------
12
iothread.c | 14 ++++++++------
12
1 file changed, 7 insertions(+), 8 deletions(-)
13
1 file changed, 8 insertions(+), 6 deletions(-)
13
14
14
diff --git a/util/throttle.c b/util/throttle.c
15
diff --git a/iothread.c b/iothread.c
15
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
16
--- a/util/throttle.c
17
--- a/iothread.c
17
+++ b/util/throttle.c
18
+++ b/iothread.c
18
@@ -XXX,XX +XXX,XX @@ bool throttle_is_valid(ThrottleConfig *cfg, Error **errp)
19
@@ -XXX,XX +XXX,XX @@ static void iothread_instance_finalize(Object *obj)
20
qemu_sem_destroy(&iothread->init_done_sem);
21
}
22
23
-static void iothread_init_gcontext(IOThread *iothread)
24
+static void iothread_init_gcontext(IOThread *iothread, const char *thread_name)
25
{
26
GSource *source;
27
+ g_autofree char *name = g_strdup_printf("%s aio-context", thread_name);
28
29
iothread->worker_context = g_main_context_new();
30
source = aio_get_g_source(iothread_get_aio_context(iothread));
31
+ g_source_set_name(source, name);
32
g_source_attach(source, iothread->worker_context);
33
g_source_unref(source);
34
iothread->main_loop = g_main_loop_new(iothread->worker_context, TRUE);
35
@@ -XXX,XX +XXX,XX @@ static void iothread_init(EventLoopBase *base, Error **errp)
36
{
37
Error *local_error = NULL;
38
IOThread *iothread = IOTHREAD(base);
39
- char *thread_name;
40
+ g_autofree char *thread_name = NULL;
41
42
iothread->stopping = false;
43
iothread->running = true;
44
@@ -XXX,XX +XXX,XX @@ static void iothread_init(EventLoopBase *base, Error **errp)
45
return;
19
}
46
}
20
47
21
for (i = 0; i < BUCKETS_COUNT; i++) {
48
+ thread_name = g_strdup_printf("IO %s",
22
- if (cfg->buckets[i].avg < 0 ||
49
+ object_get_canonical_path_component(OBJECT(base)));
23
- cfg->buckets[i].max < 0 ||
50
+
24
- cfg->buckets[i].avg > THROTTLE_VALUE_MAX ||
51
/*
25
- cfg->buckets[i].max > THROTTLE_VALUE_MAX) {
52
* Init one GMainContext for the iothread unconditionally, even if
26
+ LeakyBucket *bkt = &cfg->buckets[i];
53
* it's not used
27
+ if (bkt->avg < 0 || bkt->max < 0 ||
54
*/
28
+ bkt->avg > THROTTLE_VALUE_MAX || bkt->max > THROTTLE_VALUE_MAX) {
55
- iothread_init_gcontext(iothread);
29
error_setg(errp, "bps/iops/max values must be within [0, %lld]",
56
+ iothread_init_gcontext(iothread, thread_name);
30
THROTTLE_VALUE_MAX);
57
31
return false;
58
iothread_set_aio_context_params(base, &local_error);
32
}
59
if (local_error) {
33
60
@@ -XXX,XX +XXX,XX @@ static void iothread_init(EventLoopBase *base, Error **errp)
34
- if (!cfg->buckets[i].burst_length) {
61
/* This assumes we are called from a thread with useful CPU affinity for us
35
+ if (!bkt->burst_length) {
62
* to inherit.
36
error_setg(errp, "the burst length cannot be 0");
63
*/
37
return false;
64
- thread_name = g_strdup_printf("IO %s",
38
}
65
- object_get_canonical_path_component(OBJECT(base)));
39
66
qemu_thread_create(&iothread->thread, thread_name, iothread_run,
40
- if (cfg->buckets[i].burst_length > 1 && !cfg->buckets[i].max) {
67
iothread, QEMU_THREAD_JOINABLE);
41
+ if (bkt->burst_length > 1 && !bkt->max) {
68
- g_free(thread_name);
42
error_setg(errp, "burst length set without burst rate");
69
43
return false;
70
/* Wait for initialization to complete */
44
}
71
while (iothread->thread_id == -1) {
45
46
- if (cfg->buckets[i].max && !cfg->buckets[i].avg) {
47
+ if (bkt->max && !bkt->avg) {
48
error_setg(errp, "bps_max/iops_max require corresponding"
49
" bps/iops values");
50
return false;
51
}
52
53
- if (cfg->buckets[i].max && cfg->buckets[i].max < cfg->buckets[i].avg) {
54
+ if (bkt->max && bkt->max < bkt->avg) {
55
error_setg(errp, "bps_max/iops_max cannot be lower than bps/iops");
56
return false;
57
}
58
--
72
--
59
2.13.5
73
2.41.0
60
74
61
75
diff view generated by jsdifflib
1
The minimum Python version supported by QEMU is 2.6. The argparse
1
From: Jeuk Kim <jeuk20.kim@samsung.com>
2
standard library module was only added in Python 2.7. Many scripts
3
would like to use argparse because it supports command-line
4
sub-commands.
5
2
6
This patch adds argparse. See the top of argparse.py for details.
3
Universal Flash Storage (UFS) is a high-performance mass storage device
4
with a serial interface. It is primarily used as a high-performance
5
data storage device for embedded applications.
7
6
8
Suggested-by: Daniel P. Berrange <berrange@redhat.com>
7
This commit contains code for UFS device to be recognized
9
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
8
as a UFS PCI device.
10
Acked-by: John Snow <jsnow@redhat.com>
9
Patches to handle UFS logical unit and Transfer Request will follow.
11
Message-id: 20170825155732.15665-2-stefanha@redhat.com
10
11
Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>
12
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
13
Message-id: 10232660d462ee5cd10cf673f1a9a1205fc8276c.1693980783.git.jeuk20.kim@gmail.com
12
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
14
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
13
---
15
---
14
COPYING.PYTHON | 270 ++++++
16
MAINTAINERS | 6 +
15
scripts/argparse.py | 2406 +++++++++++++++++++++++++++++++++++++++++++++++++++
17
docs/specs/pci-ids.rst | 2 +
16
2 files changed, 2676 insertions(+)
18
meson.build | 1 +
17
create mode 100644 COPYING.PYTHON
19
hw/ufs/trace.h | 1 +
18
create mode 100644 scripts/argparse.py
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
19
38
20
diff --git a/COPYING.PYTHON b/COPYING.PYTHON
39
diff --git a/MAINTAINERS b/MAINTAINERS
40
index XXXXXXX..XXXXXXX 100644
41
--- a/MAINTAINERS
42
+++ b/MAINTAINERS
43
@@ -XXX,XX +XXX,XX @@ F: tests/qtest/nvme-test.c
44
F: docs/system/devices/nvme.rst
45
T: git git://git.infradead.org/qemu-nvme.git nvme-next
46
47
+ufs
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
21
new file mode 100644
82
new file mode 100644
22
index XXXXXXX..XXXXXXX
83
index XXXXXXX..XXXXXXX
23
--- /dev/null
84
--- /dev/null
24
+++ b/COPYING.PYTHON
85
+++ b/hw/ufs/trace.h
25
@@ -XXX,XX +XXX,XX @@
86
@@ -0,0 +1 @@
26
+A. HISTORY OF THE SOFTWARE
87
+#include "trace/trace-hw_ufs.h"
27
+==========================
88
diff --git a/hw/ufs/ufs.h b/hw/ufs/ufs.h
28
+
29
+Python was created in the early 1990s by Guido van Rossum at Stichting
30
+Mathematisch Centrum (CWI, see http://www.cwi.nl) in the Netherlands
31
+as a successor of a language called ABC. Guido remains Python's
32
+principal author, although it includes many contributions from others.
33
+
34
+In 1995, Guido continued his work on Python at the Corporation for
35
+National Research Initiatives (CNRI, see http://www.cnri.reston.va.us)
36
+in Reston, Virginia where he released several versions of the
37
+software.
38
+
39
+In May 2000, Guido and the Python core development team moved to
40
+BeOpen.com to form the BeOpen PythonLabs team. In October of the same
41
+year, the PythonLabs team moved to Digital Creations (now Zope
42
+Corporation, see http://www.zope.com). In 2001, the Python Software
43
+Foundation (PSF, see http://www.python.org/psf/) was formed, a
44
+non-profit organization created specifically to own Python-related
45
+Intellectual Property. Zope Corporation is a sponsoring member of
46
+the PSF.
47
+
48
+All Python releases are Open Source (see http://www.opensource.org for
49
+the Open Source Definition). Historically, most, but not all, Python
50
+releases have also been GPL-compatible; the table below summarizes
51
+the various releases.
52
+
53
+ Release Derived Year Owner GPL-
54
+ from compatible? (1)
55
+
56
+ 0.9.0 thru 1.2 1991-1995 CWI yes
57
+ 1.3 thru 1.5.2 1.2 1995-1999 CNRI yes
58
+ 1.6 1.5.2 2000 CNRI no
59
+ 2.0 1.6 2000 BeOpen.com no
60
+ 1.6.1 1.6 2001 CNRI yes (2)
61
+ 2.1 2.0+1.6.1 2001 PSF no
62
+ 2.0.1 2.0+1.6.1 2001 PSF yes
63
+ 2.1.1 2.1+2.0.1 2001 PSF yes
64
+ 2.2 2.1.1 2001 PSF yes
65
+ 2.1.2 2.1.1 2002 PSF yes
66
+ 2.1.3 2.1.2 2002 PSF yes
67
+ 2.2.1 2.2 2002 PSF yes
68
+ 2.2.2 2.2.1 2002 PSF yes
69
+ 2.2.3 2.2.2 2003 PSF yes
70
+ 2.3 2.2.2 2002-2003 PSF yes
71
+ 2.3.1 2.3 2002-2003 PSF yes
72
+ 2.3.2 2.3.1 2002-2003 PSF yes
73
+ 2.3.3 2.3.2 2002-2003 PSF yes
74
+ 2.3.4 2.3.3 2004 PSF yes
75
+ 2.3.5 2.3.4 2005 PSF yes
76
+ 2.4 2.3 2004 PSF yes
77
+ 2.4.1 2.4 2005 PSF yes
78
+ 2.4.2 2.4.1 2005 PSF yes
79
+ 2.4.3 2.4.2 2006 PSF yes
80
+ 2.5 2.4 2006 PSF yes
81
+ 2.7 2.6 2010 PSF yes
82
+
83
+Footnotes:
84
+
85
+(1) GPL-compatible doesn't mean that we're distributing Python under
86
+ the GPL. All Python licenses, unlike the GPL, let you distribute
87
+ a modified version without making your changes open source. The
88
+ GPL-compatible licenses make it possible to combine Python with
89
+ other software that is released under the GPL; the others don't.
90
+
91
+(2) According to Richard Stallman, 1.6.1 is not GPL-compatible,
92
+ because its license has a choice of law clause. According to
93
+ CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1
94
+ is "not incompatible" with the GPL.
95
+
96
+Thanks to the many outside volunteers who have worked under Guido's
97
+direction to make these releases possible.
98
+
99
+
100
+B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON
101
+===============================================================
102
+
103
+PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
104
+--------------------------------------------
105
+
106
+1. This LICENSE AGREEMENT is between the Python Software Foundation
107
+("PSF"), and the Individual or Organization ("Licensee") accessing and
108
+otherwise using this software ("Python") in source or binary form and
109
+its associated documentation.
110
+
111
+2. Subject to the terms and conditions of this License Agreement, PSF
112
+hereby grants Licensee a nonexclusive, royalty-free, world-wide
113
+license to reproduce, analyze, test, perform and/or display publicly,
114
+prepare derivative works, distribute, and otherwise use Python
115
+alone or in any derivative version, provided, however, that PSF's
116
+License Agreement and PSF's notice of copyright, i.e., "Copyright (c)
117
+2001, 2002, 2003, 2004, 2005, 2006 Python Software Foundation; All Rights
118
+Reserved" are retained in Python alone or in any derivative version
119
+prepared by Licensee.
120
+
121
+3. In the event Licensee prepares a derivative work that is based on
122
+or incorporates Python or any part thereof, and wants to make
123
+the derivative work available to others as provided herein, then
124
+Licensee hereby agrees to include in any such work a brief summary of
125
+the changes made to Python.
126
+
127
+4. PSF is making Python available to Licensee on an "AS IS"
128
+basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
129
+IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
130
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
131
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
132
+INFRINGE ANY THIRD PARTY RIGHTS.
133
+
134
+5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
135
+FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
136
+A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
137
+OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
138
+
139
+6. This License Agreement will automatically terminate upon a material
140
+breach of its terms and conditions.
141
+
142
+7. Nothing in this License Agreement shall be deemed to create any
143
+relationship of agency, partnership, or joint venture between PSF and
144
+Licensee. This License Agreement does not grant permission to use PSF
145
+trademarks or trade name in a trademark sense to endorse or promote
146
+products or services of Licensee, or any third party.
147
+
148
+8. By copying, installing or otherwise using Python, Licensee
149
+agrees to be bound by the terms and conditions of this License
150
+Agreement.
151
+
152
+
153
+BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0
154
+-------------------------------------------
155
+
156
+BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1
157
+
158
+1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an
159
+office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the
160
+Individual or Organization ("Licensee") accessing and otherwise using
161
+this software in source or binary form and its associated
162
+documentation ("the Software").
163
+
164
+2. Subject to the terms and conditions of this BeOpen Python License
165
+Agreement, BeOpen hereby grants Licensee a non-exclusive,
166
+royalty-free, world-wide license to reproduce, analyze, test, perform
167
+and/or display publicly, prepare derivative works, distribute, and
168
+otherwise use the Software alone or in any derivative version,
169
+provided, however, that the BeOpen Python License is retained in the
170
+Software, alone or in any derivative version prepared by Licensee.
171
+
172
+3. BeOpen is making the Software available to Licensee on an "AS IS"
173
+basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
174
+IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND
175
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
176
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT
177
+INFRINGE ANY THIRD PARTY RIGHTS.
178
+
179
+4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE
180
+SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS
181
+AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY
182
+DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
183
+
184
+5. This License Agreement will automatically terminate upon a material
185
+breach of its terms and conditions.
186
+
187
+6. This License Agreement shall be governed by and interpreted in all
188
+respects by the law of the State of California, excluding conflict of
189
+law provisions. Nothing in this License Agreement shall be deemed to
190
+create any relationship of agency, partnership, or joint venture
191
+between BeOpen and Licensee. This License Agreement does not grant
192
+permission to use BeOpen trademarks or trade names in a trademark
193
+sense to endorse or promote products or services of Licensee, or any
194
+third party. As an exception, the "BeOpen Python" logos available at
195
+http://www.pythonlabs.com/logos.html may be used according to the
196
+permissions granted on that web page.
197
+
198
+7. By copying, installing or otherwise using the software, Licensee
199
+agrees to be bound by the terms and conditions of this License
200
+Agreement.
201
+
202
+
203
+CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1
204
+---------------------------------------
205
+
206
+1. This LICENSE AGREEMENT is between the Corporation for National
207
+Research Initiatives, having an office at 1895 Preston White Drive,
208
+Reston, VA 20191 ("CNRI"), and the Individual or Organization
209
+("Licensee") accessing and otherwise using Python 1.6.1 software in
210
+source or binary form and its associated documentation.
211
+
212
+2. Subject to the terms and conditions of this License Agreement, CNRI
213
+hereby grants Licensee a nonexclusive, royalty-free, world-wide
214
+license to reproduce, analyze, test, perform and/or display publicly,
215
+prepare derivative works, distribute, and otherwise use Python 1.6.1
216
+alone or in any derivative version, provided, however, that CNRI's
217
+License Agreement and CNRI's notice of copyright, i.e., "Copyright (c)
218
+1995-2001 Corporation for National Research Initiatives; All Rights
219
+Reserved" are retained in Python 1.6.1 alone or in any derivative
220
+version prepared by Licensee. Alternately, in lieu of CNRI's License
221
+Agreement, Licensee may substitute the following text (omitting the
222
+quotes): "Python 1.6.1 is made available subject to the terms and
223
+conditions in CNRI's License Agreement. This Agreement together with
224
+Python 1.6.1 may be located on the Internet using the following
225
+unique, persistent identifier (known as a handle): 1895.22/1013. This
226
+Agreement may also be obtained from a proxy server on the Internet
227
+using the following URL: http://hdl.handle.net/1895.22/1013".
228
+
229
+3. In the event Licensee prepares a derivative work that is based on
230
+or incorporates Python 1.6.1 or any part thereof, and wants to make
231
+the derivative work available to others as provided herein, then
232
+Licensee hereby agrees to include in any such work a brief summary of
233
+the changes made to Python 1.6.1.
234
+
235
+4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS"
236
+basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
237
+IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND
238
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
239
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT
240
+INFRINGE ANY THIRD PARTY RIGHTS.
241
+
242
+5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
243
+1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
244
+A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1,
245
+OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
246
+
247
+6. This License Agreement will automatically terminate upon a material
248
+breach of its terms and conditions.
249
+
250
+7. This License Agreement shall be governed by the federal
251
+intellectual property law of the United States, including without
252
+limitation the federal copyright law, and, to the extent such
253
+U.S. federal law does not apply, by the law of the Commonwealth of
254
+Virginia, excluding Virginia's conflict of law provisions.
255
+Notwithstanding the foregoing, with regard to derivative works based
256
+on Python 1.6.1 that incorporate non-separable material that was
257
+previously distributed under the GNU General Public License (GPL), the
258
+law of the Commonwealth of Virginia shall govern this License
259
+Agreement only as to issues arising under or with respect to
260
+Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this
261
+License Agreement shall be deemed to create any relationship of
262
+agency, partnership, or joint venture between CNRI and Licensee. This
263
+License Agreement does not grant permission to use CNRI trademarks or
264
+trade name in a trademark sense to endorse or promote products or
265
+services of Licensee, or any third party.
266
+
267
+8. By clicking on the "ACCEPT" button where indicated, or by copying,
268
+installing or otherwise using Python 1.6.1, Licensee agrees to be
269
+bound by the terms and conditions of this License Agreement.
270
+
271
+ ACCEPT
272
+
273
+
274
+CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2
275
+--------------------------------------------------
276
+
277
+Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam,
278
+The Netherlands. All rights reserved.
279
+
280
+Permission to use, copy, modify, and distribute this software and its
281
+documentation for any purpose and without fee is hereby granted,
282
+provided that the above copyright notice appear in all copies and that
283
+both that copyright notice and this permission notice appear in
284
+supporting documentation, and that the name of Stichting Mathematisch
285
+Centrum or CWI not be used in advertising or publicity pertaining to
286
+distribution of the software without specific, written prior
287
+permission.
288
+
289
+STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
290
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
291
+FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
292
+FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
293
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
294
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
295
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
296
diff --git a/scripts/argparse.py b/scripts/argparse.py
297
new file mode 100644
89
new file mode 100644
298
index XXXXXXX..XXXXXXX
90
index XXXXXXX..XXXXXXX
299
--- /dev/null
91
--- /dev/null
300
+++ b/scripts/argparse.py
92
+++ b/hw/ufs/ufs.h
301
@@ -XXX,XX +XXX,XX @@
93
@@ -XXX,XX +XXX,XX @@
302
+# This is a local copy of the standard library argparse module taken from PyPI.
94
+/*
303
+# It is licensed under the Python Software Foundation License. This is a
95
+ * QEMU UFS
304
+# fallback for Python 2.6 which does not include this module. Python 2.7+ and
96
+ *
305
+# 3+ will never load this module because built-in modules are loaded before
97
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd. All rights reserved.
306
+# anything in sys.path.
98
+ *
307
+#
99
+ * Written by Jeuk Kim <jeuk20.kim@samsung.com>
308
+# If your script is not located in the same directory as this file, import it
100
+ *
309
+# like this:
101
+ * SPDX-License-Identifier: GPL-2.0-or-later
310
+#
102
+ */
311
+# import os
103
+
312
+# import sys
104
+#ifndef HW_UFS_UFS_H
313
+# sys.path.append(os.path.join(os.path.dirname(__file__), ..., 'scripts'))
105
+#define HW_UFS_UFS_H
314
+# import argparse
106
+
315
+
107
+#include "hw/pci/pci_device.h"
316
+# Author: Steven J. Bethard <steven.bethard@gmail.com>.
108
+#include "hw/scsi/scsi.h"
317
+# Maintainer: Thomas Waldmann <tw@waldmann-edv.de>
109
+#include "block/ufs.h"
318
+
110
+
319
+"""Command-line parsing library
111
+#define UFS_MAX_LUS 32
320
+
112
+#define UFS_BLOCK_SIZE 4096
321
+This module is an optparse-inspired command-line parsing library that:
113
+
322
+
114
+typedef struct UfsParams {
323
+ - handles both optional and positional arguments
115
+ char *serial;
324
+ - produces highly informative usage messages
116
+ uint8_t nutrs; /* Number of UTP Transfer Request Slots */
325
+ - supports parsers that dispatch to sub-parsers
117
+ uint8_t nutmrs; /* Number of UTP Task Management Request Slots */
326
+
118
+} UfsParams;
327
+The following is a simple usage example that sums integers from the
119
+
328
+command-line and writes the result to a file::
120
+typedef struct UfsHc {
329
+
121
+ PCIDevice parent_obj;
330
+ parser = argparse.ArgumentParser(
122
+ MemoryRegion iomem;
331
+ description='sum the integers at the command line')
123
+ UfsReg reg;
332
+ parser.add_argument(
124
+ UfsParams params;
333
+ 'integers', metavar='int', nargs='+', type=int,
125
+ uint32_t reg_size;
334
+ help='an integer to be summed')
126
+
335
+ parser.add_argument(
127
+ qemu_irq irq;
336
+ '--log', default=sys.stdout, type=argparse.FileType('w'),
128
+ QEMUBH *doorbell_bh;
337
+ help='the file where the sum should be written')
129
+ QEMUBH *complete_bh;
338
+ args = parser.parse_args()
130
+} UfsHc;
339
+ args.log.write('%s' % sum(args.integers))
131
+
340
+ args.log.close()
132
+#define TYPE_UFS "ufs"
341
+
133
+#define UFS(obj) OBJECT_CHECK(UfsHc, (obj), TYPE_UFS)
342
+The module contains the following public classes:
134
+
343
+
135
+#endif /* HW_UFS_UFS_H */
344
+ - ArgumentParser -- The main entry point for command-line parsing. As the
136
diff --git a/include/block/ufs.h b/include/block/ufs.h
345
+ example above shows, the add_argument() method is used to populate
137
new file mode 100644
346
+ the parser with actions for optional and positional arguments. Then
138
index XXXXXXX..XXXXXXX
347
+ the parse_args() method is invoked to convert the args at the
139
--- /dev/null
348
+ command-line into an object with attributes.
140
+++ b/include/block/ufs.h
349
+
141
@@ -XXX,XX +XXX,XX @@
350
+ - ArgumentError -- The exception raised by ArgumentParser objects when
142
+/* SPDX-License-Identifier: GPL-2.0-or-later */
351
+ there are errors with the parser's actions. Errors raised while
143
+
352
+ parsing the command-line are caught by ArgumentParser and emitted
144
+#ifndef BLOCK_UFS_H
353
+ as command-line messages.
145
+#define BLOCK_UFS_H
354
+
146
+
355
+ - FileType -- A factory for defining types of files to be created. As the
147
+#include "hw/registerfields.h"
356
+ example above shows, instances of FileType are typically passed as
148
+
357
+ the type= argument of add_argument() calls.
149
+typedef struct QEMU_PACKED UfsReg {
358
+
150
+ uint32_t cap;
359
+ - Action -- The base class for parser actions. Typically actions are
151
+ uint32_t rsvd0;
360
+ selected by passing strings like 'store_true' or 'append_const' to
152
+ uint32_t ver;
361
+ the action= argument of add_argument(). However, for greater
153
+ uint32_t rsvd1;
362
+ customization of ArgumentParser actions, subclasses of Action may
154
+ uint32_t hcpid;
363
+ be defined and passed as the action= argument.
155
+ uint32_t hcmid;
364
+
156
+ uint32_t ahit;
365
+ - HelpFormatter, RawDescriptionHelpFormatter, RawTextHelpFormatter,
157
+ uint32_t rsvd2;
366
+ ArgumentDefaultsHelpFormatter -- Formatter classes which
158
+ uint32_t is;
367
+ may be passed as the formatter_class= argument to the
159
+ uint32_t ie;
368
+ ArgumentParser constructor. HelpFormatter is the default,
160
+ uint32_t rsvd3[2];
369
+ RawDescriptionHelpFormatter and RawTextHelpFormatter tell the parser
161
+ uint32_t hcs;
370
+ not to change the formatting for help text, and
162
+ uint32_t hce;
371
+ ArgumentDefaultsHelpFormatter adds information about argument defaults
163
+ uint32_t uecpa;
372
+ to the help.
164
+ uint32_t uecdl;
373
+
165
+ uint32_t uecn;
374
+All other classes in this module are considered implementation details.
166
+ uint32_t uect;
375
+(Also note that HelpFormatter and RawDescriptionHelpFormatter are only
167
+ uint32_t uecdme;
376
+considered public as object names -- the API of the formatter objects is
168
+ uint32_t utriacr;
377
+still considered an implementation detail.)
169
+ uint32_t utrlba;
378
+"""
170
+ uint32_t utrlbau;
379
+
171
+ uint32_t utrldbr;
380
+__version__ = '1.4.0' # we use our own version number independant of the
172
+ uint32_t utrlclr;
381
+ # one in stdlib and we release this on pypi.
173
+ uint32_t utrlrsr;
382
+
174
+ uint32_t utrlcnr;
383
+__external_lib__ = True # to make sure the tests really test THIS lib,
175
+ uint32_t rsvd4[2];
384
+ # not the builtin one in Python stdlib
176
+ uint32_t utmrlba;
385
+
177
+ uint32_t utmrlbau;
386
+__all__ = [
178
+ uint32_t utmrldbr;
387
+ 'ArgumentParser',
179
+ uint32_t utmrlclr;
388
+ 'ArgumentError',
180
+ uint32_t utmrlrsr;
389
+ 'ArgumentTypeError',
181
+ uint32_t rsvd5[3];
390
+ 'FileType',
182
+ uint32_t uiccmd;
391
+ 'HelpFormatter',
183
+ uint32_t ucmdarg1;
392
+ 'ArgumentDefaultsHelpFormatter',
184
+ uint32_t ucmdarg2;
393
+ 'RawDescriptionHelpFormatter',
185
+ uint32_t ucmdarg3;
394
+ 'RawTextHelpFormatter',
186
+ uint32_t rsvd6[4];
395
+ 'Namespace',
187
+ uint32_t rsvd7[4];
396
+ 'Action',
188
+ uint32_t rsvd8[16];
397
+ 'ONE_OR_MORE',
189
+ uint32_t ccap;
398
+ 'OPTIONAL',
190
+} UfsReg;
399
+ 'PARSER',
191
+
400
+ 'REMAINDER',
192
+REG32(CAP, offsetof(UfsReg, cap))
401
+ 'SUPPRESS',
193
+ FIELD(CAP, NUTRS, 0, 5)
402
+ 'ZERO_OR_MORE',
194
+ FIELD(CAP, RTT, 8, 8)
403
+]
195
+ FIELD(CAP, NUTMRS, 16, 3)
404
+
196
+ FIELD(CAP, AUTOH8, 23, 1)
405
+
197
+ FIELD(CAP, 64AS, 24, 1)
406
+import copy as _copy
198
+ FIELD(CAP, OODDS, 25, 1)
407
+import os as _os
199
+ FIELD(CAP, UICDMETMS, 26, 1)
408
+import re as _re
200
+ FIELD(CAP, CS, 28, 1)
409
+import sys as _sys
201
+REG32(VER, offsetof(UfsReg, ver))
410
+import textwrap as _textwrap
202
+REG32(HCPID, offsetof(UfsReg, hcpid))
411
+
203
+REG32(HCMID, offsetof(UfsReg, hcmid))
412
+from gettext import gettext as _
204
+REG32(AHIT, offsetof(UfsReg, ahit))
413
+
205
+REG32(IS, offsetof(UfsReg, is))
414
+try:
206
+ FIELD(IS, UTRCS, 0, 1)
415
+ set
207
+ FIELD(IS, UDEPRI, 1, 1)
416
+except NameError:
208
+ FIELD(IS, UE, 2, 1)
417
+ # for python < 2.4 compatibility (sets module is there since 2.3):
209
+ FIELD(IS, UTMS, 3, 1)
418
+ from sets import Set as set
210
+ FIELD(IS, UPMS, 4, 1)
419
+
211
+ FIELD(IS, UHXS, 5, 1)
420
+try:
212
+ FIELD(IS, UHES, 6, 1)
421
+ basestring
213
+ FIELD(IS, ULLS, 7, 1)
422
+except NameError:
214
+ FIELD(IS, ULSS, 8, 1)
423
+ basestring = str
215
+ FIELD(IS, UTMRCS, 9, 1)
424
+
216
+ FIELD(IS, UCCS, 10, 1)
425
+try:
217
+ FIELD(IS, DFES, 11, 1)
426
+ sorted
218
+ FIELD(IS, UTPES, 12, 1)
427
+except NameError:
219
+ FIELD(IS, HCFES, 16, 1)
428
+ # for python < 2.4 compatibility:
220
+ FIELD(IS, SBFES, 17, 1)
429
+ def sorted(iterable, reverse=False):
221
+ FIELD(IS, CEFES, 18, 1)
430
+ result = list(iterable)
222
+REG32(IE, offsetof(UfsReg, ie))
431
+ result.sort()
223
+ FIELD(IE, UTRCE, 0, 1)
432
+ if reverse:
224
+ FIELD(IE, UDEPRIE, 1, 1)
433
+ result.reverse()
225
+ FIELD(IE, UEE, 2, 1)
434
+ return result
226
+ FIELD(IE, UTMSE, 3, 1)
435
+
227
+ FIELD(IE, UPMSE, 4, 1)
436
+
228
+ FIELD(IE, UHXSE, 5, 1)
437
+def _callable(obj):
229
+ FIELD(IE, UHESE, 6, 1)
438
+ return hasattr(obj, '__call__') or hasattr(obj, '__bases__')
230
+ FIELD(IE, ULLSE, 7, 1)
439
+
231
+ FIELD(IE, ULSSE, 8, 1)
440
+
232
+ FIELD(IE, UTMRCE, 9, 1)
441
+SUPPRESS = '==SUPPRESS=='
233
+ FIELD(IE, UCCE, 10, 1)
442
+
234
+ FIELD(IE, DFEE, 11, 1)
443
+OPTIONAL = '?'
235
+ FIELD(IE, UTPEE, 12, 1)
444
+ZERO_OR_MORE = '*'
236
+ FIELD(IE, HCFEE, 16, 1)
445
+ONE_OR_MORE = '+'
237
+ FIELD(IE, SBFEE, 17, 1)
446
+PARSER = 'A...'
238
+ FIELD(IE, CEFEE, 18, 1)
447
+REMAINDER = '...'
239
+REG32(HCS, offsetof(UfsReg, hcs))
448
+_UNRECOGNIZED_ARGS_ATTR = '_unrecognized_args'
240
+ FIELD(HCS, DP, 0, 1)
449
+
241
+ FIELD(HCS, UTRLRDY, 1, 1)
450
+# =============================
242
+ FIELD(HCS, UTMRLRDY, 2, 1)
451
+# Utility functions and classes
243
+ FIELD(HCS, UCRDY, 3, 1)
452
+# =============================
244
+ FIELD(HCS, UPMCRS, 8, 3)
453
+
245
+REG32(HCE, offsetof(UfsReg, hce))
454
+class _AttributeHolder(object):
246
+ FIELD(HCE, HCE, 0, 1)
455
+ """Abstract base class that provides __repr__.
247
+ FIELD(HCE, CGE, 1, 1)
456
+
248
+REG32(UECPA, offsetof(UfsReg, uecpa))
457
+ The __repr__ method returns a string in the format::
249
+REG32(UECDL, offsetof(UfsReg, uecdl))
458
+ ClassName(attr=name, attr=name, ...)
250
+REG32(UECN, offsetof(UfsReg, uecn))
459
+ The attributes are determined either by a class-level attribute,
251
+REG32(UECT, offsetof(UfsReg, uect))
460
+ '_kwarg_names', or by inspecting the instance __dict__.
252
+REG32(UECDME, offsetof(UfsReg, uecdme))
461
+ """
253
+REG32(UTRIACR, offsetof(UfsReg, utriacr))
462
+
254
+REG32(UTRLBA, offsetof(UfsReg, utrlba))
463
+ def __repr__(self):
255
+ FIELD(UTRLBA, UTRLBA, 9, 22)
464
+ type_name = type(self).__name__
256
+REG32(UTRLBAU, offsetof(UfsReg, utrlbau))
465
+ arg_strings = []
257
+REG32(UTRLDBR, offsetof(UfsReg, utrldbr))
466
+ for arg in self._get_args():
258
+REG32(UTRLCLR, offsetof(UfsReg, utrlclr))
467
+ arg_strings.append(repr(arg))
259
+REG32(UTRLRSR, offsetof(UfsReg, utrlrsr))
468
+ for name, value in self._get_kwargs():
260
+REG32(UTRLCNR, offsetof(UfsReg, utrlcnr))
469
+ arg_strings.append('%s=%r' % (name, value))
261
+REG32(UTMRLBA, offsetof(UfsReg, utmrlba))
470
+ return '%s(%s)' % (type_name, ', '.join(arg_strings))
262
+ FIELD(UTMRLBA, UTMRLBA, 9, 22)
471
+
263
+REG32(UTMRLBAU, offsetof(UfsReg, utmrlbau))
472
+ def _get_kwargs(self):
264
+REG32(UTMRLDBR, offsetof(UfsReg, utmrldbr))
473
+ return sorted(self.__dict__.items())
265
+REG32(UTMRLCLR, offsetof(UfsReg, utmrlclr))
474
+
266
+REG32(UTMRLRSR, offsetof(UfsReg, utmrlrsr))
475
+ def _get_args(self):
267
+REG32(UICCMD, offsetof(UfsReg, uiccmd))
476
+ return []
268
+REG32(UCMDARG1, offsetof(UfsReg, ucmdarg1))
477
+
269
+REG32(UCMDARG2, offsetof(UfsReg, ucmdarg2))
478
+
270
+REG32(UCMDARG3, offsetof(UfsReg, ucmdarg3))
479
+def _ensure_value(namespace, name, value):
271
+REG32(CCAP, offsetof(UfsReg, ccap))
480
+ if getattr(namespace, name, None) is None:
272
+
481
+ setattr(namespace, name, value)
273
+#define UFS_INTR_MASK \
482
+ return getattr(namespace, name)
274
+ ((1 << R_IS_CEFES_SHIFT) | (1 << R_IS_SBFES_SHIFT) | \
483
+
275
+ (1 << R_IS_HCFES_SHIFT) | (1 << R_IS_UTPES_SHIFT) | \
484
+
276
+ (1 << R_IS_DFES_SHIFT) | (1 << R_IS_UCCS_SHIFT) | \
485
+# ===============
277
+ (1 << R_IS_UTMRCS_SHIFT) | (1 << R_IS_ULSS_SHIFT) | \
486
+# Formatting Help
278
+ (1 << R_IS_ULLS_SHIFT) | (1 << R_IS_UHES_SHIFT) | \
487
+# ===============
279
+ (1 << R_IS_UHXS_SHIFT) | (1 << R_IS_UPMS_SHIFT) | \
488
+
280
+ (1 << R_IS_UTMS_SHIFT) | (1 << R_IS_UE_SHIFT) | \
489
+class HelpFormatter(object):
281
+ (1 << R_IS_UDEPRI_SHIFT) | (1 << R_IS_UTRCS_SHIFT))
490
+ """Formatter for generating usage messages and argument help strings.
282
+
491
+
283
+#define UFS_UPIU_HEADER_TRANSACTION_TYPE_SHIFT 24
492
+ Only the name of this class is considered a public API. All the methods
284
+#define UFS_UPIU_HEADER_TRANSACTION_TYPE_MASK 0xff
493
+ provided by the class are considered an implementation detail.
285
+#define UFS_UPIU_HEADER_TRANSACTION_TYPE(dword0) \
494
+ """
286
+ ((be32_to_cpu(dword0) >> UFS_UPIU_HEADER_TRANSACTION_TYPE_SHIFT) & \
495
+
287
+ UFS_UPIU_HEADER_TRANSACTION_TYPE_MASK)
496
+ def __init__(self,
288
+
497
+ prog,
289
+#define UFS_UPIU_HEADER_QUERY_FUNC_SHIFT 16
498
+ indent_increment=2,
290
+#define UFS_UPIU_HEADER_QUERY_FUNC_MASK 0xff
499
+ max_help_position=24,
291
+#define UFS_UPIU_HEADER_QUERY_FUNC(dword1) \
500
+ width=None):
292
+ ((be32_to_cpu(dword1) >> UFS_UPIU_HEADER_QUERY_FUNC_SHIFT) & \
501
+
293
+ UFS_UPIU_HEADER_QUERY_FUNC_MASK)
502
+ # default setting for width
294
+
503
+ if width is None:
295
+#define UFS_UPIU_HEADER_DATA_SEGMENT_LENGTH_SHIFT 0
504
+ try:
296
+#define UFS_UPIU_HEADER_DATA_SEGMENT_LENGTH_MASK 0xffff
505
+ width = int(_os.environ['COLUMNS'])
297
+#define UFS_UPIU_HEADER_DATA_SEGMENT_LENGTH(dword2) \
506
+ except (KeyError, ValueError):
298
+ ((be32_to_cpu(dword2) >> UFS_UPIU_HEADER_DATA_SEGMENT_LENGTH_SHIFT) & \
507
+ width = 80
299
+ UFS_UPIU_HEADER_DATA_SEGMENT_LENGTH_MASK)
508
+ width -= 2
300
+
509
+
301
+typedef struct QEMU_PACKED DeviceDescriptor {
510
+ self._prog = prog
302
+ uint8_t length;
511
+ self._indent_increment = indent_increment
303
+ uint8_t descriptor_idn;
512
+ self._max_help_position = max_help_position
304
+ uint8_t device;
513
+ self._width = width
305
+ uint8_t device_class;
514
+
306
+ uint8_t device_sub_class;
515
+ self._current_indent = 0
307
+ uint8_t protocol;
516
+ self._level = 0
308
+ uint8_t number_lu;
517
+ self._action_max_length = 0
309
+ uint8_t number_wlu;
518
+
310
+ uint8_t boot_enable;
519
+ self._root_section = self._Section(self, None)
311
+ uint8_t descr_access_en;
520
+ self._current_section = self._root_section
312
+ uint8_t init_power_mode;
521
+
313
+ uint8_t high_priority_lun;
522
+ self._whitespace_matcher = _re.compile(r'\s+')
314
+ uint8_t secure_removal_type;
523
+ self._long_break_matcher = _re.compile(r'\n\n\n+')
315
+ uint8_t security_lu;
524
+
316
+ uint8_t background_ops_term_lat;
525
+ # ===============================
317
+ uint8_t init_active_icc_level;
526
+ # Section and indentation methods
318
+ uint16_t spec_version;
527
+ # ===============================
319
+ uint16_t manufacture_date;
528
+ def _indent(self):
320
+ uint8_t manufacturer_name;
529
+ self._current_indent += self._indent_increment
321
+ uint8_t product_name;
530
+ self._level += 1
322
+ uint8_t serial_number;
531
+
323
+ uint8_t oem_id;
532
+ def _dedent(self):
324
+ uint16_t manufacturer_id;
533
+ self._current_indent -= self._indent_increment
325
+ uint8_t ud_0_base_offset;
534
+ assert self._current_indent >= 0, 'Indent decreased below 0.'
326
+ uint8_t ud_config_p_length;
535
+ self._level -= 1
327
+ uint8_t device_rtt_cap;
536
+
328
+ uint16_t periodic_rtc_update;
537
+ class _Section(object):
329
+ uint8_t ufs_features_support;
538
+
330
+ uint8_t ffu_timeout;
539
+ def __init__(self, formatter, parent, heading=None):
331
+ uint8_t queue_depth;
540
+ self.formatter = formatter
332
+ uint16_t device_version;
541
+ self.parent = parent
333
+ uint8_t num_secure_wp_area;
542
+ self.heading = heading
334
+ uint32_t psa_max_data_size;
543
+ self.items = []
335
+ uint8_t psa_state_timeout;
544
+
336
+ uint8_t product_revision_level;
545
+ def format_help(self):
337
+ uint8_t reserved[36];
546
+ # format the indented section
338
+ uint32_t extended_ufs_features_support;
547
+ if self.parent is not None:
339
+ uint8_t write_booster_buffer_preserve_user_space_en;
548
+ self.formatter._indent()
340
+ uint8_t write_booster_buffer_type;
549
+ join = self.formatter._join_parts
341
+ uint32_t num_shared_write_booster_buffer_alloc_units;
550
+ for func, args in self.items:
342
+} DeviceDescriptor;
551
+ func(*args)
343
+
552
+ item_help = join([func(*args) for func, args in self.items])
344
+typedef struct QEMU_PACKED GeometryDescriptor {
553
+ if self.parent is not None:
345
+ uint8_t length;
554
+ self.formatter._dedent()
346
+ uint8_t descriptor_idn;
555
+
347
+ uint8_t media_technology;
556
+ # return nothing if the section was empty
348
+ uint8_t reserved;
557
+ if not item_help:
349
+ uint64_t total_raw_device_capacity;
558
+ return ''
350
+ uint8_t max_number_lu;
559
+
351
+ uint32_t segment_size;
560
+ # add the heading if the section was non-empty
352
+ uint8_t allocation_unit_size;
561
+ if self.heading is not SUPPRESS and self.heading is not None:
353
+ uint8_t min_addr_block_size;
562
+ current_indent = self.formatter._current_indent
354
+ uint8_t optimal_read_block_size;
563
+ heading = '%*s%s:\n' % (current_indent, '', self.heading)
355
+ uint8_t optimal_write_block_size;
564
+ else:
356
+ uint8_t max_in_buffer_size;
565
+ heading = ''
357
+ uint8_t max_out_buffer_size;
566
+
358
+ uint8_t rpmb_read_write_size;
567
+ # join the section-initial newline, the heading and the help
359
+ uint8_t dynamic_capacity_resource_policy;
568
+ return join(['\n', heading, item_help, '\n'])
360
+ uint8_t data_ordering;
569
+
361
+ uint8_t max_context_id_number;
570
+ def _add_item(self, func, args):
362
+ uint8_t sys_data_tag_unit_size;
571
+ self._current_section.items.append((func, args))
363
+ uint8_t sys_data_tag_res_size;
572
+
364
+ uint8_t supported_sec_r_types;
573
+ # ========================
365
+ uint16_t supported_memory_types;
574
+ # Message building methods
366
+ uint32_t system_code_max_n_alloc_u;
575
+ # ========================
367
+ uint16_t system_code_cap_adj_fac;
576
+ def start_section(self, heading):
368
+ uint32_t non_persist_max_n_alloc_u;
577
+ self._indent()
369
+ uint16_t non_persist_cap_adj_fac;
578
+ section = self._Section(self, self._current_section, heading)
370
+ uint32_t enhanced_1_max_n_alloc_u;
579
+ self._add_item(section.format_help, [])
371
+ uint16_t enhanced_1_cap_adj_fac;
580
+ self._current_section = section
372
+ uint32_t enhanced_2_max_n_alloc_u;
581
+
373
+ uint16_t enhanced_2_cap_adj_fac;
582
+ def end_section(self):
374
+ uint32_t enhanced_3_max_n_alloc_u;
583
+ self._current_section = self._current_section.parent
375
+ uint16_t enhanced_3_cap_adj_fac;
584
+ self._dedent()
376
+ uint32_t enhanced_4_max_n_alloc_u;
585
+
377
+ uint16_t enhanced_4_cap_adj_fac;
586
+ def add_text(self, text):
378
+ uint32_t optimal_logical_block_size;
587
+ if text is not SUPPRESS and text is not None:
379
+ uint8_t reserved2[7];
588
+ self._add_item(self._format_text, [text])
380
+ uint32_t write_booster_buffer_max_n_alloc_units;
589
+
381
+ uint8_t device_max_write_booster_l_us;
590
+ def add_usage(self, usage, actions, groups, prefix=None):
382
+ uint8_t write_booster_buffer_cap_adj_fac;
591
+ if usage is not SUPPRESS:
383
+ uint8_t supported_write_booster_buffer_user_space_reduction_types;
592
+ args = usage, actions, groups, prefix
384
+ uint8_t supported_write_booster_buffer_types;
593
+ self._add_item(self._format_usage, args)
385
+} GeometryDescriptor;
594
+
386
+
595
+ def add_argument(self, action):
387
+#define UFS_GEOMETRY_CAPACITY_SHIFT 9
596
+ if action.help is not SUPPRESS:
388
+
597
+
389
+typedef struct QEMU_PACKED UnitDescriptor {
598
+ # find all invocations
390
+ uint8_t length;
599
+ get_invocation = self._format_action_invocation
391
+ uint8_t descriptor_idn;
600
+ invocations = [get_invocation(action)]
392
+ uint8_t unit_index;
601
+ for subaction in self._iter_indented_subactions(action):
393
+ uint8_t lu_enable;
602
+ invocations.append(get_invocation(subaction))
394
+ uint8_t boot_lun_id;
603
+
395
+ uint8_t lu_write_protect;
604
+ # update the maximum item length
396
+ uint8_t lu_queue_depth;
605
+ invocation_length = max([len(s) for s in invocations])
397
+ uint8_t psa_sensitive;
606
+ action_length = invocation_length + self._current_indent
398
+ uint8_t memory_type;
607
+ self._action_max_length = max(self._action_max_length,
399
+ uint8_t data_reliability;
608
+ action_length)
400
+ uint8_t logical_block_size;
609
+
401
+ uint64_t logical_block_count;
610
+ # add the item to the list
402
+ uint32_t erase_block_size;
611
+ self._add_item(self._format_action, [action])
403
+ uint8_t provisioning_type;
612
+
404
+ uint64_t phy_mem_resource_count;
613
+ def add_arguments(self, actions):
405
+ uint16_t context_capabilities;
614
+ for action in actions:
406
+ uint8_t large_unit_granularity_m1;
615
+ self.add_argument(action)
407
+ uint8_t reserved[6];
616
+
408
+ uint32_t lu_num_write_booster_buffer_alloc_units;
617
+ # =======================
409
+} UnitDescriptor;
618
+ # Help-formatting methods
410
+
619
+ # =======================
411
+typedef struct QEMU_PACKED RpmbUnitDescriptor {
620
+ def format_help(self):
412
+ uint8_t length;
621
+ help = self._root_section.format_help()
413
+ uint8_t descriptor_idn;
622
+ if help:
414
+ uint8_t unit_index;
623
+ help = self._long_break_matcher.sub('\n\n', help)
415
+ uint8_t lu_enable;
624
+ help = help.strip('\n') + '\n'
416
+ uint8_t boot_lun_id;
625
+ return help
417
+ uint8_t lu_write_protect;
626
+
418
+ uint8_t lu_queue_depth;
627
+ def _join_parts(self, part_strings):
419
+ uint8_t psa_sensitive;
628
+ return ''.join([part
420
+ uint8_t memory_type;
629
+ for part in part_strings
421
+ uint8_t reserved;
630
+ if part and part is not SUPPRESS])
422
+ uint8_t logical_block_size;
631
+
423
+ uint64_t logical_block_count;
632
+ def _format_usage(self, usage, actions, groups, prefix):
424
+ uint32_t erase_block_size;
633
+ if prefix is None:
425
+ uint8_t provisioning_type;
634
+ prefix = _('usage: ')
426
+ uint64_t phy_mem_resource_count;
635
+
427
+ uint8_t reserved2[3];
636
+ # if usage is specified, use that
428
+} RpmbUnitDescriptor;
637
+ if usage is not None:
429
+
638
+ usage = usage % dict(prog=self._prog)
430
+typedef struct QEMU_PACKED PowerParametersDescriptor {
639
+
431
+ uint8_t length;
640
+ # if no optionals or positionals are available, usage is just prog
432
+ uint8_t descriptor_idn;
641
+ elif usage is None and not actions:
433
+ uint16_t active_icc_levels_vcc[16];
642
+ usage = '%(prog)s' % dict(prog=self._prog)
434
+ uint16_t active_icc_levels_vccq[16];
643
+
435
+ uint16_t active_icc_levels_vccq_2[16];
644
+ # if optionals and positionals are available, calculate usage
436
+} PowerParametersDescriptor;
645
+ elif usage is None:
437
+
646
+ prog = '%(prog)s' % dict(prog=self._prog)
438
+typedef struct QEMU_PACKED InterconnectDescriptor {
647
+
439
+ uint8_t length;
648
+ # split optionals from positionals
440
+ uint8_t descriptor_idn;
649
+ optionals = []
441
+ uint16_t bcd_unipro_version;
650
+ positionals = []
442
+ uint16_t bcd_mphy_version;
651
+ for action in actions:
443
+} InterconnectDescriptor;
652
+ if action.option_strings:
444
+
653
+ optionals.append(action)
445
+typedef struct QEMU_PACKED StringDescriptor {
654
+ else:
446
+ uint8_t length;
655
+ positionals.append(action)
447
+ uint8_t descriptor_idn;
656
+
448
+ uint16_t UC[126];
657
+ # build full usage string
449
+} StringDescriptor;
658
+ format = self._format_actions_usage
450
+
659
+ action_usage = format(optionals + positionals, groups)
451
+typedef struct QEMU_PACKED DeviceHealthDescriptor {
660
+ usage = ' '.join([s for s in [prog, action_usage] if s])
452
+ uint8_t length;
661
+
453
+ uint8_t descriptor_idn;
662
+ # wrap the usage parts if it's too long
454
+ uint8_t pre_eol_info;
663
+ text_width = self._width - self._current_indent
455
+ uint8_t device_life_time_est_a;
664
+ if len(prefix) + len(usage) > text_width:
456
+ uint8_t device_life_time_est_b;
665
+
457
+ uint8_t vendor_prop_info[32];
666
+ # break usage into wrappable parts
458
+ uint32_t refresh_total_count;
667
+ part_regexp = r'\(.*?\)+|\[.*?\]+|\S+'
459
+ uint32_t refresh_progress;
668
+ opt_usage = format(optionals, groups)
460
+} DeviceHealthDescriptor;
669
+ pos_usage = format(positionals, groups)
461
+
670
+ opt_parts = _re.findall(part_regexp, opt_usage)
462
+typedef struct QEMU_PACKED Flags {
671
+ pos_parts = _re.findall(part_regexp, pos_usage)
463
+ uint8_t reserved;
672
+ assert ' '.join(opt_parts) == opt_usage
464
+ uint8_t device_init;
673
+ assert ' '.join(pos_parts) == pos_usage
465
+ uint8_t permanent_wp_en;
674
+
466
+ uint8_t power_on_wp_en;
675
+ # helper for wrapping lines
467
+ uint8_t background_ops_en;
676
+ def get_lines(parts, indent, prefix=None):
468
+ uint8_t device_life_span_mode_en;
677
+ lines = []
469
+ uint8_t purge_enable;
678
+ line = []
470
+ uint8_t refresh_enable;
679
+ if prefix is not None:
471
+ uint8_t phy_resource_removal;
680
+ line_len = len(prefix) - 1
472
+ uint8_t busy_rtc;
681
+ else:
473
+ uint8_t reserved2;
682
+ line_len = len(indent) - 1
474
+ uint8_t permanently_disable_fw_update;
683
+ for part in parts:
475
+ uint8_t reserved3[2];
684
+ if line_len + 1 + len(part) > text_width:
476
+ uint8_t wb_en;
685
+ lines.append(indent + ' '.join(line))
477
+ uint8_t wb_buffer_flush_en;
686
+ line = []
478
+ uint8_t wb_buffer_flush_during_hibernate;
687
+ line_len = len(indent) - 1
479
+ uint8_t reserved4[2];
688
+ line.append(part)
480
+} Flags;
689
+ line_len += len(part) + 1
481
+
690
+ if line:
482
+typedef struct Attributes {
691
+ lines.append(indent + ' '.join(line))
483
+ uint8_t boot_lun_en;
692
+ if prefix is not None:
484
+ uint8_t reserved;
693
+ lines[0] = lines[0][len(indent):]
485
+ uint8_t current_power_mode;
694
+ return lines
486
+ uint8_t active_icc_level;
695
+
487
+ uint8_t out_of_order_data_en;
696
+ # if prog is short, follow it with optionals or positionals
488
+ uint8_t background_op_status;
697
+ if len(prefix) + len(prog) <= 0.75 * text_width:
489
+ uint8_t purge_status;
698
+ indent = ' ' * (len(prefix) + len(prog) + 1)
490
+ uint8_t max_data_in_size;
699
+ if opt_parts:
491
+ uint8_t max_data_out_size;
700
+ lines = get_lines([prog] + opt_parts, indent, prefix)
492
+ uint32_t dyn_cap_needed;
701
+ lines.extend(get_lines(pos_parts, indent))
493
+ uint8_t ref_clk_freq;
702
+ elif pos_parts:
494
+ uint8_t config_descr_lock;
703
+ lines = get_lines([prog] + pos_parts, indent, prefix)
495
+ uint8_t max_num_of_rtt;
704
+ else:
496
+ uint16_t exception_event_control;
705
+ lines = [prog]
497
+ uint16_t exception_event_status;
706
+
498
+ uint32_t seconds_passed;
707
+ # if prog is long, put it on its own line
499
+ uint16_t context_conf;
708
+ else:
500
+ uint8_t device_ffu_status;
709
+ indent = ' ' * len(prefix)
501
+ uint8_t psa_state;
710
+ parts = opt_parts + pos_parts
502
+ uint32_t psa_data_size;
711
+ lines = get_lines(parts, indent)
503
+ uint8_t ref_clk_gating_wait_time;
712
+ if len(lines) > 1:
504
+ uint8_t device_case_rough_temperaure;
713
+ lines = []
505
+ uint8_t device_too_high_temp_boundary;
714
+ lines.extend(get_lines(opt_parts, indent))
506
+ uint8_t device_too_low_temp_boundary;
715
+ lines.extend(get_lines(pos_parts, indent))
507
+ uint8_t throttling_status;
716
+ lines = [prog] + lines
508
+ uint8_t wb_buffer_flush_status;
717
+
509
+ uint8_t available_wb_buffer_size;
718
+ # join lines into usage
510
+ uint8_t wb_buffer_life_time_est;
719
+ usage = '\n'.join(lines)
511
+ uint32_t current_wb_buffer_size;
720
+
512
+ uint8_t refresh_status;
721
+ # prefix with 'usage:'
513
+ uint8_t refresh_freq;
722
+ return '%s%s\n\n' % (prefix, usage)
514
+ uint8_t refresh_unit;
723
+
515
+ uint8_t refresh_method;
724
+ def _format_actions_usage(self, actions, groups):
516
+} Attributes;
725
+ # find group indices and identify actions in groups
517
+
726
+ group_actions = set()
518
+#define UFS_TRANSACTION_SPECIFIC_FIELD_SIZE 20
727
+ inserts = {}
519
+#define UFS_MAX_QUERY_DATA_SIZE 256
728
+ for group in groups:
520
+
729
+ try:
521
+/* Command response result code */
730
+ start = actions.index(group._group_actions[0])
522
+typedef enum CommandRespCode {
731
+ except ValueError:
523
+ UFS_COMMAND_RESULT_SUCESS = 0x00,
732
+ continue
524
+ UFS_COMMAND_RESULT_FAIL = 0x01,
733
+ else:
525
+} CommandRespCode;
734
+ end = start + len(group._group_actions)
526
+
735
+ if actions[start:end] == group._group_actions:
527
+enum {
736
+ for action in group._group_actions:
528
+ UFS_UPIU_FLAG_UNDERFLOW = 0x20,
737
+ group_actions.add(action)
529
+ UFS_UPIU_FLAG_OVERFLOW = 0x40,
738
+ if not group.required:
530
+};
739
+ if start in inserts:
531
+
740
+ inserts[start] += ' ['
532
+typedef struct QEMU_PACKED UtpUpiuHeader {
741
+ else:
533
+ uint8_t trans_type;
742
+ inserts[start] = '['
534
+ uint8_t flags;
743
+ inserts[end] = ']'
535
+ uint8_t lun;
744
+ else:
536
+ uint8_t task_tag;
745
+ if start in inserts:
537
+ uint8_t iid_cmd_set_type;
746
+ inserts[start] += ' ('
538
+ uint8_t query_func;
747
+ else:
539
+ uint8_t response;
748
+ inserts[start] = '('
540
+ uint8_t scsi_status;
749
+ inserts[end] = ')'
541
+ uint8_t ehs_len;
750
+ for i in range(start + 1, end):
542
+ uint8_t device_inf;
751
+ inserts[i] = '|'
543
+ uint16_t data_segment_length;
752
+
544
+} UtpUpiuHeader;
753
+ # collect all actions format strings
545
+
754
+ parts = []
546
+/*
755
+ for i, action in enumerate(actions):
547
+ * The code below is copied from the linux kernel
756
+
548
+ * ("include/uapi/scsi/scsi_bsg_ufs.h") and modified to fit the qemu style.
757
+ # suppressed arguments are marked with None
549
+ */
758
+ # remove | separators for suppressed arguments
550
+
759
+ if action.help is SUPPRESS:
551
+typedef struct QEMU_PACKED UtpUpiuQuery {
760
+ parts.append(None)
552
+ uint8_t opcode;
761
+ if inserts.get(i) == '|':
553
+ uint8_t idn;
762
+ inserts.pop(i)
554
+ uint8_t index;
763
+ elif inserts.get(i + 1) == '|':
555
+ uint8_t selector;
764
+ inserts.pop(i + 1)
556
+ uint16_t reserved_osf;
765
+
557
+ uint16_t length;
766
+ # produce all arg strings
558
+ uint32_t value;
767
+ elif not action.option_strings:
559
+ uint32_t reserved[2];
768
+ part = self._format_args(action, action.dest)
560
+ /* EHS length should be 0. We don't have to worry about EHS area. */
769
+
561
+ uint8_t data[UFS_MAX_QUERY_DATA_SIZE];
770
+ # if it's in a group, strip the outer []
562
+} UtpUpiuQuery;
771
+ if action in group_actions:
563
+
772
+ if part[0] == '[' and part[-1] == ']':
564
+#define UFS_CDB_SIZE 16
773
+ part = part[1:-1]
565
+
774
+
566
+/*
775
+ # add the action string to the list
567
+ * struct UtpUpiuCmd - Command UPIU structure
776
+ parts.append(part)
568
+ * @data_transfer_len: Data Transfer Length DW-3
777
+
569
+ * @cdb: Command Descriptor Block CDB DW-4 to DW-7
778
+ # produce the first way to invoke the option in brackets
570
+ */
779
+ else:
571
+typedef struct QEMU_PACKED UtpUpiuCmd {
780
+ option_string = action.option_strings[0]
572
+ uint32_t exp_data_transfer_len;
781
+
573
+ uint8_t cdb[UFS_CDB_SIZE];
782
+ # if the Optional doesn't take a value, format is:
574
+} UtpUpiuCmd;
783
+ # -s or --long
575
+
784
+ if action.nargs == 0:
576
+/*
785
+ part = '%s' % option_string
577
+ * struct UtpUpiuReq - general upiu request structure
786
+
578
+ * @header:UPIU header structure DW-0 to DW-2
787
+ # if the Optional takes a value, format is:
579
+ * @sc: fields structure for scsi command DW-3 to DW-7
788
+ # -s ARGS or --long ARGS
580
+ * @qr: fields structure for query request DW-3 to DW-7
789
+ else:
581
+ * @uc: use utp_upiu_query to host the 4 dwords of uic command
790
+ default = action.dest.upper()
582
+ */
791
+ args_string = self._format_args(action, default)
583
+typedef struct QEMU_PACKED UtpUpiuReq {
792
+ part = '%s %s' % (option_string, args_string)
584
+ UtpUpiuHeader header;
793
+
585
+ union {
794
+ # make it look optional if it's not required or in a group
586
+ UtpUpiuCmd sc;
795
+ if not action.required and action not in group_actions:
587
+ UtpUpiuQuery qr;
796
+ part = '[%s]' % part
588
+ };
797
+
589
+} UtpUpiuReq;
798
+ # add the action string to the list
590
+
799
+ parts.append(part)
591
+/*
800
+
592
+ * The code below is copied from the linux kernel ("include/ufs/ufshci.h") and
801
+ # insert things at the necessary indices
593
+ * modified to fit the qemu style.
802
+ for i in sorted(inserts, reverse=True):
594
+ */
803
+ parts[i:i] = [inserts[i]]
595
+
804
+
596
+enum {
805
+ # join all the action items with spaces
597
+ UFS_PWR_OK = 0x0,
806
+ text = ' '.join([item for item in parts if item is not None])
598
+ UFS_PWR_LOCAL = 0x01,
807
+
599
+ UFS_PWR_REMOTE = 0x02,
808
+ # clean up separators for mutually exclusive groups
600
+ UFS_PWR_BUSY = 0x03,
809
+ open = r'[\[(]'
601
+ UFS_PWR_ERROR_CAP = 0x04,
810
+ close = r'[\])]'
602
+ UFS_PWR_FATAL_ERROR = 0x05,
811
+ text = _re.sub(r'(%s) ' % open, r'\1', text)
603
+};
812
+ text = _re.sub(r' (%s)' % close, r'\1', text)
604
+
813
+ text = _re.sub(r'%s *%s' % (open, close), r'', text)
605
+/* UIC Commands */
814
+ text = _re.sub(r'\(([^|]*)\)', r'\1', text)
606
+enum uic_cmd_dme {
815
+ text = text.strip()
607
+ UFS_UIC_CMD_DME_GET = 0x01,
816
+
608
+ UFS_UIC_CMD_DME_SET = 0x02,
817
+ # return the text
609
+ UFS_UIC_CMD_DME_PEER_GET = 0x03,
818
+ return text
610
+ UFS_UIC_CMD_DME_PEER_SET = 0x04,
819
+
611
+ UFS_UIC_CMD_DME_POWERON = 0x10,
820
+ def _format_text(self, text):
612
+ UFS_UIC_CMD_DME_POWEROFF = 0x11,
821
+ if '%(prog)' in text:
613
+ UFS_UIC_CMD_DME_ENABLE = 0x12,
822
+ text = text % dict(prog=self._prog)
614
+ UFS_UIC_CMD_DME_RESET = 0x14,
823
+ text_width = self._width - self._current_indent
615
+ UFS_UIC_CMD_DME_END_PT_RST = 0x15,
824
+ indent = ' ' * self._current_indent
616
+ UFS_UIC_CMD_DME_LINK_STARTUP = 0x16,
825
+ return self._fill_text(text, text_width, indent) + '\n\n'
617
+ UFS_UIC_CMD_DME_HIBER_ENTER = 0x17,
826
+
618
+ UFS_UIC_CMD_DME_HIBER_EXIT = 0x18,
827
+ def _format_action(self, action):
619
+ UFS_UIC_CMD_DME_TEST_MODE = 0x1A,
828
+ # determine the required width and the entry label
620
+};
829
+ help_position = min(self._action_max_length + 2,
621
+
830
+ self._max_help_position)
622
+/* UIC Config result code / Generic error code */
831
+ help_width = self._width - help_position
623
+enum {
832
+ action_width = help_position - self._current_indent - 2
624
+ UFS_UIC_CMD_RESULT_SUCCESS = 0x00,
833
+ action_header = self._format_action_invocation(action)
625
+ UFS_UIC_CMD_RESULT_INVALID_ATTR = 0x01,
834
+
626
+ UFS_UIC_CMD_RESULT_FAILURE = 0x01,
835
+ # ho nelp; start on same line and add a final newline
627
+ UFS_UIC_CMD_RESULT_INVALID_ATTR_VALUE = 0x02,
836
+ if not action.help:
628
+ UFS_UIC_CMD_RESULT_READ_ONLY_ATTR = 0x03,
837
+ tup = self._current_indent, '', action_header
629
+ UFS_UIC_CMD_RESULT_WRITE_ONLY_ATTR = 0x04,
838
+ action_header = '%*s%s\n' % tup
630
+ UFS_UIC_CMD_RESULT_BAD_INDEX = 0x05,
839
+
631
+ UFS_UIC_CMD_RESULT_LOCKED_ATTR = 0x06,
840
+ # short action name; start on the same line and pad two spaces
632
+ UFS_UIC_CMD_RESULT_BAD_TEST_FEATURE_INDEX = 0x07,
841
+ elif len(action_header) <= action_width:
633
+ UFS_UIC_CMD_RESULT_PEER_COMM_FAILURE = 0x08,
842
+ tup = self._current_indent, '', action_width, action_header
634
+ UFS_UIC_CMD_RESULT_BUSY = 0x09,
843
+ action_header = '%*s%-*s ' % tup
635
+ UFS_UIC_CMD_RESULT_DME_FAILURE = 0x0A,
844
+ indent_first = 0
636
+};
845
+
637
+
846
+ # long action name; start on the next line
638
+#define UFS_MASK_UIC_COMMAND_RESULT 0xFF
847
+ else:
639
+
848
+ tup = self._current_indent, '', action_header
640
+/*
849
+ action_header = '%*s%s\n' % tup
641
+ * Request Descriptor Definitions
850
+ indent_first = help_position
642
+ */
851
+
643
+
852
+ # collect the pieces of the action help
644
+/* Transfer request command type */
853
+ parts = [action_header]
645
+enum {
854
+
646
+ UFS_UTP_CMD_TYPE_SCSI = 0x0,
855
+ # if there was help for the action, add lines of help text
647
+ UFS_UTP_CMD_TYPE_UFS = 0x1,
856
+ if action.help:
648
+ UFS_UTP_CMD_TYPE_DEV_MANAGE = 0x2,
857
+ help_text = self._expand_help(action)
649
+};
858
+ help_lines = self._split_lines(help_text, help_width)
650
+
859
+ parts.append('%*s%s\n' % (indent_first, '', help_lines[0]))
651
+/* To accommodate UFS2.0 required Command type */
860
+ for line in help_lines[1:]:
652
+enum {
861
+ parts.append('%*s%s\n' % (help_position, '', line))
653
+ UFS_UTP_CMD_TYPE_UFS_STORAGE = 0x1,
862
+
654
+};
863
+ # or add a newline if the description doesn't end with one
655
+
864
+ elif not action_header.endswith('\n'):
656
+enum {
865
+ parts.append('\n')
657
+ UFS_UTP_SCSI_COMMAND = 0x00000000,
866
+
658
+ UFS_UTP_NATIVE_UFS_COMMAND = 0x10000000,
867
+ # if there are any sub-actions, add their help as well
659
+ UFS_UTP_DEVICE_MANAGEMENT_FUNCTION = 0x20000000,
868
+ for subaction in self._iter_indented_subactions(action):
660
+ UFS_UTP_REQ_DESC_INT_CMD = 0x01000000,
869
+ parts.append(self._format_action(subaction))
661
+ UFS_UTP_REQ_DESC_CRYPTO_ENABLE_CMD = 0x00800000,
870
+
662
+};
871
+ # return a single string
663
+
872
+ return self._join_parts(parts)
664
+/* UTP Transfer Request Data Direction (DD) */
873
+
665
+enum {
874
+ def _format_action_invocation(self, action):
666
+ UFS_UTP_NO_DATA_TRANSFER = 0x00000000,
875
+ if not action.option_strings:
667
+ UFS_UTP_HOST_TO_DEVICE = 0x02000000,
876
+ metavar, = self._metavar_formatter(action, action.dest)(1)
668
+ UFS_UTP_DEVICE_TO_HOST = 0x04000000,
877
+ return metavar
669
+};
878
+
670
+
879
+ else:
671
+/* Overall command status values */
880
+ parts = []
672
+enum UtpOcsCodes {
881
+
673
+ UFS_OCS_SUCCESS = 0x0,
882
+ # if the Optional doesn't take a value, format is:
674
+ UFS_OCS_INVALID_CMD_TABLE_ATTR = 0x1,
883
+ # -s, --long
675
+ UFS_OCS_INVALID_PRDT_ATTR = 0x2,
884
+ if action.nargs == 0:
676
+ UFS_OCS_MISMATCH_DATA_BUF_SIZE = 0x3,
885
+ parts.extend(action.option_strings)
677
+ UFS_OCS_MISMATCH_RESP_UPIU_SIZE = 0x4,
886
+
678
+ UFS_OCS_PEER_COMM_FAILURE = 0x5,
887
+ # if the Optional takes a value, format is:
679
+ UFS_OCS_ABORTED = 0x6,
888
+ # -s ARGS, --long ARGS
680
+ UFS_OCS_FATAL_ERROR = 0x7,
889
+ else:
681
+ UFS_OCS_DEVICE_FATAL_ERROR = 0x8,
890
+ default = action.dest.upper()
682
+ UFS_OCS_INVALID_CRYPTO_CONFIG = 0x9,
891
+ args_string = self._format_args(action, default)
683
+ UFS_OCS_GENERAL_CRYPTO_ERROR = 0xa,
892
+ for option_string in action.option_strings:
684
+ UFS_OCS_INVALID_COMMAND_STATUS = 0xf,
893
+ parts.append('%s %s' % (option_string, args_string))
685
+};
894
+
686
+
895
+ return ', '.join(parts)
687
+enum {
896
+
688
+ UFS_MASK_OCS = 0x0F,
897
+ def _metavar_formatter(self, action, default_metavar):
689
+};
898
+ if action.metavar is not None:
690
+
899
+ result = action.metavar
691
+/*
900
+ elif action.choices is not None:
692
+ * struct UfshcdSgEntry - UFSHCI PRD Entry
901
+ choice_strs = [str(choice) for choice in action.choices]
693
+ * @addr: Physical address; DW-0 and DW-1.
902
+ result = '{%s}' % ','.join(choice_strs)
694
+ * @reserved: Reserved for future use DW-2
903
+ else:
695
+ * @size: size of physical segment DW-3
904
+ result = default_metavar
696
+ */
905
+
697
+typedef struct QEMU_PACKED UfshcdSgEntry {
906
+ def format(tuple_size):
698
+ uint64_t addr;
907
+ if isinstance(result, tuple):
699
+ uint32_t reserved;
908
+ return result
700
+ uint32_t size;
909
+ else:
701
+ /*
910
+ return (result, ) * tuple_size
702
+ * followed by variant-specific fields if
911
+ return format
703
+ * CONFIG_SCSI_UFS_VARIABLE_SG_ENTRY_SIZE has been defined.
912
+
704
+ */
913
+ def _format_args(self, action, default_metavar):
705
+} UfshcdSgEntry;
914
+ get_metavar = self._metavar_formatter(action, default_metavar)
706
+
915
+ if action.nargs is None:
707
+/*
916
+ result = '%s' % get_metavar(1)
708
+ * struct RequestDescHeader - Descriptor Header common to both UTRD and UTMRD
917
+ elif action.nargs == OPTIONAL:
709
+ * @dword0: Descriptor Header DW0
918
+ result = '[%s]' % get_metavar(1)
710
+ * @dword1: Descriptor Header DW1
919
+ elif action.nargs == ZERO_OR_MORE:
711
+ * @dword2: Descriptor Header DW2
920
+ result = '[%s [%s ...]]' % get_metavar(2)
712
+ * @dword3: Descriptor Header DW3
921
+ elif action.nargs == ONE_OR_MORE:
713
+ */
922
+ result = '%s [%s ...]' % get_metavar(2)
714
+typedef struct QEMU_PACKED RequestDescHeader {
923
+ elif action.nargs == REMAINDER:
715
+ uint32_t dword_0;
924
+ result = '...'
716
+ uint32_t dword_1;
925
+ elif action.nargs == PARSER:
717
+ uint32_t dword_2;
926
+ result = '%s ...' % get_metavar(1)
718
+ uint32_t dword_3;
927
+ else:
719
+} RequestDescHeader;
928
+ formats = ['%s' for _ in range(action.nargs)]
720
+
929
+ result = ' '.join(formats) % get_metavar(action.nargs)
721
+/*
930
+ return result
722
+ * struct UtpTransferReqDesc - UTP Transfer Request Descriptor (UTRD)
931
+
723
+ * @header: UTRD header DW-0 to DW-3
932
+ def _expand_help(self, action):
724
+ * @command_desc_base_addr_lo: UCD base address low DW-4
933
+ params = dict(vars(action), prog=self._prog)
725
+ * @command_desc_base_addr_hi: UCD base address high DW-5
934
+ for name in list(params):
726
+ * @response_upiu_length: response UPIU length DW-6
935
+ if params[name] is SUPPRESS:
727
+ * @response_upiu_offset: response UPIU offset DW-6
936
+ del params[name]
728
+ * @prd_table_length: Physical region descriptor length DW-7
937
+ for name in list(params):
729
+ * @prd_table_offset: Physical region descriptor offset DW-7
938
+ if hasattr(params[name], '__name__'):
730
+ */
939
+ params[name] = params[name].__name__
731
+typedef struct QEMU_PACKED UtpTransferReqDesc {
940
+ if params.get('choices') is not None:
732
+ /* DW 0-3 */
941
+ choices_str = ', '.join([str(c) for c in params['choices']])
733
+ RequestDescHeader header;
942
+ params['choices'] = choices_str
734
+
943
+ return self._get_help_string(action) % params
735
+ /* DW 4-5*/
944
+
736
+ uint32_t command_desc_base_addr_lo;
945
+ def _iter_indented_subactions(self, action):
737
+ uint32_t command_desc_base_addr_hi;
946
+ try:
738
+
947
+ get_subactions = action._get_subactions
739
+ /* DW 6 */
948
+ except AttributeError:
740
+ uint16_t response_upiu_length;
949
+ pass
741
+ uint16_t response_upiu_offset;
950
+ else:
742
+
951
+ self._indent()
743
+ /* DW 7 */
952
+ for subaction in get_subactions():
744
+ uint16_t prd_table_length;
953
+ yield subaction
745
+ uint16_t prd_table_offset;
954
+ self._dedent()
746
+} UtpTransferReqDesc;
955
+
747
+
956
+ def _split_lines(self, text, width):
748
+/*
957
+ text = self._whitespace_matcher.sub(' ', text).strip()
749
+ * UTMRD structure.
958
+ return _textwrap.wrap(text, width)
750
+ */
959
+
751
+typedef struct QEMU_PACKED UtpTaskReqDesc {
960
+ def _fill_text(self, text, width, indent):
752
+ /* DW 0-3 */
961
+ text = self._whitespace_matcher.sub(' ', text).strip()
753
+ RequestDescHeader header;
962
+ return _textwrap.fill(text, width, initial_indent=indent,
754
+
963
+ subsequent_indent=indent)
755
+ /* DW 4-11 - Task request UPIU structure */
964
+
756
+ struct {
965
+ def _get_help_string(self, action):
757
+ UtpUpiuHeader req_header;
966
+ return action.help
758
+ uint32_t input_param1;
967
+
759
+ uint32_t input_param2;
968
+
760
+ uint32_t input_param3;
969
+class RawDescriptionHelpFormatter(HelpFormatter):
761
+ uint32_t reserved1[2];
970
+ """Help message formatter which retains any formatting in descriptions.
762
+ } upiu_req;
971
+
763
+
972
+ Only the name of this class is considered a public API. All the methods
764
+ /* DW 12-19 - Task Management Response UPIU structure */
973
+ provided by the class are considered an implementation detail.
765
+ struct {
974
+ """
766
+ UtpUpiuHeader rsp_header;
975
+
767
+ uint32_t output_param1;
976
+ def _fill_text(self, text, width, indent):
768
+ uint32_t output_param2;
977
+ return ''.join([indent + line for line in text.splitlines(True)])
769
+ uint32_t reserved2[3];
978
+
770
+ } upiu_rsp;
979
+
771
+} UtpTaskReqDesc;
980
+class RawTextHelpFormatter(RawDescriptionHelpFormatter):
772
+
981
+ """Help message formatter which retains formatting of all help text.
773
+/*
982
+
774
+ * The code below is copied from the linux kernel ("include/ufs/ufs.h") and
983
+ Only the name of this class is considered a public API. All the methods
775
+ * modified to fit the qemu style.
984
+ provided by the class are considered an implementation detail.
776
+ */
985
+ """
777
+
986
+
778
+#define UFS_GENERAL_UPIU_REQUEST_SIZE (sizeof(UtpUpiuReq))
987
+ def _split_lines(self, text, width):
779
+#define UFS_QUERY_DESC_MAX_SIZE 255
988
+ return text.splitlines()
780
+#define UFS_QUERY_DESC_MIN_SIZE 2
989
+
781
+#define UFS_QUERY_DESC_HDR_SIZE 2
990
+
782
+#define UFS_QUERY_OSF_SIZE (GENERAL_UPIU_REQUEST_SIZE - (sizeof(UtpUpiuHeader)))
991
+class ArgumentDefaultsHelpFormatter(HelpFormatter):
783
+#define UFS_SENSE_SIZE 18
992
+ """Help message formatter which adds default values to argument help.
784
+
993
+
785
+/*
994
+ Only the name of this class is considered a public API. All the methods
786
+ * UFS device may have standard LUs and LUN id could be from 0x00 to
995
+ provided by the class are considered an implementation detail.
787
+ * 0x7F. Standard LUs use "Peripheral Device Addressing Format".
996
+ """
788
+ * UFS device may also have the Well Known LUs (also referred as W-LU)
997
+
789
+ * which again could be from 0x00 to 0x7F. For W-LUs, device only use
998
+ def _get_help_string(self, action):
790
+ * the "Extended Addressing Format" which means the W-LUNs would be
999
+ help = action.help
791
+ * from 0xc100 (SCSI_W_LUN_BASE) onwards.
1000
+ if '%(default)' not in action.help:
792
+ * This means max. LUN number reported from UFS device could be 0xC17F.
1001
+ if action.default is not SUPPRESS:
793
+ */
1002
+ defaulting_nargs = [OPTIONAL, ZERO_OR_MORE]
794
+#define UFS_UPIU_MAX_UNIT_NUM_ID 0x7F
1003
+ if action.option_strings or action.nargs in defaulting_nargs:
795
+#define UFS_UPIU_WLUN_ID (1 << 7)
1004
+ help += ' (default: %(default)s)'
796
+
1005
+ return help
797
+/* WriteBooster buffer is available only for the logical unit from 0 to 7 */
1006
+
798
+#define UFS_UPIU_MAX_WB_LUN_ID 8
1007
+
799
+
1008
+# =====================
800
+/*
1009
+# Options and Arguments
801
+ * WriteBooster buffer lifetime has a limit setted by vendor.
1010
+# =====================
802
+ * If it is over the limit, WriteBooster feature will be disabled.
1011
+
803
+ */
1012
+def _get_action_name(argument):
804
+#define UFS_WB_EXCEED_LIFETIME 0x0B
1013
+ if argument is None:
805
+
1014
+ return None
806
+/*
1015
+ elif argument.option_strings:
807
+ * In UFS Spec, the Extra Header Segment (EHS) starts from byte 32 in UPIU
1016
+ return '/'.join(argument.option_strings)
808
+ * request/response packet
1017
+ elif argument.metavar not in (None, SUPPRESS):
809
+ */
1018
+ return argument.metavar
810
+#define UFS_EHS_OFFSET_IN_RESPONSE 32
1019
+ elif argument.dest not in (None, SUPPRESS):
811
+
1020
+ return argument.dest
812
+/* Well known logical unit id in LUN field of UPIU */
1021
+ else:
813
+enum {
1022
+ return None
814
+ UFS_UPIU_REPORT_LUNS_WLUN = 0x81,
1023
+
815
+ UFS_UPIU_UFS_DEVICE_WLUN = 0xD0,
1024
+
816
+ UFS_UPIU_BOOT_WLUN = 0xB0,
1025
+class ArgumentError(Exception):
817
+ UFS_UPIU_RPMB_WLUN = 0xC4,
1026
+ """An error from creating or using an argument (optional or positional).
818
+};
1027
+
819
+
1028
+ The string value of this exception is the message, augmented with
820
+/*
1029
+ information about the argument that caused it.
821
+ * UFS Protocol Information Unit related definitions
1030
+ """
822
+ */
1031
+
823
+
1032
+ def __init__(self, argument, message):
824
+/* Task management functions */
1033
+ self.argument_name = _get_action_name(argument)
825
+enum {
1034
+ self.message = message
826
+ UFS_ABORT_TASK = 0x01,
1035
+
827
+ UFS_ABORT_TASK_SET = 0x02,
1036
+ def __str__(self):
828
+ UFS_CLEAR_TASK_SET = 0x04,
1037
+ if self.argument_name is None:
829
+ UFS_LOGICAL_RESET = 0x08,
1038
+ format = '%(message)s'
830
+ UFS_QUERY_TASK = 0x80,
1039
+ else:
831
+ UFS_QUERY_TASK_SET = 0x81,
1040
+ format = 'argument %(argument_name)s: %(message)s'
832
+};
1041
+ return format % dict(message=self.message,
833
+
1042
+ argument_name=self.argument_name)
834
+/* UTP UPIU Transaction Codes Initiator to Target */
1043
+
835
+enum {
1044
+
836
+ UFS_UPIU_TRANSACTION_NOP_OUT = 0x00,
1045
+class ArgumentTypeError(Exception):
837
+ UFS_UPIU_TRANSACTION_COMMAND = 0x01,
1046
+ """An error from trying to convert a command line string to a type."""
838
+ UFS_UPIU_TRANSACTION_DATA_OUT = 0x02,
1047
+ pass
839
+ UFS_UPIU_TRANSACTION_TASK_REQ = 0x04,
1048
+
840
+ UFS_UPIU_TRANSACTION_QUERY_REQ = 0x16,
1049
+
841
+};
1050
+# ==============
842
+
1051
+# Action classes
843
+/* UTP UPIU Transaction Codes Target to Initiator */
1052
+# ==============
844
+enum {
1053
+
845
+ UFS_UPIU_TRANSACTION_NOP_IN = 0x20,
1054
+class Action(_AttributeHolder):
846
+ UFS_UPIU_TRANSACTION_RESPONSE = 0x21,
1055
+ """Information about how to convert command line strings to Python objects.
847
+ UFS_UPIU_TRANSACTION_DATA_IN = 0x22,
1056
+
848
+ UFS_UPIU_TRANSACTION_TASK_RSP = 0x24,
1057
+ Action objects are used by an ArgumentParser to represent the information
849
+ UFS_UPIU_TRANSACTION_READY_XFER = 0x31,
1058
+ needed to parse a single argument from one or more strings from the
850
+ UFS_UPIU_TRANSACTION_QUERY_RSP = 0x36,
1059
+ command line. The keyword arguments to the Action constructor are also
851
+ UFS_UPIU_TRANSACTION_REJECT_UPIU = 0x3F,
1060
+ all attributes of Action instances.
852
+};
1061
+
853
+
1062
+ Keyword Arguments:
854
+/* UPIU Read/Write flags */
1063
+
855
+enum {
1064
+ - option_strings -- A list of command-line option strings which
856
+ UFS_UPIU_CMD_FLAGS_NONE = 0x00,
1065
+ should be associated with this action.
857
+ UFS_UPIU_CMD_FLAGS_WRITE = 0x20,
1066
+
858
+ UFS_UPIU_CMD_FLAGS_READ = 0x40,
1067
+ - dest -- The name of the attribute to hold the created object(s)
859
+};
1068
+
860
+
1069
+ - nargs -- The number of command-line arguments that should be
861
+/* UPIU Task Attributes */
1070
+ consumed. By default, one argument will be consumed and a single
862
+enum {
1071
+ value will be produced. Other values include:
863
+ UFS_UPIU_TASK_ATTR_SIMPLE = 0x00,
1072
+ - N (an integer) consumes N arguments (and produces a list)
864
+ UFS_UPIU_TASK_ATTR_ORDERED = 0x01,
1073
+ - '?' consumes zero or one arguments
865
+ UFS_UPIU_TASK_ATTR_HEADQ = 0x02,
1074
+ - '*' consumes zero or more arguments (and produces a list)
866
+ UFS_UPIU_TASK_ATTR_ACA = 0x03,
1075
+ - '+' consumes one or more arguments (and produces a list)
867
+};
1076
+ Note that the difference between the default and nargs=1 is that
868
+
1077
+ with the default, a single value will be produced, while with
869
+/* UPIU Query request function */
1078
+ nargs=1, a list containing a single value will be produced.
870
+enum {
1079
+
871
+ UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST = 0x01,
1080
+ - const -- The value to be produced if the option is specified and the
872
+ UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST = 0x81,
1081
+ option uses an action that takes no values.
873
+};
1082
+
874
+
1083
+ - default -- The value to be produced if the option is not specified.
875
+/* Flag idn for Query Requests*/
1084
+
876
+enum flag_idn {
1085
+ - type -- The type which the command-line arguments should be converted
877
+ UFS_QUERY_FLAG_IDN_FDEVICEINIT = 0x01,
1086
+ to, should be one of 'string', 'int', 'float', 'complex' or a
878
+ UFS_QUERY_FLAG_IDN_PERMANENT_WPE = 0x02,
1087
+ callable object that accepts a single string argument. If None,
879
+ UFS_QUERY_FLAG_IDN_PWR_ON_WPE = 0x03,
1088
+ 'string' is assumed.
880
+ UFS_QUERY_FLAG_IDN_BKOPS_EN = 0x04,
1089
+
881
+ UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE = 0x05,
1090
+ - choices -- A container of values that should be allowed. If not None,
882
+ UFS_QUERY_FLAG_IDN_PURGE_ENABLE = 0x06,
1091
+ after a command-line argument has been converted to the appropriate
883
+ UFS_QUERY_FLAG_IDN_REFRESH_ENABLE = 0x07,
1092
+ type, an exception will be raised if it is not a member of this
884
+ UFS_QUERY_FLAG_IDN_FPHYRESOURCEREMOVAL = 0x08,
1093
+ collection.
885
+ UFS_QUERY_FLAG_IDN_BUSY_RTC = 0x09,
1094
+
886
+ UFS_QUERY_FLAG_IDN_RESERVED3 = 0x0A,
1095
+ - required -- True if the action must always be specified at the
887
+ UFS_QUERY_FLAG_IDN_PERMANENTLY_DISABLE_FW_UPDATE = 0x0B,
1096
+ command line. This is only meaningful for optional command-line
888
+ UFS_QUERY_FLAG_IDN_WB_EN = 0x0E,
1097
+ arguments.
889
+ UFS_QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN = 0x0F,
1098
+
890
+ UFS_QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8 = 0x10,
1099
+ - help -- The help string describing the argument.
891
+ UFS_QUERY_FLAG_IDN_HPB_RESET = 0x11,
1100
+
892
+ UFS_QUERY_FLAG_IDN_HPB_EN = 0x12,
1101
+ - metavar -- The name to be used for the option's argument with the
893
+ UFS_QUERY_FLAG_IDN_COUNT,
1102
+ help string. If None, the 'dest' value will be used as the name.
894
+};
1103
+ """
895
+
1104
+
896
+/* Attribute idn for Query requests */
1105
+ def __init__(self,
897
+enum attr_idn {
1106
+ option_strings,
898
+ UFS_QUERY_ATTR_IDN_BOOT_LU_EN = 0x00,
1107
+ dest,
899
+ UFS_QUERY_ATTR_IDN_MAX_HPB_SINGLE_CMD = 0x01,
1108
+ nargs=None,
900
+ UFS_QUERY_ATTR_IDN_POWER_MODE = 0x02,
1109
+ const=None,
901
+ UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL = 0x03,
1110
+ default=None,
902
+ UFS_QUERY_ATTR_IDN_OOO_DATA_EN = 0x04,
1111
+ type=None,
903
+ UFS_QUERY_ATTR_IDN_BKOPS_STATUS = 0x05,
1112
+ choices=None,
904
+ UFS_QUERY_ATTR_IDN_PURGE_STATUS = 0x06,
1113
+ required=False,
905
+ UFS_QUERY_ATTR_IDN_MAX_DATA_IN = 0x07,
1114
+ help=None,
906
+ UFS_QUERY_ATTR_IDN_MAX_DATA_OUT = 0x08,
1115
+ metavar=None):
907
+ UFS_QUERY_ATTR_IDN_DYN_CAP_NEEDED = 0x09,
1116
+ self.option_strings = option_strings
908
+ UFS_QUERY_ATTR_IDN_REF_CLK_FREQ = 0x0A,
1117
+ self.dest = dest
909
+ UFS_QUERY_ATTR_IDN_CONF_DESC_LOCK = 0x0B,
1118
+ self.nargs = nargs
910
+ UFS_QUERY_ATTR_IDN_MAX_NUM_OF_RTT = 0x0C,
1119
+ self.const = const
911
+ UFS_QUERY_ATTR_IDN_EE_CONTROL = 0x0D,
1120
+ self.default = default
912
+ UFS_QUERY_ATTR_IDN_EE_STATUS = 0x0E,
1121
+ self.type = type
913
+ UFS_QUERY_ATTR_IDN_SECONDS_PASSED = 0x0F,
1122
+ self.choices = choices
914
+ UFS_QUERY_ATTR_IDN_CNTX_CONF = 0x10,
1123
+ self.required = required
915
+ UFS_QUERY_ATTR_IDN_CORR_PRG_BLK_NUM = 0x11,
1124
+ self.help = help
916
+ UFS_QUERY_ATTR_IDN_RESERVED2 = 0x12,
1125
+ self.metavar = metavar
917
+ UFS_QUERY_ATTR_IDN_RESERVED3 = 0x13,
1126
+
918
+ UFS_QUERY_ATTR_IDN_FFU_STATUS = 0x14,
1127
+ def _get_kwargs(self):
919
+ UFS_QUERY_ATTR_IDN_PSA_STATE = 0x15,
1128
+ names = [
920
+ UFS_QUERY_ATTR_IDN_PSA_DATA_SIZE = 0x16,
1129
+ 'option_strings',
921
+ UFS_QUERY_ATTR_IDN_REF_CLK_GATING_WAIT_TIME = 0x17,
1130
+ 'dest',
922
+ UFS_QUERY_ATTR_IDN_CASE_ROUGH_TEMP = 0x18,
1131
+ 'nargs',
923
+ UFS_QUERY_ATTR_IDN_HIGH_TEMP_BOUND = 0x19,
1132
+ 'const',
924
+ UFS_QUERY_ATTR_IDN_LOW_TEMP_BOUND = 0x1A,
1133
+ 'default',
925
+ UFS_QUERY_ATTR_IDN_THROTTLING_STATUS = 0x1B,
1134
+ 'type',
926
+ UFS_QUERY_ATTR_IDN_WB_FLUSH_STATUS = 0x1C,
1135
+ 'choices',
927
+ UFS_QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE = 0x1D,
1136
+ 'help',
928
+ UFS_QUERY_ATTR_IDN_WB_BUFF_LIFE_TIME_EST = 0x1E,
1137
+ 'metavar',
929
+ UFS_QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE = 0x1F,
1138
+ ]
930
+ UFS_QUERY_ATTR_IDN_REFRESH_STATUS = 0x2C,
1139
+ return [(name, getattr(self, name)) for name in names]
931
+ UFS_QUERY_ATTR_IDN_REFRESH_FREQ = 0x2D,
1140
+
932
+ UFS_QUERY_ATTR_IDN_REFRESH_UNIT = 0x2E,
1141
+ def __call__(self, parser, namespace, values, option_string=None):
933
+ UFS_QUERY_ATTR_IDN_COUNT,
1142
+ raise NotImplementedError(_('.__call__() not defined'))
934
+};
1143
+
935
+
1144
+
936
+/* Descriptor idn for Query requests */
1145
+class _StoreAction(Action):
937
+enum desc_idn {
1146
+
938
+ UFS_QUERY_DESC_IDN_DEVICE = 0x0,
1147
+ def __init__(self,
939
+ UFS_QUERY_DESC_IDN_CONFIGURATION = 0x1,
1148
+ option_strings,
940
+ UFS_QUERY_DESC_IDN_UNIT = 0x2,
1149
+ dest,
941
+ UFS_QUERY_DESC_IDN_RFU_0 = 0x3,
1150
+ nargs=None,
942
+ UFS_QUERY_DESC_IDN_INTERCONNECT = 0x4,
1151
+ const=None,
943
+ UFS_QUERY_DESC_IDN_STRING = 0x5,
1152
+ default=None,
944
+ UFS_QUERY_DESC_IDN_RFU_1 = 0x6,
1153
+ type=None,
945
+ UFS_QUERY_DESC_IDN_GEOMETRY = 0x7,
1154
+ choices=None,
946
+ UFS_QUERY_DESC_IDN_POWER = 0x8,
1155
+ required=False,
947
+ UFS_QUERY_DESC_IDN_HEALTH = 0x9,
1156
+ help=None,
948
+ UFS_QUERY_DESC_IDN_MAX,
1157
+ metavar=None):
949
+};
1158
+ if nargs == 0:
950
+
1159
+ raise ValueError('nargs for store actions must be > 0; if you '
951
+enum desc_header_offset {
1160
+ 'have nothing to store, actions such as store '
952
+ UFS_QUERY_DESC_LENGTH_OFFSET = 0x00,
1161
+ 'true or store const may be more appropriate')
953
+ UFS_QUERY_DESC_DESC_TYPE_OFFSET = 0x01,
1162
+ if const is not None and nargs != OPTIONAL:
954
+};
1163
+ raise ValueError('nargs must be %r to supply const' % OPTIONAL)
955
+
1164
+ super(_StoreAction, self).__init__(
956
+/* Unit descriptor parameters offsets in bytes*/
1165
+ option_strings=option_strings,
957
+enum unit_desc_param {
1166
+ dest=dest,
958
+ UFS_UNIT_DESC_PARAM_LEN = 0x0,
1167
+ nargs=nargs,
959
+ UFS_UNIT_DESC_PARAM_TYPE = 0x1,
1168
+ const=const,
960
+ UFS_UNIT_DESC_PARAM_UNIT_INDEX = 0x2,
1169
+ default=default,
961
+ UFS_UNIT_DESC_PARAM_LU_ENABLE = 0x3,
1170
+ type=type,
962
+ UFS_UNIT_DESC_PARAM_BOOT_LUN_ID = 0x4,
1171
+ choices=choices,
963
+ UFS_UNIT_DESC_PARAM_LU_WR_PROTECT = 0x5,
1172
+ required=required,
964
+ UFS_UNIT_DESC_PARAM_LU_Q_DEPTH = 0x6,
1173
+ help=help,
965
+ UFS_UNIT_DESC_PARAM_PSA_SENSITIVE = 0x7,
1174
+ metavar=metavar)
966
+ UFS_UNIT_DESC_PARAM_MEM_TYPE = 0x8,
1175
+
967
+ UFS_UNIT_DESC_PARAM_DATA_RELIABILITY = 0x9,
1176
+ def __call__(self, parser, namespace, values, option_string=None):
968
+ UFS_UNIT_DESC_PARAM_LOGICAL_BLK_SIZE = 0xA,
1177
+ setattr(namespace, self.dest, values)
969
+ UFS_UNIT_DESC_PARAM_LOGICAL_BLK_COUNT = 0xB,
1178
+
970
+ UFS_UNIT_DESC_PARAM_ERASE_BLK_SIZE = 0x13,
1179
+
971
+ UFS_UNIT_DESC_PARAM_PROVISIONING_TYPE = 0x17,
1180
+class _StoreConstAction(Action):
972
+ UFS_UNIT_DESC_PARAM_PHY_MEM_RSRC_CNT = 0x18,
1181
+
973
+ UFS_UNIT_DESC_PARAM_CTX_CAPABILITIES = 0x20,
1182
+ def __init__(self,
974
+ UFS_UNIT_DESC_PARAM_LARGE_UNIT_SIZE_M1 = 0x22,
1183
+ option_strings,
975
+ UFS_UNIT_DESC_PARAM_HPB_LU_MAX_ACTIVE_RGNS = 0x23,
1184
+ dest,
976
+ UFS_UNIT_DESC_PARAM_HPB_PIN_RGN_START_OFF = 0x25,
1185
+ const,
977
+ UFS_UNIT_DESC_PARAM_HPB_NUM_PIN_RGNS = 0x27,
1186
+ default=None,
978
+ UFS_UNIT_DESC_PARAM_WB_BUF_ALLOC_UNITS = 0x29,
1187
+ required=False,
979
+};
1188
+ help=None,
980
+
1189
+ metavar=None):
981
+/* RPMB Unit descriptor parameters offsets in bytes*/
1190
+ super(_StoreConstAction, self).__init__(
982
+enum rpmb_unit_desc_param {
1191
+ option_strings=option_strings,
983
+ UFS_RPMB_UNIT_DESC_PARAM_LEN = 0x0,
1192
+ dest=dest,
984
+ UFS_RPMB_UNIT_DESC_PARAM_TYPE = 0x1,
1193
+ nargs=0,
985
+ UFS_RPMB_UNIT_DESC_PARAM_UNIT_INDEX = 0x2,
1194
+ const=const,
986
+ UFS_RPMB_UNIT_DESC_PARAM_LU_ENABLE = 0x3,
1195
+ default=default,
987
+ UFS_RPMB_UNIT_DESC_PARAM_BOOT_LUN_ID = 0x4,
1196
+ required=required,
988
+ UFS_RPMB_UNIT_DESC_PARAM_LU_WR_PROTECT = 0x5,
1197
+ help=help)
989
+ UFS_RPMB_UNIT_DESC_PARAM_LU_Q_DEPTH = 0x6,
1198
+
990
+ UFS_RPMB_UNIT_DESC_PARAM_PSA_SENSITIVE = 0x7,
1199
+ def __call__(self, parser, namespace, values, option_string=None):
991
+ UFS_RPMB_UNIT_DESC_PARAM_MEM_TYPE = 0x8,
1200
+ setattr(namespace, self.dest, self.const)
992
+ UFS_RPMB_UNIT_DESC_PARAM_REGION_EN = 0x9,
1201
+
993
+ UFS_RPMB_UNIT_DESC_PARAM_LOGICAL_BLK_SIZE = 0xA,
1202
+
994
+ UFS_RPMB_UNIT_DESC_PARAM_LOGICAL_BLK_COUNT = 0xB,
1203
+class _StoreTrueAction(_StoreConstAction):
995
+ UFS_RPMB_UNIT_DESC_PARAM_REGION0_SIZE = 0x13,
1204
+
996
+ UFS_RPMB_UNIT_DESC_PARAM_REGION1_SIZE = 0x14,
1205
+ def __init__(self,
997
+ UFS_RPMB_UNIT_DESC_PARAM_REGION2_SIZE = 0x15,
1206
+ option_strings,
998
+ UFS_RPMB_UNIT_DESC_PARAM_REGION3_SIZE = 0x16,
1207
+ dest,
999
+ UFS_RPMB_UNIT_DESC_PARAM_PROVISIONING_TYPE = 0x17,
1208
+ default=False,
1000
+ UFS_RPMB_UNIT_DESC_PARAM_PHY_MEM_RSRC_CNT = 0x18,
1209
+ required=False,
1001
+};
1210
+ help=None):
1002
+
1211
+ super(_StoreTrueAction, self).__init__(
1003
+/* Device descriptor parameters offsets in bytes*/
1212
+ option_strings=option_strings,
1004
+enum device_desc_param {
1213
+ dest=dest,
1005
+ UFS_DEVICE_DESC_PARAM_LEN = 0x0,
1214
+ const=True,
1006
+ UFS_DEVICE_DESC_PARAM_TYPE = 0x1,
1215
+ default=default,
1007
+ UFS_DEVICE_DESC_PARAM_DEVICE_TYPE = 0x2,
1216
+ required=required,
1008
+ UFS_DEVICE_DESC_PARAM_DEVICE_CLASS = 0x3,
1217
+ help=help)
1009
+ UFS_DEVICE_DESC_PARAM_DEVICE_SUB_CLASS = 0x4,
1218
+
1010
+ UFS_DEVICE_DESC_PARAM_PRTCL = 0x5,
1219
+
1011
+ UFS_DEVICE_DESC_PARAM_NUM_LU = 0x6,
1220
+class _StoreFalseAction(_StoreConstAction):
1012
+ UFS_DEVICE_DESC_PARAM_NUM_WLU = 0x7,
1221
+
1013
+ UFS_DEVICE_DESC_PARAM_BOOT_ENBL = 0x8,
1222
+ def __init__(self,
1014
+ UFS_DEVICE_DESC_PARAM_DESC_ACCSS_ENBL = 0x9,
1223
+ option_strings,
1015
+ UFS_DEVICE_DESC_PARAM_INIT_PWR_MODE = 0xA,
1224
+ dest,
1016
+ UFS_DEVICE_DESC_PARAM_HIGH_PR_LUN = 0xB,
1225
+ default=True,
1017
+ UFS_DEVICE_DESC_PARAM_SEC_RMV_TYPE = 0xC,
1226
+ required=False,
1018
+ UFS_DEVICE_DESC_PARAM_SEC_LU = 0xD,
1227
+ help=None):
1019
+ UFS_DEVICE_DESC_PARAM_BKOP_TERM_LT = 0xE,
1228
+ super(_StoreFalseAction, self).__init__(
1020
+ UFS_DEVICE_DESC_PARAM_ACTVE_ICC_LVL = 0xF,
1229
+ option_strings=option_strings,
1021
+ UFS_DEVICE_DESC_PARAM_SPEC_VER = 0x10,
1230
+ dest=dest,
1022
+ UFS_DEVICE_DESC_PARAM_MANF_DATE = 0x12,
1231
+ const=False,
1023
+ UFS_DEVICE_DESC_PARAM_MANF_NAME = 0x14,
1232
+ default=default,
1024
+ UFS_DEVICE_DESC_PARAM_PRDCT_NAME = 0x15,
1233
+ required=required,
1025
+ UFS_DEVICE_DESC_PARAM_SN = 0x16,
1234
+ help=help)
1026
+ UFS_DEVICE_DESC_PARAM_OEM_ID = 0x17,
1235
+
1027
+ UFS_DEVICE_DESC_PARAM_MANF_ID = 0x18,
1236
+
1028
+ UFS_DEVICE_DESC_PARAM_UD_OFFSET = 0x1A,
1237
+class _AppendAction(Action):
1029
+ UFS_DEVICE_DESC_PARAM_UD_LEN = 0x1B,
1238
+
1030
+ UFS_DEVICE_DESC_PARAM_RTT_CAP = 0x1C,
1239
+ def __init__(self,
1031
+ UFS_DEVICE_DESC_PARAM_FRQ_RTC = 0x1D,
1240
+ option_strings,
1032
+ UFS_DEVICE_DESC_PARAM_UFS_FEAT = 0x1F,
1241
+ dest,
1033
+ UFS_DEVICE_DESC_PARAM_FFU_TMT = 0x20,
1242
+ nargs=None,
1034
+ UFS_DEVICE_DESC_PARAM_Q_DPTH = 0x21,
1243
+ const=None,
1035
+ UFS_DEVICE_DESC_PARAM_DEV_VER = 0x22,
1244
+ default=None,
1036
+ UFS_DEVICE_DESC_PARAM_NUM_SEC_WPA = 0x24,
1245
+ type=None,
1037
+ UFS_DEVICE_DESC_PARAM_PSA_MAX_DATA = 0x25,
1246
+ choices=None,
1038
+ UFS_DEVICE_DESC_PARAM_PSA_TMT = 0x29,
1247
+ required=False,
1039
+ UFS_DEVICE_DESC_PARAM_PRDCT_REV = 0x2A,
1248
+ help=None,
1040
+ UFS_DEVICE_DESC_PARAM_HPB_VER = 0x40,
1249
+ metavar=None):
1041
+ UFS_DEVICE_DESC_PARAM_HPB_CONTROL = 0x42,
1250
+ if nargs == 0:
1042
+ UFS_DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP = 0x4F,
1251
+ raise ValueError('nargs for append actions must be > 0; if arg '
1043
+ UFS_DEVICE_DESC_PARAM_WB_PRESRV_USRSPC_EN = 0x53,
1252
+ 'strings are not supplying the value to append, '
1044
+ UFS_DEVICE_DESC_PARAM_WB_TYPE = 0x54,
1253
+ 'the append const action may be more appropriate')
1045
+ UFS_DEVICE_DESC_PARAM_WB_SHARED_ALLOC_UNITS = 0x55,
1254
+ if const is not None and nargs != OPTIONAL:
1046
+};
1255
+ raise ValueError('nargs must be %r to supply const' % OPTIONAL)
1047
+
1256
+ super(_AppendAction, self).__init__(
1048
+/* Interconnect descriptor parameters offsets in bytes*/
1257
+ option_strings=option_strings,
1049
+enum interconnect_desc_param {
1258
+ dest=dest,
1050
+ UFS_INTERCONNECT_DESC_PARAM_LEN = 0x0,
1259
+ nargs=nargs,
1051
+ UFS_INTERCONNECT_DESC_PARAM_TYPE = 0x1,
1260
+ const=const,
1052
+ UFS_INTERCONNECT_DESC_PARAM_UNIPRO_VER = 0x2,
1261
+ default=default,
1053
+ UFS_INTERCONNECT_DESC_PARAM_MPHY_VER = 0x4,
1262
+ type=type,
1054
+};
1263
+ choices=choices,
1055
+
1264
+ required=required,
1056
+/* Geometry descriptor parameters offsets in bytes*/
1265
+ help=help,
1057
+enum geometry_desc_param {
1266
+ metavar=metavar)
1058
+ UFS_GEOMETRY_DESC_PARAM_LEN = 0x0,
1267
+
1059
+ UFS_GEOMETRY_DESC_PARAM_TYPE = 0x1,
1268
+ def __call__(self, parser, namespace, values, option_string=None):
1060
+ UFS_GEOMETRY_DESC_PARAM_DEV_CAP = 0x4,
1269
+ items = _copy.copy(_ensure_value(namespace, self.dest, []))
1061
+ UFS_GEOMETRY_DESC_PARAM_MAX_NUM_LUN = 0xC,
1270
+ items.append(values)
1062
+ UFS_GEOMETRY_DESC_PARAM_SEG_SIZE = 0xD,
1271
+ setattr(namespace, self.dest, items)
1063
+ UFS_GEOMETRY_DESC_PARAM_ALLOC_UNIT_SIZE = 0x11,
1272
+
1064
+ UFS_GEOMETRY_DESC_PARAM_MIN_BLK_SIZE = 0x12,
1273
+
1065
+ UFS_GEOMETRY_DESC_PARAM_OPT_RD_BLK_SIZE = 0x13,
1274
+class _AppendConstAction(Action):
1066
+ UFS_GEOMETRY_DESC_PARAM_OPT_WR_BLK_SIZE = 0x14,
1275
+
1067
+ UFS_GEOMETRY_DESC_PARAM_MAX_IN_BUF_SIZE = 0x15,
1276
+ def __init__(self,
1068
+ UFS_GEOMETRY_DESC_PARAM_MAX_OUT_BUF_SIZE = 0x16,
1277
+ option_strings,
1069
+ UFS_GEOMETRY_DESC_PARAM_RPMB_RW_SIZE = 0x17,
1278
+ dest,
1070
+ UFS_GEOMETRY_DESC_PARAM_DYN_CAP_RSRC_PLC = 0x18,
1279
+ const,
1071
+ UFS_GEOMETRY_DESC_PARAM_DATA_ORDER = 0x19,
1280
+ default=None,
1072
+ UFS_GEOMETRY_DESC_PARAM_MAX_NUM_CTX = 0x1A,
1281
+ required=False,
1073
+ UFS_GEOMETRY_DESC_PARAM_TAG_UNIT_SIZE = 0x1B,
1282
+ help=None,
1074
+ UFS_GEOMETRY_DESC_PARAM_TAG_RSRC_SIZE = 0x1C,
1283
+ metavar=None):
1075
+ UFS_GEOMETRY_DESC_PARAM_SEC_RM_TYPES = 0x1D,
1284
+ super(_AppendConstAction, self).__init__(
1076
+ UFS_GEOMETRY_DESC_PARAM_MEM_TYPES = 0x1E,
1285
+ option_strings=option_strings,
1077
+ UFS_GEOMETRY_DESC_PARAM_SCM_MAX_NUM_UNITS = 0x20,
1286
+ dest=dest,
1078
+ UFS_GEOMETRY_DESC_PARAM_SCM_CAP_ADJ_FCTR = 0x24,
1287
+ nargs=0,
1079
+ UFS_GEOMETRY_DESC_PARAM_NPM_MAX_NUM_UNITS = 0x26,
1288
+ const=const,
1080
+ UFS_GEOMETRY_DESC_PARAM_NPM_CAP_ADJ_FCTR = 0x2A,
1289
+ default=default,
1081
+ UFS_GEOMETRY_DESC_PARAM_ENM1_MAX_NUM_UNITS = 0x2C,
1290
+ required=required,
1082
+ UFS_GEOMETRY_DESC_PARAM_ENM1_CAP_ADJ_FCTR = 0x30,
1291
+ help=help,
1083
+ UFS_GEOMETRY_DESC_PARAM_ENM2_MAX_NUM_UNITS = 0x32,
1292
+ metavar=metavar)
1084
+ UFS_GEOMETRY_DESC_PARAM_ENM2_CAP_ADJ_FCTR = 0x36,
1293
+
1085
+ UFS_GEOMETRY_DESC_PARAM_ENM3_MAX_NUM_UNITS = 0x38,
1294
+ def __call__(self, parser, namespace, values, option_string=None):
1086
+ UFS_GEOMETRY_DESC_PARAM_ENM3_CAP_ADJ_FCTR = 0x3C,
1295
+ items = _copy.copy(_ensure_value(namespace, self.dest, []))
1087
+ UFS_GEOMETRY_DESC_PARAM_ENM4_MAX_NUM_UNITS = 0x3E,
1296
+ items.append(self.const)
1088
+ UFS_GEOMETRY_DESC_PARAM_ENM4_CAP_ADJ_FCTR = 0x42,
1297
+ setattr(namespace, self.dest, items)
1089
+ UFS_GEOMETRY_DESC_PARAM_OPT_LOG_BLK_SIZE = 0x44,
1298
+
1090
+ UFS_GEOMETRY_DESC_PARAM_HPB_REGION_SIZE = 0x48,
1299
+
1091
+ UFS_GEOMETRY_DESC_PARAM_HPB_NUMBER_LU = 0x49,
1300
+class _CountAction(Action):
1092
+ UFS_GEOMETRY_DESC_PARAM_HPB_SUBREGION_SIZE = 0x4A,
1301
+
1093
+ UFS_GEOMETRY_DESC_PARAM_HPB_MAX_ACTIVE_REGS = 0x4B,
1302
+ def __init__(self,
1094
+ UFS_GEOMETRY_DESC_PARAM_WB_MAX_ALLOC_UNITS = 0x4F,
1303
+ option_strings,
1095
+ UFS_GEOMETRY_DESC_PARAM_WB_MAX_WB_LUNS = 0x53,
1304
+ dest,
1096
+ UFS_GEOMETRY_DESC_PARAM_WB_BUFF_CAP_ADJ = 0x54,
1305
+ default=None,
1097
+ UFS_GEOMETRY_DESC_PARAM_WB_SUP_RED_TYPE = 0x55,
1306
+ required=False,
1098
+ UFS_GEOMETRY_DESC_PARAM_WB_SUP_WB_TYPE = 0x56,
1307
+ help=None):
1099
+};
1308
+ super(_CountAction, self).__init__(
1100
+
1309
+ option_strings=option_strings,
1101
+/* Health descriptor parameters offsets in bytes*/
1310
+ dest=dest,
1102
+enum health_desc_param {
1311
+ nargs=0,
1103
+ UFS_HEALTH_DESC_PARAM_LEN = 0x0,
1312
+ default=default,
1104
+ UFS_HEALTH_DESC_PARAM_TYPE = 0x1,
1313
+ required=required,
1105
+ UFS_HEALTH_DESC_PARAM_EOL_INFO = 0x2,
1314
+ help=help)
1106
+ UFS_HEALTH_DESC_PARAM_LIFE_TIME_EST_A = 0x3,
1315
+
1107
+ UFS_HEALTH_DESC_PARAM_LIFE_TIME_EST_B = 0x4,
1316
+ def __call__(self, parser, namespace, values, option_string=None):
1108
+};
1317
+ new_count = _ensure_value(namespace, self.dest, 0) + 1
1109
+
1318
+ setattr(namespace, self.dest, new_count)
1110
+/* WriteBooster buffer mode */
1319
+
1111
+enum {
1320
+
1112
+ UFS_WB_BUF_MODE_LU_DEDICATED = 0x0,
1321
+class _HelpAction(Action):
1113
+ UFS_WB_BUF_MODE_SHARED = 0x1,
1322
+
1114
+};
1323
+ def __init__(self,
1115
+
1324
+ option_strings,
1116
+/*
1325
+ dest=SUPPRESS,
1117
+ * Logical Unit Write Protect
1326
+ default=SUPPRESS,
1118
+ * 00h: LU not write protected
1327
+ help=None):
1119
+ * 01h: LU write protected when fPowerOnWPEn =1
1328
+ super(_HelpAction, self).__init__(
1120
+ * 02h: LU permanently write protected when fPermanentWPEn =1
1329
+ option_strings=option_strings,
1121
+ */
1330
+ dest=dest,
1122
+enum ufs_lu_wp_type {
1331
+ default=default,
1123
+ UFS_LU_NO_WP = 0x00,
1332
+ nargs=0,
1124
+ UFS_LU_POWER_ON_WP = 0x01,
1333
+ help=help)
1125
+ UFS_LU_PERM_WP = 0x02,
1334
+
1126
+};
1335
+ def __call__(self, parser, namespace, values, option_string=None):
1127
+
1336
+ parser.print_help()
1128
+/* UTP QUERY Transaction Specific Fields OpCode */
1337
+ parser.exit()
1129
+enum query_opcode {
1338
+
1130
+ UFS_UPIU_QUERY_OPCODE_NOP = 0x0,
1339
+
1131
+ UFS_UPIU_QUERY_OPCODE_READ_DESC = 0x1,
1340
+class _VersionAction(Action):
1132
+ UFS_UPIU_QUERY_OPCODE_WRITE_DESC = 0x2,
1341
+
1133
+ UFS_UPIU_QUERY_OPCODE_READ_ATTR = 0x3,
1342
+ def __init__(self,
1134
+ UFS_UPIU_QUERY_OPCODE_WRITE_ATTR = 0x4,
1343
+ option_strings,
1135
+ UFS_UPIU_QUERY_OPCODE_READ_FLAG = 0x5,
1344
+ version=None,
1136
+ UFS_UPIU_QUERY_OPCODE_SET_FLAG = 0x6,
1345
+ dest=SUPPRESS,
1137
+ UFS_UPIU_QUERY_OPCODE_CLEAR_FLAG = 0x7,
1346
+ default=SUPPRESS,
1138
+ UFS_UPIU_QUERY_OPCODE_TOGGLE_FLAG = 0x8,
1347
+ help="show program's version number and exit"):
1139
+};
1348
+ super(_VersionAction, self).__init__(
1140
+
1349
+ option_strings=option_strings,
1141
+/* Query response result code */
1350
+ dest=dest,
1142
+typedef enum QueryRespCode {
1351
+ default=default,
1143
+ UFS_QUERY_RESULT_SUCCESS = 0x00,
1352
+ nargs=0,
1144
+ UFS_QUERY_RESULT_NOT_READABLE = 0xF6,
1353
+ help=help)
1145
+ UFS_QUERY_RESULT_NOT_WRITEABLE = 0xF7,
1354
+ self.version = version
1146
+ UFS_QUERY_RESULT_ALREADY_WRITTEN = 0xF8,
1355
+
1147
+ UFS_QUERY_RESULT_INVALID_LENGTH = 0xF9,
1356
+ def __call__(self, parser, namespace, values, option_string=None):
1148
+ UFS_QUERY_RESULT_INVALID_VALUE = 0xFA,
1357
+ version = self.version
1149
+ UFS_QUERY_RESULT_INVALID_SELECTOR = 0xFB,
1358
+ if version is None:
1150
+ UFS_QUERY_RESULT_INVALID_INDEX = 0xFC,
1359
+ version = parser.version
1151
+ UFS_QUERY_RESULT_INVALID_IDN = 0xFD,
1360
+ formatter = parser._get_formatter()
1152
+ UFS_QUERY_RESULT_INVALID_OPCODE = 0xFE,
1361
+ formatter.add_text(version)
1153
+ UFS_QUERY_RESULT_GENERAL_FAILURE = 0xFF,
1362
+ parser.exit(message=formatter.format_help())
1154
+} QueryRespCode;
1363
+
1155
+
1364
+
1156
+/* UTP Transfer Request Command Type (CT) */
1365
+class _SubParsersAction(Action):
1157
+enum {
1366
+
1158
+ UFS_UPIU_COMMAND_SET_TYPE_SCSI = 0x0,
1367
+ class _ChoicesPseudoAction(Action):
1159
+ UFS_UPIU_COMMAND_SET_TYPE_UFS = 0x1,
1368
+
1160
+ UFS_UPIU_COMMAND_SET_TYPE_QUERY = 0x2,
1369
+ def __init__(self, name, aliases, help):
1161
+};
1370
+ metavar = dest = name
1162
+
1371
+ if aliases:
1163
+/* Task management service response */
1372
+ metavar += ' (%s)' % ', '.join(aliases)
1164
+enum {
1373
+ sup = super(_SubParsersAction._ChoicesPseudoAction, self)
1165
+ UFS_UPIU_TASK_MANAGEMENT_FUNC_COMPL = 0x00,
1374
+ sup.__init__(option_strings=[], dest=dest, help=help,
1166
+ UFS_UPIU_TASK_MANAGEMENT_FUNC_NOT_SUPPORTED = 0x04,
1375
+ metavar=metavar)
1167
+ UFS_UPIU_TASK_MANAGEMENT_FUNC_SUCCEEDED = 0x08,
1376
+
1168
+ UFS_UPIU_TASK_MANAGEMENT_FUNC_FAILED = 0x05,
1377
+ def __init__(self,
1169
+ UFS_UPIU_INCORRECT_LOGICAL_UNIT_NO = 0x09,
1378
+ option_strings,
1170
+};
1379
+ prog,
1171
+
1380
+ parser_class,
1172
+/* UFS device power modes */
1381
+ dest=SUPPRESS,
1173
+enum ufs_dev_pwr_mode {
1382
+ help=None,
1174
+ UFS_ACTIVE_PWR_MODE = 1,
1383
+ metavar=None):
1175
+ UFS_SLEEP_PWR_MODE = 2,
1384
+
1176
+ UFS_POWERDOWN_PWR_MODE = 3,
1385
+ self._prog_prefix = prog
1177
+ UFS_DEEPSLEEP_PWR_MODE = 4,
1386
+ self._parser_class = parser_class
1178
+};
1387
+ self._name_parser_map = {}
1179
+
1388
+ self._choices_actions = []
1180
+/*
1389
+
1181
+ * struct UtpCmdRsp - Response UPIU structure
1390
+ super(_SubParsersAction, self).__init__(
1182
+ * @residual_transfer_count: Residual transfer count DW-3
1391
+ option_strings=option_strings,
1183
+ * @reserved: Reserved double words DW-4 to DW-7
1392
+ dest=dest,
1184
+ * @sense_data_len: Sense data length DW-8 U16
1393
+ nargs=PARSER,
1185
+ * @sense_data: Sense data field DW-8 to DW-12
1394
+ choices=self._name_parser_map,
1186
+ */
1395
+ help=help,
1187
+typedef struct QEMU_PACKED UtpCmdRsp {
1396
+ metavar=metavar)
1188
+ uint32_t residual_transfer_count;
1397
+
1189
+ uint32_t reserved[4];
1398
+ def add_parser(self, name, **kwargs):
1190
+ uint16_t sense_data_len;
1399
+ # set prog from the existing prefix
1191
+ uint8_t sense_data[UFS_SENSE_SIZE];
1400
+ if kwargs.get('prog') is None:
1192
+} UtpCmdRsp;
1401
+ kwargs['prog'] = '%s %s' % (self._prog_prefix, name)
1193
+
1402
+
1194
+/*
1403
+ aliases = kwargs.pop('aliases', ())
1195
+ * struct UtpUpiuRsp - general upiu response structure
1404
+
1196
+ * @header: UPIU header structure DW-0 to DW-2
1405
+ # create a pseudo-action to hold the choice help
1197
+ * @sr: fields structure for scsi command DW-3 to DW-12
1406
+ if 'help' in kwargs:
1198
+ * @qr: fields structure for query request DW-3 to DW-7
1407
+ help = kwargs.pop('help')
1199
+ */
1408
+ choice_action = self._ChoicesPseudoAction(name, aliases, help)
1200
+typedef struct QEMU_PACKED UtpUpiuRsp {
1409
+ self._choices_actions.append(choice_action)
1201
+ UtpUpiuHeader header;
1410
+
1202
+ union {
1411
+ # create the parser and add it to the map
1203
+ UtpCmdRsp sr;
1412
+ parser = self._parser_class(**kwargs)
1204
+ UtpUpiuQuery qr;
1413
+ self._name_parser_map[name] = parser
1205
+ };
1414
+
1206
+} UtpUpiuRsp;
1415
+ # make parser available under aliases also
1207
+
1416
+ for alias in aliases:
1208
+static inline void _ufs_check_size(void)
1417
+ self._name_parser_map[alias] = parser
1209
+{
1418
+
1210
+ QEMU_BUILD_BUG_ON(sizeof(UfsReg) != 0x104);
1419
+ return parser
1211
+ QEMU_BUILD_BUG_ON(sizeof(DeviceDescriptor) != 89);
1420
+
1212
+ QEMU_BUILD_BUG_ON(sizeof(GeometryDescriptor) != 87);
1421
+ def _get_subactions(self):
1213
+ QEMU_BUILD_BUG_ON(sizeof(UnitDescriptor) != 45);
1422
+ return self._choices_actions
1214
+ QEMU_BUILD_BUG_ON(sizeof(RpmbUnitDescriptor) != 35);
1423
+
1215
+ QEMU_BUILD_BUG_ON(sizeof(PowerParametersDescriptor) != 98);
1424
+ def __call__(self, parser, namespace, values, option_string=None):
1216
+ QEMU_BUILD_BUG_ON(sizeof(InterconnectDescriptor) != 6);
1425
+ parser_name = values[0]
1217
+ QEMU_BUILD_BUG_ON(sizeof(StringDescriptor) != 254);
1426
+ arg_strings = values[1:]
1218
+ QEMU_BUILD_BUG_ON(sizeof(DeviceHealthDescriptor) != 45);
1427
+
1219
+ QEMU_BUILD_BUG_ON(sizeof(Flags) != 0x13);
1428
+ # set the parser name if requested
1220
+ QEMU_BUILD_BUG_ON(sizeof(UtpUpiuHeader) != 12);
1429
+ if self.dest is not SUPPRESS:
1221
+ QEMU_BUILD_BUG_ON(sizeof(UtpUpiuQuery) != 276);
1430
+ setattr(namespace, self.dest, parser_name)
1222
+ QEMU_BUILD_BUG_ON(sizeof(UtpUpiuCmd) != 20);
1431
+
1223
+ QEMU_BUILD_BUG_ON(sizeof(UtpUpiuReq) != 288);
1432
+ # select the parser
1224
+ QEMU_BUILD_BUG_ON(sizeof(UfshcdSgEntry) != 16);
1433
+ try:
1225
+ QEMU_BUILD_BUG_ON(sizeof(RequestDescHeader) != 16);
1434
+ parser = self._name_parser_map[parser_name]
1226
+ QEMU_BUILD_BUG_ON(sizeof(UtpTransferReqDesc) != 32);
1435
+ except KeyError:
1227
+ QEMU_BUILD_BUG_ON(sizeof(UtpTaskReqDesc) != 80);
1436
+ tup = parser_name, ', '.join(self._name_parser_map)
1228
+ QEMU_BUILD_BUG_ON(sizeof(UtpCmdRsp) != 40);
1437
+ msg = _('unknown parser %r (choices: %s)' % tup)
1229
+ QEMU_BUILD_BUG_ON(sizeof(UtpUpiuRsp) != 288);
1438
+ raise ArgumentError(self, msg)
1230
+}
1439
+
1231
+#endif
1440
+ # parse all the remaining options into the namespace
1232
diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
1441
+ # store any unrecognized options on the object, so that the top
1233
index XXXXXXX..XXXXXXX 100644
1442
+ # level parser can decide what to do with them
1234
--- a/include/hw/pci/pci.h
1443
+ namespace, arg_strings = parser.parse_known_args(arg_strings, namespace)
1235
+++ b/include/hw/pci/pci.h
1444
+ if arg_strings:
1236
@@ -XXX,XX +XXX,XX @@ extern bool pci_available;
1445
+ vars(namespace).setdefault(_UNRECOGNIZED_ARGS_ATTR, [])
1237
#define PCI_DEVICE_ID_REDHAT_NVME 0x0010
1446
+ getattr(namespace, _UNRECOGNIZED_ARGS_ATTR).extend(arg_strings)
1238
#define PCI_DEVICE_ID_REDHAT_PVPANIC 0x0011
1447
+
1239
#define PCI_DEVICE_ID_REDHAT_ACPI_ERST 0x0012
1448
+
1240
+#define PCI_DEVICE_ID_REDHAT_UFS 0x0013
1449
+# ==============
1241
#define PCI_DEVICE_ID_REDHAT_QXL 0x0100
1450
+# Type classes
1242
1451
+# ==============
1243
#define FMT_PCIBUS PRIx64
1452
+
1244
diff --git a/include/hw/pci/pci_ids.h b/include/hw/pci/pci_ids.h
1453
+class FileType(object):
1245
index XXXXXXX..XXXXXXX 100644
1454
+ """Factory for creating file object types
1246
--- a/include/hw/pci/pci_ids.h
1455
+
1247
+++ b/include/hw/pci/pci_ids.h
1456
+ Instances of FileType are typically passed as type= arguments to the
1248
@@ -XXX,XX +XXX,XX @@
1457
+ ArgumentParser add_argument() method.
1249
#define PCI_CLASS_STORAGE_SATA 0x0106
1458
+
1250
#define PCI_CLASS_STORAGE_SAS 0x0107
1459
+ Keyword Arguments:
1251
#define PCI_CLASS_STORAGE_EXPRESS 0x0108
1460
+ - mode -- A string indicating how the file is to be opened. Accepts the
1252
+#define PCI_CLASS_STORAGE_UFS 0x0109
1461
+ same values as the builtin open() function.
1253
#define PCI_CLASS_STORAGE_OTHER 0x0180
1462
+ - bufsize -- The file's desired buffer size. Accepts the same values as
1254
1463
+ the builtin open() function.
1255
#define PCI_BASE_CLASS_NETWORK 0x02
1464
+ """
1256
diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c
1465
+
1257
new file mode 100644
1466
+ def __init__(self, mode='r', bufsize=None):
1258
index XXXXXXX..XXXXXXX
1467
+ self._mode = mode
1259
--- /dev/null
1468
+ self._bufsize = bufsize
1260
+++ b/hw/ufs/ufs.c
1469
+
1261
@@ -XXX,XX +XXX,XX @@
1470
+ def __call__(self, string):
1262
+/*
1471
+ # the special argument "-" means sys.std{in,out}
1263
+ * QEMU Universal Flash Storage (UFS) Controller
1472
+ if string == '-':
1264
+ *
1473
+ if 'r' in self._mode:
1265
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd. All rights reserved.
1474
+ return _sys.stdin
1266
+ *
1475
+ elif 'w' in self._mode:
1267
+ * Written by Jeuk Kim <jeuk20.kim@samsung.com>
1476
+ return _sys.stdout
1268
+ *
1477
+ else:
1269
+ * SPDX-License-Identifier: GPL-2.0-or-later
1478
+ msg = _('argument "-" with mode %r' % self._mode)
1270
+ */
1479
+ raise ValueError(msg)
1271
+
1480
+
1272
+#include "qemu/osdep.h"
1481
+ try:
1273
+#include "qapi/error.h"
1482
+ # all other arguments are used as file names
1274
+#include "migration/vmstate.h"
1483
+ if self._bufsize:
1275
+#include "trace.h"
1484
+ return open(string, self._mode, self._bufsize)
1276
+#include "ufs.h"
1485
+ else:
1277
+
1486
+ return open(string, self._mode)
1278
+/* The QEMU-UFS device follows spec version 3.1 */
1487
+ except IOError:
1279
+#define UFS_SPEC_VER 0x00000310
1488
+ err = _sys.exc_info()[1]
1280
+#define UFS_MAX_NUTRS 32
1489
+ message = _("can't open '%s': %s")
1281
+#define UFS_MAX_NUTMRS 8
1490
+ raise ArgumentTypeError(message % (string, err))
1282
+
1491
+
1283
+static void ufs_irq_check(UfsHc *u)
1492
+ def __repr__(self):
1284
+{
1493
+ args = [self._mode, self._bufsize]
1285
+ PCIDevice *pci = PCI_DEVICE(u);
1494
+ args_str = ', '.join([repr(arg) for arg in args if arg is not None])
1286
+
1495
+ return '%s(%s)' % (type(self).__name__, args_str)
1287
+ if ((u->reg.is & UFS_INTR_MASK) & u->reg.ie) {
1496
+
1288
+ trace_ufs_irq_raise();
1497
+# ===========================
1289
+ pci_irq_assert(pci);
1498
+# Optional and Positional Parsing
1290
+ } else {
1499
+# ===========================
1291
+ trace_ufs_irq_lower();
1500
+
1292
+ pci_irq_deassert(pci);
1501
+class Namespace(_AttributeHolder):
1293
+ }
1502
+ """Simple object for storing attributes.
1294
+}
1503
+
1295
+
1504
+ Implements equality by attribute names and values, and provides a simple
1296
+static void ufs_process_uiccmd(UfsHc *u, uint32_t val)
1505
+ string representation.
1297
+{
1506
+ """
1298
+ trace_ufs_process_uiccmd(val, u->reg.ucmdarg1, u->reg.ucmdarg2,
1507
+
1299
+ u->reg.ucmdarg3);
1508
+ def __init__(self, **kwargs):
1300
+ /*
1509
+ for name in kwargs:
1301
+ * Only the essential uic commands for running drivers on Linux and Windows
1510
+ setattr(self, name, kwargs[name])
1302
+ * are implemented.
1511
+
1303
+ */
1512
+ __hash__ = None
1304
+ switch (val) {
1513
+
1305
+ case UFS_UIC_CMD_DME_LINK_STARTUP:
1514
+ def __eq__(self, other):
1306
+ u->reg.hcs = FIELD_DP32(u->reg.hcs, HCS, DP, 1);
1515
+ return vars(self) == vars(other)
1307
+ u->reg.hcs = FIELD_DP32(u->reg.hcs, HCS, UTRLRDY, 1);
1516
+
1308
+ u->reg.hcs = FIELD_DP32(u->reg.hcs, HCS, UTMRLRDY, 1);
1517
+ def __ne__(self, other):
1309
+ u->reg.ucmdarg2 = UFS_UIC_CMD_RESULT_SUCCESS;
1518
+ return not (self == other)
1310
+ break;
1519
+
1311
+ /* TODO: Revisit it when Power Management is implemented */
1520
+ def __contains__(self, key):
1312
+ case UFS_UIC_CMD_DME_HIBER_ENTER:
1521
+ return key in self.__dict__
1313
+ u->reg.is = FIELD_DP32(u->reg.is, IS, UHES, 1);
1522
+
1314
+ u->reg.hcs = FIELD_DP32(u->reg.hcs, HCS, UPMCRS, UFS_PWR_LOCAL);
1523
+
1315
+ u->reg.ucmdarg2 = UFS_UIC_CMD_RESULT_SUCCESS;
1524
+class _ActionsContainer(object):
1316
+ break;
1525
+
1317
+ case UFS_UIC_CMD_DME_HIBER_EXIT:
1526
+ def __init__(self,
1318
+ u->reg.is = FIELD_DP32(u->reg.is, IS, UHXS, 1);
1527
+ description,
1319
+ u->reg.hcs = FIELD_DP32(u->reg.hcs, HCS, UPMCRS, UFS_PWR_LOCAL);
1528
+ prefix_chars,
1320
+ u->reg.ucmdarg2 = UFS_UIC_CMD_RESULT_SUCCESS;
1529
+ argument_default,
1321
+ break;
1530
+ conflict_handler):
1322
+ default:
1531
+ super(_ActionsContainer, self).__init__()
1323
+ u->reg.ucmdarg2 = UFS_UIC_CMD_RESULT_FAILURE;
1532
+
1324
+ }
1533
+ self.description = description
1325
+
1534
+ self.argument_default = argument_default
1326
+ u->reg.is = FIELD_DP32(u->reg.is, IS, UCCS, 1);
1535
+ self.prefix_chars = prefix_chars
1327
+
1536
+ self.conflict_handler = conflict_handler
1328
+ ufs_irq_check(u);
1537
+
1329
+}
1538
+ # set up registries
1330
+
1539
+ self._registries = {}
1331
+static void ufs_write_reg(UfsHc *u, hwaddr offset, uint32_t data, unsigned size)
1540
+
1332
+{
1541
+ # register actions
1333
+ switch (offset) {
1542
+ self.register('action', None, _StoreAction)
1334
+ case A_IS:
1543
+ self.register('action', 'store', _StoreAction)
1335
+ u->reg.is &= ~data;
1544
+ self.register('action', 'store_const', _StoreConstAction)
1336
+ ufs_irq_check(u);
1545
+ self.register('action', 'store_true', _StoreTrueAction)
1337
+ break;
1546
+ self.register('action', 'store_false', _StoreFalseAction)
1338
+ case A_IE:
1547
+ self.register('action', 'append', _AppendAction)
1339
+ u->reg.ie = data;
1548
+ self.register('action', 'append_const', _AppendConstAction)
1340
+ ufs_irq_check(u);
1549
+ self.register('action', 'count', _CountAction)
1341
+ break;
1550
+ self.register('action', 'help', _HelpAction)
1342
+ case A_HCE:
1551
+ self.register('action', 'version', _VersionAction)
1343
+ if (!FIELD_EX32(u->reg.hce, HCE, HCE) && FIELD_EX32(data, HCE, HCE)) {
1552
+ self.register('action', 'parsers', _SubParsersAction)
1344
+ u->reg.hcs = FIELD_DP32(u->reg.hcs, HCS, UCRDY, 1);
1553
+
1345
+ u->reg.hce = FIELD_DP32(u->reg.hce, HCE, HCE, 1);
1554
+ # raise an exception if the conflict handler is invalid
1346
+ } else if (FIELD_EX32(u->reg.hce, HCE, HCE) &&
1555
+ self._get_handler()
1347
+ !FIELD_EX32(data, HCE, HCE)) {
1556
+
1348
+ u->reg.hcs = 0;
1557
+ # action storage
1349
+ u->reg.hce = FIELD_DP32(u->reg.hce, HCE, HCE, 0);
1558
+ self._actions = []
1350
+ }
1559
+ self._option_string_actions = {}
1351
+ break;
1560
+
1352
+ case A_UTRLBA:
1561
+ # groups
1353
+ u->reg.utrlba = data & R_UTRLBA_UTRLBA_MASK;
1562
+ self._action_groups = []
1354
+ break;
1563
+ self._mutually_exclusive_groups = []
1355
+ case A_UTRLBAU:
1564
+
1356
+ u->reg.utrlbau = data;
1565
+ # defaults storage
1357
+ break;
1566
+ self._defaults = {}
1358
+ case A_UTRLDBR:
1567
+
1359
+ /* Not yet supported */
1568
+ # determines whether an "option" looks like a negative number
1360
+ break;
1569
+ self._negative_number_matcher = _re.compile(r'^-\d+$|^-\d*\.\d+$')
1361
+ case A_UTRLRSR:
1570
+
1362
+ u->reg.utrlrsr = data;
1571
+ # whether or not there are any optionals that look like negative
1363
+ break;
1572
+ # numbers -- uses a list so it can be shared and edited
1364
+ case A_UTRLCNR:
1573
+ self._has_negative_number_optionals = []
1365
+ u->reg.utrlcnr &= ~data;
1574
+
1366
+ break;
1575
+ # ====================
1367
+ case A_UTMRLBA:
1576
+ # Registration methods
1368
+ u->reg.utmrlba = data & R_UTMRLBA_UTMRLBA_MASK;
1577
+ # ====================
1369
+ break;
1578
+ def register(self, registry_name, value, object):
1370
+ case A_UTMRLBAU:
1579
+ registry = self._registries.setdefault(registry_name, {})
1371
+ u->reg.utmrlbau = data;
1580
+ registry[value] = object
1372
+ break;
1581
+
1373
+ case A_UICCMD:
1582
+ def _registry_get(self, registry_name, value, default=None):
1374
+ ufs_process_uiccmd(u, data);
1583
+ return self._registries[registry_name].get(value, default)
1375
+ break;
1584
+
1376
+ case A_UCMDARG1:
1585
+ # ==================================
1377
+ u->reg.ucmdarg1 = data;
1586
+ # Namespace default accessor methods
1378
+ break;
1587
+ # ==================================
1379
+ case A_UCMDARG2:
1588
+ def set_defaults(self, **kwargs):
1380
+ u->reg.ucmdarg2 = data;
1589
+ self._defaults.update(kwargs)
1381
+ break;
1590
+
1382
+ case A_UCMDARG3:
1591
+ # if these defaults match any existing arguments, replace
1383
+ u->reg.ucmdarg3 = data;
1592
+ # the previous default on the object with the new one
1384
+ break;
1593
+ for action in self._actions:
1385
+ case A_UTRLCLR:
1594
+ if action.dest in kwargs:
1386
+ case A_UTMRLDBR:
1595
+ action.default = kwargs[action.dest]
1387
+ case A_UTMRLCLR:
1596
+
1388
+ case A_UTMRLRSR:
1597
+ def get_default(self, dest):
1389
+ trace_ufs_err_unsupport_register_offset(offset);
1598
+ for action in self._actions:
1390
+ break;
1599
+ if action.dest == dest and action.default is not None:
1391
+ default:
1600
+ return action.default
1392
+ trace_ufs_err_invalid_register_offset(offset);
1601
+ return self._defaults.get(dest, None)
1393
+ break;
1602
+
1394
+ }
1603
+
1395
+}
1604
+ # =======================
1396
+
1605
+ # Adding argument actions
1397
+static uint64_t ufs_mmio_read(void *opaque, hwaddr addr, unsigned size)
1606
+ # =======================
1398
+{
1607
+ def add_argument(self, *args, **kwargs):
1399
+ UfsHc *u = (UfsHc *)opaque;
1608
+ """
1400
+ uint8_t *ptr = (uint8_t *)&u->reg;
1609
+ add_argument(dest, ..., name=value, ...)
1401
+ uint64_t value;
1610
+ add_argument(option_string, option_string, ..., name=value, ...)
1402
+
1611
+ """
1403
+ if (addr > sizeof(u->reg) - size) {
1612
+
1404
+ trace_ufs_err_invalid_register_offset(addr);
1613
+ # if no positional args are supplied or only one is supplied and
1405
+ return 0;
1614
+ # it doesn't look like an option string, parse a positional
1406
+ }
1615
+ # argument
1407
+
1616
+ chars = self.prefix_chars
1408
+ value = *(uint32_t *)(ptr + addr);
1617
+ if not args or len(args) == 1 and args[0][0] not in chars:
1409
+ trace_ufs_mmio_read(addr, value, size);
1618
+ if args and 'dest' in kwargs:
1410
+ return value;
1619
+ raise ValueError('dest supplied twice for positional argument')
1411
+}
1620
+ kwargs = self._get_positional_kwargs(*args, **kwargs)
1412
+
1621
+
1413
+static void ufs_mmio_write(void *opaque, hwaddr addr, uint64_t data,
1622
+ # otherwise, we're adding an optional argument
1414
+ unsigned size)
1623
+ else:
1415
+{
1624
+ kwargs = self._get_optional_kwargs(*args, **kwargs)
1416
+ UfsHc *u = (UfsHc *)opaque;
1625
+
1417
+
1626
+ # if no default was supplied, use the parser-level default
1418
+ if (addr > sizeof(u->reg) - size) {
1627
+ if 'default' not in kwargs:
1419
+ trace_ufs_err_invalid_register_offset(addr);
1628
+ dest = kwargs['dest']
1420
+ return;
1629
+ if dest in self._defaults:
1421
+ }
1630
+ kwargs['default'] = self._defaults[dest]
1422
+
1631
+ elif self.argument_default is not None:
1423
+ trace_ufs_mmio_write(addr, data, size);
1632
+ kwargs['default'] = self.argument_default
1424
+ ufs_write_reg(u, addr, data, size);
1633
+
1425
+}
1634
+ # create the action object, and add it to the parser
1426
+
1635
+ action_class = self._pop_action_class(kwargs)
1427
+static const MemoryRegionOps ufs_mmio_ops = {
1636
+ if not _callable(action_class):
1428
+ .read = ufs_mmio_read,
1637
+ raise ValueError('unknown action "%s"' % action_class)
1429
+ .write = ufs_mmio_write,
1638
+ action = action_class(**kwargs)
1430
+ .endianness = DEVICE_LITTLE_ENDIAN,
1639
+
1431
+ .impl = {
1640
+ # raise an error if the action type is not callable
1432
+ .min_access_size = 4,
1641
+ type_func = self._registry_get('type', action.type, action.type)
1433
+ .max_access_size = 4,
1642
+ if not _callable(type_func):
1434
+ },
1643
+ raise ValueError('%r is not callable' % type_func)
1435
+};
1644
+
1436
+
1645
+ return self._add_action(action)
1437
+static bool ufs_check_constraints(UfsHc *u, Error **errp)
1646
+
1438
+{
1647
+ def add_argument_group(self, *args, **kwargs):
1439
+ if (u->params.nutrs > UFS_MAX_NUTRS) {
1648
+ group = _ArgumentGroup(self, *args, **kwargs)
1440
+ error_setg(errp, "nutrs must be less than or equal to %d",
1649
+ self._action_groups.append(group)
1441
+ UFS_MAX_NUTRS);
1650
+ return group
1442
+ return false;
1651
+
1443
+ }
1652
+ def add_mutually_exclusive_group(self, **kwargs):
1444
+
1653
+ group = _MutuallyExclusiveGroup(self, **kwargs)
1445
+ if (u->params.nutmrs > UFS_MAX_NUTMRS) {
1654
+ self._mutually_exclusive_groups.append(group)
1446
+ error_setg(errp, "nutmrs must be less than or equal to %d",
1655
+ return group
1447
+ UFS_MAX_NUTMRS);
1656
+
1448
+ return false;
1657
+ def _add_action(self, action):
1449
+ }
1658
+ # resolve any conflicts
1450
+
1659
+ self._check_conflict(action)
1451
+ return true;
1660
+
1452
+}
1661
+ # add to actions list
1453
+
1662
+ self._actions.append(action)
1454
+static void ufs_init_pci(UfsHc *u, PCIDevice *pci_dev)
1663
+ action.container = self
1455
+{
1664
+
1456
+ uint8_t *pci_conf = pci_dev->config;
1665
+ # index the action by any option strings it has
1457
+
1666
+ for option_string in action.option_strings:
1458
+ pci_conf[PCI_INTERRUPT_PIN] = 1;
1667
+ self._option_string_actions[option_string] = action
1459
+ pci_config_set_prog_interface(pci_conf, 0x1);
1668
+
1460
+
1669
+ # set the flag if any option strings look like negative numbers
1461
+ memory_region_init_io(&u->iomem, OBJECT(u), &ufs_mmio_ops, u, "ufs",
1670
+ for option_string in action.option_strings:
1462
+ u->reg_size);
1671
+ if self._negative_number_matcher.match(option_string):
1463
+ pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &u->iomem);
1672
+ if not self._has_negative_number_optionals:
1464
+ u->irq = pci_allocate_irq(pci_dev);
1673
+ self._has_negative_number_optionals.append(True)
1465
+}
1674
+
1466
+
1675
+ # return the created action
1467
+static void ufs_init_hc(UfsHc *u)
1676
+ return action
1468
+{
1677
+
1469
+ uint32_t cap = 0;
1678
+ def _remove_action(self, action):
1470
+
1679
+ self._actions.remove(action)
1471
+ u->reg_size = pow2ceil(sizeof(UfsReg));
1680
+
1472
+
1681
+ def _add_container_actions(self, container):
1473
+ memset(&u->reg, 0, sizeof(u->reg));
1682
+ # collect groups by titles
1474
+ cap = FIELD_DP32(cap, CAP, NUTRS, (u->params.nutrs - 1));
1683
+ title_group_map = {}
1475
+ cap = FIELD_DP32(cap, CAP, RTT, 2);
1684
+ for group in self._action_groups:
1476
+ cap = FIELD_DP32(cap, CAP, NUTMRS, (u->params.nutmrs - 1));
1685
+ if group.title in title_group_map:
1477
+ cap = FIELD_DP32(cap, CAP, AUTOH8, 0);
1686
+ msg = _('cannot merge actions - two groups are named %r')
1478
+ cap = FIELD_DP32(cap, CAP, 64AS, 1);
1687
+ raise ValueError(msg % (group.title))
1479
+ cap = FIELD_DP32(cap, CAP, OODDS, 0);
1688
+ title_group_map[group.title] = group
1480
+ cap = FIELD_DP32(cap, CAP, UICDMETMS, 0);
1689
+
1481
+ cap = FIELD_DP32(cap, CAP, CS, 0);
1690
+ # map each action to its group
1482
+ u->reg.cap = cap;
1691
+ group_map = {}
1483
+ u->reg.ver = UFS_SPEC_VER;
1692
+ for group in container._action_groups:
1484
+}
1693
+
1485
+
1694
+ # if a group with the title exists, use that, otherwise
1486
+static void ufs_realize(PCIDevice *pci_dev, Error **errp)
1695
+ # create a new group matching the container's group
1487
+{
1696
+ if group.title not in title_group_map:
1488
+ UfsHc *u = UFS(pci_dev);
1697
+ title_group_map[group.title] = self.add_argument_group(
1489
+
1698
+ title=group.title,
1490
+ if (!ufs_check_constraints(u, errp)) {
1699
+ description=group.description,
1491
+ return;
1700
+ conflict_handler=group.conflict_handler)
1492
+ }
1701
+
1493
+
1702
+ # map the actions to their new group
1494
+ ufs_init_hc(u);
1703
+ for action in group._group_actions:
1495
+ ufs_init_pci(u, pci_dev);
1704
+ group_map[action] = title_group_map[group.title]
1496
+}
1705
+
1497
+
1706
+ # add container's mutually exclusive groups
1498
+static Property ufs_props[] = {
1707
+ # NOTE: if add_mutually_exclusive_group ever gains title= and
1499
+ DEFINE_PROP_STRING("serial", UfsHc, params.serial),
1708
+ # description= then this code will need to be expanded as above
1500
+ DEFINE_PROP_UINT8("nutrs", UfsHc, params.nutrs, 32),
1709
+ for group in container._mutually_exclusive_groups:
1501
+ DEFINE_PROP_UINT8("nutmrs", UfsHc, params.nutmrs, 8),
1710
+ mutex_group = self.add_mutually_exclusive_group(
1502
+ DEFINE_PROP_END_OF_LIST(),
1711
+ required=group.required)
1503
+};
1712
+
1504
+
1713
+ # map the actions to their new mutex group
1505
+static const VMStateDescription ufs_vmstate = {
1714
+ for action in group._group_actions:
1506
+ .name = "ufs",
1715
+ group_map[action] = mutex_group
1507
+ .unmigratable = 1,
1716
+
1508
+};
1717
+ # add all actions to this container or their group
1509
+
1718
+ for action in container._actions:
1510
+static void ufs_class_init(ObjectClass *oc, void *data)
1719
+ group_map.get(action, self)._add_action(action)
1511
+{
1720
+
1512
+ DeviceClass *dc = DEVICE_CLASS(oc);
1721
+ def _get_positional_kwargs(self, dest, **kwargs):
1513
+ PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc);
1722
+ # make sure required is not specified
1514
+
1723
+ if 'required' in kwargs:
1515
+ pc->realize = ufs_realize;
1724
+ msg = _("'required' is an invalid argument for positionals")
1516
+ pc->vendor_id = PCI_VENDOR_ID_REDHAT;
1725
+ raise TypeError(msg)
1517
+ pc->device_id = PCI_DEVICE_ID_REDHAT_UFS;
1726
+
1518
+ pc->class_id = PCI_CLASS_STORAGE_UFS;
1727
+ # mark positional arguments as required if at least one is
1519
+
1728
+ # always required
1520
+ set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
1729
+ if kwargs.get('nargs') not in [OPTIONAL, ZERO_OR_MORE]:
1521
+ dc->desc = "Universal Flash Storage";
1730
+ kwargs['required'] = True
1522
+ device_class_set_props(dc, ufs_props);
1731
+ if kwargs.get('nargs') == ZERO_OR_MORE and 'default' not in kwargs:
1523
+ dc->vmsd = &ufs_vmstate;
1732
+ kwargs['required'] = True
1524
+}
1733
+
1525
+
1734
+ # return the keyword arguments with no option strings
1526
+static const TypeInfo ufs_info = {
1735
+ return dict(kwargs, dest=dest, option_strings=[])
1527
+ .name = TYPE_UFS,
1736
+
1528
+ .parent = TYPE_PCI_DEVICE,
1737
+ def _get_optional_kwargs(self, *args, **kwargs):
1529
+ .class_init = ufs_class_init,
1738
+ # determine short and long option strings
1530
+ .instance_size = sizeof(UfsHc),
1739
+ option_strings = []
1531
+ .interfaces = (InterfaceInfo[]){ { INTERFACE_PCIE_DEVICE }, {} },
1740
+ long_option_strings = []
1532
+};
1741
+ for option_string in args:
1533
+
1742
+ # error on strings that don't start with an appropriate prefix
1534
+static void ufs_register_types(void)
1743
+ if not option_string[0] in self.prefix_chars:
1535
+{
1744
+ msg = _('invalid option string %r: '
1536
+ type_register_static(&ufs_info);
1745
+ 'must start with a character %r')
1537
+}
1746
+ tup = option_string, self.prefix_chars
1538
+
1747
+ raise ValueError(msg % tup)
1539
+type_init(ufs_register_types)
1748
+
1540
diff --git a/hw/Kconfig b/hw/Kconfig
1749
+ # strings starting with two prefix characters are long options
1541
index XXXXXXX..XXXXXXX 100644
1750
+ option_strings.append(option_string)
1542
--- a/hw/Kconfig
1751
+ if option_string[0] in self.prefix_chars:
1543
+++ b/hw/Kconfig
1752
+ if len(option_string) > 1:
1544
@@ -XXX,XX +XXX,XX @@ source smbios/Kconfig
1753
+ if option_string[1] in self.prefix_chars:
1545
source ssi/Kconfig
1754
+ long_option_strings.append(option_string)
1546
source timer/Kconfig
1755
+
1547
source tpm/Kconfig
1756
+ # infer destination, '--foo-bar' -> 'foo_bar' and '-x' -> 'x'
1548
+source ufs/Kconfig
1757
+ dest = kwargs.pop('dest', None)
1549
source usb/Kconfig
1758
+ if dest is None:
1550
source virtio/Kconfig
1759
+ if long_option_strings:
1551
source vfio/Kconfig
1760
+ dest_option_string = long_option_strings[0]
1552
diff --git a/hw/meson.build b/hw/meson.build
1761
+ else:
1553
index XXXXXXX..XXXXXXX 100644
1762
+ dest_option_string = option_strings[0]
1554
--- a/hw/meson.build
1763
+ dest = dest_option_string.lstrip(self.prefix_chars)
1555
+++ b/hw/meson.build
1764
+ if not dest:
1556
@@ -XXX,XX +XXX,XX @@ subdir('smbios')
1765
+ msg = _('dest= is required for options like %r')
1557
subdir('ssi')
1766
+ raise ValueError(msg % option_string)
1558
subdir('timer')
1767
+ dest = dest.replace('-', '_')
1559
subdir('tpm')
1768
+
1560
+subdir('ufs')
1769
+ # return the updated keyword arguments
1561
subdir('usb')
1770
+ return dict(kwargs, dest=dest, option_strings=option_strings)
1562
subdir('vfio')
1771
+
1563
subdir('virtio')
1772
+ def _pop_action_class(self, kwargs, default=None):
1564
diff --git a/hw/ufs/Kconfig b/hw/ufs/Kconfig
1773
+ action = kwargs.pop('action', default)
1565
new file mode 100644
1774
+ return self._registry_get('action', action, action)
1566
index XXXXXXX..XXXXXXX
1775
+
1567
--- /dev/null
1776
+ def _get_handler(self):
1568
+++ b/hw/ufs/Kconfig
1777
+ # determine function from conflict handler string
1569
@@ -XXX,XX +XXX,XX @@
1778
+ handler_func_name = '_handle_conflict_%s' % self.conflict_handler
1570
+config UFS_PCI
1779
+ try:
1571
+ bool
1780
+ return getattr(self, handler_func_name)
1572
+ default y if PCI_DEVICES
1781
+ except AttributeError:
1573
+ depends on PCI
1782
+ msg = _('invalid conflict_resolution value: %r')
1574
diff --git a/hw/ufs/meson.build b/hw/ufs/meson.build
1783
+ raise ValueError(msg % self.conflict_handler)
1575
new file mode 100644
1784
+
1576
index XXXXXXX..XXXXXXX
1785
+ def _check_conflict(self, action):
1577
--- /dev/null
1786
+
1578
+++ b/hw/ufs/meson.build
1787
+ # find all options that conflict with this option
1579
@@ -0,0 +1 @@
1788
+ confl_optionals = []
1580
+system_ss.add(when: 'CONFIG_UFS_PCI', if_true: files('ufs.c'))
1789
+ for option_string in action.option_strings:
1581
diff --git a/hw/ufs/trace-events b/hw/ufs/trace-events
1790
+ if option_string in self._option_string_actions:
1582
new file mode 100644
1791
+ confl_optional = self._option_string_actions[option_string]
1583
index XXXXXXX..XXXXXXX
1792
+ confl_optionals.append((option_string, confl_optional))
1584
--- /dev/null
1793
+
1585
+++ b/hw/ufs/trace-events
1794
+ # resolve any conflicts
1586
@@ -XXX,XX +XXX,XX @@
1795
+ if confl_optionals:
1587
+# ufs.c
1796
+ conflict_handler = self._get_handler()
1588
+ufs_irq_raise(void) "INTx"
1797
+ conflict_handler(action, confl_optionals)
1589
+ufs_irq_lower(void) "INTx"
1798
+
1590
+ufs_mmio_read(uint64_t addr, uint64_t data, unsigned size) "addr 0x%"PRIx64" data 0x%"PRIx64" size %d"
1799
+ def _handle_conflict_error(self, action, conflicting_actions):
1591
+ufs_mmio_write(uint64_t addr, uint64_t data, unsigned size) "addr 0x%"PRIx64" data 0x%"PRIx64" size %d"
1800
+ message = _('conflicting option string(s): %s')
1592
+ufs_process_db(uint32_t slot) "UTRLDBR slot %"PRIu32""
1801
+ conflict_string = ', '.join([option_string
1593
+ufs_process_req(uint32_t slot) "UTRLDBR slot %"PRIu32""
1802
+ for option_string, action
1594
+ufs_complete_req(uint32_t slot) "UTRLDBR slot %"PRIu32""
1803
+ in conflicting_actions])
1595
+ufs_sendback_req(uint32_t slot) "UTRLDBR slot %"PRIu32""
1804
+ raise ArgumentError(action, message % conflict_string)
1596
+ufs_exec_nop_cmd(uint32_t slot) "UTRLDBR slot %"PRIu32""
1805
+
1597
+ufs_exec_scsi_cmd(uint32_t slot, uint8_t lun, uint8_t opcode) "slot %"PRIu32", lun 0x%"PRIx8", opcode 0x%"PRIx8""
1806
+ def _handle_conflict_resolve(self, action, conflicting_actions):
1598
+ufs_exec_query_cmd(uint32_t slot, uint8_t opcode) "slot %"PRIu32", opcode 0x%"PRIx8""
1807
+
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""
1808
+ # remove all conflicting options
1600
+
1809
+ for option_string, action in conflicting_actions:
1601
+# error condition
1810
+
1602
+ufs_err_dma_read_utrd(uint32_t slot, uint64_t addr) "failed to read utrd. UTRLDBR slot %"PRIu32", UTRD dma addr %"PRIu64""
1811
+ # remove the conflicting option
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""
1812
+ action.option_strings.remove(option_string)
1604
+ufs_err_dma_read_prdt(uint32_t slot, uint64_t addr) "failed to read prdt. UTRLDBR slot %"PRIu32", prdt addr %"PRIu64""
1813
+ self._option_string_actions.pop(option_string, None)
1605
+ufs_err_dma_write_utrd(uint32_t slot, uint64_t addr) "failed to write utrd. UTRLDBR slot %"PRIu32", UTRD dma addr %"PRIu64""
1814
+
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""
1815
+ # if the option now has no option string, remove it from the
1607
+ufs_err_utrl_slot_busy(uint32_t slot) "UTRLDBR slot %"PRIu32" is busy"
1816
+ # container holding it
1608
+ufs_err_unsupport_register_offset(uint32_t offset) "Register offset 0x%"PRIx32" is not yet supported"
1817
+ if not action.option_strings:
1609
+ufs_err_invalid_register_offset(uint32_t offset) "Register offset 0x%"PRIx32" is invalid"
1818
+ action.container._remove_action(action)
1610
+ufs_err_scsi_cmd_invalid_lun(uint8_t lun) "scsi command has invalid lun: 0x%"PRIx8""
1819
+
1611
+ufs_err_query_flag_not_readable(uint8_t idn) "query flag idn 0x%"PRIx8" is denied to read"
1820
+
1612
+ufs_err_query_flag_not_writable(uint8_t idn) "query flag idn 0x%"PRIx8" is denied to write"
1821
+class _ArgumentGroup(_ActionsContainer):
1613
+ufs_err_query_attr_not_readable(uint8_t idn) "query attribute idn 0x%"PRIx8" is denied to read"
1822
+
1614
+ufs_err_query_attr_not_writable(uint8_t idn) "query attribute idn 0x%"PRIx8" is denied to write"
1823
+ def __init__(self, container, title=None, description=None, **kwargs):
1615
+ufs_err_query_invalid_opcode(uint8_t opcode) "query request has invalid opcode. opcode: 0x%"PRIx8""
1824
+ # add any missing keyword arguments by checking the container
1616
+ufs_err_query_invalid_idn(uint8_t opcode, uint8_t idn) "query request has invalid idn. opcode: 0x%"PRIx8", idn 0x%"PRIx8""
1825
+ update = kwargs.setdefault
1617
+ufs_err_query_invalid_index(uint8_t opcode, uint8_t index) "query request has invalid index. opcode: 0x%"PRIx8", index 0x%"PRIx8""
1826
+ update('conflict_handler', container.conflict_handler)
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""
1827
+ update('prefix_chars', container.prefix_chars)
1828
+ update('argument_default', container.argument_default)
1829
+ super_init = super(_ArgumentGroup, self).__init__
1830
+ super_init(description=description, **kwargs)
1831
+
1832
+ # group attributes
1833
+ self.title = title
1834
+ self._group_actions = []
1835
+
1836
+ # share most attributes with the container
1837
+ self._registries = container._registries
1838
+ self._actions = container._actions
1839
+ self._option_string_actions = container._option_string_actions
1840
+ self._defaults = container._defaults
1841
+ self._has_negative_number_optionals = \
1842
+ container._has_negative_number_optionals
1843
+
1844
+ def _add_action(self, action):
1845
+ action = super(_ArgumentGroup, self)._add_action(action)
1846
+ self._group_actions.append(action)
1847
+ return action
1848
+
1849
+ def _remove_action(self, action):
1850
+ super(_ArgumentGroup, self)._remove_action(action)
1851
+ self._group_actions.remove(action)
1852
+
1853
+
1854
+class _MutuallyExclusiveGroup(_ArgumentGroup):
1855
+
1856
+ def __init__(self, container, required=False):
1857
+ super(_MutuallyExclusiveGroup, self).__init__(container)
1858
+ self.required = required
1859
+ self._container = container
1860
+
1861
+ def _add_action(self, action):
1862
+ if action.required:
1863
+ msg = _('mutually exclusive arguments must be optional')
1864
+ raise ValueError(msg)
1865
+ action = self._container._add_action(action)
1866
+ self._group_actions.append(action)
1867
+ return action
1868
+
1869
+ def _remove_action(self, action):
1870
+ self._container._remove_action(action)
1871
+ self._group_actions.remove(action)
1872
+
1873
+
1874
+class ArgumentParser(_AttributeHolder, _ActionsContainer):
1875
+ """Object for parsing command line strings into Python objects.
1876
+
1877
+ Keyword Arguments:
1878
+ - prog -- The name of the program (default: sys.argv[0])
1879
+ - usage -- A usage message (default: auto-generated from arguments)
1880
+ - description -- A description of what the program does
1881
+ - epilog -- Text following the argument descriptions
1882
+ - parents -- Parsers whose arguments should be copied into this one
1883
+ - formatter_class -- HelpFormatter class for printing help messages
1884
+ - prefix_chars -- Characters that prefix optional arguments
1885
+ - fromfile_prefix_chars -- Characters that prefix files containing
1886
+ additional arguments
1887
+ - argument_default -- The default value for all arguments
1888
+ - conflict_handler -- String indicating how to handle conflicts
1889
+ - add_help -- Add a -h/-help option
1890
+ """
1891
+
1892
+ def __init__(self,
1893
+ prog=None,
1894
+ usage=None,
1895
+ description=None,
1896
+ epilog=None,
1897
+ version=None,
1898
+ parents=[],
1899
+ formatter_class=HelpFormatter,
1900
+ prefix_chars='-',
1901
+ fromfile_prefix_chars=None,
1902
+ argument_default=None,
1903
+ conflict_handler='error',
1904
+ add_help=True):
1905
+
1906
+ if version is not None:
1907
+ import warnings
1908
+ warnings.warn(
1909
+ """The "version" argument to ArgumentParser is deprecated. """
1910
+ """Please use """
1911
+ """"add_argument(..., action='version', version="N", ...)" """
1912
+ """instead""", DeprecationWarning)
1913
+
1914
+ superinit = super(ArgumentParser, self).__init__
1915
+ superinit(description=description,
1916
+ prefix_chars=prefix_chars,
1917
+ argument_default=argument_default,
1918
+ conflict_handler=conflict_handler)
1919
+
1920
+ # default setting for prog
1921
+ if prog is None:
1922
+ prog = _os.path.basename(_sys.argv[0])
1923
+
1924
+ self.prog = prog
1925
+ self.usage = usage
1926
+ self.epilog = epilog
1927
+ self.version = version
1928
+ self.formatter_class = formatter_class
1929
+ self.fromfile_prefix_chars = fromfile_prefix_chars
1930
+ self.add_help = add_help
1931
+
1932
+ add_group = self.add_argument_group
1933
+ self._positionals = add_group(_('positional arguments'))
1934
+ self._optionals = add_group(_('optional arguments'))
1935
+ self._subparsers = None
1936
+
1937
+ # register types
1938
+ def identity(string):
1939
+ return string
1940
+ self.register('type', None, identity)
1941
+
1942
+ # add help and version arguments if necessary
1943
+ # (using explicit default to override global argument_default)
1944
+ if '-' in prefix_chars:
1945
+ default_prefix = '-'
1946
+ else:
1947
+ default_prefix = prefix_chars[0]
1948
+ if self.add_help:
1949
+ self.add_argument(
1950
+ default_prefix+'h', default_prefix*2+'help',
1951
+ action='help', default=SUPPRESS,
1952
+ help=_('show this help message and exit'))
1953
+ if self.version:
1954
+ self.add_argument(
1955
+ default_prefix+'v', default_prefix*2+'version',
1956
+ action='version', default=SUPPRESS,
1957
+ version=self.version,
1958
+ help=_("show program's version number and exit"))
1959
+
1960
+ # add parent arguments and defaults
1961
+ for parent in parents:
1962
+ self._add_container_actions(parent)
1963
+ try:
1964
+ defaults = parent._defaults
1965
+ except AttributeError:
1966
+ pass
1967
+ else:
1968
+ self._defaults.update(defaults)
1969
+
1970
+ # =======================
1971
+ # Pretty __repr__ methods
1972
+ # =======================
1973
+ def _get_kwargs(self):
1974
+ names = [
1975
+ 'prog',
1976
+ 'usage',
1977
+ 'description',
1978
+ 'version',
1979
+ 'formatter_class',
1980
+ 'conflict_handler',
1981
+ 'add_help',
1982
+ ]
1983
+ return [(name, getattr(self, name)) for name in names]
1984
+
1985
+ # ==================================
1986
+ # Optional/Positional adding methods
1987
+ # ==================================
1988
+ def add_subparsers(self, **kwargs):
1989
+ if self._subparsers is not None:
1990
+ self.error(_('cannot have multiple subparser arguments'))
1991
+
1992
+ # add the parser class to the arguments if it's not present
1993
+ kwargs.setdefault('parser_class', type(self))
1994
+
1995
+ if 'title' in kwargs or 'description' in kwargs:
1996
+ title = _(kwargs.pop('title', 'subcommands'))
1997
+ description = _(kwargs.pop('description', None))
1998
+ self._subparsers = self.add_argument_group(title, description)
1999
+ else:
2000
+ self._subparsers = self._positionals
2001
+
2002
+ # prog defaults to the usage message of this parser, skipping
2003
+ # optional arguments and with no "usage:" prefix
2004
+ if kwargs.get('prog') is None:
2005
+ formatter = self._get_formatter()
2006
+ positionals = self._get_positional_actions()
2007
+ groups = self._mutually_exclusive_groups
2008
+ formatter.add_usage(self.usage, positionals, groups, '')
2009
+ kwargs['prog'] = formatter.format_help().strip()
2010
+
2011
+ # create the parsers action and add it to the positionals list
2012
+ parsers_class = self._pop_action_class(kwargs, 'parsers')
2013
+ action = parsers_class(option_strings=[], **kwargs)
2014
+ self._subparsers._add_action(action)
2015
+
2016
+ # return the created parsers action
2017
+ return action
2018
+
2019
+ def _add_action(self, action):
2020
+ if action.option_strings:
2021
+ self._optionals._add_action(action)
2022
+ else:
2023
+ self._positionals._add_action(action)
2024
+ return action
2025
+
2026
+ def _get_optional_actions(self):
2027
+ return [action
2028
+ for action in self._actions
2029
+ if action.option_strings]
2030
+
2031
+ def _get_positional_actions(self):
2032
+ return [action
2033
+ for action in self._actions
2034
+ if not action.option_strings]
2035
+
2036
+ # =====================================
2037
+ # Command line argument parsing methods
2038
+ # =====================================
2039
+ def parse_args(self, args=None, namespace=None):
2040
+ args, argv = self.parse_known_args(args, namespace)
2041
+ if argv:
2042
+ msg = _('unrecognized arguments: %s')
2043
+ self.error(msg % ' '.join(argv))
2044
+ return args
2045
+
2046
+ def parse_known_args(self, args=None, namespace=None):
2047
+ # args default to the system args
2048
+ if args is None:
2049
+ args = _sys.argv[1:]
2050
+
2051
+ # default Namespace built from parser defaults
2052
+ if namespace is None:
2053
+ namespace = Namespace()
2054
+
2055
+ # add any action defaults that aren't present
2056
+ for action in self._actions:
2057
+ if action.dest is not SUPPRESS:
2058
+ if not hasattr(namespace, action.dest):
2059
+ if action.default is not SUPPRESS:
2060
+ setattr(namespace, action.dest, action.default)
2061
+
2062
+ # add any parser defaults that aren't present
2063
+ for dest in self._defaults:
2064
+ if not hasattr(namespace, dest):
2065
+ setattr(namespace, dest, self._defaults[dest])
2066
+
2067
+ # parse the arguments and exit if there are any errors
2068
+ try:
2069
+ namespace, args = self._parse_known_args(args, namespace)
2070
+ if hasattr(namespace, _UNRECOGNIZED_ARGS_ATTR):
2071
+ args.extend(getattr(namespace, _UNRECOGNIZED_ARGS_ATTR))
2072
+ delattr(namespace, _UNRECOGNIZED_ARGS_ATTR)
2073
+ return namespace, args
2074
+ except ArgumentError:
2075
+ err = _sys.exc_info()[1]
2076
+ self.error(str(err))
2077
+
2078
+ def _parse_known_args(self, arg_strings, namespace):
2079
+ # replace arg strings that are file references
2080
+ if self.fromfile_prefix_chars is not None:
2081
+ arg_strings = self._read_args_from_files(arg_strings)
2082
+
2083
+ # map all mutually exclusive arguments to the other arguments
2084
+ # they can't occur with
2085
+ action_conflicts = {}
2086
+ for mutex_group in self._mutually_exclusive_groups:
2087
+ group_actions = mutex_group._group_actions
2088
+ for i, mutex_action in enumerate(mutex_group._group_actions):
2089
+ conflicts = action_conflicts.setdefault(mutex_action, [])
2090
+ conflicts.extend(group_actions[:i])
2091
+ conflicts.extend(group_actions[i + 1:])
2092
+
2093
+ # find all option indices, and determine the arg_string_pattern
2094
+ # which has an 'O' if there is an option at an index,
2095
+ # an 'A' if there is an argument, or a '-' if there is a '--'
2096
+ option_string_indices = {}
2097
+ arg_string_pattern_parts = []
2098
+ arg_strings_iter = iter(arg_strings)
2099
+ for i, arg_string in enumerate(arg_strings_iter):
2100
+
2101
+ # all args after -- are non-options
2102
+ if arg_string == '--':
2103
+ arg_string_pattern_parts.append('-')
2104
+ for arg_string in arg_strings_iter:
2105
+ arg_string_pattern_parts.append('A')
2106
+
2107
+ # otherwise, add the arg to the arg strings
2108
+ # and note the index if it was an option
2109
+ else:
2110
+ option_tuple = self._parse_optional(arg_string)
2111
+ if option_tuple is None:
2112
+ pattern = 'A'
2113
+ else:
2114
+ option_string_indices[i] = option_tuple
2115
+ pattern = 'O'
2116
+ arg_string_pattern_parts.append(pattern)
2117
+
2118
+ # join the pieces together to form the pattern
2119
+ arg_strings_pattern = ''.join(arg_string_pattern_parts)
2120
+
2121
+ # converts arg strings to the appropriate and then takes the action
2122
+ seen_actions = set()
2123
+ seen_non_default_actions = set()
2124
+
2125
+ def take_action(action, argument_strings, option_string=None):
2126
+ seen_actions.add(action)
2127
+ argument_values = self._get_values(action, argument_strings)
2128
+
2129
+ # error if this argument is not allowed with other previously
2130
+ # seen arguments, assuming that actions that use the default
2131
+ # value don't really count as "present"
2132
+ if argument_values is not action.default:
2133
+ seen_non_default_actions.add(action)
2134
+ for conflict_action in action_conflicts.get(action, []):
2135
+ if conflict_action in seen_non_default_actions:
2136
+ msg = _('not allowed with argument %s')
2137
+ action_name = _get_action_name(conflict_action)
2138
+ raise ArgumentError(action, msg % action_name)
2139
+
2140
+ # take the action if we didn't receive a SUPPRESS value
2141
+ # (e.g. from a default)
2142
+ if argument_values is not SUPPRESS:
2143
+ action(self, namespace, argument_values, option_string)
2144
+
2145
+ # function to convert arg_strings into an optional action
2146
+ def consume_optional(start_index):
2147
+
2148
+ # get the optional identified at this index
2149
+ option_tuple = option_string_indices[start_index]
2150
+ action, option_string, explicit_arg = option_tuple
2151
+
2152
+ # identify additional optionals in the same arg string
2153
+ # (e.g. -xyz is the same as -x -y -z if no args are required)
2154
+ match_argument = self._match_argument
2155
+ action_tuples = []
2156
+ while True:
2157
+
2158
+ # if we found no optional action, skip it
2159
+ if action is None:
2160
+ extras.append(arg_strings[start_index])
2161
+ return start_index + 1
2162
+
2163
+ # if there is an explicit argument, try to match the
2164
+ # optional's string arguments to only this
2165
+ if explicit_arg is not None:
2166
+ arg_count = match_argument(action, 'A')
2167
+
2168
+ # if the action is a single-dash option and takes no
2169
+ # arguments, try to parse more single-dash options out
2170
+ # of the tail of the option string
2171
+ chars = self.prefix_chars
2172
+ if arg_count == 0 and option_string[1] not in chars:
2173
+ action_tuples.append((action, [], option_string))
2174
+ char = option_string[0]
2175
+ option_string = char + explicit_arg[0]
2176
+ new_explicit_arg = explicit_arg[1:] or None
2177
+ optionals_map = self._option_string_actions
2178
+ if option_string in optionals_map:
2179
+ action = optionals_map[option_string]
2180
+ explicit_arg = new_explicit_arg
2181
+ else:
2182
+ msg = _('ignored explicit argument %r')
2183
+ raise ArgumentError(action, msg % explicit_arg)
2184
+
2185
+ # if the action expect exactly one argument, we've
2186
+ # successfully matched the option; exit the loop
2187
+ elif arg_count == 1:
2188
+ stop = start_index + 1
2189
+ args = [explicit_arg]
2190
+ action_tuples.append((action, args, option_string))
2191
+ break
2192
+
2193
+ # error if a double-dash option did not use the
2194
+ # explicit argument
2195
+ else:
2196
+ msg = _('ignored explicit argument %r')
2197
+ raise ArgumentError(action, msg % explicit_arg)
2198
+
2199
+ # if there is no explicit argument, try to match the
2200
+ # optional's string arguments with the following strings
2201
+ # if successful, exit the loop
2202
+ else:
2203
+ start = start_index + 1
2204
+ selected_patterns = arg_strings_pattern[start:]
2205
+ arg_count = match_argument(action, selected_patterns)
2206
+ stop = start + arg_count
2207
+ args = arg_strings[start:stop]
2208
+ action_tuples.append((action, args, option_string))
2209
+ break
2210
+
2211
+ # add the Optional to the list and return the index at which
2212
+ # the Optional's string args stopped
2213
+ assert action_tuples
2214
+ for action, args, option_string in action_tuples:
2215
+ take_action(action, args, option_string)
2216
+ return stop
2217
+
2218
+ # the list of Positionals left to be parsed; this is modified
2219
+ # by consume_positionals()
2220
+ positionals = self._get_positional_actions()
2221
+
2222
+ # function to convert arg_strings into positional actions
2223
+ def consume_positionals(start_index):
2224
+ # match as many Positionals as possible
2225
+ match_partial = self._match_arguments_partial
2226
+ selected_pattern = arg_strings_pattern[start_index:]
2227
+ arg_counts = match_partial(positionals, selected_pattern)
2228
+
2229
+ # slice off the appropriate arg strings for each Positional
2230
+ # and add the Positional and its args to the list
2231
+ for action, arg_count in zip(positionals, arg_counts):
2232
+ args = arg_strings[start_index: start_index + arg_count]
2233
+ start_index += arg_count
2234
+ take_action(action, args)
2235
+
2236
+ # slice off the Positionals that we just parsed and return the
2237
+ # index at which the Positionals' string args stopped
2238
+ positionals[:] = positionals[len(arg_counts):]
2239
+ return start_index
2240
+
2241
+ # consume Positionals and Optionals alternately, until we have
2242
+ # passed the last option string
2243
+ extras = []
2244
+ start_index = 0
2245
+ if option_string_indices:
2246
+ max_option_string_index = max(option_string_indices)
2247
+ else:
2248
+ max_option_string_index = -1
2249
+ while start_index <= max_option_string_index:
2250
+
2251
+ # consume any Positionals preceding the next option
2252
+ next_option_string_index = min([
2253
+ index
2254
+ for index in option_string_indices
2255
+ if index >= start_index])
2256
+ if start_index != next_option_string_index:
2257
+ positionals_end_index = consume_positionals(start_index)
2258
+
2259
+ # only try to parse the next optional if we didn't consume
2260
+ # the option string during the positionals parsing
2261
+ if positionals_end_index > start_index:
2262
+ start_index = positionals_end_index
2263
+ continue
2264
+ else:
2265
+ start_index = positionals_end_index
2266
+
2267
+ # if we consumed all the positionals we could and we're not
2268
+ # at the index of an option string, there were extra arguments
2269
+ if start_index not in option_string_indices:
2270
+ strings = arg_strings[start_index:next_option_string_index]
2271
+ extras.extend(strings)
2272
+ start_index = next_option_string_index
2273
+
2274
+ # consume the next optional and any arguments for it
2275
+ start_index = consume_optional(start_index)
2276
+
2277
+ # consume any positionals following the last Optional
2278
+ stop_index = consume_positionals(start_index)
2279
+
2280
+ # if we didn't consume all the argument strings, there were extras
2281
+ extras.extend(arg_strings[stop_index:])
2282
+
2283
+ # if we didn't use all the Positional objects, there were too few
2284
+ # arg strings supplied.
2285
+ if positionals:
2286
+ self.error(_('too few arguments'))
2287
+
2288
+ # make sure all required actions were present, and convert defaults.
2289
+ for action in self._actions:
2290
+ if action not in seen_actions:
2291
+ if action.required:
2292
+ name = _get_action_name(action)
2293
+ self.error(_('argument %s is required') % name)
2294
+ else:
2295
+ # Convert action default now instead of doing it before
2296
+ # parsing arguments to avoid calling convert functions
2297
+ # twice (which may fail) if the argument was given, but
2298
+ # only if it was defined already in the namespace
2299
+ if (action.default is not None and
2300
+ isinstance(action.default, basestring) and
2301
+ hasattr(namespace, action.dest) and
2302
+ action.default is getattr(namespace, action.dest)):
2303
+ setattr(namespace, action.dest,
2304
+ self._get_value(action, action.default))
2305
+
2306
+ # make sure all required groups had one option present
2307
+ for group in self._mutually_exclusive_groups:
2308
+ if group.required:
2309
+ for action in group._group_actions:
2310
+ if action in seen_non_default_actions:
2311
+ break
2312
+
2313
+ # if no actions were used, report the error
2314
+ else:
2315
+ names = [_get_action_name(action)
2316
+ for action in group._group_actions
2317
+ if action.help is not SUPPRESS]
2318
+ msg = _('one of the arguments %s is required')
2319
+ self.error(msg % ' '.join(names))
2320
+
2321
+ # return the updated namespace and the extra arguments
2322
+ return namespace, extras
2323
+
2324
+ def _read_args_from_files(self, arg_strings):
2325
+ # expand arguments referencing files
2326
+ new_arg_strings = []
2327
+ for arg_string in arg_strings:
2328
+
2329
+ # for regular arguments, just add them back into the list
2330
+ if arg_string[0] not in self.fromfile_prefix_chars:
2331
+ new_arg_strings.append(arg_string)
2332
+
2333
+ # replace arguments referencing files with the file content
2334
+ else:
2335
+ try:
2336
+ args_file = open(arg_string[1:])
2337
+ try:
2338
+ arg_strings = []
2339
+ for arg_line in args_file.read().splitlines():
2340
+ for arg in self.convert_arg_line_to_args(arg_line):
2341
+ arg_strings.append(arg)
2342
+ arg_strings = self._read_args_from_files(arg_strings)
2343
+ new_arg_strings.extend(arg_strings)
2344
+ finally:
2345
+ args_file.close()
2346
+ except IOError:
2347
+ err = _sys.exc_info()[1]
2348
+ self.error(str(err))
2349
+
2350
+ # return the modified argument list
2351
+ return new_arg_strings
2352
+
2353
+ def convert_arg_line_to_args(self, arg_line):
2354
+ return [arg_line]
2355
+
2356
+ def _match_argument(self, action, arg_strings_pattern):
2357
+ # match the pattern for this action to the arg strings
2358
+ nargs_pattern = self._get_nargs_pattern(action)
2359
+ match = _re.match(nargs_pattern, arg_strings_pattern)
2360
+
2361
+ # raise an exception if we weren't able to find a match
2362
+ if match is None:
2363
+ nargs_errors = {
2364
+ None: _('expected one argument'),
2365
+ OPTIONAL: _('expected at most one argument'),
2366
+ ONE_OR_MORE: _('expected at least one argument'),
2367
+ }
2368
+ default = _('expected %s argument(s)') % action.nargs
2369
+ msg = nargs_errors.get(action.nargs, default)
2370
+ raise ArgumentError(action, msg)
2371
+
2372
+ # return the number of arguments matched
2373
+ return len(match.group(1))
2374
+
2375
+ def _match_arguments_partial(self, actions, arg_strings_pattern):
2376
+ # progressively shorten the actions list by slicing off the
2377
+ # final actions until we find a match
2378
+ result = []
2379
+ for i in range(len(actions), 0, -1):
2380
+ actions_slice = actions[:i]
2381
+ pattern = ''.join([self._get_nargs_pattern(action)
2382
+ for action in actions_slice])
2383
+ match = _re.match(pattern, arg_strings_pattern)
2384
+ if match is not None:
2385
+ result.extend([len(string) for string in match.groups()])
2386
+ break
2387
+
2388
+ # return the list of arg string counts
2389
+ return result
2390
+
2391
+ def _parse_optional(self, arg_string):
2392
+ # if it's an empty string, it was meant to be a positional
2393
+ if not arg_string:
2394
+ return None
2395
+
2396
+ # if it doesn't start with a prefix, it was meant to be positional
2397
+ if not arg_string[0] in self.prefix_chars:
2398
+ return None
2399
+
2400
+ # if the option string is present in the parser, return the action
2401
+ if arg_string in self._option_string_actions:
2402
+ action = self._option_string_actions[arg_string]
2403
+ return action, arg_string, None
2404
+
2405
+ # if it's just a single character, it was meant to be positional
2406
+ if len(arg_string) == 1:
2407
+ return None
2408
+
2409
+ # if the option string before the "=" is present, return the action
2410
+ if '=' in arg_string:
2411
+ option_string, explicit_arg = arg_string.split('=', 1)
2412
+ if option_string in self._option_string_actions:
2413
+ action = self._option_string_actions[option_string]
2414
+ return action, option_string, explicit_arg
2415
+
2416
+ # search through all possible prefixes of the option string
2417
+ # and all actions in the parser for possible interpretations
2418
+ option_tuples = self._get_option_tuples(arg_string)
2419
+
2420
+ # if multiple actions match, the option string was ambiguous
2421
+ if len(option_tuples) > 1:
2422
+ options = ', '.join([option_string
2423
+ for action, option_string, explicit_arg in option_tuples])
2424
+ tup = arg_string, options
2425
+ self.error(_('ambiguous option: %s could match %s') % tup)
2426
+
2427
+ # if exactly one action matched, this segmentation is good,
2428
+ # so return the parsed action
2429
+ elif len(option_tuples) == 1:
2430
+ option_tuple, = option_tuples
2431
+ return option_tuple
2432
+
2433
+ # if it was not found as an option, but it looks like a negative
2434
+ # number, it was meant to be positional
2435
+ # unless there are negative-number-like options
2436
+ if self._negative_number_matcher.match(arg_string):
2437
+ if not self._has_negative_number_optionals:
2438
+ return None
2439
+
2440
+ # if it contains a space, it was meant to be a positional
2441
+ if ' ' in arg_string:
2442
+ return None
2443
+
2444
+ # it was meant to be an optional but there is no such option
2445
+ # in this parser (though it might be a valid option in a subparser)
2446
+ return None, arg_string, None
2447
+
2448
+ def _get_option_tuples(self, option_string):
2449
+ result = []
2450
+
2451
+ # option strings starting with two prefix characters are only
2452
+ # split at the '='
2453
+ chars = self.prefix_chars
2454
+ if option_string[0] in chars and option_string[1] in chars:
2455
+ if '=' in option_string:
2456
+ option_prefix, explicit_arg = option_string.split('=', 1)
2457
+ else:
2458
+ option_prefix = option_string
2459
+ explicit_arg = None
2460
+ for option_string in self._option_string_actions:
2461
+ if option_string.startswith(option_prefix):
2462
+ action = self._option_string_actions[option_string]
2463
+ tup = action, option_string, explicit_arg
2464
+ result.append(tup)
2465
+
2466
+ # single character options can be concatenated with their arguments
2467
+ # but multiple character options always have to have their argument
2468
+ # separate
2469
+ elif option_string[0] in chars and option_string[1] not in chars:
2470
+ option_prefix = option_string
2471
+ explicit_arg = None
2472
+ short_option_prefix = option_string[:2]
2473
+ short_explicit_arg = option_string[2:]
2474
+
2475
+ for option_string in self._option_string_actions:
2476
+ if option_string == short_option_prefix:
2477
+ action = self._option_string_actions[option_string]
2478
+ tup = action, option_string, short_explicit_arg
2479
+ result.append(tup)
2480
+ elif option_string.startswith(option_prefix):
2481
+ action = self._option_string_actions[option_string]
2482
+ tup = action, option_string, explicit_arg
2483
+ result.append(tup)
2484
+
2485
+ # shouldn't ever get here
2486
+ else:
2487
+ self.error(_('unexpected option string: %s') % option_string)
2488
+
2489
+ # return the collected option tuples
2490
+ return result
2491
+
2492
+ def _get_nargs_pattern(self, action):
2493
+ # in all examples below, we have to allow for '--' args
2494
+ # which are represented as '-' in the pattern
2495
+ nargs = action.nargs
2496
+
2497
+ # the default (None) is assumed to be a single argument
2498
+ if nargs is None:
2499
+ nargs_pattern = '(-*A-*)'
2500
+
2501
+ # allow zero or one arguments
2502
+ elif nargs == OPTIONAL:
2503
+ nargs_pattern = '(-*A?-*)'
2504
+
2505
+ # allow zero or more arguments
2506
+ elif nargs == ZERO_OR_MORE:
2507
+ nargs_pattern = '(-*[A-]*)'
2508
+
2509
+ # allow one or more arguments
2510
+ elif nargs == ONE_OR_MORE:
2511
+ nargs_pattern = '(-*A[A-]*)'
2512
+
2513
+ # allow any number of options or arguments
2514
+ elif nargs == REMAINDER:
2515
+ nargs_pattern = '([-AO]*)'
2516
+
2517
+ # allow one argument followed by any number of options or arguments
2518
+ elif nargs == PARSER:
2519
+ nargs_pattern = '(-*A[-AO]*)'
2520
+
2521
+ # all others should be integers
2522
+ else:
2523
+ nargs_pattern = '(-*%s-*)' % '-*'.join('A' * nargs)
2524
+
2525
+ # if this is an optional action, -- is not allowed
2526
+ if action.option_strings:
2527
+ nargs_pattern = nargs_pattern.replace('-*', '')
2528
+ nargs_pattern = nargs_pattern.replace('-', '')
2529
+
2530
+ # return the pattern
2531
+ return nargs_pattern
2532
+
2533
+ # ========================
2534
+ # Value conversion methods
2535
+ # ========================
2536
+ def _get_values(self, action, arg_strings):
2537
+ # for everything but PARSER args, strip out '--'
2538
+ if action.nargs not in [PARSER, REMAINDER]:
2539
+ arg_strings = [s for s in arg_strings if s != '--']
2540
+
2541
+ # optional argument produces a default when not present
2542
+ if not arg_strings and action.nargs == OPTIONAL:
2543
+ if action.option_strings:
2544
+ value = action.const
2545
+ else:
2546
+ value = action.default
2547
+ if isinstance(value, basestring):
2548
+ value = self._get_value(action, value)
2549
+ self._check_value(action, value)
2550
+
2551
+ # when nargs='*' on a positional, if there were no command-line
2552
+ # args, use the default if it is anything other than None
2553
+ elif (not arg_strings and action.nargs == ZERO_OR_MORE and
2554
+ not action.option_strings):
2555
+ if action.default is not None:
2556
+ value = action.default
2557
+ else:
2558
+ value = arg_strings
2559
+ self._check_value(action, value)
2560
+
2561
+ # single argument or optional argument produces a single value
2562
+ elif len(arg_strings) == 1 and action.nargs in [None, OPTIONAL]:
2563
+ arg_string, = arg_strings
2564
+ value = self._get_value(action, arg_string)
2565
+ self._check_value(action, value)
2566
+
2567
+ # REMAINDER arguments convert all values, checking none
2568
+ elif action.nargs == REMAINDER:
2569
+ value = [self._get_value(action, v) for v in arg_strings]
2570
+
2571
+ # PARSER arguments convert all values, but check only the first
2572
+ elif action.nargs == PARSER:
2573
+ value = [self._get_value(action, v) for v in arg_strings]
2574
+ self._check_value(action, value[0])
2575
+
2576
+ # all other types of nargs produce a list
2577
+ else:
2578
+ value = [self._get_value(action, v) for v in arg_strings]
2579
+ for v in value:
2580
+ self._check_value(action, v)
2581
+
2582
+ # return the converted value
2583
+ return value
2584
+
2585
+ def _get_value(self, action, arg_string):
2586
+ type_func = self._registry_get('type', action.type, action.type)
2587
+ if not _callable(type_func):
2588
+ msg = _('%r is not callable')
2589
+ raise ArgumentError(action, msg % type_func)
2590
+
2591
+ # convert the value to the appropriate type
2592
+ try:
2593
+ result = type_func(arg_string)
2594
+
2595
+ # ArgumentTypeErrors indicate errors
2596
+ except ArgumentTypeError:
2597
+ name = getattr(action.type, '__name__', repr(action.type))
2598
+ msg = str(_sys.exc_info()[1])
2599
+ raise ArgumentError(action, msg)
2600
+
2601
+ # TypeErrors or ValueErrors also indicate errors
2602
+ except (TypeError, ValueError):
2603
+ name = getattr(action.type, '__name__', repr(action.type))
2604
+ msg = _('invalid %s value: %r')
2605
+ raise ArgumentError(action, msg % (name, arg_string))
2606
+
2607
+ # return the converted value
2608
+ return result
2609
+
2610
+ def _check_value(self, action, value):
2611
+ # converted value must be one of the choices (if specified)
2612
+ if action.choices is not None and value not in action.choices:
2613
+ tup = value, ', '.join(map(repr, action.choices))
2614
+ msg = _('invalid choice: %r (choose from %s)') % tup
2615
+ raise ArgumentError(action, msg)
2616
+
2617
+ # =======================
2618
+ # Help-formatting methods
2619
+ # =======================
2620
+ def format_usage(self):
2621
+ formatter = self._get_formatter()
2622
+ formatter.add_usage(self.usage, self._actions,
2623
+ self._mutually_exclusive_groups)
2624
+ return formatter.format_help()
2625
+
2626
+ def format_help(self):
2627
+ formatter = self._get_formatter()
2628
+
2629
+ # usage
2630
+ formatter.add_usage(self.usage, self._actions,
2631
+ self._mutually_exclusive_groups)
2632
+
2633
+ # description
2634
+ formatter.add_text(self.description)
2635
+
2636
+ # positionals, optionals and user-defined groups
2637
+ for action_group in self._action_groups:
2638
+ formatter.start_section(action_group.title)
2639
+ formatter.add_text(action_group.description)
2640
+ formatter.add_arguments(action_group._group_actions)
2641
+ formatter.end_section()
2642
+
2643
+ # epilog
2644
+ formatter.add_text(self.epilog)
2645
+
2646
+ # determine help from format above
2647
+ return formatter.format_help()
2648
+
2649
+ def format_version(self):
2650
+ import warnings
2651
+ warnings.warn(
2652
+ 'The format_version method is deprecated -- the "version" '
2653
+ 'argument to ArgumentParser is no longer supported.',
2654
+ DeprecationWarning)
2655
+ formatter = self._get_formatter()
2656
+ formatter.add_text(self.version)
2657
+ return formatter.format_help()
2658
+
2659
+ def _get_formatter(self):
2660
+ return self.formatter_class(prog=self.prog)
2661
+
2662
+ # =====================
2663
+ # Help-printing methods
2664
+ # =====================
2665
+ def print_usage(self, file=None):
2666
+ if file is None:
2667
+ file = _sys.stdout
2668
+ self._print_message(self.format_usage(), file)
2669
+
2670
+ def print_help(self, file=None):
2671
+ if file is None:
2672
+ file = _sys.stdout
2673
+ self._print_message(self.format_help(), file)
2674
+
2675
+ def print_version(self, file=None):
2676
+ import warnings
2677
+ warnings.warn(
2678
+ 'The print_version method is deprecated -- the "version" '
2679
+ 'argument to ArgumentParser is no longer supported.',
2680
+ DeprecationWarning)
2681
+ self._print_message(self.format_version(), file)
2682
+
2683
+ def _print_message(self, message, file=None):
2684
+ if message:
2685
+ if file is None:
2686
+ file = _sys.stderr
2687
+ file.write(message)
2688
+
2689
+ # ===============
2690
+ # Exiting methods
2691
+ # ===============
2692
+ def exit(self, status=0, message=None):
2693
+ if message:
2694
+ self._print_message(message, _sys.stderr)
2695
+ _sys.exit(status)
2696
+
2697
+ def error(self, message):
2698
+ """error(message: string)
2699
+
2700
+ Prints a usage message incorporating the message to stderr and
2701
+ exits.
2702
+
2703
+ If you override this in a subclass, it should not return -- it
2704
+ should either exit or raise an exception.
2705
+ """
2706
+ self.print_usage(_sys.stderr)
2707
+ self.exit(2, _('%s: error: %s\n') % (self.prog, message))
2708
--
1619
--
2709
2.13.5
1620
2.41.0
2710
2711
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Jeuk Kim <jeuk20.kim@samsung.com>
2
2
3
Both the throttling limits set with the throttling.iops-* and
3
This commit makes the UFS device support query
4
throttling.bps-* options and their QMP equivalents defined in the
4
and nop out transfer requests.
5
BlockIOThrottle struct are integer values.
6
5
7
Those limits are also reported in the BlockDeviceInfo struct and they
6
The next patch would be support for UFS logical
8
are integers there as well.
7
unit and scsi command transfer request.
9
8
10
Therefore there's no reason to store them internally as double and do
9
Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>
11
the conversion everytime we're setting or querying them, so this patch
10
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
12
uses uint64_t for those types. Let's also use an unsigned type because
11
Message-id: ff7a5f0fd26761936a553ffb89d3df0ba62844e9.1693980783.git.jeuk20.kim@gmail.com
13
we don't allow negative values anyway.
14
15
LeakyBucket.level and LeakyBucket.burst_level do however remain double
16
because their value changes depending on the fraction of time elapsed
17
since the previous I/O operation.
18
19
Signed-off-by: Alberto Garcia <berto@igalia.com>
20
Message-id: f29b840422767b5be2c41c2dfdbbbf6c5f8fedf8.1503580370.git.berto@igalia.com
21
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
22
---
13
---
23
include/qemu/throttle.h | 4 ++--
14
hw/ufs/ufs.h | 46 +++
24
tests/test-throttle.c | 3 ++-
15
hw/ufs/ufs.c | 988 +++++++++++++++++++++++++++++++++++++++++++-
25
util/throttle.c | 7 +++----
16
hw/ufs/trace-events | 1 +
26
3 files changed, 7 insertions(+), 7 deletions(-)
17
3 files changed, 1033 insertions(+), 2 deletions(-)
27
18
28
diff --git a/include/qemu/throttle.h b/include/qemu/throttle.h
19
diff --git a/hw/ufs/ufs.h b/hw/ufs/ufs.h
29
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
30
--- a/include/qemu/throttle.h
21
--- a/hw/ufs/ufs.h
31
+++ b/include/qemu/throttle.h
22
+++ b/hw/ufs/ufs.h
32
@@ -XXX,XX +XXX,XX @@ typedef enum {
23
@@ -XXX,XX +XXX,XX @@
33
*/
24
#define UFS_MAX_LUS 32
34
25
#define UFS_BLOCK_SIZE 4096
35
typedef struct LeakyBucket {
26
36
- double avg; /* average goal in units per second */
27
+typedef enum UfsRequestState {
37
- double max; /* leaky bucket max burst in units */
28
+ UFS_REQUEST_IDLE = 0,
38
+ uint64_t avg; /* average goal in units per second */
29
+ UFS_REQUEST_READY = 1,
39
+ uint64_t max; /* leaky bucket max burst in units */
30
+ UFS_REQUEST_RUNNING = 2,
40
double level; /* bucket level in units */
31
+ UFS_REQUEST_COMPLETE = 3,
41
double burst_level; /* bucket level in units (for computing bursts) */
32
+ UFS_REQUEST_ERROR = 4,
42
unsigned burst_length; /* max length of the burst period, in seconds */
33
+} UfsRequestState;
43
diff --git a/tests/test-throttle.c b/tests/test-throttle.c
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
44
index XXXXXXX..XXXXXXX 100644
89
index XXXXXXX..XXXXXXX 100644
45
--- a/tests/test-throttle.c
90
--- a/hw/ufs/ufs.c
46
+++ b/tests/test-throttle.c
91
+++ b/hw/ufs/ufs.c
47
@@ -XXX,XX +XXX,XX @@ static void test_enabled(void)
92
@@ -XXX,XX +XXX,XX @@
48
for (i = 0; i < BUCKETS_COUNT; i++) {
93
#include "ufs.h"
49
throttle_config_init(&cfg);
94
50
set_cfg_value(false, i, 150);
95
/* The QEMU-UFS device follows spec version 3.1 */
51
+ g_assert(throttle_is_valid(&cfg, NULL));
96
-#define UFS_SPEC_VER 0x00000310
52
g_assert(throttle_enabled(&cfg));
97
+#define UFS_SPEC_VER 0x0310
53
}
98
#define UFS_MAX_NUTRS 32
54
99
#define UFS_MAX_NUTMRS 8
55
for (i = 0; i < BUCKETS_COUNT; i++) {
100
56
throttle_config_init(&cfg);
101
+static MemTxResult ufs_addr_read(UfsHc *u, hwaddr addr, void *buf, int size)
57
set_cfg_value(false, i, -150);
102
+{
58
- g_assert(!throttle_enabled(&cfg));
103
+ hwaddr hi = addr + size - 1;
59
+ g_assert(!throttle_is_valid(&cfg, NULL));
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)
313
{
314
PCIDevice *pci = PCI_DEVICE(u);
315
@@ -XXX,XX +XXX,XX @@ static void ufs_irq_check(UfsHc *u)
60
}
316
}
61
}
317
}
62
318
63
diff --git a/util/throttle.c b/util/throttle.c
319
+static void ufs_process_db(UfsHc *u, uint32_t val)
320
+{
321
+ unsigned long doorbell;
322
+ uint32_t slot;
323
+ uint32_t nutrs = u->params.nutrs;
324
+ UfsRequest *req;
325
+
326
+ val &= ~u->reg.utrldbr;
327
+ if (!val) {
328
+ return;
329
+ }
330
+
331
+ doorbell = val;
332
+ slot = find_first_bit(&doorbell, nutrs);
333
+
334
+ while (slot < nutrs) {
335
+ req = &u->req_list[slot];
336
+ if (req->state == UFS_REQUEST_ERROR) {
337
+ trace_ufs_err_utrl_slot_error(req->slot);
338
+ return;
339
+ }
340
+
341
+ if (req->state != UFS_REQUEST_IDLE) {
342
+ trace_ufs_err_utrl_slot_busy(req->slot);
343
+ return;
344
+ }
345
+
346
+ trace_ufs_process_db(slot);
347
+ req->state = UFS_REQUEST_READY;
348
+ slot = find_next_bit(&doorbell, nutrs, slot + 1);
349
+ }
350
+
351
+ qemu_bh_schedule(u->doorbell_bh);
352
+}
353
+
354
static void ufs_process_uiccmd(UfsHc *u, uint32_t val)
355
{
356
trace_ufs_process_uiccmd(val, u->reg.ucmdarg1, u->reg.ucmdarg2,
357
@@ -XXX,XX +XXX,XX @@ static void ufs_write_reg(UfsHc *u, hwaddr offset, uint32_t data, unsigned size)
358
u->reg.utrlbau = data;
359
break;
360
case A_UTRLDBR:
361
- /* Not yet supported */
362
+ ufs_process_db(u, data);
363
+ u->reg.utrldbr |= data;
364
break;
365
case A_UTRLRSR:
366
u->reg.utrlrsr = data;
367
@@ -XXX,XX +XXX,XX @@ static const MemoryRegionOps ufs_mmio_ops = {
368
},
369
};
370
371
+static void ufs_build_upiu_header(UfsRequest *req, uint8_t trans_type,
372
+ uint8_t flags, uint8_t response,
373
+ uint8_t scsi_status,
374
+ uint16_t data_segment_length)
375
+{
376
+ memcpy(&req->rsp_upiu.header, &req->req_upiu.header, sizeof(UtpUpiuHeader));
377
+ req->rsp_upiu.header.trans_type = trans_type;
378
+ req->rsp_upiu.header.flags = flags;
379
+ req->rsp_upiu.header.response = response;
380
+ req->rsp_upiu.header.scsi_status = scsi_status;
381
+ req->rsp_upiu.header.data_segment_length = cpu_to_be16(data_segment_length);
382
+}
383
+
384
+static UfsReqResult ufs_exec_nop_cmd(UfsRequest *req)
385
+{
386
+ trace_ufs_exec_nop_cmd(req->slot);
387
+ ufs_build_upiu_header(req, UFS_UPIU_TRANSACTION_NOP_IN, 0, 0, 0, 0);
388
+ return UFS_REQUEST_SUCCESS;
389
+}
390
+
391
+/*
392
+ * This defines the permission of flags based on their IDN. There are some
393
+ * things that are declared read-only, which is inconsistent with the ufs spec,
394
+ * because we want to return an error for features that are not yet supported.
395
+ */
396
+static const int flag_permission[UFS_QUERY_FLAG_IDN_COUNT] = {
397
+ [UFS_QUERY_FLAG_IDN_FDEVICEINIT] = UFS_QUERY_FLAG_READ | UFS_QUERY_FLAG_SET,
398
+ /* Write protection is not supported */
399
+ [UFS_QUERY_FLAG_IDN_PERMANENT_WPE] = UFS_QUERY_FLAG_READ,
400
+ [UFS_QUERY_FLAG_IDN_PWR_ON_WPE] = UFS_QUERY_FLAG_READ,
401
+ [UFS_QUERY_FLAG_IDN_BKOPS_EN] = UFS_QUERY_FLAG_READ | UFS_QUERY_FLAG_SET |
402
+ UFS_QUERY_FLAG_CLEAR |
403
+ UFS_QUERY_FLAG_TOGGLE,
404
+ [UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE] =
405
+ UFS_QUERY_FLAG_READ | UFS_QUERY_FLAG_SET | UFS_QUERY_FLAG_CLEAR |
406
+ UFS_QUERY_FLAG_TOGGLE,
407
+ /* Purge Operation is not supported */
408
+ [UFS_QUERY_FLAG_IDN_PURGE_ENABLE] = UFS_QUERY_FLAG_NONE,
409
+ /* Refresh Operation is not supported */
410
+ [UFS_QUERY_FLAG_IDN_REFRESH_ENABLE] = UFS_QUERY_FLAG_NONE,
411
+ /* Physical Resource Removal is not supported */
412
+ [UFS_QUERY_FLAG_IDN_FPHYRESOURCEREMOVAL] = UFS_QUERY_FLAG_READ,
413
+ [UFS_QUERY_FLAG_IDN_BUSY_RTC] = UFS_QUERY_FLAG_READ,
414
+ [UFS_QUERY_FLAG_IDN_PERMANENTLY_DISABLE_FW_UPDATE] = UFS_QUERY_FLAG_READ,
415
+ /* Write Booster is not supported */
416
+ [UFS_QUERY_FLAG_IDN_WB_EN] = UFS_QUERY_FLAG_READ,
417
+ [UFS_QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN] = UFS_QUERY_FLAG_READ,
418
+ [UFS_QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8] = UFS_QUERY_FLAG_READ,
419
+};
420
+
421
+static inline QueryRespCode ufs_flag_check_idn_valid(uint8_t idn, int op)
422
+{
423
+ if (idn >= UFS_QUERY_FLAG_IDN_COUNT) {
424
+ return UFS_QUERY_RESULT_INVALID_IDN;
425
+ }
426
+
427
+ if (!(flag_permission[idn] & op)) {
428
+ if (op == UFS_QUERY_FLAG_READ) {
429
+ trace_ufs_err_query_flag_not_readable(idn);
430
+ return UFS_QUERY_RESULT_NOT_READABLE;
431
+ }
432
+ trace_ufs_err_query_flag_not_writable(idn);
433
+ return UFS_QUERY_RESULT_NOT_WRITEABLE;
434
+ }
435
+
436
+ return UFS_QUERY_RESULT_SUCCESS;
437
+}
438
+
439
+static const int attr_permission[UFS_QUERY_ATTR_IDN_COUNT] = {
440
+ /* booting is not supported */
441
+ [UFS_QUERY_ATTR_IDN_BOOT_LU_EN] = UFS_QUERY_ATTR_READ,
442
+ [UFS_QUERY_ATTR_IDN_POWER_MODE] = UFS_QUERY_ATTR_READ,
443
+ [UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL] =
444
+ UFS_QUERY_ATTR_READ | UFS_QUERY_ATTR_WRITE,
445
+ [UFS_QUERY_ATTR_IDN_OOO_DATA_EN] = UFS_QUERY_ATTR_READ,
446
+ [UFS_QUERY_ATTR_IDN_BKOPS_STATUS] = UFS_QUERY_ATTR_READ,
447
+ [UFS_QUERY_ATTR_IDN_PURGE_STATUS] = UFS_QUERY_ATTR_READ,
448
+ [UFS_QUERY_ATTR_IDN_MAX_DATA_IN] =
449
+ UFS_QUERY_ATTR_READ | UFS_QUERY_ATTR_WRITE,
450
+ [UFS_QUERY_ATTR_IDN_MAX_DATA_OUT] =
451
+ UFS_QUERY_ATTR_READ | UFS_QUERY_ATTR_WRITE,
452
+ [UFS_QUERY_ATTR_IDN_DYN_CAP_NEEDED] = UFS_QUERY_ATTR_READ,
453
+ [UFS_QUERY_ATTR_IDN_REF_CLK_FREQ] =
454
+ UFS_QUERY_ATTR_READ | UFS_QUERY_ATTR_WRITE,
455
+ [UFS_QUERY_ATTR_IDN_CONF_DESC_LOCK] = UFS_QUERY_ATTR_READ,
456
+ [UFS_QUERY_ATTR_IDN_MAX_NUM_OF_RTT] =
457
+ UFS_QUERY_ATTR_READ | UFS_QUERY_ATTR_WRITE,
458
+ [UFS_QUERY_ATTR_IDN_EE_CONTROL] =
459
+ UFS_QUERY_ATTR_READ | UFS_QUERY_ATTR_WRITE,
460
+ [UFS_QUERY_ATTR_IDN_EE_STATUS] = UFS_QUERY_ATTR_READ,
461
+ [UFS_QUERY_ATTR_IDN_SECONDS_PASSED] = UFS_QUERY_ATTR_WRITE,
462
+ [UFS_QUERY_ATTR_IDN_CNTX_CONF] = UFS_QUERY_ATTR_READ,
463
+ [UFS_QUERY_ATTR_IDN_FFU_STATUS] = UFS_QUERY_ATTR_READ,
464
+ [UFS_QUERY_ATTR_IDN_PSA_STATE] = UFS_QUERY_ATTR_READ | UFS_QUERY_ATTR_WRITE,
465
+ [UFS_QUERY_ATTR_IDN_PSA_DATA_SIZE] =
466
+ UFS_QUERY_ATTR_READ | UFS_QUERY_ATTR_WRITE,
467
+ [UFS_QUERY_ATTR_IDN_REF_CLK_GATING_WAIT_TIME] = UFS_QUERY_ATTR_READ,
468
+ [UFS_QUERY_ATTR_IDN_CASE_ROUGH_TEMP] = UFS_QUERY_ATTR_READ,
469
+ [UFS_QUERY_ATTR_IDN_HIGH_TEMP_BOUND] = UFS_QUERY_ATTR_READ,
470
+ [UFS_QUERY_ATTR_IDN_LOW_TEMP_BOUND] = UFS_QUERY_ATTR_READ,
471
+ [UFS_QUERY_ATTR_IDN_THROTTLING_STATUS] = UFS_QUERY_ATTR_READ,
472
+ [UFS_QUERY_ATTR_IDN_WB_FLUSH_STATUS] = UFS_QUERY_ATTR_READ,
473
+ [UFS_QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE] = UFS_QUERY_ATTR_READ,
474
+ [UFS_QUERY_ATTR_IDN_WB_BUFF_LIFE_TIME_EST] = UFS_QUERY_ATTR_READ,
475
+ [UFS_QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE] = UFS_QUERY_ATTR_READ,
476
+ /* refresh operation is not supported */
477
+ [UFS_QUERY_ATTR_IDN_REFRESH_STATUS] = UFS_QUERY_ATTR_READ,
478
+ [UFS_QUERY_ATTR_IDN_REFRESH_FREQ] = UFS_QUERY_ATTR_READ,
479
+ [UFS_QUERY_ATTR_IDN_REFRESH_UNIT] = UFS_QUERY_ATTR_READ,
480
+};
481
+
482
+static inline QueryRespCode ufs_attr_check_idn_valid(uint8_t idn, int op)
483
+{
484
+ if (idn >= UFS_QUERY_ATTR_IDN_COUNT) {
485
+ return UFS_QUERY_RESULT_INVALID_IDN;
486
+ }
487
+
488
+ if (!(attr_permission[idn] & op)) {
489
+ if (op == UFS_QUERY_ATTR_READ) {
490
+ trace_ufs_err_query_attr_not_readable(idn);
491
+ return UFS_QUERY_RESULT_NOT_READABLE;
492
+ }
493
+ trace_ufs_err_query_attr_not_writable(idn);
494
+ return UFS_QUERY_RESULT_NOT_WRITEABLE;
495
+ }
496
+
497
+ return UFS_QUERY_RESULT_SUCCESS;
498
+}
499
+
500
+static QueryRespCode ufs_exec_query_flag(UfsRequest *req, int op)
501
+{
502
+ UfsHc *u = req->hc;
503
+ uint8_t idn = req->req_upiu.qr.idn;
504
+ uint32_t value;
505
+ QueryRespCode ret;
506
+
507
+ ret = ufs_flag_check_idn_valid(idn, op);
508
+ if (ret) {
509
+ return ret;
510
+ }
511
+
512
+ if (idn == UFS_QUERY_FLAG_IDN_FDEVICEINIT) {
513
+ value = 0;
514
+ } else if (op == UFS_QUERY_FLAG_READ) {
515
+ value = *(((uint8_t *)&u->flags) + idn);
516
+ } else if (op == UFS_QUERY_FLAG_SET) {
517
+ value = 1;
518
+ } else if (op == UFS_QUERY_FLAG_CLEAR) {
519
+ value = 0;
520
+ } else if (op == UFS_QUERY_FLAG_TOGGLE) {
521
+ value = *(((uint8_t *)&u->flags) + idn);
522
+ value = !value;
523
+ } else {
524
+ trace_ufs_err_query_invalid_opcode(op);
525
+ return UFS_QUERY_RESULT_INVALID_OPCODE;
526
+ }
527
+
528
+ *(((uint8_t *)&u->flags) + idn) = value;
529
+ req->rsp_upiu.qr.value = cpu_to_be32(value);
530
+ return UFS_QUERY_RESULT_SUCCESS;
531
+}
532
+
533
+static uint32_t ufs_read_attr_value(UfsHc *u, uint8_t idn)
534
+{
535
+ switch (idn) {
536
+ case UFS_QUERY_ATTR_IDN_BOOT_LU_EN:
537
+ return u->attributes.boot_lun_en;
538
+ case UFS_QUERY_ATTR_IDN_POWER_MODE:
539
+ return u->attributes.current_power_mode;
540
+ case UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL:
541
+ return u->attributes.active_icc_level;
542
+ case UFS_QUERY_ATTR_IDN_OOO_DATA_EN:
543
+ return u->attributes.out_of_order_data_en;
544
+ case UFS_QUERY_ATTR_IDN_BKOPS_STATUS:
545
+ return u->attributes.background_op_status;
546
+ case UFS_QUERY_ATTR_IDN_PURGE_STATUS:
547
+ return u->attributes.purge_status;
548
+ case UFS_QUERY_ATTR_IDN_MAX_DATA_IN:
549
+ return u->attributes.max_data_in_size;
550
+ case UFS_QUERY_ATTR_IDN_MAX_DATA_OUT:
551
+ return u->attributes.max_data_out_size;
552
+ case UFS_QUERY_ATTR_IDN_DYN_CAP_NEEDED:
553
+ return be32_to_cpu(u->attributes.dyn_cap_needed);
554
+ case UFS_QUERY_ATTR_IDN_REF_CLK_FREQ:
555
+ return u->attributes.ref_clk_freq;
556
+ case UFS_QUERY_ATTR_IDN_CONF_DESC_LOCK:
557
+ return u->attributes.config_descr_lock;
558
+ case UFS_QUERY_ATTR_IDN_MAX_NUM_OF_RTT:
559
+ return u->attributes.max_num_of_rtt;
560
+ case UFS_QUERY_ATTR_IDN_EE_CONTROL:
561
+ return be16_to_cpu(u->attributes.exception_event_control);
562
+ case UFS_QUERY_ATTR_IDN_EE_STATUS:
563
+ return be16_to_cpu(u->attributes.exception_event_status);
564
+ case UFS_QUERY_ATTR_IDN_SECONDS_PASSED:
565
+ return be32_to_cpu(u->attributes.seconds_passed);
566
+ case UFS_QUERY_ATTR_IDN_CNTX_CONF:
567
+ return be16_to_cpu(u->attributes.context_conf);
568
+ case UFS_QUERY_ATTR_IDN_FFU_STATUS:
569
+ return u->attributes.device_ffu_status;
570
+ case UFS_QUERY_ATTR_IDN_PSA_STATE:
571
+ return be32_to_cpu(u->attributes.psa_state);
572
+ case UFS_QUERY_ATTR_IDN_PSA_DATA_SIZE:
573
+ return be32_to_cpu(u->attributes.psa_data_size);
574
+ case UFS_QUERY_ATTR_IDN_REF_CLK_GATING_WAIT_TIME:
575
+ return u->attributes.ref_clk_gating_wait_time;
576
+ case UFS_QUERY_ATTR_IDN_CASE_ROUGH_TEMP:
577
+ return u->attributes.device_case_rough_temperaure;
578
+ case UFS_QUERY_ATTR_IDN_HIGH_TEMP_BOUND:
579
+ return u->attributes.device_too_high_temp_boundary;
580
+ case UFS_QUERY_ATTR_IDN_LOW_TEMP_BOUND:
581
+ return u->attributes.device_too_low_temp_boundary;
582
+ case UFS_QUERY_ATTR_IDN_THROTTLING_STATUS:
583
+ return u->attributes.throttling_status;
584
+ case UFS_QUERY_ATTR_IDN_WB_FLUSH_STATUS:
585
+ return u->attributes.wb_buffer_flush_status;
586
+ case UFS_QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE:
587
+ return u->attributes.available_wb_buffer_size;
588
+ case UFS_QUERY_ATTR_IDN_WB_BUFF_LIFE_TIME_EST:
589
+ return u->attributes.wb_buffer_life_time_est;
590
+ case UFS_QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE:
591
+ return be32_to_cpu(u->attributes.current_wb_buffer_size);
592
+ case UFS_QUERY_ATTR_IDN_REFRESH_STATUS:
593
+ return u->attributes.refresh_status;
594
+ case UFS_QUERY_ATTR_IDN_REFRESH_FREQ:
595
+ return u->attributes.refresh_freq;
596
+ case UFS_QUERY_ATTR_IDN_REFRESH_UNIT:
597
+ return u->attributes.refresh_unit;
598
+ }
599
+ return 0;
600
+}
601
+
602
+static void ufs_write_attr_value(UfsHc *u, uint8_t idn, uint32_t value)
603
+{
604
+ switch (idn) {
605
+ case UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL:
606
+ u->attributes.active_icc_level = value;
607
+ break;
608
+ case UFS_QUERY_ATTR_IDN_MAX_DATA_IN:
609
+ u->attributes.max_data_in_size = value;
610
+ break;
611
+ case UFS_QUERY_ATTR_IDN_MAX_DATA_OUT:
612
+ u->attributes.max_data_out_size = value;
613
+ break;
614
+ case UFS_QUERY_ATTR_IDN_REF_CLK_FREQ:
615
+ u->attributes.ref_clk_freq = value;
616
+ break;
617
+ case UFS_QUERY_ATTR_IDN_MAX_NUM_OF_RTT:
618
+ u->attributes.max_num_of_rtt = value;
619
+ break;
620
+ case UFS_QUERY_ATTR_IDN_EE_CONTROL:
621
+ u->attributes.exception_event_control = cpu_to_be16(value);
622
+ break;
623
+ case UFS_QUERY_ATTR_IDN_SECONDS_PASSED:
624
+ u->attributes.seconds_passed = cpu_to_be32(value);
625
+ break;
626
+ case UFS_QUERY_ATTR_IDN_PSA_STATE:
627
+ u->attributes.psa_state = value;
628
+ break;
629
+ case UFS_QUERY_ATTR_IDN_PSA_DATA_SIZE:
630
+ u->attributes.psa_data_size = cpu_to_be32(value);
631
+ break;
632
+ }
633
+}
634
+
635
+static QueryRespCode ufs_exec_query_attr(UfsRequest *req, int op)
636
+{
637
+ UfsHc *u = req->hc;
638
+ uint8_t idn = req->req_upiu.qr.idn;
639
+ uint32_t value;
640
+ QueryRespCode ret;
641
+
642
+ ret = ufs_attr_check_idn_valid(idn, op);
643
+ if (ret) {
644
+ return ret;
645
+ }
646
+
647
+ if (op == UFS_QUERY_ATTR_READ) {
648
+ value = ufs_read_attr_value(u, idn);
649
+ } else {
650
+ value = be32_to_cpu(req->req_upiu.qr.value);
651
+ ufs_write_attr_value(u, idn, value);
652
+ }
653
+
654
+ req->rsp_upiu.qr.value = cpu_to_be32(value);
655
+ return UFS_QUERY_RESULT_SUCCESS;
656
+}
657
+
658
+static const RpmbUnitDescriptor rpmb_unit_desc = {
659
+ .length = sizeof(RpmbUnitDescriptor),
660
+ .descriptor_idn = 2,
661
+ .unit_index = UFS_UPIU_RPMB_WLUN,
662
+ .lu_enable = 0,
663
+};
664
+
665
+static QueryRespCode ufs_read_unit_desc(UfsRequest *req)
666
+{
667
+ uint8_t lun = req->req_upiu.qr.index;
668
+
669
+ if (lun != UFS_UPIU_RPMB_WLUN && lun > UFS_MAX_LUS) {
670
+ trace_ufs_err_query_invalid_index(req->req_upiu.qr.opcode, lun);
671
+ return UFS_QUERY_RESULT_INVALID_INDEX;
672
+ }
673
+
674
+ if (lun == UFS_UPIU_RPMB_WLUN) {
675
+ memcpy(&req->rsp_upiu.qr.data, &rpmb_unit_desc, rpmb_unit_desc.length);
676
+ } else {
677
+ /* unit descriptor is not yet supported */
678
+ return UFS_QUERY_RESULT_INVALID_INDEX;
679
+ }
680
+
681
+ return UFS_QUERY_RESULT_SUCCESS;
682
+}
683
+
684
+static inline StringDescriptor manufacturer_str_desc(void)
685
+{
686
+ StringDescriptor desc = {
687
+ .length = 0x12,
688
+ .descriptor_idn = UFS_QUERY_DESC_IDN_STRING,
689
+ };
690
+ desc.UC[0] = cpu_to_be16('R');
691
+ desc.UC[1] = cpu_to_be16('E');
692
+ desc.UC[2] = cpu_to_be16('D');
693
+ desc.UC[3] = cpu_to_be16('H');
694
+ desc.UC[4] = cpu_to_be16('A');
695
+ desc.UC[5] = cpu_to_be16('T');
696
+ return desc;
697
+}
698
+
699
+static inline StringDescriptor product_name_str_desc(void)
700
+{
701
+ StringDescriptor desc = {
702
+ .length = 0x22,
703
+ .descriptor_idn = UFS_QUERY_DESC_IDN_STRING,
704
+ };
705
+ desc.UC[0] = cpu_to_be16('Q');
706
+ desc.UC[1] = cpu_to_be16('E');
707
+ desc.UC[2] = cpu_to_be16('M');
708
+ desc.UC[3] = cpu_to_be16('U');
709
+ desc.UC[4] = cpu_to_be16(' ');
710
+ desc.UC[5] = cpu_to_be16('U');
711
+ desc.UC[6] = cpu_to_be16('F');
712
+ desc.UC[7] = cpu_to_be16('S');
713
+ return desc;
714
+}
715
+
716
+static inline StringDescriptor product_rev_level_str_desc(void)
717
+{
718
+ StringDescriptor desc = {
719
+ .length = 0x0a,
720
+ .descriptor_idn = UFS_QUERY_DESC_IDN_STRING,
721
+ };
722
+ desc.UC[0] = cpu_to_be16('0');
723
+ desc.UC[1] = cpu_to_be16('0');
724
+ desc.UC[2] = cpu_to_be16('0');
725
+ desc.UC[3] = cpu_to_be16('1');
726
+ return desc;
727
+}
728
+
729
+static const StringDescriptor null_str_desc = {
730
+ .length = 0x02,
731
+ .descriptor_idn = UFS_QUERY_DESC_IDN_STRING,
732
+};
733
+
734
+static QueryRespCode ufs_read_string_desc(UfsRequest *req)
735
+{
736
+ UfsHc *u = req->hc;
737
+ uint8_t index = req->req_upiu.qr.index;
738
+ StringDescriptor desc;
739
+
740
+ if (index == u->device_desc.manufacturer_name) {
741
+ desc = manufacturer_str_desc();
742
+ memcpy(&req->rsp_upiu.qr.data, &desc, desc.length);
743
+ } else if (index == u->device_desc.product_name) {
744
+ desc = product_name_str_desc();
745
+ memcpy(&req->rsp_upiu.qr.data, &desc, desc.length);
746
+ } else if (index == u->device_desc.serial_number) {
747
+ memcpy(&req->rsp_upiu.qr.data, &null_str_desc, null_str_desc.length);
748
+ } else if (index == u->device_desc.oem_id) {
749
+ memcpy(&req->rsp_upiu.qr.data, &null_str_desc, null_str_desc.length);
750
+ } else if (index == u->device_desc.product_revision_level) {
751
+ desc = product_rev_level_str_desc();
752
+ memcpy(&req->rsp_upiu.qr.data, &desc, desc.length);
753
+ } else {
754
+ trace_ufs_err_query_invalid_index(req->req_upiu.qr.opcode, index);
755
+ return UFS_QUERY_RESULT_INVALID_INDEX;
756
+ }
757
+ return UFS_QUERY_RESULT_SUCCESS;
758
+}
759
+
760
+static inline InterconnectDescriptor interconnect_desc(void)
761
+{
762
+ InterconnectDescriptor desc = {
763
+ .length = sizeof(InterconnectDescriptor),
764
+ .descriptor_idn = UFS_QUERY_DESC_IDN_INTERCONNECT,
765
+ };
766
+ desc.bcd_unipro_version = cpu_to_be16(0x180);
767
+ desc.bcd_mphy_version = cpu_to_be16(0x410);
768
+ return desc;
769
+}
770
+
771
+static QueryRespCode ufs_read_desc(UfsRequest *req)
772
+{
773
+ UfsHc *u = req->hc;
774
+ QueryRespCode status;
775
+ uint8_t idn = req->req_upiu.qr.idn;
776
+ uint16_t length = be16_to_cpu(req->req_upiu.qr.length);
777
+ InterconnectDescriptor desc;
778
+
779
+ switch (idn) {
780
+ case UFS_QUERY_DESC_IDN_DEVICE:
781
+ memcpy(&req->rsp_upiu.qr.data, &u->device_desc, sizeof(u->device_desc));
782
+ status = UFS_QUERY_RESULT_SUCCESS;
783
+ break;
784
+ case UFS_QUERY_DESC_IDN_UNIT:
785
+ status = ufs_read_unit_desc(req);
786
+ break;
787
+ case UFS_QUERY_DESC_IDN_GEOMETRY:
788
+ memcpy(&req->rsp_upiu.qr.data, &u->geometry_desc,
789
+ sizeof(u->geometry_desc));
790
+ status = UFS_QUERY_RESULT_SUCCESS;
791
+ break;
792
+ case UFS_QUERY_DESC_IDN_INTERCONNECT: {
793
+ desc = interconnect_desc();
794
+ memcpy(&req->rsp_upiu.qr.data, &desc, sizeof(InterconnectDescriptor));
795
+ status = UFS_QUERY_RESULT_SUCCESS;
796
+ break;
797
+ }
798
+ case UFS_QUERY_DESC_IDN_STRING:
799
+ status = ufs_read_string_desc(req);
800
+ break;
801
+ case UFS_QUERY_DESC_IDN_POWER:
802
+ /* mocking of power descriptor is not supported */
803
+ memset(&req->rsp_upiu.qr.data, 0, sizeof(PowerParametersDescriptor));
804
+ req->rsp_upiu.qr.data[0] = sizeof(PowerParametersDescriptor);
805
+ req->rsp_upiu.qr.data[1] = UFS_QUERY_DESC_IDN_POWER;
806
+ status = UFS_QUERY_RESULT_SUCCESS;
807
+ break;
808
+ case UFS_QUERY_DESC_IDN_HEALTH:
809
+ /* mocking of health descriptor is not supported */
810
+ memset(&req->rsp_upiu.qr.data, 0, sizeof(DeviceHealthDescriptor));
811
+ req->rsp_upiu.qr.data[0] = sizeof(DeviceHealthDescriptor);
812
+ req->rsp_upiu.qr.data[1] = UFS_QUERY_DESC_IDN_HEALTH;
813
+ status = UFS_QUERY_RESULT_SUCCESS;
814
+ break;
815
+ default:
816
+ length = 0;
817
+ trace_ufs_err_query_invalid_idn(req->req_upiu.qr.opcode, idn);
818
+ status = UFS_QUERY_RESULT_INVALID_IDN;
819
+ }
820
+
821
+ if (length > req->rsp_upiu.qr.data[0]) {
822
+ length = req->rsp_upiu.qr.data[0];
823
+ }
824
+ req->rsp_upiu.qr.opcode = req->req_upiu.qr.opcode;
825
+ req->rsp_upiu.qr.idn = req->req_upiu.qr.idn;
826
+ req->rsp_upiu.qr.index = req->req_upiu.qr.index;
827
+ req->rsp_upiu.qr.selector = req->req_upiu.qr.selector;
828
+ req->rsp_upiu.qr.length = cpu_to_be16(length);
829
+
830
+ return status;
831
+}
832
+
833
+static QueryRespCode ufs_exec_query_read(UfsRequest *req)
834
+{
835
+ QueryRespCode status;
836
+ switch (req->req_upiu.qr.opcode) {
837
+ case UFS_UPIU_QUERY_OPCODE_NOP:
838
+ status = UFS_QUERY_RESULT_SUCCESS;
839
+ break;
840
+ case UFS_UPIU_QUERY_OPCODE_READ_DESC:
841
+ status = ufs_read_desc(req);
842
+ break;
843
+ case UFS_UPIU_QUERY_OPCODE_READ_ATTR:
844
+ status = ufs_exec_query_attr(req, UFS_QUERY_ATTR_READ);
845
+ break;
846
+ case UFS_UPIU_QUERY_OPCODE_READ_FLAG:
847
+ status = ufs_exec_query_flag(req, UFS_QUERY_FLAG_READ);
848
+ break;
849
+ default:
850
+ trace_ufs_err_query_invalid_opcode(req->req_upiu.qr.opcode);
851
+ status = UFS_QUERY_RESULT_INVALID_OPCODE;
852
+ break;
853
+ }
854
+
855
+ return status;
856
+}
857
+
858
+static QueryRespCode ufs_exec_query_write(UfsRequest *req)
859
+{
860
+ QueryRespCode status;
861
+ switch (req->req_upiu.qr.opcode) {
862
+ case UFS_UPIU_QUERY_OPCODE_NOP:
863
+ status = UFS_QUERY_RESULT_SUCCESS;
864
+ break;
865
+ case UFS_UPIU_QUERY_OPCODE_WRITE_DESC:
866
+ /* write descriptor is not supported */
867
+ status = UFS_QUERY_RESULT_NOT_WRITEABLE;
868
+ break;
869
+ case UFS_UPIU_QUERY_OPCODE_WRITE_ATTR:
870
+ status = ufs_exec_query_attr(req, UFS_QUERY_ATTR_WRITE);
871
+ break;
872
+ case UFS_UPIU_QUERY_OPCODE_SET_FLAG:
873
+ status = ufs_exec_query_flag(req, UFS_QUERY_FLAG_SET);
874
+ break;
875
+ case UFS_UPIU_QUERY_OPCODE_CLEAR_FLAG:
876
+ status = ufs_exec_query_flag(req, UFS_QUERY_FLAG_CLEAR);
877
+ break;
878
+ case UFS_UPIU_QUERY_OPCODE_TOGGLE_FLAG:
879
+ status = ufs_exec_query_flag(req, UFS_QUERY_FLAG_TOGGLE);
880
+ break;
881
+ default:
882
+ trace_ufs_err_query_invalid_opcode(req->req_upiu.qr.opcode);
883
+ status = UFS_QUERY_RESULT_INVALID_OPCODE;
884
+ break;
885
+ }
886
+
887
+ return status;
888
+}
889
+
890
+static UfsReqResult ufs_exec_query_cmd(UfsRequest *req)
891
+{
892
+ uint8_t query_func = req->req_upiu.header.query_func;
893
+ uint16_t data_segment_length;
894
+ QueryRespCode status;
895
+
896
+ trace_ufs_exec_query_cmd(req->slot, req->req_upiu.qr.opcode);
897
+ if (query_func == UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST) {
898
+ status = ufs_exec_query_read(req);
899
+ } else if (query_func == UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST) {
900
+ status = ufs_exec_query_write(req);
901
+ } else {
902
+ status = UFS_QUERY_RESULT_GENERAL_FAILURE;
903
+ }
904
+
905
+ data_segment_length = be16_to_cpu(req->rsp_upiu.qr.length);
906
+ ufs_build_upiu_header(req, UFS_UPIU_TRANSACTION_QUERY_RSP, 0, status, 0,
907
+ data_segment_length);
908
+
909
+ if (status != UFS_QUERY_RESULT_SUCCESS) {
910
+ return UFS_REQUEST_FAIL;
911
+ }
912
+ return UFS_REQUEST_SUCCESS;
913
+}
914
+
915
+static void ufs_exec_req(UfsRequest *req)
916
+{
917
+ UfsReqResult req_result;
918
+
919
+ if (ufs_dma_read_upiu(req)) {
920
+ return;
921
+ }
922
+
923
+ switch (req->req_upiu.header.trans_type) {
924
+ case UFS_UPIU_TRANSACTION_NOP_OUT:
925
+ req_result = ufs_exec_nop_cmd(req);
926
+ break;
927
+ case UFS_UPIU_TRANSACTION_COMMAND:
928
+ /* Not yet implemented */
929
+ req_result = UFS_REQUEST_FAIL;
930
+ break;
931
+ case UFS_UPIU_TRANSACTION_QUERY_REQ:
932
+ req_result = ufs_exec_query_cmd(req);
933
+ break;
934
+ default:
935
+ trace_ufs_err_invalid_trans_code(req->slot,
936
+ req->req_upiu.header.trans_type);
937
+ req_result = UFS_REQUEST_FAIL;
938
+ }
939
+
940
+ ufs_complete_req(req, req_result);
941
+}
942
+
943
+static void ufs_process_req(void *opaque)
944
+{
945
+ UfsHc *u = opaque;
946
+ UfsRequest *req;
947
+ int slot;
948
+
949
+ for (slot = 0; slot < u->params.nutrs; slot++) {
950
+ req = &u->req_list[slot];
951
+
952
+ if (req->state != UFS_REQUEST_READY) {
953
+ continue;
954
+ }
955
+ trace_ufs_process_req(slot);
956
+ req->state = UFS_REQUEST_RUNNING;
957
+
958
+ ufs_exec_req(req);
959
+ }
960
+}
961
+
962
+static void ufs_complete_req(UfsRequest *req, UfsReqResult req_result)
963
+{
964
+ UfsHc *u = req->hc;
965
+ assert(req->state == UFS_REQUEST_RUNNING);
966
+
967
+ if (req_result == UFS_REQUEST_SUCCESS) {
968
+ req->utrd.header.dword_2 = cpu_to_le32(UFS_OCS_SUCCESS);
969
+ } else {
970
+ req->utrd.header.dword_2 = cpu_to_le32(UFS_OCS_INVALID_CMD_TABLE_ATTR);
971
+ }
972
+
973
+ trace_ufs_complete_req(req->slot);
974
+ req->state = UFS_REQUEST_COMPLETE;
975
+ qemu_bh_schedule(u->complete_bh);
976
+}
977
+
978
+static void ufs_clear_req(UfsRequest *req)
979
+{
980
+ if (req->sg != NULL) {
981
+ qemu_sglist_destroy(req->sg);
982
+ g_free(req->sg);
983
+ req->sg = NULL;
984
+ }
985
+
986
+ memset(&req->utrd, 0, sizeof(req->utrd));
987
+ memset(&req->req_upiu, 0, sizeof(req->req_upiu));
988
+ memset(&req->rsp_upiu, 0, sizeof(req->rsp_upiu));
989
+}
990
+
991
+static void ufs_sendback_req(void *opaque)
992
+{
993
+ UfsHc *u = opaque;
994
+ UfsRequest *req;
995
+ int slot;
996
+
997
+ for (slot = 0; slot < u->params.nutrs; slot++) {
998
+ req = &u->req_list[slot];
999
+
1000
+ if (req->state != UFS_REQUEST_COMPLETE) {
1001
+ continue;
1002
+ }
1003
+
1004
+ if (ufs_dma_write_upiu(req)) {
1005
+ req->state = UFS_REQUEST_ERROR;
1006
+ continue;
1007
+ }
1008
+
1009
+ /*
1010
+ * TODO: UTP Transfer Request Interrupt Aggregation Control is not yet
1011
+ * supported
1012
+ */
1013
+ if (le32_to_cpu(req->utrd.header.dword_2) != UFS_OCS_SUCCESS ||
1014
+ le32_to_cpu(req->utrd.header.dword_0) & UFS_UTP_REQ_DESC_INT_CMD) {
1015
+ u->reg.is = FIELD_DP32(u->reg.is, IS, UTRCS, 1);
1016
+ }
1017
+
1018
+ u->reg.utrldbr &= ~(1 << slot);
1019
+ u->reg.utrlcnr |= (1 << slot);
1020
+
1021
+ trace_ufs_sendback_req(req->slot);
1022
+
1023
+ ufs_clear_req(req);
1024
+ req->state = UFS_REQUEST_IDLE;
1025
+ }
1026
+
1027
+ ufs_irq_check(u);
1028
+}
1029
+
1030
static bool ufs_check_constraints(UfsHc *u, Error **errp)
1031
{
1032
if (u->params.nutrs > UFS_MAX_NUTRS) {
1033
@@ -XXX,XX +XXX,XX @@ static void ufs_init_pci(UfsHc *u, PCIDevice *pci_dev)
1034
u->irq = pci_allocate_irq(pci_dev);
1035
}
1036
1037
+static void ufs_init_state(UfsHc *u)
1038
+{
1039
+ u->req_list = g_new0(UfsRequest, u->params.nutrs);
1040
+
1041
+ for (int i = 0; i < u->params.nutrs; i++) {
1042
+ u->req_list[i].hc = u;
1043
+ u->req_list[i].slot = i;
1044
+ u->req_list[i].sg = NULL;
1045
+ u->req_list[i].state = UFS_REQUEST_IDLE;
1046
+ }
1047
+
1048
+ u->doorbell_bh = qemu_bh_new_guarded(ufs_process_req, u,
1049
+ &DEVICE(u)->mem_reentrancy_guard);
1050
+ u->complete_bh = qemu_bh_new_guarded(ufs_sendback_req, u,
1051
+ &DEVICE(u)->mem_reentrancy_guard);
1052
+}
1053
+
1054
static void ufs_init_hc(UfsHc *u)
1055
{
1056
uint32_t cap = 0;
1057
@@ -XXX,XX +XXX,XX @@ static void ufs_init_hc(UfsHc *u)
1058
cap = FIELD_DP32(cap, CAP, CS, 0);
1059
u->reg.cap = cap;
1060
u->reg.ver = UFS_SPEC_VER;
1061
+
1062
+ memset(&u->device_desc, 0, sizeof(DeviceDescriptor));
1063
+ u->device_desc.length = sizeof(DeviceDescriptor);
1064
+ u->device_desc.descriptor_idn = UFS_QUERY_DESC_IDN_DEVICE;
1065
+ u->device_desc.device_sub_class = 0x01;
1066
+ u->device_desc.number_lu = 0x00;
1067
+ u->device_desc.number_wlu = 0x04;
1068
+ /* TODO: Revisit it when Power Management is implemented */
1069
+ u->device_desc.init_power_mode = 0x01; /* Active Mode */
1070
+ u->device_desc.high_priority_lun = 0x7F; /* Same Priority */
1071
+ u->device_desc.spec_version = cpu_to_be16(UFS_SPEC_VER);
1072
+ u->device_desc.manufacturer_name = 0x00;
1073
+ u->device_desc.product_name = 0x01;
1074
+ u->device_desc.serial_number = 0x02;
1075
+ u->device_desc.oem_id = 0x03;
1076
+ u->device_desc.ud_0_base_offset = 0x16;
1077
+ u->device_desc.ud_config_p_length = 0x1A;
1078
+ u->device_desc.device_rtt_cap = 0x02;
1079
+ u->device_desc.queue_depth = u->params.nutrs;
1080
+ u->device_desc.product_revision_level = 0x04;
1081
+
1082
+ memset(&u->geometry_desc, 0, sizeof(GeometryDescriptor));
1083
+ u->geometry_desc.length = sizeof(GeometryDescriptor);
1084
+ u->geometry_desc.descriptor_idn = UFS_QUERY_DESC_IDN_GEOMETRY;
1085
+ u->geometry_desc.max_number_lu = (UFS_MAX_LUS == 32) ? 0x1 : 0x0;
1086
+ u->geometry_desc.segment_size = cpu_to_be32(0x2000); /* 4KB */
1087
+ u->geometry_desc.allocation_unit_size = 0x1; /* 4KB */
1088
+ u->geometry_desc.min_addr_block_size = 0x8; /* 4KB */
1089
+ u->geometry_desc.max_in_buffer_size = 0x8;
1090
+ u->geometry_desc.max_out_buffer_size = 0x8;
1091
+ u->geometry_desc.rpmb_read_write_size = 0x40;
1092
+ u->geometry_desc.data_ordering =
1093
+ 0x0; /* out-of-order data transfer is not supported */
1094
+ u->geometry_desc.max_context_id_number = 0x5;
1095
+ u->geometry_desc.supported_memory_types = cpu_to_be16(0x8001);
1096
+
1097
+ memset(&u->attributes, 0, sizeof(u->attributes));
1098
+ u->attributes.max_data_in_size = 0x08;
1099
+ u->attributes.max_data_out_size = 0x08;
1100
+ u->attributes.ref_clk_freq = 0x01; /* 26 MHz */
1101
+ /* configure descriptor is not supported */
1102
+ u->attributes.config_descr_lock = 0x01;
1103
+ u->attributes.max_num_of_rtt = 0x02;
1104
+
1105
+ memset(&u->flags, 0, sizeof(u->flags));
1106
+ u->flags.permanently_disable_fw_update = 1;
1107
}
1108
1109
static void ufs_realize(PCIDevice *pci_dev, Error **errp)
1110
@@ -XXX,XX +XXX,XX @@ static void ufs_realize(PCIDevice *pci_dev, Error **errp)
1111
return;
1112
}
1113
1114
+ ufs_init_state(u);
1115
ufs_init_hc(u);
1116
ufs_init_pci(u, pci_dev);
1117
}
1118
1119
+static void ufs_exit(PCIDevice *pci_dev)
1120
+{
1121
+ UfsHc *u = UFS(pci_dev);
1122
+
1123
+ qemu_bh_delete(u->doorbell_bh);
1124
+ qemu_bh_delete(u->complete_bh);
1125
+
1126
+ for (int i = 0; i < u->params.nutrs; i++) {
1127
+ ufs_clear_req(&u->req_list[i]);
1128
+ }
1129
+ g_free(u->req_list);
1130
+}
1131
+
1132
static Property ufs_props[] = {
1133
DEFINE_PROP_STRING("serial", UfsHc, params.serial),
1134
DEFINE_PROP_UINT8("nutrs", UfsHc, params.nutrs, 32),
1135
@@ -XXX,XX +XXX,XX @@ static void ufs_class_init(ObjectClass *oc, void *data)
1136
PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc);
1137
1138
pc->realize = ufs_realize;
1139
+ pc->exit = ufs_exit;
1140
pc->vendor_id = PCI_VENDOR_ID_REDHAT;
1141
pc->device_id = PCI_DEVICE_ID_REDHAT_UFS;
1142
pc->class_id = PCI_CLASS_STORAGE_UFS;
1143
diff --git a/hw/ufs/trace-events b/hw/ufs/trace-events
64
index XXXXXXX..XXXXXXX 100644
1144
index XXXXXXX..XXXXXXX 100644
65
--- a/util/throttle.c
1145
--- a/hw/ufs/trace-events
66
+++ b/util/throttle.c
1146
+++ b/hw/ufs/trace-events
67
@@ -XXX,XX +XXX,XX @@ int64_t throttle_compute_wait(LeakyBucket *bkt)
1147
@@ -XXX,XX +XXX,XX @@ ufs_err_dma_read_req_upiu(uint32_t slot, uint64_t addr) "failed to read req upiu
68
/* If bkt->max is 0 we still want to allow short bursts of I/O
1148
ufs_err_dma_read_prdt(uint32_t slot, uint64_t addr) "failed to read prdt. UTRLDBR slot %"PRIu32", prdt addr %"PRIu64""
69
* from the guest, otherwise every other request will be throttled
1149
ufs_err_dma_write_utrd(uint32_t slot, uint64_t addr) "failed to write utrd. UTRLDBR slot %"PRIu32", UTRD dma addr %"PRIu64""
70
* and performance will suffer considerably. */
1150
ufs_err_dma_write_rsp_upiu(uint32_t slot, uint64_t addr) "failed to write rsp upiu. UTRLDBR slot %"PRIu32", response upiu addr %"PRIu64""
71
- bucket_size = bkt->avg / 10;
1151
+ufs_err_utrl_slot_error(uint32_t slot) "UTRLDBR slot %"PRIu32" is in error"
72
+ bucket_size = (double) bkt->avg / 10;
1152
ufs_err_utrl_slot_busy(uint32_t slot) "UTRLDBR slot %"PRIu32" is busy"
73
burst_bucket_size = 0;
1153
ufs_err_unsupport_register_offset(uint32_t offset) "Register offset 0x%"PRIx32" is not yet supported"
74
} else {
1154
ufs_err_invalid_register_offset(uint32_t offset) "Register offset 0x%"PRIx32" is invalid"
75
/* If we have a burst limit then we have to wait until all I/O
76
* at burst rate has finished before throttling to bkt->avg */
77
bucket_size = bkt->max * bkt->burst_length;
78
- burst_bucket_size = bkt->max / 10;
79
+ burst_bucket_size = (double) bkt->max / 10;
80
}
81
82
/* If the main bucket is full then we have to wait */
83
@@ -XXX,XX +XXX,XX @@ bool throttle_is_valid(ThrottleConfig *cfg, Error **errp)
84
85
for (i = 0; i < BUCKETS_COUNT; i++) {
86
LeakyBucket *bkt = &cfg->buckets[i];
87
- if (bkt->avg < 0 || bkt->max < 0 ||
88
- bkt->avg > THROTTLE_VALUE_MAX || bkt->max > THROTTLE_VALUE_MAX) {
89
+ if (bkt->avg > THROTTLE_VALUE_MAX || bkt->max > THROTTLE_VALUE_MAX) {
90
error_setg(errp, "bps/iops/max values must be within [0, %lld]",
91
THROTTLE_VALUE_MAX);
92
return false;
93
--
1155
--
94
2.13.5
1156
2.41.0
95
96
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Jeuk Kim <jeuk20.kim@samsung.com>
2
2
3
The throttling code can change internally the value of bkt->max if it
3
This commit adds support for ufs logical unit.
4
hasn't been set by the user. The problem with this is that if we want
4
The LU handles processing for the SCSI command,
5
to retrieve the original value we have to undo this change first. This
5
unit descriptor query request.
6
is ugly and unnecessary: this patch removes the throttle_fix_bucket()
7
and throttle_unfix_bucket() functions completely and moves the logic
8
to throttle_compute_wait().
9
6
10
Signed-off-by: Alberto Garcia <berto@igalia.com>
7
This commit enables the UFS device to process
11
Reviewed-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
8
IO requests.
12
Message-id: 5b0b9e1ac6eb208d709eddc7b09e7669a523bff3.1503580370.git.berto@igalia.com
9
10
Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>
11
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Message-id: beacc504376ab6a14b1a3830bb3c69382cf6aebc.1693980783.git.jeuk20.kim@gmail.com
13
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
13
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
14
---
14
---
15
util/throttle.c | 62 +++++++++++++++++++++------------------------------------
15
hw/ufs/ufs.h | 43 ++
16
1 file changed, 23 insertions(+), 39 deletions(-)
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
17
23
18
diff --git a/util/throttle.c b/util/throttle.c
24
diff --git a/hw/ufs/ufs.h b/hw/ufs/ufs.h
19
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100644
20
--- a/util/throttle.c
26
--- a/hw/ufs/ufs.h
21
+++ b/util/throttle.c
27
+++ b/hw/ufs/ufs.h
22
@@ -XXX,XX +XXX,XX @@ static int64_t throttle_do_compute_wait(double limit, double extra)
28
@@ -XXX,XX +XXX,XX @@
23
int64_t throttle_compute_wait(LeakyBucket *bkt)
29
#define UFS_MAX_LUS 32
30
#define UFS_BLOCK_SIZE 4096
31
32
+typedef struct UfsBusClass {
33
+ BusClass parent_class;
34
+ bool (*parent_check_address)(BusState *bus, DeviceState *dev, Error **errp);
35
+} UfsBusClass;
36
+
37
+typedef struct UfsBus {
38
+ SCSIBus parent_bus;
39
+} UfsBus;
40
+
41
+#define TYPE_UFS_BUS "ufs-bus"
42
+DECLARE_OBJ_CHECKERS(UfsBus, UfsBusClass, UFS_BUS, TYPE_UFS_BUS)
43
+
44
typedef enum UfsRequestState {
45
UFS_REQUEST_IDLE = 0,
46
UFS_REQUEST_READY = 1,
47
@@ -XXX,XX +XXX,XX @@ typedef enum UfsRequestState {
48
typedef enum UfsReqResult {
49
UFS_REQUEST_SUCCESS = 0,
50
UFS_REQUEST_FAIL = 1,
51
+ UFS_REQUEST_NO_COMPLETE = 2,
52
} UfsReqResult;
53
54
typedef struct UfsRequest {
55
@@ -XXX,XX +XXX,XX @@ typedef struct UfsRequest {
56
QEMUSGList *sg;
57
} UfsRequest;
58
59
+typedef struct UfsLu {
60
+ SCSIDevice qdev;
61
+ uint8_t lun;
62
+ UnitDescriptor unit_desc;
63
+} UfsLu;
64
+
65
+typedef struct UfsWLu {
66
+ SCSIDevice qdev;
67
+ uint8_t lun;
68
+} UfsWLu;
69
+
70
typedef struct UfsParams {
71
char *serial;
72
uint8_t nutrs; /* Number of UTP Transfer Request Slots */
73
@@ -XXX,XX +XXX,XX @@ typedef struct UfsParams {
74
75
typedef struct UfsHc {
76
PCIDevice parent_obj;
77
+ UfsBus bus;
78
MemoryRegion iomem;
79
UfsReg reg;
80
UfsParams params;
81
uint32_t reg_size;
82
UfsRequest *req_list;
83
84
+ UfsLu *lus[UFS_MAX_LUS];
85
+ UfsWLu *report_wlu;
86
+ UfsWLu *dev_wlu;
87
+ UfsWLu *boot_wlu;
88
+ UfsWLu *rpmb_wlu;
89
DeviceDescriptor device_desc;
90
GeometryDescriptor geometry_desc;
91
Attributes attributes;
92
@@ -XXX,XX +XXX,XX @@ typedef struct UfsHc {
93
#define TYPE_UFS "ufs"
94
#define UFS(obj) OBJECT_CHECK(UfsHc, (obj), TYPE_UFS)
95
96
+#define TYPE_UFS_LU "ufs-lu"
97
+#define UFSLU(obj) OBJECT_CHECK(UfsLu, (obj), TYPE_UFS_LU)
98
+
99
+#define TYPE_UFS_WLU "ufs-wlu"
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
118
index XXXXXXX..XXXXXXX 100644
119
--- a/include/scsi/constants.h
120
+++ b/include/scsi/constants.h
121
@@ -XXX,XX +XXX,XX @@
122
#define MODE_PAGE_FLEXIBLE_DISK_GEOMETRY 0x05
123
#define MODE_PAGE_CACHING 0x08
124
#define MODE_PAGE_AUDIO_CTL 0x0e
125
+#define MODE_PAGE_CONTROL 0x0a
126
#define MODE_PAGE_POWER 0x1a
127
#define MODE_PAGE_FAULT_FAIL 0x1c
128
#define MODE_PAGE_TO_PROTECT 0x1d
129
diff --git a/hw/ufs/lu.c b/hw/ufs/lu.c
130
new file mode 100644
131
index XXXXXXX..XXXXXXX
132
--- /dev/null
133
+++ b/hw/ufs/lu.c
134
@@ -XXX,XX +XXX,XX @@
135
+/*
136
+ * QEMU UFS Logical Unit
137
+ *
138
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd. All rights reserved.
139
+ *
140
+ * Written by Jeuk Kim <jeuk20.kim@samsung.com>
141
+ *
142
+ * This code is licensed under the GNU GPL v2 or later.
143
+ */
144
+
145
+#include "qemu/osdep.h"
146
+#include "qemu/units.h"
147
+#include "qapi/error.h"
148
+#include "qemu/memalign.h"
149
+#include "hw/scsi/scsi.h"
150
+#include "scsi/constants.h"
151
+#include "sysemu/block-backend.h"
152
+#include "qemu/cutils.h"
153
+#include "trace.h"
154
+#include "ufs.h"
155
+
156
+/*
157
+ * The code below handling SCSI commands is copied from hw/scsi/scsi-disk.c,
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 = UFS_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 = UFS_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 = UFS_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, UFS_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)
24
{
1721
{
25
double extra; /* the number of extra units blocking the io */
1722
trace_ufs_exec_nop_cmd(req->slot);
26
+ double bucket_size; /* I/O before throttling to bkt->avg */
1723
@@ -XXX,XX +XXX,XX @@ static const RpmbUnitDescriptor rpmb_unit_desc = {
27
+ double burst_bucket_size; /* Before throttling to bkt->max */
1724
28
1725
static QueryRespCode ufs_read_unit_desc(UfsRequest *req)
29
if (!bkt->avg) {
1726
{
30
return 0;
1727
+ UfsHc *u = req->hc;
1728
uint8_t lun = req->req_upiu.qr.index;
1729
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 UFS_QUERY_RESULT_INVALID_INDEX;
31
}
1735
}
32
1736
@@ -XXX,XX +XXX,XX @@ static QueryRespCode ufs_read_unit_desc(UfsRequest *req)
33
- /* If the bucket is full then we have to wait */
1737
if (lun == UFS_UPIU_RPMB_WLUN) {
34
- extra = bkt->level - bkt->max * bkt->burst_length;
1738
memcpy(&req->rsp_upiu.qr.data, &rpmb_unit_desc, rpmb_unit_desc.length);
35
+ if (!bkt->max) {
1739
} else {
36
+ /* If bkt->max is 0 we still want to allow short bursts of I/O
1740
- /* unit descriptor is not yet supported */
37
+ * from the guest, otherwise every other request will be throttled
1741
- return UFS_QUERY_RESULT_INVALID_INDEX;
38
+ * and performance will suffer considerably. */
1742
+ memcpy(&req->rsp_upiu.qr.data, &u->lus[lun]->unit_desc,
39
+ bucket_size = bkt->avg / 10;
1743
+ sizeof(u->lus[lun]->unit_desc));
40
+ burst_bucket_size = 0;
41
+ } else {
42
+ /* If we have a burst limit then we have to wait until all I/O
43
+ * at burst rate has finished before throttling to bkt->avg */
44
+ bucket_size = bkt->max * bkt->burst_length;
45
+ burst_bucket_size = bkt->max / 10;
46
+ }
47
+
48
+ /* If the main bucket is full then we have to wait */
49
+ extra = bkt->level - bucket_size;
50
if (extra > 0) {
51
return throttle_do_compute_wait(bkt->avg, extra);
52
}
1744
}
53
1745
54
- /* If the bucket is not full yet we have to make sure that we
1746
return UFS_QUERY_RESULT_SUCCESS;
55
- * fulfill the goal of bkt->max units per second. */
1747
@@ -XXX,XX +XXX,XX @@ static void ufs_exec_req(UfsRequest *req)
56
+ /* If the main bucket is not full yet we still have to check the
1748
req_result = ufs_exec_nop_cmd(req);
57
+ * burst bucket in order to enforce the burst limit */
1749
break;
58
if (bkt->burst_length > 1) {
1750
case UFS_UPIU_TRANSACTION_COMMAND:
59
- /* We use 1/10 of the max value to smooth the throttling.
1751
- /* Not yet implemented */
60
- * See throttle_fix_bucket() for more details. */
1752
- req_result = UFS_REQUEST_FAIL;
61
- extra = bkt->burst_level - bkt->max / 10;
1753
+ req_result = ufs_exec_scsi_cmd(req);
62
+ extra = bkt->burst_level - burst_bucket_size;
1754
break;
63
if (extra > 0) {
1755
case UFS_UPIU_TRANSACTION_QUERY_REQ:
64
return throttle_do_compute_wait(bkt->max, extra);
1756
req_result = ufs_exec_query_cmd(req);
65
}
1757
@@ -XXX,XX +XXX,XX @@ static void ufs_exec_req(UfsRequest *req)
66
@@ -XXX,XX +XXX,XX @@ bool throttle_is_valid(ThrottleConfig *cfg, Error **errp)
1758
req_result = UFS_REQUEST_FAIL;
67
return true;
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
+ }
68
}
1770
}
69
1771
70
-/* fix bucket parameters */
1772
static void ufs_process_req(void *opaque)
71
-static void throttle_fix_bucket(LeakyBucket *bkt)
1773
@@ -XXX,XX +XXX,XX @@ static void ufs_init_hc(UfsHc *u)
72
-{
1774
u->flags.permanently_disable_fw_update = 1;
73
- double min;
1775
}
74
-
1776
75
- /* zero bucket level */
1777
+static bool ufs_init_wlu(UfsHc *u, UfsWLu **wlu, uint8_t wlun, Error **errp)
76
- bkt->level = bkt->burst_level = 0;
1778
+{
77
-
1779
+ UfsWLu *new_wlu = UFSWLU(qdev_new(TYPE_UFS_WLU));
78
- /* If bkt->max is 0 we still want to allow short bursts of I/O
1780
+
79
- * from the guest, otherwise every other request will be throttled
1781
+ qdev_prop_set_uint32(DEVICE(new_wlu), "lun", wlun);
80
- * and performance will suffer considerably. */
1782
+
81
- min = bkt->avg / 10;
1783
+ /*
82
- if (bkt->avg && !bkt->max) {
1784
+ * The well-known lu shares the same bus as the normal lu. If the well-known
83
- bkt->max = min;
1785
+ * lu writes the same channel value as the normal lu, the report will be
84
- }
1786
+ * made not only for the normal lu but also for the well-known lu at
85
-}
1787
+ * REPORT_LUN time. To prevent this, the channel value of normal lu is fixed
86
-
1788
+ * to 0 and the channel value of well-known lu is fixed to 1.
87
-/* undo internal bucket parameter changes (see throttle_fix_bucket()) */
1789
+ */
88
-static void throttle_unfix_bucket(LeakyBucket *bkt)
1790
+ qdev_prop_set_uint32(DEVICE(new_wlu), "channel", 1);
89
-{
1791
+ if (!qdev_realize_and_unref(DEVICE(new_wlu), BUS(&u->bus), errp)) {
90
- if (bkt->max < bkt->avg) {
1792
+ return false;
91
- bkt->max = 0;
1793
+ }
92
- }
1794
+
93
-}
1795
+ *wlu = new_wlu;
94
-
1796
+ return true;
95
/* Used to configure the throttle
1797
+}
96
*
1798
+
97
* @ts: the throttle state we are working on
1799
static void ufs_realize(PCIDevice *pci_dev, Error **errp)
98
@@ -XXX,XX +XXX,XX @@ void throttle_config(ThrottleState *ts,
1800
{
99
1801
UfsHc *u = UFS(pci_dev);
100
ts->cfg = *cfg;
1802
@@ -XXX,XX +XXX,XX @@ static void ufs_realize(PCIDevice *pci_dev, Error **errp)
101
1803
return;
102
+ /* Zero bucket level */
103
for (i = 0; i < BUCKETS_COUNT; i++) {
104
- throttle_fix_bucket(&ts->cfg.buckets[i]);
105
+ ts->cfg.buckets[i].level = 0;
106
+ ts->cfg.buckets[i].burst_level = 0;
107
}
1804
}
108
1805
109
ts->previous_leak = qemu_clock_get_ns(clock_type);
1806
+ qbus_init(&u->bus, sizeof(UfsBus), TYPE_UFS_BUS, &pci_dev->qdev,
110
@@ -XXX,XX +XXX,XX @@ void throttle_config(ThrottleState *ts,
1807
+ u->parent_obj.qdev.id);
111
*/
1808
+ u->bus.parent_bus.info = &ufs_scsi_info;
112
void throttle_get_config(ThrottleState *ts, ThrottleConfig *cfg)
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)
113
{
1832
{
114
- int i;
1833
UfsHc *u = UFS(pci_dev);
115
-
1834
116
*cfg = ts->cfg;
1835
+ if (u->dev_wlu) {
117
-
1836
+ object_unref(OBJECT(u->dev_wlu));
118
- for (i = 0; i < BUCKETS_COUNT; i++) {
1837
+ u->dev_wlu = NULL;
119
- throttle_unfix_bucket(&cfg->buckets[i]);
1838
+ }
120
- }
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;
121
}
1860
}
122
1861
123
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
1928
index XXXXXXX..XXXXXXX 100644
1929
--- a/hw/ufs/meson.build
1930
+++ b/hw/ufs/meson.build
1931
@@ -1 +1 @@
1932
-system_ss.add(when: 'CONFIG_UFS_PCI', if_true: files('ufs.c'))
1933
+system_ss.add(when: 'CONFIG_UFS_PCI', if_true: files('ufs.c', 'lu.c'))
1934
diff --git a/hw/ufs/trace-events b/hw/ufs/trace-events
1935
index XXXXXXX..XXXXXXX 100644
1936
--- a/hw/ufs/trace-events
1937
+++ b/hw/ufs/trace-events
1938
@@ -XXX,XX +XXX,XX @@ ufs_exec_scsi_cmd(uint32_t slot, uint8_t lun, uint8_t opcode) "slot %"PRIu32", l
1939
ufs_exec_query_cmd(uint32_t slot, uint8_t opcode) "slot %"PRIu32", opcode 0x%"PRIx8""
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""
1941
1942
+# lu.c
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"
1944
+ufs_scsi_read_complete(uint32_t tag, size_t size) "Data ready tag=0x%x len=%zd"
1945
+ufs_scsi_read_data_count(uint32_t sector_count) "Read sector_count=%d"
1946
+ufs_scsi_read_data_invalid(void) "Data transfer direction invalid"
1947
+ufs_scsi_write_complete_noio(uint32_t tag, size_t size) "Write complete tag=0x%x more=%zd"
1948
+ufs_scsi_write_data_invalid(void) "Data transfer direction invalid"
1949
+ufs_scsi_emulate_vpd_page_00(size_t xfer) "Inquiry EVPD[Supported pages] buffer size %zd"
1950
+ufs_scsi_emulate_vpd_page_80_not_supported(void) "Inquiry EVPD[Serial number] not supported"
1951
+ufs_scsi_emulate_vpd_page_80(size_t xfer) "Inquiry EVPD[Serial number] buffer size %zd"
1952
+ufs_scsi_emulate_vpd_page_87(size_t xfer) "Inquiry EVPD[Mode Page Policy] buffer size %zd"
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)"
1954
+ufs_scsi_emulate_read_data(int buflen) "Read buf_len=%d"
1955
+ufs_scsi_emulate_write_data(int buflen) "Write buf_len=%d"
1956
+ufs_scsi_emulate_command_START_STOP(void) "START STOP UNIT"
1957
+ufs_scsi_emulate_command_FORMAT_UNIT(void) "FORMAT UNIT"
1958
+ufs_scsi_emulate_command_SEND_DIAGNOSTIC(void) "SEND DIAGNOSTIC"
1959
+ufs_scsi_emulate_command_SAI_16(void) "SAI READ CAPACITY(16)"
1960
+ufs_scsi_emulate_command_SAI_unsupported(void) "Unsupported Service Action In"
1961
+ufs_scsi_emulate_command_MODE_SELECT_10(size_t xfer) "Mode Select(10) (len %zd)"
1962
+ufs_scsi_emulate_command_VERIFY(int bytchk) "Verify (bytchk %d)"
1963
+ufs_scsi_emulate_command_UNKNOWN(int cmd, const char *name) "Unknown SCSI command (0x%2.2x=%s)"
1964
+ufs_scsi_dma_command_READ(uint64_t lba, uint32_t len) "Read (block %" PRIu64 ", count %u)"
1965
+ufs_scsi_dma_command_WRITE(uint64_t lba, int len) "Write (block %" PRIu64 ", count %u)"
1966
+
1967
# error condition
1968
ufs_err_dma_read_utrd(uint32_t slot, uint64_t addr) "failed to read utrd. UTRLDBR slot %"PRIu32", UTRD dma addr %"PRIu64""
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""
124
--
1970
--
125
2.13.5
1971
2.41.0
126
127
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
LeakyBucket.burst_length is defined as an unsigned integer but the
4
code never checks for overflows and it only makes sure that the value
5
is not 0.
6
7
In practice this means that the user can set something like
8
throttling.iops-total-max-length=4294967300 despite being larger than
9
UINT_MAX and the final value after casting to unsigned int will be 4.
10
11
This patch changes the data type to uint64_t. This does not increase
12
the storage size of LeakyBucket, and allows us to assign the value
13
directly from qemu_opt_get_number() or BlockIOThrottle and then do the
14
checks directly in throttle_is_valid().
15
16
The value of burst_length does not have a specific upper limit,
17
but since the bucket size is defined by max * burst_length we have
18
to prevent overflows. Instead of going for UINT64_MAX or something
19
similar this patch reuses THROTTLE_VALUE_MAX, which allows I/O bursts
20
of 1 GiB/s for 10 days in a row.
21
22
Signed-off-by: Alberto Garcia <berto@igalia.com>
23
Message-id: 1b2e3049803f71cafb2e1fa1be4fb47147a0d398.1503580370.git.berto@igalia.com
24
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
25
---
26
include/qemu/throttle.h | 2 +-
27
util/throttle.c | 5 +++++
28
2 files changed, 6 insertions(+), 1 deletion(-)
29
30
diff --git a/include/qemu/throttle.h b/include/qemu/throttle.h
31
index XXXXXXX..XXXXXXX 100644
32
--- a/include/qemu/throttle.h
33
+++ b/include/qemu/throttle.h
34
@@ -XXX,XX +XXX,XX @@ typedef struct LeakyBucket {
35
uint64_t max; /* leaky bucket max burst in units */
36
double level; /* bucket level in units */
37
double burst_level; /* bucket level in units (for computing bursts) */
38
- unsigned burst_length; /* max length of the burst period, in seconds */
39
+ uint64_t burst_length; /* max length of the burst period, in seconds */
40
} LeakyBucket;
41
42
/* The following structure is used to configure a ThrottleState
43
diff --git a/util/throttle.c b/util/throttle.c
44
index XXXXXXX..XXXXXXX 100644
45
--- a/util/throttle.c
46
+++ b/util/throttle.c
47
@@ -XXX,XX +XXX,XX @@ bool throttle_is_valid(ThrottleConfig *cfg, Error **errp)
48
return false;
49
}
50
51
+ if (bkt->max && bkt->burst_length > THROTTLE_VALUE_MAX / bkt->max) {
52
+ error_setg(errp, "burst length too high for this burst rate");
53
+ return false;
54
+ }
55
+
56
if (bkt->max && !bkt->avg) {
57
error_setg(errp, "bps_max/iops_max require corresponding"
58
" bps/iops values");
59
--
60
2.13.5
61
62
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
Signed-off-by: Alberto Garcia <berto@igalia.com>
4
Message-id: a57dd6274e1b6dc9c28769fec4c7ea543be5c5e3.1503580370.git.berto@igalia.com
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
6
---
7
tests/test-throttle.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++
8
1 file changed, 77 insertions(+)
9
10
diff --git a/tests/test-throttle.c b/tests/test-throttle.c
11
index XXXXXXX..XXXXXXX 100644
12
--- a/tests/test-throttle.c
13
+++ b/tests/test-throttle.c
14
@@ -XXX,XX +XXX,XX @@ static void test_is_valid(void)
15
test_is_valid_for_value(1, true);
16
}
17
18
+static void test_ranges(void)
19
+{
20
+ int i;
21
+
22
+ for (i = 0; i < BUCKETS_COUNT; i++) {
23
+ LeakyBucket *b = &cfg.buckets[i];
24
+ throttle_config_init(&cfg);
25
+
26
+ /* avg = 0 means throttling is disabled, but the config is valid */
27
+ b->avg = 0;
28
+ g_assert(throttle_is_valid(&cfg, NULL));
29
+ g_assert(!throttle_enabled(&cfg));
30
+
31
+ /* These are valid configurations (values <= THROTTLE_VALUE_MAX) */
32
+ b->avg = 1;
33
+ g_assert(throttle_is_valid(&cfg, NULL));
34
+
35
+ b->avg = THROTTLE_VALUE_MAX;
36
+ g_assert(throttle_is_valid(&cfg, NULL));
37
+
38
+ b->avg = THROTTLE_VALUE_MAX;
39
+ b->max = THROTTLE_VALUE_MAX;
40
+ g_assert(throttle_is_valid(&cfg, NULL));
41
+
42
+ /* Values over THROTTLE_VALUE_MAX are not allowed */
43
+ b->avg = THROTTLE_VALUE_MAX + 1;
44
+ g_assert(!throttle_is_valid(&cfg, NULL));
45
+
46
+ b->avg = THROTTLE_VALUE_MAX;
47
+ b->max = THROTTLE_VALUE_MAX + 1;
48
+ g_assert(!throttle_is_valid(&cfg, NULL));
49
+
50
+ /* burst_length must be between 1 and THROTTLE_VALUE_MAX */
51
+ b->avg = 1;
52
+ b->max = 1;
53
+ b->burst_length = 0;
54
+ g_assert(!throttle_is_valid(&cfg, NULL));
55
+
56
+ b->avg = 1;
57
+ b->max = 1;
58
+ b->burst_length = 1;
59
+ g_assert(throttle_is_valid(&cfg, NULL));
60
+
61
+ b->avg = 1;
62
+ b->max = 1;
63
+ b->burst_length = THROTTLE_VALUE_MAX;
64
+ g_assert(throttle_is_valid(&cfg, NULL));
65
+
66
+ b->avg = 1;
67
+ b->max = 1;
68
+ b->burst_length = THROTTLE_VALUE_MAX + 1;
69
+ g_assert(!throttle_is_valid(&cfg, NULL));
70
+
71
+ /* burst_length * max cannot exceed THROTTLE_VALUE_MAX */
72
+ b->avg = 1;
73
+ b->max = 2;
74
+ b->burst_length = THROTTLE_VALUE_MAX / 2;
75
+ g_assert(throttle_is_valid(&cfg, NULL));
76
+
77
+ b->avg = 1;
78
+ b->max = 3;
79
+ b->burst_length = THROTTLE_VALUE_MAX / 2;
80
+ g_assert(!throttle_is_valid(&cfg, NULL));
81
+
82
+ b->avg = 1;
83
+ b->max = THROTTLE_VALUE_MAX;
84
+ b->burst_length = 1;
85
+ g_assert(throttle_is_valid(&cfg, NULL));
86
+
87
+ b->avg = 1;
88
+ b->max = THROTTLE_VALUE_MAX;
89
+ b->burst_length = 2;
90
+ g_assert(!throttle_is_valid(&cfg, NULL));
91
+ }
92
+}
93
+
94
static void test_max_is_missing_limit(void)
95
{
96
int i;
97
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
98
g_test_add_func("/throttle/config/enabled", test_enabled);
99
g_test_add_func("/throttle/config/conflicting", test_conflicting_config);
100
g_test_add_func("/throttle/config/is_valid", test_is_valid);
101
+ g_test_add_func("/throttle/config/ranges", test_ranges);
102
g_test_add_func("/throttle/config/max", test_max_is_missing_limit);
103
g_test_add_func("/throttle/config/iops_size",
104
test_iops_size_is_missing_limit);
105
--
106
2.13.5
107
108
diff view generated by jsdifflib
Deleted patch
1
From: Eduardo Habkost <ehabkost@redhat.com>
2
1
3
If QEMU is running on a system that's out of memory and mmap()
4
fails, QEMU aborts with no error message at all, making it hard
5
to debug the reason for the failure.
6
7
Add perror() calls that will print error information before
8
aborting.
9
10
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
11
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
12
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
13
Message-id: 20170829212053.6003-1-ehabkost@redhat.com
14
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
15
---
16
util/oslib-posix.c | 2 ++
17
1 file changed, 2 insertions(+)
18
19
diff --git a/util/oslib-posix.c b/util/oslib-posix.c
20
index XXXXXXX..XXXXXXX 100644
21
--- a/util/oslib-posix.c
22
+++ b/util/oslib-posix.c
23
@@ -XXX,XX +XXX,XX @@ void *qemu_alloc_stack(size_t *sz)
24
ptr = mmap(NULL, *sz, PROT_READ | PROT_WRITE,
25
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
26
if (ptr == MAP_FAILED) {
27
+ perror("failed to allocate memory for stack");
28
abort();
29
}
30
31
@@ -XXX,XX +XXX,XX @@ void *qemu_alloc_stack(size_t *sz)
32
guardpage = ptr;
33
#endif
34
if (mprotect(guardpage, pagesz, PROT_NONE) != 0) {
35
+ perror("failed to set up stack guard page");
36
abort();
37
}
38
39
--
40
2.13.5
41
42
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
There's a few cases which we're passing an Error pointer to a function
4
only to discard it immediately afterwards without checking it. In
5
these cases we can simply remove the variable and pass NULL instead.
6
7
Signed-off-by: Alberto Garcia <berto@igalia.com>
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Message-id: 20170829120836.16091-1-berto@igalia.com
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
---
13
block/qcow.c | 12 +++---------
14
block/qcow2.c | 8 ++------
15
dump.c | 4 +---
16
3 files changed, 6 insertions(+), 18 deletions(-)
17
18
diff --git a/block/qcow.c b/block/qcow.c
19
index XXXXXXX..XXXXXXX 100644
20
--- a/block/qcow.c
21
+++ b/block/qcow.c
22
@@ -XXX,XX +XXX,XX @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
23
start_sect = (offset & ~(s->cluster_size - 1)) >> 9;
24
for(i = 0; i < s->cluster_sectors; i++) {
25
if (i < n_start || i >= n_end) {
26
- Error *err = NULL;
27
memset(s->cluster_data, 0x00, 512);
28
if (qcrypto_block_encrypt(s->crypto, start_sect + i,
29
s->cluster_data,
30
BDRV_SECTOR_SIZE,
31
- &err) < 0) {
32
- error_free(err);
33
+ NULL) < 0) {
34
errno = EIO;
35
return -1;
36
}
37
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
38
QEMUIOVector hd_qiov;
39
uint8_t *buf;
40
void *orig_buf;
41
- Error *err = NULL;
42
43
if (qiov->niov > 1) {
44
buf = orig_buf = qemu_try_blockalign(bs, qiov->size);
45
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
46
if (bs->encrypted) {
47
assert(s->crypto);
48
if (qcrypto_block_decrypt(s->crypto, sector_num, buf,
49
- n * BDRV_SECTOR_SIZE, &err) < 0) {
50
+ n * BDRV_SECTOR_SIZE, NULL) < 0) {
51
goto fail;
52
}
53
}
54
@@ -XXX,XX +XXX,XX @@ done:
55
return ret;
56
57
fail:
58
- error_free(err);
59
ret = -EIO;
60
goto done;
61
}
62
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
63
break;
64
}
65
if (bs->encrypted) {
66
- Error *err = NULL;
67
assert(s->crypto);
68
if (qcrypto_block_encrypt(s->crypto, sector_num, buf,
69
- n * BDRV_SECTOR_SIZE, &err) < 0) {
70
- error_free(err);
71
+ n * BDRV_SECTOR_SIZE, NULL) < 0) {
72
ret = -EIO;
73
break;
74
}
75
diff --git a/block/qcow2.c b/block/qcow2.c
76
index XXXXXXX..XXXXXXX 100644
77
--- a/block/qcow2.c
78
+++ b/block/qcow2.c
79
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
80
assert(s->crypto);
81
assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
82
assert((cur_bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
83
- Error *err = NULL;
84
if (qcrypto_block_decrypt(s->crypto,
85
(s->crypt_physical_offset ?
86
cluster_offset + offset_in_cluster :
87
offset) >> BDRV_SECTOR_BITS,
88
cluster_data,
89
cur_bytes,
90
- &err) < 0) {
91
- error_free(err);
92
+ NULL) < 0) {
93
ret = -EIO;
94
goto fail;
95
}
96
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset,
97
qemu_iovec_concat(&hd_qiov, qiov, bytes_done, cur_bytes);
98
99
if (bs->encrypted) {
100
- Error *err = NULL;
101
assert(s->crypto);
102
if (!cluster_data) {
103
cluster_data = qemu_try_blockalign(bs->file->bs,
104
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset,
105
cluster_offset + offset_in_cluster :
106
offset) >> BDRV_SECTOR_BITS,
107
cluster_data,
108
- cur_bytes, &err) < 0) {
109
- error_free(err);
110
+ cur_bytes, NULL) < 0) {
111
ret = -EIO;
112
goto fail;
113
}
114
diff --git a/dump.c b/dump.c
115
index XXXXXXX..XXXXXXX 100644
116
--- a/dump.c
117
+++ b/dump.c
118
@@ -XXX,XX +XXX,XX @@ static void dump_process(DumpState *s, Error **errp)
119
120
static void *dump_thread(void *data)
121
{
122
- Error *err = NULL;
123
DumpState *s = (DumpState *)data;
124
- dump_process(s, &err);
125
- error_free(err);
126
+ dump_process(s, NULL);
127
return NULL;
128
}
129
130
--
131
2.13.5
132
133
diff view generated by jsdifflib
Deleted patch
1
Add the scripts/ directory to sys.path so Python 2.6 will be able to
2
import argparse.
3
1
4
Cc: Fam Zheng <famz@redhat.com>
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
6
Acked-by: John Snow <jsnow@redhat.com>
7
Acked-by: Fam Zheng <famz@redhat.com>
8
Message-id: 20170825155732.15665-3-stefanha@redhat.com
9
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
---
11
tests/docker/docker.py | 4 +++-
12
1 file changed, 3 insertions(+), 1 deletion(-)
13
14
diff --git a/tests/docker/docker.py b/tests/docker/docker.py
15
index XXXXXXX..XXXXXXX 100755
16
--- a/tests/docker/docker.py
17
+++ b/tests/docker/docker.py
18
@@ -XXX,XX +XXX,XX @@
19
20
import os
21
import sys
22
+sys.path.append(os.path.join(os.path.dirname(__file__),
23
+ '..', '..', 'scripts'))
24
+import argparse
25
import subprocess
26
import json
27
import hashlib
28
import atexit
29
import uuid
30
-import argparse
31
import tempfile
32
import re
33
import signal
34
--
35
2.13.5
36
37
diff view generated by jsdifflib
Deleted patch
1
Add the scripts/ directory to sys.path so Python 2.6 will be able to
2
import argparse.
3
1
4
Cc: Daniel P. Berrange <berrange@redhat.com>
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
6
Acked-by: John Snow <jsnow@redhat.com>
7
Acked-by: Fam Zheng <famz@redhat.com>
8
Message-id: 20170825155732.15665-4-stefanha@redhat.com
9
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
---
11
tests/migration/guestperf/shell.py | 8 +++++---
12
1 file changed, 5 insertions(+), 3 deletions(-)
13
14
diff --git a/tests/migration/guestperf/shell.py b/tests/migration/guestperf/shell.py
15
index XXXXXXX..XXXXXXX 100644
16
--- a/tests/migration/guestperf/shell.py
17
+++ b/tests/migration/guestperf/shell.py
18
@@ -XXX,XX +XXX,XX @@
19
#
20
21
22
-import argparse
23
-import fnmatch
24
import os
25
import os.path
26
-import platform
27
import sys
28
+sys.path.append(os.path.join(os.path.dirname(__file__),
29
+ '..', '..', '..', 'scripts'))
30
+import argparse
31
+import fnmatch
32
+import platform
33
34
from guestperf.hardware import Hardware
35
from guestperf.engine import Engine
36
--
37
2.13.5
38
39
diff view generated by jsdifflib
Deleted patch
1
From: Fred Rolland <rollandf@gmail.com>
2
1
3
Update doc with the usage of UUID for initiator name.
4
5
Related-To: https://bugzilla.redhat.com/1006468
6
Signed-off-by: Fred Rolland <frolland@redhat.com>
7
Message-id: 20170823084830.30500-1-frolland@redhat.com
8
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
---
10
qemu-doc.texi | 5 +++--
11
1 file changed, 3 insertions(+), 2 deletions(-)
12
13
diff --git a/qemu-doc.texi b/qemu-doc.texi
14
index XXXXXXX..XXXXXXX 100644
15
--- a/qemu-doc.texi
16
+++ b/qemu-doc.texi
17
@@ -XXX,XX +XXX,XX @@ in a configuration file provided via '-readconfig' or directly on the
18
command line.
19
20
If the initiator-name is not specified qemu will use a default name
21
-of 'iqn.2008-11.org.linux-kvm[:<name>'] where <name> is the name of the
22
+of 'iqn.2008-11.org.linux-kvm[:<uuid>'] where <uuid> is the UUID of the
23
+virtual machine. If the UUID is not specified qemu will use
24
+'iqn.2008-11.org.linux-kvm[:<name>'] where <name> is the name of the
25
virtual machine.
26
27
-
28
@example
29
Setting a specific initiator name to use when logging in to the target
30
-iscsi initiator-name=iqn.qemu.test:my-initiator
31
--
32
2.13.5
33
34
diff view generated by jsdifflib
1
Most qcow2 files are uncompressed so it is wasteful to allocate (32 + 1)
1
From: Jeuk Kim <jeuk20.kim@samsung.com>
2
* cluster_size + 512 bytes upfront. Allocate s->cluster_cache and
3
s->cluster_data when the first read operation is performance on a
4
compressed cluster.
5
2
6
The buffers are freed in .bdrv_close(). .bdrv_open() no longer has any
3
This patch includes the following tests
7
code paths that can allocate these buffers, so remove the free functions
4
Test mmio read
8
in the error code path.
5
Test ufs device initialization and ufs-lu recognition
6
Test I/O (Performs a write followed by a read to verify)
9
7
10
This patch can result in significant memory savings when many qcow2
8
Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>
11
disks are attached or backing file chains are long:
9
Acked-by: Thomas Huth <thuth@redhat.com>
12
10
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
13
Before 12.81% (1,023,193,088B)
11
Message-id: 9e9207f54505e9ba30931849f949ff6f474ac333.1693980783.git.jeuk20.kim@gmail.com
14
After 5.36% (393,893,888B)
15
16
Reported-by: Alexey Kardashevskiy <aik@ozlabs.ru>
17
Tested-by: Alexey Kardashevskiy <aik@ozlabs.ru>
18
Reviewed-by: Eric Blake <eblake@redhat.com>
19
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
20
Message-id: 20170821135530.32344-1-stefanha@redhat.com
21
Cc: Kevin Wolf <kwolf@redhat.com>
22
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
23
---
13
---
24
block/qcow2-cluster.c | 17 +++++++++++++++++
14
MAINTAINERS | 1 +
25
block/qcow2.c | 12 ------------
15
tests/qtest/ufs-test.c | 587 ++++++++++++++++++++++++++++++++++++++++
26
2 files changed, 17 insertions(+), 12 deletions(-)
16
tests/qtest/meson.build | 1 +
17
3 files changed, 589 insertions(+)
18
create mode 100644 tests/qtest/ufs-test.c
27
19
28
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
20
diff --git a/MAINTAINERS b/MAINTAINERS
29
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
30
--- a/block/qcow2-cluster.c
22
--- a/MAINTAINERS
31
+++ b/block/qcow2-cluster.c
23
+++ b/MAINTAINERS
32
@@ -XXX,XX +XXX,XX @@ int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
24
@@ -XXX,XX +XXX,XX @@ M: Jeuk Kim <jeuk20.kim@samsung.com>
33
nb_csectors = ((cluster_offset >> s->csize_shift) & s->csize_mask) + 1;
25
S: Supported
34
sector_offset = coffset & 511;
26
F: hw/ufs/*
35
csize = nb_csectors * 512 - sector_offset;
27
F: include/block/ufs.h
36
+
28
+F: tests/qtest/ufs-test.c
37
+ /* Allocate buffers on first decompress operation, most images are
29
38
+ * uncompressed and the memory overhead can be avoided. The buffers
30
megasas
39
+ * are freed in .bdrv_close().
31
M: Hannes Reinecke <hare@suse.com>
40
+ */
32
diff --git a/tests/qtest/ufs-test.c b/tests/qtest/ufs-test.c
41
+ if (!s->cluster_data) {
33
new file mode 100644
42
+ /* one more sector for decompressed data alignment */
34
index XXXXXXX..XXXXXXX
43
+ s->cluster_data = qemu_try_blockalign(bs->file->bs,
35
--- /dev/null
44
+ QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size + 512);
36
+++ b/tests/qtest/ufs-test.c
45
+ if (!s->cluster_data) {
37
@@ -XXX,XX +XXX,XX @@
46
+ return -ENOMEM;
38
+/*
47
+ }
39
+ * QTest testcase for UFS
40
+ *
41
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd. All rights reserved.
42
+ *
43
+ * SPDX-License-Identifier: GPL-2.0-or-later
44
+ */
45
+
46
+#include "qemu/osdep.h"
47
+#include "qemu/module.h"
48
+#include "qemu/units.h"
49
+#include "libqtest.h"
50
+#include "libqos/qgraph.h"
51
+#include "libqos/pci.h"
52
+#include "scsi/constants.h"
53
+#include "include/block/ufs.h"
54
+
55
+/* Test images sizes in Bytes */
56
+#define TEST_IMAGE_SIZE (64 * 1024 * 1024)
57
+/* Timeout for various operations, in seconds. */
58
+#define TIMEOUT_SECONDS 10
59
+/* Maximum PRD entry count */
60
+#define MAX_PRD_ENTRY_COUNT 10
61
+#define PRD_ENTRY_DATA_SIZE 4096
62
+/* Constants to build upiu */
63
+#define UTP_COMMAND_DESCRIPTOR_SIZE 4096
64
+#define UTP_RESPONSE_UPIU_OFFSET 1024
65
+#define UTP_PRDT_UPIU_OFFSET 2048
66
+
67
+typedef struct QUfs QUfs;
68
+
69
+struct QUfs {
70
+ QOSGraphObject obj;
71
+ QPCIDevice dev;
72
+ QPCIBar bar;
73
+
74
+ uint64_t utrlba;
75
+ uint64_t utmrlba;
76
+ uint64_t cmd_desc_addr;
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 | UFS_UTP_REQ_DESC_INT_CMD);
115
+ req.header.dword_2 = cpu_to_le32(UFS_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 = ufs_build_req_utrd(ufs->cmd_desc_addr, slot,
133
+ UFS_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 = UFS_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 = ufs_build_req_utrd(ufs->cmd_desc_addr, slot,
163
+ UFS_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 = UFS_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 = UFS_UTP_HOST_TO_DEVICE;
220
+ data_len = data_in_len;
221
+ flags = UFS_UPIU_CMD_FLAGS_WRITE;
222
+ } else if (data_out_len > 0) {
223
+ g_assert_nonnull(data_out);
224
+ data_direction = UFS_UTP_DEVICE_TO_HOST;
225
+ data_len = data_out_len;
226
+ flags = UFS_UPIU_CMD_FLAGS_READ;
227
+ } else {
228
+ data_direction = UFS_UTP_NO_DATA_TRANSFER;
229
+ data_len = 0;
230
+ flags = UFS_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);
48
+ }
249
+ }
49
+ if (!s->cluster_cache) {
250
+ }
50
+ s->cluster_cache = g_malloc(s->cluster_size);
251
+ qtest_memwrite(ufs->dev.bus->qts, prdt_addr, entries,
51
+ }
252
+ prd_table_length * sizeof(UfshcdSgEntry));
52
+
253
+
53
BLKDBG_EVENT(bs->file, BLKDBG_READ_COMPRESSED);
254
+ /* Build up utp transfer request descriptor */
54
ret = bdrv_read(bs->file, coffset >> 9, s->cluster_data,
255
+ UtpTransferReqDesc utrd = ufs_build_req_utrd(
55
nb_csectors);
256
+ ufs->cmd_desc_addr, slot, data_direction, prd_table_length);
56
diff --git a/block/qcow2.c b/block/qcow2.c
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 = UFS_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, UFS_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), ==, UFS_OCS_SUCCESS);
380
+
381
+ /* Set fDeviceInit flag via query request */
382
+ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
383
+ UFS_UPIU_QUERY_OPCODE_SET_FLAG,
384
+ UFS_QUERY_FLAG_IDN_FDEVICEINIT, 0, &utrd, &rsp_upiu);
385
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_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, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
392
+ UFS_UPIU_QUERY_OPCODE_READ_FLAG,
393
+ UFS_QUERY_FLAG_IDN_FDEVICEINIT, 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), ==, UFS_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), ==, UFS_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), ==, UFS_OCS_SUCCESS);
531
+ g_assert_cmpuint(rsp_upiu.header.scsi_status, ==,
532
+ UFS_COMMAND_RESULT_SUCESS);
533
+ block_size = ldl_be_p(&read_buf[8]);
534
+ g_assert_cmpuint(block_size, ==, 4096);
535
+
536
+ /* Write data */
537
+ memset(write_buf, rand() % 255 + 1, block_size);
538
+ ufs_send_scsi_command(ufs, 0, 1, write_cdb, write_buf, block_size, NULL, 0,
539
+ &utrd, &rsp_upiu);
540
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
541
+ g_assert_cmpuint(rsp_upiu.header.scsi_status, ==,
542
+ UFS_COMMAND_RESULT_SUCESS);
543
+
544
+ /* Read data and verify */
545
+ ufs_send_scsi_command(ufs, 0, 1, read_cdb, NULL, 0, read_buf, block_size,
546
+ &utrd, &rsp_upiu);
547
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
548
+ g_assert_cmpuint(rsp_upiu.header.scsi_status, ==,
549
+ UFS_COMMAND_RESULT_SUCESS);
550
+ g_assert_cmpint(memcmp(read_buf, write_buf, block_size), ==, 0);
551
+
552
+ ufs_exit(ufs, alloc);
553
+}
554
+
555
+static void drive_destroy(void *path)
556
+{
557
+ unlink(path);
558
+ g_free(path);
559
+ qos_invalidate_command_line();
560
+}
561
+
562
+static char *drive_create(void)
563
+{
564
+ int fd, ret;
565
+ char *t_path;
566
+
567
+ /* Create a temporary raw image */
568
+ fd = g_file_open_tmp("qtest-ufs.XXXXXX", &t_path, NULL);
569
+ g_assert_cmpint(fd, >=, 0);
570
+ ret = ftruncate(fd, TEST_IMAGE_SIZE);
571
+ g_assert_cmpint(ret, ==, 0);
572
+ close(fd);
573
+
574
+ g_test_queue_destroy(drive_destroy, t_path);
575
+ return t_path;
576
+}
577
+
578
+static void *ufs_blk_test_setup(GString *cmd_line, void *arg)
579
+{
580
+ char *tmp_path = drive_create();
581
+
582
+ g_string_append_printf(cmd_line,
583
+ " -blockdev file,filename=%s,node-name=drv1 "
584
+ "-device ufs-lu,bus=ufs0,drive=drv1,lun=1 ",
585
+ tmp_path);
586
+
587
+ return arg;
588
+}
589
+
590
+static void ufs_register_nodes(void)
591
+{
592
+ const char *arch;
593
+ QOSGraphEdgeOptions edge_opts = {
594
+ .before_cmd_line = "-blockdev null-co,node-name=drv0,read-zeroes=on",
595
+ .after_cmd_line = "-device ufs-lu,bus=ufs0,drive=drv0,lun=0",
596
+ .extra_device_opts = "addr=04.0,id=ufs0,nutrs=32,nutmrs=8"
597
+ };
598
+
599
+ QOSGraphTestOptions io_test_opts = {
600
+ .before = ufs_blk_test_setup,
601
+ };
602
+
603
+ add_qpci_address(&edge_opts, &(QPCIAddress){ .devfn = QPCI_DEVFN(4, 0) });
604
+
605
+ qos_node_create_driver("ufs", ufs_create);
606
+ qos_node_consumes("ufs", "pci-bus", &edge_opts);
607
+ qos_node_produces("ufs", "pci-device");
608
+
609
+ qos_add_test("reg-read", "ufs", ufstest_reg_read, NULL);
610
+
611
+ /*
612
+ * Check architecture
613
+ * TODO: Enable ufs io tests for ppc64
614
+ */
615
+ arch = qtest_get_arch();
616
+ if (!strcmp(arch, "ppc64")) {
617
+ g_test_message("Skipping ufs io tests for ppc64");
618
+ return;
619
+ }
620
+ qos_add_test("init", "ufs", ufstest_init, NULL);
621
+ qos_add_test("read-write", "ufs", ufstest_read_write, &io_test_opts);
622
+}
623
+
624
+libqos_init(ufs_register_nodes);
625
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
57
index XXXXXXX..XXXXXXX 100644
626
index XXXXXXX..XXXXXXX 100644
58
--- a/block/qcow2.c
627
--- a/tests/qtest/meson.build
59
+++ b/block/qcow2.c
628
+++ b/tests/qtest/meson.build
60
@@ -XXX,XX +XXX,XX @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
629
@@ -XXX,XX +XXX,XX @@ qos_test_ss.add(
61
goto fail;
630
'virtio-iommu-test.c',
62
}
631
'vmxnet3-test.c',
63
632
'igb-test.c',
64
- s->cluster_cache = g_malloc(s->cluster_size);
633
+ 'ufs-test.c',
65
- /* one more sector for decompressed data alignment */
634
)
66
- s->cluster_data = qemu_try_blockalign(bs->file->bs, QCOW_MAX_CRYPT_CLUSTERS
635
67
- * s->cluster_size + 512);
636
if config_all_devices.has_key('CONFIG_VIRTIO_SERIAL')
68
- if (s->cluster_data == NULL) {
69
- error_setg(errp, "Could not allocate temporary cluster buffer");
70
- ret = -ENOMEM;
71
- goto fail;
72
- }
73
-
74
s->cluster_cache_offset = -1;
75
s->flags = flags;
76
77
@@ -XXX,XX +XXX,XX @@ static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
78
if (s->refcount_block_cache) {
79
qcow2_cache_destroy(bs, s->refcount_block_cache);
80
}
81
- g_free(s->cluster_cache);
82
- qemu_vfree(s->cluster_data);
83
qcrypto_block_free(s->crypto);
84
qapi_free_QCryptoBlockOpenOptions(s->crypto_opts);
85
return ret;
86
--
637
--
87
2.13.5
638
2.41.0
88
89
diff view generated by jsdifflib