]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
s390/cio: Do not unregister the subchannel based on DNV
authorVineeth Vijayan <vneethv@linux.ibm.com>
Mon, 23 Sep 2024 20:16:43 +0000 (22:16 +0200)
committerHeiko Carstens <hca@linux.ibm.com>
Fri, 25 Oct 2024 14:03:23 +0000 (16:03 +0200)
Starting with commit 2297791c92d0 ("s390/cio: dont unregister
subchannel from child-drivers"), CIO does not unregister subchannels
when the attached device is invalid or unavailable. Instead, it
allows subchannels to exist without a connected device. However, if
the DNV value is 0, such as, when all the CHPIDs of a subchannel are
configured in standby state, the subchannel is unregistered, which
contradicts the current subchannel specification.

Update the logic so that subchannels are not unregistered based
on the DNV value. Also update the SCHIB information even if the
DNV bit is zero.

Suggested-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Fixes: 2297791c92d0 ("s390/cio: dont unregister subchannel from child-drivers")
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
drivers/s390/cio/cio.c
drivers/s390/cio/device.c

index c32e818f06dbadbf103a3c487769a7b152f4713f..ad17ab0a931494dec03f293e1c037e46516c32f5 100644 (file)
@@ -459,10 +459,14 @@ int cio_update_schib(struct subchannel *sch)
 {
        struct schib schib;
 
-       if (stsch(sch->schid, &schib) || !css_sch_is_valid(&schib))
+       if (stsch(sch->schid, &schib))
                return -ENODEV;
 
        memcpy(&sch->schib, &schib, sizeof(schib));
+
+       if (!css_sch_is_valid(&schib))
+               return -EACCES;
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(cio_update_schib);
index b0f23242e1714593fffa895e1ad08a79e8b3955d..9498825d9c7a5cb7ebfcf6e09973a1e6e405f187 100644 (file)
@@ -1387,14 +1387,18 @@ enum io_sch_action {
        IO_SCH_VERIFY,
        IO_SCH_DISC,
        IO_SCH_NOP,
+       IO_SCH_ORPH_CDEV,
 };
 
 static enum io_sch_action sch_get_action(struct subchannel *sch)
 {
        struct ccw_device *cdev;
+       int rc;
 
        cdev = sch_get_cdev(sch);
-       if (cio_update_schib(sch)) {
+       rc = cio_update_schib(sch);
+
+       if (rc == -ENODEV) {
                /* Not operational. */
                if (!cdev)
                        return IO_SCH_UNREG;
@@ -1402,6 +1406,16 @@ static enum io_sch_action sch_get_action(struct subchannel *sch)
                        return IO_SCH_UNREG;
                return IO_SCH_ORPH_UNREG;
        }
+
+       /* Avoid unregistering subchannels without working device. */
+       if (rc == -EACCES) {
+               if (!cdev)
+                       return IO_SCH_NOP;
+               if (ccw_device_notify(cdev, CIO_GONE) != NOTIFY_OK)
+                       return IO_SCH_UNREG_CDEV;
+               return IO_SCH_ORPH_CDEV;
+       }
+
        /* Operational. */
        if (!cdev)
                return IO_SCH_ATTACH;
@@ -1471,6 +1485,7 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process)
                rc = 0;
                goto out_unlock;
        case IO_SCH_ORPH_UNREG:
+       case IO_SCH_ORPH_CDEV:
        case IO_SCH_ORPH_ATTACH:
                ccw_device_set_disconnected(cdev);
                break;
@@ -1502,6 +1517,7 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process)
        /* Handle attached ccw device. */
        switch (action) {
        case IO_SCH_ORPH_UNREG:
+       case IO_SCH_ORPH_CDEV:
        case IO_SCH_ORPH_ATTACH:
                /* Move ccw device to orphanage. */
                rc = ccw_device_move_to_orph(cdev);