]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/s390/cio/device_status.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux...
[linux-2.6-omap-h63xx.git] / drivers / s390 / cio / device_status.c
index bdcf930f7beb120a636565f461ac32c9e9c6b9c0..4a38993000f2123d5e104af71ffa5ad0bcd2cd59 100644 (file)
 #include "css.h"
 #include "device.h"
 #include "ioasm.h"
+#include "io_sch.h"
 
 /*
  * Check for any kind of channel or interface control check but don't
  * issue the message for the console device
  */
-static inline void
+static void
 ccw_device_msg_control_check(struct ccw_device *cdev, struct irb *irb)
 {
        if (!(irb->scsw.cstat & (SCHN_STAT_CHN_DATA_CHK |
@@ -61,7 +62,7 @@ ccw_device_path_notoper(struct ccw_device *cdev)
        stsch (sch->schid, &sch->schib);
 
        CIO_MSG_EVENT(0, "%s(0.%x.%04x) - path(s) %02x are "
-                     "not operational \n", __FUNCTION__,
+                     "not operational \n", __func__,
                      sch->schid.ssid, sch->schid.sch_no,
                      sch->schib.pmcw.pnom);
 
@@ -72,7 +73,7 @@ ccw_device_path_notoper(struct ccw_device *cdev)
 /*
  * Copy valid bits from the extended control word to device irb.
  */
-static inline void
+static void
 ccw_device_accumulate_ecw(struct ccw_device *cdev, struct irb *irb)
 {
        /*
@@ -94,7 +95,7 @@ ccw_device_accumulate_ecw(struct ccw_device *cdev, struct irb *irb)
 /*
  * Check if extended status word is valid.
  */
-static inline int
+static int
 ccw_device_accumulate_esw_valid(struct irb *irb)
 {
        if (!irb->scsw.eswf && irb->scsw.stctl == SCSW_STCTL_STATUS_PEND)
@@ -109,7 +110,7 @@ ccw_device_accumulate_esw_valid(struct irb *irb)
 /*
  * Copy valid bits from the extended status word to device irb.
  */
-static inline void
+static void
 ccw_device_accumulate_esw(struct ccw_device *cdev, struct irb *irb)
 {
        struct irb *cdev_irb;
@@ -221,6 +222,14 @@ ccw_device_accumulate_irb(struct ccw_device *cdev, struct irb *irb)
 
        cdev_irb = &cdev->private->irb;
 
+       /*
+        * If the clear function had been performed, all formerly pending
+        * status at the subchannel has been cleared and we must not pass
+        * intermediate accumulated status to the device driver.
+        */
+       if (irb->scsw.fctl & SCSW_FCTL_CLEAR_FUNC)
+               memset(&cdev->private->irb, 0, sizeof(struct irb));
+
        /* Copy bits which are valid only for the start function. */
        if (irb->scsw.fctl & SCSW_FCTL_START_FUNC) {
                /* Copy key. */
@@ -263,7 +272,11 @@ ccw_device_accumulate_irb(struct ccw_device *cdev, struct irb *irb)
                cdev_irb->scsw.cpa = irb->scsw.cpa;
        /* Accumulate device status, but not the device busy flag. */
        cdev_irb->scsw.dstat &= ~DEV_STAT_BUSY;
-       cdev_irb->scsw.dstat |= irb->scsw.dstat;
+       /* dstat is not always valid. */
+       if (irb->scsw.stctl &
+           (SCSW_STCTL_PRIM_STATUS | SCSW_STCTL_SEC_STATUS
+            | SCSW_STCTL_INTER_STATUS | SCSW_STCTL_ALERT_STATUS))
+               cdev_irb->scsw.dstat |= irb->scsw.dstat;
        /* Accumulate subchannel status. */
        cdev_irb->scsw.cstat |= irb->scsw.cstat;
        /* Copy residual count if it is valid. */
@@ -298,6 +311,8 @@ int
 ccw_device_do_sense(struct ccw_device *cdev, struct irb *irb)
 {
        struct subchannel *sch;
+       struct ccw1 *sense_ccw;
+       int rc;
 
        sch = to_subchannel(cdev->dev.parent);
 
@@ -314,15 +329,19 @@ ccw_device_do_sense(struct ccw_device *cdev, struct irb *irb)
        /*
         * We have ending status but no sense information. Do a basic sense.
         */
-       sch->sense_ccw.cmd_code = CCW_CMD_BASIC_SENSE;
-       sch->sense_ccw.cda = (__u32) __pa(cdev->private->irb.ecw);
-       sch->sense_ccw.count = SENSE_MAX_COUNT;
-       sch->sense_ccw.flags = CCW_FLAG_SLI;
+       sense_ccw = &to_io_private(sch)->sense_ccw;
+       sense_ccw->cmd_code = CCW_CMD_BASIC_SENSE;
+       sense_ccw->cda = (__u32) __pa(cdev->private->irb.ecw);
+       sense_ccw->count = SENSE_MAX_COUNT;
+       sense_ccw->flags = CCW_FLAG_SLI;
 
        /* Reset internal retry indication. */
        cdev->private->flags.intretry = 0;
 
-       return cio_start (sch, &sch->sense_ccw, 0xff);
+       rc = cio_start(sch, sense_ccw, 0xff);
+       if (rc == -ENODEV || rc == -EACCES)
+               dev_fsm_event(cdev, DEV_EVENT_VERIFY);
+       return rc;
 }
 
 /*