summaryrefslogtreecommitdiffstats
path: root/drivers/s390/block/dasd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/block/dasd.c')
-rw-r--r--drivers/s390/block/dasd.c159
1 files changed, 70 insertions, 89 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 08c88fc..0a9f12c 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -18,7 +18,6 @@
#include <linux/slab.h>
#include <linux/buffer_head.h>
#include <linux/hdreg.h>
-#include <linux/notifier.h>
#include <asm/ccwdev.h>
#include <asm/ebcdic.h>
@@ -44,7 +43,6 @@ MODULE_AUTHOR("Holger Smolinski <Holger.Smolinski@de.ibm.com>");
MODULE_DESCRIPTION("Linux on S/390 DASD device driver,"
" Copyright 2000 IBM Corporation");
MODULE_SUPPORTED_DEVICE("dasd");
-MODULE_PARM(dasd, "1-" __MODULE_STRING(256) "s");
MODULE_LICENSE("GPL");
/*
@@ -58,7 +56,6 @@ static void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *);
static void dasd_flush_ccw_queue(struct dasd_device *, int);
static void dasd_tasklet(struct dasd_device *);
static void do_kick_device(void *data);
-static void dasd_disable_eer(struct dasd_device *device);
/*
* SECTION: Operations on the device structure.
@@ -73,10 +70,9 @@ dasd_alloc_device(void)
{
struct dasd_device *device;
- device = kmalloc(sizeof (struct dasd_device), GFP_ATOMIC);
+ device = kzalloc(sizeof (struct dasd_device), GFP_ATOMIC);
if (device == NULL)
return ERR_PTR(-ENOMEM);
- memset(device, 0, sizeof (struct dasd_device));
/* open_count = 0 means device online but not in use */
atomic_set(&device->open_count, -1);
@@ -153,10 +149,15 @@ dasd_state_new_to_known(struct dasd_device *device)
static inline void
dasd_state_known_to_new(struct dasd_device * device)
{
- /* disable extended error reporting for this device */
- dasd_disable_eer(device);
+ /* Disable extended error reporting for this device. */
+ dasd_eer_disable(device);
/* Forget the discipline information. */
+ if (device->discipline)
+ module_put(device->discipline->owner);
device->discipline = NULL;
+ if (device->base_discipline)
+ module_put(device->base_discipline->owner);
+ device->base_discipline = NULL;
device->state = DASD_STATE_NEW;
dasd_free_queue(device);
@@ -214,9 +215,10 @@ dasd_state_basic_to_known(struct dasd_device * device)
* interrupt for this detection ccw uses the kernel event daemon to
* trigger the call to dasd_change_state. All this is done in the
* discipline code, see dasd_eckd.c.
- * After the analysis ccw is done (do_analysis returned 0 or error)
- * the block device is setup. Either a fake disk is added to allow
- * formatting or a proper device request queue is created.
+ * After the analysis ccw is done (do_analysis returned 0) the block
+ * device is setup.
+ * In case the analysis returns an error, the device setup is stopped
+ * (a fake disk was already added to allow formatting).
*/
static inline int
dasd_state_basic_to_ready(struct dasd_device * device)
@@ -226,13 +228,19 @@ dasd_state_basic_to_ready(struct dasd_device * device)
rc = 0;
if (device->discipline->do_analysis != NULL)
rc = device->discipline->do_analysis(device);
- if (rc)
+ if (rc) {
+ if (rc != -EAGAIN)
+ device->state = DASD_STATE_UNFMT;
return rc;
+ }
+ /* make disk known with correct capacity */
dasd_setup_queue(device);
+ set_capacity(device->gdp, device->blocks << device->s2b_shift);
device->state = DASD_STATE_READY;
- if (dasd_scan_partitions(device) != 0)
+ rc = dasd_scan_partitions(device);
+ if (rc)
device->state = DASD_STATE_BASIC;
- return 0;
+ return rc;
}
/*
@@ -253,6 +261,15 @@ dasd_state_ready_to_basic(struct dasd_device * device)
}
/*
+ * Back to basic.
+ */
+static inline void
+dasd_state_unfmt_to_basic(struct dasd_device * device)
+{
+ device->state = DASD_STATE_BASIC;
+}
+
+/*
* Make the device online and schedule the bottom half to start
* the requeueing of requests from the linux request queue to the
* ccw queue.
@@ -318,8 +335,12 @@ dasd_decrease_state(struct dasd_device *device)
if (device->state == DASD_STATE_READY &&
device->target <= DASD_STATE_BASIC)
dasd_state_ready_to_basic(device);
-
- if (device->state == DASD_STATE_BASIC &&
+
+ if (device->state == DASD_STATE_UNFMT &&
+ device->target <= DASD_STATE_BASIC)
+ dasd_state_unfmt_to_basic(device);
+
+ if (device->state == DASD_STATE_BASIC &&
device->target <= DASD_STATE_KNOWN)
dasd_state_basic_to_known(device);
@@ -520,33 +541,29 @@ dasd_kmalloc_request(char *magic, int cplength, int datasize,
struct dasd_ccw_req *cqr;
/* Sanity checks */
- if ( magic == NULL || datasize > PAGE_SIZE ||
- (cplength*sizeof(struct ccw1)) > PAGE_SIZE)
- BUG();
+ BUG_ON( magic == NULL || datasize > PAGE_SIZE ||
+ (cplength*sizeof(struct ccw1)) > PAGE_SIZE);
- cqr = kmalloc(sizeof(struct dasd_ccw_req), GFP_ATOMIC);
+ cqr = kzalloc(sizeof(struct dasd_ccw_req), GFP_ATOMIC);
if (cqr == NULL)
return ERR_PTR(-ENOMEM);
- memset(cqr, 0, sizeof(struct dasd_ccw_req));
cqr->cpaddr = NULL;
if (cplength > 0) {
- cqr->cpaddr = kmalloc(cplength*sizeof(struct ccw1),
+ cqr->cpaddr = kcalloc(cplength, sizeof(struct ccw1),
GFP_ATOMIC | GFP_DMA);
if (cqr->cpaddr == NULL) {
kfree(cqr);
return ERR_PTR(-ENOMEM);
}
- memset(cqr->cpaddr, 0, cplength*sizeof(struct ccw1));
}
cqr->data = NULL;
if (datasize > 0) {
- cqr->data = kmalloc(datasize, GFP_ATOMIC | GFP_DMA);
+ cqr->data = kzalloc(datasize, GFP_ATOMIC | GFP_DMA);
if (cqr->data == NULL) {
kfree(cqr->cpaddr);
kfree(cqr);
return ERR_PTR(-ENOMEM);
}
- memset(cqr->data, 0, datasize);
}
strncpy((char *) &cqr->magic, magic, 4);
ASCEBC((char *) &cqr->magic, 4);
@@ -565,9 +582,8 @@ dasd_smalloc_request(char *magic, int cplength, int datasize,
int size;
/* Sanity checks */
- if ( magic == NULL || datasize > PAGE_SIZE ||
- (cplength*sizeof(struct ccw1)) > PAGE_SIZE)
- BUG();
+ BUG_ON( magic == NULL || datasize > PAGE_SIZE ||
+ (cplength*sizeof(struct ccw1)) > PAGE_SIZE);
size = (sizeof(struct dasd_ccw_req) + 7L) & -8L;
if (cplength > 0)
@@ -871,8 +887,8 @@ dasd_handle_state_change_pending(struct dasd_device *device)
struct dasd_ccw_req *cqr;
struct list_head *l, *n;
- /* first of all call extended error reporting */
- dasd_write_eer_trigger(DASD_EER_STATECHANGE, device, NULL);
+ /* First of all start sense subsystem status request. */
+ dasd_eer_snss(device);
device->stopped &= ~DASD_STOPPED_PENDING;
@@ -1094,10 +1110,10 @@ restart:
goto restart;
}
- /* first of all call extended error reporting */
- if (device->eer && cqr->status == DASD_CQR_FAILED) {
- dasd_write_eer_trigger(DASD_EER_FATALERROR,
- device, cqr);
+ /* First of all call extended error reporting. */
+ if (dasd_eer_enabled(device) &&
+ cqr->status == DASD_CQR_FAILED) {
+ dasd_eer_write(device, cqr, DASD_EER_FATALERROR);
/* restart request */
cqr->status = DASD_CQR_QUEUED;
@@ -1244,7 +1260,7 @@ __dasd_start_head(struct dasd_device * device)
/* check FAILFAST */
if (device->stopped & ~DASD_STOPPED_PENDING &&
test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) &&
- (!device->eer)) {
+ (!dasd_eer_enabled(device))) {
cqr->status = DASD_CQR_FAILED;
dasd_schedule_bh(device);
}
@@ -1738,7 +1754,7 @@ dasd_open(struct inode *inp, struct file *filp)
goto out;
}
- if (device->state < DASD_STATE_BASIC) {
+ if (device->state <= DASD_STATE_BASIC) {
DBF_DEV_EVENT(DBF_ERR, device, " %s",
" Cannot open unrecognized device");
rc = -ENODEV;
@@ -1803,7 +1819,7 @@ dasd_exit(void)
#ifdef CONFIG_PROC_FS
dasd_proc_exit();
#endif
- dasd_ioctl_exit();
+ dasd_eer_exit();
if (dasd_page_cache != NULL) {
kmem_cache_destroy(dasd_page_cache);
dasd_page_cache = NULL;
@@ -1880,9 +1896,10 @@ dasd_generic_remove (struct ccw_device *cdev)
*/
int
dasd_generic_set_online (struct ccw_device *cdev,
- struct dasd_discipline *discipline)
+ struct dasd_discipline *base_discipline)
{
+ struct dasd_discipline *discipline;
struct dasd_device *device;
int rc;
@@ -1890,6 +1907,7 @@ dasd_generic_set_online (struct ccw_device *cdev,
if (IS_ERR(device))
return PTR_ERR(device);
+ discipline = base_discipline;
if (device->features & DASD_FEATURE_USEDIAG) {
if (!dasd_diag_discipline_pointer) {
printk (KERN_WARNING
@@ -1901,6 +1919,16 @@ dasd_generic_set_online (struct ccw_device *cdev,
}
discipline = dasd_diag_discipline_pointer;
}
+ if (!try_module_get(base_discipline->owner)) {
+ dasd_delete_device(device);
+ return -EINVAL;
+ }
+ if (!try_module_get(discipline->owner)) {
+ module_put(base_discipline->owner);
+ dasd_delete_device(device);
+ return -EINVAL;
+ }
+ device->base_discipline = base_discipline;
device->discipline = discipline;
rc = discipline->check_device(device);
@@ -1909,6 +1937,8 @@ dasd_generic_set_online (struct ccw_device *cdev,
"dasd_generic couldn't online device %s "
"with discipline %s rc=%i\n",
cdev->dev.bus_id, discipline->name, rc);
+ module_put(discipline->owner);
+ module_put(base_discipline->owner);
dasd_delete_device(device);
return rc;
}
@@ -1986,8 +2016,8 @@ dasd_generic_notify(struct ccw_device *cdev, int event)
switch (event) {
case CIO_GONE:
case CIO_NO_PATH:
- /* first of all call extended error reporting */
- dasd_write_eer_trigger(DASD_EER_NOPATH, device, NULL);
+ /* First of all call extended error reporting. */
+ dasd_eer_write(device, NULL, DASD_EER_NOPATH);
if (device->state < DASD_STATE_BASIC)
break;
@@ -2046,50 +2076,6 @@ dasd_generic_auto_online (struct ccw_driver *dasd_discipline_driver)
put_driver(drv);
}
-/*
- * notifications for extended error reports
- */
-static struct notifier_block *dasd_eer_chain;
-
-int
-dasd_register_eer_notifier(struct notifier_block *nb)
-{
- return notifier_chain_register(&dasd_eer_chain, nb);
-}
-
-int
-dasd_unregister_eer_notifier(struct notifier_block *nb)
-{
- return notifier_chain_unregister(&dasd_eer_chain, nb);
-}
-
-/*
- * Notify the registered error reporting module of a problem
- */
-void
-dasd_write_eer_trigger(unsigned int id, struct dasd_device *device,
- struct dasd_ccw_req *cqr)
-{
- if (device->eer) {
- struct dasd_eer_trigger temp;
- temp.id = id;
- temp.device = device;
- temp.cqr = cqr;
- notifier_call_chain(&dasd_eer_chain, DASD_EER_TRIGGER,
- (void *)&temp);
- }
-}
-
-/*
- * Tell the registered error reporting module to disable error reporting for
- * a given device and to cleanup any private data structures on that device.
- */
-static void
-dasd_disable_eer(struct dasd_device *device)
-{
- notifier_call_chain(&dasd_eer_chain, DASD_EER_DISABLE, (void *)device);
-}
-
static int __init
dasd_init(void)
@@ -2123,7 +2109,7 @@ dasd_init(void)
rc = dasd_parse();
if (rc)
goto failed;
- rc = dasd_ioctl_init();
+ rc = dasd_eer_init();
if (rc)
goto failed;
#ifdef CONFIG_PROC_FS
@@ -2172,11 +2158,6 @@ EXPORT_SYMBOL_GPL(dasd_generic_set_online);
EXPORT_SYMBOL_GPL(dasd_generic_set_offline);
EXPORT_SYMBOL_GPL(dasd_generic_auto_online);
-EXPORT_SYMBOL(dasd_register_eer_notifier);
-EXPORT_SYMBOL(dasd_unregister_eer_notifier);
-EXPORT_SYMBOL(dasd_write_eer_trigger);
-
-
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
OpenPOWER on IntegriCloud