patch-2.4.8 linux/drivers/s390/block/dasd.c
Next file: linux/drivers/s390/block/dasd_3370_erp.c
Previous file: linux/drivers/s390/block/Makefile
Back to the patch index
Back to the overall index
- Lines: 5682
- Date:
Sun Aug 5 13:12:41 2001
- Orig file:
v2.4.7/linux/drivers/s390/block/dasd.c
- Orig date:
Tue May 15 01:29:34 2001
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/block/dasd.c linux/drivers/s390/block/dasd.c
@@ -1,14 +1,13 @@
-/*
+/*
* File...........: linux/drivers/s390/block/dasd.c
* 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>
* Bugreports.to..: <Linux390@de.ibm.com>
- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
*
* History of changes (starts July 2000)
* 11/09/00 complete redesign after code review
- * 02/01/01 removed some warnings
* 02/01/01 added dynamic registration of ioctls
* fixed bug in registration of new majors
* fixed handling of request during dasd_end_request
@@ -18,20 +17,34 @@
* fixed some race conditions related to modules
* added devfs suupport
* 03/06/01 refined dynamic attach/detach for leaving devices which are online.
- * 06/09/01 refined dynamic modifiaction of devices
- * renewed debug feature exploitation
+ * 03/09/01 refined dynamic modifiaction of devices
+ * 03/12/01 moved policy in dasd_format to dasdfmt (renamed BIODASDFORMAT)
+ * 03/19/01 added BIODASDINFO-ioctl
+ * removed 2.2 compatibility
+ * 04/27/01 fixed PL030119COT (dasd_disciplines does not work)
+ * 04/30/01 fixed PL030146HSM (module locking with dynamic ioctls)
+ * fixed PL030130SBA (handling of invalid ranges)
+ * 05/02/01 fixed PL030145SBA (killing dasdmt)
+ * fixed PL030149SBA (status of 'accepted' devices)
+ * fixed PL030146SBA (BUG in ibm.c after adding device)
+ * added BIODASDPRRD ioctl interface
+ * 05/11/01 fixed PL030164MVE (trap in probeonly mode)
+ * 05/15/01 fixed devfs support for unformatted devices
+ * 06/26/01 hopefully fixed PL030172SBA,PL030234SBA
+ * 07/09/01 fixed PL030324MSH (wrong statistics output)
+ * 07/16/01 merged in new fixes for handling low-mem situations
*/
-#include <linux/module.h>
#include <linux/config.h>
#include <linux/version.h>
+#include <linux/kmod.h>
#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/tqueue.h>
#include <linux/timer.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/genhd.h>
#include <linux/hdreg.h>
#include <linux/interrupt.h>
@@ -42,9 +55,9 @@
#include <linux/spinlock.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/blkpg.h>
+#include <linux/wait.h>
#include <asm/ccwcache.h>
-#include <asm/dasd.h>
#include <asm/debug.h>
#include <asm/atomic.h>
@@ -57,6 +70,9 @@
#include <asm/s390_ext.h>
#include <asm/s390dyn.h>
#include <asm/idals.h>
+#include <asm/dasd.h>
+
+#include "dasd_int.h"
#ifdef CONFIG_DASD_ECKD
#include "dasd_eckd.h"
@@ -68,25 +84,40 @@
#include "dasd_diag.h"
#endif /* CONFIG_DASD_DIAG */
+/* SECTION: exported variables of dasd.c */
+
+debug_info_t *dasd_debug_area;
+
MODULE_AUTHOR ("Holger Smolinski <Holger.Smolinski@de.ibm.com>");
MODULE_DESCRIPTION ("Linux on S/390 DASD device driver,"
" Copyright 2000 IBM Corporation");
MODULE_SUPPORTED_DEVICE ("dasd");
MODULE_PARM (dasd, "1-" __MODULE_STRING (256) "s");
-EXPORT_SYMBOL (dasd_discipline_enq);
-EXPORT_SYMBOL (dasd_discipline_deq);
+MODULE_PARM (dasd_disciplines, "1-" __MODULE_STRING (8) "s");
+EXPORT_SYMBOL (dasd_chanq_enq_head);
+EXPORT_SYMBOL (dasd_debug_area);
+EXPORT_SYMBOL (dasd_chanq_enq);
+EXPORT_SYMBOL (dasd_chanq_deq);
+EXPORT_SYMBOL (dasd_discipline_add);
+EXPORT_SYMBOL (dasd_discipline_del);
EXPORT_SYMBOL (dasd_start_IO);
+EXPORT_SYMBOL (dasd_term_IO);
+EXPORT_SYMBOL (dasd_schedule_bh);
EXPORT_SYMBOL (dasd_int_handler);
+EXPORT_SYMBOL (dasd_oper_handler);
EXPORT_SYMBOL (dasd_alloc_request);
EXPORT_SYMBOL (dasd_free_request);
-EXPORT_SYMBOL(dasd_ioctl_no_register);
-EXPORT_SYMBOL(dasd_ioctl_no_unregister);
+EXPORT_SYMBOL (dasd_ioctl_no_register);
+EXPORT_SYMBOL (dasd_ioctl_no_unregister);
+EXPORT_SYMBOL (dasd_default_erp_action);
+EXPORT_SYMBOL (dasd_default_erp_postaction);
+EXPORT_SYMBOL (dasd_sleep_on_req);
+EXPORT_SYMBOL (dasd_set_normalized_cda);
/* SECTION: Constant definitions to be used within this file */
-#define PRINTK_HEADER DASD_NAME": "
+#define PRINTK_HEADER DASD_NAME":"
-#define DASD_EMERGENCY_REQUESTS 16
#define DASD_MIN_SIZE_FOR_QUEUE 32
#undef CONFIG_DYNAMIC_QUEUE_MIN_SIZE
#define DASD_CHANQ_MAX_SIZE 6
@@ -94,27 +125,36 @@
/* SECTION: prototypes for static functions of dasd.c */
static request_fn_proc do_dasd_request;
-static int dasd_set_device_level (unsigned int, int, dasd_discipline_t *, int);
+static int dasd_set_device_level (unsigned int, dasd_discipline_t *, int);
static request_queue_t *dasd_get_queue (kdev_t kdev);
static void cleanup_dasd (void);
-int dasd_fillgeo(int kdev,struct hd_geometry *geo);
-
+static void dasd_plug_device (dasd_device_t * device);
+static int dasd_fillgeo (int kdev, struct hd_geometry *geo);
+static void dasd_enable_ranges (dasd_range_t *, dasd_discipline_t *, int);
+static void dasd_disable_ranges (dasd_range_t *, dasd_discipline_t *, int, int);
+static void dasd_enable_single_device ( unsigned long);
+static inline int dasd_state_init_to_ready(dasd_device_t*);
+static inline void dasd_setup_partitions ( dasd_device_t *);
+static inline int dasd_setup_blkdev(dasd_device_t*);
+static inline int dasd_disable_blkdev(dasd_device_t*);
+static void dasd_flush_chanq ( dasd_device_t * device, int destroy );
+static void dasd_flush_request_queues ( dasd_device_t * device, int destroy );
static struct block_device_operations dasd_device_operations;
-
+static inline dasd_device_t ** dasd_device_from_devno (int);
+static void dasd_process_queues (dasd_device_t * device);
/* SECTION: static variables of dasd.c */
static devfs_handle_t dasd_devfs_handle;
-
-/* SECTION: exported variables of dasd.c */
-
-debug_info_t *dasd_debug_area;
+static wait_queue_head_t dasd_init_waitq;
+static atomic_t dasd_init_pending = ATOMIC_INIT (0);
#ifdef CONFIG_DASD_DYNAMIC
+
/* SECTION: managing dynamic configuration of dasd_driver */
-static struct list_head dasd_devreg_head = LIST_HEAD_INIT(dasd_devreg_head);
+static struct list_head dasd_devreg_head = LIST_HEAD_INIT (dasd_devreg_head);
-/*
+/*
* function: dasd_create_devreg
* creates a dasd_devreg_t related to a devno
*/
@@ -131,7 +171,7 @@
return r;
}
-/*
+/*
* function: dasd_destroy_devreg
* destroys the dasd_devreg_t given as argument
*/
@@ -149,44 +189,44 @@
static int dasd_probeonly = 1; /* is true, when probeonly mode is active */
static int dasd_autodetect = 1; /* is true, when autodetection is active */
-/* dasd_range_t are used for ordering the DASD devices */
-typedef struct dasd_range_t {
- unsigned int from; /* first DASD in range */
- unsigned int to; /* last DASD in range */
- char discipline[4]; /* placeholder to force discipline */
- struct dasd_range_t *next; /* next one in linked list */
-} dasd_range_t;
-
-static dasd_range_t *dasd_range_head = NULL; /* anchor for list of ranges */
+static dasd_range_t dasd_range_head =
+ { list:LIST_HEAD_INIT (dasd_range_head.list) };
static spinlock_t range_lock = SPIN_LOCK_UNLOCKED;
-static spinlock_t dasd_open_count_lock;
-/*
+/*
* function: dasd_create_range
- * creates a dasd_range_t according to the arguments
+ * creates a dasd_range_t according to the arguments
* FIXME: no check is performed for reoccurrence of a devno
*/
static inline dasd_range_t *
-dasd_create_range (int from, int to)
+dasd_create_range (int from, int to, int features)
{
dasd_range_t *range = NULL;
+ int i;
+
+ if ( from > to ) {
+ printk (KERN_WARNING PRINTK_HEADER "Adding device range %04X-%04X: range invalid, ignoring.\n",from,to);
+ return NULL;
+ }
+ for (i=from;i<=to;i++) {
+ if (dasd_device_from_devno(i)) {
+ printk (KERN_WARNING PRINTK_HEADER "device range %04X-%04X: device %04X is already in a range.\n",from,to,i);
+ }
+ }
range = (dasd_range_t *) kmalloc (sizeof (dasd_range_t), GFP_KERNEL);
if (range == NULL)
return NULL;
memset (range, 0, sizeof (dasd_range_t));
range->from = from;
- if (to == 0) { /* single devno ? */
- range->to = from;
- } else {
- range->to = to;
- }
+ range->to = to;
+ range->features = features;
return range;
}
-/*
+/*
* function dasd_destroy_range
* destroy a range allocated wit dasd_crate_range
- * CAUTION: must not be callen in arunning sysztem, because it destroys
+ * CAUTION: must not be callen in arunning sysztem, because it destroys
* the mapping of DASDs
*/
static inline void
@@ -195,68 +235,50 @@
kfree (range);
}
-/*
+/*
* function: dasd_append_range
- * appends the range given as argument to the list anchored at dasd_range_head.
+ * appends the range given as argument to the list anchored at dasd_range_head.
*/
static inline void
dasd_append_range (dasd_range_t * range)
{
- dasd_range_t *temp;
long flags;
spin_lock_irqsave (&range_lock, flags);
- if (dasd_range_head == NULL) {
- dasd_range_head = range;
- } else {
- for (temp = dasd_range_head;
- temp && temp->next;
- temp = temp->next) ;
- temp->next = range;
- }
+ list_add_tail (&range->list, &dasd_range_head.list);
spin_unlock_irqrestore (&range_lock, flags);
}
/*
* function dasd_dechain_range
* removes a range from the chain of ranges
- * CAUTION: must not be called in a running system because it destroys
+ * CAUTION: must not be called in a running system because it destroys
* the mapping of devices
*/
static inline void
dasd_dechain_range (dasd_range_t * range)
{
- dasd_range_t *temp, *prev = NULL;
unsigned long flags;
spin_lock_irqsave (&range_lock, flags);
- for (temp = dasd_range_head; temp != NULL; temp = temp->next) {
- if (temp == range)
- break;
- prev = temp;
- }
- if (!temp)
- BUG ();
- if (prev) {
- prev->next = temp->next;
- } else {
- dasd_range_head = temp->next;
- }
+ list_del (&range->list);
spin_unlock_irqrestore (&range_lock, flags);
}
-/*
+/*
* function: dasd_add_range
* creates a dasd_range_t according to the arguments and
* appends it to the list of ranges
- * additionally a devreg_t is created and added to the list of devregs
+ * additionally a devreg_t is created and added to the list of devregs
*/
-static inline dasd_range_t*
-dasd_add_range (int from, int to)
+static inline dasd_range_t *
+dasd_add_range (int from, int to, int features)
{
dasd_range_t *range;
- range = dasd_create_range (from, to);
- if (!range) return NULL;
+
+ range = dasd_create_range (from, to, features);
+ if (!range)
+ return NULL;
dasd_append_range (range);
#ifdef CONFIG_DASD_DYNAMIC
@@ -266,14 +288,14 @@
for (i = range->from; i <= range->to; i++) {
dasd_devreg_t *reg = dasd_create_devreg (i);
s390_device_register (®->devreg);
- list_add(®->list,&dasd_devreg_head);
+ list_add (®->list, &dasd_devreg_head);
}
}
#endif /* CONFIG_DASD_DYNAMIC */
return range;
}
-/*
+/*
* function: dasd_remove_range
* removes a range and the corresponding devregs from all of the chains
* CAUTION: must not be called in a running system because it destroys
@@ -287,10 +309,10 @@
{
int i;
for (i = range->from; i <= range->to; i++) {
- struct list_head *l;
- dasd_devreg_t *reg = NULL;
+ struct list_head *l;
+ dasd_devreg_t *reg = NULL;
list_for_each (l, &dasd_devreg_head) {
- reg = list_entry(l,dasd_devreg_t,list);
+ reg = list_entry (l, dasd_devreg_t, list);
if (reg->devreg.flag == DEVREG_TYPE_DEVNO &&
reg->devreg.ci.devno == i &&
reg->devreg.oper_func == dasd_oper_handler)
@@ -319,9 +341,11 @@
dasd_range_t *temp;
int devindex = 0;
unsigned long flags;
+ struct list_head *l;
spin_lock_irqsave (&range_lock, flags);
- for (temp = dasd_range_head; temp; temp = temp->next) {
+ list_for_each (l, &dasd_range_head.list) {
+ temp = list_entry (l, dasd_range_t, list);
if (devno >= temp->from && devno <= temp->to) {
spin_unlock_irqrestore (&range_lock, flags);
return devindex + devno - temp->from;
@@ -332,19 +356,43 @@
return -ENODEV;
}
+/*
+ * function: dasd_devno_from_devindex
+ */
+static int
+dasd_devno_from_devindex (int devindex)
+{
+ dasd_range_t *temp;
+ unsigned long flags;
+ struct list_head *l;
+
+ spin_lock_irqsave (&range_lock, flags);
+ list_for_each (l, &dasd_range_head.list) {
+ temp = list_entry (l, dasd_range_t, list);
+ if ( devindex < temp->to - temp->from + 1) {
+ spin_unlock_irqrestore (&range_lock, flags);
+ return temp->from + devindex;
+ }
+ devindex -= temp->to - temp->from + 1;
+ }
+ spin_unlock_irqrestore (&range_lock, flags);
+ return -ENODEV;
+}
+
/* SECTION: parsing the dasd= parameter of the parmline/insmod cmdline */
-/*
+/*
* char *dasd[] is intended to hold the ranges supplied by the dasd= statement
* it is named 'dasd' to directly be filled by insmod with the comma separated
* strings when running as a module.
* a maximum of 256 ranges can be supplied, as the parmline is limited to
* <1024 Byte anyway.
*/
-char *dasd[256] = {NULL,};
+char *dasd[256];
+char *dasd_disciplines[8];
#ifndef MODULE
-/*
+/*
* function: dasd_split_parm_string
* splits the parmline given to the kernel into comma separated strings
* which are filled into the 'dasd[]' array, to be parsed later on
@@ -354,7 +402,7 @@
{
char *tmp = str;
int count = 0;
- do {
+ while (tmp != NULL && *tmp != '\0') {
char *end;
int len;
end = strchr (tmp, ',');
@@ -366,27 +414,28 @@
end++;
}
dasd[count] = kmalloc (len * sizeof (char), GFP_ATOMIC);
- if (dasd == NULL) {
+ if (dasd[count] == NULL) {
printk (KERN_WARNING PRINTK_HEADER
- "can't store dasd= parameter no %d\n", count + 1);
+ "can't store dasd= parameter no %d\n",
+ count + 1);
break;
}
memset (dasd[count], 0, len * sizeof (char));
memcpy (dasd[count], tmp, len * sizeof (char));
count++;
tmp = end;
- } while (tmp != NULL && *tmp != '\0');
+ };
}
-/*
+/*
* dasd_parm_string holds a concatenated version of all 'dasd=' parameters
- * supplied in the parmline, which is later to be split by
+ * supplied in the parmline, which is later to be split by
* dasd_split_parm_string
* FIXME: why first concatenate then split ?
*/
-static char dasd_parm_string[1024] __initdata = {0,};
+static char dasd_parm_string[1024] __initdata = { 0, };
-/*
+/*
* function: dasd_setup
* is invoked for any single 'dasd=' parameter supplied in the parmline
* it merges all the arguments into dasd_parm_string
@@ -400,44 +449,90 @@
}
strcat (dasd_parm_string, str);
}
-/*
- * function: dasd_call_setup
+
+/*
+ * function: dasd_call_setup
* is the 2.4 version of dasd_setup and
* is invoked for any single 'dasd=' parameter supplied in the parmline
*/
int __init
dasd_call_setup (char *str)
{
- int dummy;
- dasd_setup(str,&dummy);
+ int dummy;
+ dasd_setup (str, &dummy);
+ return 1;
+}
+
+int __init
+dasd_disciplines_setup (char *str)
+{
return 1;
}
__setup ("dasd=", dasd_call_setup);
+__setup ("dasd_disciplines=", dasd_disciplines_setup);
-#endif /* MODULE */
+#endif /* MODULE */
-/*
+/*
* function: dasd_strtoul
* provides a wrapper to simple_strtoul to strip leading '0x' and
* interpret any argument to dasd=[range,...] as hexadecimal
*/
static inline int
-dasd_strtoul (char *str, char **stra)
+dasd_strtoul (char *str, char **stra, int* features)
{
- char *temp = str;
- int val;
- if (*temp == '0') {
- temp++; /* strip leading zero */
- if (*temp == 'x')
- temp++; /* strip leading x */
- }
- val = simple_strtoul (temp, &temp, 16); /* interpret anything as hex */
- *stra = temp;
- return val;
+ char *temp=str;
+ char *buffer;
+ int val,i,start;
+
+ buffer=(char*)kmalloc((strlen(str)+1)*sizeof(char),GFP_ATOMIC);
+ if (buffer==NULL) {
+ printk (KERN_WARNING PRINTK_HEADER
+ "can't parse dasd= parameter %s due to low memory\n",
+ str);
+ }
+
+ /* remove leading '0x' */
+ if (*temp == '0') {
+ temp++; /* strip leading zero */
+ if (*temp == 'x')
+ temp++; /* strip leading x */
+ }
+
+ /* copy device no to buffer and convert to decimal */
+ for (i=0;isxdigit(temp[i]);i++)
+ buffer[i]=temp[i];
+ buffer[i]='\0';
+
+ val = simple_strtoul (buffer, &buffer, 16);
+
+ /* check for features - e.g. (ro) ; the '\0', ')' and '-' stops check */
+ if (temp[i]=='(') {
+
+ while (temp[i]!='\0' && temp[i]!=')'&&temp[i]!='-') {
+ start=++i;
+
+ /* move next feature to buffer */
+ for (;temp[i]!='\0'&&temp[i]!=':'&&temp[i]!=')'&&temp[i]!='-';i++)
+ buffer[i-start]=temp[i];
+ buffer[i-start]='\0';
+
+ if (strlen(buffer)) {
+ if (!strcmp(buffer,"ro")) { /* handle 'ro' feature */
+ (*features) |= DASD_FEATURE_READONLY;
+ break;
+ }
+ printk (KERN_WARNING PRINTK_HEADER
+ "unsupported feature: %s, ignoring setting",buffer);
+ }
+ }
+ }
+ *stra = temp+i;
+ return val;
}
-/*
+/*
* function: dasd_parse
* examines the strings given in the string array str and
* creates and adds the ranges to the apropriate lists
@@ -447,6 +542,7 @@
{
char *temp;
int from, to;
+ int features = 0;
if (*str) {
/* turn off probeonly mode, if any dasd parameter is present */
@@ -468,12 +564,13 @@
} else {
/* turn off autodetect mode, if any range is present */
dasd_autodetect = 0;
- from = dasd_strtoul (temp, &temp);
+ from = dasd_strtoul (temp, &temp, &features);
+ to = from;
if (*temp == '-') {
temp++;
- to = dasd_strtoul (temp, &temp);
+ to = dasd_strtoul (temp, &temp, &features);
}
- dasd_add_range (from, to);
+ dasd_add_range (from, to ,features);
}
str++;
}
@@ -483,18 +580,16 @@
static spinlock_t dasd_major_lock = SPIN_LOCK_UNLOCKED;
-static major_info_t dasd_major_info[] =
-{
+static major_info_t dasd_major_info[] = {
{
- list: LIST_HEAD_INIT(dasd_major_info[1].list )
- },
+ list:LIST_HEAD_INIT (dasd_major_info[1].list)
+ },
{
- list: LIST_HEAD_INIT(dasd_major_info[0].list ),
- gendisk: {
- INIT_GENDISK(94,DASD_NAME,DASD_PARTN_BITS,DASD_PER_MAJOR)
- },
- flags : DASD_MAJOR_INFO_IS_STATIC
- }
+ list:LIST_HEAD_INIT (dasd_major_info[0].list),
+ gendisk:{
+ INIT_GENDISK (94, DASD_NAME, DASD_PARTN_BITS, DASD_PER_MAJOR)
+ },
+ flags:DASD_MAJOR_INFO_IS_STATIC}
};
static major_info_t *
@@ -504,17 +599,21 @@
major_info = kmalloc (sizeof (major_info_t), GFP_KERNEL);
if (major_info) {
- static major_info_t temp_major_info =
- {
- gendisk: {
- INIT_GENDISK(0,DASD_NAME,DASD_PARTN_BITS,DASD_PER_MAJOR)
- }
+ static major_info_t temp_major_info = {
+ gendisk:{
+ INIT_GENDISK (0, DASD_NAME, DASD_PARTN_BITS,
+ DASD_PER_MAJOR)}
};
memcpy (major_info, &temp_major_info, sizeof (major_info_t));
}
return major_info;
}
+/*
+ * register major number
+ * is called with the 'static' major_info during init of the driver or 'NULL' to
+ * allocate an additional dynamic major.
+ */
static int
dasd_register_major (major_info_t * major_info)
{
@@ -522,67 +621,86 @@
int major;
unsigned long flags;
+ /* allocate dynamic major */
if (major_info == NULL) {
major_info = get_new_major_info ();
if (!major_info) {
printk (KERN_WARNING PRINTK_HEADER
"Cannot get memory to allocate another major number\n");
return -ENOMEM;
- } else {
- printk (KERN_INFO PRINTK_HEADER
- "Created another major number\n");
}
}
+
major = major_info->gendisk.major;
- major_info->gendisk.de_arr = (devfs_handle_t*)
- kmalloc(DASD_PER_MAJOR * sizeof(devfs_handle_t), GFP_KERNEL);
- memset(major_info->gendisk.de_arr,0,DASD_PER_MAJOR * sizeof(devfs_handle_t));
- major_info->gendisk.flags = (char*)
- kmalloc(DASD_PER_MAJOR * sizeof(char), GFP_KERNEL);
- memset(major_info->gendisk.flags,0,DASD_PER_MAJOR * sizeof(char));
+ /* init devfs array */
+ major_info->gendisk.de_arr = (devfs_handle_t *)
+ kmalloc (DASD_PER_MAJOR * sizeof (devfs_handle_t), GFP_KERNEL);
+ memset (major_info->gendisk.de_arr, 0,
+ DASD_PER_MAJOR * sizeof (devfs_handle_t));
+
+ /* init flags */
+ major_info->gendisk.flags = (char *)
+ kmalloc (DASD_PER_MAJOR * sizeof (char), GFP_KERNEL);
+ memset (major_info->gendisk.flags, 0, DASD_PER_MAJOR * sizeof (char));
+
+ /* register blockdevice */
rc = devfs_register_blkdev (major, DASD_NAME, &dasd_device_operations);
if (rc < 0) {
printk (KERN_WARNING PRINTK_HEADER
- "Cannot register to major no %d, rc = %d\n", major, rc);
- return rc;
+ "Cannot register to major no %d, rc = %d\n", major, rc);
+ goto out_reg_blkdev;
} else {
major_info->flags |= DASD_MAJOR_INFO_REGISTERED;
}
- /* Insert the new major info into dasd_major_info if needed */
- if (!(major_info->flags & DASD_MAJOR_INFO_IS_STATIC) ){
- spin_lock_irqsave (&dasd_major_lock, flags);
- list_add_tail(&major_info->list,&dasd_major_info[0].list);
+
+ /* Insert the new major info into dasd_major_info if needed (dynamic major) */
+ if (!(major_info->flags & DASD_MAJOR_INFO_IS_STATIC)) {
+ spin_lock_irqsave (&dasd_major_lock, flags);
+ list_add_tail (&major_info->list, &dasd_major_info[0].list);
spin_unlock_irqrestore (&dasd_major_lock, flags);
- }
+ }
+
if (major == 0) {
major = rc;
rc = 0;
}
- major_info->dasd_device = (dasd_device_t **) kmalloc (DASD_PER_MAJOR * sizeof (dasd_device_t *),
- GFP_ATOMIC);
+
+ /* init array of devices */
+ major_info->dasd_device =
+ (dasd_device_t **) kmalloc (DASD_PER_MAJOR *
+ sizeof (dasd_device_t *), GFP_ATOMIC);
if (!major_info->dasd_device)
- goto out_devfs;
- memset (major_info->dasd_device, 0, DASD_PER_MAJOR * sizeof (dasd_device_t *));
+ goto out_devices;
+ memset (major_info->dasd_device, 0,
+ DASD_PER_MAJOR * sizeof (dasd_device_t *));
+
+ /* init blk_size */
blk_size[major] =
(int *) kmalloc ((1 << MINORBITS) * sizeof (int), GFP_ATOMIC);
if (!blk_size[major])
- goto out_dasd_device;
+ goto out_blk_size;
memset (blk_size[major], 0, (1 << MINORBITS) * sizeof (int));
+
+ /* init blksize_size */
blksize_size[major] =
(int *) kmalloc ((1 << MINORBITS) * sizeof (int), GFP_ATOMIC);
if (!blksize_size[major])
- goto out_blk_size;
+ goto out_blksize_size;
memset (blksize_size[major], 0, (1 << MINORBITS) * sizeof (int));
+
+ /* init_hardsect_size */
hardsect_size[major] =
(int *) kmalloc ((1 << MINORBITS) * sizeof (int), GFP_ATOMIC);
if (!hardsect_size[major])
- goto out_blksize_size;
+ goto out_hardsect_size;
memset (hardsect_size[major], 0, (1 << MINORBITS) * sizeof (int));
+
+ /* init max_sectors */
max_sectors[major] =
(int *) kmalloc ((1 << MINORBITS) * sizeof (int), GFP_ATOMIC);
if (!max_sectors[major])
- goto out_hardsect_size;
+ goto out_max_sectors;
memset (max_sectors[major], 0, (1 << MINORBITS) * sizeof (int));
/* finally do the gendisk stuff */
@@ -590,29 +708,65 @@
sizeof (struct hd_struct),
GFP_ATOMIC);
if (!major_info->gendisk.part)
- goto out_max_sectors;
+ goto out_gendisk;
memset (major_info->gendisk.part, 0, (1 << MINORBITS) *
sizeof (struct hd_struct));
- INIT_BLK_DEV(major,do_dasd_request,dasd_get_queue,NULL);
+ INIT_BLK_DEV (major, do_dasd_request, dasd_get_queue, NULL);
major_info->gendisk.major = major;
major_info->gendisk.next = gendisk_head;
major_info->gendisk.sizes = blk_size[major];
gendisk_head = &major_info->gendisk;
return major;
-out_max_sectors:
- kfree(max_sectors[major]);
-out_hardsect_size:
- kfree(hardsect_size[major]);
-out_blksize_size:
- kfree(blksize_size[major]);
-out_blk_size:
- kfree(blk_size[major]);
-out_dasd_device:
- kfree(major_info->dasd_device);
-out_devfs:
- devfs_unregister_blkdev(major, DASD_NAME);
+
+ /* error handling - free the prior allocated memory */
+ out_gendisk:
+ kfree (max_sectors[major]);
+ max_sectors[major] = NULL;
+
+ out_max_sectors:
+ kfree (hardsect_size[major]);
+ hardsect_size[major] = NULL;
+
+ out_hardsect_size:
+ kfree (blksize_size[major]);
+ blksize_size[major] = NULL;
+
+ out_blksize_size:
+ kfree (blk_size[major]);
+ blk_size[major] = NULL;
+
+ out_blk_size:
+ kfree (major_info->dasd_device);
+
+ out_devices:
+ /* Delete the new major info from dasd_major_info list if needed (dynamic) +*/
+ if (!(major_info->flags & DASD_MAJOR_INFO_IS_STATIC)) {
+ spin_lock_irqsave (&dasd_major_lock, flags);
+ list_del (&major_info->list);
+ spin_unlock_irqrestore (&dasd_major_lock, flags);
+ }
+
+ /* unregister blockdevice */
+ rc = devfs_unregister_blkdev (major, DASD_NAME);
+ if (rc < 0) {
+ printk (KERN_WARNING PRINTK_HEADER
+ "Unable to unregister from major no %d, rc = %d\n", major,
+ rc);
+ } else {
+ major_info->flags &= ~DASD_MAJOR_INFO_REGISTERED;
+ }
+
+ out_reg_blkdev:
+ kfree (major_info->gendisk.flags);
+ kfree (major_info->gendisk.de_arr);
+
+ /* Delete the new major info from dasd_major_info if needed */
+ if (!(major_info->flags & DASD_MAJOR_INFO_IS_STATIC)) {
+ kfree (major_info);
+ }
+
return -ENOMEM;
}
@@ -628,11 +782,7 @@
return -EINVAL;
}
major = major_info->gendisk.major;
- INIT_BLK_DEV(major,NULL,NULL,NULL);
- blk_size[major] = NULL;
- blksize_size[major] = NULL;
- hardsect_size[major] = NULL;
- max_sectors[major] = NULL;
+ INIT_BLK_DEV (major, NULL, NULL, NULL);
/* do the gendisk stuff */
for (dd = gendisk_head; dd; dd = dd->next) {
@@ -648,34 +798,43 @@
if (dd == NULL) {
return -ENOENT;
}
- kfree (major_info->gendisk.de_arr);
- kfree (major_info->gendisk.flags);
kfree (major_info->dasd_device);
+ kfree (major_info->gendisk.part);
+
kfree (blk_size[major]);
kfree (blksize_size[major]);
kfree (hardsect_size[major]);
kfree (max_sectors[major]);
- kfree (major_info->gendisk.part);
+
+ blk_size[major] = NULL;
+ blksize_size[major] = NULL;
+ hardsect_size[major] = NULL;
+ max_sectors[major] = NULL;
rc = devfs_unregister_blkdev (major, DASD_NAME);
if (rc < 0) {
printk (KERN_WARNING PRINTK_HEADER
- "Cannot unregister from major no %d, rc = %d\n", major, rc);
+ "Cannot unregister from major no %d, rc = %d\n", major,
+ rc);
return rc;
} else {
major_info->flags &= ~DASD_MAJOR_INFO_REGISTERED;
}
- /* Delete the new major info from dasd_major_info if needed */
- if (!(major_info->flags & DASD_MAJOR_INFO_IS_STATIC)) {
- spin_lock_irqsave (&dasd_major_lock, flags);
- list_del(&major_info->list);
+
+ kfree (major_info->gendisk.flags);
+ kfree (major_info->gendisk.de_arr);
+
+ /* Delete the new major info from dasd_major_info if needed */
+ if (!(major_info->flags & DASD_MAJOR_INFO_IS_STATIC)) {
+ spin_lock_irqsave (&dasd_major_lock, flags);
+ list_del (&major_info->list);
spin_unlock_irqrestore (&dasd_major_lock, flags);
kfree (major_info);
- }
+ }
return rc;
}
-/*
+/*
* function: dasd_device_from_kdev
* finds the device structure corresponding to the kdev supplied as argument
* in the major_info structures and returns it or NULL when not found
@@ -688,9 +847,9 @@
unsigned long flags;
spin_lock_irqsave (&dasd_major_lock, flags);
- list_for_each(l,&dasd_major_info[0].list) {
- major_info = list_entry(l,major_info_t,list);
- if ( major_info->gendisk.major == MAJOR(kdev) )
+ list_for_each (l, &dasd_major_info[0].list) {
+ major_info = list_entry (l, major_info_t, list);
+ if (major_info->gendisk.major == MAJOR (kdev))
break;
}
spin_unlock_irqrestore (&dasd_major_lock, flags);
@@ -699,10 +858,10 @@
return NULL;
}
-/*
+/*
* function: dasd_device_from_devno
- * finds the address of the device structure corresponding to the devno
- * supplied as argument in the major_info structures and returns
+ * finds the address of the device structure corresponding to the devno
+ * supplied as argument in the major_info structures and returns
* it or NULL when not found
*/
static inline dasd_device_t **
@@ -714,8 +873,8 @@
unsigned long flags;
spin_lock_irqsave (&dasd_major_lock, flags);
- list_for_each(l,&dasd_major_info[0].list) {
- major_info = list_entry(l,major_info_t,list);
+ list_for_each (l, &dasd_major_info[0].list) {
+ major_info = list_entry (l, major_info_t, list);
if (devindex < DASD_PER_MAJOR) {
spin_unlock_irqrestore (&dasd_major_lock, flags);
return &major_info->dasd_device[devindex];
@@ -726,70 +885,105 @@
return NULL;
}
+/*
+ * function: dasd_features_from_devno
+ * finds the device range corresponding to the devno
+ * supplied as argument in the major_info structures and returns
+ * the features set for it
+ */
+
+static int
+dasd_features_from_devno (int devno)
+{
+ dasd_range_t *temp;
+ int devindex = 0;
+ unsigned long flags;
+ struct list_head *l;
+
+ spin_lock_irqsave (&range_lock, flags);
+ list_for_each (l, &dasd_range_head.list) {
+ temp = list_entry (l, dasd_range_t, list);
+ if (devno >= temp->from && devno <= temp->to) {
+ spin_unlock_irqrestore (&range_lock, flags);
+ return temp->features;
+ }
+ devindex += temp->to - temp->from + 1;
+ }
+ spin_unlock_irqrestore (&range_lock, flags);
+ return -ENODEV;
+}
+
+
+
/* SECTION: managing dasd disciplines */
/* anchor and spinlock for list of disciplines */
-static dasd_discipline_t *dasd_disciplines;
+static struct list_head dasd_disc_head = LIST_HEAD_INIT(dasd_disc_head);
static spinlock_t discipline_lock = SPIN_LOCK_UNLOCKED;
-/*
- * function dasd_discipline_enq
+/*
+ * function dasd_discipline_enq
* chains the discpline given as argument to the head of disiplines
* head chaining policy is required to allow module disciplines to
* be preferred against those, who are statically linked
*/
-void
+static inline void
dasd_discipline_enq (dasd_discipline_t * d)
{
- spin_lock (&discipline_lock);
- d->next = dasd_disciplines;
- dasd_disciplines = d;
- spin_unlock (&discipline_lock);
+ list_add(&d->list, &dasd_disc_head);
}
-/*
- * function dasd_discipline_deq
+/*
+ * function dasd_discipline_deq
* removes the discipline given as argument from the list of disciplines
*/
-int
+static inline void
dasd_discipline_deq (dasd_discipline_t * d)
{
- int rc = 0;
- spin_lock (&discipline_lock);
- if (dasd_disciplines == d) {
- dasd_disciplines = dasd_disciplines->next;
- } else {
- dasd_discipline_t *b;
- b = dasd_disciplines;
- while (b && b->next != d)
- b = b->next;
- if (b != NULL) {
- b->next = b->next->next;
- } else {
- rc = -ENOENT;
- }
- }
- spin_unlock (&discipline_lock);
- return rc;
+ list_del(&d->list);
+}
+
+void
+dasd_discipline_add (dasd_discipline_t * d)
+{
+ unsigned long flags;
+ MOD_INC_USE_COUNT;
+ spin_lock_irqsave (&discipline_lock,flags);
+ dasd_discipline_enq (d);
+ spin_unlock_irqrestore (&discipline_lock,flags);
+ dasd_enable_ranges (&dasd_range_head, d, DASD_STATE_ONLINE);
+}
+
+void dasd_discipline_del (dasd_discipline_t * d)
+{
+ unsigned long flags;
+ spin_lock_irqsave (&discipline_lock,flags);
+ dasd_disable_ranges(&dasd_range_head, d, DASD_STATE_DEL, 1);
+ dasd_discipline_deq (d);
+ spin_unlock_irqrestore (&discipline_lock,flags);
+ MOD_DEC_USE_COUNT;
}
static inline dasd_discipline_t *
-dasd_find_discipline (dasd_device_t * device)
+dasd_find_disc (dasd_device_t * device, dasd_discipline_t *d)
{
- dasd_discipline_t *temp;
- for (temp = dasd_disciplines; temp != NULL; temp = temp->next) {
- if (temp->id_check)
- if (temp->id_check (&device->devinfo)) {
- continue;
- }
- if (temp->check_characteristics) {
- if (temp->check_characteristics (device)) {
- continue;
- }
- }
- break;
- }
- return temp;
+ dasd_discipline_t *t;
+ struct list_head *l = d ? &d->list : dasd_disc_head.next;
+ do {
+ t = list_entry(l,dasd_discipline_t,list);
+ if ( ( t->id_check == NULL ||
+ t->id_check (&device->devinfo) == 0 ) &&
+ ( t->check_characteristics == NULL ||
+ t->check_characteristics (device) == 0 ) )
+ break;
+ l = l->next;
+ if ( d ||
+ l == &dasd_disc_head ) {
+ t = NULL;
+ break;
+ }
+ } while ( 1 );
+ return t;
}
/* SECTION: profiling stuff */
@@ -813,9 +1007,9 @@
}
/*
- * function dasd_profile_add
+ * function dasd_profile_add
* adds the profiling information from the cqr given as argument to the
- * global and device specific profiling information
+ * global and device specific profiling information
*/
void
dasd_profile_add (ccw_req_t * cqr)
@@ -840,8 +1034,10 @@
memset (&device->profile, 0, sizeof (dasd_profile_info_t));
};
- dasd_global_profile.dasd_io_reqs++;
- device->profile.dasd_io_reqs++;
+ dasd_global_profile.dasd_io_reqs++;
+ device->profile.dasd_io_reqs++;
+ dasd_global_profile.dasd_io_sects+=sectors;
+ device->profile.dasd_io_sects+=sectors;
dasd_profile_add_counter (sectors, dasd_io_secs, device);
dasd_profile_add_counter (tottime, dasd_io_times, device);
dasd_profile_add_counter (tottimeps, dasd_io_timps, device);
@@ -851,54 +1047,168 @@
dasd_profile_add_counter (endtime, dasd_io_time3, device);
}
-/* SECTION: (de)queueing of requests to channel program queues */
-/*
- * function dasd_chanq_enq
- * appends the cqr given as argument to the queue
- * has to be called with the queue lock (namely the s390_irq_lock) acquired
+/* SECTION: All the gendisk stuff */
+
+
+/* SECTION: Managing wrappers for ccwcache */
+
+/*
+ * function dasd_alloc_request
+ * tries to return space for a channel program of length cplength with
+ * additional data of size datasize.
+ * If the ccwcache cannot fulfill the request it tries the emergeny requests
+ * before giving up finally
+ * FIXME: initialization of ccw_req_t should be done by function of ccwcache
*/
-static inline void
-dasd_chanq_enq (dasd_chanq_t * q, ccw_req_t * cqr)
+ccw_req_t *
+dasd_alloc_request (char *magic, int cplength, int datasize, dasd_device_t* device)
{
- if (q->head != NULL) {
- q->tail->next = cqr;
- } else
+ ccw_req_t *rv = NULL;
+ int i;
+ unsigned long flags;
+
+ if ((rv = ccw_alloc_request (magic, cplength, datasize)) != NULL) {
+ return rv;
+ }
+ if ((((sizeof (ccw_req_t) + 7) & -8) +
+ cplength * sizeof (ccw1_t) + datasize) > PAGE_SIZE) {
+ BUG ();
+ }
+ if (device->lowmem_cqr==NULL) {
+ DASD_MESSAGE (KERN_WARNING, device, "Low memory! Using emergency request %p",device->lowmem_ccws);
+ device->lowmem_cqr=device->lowmem_ccws;
+ rv = device->lowmem_ccws;
+ memset (rv, 0, PAGE_SIZE);
+ strncpy ((char *) (&rv->magic), magic, 4);
+ ASCEBC ((char *) (&rv->magic), 4);
+ rv->cplength = cplength;
+ rv->datasize = datasize;
+ rv->data = (void *) ((long) rv + PAGE_SIZE - datasize);
+ rv->cpaddr = (ccw1_t *) ((long) rv + sizeof (ccw_req_t));
+ } else {
+ DASD_MESSAGE (KERN_WARNING, device,"Refusing emergency mem for request NULL, already in use at %p.",device->lowmem_ccws);
+ }
+ return rv;
+}
+
+/*
+ * function dasd_free_request
+ * returns a ccw_req_t to the appropriate cache or emergeny request line
+ */
+void
+dasd_free_request (ccw_req_t * request, dasd_device_t* device)
+{
+#ifdef CONFIG_ARCH_S390X
+ ccw1_t* ccw;
+ /* clear any idals used for chain */
+ ccw=request->cpaddr-1;
+ do {
+ ccw++;
+ if ((ccw->cda < (unsigned long) device->lowmem_idals) || (ccw->cda >= (unsigned long) device->lowmem_idals+PAGE_SIZE))
+ clear_normalized_cda (ccw);
+ else {
+ if (device->lowmem_idal_ptr != device->lowmem_idals)
+ DASD_MESSAGE (KERN_WARNING, device, "Freeing emergency idals from request at %p.",request);
+ device->lowmem_idal_ptr = device->lowmem_idals;
+ device->lowmem_cqr=NULL;
+ }
+ } while ((ccw->flags & CCW_FLAG_CC) || (ccw->flags & CCW_FLAG_DC));
+#endif
+ if (request != device->lowmem_ccws) { /* compare to lowmem_ccws to protect usage of lowmem_cqr for IDAL only ! */
+ ccw_free_request (request);
+ } else {
+ DASD_MESSAGE (KERN_WARNING, device, "Freeing emergency request at %p",request);
+ device->lowmem_cqr=NULL;
+ }
+}
+
+int
+dasd_set_normalized_cda ( ccw1_t * cp, unsigned long address, ccw_req_t* request, dasd_device_t* device )
+{
+#ifdef CONFIG_ARCH_S390X
+ int nridaws;
+ int count = cp->count;
+
+ if (set_normalized_cda (cp, address)!=-ENOMEM) {
+ return 0;
+ }
+
+ if ((device->lowmem_cqr!=NULL) && (device->lowmem_cqr!=request)) {
+ DASD_MESSAGE (KERN_WARNING, device, "Refusing emergency idals for request %p, memory is already in use for request %p",request,device->lowmem_cqr);
+ return -ENOMEM;
+ }
+ device->lowmem_cqr=request;
+ if (device->lowmem_idal_ptr == device->lowmem_idals) {
+ DASD_MESSAGE (KERN_WARNING,device, "Low memory! Using emergency IDALs for request %p.\n",request);
+ }
+ nridaws = ((address & (IDA_BLOCK_SIZE-1)) + count +
+ (IDA_BLOCK_SIZE-1)) >> IDA_SIZE_LOG;
+ if ( device->lowmem_idal_ptr>=device->lowmem_idals + PAGE_SIZE ) {
+ /* Ouch! No Idals left for emergency request */
+ BUG();
+ }
+ cp->flags |= CCW_FLAG_IDA;
+ cp->cda = (__u32)(unsigned long)device->lowmem_idal_ptr;
+ do {
+ *((long*)device->lowmem_idal_ptr) = address;
+ address = (address & -(IDA_BLOCK_SIZE)) + (IDA_BLOCK_SIZE);
+ nridaws --;
+ device->lowmem_idal_ptr += sizeof(unsigned long);
+ } while ( nridaws > 0 );
+#else
+ cp -> cda = address;
+#endif
+ return 0;
+}
+
+
+/* SECTION: (de)queueing of requests to channel program queues */
+
+/*
+ * function dasd_chanq_enq
+ * appends the cqr given as argument to the queue
+ * has to be called with the queue lock (namely the s390_irq_lock) acquired
+ */
+inline void
+dasd_chanq_enq (dasd_chanq_t * q, ccw_req_t * cqr)
+{
+ if (q->head != NULL) {
+ q->tail->next = cqr;
+ } else
q->head = cqr;
cqr->next = NULL;
q->tail = cqr;
check_then_set (&cqr->status, CQR_STATUS_FILLED, CQR_STATUS_QUEUED);
}
-/*
+/*
* function dasd_chanq_enq_head
* chains the cqr given as argument to the queue head
* has to be called with the queue lock (namely the s390_irq_lock) acquired
*/
-static inline void
+inline void
dasd_chanq_enq_head (dasd_chanq_t * q, ccw_req_t * cqr)
{
cqr->next = q->head;
q->head = cqr;
if (q->tail == NULL)
q->tail = cqr;
- check_then_set (&cqr->status,
- CQR_STATUS_FILLED,
- CQR_STATUS_QUEUED);
+ check_then_set (&cqr->status, CQR_STATUS_FILLED, CQR_STATUS_QUEUED);
}
-/*
+/*
* function dasd_chanq_deq
* dechains the cqr given as argument from the queue
* has to be called with the queue lock (namely the s390_irq_lock) acquired
*/
-int
+inline void
dasd_chanq_deq (dasd_chanq_t * q, ccw_req_t * cqr)
{
ccw_req_t *prev;
if (cqr == NULL)
- BUG ();
+ BUG ();
if (cqr == q->head) {
q->head = cqr->next;
@@ -910,138 +1220,82 @@
while (prev && prev->next != cqr)
prev = prev->next;
if (prev == NULL)
- return -ENOENT;
+ return;
prev->next = cqr->next;
if (prev->next == NULL)
q->tail = prev;
}
cqr->next = NULL;
- return 0;
}
-/* SECTION: All the gendisk stuff */
+/* SECTION: Managing the device queues etc. */
-/*
- * function dasd_partn_detect
- * calls the function in genhd, which is appropriate to setup a partitioned disk
+/*
+ * function dasd_start_IO
+ * attempts to start the IO and returns an appropriate return code
*/
-static void
-dasd_partn_detect (dasd_device_t * dev)
+int
+dasd_term_IO (ccw_req_t * cqr)
{
- major_info_t *major_info = dev->major_info;
- struct gendisk *dd = &major_info->gendisk;
- int minor = MINOR (dev->kdev);
-
- register_disk (dd,
- MKDEV (dd->major, minor),
- 1 << DASD_PARTN_BITS,
- &dasd_device_operations,
- (dev->sizes.blocks << dev->sizes.s2b_shift));
-}
-
-/* SECTION: Managing wrappers for ccwcache */
-
-/* array and spinlock of emergency requests */
-static ccw_req_t *dasd_emergency_req[DASD_EMERGENCY_REQUESTS];
-static spinlock_t dasd_emergency_req_lock = SPIN_LOCK_UNLOCKED;
+ int rc = 0;
+ dasd_device_t *device = cqr->device;
+ int irq;
+ int retries = 0;
-/*
- * function dasd_init_emergeny_req
- * allocates emergeny requests
- */
-static inline void __init
-dasd_init_emergency_req (void)
-{
- int i;
- for (i = 0; i < DASD_EMERGENCY_REQUESTS; i++) {
- dasd_emergency_req[i] = (ccw_req_t *) get_free_page (GFP_KERNEL);
- memset (dasd_emergency_req[i], 0, PAGE_SIZE);
+ if (!cqr) {
+ BUG ();
}
-}
-
-/*
- * function dasd_cleanup_emergeny_req
- * tries to free emergeny requests skipping those, which are currently in use
- */
-static inline void
-dasd_cleanup_emergency_req (void)
-{
- int i;
- for (i = 0; i < DASD_EMERGENCY_REQUESTS; i++) {
- if (dasd_emergency_req[i])
- free_page ((long) (dasd_emergency_req[i]));
- else
- printk (KERN_WARNING PRINTK_HEADER
- "losing page for emergency request in use\n");
+ irq = device->devinfo.irq;
+ if (strncmp ((char *) &cqr->magic, device->discipline->ebcname, 4)) {
+ DASD_MESSAGE (KERN_WARNING, device,
+ " ccw_req_t 0x%08X magic doesn't match"
+ " discipline 0x%08X\n",
+ cqr->magic,
+ *(unsigned int *) device->discipline->name);
+ return -EINVAL;
}
-}
-
-/*
- * function dasd_alloc_request
- * tries to return space for a channel program of length cplength with
- * additional data of size datasize.
- * If the ccwcache cannot fulfill the request it tries the emergeny requests
- * before giving up finally
- * FIXME: initialization of ccw_req_t should be done by function of ccwcache
- */
-ccw_req_t *
-dasd_alloc_request (char *magic, int cplength, int datasize)
-{
- ccw_req_t *rv = NULL;
- int i;
- unsigned long flags;
- if ((rv = ccw_alloc_request (magic, cplength, datasize)) != NULL) {
- return rv;
- }
- if ((((sizeof (ccw_req_t) + 7) & -8) +
- cplength*sizeof(ccw1_t) + datasize) > PAGE_SIZE) {
- BUG();
+ while ( retries < 5 ) {
+ if ( retries < 2 )
+ rc = halt_IO(irq, (long)cqr,
+ cqr->options | DOIO_WAIT_FOR_INTERRUPT);
+ else
+ rc = clear_IO(irq, (long)cqr,
+ cqr->options | DOIO_WAIT_FOR_INTERRUPT);
+ switch (rc) {
+ case 0:
+ break;
+ case -ENODEV:
+ DASD_MESSAGE (KERN_WARNING, device, "%s",
+ "device gone, retry\n");
+ break;
+ case -EIO:
+ DASD_MESSAGE (KERN_WARNING, device, "%s",
+ "I/O error, retry\n");
+ break;
+ case -EBUSY:
+ DASD_MESSAGE (KERN_WARNING, device, "%s",
+ "device busy, retry later\n");
+ break;
+ default:
+ DASD_MESSAGE (KERN_ERR, device,
+ "line %d unknown RC=%d, please report"
+ " to linux390@de.ibm.com\n", __LINE__, rc);
+ BUG ();
+ break;
+ }
+ if (rc == 0) {
+ check_then_set (&cqr->status,
+ CQR_STATUS_IN_IO, CQR_STATUS_FAILED);
+ asm volatile ("STCK %0":"=m" (cqr->stopclk));
+ break;
+ }
+ retries ++;
}
- spin_lock_irqsave (&dasd_emergency_req_lock, flags);
- for (i = 0; i < DASD_EMERGENCY_REQUESTS; i++) {
- if (dasd_emergency_req[i] != NULL) {
- rv = dasd_emergency_req[i];
- dasd_emergency_req[i] = NULL;
- break;
- }
- }
- spin_unlock_irqrestore (&dasd_emergency_req_lock, flags);
- if (rv) {
- memset (rv, 0, PAGE_SIZE);
- rv->cache = (kmem_cache_t *) (dasd_emergency_req + i);
- strncpy ((char *) (&rv->magic), magic, 4);
- ASCEBC ((char *) (&rv->magic), 4);
- rv->cplength = cplength;
- rv->datasize = datasize;
- rv->data = (void *) ((long) rv + PAGE_SIZE - datasize);
- rv->cpaddr = (ccw1_t *) ((long) rv + sizeof (ccw_req_t));
- } else {
- panic ("No way to fulfill request for I/O request\n");
- }
- return rv;
+ return rc;
}
-/*
- * function dasd_free_request
- * returns a ccw_req_t to the appropriate cache or emergeny request line
- */
-void
-dasd_free_request (ccw_req_t * request)
-{
- if ((request->cache >= (kmem_cache_t *) dasd_emergency_req) &&
- (request->cache < (kmem_cache_t *) (dasd_emergency_req +
- DASD_EMERGENCY_REQUESTS))) {
- *((ccw_req_t **) (request->cache)) = request;
- } else {
- ccw_free_request (request);
- }
-}
-
-/* SECTION: Managing the device queues etc. */
-
-
-/*
+/*
* function dasd_start_IO
* attempts to start the IO and returns an appropriate return code
*/
@@ -1051,7 +1305,7 @@
int rc = 0;
dasd_device_t *device = cqr->device;
int irq;
- unsigned long long now;
+ unsigned long long now;
if (!cqr) {
BUG ();
@@ -1066,75 +1320,80 @@
return -EINVAL;
}
- asm volatile ("STCK %0":"=m" (now));
- rc = do_IO (irq, cqr->cpaddr, (long) cqr, cqr->lpm, cqr->options);
- switch (rc) {
- case 0:
- break;
- case -ENODEV:
- check_then_set (&cqr->status,
- CQR_STATUS_QUEUED, CQR_STATUS_FAILED);
- break;
- case -EIO:
- check_then_set (&cqr->status,
- CQR_STATUS_QUEUED, CQR_STATUS_FAILED);
- break;
- case -EBUSY:
- DASD_MESSAGE (KERN_WARNING, device,"%s",
- "device busy, retry later\n");
- break;
- default:
- DASD_MESSAGE (KERN_ERR, device,
- "line %d unknown RC=%d, please report"
- " to linux390@de.ibm.com\n",
- __LINE__, rc);
- BUG();
- break;
- }
+ asm volatile ("STCK %0":"=m" (now));
+ rc = do_IO (irq, cqr->cpaddr, (long) cqr, cqr->lpm, cqr->options);
+ switch (rc) {
+ case 0:
+ break;
+ case -ENODEV:
+ check_then_set (&cqr->status,
+ CQR_STATUS_QUEUED, CQR_STATUS_FAILED);
+ break;
+ case -EIO:
+ check_then_set (&cqr->status,
+ CQR_STATUS_QUEUED, CQR_STATUS_FAILED);
+ break;
+ case -EBUSY:
+ DASD_MESSAGE (KERN_WARNING, device, "%s",
+ "device busy, retry later\n");
+ break;
+ default:
+ DASD_MESSAGE (KERN_ERR, device,
+ "line %d unknown RC=%d, please report"
+ " to linux390@de.ibm.com\n", __LINE__, rc);
+ BUG ();
+ break;
+ }
if (rc == 0) {
- check_then_set (&cqr->status,
- CQR_STATUS_QUEUED, CQR_STATUS_IN_IO);
- cqr->startclk = now;
+ check_then_set (&cqr->status,
+ CQR_STATUS_QUEUED, CQR_STATUS_IN_IO);
+ cqr->startclk = now;
}
return rc;
}
-/*
- * function sleep_on_req
+/*
+ * function dasd_sleep_on_req
* attempts to start the IO and waits for completion
* FIXME: replace handmade sleeping by wait_event
*/
-static int
-sleep_on_req (ccw_req_t * req)
+int
+dasd_sleep_on_req (ccw_req_t * req)
{
unsigned long flags;
int cs;
int rc = 0;
dasd_device_t *device = (dasd_device_t *) req->device;
+ if ( signal_pending(current) ) {
+ return -ERESTARTSYS;
+ }
s390irq_spin_lock_irqsave (device->devinfo.irq, flags);
dasd_chanq_enq (&device->queue, req);
- /* let the bh start the request to keep them in order */
- dasd_schedule_bh (device);
-
+ /* let the bh start the request to keep them in order */
+ dasd_schedule_bh (device);
do {
s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags);
- wait_event (device->wait_q,
- (((cs=req->status)==CQR_STATUS_DONE)||
- (cs==CQR_STATUS_FAILED)));
+ wait_event ( device->wait_q,
+ (((cs = req->status) == CQR_STATUS_DONE) ||
+ (cs == CQR_STATUS_FAILED) ||
+ signal_pending(current)));
s390irq_spin_lock_irqsave (device->devinfo.irq, flags);
- cs = req->status;
+ if ( signal_pending(current) ) {
+ rc = -ERESTARTSYS;
+ if (req->status == CQR_STATUS_IN_IO )
+ device->discipline->term_IO(req);
+ break;
+ } else if ( req->status == CQR_STATUS_FAILED) {
+ rc = -EIO;
+ break;
+ }
} while (cs != CQR_STATUS_DONE && cs != CQR_STATUS_FAILED);
-
s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags);
- if (cs == CQR_STATUS_FAILED) {
- rc = -EIO;
- }
return rc;
+} /* end dasd_sleep_on_req */
-} /* end sleep_on_req */
-
-/*
+/*
* function dasd_end_request
* posts the buffer_cache about a finalized request
* FIXME: for requests splitted to serveral cqrs
@@ -1142,7 +1401,8 @@
static inline void
dasd_end_request (struct request *req, int uptodate)
{
- while (end_that_request_first (req, uptodate, DASD_NAME)) {}
+ while (end_that_request_first (req, uptodate, DASD_NAME)) {
+ }
#ifndef DEVICE_NO_RANDOM
add_blkdev_randomness (MAJOR (req->rq_dev));
#endif
@@ -1150,7 +1410,7 @@
return;
}
-/*
+/*
* function dasd_get_queue
* returns the queue corresponding to a device behind a kdev
*/
@@ -1158,10 +1418,10 @@
dasd_get_queue (kdev_t kdev)
{
dasd_device_t *device = dasd_device_from_kdev (kdev);
- return &device->request_queue;
+ return device->request_queue;
}
-/*
+/*
* function dasd_check_expire_time
* check the request given as argument for expiration
* and returns 0 if not yet expired, nonzero else
@@ -1173,18 +1433,17 @@
int rc = 0;
asm volatile ("STCK %0":"=m" (now));
- if ( cqr->expires &&
- cqr->expires + cqr->startclk < now) {
- DASD_MESSAGE (KERN_ERR, ((dasd_device_t*)cqr->device),
+ if (cqr->expires && cqr->expires + cqr->startclk < now) {
+ DASD_MESSAGE (KERN_ERR, ((dasd_device_t *) cqr->device),
"IO timeout 0x%08lx%08lx usecs in req %p\n",
- (long) (cqr->expires >> 44),
- (long) (cqr->expires >> 12), cqr);
- cqr->expires <<=1;
+ (long) (cqr->expires >> 44),
+ (long) (cqr->expires >> 12), cqr);
+ cqr->expires <<= 1;
}
return rc;
}
-/*
+/*
* function dasd_finalize_request
* implemets the actions to perform, when a request is finally finished
* namely in status CQR_STATUS_DONE || CQR_STATUS_FAILED
@@ -1192,190 +1451,226 @@
static inline void
dasd_finalize_request (ccw_req_t * cqr)
{
- dasd_device_t *device = cqr->device;
-
+ dasd_device_t *device = cqr->device;
+
asm volatile ("STCK %0":"=m" (cqr->endclk));
if (cqr->req) {
- dasd_end_request (cqr->req, (cqr->status == CQR_STATUS_DONE));
- dasd_profile_add (cqr);
+ dasd_profile_add (cqr);
+ dasd_end_request (cqr->req, (cqr->status == CQR_STATUS_DONE));
/* free request if nobody is waiting on it */
- dasd_free_request (cqr);
+ dasd_free_request (cqr, cqr->device);
} else {
- /* during format we don't have the request structure */
+ if ( cqr == device->init_cqr && /* bring late devices online */
+ device->level <= DASD_STATE_ONLINE ) {
+ device->timer.function = dasd_enable_single_device;
+ device->timer.data = (unsigned long) device;
+ device->timer.expires = jiffies;
+ add_timer(&device->timer);
+ }
/* notify sleeping task about finished postprocessing */
wake_up (&device->wait_q);
+
}
return;
}
-/*
+/*
* function dasd_process_queues
* transfers the requests on the queue given as argument to the chanq
* if possible, the request ist started on a fastpath
*/
static void
-dasd_process_queues (dasd_device_t *device)
+dasd_process_queues (dasd_device_t * device)
{
- unsigned long flags;
- struct request *req;
- request_queue_t * queue = &device->request_queue;
+ unsigned long flags;
+ struct request *req;
+ request_queue_t *queue = device->request_queue;
dasd_chanq_t *qp = &device->queue;
- int irq = device -> devinfo.irq;
- ccw_req_t *final_requests= NULL;
- static int chanq_min_size = DASD_MIN_SIZE_FOR_QUEUE;
- int chanq_max_size = DASD_CHANQ_MAX_SIZE;
- ccw_req_t * cqr=NULL,*temp;
- dasd_erp_postaction_fn_t erp_postaction;
-
- s390irq_spin_lock_irqsave (irq, flags);
- /* First we dechain the requests, processed with completed status */
- while ( qp -> head &&
- ((qp -> head -> status == CQR_STATUS_DONE) ||
- (qp -> head -> status == CQR_STATUS_FAILED) ||
- (qp -> head -> status == CQR_STATUS_ERROR) ) ) {
+ int irq = device->devinfo.irq;
+ ccw_req_t *final_requests = NULL;
+ static int chanq_min_size = DASD_MIN_SIZE_FOR_QUEUE;
+ int chanq_max_size = DASD_CHANQ_MAX_SIZE;
+ ccw_req_t *cqr = NULL, *temp;
+ dasd_erp_postaction_fn_t erp_postaction;
+
+
+ s390irq_spin_lock_irqsave (irq, flags);
+
+ /* First we dechain the requests, processed with completed status */
+ while (qp->head &&
+ ((qp->head->status == CQR_STATUS_DONE ) ||
+ (qp->head->status == CQR_STATUS_FAILED) ||
+ (qp->head->status == CQR_STATUS_ERROR ) )) {
+
dasd_erp_action_fn_t erp_action;
- ccw_req_t *erp_cqr = NULL;
+ ccw_req_t *erp_cqr = NULL;
+
/* preprocess requests with CQR_STATUS_ERROR */
- if (qp -> head -> status == CQR_STATUS_ERROR) {
- if ((qp -> head -> dstat -> flag & DEVSTAT_HALT_FUNCTION) ||
- (qp->head->retries-- == 0 ) ||
- (device->discipline->erp_action==NULL) ||
- ((erp_action=device->discipline->erp_action(qp->head))==NULL)||
- ((erp_cqr = erp_action(qp->head))== NULL)) {
- check_then_set (&qp->head->status,
+ if (qp->head->status == CQR_STATUS_ERROR) {
+
+ qp->head->retries--;
+
+ if (qp->head->dstat->flag & DEVSTAT_HALT_FUNCTION) {
+
+ check_then_set (&qp->head->status,
CQR_STATUS_ERROR,
CQR_STATUS_FAILED);
- continue;
+
+ } else if ((device->discipline->erp_action == NULL ) ||
+ ((erp_action = device->discipline->erp_action (qp->head)) == NULL) ) {
+
+ erp_cqr = dasd_default_erp_action (qp->head);
+
+ } else { /* call discipline ERP action */
+
+ erp_cqr = erp_action (qp->head);
+ }
+ continue;
+
+ } else if (qp->head->refers) { /* we deal with a finished ERP */
+
+ if (qp->head->status == CQR_STATUS_DONE) {
+
+ DASD_MESSAGE (KERN_DEBUG, device, "%s",
+ "ERP successful");
} else {
- if (erp_cqr != qp->head){
- dasd_chanq_enq_head (qp, erp_cqr);
- }
- /* chain of completed requests is now broken */
- continue;
+
+ DASD_MESSAGE (KERN_ERR, device, "%s",
+ "ERP unsuccessful");
}
- } else if ( qp -> head -> refers ) { /* we deal with an ERP */
- char *uptodatestr;
- if ( qp -> head -> status == CQR_STATUS_DONE) {
- uptodatestr = "ERP successful";
- } else {
- uptodatestr = "ERP unsuccessful";
- }
-
- if (device->discipline->erp_postaction == NULL ||
- ((erp_postaction = device->discipline->erp_postaction (qp->head)) == NULL)) {
- /*
- * maybe we shoud set it to FAILED,
- * because we are very paranoid ;)
- */
- erp_postaction = default_erp_postaction;
+
+ if ((device->discipline->erp_postaction == NULL )||
+ ((erp_postaction = device->discipline->erp_postaction (qp->head)) == NULL) ) {
+
+ dasd_default_erp_postaction (qp->head);
+
+ } else { /* call ERP postaction of discipline */
+
+ erp_postaction (qp->head);
}
- DASD_MESSAGE (KERN_INFO, device,
- "%s: postaction [<%p>]\n",
- uptodatestr, erp_postaction);
- erp_postaction (qp->head);
- continue;
- }
-
+
+ continue;
+ }
+
/* dechain request now */
- if ( final_requests == NULL )
- final_requests = qp -> head;
- cqr = qp -> head;
- qp -> head = qp -> head -> next;
+ if (final_requests == NULL)
+ final_requests = qp->head;
+
+ cqr = qp->head;
+ qp->head = qp->head->next;
+
if (qp->head == NULL)
qp->tail = NULL;
- }
- if ( cqr )
- cqr -> next = NULL;
- /* Now we try to fetch requests from the request queue */
- for (temp = cqr; temp != NULL ;temp=temp-> next )
- if ( temp ->status == CQR_STATUS_QUEUED)
- chanq_max_size --;
- while ( (! queue->plugged) &&
- (! list_empty(&queue->queue_head)) &&
- (req=dasd_next_request(queue)) != NULL) {
- /* queue empty or certain critera fulfilled -> transfer */
- if ( qp -> head == NULL ||
- chanq_max_size > 0 ||
- (req->nr_sectors >= chanq_min_size)) {
- ccw_req_t *cqr;
- /* relocate request according to partition table */
- req->sector += device->major_info->gendisk.part[MINOR (req->rq_dev)].start_sect;
- cqr = device->discipline->build_cp_from_req (device, req);
- if (cqr == NULL) {
- DASD_MESSAGE (KERN_WARNING, device,
- "CCW creation failed on request %p\n", req);
- /* revert relocation of request */
- req->sector -= device->major_info->gendisk.part[MINOR (req->rq_dev)].start_sect;
- break; /* terminate request queue loop */
-
- }
+
+ } /* end while over completed requests */
+
+ if (cqr)
+ cqr->next = NULL;
+ /* Now clean the requests with final status */
+ while (final_requests) {
+ temp = final_requests;
+ final_requests = temp->next;
+ dasd_finalize_request (temp);
+ }
+ /* Now we try to fetch requests from the request queue */
+ for (temp = cqr; temp != NULL; temp = temp->next)
+ if (temp->status == CQR_STATUS_QUEUED)
+ chanq_max_size--;
+ while ((atomic_read(&device->plugged) == 0) &&
+ (!queue->plugged) &&
+ (!list_empty (&queue->queue_head)) &&
+ (req = dasd_next_request (queue)) != NULL) {
+ /* queue empty or certain critera fulfilled -> transfer */
+ if (qp->head == NULL ||
+ chanq_max_size > 0 || (req->nr_sectors >= chanq_min_size)) {
+ ccw_req_t *cqr = NULL;
+ if (is_read_only(device->kdev) && req->cmd == WRITE) {
+ DASD_MESSAGE (KERN_WARNING, device,
+ "rejecting write request %p\n",
+ req);
+ dasd_end_request (req, 0);
+ dasd_dequeue_request (queue,req);
+ } else {
+ /* relocate request according to partition table */
+ req->sector +=
+ device->major_info->gendisk.
+ part[MINOR (req->rq_dev)].start_sect;
+ cqr = device->discipline->build_cp_from_req (device, req);
+ if (cqr == NULL) {
+ DASD_MESSAGE (KERN_WARNING, device,
+ "CCW creation failed on request %p\n",
+ req);
+ /* revert relocation of request */
+ req->sector -=
+ device->major_info->gendisk.
+ part[MINOR (req->rq_dev)].start_sect;
+ break; /* terminate request queue loop */
+
+ }
#ifdef CONFIG_DYNAMIC_QUEUE_MIN_SIZE
- chanq_min_size = (chanq_min_size + req->nr_sectors)>>1;
-#endif /* CONFIG_DYNAMIC_QUEUE_MIN_SIZE */
- dasd_dequeue_request(queue,req);
- dasd_chanq_enq (qp, cqr);
- } else { /* queue not empty OR criteria not met */
- break; /* terminate request queue loop */
- }
- }
- /* we process the requests with non-final status */
- if ( qp -> head ) {
- switch ( qp->head->status ) {
- case CQR_STATUS_QUEUED:
- /* try to start the first I/O that can be started */
- if ( device->discipline->start_IO (qp->head) != 0)
- BUG();
- break;
- case CQR_STATUS_IN_IO:
- /* Check, if to invoke the missing interrupt handler */
- if ( dasd_check_expire_time (qp->head) ) {
- /* to be filled with MIH */
+ chanq_min_size =
+ (chanq_min_size + req->nr_sectors) >> 1;
+#endif /* CONFIG_DYNAMIC_QUEUE_MIN_SIZE */
+ dasd_dequeue_request (queue, req);
+ dasd_chanq_enq (qp, cqr);
}
- break;
+ } else { /* queue not empty OR criteria not met */
+ break; /* terminate request queue loop */
+ }
+ }
+ /* we process the requests with non-final status */
+ if (qp->head) {
+ switch (qp->head->status) {
+ case CQR_STATUS_QUEUED:
+ /* try to start the first I/O that can be started */
+ if (device->discipline->start_IO == NULL)
+ BUG ();
+ device->discipline->start_IO(qp->head);
+ break;
+ case CQR_STATUS_IN_IO:
+ /* Check, if to invoke the missing interrupt handler */
+ if (dasd_check_expire_time (qp->head)) {
+ /* to be filled with MIH */
+ }
+ break;
- case CQR_STATUS_PENDING:
- /* just wait */
- break;
- default:
- BUG();
- }
- }
- /* Now clean the requests with final status */
- while ( final_requests ) {
- cqr = final_requests;
- final_requests = cqr-> next;
- dasd_finalize_request( cqr );
- }
- s390irq_spin_unlock_irqrestore (irq, flags);
+ case CQR_STATUS_PENDING:
+ /* just wait */
+ break;
+ default:
+ BUG ();
+ }
+ }
+ s390irq_spin_unlock_irqrestore (irq, flags);
}
-/*
+/*
* function dasd_run_bh
* acquires the locks needed and then runs the bh
*/
static void
-dasd_run_bh (dasd_device_t *device)
+dasd_run_bh (dasd_device_t * device)
{
long flags;
spin_lock_irqsave (&io_request_lock, flags);
- atomic_set(&device->bh_scheduled,0);
+ atomic_set (&device->bh_scheduled, 0);
dasd_process_queues (device);
spin_unlock_irqrestore (&io_request_lock, flags);
}
-/*
+/*
* function dasd_schedule_bh
* schedules the request_fn to run with next run_bh cycle
*/
void
-dasd_schedule_bh (dasd_device_t *device)
+dasd_schedule_bh (dasd_device_t * device)
{
/* Protect against rescheduling, when already running */
- if (atomic_compare_and_swap(0,1,&device->bh_scheduled)) {
- return;
- }
+ if (atomic_compare_and_swap (0, 1, &device->bh_scheduled)) {
+ return;
+ }
- INIT_LIST_HEAD(&device->bh_tq.list);
+ INIT_LIST_HEAD (&device->bh_tq.list);
device->bh_tq.sync = 0;
device->bh_tq.routine = (void *) (void *) dasd_run_bh;
device->bh_tq.data = device;
@@ -1385,46 +1680,24 @@
return;
}
-/*
+/*
* function do_dasd_request
- * is called from ll_rw_blk.c and provides the caller of
+ * is called from ll_rw_blk.c and provides the caller of
* dasd_process_queues
*/
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
static void
do_dasd_request (request_queue_t * queue)
{
- dasd_device_t *device = (dasd_device_t *)
- ((long)queue-(long)offsetof (dasd_device_t, request_queue));
+ dasd_device_t *device = (dasd_device_t *)queue->queuedata;
dasd_process_queues (device);
}
-#else
-static void
-do_dasd_request (void)
-{
- major_info_t *major_info;
- dasd_device_t *device;
- int i;
-
- for (major_info = dasd_major_info;
- major_info != NULL;
- major_info = major_info->next) {
- for (i = 0; i < DASD_PER_MAJOR; i++) {
- device = major_info->dasd_device[i];
- if (!device)
- continue; /* remove indentation level */
- dasd_process_queues (device);
- }
- }
-}
-#endif /* LINUX_IS_24 */
/*
- * DASD_HANDLE_STATE_CHANGE_PENDING
+ * DASD_HANDLE_STATE_CHANGE_PENDING
*
* DESCRIPTION
* Handles the state change pending interrupt.
- * Search for the device related request queue and check if the first
+ * Search for the device related request queue and check if the first
* cqr in queue in in status 'CQR_STATUE_PENDING'.
* If so the status is set to 'CQR_STATUS_QUEUED' to reactivate
* the device.
@@ -1432,43 +1705,42 @@
* PARAMETER
* stat device status of state change pending interrupt.
*/
-void
-dasd_handle_state_change_pending (devstat_t *stat)
+void
+dasd_handle_state_change_pending (devstat_t * stat)
{
- dasd_device_t **device_addr;
- ccw_req_t *cqr;
+ dasd_device_t **device_addr;
+ ccw_req_t *cqr;
device_addr = dasd_device_from_devno (stat->devno);
- if (device_addr == NULL) {
- printk (KERN_INFO PRINTK_HEADER
- "unable to find device for state change pending "
- "interrupt: devno%04X\n",
- stat->devno);
- } else {
- /* re-activate first request in queue */
- cqr = (*device_addr)->queue.head;
+ if (device_addr == NULL) {
- if (cqr->status == CQR_STATUS_PENDING) {
+ printk (KERN_DEBUG PRINTK_HEADER
+ "unable to find device for state change pending "
+ "interrupt: devno%04X\n", stat->devno);
+ } else {
+ /* re-activate first request in queue */
+ cqr = (*device_addr)->queue.head;
- DASD_MESSAGE (KERN_INFO, (*device_addr),
- "%s",
- "device request queue restarted by "
- "state change pending interrupt\n");
+ if (cqr->status == CQR_STATUS_PENDING) {
- del_timer(&(*device_addr)->timer);
+ DASD_MESSAGE (KERN_DEBUG, (*device_addr),
+ "%s",
+ "device request queue restarted by "
+ "state change pending interrupt\n");
- check_then_set(&cqr->status,
- CQR_STATUS_PENDING,
- CQR_STATUS_QUEUED);
+ del_timer (&(*device_addr)->timer);
- dasd_schedule_bh(*device_addr);
+ check_then_set (&cqr->status,
+ CQR_STATUS_PENDING, CQR_STATUS_QUEUED);
- }
- }
-} /* end dasd_handle_state_change_pending */
+ dasd_schedule_bh (*device_addr);
-/*
+ }
+ }
+} /* end dasd_handle_state_change_pending */
+
+/*
* function dasd_int_handler
* is the DASD driver's default interrupt handler for SSCH-IO
*/
@@ -1476,16 +1748,14 @@
dasd_int_handler (int irq, void *ds, struct pt_regs *regs)
{
int ip;
- int devno;
ccw_req_t *cqr;
dasd_device_t *device;
unsigned long long now;
-#ifdef ERP_DEBUG
- static int counter = 0;
-#endif
dasd_era_t era = dasd_era_none; /* default is everything is okay */
devstat_t *stat = (devstat_t *)ds;
+ DASD_DRIVER_DEBUG_EVENT (4, dasd_int_handler,
+ "Interrupt: IRQ 0x%x",irq);
asm volatile ("STCK %0":"=m" (now));
if (stat == NULL) {
BUG();
@@ -1495,145 +1765,148 @@
if (stat->dstat & (DEV_STAT_ATTENTION |
DEV_STAT_DEV_END |
DEV_STAT_UNIT_EXCEP )) {
-
+ DASD_DRIVER_DEBUG_EVENT (2, dasd_int_handler,
+ "State change Interrupt: %04X",
+ stat->devno);
dasd_handle_state_change_pending (stat);
//return; /* TBD */
}
ip = stat->intparm;
if (!ip) { /* no intparm: unsolicited interrupt */
- printk (KERN_INFO PRINTK_HEADER
+ DASD_DRIVER_DEBUG_EVENT (2, dasd_int_handler,
+ "Unsolicited Interrupt: %04X",
+ stat->devno);
+ printk (KERN_DEBUG PRINTK_HEADER
"unsolicited interrupt: irq0x%x devno%04X\n",
irq,stat->devno);
return;
}
if (ip & 0x80000001) {
- printk (KERN_INFO PRINTK_HEADER
+ DASD_DRIVER_DEBUG_EVENT (2, dasd_int_handler,
+ "spurious Interrupt: %04X",
+ stat->devno);
+ printk (KERN_DEBUG PRINTK_HEADER
"spurious interrupt: irq0x%x devno%04X, parm %08x\n",
irq,stat->devno,ip);
return;
}
cqr = (ccw_req_t *)(long)ip;
device = (dasd_device_t *) cqr->device;
- if (device == NULL || device != ds-offsetof(dasd_device_t,dev_status)) {
+ if (device == NULL ||
+ device != ds-offsetof(dasd_device_t,dev_status)) {
BUG();
}
- devno = device->devinfo.devno;
if (device->devinfo.irq != irq) {
BUG();
}
if (strncmp (device->discipline->ebcname, (char *) &cqr->magic, 4)) {
BUG();
}
-#ifdef ERP_DEBUG
- if ((++counter % 937 >= 0) &&
- ( counter % 937 <= 10) &&
- ( counter < 5000 ) &&
- ( counter > 2000 ) ){
- static int fake_count = 0;
- printk ( KERN_INFO PRINTK_HEADER "***********************************************\n");
- printk ( KERN_INFO PRINTK_HEADER "Faking I/O error to recover from; cntr=%i / %02X\n",counter,++fake_count);
- printk ( KERN_INFO PRINTK_HEADER "***********************************************\n");
+#ifdef ERP_FAKE
+ {
+ static int counter = 0;
+ static int fake_count = 0;
+
+ if ((++counter % 937 >= 0) &&
+ ( counter % 937 <= 10) &&
+ ( counter < 5000) &&
+ ( counter > 2000) ) {
+
+ char *sense = stat->ii.sense.data;
+
+ printk (KERN_INFO PRINTK_HEADER
+ "***********************************************\n");
+ printk (KERN_INFO PRINTK_HEADER
+ "Faking I/O error to recover from; cntr=%i / %02X\n",
+ counter, ++fake_count);
+ printk (KERN_INFO PRINTK_HEADER
+ "***********************************************\n");
+
era = dasd_era_recover;
- stat->flag |= DEVSTAT_FLAG_SENSE_AVAIL;
+ stat->flag |= DEVSTAT_FLAG_SENSE_AVAIL;
stat->dstat |= 0x02;
-// sense 32
- {
- char *sense = stat->ii.sense.data;
- sense [25] = 0x1D;
- sense [27] = 0x00;
- //sense [25] = (fake_count % 256); //0x1B;
- //sense [27] = 0x00;
- }
-// sense 24
-// {
-// char *sense = stat->ii.sense.data;
-// sense [0] = (counter % 0xFF); //0x1B;
-// sense [1] = ((counter * 7) % 0xFF); //0x1B;
-// sense [2] = (fake_count % 0xFF); //0x1B;
-// sense [27] = 0x80;
-// }
-
-/*
- memset(stat->ii.sense.data,0,32);
- stat->ii.sense.data[2] = 0x06;
- stat->ii.sense.data[4] = 0x04;
- stat->ii.sense.data[5] = 0x60;
- stat->ii.sense.data[6] = 0x41;
- stat->ii.sense.data[8] = 0xff;
- stat->ii.sense.data[9] = 0xff;
- stat->ii.sense.data[15] = 0x05;
- stat->ii.sense.data[16] = 0x21;
- stat->ii.sense.data[18] = 0x60;
- stat->ii.sense.data[19] = 0x3b;
- stat->ii.sense.data[20] = 0x24;
- stat->ii.sense.data[21] = 0x61;
- stat->ii.sense.data[22] = 0x65;
- stat->ii.sense.data[23] = 0x03;
- stat->ii.sense.data[24] = 0x04;
- stat->ii.sense.data[25] = 0x10;
- stat->ii.sense.data[26] = 0x4e;
-*/
- }
-#endif
- /* first of all lets try to find out the appropriate era_action */
- if ( stat->flag & DEVSTAT_FLAG_SENSE_AVAIL ||
- stat->dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END) ) {
- /* anything abnormal ? */
- if ( device->discipline->examine_error == NULL ||
- stat->flag & DEVSTAT_HALT_FUNCTION ) {
- era = dasd_era_fatal;
- } else {
- era = device->discipline->examine_error (cqr, stat);
+ memset(sense,0,32);
+
+ /* 32 byte sense (byte 27 bit 1 = 0)*/
+ sense[25] = 0x1D;
+// sense [25] = (fake_count % 256); //0x1B;
+
+ /* 24 byte sense (byte 27 bit 1 = 1)*/
+// sense [0] = (counter % 0xFF); //0x1B;
+// sense [1] = ((counter * 7) % 0xFF); //0x1B;
+// sense [2] = (fake_count % 0xFF); //0x1B;
+// sense [27] = 0x80;
}
}
+#endif /* ERP_FAKE */
+ /* first of all lets try to find out the appropriate era_action */
+ DASD_DEVICE_DEBUG_EVENT (4, device," Int: CS/DS 0x%04X",
+ ((stat->cstat<<8)|stat->dstat));
+ /* first of all lets try to find out the appropriate era_action */
+ if (stat->flag & DEVSTAT_FLAG_SENSE_AVAIL ||
+ stat->dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) {
+ /* anything abnormal ? */
+ if (device->discipline->examine_error == NULL ||
+ stat->flag & DEVSTAT_HALT_FUNCTION) {
+ era = dasd_era_fatal;
+ } else {
+ era = device->discipline->examine_error (cqr, stat);
+ }
+ DASD_DRIVER_DEBUG_EVENT (1, dasd_int_handler," era_code %d",
+ era);
+ }
if ( era == dasd_era_none ) {
- if (device->level == DASD_DEVICE_LEVEL_ANALYSIS_PENDING)
- device->level = DASD_DEVICE_LEVEL_ANALYSIS_PREPARED;
check_then_set(&cqr->status,
CQR_STATUS_IN_IO, CQR_STATUS_DONE);
cqr->stopclk=now;
- cqr=cqr->next;
/* start the next queued request if possible -> fast_io */
- if (cqr->status == CQR_STATUS_QUEUED) {
- if (device->discipline->start_IO (cqr) != 0) {
+ if (cqr->next &&
+ cqr->next->status == CQR_STATUS_QUEUED) {
+ if (device->discipline->start_IO (cqr->next) != 0) {
printk (KERN_WARNING PRINTK_HEADER
"Interrupt fastpath failed!\n");
}
}
} else { /* error */
- if (cqr->dstat == NULL)
- cqr->dstat = kmalloc (sizeof (devstat_t), GFP_ATOMIC);
- if (cqr->dstat) {
- memcpy (cqr->dstat, stat, sizeof (devstat_t));
- } else {
- PRINT_ERR ("no memory for dstat...ignoring\n");
- }
- /* dump sense data */
- if (device->discipline &&
- device->discipline->dump_sense) {
- char *errmsg = device->discipline->dump_sense (device, cqr);
- if (errmsg != NULL) {
- printk ("Sense data:\n%s", errmsg);
- free_page ((unsigned long) errmsg);
- } else {
- printk (KERN_WARNING PRINTK_HEADER
- "No memory to dump error message\n");
- }
- }
- switch(era) {
- case dasd_era_fatal:
- check_then_set (&cqr->status,CQR_STATUS_IN_IO,
- CQR_STATUS_FAILED);
- break;
- case dasd_era_recover:
- check_then_set (&cqr->status,CQR_STATUS_IN_IO,
- CQR_STATUS_ERROR);
- break;
- default:
- BUG();
- }
- }
+ if (cqr->dstat == NULL)
+ cqr->dstat = kmalloc (sizeof (devstat_t), GFP_ATOMIC);
+ if (cqr->dstat) {
+ memcpy (cqr->dstat, stat, sizeof (devstat_t));
+ } else {
+ PRINT_ERR ("no memory for dstat...ignoring\n");
+ }
+
+#ifdef ERP_DEBUG
+ /* dump sense data */
+ if (device->discipline &&
+ device->discipline->dump_sense ) {
+
+ device->discipline->dump_sense (device,
+ cqr);
+ }
+#endif
+
+ switch (era) {
+ case dasd_era_fatal:
+ check_then_set (&cqr->status, CQR_STATUS_IN_IO,
+ CQR_STATUS_FAILED);
+ break;
+ case dasd_era_recover:
+ check_then_set (&cqr->status, CQR_STATUS_IN_IO,
+ CQR_STATUS_ERROR);
+ break;
+ default:
+ BUG ();
+ }
+ }
+ if ( cqr == device->init_cqr &&
+ ( cqr->status == CQR_STATUS_DONE ||
+ cqr->status == CQR_STATUS_FAILED )){
+ dasd_state_init_to_ready(device);
+ if ( atomic_read(&dasd_init_pending) == 0)
+ wake_up (&dasd_init_waitq);
+ }
dasd_schedule_bh (device);
}
@@ -1653,26 +1926,39 @@
* erp CQR performing the ERP
*/
ccw_req_t *
-default_erp_action (ccw_req_t * cqr)
+dasd_default_erp_action (ccw_req_t * cqr)
{
- ccw_req_t *erp = dasd_alloc_request ((char *) &cqr->magic, 1, 0);
- printk (KERN_WARNING PRINTK_HEADER
- "Default ERP called... \n");
+ dasd_device_t *device = cqr->device;
+ ccw_req_t *erp = dasd_alloc_request ((char *) &cqr->magic, 1, 0, cqr->device);
+
+ printk (KERN_DEBUG PRINTK_HEADER "Default ERP called... \n");
+
+ if (!erp) {
+
+ DASD_MESSAGE (KERN_ERR, device, "%s",
+ "Unable to allocate ERP request");
+
+ check_then_set (&cqr->status,
+ CQR_STATUS_ERROR,
+ CQR_STATUS_FAILED);
- if (erp == NULL)
- return NULL;
+ return cqr;
+ }
erp->cpaddr->cmd_code = CCW_CMD_TIC;
- erp->cpaddr->cda = (__u32)(void *)cqr->cpaddr;
- erp->function = default_erp_action;
- erp->refers = cqr;
+ erp->cpaddr->cda = (__u32) (void *) cqr->cpaddr;
+ erp->function = dasd_default_erp_action;
+ erp->refers = (unsigned int) (unsigned long) cqr;
erp->device = cqr->device;
erp->magic = cqr->magic;
erp->retries = 16;
erp->status = CQR_STATUS_FILLED;
+ dasd_chanq_enq_head (&device->queue,
+ erp);
+
return erp;
}
@@ -1683,6 +1969,8 @@
* Frees all ERPs of the current ERP Chain and set the status
* of the original CQR either to CQR_STATUS_DONE if ERP was successful
* or to CQR_STATUS_FAILED if ERP was NOT successful.
+ * NOTE: This function is only called if no discipline postaction
+ * is available
*
* PARAMETER
* erp current erp_head
@@ -1691,96 +1979,63 @@
* cqr pointer to the original CQR
*/
ccw_req_t *
-default_erp_postaction (ccw_req_t * erp)
+dasd_default_erp_postaction (ccw_req_t *erp)
{
- ccw_req_t *cqr = NULL, *free_erp = NULL;
- dasd_device_t *device = NULL;
- int success;
-
- device = (dasd_device_t *) (erp->device);
+
+ ccw_req_t *cqr = NULL,
+ *free_erp = NULL;
+ dasd_device_t *device = erp->device;
+ int success;
+
+ if (erp->refers == NULL ||
+ erp->function == NULL ) {
+
+ BUG ();
+ }
if (erp->status == CQR_STATUS_DONE)
success = 1;
else
success = 0;
-#ifdef ERP_DEBUG
-
- /* print current erp_chain */
- printk (KERN_WARNING PRINTK_HEADER
- "default ERP postaction called for erp chain:\n");
- {
- ccw_req_t *temp_erp = NULL;
- for (temp_erp = erp; temp_erp != NULL; temp_erp = temp_erp->refers){
- printk(KERN_WARNING PRINTK_HEADER
- " erp %p refers to %p with erp function %p\n",
- temp_erp,
- temp_erp->refers,
- temp_erp->function );
- }
- }
-
-#endif /* ERP_DEBUG*/
-
- if (erp->refers == NULL || erp->function == NULL) {
- BUG();
- }
- if (erp->function != default_erp_action) {
- printk (KERN_WARNING PRINTK_HEADER
- "default ERP postaction called ERP action [<%p>]\n",
- erp->function);
- }
/* free all ERPs - but NOT the original cqr */
-
while (erp->refers != NULL) {
- free_erp = erp;
- erp = erp->refers;
+
+ free_erp = erp;
+ erp = erp->refers;
+
/* remove the request from the device queue */
- dasd_chanq_deq (&device->queue, free_erp);
+ dasd_chanq_deq (&device->queue,
+ free_erp);
+
/* free the finished erp request */
- dasd_free_request (free_erp);
+ dasd_free_request (free_erp, free_erp->device);
}
-
+
/* save ptr to original cqr */
cqr = erp;
-#ifdef ERP_DEBUG
- printk (KERN_INFO PRINTK_HEADER
- "default_erp_postaction - left original request = %p \n",cqr);
-#endif /* ERP_DEBUG */
-
/* set corresponding status to original cqr */
if (success) {
+
check_then_set (&cqr->status,
- CQR_STATUS_ERROR,
- CQR_STATUS_DONE);
+ CQR_STATUS_ERROR,
+ CQR_STATUS_DONE);
} else {
+
check_then_set (&cqr->status,
- CQR_STATUS_ERROR,
+ CQR_STATUS_ERROR,
CQR_STATUS_FAILED);
}
-#ifdef ERP_DEBUG
- /* print current erp_chain */
- printk (KERN_WARNING PRINTK_HEADER
- "default ERP postaction finished with remaining chain:\n");
- {
- ccw_req_t *temp_erp = NULL;
- for (temp_erp = cqr; temp_erp != NULL; temp_erp = temp_erp->refers) {
- printk (KERN_WARNING PRINTK_HEADER
- " erp %p refers to %p \n",
- temp_erp, temp_erp->refers);
- }
- }
-#endif /* ERP_DEBUG */
-
return cqr;
-} /* end default_erp_postaction */
+
+} /* end default_erp_postaction */
/* SECTION: The helpers of the struct file_operations */
-/*
- * function dasd_format
+/*
+ * function dasd_format
* performs formatting of _device_ according to _fdata_
* Note: The discipline's format_function is assumed to deliver formatting
* commands to format a single unit of the device. In terms of the ECKD
@@ -1791,196 +2046,114 @@
dasd_format (dasd_device_t * device, format_data_t * fdata)
{
int rc = 0;
- int format_done = 0;
- ccw_req_t *req = NULL;
- format_data_t temp =
- {
- fdata->start_unit,
- fdata->stop_unit,
- fdata->blksize,
- fdata->intensity
- };
-
- spin_lock (&dasd_open_count_lock);
- if (device->open_count != 1) {
- DASD_MESSAGE (KERN_INFO, device,
- "device is already open %d times",
- device->open_count);
- spin_unlock(&dasd_open_count_lock);
- return -EINVAL;
- }
- if (!device->discipline->format_device) {
- spin_unlock(&dasd_open_count_lock);
- return -EINVAL;
- }
- device->open_count = -1;
- spin_unlock (&dasd_open_count_lock);
- /* downgrade state of the device */
- dasd_set_device_level (device->devinfo.irq,
- DASD_DEVICE_LEVEL_RECOGNIZED,
- device->discipline,
- 0);
- DASD_MESSAGE (KERN_INFO, device,
- "Starting format from %d to %d (%d B blocks flags %d",
- fdata->start_unit,
- fdata->stop_unit,
- fdata->blksize,
- fdata->intensity);
- /* Invalidate first track */
- if (fdata->start_unit == DASD_FORMAT_DEFAULT_START_UNIT &&
- fdata->stop_unit == DASD_FORMAT_DEFAULT_STOP_UNIT &&
- fdata->intensity == DASD_FORMAT_DEFAULT_INTENSITY ) {
- format_data_t temp2 =
- {0, 0, fdata->blksize, 0x04};
- DASD_MESSAGE (KERN_INFO, device,
- "%s",
- "Invalidating first track...");
- req = device->discipline->format_device (device, &temp2);
- if (req) {
- rc = sleep_on_req (req);
- dasd_free_request (req); /* request is no longer used */
- } else {
- rc = -EINVAL;
- }
- if (rc) {
- DASD_MESSAGE (KERN_WARNING, device,
- "%s",
- "Can't invalidate Track 0\n");
- } else {
- DASD_MESSAGE (KERN_INFO, device,
- "%s",
- "...Invalidation complete");
- }
- temp.start_unit++;
- }
- /* format remainnig tracks of device */
- while (!rc &&
- ((req = device->discipline->format_device (device, &temp)) != NULL) ) {
- format_done=1;
- if ((rc = sleep_on_req (req)) != 0) {
+ int openct = atomic_read (&device->open_count);
-
- DASD_MESSAGE (KERN_WARNING, device,
- " Formatting failed with rc = %d\n",
- rc);
+ if (openct > 1) {
+ DASD_MESSAGE (KERN_WARNING, device, "%s",
+ "dasd_format: device is open! expect errors.");
+ }
+ DASD_MESSAGE (KERN_INFO, device,
+ "formatting units %d to %d (%d B blocks) flags %d",
+ fdata->start_unit, fdata->stop_unit,
+ fdata->blksize, fdata->intensity);
+ while ((!rc) && (fdata->start_unit <= fdata->stop_unit)) {
+ ccw_req_t *req;
+ dasd_format_fn_t ffn = device->discipline->format_device;
+ ffn = device->discipline->format_device;
+ if (ffn == NULL)
+ break;
+ req = ffn (device, fdata);
+ if (req == NULL) {
+ rc = -ENOMEM;
break;
}
-
- dasd_free_request (req); /* request is no longer used */
- temp.start_unit++;
+ if ((rc = dasd_sleep_on_req (req)) != 0) {
+ DASD_MESSAGE (KERN_WARNING, device,
+ " Formatting of unit %d failed with rc = %d\n",
+ fdata->start_unit, rc);
+ break;
+ }
+ dasd_free_request (req, device); /* request is no longer used */
+ if ( signal_pending(current) )
+ break;
+ fdata->start_unit++;
}
-
- if (!rc &&
- req == NULL ) {
- if (fdata->start_unit == DASD_FORMAT_DEFAULT_START_UNIT &&
- fdata->stop_unit == DASD_FORMAT_DEFAULT_STOP_UNIT &&
- fdata->intensity == DASD_FORMAT_DEFAULT_INTENSITY ) {
- format_data_t temp2 =
- {0, 0, fdata->blksize, fdata->intensity};
- DASD_MESSAGE (KERN_INFO, device,
- "%s",
- "Revalidating first track...");
- req = device->discipline->format_device (device, &temp2);
- if (req) {
- rc = sleep_on_req (req);
- dasd_free_request (req); /* request is no longer used */
- } else {
- rc = -EINVAL;
- }
- if (rc) {
- DASD_MESSAGE (KERN_WARNING, device,
- "%s",
- "Can't revalidate Track 0\n");
- } else {
- DASD_MESSAGE (KERN_INFO, device,
- "%s",
- "...Revalidation complete");
- }
- }
- } /* end if no more requests */
-
- /* check if at least one format cp was build in discipline */
- if (!format_done) {
- rc = -EINVAL;
- }
-
- if (rc)
- DASD_MESSAGE (KERN_WARNING, device,
- "%s", " Formatting finished unsuccessfully");
- else
- DASD_MESSAGE (KERN_INFO, device,
- "%s", " Formatting finished successfully");
-
- /*
- * re-analyse device
- */
- dasd_set_device_level (device->devinfo.irq,
- DASD_DEVICE_LEVEL_ONLINE,
- device->discipline,
- 0);
- udelay (1500000);
-
- dasd_set_device_level (device->devinfo.irq,
- DASD_DEVICE_LEVEL_ONLINE,
- device->discipline,
- 0);
-
- spin_lock (&dasd_open_count_lock);
- device->open_count=1;
- spin_unlock (&dasd_open_count_lock);
return rc;
} /* end dasd_format */
-static struct list_head dasd_ioctls = LIST_HEAD_INIT(dasd_ioctls);
+static struct list_head dasd_ioctls = LIST_HEAD_INIT (dasd_ioctls);
static dasd_ioctl_list_t *
-dasd_find_ioctl( int no )
+dasd_find_ioctl (int no)
{
struct list_head *curr;
- list_for_each(curr,&dasd_ioctls){
- if (list_entry(curr,dasd_ioctl_list_t,list)->no == no ){
- return list_entry(curr,dasd_ioctl_list_t,list);
+ list_for_each (curr, &dasd_ioctls) {
+ if (list_entry (curr, dasd_ioctl_list_t, list)->no == no) {
+ return list_entry (curr, dasd_ioctl_list_t, list);
}
}
return NULL;
}
int
-dasd_ioctl_no_register ( int no, dasd_ioctl_fn_t handler )
+dasd_ioctl_no_register (struct module *owner, int no, dasd_ioctl_fn_t handler)
{
dasd_ioctl_list_t *new;
- if (dasd_find_ioctl(no))
+ if (dasd_find_ioctl (no))
return -EBUSY;
- new = kmalloc(sizeof(dasd_ioctl_list_t),GFP_KERNEL);
- if ( new == NULL )
+ new = kmalloc (sizeof (dasd_ioctl_list_t), GFP_KERNEL);
+ if (new == NULL)
return -ENOMEM;
- new -> no = no;
- new -> handler = handler;
- list_add(&new->list,&dasd_ioctls);
-#ifdef MODULE
- MOD_INC_USE_COUNT;
-#endif
+ new->owner = owner;
+ new->no = no;
+ new->handler = handler;
+ list_add (&new->list, &dasd_ioctls);
+ MOD_INC_USE_COUNT;
return 0;
}
int
-dasd_ioctl_no_unregister ( int no, dasd_ioctl_fn_t handler )
-{
- dasd_ioctl_list_t *old = dasd_find_ioctl(no);
- if ( old == NULL )
+dasd_ioctl_no_unregister (struct module *owner, int no, dasd_ioctl_fn_t handler)
+{
+ dasd_ioctl_list_t *old = dasd_find_ioctl (no);
+ if (old == NULL)
return -ENOENT;
- if ( old->no != no ||
- old->handler != handler )
+ if (old->no != no || old->handler != handler || owner != old->owner )
return -EINVAL;
- list_del(&old->list);
- kfree(old);
-#ifdef MODULE
- MOD_DEC_USE_COUNT;
-#endif
+ list_del (&old->list);
+ kfree (old);
+ MOD_DEC_USE_COUNT;
return 0;
}
static int
+dasd_revalidate (dasd_device_t * device)
+{
+ int rc = 0;
+ int i;
+ kdev_t kdev = device->kdev;
+ int openct = atomic_read (&device->open_count);
+ int start = MINOR (kdev);
+ if (openct != 1) {
+ DASD_MESSAGE (KERN_WARNING, device, "%s",
+ "BLKRRPART: device is open! expect errors.");
+ }
+ for (i = (1 << DASD_PARTN_BITS) - 1; i >= 0; i--) {
+ int major = device->major_info->gendisk.major;
+ int minor = start + i;
+ kdev_t devi = MKDEV (major, minor);
+ struct super_block *sb = get_super (devi);
+ sync_dev (devi);
+ if (sb)
+ invalidate_inodes (sb);
+ invalidate_buffers (devi);
+ }
+ dasd_destroy_partitions(device);
+ dasd_setup_partitions(device);
+ return rc;
+
+}
+static int
do_dasd_ioctl (struct inode *inp, /* unsigned */ int no, unsigned long data)
{
int rc = 0;
@@ -2009,31 +2182,37 @@
_IOC_DIR (no) == (_IOC_READ | _IOC_WRITE) ? "rw" : "u",
_IOC_TYPE (no), _IOC_NR (no), _IOC_SIZE (no),
device->name, MAJOR (inp->i_rdev), MINOR (inp->i_rdev),
- device->devinfo.devno, device->devinfo.irq,
- data);
+ device->devinfo.devno, device->devinfo.irq, data);
#endif
switch (no) {
+ case DASDAPIVER: {
+ int ver = DASD_API_VERSION;
+ rc = copy_to_user ((int *) data, &ver, sizeof (int));
+ if (rc)
+ rc = -EFAULT;
+ break;
+ }
case BLKGETSIZE:{ /* Return device size */
- long blocks = blk_size[MAJOR (inp->i_rdev)][MINOR (inp->i_rdev)] << 1;
- rc = copy_to_user ((long *) data, &blocks, sizeof (long));
+ long blocks = major_info->gendisk.sizes
+ [MINOR (inp->i_rdev)] << 1;
+ rc =
+ copy_to_user ((long *) data, &blocks,
+ sizeof (long));
if (rc)
rc = -EFAULT;
break;
}
case BLKRRPART:{
- if (!capable(CAP_SYS_ADMIN)) {
- rc = -EACCES;
- break;
- }
- fsync_dev(inp->i_rdev);
- dasd_partn_detect (device);
- invalidate_buffers(inp->i_rdev);
- rc = 0;
+ if (!capable (CAP_SYS_ADMIN)) {
+ rc = -EACCES;
+ break;
+ }
+ rc = dasd_revalidate (device);
break;
}
case HDIO_GETGEO:{
- struct hd_geometry geo = {0,};
- rc = dasd_fillgeo(inp->i_rdev, &geo);
+ struct hd_geometry geo = { 0, };
+ rc = dasd_fillgeo (inp->i_rdev, &geo);
if (rc)
break;
@@ -2043,148 +2222,208 @@
rc = -EFAULT;
break;
}
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
- case BLKSSZGET:
- case BLKROSET:
- case BLKROGET:
- case BLKRASET:
- case BLKRAGET:
- case BLKFLSBUF:
- case BLKPG:
- case BLKELVGET:
- case BLKELVSET:
- return blk_ioctl(inp->i_rdev, no, data);
- break;
-#else
- case BLKRASET:
- if(!capable(CAP_SYS_ADMIN))
- return -EACCES;
- if(!dev || arg > 0xff)
- return -EINVAL;
- read_ahead[MAJOR(dev)] = arg;
- rc = 0;
- break;
- case BLKRAGET:
- if (!arg)
- return -EINVAL;
- rc = put_user(read_ahead[MAJOR(dev)], (long *) arg);
- break;
- case BLKSSZGET: {
- /* Block size of media */
- rc = copy_to_user((int *)data,
- &blksize_size[MAJOR(device->kdev)]
- [MINOR(device->kdev)],
- sizeof(int)) ? -EFAULT : 0;
- }
- RO_IOCTLS (inp->i_rdev, data);
- case BLKFLSBUF:{
- if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
- fsync_dev(inp->i_rdev);
- invalidate_buffers(inp->i_rdev);
- rc = 0;
- break;
+ case BIODASDDISABLE:{
+ if (!capable (CAP_SYS_ADMIN)) {
+ rc = -EACCES;
+ break;
+ }
+ if ( device->level > DASD_STATE_ACCEPT) {
+ if ( device->request_queue)
+ dasd_flush_request_queues(device,0);
+ dasd_flush_chanq(device,0);
+ dasd_disable_blkdev(device);
+ dasd_set_device_level (device->devinfo.devno,
+ device->discipline,
+ DASD_STATE_ACCEPT);
+ }
+ break;
}
-#endif /* LINUX_IS_24 */
- case BIODASDRSID:{
- rc = copy_to_user ((void *) data,
- &(device->devinfo.sid_data),
- sizeof (senseid_t)) ? -EFAULT : 0;
- break;
- }
- case BIODASDRWTB:{
- int offset = 0;
- int xlt;
- rc = copy_from_user (&xlt, (void *) data,
- sizeof (int)) ? -EFAULT : 0;
- if (rc)
+ case BIODASDENABLE:{
+ dasd_range_t range = {
+ from: device->devinfo.devno,
+ to: device->devinfo.devno
+ };
+ if (!capable (CAP_SYS_ADMIN)) {
+ rc = -EACCES;
+ break;
+ }
+ dasd_enable_ranges (&range, device->discipline, 0);
+ break;
+ }
+ case BIODASDFMT:{
+ /* fdata == NULL is no longer a valid arg to dasd_format ! */
+ int partn = MINOR (inp->i_rdev) &
+ ((1 << major_info->gendisk.minor_shift) - 1);
+ format_data_t fdata;
+
+ if (!capable (CAP_SYS_ADMIN)) {
+ rc = -EACCES;
break;
- offset = major_info->gendisk.part[MINOR (inp->i_rdev)].start_sect >>
- device->sizes.s2b_shift;
- xlt += offset;
- rc = copy_to_user ((void *) data, &xlt,
- sizeof (int)) ? -EFAULT : 0;
- break;
- }
- case BIODASDFORMAT:{
- /* fdata == NULL is a valid arg to dasd_format ! */
- int partn;
- format_data_t fdata =
- {
- DASD_FORMAT_DEFAULT_START_UNIT,
- DASD_FORMAT_DEFAULT_STOP_UNIT,
- DASD_FORMAT_DEFAULT_BLOCKSIZE,
- DASD_FORMAT_DEFAULT_INTENSITY};
-
- if (!capable(CAP_SYS_ADMIN)) {
- rc = -EACCES;
- break;
+ }
+ if (dasd_features_from_devno(device->devinfo.devno)&DASD_FEATURE_READONLY) {
+ rc = -EROFS;
+ break;
}
- if (data) {
- rc = copy_from_user (&fdata, (void *) data,
- sizeof (format_data_t));
- if (rc) {
- rc = -EFAULT;
- break;
- }
+ if (!data) {
+ rc = -EINVAL;
+ break;
+ }
+ rc = copy_from_user (&fdata, (void *) data,
+ sizeof (format_data_t));
+ if (rc) {
+ rc = -EFAULT;
+ break;
}
- partn = MINOR (inp->i_rdev) & ((1 << major_info->gendisk.minor_shift) - 1);
if (partn != 0) {
- printk (KERN_WARNING PRINTK_HEADER
- " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
- " Cannot low-level format a partition\n",
- device->devinfo.devno, device->devinfo.irq, device->name,
- MAJOR (inp->i_rdev), MINOR (inp->i_rdev));
+ DASD_MESSAGE (KERN_WARNING, device, "%s",
+ "Cannot low-level format a partition");
return -EINVAL;
}
rc = dasd_format (device, &fdata);
break;
}
+ case BIODASDPRRST:{
+ if (!capable (CAP_SYS_ADMIN)) {
+ rc = -EACCES;
+ break;
+ }
+ memset (&device->profile, 0,
+ sizeof (dasd_profile_info_t));
+ break;
+ }
+ case BIODASDPRRD:{
+ rc = copy_to_user((long *)data,
+ (long *)&device->profile,
+ sizeof(dasd_profile_info_t));
+ if (rc)
+ rc = -EFAULT;
+ break;
+ }
case BIODASDRSRV:{
- ccw_req_t *req;
- if (!capable(CAP_SYS_ADMIN)) {
- rc = -EACCES;
- break;
- }
- req = device->discipline->reserve (device);
- rc = sleep_on_req (req);
- dasd_free_request (req);
- break;
- }
+ ccw_req_t *req;
+ if (!capable (CAP_SYS_ADMIN)) {
+ rc = -EACCES;
+ break;
+ }
+ req = device->discipline->reserve (device);
+ rc = dasd_sleep_on_req (req);
+ dasd_free_request (req, device);
+ break;
+ }
case BIODASDRLSE:{
- ccw_req_t *req;
- if (!capable(CAP_SYS_ADMIN)) {
- rc = -EACCES;
- break;
- }
- req = device->discipline->release (device);
- rc = sleep_on_req (req);
- dasd_free_request (req);
- break;
- }
+ ccw_req_t *req;
+ if (!capable (CAP_SYS_ADMIN)) {
+ rc = -EACCES;
+ break;
+ }
+ req = device->discipline->release (device);
+ rc = dasd_sleep_on_req (req);
+ dasd_free_request (req, device);
+ break;
+ }
case BIODASDSLCK:{
printk (KERN_WARNING PRINTK_HEADER
"Unsupported ioctl BIODASDSLCK\n");
break;
}
+ case BIODASDINFO:{
+ dasd_information_t dasd_info;
+ unsigned long flags;
+ rc = device->discipline->fill_info (device, &dasd_info);
+ dasd_info.label_block = device->sizes.pt_block;
+ dasd_info.devno = device->devinfo.devno;
+ dasd_info.schid = device->devinfo.irq;
+ dasd_info.cu_type = device->devinfo.sid_data.cu_type;
+ dasd_info.cu_model = device->devinfo.sid_data.cu_model;
+ dasd_info.dev_type = device->devinfo.sid_data.dev_type;
+ dasd_info.dev_model = device->devinfo.sid_data.dev_model;
+ dasd_info.open_count =
+ atomic_read (&device->open_count);
+ dasd_info.status = device->level;
+ if (device->discipline) {
+ memcpy (dasd_info.type,
+ device->discipline->name, 4);
+ } else {
+ memcpy (dasd_info.type, "none", 4);
+ }
+ dasd_info.req_queue_len = 0;
+ dasd_info.chanq_len = 0;
+ if (device->request_queue->request_fn) {
+ struct list_head *l;
+ ccw_req_t *cqr = device->queue.head;
+ spin_lock_irqsave (&io_request_lock, flags);
+ list_for_each (l,
+ &device->request_queue->
+ queue_head) {
+ dasd_info.req_queue_len++;
+ }
+ spin_unlock_irqrestore (&io_request_lock,
+ flags);
+ s390irq_spin_lock_irqsave (device->devinfo.irq,
+ flags);
+ while (cqr) {
+ cqr = cqr->next;
+ dasd_info.chanq_len++;
+ }
+ s390irq_spin_unlock_irqrestore (device->devinfo.
+ irq, flags);
+ }
+ rc =
+ copy_to_user ((long *) data, (long *) &dasd_info,
+ sizeof (dasd_information_t));
+ if (rc)
+ rc = -EFAULT;
+ break;
+ }
+#if 0 /* needed for XFS */
+ case BLKBSZSET:{
+ int bsz;
+ rc = copy_from_user ((long *)&bsz,(long *)data,sizeof(int));
+ if ( rc ) {
+ rc = -EFAULT;
+ } else {
+ if ( bsz >= device->sizes.bp_block )
+ rc = blk_ioctl (inp->i_rdev, no, data);
+ else
+ rc = -EINVAL;
+ }
+ break;
+ }
+#endif /* 0 */
+ case BLKSSZGET:
+ case BLKROSET:
+ case BLKROGET:
+ case BLKRASET:
+ case BLKRAGET:
+ case BLKFLSBUF:
+ case BLKPG:
+ case BLKELVGET:
+ case BLKELVSET:
+ return blk_ioctl (inp->i_rdev, no, data);
+ break;
default:{
- dasd_ioctl_list_t *old = dasd_find_ioctl(no);
- if ( old ) {
- rc = old->handler(inp,no,data);
+ dasd_ioctl_list_t *old = dasd_find_ioctl (no);
+ if (old) {
+ if ( old->owner )
+ __MOD_INC_USE_COUNT(old->owner);
+ rc = old->handler (inp, no, data);
+ if ( old->owner )
+ __MOD_DEC_USE_COUNT(old->owner);
} else {
DASD_MESSAGE (KERN_INFO, device,
- "ioctl 0x%08x=%s'0x%x'%d(%d) data %8lx\n",
+ "ioctl 0x%08x=%s'0x%x'%d(%d) data %8lx\n",
no,
_IOC_DIR (no) == _IOC_NONE ? "0" :
_IOC_DIR (no) == _IOC_READ ? "r" :
- _IOC_DIR (no) == _IOC_WRITE ? "w" :
- _IOC_DIR (no) == (_IOC_READ | _IOC_WRITE) ?
- "rw" : "u",
- _IOC_TYPE (no), _IOC_NR (no), _IOC_SIZE (no),
+ _IOC_DIR (no) ==
+ _IOC_WRITE ? "w" : _IOC_DIR (no)
+ == (_IOC_READ | _IOC_WRITE) ? "rw"
+ : "u", _IOC_TYPE (no),
+ _IOC_NR (no), _IOC_SIZE (no),
data);
- rc = -EINVAL;
- }
+ rc = -ENOTTY;
+ }
break;
}
}
@@ -2209,37 +2448,46 @@
dasd_open (struct inode *inp, struct file *filp)
{
int rc = 0;
+ unsigned long flags;
dasd_device_t *device;
+ MOD_INC_USE_COUNT;
if ((!inp) || !(inp->i_rdev)) {
- return -EINVAL;
+ rc = -EINVAL;
+ goto fail;
}
if (dasd_probeonly) {
- printk ("\n" KERN_INFO PRINTK_HEADER "No access to device (%d:%d) due to probeonly mode\n", MAJOR (inp->i_rdev), MINOR (inp->i_rdev));
- return -EPERM;
+ printk ("\n" KERN_INFO PRINTK_HEADER
+ "No access to device (%d:%d) due to probeonly mode\n",
+ MAJOR (inp->i_rdev), MINOR (inp->i_rdev));
+ rc = -EPERM;
+ goto fail;
}
+ spin_lock_irqsave(&discipline_lock,flags);
device = dasd_device_from_kdev (inp->i_rdev);
- if (device == NULL) {
+ if (device == NULL ) {
printk (KERN_WARNING PRINTK_HEADER
- "No device registered as (%d:%d)\n", MAJOR (inp->i_rdev), MINOR (inp->i_rdev));
- return -ENODEV;
+ "No device registered as (%d:%d)\n",
+ MAJOR (inp->i_rdev), MINOR (inp->i_rdev));
+ rc = -ENODEV;
+ goto unlock;
}
- if (device->level < DASD_DEVICE_LEVEL_RECOGNIZED ||
- device->discipline == NULL) {
+ if (device->level < DASD_STATE_ACCEPT ) {
DASD_MESSAGE (KERN_WARNING, device,
" %s", " Cannot open unrecognized device\n");
- return -EINVAL;
+ rc = -ENODEV;
+ goto unlock;
}
- spin_lock(&dasd_open_count_lock);
- if (device->open_count == -1) {
- spin_unlock (&dasd_open_count_lock);
- return -EBUSY;
+ if (atomic_inc_return (&device->open_count) == 1 ) {
+ if ( device->discipline->owner )
+ __MOD_INC_USE_COUNT(device->discipline->owner);
+ } else {
+ MOD_DEC_USE_COUNT;
}
-#ifdef MODULE
- MOD_INC_USE_COUNT;
-#endif /* MODULE */
- device->open_count++;
- spin_unlock (&dasd_open_count_lock);
+ unlock:
+ spin_unlock_irqrestore(&discipline_lock,flags);
+ fail:
+ if (rc) MOD_DEC_USE_COUNT;
return rc;
}
@@ -2247,28 +2495,41 @@
dasd_release (struct inode *inp, struct file *filp)
{
int rc = 0;
+ int count;
dasd_device_t *device;
if ((!inp) || !(inp->i_rdev)) {
- return -EINVAL;
+ rc = -EINVAL;
+ goto out;
}
device = dasd_device_from_kdev (inp->i_rdev);
if (device == NULL) {
printk (KERN_WARNING PRINTK_HEADER
"No device registered as %d:%d\n",
MAJOR (inp->i_rdev), MINOR (inp->i_rdev));
- return -EINVAL;
+ rc = -EINVAL;
+ goto out;
}
- spin_lock(&dasd_open_count_lock);
- if (device->open_count--) {
-#ifdef MODULE
- MOD_DEC_USE_COUNT;
-#endif /* MODULE */
- }
- fsync_dev(inp->i_rdev); /* sync the device */
- if (device->open_count == 0) /* finally invalidate buffers */
- invalidate_buffers(inp->i_rdev);
- spin_unlock(&dasd_open_count_lock);
+
+ if (device->level < DASD_STATE_ACCEPT ) {
+ DASD_MESSAGE (KERN_WARNING, device,
+ " %s", " Cannot release unrecognized device\n");
+ rc = -ENODEV;
+ goto out;
+ }
+ fsync_dev (inp->i_rdev); /* sync the device */
+ count = atomic_dec_return (&device->open_count);
+ if ( count == 0) {
+ invalidate_buffers (inp->i_rdev);
+ if ( device->discipline->owner )
+ __MOD_DEC_USE_COUNT(device->discipline->owner);
+ MOD_DEC_USE_COUNT;
+ } else if ( count == -1 ) { /* paranoia only */
+ atomic_set (&device->open_count,0);
+ printk (KERN_WARNING PRINTK_HEADER
+ "release called with open count==0\n");
+ }
+ out:
return rc;
}
@@ -2278,11 +2539,6 @@
open:dasd_open,
release:dasd_release,
ioctl:dasd_ioctl,
-#if ! (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
- read:block_read,
- write:block_write,
- fsync:block_fsync,
-#endif /* LINUX_IS_24 */
};
/* SECTION: Management of device list */
@@ -2294,16 +2550,9 @@
return -EINVAL;
device->discipline->fill_geometry (device, geo);
- geo->start = device->major_info->
- gendisk.part[MINOR(kdev)].start_sect;
-
- /* This is a hack. dasdfmt and ibm.c expect geo.start
- to contain the block number of the label block when
- it calls HDIO_GETGEO on the first partition. */
- if (geo->start == 0)
- geo->start = device->sizes.pt_block;
-
- return 0;
+ geo->start = device->major_info->gendisk.part[MINOR(kdev)].start_sect
+ >> device->sizes.s2b_shift;;
+ return 0;
}
@@ -2315,11 +2564,11 @@
char first, second, third;
if (hd) {
- major_info_t *major_info=NULL;
+ major_info_t *major_info = NULL;
struct list_head *l;
- list_for_each(l,&dasd_major_info[0].list) {
- major_info = list_entry(l,major_info_t,list);
+ list_for_each (l, &dasd_major_info[0].list) {
+ major_info = list_entry (l, major_info_t, list);
if (&major_info->gendisk == hd) {
break;
}
@@ -2330,14 +2579,14 @@
}
}
third = index % 26;
- second = ((index-26) / 26) % 26;
- first = (((index-702) / 26) / 26) % 26;
+ second = ((index - 26) / 26) % 26;
+ first = (((index - 702) / 26) / 26) % 26;
len = sprintf (str, "dasd");
- if (index>701) {
+ if (index > 701) {
len += sprintf (str + len, "%c", first + 'a');
}
- if (index>25) {
+ if (index > 25) {
len += sprintf (str + len, "%c", second + 'a');
}
len += sprintf (str + len, "%c", third + 'a');
@@ -2352,19 +2601,214 @@
return 0;
}
-#ifdef CONFIG_DASD_DYNAMIC
static void
-dasd_plug_device (dasd_device_t *device)
+dasd_plug_device (dasd_device_t * device)
{
- device->request_queue.plugged = 1; /* inhibit further calls of request_fn */
+ atomic_set(&device->plugged,1);
+}
+
+static void
+dasd_unplug_device (dasd_device_t * device)
+{
+ atomic_set(&device->plugged,0);
+ dasd_schedule_bh(device);
+}
+
+static void
+dasd_flush_chanq ( dasd_device_t * device, int destroy )
+{
+ ccw_req_t *cqr;
+ unsigned long flags;
+ if ( destroy ) {
+ s390irq_spin_lock_irqsave (device->devinfo.irq, flags);
+ cqr = device->queue.head;
+ while ( cqr != NULL ) {
+ if ( cqr -> status == CQR_STATUS_IN_IO )
+ device->discipline->term_IO (cqr);
+ if ( cqr->status != CQR_STATUS_DONE ||
+ cqr->status != CQR_STATUS_FAILED ) {
+ cqr->status = CQR_STATUS_FAILED;
+ }
+ dasd_schedule_bh(device);
+ cqr = cqr->next;
+ }
+ s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags);
+ }
+ wait_event( device->wait_q, device->queue.head == NULL );
+}
+
+static void
+dasd_flush_request_queues ( dasd_device_t * device, int destroy )
+{
+ int i;
+ int major = MAJOR(device->kdev);
+ int minor = MINOR(device->kdev);
+ for ( i = 0; i < (1 << DASD_PARTN_BITS); i ++) {
+ if ( destroy )
+ destroy_buffers(MKDEV(major,minor+i));
+ else
+ invalidate_buffers(MKDEV(major,minor+i));
+ }
+}
+
+static int
+dasd_disable_volume ( dasd_device_t * device, int force )
+{
+ int rc = 0;
+ int target = DASD_STATE_KNOWN;
+ int count = atomic_read (&device->open_count);
+ int part;
+
+ if ( count ) {
+ DASD_MESSAGE (KERN_EMERG, device, "%s",
+ "device has vanished although it was open!");
+ }
+ if ( force ) {
+ dasd_flush_chanq(device,force);
+ dasd_flush_request_queues(device,force);
+ dasd_disable_blkdev(device);
+ target = DASD_STATE_DEL;
+ }
+
+#if 0
+ /* unregister devfs entries */
+ for (part = 0; part < (1 << DASD_PARTN_BITS); part++) {
+ devfs_unregister(device->major_info->gendisk.part[MINOR(device->kdev)+part].de);
+ device->major_info->gendisk.part[MINOR(device->kdev)+part].de = NULL;
+ }
+#endif
+
+ DASD_MESSAGE (KERN_WARNING, device,
+ "disabling device, target state:%d",target);
+ dasd_set_device_level (device->devinfo.devno,
+ device->discipline,
+ target);
+ return rc;
+}
+
+static void
+dasd_disable_ranges (dasd_range_t *range,
+ dasd_discipline_t *d,
+ int all, int force )
+{
+ dasd_range_t *rrange;
+ int j;
+
+ if (range == &dasd_range_head) {
+ rrange = list_entry (range->list.next,
+ dasd_range_t, list);
+ } else {
+ rrange = range;
+ }
+ do {
+ for (j = rrange->from; j <= rrange->to; j++) {
+ dasd_device_t **dptr;
+ dasd_device_t *device;
+ dptr = dasd_device_from_devno(j);
+ if ( dptr == NULL ) {
+ continue;
+ }
+ device = *dptr;
+ if (device == NULL ||
+ (d != NULL &&
+ device -> discipline != d))
+ continue;
+
+ dasd_disable_volume(device, force);
+ }
+ rrange = list_entry (rrange->list.next, dasd_range_t, list);
+ } while ( all && rrange && rrange != range );
+}
+
+static void
+dasd_enable_single_device ( unsigned long arg ) {
+ dasd_device_t * device =(dasd_device_t *) arg;
+ int devno = device->devinfo.devno;
+ dasd_range_t range = { from: devno, to:devno };
+ dasd_enable_ranges (&range,NULL,0);
}
static void
-dasd_unplug_device (dasd_device_t *device)
+dasd_enable_ranges (dasd_range_t *range, dasd_discipline_t *d, int all )
{
- generic_unplug_device(&device->request_queue);
+ int retries = 0;
+ int j;
+ kdev_t tempdev;
+ dasd_range_t *rrange;
+
+ if (range == NULL)
+ return;
+
+ do {
+ if (range == &dasd_range_head) {
+ rrange = list_entry (range->list.next,
+ dasd_range_t, list);
+ } else {
+ rrange = range;
+ }
+ do {
+ for (j = rrange->from; j <= rrange->to; j++) {
+ if ( dasd_devindex_from_devno(j) < 0 )
+ continue;
+ dasd_set_device_level (j, d, DASD_STATE_ONLINE);
+ }
+ rrange = list_entry (rrange->list.next, dasd_range_t, list);
+ } while ( all && rrange && rrange != range );
+
+ if (atomic_read (&dasd_init_pending) == 0) /* we are done, exit loop */
+ break;
+
+ if ( retries == 0 ) {
+ printk (KERN_INFO PRINTK_HEADER
+ "waiting for responses...\n");
+ } else if ( retries < 5 ) {
+ printk (KERN_INFO PRINTK_HEADER
+ "waiting a little bit longer...\n");
+ } else {
+ printk (KERN_INFO PRINTK_HEADER
+ "giving up, enable late devices manually!\n");
+ break;
+ }
+ interruptible_sleep_on_timeout (&dasd_init_waitq, (1 * HZ));
+ retries ++;
+ } while (1);
+ /* now setup block devices */
+
+ /* Now do block device and partition setup */
+ if (range == &dasd_range_head) {
+ rrange = list_entry (range->list.next,
+ dasd_range_t, list);
+ } else {
+ rrange = range;
+ }
+ do {
+ for (j = rrange->from; j <= rrange->to; j++) {
+ dasd_device_t **dptr;
+ dasd_device_t *device;
+ if ( dasd_devindex_from_devno(j) < 0 )
+ continue;
+ dptr = dasd_device_from_devno(j);
+ device = *dptr;
+ if (device == NULL )
+ continue;
+ if ( ((d == NULL && device->discipline != NULL) ||
+ (device->discipline == d )) &&
+ device->level >= DASD_STATE_READY &&
+ device->request_queue == NULL ) {
+ if (dasd_features_from_devno(j)&DASD_FEATURE_READONLY) {
+ for (tempdev=device->kdev;tempdev<(device->kdev +(1 << DASD_PARTN_BITS));tempdev++)
+ set_device_ro (tempdev, 1);
+ printk (KERN_WARNING PRINTK_HEADER "setting read-only mode for device /dev/%s\n",device->name);
+ }
+ dasd_setup_blkdev(device);
+ dasd_setup_partitions(device);
+ }
+ }
+ rrange = list_entry (rrange->list.next, dasd_range_t, list);
+ } while ( all && rrange && rrange != range );
}
+#ifdef CONFIG_DASD_DYNAMIC
static void
dasd_not_oper_handler (int irq, int status)
{
@@ -2373,13 +2817,12 @@
struct list_head *l;
int i, devno = -ENODEV;
- /* find out devno of leaving device: CIO has already deleted this information ! */
- list_for_each(l,&dasd_major_info[0].list) {
- major_info=list_entry(l, major_info_t,list);
+ /* find out devno of leaving device: CIO has already deleted this information ! */
+ list_for_each (l, &dasd_major_info[0].list) {
+ major_info = list_entry (l, major_info_t, list);
for (i = 0; i < DASD_PER_MAJOR; i++) {
device = major_info->dasd_device[i];
- if (device &&
- device->devinfo.irq == irq) {
+ if (device && device->devinfo.irq == irq) {
devno = device->devinfo.devno;
break;
}
@@ -2392,360 +2835,561 @@
"not_oper_handler called on irq %d no devno!\n", irq);
return;
}
-
- if (device->open_count != 0) {
- DASD_MESSAGE(KERN_ALERT,device,"%s",
- "open device has gone. please repair!");
- dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSED,
- NULL, 0);
- } else {
- DASD_MESSAGE(KERN_INFO,device,"%s","device has gone");
- dasd_set_device_level (irq, DASD_DEVICE_LEVEL_UNKNOWN,
- NULL, 0);
- }
+ dasd_disable_volume(device, 0);
}
-static int
-dasd_enable_single_volume (int irq)
+int
+dasd_oper_handler (int irq, devreg_t * devreg)
{
+ int devno;
int rc = 0;
- dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ONLINE,
- NULL, 0);
- printk (KERN_INFO PRINTK_HEADER "waiting for response...\n");
- {
- static wait_queue_head_t wait_queue;
- init_waitqueue_head (&wait_queue);
- interruptible_sleep_on_timeout (&wait_queue, (5 * HZ) >> 1);
+ major_info_t *major_info = NULL;
+ dasd_range_t *rptr,range;
+ dasd_device_t *device = NULL;
+ struct list_head *l;
+ int i;
+
+ devno = get_devno_by_irq (irq);
+ if (devno == -ENODEV) {
+ rc = -ENODEV;
+ goto out;
}
- dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ONLINE, NULL, 0);
+ /* find out devno of leaving device: CIO has already deleted this information ! */
+ list_for_each (l, &dasd_major_info[0].list) {
+ major_info = list_entry (l, major_info_t, list);
+ for (i = 0; i < DASD_PER_MAJOR; i++) {
+ device = major_info->dasd_device[i];
+ if (device && device->devinfo.irq == irq) {
+ devno = device->devinfo.devno;
+ break;
+ }
+ }
+ if (devno != -ENODEV)
+ break;
+ }
+ if (devno < 0) {
+ BUG();
+ }
+ if ( device &&
+ device->level == DASD_STATE_READY ) {
+ dasd_set_device_level (device->devinfo.devno,
+ device->discipline, DASD_STATE_ONLINE);
+
+ } else {
+ if (dasd_autodetect) {
+ rptr = dasd_add_range (devno, devno, DASD_DEFAULT_FEATURES);
+ if ( rptr == NULL ) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ } else {
+ range.from = devno;
+ range.to = devno;
+ rptr = ⦥
+ }
+ dasd_enable_ranges (rptr, NULL, 0);
+ }
+ out:
return rc;
}
+#endif /* CONFIG_DASD_DYNAMIC */
+
+static inline dasd_device_t **
+dasd_find_device_addr ( int devno )
+{
+ dasd_device_t **device_addr;
+
+ DASD_DRIVER_DEBUG_EVENT (1, dasd_find_device_addr,
+ "devno %04X", devno);
+ if ( dasd_devindex_from_devno (devno) < 0 ) {
+ DASD_DRIVER_DEBUG_EXCEPTION (1, dasd_find_device_addr,
+ "no dasd: devno %04X",
+ devno);
+ return NULL;
+ }
+ /* allocate major numbers on demand for new devices */
+ while ((device_addr = dasd_device_from_devno (devno)) == NULL) {
+ int rc;
+
+ if ((rc = dasd_register_major (NULL)) <= 0) {
+
+ DASD_DRIVER_DEBUG_EXCEPTION (1, dasd_find_device_addr,
+ "%s",
+ "out of major numbers!");
+ break;
+ }
+ }
+ return device_addr;
+}
+
+static inline int
+dasd_state_del_to_new (dasd_device_t **addr )
+{
+ dasd_device_t* device;
+ int rc = 0;
+ if (*addr == NULL) { /* allocate device descriptor on demand for new device */
+ device = kmalloc (sizeof (dasd_device_t), GFP_ATOMIC);
+ if (device == NULL ) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ memset (device, 0, sizeof (dasd_device_t));
+ *addr = device;
+ device->lowmem_ccws = (void*)get_free_page (GFP_ATOMIC|GFP_DMA);
+ if (device->lowmem_ccws == NULL) {
+ rc = -ENOMEM;
+ goto noccw;
+ }
+#ifdef CONFIG_ARCH_S390X
+ device->lowmem_idals =
+ device->lowmem_idal_ptr = (void*) get_free_page (GFP_ATOMIC|GFP_DMA);
+ if (device->lowmem_idals == NULL) {
+ rc = -ENOMEM;
+ goto noidal;
+ }
+#endif
+}
+ goto out;
+ noidal:
+ free_page ((long) device->lowmem_ccws);
+ noccw:
+ kfree(device);
+ out:
+ return rc;
+}
+
+static inline int
+dasd_state_new_to_del (dasd_device_t **addr )
+{
+ dasd_device_t *device = *addr;
+ if (device && device->private) {
+ kfree(device->private);
+ device->private = NULL;
+ }
+#ifdef CONFIG_ARCH_S390X
+ free_page ((long)(device->lowmem_idals));
+#endif
+ free_page((long)(device->lowmem_ccws));
+ kfree(device);
+ *addr = NULL;
+ return 0;
+}
+
+static inline int
+dasd_state_new_to_known (dasd_device_t **dptr, int devno, dasd_discipline_t *disc)
+{
+ int rc = 0;
+ umode_t devfs_perm = S_IFBLK | S_IRUSR | S_IWUSR;
+ struct list_head *l;
+ major_info_t *major_info = NULL;
+ int i;
+ dasd_device_t *device = *dptr;
+ devfs_handle_t dir;
+ char buffer[5];
+
+
+ list_for_each (l, &dasd_major_info[0].list) {
+ major_info = list_entry (l, major_info_t, list);
+ for (i = 0; i < DASD_PER_MAJOR; i++) {
+ if (major_info->dasd_device[i] == device) {
+ device->kdev = MKDEV (major_info->gendisk.major,
+ i << DASD_PARTN_BITS);
+ break;
+ }
+ }
+ if (i < DASD_PER_MAJOR) /* we found one */
+ break;
+ }
+ if ( major_info == NULL || major_info == &dasd_major_info[0] )
+ BUG();
+
+ device->major_info = major_info;
+ dasd_device_name (device->name,
+ (((long)dptr -
+ (long)device->major_info->dasd_device) /
+ sizeof (dasd_device_t *)),
+ 0, &device->major_info->gendisk);
+ init_waitqueue_head (&device->wait_q);
+
+ rc = get_dev_info_by_devno (devno, &device->devinfo);
+ if ( rc ) {
+ goto out;
+ }
+ if ( devno != device->devinfo.devno )
+ BUG();
+ device->discipline = dasd_find_disc (device, disc);
+ if ( device->discipline == NULL ) {
+ rc = -ENODEV;
+ goto out;
+ }
+ sprintf (buffer, "%04x", device->devinfo.devno);
+ dir = devfs_mk_dir (dasd_devfs_handle, buffer, device);
+ device->major_info->gendisk.de_arr[MINOR(device->kdev)
+ >> DASD_PARTN_BITS] = dir;
+ if (dasd_features_from_devno(device->devinfo.devno)&DASD_FEATURE_READONLY) {
+ devfs_perm &= ~(S_IWUSR);
+ }
+ device->devfs_entry = devfs_register (dir,"device",DEVFS_FL_DEFAULT,
+ MAJOR(device->kdev),
+ MINOR(device->kdev),
+ devfs_perm,
+ &dasd_device_operations,NULL);
+ device->level = DASD_STATE_KNOWN;
+ out:
+ return rc;
+}
+
+static inline int
+dasd_state_known_to_new (dasd_device_t *device )
+{
+ int rc = 0;
+ /* don't reset to zeros because of persistent data durich detach/attach! */
+ devfs_unregister(device->devfs_entry);
+ devfs_unregister(device->major_info->gendisk.de_arr[MINOR(device->kdev) >> DASD_PARTN_BITS]);
+
+ return rc;
+}
+
+static inline int
+dasd_state_known_to_accept (dasd_device_t *device)
+{
+ int rc = 0;
+ device->debug_area = debug_register (device->name, 0, 2,
+ 3 * sizeof (long));
+ debug_register_view (device->debug_area, &debug_sprintf_view);
+ debug_register_view (device->debug_area, &debug_hex_ascii_view);
+ DASD_DEVICE_DEBUG_EVENT (0, device,"%p debug area created",device);
+
+ if (device->discipline->int_handler) {
+ rc = s390_request_irq_special (device->devinfo.irq,
+ device->discipline->int_handler,
+ dasd_not_oper_handler,
+ 0, DASD_NAME,
+ &device->dev_status);
+ if ( rc ) {
+ printk("No request IRQ\n");
+ goto out;
+ }
+ }
+ device->level = DASD_STATE_ACCEPT;
+ out:
+ return rc;
+}
+
+static inline int
+dasd_state_accept_to_known (dasd_device_t *device )
+{
+ if ( device->discipline == NULL )
+ goto out;
+ if (device->discipline->int_handler) {
+ free_irq (device->devinfo.irq, &device->dev_status);
+ }
+ DASD_DEVICE_DEBUG_EVENT (0, device,"%p debug area deleted",device);
+ if ( device->debug_area != NULL )
+ debug_unregister (device->debug_area);
+ device->discipline = NULL;
+ device->level = DASD_STATE_KNOWN;
+ out:
+ return 0;
+}
+
+static inline int
+dasd_state_accept_to_init (dasd_device_t *device)
+{
+ int rc = 0;
+ unsigned long flags;
+
+ if ( device->discipline->init_analysis ) {
+ device->init_cqr=device->discipline->init_analysis (device);
+ if ( device->init_cqr != NULL ) {
+ if ( device->discipline->start_IO == NULL )
+ BUG();
+ atomic_inc (&dasd_init_pending);
+ s390irq_spin_lock_irqsave (device->devinfo.irq,
+ flags);
+ rc = device->discipline->start_IO (device->init_cqr);
+ s390irq_spin_unlock_irqrestore(device->devinfo.irq,
+ flags);
+ if ( rc )
+ goto out;
+ device->level = DASD_STATE_INIT;
+ } else {
+ rc = -ENOMEM;
+ }
+ } else {
+ rc = dasd_state_init_to_ready ( device );
+ }
+ out:
+ return rc;
+}
+
+static inline int
+dasd_state_init_to_ready (dasd_device_t *device )
+{
+ int rc = 0;
+ if (device->discipline->do_analysis != NULL)
+ if ( device->discipline->do_analysis (device) == 0 )
+ switch (device->sizes.bp_block) {
+ case 512:
+ case 1024:
+ case 2048:
+ case 4096:
+ break;
+ default:
+ rc = -EMEDIUMTYPE;
+ }
+ if ( device->init_cqr ) {
+ atomic_dec(&dasd_init_pending);
+ device->init_cqr = NULL; /* This one is no longer needed */
+ }
+ device->level = DASD_STATE_READY;
+ return rc;
+}
+
+static inline int
+dasd_state_ready_to_accept (dasd_device_t *device )
+{
+ int rc = 0;
+ unsigned long flags;
+
+ if ( device->init_cqr != NULL ) {
+ if ( device->discipline->term_IO == NULL )
+ BUG();
+ s390irq_spin_lock_irqsave (device->devinfo.irq, flags);
+ device->discipline->term_IO (device->init_cqr);
+ s390irq_spin_unlock_irqrestore(device->devinfo.irq, flags);
+ atomic_dec (&dasd_init_pending);
+ dasd_free_request (device->init_cqr, device);
+ device->init_cqr = NULL;
+ }
+ memset(&device->sizes,0,sizeof(dasd_sizes_t));
+ device->level = DASD_STATE_ACCEPT;
+ return rc;
+}
+
+static inline int
+dasd_state_ready_to_online (dasd_device_t *device )
+{
+ int rc = 0;
+ dasd_unplug_device (device);
+ device->level = DASD_STATE_ONLINE;
+ return rc;
+}
+
+static inline int
+dasd_state_online_to_ready (dasd_device_t *device )
+{
+ int rc = 0;
+ dasd_plug_device (device);
+ device->level = DASD_STATE_READY;
+ return rc;
+}
+
+static inline int
+dasd_setup_blkdev (dasd_device_t *device )
+{
+ int rc = 0;
+ int i;
+ int major = MAJOR(device->kdev);
+ int minor = MINOR(device->kdev);
+
+ for (i = 0; i < (1 << DASD_PARTN_BITS); i++) {
+ if (i == 0)
+ device->major_info->gendisk.sizes[minor] =
+ (device->sizes.blocks << device->
+ sizes.s2b_shift) >> 1;
+ else
+ device->major_info->gendisk.sizes[minor + i] = 0;
+ hardsect_size[major][minor + i] = device->sizes.bp_block;
+ blksize_size[major][minor + i] = device->sizes.bp_block;
+ max_sectors[major][minor + i] =
+ device->discipline->max_blocks <<
+ device->sizes.s2b_shift;
+ device->major_info->gendisk.part[minor+i].start_sect = 0;
+ device->major_info->gendisk.part[minor+i].nr_sects = 0;
+ }
+ device->request_queue = kmalloc(sizeof(request_queue_t),GFP_KERNEL);
+ device->request_queue->queuedata = device;
+ blk_init_queue (device->request_queue, do_dasd_request);
+ blk_queue_headactive (device->request_queue, 0);
+ elevator_init (&(device->request_queue->elevator),ELEVATOR_NOOP);
+ return rc;
+}
+
+static inline int
+dasd_disable_blkdev (dasd_device_t *device )
+{
+ int i;
+ int major = MAJOR(device->kdev);
+ int minor = MINOR(device->kdev);
+
+ for (i = 0; i < (1 << DASD_PARTN_BITS); i++) {
+ destroy_buffers(MKDEV(major,minor+i));
+ device->major_info->gendisk.sizes[minor + i] = 0;
+ hardsect_size[major][minor + i] = 0;
+ blksize_size[major][minor + i] = 0;
+ max_sectors[major][minor + i] = 0;
+ }
+ if (device->request_queue) {
+ blk_cleanup_queue (device->request_queue);
+ kfree(device->request_queue);
+ device->request_queue = NULL;
+ }
+ return 0;
+}
+
+
+/*
+ * function dasd_setup_partitions
+ * calls the function in genhd, which is appropriate to setup a partitioned disk
+ */
+static inline void
+dasd_setup_partitions ( dasd_device_t * device )
+{
+ register_disk (&device->major_info->gendisk,
+ device->kdev,
+ 1 << DASD_PARTN_BITS,
+ &dasd_device_operations,
+ (device->sizes.blocks << device->sizes.s2b_shift));
+}
-int
-dasd_oper_handler (int irq, devreg_t * devreg)
+static inline void
+dasd_destroy_partitions ( dasd_device_t * device )
{
- int devno;
- int rc;
- devno = get_devno_by_irq (irq);
- printk (KERN_WARNING PRINTK_HEADER "Oper handler called\n");
- if (devno == -ENODEV) {
- printk (KERN_WARNING PRINTK_HEADER "NODEV\n");
- return -ENODEV;
+ int i;
+ int major = MAJOR(device->kdev);
+ int minor = MINOR(device->kdev);
+
+ for (i = 0; i < (1 << DASD_PARTN_BITS); i++) {
+ device->major_info->gendisk.part[minor+i].start_sect = 0;
+ device->major_info->gendisk.part[minor+i].nr_sects = 0;
}
- if (dasd_autodetect) {
- dasd_add_range (devno, 0);
- }
- rc = dasd_enable_single_volume (irq);
- return rc;
+ devfs_register_partitions(&device->major_info->gendisk,
+ MINOR(device->kdev),1);
}
-#endif /* CONFIG_DASD_DYNAMIC */
-/*
- * function dasd_set_device_level
+static inline void
+dasd_resetup_partitions ( dasd_device_t * device )
+{
+ BUG();
+ dasd_destroy_partitions ( device ) ;
+ dasd_setup_partitions ( device ) ;
+}
+
+/*
+ * function dasd_set_device_level
*/
static int
-dasd_set_device_level (unsigned int irq, int desired_level,
- dasd_discipline_t * discipline, int flags)
+dasd_set_device_level (unsigned int devno,
+ dasd_discipline_t * discipline,
+ int to_state)
{
int rc = 0;
- int devno;
- dasd_device_t **device_addr, *device;
- int current_level;
- major_info_t *major_info = NULL;
- struct list_head *l;
- int i, minor, major;
- ccw_req_t *cqr = NULL;
- struct gendisk *dd;
+ dasd_device_t **device_addr;
+ dasd_device_t *device;
+ int from_state;
- devno = get_devno_by_irq (irq);
- if (devno < 0) { /* e.g. when device has been detached before */
- /* search in device list */
- list_for_each(l,&dasd_major_info[0].list) {
- major_info = list_entry(l,major_info_t,list);
- for (i = 0; i < DASD_PER_MAJOR; i++) {
- device = major_info->dasd_device[i];
- if (device && device->devinfo.irq == irq) {
- devno = device->devinfo.devno;
- break;
- }
- }
- if (devno == -ENODEV)
- return -ENODEV;
- }
- }
- if (dasd_devindex_from_devno (devno) < 0) {
- return -ENODEV;
- }
- while ((device_addr = dasd_device_from_devno (devno)) == NULL) {
- if ((rc = dasd_register_major (NULL)) > 0) {
- printk (KERN_INFO PRINTK_HEADER
- "Registered to major number: %u\n", rc);
- } else {
- printk (KERN_WARNING PRINTK_HEADER
- "Couldn't register to another major no\n");
- return -ERANGE;
- }
- }
- device = *device_addr;
- if (!device) { /* allocate device descriptor */
- device = kmalloc (sizeof (dasd_device_t), GFP_ATOMIC);
- if (!device) {
- printk (KERN_WARNING PRINTK_HEADER " No memory for device descriptor\n");
- goto nomem;
- }
- memset (device, 0, sizeof (dasd_device_t));
- *device_addr = device;
- }
- list_for_each(l,&dasd_major_info[0].list) {
- int i;
- major_info = list_entry(l,major_info_t,list);
- for (i = 0; i < DASD_PER_MAJOR; i++) {
- if (major_info->dasd_device[i] == device) {
- device->kdev = MKDEV (major_info->gendisk.major, i << DASD_PARTN_BITS);
- break;
- }
- }
- if (i < DASD_PER_MAJOR)
- break;
- }
- if (major_info == &dasd_major_info[0]) {
- return -ENODEV;
- }
- minor = MINOR (device->kdev);
- major = MAJOR (device->kdev);
- current_level = device->level;
- if (desired_level > current_level) {
- switch (current_level) {
- case DASD_DEVICE_LEVEL_UNKNOWN: /* Find a discipline */
- device->major_info = major_info;
- dasd_device_name (device->name,
- ((long) device_addr -
- (long) device->major_info->dasd_device) /
- sizeof (dasd_device_t *),
- 0, &major_info->gendisk);
- rc = get_dev_info_by_irq (irq, &device->devinfo);
- if (rc < 0) {
- break;
- }
- discipline = dasd_find_discipline (device);
- if (discipline && !rc) {
- DASD_MESSAGE (KERN_INFO, device,
- "%s", " ");
- } else {
- break;
- }
- device->discipline = discipline;
- device->debug_area = debug_register(device->name,0,2,3*sizeof(long));
- debug_register_view(device->debug_area,&debug_sprintf_view);
- debug_register_view(device->debug_area,&debug_hex_ascii_view);
- if (device->discipline->int_handler) {
-#ifdef CONFIG_DASD_DYNAMIC
- s390_request_irq_special (irq,
- device->discipline->int_handler,
- dasd_not_oper_handler,
- 0,
- DASD_NAME,
- &device->dev_status);
-#else /* !defined(CONFIG_DASD_DYNAMIC) */
- request_irq (irq,
- device->discipline->int_handler,
- 0,
- DASD_NAME,
- &device->dev_status);
-#endif /* CONFIG_DASD_DYNAMIC */
- }
- device->proc_dir = (struct proc_dir_entry *)
- kmalloc (sizeof (struct proc_dir_entry), GFP_KERNEL);
- if (device->proc_dir) {
- memset (device->proc_dir, 0, sizeof (struct proc_dir_entry));
- device->proc_info = (struct proc_dir_entry *)
- kmalloc (sizeof (struct proc_dir_entry), GFP_KERNEL);
- if (device->proc_info) {
- memset (device->proc_info, 0,
- sizeof (struct proc_dir_entry));
- }
- device->proc_stats = (struct proc_dir_entry *)
- kmalloc (sizeof (struct proc_dir_entry), GFP_KERNEL);
- if (device->proc_stats) {
- memset (device->proc_stats, 0,
- sizeof (struct proc_dir_entry));
- }
- }
- init_waitqueue_head (&device->wait_q);
- check_then_set (&device->level,
- DASD_DEVICE_LEVEL_UNKNOWN,
- DASD_DEVICE_LEVEL_RECOGNIZED);
- if (desired_level == DASD_DEVICE_LEVEL_RECOGNIZED)
- break;
- case DASD_DEVICE_LEVEL_RECOGNIZED: /* Fallthrough ?? */
- if (device->discipline->init_analysis) {
- cqr = device->discipline->init_analysis (device);
- if (cqr != NULL) {
- dasd_chanq_enq (&device->queue, cqr);
- if (device->discipline->start_IO) {
- long flags;
- s390irq_spin_lock_irqsave (irq, flags);
- device->discipline->start_IO (cqr);
- check_then_set (&device->level,
- DASD_DEVICE_LEVEL_RECOGNIZED,
- DASD_DEVICE_LEVEL_ANALYSIS_PENDING);
- s390irq_spin_unlock_irqrestore (irq, flags);
- }
- }
- } else {
- check_then_set (&device->level, DASD_DEVICE_LEVEL_RECOGNIZED,
- DASD_DEVICE_LEVEL_ANALYSIS_PREPARED);
- }
- if (desired_level >= DASD_DEVICE_LEVEL_ANALYSIS_PENDING)
- break;
- case DASD_DEVICE_LEVEL_ANALYSIS_PENDING: /* Fallthrough ?? */
- return -EAGAIN;
- case DASD_DEVICE_LEVEL_ANALYSIS_PREPARED: /* Re-entering here ! */
- if (device->discipline->do_analysis)
- if (device->discipline->do_analysis (device))
- return -ENODEV;
- switch (device->sizes.bp_block) {
- case 512:
- case 1024:
- case 2048:
- case 4096:
- break;
- default:
- {
- printk (KERN_INFO PRINTK_HEADER
- "/dev/%s (devno 0x%04X): Detected invalid blocksize of %d bytes"
- " Did you format the drive?\n",
- device->name, devno, device->sizes.bp_block);
- return -EMEDIUMTYPE;
- }
- }
- blk_init_queue (&device->request_queue, do_dasd_request);
- blk_queue_headactive (&device->request_queue, 0);
- elevator_init(&device->request_queue.elevator, ELEVATOR_NOOP);
- for (i = 0; i < (1 << DASD_PARTN_BITS); i++) {
- if (i == 0)
- blk_size[major][minor] = (device->sizes.blocks << device->sizes.s2b_shift) >> 1;
- else
- blk_size[major][minor + i] = 0;
- hardsect_size[major][minor + i] = device->sizes.bp_block;
- blksize_size[major][minor + i] = device->sizes.bp_block;
- if (blksize_size[major][minor + i] < 1024)
- blksize_size[major][minor + i] = 1024;
-
- max_sectors[major][minor + i] =
- device->discipline->max_blocks << device->sizes.s2b_shift;
- }
- check_then_set (&device->level,
- DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
- DASD_DEVICE_LEVEL_ANALYSED);
- dd = &major_info->gendisk;
- dd->sizes[minor] = (device->sizes.blocks <<
- device->sizes.s2b_shift) >> 1;
- dd->part[minor].start_sect = 0;
- {
- char buffer[5];
- sprintf(buffer,"%04X",device->devinfo.devno);
- dd->de_arr[minor>>DASD_PARTN_BITS] = devfs_mk_dir(dasd_devfs_handle,buffer,NULL);
- }
-#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-#ifndef MODULE
- if (flags & 0x80)
+ device_addr = dasd_find_device_addr ( devno );
+ if ( device_addr == NULL ) {
+ rc = -ENODEV;
+ goto out;
+ }
+ device = *device_addr;
+
+ if ( device == NULL ) {
+ from_state = DASD_STATE_DEL;
+ if ( to_state == DASD_STATE_DEL )
+ goto out;
+ } else {
+ from_state = device->level;
+ }
+
+ if ( from_state == to_state )
+ goto out;
+
+ if ( to_state < from_state )
+ goto shutdown;
+
+ /* First check for bringup */
+ if ( from_state <= DASD_STATE_DEL &&
+ to_state >= DASD_STATE_NEW ) {
+ rc = dasd_state_del_to_new(device_addr);
+ if ( rc ) {
+ goto bringup_fail;
+ }
+ device = *device_addr;
+ }
+ if ( from_state <= DASD_STATE_NEW &&
+ to_state >= DASD_STATE_KNOWN ) {
+ rc = dasd_state_new_to_known( device_addr, devno, discipline );
+ if ( rc ) {
+ goto bringup_fail;
+ }
+ }
+ if ( from_state <= DASD_STATE_KNOWN &&
+ to_state >= DASD_STATE_ACCEPT ) {
+ rc = dasd_state_known_to_accept(device);
+ if ( rc ) {
+ goto bringup_fail;
+ }
+ }
+ if ( dasd_probeonly ) {
+ goto out;
+ }
+ if ( from_state <= DASD_STATE_ACCEPT &&
+ to_state >= DASD_STATE_INIT ) {
+ rc = dasd_state_accept_to_init(device);
+ if ( rc ) {
+ goto bringup_fail;
+ }
+ }
+ if ( from_state <= DASD_STATE_INIT &&
+ to_state >= DASD_STATE_READY ) {
+ rc = -EAGAIN;
+ goto out;
+ }
+ if ( from_state <= DASD_STATE_READY &&
+ to_state >= DASD_STATE_ONLINE ) {
+ rc = dasd_state_ready_to_online(device);
+ if ( rc ) {
+ goto bringup_fail;
+ }
+ }
+ goto out;
+ bringup_fail: /* revert changes */
+#if 0
+ printk (KERN_DEBUG PRINTK_HEADER
+ "failed to set device from state %d to %d at level %d rc %d. Reverting...\n",
+ from_state,to_state,device->level,rc);
#endif
-#endif /* KERNEL_VERSION */
- dasd_partn_detect (device);
- if (desired_level == DASD_DEVICE_LEVEL_ANALYSED)
- break;
- case DASD_DEVICE_LEVEL_ANALYSED: /* Fallthrough ?? */
- dasd_unplug_device(device);
- check_then_set (&device->level,
- DASD_DEVICE_LEVEL_ANALYSED,
- DASD_DEVICE_LEVEL_ONLINE);
-
- if (desired_level == DASD_DEVICE_LEVEL_ONLINE)
- break;
- case DASD_DEVICE_LEVEL_ONLINE:
- break;
- default:
- printk (KERN_WARNING PRINTK_HEADER
- "Internal error in " __FILE__ " on line %d."
- " validate_dasd called from %p with "
- " desired_level = %d, current_level =%d"
- " Pls send this message and your System.map to"
- " linux390@de.ibm.com\n",
- __LINE__, __builtin_return_address (0),
- desired_level, current_level);
- break;
- }
- } else if (desired_level < current_level) { /* donwgrade device status */
- switch (current_level) {
- case DASD_DEVICE_LEVEL_ONLINE: /* Fallthrough ?? */
- dasd_plug_device(device);
- check_then_set (&device->level,
- DASD_DEVICE_LEVEL_ONLINE,
- DASD_DEVICE_LEVEL_ANALYSED);
- if (desired_level == DASD_DEVICE_LEVEL_ANALYSED)
- break;
- case DASD_DEVICE_LEVEL_ANALYSED: /* Fallthrough ?? */
- for (i = 0; i < (1 << DASD_PARTN_BITS); i++) {
- __invalidate_buffers(MKDEV(major,minor),1);
- blk_size[major][minor] = 0;
- hardsect_size[major][minor + i] = 0;
- blksize_size[major][minor + i] = 0;
- max_sectors[major][minor + i] = 0;
- }
- memset (&device->sizes, 0, sizeof (dasd_sizes_t));
- blk_cleanup_queue (&device->request_queue);
- check_then_set (&device->level,
- DASD_DEVICE_LEVEL_ANALYSED,
- DASD_DEVICE_LEVEL_ANALYSIS_PREPARED);
- if (desired_level == DASD_DEVICE_LEVEL_ANALYSIS_PREPARED)
- break;
- case DASD_DEVICE_LEVEL_ANALYSIS_PREPARED:
- check_then_set (&device->level,
- DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
- DASD_DEVICE_LEVEL_ANALYSIS_PENDING);
- if (desired_level == DASD_DEVICE_LEVEL_ANALYSIS_PENDING)
- break;
- case DASD_DEVICE_LEVEL_ANALYSIS_PENDING: /* Fallthrough ?? */
- check_then_set (&device->level,
- DASD_DEVICE_LEVEL_ANALYSIS_PENDING,
- DASD_DEVICE_LEVEL_RECOGNIZED);
- if (desired_level == DASD_DEVICE_LEVEL_RECOGNIZED)
- break;
- case DASD_DEVICE_LEVEL_RECOGNIZED: /* Fallthrough ?? */
- if (device->discipline->int_handler) {
- free_irq (irq, &device->dev_status);
- }
- device->discipline = NULL;
- debug_unregister(device->debug_area);
- check_then_set (&device->level,
- DASD_DEVICE_LEVEL_RECOGNIZED,
- DASD_DEVICE_LEVEL_UNKNOWN);
- *device_addr = NULL;
- kfree(device);
- if (desired_level == DASD_DEVICE_LEVEL_UNKNOWN)
- break;
- case DASD_DEVICE_LEVEL_UNKNOWN:
- break;
- default:
- printk (KERN_WARNING PRINTK_HEADER
- "Internal error in " __FILE__ " on line %d."
- " validate_dasd called from %p with "
- " desired_level = %d, current_level =%d"
- " Pls send this message and your System.map to"
- " linux390@de.ibm.com\n",
- __LINE__, __builtin_return_address (0),
- desired_level, current_level);
- break;
- }
- }
- if (rc) {
- goto exit;
- }
- nomem:
- rc = -ENOMEM;
- exit:
- return 0;
+ to_state = from_state;
+ from_state = device->level;
+
+ /* now do a shutdown */
+ shutdown:
+ if ( from_state >= DASD_STATE_ONLINE &&
+ to_state <= DASD_STATE_READY )
+ if (dasd_state_online_to_ready(device))
+ BUG();
+ if ( from_state >= DASD_STATE_READY &&
+ to_state <= DASD_STATE_ACCEPT )
+ if ( dasd_state_ready_to_accept(device))
+ BUG();
+ if ( from_state >= DASD_STATE_ACCEPT &&
+ to_state <= DASD_STATE_KNOWN )
+ if ( dasd_state_accept_to_known(device))
+ BUG();
+ if ( from_state >= DASD_STATE_KNOWN &&
+ to_state <= DASD_STATE_NEW )
+ if ( dasd_state_known_to_new(device))
+ BUG();
+ if ( from_state >= DASD_STATE_NEW &&
+ to_state <= DASD_STATE_DEL)
+ if (dasd_state_new_to_del(device_addr))
+ BUG();
+ goto out;
+ out:
+ return rc;
}
/* SECTION: Procfs stuff */
@@ -2754,29 +3398,16 @@
int len;
} tempinfo_t;
-void dasd_fill_inode (struct inode* inode, int fill) {
- if (fill)
- MOD_INC_USE_COUNT;
- else
- MOD_DEC_USE_COUNT;
+void
+dasd_fill_inode (struct inode *inode, int fill)
+{
+ if (fill)
+ MOD_INC_USE_COUNT;
+ else
+ MOD_DEC_USE_COUNT;
}
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
static struct proc_dir_entry *dasd_proc_root_entry = NULL;
-#else
-static struct proc_dir_entry dasd_proc_root_entry =
-{
- low_ino:0,
- namelen:4,
- name:"dasd",
- mode:S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR | S_IWGRP,
- nlink:1,
- uid:0,
- gid:0,
- size:0,
- fill_inode:dasd_fill_inode
-};
-#endif /* KERNEL_VERSION */
static struct proc_dir_entry *dasd_devices_entry;
static struct proc_dir_entry *dasd_statistics_entry;
@@ -2786,94 +3417,138 @@
int rc = 0;
int size = 1;
int len = 0;
- major_info_t *temp = dasd_major_info;
+ major_info_t *temp = NULL;
struct list_head *l;
tempinfo_t *info;
int i;
+ unsigned long flags;
+ int index = 0;
+ MOD_INC_USE_COUNT;
+ spin_lock_irqsave(&discipline_lock,flags);
info = (tempinfo_t *) vmalloc (sizeof (tempinfo_t));
if (info == NULL) {
- printk (KERN_WARNING "No memory available for data\n");
- return -ENOMEM;
+ printk (KERN_WARNING "No memory available for data\n");
+ MOD_DEC_USE_COUNT;
+ return -ENOMEM;
} else {
file->private_data = (void *) info;
}
- list_for_each(l,&dasd_major_info[0].list) {
- temp = list_entry(l,major_info_t,list);
- for (i = 0; i < 1 << (MINORBITS - DASD_PARTN_BITS); i++) {
- dasd_device_t *device = temp->dasd_device[i];
- if (device) {
- size += 128;
- }
- }
+ list_for_each (l, &dasd_major_info[0].list) {
+ size += 128 * 1 << (MINORBITS - DASD_PARTN_BITS);
}
- temp = dasd_major_info;
- info->data = (char *) vmalloc (size); /* FIXME! determine space needed in a better way */
+ info->data = (char *) vmalloc (size);
+ DASD_DRIVER_DEBUG_EVENT (1, dasd_devices_open, "area: %p, size 0x%x",
+ info->data, size);
if (size && info->data == NULL) {
printk (KERN_WARNING "No memory available for data\n");
vfree (info);
+ MOD_DEC_USE_COUNT;
return -ENOMEM;
}
- list_for_each(l,&dasd_major_info[0].list) {
- temp = list_entry(l,major_info_t,list);
+ list_for_each (l, &dasd_major_info[0].list) {
+ temp = list_entry (l, major_info_t, list);
for (i = 0; i < 1 << (MINORBITS - DASD_PARTN_BITS); i++) {
- dasd_device_t *device = temp->dasd_device[i];
+ dasd_device_t *device;
+ int devno = dasd_devno_from_devindex(index+i);
+ if ( devno == -ENODEV )
+ continue;
+ device = temp->dasd_device[i];
if (device) {
len += sprintf (info->data + len,
- "%04X(%s) at (%d:%d) is %7s:",
+ "%04X(%s) at (%3d:%3d) is %7s:",
device->devinfo.devno,
- device->discipline ? device->discipline->name : "none",
- temp->gendisk.major, i << DASD_PARTN_BITS,
+ device->discipline ?
+ device->
+ discipline->name : "none",
+ temp->gendisk.major,
+ i << DASD_PARTN_BITS,
device->name);
switch (device->level) {
- case DASD_DEVICE_LEVEL_UNKNOWN:
- len += sprintf (info->data + len, "unknown\n");
- break;
- case DASD_DEVICE_LEVEL_RECOGNIZED:
- len += sprintf (info->data + len, "passive");
- len += sprintf (info->data + len, " at blocksize: %d, %ld blocks, %ld MB\n",
- device->sizes.bp_block,
- device->sizes.blocks,
- ((device->sizes.bp_block >> 9) * device->sizes.blocks) >> 11);
+ case DASD_STATE_NEW:
+ len +=
+ sprintf (info->data + len,
+ "new");
+ break;
+ case DASD_STATE_KNOWN:
+ len +=
+ sprintf (info->data + len,
+ "detected");
break;
- case DASD_DEVICE_LEVEL_ANALYSIS_PENDING:
- len += sprintf (info->data + len, "busy \n");
+ case DASD_STATE_ACCEPT:
+ len += sprintf (info->data + len,"accepted");
break;
- case DASD_DEVICE_LEVEL_ANALYSIS_PREPARED:
- len += sprintf (info->data + len, "n/f \n");
+ case DASD_STATE_INIT:
+ len +=
+ sprintf (info->data + len,
+ "busy ");
break;
- case DASD_DEVICE_LEVEL_ANALYSED:
- len += sprintf (info->data + len, "active ");
- len += sprintf (info->data + len, " at blocksize: %d, %ld blocks, %ld MB\n",
- device->sizes.bp_block,
- device->sizes.blocks,
- ((device->sizes.bp_block >> 9) * device->sizes.blocks) >> 11);
- break;
- case DASD_DEVICE_LEVEL_ONLINE:
- len += sprintf (info->data + len, "active ");
- len += sprintf (info->data + len, " at blocksize: %d, %ld blocks, %ld MB\n",
- device->sizes.bp_block,
- device->sizes.blocks,
- ((device->sizes.bp_block >> 9) * device->sizes.blocks) >> 11);
+ case DASD_STATE_READY:
+ case DASD_STATE_ONLINE:
+ if ( atomic_read(&device->plugged) )
+ len +=
+ sprintf (info->data + len,
+ "fenced ");
+ else
+ len +=
+ sprintf (info->data + len,
+ "active ");
+ if ( device->sizes.bp_block == 512 ||
+ device->sizes.bp_block == 1024 ||
+ device->sizes.bp_block == 2048 ||
+ device->sizes.bp_block == 4096 )
+ len +=
+ sprintf (info->data + len,
+ "at blocksize: %d, %ld blocks, %ld MB",
+ device->sizes.bp_block,
+ device->sizes.blocks,
+ ((device->
+ sizes.bp_block >> 9) *
+ device->sizes.
+ blocks) >> 11);
+ else
+ len +=
+ sprintf (info->data + len,
+ "n/f ");
break;
default:
- len += sprintf (info->data + len, "no stat\n");
+ len +=
+ sprintf (info->data + len,
+ "no stat");
break;
}
- }
+ } else {
+ char buffer[7];
+ dasd_device_name (buffer, i, 0, &temp->gendisk);
+ if ( devno < 0 ) {
+ len += sprintf (info->data + len,
+ "none");
+ } else {
+ len += sprintf (info->data + len,
+ "%04X",devno);
+ }
+ len += sprintf (info->data + len,
+ "(none) at (%3d:%3d) is %7s: unknown",
+ temp->gendisk.major,
+ i << DASD_PARTN_BITS,
+ buffer);
+ }
+ if ( dasd_probeonly )
+ len += sprintf(info->data + len,"(probeonly)");
+ len += sprintf(info->data + len,"\n");
}
+ index += 1 << (MINORBITS - DASD_PARTN_BITS);
}
info->len = len;
-#ifdef MODULE
- MOD_INC_USE_COUNT;
-#endif
+ spin_unlock_irqrestore(&discipline_lock,flags);
return rc;
}
#define MIN(a,b) ((a)<(b)?(a):(b))
static ssize_t
-dasd_devices_read (struct file *file, char *user_buf, size_t user_len, loff_t * offset)
+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;
@@ -2890,85 +3565,68 @@
}
static ssize_t
-dasd_devices_write (struct file *file, const char *user_buf, size_t user_len, loff_t * offset)
+dasd_devices_write (struct file *file, const char *user_buf,
+ size_t user_len, loff_t * offset)
{
char *buffer = vmalloc (user_len+1);
int off = 0;
char *temp;
- int irq;
- int j,target;
- dasd_range_t *rptr, range;
+ dasd_range_t range;
+ int features = 0;
if (buffer == NULL)
return -ENOMEM;
if (copy_from_user (buffer, user_buf, user_len)) {
- vfree(buffer);
+ vfree (buffer);
return -EFAULT;
}
buffer[user_len] = 0;
- printk (KERN_INFO PRINTK_HEADER "Now executing %s\n", buffer);
- if (strncmp ( buffer, "set ",4) &&
- strncmp ( buffer, "add ",4)){
- printk (KERN_WARNING PRINTK_HEADER
- "/proc/dasd/devices: only 'set' and 'add' are supported verbs");
- return -EINVAL;
- }
- off += 4;
- while (!isalnum(buffer[off])) off++;
+ printk (KERN_INFO PRINTK_HEADER "/proc/dasd/devices: '%s'\n", buffer);
+ if (strncmp (buffer, "set ", 4) && strncmp (buffer, "add ", 4)) {
+ printk (KERN_WARNING PRINTK_HEADER
+ "/proc/dasd/devices: only 'set' and 'add' are supported verbs\n");
+ return -EINVAL;
+ }
+ off += 4;
+ while (buffer[off] && !isalnum (buffer[off]))
+ off++;
if (!strncmp (buffer + off, "device", strlen ("device"))) {
- off += strlen("device");
- while (!isalnum(buffer[off])) off++;
- }
+ off += strlen ("device");
+ while (buffer[off] && !isalnum (buffer[off]))
+ off++;
+ }
if (!strncmp (buffer + off, "range=", strlen ("range="))) {
- off += strlen("range=");
- while (!isalnum(buffer[off])) off++;
- }
- temp = buffer+off;
- range.from = dasd_strtoul (temp, &temp);
- range.to = range.from;
- if (*temp == '-') {
- temp++;
- range.to = dasd_strtoul (temp, &temp);
- }
- off = (long)temp - (long)buffer;
- if ( !strncmp ( buffer, "add",strlen("add"))) {
- rptr = dasd_add_range (range.from, range.to);
- } else {
- rptr = ⦥
- }
- while (!isalnum(buffer[off])) off++;
- printk (KERN_INFO PRINTK_HEADER
- "varying device range %04X-%04X\n", rptr->from, rptr->to);
- if ( !strncmp ( buffer, "add",strlen("add")) ||
- !strncmp ( buffer+off, "on",strlen("on")) ) {
- target = DASD_DEVICE_LEVEL_ONLINE;
- for (j = rptr->from; j <= rptr->to; j++) {
- irq = get_irq_by_devno (j);
- if (irq >= 0) {
- dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ONLINE, NULL, 0);
- }
- }
- printk (KERN_INFO PRINTK_HEADER "waiting for responses...\n");
- {
- static wait_queue_head_t wait_queue;
- init_waitqueue_head (&wait_queue);
- interruptible_sleep_on_timeout (&wait_queue, (5 * HZ) );
+ off += strlen ("range=");
+ while (buffer[off] && !isalnum (buffer[off]))
+ off++;
+ }
+
+ temp = buffer + off;
+ range.from = dasd_strtoul (temp, &temp, &features);
+ range.to = range.from;
+
+ if (*temp == '-') {
+ temp++;
+ range.to = dasd_strtoul (temp, &temp, &features);
+ }
+
+ off = (long) temp - (long) buffer;
+ if (!strncmp (buffer, "add", strlen ("add"))) {
+ dasd_add_range (range.from, range.to, features);
+ dasd_enable_ranges (&range, NULL, 0);
+ } else {
+ while (buffer[off] && !isalnum (buffer[off]))
+ off++;
+ if (!strncmp (buffer + off, "on", strlen ("on"))) {
+ dasd_enable_ranges (&range, NULL, 0);
+ } else if (!strncmp (buffer + off, "off", strlen ("off"))) {
+ dasd_disable_ranges (&range, NULL, 0, 1);
+ } else {
+ printk (KERN_WARNING PRINTK_HEADER
+ "/proc/dasd/devices: parse error in '%s'", buffer);
}
- } else if ( !strncmp ( buffer+off, "off",strlen("off"))) {
- target = DASD_DEVICE_LEVEL_UNKNOWN;
- } else {
- printk (KERN_WARNING PRINTK_HEADER
- "/proc/dasd/devices: parse error in '%s'", buffer);
- vfree (buffer);
- return -EINVAL;
-
- }
- for (j = rptr->from; j <= rptr->to; j++) {
- irq = get_irq_by_devno (j);
- if (irq >= 0) {
- dasd_set_device_level (irq, target, NULL, 0);
- }
- }
+ }
+ vfree (buffer);
return user_len;
}
@@ -2982,25 +3640,18 @@
vfree (p_info->data);
vfree (p_info);
}
-#ifdef MODULE
- MOD_DEC_USE_COUNT;
-#endif
+ MOD_DEC_USE_COUNT;
return rc;
}
-static struct file_operations dasd_devices_file_ops =
-{
- read:dasd_devices_read, /* read */
+static struct file_operations dasd_devices_file_ops = {
+ read:dasd_generic_read, /* read */
write:dasd_devices_write, /* write */
open:dasd_devices_open, /* open */
release:dasd_devices_close, /* close */
};
-static struct inode_operations dasd_devices_inode_ops =
-{
-#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
- default_file_ops:&dasd_devices_file_ops /* file ops */
-#endif /* LINUX_IS_24 */
+static struct inode_operations dasd_devices_inode_ops = {
};
static int
@@ -3011,9 +3662,11 @@
tempinfo_t *info;
int shift, i, help = 0;
+ MOD_INC_USE_COUNT;
info = (tempinfo_t *) vmalloc (sizeof (tempinfo_t));
if (info == NULL) {
printk (KERN_WARNING "No memory available for data\n");
+ MOD_DEC_USE_COUNT;
return -ENOMEM;
} else {
file->private_data = (void *) info;
@@ -3023,99 +3676,154 @@
printk (KERN_WARNING "No memory available for data\n");
vfree (info);
file->private_data = NULL;
+ MOD_DEC_USE_COUNT;
return -ENOMEM;
}
for (shift = 0, help = dasd_global_profile.dasd_io_reqs;
- help > 8192;
- help = help >> 1, shift++) ;
- len = sprintf (info->data, "%ld dasd I/O requests\n", dasd_global_profile.dasd_io_reqs);
- len += sprintf (info->data + len, "__<4 ___8 __16 __32 __64 _128 _256 _512 __1k __2k __4k __8k _16k _32k _64k 128k\n");
- len += sprintf (info->data + len, "_256 _512 __1M __2M __4M __8M _16M _32M _64M 128M 256M 512M __1G __2G __4G _>4G\n");
+ help > 8192; help = help >> 1, shift++) ;
+ len =
+ sprintf (info->data, "%d dasd I/O requests\n",
+ dasd_global_profile.dasd_io_reqs);
+ len +=
+ sprintf (info->data + len, "with %d sectors(512B each)\n",
+ dasd_global_profile.dasd_io_sects);
+ len +=
+ sprintf (info->data + len,
+ "__<4 ___8 __16 __32 __64 _128 _256 _512 __1k __2k __4k __8k _16k _32k _64k 128k\n");
+ len +=
+ sprintf (info->data + len,
+ "_256 _512 __1M __2M __4M __8M _16M _32M _64M 128M 256M 512M __1G __2G __4G _>4G\n");
len += sprintf (info->data + len, "Histogram of sizes (512B secs)\n");
for (i = 0; i < 16; i++) {
- len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_secs[i] >> shift);
+ len +=
+ sprintf (info->data + len, "%4d ",
+ dasd_global_profile.dasd_io_secs[i] >> shift);
}
len += sprintf (info->data + len, "\n");
len += sprintf (info->data + len, "Histogram of I/O times\n");
for (i = 0; i < 16; i++) {
- len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_times[i] >> shift);
+ len +=
+ sprintf (info->data + len, "%4d ",
+ dasd_global_profile.dasd_io_times[i] >> shift);
}
len += sprintf (info->data + len, "\n");
for (; i < 32; i++) {
- len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_times[i] >> shift);
+ len +=
+ sprintf (info->data + len, "%4d ",
+ dasd_global_profile.dasd_io_times[i] >> shift);
}
len += sprintf (info->data + len, "\n");
- len += sprintf (info->data + len, "Histogram of I/O times per sector\n");
+ len +=
+ sprintf (info->data + len, "Histogram of I/O times per sector\n");
for (i = 0; i < 16; i++) {
- len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_timps[i] >> shift);
+ len +=
+ sprintf (info->data + len, "%4d ",
+ dasd_global_profile.dasd_io_timps[i] >> shift);
}
len += sprintf (info->data + len, "\n");
for (; i < 32; i++) {
- len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_timps[i] >> shift);
+ len +=
+ sprintf (info->data + len, "%4d ",
+ dasd_global_profile.dasd_io_timps[i] >> shift);
}
len += sprintf (info->data + len, "\n");
len += sprintf (info->data + len, "Histogram of I/O time till ssch\n");
for (i = 0; i < 16; i++) {
- len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_time1[i] >> shift);
+ len +=
+ sprintf (info->data + len, "%4d ",
+ dasd_global_profile.dasd_io_time1[i] >> shift);
}
len += sprintf (info->data + len, "\n");
for (; i < 32; i++) {
- len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_time1[i] >> shift);
+ len +=
+ sprintf (info->data + len, "%4d ",
+ dasd_global_profile.dasd_io_time1[i] >> shift);
}
len += sprintf (info->data + len, "\n");
- len += sprintf (info->data + len, "Histogram of I/O time between ssch and irq\n");
+ len +=
+ sprintf (info->data + len,
+ "Histogram of I/O time between ssch and irq\n");
for (i = 0; i < 16; i++) {
- len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_time2[i] >> shift);
+ len +=
+ sprintf (info->data + len, "%4d ",
+ dasd_global_profile.dasd_io_time2[i] >> shift);
}
len += sprintf (info->data + len, "\n");
for (; i < 32; i++) {
- len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_time2[i] >> shift);
+ len +=
+ sprintf (info->data + len, "%4d ",
+ dasd_global_profile.dasd_io_time2[i] >> shift);
}
len += sprintf (info->data + len, "\n");
- len += sprintf (info->data + len, "Histogram of I/O time between ssch and irq per sector\n");
+ len +=
+ sprintf (info->data + len,
+ "Histogram of I/O time between ssch and irq per sector\n");
for (i = 0; i < 16; i++) {
- len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_time2ps[i] >> shift);
+ len +=
+ sprintf (info->data + len, "%4d ",
+ dasd_global_profile.dasd_io_time2ps[i] >> shift);
}
len += sprintf (info->data + len, "\n");
for (; i < 32; i++) {
- len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_time2ps[i] >> shift);
+ len +=
+ sprintf (info->data + len, "%4d ",
+ dasd_global_profile.dasd_io_time2ps[i] >> shift);
}
len += sprintf (info->data + len, "\n");
- len += sprintf (info->data + len, "Histogram of I/O time between irq and end\n");
+ len +=
+ sprintf (info->data + len,
+ "Histogram of I/O time between irq and end\n");
for (i = 0; i < 16; i++) {
- len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_time3[i] >> shift);
+ len +=
+ sprintf (info->data + len, "%4d ",
+ dasd_global_profile.dasd_io_time3[i] >> shift);
}
len += sprintf (info->data + len, "\n");
for (; i < 32; i++) {
- len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_time3[i] >> shift);
+ len +=
+ sprintf (info->data + len, "%4d ",
+ dasd_global_profile.dasd_io_time3[i] >> shift);
}
len += sprintf (info->data + len, "\n");
info->len = len;
-#ifdef MODULE
- MOD_INC_USE_COUNT;
-#endif
return rc;
}
-static struct file_operations dasd_statistics_file_ops =
+static ssize_t
+dasd_statistics_write (struct file *file, const char *user_buf,
+ size_t user_len, loff_t * offset)
{
- read:dasd_devices_read, /* read */
+ char *buffer = vmalloc (user_len);
+
+ if (buffer == NULL)
+ return -ENOMEM;
+ if (copy_from_user (buffer, user_buf, user_len)) {
+ vfree (buffer);
+ return -EFAULT;
+ }
+ buffer[user_len] = 0;
+ printk (KERN_INFO PRINTK_HEADER "/proc/dasd/statictics: '%s'\n",
+ buffer);
+ if (strncmp (buffer, "reset", 4)) {
+ memset (&dasd_global_profile, 0, sizeof (dasd_profile_info_t));
+ }
+ return user_len;
+}
+
+static struct file_operations dasd_statistics_file_ops = {
+ read:dasd_generic_read, /* read */
open:dasd_statistics_open, /* open */
+ write:dasd_statistics_write, /* write */
release:dasd_devices_close, /* close */
};
-static struct inode_operations dasd_statistics_inode_ops =
-{
-#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
- default_file_ops:&dasd_statistics_file_ops /* file ops */
-#endif /* LINUX_IS_24 */
+static struct inode_operations dasd_statistics_inode_ops = {
};
int
dasd_proc_init (void)
{
int rc = 0;
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
dasd_proc_root_entry = proc_mkdir ("dasd", &proc_root);
dasd_devices_entry = create_proc_entry ("devices",
S_IFREG | S_IRUGO | S_IWUSR,
@@ -3127,204 +3835,175 @@
dasd_proc_root_entry);
dasd_statistics_entry->proc_fops = &dasd_statistics_file_ops;
dasd_statistics_entry->proc_iops = &dasd_statistics_inode_ops;
-#else
- proc_register (&proc_root, &dasd_proc_root_entry);
- dasd_devices_entry = (struct proc_dir_entry *) kmalloc (sizeof (struct proc_dir_entry), GFP_ATOMIC);
- if (dasd_devices_entry) {
- memset (dasd_devices_entry, 0, sizeof (struct proc_dir_entry));
- dasd_devices_entry->name = "devices";
- dasd_devices_entry->namelen = strlen ("devices");
- dasd_devices_entry->low_ino = 0;
- dasd_devices_entry->mode = (S_IFREG | S_IRUGO | S_IWUSR);
- dasd_devices_entry->nlink = 1;
- dasd_devices_entry->uid = 0;
- dasd_devices_entry->gid = 0;
- dasd_devices_entry->size = 0;
- dasd_devices_entry->get_info = NULL;
- dasd_devices_entry->ops = &dasd_devices_inode_ops;
- proc_register (&dasd_proc_root_entry, dasd_devices_entry);
- }
- dasd_statistics_entry = (struct proc_dir_entry *) kmalloc (sizeof (struct proc_dir_entry), GFP_ATOMIC);
- if (dasd_statistics_entry) {
- memset (dasd_statistics_entry, 0, sizeof (struct proc_dir_entry));
- dasd_statistics_entry->name = "statistics";
- dasd_statistics_entry->namelen = strlen ("statistics");
- dasd_statistics_entry->low_ino = 0;
- dasd_statistics_entry->mode = (S_IFREG | S_IRUGO | S_IWUSR);
- dasd_statistics_entry->nlink = 1;
- dasd_statistics_entry->uid = 0;
- dasd_statistics_entry->gid = 0;
- dasd_statistics_entry->size = 0;
- dasd_statistics_entry->get_info = NULL;
- dasd_statistics_entry->ops = &dasd_statistics_inode_ops;
- proc_register (&dasd_proc_root_entry, dasd_statistics_entry);
- }
-#endif /* LINUX_IS_24 */
return rc;
}
void
dasd_proc_cleanup (void)
{
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
remove_proc_entry ("devices", dasd_proc_root_entry);
remove_proc_entry ("statistics", dasd_proc_root_entry);
remove_proc_entry ("dasd", &proc_root);
-#else
- proc_unregister (&dasd_proc_root_entry, dasd_statistics_entry->low_ino);
- kfree (dasd_statistics_entry);
- proc_unregister (&dasd_proc_root_entry, dasd_devices_entry->low_ino);
- kfree (dasd_devices_entry);
- proc_unregister (&proc_root, dasd_proc_root_entry.low_ino);
-#endif /* LINUX_IS_24 */
}
+int
+dasd_request_module ( void *name ) {
+ int rc = -ERESTARTSYS;
+ strcpy(current->comm, name);
+ daemonize();
+ while ( current->fs->root == NULL ) { /* wait for root-FS */
+ DECLARE_WAIT_QUEUE_HEAD(wait);
+ sleep_on_timeout(&wait,HZ); /* wait in steps of one second */
+ }
+ while ( (rc=request_module(name)) != 0 ) {
+ DECLARE_WAIT_QUEUE_HEAD(wait);
+ printk ( KERN_INFO "request_module returned %d for %s\n",rc,(char*)name);
+ sleep_on_timeout(&wait,5* HZ); /* wait in steps of 5 seconds */
+ }
+ return rc;
+}
+
+
/* SECTION: Initializing the driver */
int __init
dasd_init (void)
{
int rc = 0;
int irq;
- int j;
- major_info_t *major_info=NULL;
+ major_info_t *major_info = NULL;
struct list_head *l;
- dasd_range_t *range;
printk (KERN_INFO PRINTK_HEADER "initializing...\n");
- dasd_debug_area = debug_register(DASD_NAME,0,2,3*sizeof(long));
- debug_register_view(dasd_debug_area,&debug_sprintf_view);
- debug_register_view(dasd_debug_area,&debug_hex_ascii_view);
-
- if ( dasd_debug_area == NULL ) {
- goto failed;
- }
- DASD_DRIVER_DEBUG_EVENT(0,dasd_init,"%s","ENTRY");
- dasd_devfs_handle = devfs_mk_dir(NULL,DASD_NAME,NULL);
- if ( dasd_devfs_handle < 0 ) {
- DASD_DRIVER_DEBUG_EVENT(1,dasd_init,"%s","no devfs");
- goto failed;
- }
- list_for_each(l,&dasd_major_info[0].list) {
- major_info=list_entry(l,major_info_t,list);
- if ((rc = dasd_register_major (major_info)) > 0) {
- DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
- "major %d: success",major_info->gendisk.major);
- printk (KERN_INFO PRINTK_HEADER
- "Registered successfully to major no %u\n", major_info->gendisk.major);
+ dasd_debug_area = debug_register (DASD_NAME, 0, 2, 4 * sizeof (long));
+ debug_register_view (dasd_debug_area, &debug_sprintf_view);
+ debug_register_view (dasd_debug_area, &debug_hex_ascii_view);
+
+ init_waitqueue_head (&dasd_init_waitq);
+
+ if (dasd_debug_area == NULL) {
+ goto failed;
+ }
+ DASD_DRIVER_DEBUG_EVENT (0, dasd_init, "%s", "ENTRY");
+ dasd_devfs_handle = devfs_mk_dir (NULL, DASD_NAME, NULL);
+ if (dasd_devfs_handle < 0) {
+ DASD_DRIVER_DEBUG_EVENT (1, dasd_init, "%s", "no devfs");
+ goto failed;
+ }
+ list_for_each (l, &dasd_major_info[0].list) {
+ major_info = list_entry (l, major_info_t, list);
+ if ((rc = dasd_register_major (major_info)) > 0) {
+ DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
+ "major %d: success",
+ major_info->gendisk.major);
+ printk (KERN_INFO PRINTK_HEADER
+ "Registered successfully to major no %u\n",
+ major_info->gendisk.major);
} else {
- DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
- "major %d: failed",major_info->gendisk.major);
+ DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
+ "major %d: failed",
+ major_info->gendisk.major);
printk (KERN_WARNING PRINTK_HEADER
- "Couldn't register successfully to major no %d\n", major_info->gendisk.major);
+ "Couldn't register successfully to major no %d\n",
+ major_info->gendisk.major);
/* revert registration of major infos */
- goto failed;
+ goto failed;
}
}
#ifndef MODULE
dasd_split_parm_string (dasd_parm_string);
#endif /* ! MODULE */
dasd_parse (dasd);
- dasd_init_emergency_req ();
rc = dasd_proc_init ();
if (rc) {
- DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
- "%s","no proc-FS");
- goto failed;
+ DASD_DRIVER_DEBUG_EVENT (1, dasd_init, "%s", "no proc-FS");
+ goto failed;
}
genhd_dasd_name = dasd_device_name;
- genhd_dasd_fillgeo = dasd_fillgeo;
+ if (dasd_autodetect) { /* update device range to all devices */
+ for (irq = get_irq_first (); irq != -ENODEV;
+ irq = get_irq_next (irq)) {
+ int devno = get_devno_by_irq (irq);
+ int index = dasd_devindex_from_devno (devno);
+ if (index == -ENODEV) { /* not included in ranges */
+ DASD_DRIVER_DEBUG_EVENT (2, dasd_init,
+ "add %04X to range",
+ devno);
+ dasd_add_range (devno, devno, DASD_DEFAULT_FEATURES);
+ }
+ }
+ }
+
+ if (MACHINE_IS_VM) {
+#ifdef CONFIG_DASD_DIAG
+ rc = dasd_diag_init ();
+ if (rc == 0) {
+ DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
+ "DIAG discipline %s",
+ "success");
+ printk (KERN_INFO PRINTK_HEADER
+ "Registered DIAG discipline successfully\n");
+ } else {
+ DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
+ "DIAG discipline %s",
+ "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 /* CONFIG_DASD_AUTO_DIAG */
+ }
#ifdef CONFIG_DASD_ECKD
rc = dasd_eckd_init ();
if (rc == 0) {
- DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
- "ECKD discipline %s","success");
+ DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
+ "ECKD discipline %s", "success");
printk (KERN_INFO PRINTK_HEADER
"Registered ECKD discipline successfully\n");
} else {
- DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
- "ECKD discipline %s","failed");
- goto failed;
- }
-#endif /* CONFIG_DASD_ECKD */
+ DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
+ "ECKD discipline %s", "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 /* CONFIG_DASD_AUTO_ECKD */
#ifdef CONFIG_DASD_FBA
rc = dasd_fba_init ();
if (rc == 0) {
- DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
- "FBA discipline %s","success");
+ DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
+ "FBA discipline %s", "success");
printk (KERN_INFO PRINTK_HEADER
"Registered FBA discipline successfully\n");
} else {
- DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
- "FBA discipline %s","failed");
- goto failed;
- }
-#endif /* CONFIG_DASD_FBA */
-#ifdef CONFIG_DASD_DIAG
- if (MACHINE_IS_VM) {
- rc = dasd_diag_init ();
- if (rc == 0) {
- DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
- "DIAG discipline %s","success");
- printk (KERN_INFO PRINTK_HEADER
- "Registered DIAG discipline successfully\n");
- } else {
- DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
- "DIAG discipline %s","failed");
- goto failed;
- }
- }
-#endif /* CONFIG_DASD_DIAG */
- rc = 0;
- if (dasd_autodetect) { /* update device range to all devices */
- for (irq = get_irq_first (); irq != -ENODEV;
- irq = get_irq_next (irq)) {
- int devno = get_devno_by_irq (irq);
- int index = dasd_devindex_from_devno (devno);
- if (index == -ENODEV) { /* not included in ranges */
- DASD_DRIVER_DEBUG_EVENT(2,dasd_init,
- "add %04X to range",
- devno);
- dasd_add_range (devno, 0);
- }
+ DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
+ "FBA discipline %s", "failed");
+ goto failed;
+ }
+#endif /* CONFIG_DASD_FBA */
+#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 */
+ {
+ char **disc=dasd_disciplines;
+ while (*disc) {
+ kernel_thread(dasd_request_module,*disc,SIGCHLD);
+ disc++;
}
}
- for (range = dasd_range_head; range; range = range->next) {
- for (j = range->from; j <= range->to; j++) {
- irq = get_irq_by_devno (j);
- if (irq >= 0)
- DASD_DRIVER_DEBUG_EVENT(2,dasd_init,
- "1st step in initialization irq 0x%x",irq);
- dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ONLINE,
- NULL, 0);
- }
- }
- printk (KERN_INFO PRINTK_HEADER "waiting for responses...\n");
- {
- static wait_queue_head_t wait_queue;
- init_waitqueue_head (&wait_queue);
- interruptible_sleep_on_timeout (&wait_queue,
- (5 * HZ) );
- }
- for (range = dasd_range_head; range; range = range->next) {
- for (j = range->from; j <= range->to; j++) {
- irq = get_irq_by_devno (j);
- if (irq >= 0) {
- DASD_DRIVER_DEBUG_EVENT(2,dasd_init,
- "2nd step in initialization irq 0x%x",irq);
- dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ONLINE,
- NULL, 0);
- }
- }
- }
- goto out;
- failed:
- printk (KERN_INFO PRINTK_HEADER "initialization not performed due to errors\n");
- cleanup_dasd();
- out:
- DASD_DRIVER_DEBUG_EVENT(0,dasd_init,"%s","LEAVE");
+
+ rc = 0;
+ goto out;
+ failed:
+ printk (KERN_INFO PRINTK_HEADER
+ "initialization not performed due to errors\n");
+ cleanup_dasd ();
+ out:
+ DASD_DRIVER_DEBUG_EVENT (0, dasd_init, "%s", "LEAVE");
printk (KERN_INFO PRINTK_HEADER "initialization finished\n");
return rc;
}
@@ -3332,95 +4011,78 @@
static void
cleanup_dasd (void)
{
- int i,j,rc;
- int irq;
- major_info_t *major_info=NULL;
- struct list_head *l;
- dasd_range_t *range, *next;
+ int i,rc=0;
+ major_info_t *major_info = NULL;
+ struct list_head *l,*n;
+ dasd_range_t *range;
printk (KERN_INFO PRINTK_HEADER "shutting down\n");
DASD_DRIVER_DEBUG_EVENT(0,"cleanup_dasd","%s","ENTRY");
- for (range = dasd_range_head; range; range = range->next) {
- for (j = range->from; j <= range->to; j++) {
- irq = get_irq_by_devno (j);
- if (irq >= 0) {
- DASD_DRIVER_DEBUG_EVENT(2,"cleanup_dasd",
- "shutdown irq 0x%x",irq);
- dasd_set_device_level (irq, DASD_DEVICE_LEVEL_UNKNOWN,
- NULL, 0);
- }
- }
- }
+ dasd_disable_ranges (&dasd_range_head, NULL, 1, 1);
+ if (MACHINE_IS_VM) {
#ifdef CONFIG_DASD_DIAG
- if (MACHINE_IS_VM) {
- dasd_diag_cleanup ();
- DASD_DRIVER_DEBUG_EVENT(1,"cleanup_dasd",
- "DIAG discipline %s","success");
+ dasd_diag_cleanup ();
+ DASD_DRIVER_DEBUG_EVENT (1, "cleanup_dasd",
+ "DIAG discipline %s", "success");
printk (KERN_INFO PRINTK_HEADER
- "De-Registered DIAG discipline successfully\n");
+ "De-Registered DIAG discipline successfully\n");
+#endif /* CONFIG_DASD_ECKD_BUILTIN */
}
-#endif /* CONFIG_DASD_DIAG */
#ifdef CONFIG_DASD_FBA
dasd_fba_cleanup ();
- DASD_DRIVER_DEBUG_EVENT(1,"cleanup_dasd",
- "FBA discipline %s","success");
- printk (KERN_INFO PRINTK_HEADER
- "De-Registered FBA discipline successfully\n");
-#endif /* CONFIG_DASD_FBA */
+ DASD_DRIVER_DEBUG_EVENT (1, "cleanup_dasd",
+ "FBA discipline %s", "success");
+ printk (KERN_INFO PRINTK_HEADER
+ "De-Registered FBA discipline successfully\n");
+#endif /* CONFIG_DASD_ECKD_BUILTIN */
#ifdef CONFIG_DASD_ECKD
dasd_eckd_cleanup ();
- DASD_DRIVER_DEBUG_EVENT(1,"cleanup_dasd",
- "ECKD discipline %s","success");
- printk (KERN_INFO PRINTK_HEADER
- "De-Registered ECKD discipline successfully\n");
-#endif /* CONFIG_DASD_ECKD */
+ DASD_DRIVER_DEBUG_EVENT (1, "cleanup_dasd",
+ "ECKD discipline %s", "success");
+ printk (KERN_INFO PRINTK_HEADER
+ "De-Registered ECKD discipline successfully\n");
+#endif /* CONFIG_DASD_ECKD_BUILTIN */
dasd_proc_cleanup ();
- dasd_cleanup_emergency_req ();
-
- list_for_each(l,&dasd_major_info[0].list) {
- major_info=list_entry(l,major_info_t,list);
+
+ list_for_each_safe (l, n, &dasd_major_info[0].list) {
+ major_info = list_entry (l, major_info_t, list);
for (i = 0; i < DASD_PER_MAJOR; i++) {
kfree (major_info->dasd_device[i]);
}
- if ((major_info -> flags & DASD_MAJOR_INFO_REGISTERED) &&
+ if ((major_info->flags & DASD_MAJOR_INFO_REGISTERED) &&
(rc = dasd_unregister_major (major_info)) == 0) {
- DASD_DRIVER_DEBUG_EVENT(1,"cleanup_dasd",
- "major %d: success",major_info->gendisk.major);
+ DASD_DRIVER_DEBUG_EVENT (1, "cleanup_dasd",
+ "major %d: success",
+ major_info->gendisk.major);
printk (KERN_INFO PRINTK_HEADER
- "Unregistered successfully from major no %u\n", major_info->gendisk.major);
+ "Unregistered successfully from major no %u\n",
+ major_info->gendisk.major);
} else {
- DASD_DRIVER_DEBUG_EVENT(1,"cleanup_dasd",
- "major %d: failed",major_info->gendisk.major);
+ DASD_DRIVER_DEBUG_EVENT (1, "cleanup_dasd",
+ "major %d: failed",
+ major_info->gendisk.major);
printk (KERN_WARNING PRINTK_HEADER
- "Couldn't unregister successfully from major no %d rc = %d\n", major_info->gendisk.major, rc);
- }
- }
-
+ "Couldn't unregister successfully from major no %d rc = %d\n",
+ major_info->gendisk.major, rc);
+ }
+ }
+ list_for_each_safe (l, n, &dasd_range_head.list) {
+ range = list_entry (l, dasd_range_t, list);
+ dasd_remove_range(range);
+ }
- range = dasd_range_head;
- while (range) {
- next = range->next;
- dasd_remove_range (range);
- if (next == NULL)
- break;
- else
- range = next;
- }
- dasd_range_head = NULL;
-
#ifndef MODULE
- for( j = 0; j < 256; j++ )
- if ( dasd[j] ) {
- kfree(dasd[j]);
- dasd[j] = NULL;
+ for( i = 0; i < 256; i++ )
+ if ( dasd[i] ) {
+ kfree(dasd[i]);
+ dasd[i] = NULL;
}
#endif /* MODULE */
if (dasd_devfs_handle)
devfs_unregister(dasd_devfs_handle);
if (dasd_debug_area != NULL )
debug_unregister(dasd_debug_area);
-
printk (KERN_INFO PRINTK_HEADER "shutdown completed\n");
DASD_DRIVER_DEBUG_EVENT(0,"cleanup_dasd","%s","LEAVE");
}
@@ -3430,7 +4092,7 @@
init_module (void)
{
int rc = 0;
- return dasd_init ();
+ rc = dasd_init ();
return rc;
}
@@ -3449,7 +4111,7 @@
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
- * c-indent-level: 4
+ * c-indent-level: 4
* c-brace-imaginary-offset: 0
* c-brace-offset: -4
* c-argdecl-indent: 4
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)