11e8a1faeSThomas Huth /*
21e8a1faeSThomas Huth * QTest testcase for LSI MegaRAID
31e8a1faeSThomas Huth *
41e8a1faeSThomas Huth * Copyright (c) 2017 Red Hat Inc.
51e8a1faeSThomas Huth *
61e8a1faeSThomas Huth * This work is licensed under the terms of the GNU GPL, version 2 or later.
71e8a1faeSThomas Huth * See the COPYING file in the top-level directory.
81e8a1faeSThomas Huth */
91e8a1faeSThomas Huth
101e8a1faeSThomas Huth #include "qemu/osdep.h"
11*907b5105SMarc-André Lureau #include "libqtest.h"
121e8a1faeSThomas Huth #include "qemu/bswap.h"
131e8a1faeSThomas Huth #include "qemu/module.h"
141e8a1faeSThomas Huth #include "libqos/qgraph.h"
151e8a1faeSThomas Huth #include "libqos/pci.h"
161e8a1faeSThomas Huth
171e8a1faeSThomas Huth typedef struct QMegasas QMegasas;
181e8a1faeSThomas Huth
191e8a1faeSThomas Huth struct QMegasas {
201e8a1faeSThomas Huth QOSGraphObject obj;
211e8a1faeSThomas Huth QPCIDevice dev;
221e8a1faeSThomas Huth };
231e8a1faeSThomas Huth
megasas_get_driver(void * obj,const char * interface)241e8a1faeSThomas Huth static void *megasas_get_driver(void *obj, const char *interface)
251e8a1faeSThomas Huth {
261e8a1faeSThomas Huth QMegasas *megasas = obj;
271e8a1faeSThomas Huth
281e8a1faeSThomas Huth if (!g_strcmp0(interface, "pci-device")) {
291e8a1faeSThomas Huth return &megasas->dev;
301e8a1faeSThomas Huth }
311e8a1faeSThomas Huth
321e8a1faeSThomas Huth fprintf(stderr, "%s not present in megasas\n", interface);
331e8a1faeSThomas Huth g_assert_not_reached();
341e8a1faeSThomas Huth }
351e8a1faeSThomas Huth
megasas_create(void * pci_bus,QGuestAllocator * alloc,void * addr)361e8a1faeSThomas Huth static void *megasas_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
371e8a1faeSThomas Huth {
381e8a1faeSThomas Huth QMegasas *megasas = g_new0(QMegasas, 1);
391e8a1faeSThomas Huth QPCIBus *bus = pci_bus;
401e8a1faeSThomas Huth
411e8a1faeSThomas Huth qpci_device_init(&megasas->dev, bus, addr);
421e8a1faeSThomas Huth megasas->obj.get_driver = megasas_get_driver;
431e8a1faeSThomas Huth
441e8a1faeSThomas Huth return &megasas->obj;
451e8a1faeSThomas Huth }
461e8a1faeSThomas Huth
471e8a1faeSThomas Huth /* This used to cause a NULL pointer dereference. */
megasas_pd_get_info_fuzz(void * obj,void * data,QGuestAllocator * alloc)481e8a1faeSThomas Huth static void megasas_pd_get_info_fuzz(void *obj, void *data, QGuestAllocator *alloc)
491e8a1faeSThomas Huth {
501e8a1faeSThomas Huth QMegasas *megasas = obj;
511e8a1faeSThomas Huth QPCIDevice *dev = &megasas->dev;
521e8a1faeSThomas Huth QPCIBar bar;
531e8a1faeSThomas Huth uint32_t context[256];
541e8a1faeSThomas Huth uint64_t context_pa;
551e8a1faeSThomas Huth int i;
561e8a1faeSThomas Huth
571e8a1faeSThomas Huth qpci_device_enable(dev);
581e8a1faeSThomas Huth bar = qpci_iomap(dev, 0, NULL);
591e8a1faeSThomas Huth
601e8a1faeSThomas Huth memset(context, 0, sizeof(context));
611e8a1faeSThomas Huth context[0] = cpu_to_le32(0x05050505);
621e8a1faeSThomas Huth context[1] = cpu_to_le32(0x01010101);
631e8a1faeSThomas Huth for (i = 2; i < ARRAY_SIZE(context); i++) {
641e8a1faeSThomas Huth context[i] = cpu_to_le32(0x41414141);
651e8a1faeSThomas Huth }
661e8a1faeSThomas Huth context[6] = cpu_to_le32(0x02020000);
671e8a1faeSThomas Huth context[7] = cpu_to_le32(0);
681e8a1faeSThomas Huth
691e8a1faeSThomas Huth context_pa = guest_alloc(alloc, sizeof(context));
701e8a1faeSThomas Huth qtest_memwrite(dev->bus->qts, context_pa, context, sizeof(context));
711e8a1faeSThomas Huth qpci_io_writel(dev, bar, 0x40, context_pa);
721e8a1faeSThomas Huth }
731e8a1faeSThomas Huth
megasas_register_nodes(void)741e8a1faeSThomas Huth static void megasas_register_nodes(void)
751e8a1faeSThomas Huth {
761e8a1faeSThomas Huth QOSGraphEdgeOptions opts = {
771e8a1faeSThomas Huth .extra_device_opts = "addr=04.0,id=scsi0",
781e8a1faeSThomas Huth .before_cmd_line = "-drive id=drv0,if=none,file=null-co://,"
791e8a1faeSThomas Huth "file.read-zeroes=on,format=raw",
801e8a1faeSThomas Huth .after_cmd_line = "-device scsi-hd,bus=scsi0.0,drive=drv0",
811e8a1faeSThomas Huth };
821e8a1faeSThomas Huth
831e8a1faeSThomas Huth add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
841e8a1faeSThomas Huth
851e8a1faeSThomas Huth qos_node_create_driver("megasas", megasas_create);
861e8a1faeSThomas Huth qos_node_consumes("megasas", "pci-bus", &opts);
871e8a1faeSThomas Huth qos_node_produces("megasas", "pci-device");
881e8a1faeSThomas Huth
891e8a1faeSThomas Huth qos_add_test("dcmd/pd-get-info/fuzz", "megasas", megasas_pd_get_info_fuzz, NULL);
901e8a1faeSThomas Huth }
911e8a1faeSThomas Huth libqos_init(megasas_register_nodes);
92