static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)

{

    int ret;

    VirtioRevInfo revinfo;

    uint8_t status;

    VirtioFeatDesc features;

    void *config;

    hwaddr indicators;

    VqConfigBlock vq_config;

    VirtioCcwDevice *dev = sch->driver_data;

    VirtIODevice *vdev = virtio_ccw_get_vdev(sch);

    bool check_len;

    int len;

    hwaddr hw_len;

    VirtioThinintInfo *thinint;



    if (!dev) {

        return -EINVAL;

    }



    trace_virtio_ccw_interpret_ccw(sch->cssid, sch->ssid, sch->schid,

                                   ccw.cmd_code);

    check_len = !((ccw.flags & CCW_FLAG_SLI) && !(ccw.flags & CCW_FLAG_DC));



    if (dev->force_revision_1 && dev->revision < 0 &&

        ccw.cmd_code != CCW_CMD_SET_VIRTIO_REV) {

        /*

         * virtio-1 drivers must start with negotiating to a revision >= 1,

         * so post a command reject for all other commands

         */

        return -ENOSYS;

    }



    /* Look at the command. */

    switch (ccw.cmd_code) {

    case CCW_CMD_SET_VQ:

        ret = virtio_ccw_handle_set_vq(sch, ccw, check_len, dev->revision < 1);

        break;

    case CCW_CMD_VDEV_RESET:

        virtio_ccw_reset_virtio(dev, vdev);

        ret = 0;

        break;

    case CCW_CMD_READ_FEAT:

        if (check_len) {

            if (ccw.count != sizeof(features)) {

                ret = -EINVAL;

                break;

            }

        } else if (ccw.count < sizeof(features)) {

            /* Can't execute command. */

            ret = -EINVAL;

            break;

        }

        if (!ccw.cda) {

            ret = -EFAULT;

        } else {

            VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);



            features.index = address_space_ldub(&address_space_memory,

                                                ccw.cda

                                                + sizeof(features.features),

                                                MEMTXATTRS_UNSPECIFIED,

                                                NULL);

            if (features.index == 0) {

                if (dev->revision >= 1) {

                    /* Don't offer legacy features for modern devices. */

                    features.features = (uint32_t)

                        (vdev->host_features & ~vdc->legacy_features);

                } else {

                    features.features = (uint32_t)vdev->host_features;

                }

            } else if ((features.index == 1) && (dev->revision >= 1)) {

                /*

                 * Only offer feature bits beyond 31 if the guest has

                 * negotiated at least revision 1.

                 */

                features.features = (uint32_t)(vdev->host_features >> 32);

            } else {

                /* Return zeroes if the guest supports more feature bits. */

                features.features = 0;

            }

            address_space_stl_le(&address_space_memory, ccw.cda,

                                 features.features, MEMTXATTRS_UNSPECIFIED,

                                 NULL);

            sch->curr_status.scsw.count = ccw.count - sizeof(features);

            ret = 0;

        }

        break;

    case CCW_CMD_WRITE_FEAT:

        if (check_len) {

            if (ccw.count != sizeof(features)) {

                ret = -EINVAL;

                break;

            }

        } else if (ccw.count < sizeof(features)) {

            /* Can't execute command. */

            ret = -EINVAL;

            break;

        }

        if (!ccw.cda) {

            ret = -EFAULT;

        } else {

            features.index = address_space_ldub(&address_space_memory,

                                                ccw.cda

                                                + sizeof(features.features),

                                                MEMTXATTRS_UNSPECIFIED,

                                                NULL);

            features.features = address_space_ldl_le(&address_space_memory,

                                                     ccw.cda,

                                                     MEMTXATTRS_UNSPECIFIED,

                                                     NULL);

            if (features.index == 0) {

                virtio_set_features(vdev,

                                    (vdev->guest_features & 0xffffffff00000000ULL) |

                                    features.features);

            } else if ((features.index == 1) && (dev->revision >= 1)) {

                /*

                 * If the guest did not negotiate at least revision 1,

                 * we did not offer it any feature bits beyond 31. Such a

                 * guest passing us any bit here is therefore buggy.

                 */

                virtio_set_features(vdev,

                                    (vdev->guest_features & 0x00000000ffffffffULL) |

                                    ((uint64_t)features.features << 32));

            } else {

                /*

                 * If the guest supports more feature bits, assert that it

                 * passes us zeroes for those we don't support.

                 */

                if (features.features) {

                    fprintf(stderr, "Guest bug: features[%i]=%x (expected 0)\n",

                            features.index, features.features);

                    /* XXX: do a unit check here? */

                }

            }

            sch->curr_status.scsw.count = ccw.count - sizeof(features);

            ret = 0;

        }

        break;

    case CCW_CMD_READ_CONF:

        if (check_len) {

            if (ccw.count > vdev->config_len) {

                ret = -EINVAL;

                break;

            }

        }

        len = MIN(ccw.count, vdev->config_len);

        if (!ccw.cda) {

            ret = -EFAULT;

        } else {

            virtio_bus_get_vdev_config(&dev->bus, vdev->config);

            cpu_physical_memory_write(ccw.cda, vdev->config, len);

            sch->curr_status.scsw.count = ccw.count - len;

            ret = 0;

        }

        break;

    case CCW_CMD_WRITE_CONF:

        if (check_len) {

            if (ccw.count > vdev->config_len) {

                ret = -EINVAL;

                break;

            }

        }

        len = MIN(ccw.count, vdev->config_len);

        hw_len = len;

        if (!ccw.cda) {

            ret = -EFAULT;

        } else {

            config = cpu_physical_memory_map(ccw.cda, &hw_len, 0);

            if (!config) {

                ret = -EFAULT;

            } else {

                len = hw_len;

                memcpy(vdev->config, config, len);

                cpu_physical_memory_unmap(config, hw_len, 0, hw_len);

                virtio_bus_set_vdev_config(&dev->bus, vdev->config);

                sch->curr_status.scsw.count = ccw.count - len;

                ret = 0;

            }

        }

        break;

    case CCW_CMD_READ_STATUS:

        if (check_len) {

            if (ccw.count != sizeof(status)) {

                ret = -EINVAL;

                break;

            }

        } else if (ccw.count < sizeof(status)) {

            /* Can't execute command. */

            ret = -EINVAL;

            break;

        }

        if (!ccw.cda) {

            ret = -EFAULT;

        } else {

            address_space_stb(&address_space_memory, ccw.cda, vdev->status,

                                        MEMTXATTRS_UNSPECIFIED, NULL);

            sch->curr_status.scsw.count = ccw.count - sizeof(vdev->status);;

            ret = 0;

        }

        break;

    case CCW_CMD_WRITE_STATUS:

        if (check_len) {

            if (ccw.count != sizeof(status)) {

                ret = -EINVAL;

                break;

            }

        } else if (ccw.count < sizeof(status)) {

            /* Can't execute command. */

            ret = -EINVAL;

            break;

        }

        if (!ccw.cda) {

            ret = -EFAULT;

        } else {

            status = address_space_ldub(&address_space_memory, ccw.cda,

                                        MEMTXATTRS_UNSPECIFIED, NULL);

            if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) {

                virtio_ccw_stop_ioeventfd(dev);

            }

            if (virtio_set_status(vdev, status) == 0) {

                if (vdev->status == 0) {

                    virtio_ccw_reset_virtio(dev, vdev);

                }

                if (status & VIRTIO_CONFIG_S_DRIVER_OK) {

                    virtio_ccw_start_ioeventfd(dev);

                }

                sch->curr_status.scsw.count = ccw.count - sizeof(status);

                ret = 0;

            } else {

                /* Trigger a command reject. */

                ret = -ENOSYS;

            }

        }

        break;

    case CCW_CMD_SET_IND:

        if (check_len) {

            if (ccw.count != sizeof(indicators)) {

                ret = -EINVAL;

                break;

            }

        } else if (ccw.count < sizeof(indicators)) {

            /* Can't execute command. */

            ret = -EINVAL;

            break;

        }

        if (sch->thinint_active) {

            /* Trigger a command reject. */

            ret = -ENOSYS;

            break;

        }

        if (virtio_get_num_queues(vdev) > NR_CLASSIC_INDICATOR_BITS) {

            /* More queues than indicator bits --> trigger a reject */

            ret = -ENOSYS;

            break;

        }

        if (!ccw.cda) {

            ret = -EFAULT;

        } else {

            indicators = address_space_ldq_be(&address_space_memory, ccw.cda,

                                              MEMTXATTRS_UNSPECIFIED, NULL);

            dev->indicators = get_indicator(indicators, sizeof(uint64_t));

            sch->curr_status.scsw.count = ccw.count - sizeof(indicators);

            ret = 0;

        }

        break;

    case CCW_CMD_SET_CONF_IND:

        if (check_len) {

            if (ccw.count != sizeof(indicators)) {

                ret = -EINVAL;

                break;

            }

        } else if (ccw.count < sizeof(indicators)) {

            /* Can't execute command. */

            ret = -EINVAL;

            break;

        }

        if (!ccw.cda) {

            ret = -EFAULT;

        } else {

            indicators = address_space_ldq_be(&address_space_memory, ccw.cda,

                                              MEMTXATTRS_UNSPECIFIED, NULL);

            dev->indicators2 = get_indicator(indicators, sizeof(uint64_t));

            sch->curr_status.scsw.count = ccw.count - sizeof(indicators);

            ret = 0;

        }

        break;

    case CCW_CMD_READ_VQ_CONF:

        if (check_len) {

            if (ccw.count != sizeof(vq_config)) {

                ret = -EINVAL;

                break;

            }

        } else if (ccw.count < sizeof(vq_config)) {

            /* Can't execute command. */

            ret = -EINVAL;

            break;

        }

        if (!ccw.cda) {

            ret = -EFAULT;

        } else {

            vq_config.index = address_space_lduw_be(&address_space_memory,

                                                    ccw.cda,

                                                    MEMTXATTRS_UNSPECIFIED,

                                                    NULL);

            if (vq_config.index >= VIRTIO_QUEUE_MAX) {

                ret = -EINVAL;

                break;

            }

            vq_config.num_max = virtio_queue_get_num(vdev,

                                                     vq_config.index);

            address_space_stw_be(&address_space_memory,

                                 ccw.cda + sizeof(vq_config.index),

                                 vq_config.num_max,

                                 MEMTXATTRS_UNSPECIFIED,

                                 NULL);

            sch->curr_status.scsw.count = ccw.count - sizeof(vq_config);

            ret = 0;

        }

        break;

    case CCW_CMD_SET_IND_ADAPTER:

        if (check_len) {

            if (ccw.count != sizeof(*thinint)) {

                ret = -EINVAL;

                break;

            }

        } else if (ccw.count < sizeof(*thinint)) {

            /* Can't execute command. */

            ret = -EINVAL;

            break;

        }

        len = sizeof(*thinint);

        hw_len = len;

        if (!ccw.cda) {

            ret = -EFAULT;

        } else if (dev->indicators && !sch->thinint_active) {

            /* Trigger a command reject. */

            ret = -ENOSYS;

        } else {

            thinint = cpu_physical_memory_map(ccw.cda, &hw_len, 0);

            if (!thinint) {

                ret = -EFAULT;

            } else {

                uint64_t ind_bit = ldq_be_p(&thinint->ind_bit);



                len = hw_len;

                dev->summary_indicator =

                    get_indicator(ldq_be_p(&thinint->summary_indicator),

                                  sizeof(uint8_t));

                dev->indicators =

                    get_indicator(ldq_be_p(&thinint->device_indicator),

                                  ind_bit / 8 + 1);

                dev->thinint_isc = thinint->isc;

                dev->routes.adapter.ind_offset = ind_bit;

                dev->routes.adapter.summary_offset = 7;

                cpu_physical_memory_unmap(thinint, hw_len, 0, hw_len);

                dev->routes.adapter.adapter_id = css_get_adapter_id(

                                                 CSS_IO_ADAPTER_VIRTIO,

                                                 dev->thinint_isc);

                sch->thinint_active = ((dev->indicators != NULL) &&

                                       (dev->summary_indicator != NULL));

                sch->curr_status.scsw.count = ccw.count - len;

                ret = 0;

            }

        }

        break;

    case CCW_CMD_SET_VIRTIO_REV:

        len = sizeof(revinfo);

        if (ccw.count < len) {

            ret = -EINVAL;

            break;

        }

        if (!ccw.cda) {

            ret = -EFAULT;

            break;

        }

        revinfo.revision =

            address_space_lduw_be(&address_space_memory, ccw.cda,

                                  MEMTXATTRS_UNSPECIFIED, NULL);

        revinfo.length =

            address_space_lduw_be(&address_space_memory,

                                  ccw.cda + sizeof(revinfo.revision),

                                  MEMTXATTRS_UNSPECIFIED, NULL);

        if (ccw.count < len + revinfo.length ||

            (check_len && ccw.count > len + revinfo.length)) {

            ret = -EINVAL;

            break;

        }

        /*

         * Once we start to support revisions with additional data, we'll

         * need to fetch it here. Nothing to do for now, though.

         */

        if (dev->revision >= 0 ||

            revinfo.revision > virtio_ccw_rev_max(dev) ||

            (dev->force_revision_1 && !revinfo.revision)) {

            ret = -ENOSYS;

            break;

        }

        ret = 0;

        dev->revision = revinfo.revision;

        break;

    default:

        ret = -ENOSYS;

        break;

    }

    return ret;

}

static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)

{

    int ret;

    VirtioRevInfo revinfo;

    uint8_t status;

    VirtioFeatDesc features;

    void *config;

    hwaddr indicators;

    VqConfigBlock vq_config;

    VirtioCcwDevice *dev = sch->driver_data;

    VirtIODevice *vdev = virtio_ccw_get_vdev(sch);

    bool check_len;

    int len;

    hwaddr hw_len;

    VirtioThinintInfo *thinint;



    if (!dev) {

        return -EINVAL;

    }



    trace_virtio_ccw_interpret_ccw(sch->cssid, sch->ssid, sch->schid,

                                   ccw.cmd_code);

    check_len = !((ccw.flags & CCW_FLAG_SLI) && !(ccw.flags & CCW_FLAG_DC));



    if (dev->force_revision_1 && dev->revision < 0 &&

        ccw.cmd_code != CCW_CMD_SET_VIRTIO_REV) {

        







        return -ENOSYS;

    }



    

    switch (ccw.cmd_code) {

    case CCW_CMD_SET_VQ:

        ret = virtio_ccw_handle_set_vq(sch, ccw, check_len, dev->revision < 1);

        break;

    case CCW_CMD_VDEV_RESET:

        virtio_ccw_reset_virtio(dev, vdev);

        ret = 0;

        break;

    case CCW_CMD_READ_FEAT:

        if (check_len) {

            if (ccw.count != sizeof(features)) {

                ret = -EINVAL;

                break;

            }

        } else if (ccw.count < sizeof(features)) {

            

            ret = -EINVAL;

            break;

        }

        if (!ccw.cda) {

            ret = -EFAULT;

        } else {

            VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);



            features.index = address_space_ldub(&address_space_memory,

                                                ccw.cda

                                                + sizeof(features.features),

                                                MEMTXATTRS_UNSPECIFIED,

                                                NULL);

            if (features.index == 0) {

                if (dev->revision >= 1) {

                    

                    features.features = (uint32_t)

                        (vdev->host_features & ~vdc->legacy_features);

                } else {

                    features.features = (uint32_t)vdev->host_features;

                }

            } else if ((features.index == 1) && (dev->revision >= 1)) {

                







                features.features = (uint32_t)(vdev->host_features >> 32);

            } else {

                

                features.features = 0;

            }

            address_space_stl_le(&address_space_memory, ccw.cda,

                                 features.features, MEMTXATTRS_UNSPECIFIED,

                                 NULL);

            sch->curr_status.scsw.count = ccw.count - sizeof(features);

            ret = 0;

        }

        break;

    case CCW_CMD_WRITE_FEAT:

        if (check_len) {

            if (ccw.count != sizeof(features)) {

                ret = -EINVAL;

                break;

            }

        } else if (ccw.count < sizeof(features)) {

            

            ret = -EINVAL;

            break;

        }

        if (!ccw.cda) {

            ret = -EFAULT;

        } else {

            features.index = address_space_ldub(&address_space_memory,

                                                ccw.cda

                                                + sizeof(features.features),

                                                MEMTXATTRS_UNSPECIFIED,

                                                NULL);

            features.features = address_space_ldl_le(&address_space_memory,

                                                     ccw.cda,

                                                     MEMTXATTRS_UNSPECIFIED,

                                                     NULL);

            if (features.index == 0) {

                virtio_set_features(vdev,

                                    (vdev->guest_features & 0xffffffff00000000ULL) |

                                    features.features);

            } else if ((features.index == 1) && (dev->revision >= 1)) {

                









                virtio_set_features(vdev,

                                    (vdev->guest_features & 0x00000000ffffffffULL) |

                                    ((uint64_t)features.features << 32));

            } else {

                







                if (features.features) {

                    fprintf(stderr, "Guest bug: features[%i]=%x (expected 0)\n",

                            features.index, features.features);

                    

                }

            }

            sch->curr_status.scsw.count = ccw.count - sizeof(features);

            ret = 0;

        }

        break;

    case CCW_CMD_READ_CONF:

        if (check_len) {

            if (ccw.count > vdev->config_len) {

                ret = -EINVAL;

                break;

            }

        }

        len = MIN(ccw.count, vdev->config_len);

        if (!ccw.cda) {

            ret = -EFAULT;

        } else {

            virtio_bus_get_vdev_config(&dev->bus, vdev->config);

            cpu_physical_memory_write(ccw.cda, vdev->config, len);

            sch->curr_status.scsw.count = ccw.count - len;

            ret = 0;

        }

        break;

    case CCW_CMD_WRITE_CONF:

        if (check_len) {

            if (ccw.count > vdev->config_len) {

                ret = -EINVAL;

                break;

            }

        }

        len = MIN(ccw.count, vdev->config_len);

        hw_len = len;

        if (!ccw.cda) {

            ret = -EFAULT;

        } else {

            config = cpu_physical_memory_map(ccw.cda, &hw_len, 0);

            if (!config) {

                ret = -EFAULT;

            } else {

                len = hw_len;

                memcpy(vdev->config, config, len);

                cpu_physical_memory_unmap(config, hw_len, 0, hw_len);

                virtio_bus_set_vdev_config(&dev->bus, vdev->config);

                sch->curr_status.scsw.count = ccw.count - len;

                ret = 0;

            }

        }

        break;

    case CCW_CMD_READ_STATUS:

        if (check_len) {

            if (ccw.count != sizeof(status)) {

                ret = -EINVAL;

                break;

            }

        } else if (ccw.count < sizeof(status)) {

            

            ret = -EINVAL;

            break;

        }

        if (!ccw.cda) {

            ret = -EFAULT;

        } else {

            address_space_stb(&address_space_memory, ccw.cda, vdev->status,

                                        MEMTXATTRS_UNSPECIFIED, NULL);

            sch->curr_status.scsw.count = ccw.count - sizeof(vdev->status);;

            ret = 0;

        }

        break;

    case CCW_CMD_WRITE_STATUS:

        if (check_len) {

            if (ccw.count != sizeof(status)) {

                ret = -EINVAL;

                break;

            }

        } else if (ccw.count < sizeof(status)) {

            

            ret = -EINVAL;

            break;

        }

        if (!ccw.cda) {

            ret = -EFAULT;

        } else {

            status = address_space_ldub(&address_space_memory, ccw.cda,

                                        MEMTXATTRS_UNSPECIFIED, NULL);

            if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) {

                virtio_ccw_stop_ioeventfd(dev);

            }

            if (virtio_set_status(vdev, status) == 0) {

                if (vdev->status == 0) {

                    virtio_ccw_reset_virtio(dev, vdev);

                }

                if (status & VIRTIO_CONFIG_S_DRIVER_OK) {

                    virtio_ccw_start_ioeventfd(dev);

                }

                sch->curr_status.scsw.count = ccw.count - sizeof(status);

                ret = 0;

            } else {

                

                ret = -ENOSYS;

            }

        }

        break;

    case CCW_CMD_SET_IND:

        if (check_len) {

            if (ccw.count != sizeof(indicators)) {

                ret = -EINVAL;

                break;

            }

        } else if (ccw.count < sizeof(indicators)) {

            

            ret = -EINVAL;

            break;

        }

        if (sch->thinint_active) {

            

            ret = -ENOSYS;

            break;

        }

        if (virtio_get_num_queues(vdev) > NR_CLASSIC_INDICATOR_BITS) {

            

            ret = -ENOSYS;

            break;

        }

        if (!ccw.cda) {

            ret = -EFAULT;

        } else {

            indicators = address_space_ldq_be(&address_space_memory, ccw.cda,

                                              MEMTXATTRS_UNSPECIFIED, NULL);

            dev->indicators = get_indicator(indicators, sizeof(uint64_t));

            sch->curr_status.scsw.count = ccw.count - sizeof(indicators);

            ret = 0;

        }

        break;

    case CCW_CMD_SET_CONF_IND:

        if (check_len) {

            if (ccw.count != sizeof(indicators)) {

                ret = -EINVAL;

                break;

            }

        } else if (ccw.count < sizeof(indicators)) {

            

            ret = -EINVAL;

            break;

        }

        if (!ccw.cda) {

            ret = -EFAULT;

        } else {

            indicators = address_space_ldq_be(&address_space_memory, ccw.cda,

                                              MEMTXATTRS_UNSPECIFIED, NULL);

            dev->indicators2 = get_indicator(indicators, sizeof(uint64_t));

            sch->curr_status.scsw.count = ccw.count - sizeof(indicators);

            ret = 0;

        }

        break;

    case CCW_CMD_READ_VQ_CONF:

        if (check_len) {

            if (ccw.count != sizeof(vq_config)) {

                ret = -EINVAL;

                break;

            }

        } else if (ccw.count < sizeof(vq_config)) {

            

            ret = -EINVAL;

            break;

        }

        if (!ccw.cda) {

            ret = -EFAULT;

        } else {

            vq_config.index = address_space_lduw_be(&address_space_memory,

                                                    ccw.cda,

                                                    MEMTXATTRS_UNSPECIFIED,

                                                    NULL);

            if (vq_config.index >= VIRTIO_QUEUE_MAX) {

                ret = -EINVAL;

                break;

            }

            vq_config.num_max = virtio_queue_get_num(vdev,

                                                     vq_config.index);

            address_space_stw_be(&address_space_memory,

                                 ccw.cda + sizeof(vq_config.index),

                                 vq_config.num_max,

                                 MEMTXATTRS_UNSPECIFIED,

                                 NULL);

            sch->curr_status.scsw.count = ccw.count - sizeof(vq_config);

            ret = 0;

        }

        break;

    case CCW_CMD_SET_IND_ADAPTER:

        if (check_len) {

            if (ccw.count != sizeof(*thinint)) {

                ret = -EINVAL;

                break;

            }

        } else if (ccw.count < sizeof(*thinint)) {

            

            ret = -EINVAL;

            break;

        }

        len = sizeof(*thinint);

        hw_len = len;

        if (!ccw.cda) {

            ret = -EFAULT;

        } else if (dev->indicators && !sch->thinint_active) {

            

            ret = -ENOSYS;

        } else {

            thinint = cpu_physical_memory_map(ccw.cda, &hw_len, 0);

            if (!thinint) {

                ret = -EFAULT;

            } else {

                uint64_t ind_bit = ldq_be_p(&thinint->ind_bit);



                len = hw_len;

                dev->summary_indicator =

                    get_indicator(ldq_be_p(&thinint->summary_indicator),

                                  sizeof(uint8_t));

                dev->indicators =

                    get_indicator(ldq_be_p(&thinint->device_indicator),

                                  ind_bit / 8 + 1);

                dev->thinint_isc = thinint->isc;

                dev->routes.adapter.ind_offset = ind_bit;

                dev->routes.adapter.summary_offset = 7;

                cpu_physical_memory_unmap(thinint, hw_len, 0, hw_len);

                dev->routes.adapter.adapter_id = css_get_adapter_id(

                                                 CSS_IO_ADAPTER_VIRTIO,

                                                 dev->thinint_isc);

                sch->thinint_active = ((dev->indicators != NULL) &&

                                       (dev->summary_indicator != NULL));

                sch->curr_status.scsw.count = ccw.count - len;

                ret = 0;

            }

        }

        break;

    case CCW_CMD_SET_VIRTIO_REV:

        len = sizeof(revinfo);

        if (ccw.count < len) {

            ret = -EINVAL;

            break;

        }

        if (!ccw.cda) {

            ret = -EFAULT;

            break;

        }

        revinfo.revision =

            address_space_lduw_be(&address_space_memory, ccw.cda,

                                  MEMTXATTRS_UNSPECIFIED, NULL);

        revinfo.length =

            address_space_lduw_be(&address_space_memory,

                                  ccw.cda + sizeof(revinfo.revision),

                                  MEMTXATTRS_UNSPECIFIED, NULL);

        if (ccw.count < len + revinfo.length ||

            (check_len && ccw.count > len + revinfo.length)) {

            ret = -EINVAL;

            break;

        }

        







        if (dev->revision >= 0 ||

            revinfo.revision > virtio_ccw_rev_max(dev) ||

            (dev->force_revision_1 && !revinfo.revision)) {

            ret = -ENOSYS;

            break;

        }

        ret = 0;

        dev->revision = revinfo.revision;

        break;

    default:

        ret = -ENOSYS;

        break;

    }

    return ret;

}

static int FUNC_0(SubchDev *VAR_0, CCW1 VAR_1)

{

    int VAR_2;

    VirtioRevInfo revinfo;

    uint8_t status;

    VirtioFeatDesc features;

    void *VAR_3;

    hwaddr indicators;

    VqConfigBlock vq_config;

    VirtioCcwDevice *dev = VAR_0->driver_data;

    VirtIODevice *vdev = virtio_ccw_get_vdev(VAR_0);

    bool check_len;

    int VAR_4;

    hwaddr hw_len;

    VirtioThinintInfo *thinint;



    if (!dev) {

        return -EINVAL;

    }



    trace_virtio_ccw_interpret_ccw(VAR_0->cssid, VAR_0->ssid, VAR_0->schid,

                                   VAR_1.cmd_code);

    check_len = !((VAR_1.flags & CCW_FLAG_SLI) && !(VAR_1.flags & CCW_FLAG_DC));



    if (dev->force_revision_1 && dev->revision < 0 &&

        VAR_1.cmd_code != CCW_CMD_SET_VIRTIO_REV) {

        







        return -ENOSYS;

    }



    

    switch (VAR_1.cmd_code) {

    case CCW_CMD_SET_VQ:

        VAR_2 = virtio_ccw_handle_set_vq(VAR_0, VAR_1, check_len, dev->revision < 1);

        break;

    case CCW_CMD_VDEV_RESET:

        virtio_ccw_reset_virtio(dev, vdev);

        VAR_2 = 0;

        break;

    case CCW_CMD_READ_FEAT:

        if (check_len) {

            if (VAR_1.count != sizeof(features)) {

                VAR_2 = -EINVAL;

                break;

            }

        } else if (VAR_1.count < sizeof(features)) {

            

            VAR_2 = -EINVAL;

            break;

        }

        if (!VAR_1.cda) {

            VAR_2 = -EFAULT;

        } else {

            VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);



            features.index = address_space_ldub(&address_space_memory,

                                                VAR_1.cda

                                                + sizeof(features.features),

                                                MEMTXATTRS_UNSPECIFIED,

                                                NULL);

            if (features.index == 0) {

                if (dev->revision >= 1) {

                    

                    features.features = (uint32_t)

                        (vdev->host_features & ~vdc->legacy_features);

                } else {

                    features.features = (uint32_t)vdev->host_features;

                }

            } else if ((features.index == 1) && (dev->revision >= 1)) {

                







                features.features = (uint32_t)(vdev->host_features >> 32);

            } else {

                

                features.features = 0;

            }

            address_space_stl_le(&address_space_memory, VAR_1.cda,

                                 features.features, MEMTXATTRS_UNSPECIFIED,

                                 NULL);

            VAR_0->curr_status.scsw.count = VAR_1.count - sizeof(features);

            VAR_2 = 0;

        }

        break;

    case CCW_CMD_WRITE_FEAT:

        if (check_len) {

            if (VAR_1.count != sizeof(features)) {

                VAR_2 = -EINVAL;

                break;

            }

        } else if (VAR_1.count < sizeof(features)) {

            

            VAR_2 = -EINVAL;

            break;

        }

        if (!VAR_1.cda) {

            VAR_2 = -EFAULT;

        } else {

            features.index = address_space_ldub(&address_space_memory,

                                                VAR_1.cda

                                                + sizeof(features.features),

                                                MEMTXATTRS_UNSPECIFIED,

                                                NULL);

            features.features = address_space_ldl_le(&address_space_memory,

                                                     VAR_1.cda,

                                                     MEMTXATTRS_UNSPECIFIED,

                                                     NULL);

            if (features.index == 0) {

                virtio_set_features(vdev,

                                    (vdev->guest_features & 0xffffffff00000000ULL) |

                                    features.features);

            } else if ((features.index == 1) && (dev->revision >= 1)) {

                









                virtio_set_features(vdev,

                                    (vdev->guest_features & 0x00000000ffffffffULL) |

                                    ((uint64_t)features.features << 32));

            } else {

                







                if (features.features) {

                    fprintf(stderr, "Guest bug: features[%i]=%x (expected 0)\n",

                            features.index, features.features);

                    

                }

            }

            VAR_0->curr_status.scsw.count = VAR_1.count - sizeof(features);

            VAR_2 = 0;

        }

        break;

    case CCW_CMD_READ_CONF:

        if (check_len) {

            if (VAR_1.count > vdev->config_len) {

                VAR_2 = -EINVAL;

                break;

            }

        }

        VAR_4 = MIN(VAR_1.count, vdev->config_len);

        if (!VAR_1.cda) {

            VAR_2 = -EFAULT;

        } else {

            virtio_bus_get_vdev_config(&dev->bus, vdev->VAR_3);

            cpu_physical_memory_write(VAR_1.cda, vdev->VAR_3, VAR_4);

            VAR_0->curr_status.scsw.count = VAR_1.count - VAR_4;

            VAR_2 = 0;

        }

        break;

    case CCW_CMD_WRITE_CONF:

        if (check_len) {

            if (VAR_1.count > vdev->config_len) {

                VAR_2 = -EINVAL;

                break;

            }

        }

        VAR_4 = MIN(VAR_1.count, vdev->config_len);

        hw_len = VAR_4;

        if (!VAR_1.cda) {

            VAR_2 = -EFAULT;

        } else {

            VAR_3 = cpu_physical_memory_map(VAR_1.cda, &hw_len, 0);

            if (!VAR_3) {

                VAR_2 = -EFAULT;

            } else {

                VAR_4 = hw_len;

                memcpy(vdev->VAR_3, VAR_3, VAR_4);

                cpu_physical_memory_unmap(VAR_3, hw_len, 0, hw_len);

                virtio_bus_set_vdev_config(&dev->bus, vdev->VAR_3);

                VAR_0->curr_status.scsw.count = VAR_1.count - VAR_4;

                VAR_2 = 0;

            }

        }

        break;

    case CCW_CMD_READ_STATUS:

        if (check_len) {

            if (VAR_1.count != sizeof(status)) {

                VAR_2 = -EINVAL;

                break;

            }

        } else if (VAR_1.count < sizeof(status)) {

            

            VAR_2 = -EINVAL;

            break;

        }

        if (!VAR_1.cda) {

            VAR_2 = -EFAULT;

        } else {

            address_space_stb(&address_space_memory, VAR_1.cda, vdev->status,

                                        MEMTXATTRS_UNSPECIFIED, NULL);

            VAR_0->curr_status.scsw.count = VAR_1.count - sizeof(vdev->status);;

            VAR_2 = 0;

        }

        break;

    case CCW_CMD_WRITE_STATUS:

        if (check_len) {

            if (VAR_1.count != sizeof(status)) {

                VAR_2 = -EINVAL;

                break;

            }

        } else if (VAR_1.count < sizeof(status)) {

            

            VAR_2 = -EINVAL;

            break;

        }

        if (!VAR_1.cda) {

            VAR_2 = -EFAULT;

        } else {

            status = address_space_ldub(&address_space_memory, VAR_1.cda,

                                        MEMTXATTRS_UNSPECIFIED, NULL);

            if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) {

                virtio_ccw_stop_ioeventfd(dev);

            }

            if (virtio_set_status(vdev, status) == 0) {

                if (vdev->status == 0) {

                    virtio_ccw_reset_virtio(dev, vdev);

                }

                if (status & VIRTIO_CONFIG_S_DRIVER_OK) {

                    virtio_ccw_start_ioeventfd(dev);

                }

                VAR_0->curr_status.scsw.count = VAR_1.count - sizeof(status);

                VAR_2 = 0;

            } else {

                

                VAR_2 = -ENOSYS;

            }

        }

        break;

    case CCW_CMD_SET_IND:

        if (check_len) {

            if (VAR_1.count != sizeof(indicators)) {

                VAR_2 = -EINVAL;

                break;

            }

        } else if (VAR_1.count < sizeof(indicators)) {

            

            VAR_2 = -EINVAL;

            break;

        }

        if (VAR_0->thinint_active) {

            

            VAR_2 = -ENOSYS;

            break;

        }

        if (virtio_get_num_queues(vdev) > NR_CLASSIC_INDICATOR_BITS) {

            

            VAR_2 = -ENOSYS;

            break;

        }

        if (!VAR_1.cda) {

            VAR_2 = -EFAULT;

        } else {

            indicators = address_space_ldq_be(&address_space_memory, VAR_1.cda,

                                              MEMTXATTRS_UNSPECIFIED, NULL);

            dev->indicators = get_indicator(indicators, sizeof(uint64_t));

            VAR_0->curr_status.scsw.count = VAR_1.count - sizeof(indicators);

            VAR_2 = 0;

        }

        break;

    case CCW_CMD_SET_CONF_IND:

        if (check_len) {

            if (VAR_1.count != sizeof(indicators)) {

                VAR_2 = -EINVAL;

                break;

            }

        } else if (VAR_1.count < sizeof(indicators)) {

            

            VAR_2 = -EINVAL;

            break;

        }

        if (!VAR_1.cda) {

            VAR_2 = -EFAULT;

        } else {

            indicators = address_space_ldq_be(&address_space_memory, VAR_1.cda,

                                              MEMTXATTRS_UNSPECIFIED, NULL);

            dev->indicators2 = get_indicator(indicators, sizeof(uint64_t));

            VAR_0->curr_status.scsw.count = VAR_1.count - sizeof(indicators);

            VAR_2 = 0;

        }

        break;

    case CCW_CMD_READ_VQ_CONF:

        if (check_len) {

            if (VAR_1.count != sizeof(vq_config)) {

                VAR_2 = -EINVAL;

                break;

            }

        } else if (VAR_1.count < sizeof(vq_config)) {

            

            VAR_2 = -EINVAL;

            break;

        }

        if (!VAR_1.cda) {

            VAR_2 = -EFAULT;

        } else {

            vq_config.index = address_space_lduw_be(&address_space_memory,

                                                    VAR_1.cda,

                                                    MEMTXATTRS_UNSPECIFIED,

                                                    NULL);

            if (vq_config.index >= VIRTIO_QUEUE_MAX) {

                VAR_2 = -EINVAL;

                break;

            }

            vq_config.num_max = virtio_queue_get_num(vdev,

                                                     vq_config.index);

            address_space_stw_be(&address_space_memory,

                                 VAR_1.cda + sizeof(vq_config.index),

                                 vq_config.num_max,

                                 MEMTXATTRS_UNSPECIFIED,

                                 NULL);

            VAR_0->curr_status.scsw.count = VAR_1.count - sizeof(vq_config);

            VAR_2 = 0;

        }

        break;

    case CCW_CMD_SET_IND_ADAPTER:

        if (check_len) {

            if (VAR_1.count != sizeof(*thinint)) {

                VAR_2 = -EINVAL;

                break;

            }

        } else if (VAR_1.count < sizeof(*thinint)) {

            

            VAR_2 = -EINVAL;

            break;

        }

        VAR_4 = sizeof(*thinint);

        hw_len = VAR_4;

        if (!VAR_1.cda) {

            VAR_2 = -EFAULT;

        } else if (dev->indicators && !VAR_0->thinint_active) {

            

            VAR_2 = -ENOSYS;

        } else {

            thinint = cpu_physical_memory_map(VAR_1.cda, &hw_len, 0);

            if (!thinint) {

                VAR_2 = -EFAULT;

            } else {

                uint64_t ind_bit = ldq_be_p(&thinint->ind_bit);



                VAR_4 = hw_len;

                dev->summary_indicator =

                    get_indicator(ldq_be_p(&thinint->summary_indicator),

                                  sizeof(uint8_t));

                dev->indicators =

                    get_indicator(ldq_be_p(&thinint->device_indicator),

                                  ind_bit / 8 + 1);

                dev->thinint_isc = thinint->isc;

                dev->routes.adapter.ind_offset = ind_bit;

                dev->routes.adapter.summary_offset = 7;

                cpu_physical_memory_unmap(thinint, hw_len, 0, hw_len);

                dev->routes.adapter.adapter_id = css_get_adapter_id(

                                                 CSS_IO_ADAPTER_VIRTIO,

                                                 dev->thinint_isc);

                VAR_0->thinint_active = ((dev->indicators != NULL) &&

                                       (dev->summary_indicator != NULL));

                VAR_0->curr_status.scsw.count = VAR_1.count - VAR_4;

                VAR_2 = 0;

            }

        }

        break;

    case CCW_CMD_SET_VIRTIO_REV:

        VAR_4 = sizeof(revinfo);

        if (VAR_1.count < VAR_4) {

            VAR_2 = -EINVAL;

            break;

        }

        if (!VAR_1.cda) {

            VAR_2 = -EFAULT;

            break;

        }

        revinfo.revision =

            address_space_lduw_be(&address_space_memory, VAR_1.cda,

                                  MEMTXATTRS_UNSPECIFIED, NULL);

        revinfo.length =

            address_space_lduw_be(&address_space_memory,

                                  VAR_1.cda + sizeof(revinfo.revision),

                                  MEMTXATTRS_UNSPECIFIED, NULL);

        if (VAR_1.count < VAR_4 + revinfo.length ||

            (check_len && VAR_1.count > VAR_4 + revinfo.length)) {

            VAR_2 = -EINVAL;

            break;

        }

        







        if (dev->revision >= 0 ||

            revinfo.revision > virtio_ccw_rev_max(dev) ||

            (dev->force_revision_1 && !revinfo.revision)) {

            VAR_2 = -ENOSYS;

            break;

        }

        VAR_2 = 0;

        dev->revision = revinfo.revision;

        break;

    default:

        VAR_2 = -ENOSYS;

        break;

    }

    return VAR_2;

}

static int FUNC_0(SubchDev *VAR_0, CCW1 VAR_1)
{ int VAR_2; VirtioRevInfo revinfo; uint8_t status; VirtioFeatDesc features; void *VAR_3; hwaddr indicators; VqConfigBlock vq_config; VirtioCcwDevice *dev = VAR_0->driver_data; VirtIODevice *vdev = virtio_ccw_get_vdev(VAR_0); bool check_len; int VAR_4; hwaddr hw_len; VirtioThinintInfo *thinint; if (!dev) { return -EINVAL; } trace_virtio_ccw_interpret_ccw(VAR_0->cssid, VAR_0->ssid, VAR_0->schid,
VAR_1.cmd_code); check_len = !((VAR_1.flags & CCW_FLAG_SLI) && !(VAR_1.flags & CCW_FLAG_DC)); if (dev->force_revision_1 && dev->revision < 0 &&
VAR_1.cmd_code != CCW_CMD_SET_VIRTIO_REV) { return -ENOSYS; } switch (VAR_1.cmd_code) { case CCW_CMD_SET_VQ:
VAR_2 = virtio_ccw_handle_set_vq(VAR_0, VAR_1, check_len, dev->revision < 1); break; case CCW_CMD_VDEV_RESET:
virtio_ccw_reset_virtio(dev, vdev); VAR_2 = 0; break; case CCW_CMD_READ_FEAT:
if (check_len) { if (VAR_1.count != sizeof(features)) { VAR_2 = -EINVAL; break; } } else if (VAR_1.count < sizeof(features)) { VAR_2 = -EINVAL; break; } if (!VAR_1.cda) { VAR_2 = -EFAULT; } else { VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); features.index = address_space_ldub(&address_space_memory,
VAR_1.cda
+ sizeof(features.features),
MEMTXATTRS_UNSPECIFIED,
NULL); if (features.index == 0) { if (dev->revision >= 1) { features.features = (uint32_t)
(vdev->host_features & ~vdc->legacy_features); } else { features.features = (uint32_t)vdev->host_features; } } else if ((features.index == 1) && (dev->revision >= 1)) { features.features = (uint32_t)(vdev->host_features >> 32); } else { features.features = 0; } address_space_stl_le(&address_space_memory, VAR_1.cda,
features.features, MEMTXATTRS_UNSPECIFIED,
NULL); VAR_0->curr_status.scsw.count = VAR_1.count - sizeof(features); VAR_2 = 0; } break; case CCW_CMD_WRITE_FEAT:
if (check_len) { if (VAR_1.count != sizeof(features)) { VAR_2 = -EINVAL; break; } } else if (VAR_1.count < sizeof(features)) { VAR_2 = -EINVAL; break; } if (!VAR_1.cda) { VAR_2 = -EFAULT; } else { features.index = address_space_ldub(&address_space_memory,
VAR_1.cda
+ sizeof(features.features),
MEMTXATTRS_UNSPECIFIED,
NULL); features.features = address_space_ldl_le(&address_space_memory,
VAR_1.cda,
MEMTXATTRS_UNSPECIFIED,
NULL); if (features.index == 0) { virtio_set_features(vdev,
(vdev->guest_features & 0xffffffff00000000ULL) |
features.features); } else if ((features.index == 1) && (dev->revision >= 1)) { virtio_set_features(vdev,
(vdev->guest_features & 0x00000000ffffffffULL) |
((uint64_t)features.features << 32)); } else { if (features.features) { fprintf(stderr, "Guest bug: features[%i]=%x (expected 0)\n",
features.index, features.features); } } VAR_0->curr_status.scsw.count = VAR_1.count - sizeof(features); VAR_2 = 0; } break; case CCW_CMD_READ_CONF:
if (check_len) { if (VAR_1.count > vdev->config_len) { VAR_2 = -EINVAL; break; } } VAR_4 = MIN(VAR_1.count, vdev->config_len); if (!VAR_1.cda) { VAR_2 = -EFAULT; } else { virtio_bus_get_vdev_config(&dev->bus, vdev->VAR_3); cpu_physical_memory_write(VAR_1.cda, vdev->VAR_3, VAR_4); VAR_0->curr_status.scsw.count = VAR_1.count - VAR_4; VAR_2 = 0; } break; case CCW_CMD_WRITE_CONF:
if (check_len) { if (VAR_1.count > vdev->config_len) { VAR_2 = -EINVAL; break; } } VAR_4 = MIN(VAR_1.count, vdev->config_len); hw_len = VAR_4; if (!VAR_1.cda) { VAR_2 = -EFAULT; } else { VAR_3 = cpu_physical_memory_map(VAR_1.cda, &hw_len, 0); if (!VAR_3) { VAR_2 = -EFAULT; } else { VAR_4 = hw_len; memcpy(vdev->VAR_3, VAR_3, VAR_4); cpu_physical_memory_unmap(VAR_3, hw_len, 0, hw_len); virtio_bus_set_vdev_config(&dev->bus, vdev->VAR_3); VAR_0->curr_status.scsw.count = VAR_1.count - VAR_4; VAR_2 = 0; } } break; case CCW_CMD_READ_STATUS:
if (check_len) { if (VAR_1.count != sizeof(status)) { VAR_2 = -EINVAL; break; } } else if (VAR_1.count < sizeof(status)) { VAR_2 = -EINVAL; break; } if (!VAR_1.cda) { VAR_2 = -EFAULT; } else { address_space_stb(&address_space_memory, VAR_1.cda, vdev->status,
MEMTXATTRS_UNSPECIFIED, NULL); VAR_0->curr_status.scsw.count = VAR_1.count - sizeof(vdev->status);; VAR_2 = 0; } break; case CCW_CMD_WRITE_STATUS:
if (check_len) { if (VAR_1.count != sizeof(status)) { VAR_2 = -EINVAL; break; } } else if (VAR_1.count < sizeof(status)) { VAR_2 = -EINVAL; break; } if (!VAR_1.cda) { VAR_2 = -EFAULT; } else { status = address_space_ldub(&address_space_memory, VAR_1.cda,
MEMTXATTRS_UNSPECIFIED, NULL); if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) { virtio_ccw_stop_ioeventfd(dev); } if (virtio_set_status(vdev, status) == 0) { if (vdev->status == 0) { virtio_ccw_reset_virtio(dev, vdev); } if (status & VIRTIO_CONFIG_S_DRIVER_OK) { virtio_ccw_start_ioeventfd(dev); } VAR_0->curr_status.scsw.count = VAR_1.count - sizeof(status); VAR_2 = 0; } else { VAR_2 = -ENOSYS; } } break; case CCW_CMD_SET_IND:
if (check_len) { if (VAR_1.count != sizeof(indicators)) { VAR_2 = -EINVAL; break; } } else if (VAR_1.count < sizeof(indicators)) { VAR_2 = -EINVAL; break; } if (VAR_0->thinint_active) { VAR_2 = -ENOSYS; break; } if (virtio_get_num_queues(vdev) > NR_CLASSIC_INDICATOR_BITS) { VAR_2 = -ENOSYS; break; } if (!VAR_1.cda) { VAR_2 = -EFAULT; } else { indicators = address_space_ldq_be(&address_space_memory, VAR_1.cda,
MEMTXATTRS_UNSPECIFIED, NULL); dev->indicators = get_indicator(indicators, sizeof(uint64_t)); VAR_0->curr_status.scsw.count = VAR_1.count - sizeof(indicators); VAR_2 = 0; } break; case CCW_CMD_SET_CONF_IND:
if (check_len) { if (VAR_1.count != sizeof(indicators)) { VAR_2 = -EINVAL; break; } } else if (VAR_1.count < sizeof(indicators)) { VAR_2 = -EINVAL; break; } if (!VAR_1.cda) { VAR_2 = -EFAULT; } else { indicators = address_space_ldq_be(&address_space_memory, VAR_1.cda,
MEMTXATTRS_UNSPECIFIED, NULL); dev->indicators2 = get_indicator(indicators, sizeof(uint64_t)); VAR_0->curr_status.scsw.count = VAR_1.count - sizeof(indicators); VAR_2 = 0; } break; case CCW_CMD_READ_VQ_CONF:
if (check_len) { if (VAR_1.count != sizeof(vq_config)) { VAR_2 = -EINVAL; break; } } else if (VAR_1.count < sizeof(vq_config)) { VAR_2 = -EINVAL; break; } if (!VAR_1.cda) { VAR_2 = -EFAULT; } else { vq_config.index = address_space_lduw_be(&address_space_memory,
VAR_1.cda,
MEMTXATTRS_UNSPECIFIED,
NULL); if (vq_config.index >= VIRTIO_QUEUE_MAX) { VAR_2 = -EINVAL; break; } vq_config.num_max = virtio_queue_get_num(vdev,
vq_config.index); address_space_stw_be(&address_space_memory,
VAR_1.cda + sizeof(vq_config.index),
vq_config.num_max,
MEMTXATTRS_UNSPECIFIED,
NULL); VAR_0->curr_status.scsw.count = VAR_1.count - sizeof(vq_config); VAR_2 = 0; } break; case CCW_CMD_SET_IND_ADAPTER:
if (check_len) { if (VAR_1.count != sizeof(*thinint)) { VAR_2 = -EINVAL; break; } } else if (VAR_1.count < sizeof(*thinint)) { VAR_2 = -EINVAL; break; } VAR_4 = sizeof(*thinint); hw_len = VAR_4; if (!VAR_1.cda) { VAR_2 = -EFAULT; } else if (dev->indicators && !VAR_0->thinint_active) { VAR_2 = -ENOSYS; } else { thinint = cpu_physical_memory_map(VAR_1.cda, &hw_len, 0); if (!thinint) { VAR_2 = -EFAULT; } else { uint64_t ind_bit = ldq_be_p(&thinint->ind_bit); VAR_4 = hw_len; dev->summary_indicator =
get_indicator(ldq_be_p(&thinint->summary_indicator),
sizeof(uint8_t)); dev->indicators =
get_indicator(ldq_be_p(&thinint->device_indicator),
ind_bit / 8 + 1); dev->thinint_isc = thinint->isc; dev->routes.adapter.ind_offset = ind_bit; dev->routes.adapter.summary_offset = 7; cpu_physical_memory_unmap(thinint, hw_len, 0, hw_len); dev->routes.adapter.adapter_id = css_get_adapter_id(
CSS_IO_ADAPTER_VIRTIO,
dev->thinint_isc); VAR_0->thinint_active = ((dev->indicators != NULL) &&
(dev->summary_indicator != NULL)); VAR_0->curr_status.scsw.count = VAR_1.count - VAR_4; VAR_2 = 0; } } break; case CCW_CMD_SET_VIRTIO_REV:
VAR_4 = sizeof(revinfo); if (VAR_1.count < VAR_4) { VAR_2 = -EINVAL; break; } if (!VAR_1.cda) { VAR_2 = -EFAULT; break; } revinfo.revision =
address_space_lduw_be(&address_space_memory, VAR_1.cda,
MEMTXATTRS_UNSPECIFIED, NULL); revinfo.length =
address_space_lduw_be(&address_space_memory,
VAR_1.cda + sizeof(revinfo.revision),
MEMTXATTRS_UNSPECIFIED, NULL); if (VAR_1.count < VAR_4 + revinfo.length ||
(check_len && VAR_1.count > VAR_4 + revinfo.length)) { VAR_2 = -EINVAL; break; } if (dev->revision >= 0 ||
revinfo.revision > virtio_ccw_rev_max(dev) ||
(dev->force_revision_1 && !revinfo.revision)) { VAR_2 = -ENOSYS; break; } VAR_2 = 0; dev->revision = revinfo.revision; break; default:
VAR_2 = -ENOSYS; break; } return VAR_2; }