Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <cornelia.huck@de.ibm.com>
Reviewed-by: Guenther Hutzl <hutzl@linux.vnet.ibm.com>
Reviewed-by: Pierre Morel <pmorel@linux.vnet.ibm.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

authored by

Cornelia Huck and committed by
Michael S. Tsirkin
74a599f0 9f9499ae

+39 -27
+39 -27
drivers/s390/virtio/virtio_ccw.c
··· 984 984 return vq; 985 985 } 986 986 987 - static void virtio_ccw_int_handler(struct ccw_device *cdev, 988 - unsigned long intparm, 989 - struct irb *irb) 987 + static void virtio_ccw_check_activity(struct virtio_ccw_device *vcdev, 988 + __u32 activity) 990 989 { 991 - __u32 activity = intparm & VIRTIO_CCW_INTPARM_MASK; 992 - struct virtio_ccw_device *vcdev = dev_get_drvdata(&cdev->dev); 993 - int i; 994 - struct virtqueue *vq; 995 - 996 - if (!vcdev) 997 - return; 998 - /* Check if it's a notification from the host. */ 999 - if ((intparm == 0) && 1000 - (scsw_stctl(&irb->scsw) == 1001 - (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND))) { 1002 - /* OK */ 1003 - } 1004 - if (irb_is_error(irb)) { 1005 - /* Command reject? */ 1006 - if ((scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK) && 1007 - (irb->ecw[0] & SNS0_CMD_REJECT)) 1008 - vcdev->err = -EOPNOTSUPP; 1009 - else 1010 - /* Map everything else to -EIO. */ 1011 - vcdev->err = -EIO; 1012 - } 1013 990 if (vcdev->curr_io & activity) { 1014 991 switch (activity) { 1015 992 case VIRTIO_CCW_DOING_READ_FEAT: ··· 1006 1029 break; 1007 1030 default: 1008 1031 /* don't know what to do... */ 1009 - dev_warn(&cdev->dev, "Suspicious activity '%08x'\n", 1010 - activity); 1032 + dev_warn(&vcdev->cdev->dev, 1033 + "Suspicious activity '%08x'\n", activity); 1011 1034 WARN_ON(1); 1012 1035 break; 1013 1036 } 1014 1037 } 1038 + } 1039 + 1040 + static void virtio_ccw_int_handler(struct ccw_device *cdev, 1041 + unsigned long intparm, 1042 + struct irb *irb) 1043 + { 1044 + __u32 activity = intparm & VIRTIO_CCW_INTPARM_MASK; 1045 + struct virtio_ccw_device *vcdev = dev_get_drvdata(&cdev->dev); 1046 + int i; 1047 + struct virtqueue *vq; 1048 + 1049 + if (!vcdev) 1050 + return; 1051 + if (IS_ERR(irb)) { 1052 + vcdev->err = PTR_ERR(irb); 1053 + virtio_ccw_check_activity(vcdev, activity); 1054 + /* Don't poke around indicators, something's wrong. */ 1055 + return; 1056 + } 1057 + /* Check if it's a notification from the host. */ 1058 + if ((intparm == 0) && 1059 + (scsw_stctl(&irb->scsw) == 1060 + (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND))) { 1061 + /* OK */ 1062 + } 1063 + if (irb_is_error(irb)) { 1064 + /* Command reject? */ 1065 + if ((scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK) && 1066 + (irb->ecw[0] & SNS0_CMD_REJECT)) 1067 + vcdev->err = -EOPNOTSUPP; 1068 + else 1069 + /* Map everything else to -EIO. */ 1070 + vcdev->err = -EIO; 1071 + } 1072 + virtio_ccw_check_activity(vcdev, activity); 1015 1073 for_each_set_bit(i, &vcdev->indicators, 1016 1074 sizeof(vcdev->indicators) * BITS_PER_BYTE) { 1017 1075 /* The bit clear must happen before the vring kick. */