Commit f7a9fa93 authored by Martin Schwidefsky's avatar Martin Schwidefsky Committed by Linus Torvalds

[PATCH] s390: dasd driver.

Convert dasd driver to new channel subsystem driver

This makes the dasd driver work again after the changes to
the channel subsystem driver:
- handle device detection with standard driver model functions
- reduce use of dasd_devmap (devmap will die as soon as
  dasd configuration is handled from initramfs)
- some cleanups

Authors: Arnd Bergmann <arndb@de.ibm.com>
	 Martin Schwidefsky <schwidefsky@de.ibm.com>
parent 0286402a
...@@ -79,6 +79,7 @@ CONFIG_BLK_DEV_XPRAM=m ...@@ -79,6 +79,7 @@ CONFIG_BLK_DEV_XPRAM=m
# S/390 block device drivers # S/390 block device drivers
# #
CONFIG_DASD=y CONFIG_DASD=y
# CONFIG_DASD_PROFILE is not set
CONFIG_DASD_ECKD=y CONFIG_DASD_ECKD=y
CONFIG_DASD_FBA=y CONFIG_DASD_FBA=y
CONFIG_DASD_DIAG=y CONFIG_DASD_DIAG=y
......
...@@ -137,6 +137,7 @@ CONFIG_BLK_DEV_XPRAM=m ...@@ -137,6 +137,7 @@ CONFIG_BLK_DEV_XPRAM=m
# S/390 block device drivers # S/390 block device drivers
# #
CONFIG_DASD=y CONFIG_DASD=y
# CONFIG_DASD_PROFILE is not set
CONFIG_DASD_ECKD=y CONFIG_DASD_ECKD=y
CONFIG_DASD_FBA=y CONFIG_DASD_FBA=y
# CONFIG_DASD_DIAG is not set # CONFIG_DASD_DIAG is not set
......
...@@ -138,49 +138,34 @@ config DASD ...@@ -138,49 +138,34 @@ config DASD
S/390s channel subsystem commands. This is necessary for running S/390s channel subsystem commands. This is necessary for running
natively on a single image or an LPAR. natively on a single image or an LPAR.
config DASD_PROFILE
bool "Profiling support for dasd devices"
help
Enable this option if you want to see profiling information
in /proc/dasd/statistics.
config DASD_ECKD config DASD_ECKD
tristate "Support for ECKD Disks" tristate "Support for ECKD Disks"
depends on DASD depends on DASD
help help
ECKD devices are the most commonly used devices. you should enable ECKD devices are the most commonly used devices. You should enable
this option unless you are very sure to have no ECKD device. this option unless you are very sure to have no ECKD device.
config DASD_AUTO_ECKD
bool "Automatic activation of ECKD module"
depends on DASD && DASD_ECKD=m
help
Enable this option if you want your ECKD discipline module loaded
on DASD driver startup.
config DASD_FBA config DASD_FBA
tristate "Support for FBA Disks" tristate "Support for FBA Disks"
depends on DASD depends on DASD
help help
FBA devices are currently unsupported. Select this option to be able to access FBA devices. It is safe to
say "Y".
config DASD_AUTO_FBA
bool "Automatic activation of FBA module"
depends on DASD && DASD_FBA=m
help
Enable this option if you want your FBA discipline module loaded
on DASD driver startup.
# dep_tristate ' Support for CKD Disks' CONFIG_DASD_CKD $CONFIG_DASD
config DASD_DIAG config DASD_DIAG
tristate "Support for DIAG access to CMS reserved Disks" tristate "Support for DIAG access to CMS reserved Disks"
depends on !ARCH_S390X && DASD depends on DASD
help help
Select this option if you want to use CMS reserved Disks under VM Select this option if you want to use CMS reserved Disks under VM
with the Diagnose250 command. If you are not running under VM or with the Diagnose250 command. If you are not running under VM or
unsure what it is, say "N". unsure what it is, say "N".
config DASD_AUTO_DIAG
bool "Automatic activation of DIAG module"
depends on DASD && !ARCH_S390X && DASD_DIAG=m
help
Enable this option if you want your DIAG discipline module loaded
on DASD driver startup.
endmenu endmenu
source "drivers/md/Kconfig" source "drivers/md/Kconfig"
......
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
* 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.71 $
*
* History of changes (starts July 2000) * History of changes (starts July 2000)
* 11/09/00 complete redesign after code review * 11/09/00 complete redesign after code review
* 02/01/01 added dynamic registration of ioctls * 02/01/01 added dynamic registration of ioctls
...@@ -51,7 +53,7 @@ ...@@ -51,7 +53,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <asm/div64.h> #include <asm/ccwdev.h>
#include <asm/ebcdic.h> #include <asm/ebcdic.h>
#include <asm/idals.h> #include <asm/idals.h>
#include <asm/todclk.h> #include <asm/todclk.h>
...@@ -60,10 +62,6 @@ ...@@ -60,10 +62,6 @@
#define PRINTK_HEADER "dasd:" #define PRINTK_HEADER "dasd:"
#include "dasd_int.h" #include "dasd_int.h"
#include "dasd_eckd.h"
#include "dasd_fba.h"
#include "dasd_diag.h"
/* /*
* SECTION: Constant definitions to be used within this file * SECTION: Constant definitions to be used within this file
*/ */
...@@ -80,116 +78,19 @@ MODULE_DESCRIPTION("Linux on S/390 DASD device driver," ...@@ -80,116 +78,19 @@ MODULE_DESCRIPTION("Linux on S/390 DASD device driver,"
MODULE_SUPPORTED_DEVICE("dasd"); MODULE_SUPPORTED_DEVICE("dasd");
MODULE_PARM(dasd, "1-" __MODULE_STRING(256) "s"); MODULE_PARM(dasd, "1-" __MODULE_STRING(256) "s");
MODULE_PARM(dasd_disciplines, "1-" __MODULE_STRING(8) "s"); MODULE_PARM(dasd_disciplines, "1-" __MODULE_STRING(8) "s");
MODULE_LICENSE("GPL");
/* /*
* SECTION: prototypes for static functions of dasd.c * SECTION: prototypes for static functions of dasd.c
*/ */
static void dasd_enable_discipline(dasd_discipline_t *);
static void dasd_disable_discipline(dasd_discipline_t *);
static void dasd_not_oper_handler(int irq, int status);
static int dasd_setup_blkdev(dasd_device_t * device); static int dasd_setup_blkdev(dasd_device_t * device);
static void dasd_disable_blkdev(dasd_device_t * device); static void dasd_disable_blkdev(dasd_device_t * device);
static void dasd_flush_request_queue(dasd_device_t *); static void dasd_flush_request_queue(dasd_device_t *);
static void dasd_int_handler(int, void *, struct pt_regs *); static void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *);
static void dasd_flush_ccw_queue(dasd_device_t *, int); static void dasd_flush_ccw_queue(dasd_device_t *, int);
static void dasd_tasklet(dasd_device_t *); static void dasd_tasklet(dasd_device_t *);
static void do_kick_device(void *data); static void do_kick_device(void *data);
static int dasd_add_sysfs_files(struct ccw_device *cdev);
/*
* Parameter parsing functions. There are two for the dasd driver:
* <dasd_disciplines> : <dasd_module>(,<dasd_module>)*
*/
static char *dasd_disciplines[8];
#ifndef MODULE
/*
* The parameter parsing functions for builtin-drivers are called
* before kmalloc works. Store the pointers to the parameters strings
* into dasd_disciplines[] for later processing.
*/
static int __init
dasd_disciplines_setup(char *str)
{
static int count = 0;
if (count < 8)
dasd_disciplines[count++] = str;
return 1;
}
__setup ("dasd_disciplines=", dasd_disciplines_setup);
#endif /* #ifndef MODULE */
/*
* SECTION: managing dasd disciplines
*/
static struct list_head dasd_disc_head = LIST_HEAD_INIT(dasd_disc_head);
static spinlock_t discipline_lock = SPIN_LOCK_UNLOCKED;
/*
* Add a discipline to the head of the discipline chain. The last added
* discipline that matches a device is used. In particular disciplines
* added by a module will have precedence over statically linked
* disciplines.
*/
void
dasd_discipline_add(dasd_discipline_t * discipline)
{
MOD_INC_USE_COUNT;
spin_lock(&discipline_lock);
list_add(&discipline->list, &dasd_disc_head);
spin_unlock(&discipline_lock);
/* Setup devices for discipline. */
dasd_enable_discipline(discipline);
}
/*
* Remove a discipline from the discipline list and disable all devices
* that rely on that discipline.
*/
void
dasd_discipline_del(dasd_discipline_t * discipline)
{
struct list_head *l;
spin_lock(&discipline_lock);
/* Check if the discipline was added. */
list_for_each(l, &dasd_disc_head) {
if (list_entry(l, dasd_discipline_t, list) == discipline) {
list_del(&discipline->list);
break;
}
}
spin_unlock(&discipline_lock);
/* Disable devices for discipline. */
dasd_disable_discipline(discipline);
MOD_DEC_USE_COUNT;
}
/*
* Find the discipline for a device.
*/
static inline int
dasd_find_disc(dasd_device_t * device)
{
struct list_head *l;
dasd_discipline_t *discipline, *tmp;
discipline = NULL;
spin_lock(&discipline_lock);
list_for_each(l, &dasd_disc_head) {
tmp = list_entry(l, dasd_discipline_t, list);
if (tmp->check_device(device) == 0) {
/* Found a matching discipline. */
discipline = tmp;
break;
}
}
device->discipline = discipline;
spin_unlock(&discipline_lock);
return (discipline != NULL) ? 0 : -ENODEV;
}
/* /*
* SECTION: Operations on the device structure. * SECTION: Operations on the device structure.
...@@ -204,22 +105,13 @@ dasd_alloc_device(dasd_devmap_t *devmap) ...@@ -204,22 +105,13 @@ dasd_alloc_device(dasd_devmap_t *devmap)
{ {
dasd_device_t *device; dasd_device_t *device;
struct gendisk *gdp; struct gendisk *gdp;
int rc;
device = kmalloc(sizeof (dasd_device_t), GFP_ATOMIC); device = kmalloc(sizeof (dasd_device_t), GFP_ATOMIC);
if (device == NULL) if (device == NULL)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
memset(device, 0, sizeof (dasd_device_t)); memset(device, 0, sizeof (dasd_device_t));
/* Get devinfo from the common io layer. */ device->devno = devmap->devno;
rc = get_dev_info_by_devno(devmap->devno, &device->devinfo);
if (rc) {
kfree(device);
return ERR_PTR(rc);
}
DBF_EVENT(DBF_NOTICE, "got devinfo CU-type %04x and dev-type %04x",
device->devinfo.sid_data.cu_type,
device->devinfo.sid_data.dev_type);
/* Get two pages for normal block device operations. */ /* Get two pages for normal block device operations. */
device->ccw_mem = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, 1); device->ccw_mem = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, 1);
...@@ -255,7 +147,7 @@ dasd_alloc_device(dasd_devmap_t *devmap) ...@@ -255,7 +147,7 @@ dasd_alloc_device(dasd_devmap_t *devmap)
(unsigned long) device); (unsigned long) device);
INIT_LIST_HEAD(&device->ccw_queue); INIT_LIST_HEAD(&device->ccw_queue);
init_timer(&device->timer); init_timer(&device->timer);
INIT_WORK(&device->kick_work, do_kick_device, (void *) (addr_t) device->devinfo.devno); INIT_WORK(&device->kick_work, do_kick_device, (void *) (addr_t) device->devno);
device->state = DASD_STATE_NEW; device->state = DASD_STATE_NEW;
device->target = DASD_STATE_NEW; device->target = DASD_STATE_NEW;
...@@ -286,9 +178,13 @@ dasd_state_new_to_known(dasd_device_t *device) ...@@ -286,9 +178,13 @@ dasd_state_new_to_known(dasd_device_t *device)
dasd_devmap_t *devmap; dasd_devmap_t *devmap;
umode_t devfs_perm; umode_t devfs_perm;
devfs_handle_t dir; devfs_handle_t dir;
int major, minor, rc; int major, minor;
devmap = dasd_devmap_from_devno(device->devinfo.devno); /* Increase reference count of bdev. */
if (bdget(MKDEV(device->gdp->major, device->gdp->first_minor)) == NULL)
return -ENODEV;
devmap = dasd_devmap_from_devno(device->devno);
if (devmap == NULL) if (devmap == NULL)
return -ENODEV; return -ENODEV;
major = dasd_gendisk_index_major(devmap->devindex); major = dasd_gendisk_index_major(devmap->devindex);
...@@ -296,16 +192,11 @@ dasd_state_new_to_known(dasd_device_t *device) ...@@ -296,16 +192,11 @@ dasd_state_new_to_known(dasd_device_t *device)
return -ENODEV; return -ENODEV;
minor = devmap->devindex % DASD_PER_MAJOR; minor = devmap->devindex % DASD_PER_MAJOR;
/* Find a discipline for the device. */
rc = dasd_find_disc(device);
if (rc)
return rc;
/* Add a proc directory and the dasd device entry to devfs. */ /* Add a proc directory and the dasd device entry to devfs. */
sprintf(buffer, "dasd/%04x", device->devinfo.devno); sprintf(buffer, "dasd/%04x", device->devno);
dir = devfs_mk_dir(NULL, buffer, NULL); dir = devfs_mk_dir(NULL, buffer, NULL);
device->gdp->de = dir; device->gdp->de = dir;
if (devmap->features & DASD_FEATURE_READONLY) if (device->ro_flag)
devfs_perm = S_IFBLK | S_IRUSR; devfs_perm = S_IFBLK | S_IRUSR;
else else
devfs_perm = S_IFBLK | S_IRUSR | S_IWUSR; devfs_perm = S_IFBLK | S_IRUSR | S_IWUSR;
...@@ -323,12 +214,7 @@ dasd_state_new_to_known(dasd_device_t *device) ...@@ -323,12 +214,7 @@ dasd_state_new_to_known(dasd_device_t *device)
static inline void static inline void
dasd_state_known_to_new(dasd_device_t * device) dasd_state_known_to_new(dasd_device_t * device)
{ {
dasd_devmap_t *devmap;
struct block_device *bdev; struct block_device *bdev;
int minor;
devmap = dasd_devmap_from_devno(device->devinfo.devno);
minor = devmap->devindex % DASD_PER_MAJOR;
/* Remove device entry and devfs directory. */ /* Remove device entry and devfs directory. */
devfs_unregister(device->devfs_entry); devfs_unregister(device->devfs_entry);
...@@ -337,6 +223,11 @@ dasd_state_known_to_new(dasd_device_t * device) ...@@ -337,6 +223,11 @@ dasd_state_known_to_new(dasd_device_t * device)
/* Forget the discipline information. */ /* Forget the discipline information. */
device->discipline = NULL; device->discipline = NULL;
device->state = DASD_STATE_NEW; device->state = DASD_STATE_NEW;
/* Decrease reference count of bdev. */
bdev = bdget(MKDEV(device->gdp->major, device->gdp->first_minor));
bdput(bdev);
bdput(bdev);
} }
/* /*
...@@ -345,8 +236,6 @@ dasd_state_known_to_new(dasd_device_t * device) ...@@ -345,8 +236,6 @@ dasd_state_known_to_new(dasd_device_t * device)
static inline int static inline int
dasd_state_known_to_basic(dasd_device_t * device) dasd_state_known_to_basic(dasd_device_t * device)
{ {
int rc;
/* register 'device' debug area, used for all DBF_DEV_XXX calls */ /* register 'device' debug area, used for all DBF_DEV_XXX calls */
device->debug_area = debug_register(device->gdp->disk_name, 0, 2, device->debug_area = debug_register(device->gdp->disk_name, 0, 2,
8 * sizeof (long)); 8 * sizeof (long));
...@@ -354,19 +243,6 @@ dasd_state_known_to_basic(dasd_device_t * device) ...@@ -354,19 +243,6 @@ dasd_state_known_to_basic(dasd_device_t * device)
debug_set_level(device->debug_area, DBF_ERR); debug_set_level(device->debug_area, DBF_ERR);
DBF_DEV_EVENT(DBF_EMERG, device, "%s", "debug area created"); DBF_DEV_EVENT(DBF_EMERG, device, "%s", "debug area created");
/*
* We request the "official" irq line even for dasd diag device.
* The interrupts for dasd diag will arrive at dasd_ext_handler
* instead of dasd_int_handler so this is just a placeholder.
*/
rc = s390_request_irq_special(device->devinfo.irq,
dasd_int_handler,
dasd_not_oper_handler,
0, "dasd", &device->dev_status);
if (rc) {
MESSAGE(KERN_ERR, "%s", "No request IRQ");
return rc;
}
device->state = DASD_STATE_BASIC; device->state = DASD_STATE_BASIC;
return 0; return 0;
} }
...@@ -378,7 +254,6 @@ static inline void ...@@ -378,7 +254,6 @@ static inline void
dasd_state_basic_to_known(dasd_device_t * device) dasd_state_basic_to_known(dasd_device_t * device)
{ {
dasd_flush_ccw_queue(device, 1); dasd_flush_ccw_queue(device, 1);
free_irq(device->devinfo.irq, &device->dev_status);
DBF_DEV_EVENT(DBF_EMERG, device, "%p debug area deleted", device); DBF_DEV_EVENT(DBF_EMERG, device, "%p debug area deleted", device);
if (device->debug_area != NULL) { if (device->debug_area != NULL) {
debug_unregister(device->debug_area); debug_unregister(device->debug_area);
...@@ -428,15 +303,8 @@ dasd_state_accept_to_basic(dasd_device_t * device) ...@@ -428,15 +303,8 @@ dasd_state_accept_to_basic(dasd_device_t * device)
static inline int static inline int
dasd_state_accept_to_ready(dasd_device_t * device) dasd_state_accept_to_ready(dasd_device_t * device)
{ {
dasd_devmap_t *devmap; int rc;
int rc, i;
devmap = dasd_devmap_from_devno(device->devinfo.devno);
if (devmap->features & DASD_FEATURE_READONLY) {
device->ro_flag = 1;
DEV_MESSAGE (KERN_WARNING, device, "%s",
"setting read-only mode ");
}
rc = dasd_setup_blkdev(device); rc = dasd_setup_blkdev(device);
if (rc == 0) { if (rc == 0) {
dasd_setup_partitions(device); dasd_setup_partitions(device);
...@@ -559,7 +427,7 @@ dasd_change_state(dasd_device_t *device) ...@@ -559,7 +427,7 @@ dasd_change_state(dasd_device_t *device)
if (rc && rc != -EAGAIN) { if (rc && rc != -EAGAIN) {
if (rc != -ENODEV) if (rc != -ENODEV)
MESSAGE (KERN_INFO, "giving up on dasd device with " MESSAGE (KERN_INFO, "giving up on dasd device with "
"devno %04x", device->devinfo.devno); "devno %04x", device->devno);
device->target = device->state; device->target = device->state;
} }
...@@ -622,255 +490,25 @@ dasd_set_target_state(dasd_device_t *device, int target) ...@@ -622,255 +490,25 @@ dasd_set_target_state(dasd_device_t *device, int target)
* Enable devices with device numbers in [from..to]. * Enable devices with device numbers in [from..to].
*/ */
static inline int static inline int
_wait_for_devices(int from, int to) _wait_for_device(dasd_device_t *device)
{ {
dasd_devmap_t *devmap; return (device->state == device->target);
dasd_device_t *device;
int devno, rc;
rc = 0;
for (devno = from; devno <= to && rc == 0; devno++) {
devmap = dasd_devmap_from_devno(devno);
device = (devmap != NULL) ?
dasd_get_device(devmap) : ERR_PTR(-ENODEV);
if (IS_ERR(device))
continue;
if (device->state != device->target)
rc = 1;
dasd_put_device(devmap);
}
return rc;
} }
// FIXME: if called from dasd_devices_write discpline is not set -> oops.
void void
dasd_enable_devices(int from, int to) dasd_enable_device(dasd_device_t *device)
{ {
dasd_devmap_t *devmap;
dasd_device_t *device;
int devno;
for (devno = from; devno <= to; devno++) {
devmap = dasd_devmap_from_devno(devno);
device = (devmap != NULL) ?
dasd_get_device(devmap) : ERR_PTR(-ENODEV);
if (IS_ERR(device))
continue;
dasd_set_target_state(device, DASD_STATE_ONLINE); dasd_set_target_state(device, DASD_STATE_ONLINE);
if (device->state <= DASD_STATE_KNOWN) if (device->state <= DASD_STATE_KNOWN)
/* No discipline for device found. */ /* No discipline for device found. */
dasd_set_target_state(device, DASD_STATE_NEW); dasd_set_target_state(device, DASD_STATE_NEW);
dasd_put_device(devmap);
}
/* Now wait for the devices to come up. */ /* Now wait for the devices to come up. */
wait_event(dasd_init_waitq, _wait_for_devices(from, to) == 0); wait_event(dasd_init_waitq, _wait_for_device(device));
}
/*
* Disable devices with device numbers in [from..to].
*/
void
dasd_disable_devices(int from, int to)
{
dasd_devmap_t *devmap;
dasd_device_t *device;
int devno;
for (devno = from; devno <= to; devno++) {
devmap = dasd_devmap_from_devno(devno);
device = (devmap != NULL) ?
dasd_get_device(devmap) : ERR_PTR(-ENODEV);
if (IS_ERR(device))
continue;
dasd_set_target_state(device, DASD_STATE_NEW);
dasd_put_device(devmap);
}
} }
/* /*
* Enable devices that use a specific discipline. * SECTION: device operation (interrupt handler, start i/o, term i/o ...)
*/
static inline int
_wait_for_disc_devices(dasd_discipline_t *discipline)
{
dasd_devmap_t *devmap;
dasd_device_t *device;
int devindex, rc;
rc = 0;
for (devindex = 0; devindex < dasd_max_devindex; devindex++) {
devmap = dasd_devmap_from_devindex(devindex);
device = (devmap != NULL) ?
dasd_get_device(devmap) : ERR_PTR(-ENODEV);
if (IS_ERR(device))
continue;
if (device->discipline == discipline &&
device->state != device->target)
rc = 1;
dasd_put_device(devmap);
}
return rc;
}
static void
dasd_enable_discipline(dasd_discipline_t *discipline)
{
dasd_devmap_t *devmap;
dasd_device_t *device;
int devindex;
for (devindex = 0; devindex < dasd_max_devindex; devindex++) {
devmap = dasd_devmap_from_devindex(devindex);
device = (devmap != NULL) ?
dasd_get_device(devmap) : ERR_PTR(-ENODEV);
if (IS_ERR(device))
continue;
if (device->discipline != NULL &&
device->discipline != discipline)
continue;
dasd_set_target_state(device, DASD_STATE_ONLINE);
if (device->discipline == NULL)
/* No discipline for device found. */
dasd_set_target_state(device, DASD_STATE_NEW);
dasd_put_device(devmap);
}
/* Now wait for the devices to come up. */
wait_event(dasd_init_waitq, _wait_for_disc_devices(discipline) == 0);
}
/*
* Disable devices that use a specific discipline.
*/
static void
dasd_disable_discipline(dasd_discipline_t *discipline)
{
dasd_devmap_t *devmap;
dasd_device_t *device;
int devindex;
/* Shutdown device that use the discipline. */
for (devindex = 0; devindex < dasd_max_devindex; devindex++) {
devmap = dasd_devmap_from_devindex(devindex);
device = (devmap != NULL) ?
dasd_get_device(devmap) : ERR_PTR(-ENODEV);
if (IS_ERR(device))
continue;
if (device->discipline == discipline)
dasd_set_target_state(device, DASD_STATE_NEW);
dasd_put_device(devmap);
}
}
/*
* Deactivate a device that has vaninshed.
*/
static void
do_not_oper_handler(void *data)
{
struct {
struct work_struct work;
int irq;
} *p;
dasd_device_t *device;
dasd_devmap_t *devmap;
/*
* find out devno of leaving device: CIO has already deleted
* this information so we need to find it by irq!
*/
p = data;
devmap = dasd_devmap_from_irq(p->irq);
if (devmap == NULL) {
MESSAGE(KERN_WARNING,
"not_oper_handler called on irq 0x%04x no devno!",
p->irq);
return;
} else
DBF_EVENT(DBF_NOTICE, "called for devno %04x", devmap->devno);
device = dasd_get_device(devmap);
if (IS_ERR(device))
return;
dasd_set_target_state(device, DASD_STATE_NEW);
dasd_put_device(devmap);
kfree(p);
}
void
dasd_not_oper_handler(int irq, int status)
{
struct {
struct work_struct work;
int irq;
} *p;
p = kmalloc(sizeof(*p), GFP_ATOMIC);
if (p == NULL)
/* FIXME: No memory, we loose. */
return;
INIT_WORK(&p->work, (void *) do_not_oper_handler, p);
p->irq = irq;
/* queue call to do_not_oper_handler to the kernel event daemon. */
schedule_work(&p->work);
}
/*
* Activate a device that appeared out of nowhere.
*/
static void
do_oper_handler(void *data)
{
struct {
struct work_struct work;
int devno;
} *p;
dasd_devmap_t *devmap;
dasd_device_t *device;
p = data;
DBF_EVENT(DBF_NOTICE, "called for devno %04x", p->devno);
if (dasd_autodetect &&
dasd_add_range(p->devno, p->devno, DASD_FEATURE_DEFAULT) != 0)
return;
/* Get/create the device structure for devno. */
devmap = dasd_devmap_from_devno(p->devno);
if (devmap == NULL) {
DBF_EXC(DBF_ALERT, "no dasd: devno %04x", p->devno);
return;
}
device = dasd_get_device(devmap);
if (IS_ERR(device))
return;
dasd_enable_devices(p->devno, p->devno);
dasd_put_device(devmap);
kfree(p);
}
int
dasd_oper_handler(int irq, devreg_t * devreg)
{
struct {
struct work_struct work;
int devno;
} *p;
p = kmalloc(sizeof(*p), GFP_ATOMIC);
if (p == NULL)
/* FIXME: No memory, we loose. */
return -ENOMEM;
p->devno = get_devno_by_irq(irq);
if (p->devno == -ENODEV)
return -ENODEV;
INIT_WORK(&p->work, (void *) do_oper_handler, p);
/* queue call to do_oper_handler to the kernel event daemon. */
schedule_work(&p->work);
return 0;
}
/*
* SECTION: device operation (interrupt handler, start_IO, term_IO ...)
*/ */
#ifdef CONFIG_DASD_PROFILE #ifdef CONFIG_DASD_PROFILE
...@@ -973,7 +611,7 @@ dasd_kmalloc_request(char *magic, int cplength, int datasize, ...@@ -973,7 +611,7 @@ dasd_kmalloc_request(char *magic, int cplength, int datasize,
/* Sanity checks */ /* Sanity checks */
if ( magic == NULL || datasize > PAGE_SIZE || if ( magic == NULL || datasize > PAGE_SIZE ||
(cplength*sizeof(ccw1_t)) > PAGE_SIZE) (cplength*sizeof(struct ccw1)) > PAGE_SIZE)
BUG(); BUG();
debug_text_event ( dasd_debug_area, 1, "ALLC"); debug_text_event ( dasd_debug_area, 1, "ALLC");
debug_text_event ( dasd_debug_area, 1, magic); debug_text_event ( dasd_debug_area, 1, magic);
...@@ -986,13 +624,13 @@ dasd_kmalloc_request(char *magic, int cplength, int datasize, ...@@ -986,13 +624,13 @@ dasd_kmalloc_request(char *magic, int cplength, int datasize,
memset(cqr, 0, sizeof(dasd_ccw_req_t)); memset(cqr, 0, sizeof(dasd_ccw_req_t));
cqr->cpaddr = NULL; cqr->cpaddr = NULL;
if (cplength > 0) { if (cplength > 0) {
cqr->cpaddr = kmalloc(cplength*sizeof(ccw1_t), cqr->cpaddr = kmalloc(cplength*sizeof(struct ccw1),
GFP_ATOMIC | GFP_DMA); GFP_ATOMIC | GFP_DMA);
if (cqr->cpaddr == NULL) { if (cqr->cpaddr == NULL) {
kfree(cqr); kfree(cqr);
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
} }
memset(cqr->cpaddr, 0, cplength*sizeof(ccw1_t)); memset(cqr->cpaddr, 0, cplength*sizeof(struct ccw1));
} }
cqr->data = NULL; cqr->data = NULL;
if (datasize > 0) { if (datasize > 0) {
...@@ -1022,7 +660,7 @@ dasd_smalloc_request(char *magic, int cplength, int datasize, ...@@ -1022,7 +660,7 @@ dasd_smalloc_request(char *magic, int cplength, int datasize,
/* Sanity checks */ /* Sanity checks */
if ( magic == NULL || datasize > PAGE_SIZE || if ( magic == NULL || datasize > PAGE_SIZE ||
(cplength*sizeof(ccw1_t)) > PAGE_SIZE) (cplength*sizeof(struct ccw1)) > PAGE_SIZE)
BUG(); BUG();
debug_text_event ( dasd_debug_area, 1, "ALLC"); debug_text_event ( dasd_debug_area, 1, "ALLC");
debug_text_event ( dasd_debug_area, 1, magic); debug_text_event ( dasd_debug_area, 1, magic);
...@@ -1031,7 +669,7 @@ dasd_smalloc_request(char *magic, int cplength, int datasize, ...@@ -1031,7 +669,7 @@ dasd_smalloc_request(char *magic, int cplength, int datasize,
size = (sizeof(dasd_ccw_req_t) + 7L) & -8L; size = (sizeof(dasd_ccw_req_t) + 7L) & -8L;
if (cplength > 0) if (cplength > 0)
size += cplength * sizeof(ccw1_t); size += cplength * sizeof(struct ccw1);
if (datasize > 0) if (datasize > 0)
size += datasize; size += datasize;
spin_lock_irqsave(&device->mem_lock, flags); spin_lock_irqsave(&device->mem_lock, flags);
...@@ -1043,9 +681,9 @@ dasd_smalloc_request(char *magic, int cplength, int datasize, ...@@ -1043,9 +681,9 @@ dasd_smalloc_request(char *magic, int cplength, int datasize,
data = (char *) cqr + ((sizeof(dasd_ccw_req_t) + 7L) & -8L); data = (char *) cqr + ((sizeof(dasd_ccw_req_t) + 7L) & -8L);
cqr->cpaddr = NULL; cqr->cpaddr = NULL;
if (cplength > 0) { if (cplength > 0) {
cqr->cpaddr = (ccw1_t *) data; cqr->cpaddr = (struct ccw1 *) data;
data += cplength*sizeof(ccw1_t); data += cplength*sizeof(struct ccw1);
memset(cqr->cpaddr, 0, cplength*sizeof(ccw1_t)); memset(cqr->cpaddr, 0, cplength*sizeof(struct ccw1));
} }
cqr->data = NULL; cqr->data = NULL;
if (datasize > 0) { if (datasize > 0) {
...@@ -1067,7 +705,7 @@ void ...@@ -1067,7 +705,7 @@ void
dasd_kfree_request(dasd_ccw_req_t * cqr, dasd_device_t * device) dasd_kfree_request(dasd_ccw_req_t * cqr, dasd_device_t * device)
{ {
#ifdef CONFIG_ARCH_S390X #ifdef CONFIG_ARCH_S390X
ccw1_t *ccw; struct ccw1 *ccw;
/* Clear any idals used for the request. */ /* Clear any idals used for the request. */
ccw = cqr->cpaddr; ccw = cqr->cpaddr;
...@@ -1126,7 +764,8 @@ dasd_check_cqr(dasd_ccw_req_t *cqr) ...@@ -1126,7 +764,8 @@ dasd_check_cqr(dasd_ccw_req_t *cqr)
/* /*
* Terminate the current i/o and set the request to failed. * Terminate the current i/o and set the request to failed.
* halt_IO/clear_IO can fail if the i/o subsystem is in a bad mood. * ccw_device_halt/ccw_device_clear can fail if the i/o subsystem
* is in a bad mood.
*/ */
int int
dasd_term_IO(dasd_ccw_req_t * cqr) dasd_term_IO(dasd_ccw_req_t * cqr)
...@@ -1142,11 +781,9 @@ dasd_term_IO(dasd_ccw_req_t * cqr) ...@@ -1142,11 +781,9 @@ dasd_term_IO(dasd_ccw_req_t * cqr)
device = (dasd_device_t *) cqr->device; device = (dasd_device_t *) cqr->device;
while ((retries < 5) && (cqr->status == DASD_CQR_IN_IO)) { while ((retries < 5) && (cqr->status == DASD_CQR_IN_IO)) {
if (retries < 2) if (retries < 2)
rc = halt_IO(device->devinfo.irq, rc = ccw_device_halt(device->cdev, (long) cqr);
(long) cqr, cqr->options);
else else
rc = clear_IO(device->devinfo.irq, rc = ccw_device_clear(device->cdev, (long) cqr);
(long) cqr, cqr->options);
switch (rc) { switch (rc) {
case 0: /* termination successful */ case 0: /* termination successful */
cqr->status = DASD_CQR_FAILED; cqr->status = DASD_CQR_FAILED;
...@@ -1172,6 +809,7 @@ dasd_term_IO(dasd_ccw_req_t * cqr) ...@@ -1172,6 +809,7 @@ dasd_term_IO(dasd_ccw_req_t * cqr)
BUG(); BUG();
break; break;
} }
retries++;
} }
dasd_schedule_bh(device); dasd_schedule_bh(device);
return rc; return rc;
...@@ -1193,16 +831,10 @@ dasd_start_IO(dasd_ccw_req_t * cqr) ...@@ -1193,16 +831,10 @@ dasd_start_IO(dasd_ccw_req_t * cqr)
return rc; return rc;
device = (dasd_device_t *) cqr->device; device = (dasd_device_t *) cqr->device;
cqr->startclk = get_clock(); cqr->startclk = get_clock();
rc = do_IO(device->devinfo.irq, rc = ccw_device_start(device->cdev, cqr->cpaddr, (long) cqr,
cqr->cpaddr, (long) cqr, cqr->lpm, cqr->options); cqr->lpm, 0);
switch (rc) { switch (rc) {
case 0: case 0:
if (cqr->options & DOIO_WAIT_FOR_INTERRUPT) {
/* request already finished (synchronous IO) */
cqr->status = DASD_CQR_DONE;
cqr->stopclk = cqr->startclk;
dasd_schedule_bh(device);
} else
cqr->status = DASD_CQR_IN_IO; cqr->status = DASD_CQR_IN_IO;
break; break;
case -EBUSY: case -EBUSY:
...@@ -1244,14 +876,14 @@ dasd_timeout_device(unsigned long ptr) ...@@ -1244,14 +876,14 @@ dasd_timeout_device(unsigned long ptr)
dasd_ccw_req_t *cqr; dasd_ccw_req_t *cqr;
device = (dasd_device_t *) ptr; device = (dasd_device_t *) ptr;
spin_lock_irqsave(get_irq_lock(device->devinfo.irq), 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)) { if (!list_empty(&device->ccw_queue)) {
cqr = list_entry(device->ccw_queue.next, dasd_ccw_req_t, list); cqr = list_entry(device->ccw_queue.next, dasd_ccw_req_t, list);
if (cqr->status == DASD_CQR_PENDING) if (cqr->status == DASD_CQR_PENDING)
cqr->status = DASD_CQR_QUEUED; cqr->status = DASD_CQR_QUEUED;
} }
spin_unlock_irqrestore(get_irq_lock(device->devinfo.irq), flags); spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
dasd_schedule_bh(device); dasd_schedule_bh(device);
} }
...@@ -1264,18 +896,19 @@ dasd_set_timer(dasd_device_t *device, int expires) ...@@ -1264,18 +896,19 @@ dasd_set_timer(dasd_device_t *device, int expires)
/* FIXME: timeouts are based on jiffies but the timeout /* FIXME: timeouts are based on jiffies but the timeout
* comparision in __dasd_check_expire is based on the * comparision in __dasd_check_expire is based on the
* TOD clock. */ * TOD clock. */
if (expires != 0) { if (expires == 0) {
if (!timer_pending(&device->timer)) { if (timer_pending(&device->timer))
del_timer(&device->timer);
return;
}
if (timer_pending(&device->timer)) {
if (mod_timer(&device->timer, jiffies + expires))
return;
}
device->timer.function = dasd_timeout_device; device->timer.function = dasd_timeout_device;
device->timer.data = (unsigned long) device; device->timer.data = (unsigned long) device;
device->timer.expires = jiffies + expires; device->timer.expires = jiffies + expires;
add_timer(&device->timer); add_timer(&device->timer);
} else
mod_timer(&device->timer, jiffies + expires);
} else {
if (timer_pending(&device->timer))
del_timer(&device->timer);
}
} }
/* /*
...@@ -1300,33 +933,36 @@ do_state_change_pending(void *data) ...@@ -1300,33 +933,36 @@ do_state_change_pending(void *data)
{ {
struct { struct {
struct work_struct work; struct work_struct work;
unsigned short devno; dasd_device_t *device;
} *p; } *p;
dasd_devmap_t *devmap; dasd_devmap_t *devmap;
dasd_device_t *device; dasd_device_t *device;
dasd_ccw_req_t *cqr; dasd_ccw_req_t *cqr;
int devno;
p = data; p = data;
DBF_EVENT(DBF_NOTICE, "State change Interrupt: %04x", p->devno); device = p->device;
DBF_EVENT(DBF_NOTICE, "State change Interrupt for bus_id %s",
devmap = dasd_devmap_from_devno(p->devno); device->cdev->dev.bus_id);
device = (devmap != NULL) ?
dasd_get_device(devmap) : ERR_PTR(-ENODEV);
if (IS_ERR(device)) {
MESSAGE(KERN_DEBUG,
"unable to find device for state change pending "
"interrupt: devno%04x", p->devno);
return;
}
spin_lock_irq(get_irq_lock(device->devinfo.irq)); // FIXME: get rid of devmap.
devno = _ccw_device_get_device_number(device->cdev);
devmap = dasd_devmap_from_devno(devno);
spin_lock_irq(get_ccwdev_lock(device->cdev));
/* re-activate first request in queue */ /* re-activate first request in queue */
if (!list_empty(&device->ccw_queue)) { if (!list_empty(&device->ccw_queue)) {
cqr = list_entry(device->ccw_queue.next, dasd_ccw_req_t, list); cqr = list_entry(device->ccw_queue.next, dasd_ccw_req_t, 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) if (cqr->status == DASD_CQR_PENDING)
cqr->status = DASD_CQR_QUEUED; cqr->status = DASD_CQR_QUEUED;
} }
spin_unlock_irq(get_irq_lock(device->devinfo.irq)); spin_unlock_irq(get_ccwdev_lock(device->cdev));
dasd_schedule_bh(device); dasd_schedule_bh(device);
dasd_put_device(devmap); dasd_put_device(devmap);
kfree(p); kfree(p);
...@@ -1334,11 +970,11 @@ do_state_change_pending(void *data) ...@@ -1334,11 +970,11 @@ do_state_change_pending(void *data)
static void static void
dasd_handle_state_change_pending(devstat_t * stat) dasd_handle_state_change_pending(dasd_device_t *device)
{ {
struct { struct {
struct work_struct work; struct work_struct work;
unsigned short devno; dasd_device_t *device;
} *p; } *p;
p = kmalloc(sizeof(*p), GFP_ATOMIC); p = kmalloc(sizeof(*p), GFP_ATOMIC);
...@@ -1346,7 +982,8 @@ dasd_handle_state_change_pending(devstat_t * stat) ...@@ -1346,7 +982,8 @@ dasd_handle_state_change_pending(devstat_t * stat)
/* No memory, let the timeout do the reactivation. */ /* No memory, let the timeout do the reactivation. */
return; return;
INIT_WORK(&p->work, (void *) do_state_change_pending, p); INIT_WORK(&p->work, (void *) do_state_change_pending, p);
p->devno = stat->devno; p->device = device;
atomic_inc(&device->ref_count);
/* queue call to do_state_change_pending to the kernel event daemon. */ /* queue call to do_state_change_pending to the kernel event daemon. */
schedule_work(&p->work); schedule_work(&p->work);
} }
...@@ -1355,71 +992,61 @@ dasd_handle_state_change_pending(devstat_t * stat) ...@@ -1355,71 +992,61 @@ dasd_handle_state_change_pending(devstat_t * stat)
* Interrupt handler for "normal" ssch-io based dasd devices. * Interrupt handler for "normal" ssch-io based dasd devices.
*/ */
void void
dasd_int_handler(int irq, void *ds, struct pt_regs *regs) dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
struct irb *irb)
{ {
dasd_ccw_req_t *cqr, *next; dasd_ccw_req_t *cqr, *next;
dasd_device_t *device; dasd_device_t *device;
unsigned long long now; unsigned long long now;
int expires; int expires;
dasd_era_t era; dasd_era_t era;
devstat_t *stat;
char mask; char mask;
now = get_clock(); now = get_clock();
stat = (devstat_t *) ds;
DBF_EVENT(DBF_DEBUG, "Interrupt: IRQ %02x, stat %02x, devno %04x", DBF_EVENT(DBF_DEBUG, "Interrupt: stat %02x, bus_id %s",
irq, stat->dstat, stat->devno); irb->scsw.dstat, cdev->dev.bus_id);
/* first of all check for state change pending interrupt */ /* first of all check for state change pending interrupt */
mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP; mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP;
if ((stat->dstat & mask) == mask) { if ((irb->scsw.dstat & mask) == mask) {
dasd_handle_state_change_pending(stat); dasd_handle_state_change_pending(cdev->dev.driver_data);
return;
}
if (stat->intparm == 0) { /* no intparm: unsolicited interrupt */
MESSAGE(KERN_DEBUG,
"unsolicited interrupt: irq 0x%x devno %04x",
irq, stat->devno);
return; return;
} }
cqr = (dasd_ccw_req_t *) (unsigned long) stat->intparm; cqr = (dasd_ccw_req_t *) intparm;
/* /*
* check status - the request might have been killed * check status - the request might have been killed
* because of dyn detach * because of dyn detach
*/ */
if (cqr->status != DASD_CQR_IN_IO) { if (cqr->status != DASD_CQR_IN_IO) {
MESSAGE(KERN_DEBUG, MESSAGE(KERN_DEBUG,
"invalid status: irq 0x%x devno %04x, status %02x", "invalid status: bus_id %s, status %02x",
irq, stat->devno, cqr->status); cdev->dev.bus_id, cqr->status);
return; return;
} }
device = (dasd_device_t *) cqr->device; device = (dasd_device_t *) cqr->device;
if (device == NULL || if (device == NULL ||
device != ds - offsetof(dasd_device_t, dev_status) || device != cdev->dev.driver_data ||
device->devinfo.irq != irq ||
strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) { strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
MESSAGE(KERN_DEBUG, MESSAGE(KERN_DEBUG, "invalid device in request: bus_id %s",
"invalid device in request: irq 0x%x devno %04x", cdev->dev.bus_id);
irq, stat->devno);
return; return;
} }
DBF_DEV_EVENT(DBF_DEBUG, device, DBF_DEV_EVENT(DBF_DEBUG, device, "Int: CS/DS 0x%04x",
"Int: CS/DS 0x%04x", ((stat->cstat << 8) | stat->dstat)); ((irb->scsw.cstat << 8) | irb->scsw.dstat));
/* Find out the appropriate era_action. */ /* Find out the appropriate era_action. */
era = dasd_era_none; era = dasd_era_none;
if (stat->flag & DEVSTAT_FLAG_SENSE_AVAIL || if (irb->scsw.dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END) ||
stat->dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) { irb->esw.esw0.erw.cons) {
/* The request did end abnormally. */ /* The request did end abnormally. */
if (stat->flag & DEVSTAT_HALT_FUNCTION) if (irb->scsw.fctl & SCSW_FCTL_HALT_FUNC)
era = dasd_era_fatal; era = dasd_era_fatal;
else else
era = device->discipline->examine_error(cqr, stat); era = device->discipline->examine_error(cqr, irb);
DBF_EVENT(DBF_NOTICE, "era_code %d", era); DBF_EVENT(DBF_NOTICE, "era_code %d", era);
} }
expires = 0; expires = 0;
...@@ -1440,9 +1067,9 @@ dasd_int_handler(int irq, void *ds, struct pt_regs *regs) ...@@ -1440,9 +1067,9 @@ dasd_int_handler(int irq, void *ds, struct pt_regs *regs)
} }
} else { /* error */ } else { /* error */
if (cqr->dstat == NULL) if (cqr->dstat == NULL)
cqr->dstat = kmalloc(sizeof(devstat_t), GFP_ATOMIC); cqr->dstat = kmalloc(sizeof(struct irb), GFP_ATOMIC);
if (cqr->dstat) if (cqr->dstat)
memcpy(cqr->dstat, stat, sizeof (devstat_t)); memcpy(cqr->dstat, irb, sizeof (struct irb));
else else
MESSAGE(KERN_ERR, "%s", MESSAGE(KERN_ERR, "%s",
"no memory for dstat...ignoring"); "no memory for dstat...ignoring");
...@@ -1521,7 +1148,7 @@ __dasd_process_ccw_queue(dasd_device_t * device, struct list_head *final_queue) ...@@ -1521,7 +1148,7 @@ __dasd_process_ccw_queue(dasd_device_t * device, struct list_head *final_queue)
/* Process requests with DASD_CQR_ERROR */ /* Process requests with DASD_CQR_ERROR */
if (cqr->status == DASD_CQR_ERROR) { if (cqr->status == DASD_CQR_ERROR) {
cqr->retries--; cqr->retries--;
if (cqr->dstat->flag & DEVSTAT_HALT_FUNCTION) { if (cqr->dstat->scsw.fctl & SCSW_FCTL_HALT_FUNC) {
cqr->status = DASD_CQR_FAILED; cqr->status = DASD_CQR_FAILED;
cqr->stopclk = get_clock(); cqr->stopclk = get_clock();
} else { } else {
...@@ -1536,7 +1163,7 @@ __dasd_process_ccw_queue(dasd_device_t * device, struct list_head *final_queue) ...@@ -1536,7 +1163,7 @@ __dasd_process_ccw_queue(dasd_device_t * device, struct list_head *final_queue)
goto restart; goto restart;
} }
/* Rechain request on device device request queue */ /* Rechain finished requests to final queue */
cqr->endclk = get_clock(); cqr->endclk = get_clock();
list_move_tail(&cqr->list, final_queue); list_move_tail(&cqr->list, final_queue);
} }
...@@ -1595,7 +1222,7 @@ __dasd_process_blk_queue(dasd_device_t * device) ...@@ -1595,7 +1222,7 @@ __dasd_process_blk_queue(dasd_device_t * device)
if (device->ro_flag && rq_data_dir(req) == WRITE) { if (device->ro_flag && rq_data_dir(req) == WRITE) {
DBF_EVENT(DBF_ERR, DBF_EVENT(DBF_ERR,
"(%04x) Rejecting write request %p", "(%04x) Rejecting write request %p",
device->devinfo.devno, req); device->devno, req);
blkdev_dequeue_request(req); blkdev_dequeue_request(req);
dasd_end_request(req, 0); dasd_end_request(req, 0);
continue; continue;
...@@ -1606,7 +1233,7 @@ __dasd_process_blk_queue(dasd_device_t * device) ...@@ -1606,7 +1233,7 @@ __dasd_process_blk_queue(dasd_device_t * device)
break; /* terminate request queue loop */ break; /* terminate request queue loop */
DBF_EVENT(DBF_ERR, DBF_EVENT(DBF_ERR,
"(%04x) CCW creation failed on request %p", "(%04x) CCW creation failed on request %p",
device->devinfo.devno, req); device->devno, req);
blkdev_dequeue_request(req); blkdev_dequeue_request(req);
dasd_end_request(req, 0); dasd_end_request(req, 0);
continue; continue;
...@@ -1623,7 +1250,7 @@ __dasd_process_blk_queue(dasd_device_t * device) ...@@ -1623,7 +1250,7 @@ __dasd_process_blk_queue(dasd_device_t * device)
/* /*
* Take a look at the first request on the ccw queue and check * Take a look at the first request on the ccw queue and check
* if it reached its expire time. * if it reached its expire time. If so, terminate the IO.
*/ */
static inline void static inline void
__dasd_check_expire(dasd_device_t * device) __dasd_check_expire(dasd_device_t * device)
...@@ -1679,7 +1306,7 @@ dasd_flush_ccw_queue(dasd_device_t * device, int all) ...@@ -1679,7 +1306,7 @@ dasd_flush_ccw_queue(dasd_device_t * device, int all)
dasd_ccw_req_t *cqr; dasd_ccw_req_t *cqr;
INIT_LIST_HEAD(&flush_queue); INIT_LIST_HEAD(&flush_queue);
spin_lock_irq(get_irq_lock(device->devinfo.irq)); spin_lock_irq(get_ccwdev_lock(device->cdev));
list_for_each_safe(l, n, &device->ccw_queue) { list_for_each_safe(l, n, &device->ccw_queue) {
cqr = list_entry(l, dasd_ccw_req_t, list); cqr = list_entry(l, dasd_ccw_req_t, list);
/* Flush all request or only block device requests? */ /* Flush all request or only block device requests? */
...@@ -1701,7 +1328,7 @@ dasd_flush_ccw_queue(dasd_device_t * device, int all) ...@@ -1701,7 +1328,7 @@ dasd_flush_ccw_queue(dasd_device_t * device, int all)
cqr->endclk = get_clock(); cqr->endclk = get_clock();
list_move_tail(&cqr->list, &flush_queue); list_move_tail(&cqr->list, &flush_queue);
} }
spin_unlock_irq(get_irq_lock(device->devinfo.irq)); spin_unlock_irq(get_ccwdev_lock(device->cdev));
/* Now call the callback function of flushed requests */ /* Now call the callback function of flushed requests */
list_for_each_safe(l, n, &flush_queue) { list_for_each_safe(l, n, &flush_queue) {
cqr = list_entry(l, dasd_ccw_req_t, list); cqr = list_entry(l, dasd_ccw_req_t, list);
...@@ -1722,12 +1349,12 @@ dasd_tasklet(dasd_device_t * device) ...@@ -1722,12 +1349,12 @@ dasd_tasklet(dasd_device_t * device)
atomic_set (&device->tasklet_scheduled, 0); atomic_set (&device->tasklet_scheduled, 0);
INIT_LIST_HEAD(&final_queue); INIT_LIST_HEAD(&final_queue);
spin_lock_irq(get_irq_lock(device->devinfo.irq)); spin_lock_irq(get_ccwdev_lock(device->cdev));
/* Check expire time of first request on the ccw queue. */ /* Check expire time of first request on the ccw queue. */
__dasd_check_expire(device); __dasd_check_expire(device);
/* Finish off requests on ccw queue */ /* Finish off requests on ccw queue */
__dasd_process_ccw_queue(device, &final_queue); __dasd_process_ccw_queue(device, &final_queue);
spin_unlock_irq(get_irq_lock(device->devinfo.irq)); spin_unlock_irq(get_ccwdev_lock(device->cdev));
/* Now call the callback function of requests with final status */ /* Now call the callback function of requests with final status */
list_for_each_safe(l, n, &final_queue) { list_for_each_safe(l, n, &final_queue) {
cqr = list_entry(l, dasd_ccw_req_t, list); cqr = list_entry(l, dasd_ccw_req_t, list);
...@@ -1736,19 +1363,19 @@ dasd_tasklet(dasd_device_t * device) ...@@ -1736,19 +1363,19 @@ dasd_tasklet(dasd_device_t * device)
(cqr->callback)(cqr, cqr->callback_data); (cqr->callback)(cqr, cqr->callback_data);
} }
spin_lock_irq(&device->request_queue_lock); spin_lock_irq(&device->request_queue_lock);
spin_lock(get_irq_lock(device->devinfo.irq)); spin_lock(get_ccwdev_lock(device->cdev));
/* Get new request from the block device request queue */ /* Get new request from the block device request queue */
__dasd_process_blk_queue(device); __dasd_process_blk_queue(device);
/* Now check if the head of the ccw queue needs to be started. */ /* Now check if the head of the ccw queue needs to be started. */
__dasd_start_head(device); __dasd_start_head(device);
spin_unlock(get_irq_lock(device->devinfo.irq)); spin_unlock(get_ccwdev_lock(device->cdev));
spin_unlock_irq(&device->request_queue_lock); spin_unlock_irq(&device->request_queue_lock);
/* FIXME: what if ref_count == 0 && state == DASD_STATE_NEW ?? */ /* FIXME: what if ref_count == 0 && state == DASD_STATE_NEW ?? */
atomic_dec(&device->ref_count); atomic_dec(&device->ref_count);
} }
/* /*
* Schedules a call to dasd_process_queues over the device tasklet. * Schedules a call to dasd_tasklet over the device tasklet.
*/ */
void void
dasd_schedule_bh(dasd_device_t * device) dasd_schedule_bh(dasd_device_t * device)
...@@ -1771,13 +1398,13 @@ dasd_add_request_head(dasd_ccw_req_t *req) ...@@ -1771,13 +1398,13 @@ dasd_add_request_head(dasd_ccw_req_t *req)
unsigned long flags; unsigned long flags;
device = req->device; device = req->device;
spin_lock_irqsave(get_irq_lock(device->devinfo.irq), flags); spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
req->status = DASD_CQR_QUEUED; req->status = DASD_CQR_QUEUED;
req->device = device; req->device = device;
list_add(&req->list, &device->ccw_queue); list_add(&req->list, &device->ccw_queue);
/* let the bh start the request to keep them in order */ /* let the bh start the request to keep them in order */
dasd_schedule_bh(device); dasd_schedule_bh(device);
spin_unlock_irqrestore(get_irq_lock(device->devinfo.irq), flags); spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
} }
/* /*
...@@ -1791,13 +1418,13 @@ dasd_add_request_tail(dasd_ccw_req_t *req) ...@@ -1791,13 +1418,13 @@ dasd_add_request_tail(dasd_ccw_req_t *req)
unsigned long flags; unsigned long flags;
device = req->device; device = req->device;
spin_lock_irqsave(get_irq_lock(device->devinfo.irq), flags); spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
req->status = DASD_CQR_QUEUED; req->status = DASD_CQR_QUEUED;
req->device = device; req->device = device;
list_add_tail(&req->list, &device->ccw_queue); list_add_tail(&req->list, &device->ccw_queue);
/* let the bh start the request to keep them in order */ /* let the bh start the request to keep them in order */
dasd_schedule_bh(device); dasd_schedule_bh(device);
spin_unlock_irqrestore(get_irq_lock(device->devinfo.irq), flags); spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
} }
/* /*
...@@ -1816,9 +1443,9 @@ _wait_for_wakeup(dasd_ccw_req_t *cqr) ...@@ -1816,9 +1443,9 @@ _wait_for_wakeup(dasd_ccw_req_t *cqr)
int rc; int rc;
device = cqr->device; device = cqr->device;
spin_lock_irq(get_irq_lock(device->devinfo.irq)); spin_lock_irq(get_ccwdev_lock(device->cdev));
rc = cqr->status == DASD_CQR_DONE || cqr->status == DASD_CQR_FAILED; rc = cqr->status == DASD_CQR_DONE || cqr->status == DASD_CQR_FAILED;
spin_unlock_irq(get_irq_lock(device->devinfo.irq)); spin_unlock_irq(get_ccwdev_lock(device->cdev));
return rc; return rc;
} }
...@@ -1833,7 +1460,7 @@ dasd_sleep_on(dasd_ccw_req_t * cqr) ...@@ -1833,7 +1460,7 @@ dasd_sleep_on(dasd_ccw_req_t * cqr)
int rc; int rc;
device = cqr->device; device = cqr->device;
spin_lock_irq(get_irq_lock(device->devinfo.irq)); spin_lock_irq(get_ccwdev_lock(device->cdev));
init_waitqueue_head (&wait_q); init_waitqueue_head (&wait_q);
cqr->callback = dasd_wakeup_cb; cqr->callback = dasd_wakeup_cb;
...@@ -1844,7 +1471,7 @@ dasd_sleep_on(dasd_ccw_req_t * cqr) ...@@ -1844,7 +1471,7 @@ dasd_sleep_on(dasd_ccw_req_t * cqr)
/* let the bh start the request to keep them in order */ /* let the bh start the request to keep them in order */
dasd_schedule_bh(device); dasd_schedule_bh(device);
spin_unlock_irq(get_irq_lock(device->devinfo.irq)); spin_unlock_irq(get_ccwdev_lock(device->cdev));
wait_event(wait_q, _wait_for_wakeup(cqr)); wait_event(wait_q, _wait_for_wakeup(cqr));
...@@ -1865,7 +1492,7 @@ dasd_sleep_on_interruptible(dasd_ccw_req_t * cqr) ...@@ -1865,7 +1492,7 @@ dasd_sleep_on_interruptible(dasd_ccw_req_t * cqr)
int rc, finished; int rc, finished;
device = cqr->device; device = cqr->device;
spin_lock_irq(get_irq_lock(device->devinfo.irq)); spin_lock_irq(get_ccwdev_lock(device->cdev));
init_waitqueue_head (&wait_q); init_waitqueue_head (&wait_q);
cqr->callback = dasd_wakeup_cb; cqr->callback = dasd_wakeup_cb;
...@@ -1875,7 +1502,7 @@ dasd_sleep_on_interruptible(dasd_ccw_req_t * cqr) ...@@ -1875,7 +1502,7 @@ dasd_sleep_on_interruptible(dasd_ccw_req_t * cqr)
/* let the bh start the request to keep them in order */ /* let the bh start the request to keep them in order */
dasd_schedule_bh(device); dasd_schedule_bh(device);
spin_unlock_irq(get_irq_lock(device->devinfo.irq)); spin_unlock_irq(get_ccwdev_lock(device->cdev));
finished = 0; finished = 0;
while (!finished) { while (!finished) {
...@@ -1885,13 +1512,13 @@ dasd_sleep_on_interruptible(dasd_ccw_req_t * cqr) ...@@ -1885,13 +1512,13 @@ dasd_sleep_on_interruptible(dasd_ccw_req_t * cqr)
rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0; rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0;
break; break;
} }
spin_lock_irq(get_irq_lock(device->devinfo.irq)); spin_lock_irq(get_ccwdev_lock(device->cdev));
if (cqr->status == DASD_CQR_IN_IO && if (cqr->status == DASD_CQR_IN_IO &&
device->discipline->term_IO(cqr) == 0) { device->discipline->term_IO(cqr) == 0) {
list_del(&cqr->list); list_del(&cqr->list);
finished = 1; finished = 1;
} }
spin_unlock_irq(get_irq_lock(device->devinfo.irq)); spin_unlock_irq(get_ccwdev_lock(device->cdev));
} }
return rc; return rc;
} }
...@@ -1928,10 +1555,10 @@ dasd_sleep_on_immediatly(dasd_ccw_req_t * cqr) ...@@ -1928,10 +1555,10 @@ dasd_sleep_on_immediatly(dasd_ccw_req_t * cqr)
int rc; int rc;
device = cqr->device; device = cqr->device;
spin_lock_irq(get_irq_lock(device->devinfo.irq)); spin_lock_irq(get_ccwdev_lock(device->cdev));
rc = _dasd_term_running_cqr(device); rc = _dasd_term_running_cqr(device);
if (rc) { if (rc) {
spin_unlock_irq(get_irq_lock(device->devinfo.irq)); spin_unlock_irq(get_ccwdev_lock(device->cdev));
return rc; return rc;
} }
...@@ -1944,7 +1571,7 @@ dasd_sleep_on_immediatly(dasd_ccw_req_t * cqr) ...@@ -1944,7 +1571,7 @@ dasd_sleep_on_immediatly(dasd_ccw_req_t * cqr)
/* let the bh start the request to keep them in order */ /* let the bh start the request to keep them in order */
dasd_schedule_bh(device); dasd_schedule_bh(device);
spin_unlock_irq(get_irq_lock(device->devinfo.irq)); spin_unlock_irq(get_ccwdev_lock(device->cdev));
wait_event(wait_q, _wait_for_wakeup(cqr)); wait_event(wait_q, _wait_for_wakeup(cqr));
...@@ -1966,7 +1593,7 @@ int dasd_cancel_req(dasd_ccw_req_t *cqr) ...@@ -1966,7 +1593,7 @@ int dasd_cancel_req(dasd_ccw_req_t *cqr)
int rc; int rc;
rc = 0; rc = 0;
spin_lock_irqsave(get_irq_lock(device->devinfo.irq), flags); spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
switch (cqr->status) { switch (cqr->status) {
case DASD_CQR_QUEUED: case DASD_CQR_QUEUED:
/* request was not started - just set to failed */ /* request was not started - just set to failed */
...@@ -1992,7 +1619,7 @@ int dasd_cancel_req(dasd_ccw_req_t *cqr) ...@@ -1992,7 +1619,7 @@ int dasd_cancel_req(dasd_ccw_req_t *cqr)
BUG(); BUG();
} }
spin_unlock_irqrestore(get_irq_lock(device->devinfo.irq), flags); spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
dasd_schedule_bh(device); dasd_schedule_bh(device);
return rc; return rc;
} }
...@@ -2010,12 +1637,12 @@ do_dasd_request(request_queue_t * queue) ...@@ -2010,12 +1637,12 @@ do_dasd_request(request_queue_t * queue)
dasd_device_t *device; dasd_device_t *device;
device = (dasd_device_t *) queue->queuedata; device = (dasd_device_t *) queue->queuedata;
spin_lock(get_irq_lock(device->devinfo.irq)); spin_lock(get_ccwdev_lock(device->cdev));
/* Get new request from the block device request queue */ /* Get new request from the block device request queue */
__dasd_process_blk_queue(device); __dasd_process_blk_queue(device);
/* Now check if the head of the ccw queue needs to be started. */ /* Now check if the head of the ccw queue needs to be started. */
__dasd_start_head(device); __dasd_start_head(device);
spin_unlock(get_irq_lock(device->devinfo.irq)); spin_unlock(get_ccwdev_lock(device->cdev));
} }
/* /*
...@@ -2088,7 +1715,6 @@ dasd_flush_request_queue(dasd_device_t * device) ...@@ -2088,7 +1715,6 @@ dasd_flush_request_queue(dasd_device_t * device)
static int static int
dasd_open(struct inode *inp, struct file *filp) dasd_open(struct inode *inp, struct file *filp)
{ {
dasd_devmap_t *devmap;
dasd_device_t *device; dasd_device_t *device;
int rc; int rc;
...@@ -2098,55 +1724,35 @@ dasd_open(struct inode *inp, struct file *filp) ...@@ -2098,55 +1724,35 @@ dasd_open(struct inode *inp, struct file *filp)
major(inp->i_rdev), minor(inp->i_rdev)); major(inp->i_rdev), minor(inp->i_rdev));
return -EPERM; return -EPERM;
} }
devmap = dasd_devmap_from_bdev(inp->i_bdev);
device = (devmap != NULL) ? device = inp->i_bdev->bd_disk->private_data;
dasd_get_device(devmap) : ERR_PTR(-ENODEV);
if (IS_ERR(device)) {
MESSAGE(KERN_WARNING,
"No device registered as (%d:%d)",
major(inp->i_rdev), minor(inp->i_rdev));
return PTR_ERR(device);
}
if (device->state < DASD_STATE_BASIC) { if (device->state < DASD_STATE_BASIC) {
DBF_DEV_EVENT(DBF_ERR, device, " %s", DBF_DEV_EVENT(DBF_ERR, device, " %s",
" Cannot open unrecognized device"); " Cannot open unrecognized device");
dasd_put_device(devmap);
return -ENODEV; return -ENODEV;
} }
rc = 0; rc = 0;
spin_lock(&discipline_lock);
if (atomic_inc_return(&device->open_count) == 1 && if (atomic_inc_return(&device->open_count) == 1) {
device->discipline->owner != NULL) {
if (!try_inc_mod_count(device->discipline->owner)) { if (!try_inc_mod_count(device->discipline->owner)) {
/* Discipline is currently unloaded! */ /* Discipline is currently unloaded! */
atomic_dec(&device->open_count); atomic_dec(&device->open_count);
rc = -ENODEV; rc = -ENODEV;
} }
} }
spin_unlock(&discipline_lock);
dasd_put_device(devmap);
return rc; return rc;
} }
static int static int
dasd_release(struct inode *inp, struct file *filp) dasd_release(struct inode *inp, struct file *filp)
{ {
dasd_devmap_t *devmap;
dasd_device_t *device; dasd_device_t *device;
devmap = dasd_devmap_from_bdev(inp->i_bdev); device = inp->i_bdev->bd_disk->private_data;
device = (devmap != NULL) ?
dasd_get_device(devmap) : ERR_PTR(-ENODEV);
if (IS_ERR(device)) {
MESSAGE(KERN_WARNING,
"No device registered as %d:%d",
major(inp->i_rdev), minor(inp->i_rdev));
return -EINVAL;
}
if (device->state < DASD_STATE_ACCEPT) { if (device->state < DASD_STATE_ACCEPT) {
DBF_DEV_EVENT(DBF_ERR, device, " %s", DBF_DEV_EVENT(DBF_ERR, device, " %s",
" Cannot release unrecognized device"); " Cannot release unrecognized device");
dasd_put_device(devmap);
return -EINVAL; return -EINVAL;
} }
if (atomic_dec_return(&device->open_count) == 0) { if (atomic_dec_return(&device->open_count) == 0) {
...@@ -2154,7 +1760,6 @@ dasd_release(struct inode *inp, struct file *filp) ...@@ -2154,7 +1760,6 @@ dasd_release(struct inode *inp, struct file *filp)
if (device->discipline->owner) if (device->discipline->owner)
__MOD_DEC_USE_COUNT(device->discipline->owner); __MOD_DEC_USE_COUNT(device->discipline->owner);
} }
dasd_put_device(devmap);
return 0; return 0;
} }
...@@ -2170,18 +1775,6 @@ block_device_operations dasd_device_operations = { ...@@ -2170,18 +1775,6 @@ block_device_operations dasd_device_operations = {
static void static void
dasd_exit(void) dasd_exit(void)
{ {
dasd_disable_devices(0, dasd_max_devindex);
#ifdef CONFIG_DASD_DIAG
if (MACHINE_IS_VM)
dasd_diag_cleanup();
#endif
#ifdef CONFIG_DASD_FBA
dasd_fba_cleanup();
#endif
#ifdef CONFIG_DASD_ECKD
dasd_eckd_cleanup();
#endif
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
dasd_proc_exit(); dasd_proc_exit();
#endif #endif
...@@ -2196,30 +1789,295 @@ dasd_exit(void) ...@@ -2196,30 +1789,295 @@ dasd_exit(void)
} }
/* /*
* SECTION: Initializing the driver * SECTION: common functions for ccw_driver use
*/ */
static int
dasd_request_module(void *name) /* initial attempt at a probe function. this can be simplified once
* the other detection code is gone */
int
dasd_generic_probe (struct ccw_device *cdev, dasd_discipline_t *discipline)
{ {
int rc = -ERESTARTSYS; int devno;
int ret = 0;
snprintf(cdev->dev.name, DEVICE_NAME_SIZE,
"Direct Access Storage Device");
devno = _ccw_device_get_device_number(cdev);
if (dasd_autodetect
&& (ret = dasd_add_range(devno, devno, DASD_FEATURE_DEFAULT))) {
printk (KERN_WARNING
"dasd_generic_probe: cannot autodetect %s\n",
cdev->dev.bus_id);
return ret;
}
if (!ret && (ret = dasd_add_sysfs_files(cdev))) {
printk(KERN_WARNING
"dasd_generic_probe: could not add driverfs entries"
"for %s\n", cdev->dev.bus_id);
}
cdev->handler = &dasd_int_handler;
if (dasd_autodetect ||
dasd_devmap_from_devno(devno) != 0) {
/* => device was in dasd parameter line */
ccw_device_set_online(cdev);
}
return ret;
}
/* this will one day be called from a global not_oper handler.
* It is also used by driver_unregister during module unload */
int
dasd_generic_remove (struct ccw_device *cdev)
{
struct dasd_device_t *device;
device = cdev->dev.driver_data;
cdev->dev.driver_data = NULL;
if (device)
kfree(device);
return 0;
}
/* activate a device. This is called from dasd_{eckd,fba}_probe() when either
* the device is detected for the first time and is supposed to be used
* or the user has started activation through sysfs */
int
dasd_generic_set_online (struct ccw_device *cdev,
dasd_discipline_t *discipline)
{
int devno;
dasd_devmap_t *devmap;
dasd_device_t *device;
int rc;
if (cdev->dev.driver_data != NULL) /* already enabled */
return 0;
devno = _ccw_device_get_device_number(cdev);
rc = dasd_add_range(devno, devno, DASD_FEATURE_DEFAULT);
if (rc)
return rc;
if (!(devmap = dasd_devmap_from_devno (devno)))
return 0; /* device is still disabled -> ignore it */
if (IS_ERR(device = dasd_get_device(devmap))) {
printk (KERN_WARNING "dasd_generic could not get %s\n",
cdev->dev.bus_id);
return PTR_ERR(device);
}
device->gdp->driverfs_dev = &cdev->dev;
device->cdev = cdev;
if (device->use_diag_flag)
device->discipline = dasd_diag_discipline_pointer;
rc = 0;
if (!device->discipline ||
(rc = device->discipline->check_device(device))) {
pr_debug("device %s is not diag (%d)\n",
cdev->dev.bus_id, rc);
if (device->private != NULL) {
kfree(device->private);
device->private = NULL;
}
device->discipline = discipline;
rc = discipline->check_device(device);
}
if (rc) {
printk (KERN_WARNING "dasd_generic found a bad device %s\n",
cdev->dev.bus_id);
dasd_put_device(devmap);
return rc;
}
strcpy(current->comm, name); dasd_set_target_state(device, DASD_STATE_ONLINE);
daemonize(); if (device->state <= DASD_STATE_KNOWN) {
while (current->fs->root == NULL) /* wait for root-FS */ printk (KERN_WARNING
schedule_timeout(HZ); /* wait a second */ "dasd_generic discipline not found for %s\n",
while ((rc = request_module(name)) != 0) { cdev->dev.bus_id);
MESSAGE(KERN_INFO, "request_module returned %d for %s", rc = -ENODEV;
rc, (char *) name); dasd_set_target_state(device, DASD_STATE_NEW);
schedule_timeout(5 * HZ); /* wait 5 seconds */ } else {
pr_debug("dasd_generic device %s found\n",
cdev->dev.bus_id);
cdev->dev.driver_data = device;
} }
dasd_put_device(devmap);
/* FIXME: we have to wait for the root device but we don't want
* to wait for each single device but for all at once. */
wait_event(dasd_init_waitq, _wait_for_device(device));
return rc; return rc;
} }
int
dasd_generic_set_offline (struct ccw_device *cdev)
{
dasd_device_t *device;
dasd_devmap_t *devmap;
int devno;
devno = _ccw_device_get_device_number(cdev);
device = cdev->dev.driver_data;
devmap = dasd_devmap_from_devno(devno);
if (device == NULL || devmap == NULL)
return -ENODEV;
device = dasd_get_device(devmap);
if (IS_ERR(device))
return PTR_ERR(device);
dasd_set_target_state(device, DASD_STATE_NEW);
dasd_put_device(devmap);
return 0;
}
/*
* SECTION: files in sysfs
*/
/*
* readonly controls the readonly status of a dasd
*/
static ssize_t
dasd_ro_show(struct device *dev, char *buf, size_t count, loff_t off)
{
dasd_device_t *device;
if (off)
return 0;
device = dev->driver_data;
if (!device)
return snprintf(buf, count, "n/a\n");
return snprintf(buf, count, device->ro_flag ? "1\n" : "0\n");
}
static ssize_t
dasd_ro_store(struct device *dev, const char *buf, size_t count, loff_t off)
{
dasd_device_t *device = dev->driver_data;
if (off)
return 0;
if (device)
device->ro_flag = (buf[0] == '1') ? 1 : 0;
return count;
}
static DEVICE_ATTR(readonly, 0644, dasd_ro_show, dasd_ro_store);
/*
* use_diag controls whether the driver should use diag rather than ssch
* to talk to the device
*/
/* TODO: Implement */
static ssize_t
dasd_use_diag_show(struct device *dev, char *buf, size_t count, loff_t off)
{
dasd_device_t *device;
if (off)
return 0;
device = dev->driver_data;
if (!device)
return snprintf(buf, count, "n/a\n");
return snprintf(buf, count, device->use_diag_flag ? "1\n" : "0\n");
}
static ssize_t
dasd_use_diag_store(struct device *dev, const char *buf,
size_t count, loff_t off)
{
dasd_device_t *device = dev->driver_data;
if (off)
return 0;
if (device)
device->use_diag_flag = (buf[0] == '1') ? 1 : 0;
return count;
}
static
DEVICE_ATTR(use_diag, 0644, dasd_use_diag_show, dasd_use_diag_store);
#if 0
/* this file shows the same information as /proc/dasd/devices using
* an inaccaptable interface */
/* TODO: Split this up into smaller files! */
static ssize_t
dasd_devices_show(struct device *dev, char *buf, size_t count, loff_t off)
{
dasd_device_t *device;
dasd_devmap_t *devmap;
if (off) /* ignore partial write */
return 0;
devmap = NULL;
device = dev->driver_data;
if (device)
devmap = dasd_devmap_from_devno(device->devno);
if (!devmap)
return snprintf(buf, count, "unused\n");
return min ((size_t) dasd_devices_print(devmap, buf), count);
}
static DEVICE_ATTR(dasd, 0444, dasd_devices_show, 0);
#endif
static ssize_t
dasd_discipline_show(struct device *dev, char *buf, size_t count, loff_t off)
{
dasd_device_t *device;
if (off)
return 0;
device = dev->driver_data;
if (!device || !device->discipline)
return snprintf(buf, count, "none\n");
return snprintf(buf, count, "%s\n", device->discipline->name);
}
static DEVICE_ATTR(discipline, 0444, dasd_discipline_show, 0);
static int
dasd_add_sysfs_files(struct ccw_device *cdev)
{
int ret;
if (/* (ret = device_create_file(&cdev->dev, &dev_attr_dasd)) || */
(ret = device_create_file(&cdev->dev, &dev_attr_readonly)) ||
(ret = device_create_file(&cdev->dev, &dev_attr_discipline)) ||
(ret = device_create_file(&cdev->dev, &dev_attr_use_diag))) {
device_remove_file(&cdev->dev, &dev_attr_discipline);
device_remove_file(&cdev->dev, &dev_attr_readonly);
/* device_remove_file(&cdev->dev, &dev_attr_dasd); */
}
return ret;
}
static int __init static int __init
dasd_init(void) dasd_init(void)
{ {
char **disc;
int irq, devno;
int rc; int rc;
init_waitqueue_head(&dasd_init_waitq); init_waitqueue_head(&dasd_init_waitq);
...@@ -2235,7 +2093,7 @@ dasd_init(void) ...@@ -2235,7 +2093,7 @@ dasd_init(void)
DBF_EVENT(DBF_EMERG, "%s", "debug area created"); DBF_EVENT(DBF_EMERG, "%s", "debug area created");
if (!devfs_mk_dir(NULL, "dasd", NULL)) { if (devfs_mk_dir(NULL, "dasd", NULL)) {
DBF_EVENT(DBF_ALERT, "%s", "no devfs"); DBF_EVENT(DBF_ALERT, "%s", "no devfs");
rc = -ENOSYS; rc = -ENOSYS;
goto failed; goto failed;
...@@ -2258,60 +2116,6 @@ dasd_init(void) ...@@ -2258,60 +2116,6 @@ dasd_init(void)
goto failed; goto failed;
#endif #endif
if (dasd_autodetect) {
/* update device range to all devices */
irq = get_irq_first();
while (irq != -ENODEV) {
devno = get_devno_by_irq(irq);
if (dasd_devmap_from_devno(devno) == NULL) {
/* devno not included yet */
DBF_EVENT(DBF_NOTICE, "add %04x to range",
devno);
dasd_add_range(devno, devno,
DASD_FEATURE_DEFAULT);
}
irq = get_irq_next(irq);
}
}
if (MACHINE_IS_VM) {
#ifdef CONFIG_DASD_DIAG
rc = dasd_diag_init();
if (rc != 0) {
DBF_EVENT(DBF_ALERT, "%s",
"Register DIAG discipline failed");
goto failed;
}
#endif /* CONFIG_DASD_DIAG */
#if defined(CONFIG_DASD_DIAG_MODULE) && defined(CONFIG_DASD_AUTO_DIAG)
kernel_thread(dasd_request_module, "dasd_diag_mod", SIGCHLD);
#endif
}
#ifdef CONFIG_DASD_ECKD
rc = dasd_eckd_init();
if (rc != 0) {
DBF_EVENT(DBF_ALERT, "%s", "Register ECKD discipline failed");
goto failed;
}
#endif /* CONFIG_DASD_ECKD */
#if defined(CONFIG_DASD_ECKD_MODULE) && defined(CONFIG_DASD_AUTO_ECKD)
kernel_thread(dasd_request_module, "dasd_eckd_mod", SIGCHLD);
#endif
#ifdef CONFIG_DASD_FBA
rc = dasd_fba_init();
if (rc != 0) {
DBF_EVENT(DBF_ALERT, "%s", "Register FBA discipline failed");
goto failed;
}
#endif
#if defined(CONFIG_DASD_FBA_MODULE) && defined(CONFIG_DASD_AUTO_FBA)
kernel_thread(dasd_request_module, "dasd_fba_mod", SIGCHLD);
#endif /* CONFIG_DASD_AUTO_FBA */
disc = dasd_disciplines;
while (*disc) {
kernel_thread(dasd_request_module, *disc, SIGCHLD);
disc++;
}
return 0; return 0;
failed: failed:
MESSAGE(KERN_INFO, "%s", "initialization not performed due to errors"); MESSAGE(KERN_INFO, "%s", "initialization not performed due to errors");
...@@ -2328,16 +2132,11 @@ EXPORT_SYMBOL(dasd_add_request_head); ...@@ -2328,16 +2132,11 @@ EXPORT_SYMBOL(dasd_add_request_head);
EXPORT_SYMBOL(dasd_add_request_tail); EXPORT_SYMBOL(dasd_add_request_tail);
EXPORT_SYMBOL(dasd_cancel_req); EXPORT_SYMBOL(dasd_cancel_req);
EXPORT_SYMBOL(dasd_clear_timer); EXPORT_SYMBOL(dasd_clear_timer);
EXPORT_SYMBOL(dasd_disable_devices); EXPORT_SYMBOL(dasd_enable_device);
EXPORT_SYMBOL(dasd_discipline_add);
EXPORT_SYMBOL(dasd_discipline_del);
EXPORT_SYMBOL(dasd_enable_devices);
EXPORT_SYMBOL(dasd_int_handler); EXPORT_SYMBOL(dasd_int_handler);
EXPORT_SYMBOL(dasd_kfree_request); EXPORT_SYMBOL(dasd_kfree_request);
EXPORT_SYMBOL(dasd_kick_device); EXPORT_SYMBOL(dasd_kick_device);
EXPORT_SYMBOL(dasd_kmalloc_request); EXPORT_SYMBOL(dasd_kmalloc_request);
EXPORT_SYMBOL(dasd_not_oper_handler);
EXPORT_SYMBOL(dasd_oper_handler);
EXPORT_SYMBOL(dasd_schedule_bh); EXPORT_SYMBOL(dasd_schedule_bh);
EXPORT_SYMBOL(dasd_set_target_state); EXPORT_SYMBOL(dasd_set_target_state);
EXPORT_SYMBOL(dasd_set_timer); EXPORT_SYMBOL(dasd_set_timer);
......
...@@ -3,6 +3,11 @@ ...@@ -3,6 +3,11 @@
* Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
* Bugreports.to..: <Linux390@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
*
* $Revision: 1.7 $
*
* History of changes
*
*/ */
#define PRINTK_HEADER "dasd_erp(3370)" #define PRINTK_HEADER "dasd_erp(3370)"
...@@ -27,13 +32,13 @@ ...@@ -27,13 +32,13 @@
* dasd_era_recover for all others. * dasd_era_recover for all others.
*/ */
dasd_era_t dasd_era_t
dasd_3370_erp_examine(dasd_ccw_req_t * cqr, devstat_t * stat) dasd_3370_erp_examine(dasd_ccw_req_t * cqr, struct irb * irb)
{ {
char *sense = stat->ii.sense.data; char *sense = irb->ecw;
/* check for successful execution first */ /* check for successful execution first */
if (stat->cstat == 0x00 && if (irb->scsw.cstat == 0x00 &&
stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
return dasd_era_none; return dasd_era_none;
if (sense[0] & 0x80) { /* CMD reject */ if (sense[0] & 0x80) { /* CMD reject */
return dasd_era_fatal; return dasd_era_fatal;
......
/*
* File...........: linux/drivers/s390/block/dasd_3370_erp.h
* Author(s)......: Horst Hummel <Horst Hummel@de.ibm.com>
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
*
* History of changes (starts July 2000)
*/
#ifndef DASD_3370_ERP_H
#define DASD_3370_ERP_H
dasd_era_t dasd_3370_erp_examine(dasd_ccw_req_t *, devstat_t *);
#endif /* DASD_3990_ERP_H */
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
* 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.19 $
*
* History of changes: * History of changes:
* 05/14/01 fixed PL030160GTO (BUG() in erp_action_5) * 05/14/01 fixed PL030160GTO (BUG() in erp_action_5)
* 05/04/02 code restructuring. * 05/04/02 code restructuring.
...@@ -13,7 +15,6 @@ ...@@ -13,7 +15,6 @@
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <asm/idals.h> #include <asm/idals.h>
#include <asm/s390io.h>
#include <asm/todclk.h> #include <asm/todclk.h>
#define PRINTK_HEADER "dasd_erp(3990): " #define PRINTK_HEADER "dasd_erp(3990): "
...@@ -148,16 +149,16 @@ dasd_3990_erp_examine_32(dasd_ccw_req_t * cqr, char *sense) ...@@ -148,16 +149,16 @@ dasd_3990_erp_examine_32(dasd_ccw_req_t * cqr, char *sense)
* dasd_era_recover for all others. * dasd_era_recover for all others.
*/ */
dasd_era_t dasd_era_t
dasd_3990_erp_examine(dasd_ccw_req_t * cqr, devstat_t * stat) dasd_3990_erp_examine(dasd_ccw_req_t * cqr, struct irb * irb)
{ {
char *sense = stat->ii.sense.data; char *sense = irb->ecw;
dasd_era_t era = dasd_era_recover; dasd_era_t era = dasd_era_recover;
dasd_device_t *device = cqr->device; dasd_device_t *device = cqr->device;
/* check for successful execution first */ /* check for successful execution first */
if (stat->cstat == 0x00 && if (irb->scsw.cstat == 0x00 &&
stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
return dasd_era_none; return dasd_era_none;
/* distinguish between 24 and 32 byte sense data */ /* distinguish between 24 and 32 byte sense data */
...@@ -172,8 +173,10 @@ dasd_3990_erp_examine(dasd_ccw_req_t * cqr, devstat_t * stat) ...@@ -172,8 +173,10 @@ dasd_3990_erp_examine(dasd_ccw_req_t * cqr, devstat_t * stat)
} }
/* log the erp chain if fatal error occurred */ /* log the erp chain if fatal error occurred */
if ((era == dasd_era_fatal) && (device->state >= DASD_STATE_READY)) if ((era == dasd_era_fatal) && (device->state >= DASD_STATE_READY)) {
dasd_log_ccw(cqr, 0, stat->cpa); dasd_log_sense(cqr, irb);
dasd_log_ccw(cqr, 0, irb->scsw.cpa);
}
return era; return era;
...@@ -296,42 +299,39 @@ dasd_3990_erp_int_req(dasd_ccw_req_t * erp) ...@@ -296,42 +299,39 @@ dasd_3990_erp_int_req(dasd_ccw_req_t * erp)
* *
* RETURN VALUES * RETURN VALUES
* erp modified pointer to the ERP * erp modified pointer to the ERP
*
*/ */
static void static void
dasd_3990_erp_alternate_path(dasd_ccw_req_t * erp) dasd_3990_erp_alternate_path(dasd_ccw_req_t * erp)
{ {
dasd_device_t *device = erp->device; dasd_device_t *device = erp->device;
int irq = device->devinfo.irq; __u8 opm;
/* try alternate valid path */ /* try alternate valid path */
erp->lpm &= ~(erp->dstat->lpum); opm = ccw_device_get_path_mask(device->cdev);
erp->options |= DOIO_VALID_LPM; /* use LPM for DO_IO */ //FIXME: start with get_opm ?
if (erp->lpm == 0)
erp->lpm = LPM_ANYPATH & ~(erp->dstat->esw.esw0.sublog.lpum);
else
erp->lpm &= ~(erp->dstat->esw.esw0.sublog.lpum);
if ((erp->lpm & ioinfo[irq]->opm) != 0x00) { if ((erp->lpm & opm) != 0x00) {
DEV_MESSAGE(KERN_DEBUG, device, DEV_MESSAGE(KERN_DEBUG, device,
"try alternate lpm=%x (lpum=%x / opm=%x)", "try alternate lpm=%x (lpum=%x / opm=%x)",
erp->lpm, erp->dstat->lpum, ioinfo[irq]->opm); erp->lpm, erp->dstat->esw.esw0.sublog.lpum, opm);
/* reset status to queued to handle the request again... */ /* reset status to queued to handle the request again... */
erp->status = DASD_CQR_QUEUED; erp->status = DASD_CQR_QUEUED;
erp->retries = 1; erp->retries = 1;
} else { } else {
DEV_MESSAGE(KERN_ERR, device, DEV_MESSAGE(KERN_ERR, device,
"No alternate channel path left (lpum=%x / " "No alternate channel path left (lpum=%x / "
"opm=%x) -> permanent error", "opm=%x) -> permanent error",
erp->dstat->lpum, ioinfo[irq]->opm); erp->dstat->esw.esw0.sublog.lpum, opm);
/* post request with permanent error */ /* post request with permanent error */
erp->status = DASD_CQR_FAILED; erp->status = DASD_CQR_FAILED;
} }
} /* end dasd_3990_erp_alternate_path */ } /* end dasd_3990_erp_alternate_path */
/* /*
...@@ -355,7 +355,7 @@ dasd_3990_erp_DCTL(dasd_ccw_req_t * erp, char modifier) ...@@ -355,7 +355,7 @@ dasd_3990_erp_DCTL(dasd_ccw_req_t * erp, char modifier)
dasd_device_t *device = erp->device; dasd_device_t *device = erp->device;
DCTL_data_t *DCTL_data; DCTL_data_t *DCTL_data;
ccw1_t *ccw; struct ccw1 *ccw;
dasd_ccw_req_t *dctl_cqr; dasd_ccw_req_t *dctl_cqr;
dctl_cqr = dasd_alloc_erp_request((char *) &erp->magic, 1, dctl_cqr = dasd_alloc_erp_request((char *) &erp->magic, 1,
...@@ -373,7 +373,7 @@ dasd_3990_erp_DCTL(dasd_ccw_req_t * erp, char modifier) ...@@ -373,7 +373,7 @@ dasd_3990_erp_DCTL(dasd_ccw_req_t * erp, char modifier)
DCTL_data->modifier = modifier; DCTL_data->modifier = modifier;
ccw = dctl_cqr->cpaddr; ccw = dctl_cqr->cpaddr;
memset(ccw, 0, sizeof (ccw1_t)); memset(ccw, 0, sizeof (struct ccw1));
ccw->cmd_code = CCW_CMD_DCTL; ccw->cmd_code = CCW_CMD_DCTL;
ccw->count = 4; ccw->count = 4;
ccw->cda = (__u32)(addr_t) DCTL_data; ccw->cda = (__u32)(addr_t) DCTL_data;
...@@ -381,7 +381,6 @@ dasd_3990_erp_DCTL(dasd_ccw_req_t * erp, char modifier) ...@@ -381,7 +381,6 @@ dasd_3990_erp_DCTL(dasd_ccw_req_t * erp, char modifier)
dctl_cqr->refers = erp; dctl_cqr->refers = erp;
dctl_cqr->device = erp->device; dctl_cqr->device = erp->device;
dctl_cqr->magic = erp->magic; dctl_cqr->magic = erp->magic;
dctl_cqr->lpm = LPM_ANYPATH;
dctl_cqr->expires = 5 * 60 * HZ; dctl_cqr->expires = 5 * 60 * HZ;
dctl_cqr->retries = 2; dctl_cqr->retries = 2;
...@@ -1122,6 +1121,9 @@ dasd_3990_handle_env_data(dasd_ccw_req_t * erp, char *sense) ...@@ -1122,6 +1121,9 @@ dasd_3990_handle_env_data(dasd_ccw_req_t * erp, char *sense)
break; break;
default: /* unknown message format - should not happen */ default: /* unknown message format - should not happen */
DEV_MESSAGE (KERN_WARNING, device,
"unknown message format %02x",
msg_format);
break; break;
} /* end switch message format */ } /* end switch message format */
...@@ -1650,7 +1652,7 @@ dasd_3990_erp_action_1B_32(dasd_ccw_req_t * default_erp, char *sense) ...@@ -1650,7 +1652,7 @@ dasd_3990_erp_action_1B_32(dasd_ccw_req_t * default_erp, char *sense)
dasd_ccw_req_t *erp; dasd_ccw_req_t *erp;
DE_eckd_data_t *DE_data; DE_eckd_data_t *DE_data;
char *LO_data; /* LO_eckd_data_t */ char *LO_data; /* LO_eckd_data_t */
ccw1_t *ccw; struct ccw1 *ccw;
DEV_MESSAGE(KERN_DEBUG, device, "%s", DEV_MESSAGE(KERN_DEBUG, device, "%s",
"Write not finished because of unexpected condition"); "Write not finished because of unexpected condition");
...@@ -1675,7 +1677,7 @@ dasd_3990_erp_action_1B_32(dasd_ccw_req_t * default_erp, char *sense) ...@@ -1675,7 +1677,7 @@ dasd_3990_erp_action_1B_32(dasd_ccw_req_t * default_erp, char *sense)
/* determine the address of the CCW to be restarted */ /* determine the address of the CCW to be restarted */
/* Imprecise ending is not set -> addr from IRB-SCSW */ /* Imprecise ending is not set -> addr from IRB-SCSW */
cpa = default_erp->refers->dstat->cpa; cpa = default_erp->refers->dstat->scsw.cpa;
if (cpa == 0) { if (cpa == 0) {
...@@ -1735,7 +1737,7 @@ dasd_3990_erp_action_1B_32(dasd_ccw_req_t * default_erp, char *sense) ...@@ -1735,7 +1737,7 @@ dasd_3990_erp_action_1B_32(dasd_ccw_req_t * default_erp, char *sense)
/* create DE ccw */ /* create DE ccw */
ccw = erp->cpaddr; ccw = erp->cpaddr;
memset(ccw, 0, sizeof (ccw1_t)); memset(ccw, 0, sizeof (struct ccw1));
ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT; ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT;
ccw->flags = CCW_FLAG_CC; ccw->flags = CCW_FLAG_CC;
ccw->count = 16; ccw->count = 16;
...@@ -1743,7 +1745,7 @@ dasd_3990_erp_action_1B_32(dasd_ccw_req_t * default_erp, char *sense) ...@@ -1743,7 +1745,7 @@ dasd_3990_erp_action_1B_32(dasd_ccw_req_t * default_erp, char *sense)
/* create LO ccw */ /* create LO ccw */
ccw++; ccw++;
memset(ccw, 0, sizeof (ccw1_t)); memset(ccw, 0, sizeof (struct ccw1));
ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD; ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD;
ccw->flags = CCW_FLAG_CC; ccw->flags = CCW_FLAG_CC;
ccw->count = 16; ccw->count = 16;
...@@ -1759,7 +1761,6 @@ dasd_3990_erp_action_1B_32(dasd_ccw_req_t * default_erp, char *sense) ...@@ -1759,7 +1761,6 @@ dasd_3990_erp_action_1B_32(dasd_ccw_req_t * default_erp, char *sense)
erp->refers = default_erp->refers; erp->refers = default_erp->refers;
erp->device = device; erp->device = device;
erp->magic = default_erp->magic; erp->magic = default_erp->magic;
erp->lpm = 0xFF;
erp->expires = 0; erp->expires = 0;
erp->retries = 256; erp->retries = 256;
erp->status = DASD_CQR_FILLED; erp->status = DASD_CQR_FILLED;
...@@ -1795,7 +1796,7 @@ dasd_3990_update_1B(dasd_ccw_req_t * previous_erp, char *sense) ...@@ -1795,7 +1796,7 @@ dasd_3990_update_1B(dasd_ccw_req_t * previous_erp, char *sense)
dasd_ccw_req_t *cqr; dasd_ccw_req_t *cqr;
dasd_ccw_req_t *erp; dasd_ccw_req_t *erp;
char *LO_data; /* LO_eckd_data_t */ char *LO_data; /* LO_eckd_data_t */
ccw1_t *ccw; struct ccw1 *ccw;
DEV_MESSAGE(KERN_DEBUG, device, "%s", DEV_MESSAGE(KERN_DEBUG, device, "%s",
"Write not finished because of unexpected condition" "Write not finished because of unexpected condition"
...@@ -1821,7 +1822,7 @@ dasd_3990_update_1B(dasd_ccw_req_t * previous_erp, char *sense) ...@@ -1821,7 +1822,7 @@ dasd_3990_update_1B(dasd_ccw_req_t * previous_erp, char *sense)
/* determine the address of the CCW to be restarted */ /* determine the address of the CCW to be restarted */
/* Imprecise ending is not set -> addr from IRB-SCSW */ /* Imprecise ending is not set -> addr from IRB-SCSW */
cpa = previous_erp->dstat->cpa; cpa = previous_erp->dstat->scsw.cpa;
if (cpa == 0) { if (cpa == 0) {
...@@ -1954,7 +1955,7 @@ dasd_3990_erp_compound_path(dasd_ccw_req_t * erp, char *sense) ...@@ -1954,7 +1955,7 @@ dasd_3990_erp_compound_path(dasd_ccw_req_t * erp, char *sense)
/* reset the lpm and the status to be able to /* reset the lpm and the status to be able to
* try further actions. */ * try further actions. */
erp->lpm = LPM_ANYPATH; erp->lpm = 0;
erp->status = DASD_CQR_ERROR; erp->status = DASD_CQR_ERROR;
...@@ -2234,7 +2235,7 @@ dasd_3990_erp_inspect(dasd_ccw_req_t * erp) ...@@ -2234,7 +2235,7 @@ dasd_3990_erp_inspect(dasd_ccw_req_t * erp)
dasd_ccw_req_t *erp_new = NULL; dasd_ccw_req_t *erp_new = NULL;
/* sense data are located in the refers record of the */ /* sense data are located in the refers record of the */
/* already set up new ERP ! */ /* already set up new ERP ! */
char *sense = erp->refers->dstat->ii.sense.data; char *sense = erp->refers->dstat->ecw;
/* distinguish between 24 and 32 byte sense data */ /* distinguish between 24 and 32 byte sense data */
if (sense[27] & DASD_SENSE_BIT_0) { if (sense[27] & DASD_SENSE_BIT_0) {
...@@ -2291,7 +2292,6 @@ dasd_3990_erp_add_erp(dasd_ccw_req_t * cqr) ...@@ -2291,7 +2292,6 @@ dasd_3990_erp_add_erp(dasd_ccw_req_t * cqr)
erp->refers = cqr; erp->refers = cqr;
erp->device = cqr->device; erp->device = cqr->device;
erp->magic = cqr->magic; erp->magic = cqr->magic;
erp->lpm = 0xFF;
erp->expires = 0; erp->expires = 0;
erp->retries = 256; erp->retries = 256;
...@@ -2357,18 +2357,14 @@ dasd_3990_erp_error_match(dasd_ccw_req_t * cqr1, dasd_ccw_req_t * cqr2) ...@@ -2357,18 +2357,14 @@ dasd_3990_erp_error_match(dasd_ccw_req_t * cqr1, dasd_ccw_req_t * cqr2)
{ {
/* check failed CCW */ /* check failed CCW */
if (cqr1->dstat->cpa != cqr2->dstat->cpa) { if (cqr1->dstat->scsw.cpa != cqr2->dstat->scsw.cpa) {
// return 0; /* CCW doesn't match */ // return 0; /* CCW doesn't match */
} }
/* check sense data; byte 0-2,25,27 */ /* check sense data; byte 0-2,25,27 */
if (!((strncmp(cqr1->dstat->ii.sense.data, if (!((strncmp(cqr1->dstat->ecw, cqr2->dstat->ecw, 3) == 0) &&
cqr2->dstat->ii.sense.data, (cqr1->dstat->ecw[27] == cqr2->dstat->ecw[27]) &&
3) == 0) && (cqr1->dstat->ecw[25] == cqr2->dstat->ecw[25]))) {
(cqr1->dstat->ii.sense.data[27] ==
cqr2->dstat->ii.sense.data[27]) &&
(cqr1->dstat->ii.sense.data[25] ==
cqr2->dstat->ii.sense.data[25]))) {
return 0; /* sense doesn't match */ return 0; /* sense doesn't match */
} }
...@@ -2441,7 +2437,7 @@ dasd_3990_erp_further_erp(dasd_ccw_req_t * erp) ...@@ -2441,7 +2437,7 @@ dasd_3990_erp_further_erp(dasd_ccw_req_t * erp)
{ {
dasd_device_t *device = erp->device; dasd_device_t *device = erp->device;
char *sense = erp->dstat->ii.sense.data; char *sense = erp->dstat->ecw;
/* check for 24 byte sense ERP */ /* check for 24 byte sense ERP */
if ((erp->function == dasd_3990_erp_bus_out) || if ((erp->function == dasd_3990_erp_bus_out) ||
...@@ -2553,7 +2549,7 @@ dasd_3990_erp_handle_match_erp(dasd_ccw_req_t * erp_head, dasd_ccw_req_t * erp) ...@@ -2553,7 +2549,7 @@ dasd_3990_erp_handle_match_erp(dasd_ccw_req_t * erp_head, dasd_ccw_req_t * erp)
if (erp->retries > 0) { if (erp->retries > 0) {
char *sense = erp->dstat->ii.sense.data; char *sense = erp->dstat->ecw;
/* check for special retries */ /* check for special retries */
if (erp->function == dasd_3990_erp_action_4) { if (erp->function == dasd_3990_erp_action_4) {
...@@ -2611,7 +2607,7 @@ dasd_3990_erp_action(dasd_ccw_req_t * cqr) ...@@ -2611,7 +2607,7 @@ dasd_3990_erp_action(dasd_ccw_req_t * cqr)
dasd_ccw_req_t *erp = NULL; dasd_ccw_req_t *erp = NULL;
dasd_device_t *device = cqr->device; dasd_device_t *device = cqr->device;
__u32 cpa = cqr->dstat->cpa; __u32 cpa = cqr->dstat->scsw.cpa;
#ifdef ERP_DEBUG #ifdef ERP_DEBUG
/* print current erp_chain */ /* print current erp_chain */
...@@ -2631,8 +2627,8 @@ dasd_3990_erp_action(dasd_ccw_req_t * cqr) ...@@ -2631,8 +2627,8 @@ dasd_3990_erp_action(dasd_ccw_req_t * cqr)
#endif /* ERP_DEBUG */ #endif /* ERP_DEBUG */
/* double-check if current erp/cqr was successfull */ /* double-check if current erp/cqr was successfull */
if ((cqr->dstat->cstat == 0x00) && if ((cqr->dstat->scsw.cstat == 0x00) &&
(cqr->dstat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))) { (cqr->dstat->scsw.dstat == (DEV_STAT_CHN_END|DEV_STAT_DEV_END))) {
DEV_MESSAGE(KERN_DEBUG, device, DEV_MESSAGE(KERN_DEBUG, device,
"ERP called for successful request %p" "ERP called for successful request %p"
...@@ -2643,7 +2639,7 @@ dasd_3990_erp_action(dasd_ccw_req_t * cqr) ...@@ -2643,7 +2639,7 @@ dasd_3990_erp_action(dasd_ccw_req_t * cqr)
return cqr; return cqr;
} }
/* check if sense data are available */ /* check if sense data are available */
if (!cqr->dstat->ii.sense.data) { if (!cqr->dstat->ecw) {
DEV_MESSAGE(KERN_DEBUG, device, DEV_MESSAGE(KERN_DEBUG, device,
"ERP called witout sense data avail ..." "ERP called witout sense data avail ..."
"request %p - NO ERP possible", cqr); "request %p - NO ERP possible", cqr);
......
/*
* File...........: linux/drivers/s390/block/dasd_3990_erp.h
* Author(s)......: Horst Hummel <Horst Hummel@de.ibm.com>
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
*
* History of changes (starts July 2000)
*/
#ifndef DASD_3990_ERP_H
#define DASD_3990_ERP_H
dasd_era_t dasd_3990_erp_examine(dasd_ccw_req_t *, devstat_t *);
dasd_ccw_req_t *dasd_3990_erp_action(dasd_ccw_req_t *);
dasd_ccw_req_t *dasd_2105_erp_action(ccw_req_t *);
void dasd_3990_erp_restart_queue(unsigned long);
typedef struct DCTL_data_t {
unsigned char subcommand; /* e.g Inhibit Write, Enable Write,... */
unsigned char modifier; /* Subcommand modifier */
unsigned short res; /* reserved */
} __attribute__ ((packed)) DCTL_data_t;
#endif /* DASD_3990_ERP_H */
...@@ -3,6 +3,11 @@ ...@@ -3,6 +3,11 @@
* Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
* Bugreports.to..: <Linux390@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
*
* $Revision: 1.6 $
*
* History of changes
*
*/ */
#define PRINTK_HEADER "dasd_erp(9336)" #define PRINTK_HEADER "dasd_erp(9336)"
...@@ -27,11 +32,11 @@ ...@@ -27,11 +32,11 @@
* dasd_era_recover for all others. * dasd_era_recover for all others.
*/ */
dasd_era_t dasd_era_t
dasd_9336_erp_examine(dasd_ccw_req_t * cqr, devstat_t * stat) dasd_9336_erp_examine(dasd_ccw_req_t * cqr, struct irb * irb)
{ {
/* check for successful execution first */ /* check for successful execution first */
if (stat->cstat == 0x00 && if (irb->scsw.cstat == 0x00 &&
stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
return dasd_era_none; return dasd_era_none;
/* examine the 24 byte sense data */ /* examine the 24 byte sense data */
......
/*
* File...........: linux/drivers/s390/block/dasd_9336_erp.h
* Author(s)......: Horst Hummel <Horst Hummel@de.ibm.com>
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
*
* History of changes (starts July 2000)
*/
#ifndef DASD_9336_ERP_H
#define DASD_9336_ERP_H
dasd_era_t dasd_9336_erp_examine(dasd_ccw_req_t *, devstat_t *);
#endif /* DASD_3990_ERP_H */
/* /*
* File...........: linux/drivers/s390/block/dasd_9345_erp.h * File...........: linux/drivers/s390/block/dasd_9345_erp.c
* Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
* Bugreports.to..: <Linux390@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
*
* $Revision: 1.11 $
*
* History of changes
*
*/ */
#define PRINTK_HEADER "dasd_erp(9343)" #define PRINTK_HEADER "dasd_erp(9343)"
...@@ -10,10 +15,11 @@ ...@@ -10,10 +15,11 @@
#include "dasd_int.h" #include "dasd_int.h"
dasd_era_t dasd_era_t
dasd_9343_erp_examine(dasd_ccw_req_t * cqr, devstat_t * stat) dasd_9343_erp_examine(dasd_ccw_req_t * cqr, struct irb * irb)
{ {
if (stat->cstat == 0x00 && if (irb->scsw.cstat == 0x00 &&
stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
return dasd_era_none; return dasd_era_none;
return dasd_era_recover; return dasd_era_recover;
} }
/*
* File...........: linux/drivers/s390/block/dasd_9343_erp.h
* Author(s)......: Horst Hummel <Horst Hummel@de.ibm.com>
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
*
* History of changes (starts July 2000)
*/
#ifndef DASD_9343_ERP_H
#define DASD_9343_ERP_H
dasd_era_t dasd_9343_erp_examine(dasd_ccw_req_t *, devstat_t *);
dasd_ccw_req_t *dasd_9343_erp_action(dasd_ccw_req_t *);
#endif /* DASD_9343_ERP_H */
...@@ -11,6 +11,9 @@ ...@@ -11,6 +11,9 @@
* functions may not be called from interrupt context. In particular * functions may not be called from interrupt context. In particular
* dasd_get_device is a no-no from interrupt context. * dasd_get_device is a no-no from interrupt context.
* *
* $Revision: 1.11 $
*
* History of changes
* 05/04/02 split from dasd.c, code restructuring. * 05/04/02 split from dasd.c, code restructuring.
*/ */
...@@ -20,7 +23,6 @@ ...@@ -20,7 +23,6 @@
#include <linux/init.h> #include <linux/init.h>
#include <asm/debug.h> #include <asm/debug.h>
#include <asm/irq.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
/* This is ugly... */ /* This is ugly... */
...@@ -84,9 +86,11 @@ __setup ("dasd=", dasd_call_setup); ...@@ -84,9 +86,11 @@ __setup ("dasd=", dasd_call_setup);
* Read a device number from a string. The number is always in hex, * Read a device number from a string. The number is always in hex,
* a leading 0x is accepted. * a leading 0x is accepted.
*/ */
int static inline int
dasd_devno(char *str, char **endp) dasd_devno(char *str, char **endp)
{ {
int val;
/* remove leading '0x' */ /* remove leading '0x' */
if (*str == '0') { if (*str == '0') {
str++; str++;
...@@ -96,7 +100,10 @@ dasd_devno(char *str, char **endp) ...@@ -96,7 +100,10 @@ dasd_devno(char *str, char **endp)
/* We require at least one hex digit */ /* We require at least one hex digit */
if (!isxdigit(*str)) if (!isxdigit(*str))
return -EINVAL; return -EINVAL;
return simple_strtoul(str, endp, 16); val = simple_strtoul(str, endp, 16);
if ((val > 0xFFFF) || (val < 0))
return -EINVAL;
return val;
} }
/* /*
...@@ -104,7 +111,7 @@ dasd_devno(char *str, char **endp) ...@@ -104,7 +111,7 @@ dasd_devno(char *str, char **endp)
* only one: "ro" for read-only devices. The default feature set * only one: "ro" for read-only devices. The default feature set
* is empty (value 0). * is empty (value 0).
*/ */
int static inline int
dasd_feature_list(char *str, char **endp) dasd_feature_list(char *str, char **endp)
{ {
int features, len, rc; int features, len, rc;
...@@ -260,64 +267,12 @@ dasd_add_range(int from, int to, int features) ...@@ -260,64 +267,12 @@ dasd_add_range(int from, int to, int features)
devmap->devindex = devindex; devmap->devindex = devindex;
devmap->devno = devno; devmap->devno = devno;
devmap->features = features; devmap->features = features;
devmap->devreg = NULL;
devmap->device = NULL; devmap->device = NULL;
list_add(&devmap->devindex_list, list_add(&devmap->devindex_list,
&dasd_devindex_hashlists[devindex & 255]); &dasd_devindex_hashlists[devindex & 255]);
list_add(&devmap->devno_list, list_add(&devmap->devno_list,
&dasd_devno_hashlists[devno & 255]); &dasd_devno_hashlists[devno & 255]);
} }
if (devmap->devreg == NULL) {
/* The devreg is missing. */
devmap->devreg = (devreg_t *)
kmalloc(sizeof(devreg_t), GFP_KERNEL);
if (devmap->devreg == NULL)
return -ENOMEM;
memset(devmap->devreg, sizeof(devreg_t), 0);
devmap->devreg->ci.devno = devno;
devmap->devreg->flag = DEVREG_TYPE_DEVNO;
devmap->devreg->oper_func = dasd_oper_handler;
s390_device_register(devmap->devreg);
}
}
spin_unlock(&dasd_devmap_lock);
return 0;
}
/*
* Removes the devreg_t structures for a range of devices. This does
* NOT remove the range itself. The mapping between devno and kdevs
* for the devices is remembered until dasd_forget_ranges() is called.
*/
static int
dasd_clear_range(int from, int to)
{
int devno;
if (from > to) {
MESSAGE(KERN_ERR,
"Invalid device range %04x-%04x", from, to);
return -EINVAL;
}
spin_lock(&dasd_devmap_lock);
for (devno = from; devno <= to; devno++) {
struct list_head *l;
dasd_devmap_t *devmap = NULL;
/* Find previous devmap for device number i */
list_for_each(l, &dasd_devno_hashlists[devno & 255]) {
devmap = list_entry(l, dasd_devmap_t, devno_list);
if (devmap->devno == devno)
break;
}
if (devmap == NULL)
continue;
if (devmap->device != NULL)
BUG();
if (devmap->devreg == NULL)
continue;
s390_device_unregister(devmap->devreg);
kfree(devmap->devreg);
devmap->devreg = NULL;
} }
spin_unlock(&dasd_devmap_lock); spin_unlock(&dasd_devmap_lock);
return 0; return 0;
...@@ -340,11 +295,6 @@ dasd_forget_ranges(void) ...@@ -340,11 +295,6 @@ dasd_forget_ranges(void)
devmap = list_entry(l, dasd_devmap_t, devno_list); devmap = list_entry(l, dasd_devmap_t, devno_list);
if (devmap->device != NULL) if (devmap->device != NULL)
BUG(); BUG();
if (devmap->devreg != NULL) {
s390_device_unregister(devmap->devreg);
kfree(devmap->devreg);
devmap->devreg = NULL;
}
list_del(&devmap->devindex_list); list_del(&devmap->devindex_list);
list_del(&devmap->devno_list); list_del(&devmap->devno_list);
kfree(devmap); kfree(devmap);
...@@ -403,52 +353,6 @@ dasd_devmap_from_devindex(int devindex) ...@@ -403,52 +353,6 @@ dasd_devmap_from_devindex(int devindex)
return devmap; return devmap;
} }
/*
* Find the devmap for a device by its irq line.
*/
dasd_devmap_t *
dasd_devmap_from_irq(int irq)
{
struct list_head *l;
dasd_devmap_t *devmap, *tmp;
int i;
devmap = NULL;
spin_lock(&dasd_devmap_lock);
for (i = 0; (i < 256) && (devmap == NULL); i++) {
list_for_each(l, &dasd_devno_hashlists[i & 255]) {
tmp = list_entry(l, dasd_devmap_t, devno_list);
if (tmp->device != NULL &&
tmp->device->devinfo.irq == irq) {
devmap = tmp;
break;
}
}
}
spin_unlock(&dasd_devmap_lock);
return devmap;
}
/*
* Find the devmap for a device corresponding to a block_device.
*/
dasd_devmap_t *
dasd_devmap_from_bdev(struct block_device *bdev)
{
kdev_t kdev = to_kdev_t(bdev->bd_dev);
int devindex;
/* Find the devindex for kdev. */
devindex = dasd_gendisk_major_index(major(kdev));
if (devindex < 0)
/* No such major -> no devmap */
return NULL;
devindex += minor(kdev) >> DASD_PARTN_BITS;
/* Now find the devmap by the devindex. */
return dasd_devmap_from_devindex(devindex);
}
/* /*
* Find the device structure for device number devno. If it does not * Find the device structure for device number devno. If it does not
* exists yet, allocate it. Increase the reference counter in the device * exists yet, allocate it. Increase the reference counter in the device
...@@ -479,6 +383,8 @@ dasd_get_device(dasd_devmap_t *devmap) ...@@ -479,6 +383,8 @@ dasd_get_device(dasd_devmap_t *devmap)
} else } else
devmap->device = device; devmap->device = device;
atomic_inc(&device->ref_count); atomic_inc(&device->ref_count);
device->ro_flag = (devmap->features & DASD_FEATURE_READONLY) ? 1 : 0;
device->use_diag_flag = 1;
spin_unlock(&dasd_devmap_lock); spin_unlock(&dasd_devmap_lock);
return device; return device;
} }
...@@ -523,9 +429,3 @@ dasd_devmap_exit(void) ...@@ -523,9 +429,3 @@ dasd_devmap_exit(void)
{ {
dasd_forget_ranges(); dasd_forget_ranges();
} }
EXPORT_SYMBOL(dasd_devmap_from_devno);
EXPORT_SYMBOL(dasd_devmap_from_devindex);
EXPORT_SYMBOL(dasd_devmap_from_irq);
EXPORT_SYMBOL(dasd_get_device);
EXPORT_SYMBOL(dasd_put_device);
...@@ -5,7 +5,9 @@ ...@@ -5,7 +5,9 @@
* ...............: by Hartmunt Penner <hpenner@de.ibm.com> * ...............: by Hartmunt Penner <hpenner@de.ibm.com>
* 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.27 $
*
* History of changes * History of changes
* 07/13/00 Added fixup sections for diagnoses ans saved some registers * 07/13/00 Added fixup sections for diagnoses ans saved some registers
* 07/14/00 fixed constraints in newly generated inline asm * 07/14/00 fixed constraints in newly generated inline asm
...@@ -22,13 +24,13 @@ ...@@ -22,13 +24,13 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/hdreg.h> /* HDIO_GETGEO */ #include <linux/hdreg.h> /* HDIO_GETGEO */
#include <linux/bio.h> #include <linux/bio.h>
#include <linux/module.h>
#include <linux/init.h>
#include <asm/dasd.h> #include <asm/dasd.h>
#include <asm/debug.h> #include <asm/debug.h>
#include <asm/ebcdic.h> #include <asm/ebcdic.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/irq.h>
#include <asm/s390dyn.h>
#include <asm/s390_ext.h> #include <asm/s390_ext.h>
#include <asm/todclk.h> #include <asm/todclk.h>
...@@ -40,7 +42,7 @@ ...@@ -40,7 +42,7 @@
#endif /* PRINTK_HEADER */ #endif /* PRINTK_HEADER */
#define PRINTK_HEADER "dasd(diag):" #define PRINTK_HEADER "dasd(diag):"
static dasd_discipline_t dasd_diag_discipline; MODULE_LICENSE("GPL");
typedef struct dasd_diag_private_t { typedef struct dasd_diag_private_t {
dasd_diag_characteristics_t rdc_data; dasd_diag_characteristics_t rdc_data;
...@@ -57,25 +59,30 @@ typedef struct dasd_diag_req_t { ...@@ -57,25 +59,30 @@ typedef struct dasd_diag_req_t {
static __inline__ int static __inline__ int
dia250(void *iob, int cmd) dia250(void *iob, int cmd)
{ {
__asm__ __volatile__(" lr 0,%1\n" int rc;
" diag 0,%0,0x250\n"
__asm__ __volatile__(" lhi %0,3\n"
" lr 0,%2\n"
" diag 0,%1,0x250\n"
"0: ipm %0\n" "0: ipm %0\n"
" srl %0,28\n" " srl %0,28\n"
" or %0,1\n" " or %0,1\n"
"1:\n" "1:\n"
".section .fixup,\"ax\"\n" #ifndef CONFIG_ARCH_S390X
"2: lhi %0,3\n"
" bras 1,3f\n"
" .long 1b\n"
"3: l 1,0(1)\n"
" br 1\n"
".previous\n"
".section __ex_table,\"a\"\n" ".section __ex_table,\"a\"\n"
" .align 4\n" " .align 4\n"
" .long 0b,2b\n" ".previous\n":"+d"(cmd) " .long 0b,1b\n"
:"d"((void *) __pa(iob)) ".previous\n"
:"0", "1", "cc"); #else
return cmd; ".section __ex_table,\"a\"\n"
" .align 8\n"
" .quad 0b,1b\n"
".previous\n"
#endif
: "=&d" (rc)
: "d" (cmd), "d" ((void *) __pa(iob))
: "0", "1", "cc");
return rc;
} }
static __inline__ int static __inline__ int
...@@ -89,7 +96,7 @@ mdsk_init_io(dasd_device_t * device, int blocksize, int offset, int size) ...@@ -89,7 +96,7 @@ mdsk_init_io(dasd_device_t * device, int blocksize, int offset, int size)
iib = &private->iib; iib = &private->iib;
memset(iib, 0, sizeof (diag_init_io_t)); memset(iib, 0, sizeof (diag_init_io_t));
iib->dev_nr = device->devinfo.devno; iib->dev_nr = device->devno;
iib->block_size = blocksize; iib->block_size = blocksize;
iib->offset = offset; iib->offset = offset;
iib->start_block = 0; iib->start_block = 0;
...@@ -110,7 +117,7 @@ mdsk_term_io(dasd_device_t * device) ...@@ -110,7 +117,7 @@ mdsk_term_io(dasd_device_t * device)
private = (dasd_diag_private_t *) device->private; private = (dasd_diag_private_t *) device->private;
iib = &private->iib; iib = &private->iib;
memset(iib, 0, sizeof (diag_init_io_t)); memset(iib, 0, sizeof (diag_init_io_t));
iib->dev_nr = device->devinfo.devno; iib->dev_nr = device->devno;
rc = dia250(iib, TERM_BIO); rc = dia250(iib, TERM_BIO);
return rc & 3; return rc & 3;
} }
...@@ -127,7 +134,7 @@ dasd_start_diag(dasd_ccw_req_t * cqr) ...@@ -127,7 +134,7 @@ dasd_start_diag(dasd_ccw_req_t * cqr)
private = (dasd_diag_private_t *) device->private; private = (dasd_diag_private_t *) device->private;
dreq = (dasd_diag_req_t *) cqr->data; dreq = (dasd_diag_req_t *) cqr->data;
private->iob.dev_nr = device->devinfo.devno; private->iob.dev_nr = device->devno;
private->iob.key = 0; private->iob.key = 0;
private->iob.flags = 2; /* do asynchronous io */ private->iob.flags = 2; /* do asynchronous io */
private->iob.block_count = dreq->block_count; private->iob.block_count = dreq->block_count;
...@@ -191,7 +198,7 @@ dasd_ext_handler(struct pt_regs *regs, __u16 code) ...@@ -191,7 +198,7 @@ dasd_ext_handler(struct pt_regs *regs, __u16 code)
} }
/* get irq lock to modify request queue */ /* get irq lock to modify request queue */
spin_lock_irqsave(get_irq_lock(device->devinfo.irq), flags); spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
cqr->stopclk = get_clock(); cqr->stopclk = get_clock();
...@@ -219,7 +226,7 @@ dasd_ext_handler(struct pt_regs *regs, __u16 code) ...@@ -219,7 +226,7 @@ dasd_ext_handler(struct pt_regs *regs, __u16 code)
dasd_clear_timer(device); dasd_clear_timer(device);
dasd_schedule_bh(device); dasd_schedule_bh(device);
spin_unlock_irqrestore(get_irq_lock(device->devinfo.irq), flags); spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
irq_exit(); irq_exit();
} }
...@@ -245,10 +252,10 @@ dasd_diag_check_device(dasd_device_t *device) ...@@ -245,10 +252,10 @@ dasd_diag_check_device(dasd_device_t *device)
} }
/* Read Device Characteristics */ /* Read Device Characteristics */
rdc_data = (void *) &(private->rdc_data); rdc_data = (void *) &(private->rdc_data);
rdc_data->dev_nr = device->devinfo.devno; rdc_data->dev_nr = device->devno;
rdc_data->rdc_len = sizeof (dasd_diag_characteristics_t); rdc_data->rdc_len = sizeof (dasd_diag_characteristics_t);
rc = diag210((diag210_t *) rdc_data); rc = diag210((struct diag210 *) rdc_data);
if (rc) if (rc)
return -ENOTSUPP; return -ENOTSUPP;
...@@ -328,7 +335,7 @@ dasd_diag_fill_geometry(dasd_device_t *device, struct hd_geometry *geo) ...@@ -328,7 +335,7 @@ dasd_diag_fill_geometry(dasd_device_t *device, struct hd_geometry *geo)
} }
static dasd_era_t static dasd_era_t
dasd_diag_examine_error(dasd_ccw_req_t * cqr, devstat_t * stat) dasd_diag_examine_error(dasd_ccw_req_t * cqr, struct irb * stat)
{ {
return dasd_era_fatal; return dasd_era_fatal;
} }
...@@ -433,7 +440,8 @@ dasd_diag_fill_info(dasd_device_t * device, dasd_information2_t * info) ...@@ -433,7 +440,8 @@ dasd_diag_fill_info(dasd_device_t * device, dasd_information2_t * info)
} }
static void static void
dasd_diag_dump_sense(dasd_device_t *device, dasd_ccw_req_t * req) dasd_diag_dump_sense(dasd_device_t *device, dasd_ccw_req_t * req,
struct irb *stat)
{ {
char *page; char *page;
...@@ -443,8 +451,8 @@ dasd_diag_dump_sense(dasd_device_t *device, dasd_ccw_req_t * req) ...@@ -443,8 +451,8 @@ dasd_diag_dump_sense(dasd_device_t *device, dasd_ccw_req_t * req)
return; return;
} }
sprintf(page, KERN_WARNING PRINTK_HEADER sprintf(page, KERN_WARNING PRINTK_HEADER
"device %04X on irq %d: I/O status report:\n", "device %s: I/O status report:\n",
device->devinfo.devno, device->devinfo.irq); device->cdev->dev.bus_id);
MESSAGE(KERN_ERR, "Sense data:\n%s", page); MESSAGE(KERN_ERR, "Sense data:\n%s", page);
...@@ -463,7 +471,7 @@ dasd_diag_dump_sense(dasd_device_t *device, dasd_ccw_req_t * req) ...@@ -463,7 +471,7 @@ dasd_diag_dump_sense(dasd_device_t *device, dasd_ccw_req_t * req)
* start the next request if one finishes off. That makes 252.75 blocks * start the next request if one finishes off. That makes 252.75 blocks
* for one request. Give a little safety and the result is 240. * for one request. Give a little safety and the result is 240.
*/ */
static dasd_discipline_t dasd_diag_discipline = { dasd_discipline_t dasd_diag_discipline = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = "DIAG", .name = "DIAG",
.ebcname = "DIAG", .ebcname = "DIAG",
...@@ -479,7 +487,7 @@ static dasd_discipline_t dasd_diag_discipline = { ...@@ -479,7 +487,7 @@ static dasd_discipline_t dasd_diag_discipline = {
.fill_info = dasd_diag_fill_info, .fill_info = dasd_diag_fill_info,
}; };
int static int __init
dasd_diag_init(void) dasd_diag_init(void)
{ {
if (!MACHINE_IS_VM) { if (!MACHINE_IS_VM) {
...@@ -489,13 +497,13 @@ dasd_diag_init(void) ...@@ -489,13 +497,13 @@ dasd_diag_init(void)
return -EINVAL; return -EINVAL;
} }
ASCEBC(dasd_diag_discipline.ebcname, 4); ASCEBC(dasd_diag_discipline.ebcname, 4);
ctl_set_bit(0, 9); ctl_set_bit(0, 9);
register_external_interrupt(0x2603, dasd_ext_handler); register_external_interrupt(0x2603, dasd_ext_handler);
dasd_discipline_add(&dasd_diag_discipline);
return 0; return 0;
} }
void static void __exit
dasd_diag_cleanup(void) dasd_diag_cleanup(void)
{ {
if (!MACHINE_IS_VM) { if (!MACHINE_IS_VM) {
...@@ -504,24 +512,12 @@ dasd_diag_cleanup(void) ...@@ -504,24 +512,12 @@ dasd_diag_cleanup(void)
dasd_diag_discipline.name); dasd_diag_discipline.name);
return; return;
} }
dasd_discipline_del(&dasd_diag_discipline);
unregister_external_interrupt(0x2603, dasd_ext_handler); unregister_external_interrupt(0x2603, dasd_ext_handler);
ctl_clear_bit(0, 9); ctl_clear_bit(0, 9);
} }
#ifdef MODULE module_init(dasd_diag_init);
int module_exit(dasd_diag_cleanup);
init_module(void)
{
return dasd_diag_init();
}
void
cleanup_module(void)
{
dasd_diag_cleanup();
}
#endif
/* /*
* Overrides for Emacs so that we follow Linus's tabbing style. * Overrides for Emacs so that we follow Linus's tabbing style.
......
...@@ -5,6 +5,11 @@ ...@@ -5,6 +5,11 @@
* ...............: by Hartmunt Penner <hpenner@de.ibm.com> * ...............: by Hartmunt Penner <hpenner@de.ibm.com>
* 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.4 $
*
* History of changes
*
*/ */
#define MDSK_WRITE_REQ 0x01 #define MDSK_WRITE_REQ 0x01
...@@ -70,5 +75,3 @@ typedef struct diag_rw_io_t { ...@@ -70,5 +75,3 @@ typedef struct diag_rw_io_t {
diag_rw_io_t; diag_rw_io_t;
int dasd_diag_init(void);
void dasd_diag_cleanup(void);
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
* 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.35 $
*
* History of changes (starts July 2000) * History of changes (starts July 2000)
* 07/11/00 Enabled rotational position sensing * 07/11/00 Enabled rotational position sensing
* 07/14/00 Reorganized the format process for better ERP * 07/14/00 Reorganized the format process for better ERP
...@@ -30,15 +32,16 @@ ...@@ -30,15 +32,16 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/hdreg.h> /* HDIO_GETGEO */ #include <linux/hdreg.h> /* HDIO_GETGEO */
#include <linux/bio.h> #include <linux/bio.h>
#include <linux/module.h>
#include <linux/init.h>
#include <asm/debug.h> #include <asm/debug.h>
#include <asm/idals.h> #include <asm/idals.h>
#include <asm/ebcdic.h> #include <asm/ebcdic.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/irq.h>
#include <asm/s390dyn.h>
#include <asm/todclk.h> #include <asm/todclk.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/ccwdev.h>
#include "dasd_int.h" #include "dasd_int.h"
#include "dasd_eckd.h" #include "dasd_eckd.h"
...@@ -59,6 +62,8 @@ ...@@ -59,6 +62,8 @@
#define ECKD_F7(i) (i->factor7) #define ECKD_F7(i) (i->factor7)
#define ECKD_F8(i) (i->factor8) #define ECKD_F8(i) (i->factor8)
MODULE_LICENSE("GPL");
static dasd_discipline_t dasd_eckd_discipline; static dasd_discipline_t dasd_eckd_discipline;
typedef struct dasd_eckd_private_t { typedef struct dasd_eckd_private_t {
...@@ -70,29 +75,44 @@ typedef struct dasd_eckd_private_t { ...@@ -70,29 +75,44 @@ typedef struct dasd_eckd_private_t {
attrib_data_t attrib; /* e.g. cache operations */ attrib_data_t attrib; /* e.g. cache operations */
} dasd_eckd_private_t; } dasd_eckd_private_t;
static /* The ccw bus type uses this table to find devices that it sends to
devreg_t dasd_eckd_known_devices[] = { * dasd_eckd_probe */
{ static struct ccw_device_id dasd_eckd_ids[] = {
.ci = { .hc = { .ctype = 0x3880, .dtype = 3390 } }, { CCW_DEVICE_DEVTYPE (0x3990, 0, 0x3390, 0), driver_info: 0x1},
.flag = (DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE | { CCW_DEVICE_DEVTYPE (0x2105, 0, 0x3390, 0), driver_info: 0x2},
DEVREG_TYPE_DEVCHARS), { CCW_DEVICE_DEVTYPE (0x3880, 0, 0x3390, 0), driver_info: 0x3},
.oper_func = dasd_oper_handler { CCW_DEVICE_DEVTYPE (0x3990, 0, 0x3380, 0), driver_info: 0x4},
}, { CCW_DEVICE_DEVTYPE (0x2105, 0, 0x3380, 0), driver_info: 0x5},
{ { CCW_DEVICE_DEVTYPE (0x9343, 0, 0x9345, 0), driver_info: 0x6},
.ci = { .hc = { .ctype = 0x3990 } }, { /* end of list */ },
.flag = (DEVREG_MATCH_CU_TYPE | DEVREG_TYPE_DEVCHARS), };
.oper_func = dasd_oper_handler
}, MODULE_DEVICE_TABLE(ccw, dasd_eckd_ids);
{
.ci = { .hc = { .ctype = 0x2105 } }, static struct ccw_driver dasd_eckd_driver; /* see below */
.flag = (DEVREG_MATCH_CU_TYPE | DEVREG_TYPE_DEVCHARS),
.oper_func = dasd_oper_handler /* initial attempt at a probe function. this can be simplified once
}, * the other detection code is gone */
{ static int
.ci = { .hc = { .ctype = 0x9343 } }, dasd_eckd_probe (struct ccw_device *cdev)
.flag = (DEVREG_MATCH_CU_TYPE | DEVREG_TYPE_DEVCHARS), {
.oper_func = dasd_oper_handler return dasd_generic_probe (cdev, &dasd_eckd_discipline);
} }
static int
dasd_eckd_set_online(struct ccw_device *cdev)
{
return dasd_generic_set_online (cdev, &dasd_eckd_discipline);
}
static struct ccw_driver dasd_eckd_driver = {
.name = "dasd-eckd",
.owner = THIS_MODULE,
.ids = dasd_eckd_ids,
.probe = dasd_eckd_probe,
.remove = dasd_generic_remove,
.set_offline = dasd_generic_set_offline,
.set_online = dasd_eckd_set_online,
}; };
static const int sizes_trk0[] = { 28, 148, 84 }; static const int sizes_trk0[] = { 28, 148, 84 };
...@@ -183,7 +203,32 @@ recs_per_track(dasd_eckd_characteristics_t * rdc, ...@@ -183,7 +203,32 @@ recs_per_track(dasd_eckd_characteristics_t * rdc,
} }
static inline void static inline void
define_extent(ccw1_t * ccw, DE_eckd_data_t * data, int trk, int totrk, check_XRC (struct ccw1 *de_ccw,
DE_eckd_data_t *data,
dasd_device_t *device)
{
dasd_eckd_private_t *private;
private = (dasd_eckd_private_t *) device->private;
/* switch on System Time Stamp - needed for XRC Support */
if (private->rdc_data.facilities.XRC_supported) {
data->ga_extended |= 0x08; /* switch on 'Time Stamp Valid' */
data->ga_extended |= 0x02; /* switch on 'Extended Parameter' */
data->ep_sys_time = get_clock ();
de_ccw->count = sizeof (DE_eckd_data_t);
de_ccw->flags = CCW_FLAG_SLI;
}
return;
} /* end check_XRC */
static inline void
define_extent(struct ccw1 * ccw, DE_eckd_data_t * data, int trk, int totrk,
int cmd, dasd_device_t * device) int cmd, dasd_device_t * device)
{ {
dasd_eckd_private_t *private; dasd_eckd_private_t *private;
...@@ -216,10 +261,12 @@ define_extent(ccw1_t * ccw, DE_eckd_data_t * data, int trk, int totrk, ...@@ -216,10 +261,12 @@ define_extent(ccw1_t * ccw, DE_eckd_data_t * data, int trk, int totrk,
case DASD_ECKD_CCW_WRITE_KD_MT: case DASD_ECKD_CCW_WRITE_KD_MT:
data->mask.perm = 0x02; data->mask.perm = 0x02;
data->attributes.operation = private->attrib.operation; data->attributes.operation = private->attrib.operation;
check_XRC (ccw, data, device);
break; break;
case DASD_ECKD_CCW_WRITE_CKD: case DASD_ECKD_CCW_WRITE_CKD:
case DASD_ECKD_CCW_WRITE_CKD_MT: case DASD_ECKD_CCW_WRITE_CKD_MT:
data->attributes.operation = DASD_BYPASS_CACHE; data->attributes.operation = DASD_BYPASS_CACHE;
check_XRC (ccw, data, device);
break; break;
case DASD_ECKD_CCW_ERASE: case DASD_ECKD_CCW_ERASE:
case DASD_ECKD_CCW_WRITE_HOME_ADDRESS: case DASD_ECKD_CCW_WRITE_HOME_ADDRESS:
...@@ -227,6 +274,7 @@ define_extent(ccw1_t * ccw, DE_eckd_data_t * data, int trk, int totrk, ...@@ -227,6 +274,7 @@ define_extent(ccw1_t * ccw, DE_eckd_data_t * data, int trk, int totrk,
data->mask.perm = 0x3; data->mask.perm = 0x3;
data->mask.auth = 0x1; data->mask.auth = 0x1;
data->attributes.operation = DASD_BYPASS_CACHE; data->attributes.operation = DASD_BYPASS_CACHE;
check_XRC (ccw, data, device);
break; break;
default: default:
MESSAGE(KERN_ERR, "unknown opcode 0x%x", cmd); MESSAGE(KERN_ERR, "unknown opcode 0x%x", cmd);
...@@ -271,7 +319,7 @@ define_extent(ccw1_t * ccw, DE_eckd_data_t * data, int trk, int totrk, ...@@ -271,7 +319,7 @@ define_extent(ccw1_t * ccw, DE_eckd_data_t * data, int trk, int totrk,
} }
static inline void static inline void
locate_record(ccw1_t *ccw, LO_eckd_data_t *data, int trk, locate_record(struct ccw1 *ccw, LO_eckd_data_t *data, int trk,
int rec_on_trk, int no_rec, int cmd, int rec_on_trk, int no_rec, int cmd,
dasd_device_t * device, int reclen) dasd_device_t * device, int reclen)
{ {
...@@ -407,24 +455,7 @@ dasd_eckd_cdl_reclen(int recid) ...@@ -407,24 +455,7 @@ dasd_eckd_cdl_reclen(int recid)
return LABEL_SIZE; return LABEL_SIZE;
} }
static inline int static int
dasd_eckd_id_check(s390_dev_info_t * info)
{
if (info->sid_data.cu_type == 0x3990 ||
info->sid_data.cu_type == 0x2105)
if (info->sid_data.dev_type == 0x3390)
return 0;
if (info->sid_data.cu_type == 0x3990 ||
info->sid_data.cu_type == 0x2105)
if (info->sid_data.dev_type == 0x3380)
return 0;
if (info->sid_data.cu_type == 0x9343)
if (info->sid_data.dev_type == 0x9345)
return 0;
return -ENODEV;
}
static inline int
dasd_eckd_check_characteristics(dasd_device_t *device) dasd_eckd_check_characteristics(dasd_device_t *device)
{ {
dasd_eckd_private_t *private; dasd_eckd_private_t *private;
...@@ -452,7 +483,7 @@ dasd_eckd_check_characteristics(dasd_device_t *device) ...@@ -452,7 +483,7 @@ dasd_eckd_check_characteristics(dasd_device_t *device)
/* Read Device Characteristics */ /* Read Device Characteristics */
rdc_data = (void *) &(private->rdc_data); rdc_data = (void *) &(private->rdc_data);
rc = read_dev_chars(device->devinfo.irq, &rdc_data, 64); rc = read_dev_chars(device->cdev, &rdc_data, 64);
if (rc) { if (rc) {
MESSAGE(KERN_WARNING, MESSAGE(KERN_WARNING,
"Read device characteristics returned error %d", rc); "Read device characteristics returned error %d", rc);
...@@ -470,8 +501,7 @@ dasd_eckd_check_characteristics(dasd_device_t *device) ...@@ -470,8 +501,7 @@ dasd_eckd_check_characteristics(dasd_device_t *device)
private->rdc_data.sec_per_trk); private->rdc_data.sec_per_trk);
/* Read Configuration Data */ /* Read Configuration Data */
rc = read_conf_data(device->devinfo.irq, rc = read_conf_data(device->cdev, &conf_data, &conf_len);
&conf_data, &conf_len, LPM_ANYPATH);
if (rc && rc != -EOPNOTSUPP) { /* -EOPNOTSUPP is ok */ if (rc && rc != -EOPNOTSUPP) { /* -EOPNOTSUPP is ok */
MESSAGE(KERN_WARNING, MESSAGE(KERN_WARNING,
"Read configuration data returned error %d", rc); "Read configuration data returned error %d", rc);
...@@ -497,17 +527,11 @@ dasd_eckd_check_characteristics(dasd_device_t *device) ...@@ -497,17 +527,11 @@ dasd_eckd_check_characteristics(dasd_device_t *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;
}
static int
dasd_eckd_check_device(struct dasd_device_t *device)
{
int rc;
rc = dasd_eckd_id_check(&device->devinfo); /* get characteristis via diag to determine the kind of minidisk under VM */
if (rc) /* needed beacause XRC is not support by VM (jet) */
return rc; /* Can be removed as soon as VM supports XRC */
return dasd_eckd_check_characteristics(device); // TBD ??? HUM
} }
static dasd_ccw_req_t * static dasd_ccw_req_t *
...@@ -517,7 +541,7 @@ dasd_eckd_analysis_ccw(struct dasd_device_t *device) ...@@ -517,7 +541,7 @@ dasd_eckd_analysis_ccw(struct dasd_device_t *device)
eckd_count_t *count_data; eckd_count_t *count_data;
LO_eckd_data_t *LO_data; LO_eckd_data_t *LO_data;
dasd_ccw_req_t *cqr; dasd_ccw_req_t *cqr;
ccw1_t *ccw; struct ccw1 *ccw;
int cplength, datasize; int cplength, datasize;
int i; int i;
...@@ -563,6 +587,7 @@ dasd_eckd_analysis_ccw(struct dasd_device_t *device) ...@@ -563,6 +587,7 @@ dasd_eckd_analysis_ccw(struct dasd_device_t *device)
cqr->device = device; cqr->device = device;
cqr->retries = 0; cqr->retries = 0;
cqr->buildclk = get_clock();
cqr->status = DASD_CQR_FILLED; cqr->status = DASD_CQR_FILLED;
return cqr; return cqr;
} }
...@@ -716,7 +741,7 @@ dasd_eckd_format_device(dasd_device_t * device, format_data_t * fdata) ...@@ -716,7 +741,7 @@ dasd_eckd_format_device(dasd_device_t * device, format_data_t * fdata)
dasd_eckd_private_t *private; dasd_eckd_private_t *private;
dasd_ccw_req_t *fcp; dasd_ccw_req_t *fcp;
eckd_count_t *ect; eckd_count_t *ect;
ccw1_t *ccw; struct ccw1 *ccw;
void *data; void *data;
int rpt, cyl, head; int rpt, cyl, head;
int cplength, datasize; int cplength, datasize;
...@@ -881,25 +906,28 @@ dasd_eckd_format_device(dasd_device_t * device, format_data_t * fdata) ...@@ -881,25 +906,28 @@ dasd_eckd_format_device(dasd_device_t * device, format_data_t * fdata)
} }
fcp->device = device; fcp->device = device;
fcp->retries = 2; /* set retry counter to enable ERP */ fcp->retries = 2; /* set retry counter to enable ERP */
fcp->buildclk = get_clock();
fcp->status = DASD_CQR_FILLED; fcp->status = DASD_CQR_FILLED;
return fcp; return fcp;
} }
static dasd_era_t static dasd_era_t
dasd_eckd_examine_error(dasd_ccw_req_t * cqr, devstat_t * stat) dasd_eckd_examine_error(dasd_ccw_req_t * cqr, struct irb * irb)
{ {
dasd_device_t *device = (dasd_device_t *) cqr->device; dasd_device_t *device = (dasd_device_t *) cqr->device;
struct ccw_device *cdev = device->cdev;
if (stat->cstat == 0x00 && if (irb->scsw.cstat == 0x00 &&
stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
return dasd_era_none; return dasd_era_none;
switch (device->devinfo.sid_data.cu_type) { switch (cdev->id.cu_type) {
case 0x3990: case 0x3990:
case 0x2105: case 0x2105:
return dasd_3990_erp_examine(cqr, stat); return dasd_3990_erp_examine(cqr, irb);
case 0x9343: case 0x9343:
return dasd_9343_erp_examine(cqr, stat); return dasd_9343_erp_examine(cqr, irb);
case 0x3880:
default: default:
MESSAGE(KERN_WARNING, "%s", MESSAGE(KERN_WARNING, "%s",
"default (unknown CU type) - RECOVERABLE return"); "default (unknown CU type) - RECOVERABLE return");
...@@ -911,13 +939,15 @@ static dasd_erp_fn_t ...@@ -911,13 +939,15 @@ static dasd_erp_fn_t
dasd_eckd_erp_action(dasd_ccw_req_t * cqr) dasd_eckd_erp_action(dasd_ccw_req_t * cqr)
{ {
dasd_device_t *device = (dasd_device_t *) cqr->device; dasd_device_t *device = (dasd_device_t *) cqr->device;
struct ccw_device *cdev = device->cdev;
switch (device->devinfo.sid_data.cu_type) { switch (cdev->id.cu_type) {
case 0x3990: case 0x3990:
case 0x2105: case 0x2105:
return dasd_3990_erp_action; return dasd_3990_erp_action;
case 0x9343: case 0x9343:
/* Return dasd_9343_erp_action; */ /* Return dasd_9343_erp_action; */
case 0x3880:
default: default:
return dasd_default_erp_action; return dasd_default_erp_action;
} }
...@@ -936,13 +966,15 @@ dasd_eckd_build_cp(dasd_device_t * device, struct request *req) ...@@ -936,13 +966,15 @@ dasd_eckd_build_cp(dasd_device_t * device, struct request *req)
unsigned long *idaws; unsigned long *idaws;
LO_eckd_data_t *LO_data; LO_eckd_data_t *LO_data;
dasd_ccw_req_t *cqr; dasd_ccw_req_t *cqr;
ccw1_t *ccw; struct ccw1 *ccw;
struct bio *bio; struct bio *bio;
struct bio_vec *bv; struct bio_vec *bv;
char *dst; char *dst;
unsigned int blksize, blk_per_trk, off; unsigned int blksize, blk_per_trk, off;
int count, cidaw, cplength, datasize; int count, cidaw, cplength, datasize;
sector_t recid, first_rec, last_rec; sector_t recid, first_rec, last_rec;
sector_t first_trk, last_trk;
unsigned int first_offs, last_offs;
unsigned char cmd, rcmd; unsigned char cmd, rcmd;
int i; int i;
...@@ -957,8 +989,10 @@ dasd_eckd_build_cp(dasd_device_t * device, struct request *req) ...@@ -957,8 +989,10 @@ dasd_eckd_build_cp(dasd_device_t * device, struct request *req)
blksize = device->bp_block; blksize = device->bp_block;
blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize); blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize);
/* Calculate record id of first and last block. */ /* Calculate record id of first and last block. */
first_rec = req->sector >> device->s2b_shift; first_rec = first_trk = req->sector >> device->s2b_shift;
last_rec = (req->sector + req->nr_sectors - 1) >> device->s2b_shift; first_offs = sector_div(first_trk, blk_per_trk);
last_rec = last_trk = (req->sector + req->nr_sectors - 1) >> device->s2b_shift;
last_offs = sector_div(last_trk, blk_per_trk);
/* Check struct bio and count the number of blocks for the request. */ /* Check struct bio and count the number of blocks for the request. */
count = 0; count = 0;
cidaw = 0; cidaw = 0;
...@@ -996,8 +1030,7 @@ dasd_eckd_build_cp(dasd_device_t * device, struct request *req) ...@@ -996,8 +1030,7 @@ dasd_eckd_build_cp(dasd_device_t * device, struct request *req)
return cqr; return cqr;
ccw = cqr->cpaddr; ccw = cqr->cpaddr;
/* First ccw is define extent. */ /* First ccw is define extent. */
define_extent(ccw++, cqr->data, first_rec / blk_per_trk, define_extent(ccw++, cqr->data, first_trk, last_trk, cmd, device);
last_rec / blk_per_trk, cmd, device);
/* Build locate_record+read/write/ccws. */ /* Build locate_record+read/write/ccws. */
idaws = (unsigned long *) (cqr->data + sizeof(DE_eckd_data_t)); idaws = (unsigned long *) (cqr->data + sizeof(DE_eckd_data_t));
LO_data = (LO_eckd_data_t *) (idaws + cidaw); LO_data = (LO_eckd_data_t *) (idaws + cidaw);
...@@ -1005,13 +1038,14 @@ dasd_eckd_build_cp(dasd_device_t * device, struct request *req) ...@@ -1005,13 +1038,14 @@ dasd_eckd_build_cp(dasd_device_t * device, struct request *req)
if (private->uses_cdl == 0 || recid > 2*blk_per_trk) { if (private->uses_cdl == 0 || recid > 2*blk_per_trk) {
/* Only standard blocks so there is just one locate record. */ /* Only standard blocks so there is just one locate record. */
ccw[-1].flags |= CCW_FLAG_CC; ccw[-1].flags |= CCW_FLAG_CC;
locate_record(ccw++, LO_data++, locate_record(ccw++, LO_data++, first_trk, first_offs + 1,
recid / blk_per_trk, recid % blk_per_trk + 1,
last_rec - recid + 1, cmd, device, blksize); last_rec - recid + 1, cmd, device, blksize);
} }
rq_for_each_bio(bio, req) bio_for_each_segment(bv, bio, i) { rq_for_each_bio(bio, req) bio_for_each_segment(bv, bio, i) {
dst = kmap(bv->bv_page) + bv->bv_offset; dst = kmap(bv->bv_page) + bv->bv_offset;
for (off = 0; off < bv->bv_len; off += blksize) { for (off = 0; off < bv->bv_len; off += blksize) {
sector_t trkid = recid;
unsigned int recoffs = sector_div(trkid, blk_per_trk);
rcmd = cmd; rcmd = cmd;
count = blksize; count = blksize;
/* Locate record for cdl special block ? */ /* Locate record for cdl special block ? */
...@@ -1025,16 +1059,14 @@ dasd_eckd_build_cp(dasd_device_t * device, struct request *req) ...@@ -1025,16 +1059,14 @@ dasd_eckd_build_cp(dasd_device_t * device, struct request *req)
} }
ccw[-1].flags |= CCW_FLAG_CC; ccw[-1].flags |= CCW_FLAG_CC;
locate_record(ccw++, LO_data++, locate_record(ccw++, LO_data++,
recid / blk_per_trk, trkid, recoffs + 1,
recid % blk_per_trk + 1,
1, rcmd, device, count); 1, rcmd, device, count);
} }
/* Locate record for standard blocks ? */ /* Locate record for standard blocks ? */
if (private->uses_cdl && recid == 2*blk_per_trk) { if (private->uses_cdl && recid == 2*blk_per_trk) {
ccw[-1].flags |= CCW_FLAG_CC; ccw[-1].flags |= CCW_FLAG_CC;
locate_record(ccw++, LO_data++, locate_record(ccw++, LO_data++,
recid / blk_per_trk, trkid, recoffs + 1,
recid % blk_per_trk + 1,
last_rec - recid + 1, last_rec - recid + 1,
cmd, device, count); cmd, device, count);
} }
...@@ -1094,37 +1126,34 @@ dasd_eckd_fill_info(dasd_device_t * device, dasd_information2_t * info) ...@@ -1094,37 +1126,34 @@ dasd_eckd_fill_info(dasd_device_t * device, dasd_information2_t * info)
static int static int
dasd_eckd_release(struct block_device *bdev, int no, long args) dasd_eckd_release(struct block_device *bdev, int no, long args)
{ {
dasd_devmap_t *devmap;
dasd_device_t *device; dasd_device_t *device;
dasd_ccw_req_t *cqr; dasd_ccw_req_t *cqr;
int rc; int rc;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EACCES; return -EACCES;
devmap = dasd_devmap_from_bdev(bdev);
device = (devmap != NULL) ? device = bdev->bd_disk->private_data;
dasd_get_device(devmap) : ERR_PTR(-ENODEV); if (device == NULL)
if (IS_ERR(device)) return -ENODEV;
return PTR_ERR(device);
cqr = dasd_smalloc_request(dasd_eckd_discipline.name, cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
1, 0, device); 1, 0, 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");
dasd_put_device(devmap);
return -ENOMEM; return -ENOMEM;
} }
cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RELEASE; cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RELEASE;
cqr->device = device; cqr->device = device;
cqr->retries = 0; cqr->retries = 0;
cqr->expires = 10 * HZ; cqr->expires = 10 * HZ;
cqr->buildclk = get_clock();
cqr->status = DASD_CQR_FILLED; cqr->status = DASD_CQR_FILLED;
rc = dasd_sleep_on_immediatly(cqr); rc = dasd_sleep_on_immediatly(cqr);
dasd_kfree_request(cqr, cqr->device); dasd_kfree_request(cqr, cqr->device);
dasd_put_device(devmap);
return rc; return rc;
} }
...@@ -1137,18 +1166,16 @@ dasd_eckd_release(struct block_device *bdev, int no, long args) ...@@ -1137,18 +1166,16 @@ dasd_eckd_release(struct block_device *bdev, int no, long args)
static int static int
dasd_eckd_reserve(struct block_device *bdev, int no, long args) dasd_eckd_reserve(struct block_device *bdev, int no, long args)
{ {
dasd_devmap_t *devmap;
dasd_device_t *device; dasd_device_t *device;
dasd_ccw_req_t *cqr; dasd_ccw_req_t *cqr;
int rc; int rc;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EACCES; return -EACCES;
devmap = dasd_devmap_from_bdev(bdev);
device = (devmap != NULL) ? device = bdev->bd_disk->private_data;
dasd_get_device(devmap) : ERR_PTR(-ENODEV); if (device == NULL)
if (IS_ERR(device)) return -ENODEV;
return PTR_ERR(device);
cqr = dasd_smalloc_request(dasd_eckd_discipline.name, cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
1, 0, device); 1, 0, device);
...@@ -1156,13 +1183,13 @@ dasd_eckd_reserve(struct block_device *bdev, int no, long args) ...@@ -1156,13 +1183,13 @@ dasd_eckd_reserve(struct block_device *bdev, int no, long args)
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");
dasd_put_device(devmap);
return -ENOMEM; return -ENOMEM;
} }
cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RESERVE; cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RESERVE;
cqr->device = device; cqr->device = device;
cqr->retries = 0; cqr->retries = 0;
cqr->expires = 10 * HZ; cqr->expires = 10 * HZ;
cqr->buildclk = get_clock();
cqr->status = DASD_CQR_FILLED; cqr->status = DASD_CQR_FILLED;
rc = dasd_sleep_on_immediatly(cqr); rc = dasd_sleep_on_immediatly(cqr);
...@@ -1172,7 +1199,6 @@ dasd_eckd_reserve(struct block_device *bdev, int no, long args) ...@@ -1172,7 +1199,6 @@ dasd_eckd_reserve(struct block_device *bdev, int no, long args)
dasd_eckd_release(bdev, no, args); dasd_eckd_release(bdev, no, args);
} }
dasd_kfree_request(cqr, cqr->device); dasd_kfree_request(cqr, cqr->device);
dasd_put_device(devmap);
return rc; return rc;
} }
...@@ -1184,31 +1210,29 @@ dasd_eckd_reserve(struct block_device *bdev, int no, long args) ...@@ -1184,31 +1210,29 @@ dasd_eckd_reserve(struct block_device *bdev, int no, long args)
static int static int
dasd_eckd_steal_lock(struct block_device *bdev, int no, long args) dasd_eckd_steal_lock(struct block_device *bdev, int no, long args)
{ {
dasd_devmap_t *devmap;
dasd_device_t *device; dasd_device_t *device;
dasd_ccw_req_t *cqr; dasd_ccw_req_t *cqr;
int rc; int rc;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EACCES; return -EACCES;
devmap = dasd_devmap_from_bdev(bdev);
device = (devmap != NULL) ? device = bdev->bd_disk->private_data;
dasd_get_device(devmap) : ERR_PTR(-ENODEV); if (device == NULL)
if (IS_ERR(device)) return -ENODEV;
return PTR_ERR(device);
cqr = dasd_smalloc_request(dasd_eckd_discipline.name, cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
1, 0, device); 1, 0, 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");
dasd_put_device(devmap);
return -ENOMEM; return -ENOMEM;
} }
cqr->cpaddr->cmd_code = DASD_ECKD_CCW_SLCK; cqr->cpaddr->cmd_code = DASD_ECKD_CCW_SLCK;
cqr->device = device; cqr->device = device;
cqr->retries = 0; cqr->retries = 0;
cqr->expires = 10 * HZ; cqr->expires = 10 * HZ;
cqr->buildclk = get_clock();
cqr->status = DASD_CQR_FILLED; cqr->status = DASD_CQR_FILLED;
rc = dasd_sleep_on_immediatly(cqr); rc = dasd_sleep_on_immediatly(cqr);
...@@ -1218,7 +1242,6 @@ dasd_eckd_steal_lock(struct block_device *bdev, int no, long args) ...@@ -1218,7 +1242,6 @@ dasd_eckd_steal_lock(struct block_device *bdev, int no, long args)
dasd_eckd_release(bdev, no, args); dasd_eckd_release(bdev, no, args);
} }
dasd_kfree_request(cqr, cqr->device); dasd_kfree_request(cqr, cqr->device);
dasd_put_device(devmap);
return rc; return rc;
} }
...@@ -1228,19 +1251,16 @@ dasd_eckd_steal_lock(struct block_device *bdev, int no, long args) ...@@ -1228,19 +1251,16 @@ dasd_eckd_steal_lock(struct block_device *bdev, int no, long args)
static int static int
dasd_eckd_performance(struct block_device *bdev, int no, long args) dasd_eckd_performance(struct block_device *bdev, int no, long args)
{ {
dasd_devmap_t *devmap;
dasd_device_t *device; dasd_device_t *device;
dasd_psf_prssd_data_t *prssdp; dasd_psf_prssd_data_t *prssdp;
dasd_rssd_perf_stats_t *stats; dasd_rssd_perf_stats_t *stats;
dasd_ccw_req_t *cqr; dasd_ccw_req_t *cqr;
ccw1_t *ccw; struct ccw1 *ccw;
int rc; int rc;
devmap = dasd_devmap_from_bdev(bdev); device = bdev->bd_disk->private_data;
device = (devmap != NULL) ? if (device == NULL)
dasd_get_device(devmap) : ERR_PTR(-ENODEV); return -ENODEV;
if (IS_ERR(device))
return PTR_ERR(device);
cqr = dasd_smalloc_request(dasd_eckd_discipline.name, cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
1 /* PSF */ + 1 /* RSSD */ , 1 /* PSF */ + 1 /* RSSD */ ,
...@@ -1249,7 +1269,6 @@ dasd_eckd_performance(struct block_device *bdev, int no, long args) ...@@ -1249,7 +1269,6 @@ dasd_eckd_performance(struct block_device *bdev, int no, long args)
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");
dasd_put_device(devmap);
return -ENOMEM; return -ENOMEM;
} }
cqr->device = device; cqr->device = device;
...@@ -1277,6 +1296,7 @@ dasd_eckd_performance(struct block_device *bdev, int no, long args) ...@@ -1277,6 +1296,7 @@ dasd_eckd_performance(struct block_device *bdev, int no, long args)
ccw->count = sizeof (dasd_rssd_perf_stats_t); ccw->count = sizeof (dasd_rssd_perf_stats_t);
ccw->cda = (__u32)(addr_t) stats; ccw->cda = (__u32)(addr_t) stats;
cqr->buildclk = get_clock();
cqr->status = DASD_CQR_FILLED; cqr->status = DASD_CQR_FILLED;
rc = dasd_sleep_on(cqr); rc = dasd_sleep_on(cqr);
if (rc == 0) { if (rc == 0) {
...@@ -1287,7 +1307,6 @@ dasd_eckd_performance(struct block_device *bdev, int no, long args) ...@@ -1287,7 +1307,6 @@ dasd_eckd_performance(struct block_device *bdev, int no, long args)
sizeof(dasd_rssd_perf_stats_t)); sizeof(dasd_rssd_perf_stats_t));
} }
dasd_sfree_request(cqr, cqr->device); dasd_sfree_request(cqr, cqr->device);
dasd_put_device(devmap);
return rc; return rc;
} }
...@@ -1298,7 +1317,6 @@ dasd_eckd_performance(struct block_device *bdev, int no, long args) ...@@ -1298,7 +1317,6 @@ dasd_eckd_performance(struct block_device *bdev, int no, long args)
static int static int
dasd_eckd_set_attrib(struct block_device *bdev, int no, long args) dasd_eckd_set_attrib(struct block_device *bdev, int no, long args)
{ {
dasd_devmap_t *devmap;
dasd_device_t *device; dasd_device_t *device;
dasd_eckd_private_t *private; dasd_eckd_private_t *private;
attrib_data_t attrib; attrib_data_t attrib;
...@@ -1308,14 +1326,11 @@ dasd_eckd_set_attrib(struct block_device *bdev, int no, long args) ...@@ -1308,14 +1326,11 @@ dasd_eckd_set_attrib(struct block_device *bdev, int no, long args)
if (!args) if (!args)
return -EINVAL; return -EINVAL;
devmap = dasd_devmap_from_bdev(bdev); device = bdev->bd_disk->private_data;
device = (devmap != NULL) ? if (device == NULL)
dasd_get_device(devmap) : ERR_PTR(-ENODEV); return -ENODEV;
if (IS_ERR(device))
return PTR_ERR(device);
if (copy_from_user(&attrib, (void *) args, sizeof (attrib_data_t))) { if (copy_from_user(&attrib, (void *) args, sizeof (attrib_data_t))) {
dasd_put_device(devmap);
return -EFAULT; return -EFAULT;
} }
...@@ -1332,16 +1347,16 @@ dasd_eckd_set_attrib(struct block_device *bdev, int no, long args) ...@@ -1332,16 +1347,16 @@ dasd_eckd_set_attrib(struct block_device *bdev, int no, long args)
"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);
dasd_put_device(devmap);
return 0; return 0;
} }
static void static void
dasd_eckd_dump_sense(struct dasd_device_t *device, dasd_ccw_req_t * req) dasd_eckd_dump_sense(struct dasd_device_t *device, dasd_ccw_req_t * req,
struct irb *irb)
{ {
char *page, *sense; char *page;
ccw1_t *act; struct ccw1 *act;
int len, sl, sct; int len, sl, sct;
page = (char *) get_zeroed_page(GFP_ATOMIC); page = (char *) get_zeroed_page(GFP_ATOMIC);
...@@ -1350,14 +1365,14 @@ dasd_eckd_dump_sense(struct dasd_device_t *device, dasd_ccw_req_t * req) ...@@ -1350,14 +1365,14 @@ dasd_eckd_dump_sense(struct dasd_device_t *device, dasd_ccw_req_t * req)
return; return;
} }
len = sprintf(page, KERN_ERR PRINTK_HEADER len = sprintf(page, KERN_ERR PRINTK_HEADER
"device %04X on irq %d: I/O status report:\n", "device %s: I/O status report:\n",
device->devinfo.devno, device->devinfo.irq); device->cdev->dev.bus_id);
len += sprintf(page + len, KERN_ERR PRINTK_HEADER len += sprintf(page + len, KERN_ERR PRINTK_HEADER
"in req: %p CS: 0x%02X DS: 0x%02X\n", req, "in req: %p CS: 0x%02X DS: 0x%02X\n", req,
device->dev_status.cstat, device->dev_status.dstat); irb->scsw.cstat, irb->scsw.dstat);
len += sprintf(page + len, KERN_ERR PRINTK_HEADER len += sprintf(page + len, KERN_ERR PRINTK_HEADER
"Failing CCW: %p\n", "Failing CCW: %p\n",
(void *) (addr_t) device->dev_status.cpa); (void *) (addr_t) irb->scsw.cpa);
act = req->cpaddr; act = req->cpaddr;
do { do {
DBF_EVENT(DBF_INFO, DBF_EVENT(DBF_INFO,
...@@ -1370,8 +1385,7 @@ dasd_eckd_dump_sense(struct dasd_device_t *device, dasd_ccw_req_t * req) ...@@ -1370,8 +1385,7 @@ dasd_eckd_dump_sense(struct dasd_device_t *device, dasd_ccw_req_t * req)
((int *) (addr_t) act->cda)[2], ((int *) (addr_t) act->cda)[2],
((int *) (addr_t) act->cda)[3]); ((int *) (addr_t) act->cda)[3]);
} while (act++->flags & (CCW_FLAG_CC | CCW_FLAG_DC)); } while (act++->flags & (CCW_FLAG_CC | CCW_FLAG_DC));
sense = device->dev_status.ii.sense.data; if (irb->esw.esw0.erw.cons) {
if (device->dev_status.flag & DEVSTAT_FLAG_SENSE_AVAIL) {
for (sl = 0; sl < 4; sl++) { for (sl = 0; sl < 4; sl++) {
len += sprintf(page + len, KERN_ERR PRINTK_HEADER len += sprintf(page + len, KERN_ERR PRINTK_HEADER
"Sense(hex) %2d-%2d:", "Sense(hex) %2d-%2d:",
...@@ -1379,23 +1393,23 @@ dasd_eckd_dump_sense(struct dasd_device_t *device, dasd_ccw_req_t * req) ...@@ -1379,23 +1393,23 @@ dasd_eckd_dump_sense(struct dasd_device_t *device, dasd_ccw_req_t * req)
for (sct = 0; sct < 8; sct++) { for (sct = 0; sct < 8; sct++) {
len += sprintf(page + len, " %02x", len += sprintf(page + len, " %02x",
sense[8 * sl + sct]); irb->ecw[8 * sl + sct]);
} }
len += sprintf(page + len, "\n"); len += sprintf(page + len, "\n");
} }
if (sense[27] & DASD_SENSE_BIT_0) { if (irb->ecw[27] & DASD_SENSE_BIT_0) {
/* 24 Byte Sense Data */ /* 24 Byte Sense Data */
len += sprintf(page + len, KERN_ERR PRINTK_HEADER len += sprintf(page + len, KERN_ERR PRINTK_HEADER
"24 Byte: %x MSG %x, %s MSGb to SYSOP\n", "24 Byte: %x MSG %x, %s MSGb to SYSOP\n",
sense[7] >> 4, sense[7] & 0x0f, irb->ecw[7] >> 4, irb->ecw[7] & 0x0f,
sense[1] & 0x10 ? "" : "no"); irb->ecw[1] & 0x10 ? "" : "no");
} else { } else {
/* 32 Byte Sense Data */ /* 32 Byte Sense Data */
len += sprintf(page + len, KERN_ERR PRINTK_HEADER len += sprintf(page + len, KERN_ERR PRINTK_HEADER
"32 Byte: Format: %x " "32 Byte: Format: %x "
"Exception class %x\n", "Exception class %x\n",
sense[6] & 0x0f, sense[22] >> 4); irb->ecw[6] & 0x0f, irb->ecw[22] >> 4);
} }
} }
...@@ -1422,7 +1436,7 @@ static dasd_discipline_t dasd_eckd_discipline = { ...@@ -1422,7 +1436,7 @@ static dasd_discipline_t dasd_eckd_discipline = {
.name = "ECKD", .name = "ECKD",
.ebcname = "ECKD", .ebcname = "ECKD",
.max_blocks = 240, .max_blocks = 240,
.check_device = dasd_eckd_check_device, .check_device = dasd_eckd_check_characteristics,
.do_analysis = dasd_eckd_do_analysis, .do_analysis = dasd_eckd_do_analysis,
.fill_geometry = dasd_eckd_fill_geometry, .fill_geometry = dasd_eckd_fill_geometry,
.start_IO = dasd_start_IO, .start_IO = dasd_start_IO,
...@@ -1436,12 +1450,9 @@ static dasd_discipline_t dasd_eckd_discipline = { ...@@ -1436,12 +1450,9 @@ static dasd_discipline_t dasd_eckd_discipline = {
.fill_info = dasd_eckd_fill_info, .fill_info = dasd_eckd_fill_info,
}; };
int static int __init
dasd_eckd_init(void) dasd_eckd_init(void)
{ {
int i;
printk("sizeof(dasd_ccw_req_t) = %li\n",
sizeof(dasd_ccw_req_t));
dasd_ioctl_no_register(THIS_MODULE, BIODASDSATTR, dasd_ioctl_no_register(THIS_MODULE, BIODASDSATTR,
dasd_eckd_set_attrib); dasd_eckd_set_attrib);
dasd_ioctl_no_register(THIS_MODULE, BIODASDPSRD, dasd_ioctl_no_register(THIS_MODULE, BIODASDPSRD,
...@@ -1454,22 +1465,15 @@ dasd_eckd_init(void) ...@@ -1454,22 +1465,15 @@ dasd_eckd_init(void)
dasd_eckd_steal_lock); dasd_eckd_steal_lock);
ASCEBC(dasd_eckd_discipline.ebcname, 4); ASCEBC(dasd_eckd_discipline.ebcname, 4);
dasd_discipline_add(&dasd_eckd_discipline);
for (i = 0; i < sizeof(dasd_eckd_known_devices)/sizeof(devreg_t); i++) ccw_driver_register(&dasd_eckd_driver);
s390_device_register(&dasd_eckd_known_devices[i]);
return 0; return 0;
} }
void static void __exit
dasd_eckd_cleanup(void) dasd_eckd_cleanup(void)
{ {
int i; ccw_driver_unregister(&dasd_eckd_driver);
for (i = 0; i < sizeof(dasd_eckd_known_devices)/sizeof(devreg_t); i++)
s390_device_unregister(&dasd_eckd_known_devices[i]);
dasd_discipline_del(&dasd_eckd_discipline);
dasd_ioctl_no_unregister(THIS_MODULE, BIODASDSATTR, dasd_ioctl_no_unregister(THIS_MODULE, BIODASDSATTR,
dasd_eckd_set_attrib); dasd_eckd_set_attrib);
...@@ -1483,19 +1487,8 @@ dasd_eckd_cleanup(void) ...@@ -1483,19 +1487,8 @@ dasd_eckd_cleanup(void)
dasd_eckd_steal_lock); dasd_eckd_steal_lock);
} }
#ifdef MODULE module_init(dasd_eckd_init);
int module_exit(dasd_eckd_cleanup);
init_module(void)
{
return dasd_eckd_init();
}
void
cleanup_module(void)
{
dasd_eckd_cleanup();
}
#endif
/* /*
* Overrides for Emacs so that we follow Linus's tabbing style. * Overrides for Emacs so that we follow Linus's tabbing style.
......
/*
* File...........: linux/drivers/s390/block/dasd_eckd.h
* Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
* Horst Hummel <Horst.Hummel@de.ibm.com>
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
*
* $Revision: 1.5 $
*
* History of changes
*
*/
#ifndef DASD_ECKD_H #ifndef DASD_ECKD_H
#define DASD_ECKD_H #define DASD_ECKD_H
...@@ -102,6 +115,10 @@ typedef struct DE_eckd_data_t { ...@@ -102,6 +115,10 @@ typedef struct DE_eckd_data_t {
__u8 ga_extended; /* Global Attributes Extended */ __u8 ga_extended; /* Global Attributes Extended */
ch_t beg_ext; ch_t beg_ext;
ch_t end_ext; ch_t end_ext;
unsigned long long ep_sys_time; /* Extended Parameter - System Time Stamp */
__u8 ep_format; /* Extended Parameter format byte */
__u8 ep_prio; /* Extended Parameter priority I/O byte */
__u8 ep_reserved[6]; /* Extended Parameter Reserved */
} __attribute__ ((packed)) DE_eckd_data_t; } __attribute__ ((packed)) DE_eckd_data_t;
typedef struct LO_eckd_data_t { typedef struct LO_eckd_data_t {
...@@ -141,7 +158,8 @@ typedef struct dasd_eckd_characteristics_t { ...@@ -141,7 +158,8 @@ typedef struct dasd_eckd_characteristics_t {
unsigned char reserved2:4; unsigned char reserved2:4;
unsigned char reserved3:8; unsigned char reserved3:8;
unsigned char defect_wr:1; unsigned char defect_wr:1;
unsigned char reserved4:2; unsigned char XRC_supported:1;
unsigned char reserved4:1;
unsigned char striping:1; unsigned char striping:1;
unsigned char reserved5:4; unsigned char reserved5:4;
unsigned char cfw:1; unsigned char cfw:1;
...@@ -322,6 +340,4 @@ typedef struct dasd_psf_prssd_data_t { ...@@ -322,6 +340,4 @@ typedef struct dasd_psf_prssd_data_t {
unsigned char varies[9]; unsigned char varies[9];
} __attribute__ ((packed)) dasd_psf_prssd_data_t; } __attribute__ ((packed)) dasd_psf_prssd_data_t;
int dasd_eckd_init(void);
void dasd_eckd_cleanup(void);
#endif /* DASD_ECKD_H */ #endif /* DASD_ECKD_H */
...@@ -7,6 +7,9 @@ ...@@ -7,6 +7,9 @@
* 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.6 $
*
* History of changes
* 05/04/02 split from dasd.c, code restructuring. * 05/04/02 split from dasd.c, code restructuring.
*/ */
...@@ -17,7 +20,6 @@ ...@@ -17,7 +20,6 @@
#include <asm/debug.h> #include <asm/debug.h>
#include <asm/ebcdic.h> #include <asm/ebcdic.h>
#include <asm/irq.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
/* This is ugly... */ /* This is ugly... */
...@@ -36,7 +38,7 @@ dasd_alloc_erp_request(char *magic, int cplength, int datasize, ...@@ -36,7 +38,7 @@ dasd_alloc_erp_request(char *magic, int cplength, int datasize,
/* Sanity checks */ /* Sanity checks */
if ( magic == NULL || datasize > PAGE_SIZE || if ( magic == NULL || datasize > PAGE_SIZE ||
(cplength*sizeof(ccw1_t)) > PAGE_SIZE) (cplength*sizeof(struct ccw1)) > PAGE_SIZE)
BUG(); BUG();
debug_text_event ( dasd_debug_area, 1, "ALLC"); debug_text_event ( dasd_debug_area, 1, "ALLC");
debug_text_event ( dasd_debug_area, 1, magic); debug_text_event ( dasd_debug_area, 1, magic);
...@@ -45,7 +47,7 @@ dasd_alloc_erp_request(char *magic, int cplength, int datasize, ...@@ -45,7 +47,7 @@ dasd_alloc_erp_request(char *magic, int cplength, int datasize,
size = (sizeof(dasd_ccw_req_t) + 7L) & -8L; size = (sizeof(dasd_ccw_req_t) + 7L) & -8L;
if (cplength > 0) if (cplength > 0)
size += cplength * sizeof(ccw1_t); size += cplength * sizeof(struct ccw1);
if (datasize > 0) if (datasize > 0)
size += datasize; size += datasize;
spin_lock_irqsave(&device->mem_lock, flags); spin_lock_irqsave(&device->mem_lock, flags);
...@@ -57,9 +59,9 @@ dasd_alloc_erp_request(char *magic, int cplength, int datasize, ...@@ -57,9 +59,9 @@ dasd_alloc_erp_request(char *magic, int cplength, int datasize,
data = (char *) cqr + ((sizeof(dasd_ccw_req_t) + 7L) & -8L); data = (char *) cqr + ((sizeof(dasd_ccw_req_t) + 7L) & -8L);
cqr->cpaddr = NULL; cqr->cpaddr = NULL;
if (cplength > 0) { if (cplength > 0) {
cqr->cpaddr = (ccw1_t *) data; cqr->cpaddr = (struct ccw1 *) data;
data += cplength*sizeof(ccw1_t); data += cplength*sizeof(struct ccw1);
memset(cqr->cpaddr, 0, cplength*sizeof(ccw1_t)); memset(cqr->cpaddr, 0, cplength*sizeof(struct ccw1));
} }
cqr->data = NULL; cqr->data = NULL;
if (datasize > 0) { if (datasize > 0) {
...@@ -201,18 +203,25 @@ hex_dump_memory(dasd_device_t *device, void *data, int len) ...@@ -201,18 +203,25 @@ hex_dump_memory(dasd_device_t *device, void *data, int len)
} }
void void
dasd_log_ccw(dasd_ccw_req_t * cqr, int caller, __u32 cpa) dasd_log_sense(dasd_ccw_req_t *cqr, struct irb *irb)
{ {
dasd_device_t *device; dasd_device_t *device;
dasd_ccw_req_t *lcqr;
ccw1_t *ccw;
int cplength;
device = cqr->device; device = cqr->device;
/* dump sense data */ /* dump sense data */
if (device->discipline && device->discipline->dump_sense) if (device->discipline && device->discipline->dump_sense)
device->discipline->dump_sense(device, cqr); device->discipline->dump_sense(device, cqr, irb);
}
void
dasd_log_ccw(dasd_ccw_req_t * cqr, int caller, __u32 cpa)
{
dasd_device_t *device;
dasd_ccw_req_t *lcqr;
struct ccw1 *ccw;
int cplength;
device = cqr->device;
/* log the channel program */ /* log the channel program */
for (lcqr = cqr; lcqr != NULL; lcqr = lcqr->refers) { for (lcqr = cqr; lcqr != NULL; lcqr = lcqr->refers) {
DEV_MESSAGE(KERN_ERR, device, DEV_MESSAGE(KERN_ERR, device,
...@@ -229,17 +238,17 @@ dasd_log_ccw(dasd_ccw_req_t * cqr, int caller, __u32 cpa) ...@@ -229,17 +238,17 @@ dasd_log_ccw(dasd_ccw_req_t * cqr, int caller, __u32 cpa)
DEV_MESSAGE(KERN_ERR, device, "%s", DEV_MESSAGE(KERN_ERR, device, "%s",
"Start of channel program:"); "Start of channel program:");
hex_dump_memory(device, lcqr->cpaddr, hex_dump_memory(device, lcqr->cpaddr,
40*sizeof(ccw1_t)); 40*sizeof(struct ccw1));
DEV_MESSAGE(KERN_ERR, device, "%s", DEV_MESSAGE(KERN_ERR, device, "%s",
"End of channel program:"); "End of channel program:");
hex_dump_memory(device, lcqr->cpaddr + cplength - 10, hex_dump_memory(device, lcqr->cpaddr + cplength - 10,
10*sizeof(ccw1_t)); 10*sizeof(struct ccw1));
} else { /* log the whole CP */ } else { /* log the whole CP */
DEV_MESSAGE(KERN_ERR, device, "%s", DEV_MESSAGE(KERN_ERR, device, "%s",
"Channel program (complete):"); "Channel program (complete):");
hex_dump_memory(device, lcqr->cpaddr, hex_dump_memory(device, lcqr->cpaddr,
cplength*sizeof(ccw1_t)); cplength*sizeof(struct ccw1));
} }
if (lcqr != cqr) if (lcqr != cqr)
...@@ -258,7 +267,7 @@ dasd_log_ccw(dasd_ccw_req_t * cqr, int caller, __u32 cpa) ...@@ -258,7 +267,7 @@ dasd_log_ccw(dasd_ccw_req_t * cqr, int caller, __u32 cpa)
"Failed CCW (%p) (area):", "Failed CCW (%p) (area):",
(void *) (long) cpa); (void *) (long) cpa);
hex_dump_memory(device, cqr->cpaddr - 10, hex_dump_memory(device, cqr->cpaddr - 10,
20*sizeof(ccw1_t)); 20*sizeof(struct ccw1));
} }
} }
...@@ -268,4 +277,5 @@ EXPORT_SYMBOL(dasd_default_erp_action); ...@@ -268,4 +277,5 @@ EXPORT_SYMBOL(dasd_default_erp_action);
EXPORT_SYMBOL(dasd_default_erp_postaction); EXPORT_SYMBOL(dasd_default_erp_postaction);
EXPORT_SYMBOL(dasd_alloc_erp_request); EXPORT_SYMBOL(dasd_alloc_erp_request);
EXPORT_SYMBOL(dasd_free_erp_request); EXPORT_SYMBOL(dasd_free_erp_request);
EXPORT_SYMBOL(dasd_log_sense);
EXPORT_SYMBOL(dasd_log_ccw); EXPORT_SYMBOL(dasd_log_ccw);
/* /*
* File...........: linux/drivers/s390/block/dasd_fba.c * File...........: linux/drivers/s390/block/dasd_fba.c
* Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
* 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.25 $
*
* History of changes
* fixed partition handling and HDIO_GETGEO * fixed partition handling and HDIO_GETGEO
* 2002/01/04 Created 2.4-2.5 compatibility mode * 2002/01/04 Created 2.4-2.5 compatibility mode
* 05/04/02 code restructuring. * 05/04/02 code restructuring.
...@@ -17,13 +20,14 @@ ...@@ -17,13 +20,14 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/hdreg.h> /* HDIO_GETGEO */ #include <linux/hdreg.h> /* HDIO_GETGEO */
#include <linux/bio.h> #include <linux/bio.h>
#include <linux/module.h>
#include <linux/init.h>
#include <asm/idals.h> #include <asm/idals.h>
#include <asm/ebcdic.h> #include <asm/ebcdic.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/irq.h>
#include <asm/s390dyn.h>
#include <asm/todclk.h> #include <asm/todclk.h>
#include <asm/ccwdev.h>
#include "dasd_int.h" #include "dasd_int.h"
#include "dasd_fba.h" #include "dasd_fba.h"
...@@ -38,30 +42,47 @@ ...@@ -38,30 +42,47 @@
#define DASD_FBA_CCW_LOCATE 0x43 #define DASD_FBA_CCW_LOCATE 0x43
#define DASD_FBA_CCW_DEFINE_EXTENT 0x63 #define DASD_FBA_CCW_DEFINE_EXTENT 0x63
MODULE_LICENSE("GPL");
static dasd_discipline_t dasd_fba_discipline; static dasd_discipline_t dasd_fba_discipline;
typedef struct dasd_fba_private_t { typedef struct dasd_fba_private_t {
dasd_fba_characteristics_t rdc_data; dasd_fba_characteristics_t rdc_data;
} dasd_fba_private_t; } dasd_fba_private_t;
static static struct ccw_device_id dasd_fba_ids[] = {
devreg_t dasd_fba_known_devices[] = { { CCW_DEVICE_DEVTYPE (0x6310, 0, 0x9336, 0), driver_info: 0x1},
{ { CCW_DEVICE_DEVTYPE (0x3880, 0, 0x3370, 0), driver_info: 0x2},
.ci = {.hc = {.ctype = 0x6310, .dtype = 0x9336}}, { /* end of list */ },
.flag = (DEVREG_MATCH_CU_TYPE | };
DEVREG_MATCH_DEV_TYPE | DEVREG_TYPE_DEVCHARS),
.oper_func = dasd_oper_handler MODULE_DEVICE_TABLE(ccw, dasd_fba_ids);
},
{ static struct ccw_driver dasd_fba_driver; /* see below */
.ci = {.hc = {.ctype = 0x3880, .dtype = 0x3370}}, static int
.flag = (DEVREG_MATCH_CU_TYPE | dasd_fba_probe(struct ccw_device *cdev)
DEVREG_MATCH_DEV_TYPE | DEVREG_TYPE_DEVCHARS), {
.oper_func = dasd_oper_handler return dasd_generic_probe (cdev, &dasd_fba_discipline);
} }
static int
dasd_fba_set_online(struct ccw_device *cdev)
{
return dasd_generic_set_online (cdev, &dasd_fba_discipline);
}
static struct ccw_driver dasd_fba_driver = {
.name = "dasd-fba",
.owner = THIS_MODULE,
.ids = dasd_fba_ids,
.probe = dasd_fba_probe,
.remove = dasd_generic_remove,
.set_offline = dasd_generic_set_offline,
.set_online = dasd_fba_set_online,
}; };
static inline void static inline void
define_extent(ccw1_t * ccw, DE_fba_data_t *data, int rw, define_extent(struct ccw1 * ccw, DE_fba_data_t *data, int rw,
int blksize, int beg, int nr) int blksize, int beg, int nr)
{ {
ccw->cmd_code = DASD_FBA_CCW_DEFINE_EXTENT; ccw->cmd_code = DASD_FBA_CCW_DEFINE_EXTENT;
...@@ -81,7 +102,7 @@ define_extent(ccw1_t * ccw, DE_fba_data_t *data, int rw, ...@@ -81,7 +102,7 @@ define_extent(ccw1_t * ccw, DE_fba_data_t *data, int rw,
} }
static inline void static inline void
locate_record(ccw1_t * ccw, LO_fba_data_t *data, int rw, locate_record(struct ccw1 * ccw, LO_fba_data_t *data, int rw,
int block_nr, int block_ct) int block_nr, int block_ct)
{ {
ccw->cmd_code = DASD_FBA_CCW_LOCATE; ccw->cmd_code = DASD_FBA_CCW_LOCATE;
...@@ -99,22 +120,11 @@ locate_record(ccw1_t * ccw, LO_fba_data_t *data, int rw, ...@@ -99,22 +120,11 @@ locate_record(ccw1_t * ccw, LO_fba_data_t *data, int rw,
data->blk_ct = block_ct; data->blk_ct = block_ct;
} }
static inline int static int
dasd_fba_id_check(s390_dev_info_t * info)
{
if (info->sid_data.cu_type == 0x3880)
if (info->sid_data.dev_type == 0x3370)
return 0;
if (info->sid_data.cu_type == 0x6310)
if (info->sid_data.dev_type == 0x9336)
return 0;
return -ENODEV;
}
static inline int
dasd_fba_check_characteristics(struct dasd_device_t *device) dasd_fba_check_characteristics(struct dasd_device_t *device)
{ {
dasd_fba_private_t *private; dasd_fba_private_t *private;
struct ccw_device *cdev = device->cdev;
void *rdc_data; void *rdc_data;
int rc; int rc;
...@@ -130,7 +140,7 @@ dasd_fba_check_characteristics(struct dasd_device_t *device) ...@@ -130,7 +140,7 @@ dasd_fba_check_characteristics(struct dasd_device_t *device)
} }
/* Read Device Characteristics */ /* Read Device Characteristics */
rdc_data = (void *) &(private->rdc_data); rdc_data = (void *) &(private->rdc_data);
rc = read_dev_chars(device->devinfo.irq, &rdc_data, 32); rc = read_dev_chars(device->cdev, &rdc_data, 32);
if (rc) { if (rc) {
MESSAGE(KERN_WARNING, MESSAGE(KERN_WARNING,
"Read device characteristics returned error %d", rc); "Read device characteristics returned error %d", rc);
...@@ -139,27 +149,16 @@ dasd_fba_check_characteristics(struct dasd_device_t *device) ...@@ -139,27 +149,16 @@ dasd_fba_check_characteristics(struct dasd_device_t *device)
DEV_MESSAGE(KERN_INFO, device, DEV_MESSAGE(KERN_INFO, device,
"%04X/%02X(CU:%04X/%02X) %dMB at(%d B/blk)", "%04X/%02X(CU:%04X/%02X) %dMB at(%d B/blk)",
device->devinfo.sid_data.dev_type, cdev->id.dev_type,
device->devinfo.sid_data.dev_model, cdev->id.dev_model,
device->devinfo.sid_data.cu_type, cdev->id.cu_type,
device->devinfo.sid_data.cu_model, cdev->id.cu_model,
((private->rdc_data.blk_bdsa * ((private->rdc_data.blk_bdsa *
(private->rdc_data.blk_size >> 9)) >> 11), (private->rdc_data.blk_size >> 9)) >> 11),
private->rdc_data.blk_size); private->rdc_data.blk_size);
return 0; return 0;
} }
static int
dasd_fba_check_device(struct dasd_device_t *device)
{
int rc;
rc = dasd_fba_id_check(&device->devinfo);
if (rc)
return rc;
return dasd_fba_check_characteristics(device);
}
static int static int
dasd_fba_do_analysis(struct dasd_device_t *device) dasd_fba_do_analysis(struct dasd_device_t *device)
{ {
...@@ -193,20 +192,22 @@ dasd_fba_fill_geometry(struct dasd_device_t *device, struct hd_geometry *geo) ...@@ -193,20 +192,22 @@ dasd_fba_fill_geometry(struct dasd_device_t *device, struct hd_geometry *geo)
} }
static dasd_era_t static dasd_era_t
dasd_fba_examine_error(dasd_ccw_req_t * cqr, devstat_t * stat) dasd_fba_examine_error(dasd_ccw_req_t * cqr, struct irb * irb)
{ {
dasd_device_t *device; dasd_device_t *device;
struct ccw_device *cdev;
device = (dasd_device_t *) cqr->device; device = (dasd_device_t *) cqr->device;
if (stat->cstat == 0x00 && if (irb->scsw.cstat == 0x00 &&
stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
return dasd_era_none; return dasd_era_none;
switch (device->devinfo.sid_data.dev_model) { cdev = device->cdev;
switch (cdev->id.dev_model) {
case 0x3370: case 0x3370:
return dasd_3370_erp_examine(cqr, stat); return dasd_3370_erp_examine(cqr, irb);
case 0x9336: case 0x9336:
return dasd_9336_erp_examine(cqr, stat); return dasd_9336_erp_examine(cqr, irb);
default: default:
return dasd_era_recover; return dasd_era_recover;
} }
...@@ -236,7 +237,7 @@ dasd_fba_build_cp(dasd_device_t * device, struct request *req) ...@@ -236,7 +237,7 @@ dasd_fba_build_cp(dasd_device_t * device, struct request *req)
unsigned long *idaws; unsigned long *idaws;
LO_fba_data_t *LO_data; LO_fba_data_t *LO_data;
dasd_ccw_req_t *cqr; dasd_ccw_req_t *cqr;
ccw1_t *ccw; struct ccw1 *ccw;
struct bio *bio; struct bio *bio;
struct bio_vec *bv; struct bio_vec *bv;
char *dst; char *dst;
...@@ -359,7 +360,8 @@ dasd_fba_fill_info(dasd_device_t * device, dasd_information2_t * info) ...@@ -359,7 +360,8 @@ dasd_fba_fill_info(dasd_device_t * device, dasd_information2_t * info)
} }
static void static void
dasd_fba_dump_sense(struct dasd_device_t *device, dasd_ccw_req_t * req) dasd_fba_dump_sense(struct dasd_device_t *device, dasd_ccw_req_t * req,
struct irb *irb)
{ {
char *page; char *page;
...@@ -369,8 +371,8 @@ dasd_fba_dump_sense(struct dasd_device_t *device, dasd_ccw_req_t * req) ...@@ -369,8 +371,8 @@ dasd_fba_dump_sense(struct dasd_device_t *device, dasd_ccw_req_t * req)
return; return;
} }
sprintf(page, KERN_WARNING PRINTK_HEADER sprintf(page, KERN_WARNING PRINTK_HEADER
"device %04X on irq %d: I/O status report:\n", "device %s: I/O status report:\n",
device->devinfo.devno, device->devinfo.irq); device->cdev->dev.bus_id);
MESSAGE(KERN_ERR, "Sense data:\n%s", page); MESSAGE(KERN_ERR, "Sense data:\n%s", page);
...@@ -396,7 +398,7 @@ static dasd_discipline_t dasd_fba_discipline = { ...@@ -396,7 +398,7 @@ static dasd_discipline_t dasd_fba_discipline = {
.name = "FBA ", .name = "FBA ",
.ebcname = "FBA ", .ebcname = "FBA ",
.max_blocks = 96, .max_blocks = 96,
.check_device = dasd_fba_check_device, .check_device = dasd_fba_check_characteristics,
.do_analysis = dasd_fba_do_analysis, .do_analysis = dasd_fba_do_analysis,
.fill_geometry = dasd_fba_fill_geometry, .fill_geometry = dasd_fba_fill_geometry,
.start_IO = dasd_start_IO, .start_IO = dasd_start_IO,
...@@ -409,41 +411,22 @@ static dasd_discipline_t dasd_fba_discipline = { ...@@ -409,41 +411,22 @@ static dasd_discipline_t dasd_fba_discipline = {
.fill_info = dasd_fba_fill_info, .fill_info = dasd_fba_fill_info,
}; };
int static int __init
dasd_fba_init(void) dasd_fba_init(void)
{ {
int i;
ASCEBC(dasd_fba_discipline.ebcname, 4); ASCEBC(dasd_fba_discipline.ebcname, 4);
dasd_discipline_add(&dasd_fba_discipline);
for (i = 0; i < sizeof(dasd_fba_known_devices) / sizeof(devreg_t); i++)
s390_device_register(&dasd_fba_known_devices[i]);
return 0;
}
void
dasd_fba_cleanup(void)
{
int i;
for (i = 0; i < sizeof(dasd_fba_known_devices) / sizeof(devreg_t); i++) return ccw_driver_register(&dasd_fba_driver);
s390_device_unregister(&dasd_fba_known_devices[i]);
dasd_discipline_del(&dasd_fba_discipline);
} }
#ifdef MODULE static void __exit
int dasd_fba_cleanup(void)
init_module(void)
{ {
return dasd_fba_init(); ccw_driver_unregister(&dasd_fba_driver);
} }
void module_init(dasd_fba_init);
cleanup_module(void) module_exit(dasd_fba_cleanup);
{
dasd_fba_cleanup();
}
#endif
/* /*
* Overrides for Emacs so that we follow Linus's tabbing style. * Overrides for Emacs so that we follow Linus's tabbing style.
......
/*
* File...........: linux/drivers/s390/block/dasd_fba.h
* Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
*
* $Revision: 1.4 $
*
* History of changes
*
*/
#ifndef DASD_FBA_H #ifndef DASD_FBA_H
#define DASD_FBA_H #define DASD_FBA_H
...@@ -71,6 +82,4 @@ typedef ...@@ -71,6 +82,4 @@ typedef
dasd_fba_characteristics_t; dasd_fba_characteristics_t;
int dasd_fba_init(void);
void dasd_fba_cleanup(void);
#endif /* DASD_FBA_H */ #endif /* DASD_FBA_H */
/* /*
* File...........: linux/drivers/s390/block/dasd_ioctl.c * File...........: linux/drivers/s390/block/dasd_genhd.c
* Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
* Horst Hummel <Horst.Hummel@de.ibm.com> * Horst Hummel <Horst.Hummel@de.ibm.com>
* Carsten Otte <Cotte@de.ibm.com> * Carsten Otte <Cotte@de.ibm.com>
...@@ -9,6 +9,9 @@ ...@@ -9,6 +9,9 @@
* *
* Dealing with devices registered to multiple major numbers. * Dealing with devices registered to multiple major numbers.
* *
* $Revision: 1.23 $
*
* History of changes
* 05/04/02 split from dasd.c, code restructuring. * 05/04/02 split from dasd.c, code restructuring.
*/ */
...@@ -19,7 +22,6 @@ ...@@ -19,7 +22,6 @@
#include <linux/blkpg.h> #include <linux/blkpg.h>
#include <linux/blk.h> #include <linux/blk.h>
#include <asm/irq.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
/* This is ugly... */ /* This is ugly... */
...@@ -72,7 +74,6 @@ dasd_register_major(int major) ...@@ -72,7 +74,6 @@ dasd_register_major(int major)
/* Initialize major info structure. */ /* Initialize major info structure. */
mi->major = new_major; mi->major = new_major;
/* Setup block device pointers for the new major. */
/* Insert the new major info structure into dasd_major_info list. */ /* Insert the new major info structure into dasd_major_info list. */
spin_lock(&dasd_major_lock); spin_lock(&dasd_major_lock);
list_add_tail(&mi->list, &dasd_major_info); list_add_tail(&mi->list, &dasd_major_info);
...@@ -104,35 +105,6 @@ dasd_unregister_major(struct major_info * mi) ...@@ -104,35 +105,6 @@ dasd_unregister_major(struct major_info * mi)
kfree(mi); kfree(mi);
} }
/*
* This one is needed for naming 18000+ possible dasd devices.
* dasda - dasdz : 26 devices
* dasdaa - dasdzz : 676 devices, added up = 702
* dasdaaa - dasdzzz : 17576 devices, added up = 18278
*/
int
dasd_device_name(char *str, int index, int partition)
{
int len;
if (partition > DASD_PARTN_MASK)
return -EINVAL;
len = sprintf(str, "dasd");
if (index > 25) {
if (index > 701)
len += sprintf(str + len, "%c",
'a' + (((index - 702) / 676) % 26));
len += sprintf(str + len, "%c",
'a' + (((index - 26) / 26) % 26));
}
len += sprintf(str + len, "%c", 'a' + (index % 26));
if (partition)
len += sprintf(str + len, "%d", partition);
return 0;
}
/* /*
* Allocate gendisk structure for devindex. * Allocate gendisk structure for devindex.
*/ */
...@@ -196,7 +168,7 @@ dasd_gendisk_alloc(int devindex) ...@@ -196,7 +168,7 @@ dasd_gendisk_alloc(int devindex)
/* /*
* Return devindex of first device using a specific major number. * Return devindex of first device using a specific major number.
*/ */
int dasd_gendisk_major_index(int major) static int dasd_gendisk_major_index(int major)
{ {
struct list_head *l; struct list_head *l;
struct major_info *mi; struct major_info *mi;
......
/* /*
* File...........: linux/drivers/s390/block/dasd.c * File...........: linux/drivers/s390/block/dasd_int.h
* Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
* Horst Hummel <Horst.Hummel@de.ibm.com>
* Martin Schwidefsky <schwidefsky@de.ibm.com> * Martin Schwidefsky <schwidefsky@de.ibm.com>
* 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.36 $
*
* History of changes (starts July 2000) * History of changes (starts July 2000)
* 02/01/01 added dynamic registration of ioctls * 02/01/01 added dynamic registration of ioctls
* 2002/01/04 Created 2.4-2.5 compatibility mode * 2002/01/04 Created 2.4-2.5 compatibility mode
...@@ -58,12 +61,11 @@ ...@@ -58,12 +61,11 @@
#include <linux/genhd.h> #include <linux/genhd.h>
#include <linux/hdreg.h> #include <linux/hdreg.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <asm/ccwdev.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <asm/debug.h> #include <asm/debug.h>
#include <asm/dasd.h> #include <asm/dasd.h>
#include <asm/idals.h> #include <asm/idals.h>
#include <asm/irq.h>
#include <asm/s390dyn.h>
/* /*
* SECTION: Type definitions * SECTION: Type definitions
...@@ -140,10 +142,9 @@ do { \ ...@@ -140,10 +142,9 @@ do { \
/* messages to be written via klogd and dbf */ /* messages to be written via klogd and dbf */
#define DEV_MESSAGE(d_loglevel,d_device,d_string,d_args...)\ #define DEV_MESSAGE(d_loglevel,d_device,d_string,d_args...)\
do { \ do { \
printk(d_loglevel PRINTK_HEADER " %s,%04x@%02x: " \ printk(d_loglevel PRINTK_HEADER " %s,%s: " \
d_string "\n", d_device->gdp->disk_name, \ d_string "\n", d_device->gdp->disk_name, \
d_device->devinfo.devno, d_device->devinfo.irq, \ d_device->cdev->dev.bus_id, d_args); \
d_args); \
DBF_DEV_EVENT(DBF_ALERT, d_device, d_string, d_args); \ DBF_DEV_EVENT(DBF_ALERT, d_device, d_string, d_args); \
} while(0) } while(0)
...@@ -159,18 +160,17 @@ typedef struct dasd_ccw_req_t { ...@@ -159,18 +160,17 @@ typedef struct dasd_ccw_req_t {
/* Where to execute what... */ /* Where to execute what... */
struct dasd_device_t *device; /* device the request is for */ struct dasd_device_t *device; /* device the request is for */
ccw1_t *cpaddr; /* address of channel program */ struct ccw1 *cpaddr; /* address of channel program */
char status; /* status of this request */ char status; /* status of this request */
short retries; /* A retry counter */ short retries; /* A retry counter */
/* ... and how */ /* ... and how */
int options; /* options for execution */
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 */
/* these are important for recovering erroneous requests */ /* these are important for recovering erroneous requests */
devstat_t *dstat; /* device status in case of an error */ struct irb *dstat; /* device status in case of an error */
struct dasd_ccw_req_t *refers; /* ERP-chain queueing. */ struct dasd_ccw_req_t *refers; /* ERP-chain queueing. */
void *function; /* originating ERP action */ void *function; /* originating ERP action */
...@@ -247,16 +247,24 @@ typedef struct dasd_discipline_t { ...@@ -247,16 +247,24 @@ typedef struct dasd_discipline_t {
* is called for every error condition to print the sense data * is called for every error condition to print the sense data
* to the console. * to the console.
*/ */
dasd_era_t(*examine_error) (dasd_ccw_req_t *, devstat_t *); dasd_era_t(*examine_error) (dasd_ccw_req_t *, struct irb *);
dasd_erp_fn_t(*erp_action) (dasd_ccw_req_t *); dasd_erp_fn_t(*erp_action) (dasd_ccw_req_t *);
dasd_erp_fn_t(*erp_postaction) (dasd_ccw_req_t *); dasd_erp_fn_t(*erp_postaction) (dasd_ccw_req_t *);
void (*dump_sense) (struct dasd_device_t *, dasd_ccw_req_t *); void (*dump_sense) (struct dasd_device_t *, dasd_ccw_req_t *,
struct irb *);
/* i/o control functions. */ /* i/o control functions. */
int (*fill_geometry) (struct dasd_device_t *, struct hd_geometry *); int (*fill_geometry) (struct dasd_device_t *, struct hd_geometry *);
int (*fill_info) (struct dasd_device_t *, dasd_information2_t *); int (*fill_info) (struct dasd_device_t *, dasd_information2_t *);
} dasd_discipline_t; } dasd_discipline_t;
extern dasd_discipline_t dasd_diag_discipline;
#ifdef CONFIG_DASD_DIAG
#define dasd_diag_discipline_pointer (&dasd_diag_discipline)
#else
#define dasd_diag_discipline_pointer (0)
#endif
typedef struct dasd_device_t { typedef struct dasd_device_t {
/* Block device stuff. */ /* Block device stuff. */
struct gendisk *gdp; struct gendisk *gdp;
...@@ -267,6 +275,8 @@ typedef struct dasd_device_t { ...@@ -267,6 +275,8 @@ typedef struct dasd_device_t {
unsigned int bp_block; /* bytes per block */ unsigned int bp_block; /* bytes per block */
unsigned int s2b_shift; /* log2 (bp_block/512) */ unsigned int s2b_shift; /* log2 (bp_block/512) */
int ro_flag; /* read-only flag */ int ro_flag; /* read-only flag */
int use_diag_flag; /* diag allowed flag */
/* Device discipline stuff. */ /* Device discipline stuff. */
dasd_discipline_t *discipline; dasd_discipline_t *discipline;
...@@ -288,8 +298,8 @@ typedef struct dasd_device_t { ...@@ -288,8 +298,8 @@ typedef struct dasd_device_t {
struct list_head erp_chunks; struct list_head erp_chunks;
/* Common i/o stuff. */ /* Common i/o stuff. */
s390_dev_info_t devinfo; /* FIXME: remove the next */
devstat_t dev_status; int devno;
atomic_t tasklet_scheduled; atomic_t tasklet_scheduled;
struct tasklet_struct tasklet; struct tasklet_struct tasklet;
...@@ -297,6 +307,9 @@ typedef struct dasd_device_t { ...@@ -297,6 +307,9 @@ typedef struct dasd_device_t {
struct timer_list timer; struct timer_list timer;
debug_info_t *debug_area; debug_info_t *debug_area;
struct ccw_device *cdev;
#ifdef CONFIG_DASD_PROFILE #ifdef CONFIG_DASD_PROFILE
dasd_profile_info_t profile; dasd_profile_info_t profile;
#endif #endif
...@@ -318,7 +331,6 @@ typedef struct { ...@@ -318,7 +331,6 @@ typedef struct {
unsigned int devindex; unsigned int devindex;
unsigned short devno; unsigned short devno;
unsigned short features; unsigned short features;
devreg_t *devreg;
dasd_device_t *device; dasd_device_t *device;
} dasd_devmap_t; } dasd_devmap_t;
...@@ -427,17 +439,14 @@ void dasd_kfree_request(dasd_ccw_req_t *, dasd_device_t *); ...@@ -427,17 +439,14 @@ void dasd_kfree_request(dasd_ccw_req_t *, dasd_device_t *);
void dasd_sfree_request(dasd_ccw_req_t *, dasd_device_t *); void dasd_sfree_request(dasd_ccw_req_t *, dasd_device_t *);
static inline int static inline int
dasd_kmalloc_set_cda(ccw1_t *ccw, void *cda, dasd_device_t *device) dasd_kmalloc_set_cda(struct ccw1 *ccw, void *cda, dasd_device_t *device)
{ {
return set_normalized_cda(ccw, cda); return set_normalized_cda(ccw, cda);
} }
dasd_device_t *dasd_alloc_device(dasd_devmap_t *); dasd_device_t *dasd_alloc_device(dasd_devmap_t *);
void dasd_free_device(dasd_device_t *); void dasd_free_device(dasd_device_t *);
void dasd_enable_devices(int, int); void dasd_enable_device(dasd_device_t *);
void dasd_disable_devices(int, int);
void dasd_discipline_add(dasd_discipline_t *);
void dasd_discipline_del(dasd_discipline_t *);
void dasd_set_target_state(dasd_device_t *, int); void dasd_set_target_state(dasd_device_t *, int);
void dasd_kick_device(dasd_device_t *); void dasd_kick_device(dasd_device_t *);
...@@ -445,7 +454,6 @@ void dasd_add_request_head(dasd_ccw_req_t *); ...@@ -445,7 +454,6 @@ void dasd_add_request_head(dasd_ccw_req_t *);
void dasd_add_request_tail(dasd_ccw_req_t *); /* unused */ void dasd_add_request_tail(dasd_ccw_req_t *); /* unused */
int dasd_start_IO(dasd_ccw_req_t *); int dasd_start_IO(dasd_ccw_req_t *);
int dasd_term_IO(dasd_ccw_req_t *); int dasd_term_IO(dasd_ccw_req_t *);
int dasd_oper_handler(int, devreg_t *);
void dasd_schedule_bh(dasd_device_t *); void dasd_schedule_bh(dasd_device_t *);
int dasd_sleep_on(dasd_ccw_req_t *); int dasd_sleep_on(dasd_ccw_req_t *);
int dasd_sleep_on_immediatly(dasd_ccw_req_t *); int dasd_sleep_on_immediatly(dasd_ccw_req_t *);
...@@ -453,6 +461,12 @@ int dasd_sleep_on_interruptible(dasd_ccw_req_t *); ...@@ -453,6 +461,12 @@ int dasd_sleep_on_interruptible(dasd_ccw_req_t *);
void dasd_set_timer(dasd_device_t *, int); void dasd_set_timer(dasd_device_t *, int);
void dasd_clear_timer(dasd_device_t *); void dasd_clear_timer(dasd_device_t *);
int dasd_cancel_req(dasd_ccw_req_t *); /* unused */ int dasd_cancel_req(dasd_ccw_req_t *); /* unused */
int dasd_generic_probe (struct ccw_device *cdev,
dasd_discipline_t *discipline);
int dasd_generic_remove (struct ccw_device *cdev);
int dasd_generic_set_online(struct ccw_device *cdev,
dasd_discipline_t *discipline);
int dasd_generic_set_offline (struct ccw_device *cdev);
/* externals in dasd_devmap.c */ /* externals in dasd_devmap.c */
extern int dasd_max_devindex; extern int dasd_max_devindex;
...@@ -463,20 +477,15 @@ int dasd_devmap_init(void); ...@@ -463,20 +477,15 @@ int dasd_devmap_init(void);
void dasd_devmap_exit(void); void dasd_devmap_exit(void);
dasd_devmap_t *dasd_devmap_from_devno(int); dasd_devmap_t *dasd_devmap_from_devno(int);
dasd_devmap_t *dasd_devmap_from_devindex(int); dasd_devmap_t *dasd_devmap_from_devindex(int);
dasd_devmap_t *dasd_devmap_from_irq(int);
dasd_devmap_t *dasd_devmap_from_bdev(struct block_device *bdev);
dasd_device_t *dasd_get_device(dasd_devmap_t *); dasd_device_t *dasd_get_device(dasd_devmap_t *);
void dasd_put_device(dasd_devmap_t *); void dasd_put_device(dasd_devmap_t *);
int dasd_devno(char *, char **);
int dasd_feature_list(char *, char **);
int dasd_parse(void); int dasd_parse(void);
int dasd_add_range(int, int, int); int dasd_add_range(int, int, int);
/* externals in dasd_gendisk.c */ /* externals in dasd_gendisk.c */
int dasd_gendisk_init(void); int dasd_gendisk_init(void);
void dasd_gendisk_exit(void); void dasd_gendisk_exit(void);
int dasd_gendisk_major_index(int);
int dasd_gendisk_index_major(int); int dasd_gendisk_index_major(int);
struct gendisk *dasd_gendisk_alloc(int); struct gendisk *dasd_gendisk_alloc(int);
void dasd_setup_partitions(dasd_device_t *); void dasd_setup_partitions(dasd_device_t *);
...@@ -498,22 +507,21 @@ dasd_ccw_req_t *dasd_default_erp_action(dasd_ccw_req_t *); ...@@ -498,22 +507,21 @@ dasd_ccw_req_t *dasd_default_erp_action(dasd_ccw_req_t *);
dasd_ccw_req_t *dasd_default_erp_postaction(dasd_ccw_req_t *); dasd_ccw_req_t *dasd_default_erp_postaction(dasd_ccw_req_t *);
dasd_ccw_req_t *dasd_alloc_erp_request(char *, int, int, dasd_device_t *); dasd_ccw_req_t *dasd_alloc_erp_request(char *, int, int, dasd_device_t *);
void dasd_free_erp_request(dasd_ccw_req_t *, dasd_device_t *); void dasd_free_erp_request(dasd_ccw_req_t *, dasd_device_t *);
void dasd_log_sense(dasd_ccw_req_t *, struct irb *);
void dasd_log_ccw(dasd_ccw_req_t *, int, __u32); void dasd_log_ccw(dasd_ccw_req_t *, int, __u32);
/* externals in dasd_3370_erp.c */ /* externals in dasd_3370_erp.c */
dasd_era_t dasd_3370_erp_examine(dasd_ccw_req_t *, devstat_t *); dasd_era_t dasd_3370_erp_examine(dasd_ccw_req_t *, struct irb *);
/* externals in dasd_3990_erp.c */ /* externals in dasd_3990_erp.c */
dasd_era_t dasd_3990_erp_examine(dasd_ccw_req_t *, devstat_t *); dasd_era_t dasd_3990_erp_examine(dasd_ccw_req_t *, struct irb *);
dasd_ccw_req_t *dasd_3990_erp_action(dasd_ccw_req_t *); dasd_ccw_req_t *dasd_3990_erp_action(dasd_ccw_req_t *);
dasd_ccw_req_t *dasd_2105_erp_action(dasd_ccw_req_t *);
void dasd_3990_erp_restart_queue(unsigned long);
/* externals in dasd_9336_erp.c */ /* externals in dasd_9336_erp.c */
dasd_era_t dasd_9336_erp_examine(dasd_ccw_req_t *, devstat_t *); dasd_era_t dasd_9336_erp_examine(dasd_ccw_req_t *, struct irb *);
/* externals in dasd_9336_erp.c */ /* externals in dasd_9336_erp.c */
dasd_era_t dasd_9343_erp_examine(dasd_ccw_req_t *, devstat_t *); dasd_era_t dasd_9343_erp_examine(dasd_ccw_req_t *, struct irb *);
dasd_ccw_req_t *dasd_9343_erp_action(dasd_ccw_req_t *); dasd_ccw_req_t *dasd_9343_erp_action(dasd_ccw_req_t *);
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
#include <linux/blkpg.h> #include <linux/blkpg.h>
#include <linux/blk.h> #include <linux/blk.h>
#include <asm/irq.h> #include <asm/ccwdev.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
/* This is ugly... */ /* This is ugly... */
...@@ -125,7 +125,7 @@ dasd_ioctl(struct inode *inp, struct file *filp, ...@@ -125,7 +125,7 @@ dasd_ioctl(struct inode *inp, struct file *filp,
DBF_DEV_EVENT(DBF_INFO, device, DBF_DEV_EVENT(DBF_INFO, device,
"unknown ioctl 0x%08x=%s'0x%x'%d(%d) data %8lx", no, "unknown ioctl 0x%08x=%s'0x%x'%d(%d) data %8lx", no,
dir, _IOC_TYPE(no), _IOC_NR(no), _IOC_SIZE(no), data); dir, _IOC_TYPE(no), _IOC_NR(no), _IOC_SIZE(no), data);
return -ENOTTY; return -EINVAL;
} }
static int static int
...@@ -137,24 +137,20 @@ dasd_ioctl_api_version(struct block_device *bdev, int no, long args) ...@@ -137,24 +137,20 @@ dasd_ioctl_api_version(struct block_device *bdev, int no, long args)
/* /*
* Enable device. * Enable device.
* FIXME: how can we get here if the device is not already enabled?
* -arnd
*/ */
static int static int
dasd_ioctl_enable(struct block_device *bdev, int no, long args) dasd_ioctl_enable(struct block_device *bdev, int no, long args)
{ {
dasd_devmap_t *devmap;
dasd_device_t *device; dasd_device_t *device;
int devno;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EACCES; return -EACCES;
devmap = dasd_devmap_from_bdev(bdev); device = bdev->bd_disk->private_data;
device = (devmap != NULL) ? if (device == NULL)
dasd_get_device(devmap) : ERR_PTR(-ENODEV); return -ENODEV;
if (IS_ERR(device)) dasd_enable_device(device);
return PTR_ERR(device);
devno = device->devinfo.devno;
dasd_enable_devices(devno, devno);
dasd_put_device(devmap);
return 0; return 0;
} }
...@@ -164,16 +160,13 @@ dasd_ioctl_enable(struct block_device *bdev, int no, long args) ...@@ -164,16 +160,13 @@ dasd_ioctl_enable(struct block_device *bdev, int no, long args)
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)
{ {
dasd_devmap_t *devmap;
dasd_device_t *device; dasd_device_t *device;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EACCES; return -EACCES;
devmap = dasd_devmap_from_bdev(bdev); device = bdev->bd_disk->private_data;
device = (devmap != NULL) ? if (device == NULL)
dasd_get_device(devmap) : ERR_PTR(-ENODEV); return -ENODEV;
if (IS_ERR(device))
return PTR_ERR(device);
/* /*
* Man this is sick. We don't do a real disable but only downgrade * Man this is sick. We don't do a real disable but only downgrade
* the device to DASD_STATE_BASIC. The reason is that dasdfmt uses * the device to DASD_STATE_BASIC. The reason is that dasdfmt uses
...@@ -183,7 +176,6 @@ dasd_ioctl_disable(struct block_device *bdev, int no, long args) ...@@ -183,7 +176,6 @@ 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);
dasd_put_device(devmap);
return 0; return 0;
} }
...@@ -238,35 +230,28 @@ dasd_format(dasd_device_t * device, format_data_t * fdata) ...@@ -238,35 +230,28 @@ dasd_format(dasd_device_t * device, format_data_t * fdata)
static int static int
dasd_ioctl_format(struct block_device *bdev, int no, long args) dasd_ioctl_format(struct block_device *bdev, int no, long args)
{ {
dasd_devmap_t *devmap;
dasd_device_t *device; dasd_device_t *device;
format_data_t fdata; format_data_t fdata;
int rc;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EACCES; return -EACCES;
if (!args) if (!args)
return -EINVAL; return -EINVAL;
/* fdata == NULL is no longer a valid arg to dasd_format ! */ /* fdata == NULL is no longer a valid arg to dasd_format ! */
devmap = dasd_devmap_from_bdev(bdev); device = bdev->bd_disk->private_data;
device = (devmap != NULL) ?
dasd_get_device(devmap) : ERR_PTR(-ENODEV);
if (IS_ERR(device))
return PTR_ERR(device);
rc = 0; if (device == NULL)
if (devmap->features & DASD_FEATURE_READONLY) return -ENODEV;
rc = -EROFS; if (device->ro_flag)
else if (copy_from_user(&fdata, (void *) args, sizeof (format_data_t))) return -EROFS;
rc = -EFAULT; if (copy_from_user(&fdata, (void *) args, sizeof (format_data_t)))
else if (bdev != bdev->bd_contains) { return -EFAULT;
if (bdev != bdev->bd_contains) {
DEV_MESSAGE(KERN_WARNING, device, "%s", DEV_MESSAGE(KERN_WARNING, device, "%s",
"Cannot low-level format a partition"); "Cannot low-level format a partition");
rc = -EINVAL; return -EINVAL;
} else }
rc = dasd_format(device, &fdata); return dasd_format(device, &fdata);
dasd_put_device(devmap);
return rc;
} }
#ifdef CONFIG_DASD_PROFILE #ifdef CONFIG_DASD_PROFILE
...@@ -276,18 +261,16 @@ dasd_ioctl_format(struct block_device *bdev, int no, long args) ...@@ -276,18 +261,16 @@ dasd_ioctl_format(struct block_device *bdev, int no, long args)
static int static int
dasd_ioctl_reset_profile(struct block_device *bdev, int no, long args) dasd_ioctl_reset_profile(struct block_device *bdev, int no, long args)
{ {
dasd_devmap_t *devmap;
dasd_device_t *device; dasd_device_t *device;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EACCES; return -EACCES;
devmap = dasd_devmap_from_bdev(bdev);
device = (devmap != NULL) ? device = = bdev->bd_disk->private_data;
dasd_get_device(devmap) : ERR_PTR(-ENODEV); if (device == NULL)
if (IS_ERR(device)) return -ENODEV;
return PTR_ERR(device);
memset(&device->profile, 0, sizeof (dasd_profile_info_t)); memset(&device->profile, 0, sizeof (dasd_profile_info_t));
dasd_put_device(devmap);
return 0; return 0;
} }
...@@ -297,21 +280,16 @@ dasd_ioctl_reset_profile(struct block_device *bdev, int no, long args) ...@@ -297,21 +280,16 @@ dasd_ioctl_reset_profile(struct block_device *bdev, int no, long args)
static int static int
dasd_ioctl_read_profile(struct block_device *bdev, int no, long args) dasd_ioctl_read_profile(struct block_device *bdev, int no, long args)
{ {
dasd_devmap_t *devmap;
dasd_device_t *device; dasd_device_t *device;
int rc;
devmap = dasd_devmap_from_bdev(bdev); device = = bdev->bd_disk->private_data;
device = (devmap != NULL) ? if (device == NULL)
dasd_get_device(devmap) : ERR_PTR(-ENODEV); return -ENODEV;
if (IS_ERR(device))
return PTR_ERR(device);
rc = 0;
if (copy_to_user((long *) args, (long *) &device->profile, if (copy_to_user((long *) args, (long *) &device->profile,
sizeof (dasd_profile_info_t))) sizeof (dasd_profile_info_t)))
rc = -EFAULT; return -EFAULT;
dasd_put_device(devmap); return 0;
return rc;
} }
#else #else
static int static int
...@@ -333,40 +311,37 @@ dasd_ioctl_read_profile(struct block_device *bdev, int no, long args) ...@@ -333,40 +311,37 @@ dasd_ioctl_read_profile(struct block_device *bdev, int no, long args)
static int static int
dasd_ioctl_information(struct block_device *bdev, int no, long args) dasd_ioctl_information(struct block_device *bdev, int no, long args)
{ {
dasd_devmap_t *devmap;
dasd_device_t *device; dasd_device_t *device;
dasd_information2_t *dasd_info; dasd_information2_t *dasd_info;
unsigned long flags; unsigned long flags;
int rc; int rc;
struct ccw_device *cdev;
devmap = dasd_devmap_from_bdev(bdev); device = bdev->bd_disk->private_data;
device = (devmap != NULL) ? if (device == NULL)
dasd_get_device(devmap) : ERR_PTR(-ENODEV); return -ENODEV;
if (IS_ERR(device))
return PTR_ERR(device); if (!device->discipline->fill_info)
if (!device->discipline->fill_info) {
dasd_put_device(devmap);
return -EINVAL; return -EINVAL;
}
dasd_info = kmalloc(sizeof(dasd_information2_t), GFP_KERNEL); dasd_info = kmalloc(sizeof(dasd_information2_t), GFP_KERNEL);
if (dasd_info == NULL) { if (dasd_info == NULL)
dasd_put_device(devmap);
return -ENOMEM; return -ENOMEM;
}
rc = device->discipline->fill_info(device, dasd_info); rc = device->discipline->fill_info(device, dasd_info);
if (rc) { if (rc) {
dasd_put_device(devmap);
kfree(dasd_info); kfree(dasd_info);
return rc; return rc;
} }
dasd_info->devno = device->devinfo.devno; cdev = device->cdev;
dasd_info->schid = device->devinfo.irq;
dasd_info->cu_type = device->devinfo.sid_data.cu_type; dasd_info->devno = device->devno;
dasd_info->cu_model = device->devinfo.sid_data.cu_model; dasd_info->schid = _ccw_device_get_subchannel_number(device->cdev);
dasd_info->dev_type = device->devinfo.sid_data.dev_type; dasd_info->cu_type = cdev->id.cu_type;
dasd_info->dev_model = device->devinfo.sid_data.dev_model; dasd_info->cu_model = cdev->id.cu_model;
dasd_info->dev_type = cdev->id.dev_type;
dasd_info->dev_model = cdev->id.dev_model;
dasd_info->open_count = atomic_read(&device->open_count); dasd_info->open_count = atomic_read(&device->open_count);
dasd_info->status = device->state; dasd_info->status = device->state;
...@@ -378,7 +353,8 @@ dasd_ioctl_information(struct block_device *bdev, int no, long args) ...@@ -378,7 +353,8 @@ dasd_ioctl_information(struct block_device *bdev, int no, long args)
(dasd_check_blocksize(device->bp_block))) (dasd_check_blocksize(device->bp_block)))
dasd_info->format = DASD_FORMAT_NONE; dasd_info->format = DASD_FORMAT_NONE;
dasd_info->features = devmap->features; dasd_info->features |= device->ro_flag ? DASD_FEATURE_READONLY
: DASD_FEATURE_DEFAULT;
if (device->discipline) if (device->discipline)
memcpy(dasd_info->type, device->discipline->name, 4); memcpy(dasd_info->type, device->discipline->name, 4);
...@@ -397,10 +373,10 @@ dasd_ioctl_information(struct block_device *bdev, int no, long args) ...@@ -397,10 +373,10 @@ dasd_ioctl_information(struct block_device *bdev, int no, long args)
spin_unlock_irqrestore(&device->lock, flags); spin_unlock_irqrestore(&device->lock, flags);
} }
#endif /* DASD_EXTENDED_PROFILING */ #endif /* DASD_EXTENDED_PROFILING */
spin_lock_irqsave(get_irq_lock(device->devinfo.irq), flags); spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
list_for_each(l, &device->ccw_queue) list_for_each(l, &device->ccw_queue)
dasd_info->chanq_len++; dasd_info->chanq_len++;
spin_unlock_irqrestore(get_irq_lock(device->devinfo.irq), spin_unlock_irqrestore(get_ccwdev_lock(device->cdev),
flags); flags);
} }
...@@ -410,7 +386,6 @@ dasd_ioctl_information(struct block_device *bdev, int no, long args) ...@@ -410,7 +386,6 @@ dasd_ioctl_information(struct block_device *bdev, int no, long args)
sizeof (dasd_information2_t) : sizeof (dasd_information2_t) :
sizeof (dasd_information_t)))) sizeof (dasd_information_t))))
rc = -EFAULT; rc = -EFAULT;
dasd_put_device(devmap);
kfree(dasd_info); kfree(dasd_info);
return rc; return rc;
} }
...@@ -421,9 +396,8 @@ dasd_ioctl_information(struct block_device *bdev, int no, long args) ...@@ -421,9 +396,8 @@ dasd_ioctl_information(struct block_device *bdev, int no, long args)
static int static int
dasd_ioctl_set_ro(struct block_device *bdev, int no, long args) dasd_ioctl_set_ro(struct block_device *bdev, int no, long args)
{ {
dasd_devmap_t *devmap;
dasd_device_t *device; dasd_device_t *device;
int intval, i; int intval;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EACCES; return -EACCES;
...@@ -432,18 +406,11 @@ dasd_ioctl_set_ro(struct block_device *bdev, int no, long args) ...@@ -432,18 +406,11 @@ dasd_ioctl_set_ro(struct block_device *bdev, int no, long args)
return -EINVAL; return -EINVAL;
if (get_user(intval, (int *) args)) if (get_user(intval, (int *) args))
return -EFAULT; return -EFAULT;
devmap = dasd_devmap_from_bdev(bdev); device = bdev->bd_disk->private_data;
device = (devmap != NULL) ? if (device == NULL)
dasd_get_device(devmap) : ERR_PTR(-ENODEV); return -ENODEV;
if (IS_ERR(device))
return PTR_ERR(device);
if (intval)
devmap->features |= DASD_FEATURE_READONLY;
else
devmap->features &= ~DASD_FEATURE_READONLY;
set_disk_ro(bdev->bd_disk, intval); set_disk_ro(bdev->bd_disk, intval);
device->ro_flag = intval; device->ro_flag = intval;
dasd_put_device(devmap);
return 0; return 0;
} }
...@@ -454,27 +421,24 @@ static int ...@@ -454,27 +421,24 @@ static int
dasd_ioctl_getgeo(struct block_device *bdev, int no, long args) dasd_ioctl_getgeo(struct block_device *bdev, int no, long args)
{ {
struct hd_geometry geo = { 0, }; struct hd_geometry geo = { 0, };
dasd_devmap_t *devmap;
dasd_device_t *device; dasd_device_t *device;
int rc;
devmap = dasd_devmap_from_bdev(bdev); device = bdev->bd_disk->private_data;
device = (devmap != NULL) ? if (device == NULL)
dasd_get_device(devmap) : ERR_PTR(-ENODEV); return -ENODEV;
if (IS_ERR(device))
return PTR_ERR(device); if (device == NULL || device->discipline == NULL ||
rc = 0; device->discipline->fill_geometry == NULL)
if (device != NULL && device->discipline != NULL && return -EINVAL;
device->discipline->fill_geometry != NULL) {
geo = (struct hd_geometry) {};
device->discipline->fill_geometry(device, &geo); device->discipline->fill_geometry(device, &geo);
geo.start = get_start_sect(bdev); geo.start = get_start_sect(bdev) >> device->s2b_shift;
if (copy_to_user((struct hd_geometry *) args, &geo, if (copy_to_user((struct hd_geometry *) args, &geo,
sizeof (struct hd_geometry))) sizeof (struct hd_geometry)))
rc = -EFAULT; return -EFAULT;
} else
rc = -EINVAL; return 0;
dasd_put_device(devmap);
return rc;
} }
/* /*
......
...@@ -9,16 +9,19 @@ ...@@ -9,16 +9,19 @@
* *
* /proc interface for the dasd driver. * /proc interface for the dasd driver.
* *
* $Revision: 1.17 $
*
* History of changes
* 05/04/02 split from dasd.c, code restructuring. * 05/04/02 split from dasd.c, code restructuring.
*/ */
#include <linux/config.h> #include <linux/config.h>
#include <linux/version.h> #include <linux/version.h>
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/seq_file.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <asm/debug.h> #include <asm/debug.h>
#include <asm/irq.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
/* This is ugly... */ /* This is ugly... */
...@@ -26,47 +29,9 @@ ...@@ -26,47 +29,9 @@
#include "dasd_int.h" #include "dasd_int.h"
typedef struct {
char *data;
int len;
} tempinfo_t;
static struct proc_dir_entry *dasd_proc_root_entry = NULL; static struct proc_dir_entry *dasd_proc_root_entry = NULL;
static struct proc_dir_entry *dasd_devices_entry; static struct proc_dir_entry *dasd_devices_entry = NULL;
static struct proc_dir_entry *dasd_statistics_entry; static struct proc_dir_entry *dasd_statistics_entry = NULL;
static ssize_t
dasd_generic_read(struct file *file, char *user_buf, size_t user_len,
loff_t * offset)
{
loff_t len;
tempinfo_t *p_info = (tempinfo_t *) file->private_data;
if (*offset >= p_info->len)
return 0; /* EOF */
len = p_info->len - *offset;
if (user_len < len)
len = user_len;
if (copy_to_user(user_buf, &(p_info->data[*offset]), len))
return -EFAULT;
(*offset) += len;
return len; /* number of bytes "read" */
}
static int
dasd_generic_close (struct inode *inode, struct file *file)
{
tempinfo_t *info;
info = (tempinfo_t *) file->private_data;
file->private_data = NULL;
if (info) {
if (info->data)
vfree (info->data);
kfree (info);
}
return 0;
}
static inline char * static inline char *
dasd_get_user_string(const char *user_buf, size_t user_len) dasd_get_user_string(const char *user_buf, size_t user_len)
...@@ -88,189 +53,121 @@ dasd_get_user_string(const char *user_buf, size_t user_len) ...@@ -88,189 +53,121 @@ dasd_get_user_string(const char *user_buf, size_t user_len)
return buffer; return buffer;
} }
static ssize_t static int
dasd_devices_write(struct file *file, const char *user_buf, dasd_devices_show(struct seq_file *m, void *v)
size_t user_len, loff_t * offset)
{
char *buffer, *str;
int add_or_set;
int from, to, features;
buffer = dasd_get_user_string(user_buf, user_len);
MESSAGE(KERN_INFO, "/proc/dasd/devices: '%s'", buffer);
/* Scan for "add " or "set ". */
for (str = buffer; isspace(*str); str++);
if (strncmp(str, "add", 3) == 0 && isspace(str[3]))
add_or_set = 0;
else if (strncmp(str, "set", 3) == 0 && isspace(str[3]))
add_or_set = 1;
else
goto out_error;
for (str = str + 4; isspace(*str); str++);
/* Scan for "device " and "range=" and ignore it. This is sick. */
if (strncmp(str, "device", 6) == 0 && isspace(str[6]))
for (str = str + 6; isspace(*str); str++);
if (strncmp(str, "range=", 6) == 0)
for (str = str + 6; isspace(*str); str++);
/* Scan device number range and feature string. */
to = from = dasd_devno(str, &str);
if (*str == '-') {
str++;
to = dasd_devno(str, &str);
}
features = dasd_feature_list(str, &str);
/* Negative numbers in from/to/features indicate errors */
if (from < 0 || to < 0 || from > 65546 || to > 65536 || features < 0)
goto out_error;
if (add_or_set == 0) {
dasd_add_range(from, to, features);
dasd_enable_devices(from, to);
} else {
for (; isspace(*str); str++);
if (strcmp(str, "on") == 0)
dasd_enable_devices(from, to);
else if (strcmp(str, "off") == 0)
dasd_disable_devices(from, to);
else
goto out_error;
}
kfree(buffer);
return user_len;
out_error:
MESSAGE(KERN_WARNING,
"/proc/dasd/devices: range parse error in '%s'",
buffer);
kfree(buffer);
return -EINVAL;
}
static inline int
dasd_devices_print(dasd_devmap_t *devmap, char *str)
{ {
dasd_devmap_t *devmap;
dasd_device_t *device; dasd_device_t *device;
char *substr; char *substr;
int len;
device = dasd_get_device(devmap); devmap = dasd_devmap_from_devindex((unsigned long) v - 1);
device = (devmap != NULL) ?
dasd_get_device(devmap) : ERR_PTR(-ENODEV);
if (IS_ERR(device)) if (IS_ERR(device))
return 0; return 0;
/* Print device number. */ /* Print device number. */
len = sprintf(str, "%04x", devmap->devno); seq_printf(m, "%04x", devmap->devno);
/* Print discipline string. */ /* Print discipline string. */
if (device != NULL && device->discipline != NULL) if (device != NULL && device->discipline != NULL)
len += sprintf(str + len, "(%s)", device->discipline->name); seq_printf(m, "(%s)", device->discipline->name);
else else
len += sprintf(str + len, "(none)"); seq_printf(m, "(none)");
/* Print kdev. */ /* Print kdev. */
len += sprintf(str + len, " at (%3d:%3d)", seq_printf(m, " at (%3d:%3d)",
device->gdp->major, device->gdp->first_minor); device->gdp->major, device->gdp->first_minor);
/* Print device name. */ /* Print device name. */
len += sprintf(str + len, " is %-7s", device->gdp->disk_name); seq_printf(m, " is %-7s", device->gdp->disk_name);
/* Print devices features. */ /* Print devices features. */
substr = (devmap->features & DASD_FEATURE_READONLY) ? "(ro)" : " "; substr = device->ro_flag ? "(ro)" : " ";
len += sprintf(str + len, "%4s: ", substr); seq_printf(m, "%4s: ", substr);
/* Print device status information. */ /* Print device status information. */
if (device == NULL) { switch ((device != NULL) ? device->state : -1) {
len += sprintf(str + len, "unknown"); case -1:
dasd_put_device(devmap); seq_printf(m, "unknown");
return len; break;
}
switch (device->state) {
case DASD_STATE_NEW: case DASD_STATE_NEW:
len += sprintf(str + len, "new"); seq_printf(m, "new");
break; break;
case DASD_STATE_KNOWN: case DASD_STATE_KNOWN:
len += sprintf(str + len, "detected"); seq_printf(m, "detected");
break; break;
case DASD_STATE_BASIC: case DASD_STATE_BASIC:
len += sprintf(str + len, "basic"); seq_printf(m, "basic");
break; break;
case DASD_STATE_ACCEPT: case DASD_STATE_ACCEPT:
len += sprintf(str + len, "accepted"); seq_printf(m, "accepted");
break; break;
case DASD_STATE_READY: case DASD_STATE_READY:
case DASD_STATE_ONLINE: case DASD_STATE_ONLINE:
if (device->state < DASD_STATE_ONLINE) seq_printf(m, "active ");
len += sprintf(str + len, "fenced ");
else
len += sprintf(str + len, "active ");
if (dasd_check_blocksize(device->bp_block)) if (dasd_check_blocksize(device->bp_block))
len += sprintf(str + len, "n/f "); seq_printf(m, "n/f ");
else else
len += sprintf(str + len, seq_printf(m,
"at blocksize: %d, %ld blocks, %ld MB", "at blocksize: %d, %ld blocks, %ld MB",
device->bp_block, device->blocks, device->bp_block, device->blocks,
((device->bp_block >> 9) * ((device->bp_block >> 9) *
device->blocks) >> 11); device->blocks) >> 11);
break; break;
default: default:
len += sprintf(str + len, "no stat"); seq_printf(m, "no stat");
break; break;
} }
dasd_put_device(devmap); dasd_put_device(devmap);
return len; if (dasd_probeonly)
seq_printf(m, "(probeonly)");
seq_printf(m, "\n");
return 0;
} }
static int static void *dasd_devices_start(struct seq_file *m, loff_t *pos)
dasd_devices_open(struct inode *inode, struct file *file)
{ {
tempinfo_t *info; if (*pos >= dasd_max_devindex)
int size, len; return NULL;
int devindex; return (void *)((unsigned long) *pos + 1);
}
info = (tempinfo_t *) kmalloc(sizeof (tempinfo_t), GFP_KERNEL);
if (info == NULL) {
MESSAGE(KERN_WARNING, "%s",
"No memory available for data (tempinfo)");
return -ENOMEM;
}
size = dasd_max_devindex * 128; static void *dasd_devices_next(struct seq_file *m, void *v, loff_t *pos)
info->data = (char *) vmalloc (size); {
if (size && info->data == NULL) { ++*pos;
MESSAGE(KERN_WARNING, "%s", return dasd_devices_start(m, pos);
"No memory available for data (info->data)"); }
kfree(info);
return -ENOMEM;
}
file->private_data = (void *) info;
DBF_EVENT(DBF_NOTICE, static void dasd_devices_stop(struct seq_file *m, void *v)
"procfs-area: %p, size 0x%x allocated", info->data, size); {
}
len = 0; static struct seq_operations dasd_devices_seq_ops = {
for (devindex = 0; devindex < dasd_max_devindex; devindex++) { .start = dasd_devices_start,
dasd_devmap_t *devmap; .next = dasd_devices_next,
.stop = dasd_devices_stop,
.show = dasd_devices_show,
};
devmap = dasd_devmap_from_devindex(devindex); static int dasd_devices_open(struct inode *inode, struct file *file)
len += dasd_devices_print(devmap, info->data + len); {
if (dasd_probeonly) return seq_open(file, &dasd_devices_seq_ops);
len += sprintf(info->data + len, "(probeonly)");
len += sprintf(info->data + len, "\n");
}
info->len = len;
if (len > size) {
printk("len = %i, size = %i\n", len, size);
BUG();
}
return 0;
} }
static struct file_operations dasd_devices_file_ops = { static struct file_operations dasd_devices_file_ops = {
.owner = THIS_MODULE, .open = dasd_devices_open,
.read = dasd_generic_read, /* read */ .read = seq_read,
.write = dasd_devices_write, /* write */ .llseek = seq_lseek,
.open = dasd_devices_open, /* open */ .release = seq_release,
.release = dasd_generic_close, /* close */
}; };
static struct inode_operations dasd_devices_inode_ops = { static inline int
}; dasd_calc_metrics(char *page, char **start, off_t off,
int count, int *eof, int len)
{
len = (len > off) ? len - off : 0;
if (len > count)
len = count;
if (len < count)
*eof = 1;
*start = page + off;
return len;
}
static inline char * static inline char *
dasd_statistics_array(char *str, int *array, int shift) dasd_statistics_array(char *str, int *array, int shift)
...@@ -287,48 +184,28 @@ dasd_statistics_array(char *str, int *array, int shift) ...@@ -287,48 +184,28 @@ dasd_statistics_array(char *str, int *array, int shift)
} }
static int static int
dasd_statistics_open(struct inode *inode, struct file *file) dasd_statistics_read(char *page, char **start, off_t off,
int count, int *eof, void *data)
{ {
tempinfo_t *info; unsigned long len;
#ifdef CONFIG_DASD_PROFILE #ifdef CONFIG_DASD_PROFILE
dasd_profile_info_t *prof; dasd_profile_info_t *prof;
char *str; char *str;
int shift; int shift;
#endif
info = (tempinfo_t *) kmalloc(sizeof (tempinfo_t), GFP_KERNEL);
if (info == NULL) {
MESSAGE(KERN_WARNING, "%s",
"No memory available for data (tempinfo)");
return -ENOMEM;
}
file->private_data = (void *) info;
/* FIXME! determine space needed in a better way */
info->data = (char *) vmalloc (PAGE_SIZE);
if (info->data == NULL) {
MESSAGE(KERN_WARNING, "%s",
"No memory available for data (info->data)");
kfree(info);
file->private_data = NULL;
return -ENOMEM;
}
#ifdef CONFIG_DASD_PROFILE
/* check for active profiling */ /* check for active profiling */
if (dasd_profile_level == DASD_PROFILE_OFF) { if (dasd_profile_level == DASD_PROFILE_OFF) {
info->len = sprintf(info->data, len = sprintf(page, "Statistics are off - they might be "
"Statistics are off - they might be "
"switched on using 'echo set on > " "switched on using 'echo set on > "
"/proc/dasd/statistics'\n"); "/proc/dasd/statistics'\n");
return 0; return dasd_calc_metrics(page, start, off, count, eof, len);
} }
prof = &dasd_global_profile; prof = &dasd_global_profile;
/* prevent couter 'overflow' on output */ /* prevent couter 'overflow' on output */
for (shift = 0; (prof->dasd_io_reqs >> shift) > 9999999; shift++); for (shift = 0; (prof->dasd_io_reqs >> shift) > 9999999; shift++);
str = info->data; str = page;
str += sprintf(str, "%d dasd I/O requests\n", prof->dasd_io_reqs); str += sprintf(str, "%d dasd I/O requests\n", prof->dasd_io_reqs);
str += sprintf(str, "with %d sectors(512B each)\n", str += sprintf(str, "with %d sectors(512B each)\n",
prof->dasd_io_sects); prof->dasd_io_sects);
...@@ -358,22 +235,22 @@ dasd_statistics_open(struct inode *inode, struct file *file) ...@@ -358,22 +235,22 @@ dasd_statistics_open(struct inode *inode, struct file *file)
str = dasd_statistics_array(str, prof->dasd_io_time3, shift); str = dasd_statistics_array(str, prof->dasd_io_time3, shift);
str += sprintf(str, "# of req in chanq at enqueuing (1..32) \n"); str += sprintf(str, "# of req in chanq at enqueuing (1..32) \n");
str = dasd_statistics_array(str, prof->dasd_io_nr_req, shift); str = dasd_statistics_array(str, prof->dasd_io_nr_req, shift);
len = str - page;
info->len = str - info->data;
#else #else
info->len = sprintf(info->data, len = sprintf(page, "Statistics are not activated in this kernel\n");
"Statistics are not activated in this kernel\n");
#endif #endif
return 0; return dasd_calc_metrics(page, start, off, count, eof, len);
} }
static ssize_t static int
dasd_statistics_write(struct file *file, const char *user_buf, dasd_statistics_write(struct file *file, const char *user_buf,
size_t user_len, loff_t * offset) unsigned long user_len, void *data)
{ {
#ifdef CONFIG_DASD_PROFILE #ifdef CONFIG_DASD_PROFILE
char *buffer, *str; char *buffer, *str;
if (user_len > 65536)
user_len = 65536;
buffer = dasd_get_user_string(user_buf, user_len); buffer = dasd_get_user_string(user_buf, user_len);
MESSAGE(KERN_INFO, "/proc/dasd/statictics: '%s'", buffer); MESSAGE(KERN_INFO, "/proc/dasd/statictics: '%s'", buffer);
...@@ -415,31 +292,22 @@ dasd_statistics_write(struct file *file, const char *user_buf, ...@@ -415,31 +292,22 @@ dasd_statistics_write(struct file *file, const char *user_buf,
#endif /* CONFIG_DASD_PROFILE */ #endif /* CONFIG_DASD_PROFILE */
} }
static struct file_operations dasd_statistics_file_ops = {
.owner = THIS_MODULE,
.read = dasd_generic_read, /* read */
.write = dasd_statistics_write, /* write */
.open = dasd_statistics_open, /* open */
.release = dasd_generic_close, /* close */
};
static struct inode_operations dasd_statistics_inode_ops = {
};
int int
dasd_proc_init(void) dasd_proc_init(void)
{ {
dasd_proc_root_entry = proc_mkdir("dasd", &proc_root); dasd_proc_root_entry = proc_mkdir("dasd", &proc_root);
dasd_proc_root_entry->owner = THIS_MODULE;
dasd_devices_entry = create_proc_entry("devices", dasd_devices_entry = create_proc_entry("devices",
S_IFREG | S_IRUGO | S_IWUSR, S_IFREG | S_IRUGO | S_IWUSR,
dasd_proc_root_entry); dasd_proc_root_entry);
dasd_devices_entry->proc_fops = &dasd_devices_file_ops; dasd_devices_entry->proc_fops = &dasd_devices_file_ops;
dasd_devices_entry->proc_iops = &dasd_devices_inode_ops; dasd_devices_entry->owner = THIS_MODULE;
dasd_statistics_entry = create_proc_entry("statistics", dasd_statistics_entry = create_proc_entry("statistics",
S_IFREG | S_IRUGO | S_IWUSR, S_IFREG | S_IRUGO | S_IWUSR,
dasd_proc_root_entry); dasd_proc_root_entry);
dasd_statistics_entry->proc_fops = &dasd_statistics_file_ops; dasd_statistics_entry->read_proc = dasd_statistics_read;
dasd_statistics_entry->proc_iops = &dasd_statistics_inode_ops; dasd_statistics_entry->write_proc = dasd_statistics_write;
dasd_statistics_entry->owner = THIS_MODULE;
return 0; return 0;
} }
......
...@@ -8,6 +8,8 @@ ...@@ -8,6 +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 $
*
* History of changes (starts July 2000) * History of changes (starts July 2000)
* 05/04/01 created by moving the kernel interface to drivers/s390/block/dasd_int.h * 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) * 12/06/01 DASD_API_VERSION 2 - binary compatible to 0 (new BIODASDINFO2)
...@@ -224,8 +226,6 @@ typedef struct attrib_data_t { ...@@ -224,8 +226,6 @@ 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)
/* enable PAV */
#define BIODASDENAPAV _IO(DASD_IOCTL_LETTER,6)
/* retrieve API version number */ /* retrieve API version number */
......
...@@ -8,6 +8,8 @@ ...@@ -8,6 +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 $
*
* History of changes (starts July 2000) * History of changes (starts July 2000)
* 05/04/01 created by moving the kernel interface to drivers/s390/block/dasd_int.h * 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) * 12/06/01 DASD_API_VERSION 2 - binary compatible to 0 (new BIODASDINFO2)
...@@ -224,8 +226,6 @@ typedef struct attrib_data_t { ...@@ -224,8 +226,6 @@ 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)
/* enable PAV */
#define BIODASDENAPAV _IO(DASD_IOCTL_LETTER,6)
/* 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