]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] s390: steal lock support.
authorMartin Schwidefsky <schwidefsky@de.ibm.com>
Mon, 26 May 2003 06:34:45 +0000 (23:34 -0700)
committerLinus Torvalds <torvalds@home.transmeta.com>
Mon, 26 May 2003 06:34:45 +0000 (23:34 -0700)
cio: Add code to break a reservation of a device (steal lock).

drivers/s390/cio/device.c
drivers/s390/cio/device.h
drivers/s390/cio/device_fsm.c
drivers/s390/cio/device_ops.c
include/asm-s390/cio.h

index 55edfe588b9771eda3cd1ea2863e0b819020bb7d..6015e6aa34871f6690b763ff17bf4d33312f9d29 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/cio/device.c
  *  bus driver for ccw devices
- *   $Revision: 1.53 $
+ *   $Revision: 1.54 $
  *
  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
  *                      IBM Corporation
@@ -316,11 +316,63 @@ online_store (struct device *dev, const char *buf, size_t count)
        return count;
 }
 
+static void ccw_device_unbox_recog(void *data);
+
+static ssize_t
+stlck_store(struct device *dev, const char *buf, size_t count)
+{
+       struct ccw_device *cdev = to_ccwdev(dev);
+       int ret;
+
+       /* We don't care what was piped to the attribute 8) */
+       ret = ccw_device_stlck(cdev);
+       if (ret != 0) {
+               printk(KERN_WARNING
+                      "Unconditional reserve failed on device %s, rc=%d\n",
+                      dev->bus_id, ret);
+               return ret;
+       }
+
+       /*
+        * Device was successfully unboxed.
+        * Trigger removal of stlck attribute and device recognition.
+        */
+       INIT_WORK(&cdev->private->kick_work,
+                 ccw_device_unbox_recog, (void *) cdev);
+       queue_work(ccw_device_work, &cdev->private->kick_work);
+       
+       return 0;
+}
+
 static DEVICE_ATTR(chpids, 0444, chpids_show, NULL);
 static DEVICE_ATTR(pimpampom, 0444, pimpampom_show, NULL);
 static DEVICE_ATTR(devtype, 0444, devtype_show, NULL);
 static DEVICE_ATTR(cutype, 0444, cutype_show, NULL);
 static DEVICE_ATTR(online, 0644, online_show, online_store);
+static DEVICE_ATTR(steal_lock, 0200, NULL, stlck_store);
+
+/* A device has been unboxed. Start device recognition. */
+static void
+ccw_device_unbox_recog(void *data)
+{
+       struct ccw_device *cdev;
+
+       cdev = (struct ccw_device *)data;
+       if (!cdev)
+               return;
+
+       /* Remove stlck attribute. */
+       device_remove_file(&cdev->dev, &dev_attr_steal_lock);
+
+       spin_lock_irq(cdev->ccwlock);
+
+       /* Device is no longer boxed. */
+       cdev->private->state = DEV_STATE_NOT_OPER;
+
+       /* Finally start device recognition. */
+       ccw_device_recognition(cdev);
+       spin_unlock_irq(cdev->ccwlock);
+}
 
 static inline int
 subchannel_add_files (struct device *dev)
@@ -348,6 +400,19 @@ device_add_files (struct device *dev)
        return ret;
 }
 
+/*
+ * Add a "steal lock" attribute to boxed devices.
+ * This allows to trigger an unconditional reserve ccw to eckd dasds
+ * (if the device is something else, there should be no problems more than
+ * a command reject; we don't have any means of finding out the device's
+ * type if it was boxed at ipl/attach).
+ */
+void
+ccw_device_add_stlck(struct ccw_device *cdev)
+{
+       device_create_file(&cdev->dev, &dev_attr_steal_lock);
+}
+
 /* this is a simple abstraction for device_register that sets the
  * correct bus type and adds the bus specific files */
 static int
index 2df32741533f2c769ce2a196d754326cbd45bc12..965b747eee2468bc0431148cbe453f460698bbe6 100644 (file)
@@ -95,6 +95,9 @@ void ccw_device_disband_done(struct ccw_device *, int);
 
 void ccw_device_call_handler(struct ccw_device *);
 
+void ccw_device_add_stlck(struct ccw_device *);
+int ccw_device_stlck(struct ccw_device *);
+
 /* qdio needs this. */
 void ccw_device_set_timeout(struct ccw_device *, int);
 #endif
index 91ae97d63375b4824f4647d225c672a8a8e43cc2..d753f20661fdd719c54543f6f51b0af3e59a98a4 100644 (file)
@@ -132,6 +132,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
                CIO_DEBUG(KERN_WARNING, 2,
                          "SenseID : boxed device %04X on subchannel %04X\n",
                          sch->schib.pmcw.dev, sch->irq);
+               ccw_device_add_stlck(cdev);
                break;
        }
        io_subchannel_recog_done(cdev);
@@ -588,6 +589,29 @@ ccw_device_killing_timeout(struct ccw_device *cdev, enum dev_event dev_event)
                              ERR_PTR(-ETIMEDOUT));
 }
 
+static void
+ccw_device_stlck_done(struct ccw_device *cdev, enum dev_event dev_event)
+{
+       struct irb *irb;
+
+       switch (dev_event) {
+       case DEV_EVENT_INTERRUPT:
+               irb = (struct irb *) __LC_IRB;
+               /* Check for unsolicited interrupt. */
+               if (irb->scsw.stctl ==
+                   (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS))
+                       goto out_wakeup;
+
+               ccw_device_accumulate_irb(cdev, irb);
+               /* We don't care about basic sense etc. */
+               break;
+       default: /* timeout */
+               break;
+       }
+out_wakeup:
+       wake_up(&cdev->private->wait_q);
+}
+
 /*
  * No operation action. This is used e.g. to ignore a timeout event in
  * state offline.
@@ -662,8 +686,8 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
        },
        [DEV_STATE_BOXED] {
                [DEV_EVENT_NOTOPER]     ccw_device_offline_notoper,
-               [DEV_EVENT_INTERRUPT]   ccw_device_bug,
-               [DEV_EVENT_TIMEOUT]     ccw_device_nop,
+               [DEV_EVENT_INTERRUPT]   ccw_device_stlck_done,
+               [DEV_EVENT_TIMEOUT]     ccw_device_stlck_done,
                [DEV_EVENT_VERIFY]      ccw_device_nop,
        },
        /* states to wait for i/o completion before doing something */
index 1381c395586d37eb0dd10bbd98ea8e0530a2ca5e..181c8faf268e3d0849f27a3e16d0d89b85c811bb 100644 (file)
@@ -6,6 +6,7 @@
  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
  *                      IBM Corporation
  *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *               Cornelia Huck (cohuck@de.ibm.com)
  */
 #include <linux/config.h>
 #include <linux/module.h>
@@ -379,6 +380,52 @@ read_conf_data (struct ccw_device *cdev, void **buffer, int *length)
        return ret;
 }
 
+/*
+ * Try to issue an unconditional reserve on a boxed device.
+ */
+int
+ccw_device_stlck(struct ccw_device *cdev)
+{
+       char buf[32];
+       unsigned long flags;
+       struct subchannel *sch;
+       int ret;
+
+       if (!cdev)
+               return -ENODEV;
+
+       sch = to_subchannel(cdev->dev.parent);
+       
+       CIO_TRACE_EVENT(2, "stl lock");
+       CIO_TRACE_EVENT(2, cdev->dev.bus_id);
+
+       /* Setup ccw. This cmd code seems not to be in use elsewhere. */
+       cdev->private->iccws[0].cmd_code = CCW_CMD_STLCK;
+       cdev->private->iccws[0].cda = (__u32) __pa(buf);
+       cdev->private->iccws[0].count = 32;
+       cdev->private->iccws[0].flags = CCW_FLAG_SLI;
+
+       spin_lock_irqsave(&sch->lock, flags);
+       ret = cio_start(sch, cdev->private->iccws, 0xE2D3C3D2, 0);
+       spin_unlock_irqrestore(&sch->lock, flags);
+       if (ret)
+               return ret;
+
+       wait_event(cdev->private->wait_q, sch->schib.scsw.actl == 0);
+       spin_lock_irqsave(&sch->lock, flags);
+
+       if ((cdev->private->irb.scsw.dstat !=
+            (DEV_STAT_CHN_END|DEV_STAT_DEV_END)) ||
+           (cdev->private->irb.scsw.cstat != 0))
+               ret = -EIO;
+
+       /* Clear irb. */
+       memset(&cdev->private->irb, 0, sizeof(struct irb));
+       spin_unlock_irqrestore(&sch->lock, flags);
+
+       return ret;
+}
+
 // FIXME: these have to go:
 
 int
index 208de2e5822cef4574f6674f2d19df5658791127..096ec314bcab81a2df492bdd4b48d82bf719b3d7 100644 (file)
@@ -128,6 +128,7 @@ struct ccw1 {
 #define CCW_CMD_NOOP           0x03
 #define CCW_CMD_BASIC_SENSE    0x04
 #define CCW_CMD_TIC            0x08
+#define CCW_CMD_STLCK           0x14
 #define CCW_CMD_SENSE_PGID     0x34
 #define CCW_CMD_SUSPEND_RECONN 0x5B
 #define CCW_CMD_RDC            0x64