Commit 6779477a authored by Martin Schwidefsky's avatar Martin Schwidefsky Committed by Linus Torvalds

[PATCH] s390: dasd driver.

- Simplify long busy condition handling, add quiesce/resume ioctl.
- Add sense data area to reserve/release/steal_lock ccw-chains.
parent 2f7b411b
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Bugreports.to..: <Linux390@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
* *
* $Revision: 1.99 $ * $Revision: 1.101 $
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
/* /*
* SECTION: Constant definitions to be used within this file * 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 * SECTION: exported variables of dasd.c
...@@ -803,24 +803,18 @@ dasd_start_IO(struct dasd_ccw_req * cqr) ...@@ -803,24 +803,18 @@ dasd_start_IO(struct dasd_ccw_req * cqr)
* 2) delayed start of request where start_IO failed with -EBUSY * 2) delayed start of request where start_IO failed with -EBUSY
* 3) timeout for missing state change interrupts * 3) timeout for missing state change interrupts
* The head of the ccw queue will have status DASD_CQR_IN_IO for 1), * 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 static void
dasd_timeout_device(unsigned long ptr) dasd_timeout_device(unsigned long ptr)
{ {
unsigned long flags; unsigned long flags;
struct dasd_device *device; struct dasd_device *device;
struct dasd_ccw_req *cqr;
device = (struct dasd_device *) ptr; device = (struct dasd_device *) ptr;
spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
/* re-activate first request in queue */ /* re-activate first request in queue */
if (!list_empty(&device->ccw_queue)) { device->stopped &= ~DASD_STOPPED_PENDING;
cqr = list_entry(device->ccw_queue.next,
struct dasd_ccw_req, list);
if (cqr->status == DASD_CQR_PENDING)
cqr->status = DASD_CQR_QUEUED;
}
spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
dasd_schedule_bh(device); dasd_schedule_bh(device);
} }
...@@ -861,10 +855,6 @@ dasd_clear_timer(struct dasd_device *device) ...@@ -861,10 +855,6 @@ dasd_clear_timer(struct dasd_device *device)
/* /*
* Handles the state change pending interrupt. * 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 static void
do_state_change_pending(void *data) do_state_change_pending(void *data)
...@@ -874,29 +864,12 @@ do_state_change_pending(void *data) ...@@ -874,29 +864,12 @@ do_state_change_pending(void *data)
struct dasd_device *device; struct dasd_device *device;
} *p; } *p;
struct dasd_device *device; struct dasd_device *device;
struct dasd_ccw_req *cqr;
p = data; p = data;
device = p->device; device = p->device;
DBF_EVENT(DBF_NOTICE, "State change Interrupt for bus_id %s", DBF_EVENT(DBF_NOTICE, "State change Interrupt for bus_id %s",
device->cdev->dev.bus_id); device->cdev->dev.bus_id);
device->stopped &= ~DASD_STOPPED_PENDING;
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));
dasd_schedule_bh(device); dasd_schedule_bh(device);
dasd_put_device(device); dasd_put_device(device);
kfree(p); kfree(p);
...@@ -1036,7 +1009,8 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, ...@@ -1036,7 +1009,8 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
if (cqr->list.next != &device->ccw_queue) { if (cqr->list.next != &device->ccw_queue) {
next = list_entry(cqr->list.next, next = list_entry(cqr->list.next,
struct dasd_ccw_req, list); 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) if (device->discipline->start_IO(next) == 0)
expires = next->expires; expires = next->expires;
else else
...@@ -1264,7 +1238,8 @@ __dasd_start_head(struct dasd_device * device) ...@@ -1264,7 +1238,8 @@ __dasd_start_head(struct dasd_device * device)
if (list_empty(&device->ccw_queue)) if (list_empty(&device->ccw_queue))
return; return;
cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list); 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 */ /* try to start the first I/O that can be started */
rc = device->discipline->start_IO(cqr); rc = device->discipline->start_IO(cqr);
if (rc == 0) if (rc == 0)
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* Bugreports.to..: <Linux390@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000, 2001 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000, 2001
* *
* $Revision: 1.24 $ * $Revision: 1.25 $
*/ */
#include <linux/timer.h> #include <linux/timer.h>
...@@ -221,13 +221,6 @@ dasd_3990_erp_cleanup(struct dasd_ccw_req * erp, char final_status) ...@@ -221,13 +221,6 @@ dasd_3990_erp_cleanup(struct dasd_ccw_req * erp, char final_status)
* Block the given device request queue to prevent from further * Block the given device request queue to prevent from further
* processing until the started timer has expired or an related * processing until the started timer has expired or an related
* interrupt was received. * interrupt was received.
*
* PARAMETER
* erp request to be blocked
* expires time to wait until restart (in jiffies)
*
* RETURN VALUES
* void
*/ */
static void static void
dasd_3990_erp_block_queue(struct dasd_ccw_req * erp, int expires) dasd_3990_erp_block_queue(struct dasd_ccw_req * erp, int expires)
...@@ -238,7 +231,9 @@ dasd_3990_erp_block_queue(struct dasd_ccw_req * erp, int expires) ...@@ -238,7 +231,9 @@ dasd_3990_erp_block_queue(struct dasd_ccw_req * erp, int expires)
DEV_MESSAGE(KERN_INFO, device, DEV_MESSAGE(KERN_INFO, device,
"blocking request queue for %is", expires); "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); dasd_set_timer(device, expires);
} }
...@@ -453,9 +448,11 @@ dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense) ...@@ -453,9 +448,11 @@ dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense)
if (sense[25] == 0x1D) { /* state change pending */ if (sense[25] == 0x1D) { /* state change pending */
DEV_MESSAGE(KERN_INFO, device, "%s", DEV_MESSAGE(KERN_INFO, device,
"waiting for state change pending " "int"); "waiting for state change pending "
"interrupt, %d retries left",
erp->retries);
dasd_3990_erp_block_queue(erp, 30*HZ); dasd_3990_erp_block_queue(erp, 30*HZ);
} else { } else {
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Bugreports.to..: <Linux390@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
* *
* $Revision: 1.42 $ * $Revision: 1.46 $
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -210,7 +210,7 @@ check_XRC (struct ccw1 *de_ccw, ...@@ -210,7 +210,7 @@ check_XRC (struct ccw1 *de_ccw,
data->ep_sys_time = get_clock (); data->ep_sys_time = get_clock ();
de_ccw->count = sizeof (struct DE_eckd_data); de_ccw->count = sizeof (struct DE_eckd_data);
de_ccw->flags = CCW_FLAG_SLI; de_ccw->flags |= CCW_FLAG_SLI;
} }
return; return;
...@@ -287,19 +287,11 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk, ...@@ -287,19 +287,11 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
/* check for sequential prestage - enhance cylinder range */ /* check for sequential prestage - enhance cylinder range */
if (data->attributes.operation == DASD_SEQ_PRESTAGE || if (data->attributes.operation == DASD_SEQ_PRESTAGE ||
data->attributes.operation == DASD_SEQ_ACCESS) { 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; end.cyl += private->attrib.nr_cyl;
DBF_DEV_EVENT(DBF_NOTICE, device, else
"Enhanced DE Cylinder from %x to %x",
(totrk / geo.head), end.cyl);
} else {
end.cyl = (geo.cyl - 1); 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; data->beg_ext.cyl = beg.cyl;
...@@ -518,12 +510,6 @@ dasd_eckd_check_characteristics(struct dasd_device *device) ...@@ -518,12 +510,6 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
private->rdc_data.cu_type, private->rdc_data.cu_type,
private->rdc_data.cu_model.model); private->rdc_data.cu_model.model);
return 0; 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 * static struct dasd_ccw_req *
...@@ -1136,13 +1122,16 @@ dasd_eckd_release(struct block_device *bdev, int no, long args) ...@@ -1136,13 +1122,16 @@ dasd_eckd_release(struct block_device *bdev, int no, long args)
return -ENODEV; return -ENODEV;
cqr = dasd_smalloc_request(dasd_eckd_discipline.name, cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
1, 0, device); 1, 32, device);
if (cqr == NULL) { if (cqr == NULL) {
MESSAGE(KERN_WARNING, "%s", MESSAGE(KERN_WARNING, "%s",
"No memory to allocate initialization request"); "No memory to allocate initialization request");
return -ENOMEM; return -ENOMEM;
} }
cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RELEASE; 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->device = device;
cqr->retries = 0; cqr->retries = 0;
cqr->expires = 10 * HZ; cqr->expires = 10 * HZ;
...@@ -1151,14 +1140,14 @@ dasd_eckd_release(struct block_device *bdev, int no, long args) ...@@ -1151,14 +1140,14 @@ dasd_eckd_release(struct block_device *bdev, int no, long args)
rc = dasd_sleep_on_immediatly(cqr); rc = dasd_sleep_on_immediatly(cqr);
dasd_kfree_request(cqr, cqr->device); dasd_sfree_request(cqr, cqr->device);
return rc; return rc;
} }
/* /*
* Reserve device ioctl. * Reserve device ioctl.
* Options are set to 'synchronous wait for interrupt' and * 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. * the interrupt is outstanding for a certain time.
*/ */
static int static int
...@@ -1176,14 +1165,16 @@ dasd_eckd_reserve(struct block_device *bdev, int no, long args) ...@@ -1176,14 +1165,16 @@ dasd_eckd_reserve(struct block_device *bdev, int no, long args)
return -ENODEV; return -ENODEV;
cqr = dasd_smalloc_request(dasd_eckd_discipline.name, cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
1, 0, device); 1, 32, device);
if (cqr == NULL) { if (cqr == NULL) {
MESSAGE(KERN_WARNING, "%s", MESSAGE(KERN_WARNING, "%s",
"No memory to allocate initialization request"); "No memory to allocate initialization request");
return -ENOMEM; return -ENOMEM;
} }
cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RESERVE; 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->device = device;
cqr->retries = 0; cqr->retries = 0;
cqr->expires = 10 * HZ; cqr->expires = 10 * HZ;
...@@ -1192,11 +1183,7 @@ dasd_eckd_reserve(struct block_device *bdev, int no, long args) ...@@ -1192,11 +1183,7 @@ dasd_eckd_reserve(struct block_device *bdev, int no, long args)
rc = dasd_sleep_on_immediatly(cqr); rc = dasd_sleep_on_immediatly(cqr);
if (rc == -EIO) { dasd_sfree_request(cqr, cqr->device);
/* Request got an error or has been timed out. */
dasd_eckd_release(bdev, no, args);
}
dasd_kfree_request(cqr, cqr->device);
return rc; return rc;
} }
...@@ -1220,13 +1207,16 @@ dasd_eckd_steal_lock(struct block_device *bdev, int no, long args) ...@@ -1220,13 +1207,16 @@ dasd_eckd_steal_lock(struct block_device *bdev, int no, long args)
return -ENODEV; return -ENODEV;
cqr = dasd_smalloc_request(dasd_eckd_discipline.name, cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
1, 0, device); 1, 32, device);
if (cqr == NULL) { if (cqr == NULL) {
MESSAGE(KERN_WARNING, "%s", MESSAGE(KERN_WARNING, "%s",
"No memory to allocate initialization request"); "No memory to allocate initialization request");
return -ENOMEM; return -ENOMEM;
} }
cqr->cpaddr->cmd_code = DASD_ECKD_CCW_SLCK; 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->device = device;
cqr->retries = 0; cqr->retries = 0;
cqr->expires = 10 * HZ; cqr->expires = 10 * HZ;
...@@ -1235,11 +1225,7 @@ dasd_eckd_steal_lock(struct block_device *bdev, int no, long args) ...@@ -1235,11 +1225,7 @@ dasd_eckd_steal_lock(struct block_device *bdev, int no, long args)
rc = dasd_sleep_on_immediatly(cqr); rc = dasd_sleep_on_immediatly(cqr);
if (rc == -EIO) { dasd_sfree_request(cqr, cqr->device);
/* Request got an error or has been timed out. */
dasd_eckd_release(bdev, no, args);
}
dasd_kfree_request(cqr, cqr->device);
return rc; return rc;
} }
...@@ -1336,17 +1322,13 @@ dasd_eckd_set_attrib(struct block_device *bdev, int no, long args) ...@@ -1336,17 +1322,13 @@ dasd_eckd_set_attrib(struct block_device *bdev, int no, long args)
private = (struct dasd_eckd_private *) device->private; 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; private->attrib = attrib;
DBF_DEV_EVENT(DBF_ERR, device, DBF_DEV_EVENT(DBF_ERR, device,
"cache operation mode set to " "cache operation mode set to "
"%x (%i cylinder prestage)", "%x (%i cylinder prestage)",
private->attrib.operation, private->attrib.nr_cyl); private->attrib.operation, private->attrib.nr_cyl);
return 0; return 0;
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Bugreports.to..: <Linux390@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
* *
* $Revision: 1.9 $ * $Revision: 1.10 $
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -86,48 +86,31 @@ dasd_free_erp_request(struct dasd_ccw_req * cqr, struct dasd_device * device) ...@@ -86,48 +86,31 @@ dasd_free_erp_request(struct dasd_ccw_req * cqr, struct dasd_device * device)
atomic_dec(&device->ref_count); atomic_dec(&device->ref_count);
} }
/* /*
* DESCRIPTION * dasd_default_erp_action just retries the current cqr
* 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
*/ */
struct dasd_ccw_req * struct dasd_ccw_req *
dasd_default_erp_action(struct dasd_ccw_req * cqr) dasd_default_erp_action(struct dasd_ccw_req * cqr)
{ {
struct dasd_device *device; struct dasd_device *device;
struct dasd_ccw_req *erp;
MESSAGE(KERN_DEBUG, "%s", "Default ERP called... ");
device = cqr->device; 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 */ } /* end dasd_default_erp_action */
/* /*
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Bugreports.to..: <Linux390@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
* *
* $Revision: 1.40 $ * $Revision: 1.42 $
*/ */
#ifndef DASD_INT_H #ifndef DASD_INT_H
...@@ -188,7 +188,6 @@ struct dasd_ccw_req { ...@@ -188,7 +188,6 @@ struct dasd_ccw_req {
#define DASD_CQR_DONE 0x03 /* request is completed successfully */ #define DASD_CQR_DONE 0x03 /* request is completed successfully */
#define DASD_CQR_ERROR 0x04 /* request is completed with error */ #define DASD_CQR_ERROR 0x04 /* request is completed with error */
#define DASD_CQR_FAILED 0x05 /* request is finally failed */ #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. */ /* Signature for error recovery functions. */
typedef struct dasd_ccw_req *(*dasd_erp_fn_t) (struct dasd_ccw_req *); typedef struct dasd_ccw_req *(*dasd_erp_fn_t) (struct dasd_ccw_req *);
...@@ -279,6 +278,7 @@ struct dasd_device { ...@@ -279,6 +278,7 @@ struct dasd_device {
/* Device state and target state. */ /* Device state and target state. */
int state, target; int state, target;
int stopped; /* device (ccw_device_start) was stopped */
/* Open and reference count. */ /* Open and reference count. */
atomic_t ref_count; atomic_t ref_count;
...@@ -306,6 +306,12 @@ struct dasd_device { ...@@ -306,6 +306,12 @@ struct dasd_device {
#endif #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 *); void dasd_put_device_wake(struct dasd_device *);
/* /*
......
...@@ -168,6 +168,58 @@ dasd_ioctl_disable(struct block_device *bdev, int no, long args) ...@@ -168,6 +168,58 @@ dasd_ioctl_disable(struct block_device *bdev, int no, long args)
return 0; return 0;
} }
/*
* 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_ * performs formatting of _device_ according to _fdata_
* Note: The discipline's format_function is assumed to deliver formatting * Note: The discipline's format_function is assumed to deliver formatting
...@@ -438,6 +490,8 @@ static struct { int no; dasd_ioctl_fn_t fn; } dasd_ioctls[] = ...@@ -438,6 +490,8 @@ static struct { int no; dasd_ioctl_fn_t fn; } dasd_ioctls[] =
{ {
{ BIODASDDISABLE, dasd_ioctl_disable }, { BIODASDDISABLE, dasd_ioctl_disable },
{ BIODASDENABLE, dasd_ioctl_enable }, { BIODASDENABLE, dasd_ioctl_enable },
{ BIODASDQUIESCE, dasd_ioctl_quiesce },
{ BIODASDRESUME, dasd_ioctl_resume },
{ BIODASDFMT, dasd_ioctl_format }, { BIODASDFMT, dasd_ioctl_format },
{ BIODASDINFO, dasd_ioctl_information }, { BIODASDINFO, dasd_ioctl_information },
{ BIODASDINFO2, dasd_ioctl_information }, { BIODASDINFO2, dasd_ioctl_information },
......
...@@ -8,16 +8,8 @@ ...@@ -8,16 +8,8 @@
* any future changes wrt the API will result in a change of the APIVERSION reported * any future changes wrt the API will result in a change of the APIVERSION reported
* to userspace by the DASDAPIVER-ioctl * 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 #ifndef DASD_H
...@@ -226,6 +218,10 @@ typedef struct attrib_data_t { ...@@ -226,6 +218,10 @@ typedef struct attrib_data_t {
#define BIODASDSLCK _IO(DASD_IOCTL_LETTER,4) /* steal lock */ #define BIODASDSLCK _IO(DASD_IOCTL_LETTER,4) /* steal lock */
/* reset profiling information of a device */ /* reset profiling information of a device */
#define BIODASDPRRST _IO(DASD_IOCTL_LETTER,5) #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 */ /* retrieve API version number */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment