From 74a599f09bec7419b2490039f0fb33bc8581ef7c Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 3 Dec 2015 17:24:00 +0100 Subject: [PATCH] virtio/s390: handle error values in irb The common I/O layer may pass an error value as the irb in the device's interrupt handler (for classic channel I/O). This won't happen in current virtio-ccw implementations, but it's better to be safe than sorry. Let's just return the error conveyed by the irb and clear any possible pending I/O indications. Signed-off-by: Cornelia Huck Reviewed-by: Guenther Hutzl Reviewed-by: Pierre Morel Signed-off-by: Michael S. Tsirkin --- drivers/s390/virtio/virtio_ccw.c | 66 +++++++++++++++++++------------- 1 file changed, 39 insertions(+), 27 deletions(-) diff --git a/drivers/s390/virtio/virtio_ccw.c b/drivers/s390/virtio/virtio_ccw.c index b2a1a81e6fc8..1b831598df7c 100644 --- a/drivers/s390/virtio/virtio_ccw.c +++ b/drivers/s390/virtio/virtio_ccw.c @@ -984,32 +984,9 @@ static struct virtqueue *virtio_ccw_vq_by_ind(struct virtio_ccw_device *vcdev, return vq; } -static void virtio_ccw_int_handler(struct ccw_device *cdev, - unsigned long intparm, - struct irb *irb) +static void virtio_ccw_check_activity(struct virtio_ccw_device *vcdev, + __u32 activity) { - __u32 activity = intparm & VIRTIO_CCW_INTPARM_MASK; - struct virtio_ccw_device *vcdev = dev_get_drvdata(&cdev->dev); - int i; - struct virtqueue *vq; - - if (!vcdev) - return; - /* Check if it's a notification from the host. */ - if ((intparm == 0) && - (scsw_stctl(&irb->scsw) == - (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND))) { - /* OK */ - } - if (irb_is_error(irb)) { - /* Command reject? */ - if ((scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK) && - (irb->ecw[0] & SNS0_CMD_REJECT)) - vcdev->err = -EOPNOTSUPP; - else - /* Map everything else to -EIO. */ - vcdev->err = -EIO; - } if (vcdev->curr_io & activity) { switch (activity) { case VIRTIO_CCW_DOING_READ_FEAT: @@ -1029,12 +1006,47 @@ static void virtio_ccw_int_handler(struct ccw_device *cdev, break; default: /* don't know what to do... */ - dev_warn(&cdev->dev, "Suspicious activity '%08x'\n", - activity); + dev_warn(&vcdev->cdev->dev, + "Suspicious activity '%08x'\n", activity); WARN_ON(1); break; } } +} + +static void virtio_ccw_int_handler(struct ccw_device *cdev, + unsigned long intparm, + struct irb *irb) +{ + __u32 activity = intparm & VIRTIO_CCW_INTPARM_MASK; + struct virtio_ccw_device *vcdev = dev_get_drvdata(&cdev->dev); + int i; + struct virtqueue *vq; + + if (!vcdev) + return; + if (IS_ERR(irb)) { + vcdev->err = PTR_ERR(irb); + virtio_ccw_check_activity(vcdev, activity); + /* Don't poke around indicators, something's wrong. */ + return; + } + /* Check if it's a notification from the host. */ + if ((intparm == 0) && + (scsw_stctl(&irb->scsw) == + (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND))) { + /* OK */ + } + if (irb_is_error(irb)) { + /* Command reject? */ + if ((scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK) && + (irb->ecw[0] & SNS0_CMD_REJECT)) + vcdev->err = -EOPNOTSUPP; + else + /* Map everything else to -EIO. */ + vcdev->err = -EIO; + } + virtio_ccw_check_activity(vcdev, activity); for_each_set_bit(i, &vcdev->indicators, sizeof(vcdev->indicators) * BITS_PER_BYTE) { /* The bit clear must happen before the vring kick. */