patch-2.4.4 linux/drivers/s390/block/dasd.c
Next file: linux/drivers/s390/block/dasd_3990_erp.c
Previous file: linux/drivers/s390/block/Makefile
Back to the patch index
Back to the overall index
- Lines: 1877
- Date:
Wed Apr 11 19:02:28 2001
- Orig file:
v2.4.3/linux/drivers/s390/block/dasd.c
- Orig date:
Fri Feb 16 16:02:36 2001
diff -u --recursive --new-file v2.4.3/linux/drivers/s390/block/dasd.c linux/drivers/s390/block/dasd.c
@@ -2,13 +2,27 @@
* File...........: linux/drivers/s390/block/dasd.c
* Author(s)......: Holger Smolinski <Holger.Smolinski@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
*
* 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
+ * fixed handling of plugged queues
+ * fixed partition handling and HDIO_GETGEO
+ * fixed traditional naming scheme for devices beyond 702
+ * 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
*/
+#include <linux/module.h>
#include <linux/config.h>
#include <linux/version.h>
#include <linux/init.h>
@@ -17,7 +31,7 @@
#include <linux/kernel.h>
#include <linux/tqueue.h>
#include <linux/timer.h>
-#include <linux/slab.h>
+#include <linux/malloc.h>
#include <linux/genhd.h>
#include <linux/hdreg.h>
#include <linux/interrupt.h>
@@ -25,13 +39,9 @@
#ifdef CONFIG_PROC_FS
#include <linux/proc_fs.h>
#endif /* CONFIG_PROC_FS */
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
#include <linux/spinlock.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/blkpg.h>
-#else
-#include <asm/spinlock.h>
-#endif
#include <asm/ccwcache.h>
#include <asm/dasd.h>
@@ -54,17 +64,10 @@
#ifdef CONFIG_DASD_FBA
#include "dasd_fba.h"
#endif /* CONFIG_DASD_FBA */
-#ifdef CONFIG_DASD_MDSK
+#ifdef CONFIG_DASD_DIAG
#include "dasd_diag.h"
-#endif /* CONFIG_DASD_MDSK */
-
-static struct block_device_operations dasd_device_operations;
+#endif /* CONFIG_DASD_DIAG */
-#ifdef MODULE
-#define EXPORT_SYMTAB
-#include <linux/module.h>
-
-EXPORT_NO_SYMBOLS;
MODULE_AUTHOR ("Holger Smolinski <Holger.Smolinski@de.ibm.com>");
MODULE_DESCRIPTION ("Linux on S/390 DASD device driver,"
" Copyright 2000 IBM Corporation");
@@ -76,11 +79,10 @@
EXPORT_SYMBOL (dasd_int_handler);
EXPORT_SYMBOL (dasd_alloc_request);
EXPORT_SYMBOL (dasd_free_request);
-
-#endif /* MODULE */
+EXPORT_SYMBOL(dasd_ioctl_no_register);
+EXPORT_SYMBOL(dasd_ioctl_no_unregister);
/* SECTION: Constant definitions to be used within this file */
-#undef ERP_DEBUG
#define PRINTK_HEADER DASD_NAME": "
@@ -89,20 +91,28 @@
#undef CONFIG_DYNAMIC_QUEUE_MIN_SIZE
#define DASD_CHANQ_MAX_SIZE 6
-
/* SECTION: prototypes for static functions of dasd.c */
static request_fn_proc do_dasd_request;
-void dasd_schedule_bh (dasd_device_t *);
static int dasd_set_device_level (unsigned int, 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 struct block_device_operations dasd_device_operations;
+/* 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;
+
#ifdef CONFIG_DASD_DYNAMIC
/* SECTION: managing dynamic configuration of dasd_driver */
-static dasd_devreg_t *dasd_devreg_head = NULL;
+static struct list_head dasd_devreg_head = LIST_HEAD_INIT(dasd_devreg_head);
/*
* function: dasd_create_devreg
@@ -149,6 +159,7 @@
static dasd_range_t *dasd_range_head = NULL; /* anchor for list of ranges */
static spinlock_t range_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t dasd_open_count_lock;
/*
* function: dasd_create_range
@@ -240,15 +251,14 @@
* appends it to the list of ranges
* additionally a devreg_t is created and added to the list of devregs
*/
-static inline void
+static inline dasd_range_t*
dasd_add_range (int from, int to)
{
dasd_range_t *range;
range = dasd_create_range (from, to);
- if (range)
- dasd_append_range (range);
- else
- return;
+ if (!range) return NULL;
+
+ dasd_append_range (range);
#ifdef CONFIG_DASD_DYNAMIC
/* allocate and chain devreg infos for the devnos... */
{
@@ -256,11 +266,11 @@
for (i = range->from; i <= range->to; i++) {
dasd_devreg_t *reg = dasd_create_devreg (i);
s390_device_register (®->devreg);
- reg->next = dasd_devreg_head;
- dasd_devreg_head = reg;
+ list_add(®->list,&dasd_devreg_head);
}
}
#endif /* CONFIG_DASD_DYNAMIC */
+ return range;
}
/*
@@ -277,28 +287,25 @@
{
int i;
for (i = range->from; i <= range->to; i++) {
- dasd_devreg_t *reg, *prev = NULL;
- for (reg = dasd_devreg_head; reg; reg = reg->next) {
+ struct list_head *l;
+ dasd_devreg_t *reg = NULL;
+ list_for_each (l, &dasd_devreg_head) {
+ reg = list_entry(l,dasd_devreg_t,list);
if (reg->devreg.flag == DEVREG_TYPE_DEVNO &&
- reg->devreg.devno == i &&
+ reg->devreg.ci.devno == i &&
reg->devreg.oper_func == dasd_oper_handler)
break;
- prev = reg;
}
- if (!reg)
+ if (l == &dasd_devreg_head)
BUG ();
- if (prev) {
- prev->next = reg->next;
- } else {
- dasd_devreg_head = reg->next;
- }
+ list_del(®->list);
s390_device_unregister (®->devreg);
dasd_destroy_devreg (reg);
}
}
+#endif /* CONFIG_DASD_DYNAMIC */
dasd_dechain_range (range);
dasd_destroy_range (range);
-#endif /* CONFIG_DASD_DYNAMIC */
}
/*
@@ -475,13 +482,18 @@
/* SECTION: Dealing with devices registered to multiple major numbers */
static spinlock_t dasd_major_lock = SPIN_LOCK_UNLOCKED;
+
static major_info_t dasd_major_info[] =
{
{
- next:NULL,
+ 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
}
};
@@ -489,26 +501,16 @@
get_new_major_info (void)
{
major_info_t *major_info = NULL;
- unsigned long flags;
major_info = kmalloc (sizeof (major_info_t), GFP_KERNEL);
if (major_info) {
- major_info_t *temp = dasd_major_info;
- static major_info_t temp_major_info[] =
- {
- {
- next:NULL,
- gendisk: {
- INIT_GENDISK(0,DASD_NAME,DASD_PARTN_BITS,DASD_PER_MAJOR)
- }
- }
- };
- spin_lock_irqsave (&dasd_major_lock, flags);
- while (temp->next)
- temp = temp->next;
- temp->next = major_info;
- spin_unlock_irqrestore (&dasd_major_lock, flags);
- memcpy (major_info, temp_major_info, sizeof (major_info_t));
+ 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;
}
@@ -518,6 +520,7 @@
{
int rc = 0;
int major;
+ unsigned long flags;
if (major_info == NULL) {
major_info = get_new_major_info ();
@@ -531,12 +534,27 @@
}
}
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));
+
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;
+ } 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);
+ spin_unlock_irqrestore (&dasd_major_lock, flags);
+ }
if (major == 0) {
major = rc;
rc = 0;
@@ -604,6 +622,7 @@
int rc = 0;
int major;
struct gendisk *dd, *prev = NULL;
+ unsigned long flags;
if (major_info == NULL) {
return -EINVAL;
@@ -629,6 +648,8 @@
if (dd == NULL) {
return -ENOENT;
}
+ kfree (major_info->gendisk.de_arr);
+ kfree (major_info->gendisk.flags);
kfree (major_info->dasd_device);
kfree (blk_size[major]);
kfree (blksize_size[major]);
@@ -641,9 +662,16 @@
printk (KERN_WARNING PRINTK_HEADER
"Cannot unregister from major no %d, rc = %d\n", major, rc);
return rc;
+ } else {
+ major_info->flags &= ~DASD_MAJOR_INFO_REGISTERED;
}
- if (major_info->gendisk.major > 128)
+ /* 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;
}
@@ -655,16 +683,18 @@
static inline dasd_device_t *
dasd_device_from_kdev (kdev_t kdev)
{
- major_info_t *major_info = dasd_major_info;
+ major_info_t *major_info = NULL;
+ struct list_head *l;
unsigned long flags;
spin_lock_irqsave (&dasd_major_lock, flags);
- while (major_info &&
- major_info->gendisk.major != MAJOR (kdev)) {
- major_info = major_info->next;
+ 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);
- if (major_info)
+ if (major_info != &dasd_major_info[0])
return major_info->dasd_device[MINOR (kdev) >> DASD_PARTN_BITS];
return NULL;
}
@@ -678,13 +708,14 @@
static inline dasd_device_t **
dasd_device_from_devno (int devno)
{
- major_info_t *major_info = dasd_major_info;
+ major_info_t *major_info;
+ struct list_head *l;
int devindex = dasd_devindex_from_devno (devno);
unsigned long flags;
spin_lock_irqsave (&dasd_major_lock, flags);
- for (major_info = dasd_major_info; major_info;
- major_info = major_info->next) {
+ 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];
@@ -867,7 +898,7 @@
ccw_req_t *prev;
if (cqr == NULL)
- BUG ();
+ BUG ();
if (cqr == q->head) {
q->head = cqr->next;
@@ -1111,20 +1142,11 @@
static inline void
dasd_end_request (struct request *req, int uptodate)
{
- struct buffer_head *bh;
- while ((bh = req->bh) != NULL) {
- int nsect = bh->b_size >> 9;
- blk_finished_io (nsect);
- req->bh = bh->b_reqnext;
- bh->b_reqnext = NULL;
- bh->b_end_io (bh, uptodate);
- }
- if (!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));
+ add_blkdev_randomness (MAJOR (req->rq_dev));
#endif
- end_that_request_last (req);
- }
+ end_that_request_last (req);
return;
}
@@ -1151,9 +1173,10 @@
int rc = 0;
asm volatile ("STCK %0":"=m" (now));
- if ( cqr->expires + cqr->startclk < now) {
+ if ( cqr->expires &&
+ cqr->expires + cqr->startclk < now) {
DASD_MESSAGE (KERN_ERR, ((dasd_device_t*)cqr->device),
- "IO timeout 0x%08lx%08lx usecs with req %p\n",
+ "IO timeout 0x%08lx%08lx usecs in req %p\n",
(long) (cqr->expires >> 44),
(long) (cqr->expires >> 12), cqr);
cqr->expires <<=1;
@@ -1170,7 +1193,6 @@
dasd_finalize_request (ccw_req_t * cqr)
{
dasd_device_t *device = cqr->device;
- dasd_discipline_t *discipline = device->discipline;
asm volatile ("STCK %0":"=m" (cqr->endclk));
if (cqr->req) {
@@ -1225,9 +1247,11 @@
CQR_STATUS_FAILED);
continue;
} else {
- dasd_chanq_enq_head (qp, erp_cqr);
+ if (erp_cqr != qp->head){
+ dasd_chanq_enq_head (qp, erp_cqr);
+ }
/* chain of completed requests is now broken */
- break;
+ continue;
}
} else if ( qp -> head -> refers ) { /* we deal with an ERP */
char *uptodatestr;
@@ -1266,7 +1290,8 @@
for (temp = cqr; temp != NULL ;temp=temp-> next )
if ( temp ->status == CQR_STATUS_QUEUED)
chanq_max_size --;
- while ( (! list_empty(&queue->queue_head)) &&
+ 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 ||
@@ -1307,6 +1332,10 @@
/* to be filled with MIH */
}
break;
+
+ case CQR_STATUS_PENDING:
+ /* just wait */
+ break;
default:
BUG();
}
@@ -1390,8 +1419,54 @@
}
#endif /* LINUX_IS_24 */
+/*
+ * DASD_HANDLE_STATE_CHANGE_PENDING
+ *
+ * DESCRIPTION
+ * Handles the state change pending interrupt.
+ * 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.
+ *
+ * PARAMETER
+ * stat device status of state change pending interrupt.
+ */
+void
+dasd_handle_state_change_pending (devstat_t *stat)
+{
+ 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 (cqr->status == CQR_STATUS_PENDING) {
+
+ DASD_MESSAGE (KERN_INFO, (*device_addr),
+ "%s",
+ "device request queue restarted by "
+ "state change pending interrupt\n");
+
+ del_timer(&(*device_addr)->timer);
+
+ check_then_set(&cqr->status,
+ CQR_STATUS_PENDING,
+ CQR_STATUS_QUEUED);
+ dasd_schedule_bh(*device_addr);
+ }
+ }
+} /* end dasd_handle_state_change_pending */
/*
* function dasd_int_handler
@@ -1406,7 +1481,7 @@
dasd_device_t *device;
unsigned long long now;
#ifdef ERP_DEBUG
- static int counter;
+ static int counter = 0;
#endif
dasd_era_t era = dasd_era_none; /* default is everything is okay */
devstat_t *stat = (devstat_t *)ds;
@@ -1415,6 +1490,16 @@
if (stat == NULL) {
BUG();
}
+
+ /* first of all check for state change pending interrupt */
+ if (stat->dstat & (DEV_STAT_ATTENTION |
+ DEV_STAT_DEV_END |
+ DEV_STAT_UNIT_EXCEP )) {
+
+ dasd_handle_state_change_pending (stat);
+ //return; /* TBD */
+ }
+
ip = stat->intparm;
if (!ip) { /* no intparm: unsolicited interrupt */
printk (KERN_INFO PRINTK_HEADER
@@ -1441,11 +1526,35 @@
BUG();
}
#ifdef ERP_DEBUG
- counter++;
- if ( counter % 137 == 0 ) {
- stat->flag |= DEVSTAT_FLAG_SENSE_AVAIL;
- stat->cstat = 0x00;
- stat->dstat = 0x02;
+ 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");
+ era = dasd_era_recover;
+ 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;
@@ -1464,6 +1573,7 @@
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 */
@@ -1545,13 +1655,13 @@
ccw_req_t *
default_erp_action (ccw_req_t * cqr)
{
- ccw_req_t *erp = ccw_alloc_request ((char *) &cqr->magic, 1, 0);
+ ccw_req_t *erp = dasd_alloc_request ((char *) &cqr->magic, 1, 0);
printk (KERN_WARNING PRINTK_HEADER
"Default ERP called... \n");
- if (!erp)
- return NULL;
+ if (erp == NULL)
+ return NULL;
erp->cpaddr->cmd_code = CCW_CMD_TIC;
erp->cpaddr->cda = (__u32)(void *)cqr->cpaddr;
@@ -1562,6 +1672,7 @@
erp->retries = 16;
erp->status = CQR_STATUS_FILLED;
+
return erp;
}
@@ -1582,8 +1693,8 @@
ccw_req_t *
default_erp_postaction (ccw_req_t * erp)
{
+ ccw_req_t *cqr = NULL, *free_erp = NULL;
dasd_device_t *device = NULL;
- ccw_req_t *free_erp;
int success;
device = (dasd_device_t *) (erp->device);
@@ -1593,6 +1704,24 @@
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();
}
@@ -1606,39 +1735,46 @@
while (erp->refers != NULL) {
free_erp = erp;
erp = erp->refers;
+ /* remove the request from the device queue */
dasd_chanq_deq (&device->queue, free_erp);
+ /* free the finished erp request */
dasd_free_request (free_erp);
}
/* 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 */
- /*
- * printk (KERN_INFO PRINTK_HEADER
- * "default_erp_postaction - left original request = %p \n",erp);
- */
/* set corresponding status to original cqr */
if (success) {
- check_then_set (&erp->status, CQR_STATUS_ERROR,
+ check_then_set (&cqr->status,
+ CQR_STATUS_ERROR,
CQR_STATUS_DONE);
} else {
- check_then_set (&erp->status, CQR_STATUS_ERROR,
+ check_then_set (&cqr->status,
+ CQR_STATUS_ERROR,
CQR_STATUS_FAILED);
}
-
+
+#ifdef ERP_DEBUG
/* print current erp_chain */
-#if 0
printk (KERN_WARNING PRINTK_HEADER
"default ERP postaction finished with remaining chain:\n");
{
ccw_req_t *temp_erp = NULL;
- for (temp_erp = erp; temp_erp != NULL; temp_erp = temp_erp->refers) {
+ 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
- return erp;
+#endif /* ERP_DEBUG */
+
+ return cqr;
} /* end default_erp_postaction */
/* SECTION: The helpers of the struct file_operations */
@@ -1655,6 +1791,7 @@
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 =
{
@@ -1663,29 +1800,41 @@
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);
+ 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 ) {
+ fdata->stop_unit == DASD_FORMAT_DEFAULT_STOP_UNIT &&
+ fdata->intensity == DASD_FORMAT_DEFAULT_INTENSITY ) {
format_data_t temp2 =
- {0, 0, DASD_FORMAT_DEFAULT_BLOCKSIZE, 0x04};
- DASD_MESSAGE (KERN_INFO, device, "%s", "Invalidating first track...");
+ {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);
@@ -1694,32 +1843,43 @@
rc = -EINVAL;
}
if (rc) {
- printk (KERN_WARNING PRINTK_HEADER "Can't invalidate Track 0\n");
- }
+ DASD_MESSAGE (KERN_WARNING, device,
+ "%s",
+ "Can't invalidate Track 0\n");
+ } else {
+ DASD_MESSAGE (KERN_INFO, device,
+ "%s",
+ "...Invalidation complete");
+ }
temp.start_unit++;
- DASD_MESSAGE (KERN_INFO, device, "%s", "...Invalidation complete");
}
/* format remainnig tracks of device */
- while (!rc &&
- ((req = device->discipline->format_device (device, &temp)) !=
- NULL)) {
+ while (!rc &&
+ ((req = device->discipline->format_device (device, &temp)) != NULL) ) {
+ format_done=1;
if ((rc = sleep_on_req (req)) != 0) {
+
+
DASD_MESSAGE (KERN_WARNING, device,
" Formatting failed with rc = %d\n",
rc);
break;
}
+
dasd_free_request (req); /* request is no longer used */
temp.start_unit++;
}
- if (!rc &&
- req == NULL) {
+
+ 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 ) {
+ 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...");
+ DASD_MESSAGE (KERN_INFO, device,
+ "%s",
+ "Revalidating first track...");
req = device->discipline->format_device (device, &temp2);
if (req) {
rc = sleep_on_req (req);
@@ -1728,12 +1888,22 @@
rc = -EINVAL;
}
if (rc) {
- printk (KERN_WARNING PRINTK_HEADER
- "Can't revalidate Track 0\n");
- }
- DASD_MESSAGE (KERN_INFO, device, "%s", "...Revalidation complete");
+ 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");
@@ -1741,22 +1911,75 @@
DASD_MESSAGE (KERN_INFO, device,
"%s", " Formatting finished successfully");
- /* re-activate device even if formatting was unsuccessful */
- /* Horst Hummel - 17/10/00 - ITPM PL020062RSC */
- dasd_set_device_level (device->devinfo.irq,
- DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
- device->discipline,
- 0);
- udelay (1500000);
-
- dasd_set_device_level (device->devinfo.irq,
- DASD_DEVICE_LEVEL_ANALYSED,
- device->discipline,
- 0);
-
+ /*
+ * 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 dasd_ioctl_list_t *
+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);
+ }
+ }
+ return NULL;
+}
+
+int
+dasd_ioctl_no_register ( int no, dasd_ioctl_fn_t handler )
+{
+ dasd_ioctl_list_t *new;
+ if (dasd_find_ioctl(no))
+ return -EBUSY;
+ 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
+ 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 )
+ return -ENOENT;
+ if ( old->no != no ||
+ old->handler != handler )
+ return -EINVAL;
+ list_del(&old->list);
+ kfree(old);
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
+ return 0;
+}
+
static int
do_dasd_ioctl (struct inode *inp, /* unsigned */ int no, unsigned long data)
{
@@ -1809,10 +2032,11 @@
break;
}
case HDIO_GETGEO:{
- struct hd_geometry geo =
- {0,};
- if (device->discipline->fill_geometry)
- device->discipline->fill_geometry (device, &geo);
+ struct hd_geometry geo = {0,};
+ rc = dasd_fillgeo(inp->i_rdev, &geo);
+ if (rc)
+ break;
+
rc = copy_to_user ((struct hd_geometry *) data, &geo,
sizeof (struct hd_geometry));
if (rc)
@@ -1944,17 +2168,23 @@
break;
}
default:{
- DASD_MESSAGE (KERN_INFO, device,
- "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),
- data);
- rc = -EINVAL;
+
+ dasd_ioctl_list_t *old = dasd_find_ioctl(no);
+ if ( old ) {
+ rc = old->handler(inp,no,data);
+ } else {
+ DASD_MESSAGE (KERN_INFO, device,
+ "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),
+ data);
+ rc = -EINVAL;
+ }
break;
}
}
@@ -2000,10 +2230,16 @@
" %s", " Cannot open unrecognized device\n");
return -EINVAL;
}
+ spin_lock(&dasd_open_count_lock);
+ if (device->open_count == -1) {
+ spin_unlock (&dasd_open_count_lock);
+ return -EBUSY;
+ }
#ifdef MODULE
MOD_INC_USE_COUNT;
#endif /* MODULE */
device->open_count++;
+ spin_unlock (&dasd_open_count_lock);
return rc;
}
@@ -2023,6 +2259,7 @@
MAJOR (inp->i_rdev), MINOR (inp->i_rdev));
return -EINVAL;
}
+ spin_lock(&dasd_open_count_lock);
if (device->open_count--) {
#ifdef MODULE
MOD_DEC_USE_COUNT;
@@ -2031,6 +2268,7 @@
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);
return rc;
}
@@ -2048,6 +2286,26 @@
};
/* SECTION: Management of device list */
+int
+dasd_fillgeo(int kdev,struct hd_geometry *geo)
+{
+ dasd_device_t *device = dasd_device_from_kdev (kdev);
+ if (!device->discipline->fill_geometry)
+ 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;
+}
+
/* This one is needed for naming 18000+ possible dasd devices */
int
@@ -2057,27 +2315,30 @@
char first, second, third;
if (hd) {
- major_info_t *major_info;
- for (major_info = dasd_major_info; major_info; major_info = major_info->next) {
+ 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);
if (&major_info->gendisk == hd) {
break;
}
index += DASD_PER_MAJOR;
}
- if (major_info == NULL) {
+ if (major_info == &dasd_major_info[0]) {
return -EINVAL;
}
}
third = index % 26;
- second = (index / 26) % 27;
- first = ((index / 26) / 27) % 27;
+ second = ((index-26) / 26) % 26;
+ first = (((index-702) / 26) / 26) % 26;
len = sprintf (str, "dasd");
- if (first) {
- len += sprintf (str + len, "%c", first + 'a' - 1);
+ if (index>701) {
+ len += sprintf (str + len, "%c", first + 'a');
}
- if (second) {
- len += sprintf (str + len, "%c", second + 'a' - 1);
+ if (index>25) {
+ len += sprintf (str + len, "%c", second + 'a');
}
len += sprintf (str + len, "%c", third + 'a');
if (partition) {
@@ -2093,13 +2354,28 @@
#ifdef CONFIG_DASD_DYNAMIC
static void
+dasd_plug_device (dasd_device_t *device)
+{
+ device->request_queue.plugged = 1; /* inhibit further calls of request_fn */
+}
+
+static void
+dasd_unplug_device (dasd_device_t *device)
+{
+ generic_unplug_device(&device->request_queue);
+}
+
+static void
dasd_not_oper_handler (int irq, int status)
{
dasd_device_t *device = NULL;
- major_info_t *major_info;
+ major_info_t *major_info = NULL;
+ struct list_head *l;
int i, devno = -ENODEV;
- for (major_info = dasd_major_info; major_info != NULL; major_info = major_info->next) {
+ /* 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 &&
@@ -2116,20 +2392,24 @@
"not_oper_handler called on irq %d no devno!\n", irq);
return;
}
- printk (KERN_INFO PRINTK_HEADER
- "not_oper_handler called on irq %d devno %04X\n", irq, devno);
+
if (device->open_count != 0) {
- printk (KERN_ALERT PRINTK_HEADER
- "Device %04X detached has still been open. expect errors\n", devno);
- }
- dasd_set_device_level (irq, DASD_DEVICE_LEVEL_UNKNOWN, NULL, 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);
+ }
}
static int
dasd_enable_single_volume (int irq)
{
int rc = 0;
- dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
+ dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ONLINE,
NULL, 0);
printk (KERN_INFO PRINTK_HEADER "waiting for response...\n");
{
@@ -2137,8 +2417,7 @@
init_waitqueue_head (&wait_queue);
interruptible_sleep_on_timeout (&wait_queue, (5 * HZ) >> 1);
}
- dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSED,
- NULL, 0);
+ dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ONLINE, NULL, 0);
return rc;
}
@@ -2148,12 +2427,13 @@
int devno;
int rc;
devno = get_devno_by_irq (irq);
- if (devno == -ENODEV)
+ printk (KERN_WARNING PRINTK_HEADER "Oper handler called\n");
+ if (devno == -ENODEV) {
+ printk (KERN_WARNING PRINTK_HEADER "NODEV\n");
return -ENODEV;
+ }
if (dasd_autodetect) {
dasd_add_range (devno, 0);
- } else {
- return -ENODEV;
}
rc = dasd_enable_single_volume (irq);
return rc;
@@ -2172,14 +2452,26 @@
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;
devno = get_devno_by_irq (irq);
- if (devno < 0) {
- printk (KERN_WARNING PRINTK_HEADER " no device appears to be connected to SCH %d\n", irq);
- return -ENODEV;
+ 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;
@@ -2204,8 +2496,9 @@
memset (device, 0, sizeof (dasd_device_t));
*device_addr = device;
}
- for (major_info = dasd_major_info; major_info; major_info = major_info->next) {
+ 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);
@@ -2215,21 +2508,21 @@
if (i < DASD_PER_MAJOR)
break;
}
- if (major_info == NULL) {
+ if (major_info == &dasd_major_info[0]) {
return -ENODEV;
}
- 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);
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;
@@ -2242,6 +2535,9 @@
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,
@@ -2276,8 +2572,6 @@
}
}
init_waitqueue_head (&device->wait_q);
- blk_init_queue (&device->request_queue, do_dasd_request);
- blk_queue_headactive (&device->request_queue, 0);
check_then_set (&device->level,
DASD_DEVICE_LEVEL_UNKNOWN,
DASD_DEVICE_LEVEL_RECOGNIZED);
@@ -2325,9 +2619,12 @@
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;
+ 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;
@@ -2336,7 +2633,7 @@
blksize_size[major][minor + i] = 1024;
max_sectors[major][minor + i] =
- 255 << device->sizes.s2b_shift;
+ device->discipline->max_blocks << device->sizes.s2b_shift;
}
check_then_set (&device->level,
DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
@@ -2344,6 +2641,12 @@
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)
@@ -2353,8 +2656,15 @@
if (desired_level == DASD_DEVICE_LEVEL_ANALYSED)
break;
case DASD_DEVICE_LEVEL_ANALYSED: /* Fallthrough ?? */
-
- break;
+ 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."
@@ -2368,20 +2678,29 @@
}
} else if (desired_level < current_level) { /* donwgrade device status */
switch (current_level) {
- case DASD_DEVICE_LEVEL_ANALYSED: /* Fallthrough ?? */
+ case DASD_DEVICE_LEVEL_ONLINE: /* Fallthrough ?? */
+ dasd_plug_device(device);
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:
+ 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++) {
- blk_size[major][minor] = 0;
+ __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);
@@ -2398,10 +2717,12 @@
free_irq (irq, &device->dev_status);
}
device->discipline = NULL;
- blk_cleanup_queue (&device->request_queue);
+ 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:
@@ -2433,6 +2754,13 @@
int len;
} tempinfo_t;
+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
@@ -2445,7 +2773,8 @@
nlink:1,
uid:0,
gid:0,
- size:0
+ size:0,
+ fill_inode:dasd_fill_inode
};
#endif /* KERNEL_VERSION */
static struct proc_dir_entry *dasd_devices_entry;
@@ -2458,7 +2787,9 @@
int size = 1;
int len = 0;
major_info_t *temp = dasd_major_info;
+ struct list_head *l;
tempinfo_t *info;
+ int i;
info = (tempinfo_t *) vmalloc (sizeof (tempinfo_t));
if (info == NULL) {
@@ -2467,15 +2798,14 @@
} else {
file->private_data = (void *) info;
}
- while (temp) {
- int i;
+ 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;
}
}
- temp = temp->next;
}
temp = dasd_major_info;
info->data = (char *) vmalloc (size); /* FIXME! determine space needed in a better way */
@@ -2484,8 +2814,8 @@
vfree (info);
return -ENOMEM;
}
- while (temp) {
- int i;
+ 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) {
@@ -2519,15 +2849,24 @@
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);
+ break;
default:
len += sprintf (info->data + len, "no stat\n");
break;
}
}
}
- temp = temp->next;
}
info->len = len;
+#ifdef MODULE
+ MOD_INC_USE_COUNT;
+#endif
return rc;
}
@@ -2554,6 +2893,11 @@
dasd_devices_write (struct file *file, const char *user_buf, size_t user_len, loff_t * offset)
{
char *buffer = vmalloc (user_len);
+ int off = 0;
+ char *temp;
+ int irq;
+ int j,target;
+ dasd_range_t *rptr, range;
if (buffer == NULL)
return -ENOMEM;
@@ -2563,17 +2907,68 @@
}
buffer[user_len] = 0;
printk (KERN_INFO PRINTK_HEADER "Now executing %s\n", buffer);
- if (!strncmp (buffer, "add range", strlen ("add_range"))) {
-
- } else if (!strncmp (buffer, "enable device", strlen ("enable device"))) {
-
- } else if (!strncmp (buffer, "disable device", strlen ("disable device"))) {
-
- } else {
- printk (KERN_WARNING PRINTK_HEADER "unknown command %s",
- buffer);
- }
- vfree (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++;
+ if (!strncmp (buffer + off, "device", strlen ("device"))) {
+ off += strlen("device");
+ while (!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) );
+ }
+ } 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);
+ }
+ }
return user_len;
}
@@ -2587,6 +2982,9 @@
vfree (p_info->data);
vfree (p_info);
}
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
return rc;
}
@@ -2693,6 +3091,9 @@
}
len += sprintf (info->data + len, "\n");
info->len = len;
+#ifdef MODULE
+ MOD_INC_USE_COUNT;
+#endif
return rc;
}
@@ -2779,26 +3180,44 @@
}
/* SECTION: Initializing the driver */
-
int __init
dasd_init (void)
{
int rc = 0;
int irq;
int j;
- major_info_t *major_info;
+ major_info_t *major_info=NULL;
+ struct list_head *l;
dasd_range_t *range;
printk (KERN_INFO PRINTK_HEADER "initializing...\n");
- for (major_info = dasd_major_info; major_info; major_info = major_info->next) {
+ 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);
} else {
+ 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);
/* revert registration of major infos */
- goto major_failed;
+ goto failed;
}
}
#ifndef MODULE
@@ -2809,57 +3228,77 @@
rc = dasd_proc_init ();
if (rc) {
- goto proc_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;
#ifdef CONFIG_DASD_ECKD
rc = dasd_eckd_init ();
if (rc == 0) {
+ DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
+ "ECKD discipline %s","success");
printk (KERN_INFO PRINTK_HEADER
"Registered ECKD discipline successfully\n");
} else {
- goto eckd_failed;
+ DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
+ "ECKD discipline %s","failed");
+ goto failed;
}
#endif /* CONFIG_DASD_ECKD */
#ifdef CONFIG_DASD_FBA
rc = dasd_fba_init ();
if (rc == 0) {
+ DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
+ "FBA discipline %s","success");
+
printk (KERN_INFO PRINTK_HEADER
"Registered FBA discipline successfully\n");
} else {
- goto fba_failed;
+ DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
+ "FBA discipline %s","failed");
+ goto failed;
}
#endif /* CONFIG_DASD_FBA */
-#ifdef CONFIG_DASD_MDSK
+#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 MDSK discipline successfully\n");
+ "Registered DIAG discipline successfully\n");
} else {
- goto mdsk_failed;
+ DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
+ "DIAG discipline %s","failed");
+ goto failed;
}
}
-#endif /* CONFIG_DASD_MDSK */
+#endif /* CONFIG_DASD_DIAG */
rc = 0;
- 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_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
- NULL, 0);
- }
- }
- if (dasd_autodetect) {
- for (irq = get_irq_first (); irq != -ENODEV; irq = get_irq_next (irq)) {
+ 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_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
- NULL, 0);
- }
+ }
+ }
+ }
+ 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");
@@ -2873,99 +3312,117 @@
for (j = range->from; j <= range->to; j++) {
irq = get_irq_by_devno (j);
if (irq >= 0) {
- dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSED,
+ 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;
-#ifdef CONFIG_DASD_MDSK
- mdsk_failed:
- dasd_diag_cleanup ();
-#endif /* CONFIG_DASD_MDSK */
-#ifdef CONFIG_DASD_FBA
- fba_failed:
- dasd_fba_cleanup ();
-#endif /* CONFIG_DASD_FBA */
-#ifdef CONFIG_DASD_ECKD
- eckd_failed:
- dasd_eckd_cleanup ();
-#endif /* CONFIG_DASD_ECKD */
- proc_failed:
- dasd_proc_cleanup ();
- major_failed:{
- major_info_t * temp;
- for (temp = dasd_major_info;
- temp && (temp != major_info);
- temp = temp->next) {
- dasd_unregister_major (temp);
- }
- }
- dasd_cleanup_emergency_req ();
+ goto out;
+ failed:
printk (KERN_INFO PRINTK_HEADER "initialization not performed due to errors\n");
- out:
+ cleanup_dasd();
+ out:
+ DASD_DRIVER_DEBUG_EVENT(0,dasd_init,"%s","LEAVE");
printk (KERN_INFO PRINTK_HEADER "initialization finished\n");
return rc;
}
-void
+static void
cleanup_dasd (void)
{
- int j, rc = 0;
+ int i,j,rc;
int irq;
- major_info_t *major_info;
+ major_info_t *major_info=NULL;
+ struct list_head *l;
dasd_range_t *range, *next;
printk (KERN_INFO PRINTK_HEADER "shutting down\n");
-
- dasd_proc_cleanup ();
-
+ 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);
}
}
}
- for (major_info = dasd_major_info; major_info; major_info = major_info->next) {
- int i;
+#ifdef CONFIG_DASD_DIAG
+ if (MACHINE_IS_VM) {
+ 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");
+ }
+#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 */
+#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_proc_cleanup ();
+ dasd_cleanup_emergency_req ();
+
+ 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++) {
kfree (major_info->dasd_device[i]);
}
- if ((rc = dasd_unregister_major (major_info)) == 0) {
+ 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);
printk (KERN_INFO PRINTK_HEADER
"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);
printk (KERN_WARNING PRINTK_HEADER
"Couldn't unregister successfully from major no %d rc = %d\n", major_info->gendisk.major, rc);
}
}
- dasd_cleanup_emergency_req ();
+
range = dasd_range_head;
while (range) {
next = range->next;
- kfree (range);
+ 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;
+ }
+#endif /* MODULE */
+ if (dasd_devfs_handle)
+ devfs_unregister(dasd_devfs_handle);
+ if (dasd_debug_area != NULL )
+ debug_unregister(dasd_debug_area);
-#ifdef CONFIG_DASD_DYNAMIC
- {
- dasd_devreg_t *reg;
- while (dasd_devreg_head) {
- reg = dasd_devreg_head->next;
- kfree (dasd_devreg_head);
- dasd_devreg_head = reg;
- }
- }
-#endif /* CONFIG_DASD_DYNAMIC */
printk (KERN_INFO PRINTK_HEADER "shutdown completed\n");
+ DASD_DRIVER_DEBUG_EVENT(0,"cleanup_dasd","%s","LEAVE");
}
#ifdef MODULE
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)