11dcac3e1SXiao Feng Ren /* 21dcac3e1SXiao Feng Ren * vfio based subchannel assignment support 31dcac3e1SXiao Feng Ren * 41dcac3e1SXiao Feng Ren * Copyright 2017 IBM Corp. 58fadea24SCornelia Huck * Copyright 2019 Red Hat, Inc. 68fadea24SCornelia Huck * 71dcac3e1SXiao Feng Ren * Author(s): Dong Jia Shi <bjsdjshi@linux.vnet.ibm.com> 81dcac3e1SXiao Feng Ren * Xiao Feng Ren <renxiaof@linux.vnet.ibm.com> 91dcac3e1SXiao Feng Ren * Pierre Morel <pmorel@linux.vnet.ibm.com> 108fadea24SCornelia Huck * Cornelia Huck <cohuck@redhat.com> 111dcac3e1SXiao Feng Ren * 121dcac3e1SXiao Feng Ren * This work is licensed under the terms of the GNU GPL, version 2 or (at 1308b824aaSCornelia Huck * your option) any later version. See the COPYING file in the top-level 141dcac3e1SXiao Feng Ren * directory. 151dcac3e1SXiao Feng Ren */ 161dcac3e1SXiao Feng Ren 17e9808d09SPhilippe Mathieu-Daudé #include "qemu/osdep.h" 181dcac3e1SXiao Feng Ren #include <linux/vfio.h> 19c14e706cSDong Jia Shi #include <linux/vfio_ccw.h> 201dcac3e1SXiao Feng Ren #include <sys/ioctl.h> 211dcac3e1SXiao Feng Ren 221dcac3e1SXiao Feng Ren #include "qapi/error.h" 231dcac3e1SXiao Feng Ren #include "hw/vfio/vfio.h" 241dcac3e1SXiao Feng Ren #include "hw/vfio/vfio-common.h" 251dcac3e1SXiao Feng Ren #include "hw/s390x/s390-ccw.h" 2644445d86SJason J. Herne #include "hw/s390x/vfio-ccw.h" 27a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h" 281dcac3e1SXiao Feng Ren #include "hw/s390x/ccw-device.h" 29d791937fSPhilippe Mathieu-Daudé #include "exec/address-spaces.h" 304886b3e9SDong Jia Shi #include "qemu/error-report.h" 31db725815SMarkus Armbruster #include "qemu/main-loop.h" 320b8fa32fSMarkus Armbruster #include "qemu/module.h" 331dcac3e1SXiao Feng Ren 3444445d86SJason J. Herne struct VFIOCCWDevice { 351dcac3e1SXiao Feng Ren S390CCWDevice cdev; 361dcac3e1SXiao Feng Ren VFIODevice vdev; 37c14e706cSDong Jia Shi uint64_t io_region_size; 38c14e706cSDong Jia Shi uint64_t io_region_offset; 39c14e706cSDong Jia Shi struct ccw_io_region *io_region; 408fadea24SCornelia Huck uint64_t async_cmd_region_size; 418fadea24SCornelia Huck uint64_t async_cmd_region_offset; 428fadea24SCornelia Huck struct ccw_cmd_region *async_cmd_region; 4346ea3841SFarhan Ali uint64_t schib_region_size; 4446ea3841SFarhan Ali uint64_t schib_region_offset; 4546ea3841SFarhan Ali struct ccw_schib_region *schib_region; 46f030532fSFarhan Ali uint64_t crw_region_size; 47f030532fSFarhan Ali uint64_t crw_region_offset; 48f030532fSFarhan Ali struct ccw_crw_region *crw_region; 494886b3e9SDong Jia Shi EventNotifier io_notifier; 50f030532fSFarhan Ali EventNotifier crw_notifier; 51b2f96f9eSEric Farman EventNotifier req_notifier; 529a51c9eeSHalil Pasic bool force_orb_pfch; 539a51c9eeSHalil Pasic bool warned_orb_pfch; 5444445d86SJason J. Herne }; 551dcac3e1SXiao Feng Ren 569a51c9eeSHalil Pasic static inline void warn_once_pfch(VFIOCCWDevice *vcdev, SubchDev *sch, 579a51c9eeSHalil Pasic const char *msg) 589a51c9eeSHalil Pasic { 59c55510b7SCornelia Huck warn_report_once_cond(&vcdev->warned_orb_pfch, 60c55510b7SCornelia Huck "vfio-ccw (devno %x.%x.%04x): %s", 619a51c9eeSHalil Pasic sch->cssid, sch->ssid, sch->devno, msg); 629a51c9eeSHalil Pasic } 639a51c9eeSHalil Pasic 641dcac3e1SXiao Feng Ren static void vfio_ccw_compute_needs_reset(VFIODevice *vdev) 651dcac3e1SXiao Feng Ren { 661dcac3e1SXiao Feng Ren vdev->needs_reset = false; 671dcac3e1SXiao Feng Ren } 681dcac3e1SXiao Feng Ren 691dcac3e1SXiao Feng Ren /* 701dcac3e1SXiao Feng Ren * We don't need vfio_hot_reset_multi and vfio_eoi operations for 711dcac3e1SXiao Feng Ren * vfio_ccw device now. 721dcac3e1SXiao Feng Ren */ 731dcac3e1SXiao Feng Ren struct VFIODeviceOps vfio_ccw_ops = { 741dcac3e1SXiao Feng Ren .vfio_compute_needs_reset = vfio_ccw_compute_needs_reset, 751dcac3e1SXiao Feng Ren }; 761dcac3e1SXiao Feng Ren 7766dc50f7SHalil Pasic static IOInstEnding vfio_ccw_handle_request(SubchDev *sch) 788ca2b376SXiao Feng Ren { 7966dc50f7SHalil Pasic S390CCWDevice *cdev = sch->driver_data; 808ca2b376SXiao Feng Ren VFIOCCWDevice *vcdev = DO_UPCAST(VFIOCCWDevice, cdev, cdev); 818ca2b376SXiao Feng Ren struct ccw_io_region *region = vcdev->io_region; 828ca2b376SXiao Feng Ren int ret; 838ca2b376SXiao Feng Ren 8424e58a7bSJared Rossi if (!(sch->orb.ctrl0 & ORB_CTRL0_MASK_PFCH) && vcdev->force_orb_pfch) { 859a51c9eeSHalil Pasic sch->orb.ctrl0 |= ORB_CTRL0_MASK_PFCH; 869a51c9eeSHalil Pasic warn_once_pfch(vcdev, sch, "PFCH flag forced"); 879a51c9eeSHalil Pasic } 889a51c9eeSHalil Pasic 898ca2b376SXiao Feng Ren QEMU_BUILD_BUG_ON(sizeof(region->orb_area) != sizeof(ORB)); 908ca2b376SXiao Feng Ren QEMU_BUILD_BUG_ON(sizeof(region->scsw_area) != sizeof(SCSW)); 918ca2b376SXiao Feng Ren QEMU_BUILD_BUG_ON(sizeof(region->irb_area) != sizeof(IRB)); 928ca2b376SXiao Feng Ren 938ca2b376SXiao Feng Ren memset(region, 0, sizeof(*region)); 948ca2b376SXiao Feng Ren 9566dc50f7SHalil Pasic memcpy(region->orb_area, &sch->orb, sizeof(ORB)); 9666dc50f7SHalil Pasic memcpy(region->scsw_area, &sch->curr_status.scsw, sizeof(SCSW)); 978ca2b376SXiao Feng Ren 988ca2b376SXiao Feng Ren again: 998ca2b376SXiao Feng Ren ret = pwrite(vcdev->vdev.fd, region, 1008ca2b376SXiao Feng Ren vcdev->io_region_size, vcdev->io_region_offset); 1018ca2b376SXiao Feng Ren if (ret != vcdev->io_region_size) { 1028ca2b376SXiao Feng Ren if (errno == EAGAIN) { 1038ca2b376SXiao Feng Ren goto again; 1048ca2b376SXiao Feng Ren } 10591f751dcSBoris Fiuczynski error_report("vfio-ccw: write I/O region failed with errno=%d", errno); 106d6cd6631SEric Farman ret = errno ? -errno : -EFAULT; 10766dc50f7SHalil Pasic } else { 108d6cd6631SEric Farman ret = 0; 1098ca2b376SXiao Feng Ren } 11066dc50f7SHalil Pasic switch (ret) { 11166dc50f7SHalil Pasic case 0: 11266dc50f7SHalil Pasic return IOINST_CC_EXPECTED; 11366dc50f7SHalil Pasic case -EBUSY: 11466dc50f7SHalil Pasic return IOINST_CC_BUSY; 11566dc50f7SHalil Pasic case -ENODEV: 11666dc50f7SHalil Pasic case -EACCES: 11766dc50f7SHalil Pasic return IOINST_CC_NOT_OPERATIONAL; 11866dc50f7SHalil Pasic case -EFAULT: 11966dc50f7SHalil Pasic default: 12066dc50f7SHalil Pasic sch_gen_unit_exception(sch); 12166dc50f7SHalil Pasic css_inject_io_interrupt(sch); 12266dc50f7SHalil Pasic return IOINST_CC_EXPECTED; 12366dc50f7SHalil Pasic } 1248ca2b376SXiao Feng Ren } 1258ca2b376SXiao Feng Ren 12646ea3841SFarhan Ali static IOInstEnding vfio_ccw_handle_store(SubchDev *sch) 12746ea3841SFarhan Ali { 12846ea3841SFarhan Ali S390CCWDevice *cdev = sch->driver_data; 12946ea3841SFarhan Ali VFIOCCWDevice *vcdev = DO_UPCAST(VFIOCCWDevice, cdev, cdev); 13046ea3841SFarhan Ali SCHIB *schib = &sch->curr_status; 13146ea3841SFarhan Ali struct ccw_schib_region *region = vcdev->schib_region; 13246ea3841SFarhan Ali SCHIB *s; 13346ea3841SFarhan Ali int ret; 13446ea3841SFarhan Ali 13546ea3841SFarhan Ali /* schib region not available so nothing else to do */ 13646ea3841SFarhan Ali if (!region) { 13746ea3841SFarhan Ali return IOINST_CC_EXPECTED; 13846ea3841SFarhan Ali } 13946ea3841SFarhan Ali 14046ea3841SFarhan Ali memset(region, 0, sizeof(*region)); 14146ea3841SFarhan Ali ret = pread(vcdev->vdev.fd, region, vcdev->schib_region_size, 14246ea3841SFarhan Ali vcdev->schib_region_offset); 14346ea3841SFarhan Ali 14446ea3841SFarhan Ali if (ret == -1) { 14546ea3841SFarhan Ali /* 14646ea3841SFarhan Ali * Device is probably damaged, but store subchannel does not 14746ea3841SFarhan Ali * have a nonzero cc defined for this scenario. Log an error, 14846ea3841SFarhan Ali * and presume things are otherwise fine. 14946ea3841SFarhan Ali */ 15046ea3841SFarhan Ali error_report("vfio-ccw: store region read failed with errno=%d", errno); 15146ea3841SFarhan Ali return IOINST_CC_EXPECTED; 15246ea3841SFarhan Ali } 15346ea3841SFarhan Ali 15446ea3841SFarhan Ali /* 15546ea3841SFarhan Ali * Selectively copy path-related bits of the SCHIB, 15646ea3841SFarhan Ali * rather than copying the entire struct. 15746ea3841SFarhan Ali */ 15846ea3841SFarhan Ali s = (SCHIB *)region->schib_area; 15946ea3841SFarhan Ali schib->pmcw.pnom = s->pmcw.pnom; 16046ea3841SFarhan Ali schib->pmcw.lpum = s->pmcw.lpum; 16146ea3841SFarhan Ali schib->pmcw.pam = s->pmcw.pam; 16246ea3841SFarhan Ali schib->pmcw.pom = s->pmcw.pom; 16346ea3841SFarhan Ali 16446ea3841SFarhan Ali if (s->scsw.flags & SCSW_FLAGS_MASK_PNO) { 16546ea3841SFarhan Ali schib->scsw.flags |= SCSW_FLAGS_MASK_PNO; 16646ea3841SFarhan Ali } 16746ea3841SFarhan Ali 16846ea3841SFarhan Ali return IOINST_CC_EXPECTED; 16946ea3841SFarhan Ali } 17046ea3841SFarhan Ali 1718fadea24SCornelia Huck static int vfio_ccw_handle_clear(SubchDev *sch) 1728fadea24SCornelia Huck { 1738fadea24SCornelia Huck S390CCWDevice *cdev = sch->driver_data; 1748fadea24SCornelia Huck VFIOCCWDevice *vcdev = DO_UPCAST(VFIOCCWDevice, cdev, cdev); 1758fadea24SCornelia Huck struct ccw_cmd_region *region = vcdev->async_cmd_region; 1768fadea24SCornelia Huck int ret; 1778fadea24SCornelia Huck 1788fadea24SCornelia Huck if (!vcdev->async_cmd_region) { 1798fadea24SCornelia Huck /* Async command region not available, fall back to emulation */ 1808fadea24SCornelia Huck return -ENOSYS; 1818fadea24SCornelia Huck } 1828fadea24SCornelia Huck 1838fadea24SCornelia Huck memset(region, 0, sizeof(*region)); 1848fadea24SCornelia Huck region->command = VFIO_CCW_ASYNC_CMD_CSCH; 1858fadea24SCornelia Huck 1868fadea24SCornelia Huck again: 1878fadea24SCornelia Huck ret = pwrite(vcdev->vdev.fd, region, 1888fadea24SCornelia Huck vcdev->async_cmd_region_size, vcdev->async_cmd_region_offset); 1898fadea24SCornelia Huck if (ret != vcdev->async_cmd_region_size) { 1908fadea24SCornelia Huck if (errno == EAGAIN) { 1918fadea24SCornelia Huck goto again; 1928fadea24SCornelia Huck } 1938fadea24SCornelia Huck error_report("vfio-ccw: write cmd region failed with errno=%d", errno); 194d6cd6631SEric Farman ret = errno ? -errno : -EFAULT; 1958fadea24SCornelia Huck } else { 196d6cd6631SEric Farman ret = 0; 1978fadea24SCornelia Huck } 1988fadea24SCornelia Huck switch (ret) { 1998fadea24SCornelia Huck case 0: 2008fadea24SCornelia Huck case -ENODEV: 2018fadea24SCornelia Huck case -EACCES: 2028fadea24SCornelia Huck return 0; 2038fadea24SCornelia Huck case -EFAULT: 2048fadea24SCornelia Huck default: 2058fadea24SCornelia Huck sch_gen_unit_exception(sch); 2068fadea24SCornelia Huck css_inject_io_interrupt(sch); 2078fadea24SCornelia Huck return 0; 2088fadea24SCornelia Huck } 2098fadea24SCornelia Huck } 2108fadea24SCornelia Huck 2118fadea24SCornelia Huck static int vfio_ccw_handle_halt(SubchDev *sch) 2128fadea24SCornelia Huck { 2138fadea24SCornelia Huck S390CCWDevice *cdev = sch->driver_data; 2148fadea24SCornelia Huck VFIOCCWDevice *vcdev = DO_UPCAST(VFIOCCWDevice, cdev, cdev); 2158fadea24SCornelia Huck struct ccw_cmd_region *region = vcdev->async_cmd_region; 2168fadea24SCornelia Huck int ret; 2178fadea24SCornelia Huck 2188fadea24SCornelia Huck if (!vcdev->async_cmd_region) { 2198fadea24SCornelia Huck /* Async command region not available, fall back to emulation */ 2208fadea24SCornelia Huck return -ENOSYS; 2218fadea24SCornelia Huck } 2228fadea24SCornelia Huck 2238fadea24SCornelia Huck memset(region, 0, sizeof(*region)); 2248fadea24SCornelia Huck region->command = VFIO_CCW_ASYNC_CMD_HSCH; 2258fadea24SCornelia Huck 2268fadea24SCornelia Huck again: 2278fadea24SCornelia Huck ret = pwrite(vcdev->vdev.fd, region, 2288fadea24SCornelia Huck vcdev->async_cmd_region_size, vcdev->async_cmd_region_offset); 2298fadea24SCornelia Huck if (ret != vcdev->async_cmd_region_size) { 2308fadea24SCornelia Huck if (errno == EAGAIN) { 2318fadea24SCornelia Huck goto again; 2328fadea24SCornelia Huck } 2338fadea24SCornelia Huck error_report("vfio-ccw: write cmd region failed with errno=%d", errno); 234d6cd6631SEric Farman ret = errno ? -errno : -EFAULT; 2358fadea24SCornelia Huck } else { 236d6cd6631SEric Farman ret = 0; 2378fadea24SCornelia Huck } 2388fadea24SCornelia Huck switch (ret) { 2398fadea24SCornelia Huck case 0: 2408fadea24SCornelia Huck case -EBUSY: 2418fadea24SCornelia Huck case -ENODEV: 2428fadea24SCornelia Huck case -EACCES: 2438fadea24SCornelia Huck return 0; 2448fadea24SCornelia Huck case -EFAULT: 2458fadea24SCornelia Huck default: 2468fadea24SCornelia Huck sch_gen_unit_exception(sch); 2478fadea24SCornelia Huck css_inject_io_interrupt(sch); 2488fadea24SCornelia Huck return 0; 2498fadea24SCornelia Huck } 2508fadea24SCornelia Huck } 2518fadea24SCornelia Huck 2521dcac3e1SXiao Feng Ren static void vfio_ccw_reset(DeviceState *dev) 2531dcac3e1SXiao Feng Ren { 2541dcac3e1SXiao Feng Ren CcwDevice *ccw_dev = DO_UPCAST(CcwDevice, parent_obj, dev); 2551dcac3e1SXiao Feng Ren S390CCWDevice *cdev = DO_UPCAST(S390CCWDevice, parent_obj, ccw_dev); 2561dcac3e1SXiao Feng Ren VFIOCCWDevice *vcdev = DO_UPCAST(VFIOCCWDevice, cdev, cdev); 2571dcac3e1SXiao Feng Ren 2581dcac3e1SXiao Feng Ren ioctl(vcdev->vdev.fd, VFIO_DEVICE_RESET); 2591dcac3e1SXiao Feng Ren } 2601dcac3e1SXiao Feng Ren 261f030532fSFarhan Ali static void vfio_ccw_crw_read(VFIOCCWDevice *vcdev) 262f030532fSFarhan Ali { 263f030532fSFarhan Ali struct ccw_crw_region *region = vcdev->crw_region; 264f030532fSFarhan Ali CRW crw; 265f030532fSFarhan Ali int size; 266f030532fSFarhan Ali 267f030532fSFarhan Ali /* Keep reading CRWs as long as data is returned */ 268f030532fSFarhan Ali do { 269f030532fSFarhan Ali memset(region, 0, sizeof(*region)); 270f030532fSFarhan Ali size = pread(vcdev->vdev.fd, region, vcdev->crw_region_size, 271f030532fSFarhan Ali vcdev->crw_region_offset); 272f030532fSFarhan Ali 273f030532fSFarhan Ali if (size == -1) { 274f030532fSFarhan Ali error_report("vfio-ccw: Read crw region failed with errno=%d", 275f030532fSFarhan Ali errno); 276f030532fSFarhan Ali break; 277f030532fSFarhan Ali } 278f030532fSFarhan Ali 279f030532fSFarhan Ali if (region->crw == 0) { 280f030532fSFarhan Ali /* No more CRWs to queue */ 281f030532fSFarhan Ali break; 282f030532fSFarhan Ali } 283f030532fSFarhan Ali 284f030532fSFarhan Ali memcpy(&crw, ®ion->crw, sizeof(CRW)); 285f030532fSFarhan Ali 286f030532fSFarhan Ali css_crw_add_to_queue(crw); 287f030532fSFarhan Ali } while (1); 288f030532fSFarhan Ali } 289f030532fSFarhan Ali 290b2f96f9eSEric Farman static void vfio_ccw_req_notifier_handler(void *opaque) 291b2f96f9eSEric Farman { 292b2f96f9eSEric Farman VFIOCCWDevice *vcdev = opaque; 293b2f96f9eSEric Farman Error *err = NULL; 294b2f96f9eSEric Farman 295b2f96f9eSEric Farman if (!event_notifier_test_and_clear(&vcdev->req_notifier)) { 296b2f96f9eSEric Farman return; 297b2f96f9eSEric Farman } 298b2f96f9eSEric Farman 299b2f96f9eSEric Farman qdev_unplug(DEVICE(vcdev), &err); 300b2f96f9eSEric Farman if (err) { 301b2f96f9eSEric Farman warn_reportf_err(err, VFIO_MSG_PREFIX, vcdev->vdev.name); 302b2f96f9eSEric Farman } 303b2f96f9eSEric Farman } 304b2f96f9eSEric Farman 305f030532fSFarhan Ali static void vfio_ccw_crw_notifier_handler(void *opaque) 306f030532fSFarhan Ali { 307f030532fSFarhan Ali VFIOCCWDevice *vcdev = opaque; 308f030532fSFarhan Ali 309f030532fSFarhan Ali while (event_notifier_test_and_clear(&vcdev->crw_notifier)) { 310f030532fSFarhan Ali vfio_ccw_crw_read(vcdev); 311f030532fSFarhan Ali } 312f030532fSFarhan Ali } 313f030532fSFarhan Ali 3144886b3e9SDong Jia Shi static void vfio_ccw_io_notifier_handler(void *opaque) 3154886b3e9SDong Jia Shi { 3164886b3e9SDong Jia Shi VFIOCCWDevice *vcdev = opaque; 3178ca2b376SXiao Feng Ren struct ccw_io_region *region = vcdev->io_region; 3188ca2b376SXiao Feng Ren S390CCWDevice *cdev = S390_CCW_DEVICE(vcdev); 3198ca2b376SXiao Feng Ren CcwDevice *ccw_dev = CCW_DEVICE(cdev); 3208ca2b376SXiao Feng Ren SubchDev *sch = ccw_dev->sch; 321e1d0b372SDaniel P. Berrangé SCHIB *schib = &sch->curr_status; 322e1d0b372SDaniel P. Berrangé SCSW s; 3238ca2b376SXiao Feng Ren IRB irb; 324*c626710fSEric Farman ESW esw; 3258ca2b376SXiao Feng Ren int size; 3264886b3e9SDong Jia Shi 3274886b3e9SDong Jia Shi if (!event_notifier_test_and_clear(&vcdev->io_notifier)) { 3284886b3e9SDong Jia Shi return; 3294886b3e9SDong Jia Shi } 3308ca2b376SXiao Feng Ren 3318ca2b376SXiao Feng Ren size = pread(vcdev->vdev.fd, region, vcdev->io_region_size, 3328ca2b376SXiao Feng Ren vcdev->io_region_offset); 3338ca2b376SXiao Feng Ren if (size == -1) { 3348ca2b376SXiao Feng Ren switch (errno) { 3358ca2b376SXiao Feng Ren case ENODEV: 3368ca2b376SXiao Feng Ren /* Generate a deferred cc 3 condition. */ 337e1d0b372SDaniel P. Berrangé schib->scsw.flags |= SCSW_FLAGS_MASK_CC; 338e1d0b372SDaniel P. Berrangé schib->scsw.ctrl &= ~SCSW_CTRL_MASK_STCTL; 339e1d0b372SDaniel P. Berrangé schib->scsw.ctrl |= (SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND); 3408ca2b376SXiao Feng Ren goto read_err; 3418ca2b376SXiao Feng Ren case EFAULT: 3428ca2b376SXiao Feng Ren /* Memory problem, generate channel data check. */ 343e1d0b372SDaniel P. Berrangé schib->scsw.ctrl &= ~SCSW_ACTL_START_PEND; 344e1d0b372SDaniel P. Berrangé schib->scsw.cstat = SCSW_CSTAT_DATA_CHECK; 345e1d0b372SDaniel P. Berrangé schib->scsw.ctrl &= ~SCSW_CTRL_MASK_STCTL; 346e1d0b372SDaniel P. Berrangé schib->scsw.ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY | 3478ca2b376SXiao Feng Ren SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND; 3488ca2b376SXiao Feng Ren goto read_err; 3498ca2b376SXiao Feng Ren default: 3508ca2b376SXiao Feng Ren /* Error, generate channel program check. */ 351e1d0b372SDaniel P. Berrangé schib->scsw.ctrl &= ~SCSW_ACTL_START_PEND; 352e1d0b372SDaniel P. Berrangé schib->scsw.cstat = SCSW_CSTAT_PROG_CHECK; 353e1d0b372SDaniel P. Berrangé schib->scsw.ctrl &= ~SCSW_CTRL_MASK_STCTL; 354e1d0b372SDaniel P. Berrangé schib->scsw.ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY | 3558ca2b376SXiao Feng Ren SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND; 3568ca2b376SXiao Feng Ren goto read_err; 3578ca2b376SXiao Feng Ren } 3588ca2b376SXiao Feng Ren } else if (size != vcdev->io_region_size) { 3598ca2b376SXiao Feng Ren /* Information transfer error, generate channel-control check. */ 360e1d0b372SDaniel P. Berrangé schib->scsw.ctrl &= ~SCSW_ACTL_START_PEND; 361e1d0b372SDaniel P. Berrangé schib->scsw.cstat = SCSW_CSTAT_CHN_CTRL_CHK; 362e1d0b372SDaniel P. Berrangé schib->scsw.ctrl &= ~SCSW_CTRL_MASK_STCTL; 363e1d0b372SDaniel P. Berrangé schib->scsw.ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY | 3648ca2b376SXiao Feng Ren SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND; 3658ca2b376SXiao Feng Ren goto read_err; 3668ca2b376SXiao Feng Ren } 3678ca2b376SXiao Feng Ren 3688ca2b376SXiao Feng Ren memcpy(&irb, region->irb_area, sizeof(IRB)); 3698ca2b376SXiao Feng Ren 3708ca2b376SXiao Feng Ren /* Update control block via irb. */ 371e1d0b372SDaniel P. Berrangé s = schib->scsw; 372e1d0b372SDaniel P. Berrangé copy_scsw_to_guest(&s, &irb.scsw); 373e1d0b372SDaniel P. Berrangé schib->scsw = s; 3748ca2b376SXiao Feng Ren 375*c626710fSEric Farman copy_esw_to_guest(&esw, &irb.esw); 376*c626710fSEric Farman sch->esw = esw; 377*c626710fSEric Farman 378334e7685SDong Jia Shi /* If a uint check is pending, copy sense data. */ 379e1d0b372SDaniel P. Berrangé if ((schib->scsw.dstat & SCSW_DSTAT_UNIT_CHECK) && 380e1d0b372SDaniel P. Berrangé (schib->pmcw.chars & PMCW_CHARS_MASK_CSENSE)) { 381334e7685SDong Jia Shi memcpy(sch->sense_data, irb.ecw, sizeof(irb.ecw)); 382334e7685SDong Jia Shi } 383334e7685SDong Jia Shi 3848ca2b376SXiao Feng Ren read_err: 3858ca2b376SXiao Feng Ren css_inject_io_interrupt(sch); 3864886b3e9SDong Jia Shi } 3874886b3e9SDong Jia Shi 388690e29b9SEric Farman static void vfio_ccw_register_irq_notifier(VFIOCCWDevice *vcdev, 389690e29b9SEric Farman unsigned int irq, 390690e29b9SEric Farman Error **errp) 3914886b3e9SDong Jia Shi { 3924886b3e9SDong Jia Shi VFIODevice *vdev = &vcdev->vdev; 3934886b3e9SDong Jia Shi struct vfio_irq_info *irq_info; 3944886b3e9SDong Jia Shi size_t argsz; 395b5e89f04SCornelia Huck int fd; 396690e29b9SEric Farman EventNotifier *notifier; 397690e29b9SEric Farman IOHandler *fd_read; 3984886b3e9SDong Jia Shi 399690e29b9SEric Farman switch (irq) { 400690e29b9SEric Farman case VFIO_CCW_IO_IRQ_INDEX: 401690e29b9SEric Farman notifier = &vcdev->io_notifier; 402690e29b9SEric Farman fd_read = vfio_ccw_io_notifier_handler; 403690e29b9SEric Farman break; 404f030532fSFarhan Ali case VFIO_CCW_CRW_IRQ_INDEX: 405f030532fSFarhan Ali notifier = &vcdev->crw_notifier; 406f030532fSFarhan Ali fd_read = vfio_ccw_crw_notifier_handler; 407f030532fSFarhan Ali break; 408b2f96f9eSEric Farman case VFIO_CCW_REQ_IRQ_INDEX: 409b2f96f9eSEric Farman notifier = &vcdev->req_notifier; 410b2f96f9eSEric Farman fd_read = vfio_ccw_req_notifier_handler; 411b2f96f9eSEric Farman break; 412690e29b9SEric Farman default: 413690e29b9SEric Farman error_setg(errp, "vfio: Unsupported device irq(%d)", irq); 414690e29b9SEric Farman return; 415690e29b9SEric Farman } 416690e29b9SEric Farman 417690e29b9SEric Farman if (vdev->num_irqs < irq + 1) { 4186178d468SEric Farman error_setg(errp, "vfio: IRQ %u not available (number of irqs %u)", 4196178d468SEric Farman irq, vdev->num_irqs); 4204886b3e9SDong Jia Shi return; 4214886b3e9SDong Jia Shi } 4224886b3e9SDong Jia Shi 42328e22d4bSJing Zhang argsz = sizeof(*irq_info); 4244886b3e9SDong Jia Shi irq_info = g_malloc0(argsz); 425690e29b9SEric Farman irq_info->index = irq; 4264886b3e9SDong Jia Shi irq_info->argsz = argsz; 4274886b3e9SDong Jia Shi if (ioctl(vdev->fd, VFIO_DEVICE_GET_IRQ_INFO, 4284886b3e9SDong Jia Shi irq_info) < 0 || irq_info->count < 1) { 4294886b3e9SDong Jia Shi error_setg_errno(errp, errno, "vfio: Error getting irq info"); 4304886b3e9SDong Jia Shi goto out_free_info; 4314886b3e9SDong Jia Shi } 4324886b3e9SDong Jia Shi 433690e29b9SEric Farman if (event_notifier_init(notifier, 0)) { 4344886b3e9SDong Jia Shi error_setg_errno(errp, errno, 435690e29b9SEric Farman "vfio: Unable to init event notifier for irq (%d)", 436690e29b9SEric Farman irq); 4374886b3e9SDong Jia Shi goto out_free_info; 4384886b3e9SDong Jia Shi } 4394886b3e9SDong Jia Shi 440690e29b9SEric Farman fd = event_notifier_get_fd(notifier); 441690e29b9SEric Farman qemu_set_fd_handler(fd, fd_read, NULL, vcdev); 4424886b3e9SDong Jia Shi 443690e29b9SEric Farman if (vfio_set_irq_signaling(vdev, irq, 0, 444b5e89f04SCornelia Huck VFIO_IRQ_SET_ACTION_TRIGGER, fd, errp)) { 445b5e89f04SCornelia Huck qemu_set_fd_handler(fd, NULL, NULL, vcdev); 446690e29b9SEric Farman event_notifier_cleanup(notifier); 4474886b3e9SDong Jia Shi } 4484886b3e9SDong Jia Shi 4494886b3e9SDong Jia Shi out_free_info: 4504886b3e9SDong Jia Shi g_free(irq_info); 4514886b3e9SDong Jia Shi } 4524886b3e9SDong Jia Shi 453690e29b9SEric Farman static void vfio_ccw_unregister_irq_notifier(VFIOCCWDevice *vcdev, 454690e29b9SEric Farman unsigned int irq) 4554886b3e9SDong Jia Shi { 456b5e89f04SCornelia Huck Error *err = NULL; 457690e29b9SEric Farman EventNotifier *notifier; 4584886b3e9SDong Jia Shi 459690e29b9SEric Farman switch (irq) { 460690e29b9SEric Farman case VFIO_CCW_IO_IRQ_INDEX: 461690e29b9SEric Farman notifier = &vcdev->io_notifier; 462690e29b9SEric Farman break; 463f030532fSFarhan Ali case VFIO_CCW_CRW_IRQ_INDEX: 464f030532fSFarhan Ali notifier = &vcdev->crw_notifier; 465f030532fSFarhan Ali break; 466b2f96f9eSEric Farman case VFIO_CCW_REQ_IRQ_INDEX: 467b2f96f9eSEric Farman notifier = &vcdev->req_notifier; 468b2f96f9eSEric Farman break; 469690e29b9SEric Farman default: 470690e29b9SEric Farman error_report("vfio: Unsupported device irq(%d)", irq); 471690e29b9SEric Farman return; 472690e29b9SEric Farman } 473690e29b9SEric Farman 474690e29b9SEric Farman if (vfio_set_irq_signaling(&vcdev->vdev, irq, 0, 475f5cf94cdSAlex Williamson VFIO_IRQ_SET_ACTION_TRIGGER, -1, &err)) { 476dcc9cf38SEric Farman warn_reportf_err(err, VFIO_MSG_PREFIX, vcdev->vdev.name); 4774886b3e9SDong Jia Shi } 4784886b3e9SDong Jia Shi 479690e29b9SEric Farman qemu_set_fd_handler(event_notifier_get_fd(notifier), 4804886b3e9SDong Jia Shi NULL, NULL, vcdev); 481690e29b9SEric Farman event_notifier_cleanup(notifier); 4824886b3e9SDong Jia Shi } 4834886b3e9SDong Jia Shi 484c14e706cSDong Jia Shi static void vfio_ccw_get_region(VFIOCCWDevice *vcdev, Error **errp) 485c14e706cSDong Jia Shi { 486c14e706cSDong Jia Shi VFIODevice *vdev = &vcdev->vdev; 487c14e706cSDong Jia Shi struct vfio_region_info *info; 488c14e706cSDong Jia Shi int ret; 489c14e706cSDong Jia Shi 490c14e706cSDong Jia Shi /* Sanity check device */ 491c14e706cSDong Jia Shi if (!(vdev->flags & VFIO_DEVICE_FLAGS_CCW)) { 492c14e706cSDong Jia Shi error_setg(errp, "vfio: Um, this isn't a vfio-ccw device"); 493c14e706cSDong Jia Shi return; 494c14e706cSDong Jia Shi } 495c14e706cSDong Jia Shi 4968fadea24SCornelia Huck /* 4978fadea24SCornelia Huck * We always expect at least the I/O region to be present. We also 4988fadea24SCornelia Huck * may have a variable number of regions governed by capabilities. 4998fadea24SCornelia Huck */ 500c14e706cSDong Jia Shi if (vdev->num_regions < VFIO_CCW_CONFIG_REGION_INDEX + 1) { 5018fadea24SCornelia Huck error_setg(errp, "vfio: too few regions (%u), expected at least %u", 5028fadea24SCornelia Huck vdev->num_regions, VFIO_CCW_CONFIG_REGION_INDEX + 1); 503c14e706cSDong Jia Shi return; 504c14e706cSDong Jia Shi } 505c14e706cSDong Jia Shi 506c14e706cSDong Jia Shi ret = vfio_get_region_info(vdev, VFIO_CCW_CONFIG_REGION_INDEX, &info); 507c14e706cSDong Jia Shi if (ret) { 508c14e706cSDong Jia Shi error_setg_errno(errp, -ret, "vfio: Error getting config info"); 509c14e706cSDong Jia Shi return; 510c14e706cSDong Jia Shi } 511c14e706cSDong Jia Shi 512c14e706cSDong Jia Shi vcdev->io_region_size = info->size; 513c14e706cSDong Jia Shi if (sizeof(*vcdev->io_region) != vcdev->io_region_size) { 514c14e706cSDong Jia Shi error_setg(errp, "vfio: Unexpected size of the I/O region"); 5152a3b9cbaSEric Farman goto out_err; 516c14e706cSDong Jia Shi } 517c14e706cSDong Jia Shi 518c14e706cSDong Jia Shi vcdev->io_region_offset = info->offset; 519c14e706cSDong Jia Shi vcdev->io_region = g_malloc0(info->size); 520c8726f7bSCornelia Huck g_free(info); 521c14e706cSDong Jia Shi 5228fadea24SCornelia Huck /* check for the optional async command region */ 5238fadea24SCornelia Huck ret = vfio_get_dev_region_info(vdev, VFIO_REGION_TYPE_CCW, 5248fadea24SCornelia Huck VFIO_REGION_SUBTYPE_CCW_ASYNC_CMD, &info); 5258fadea24SCornelia Huck if (!ret) { 5268fadea24SCornelia Huck vcdev->async_cmd_region_size = info->size; 5278fadea24SCornelia Huck if (sizeof(*vcdev->async_cmd_region) != vcdev->async_cmd_region_size) { 5288fadea24SCornelia Huck error_setg(errp, "vfio: Unexpected size of the async cmd region"); 5292a3b9cbaSEric Farman goto out_err; 5308fadea24SCornelia Huck } 5318fadea24SCornelia Huck vcdev->async_cmd_region_offset = info->offset; 5328fadea24SCornelia Huck vcdev->async_cmd_region = g_malloc0(info->size); 533c8726f7bSCornelia Huck g_free(info); 5348fadea24SCornelia Huck } 5358fadea24SCornelia Huck 53646ea3841SFarhan Ali ret = vfio_get_dev_region_info(vdev, VFIO_REGION_TYPE_CCW, 53746ea3841SFarhan Ali VFIO_REGION_SUBTYPE_CCW_SCHIB, &info); 53846ea3841SFarhan Ali if (!ret) { 53946ea3841SFarhan Ali vcdev->schib_region_size = info->size; 54046ea3841SFarhan Ali if (sizeof(*vcdev->schib_region) != vcdev->schib_region_size) { 54146ea3841SFarhan Ali error_setg(errp, "vfio: Unexpected size of the schib region"); 54246ea3841SFarhan Ali goto out_err; 54346ea3841SFarhan Ali } 54446ea3841SFarhan Ali vcdev->schib_region_offset = info->offset; 54546ea3841SFarhan Ali vcdev->schib_region = g_malloc(info->size); 546c8726f7bSCornelia Huck g_free(info); 54746ea3841SFarhan Ali } 54846ea3841SFarhan Ali 549f030532fSFarhan Ali ret = vfio_get_dev_region_info(vdev, VFIO_REGION_TYPE_CCW, 550f030532fSFarhan Ali VFIO_REGION_SUBTYPE_CCW_CRW, &info); 551f030532fSFarhan Ali 552f030532fSFarhan Ali if (!ret) { 553f030532fSFarhan Ali vcdev->crw_region_size = info->size; 554f030532fSFarhan Ali if (sizeof(*vcdev->crw_region) != vcdev->crw_region_size) { 555f030532fSFarhan Ali error_setg(errp, "vfio: Unexpected size of the CRW region"); 556f030532fSFarhan Ali goto out_err; 557f030532fSFarhan Ali } 558f030532fSFarhan Ali vcdev->crw_region_offset = info->offset; 559f030532fSFarhan Ali vcdev->crw_region = g_malloc(info->size); 560c8726f7bSCornelia Huck g_free(info); 561f030532fSFarhan Ali } 562f030532fSFarhan Ali 5632a3b9cbaSEric Farman return; 5642a3b9cbaSEric Farman 5652a3b9cbaSEric Farman out_err: 566f030532fSFarhan Ali g_free(vcdev->crw_region); 56746ea3841SFarhan Ali g_free(vcdev->schib_region); 5682a3b9cbaSEric Farman g_free(vcdev->async_cmd_region); 5692a3b9cbaSEric Farman g_free(vcdev->io_region); 5702a3b9cbaSEric Farman g_free(info); 5712a3b9cbaSEric Farman return; 572c14e706cSDong Jia Shi } 573c14e706cSDong Jia Shi 574c14e706cSDong Jia Shi static void vfio_ccw_put_region(VFIOCCWDevice *vcdev) 575c14e706cSDong Jia Shi { 576f030532fSFarhan Ali g_free(vcdev->crw_region); 57746ea3841SFarhan Ali g_free(vcdev->schib_region); 5788fadea24SCornelia Huck g_free(vcdev->async_cmd_region); 579c14e706cSDong Jia Shi g_free(vcdev->io_region); 580c14e706cSDong Jia Shi } 581c14e706cSDong Jia Shi 582c96f2c2aSGreg Kurz static void vfio_ccw_put_device(VFIOCCWDevice *vcdev) 5831dcac3e1SXiao Feng Ren { 5841dcac3e1SXiao Feng Ren g_free(vcdev->vdev.name); 5851dcac3e1SXiao Feng Ren vfio_put_base_device(&vcdev->vdev); 5861dcac3e1SXiao Feng Ren } 5871dcac3e1SXiao Feng Ren 588c96f2c2aSGreg Kurz static void vfio_ccw_get_device(VFIOGroup *group, VFIOCCWDevice *vcdev, 589c96f2c2aSGreg Kurz Error **errp) 590c96f2c2aSGreg Kurz { 591c96f2c2aSGreg Kurz char *name = g_strdup_printf("%x.%x.%04x", vcdev->cdev.hostid.cssid, 592c96f2c2aSGreg Kurz vcdev->cdev.hostid.ssid, 593c96f2c2aSGreg Kurz vcdev->cdev.hostid.devid); 594c96f2c2aSGreg Kurz VFIODevice *vbasedev; 595c96f2c2aSGreg Kurz 596c96f2c2aSGreg Kurz QLIST_FOREACH(vbasedev, &group->device_list, next) { 597c96f2c2aSGreg Kurz if (strcmp(vbasedev->name, name) == 0) { 598c96f2c2aSGreg Kurz error_setg(errp, "vfio: subchannel %s has already been attached", 599c96f2c2aSGreg Kurz name); 600c96f2c2aSGreg Kurz goto out_err; 601c96f2c2aSGreg Kurz } 602c96f2c2aSGreg Kurz } 603c96f2c2aSGreg Kurz 604238e9172SAlex Williamson /* 605238e9172SAlex Williamson * All vfio-ccw devices are believed to operate in a way compatible with 606aff92b82SDavid Hildenbrand * discarding of memory in RAM blocks, ie. pages pinned in the host are 607aff92b82SDavid Hildenbrand * in the current working set of the guest driver and therefore never 608aff92b82SDavid Hildenbrand * overlap e.g., with pages available to the guest balloon driver. This 609aff92b82SDavid Hildenbrand * needs to be set before vfio_get_device() for vfio common to handle 610aff92b82SDavid Hildenbrand * ram_block_discard_disable(). 611238e9172SAlex Williamson */ 612aff92b82SDavid Hildenbrand vcdev->vdev.ram_block_discard_allowed = true; 613238e9172SAlex Williamson 614c96f2c2aSGreg Kurz if (vfio_get_device(group, vcdev->cdev.mdevid, &vcdev->vdev, errp)) { 615c96f2c2aSGreg Kurz goto out_err; 616c96f2c2aSGreg Kurz } 617c96f2c2aSGreg Kurz 618c96f2c2aSGreg Kurz vcdev->vdev.ops = &vfio_ccw_ops; 619c96f2c2aSGreg Kurz vcdev->vdev.type = VFIO_DEVICE_TYPE_CCW; 620c96f2c2aSGreg Kurz vcdev->vdev.name = name; 621c96f2c2aSGreg Kurz vcdev->vdev.dev = &vcdev->cdev.parent_obj.parent_obj; 622c96f2c2aSGreg Kurz 623c96f2c2aSGreg Kurz return; 624c96f2c2aSGreg Kurz 625c96f2c2aSGreg Kurz out_err: 626c96f2c2aSGreg Kurz g_free(name); 627c96f2c2aSGreg Kurz } 628c96f2c2aSGreg Kurz 6291dcac3e1SXiao Feng Ren static VFIOGroup *vfio_ccw_get_group(S390CCWDevice *cdev, Error **errp) 6301dcac3e1SXiao Feng Ren { 6311dcac3e1SXiao Feng Ren char *tmp, group_path[PATH_MAX]; 6321dcac3e1SXiao Feng Ren ssize_t len; 6331dcac3e1SXiao Feng Ren int groupid; 6341dcac3e1SXiao Feng Ren 6351dcac3e1SXiao Feng Ren tmp = g_strdup_printf("/sys/bus/css/devices/%x.%x.%04x/%s/iommu_group", 6361dcac3e1SXiao Feng Ren cdev->hostid.cssid, cdev->hostid.ssid, 6371dcac3e1SXiao Feng Ren cdev->hostid.devid, cdev->mdevid); 6381dcac3e1SXiao Feng Ren len = readlink(tmp, group_path, sizeof(group_path)); 6391dcac3e1SXiao Feng Ren g_free(tmp); 6401dcac3e1SXiao Feng Ren 6411dcac3e1SXiao Feng Ren if (len <= 0 || len >= sizeof(group_path)) { 6421dcac3e1SXiao Feng Ren error_setg(errp, "vfio: no iommu_group found"); 6431dcac3e1SXiao Feng Ren return NULL; 6441dcac3e1SXiao Feng Ren } 6451dcac3e1SXiao Feng Ren 6461dcac3e1SXiao Feng Ren group_path[len] = 0; 6471dcac3e1SXiao Feng Ren 6481dcac3e1SXiao Feng Ren if (sscanf(basename(group_path), "%d", &groupid) != 1) { 6491dcac3e1SXiao Feng Ren error_setg(errp, "vfio: failed to read %s", group_path); 6501dcac3e1SXiao Feng Ren return NULL; 6511dcac3e1SXiao Feng Ren } 6521dcac3e1SXiao Feng Ren 6531dcac3e1SXiao Feng Ren return vfio_get_group(groupid, &address_space_memory, errp); 6541dcac3e1SXiao Feng Ren } 6551dcac3e1SXiao Feng Ren 6561dcac3e1SXiao Feng Ren static void vfio_ccw_realize(DeviceState *dev, Error **errp) 6571dcac3e1SXiao Feng Ren { 6581dcac3e1SXiao Feng Ren VFIOGroup *group; 6591dcac3e1SXiao Feng Ren CcwDevice *ccw_dev = DO_UPCAST(CcwDevice, parent_obj, dev); 6601dcac3e1SXiao Feng Ren S390CCWDevice *cdev = DO_UPCAST(S390CCWDevice, parent_obj, ccw_dev); 6611dcac3e1SXiao Feng Ren VFIOCCWDevice *vcdev = DO_UPCAST(VFIOCCWDevice, cdev, cdev); 6621dcac3e1SXiao Feng Ren S390CCWDeviceClass *cdc = S390_CCW_DEVICE_GET_CLASS(cdev); 6631dcac3e1SXiao Feng Ren Error *err = NULL; 6641dcac3e1SXiao Feng Ren 6651dcac3e1SXiao Feng Ren /* Call the class init function for subchannel. */ 6661dcac3e1SXiao Feng Ren if (cdc->realize) { 6671dcac3e1SXiao Feng Ren cdc->realize(cdev, vcdev->vdev.sysfsdev, &err); 6681dcac3e1SXiao Feng Ren if (err) { 6691dcac3e1SXiao Feng Ren goto out_err_propagate; 6701dcac3e1SXiao Feng Ren } 6711dcac3e1SXiao Feng Ren } 6721dcac3e1SXiao Feng Ren 6731dcac3e1SXiao Feng Ren group = vfio_ccw_get_group(cdev, &err); 6741dcac3e1SXiao Feng Ren if (!group) { 6751dcac3e1SXiao Feng Ren goto out_group_err; 6761dcac3e1SXiao Feng Ren } 6771dcac3e1SXiao Feng Ren 678c96f2c2aSGreg Kurz vfio_ccw_get_device(group, vcdev, &err); 679c96f2c2aSGreg Kurz if (err) { 6801dcac3e1SXiao Feng Ren goto out_device_err; 6811dcac3e1SXiao Feng Ren } 6821dcac3e1SXiao Feng Ren 683c14e706cSDong Jia Shi vfio_ccw_get_region(vcdev, &err); 684c14e706cSDong Jia Shi if (err) { 685c14e706cSDong Jia Shi goto out_region_err; 686c14e706cSDong Jia Shi } 687c14e706cSDong Jia Shi 688690e29b9SEric Farman vfio_ccw_register_irq_notifier(vcdev, VFIO_CCW_IO_IRQ_INDEX, &err); 6894886b3e9SDong Jia Shi if (err) { 690b2f96f9eSEric Farman goto out_io_notifier_err; 6914886b3e9SDong Jia Shi } 6924886b3e9SDong Jia Shi 693f030532fSFarhan Ali if (vcdev->crw_region) { 694f030532fSFarhan Ali vfio_ccw_register_irq_notifier(vcdev, VFIO_CCW_CRW_IRQ_INDEX, &err); 695f030532fSFarhan Ali if (err) { 696dcc9cf38SEric Farman goto out_irq_notifier_err; 697f030532fSFarhan Ali } 698f030532fSFarhan Ali } 699f030532fSFarhan Ali 700b2f96f9eSEric Farman vfio_ccw_register_irq_notifier(vcdev, VFIO_CCW_REQ_IRQ_INDEX, &err); 701b2f96f9eSEric Farman if (err) { 7026178d468SEric Farman /* 7036178d468SEric Farman * Report this error, but do not make it a failing condition. 7046178d468SEric Farman * Lack of this IRQ in the host does not prevent normal operation. 7056178d468SEric Farman */ 7066178d468SEric Farman error_report_err(err); 707b2f96f9eSEric Farman } 708b2f96f9eSEric Farman 7091dcac3e1SXiao Feng Ren return; 7101dcac3e1SXiao Feng Ren 711dcc9cf38SEric Farman out_irq_notifier_err: 712dcc9cf38SEric Farman vfio_ccw_unregister_irq_notifier(vcdev, VFIO_CCW_REQ_IRQ_INDEX); 713dcc9cf38SEric Farman vfio_ccw_unregister_irq_notifier(vcdev, VFIO_CCW_CRW_IRQ_INDEX); 714b2f96f9eSEric Farman vfio_ccw_unregister_irq_notifier(vcdev, VFIO_CCW_IO_IRQ_INDEX); 715b2f96f9eSEric Farman out_io_notifier_err: 7164886b3e9SDong Jia Shi vfio_ccw_put_region(vcdev); 717c14e706cSDong Jia Shi out_region_err: 718c96f2c2aSGreg Kurz vfio_ccw_put_device(vcdev); 7191dcac3e1SXiao Feng Ren out_device_err: 7201dcac3e1SXiao Feng Ren vfio_put_group(group); 7211dcac3e1SXiao Feng Ren out_group_err: 7221dcac3e1SXiao Feng Ren if (cdc->unrealize) { 723b69c3c21SMarkus Armbruster cdc->unrealize(cdev); 7241dcac3e1SXiao Feng Ren } 7251dcac3e1SXiao Feng Ren out_err_propagate: 7261dcac3e1SXiao Feng Ren error_propagate(errp, err); 7271dcac3e1SXiao Feng Ren } 7281dcac3e1SXiao Feng Ren 729b69c3c21SMarkus Armbruster static void vfio_ccw_unrealize(DeviceState *dev) 7301dcac3e1SXiao Feng Ren { 7311dcac3e1SXiao Feng Ren CcwDevice *ccw_dev = DO_UPCAST(CcwDevice, parent_obj, dev); 7321dcac3e1SXiao Feng Ren S390CCWDevice *cdev = DO_UPCAST(S390CCWDevice, parent_obj, ccw_dev); 7331dcac3e1SXiao Feng Ren VFIOCCWDevice *vcdev = DO_UPCAST(VFIOCCWDevice, cdev, cdev); 7341dcac3e1SXiao Feng Ren S390CCWDeviceClass *cdc = S390_CCW_DEVICE_GET_CLASS(cdev); 7351dcac3e1SXiao Feng Ren VFIOGroup *group = vcdev->vdev.group; 7361dcac3e1SXiao Feng Ren 737b2f96f9eSEric Farman vfio_ccw_unregister_irq_notifier(vcdev, VFIO_CCW_REQ_IRQ_INDEX); 738f030532fSFarhan Ali vfio_ccw_unregister_irq_notifier(vcdev, VFIO_CCW_CRW_IRQ_INDEX); 739690e29b9SEric Farman vfio_ccw_unregister_irq_notifier(vcdev, VFIO_CCW_IO_IRQ_INDEX); 740c14e706cSDong Jia Shi vfio_ccw_put_region(vcdev); 741c96f2c2aSGreg Kurz vfio_ccw_put_device(vcdev); 7421dcac3e1SXiao Feng Ren vfio_put_group(group); 7431dcac3e1SXiao Feng Ren 7441dcac3e1SXiao Feng Ren if (cdc->unrealize) { 745b69c3c21SMarkus Armbruster cdc->unrealize(cdev); 7461dcac3e1SXiao Feng Ren } 7471dcac3e1SXiao Feng Ren } 7481dcac3e1SXiao Feng Ren 7491dcac3e1SXiao Feng Ren static Property vfio_ccw_properties[] = { 7501dcac3e1SXiao Feng Ren DEFINE_PROP_STRING("sysfsdev", VFIOCCWDevice, vdev.sysfsdev), 7519a51c9eeSHalil Pasic DEFINE_PROP_BOOL("force-orb-pfch", VFIOCCWDevice, force_orb_pfch, false), 7521dcac3e1SXiao Feng Ren DEFINE_PROP_END_OF_LIST(), 7531dcac3e1SXiao Feng Ren }; 7541dcac3e1SXiao Feng Ren 7551dcac3e1SXiao Feng Ren static const VMStateDescription vfio_ccw_vmstate = { 756da56e330SLi Qiang .name = "vfio-ccw", 7571dcac3e1SXiao Feng Ren .unmigratable = 1, 7581dcac3e1SXiao Feng Ren }; 7591dcac3e1SXiao Feng Ren 7601dcac3e1SXiao Feng Ren static void vfio_ccw_class_init(ObjectClass *klass, void *data) 7611dcac3e1SXiao Feng Ren { 7621dcac3e1SXiao Feng Ren DeviceClass *dc = DEVICE_CLASS(klass); 7638ca2b376SXiao Feng Ren S390CCWDeviceClass *cdc = S390_CCW_DEVICE_CLASS(klass); 7641dcac3e1SXiao Feng Ren 7654f67d30bSMarc-André Lureau device_class_set_props(dc, vfio_ccw_properties); 7661dcac3e1SXiao Feng Ren dc->vmsd = &vfio_ccw_vmstate; 7671dcac3e1SXiao Feng Ren dc->desc = "VFIO-based subchannel assignment"; 768bd2aef10SCornelia Huck set_bit(DEVICE_CATEGORY_MISC, dc->categories); 7691dcac3e1SXiao Feng Ren dc->realize = vfio_ccw_realize; 7701dcac3e1SXiao Feng Ren dc->unrealize = vfio_ccw_unrealize; 7711dcac3e1SXiao Feng Ren dc->reset = vfio_ccw_reset; 7728ca2b376SXiao Feng Ren 7738ca2b376SXiao Feng Ren cdc->handle_request = vfio_ccw_handle_request; 7748fadea24SCornelia Huck cdc->handle_halt = vfio_ccw_handle_halt; 7758fadea24SCornelia Huck cdc->handle_clear = vfio_ccw_handle_clear; 77646ea3841SFarhan Ali cdc->handle_store = vfio_ccw_handle_store; 7771dcac3e1SXiao Feng Ren } 7781dcac3e1SXiao Feng Ren 7791dcac3e1SXiao Feng Ren static const TypeInfo vfio_ccw_info = { 7801dcac3e1SXiao Feng Ren .name = TYPE_VFIO_CCW, 7811dcac3e1SXiao Feng Ren .parent = TYPE_S390_CCW, 7821dcac3e1SXiao Feng Ren .instance_size = sizeof(VFIOCCWDevice), 7831dcac3e1SXiao Feng Ren .class_init = vfio_ccw_class_init, 7841dcac3e1SXiao Feng Ren }; 7851dcac3e1SXiao Feng Ren 7861dcac3e1SXiao Feng Ren static void register_vfio_ccw_type(void) 7871dcac3e1SXiao Feng Ren { 7881dcac3e1SXiao Feng Ren type_register_static(&vfio_ccw_info); 7891dcac3e1SXiao Feng Ren } 7901dcac3e1SXiao Feng Ren 7911dcac3e1SXiao Feng Ren type_init(register_vfio_ccw_type) 792