patch-2.2.19 linux/drivers/s390/block/dasd.c
Next file: linux/drivers/s390/block/dasd.h
Previous file: linux/drivers/s390/block/Makefile
Back to the patch index
Back to the overall index
- Lines: 996
- Date:
Sun Mar 25 11:37:35 2001
- Orig file:
v2.2.18/drivers/s390/block/dasd.c
- Orig date:
Sun Mar 25 11:28:27 2001
diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/s390/block/dasd.c linux/drivers/s390/block/dasd.c
@@ -1,9 +1,10 @@
/*
* File...........: linux/drivers/s390/block/dasd.c
* Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ * Horst Hummel <Horst.Hummel@de.ibm.com>
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
-
+ *
* History of changes (starts July 2000)
* 07/03/00 Adapted code to compile with 2.2 and 2.4 kernels
* 07/05/00 Added some missing cases when shutting down a device
@@ -36,8 +37,14 @@
* 10/26/00 fixed ITPM PL010261EPA race condition when formatting
are the fixes in dasd_do_chanq
* 11/21/00 fixed BLKFLSBUF ioctl and dasd_release to flush the buffers
+ * 01/17/01 fixed PL020234MVE problem accessing DASD 68-127, 133-191,...
+ * 01/23/01 fixed sleep_on_request to terminate when signal_pending
+ * 01/25/01 added code for error recovery with PAC'0x1D' = long busy
+ * 02/08/01 fixed PL020237RMI
+ * 02/08/01 fixed PL020265TDI
*/
+#include <linux/module.h>
#include <linux/config.h>
#include <linux/version.h>
#include <linux/init.h>
@@ -96,12 +103,7 @@
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
static struct block_device_operations dasd_device_operations;
#endif /* VERSION_CODE */
-
-#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");
MODULE_SUPPORTED_DEVICE("dasd");
@@ -113,13 +115,8 @@
EXPORT_SYMBOL (dasd_alloc_request);
EXPORT_SYMBOL (dasd_free_request);
-#else
-#endif /* MODULE */
-
/* SECTION: Constant definitions to be used within this file */
-#ifdef PRINTK_HEADER
#undef PRINTK_HEADER
-#endif
#define PRINTK_HEADER DASD_NAME":"
#define DASD_QUEUE_LIMIT 10
@@ -252,7 +249,7 @@
static char dasd_parm_string[1024] = {0,};
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,2,17))
static int
dasd_setup (char *str)
{
@@ -280,7 +277,7 @@
#endif /* LINUX_IS_24 */
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,2,17))
__setup("dasd=", dasd_setup);
#endif /* LINUX_IS_24 */
@@ -476,7 +473,7 @@
* void dasd_chanq_enq (dasd_chanq_t * q, ccw_req_t * cqr)
*/
-static void
+void
dasd_chanq_enq (dasd_chanq_t * q, ccw_req_t * cqr)
{
if (q->head != NULL) {
@@ -493,7 +490,7 @@
* void dasd_chanq_enq_head (dasd_chanq_t * q, ccw_req_t * cqr)
*/
-static void
+void
dasd_chanq_enq_head (dasd_chanq_t * q, ccw_req_t * cqr)
{
cqr->next = q->head;
@@ -501,14 +498,17 @@
if (q->tail == NULL)
q->tail = cqr;
q->queued_requests++;
- atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_FILLED, CQR_STATUS_QUEUED);
+
+ atomic_compare_and_swap_debug (&cqr->status,
+ CQR_STATUS_FILLED,
+ CQR_STATUS_QUEUED);
}
/*
* int dasd_chanq_deq (dasd_chanq_t * q, ccw_req_t * cqr)
*/
-static int
+int
dasd_chanq_deq (dasd_chanq_t * q, ccw_req_t * cqr)
{
ccw_req_t *prev;
@@ -776,9 +776,8 @@
int retries = DASD_SSCH_RETRIES;
dasd_device_t *device = cqr->device;
int irq, devno;
- int devindex, partn;
+ int devindex;
major_info_t *major_info;
- struct request *req;
if (!cqr) {
printk (KERN_WARNING PRINTK_HEADER "No request passed to start_io function");
@@ -786,10 +785,9 @@
}
irq = device->devinfo.irq;
devno = device->devinfo.devno;
- req = (struct request *) cqr->req;
- devindex = devindex_from_kdev_t (req->rq_dev);
+ devindex = devindex_from_devno (devno);
major_info = major_info_from_devindex (devindex);
- partn = MINOR (req->rq_dev) & ((1 << major_info->gendisk.minor_shift) - 1);
+
if (strncmp ((char *) &cqr->magic, device->discipline->ebcname, 4)) {
printk (KERN_WARNING PRINTK_HEADER
"0x%04X on sch %d = /dev/%s (%d:%d)"
@@ -801,10 +799,12 @@
cqr->magic, *(long *) device->discipline->name);
return -EINVAL;
}
- atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_QUEUED, CQR_STATUS_IN_IO);
+ atomic_compare_and_swap_debug (&cqr->status,
+ CQR_STATUS_QUEUED,
+ CQR_STATUS_IN_IO);
do {
asm volatile ("STCK %0":"=m" (cqr->startclk));
- rc = do_IO (irq, cqr->cpaddr, (long) cqr, 0x00, cqr->options);
+ rc = do_IO (irq, cqr->cpaddr, (long) cqr, cqr->lpm, cqr->options);
switch (rc) {
case 0:
if (!(cqr->options & DOIO_WAIT_FOR_INTERRUPT)) {
@@ -848,7 +848,7 @@
if (rc) {
atomic_compare_and_swap_debug (&cqr->status,
CQR_STATUS_IN_IO,
- CQR_STATUS_ERROR);
+ CQR_STATUS_FAILED);
}
return rc;
}
@@ -879,6 +879,10 @@
schedule ();
s390irq_spin_lock_irqsave (device->devinfo.irq, flags);
cs = atomic_read (&req->status);
+ if ( signal_pending(current) ) {
+ rc = -ERESTARTSYS;
+ break;
+ }
} while ( ! (cs & CQR_STATUS_FINISHED) );
/* was originally: while ((cs != CQR_STATUS_DONE) && (cs != CQR_STATUS_FAILED)); */
remove_wait_queue (&device->wait_q, &wait);
@@ -1178,189 +1182,216 @@
printk (KERN_WARNING PRINTK_HEADER
" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
" Failing to start I/O operation with rc %d\n",
- devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, rc);
+ devno, irq, device->name, major_from_devindex (devindex),
+ devindex << DASD_PARTN_BITS, rc);
switch (rc) {
case EBUSY:
if (cqr->retries--) {
printk (KERN_WARNING PRINTK_HEADER
" devno 0x%04X on subchannel %d = /dev/%s (%d:%d) busy:"
" retrying ... %d retries left\n",
- devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, cqr->retries);
+ devno, irq, device->name, major_from_devindex (devindex),
+ devindex << DASD_PARTN_BITS, cqr->retries);
break;
}
default:{ /* Fallthrough ?? */
printk (KERN_WARNING PRINTK_HEADER
" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
" Giving up this request!\n",
- devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
-
- atomic_compare_and_swap_debug (&cqr->status,
- CQR_STATUS_QUEUED,
- CQR_STATUS_FAILED | CQR_STATUS_FINISHED);
+ devno, irq, device->name, major_from_devindex (devindex),
+ devindex << DASD_PARTN_BITS);
break;
}
}
}
break;
case CQR_STATUS_IN_IO:{
- unsigned long long now;
- unsigned long long delta;
-
- asm volatile ("STCK %0":"=m" (now));
- if (cqr->expires && cqr->startclk &&
- cqr->expires < now) {
- delta = cqr->expires - cqr->startclk;
- printk (KERN_ERR PRINTK_HEADER
- " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
- " I/O operation outstanding longer than 0x%08x%08x usecs on req %p\n",
- devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, (long)(delta >> 44), (long)(delta >> 12), cqr);
- cqr->expires += delta;
+ unsigned long long now;
+ unsigned long long delta;
+
+ asm volatile ("STCK %0":"=m" (now));
+ if (cqr->expires && cqr->startclk &&
+ cqr->expires < now) {
+ delta = cqr->expires - cqr->startclk;
+ printk (KERN_ERR PRINTK_HEADER
+ " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+ " I/O operation outstanding longer than 0x%08lx%08lx usecs on req %p\n",
+ devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, (long)(delta >> 44), (long)(delta >> 12), cqr);
+ cqr->expires += delta;
#if 0
- if ( cqr->retries-- ) {
- printk (KERN_WARNING PRINTK_HEADER
- " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
- " waiting %d more times\n",
- devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, cqr->retries);
- cqr->expires += delta;
- break;
- } else {
- printk (KERN_WARNING PRINTK_HEADER
- " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
- " You should disable that device by issueing '@#?!'\n", /* FIXME */
- devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
- atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_FAILED);
- halt_IO(irq,(unsigned long)cqr, DOIO_WAIT_FOR_INTERRUPT);
- break;
- }
+ if ( cqr->retries-- ) {
+ printk (KERN_WARNING PRINTK_HEADER
+ " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+ " waiting %d more times\n",
+ devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, cqr->retries);
+ cqr->expires += delta;
+ break;
+ } else {
+ printk (KERN_WARNING PRINTK_HEADER
+ " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+ " You should disable that device by issueing '@#?!'\n", /* FIXME */
+ devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
+ atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_FAILED);
+ halt_IO(irq,(unsigned long)cqr, DOIO_WAIT_FOR_INTERRUPT);
+ break;
+ }
#endif
- }
- break;
+ }
+ break;
}
case CQR_STATUS_ERROR:{
- dasd_erp_action_fn_t erp_action;
- ccw_req_t *erp_cqr = NULL;
-
- if (cqr->dstat->flag & DEVSTAT_HALT_FUNCTION) {
- atomic_compare_and_swap_debug(&cqr->status,CQR_STATUS_ERROR,CQR_STATUS_FAILED);
- next = cqr;
- } else if ( cqr -> retries-- &&
- cqr -> refers == NULL &&
- discipline -> erp_action != NULL &&
- (erp_action = discipline->erp_action (cqr)) != NULL &&
- (erp_cqr = erp_action (cqr)) != NULL ) {
+ dasd_erp_action_fn_t erp_action;
+ ccw_req_t *erp_cqr = NULL;
+
+ if (cqr->dstat->flag & DEVSTAT_HALT_FUNCTION) {
+ atomic_compare_and_swap_debug(&cqr->status,
+ CQR_STATUS_ERROR,
+ CQR_STATUS_FAILED);
+ next = cqr;
+ } else if (discipline -> erp_action != NULL &&
+ (erp_action = discipline->erp_action (cqr)) != NULL &&
+ (erp_cqr = erp_action (cqr)) != NULL ) {
+
+ if (erp_cqr != cqr){
+
dasd_chanq_enq_head (qp, erp_cqr);
- next = erp_cqr; /* prefer execution of erp ccw */
- } else {
- atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED);
- next = cqr;
}
- break;
- }
+ cqr->retries--;
+ next = erp_cqr; /* prefer execution of erp ccw */
+
+ } else {
+ atomic_compare_and_swap_debug (&cqr->status,
+ CQR_STATUS_ERROR,
+ CQR_STATUS_FAILED);
+ next = cqr;
+ }
+ break;
+ }
case CQR_STATUS_DONE:{
- dasd_erp_postaction_fn_t erp_postaction;
- next = cqr->next;
- asm volatile ("STCK %0":"=m" (cqr->endclk));
- if (cqr->refers && cqr->function) { /* we deal with an ERP */
- if ( discipline->erp_postaction &&
- ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) {
- printk (KERN_WARNING PRINTK_HEADER
- " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
- " postprocessing successful error recovery action using %p\n",
- devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, erp_postaction);
- erp_postaction (cqr, 1);
- } else {
- printk (KERN_WARNING PRINTK_HEADER
- " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
- " No procedure to postprocess error recovery action"
- " giving up request",
- devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
- atomic_compare_and_swap_debug (&cqr->refers->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED);
- }
+ dasd_erp_postaction_fn_t erp_postaction;
+ next = cqr->next;
+ asm volatile ("STCK %0":"=m" (cqr->endclk));
+ if (cqr->refers && cqr->function) { /* we deal with an ERP */
+ if ( discipline->erp_postaction &&
+ ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) {
+ printk (KERN_WARNING PRINTK_HEADER
+ " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+ " postprocessing successful ERA using %p\n",
+ devno, irq, device->name, major_from_devindex (devindex),
+ devindex << DASD_PARTN_BITS, erp_postaction);
+ cqr = erp_postaction (cqr);
+ next = cqr;
+ } else {
+ printk (KERN_WARNING PRINTK_HEADER
+ " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+ " No procedure to postprocess ERA - "
+ " giving up request",
+ devno, irq, device->name, major_from_devindex (devindex),
+ devindex << DASD_PARTN_BITS);
+ atomic_compare_and_swap_debug (&cqr->refers->status,
+ CQR_STATUS_ERROR,
+ CQR_STATUS_FAILED);
+
atomic_dec (&device->queue.dirty_requests);
dasd_chanq_deq (&device->queue, cqr);
dasd_free_request(cqr); /* Only free request if nobody is waiting on it */
- } else if ( cqr->req ) {
- dasd_end_request (cqr->req, 1);
+ }
+ } else if ( cqr->req ) {
+ dasd_end_request (cqr->req, 1);
#ifdef DASD_PROFILE
- dasd_profile_add (cqr);
+ dasd_profile_add (cqr);
#endif /* DASD_PROFILE */
- dasd_chanq_deq (&device->queue, cqr);
- dasd_free_request(cqr); /* Only free request if nobody is waiting on it */
- } else {
- /* during format we don't have the request structure */
- /* notify sleeping task about finished postprocessing */
- atomic_compare_and_swap_debug (&cqr->status,
- CQR_STATUS_DONE,
- CQR_STATUS_DONE | CQR_STATUS_FINISHED);
- dasd_chanq_deq (&device->queue, cqr);
+ dasd_chanq_deq (&device->queue, cqr);
+ dasd_free_request(cqr); /* Only free request if nobody is waiting on it */
+ } else {
+ /* during format we don't have the request structure */
+ /* notify sleeping task about finished postprocessing */
+ atomic_compare_and_swap_debug (&cqr->status,
+ CQR_STATUS_DONE,
+ CQR_STATUS_DONE | CQR_STATUS_FINISHED);
+ dasd_chanq_deq (&device->queue, cqr);
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
- wake_up (&device->wait_q);
+ wake_up (&device->wait_q);
#else
- if (device->wait_q) {
- wake_up (&device->wait_q);
- }
-#endif /* LINUX_IS_24 */
+ if (device->wait_q) {
+ wake_up (&device->wait_q);
}
- break;
- }
+#endif /* LINUX_IS_24 */
+ }
+ break;
+ }
case CQR_STATUS_FAILED:{
- dasd_erp_postaction_fn_t erp_postaction;
- next = cqr->next;
- asm volatile ("STCK %0":"=m" (cqr->endclk));
- if (cqr->refers && cqr->function) { /* we deal with an ERP */
- if ( discipline->erp_postaction &&
- ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) {
- printk (KERN_WARNING PRINTK_HEADER
- " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
- " postprocessing unsuccessful error recovery action using %p\n",
- devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, erp_postaction);
- erp_postaction (cqr, 0);
- } else {
- printk (KERN_WARNING PRINTK_HEADER
- " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
- " No procedure to postprocess unsuccessful error recovery action"
- " giving up request",
- devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
- atomic_compare_and_swap_debug (&cqr->refers->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED);
- }
+ dasd_erp_postaction_fn_t erp_postaction;
+ next = cqr->next;
+ asm volatile ("STCK %0":"=m" (cqr->endclk));
+ if (cqr->refers && cqr->function) { /* we deal with an ERP */
+ if ( discipline->erp_postaction &&
+ ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) {
+ printk (KERN_WARNING PRINTK_HEADER
+ " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+ " postprocessing unsuccessful ERA using %p\n",
+ devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, erp_postaction);
+ cqr = erp_postaction (cqr);
+ next = cqr;
+ } else {
+ printk (KERN_WARNING PRINTK_HEADER
+ " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+ " No procedure to postprocess unsuccessful ERA - "
+ " giving up request",
+ devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
+ atomic_compare_and_swap_debug (&cqr->refers->status,
+ CQR_STATUS_ERROR,
+ CQR_STATUS_FAILED);
+
atomic_dec (&device->queue.dirty_requests);
dasd_chanq_deq (&device->queue, cqr);
dasd_free_request(cqr); /* Only free request if nobody is waiting on it */
- } else if (cqr->req) {
- dasd_end_request (cqr->req, 0);
+ }
+ } else if (cqr->req) {
+ dasd_end_request (cqr->req, 0);
#ifdef DASD_PROFILE
- dasd_profile_add (cqr);
+ dasd_profile_add (cqr);
#endif /* DASD_PROFILE */
- dasd_chanq_deq (&device->queue, cqr);
- dasd_free_request(cqr); /* Only free request if nobody is waiting on it */
- } else {
- /* during format we don't have the request structure */
- /* notify sleeping task about finished postprocessing */
- atomic_compare_and_swap_debug (&cqr->status,
- CQR_STATUS_FAILED,
- CQR_STATUS_FAILED | CQR_STATUS_FINISHED);
-
- dasd_chanq_deq (&device->queue, cqr);
+ dasd_chanq_deq (&device->queue, cqr);
+ dasd_free_request(cqr); /* Only free request if nobody is waiting on it */
+ } else {
+ /* during format we don't have the request structure */
+ /* notify sleeping task about finished postprocessing */
+ atomic_compare_and_swap_debug (&cqr->status,
+ CQR_STATUS_FAILED,
+ CQR_STATUS_FAILED | CQR_STATUS_FINISHED);
+
+ dasd_chanq_deq (&device->queue, cqr);
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
- wake_up (&device->wait_q);
+ wake_up (&device->wait_q);
#else
- if (device->wait_q) {
- wake_up (&device->wait_q);
- }
+ if (device->wait_q) {
+ wake_up (&device->wait_q);
+ }
#endif /* LINUX_IS_24 */
- }
- break;
- }
+ }
+ break;
+ }
- default:{
- printk (KERN_WARNING PRINTK_HEADER
- "Internal error in " __FILE__ " on line %d."
- " inconsistent content of ccw_req_t"
- " cqrstatus = %d"
- " Pls send this message and your System.map to"
- " linux390@de.ibm.com\n",
- __LINE__, cqrstatus);
- }
+ case CQR_STATUS_PENDING:
+ /* just wait */
+ printk (KERN_WARNING PRINTK_HEADER
+ " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+ " CQR_STATUS_PENDING - just wait...\n",
+ devno, irq, device->name,
+ major_from_devindex (devindex),
+ devindex << DASD_PARTN_BITS);
+ break;
+
+ default:
+ printk (KERN_WARNING PRINTK_HEADER
+ "Internal error in " __FILE__ " on line %d."
+ " inconsistent content of ccw_req_t"
+ " cqrstatus = %d"
+ " Pls send this message and your System.map to"
+ " linux390@de.ibm.com\n",
+ __LINE__, cqrstatus);
+
}
s390irq_spin_unlock_irqrestore (irq, flags);
} while ((cqr = next) != NULL);
@@ -1369,6 +1400,56 @@
return;
}
+/*
+ * 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' and the bh is
+ * scheduled.
+ *
+ * PARAMETER
+ * stat device status of state change pending interrupt.
+ */
+void
+dasd_handle_state_change_pending (devstat_t *stat)
+{
+ dasd_device_t *device;
+ ccw_req_t *cqr;
+ int devindex;
+
+ devindex = devindex_from_devno (stat->devno);
+ if (devindex < 0) {
+ return;
+ }
+
+ device = find_dasd_device (devindex);
+ if (device == NULL) {
+ return;
+ }
+
+ /* re-activate first request in queue */
+ cqr = device->queue.head;
+
+ if (cqr != NULL &&
+ atomic_read(&cqr->status) == CQR_STATUS_PENDING ) {
+ dasd_device_t *device = cqr->device;
+
+ DASD_MESSAGE (KERN_INFO, device,
+ "%s",
+ "device request queue restarted by "
+ "SCP interrupt\n");
+
+ del_timer(&device->timer);
+ atomic_compare_and_swap_debug (&cqr->status,
+ CQR_STATUS_PENDING,
+ CQR_STATUS_QUEUED);
+ dasd_schedule_bh();
+ }
+} /* end dasd_handle_state_change_pending */
+
void
dasd_int_handler (int irq, void *ds, struct pt_regs *regs)
{
@@ -1380,8 +1461,7 @@
dasd_device_t *device;
int devno = -1, devindex = -1;
-#undef ERP_DEBUG
-#ifdef ERP_DEBUG
+#ifdef ERP_DEBUG /* #define ERP_DEBUG is done in dasd.h */
static int counter = 0;
#endif
@@ -1389,12 +1469,23 @@
PRINT_ERR ("handler called without devstat");
return;
}
+
ip = stat->intparm;
if (!ip) { /* no intparm: unsolicited interrupt */
PRINT_INFO ("%04X caught unsolicited interrupt\n",
stat->devno);
+
+ /* 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;
}
+
if (ip & 0x80000001) {
PRINT_INFO ("%04X caught spurious interrupt with parm %08x\n",
stat->devno, ip);
@@ -1436,20 +1527,63 @@
return;
}
asm volatile ("STCK %0":"=m" (cqr->stopclk));
- if ((!(stat->flag & DEVSTAT_HALT_FUNCTION) &&
- stat->cstat == 0x00 &&
- stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) ||
- (device->discipline->examine_error &&
- (era = device->discipline->examine_error (cqr, stat)) == dasd_era_none)) {
#ifdef ERP_DEBUG
- if ( ++counter % 137 == 0 ) {
- printk ( KERN_INFO PRINTK_HEADER "Faking I/O error to recover from\n");
+ if ((++counter % 937 >= 100) &&
+ ( counter % 937 <= 110) &&
+ ( 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;
- goto error_fake_done;
+// reset notification
+ {
+ char *sense = stat->ii.sense.data;
+ char buffer[100];
+ memset(sense,0,32);
+ sprintf(buffer,"CPU ALL TR IO %X INST INT CCW", devno);
+ cpcmd(buffer,NULL,NULL);
+ sense[0]=0x10;
+ sense[4]=0x21;
+ sense[7]=0x9;
+ sense[15]=0x4;
+ sense[16]=0xe5;
+ sense[18]=0x43;
+ sense[19]=0xfb;
+ sense[20]=0x54;
+ sense[22]=0x0f;
+ sense[23]=0x09;
+ sense[26]=0x40;
+ sense[27]=0xe0;
+ }
+// 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;
+// }
}
#endif
+
+ if ((!(stat->flag & DEVSTAT_HALT_FUNCTION) &&
+ stat->cstat == 0x00 &&
+ stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) ||
+ (device->discipline->examine_error &&
+ (era = device->discipline->examine_error (cqr, stat)) == dasd_era_none)) {
+
atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_DONE);
atomic_compare_and_swap (DASD_DEVICE_LEVEL_ANALYSIS_PENDING,
DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
@@ -1462,9 +1596,6 @@
}
}
} else { /* only visited in case of error ! */
-#ifdef ERP_DEBUG
- error_fake_done:
-#endif
if (cqr->dstat == NULL)
cqr->dstat = kmalloc (sizeof (devstat_t), GFP_ATOMIC);
if (cqr->dstat) {
@@ -1512,7 +1643,12 @@
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);
+ if ( !erp ) {
+ printk(KERN_WARNING PRINTK_HEADER
+ "unable to allocate ERP request\n");
+ return NULL;
+ }
erp->cpaddr->cmd_code = CCW_CMD_TIC;
erp->cpaddr->cda = (__u32)cqr -> cpaddr;
@@ -1528,30 +1664,97 @@
return erp;
}
-int
-default_erp_postaction (ccw_req_t * cqr, int success)
+/*
+ * DEFAULT_ERP_POSTACTION
+ *
+ * DESCRIPTION
+ * 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.
+ *
+ * PARAMETER
+ * erp current erp_head
+ *
+ * RETURN VALUES
+ * cqr pointer to the original CQR
+ */
+ccw_req_t *
+default_erp_postaction (ccw_req_t * erp)
{
- if (cqr->refers == NULL || cqr->function == NULL) {
- printk (KERN_WARNING PRINTK_HEADER
- "ERP postaction called for non ERP cqr\n");
- return -EINVAL;
+ ccw_req_t *cqr = NULL, *free_erp = NULL;
+ dasd_device_t *device = NULL;
+ int success;
+
+ device = (dasd_device_t *) (erp->device);
+
+ if (atomic_read(&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) {
+ panic (PRINTK_HEADER "Programming error in ERP! Postaction called "
+ "for invalid ERPt\n");
+ }
+
+ /* free all ERPs - but NOT the original cqr */
+ 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;
+
+ /* set corresponding status to original cqr */
+ if (success) {
+ atomic_compare_and_swap_debug (&cqr->status,
+ CQR_STATUS_ERROR,
+ CQR_STATUS_DONE);
+ } else {
+ atomic_compare_and_swap_debug (&cqr->status,
+ CQR_STATUS_ERROR,
+ CQR_STATUS_FAILED);
}
- if (cqr->function != default_erp_action) {
- printk (KERN_WARNING PRINTK_HEADER
- "default ERP postaction called for non default ERP cqr\n");
- return -EINVAL;
+
+#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);
+ }
}
- if ( success ) {
- atomic_compare_and_swap_debug (&cqr->refers->status,
- CQR_STATUS_ERROR,
- CQR_STATUS_DONE);
- } else {
- atomic_compare_and_swap_debug (&cqr->refers->status,
- CQR_STATUS_ERROR,
- CQR_STATUS_FAILED);
- }
- return 0;
-}
+#endif /* ERP_DEBUG */
+
+ return cqr;
+} /* end default_erp_postaction */
/* SECTION: The helpers of the struct file_operations */
@@ -1641,7 +1844,7 @@
while ((!rc ) &&
((req = device->discipline->format_device (device, &temp)) != NULL ) ) {
- if ( rc=sleep_on_req(req) ) {
+ if ( (rc=sleep_on_req(req)) != 0 ) {
printk (KERN_WARNING PRINTK_HEADER
" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
" Formatting failed with rc = %d\n",
@@ -1985,10 +2188,6 @@
major_info_t *major_info = NULL;
major_info = kmalloc (sizeof (major_info_t), GFP_KERNEL);
if (major_info) {
- major_info_t *temp = dasd_major_info;
- while (temp->next)
- temp = temp->next;
- temp->next = major_info;
memset (major_info, 0, sizeof (major_info_t));
major_info->read_ahead = 8;
@@ -1998,7 +2197,8 @@
major_info->gendisk.minor_shift = DASD_PARTN_BITS;
major_info->gendisk.max_p = 1 << DASD_PARTN_BITS;
#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
- major_info->gendisk.max_nr= 1 << DASD_PARTN_BITS;
+ /* HSM changed for PL020234MVE */
+ major_info->gendisk.max_nr= DASD_PER_MAJOR;
#endif /* LINUX_IS_24 */
major_info->gendisk.nr_real=DASD_PER_MAJOR;
}
@@ -2013,6 +2213,7 @@
#endif /* LINUX_IS_24 */
int rc = 0;
int major;
+ int need_insert=0;
if (major_info == NULL) {
major_info = get_new_major_info ();
@@ -2024,6 +2225,7 @@
printk (KERN_INFO PRINTK_HEADER
"Created another major number\n");
}
+ need_insert=1; //insert new major info into dasd_major_info later
}
major = major_info->gendisk.major;
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
@@ -2052,6 +2254,13 @@
}
}
+ /* Insert the new major info into dasd_major_info if needed */
+ if (need_insert) {
+ major_info_t *temp = dasd_major_info;
+ while (temp->next)
+ temp = temp->next;
+ temp->next = major_info;
+ }
major_info->dasd_device = (dasd_device_t **) kmalloc( DASD_PER_MAJOR * sizeof(dasd_device_t*),
GFP_ATOMIC);
memset ( major_info->dasd_device ,0,DASD_PER_MAJOR * sizeof(dasd_device_t*));
@@ -2153,15 +2362,15 @@
index = devindex_from_kdev_t (MKDEV(hd->major,index<<hd->minor_shift));
}
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) {
@@ -2307,6 +2516,7 @@
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
init_waitqueue_head(&device->wait_q);
#endif /* KERNEL_VERSION */
+ init_timer(&device->timer);
minor = MINOR(device->kdev);
current_level = atomic_read (&device->level);
if (desired_level > current_level) {
@@ -2412,7 +2622,7 @@
if (major_info->blksize_size[minor + i] < 1024 )
major_info->blksize_size[minor + i] = 1024;
- major_info->max_sectors[minor + i] = 200 << device->sizes.s2b_shift; /* FIXME !!! */
+ major_info->max_sectors[minor + i] = device->discipline->max_blocks << device->sizes.s2b_shift;
}
atomic_compare_and_swap_debug (&device->level,
DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
@@ -2509,6 +2719,14 @@
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
@@ -2521,7 +2739,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;
@@ -2604,6 +2823,9 @@
temp = temp->next;
}
info->len=len;
+#ifdef MODULE
+ MOD_INC_USE_COUNT;
+#endif
return rc;
}
@@ -2661,6 +2883,9 @@
if ( p_info->data ) vfree(p_info->data);
vfree(p_info);
}
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
return rc;
}
@@ -2858,9 +3083,7 @@
dasd_unregister_major(major_info);
}
}
- emergency_failed:
dasd_cleanup_emergency_req();
- failed:
printk (KERN_INFO PRINTK_HEADER "initialization not performed due to errors\n");
out:
printk (KERN_INFO PRINTK_HEADER "initialization finished\n");
@@ -2924,9 +3147,7 @@
int
init_module ( void )
{
- int rc=0;
return dasd_init();
- return rc;
}
void
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)