[S390] cio: unit check handling during internal I/O
authorMichael Ernst <mernst@de.ibm.com>
Wed, 26 May 2010 21:27:08 +0000 (23:27 +0200)
committerMartin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com>
Wed, 26 May 2010 21:27:09 +0000 (23:27 +0200)
Send unit checks that occur during internal I/O to the device driver
and react according to its return code.

Signed-off-by: Michael Ernst <mernst@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
arch/s390/include/asm/ccwdev.h
drivers/s390/cio/ccwreq.c

index f4bd346a52d3567e6a7b33885308b28e787cac2f..1c0030f9b890b7ff29c95c10db807d8ab4d92778 100644 (file)
@@ -91,6 +91,14 @@ struct ccw_device {
        void (*handler) (struct ccw_device *, unsigned long, struct irb *);
 };
 
+/*
+ * Possible CIO actions triggered by the unit check handler.
+ */
+enum uc_todo {
+       UC_TODO_RETRY,
+       UC_TODO_RETRY_ON_NEW_PATH,
+       UC_TODO_STOP
+};
 
 /**
  * struct ccw driver - device driver for channel attached devices
@@ -107,6 +115,7 @@ struct ccw_device {
  * @freeze: callback for freezing during hibernation snapshotting
  * @thaw: undo work done in @freeze
  * @restore: callback for restoring after hibernation
+ * @uc_handler: callback for unit check handler
  * @driver: embedded device driver structure
  * @name: device driver name
  */
@@ -124,6 +133,7 @@ struct ccw_driver {
        int (*freeze)(struct ccw_device *);
        int (*thaw) (struct ccw_device *);
        int (*restore)(struct ccw_device *);
+       enum uc_todo (*uc_handler) (struct ccw_device *, struct irb *);
        struct device_driver driver;
        char *name;
 };
index 37df42af05ec604112871912cc58d57f47d19f19..7f206ed44fdf79b41d771a203a8700c3a6ba07b4 100644 (file)
@@ -159,6 +159,7 @@ static enum io_status ccwreq_status(struct ccw_device *cdev, struct irb *lcirb)
 {
        struct irb *irb = &cdev->private->irb;
        struct cmd_scsw *scsw = &irb->scsw.cmd;
+       enum uc_todo todo;
 
        /* Perform BASIC SENSE if needed. */
        if (ccw_device_accumulate_and_sense(cdev, lcirb))
@@ -178,6 +179,20 @@ static enum io_status ccwreq_status(struct ccw_device *cdev, struct irb *lcirb)
                /* Check for command reject. */
                if (irb->ecw[0] & SNS0_CMD_REJECT)
                        return IO_REJECTED;
+               /* Ask the driver what to do */
+               if (cdev->drv && cdev->drv->uc_handler) {
+                       todo = cdev->drv->uc_handler(cdev, lcirb);
+                       switch (todo) {
+                       case UC_TODO_RETRY:
+                               return IO_STATUS_ERROR;
+                       case UC_TODO_RETRY_ON_NEW_PATH:
+                               return IO_PATH_ERROR;
+                       case UC_TODO_STOP:
+                               return IO_REJECTED;
+                       default:
+                               return IO_STATUS_ERROR;
+                       }
+               }
                /* Assume that unexpected SENSE data implies an error. */
                return IO_STATUS_ERROR;
        }