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 @@
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
*
* $Revision: 1.123 $
* $Revision: 1.129 $
*/
#include <linux/config.h>
......@@ -668,7 +668,7 @@ dasd_check_cqr(struct dasd_ccw_req *cqr)
/*
* 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.
*/
int
......@@ -684,10 +684,7 @@ dasd_term_IO(struct dasd_ccw_req * cqr)
retries = 0;
device = (struct dasd_device *) cqr->device;
while ((retries < 5) && (cqr->status == DASD_CQR_IN_IO)) {
if (retries < 2)
rc = ccw_device_halt(device->cdev, (long) cqr);
else
rc = ccw_device_clear(device->cdev, (long) cqr);
rc = ccw_device_clear(device->cdev, (long) cqr);
switch (rc) {
case 0: /* termination successful */
cqr->status = DASD_CQR_FAILED;
......@@ -736,6 +733,7 @@ dasd_start_IO(struct dasd_ccw_req * cqr)
return rc;
device = (struct dasd_device *) cqr->device;
cqr->startclk = get_clock();
cqr->starttime = jiffies;
rc = ccw_device_start(device->cdev, cqr->cpaddr, (long) cqr,
cqr->lpm, 0);
switch (rc) {
......@@ -788,14 +786,11 @@ dasd_timeout_device(unsigned long ptr)
}
/*
* Setup timeout for a device.
* Setup timeout for a device in jiffies.
*/
void
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 (timer_pending(&device->timer))
del_timer(&device->timer);
......@@ -1002,8 +997,7 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
"no memory for dstat...ignoring");
#ifdef ERP_DEBUG
/* dump sense data */
if (device->discipline && device->discipline->dump_sense)
device->discipline->dump_sense(device, cqr);
dasd_log_sense(cqr, irb);
#endif
switch (era) {
case dasd_era_fatal:
......@@ -1079,8 +1073,11 @@ __dasd_process_ccw_queue(struct dasd_device * device,
cqr->status = DASD_CQR_FAILED;
cqr->stopclk = get_clock();
} else {
erp_fn = device->discipline->erp_action(cqr);
erp_fn(cqr);
if (cqr->dstat->esw.esw0.erw.cons) {
erp_fn = device->discipline->erp_action(cqr);
erp_fn(cqr);
} else
dasd_default_erp_action(cqr);
}
goto restart;
}
......@@ -1196,7 +1193,7 @@ __dasd_check_expire(struct dasd_device * device)
cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list);
if (cqr->status == DASD_CQR_IN_IO && cqr->expires != 0) {
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)
/* Hmpf, try again in 1/100 sec */
dasd_set_timer(device, 1);
......@@ -1476,6 +1473,7 @@ _dasd_term_running_cqr(struct dasd_device *device)
/* termination successful */
cqr->status = DASD_CQR_QUEUED;
cqr->startclk = cqr->stopclk = 0;
cqr->starttime = 0;
}
return rc;
}
......@@ -1782,9 +1780,19 @@ dasd_generic_set_online (struct ccw_device *cdev,
if (IS_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;
}
device->discipline = discipline;
rc = discipline->check_device(device);
if (rc) {
printk (KERN_WARNING
......@@ -1980,6 +1988,7 @@ EXPORT_SYMBOL(dasd_term_IO);
EXPORT_SYMBOL_GPL(dasd_generic_probe);
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_offline);
EXPORT_SYMBOL_GPL(dasd_generic_auto_online);
......
......@@ -5,7 +5,7 @@
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000, 2001
*
* $Revision: 1.26 $
* $Revision: 1.27 $
*/
#include <linux/timer.h>
......@@ -2129,13 +2129,10 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense)
/* single program action codes (byte25 bit 0 == '0') */
switch (sense[25]) {
case 0x00: /* success */
DEV_MESSAGE(KERN_DEBUG, device,
"ERP called for successful request %p"
" - NO ERP necessary", erp);
erp = dasd_3990_erp_cleanup(erp, DASD_CQR_DONE);
case 0x00: /* success - use default ERP for retries */
DEV_MESSAGE(KERN_DEBUG, device, "%s",
"ERP called for successful request"
" - just retry");
break;
case 0x01: /* fatal error */
......
......@@ -7,7 +7,7 @@
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
*
* $Revision: 1.49 $
* $Revision: 1.50 $
*/
#include <linux/config.h>
......@@ -1420,6 +1420,9 @@ dasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
"Exception class %x\n",
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);
......
......@@ -9,7 +9,7 @@
*
* gendisk related functions for the dasd driver.
*
* $Revision: 1.42 $
* $Revision: 1.44 $
*/
#include <linux/config.h>
......@@ -31,6 +31,7 @@ int
dasd_gendisk_alloc(struct dasd_device *device)
{
struct gendisk *gdp;
int len;
/* Make sure the minor for this device exists. */
if (device->devindex >= DASD_PER_MAJOR)
......@@ -46,8 +47,28 @@ dasd_gendisk_alloc(struct dasd_device *device)
gdp->fops = &dasd_device_operations;
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);
if (device->ro_flag)
......
......@@ -6,7 +6,7 @@
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
*
* $Revision: 1.52 $
* $Revision: 1.54 $
*/
#ifndef DASD_INT_H
......@@ -14,6 +14,10 @@
#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 */
#define DASD_PER_MAJOR (1U << (MINORBITS - DASD_PARTN_BITS))
#define DASD_PARTN_MASK ((1 << DASD_PARTN_BITS) - 1)
......@@ -157,6 +161,7 @@ struct dasd_ccw_req {
short retries; /* A retry counter */
/* ... and how */
unsigned long starttime; /* jiffies time of request start */
int expires; /* expiration period in jiffies */
char lpm; /* logical path mask */
void *data; /* pointer to data area */
......@@ -166,6 +171,7 @@ struct dasd_ccw_req {
struct dasd_ccw_req *refers; /* ERP-chain queueing. */
void *function; /* originating ERP action */
/* these are for statistics only */
unsigned long long buildclk; /* TOD-clock of request generation */
unsigned long long startclk; /* TOD-clock of request start */
unsigned long long stopclk; /* TOD-clock of request interrupt */
......
......@@ -147,6 +147,7 @@ dasd_ioctl_enable(struct block_device *bdev, int no, long args)
/*
* Disable device.
* Used by dasdfmt. Disable I/O operations but allow ioctls.
*/
static int
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.
*/
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;
}
......@@ -237,9 +245,9 @@ dasd_format(struct dasd_device * device, struct format_data_t * fdata)
if (device->discipline->format_device == NULL)
return -EPERM;
if (atomic_read(&device->open_count) > 1) {
if (device->state != DASD_STATE_BASIC) {
DEV_MESSAGE(KERN_WARNING, device, "%s",
"dasd_format: device is open! ");
"dasd_format: device is not disabled! ");
return -EBUSY;
}
......@@ -248,6 +256,16 @@ dasd_format(struct dasd_device * device, struct format_data_t * fdata)
fdata->start_unit,
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) {
cqr = device->discipline->format_device(device, fdata);
if (IS_ERR(cqr))
......
......@@ -9,7 +9,7 @@
*
* /proc interface for the dasd driver.
*
* $Revision: 1.24 $
* $Revision: 1.26 $
*/
#include <linux/config.h>
......@@ -67,10 +67,15 @@ dasd_devices_show(struct seq_file *m, void *v)
seq_printf(m, "(none)");
/* Print kdev. */
if (device->gdp)
seq_printf(m, " at (%3d:%7d)",
seq_printf(m, " at (%3d:%6d)",
device->gdp->major, device->gdp->first_minor);
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. */
substr = device->ro_flag ? "(ro)" : " ";
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