[S390] dasd: add support for irq statistics
[firefly-linux-kernel-4.4.55.git] / drivers / s390 / block / dasd.c
index 8373ca0de8e0b00484f40d48c5813e600da920c2..faa7d425cb9cbc1a2e363a248c1a743435791799 100644 (file)
@@ -11,6 +11,7 @@
 #define KMSG_COMPONENT "dasd"
 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
 
+#include <linux/kernel_stat.h>
 #include <linux/kmod.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
@@ -21,7 +22,6 @@
 #include <linux/hdreg.h>
 #include <linux/async.h>
 #include <linux/mutex.h>
-#include <linux/smp_lock.h>
 
 #include <asm/ccwdev.h>
 #include <asm/ebcdic.h>
@@ -1077,6 +1077,7 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
        unsigned long long now;
        int expires;
 
+       kstat_cpu(smp_processor_id()).irqs[IOINT_DAS]++;
        if (IS_ERR(irb)) {
                switch (PTR_ERR(irb)) {
                case -EIO:
@@ -1100,16 +1101,30 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
        cqr = (struct dasd_ccw_req *) intparm;
        if (!cqr || ((scsw_cc(&irb->scsw) == 1) &&
                     (scsw_fctl(&irb->scsw) & SCSW_FCTL_START_FUNC) &&
-                    (scsw_stctl(&irb->scsw) & SCSW_STCTL_STATUS_PEND))) {
+                    ((scsw_stctl(&irb->scsw) == SCSW_STCTL_STATUS_PEND) ||
+                     (scsw_stctl(&irb->scsw) == (SCSW_STCTL_STATUS_PEND |
+                                                 SCSW_STCTL_ALERT_STATUS))))) {
                if (cqr && cqr->status == DASD_CQR_IN_IO)
                        cqr->status = DASD_CQR_QUEUED;
+               if (cqr)
+                       memcpy(&cqr->irb, irb, sizeof(*irb));
                device = dasd_device_from_cdev_locked(cdev);
-               if (!IS_ERR(device)) {
-                       dasd_device_clear_timer(device);
-                       device->discipline->handle_unsolicited_interrupt(device,
-                                                                        irb);
+               if (IS_ERR(device))
+                       return;
+               /* ignore unsolicited interrupts for DIAG discipline */
+               if (device->discipline == dasd_diag_discipline_pointer) {
                        dasd_put_device(device);
+                       return;
                }
+               device->discipline->dump_sense_dbf(device, irb,
+                                                  "unsolicited");
+               if ((device->features & DASD_FEATURE_ERPLOG))
+                       device->discipline->dump_sense(device, cqr,
+                                                      irb);
+               dasd_device_clear_timer(device);
+               device->discipline->handle_unsolicited_interrupt(device,
+                                                                irb);
+               dasd_put_device(device);
                return;
        }
 
@@ -2197,7 +2212,6 @@ static void dasd_setup_queue(struct dasd_block *block)
         */
        blk_queue_max_segment_size(block->request_queue, PAGE_SIZE);
        blk_queue_segment_boundary(block->request_queue, PAGE_SIZE - 1);
-       blk_queue_ordered(block->request_queue, QUEUE_ORDERED_DRAIN);
 }
 
 /*
@@ -2236,7 +2250,6 @@ static int dasd_open(struct block_device *bdev, fmode_t mode)
        if (!block)
                return -ENODEV;
 
-       lock_kernel();
        base = block->base;
        atomic_inc(&block->open_count);
        if (test_bit(DASD_FLAG_OFFLINE, &base->flags)) {
@@ -2271,14 +2284,12 @@ static int dasd_open(struct block_device *bdev, fmode_t mode)
                goto out;
        }
 
-       unlock_kernel();
        return 0;
 
 out:
        module_put(base->discipline->owner);
 unlock:
        atomic_dec(&block->open_count);
-       unlock_kernel();
        return rc;
 }
 
@@ -2286,10 +2297,8 @@ static int dasd_release(struct gendisk *disk, fmode_t mode)
 {
        struct dasd_block *block = disk->private_data;
 
-       lock_kernel();
        atomic_dec(&block->open_count);
        module_put(block->base->discipline->owner);
-       unlock_kernel();
        return 0;
 }