virtio-blk-test.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802
  1. /*
  2. * QTest testcase for VirtIO Block Device
  3. *
  4. * Copyright (c) 2014 SUSE LINUX Products GmbH
  5. * Copyright (c) 2014 Marc Marí
  6. *
  7. * This work is licensed under the terms of the GNU GPL, version 2 or later.
  8. * See the COPYING file in the top-level directory.
  9. */
  10. #include "qemu/osdep.h"
  11. #include "libqtest-single.h"
  12. #include "qemu/bswap.h"
  13. #include "qemu/module.h"
  14. #include "standard-headers/linux/virtio_blk.h"
  15. #include "standard-headers/linux/virtio_pci.h"
  16. #include "libqos/qgraph.h"
  17. #include "libqos/virtio-blk.h"
  18. /* TODO actually test the results and get rid of this */
  19. #define qmp_discard_response(...) qobject_unref(qmp(__VA_ARGS__))
  20. #define TEST_IMAGE_SIZE (64 * 1024 * 1024)
  21. #define QVIRTIO_BLK_TIMEOUT_US (30 * 1000 * 1000)
  22. #define PCI_SLOT_HP 0x06
  23. typedef struct QVirtioBlkReq {
  24. uint32_t type;
  25. uint32_t ioprio;
  26. uint64_t sector;
  27. char *data;
  28. uint8_t status;
  29. } QVirtioBlkReq;
  30. #ifdef HOST_WORDS_BIGENDIAN
  31. const bool host_is_big_endian = true;
  32. #else
  33. const bool host_is_big_endian; /* false */
  34. #endif
  35. static void drive_destroy(void *path)
  36. {
  37. unlink(path);
  38. g_free(path);
  39. qos_invalidate_command_line();
  40. }
  41. static char *drive_create(void)
  42. {
  43. int fd, ret;
  44. char *t_path = g_strdup("/tmp/qtest.XXXXXX");
  45. /* Create a temporary raw image */
  46. fd = mkstemp(t_path);
  47. g_assert_cmpint(fd, >=, 0);
  48. ret = ftruncate(fd, TEST_IMAGE_SIZE);
  49. g_assert_cmpint(ret, ==, 0);
  50. close(fd);
  51. g_test_queue_destroy(drive_destroy, t_path);
  52. return t_path;
  53. }
  54. static inline void virtio_blk_fix_request(QVirtioDevice *d, QVirtioBlkReq *req)
  55. {
  56. if (qvirtio_is_big_endian(d) != host_is_big_endian) {
  57. req->type = bswap32(req->type);
  58. req->ioprio = bswap32(req->ioprio);
  59. req->sector = bswap64(req->sector);
  60. }
  61. }
  62. static inline void virtio_blk_fix_dwz_hdr(QVirtioDevice *d,
  63. struct virtio_blk_discard_write_zeroes *dwz_hdr)
  64. {
  65. if (qvirtio_is_big_endian(d) != host_is_big_endian) {
  66. dwz_hdr->sector = bswap64(dwz_hdr->sector);
  67. dwz_hdr->num_sectors = bswap32(dwz_hdr->num_sectors);
  68. dwz_hdr->flags = bswap32(dwz_hdr->flags);
  69. }
  70. }
  71. static uint64_t virtio_blk_request(QGuestAllocator *alloc, QVirtioDevice *d,
  72. QVirtioBlkReq *req, uint64_t data_size)
  73. {
  74. uint64_t addr;
  75. uint8_t status = 0xFF;
  76. switch (req->type) {
  77. case VIRTIO_BLK_T_IN:
  78. case VIRTIO_BLK_T_OUT:
  79. g_assert_cmpuint(data_size % 512, ==, 0);
  80. break;
  81. case VIRTIO_BLK_T_DISCARD:
  82. case VIRTIO_BLK_T_WRITE_ZEROES:
  83. g_assert_cmpuint(data_size %
  84. sizeof(struct virtio_blk_discard_write_zeroes), ==, 0);
  85. break;
  86. default:
  87. g_assert_cmpuint(data_size, ==, 0);
  88. }
  89. addr = guest_alloc(alloc, sizeof(*req) + data_size);
  90. virtio_blk_fix_request(d, req);
  91. memwrite(addr, req, 16);
  92. memwrite(addr + 16, req->data, data_size);
  93. memwrite(addr + 16 + data_size, &status, sizeof(status));
  94. return addr;
  95. }
  96. /* Returns the request virtqueue so the caller can perform further tests */
  97. static QVirtQueue *test_basic(QVirtioDevice *dev, QGuestAllocator *alloc)
  98. {
  99. QVirtioBlkReq req;
  100. uint64_t req_addr;
  101. uint64_t capacity;
  102. uint64_t features;
  103. uint32_t free_head;
  104. uint8_t status;
  105. char *data;
  106. QTestState *qts = global_qtest;
  107. QVirtQueue *vq;
  108. features = qvirtio_get_features(dev);
  109. features = features & ~(QVIRTIO_F_BAD_FEATURE |
  110. (1u << VIRTIO_RING_F_INDIRECT_DESC) |
  111. (1u << VIRTIO_RING_F_EVENT_IDX) |
  112. (1u << VIRTIO_BLK_F_SCSI));
  113. qvirtio_set_features(dev, features);
  114. capacity = qvirtio_config_readq(dev, 0);
  115. g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
  116. vq = qvirtqueue_setup(dev, alloc, 0);
  117. qvirtio_set_driver_ok(dev);
  118. /* Write and read with 3 descriptor layout */
  119. /* Write request */
  120. req.type = VIRTIO_BLK_T_OUT;
  121. req.ioprio = 1;
  122. req.sector = 0;
  123. req.data = g_malloc0(512);
  124. strcpy(req.data, "TEST");
  125. req_addr = virtio_blk_request(alloc, dev, &req, 512);
  126. g_free(req.data);
  127. free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
  128. qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true);
  129. qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
  130. qvirtqueue_kick(qts, dev, vq, free_head);
  131. qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
  132. QVIRTIO_BLK_TIMEOUT_US);
  133. status = readb(req_addr + 528);
  134. g_assert_cmpint(status, ==, 0);
  135. guest_free(alloc, req_addr);
  136. /* Read request */
  137. req.type = VIRTIO_BLK_T_IN;
  138. req.ioprio = 1;
  139. req.sector = 0;
  140. req.data = g_malloc0(512);
  141. req_addr = virtio_blk_request(alloc, dev, &req, 512);
  142. g_free(req.data);
  143. free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
  144. qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true);
  145. qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
  146. qvirtqueue_kick(qts, dev, vq, free_head);
  147. qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
  148. QVIRTIO_BLK_TIMEOUT_US);
  149. status = readb(req_addr + 528);
  150. g_assert_cmpint(status, ==, 0);
  151. data = g_malloc0(512);
  152. memread(req_addr + 16, data, 512);
  153. g_assert_cmpstr(data, ==, "TEST");
  154. g_free(data);
  155. guest_free(alloc, req_addr);
  156. if (features & (1u << VIRTIO_BLK_F_WRITE_ZEROES)) {
  157. struct virtio_blk_discard_write_zeroes dwz_hdr;
  158. void *expected;
  159. /*
  160. * WRITE_ZEROES request on the same sector of previous test where
  161. * we wrote "TEST".
  162. */
  163. req.type = VIRTIO_BLK_T_WRITE_ZEROES;
  164. req.data = (char *) &dwz_hdr;
  165. dwz_hdr.sector = 0;
  166. dwz_hdr.num_sectors = 1;
  167. dwz_hdr.flags = 0;
  168. virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
  169. req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
  170. free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
  171. qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true);
  172. qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr), 1, true,
  173. false);
  174. qvirtqueue_kick(qts, dev, vq, free_head);
  175. qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
  176. QVIRTIO_BLK_TIMEOUT_US);
  177. status = readb(req_addr + 16 + sizeof(dwz_hdr));
  178. g_assert_cmpint(status, ==, 0);
  179. guest_free(alloc, req_addr);
  180. /* Read request to check if the sector contains all zeroes */
  181. req.type = VIRTIO_BLK_T_IN;
  182. req.ioprio = 1;
  183. req.sector = 0;
  184. req.data = g_malloc0(512);
  185. req_addr = virtio_blk_request(alloc, dev, &req, 512);
  186. g_free(req.data);
  187. free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
  188. qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true);
  189. qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
  190. qvirtqueue_kick(qts, dev, vq, free_head);
  191. qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
  192. QVIRTIO_BLK_TIMEOUT_US);
  193. status = readb(req_addr + 528);
  194. g_assert_cmpint(status, ==, 0);
  195. data = g_malloc(512);
  196. expected = g_malloc0(512);
  197. memread(req_addr + 16, data, 512);
  198. g_assert_cmpmem(data, 512, expected, 512);
  199. g_free(expected);
  200. g_free(data);
  201. guest_free(alloc, req_addr);
  202. }
  203. if (features & (1u << VIRTIO_BLK_F_DISCARD)) {
  204. struct virtio_blk_discard_write_zeroes dwz_hdr;
  205. req.type = VIRTIO_BLK_T_DISCARD;
  206. req.data = (char *) &dwz_hdr;
  207. dwz_hdr.sector = 0;
  208. dwz_hdr.num_sectors = 1;
  209. dwz_hdr.flags = 0;
  210. virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
  211. req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
  212. free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
  213. qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true);
  214. qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr), 1, true, false);
  215. qvirtqueue_kick(qts, dev, vq, free_head);
  216. qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
  217. QVIRTIO_BLK_TIMEOUT_US);
  218. status = readb(req_addr + 16 + sizeof(dwz_hdr));
  219. g_assert_cmpint(status, ==, 0);
  220. guest_free(alloc, req_addr);
  221. }
  222. if (features & (1u << VIRTIO_F_ANY_LAYOUT)) {
  223. /* Write and read with 2 descriptor layout */
  224. /* Write request */
  225. req.type = VIRTIO_BLK_T_OUT;
  226. req.ioprio = 1;
  227. req.sector = 1;
  228. req.data = g_malloc0(512);
  229. strcpy(req.data, "TEST");
  230. req_addr = virtio_blk_request(alloc, dev, &req, 512);
  231. g_free(req.data);
  232. free_head = qvirtqueue_add(qts, vq, req_addr, 528, false, true);
  233. qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
  234. qvirtqueue_kick(qts, dev, vq, free_head);
  235. qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
  236. QVIRTIO_BLK_TIMEOUT_US);
  237. status = readb(req_addr + 528);
  238. g_assert_cmpint(status, ==, 0);
  239. guest_free(alloc, req_addr);
  240. /* Read request */
  241. req.type = VIRTIO_BLK_T_IN;
  242. req.ioprio = 1;
  243. req.sector = 1;
  244. req.data = g_malloc0(512);
  245. req_addr = virtio_blk_request(alloc, dev, &req, 512);
  246. g_free(req.data);
  247. free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
  248. qvirtqueue_add(qts, vq, req_addr + 16, 513, true, false);
  249. qvirtqueue_kick(qts, dev, vq, free_head);
  250. qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
  251. QVIRTIO_BLK_TIMEOUT_US);
  252. status = readb(req_addr + 528);
  253. g_assert_cmpint(status, ==, 0);
  254. data = g_malloc0(512);
  255. memread(req_addr + 16, data, 512);
  256. g_assert_cmpstr(data, ==, "TEST");
  257. g_free(data);
  258. guest_free(alloc, req_addr);
  259. }
  260. return vq;
  261. }
  262. static void basic(void *obj, void *data, QGuestAllocator *t_alloc)
  263. {
  264. QVirtioBlk *blk_if = obj;
  265. QVirtQueue *vq;
  266. vq = test_basic(blk_if->vdev, t_alloc);
  267. qvirtqueue_cleanup(blk_if->vdev->bus, vq, t_alloc);
  268. }
  269. static void indirect(void *obj, void *u_data, QGuestAllocator *t_alloc)
  270. {
  271. QVirtQueue *vq;
  272. QVirtioBlk *blk_if = obj;
  273. QVirtioDevice *dev = blk_if->vdev;
  274. QVirtioBlkReq req;
  275. QVRingIndirectDesc *indirect;
  276. uint64_t req_addr;
  277. uint64_t capacity;
  278. uint64_t features;
  279. uint32_t free_head;
  280. uint8_t status;
  281. char *data;
  282. QTestState *qts = global_qtest;
  283. features = qvirtio_get_features(dev);
  284. g_assert_cmphex(features & (1u << VIRTIO_RING_F_INDIRECT_DESC), !=, 0);
  285. features = features & ~(QVIRTIO_F_BAD_FEATURE |
  286. (1u << VIRTIO_RING_F_EVENT_IDX) |
  287. (1u << VIRTIO_BLK_F_SCSI));
  288. qvirtio_set_features(dev, features);
  289. capacity = qvirtio_config_readq(dev, 0);
  290. g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
  291. vq = qvirtqueue_setup(dev, t_alloc, 0);
  292. qvirtio_set_driver_ok(dev);
  293. /* Write request */
  294. req.type = VIRTIO_BLK_T_OUT;
  295. req.ioprio = 1;
  296. req.sector = 0;
  297. req.data = g_malloc0(512);
  298. strcpy(req.data, "TEST");
  299. req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
  300. g_free(req.data);
  301. indirect = qvring_indirect_desc_setup(qts, dev, t_alloc, 2);
  302. qvring_indirect_desc_add(dev, qts, indirect, req_addr, 528, false);
  303. qvring_indirect_desc_add(dev, qts, indirect, req_addr + 528, 1, true);
  304. free_head = qvirtqueue_add_indirect(qts, vq, indirect);
  305. qvirtqueue_kick(qts, dev, vq, free_head);
  306. qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
  307. QVIRTIO_BLK_TIMEOUT_US);
  308. status = readb(req_addr + 528);
  309. g_assert_cmpint(status, ==, 0);
  310. g_free(indirect);
  311. guest_free(t_alloc, req_addr);
  312. /* Read request */
  313. req.type = VIRTIO_BLK_T_IN;
  314. req.ioprio = 1;
  315. req.sector = 0;
  316. req.data = g_malloc0(512);
  317. strcpy(req.data, "TEST");
  318. req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
  319. g_free(req.data);
  320. indirect = qvring_indirect_desc_setup(qts, dev, t_alloc, 2);
  321. qvring_indirect_desc_add(dev, qts, indirect, req_addr, 16, false);
  322. qvring_indirect_desc_add(dev, qts, indirect, req_addr + 16, 513, true);
  323. free_head = qvirtqueue_add_indirect(qts, vq, indirect);
  324. qvirtqueue_kick(qts, dev, vq, free_head);
  325. qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
  326. QVIRTIO_BLK_TIMEOUT_US);
  327. status = readb(req_addr + 528);
  328. g_assert_cmpint(status, ==, 0);
  329. data = g_malloc0(512);
  330. memread(req_addr + 16, data, 512);
  331. g_assert_cmpstr(data, ==, "TEST");
  332. g_free(data);
  333. g_free(indirect);
  334. guest_free(t_alloc, req_addr);
  335. qvirtqueue_cleanup(dev->bus, vq, t_alloc);
  336. }
  337. static void config(void *obj, void *data, QGuestAllocator *t_alloc)
  338. {
  339. QVirtioBlk *blk_if = obj;
  340. QVirtioDevice *dev = blk_if->vdev;
  341. int n_size = TEST_IMAGE_SIZE / 2;
  342. uint64_t features;
  343. uint64_t capacity;
  344. features = qvirtio_get_features(dev);
  345. features = features & ~(QVIRTIO_F_BAD_FEATURE |
  346. (1u << VIRTIO_RING_F_INDIRECT_DESC) |
  347. (1u << VIRTIO_RING_F_EVENT_IDX) |
  348. (1u << VIRTIO_BLK_F_SCSI));
  349. qvirtio_set_features(dev, features);
  350. capacity = qvirtio_config_readq(dev, 0);
  351. g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
  352. qvirtio_set_driver_ok(dev);
  353. qmp_discard_response("{ 'execute': 'block_resize', "
  354. " 'arguments': { 'device': 'drive0', "
  355. " 'size': %d } }", n_size);
  356. qvirtio_wait_config_isr(dev, QVIRTIO_BLK_TIMEOUT_US);
  357. capacity = qvirtio_config_readq(dev, 0);
  358. g_assert_cmpint(capacity, ==, n_size / 512);
  359. }
  360. static void msix(void *obj, void *u_data, QGuestAllocator *t_alloc)
  361. {
  362. QVirtQueue *vq;
  363. QVirtioBlkPCI *blk = obj;
  364. QVirtioPCIDevice *pdev = &blk->pci_vdev;
  365. QVirtioDevice *dev = &pdev->vdev;
  366. QVirtioBlkReq req;
  367. int n_size = TEST_IMAGE_SIZE / 2;
  368. uint64_t req_addr;
  369. uint64_t capacity;
  370. uint64_t features;
  371. uint32_t free_head;
  372. uint8_t status;
  373. char *data;
  374. QOSGraphObject *blk_object = obj;
  375. QPCIDevice *pci_dev = blk_object->get_driver(blk_object, "pci-device");
  376. QTestState *qts = global_qtest;
  377. if (qpci_check_buggy_msi(pci_dev)) {
  378. return;
  379. }
  380. qpci_msix_enable(pdev->pdev);
  381. qvirtio_pci_set_msix_configuration_vector(pdev, t_alloc, 0);
  382. features = qvirtio_get_features(dev);
  383. features = features & ~(QVIRTIO_F_BAD_FEATURE |
  384. (1u << VIRTIO_RING_F_INDIRECT_DESC) |
  385. (1u << VIRTIO_RING_F_EVENT_IDX) |
  386. (1u << VIRTIO_BLK_F_SCSI));
  387. qvirtio_set_features(dev, features);
  388. capacity = qvirtio_config_readq(dev, 0);
  389. g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
  390. vq = qvirtqueue_setup(dev, t_alloc, 0);
  391. qvirtqueue_pci_msix_setup(pdev, (QVirtQueuePCI *)vq, t_alloc, 1);
  392. qvirtio_set_driver_ok(dev);
  393. qmp_discard_response("{ 'execute': 'block_resize', "
  394. " 'arguments': { 'device': 'drive0', "
  395. " 'size': %d } }", n_size);
  396. qvirtio_wait_config_isr(dev, QVIRTIO_BLK_TIMEOUT_US);
  397. capacity = qvirtio_config_readq(dev, 0);
  398. g_assert_cmpint(capacity, ==, n_size / 512);
  399. /* Write request */
  400. req.type = VIRTIO_BLK_T_OUT;
  401. req.ioprio = 1;
  402. req.sector = 0;
  403. req.data = g_malloc0(512);
  404. strcpy(req.data, "TEST");
  405. req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
  406. g_free(req.data);
  407. free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
  408. qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true);
  409. qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
  410. qvirtqueue_kick(qts, dev, vq, free_head);
  411. qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
  412. QVIRTIO_BLK_TIMEOUT_US);
  413. status = readb(req_addr + 528);
  414. g_assert_cmpint(status, ==, 0);
  415. guest_free(t_alloc, req_addr);
  416. /* Read request */
  417. req.type = VIRTIO_BLK_T_IN;
  418. req.ioprio = 1;
  419. req.sector = 0;
  420. req.data = g_malloc0(512);
  421. req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
  422. g_free(req.data);
  423. free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
  424. qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true);
  425. qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
  426. qvirtqueue_kick(qts, dev, vq, free_head);
  427. qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
  428. QVIRTIO_BLK_TIMEOUT_US);
  429. status = readb(req_addr + 528);
  430. g_assert_cmpint(status, ==, 0);
  431. data = g_malloc0(512);
  432. memread(req_addr + 16, data, 512);
  433. g_assert_cmpstr(data, ==, "TEST");
  434. g_free(data);
  435. guest_free(t_alloc, req_addr);
  436. /* End test */
  437. qpci_msix_disable(pdev->pdev);
  438. qvirtqueue_cleanup(dev->bus, vq, t_alloc);
  439. }
  440. static void idx(void *obj, void *u_data, QGuestAllocator *t_alloc)
  441. {
  442. QVirtQueue *vq;
  443. QVirtioBlkPCI *blk = obj;
  444. QVirtioPCIDevice *pdev = &blk->pci_vdev;
  445. QVirtioDevice *dev = &pdev->vdev;
  446. QVirtioBlkReq req;
  447. uint64_t req_addr;
  448. uint64_t capacity;
  449. uint64_t features;
  450. uint32_t free_head;
  451. uint32_t write_head;
  452. uint32_t desc_idx;
  453. uint8_t status;
  454. char *data;
  455. QOSGraphObject *blk_object = obj;
  456. QPCIDevice *pci_dev = blk_object->get_driver(blk_object, "pci-device");
  457. QTestState *qts = global_qtest;
  458. if (qpci_check_buggy_msi(pci_dev)) {
  459. return;
  460. }
  461. qpci_msix_enable(pdev->pdev);
  462. qvirtio_pci_set_msix_configuration_vector(pdev, t_alloc, 0);
  463. features = qvirtio_get_features(dev);
  464. features = features & ~(QVIRTIO_F_BAD_FEATURE |
  465. (1u << VIRTIO_RING_F_INDIRECT_DESC) |
  466. (1u << VIRTIO_F_NOTIFY_ON_EMPTY) |
  467. (1u << VIRTIO_BLK_F_SCSI));
  468. qvirtio_set_features(dev, features);
  469. capacity = qvirtio_config_readq(dev, 0);
  470. g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
  471. vq = qvirtqueue_setup(dev, t_alloc, 0);
  472. qvirtqueue_pci_msix_setup(pdev, (QVirtQueuePCI *)vq, t_alloc, 1);
  473. qvirtio_set_driver_ok(dev);
  474. /* Write request */
  475. req.type = VIRTIO_BLK_T_OUT;
  476. req.ioprio = 1;
  477. req.sector = 0;
  478. req.data = g_malloc0(512);
  479. strcpy(req.data, "TEST");
  480. req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
  481. g_free(req.data);
  482. free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
  483. qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true);
  484. qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
  485. qvirtqueue_kick(qts, dev, vq, free_head);
  486. qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
  487. QVIRTIO_BLK_TIMEOUT_US);
  488. /* Write request */
  489. req.type = VIRTIO_BLK_T_OUT;
  490. req.ioprio = 1;
  491. req.sector = 1;
  492. req.data = g_malloc0(512);
  493. strcpy(req.data, "TEST");
  494. req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
  495. g_free(req.data);
  496. /* Notify after processing the third request */
  497. qvirtqueue_set_used_event(qts, vq, 2);
  498. free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
  499. qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true);
  500. qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
  501. qvirtqueue_kick(qts, dev, vq, free_head);
  502. write_head = free_head;
  503. /* No notification expected */
  504. status = qvirtio_wait_status_byte_no_isr(qts, dev,
  505. vq, req_addr + 528,
  506. QVIRTIO_BLK_TIMEOUT_US);
  507. g_assert_cmpint(status, ==, 0);
  508. guest_free(t_alloc, req_addr);
  509. /* Read request */
  510. req.type = VIRTIO_BLK_T_IN;
  511. req.ioprio = 1;
  512. req.sector = 1;
  513. req.data = g_malloc0(512);
  514. req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
  515. g_free(req.data);
  516. free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
  517. qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true);
  518. qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
  519. qvirtqueue_kick(qts, dev, vq, free_head);
  520. /* We get just one notification for both requests */
  521. qvirtio_wait_used_elem(qts, dev, vq, write_head, NULL,
  522. QVIRTIO_BLK_TIMEOUT_US);
  523. g_assert(qvirtqueue_get_buf(qts, vq, &desc_idx, NULL));
  524. g_assert_cmpint(desc_idx, ==, free_head);
  525. status = readb(req_addr + 528);
  526. g_assert_cmpint(status, ==, 0);
  527. data = g_malloc0(512);
  528. memread(req_addr + 16, data, 512);
  529. g_assert_cmpstr(data, ==, "TEST");
  530. g_free(data);
  531. guest_free(t_alloc, req_addr);
  532. /* End test */
  533. qpci_msix_disable(pdev->pdev);
  534. qvirtqueue_cleanup(dev->bus, vq, t_alloc);
  535. }
  536. static void pci_hotplug(void *obj, void *data, QGuestAllocator *t_alloc)
  537. {
  538. QVirtioPCIDevice *dev1 = obj;
  539. QVirtioPCIDevice *dev;
  540. QTestState *qts = dev1->pdev->bus->qts;
  541. /* plug secondary disk */
  542. qtest_qmp_device_add(qts, "virtio-blk-pci", "drv1",
  543. "{'addr': %s, 'drive': 'drive1'}",
  544. stringify(PCI_SLOT_HP) ".0");
  545. dev = virtio_pci_new(dev1->pdev->bus,
  546. &(QPCIAddress) { .devfn = QPCI_DEVFN(PCI_SLOT_HP, 0) });
  547. g_assert_nonnull(dev);
  548. g_assert_cmpint(dev->vdev.device_type, ==, VIRTIO_ID_BLOCK);
  549. qvirtio_pci_device_disable(dev);
  550. qos_object_destroy((QOSGraphObject *)dev);
  551. /* unplug secondary disk */
  552. qpci_unplug_acpi_device_test(qts, "drv1", PCI_SLOT_HP);
  553. }
  554. /*
  555. * Check that setting the vring addr on a non-existent virtqueue does
  556. * not crash.
  557. */
  558. static void test_nonexistent_virtqueue(void *obj, void *data,
  559. QGuestAllocator *t_alloc)
  560. {
  561. QVirtioBlkPCI *blk = obj;
  562. QVirtioPCIDevice *pdev = &blk->pci_vdev;
  563. QPCIBar bar0;
  564. QPCIDevice *dev;
  565. dev = qpci_device_find(pdev->pdev->bus, QPCI_DEVFN(4, 0));
  566. g_assert(dev != NULL);
  567. qpci_device_enable(dev);
  568. bar0 = qpci_iomap(dev, 0, NULL);
  569. qpci_io_writeb(dev, bar0, VIRTIO_PCI_QUEUE_SEL, 2);
  570. qpci_io_writel(dev, bar0, VIRTIO_PCI_QUEUE_PFN, 1);
  571. g_free(dev);
  572. }
  573. static void resize(void *obj, void *data, QGuestAllocator *t_alloc)
  574. {
  575. QVirtioBlk *blk_if = obj;
  576. QVirtioDevice *dev = blk_if->vdev;
  577. int n_size = TEST_IMAGE_SIZE / 2;
  578. uint64_t capacity;
  579. QVirtQueue *vq;
  580. QTestState *qts = global_qtest;
  581. vq = test_basic(dev, t_alloc);
  582. qmp_discard_response("{ 'execute': 'block_resize', "
  583. " 'arguments': { 'device': 'drive0', "
  584. " 'size': %d } }", n_size);
  585. qvirtio_wait_queue_isr(qts, dev, vq, QVIRTIO_BLK_TIMEOUT_US);
  586. capacity = qvirtio_config_readq(dev, 0);
  587. g_assert_cmpint(capacity, ==, n_size / 512);
  588. qvirtqueue_cleanup(dev->bus, vq, t_alloc);
  589. }
  590. static void *virtio_blk_test_setup(GString *cmd_line, void *arg)
  591. {
  592. char *tmp_path = drive_create();
  593. g_string_append_printf(cmd_line,
  594. " -drive if=none,id=drive0,file=%s,"
  595. "format=raw,auto-read-only=off "
  596. "-drive if=none,id=drive1,file=null-co://,"
  597. "file.read-zeroes=on,format=raw ",
  598. tmp_path);
  599. return arg;
  600. }
  601. static void register_virtio_blk_test(void)
  602. {
  603. QOSGraphTestOptions opts = {
  604. .before = virtio_blk_test_setup,
  605. };
  606. qos_add_test("indirect", "virtio-blk", indirect, &opts);
  607. qos_add_test("config", "virtio-blk", config, &opts);
  608. qos_add_test("basic", "virtio-blk", basic, &opts);
  609. qos_add_test("resize", "virtio-blk", resize, &opts);
  610. /* tests just for virtio-blk-pci */
  611. qos_add_test("msix", "virtio-blk-pci", msix, &opts);
  612. qos_add_test("idx", "virtio-blk-pci", idx, &opts);
  613. qos_add_test("nxvirtq", "virtio-blk-pci",
  614. test_nonexistent_virtqueue, &opts);
  615. qos_add_test("hotplug", "virtio-blk-pci", pci_hotplug, &opts);
  616. }
  617. libqos_init(register_virtio_blk_test);