patch-2.4.8 linux/drivers/s390/s390io.c
Next file: linux/drivers/s390/s390mach.c
Previous file: linux/drivers/s390/s390dyn.c
Back to the patch index
Back to the overall index
- Lines: 2728
- Date:
Wed Jul 25 14:12:02 2001
- Orig file:
v2.4.7/linux/drivers/s390/s390io.c
- Orig date:
Wed Jul 25 17:10:22 2001
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/s390io.c linux/drivers/s390/s390io.c
@@ -15,6 +15,11 @@
* decrease retry2 on busy while
* disabling sync_isc; reset isc_cnt
* on io error during sync_isc enablement
+ * 05/09/2001 Cornelia Huck added exploitation of debug feature
+ * 05/16/2001 Cornelia Huck added /proc/deviceinfo/<devno>/
+ * 05/22/2001 Cornelia Huck added /proc/cio_ignore
+ * un-ignore blacklisted devices by piping
+ * to /proc/cio_ignore
*/
#include <linux/module.h>
@@ -24,7 +29,7 @@
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/string.h>
#include <linux/smp.h>
#include <linux/threads.h>
@@ -49,6 +54,7 @@
#include <asm/s390io.h>
#include <asm/s390dyn.h>
#include <asm/s390mach.h>
+#include <asm/debug.h>
#ifndef TRUE
#define TRUE 1
@@ -79,10 +85,17 @@
static __u64 irq_IPL_TOD;
static adapter_int_handler_t adapter_handler = NULL;
+/* for use of debug feature */
+debug_info_t *cio_debug_msg_id = NULL;
+debug_info_t *cio_debug_trace_id = NULL;
+debug_info_t *cio_debug_crw_id = NULL;
+int cio_debug_initialized = 0;
+
static void init_IRQ_handler( int irq, void *dev_id, struct pt_regs *regs);
static void s390_process_subchannels( void);
static void s390_device_recognition_all( void);
static void s390_device_recognition_irq( int irq);
+static void s390_redo_validation(void);
static int s390_validate_subchannel( int irq, int enable);
static int s390_SenseID( int irq, senseid_t *sid, __u8 lpm);
static int s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid);
@@ -91,7 +104,7 @@
static int enable_subchannel( unsigned int irq);
static int disable_subchannel( unsigned int irq);
-void chan_proc_init( void );
+static int chan_proc_init( void );
static inline void do_adapter_IO( __u32 intparm );
@@ -105,6 +118,16 @@
asmlinkage void do_IRQ( struct pt_regs regs );
+#define MAX_CIO_PROCFS_ENTRIES 0x300
+/* magic number; we want to have some room to spare */
+
+int cio_procfs_device_create(int devno);
+int cio_procfs_device_remove(int devno);
+int cio_procfs_device_purge(void);
+
+int cio_notoper_msg = 1;
+int cio_proc_devinfo = 0; /* switch off the /proc/deviceinfo/ stuff by default
+ until problems are dealt with */
/*
* "Blacklisting" of certain devices:
@@ -123,6 +146,7 @@
static dev_blacklist_range_t *dev_blacklist_range_head = NULL; /* Anchor for list of ranges */
static spinlock_t blacklist_lock = SPIN_LOCK_UNLOCKED;
+static int nr_blacklisted_ranges = 0;
/* Handling of the blacklist ranges */
@@ -133,7 +157,16 @@
static inline dev_blacklist_range_t *blacklist_range_create( int from, int to)
{
dev_blacklist_range_t *range = NULL;
- range = ( dev_blacklist_range_t *) alloc_bootmem( sizeof( dev_blacklist_range_t ) );
+
+ if (to && (from>to)) {
+ printk("Invalid blacklist range %x to %x, skipping\n", from, to);
+ return NULL;
+ }
+ if (init_IRQ_complete) {
+ range = ( dev_blacklist_range_t *) kmalloc( sizeof( dev_blacklist_range_t ), GFP_KERNEL);
+ } else {
+ range = ( dev_blacklist_range_t *) alloc_bootmem( sizeof( dev_blacklist_range_t ) );
+ }
if (range == NULL)
return NULL;
memset( range, 0, sizeof( dev_blacklist_range_t ));
@@ -143,6 +176,7 @@
} else {
range->to = to;
}
+ nr_blacklisted_ranges++;
return range;
}
@@ -153,7 +187,12 @@
static inline void blacklist_range_destroy( dev_blacklist_range_t *range )
{
- kfree( range );
+ nr_blacklisted_ranges--;
+ /*
+ * FIXME: the memory was allocated as bootmem,
+ * how to get it free again ?!
+ */
+ /* kfree( range ); */
}
/*
@@ -207,7 +246,7 @@
/*
* Function: blacklist_range_add
* Creates a range from the specified arguments and appends it to the list of
- * blacklisted devices
+ * blacklisted devices
*/
static inline dev_blacklist_range_t *blacklist_range_add( int from, int to )
@@ -342,6 +381,9 @@
#ifdef CONFIG_DEBUG_IO
printk( "Reading blacklist...\n");
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 6,
+ "Reading blacklist\n");
blacklist_split_parm_string( blacklist_parm_string );
blacklist_parse( blacklist );
}
@@ -366,6 +408,9 @@
#ifdef CONFIG_DEBUG_IO
printk( "Reading blacklist parameters...\n" );
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 6,
+ "Reading blacklist parameters\n");
blacklist_setup(str,&dummy);
blacklist_init(); /* Blacklist ranges must be ready when device recognition starts */
@@ -401,10 +446,107 @@
return 0;
}
+/*
+ * Function: blacklist_free_all_ranges
+ * set all blacklisted devices free...
+ */
+
+void blacklist_free_all_ranges(void)
+{
+ dev_blacklist_range_t *tmp = dev_blacklist_range_head;
+
+ while (tmp) {
+ blacklist_range_dechain(tmp);
+ blacklist_range_destroy(tmp);
+ tmp = dev_blacklist_range_head;
+ }
+}
+
+/*
+ * Function: blacklist_parse_proc_parameters
+ * parse the stuff which is piped to /proc/cio_ignore
+ */
+void blacklist_parse_proc_parameters(char *buf)
+{
+ char *tmp;
+ int i;
+ char *end;
+ int len = -1;
+ char *param;
+ int from = 0;
+ int to = 0;
+ int changed = 0;
+ dev_blacklist_range_t *range, *temp;
+
+ tmp = buf;
+ if (strstr(tmp, "free ")) {
+ for (i=0; i<5; i++) {
+ tmp++;
+ }
+ if (strstr(tmp, "all")) {
+ blacklist_free_all_ranges();
+ s390_redo_validation();
+ } else {
+ while (tmp != NULL) {
+ end = strchr(tmp, ',');
+ if (end == NULL) {
+ len = strlen(tmp) + 1;
+ } else {
+ len = (long)end - (long) tmp + 1;
+ *end = '\0';
+ end++;
+ }
+ param = (char*) kmalloc(len * sizeof(char) + 1, GFP_KERNEL);
+ strncpy(param, (const char *) tmp, len);
+ tmp = end;
+ from = blacklist_strtoul(param, ¶m);
+ if (*param == '-') {
+ param++;
+ to = blacklist_strtoul(param, ¶m);
+ } else {
+ to = from;
+ }
+ range = dev_blacklist_range_head;
+ while (range != NULL) {
+ temp = range->next;
+ if ((from <= range->from) && (to >= range->to)) {
+ blacklist_range_dechain(range);
+ blacklist_range_destroy(range);
+ changed = 1;
+ } else if ((from <= range->from) && (to>=range->from) && (to < range->to)) {
+ blacklist_range_add(to+1, range->to);
+ blacklist_range_dechain(range);
+ blacklist_range_destroy(range);
+ changed = 1;
+ } else if ((from > range->from) && (from<=range->to) && (to >= range->to)) {
+ blacklist_range_add(range->from, from-1);
+ blacklist_range_dechain(range);
+ blacklist_range_destroy(range);
+ changed = 1;
+ } else if ((from > range->from) && (to < range->to)) {
+ blacklist_range_add(range->from, from-1);
+ blacklist_range_add(to+1, range->to);
+ blacklist_range_dechain(range);
+ blacklist_range_destroy(range);
+ changed = 1;
+ }
+ range = temp;
+ }
+ kfree(param);
+ }
+ if (changed)
+ s390_redo_validation();
+ }
+ } else {
+ printk("cio_ignore: Parse error; try using 'free all|<devno-range>,<devno-range>,...'\n");
+ }
+}
+
/* End of blacklist handling */
void s390_displayhex(char *str,void *ptr,s32 cnt);
+void s390_displayhex2(char *str, void *ptr, s32 cnt, int level);
void s390_displayhex(char *str,void *ptr,s32 cnt)
{
@@ -425,6 +567,23 @@
}
}
+void s390_displayhex2(char *str, void *ptr, s32 cnt, int level)
+{
+ s32 cnt1, cnt2, maxcnt2;
+ u32 *currptr = (__u32 *)ptr;
+
+ debug_sprintf_event(cio_debug_msg_id, level, "%s\n", str);
+
+ for (cnt1 = 0; cnt1<cnt; cnt1+=16) {
+ debug_sprintf_event(cio_debug_msg_id, level, "%08lX ", (unsigned long)currptr);
+ maxcnt2 = cnt - cnt1;
+ if (maxcnt2 > 16)
+ maxcnt2 = 16;
+ for (cnt2 = 0; cnt2 < maxcnt2; cnt2 += 4)
+ debug_sprintf_event(cio_debug_msg_id, level, "%08X ", *currptr++);
+ }
+}
+
static int __init cio_setup( char *parm )
{
if ( !strcmp( parm, "yes") )
@@ -446,6 +605,35 @@
__setup("cio_msg=", cio_setup);
+static int __init cio_notoper_setup(char *parm)
+{
+ if (!strcmp(parm, "yes")) {
+ cio_notoper_msg = 1;
+ } else if (!strcmp(parm, "no")) {
+ cio_notoper_msg = 0;
+ } else {
+ printk("cio_notoper_setup: invalid cio_notoper_msg parameter '%s'", parm);
+ }
+
+ return 1;
+}
+
+__setup("cio_notoper_msg=", cio_notoper_setup);
+
+static int __init cio_proc_devinfo_setup(char *parm)
+{
+ if (!strcmp(parm, "yes")) {
+ cio_proc_devinfo = 1;
+ } else if (!strcmp(parm, "no")) {
+ cio_proc_devinfo = 0;
+ } else {
+ printk("cio_proc_devinfo_setup: invalid parameter '%s'\n",parm);
+ }
+
+ return 1;
+}
+
+__setup("cio_proc_devinfo=", cio_proc_devinfo_setup);
/*
* register for adapter interrupts
@@ -461,6 +649,9 @@
int s390_register_adapter_interrupt( adapter_int_handler_t handler )
{
int ret = 0;
+
+ if (cio_debug_initialized)
+ debug_text_event(cio_debug_trace_id, 4, "rgaint");
spin_lock( &adapter_lock );
@@ -480,6 +671,9 @@
int s390_unregister_adapter_interrupt( adapter_int_handler_t handler )
{
int ret = 0;
+
+ if (cio_debug_initialized)
+ debug_text_event(cio_debug_trace_id, 4, "urgaint");
spin_lock( &adapter_lock );
@@ -497,6 +691,9 @@
static inline void do_adapter_IO( __u32 intparm )
{
+ if (cio_debug_initialized)
+ debug_text_event(cio_debug_trace_id, 4, "doaio");
+
spin_lock( &adapter_lock );
if ( adapter_handler )
@@ -507,7 +704,6 @@
return;
}
-
int s390_request_irq_special( int irq,
io_handler_func_t io_handler,
not_oper_handler_func_t not_oper_handler,
@@ -517,6 +713,7 @@
{
int retval = 0;
unsigned long flags;
+ char dbf_txt[15];
if (irq >= __MAX_SUBCHANNELS)
return -EINVAL;
@@ -528,6 +725,12 @@
return -ENODEV;
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 4, "reqsp");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+ }
+
/*
* The following block of code has to be executed atomically
*/
@@ -598,6 +801,7 @@
int ret;
unsigned int count = 0;
+ char dbf_txt[15];
if ( irq >= __MAX_SUBCHANNELS || ioinfo[irq] == INVALID_STORAGE_AREA )
{
@@ -605,6 +809,12 @@
} /* endif */
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 2, "free");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 2, dbf_txt);
+ }
+
s390irq_spin_lock_irqsave( irq, flags);
#ifdef CONFIG_KERNEL_DEBUG
@@ -614,6 +824,8 @@
} /* endif */
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2, "Trying to free IRQ %d\n", irq);
/*
* disable the device and reset all IRQ info if
@@ -687,6 +899,10 @@
"count exceeded\n",
irq,
ioinfo[irq]->devstat.devno);
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 0,
+ "free_irq(%04X) - device %04X busy, retry count exceeded\n",
+ irq, ioinfo[irq]->devstat.devno);
} /* endif */
@@ -710,7 +926,10 @@
s390irq_spin_unlock_irqrestore( irq, flags);
printk( "free_irq(%04X) : error, "
- "dev_id does not match !", irq);
+ "dev_id does not match !\n", irq);
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 0,
+ "free_irq(%04X) : error, dev_id does not match !\n", irq);
} /* endif */
@@ -721,6 +940,9 @@
printk( "free_irq(%04X) : error, "
"no action block ... !\n", irq);
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 0,
+ "free_irq(%04X) : error, no action block ... !\n", irq);
} /* endif */
@@ -733,6 +955,7 @@
{
unsigned long flags;
int ret;
+ char dbf_txt[15];
if ( ioinfo[irq] == INVALID_STORAGE_AREA )
return( -ENODEV);
@@ -740,6 +963,12 @@
if ( !ioinfo[irq]->ui.flags.ready )
return -ENODEV;
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 4, "disirq");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+ }
+
s390irq_spin_lock_irqsave(irq, flags);
ret = disable_subchannel(irq);
s390irq_spin_unlock_irqrestore(irq, flags);
@@ -753,6 +982,7 @@
{
unsigned long flags;
int ret;
+ char dbf_txt[15];
if ( ioinfo[irq] == INVALID_STORAGE_AREA )
return( -ENODEV);
@@ -760,6 +990,12 @@
if ( !ioinfo[irq]->ui.flags.ready )
return -ENODEV;
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 4, "enirq");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+ }
+
s390irq_spin_lock_irqsave(irq, flags);
ret = enable_subchannel(irq);
s390irq_spin_unlock_irqrestore(irq, flags);
@@ -775,6 +1011,7 @@
int ret;
int ccode;
int retry = 5;
+ char dbf_txt[15];
if ( irq > highest_subchannel || irq < 0 )
{
@@ -785,6 +1022,12 @@
if ( ioinfo[irq] == INVALID_STORAGE_AREA )
return( -ENODEV);
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 2, "ensch");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 2, dbf_txt);
+ }
+
/*
* If a previous disable request is pending we reset it. However, this
* status implies that the device may (still) be not-operational.
@@ -862,6 +1105,10 @@
"%04X received !\n",
irq,
ioinfo[irq]->devstat.devno);
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 0,
+ "enable_subchannel(%04X) : ccode 2 on msch() for device %04X received !\n",
+ irq, ioinfo[irq]->devstat.devno);
ret = -ENODEV; // never reached
}
@@ -884,6 +1131,7 @@
int cc; /* condition code */
int ret; /* function return value */
int retry = 5;
+ char dbf_txt[15];
if ( irq > highest_subchannel )
{
@@ -903,6 +1151,12 @@
}
else
{
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 2, "dissch");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 2, dbf_txt);
+ }
+
/*
* If device isn't operational we have to perform delayed
* disabling when the next interrupt occurs - unless the
@@ -962,6 +1216,10 @@
"device %04X received !\n",
irq,
ioinfo[irq]->devstat.devno);
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 0,
+ "disable_subchannel(%04X) - unexpected busy condition for device %04X received !\n",
+ irq, ioinfo[irq]->devstat.devno);
ret = -EBUSY;
break;
@@ -998,14 +1256,6 @@
unsigned long flags; /* PSW flags */
long cr6 __attribute__ ((aligned (8)));
- // Hopefully bh_count's will get set when we copy the prefix lowcore
- // structure to other CPI's ( DJB )
- softirq_active(smp_processor_id()) = 0;
- softirq_mask(smp_processor_id()) = 0;
- local_bh_count(smp_processor_id()) = 0;
- local_irq_count(smp_processor_id()) = 0;
- syscall_count(smp_processor_id()) = 0;
-
asm volatile ("STCK %0" : "=m" (irq_IPL_TOD));
p_init_schib = alloc_bootmem_low( sizeof(schib_t));
@@ -1065,6 +1315,8 @@
{
int ccode;
int ret = 0;
+ char buffer[80];
+ char dbf_txt[15];
/*
* The flag usage is mutal exclusive ...
@@ -1076,6 +1328,12 @@
} /* endif */
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 4, "stIO");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+ }
+
/*
* setup ORB
*/
@@ -1367,18 +1625,17 @@
{
ret = -ENODEV;
ioinfo[irq]->ui.flags.oper = 0;
- }
+ }
else
{
ret = -EIO;
- } /* endif */
+ } /* endif */
ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
#ifdef CONFIG_DEBUG_IO
{
- char buffer[80];
stsch(irq, &(ioinfo[irq]->schib) );
@@ -1416,6 +1673,41 @@
} /* endif */
}
#endif
+ if (cio_debug_initialized) {
+ stsch(irq, &(ioinfo[irq]->schib) );
+
+ sprintf( buffer, "s390_start_IO(%04X) - irb for "
+ "device %04X, after status pending\n",
+ irq,
+ ioinfo[irq]->devstat.devno );
+
+ s390_displayhex2( buffer,
+ &(ioinfo[irq]->devstat.ii.irb) ,
+ sizeof(irb_t), 2);
+
+ sprintf( buffer, "s390_start_IO(%04X) - schib for "
+ "device %04X, after status pending\n",
+ irq,
+ ioinfo[irq]->devstat.devno );
+
+ s390_displayhex2( buffer,
+ &(ioinfo[irq]->schib) ,
+ sizeof(schib_t), 2);
+
+
+ if (ioinfo[irq]->devstat.flag & DEVSTAT_FLAG_SENSE_AVAIL) {
+ sprintf( buffer, "s390_start_IO(%04X) - sense "
+ "data for "
+ "device %04X, after status pending\n",
+ irq,
+ ioinfo[irq]->devstat.devno );
+
+ s390_displayhex2( buffer,
+ ioinfo[irq]->irq_desc.dev_id->ii.sense.data,
+ ioinfo[irq]->irq_desc.dev_id->rescnt, 2);
+
+ } /* endif */
+ }
}
else
{
@@ -1457,9 +1749,8 @@
&(ioinfo[irq]->devstat),
sizeof( devstat_t) );
+
#ifdef CONFIG_DEBUG_IO
- {
- char buffer[80];
stsch(irq, &(ioinfo[irq]->schib) );
@@ -1471,8 +1762,20 @@
s390_displayhex( buffer,
&(ioinfo[irq]->schib),
sizeof(schib_t));
- }
#endif
+ if (cio_debug_initialized) {
+ stsch(irq, &(ioinfo[irq]->schib) );
+
+ sprintf( buffer, "s390_start_IO(%04X) - schib for "
+ "device %04X, after 'not oper' status\n",
+ irq,
+ ioinfo[irq]->devstat.devno );
+
+ s390_displayhex2( buffer,
+ &(ioinfo[irq]->schib),
+ sizeof(schib_t), 2);
+ }
+
break;
} /* endswitch */
@@ -1499,6 +1802,7 @@
unsigned long flag) /* flags : see above */
{
int ret = 0;
+ char dbf_txt[15];
if ( irq > highest_subchannel || irq < 0 )
{
@@ -1518,6 +1822,12 @@
} /* endif */
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 4, "doIO");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+ }
+
/*
* Note: We ignore the device operational status - if not operational,
* the SSCH will lead to an -ENODEV condition ...
@@ -1567,6 +1877,7 @@
int resume_IO( int irq)
{
int ret = 0;
+ char dbf_txt[15];
if ( irq > highest_subchannel || irq < 0 )
{
@@ -1579,6 +1890,12 @@
return( -ENODEV);
}
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 4, "resIO");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+ }
+
/*
* We allow for 'resume' requests only for active I/O operations
*/
@@ -1635,16 +1952,17 @@
{
int ret;
int ccode;
+ char dbf_txt[15];
if ( irq > highest_subchannel || irq < 0 )
{
- ret = -ENODEV;
+ return -ENODEV;
}
if ( ioinfo[irq] == INVALID_STORAGE_AREA )
{
return( -ENODEV);
- }
+ }
/*
* we only allow for halt_IO if the device has an I/O handler associated
@@ -1671,6 +1989,11 @@
}
else
{
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 2, "haltIO");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 2, dbf_txt);
+ }
/*
* If sync processing was requested we lock the sync ISC,
* modify the device to present interrupts for this ISC only
@@ -1895,10 +2218,11 @@
{
int ret;
int ccode;
+ char dbf_txt[15];
if ( irq > highest_subchannel || irq < 0 )
{
- ret = -ENODEV;
+ return -ENODEV;
}
if ( ioinfo[irq] == INVALID_STORAGE_AREA )
@@ -1932,6 +2256,11 @@
}
else
{
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 2, "clearIO");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 2, dbf_txt);
+ }
/*
* If sync processing was requested we lock the sync ISC,
* modify the device to present interrupts for this ISC only
@@ -2066,7 +2395,7 @@
break;
case 1 : /* status pending */
-
+
ioinfo[irq]->devstat.flag |= DEVSTAT_STATUS_PENDING;
/*
@@ -2117,7 +2446,7 @@
ioinfo[irq]->devstat.flag &= ~DEVSTAT_NOT_OPER;
ioinfo[irq]->ui.flags.oper = 1;
- } /* endif */
+ } /* endif */
break;
@@ -2172,7 +2501,6 @@
return;
} /* endif */
-
#ifdef CONFIG_FAST_IRQ
do {
#endif /* CONFIG_FAST_IRQ */
@@ -2252,12 +2580,20 @@
int chnchk = 0;
devstat_t *dp;
devstat_t *udp;
+
+ char dbf_txt[15];
#if 0
int cpu = smp_processor_id();
kstat.irqs[cpu][irq]++;
#endif
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 3, "procIRQ");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 3, dbf_txt);
+ }
+
if ( ioinfo[irq] == INVALID_STORAGE_AREA )
{
/* we can't properly process the interrupt ... */
@@ -2270,7 +2606,6 @@
udp = ioinfo[irq]->irq_desc.dev_id;
-#ifdef CONFIG_DEBUG_IO
/*
* It might be possible that a device was not-oper. at the time
* of free_irq() processing. This means the handler is no longer
@@ -2281,16 +2616,20 @@
{
if ( !ioinfo[irq]->ui.flags.d_disable )
{
+#ifdef CONFIG_DEBUG_IO
printk( KERN_CRIT"s390_process_IRQ(%04X) "
"- no interrupt handler registered "
"for device %04X !\n",
irq,
ioinfo[irq]->devstat.devno);
-
+#endif /* CONFIG_DEBUG_IO */
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 0,
+ "s390_process_IRQ(%04X) - no interrupt handler registered for device %04X !\n",
+ irq, ioinfo[irq]->devstat.devno);
} /* endif */
} /* endif */
-#endif
/*
* retrieve the i/o interrupt information (irb),
@@ -2360,6 +2699,10 @@
"residual count from irb after tsch() %d\n",
irq, dp->rescnt );
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 6,
+ "s390_process_IRQ( %04X ) : residual count from irq after tsch() %d\n",
+ irq, dp->rescnt);
} /* endif */
@@ -2372,17 +2715,24 @@
if ( (dp->ii.irb.scsw.cstat
& ( SCHN_STAT_CHN_DATA_CHK
| SCHN_STAT_CHN_CTRL_CHK
- | SCHN_STAT_INTF_CTRL_CHK ) )
- && (irq != cons_dev ) )
+ | SCHN_STAT_INTF_CTRL_CHK )))
{
- printk( "Channel-Check or Interface-Control-Check "
- "received\n"
- " ... device %04X on subchannel %04X, dev_stat "
- ": %02X sch_stat : %02X\n",
- ioinfo[irq]->devstat.devno,
- irq,
- dp->dstat,
- dp->cstat);
+ if (irq != cons_dev)
+ printk( "Channel-Check or Interface-Control-Check "
+ "received\n"
+ " ... device %04X on subchannel %04X, dev_stat "
+ ": %02X sch_stat : %02X\n",
+ ioinfo[irq]->devstat.devno,
+ irq,
+ dp->dstat,
+ dp->cstat);
+ if (cio_debug_initialized) {
+ debug_sprintf_event(cio_debug_msg_id, 0,
+ "Channel-Check or Interface-Control-Check received\n");
+ debug_sprintf_event(cio_debug_msg_id, 0,
+ "... device %04X on subchannel %04X, dev_stat: %02X sch_stat: %02X\n",
+ ioinfo[irq]->devstat.devno, irq, dp->dstat, dp->cstat);
+ }
chnchk = 1;
@@ -2422,6 +2772,10 @@
"concurrent sense bytes avail %d\n",
irq, dp->scnt );
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 4,
+ "s390_process_IRQ( %04X ): concurrent sense bytes avail %d\n",
+ irq, dp->scnt);
}
else
{
@@ -2453,6 +2807,17 @@
s390_displayhex( buffer,
&(dp->ii.irb) ,
sizeof(irb_t));
+ if (cio_debug_initialized) {
+
+ sprintf( buffer, "s390_process_IRQ(%04X) - irb for "
+ "device %04X after channel check\n",
+ irq,
+ dp->devno );
+
+ s390_displayhex2( buffer,
+ &(dp->ii.irb) ,
+ sizeof(irb_t), 0);
+ }
} /* endif */
ioinfo[irq]->stctl |= stctl;
@@ -2473,20 +2838,19 @@
* unsolicited interrupt applies to the console device
* itself !
*/
-#ifdef CONFIG_DEBUG_IO
- if ( ( irq != cons_dev )
- && !( stctl & SCSW_STCTL_ALERT_STATUS )
- && ( ioinfo[irq]->ui.flags.busy == 0 ) )
+ if ( !( stctl & SCSW_STCTL_ALERT_STATUS )
+ && ( ioinfo[irq]->ui.flags.busy == 0 ) )
{
char buffer[80];
-
- printk( "Unsolicited interrupt received for device %04X on subchannel %04X\n"
- " ... device status : %02X subchannel status : %02X\n",
- dp->devno,
- irq,
- dp->dstat,
- dp->cstat);
-
+#ifdef CONFIG_DEBUG_IO
+ if (irq != cons_dev)
+ printk( "Unsolicited interrupt received for device %04X on subchannel %04X\n"
+ " ... device status : %02X subchannel status : %02X\n",
+ dp->devno,
+ irq,
+ dp->dstat,
+ dp->cstat);
+
sprintf( buffer, "s390_process_IRQ(%04X) - irb for "
"device %04X, ending_status %d\n",
irq,
@@ -2496,10 +2860,27 @@
s390_displayhex( buffer,
&(dp->ii.irb) ,
sizeof(irb_t));
-
+#endif
+ if (cio_debug_initialized) {
+ debug_sprintf_event(cio_debug_msg_id, 2,
+ "Unsolicited interrupt received for device %04X on subchannel %04X\n"
+ " ... device status : %02X subchannel status : %02X\n",
+ dp->devno,
+ irq,
+ dp->dstat,
+ dp->cstat);
+ sprintf( buffer, "s390_process_IRQ(%04X) - irb for "
+ "device %04X, ending_status %d\n",
+ irq,
+ dp->devno,
+ ending_status);
+
+ s390_displayhex2( buffer,
+ &(dp->ii.irb) ,
+ sizeof(irb_t), 2);
+ }
} /* endif */
-#endif
/*
* take fast exit if no handler is available
*/
@@ -2639,11 +3020,15 @@
int sense_count = SENSE_MAX_COUNT-ioinfo[irq]->devstat.rescnt;
#ifdef CONFIG_DEBUG_IO
- if ( irq != cons_dev )
- printk( "s390_process_IRQ( %04X ) : "
- "BASIC SENSE bytes avail %d\n",
- irq, sense_count );
-#endif
+ if ( irq != cons_dev )
+ printk( "s390_process_IRQ( %04X ) : "
+ "BASIC SENSE bytes avail %d\n",
+ irq, sense_count );
+#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 4,
+ "s390_process_IRQ( %04X ): BASIC SENSE bytes avail %d\n",
+ irq, sense_count);
ioinfo[irq]->ui.flags.w4sense = 0;
udp->flag |= DEVSTAT_FLAG_SENSE_AVAIL;
udp->scnt = sense_count;
@@ -2664,6 +3049,11 @@
printk( KERN_CRIT"s390_process_IRQ(%04x) encountered "
"negative sense count\n",
irq);
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 0,
+ "s390_process_IRQ(%04x) encountered "
+ "negative sense count\n",
+ irq);
#endif
} /* endif */
}
@@ -2906,6 +3296,7 @@
int ccode;
unsigned long cr6 __attribute__ ((aligned (8)));
int rc = 0;
+ char dbf_txt[15];
if ( cons_dev != -1 )
{
@@ -2921,6 +3312,12 @@
}
else
{
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 4, "scons");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+ }
+
/*
* modify the indicated console device to operate
* on special console interrupt sublass 7
@@ -2967,6 +3364,7 @@
int rc = 0;
int ccode;
long cr6 __attribute__ ((aligned (8)));
+ char dbf_txt[15];
if ( cons_dev != -1 )
{
@@ -2982,6 +3380,12 @@
}
else
{
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 4, "rcons");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+ }
+
/*
* reset the indicated console device to operate
* on default console interrupt sublass 3
@@ -3028,10 +3432,17 @@
{
int rc = 0;
long save_cr6;
+ char dbf_txt[15];
if ( irq == cons_dev )
{
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 4, "wcons");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+ }
+
/*
* before entering the spinlock we may already have
* processed the interrupt on a different CPU ...
@@ -3087,6 +3498,13 @@
int count = 0;
int rc = 0;
+ char dbf_txt[15];
+
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 4, "enisc");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+ }
/* This one spins until it can get the sync_isc lock for irq# irq */
@@ -3171,6 +3589,7 @@
} /* endif */
+
if ( rc ) /* can only happen if stsch/msch fails */
{
sync_isc_cnt = 0;
@@ -3200,6 +3619,14 @@
int ccode;
long cr6 __attribute__ ((aligned (8)));
+ char dbf_txt[15];
+
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 4, "disisc");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+ }
+
if ( irq <= highest_subchannel && ioinfo[irq] != INVALID_STORAGE_AREA )
{
/*
@@ -3311,6 +3738,9 @@
int error = 0;
+ if (cio_debug_initialized)
+ debug_text_event(cio_debug_trace_id, 4, "VMvdinf");
+
if ( init_IRQ_complete )
{
p_diag_data = kmalloc( sizeof( diag210_t), GFP_DMA );
@@ -3596,6 +4026,19 @@
p_diag_data->vrdcrccl,
p_diag_data->vrdccrty,
p_diag_data->vrdccrmd );
+ if (cio_debug_initialized)
+ debug_sprintf_event( cio_debug_msg_id, 0,
+ "DIAG X'210' for "
+ "device %04X returned "
+ "(cc = %d): vdev class : %02X, "
+ "vdev type : %04X \n ... rdev class : %02X, rdev type : %04X, rdev model: %02X\n",
+ devno,
+ ccode,
+ p_diag_data->vrdcvcla,
+ p_diag_data->vrdcvtyp,
+ p_diag_data->vrdcrccl,
+ p_diag_data->vrdccrty,
+ p_diag_data->vrdccrmd );
} /* endif */
@@ -3636,6 +4079,8 @@
int emulated = 0;
int retry = 5;
+ char dbf_txt[15];
+
if ( !buffer || !length )
{
return( -EINVAL );
@@ -3650,7 +4095,7 @@
else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
{
return( -ENODEV);
- }
+ }
if ( ioinfo[irq]->ui.flags.oper == 0 )
{
@@ -3658,6 +4103,12 @@
} /* endif */
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 4, "rddevch");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+ }
+
/*
* Before playing around with irq locks we should assure
* running disabled on (just) our CPU. Sync. I/O requests
@@ -3769,6 +4220,8 @@
int found = 0; // RCD CIW found
int ret = 0; // return code
+ char dbf_txt[15];
+
if ( (irq > highest_subchannel) || (irq < 0 ) )
{
return( -ENODEV );
@@ -3791,6 +4244,12 @@
} /* endif */
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 4, "rdconf");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+ }
+
/*
* scan for RCD command in extended SenseID data
*/
@@ -4262,6 +4721,13 @@
void s390_device_recognition_irq( int irq )
{
int ret;
+ char dbf_txt[15];
+
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 4, "devrec");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+ }
/*
* We issue the SenseID command on I/O subchannels we think are
@@ -4274,7 +4740,7 @@
int irq_ret;
devstat_t devstat;
- irq_ret = request_irq( irq,
+ irq_ret = request_irq( irq,
init_IRQ_handler,
0,
"INIT",
@@ -4284,7 +4750,7 @@
{
ret = enable_cpu_sync_isc( irq );
- if ( !ret )
+ if ( !ret )
{
ioinfo[irq]->ui.flags.unknown = 0;
@@ -4305,9 +4771,8 @@
if ( !ret ) // on success only ...
{
-#ifdef CONFIG_DEBUG_IO
char buffer[80];
-
+#ifdef CONFIG_DEBUG_IO
sprintf( buffer,
"RCD for device(%04X)/"
"subchannel(%04X) returns :\n",
@@ -4316,6 +4781,15 @@
s390_displayhex( buffer, prcd, lrcd );
#endif
+ if (cio_debug_initialized) {
+ sprintf( buffer,
+ "RCD for device(%04X)/"
+ "subchannel(%04X) returns :\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ irq );
+
+ s390_displayhex2( buffer, prcd, lrcd, 2);
+ }
if ( init_IRQ_complete )
{
kfree( prcd );
@@ -4326,9 +4800,9 @@
} /* endif */
- } /* endif */
-
- } /* endif */
+ } /* endif */
+
+ } /* endif */
#endif
s390_DevicePathVerification( irq, 0 );
@@ -4364,6 +4838,44 @@
}
+/*
+ * Function: s390_redo_validation
+ * Look for no longer blacklisted devices
+ * FIXME: there must be a better way to do this...
+ */
+
+void s390_redo_validation(void)
+{
+ int irq = 0;
+ int ret;
+
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 0, "redoval");
+ }
+ do {
+ if (ioinfo[irq] == INVALID_STORAGE_AREA) {
+ ret = s390_validate_subchannel(irq, 0);
+ if (!ret) {
+ s390_device_recognition_irq(irq);
+ if (ioinfo[irq]->ui.flags.oper) {
+ devreg_t *pdevreg;
+
+ pdevreg = s390_search_devreg( ioinfo[irq] );
+ if ( pdevreg != NULL ) {
+ if ( pdevreg->oper_func != NULL )
+ pdevreg->oper_func( irq, pdevreg );
+
+ }
+ }
+ if (cio_proc_devinfo)
+ if (irq < MAX_CIO_PROCFS_ENTRIES) {
+ cio_procfs_device_create(ioinfo[irq]->devno);
+ }
+ }
+ }
+ irq++;
+ } while (irq<=highest_subchannel);
+}
/*
* s390_search_devices
@@ -4389,6 +4901,10 @@
printk( "Highest subchannel number detected (hex) : %04X\n",
highest_subchannel);
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 0,
+ "Highest subchannel number detected (hex) : %04X\n",
+ highest_subchannel);
}
/*
@@ -4405,6 +4921,14 @@
int ccode2; /* condition code for other I/O routines */
schib_t *p_schib;
int ret;
+
+ char dbf_txt[15];
+
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 4, "valsch");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+ }
/*
* The first subchannel that is not-operational (ccode==3)
@@ -4444,6 +4968,10 @@
"non-I/O subchannel type %04X\n",
irq,
p_schib->pmcw.st);
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 0,
+ "Subchannel %04X reports non-I/O subchannel type %04X\n",
+ irq, p_schib->pmcw.st);
if ( ioinfo[irq] != INVALID_STORAGE_AREA )
ioinfo[irq]->ui.flags.oper = 0;
@@ -4460,6 +4988,10 @@
#ifdef CONFIG_DEBUG_IO
printk( "Blacklisted device detected at devno %04X\n", p_schib->pmcw.dev );
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 0,
+ "Blacklisted device detected at devno %04X\n",
+ p_schib->pmcw.dev);
ret = -ENODEV;
} else {
if ( ioinfo[irq] == INVALID_STORAGE_AREA )
@@ -4547,6 +5079,16 @@
ioinfo[irq]->schib.pmcw.pom);
} /* endif */
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 0,
+ "Detected device %04X "
+ "on subchannel %04X"
+ " - PIM = %02X, PAM = %02X, POM = %02X\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ irq,
+ ioinfo[irq]->schib.pmcw.pim,
+ ioinfo[irq]->schib.pmcw.pam,
+ ioinfo[irq]->schib.pmcw.pom);
/*
* initialize ioinfo structure
@@ -4661,6 +5203,10 @@
{
printk( " ... msch() (2) failed with CC = %X\n",
ccode2 );
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 0,
+ "msch() (2) failed with CC=%X\n",
+ ccode2);
ioinfo[irq]->ui.flags.oper = 0;
ret = -EIO;
}
@@ -4676,6 +5222,10 @@
{
printk( " ... msch() (1) failed with CC = %X\n",
ccode2);
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 0,
+ "msch() (1) failed with CC = %X\n",
+ ccode2);
ioinfo[irq]->ui.flags.oper = 0;
ret = -EIO;
@@ -4694,6 +5244,11 @@
"subchannel %04X exceeded, CC = %d\n",
irq,
ccode2);
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 0,
+ " ... msch() retry count for "
+ "subchannel %04X exceeded, CC = %d\n",
+ irq, ccode2);
} /* endif */
}
@@ -4750,6 +5305,8 @@
senseid_t *psid = sid;/* start with the external buffer */
int sbuffer = 0; /* switch SID data buffer */
+ char dbf_txt[15];
+
if ( (irq > highest_subchannel) || (irq < 0 ) )
{
return( -ENODEV );
@@ -4767,6 +5324,12 @@
} /* endif */
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 4, "snsID");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+ }
+
if ( !ioinfo[irq]->ui.flags.ready )
{
@@ -4792,8 +5355,8 @@
} /* endif */
if ( irq_ret == 0 )
- {
- int i;
+ {
+ int i;
s390irq_spin_lock( irq);
@@ -4888,6 +5451,15 @@
irq,
retry);
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2,
+ "SenseID : device %04X on "
+ "Subchannel %04X "
+ "reports pending status, "
+ "retry : %d\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ irq,
+ retry);
} /* endif */
if ( pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL )
@@ -4907,11 +5479,20 @@
ioinfo[irq]->schib.pmcw.dev,
irq);
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2,
+ "SenseID : device %04X on "
+ "Subchannel %04X "
+ "reports cmd reject or "
+ "intervention required\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ irq);
io_retry = 1;
}
-#ifdef CONFIG_DEBUG_IO
+
else
{
+#ifdef CONFIG_DEBUG_IO
printk( "SenseID : UC on "
"dev %04X, "
"retry %d, "
@@ -4932,9 +5513,31 @@
pdevstat->ii.sense.data[5],
pdevstat->ii.sense.data[6],
pdevstat->ii.sense.data[7]);
-
- } /* endif */
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2,
+ "SenseID : UC on "
+ "dev %04X, "
+ "retry %d, "
+ "lpum %02X, "
+ "cnt %02d, "
+ "sns :"
+ " %02X%02X%02X%02X "
+ "%02X%02X%02X%02X ...\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ retry,
+ pdevstat->lpum,
+ pdevstat->scnt,
+ pdevstat->ii.sense.data[0],
+ pdevstat->ii.sense.data[1],
+ pdevstat->ii.sense.data[2],
+ pdevstat->ii.sense.data[3],
+ pdevstat->ii.sense.data[4],
+ pdevstat->ii.sense.data[5],
+ pdevstat->ii.sense.data[6],
+ pdevstat->ii.sense.data[7]);
+ } /* endif */
+
}
else if ( ( pdevstat->flag & DEVSTAT_NOT_OPER )
|| ( irq_ret == -ENODEV ) )
@@ -4948,18 +5551,28 @@
ioinfo[irq]->schib.pmcw.dev,
irq);
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2,
+ "SenseID : path %02X for "
+ "device %04X on "
+ "subchannel %04X "
+ "is 'not operational'\n",
+ domask,
+ ioinfo[irq]->schib.pmcw.dev,
+ irq);
io_retry = 0;
ioinfo[irq]->opm &= ~domask;
}
-#ifdef CONFIG_DEBUG_IO
+
else if ( (pdevstat->flag !=
( DEVSTAT_START_FUNCTION
| DEVSTAT_FINAL_STATUS ) )
&& !(pdevstat->flag &
DEVSTAT_STATUS_PENDING ) )
{
+#ifdef CONFIG_DEBUG_IO
printk( "SenseID : start_IO() for "
"device %04X on "
"subchannel %04X "
@@ -4970,9 +5583,22 @@
irq_ret,
retry,
pdevstat->flag);
+#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2,
+ "SenseID : start_IO() for "
+ "device %04X on "
+ "subchannel %04X "
+ "returns %d, retry %d, "
+ "status %04X\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ irq,
+ irq_ret,
+ retry,
+ pdevstat->flag);
} /* endif */
-#endif
+
}
else // we got it ...
{
@@ -5079,38 +5705,54 @@
ioinfo[irq]->schib.pmcw.dev,
irq);
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2,
+ "SenseID : unknown device %04X on subchannel %04X\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ irq);
ioinfo[irq]->ui.flags.unknown = 1;
} /* endif */
- if ( cio_show_msg )
- {
+
/*
* Issue device info message if unit was operational .
*/
- if ( !ioinfo[irq]->ui.flags.unknown )
- {
- if ( sid->dev_type != 0 )
- {
+ if ( !ioinfo[irq]->ui.flags.unknown ) {
+ if ( sid->dev_type != 0 ) {
+ if ( cio_show_msg )
printk( KERN_INFO"SenseID : device %04X reports: "
- "CU Type/Mod = %04X/%02X,"
- " Dev Type/Mod = %04X/%02X\n",
- ioinfo[irq]->schib.pmcw.dev,
- sid->cu_type,
- sid->cu_model,
- sid->dev_type,
- sid->dev_model);
- }
- else
- {
+ "CU Type/Mod = %04X/%02X,"
+ " Dev Type/Mod = %04X/%02X\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ sid->cu_type,
+ sid->cu_model,
+ sid->dev_type,
+ sid->dev_model);
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2,
+ "SenseID : device %04X reports: "
+ "CU Type/Mod = %04X/%02X,"
+ " Dev Type/Mod = %04X/%02X\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ sid->cu_type,
+ sid->cu_model,
+ sid->dev_type,
+ sid->dev_model);
+ } else {
+ if ( cio_show_msg )
printk( KERN_INFO"SenseID : device %04X reports:"
- " Dev Type/Mod = %04X/%02X\n",
- ioinfo[irq]->schib.pmcw.dev,
- sid->cu_type,
- sid->cu_model);
-
- } /* endif */
-
+ " Dev Type/Mod = %04X/%02X\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ sid->cu_type,
+ sid->cu_model);
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2,
+ "SenseID : device %04X reports:"
+ " Dev Type/Mod = %04X/%02X\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ sid->cu_type,
+ sid->cu_model);
} /* endif */
} /* endif */
@@ -5159,6 +5801,14 @@
int ret = 0;
+ char dbf_txt[15];
+
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 4, "dpver");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+ }
+
if ( ioinfo[irq]->ui.flags.pgid_supp == 0 )
{
return( 0); // just exit ...
@@ -5270,16 +5920,30 @@
irq,
ioinfo[irq]->schib.pmcw.dev);
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2,
+ "PathVerification(%04X) "
+ "- Device %04X doesn't "
+ " support path grouping\n",
+ irq,
+ ioinfo[irq]->schib.pmcw.dev);
} /* endif */
}
- else if ( ret == -EIO )
+ else if ( ret == -EIO )
{
#ifdef CONFIG_DEBUG_IO
printk("PathVerification(%04X) - I/O error "
"on device %04X\n", irq,
ioinfo[irq]->schib.pmcw.dev);
#endif
+
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2,
+ "PathVerification(%04X) - I/O error "
+ "on device %04X\n", irq,
+ ioinfo[irq]->schib.pmcw.dev);
+
ioinfo[irq]->ui.flags.pgid_supp = 0;
} else {
@@ -5289,6 +5953,13 @@
irq,
ioinfo[irq]->schib.pmcw.dev);
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2,
+ "PathVerification(%04X) - "
+ "Unexpected error on device %04X\n",
+ irq,
+ ioinfo[irq]->schib.pmcw.dev);
+
ioinfo[irq]->ui.flags.pgid_supp = 0;
} /* endif */
@@ -5357,7 +6028,7 @@
if ( irq_ret == 0 )
inlreq = 1;
- }
+ }
else
{
pdevstat = ioinfo[irq]->irq_desc.dev_id;
@@ -5419,6 +6090,15 @@
irq,
retry);
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2,
+ "SPID - Device %04X "
+ "on Subchannel %04X "
+ "reports pending status, "
+ "retry : %d\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ irq,
+ retry);
} /* endif */
if ( pdevstat->flag == ( DEVSTAT_START_FUNCTION
@@ -5468,19 +6148,50 @@
pdevstat->ii.sense.data[5],
pdevstat->ii.sense.data[6],
pdevstat->ii.sense.data[7]);
-
#endif
- retry--;
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2,
+ "SPID - device %04X,"
+ " unit check,"
+ " retry %d, cnt %02d,"
+ " sns :"
+ " %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ retry,
+ pdevstat->scnt,
+ pdevstat->ii.sense.data[0],
+ pdevstat->ii.sense.data[1],
+ pdevstat->ii.sense.data[2],
+ pdevstat->ii.sense.data[3],
+ pdevstat->ii.sense.data[4],
+ pdevstat->ii.sense.data[5],
+ pdevstat->ii.sense.data[6],
+ pdevstat->ii.sense.data[7]);
+
+ retry--;
+
} /* endif */
+
}
else if ( pdevstat->flag & DEVSTAT_NOT_OPER )
{
- printk( "SPID - Device %04X "
- "on Subchannel %04X "
- "became 'not operational'\n",
- ioinfo[irq]->schib.pmcw.dev,
- irq);
+ /* don't issue warnings during startup unless requested*/
+ if (init_IRQ_complete || cio_notoper_msg) {
+
+ printk( "SPID - Device %04X "
+ "on Subchannel %04X "
+ "became 'not operational'\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ irq);
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2,
+ "SPID - Device %04X "
+ "on Subchannel %04X "
+ "became 'not operational'\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ irq);
+ }
retry = 0;
irq_ret = -EIO;
@@ -5503,7 +6214,7 @@
{
irq_ret = -EIO;
- } /* endif */
+ } /* endif */
if ( init_IRQ_complete )
{
@@ -5659,17 +6370,47 @@
pdevstat->ii.sense.data[7]);
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2,
+ "SNID - device %04X,"
+ " unit check,"
+ " flag %04X, "
+ " retry %d, cnt %02d,"
+ " sns :"
+ " %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ pdevstat->flag,
+ retry,
+ pdevstat->scnt,
+ pdevstat->ii.sense.data[0],
+ pdevstat->ii.sense.data[1],
+ pdevstat->ii.sense.data[2],
+ pdevstat->ii.sense.data[3],
+ pdevstat->ii.sense.data[4],
+ pdevstat->ii.sense.data[5],
+ pdevstat->ii.sense.data[6],
+ pdevstat->ii.sense.data[7]);
retry--;
} /* endif */
}
else if ( pdevstat->flag & DEVSTAT_NOT_OPER )
{
- printk( "SNID - Device %04X "
- "on Subchannel %04X "
- "became 'not operational'\n",
- ioinfo[irq]->schib.pmcw.dev,
- irq);
+ /* don't issue warnings during startup unless requested*/
+ if (init_IRQ_complete || cio_notoper_msg) {
+ printk( "SNID - Device %04X "
+ "on Subchannel %04X "
+ "became 'not operational'\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ irq);
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2,
+ "SNID - Device %04X "
+ "on Subchannel %04X "
+ "became 'not operational'\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ irq);
+ }
retry = 0;
@@ -5682,9 +6423,10 @@
}
else if ( irq_ret != -ENODEV ) // -EIO, or -EBUSY
{
-#ifdef CONFIG_DEBUG_IO
+
if ( pdevstat->flag & DEVSTAT_STATUS_PENDING )
{
+#ifdef CONFIG_DEBUG_IO
printk( "SNID - Device %04X "
"on Subchannel %04X "
"reports pending status, "
@@ -5692,13 +6434,29 @@
ioinfo[irq]->schib.pmcw.dev,
irq,
retry);
- } /* endif */
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2,
+ "SNID - Device %04X "
+ "on Subchannel %04X "
+ "reports pending status, "
+ "retry : %d\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ irq,
+ retry);
+ } /* endif */
+
printk( "SNID - device %04X,"
" start_io() reports rc : %d, retrying ...\n",
ioinfo[irq]->schib.pmcw.dev,
irq_ret);
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2,
+ "SNID - device %04X,"
+ " start_io() reports rc : %d, retrying ...\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ irq_ret);
retry--;
}
else // -ENODEV ...
@@ -5758,7 +6516,9 @@
#ifdef CONFIG_DEBUG_CRW
printk( "do_crw_pending : starting ...\n");
#endif
-
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_crw_id, 2,
+ "do_crw_pending: starting\n");
while ( pcrwe != NULL )
{
int is_owned = 0;
@@ -5772,7 +6532,9 @@
printk( KERN_INFO"do_crw_pending : source is "
"subchannel %04X\n", irq);
#endif
-
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_crw_id, 2,
+ "source is subchannel %04X\n", irq);
/*
* If the device isn't known yet
* we can't lock it ...
@@ -5794,6 +6556,9 @@
#ifdef CONFIG_DEBUG_CRW
printk( "do_crw_pending : subchannel validation - start ...\n");
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_crw_id, 4,
+ "subchannel validation - start\n");
s390_validate_subchannel( irq, is_owned );
if ( irq > highest_subchannel )
@@ -5802,6 +6567,9 @@
#ifdef CONFIG_DEBUG_CRW
printk( "do_crw_pending : subchannel validation - done\n");
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_crw_id, 4,
+ "subchannel validation - done\n");
/*
* After the validate processing
* the ioinfo control block
@@ -5813,26 +6581,34 @@
} /* endif */
-#ifdef CONFIG_DEBUG_CRW
+
if ( ioinfo[irq] != INVALID_STORAGE_AREA )
{
+#ifdef CONFIG_DEBUG_CRW
printk( "do_crw_pending : ioinfo at %08X\n",
(unsigned)ioinfo[irq]);
-
- } /* endif */
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_crw_id, 4,
+ "ioinfo at %08X\n");
+ } /* endif */
+
if ( ioinfo[irq] != INVALID_STORAGE_AREA )
{
if ( ioinfo[irq]->ui.flags.oper == 0 )
{
not_oper_handler_func_t nopfunc=ioinfo[irq]->nopfunc;
+
+ /* remove procfs entry */
+ if (cio_proc_devinfo)
+ cio_procfs_device_remove(dev_no);
/*
* If the device has gone
* call not oper handler
*/
- if ( ( dev_oper == 1 )
- && ( nopfunc != NULL ) )
+ if (( dev_oper == 1 )
+ && ( nopfunc != NULL))
{
free_irq( irq,ioinfo[irq]->irq_desc.dev_id );
@@ -5846,13 +6622,18 @@
printk( "do_crw_pending : device "
"recognition - start ...\n");
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_crw_id, 4,
+ "device recognition - start\n");
s390_device_recognition_irq( irq );
#ifdef CONFIG_DEBUG_CRW
printk( "do_crw_pending : device "
"recognition - done\n");
#endif
-
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_crw_id, 4,
+ "device recognition - done\n");
/*
* the device became operational
*/
@@ -5868,6 +6649,12 @@
pdevreg->oper_func( irq, pdevreg );
} /* endif */
+
+ /* add new procfs entry */
+ if (cio_proc_devinfo)
+ if (highest_subchannel < MAX_CIO_PROCFS_ENTRIES) {
+ cio_procfs_device_create(ioinfo[irq]->devno);
+ }
}
/*
* ... it is and was operational, but
@@ -5875,13 +6662,23 @@
*/
else if ((ioinfo[irq]->devno != dev_no) && ( ioinfo[irq]->nopfunc != NULL ))
{
+ int devno_old = ioinfo[irq]->devno;
ioinfo[irq]->nopfunc( irq,
DEVSTAT_REVALIDATE );
+ /* remove old entry, add new */
+ if (cio_proc_devinfo) {
+ cio_procfs_device_remove(devno_old);
+ cio_procfs_device_create(ioinfo[irq]->devno);
+ }
} /* endif */
} /* endif */
+ /* get rid of dead procfs entries */
+ if (cio_proc_devinfo)
+ cio_procfs_device_purge();
+
} /* endif */
break;
@@ -5892,6 +6689,9 @@
printk( "do_crw_pending : source is "
"monitoring facility\n");
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_crw_id, 2,
+ "source is monitoring facility\n");
break;
case CRW_RSC_CPATH :
@@ -5902,6 +6702,9 @@
printk( "do_crw_pending : source is "
"channel path %02X\n", chpid);
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_crw_id, 2,
+ "source is channel path %02X\n");
break;
case CRW_RSC_CONFIG :
@@ -5910,6 +6713,9 @@
printk( "do_crw_pending : source is "
"configuration-alert facility\n");
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_crw_id, 2,
+ "source is configuration-alert facility\n");
break;
case CRW_RSC_CSS :
@@ -5918,6 +6724,9 @@
printk( "do_crw_pending : source is "
"channel subsystem\n");
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_crw_id, 2,
+ "source is channel subsystem\n");
break;
default :
@@ -5925,6 +6734,9 @@
#ifdef CONFIG_DEBUG_CRW
printk( "do_crw_pending : unknown source\n");
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_crw_id, 2,
+ "unknown source\n");
break;
} /* endswitch */
@@ -5936,7 +6748,9 @@
#ifdef CONFIG_DEBUG_CRW
printk( "do_crw_pending : done\n");
#endif
-
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_crw_id, 2,
+ "do_crw_pending: done\n");
return;
}
@@ -5964,8 +6778,64 @@
do_reipl( 0x10000 | sch );
}
-/* Display info on subchannels in /proc/subchannels. *
- * Adapted from procfs stuff in dasd.c by Cornelia Huck, 02/28/01. */
+
+/*
+ * Function: cio_debug_init
+ * Initializes three debug logs (under /proc/s390dbf) for common I/O:
+ * - cio_msg logs the messages which are printk'ed when CONFIG_DEBUG_IO is on
+ * - cio_trace logs the calling of different functions
+ * - cio_crw logs the messages which are printk'ed when CONFIG_DEBUG_CRW is on
+ * debug levels depend on CONFIG_DEBUG_IO resp. CONFIG_DEBUG_CRW
+ */
+int cio_debug_init( void )
+{
+ int ret = 0;
+
+ cio_debug_msg_id = debug_register("cio_msg",2,4,16*sizeof(long));
+ if (cio_debug_msg_id != NULL) {
+ debug_register_view(cio_debug_msg_id, &debug_sprintf_view);
+#ifdef CONFIG_DEBUG_IO
+ debug_set_level(cio_debug_msg_id, 6);
+#else /* CONFIG_DEBUG_IO */
+ debug_set_level(cio_debug_msg_id, 2);
+#endif /* CONFIG_DEBUG_IO */
+ } else {
+ ret = -1;
+ }
+ cio_debug_trace_id = debug_register("cio_trace",4,4,8);
+ if (cio_debug_trace_id != NULL) {
+ debug_register_view(cio_debug_trace_id, &debug_hex_ascii_view);
+#ifdef CONFIG_DEBUG_IO
+ debug_set_level(cio_debug_trace_id, 6);
+#else /* CONFIG_DEBUG_IO */
+ debug_set_level(cio_debug_trace_id, 2);
+#endif /* CONFIG_DEBUG_IO */
+ } else {
+ ret = -1;
+ }
+ cio_debug_crw_id = debug_register("cio_crw",2,4,16*sizeof(long));
+ if (cio_debug_crw_id != NULL) {
+ debug_register_view(cio_debug_crw_id, &debug_sprintf_view);
+#ifdef CONFIG_DEBUG_CRW
+ debug_set_level(cio_debug_crw_id, 6);
+#else /* CONFIG_DEBUG_CRW */
+ debug_set_level(cio_debug_crw_id, 2);
+#endif /* CONFIG_DEBUG_CRW */
+ } else {
+ ret = -1;
+ }
+ if (ret)
+ return ret;
+ cio_debug_initialized = 1;
+ return 0;
+}
+
+__initcall(cio_debug_init);
+
+/*
+ * Display info on subchannels in /proc/subchannels.
+ * Adapted from procfs stuff in dasd.c by Cornelia Huck, 02/28/01.
+ */
typedef struct {
char *data;
@@ -6090,10 +6960,12 @@
release:chan_subch_close,
};
-void chan_proc_init( void )
+static int chan_proc_init( void )
{
chan_subch_entry = create_proc_entry( "subchannels", S_IFREG|S_IRUGO, &proc_root);
chan_subch_entry->proc_fops = &chan_subch_file_ops;
+
+ return 1;
}
__initcall(chan_proc_init);
@@ -6103,6 +6975,531 @@
remove_proc_entry( "subchannels", &proc_root);
}
+/*
+ * Display device specific information under /proc/deviceinfo/<devno>
+ */
+
+static struct proc_dir_entry *cio_procfs_deviceinfo_root = NULL;
+
+/*
+ * cio_procfs_device_list holds all devno-specific procfs directories
+ */
+
+typedef struct {
+ int devno;
+ struct proc_dir_entry *cio_device_entry;
+ struct proc_dir_entry *cio_sensedata_entry;
+ struct proc_dir_entry *cio_in_use_entry;
+ struct proc_dir_entry *cio_chpid_entry;
+} cio_procfs_entry_t;
+
+typedef struct _cio_procfs_device{
+ struct _cio_procfs_device *next;
+ cio_procfs_entry_t *entry;
+} cio_procfs_device_t;
+
+cio_procfs_device_t *cio_procfs_device_list = NULL;
+
+/*
+ * File operations
+ */
+
+static int cio_device_entry_close( struct inode *inode, struct file *file)
+{
+ int rc = 0;
+ tempinfo_t *p_info = (tempinfo_t *) file->private_data;
+
+ if (p_info) {
+ if (p_info->data)
+ vfree( p_info->data );
+ vfree( p_info );
+ }
+
+ return rc;
+}
+
+static ssize_t cio_device_entry_read( struct file *file, char *user_buf, size_t user_len, loff_t * offset)
+{
+ loff_t len;
+ tempinfo_t *p_info = (tempinfo_t *) file->private_data;
+
+ if ( *offset>=p_info->len) {
+ return 0;
+ } else {
+ len = MIN(user_len, (p_info->len - *offset));
+ if (copy_to_user( user_buf, &(p_info->data[*offset]), len))
+ return -EFAULT;
+ (* offset) += len;
+ return len;
+ }
+}
+
+int cio_search_devno_by_inode(struct inode *inode)
+{
+ int devno = -1;
+ struct proc_dir_entry *pde;
+ cio_procfs_device_t *tmp;
+
+ pde = (struct proc_dir_entry *)inode->u.generic_ip;
+ tmp = cio_procfs_device_list;
+
+ while (tmp) {
+ if ((tmp->entry->cio_device_entry == pde) ||
+ (tmp->entry->cio_sensedata_entry == pde) ||
+ (tmp->entry->cio_in_use_entry == pde) ||
+ (tmp->entry->cio_chpid_entry == pde))
+ break;
+ tmp = tmp->next;
+ }
+
+ if (tmp)
+ devno = tmp->entry->devno;
+
+ return devno;
+}
+
+
+static int cio_sensedata_entry_open( struct inode *inode, struct file *file)
+{
+ int rc = 0;
+ int size = 1;
+ int len = 0;
+ tempinfo_t *info;
+ int irq;
+ int devno;
+
+ info = (tempinfo_t *) vmalloc(sizeof(tempinfo_t));
+ if (info == NULL) {
+ printk( KERN_WARNING "No memory available for data\n");
+ rc = -ENOMEM;
+ } else {
+ file->private_data = (void *) info;
+ size += 2 * 32;
+ info->data = (char *) vmalloc(size);
+ if (size && info->data == NULL) {
+ printk(KERN_WARNING "No memory available for data\n");
+ vfree(info);
+ rc = -ENOMEM;
+ } else {
+ devno = cio_search_devno_by_inode(inode);
+ if (devno != 0xFFFF) {
+ irq = get_irq_by_devno(devno);
+ if (irq != -1) {
+ len += sprintf(info->data+len, "Dev Type/Mod: ");
+ if (ioinfo[irq]->senseid.dev_type == 0) {
+ len += sprintf(info->data+len, "%04X/%02X\n",
+ ioinfo[irq]->senseid.cu_type,
+ ioinfo[irq]->senseid.cu_model);
+ } else {
+ len += sprintf(info->data+len, "%04X/%02X\n",
+ ioinfo[irq]->senseid.dev_type,
+ ioinfo[irq]->senseid.dev_model);
+ len+= sprintf(info->data+len, "CU Type/Mod: %04X/%02X\n",
+ ioinfo[irq]->senseid.cu_type,
+ ioinfo[irq]->senseid.cu_model);
+ }
+ }
+ }
+ info->len = len;
+ }
+ }
+
+ return rc;
+}
+
+static int cio_in_use_entry_open( struct inode *inode, struct file *file)
+{
+ int rc = 0;
+ int size = 1;
+ int len = 0;
+ tempinfo_t *info;
+ int irq;
+ int devno;
+
+ info = (tempinfo_t *) vmalloc(sizeof(tempinfo_t));
+ if (info == NULL) {
+ printk( KERN_WARNING "No memory available for data\n");
+ rc = -ENOMEM;
+ } else {
+ file->private_data = (void *) info;
+ size += 8;
+ info->data = (char *) vmalloc(size);
+ if (size && info->data == NULL) {
+ printk(KERN_WARNING "No memory available for data\n");
+ vfree(info);
+ rc = -ENOMEM;
+ } else {
+ devno = cio_search_devno_by_inode(inode);
+ if (devno != -1) {
+ irq = get_irq_by_devno(devno);
+ if (irq != -1) {
+ len += sprintf(info->data+len, "%s\n", ioinfo[irq]->ui.flags.ready?"yes":"no");
+ }
+ }
+ info->len = len;
+ }
+ }
+
+ return rc;
+}
+
+static int cio_chpid_entry_open( struct inode *inode, struct file *file)
+{
+ int rc = 0;
+ int size = 1;
+ int len = 0;
+ tempinfo_t *info;
+ int irq;
+ int devno;
+ int i;
+
+ info = (tempinfo_t *) vmalloc(sizeof(tempinfo_t));
+ if (info == NULL) {
+ printk( KERN_WARNING "No memory available for data\n");
+ rc = -ENOMEM;
+ } else {
+ file->private_data = (void *) info;
+ size += 8*16;
+ info->data = (char *) vmalloc(size);
+ if (size && info->data == NULL) {
+ printk(KERN_WARNING "No memory available for data\n");
+ vfree(info);
+ rc = -ENOMEM;
+ } else {
+ devno = cio_search_devno_by_inode(inode);
+ if (devno != -1) {
+ irq = get_irq_by_devno(devno);
+ if (irq != -1) {
+ for (i=0; i<8; i++) {
+ len += sprintf(info->data+len, "CHPID[%d]: ", i);
+ len += sprintf(info->data+len, "%02X\n", ioinfo[irq]->schib.pmcw.chpid[i]);
+ }
+ }
+ }
+ info->len = len;
+ }
+ }
+
+ return rc;
+}
+
+static struct file_operations cio_sensedata_entry_file_ops =
+{
+ read:cio_device_entry_read,
+ open:cio_sensedata_entry_open,
+ release:cio_device_entry_close,
+};
+
+static struct file_operations cio_in_use_entry_file_ops =
+{
+ read:cio_device_entry_read,
+ open:cio_in_use_entry_open,
+ release:cio_device_entry_close,
+};
+
+static struct file_operations cio_chpid_entry_file_ops =
+{
+ read:cio_device_entry_read,
+ open:cio_chpid_entry_open,
+ release:cio_device_entry_close,
+};
+
+/*
+ * Function: cio_procfs_device_create
+ * create procfs entry for given device number
+ * and insert it into list
+ */
+int cio_procfs_device_create(int devno)
+{
+ cio_procfs_entry_t *entry;
+ cio_procfs_device_t *tmp;
+ cio_procfs_device_t *where;
+ char buf[8];
+ int i;
+ int rc = 0;
+
+
+ /* create the directory entry */
+ entry = (cio_procfs_entry_t *)kmalloc(sizeof(cio_procfs_entry_t), GFP_KERNEL);
+ if (entry) {
+ entry->devno = devno;
+ sprintf(buf, "%x", devno);
+ entry->cio_device_entry = proc_mkdir(buf, cio_procfs_deviceinfo_root);
+
+ if (entry->cio_device_entry) {
+ tmp = (cio_procfs_device_t *)kmalloc(sizeof(cio_procfs_device_t), GFP_KERNEL);
+ if (tmp) {
+ tmp->entry = entry;
+
+ if (cio_procfs_device_list == NULL) {
+ cio_procfs_device_list = tmp;
+ tmp->next = NULL;
+ } else {
+ where = cio_procfs_device_list;
+ i = where->entry->devno;
+ while ((devno>i) && (where->next != NULL)) {
+ where = where->next;
+ i = where->entry->devno;
+ }
+ if (where->next == NULL) {
+ where->next = tmp;
+ tmp->next = NULL;
+ } else {
+ tmp->next = where->next;
+ where->next = tmp;
+ }
+ }
+ /* create the different entries */
+ entry->cio_sensedata_entry = create_proc_entry( "sensedata", S_IFREG|S_IRUGO, entry->cio_device_entry);
+ entry->cio_sensedata_entry->proc_fops = &cio_sensedata_entry_file_ops;
+ entry->cio_in_use_entry = create_proc_entry( "in_use", S_IFREG|S_IRUGO, entry->cio_device_entry);
+ entry->cio_in_use_entry->proc_fops = &cio_in_use_entry_file_ops;
+ entry->cio_chpid_entry = create_proc_entry( "chpids", S_IFREG|S_IRUGO, entry->cio_device_entry);
+ entry->cio_chpid_entry->proc_fops = &cio_chpid_entry_file_ops;
+ } else {
+ printk("Error, could not allocate procfs structure!\n");
+ remove_proc_entry(buf, cio_procfs_deviceinfo_root);
+ kfree(entry);
+ rc = -ENOMEM;
+ }
+ } else {
+ printk("Error, could not allocate procfs structure!\n");
+ kfree(entry);
+ rc = -ENOMEM;
+ }
+
+ } else {
+ printk("Error, could not allocate procfs structure!\n");
+ rc = -ENOMEM;
+ }
+ return rc;
+}
+
+/*
+ * Function: cio_procfs_device_remove
+ * remove procfs entry for given device number
+ */
+int cio_procfs_device_remove(int devno)
+{
+ int rc = 0;
+ cio_procfs_device_t *tmp;
+ cio_procfs_device_t *prev = NULL;
+
+ tmp=cio_procfs_device_list;
+ while (tmp) {
+ if (tmp->entry->devno == devno)
+ break;
+ prev = tmp;
+ tmp = tmp->next;
+ }
+
+ if (tmp) {
+ char buf[8];
+
+ remove_proc_entry("sensedata", tmp->entry->cio_device_entry);
+ remove_proc_entry("in_use", tmp->entry->cio_device_entry);
+ remove_proc_entry("chpid", tmp->entry->cio_device_entry);
+ sprintf(buf, "%x", devno);
+ remove_proc_entry(buf, cio_procfs_deviceinfo_root);
+
+ if (tmp == cio_procfs_device_list) {
+ cio_procfs_device_list = tmp->next;
+ } else {
+ prev->next = tmp->next;
+ }
+ kfree(tmp->entry);
+ kfree(tmp);
+ } else {
+ rc = -ENODEV;
+ }
+
+ return rc;
+}
+
+/*
+ * Function: cio_procfs_purge
+ * purge /proc/deviceinfo of entries for gone devices
+ */
+
+int cio_procfs_device_purge(void)
+{
+ int i;
+
+ for (i=0; i<=highest_subchannel; i++) {
+ if (ioinfo[i] != INVALID_STORAGE_AREA) {
+ if (!ioinfo[i]->ui.flags.oper)
+ cio_procfs_device_remove(ioinfo[i]->devno);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Function: cio_procfs_create
+ * create /proc/deviceinfo/ and subdirs for the devices
+ */
+static int cio_procfs_create( void )
+{
+ int irq;
+
+ if (cio_proc_devinfo) {
+
+ cio_procfs_deviceinfo_root = proc_mkdir( "deviceinfo", &proc_root);
+
+ if (highest_subchannel >= MAX_CIO_PROCFS_ENTRIES) {
+ printk(KERN_ALERT "Warning: Not enough inodes for creating all entries under /proc/deviceinfo/. "
+ "Not every device will get an entry.\n");
+ }
+
+ for (irq=0; irq<=highest_subchannel; irq++) {
+ if (irq >= MAX_CIO_PROCFS_ENTRIES)
+ break;
+ if (ioinfo[irq] != INVALID_STORAGE_AREA) {
+ if (ioinfo[irq]->ui.flags.oper)
+ if (cio_procfs_device_create(ioinfo[irq]->devno) == -ENOMEM) {
+ printk(KERN_CRIT "Out of memory while creating entries in /proc/deviceinfo/, "
+ "not all devices might show up\n");
+ break;
+ }
+ }
+ }
+
+ }
+
+ return 1;
+}
+
+__initcall(cio_procfs_create);
+
+/*
+ * Entry /proc/cio_ignore to display blacklisted ranges of devices.
+ * un-ignore devices by piping to /proc/cio_ignore:
+ * free all frees all blacklisted devices, free <range>,<range>,...
+ * frees specified ranges of devnos
+ */
+
+static struct proc_dir_entry *cio_ignore_proc_entry;
+
+static int cio_ignore_proc_open(struct inode *inode, struct file *file)
+{
+ int rc = 0;
+ int size = 1;
+ int len = 0;
+ tempinfo_t *info;
+ dev_blacklist_range_t *tmp;
+
+ info = (tempinfo_t *) vmalloc(sizeof(tempinfo_t));
+ if (info == NULL) {
+ printk( KERN_WARNING "No memory available for data\n");
+ rc = -ENOMEM;
+ } else {
+ file->private_data = (void *) info;
+ size += nr_blacklisted_ranges * 32;
+ info->data = (char *) vmalloc(size);
+ if (size && info->data == NULL) {
+ printk( KERN_WARNING "No memory available for data\n");
+ vfree (info);
+ rc = -ENOMEM;
+ } else {
+ tmp = dev_blacklist_range_head;
+ while (tmp) {
+ len += sprintf(info->data+len, "%04x ", tmp->from);
+ if (tmp->to != tmp->from)
+ len += sprintf(info->data+len, "- %04x", tmp->to);
+ len += sprintf(info->data+len, "\n");
+ tmp = tmp->next;
+ }
+ info->len = len;
+ }
+ }
+ return rc;
+}
+
+static int cio_ignore_proc_close(struct inode *inode, struct file *file)
+{
+ int rc = 0;
+ tempinfo_t *p_info = (tempinfo_t *) file->private_data;
+
+ if (p_info) {
+ if (p_info->data)
+ vfree( p_info->data );
+ vfree( p_info );
+ }
+
+ return rc;
+}
+
+static ssize_t cio_ignore_proc_read( struct file *file, char *user_buf, size_t user_len, loff_t * offset)
+{
+ loff_t len;
+ tempinfo_t *p_info = (tempinfo_t *) file->private_data;
+
+ if ( *offset>=p_info->len) {
+ return 0;
+ } else {
+ len = MIN(user_len, (p_info->len - *offset));
+ if (copy_to_user( user_buf, &(p_info->data[*offset]), len))
+ return -EFAULT;
+ (* offset) += len;
+ return len;
+ }
+}
+
+static ssize_t cio_ignore_proc_write (struct file *file, const char *user_buf,
+ size_t user_len, loff_t * offset)
+{
+ 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';
+#ifdef CIO_DEBUG_IO
+ printk ("/proc/cio_ignore: '%s'\n", buffer);
+#endif /* CIO_DEBUG_IO */
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2, "/proc/cio_ignore: '%s'\n",buffer);
+
+ blacklist_parse_proc_parameters(buffer);
+
+ return user_len;
+}
+
+static struct file_operations cio_ignore_proc_file_ops =
+{
+ read:cio_ignore_proc_read,
+ open:cio_ignore_proc_open,
+ write:cio_ignore_proc_write,
+ release:cio_ignore_proc_close,
+};
+
+static int cio_ignore_proc_init(void)
+{
+ cio_ignore_proc_entry = create_proc_entry("cio_ignore", S_IFREG|S_IRUGO|S_IWUSR, &proc_root);
+ cio_ignore_proc_entry->proc_fops = &cio_ignore_proc_file_ops;
+
+ return 1;
+}
+
+__initcall(cio_ignore_proc_init);
+
+/* end of procfs stuff */
+
+schib_t *s390_get_schib( int irq )
+{
+ if ( (irq > highest_subchannel) || (irq < 0) )
+ return NULL;
+ if ( ioinfo[irq] == INVALID_STORAGE_AREA )
+ return NULL;
+ return &ioinfo[irq]->schib;
+
+}
+
+
EXPORT_SYMBOL(halt_IO);
EXPORT_SYMBOL(clear_IO);
EXPORT_SYMBOL(do_IO);
@@ -6117,3 +7514,6 @@
EXPORT_SYMBOL(read_conf_data);
EXPORT_SYMBOL(read_dev_chars);
EXPORT_SYMBOL(s390_request_irq_special);
+EXPORT_SYMBOL(s390_get_schib);
+EXPORT_SYMBOL(s390_register_adapter_interrupt);
+EXPORT_SYMBOL(s390_unregister_adapter_interrupt);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)