Commit 2e05bc63 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] s390: DASD device driver.

From: Martin Schwidefsky <schwidefsky@de.ibm.com>

DASD driver fixes:
 - Fix generic_set_online if diag discipline is not availab.e
 - Fix reserve on already reserved device.
 - Use default-erp for unit check without sence information.
 - Revert dasd naming scheme change from dasd<xyz> to dasd_<busid>_. This
   breaks too many user space packages.
 - Extend dasd naming scheme to four letters dasd<aaaa>-dasd<zzzz>.
 - Fix formatting of dasds.
parent 6cab1ea3
...@@ -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.123 $ * $Revision: 1.129 $
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -668,7 +668,7 @@ dasd_check_cqr(struct dasd_ccw_req *cqr) ...@@ -668,7 +668,7 @@ dasd_check_cqr(struct dasd_ccw_req *cqr)
/* /*
* Terminate the current i/o and set the request to failed. * Terminate the current i/o and set the request to failed.
* ccw_device_halt/ccw_device_clear can fail if the i/o subsystem * ccw_device_clear can fail if the i/o subsystem
* is in a bad mood. * is in a bad mood.
*/ */
int int
...@@ -684,10 +684,7 @@ dasd_term_IO(struct dasd_ccw_req * cqr) ...@@ -684,10 +684,7 @@ dasd_term_IO(struct dasd_ccw_req * cqr)
retries = 0; retries = 0;
device = (struct dasd_device *) cqr->device; device = (struct dasd_device *) cqr->device;
while ((retries < 5) && (cqr->status == DASD_CQR_IN_IO)) { while ((retries < 5) && (cqr->status == DASD_CQR_IN_IO)) {
if (retries < 2) rc = ccw_device_clear(device->cdev, (long) cqr);
rc = ccw_device_halt(device->cdev, (long) cqr);
else
rc = ccw_device_clear(device->cdev, (long) cqr);
switch (rc) { switch (rc) {
case 0: /* termination successful */ case 0: /* termination successful */
cqr->status = DASD_CQR_FAILED; cqr->status = DASD_CQR_FAILED;
...@@ -736,6 +733,7 @@ dasd_start_IO(struct dasd_ccw_req * cqr) ...@@ -736,6 +733,7 @@ dasd_start_IO(struct dasd_ccw_req * cqr)
return rc; return rc;
device = (struct dasd_device *) cqr->device; device = (struct dasd_device *) cqr->device;
cqr->startclk = get_clock(); cqr->startclk = get_clock();
cqr->starttime = jiffies;
rc = ccw_device_start(device->cdev, cqr->cpaddr, (long) cqr, rc = ccw_device_start(device->cdev, cqr->cpaddr, (long) cqr,
cqr->lpm, 0); cqr->lpm, 0);
switch (rc) { switch (rc) {
...@@ -788,14 +786,11 @@ dasd_timeout_device(unsigned long ptr) ...@@ -788,14 +786,11 @@ dasd_timeout_device(unsigned long ptr)
} }
/* /*
* Setup timeout for a device. * Setup timeout for a device in jiffies.
*/ */
void void
dasd_set_timer(struct dasd_device *device, int expires) dasd_set_timer(struct dasd_device *device, int expires)
{ {
/* FIXME: timeouts are based on jiffies but the timeout
* comparision in __dasd_check_expire is based on the
* TOD clock. */
if (expires == 0) { if (expires == 0) {
if (timer_pending(&device->timer)) if (timer_pending(&device->timer))
del_timer(&device->timer); del_timer(&device->timer);
...@@ -1002,8 +997,7 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, ...@@ -1002,8 +997,7 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
"no memory for dstat...ignoring"); "no memory for dstat...ignoring");
#ifdef ERP_DEBUG #ifdef ERP_DEBUG
/* dump sense data */ /* dump sense data */
if (device->discipline && device->discipline->dump_sense) dasd_log_sense(cqr, irb);
device->discipline->dump_sense(device, cqr);
#endif #endif
switch (era) { switch (era) {
case dasd_era_fatal: case dasd_era_fatal:
...@@ -1079,8 +1073,11 @@ __dasd_process_ccw_queue(struct dasd_device * device, ...@@ -1079,8 +1073,11 @@ __dasd_process_ccw_queue(struct dasd_device * device,
cqr->status = DASD_CQR_FAILED; cqr->status = DASD_CQR_FAILED;
cqr->stopclk = get_clock(); cqr->stopclk = get_clock();
} else { } else {
erp_fn = device->discipline->erp_action(cqr); if (cqr->dstat->esw.esw0.erw.cons) {
erp_fn(cqr); erp_fn = device->discipline->erp_action(cqr);
erp_fn(cqr);
} else
dasd_default_erp_action(cqr);
} }
goto restart; goto restart;
} }
...@@ -1196,7 +1193,7 @@ __dasd_check_expire(struct dasd_device * device) ...@@ -1196,7 +1193,7 @@ __dasd_check_expire(struct dasd_device * device)
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_IN_IO && cqr->expires != 0) { if (cqr->status == DASD_CQR_IN_IO && cqr->expires != 0) {
now = get_clock(); now = get_clock();
if (cqr->expires * (TOD_SEC / HZ) + cqr->startclk < now) { if (time_after_eq(jiffies, cqr->expires + cqr->starttime)) {
if (device->discipline->term_IO(cqr) != 0) if (device->discipline->term_IO(cqr) != 0)
/* Hmpf, try again in 1/100 sec */ /* Hmpf, try again in 1/100 sec */
dasd_set_timer(device, 1); dasd_set_timer(device, 1);
...@@ -1476,6 +1473,7 @@ _dasd_term_running_cqr(struct dasd_device *device) ...@@ -1476,6 +1473,7 @@ _dasd_term_running_cqr(struct dasd_device *device)
/* termination successful */ /* termination successful */
cqr->status = DASD_CQR_QUEUED; cqr->status = DASD_CQR_QUEUED;
cqr->startclk = cqr->stopclk = 0; cqr->startclk = cqr->stopclk = 0;
cqr->starttime = 0;
} }
return rc; return rc;
} }
...@@ -1782,9 +1780,19 @@ dasd_generic_set_online (struct ccw_device *cdev, ...@@ -1782,9 +1780,19 @@ dasd_generic_set_online (struct ccw_device *cdev,
if (IS_ERR(device)) if (IS_ERR(device))
return PTR_ERR(device); return PTR_ERR(device);
if (device->use_diag_flag) if (device->use_diag_flag) {
if (!dasd_diag_discipline_pointer) {
printk (KERN_WARNING
"dasd_generic couldn't online device %s "
"- discipline DIAG not available\n",
cdev->dev.bus_id);
dasd_delete_device(device);
return -ENODEV;
}
discipline = dasd_diag_discipline_pointer; discipline = dasd_diag_discipline_pointer;
}
device->discipline = discipline; device->discipline = discipline;
rc = discipline->check_device(device); rc = discipline->check_device(device);
if (rc) { if (rc) {
printk (KERN_WARNING printk (KERN_WARNING
...@@ -1980,6 +1988,7 @@ EXPORT_SYMBOL(dasd_term_IO); ...@@ -1980,6 +1988,7 @@ EXPORT_SYMBOL(dasd_term_IO);
EXPORT_SYMBOL_GPL(dasd_generic_probe); EXPORT_SYMBOL_GPL(dasd_generic_probe);
EXPORT_SYMBOL_GPL(dasd_generic_remove); EXPORT_SYMBOL_GPL(dasd_generic_remove);
EXPORT_SYMBOL_GPL(dasd_generic_notify);
EXPORT_SYMBOL_GPL(dasd_generic_set_online); EXPORT_SYMBOL_GPL(dasd_generic_set_online);
EXPORT_SYMBOL_GPL(dasd_generic_set_offline); EXPORT_SYMBOL_GPL(dasd_generic_set_offline);
EXPORT_SYMBOL_GPL(dasd_generic_auto_online); EXPORT_SYMBOL_GPL(dasd_generic_auto_online);
......
...@@ -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.26 $ * $Revision: 1.27 $
*/ */
#include <linux/timer.h> #include <linux/timer.h>
...@@ -2129,13 +2129,10 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense) ...@@ -2129,13 +2129,10 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense)
/* single program action codes (byte25 bit 0 == '0') */ /* single program action codes (byte25 bit 0 == '0') */
switch (sense[25]) { switch (sense[25]) {
case 0x00: /* success */ case 0x00: /* success - use default ERP for retries */
DEV_MESSAGE(KERN_DEBUG, device, DEV_MESSAGE(KERN_DEBUG, device, "%s",
"ERP called for successful request %p" "ERP called for successful request"
" - NO ERP necessary", erp); " - just retry");
erp = dasd_3990_erp_cleanup(erp, DASD_CQR_DONE);
break; break;
case 0x01: /* fatal error */ case 0x01: /* fatal error */
......
...@@ -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.49 $ * $Revision: 1.50 $
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -1420,6 +1420,9 @@ dasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req, ...@@ -1420,6 +1420,9 @@ dasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
"Exception class %x\n", "Exception class %x\n",
irb->ecw[6] & 0x0f, irb->ecw[22] >> 4); irb->ecw[6] & 0x0f, irb->ecw[22] >> 4);
} }
} else {
len += sprintf(page + len, KERN_ERR PRINTK_HEADER
"SORRY - NO VALID SENSE AVAILABLE\n");
} }
MESSAGE(KERN_ERR, "Sense data:\n%s", page); MESSAGE(KERN_ERR, "Sense data:\n%s", page);
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* gendisk related functions for the dasd driver. * gendisk related functions for the dasd driver.
* *
* $Revision: 1.42 $ * $Revision: 1.44 $
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -31,6 +31,7 @@ int ...@@ -31,6 +31,7 @@ int
dasd_gendisk_alloc(struct dasd_device *device) dasd_gendisk_alloc(struct dasd_device *device)
{ {
struct gendisk *gdp; struct gendisk *gdp;
int len;
/* Make sure the minor for this device exists. */ /* Make sure the minor for this device exists. */
if (device->devindex >= DASD_PER_MAJOR) if (device->devindex >= DASD_PER_MAJOR)
...@@ -46,8 +47,28 @@ dasd_gendisk_alloc(struct dasd_device *device) ...@@ -46,8 +47,28 @@ dasd_gendisk_alloc(struct dasd_device *device)
gdp->fops = &dasd_device_operations; gdp->fops = &dasd_device_operations;
gdp->driverfs_dev = &device->cdev->dev; gdp->driverfs_dev = &device->cdev->dev;
/* Set device name */ /*
sprintf(gdp->disk_name, "dasd_%s_", device->cdev->dev.bus_id); * Set device name.
* dasda - dasdz : 26 devices
* dasdaa - dasdzz : 676 devices, added up = 702
* dasdaaa - dasdzzz : 17576 devices, added up = 18278
* dasdaaaa - dasdzzzz : 456976 devices, added up = 475252
*/
len = sprintf(gdp->disk_name, "dasd");
if (device->devindex > 25) {
if (device->devindex > 701) {
if (device->devindex > 18277)
len += sprintf(gdp->disk_name + len, "%c",
'a'+(((device->devindex-18278)
/17576)%26));
len += sprintf(gdp->disk_name + len, "%c",
'a'+(((device->devindex-702)/676)%26));
}
len += sprintf(gdp->disk_name + len, "%c",
'a'+(((device->devindex-26)/26)%26));
}
len += sprintf(gdp->disk_name + len, "%c", 'a'+(device->devindex%26));
sprintf(gdp->devfs_name, "dasd/%s", device->cdev->dev.bus_id); sprintf(gdp->devfs_name, "dasd/%s", device->cdev->dev.bus_id);
if (device->ro_flag) if (device->ro_flag)
......
...@@ -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.52 $ * $Revision: 1.54 $
*/ */
#ifndef DASD_INT_H #ifndef DASD_INT_H
...@@ -14,6 +14,10 @@ ...@@ -14,6 +14,10 @@
#ifdef __KERNEL__ #ifdef __KERNEL__
/* erp debugging in dasd.c and dasd_3990_erp.c */
#define ERP_DEBUG
/* we keep old device allocation scheme; IOW, minors are still in 0..255 */ /* we keep old device allocation scheme; IOW, minors are still in 0..255 */
#define DASD_PER_MAJOR (1U << (MINORBITS - DASD_PARTN_BITS)) #define DASD_PER_MAJOR (1U << (MINORBITS - DASD_PARTN_BITS))
#define DASD_PARTN_MASK ((1 << DASD_PARTN_BITS) - 1) #define DASD_PARTN_MASK ((1 << DASD_PARTN_BITS) - 1)
...@@ -157,6 +161,7 @@ struct dasd_ccw_req { ...@@ -157,6 +161,7 @@ struct dasd_ccw_req {
short retries; /* A retry counter */ short retries; /* A retry counter */
/* ... and how */ /* ... and how */
unsigned long starttime; /* jiffies time of request start */
int expires; /* expiration period in jiffies */ int expires; /* expiration period in jiffies */
char lpm; /* logical path mask */ char lpm; /* logical path mask */
void *data; /* pointer to data area */ void *data; /* pointer to data area */
...@@ -166,6 +171,7 @@ struct dasd_ccw_req { ...@@ -166,6 +171,7 @@ struct dasd_ccw_req {
struct dasd_ccw_req *refers; /* ERP-chain queueing. */ struct dasd_ccw_req *refers; /* ERP-chain queueing. */
void *function; /* originating ERP action */ void *function; /* originating ERP action */
/* these are for statistics only */
unsigned long long buildclk; /* TOD-clock of request generation */ unsigned long long buildclk; /* TOD-clock of request generation */
unsigned long long startclk; /* TOD-clock of request start */ unsigned long long startclk; /* TOD-clock of request start */
unsigned long long stopclk; /* TOD-clock of request interrupt */ unsigned long long stopclk; /* TOD-clock of request interrupt */
......
...@@ -147,6 +147,7 @@ dasd_ioctl_enable(struct block_device *bdev, int no, long args) ...@@ -147,6 +147,7 @@ dasd_ioctl_enable(struct block_device *bdev, int no, long args)
/* /*
* Disable device. * Disable device.
* Used by dasdfmt. Disable I/O operations but allow ioctls.
*/ */
static int static int
dasd_ioctl_disable(struct block_device *bdev, int no, long args) dasd_ioctl_disable(struct block_device *bdev, int no, long args)
...@@ -167,6 +168,13 @@ dasd_ioctl_disable(struct block_device *bdev, int no, long args) ...@@ -167,6 +168,13 @@ dasd_ioctl_disable(struct block_device *bdev, int no, long args)
* device is DASD_STATE_BASIC that allows to do basic i/o. * device is DASD_STATE_BASIC that allows to do basic i/o.
*/ */
dasd_set_target_state(device, DASD_STATE_BASIC); dasd_set_target_state(device, DASD_STATE_BASIC);
/*
* Set i_size to zero, since read, write, etc. check against this
* value.
*/
down(&bdev->bd_sem);
i_size_write(bdev->bd_inode, 0);
up(&bdev->bd_sem);
return 0; return 0;
} }
...@@ -237,9 +245,9 @@ dasd_format(struct dasd_device * device, struct format_data_t * fdata) ...@@ -237,9 +245,9 @@ dasd_format(struct dasd_device * device, struct format_data_t * fdata)
if (device->discipline->format_device == NULL) if (device->discipline->format_device == NULL)
return -EPERM; return -EPERM;
if (atomic_read(&device->open_count) > 1) { if (device->state != DASD_STATE_BASIC) {
DEV_MESSAGE(KERN_WARNING, device, "%s", DEV_MESSAGE(KERN_WARNING, device, "%s",
"dasd_format: device is open! "); "dasd_format: device is not disabled! ");
return -EBUSY; return -EBUSY;
} }
...@@ -248,6 +256,16 @@ dasd_format(struct dasd_device * device, struct format_data_t * fdata) ...@@ -248,6 +256,16 @@ dasd_format(struct dasd_device * device, struct format_data_t * fdata)
fdata->start_unit, fdata->start_unit,
fdata->stop_unit, fdata->blksize, fdata->intensity); fdata->stop_unit, fdata->blksize, fdata->intensity);
/* Since dasdfmt keeps the device open after it was disabled,
* there still exists an inode for this device. We must update i_blkbits,
* otherwise we might get errors when enabling the device later.
*/
if (fdata->start_unit == 0) {
struct block_device *bdev = bdget_disk(device->gdp, 0);
bdev->bd_inode->i_blkbits = blksize_bits(fdata->blksize);
bdput(bdev);
}
while (fdata->start_unit <= fdata->stop_unit) { while (fdata->start_unit <= fdata->stop_unit) {
cqr = device->discipline->format_device(device, fdata); cqr = device->discipline->format_device(device, fdata);
if (IS_ERR(cqr)) if (IS_ERR(cqr))
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* /proc interface for the dasd driver. * /proc interface for the dasd driver.
* *
* $Revision: 1.24 $ * $Revision: 1.26 $
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -67,10 +67,15 @@ dasd_devices_show(struct seq_file *m, void *v) ...@@ -67,10 +67,15 @@ dasd_devices_show(struct seq_file *m, void *v)
seq_printf(m, "(none)"); seq_printf(m, "(none)");
/* Print kdev. */ /* Print kdev. */
if (device->gdp) if (device->gdp)
seq_printf(m, " at (%3d:%7d)", seq_printf(m, " at (%3d:%6d)",
device->gdp->major, device->gdp->first_minor); device->gdp->major, device->gdp->first_minor);
else else
seq_printf(m, " at (???:???????)"); seq_printf(m, " at (???:??????)");
/* Print device name. */
if (device->gdp)
seq_printf(m, " is %-8s", device->gdp->disk_name);
else
seq_printf(m, " is ????????");
/* Print devices features. */ /* Print devices features. */
substr = device->ro_flag ? "(ro)" : " "; substr = device->ro_flag ? "(ro)" : " ";
seq_printf(m, "%4s: ", substr); seq_printf(m, "%4s: ", substr);
......
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