s390/zcrypt: use new state UNBOUND during queue driver rebind
authorHarald Freudenberger <freude@linux.ibm.com>
Tue, 5 Feb 2019 16:22:36 +0000 (17:22 +0100)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Wed, 13 Feb 2019 07:27:44 +0000 (08:27 +0100)
When an alternate driver (vfio-ap) has bound an ap queue and this
binding is revised the ap queue device is in an intermittent
state not bound to any driver. The internal state variable
covered this with the state AP_STATE_BORKED which is also used to
reflect broken devices. When now an ap bus scan runs such a
device is destroyed and on the next scan reconstructed.

So a stress test with high frequency switching the queue driver
between the default and the vfio-ap driver hit this gap and the
queue was removed until the next ap bus scan. This fix now
introduces another state for the in-between condition for a queue
momentary not bound to a driver and so the ap bus scan function
skips this device instead of removing it.

Also some very slight but maybe helpful debug feature messages
come with this patch - in particular a message showing that a
broken card/queue device will get removed.

Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
drivers/s390/crypto/ap_bus.c
drivers/s390/crypto/ap_bus.h
drivers/s390/crypto/ap_queue.c

index 48ea0004a56da0dfe51c4251f0af62d0b4679a83..f07632da815eb08098bf7888053cf9c1367b77be 100644 (file)
@@ -1334,6 +1334,16 @@ static int __match_queue_device_with_qid(struct device *dev, void *data)
        return is_queue_dev(dev) && to_ap_queue(dev)->qid == (int)(long) data;
 }
 
+/*
+ * Helper function to be used with bus_find_dev
+ * matches any queue device with given queue id
+ */
+static int __match_queue_device_with_queue_id(struct device *dev, void *data)
+{
+       return is_queue_dev(dev)
+               && AP_QID_QUEUE(to_ap_queue(dev)->qid) == (int)(long) data;
+}
+
 /*
  * Helper function for ap_scan_bus().
  * Does the scan bus job for the given adapter id.
@@ -1434,8 +1444,13 @@ static void _ap_scan_bus_adapter(int id)
                                borked = aq->state == AP_STATE_BORKED;
                                spin_unlock_bh(&aq->lock);
                        }
-                       if (borked)     /* Remove broken device */
+                       if (borked) {
+                               /* Remove broken device */
+                               AP_DBF(DBF_DEBUG,
+                                      "removing broken queue=%02x.%04x\n",
+                                      id, dom);
                                device_unregister(dev);
+                       }
                        put_device(dev);
                        continue;
                }
@@ -1505,7 +1520,7 @@ static void ap_scan_bus(struct work_struct *unused)
                struct device *dev =
                        bus_find_device(&ap_bus_type, NULL,
                                        (void *)(long) ap_domain_index,
-                                       __match_queue_device_with_qid);
+                                       __match_queue_device_with_queue_id);
                if (dev)
                        put_device(dev);
                else
index bfc66e4a9de14de0fd4d4da97dedfd53f605ddea..d0059eae5d94bd51a5c677c28162ed63c9f0d437 100644 (file)
@@ -91,7 +91,8 @@ enum ap_state {
        AP_STATE_WORKING,
        AP_STATE_QUEUE_FULL,
        AP_STATE_SUSPEND_WAIT,
-       AP_STATE_BORKED,
+       AP_STATE_UNBOUND,       /* momentary not bound to a driver */
+       AP_STATE_BORKED,        /* broken */
        NR_AP_STATES
 };
 
index 576ac08777c509ee038a50ec95a892fc79776355..ba261210c6da0518fe7f8f4cb8f702b0503464b9 100644 (file)
@@ -420,6 +420,10 @@ static ap_func_t *ap_jumptable[NR_AP_STATES][NR_AP_EVENTS] = {
                [AP_EVENT_POLL] = ap_sm_suspend_read,
                [AP_EVENT_TIMEOUT] = ap_sm_nop,
        },
+       [AP_STATE_UNBOUND] = {
+               [AP_EVENT_POLL] = ap_sm_nop,
+               [AP_EVENT_TIMEOUT] = ap_sm_nop,
+       },
        [AP_STATE_BORKED] = {
                [AP_EVENT_POLL] = ap_sm_nop,
                [AP_EVENT_TIMEOUT] = ap_sm_nop,
@@ -725,6 +729,7 @@ static void __ap_flush_queue(struct ap_queue *aq)
                ap_msg->rc = -EAGAIN;
                ap_msg->receive(aq, ap_msg, NULL);
        }
+       aq->queue_count = 0;
 }
 
 void ap_flush_queue(struct ap_queue *aq)
@@ -743,7 +748,7 @@ void ap_queue_remove(struct ap_queue *aq)
        /* reset with zero, also clears irq registration */
        spin_lock_bh(&aq->lock);
        ap_zapq(aq->qid);
-       aq->state = AP_STATE_BORKED;
+       aq->state = AP_STATE_UNBOUND;
        spin_unlock_bh(&aq->lock);
 }
 EXPORT_SYMBOL(ap_queue_remove);