From ea82aa42835e3f56b3649c92764ac40552aac789 Mon Sep 17 00:00:00 2001 From: Max Reitz <mreitz@redhat.com> Date: Fri, 6 Feb 2015 16:06:17 -0500 Subject: iotests: Add "wait" functionality to _cleanup_qemu The qemu process does not always need to be killed, just waiting for it can be fine, too. This introduces a way to do so. Signed-off-by: Max Reitz <mreitz@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Message-id: 1423256778-3340-3-git-send-email-mreitz@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/qemu-iotests/common.qemu | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/qemu-iotests/common.qemu b/tests/qemu-iotests/common.qemu index 8e618b5149..4e1996c3ec 100644 --- a/tests/qemu-iotests/common.qemu +++ b/tests/qemu-iotests/common.qemu @@ -187,13 +187,23 @@ function _launch_qemu() # Silenty kills the QEMU process +# +# If $wait is set to anything other than the empty string, the process will not +# be killed but only waited for, and any output will be forwarded to stdout. If +# $wait is empty, the process will be killed and all output will be suppressed. function _cleanup_qemu() { # QEMU_PID[], QEMU_IN[], QEMU_OUT[] all use same indices for i in "${!QEMU_OUT[@]}" do - kill -KILL ${QEMU_PID[$i]} 2>/dev/null + if [ -z "${wait}" ]; then + kill -KILL ${QEMU_PID[$i]} 2>/dev/null + fi wait ${QEMU_PID[$i]} 2>/dev/null # silent kill + if [ -n "${wait}" ]; then + cat <&${QEMU_OUT[$i]} | _filter_testdir | _filter_qemu \ + | _filter_qemu_io | _filter_qmp + fi rm -f "${QEMU_FIFO_IN}_${i}" "${QEMU_FIFO_OUT}_${i}" eval "exec ${QEMU_IN[$i]}<&-" # close file descriptors eval "exec ${QEMU_OUT[$i]}<&-" -- cgit v1.2.3 From 21c7f3f74959f18c5feb9b44511cb1a965c25a36 Mon Sep 17 00:00:00 2001 From: Max Reitz <mreitz@redhat.com> Date: Fri, 6 Feb 2015 16:06:18 -0500 Subject: iotests: Add test for drive-mirror with NBD target When the drive-mirror block job is completed, it will call bdrv_swap() on the source and the target BDS; this should obviously not result in a segmentation fault. Signed-off-by: Max Reitz <mreitz@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Message-id: 1423256778-3340-4-git-send-email-mreitz@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/qemu-iotests/094 | 81 ++++++++++++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/094.out | 11 +++++++ tests/qemu-iotests/group | 1 + 3 files changed, 93 insertions(+) create mode 100755 tests/qemu-iotests/094 create mode 100644 tests/qemu-iotests/094.out (limited to 'tests') diff --git a/tests/qemu-iotests/094 b/tests/qemu-iotests/094 new file mode 100755 index 0000000000..27a2be2569 --- /dev/null +++ b/tests/qemu-iotests/094 @@ -0,0 +1,81 @@ +#!/bin/bash +# +# Test case for drive-mirror to NBD (especially bdrv_swap() on NBD BDS) +# +# Copyright (C) 2015 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +# creator +owner=mreitz@redhat.com + +seq="$(basename $0)" +echo "QA output created by $seq" + +here="$PWD" +tmp=/tmp/$$ +status=1 # failure is the default! + +trap "exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter +. ./common.qemu + +_supported_fmt generic +_supported_proto nbd +_supported_os Linux +_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat" + +_make_test_img 64M +$QEMU_IMG create -f $IMGFMT "$TEST_DIR/source.$IMGFMT" 64M | _filter_img_create + +_launch_qemu -drive if=none,id=src,file="$TEST_DIR/source.$IMGFMT",format=raw \ + -nodefaults + +_send_qemu_cmd $QEMU_HANDLE \ + "{'execute': 'qmp_capabilities'}" \ + 'return' + +# 'format': 'nbd' is not actually "correct", but this is probably the only way +# to test bdrv_swap() on an NBD BDS +_send_qemu_cmd $QEMU_HANDLE \ + "{'execute': 'drive-mirror', + 'arguments': {'device': 'src', + 'target': '$TEST_IMG', + 'format': 'nbd', + 'sync':'full', + 'mode':'existing'}}" \ + 'BLOCK_JOB_READY' + +_send_qemu_cmd $QEMU_HANDLE \ + "{'execute': 'block-job-complete', + 'arguments': {'device': 'src'}}" \ + 'BLOCK_JOB_COMPLETE' + +_send_qemu_cmd $QEMU_HANDLE \ + "{'execute': 'quit'}" \ + 'return' + +wait=1 _cleanup_qemu + +_cleanup_test_img +rm -f "$TEST_DIR/source.$IMGFMT" + +# success, all done +echo '*** done' +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/094.out b/tests/qemu-iotests/094.out new file mode 100644 index 0000000000..b66dc0787d --- /dev/null +++ b/tests/qemu-iotests/094.out @@ -0,0 +1,11 @@ +QA output created by 094 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/source.IMGFMT', fmt=IMGFMT size=67108864 +{"return": {}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 67108864, "offset": 67108864, "speed": 0, "type": "mirror"}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"} +*** done diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 4b2b93bc19..6e2447a597 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -99,6 +99,7 @@ 090 rw auto quick 091 rw auto 092 rw auto quick +094 rw auto quick 095 rw auto quick 097 rw auto backing 098 rw auto backing quick -- cgit v1.2.3 From af77f2cd7af1fa65a414c86767366bae95892e69 Mon Sep 17 00:00:00 2001 From: John Snow <jsnow@redhat.com> Date: Mon, 19 Jan 2015 15:15:49 -0500 Subject: libqos: Split apart pc_alloc_init Move the list-specific initialization over into malloc.c, to keep all of the list implementation details within the same file. The allocation and freeing of these structures are now both back within the same layer. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Message-id: 1421698563-6977-2-git-send-email-jsnow@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/libqos/malloc-pc.c | 20 ++++---------------- tests/libqos/malloc.c | 17 +++++++++++++++++ tests/libqos/malloc.h | 1 + 3 files changed, 22 insertions(+), 16 deletions(-) (limited to 'tests') diff --git a/tests/libqos/malloc-pc.c b/tests/libqos/malloc-pc.c index c9c48fddc9..36a0740f94 100644 --- a/tests/libqos/malloc-pc.c +++ b/tests/libqos/malloc-pc.c @@ -32,31 +32,19 @@ void pc_alloc_uninit(QGuestAllocator *allocator) QGuestAllocator *pc_alloc_init_flags(QAllocOpts flags) { - QGuestAllocator *s = g_malloc0(sizeof(*s)); + QGuestAllocator *s; uint64_t ram_size; QFWCFG *fw_cfg = pc_fw_cfg_init(); - MemBlock *node; - - s->opts = flags; - s->page_size = PAGE_SIZE; ram_size = qfw_cfg_get_u64(fw_cfg, FW_CFG_RAM_SIZE); + s = alloc_init(1 << 20, MIN(ram_size, 0xE0000000)); - /* Start at 1MB */ - s->start = 1 << 20; - - /* Respect PCI hole */ - s->end = MIN(ram_size, 0xE0000000); + s->opts = flags; + s->page_size = PAGE_SIZE; /* clean-up */ g_free(fw_cfg); - QTAILQ_INIT(&s->used); - QTAILQ_INIT(&s->free); - - node = mlist_new(s->start, s->end - s->start); - QTAILQ_INSERT_HEAD(&s->free, node, MLIST_ENTNAME); - return s; } diff --git a/tests/libqos/malloc.c b/tests/libqos/malloc.c index 5debf18497..0d34ecd4b6 100644 --- a/tests/libqos/malloc.c +++ b/tests/libqos/malloc.c @@ -268,3 +268,20 @@ void guest_free(QGuestAllocator *allocator, uint64_t addr) mlist_check(allocator); } } + +QGuestAllocator *alloc_init(uint64_t start, uint64_t end) +{ + QGuestAllocator *s = g_malloc0(sizeof(*s)); + MemBlock *node; + + s->start = start; + s->end = end; + + QTAILQ_INIT(&s->used); + QTAILQ_INIT(&s->free); + + node = mlist_new(s->start, s->end - s->start); + QTAILQ_INSERT_HEAD(&s->free, node, MLIST_ENTNAME); + + return s; +} diff --git a/tests/libqos/malloc.h b/tests/libqos/malloc.h index 465efeb8fb..677db7764b 100644 --- a/tests/libqos/malloc.h +++ b/tests/libqos/malloc.h @@ -50,4 +50,5 @@ void alloc_uninit(QGuestAllocator *allocator); uint64_t guest_alloc(QGuestAllocator *allocator, size_t size); void guest_free(QGuestAllocator *allocator, uint64_t addr); +QGuestAllocator *alloc_init(uint64_t start, uint64_t end); #endif -- cgit v1.2.3 From 90fc5e097534765f30b11e34cc00aa6c6629e3ea Mon Sep 17 00:00:00 2001 From: John Snow <jsnow@redhat.com> Date: Mon, 19 Jan 2015 15:15:50 -0500 Subject: qtest/ahci: Create ahci.h Extract defines and other information to ahci.h, to be shared with other tests if they so please. At the very least, reduce clutter in the test file itself. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Message-id: 1421698563-6977-3-git-send-email-jsnow@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/ahci-test.c | 319 +---------------------------------------------- tests/libqos/ahci.h | 352 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 353 insertions(+), 318 deletions(-) create mode 100644 tests/libqos/ahci.h (limited to 'tests') diff --git a/tests/ahci-test.c b/tests/ahci-test.c index b1a59f21a7..5c9da1283c 100644 --- a/tests/ahci-test.c +++ b/tests/ahci-test.c @@ -29,6 +29,7 @@ #include <glib.h> #include "libqtest.h" +#include "libqos/ahci.h" #include "libqos/pci-pc.h" #include "libqos/malloc-pc.h" @@ -41,313 +42,6 @@ /* Test-specific defines. */ #define TEST_IMAGE_SIZE (64 * 1024 * 1024) -/*** Supplementary PCI Config Space IDs & Masks ***/ -#define PCI_DEVICE_ID_INTEL_Q35_AHCI (0x2922) -#define PCI_MSI_FLAGS_RESERVED (0xFF00) -#define PCI_PM_CTRL_RESERVED (0xFC) -#define PCI_BCC(REG32) ((REG32) >> 24) -#define PCI_PI(REG32) (((REG32) >> 8) & 0xFF) -#define PCI_SCC(REG32) (((REG32) >> 16) & 0xFF) - -/*** Recognized AHCI Device Types ***/ -#define AHCI_INTEL_ICH9 (PCI_DEVICE_ID_INTEL_Q35_AHCI << 16 | \ - PCI_VENDOR_ID_INTEL) - -/*** AHCI/HBA Register Offsets and Bitmasks ***/ -#define AHCI_CAP (0) -#define AHCI_CAP_NP (0x1F) -#define AHCI_CAP_SXS (0x20) -#define AHCI_CAP_EMS (0x40) -#define AHCI_CAP_CCCS (0x80) -#define AHCI_CAP_NCS (0x1F00) -#define AHCI_CAP_PSC (0x2000) -#define AHCI_CAP_SSC (0x4000) -#define AHCI_CAP_PMD (0x8000) -#define AHCI_CAP_FBSS (0x10000) -#define AHCI_CAP_SPM (0x20000) -#define AHCI_CAP_SAM (0x40000) -#define AHCI_CAP_RESERVED (0x80000) -#define AHCI_CAP_ISS (0xF00000) -#define AHCI_CAP_SCLO (0x1000000) -#define AHCI_CAP_SAL (0x2000000) -#define AHCI_CAP_SALP (0x4000000) -#define AHCI_CAP_SSS (0x8000000) -#define AHCI_CAP_SMPS (0x10000000) -#define AHCI_CAP_SSNTF (0x20000000) -#define AHCI_CAP_SNCQ (0x40000000) -#define AHCI_CAP_S64A (0x80000000) - -#define AHCI_GHC (1) -#define AHCI_GHC_HR (0x01) -#define AHCI_GHC_IE (0x02) -#define AHCI_GHC_MRSM (0x04) -#define AHCI_GHC_RESERVED (0x7FFFFFF8) -#define AHCI_GHC_AE (0x80000000) - -#define AHCI_IS (2) -#define AHCI_PI (3) -#define AHCI_VS (4) - -#define AHCI_CCCCTL (5) -#define AHCI_CCCCTL_EN (0x01) -#define AHCI_CCCCTL_RESERVED (0x06) -#define AHCI_CCCCTL_CC (0xFF00) -#define AHCI_CCCCTL_TV (0xFFFF0000) - -#define AHCI_CCCPORTS (6) -#define AHCI_EMLOC (7) - -#define AHCI_EMCTL (8) -#define AHCI_EMCTL_STSMR (0x01) -#define AHCI_EMCTL_CTLTM (0x100) -#define AHCI_EMCTL_CTLRST (0x200) -#define AHCI_EMCTL_RESERVED (0xF0F0FCFE) - -#define AHCI_CAP2 (9) -#define AHCI_CAP2_BOH (0x01) -#define AHCI_CAP2_NVMP (0x02) -#define AHCI_CAP2_APST (0x04) -#define AHCI_CAP2_RESERVED (0xFFFFFFF8) - -#define AHCI_BOHC (10) -#define AHCI_RESERVED (11) -#define AHCI_NVMHCI (24) -#define AHCI_VENDOR (40) -#define AHCI_PORTS (64) - -/*** Port Memory Offsets & Bitmasks ***/ -#define AHCI_PX_CLB (0) -#define AHCI_PX_CLB_RESERVED (0x1FF) - -#define AHCI_PX_CLBU (1) - -#define AHCI_PX_FB (2) -#define AHCI_PX_FB_RESERVED (0xFF) - -#define AHCI_PX_FBU (3) - -#define AHCI_PX_IS (4) -#define AHCI_PX_IS_DHRS (0x1) -#define AHCI_PX_IS_PSS (0x2) -#define AHCI_PX_IS_DSS (0x4) -#define AHCI_PX_IS_SDBS (0x8) -#define AHCI_PX_IS_UFS (0x10) -#define AHCI_PX_IS_DPS (0x20) -#define AHCI_PX_IS_PCS (0x40) -#define AHCI_PX_IS_DMPS (0x80) -#define AHCI_PX_IS_RESERVED (0x23FFF00) -#define AHCI_PX_IS_PRCS (0x400000) -#define AHCI_PX_IS_IPMS (0x800000) -#define AHCI_PX_IS_OFS (0x1000000) -#define AHCI_PX_IS_INFS (0x4000000) -#define AHCI_PX_IS_IFS (0x8000000) -#define AHCI_PX_IS_HBDS (0x10000000) -#define AHCI_PX_IS_HBFS (0x20000000) -#define AHCI_PX_IS_TFES (0x40000000) -#define AHCI_PX_IS_CPDS (0x80000000) - -#define AHCI_PX_IE (5) -#define AHCI_PX_IE_DHRE (0x1) -#define AHCI_PX_IE_PSE (0x2) -#define AHCI_PX_IE_DSE (0x4) -#define AHCI_PX_IE_SDBE (0x8) -#define AHCI_PX_IE_UFE (0x10) -#define AHCI_PX_IE_DPE (0x20) -#define AHCI_PX_IE_PCE (0x40) -#define AHCI_PX_IE_DMPE (0x80) -#define AHCI_PX_IE_RESERVED (0x23FFF00) -#define AHCI_PX_IE_PRCE (0x400000) -#define AHCI_PX_IE_IPME (0x800000) -#define AHCI_PX_IE_OFE (0x1000000) -#define AHCI_PX_IE_INFE (0x4000000) -#define AHCI_PX_IE_IFE (0x8000000) -#define AHCI_PX_IE_HBDE (0x10000000) -#define AHCI_PX_IE_HBFE (0x20000000) -#define AHCI_PX_IE_TFEE (0x40000000) -#define AHCI_PX_IE_CPDE (0x80000000) - -#define AHCI_PX_CMD (6) -#define AHCI_PX_CMD_ST (0x1) -#define AHCI_PX_CMD_SUD (0x2) -#define AHCI_PX_CMD_POD (0x4) -#define AHCI_PX_CMD_CLO (0x8) -#define AHCI_PX_CMD_FRE (0x10) -#define AHCI_PX_CMD_RESERVED (0xE0) -#define AHCI_PX_CMD_CCS (0x1F00) -#define AHCI_PX_CMD_MPSS (0x2000) -#define AHCI_PX_CMD_FR (0x4000) -#define AHCI_PX_CMD_CR (0x8000) -#define AHCI_PX_CMD_CPS (0x10000) -#define AHCI_PX_CMD_PMA (0x20000) -#define AHCI_PX_CMD_HPCP (0x40000) -#define AHCI_PX_CMD_MPSP (0x80000) -#define AHCI_PX_CMD_CPD (0x100000) -#define AHCI_PX_CMD_ESP (0x200000) -#define AHCI_PX_CMD_FBSCP (0x400000) -#define AHCI_PX_CMD_APSTE (0x800000) -#define AHCI_PX_CMD_ATAPI (0x1000000) -#define AHCI_PX_CMD_DLAE (0x2000000) -#define AHCI_PX_CMD_ALPE (0x4000000) -#define AHCI_PX_CMD_ASP (0x8000000) -#define AHCI_PX_CMD_ICC (0xF0000000) - -#define AHCI_PX_RES1 (7) - -#define AHCI_PX_TFD (8) -#define AHCI_PX_TFD_STS (0xFF) -#define AHCI_PX_TFD_STS_ERR (0x01) -#define AHCI_PX_TFD_STS_CS1 (0x06) -#define AHCI_PX_TFD_STS_DRQ (0x08) -#define AHCI_PX_TFD_STS_CS2 (0x70) -#define AHCI_PX_TFD_STS_BSY (0x80) -#define AHCI_PX_TFD_ERR (0xFF00) -#define AHCI_PX_TFD_RESERVED (0xFFFF0000) - -#define AHCI_PX_SIG (9) -#define AHCI_PX_SIG_SECTOR_COUNT (0xFF) -#define AHCI_PX_SIG_LBA_LOW (0xFF00) -#define AHCI_PX_SIG_LBA_MID (0xFF0000) -#define AHCI_PX_SIG_LBA_HIGH (0xFF000000) - -#define AHCI_PX_SSTS (10) -#define AHCI_PX_SSTS_DET (0x0F) -#define AHCI_PX_SSTS_SPD (0xF0) -#define AHCI_PX_SSTS_IPM (0xF00) -#define AHCI_PX_SSTS_RESERVED (0xFFFFF000) -#define SSTS_DET_NO_DEVICE (0x00) -#define SSTS_DET_PRESENT (0x01) -#define SSTS_DET_ESTABLISHED (0x03) -#define SSTS_DET_OFFLINE (0x04) - -#define AHCI_PX_SCTL (11) - -#define AHCI_PX_SERR (12) -#define AHCI_PX_SERR_ERR (0xFFFF) -#define AHCI_PX_SERR_DIAG (0xFFFF0000) -#define AHCI_PX_SERR_DIAG_X (0x04000000) - -#define AHCI_PX_SACT (13) -#define AHCI_PX_CI (14) -#define AHCI_PX_SNTF (15) - -#define AHCI_PX_FBS (16) -#define AHCI_PX_FBS_EN (0x1) -#define AHCI_PX_FBS_DEC (0x2) -#define AHCI_PX_FBS_SDE (0x4) -#define AHCI_PX_FBS_DEV (0xF00) -#define AHCI_PX_FBS_ADO (0xF000) -#define AHCI_PX_FBS_DWE (0xF0000) -#define AHCI_PX_FBS_RESERVED (0xFFF000F8) - -#define AHCI_PX_RES2 (17) -#define AHCI_PX_VS (28) - -#define HBA_DATA_REGION_SIZE (256) -#define HBA_PORT_DATA_SIZE (128) -#define HBA_PORT_NUM_REG (HBA_PORT_DATA_SIZE/4) - -#define AHCI_VERSION_0_95 (0x00000905) -#define AHCI_VERSION_1_0 (0x00010000) -#define AHCI_VERSION_1_1 (0x00010100) -#define AHCI_VERSION_1_2 (0x00010200) -#define AHCI_VERSION_1_3 (0x00010300) - -/*** Structures ***/ - -/** - * Generic FIS structure. - */ -typedef struct FIS { - uint8_t fis_type; - uint8_t flags; - char data[0]; -} __attribute__((__packed__)) FIS; - -/** - * Register device-to-host FIS structure. - */ -typedef struct RegD2HFIS { - /* DW0 */ - uint8_t fis_type; - uint8_t flags; - uint8_t status; - uint8_t error; - /* DW1 */ - uint8_t lba_low; - uint8_t lba_mid; - uint8_t lba_high; - uint8_t device; - /* DW2 */ - uint8_t lba3; - uint8_t lba4; - uint8_t lba5; - uint8_t res1; - /* DW3 */ - uint16_t count; - uint8_t res2; - uint8_t res3; - /* DW4 */ - uint16_t res4; - uint16_t res5; -} __attribute__((__packed__)) RegD2HFIS; - -/** - * Register host-to-device FIS structure. - */ -typedef struct RegH2DFIS { - /* DW0 */ - uint8_t fis_type; - uint8_t flags; - uint8_t command; - uint8_t feature_low; - /* DW1 */ - uint8_t lba_low; - uint8_t lba_mid; - uint8_t lba_high; - uint8_t device; - /* DW2 */ - uint8_t lba3; - uint8_t lba4; - uint8_t lba5; - uint8_t feature_high; - /* DW3 */ - uint16_t count; - uint8_t icc; - uint8_t control; - /* DW4 */ - uint32_t aux; -} __attribute__((__packed__)) RegH2DFIS; - -/** - * Command List entry structure. - * The command list contains between 1-32 of these structures. - */ -typedef struct AHCICommand { - uint8_t b1; - uint8_t b2; - uint16_t prdtl; /* Phys Region Desc. Table Length */ - uint32_t prdbc; /* Phys Region Desc. Byte Count */ - uint32_t ctba; /* Command Table Descriptor Base Address */ - uint32_t ctbau; /* '' Upper */ - uint32_t res[4]; -} __attribute__((__packed__)) AHCICommand; - -/** - * Physical Region Descriptor; pointed to by the Command List Header, - * struct ahci_command. - */ -typedef struct PRD { - uint32_t dba; /* Data Base Address */ - uint32_t dbau; /* Data Base Address Upper */ - uint32_t res; /* Reserved */ - uint32_t dbc; /* Data Byte Count (0-indexed) & Interrupt Flag (bit 2^31) */ -} PRD; - -typedef struct HBACap { - uint32_t cap; - uint32_t cap2; -} HBACap; - /*** Globals ***/ static QGuestAllocator *guest_malloc; static QPCIBus *pcibus; @@ -356,13 +50,6 @@ static char tmp_path[] = "/tmp/qtest.XXXXXX"; static bool ahci_pedantic; static uint32_t ahci_fingerprint; -/*** Macro Utilities ***/ -#define BITANY(data, mask) (((data) & (mask)) != 0) -#define BITSET(data, mask) (((data) & (mask)) == (mask)) -#define BITCLR(data, mask) (((data) & (mask)) == 0) -#define ASSERT_BIT_SET(data, mask) g_assert_cmphex((data) & (mask), ==, (mask)) -#define ASSERT_BIT_CLEAR(data, mask) g_assert_cmphex((data) & (mask), ==, 0) - /*** IO macros for the AHCI memory registers. ***/ #define AHCI_READ(OFST) qpci_io_readl(ahci, hba_base + (OFST)) #define AHCI_WRITE(OFST, VAL) qpci_io_writel(ahci, hba_base + (OFST), (VAL)) @@ -380,10 +67,6 @@ static uint32_t ahci_fingerprint; #define PX_CLR(port, reg, mask) PX_WREG((port), (reg), \ PX_RREG((port), (reg)) & ~(mask)); -/* For calculating how big the PRD table needs to be: */ -#define CMD_TBL_SIZ(n) ((0x80 + ((n) * sizeof(PRD)) + 0x7F) & ~0x7F) - - /*** Function Declarations ***/ static QPCIDevice *get_ahci_device(void); static QPCIDevice *start_ahci_device(QPCIDevice *dev, void **hba_base); diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h new file mode 100644 index 0000000000..6564c5a4e1 --- /dev/null +++ b/tests/libqos/ahci.h @@ -0,0 +1,352 @@ +#ifndef __libqos_ahci_h +#define __libqos_ahci_h + +/* + * AHCI qtest library functions and definitions + * + * Copyright (c) 2014 John Snow <jsnow@redhat.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <stdint.h> +#include <stdlib.h> +#include <stdbool.h> + +#include "libqos/pci.h" +#include "libqos/malloc-pc.h" + +/*** Supplementary PCI Config Space IDs & Masks ***/ +#define PCI_DEVICE_ID_INTEL_Q35_AHCI (0x2922) +#define PCI_MSI_FLAGS_RESERVED (0xFF00) +#define PCI_PM_CTRL_RESERVED (0xFC) +#define PCI_BCC(REG32) ((REG32) >> 24) +#define PCI_PI(REG32) (((REG32) >> 8) & 0xFF) +#define PCI_SCC(REG32) (((REG32) >> 16) & 0xFF) + +/*** Recognized AHCI Device Types ***/ +#define AHCI_INTEL_ICH9 (PCI_DEVICE_ID_INTEL_Q35_AHCI << 16 | \ + PCI_VENDOR_ID_INTEL) + +/*** AHCI/HBA Register Offsets and Bitmasks ***/ +#define AHCI_CAP (0) +#define AHCI_CAP_NP (0x1F) +#define AHCI_CAP_SXS (0x20) +#define AHCI_CAP_EMS (0x40) +#define AHCI_CAP_CCCS (0x80) +#define AHCI_CAP_NCS (0x1F00) +#define AHCI_CAP_PSC (0x2000) +#define AHCI_CAP_SSC (0x4000) +#define AHCI_CAP_PMD (0x8000) +#define AHCI_CAP_FBSS (0x10000) +#define AHCI_CAP_SPM (0x20000) +#define AHCI_CAP_SAM (0x40000) +#define AHCI_CAP_RESERVED (0x80000) +#define AHCI_CAP_ISS (0xF00000) +#define AHCI_CAP_SCLO (0x1000000) +#define AHCI_CAP_SAL (0x2000000) +#define AHCI_CAP_SALP (0x4000000) +#define AHCI_CAP_SSS (0x8000000) +#define AHCI_CAP_SMPS (0x10000000) +#define AHCI_CAP_SSNTF (0x20000000) +#define AHCI_CAP_SNCQ (0x40000000) +#define AHCI_CAP_S64A (0x80000000) + +#define AHCI_GHC (1) +#define AHCI_GHC_HR (0x01) +#define AHCI_GHC_IE (0x02) +#define AHCI_GHC_MRSM (0x04) +#define AHCI_GHC_RESERVED (0x7FFFFFF8) +#define AHCI_GHC_AE (0x80000000) + +#define AHCI_IS (2) +#define AHCI_PI (3) +#define AHCI_VS (4) + +#define AHCI_CCCCTL (5) +#define AHCI_CCCCTL_EN (0x01) +#define AHCI_CCCCTL_RESERVED (0x06) +#define AHCI_CCCCTL_CC (0xFF00) +#define AHCI_CCCCTL_TV (0xFFFF0000) + +#define AHCI_CCCPORTS (6) +#define AHCI_EMLOC (7) + +#define AHCI_EMCTL (8) +#define AHCI_EMCTL_STSMR (0x01) +#define AHCI_EMCTL_CTLTM (0x100) +#define AHCI_EMCTL_CTLRST (0x200) +#define AHCI_EMCTL_RESERVED (0xF0F0FCFE) + +#define AHCI_CAP2 (9) +#define AHCI_CAP2_BOH (0x01) +#define AHCI_CAP2_NVMP (0x02) +#define AHCI_CAP2_APST (0x04) +#define AHCI_CAP2_RESERVED (0xFFFFFFF8) + +#define AHCI_BOHC (10) +#define AHCI_RESERVED (11) +#define AHCI_NVMHCI (24) +#define AHCI_VENDOR (40) +#define AHCI_PORTS (64) + +/*** Port Memory Offsets & Bitmasks ***/ +#define AHCI_PX_CLB (0) +#define AHCI_PX_CLB_RESERVED (0x1FF) + +#define AHCI_PX_CLBU (1) + +#define AHCI_PX_FB (2) +#define AHCI_PX_FB_RESERVED (0xFF) + +#define AHCI_PX_FBU (3) + +#define AHCI_PX_IS (4) +#define AHCI_PX_IS_DHRS (0x1) +#define AHCI_PX_IS_PSS (0x2) +#define AHCI_PX_IS_DSS (0x4) +#define AHCI_PX_IS_SDBS (0x8) +#define AHCI_PX_IS_UFS (0x10) +#define AHCI_PX_IS_DPS (0x20) +#define AHCI_PX_IS_PCS (0x40) +#define AHCI_PX_IS_DMPS (0x80) +#define AHCI_PX_IS_RESERVED (0x23FFF00) +#define AHCI_PX_IS_PRCS (0x400000) +#define AHCI_PX_IS_IPMS (0x800000) +#define AHCI_PX_IS_OFS (0x1000000) +#define AHCI_PX_IS_INFS (0x4000000) +#define AHCI_PX_IS_IFS (0x8000000) +#define AHCI_PX_IS_HBDS (0x10000000) +#define AHCI_PX_IS_HBFS (0x20000000) +#define AHCI_PX_IS_TFES (0x40000000) +#define AHCI_PX_IS_CPDS (0x80000000) + +#define AHCI_PX_IE (5) +#define AHCI_PX_IE_DHRE (0x1) +#define AHCI_PX_IE_PSE (0x2) +#define AHCI_PX_IE_DSE (0x4) +#define AHCI_PX_IE_SDBE (0x8) +#define AHCI_PX_IE_UFE (0x10) +#define AHCI_PX_IE_DPE (0x20) +#define AHCI_PX_IE_PCE (0x40) +#define AHCI_PX_IE_DMPE (0x80) +#define AHCI_PX_IE_RESERVED (0x23FFF00) +#define AHCI_PX_IE_PRCE (0x400000) +#define AHCI_PX_IE_IPME (0x800000) +#define AHCI_PX_IE_OFE (0x1000000) +#define AHCI_PX_IE_INFE (0x4000000) +#define AHCI_PX_IE_IFE (0x8000000) +#define AHCI_PX_IE_HBDE (0x10000000) +#define AHCI_PX_IE_HBFE (0x20000000) +#define AHCI_PX_IE_TFEE (0x40000000) +#define AHCI_PX_IE_CPDE (0x80000000) + +#define AHCI_PX_CMD (6) +#define AHCI_PX_CMD_ST (0x1) +#define AHCI_PX_CMD_SUD (0x2) +#define AHCI_PX_CMD_POD (0x4) +#define AHCI_PX_CMD_CLO (0x8) +#define AHCI_PX_CMD_FRE (0x10) +#define AHCI_PX_CMD_RESERVED (0xE0) +#define AHCI_PX_CMD_CCS (0x1F00) +#define AHCI_PX_CMD_MPSS (0x2000) +#define AHCI_PX_CMD_FR (0x4000) +#define AHCI_PX_CMD_CR (0x8000) +#define AHCI_PX_CMD_CPS (0x10000) +#define AHCI_PX_CMD_PMA (0x20000) +#define AHCI_PX_CMD_HPCP (0x40000) +#define AHCI_PX_CMD_MPSP (0x80000) +#define AHCI_PX_CMD_CPD (0x100000) +#define AHCI_PX_CMD_ESP (0x200000) +#define AHCI_PX_CMD_FBSCP (0x400000) +#define AHCI_PX_CMD_APSTE (0x800000) +#define AHCI_PX_CMD_ATAPI (0x1000000) +#define AHCI_PX_CMD_DLAE (0x2000000) +#define AHCI_PX_CMD_ALPE (0x4000000) +#define AHCI_PX_CMD_ASP (0x8000000) +#define AHCI_PX_CMD_ICC (0xF0000000) + +#define AHCI_PX_RES1 (7) + +#define AHCI_PX_TFD (8) +#define AHCI_PX_TFD_STS (0xFF) +#define AHCI_PX_TFD_STS_ERR (0x01) +#define AHCI_PX_TFD_STS_CS1 (0x06) +#define AHCI_PX_TFD_STS_DRQ (0x08) +#define AHCI_PX_TFD_STS_CS2 (0x70) +#define AHCI_PX_TFD_STS_BSY (0x80) +#define AHCI_PX_TFD_ERR (0xFF00) +#define AHCI_PX_TFD_RESERVED (0xFFFF0000) + +#define AHCI_PX_SIG (9) +#define AHCI_PX_SIG_SECTOR_COUNT (0xFF) +#define AHCI_PX_SIG_LBA_LOW (0xFF00) +#define AHCI_PX_SIG_LBA_MID (0xFF0000) +#define AHCI_PX_SIG_LBA_HIGH (0xFF000000) + +#define AHCI_PX_SSTS (10) +#define AHCI_PX_SSTS_DET (0x0F) +#define AHCI_PX_SSTS_SPD (0xF0) +#define AHCI_PX_SSTS_IPM (0xF00) +#define AHCI_PX_SSTS_RESERVED (0xFFFFF000) +#define SSTS_DET_NO_DEVICE (0x00) +#define SSTS_DET_PRESENT (0x01) +#define SSTS_DET_ESTABLISHED (0x03) +#define SSTS_DET_OFFLINE (0x04) + +#define AHCI_PX_SCTL (11) + +#define AHCI_PX_SERR (12) +#define AHCI_PX_SERR_ERR (0xFFFF) +#define AHCI_PX_SERR_DIAG (0xFFFF0000) +#define AHCI_PX_SERR_DIAG_X (0x04000000) + +#define AHCI_PX_SACT (13) +#define AHCI_PX_CI (14) +#define AHCI_PX_SNTF (15) + +#define AHCI_PX_FBS (16) +#define AHCI_PX_FBS_EN (0x1) +#define AHCI_PX_FBS_DEC (0x2) +#define AHCI_PX_FBS_SDE (0x4) +#define AHCI_PX_FBS_DEV (0xF00) +#define AHCI_PX_FBS_ADO (0xF000) +#define AHCI_PX_FBS_DWE (0xF0000) +#define AHCI_PX_FBS_RESERVED (0xFFF000F8) + +#define AHCI_PX_RES2 (17) +#define AHCI_PX_VS (28) + +#define HBA_DATA_REGION_SIZE (256) +#define HBA_PORT_DATA_SIZE (128) +#define HBA_PORT_NUM_REG (HBA_PORT_DATA_SIZE/4) + +#define AHCI_VERSION_0_95 (0x00000905) +#define AHCI_VERSION_1_0 (0x00010000) +#define AHCI_VERSION_1_1 (0x00010100) +#define AHCI_VERSION_1_2 (0x00010200) +#define AHCI_VERSION_1_3 (0x00010300) + +/*** Structures ***/ + +/** + * Generic FIS structure. + */ +typedef struct FIS { + uint8_t fis_type; + uint8_t flags; + char data[0]; +} __attribute__((__packed__)) FIS; + +/** + * Register device-to-host FIS structure. + */ +typedef struct RegD2HFIS { + /* DW0 */ + uint8_t fis_type; + uint8_t flags; + uint8_t status; + uint8_t error; + /* DW1 */ + uint8_t lba_low; + uint8_t lba_mid; + uint8_t lba_high; + uint8_t device; + /* DW2 */ + uint8_t lba3; + uint8_t lba4; + uint8_t lba5; + uint8_t res1; + /* DW3 */ + uint16_t count; + uint8_t res2; + uint8_t res3; + /* DW4 */ + uint16_t res4; + uint16_t res5; +} __attribute__((__packed__)) RegD2HFIS; + +/** + * Register host-to-device FIS structure. + */ +typedef struct RegH2DFIS { + /* DW0 */ + uint8_t fis_type; + uint8_t flags; + uint8_t command; + uint8_t feature_low; + /* DW1 */ + uint8_t lba_low; + uint8_t lba_mid; + uint8_t lba_high; + uint8_t device; + /* DW2 */ + uint8_t lba3; + uint8_t lba4; + uint8_t lba5; + uint8_t feature_high; + /* DW3 */ + uint16_t count; + uint8_t icc; + uint8_t control; + /* DW4 */ + uint32_t aux; +} __attribute__((__packed__)) RegH2DFIS; + +/** + * Command List entry structure. + * The command list contains between 1-32 of these structures. + */ +typedef struct AHCICommand { + uint8_t b1; + uint8_t b2; + uint16_t prdtl; /* Phys Region Desc. Table Length */ + uint32_t prdbc; /* Phys Region Desc. Byte Count */ + uint32_t ctba; /* Command Table Descriptor Base Address */ + uint32_t ctbau; /* '' Upper */ + uint32_t res[4]; +} __attribute__((__packed__)) AHCICommand; + +/** + * Physical Region Descriptor; pointed to by the Command List Header, + * struct ahci_command. + */ +typedef struct PRD { + uint32_t dba; /* Data Base Address */ + uint32_t dbau; /* Data Base Address Upper */ + uint32_t res; /* Reserved */ + uint32_t dbc; /* Data Byte Count (0-indexed) & Interrupt Flag (bit 2^31) */ +} PRD; + +typedef struct HBACap { + uint32_t cap; + uint32_t cap2; +} HBACap; + +/*** Macro Utilities ***/ +#define BITANY(data, mask) (((data) & (mask)) != 0) +#define BITSET(data, mask) (((data) & (mask)) == (mask)) +#define BITCLR(data, mask) (((data) & (mask)) == 0) +#define ASSERT_BIT_SET(data, mask) g_assert_cmphex((data) & (mask), ==, (mask)) +#define ASSERT_BIT_CLEAR(data, mask) g_assert_cmphex((data) & (mask), ==, 0) + +/* For calculating how big the PRD table needs to be: */ +#define CMD_TBL_SIZ(n) ((0x80 + ((n) * sizeof(PRD)) + 0x7F) & ~0x7F) + +#endif -- cgit v1.2.3 From dd0029c0f44d5121c64a02d3aa0440283fb72fcd Mon Sep 17 00:00:00 2001 From: John Snow <jsnow@redhat.com> Date: Mon, 19 Jan 2015 15:15:51 -0500 Subject: libqos: create libqos.c The intent of this file is to serve as a misc. utilities file to be shared amongst tests that are utilizing libqos facilities. In a later patch, migration test helpers will be added to libqos.c that will allow simplified testing of migration cases where libqos is "Just Enough OS" for migrations testing. The addition of the AHCIQState structure will also allow us to eliminate global variables inside of qtests to manage allocators and test instances in a better, more functional way. libqos.c: - Add qtest_boot - Add qtest_shutdown libqos.h: - Create QOSState structure for allocator and QTestState. ahci-test.c: - Move qtest_boot and qtest_shutdown to libqos.c/h - Create AHCIQState to interface with new qtest_boot/shutdown prototypes - Modify tests slightly to use new types. For now, the new object file is only linked to ahci-test, because it still relies on pc architecture specific code in libqos. The next two patches will reorganize the code to be more general. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Message-id: 1421698563-6977-4-git-send-email-jsnow@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/Makefile | 2 +- tests/ahci-test.c | 91 +++++++++++++++++++++------------------------------ tests/libqos/ahci.h | 5 +++ tests/libqos/libqos.c | 48 +++++++++++++++++++++++++++ tests/libqos/libqos.h | 26 +++++++++++++++ 5 files changed, 117 insertions(+), 55 deletions(-) create mode 100644 tests/libqos/libqos.c create mode 100644 tests/libqos/libqos.h (limited to 'tests') diff --git a/tests/Makefile b/tests/Makefile index d5df16882d..0469bbd5af 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -320,7 +320,7 @@ tests/endianness-test$(EXESUF): tests/endianness-test.o tests/spapr-phb-test$(EXESUF): tests/spapr-phb-test.o $(libqos-obj-y) tests/fdc-test$(EXESUF): tests/fdc-test.o tests/ide-test$(EXESUF): tests/ide-test.o $(libqos-pc-obj-y) -tests/ahci-test$(EXESUF): tests/ahci-test.o $(libqos-pc-obj-y) +tests/ahci-test$(EXESUF): tests/ahci-test.o $(libqos-pc-obj-y) tests/libqos/libqos.o tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o tests/boot-order-test$(EXESUF): tests/boot-order-test.o $(libqos-obj-y) tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o $(libqos-obj-y) diff --git a/tests/ahci-test.c b/tests/ahci-test.c index 5c9da1283c..15542b9a78 100644 --- a/tests/ahci-test.c +++ b/tests/ahci-test.c @@ -29,6 +29,7 @@ #include <glib.h> #include "libqtest.h" +#include "libqos/libqos.h" #include "libqos/ahci.h" #include "libqos/pci-pc.h" #include "libqos/malloc-pc.h" @@ -136,58 +137,40 @@ static void free_ahci_device(QPCIDevice *ahci) /*** Test Setup & Teardown ***/ /** - * Launch QEMU with the given command line, - * and then set up interrupts and our guest malloc interface. + * Start a Q35 machine and bookmark a handle to the AHCI device. */ -static void qtest_boot(const char *cmdline_fmt, ...) +static AHCIQState *ahci_boot(void) { - va_list ap; - char *cmdline; - - va_start(ap, cmdline_fmt); - cmdline = g_strdup_vprintf(cmdline_fmt, ap); - va_end(ap); + AHCIQState *s; + const char *cli; - qtest_start(cmdline); - qtest_irq_intercept_in(global_qtest, "ioapic"); - guest_malloc = pc_alloc_init(); + s = g_malloc0(sizeof(AHCIQState)); - g_free(cmdline); -} + cli = "-drive if=none,id=drive0,file=%s,cache=writeback,serial=%s" + ",format=raw" + " -M q35 " + "-device ide-hd,drive=drive0 " + "-global ide-hd.ver=%s"; + s->parent = qtest_boot(cli, tmp_path, "testdisk", "version"); -/** - * Tear down the QEMU instance. - */ -static void qtest_shutdown(void) -{ - g_free(guest_malloc); - guest_malloc = NULL; - qtest_end(); -} + /* Verify that we have an AHCI device present. */ + s->dev = get_ahci_device(); -/** - * Start a Q35 machine and bookmark a handle to the AHCI device. - */ -static QPCIDevice *ahci_boot(void) -{ - qtest_boot("-drive if=none,id=drive0,file=%s,cache=writeback,serial=%s," - "format=raw" - " -M q35 " - "-device ide-hd,drive=drive0 " - "-global ide-hd.ver=%s", - tmp_path, "testdisk", "version"); + /* Stopgap: Copy the allocator reference */ + guest_malloc = s->parent->alloc; - /* Verify that we have an AHCI device present. */ - return get_ahci_device(); + return s; } /** * Clean up the PCI device, then terminate the QEMU instance. */ -static void ahci_shutdown(QPCIDevice *ahci) +static void ahci_shutdown(AHCIQState *ahci) { - free_ahci_device(ahci); - qtest_shutdown(); + QOSState *qs = ahci->parent; + free_ahci_device(ahci->dev); + g_free(ahci); + qtest_shutdown(qs); } /*** Logical Device Initialization ***/ @@ -1104,7 +1087,7 @@ static void ahci_test_identify(QPCIDevice *ahci, void *hba_base) */ static void test_sanity(void) { - QPCIDevice *ahci; + AHCIQState *ahci; ahci = ahci_boot(); ahci_shutdown(ahci); } @@ -1115,9 +1098,9 @@ static void test_sanity(void) */ static void test_pci_spec(void) { - QPCIDevice *ahci; + AHCIQState *ahci; ahci = ahci_boot(); - ahci_test_pci_spec(ahci); + ahci_test_pci_spec(ahci->dev); ahci_shutdown(ahci); } @@ -1127,10 +1110,10 @@ static void test_pci_spec(void) */ static void test_pci_enable(void) { - QPCIDevice *ahci; + AHCIQState *ahci; void *hba_base; ahci = ahci_boot(); - ahci_pci_enable(ahci, &hba_base); + ahci_pci_enable(ahci->dev, &hba_base); ahci_shutdown(ahci); } @@ -1140,12 +1123,12 @@ static void test_pci_enable(void) */ static void test_hba_spec(void) { - QPCIDevice *ahci; + AHCIQState *ahci; void *hba_base; ahci = ahci_boot(); - ahci_pci_enable(ahci, &hba_base); - ahci_test_hba_spec(ahci, hba_base); + ahci_pci_enable(ahci->dev, &hba_base); + ahci_test_hba_spec(ahci->dev, hba_base); ahci_shutdown(ahci); } @@ -1155,12 +1138,12 @@ static void test_hba_spec(void) */ static void test_hba_enable(void) { - QPCIDevice *ahci; + AHCIQState *ahci; void *hba_base; ahci = ahci_boot(); - ahci_pci_enable(ahci, &hba_base); - ahci_hba_enable(ahci, hba_base); + ahci_pci_enable(ahci->dev, &hba_base); + ahci_hba_enable(ahci->dev, hba_base); ahci_shutdown(ahci); } @@ -1170,13 +1153,13 @@ static void test_hba_enable(void) */ static void test_identify(void) { - QPCIDevice *ahci; + AHCIQState *ahci; void *hba_base; ahci = ahci_boot(); - ahci_pci_enable(ahci, &hba_base); - ahci_hba_enable(ahci, hba_base); - ahci_test_identify(ahci, hba_base); + ahci_pci_enable(ahci->dev, &hba_base); + ahci_hba_enable(ahci->dev, hba_base); + ahci_test_identify(ahci->dev, hba_base); ahci_shutdown(ahci); } diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h index 6564c5a4e1..bc5f45d77e 100644 --- a/tests/libqos/ahci.h +++ b/tests/libqos/ahci.h @@ -245,6 +245,11 @@ /*** Structures ***/ +typedef struct AHCIQState { + QOSState *parent; + QPCIDevice *dev; +} AHCIQState; + /** * Generic FIS structure. */ diff --git a/tests/libqos/libqos.c b/tests/libqos/libqos.c new file mode 100644 index 0000000000..c478bc958c --- /dev/null +++ b/tests/libqos/libqos.c @@ -0,0 +1,48 @@ +#include <stdio.h> +#include <stdlib.h> +#include <glib.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/wait.h> + +#include "libqtest.h" +#include "libqos/libqos.h" +#include "libqos/pci.h" +#include "libqos/malloc-pc.h" + +/*** Test Setup & Teardown ***/ + +/** + * Launch QEMU with the given command line, + * and then set up interrupts and our guest malloc interface. + */ +QOSState *qtest_boot(const char *cmdline_fmt, ...) +{ + QOSState *qs = g_malloc(sizeof(QOSState)); + char *cmdline; + va_list ap; + + va_start(ap, cmdline_fmt); + cmdline = g_strdup_vprintf(cmdline_fmt, ap); + va_end(ap); + + qs->qts = qtest_start(cmdline); + qtest_irq_intercept_in(global_qtest, "ioapic"); + qs->alloc = pc_alloc_init(); + + g_free(cmdline); + return qs; +} + +/** + * Tear down the QEMU instance. + */ +void qtest_shutdown(QOSState *qs) +{ + if (qs->alloc) { + pc_alloc_uninit(qs->alloc); + qs->alloc = NULL; + } + qtest_quit(qs->qts); + g_free(qs); +} diff --git a/tests/libqos/libqos.h b/tests/libqos/libqos.h new file mode 100644 index 0000000000..7a106f24e9 --- /dev/null +++ b/tests/libqos/libqos.h @@ -0,0 +1,26 @@ +#ifndef __libqos_h +#define __libqos_h + +#include "libqtest.h" +#include "libqos/pci.h" +#include "libqos/malloc-pc.h" + +typedef struct QOSState { + QTestState *qts; + QGuestAllocator *alloc; +} QOSState; + +QOSState *qtest_boot(const char *cmdline_fmt, ...); +void qtest_shutdown(QOSState *qs); + +static inline uint64_t qmalloc(QOSState *q, size_t bytes) +{ + return guest_alloc(q->alloc, bytes); +} + +static inline void qfree(QOSState *q, uint64_t addr) +{ + guest_free(q->alloc, addr); +} + +#endif -- cgit v1.2.3 From f1518d1192a1a9387f881919897fbb0101ad3426 Mon Sep 17 00:00:00 2001 From: John Snow <jsnow@redhat.com> Date: Mon, 19 Jan 2015 15:15:52 -0500 Subject: libqos: add qtest_vboot Add a va_list variant of the qtest_boot function. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Message-id: 1421698563-6977-5-git-send-email-jsnow@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/libqos/libqos.c | 25 +++++++++++++++++++------ tests/libqos/libqos.h | 1 + 2 files changed, 20 insertions(+), 6 deletions(-) (limited to 'tests') diff --git a/tests/libqos/libqos.c b/tests/libqos/libqos.c index c478bc958c..c8b3ef044b 100644 --- a/tests/libqos/libqos.c +++ b/tests/libqos/libqos.c @@ -16,16 +16,13 @@ * Launch QEMU with the given command line, * and then set up interrupts and our guest malloc interface. */ -QOSState *qtest_boot(const char *cmdline_fmt, ...) +QOSState *qtest_vboot(const char *cmdline_fmt, va_list ap) { - QOSState *qs = g_malloc(sizeof(QOSState)); char *cmdline; - va_list ap; - va_start(ap, cmdline_fmt); - cmdline = g_strdup_vprintf(cmdline_fmt, ap); - va_end(ap); + struct QOSState *qs = g_malloc(sizeof(QOSState)); + cmdline = g_strdup_vprintf(cmdline_fmt, ap); qs->qts = qtest_start(cmdline); qtest_irq_intercept_in(global_qtest, "ioapic"); qs->alloc = pc_alloc_init(); @@ -34,6 +31,22 @@ QOSState *qtest_boot(const char *cmdline_fmt, ...) return qs; } +/** + * Launch QEMU with the given command line, + * and then set up interrupts and our guest malloc interface. + */ +QOSState *qtest_boot(const char *cmdline_fmt, ...) +{ + QOSState *qs; + va_list ap; + + va_start(ap, cmdline_fmt); + qs = qtest_vboot(cmdline_fmt, ap); + va_end(ap); + + return qs; +} + /** * Tear down the QEMU instance. */ diff --git a/tests/libqos/libqos.h b/tests/libqos/libqos.h index 7a106f24e9..7ae0a8d600 100644 --- a/tests/libqos/libqos.h +++ b/tests/libqos/libqos.h @@ -10,6 +10,7 @@ typedef struct QOSState { QGuestAllocator *alloc; } QOSState; +QOSState *qtest_vboot(const char *cmdline_fmt, va_list ap); QOSState *qtest_boot(const char *cmdline_fmt, ...); void qtest_shutdown(QOSState *qs); -- cgit v1.2.3 From fa02e6084f727191e15fc6b2d1328c4fae874741 Mon Sep 17 00:00:00 2001 From: John Snow <jsnow@redhat.com> Date: Mon, 19 Jan 2015 15:15:53 -0500 Subject: libqos: add alloc_init_flags Allow a generic interface to alloc_init_flags, not just through pc_alloc_init_flags. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Message-id: 1421698563-6977-6-git-send-email-jsnow@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/libqos/malloc-pc.c | 4 +--- tests/libqos/malloc.c | 8 ++++++++ tests/libqos/malloc.h | 2 ++ 3 files changed, 11 insertions(+), 3 deletions(-) (limited to 'tests') diff --git a/tests/libqos/malloc-pc.c b/tests/libqos/malloc-pc.c index 36a0740f94..6a5fdf360a 100644 --- a/tests/libqos/malloc-pc.c +++ b/tests/libqos/malloc-pc.c @@ -37,9 +37,7 @@ QGuestAllocator *pc_alloc_init_flags(QAllocOpts flags) QFWCFG *fw_cfg = pc_fw_cfg_init(); ram_size = qfw_cfg_get_u64(fw_cfg, FW_CFG_RAM_SIZE); - s = alloc_init(1 << 20, MIN(ram_size, 0xE0000000)); - - s->opts = flags; + s = alloc_init_flags(flags, 1 << 20, MIN(ram_size, 0xE0000000)); s->page_size = PAGE_SIZE; /* clean-up */ diff --git a/tests/libqos/malloc.c b/tests/libqos/malloc.c index 0d34ecd4b6..4ff260f085 100644 --- a/tests/libqos/malloc.c +++ b/tests/libqos/malloc.c @@ -285,3 +285,11 @@ QGuestAllocator *alloc_init(uint64_t start, uint64_t end) return s; } + +QGuestAllocator *alloc_init_flags(QAllocOpts opts, + uint64_t start, uint64_t end) +{ + QGuestAllocator *s = alloc_init(start, end); + s->opts = opts; + return s; +} diff --git a/tests/libqos/malloc.h b/tests/libqos/malloc.h index 677db7764b..7b2954784f 100644 --- a/tests/libqos/malloc.h +++ b/tests/libqos/malloc.h @@ -51,4 +51,6 @@ uint64_t guest_alloc(QGuestAllocator *allocator, size_t size); void guest_free(QGuestAllocator *allocator, uint64_t addr); QGuestAllocator *alloc_init(uint64_t start, uint64_t end); +QGuestAllocator *alloc_init_flags(QAllocOpts flags, + uint64_t start, uint64_t end); #endif -- cgit v1.2.3 From f6f363c1f4f962aee9f69c67ab2f3ff58c30f8c1 Mon Sep 17 00:00:00 2001 From: John Snow <jsnow@redhat.com> Date: Mon, 19 Jan 2015 15:15:54 -0500 Subject: libqos: Update QGuestAllocator to be opaque MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To avoid the architecture-specific implementations of the generic qtest allocator having to know about fields within the allocator, add a page_size setter method for users or arch specializations to use. The allocator will assume a default page_size for general use, but it can always be overridden. Since this was the last instance of code directly using properties of the QGuestAllocator object directly, modify the type to be opaque and move the structure inside of malloc.c. mlist_new, which was previously exported, is made static local to malloc.c, as it has no external users. [Peter Maydell <peter.maydell@linaro.org> reported the following clang warning: tests/libqos/malloc.c:35:3: warning: redefinition of typedef 'QGuestAllocator' is a C11 feature [-Wtypedef-redefinition] } QGuestAllocator; I converted typedef struct ... QGuestAllocator; to struct ...; --Stefan] Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Marc MarĂ <marc.mari.barcelo@gmail.com> Message-id: 1421698563-6977-7-git-send-email-jsnow@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/libqos/malloc-pc.c | 2 +- tests/libqos/malloc.c | 61 ++++++++++++++++++++++++++++++++++++------------ tests/libqos/malloc.h | 22 +++-------------- 3 files changed, 50 insertions(+), 35 deletions(-) (limited to 'tests') diff --git a/tests/libqos/malloc-pc.c b/tests/libqos/malloc-pc.c index 6a5fdf360a..6e253b6877 100644 --- a/tests/libqos/malloc-pc.c +++ b/tests/libqos/malloc-pc.c @@ -38,7 +38,7 @@ QGuestAllocator *pc_alloc_init_flags(QAllocOpts flags) ram_size = qfw_cfg_get_u64(fw_cfg, FW_CFG_RAM_SIZE); s = alloc_init_flags(flags, 1 << 20, MIN(ram_size, 0xE0000000)); - s->page_size = PAGE_SIZE; + alloc_set_page_size(s, PAGE_SIZE); /* clean-up */ g_free(fw_cfg); diff --git a/tests/libqos/malloc.c b/tests/libqos/malloc.c index 4ff260f085..42e34345ad 100644 --- a/tests/libqos/malloc.c +++ b/tests/libqos/malloc.c @@ -16,6 +16,26 @@ #include <inttypes.h> #include <glib.h> +typedef QTAILQ_HEAD(MemList, MemBlock) MemList; + +typedef struct MemBlock { + QTAILQ_ENTRY(MemBlock) MLIST_ENTNAME; + uint64_t size; + uint64_t addr; +} MemBlock; + +struct QGuestAllocator { + QAllocOpts opts; + uint64_t start; + uint64_t end; + uint32_t page_size; + + MemList used; + MemList free; +}; + +#define DEFAULT_PAGE_SIZE 4096 + static void mlist_delete(MemList *list, MemBlock *node) { g_assert(list && node); @@ -103,6 +123,21 @@ static void mlist_coalesce(MemList *head, MemBlock *node) } while (merge); } +static MemBlock *mlist_new(uint64_t addr, uint64_t size) +{ + MemBlock *block; + + if (!size) { + return NULL; + } + block = g_malloc0(sizeof(MemBlock)); + + block->addr = addr; + block->size = size; + + return block; +} + static uint64_t mlist_fulfill(QGuestAllocator *s, MemBlock *freenode, uint64_t size) { @@ -187,21 +222,6 @@ static void mlist_free(QGuestAllocator *s, uint64_t addr) mlist_coalesce(&s->free, node); } -MemBlock *mlist_new(uint64_t addr, uint64_t size) -{ - MemBlock *block; - - if (!size) { - return NULL; - } - block = g_malloc0(sizeof(MemBlock)); - - block->addr = addr; - block->size = size; - - return block; -} - /* * Mostly for valgrind happiness, but it does offer * a chokepoint for debugging guest memory leaks, too. @@ -283,6 +303,8 @@ QGuestAllocator *alloc_init(uint64_t start, uint64_t end) node = mlist_new(s->start, s->end - s->start); QTAILQ_INSERT_HEAD(&s->free, node, MLIST_ENTNAME); + s->page_size = DEFAULT_PAGE_SIZE; + return s; } @@ -293,3 +315,12 @@ QGuestAllocator *alloc_init_flags(QAllocOpts opts, s->opts = opts; return s; } + +void alloc_set_page_size(QGuestAllocator *allocator, size_t page_size) +{ + /* Can't alter the page_size for an allocator in-use */ + g_assert(QTAILQ_EMPTY(&allocator->used)); + + g_assert(is_power_of_2(page_size)); + allocator->page_size = page_size; +} diff --git a/tests/libqos/malloc.h b/tests/libqos/malloc.h index 7b2954784f..a39dba49b0 100644 --- a/tests/libqos/malloc.h +++ b/tests/libqos/malloc.h @@ -17,8 +17,6 @@ #include <sys/types.h> #include "qemu/queue.h" -#define MLIST_ENTNAME entries - typedef enum { ALLOC_NO_FLAGS = 0x00, ALLOC_LEAK_WARN = 0x01, @@ -26,24 +24,8 @@ typedef enum { ALLOC_PARANOID = 0x04 } QAllocOpts; -typedef QTAILQ_HEAD(MemList, MemBlock) MemList; -typedef struct MemBlock { - QTAILQ_ENTRY(MemBlock) MLIST_ENTNAME; - uint64_t size; - uint64_t addr; -} MemBlock; - -typedef struct QGuestAllocator { - QAllocOpts opts; - uint64_t start; - uint64_t end; - uint32_t page_size; +typedef struct QGuestAllocator QGuestAllocator; - MemList used; - MemList free; -} QGuestAllocator; - -MemBlock *mlist_new(uint64_t addr, uint64_t size); void alloc_uninit(QGuestAllocator *allocator); /* Always returns page aligned values */ @@ -53,4 +35,6 @@ void guest_free(QGuestAllocator *allocator, uint64_t addr); QGuestAllocator *alloc_init(uint64_t start, uint64_t end); QGuestAllocator *alloc_init_flags(QAllocOpts flags, uint64_t start, uint64_t end); +void alloc_set_page_size(QGuestAllocator *allocator, size_t page_size); + #endif -- cgit v1.2.3 From 90e5add6f2fa0b0bd9a4c1d5a4de2304b5f3e466 Mon Sep 17 00:00:00 2001 From: John Snow <jsnow@redhat.com> Date: Mon, 19 Jan 2015 15:15:55 -0500 Subject: libqos: add pc specific interface Create an operations structure so that the libqos interface can be architecture agnostic, and create a pc-specific interface to functions like qtest_boot. Move the libqos object in the Makefile from being ahci-test only to being linked with all tests that utilize the libqos features. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Message-id: 1421698563-6977-8-git-send-email-jsnow@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/Makefile | 6 +++--- tests/ahci-test.c | 4 ++-- tests/libqos/libqos-pc.c | 24 ++++++++++++++++++++++++ tests/libqos/libqos-pc.h | 9 +++++++++ tests/libqos/libqos.c | 16 +++++++++------- tests/libqos/libqos.h | 10 ++++++++-- 6 files changed, 55 insertions(+), 14 deletions(-) create mode 100644 tests/libqos/libqos-pc.c create mode 100644 tests/libqos/libqos-pc.h (limited to 'tests') diff --git a/tests/Makefile b/tests/Makefile index 0469bbd5af..415498cbaa 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -307,9 +307,9 @@ tests/test-mul64$(EXESUF): tests/test-mul64.o libqemuutil.a tests/test-bitops$(EXESUF): tests/test-bitops.o libqemuutil.a libqos-obj-y = tests/libqos/pci.o tests/libqos/fw_cfg.o tests/libqos/malloc.o -libqos-obj-y += tests/libqos/i2c.o +libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o -libqos-pc-obj-y += tests/libqos/malloc-pc.o +libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o libqos-omap-obj-y = $(libqos-obj-y) tests/libqos/i2c-omap.o libqos-virtio-obj-y = $(libqos-obj-y) $(libqos-pc-obj-y) tests/libqos/virtio.o tests/libqos/virtio-pci.o libqos-usb-obj-y = $(libqos-pc-obj-y) tests/libqos/usb.o @@ -320,7 +320,7 @@ tests/endianness-test$(EXESUF): tests/endianness-test.o tests/spapr-phb-test$(EXESUF): tests/spapr-phb-test.o $(libqos-obj-y) tests/fdc-test$(EXESUF): tests/fdc-test.o tests/ide-test$(EXESUF): tests/ide-test.o $(libqos-pc-obj-y) -tests/ahci-test$(EXESUF): tests/ahci-test.o $(libqos-pc-obj-y) tests/libqos/libqos.o +tests/ahci-test$(EXESUF): tests/ahci-test.o $(libqos-pc-obj-y) tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o tests/boot-order-test$(EXESUF): tests/boot-order-test.o $(libqos-obj-y) tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o $(libqos-obj-y) diff --git a/tests/ahci-test.c b/tests/ahci-test.c index 15542b9a78..3bc97727fe 100644 --- a/tests/ahci-test.c +++ b/tests/ahci-test.c @@ -29,7 +29,7 @@ #include <glib.h> #include "libqtest.h" -#include "libqos/libqos.h" +#include "libqos/libqos-pc.h" #include "libqos/ahci.h" #include "libqos/pci-pc.h" #include "libqos/malloc-pc.h" @@ -151,7 +151,7 @@ static AHCIQState *ahci_boot(void) " -M q35 " "-device ide-hd,drive=drive0 " "-global ide-hd.ver=%s"; - s->parent = qtest_boot(cli, tmp_path, "testdisk", "version"); + s->parent = qtest_pc_boot(cli, tmp_path, "testdisk", "version"); /* Verify that we have an AHCI device present. */ s->dev = get_ahci_device(); diff --git a/tests/libqos/libqos-pc.c b/tests/libqos/libqos-pc.c new file mode 100644 index 0000000000..bbace893fb --- /dev/null +++ b/tests/libqos/libqos-pc.c @@ -0,0 +1,24 @@ +#include "libqos/libqos-pc.h" +#include "libqos/malloc-pc.h" + +static QOSOps qos_ops = { + .init_allocator = pc_alloc_init_flags, + .uninit_allocator = pc_alloc_uninit +}; + +QOSState *qtest_pc_boot(const char *cmdline_fmt, ...) +{ + QOSState *qs; + va_list ap; + + va_start(ap, cmdline_fmt); + qs = qtest_vboot(&qos_ops, cmdline_fmt, ap); + va_end(ap); + + return qs; +} + +void qtest_pc_shutdown(QOSState *qs) +{ + return qtest_shutdown(qs); +} diff --git a/tests/libqos/libqos-pc.h b/tests/libqos/libqos-pc.h new file mode 100644 index 0000000000..316857d32f --- /dev/null +++ b/tests/libqos/libqos-pc.h @@ -0,0 +1,9 @@ +#ifndef __libqos_pc_h +#define __libqos_pc_h + +#include "libqos/libqos.h" + +QOSState *qtest_pc_boot(const char *cmdline_fmt, ...); +void qtest_pc_shutdown(QOSState *qs); + +#endif diff --git a/tests/libqos/libqos.c b/tests/libqos/libqos.c index c8b3ef044b..bc8beb281f 100644 --- a/tests/libqos/libqos.c +++ b/tests/libqos/libqos.c @@ -8,7 +8,6 @@ #include "libqtest.h" #include "libqos/libqos.h" #include "libqos/pci.h" -#include "libqos/malloc-pc.h" /*** Test Setup & Teardown ***/ @@ -16,7 +15,7 @@ * Launch QEMU with the given command line, * and then set up interrupts and our guest malloc interface. */ -QOSState *qtest_vboot(const char *cmdline_fmt, va_list ap) +QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap) { char *cmdline; @@ -24,8 +23,11 @@ QOSState *qtest_vboot(const char *cmdline_fmt, va_list ap) cmdline = g_strdup_vprintf(cmdline_fmt, ap); qs->qts = qtest_start(cmdline); + qs->ops = ops; qtest_irq_intercept_in(global_qtest, "ioapic"); - qs->alloc = pc_alloc_init(); + if (ops && ops->init_allocator) { + qs->alloc = ops->init_allocator(ALLOC_NO_FLAGS); + } g_free(cmdline); return qs; @@ -35,13 +37,13 @@ QOSState *qtest_vboot(const char *cmdline_fmt, va_list ap) * Launch QEMU with the given command line, * and then set up interrupts and our guest malloc interface. */ -QOSState *qtest_boot(const char *cmdline_fmt, ...) +QOSState *qtest_boot(QOSOps *ops, const char *cmdline_fmt, ...) { QOSState *qs; va_list ap; va_start(ap, cmdline_fmt); - qs = qtest_vboot(cmdline_fmt, ap); + qs = qtest_vboot(ops, cmdline_fmt, ap); va_end(ap); return qs; @@ -52,8 +54,8 @@ QOSState *qtest_boot(const char *cmdline_fmt, ...) */ void qtest_shutdown(QOSState *qs) { - if (qs->alloc) { - pc_alloc_uninit(qs->alloc); + if (qs->alloc && qs->ops && qs->ops->uninit_allocator) { + qs->ops->uninit_allocator(qs->alloc); qs->alloc = NULL; } qtest_quit(qs->qts); diff --git a/tests/libqos/libqos.h b/tests/libqos/libqos.h index 7ae0a8d600..612d41e5e9 100644 --- a/tests/libqos/libqos.h +++ b/tests/libqos/libqos.h @@ -5,13 +5,19 @@ #include "libqos/pci.h" #include "libqos/malloc-pc.h" +typedef struct QOSOps { + QGuestAllocator *(*init_allocator)(QAllocOpts); + void (*uninit_allocator)(QGuestAllocator *); +} QOSOps; + typedef struct QOSState { QTestState *qts; QGuestAllocator *alloc; + QOSOps *ops; } QOSState; -QOSState *qtest_vboot(const char *cmdline_fmt, va_list ap); -QOSState *qtest_boot(const char *cmdline_fmt, ...); +QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap); +QOSState *qtest_boot(QOSOps *ops, const char *cmdline_fmt, ...); void qtest_shutdown(QOSState *qs); static inline uint64_t qmalloc(QOSState *q, size_t bytes) -- cgit v1.2.3 From 6100ddb0f9776555b581455be4707f2077eee42f Mon Sep 17 00:00:00 2001 From: John Snow <jsnow@redhat.com> Date: Mon, 19 Jan 2015 15:15:56 -0500 Subject: qtest/ahci: Store hba_base in AHCIQState Store the HBA memory base address in the new state object, to simplify function prototypes and encourage a more functional testing style. This causes a lot of churn, but this patch is as "simplified" as I could get it to be. This patch is therefore fairly mechanical and straightforward: Any case where we pass "hba_base" has been consolidated into the AHCIQState object and we pass the one unified parameter. Any case where we reference "ahci" and "hba_state" have been modified to use "ahci->dev" for the PCIDevice and "ahci->hba_state" to get at the base memory address, accordingly. Notes: - A needless return is removed from start_ahci_device. - For ease of reviewing, this patch can be reproduced (mostly) by: # Replace (ahci, hba_base) prototypes with unified parameter 's/(QPCIDevice \*ahci, void \*\?\*hba_base/(AHCIQState *ahci/' # Replace (ahci->dev, hba_base) calls with unified parameter 's/(ahci->dev, &\?hba_base)/(ahci)/' # Replace calls to PCI config space using "ahci" with "ahci->dev" 's/qpci_config_\(read\|write\)\(.\)(ahci,/qpci_config_\1\2(ahci->dev,/' After these, the remaining differences are easy to review by hand. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Message-id: 1421698563-6977-9-git-send-email-jsnow@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/ahci-test.c | 136 +++++++++++++++++++++++++--------------------------- tests/libqos/ahci.h | 1 + 2 files changed, 65 insertions(+), 72 deletions(-) (limited to 'tests') diff --git a/tests/ahci-test.c b/tests/ahci-test.c index 3bc97727fe..a6e507f583 100644 --- a/tests/ahci-test.c +++ b/tests/ahci-test.c @@ -52,8 +52,9 @@ static bool ahci_pedantic; static uint32_t ahci_fingerprint; /*** IO macros for the AHCI memory registers. ***/ -#define AHCI_READ(OFST) qpci_io_readl(ahci, hba_base + (OFST)) -#define AHCI_WRITE(OFST, VAL) qpci_io_writel(ahci, hba_base + (OFST), (VAL)) +#define AHCI_READ(OFST) qpci_io_readl(ahci->dev, ahci->hba_base + (OFST)) +#define AHCI_WRITE(OFST, VAL) qpci_io_writel(ahci->dev, \ + ahci->hba_base + (OFST), (VAL)) #define AHCI_RREG(regno) AHCI_READ(4 * (regno)) #define AHCI_WREG(regno, val) AHCI_WRITE(4 * (regno), (val)) #define AHCI_SET(regno, mask) AHCI_WREG((regno), AHCI_RREG(regno) | (mask)) @@ -70,16 +71,17 @@ static uint32_t ahci_fingerprint; /*** Function Declarations ***/ static QPCIDevice *get_ahci_device(void); -static QPCIDevice *start_ahci_device(QPCIDevice *dev, void **hba_base); +static void start_ahci_device(AHCIQState *ahci); static void free_ahci_device(QPCIDevice *dev); -static void ahci_test_port_spec(QPCIDevice *ahci, void *hba_base, + +static void ahci_test_port_spec(AHCIQState *ahci, HBACap *hcap, uint8_t port); -static void ahci_test_pci_spec(QPCIDevice *ahci); -static void ahci_test_pci_caps(QPCIDevice *ahci, uint16_t header, +static void ahci_test_pci_spec(AHCIQState *ahci); +static void ahci_test_pci_caps(AHCIQState *ahci, uint16_t header, uint8_t offset); -static void ahci_test_satacap(QPCIDevice *ahci, uint8_t offset); -static void ahci_test_msicap(QPCIDevice *ahci, uint8_t offset); -static void ahci_test_pmcap(QPCIDevice *ahci, uint8_t offset); +static void ahci_test_satacap(AHCIQState *ahci, uint8_t offset); +static void ahci_test_msicap(AHCIQState *ahci, uint8_t offset); +static void ahci_test_pmcap(AHCIQState *ahci, uint8_t offset); /*** Utilities ***/ @@ -178,21 +180,21 @@ static void ahci_shutdown(AHCIQState *ahci) /** * Start the PCI device and sanity-check default operation. */ -static void ahci_pci_enable(QPCIDevice *ahci, void **hba_base) +static void ahci_pci_enable(AHCIQState *ahci) { uint8_t reg; - start_ahci_device(ahci, hba_base); + start_ahci_device(ahci); switch (ahci_fingerprint) { case AHCI_INTEL_ICH9: /* ICH9 has a register at PCI 0x92 that * acts as a master port enabler mask. */ - reg = qpci_config_readb(ahci, 0x92); + reg = qpci_config_readb(ahci->dev, 0x92); reg |= 0x3F; - qpci_config_writeb(ahci, 0x92, reg); + qpci_config_writeb(ahci->dev, 0x92, reg); /* 0...0111111b -- bit significant, ports 0-5 enabled. */ - ASSERT_BIT_SET(qpci_config_readb(ahci, 0x92), 0x3F); + ASSERT_BIT_SET(qpci_config_readb(ahci->dev, 0x92), 0x3F); break; } @@ -201,15 +203,13 @@ static void ahci_pci_enable(QPCIDevice *ahci, void **hba_base) /** * Map BAR5/ABAR, and engage the PCI device. */ -static QPCIDevice *start_ahci_device(QPCIDevice *ahci, void **hba_base) +static void start_ahci_device(AHCIQState *ahci) { /* Map AHCI's ABAR (BAR5) */ - *hba_base = qpci_iomap(ahci, 5, &barsize); + ahci->hba_base = qpci_iomap(ahci->dev, 5, &barsize); /* turns on pci.cmd.iose, pci.cmd.mse and pci.cmd.bme */ - qpci_device_enable(ahci); - - return ahci; + qpci_device_enable(ahci->dev); } /** @@ -217,7 +217,7 @@ static QPCIDevice *start_ahci_device(QPCIDevice *ahci, void **hba_base) * Initialize and start any ports with devices attached. * Bring the HBA into the idle state. */ -static void ahci_hba_enable(QPCIDevice *ahci, void *hba_base) +static void ahci_hba_enable(AHCIQState *ahci) { /* Bits of interest in this section: * GHC.AE Global Host Control / AHCI Enable @@ -230,14 +230,11 @@ static void ahci_hba_enable(QPCIDevice *ahci, void *hba_base) */ g_assert(ahci != NULL); - g_assert(hba_base != NULL); uint32_t reg, ports_impl, clb, fb; uint16_t i; uint8_t num_cmd_slots; - g_assert(hba_base != 0); - /* Set GHC.AE to 1 */ AHCI_SET(AHCI_GHC, AHCI_GHC_AE); reg = AHCI_RREG(AHCI_GHC); @@ -351,14 +348,14 @@ static void ahci_hba_enable(QPCIDevice *ahci, void *hba_base) /** * Implementation for test_pci_spec. Ensures PCI configuration space is sane. */ -static void ahci_test_pci_spec(QPCIDevice *ahci) +static void ahci_test_pci_spec(AHCIQState *ahci) { uint8_t datab; uint16_t data; uint32_t datal; /* Most of these bits should start cleared until we turn them on. */ - data = qpci_config_readw(ahci, PCI_COMMAND); + data = qpci_config_readw(ahci->dev, PCI_COMMAND); ASSERT_BIT_CLEAR(data, PCI_COMMAND_MEMORY); ASSERT_BIT_CLEAR(data, PCI_COMMAND_MASTER); ASSERT_BIT_CLEAR(data, PCI_COMMAND_SPECIAL); /* Reserved */ @@ -370,7 +367,7 @@ static void ahci_test_pci_spec(QPCIDevice *ahci) ASSERT_BIT_CLEAR(data, PCI_COMMAND_INTX_DISABLE); ASSERT_BIT_CLEAR(data, 0xF800); /* Reserved */ - data = qpci_config_readw(ahci, PCI_STATUS); + data = qpci_config_readw(ahci->dev, PCI_STATUS); ASSERT_BIT_CLEAR(data, 0x01 | 0x02 | 0x04); /* Reserved */ ASSERT_BIT_CLEAR(data, PCI_STATUS_INTERRUPT); ASSERT_BIT_SET(data, PCI_STATUS_CAP_LIST); /* must be set */ @@ -383,7 +380,7 @@ static void ahci_test_pci_spec(QPCIDevice *ahci) ASSERT_BIT_CLEAR(data, PCI_STATUS_DETECTED_PARITY); /* RID occupies the low byte, CCs occupy the high three. */ - datal = qpci_config_readl(ahci, PCI_CLASS_REVISION); + datal = qpci_config_readl(ahci->dev, PCI_CLASS_REVISION); if (ahci_pedantic) { /* AHCI 1.3 specifies that at-boot, the RID should reset to 0x00, * Though in practice this is likely seldom true. */ @@ -406,38 +403,38 @@ static void ahci_test_pci_spec(QPCIDevice *ahci) g_assert_not_reached(); } - datab = qpci_config_readb(ahci, PCI_CACHE_LINE_SIZE); + datab = qpci_config_readb(ahci->dev, PCI_CACHE_LINE_SIZE); g_assert_cmphex(datab, ==, 0); - datab = qpci_config_readb(ahci, PCI_LATENCY_TIMER); + datab = qpci_config_readb(ahci->dev, PCI_LATENCY_TIMER); g_assert_cmphex(datab, ==, 0); /* Only the bottom 7 bits must be off. */ - datab = qpci_config_readb(ahci, PCI_HEADER_TYPE); + datab = qpci_config_readb(ahci->dev, PCI_HEADER_TYPE); ASSERT_BIT_CLEAR(datab, 0x7F); /* BIST is optional, but the low 7 bits must always start off regardless. */ - datab = qpci_config_readb(ahci, PCI_BIST); + datab = qpci_config_readb(ahci->dev, PCI_BIST); ASSERT_BIT_CLEAR(datab, 0x7F); /* BARS 0-4 do not have a boot spec, but ABAR/BAR5 must be clean. */ - datal = qpci_config_readl(ahci, PCI_BASE_ADDRESS_5); + datal = qpci_config_readl(ahci->dev, PCI_BASE_ADDRESS_5); g_assert_cmphex(datal, ==, 0); - qpci_config_writel(ahci, PCI_BASE_ADDRESS_5, 0xFFFFFFFF); - datal = qpci_config_readl(ahci, PCI_BASE_ADDRESS_5); + qpci_config_writel(ahci->dev, PCI_BASE_ADDRESS_5, 0xFFFFFFFF); + datal = qpci_config_readl(ahci->dev, PCI_BASE_ADDRESS_5); /* ABAR must be 32-bit, memory mapped, non-prefetchable and * must be >= 512 bytes. To that end, bits 0-8 must be off. */ ASSERT_BIT_CLEAR(datal, 0xFF); /* Capability list MUST be present, */ - datal = qpci_config_readl(ahci, PCI_CAPABILITY_LIST); + datal = qpci_config_readl(ahci->dev, PCI_CAPABILITY_LIST); /* But these bits are reserved. */ ASSERT_BIT_CLEAR(datal, ~0xFF); g_assert_cmphex(datal, !=, 0); /* Check specification adherence for capability extenstions. */ - data = qpci_config_readw(ahci, datal); + data = qpci_config_readw(ahci->dev, datal); switch (ahci_fingerprint) { case AHCI_INTEL_ICH9: @@ -452,18 +449,18 @@ static void ahci_test_pci_spec(QPCIDevice *ahci) ahci_test_pci_caps(ahci, data, (uint8_t)datal); /* Reserved. */ - datal = qpci_config_readl(ahci, PCI_CAPABILITY_LIST + 4); + datal = qpci_config_readl(ahci->dev, PCI_CAPABILITY_LIST + 4); g_assert_cmphex(datal, ==, 0); /* IPIN might vary, but ILINE must be off. */ - datab = qpci_config_readb(ahci, PCI_INTERRUPT_LINE); + datab = qpci_config_readb(ahci->dev, PCI_INTERRUPT_LINE); g_assert_cmphex(datab, ==, 0); } /** * Test PCI capabilities for AHCI specification adherence. */ -static void ahci_test_pci_caps(QPCIDevice *ahci, uint16_t header, +static void ahci_test_pci_caps(AHCIQState *ahci, uint16_t header, uint8_t offset) { uint8_t cid = header & 0xFF; @@ -487,14 +484,14 @@ static void ahci_test_pci_caps(QPCIDevice *ahci, uint16_t header, } if (next) { - ahci_test_pci_caps(ahci, qpci_config_readw(ahci, next), next); + ahci_test_pci_caps(ahci, qpci_config_readw(ahci->dev, next), next); } } /** * Test SATA PCI capabilitity for AHCI specification adherence. */ -static void ahci_test_satacap(QPCIDevice *ahci, uint8_t offset) +static void ahci_test_satacap(AHCIQState *ahci, uint8_t offset) { uint16_t dataw; uint32_t datal; @@ -502,11 +499,11 @@ static void ahci_test_satacap(QPCIDevice *ahci, uint8_t offset) g_test_message("Verifying SATACAP"); /* Assert that the SATACAP version is 1.0, And reserved bits are empty. */ - dataw = qpci_config_readw(ahci, offset + 2); + dataw = qpci_config_readw(ahci->dev, offset + 2); g_assert_cmphex(dataw, ==, 0x10); /* Grab the SATACR1 register. */ - datal = qpci_config_readw(ahci, offset + 4); + datal = qpci_config_readw(ahci->dev, offset + 4); switch (datal & 0x0F) { case 0x04: /* BAR0 */ @@ -529,30 +526,30 @@ static void ahci_test_satacap(QPCIDevice *ahci, uint8_t offset) /** * Test MSI PCI capability for AHCI specification adherence. */ -static void ahci_test_msicap(QPCIDevice *ahci, uint8_t offset) +static void ahci_test_msicap(AHCIQState *ahci, uint8_t offset) { uint16_t dataw; uint32_t datal; g_test_message("Verifying MSICAP"); - dataw = qpci_config_readw(ahci, offset + PCI_MSI_FLAGS); + dataw = qpci_config_readw(ahci->dev, offset + PCI_MSI_FLAGS); ASSERT_BIT_CLEAR(dataw, PCI_MSI_FLAGS_ENABLE); ASSERT_BIT_CLEAR(dataw, PCI_MSI_FLAGS_QSIZE); ASSERT_BIT_CLEAR(dataw, PCI_MSI_FLAGS_RESERVED); - datal = qpci_config_readl(ahci, offset + PCI_MSI_ADDRESS_LO); + datal = qpci_config_readl(ahci->dev, offset + PCI_MSI_ADDRESS_LO); g_assert_cmphex(datal, ==, 0); if (dataw & PCI_MSI_FLAGS_64BIT) { g_test_message("MSICAP is 64bit"); - datal = qpci_config_readl(ahci, offset + PCI_MSI_ADDRESS_HI); + datal = qpci_config_readl(ahci->dev, offset + PCI_MSI_ADDRESS_HI); g_assert_cmphex(datal, ==, 0); - dataw = qpci_config_readw(ahci, offset + PCI_MSI_DATA_64); + dataw = qpci_config_readw(ahci->dev, offset + PCI_MSI_DATA_64); g_assert_cmphex(dataw, ==, 0); } else { g_test_message("MSICAP is 32bit"); - dataw = qpci_config_readw(ahci, offset + PCI_MSI_DATA_32); + dataw = qpci_config_readw(ahci->dev, offset + PCI_MSI_DATA_32); g_assert_cmphex(dataw, ==, 0); } } @@ -560,26 +557,26 @@ static void ahci_test_msicap(QPCIDevice *ahci, uint8_t offset) /** * Test Power Management PCI capability for AHCI specification adherence. */ -static void ahci_test_pmcap(QPCIDevice *ahci, uint8_t offset) +static void ahci_test_pmcap(AHCIQState *ahci, uint8_t offset) { uint16_t dataw; g_test_message("Verifying PMCAP"); - dataw = qpci_config_readw(ahci, offset + PCI_PM_PMC); + dataw = qpci_config_readw(ahci->dev, offset + PCI_PM_PMC); ASSERT_BIT_CLEAR(dataw, PCI_PM_CAP_PME_CLOCK); ASSERT_BIT_CLEAR(dataw, PCI_PM_CAP_RESERVED); ASSERT_BIT_CLEAR(dataw, PCI_PM_CAP_D1); ASSERT_BIT_CLEAR(dataw, PCI_PM_CAP_D2); - dataw = qpci_config_readw(ahci, offset + PCI_PM_CTRL); + dataw = qpci_config_readw(ahci->dev, offset + PCI_PM_CTRL); ASSERT_BIT_CLEAR(dataw, PCI_PM_CTRL_STATE_MASK); ASSERT_BIT_CLEAR(dataw, PCI_PM_CTRL_RESERVED); ASSERT_BIT_CLEAR(dataw, PCI_PM_CTRL_DATA_SEL_MASK); ASSERT_BIT_CLEAR(dataw, PCI_PM_CTRL_DATA_SCALE_MASK); } -static void ahci_test_hba_spec(QPCIDevice *ahci, void *hba_base) +static void ahci_test_hba_spec(AHCIQState *ahci) { HBACap hcap; unsigned i; @@ -588,8 +585,7 @@ static void ahci_test_hba_spec(QPCIDevice *ahci, void *hba_base) uint8_t nports_impl; uint8_t maxports; - g_assert(ahci != 0); - g_assert(hba_base != 0); + g_assert(ahci != NULL); /* * Note that the AHCI spec does expect the BIOS to set up a few things: @@ -731,7 +727,7 @@ static void ahci_test_hba_spec(QPCIDevice *ahci, void *hba_base) for (i = 0; ports || (i < maxports); ports >>= 1, ++i) { if (BITSET(ports, 0x1)) { g_test_message("Testing port %u for spec", i); - ahci_test_port_spec(ahci, hba_base, &hcap, i); + ahci_test_port_spec(ahci, &hcap, i); } else { uint16_t j; uint16_t low = AHCI_PORTS + (32 * i); @@ -750,7 +746,7 @@ static void ahci_test_hba_spec(QPCIDevice *ahci, void *hba_base) /** * Test the memory space for one port for specification adherence. */ -static void ahci_test_port_spec(QPCIDevice *ahci, void *hba_base, +static void ahci_test_port_spec(AHCIQState *ahci, HBACap *hcap, uint8_t port) { uint32_t reg; @@ -902,7 +898,7 @@ static void ahci_test_port_spec(QPCIDevice *ahci, void *hba_base, * Utilizing an initialized AHCI HBA, issue an IDENTIFY command to the first * device we see, then read and check the response. */ -static void ahci_test_identify(QPCIDevice *ahci, void *hba_base) +static void ahci_test_identify(AHCIQState *ahci) { RegD2HFIS *d2h = g_malloc0(0x20); RegD2HFIS *pio = g_malloc0(0x20); @@ -915,7 +911,6 @@ static void ahci_test_identify(QPCIDevice *ahci, void *hba_base) int rc; g_assert(ahci != NULL); - g_assert(hba_base != NULL); /* We need to: * (1) Create a Command Table Buffer and update the Command List Slot #0 @@ -1100,7 +1095,7 @@ static void test_pci_spec(void) { AHCIQState *ahci; ahci = ahci_boot(); - ahci_test_pci_spec(ahci->dev); + ahci_test_pci_spec(ahci); ahci_shutdown(ahci); } @@ -1111,9 +1106,9 @@ static void test_pci_spec(void) static void test_pci_enable(void) { AHCIQState *ahci; - void *hba_base; + ahci = ahci_boot(); - ahci_pci_enable(ahci->dev, &hba_base); + ahci_pci_enable(ahci); ahci_shutdown(ahci); } @@ -1124,11 +1119,10 @@ static void test_pci_enable(void) static void test_hba_spec(void) { AHCIQState *ahci; - void *hba_base; ahci = ahci_boot(); - ahci_pci_enable(ahci->dev, &hba_base); - ahci_test_hba_spec(ahci->dev, hba_base); + ahci_pci_enable(ahci); + ahci_test_hba_spec(ahci); ahci_shutdown(ahci); } @@ -1139,11 +1133,10 @@ static void test_hba_spec(void) static void test_hba_enable(void) { AHCIQState *ahci; - void *hba_base; ahci = ahci_boot(); - ahci_pci_enable(ahci->dev, &hba_base); - ahci_hba_enable(ahci->dev, hba_base); + ahci_pci_enable(ahci); + ahci_hba_enable(ahci); ahci_shutdown(ahci); } @@ -1154,12 +1147,11 @@ static void test_hba_enable(void) static void test_identify(void) { AHCIQState *ahci; - void *hba_base; ahci = ahci_boot(); - ahci_pci_enable(ahci->dev, &hba_base); - ahci_hba_enable(ahci->dev, hba_base); - ahci_test_identify(ahci->dev, hba_base); + ahci_pci_enable(ahci); + ahci_hba_enable(ahci); + ahci_test_identify(ahci); ahci_shutdown(ahci); } diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h index bc5f45d77e..e9e0206404 100644 --- a/tests/libqos/ahci.h +++ b/tests/libqos/ahci.h @@ -248,6 +248,7 @@ typedef struct AHCIQState { QOSState *parent; QPCIDevice *dev; + void *hba_base; } AHCIQState; /** -- cgit v1.2.3 From 8d5eeceddcb6464c7db3b4504c14766453db091e Mon Sep 17 00:00:00 2001 From: John Snow <jsnow@redhat.com> Date: Mon, 19 Jan 2015 15:15:57 -0500 Subject: qtest/ahci: finalize AHCIQState consolidation Move barsize, ahci_fingerprint and capabilities registers into the AHCIQState object, removing global ahci-related state from the ahci-test.c file. More churn, less globals. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Message-id: 1421698563-6977-10-git-send-email-jsnow@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/ahci-test.c | 80 +++++++++++++++++++++++++---------------------------- tests/libqos/ahci.h | 9 +++--- 2 files changed, 42 insertions(+), 47 deletions(-) (limited to 'tests') diff --git a/tests/ahci-test.c b/tests/ahci-test.c index a6e507f583..96fb45c17d 100644 --- a/tests/ahci-test.c +++ b/tests/ahci-test.c @@ -46,10 +46,8 @@ /*** Globals ***/ static QGuestAllocator *guest_malloc; static QPCIBus *pcibus; -static uint64_t barsize; static char tmp_path[] = "/tmp/qtest.XXXXXX"; static bool ahci_pedantic; -static uint32_t ahci_fingerprint; /*** IO macros for the AHCI memory registers. ***/ #define AHCI_READ(OFST) qpci_io_readl(ahci->dev, ahci->hba_base + (OFST)) @@ -70,12 +68,11 @@ static uint32_t ahci_fingerprint; PX_RREG((port), (reg)) & ~(mask)); /*** Function Declarations ***/ -static QPCIDevice *get_ahci_device(void); +static QPCIDevice *get_ahci_device(uint32_t *fingerprint); static void start_ahci_device(AHCIQState *ahci); static void free_ahci_device(QPCIDevice *dev); -static void ahci_test_port_spec(AHCIQState *ahci, - HBACap *hcap, uint8_t port); +static void ahci_test_port_spec(AHCIQState *ahci, uint8_t port); static void ahci_test_pci_spec(AHCIQState *ahci); static void ahci_test_pci_caps(AHCIQState *ahci, uint16_t header, uint8_t offset); @@ -99,9 +96,10 @@ static void string_bswap16(uint16_t *s, size_t bytes) /** * Locate, verify, and return a handle to the AHCI device. */ -static QPCIDevice *get_ahci_device(void) +static QPCIDevice *get_ahci_device(uint32_t *fingerprint) { QPCIDevice *ahci; + uint32_t ahci_fingerprint; pcibus = qpci_init_pc(); @@ -119,6 +117,9 @@ static QPCIDevice *get_ahci_device(void) g_assert_not_reached(); } + if (fingerprint) { + *fingerprint = ahci_fingerprint; + } return ahci; } @@ -131,9 +132,6 @@ static void free_ahci_device(QPCIDevice *ahci) qpci_free_pc(pcibus); pcibus = NULL; } - - /* Clear our cached barsize information. */ - barsize = 0; } /*** Test Setup & Teardown ***/ @@ -156,7 +154,7 @@ static AHCIQState *ahci_boot(void) s->parent = qtest_pc_boot(cli, tmp_path, "testdisk", "version"); /* Verify that we have an AHCI device present. */ - s->dev = get_ahci_device(); + s->dev = get_ahci_device(&s->fingerprint); /* Stopgap: Copy the allocator reference */ guest_malloc = s->parent->alloc; @@ -186,7 +184,7 @@ static void ahci_pci_enable(AHCIQState *ahci) start_ahci_device(ahci); - switch (ahci_fingerprint) { + switch (ahci->fingerprint) { case AHCI_INTEL_ICH9: /* ICH9 has a register at PCI 0x92 that * acts as a master port enabler mask. */ @@ -206,7 +204,7 @@ static void ahci_pci_enable(AHCIQState *ahci) static void start_ahci_device(AHCIQState *ahci) { /* Map AHCI's ABAR (BAR5) */ - ahci->hba_base = qpci_iomap(ahci->dev, 5, &barsize); + ahci->hba_base = qpci_iomap(ahci->dev, 5, &ahci->barsize); /* turns on pci.cmd.iose, pci.cmd.mse and pci.cmd.bme */ qpci_device_enable(ahci->dev); @@ -228,21 +226,23 @@ static void ahci_hba_enable(AHCIQState *ahci) * PxCMD.FR "FIS Receive Running" * PxCMD.CR "Command List Running" */ - - g_assert(ahci != NULL); - uint32_t reg, ports_impl, clb, fb; uint16_t i; uint8_t num_cmd_slots; + g_assert(ahci != NULL); + /* Set GHC.AE to 1 */ AHCI_SET(AHCI_GHC, AHCI_GHC_AE); reg = AHCI_RREG(AHCI_GHC); ASSERT_BIT_SET(reg, AHCI_GHC_AE); + /* Cache CAP and CAP2. */ + ahci->cap = AHCI_RREG(AHCI_CAP); + ahci->cap2 = AHCI_RREG(AHCI_CAP2); + /* Read CAP.NCS, how many command slots do we have? */ - reg = AHCI_RREG(AHCI_CAP); - num_cmd_slots = ((reg & AHCI_CAP_NCS) >> ctzl(AHCI_CAP_NCS)) + 1; + num_cmd_slots = ((ahci->cap & AHCI_CAP_NCS) >> ctzl(AHCI_CAP_NCS)) + 1; g_test_message("Number of Command Slots: %u", num_cmd_slots); /* Determine which ports are implemented. */ @@ -436,7 +436,7 @@ static void ahci_test_pci_spec(AHCIQState *ahci) /* Check specification adherence for capability extenstions. */ data = qpci_config_readw(ahci->dev, datal); - switch (ahci_fingerprint) { + switch (ahci->fingerprint) { case AHCI_INTEL_ICH9: /* Intel ICH9 Family Datasheet 14.1.19 p.550 */ g_assert_cmphex((data & 0xFF), ==, PCI_CAP_ID_MSI); @@ -578,9 +578,8 @@ static void ahci_test_pmcap(AHCIQState *ahci, uint8_t offset) static void ahci_test_hba_spec(AHCIQState *ahci) { - HBACap hcap; unsigned i; - uint32_t cap, cap2, reg; + uint32_t reg; uint32_t ports; uint8_t nports_impl; uint8_t maxports; @@ -608,15 +607,15 @@ static void ahci_test_hba_spec(AHCIQState *ahci) */ /* 1 CAP - Capabilities Register */ - cap = AHCI_RREG(AHCI_CAP); - ASSERT_BIT_CLEAR(cap, AHCI_CAP_RESERVED); + ahci->cap = AHCI_RREG(AHCI_CAP); + ASSERT_BIT_CLEAR(ahci->cap, AHCI_CAP_RESERVED); /* 2 GHC - Global Host Control */ reg = AHCI_RREG(AHCI_GHC); ASSERT_BIT_CLEAR(reg, AHCI_GHC_HR); ASSERT_BIT_CLEAR(reg, AHCI_GHC_IE); ASSERT_BIT_CLEAR(reg, AHCI_GHC_MRSM); - if (BITSET(cap, AHCI_CAP_SAM)) { + if (BITSET(ahci->cap, AHCI_CAP_SAM)) { g_test_message("Supports AHCI-Only Mode: GHC_AE is Read-Only."); ASSERT_BIT_SET(reg, AHCI_GHC_AE); } else { @@ -634,13 +633,13 @@ static void ahci_test_hba_spec(AHCIQState *ahci) g_assert_cmphex(ports, !=, 0); /* Ports Implemented must be <= Number of Ports. */ nports_impl = ctpopl(ports); - g_assert_cmpuint(((AHCI_CAP_NP & cap) + 1), >=, nports_impl); + g_assert_cmpuint(((AHCI_CAP_NP & ahci->cap) + 1), >=, nports_impl); - g_assert_cmphex(barsize, >, 0); /* Ports must be within the proper range. Given a mapping of SIZE, * 256 bytes are used for global HBA control, and the rest is used * for ports data, at 0x80 bytes each. */ - maxports = (barsize - HBA_DATA_REGION_SIZE) / HBA_PORT_DATA_SIZE; + g_assert_cmphex(ahci->barsize, >, 0); + maxports = (ahci->barsize - HBA_DATA_REGION_SIZE) / HBA_PORT_DATA_SIZE; /* e.g, 30 ports for 4K of memory. (4096 - 256) / 128 = 30 */ g_assert_cmphex((reg >> maxports), ==, 0); @@ -659,7 +658,7 @@ static void ahci_test_hba_spec(AHCIQState *ahci) /* 6 Command Completion Coalescing Control: depends on CAP.CCCS. */ reg = AHCI_RREG(AHCI_CCCCTL); - if (BITSET(cap, AHCI_CAP_CCCS)) { + if (BITSET(ahci->cap, AHCI_CAP_CCCS)) { ASSERT_BIT_CLEAR(reg, AHCI_CCCCTL_EN); ASSERT_BIT_CLEAR(reg, AHCI_CCCCTL_RESERVED); ASSERT_BIT_SET(reg, AHCI_CCCCTL_CC); @@ -675,13 +674,13 @@ static void ahci_test_hba_spec(AHCIQState *ahci) /* 8 EM_LOC */ reg = AHCI_RREG(AHCI_EMLOC); - if (BITCLR(cap, AHCI_CAP_EMS)) { + if (BITCLR(ahci->cap, AHCI_CAP_EMS)) { g_assert_cmphex(reg, ==, 0); } /* 9 EM_CTL */ reg = AHCI_RREG(AHCI_EMCTL); - if (BITSET(cap, AHCI_CAP_EMS)) { + if (BITSET(ahci->cap, AHCI_CAP_EMS)) { ASSERT_BIT_CLEAR(reg, AHCI_EMCTL_STSMR); ASSERT_BIT_CLEAR(reg, AHCI_EMCTL_CTLTM); ASSERT_BIT_CLEAR(reg, AHCI_EMCTL_CTLRST); @@ -691,8 +690,8 @@ static void ahci_test_hba_spec(AHCIQState *ahci) } /* 10 CAP2 -- Capabilities Extended */ - cap2 = AHCI_RREG(AHCI_CAP2); - ASSERT_BIT_CLEAR(cap2, AHCI_CAP2_RESERVED); + ahci->cap2 = AHCI_RREG(AHCI_CAP2); + ASSERT_BIT_CLEAR(ahci->cap2, AHCI_CAP2_RESERVED); /* 11 BOHC -- Bios/OS Handoff Control */ reg = AHCI_RREG(AHCI_BOHC); @@ -706,7 +705,7 @@ static void ahci_test_hba_spec(AHCIQState *ahci) } /* 24 -- 39: NVMHCI */ - if (BITCLR(cap2, AHCI_CAP2_NVMP)) { + if (BITCLR(ahci->cap2, AHCI_CAP2_NVMP)) { g_test_message("Verifying HBA/NVMHCI area is empty."); for (i = AHCI_NVMHCI; i < AHCI_VENDOR; ++i) { reg = AHCI_RREG(i); @@ -722,12 +721,10 @@ static void ahci_test_hba_spec(AHCIQState *ahci) } /* 64 -- XX: Port Space */ - hcap.cap = cap; - hcap.cap2 = cap2; for (i = 0; ports || (i < maxports); ports >>= 1, ++i) { if (BITSET(ports, 0x1)) { g_test_message("Testing port %u for spec", i); - ahci_test_port_spec(ahci, &hcap, i); + ahci_test_port_spec(ahci, i); } else { uint16_t j; uint16_t low = AHCI_PORTS + (32 * i); @@ -746,8 +743,7 @@ static void ahci_test_hba_spec(AHCIQState *ahci) /** * Test the memory space for one port for specification adherence. */ -static void ahci_test_port_spec(AHCIQState *ahci, - HBACap *hcap, uint8_t port) +static void ahci_test_port_spec(AHCIQState *ahci, uint8_t port) { uint32_t reg; unsigned i; @@ -757,7 +753,7 @@ static void ahci_test_port_spec(AHCIQState *ahci, ASSERT_BIT_CLEAR(reg, AHCI_PX_CLB_RESERVED); /* (1) CLBU */ - if (BITCLR(hcap->cap, AHCI_CAP_S64A)) { + if (BITCLR(ahci->cap, AHCI_CAP_S64A)) { reg = PX_RREG(port, AHCI_PX_CLBU); g_assert_cmphex(reg, ==, 0); } @@ -767,7 +763,7 @@ static void ahci_test_port_spec(AHCIQState *ahci, ASSERT_BIT_CLEAR(reg, AHCI_PX_FB_RESERVED); /* (3) FBU */ - if (BITCLR(hcap->cap, AHCI_CAP_S64A)) { + if (BITCLR(ahci->cap, AHCI_CAP_S64A)) { reg = PX_RREG(port, AHCI_PX_FBU); g_assert_cmphex(reg, ==, 0); } @@ -803,7 +799,7 @@ static void ahci_test_port_spec(AHCIQState *ahci, ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_MPSS); } /* If we do not support MPS, MPSS and MPSP must be off. */ - if (BITCLR(hcap->cap, AHCI_CAP_SMPS)) { + if (BITCLR(ahci->cap, AHCI_CAP_SMPS)) { ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_MPSS); ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_MPSP); } @@ -814,7 +810,7 @@ static void ahci_test_port_spec(AHCIQState *ahci, /* HPCP and ESP cannot both be active. */ g_assert(!BITSET(reg, AHCI_PX_CMD_HPCP | AHCI_PX_CMD_ESP)); /* If CAP.FBSS is not set, FBSCP must not be set. */ - if (BITCLR(hcap->cap, AHCI_CAP_FBSS)) { + if (BITCLR(ahci->cap, AHCI_CAP_FBSS)) { ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_FBSCP); } @@ -874,7 +870,7 @@ static void ahci_test_port_spec(AHCIQState *ahci, ASSERT_BIT_CLEAR(reg, AHCI_PX_FBS_DEV); ASSERT_BIT_CLEAR(reg, AHCI_PX_FBS_DWE); ASSERT_BIT_CLEAR(reg, AHCI_PX_FBS_RESERVED); - if (BITSET(hcap->cap, AHCI_CAP_FBSS)) { + if (BITSET(ahci->cap, AHCI_CAP_FBSS)) { /* if Port-Multiplier FIS-based switching avail, ADO must >= 2 */ g_assert((reg & AHCI_PX_FBS_ADO) >> ctzl(AHCI_PX_FBS_ADO) >= 2); } diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h index e9e0206404..8e92385816 100644 --- a/tests/libqos/ahci.h +++ b/tests/libqos/ahci.h @@ -249,6 +249,10 @@ typedef struct AHCIQState { QOSState *parent; QPCIDevice *dev; void *hba_base; + uint64_t barsize; + uint32_t fingerprint; + uint32_t cap; + uint32_t cap2; } AHCIQState; /** @@ -340,11 +344,6 @@ typedef struct PRD { uint32_t dbc; /* Data Byte Count (0-indexed) & Interrupt Flag (bit 2^31) */ } PRD; -typedef struct HBACap { - uint32_t cap; - uint32_t cap2; -} HBACap; - /*** Macro Utilities ***/ #define BITANY(data, mask) (((data) & (mask)) != 0) #define BITSET(data, mask) (((data) & (mask)) == (mask)) -- cgit v1.2.3 From 7f410456652463db7312bc839d45396bf48a849e Mon Sep 17 00:00:00 2001 From: John Snow <jsnow@redhat.com> Date: Mon, 19 Jan 2015 15:15:58 -0500 Subject: qtest/ahci: remove pcibus global Rely on the PCI Device's bus pointer instead. One less global to worry about. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Message-id: 1421698563-6977-11-git-send-email-jsnow@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/ahci-test.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'tests') diff --git a/tests/ahci-test.c b/tests/ahci-test.c index 96fb45c17d..0cc56ab28f 100644 --- a/tests/ahci-test.c +++ b/tests/ahci-test.c @@ -45,7 +45,6 @@ /*** Globals ***/ static QGuestAllocator *guest_malloc; -static QPCIBus *pcibus; static char tmp_path[] = "/tmp/qtest.XXXXXX"; static bool ahci_pedantic; @@ -100,6 +99,7 @@ static QPCIDevice *get_ahci_device(uint32_t *fingerprint) { QPCIDevice *ahci; uint32_t ahci_fingerprint; + QPCIBus *pcibus; pcibus = qpci_init_pc(); @@ -123,15 +123,13 @@ static QPCIDevice *get_ahci_device(uint32_t *fingerprint) return ahci; } -static void free_ahci_device(QPCIDevice *ahci) +static void free_ahci_device(QPCIDevice *dev) { - /* libqos doesn't have a function for this, so free it manually */ - g_free(ahci); + QPCIBus *pcibus = dev ? dev->bus : NULL; - if (pcibus) { - qpci_free_pc(pcibus); - pcibus = NULL; - } + /* libqos doesn't have a function for this, so free it manually */ + g_free(dev); + qpci_free_pc(pcibus); } /*** Test Setup & Teardown ***/ -- cgit v1.2.3 From c12e8293b8ed29d98f9ef563e997c9de8ff10e23 Mon Sep 17 00:00:00 2001 From: John Snow <jsnow@redhat.com> Date: Mon, 19 Jan 2015 15:15:59 -0500 Subject: qtest/ahci: remove guest_malloc global Make helper routines rely on the earmarked guest allocator object with AHCIQState/QOSSTate instead. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Message-id: 1421698563-6977-12-git-send-email-jsnow@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/ahci-test.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'tests') diff --git a/tests/ahci-test.c b/tests/ahci-test.c index 0cc56ab28f..bb98968209 100644 --- a/tests/ahci-test.c +++ b/tests/ahci-test.c @@ -32,7 +32,6 @@ #include "libqos/libqos-pc.h" #include "libqos/ahci.h" #include "libqos/pci-pc.h" -#include "libqos/malloc-pc.h" #include "qemu-common.h" #include "qemu/host-utils.h" @@ -44,7 +43,6 @@ #define TEST_IMAGE_SIZE (64 * 1024 * 1024) /*** Globals ***/ -static QGuestAllocator *guest_malloc; static char tmp_path[] = "/tmp/qtest.XXXXXX"; static bool ahci_pedantic; @@ -92,6 +90,11 @@ static void string_bswap16(uint16_t *s, size_t bytes) } } +static uint64_t ahci_alloc(AHCIQState *ahci, size_t bytes) +{ + return qmalloc(ahci->parent, bytes); +} + /** * Locate, verify, and return a handle to the AHCI device. */ @@ -154,9 +157,6 @@ static AHCIQState *ahci_boot(void) /* Verify that we have an AHCI device present. */ s->dev = get_ahci_device(&s->fingerprint); - /* Stopgap: Copy the allocator reference */ - guest_malloc = s->parent->alloc; - return s; } @@ -272,13 +272,13 @@ static void ahci_hba_enable(AHCIQState *ahci) /* Allocate Memory for the Command List Buffer & FIS Buffer */ /* PxCLB space ... 0x20 per command, as in 4.2.2 p 36 */ - clb = guest_alloc(guest_malloc, num_cmd_slots * 0x20); + clb = ahci_alloc(ahci, num_cmd_slots * 0x20); g_test_message("CLB: 0x%08x", clb); PX_WREG(i, AHCI_PX_CLB, clb); g_assert_cmphex(clb, ==, PX_RREG(i, AHCI_PX_CLB)); /* PxFB space ... 0x100, as in 4.2.1 p 35 */ - fb = guest_alloc(guest_malloc, 0x100); + fb = ahci_alloc(ahci, 0x100); g_test_message("FB: 0x%08x", fb); PX_WREG(i, AHCI_PX_FB, fb); g_assert_cmphex(fb, ==, PX_RREG(i, AHCI_PX_FB)); @@ -951,12 +951,12 @@ static void ahci_test_identify(AHCIQState *ahci) /* Create a Command Table buffer. 0x80 is the smallest with a PRDTL of 0. */ /* We need at least one PRD, so round up to the nearest 0x80 multiple. */ - table = guest_alloc(guest_malloc, CMD_TBL_SIZ(1)); + table = ahci_alloc(ahci, CMD_TBL_SIZ(1)); g_assert(table); ASSERT_BIT_CLEAR(table, 0x7F); /* Create a data buffer ... where we will dump the IDENTIFY data to. */ - data_ptr = guest_alloc(guest_malloc, 512); + data_ptr = ahci_alloc(ahci, 512); g_assert(data_ptr); /* Grab the Command List Buffer pointer */ -- cgit v1.2.3 From 4882f359493cd02d7a5caa7b85d2e1bc4b2f8177 Mon Sep 17 00:00:00 2001 From: John Snow <jsnow@redhat.com> Date: Mon, 19 Jan 2015 15:16:00 -0500 Subject: libqos/ahci: Functional register helpers Introduce a set of "static inline" register helpers that are intended to replace the current set of macros with more functional versions that are better suited to inclusion in libqos than porcelain macros. As a stopgap measure before eliminating the porcelain macros, define them to use the new functions defined in the ahci.h header. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Message-id: 1421698563-6977-13-git-send-email-jsnow@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/ahci-test.c | 25 ++++++++++----------- tests/libqos/ahci.h | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 14 deletions(-) (limited to 'tests') diff --git a/tests/ahci-test.c b/tests/ahci-test.c index bb98968209..25e54b8fed 100644 --- a/tests/ahci-test.c +++ b/tests/ahci-test.c @@ -47,22 +47,19 @@ static char tmp_path[] = "/tmp/qtest.XXXXXX"; static bool ahci_pedantic; /*** IO macros for the AHCI memory registers. ***/ -#define AHCI_READ(OFST) qpci_io_readl(ahci->dev, ahci->hba_base + (OFST)) -#define AHCI_WRITE(OFST, VAL) qpci_io_writel(ahci->dev, \ - ahci->hba_base + (OFST), (VAL)) -#define AHCI_RREG(regno) AHCI_READ(4 * (regno)) -#define AHCI_WREG(regno, val) AHCI_WRITE(4 * (regno), (val)) -#define AHCI_SET(regno, mask) AHCI_WREG((regno), AHCI_RREG(regno) | (mask)) -#define AHCI_CLR(regno, mask) AHCI_WREG((regno), AHCI_RREG(regno) & ~(mask)) +#define AHCI_READ(OFST) ahci_mread(ahci, (OFST)) +#define AHCI_WRITE(OFST, VAL) ahci_mwrite(ahci, (OFST), (VAL)) +#define AHCI_RREG(regno) ahci_rreg(ahci, (regno)) +#define AHCI_WREG(regno, val) ahci_wreg(ahci, (regno), (val)) +#define AHCI_SET(regno, mask) ahci_set(ahci, (regno), (mask)) +#define AHCI_CLR(regno, mask) ahci_clr(ahci, (regno), (mask)) /*** IO macros for port-specific offsets inside of AHCI memory. ***/ -#define PX_OFST(port, regno) (HBA_PORT_NUM_REG * (port) + AHCI_PORTS + (regno)) -#define PX_RREG(port, regno) AHCI_RREG(PX_OFST((port), (regno))) -#define PX_WREG(port, regno, val) AHCI_WREG(PX_OFST((port), (regno)), (val)) -#define PX_SET(port, reg, mask) PX_WREG((port), (reg), \ - PX_RREG((port), (reg)) | (mask)); -#define PX_CLR(port, reg, mask) PX_WREG((port), (reg), \ - PX_RREG((port), (reg)) & ~(mask)); +#define PX_OFST(port, regno) ahci_px_ofst((port), (regno)) +#define PX_RREG(port, regno) ahci_px_rreg(ahci, (port), (regno)) +#define PX_WREG(port, regno, val) ahci_px_wreg(ahci, (port), (regno), (val)) +#define PX_SET(port, reg, mask) ahci_px_set(ahci, (port), (reg), (mask)) +#define PX_CLR(port, reg, mask) ahci_px_clr(ahci, (port), (reg), (mask)) /*** Function Declarations ***/ static QPCIDevice *get_ahci_device(uint32_t *fingerprint); diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h index 8e92385816..645f05b9c4 100644 --- a/tests/libqos/ahci.h +++ b/tests/libqos/ahci.h @@ -354,4 +354,67 @@ typedef struct PRD { /* For calculating how big the PRD table needs to be: */ #define CMD_TBL_SIZ(n) ((0x80 + ((n) * sizeof(PRD)) + 0x7F) & ~0x7F) +/* Helpers for reading/writing AHCI HBA register values */ + +static inline uint32_t ahci_mread(AHCIQState *ahci, size_t offset) +{ + return qpci_io_readl(ahci->dev, ahci->hba_base + offset); +} + +static inline void ahci_mwrite(AHCIQState *ahci, size_t offset, uint32_t value) +{ + qpci_io_writel(ahci->dev, ahci->hba_base + offset, value); +} + +static inline uint32_t ahci_rreg(AHCIQState *ahci, uint32_t reg_num) +{ + return ahci_mread(ahci, 4 * reg_num); +} + +static inline void ahci_wreg(AHCIQState *ahci, uint32_t reg_num, uint32_t value) +{ + ahci_mwrite(ahci, 4 * reg_num, value); +} + +static inline void ahci_set(AHCIQState *ahci, uint32_t reg_num, uint32_t mask) +{ + ahci_wreg(ahci, reg_num, ahci_rreg(ahci, reg_num) | mask); +} + +static inline void ahci_clr(AHCIQState *ahci, uint32_t reg_num, uint32_t mask) +{ + ahci_wreg(ahci, reg_num, ahci_rreg(ahci, reg_num) & ~mask); +} + +static inline size_t ahci_px_offset(uint8_t port, uint32_t reg_num) +{ + return AHCI_PORTS + (HBA_PORT_NUM_REG * port) + reg_num; +} + +static inline uint32_t ahci_px_rreg(AHCIQState *ahci, uint8_t port, + uint32_t reg_num) +{ + return ahci_rreg(ahci, ahci_px_offset(port, reg_num)); +} + +static inline void ahci_px_wreg(AHCIQState *ahci, uint8_t port, + uint32_t reg_num, uint32_t value) +{ + ahci_wreg(ahci, ahci_px_offset(port, reg_num), value); +} + +static inline void ahci_px_set(AHCIQState *ahci, uint8_t port, + uint32_t reg_num, uint32_t mask) +{ + ahci_px_wreg(ahci, port, reg_num, + ahci_px_rreg(ahci, port, reg_num) | mask); +} + +static inline void ahci_px_clr(AHCIQState *ahci, uint8_t port, + uint32_t reg_num, uint32_t mask) +{ + ahci_px_wreg(ahci, port, reg_num, + ahci_px_rreg(ahci, port, reg_num) & ~mask); +} + #endif -- cgit v1.2.3 From 1a8bba4ddce44cff33bfd3d4976fb33923c06a1b Mon Sep 17 00:00:00 2001 From: John Snow <jsnow@redhat.com> Date: Mon, 19 Jan 2015 15:16:01 -0500 Subject: qtest/ahci: remove getter/setter macros These macros were a bad idea: They relied upon certain arguments being present locally with a specific name. With the endgoal being to factor out AHCI helper functions outside of the test file itself, these have to be replaced by more explicit helper setter/getter functions. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Message-id: 1421698563-6977-14-git-send-email-jsnow@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/ahci-test.c | 178 +++++++++++++++++++++++++----------------------------- 1 file changed, 83 insertions(+), 95 deletions(-) (limited to 'tests') diff --git a/tests/ahci-test.c b/tests/ahci-test.c index 25e54b8fed..aa1f66f012 100644 --- a/tests/ahci-test.c +++ b/tests/ahci-test.c @@ -46,21 +46,6 @@ static char tmp_path[] = "/tmp/qtest.XXXXXX"; static bool ahci_pedantic; -/*** IO macros for the AHCI memory registers. ***/ -#define AHCI_READ(OFST) ahci_mread(ahci, (OFST)) -#define AHCI_WRITE(OFST, VAL) ahci_mwrite(ahci, (OFST), (VAL)) -#define AHCI_RREG(regno) ahci_rreg(ahci, (regno)) -#define AHCI_WREG(regno, val) ahci_wreg(ahci, (regno), (val)) -#define AHCI_SET(regno, mask) ahci_set(ahci, (regno), (mask)) -#define AHCI_CLR(regno, mask) ahci_clr(ahci, (regno), (mask)) - -/*** IO macros for port-specific offsets inside of AHCI memory. ***/ -#define PX_OFST(port, regno) ahci_px_ofst((port), (regno)) -#define PX_RREG(port, regno) ahci_px_rreg(ahci, (port), (regno)) -#define PX_WREG(port, regno, val) ahci_px_wreg(ahci, (port), (regno), (val)) -#define PX_SET(port, reg, mask) ahci_px_set(ahci, (port), (reg), (mask)) -#define PX_CLR(port, reg, mask) ahci_px_clr(ahci, (port), (reg), (mask)) - /*** Function Declarations ***/ static QPCIDevice *get_ahci_device(uint32_t *fingerprint); static void start_ahci_device(AHCIQState *ahci); @@ -228,20 +213,20 @@ static void ahci_hba_enable(AHCIQState *ahci) g_assert(ahci != NULL); /* Set GHC.AE to 1 */ - AHCI_SET(AHCI_GHC, AHCI_GHC_AE); - reg = AHCI_RREG(AHCI_GHC); + ahci_set(ahci, AHCI_GHC, AHCI_GHC_AE); + reg = ahci_rreg(ahci, AHCI_GHC); ASSERT_BIT_SET(reg, AHCI_GHC_AE); /* Cache CAP and CAP2. */ - ahci->cap = AHCI_RREG(AHCI_CAP); - ahci->cap2 = AHCI_RREG(AHCI_CAP2); + ahci->cap = ahci_rreg(ahci, AHCI_CAP); + ahci->cap2 = ahci_rreg(ahci, AHCI_CAP2); /* Read CAP.NCS, how many command slots do we have? */ num_cmd_slots = ((ahci->cap & AHCI_CAP_NCS) >> ctzl(AHCI_CAP_NCS)) + 1; g_test_message("Number of Command Slots: %u", num_cmd_slots); /* Determine which ports are implemented. */ - ports_impl = AHCI_RREG(AHCI_PI); + ports_impl = ahci_rreg(ahci, AHCI_PI); for (i = 0; ports_impl; ports_impl >>= 1, ++i) { if (!(ports_impl & 0x01)) { @@ -250,16 +235,17 @@ static void ahci_hba_enable(AHCIQState *ahci) g_test_message("Initializing port %u", i); - reg = PX_RREG(i, AHCI_PX_CMD); + reg = ahci_px_rreg(ahci, i, AHCI_PX_CMD); if (BITCLR(reg, AHCI_PX_CMD_ST | AHCI_PX_CMD_CR | AHCI_PX_CMD_FRE | AHCI_PX_CMD_FR)) { g_test_message("port is idle"); } else { g_test_message("port needs to be idled"); - PX_CLR(i, AHCI_PX_CMD, (AHCI_PX_CMD_ST | AHCI_PX_CMD_FRE)); + ahci_px_clr(ahci, i, AHCI_PX_CMD, + (AHCI_PX_CMD_ST | AHCI_PX_CMD_FRE)); /* The port has 500ms to disengage. */ usleep(500000); - reg = PX_RREG(i, AHCI_PX_CMD); + reg = ahci_px_rreg(ahci, i, AHCI_PX_CMD); ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_CR); ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_FR); g_test_message("port is now idle"); @@ -271,55 +257,56 @@ static void ahci_hba_enable(AHCIQState *ahci) /* PxCLB space ... 0x20 per command, as in 4.2.2 p 36 */ clb = ahci_alloc(ahci, num_cmd_slots * 0x20); g_test_message("CLB: 0x%08x", clb); - PX_WREG(i, AHCI_PX_CLB, clb); - g_assert_cmphex(clb, ==, PX_RREG(i, AHCI_PX_CLB)); + ahci_px_wreg(ahci, i, AHCI_PX_CLB, clb); + g_assert_cmphex(clb, ==, ahci_px_rreg(ahci, i, AHCI_PX_CLB)); /* PxFB space ... 0x100, as in 4.2.1 p 35 */ fb = ahci_alloc(ahci, 0x100); g_test_message("FB: 0x%08x", fb); - PX_WREG(i, AHCI_PX_FB, fb); - g_assert_cmphex(fb, ==, PX_RREG(i, AHCI_PX_FB)); + ahci_px_wreg(ahci, i, AHCI_PX_FB, fb); + g_assert_cmphex(fb, ==, ahci_px_rreg(ahci, i, AHCI_PX_FB)); /* Clear PxSERR, PxIS, then IS.IPS[x] by writing '1's. */ - PX_WREG(i, AHCI_PX_SERR, 0xFFFFFFFF); - PX_WREG(i, AHCI_PX_IS, 0xFFFFFFFF); - AHCI_WREG(AHCI_IS, (1 << i)); + ahci_px_wreg(ahci, i, AHCI_PX_SERR, 0xFFFFFFFF); + ahci_px_wreg(ahci, i, AHCI_PX_IS, 0xFFFFFFFF); + ahci_wreg(ahci, AHCI_IS, (1 << i)); /* Verify Interrupts Cleared */ - reg = PX_RREG(i, AHCI_PX_SERR); + reg = ahci_px_rreg(ahci, i, AHCI_PX_SERR); g_assert_cmphex(reg, ==, 0); - reg = PX_RREG(i, AHCI_PX_IS); + reg = ahci_px_rreg(ahci, i, AHCI_PX_IS); g_assert_cmphex(reg, ==, 0); - reg = AHCI_RREG(AHCI_IS); + reg = ahci_rreg(ahci, AHCI_IS); ASSERT_BIT_CLEAR(reg, (1 << i)); /* Enable All Interrupts: */ - PX_WREG(i, AHCI_PX_IE, 0xFFFFFFFF); - reg = PX_RREG(i, AHCI_PX_IE); + ahci_px_wreg(ahci, i, AHCI_PX_IE, 0xFFFFFFFF); + reg = ahci_px_rreg(ahci, i, AHCI_PX_IE); g_assert_cmphex(reg, ==, ~((uint32_t)AHCI_PX_IE_RESERVED)); /* Enable the FIS Receive Engine. */ - PX_SET(i, AHCI_PX_CMD, AHCI_PX_CMD_FRE); - reg = PX_RREG(i, AHCI_PX_CMD); + ahci_px_set(ahci, i, AHCI_PX_CMD, AHCI_PX_CMD_FRE); + reg = ahci_px_rreg(ahci, i, AHCI_PX_CMD); ASSERT_BIT_SET(reg, AHCI_PX_CMD_FR); /* AHCI 1.3 spec: if !STS.BSY, !STS.DRQ and PxSSTS.DET indicates * physical presence, a device is present and may be started. However, * PxSERR.DIAG.X /may/ need to be cleared a priori. */ - reg = PX_RREG(i, AHCI_PX_SERR); + reg = ahci_px_rreg(ahci, i, AHCI_PX_SERR); if (BITSET(reg, AHCI_PX_SERR_DIAG_X)) { - PX_SET(i, AHCI_PX_SERR, AHCI_PX_SERR_DIAG_X); + ahci_px_set(ahci, i, AHCI_PX_SERR, AHCI_PX_SERR_DIAG_X); } - reg = PX_RREG(i, AHCI_PX_TFD); + reg = ahci_px_rreg(ahci, i, AHCI_PX_TFD); if (BITCLR(reg, AHCI_PX_TFD_STS_BSY | AHCI_PX_TFD_STS_DRQ)) { - reg = PX_RREG(i, AHCI_PX_SSTS); + reg = ahci_px_rreg(ahci, i, AHCI_PX_SSTS); if ((reg & AHCI_PX_SSTS_DET) == SSTS_DET_ESTABLISHED) { /* Device Found: set PxCMD.ST := 1 */ - PX_SET(i, AHCI_PX_CMD, AHCI_PX_CMD_ST); - ASSERT_BIT_SET(PX_RREG(i, AHCI_PX_CMD), AHCI_PX_CMD_CR); + ahci_px_set(ahci, i, AHCI_PX_CMD, AHCI_PX_CMD_ST); + ASSERT_BIT_SET(ahci_px_rreg(ahci, i, AHCI_PX_CMD), + AHCI_PX_CMD_CR); g_test_message("Started Device %u", i); } else if ((reg & AHCI_PX_SSTS_DET)) { /* Device present, but in some unknown state. */ @@ -329,8 +316,8 @@ static void ahci_hba_enable(AHCIQState *ahci) } /* Enable GHC.IE */ - AHCI_SET(AHCI_GHC, AHCI_GHC_IE); - reg = AHCI_RREG(AHCI_GHC); + ahci_set(ahci, AHCI_GHC, AHCI_GHC_IE); + reg = ahci_rreg(ahci, AHCI_GHC); ASSERT_BIT_SET(reg, AHCI_GHC_IE); /* TODO: The device should now be idling and waiting for commands. @@ -602,11 +589,11 @@ static void ahci_test_hba_spec(AHCIQState *ahci) */ /* 1 CAP - Capabilities Register */ - ahci->cap = AHCI_RREG(AHCI_CAP); + ahci->cap = ahci_rreg(ahci, AHCI_CAP); ASSERT_BIT_CLEAR(ahci->cap, AHCI_CAP_RESERVED); /* 2 GHC - Global Host Control */ - reg = AHCI_RREG(AHCI_GHC); + reg = ahci_rreg(ahci, AHCI_GHC); ASSERT_BIT_CLEAR(reg, AHCI_GHC_HR); ASSERT_BIT_CLEAR(reg, AHCI_GHC_IE); ASSERT_BIT_CLEAR(reg, AHCI_GHC_MRSM); @@ -619,11 +606,11 @@ static void ahci_test_hba_spec(AHCIQState *ahci) } /* 3 IS - Interrupt Status */ - reg = AHCI_RREG(AHCI_IS); + reg = ahci_rreg(ahci, AHCI_IS); g_assert_cmphex(reg, ==, 0); /* 4 PI - Ports Implemented */ - ports = AHCI_RREG(AHCI_PI); + ports = ahci_rreg(ahci, AHCI_PI); /* Ports Implemented must be non-zero. */ g_assert_cmphex(ports, !=, 0); /* Ports Implemented must be <= Number of Ports. */ @@ -639,7 +626,7 @@ static void ahci_test_hba_spec(AHCIQState *ahci) g_assert_cmphex((reg >> maxports), ==, 0); /* 5 AHCI Version */ - reg = AHCI_RREG(AHCI_VS); + reg = ahci_rreg(ahci, AHCI_VS); switch (reg) { case AHCI_VERSION_0_95: case AHCI_VERSION_1_0: @@ -652,7 +639,7 @@ static void ahci_test_hba_spec(AHCIQState *ahci) } /* 6 Command Completion Coalescing Control: depends on CAP.CCCS. */ - reg = AHCI_RREG(AHCI_CCCCTL); + reg = ahci_rreg(ahci, AHCI_CCCCTL); if (BITSET(ahci->cap, AHCI_CAP_CCCS)) { ASSERT_BIT_CLEAR(reg, AHCI_CCCCTL_EN); ASSERT_BIT_CLEAR(reg, AHCI_CCCCTL_RESERVED); @@ -663,18 +650,18 @@ static void ahci_test_hba_spec(AHCIQState *ahci) } /* 7 CCC_PORTS */ - reg = AHCI_RREG(AHCI_CCCPORTS); + reg = ahci_rreg(ahci, AHCI_CCCPORTS); /* Must be zeroes initially regardless of CAP.CCCS */ g_assert_cmphex(reg, ==, 0); /* 8 EM_LOC */ - reg = AHCI_RREG(AHCI_EMLOC); + reg = ahci_rreg(ahci, AHCI_EMLOC); if (BITCLR(ahci->cap, AHCI_CAP_EMS)) { g_assert_cmphex(reg, ==, 0); } /* 9 EM_CTL */ - reg = AHCI_RREG(AHCI_EMCTL); + reg = ahci_rreg(ahci, AHCI_EMCTL); if (BITSET(ahci->cap, AHCI_CAP_EMS)) { ASSERT_BIT_CLEAR(reg, AHCI_EMCTL_STSMR); ASSERT_BIT_CLEAR(reg, AHCI_EMCTL_CTLTM); @@ -685,17 +672,17 @@ static void ahci_test_hba_spec(AHCIQState *ahci) } /* 10 CAP2 -- Capabilities Extended */ - ahci->cap2 = AHCI_RREG(AHCI_CAP2); + ahci->cap2 = ahci_rreg(ahci, AHCI_CAP2); ASSERT_BIT_CLEAR(ahci->cap2, AHCI_CAP2_RESERVED); /* 11 BOHC -- Bios/OS Handoff Control */ - reg = AHCI_RREG(AHCI_BOHC); + reg = ahci_rreg(ahci, AHCI_BOHC); g_assert_cmphex(reg, ==, 0); /* 12 -- 23: Reserved */ g_test_message("Verifying HBA reserved area is empty."); for (i = AHCI_RESERVED; i < AHCI_NVMHCI; ++i) { - reg = AHCI_RREG(i); + reg = ahci_rreg(ahci, i); g_assert_cmphex(reg, ==, 0); } @@ -703,7 +690,7 @@ static void ahci_test_hba_spec(AHCIQState *ahci) if (BITCLR(ahci->cap2, AHCI_CAP2_NVMP)) { g_test_message("Verifying HBA/NVMHCI area is empty."); for (i = AHCI_NVMHCI; i < AHCI_VENDOR; ++i) { - reg = AHCI_RREG(i); + reg = ahci_rreg(ahci, i); g_assert_cmphex(reg, ==, 0); } } @@ -711,7 +698,7 @@ static void ahci_test_hba_spec(AHCIQState *ahci) /* 40 -- 63: Vendor */ g_test_message("Verifying HBA/Vendor area is empty."); for (i = AHCI_VENDOR; i < AHCI_PORTS; ++i) { - reg = AHCI_RREG(i); + reg = ahci_rreg(ahci, i); g_assert_cmphex(reg, ==, 0); } @@ -728,7 +715,7 @@ static void ahci_test_hba_spec(AHCIQState *ahci) "(reg [%u-%u]) is empty.", i, low, high - 1); for (j = low; j < high; ++j) { - reg = AHCI_RREG(j); + reg = ahci_rreg(ahci, j); g_assert_cmphex(reg, ==, 0); } } @@ -744,35 +731,35 @@ static void ahci_test_port_spec(AHCIQState *ahci, uint8_t port) unsigned i; /* (0) CLB */ - reg = PX_RREG(port, AHCI_PX_CLB); + reg = ahci_px_rreg(ahci, port, AHCI_PX_CLB); ASSERT_BIT_CLEAR(reg, AHCI_PX_CLB_RESERVED); /* (1) CLBU */ if (BITCLR(ahci->cap, AHCI_CAP_S64A)) { - reg = PX_RREG(port, AHCI_PX_CLBU); + reg = ahci_px_rreg(ahci, port, AHCI_PX_CLBU); g_assert_cmphex(reg, ==, 0); } /* (2) FB */ - reg = PX_RREG(port, AHCI_PX_FB); + reg = ahci_px_rreg(ahci, port, AHCI_PX_FB); ASSERT_BIT_CLEAR(reg, AHCI_PX_FB_RESERVED); /* (3) FBU */ if (BITCLR(ahci->cap, AHCI_CAP_S64A)) { - reg = PX_RREG(port, AHCI_PX_FBU); + reg = ahci_px_rreg(ahci, port, AHCI_PX_FBU); g_assert_cmphex(reg, ==, 0); } /* (4) IS */ - reg = PX_RREG(port, AHCI_PX_IS); + reg = ahci_px_rreg(ahci, port, AHCI_PX_IS); g_assert_cmphex(reg, ==, 0); /* (5) IE */ - reg = PX_RREG(port, AHCI_PX_IE); + reg = ahci_px_rreg(ahci, port, AHCI_PX_IE); g_assert_cmphex(reg, ==, 0); /* (6) CMD */ - reg = PX_RREG(port, AHCI_PX_CMD); + reg = ahci_px_rreg(ahci, port, AHCI_PX_CMD); ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_FRE); ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_RESERVED); ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_CCS); @@ -810,11 +797,11 @@ static void ahci_test_port_spec(AHCIQState *ahci, uint8_t port) } /* (7) RESERVED */ - reg = PX_RREG(port, AHCI_PX_RES1); + reg = ahci_px_rreg(ahci, port, AHCI_PX_RES1); g_assert_cmphex(reg, ==, 0); /* (8) TFD */ - reg = PX_RREG(port, AHCI_PX_TFD); + reg = ahci_px_rreg(ahci, port, AHCI_PX_TFD); /* At boot, prior to an FIS being received, the TFD register should be 0x7F, * which breaks down as follows, as seen in AHCI 1.3 sec 3.3.8, p. 27. */ ASSERT_BIT_SET(reg, AHCI_PX_TFD_STS_ERR); @@ -832,33 +819,33 @@ static void ahci_test_port_spec(AHCIQState *ahci, uint8_t port) * so we cannot expect a value here. AHCI 1.3, sec 3.3.9, pp 27-28 */ /* (10) SSTS / SCR0: SStatus */ - reg = PX_RREG(port, AHCI_PX_SSTS); + reg = ahci_px_rreg(ahci, port, AHCI_PX_SSTS); ASSERT_BIT_CLEAR(reg, AHCI_PX_SSTS_RESERVED); /* Even though the register should be 0 at boot, it is asynchronous and * prone to change, so we cannot test any well known value. */ /* (11) SCTL / SCR2: SControl */ - reg = PX_RREG(port, AHCI_PX_SCTL); + reg = ahci_px_rreg(ahci, port, AHCI_PX_SCTL); g_assert_cmphex(reg, ==, 0); /* (12) SERR / SCR1: SError */ - reg = PX_RREG(port, AHCI_PX_SERR); + reg = ahci_px_rreg(ahci, port, AHCI_PX_SERR); g_assert_cmphex(reg, ==, 0); /* (13) SACT / SCR3: SActive */ - reg = PX_RREG(port, AHCI_PX_SACT); + reg = ahci_px_rreg(ahci, port, AHCI_PX_SACT); g_assert_cmphex(reg, ==, 0); /* (14) CI */ - reg = PX_RREG(port, AHCI_PX_CI); + reg = ahci_px_rreg(ahci, port, AHCI_PX_CI); g_assert_cmphex(reg, ==, 0); /* (15) SNTF */ - reg = PX_RREG(port, AHCI_PX_SNTF); + reg = ahci_px_rreg(ahci, port, AHCI_PX_SNTF); g_assert_cmphex(reg, ==, 0); /* (16) FBS */ - reg = PX_RREG(port, AHCI_PX_FBS); + reg = ahci_px_rreg(ahci, port, AHCI_PX_FBS); ASSERT_BIT_CLEAR(reg, AHCI_PX_FBS_EN); ASSERT_BIT_CLEAR(reg, AHCI_PX_FBS_DEC); ASSERT_BIT_CLEAR(reg, AHCI_PX_FBS_SDE); @@ -872,13 +859,13 @@ static void ahci_test_port_spec(AHCIQState *ahci, uint8_t port) /* [17 -- 27] RESERVED */ for (i = AHCI_PX_RES2; i < AHCI_PX_VS; ++i) { - reg = PX_RREG(port, i); + reg = ahci_px_rreg(ahci, port, i); g_assert_cmphex(reg, ==, 0); } /* [28 -- 31] Vendor-Specific */ for (i = AHCI_PX_VS; i < 32; ++i) { - reg = PX_RREG(port, i); + reg = ahci_px_rreg(ahci, port, i); if (reg) { g_test_message("INFO: Vendor register %u non-empty", i); } @@ -918,7 +905,7 @@ static void ahci_test_identify(AHCIQState *ahci) */ /* Pick the first implemented and running port */ - ports = AHCI_RREG(AHCI_PI); + ports = ahci_rreg(ahci, AHCI_PI); for (i = 0; i < 32; ports >>= 1, ++i) { if (ports == 0) { i = 32; @@ -928,7 +915,7 @@ static void ahci_test_identify(AHCIQState *ahci) continue; } - reg = PX_RREG(i, AHCI_PX_CMD); + reg = ahci_px_rreg(ahci, i, AHCI_PX_CMD); if (BITSET(reg, AHCI_PX_CMD_ST)) { break; } @@ -937,12 +924,12 @@ static void ahci_test_identify(AHCIQState *ahci) g_test_message("Selected port %u for test", i); /* Clear out this port's interrupts (ignore the init register d2h fis) */ - reg = PX_RREG(i, AHCI_PX_IS); - PX_WREG(i, AHCI_PX_IS, reg); - g_assert_cmphex(PX_RREG(i, AHCI_PX_IS), ==, 0); + reg = ahci_px_rreg(ahci, i, AHCI_PX_IS); + ahci_px_wreg(ahci, i, AHCI_PX_IS, reg); + g_assert_cmphex(ahci_px_rreg(ahci, i, AHCI_PX_IS), ==, 0); /* Wipe the FIS-Receive Buffer */ - fb = PX_RREG(i, AHCI_PX_FB); + fb = ahci_px_rreg(ahci, i, AHCI_PX_FB); g_assert_cmphex(fb, !=, 0); qmemset(fb, 0x00, 0x100); @@ -957,7 +944,7 @@ static void ahci_test_identify(AHCIQState *ahci) g_assert(data_ptr); /* Grab the Command List Buffer pointer */ - clb = PX_RREG(i, AHCI_PX_CLB); + clb = ahci_px_rreg(ahci, i, AHCI_PX_CLB); g_assert(clb); /* Copy the existing Command #0 structure from the CLB into local memory, @@ -985,7 +972,7 @@ static void ahci_test_identify(AHCIQState *ahci) fis.flags = 0x80; /* Indicate this is a command FIS */ /* We've committed nothing yet, no interrupts should be posted yet. */ - g_assert_cmphex(PX_RREG(i, AHCI_PX_IS), ==, 0); + g_assert_cmphex(ahci_px_rreg(ahci, i, AHCI_PX_IS), ==, 0); /* Commit the Command FIS to the Command Table */ memwrite(table, &fis, sizeof(fis)); @@ -997,29 +984,30 @@ static void ahci_test_identify(AHCIQState *ahci) memwrite(clb, &cmd, sizeof(cmd)); /* Everything is in place, but we haven't given the go-ahead yet. */ - g_assert_cmphex(PX_RREG(i, AHCI_PX_IS), ==, 0); + g_assert_cmphex(ahci_px_rreg(ahci, i, AHCI_PX_IS), ==, 0); /* Issue Command #0 via PxCI */ - PX_WREG(i, AHCI_PX_CI, (1 << 0)); - while (BITSET(PX_RREG(i, AHCI_PX_TFD), AHCI_PX_TFD_STS_BSY)) { + ahci_px_wreg(ahci, i, AHCI_PX_CI, (1 << 0)); + while (BITSET(ahci_px_rreg(ahci, i, AHCI_PX_TFD), AHCI_PX_TFD_STS_BSY)) { usleep(50); } /* Check for expected interrupts */ - reg = PX_RREG(i, AHCI_PX_IS); + reg = ahci_px_rreg(ahci, i, AHCI_PX_IS); ASSERT_BIT_SET(reg, AHCI_PX_IS_DHRS); ASSERT_BIT_SET(reg, AHCI_PX_IS_PSS); /* BUG: we expect AHCI_PX_IS_DPS to be set. */ ASSERT_BIT_CLEAR(reg, AHCI_PX_IS_DPS); /* Clear expected interrupts and assert all interrupts now cleared. */ - PX_WREG(i, AHCI_PX_IS, AHCI_PX_IS_DHRS | AHCI_PX_IS_PSS | AHCI_PX_IS_DPS); - g_assert_cmphex(PX_RREG(i, AHCI_PX_IS), ==, 0); + ahci_px_wreg(ahci, i, AHCI_PX_IS, + AHCI_PX_IS_DHRS | AHCI_PX_IS_PSS | AHCI_PX_IS_DPS); + g_assert_cmphex(ahci_px_rreg(ahci, i, AHCI_PX_IS), ==, 0); /* Check for errors. */ - reg = PX_RREG(i, AHCI_PX_SERR); + reg = ahci_px_rreg(ahci, i, AHCI_PX_SERR); g_assert_cmphex(reg, ==, 0); - reg = PX_RREG(i, AHCI_PX_TFD); + reg = ahci_px_rreg(ahci, i, AHCI_PX_TFD); ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_STS_ERR); ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_ERR); @@ -1036,7 +1024,7 @@ static void ahci_test_identify(AHCIQState *ahci) g_assert_cmphex(pio->status, ==, d2h->status); g_assert_cmphex(pio->error, ==, d2h->error); - reg = PX_RREG(i, AHCI_PX_TFD); + reg = ahci_px_rreg(ahci, i, AHCI_PX_TFD); g_assert_cmphex((reg & AHCI_PX_TFD_ERR), ==, pio->error); g_assert_cmphex((reg & AHCI_PX_TFD_STS), ==, pio->status); /* The PIO Setup FIS contains a "bytes read" field, which is a -- cgit v1.2.3 From f3dd2da4cc8c17921cb50920600adafb02959abf Mon Sep 17 00:00:00 2001 From: John Snow <jsnow@redhat.com> Date: Mon, 19 Jan 2015 15:16:02 -0500 Subject: qtest/ahci: Bookmark FB and CLB pointers Instead of re-querying the AHCI device for the FB and CLB buffers, save the pointer we gave to the device during initialization and reference these values instead. [Peter Maydell <peter.maydell@linaro.org> reported the following clang compiler warnings: tests/libqos/ahci.c:256:40: warning: format specifies type 'unsigned long' but the argument has type 'uint64_t' (aka 'unsigned long long') [-Wformat] g_test_message("CLB: 0x%08lx", ahci->port[i].clb); tests/libqos/ahci.c:264:39: warning: format specifies type 'unsigned long' but the argument has type 'uint64_t' (aka 'unsigned long long') [-Wformat] g_test_message("FB: 0x%08lx", ahci->port[i].fb); The commit moved from uint32_t to uint64_t, so PRIx64 should be used for the format specifier. --Stefan] Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Message-id: 1421698563-6977-15-git-send-email-jsnow@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/ahci-test.c | 42 ++++++++++++++++++++---------------------- tests/libqos/ahci.h | 6 ++++++ 2 files changed, 26 insertions(+), 22 deletions(-) (limited to 'tests') diff --git a/tests/ahci-test.c b/tests/ahci-test.c index aa1f66f012..a0a77763a2 100644 --- a/tests/ahci-test.c +++ b/tests/ahci-test.c @@ -206,7 +206,7 @@ static void ahci_hba_enable(AHCIQState *ahci) * PxCMD.FR "FIS Receive Running" * PxCMD.CR "Command List Running" */ - uint32_t reg, ports_impl, clb, fb; + uint32_t reg, ports_impl; uint16_t i; uint8_t num_cmd_slots; @@ -255,16 +255,20 @@ static void ahci_hba_enable(AHCIQState *ahci) /* Allocate Memory for the Command List Buffer & FIS Buffer */ /* PxCLB space ... 0x20 per command, as in 4.2.2 p 36 */ - clb = ahci_alloc(ahci, num_cmd_slots * 0x20); - g_test_message("CLB: 0x%08x", clb); - ahci_px_wreg(ahci, i, AHCI_PX_CLB, clb); - g_assert_cmphex(clb, ==, ahci_px_rreg(ahci, i, AHCI_PX_CLB)); + ahci->port[i].clb = ahci_alloc(ahci, num_cmd_slots * 0x20); + qmemset(ahci->port[i].clb, 0x00, 0x100); + g_test_message("CLB: 0x%08" PRIx64, ahci->port[i].clb); + ahci_px_wreg(ahci, i, AHCI_PX_CLB, ahci->port[i].clb); + g_assert_cmphex(ahci->port[i].clb, ==, + ahci_px_rreg(ahci, i, AHCI_PX_CLB)); /* PxFB space ... 0x100, as in 4.2.1 p 35 */ - fb = ahci_alloc(ahci, 0x100); - g_test_message("FB: 0x%08x", fb); - ahci_px_wreg(ahci, i, AHCI_PX_FB, fb); - g_assert_cmphex(fb, ==, ahci_px_rreg(ahci, i, AHCI_PX_FB)); + ahci->port[i].fb = ahci_alloc(ahci, 0x100); + qmemset(ahci->port[i].fb, 0x00, 0x100); + g_test_message("FB: 0x%08" PRIx64, ahci->port[i].fb); + ahci_px_wreg(ahci, i, AHCI_PX_FB, ahci->port[i].fb); + g_assert_cmphex(ahci->port[i].fb, ==, + ahci_px_rreg(ahci, i, AHCI_PX_FB)); /* Clear PxSERR, PxIS, then IS.IPS[x] by writing '1's. */ ahci_px_wreg(ahci, i, AHCI_PX_SERR, 0xFFFFFFFF); @@ -883,7 +887,7 @@ static void ahci_test_identify(AHCIQState *ahci) RegH2DFIS fis; AHCICommand cmd; PRD prd; - uint32_t ports, reg, clb, table, fb, data_ptr; + uint32_t ports, reg, table, data_ptr; uint16_t buff[256]; unsigned i; int rc; @@ -929,9 +933,7 @@ static void ahci_test_identify(AHCIQState *ahci) g_assert_cmphex(ahci_px_rreg(ahci, i, AHCI_PX_IS), ==, 0); /* Wipe the FIS-Receive Buffer */ - fb = ahci_px_rreg(ahci, i, AHCI_PX_FB); - g_assert_cmphex(fb, !=, 0); - qmemset(fb, 0x00, 0x100); + qmemset(ahci->port[i].fb, 0x00, 0x100); /* Create a Command Table buffer. 0x80 is the smallest with a PRDTL of 0. */ /* We need at least one PRD, so round up to the nearest 0x80 multiple. */ @@ -943,13 +945,9 @@ static void ahci_test_identify(AHCIQState *ahci) data_ptr = ahci_alloc(ahci, 512); g_assert(data_ptr); - /* Grab the Command List Buffer pointer */ - clb = ahci_px_rreg(ahci, i, AHCI_PX_CLB); - g_assert(clb); - /* Copy the existing Command #0 structure from the CLB into local memory, * and build a new command #0. */ - memread(clb, &cmd, sizeof(cmd)); + memread(ahci->port[i].clb, &cmd, sizeof(cmd)); cmd.b1 = 5; /* reg_h2d_fis is 5 double-words long */ cmd.b2 = 0x04; /* clear PxTFD.STS.BSY when done */ cmd.prdtl = cpu_to_le16(1); /* One PRD table entry. */ @@ -981,7 +979,7 @@ static void ahci_test_identify(AHCIQState *ahci) memwrite(table + 0x80, &prd, sizeof(prd)); /* Commit Command #0, pointing to the Table, to the Command List Buffer. */ - memwrite(clb, &cmd, sizeof(cmd)); + memwrite(ahci->port[i].clb, &cmd, sizeof(cmd)); /* Everything is in place, but we haven't given the go-ahead yet. */ g_assert_cmphex(ahci_px_rreg(ahci, i, AHCI_PX_IS), ==, 0); @@ -1012,12 +1010,12 @@ static void ahci_test_identify(AHCIQState *ahci) ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_ERR); /* Investigate CMD #0, assert that we read 512 bytes */ - memread(clb, &cmd, sizeof(cmd)); + memread(ahci->port[i].clb, &cmd, sizeof(cmd)); g_assert_cmphex(512, ==, le32_to_cpu(cmd.prdbc)); /* Investigate FIS responses */ - memread(fb + 0x20, pio, 0x20); - memread(fb + 0x40, d2h, 0x20); + memread(ahci->port[i].fb + 0x20, pio, 0x20); + memread(ahci->port[i].fb + 0x40, d2h, 0x20); g_assert_cmphex(pio->fis_type, ==, 0x5f); g_assert_cmphex(d2h->fis_type, ==, 0x34); g_assert_cmphex(pio->flags, ==, d2h->flags); diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h index 645f05b9c4..72c39bcefa 100644 --- a/tests/libqos/ahci.h +++ b/tests/libqos/ahci.h @@ -245,6 +245,11 @@ /*** Structures ***/ +typedef struct AHCIPortQState { + uint64_t fb; + uint64_t clb; +} AHCIPortQState; + typedef struct AHCIQState { QOSState *parent; QPCIDevice *dev; @@ -253,6 +258,7 @@ typedef struct AHCIQState { uint32_t fingerprint; uint32_t cap; uint32_t cap2; + AHCIPortQState port[32]; } AHCIQState; /** -- cgit v1.2.3 From 9a75b0a037e3a8030992244353f17b62f6daf2ab Mon Sep 17 00:00:00 2001 From: John Snow <jsnow@redhat.com> Date: Mon, 19 Jan 2015 15:16:03 -0500 Subject: libqos/ahci: create libqos/ahci.c With global state removed, code responsible for booting up, verifying, and initializing the AHCI HBA is extracted and inserted into libqos/ahci.c, which would allow for other qtests in the future to quickly grab a meaningfully initialized reference to an AHCI HBA. Even without other users, functionalizing and isolating the code assists future AHCI tests that exercise Q35 migration. For now, libqos/ahci.o will be PC-only, but can be expanded into something arch-agnostic in the future, if needed. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Message-id: 1421698563-6977-16-git-send-email-jsnow@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/Makefile | 1 + tests/ahci-test.c | 225 ------------------------------------------- tests/libqos/ahci.c | 269 ++++++++++++++++++++++++++++++++++++++++++++++++++++ tests/libqos/ahci.h | 11 ++- 4 files changed, 280 insertions(+), 226 deletions(-) create mode 100644 tests/libqos/ahci.c (limited to 'tests') diff --git a/tests/Makefile b/tests/Makefile index 415498cbaa..53a4c30641 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -310,6 +310,7 @@ libqos-obj-y = tests/libqos/pci.o tests/libqos/fw_cfg.o tests/libqos/malloc.o libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o +libqos-pc-obj-y += tests/libqos/ahci.o libqos-omap-obj-y = $(libqos-obj-y) tests/libqos/i2c-omap.o libqos-virtio-obj-y = $(libqos-obj-y) $(libqos-pc-obj-y) tests/libqos/virtio.o tests/libqos/virtio-pci.o libqos-usb-obj-y = $(libqos-pc-obj-y) tests/libqos/usb.o diff --git a/tests/ahci-test.c b/tests/ahci-test.c index a0a77763a2..fca33d2998 100644 --- a/tests/ahci-test.c +++ b/tests/ahci-test.c @@ -47,10 +47,6 @@ static char tmp_path[] = "/tmp/qtest.XXXXXX"; static bool ahci_pedantic; /*** Function Declarations ***/ -static QPCIDevice *get_ahci_device(uint32_t *fingerprint); -static void start_ahci_device(AHCIQState *ahci); -static void free_ahci_device(QPCIDevice *dev); - static void ahci_test_port_spec(AHCIQState *ahci, uint8_t port); static void ahci_test_pci_spec(AHCIQState *ahci); static void ahci_test_pci_caps(AHCIQState *ahci, uint16_t header, @@ -72,51 +68,6 @@ static void string_bswap16(uint16_t *s, size_t bytes) } } -static uint64_t ahci_alloc(AHCIQState *ahci, size_t bytes) -{ - return qmalloc(ahci->parent, bytes); -} - -/** - * Locate, verify, and return a handle to the AHCI device. - */ -static QPCIDevice *get_ahci_device(uint32_t *fingerprint) -{ - QPCIDevice *ahci; - uint32_t ahci_fingerprint; - QPCIBus *pcibus; - - pcibus = qpci_init_pc(); - - /* Find the AHCI PCI device and verify it's the right one. */ - ahci = qpci_device_find(pcibus, QPCI_DEVFN(0x1F, 0x02)); - g_assert(ahci != NULL); - - ahci_fingerprint = qpci_config_readl(ahci, PCI_VENDOR_ID); - - switch (ahci_fingerprint) { - case AHCI_INTEL_ICH9: - break; - default: - /* Unknown device. */ - g_assert_not_reached(); - } - - if (fingerprint) { - *fingerprint = ahci_fingerprint; - } - return ahci; -} - -static void free_ahci_device(QPCIDevice *dev) -{ - QPCIBus *pcibus = dev ? dev->bus : NULL; - - /* libqos doesn't have a function for this, so free it manually */ - g_free(dev); - qpci_free_pc(pcibus); -} - /*** Test Setup & Teardown ***/ /** @@ -153,182 +104,6 @@ static void ahci_shutdown(AHCIQState *ahci) qtest_shutdown(qs); } -/*** Logical Device Initialization ***/ - -/** - * Start the PCI device and sanity-check default operation. - */ -static void ahci_pci_enable(AHCIQState *ahci) -{ - uint8_t reg; - - start_ahci_device(ahci); - - switch (ahci->fingerprint) { - case AHCI_INTEL_ICH9: - /* ICH9 has a register at PCI 0x92 that - * acts as a master port enabler mask. */ - reg = qpci_config_readb(ahci->dev, 0x92); - reg |= 0x3F; - qpci_config_writeb(ahci->dev, 0x92, reg); - /* 0...0111111b -- bit significant, ports 0-5 enabled. */ - ASSERT_BIT_SET(qpci_config_readb(ahci->dev, 0x92), 0x3F); - break; - } - -} - -/** - * Map BAR5/ABAR, and engage the PCI device. - */ -static void start_ahci_device(AHCIQState *ahci) -{ - /* Map AHCI's ABAR (BAR5) */ - ahci->hba_base = qpci_iomap(ahci->dev, 5, &ahci->barsize); - - /* turns on pci.cmd.iose, pci.cmd.mse and pci.cmd.bme */ - qpci_device_enable(ahci->dev); -} - -/** - * Test and initialize the AHCI's HBA memory areas. - * Initialize and start any ports with devices attached. - * Bring the HBA into the idle state. - */ -static void ahci_hba_enable(AHCIQState *ahci) -{ - /* Bits of interest in this section: - * GHC.AE Global Host Control / AHCI Enable - * PxCMD.ST Port Command: Start - * PxCMD.SUD "Spin Up Device" - * PxCMD.POD "Power On Device" - * PxCMD.FRE "FIS Receive Enable" - * PxCMD.FR "FIS Receive Running" - * PxCMD.CR "Command List Running" - */ - uint32_t reg, ports_impl; - uint16_t i; - uint8_t num_cmd_slots; - - g_assert(ahci != NULL); - - /* Set GHC.AE to 1 */ - ahci_set(ahci, AHCI_GHC, AHCI_GHC_AE); - reg = ahci_rreg(ahci, AHCI_GHC); - ASSERT_BIT_SET(reg, AHCI_GHC_AE); - - /* Cache CAP and CAP2. */ - ahci->cap = ahci_rreg(ahci, AHCI_CAP); - ahci->cap2 = ahci_rreg(ahci, AHCI_CAP2); - - /* Read CAP.NCS, how many command slots do we have? */ - num_cmd_slots = ((ahci->cap & AHCI_CAP_NCS) >> ctzl(AHCI_CAP_NCS)) + 1; - g_test_message("Number of Command Slots: %u", num_cmd_slots); - - /* Determine which ports are implemented. */ - ports_impl = ahci_rreg(ahci, AHCI_PI); - - for (i = 0; ports_impl; ports_impl >>= 1, ++i) { - if (!(ports_impl & 0x01)) { - continue; - } - - g_test_message("Initializing port %u", i); - - reg = ahci_px_rreg(ahci, i, AHCI_PX_CMD); - if (BITCLR(reg, AHCI_PX_CMD_ST | AHCI_PX_CMD_CR | - AHCI_PX_CMD_FRE | AHCI_PX_CMD_FR)) { - g_test_message("port is idle"); - } else { - g_test_message("port needs to be idled"); - ahci_px_clr(ahci, i, AHCI_PX_CMD, - (AHCI_PX_CMD_ST | AHCI_PX_CMD_FRE)); - /* The port has 500ms to disengage. */ - usleep(500000); - reg = ahci_px_rreg(ahci, i, AHCI_PX_CMD); - ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_CR); - ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_FR); - g_test_message("port is now idle"); - /* The spec does allow for possibly needing a PORT RESET - * or HBA reset if we fail to idle the port. */ - } - - /* Allocate Memory for the Command List Buffer & FIS Buffer */ - /* PxCLB space ... 0x20 per command, as in 4.2.2 p 36 */ - ahci->port[i].clb = ahci_alloc(ahci, num_cmd_slots * 0x20); - qmemset(ahci->port[i].clb, 0x00, 0x100); - g_test_message("CLB: 0x%08" PRIx64, ahci->port[i].clb); - ahci_px_wreg(ahci, i, AHCI_PX_CLB, ahci->port[i].clb); - g_assert_cmphex(ahci->port[i].clb, ==, - ahci_px_rreg(ahci, i, AHCI_PX_CLB)); - - /* PxFB space ... 0x100, as in 4.2.1 p 35 */ - ahci->port[i].fb = ahci_alloc(ahci, 0x100); - qmemset(ahci->port[i].fb, 0x00, 0x100); - g_test_message("FB: 0x%08" PRIx64, ahci->port[i].fb); - ahci_px_wreg(ahci, i, AHCI_PX_FB, ahci->port[i].fb); - g_assert_cmphex(ahci->port[i].fb, ==, - ahci_px_rreg(ahci, i, AHCI_PX_FB)); - - /* Clear PxSERR, PxIS, then IS.IPS[x] by writing '1's. */ - ahci_px_wreg(ahci, i, AHCI_PX_SERR, 0xFFFFFFFF); - ahci_px_wreg(ahci, i, AHCI_PX_IS, 0xFFFFFFFF); - ahci_wreg(ahci, AHCI_IS, (1 << i)); - - /* Verify Interrupts Cleared */ - reg = ahci_px_rreg(ahci, i, AHCI_PX_SERR); - g_assert_cmphex(reg, ==, 0); - - reg = ahci_px_rreg(ahci, i, AHCI_PX_IS); - g_assert_cmphex(reg, ==, 0); - - reg = ahci_rreg(ahci, AHCI_IS); - ASSERT_BIT_CLEAR(reg, (1 << i)); - - /* Enable All Interrupts: */ - ahci_px_wreg(ahci, i, AHCI_PX_IE, 0xFFFFFFFF); - reg = ahci_px_rreg(ahci, i, AHCI_PX_IE); - g_assert_cmphex(reg, ==, ~((uint32_t)AHCI_PX_IE_RESERVED)); - - /* Enable the FIS Receive Engine. */ - ahci_px_set(ahci, i, AHCI_PX_CMD, AHCI_PX_CMD_FRE); - reg = ahci_px_rreg(ahci, i, AHCI_PX_CMD); - ASSERT_BIT_SET(reg, AHCI_PX_CMD_FR); - - /* AHCI 1.3 spec: if !STS.BSY, !STS.DRQ and PxSSTS.DET indicates - * physical presence, a device is present and may be started. However, - * PxSERR.DIAG.X /may/ need to be cleared a priori. */ - reg = ahci_px_rreg(ahci, i, AHCI_PX_SERR); - if (BITSET(reg, AHCI_PX_SERR_DIAG_X)) { - ahci_px_set(ahci, i, AHCI_PX_SERR, AHCI_PX_SERR_DIAG_X); - } - - reg = ahci_px_rreg(ahci, i, AHCI_PX_TFD); - if (BITCLR(reg, AHCI_PX_TFD_STS_BSY | AHCI_PX_TFD_STS_DRQ)) { - reg = ahci_px_rreg(ahci, i, AHCI_PX_SSTS); - if ((reg & AHCI_PX_SSTS_DET) == SSTS_DET_ESTABLISHED) { - /* Device Found: set PxCMD.ST := 1 */ - ahci_px_set(ahci, i, AHCI_PX_CMD, AHCI_PX_CMD_ST); - ASSERT_BIT_SET(ahci_px_rreg(ahci, i, AHCI_PX_CMD), - AHCI_PX_CMD_CR); - g_test_message("Started Device %u", i); - } else if ((reg & AHCI_PX_SSTS_DET)) { - /* Device present, but in some unknown state. */ - g_assert_not_reached(); - } - } - } - - /* Enable GHC.IE */ - ahci_set(ahci, AHCI_GHC, AHCI_GHC_IE); - reg = ahci_rreg(ahci, AHCI_GHC); - ASSERT_BIT_SET(reg, AHCI_GHC_IE); - - /* TODO: The device should now be idling and waiting for commands. - * In the future, a small test-case to inspect the Register D2H FIS - * and clear the initial interrupts might be good. */ -} - /*** Specification Adherence Tests ***/ /** diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c new file mode 100644 index 0000000000..5164d42450 --- /dev/null +++ b/tests/libqos/ahci.c @@ -0,0 +1,269 @@ +/* + * libqos AHCI functions + * + * Copyright (c) 2014 John Snow <jsnow@redhat.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <glib.h> + +#include "libqtest.h" +#include "libqos/ahci.h" +#include "libqos/pci-pc.h" + +#include "qemu-common.h" +#include "qemu/host-utils.h" + +#include "hw/pci/pci_ids.h" +#include "hw/pci/pci_regs.h" + +/** + * Allocate space in the guest using information in the AHCIQState object. + */ +uint64_t ahci_alloc(AHCIQState *ahci, size_t bytes) +{ + g_assert(ahci); + g_assert(ahci->parent); + return qmalloc(ahci->parent, bytes); +} + +void ahci_free(AHCIQState *ahci, uint64_t addr) +{ + g_assert(ahci); + g_assert(ahci->parent); + qfree(ahci->parent, addr); +} + +/** + * Locate, verify, and return a handle to the AHCI device. + */ +QPCIDevice *get_ahci_device(uint32_t *fingerprint) +{ + QPCIDevice *ahci; + uint32_t ahci_fingerprint; + QPCIBus *pcibus; + + pcibus = qpci_init_pc(); + + /* Find the AHCI PCI device and verify it's the right one. */ + ahci = qpci_device_find(pcibus, QPCI_DEVFN(0x1F, 0x02)); + g_assert(ahci != NULL); + + ahci_fingerprint = qpci_config_readl(ahci, PCI_VENDOR_ID); + + switch (ahci_fingerprint) { + case AHCI_INTEL_ICH9: + break; + default: + /* Unknown device. */ + g_assert_not_reached(); + } + + if (fingerprint) { + *fingerprint = ahci_fingerprint; + } + return ahci; +} + +void free_ahci_device(QPCIDevice *dev) +{ + QPCIBus *pcibus = dev ? dev->bus : NULL; + + /* libqos doesn't have a function for this, so free it manually */ + g_free(dev); + qpci_free_pc(pcibus); +} + +/*** Logical Device Initialization ***/ + +/** + * Start the PCI device and sanity-check default operation. + */ +void ahci_pci_enable(AHCIQState *ahci) +{ + uint8_t reg; + + start_ahci_device(ahci); + + switch (ahci->fingerprint) { + case AHCI_INTEL_ICH9: + /* ICH9 has a register at PCI 0x92 that + * acts as a master port enabler mask. */ + reg = qpci_config_readb(ahci->dev, 0x92); + reg |= 0x3F; + qpci_config_writeb(ahci->dev, 0x92, reg); + /* 0...0111111b -- bit significant, ports 0-5 enabled. */ + ASSERT_BIT_SET(qpci_config_readb(ahci->dev, 0x92), 0x3F); + break; + } + +} + +/** + * Map BAR5/ABAR, and engage the PCI device. + */ +void start_ahci_device(AHCIQState *ahci) +{ + /* Map AHCI's ABAR (BAR5) */ + ahci->hba_base = qpci_iomap(ahci->dev, 5, &ahci->barsize); + g_assert(ahci->hba_base); + + /* turns on pci.cmd.iose, pci.cmd.mse and pci.cmd.bme */ + qpci_device_enable(ahci->dev); +} + +/** + * Test and initialize the AHCI's HBA memory areas. + * Initialize and start any ports with devices attached. + * Bring the HBA into the idle state. + */ +void ahci_hba_enable(AHCIQState *ahci) +{ + /* Bits of interest in this section: + * GHC.AE Global Host Control / AHCI Enable + * PxCMD.ST Port Command: Start + * PxCMD.SUD "Spin Up Device" + * PxCMD.POD "Power On Device" + * PxCMD.FRE "FIS Receive Enable" + * PxCMD.FR "FIS Receive Running" + * PxCMD.CR "Command List Running" + */ + uint32_t reg, ports_impl; + uint16_t i; + uint8_t num_cmd_slots; + + g_assert(ahci != NULL); + + /* Set GHC.AE to 1 */ + ahci_set(ahci, AHCI_GHC, AHCI_GHC_AE); + reg = ahci_rreg(ahci, AHCI_GHC); + ASSERT_BIT_SET(reg, AHCI_GHC_AE); + + /* Cache CAP and CAP2. */ + ahci->cap = ahci_rreg(ahci, AHCI_CAP); + ahci->cap2 = ahci_rreg(ahci, AHCI_CAP2); + + /* Read CAP.NCS, how many command slots do we have? */ + num_cmd_slots = ((ahci->cap & AHCI_CAP_NCS) >> ctzl(AHCI_CAP_NCS)) + 1; + g_test_message("Number of Command Slots: %u", num_cmd_slots); + + /* Determine which ports are implemented. */ + ports_impl = ahci_rreg(ahci, AHCI_PI); + + for (i = 0; ports_impl; ports_impl >>= 1, ++i) { + if (!(ports_impl & 0x01)) { + continue; + } + + g_test_message("Initializing port %u", i); + + reg = ahci_px_rreg(ahci, i, AHCI_PX_CMD); + if (BITCLR(reg, AHCI_PX_CMD_ST | AHCI_PX_CMD_CR | + AHCI_PX_CMD_FRE | AHCI_PX_CMD_FR)) { + g_test_message("port is idle"); + } else { + g_test_message("port needs to be idled"); + ahci_px_clr(ahci, i, AHCI_PX_CMD, + (AHCI_PX_CMD_ST | AHCI_PX_CMD_FRE)); + /* The port has 500ms to disengage. */ + usleep(500000); + reg = ahci_px_rreg(ahci, i, AHCI_PX_CMD); + ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_CR); + ASSERT_BIT_CLEAR(reg, AHCI_PX_CMD_FR); + g_test_message("port is now idle"); + /* The spec does allow for possibly needing a PORT RESET + * or HBA reset if we fail to idle the port. */ + } + + /* Allocate Memory for the Command List Buffer & FIS Buffer */ + /* PxCLB space ... 0x20 per command, as in 4.2.2 p 36 */ + ahci->port[i].clb = ahci_alloc(ahci, num_cmd_slots * 0x20); + qmemset(ahci->port[i].clb, 0x00, 0x100); + g_test_message("CLB: 0x%08" PRIx64, ahci->port[i].clb); + ahci_px_wreg(ahci, i, AHCI_PX_CLB, ahci->port[i].clb); + g_assert_cmphex(ahci->port[i].clb, ==, + ahci_px_rreg(ahci, i, AHCI_PX_CLB)); + + /* PxFB space ... 0x100, as in 4.2.1 p 35 */ + ahci->port[i].fb = ahci_alloc(ahci, 0x100); + qmemset(ahci->port[i].fb, 0x00, 0x100); + g_test_message("FB: 0x%08" PRIx64, ahci->port[i].fb); + ahci_px_wreg(ahci, i, AHCI_PX_FB, ahci->port[i].fb); + g_assert_cmphex(ahci->port[i].fb, ==, + ahci_px_rreg(ahci, i, AHCI_PX_FB)); + + /* Clear PxSERR, PxIS, then IS.IPS[x] by writing '1's. */ + ahci_px_wreg(ahci, i, AHCI_PX_SERR, 0xFFFFFFFF); + ahci_px_wreg(ahci, i, AHCI_PX_IS, 0xFFFFFFFF); + ahci_wreg(ahci, AHCI_IS, (1 << i)); + + /* Verify Interrupts Cleared */ + reg = ahci_px_rreg(ahci, i, AHCI_PX_SERR); + g_assert_cmphex(reg, ==, 0); + + reg = ahci_px_rreg(ahci, i, AHCI_PX_IS); + g_assert_cmphex(reg, ==, 0); + + reg = ahci_rreg(ahci, AHCI_IS); + ASSERT_BIT_CLEAR(reg, (1 << i)); + + /* Enable All Interrupts: */ + ahci_px_wreg(ahci, i, AHCI_PX_IE, 0xFFFFFFFF); + reg = ahci_px_rreg(ahci, i, AHCI_PX_IE); + g_assert_cmphex(reg, ==, ~((uint32_t)AHCI_PX_IE_RESERVED)); + + /* Enable the FIS Receive Engine. */ + ahci_px_set(ahci, i, AHCI_PX_CMD, AHCI_PX_CMD_FRE); + reg = ahci_px_rreg(ahci, i, AHCI_PX_CMD); + ASSERT_BIT_SET(reg, AHCI_PX_CMD_FR); + + /* AHCI 1.3 spec: if !STS.BSY, !STS.DRQ and PxSSTS.DET indicates + * physical presence, a device is present and may be started. However, + * PxSERR.DIAG.X /may/ need to be cleared a priori. */ + reg = ahci_px_rreg(ahci, i, AHCI_PX_SERR); + if (BITSET(reg, AHCI_PX_SERR_DIAG_X)) { + ahci_px_set(ahci, i, AHCI_PX_SERR, AHCI_PX_SERR_DIAG_X); + } + + reg = ahci_px_rreg(ahci, i, AHCI_PX_TFD); + if (BITCLR(reg, AHCI_PX_TFD_STS_BSY | AHCI_PX_TFD_STS_DRQ)) { + reg = ahci_px_rreg(ahci, i, AHCI_PX_SSTS); + if ((reg & AHCI_PX_SSTS_DET) == SSTS_DET_ESTABLISHED) { + /* Device Found: set PxCMD.ST := 1 */ + ahci_px_set(ahci, i, AHCI_PX_CMD, AHCI_PX_CMD_ST); + ASSERT_BIT_SET(ahci_px_rreg(ahci, i, AHCI_PX_CMD), + AHCI_PX_CMD_CR); + g_test_message("Started Device %u", i); + } else if ((reg & AHCI_PX_SSTS_DET)) { + /* Device present, but in some unknown state. */ + g_assert_not_reached(); + } + } + } + + /* Enable GHC.IE */ + ahci_set(ahci, AHCI_GHC, AHCI_GHC_IE); + reg = ahci_rreg(ahci, AHCI_GHC); + ASSERT_BIT_SET(reg, AHCI_GHC_IE); + + /* TODO: The device should now be idling and waiting for commands. + * In the future, a small test-case to inspect the Register D2H FIS + * and clear the initial interrupts might be good. */ +} diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h index 72c39bcefa..77f205590e 100644 --- a/tests/libqos/ahci.h +++ b/tests/libqos/ahci.h @@ -28,7 +28,7 @@ #include <stdint.h> #include <stdlib.h> #include <stdbool.h> - +#include "libqos/libqos.h" #include "libqos/pci.h" #include "libqos/malloc-pc.h" @@ -423,4 +423,13 @@ static inline void ahci_px_clr(AHCIQState *ahci, uint8_t port, ahci_px_rreg(ahci, port, reg_num) & ~mask); } +/*** Prototypes ***/ +uint64_t ahci_alloc(AHCIQState *ahci, size_t bytes); +void ahci_free(AHCIQState *ahci, uint64_t addr); +QPCIDevice *get_ahci_device(uint32_t *fingerprint); +void free_ahci_device(QPCIDevice *dev); +void ahci_pci_enable(AHCIQState *ahci); +void start_ahci_device(AHCIQState *ahci); +void ahci_hba_enable(AHCIQState *ahci); + #endif -- cgit v1.2.3 From e77448a385dc72fa671752ec11c84c931f316d09 Mon Sep 17 00:00:00 2001 From: John Snow <jsnow@redhat.com> Date: Thu, 5 Feb 2015 12:41:12 -0500 Subject: libqos/ahci: Add ahci_port_select helper This helper identifies which port of the AHCI HBA has a device we may run tests on. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Message-id: 1423158090-25580-2-git-send-email-jsnow@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/ahci-test.c | 19 ++----------------- tests/libqos/ahci.c | 27 +++++++++++++++++++++++++++ tests/libqos/ahci.h | 1 + 3 files changed, 30 insertions(+), 17 deletions(-) (limited to 'tests') diff --git a/tests/ahci-test.c b/tests/ahci-test.c index fca33d2998..c689b62fc0 100644 --- a/tests/ahci-test.c +++ b/tests/ahci-test.c @@ -662,7 +662,7 @@ static void ahci_test_identify(AHCIQState *ahci) RegH2DFIS fis; AHCICommand cmd; PRD prd; - uint32_t ports, reg, table, data_ptr; + uint32_t reg, table, data_ptr; uint16_t buff[256]; unsigned i; int rc; @@ -684,22 +684,7 @@ static void ahci_test_identify(AHCIQState *ahci) */ /* Pick the first implemented and running port */ - ports = ahci_rreg(ahci, AHCI_PI); - for (i = 0; i < 32; ports >>= 1, ++i) { - if (ports == 0) { - i = 32; - } - - if (!(ports & 0x01)) { - continue; - } - - reg = ahci_px_rreg(ahci, i, AHCI_PX_CMD); - if (BITSET(reg, AHCI_PX_CMD_ST)) { - break; - } - } - g_assert_cmphex(i, <, 32); + i = ahci_port_select(ahci); g_test_message("Selected port %u for test", i); /* Clear out this port's interrupts (ignore the init register d2h fis) */ diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c index 5164d42450..7ea55f90b7 100644 --- a/tests/libqos/ahci.c +++ b/tests/libqos/ahci.c @@ -267,3 +267,30 @@ void ahci_hba_enable(AHCIQState *ahci) * In the future, a small test-case to inspect the Register D2H FIS * and clear the initial interrupts might be good. */ } + +/** + * Pick the first implemented and running port + */ +unsigned ahci_port_select(AHCIQState *ahci) +{ + uint32_t ports, reg; + unsigned i; + + ports = ahci_rreg(ahci, AHCI_PI); + for (i = 0; i < 32; ports >>= 1, ++i) { + if (ports == 0) { + i = 32; + } + + if (!(ports & 0x01)) { + continue; + } + + reg = ahci_px_rreg(ahci, i, AHCI_PX_CMD); + if (BITSET(reg, AHCI_PX_CMD_ST)) { + break; + } + } + g_assert(i < 32); + return i; +} diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h index 77f205590e..b3992e19e5 100644 --- a/tests/libqos/ahci.h +++ b/tests/libqos/ahci.h @@ -431,5 +431,6 @@ void free_ahci_device(QPCIDevice *dev); void ahci_pci_enable(AHCIQState *ahci); void start_ahci_device(AHCIQState *ahci); void ahci_hba_enable(AHCIQState *ahci); +unsigned ahci_port_select(AHCIQState *ahci); #endif -- cgit v1.2.3 From e83fd96bfab90298beaa8c8a31e48a905564180e Mon Sep 17 00:00:00 2001 From: John Snow <jsnow@redhat.com> Date: Thu, 5 Feb 2015 12:41:13 -0500 Subject: libqos/ahci: Add ahci_port_clear helper Add a helper that assists in clearing out potentially old error and FIS information from an AHCI port's data structures. This ensures we always start with a blank slate for interrupt and FIS receipt information. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Message-id: 1423158090-25580-3-git-send-email-jsnow@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/ahci-test.c | 9 ++------- tests/libqos/ahci.c | 16 ++++++++++++++++ tests/libqos/ahci.h | 1 + 3 files changed, 19 insertions(+), 7 deletions(-) (limited to 'tests') diff --git a/tests/ahci-test.c b/tests/ahci-test.c index c689b62fc0..90647f2a0c 100644 --- a/tests/ahci-test.c +++ b/tests/ahci-test.c @@ -687,13 +687,8 @@ static void ahci_test_identify(AHCIQState *ahci) i = ahci_port_select(ahci); g_test_message("Selected port %u for test", i); - /* Clear out this port's interrupts (ignore the init register d2h fis) */ - reg = ahci_px_rreg(ahci, i, AHCI_PX_IS); - ahci_px_wreg(ahci, i, AHCI_PX_IS, reg); - g_assert_cmphex(ahci_px_rreg(ahci, i, AHCI_PX_IS), ==, 0); - - /* Wipe the FIS-Receive Buffer */ - qmemset(ahci->port[i].fb, 0x00, 0x100); + /* Clear out the FIS Receive area and any pending interrupts. */ + ahci_port_clear(ahci, i); /* Create a Command Table buffer. 0x80 is the smallest with a PRDTL of 0. */ /* We need at least one PRD, so round up to the nearest 0x80 multiple. */ diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c index 7ea55f90b7..3b1b9ba499 100644 --- a/tests/libqos/ahci.c +++ b/tests/libqos/ahci.c @@ -294,3 +294,19 @@ unsigned ahci_port_select(AHCIQState *ahci) g_assert(i < 32); return i; } + +/** + * Clear a port's interrupts and status information prior to a test. + */ +void ahci_port_clear(AHCIQState *ahci, uint8_t port) +{ + uint32_t reg; + + /* Clear out this port's interrupts (ignore the init register d2h fis) */ + reg = ahci_px_rreg(ahci, port, AHCI_PX_IS); + ahci_px_wreg(ahci, port, AHCI_PX_IS, reg); + g_assert_cmphex(ahci_px_rreg(ahci, port, AHCI_PX_IS), ==, 0); + + /* Wipe the FIS-Recieve Buffer */ + qmemset(ahci->port[port].fb, 0x00, 0x100); +} diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h index b3992e19e5..39ba94e3f4 100644 --- a/tests/libqos/ahci.h +++ b/tests/libqos/ahci.h @@ -432,5 +432,6 @@ void ahci_pci_enable(AHCIQState *ahci); void start_ahci_device(AHCIQState *ahci); void ahci_hba_enable(AHCIQState *ahci); unsigned ahci_port_select(AHCIQState *ahci); +void ahci_port_clear(AHCIQState *ahci, uint8_t port); #endif -- cgit v1.2.3 From c7f9c570b908a844aee393d93d01c332aea2a5a5 Mon Sep 17 00:00:00 2001 From: John Snow <jsnow@redhat.com> Date: Thu, 5 Feb 2015 12:41:14 -0500 Subject: qtest/ahci: rename 'Command' to 'CommandHeader' The structure name is a bit of a misnomer; the structure currently named command is actually the commandheader. A future patch in this series will add an actual "Command" structure, so we'll rename it now before the rest of the functions in this series try to use it. In addition, rename the "b1" and "b2" fields to be a unified uint16_t named "flags." Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Signed-off-by: John Snow <jsnow@redhat.com> Message-id: 1423158090-25580-4-git-send-email-jsnow@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/ahci-test.c | 8 ++++---- tests/libqos/ahci.h | 7 +++---- 2 files changed, 7 insertions(+), 8 deletions(-) (limited to 'tests') diff --git a/tests/ahci-test.c b/tests/ahci-test.c index 90647f2a0c..d420e5f8be 100644 --- a/tests/ahci-test.c +++ b/tests/ahci-test.c @@ -660,7 +660,7 @@ static void ahci_test_identify(AHCIQState *ahci) RegD2HFIS *d2h = g_malloc0(0x20); RegD2HFIS *pio = g_malloc0(0x20); RegH2DFIS fis; - AHCICommand cmd; + AHCICommandHeader cmd; PRD prd; uint32_t reg, table, data_ptr; uint16_t buff[256]; @@ -703,9 +703,9 @@ static void ahci_test_identify(AHCIQState *ahci) /* Copy the existing Command #0 structure from the CLB into local memory, * and build a new command #0. */ memread(ahci->port[i].clb, &cmd, sizeof(cmd)); - cmd.b1 = 5; /* reg_h2d_fis is 5 double-words long */ - cmd.b2 = 0x04; /* clear PxTFD.STS.BSY when done */ - cmd.prdtl = cpu_to_le16(1); /* One PRD table entry. */ + cmd.flags = cpu_to_le16(5); /* reg_h2d_fis is 5 double-words long */ + cmd.flags |= cpu_to_le16(0x400); /* clear PxTFD.STS.BSY when done */ + cmd.prdtl = cpu_to_le16(1); /* One PRD table entry. */ cmd.prdbc = 0; cmd.ctba = cpu_to_le32(table); cmd.ctbau = 0; diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h index 39ba94e3f4..1fddf33156 100644 --- a/tests/libqos/ahci.h +++ b/tests/libqos/ahci.h @@ -329,15 +329,14 @@ typedef struct RegH2DFIS { * Command List entry structure. * The command list contains between 1-32 of these structures. */ -typedef struct AHCICommand { - uint8_t b1; - uint8_t b2; +typedef struct AHCICommandHeader { + uint16_t flags; /* Cmd-Fis-Len, PMP#, and flags. */ uint16_t prdtl; /* Phys Region Desc. Table Length */ uint32_t prdbc; /* Phys Region Desc. Byte Count */ uint32_t ctba; /* Command Table Descriptor Base Address */ uint32_t ctbau; /* '' Upper */ uint32_t res[4]; -} __attribute__((__packed__)) AHCICommand; +} __attribute__((__packed__)) AHCICommandHeader; /** * Physical Region Descriptor; pointed to by the Command List Header, -- cgit v1.2.3 From 6cae27a6af159ab44f7c265d7f22d9e95880db25 Mon Sep 17 00:00:00 2001 From: John Snow <jsnow@redhat.com> Date: Thu, 5 Feb 2015 12:41:15 -0500 Subject: libqos/ahci: Add command header helpers Adds command header helper functions: -ahci_command_header_set -ahci_command_header_get, -ahci_command_destroy, and -ahci_cmd_pick These helpers help to quickly manage the command header information in the AHCI device. ahci_command_header_set and get will store or retrieve an AHCI command header, respectively. ahci_cmd_pick chooses the first available but least recently used command slot to allow us to cycle through the available command slots. ahci_command_destroy obliterates all information contained within a given slot's command header, and frees its associated command table, but not its DMA buffer! Lastly, the command table pointer fields (dba and dbau) are merged into a single 64bit value to make managing 64bit tests simpler. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Message-id: 1423158090-25580-5-git-send-email-jsnow@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/ahci-test.c | 43 ++++++++++++++++-------------- tests/libqos/ahci.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++ tests/libqos/ahci.h | 17 ++++++++---- 3 files changed, 110 insertions(+), 25 deletions(-) (limited to 'tests') diff --git a/tests/ahci-test.c b/tests/ahci-test.c index d420e5f8be..fbf329e91e 100644 --- a/tests/ahci-test.c +++ b/tests/ahci-test.c @@ -662,10 +662,12 @@ static void ahci_test_identify(AHCIQState *ahci) RegH2DFIS fis; AHCICommandHeader cmd; PRD prd; - uint32_t reg, table, data_ptr; + uint32_t reg, data_ptr; uint16_t buff[256]; unsigned i; int rc; + uint8_t cx; + uint64_t table; g_assert(ahci != NULL); @@ -700,19 +702,19 @@ static void ahci_test_identify(AHCIQState *ahci) data_ptr = ahci_alloc(ahci, 512); g_assert(data_ptr); - /* Copy the existing Command #0 structure from the CLB into local memory, - * and build a new command #0. */ - memread(ahci->port[i].clb, &cmd, sizeof(cmd)); - cmd.flags = cpu_to_le16(5); /* reg_h2d_fis is 5 double-words long */ - cmd.flags |= cpu_to_le16(0x400); /* clear PxTFD.STS.BSY when done */ - cmd.prdtl = cpu_to_le16(1); /* One PRD table entry. */ + /* pick a command slot (should be 0!) */ + cx = ahci_pick_cmd(ahci, i); + + /* Construct our Command Header (set_command_header handles endianness.) */ + memset(&cmd, 0x00, sizeof(cmd)); + cmd.flags = 5; /* reg_h2d_fis is 5 double-words long */ + cmd.flags |= 0x400; /* clear PxTFD.STS.BSY when done */ + cmd.prdtl = 1; /* One PRD table entry. */ cmd.prdbc = 0; - cmd.ctba = cpu_to_le32(table); - cmd.ctbau = 0; + cmd.ctba = table; /* Construct our PRD, noting that DBC is 0-indexed. */ - prd.dba = cpu_to_le32(data_ptr); - prd.dbau = 0; + prd.dba = cpu_to_le64(data_ptr); prd.res = 0; /* 511+1 bytes, request DPS interrupt */ prd.dbc = cpu_to_le32(511 | 0x80000000); @@ -733,14 +735,15 @@ static void ahci_test_identify(AHCIQState *ahci) /* Commit the PRD entry to the Command Table */ memwrite(table + 0x80, &prd, sizeof(prd)); - /* Commit Command #0, pointing to the Table, to the Command List Buffer. */ - memwrite(ahci->port[i].clb, &cmd, sizeof(cmd)); + /* Commit Command #cx, pointing to the Table, to the Command List Buffer. */ + ahci_set_command_header(ahci, i, cx, &cmd); - /* Everything is in place, but we haven't given the go-ahead yet. */ + /* Everything is in place, but we haven't given the go-ahead yet, + * so we should find that there are no pending interrupts yet. */ g_assert_cmphex(ahci_px_rreg(ahci, i, AHCI_PX_IS), ==, 0); - /* Issue Command #0 via PxCI */ - ahci_px_wreg(ahci, i, AHCI_PX_CI, (1 << 0)); + /* Issue Command #cx via PxCI */ + ahci_px_wreg(ahci, i, AHCI_PX_CI, (1 << cx)); while (BITSET(ahci_px_rreg(ahci, i, AHCI_PX_TFD), AHCI_PX_TFD_STS_BSY)) { usleep(50); } @@ -764,9 +767,9 @@ static void ahci_test_identify(AHCIQState *ahci) ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_STS_ERR); ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_ERR); - /* Investigate CMD #0, assert that we read 512 bytes */ - memread(ahci->port[i].clb, &cmd, sizeof(cmd)); - g_assert_cmphex(512, ==, le32_to_cpu(cmd.prdbc)); + /* Investigate the CMD, assert that we read 512 bytes */ + ahci_get_command_header(ahci, i, cx, &cmd); + g_assert_cmphex(512, ==, cmd.prdbc); /* Investigate FIS responses */ memread(ahci->port[i].fb + 0x20, pio, 0x20); @@ -783,7 +786,7 @@ static void ahci_test_identify(AHCIQState *ahci) /* The PIO Setup FIS contains a "bytes read" field, which is a * 16-bit value. The Physical Region Descriptor Byte Count is * 32-bit, but for small transfers using one PRD, it should match. */ - g_assert_cmphex(le16_to_cpu(pio->res4), ==, le32_to_cpu(cmd.prdbc)); + g_assert_cmphex(le16_to_cpu(pio->res4), ==, cmd.prdbc); /* Last, but not least: Investigate the IDENTIFY response data. */ memread(data_ptr, &buff, 512); diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c index 3b1b9ba499..8c3f6645eb 100644 --- a/tests/libqos/ahci.c +++ b/tests/libqos/ahci.c @@ -310,3 +310,78 @@ void ahci_port_clear(AHCIQState *ahci, uint8_t port) /* Wipe the FIS-Recieve Buffer */ qmemset(ahci->port[port].fb, 0x00, 0x100); } + +/* Get the command in #slot of port #port. */ +void ahci_get_command_header(AHCIQState *ahci, uint8_t port, + uint8_t slot, AHCICommandHeader *cmd) +{ + uint64_t ba = ahci->port[port].clb; + ba += slot * sizeof(AHCICommandHeader); + memread(ba, cmd, sizeof(AHCICommandHeader)); + + cmd->flags = le16_to_cpu(cmd->flags); + cmd->prdtl = le16_to_cpu(cmd->prdtl); + cmd->prdbc = le32_to_cpu(cmd->prdbc); + cmd->ctba = le64_to_cpu(cmd->ctba); +} + +/* Set the command in #slot of port #port. */ +void ahci_set_command_header(AHCIQState *ahci, uint8_t port, + uint8_t slot, AHCICommandHeader *cmd) +{ + AHCICommandHeader tmp; + uint64_t ba = ahci->port[port].clb; + ba += slot * sizeof(AHCICommandHeader); + + tmp.flags = cpu_to_le16(cmd->flags); + tmp.prdtl = cpu_to_le16(cmd->prdtl); + tmp.prdbc = cpu_to_le32(cmd->prdbc); + tmp.ctba = cpu_to_le64(cmd->ctba); + + memwrite(ba, &tmp, sizeof(AHCICommandHeader)); +} + +void ahci_destroy_command(AHCIQState *ahci, uint8_t port, uint8_t slot) +{ + AHCICommandHeader cmd; + + /* Obtain the Nth Command Header */ + ahci_get_command_header(ahci, port, slot, &cmd); + if (cmd.ctba == 0) { + /* No address in it, so just return -- it's empty. */ + goto tidy; + } + + /* Free the Table */ + ahci_free(ahci, cmd.ctba); + + tidy: + /* NULL the header. */ + memset(&cmd, 0x00, sizeof(cmd)); + ahci_set_command_header(ahci, port, slot, &cmd); + ahci->port[port].ctba[slot] = 0; + ahci->port[port].prdtl[slot] = 0; +} + +unsigned ahci_pick_cmd(AHCIQState *ahci, uint8_t port) +{ + unsigned i; + unsigned j; + uint32_t reg; + + reg = ahci_px_rreg(ahci, port, AHCI_PX_CI); + + /* Pick the least recently used command slot that's available */ + for (i = 0; i < 32; ++i) { + j = ((ahci->port[port].next + i) % 32); + if (reg & (1 << j)) { + continue; + } + ahci_destroy_command(ahci, port, i); + ahci->port[port].next = (j + 1) % 32; + return j; + } + + g_test_message("All command slots were busy."); + g_assert_not_reached(); +} diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h index 1fddf33156..0835be46fc 100644 --- a/tests/libqos/ahci.h +++ b/tests/libqos/ahci.h @@ -248,6 +248,9 @@ typedef struct AHCIPortQState { uint64_t fb; uint64_t clb; + uint64_t ctba[32]; + uint16_t prdtl[32]; + uint8_t next; /** Next Command Slot to Use **/ } AHCIPortQState; typedef struct AHCIQState { @@ -333,8 +336,7 @@ typedef struct AHCICommandHeader { uint16_t flags; /* Cmd-Fis-Len, PMP#, and flags. */ uint16_t prdtl; /* Phys Region Desc. Table Length */ uint32_t prdbc; /* Phys Region Desc. Byte Count */ - uint32_t ctba; /* Command Table Descriptor Base Address */ - uint32_t ctbau; /* '' Upper */ + uint64_t ctba; /* Command Table Descriptor Base Address */ uint32_t res[4]; } __attribute__((__packed__)) AHCICommandHeader; @@ -343,11 +345,10 @@ typedef struct AHCICommandHeader { * struct ahci_command. */ typedef struct PRD { - uint32_t dba; /* Data Base Address */ - uint32_t dbau; /* Data Base Address Upper */ + uint64_t dba; /* Data Base Address */ uint32_t res; /* Reserved */ uint32_t dbc; /* Data Byte Count (0-indexed) & Interrupt Flag (bit 2^31) */ -} PRD; +} __attribute__((__packed__)) PRD; /*** Macro Utilities ***/ #define BITANY(data, mask) (((data) & (mask)) != 0) @@ -432,5 +433,11 @@ void start_ahci_device(AHCIQState *ahci); void ahci_hba_enable(AHCIQState *ahci); unsigned ahci_port_select(AHCIQState *ahci); void ahci_port_clear(AHCIQState *ahci, uint8_t port); +void ahci_get_command_header(AHCIQState *ahci, uint8_t port, + uint8_t slot, AHCICommandHeader *cmd); +void ahci_set_command_header(AHCIQState *ahci, uint8_t port, + uint8_t slot, AHCICommandHeader *cmd); +void ahci_destroy_command(AHCIQState *ahci, uint8_t port, uint8_t slot); +unsigned ahci_pick_cmd(AHCIQState *ahci, uint8_t port); #endif -- cgit v1.2.3 From 85c34e9395a97e49def6697537417ead2077c096 Mon Sep 17 00:00:00 2001 From: John Snow <jsnow@redhat.com> Date: Thu, 5 Feb 2015 12:41:16 -0500 Subject: libqos/ahci: Add ahci_port_check_error helper ahci_port_check_error checks a given port's error registers and asserts that everything from the port-level view is still OK. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Message-id: 1423158090-25580-6-git-send-email-jsnow@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/ahci-test.c | 8 +------- tests/libqos/ahci.c | 22 ++++++++++++++++++++++ tests/libqos/ahci.h | 1 + 3 files changed, 24 insertions(+), 7 deletions(-) (limited to 'tests') diff --git a/tests/ahci-test.c b/tests/ahci-test.c index fbf329e91e..a3e8f1292b 100644 --- a/tests/ahci-test.c +++ b/tests/ahci-test.c @@ -747,6 +747,7 @@ static void ahci_test_identify(AHCIQState *ahci) while (BITSET(ahci_px_rreg(ahci, i, AHCI_PX_TFD), AHCI_PX_TFD_STS_BSY)) { usleep(50); } + ahci_port_check_error(ahci, i); /* Check for expected interrupts */ reg = ahci_px_rreg(ahci, i, AHCI_PX_IS); @@ -760,13 +761,6 @@ static void ahci_test_identify(AHCIQState *ahci) AHCI_PX_IS_DHRS | AHCI_PX_IS_PSS | AHCI_PX_IS_DPS); g_assert_cmphex(ahci_px_rreg(ahci, i, AHCI_PX_IS), ==, 0); - /* Check for errors. */ - reg = ahci_px_rreg(ahci, i, AHCI_PX_SERR); - g_assert_cmphex(reg, ==, 0); - reg = ahci_px_rreg(ahci, i, AHCI_PX_TFD); - ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_STS_ERR); - ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_ERR); - /* Investigate the CMD, assert that we read 512 bytes */ ahci_get_command_header(ahci, i, cx, &cmd); g_assert_cmphex(512, ==, cmd.prdbc); diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c index 8c3f6645eb..3da168abb2 100644 --- a/tests/libqos/ahci.c +++ b/tests/libqos/ahci.c @@ -311,6 +311,28 @@ void ahci_port_clear(AHCIQState *ahci, uint8_t port) qmemset(ahci->port[port].fb, 0x00, 0x100); } +/** + * Check a port for errors. + */ +void ahci_port_check_error(AHCIQState *ahci, uint8_t port) +{ + uint32_t reg; + + /* The upper 9 bits of the IS register all indicate errors. */ + reg = ahci_px_rreg(ahci, port, AHCI_PX_IS); + reg >>= 23; + g_assert_cmphex(reg, ==, 0); + + /* The Sata Error Register should be empty. */ + reg = ahci_px_rreg(ahci, port, AHCI_PX_SERR); + g_assert_cmphex(reg, ==, 0); + + /* The TFD also has two error sections. */ + reg = ahci_px_rreg(ahci, port, AHCI_PX_TFD); + ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_STS_ERR); + ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_ERR); +} + /* Get the command in #slot of port #port. */ void ahci_get_command_header(AHCIQState *ahci, uint8_t port, uint8_t slot, AHCICommandHeader *cmd) diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h index 0835be46fc..af62a8a9aa 100644 --- a/tests/libqos/ahci.h +++ b/tests/libqos/ahci.h @@ -433,6 +433,7 @@ void start_ahci_device(AHCIQState *ahci); void ahci_hba_enable(AHCIQState *ahci); unsigned ahci_port_select(AHCIQState *ahci); void ahci_port_clear(AHCIQState *ahci, uint8_t port); +void ahci_port_check_error(AHCIQState *ahci, uint8_t port); void ahci_get_command_header(AHCIQState *ahci, uint8_t port, uint8_t slot, AHCICommandHeader *cmd); void ahci_set_command_header(AHCIQState *ahci, uint8_t port, -- cgit v1.2.3 From 5bf99aa1cf67a210dd441ae4edf1e26df05360d5 Mon Sep 17 00:00:00 2001 From: John Snow <jsnow@redhat.com> Date: Thu, 5 Feb 2015 12:41:17 -0500 Subject: libqos/ahci: Add ahci_port_check_interrupts helper A helper that compares a given port's current interrupts and checks them against a supplied list of expected interrupt bits, and throws an error if they do not match. The helper then resets the requested interrupts on this port, and asserts that the interrupt register is now empty. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Message-id: 1423158090-25580-7-git-send-email-jsnow@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/ahci-test.c | 13 ++----------- tests/libqos/ahci.c | 14 ++++++++++++++ tests/libqos/ahci.h | 2 ++ 3 files changed, 18 insertions(+), 11 deletions(-) (limited to 'tests') diff --git a/tests/ahci-test.c b/tests/ahci-test.c index a3e8f1292b..32b6be3b92 100644 --- a/tests/ahci-test.c +++ b/tests/ahci-test.c @@ -747,19 +747,10 @@ static void ahci_test_identify(AHCIQState *ahci) while (BITSET(ahci_px_rreg(ahci, i, AHCI_PX_TFD), AHCI_PX_TFD_STS_BSY)) { usleep(50); } + /* Check registers for post-command consistency */ ahci_port_check_error(ahci, i); - - /* Check for expected interrupts */ - reg = ahci_px_rreg(ahci, i, AHCI_PX_IS); - ASSERT_BIT_SET(reg, AHCI_PX_IS_DHRS); - ASSERT_BIT_SET(reg, AHCI_PX_IS_PSS); /* BUG: we expect AHCI_PX_IS_DPS to be set. */ - ASSERT_BIT_CLEAR(reg, AHCI_PX_IS_DPS); - - /* Clear expected interrupts and assert all interrupts now cleared. */ - ahci_px_wreg(ahci, i, AHCI_PX_IS, - AHCI_PX_IS_DHRS | AHCI_PX_IS_PSS | AHCI_PX_IS_DPS); - g_assert_cmphex(ahci_px_rreg(ahci, i, AHCI_PX_IS), ==, 0); + ahci_port_check_interrupts(ahci, i, AHCI_PX_IS_DHRS | AHCI_PX_IS_PSS); /* Investigate the CMD, assert that we read 512 bytes */ ahci_get_command_header(ahci, i, cx, &cmd); diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c index 3da168abb2..ef84cc6660 100644 --- a/tests/libqos/ahci.c +++ b/tests/libqos/ahci.c @@ -333,6 +333,20 @@ void ahci_port_check_error(AHCIQState *ahci, uint8_t port) ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_ERR); } +void ahci_port_check_interrupts(AHCIQState *ahci, uint8_t port, + uint32_t intr_mask) +{ + uint32_t reg; + + /* Check for expected interrupts */ + reg = ahci_px_rreg(ahci, port, AHCI_PX_IS); + ASSERT_BIT_SET(reg, intr_mask); + + /* Clear expected interrupts and assert all interrupts now cleared. */ + ahci_px_wreg(ahci, port, AHCI_PX_IS, intr_mask); + g_assert_cmphex(ahci_px_rreg(ahci, port, AHCI_PX_IS), ==, 0); +} + /* Get the command in #slot of port #port. */ void ahci_get_command_header(AHCIQState *ahci, uint8_t port, uint8_t slot, AHCICommandHeader *cmd) diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h index af62a8a9aa..a2ffa70d22 100644 --- a/tests/libqos/ahci.h +++ b/tests/libqos/ahci.h @@ -434,6 +434,8 @@ void ahci_hba_enable(AHCIQState *ahci); unsigned ahci_port_select(AHCIQState *ahci); void ahci_port_clear(AHCIQState *ahci, uint8_t port); void ahci_port_check_error(AHCIQState *ahci, uint8_t port); +void ahci_port_check_interrupts(AHCIQState *ahci, uint8_t port, + uint32_t intr_mask); void ahci_get_command_header(AHCIQState *ahci, uint8_t port, uint8_t slot, AHCICommandHeader *cmd); void ahci_set_command_header(AHCIQState *ahci, uint8_t port, -- cgit v1.2.3 From 89a46723668a35db3eac5cb59b32ba67948dee0d Mon Sep 17 00:00:00 2001 From: John Snow <jsnow@redhat.com> Date: Thu, 5 Feb 2015 12:41:18 -0500 Subject: libqos/ahci: Add port_check_nonbusy helper A simple helper that asserts a given port is not busy processing any commands via the TFD, Command Issue and SACT registers. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Message-id: 1423158090-25580-8-git-send-email-jsnow@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/ahci-test.c | 1 + tests/libqos/ahci.c | 18 ++++++++++++++++++ tests/libqos/ahci.h | 1 + 3 files changed, 20 insertions(+) (limited to 'tests') diff --git a/tests/ahci-test.c b/tests/ahci-test.c index 32b6be3b92..4cc7e21a43 100644 --- a/tests/ahci-test.c +++ b/tests/ahci-test.c @@ -751,6 +751,7 @@ static void ahci_test_identify(AHCIQState *ahci) ahci_port_check_error(ahci, i); /* BUG: we expect AHCI_PX_IS_DPS to be set. */ ahci_port_check_interrupts(ahci, i, AHCI_PX_IS_DHRS | AHCI_PX_IS_PSS); + ahci_port_check_nonbusy(ahci, i, cx); /* Investigate the CMD, assert that we read 512 bytes */ ahci_get_command_header(ahci, i, cx, &cmd); diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c index ef84cc6660..7ed6494805 100644 --- a/tests/libqos/ahci.c +++ b/tests/libqos/ahci.c @@ -347,6 +347,24 @@ void ahci_port_check_interrupts(AHCIQState *ahci, uint8_t port, g_assert_cmphex(ahci_px_rreg(ahci, port, AHCI_PX_IS), ==, 0); } +void ahci_port_check_nonbusy(AHCIQState *ahci, uint8_t port, uint8_t slot) +{ + uint32_t reg; + + /* Assert that the command slot is no longer busy (NCQ) */ + reg = ahci_px_rreg(ahci, port, AHCI_PX_SACT); + ASSERT_BIT_CLEAR(reg, (1 << slot)); + + /* Non-NCQ */ + reg = ahci_px_rreg(ahci, port, AHCI_PX_CI); + ASSERT_BIT_CLEAR(reg, (1 << slot)); + + /* And assert that we are generally not busy. */ + reg = ahci_px_rreg(ahci, port, AHCI_PX_TFD); + ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_STS_BSY); + ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_STS_DRQ); +} + /* Get the command in #slot of port #port. */ void ahci_get_command_header(AHCIQState *ahci, uint8_t port, uint8_t slot, AHCICommandHeader *cmd) diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h index a2ffa70d22..eaad076f46 100644 --- a/tests/libqos/ahci.h +++ b/tests/libqos/ahci.h @@ -436,6 +436,7 @@ void ahci_port_clear(AHCIQState *ahci, uint8_t port); void ahci_port_check_error(AHCIQState *ahci, uint8_t port); void ahci_port_check_interrupts(AHCIQState *ahci, uint8_t port, uint32_t intr_mask); +void ahci_port_check_nonbusy(AHCIQState *ahci, uint8_t port, uint8_t slot); void ahci_get_command_header(AHCIQState *ahci, uint8_t port, uint8_t slot, AHCICommandHeader *cmd); void ahci_set_command_header(AHCIQState *ahci, uint8_t port, -- cgit v1.2.3 From d1ef883894f0661f9994bc937ba09077a32a8bee Mon Sep 17 00:00:00 2001 From: John Snow <jsnow@redhat.com> Date: Thu, 5 Feb 2015 12:41:19 -0500 Subject: libqos/ahci: Add cmd response sanity check helpers This patch adds a few helpers to help sanity-check the response of the AHCI device after a command. ahci_d2h_check_sanity inspects the D2H Register FIS, ahci_pio_check_sanity inspects the PIO Setup FIS, and ahci_cmd_check_sanity inspects the command header. To support the PIO sanity check, a new structure is added for the PIO Setup FIS type. Existing FIS types (H2D and D2H) have had their members renamed slightly to condense reserved members into fewer fields; and LBA fields are now represented by arrays of 8 byte chunks instead of independent variables. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Message-id: 1423158090-25580-9-git-send-email-jsnow@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/ahci-test.c | 29 ++++------------------------ tests/libqos/ahci.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++ tests/libqos/ahci.h | 54 ++++++++++++++++++++++++++++++++++++----------------- 3 files changed, 88 insertions(+), 42 deletions(-) (limited to 'tests') diff --git a/tests/ahci-test.c b/tests/ahci-test.c index 4cc7e21a43..b67d935597 100644 --- a/tests/ahci-test.c +++ b/tests/ahci-test.c @@ -657,12 +657,10 @@ static void ahci_test_port_spec(AHCIQState *ahci, uint8_t port) */ static void ahci_test_identify(AHCIQState *ahci) { - RegD2HFIS *d2h = g_malloc0(0x20); - RegD2HFIS *pio = g_malloc0(0x20); RegH2DFIS fis; AHCICommandHeader cmd; PRD prd; - uint32_t reg, data_ptr; + uint32_t data_ptr; uint16_t buff[256]; unsigned i; int rc; @@ -752,27 +750,11 @@ static void ahci_test_identify(AHCIQState *ahci) /* BUG: we expect AHCI_PX_IS_DPS to be set. */ ahci_port_check_interrupts(ahci, i, AHCI_PX_IS_DHRS | AHCI_PX_IS_PSS); ahci_port_check_nonbusy(ahci, i, cx); - /* Investigate the CMD, assert that we read 512 bytes */ - ahci_get_command_header(ahci, i, cx, &cmd); - g_assert_cmphex(512, ==, cmd.prdbc); - + ahci_port_check_cmd_sanity(ahci, i, cx, 512); /* Investigate FIS responses */ - memread(ahci->port[i].fb + 0x20, pio, 0x20); - memread(ahci->port[i].fb + 0x40, d2h, 0x20); - g_assert_cmphex(pio->fis_type, ==, 0x5f); - g_assert_cmphex(d2h->fis_type, ==, 0x34); - g_assert_cmphex(pio->flags, ==, d2h->flags); - g_assert_cmphex(pio->status, ==, d2h->status); - g_assert_cmphex(pio->error, ==, d2h->error); - - reg = ahci_px_rreg(ahci, i, AHCI_PX_TFD); - g_assert_cmphex((reg & AHCI_PX_TFD_ERR), ==, pio->error); - g_assert_cmphex((reg & AHCI_PX_TFD_STS), ==, pio->status); - /* The PIO Setup FIS contains a "bytes read" field, which is a - * 16-bit value. The Physical Region Descriptor Byte Count is - * 32-bit, but for small transfers using one PRD, it should match. */ - g_assert_cmphex(le16_to_cpu(pio->res4), ==, cmd.prdbc); + ahci_port_check_d2h_sanity(ahci, i, cx); + ahci_port_check_pio_sanity(ahci, i, cx, 512); /* Last, but not least: Investigate the IDENTIFY response data. */ memread(data_ptr, &buff, 512); @@ -789,9 +771,6 @@ static void ahci_test_identify(AHCIQState *ahci) string_bswap16(&buff[23], 8); rc = memcmp(&buff[23], "version ", 8); g_assert_cmphex(rc, ==, 0); - - g_free(d2h); - g_free(pio); } /******************************************************************************/ diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c index 7ed6494805..8ecfdd30d8 100644 --- a/tests/libqos/ahci.c +++ b/tests/libqos/ahci.c @@ -365,6 +365,53 @@ void ahci_port_check_nonbusy(AHCIQState *ahci, uint8_t port, uint8_t slot) ASSERT_BIT_CLEAR(reg, AHCI_PX_TFD_STS_DRQ); } +void ahci_port_check_d2h_sanity(AHCIQState *ahci, uint8_t port, uint8_t slot) +{ + RegD2HFIS *d2h = g_malloc0(0x20); + uint32_t reg; + + memread(ahci->port[port].fb + 0x40, d2h, 0x20); + g_assert_cmphex(d2h->fis_type, ==, 0x34); + + reg = ahci_px_rreg(ahci, port, AHCI_PX_TFD); + g_assert_cmphex((reg & AHCI_PX_TFD_ERR) >> 8, ==, d2h->error); + g_assert_cmphex((reg & AHCI_PX_TFD_STS), ==, d2h->status); + + g_free(d2h); +} + +void ahci_port_check_pio_sanity(AHCIQState *ahci, uint8_t port, + uint8_t slot, size_t buffsize) +{ + PIOSetupFIS *pio = g_malloc0(0x20); + + /* We cannot check the Status or E_Status registers, becuase + * the status may have again changed between the PIO Setup FIS + * and the conclusion of the command with the D2H Register FIS. */ + memread(ahci->port[port].fb + 0x20, pio, 0x20); + g_assert_cmphex(pio->fis_type, ==, 0x5f); + + /* BUG: PIO Setup FIS as utilized by QEMU tries to fit the entire + * transfer size in a uint16_t field. The maximum transfer size can + * eclipse this; the field is meant to convey the size of data per + * each Data FIS, not the entire operation as a whole. For now, + * we will sanity check the broken case where applicable. */ + if (buffsize <= UINT16_MAX) { + g_assert_cmphex(le16_to_cpu(pio->tx_count), ==, buffsize); + } + + g_free(pio); +} + +void ahci_port_check_cmd_sanity(AHCIQState *ahci, uint8_t port, + uint8_t slot, size_t buffsize) +{ + AHCICommandHeader cmd; + + ahci_get_command_header(ahci, port, slot, &cmd); + g_assert_cmphex(buffsize, ==, cmd.prdbc); +} + /* Get the command in #slot of port #port. */ void ahci_get_command_header(AHCIQState *ahci, uint8_t port, uint8_t slot, AHCICommandHeader *cmd) diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h index eaad076f46..f17aa23e0e 100644 --- a/tests/libqos/ahci.h +++ b/tests/libqos/ahci.h @@ -283,24 +283,43 @@ typedef struct RegD2HFIS { uint8_t status; uint8_t error; /* DW1 */ - uint8_t lba_low; - uint8_t lba_mid; - uint8_t lba_high; + uint8_t lba_lo[3]; uint8_t device; /* DW2 */ - uint8_t lba3; - uint8_t lba4; - uint8_t lba5; - uint8_t res1; + uint8_t lba_hi[3]; + uint8_t res0; /* DW3 */ uint16_t count; - uint8_t res2; - uint8_t res3; + uint16_t res1; /* DW4 */ - uint16_t res4; - uint16_t res5; + uint32_t res2; } __attribute__((__packed__)) RegD2HFIS; +/** + * Register device-to-host FIS structure; + * PIO Setup variety. + */ +typedef struct PIOSetupFIS { + /* DW0 */ + uint8_t fis_type; + uint8_t flags; + uint8_t status; + uint8_t error; + /* DW1 */ + uint8_t lba_lo[3]; + uint8_t device; + /* DW2 */ + uint8_t lba_hi[3]; + uint8_t res0; + /* DW3 */ + uint16_t count; + uint8_t res1; + uint8_t e_status; + /* DW4 */ + uint16_t tx_count; + uint16_t res2; +} __attribute__((__packed__)) PIOSetupFIS; + /** * Register host-to-device FIS structure. */ @@ -311,14 +330,10 @@ typedef struct RegH2DFIS { uint8_t command; uint8_t feature_low; /* DW1 */ - uint8_t lba_low; - uint8_t lba_mid; - uint8_t lba_high; + uint8_t lba_lo[3]; uint8_t device; /* DW2 */ - uint8_t lba3; - uint8_t lba4; - uint8_t lba5; + uint8_t lba_hi[3]; uint8_t feature_high; /* DW3 */ uint16_t count; @@ -437,6 +452,11 @@ void ahci_port_check_error(AHCIQState *ahci, uint8_t port); void ahci_port_check_interrupts(AHCIQState *ahci, uint8_t port, uint32_t intr_mask); void ahci_port_check_nonbusy(AHCIQState *ahci, uint8_t port, uint8_t slot); +void ahci_port_check_d2h_sanity(AHCIQState *ahci, uint8_t port, uint8_t slot); +void ahci_port_check_pio_sanity(AHCIQState *ahci, uint8_t port, + uint8_t slot, size_t buffsize); +void ahci_port_check_cmd_sanity(AHCIQState *ahci, uint8_t port, + uint8_t slot, size_t buffsize); void ahci_get_command_header(AHCIQState *ahci, uint8_t port, uint8_t slot, AHCICommandHeader *cmd); void ahci_set_command_header(AHCIQState *ahci, uint8_t port, -- cgit v1.2.3 From 36e367261c15f0fa9acfbe9f4301c96e19be7f52 Mon Sep 17 00:00:00 2001 From: John Snow <jsnow@redhat.com> Date: Thu, 5 Feb 2015 12:41:20 -0500 Subject: qtest/ahci: Demagic ahci tests. Add human-readable command names and other miscellaneous #defines to help make the code more readable. Some of these definitions are not yet used in this current series, but for convenience and sanity they have been lumped together here, as it's more trouble than it is worth in a test suite to hand-pick, one-by-one, which preprocessor definitions are useful per-each test. These definitions include: ATA Command Mnemonics Current expected AHCI sector size FIS magic bytes REG_H2D_FIS flags Command Header flags Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Signed-off-by: John Snow <jsnow@redhat.com> Message-id: 1423158090-25580-10-git-send-email-jsnow@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/ahci-test.c | 12 ++++++------ tests/libqos/ahci.h | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 6 deletions(-) (limited to 'tests') diff --git a/tests/ahci-test.c b/tests/ahci-test.c index b67d935597..211274e8c3 100644 --- a/tests/ahci-test.c +++ b/tests/ahci-test.c @@ -705,9 +705,9 @@ static void ahci_test_identify(AHCIQState *ahci) /* Construct our Command Header (set_command_header handles endianness.) */ memset(&cmd, 0x00, sizeof(cmd)); - cmd.flags = 5; /* reg_h2d_fis is 5 double-words long */ - cmd.flags |= 0x400; /* clear PxTFD.STS.BSY when done */ - cmd.prdtl = 1; /* One PRD table entry. */ + cmd.flags = 5; /* reg_h2d_fis is 5 double-words long */ + cmd.flags |= CMDH_CLR_BSY; /* clear PxTFD.STS.BSY when done */ + cmd.prdtl = 1; /* One PRD table entry. */ cmd.prdbc = 0; cmd.ctba = table; @@ -719,10 +719,10 @@ static void ahci_test_identify(AHCIQState *ahci) /* Construct our Command FIS, Based on http://wiki.osdev.org/AHCI */ memset(&fis, 0x00, sizeof(fis)); - fis.fis_type = 0x27; /* Register Host-to-Device FIS */ - fis.command = 0xEC; /* IDENTIFY */ + fis.fis_type = REG_H2D_FIS; /* Register Host-to-Device FIS */ + fis.command = CMD_IDENTIFY; fis.device = 0; - fis.flags = 0x80; /* Indicate this is a command FIS */ + fis.flags = REG_H2D_FIS_CMD; /* Indicate this is a command FIS */ /* We've committed nothing yet, no interrupts should be posted yet. */ g_assert_cmphex(ahci_px_rreg(ahci, i, AHCI_PX_IS), ==, 0); diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h index f17aa23e0e..0837bf5032 100644 --- a/tests/libqos/ahci.h +++ b/tests/libqos/ahci.h @@ -243,6 +243,59 @@ #define AHCI_VERSION_1_2 (0x00010200) #define AHCI_VERSION_1_3 (0x00010300) +#define AHCI_SECTOR_SIZE (512) + +/* FIS types */ +enum { + REG_H2D_FIS = 0x27, + REG_D2H_FIS = 0x34, + DMA_ACTIVATE_FIS = 0x39, + DMA_SETUP_FIS = 0x41, + DATA_FIS = 0x46, + BIST_ACTIVATE_FIS = 0x58, + PIO_SETUP_FIS = 0x5F, + SDB_FIS = 0xA1 +}; + +/* FIS flags */ +#define REG_H2D_FIS_CMD 0x80 + +/* ATA Commands */ +enum { + /* DMA */ + CMD_READ_DMA = 0xC8, + CMD_READ_DMA_EXT = 0x25, + CMD_WRITE_DMA = 0xCA, + CMD_WRITE_DMA_EXT = 0x35, + /* PIO */ + CMD_READ_PIO = 0x20, + CMD_READ_PIO_EXT = 0x24, + CMD_WRITE_PIO = 0x30, + CMD_WRITE_PIO_EXT = 0x34, + /* Misc */ + CMD_READ_MAX = 0xF8, + CMD_READ_MAX_EXT = 0x27, + CMD_FLUSH_CACHE = 0xE7, + CMD_IDENTIFY = 0xEC +}; + +/* AHCI Command Header Flags & Masks*/ +#define CMDH_CFL (0x1F) +#define CMDH_ATAPI (0x20) +#define CMDH_WRITE (0x40) +#define CMDH_PREFETCH (0x80) +#define CMDH_RESET (0x100) +#define CMDH_BIST (0x200) +#define CMDH_CLR_BSY (0x400) +#define CMDH_RES (0x800) +#define CMDH_PMP (0xF000) + +/* ATA device register masks */ +#define ATA_DEVICE_MAGIC 0xA0 +#define ATA_DEVICE_LBA 0x40 +#define ATA_DEVICE_DRIVE 0x10 +#define ATA_DEVICE_HEAD 0x0F + /*** Structures ***/ typedef struct AHCIPortQState { -- cgit v1.2.3 From 52515766f1e18b596a6dc31421ca14a63114c9eb Mon Sep 17 00:00:00 2001 From: John Snow <jsnow@redhat.com> Date: Thu, 5 Feb 2015 12:41:21 -0500 Subject: qtest/ahci: add ahci_write_fis Similar to ahci_set_command_header, add a helper that takes an in-memory representation of a command FIS and writes it to guest memory, handling endianness as-needed. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Message-id: 1423158090-25580-11-git-send-email-jsnow@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/ahci-test.c | 2 +- tests/libqos/ahci.c | 14 ++++++++++++++ tests/libqos/ahci.h | 3 ++- 3 files changed, 17 insertions(+), 2 deletions(-) (limited to 'tests') diff --git a/tests/ahci-test.c b/tests/ahci-test.c index 211274e8c3..658956d6a1 100644 --- a/tests/ahci-test.c +++ b/tests/ahci-test.c @@ -728,7 +728,7 @@ static void ahci_test_identify(AHCIQState *ahci) g_assert_cmphex(ahci_px_rreg(ahci, i, AHCI_PX_IS), ==, 0); /* Commit the Command FIS to the Command Table */ - memwrite(table, &fis, sizeof(fis)); + ahci_write_fis(ahci, &fis, table); /* Commit the PRD entry to the Command Table */ memwrite(table + 0x80, &prd, sizeof(prd)); diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c index 8ecfdd30d8..1294f8083c 100644 --- a/tests/libqos/ahci.c +++ b/tests/libqos/ahci.c @@ -464,6 +464,20 @@ void ahci_destroy_command(AHCIQState *ahci, uint8_t port, uint8_t slot) ahci->port[port].prdtl[slot] = 0; } +void ahci_write_fis(AHCIQState *ahci, RegH2DFIS *fis, uint64_t addr) +{ + RegH2DFIS tmp = *fis; + + /* The auxiliary FIS fields are defined per-command and are not + * currently implemented in libqos/ahci.o, but may or may not need + * to be flipped. */ + + /* All other FIS fields are 8 bit and do not need to be flipped. */ + tmp.count = cpu_to_le16(tmp.count); + + memwrite(addr, &tmp, sizeof(tmp)); +} + unsigned ahci_pick_cmd(AHCIQState *ahci, uint8_t port) { unsigned i; diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h index 0837bf5032..83a62acf44 100644 --- a/tests/libqos/ahci.h +++ b/tests/libqos/ahci.h @@ -393,7 +393,7 @@ typedef struct RegH2DFIS { uint8_t icc; uint8_t control; /* DW4 */ - uint32_t aux; + uint8_t aux[4]; } __attribute__((__packed__)) RegH2DFIS; /** @@ -515,6 +515,7 @@ void ahci_get_command_header(AHCIQState *ahci, uint8_t port, void ahci_set_command_header(AHCIQState *ahci, uint8_t port, uint8_t slot, AHCICommandHeader *cmd); void ahci_destroy_command(AHCIQState *ahci, uint8_t port, uint8_t slot); +void ahci_write_fis(AHCIQState *ahci, RegH2DFIS *fis, uint64_t addr); unsigned ahci_pick_cmd(AHCIQState *ahci, uint8_t port); #endif -- cgit v1.2.3 From 716b64079ceaa6fede724f8a24a24b0209fa5173 Mon Sep 17 00:00:00 2001 From: John Snow <jsnow@redhat.com> Date: Thu, 5 Feb 2015 12:41:22 -0500 Subject: libqos/ahci: Add ide cmd properties Add a structure that defines some properties of various IDE commands. These will be used to simplify the interface to the libqos AHCI calls, lessening the redundancy of specifying and respecifying properties of commands to various helper functions. Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Signed-off-by: John Snow <jsnow@redhat.com> Message-id: 1423158090-25580-12-git-send-email-jsnow@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/libqos/ahci.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'tests') diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c index 1294f8083c..148aa1b4b5 100644 --- a/tests/libqos/ahci.c +++ b/tests/libqos/ahci.c @@ -34,6 +34,45 @@ #include "hw/pci/pci_ids.h" #include "hw/pci/pci_regs.h" +typedef struct AHCICommandProp { + uint8_t cmd; /* Command Code */ + bool data; /* Data transfer command? */ + bool pio; + bool dma; + bool lba28; + bool lba48; + bool read; + bool write; + bool atapi; + bool ncq; + uint64_t size; /* Static transfer size, for commands like IDENTIFY. */ + uint32_t interrupts; /* Expected interrupts for this command. */ +} AHCICommandProp; + +AHCICommandProp ahci_command_properties[] = { + { .cmd = CMD_READ_PIO, .data = true, .pio = true, + .lba28 = true, .read = true }, + { .cmd = CMD_WRITE_PIO, .data = true, .pio = true, + .lba28 = true, .write = true }, + { .cmd = CMD_READ_PIO_EXT, .data = true, .pio = true, + .lba48 = true, .read = true }, + { .cmd = CMD_WRITE_PIO_EXT, .data = true, .pio = true, + .lba48 = true, .write = true }, + { .cmd = CMD_READ_DMA, .data = true, .dma = true, + .lba28 = true, .read = true }, + { .cmd = CMD_WRITE_DMA, .data = true, .dma = true, + .lba28 = true, .write = true }, + { .cmd = CMD_READ_DMA_EXT, .data = true, .dma = true, + .lba48 = true, .read = true }, + { .cmd = CMD_WRITE_DMA_EXT, .data = true, .dma = true, + .lba48 = true, .write = true }, + { .cmd = CMD_IDENTIFY, .data = true, .pio = true, + .size = 512, .read = true }, + { .cmd = CMD_READ_MAX, .lba28 = true }, + { .cmd = CMD_READ_MAX_EXT, .lba48 = true }, + { .cmd = CMD_FLUSH_CACHE, .data = false } +}; + /** * Allocate space in the guest using information in the AHCIQState object. */ -- cgit v1.2.3 From 64a5a272e31c99cfb348f908d71c98d2eb83ba28 Mon Sep 17 00:00:00 2001 From: John Snow <jsnow@redhat.com> Date: Thu, 5 Feb 2015 12:41:23 -0500 Subject: libqos/ahci: add ahci command functions This patch adds the AHCICommand structure, and a set of functions to operate on the structure. ahci_command_create - Initialize and create a new AHCICommand in memory ahci_command_free - Destroy this object. ahci_command_set_buffer - Set where the guest memory DMA buffer is. ahci_command_commit - Write this command to the AHCI HBA. ahci_command_issue - Issue the committed command synchronously. ahci_command_issue_async - Issue the committed command asynchronously. ahci_command_wait - Wait for an asynchronous command to finish. ahci_command_slot - Get the number of the command slot we committed to. Helpers: size_to_prdtl - Calculate the required minimum PRDTL size from a buffer size. ahci_command_find - Given an ATA command mnemonic, look it up in the properties table to obtain info about the command. command_header_init - Initialize the command header with sane values. command_table_init - Initialize the command table with sane values. [Peter Maydell <peter.maydell@linaro.org> reported the following clang warning: tests/libqos/ahci.c:598:3: warning: redefinition of typedef 'AHCICommand' is a C11 feature [-Wtypedef-redefinition] } AHCICommand; I have replaced typedef struct ... AHCICommand; with struct ... ; --Stefan] Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Signed-off-by: John Snow <jsnow@redhat.com> Message-id: 1423158090-25580-13-git-send-email-jsnow@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/ahci-test.c | 73 +++++-------------- tests/libqos/ahci.c | 202 ++++++++++++++++++++++++++++++++++++++++++++++++++++ tests/libqos/ahci.h | 18 +++++ 3 files changed, 237 insertions(+), 56 deletions(-) (limited to 'tests') diff --git a/tests/ahci-test.c b/tests/ahci-test.c index 658956d6a1..08340207b3 100644 --- a/tests/ahci-test.c +++ b/tests/ahci-test.c @@ -657,30 +657,28 @@ static void ahci_test_port_spec(AHCIQState *ahci, uint8_t port) */ static void ahci_test_identify(AHCIQState *ahci) { - RegH2DFIS fis; - AHCICommandHeader cmd; - PRD prd; uint32_t data_ptr; uint16_t buff[256]; unsigned i; int rc; + AHCICommand *cmd; uint8_t cx; - uint64_t table; g_assert(ahci != NULL); /* We need to: - * (1) Create a Command Table Buffer and update the Command List Slot #0 - * to point to this buffer. - * (2) Construct an FIS host-to-device command structure, and write it to + * (1) Create a data buffer for the IDENTIFY response to be sent to, + * (2) Create a Command Table Buffer + * (3) Construct an FIS host-to-device command structure, and write it to * the top of the command table buffer. - * (3) Create a data buffer for the IDENTIFY response to be sent to * (4) Create a Physical Region Descriptor that points to the data buffer, * and write it to the bottom (offset 0x80) of the command table. - * (5) Now, PxCLB points to the command list, command 0 points to + * (5) Obtain a Command List slot, and update this header to point to + * the Command Table we built above. + * (6) Now, PxCLB points to the command list, command 0 points to * our table, and our table contains an FIS instruction and a * PRD that points to our rx buffer. - * (6) We inform the HBA via PxCI that there is a command ready in slot #0. + * (7) We inform the HBA via PxCI that there is a command ready in slot #0. */ /* Pick the first implemented and running port */ @@ -690,61 +688,24 @@ static void ahci_test_identify(AHCIQState *ahci) /* Clear out the FIS Receive area and any pending interrupts. */ ahci_port_clear(ahci, i); - /* Create a Command Table buffer. 0x80 is the smallest with a PRDTL of 0. */ - /* We need at least one PRD, so round up to the nearest 0x80 multiple. */ - table = ahci_alloc(ahci, CMD_TBL_SIZ(1)); - g_assert(table); - ASSERT_BIT_CLEAR(table, 0x7F); - - /* Create a data buffer ... where we will dump the IDENTIFY data to. */ + /* Create a data buffer where we will dump the IDENTIFY data to. */ data_ptr = ahci_alloc(ahci, 512); g_assert(data_ptr); - /* pick a command slot (should be 0!) */ - cx = ahci_pick_cmd(ahci, i); - - /* Construct our Command Header (set_command_header handles endianness.) */ - memset(&cmd, 0x00, sizeof(cmd)); - cmd.flags = 5; /* reg_h2d_fis is 5 double-words long */ - cmd.flags |= CMDH_CLR_BSY; /* clear PxTFD.STS.BSY when done */ - cmd.prdtl = 1; /* One PRD table entry. */ - cmd.prdbc = 0; - cmd.ctba = table; - - /* Construct our PRD, noting that DBC is 0-indexed. */ - prd.dba = cpu_to_le64(data_ptr); - prd.res = 0; - /* 511+1 bytes, request DPS interrupt */ - prd.dbc = cpu_to_le32(511 | 0x80000000); - - /* Construct our Command FIS, Based on http://wiki.osdev.org/AHCI */ - memset(&fis, 0x00, sizeof(fis)); - fis.fis_type = REG_H2D_FIS; /* Register Host-to-Device FIS */ - fis.command = CMD_IDENTIFY; - fis.device = 0; - fis.flags = REG_H2D_FIS_CMD; /* Indicate this is a command FIS */ - - /* We've committed nothing yet, no interrupts should be posted yet. */ - g_assert_cmphex(ahci_px_rreg(ahci, i, AHCI_PX_IS), ==, 0); - - /* Commit the Command FIS to the Command Table */ - ahci_write_fis(ahci, &fis, table); - - /* Commit the PRD entry to the Command Table */ - memwrite(table + 0x80, &prd, sizeof(prd)); - - /* Commit Command #cx, pointing to the Table, to the Command List Buffer. */ - ahci_set_command_header(ahci, i, cx, &cmd); + /* Construct the Command Table (FIS and PRDT) and Command Header */ + cmd = ahci_command_create(CMD_IDENTIFY); + ahci_command_set_buffer(cmd, data_ptr); + /* Write the command header and PRDT to guest memory */ + ahci_command_commit(ahci, cmd, i); /* Everything is in place, but we haven't given the go-ahead yet, * so we should find that there are no pending interrupts yet. */ g_assert_cmphex(ahci_px_rreg(ahci, i, AHCI_PX_IS), ==, 0); /* Issue Command #cx via PxCI */ - ahci_px_wreg(ahci, i, AHCI_PX_CI, (1 << cx)); - while (BITSET(ahci_px_rreg(ahci, i, AHCI_PX_TFD), AHCI_PX_TFD_STS_BSY)) { - usleep(50); - } + ahci_command_issue(ahci, cmd); + cx = ahci_command_slot(cmd); + /* Check registers for post-command consistency */ ahci_port_check_error(ahci, i); /* BUG: we expect AHCI_PX_IS_DPS to be set. */ diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c index 148aa1b4b5..21f86c0799 100644 --- a/tests/libqos/ahci.c +++ b/tests/libqos/ahci.c @@ -539,3 +539,205 @@ unsigned ahci_pick_cmd(AHCIQState *ahci, uint8_t port) g_test_message("All command slots were busy."); g_assert_not_reached(); } + +inline unsigned size_to_prdtl(unsigned bytes, unsigned bytes_per_prd) +{ + /* Each PRD can describe up to 4MiB */ + g_assert_cmphex(bytes_per_prd, <=, 4096 * 1024); + g_assert_cmphex(bytes_per_prd & 0x01, ==, 0x00); + return (bytes + bytes_per_prd - 1) / bytes_per_prd; +} + +struct AHCICommand { + /* Test Management Data */ + uint8_t name; + uint8_t port; + uint8_t slot; + uint32_t interrupts; + uint64_t xbytes; + uint32_t prd_size; + uint64_t buffer; + AHCICommandProp *props; + /* Data to be transferred to the guest */ + AHCICommandHeader header; + RegH2DFIS fis; + void *atapi_cmd; +}; + +static AHCICommandProp *ahci_command_find(uint8_t command_name) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ahci_command_properties); i++) { + if (ahci_command_properties[i].cmd == command_name) { + return &ahci_command_properties[i]; + } + } + + return NULL; +} + +/** + * Initializes a basic command header in memory. + * We assume that this is for an ATA command using RegH2DFIS. + */ +static void command_header_init(AHCICommand *cmd) +{ + AHCICommandHeader *hdr = &cmd->header; + AHCICommandProp *props = cmd->props; + + hdr->flags = 5; /* RegH2DFIS is 5 DW long. Must be < 32 */ + hdr->flags |= CMDH_CLR_BSY; /* Clear the BSY bit when done */ + if (props->write) { + hdr->flags |= CMDH_WRITE; + } + if (props->atapi) { + hdr->flags |= CMDH_ATAPI; + } + /* Other flags: PREFETCH, RESET, and BIST */ + hdr->prdtl = size_to_prdtl(cmd->xbytes, cmd->prd_size); + hdr->prdbc = 0; + hdr->ctba = 0; +} + +static void command_table_init(AHCICommand *cmd) +{ + RegH2DFIS *fis = &(cmd->fis); + + fis->fis_type = REG_H2D_FIS; + fis->flags = REG_H2D_FIS_CMD; /* "Command" bit */ + fis->command = cmd->name; + cmd->fis.feature_low = 0x00; + cmd->fis.feature_high = 0x00; + if (cmd->props->lba28 || cmd->props->lba48) { + cmd->fis.device = ATA_DEVICE_LBA; + } + cmd->fis.count = (cmd->xbytes / AHCI_SECTOR_SIZE); + cmd->fis.icc = 0x00; + cmd->fis.control = 0x00; + memset(cmd->fis.aux, 0x00, ARRAY_SIZE(cmd->fis.aux)); +} + +AHCICommand *ahci_command_create(uint8_t command_name) +{ + AHCICommandProp *props = ahci_command_find(command_name); + AHCICommand *cmd; + + g_assert(props); + cmd = g_malloc0(sizeof(AHCICommand)); + g_assert(!(props->dma && props->pio)); + g_assert(!(props->lba28 && props->lba48)); + g_assert(!(props->read && props->write)); + g_assert(!props->size || props->data); + + /* Defaults and book-keeping */ + cmd->props = props; + cmd->name = command_name; + cmd->xbytes = props->size; + cmd->prd_size = 4096; + cmd->buffer = 0xabad1dea; + + cmd->interrupts = AHCI_PX_IS_DHRS; + /* BUG: We expect the DPS interrupt for data commands */ + /* cmd->interrupts |= props->data ? AHCI_PX_IS_DPS : 0; */ + /* BUG: We expect the DMA Setup interrupt for DMA commands */ + /* cmd->interrupts |= props->dma ? AHCI_PX_IS_DSS : 0; */ + cmd->interrupts |= props->pio ? AHCI_PX_IS_PSS : 0; + + command_header_init(cmd); + command_table_init(cmd); + + return cmd; +} + +void ahci_command_free(AHCICommand *cmd) +{ + g_free(cmd); +} + +void ahci_command_set_buffer(AHCICommand *cmd, uint64_t buffer) +{ + cmd->buffer = buffer; +} + +void ahci_command_commit(AHCIQState *ahci, AHCICommand *cmd, uint8_t port) +{ + uint16_t i, prdtl; + uint64_t table_size, table_ptr, remaining; + PRD prd; + + /* This command is now tied to this port/command slot */ + cmd->port = port; + cmd->slot = ahci_pick_cmd(ahci, port); + + /* Create a buffer for the command table */ + prdtl = size_to_prdtl(cmd->xbytes, cmd->prd_size); + table_size = CMD_TBL_SIZ(prdtl); + table_ptr = ahci_alloc(ahci, table_size); + g_assert(table_ptr); + /* AHCI 1.3: Must be aligned to 0x80 */ + g_assert((table_ptr & 0x7F) == 0x00); + cmd->header.ctba = table_ptr; + + /* Commit the command header and command FIS */ + ahci_set_command_header(ahci, port, cmd->slot, &(cmd->header)); + ahci_write_fis(ahci, &(cmd->fis), table_ptr); + + /* Construct and write the PRDs to the command table */ + g_assert_cmphex(prdtl, ==, cmd->header.prdtl); + remaining = cmd->xbytes; + for (i = 0; i < prdtl; ++i) { + prd.dba = cpu_to_le64(cmd->buffer + (cmd->prd_size * i)); + prd.res = 0; + if (remaining > cmd->prd_size) { + /* Note that byte count is 0-based. */ + prd.dbc = cpu_to_le32(cmd->prd_size - 1); + remaining -= cmd->prd_size; + } else { + /* Again, dbc is 0-based. */ + prd.dbc = cpu_to_le32(remaining - 1); + remaining = 0; + } + prd.dbc |= cpu_to_le32(0x80000000); /* Request DPS Interrupt */ + + /* Commit the PRD entry to the Command Table */ + memwrite(table_ptr + 0x80 + (i * sizeof(PRD)), + &prd, sizeof(PRD)); + } + + /* Bookmark the PRDTL and CTBA values */ + ahci->port[port].ctba[cmd->slot] = table_ptr; + ahci->port[port].prdtl[cmd->slot] = prdtl; +} + +void ahci_command_issue_async(AHCIQState *ahci, AHCICommand *cmd) +{ + if (cmd->props->ncq) { + ahci_px_wreg(ahci, cmd->port, AHCI_PX_SACT, (1 << cmd->slot)); + } + + ahci_px_wreg(ahci, cmd->port, AHCI_PX_CI, (1 << cmd->slot)); +} + +void ahci_command_wait(AHCIQState *ahci, AHCICommand *cmd) +{ + /* We can't rely on STS_BSY until the command has started processing. + * Therefore, we also use the Command Issue bit as indication of + * a command in-flight. */ + while (BITSET(ahci_px_rreg(ahci, cmd->port, AHCI_PX_TFD), + AHCI_PX_TFD_STS_BSY) || + BITSET(ahci_px_rreg(ahci, cmd->port, AHCI_PX_CI), (1 << cmd->slot))) { + usleep(50); + } +} + +void ahci_command_issue(AHCIQState *ahci, AHCICommand *cmd) +{ + ahci_command_issue_async(ahci, cmd); + ahci_command_wait(ahci, cmd); +} + +uint8_t ahci_command_slot(AHCICommand *cmd) +{ + return cmd->slot; +} diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h index 83a62acf44..6ca1a6eb15 100644 --- a/tests/libqos/ahci.h +++ b/tests/libqos/ahci.h @@ -418,6 +418,9 @@ typedef struct PRD { uint32_t dbc; /* Data Byte Count (0-indexed) & Interrupt Flag (bit 2^31) */ } __attribute__((__packed__)) PRD; +/* Opaque, defined within ahci.c */ +typedef struct AHCICommand AHCICommand; + /*** Macro Utilities ***/ #define BITANY(data, mask) (((data) & (mask)) != 0) #define BITSET(data, mask) (((data) & (mask)) == (mask)) @@ -517,5 +520,20 @@ void ahci_set_command_header(AHCIQState *ahci, uint8_t port, void ahci_destroy_command(AHCIQState *ahci, uint8_t port, uint8_t slot); void ahci_write_fis(AHCIQState *ahci, RegH2DFIS *fis, uint64_t addr); unsigned ahci_pick_cmd(AHCIQState *ahci, uint8_t port); +unsigned size_to_prdtl(unsigned bytes, unsigned bytes_per_prd); + +/* Command Lifecycle */ +AHCICommand *ahci_command_create(uint8_t command_name); +void ahci_command_commit(AHCIQState *ahci, AHCICommand *cmd, uint8_t port); +void ahci_command_issue(AHCIQState *ahci, AHCICommand *cmd); +void ahci_command_issue_async(AHCIQState *ahci, AHCICommand *cmd); +void ahci_command_wait(AHCIQState *ahci, AHCICommand *cmd); +void ahci_command_free(AHCICommand *cmd); + +/* Command adjustments */ +void ahci_command_set_buffer(AHCICommand *cmd, uint64_t buffer); + +/* Command Misc */ +uint8_t ahci_command_slot(AHCICommand *cmd); #endif -- cgit v1.2.3 From ea41deb6022c1468de094dac12610de74220e4b0 Mon Sep 17 00:00:00 2001 From: John Snow <jsnow@redhat.com> Date: Thu, 5 Feb 2015 12:41:24 -0500 Subject: libqos/ahci: add ahci command verify Helps to verify that a command completed successfully. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Message-id: 1423158090-25580-14-git-send-email-jsnow@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/ahci-test.c | 16 ++-------------- tests/libqos/ahci.c | 15 +++++++++++++++ tests/libqos/ahci.h | 1 + 3 files changed, 18 insertions(+), 14 deletions(-) (limited to 'tests') diff --git a/tests/ahci-test.c b/tests/ahci-test.c index 08340207b3..6e7b76533f 100644 --- a/tests/ahci-test.c +++ b/tests/ahci-test.c @@ -662,7 +662,6 @@ static void ahci_test_identify(AHCIQState *ahci) unsigned i; int rc; AHCICommand *cmd; - uint8_t cx; g_assert(ahci != NULL); @@ -702,20 +701,9 @@ static void ahci_test_identify(AHCIQState *ahci) * so we should find that there are no pending interrupts yet. */ g_assert_cmphex(ahci_px_rreg(ahci, i, AHCI_PX_IS), ==, 0); - /* Issue Command #cx via PxCI */ + /* Issue command and sanity check response. */ ahci_command_issue(ahci, cmd); - cx = ahci_command_slot(cmd); - - /* Check registers for post-command consistency */ - ahci_port_check_error(ahci, i); - /* BUG: we expect AHCI_PX_IS_DPS to be set. */ - ahci_port_check_interrupts(ahci, i, AHCI_PX_IS_DHRS | AHCI_PX_IS_PSS); - ahci_port_check_nonbusy(ahci, i, cx); - /* Investigate the CMD, assert that we read 512 bytes */ - ahci_port_check_cmd_sanity(ahci, i, cx, 512); - /* Investigate FIS responses */ - ahci_port_check_d2h_sanity(ahci, i, cx); - ahci_port_check_pio_sanity(ahci, i, cx, 512); + ahci_command_verify(ahci, cmd); /* Last, but not least: Investigate the IDENTIFY response data. */ memread(data_ptr, &buff, 512); diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c index 21f86c0799..09e7159d25 100644 --- a/tests/libqos/ahci.c +++ b/tests/libqos/ahci.c @@ -737,6 +737,21 @@ void ahci_command_issue(AHCIQState *ahci, AHCICommand *cmd) ahci_command_wait(ahci, cmd); } +void ahci_command_verify(AHCIQState *ahci, AHCICommand *cmd) +{ + uint8_t slot = cmd->slot; + uint8_t port = cmd->port; + + ahci_port_check_error(ahci, port); + ahci_port_check_interrupts(ahci, port, cmd->interrupts); + ahci_port_check_nonbusy(ahci, port, slot); + ahci_port_check_cmd_sanity(ahci, port, slot, cmd->xbytes); + ahci_port_check_d2h_sanity(ahci, port, slot); + if (cmd->props->pio) { + ahci_port_check_pio_sanity(ahci, port, slot, cmd->xbytes); + } +} + uint8_t ahci_command_slot(AHCICommand *cmd) { return cmd->slot; diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h index 6ca1a6eb15..26ccdd6d9b 100644 --- a/tests/libqos/ahci.h +++ b/tests/libqos/ahci.h @@ -528,6 +528,7 @@ void ahci_command_commit(AHCIQState *ahci, AHCICommand *cmd, uint8_t port); void ahci_command_issue(AHCIQState *ahci, AHCICommand *cmd); void ahci_command_issue_async(AHCIQState *ahci, AHCICommand *cmd); void ahci_command_wait(AHCIQState *ahci, AHCICommand *cmd); +void ahci_command_verify(AHCIQState *ahci, AHCICommand *cmd); void ahci_command_free(AHCICommand *cmd); /* Command adjustments */ -- cgit v1.2.3 From cbc97569dcce317f7bb32d766d4dfcbeb7fd3013 Mon Sep 17 00:00:00 2001 From: John Snow <jsnow@redhat.com> Date: Thu, 5 Feb 2015 12:41:25 -0500 Subject: libqos/ahci: add ahci command size setters Adds setters for size, prd_size and both via set_sizes. Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Signed-off-by: John Snow <jsnow@redhat.com> Message-id: 1423158090-25580-15-git-send-email-jsnow@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/libqos/ahci.c | 22 ++++++++++++++++++++++ tests/libqos/ahci.h | 4 ++++ 2 files changed, 26 insertions(+) (limited to 'tests') diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c index 09e7159d25..cd1f3ffcda 100644 --- a/tests/libqos/ahci.c +++ b/tests/libqos/ahci.c @@ -660,6 +660,28 @@ void ahci_command_set_buffer(AHCICommand *cmd, uint64_t buffer) cmd->buffer = buffer; } +void ahci_command_set_sizes(AHCICommand *cmd, uint64_t xbytes, + unsigned prd_size) +{ + /* Each PRD can describe up to 4MiB, and must not be odd. */ + g_assert_cmphex(prd_size, <=, 4096 * 1024); + g_assert_cmphex(prd_size & 0x01, ==, 0x00); + cmd->prd_size = prd_size; + cmd->xbytes = xbytes; + cmd->fis.count = (cmd->xbytes / AHCI_SECTOR_SIZE); + cmd->header.prdtl = size_to_prdtl(cmd->xbytes, cmd->prd_size); +} + +void ahci_command_set_size(AHCICommand *cmd, uint64_t xbytes) +{ + ahci_command_set_sizes(cmd, xbytes, cmd->prd_size); +} + +void ahci_command_set_prd_size(AHCICommand *cmd, unsigned prd_size) +{ + ahci_command_set_sizes(cmd, cmd->xbytes, prd_size); +} + void ahci_command_commit(AHCIQState *ahci, AHCICommand *cmd, uint8_t port) { uint16_t i, prdtl; diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h index 26ccdd6d9b..57ff3445c4 100644 --- a/tests/libqos/ahci.h +++ b/tests/libqos/ahci.h @@ -533,6 +533,10 @@ void ahci_command_free(AHCICommand *cmd); /* Command adjustments */ void ahci_command_set_buffer(AHCICommand *cmd, uint64_t buffer); +void ahci_command_set_size(AHCICommand *cmd, uint64_t xbytes); +void ahci_command_set_prd_size(AHCICommand *cmd, unsigned prd_size); +void ahci_command_set_sizes(AHCICommand *cmd, uint64_t xbytes, + unsigned prd_size); /* Command Misc */ uint8_t ahci_command_slot(AHCICommand *cmd); -- cgit v1.2.3 From 113221956cb819837dda5350e3f9d52819183805 Mon Sep 17 00:00:00 2001 From: John Snow <jsnow@redhat.com> Date: Thu, 5 Feb 2015 12:41:26 -0500 Subject: libqos/ahci: Add ahci_guest_io ahci_guest_io is a shorthand function that will, in one shot, execute a data command on the guest to the specified guest buffer location, in the requested amount. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Message-id: 1423158090-25580-16-git-send-email-jsnow@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/libqos/ahci.c | 15 +++++++++++++++ tests/libqos/ahci.h | 2 ++ 2 files changed, 17 insertions(+) (limited to 'tests') diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c index cd1f3ffcda..345d1f190b 100644 --- a/tests/libqos/ahci.c +++ b/tests/libqos/ahci.c @@ -548,6 +548,21 @@ inline unsigned size_to_prdtl(unsigned bytes, unsigned bytes_per_prd) return (bytes + bytes_per_prd - 1) / bytes_per_prd; } +/* Given a guest buffer address, perform an IO operation */ +void ahci_guest_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd, + uint64_t buffer, size_t bufsize) +{ + AHCICommand *cmd; + + cmd = ahci_command_create(ide_cmd); + ahci_command_set_buffer(cmd, buffer); + ahci_command_set_size(cmd, bufsize); + ahci_command_commit(ahci, cmd, port); + ahci_command_issue(ahci, cmd); + ahci_command_verify(ahci, cmd); + ahci_command_free(cmd); +} + struct AHCICommand { /* Test Management Data */ uint8_t name; diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h index 57ff3445c4..1206c7abab 100644 --- a/tests/libqos/ahci.h +++ b/tests/libqos/ahci.h @@ -521,6 +521,8 @@ void ahci_destroy_command(AHCIQState *ahci, uint8_t port, uint8_t slot); void ahci_write_fis(AHCIQState *ahci, RegH2DFIS *fis, uint64_t addr); unsigned ahci_pick_cmd(AHCIQState *ahci, uint8_t port); unsigned size_to_prdtl(unsigned bytes, unsigned bytes_per_prd); +void ahci_guest_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd, + uint64_t gbuffer, size_t size); /* Command Lifecycle */ AHCICommand *ahci_command_create(uint8_t command_name); -- cgit v1.2.3 From ae029620173239f3643925299790ecc5e1d72db1 Mon Sep 17 00:00:00 2001 From: John Snow <jsnow@redhat.com> Date: Thu, 5 Feb 2015 12:41:27 -0500 Subject: libqos/ahci: add ahci_io ahci_io is a wrapper around ahci_guest_io that takes a pointer to host memory instead, and will create a guest memory buffer and copy the data to/from as needed and as appropriate for a read/write command, such that after a read, the guest data will be in a host buffer, and for a write, the data will be transmitted to guest memory prior to the block operation. Now that we have all the syntactic sugar functions in place for AHCI, we can convert the identify test to be very, very short. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Message-id: 1423158090-25580-17-git-send-email-jsnow@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/ahci-test.c | 63 +++++++++++++++++++++-------------------------------- tests/libqos/ahci.c | 25 +++++++++++++++++++++ tests/libqos/ahci.h | 2 ++ 3 files changed, 52 insertions(+), 38 deletions(-) (limited to 'tests') diff --git a/tests/ahci-test.c b/tests/ahci-test.c index 6e7b76533f..47491fe96c 100644 --- a/tests/ahci-test.c +++ b/tests/ahci-test.c @@ -657,56 +657,43 @@ static void ahci_test_port_spec(AHCIQState *ahci, uint8_t port) */ static void ahci_test_identify(AHCIQState *ahci) { - uint32_t data_ptr; uint16_t buff[256]; - unsigned i; + unsigned px; int rc; - AHCICommand *cmd; + const size_t buffsize = 512; g_assert(ahci != NULL); - /* We need to: - * (1) Create a data buffer for the IDENTIFY response to be sent to, - * (2) Create a Command Table Buffer + /** + * This serves as a bit of a tutorial on AHCI device programming: + * + * (1) Create a data buffer for the IDENTIFY response to be sent to + * (2) Create a Command Table buffer, where we will store the + * command and PRDT (Physical Region Descriptor Table) * (3) Construct an FIS host-to-device command structure, and write it to - * the top of the command table buffer. - * (4) Create a Physical Region Descriptor that points to the data buffer, - * and write it to the bottom (offset 0x80) of the command table. - * (5) Obtain a Command List slot, and update this header to point to - * the Command Table we built above. - * (6) Now, PxCLB points to the command list, command 0 points to - * our table, and our table contains an FIS instruction and a - * PRD that points to our rx buffer. - * (7) We inform the HBA via PxCI that there is a command ready in slot #0. + * the top of the Command Table buffer. + * (4) Create one or more Physical Region Descriptors (PRDs) that describe + * a location in memory where data may be stored/retrieved. + * (5) Write these PRDTs to the bottom (offset 0x80) of the Command Table. + * (6) Each AHCI port has up to 32 command slots. Each slot contains a + * header that points to a Command Table buffer. Pick an unused slot + * and update it to point to the Command Table we have built. + * (7) Now: Command #n points to our Command Table, and our Command Table + * contains the FIS (that describes our command) and the PRDTL, which + * describes our buffer. + * (8) We inform the HBA via PxCI (Command Issue) that the command in slot + * #n is ready for processing. */ /* Pick the first implemented and running port */ - i = ahci_port_select(ahci); - g_test_message("Selected port %u for test", i); + px = ahci_port_select(ahci); + g_test_message("Selected port %u for test", px); /* Clear out the FIS Receive area and any pending interrupts. */ - ahci_port_clear(ahci, i); - - /* Create a data buffer where we will dump the IDENTIFY data to. */ - data_ptr = ahci_alloc(ahci, 512); - g_assert(data_ptr); - - /* Construct the Command Table (FIS and PRDT) and Command Header */ - cmd = ahci_command_create(CMD_IDENTIFY); - ahci_command_set_buffer(cmd, data_ptr); - /* Write the command header and PRDT to guest memory */ - ahci_command_commit(ahci, cmd, i); - - /* Everything is in place, but we haven't given the go-ahead yet, - * so we should find that there are no pending interrupts yet. */ - g_assert_cmphex(ahci_px_rreg(ahci, i, AHCI_PX_IS), ==, 0); - - /* Issue command and sanity check response. */ - ahci_command_issue(ahci, cmd); - ahci_command_verify(ahci, cmd); + ahci_port_clear(ahci, px); - /* Last, but not least: Investigate the IDENTIFY response data. */ - memread(data_ptr, &buff, 512); + /* "Read" 512 bytes using CMD_IDENTIFY into the host buffer. */ + ahci_io(ahci, px, CMD_IDENTIFY, &buff, buffsize); /* Check serial number/version in the buffer */ /* NB: IDENTIFY strings are packed in 16bit little endian chunks. diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c index 345d1f190b..85222248b6 100644 --- a/tests/libqos/ahci.c +++ b/tests/libqos/ahci.c @@ -592,6 +592,31 @@ static AHCICommandProp *ahci_command_find(uint8_t command_name) return NULL; } +/* Given a HOST buffer, create a buffer address and perform an IO operation. */ +void ahci_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd, + void *buffer, size_t bufsize) +{ + uint64_t ptr; + AHCICommandProp *props; + + props = ahci_command_find(ide_cmd); + g_assert(props); + ptr = ahci_alloc(ahci, bufsize); + g_assert(ptr); + + if (props->write) { + memwrite(ptr, buffer, bufsize); + } + + ahci_guest_io(ahci, port, ide_cmd, ptr, bufsize); + + if (props->read) { + memread(ptr, buffer, bufsize); + } + + ahci_free(ahci, ptr); +} + /** * Initializes a basic command header in memory. * We assume that this is for an ATA command using RegH2DFIS. diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h index 1206c7abab..9133033f1c 100644 --- a/tests/libqos/ahci.h +++ b/tests/libqos/ahci.h @@ -523,6 +523,8 @@ unsigned ahci_pick_cmd(AHCIQState *ahci, uint8_t port); unsigned size_to_prdtl(unsigned bytes, unsigned bytes_per_prd); void ahci_guest_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd, uint64_t gbuffer, size_t size); +void ahci_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd, + void *buffer, size_t bufsize); /* Command Lifecycle */ AHCICommand *ahci_command_create(uint8_t command_name); -- cgit v1.2.3 From 259342d34dbdfb304374f569feec26317edd97c9 Mon Sep 17 00:00:00 2001 From: John Snow <jsnow@redhat.com> Date: Thu, 5 Feb 2015 12:41:28 -0500 Subject: libqos/ahci: Add ahci_clean_mem Clean up guest memory being used in ahci_clean_mem, to be called during ahci_shutdown. With all guest memory leaks removed, add an option to the allocator to throw an assertion if a leak occurs. This test adds some sanity to both the AHCI library and the allocator. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Message-id: 1423158090-25580-18-git-send-email-jsnow@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/ahci-test.c | 3 +++ tests/libqos/ahci.c | 18 ++++++++++++++++++ tests/libqos/ahci.h | 1 + tests/libqos/malloc.c | 5 +++++ tests/libqos/malloc.h | 1 + 5 files changed, 28 insertions(+) (limited to 'tests') diff --git a/tests/ahci-test.c b/tests/ahci-test.c index 47491fe96c..3a0131aa66 100644 --- a/tests/ahci-test.c +++ b/tests/ahci-test.c @@ -86,6 +86,7 @@ static AHCIQState *ahci_boot(void) "-device ide-hd,drive=drive0 " "-global ide-hd.ver=%s"; s->parent = qtest_pc_boot(cli, tmp_path, "testdisk", "version"); + alloc_set_flags(s->parent->alloc, ALLOC_LEAK_ASSERT); /* Verify that we have an AHCI device present. */ s->dev = get_ahci_device(&s->fingerprint); @@ -99,6 +100,8 @@ static AHCIQState *ahci_boot(void) static void ahci_shutdown(AHCIQState *ahci) { QOSState *qs = ahci->parent; + + ahci_clean_mem(ahci); free_ahci_device(ahci->dev); g_free(ahci); qtest_shutdown(qs); diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c index 85222248b6..a6105c750f 100644 --- a/tests/libqos/ahci.c +++ b/tests/libqos/ahci.c @@ -130,6 +130,24 @@ void free_ahci_device(QPCIDevice *dev) qpci_free_pc(pcibus); } +/* Free all memory in-use by the AHCI device. */ +void ahci_clean_mem(AHCIQState *ahci) +{ + uint8_t port, slot; + + for (port = 0; port < 32; ++port) { + if (ahci->port[port].fb) { + ahci_free(ahci, ahci->port[port].fb); + } + if (ahci->port[port].clb) { + for (slot = 0; slot < 32; slot++) { + ahci_destroy_command(ahci, port, slot); + } + ahci_free(ahci, ahci->port[port].clb); + } + } +} + /*** Logical Device Initialization ***/ /** diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h index 9133033f1c..39b99d3658 100644 --- a/tests/libqos/ahci.h +++ b/tests/libqos/ahci.h @@ -499,6 +499,7 @@ uint64_t ahci_alloc(AHCIQState *ahci, size_t bytes); void ahci_free(AHCIQState *ahci, uint64_t addr); QPCIDevice *get_ahci_device(uint32_t *fingerprint); void free_ahci_device(QPCIDevice *dev); +void ahci_clean_mem(AHCIQState *ahci); void ahci_pci_enable(AHCIQState *ahci); void start_ahci_device(AHCIQState *ahci); void ahci_hba_enable(AHCIQState *ahci); diff --git a/tests/libqos/malloc.c b/tests/libqos/malloc.c index 42e34345ad..67f31902fd 100644 --- a/tests/libqos/malloc.c +++ b/tests/libqos/malloc.c @@ -324,3 +324,8 @@ void alloc_set_page_size(QGuestAllocator *allocator, size_t page_size) g_assert(is_power_of_2(page_size)); allocator->page_size = page_size; } + +void alloc_set_flags(QGuestAllocator *allocator, QAllocOpts opts) +{ + allocator->opts |= opts; +} diff --git a/tests/libqos/malloc.h b/tests/libqos/malloc.h index a39dba49b0..71ac407dcd 100644 --- a/tests/libqos/malloc.h +++ b/tests/libqos/malloc.h @@ -36,5 +36,6 @@ QGuestAllocator *alloc_init(uint64_t start, uint64_t end); QGuestAllocator *alloc_init_flags(QAllocOpts flags, uint64_t start, uint64_t end); void alloc_set_page_size(QGuestAllocator *allocator, size_t page_size); +void alloc_set_flags(QGuestAllocator *allocator, QAllocOpts opts); #endif -- cgit v1.2.3 From 122482a398db9f02287efce9eec26e08dac82bcd Mon Sep 17 00:00:00 2001 From: John Snow <jsnow@redhat.com> Date: Thu, 5 Feb 2015 12:41:29 -0500 Subject: qtest/ahci: Assert sector size in identify test A minor sanity check to assert that the sector size is 512. The current block layer code deeply assumes that the IDE sector size will be 512 bytes, so we carry forward that assumption here. This is useful for the DMA tests, which currently assume that a sector will always be 512 bytes. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Message-id: 1423158090-25580-19-git-send-email-jsnow@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/ahci-test.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'tests') diff --git a/tests/ahci-test.c b/tests/ahci-test.c index 3a0131aa66..f595b96a94 100644 --- a/tests/ahci-test.c +++ b/tests/ahci-test.c @@ -663,6 +663,7 @@ static void ahci_test_identify(AHCIQState *ahci) uint16_t buff[256]; unsigned px; int rc; + uint16_t sect_size; const size_t buffsize = 512; g_assert(ahci != NULL); @@ -710,6 +711,9 @@ static void ahci_test_identify(AHCIQState *ahci) string_bswap16(&buff[23], 8); rc = memcmp(&buff[23], "version ", 8); g_assert_cmphex(rc, ==, 0); + + sect_size = le16_to_cpu(*((uint16_t *)(&buff[5]))); + g_assert_cmphex(sect_size, ==, 0x200); } /******************************************************************************/ -- cgit v1.2.3 From 81705ee4850b55ef4879c941e4a7703efd3cb760 Mon Sep 17 00:00:00 2001 From: John Snow <jsnow@redhat.com> Date: Thu, 5 Feb 2015 12:41:30 -0500 Subject: qtest/ahci: Adding simple dma read-write test Adds a test case for AHCI wherein we write a 4K block of a changing pattern to sector 0, then read back that 4K and compare the transmit and receive buffers. Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Signed-off-by: John Snow <jsnow@redhat.com> Message-id: 1423158090-25580-20-git-send-email-jsnow@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/ahci-test.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) (limited to 'tests') diff --git a/tests/ahci-test.c b/tests/ahci-test.c index f595b96a94..53fd068c8a 100644 --- a/tests/ahci-test.c +++ b/tests/ahci-test.c @@ -716,6 +716,46 @@ static void ahci_test_identify(AHCIQState *ahci) g_assert_cmphex(sect_size, ==, 0x200); } +static void ahci_test_dma_rw_simple(AHCIQState *ahci) +{ + uint64_t ptr; + uint8_t port; + unsigned i; + const unsigned bufsize = 4096; + unsigned char *tx = g_malloc(bufsize); + unsigned char *rx = g_malloc0(bufsize); + + g_assert(ahci != NULL); + + /* Pick the first running port and clear it. */ + port = ahci_port_select(ahci); + ahci_port_clear(ahci, port); + + /*** Create pattern and transfer to guest ***/ + /* Data buffer in the guest */ + ptr = ahci_alloc(ahci, bufsize); + g_assert(ptr); + + /* Write some indicative pattern to our 4K buffer. */ + for (i = 0; i < bufsize; i++) { + tx[i] = (bufsize - i); + } + memwrite(ptr, tx, bufsize); + + /* Write this buffer to disk, then read it back to the DMA buffer. */ + ahci_guest_io(ahci, port, CMD_WRITE_DMA, ptr, bufsize); + qmemset(ptr, 0x00, bufsize); + ahci_guest_io(ahci, port, CMD_READ_DMA, ptr, bufsize); + + /*** Read back the Data ***/ + memread(ptr, rx, bufsize); + g_assert_cmphex(memcmp(tx, rx, bufsize), ==, 0); + + ahci_free(ahci, ptr); + g_free(tx); + g_free(rx); +} + /******************************************************************************/ /* Test Interfaces */ /******************************************************************************/ @@ -798,6 +838,20 @@ static void test_identify(void) ahci_shutdown(ahci); } +/** + * Perform a simple DMA R/W test, using a single PRD and non-NCQ commands. + */ +static void test_dma_rw_simple(void) +{ + AHCIQState *ahci; + + ahci = ahci_boot(); + ahci_pci_enable(ahci); + ahci_hba_enable(ahci); + ahci_test_dma_rw_simple(ahci); + ahci_shutdown(ahci); +} + /******************************************************************************/ int main(int argc, char **argv) @@ -853,6 +907,7 @@ int main(int argc, char **argv) qtest_add_func("/ahci/hba_spec", test_hba_spec); qtest_add_func("/ahci/hba_enable", test_hba_enable); qtest_add_func("/ahci/identify", test_identify); + qtest_add_func("/ahci/dma/simple", test_dma_rw_simple); ret = g_test_run(); -- cgit v1.2.3 From ed338bb07504091dbf36d9cc741e8363f1962a74 Mon Sep 17 00:00:00 2001 From: Fam Zheng <famz@redhat.com> Date: Fri, 30 Jan 2015 10:49:44 +0800 Subject: qemu-iotests: Add VM method qtest() to iotests.py This will allow test cases to run command in qtest protocol. It's write-only for now. Signed-off-by: Fam Zheng <famz@redhat.com> Reviewed-by: Max Reitz <mreitz@redhat.com> Message-id: 1422586186-9925-4-git-send-email-famz@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/qemu-iotests/iotests.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'tests') diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 241b5ee9dd..85cb9a583f 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -21,8 +21,11 @@ import re import subprocess import string import unittest -import sys; sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'scripts', 'qmp')) +import sys +sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'scripts')) +sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'scripts', 'qmp')) import qmp +import qtest import struct __all__ = ['imgfmt', 'imgproto', 'test_dir' 'qemu_img', 'qemu_io', @@ -81,10 +84,12 @@ class VM(object): def __init__(self): self._monitor_path = os.path.join(test_dir, 'qemu-mon.%d' % os.getpid()) self._qemu_log_path = os.path.join(test_dir, 'qemu-log.%d' % os.getpid()) + self._qtest_path = os.path.join(test_dir, 'qemu-qtest.%d' % os.getpid()) self._args = qemu_args + ['-chardev', 'socket,id=mon,path=' + self._monitor_path, '-mon', 'chardev=mon,mode=control', - '-qtest', 'stdio', '-machine', 'accel=qtest', + '-qtest', 'unix:path=' + self._qtest_path, + '-machine', 'accel=qtest', '-display', 'none', '-vga', 'none'] self._num_drives = 0 @@ -160,9 +165,11 @@ class VM(object): qemulog = open(self._qemu_log_path, 'wb') try: self._qmp = qmp.QEMUMonitorProtocol(self._monitor_path, server=True) + self._qtest = qtest.QEMUQtestProtocol(self._qtest_path, server=True) self._popen = subprocess.Popen(self._args, stdin=devnull, stdout=qemulog, stderr=subprocess.STDOUT) self._qmp.accept() + self._qtest.accept() except: os.remove(self._monitor_path) raise @@ -173,6 +180,7 @@ class VM(object): self._qmp.cmd('quit') self._popen.wait() os.remove(self._monitor_path) + os.remove(self._qtest_path) os.remove(self._qemu_log_path) self._popen = None @@ -185,6 +193,10 @@ class VM(object): return self._qmp.cmd(cmd, args=qmp_args) + def qtest(self, cmd): + '''Send a qtest command to guest''' + return self._qtest.cmd(cmd) + def get_qmp_event(self, wait=False): '''Poll for one queued QMP events and return it''' return self._qmp.pull_event(wait=wait) -- cgit v1.2.3 From df89d112279779609d50db93b024ed71f0402854 Mon Sep 17 00:00:00 2001 From: Fam Zheng <famz@redhat.com> Date: Fri, 30 Jan 2015 10:49:45 +0800 Subject: qemu-iotests: Allow caller to disable underscore convertion for qmp QMP command "block_set_io_throttle" expects underscores in parameters instead of dashes: {iops,bps}_{rd,wr,max}. Add optional argument conv_keys (defaults to True, backward compatible), it will be used in IO throttling test case. Reviewed-by: Benoit Canet <benoit@irqsave.net> Signed-off-by: Fam Zheng <famz@redhat.com> Reviewed-by: Max Reitz <mreitz@redhat.com> Message-id: 1422586186-9925-5-git-send-email-famz@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/qemu-iotests/iotests.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'tests') diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 85cb9a583f..14028540b3 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -185,11 +185,14 @@ class VM(object): self._popen = None underscore_to_dash = string.maketrans('_', '-') - def qmp(self, cmd, **args): + def qmp(self, cmd, conv_keys=True, **args): '''Invoke a QMP command and return the result dict''' qmp_args = dict() for k in args.keys(): - qmp_args[k.translate(self.underscore_to_dash)] = args[k] + if conv_keys: + qmp_args[k.translate(self.underscore_to_dash)] = args[k] + else: + qmp_args[k] = args[k] return self._qmp.cmd(cmd, args=qmp_args) -- cgit v1.2.3 From fb13bbf2fd5292d0aab617709017a4032f328730 Mon Sep 17 00:00:00 2001 From: Fam Zheng <famz@redhat.com> Date: Fri, 30 Jan 2015 10:49:46 +0800 Subject: qemu-iotests: Add 093 for IO throttling This case utilizes qemu-io command "aio_{read,write} -q" to verify the effectiveness of IO throttling options. It's implemented by driving the vm timer from qtest protocol, so the throttling timers are signaled with determinied time duration. Then we verify the completed IO requests are within 10% error of bps and iops limits. "null" protocol is used as the disk backend so that no actual disk IO is performed on host, this will make the blockstats much more deterministic. Both "null-aio" and "null-co" are covered, which is also a simple cross validation test for the driver code. Signed-off-by: Fam Zheng <famz@redhat.com> Reviewed-by: Max Reitz <mreitz@redhat.com> Message-id: 1422586186-9925-6-git-send-email-famz@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/qemu-iotests/093 | 114 +++++++++++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/093.out | 5 ++ tests/qemu-iotests/group | 1 + 3 files changed, 120 insertions(+) create mode 100755 tests/qemu-iotests/093 create mode 100644 tests/qemu-iotests/093.out (limited to 'tests') diff --git a/tests/qemu-iotests/093 b/tests/qemu-iotests/093 new file mode 100755 index 0000000000..b9096a55d4 --- /dev/null +++ b/tests/qemu-iotests/093 @@ -0,0 +1,114 @@ +#!/usr/bin/env python +# +# Tests for IO throttling +# +# Copyright (C) 2015 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +import iotests + +class ThrottleTestCase(iotests.QMPTestCase): + test_img = "null-aio://" + + def blockstats(self, device): + result = self.vm.qmp("query-blockstats") + for r in result['return']: + if r['device'] == device: + stat = r['stats'] + return stat['rd_bytes'], stat['rd_operations'], stat['wr_bytes'], stat['wr_operations'] + raise Exception("Device not found for blockstats: %s" % device) + + def setUp(self): + self.vm = iotests.VM().add_drive(self.test_img) + self.vm.launch() + + def tearDown(self): + self.vm.shutdown() + + def do_test_throttle(self, seconds, params): + def check_limit(limit, num): + # IO throttling algorithm is discrete, allow 10% error so the test + # is more robust + return limit == 0 or \ + (num < seconds * limit * 1.1 + and num > seconds * limit * 0.9) + + nsec_per_sec = 1000000000 + + params['device'] = 'drive0' + + result = self.vm.qmp("block_set_io_throttle", conv_keys=False, **params) + self.assert_qmp(result, 'return', {}) + + # Set vm clock to a known value + ns = seconds * nsec_per_sec + self.vm.qtest("clock_step %d" % ns) + + # Submit enough requests. They will drain bps_max and iops_max, but the + # rest requests won't get executed until we advance the virtual clock + # with qtest interface + rq_size = 512 + rd_nr = max(params['bps'] / rq_size / 2, + params['bps_rd'] / rq_size, + params['iops'] / 2, + params['iops_rd']) + rd_nr *= seconds * 2 + wr_nr = max(params['bps'] / rq_size / 2, + params['bps_wr'] / rq_size, + params['iops'] / 2, + params['iops_wr']) + wr_nr *= seconds * 2 + for i in range(rd_nr): + self.vm.hmp_qemu_io("drive0", "aio_read %d %d" % (i * rq_size, rq_size)) + for i in range(wr_nr): + self.vm.hmp_qemu_io("drive0", "aio_write %d %d" % (i * rq_size, rq_size)) + + start_rd_bytes, start_rd_iops, start_wr_bytes, start_wr_iops = self.blockstats('drive0') + + self.vm.qtest("clock_step %d" % ns) + end_rd_bytes, end_rd_iops, end_wr_bytes, end_wr_iops = self.blockstats('drive0') + + rd_bytes = end_rd_bytes - start_rd_bytes + rd_iops = end_rd_iops - start_rd_iops + wr_bytes = end_wr_bytes - start_wr_bytes + wr_iops = end_wr_iops - start_wr_iops + + self.assertTrue(check_limit(params['bps'], rd_bytes + wr_bytes)) + self.assertTrue(check_limit(params['bps_rd'], rd_bytes)) + self.assertTrue(check_limit(params['bps_wr'], wr_bytes)) + self.assertTrue(check_limit(params['iops'], rd_iops + wr_iops)) + self.assertTrue(check_limit(params['iops_rd'], rd_iops)) + self.assertTrue(check_limit(params['iops_wr'], wr_iops)) + + def test_all(self): + params = {"bps": 4096, + "bps_rd": 4096, + "bps_wr": 4096, + "iops": 10, + "iops_rd": 10, + "iops_wr": 10, + } + # Pick each out of all possible params and test + for tk in params: + limits = dict([(k, 0) for k in params]) + limits[tk] = params[tk] + self.do_test_throttle(5, limits) + +class ThrottleTestCoroutine(ThrottleTestCase): + test_img = "null-co://" + +if __name__ == '__main__': + iotests.main(supported_fmts=["raw"]) diff --git a/tests/qemu-iotests/093.out b/tests/qemu-iotests/093.out new file mode 100644 index 0000000000..fbc63e62f8 --- /dev/null +++ b/tests/qemu-iotests/093.out @@ -0,0 +1,5 @@ +.. +---------------------------------------------------------------------- +Ran 2 tests + +OK diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 6e2447a597..186c7dfd77 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -99,6 +99,7 @@ 090 rw auto quick 091 rw auto 092 rw auto quick +093 auto 094 rw auto quick 095 rw auto quick 097 rw auto backing -- cgit v1.2.3 From 723bfab5cb229436ab31498a19aed931723cd3be Mon Sep 17 00:00:00 2001 From: Max Reitz <mreitz@redhat.com> Date: Wed, 11 Feb 2015 09:58:47 -0500 Subject: iotests: Add test for qemu-img convert to NBD Signed-off-by: Max Reitz <mreitz@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> Message-id: 1423666727-20777-3-git-send-email-mreitz@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/qemu-iotests/123 | 62 ++++++++++++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/123.out | 9 +++++++ tests/qemu-iotests/group | 1 + 3 files changed, 72 insertions(+) create mode 100755 tests/qemu-iotests/123 create mode 100644 tests/qemu-iotests/123.out (limited to 'tests') diff --git a/tests/qemu-iotests/123 b/tests/qemu-iotests/123 new file mode 100755 index 0000000000..ad608035d1 --- /dev/null +++ b/tests/qemu-iotests/123 @@ -0,0 +1,62 @@ +#!/bin/bash +# +# Test case for qemu-img convert to NBD +# +# Copyright (C) 2015 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +# creator +owner=mreitz@redhat.com + +seq="$(basename $0)" +echo "QA output created by $seq" + +here="$PWD" +tmp=/tmp/$$ +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img + rm -f "$SRC_IMG" +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_supported_fmt raw +_supported_proto nbd +_supported_os Linux + +SRC_IMG="$TEST_DIR/source.$IMGFMT" + +_make_test_img 1M +$QEMU_IMG create -f $IMGFMT "$SRC_IMG" 1M | _filter_img_create + +$QEMU_IO -c 'write -P 42 0 1M' "$SRC_IMG" | _filter_qemu_io + +$QEMU_IMG convert -n -f $IMGFMT -O raw "$SRC_IMG" "$TEST_IMG" + +$QEMU_IO -c 'read -P 42 0 1M' "$TEST_IMG" | _filter_qemu_io + + +# success, all done +echo +echo '*** done' +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/123.out b/tests/qemu-iotests/123.out new file mode 100644 index 0000000000..0b818d34c4 --- /dev/null +++ b/tests/qemu-iotests/123.out @@ -0,0 +1,9 @@ +QA output created by 123 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 +Formatting 'TEST_DIR/source.IMGFMT', fmt=IMGFMT size=1048576 +wrote 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +*** done diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 186c7dfd77..86f072ef92 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -119,3 +119,4 @@ 113 rw auto quick 114 rw auto quick 116 rw auto quick +123 rw auto quick -- cgit v1.2.3 From b65a5e12a4136b20f9d06675d597b52d64ac903c Mon Sep 17 00:00:00 2001 From: Max Reitz <mreitz@redhat.com> Date: Thu, 5 Feb 2015 13:58:12 -0500 Subject: block: Add Error parameter to bdrv_find_protocol() The argument given to bdrv_find_protocol() is just a file name, which makes it difficult for the caller to reconstruct what protocol bdrv_find_protocol() was hoping to find. This patch adds an Error parameter to that function to solve this issue. Suggested-by: Eric Blake <eblake@redhat.com> Signed-off-by: Max Reitz <mreitz@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> Message-id: 1423162705-32065-4-git-send-email-mreitz@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/qemu-iotests/051.out | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tests') diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out index f497c5717b..9596e20f58 100644 --- a/tests/qemu-iotests/051.out +++ b/tests/qemu-iotests/051.out @@ -323,10 +323,10 @@ QEMU_PROG: -drive file=TEST_DIR/t.qcow2,readonly=on,read-only=off: 'read-only' a === Parsing protocol from file name === Testing: -hda foo:bar -QEMU_PROG: -hda foo:bar: could not open disk image foo:bar: Unknown protocol +QEMU_PROG: -hda foo:bar: could not open disk image foo:bar: Unknown protocol 'foo' Testing: -drive file=foo:bar -QEMU_PROG: -drive file=foo:bar: could not open disk image foo:bar: Unknown protocol +QEMU_PROG: -drive file=foo:bar: could not open disk image foo:bar: Unknown protocol 'foo' Testing: -drive file.filename=foo:bar QEMU_PROG: -drive file.filename=foo:bar: could not open disk image ide0-hd0: Could not open 'foo:bar': No such file or directory -- cgit v1.2.3 From 80495fdf44ff7e44bafe9f4d8367700a197f1106 Mon Sep 17 00:00:00 2001 From: Max Reitz <mreitz@redhat.com> Date: Thu, 5 Feb 2015 13:58:13 -0500 Subject: iotests: Add test for driver=qcow2, format=qcow2 While specifying a different driver and format is obviously invalid, specifying the same driver once through driver and once through format is invalid as well. Add a test for it. Signed-off-by: Max Reitz <mreitz@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> Message-id: 1423162705-32065-5-git-send-email-mreitz@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/qemu-iotests/051 | 1 + tests/qemu-iotests/051.out | 3 +++ 2 files changed, 4 insertions(+) (limited to 'tests') diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051 index 11c858f27d..27138a2299 100755 --- a/tests/qemu-iotests/051 +++ b/tests/qemu-iotests/051 @@ -93,6 +93,7 @@ echo run_qemu -drive file="$TEST_IMG",format=foo run_qemu -drive file="$TEST_IMG",driver=foo run_qemu -drive file="$TEST_IMG",driver=raw,format=qcow2 +run_qemu -drive file="$TEST_IMG",driver=qcow2,format=qcow2 echo echo === Overriding backing file === diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out index 9596e20f58..e727dc16c4 100644 --- a/tests/qemu-iotests/051.out +++ b/tests/qemu-iotests/051.out @@ -43,6 +43,9 @@ QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=foo: could not open disk image TE Testing: -drive file=TEST_DIR/t.qcow2,driver=raw,format=qcow2 QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=raw,format=qcow2: could not open disk image TEST_DIR/t.qcow2: Driver specified twice +Testing: -drive file=TEST_DIR/t.qcow2,driver=qcow2,format=qcow2 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=qcow2,format=qcow2: could not open disk image TEST_DIR/t.qcow2: Driver specified twice + === Overriding backing file === -- cgit v1.2.3 From e4342ce5a2bc7742c7193d1a3291ae513ca4857a Mon Sep 17 00:00:00 2001 From: Max Reitz <mreitz@redhat.com> Date: Thu, 5 Feb 2015 13:58:14 -0500 Subject: blockdev: Use blk_new_open() in blockdev_init() Due to different error propagation, this breaks tests 051 and 087; fix their output. Signed-off-by: Max Reitz <mreitz@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> Message-id: 1423162705-32065-6-git-send-email-mreitz@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/qemu-iotests/051.out | 62 +++++++++++++++++++++++----------------------- tests/qemu-iotests/087.out | 8 +++--- 2 files changed, 35 insertions(+), 35 deletions(-) (limited to 'tests') diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out index e727dc16c4..bf52bf02d4 100644 --- a/tests/qemu-iotests/051.out +++ b/tests/qemu-iotests/051.out @@ -5,46 +5,46 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file='TEST_DIR === Unknown option === Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt= -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=: could not open disk image TEST_DIR/t.qcow2: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt' +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt' Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=on -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=on: could not open disk image TEST_DIR/t.qcow2: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt' +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=on: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt' Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=1234 -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=1234: could not open disk image TEST_DIR/t.qcow2: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt' +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=1234: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt' Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=foo -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=foo: could not open disk image TEST_DIR/t.qcow2: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt' +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=foo: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt' === Unknown protocol option === Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt= -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=: could not open disk image TEST_DIR/t.qcow2: Block protocol 'file' doesn't support the option 'unknown_opt' +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=: Block protocol 'file' doesn't support the option 'unknown_opt' Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=on -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=on: could not open disk image TEST_DIR/t.qcow2: Block protocol 'file' doesn't support the option 'unknown_opt' +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=on: Block protocol 'file' doesn't support the option 'unknown_opt' Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=1234 -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=1234: could not open disk image TEST_DIR/t.qcow2: Block protocol 'file' doesn't support the option 'unknown_opt' +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=1234: Block protocol 'file' doesn't support the option 'unknown_opt' Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=foo -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=foo: could not open disk image TEST_DIR/t.qcow2: Block protocol 'file' doesn't support the option 'unknown_opt' +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=foo: Block protocol 'file' doesn't support the option 'unknown_opt' === Invalid format === Testing: -drive file=TEST_DIR/t.qcow2,format=foo -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=foo: 'foo' invalid format +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=foo: Unknown driver 'foo' Testing: -drive file=TEST_DIR/t.qcow2,driver=foo -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=foo: could not open disk image TEST_DIR/t.qcow2: Unknown driver 'foo' +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=foo: Unknown driver 'foo' Testing: -drive file=TEST_DIR/t.qcow2,driver=raw,format=qcow2 -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=raw,format=qcow2: could not open disk image TEST_DIR/t.qcow2: Driver specified twice +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=raw,format=qcow2: Cannot specify both 'driver' and 'format' Testing: -drive file=TEST_DIR/t.qcow2,driver=qcow2,format=qcow2 -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=qcow2,format=qcow2: could not open disk image TEST_DIR/t.qcow2: Driver specified twice +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=qcow2,format=qcow2: Cannot specify both 'driver' and 'format' === Overriding backing file === @@ -58,13 +58,13 @@ ide0-hd0: TEST_DIR/t.qcow2 (qcow2) (qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K Testing: -drive file=TEST_DIR/t.qcow2,driver=raw,backing.file.filename=TEST_DIR/t.qcow2.orig -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=raw,backing.file.filename=TEST_DIR/t.qcow2.orig: could not open disk image TEST_DIR/t.qcow2: Driver doesn't support backing files +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=raw,backing.file.filename=TEST_DIR/t.qcow2.orig: Driver doesn't support backing files Testing: -drive file=TEST_DIR/t.qcow2,file.backing.driver=file,file.backing.filename=TEST_DIR/t.qcow2.orig -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,file.backing.driver=file,file.backing.filename=TEST_DIR/t.qcow2.orig: could not open disk image TEST_DIR/t.qcow2: Driver doesn't support backing files +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,file.backing.driver=file,file.backing.filename=TEST_DIR/t.qcow2.orig: Driver doesn't support backing files Testing: -drive file=TEST_DIR/t.qcow2,file.backing.driver=qcow2,file.backing.file.filename=TEST_DIR/t.qcow2.orig -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,file.backing.driver=qcow2,file.backing.file.filename=TEST_DIR/t.qcow2.orig: could not open disk image TEST_DIR/t.qcow2: Driver doesn't support backing files +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,file.backing.driver=qcow2,file.backing.file.filename=TEST_DIR/t.qcow2.orig: Driver doesn't support backing files === Enable and disable lazy refcounting on the command line, plus some invalid values === @@ -78,20 +78,20 @@ QEMU X.Y.Z monitor - type 'help' for more information (qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts= -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=: could not open disk image TEST_DIR/t.qcow2: Parameter 'lazy-refcounts' expects 'on' or 'off' +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=: Parameter 'lazy-refcounts' expects 'on' or 'off' Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=42 -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=42: could not open disk image TEST_DIR/t.qcow2: Parameter 'lazy-refcounts' expects 'on' or 'off' +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=42: Parameter 'lazy-refcounts' expects 'on' or 'off' Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=foo -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=foo: could not open disk image TEST_DIR/t.qcow2: Parameter 'lazy-refcounts' expects 'on' or 'off' +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=foo: Parameter 'lazy-refcounts' expects 'on' or 'off' === With version 2 images enabling lazy refcounts must fail === Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on: could not open disk image TEST_DIR/t.qcow2: Lazy refcounts require a qcow2 image with at least qemu 1.1 compatibility level +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on: Lazy refcounts require a qcow2 image with at least qemu 1.1 compatibility level Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=off QEMU X.Y.Z monitor - type 'help' for more information @@ -251,31 +251,31 @@ QEMU X.Y.Z monitor - type 'help' for more information (qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K Testing: -drive file=TEST_DIR/t.qcow2,file.driver=qcow2 -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,file.driver=qcow2: could not open disk image TEST_DIR/t.qcow2: Block format 'qcow2' used by device '' doesn't support the option 'filename' +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,file.driver=qcow2: Block format 'qcow2' used by device '' doesn't support the option 'filename' === Leaving out required options === Testing: -drive driver=file -QEMU_PROG: -drive driver=file: could not open disk image ide0-hd0: The 'file' block driver requires a file name +QEMU_PROG: -drive driver=file: The 'file' block driver requires a file name Testing: -drive driver=nbd -QEMU_PROG: -drive driver=nbd: could not open disk image ide0-hd0: one of path and host must be specified. +QEMU_PROG: -drive driver=nbd: one of path and host must be specified. Testing: -drive driver=raw -QEMU_PROG: -drive driver=raw: could not open disk image ide0-hd0: Can't use 'raw' as a block driver for the protocol level +QEMU_PROG: -drive driver=raw: Can't use 'raw' as a block driver for the protocol level Testing: -drive file.driver=file -QEMU_PROG: -drive file.driver=file: could not open disk image ide0-hd0: The 'file' block driver requires a file name +QEMU_PROG: -drive file.driver=file: The 'file' block driver requires a file name Testing: -drive file.driver=nbd -QEMU_PROG: -drive file.driver=nbd: could not open disk image ide0-hd0: one of path and host must be specified. +QEMU_PROG: -drive file.driver=nbd: one of path and host must be specified. Testing: -drive file.driver=raw -QEMU_PROG: -drive file.driver=raw: could not open disk image ide0-hd0: Can't use 'raw' as a block driver for the protocol level +QEMU_PROG: -drive file.driver=raw: Can't use 'raw' as a block driver for the protocol level Testing: -drive foo=bar -QEMU_PROG: -drive foo=bar: could not open disk image ide0-hd0: Must specify either driver or file +QEMU_PROG: -drive foo=bar: Must specify either driver or file === Specifying both an option and its legacy alias === @@ -326,13 +326,13 @@ QEMU_PROG: -drive file=TEST_DIR/t.qcow2,readonly=on,read-only=off: 'read-only' a === Parsing protocol from file name === Testing: -hda foo:bar -QEMU_PROG: -hda foo:bar: could not open disk image foo:bar: Unknown protocol 'foo' +QEMU_PROG: -hda foo:bar: Unknown protocol 'foo' Testing: -drive file=foo:bar -QEMU_PROG: -drive file=foo:bar: could not open disk image foo:bar: Unknown protocol 'foo' +QEMU_PROG: -drive file=foo:bar: Unknown protocol 'foo' Testing: -drive file.filename=foo:bar -QEMU_PROG: -drive file.filename=foo:bar: could not open disk image ide0-hd0: Could not open 'foo:bar': No such file or directory +QEMU_PROG: -drive file.filename=foo:bar: Could not open 'foo:bar': No such file or directory Testing: -hda file:TEST_DIR/t.qcow2 QEMU X.Y.Z monitor - type 'help' for more information @@ -343,7 +343,7 @@ QEMU X.Y.Z monitor - type 'help' for more information (qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K Testing: -drive file.filename=file:TEST_DIR/t.qcow2 -QEMU_PROG: -drive file.filename=file:TEST_DIR/t.qcow2: could not open disk image ide0-hd0: Could not open 'file:TEST_DIR/t.qcow2': No such file or directory +QEMU_PROG: -drive file.filename=file:TEST_DIR/t.qcow2: Could not open 'file:TEST_DIR/t.qcow2': No such file or directory === Snapshot mode === diff --git a/tests/qemu-iotests/087.out b/tests/qemu-iotests/087.out index 91f4ea1a8b..0ba2e43b40 100644 --- a/tests/qemu-iotests/087.out +++ b/tests/qemu-iotests/087.out @@ -21,9 +21,9 @@ QMP_VERSION {"return": {}} {"error": {"class": "GenericError", "desc": "Device with id 'disk' already exists"}} {"error": {"class": "GenericError", "desc": "Device name 'test-node' conflicts with an existing node name"}} -{"error": {"class": "GenericError", "desc": "could not open disk image disk2: node-name=disk is conflicting with a device id"}} -{"error": {"class": "GenericError", "desc": "could not open disk image disk2: Duplicate node name"}} -{"error": {"class": "GenericError", "desc": "could not open disk image disk3: node-name=disk3 is conflicting with a device id"}} +{"error": {"class": "GenericError", "desc": "node-name=disk is conflicting with a device id"}} +{"error": {"class": "GenericError", "desc": "Duplicate node name"}} +{"error": {"class": "GenericError", "desc": "node-name=disk3 is conflicting with a device id"}} {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}} @@ -57,7 +57,7 @@ QMP_VERSION Testing: QMP_VERSION {"return": {}} -{"error": {"class": "GenericError", "desc": "could not open disk image disk: Guest must be stopped for opening of encrypted image"}} +{"error": {"class": "GenericError", "desc": "Guest must be stopped for opening of encrypted image"}} {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}} -- cgit v1.2.3 From 10d9d75ce4cfb568b4845d8c4d0e65968f740edf Mon Sep 17 00:00:00 2001 From: Max Reitz <mreitz@redhat.com> Date: Thu, 5 Feb 2015 13:58:21 -0500 Subject: qemu-io: Remove "growable" option Remove "growable" option from the "open" command and from the qemu-io command line. qemu-io is about to be converted to BlockBackend which will make sure that no request exceeds the image size, so the only way to keep "growable" would be to use BlockBackend if it is not given and to directly access the BDS if it is. qemu-io is a debugging tool, therefore removing a rarely used option will have only a very small impact, if any. There was only one qemu-iotest which used the option; since it is not critical, this patch just removes it. Signed-off-by: Max Reitz <mreitz@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> Message-id: 1423162705-32065-13-git-send-email-mreitz@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- tests/qemu-iotests/016 | 73 ---------------------------------------------- tests/qemu-iotests/016.out | 23 --------------- tests/qemu-iotests/group | 2 +- 3 files changed, 1 insertion(+), 97 deletions(-) delete mode 100755 tests/qemu-iotests/016 delete mode 100644 tests/qemu-iotests/016.out (limited to 'tests') diff --git a/tests/qemu-iotests/016 b/tests/qemu-iotests/016 deleted file mode 100755 index 52397aa80e..0000000000 --- a/tests/qemu-iotests/016 +++ /dev/null @@ -1,73 +0,0 @@ -#!/bin/bash -# -# Test I/O after EOF for growable images. -# -# Copyright (C) 2009 Red Hat, Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. -# - -# creator -owner=hch@lst.de - -seq=`basename $0` -echo "QA output created by $seq" - -here=`pwd` -tmp=/tmp/$$ -status=1 # failure is the default! - -_cleanup() -{ - _cleanup_test_img -} -trap "_cleanup; exit \$status" 0 1 2 3 15 - -# get standard environment, filters and checks -. ./common.rc -. ./common.filter - -_supported_fmt raw -_supported_proto file sheepdog nfs -_supported_os Linux - - -# No -f, use probing for the protocol driver -QEMU_IO_PROTO="$QEMU_IO_PROG -g --cache $CACHEMODE" - -size=128M -_make_test_img $size - -echo -echo "== reading at EOF ==" -$QEMU_IO_PROTO -c "read -P 0 $size 512" "$TEST_IMG" | _filter_qemu_io - -echo -echo "== reading far past EOF ==" -$QEMU_IO_PROTO -c "read -P 0 256M 512" "$TEST_IMG" | _filter_qemu_io - -echo -echo "== writing at EOF ==" -$QEMU_IO_PROTO -c "write -P 66 $size 512" "$TEST_IMG" | _filter_qemu_io -$QEMU_IO -c "read -P 66 $size 512" "$TEST_IMG" | _filter_qemu_io - -echo -echo "== writing far past EOF ==" -$QEMU_IO_PROTO -c "write -P 66 256M 512" "$TEST_IMG" | _filter_qemu_io -$QEMU_IO -c "read -P 66 256M 512" "$TEST_IMG" | _filter_qemu_io - -# success, all done -echo "*** done" -rm -f $seq.full -status=0 diff --git a/tests/qemu-iotests/016.out b/tests/qemu-iotests/016.out deleted file mode 100644 index acbd60b4a3..0000000000 --- a/tests/qemu-iotests/016.out +++ /dev/null @@ -1,23 +0,0 @@ -QA output created by 016 -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 - -== reading at EOF == -read 512/512 bytes at offset 134217728 -512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - -== reading far past EOF == -read 512/512 bytes at offset 268435456 -512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - -== writing at EOF == -wrote 512/512 bytes at offset 134217728 -512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -read 512/512 bytes at offset 134217728 -512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - -== writing far past EOF == -wrote 512/512 bytes at offset 268435456 -512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -read 512/512 bytes at offset 268435456 -512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -*** done diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 86f072ef92..0d3b95c258 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -22,7 +22,7 @@ 013 rw auto 014 rw auto 015 rw snapshot auto -016 rw auto quick +# 016 was removed, do not reuse 017 rw backing auto quick 018 rw backing auto quick 019 rw backing auto quick -- cgit v1.2.3