[PATCH] s390 (4/7): dasd driver.

From: Martin Schwidefsky (schwidefsky@de.ibm.com)
Date: Fri Jun 27 2003 - 10:06:29 EST


- Simplify long busy condition handling, add quiesce/resume ioctl.
- Add sense data area to reserve/release/steal_lock ccw-chains.

diffstat:
 drivers/s390/block/dasd.c | 43 +++++--------------------
 drivers/s390/block/dasd_3990_erp.c | 21 +++++-------
 drivers/s390/block/dasd_eckd.c | 62 +++++++++++++------------------------
 drivers/s390/block/dasd_erp.c | 51 ++++++++++--------------------
 drivers/s390/block/dasd_int.h | 10 ++++-
 drivers/s390/block/dasd_ioctl.c | 54 ++++++++++++++++++++++++++++++++
 include/asm-s390/dasd.h | 14 ++------
 7 files changed, 124 insertions(+), 131 deletions(-)

diff -urN linux-2.5/drivers/s390/block/dasd.c linux-2.5-s390/drivers/s390/block/dasd.c
--- linux-2.5/drivers/s390/block/dasd.c Sun Jun 22 20:32:43 2003
+++ linux-2.5-s390/drivers/s390/block/dasd.c Fri Jun 27 16:04:39 2003
@@ -7,7 +7,7 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
  *
- * $Revision: 1.99 $
+ * $Revision: 1.101 $
  */
 
 #include <linux/config.h>
@@ -32,7 +32,7 @@
 /*
  * SECTION: Constant definitions to be used within this file
  */
-#define DASD_CHANQ_MAX_SIZE 5
+#define DASD_CHANQ_MAX_SIZE 4
 
 /*
  * SECTION: exported variables of dasd.c
@@ -803,24 +803,18 @@
  * 2) delayed start of request where start_IO failed with -EBUSY
  * 3) timeout for missing state change interrupts
  * The head of the ccw queue will have status DASD_CQR_IN_IO for 1),
- * DASD_CQR_QUEUED for 2) and DASD_CQR_PENDING for 3).
+ * DASD_CQR_QUEUED for 2) and 3).
  */
 static void
 dasd_timeout_device(unsigned long ptr)
 {
         unsigned long flags;
         struct dasd_device *device;
- struct dasd_ccw_req *cqr;
 
         device = (struct dasd_device *) ptr;
         spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
         /* re-activate first request in queue */
- if (!list_empty(&device->ccw_queue)) {
- cqr = list_entry(device->ccw_queue.next,
- struct dasd_ccw_req, list);
- if (cqr->status == DASD_CQR_PENDING)
- cqr->status = DASD_CQR_QUEUED;
- }
+ device->stopped &= ~DASD_STOPPED_PENDING;
         spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
         dasd_schedule_bh(device);
 }
@@ -861,10 +855,6 @@
 
 /*
  * Handles the state change pending interrupt.
- * Search for the device related request queue and check if the first
- * cqr in queue in in status 'DASD_CQR_PENDING'.
- * If so the status is set to 'DASD_CQR_QUEUED' to reactivate
- * the device.
  */
 static void
 do_state_change_pending(void *data)
@@ -874,29 +864,12 @@
                 struct dasd_device *device;
         } *p;
         struct dasd_device *device;
- struct dasd_ccw_req *cqr;
 
         p = data;
         device = p->device;
         DBF_EVENT(DBF_NOTICE, "State change Interrupt for bus_id %s",
                   device->cdev->dev.bus_id);
-
- spin_lock_irq(get_ccwdev_lock(device->cdev));
- /* re-activate first request in queue */
- if (!list_empty(&device->ccw_queue)) {
- cqr = list_entry(device->ccw_queue.next,
- struct dasd_ccw_req, list);
- if (cqr == NULL) {
- MESSAGE (KERN_DEBUG,
- "got state change pending interrupt on"
- "an idle device: bus_id %s",
- device->cdev->dev.bus_id);
- return;
- }
- if (cqr->status == DASD_CQR_PENDING)
- cqr->status = DASD_CQR_QUEUED;
- }
- spin_unlock_irq(get_ccwdev_lock(device->cdev));
+ device->stopped &= ~DASD_STOPPED_PENDING;
         dasd_schedule_bh(device);
         dasd_put_device(device);
         kfree(p);
@@ -1036,7 +1009,8 @@
                 if (cqr->list.next != &device->ccw_queue) {
                         next = list_entry(cqr->list.next,
                                           struct dasd_ccw_req, list);
- if (next->status == DASD_CQR_QUEUED) {
+ if ((next->status == DASD_CQR_QUEUED) &&
+ (!device->stopped)) {
                                 if (device->discipline->start_IO(next) == 0)
                                         expires = next->expires;
                                 else
@@ -1264,7 +1238,8 @@
         if (list_empty(&device->ccw_queue))
                 return;
         cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list);
- if (cqr->status == DASD_CQR_QUEUED) {
+ if ((cqr->status == DASD_CQR_QUEUED) &&
+ (!device->stopped)) {
                 /* try to start the first I/O that can be started */
                 rc = device->discipline->start_IO(cqr);
                 if (rc == 0)
diff -urN linux-2.5/drivers/s390/block/dasd_3990_erp.c linux-2.5-s390/drivers/s390/block/dasd_3990_erp.c
--- linux-2.5/drivers/s390/block/dasd_3990_erp.c Sun Jun 22 20:33:12 2003
+++ linux-2.5-s390/drivers/s390/block/dasd_3990_erp.c Fri Jun 27 16:04:39 2003
@@ -5,7 +5,7 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000, 2001
  *
- * $Revision: 1.24 $
+ * $Revision: 1.25 $
  */
 
 #include <linux/timer.h>
@@ -221,13 +221,6 @@
  * Block the given device request queue to prevent from further
  * processing until the started timer has expired or an related
  * interrupt was received.
- *
- * PARAMETER
- * erp request to be blocked
- * expires time to wait until restart (in jiffies)
- *
- * RETURN VALUES
- * void
  */
 static void
 dasd_3990_erp_block_queue(struct dasd_ccw_req * erp, int expires)
@@ -238,7 +231,9 @@
         DEV_MESSAGE(KERN_INFO, device,
                     "blocking request queue for %is", expires);
 
- erp->status = DASD_CQR_PENDING;
+ device->stopped |= DASD_STOPPED_PENDING;
+ erp->status = DASD_CQR_QUEUED;
+
         dasd_set_timer(device, expires);
 }
 
@@ -453,9 +448,11 @@
 
                 if (sense[25] == 0x1D) { /* state change pending */
 
- DEV_MESSAGE(KERN_INFO, device, "%s",
- "waiting for state change pending " "int");
-
+ DEV_MESSAGE(KERN_INFO, device,
+ "waiting for state change pending "
+ "interrupt, %d retries left",
+ erp->retries);
+
                         dasd_3990_erp_block_queue(erp, 30*HZ);
 
                 } else {
diff -urN linux-2.5/drivers/s390/block/dasd_eckd.c linux-2.5-s390/drivers/s390/block/dasd_eckd.c
--- linux-2.5/drivers/s390/block/dasd_eckd.c Fri Jun 27 16:04:39 2003
+++ linux-2.5-s390/drivers/s390/block/dasd_eckd.c Fri Jun 27 16:04:39 2003
@@ -7,7 +7,7 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
  *
- * $Revision: 1.42 $
+ * $Revision: 1.46 $
  */
 
 #include <linux/config.h>
@@ -210,7 +210,7 @@
                 data->ep_sys_time = get_clock ();
                 
                 de_ccw->count = sizeof (struct DE_eckd_data);
- de_ccw->flags = CCW_FLAG_SLI;
+ de_ccw->flags |= CCW_FLAG_SLI;
         }
 
         return;
@@ -287,19 +287,11 @@
         /* check for sequential prestage - enhance cylinder range */
         if (data->attributes.operation == DASD_SEQ_PRESTAGE ||
             data->attributes.operation == DASD_SEQ_ACCESS) {
-
- if (end.cyl + private->attrib.nr_cyl < geo.cyl) {
+
+ if (end.cyl + private->attrib.nr_cyl < geo.cyl)
                         end.cyl += private->attrib.nr_cyl;
- DBF_DEV_EVENT(DBF_NOTICE, device,
- "Enhanced DE Cylinder from %x to %x",
- (totrk / geo.head), end.cyl);
- } else {
+ else
                         end.cyl = (geo.cyl - 1);
- DBF_DEV_EVENT(DBF_NOTICE, device,
- "Enhanced DE Cylinder from %x to "
- "End of device %x",
- (totrk / geo.head), end.cyl);
- }
         }
 
         data->beg_ext.cyl = beg.cyl;
@@ -518,12 +510,6 @@
                     private->rdc_data.cu_type,
                     private->rdc_data.cu_model.model);
         return 0;
-
- /* get characteristis via diag to determine the kind of
- * minidisk under VM needed beacause XRC is not support
- * by VM (jet). Can be removed as soon as VM supports XRC
- * FIXME: TBD ??? HUM
- */
 }
 
 static struct dasd_ccw_req *
@@ -1136,13 +1122,16 @@
                 return -ENODEV;
 
         cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
- 1, 0, device);
+ 1, 32, device);
         if (cqr == NULL) {
                 MESSAGE(KERN_WARNING, "%s",
                         "No memory to allocate initialization request");
                 return -ENOMEM;
         }
         cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RELEASE;
+ cqr->cpaddr->flags |= CCW_FLAG_SLI;
+ cqr->cpaddr->count = 32;
+ cqr->cpaddr->cda = (__u32)(addr_t) cqr->data;
         cqr->device = device;
         cqr->retries = 0;
         cqr->expires = 10 * HZ;
@@ -1151,14 +1140,14 @@
 
         rc = dasd_sleep_on_immediatly(cqr);
 
- dasd_kfree_request(cqr, cqr->device);
+ dasd_sfree_request(cqr, cqr->device);
         return rc;
 }
 
 /*
  * Reserve device ioctl.
  * Options are set to 'synchronous wait for interrupt' and
- * 'timeout the request'. This leads to an terminate IO if
+ * 'timeout the request'. This leads to a terminate IO if
  * the interrupt is outstanding for a certain time.
  */
 static int
@@ -1176,14 +1165,16 @@
                 return -ENODEV;
 
         cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
- 1, 0, device);
-
+ 1, 32, device);
         if (cqr == NULL) {
                 MESSAGE(KERN_WARNING, "%s",
                         "No memory to allocate initialization request");
                 return -ENOMEM;
         }
         cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RESERVE;
+ cqr->cpaddr->flags |= CCW_FLAG_SLI;
+ cqr->cpaddr->count = 32;
+ cqr->cpaddr->cda = (__u32)(addr_t) cqr->data;
         cqr->device = device;
         cqr->retries = 0;
         cqr->expires = 10 * HZ;
@@ -1192,11 +1183,7 @@
 
         rc = dasd_sleep_on_immediatly(cqr);
 
- if (rc == -EIO) {
- /* Request got an error or has been timed out. */
- dasd_eckd_release(bdev, no, args);
- }
- dasd_kfree_request(cqr, cqr->device);
+ dasd_sfree_request(cqr, cqr->device);
         return rc;
 }
 
@@ -1220,13 +1207,16 @@
                 return -ENODEV;
 
         cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
- 1, 0, device);
+ 1, 32, device);
         if (cqr == NULL) {
                 MESSAGE(KERN_WARNING, "%s",
                         "No memory to allocate initialization request");
                 return -ENOMEM;
         }
         cqr->cpaddr->cmd_code = DASD_ECKD_CCW_SLCK;
+ cqr->cpaddr->flags |= CCW_FLAG_SLI;
+ cqr->cpaddr->count = 32;
+ cqr->cpaddr->cda = (__u32)(addr_t) cqr->data;
         cqr->device = device;
         cqr->retries = 0;
         cqr->expires = 10 * HZ;
@@ -1235,11 +1225,7 @@
 
         rc = dasd_sleep_on_immediatly(cqr);
 
- if (rc == -EIO) {
- /* Request got an error or has been timed out. */
- dasd_eckd_release(bdev, no, args);
- }
- dasd_kfree_request(cqr, cqr->device);
+ dasd_sfree_request(cqr, cqr->device);
         return rc;
 }
 
@@ -1336,17 +1322,13 @@
 
         private = (struct dasd_eckd_private *) device->private;
 
- DBF_DEV_EVENT(DBF_ERR, device,
- "cache operation mode got "
- "%x (%i cylinder prestage)",
- attrib.operation, attrib.nr_cyl);
-
         private->attrib = attrib;
 
         DBF_DEV_EVENT(DBF_ERR, device,
                       "cache operation mode set to "
                       "%x (%i cylinder prestage)",
                       private->attrib.operation, private->attrib.nr_cyl);
+
         return 0;
 }
 
diff -urN linux-2.5/drivers/s390/block/dasd_erp.c linux-2.5-s390/drivers/s390/block/dasd_erp.c
--- linux-2.5/drivers/s390/block/dasd_erp.c Sun Jun 22 20:32:33 2003
+++ linux-2.5-s390/drivers/s390/block/dasd_erp.c Fri Jun 27 16:04:39 2003
@@ -7,7 +7,7 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
  *
- * $Revision: 1.9 $
+ * $Revision: 1.10 $
  */
 
 #include <linux/config.h>
@@ -86,48 +86,31 @@
         atomic_dec(&device->ref_count);
 }
 
+
 /*
- * DESCRIPTION
- * sets up the default-ERP struct dasd_ccw_req, namely one, which performs
- * a TIC to the original channel program with a retry counter of 16
- *
- * PARAMETER
- * cqr failed CQR
- *
- * RETURN VALUES
- * erp CQR performing the ERP
+ * dasd_default_erp_action just retries the current cqr
  */
 struct dasd_ccw_req *
 dasd_default_erp_action(struct dasd_ccw_req * cqr)
 {
         struct dasd_device *device;
- struct dasd_ccw_req *erp;
 
- MESSAGE(KERN_DEBUG, "%s", "Default ERP called... ");
         device = cqr->device;
- erp = dasd_alloc_erp_request((char *) &cqr->magic, 1, 0, device);
- if (IS_ERR(erp)) {
- DEV_MESSAGE(KERN_ERR, device, "%s",
- "Unable to allocate request for default ERP");
- cqr->status = DASD_CQR_FAILED;
- cqr->stopclk = get_clock();
- return cqr;
- }
-
- erp->cpaddr->cmd_code = CCW_CMD_TIC;
- erp->cpaddr->cda = (__u32) (addr_t) cqr->cpaddr;
- erp->function = dasd_default_erp_action;
- erp->refers = cqr;
- erp->device = device;
- erp->magic = cqr->magic;
- erp->retries = 16;
- erp->status = DASD_CQR_FILLED;
-
- list_add(&erp->list, &device->ccw_queue);
- erp->status = DASD_CQR_QUEUED;
-
- return erp;
 
+ /* just retry - there is nothing to save ... I got no sense data.... */
+ if (cqr->retries > 0) {
+ DEV_MESSAGE (KERN_DEBUG, device,
+ "default ERP called (%i retries left)",
+ cqr->retries);
+ cqr->status = DASD_CQR_QUEUED;
+ } else {
+ DEV_MESSAGE (KERN_WARNING, device, "%s",
+ "default ERP called (NO retry left)");
+
+ cqr->status = DASD_CQR_FAILED;
+ cqr->stopclk = get_clock ();
+ }
+ return cqr;
 } /* end dasd_default_erp_action */
 
 /*
diff -urN linux-2.5/drivers/s390/block/dasd_int.h linux-2.5-s390/drivers/s390/block/dasd_int.h
--- linux-2.5/drivers/s390/block/dasd_int.h Sun Jun 22 20:33:01 2003
+++ linux-2.5-s390/drivers/s390/block/dasd_int.h Fri Jun 27 16:04:39 2003
@@ -6,7 +6,7 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
  *
- * $Revision: 1.40 $
+ * $Revision: 1.42 $
  */
 
 #ifndef DASD_INT_H
@@ -188,7 +188,6 @@
 #define DASD_CQR_DONE 0x03 /* request is completed successfully */
 #define DASD_CQR_ERROR 0x04 /* request is completed with error */
 #define DASD_CQR_FAILED 0x05 /* request is finally failed */
-#define DASD_CQR_PENDING 0x06 /* request is waiting for interrupt - ERP only */
 
 /* Signature for error recovery functions. */
 typedef struct dasd_ccw_req *(*dasd_erp_fn_t) (struct dasd_ccw_req *);
@@ -279,6 +278,7 @@
 
         /* Device state and target state. */
         int state, target;
+ int stopped; /* device (ccw_device_start) was stopped */
 
         /* Open and reference count. */
         atomic_t ref_count;
@@ -306,6 +306,12 @@
 #endif
 };
 
+/* reasons why device (ccw_device_start) was stopped */
+#define DASD_STOPPED_NOT_ACC 1 /* not accessible */
+#define DASD_STOPPED_QUIESCE 2 /* Quiesced */
+#define DASD_STOPPED_PENDING 4 /* long busy */
+
+
 void dasd_put_device_wake(struct dasd_device *);
 
 /*
diff -urN linux-2.5/drivers/s390/block/dasd_ioctl.c linux-2.5-s390/drivers/s390/block/dasd_ioctl.c
--- linux-2.5/drivers/s390/block/dasd_ioctl.c Sun Jun 22 20:32:56 2003
+++ linux-2.5-s390/drivers/s390/block/dasd_ioctl.c Fri Jun 27 16:04:39 2003
@@ -169,6 +169,58 @@
 }
 
 /*
+ * Quiesce device.
+ */
+static int
+dasd_ioctl_quiesce(struct block_device *bdev, int no, long args)
+{
+ struct dasd_device *device;
+ unsigned long flags;
+
+ if (!capable (CAP_SYS_ADMIN))
+ return -EACCES;
+
+ device = bdev->bd_disk->private_data;
+ if (device == NULL)
+ return -ENODEV;
+
+ DEV_MESSAGE (KERN_DEBUG, device, "%s",
+ "Quiesce IO on device");
+ spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+ device->stopped |= DASD_STOPPED_QUIESCE;
+ spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
+ return 0;
+}
+
+
+/*
+ * Quiesce device.
+ */
+static int
+dasd_ioctl_resume(struct block_device *bdev, int no, long args)
+{
+ struct dasd_device *device;
+ unsigned long flags;
+
+ if (!capable (CAP_SYS_ADMIN))
+ return -EACCES;
+
+ device = bdev->bd_disk->private_data;
+ if (device == NULL)
+ return -ENODEV;
+
+ DEV_MESSAGE (KERN_DEBUG, device, "%s",
+ "resume IO on device");
+
+ spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+ device->stopped &= ~DASD_STOPPED_QUIESCE;
+ spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
+
+ dasd_schedule_bh (device);
+ return 0;
+}
+
+/*
  * performs formatting of _device_ according to _fdata_
  * Note: The discipline's format_function is assumed to deliver formatting
  * commands to format a single unit of the device. In terms of the ECKD
@@ -438,6 +490,8 @@
 {
         { BIODASDDISABLE, dasd_ioctl_disable },
         { BIODASDENABLE, dasd_ioctl_enable },
+ { BIODASDQUIESCE, dasd_ioctl_quiesce },
+ { BIODASDRESUME, dasd_ioctl_resume },
         { BIODASDFMT, dasd_ioctl_format },
         { BIODASDINFO, dasd_ioctl_information },
         { BIODASDINFO2, dasd_ioctl_information },
diff -urN linux-2.5/include/asm-s390/dasd.h linux-2.5-s390/include/asm-s390/dasd.h
--- linux-2.5/include/asm-s390/dasd.h Sun Jun 22 20:32:34 2003
+++ linux-2.5-s390/include/asm-s390/dasd.h Fri Jun 27 16:04:39 2003
@@ -8,16 +8,8 @@
  * any future changes wrt the API will result in a change of the APIVERSION reported
  * to userspace by the DASDAPIVER-ioctl
  *
- * $Revision: 1.3 $
+ * $Revision: 1.4 $
  *
- * History of changes (starts July 2000)
- * 05/04/01 created by moving the kernel interface to drivers/s390/block/dasd_int.h
- * 12/06/01 DASD_API_VERSION 2 - binary compatible to 0 (new BIODASDINFO2)
- * 01/23/02 DASD_API_VERSION 3 - added BIODASDPSRD (and BIODASDENAPAV) IOCTL
- * 02/15/02 DASD_API_VERSION 4 - added BIODASDSATTR IOCTL
- * ##/##/## DASD_API_VERSION 5 - added boxed dasd support TOBEDONE
- * 21/06/02 DASD_API_VERSION 6 - fixed HDIO_GETGEO: geo.start is in sectors!
- *
  */
 
 #ifndef DASD_H
@@ -226,6 +218,10 @@
 #define BIODASDSLCK _IO(DASD_IOCTL_LETTER,4) /* steal lock */
 /* reset profiling information of a device */
 #define BIODASDPRRST _IO(DASD_IOCTL_LETTER,5)
+/* Quiesce IO on device */
+#define BIODASDQUIESCE _IO(DASD_IOCTL_LETTER,6)
+/* Resume IO on device */
+#define BIODASDRESUME _IO(DASD_IOCTL_LETTER,7)
 
 
 /* retrieve API version number */
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Mon Jun 30 2003 - 22:00:26 EST